From nobody Mon May 6 19:29:01 2024 Delivered-To: importer@patchew.org Received-SPF: pass (zohomail.com: domain of groups.io designates 66.175.222.12 as permitted sender) client-ip=66.175.222.12; envelope-from=bounce+27952+58448+1787277+3901457@groups.io; helo=web01.groups.io; Authentication-Results: mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of groups.io designates 66.175.222.12 as permitted sender) smtp.mailfrom=bounce+27952+58448+1787277+3901457@groups.io ARC-Seal: i=1; a=rsa-sha256; t=1588267020; cv=none; d=zohomail.com; s=zohoarc; b=c4fU0AJyAdx9CZYV2kIrlQS1Wj+7rS5dOZarrvD+vPJl6mwQXFrVANFcLE6x42wM3IgChWbF3Lzd5GoF9C6dOsR6knVkJaW3lQ/IzLMmyFE8cOPEUhJ69C23F1DTWxupf6Vm8UnGUlsrnIgaZnNKCE04Wuf2CiUAG0c9wgPNZl4= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1588267020; h=Cc:Date:From:In-Reply-To:List-Id:List-Unsubscribe:Message-ID:Reply-To:References:Sender:Subject:To; bh=6dFjVDdSi5QkqtGp5Glxs343lJjeuOH7ufDai6JhNRI=; b=E78BHr8o3vEIijGDOiWpEJD1UOBbQ79Dlg/xCM5PlGLQxZZZaw6eptnvaAFAs231U19l1RCWtKPbSQnpXCzmNR5eEtSaKpVLC6P+QuIZCImozwkcCjzL0fDswC9RbVCmn91POqTj2CGZErLpccU25WctcawnCBvoYCEh7RNKK1w= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of groups.io designates 66.175.222.12 as permitted sender) smtp.mailfrom=bounce+27952+58448+1787277+3901457@groups.io Received: from web01.groups.io (web01.groups.io [66.175.222.12]) by mx.zohomail.com with SMTPS id 1588267020315460.2439293320391; Thu, 30 Apr 2020 10:17:00 -0700 (PDT) Return-Path: X-Received: by 127.0.0.2 with SMTP id uTesYY1788612x7Q3bd2LxIH; Thu, 30 Apr 2020 10:16:59 -0700 X-Received: from foss.arm.com (foss.arm.com [217.140.110.172]) by mx.groups.io with SMTP id smtpd.web12.750.1588267018852967459 for ; Thu, 30 Apr 2020 10:16:59 -0700 X-Received: from usa-sjc-imap-foss1.foss.arm.com (unknown [10.121.207.14]) by usa-sjc-mx-foss1.foss.arm.com (Postfix) with ESMTP id 7E37C1045; Thu, 30 Apr 2020 10:16:58 -0700 (PDT) X-Received: from e123331-lin.home (unknown [172.31.20.19]) by usa-sjc-imap-foss1.foss.arm.com (Postfix) with ESMTPSA id 9FA523F73D; Thu, 30 Apr 2020 10:16:57 -0700 (PDT) From: "Ard Biesheuvel" To: devel@edk2.groups.io Cc: leif@nuviainc.com, Ard Biesheuvel Subject: [edk2-devel] [PATCH edk2-platforms v3 1/8] Omap35xxPkg/LcdGraphicsOutputDxe: add missing protocol reference Date: Thu, 30 Apr 2020 19:16:42 +0200 Message-Id: <20200430171650.24139-2-ard.biesheuvel@arm.com> In-Reply-To: <20200430171650.24139-1-ard.biesheuvel@arm.com> References: <20200430171650.24139-1-ard.biesheuvel@arm.com> Precedence: Bulk List-Unsubscribe: Sender: devel@edk2.groups.io List-Id: <27952.devel.edk2.groups.io> Mailing-List: list devel@edk2.groups.io; contact devel+owner@edk2.groups.io Reply-To: devel@edk2.groups.io,ard.biesheuvel@arm.com X-Gm-Message-State: 5WB0dtnjSjaSeQqeZh1xZW25x1787277AA= DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=groups.io; q=dns/txt; s=20140610; t=1588267019; bh=lCZleHs2l5vy9IU1HxzhEVo1hTtN1fq7YJqRZRIszt4=; h=Cc:Date:From:Reply-To:Subject:To; b=V4Inu3YJ5Ag7SRO8ZfdZe/Ucb63AK7oepPVh2T+EoT6LSDy0BjQ0mpYH+CeGbP2PRhU BU10AsTmuSk8c6J+nYgNydpF9L2Ewttz4m5/qT9HKHQvgKN1GuMlMlfxRqKLvhp/QQ5H5 ERvZfeEVzqCHwaCOC5KO36drS4iTA2b2byU= X-ZohoMail-DKIM: pass (identity @groups.io) Content-Transfer-Encoding: quoted-printable MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" ArmPkg's ArmLib recently dropped an unnecessary reference to gEfiCpuArchProtocolGuid, causing the build to fail for BeagleBoard, due to the fact that LcdGraphicsOutputDxe does need it, but lacks the reference, which no longer gets satisfied transitively through ArmLib. So add the reference to LcdGraphicsOutputDxe directly. Signed-off-by: Ard Biesheuvel Reviewed-by: Leif Lindholm --- Silicon/TexasInstruments/Omap35xxPkg/LcdGraphicsOutputDxe/LcdGraphicsOutpu= tDxe.inf | 1 + 1 file changed, 1 insertion(+) diff --git a/Silicon/TexasInstruments/Omap35xxPkg/LcdGraphicsOutputDxe/LcdG= raphicsOutputDxe.inf b/Silicon/TexasInstruments/Omap35xxPkg/LcdGraphicsOutp= utDxe/LcdGraphicsOutputDxe.inf index 65624ce7e189..d07be1c74cf5 100644 --- a/Silicon/TexasInstruments/Omap35xxPkg/LcdGraphicsOutputDxe/LcdGraphics= OutputDxe.inf +++ b/Silicon/TexasInstruments/Omap35xxPkg/LcdGraphicsOutputDxe/LcdGraphics= OutputDxe.inf @@ -37,6 +37,7 @@ [LibraryClasses] BaseMemoryLib =20 [Protocols] + gEfiCpuArchProtocolGuid gEfiDevicePathProtocolGuid gEfiGraphicsOutputProtocolGuid gEfiDevicePathToTextProtocolGuid --=20 2.17.1 -=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D- Groups.io Links: You receive all messages sent to this group. View/Reply Online (#58448): https://edk2.groups.io/g/devel/message/58448 Mute This Topic: https://groups.io/mt/73380288/1787277 Group Owner: devel+owner@edk2.groups.io Unsubscribe: https://edk2.groups.io/g/devel/unsub [importer@patchew.org] -=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D- From nobody Mon May 6 19:29:01 2024 Delivered-To: importer@patchew.org Received-SPF: pass (zohomail.com: domain of groups.io designates 66.175.222.12 as permitted sender) client-ip=66.175.222.12; envelope-from=bounce+27952+58450+1787277+3901457@groups.io; helo=web01.groups.io; Authentication-Results: mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of groups.io designates 66.175.222.12 as permitted sender) smtp.mailfrom=bounce+27952+58450+1787277+3901457@groups.io ARC-Seal: i=1; a=rsa-sha256; t=1588267021; cv=none; d=zohomail.com; s=zohoarc; b=EInv7raGwqdZxiCwigyv3AQnVIY7bJt/erGnxkFmRhj+xPMpL7v2Jbu5GsbkPlGG/2rd/L3EqJISH8FH5AkFldYJx2/UIbB5HdSb+38POx1AlC5sO7njJg+ManFcUKKSNDWvSCkD4GIOfJ7DxWMWSUQJ7aOLePVb9JBfhxLr5Pk= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1588267021; h=Cc:Date:From:In-Reply-To:List-Id:List-Unsubscribe:Message-ID:Reply-To:References:Sender:Subject:To; bh=SkhGEwl8J03McBpcBmkHvlNckboY2PE2xEnb7dE72+A=; b=l0681GsZrN+Ki19E58imaA6b+gWCNIzpGMKAzR/+QOLwIYonift6tfTZ8apoGdhJvrfVPhWUhBvRr+m39AgqkKhYRXxLlBOdAuQde9c5QaWIbCbRVA9v9GfHrhvFsr5RJVyGJgR0Dt9GrEzfFJTCAOpKvt1GZHToUf7ivNXA7Hk= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of groups.io designates 66.175.222.12 as permitted sender) smtp.mailfrom=bounce+27952+58450+1787277+3901457@groups.io Received: from web01.groups.io (web01.groups.io [66.175.222.12]) by mx.zohomail.com with SMTPS id 1588267021657546.5049175589345; Thu, 30 Apr 2020 10:17:01 -0700 (PDT) Return-Path: X-Received: by 127.0.0.2 with SMTP id LHL7YY1788612xSgROHnqUHb; Thu, 30 Apr 2020 10:17:01 -0700 X-Received: from foss.arm.com (foss.arm.com [217.140.110.172]) by mx.groups.io with SMTP id smtpd.web11.818.1588267020239416253 for ; Thu, 30 Apr 2020 10:17:00 -0700 X-Received: from usa-sjc-imap-foss1.foss.arm.com (unknown [10.121.207.14]) by usa-sjc-mx-foss1.foss.arm.com (Postfix) with ESMTP id E1924101E; Thu, 30 Apr 2020 10:16:59 -0700 (PDT) X-Received: from e123331-lin.home (unknown [172.31.20.19]) by usa-sjc-imap-foss1.foss.arm.com (Postfix) with ESMTPSA id BCE7A3F73D; Thu, 30 Apr 2020 10:16:58 -0700 (PDT) From: "Ard Biesheuvel" To: devel@edk2.groups.io Cc: leif@nuviainc.com, Ard Biesheuvel Subject: [edk2-devel] [PATCH edk2-platforms v3 2/8] Platform/ARM/VExpressPkg: incorporate PL180 driver Date: Thu, 30 Apr 2020 19:16:43 +0200 Message-Id: <20200430171650.24139-3-ard.biesheuvel@arm.com> In-Reply-To: <20200430171650.24139-1-ard.biesheuvel@arm.com> References: <20200430171650.24139-1-ard.biesheuvel@arm.com> Precedence: Bulk List-Unsubscribe: Sender: devel@edk2.groups.io List-Id: <27952.devel.edk2.groups.io> Mailing-List: list devel@edk2.groups.io; contact devel+owner@edk2.groups.io Reply-To: devel@edk2.groups.io,ard.biesheuvel@arm.com X-Gm-Message-State: Nvn0RGkF5C86pe7jZzkPdTR3x1787277AA= DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=groups.io; q=dns/txt; s=20140610; t=1588267021; bh=PDchztIEVvL4FGVX6uLcEKoT+gHg+ooJPdh/DaEN2yQ=; h=Cc:Date:From:Reply-To:Subject:To; b=hHRtVR7rLaMYiRzAIOe3FiVrsSBUrtfI3CKhqqpS3leJt7puGXdvSUeJ8VpsLljy+Mq 294TMovQc8Ol0nlizmwkZ/G/a4moyQ+If7rxU6YsokRhUTHAoG0MZm3lJ/yPWO2pLplud gGtYUxJiwaHboZVAaB2dUZDjOvy/YfZhiQE= X-ZohoMail-DKIM: pass (identity @groups.io) Content-Transfer-Encoding: quoted-printable MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" The PL180 SD host controller driver is only used on emulated ARM platforms, uses an obsolete version of the MMC host protocol and does not adhere to the UEFI driver model. Given the above, let's just move it into VExpressPkg where it belongs. Signed-off-by: Ard Biesheuvel Reviewed-by: Philippe Mathieu-Daude Reviewed-by: Leif Lindholm --- Platform/ARM/VExpressPkg/ArmVExpress-CTA15-A7.dsc | 6 +- Platform/ARM/VExpressPkg/ArmVExpress-CTA15-A7.fdf | 2 +- Platform/ARM/VExpressPkg/ArmVExpress-FVP-AArch64.dsc | 6 +- Platform/ARM/VExpressPkg/ArmVExpress-FVP-AArch64.fdf | 2 +- Platform/ARM/VExpressPkg/ArmVExpressPkg.dec | 4 + Platform/ARM/VExpressPkg/Drivers/PL180MciDxe/PL180Mci.c | 570 +++++++= +++++++++++++ Platform/ARM/VExpressPkg/Drivers/PL180MciDxe/PL180Mci.h | 169 ++++++ Platform/ARM/VExpressPkg/Drivers/PL180MciDxe/PL180MciDxe.inf | 53 ++ 8 files changed, 804 insertions(+), 8 deletions(-) diff --git a/Platform/ARM/VExpressPkg/ArmVExpress-CTA15-A7.dsc b/Platform/A= RM/VExpressPkg/ArmVExpress-CTA15-A7.dsc index 2f8021d3eabc..6dad31026aa5 100644 --- a/Platform/ARM/VExpressPkg/ArmVExpress-CTA15-A7.dsc +++ b/Platform/ARM/VExpressPkg/ArmVExpress-CTA15-A7.dsc @@ -146,8 +146,8 @@ [PcdsFixedAtBuild.common] # # PL180 MMC/SD card controller # - gArmPlatformTokenSpaceGuid.PcdPL180SysMciRegAddress|0x1C010048 - gArmPlatformTokenSpaceGuid.PcdPL180MciBaseAddress|0x1C050000 + gArmVExpressTokenSpaceGuid.PcdPL180SysMciRegAddress|0x1C010048 + gArmVExpressTokenSpaceGuid.PcdPL180MciBaseAddress|0x1C050000 =20 =20 # @@ -249,7 +249,7 @@ [Components.common] # Multimedia Card Interface # EmbeddedPkg/Universal/MmcDxe/MmcDxe.inf - ArmPlatformPkg/Drivers/PL180MciDxe/PL180MciDxe.inf + Platform/ARM/VExpressPkg/Drivers/PL180MciDxe/PL180MciDxe.inf =20 # SMSC LAN 9118 EmbeddedPkg/Drivers/Lan9118Dxe/Lan9118Dxe.inf diff --git a/Platform/ARM/VExpressPkg/ArmVExpress-CTA15-A7.fdf b/Platform/A= RM/VExpressPkg/ArmVExpress-CTA15-A7.fdf index 082f80d9996d..64da1102ff07 100644 --- a/Platform/ARM/VExpressPkg/ArmVExpress-CTA15-A7.fdf +++ b/Platform/ARM/VExpressPkg/ArmVExpress-CTA15-A7.fdf @@ -103,7 +103,7 @@ [FV.FvMain] # Multimedia Card Interface # INF EmbeddedPkg/Universal/MmcDxe/MmcDxe.inf - INF ArmPlatformPkg/Drivers/PL180MciDxe/PL180MciDxe.inf + INF Platform/ARM/VExpressPkg/Drivers/PL180MciDxe/PL180MciDxe.inf =20 # # Filesystems diff --git a/Platform/ARM/VExpressPkg/ArmVExpress-FVP-AArch64.dsc b/Platfor= m/ARM/VExpressPkg/ArmVExpress-FVP-AArch64.dsc index 63d79a488500..a6f536a33228 100644 --- a/Platform/ARM/VExpressPkg/ArmVExpress-FVP-AArch64.dsc +++ b/Platform/ARM/VExpressPkg/ArmVExpress-FVP-AArch64.dsc @@ -151,8 +151,8 @@ [PcdsFixedAtBuild.common] !endif =20 ## PL180 MMC/SD card controller - gArmPlatformTokenSpaceGuid.PcdPL180SysMciRegAddress|0x1C010048 - gArmPlatformTokenSpaceGuid.PcdPL180MciBaseAddress|0x1C050000 + gArmVExpressTokenSpaceGuid.PcdPL180SysMciRegAddress|0x1C010048 + gArmVExpressTokenSpaceGuid.PcdPL180MciBaseAddress|0x1C050000 =20 # # ARM Generic Interrupt Controller @@ -290,7 +290,7 @@ [Components.common] # Multimedia Card Interface # EmbeddedPkg/Universal/MmcDxe/MmcDxe.inf - ArmPlatformPkg/Drivers/PL180MciDxe/PL180MciDxe.inf + Platform/ARM/VExpressPkg/Drivers/PL180MciDxe/PL180MciDxe.inf =20 # # Platform Driver diff --git a/Platform/ARM/VExpressPkg/ArmVExpress-FVP-AArch64.fdf b/Platfor= m/ARM/VExpressPkg/ArmVExpress-FVP-AArch64.fdf index 8f49ed3dba3c..f18ead75eaec 100644 --- a/Platform/ARM/VExpressPkg/ArmVExpress-FVP-AArch64.fdf +++ b/Platform/ARM/VExpressPkg/ArmVExpress-FVP-AArch64.fdf @@ -139,7 +139,7 @@ [FV.FvMain] # Multimedia Card Interface # INF EmbeddedPkg/Universal/MmcDxe/MmcDxe.inf - INF ArmPlatformPkg/Drivers/PL180MciDxe/PL180MciDxe.inf + INF Platform/ARM/VExpressPkg/Drivers/PL180MciDxe/PL180MciDxe.inf =20 # # SMBIOS Support diff --git a/Platform/ARM/VExpressPkg/ArmVExpressPkg.dec b/Platform/ARM/VEx= pressPkg/ArmVExpressPkg.dec index a659cda2e44a..a4e9bfd73eb6 100644 --- a/Platform/ARM/VExpressPkg/ArmVExpressPkg.dec +++ b/Platform/ARM/VExpressPkg/ArmVExpressPkg.dec @@ -52,3 +52,7 @@ [PcdsFixedAtBuild.common] # gArmVExpressTokenSpaceGuid.PcdAndroidFastbootNvmDevicePath|""|VOID*|0x00= 000006 gArmVExpressTokenSpaceGuid.PcdAndroidFastbootProductName|""|VOID*|0x0000= 0007 + + ## PL180 MCI + gArmVExpressTokenSpaceGuid.PcdPL180SysMciRegAddress|0x00000000|UINT32|0x= 00000009 + gArmVExpressTokenSpaceGuid.PcdPL180MciBaseAddress|0x00000000|UINT32|0x00= 00000A diff --git a/Platform/ARM/VExpressPkg/Drivers/PL180MciDxe/PL180Mci.c b/Plat= form/ARM/VExpressPkg/Drivers/PL180MciDxe/PL180Mci.c new file mode 100644 index 000000000000..8572513f559a --- /dev/null +++ b/Platform/ARM/VExpressPkg/Drivers/PL180MciDxe/PL180Mci.c @@ -0,0 +1,570 @@ +/** @file + This file implement the MMC Host Protocol for the ARM PrimeCell PL180. + + WARNING: + This driver fails to follow the UEFI driver model without a good + reason, and only remains in the tree because it is still used by + a small number of platforms. It will be removed when no longer used. + New platforms should not use it, and no one should use this as + reference code for developing new drivers. + + Copyright (c) 2011-2020, ARM Limited. All rights reserved. + + SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include "PL180Mci.h" + +#include +#include + +EFI_MMC_HOST_PROTOCOL *gpMmcHost; + +// Untested ... +//#define USE_STREAM + +#define MMCI0_BLOCKLEN 512 +#define MMCI0_POW2_BLOCKLEN 9 +#define MMCI0_TIMEOUT 1000 + +#define SYS_MCI_CARDIN BIT0 +#define SYS_MCI_WPROT BIT1 + +BOOLEAN +MciIsPowerOn ( + VOID + ) +{ + return ((MmioRead32 (MCI_POWER_CONTROL_REG) & MCI_POWER_ON) =3D=3D MCI_P= OWER_ON); +} + +EFI_STATUS +MciInitialize ( + VOID + ) +{ + MCI_TRACE ("MciInitialize()"); + return EFI_SUCCESS; +} + +BOOLEAN +MciIsCardPresent ( + IN EFI_MMC_HOST_PROTOCOL *This + ) +{ + return (MmioRead32 (FixedPcdGet32 (PcdPL180SysMciRegAddress)) & SYS_MCI_= CARDIN); +} + +BOOLEAN +MciIsReadOnly ( + IN EFI_MMC_HOST_PROTOCOL *This + ) +{ + return (MmioRead32 (FixedPcdGet32 (PcdPL180SysMciRegAddress)) & SYS_MCI_= WPROT); +} + +// Convert block size to 2^n +STATIC +UINT32 +GetPow2BlockLen ( + IN UINT32 BlockLen + ) +{ + UINTN Loop; + UINTN Pow2BlockLen; + + Loop =3D 0x8000; + Pow2BlockLen =3D 15; + do { + Loop =3D (Loop >> 1) & 0xFFFF; + Pow2BlockLen--; + } while (Pow2BlockLen && (!(Loop & BlockLen))); + + return Pow2BlockLen; +} + +VOID +MciPrepareDataPath ( + IN UINTN TransferDirection + ) +{ + // Set Data Length & Data Timer + MmioWrite32 (MCI_DATA_TIMER_REG, 0xFFFFFFF); + MmioWrite32 (MCI_DATA_LENGTH_REG, MMCI0_BLOCKLEN); + +#ifndef USE_STREAM + //Note: we are using a hardcoded BlockLen (=3D=3D512). If we decide to u= se a variable size, we could + // compute the pow2 of BlockLen with the above function GetPow2BlockLen = () + MmioWrite32 (MCI_DATA_CTL_REG, MCI_DATACTL_ENABLE | MCI_DATACTL_DMA_ENAB= LE | TransferDirection | (MMCI0_POW2_BLOCKLEN << 4)); +#else + MmioWrite32 (MCI_DATA_CTL_REG, MCI_DATACTL_ENABLE | MCI_DATACTL_DMA_ENAB= LE | TransferDirection | MCI_DATACTL_STREAM_TRANS); +#endif +} + +EFI_STATUS +MciSendCommand ( + IN EFI_MMC_HOST_PROTOCOL *This, + IN MMC_CMD MmcCmd, + IN UINT32 Argument + ) +{ + UINT32 Status; + UINT32 Cmd; + UINTN RetVal; + UINTN CmdCtrlReg; + UINT32 DoneMask; + + RetVal =3D EFI_SUCCESS; + + if ((MmcCmd =3D=3D MMC_CMD17) || (MmcCmd =3D=3D MMC_CMD11)) { + MciPrepareDataPath (MCI_DATACTL_CARD_TO_CONT); + } else if ((MmcCmd =3D=3D MMC_CMD24) || (MmcCmd =3D=3D MMC_CMD20)) { + MciPrepareDataPath (MCI_DATACTL_CONT_TO_CARD); + } else if (MmcCmd =3D=3D MMC_CMD6) { + MmioWrite32 (MCI_DATA_TIMER_REG, 0xFFFFFFF); + MmioWrite32 (MCI_DATA_LENGTH_REG, 64); +#ifndef USE_STREAM + MmioWrite32 (MCI_DATA_CTL_REG, MCI_DATACTL_ENABLE | MCI_DATACTL_CARD_T= O_CONT | GetPow2BlockLen (64)); +#else + MmioWrite32 (MCI_DATA_CTL_REG, MCI_DATACTL_ENABLE | MCI_DATACTL_CARD_T= O_CONT | MCI_DATACTL_STREAM_TRANS); +#endif + } else if (MmcCmd =3D=3D MMC_ACMD51) { + MmioWrite32 (MCI_DATA_TIMER_REG, 0xFFFFFFF); + /* SCR register is 8 bytes long. */ + MmioWrite32 (MCI_DATA_LENGTH_REG, 8); +#ifndef USE_STREAM + MmioWrite32 (MCI_DATA_CTL_REG, MCI_DATACTL_ENABLE | MCI_DATACTL_CARD_T= O_CONT | GetPow2BlockLen (8)); +#else + MmioWrite32 (MCI_DATA_CTL_REG, MCI_DATACTL_ENABLE | MCI_DATACTL_CARD_T= O_CONT | MCI_DATACTL_STREAM_TRANS); +#endif + } + + // Create Command for PL180 + Cmd =3D (MMC_GET_INDX (MmcCmd) & INDX_MASK) | MCI_CPSM_ENABLE; + if (MmcCmd & MMC_CMD_WAIT_RESPONSE) { + Cmd |=3D MCI_CPSM_WAIT_RESPONSE; + } + + if (MmcCmd & MMC_CMD_LONG_RESPONSE) { + Cmd |=3D MCI_CPSM_LONG_RESPONSE; + } + + // Clear Status register static flags + MmioWrite32 (MCI_CLEAR_STATUS_REG, MCI_CLR_ALL_STATUS); + + // Write to command argument register + MmioWrite32 (MCI_ARGUMENT_REG, Argument); + + // Write to command register + MmioWrite32 (MCI_COMMAND_REG, Cmd); + + DoneMask =3D (Cmd & MCI_CPSM_WAIT_RESPONSE) + ? (MCI_STATUS_CMD_RESPEND | MCI_STATUS_CMD_ERROR) + : (MCI_STATUS_CMD_SENT | MCI_STATUS_CMD_ERROR); + do { + Status =3D MmioRead32 (MCI_STATUS_REG); + } while (! (Status & DoneMask)); + + if ((Status & MCI_STATUS_CMD_ERROR)) { + // Clear Status register error flags + MmioWrite32 (MCI_CLEAR_STATUS_REG, MCI_STATUS_CMD_ERROR); + + if ((Status & MCI_STATUS_CMD_START_BIT_ERROR)) { + DEBUG ((EFI_D_ERROR, "MciSendCommand(CmdIndex:%d) Start bit Error! R= esponse:0x%X Status:0x%x\n", (Cmd & 0x3F), MmioRead32 (MCI_RESPONSE0_REG), = Status)); + RetVal =3D EFI_NO_RESPONSE; + } else if ((Status & MCI_STATUS_CMD_CMDTIMEOUT)) { + //DEBUG ((EFI_D_ERROR, "MciSendCommand(CmdIndex:%d) TIMEOUT! Respons= e:0x%X Status:0x%x\n", (Cmd & 0x3F), MmioRead32 (MCI_RESPONSE0_REG), Status= )); + RetVal =3D EFI_TIMEOUT; + } else if ((!(MmcCmd & MMC_CMD_NO_CRC_RESPONSE)) && (Status & MCI_STAT= US_CMD_CMDCRCFAIL)) { + // The CMD1 and response type R3 do not contain CRC. We should ignor= e the CRC failed Status. + RetVal =3D EFI_CRC_ERROR; + } + } + + // Disable Command Path + CmdCtrlReg =3D MmioRead32 (MCI_COMMAND_REG); + MmioWrite32 (MCI_COMMAND_REG, (CmdCtrlReg & ~MCI_CPSM_ENABLE)); + return RetVal; +} + +EFI_STATUS +MciReceiveResponse ( + IN EFI_MMC_HOST_PROTOCOL *This, + IN MMC_RESPONSE_TYPE Type, + IN UINT32* Buffer + ) +{ + if (Buffer =3D=3D NULL) { + return EFI_INVALID_PARAMETER; + } + + if ( (Type =3D=3D MMC_RESPONSE_TYPE_R1) + || (Type =3D=3D MMC_RESPONSE_TYPE_R1b) + || (Type =3D=3D MMC_RESPONSE_TYPE_R3) + || (Type =3D=3D MMC_RESPONSE_TYPE_R6) + || (Type =3D=3D MMC_RESPONSE_TYPE_R7)) + { + Buffer[0] =3D MmioRead32 (MCI_RESPONSE3_REG); + } else if (Type =3D=3D MMC_RESPONSE_TYPE_R2) { + Buffer[0] =3D MmioRead32 (MCI_RESPONSE0_REG); + Buffer[1] =3D MmioRead32 (MCI_RESPONSE1_REG); + Buffer[2] =3D MmioRead32 (MCI_RESPONSE2_REG); + Buffer[3] =3D MmioRead32 (MCI_RESPONSE3_REG); + } + + return EFI_SUCCESS; +} + +EFI_STATUS +MciReadBlockData ( + IN EFI_MMC_HOST_PROTOCOL *This, + IN EFI_LBA Lba, + IN UINTN Length, + IN UINT32* Buffer + ) +{ + UINTN Loop; + UINTN Finish; + UINTN Status; + EFI_STATUS RetVal; + UINTN DataCtrlReg; + EFI_TPL Tpl; + + RetVal =3D EFI_SUCCESS; + + // Read data from the RX FIFO + Loop =3D 0; + if (Length < MMCI0_BLOCKLEN) { + Finish =3D Length / 4; + } else { + Finish =3D MMCI0_BLOCKLEN / 4; + } + + // Raise the TPL at the highest level to disable Interrupts. + Tpl =3D gBS->RaiseTPL (TPL_HIGH_LEVEL); + + do { + // Read the Status flags + Status =3D MmioRead32 (MCI_STATUS_REG); + + // Do eight reads if possible else a single read + if (Status & MCI_STATUS_CMD_RXFIFOHALFFULL) { + Buffer[Loop] =3D MmioRead32(MCI_FIFO_REG); + Loop++; + Buffer[Loop] =3D MmioRead32(MCI_FIFO_REG); + Loop++; + Buffer[Loop] =3D MmioRead32(MCI_FIFO_REG); + Loop++; + Buffer[Loop] =3D MmioRead32(MCI_FIFO_REG); + Loop++; + Buffer[Loop] =3D MmioRead32(MCI_FIFO_REG); + Loop++; + Buffer[Loop] =3D MmioRead32(MCI_FIFO_REG); + Loop++; + Buffer[Loop] =3D MmioRead32(MCI_FIFO_REG); + Loop++; + Buffer[Loop] =3D MmioRead32(MCI_FIFO_REG); + Loop++; + } else if (Status & MCI_STATUS_CMD_RXDATAAVAILBL) { + Buffer[Loop] =3D MmioRead32(MCI_FIFO_REG); + Loop++; + } else { + //Check for error conditions and timeouts + if (Status & MCI_STATUS_CMD_DATATIMEOUT) { + DEBUG ((EFI_D_ERROR, "MciReadBlockData(): TIMEOUT! Response:0x%X S= tatus:0x%x\n", MmioRead32 (MCI_RESPONSE0_REG), Status)); + RetVal =3D EFI_TIMEOUT; + break; + } else if (Status & MCI_STATUS_CMD_DATACRCFAIL) { + DEBUG ((EFI_D_ERROR, "MciReadBlockData(): CRC Error! Response:0x%X= Status:0x%x\n", MmioRead32 (MCI_RESPONSE0_REG), Status)); + RetVal =3D EFI_CRC_ERROR; + break; + } else if (Status & MCI_STATUS_CMD_START_BIT_ERROR) { + DEBUG ((EFI_D_ERROR, "MciReadBlockData(): Start-bit Error! Respons= e:0x%X Status:0x%x\n", MmioRead32 (MCI_RESPONSE0_REG), Status)); + RetVal =3D EFI_NO_RESPONSE; + break; + } + } + //clear RX over run flag + if(Status & MCI_STATUS_CMD_RXOVERRUN) { + MmioWrite32(MCI_CLEAR_STATUS_REG, MCI_STATUS_CMD_RXOVERRUN); + } + } while ((Loop < Finish)); + + // Restore Tpl + gBS->RestoreTPL (Tpl); + + // Clear Status flags + MmioWrite32 (MCI_CLEAR_STATUS_REG, MCI_CLR_ALL_STATUS); + + //Disable Data path + DataCtrlReg =3D MmioRead32 (MCI_DATA_CTL_REG); + MmioWrite32 (MCI_DATA_CTL_REG, (DataCtrlReg & MCI_DATACTL_DISABLE_MASK)); + + return RetVal; +} + +EFI_STATUS +MciWriteBlockData ( + IN EFI_MMC_HOST_PROTOCOL *This, + IN EFI_LBA Lba, + IN UINTN Length, + IN UINT32* Buffer + ) +{ + UINTN Loop; + UINTN Finish; + UINTN Timer; + UINTN Status; + EFI_STATUS RetVal; + UINTN DataCtrlReg; + EFI_TPL Tpl; + + RetVal =3D EFI_SUCCESS; + + // Write the data to the TX FIFO + Loop =3D 0; + Finish =3D MMCI0_BLOCKLEN / 4; + Timer =3D MMCI0_TIMEOUT * 100; + + // Raise the TPL at the highest level to disable Interrupts. + Tpl =3D gBS->RaiseTPL (TPL_HIGH_LEVEL); + + do { + // Read the Status flags + Status =3D MmioRead32 (MCI_STATUS_REG); + + // Do eight writes if possible else a single write + if (Status & MCI_STATUS_CMD_TXFIFOHALFEMPTY) { + MmioWrite32(MCI_FIFO_REG, Buffer[Loop]); + Loop++; + MmioWrite32(MCI_FIFO_REG, Buffer[Loop]); + Loop++; + MmioWrite32(MCI_FIFO_REG, Buffer[Loop]); + Loop++; + MmioWrite32(MCI_FIFO_REG, Buffer[Loop]); + Loop++; + MmioWrite32(MCI_FIFO_REG, Buffer[Loop]); + Loop++; + MmioWrite32(MCI_FIFO_REG, Buffer[Loop]); + Loop++; + MmioWrite32(MCI_FIFO_REG, Buffer[Loop]); + Loop++; + MmioWrite32(MCI_FIFO_REG, Buffer[Loop]); + Loop++; + } else if (!(Status & MCI_STATUS_CMD_TXFIFOFULL)) { + MmioWrite32(MCI_FIFO_REG, Buffer[Loop]); + Loop++; + } else { + // Check for error conditions and timeouts + if (Status & MCI_STATUS_CMD_DATATIMEOUT) { + DEBUG ((EFI_D_ERROR, "MciWriteBlockData(): TIMEOUT! Response:0x%X = Status:0x%x\n", MmioRead32 (MCI_RESPONSE0_REG), Status)); + RetVal =3D EFI_TIMEOUT; + goto Exit; + } else if (Status & MCI_STATUS_CMD_DATACRCFAIL) { + DEBUG ((EFI_D_ERROR, "MciWriteBlockData(): CRC Error! Response:0x%= X Status:0x%x\n", MmioRead32 (MCI_RESPONSE0_REG), Status)); + RetVal =3D EFI_CRC_ERROR; + goto Exit; + } else if (Status & MCI_STATUS_CMD_TX_UNDERRUN) { + DEBUG ((EFI_D_ERROR, "MciWriteBlockData(): TX buffer Underrun! Res= ponse:0x%X Status:0x%x, Number of bytes written 0x%x\n",MmioRead32(MCI_RESP= ONSE0_REG),Status, Loop)); + RetVal =3D EFI_BUFFER_TOO_SMALL; + ASSERT(0); + goto Exit; + } + } + } while (Loop < Finish); + + // Restore Tpl + gBS->RestoreTPL (Tpl); + + // Wait for FIFO to drain + Timer =3D MMCI0_TIMEOUT * 60; + Status =3D MmioRead32 (MCI_STATUS_REG); +#ifndef USE_STREAM + // Single block + while (((Status & MCI_STATUS_TXDONE) !=3D MCI_STATUS_TXDONE) && Timer) { +#else + // Stream + while (((Status & MCI_STATUS_CMD_DATAEND) !=3D MCI_STATUS_CMD_DATAEND) &= & Timer) { +#endif + NanoSecondDelay(10); + Status =3D MmioRead32 (MCI_STATUS_REG); + Timer--; + } + + // Clear Status flags + MmioWrite32 (MCI_CLEAR_STATUS_REG, MCI_CLR_ALL_STATUS); + + if (Timer =3D=3D 0) { + DEBUG ((EFI_D_ERROR, "MciWriteBlockData(): Data End timeout Number of = words written 0x%x\n", Loop)); + RetVal =3D EFI_TIMEOUT; + } + +Exit: + // Disable Data path + DataCtrlReg =3D MmioRead32 (MCI_DATA_CTL_REG); + MmioWrite32 (MCI_DATA_CTL_REG, (DataCtrlReg & MCI_DATACTL_DISABLE_MASK)); + return RetVal; +} + +EFI_STATUS +MciNotifyState ( + IN EFI_MMC_HOST_PROTOCOL *This, + IN MMC_STATE State + ) +{ + UINT32 Data32; + + switch (State) { + case MmcInvalidState: + ASSERT (0); + break; + case MmcHwInitializationState: + // If device already turn on then restart it + Data32 =3D MmioRead32 (MCI_POWER_CONTROL_REG); + if ((Data32 & 0x2) =3D=3D MCI_POWER_UP) { + MCI_TRACE ("MciNotifyState(MmcHwInitializationState): TurnOff MCI"); + + // Turn off + MmioWrite32 (MCI_CLOCK_CONTROL_REG, 0); + MmioWrite32 (MCI_POWER_CONTROL_REG, 0); + MicroSecondDelay (100); + } + + MCI_TRACE ("MciNotifyState(MmcHwInitializationState): TurnOn MCI"); + // Setup clock + // - 0x1D =3D 29 =3D> should be the clock divider to be less than 400= kHz at MCLK =3D 24Mhz + MmioWrite32 (MCI_CLOCK_CONTROL_REG, 0x1D | MCI_CLOCK_ENABLE | MCI_CLOC= K_POWERSAVE); + + // Set the voltage + MmioWrite32 (MCI_POWER_CONTROL_REG, MCI_POWER_OPENDRAIN | (15<<2)); + MmioWrite32 (MCI_POWER_CONTROL_REG, MCI_POWER_ROD | MCI_POWER_OPENDRAI= N | (15<<2) | MCI_POWER_UP); + MicroSecondDelay (10); + MmioWrite32 (MCI_POWER_CONTROL_REG, MCI_POWER_ROD | MCI_POWER_OPENDRAI= N | (15<<2) | MCI_POWER_ON); + MicroSecondDelay (100); + + // Set Data Length & Data Timer + MmioWrite32 (MCI_DATA_TIMER_REG, 0xFFFFF); + MmioWrite32 (MCI_DATA_LENGTH_REG, 8); + + ASSERT ((MmioRead32 (MCI_POWER_CONTROL_REG) & 0x3) =3D=3D MCI_POWER_ON= ); + break; + case MmcIdleState: + MCI_TRACE ("MciNotifyState(MmcIdleState)"); + break; + case MmcReadyState: + MCI_TRACE ("MciNotifyState(MmcReadyState)"); + break; + case MmcIdentificationState: + MCI_TRACE ("MciNotifyState (MmcIdentificationState)"); + break; + case MmcStandByState:{ + volatile UINT32 PwrCtrlReg; + MCI_TRACE ("MciNotifyState (MmcStandByState)"); + + // Enable MCICMD push-pull drive + PwrCtrlReg =3D MmioRead32 (MCI_POWER_CONTROL_REG); + //Disable Open Drain output + PwrCtrlReg &=3D ~ (MCI_POWER_OPENDRAIN); + MmioWrite32 (MCI_POWER_CONTROL_REG, PwrCtrlReg); + + // Set MMCI0 clock to 4MHz (24MHz may be possible with cache enabled) + // + // Note: Increasing clock speed causes TX FIFO under-run errors. + // So careful when optimising this driver for higher performance. + // + MmioWrite32(MCI_CLOCK_CONTROL_REG,0x02 | MCI_CLOCK_ENABLE | MCI_CLOCK_= POWERSAVE); + // Set MMCI0 clock to 24MHz (by bypassing the divider) + //MmioWrite32(MCI_CLOCK_CONTROL_REG,MCI_CLOCK_BYPASS | MCI_CLOCK_ENABL= E); + break; + } + case MmcTransferState: + //MCI_TRACE ("MciNotifyState(MmcTransferState)"); + break; + case MmcSendingDataState: + MCI_TRACE ("MciNotifyState(MmcSendingDataState)"); + break; + case MmcReceiveDataState: + MCI_TRACE ("MciNotifyState(MmcReceiveDataState)"); + break; + case MmcProgrammingState: + MCI_TRACE ("MciNotifyState(MmcProgrammingState)"); + break; + case MmcDisconnectState: + MCI_TRACE ("MciNotifyState(MmcDisconnectState)"); + break; + default: + ASSERT (0); + } + return EFI_SUCCESS; +} + +EFI_GUID mPL180MciDevicePathGuid =3D EFI_CALLER_ID_GUID; + +EFI_STATUS +MciBuildDevicePath ( + IN EFI_MMC_HOST_PROTOCOL *This, + IN EFI_DEVICE_PATH_PROTOCOL **DevicePath + ) +{ + EFI_DEVICE_PATH_PROTOCOL *NewDevicePathNode; + + NewDevicePathNode =3D CreateDeviceNode (HARDWARE_DEVICE_PATH, HW_VENDOR_= DP, sizeof (VENDOR_DEVICE_PATH)); + CopyGuid (& ((VENDOR_DEVICE_PATH*)NewDevicePathNode)->Guid, &mPL180MciDe= vicePathGuid); + + *DevicePath =3D NewDevicePathNode; + return EFI_SUCCESS; +} + +EFI_MMC_HOST_PROTOCOL gMciHost =3D { + MMC_HOST_PROTOCOL_REVISION, + MciIsCardPresent, + MciIsReadOnly, + MciBuildDevicePath, + MciNotifyState, + MciSendCommand, + MciReceiveResponse, + MciReadBlockData, + MciWriteBlockData +}; + +EFI_STATUS +PL180MciDxeInitialize ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + EFI_STATUS Status; + EFI_HANDLE Handle; + + DEBUG ((EFI_D_WARN, "Probing ID registers at 0x%lx for a PL180\n", + MCI_PERIPH_ID_REG0)); + + // Check if this is a PL180 + if (MmioRead8 (MCI_PERIPH_ID_REG0) !=3D MCI_PERIPH_ID0 || + MmioRead8 (MCI_PERIPH_ID_REG1) !=3D MCI_PERIPH_ID1 || + MmioRead8 (MCI_PERIPH_ID_REG2) !=3D MCI_PERIPH_ID2 || + MmioRead8 (MCI_PCELL_ID_REG0) !=3D MCI_PCELL_ID0 || + MmioRead8 (MCI_PCELL_ID_REG1) !=3D MCI_PCELL_ID1 || + MmioRead8 (MCI_PCELL_ID_REG2) !=3D MCI_PCELL_ID2 || + MmioRead8 (MCI_PCELL_ID_REG3) !=3D MCI_PCELL_ID3) { + + DEBUG ((EFI_D_WARN, "Probing ID registers at 0x%lx for a PL180" + " failed\n", MCI_PERIPH_ID_REG0)); + return EFI_NOT_FOUND; + } + + Handle =3D NULL; + + MCI_TRACE ("PL180MciDxeInitialize()"); + + //Publish Component Name, BlockIO protocol interfaces + Status =3D gBS->InstallMultipleProtocolInterfaces ( + &Handle, + &gEmbeddedMmcHostProtocolGuid, &gMciHost, + NULL + ); + ASSERT_EFI_ERROR (Status); + + return EFI_SUCCESS; +} diff --git a/Platform/ARM/VExpressPkg/Drivers/PL180MciDxe/PL180Mci.h b/Plat= form/ARM/VExpressPkg/Drivers/PL180MciDxe/PL180Mci.h new file mode 100644 index 000000000000..4c5246044e75 --- /dev/null +++ b/Platform/ARM/VExpressPkg/Drivers/PL180MciDxe/PL180Mci.h @@ -0,0 +1,169 @@ +/** @file + Header for the MMC Host Protocol implementation for the ARM PrimeCell PL= 180. + + WARNING: + This driver fails to follow the UEFI driver model without a good + reason, and only remains in the tree because it is still used by + a small number of platforms. It will be removed when no longer used. + New platforms should not use it, and no one should use this as + reference code for developing new drivers. + + Copyright (c) 2011-2020, ARM Limited. All rights reserved. + + SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#ifndef __PL180_MCI_H +#define __PL180_MCI_H + +#include + +#include + +#include +#include +#include +#include +#include +#include + +#define PL180_MCI_DXE_VERSION 0x10 + +#define MCI_SYSCTL FixedPcdGet32 (PcdPL180MciBaseAddress) + +#define MCI_POWER_CONTROL_REG (MCI_SYSCTL + 0x000) +#define MCI_CLOCK_CONTROL_REG (MCI_SYSCTL + 0x004) +#define MCI_ARGUMENT_REG (MCI_SYSCTL + 0x008) +#define MCI_COMMAND_REG (MCI_SYSCTL + 0x00C) +#define MCI_RESPCMD_REG (MCI_SYSCTL + 0x010) +#define MCI_RESPONSE3_REG (MCI_SYSCTL + 0x014) +#define MCI_RESPONSE2_REG (MCI_SYSCTL + 0x018) +#define MCI_RESPONSE1_REG (MCI_SYSCTL + 0x01C) +#define MCI_RESPONSE0_REG (MCI_SYSCTL + 0x020) +#define MCI_DATA_TIMER_REG (MCI_SYSCTL + 0x024) +#define MCI_DATA_LENGTH_REG (MCI_SYSCTL + 0x028) +#define MCI_DATA_CTL_REG (MCI_SYSCTL + 0x02C) +#define MCI_DATA_COUNTER (MCI_SYSCTL + 0x030) +#define MCI_STATUS_REG (MCI_SYSCTL + 0x034) +#define MCI_CLEAR_STATUS_REG (MCI_SYSCTL + 0x038) +#define MCI_INT0_MASK_REG (MCI_SYSCTL + 0x03C) +#define MCI_INT1_MASK_REG (MCI_SYSCTL + 0x040) +#define MCI_SELECT_REG (MCI_SYSCTL + 0x044) +#define MCI_FIFOCOUNT_REG (MCI_SYSCTL + 0x048) +#define MCI_FIFO_REG (MCI_SYSCTL + 0x080) +#define MCI_PERIPH_ID_REG0 (MCI_SYSCTL + 0xFE0) +#define MCI_PERIPH_ID_REG1 (MCI_SYSCTL + 0xFE4) +#define MCI_PERIPH_ID_REG2 (MCI_SYSCTL + 0xFE8) +#define MCI_PERIPH_ID_REG3 (MCI_SYSCTL + 0xFEC) +#define MCI_PCELL_ID_REG0 (MCI_SYSCTL + 0xFF0) +#define MCI_PCELL_ID_REG1 (MCI_SYSCTL + 0xFF4) +#define MCI_PCELL_ID_REG2 (MCI_SYSCTL + 0xFF8) +#define MCI_PCELL_ID_REG3 (MCI_SYSCTL + 0xFFC) + +#define MCI_PERIPH_ID0 0x80 +#define MCI_PERIPH_ID1 0x11 +#define MCI_PERIPH_ID2 0x04 +#define MCI_PERIPH_ID3 0x00 +#define MCI_PCELL_ID0 0x0D +#define MCI_PCELL_ID1 0xF0 +#define MCI_PCELL_ID2 0x05 +#define MCI_PCELL_ID3 0xB1 + +#define MCI_POWER_OFF 0 +#define MCI_POWER_UP BIT1 +#define MCI_POWER_ON (BIT1 | BIT0) +#define MCI_POWER_OPENDRAIN BIT6 +#define MCI_POWER_ROD BIT7 + +#define MCI_CLOCK_ENABLE BIT8 +#define MCI_CLOCK_POWERSAVE BIT9 +#define MCI_CLOCK_BYPASS BIT10 +#define MCI_CLOCK_WIDEBUS BIT11 + +#define MCI_STATUS_CMD_CMDCRCFAIL BIT0 +#define MCI_STATUS_CMD_DATACRCFAIL BIT1 +#define MCI_STATUS_CMD_CMDTIMEOUT BIT2 +#define MCI_STATUS_CMD_DATATIMEOUT BIT3 +#define MCI_STATUS_CMD_TX_UNDERRUN BIT4 +#define MCI_STATUS_CMD_RXOVERRUN BIT5 +#define MCI_STATUS_CMD_RESPEND BIT6 +#define MCI_STATUS_CMD_SENT BIT7 +#define MCI_STATUS_CMD_DATAEND BIT8 +#define MCI_STATUS_CMD_START_BIT_ERROR BIT9 +#define MCI_STATUS_CMD_DATABLOCKEND BIT10 +#define MCI_STATUS_CMD_ACTIVE BIT11 +#define MCI_STATUS_CMD_TXACTIVE BIT12 +#define MCI_STATUS_CMD_RXACTIVE BIT13 +#define MCI_STATUS_CMD_TXFIFOHALFEMPTY BIT14 +#define MCI_STATUS_CMD_RXFIFOHALFFULL BIT15 +#define MCI_STATUS_CMD_TXFIFOFULL BIT16 +#define MCI_STATUS_CMD_RXFIFOFULL BIT17 +#define MCI_STATUS_CMD_TXFIFOEMPTY BIT18 +#define MCI_STATUS_CMD_RXFIFOEMPTY BIT19 +#define MCI_STATUS_CMD_TXDATAAVAILBL BIT20 +#define MCI_STATUS_CMD_RXDATAAVAILBL BIT21 + +#define MCI_STATUS_TXDONE (MCI_STATUS_CMD_DATAEND | MCI_STAT= US_CMD_DATABLOCKEND) +#define MCI_STATUS_RXDONE (MCI_STATUS_CMD_DATAEND | MCI_STAT= US_CMD_DATABLOCKEND) +#define MCI_STATUS_READ_ERROR ( MCI_STATUS_CMD_DATACRCFAIL \ + | MCI_STATUS_CMD_DATATIMEOUT \ + | MCI_STATUS_CMD_RXOVERRUN \ + | MCI_STATUS_CMD_START_BIT_ERROR ) +#define MCI_STATUS_WRITE_ERROR ( MCI_STATUS_CMD_DATACRCFAIL \ + | MCI_STATUS_CMD_DATATIMEOUT \ + | MCI_STATUS_CMD_TX_UNDERRUN ) +#define MCI_STATUS_CMD_ERROR ( MCI_STATUS_CMD_CMDCRCFAIL \ + | MCI_STATUS_CMD_CMDTIMEOUT \ + | MCI_STATUS_CMD_START_BIT_ERROR ) + +#define MCI_CLR_CMD_STATUS ( MCI_STATUS_CMD_RESPEND \ + | MCI_STATUS_CMD_SENT \ + | MCI_STATUS_CMD_ERROR ) + +#define MCI_CLR_READ_STATUS ( MCI_STATUS_RXDONE \ + | MCI_STATUS_READ_ERROR ) + +#define MCI_CLR_WRITE_STATUS ( MCI_STATUS_TXDONE \ + | MCI_STATUS_WRITE_ERROR ) + +#define MCI_CLR_ALL_STATUS (BIT11 - 1) + +#define MCI_DATACTL_DISABLE_MASK 0xFE +#define MCI_DATACTL_ENABLE BIT0 +#define MCI_DATACTL_CONT_TO_CARD 0 +#define MCI_DATACTL_CARD_TO_CONT BIT1 +#define MCI_DATACTL_BLOCK_TRANS 0 +#define MCI_DATACTL_STREAM_TRANS BIT2 +#define MCI_DATACTL_DMA_DISABLED 0 +#define MCI_DATACTL_DMA_ENABLE BIT3 + +#define INDX_MASK 0x3F + +#define MCI_CPSM_WAIT_RESPONSE BIT6 +#define MCI_CPSM_LONG_RESPONSE BIT7 +#define MCI_CPSM_LONG_INTERRUPT BIT8 +#define MCI_CPSM_LONG_PENDING BIT9 +#define MCI_CPSM_ENABLE BIT10 + +#define MCI_TRACE(txt) DEBUG ((EFI_D_BLKIO, "ARM_MCI: " t= xt "\n")) + +EFI_STATUS +EFIAPI +MciGetDriverName ( + IN EFI_COMPONENT_NAME_PROTOCOL *This, + IN CHAR8 *Language, + OUT CHAR16 **DriverName + ); + +EFI_STATUS +EFIAPI +MciGetControllerName ( + IN EFI_COMPONENT_NAME_PROTOCOL *This, + IN EFI_HANDLE ControllerHandle, + IN EFI_HANDLE ChildHandle O= PTIONAL, + IN CHAR8 *Language, + OUT CHAR16 **ControllerName + ); + +#endif diff --git a/Platform/ARM/VExpressPkg/Drivers/PL180MciDxe/PL180MciDxe.inf b= /Platform/ARM/VExpressPkg/Drivers/PL180MciDxe/PL180MciDxe.inf new file mode 100644 index 000000000000..34690a135e16 --- /dev/null +++ b/Platform/ARM/VExpressPkg/Drivers/PL180MciDxe/PL180MciDxe.inf @@ -0,0 +1,53 @@ +#/** @file +# INF file for the MMC Host Protocol implementation for the ARM PrimeCell= PL180. +# +# WARNING: +# This driver fails to follow the UEFI driver model without a good +# reason, and only remains in the tree because it is still used by +# a small number of platforms. It will be removed when no longer used. +# New platforms should not use it, and no one should use this as +# reference code for developing new drivers. +# +# Copyright (c) 2011-2020, ARM Limited. All rights reserved. +# +# SPDX-License-Identifier: BSD-2-Clause-Patent +# +#**/ + +[Defines] + INF_VERSION =3D 0x00010005 + BASE_NAME =3D PL180MciDxe + FILE_GUID =3D 09831032-6fa3-4484-af4f-0a000a8d3a82 + MODULE_TYPE =3D DXE_DRIVER + VERSION_STRING =3D 1.0 + + ENTRY_POINT =3D PL180MciDxeInitialize + +[Sources.common] + PL180Mci.c + +[Packages] + EmbeddedPkg/EmbeddedPkg.dec + MdePkg/MdePkg.dec + Platform/ARM/VExpressPkg/ArmVExpressPkg.dec + +[LibraryClasses] + BaseLib + UefiLib + UefiDriverEntryPoint + BaseMemoryLib + ArmLib + IoLib + TimerLib + +[Protocols] + gEfiCpuArchProtocolGuid + gEfiDevicePathProtocolGuid + gEmbeddedMmcHostProtocolGuid + +[Pcd] + gArmVExpressTokenSpaceGuid.PcdPL180SysMciRegAddress + gArmVExpressTokenSpaceGuid.PcdPL180MciBaseAddress + +[Depex] + gEfiCpuArchProtocolGuid --=20 2.17.1 -=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D- Groups.io Links: You receive all messages sent to this group. View/Reply Online (#58450): https://edk2.groups.io/g/devel/message/58450 Mute This Topic: https://groups.io/mt/73380291/1787277 Group Owner: devel+owner@edk2.groups.io Unsubscribe: https://edk2.groups.io/g/devel/unsub [importer@patchew.org] -=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D- From nobody Mon May 6 19:29:01 2024 Delivered-To: importer@patchew.org Received-SPF: pass (zohomail.com: domain of groups.io designates 66.175.222.12 as permitted sender) client-ip=66.175.222.12; envelope-from=bounce+27952+58451+1787277+3901457@groups.io; helo=web01.groups.io; Authentication-Results: mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of groups.io designates 66.175.222.12 as permitted sender) smtp.mailfrom=bounce+27952+58451+1787277+3901457@groups.io ARC-Seal: i=1; a=rsa-sha256; t=1588267022; cv=none; d=zohomail.com; s=zohoarc; b=OTR4gABKytkcMJapegZIVCmI3tEjxJShdiPZJSm8Ym0YgDSXdwNfF47jaHBld1wYMtrhJoGRj5k8ZPa5iOo1OcsVMBNc4mg+eVr3x9vX69Hvx+s/0i+WQeLcqL4zSpJ2Qhm+iozRVSykEpsPQINk1lRBOWTuhKmb04GIfut/q0Q= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1588267022; h=Cc:Date:From:In-Reply-To:List-Id:List-Unsubscribe:Message-ID:Reply-To:References:Sender:Subject:To; bh=TFsnklUpkRo6rWsHEr0fI9Z3KZt70F1gecYlgC1mCE0=; b=TmqFornHOf+7Xyl0kNCfdw0VsI1Ijw0bCwp0Au3bkVbx1u2P8B4cOk2M0xmWqPU80Idqr0cqSwZ7pS5KOnzDY9Z5BJ+RsyHg9nw3tNqGgLq54E7mcHbq0uoVzV6uoNlnN9irC75gTRQ3kBIbSRxBqbhGfocfM+EqncNG/LAdMCo= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of groups.io designates 66.175.222.12 as permitted sender) smtp.mailfrom=bounce+27952+58451+1787277+3901457@groups.io Received: from web01.groups.io (web01.groups.io [66.175.222.12]) by mx.zohomail.com with SMTPS id 1588267022913361.6387212159358; Thu, 30 Apr 2020 10:17:02 -0700 (PDT) Return-Path: X-Received: by 127.0.0.2 with SMTP id vrMbYY1788612x7U605zx61z; Thu, 30 Apr 2020 10:17:02 -0700 X-Received: from foss.arm.com (foss.arm.com [217.140.110.172]) by mx.groups.io with SMTP id smtpd.web12.753.1588267021841785083 for ; Thu, 30 Apr 2020 10:17:02 -0700 X-Received: from usa-sjc-imap-foss1.foss.arm.com (unknown [10.121.207.14]) by usa-sjc-mx-foss1.foss.arm.com (Postfix) with ESMTP id 71725101E; Thu, 30 Apr 2020 10:17:01 -0700 (PDT) X-Received: from e123331-lin.home (unknown [172.31.20.19]) by usa-sjc-imap-foss1.foss.arm.com (Postfix) with ESMTPSA id 4C7CF3F73D; Thu, 30 Apr 2020 10:17:00 -0700 (PDT) From: "Ard Biesheuvel" To: devel@edk2.groups.io Cc: leif@nuviainc.com, Ard Biesheuvel Subject: [edk2-devel] [PATCH edk2-platforms v3 3/8] Platform/ARM/JunoPkg: incorporate SiI3132 SATA controller driver Date: Thu, 30 Apr 2020 19:16:44 +0200 Message-Id: <20200430171650.24139-4-ard.biesheuvel@arm.com> In-Reply-To: <20200430171650.24139-1-ard.biesheuvel@arm.com> References: <20200430171650.24139-1-ard.biesheuvel@arm.com> Precedence: Bulk List-Unsubscribe: Sender: devel@edk2.groups.io List-Id: <27952.devel.edk2.groups.io> Mailing-List: list devel@edk2.groups.io; contact devel+owner@edk2.groups.io Reply-To: devel@edk2.groups.io,ard.biesheuvel@arm.com X-Gm-Message-State: XnWbaI89owwIYQAvOKIVXuRNx1787277AA= DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=groups.io; q=dns/txt; s=20140610; t=1588267022; bh=kq8Fp9lcMZSq+QDNj15l1k/L7CMjXl59YqYf4UdmGk8=; h=Cc:Date:From:Reply-To:Subject:To; b=Jf0wGPcbYN+LtSRDbhrmi8ND4oi5qQgujrR7RfTdqeL3uHz+xm7asvBtfPiPnR5Q8tp 9mQ+H/xwbWqzuqzzTszBOeBeNloFVUc1t0Hwbuyg98RoY2cn8fUFfKJ1snwD87bQ1n2MK qMsm7hRyluK4GW91IbtEusaVZ8SrvUjPIPk= X-ZohoMail-DKIM: pass (identity @groups.io) Content-Transfer-Encoding: quoted-printable MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Juno is the only user of the SiI3132 SATA controller driver, which is not quite fit for reuse in its current state. So incorporate it into JunoPkg so we will be able to drop it from the core EDK2 repository. Signed-off-by: Ard Biesheuvel Reviewed-by: Leif Lindholm --- Platform/ARM/JunoPkg/ArmJuno.dec | 4 +- Platform/ARM/JunoPkg/ArmJuno.dsc | 2 +- Platform/ARM/JunoPkg/ArmJuno.fdf | 2 +- Platform/ARM/JunoPkg/Drivers/SataSiI3132Dxe/ComponentName.c | 179 +++= ++ Platform/ARM/JunoPkg/Drivers/SataSiI3132Dxe/SataSiI3132.c | 546 +++= ++++++++++ Platform/ARM/JunoPkg/Drivers/SataSiI3132Dxe/SataSiI3132.h | 286 +++= ++++ Platform/ARM/JunoPkg/Drivers/SataSiI3132Dxe/SataSiI3132Dxe.inf | 38 + Platform/ARM/JunoPkg/Drivers/SataSiI3132Dxe/SiI3132AtaPassThru.c | 834 +++= +++++++++++++++++ 8 files changed, 1888 insertions(+), 3 deletions(-) diff --git a/Platform/ARM/JunoPkg/ArmJuno.dec b/Platform/ARM/JunoPkg/ArmJun= o.dec index 27fe75790721..37ea6857366f 100644 --- a/Platform/ARM/JunoPkg/ArmJuno.dec +++ b/Platform/ARM/JunoPkg/ArmJuno.dec @@ -28,6 +28,9 @@ [Guids.common] [PcdsFeatureFlag.common] gArmJunoTokenSpaceGuid.PcdPciMaxPayloadFixup|FALSE|BOOLEAN|0x00000013 =20 + gArmJunoTokenSpaceGuid.PcdSataSiI3132FeaturePMPSupport|FALSE|BOOLEAN|0x0= 0000018 + gArmJunoTokenSpaceGuid.PcdSataSiI3132FeatureDirectCommandIssuing|FALSE|B= OOLEAN|0x00000019 + [PcdsFixedAtBuild.common] gArmJunoTokenSpaceGuid.PcdPcieControlBaseAddress|0x7FF20000|UINT64|0x000= 0000B gArmJunoTokenSpaceGuid.PcdPcieRootPortBaseAddress|0x7FF30000|UINT64|0x00= 00000C @@ -54,4 +57,3 @@ [PcdsFixedAtBuild.common] # # For a list of mode numbers look in HdLcdArmJuno.c gArmJunoTokenSpaceGuid.PcdArmHdLcdMaxMode|0|UINT32|0x00000017 - diff --git a/Platform/ARM/JunoPkg/ArmJuno.dsc b/Platform/ARM/JunoPkg/ArmJun= o.dsc index 954faca1bbfa..1c39da4897ed 100644 --- a/Platform/ARM/JunoPkg/ArmJuno.dsc +++ b/Platform/ARM/JunoPkg/ArmJuno.dsc @@ -314,7 +314,7 @@ [Components.common] # SATA Controller # MdeModulePkg/Bus/Ata/AtaBusDxe/AtaBusDxe.inf - EmbeddedPkg/Drivers/SataSiI3132Dxe/SataSiI3132Dxe.inf + Platform/ARM/JunoPkg/Drivers/SataSiI3132Dxe/SataSiI3132Dxe.inf =20 # # NVMe boot devices diff --git a/Platform/ARM/JunoPkg/ArmJuno.fdf b/Platform/ARM/JunoPkg/ArmJun= o.fdf index 7c128b2c5bff..d771cbf35790 100644 --- a/Platform/ARM/JunoPkg/ArmJuno.fdf +++ b/Platform/ARM/JunoPkg/ArmJuno.fdf @@ -184,7 +184,7 @@ [FV.FvMain] # SATA Controller # INF MdeModulePkg/Bus/Ata/AtaBusDxe/AtaBusDxe.inf - INF EmbeddedPkg/Drivers/SataSiI3132Dxe/SataSiI3132Dxe.inf + INF Platform/ARM/JunoPkg/Drivers/SataSiI3132Dxe/SataSiI3132Dxe.inf =20 # # NVMe boot devices diff --git a/Platform/ARM/JunoPkg/Drivers/SataSiI3132Dxe/ComponentName.c b/= Platform/ARM/JunoPkg/Drivers/SataSiI3132Dxe/ComponentName.c new file mode 100644 index 000000000000..944e827f7170 --- /dev/null +++ b/Platform/ARM/JunoPkg/Drivers/SataSiI3132Dxe/ComponentName.c @@ -0,0 +1,179 @@ +/** @file + UEFI Component Name(2) protocol implementation for Silicon Image I3132 S= ATA controller + + WARNING: + This driver fails to follow the UEFI driver model without a good + reason, and only remains in the tree because it is still used by + a small number of platforms. It will be removed when no longer used. + New platforms should not use it, and no one should use this as + reference code for developing new drivers. + + Copyright (c) 2011-2020, ARM Limited. All rights reserved. + + SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include "SataSiI3132.h" + +// +// EFI Component Name Protocol +// +GLOBAL_REMOVE_IF_UNREFERENCED EFI_COMPONENT_NAME_PROTOCOL gSataSiI3132Com= ponentName =3D { + SataSiI3132ComponentNameGetDriverName, + SataSiI3132ComponentNameGetControllerName, + "eng" +}; + +// +// EFI Component Name 2 Protocol +// +GLOBAL_REMOVE_IF_UNREFERENCED EFI_COMPONENT_NAME2_PROTOCOL gSataSiI3132Com= ponentName2 =3D { + (EFI_COMPONENT_NAME2_GET_DRIVER_NAME) SataSiI3132ComponentNameGetDriverN= ame, + (EFI_COMPONENT_NAME2_GET_CONTROLLER_NAME) SataSiI3132ComponentNameGetCon= trollerName, + "en" +}; + + +GLOBAL_REMOVE_IF_UNREFERENCED EFI_UNICODE_STRING_TABLE mSataSiI3132DriverN= ameTable[] =3D { + { "eng;en", L"Pci SATA Silicon Image 3132 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 o= f 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 speci= fied + 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_PROTO= COL 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 calle= r 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 for= mat. + + @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 specifie= d by + This and the language specified by Languag= e 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 supp= ort + the language specified by Language. + +**/ +EFI_STATUS +EFIAPI +SataSiI3132ComponentNameGetDriverName ( + IN EFI_COMPONENT_NAME_PROTOCOL *This, + IN CHAR8 *Language, + OUT CHAR16 **DriverName + ) +{ + return LookupUnicodeString2 ( + Language, + This->SupportedLanguages, + mSataSiI3132DriverNameTable, + DriverName, + (BOOLEAN)(This =3D=3D &gSataSiI3132ComponentName) + ); +} + +/** + Retrieves a Unicode string that is the user readable name of the control= ler + that is being managed by a driver. + + This function retrieves the user readable name of the controller specifi= ed 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 specif= ied by + Language, then a pointer to the controller name is returned in Controlle= rName, + and EFI_SUCCESS is returned. If the driver specified by This is not cur= rently + 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 retu= rned. + + @param This[in] A pointer to the EFI_COMPONENT_NAME2_PROTO= COL 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 retr= ieve + the name of. This is an optional paramete= r that + may be NULL. It will be NULL for device + drivers. It will also be NULL for a bus d= rivers + 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 calle= r 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 specifie= d 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 a= nd + ChildHandle in the language specified by + Language from the point of view of the dri= ver + specified by This. + + @retval EFI_SUCCESS The Unicode string for the user readable n= ame 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 va= lid + 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 curren= tly + managing the controller specified by + ControllerHandle and ChildHandle. + + @retval EFI_UNSUPPORTED The driver specified by This does not supp= ort + the language specified by Language. + +**/ +EFI_STATUS +EFIAPI +SataSiI3132ComponentNameGetControllerName ( + IN EFI_COMPONENT_NAME_PROTOCOL *This, + IN EFI_HANDLE ControllerHandle, + IN EFI_HANDLE ChildHandle O= PTIONAL, + IN CHAR8 *Language, + OUT CHAR16 **ControllerName + ) +{ + return EFI_UNSUPPORTED; +} diff --git a/Platform/ARM/JunoPkg/Drivers/SataSiI3132Dxe/SataSiI3132.c b/Pl= atform/ARM/JunoPkg/Drivers/SataSiI3132Dxe/SataSiI3132.c new file mode 100644 index 000000000000..ad7cc1cd75a1 --- /dev/null +++ b/Platform/ARM/JunoPkg/Drivers/SataSiI3132Dxe/SataSiI3132.c @@ -0,0 +1,546 @@ +/** @file + PCIe Sata support for the Silicon Image I3132 + + WARNING: + This driver fails to follow the UEFI driver model without a good + reason, and only remains in the tree because it is still used by + a small number of platforms. It will be removed when no longer used. + New platforms should not use it, and no one should use this as + reference code for developing new drivers. + + Copyright (c) 2011-2020, ARM Limited. All rights reserved. + + SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include "SataSiI3132.h" + +#include + +#include +#include +#include +#include + +#define ACPI_SPECFLAG_PREFETCHABLE 0x06 + +EFI_DRIVER_BINDING_PROTOCOL +gSataSiI3132DriverBinding =3D { + SataSiI3132DriverBindingSupported, + SataSiI3132DriverBindingStart, + SataSiI3132DriverBindingStop, + 0x30, + NULL, + NULL +}; + +EFI_STATUS +SataSiI3132PortConstructor ( + IN SATA_SI3132_INSTANCE *SataSiI3132Instance, + IN UINTN Index + ) +{ + EFI_STATUS Status; + SATA_SI3132_PORT *Port; + VOID *HostPRB; + EFI_PHYSICAL_ADDRESS PhysAddrHostPRB; + VOID *PciAllocMappingPRB; + UINTN NumberOfBytes; + + Port =3D &(SataSiI3132Instance->Ports[Index]); + + Port->Index =3D Index; + Port->RegBase =3D Index * 0x2000; + Port->Instance =3D SataSiI3132Instance; + InitializeListHead (&(Port->Devices)); + + NumberOfBytes =3D sizeof (SATA_SI3132_PRB); + Status =3D SataSiI3132Instance->PciIo->AllocateBuffer ( + SataSiI3132Instance->PciIo, AllocateAnyPages, EfiBootServices= Data, + EFI_SIZE_TO_PAGES (NumberOfBytes), &HostPRB, 0 + ); + if (EFI_ERROR (Status)) { + return Status; + } + + // Check the alignment of the PCI Buffer + ASSERT (((UINTN)HostPRB & (0x1000 - 1)) =3D=3D 0); + Status =3D SataSiI3132Instance->PciIo->Map ( + SataSiI3132Instance->PciIo, EfiPciIoOperationBusMasterCommonB= uffer, HostPRB, + &NumberOfBytes, &PhysAddrHostPRB, &PciAllocMappingPRB + ); + if (EFI_ERROR (Status)) { + return Status; + } + + Port->HostPRB =3D HostPRB; + Port->PhysAddrHostPRB =3D PhysAddrHostPRB; + Port->PciAllocMappingPRB =3D PciAllocMappingPRB; + + return Status; +} + +STATIC +EFI_STATUS +SataSiI3132Constructor ( + IN EFI_PCI_IO_PROTOCOL *PciIo, + OUT SATA_SI3132_INSTANCE** SataSiI3132Instance + ) +{ + SATA_SI3132_INSTANCE *Instance; + EFI_ATA_PASS_THRU_MODE *AtaPassThruMode; + + if (!SataSiI3132Instance) { + return EFI_INVALID_PARAMETER; + } + + Instance =3D (SATA_SI3132_INSTANCE*)AllocateZeroPool (sizeof (SATA_SI313= 2_INSTANCE)); + if (Instance =3D=3D NULL) { + return EFI_OUT_OF_RESOURCES; + } + + Instance->Signature =3D SATA_SII3132_SIGNATURE; + Instance->PciIo =3D PciIo; + + AtaPassThruMode =3D (EFI_ATA_PASS_THRU_MODE*)AllocatePool (sizeof (EFI_A= TA_PASS_THRU_MODE)); + AtaPassThruMode->Attributes =3D EFI_ATA_PASS_THRU_ATTRIBUTES_PHYSICAL | = EFI_ATA_PASS_THRU_ATTRIBUTES_LOGICAL; + AtaPassThruMode->IoAlign =3D 0x1000; + + // Initialize SiI3132 ports + SataSiI3132PortConstructor (Instance, 0); + SataSiI3132PortConstructor (Instance, 1); + + // Set ATA Pass Thru Protocol + Instance->AtaPassThruProtocol.Mode =3D AtaPassThruMode; + Instance->AtaPassThruProtocol.PassThru =3D SiI3132AtaPassThru; + Instance->AtaPassThruProtocol.GetNextPort =3D SiI3132GetNextPort; + Instance->AtaPassThruProtocol.GetNextDevice =3D SiI3132GetNextDevice; + Instance->AtaPassThruProtocol.BuildDevicePath =3D SiI3132BuildDevicePath; + Instance->AtaPassThruProtocol.GetDevice =3D SiI3132GetDevice; + Instance->AtaPassThruProtocol.ResetPort =3D SiI3132ResetPort; + Instance->AtaPassThruProtocol.ResetDevice =3D SiI3132ResetDevice; + + *SataSiI3132Instance =3D Instance; + + return EFI_SUCCESS; +} + +EFI_STATUS +SiI3132SoftResetCommand ( + IN SATA_SI3132_PORT *Port, + OUT UINT32* Signature + ) +{ + EFI_STATUS Status; + EFI_ATA_PASS_THRU_COMMAND_PACKET Packet; + EFI_ATA_STATUS_BLOCK Asb; + EFI_ATA_COMMAND_BLOCK Acb; + CONST UINT16 PortMultiplierPort =3D 0; + + ZeroMem (&Acb, sizeof (EFI_ATA_COMMAND_BLOCK)); + + Acb.Reserved1[1] =3D 0; + + Packet.Asb =3D &Asb; + Packet.Acb =3D &Acb; + Packet.Timeout =3D 100000; + Packet.Protocol =3D EFI_ATA_PASS_THRU_PROTOCOL_ATA_SOFTWARE_RESET; + + Status =3D SiI3132AtaPassThruCommand (Port->Instance, Port, PortMultipli= erPort, &Packet, 0); + + if (Status =3D=3D EFI_SUCCESS) { + *Signature =3D (Asb.AtaCylinderHigh << 24) | (Asb.AtaCylinderLow << 16= ) | + (Asb.AtaSectorNumber << 8 ) | (Asb.AtaSectorCount); + } + return Status; +} + +EFI_STATUS +SataSiI3132PortInitialization ( + IN SATA_SI3132_PORT *Port + ) +{ + UINT32 Value32; + SATA_SI3132_DEVICE* Device; + UINT32 Signature; + EFI_STATUS Status; + EFI_PCI_IO_PROTOCOL* PciIo; + + Status =3D SiI3132HwResetPort (Port); + if (EFI_ERROR (Status)) { + return Status; + } + + PciIo =3D Port->Instance->PciIo; + + // Is a device is present ? + Status =3D SATA_PORT_READ32 (Port->RegBase + SII3132_PORT_SSTATUS_REG, &= Value32); + if (!EFI_ERROR (Status) && (Value32 & 0x3)) { + // Do a soft reset to see if it is a port multiplier + SATA_TRACE ("SataSiI3132PortInitialization: soft reset - it is a port = multiplier\n"); + Status =3D SiI3132SoftResetCommand (Port, &Signature); + if (!EFI_ERROR (Status)) { + if (Signature =3D=3D SII3132_PORT_SIGNATURE_PMP) { + SATA_TRACE ("SataSiI3132PortInitialization(): a Port Multiplier is= present"); + if (FeaturePcdGet (PcdSataSiI3132FeaturePMPSupport)) { + ASSERT (0); // Not supported yet + } else { + return EFI_UNSUPPORTED; + } + } else if (Signature =3D=3D SII3132_PORT_SIGNATURE_ATAPI) { + ASSERT (0); // Not supported yet + SATA_TRACE ("SataSiI3132PortInitialization(): an ATAPI device is p= resent"); + return EFI_UNSUPPORTED; + } else if (Signature =3D=3D SII3132_PORT_SIGNATURE_ATA) { + SATA_TRACE ("SataSiI3132PortInitialization(): an ATA device is pre= sent"); + } else { + SATA_TRACE ("SataSiI3132PortInitialization(): Present device unkno= wn!"); + ASSERT (0); // Not supported + return EFI_UNSUPPORTED; + } + + // Create Device + Device =3D (SATA_SI3132_DEVICE*)AllocatePool (sizeof (SAT= A_SI3132_DEVICE)); + Device->Index =3D Port->Index; //TODO: Could need to be fixed wh= en SATA Port Multiplier support + Device->Port =3D Port; + Device->BlockSize =3D 0; + + // Attached the device to the Sata Port + InsertTailList (&Port->Devices, &Device->Link); + + SATA_TRACE ("SataSiI3132PortInitialization(): Port Ready"); + } + } + return Status; +} + +EFI_STATUS +SataSiI3132Initialization ( + IN SATA_SI3132_INSTANCE* SataSiI3132Instance + ) +{ + UINTN Index; + EFI_PCI_IO_PROTOCOL* PciIo; + + if (!SataSiI3132Instance) { + return EFI_INVALID_PARAMETER; + } + + PciIo =3D SataSiI3132Instance->PciIo; + + // Turn Off GPIO + SATA_GLOBAL_WRITE32 (SII3132_GLOBAL_FLASHADDR_REG, 0x0); + + // Clear Global Control Register + SATA_GLOBAL_WRITE32 (SII3132_GLOBAL_CONTROL_REG, 0x0); + + for (Index =3D 0; Index < SATA_SII3132_MAXPORT; Index++) { + SataSiI3132PortInitialization (&(SataSiI3132Instance->Ports[Index])); + } + + return EFI_SUCCESS; +} + +/** + Test to see if this driver supports ControllerHandle. + + @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 +SataSiI3132DriverBindingSupported ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE Controller, + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath + ) +{ + EFI_STATUS Status; + EFI_PCI_IO_PROTOCOL *PciIo; + UINT32 PciID; + + // + // Test whether there is PCI IO Protocol attached on the controller hand= le. + // + Status =3D gBS->OpenProtocol ( + Controller, + &gEfiPciIoProtocolGuid, + (VOID **) &PciIo, + This->DriverBindingHandle, + Controller, + EFI_OPEN_PROTOCOL_BY_DRIVER + ); + if (EFI_ERROR (Status)) { + return Status; + } + + Status =3D PciIo->Pci.Read ( + PciIo, + EfiPciIoWidthUint32, + PCI_VENDOR_ID_OFFSET, + 1, + &PciID + ); + if (EFI_ERROR (Status)) { + Status =3D EFI_UNSUPPORTED; + goto ON_EXIT; + } + + // + // Test whether the controller belongs to SATA Mass Storage type + // + if (PciID !=3D ((SATA_SII3132_DEVICE_ID << 16) | SATA_SII3132_VENDOR_ID)= ) { + Status =3D EFI_UNSUPPORTED; + } + +ON_EXIT: + gBS->CloseProtocol ( + Controller, + &gEfiPciIoProtocolGuid, + This->DriverBindingHandle, + Controller + ); + + return Status; +} + +BOOLEAN mbStarted =3D FALSE; + +/** + Starting the Pci SATA 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 +SataSiI3132DriverBindingStart ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE Controller, + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath + ) +{ + EFI_STATUS Status; + EFI_PCI_IO_PROTOCOL *PciIo; + UINT64 Supports; + UINT64 OriginalPciAttributes; + BOOLEAN PciAttributesSaved; + UINT32 PciID; + SATA_SI3132_INSTANCE *SataSiI3132Instance =3D NULL; + + SATA_TRACE ("SataSiI3132DriverBindingStart()"); + + //TODO: Find a nicer way to do it ! + if (mbStarted) { + return EFI_SUCCESS; // Don't restart me ! + } + + // + // Open the PciIo Protocol + // + Status =3D gBS->OpenProtocol ( + Controller, + &gEfiPciIoProtocolGuid, + (VOID **) &PciIo, + This->DriverBindingHandle, + Controller, + EFI_OPEN_PROTOCOL_BY_DRIVER + ); + if (EFI_ERROR (Status)) { + return Status; + } + + PciAttributesSaved =3D FALSE; + // + // Save original PCI attributes + // + Status =3D PciIo->Attributes ( + PciIo, + EfiPciIoAttributeOperationGet, + 0, + &OriginalPciAttributes + ); + if (EFI_ERROR (Status)) { + goto CLOSE_PCIIO; + } + PciAttributesSaved =3D TRUE; + + Status =3D PciIo->Attributes ( + PciIo, + EfiPciIoAttributeOperationSupported, + 0, + &Supports + ); + if (!EFI_ERROR (Status)) { + Supports &=3D EFI_PCI_DEVICE_ENABLE | EFI_PCI_IO_ATTRIBUTE_DUAL_ADDR= ESS_CYCLE; + Status =3D PciIo->Attributes ( + PciIo, + EfiPciIoAttributeOperationEnable, + Supports, + NULL + ); + } + if (EFI_ERROR (Status)) { + DEBUG ((EFI_D_ERROR, "SataSiI3132DriverBindingStart: failed to enable = controller\n")); + goto CLOSE_PCIIO; + } + + // + // Get the Pci device class code. + // + Status =3D PciIo->Pci.Read ( + PciIo, + EfiPciIoWidthUint32, + PCI_VENDOR_ID_OFFSET, + 1, + &PciID + ); + if (EFI_ERROR (Status)) { + Status =3D EFI_UNSUPPORTED; + goto CLOSE_PCIIO; + } + + // + // Test whether the controller belongs to SATA Mass Storage type + // + if (PciID !=3D ((SATA_SII3132_DEVICE_ID << 16) | SATA_SII3132_VENDOR_ID)= ) { + Status =3D EFI_UNSUPPORTED; + goto CLOSE_PCIIO; + } + + // Create SiI3132 Sata Instance + Status =3D SataSiI3132Constructor (PciIo, &SataSiI3132Instance); + if (EFI_ERROR (Status)) { + return Status; + } + + // Initialize SiI3132 Sata Controller + Status =3D SataSiI3132Initialization (SataSiI3132Instance); + if (EFI_ERROR (Status)) { + return Status; + } + + // Install Ata Pass Thru Protocol + Status =3D gBS->InstallProtocolInterface ( + &Controller, + &gEfiAtaPassThruProtocolGuid, + EFI_NATIVE_INTERFACE, + &(SataSiI3132Instance->AtaPassThruProtocol) + ); + if (EFI_ERROR (Status)) { + goto FREE_POOL; + } + +/* // + // Create event to stop the HC when exit boot service. + // + Status =3D gBS->CreateEventEx ( + EVT_NOTIFY_SIGNAL, + TPL_NOTIFY, + EhcExitBootService, + Ehc, + &gEfiEventExitBootServicesGuid, + &Ehc->ExitBootServiceEvent + ); + if (EFI_ERROR (Status)) { + goto UNINSTALL_USBHC; + }*/ + + mbStarted =3D TRUE; + + SATA_TRACE ("SataSiI3132DriverBindingStart() Success!"); + return EFI_SUCCESS; + +FREE_POOL: + //TODO: Free SATA Instance + +CLOSE_PCIIO: + if (PciAttributesSaved) { + // + // Restore original PCI attributes + // + PciIo->Attributes ( + PciIo, + EfiPciIoAttributeOperationSet, + OriginalPciAttributes, + NULL + ); + } + + gBS->CloseProtocol ( + Controller, + &gEfiPciIoProtocolGuid, + This->DriverBindingHandle, + Controller + ); + + 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 +SataSiI3132DriverBindingStop ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE Controller, + IN UINTN NumberOfChildren, + IN EFI_HANDLE *ChildHandleBuffer + ) +{ + SATA_TRACE ("SataSiI3132DriverBindingStop()"); + return EFI_UNSUPPORTED; +} + +/** + Entry point of this driver + + @param ImageHandle Handle of driver image + @param SystemTable Point to EFI_SYSTEM_TABLE + + @retval EFI_OUT_OF_RESOURCES Can not allocate memory resource + @retval EFI_DEVICE_ERROR Can not install the protocol instance + @retval EFI_SUCCESS Success to initialize the Pci host bridge. +**/ +EFI_STATUS +EFIAPI +InitializeSataSiI3132 ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + SATA_TRACE ("InitializeSataSiI3132 ()"); + + return EfiLibInstallDriverBindingComponentName2 ( + ImageHandle, + SystemTable, + &gSataSiI3132DriverBinding, + ImageHandle, + &gSataSiI3132ComponentName, + &gSataSiI3132ComponentName2 + ); +} diff --git a/Platform/ARM/JunoPkg/Drivers/SataSiI3132Dxe/SataSiI3132.h b/Pl= atform/ARM/JunoPkg/Drivers/SataSiI3132Dxe/SataSiI3132.h new file mode 100644 index 000000000000..f799fe84a047 --- /dev/null +++ b/Platform/ARM/JunoPkg/Drivers/SataSiI3132Dxe/SataSiI3132.h @@ -0,0 +1,286 @@ +/** @file + Header containing the structure specific to the Silicon Image I3132 Sata= PCI card + + WARNING: + This driver fails to follow the UEFI driver model without a good + reason, and only remains in the tree because it is still used by + a small number of platforms. It will be removed when no longer used. + New platforms should not use it, and no one should use this as + reference code for developing new drivers. + + Copyright (c) 2011-2020, ARM Limited. All rights reserved. + + SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#ifndef __SATASII3132_H +#define __SATASII3132_H + +#include + +#include +#include + +#include +#include +#include +#include +#include + +#include + +#define SATA_SII3132_DEVICE_ID 0x3132 +#define SATA_SII3132_VENDOR_ID 0x1095 + +#define SII3132_PORT_SIGNATURE_PMP 0x96690101 +#define SII3132_PORT_SIGNATURE_ATAPI 0xEB140101 +#define SII3132_PORT_SIGNATURE_ATA 0x00000101 + +/* + * Silicon Image SiI3132 Registers + */ +#define SII3132_GLOBAL_CONTROL_REG 0x40 +#define SII3132_GLOBAL_FLASHADDR_REG 0x70 + +#define SII3132_PORT_STATUS_REG 0x1000 +#define SII3132_PORT_CONTROLSET_REG 0x1000 +#define SII3132_PORT_CONTROLCLEAR_REG 0x1004 +#define SII3132_PORT_INTSTATUS_REG 0x1008 +#define SII3132_PORT_ENABLEINT_REG 0x1010 +#define SII3132_PORT_INTCLEAR_REG 0x1014 +#define SII3132_PORT_32BITACTIVADDR_REG 0x101C +#define SII3132_PORT_CMDEXECFIFO_REG 0x1020 +#define SII3132_PORT_CMDERROR_REG 0x1024 +#define SII3132_PORT_ERRCOUNTDECODE 0x1040 +#define SII3132_PORT_ERRCOUNTCRC 0x1044 +#define SII3132_PORT_ERRCOUNTHANDSHAKE 0x1048 +#define SII3132_PORT_SLOTSTATUS_REG 0x1800 +#define SII3132_PORT_CMDACTIV_REG 0x1C00 +#define SII3132_PORT_SSTATUS_REG 0x1F04 + +#define SII3132_PORT_CONTROL_RESET (1 << 0) +#define SII3132_PORT_DEVICE_RESET (1 << 1) +#define SII3132_PORT_CONTROL_INT (1 << 2) +#define SII3132_PORT_CONTROL_32BITACTIVATION (1 << 10) + +#define SII3132_PORT_STATUS_PORTREADY 0x80000000 + +#define SII3132_PORT_INT_CMDCOMPL (1 << 0) +#define SII3132_PORT_INT_CMDERR (1 << 1) +#define SII3132_PORT_INT_PORTRDY (1 << 2) + +#define SATA_SII3132_MAXPORT 2 + +#define PRB_CTRL_ATA 0x0 +#define PRB_CTRL_PROT_OVERRIDE 0x1 +#define PRB_CTRL_RESTRANSMIT 0x2 +#define PRB_CTRL_EXT_CMD 0x4 +#define PRB_CTRL_RCV 0x8 +#define PRB_CTRL_PKT_READ 0x10 +#define PRB_CTRL_PKT_WRITE 0x20 +#define PRB_CTRL_INT_MASK 0x40 +#define PRB_CTRL_SRST 0x80 + +#define PRB_PROT_PACKET 0x01 +#define PRB_PROT_LEGACY_QUEUE 0x02 +#define PRB_PROT_NATIVE_QUEUE 0x04 +#define PRB_PROT_READ 0x08 +#define PRB_PROT_WRITE 0x10 +#define PRB_PROT_TRANSPARENT 0x20 + +#define SGE_XCF (1 << 28) +#define SGE_DRD (1 << 29) +#define SGE_LNK (1 << 30) +#define SGE_TRM 0x80000000 + +typedef struct _SATA_SI3132_SGE { + UINT32 DataAddressLow; + UINT32 DataAddressHigh; + UINT32 DataCount; + UINT32 Attributes; +} SATA_SI3132_SGE; + +typedef struct _SATA_SI3132_FIS { + UINT8 FisType; + UINT8 Control; + UINT8 Command; + UINT8 Features; + UINT8 Fis[5 * 4]; +} SATA_SI3132_FIS; + +typedef struct _SATA_SI3132_PRB { + UINT16 Control; + UINT16 ProtocolOverride; + UINT32 RecTransCount; + SATA_SI3132_FIS Fis; + SATA_SI3132_SGE Sge[2]; +} SATA_SI3132_PRB; + +typedef struct _SATA_SI3132_DEVICE { + LIST_ENTRY Link; // This attribute must be the first = entry of this structure (to avoid pointer computation) + UINTN Index; + struct _SATA_SI3132_PORT *Port; //Parent Port + UINT32 BlockSize; +} SATA_SI3132_DEVICE; + +typedef struct _SATA_SI3132_PORT { + UINTN Index; + UINTN RegBase; + struct _SATA_SI3132_INSTANCE *Instance; + + //TODO: Support Port multiplier + LIST_ENTRY Devices; + + SATA_SI3132_PRB* HostPRB; + EFI_PHYSICAL_ADDRESS PhysAddrHostPRB; + VOID* PciAllocMappingPRB; +} SATA_SI3132_PORT; + +typedef struct _SATA_SI3132_INSTANCE { + UINTN Signature; + + SATA_SI3132_PORT Ports[SATA_SII3132_MAXPORT]; + + EFI_ATA_PASS_THRU_PROTOCOL AtaPassThruProtocol; + + EFI_PCI_IO_PROTOCOL *PciIo; +} SATA_SI3132_INSTANCE; + +#define SATA_SII3132_SIGNATURE SIGNATURE_32('s', 'i', '3', '2= ') +#define INSTANCE_FROM_ATAPASSTHRU_THIS(a) CR(a, SATA_SI3132_INSTANCE, At= aPassThruProtocol, SATA_SII3132_SIGNATURE) + +#define SATA_GLOBAL_READ32(Offset, Value) PciIo->Mem.Read (PciIo, EfiPciI= oWidthUint32, 0, Offset, 1, Value) +#define SATA_GLOBAL_WRITE32(Offset, Value) { UINT32 Value32 =3D Value; Pci= Io->Mem.Write (PciIo, EfiPciIoWidthUint32, 0, Offset, 1, &Value32); } + +#define SATA_PORT_READ32(Offset, Value) PciIo->Mem.Read (PciIo, EfiPciIoW= idthUint32, 1, Offset, 1, Value) +#define SATA_PORT_WRITE32(Offset, Value) { UINT32 Value32 =3D Value; PciIo= ->Mem.Write (PciIo, EfiPciIoWidthUint32, 1, Offset, 1, &Value32); } + +#define SATA_TRACE(txt) DEBUG((EFI_D_VERBOSE, "ARM_SATA: " txt "\n")) + +extern EFI_COMPONENT_NAME_PROTOCOL gSataSiI3132ComponentName; +extern EFI_COMPONENT_NAME2_PROTOCOL gSataSiI3132ComponentName2; + +/* + * Component Name Protocol Functions + */ +EFI_STATUS +EFIAPI +SataSiI3132ComponentNameGetDriverName ( + IN EFI_COMPONENT_NAME_PROTOCOL *This, + IN CHAR8 *Language, + OUT CHAR16 **DriverName + ); + +EFI_STATUS +EFIAPI +SataSiI3132ComponentNameGetControllerName ( + IN EFI_COMPONENT_NAME_PROTOCOL *This, + IN EFI_HANDLE ControllerHandle, + IN EFI_HANDLE ChildHandle O= PTIONAL, + IN CHAR8 *Language, + OUT CHAR16 **ControllerName + ); + +EFI_STATUS SiI3132HwResetPort (SATA_SI3132_PORT *Port); + +/* + * Driver Binding Protocol Functions + */ +EFI_STATUS +EFIAPI +SataSiI3132DriverBindingSupported ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE Controller, + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath + ); + +EFI_STATUS +EFIAPI +SataSiI3132DriverBindingStart ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE Controller, + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath + ); + +EFI_STATUS +EFIAPI +SataSiI3132DriverBindingStop ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE Controller, + IN UINTN NumberOfChildren, + IN EFI_HANDLE *ChildHandleBuffer + ); + +EFI_STATUS +EFIAPI +SiI3132AtaPassThruCommand ( + IN SATA_SI3132_INSTANCE *pSataSiI3132Instance, + IN SATA_SI3132_PORT *pSataPort, + IN UINT16 PortMultiplierPort, + IN OUT EFI_ATA_PASS_THRU_COMMAND_PACKET *Packet, + IN EFI_EVENT Event OPTIONAL + ); + +/** + * EFI ATA Pass Thru Protocol + */ +EFI_STATUS +EFIAPI +SiI3132AtaPassThru ( + IN EFI_ATA_PASS_THRU_PROTOCOL *This, + IN UINT16 Port, + IN UINT16 PortMultiplierPort, + IN OUT EFI_ATA_PASS_THRU_COMMAND_PACKET *Packet, + IN EFI_EVENT Event OPTIONAL + ); + +EFI_STATUS +EFIAPI +SiI3132GetNextPort ( + IN EFI_ATA_PASS_THRU_PROTOCOL *This, + IN OUT UINT16 *Port + ); + +EFI_STATUS +EFIAPI +SiI3132GetNextDevice ( + IN EFI_ATA_PASS_THRU_PROTOCOL *This, + IN UINT16 Port, + IN OUT UINT16 *PortMultiplierPort + ); + +EFI_STATUS +EFIAPI +SiI3132BuildDevicePath ( + IN EFI_ATA_PASS_THRU_PROTOCOL *This, + IN UINT16 Port, + IN UINT16 PortMultiplierPort, + IN OUT EFI_DEVICE_PATH_PROTOCOL **DevicePath + ); + +EFI_STATUS +EFIAPI +SiI3132GetDevice ( + IN EFI_ATA_PASS_THRU_PROTOCOL *This, + IN EFI_DEVICE_PATH_PROTOCOL *DevicePath, + OUT UINT16 *Port, + OUT UINT16 *PortMultiplierPort + ); + +EFI_STATUS +EFIAPI +SiI3132ResetPort ( + IN EFI_ATA_PASS_THRU_PROTOCOL *This, + IN UINT16 Port + ); + +EFI_STATUS +EFIAPI +SiI3132ResetDevice ( + IN EFI_ATA_PASS_THRU_PROTOCOL *This, + IN UINT16 Port, + IN UINT16 PortMultiplierPort + ); + +#endif diff --git a/Platform/ARM/JunoPkg/Drivers/SataSiI3132Dxe/SataSiI3132Dxe.inf= b/Platform/ARM/JunoPkg/Drivers/SataSiI3132Dxe/SataSiI3132Dxe.inf new file mode 100644 index 000000000000..a73b3bc168a8 --- /dev/null +++ b/Platform/ARM/JunoPkg/Drivers/SataSiI3132Dxe/SataSiI3132Dxe.inf @@ -0,0 +1,38 @@ +#/** @file +# INF file for the Silicon Image I3132 SATA controller +# +# Copyright (c) 2011-2020, ARM Limited. All rights reserved. +# +# SPDX-License-Identifier: BSD-2-Clause-Patent +# +#**/ + +[Defines] + INF_VERSION =3D 1.27 + BASE_NAME =3D SataSiI3132Dxe + FILE_GUID =3D 1df18da0-a18b-11df-8c3a-0002a5d5c51b + MODULE_TYPE =3D UEFI_DRIVER + VERSION_STRING =3D 1.0 + ENTRY_POINT =3D InitializeSataSiI3132 + +[Packages] + MdePkg/MdePkg.dec + Platform/ARM/JunoPkg/ArmJuno.dec + +[LibraryClasses] + MemoryAllocationLib + UefiDriverEntryPoint + UefiLib + +[Sources] + ComponentName.c + SataSiI3132.c + SiI3132AtaPassThru.c + +[Protocols] + gEfiPciIoProtocolGuid # CONSUMED + gEfiAtaPassThruProtocolGuid # PRODUCED + +[Pcd] + gArmJunoTokenSpaceGuid.PcdSataSiI3132FeaturePMPSupport + gArmJunoTokenSpaceGuid.PcdSataSiI3132FeatureDirectCommandIssuing diff --git a/Platform/ARM/JunoPkg/Drivers/SataSiI3132Dxe/SiI3132AtaPassThru= .c b/Platform/ARM/JunoPkg/Drivers/SataSiI3132Dxe/SiI3132AtaPassThru.c new file mode 100644 index 000000000000..f15b59788310 --- /dev/null +++ b/Platform/ARM/JunoPkg/Drivers/SataSiI3132Dxe/SiI3132AtaPassThru.c @@ -0,0 +1,834 @@ +/** @file + + WARNING: + This driver fails to follow the UEFI driver model without a good + reason, and only remains in the tree because it is still used by + a small number of platforms. It will be removed when no longer used. + New platforms should not use it, and no one should use this as + reference code for developing new drivers. + + Copyright (c) 2011-2020, ARM Limited. All rights reserved. + + SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include "SataSiI3132.h" + +#include +#include + +SATA_SI3132_DEVICE* +GetSataDevice ( + IN SATA_SI3132_INSTANCE* SataInstance, + IN UINT16 Port, + IN UINT16 PortMultiplierPort +) { + LIST_ENTRY *List; + SATA_SI3132_PORT *SataPort; + SATA_SI3132_DEVICE *SataDevice; + + if (Port >=3D SATA_SII3132_MAXPORT) { + return NULL; + } + + SataPort =3D &(SataInstance->Ports[Port]); + List =3D SataPort->Devices.ForwardLink; + + while (List !=3D &SataPort->Devices) { + SataDevice =3D (SATA_SI3132_DEVICE*)List; + if (SataDevice->Index =3D=3D PortMultiplierPort) { + return SataDevice; + } + List =3D List->ForwardLink; + } + return NULL; +} + +EFI_STATUS +EFIAPI +SiI3132AtaPassThruCommand ( + IN SATA_SI3132_INSTANCE *SataSiI3132Instance, + IN SATA_SI3132_PORT *SataPort, + IN UINT16 PortMultiplierPort, + IN OUT EFI_ATA_PASS_THRU_COMMAND_PACKET *Packet, + IN EFI_EVENT Event OPTIONAL + ) +{ + SATA_SI3132_DEVICE *SataDevice; + EFI_PHYSICAL_ADDRESS PhysInDataBuffer; + UINTN InDataBufferLength =3D 0; + EFI_PHYSICAL_ADDRESS PhysOutDataBuffer; + UINTN OutDataBufferLength; + CONST UINTN EmptySlot =3D 0; + UINTN Control =3D PRB_CTRL_ATA; + UINTN Protocol =3D 0; + UINT32 Value32, Error, Timeout =3D 0; + CONST UINT32 IrqMask =3D (SII3132_PORT_INT_CMDCOMPL | SII3132= _PORT_INT_CMDERR) << 16; + EFI_STATUS Status; + VOID* PciAllocMapping =3D NULL; + EFI_PCI_IO_PROTOCOL *PciIo; + + PciIo =3D SataSiI3132Instance->PciIo; + ZeroMem (SataPort->HostPRB, sizeof (SATA_SI3132_PRB)); + + // Construct Si3132 PRB + switch (Packet->Protocol) { + case EFI_ATA_PASS_THRU_PROTOCOL_ATA_HARDWARE_RESET: + ASSERT (0); //TODO: Implement me! + break; + case EFI_ATA_PASS_THRU_PROTOCOL_ATA_SOFTWARE_RESET: + SATA_TRACE ("SiI3132AtaPassThru() EFI_ATA_PASS_THRU_PROTOCOL_ATA_SOFTW= ARE_RESET"); + Control =3D PRB_CTRL_SRST; + + if (FeaturePcdGet (PcdSataSiI3132FeaturePMPSupport)) { + SataPort->HostPRB->Fis.Control =3D 0x0F; + } + break; + case EFI_ATA_PASS_THRU_PROTOCOL_ATA_NON_DATA: + ASSERT (0); //TODO: Implement me! + break; + + // There is no difference for SiI3132 between PIO and DMA invokation + case EFI_ATA_PASS_THRU_PROTOCOL_UDMA_DATA_IN: + case EFI_ATA_PASS_THRU_PROTOCOL_PIO_DATA_IN: + // Fixup the size for block transfer. Following UEFI Specification, 'I= nTransferLength' should + // be in number of bytes. But for most data transfer commands, the val= ue is in number of blocks + if (Packet->Acb->AtaCommand =3D=3D ATA_CMD_IDENTIFY_DRIVE) { + InDataBufferLength =3D Packet->InTransferLength; + } else { + SataDevice =3D GetSataDevice (SataSiI3132Instance, SataPort->Index, = PortMultiplierPort); + if (!SataDevice || (SataDevice->BlockSize =3D=3D 0)) { + return EFI_INVALID_PARAMETER; + } + + InDataBufferLength =3D Packet->InTransferLength * SataDevice->BlockS= ize; + } + + Status =3D PciIo->Map ( + PciIo, EfiPciIoOperationBusMasterWrite, + Packet->InDataBuffer, &InDataBufferLength, &PhysInDataBuffe= r, &PciAllocMapping + ); + if (EFI_ERROR (Status)) { + return Status; + } + + // Construct SGEs (32-bit system) + SataPort->HostPRB->Sge[0].DataAddressLow =3D (UINT32)PhysInDataBuffer; + SataPort->HostPRB->Sge[0].DataAddressHigh =3D (UINT32)(PhysInDataBuffe= r >> 32); + SataPort->HostPRB->Sge[0].Attributes =3D SGE_TRM; // Only one SGE + SataPort->HostPRB->Sge[0].DataCount =3D InDataBufferLength; + + // Copy the Ata Command Block + CopyMem (&SataPort->HostPRB->Fis, Packet->Acb, sizeof (EFI_ATA_COMMAND= _BLOCK)); + + // Fixup the FIS + SataPort->HostPRB->Fis.FisType =3D 0x27; // Register - Host to Device = FIS + SataPort->HostPRB->Fis.Control =3D 1 << 7; // Is a command + if (FeaturePcdGet (PcdSataSiI3132FeaturePMPSupport)) { + SataPort->HostPRB->Fis.Control |=3D PortMultiplierPort & 0xFF; + } + break; + case EFI_ATA_PASS_THRU_PROTOCOL_UDMA_DATA_OUT: + case EFI_ATA_PASS_THRU_PROTOCOL_PIO_DATA_OUT: + SataDevice =3D GetSataDevice (SataSiI3132Instance, SataPort->Index, Po= rtMultiplierPort); + if (!SataDevice || (SataDevice->BlockSize =3D=3D 0)) { + return EFI_INVALID_PARAMETER; + } + + // Fixup the size for block transfer. Following UEFI Specification, 'I= nTransferLength' should + // be in number of bytes. But for most data transfer commands, the val= ue is in number of blocks + OutDataBufferLength =3D Packet->OutTransferLength * SataDevice->BlockS= ize; + + Status =3D PciIo->Map ( + PciIo, EfiPciIoOperationBusMasterRead, + Packet->OutDataBuffer, &OutDataBufferLength, &PhysOutDataBu= ffer, &PciAllocMapping + ); + if (EFI_ERROR (Status)) { + return Status; + } + + // Construct SGEs (32-bit system) + SataPort->HostPRB->Sge[0].DataAddressLow =3D (UINT32)PhysOutDataBuffe= r; + SataPort->HostPRB->Sge[0].DataAddressHigh =3D (UINT32)(PhysOutDataBuff= er >> 32); + SataPort->HostPRB->Sge[0].Attributes =3D SGE_TRM; // Only one SGE + SataPort->HostPRB->Sge[0].DataCount =3D OutDataBufferLength; + + // Copy the Ata Command Block + CopyMem (&SataPort->HostPRB->Fis, Packet->Acb, sizeof (EFI_ATA_COMMAND= _BLOCK)); + + // Fixup the FIS + SataPort->HostPRB->Fis.FisType =3D 0x27; // Register - Host to Device = FIS + SataPort->HostPRB->Fis.Control =3D 1 << 7; // Is a command + if (FeaturePcdGet (PcdSataSiI3132FeaturePMPSupport)) { + SataPort->HostPRB->Fis.Control |=3D PortMultiplierPort & 0xFF; + } + break; + case EFI_ATA_PASS_THRU_PROTOCOL_DMA: + ASSERT (0); //TODO: Implement me! + break; + case EFI_ATA_PASS_THRU_PROTOCOL_DMA_QUEUED: + ASSERT (0); //TODO: Implement me! + break; + case EFI_ATA_PASS_THRU_PROTOCOL_DEVICE_DIAGNOSTIC: + ASSERT (0); //TODO: Implement me! + break; + case EFI_ATA_PASS_THRU_PROTOCOL_DEVICE_RESET: + ASSERT (0); //TODO: Implement me! + break; + case EFI_ATA_PASS_THRU_PROTOCOL_FPDMA: + ASSERT (0); //TODO: Implement me! + break; + case EFI_ATA_PASS_THRU_PROTOCOL_RETURN_RESPONSE: + ASSERT (0); //TODO: Implement me! + break; + default: + ASSERT (0); + break; + } + + SataPort->HostPRB->Control =3D Control; + SataPort->HostPRB->ProtocolOverride =3D Protocol; + + // Clear IRQ + SATA_PORT_WRITE32 (SataPort->RegBase + SII3132_PORT_INTSTATUS_REG, IrqMa= sk); + + if (!FeaturePcdGet (PcdSataSiI3132FeatureDirectCommandIssuing)) { + // Indirect Command Issuance + + //TODO: Find which slot is free (maybe use the Cmd FIFO) + //SATA_PORT_READ32 (SataPort->RegBase + SII3132_PORT_CMDEXECFIFO_REG, = &EmptySlot); + + SATA_PORT_WRITE32 (SataPort->RegBase + SII3132_PORT_CMDACTIV_REG + (Em= ptySlot * 8), + (UINT32)(SataPort->PhysAddrHostPRB & 0xFFFFFFFF)); + SATA_PORT_WRITE32 (SataPort->RegBase + SII3132_PORT_CMDACTIV_REG + (Em= ptySlot * 8) + 4, + (UINT32)((SataPort->PhysAddrHostPRB >> 32) & 0xFFFFFF= FF)); + } else { + // Direct Command Issuance + Status =3D PciIo->Mem.Write (PciIo, EfiPciIoWidthUint32, 1, // Bar 1 + SataPort->RegBase + (EmptySlot * 0x80), + sizeof (SATA_SI3132_PRB) / 4, + SataPort->HostPRB); + ASSERT_EFI_ERROR (Status); + + SATA_PORT_WRITE32 (SataPort->RegBase + SII3132_PORT_CMDEXECFIFO_REG, E= mptySlot); + } + +#if 0 + // Could need to be implemented if we run multiple command in parallel t= o know which slot has been completed + SATA_PORT_READ32 (SataPort->RegBase + SII3132_PORT_SLOTSTATUS_REG, &Valu= e32); + Timeout =3D Packet->Timeout; + while (!Timeout && !Value32) { + gBS->Stall (1); + SATA_PORT_READ32 (SataPort->RegBase + SII3132_PORT_SLOTSTATUS_REG, &Va= lue32); + Timeout--; + } +#else + SATA_PORT_READ32 (SataPort->RegBase + SII3132_PORT_INTSTATUS_REG, &Value= 32); + if (!Packet->Timeout) { + while (!(Value32 & IrqMask)) { + gBS->Stall (1); + SATA_PORT_READ32 (SataPort->RegBase + SII3132_PORT_INTSTATUS_REG, &V= alue32); + } + } else { + Timeout =3D Packet->Timeout; + while (Timeout && !(Value32 & IrqMask)) { + gBS->Stall (1); + SATA_PORT_READ32 (SataPort->RegBase + SII3132_PORT_INTSTATUS_REG, &V= alue32); + Timeout--; + } + } +#endif + // Fill Packet Ata Status Block + Status =3D PciIo->Mem.Read (PciIo, EfiPciIoWidthUint32, 1, // Bar 1 + SataPort->RegBase + 0x08, + sizeof (EFI_ATA_STATUS_BLOCK) / 4, + Packet->Asb); + ASSERT_EFI_ERROR (Status); + + + if ((Packet->Timeout !=3D 0) && (Timeout =3D=3D 0)) { + DEBUG ((EFI_D_ERROR, "SiI3132AtaPassThru() Err:Timeout\n")); + //ASSERT (0); + return EFI_TIMEOUT; + } else if (Value32 & (SII3132_PORT_INT_CMDERR << 16)) { + SATA_PORT_READ32 (SataPort->RegBase + SII3132_PORT_CMDERROR_REG, &Erro= r); + DEBUG ((EFI_D_ERROR, "SiI3132AtaPassThru() CmdErr:0x%X (SiI3132 Err:0x= %X)\n", Value32, Error)); + ASSERT (0); + return EFI_DEVICE_ERROR; + } else if (Value32 & (SII3132_PORT_INT_CMDCOMPL << 16)) { + // Clear Command Complete + SATA_PORT_WRITE32 (SataPort->RegBase + SII3132_PORT_INTSTATUS_REG, SII= 3132_PORT_INT_CMDCOMPL << 16); + + if (PciAllocMapping) { + Status =3D PciIo->Unmap (PciIo, PciAllocMapping); + ASSERT (!EFI_ERROR (Status)); + } + + // If the command was ATA_CMD_IDENTIFY_DRIVE then we need to update th= e BlockSize + if (Packet->Acb->AtaCommand =3D=3D ATA_CMD_IDENTIFY_DRIVE) { + ATA_IDENTIFY_DATA *IdentifyData =3D (ATA_IDENTIFY_DATA*)Packet->InDa= taBuffer; + + // Get the corresponding Block Device + SataDevice =3D GetSataDevice (SataSiI3132Instance, SataPort->Index, = PortMultiplierPort); + + // Check logical block size + if ((IdentifyData->phy_logic_sector_support & BIT12) !=3D 0) { + ASSERT (SataDevice !=3D NULL); + SataDevice->BlockSize =3D (UINT32) (((IdentifyData->logic_sector_s= ize_hi << 16) | + IdentifyData->logic_sector_siz= e_lo) * sizeof (UINT16)); + } else { + SataDevice->BlockSize =3D 0x200; + } + } + return EFI_SUCCESS; + } else { + ASSERT (0); + return EFI_DEVICE_ERROR; + } +} + +/** + Sends an ATA command to an ATA device that is attached to the ATA contro= ller. This function + supports both blocking I/O and non-blocking I/O. The blocking I/O functi= onality is required, + and the non-blocking I/O functionality is optional. + + @param[in] This A pointer to the EFI_ATA_PASS_THRU_PR= OTOCOL instance. + @param[in] Port The port number of the ATA device to = send the command. + @param[in] PortMultiplierPort The port multiplier port number of th= e ATA device to send the command. + If there is no port multiplier, then = specify 0. + @param[in,out] Packet A pointer to the ATA command to send = to the ATA device specified by Port + and PortMultiplierPort. + @param[in] Event If non-blocking I/O is not supported = then Event is ignored, and blocking + I/O is performed. If Event is NULL, t= hen blocking I/O is performed. If + Event is not NULL and non blocking I/= O is supported, then non-blocking + I/O is performed, and Event will be s= ignaled when the ATA command completes. + + @retval EFI_SUCCESS The ATA command was sent by the host.= For bi-directional commands, + InTransferLength bytes were transferr= ed from InDataBuffer. For write and + bi-directional commands, OutTransferL= ength bytes were transferred by OutDataBuffer. + @retval EFI_BAD_BUFFER_SIZE The ATA command was not executed. The= number of bytes that could be transferred + is returned in InTransferLength. For = write and bi-directional commands, + OutTransferLength bytes were transfer= red by OutDataBuffer. + @retval EFI_NOT_READY The ATA command could not be sent bec= ause there are too many ATA commands + already queued. The caller may retry = again later. + @retval EFI_DEVICE_ERROR A device error occurred while attempt= ing to send the ATA command. + @retval EFI_INVALID_PARAMETER Port, PortMultiplierPort, or the cont= ents of Acb are invalid. The ATA + command was not sent, so no additiona= l status information is available. + +**/ +EFI_STATUS +EFIAPI +SiI3132AtaPassThru ( + IN EFI_ATA_PASS_THRU_PROTOCOL *This, + IN UINT16 Port, + IN UINT16 PortMultiplierPort, + IN OUT EFI_ATA_PASS_THRU_COMMAND_PACKET *Packet, + IN EFI_EVENT Event OPTIONAL + ) +{ + SATA_SI3132_INSTANCE *SataSiI3132Instance; + SATA_SI3132_DEVICE *SataDevice; + SATA_SI3132_PORT *SataPort; + + SataSiI3132Instance =3D INSTANCE_FROM_ATAPASSTHRU_THIS (This); + if (!SataSiI3132Instance) { + return EFI_INVALID_PARAMETER; + } + + SataDevice =3D GetSataDevice (SataSiI3132Instance, Port, PortMultiplierP= ort); + if (!SataDevice) { + return EFI_INVALID_PARAMETER; + } + SataPort =3D SataDevice->Port; + + DEBUG ((EFI_D_INFO, "SiI3132AtaPassThru(%d,%d) : AtaCmd:0x%X Prot:%d\n",= Port, PortMultiplierPort, + Packet->Acb->AtaCommand, Packet->Protocol)); + + return SiI3132AtaPassThruCommand (SataSiI3132Instance, SataPort, PortMul= tiplierPort, Packet, Event); +} + +/** + Used to retrieve the list of legal port numbers for ATA devices on an AT= A controller. + These can either be the list of ports where ATA devices are actually pre= sent or the + list of legal port numbers for the ATA controller. Regardless, the calle= r of this + function must probe the port number returned to see if an ATA device is = actually + present at that location on the ATA controller. + + The GetNextPort() function retrieves the port number on an ATA controlle= r. If on input + Port is 0xFFFF, then the port number of the first port on the ATA contro= ller is returned + in Port and EFI_SUCCESS is returned. + + If Port is a port number that was returned on a previous call to GetNext= Port(), then the + port number of the next port on the ATA controller is returned in Port, = and EFI_SUCCESS + is returned. If Port is not 0xFFFF and Port was not returned on a previo= us call to + GetNextPort(), then EFI_INVALID_PARAMETER is returned. + + If Port is the port number of the last port on the ATA controller, then = EFI_NOT_FOUND is + returned. + + @param[in] This A pointer to the EFI_ATA_PASS_THRU_PROTOCO= L instance. + @param[in,out] Port On input, a pointer to the port number on = the ATA controller. + On output, a pointer to the next port numb= er on the ATA + controller. An input value of 0xFFFF retri= eves the first port + number on the ATA controller. + + @retval EFI_SUCCESS The next port number on the ATA controller= was returned in Port. + @retval EFI_NOT_FOUND There are no more ports on this ATA contro= ller. + @retval EFI_INVALID_PARAMETER Port is not 0xFFFF and Port was not return= ed on a previous call + to GetNextPort(). + +**/ +EFI_STATUS +EFIAPI +SiI3132GetNextPort ( + IN EFI_ATA_PASS_THRU_PROTOCOL *This, + IN OUT UINT16 *Port + ) +{ + SATA_SI3132_INSTANCE *SataSiI3132Instance; + UINTN PrevPort; + EFI_STATUS Status =3D EFI_SUCCESS; + + SataSiI3132Instance =3D INSTANCE_FROM_ATAPASSTHRU_THIS (This); + if (!SataSiI3132Instance) { + return EFI_INVALID_PARAMETER; + } + + PrevPort =3D *Port; + + if (PrevPort =3D=3D 0xFFFF) { + *Port =3D 0; + } else { + if (PrevPort < SATA_SII3132_MAXPORT) { + *Port =3D PrevPort + 1; + } else { + Status =3D EFI_NOT_FOUND; + } + } + return Status; +} + +/** + Used to retrieve the list of legal port multiplier port numbers for ATA = devices on a port of an ATA + controller. These can either be the list of port multiplier ports where = ATA devices are actually + present on port or the list of legal port multiplier ports on that port.= Regardless, the caller of this + function must probe the port number and port multiplier port number retu= rned to see if an ATA + device is actually present. + + The GetNextDevice() function retrieves the port multiplier port number o= f an ATA device + present on a port of an ATA controller. + + If PortMultiplierPort points to a port multiplier port number value that= was returned on a + previous call to GetNextDevice(), then the port multiplier port number o= f the next ATA device + on the port of the ATA controller is returned in PortMultiplierPort, and= EFI_SUCCESS is + returned. + + If PortMultiplierPort points to 0xFFFF, then the port multiplier port nu= mber of the first + ATA device on port of the ATA controller is returned in PortMultiplierPo= rt and + EFI_SUCCESS is returned. + + If PortMultiplierPort is not 0xFFFF and the value pointed to by PortMult= iplierPort + was not returned on a previous call to GetNextDevice(), then EFI_INVALID= _PARAMETER + is returned. + + If PortMultiplierPort is the port multiplier port number of the last ATA= device on the port of + the ATA controller, then EFI_NOT_FOUND is returned. + + @param[in] This A pointer to the EFI_ATA_PASS_THRU_PR= OTOCOL instance. + @param[in] Port The port number present on the ATA co= ntroller. + @param[in,out] PortMultiplierPort On input, a pointer to the port multi= plier port number of an + ATA device present on the ATA control= ler. + If on input a PortMultiplierPort of 0= xFFFF is specified, + then the port multiplier port number = of the first ATA device + is returned. On output, a pointer to = the port multiplier port + number of the next ATA device present= on an ATA controller. + + @retval EFI_SUCCESS The port multiplier port number of th= e next ATA device on the port + of the ATA controller was returned in= PortMultiplierPort. + @retval EFI_NOT_FOUND There are no more ATA devices on this= port of the ATA controller. + @retval EFI_INVALID_PARAMETER PortMultiplierPort is not 0xFFFF, and= PortMultiplierPort was not + returned on a previous call to GetNex= tDevice(). + +**/ +EFI_STATUS +EFIAPI +SiI3132GetNextDevice ( + IN EFI_ATA_PASS_THRU_PROTOCOL *This, + IN UINT16 Port, + IN OUT UINT16 *PortMultiplierPort + ) +{ + SATA_SI3132_INSTANCE *SataSiI3132Instance; + SATA_SI3132_PORT *SataPort; + SATA_SI3132_DEVICE *SataDevice; + LIST_ENTRY *List; + EFI_STATUS Status =3D EFI_SUCCESS; + + SataSiI3132Instance =3D INSTANCE_FROM_ATAPASSTHRU_THIS (This); + if (!SataSiI3132Instance) { + return EFI_INVALID_PARAMETER; + } + + if (Port >=3D SATA_SII3132_MAXPORT) { + return EFI_INVALID_PARAMETER; + } + + SataPort =3D &(SataSiI3132Instance->Ports[Port]); + + if (*PortMultiplierPort =3D=3D 0xFFFF) { + List =3D SataPort->Devices.ForwardLink; + if (List !=3D &SataPort->Devices) { + // The list is not empty, return the first device + *PortMultiplierPort =3D ((SATA_SI3132_DEVICE*)List)->Index; + } else { + Status =3D EFI_NOT_FOUND; + } + } else { + SataDevice =3D GetSataDevice (SataSiI3132Instance, Port, *PortMultipli= erPort); + if (SataDevice !=3D NULL) { + // We have found the previous port multiplier, return the next one + List =3D SataDevice->Link.ForwardLink; + if (List !=3D &SataPort->Devices) { + *PortMultiplierPort =3D ((SATA_SI3132_DEVICE*)List)->Index; + } else { + Status =3D EFI_NOT_FOUND; + } + } else { + Status =3D EFI_NOT_FOUND; + } + } + return Status; +} + +/** + Used to allocate and build a device path node for an ATA device on an AT= A controller. + + The BuildDevicePath() function allocates and builds a single device node= for the ATA + device specified by Port and PortMultiplierPort. If the ATA device speci= fied by Port and + PortMultiplierPort is not present on the ATA controller, then EFI_NOT_FO= UND is returned. + If DevicePath is NULL, then EFI_INVALID_PARAMETER is returned. If there = are not enough + resources to allocate the device path node, then EFI_OUT_OF_RESOURCES is= returned. + + Otherwise, DevicePath is allocated with the boot service AllocatePool(),= the contents of + DevicePath are initialized to describe the ATA device specified by Port = and PortMultiplierPort, + and EFI_SUCCESS is returned. + + @param[in] This A pointer to the EFI_ATA_PASS_THRU_PR= OTOCOL instance. + @param[in] Port Port specifies the port number of the= ATA device for which a + device path node is to be allocated a= nd built. + @param[in] PortMultiplierPort The port multiplier port number of th= e ATA device for which a + device path node is to be allocated a= nd built. If there is no + port multiplier, then specify 0. + @param[in,out] DevicePath A pointer to a single device path nod= e that describes the ATA + device specified by Port and PortMult= iplierPort. This function + is responsible for allocating the buf= fer DevicePath with the + boot service AllocatePool(). It is th= e caller's responsibility + to free DevicePath when the caller is= finished with DevicePath. + @retval EFI_SUCCESS The device path node that describes t= he ATA device specified by + Port and PortMultiplierPort was alloc= ated and returned in DevicePath. + @retval EFI_NOT_FOUND The ATA device specified by Port and = PortMultiplierPort does not + exist on the ATA controller. + @retval EFI_INVALID_PARAMETER DevicePath is NULL. + @retval EFI_OUT_OF_RESOURCES There are not enough resources to all= ocate DevicePath. + +**/ +EFI_STATUS +EFIAPI +SiI3132BuildDevicePath ( + IN EFI_ATA_PASS_THRU_PROTOCOL *This, + IN UINT16 Port, + IN UINT16 PortMultiplierPort, + IN OUT EFI_DEVICE_PATH_PROTOCOL **DevicePath + ) +{ + SATA_SI3132_INSTANCE *SataSiI3132Instance; + SATA_SI3132_DEVICE *SataDevice; + EFI_DEVICE_PATH_PROTOCOL *SiI3132DevicePath; + + SATA_TRACE ("SiI3132BuildDevicePath()"); + + SataSiI3132Instance =3D INSTANCE_FROM_ATAPASSTHRU_THIS (This); + if (!SataSiI3132Instance) { + return EFI_INVALID_PARAMETER; + } + + SataDevice =3D GetSataDevice (SataSiI3132Instance, Port, PortMultiplierP= ort); + if (SataDevice =3D=3D NULL) { + return EFI_NOT_FOUND; + } + + SiI3132DevicePath =3D CreateDeviceNode (MESSAGING_DEVICE_PATH, MSG_SATA_= DP, sizeof (SATA_DEVICE_PATH)); + if (SiI3132DevicePath =3D=3D NULL) { + return EFI_OUT_OF_RESOURCES; + } + + ((SATA_DEVICE_PATH*)SiI3132DevicePath)->HBAPortNumber =3D Port; + if (FeaturePcdGet (PcdSataSiI3132FeaturePMPSupport)) { + ((SATA_DEVICE_PATH*)SiI3132DevicePath)->PortMultiplierPortNumber =3D P= ortMultiplierPort; + } else { + //Temp:((SATA_DEVICE_PATH*)SiI3132DevicePath)->PortMultiplierPortNumbe= r =3D SATA_HBA_DIRECT_CONNECT_FLAG; + ((SATA_DEVICE_PATH*)SiI3132DevicePath)->PortMultiplierPortNumber =3D 0; + } + ((SATA_DEVICE_PATH*)SiI3132DevicePath)->Lun =3D Port; //TODO: Search inf= ormation how to define properly LUN (Logical Unit Number) + + *DevicePath =3D SiI3132DevicePath; + return EFI_SUCCESS; +} + +/** + Used to translate a device path node to a port number and port multiplie= r port number. + + The GetDevice() function determines the port and port multiplier port nu= mber associated with + the ATA device described by DevicePath. If DevicePath is a device path n= ode type that the + ATA Pass Thru driver supports, then the ATA Pass Thru driver will attemp= t to translate the contents + DevicePath into a port number and port multiplier port number. + + If this translation is successful, then that port number and port multip= lier port number are returned + in Port and PortMultiplierPort, and EFI_SUCCESS is returned. + + If DevicePath, Port, or PortMultiplierPort are NULL, then EFI_INVALID_PA= RAMETER is returned. + + If DevicePath is not a device path node type that the ATA Pass Thru driv= er supports, then + EFI_UNSUPPORTED is returned. + + If DevicePath is a device path node type that the ATA Pass Thru driver s= upports, but there is not + a valid translation from DevicePath to a port number and port multiplier= port number, then + EFI_NOT_FOUND is returned. + + @param[in] This A pointer to the EFI_ATA_PASS_THRU_PROTO= COL instance. + @param[in] DevicePath A pointer to the device path node that d= escribes an ATA device on the + ATA controller. + @param[out] Port On return, points to the port number of = an ATA device on the ATA controller. + @param[out] PortMultiplierPort On return, points to the port multiplier= port number of an ATA device + on the ATA controller. + + @retval EFI_SUCCESS DevicePath was successfully translated t= o a port number and port multiplier + port number, and they were returned in P= ort and PortMultiplierPort. + @retval EFI_INVALID_PARAMETER DevicePath is NULL. + @retval EFI_INVALID_PARAMETER Port is NULL. + @retval EFI_INVALID_PARAMETER PortMultiplierPort is NULL. + @retval EFI_UNSUPPORTED This driver does not support the device = path node type in DevicePath. + @retval EFI_NOT_FOUND A valid translation from DevicePath to a= port number and port multiplier + port number does not exist. +**/ +EFI_STATUS +EFIAPI +SiI3132GetDevice ( + IN EFI_ATA_PASS_THRU_PROTOCOL *This, + IN EFI_DEVICE_PATH_PROTOCOL *DevicePath, + OUT UINT16 *Port, + OUT UINT16 *PortMultiplierPort + ) +{ + SATA_SI3132_INSTANCE *SataSiI3132Instance; + + SATA_TRACE ("SiI3132GetDevice()"); + + if (!DevicePath || !Port || !PortMultiplierPort) { + return EFI_INVALID_PARAMETER; + } + + if ((DevicePath->Type !=3D MESSAGING_DEVICE_PATH) || (DevicePath->SubTyp= e !=3D MSG_SATA_DP)) { + return EFI_UNSUPPORTED; + } + + SataSiI3132Instance =3D INSTANCE_FROM_ATAPASSTHRU_THIS (This); + if (!SataSiI3132Instance) { + return EFI_INVALID_PARAMETER; + } + + if (((SATA_DEVICE_PATH*)DevicePath)->Lun >=3D SATA_SII3132_MAXPORT) { + return EFI_NOT_FOUND; + } + + if (FeaturePcdGet (PcdSataSiI3132FeaturePMPSupport)) { + ASSERT (0); //TODO: Implement me! + return EFI_UNSUPPORTED; + } else { + *Port =3D ((SATA_DEVICE_PATH*)DevicePath)->Lun; + // Return the first Sata Device as there should be only one directly c= onnected + *PortMultiplierPort =3D ((SATA_SI3132_DEVICE*)SataSiI3132Instance->Por= ts[*Port].Devices.ForwardLink)->Index; + return EFI_SUCCESS; + } +} + +EFI_STATUS +SiI3132HwResetPort ( + IN SATA_SI3132_PORT *SataPort + ) +{ + EFI_PCI_IO_PROTOCOL *PciIo; + UINT32 Value32; + UINTN Timeout; + + SATA_TRACE ("SiI3132HwResetPort()"); + + PciIo =3D SataPort->Instance->PciIo; + + // Clear Port Reset + SATA_PORT_WRITE32 (SataPort->RegBase + SII3132_PORT_CONTROLCLEAR_REG, SI= I3132_PORT_CONTROL_RESET); + + SATA_PORT_READ32 (SataPort->RegBase + SII3132_PORT_STATUS_REG, &Value32); + ASSERT (!(Value32 & SII3132_PORT_CONTROL_RESET)); + + // Initialize error counters + SATA_PORT_WRITE32 (SataPort->RegBase + SII3132_PORT_ERRCOUNTDECODE, 0); + SATA_PORT_WRITE32 (SataPort->RegBase + SII3132_PORT_ERRCOUNTCRC, 0); + SATA_PORT_WRITE32 (SataPort->RegBase + SII3132_PORT_ERRCOUNTHANDSHAKE, 0= ); + + // Enable interrupts for command completion and command errors + SATA_PORT_WRITE32 (SataPort->RegBase + SII3132_PORT_ENABLEINT_REG, SII31= 32_PORT_INT_CMDCOMPL | SII3132_PORT_INT_CMDERR); + + // Clear IRQ + SATA_PORT_WRITE32 (SataPort->RegBase + SII3132_PORT_ENABLEINT_REG, SII31= 32_PORT_INT_CMDCOMPL | SII3132_PORT_INT_CMDERR | SII3132_PORT_INT_PORTRDY |= (1 << 3)); + + // Wait until Port Ready + SATA_PORT_READ32 (SataPort->RegBase + SII3132_PORT_INTSTATUS_REG, &Value= 32); + Timeout =3D 1000; + while ((Timeout > 0) && ((Value32 & SII3132_PORT_INT_PORTRDY) =3D=3D 0))= { + gBS->Stall (1); + Timeout--; + SATA_PORT_READ32 (SataPort->RegBase + SII3132_PORT_INTSTATUS_REG, &Val= ue32); + } + // Clear IRQ + SATA_PORT_WRITE32 (SataPort->RegBase + SII3132_PORT_INTSTATUS_REG, SII31= 32_PORT_INT_PORTRDY); + + if (Timeout =3D=3D 0) { + SATA_TRACE ("SiI3132HwResetPort(): Timeout"); + return EFI_TIMEOUT; + } else if ((Value32 & SII3132_PORT_INT_PORTRDY) =3D=3D 0) { + SATA_TRACE ("SiI3132HwResetPort(): Port Not Ready"); + return EFI_DEVICE_ERROR; + } else { + return EFI_SUCCESS; + } +} + +/** + Resets a specific port on the ATA controller. This operation also resets= all the ATA devices + connected to the port. + + The ResetChannel() function resets an a specific port on an ATA controll= er. This operation + resets all the ATA devices connected to that port. If this ATA controlle= r does not support + a reset port operation, then EFI_UNSUPPORTED is returned. + + If a device error occurs while executing that port reset operation, then= EFI_DEVICE_ERROR is + returned. + + If a timeout occurs during the execution of the port reset operation, th= en EFI_TIMEOUT is returned. + + If the port reset operation is completed, then EFI_SUCCESS is returned. + + @param[in] This A pointer to the EFI_ATA_PASS_THRU_PROTOCOL in= stance. + @param[in] Port The port number on the ATA controller. + + @retval EFI_SUCCESS The ATA controller port was reset. + @retval EFI_UNSUPPORTED The ATA controller does not support a port res= et operation. + @retval EFI_DEVICE_ERROR A device error occurred while attempting to re= set the ATA port. + @retval EFI_TIMEOUT A timeout occurred while attempting to reset t= he ATA port. + +**/ +EFI_STATUS +EFIAPI +SiI3132ResetPort ( + IN EFI_ATA_PASS_THRU_PROTOCOL *This, + IN UINT16 Port + ) +{ + SATA_SI3132_INSTANCE *SataSiI3132Instance; + SATA_SI3132_PORT *SataPort; + + SATA_TRACE ("SiI3132ResetPort()"); + + SataSiI3132Instance =3D INSTANCE_FROM_ATAPASSTHRU_THIS (This); + if (!SataSiI3132Instance) { + return EFI_INVALID_PARAMETER; + } + + if (Port >=3D SATA_SII3132_MAXPORT) { + return EFI_UNSUPPORTED; + } + + SataPort =3D &(SataSiI3132Instance->Ports[Port]); + return SiI3132HwResetPort (SataPort); +} + +/** + Resets an ATA device that is connected to an ATA controller. + + The ResetDevice() function resets the ATA device specified by Port and P= ortMultiplierPort. + If this ATA controller does not support a device reset operation, then E= FI_UNSUPPORTED is + returned. + + If Port or PortMultiplierPort are not in a valid range for this ATA cont= roller, then + EFI_INVALID_PARAMETER is returned. + + If a device error occurs while executing that device reset operation, th= en EFI_DEVICE_ERROR + is returned. + + If a timeout occurs during the execution of the device reset operation, = then EFI_TIMEOUT is + returned. + + If the device reset operation is completed, then EFI_SUCCESS is returned. + + @param[in] This A pointer to the EFI_ATA_PASS_THRU_PROTOC= OL instance. + @param[in] Port Port represents the port number of the AT= A device to be reset. + @param[in] PortMultiplierPort The port multiplier port number of the AT= A device to reset. + If there is no port multiplier, then spec= ify 0. + @retval EFI_SUCCESS The ATA device specified by Port and Port= MultiplierPort was reset. + @retval EFI_UNSUPPORTED The ATA controller does not support a dev= ice reset operation. + @retval EFI_INVALID_PARAMETER Port or PortMultiplierPort are invalid. + @retval EFI_DEVICE_ERROR A device error occurred while attempting = to reset the ATA device + specified by Port and PortMultiplierPort. + @retval EFI_TIMEOUT A timeout occurred while attempting to re= set the ATA device + specified by Port and PortMultiplierPort. + +**/ +EFI_STATUS +EFIAPI +SiI3132ResetDevice ( + IN EFI_ATA_PASS_THRU_PROTOCOL *This, + IN UINT16 Port, + IN UINT16 PortMultiplierPort + ) +{ + EFI_PCI_IO_PROTOCOL *PciIo; + SATA_SI3132_INSTANCE *SataSiI3132Instance; + SATA_SI3132_PORT *SataPort; + SATA_SI3132_DEVICE *SataDevice; + UINTN Timeout; + UINT32 Value32; + + SATA_TRACE ("SiI3132ResetDevice()"); + + SataSiI3132Instance =3D INSTANCE_FROM_ATAPASSTHRU_THIS (This); + if (!SataSiI3132Instance) { + return EFI_INVALID_PARAMETER; + } + + PciIo =3D SataSiI3132Instance->PciIo; + + SataDevice =3D GetSataDevice (SataSiI3132Instance, Port, PortMultiplierP= ort); + if (!SataDevice) { + return EFI_INVALID_PARAMETER; + } + SataPort =3D SataDevice->Port; + + SATA_PORT_WRITE32 (SataPort->RegBase + SII3132_PORT_CONTROLSET_REG, SII3= 132_PORT_DEVICE_RESET); + + Timeout =3D 100; + SATA_PORT_READ32 (SataPort->RegBase + SII3132_PORT_STATUS_REG, &Value32); + while ((Timeout > 0) && ((Value32 & SII3132_PORT_DEVICE_RESET) !=3D 0)) { + gBS->Stall (1); + SATA_PORT_READ32 (SataPort->RegBase + SII3132_PORT_STATUS_REG, &Value3= 2); + Timeout--; + } + + if (Timeout =3D=3D 0) { + SATA_TRACE ("SiI3132ResetDevice(): Timeout"); + return EFI_TIMEOUT; + } else { + return EFI_SUCCESS; + } +} --=20 2.17.1 -=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D- Groups.io Links: You receive all messages sent to this group. View/Reply Online (#58451): https://edk2.groups.io/g/devel/message/58451 Mute This Topic: https://groups.io/mt/73380292/1787277 Group Owner: devel+owner@edk2.groups.io Unsubscribe: https://edk2.groups.io/g/devel/unsub [importer@patchew.org] -=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D- From nobody Mon May 6 19:29:01 2024 Delivered-To: importer@patchew.org Received-SPF: pass (zohomail.com: domain of groups.io designates 66.175.222.12 as permitted sender) client-ip=66.175.222.12; envelope-from=bounce+27952+58452+1787277+3901457@groups.io; helo=web01.groups.io; Authentication-Results: mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of groups.io designates 66.175.222.12 as permitted sender) smtp.mailfrom=bounce+27952+58452+1787277+3901457@groups.io ARC-Seal: i=1; a=rsa-sha256; t=1588267024; cv=none; d=zohomail.com; s=zohoarc; b=HanzeA+DgWGZFFqdd+Y8rt0xuWPP0YYGfz8PYJ3UFK3gqdR5ATR233R0RRiCHoQbWeyngxaQNs9QqHVckPs+73HpLg2I5LoOTWwWzxODhbpzcsr4xjA/pvEL5Om7Cw1D7uzNaQtO0chj1R4vmsQceviWxRF/pQIxtPepjnvQdQQ= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1588267024; h=Cc:Date:From:In-Reply-To:List-Id:List-Unsubscribe:Message-ID:Reply-To:References:Sender:Subject:To; bh=lI+ZuglGopUSfzhkyjUmqV/3l3lGtjsl5775cnMwj30=; b=ioKh8JDtINYZh0mp6SoxwIXK+M0nAIrh54Uh1NX+uoUMLp+IFIl+rOfSZhhIrhNJ3A6FNui8IkGtXGry/IfKVUTW3G2tfbdkQ5asGR6VKwaxSk5yXqawTuUduXVyrgUgU4WRanbPAFXOWe0uO36d1P5OLYAvwQFAfZE1+779rFY= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of groups.io designates 66.175.222.12 as permitted sender) smtp.mailfrom=bounce+27952+58452+1787277+3901457@groups.io Received: from web01.groups.io (web01.groups.io [66.175.222.12]) by mx.zohomail.com with SMTPS id 1588267023972375.95828026879394; Thu, 30 Apr 2020 10:17:03 -0700 (PDT) Return-Path: X-Received: by 127.0.0.2 with SMTP id 84Q4YY1788612xyORfIwRTHz; Thu, 30 Apr 2020 10:17:03 -0700 X-Received: from foss.arm.com (foss.arm.com [217.140.110.172]) by mx.groups.io with SMTP id smtpd.web11.821.1588267023065899168 for ; Thu, 30 Apr 2020 10:17:03 -0700 X-Received: from usa-sjc-imap-foss1.foss.arm.com (unknown [10.121.207.14]) by usa-sjc-mx-foss1.foss.arm.com (Postfix) with ESMTP id ADFB41045; Thu, 30 Apr 2020 10:17:02 -0700 (PDT) X-Received: from e123331-lin.home (unknown [172.31.20.19]) by usa-sjc-imap-foss1.foss.arm.com (Postfix) with ESMTPSA id B04793F73D; Thu, 30 Apr 2020 10:17:01 -0700 (PDT) From: "Ard Biesheuvel" To: devel@edk2.groups.io Cc: leif@nuviainc.com, Ard Biesheuvel Subject: [edk2-devel] [PATCH edk2-platforms v3 4/8] Silicon/Synopsys/DesignWare: import eMMC DXE driver from EmbeddedPkg Date: Thu, 30 Apr 2020 19:16:45 +0200 Message-Id: <20200430171650.24139-5-ard.biesheuvel@arm.com> In-Reply-To: <20200430171650.24139-1-ard.biesheuvel@arm.com> References: <20200430171650.24139-1-ard.biesheuvel@arm.com> Precedence: Bulk List-Unsubscribe: Sender: devel@edk2.groups.io List-Id: <27952.devel.edk2.groups.io> Mailing-List: list devel@edk2.groups.io; contact devel+owner@edk2.groups.io Reply-To: devel@edk2.groups.io,ard.biesheuvel@arm.com X-Gm-Message-State: ItsrSKKRMMIavtbSXmgWw4oXx1787277AA= DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=groups.io; q=dns/txt; s=20140610; t=1588267023; bh=VnNE/dXTjp1X/w+Nhrp+DvgzgQvJgzHsu+roX8uM1uY=; h=Cc:Date:From:Reply-To:Subject:To; b=a1p1nSue1bMHIkyywvIA5YMx7BsGxIbzKSKjnQNk5cHWvYX7FV65hHSEe2FC7EmWn1A GJI0m2q1SdymFXYAfe2dTOTaY1Q140dUD0edcHrJbmC9WAMAbIUtGLmYXNoUhFX25YuoL 4xvgmaOjThyyQnL4owK2Smw/ZvxkLcuFA0w= X-ZohoMail-DKIM: pass (identity @groups.io) Content-Transfer-Encoding: quoted-printable MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Incorporate the driver for the DesignWare eMMC host controller that is based on the obsolete MMC host controller protocol that is defined in EmbeddedPkg. This driver does not follow the UEFI driver model, and is only kept around for its only users, which is the HiKey platform, which is rapidly reaching obsolescence itself, at which point this driver may be removed again. To prevent inadvertent use in new platforms, add a PCD that needs to be changed from its default value in order for the driver to be functional. Signed-off-by: Ard Biesheuvel Reviewed-by: Leif Lindholm Reviewed-by: Philippe Mathieu-Daude Reviewed-by: Philippe Mathieu-Daud=C3=A9 --- Silicon/Synopsys/DesignWare/DesignWare.dec | 9 + Silicon/Synopsys/DesignWare/DesignWare.dsc | 2 + Silicon/Synopsys/DesignWare/Drivers/DwEmmcDxe/DwEmmc.h | 132 ++++ Silicon/Synopsys/DesignWare/Drivers/DwEmmcDxe/DwEmmcDxe.c | 693 ++++++++= ++++++++++++ Silicon/Synopsys/DesignWare/Drivers/DwEmmcDxe/DwEmmcDxe.inf | 56 ++ 5 files changed, 892 insertions(+) diff --git a/Silicon/Synopsys/DesignWare/DesignWare.dec b/Silicon/Synopsys/= DesignWare/DesignWare.dec index 71ddd24b7404..f7ec7927543c 100755 --- a/Silicon/Synopsys/DesignWare/DesignWare.dec +++ b/Silicon/Synopsys/DesignWare/DesignWare.dec @@ -21,4 +21,13 @@ [Guids.common] gDesignWareTokenSpaceGuid =3D { 0x89cb1241, 0xd283, 0x4543, { 0x88, 0x9c= , 0x6b, 0x62, 0x36, 0x1a, 0x95, 0x7a } } gDwEmacNetNonDiscoverableDeviceGuid =3D { 0x401950CD, 0xF9CD, 0x4A65, { = 0xAD, 0x8E, 0x84, 0x9F, 0x3B, 0xAF, 0x23, 0x04 } } =20 +[PcdsFixedAtBuild.common] + # + # Permit the use of obsolete drivers in this package + # + gDesignWareTokenSpaceGuid.PcdDwPermitObsoleteDrivers|FALSE|BOOLEAN|0x000= 00001 =20 + gDesignWareTokenSpaceGuid.PcdDwEmmcDxeBaseAddress|0x0|UINT32|0x00000002 + gDesignWareTokenSpaceGuid.PcdDwEmmcDxeClockFrequencyInHz|0x0|UINT32|0x00= 000003 + gDesignWareTokenSpaceGuid.PcdDwEmmcDxeMaxClockFreqInHz|0x0|UINT32|0x0000= 0004 + gDesignWareTokenSpaceGuid.PcdDwEmmcDxeFifoDepth|0x0|UINT32|0x00000005 diff --git a/Silicon/Synopsys/DesignWare/DesignWare.dsc b/Silicon/Synopsys/= DesignWare/DesignWare.dsc index ad6a5ede4ae0..098bba3f7d68 100755 --- a/Silicon/Synopsys/DesignWare/DesignWare.dsc +++ b/Silicon/Synopsys/DesignWare/DesignWare.dsc @@ -20,6 +20,7 @@ [LibraryClasses] ArmLib|ArmPkg/Library/ArmLib/ArmBaseLib.inf BaseLib|MdePkg/Library/BaseLib/BaseLib.inf BaseMemoryLib|MdePkg/Library/BaseMemoryLib/BaseMemoryLib.inf + CacheMaintenanceLib|MdePkg/Library/BaseCacheMaintenanceLib/BaseCacheMain= tenanceLib.inf DebugLib|MdePkg/Library/BaseDebugLibNull/BaseDebugLibNull.inf DevicePathLib|MdePkg/Library/UefiDevicePathLib/UefiDevicePathLib.inf DmaLib|EmbeddedPkg/Library/NonCoherentDmaLib/NonCoherentDmaLib.inf @@ -39,3 +40,4 @@ [LibraryClasses] =20 [Components] Silicon/Synopsys/DesignWare/Drivers/DwEmacSnpDxe/DwEmacSnpDxe.inf + Silicon/Synopsys/DesignWare/Drivers/DwEmmcDxe/DwEmmcDxe.inf diff --git a/Silicon/Synopsys/DesignWare/Drivers/DwEmmcDxe/DwEmmc.h b/Silic= on/Synopsys/DesignWare/Drivers/DwEmmcDxe/DwEmmc.h new file mode 100644 index 000000000000..09ad9b8428c4 --- /dev/null +++ b/Silicon/Synopsys/DesignWare/Drivers/DwEmmcDxe/DwEmmc.h @@ -0,0 +1,132 @@ +/** @file +* +* WARNING: +* This driver fails to follow the UEFI driver model without a good +* reason, and only remains in the tree because it is still used by +* a small number of platforms. It will be removed when no longer used. +* +* Copyright (c) 2014-2017, Linaro Limited. All rights reserved. +* +* SPDX-License-Identifier: BSD-2-Clause-Patent +* +**/ + + +#ifndef __DWEMMC_H__ +#define __DWEMMC_H__ + +#include + +// DW MMC Registers +#define DWEMMC_CTRL ((UINT32)PcdGet32 (PcdDwEmmcDxeBaseAddress= ) + 0x000) +#define DWEMMC_PWREN ((UINT32)PcdGet32 (PcdDwEmmcDxeBaseAddress= ) + 0x004) +#define DWEMMC_CLKDIV ((UINT32)PcdGet32 (PcdDwEmmcDxeBaseAddress= ) + 0x008) +#define DWEMMC_CLKSRC ((UINT32)PcdGet32 (PcdDwEmmcDxeBaseAddress= ) + 0x00c) +#define DWEMMC_CLKENA ((UINT32)PcdGet32 (PcdDwEmmcDxeBaseAddress= ) + 0x010) +#define DWEMMC_TMOUT ((UINT32)PcdGet32 (PcdDwEmmcDxeBaseAddress= ) + 0x014) +#define DWEMMC_CTYPE ((UINT32)PcdGet32 (PcdDwEmmcDxeBaseAddress= ) + 0x018) +#define DWEMMC_BLKSIZ ((UINT32)PcdGet32 (PcdDwEmmcDxeBaseAddress= ) + 0x01c) +#define DWEMMC_BYTCNT ((UINT32)PcdGet32 (PcdDwEmmcDxeBaseAddress= ) + 0x020) +#define DWEMMC_INTMASK ((UINT32)PcdGet32 (PcdDwEmmcDxeBaseAddress= ) + 0x024) +#define DWEMMC_CMDARG ((UINT32)PcdGet32 (PcdDwEmmcDxeBaseAddress= ) + 0x028) +#define DWEMMC_CMD ((UINT32)PcdGet32 (PcdDwEmmcDxeBaseAddress= ) + 0x02c) +#define DWEMMC_RESP0 ((UINT32)PcdGet32 (PcdDwEmmcDxeBaseAddress= ) + 0x030) +#define DWEMMC_RESP1 ((UINT32)PcdGet32 (PcdDwEmmcDxeBaseAddress= ) + 0x034) +#define DWEMMC_RESP2 ((UINT32)PcdGet32 (PcdDwEmmcDxeBaseAddress= ) + 0x038) +#define DWEMMC_RESP3 ((UINT32)PcdGet32 (PcdDwEmmcDxeBaseAddress= ) + 0x03c) +#define DWEMMC_RINTSTS ((UINT32)PcdGet32 (PcdDwEmmcDxeBaseAddress= ) + 0x044) +#define DWEMMC_STATUS ((UINT32)PcdGet32 (PcdDwEmmcDxeBaseAddress= ) + 0x048) +#define DWEMMC_FIFOTH ((UINT32)PcdGet32 (PcdDwEmmcDxeBaseAddress= ) + 0x04c) +#define DWEMMC_TCBCNT ((UINT32)PcdGet32 (PcdDwEmmcDxeBaseAddress= ) + 0x05c) +#define DWEMMC_TBBCNT ((UINT32)PcdGet32 (PcdDwEmmcDxeBaseAddress= ) + 0x060) +#define DWEMMC_DEBNCE ((UINT32)PcdGet32 (PcdDwEmmcDxeBaseAddress= ) + 0x064) +#define DWEMMC_HCON ((UINT32)PcdGet32 (PcdDwEmmcDxeBaseAddress= ) + 0x070) +#define DWEMMC_UHSREG ((UINT32)PcdGet32 (PcdDwEmmcDxeBaseAddress= ) + 0x074) +#define DWEMMC_BMOD ((UINT32)PcdGet32 (PcdDwEmmcDxeBaseAddress= ) + 0x080) +#define DWEMMC_DBADDR ((UINT32)PcdGet32 (PcdDwEmmcDxeBaseAddress= ) + 0x088) +#define DWEMMC_IDSTS ((UINT32)PcdGet32 (PcdDwEmmcDxeBaseAddress= ) + 0x08c) +#define DWEMMC_IDINTEN ((UINT32)PcdGet32 (PcdDwEmmcDxeBaseAddress= ) + 0x090) +#define DWEMMC_DSCADDR ((UINT32)PcdGet32 (PcdDwEmmcDxeBaseAddress= ) + 0x094) +#define DWEMMC_BUFADDR ((UINT32)PcdGet32 (PcdDwEmmcDxeBaseAddress= ) + 0x098) +#define DWEMMC_CARDTHRCTL ((UINT32)PcdGet32 (PcdDwEmmcDxeBaseAddress= ) + 0X100) +#define DWEMMC_DATA ((UINT32)PcdGet32 (PcdDwEmmcDxeBaseAddress= ) + 0X200) + +#define CMD_UPDATE_CLK 0x80202000 +#define CMD_START_BIT (1 << 31) + +#define MMC_8BIT_MODE (1 << 16) + +#define BIT_CMD_RESPONSE_EXPECT (1 << 6) +#define BIT_CMD_LONG_RESPONSE (1 << 7) +#define BIT_CMD_CHECK_RESPONSE_CRC (1 << 8) +#define BIT_CMD_DATA_EXPECTED (1 << 9) +#define BIT_CMD_READ (0 << 10) +#define BIT_CMD_WRITE (1 << 10) +#define BIT_CMD_BLOCK_TRANSFER (0 << 11) +#define BIT_CMD_STREAM_TRANSFER (1 << 11) +#define BIT_CMD_SEND_AUTO_STOP (1 << 12) +#define BIT_CMD_WAIT_PRVDATA_COMPLETE (1 << 13) +#define BIT_CMD_STOP_ABORT_CMD (1 << 14) +#define BIT_CMD_SEND_INIT (1 << 15) +#define BIT_CMD_UPDATE_CLOCK_ONLY (1 << 21) +#define BIT_CMD_READ_CEATA_DEVICE (1 << 22) +#define BIT_CMD_CCS_EXPECTED (1 << 23) +#define BIT_CMD_ENABLE_BOOT (1 << 24) +#define BIT_CMD_EXPECT_BOOT_ACK (1 << 25) +#define BIT_CMD_DISABLE_BOOT (1 << 26) +#define BIT_CMD_MANDATORY_BOOT (0 << 27) +#define BIT_CMD_ALTERNATE_BOOT (1 << 27) +#define BIT_CMD_VOLT_SWITCH (1 << 28) +#define BIT_CMD_USE_HOLD_REG (1 << 29) +#define BIT_CMD_START (1 << 31) + +#define DWEMMC_INT_EBE (1 << 15) /* End-bit= Err */ +#define DWEMMC_INT_SBE (1 << 13) /* Start-b= it Err */ +#define DWEMMC_INT_HLE (1 << 12) /* Hardwar= e-lock Err */ +#define DWEMMC_INT_FRUN (1 << 11) /* FIFO UN= /OV RUN */ +#define DWEMMC_INT_DRT (1 << 9) /* Data ti= meout */ +#define DWEMMC_INT_RTO (1 << 8) /* Respons= e timeout */ +#define DWEMMC_INT_DCRC (1 << 7) /* Data CR= C err */ +#define DWEMMC_INT_RCRC (1 << 6) /* Respons= e CRC err */ +#define DWEMMC_INT_RXDR (1 << 5) +#define DWEMMC_INT_TXDR (1 << 4) +#define DWEMMC_INT_DTO (1 << 3) /* Data tr= ans over */ +#define DWEMMC_INT_CMD_DONE (1 << 2) +#define DWEMMC_INT_RE (1 << 1) + +#define DWEMMC_IDMAC_DES0_DIC (1 << 1) +#define DWEMMC_IDMAC_DES0_LD (1 << 2) +#define DWEMMC_IDMAC_DES0_FS (1 << 3) +#define DWEMMC_IDMAC_DES0_CH (1 << 4) +#define DWEMMC_IDMAC_DES0_ER (1 << 5) +#define DWEMMC_IDMAC_DES0_CES (1 << 30) +#define DWEMMC_IDMAC_DES0_OWN (1 << 31) +#define DWEMMC_IDMAC_DES1_BS1(x) ((x) & 0x1fff) +#define DWEMMC_IDMAC_DES2_BS2(x) (((x) & 0x1fff) << 13) +#define DWEMMC_IDMAC_SWRESET (1 << 0) +#define DWEMMC_IDMAC_FB (1 << 1) +#define DWEMMC_IDMAC_ENABLE (1 << 7) + +#define EMMC_FIX_RCA 6 + +/* bits in MMC0_CTRL */ +#define DWEMMC_CTRL_RESET (1 << 0) +#define DWEMMC_CTRL_FIFO_RESET (1 << 1) +#define DWEMMC_CTRL_DMA_RESET (1 << 2) +#define DWEMMC_CTRL_INT_EN (1 << 4) +#define DWEMMC_CTRL_DMA_EN (1 << 5) +#define DWEMMC_CTRL_IDMAC_EN (1 << 25) +#define DWEMMC_CTRL_RESET_ALL (DWEMMC_CTRL_RESET | DWEMM= C_CTRL_FIFO_RESET | DWEMMC_CTRL_DMA_RESET) + +#define DWEMMC_STS_DATA_BUSY (1 << 9) + +#define DWEMMC_FIFO_TWMARK(x) (x & 0xfff) +#define DWEMMC_FIFO_RWMARK(x) ((x & 0x1ff) << 16) +#define DWEMMC_DMA_BURST_SIZE(x) ((x & 0x7) << 28) + +#define DWEMMC_CARD_RD_THR(x) ((x & 0xfff) << 16) +#define DWEMMC_CARD_RD_THR_EN (1 << 0) + +#define DWEMMC_GET_HDATA_WIDTH(x) (((x) >> 7) & 0x7) + +#endif // __DWEMMC_H__ diff --git a/Silicon/Synopsys/DesignWare/Drivers/DwEmmcDxe/DwEmmcDxe.c b/Si= licon/Synopsys/DesignWare/Drivers/DwEmmcDxe/DwEmmcDxe.c new file mode 100644 index 000000000000..eed5fc57fc22 --- /dev/null +++ b/Silicon/Synopsys/DesignWare/Drivers/DwEmmcDxe/DwEmmcDxe.c @@ -0,0 +1,693 @@ +/** @file + This file implement the MMC Host Protocol for the DesignWare eMMC. + + Copyright (c) 2014-2017, Linaro Limited. All rights reserved. + + SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "DwEmmc.h" + +#define DWEMMC_DESC_PAGE 1 +#define DWEMMC_BLOCK_SIZE 512 +#define DWEMMC_DMA_BUF_SIZE (512 * 8) +#define DWEMMC_MAX_DESC_PAGES 512 + +typedef struct { + UINT32 Des0; + UINT32 Des1; + UINT32 Des2; + UINT32 Des3; +} DWEMMC_IDMAC_DESCRIPTOR; + +EFI_MMC_HOST_PROTOCOL *gpMmcHost; +DWEMMC_IDMAC_DESCRIPTOR *gpIdmacDesc; +EFI_GUID mDwEmmcDevicePathGuid =3D EFI_CALLER_ID_GUID; +STATIC UINT32 mDwEmmcCommand; +STATIC UINT32 mDwEmmcArgument; + +EFI_STATUS +DwEmmcReadBlockData ( + IN EFI_MMC_HOST_PROTOCOL *This, + IN EFI_LBA Lba, + IN UINTN Length, + IN UINT32* Buffer + ); + +BOOLEAN +DwEmmcIsPowerOn ( + VOID + ) +{ + return TRUE; +} + +EFI_STATUS +DwEmmcInitialize ( + VOID + ) +{ + DEBUG ((DEBUG_BLKIO, "DwEmmcInitialize()")); + return EFI_SUCCESS; +} + +BOOLEAN +DwEmmcIsCardPresent ( + IN EFI_MMC_HOST_PROTOCOL *This + ) +{ + return TRUE; +} + +BOOLEAN +DwEmmcIsReadOnly ( + IN EFI_MMC_HOST_PROTOCOL *This + ) +{ + return FALSE; +} + +BOOLEAN +DwEmmcIsDmaSupported ( + IN EFI_MMC_HOST_PROTOCOL *This + ) +{ + return TRUE; +} + +EFI_STATUS +DwEmmcBuildDevicePath ( + IN EFI_MMC_HOST_PROTOCOL *This, + IN EFI_DEVICE_PATH_PROTOCOL **DevicePath + ) +{ + EFI_DEVICE_PATH_PROTOCOL *NewDevicePathNode; + + NewDevicePathNode =3D CreateDeviceNode (HARDWARE_DEVICE_PATH, HW_VENDOR_= DP, sizeof (VENDOR_DEVICE_PATH)); + CopyGuid (& ((VENDOR_DEVICE_PATH*)NewDevicePathNode)->Guid, &mDwEmmcDevi= cePathGuid); + + *DevicePath =3D NewDevicePathNode; + return EFI_SUCCESS; +} + +EFI_STATUS +DwEmmcUpdateClock ( + VOID + ) +{ + UINT32 Data; + + /* CMD_UPDATE_CLK */ + Data =3D BIT_CMD_WAIT_PRVDATA_COMPLETE | BIT_CMD_UPDATE_CLOCK_ONLY | + BIT_CMD_START; + MmioWrite32 (DWEMMC_CMD, Data); + while (1) { + Data =3D MmioRead32 (DWEMMC_CMD); + if (!(Data & CMD_START_BIT)) { + break; + } + Data =3D MmioRead32 (DWEMMC_RINTSTS); + if (Data & DWEMMC_INT_HLE) { + Print (L"failed to update mmc clock frequency\n"); + return EFI_DEVICE_ERROR; + } + } + return EFI_SUCCESS; +} + +EFI_STATUS +DwEmmcSetClock ( + IN UINTN ClockFreq + ) +{ + UINT32 Divider, Rate, Data; + EFI_STATUS Status; + BOOLEAN Found =3D FALSE; + + for (Divider =3D 1; Divider < 256; Divider++) { + Rate =3D PcdGet32 (PcdDwEmmcDxeClockFrequencyInHz); + if ((Rate / (2 * Divider)) <=3D ClockFreq) { + Found =3D TRUE; + break; + } + } + if (Found =3D=3D FALSE) { + return EFI_NOT_FOUND; + } + + // Wait until MMC is idle + do { + Data =3D MmioRead32 (DWEMMC_STATUS); + } while (Data & DWEMMC_STS_DATA_BUSY); + + // Disable MMC clock first + MmioWrite32 (DWEMMC_CLKENA, 0); + Status =3D DwEmmcUpdateClock (); + ASSERT (!EFI_ERROR (Status)); + + MmioWrite32 (DWEMMC_CLKDIV, Divider); + Status =3D DwEmmcUpdateClock (); + ASSERT (!EFI_ERROR (Status)); + + // Enable MMC clock + MmioWrite32 (DWEMMC_CLKENA, 1); + MmioWrite32 (DWEMMC_CLKSRC, 0); + Status =3D DwEmmcUpdateClock (); + ASSERT (!EFI_ERROR (Status)); + return EFI_SUCCESS; +} + +EFI_STATUS +DwEmmcNotifyState ( + IN EFI_MMC_HOST_PROTOCOL *This, + IN MMC_STATE State + ) +{ + UINT32 Data; + EFI_STATUS Status; + + switch (State) { + case MmcInvalidState: + return EFI_INVALID_PARAMETER; + case MmcHwInitializationState: + MmioWrite32 (DWEMMC_PWREN, 1); + + // If device already turn on then restart it + Data =3D DWEMMC_CTRL_RESET_ALL; + MmioWrite32 (DWEMMC_CTRL, Data); + do { + // Wait until reset operation finished + Data =3D MmioRead32 (DWEMMC_CTRL); + } while (Data & DWEMMC_CTRL_RESET_ALL); + + // Setup clock that could not be higher than 400KHz. + Status =3D DwEmmcSetClock (400000); + ASSERT (!EFI_ERROR (Status)); + // Wait clock stable + MicroSecondDelay (100); + + MmioWrite32 (DWEMMC_RINTSTS, ~0); + MmioWrite32 (DWEMMC_INTMASK, 0); + MmioWrite32 (DWEMMC_TMOUT, ~0); + MmioWrite32 (DWEMMC_IDINTEN, 0); + MmioWrite32 (DWEMMC_BMOD, DWEMMC_IDMAC_SWRESET); + + MmioWrite32 (DWEMMC_BLKSIZ, DWEMMC_BLOCK_SIZE); + do { + Data =3D MmioRead32 (DWEMMC_BMOD); + } while (Data & DWEMMC_IDMAC_SWRESET); + break; + case MmcIdleState: + break; + case MmcReadyState: + break; + case MmcIdentificationState: + break; + case MmcStandByState: + break; + case MmcTransferState: + break; + case MmcSendingDataState: + break; + case MmcReceiveDataState: + break; + case MmcProgrammingState: + break; + case MmcDisconnectState: + break; + default: + return EFI_INVALID_PARAMETER; + } + return EFI_SUCCESS; +} + +// Need to prepare DMA buffer first before sending commands to MMC card +BOOLEAN +IsPendingReadCommand ( + IN MMC_CMD MmcCmd + ) +{ + UINTN Mask; + + Mask =3D BIT_CMD_DATA_EXPECTED | BIT_CMD_READ; + if ((MmcCmd & Mask) =3D=3D Mask) { + return TRUE; + } + return FALSE; +} + +BOOLEAN +IsPendingWriteCommand ( + IN MMC_CMD MmcCmd + ) +{ + UINTN Mask; + + Mask =3D BIT_CMD_DATA_EXPECTED | BIT_CMD_WRITE; + if ((MmcCmd & Mask) =3D=3D Mask) { + return TRUE; + } + return FALSE; +} + +EFI_STATUS +SendCommand ( + IN MMC_CMD MmcCmd, + IN UINT32 Argument + ) +{ + UINT32 Data, ErrMask; + + // Wait until MMC is idle + do { + Data =3D MmioRead32 (DWEMMC_STATUS); + } while (Data & DWEMMC_STS_DATA_BUSY); + + MmioWrite32 (DWEMMC_RINTSTS, ~0); + MmioWrite32 (DWEMMC_CMDARG, Argument); + MmioWrite32 (DWEMMC_CMD, MmcCmd); + + ErrMask =3D DWEMMC_INT_EBE | DWEMMC_INT_HLE | DWEMMC_INT_RTO | + DWEMMC_INT_RCRC | DWEMMC_INT_RE; + ErrMask |=3D DWEMMC_INT_DCRC | DWEMMC_INT_DRT | DWEMMC_INT_SBE; + do { + MicroSecondDelay(500); + Data =3D MmioRead32 (DWEMMC_RINTSTS); + + if (Data & ErrMask) { + return EFI_DEVICE_ERROR; + } + if (Data & DWEMMC_INT_DTO) { // Transfer Done + break; + } + } while (!(Data & DWEMMC_INT_CMD_DONE)); + return EFI_SUCCESS; +} + +EFI_STATUS +DwEmmcSendCommand ( + IN EFI_MMC_HOST_PROTOCOL *This, + IN MMC_CMD MmcCmd, + IN UINT32 Argument + ) +{ + UINT32 Cmd =3D 0; + EFI_STATUS Status =3D EFI_SUCCESS; + + switch (MMC_GET_INDX(MmcCmd)) { + case MMC_INDX(0): + Cmd =3D BIT_CMD_SEND_INIT; + break; + case MMC_INDX(1): + Cmd =3D BIT_CMD_RESPONSE_EXPECT; + break; + case MMC_INDX(2): + Cmd =3D BIT_CMD_RESPONSE_EXPECT | BIT_CMD_LONG_RESPONSE | + BIT_CMD_CHECK_RESPONSE_CRC | BIT_CMD_SEND_INIT; + break; + case MMC_INDX(3): + Cmd =3D BIT_CMD_RESPONSE_EXPECT | BIT_CMD_CHECK_RESPONSE_CRC | + BIT_CMD_SEND_INIT; + break; + case MMC_INDX(7): + if (Argument) + Cmd =3D BIT_CMD_RESPONSE_EXPECT | BIT_CMD_CHECK_RESPONSE_CRC; + else + Cmd =3D 0; + break; + case MMC_INDX(8): + Cmd =3D BIT_CMD_RESPONSE_EXPECT | BIT_CMD_CHECK_RESPONSE_CRC | + BIT_CMD_DATA_EXPECTED | BIT_CMD_READ | + BIT_CMD_WAIT_PRVDATA_COMPLETE; + break; + case MMC_INDX(9): + Cmd =3D BIT_CMD_RESPONSE_EXPECT | BIT_CMD_CHECK_RESPONSE_CRC | + BIT_CMD_LONG_RESPONSE; + break; + case MMC_INDX(12): + Cmd =3D BIT_CMD_RESPONSE_EXPECT | BIT_CMD_CHECK_RESPONSE_CRC | + BIT_CMD_STOP_ABORT_CMD; + break; + case MMC_INDX(13): + Cmd =3D BIT_CMD_RESPONSE_EXPECT | BIT_CMD_CHECK_RESPONSE_CRC | + BIT_CMD_WAIT_PRVDATA_COMPLETE; + break; + case MMC_INDX(16): + Cmd =3D BIT_CMD_RESPONSE_EXPECT | BIT_CMD_CHECK_RESPONSE_CRC | + BIT_CMD_DATA_EXPECTED | BIT_CMD_READ | + BIT_CMD_WAIT_PRVDATA_COMPLETE; + break; + case MMC_INDX(17): + case MMC_INDX(18): + Cmd =3D BIT_CMD_RESPONSE_EXPECT | BIT_CMD_CHECK_RESPONSE_CRC | + BIT_CMD_DATA_EXPECTED | BIT_CMD_READ | + BIT_CMD_WAIT_PRVDATA_COMPLETE; + break; + case MMC_INDX(24): + case MMC_INDX(25): + Cmd =3D BIT_CMD_RESPONSE_EXPECT | BIT_CMD_CHECK_RESPONSE_CRC | + BIT_CMD_DATA_EXPECTED | BIT_CMD_WRITE | + BIT_CMD_WAIT_PRVDATA_COMPLETE; + break; + case MMC_INDX(30): + Cmd =3D BIT_CMD_RESPONSE_EXPECT | BIT_CMD_CHECK_RESPONSE_CRC | + BIT_CMD_DATA_EXPECTED; + break; + default: + Cmd =3D BIT_CMD_RESPONSE_EXPECT | BIT_CMD_CHECK_RESPONSE_CRC; + break; + } + + Cmd |=3D MMC_GET_INDX(MmcCmd) | BIT_CMD_USE_HOLD_REG | BIT_CMD_START; + if (IsPendingReadCommand (Cmd) || IsPendingWriteCommand (Cmd)) { + mDwEmmcCommand =3D Cmd; + mDwEmmcArgument =3D Argument; + } else { + Status =3D SendCommand (Cmd, Argument); + } + return Status; +} + +EFI_STATUS +DwEmmcReceiveResponse ( + IN EFI_MMC_HOST_PROTOCOL *This, + IN MMC_RESPONSE_TYPE Type, + IN UINT32* Buffer + ) +{ + if (Buffer =3D=3D NULL) { + return EFI_INVALID_PARAMETER; + } + + if ( (Type =3D=3D MMC_RESPONSE_TYPE_R1) + || (Type =3D=3D MMC_RESPONSE_TYPE_R1b) + || (Type =3D=3D MMC_RESPONSE_TYPE_R3) + || (Type =3D=3D MMC_RESPONSE_TYPE_R6) + || (Type =3D=3D MMC_RESPONSE_TYPE_R7)) + { + Buffer[0] =3D MmioRead32 (DWEMMC_RESP0); + } else if (Type =3D=3D MMC_RESPONSE_TYPE_R2) { + Buffer[0] =3D MmioRead32 (DWEMMC_RESP0); + Buffer[1] =3D MmioRead32 (DWEMMC_RESP1); + Buffer[2] =3D MmioRead32 (DWEMMC_RESP2); + Buffer[3] =3D MmioRead32 (DWEMMC_RESP3); + } + return EFI_SUCCESS; +} + +VOID +DwEmmcAdjustFifoThreshold ( + VOID + ) +{ + /* DMA multiple transaction size map to reg value as array index */ + CONST UINT32 BurstSize[] =3D {1, 4, 8, 16, 32, 64, 128, 256}; + UINT32 BlkDepthInFifo, FifoThreshold, FifoWidth, FifoDepth; + UINT32 BlkSize =3D DWEMMC_BLOCK_SIZE, Idx =3D 0, RxWatermark =3D 1, TxWa= termark, TxWatermarkInvers; + + /* Skip FIFO adjustment if we do not have platform FIFO depth info */ + FifoDepth =3D PcdGet32 (PcdDwEmmcDxeFifoDepth); + if (!FifoDepth) { + return; + } + + TxWatermark =3D FifoDepth / 2; + TxWatermarkInvers =3D FifoDepth - TxWatermark; + + FifoWidth =3D DWEMMC_GET_HDATA_WIDTH (MmioRead32 (DWEMMC_HCON)); + if (!FifoWidth) { + FifoWidth =3D 2; + } else if (FifoWidth =3D=3D 2) { + FifoWidth =3D 8; + } else { + FifoWidth =3D 4; + } + + BlkDepthInFifo =3D BlkSize / FifoWidth; + + Idx =3D ARRAY_SIZE (BurstSize) - 1; + while (Idx && ((BlkDepthInFifo % BurstSize[Idx]) || (TxWatermarkInvers %= BurstSize[Idx]))) { + Idx--; + } + + RxWatermark =3D BurstSize[Idx] - 1; + FifoThreshold =3D DWEMMC_DMA_BURST_SIZE (Idx) | DWEMMC_FIFO_TWMARK (TxWa= termark) + | DWEMMC_FIFO_RWMARK (RxWatermark); + MmioWrite32 (DWEMMC_FIFOTH, FifoThreshold); +} + +EFI_STATUS +PrepareDmaData ( + IN DWEMMC_IDMAC_DESCRIPTOR* IdmacDesc, + IN UINTN Length, + IN UINT32* Buffer + ) +{ + UINTN Cnt, Blks, Idx, LastIdx; + + Cnt =3D (Length + DWEMMC_DMA_BUF_SIZE - 1) / DWEMMC_DMA_BUF_SIZE; + Blks =3D (Length + DWEMMC_BLOCK_SIZE - 1) / DWEMMC_BLOCK_SIZE; + Length =3D DWEMMC_BLOCK_SIZE * Blks; + + for (Idx =3D 0; Idx < Cnt; Idx++) { + (IdmacDesc + Idx)->Des0 =3D DWEMMC_IDMAC_DES0_OWN | DWEMMC_IDMAC_DES0_= CH | + DWEMMC_IDMAC_DES0_DIC; + (IdmacDesc + Idx)->Des1 =3D DWEMMC_IDMAC_DES1_BS1(DWEMMC_DMA_BUF_SIZE); + /* Buffer Address */ + (IdmacDesc + Idx)->Des2 =3D (UINT32)((UINTN)Buffer + DWEMMC_DMA_BUF_SI= ZE * Idx); + /* Next Descriptor Address */ + (IdmacDesc + Idx)->Des3 =3D (UINT32)((UINTN)IdmacDesc + + (sizeof(DWEMMC_IDMAC_DESCRIPTOR) * = (Idx + 1))); + } + /* First Descriptor */ + IdmacDesc->Des0 |=3D DWEMMC_IDMAC_DES0_FS; + /* Last Descriptor */ + LastIdx =3D Cnt - 1; + (IdmacDesc + LastIdx)->Des0 |=3D DWEMMC_IDMAC_DES0_LD; + (IdmacDesc + LastIdx)->Des0 &=3D ~(DWEMMC_IDMAC_DES0_DIC | DWEMMC_IDMAC_= DES0_CH); + (IdmacDesc + LastIdx)->Des1 =3D DWEMMC_IDMAC_DES1_BS1(Length - + (LastIdx * DWEMMC_DM= A_BUF_SIZE)); + /* Set the Next field of Last Descriptor */ + (IdmacDesc + LastIdx)->Des3 =3D 0; + MmioWrite32 (DWEMMC_DBADDR, (UINT32)((UINTN)IdmacDesc)); + + return EFI_SUCCESS; +} + +VOID +StartDma ( + UINTN Length + ) +{ + UINT32 Data; + + Data =3D MmioRead32 (DWEMMC_CTRL); + Data |=3D DWEMMC_CTRL_INT_EN | DWEMMC_CTRL_DMA_EN | DWEMMC_CTRL_IDMAC_EN; + MmioWrite32 (DWEMMC_CTRL, Data); + Data =3D MmioRead32 (DWEMMC_BMOD); + Data |=3D DWEMMC_IDMAC_ENABLE | DWEMMC_IDMAC_FB; + MmioWrite32 (DWEMMC_BMOD, Data); + + MmioWrite32 (DWEMMC_BLKSIZ, DWEMMC_BLOCK_SIZE); + MmioWrite32 (DWEMMC_BYTCNT, Length); +} + +EFI_STATUS +DwEmmcReadBlockData ( + IN EFI_MMC_HOST_PROTOCOL *This, + IN EFI_LBA Lba, + IN UINTN Length, + IN UINT32* Buffer + ) +{ + EFI_STATUS Status; + UINT32 DescPages, CountPerPage, Count; + EFI_TPL Tpl; + + Tpl =3D gBS->RaiseTPL (TPL_NOTIFY); + + CountPerPage =3D EFI_PAGE_SIZE / 16; + Count =3D (Length + DWEMMC_DMA_BUF_SIZE - 1) / DWEMMC_DMA_BUF_SIZE; + DescPages =3D (Count + CountPerPage - 1) / CountPerPage; + + InvalidateDataCacheRange (Buffer, Length); + + Status =3D PrepareDmaData (gpIdmacDesc, Length, Buffer); + if (EFI_ERROR (Status)) { + goto out; + } + + WriteBackDataCacheRange (gpIdmacDesc, DescPages * EFI_PAGE_SIZE); + StartDma (Length); + + Status =3D SendCommand (mDwEmmcCommand, mDwEmmcArgument); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "Failed to read data, mDwEmmcCommand:%x, mDwEmmcA= rgument:%x, Status:%r\n", mDwEmmcCommand, mDwEmmcArgument, Status)); + goto out; + } +out: + // Restore Tpl + gBS->RestoreTPL (Tpl); + return Status; +} + +EFI_STATUS +DwEmmcWriteBlockData ( + IN EFI_MMC_HOST_PROTOCOL *This, + IN EFI_LBA Lba, + IN UINTN Length, + IN UINT32* Buffer + ) +{ + EFI_STATUS Status; + UINT32 DescPages, CountPerPage, Count; + EFI_TPL Tpl; + + Tpl =3D gBS->RaiseTPL (TPL_NOTIFY); + + CountPerPage =3D EFI_PAGE_SIZE / 16; + Count =3D (Length + DWEMMC_DMA_BUF_SIZE - 1) / DWEMMC_DMA_BUF_SIZE; + DescPages =3D (Count + CountPerPage - 1) / CountPerPage; + + WriteBackDataCacheRange (Buffer, Length); + + Status =3D PrepareDmaData (gpIdmacDesc, Length, Buffer); + if (EFI_ERROR (Status)) { + goto out; + } + + WriteBackDataCacheRange (gpIdmacDesc, DescPages * EFI_PAGE_SIZE); + StartDma (Length); + + Status =3D SendCommand (mDwEmmcCommand, mDwEmmcArgument); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "Failed to write data, mDwEmmcCommand:%x, mDwEmmc= Argument:%x, Status:%r\n", mDwEmmcCommand, mDwEmmcArgument, Status)); + goto out; + } +out: + // Restore Tpl + gBS->RestoreTPL (Tpl); + return Status; +} + +EFI_STATUS +DwEmmcSetIos ( + IN EFI_MMC_HOST_PROTOCOL *This, + IN UINT32 BusClockFreq, + IN UINT32 BusWidth, + IN UINT32 TimingMode + ) +{ + EFI_STATUS Status =3D EFI_SUCCESS; + UINT32 Data; + + if ((PcdGet32 (PcdDwEmmcDxeMaxClockFreqInHz) !=3D 0) && + (BusClockFreq > PcdGet32 (PcdDwEmmcDxeMaxClockFreqInHz))) { + return EFI_UNSUPPORTED; + } + if (TimingMode !=3D EMMCBACKWARD) { + Data =3D MmioRead32 (DWEMMC_UHSREG); + switch (TimingMode) { + case EMMCHS52DDR1V2: + case EMMCHS52DDR1V8: + Data |=3D 1 << 16; + break; + case EMMCHS52: + case EMMCHS26: + Data &=3D ~(1 << 16); + break; + default: + return EFI_UNSUPPORTED; + } + MmioWrite32 (DWEMMC_UHSREG, Data); + } + + switch (BusWidth) { + case 1: + MmioWrite32 (DWEMMC_CTYPE, 0); + break; + case 4: + MmioWrite32 (DWEMMC_CTYPE, 1); + break; + case 8: + MmioWrite32 (DWEMMC_CTYPE, 1 << 16); + break; + default: + return EFI_UNSUPPORTED; + } + if (BusClockFreq) { + Status =3D DwEmmcSetClock (BusClockFreq); + } + return Status; +} + +BOOLEAN +DwEmmcIsMultiBlock ( + IN EFI_MMC_HOST_PROTOCOL *This + ) +{ + return TRUE; +} + +EFI_MMC_HOST_PROTOCOL gMciHost =3D { + MMC_HOST_PROTOCOL_REVISION, + DwEmmcIsCardPresent, + DwEmmcIsReadOnly, + DwEmmcBuildDevicePath, + DwEmmcNotifyState, + DwEmmcSendCommand, + DwEmmcReceiveResponse, + DwEmmcReadBlockData, + DwEmmcWriteBlockData, + DwEmmcSetIos, + DwEmmcIsMultiBlock +}; + +EFI_STATUS +DwEmmcDxeInitialize ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + EFI_STATUS Status; + EFI_HANDLE Handle; + + if (!FixedPcdGetBool (PcdDwPermitObsoleteDrivers)) { + ASSERT (FALSE); + return EFI_UNSUPPORTED; + } + + Handle =3D NULL; + + DwEmmcAdjustFifoThreshold (); + gpIdmacDesc =3D (DWEMMC_IDMAC_DESCRIPTOR *)AllocatePages (DWEMMC_MAX_DES= C_PAGES); + if (gpIdmacDesc =3D=3D NULL) { + return EFI_BUFFER_TOO_SMALL; + } + + DEBUG ((DEBUG_BLKIO, "DwEmmcDxeInitialize()\n")); + + //Publish Component Name, BlockIO protocol interfaces + Status =3D gBS->InstallMultipleProtocolInterfaces ( + &Handle, + &gEmbeddedMmcHostProtocolGuid, &gMciHost, + NULL + ); + ASSERT_EFI_ERROR (Status); + + return EFI_SUCCESS; +} diff --git a/Silicon/Synopsys/DesignWare/Drivers/DwEmmcDxe/DwEmmcDxe.inf b/= Silicon/Synopsys/DesignWare/Drivers/DwEmmcDxe/DwEmmcDxe.inf new file mode 100644 index 000000000000..7f70fe1e2a38 --- /dev/null +++ b/Silicon/Synopsys/DesignWare/Drivers/DwEmmcDxe/DwEmmcDxe.inf @@ -0,0 +1,56 @@ +#/** @file +# INF file for the eMMC Host Protocol implementation for the DesignWare M= MC. +# +# WARNING: +# This driver fails to follow the UEFI driver model without a good +# reason, and only remains in the tree because it is still used by +# a small number of platforms. It will be removed when no longer used. +# +# Copyright (c) 2014-2017, Linaro Limited. All rights reserved. +# +# SPDX-License-Identifier: BSD-2-Clause-Patent +# +#**/ + +[Defines] + INF_VERSION =3D 0x00010019 + BASE_NAME =3D DwEmmcDxe + FILE_GUID =3D b549f005-4bd4-4020-a0cb-06f42bda68c3 + MODULE_TYPE =3D DXE_DRIVER + VERSION_STRING =3D 1.0 + + ENTRY_POINT =3D DwEmmcDxeInitialize + +[Sources.common] + DwEmmcDxe.c + +[Packages] + EmbeddedPkg/EmbeddedPkg.dec + MdePkg/MdePkg.dec + Silicon/Synopsys/DesignWare/DesignWare.dec + +[LibraryClasses] + ArmLib + BaseLib + BaseMemoryLib + CacheMaintenanceLib + IoLib + MemoryAllocationLib + TimerLib + UefiDriverEntryPoint + UefiLib + +[Protocols] + gEfiCpuArchProtocolGuid + gEfiDevicePathProtocolGuid + gEmbeddedMmcHostProtocolGuid + +[Pcd] + gDesignWareTokenSpaceGuid.PcdDwEmmcDxeBaseAddress + gDesignWareTokenSpaceGuid.PcdDwEmmcDxeClockFrequencyInHz + gDesignWareTokenSpaceGuid.PcdDwEmmcDxeMaxClockFreqInHz + gDesignWareTokenSpaceGuid.PcdDwEmmcDxeFifoDepth + gDesignWareTokenSpaceGuid.PcdDwPermitObsoleteDrivers + +[Depex] + TRUE --=20 2.17.1 -=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D- Groups.io Links: You receive all messages sent to this group. View/Reply Online (#58452): https://edk2.groups.io/g/devel/message/58452 Mute This Topic: https://groups.io/mt/73380293/1787277 Group Owner: devel+owner@edk2.groups.io Unsubscribe: https://edk2.groups.io/g/devel/unsub [importer@patchew.org] -=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D- From nobody Mon May 6 19:29:01 2024 Delivered-To: importer@patchew.org Received-SPF: pass (zohomail.com: domain of groups.io designates 66.175.222.12 as permitted sender) client-ip=66.175.222.12; envelope-from=bounce+27952+58453+1787277+3901457@groups.io; helo=web01.groups.io; Authentication-Results: mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of groups.io designates 66.175.222.12 as permitted sender) smtp.mailfrom=bounce+27952+58453+1787277+3901457@groups.io ARC-Seal: i=1; a=rsa-sha256; t=1588267025; cv=none; d=zohomail.com; s=zohoarc; b=TyHpoAlQRf7G/Z52lI2XNZ+fbSwvQTV3GpPiCP0cUjhC0uly6nopnenqnG9SnShiL+Nj2bW4kGvNSTDSd0jQUYWgboQhXrO7AR/FwQADGXUZilCG7f9fIt/00FEeiukXnwKoJVkuKrZHrZisj7teRGbSP3UWqjQxXjYZ8jykeV0= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1588267025; h=Cc:Date:From:In-Reply-To:List-Id:List-Unsubscribe:Message-ID:Reply-To:References:Sender:Subject:To; bh=qUHsi3LWyBXplapvKYDpj9JbfIPWyK/3j3xZERExv+8=; b=Veqq9Lbp6d4I2WKqunZuiyssMKe7OqYt8wPx2+XCUY5PSgp99x65K04rKSP12LLSw8dVMPPvd9fR4UlhT334ehiS4gEiVsTKHvD9LOxGDy4hSEOjG2yb5ycLI+Zc1SyHW9/ZK6qQ8k+6aL1OL0VWjoXSbS1mCHWZsvbYRZFoiiQ= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of groups.io designates 66.175.222.12 as permitted sender) smtp.mailfrom=bounce+27952+58453+1787277+3901457@groups.io Received: from web01.groups.io (web01.groups.io [66.175.222.12]) by mx.zohomail.com with SMTPS id 158826702564176.5924648150584; Thu, 30 Apr 2020 10:17:05 -0700 (PDT) Return-Path: X-Received: by 127.0.0.2 with SMTP id Na29YY1788612xVJTvMwMOL9; Thu, 30 Apr 2020 10:17:05 -0700 X-Received: from foss.arm.com (foss.arm.com [217.140.110.172]) by mx.groups.io with SMTP id smtpd.web10.755.1588267024602998260 for ; Thu, 30 Apr 2020 10:17:04 -0700 X-Received: from usa-sjc-imap-foss1.foss.arm.com (unknown [10.121.207.14]) by usa-sjc-mx-foss1.foss.arm.com (Postfix) with ESMTP id 34C0E101E; Thu, 30 Apr 2020 10:17:04 -0700 (PDT) X-Received: from e123331-lin.home (unknown [172.31.20.19]) by usa-sjc-imap-foss1.foss.arm.com (Postfix) with ESMTPSA id 3428A3F73D; Thu, 30 Apr 2020 10:17:02 -0700 (PDT) From: "Ard Biesheuvel" To: devel@edk2.groups.io Cc: leif@nuviainc.com, Ard Biesheuvel Subject: [edk2-devel] [PATCH edk2-platforms v3 5/8] Platform/HiKey: switch to relocated version of eMMC driver Date: Thu, 30 Apr 2020 19:16:46 +0200 Message-Id: <20200430171650.24139-6-ard.biesheuvel@arm.com> In-Reply-To: <20200430171650.24139-1-ard.biesheuvel@arm.com> References: <20200430171650.24139-1-ard.biesheuvel@arm.com> Precedence: Bulk List-Unsubscribe: Sender: devel@edk2.groups.io List-Id: <27952.devel.edk2.groups.io> Mailing-List: list devel@edk2.groups.io; contact devel+owner@edk2.groups.io Reply-To: devel@edk2.groups.io,ard.biesheuvel@arm.com X-Gm-Message-State: xNwrG2tLeycplZVfb2D1Y7Rqx1787277AA= DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=groups.io; q=dns/txt; s=20140610; t=1588267025; bh=ChmYGD+sVMTrIl+wyT6P/OZPeKsfQM7vTDGt5mssKzw=; h=Cc:Date:From:Reply-To:Subject:To; b=mkuTg32gLiSj1KikaBSWFU1DrGbLsXA9s9DcZVmLW5nFxQMIeT1UnTgymQ5om9MMJH/ pqi7q9zy9aImMCOEn5JntIG1ullkxAR86QR9LV4nHp93ISQC/kvyXNhxZT5OL8+AqBLus NBjw2o+yd3ho5cvB/nd6cPbquHEKoEViNU4= X-ZohoMail-DKIM: pass (identity @groups.io) Content-Transfer-Encoding: quoted-printable MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Switch to the version of the DesignWare eMMC host controller driver that was moved into edk2-platforms, as part of a spring cleaning exercise of EmbeddedPkg. Signed-off-by: Ard Biesheuvel Reviewed-by: Leif Lindholm --- Platform/Hisilicon/HiKey/HiKey.dsc | 7 ++++--- Platform/Hisilicon/HiKey/HiKey.fdf | 2 +- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/Platform/Hisilicon/HiKey/HiKey.dsc b/Platform/Hisilicon/HiKey/= HiKey.dsc index bcbe4fafce1a..600f19a30762 100644 --- a/Platform/Hisilicon/HiKey/HiKey.dsc +++ b/Platform/Hisilicon/HiKey/HiKey.dsc @@ -131,8 +131,9 @@ [PcdsFixedAtBuild.common] # # DW MMC/SD card controller # - gEmbeddedTokenSpaceGuid.PcdDwEmmcDxeBaseAddress|0xF723D000 - gEmbeddedTokenSpaceGuid.PcdDwEmmcDxeClockFrequencyInHz|100000000 + gDesignWareTokenSpaceGuid.PcdDwEmmcDxeBaseAddress|0xF723D000 + gDesignWareTokenSpaceGuid.PcdDwEmmcDxeClockFrequencyInHz|100000000 + gDesignWareTokenSpaceGuid.PcdDwPermitObsoleteDrivers|TRUE =20 # # @@ -216,7 +217,7 @@ [Components.common] # MMC/SD # EmbeddedPkg/Universal/MmcDxe/MmcDxe.inf - EmbeddedPkg/Drivers/DwEmmcDxe/DwEmmcDxe.inf + Silicon/Synopsys/DesignWare/Drivers/DwEmmcDxe/DwEmmcDxe.inf =20 # # USB Host Support diff --git a/Platform/Hisilicon/HiKey/HiKey.fdf b/Platform/Hisilicon/HiKey/= HiKey.fdf index 33fa0da208fb..657e6c8ef2ec 100644 --- a/Platform/Hisilicon/HiKey/HiKey.fdf +++ b/Platform/Hisilicon/HiKey/HiKey.fdf @@ -128,7 +128,7 @@ [FV.FvMain] # Multimedia Card Interface # INF EmbeddedPkg/Universal/MmcDxe/MmcDxe.inf - INF EmbeddedPkg/Drivers/DwEmmcDxe/DwEmmcDxe.inf + INF Silicon/Synopsys/DesignWare/Drivers/DwEmmcDxe/DwEmmcDxe.inf =20 # # USB Host Support --=20 2.17.1 -=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D- Groups.io Links: You receive all messages sent to this group. View/Reply Online (#58453): https://edk2.groups.io/g/devel/message/58453 Mute This Topic: https://groups.io/mt/73380295/1787277 Group Owner: devel+owner@edk2.groups.io Unsubscribe: https://edk2.groups.io/g/devel/unsub [importer@patchew.org] -=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D- From nobody Mon May 6 19:29:01 2024 Delivered-To: importer@patchew.org Received-SPF: pass (zohomail.com: domain of groups.io designates 66.175.222.12 as permitted sender) client-ip=66.175.222.12; envelope-from=bounce+27952+58454+1787277+3901457@groups.io; helo=web01.groups.io; Authentication-Results: mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of groups.io designates 66.175.222.12 as permitted sender) smtp.mailfrom=bounce+27952+58454+1787277+3901457@groups.io ARC-Seal: i=1; a=rsa-sha256; t=1588267027; cv=none; d=zohomail.com; s=zohoarc; b=bCirbKUHhVARGKGtgk/NaZq09Y6IHupaaDTXr5zDgA1eMFkoW08hH33BcuNxx7iePqS8PmWK7LlFt+3j2MMyTLFNxnorD4JmZbjhndrV5iYr5gd1hp68CB6q7nKP4KK75c+Y8ZnpuJ7fmetO9/ws6ABn+GhJS8+WgIYpY98rf/4= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1588267027; h=Cc:Date:From:In-Reply-To:List-Id:List-Unsubscribe:Message-ID:Reply-To:References:Sender:Subject:To; bh=+qrpIun72BLDewAO5KyaOB+1rmTaYvXYztqnBYLpzT4=; b=A4xNsEKoc+zDSgP6NEXK/uCTcfNNTbWgMM0QfgrUFRGNAaImtRrvjD/YVik0Q0Ep4mcbe5IHDYXk0dOJMFOiIuFqCpLBgVEcIVayzrisq/PK8RBfWko/26vZEnmv7UQUYWGW7ulfP1xijLxQk/u0F7OaI5CIpZjSFbzHU1JKsI4= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of groups.io designates 66.175.222.12 as permitted sender) smtp.mailfrom=bounce+27952+58454+1787277+3901457@groups.io Received: from web01.groups.io (web01.groups.io [66.175.222.12]) by mx.zohomail.com with SMTPS id 1588267027291718.0115581902533; Thu, 30 Apr 2020 10:17:07 -0700 (PDT) Return-Path: X-Received: by 127.0.0.2 with SMTP id agmTYY1788612x05SPVhNo8t; Thu, 30 Apr 2020 10:17:06 -0700 X-Received: from foss.arm.com (foss.arm.com [217.140.110.172]) by mx.groups.io with SMTP id smtpd.web11.823.1588267026228539046 for ; Thu, 30 Apr 2020 10:17:06 -0700 X-Received: from usa-sjc-imap-foss1.foss.arm.com (unknown [10.121.207.14]) by usa-sjc-mx-foss1.foss.arm.com (Postfix) with ESMTP id D6537106F; Thu, 30 Apr 2020 10:17:05 -0700 (PDT) X-Received: from e123331-lin.home (unknown [172.31.20.19]) by usa-sjc-imap-foss1.foss.arm.com (Postfix) with ESMTPSA id 95AD13F73D; Thu, 30 Apr 2020 10:17:04 -0700 (PDT) From: "Ard Biesheuvel" To: devel@edk2.groups.io Cc: leif@nuviainc.com, Ard Biesheuvel Subject: [edk2-devel] [PATCH edk2-platforms v3 6/8] Platform/ARM/VExpressPkg: incorporate Lan91x driver Date: Thu, 30 Apr 2020 19:16:47 +0200 Message-Id: <20200430171650.24139-7-ard.biesheuvel@arm.com> In-Reply-To: <20200430171650.24139-1-ard.biesheuvel@arm.com> References: <20200430171650.24139-1-ard.biesheuvel@arm.com> Precedence: Bulk List-Unsubscribe: Sender: devel@edk2.groups.io List-Id: <27952.devel.edk2.groups.io> Mailing-List: list devel@edk2.groups.io; contact devel+owner@edk2.groups.io Reply-To: devel@edk2.groups.io,ard.biesheuvel@arm.com X-Gm-Message-State: erTthd2XBUe4Tx1615fm7u3Dx1787277AA= DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=groups.io; q=dns/txt; s=20140610; t=1588267026; bh=LzqfPRugZhoKq1/9eixZk2SmB00CPUVMlYJAHrBf/qc=; h=Cc:Date:From:Reply-To:Subject:To; b=RMM1ScJtYNJVXqNnkJNzK2DvahC4jMGPOmr0BJl+VsnqK5gDZF3AILkEEMgCaMPgwzF IPo/twgcOytp3/Zr3zM96BtdBn/+xijn95j1hrt9AscxjvDNXwVIwM0iYIzvMvFObFYp0 c0ApvgzAcoBjIbZ7mv9LVzu8GNiUCqfgvgs= X-ZohoMail-DKIM: pass (identity @groups.io) Content-Transfer-Encoding: quoted-printable MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Incorporate the Lan91x driver from EmbeddedPkg, which is only used on emulated ARM development platforms and does not follow the UEFI driver model. This will allow us to drop if from the core EDK2 repository. Signed-off-by: Ard Biesheuvel Reviewed-by: Leif Lindholm Reviewed-by: Philippe Mathieu-Daude Reviewed-by: Philippe Mathieu-Daud=C3=A9 --- Platform/ARM/SgiPkg/SgiPlatform.dsc | 4 +- Platform/ARM/SgiPkg/SgiPlatform.fdf | 2 +- Platform/ARM/VExpressPkg/ArmVExpress-FVP-AArch64.fdf | 2 +- Platform/ARM/VExpressPkg/ArmVExpress.dsc.inc | 4 +- Platform/ARM/VExpressPkg/ArmVExpressPkg.dec | 3 + Platform/ARM/VExpressPkg/Drivers/Lan91xDxe/Lan91xDxe.c | 2236 ++++++++++= ++++++++++ Platform/ARM/VExpressPkg/Drivers/Lan91xDxe/Lan91xDxe.inf | 59 + Platform/ARM/VExpressPkg/Drivers/Lan91xDxe/Lan91xDxeHw.h | 279 +++ 8 files changed, 2583 insertions(+), 6 deletions(-) diff --git a/Platform/ARM/SgiPkg/SgiPlatform.dsc b/Platform/ARM/SgiPkg/SgiP= latform.dsc index 5226c5751e98..fddc1fef65d4 100644 --- a/Platform/ARM/SgiPkg/SgiPlatform.dsc +++ b/Platform/ARM/SgiPkg/SgiPlatform.dsc @@ -188,7 +188,7 @@ [PcdsFixedAtBuild.common] =20 # Ethernet / Virtio Network !ifdef EDK2_ENABLE_SMSC_91X - gEmbeddedTokenSpaceGuid.PcdLan91xDxeBaseAddress|0x18000000 + gArmVExpressTokenSpaceGuid.PcdLan91xDxeBaseAddress|0x18000000 !endif gArmSgiTokenSpaceGuid.PcdVirtioNetBaseAddress|0x1c150000 gArmSgiTokenSpaceGuid.PcdVirtioNetSize|0x10000 @@ -313,7 +313,7 @@ [Components.common] =20 # SMSC LAN 91C111 / Virtio Network !ifdef EDK2_ENABLE_SMSC_91X - EmbeddedPkg/Drivers/Lan91xDxe/Lan91xDxe.inf + Platform/ARM/VExpressPkg/Drivers/Lan91xDxe/Lan91xDxe.inf !endif OvmfPkg/VirtioNetDxe/VirtioNet.inf =20 diff --git a/Platform/ARM/SgiPkg/SgiPlatform.fdf b/Platform/ARM/SgiPkg/SgiP= latform.fdf index 3d13998015b9..2bf00f0022f3 100644 --- a/Platform/ARM/SgiPkg/SgiPlatform.fdf +++ b/Platform/ARM/SgiPkg/SgiPlatform.fdf @@ -187,7 +187,7 @@ [FV.FvMain] !include NetworkPkg/Network.fdf.inc =20 !ifdef EDK2_ENABLE_SMSC_91X - INF EmbeddedPkg/Drivers/Lan91xDxe/Lan91xDxe.inf + INF Platform/ARM/VExpressPkg/Drivers/Lan91xDxe/Lan91xDxe.inf !endif INF OvmfPkg/VirtioNetDxe/VirtioNet.inf =20 diff --git a/Platform/ARM/VExpressPkg/ArmVExpress-FVP-AArch64.fdf b/Platfor= m/ARM/VExpressPkg/ArmVExpress-FVP-AArch64.fdf index f18ead75eaec..513054dbcbc5 100644 --- a/Platform/ARM/VExpressPkg/ArmVExpress-FVP-AArch64.fdf +++ b/Platform/ARM/VExpressPkg/ArmVExpress-FVP-AArch64.fdf @@ -154,7 +154,7 @@ [FV.FvMain] =20 !ifdef EDK2_ENABLE_SMSC_91X !include Platform/ARM/VExpressPkg/ArmVExpress-networking.fdf.inc - INF EmbeddedPkg/Drivers/Lan91xDxe/Lan91xDxe.inf + INF Platform/ARM/VExpressPkg/Drivers/Lan91xDxe/Lan91xDxe.inf !endif =20 # diff --git a/Platform/ARM/VExpressPkg/ArmVExpress.dsc.inc b/Platform/ARM/VE= xpressPkg/ArmVExpress.dsc.inc index 0d543d2a61b1..912ad5e5a1ec 100644 --- a/Platform/ARM/VExpressPkg/ArmVExpress.dsc.inc +++ b/Platform/ARM/VExpressPkg/ArmVExpress.dsc.inc @@ -368,7 +368,7 @@ [PcdsFixedAtBuild.common] =20 !ifdef EDK2_ENABLE_SMSC_91X # Ethernet (SMSC 91C111) - gEmbeddedTokenSpaceGuid.PcdLan91xDxeBaseAddress|0x1A000000 + gArmVExpressTokenSpaceGuid.PcdLan91xDxeBaseAddress|0x1A000000 !endif =20 !if $(SECURE_BOOT_ENABLE) =3D=3D TRUE @@ -417,7 +417,7 @@ [Components.common] !include NetworkPkg/Network.dsc.inc !ifdef EDK2_ENABLE_SMSC_91X # SMSC LAN 91C111 - EmbeddedPkg/Drivers/Lan91xDxe/Lan91xDxe.inf + Platform/ARM/VExpressPkg/Drivers/Lan91xDxe/Lan91xDxe.inf !endif =20 # diff --git a/Platform/ARM/VExpressPkg/ArmVExpressPkg.dec b/Platform/ARM/VEx= pressPkg/ArmVExpressPkg.dec index a4e9bfd73eb6..ea000a0e5387 100644 --- a/Platform/ARM/VExpressPkg/ArmVExpressPkg.dec +++ b/Platform/ARM/VExpressPkg/ArmVExpressPkg.dec @@ -56,3 +56,6 @@ [PcdsFixedAtBuild.common] ## PL180 MCI gArmVExpressTokenSpaceGuid.PcdPL180SysMciRegAddress|0x00000000|UINT32|0x= 00000009 gArmVExpressTokenSpaceGuid.PcdPL180MciBaseAddress|0x00000000|UINT32|0x00= 00000A + + # LAN91x Ethernet Driver PCDs + gArmVExpressTokenSpaceGuid.PcdLan91xDxeBaseAddress|0x0|UINT32|0x0000000B diff --git a/Platform/ARM/VExpressPkg/Drivers/Lan91xDxe/Lan91xDxe.c b/Platf= orm/ARM/VExpressPkg/Drivers/Lan91xDxe/Lan91xDxe.c new file mode 100644 index 000000000000..fae318ab96d5 --- /dev/null +++ b/Platform/ARM/VExpressPkg/Drivers/Lan91xDxe/Lan91xDxe.c @@ -0,0 +1,2236 @@ +/** @file +* SMSC LAN91x series Network Controller Driver. +* +* WARNING: +* This driver fails to follow the UEFI driver model without a good +* reason, and only remains in the tree because it is still used by +* a small number of platforms. It will be removed when no longer used. +* New platforms should not use it, and no one should use this as +* reference code for developing new drivers. +* +* Copyright (c) 2013-2017 Linaro.org +* +* Derived from the LAN9118 driver. Original sources +* Copyright (c) 2012-2013, ARM Limited. All rights reserved. +* +* SPDX-License-Identifier: BSD-2-Clause-Patent +* +**/ + +#include +#include +#include + +// Protocols used by this driver +#include +#include +#include +#include + +// Libraries used by this driver +#include +#include +#include +#include +#include +#include +#include +#include + +// Hardware register definitions +#include "Lan91xDxeHw.h" + +// Debugging output options +//#define LAN91X_PRINT_REGISTERS 1 +//#define LAN91X_PRINT_PACKET_HEADERS 1 +//#define LAN91X_PRINT_RECEIVE_FILTERS 1 + +// Chip power-down option -- UNTESTED +//#define LAN91X_POWER_DOWN 1 + +/*------------------------------------------------------------------------= --------------------------------------------- + + LAN91x Information Structure + +--------------------------------------------------------------------------= -------------------------------------------*/ +typedef struct _LAN91X_DRIVER { + // Driver signature + UINT32 Signature; + EFI_HANDLE ControllerHandle; + + // EFI SNP protocol instances + EFI_SIMPLE_NETWORK_PROTOCOL Snp; + EFI_SIMPLE_NETWORK_MODE SnpMode; + + // EFI Snp statistics instance + EFI_NETWORK_STATISTICS Stats; + + // Transmit Buffer recycle queue + + LIST_ENTRY TransmitQueueHead; + + // Register access variables + UINTN IoBase; // I/O Base Address + UINT8 Revision; // Chip Revision Number + INT8 PhyAd; // Phy Address + UINT8 BankSel; // Currently selected register bank + +} LAN91X_DRIVER; + +#define LAN91X_NO_PHY (-1) // PhyAd value if PHY not detected + +#define LAN91X_SIGNATURE SIGNATURE_32('S', 'M', '9'= , '1') +#define INSTANCE_FROM_SNP_THIS(a) CR(a, LAN91X_DRIVER, Snp, = LAN91X_SIGNATURE) + +#define LAN91X_STALL 2 +#define LAN91X_MEMORY_ALLOC_POLLS 100 // Max times to poll for memory al= location +#define LAN91X_PKT_OVERHEAD 6 // Overhead bytes in packet buffer + +// Synchronization TPLs +#define LAN91X_TPL TPL_CALLBACK + +// Most common CRC32 Polynomial for little endian machines +#define CRC_POLYNOMIAL 0xEDB88320 + + +typedef struct { + MAC_ADDR_DEVICE_PATH Lan91x; + EFI_DEVICE_PATH_PROTOCOL End; +} LAN91X_DEVICE_PATH; + +LAN91X_DEVICE_PATH Lan91xPathTemplate =3D { + { + { + MESSAGING_DEVICE_PATH, MSG_MAC_ADDR_DP, + { (UINT8) (sizeof(MAC_ADDR_DEVICE_PATH)), (UINT8) ((sizeof(MAC_ADDR_= DEVICE_PATH)) >> 8) } + }, + { { 0 } }, + 0 + }, + { + END_DEVICE_PATH_TYPE, + END_ENTIRE_DEVICE_PATH_SUBTYPE, + { sizeof(EFI_DEVICE_PATH_PROTOCOL), 0 } + } +}; + +// Chip ID numbers and name strings +#define CHIP_9192 3 +#define CHIP_9194 4 +#define CHIP_9195 5 +#define CHIP_9196 6 +#define CHIP_91100 7 +#define CHIP_91100FD 8 +#define CHIP_91111FD 9 + +STATIC CHAR16 CONST * CONST ChipIds[ 16 ] =3D { + NULL, NULL, NULL, + /* 3 */ L"SMC91C90/91C92", + /* 4 */ L"SMC91C94", + /* 5 */ L"SMC91C95", + /* 6 */ L"SMC91C96", + /* 7 */ L"SMC91C100", + /* 8 */ L"SMC91C100FD", + /* 9 */ L"SMC91C11xFD", + NULL, NULL, NULL, + NULL, NULL, NULL +}; + +/* ------------------ TxBuffer Queue structures ------------------- */ + +typedef struct { + VOID *Buf; + UINTN Length; +} MSK_SYSTEM_BUF; + +typedef struct { + UINTN Signature; + LIST_ENTRY Link; + MSK_SYSTEM_BUF SystemBuf; +} MSK_LINKED_SYSTEM_BUF; + +#define TX_MBUF_SIGNATURE SIGNATURE_32 ('t','x','m','b') + +/* ------------------ MAC Address Hash Calculations ------------------- */ + +/* +** Generate a hash value from a multicast address +** +** This uses the Ethernet standard CRC32 algorithm +** +** INFO USED: +** 1: http://en.wikipedia.org/wiki/Cyclic_redundancy_check +** +** 2: http://www.erg.abdn.ac.uk/~gorry/eg3567/dl-pages/crc.html +** +** 3: http://en.wikipedia.org/wiki/Computation_of_CRC +*/ +STATIC +UINT32 +MulticastHash ( + IN EFI_MAC_ADDRESS *Mac, + IN UINT32 AddrLen + ) +{ + UINT32 Iter; + UINT32 Remainder; + UINT32 Crc32; + UINT8 *Addr; + + // 0xFFFFFFFF is standard seed for Ethernet + Remainder =3D 0xFFFFFFFF; + + // Generate the remainder byte-by-byte (LSB first) + Addr =3D &Mac->Addr[0]; + while (AddrLen-- > 0) { + Remainder ^=3D *Addr++; + for (Iter =3D 0; Iter < 8; ++Iter) { + // Check if exponent is set + if ((Remainder & 1) !=3D 0) { + Remainder =3D (Remainder >> 1) ^ CRC_POLYNOMIAL; + } else { + Remainder =3D (Remainder >> 1) ^ 0; + } + } + } + + // Reverse the bits of the remainder + Crc32 =3D 0; + for (Iter =3D 0; Iter < 32; ++Iter) { + Crc32 <<=3D 1; + Crc32 |=3D Remainder & 1; + Remainder >>=3D 1; + } + return Crc32; +} + + +/* ---------------- Banked Register Operations ------------------ */ + +// Select the proper I/O bank +STATIC +VOID +SelectIoBank ( + LAN91X_DRIVER *LanDriver, + UINTN Register + ) +{ + UINT8 Bank; + + Bank =3D RegisterToBank (Register); + + // Select the proper I/O bank + if (LanDriver->BankSel !=3D Bank) { + MmioWrite16 (LanDriver->IoBase + LAN91X_BANK_OFFSET, Bank); + LanDriver->BankSel =3D Bank; + } +} + +// Read a 16-bit I/O-space register +STATIC +UINT16 +ReadIoReg16 ( + LAN91X_DRIVER *LanDriver, + UINTN Register + ) +{ + UINT8 Offset; + + // Select the proper I/O bank + SelectIoBank (LanDriver, Register); + + // Read the requested register + Offset =3D RegisterToOffset (Register); + return MmioRead16 (LanDriver->IoBase + Offset); +} + +// Write a 16-bit I/O-space register +STATIC +UINT16 +WriteIoReg16 ( + LAN91X_DRIVER *LanDriver, + UINTN Register, + UINT16 Value + ) +{ + UINT8 Offset; + + // Select the proper I/O bank + SelectIoBank (LanDriver, Register); + + // Write the requested register + Offset =3D RegisterToOffset (Register); + return MmioWrite16 (LanDriver->IoBase + Offset, Value); +} + +// Read an 8-bit I/O-space register +STATIC +UINT8 +ReadIoReg8 ( + LAN91X_DRIVER *LanDriver, + UINTN Register + ) +{ + UINT8 Offset; + + // Select the proper I/O bank + SelectIoBank (LanDriver, Register); + + // Read the requested register + Offset =3D RegisterToOffset (Register); + return MmioRead8 (LanDriver->IoBase + Offset); +} + +// Write an 8-bit I/O-space register +STATIC +UINT8 +WriteIoReg8 ( + LAN91X_DRIVER *LanDriver, + UINTN Register, + UINT8 Value + ) +{ + UINT8 Offset; + + // Select the proper I/O bank + SelectIoBank (LanDriver, Register); + + // Write the requested register + Offset =3D RegisterToOffset (Register); + return MmioWrite8 (LanDriver->IoBase + Offset, Value); +} + + +/* ---------------- MII/PHY Access Operations ------------------ */ + +#define LAN91X_MDIO_STALL 1 + +STATIC +VOID +MdioOutput ( + LAN91X_DRIVER *LanDriver, + UINTN Bits, + UINT32 Value + ) +{ + UINT16 MgmtReg; + UINT32 Mask; + + MgmtReg =3D ReadIoReg16 (LanDriver, LAN91X_MGMT); + MgmtReg &=3D ~MGMT_MCLK; + MgmtReg |=3D MGMT_MDOE; + + for (Mask =3D (1 << (Bits - 1)); Mask !=3D 0; Mask >>=3D 1) { + if ((Value & Mask) !=3D 0) { + MgmtReg |=3D MGMT_MDO; + } else { + MgmtReg &=3D ~MGMT_MDO; + } + + WriteIoReg16 (LanDriver, LAN91X_MGMT, MgmtReg); + gBS->Stall (LAN91X_MDIO_STALL); + WriteIoReg16 (LanDriver, LAN91X_MGMT, MgmtReg | MGMT_MCLK); + gBS->Stall (LAN91X_MDIO_STALL); + } +} +#define PHY_OUTPUT_TIME (2 * LAN91X_MDIO_STALL) + +STATIC +UINT32 +MdioInput ( + LAN91X_DRIVER *LanDriver, + UINTN Bits + ) +{ + UINT16 MgmtReg; + UINT32 Mask; + UINT32 Value; + + MgmtReg =3D ReadIoReg16 (LanDriver, LAN91X_MGMT); + MgmtReg &=3D ~(MGMT_MDOE | MGMT_MCLK | MGMT_MDO); + WriteIoReg16 (LanDriver, LAN91X_MGMT, MgmtReg); + + Value =3D 0; + for (Mask =3D (1 << (Bits - 1)); Mask !=3D 0; Mask >>=3D 1) { + if ((ReadIoReg16 (LanDriver, LAN91X_MGMT) & MGMT_MDI) !=3D 0) { + Value |=3D Mask; + } + + WriteIoReg16 (LanDriver, LAN91X_MGMT, MgmtReg); + gBS->Stall (LAN91X_MDIO_STALL); + WriteIoReg16 (LanDriver, LAN91X_MGMT, MgmtReg | MGMT_MCLK); + gBS->Stall (LAN91X_MDIO_STALL); + } + + return Value; +} +#define PHY_INPUT_TIME (2 * LAN91X_MDIO_STALL) + +STATIC +VOID +MdioIdle ( + LAN91X_DRIVER *LanDriver + ) +{ + UINT16 MgmtReg; + + MgmtReg =3D ReadIoReg16 (LanDriver, LAN91X_MGMT); + MgmtReg &=3D ~(MGMT_MDOE | MGMT_MCLK | MGMT_MDO); + WriteIoReg16 (LanDriver, LAN91X_MGMT, MgmtReg); +} + +// Write to a PHY register +STATIC +VOID +WritePhyReg16 ( + LAN91X_DRIVER *LanDriver, + UINTN RegAd, + UINT16 Value + ) +{ + // Bit-bang the MII Serial Frame write operation + MdioOutput (LanDriver, 32, 0xffffffff); // Send 32 Ones as a pream= ble + MdioOutput (LanDriver, 2, 0x01); // Send Start (01) + MdioOutput (LanDriver, 2, 0x01); // Send Write (01) + MdioOutput (LanDriver, 5, LanDriver->PhyAd); // Send PHYAD[4:0] + MdioOutput (LanDriver, 5, RegAd); // Send REGAD[4:0] + MdioOutput (LanDriver, 2, 0x02); // Send TurnAround (10) + MdioOutput (LanDriver, 16, Value); // Write 16 data bits + + // Idle the MDIO bus + MdioIdle (LanDriver); +} +// Calculate approximate time to write a PHY register in microseconds +#define PHY_WRITE_TIME ((32 + 2 + 2 + 5 + 5 + 2 + 16) * PHY_OUTPUT_TIME) + +// Read from a PHY register +STATIC +UINT16 +ReadPhyReg16 ( + LAN91X_DRIVER *LanDriver, + UINTN RegAd + ) +{ + UINT32 Value; + + // Bit-bang the MII Serial Frame read operation + MdioOutput (LanDriver, 32, 0xffffffff); // Send 32 Ones as a pream= ble + MdioOutput (LanDriver, 2, 0x01); // Send Start (01) + MdioOutput (LanDriver, 2, 0x02); // Send Read (10) + MdioOutput (LanDriver, 5, LanDriver->PhyAd); // Send PHYAD[4:0] + MdioOutput (LanDriver, 5, RegAd); // Send REGAD[4:0] + + (VOID) MdioInput (LanDriver, 2); // Discard TurnAround bits + Value =3D MdioInput (LanDriver, 16); // Read 16 data bits + + // Idle the MDIO bus + MdioIdle (LanDriver); + + return (Value & 0xffff); +} +// Calculate approximate time to read a PHY register in microseconds +#define PHY_READ_TIME (((32 + 2 + 2 + 5 + 5) * PHY_OUTPUT_TIME) + \ + ((2 + 16) * PHY_INPUT_TIME)) + + +/* ---------------- Debug Functions ------------------ */ + +#ifdef LAN91X_PRINT_REGISTERS +STATIC +VOID +PrintIoRegisters ( + IN LAN91X_DRIVER *LanDriver + ) +{ + UINTN Bank; + UINTN Offset; + UINT16 Value; + + DEBUG ((DEBUG_ERROR, "\nLAN91x I/O Register Dump:\n")); + + // Print current bank select register + Value =3D MmioRead16 (LanDriver->IoBase + LAN91X_BANK_OFFSET); + DEBUG ((DEBUG_ERROR, " BankSel: %d Bank Register %04x (%d)\n", + LanDriver->BankSel, Value, Value & 0x0007)); + + // Print all I/O registers + for (Offset =3D 0; Offset < 0x0e; Offset +=3D 2) { + DEBUG ((DEBUG_ERROR, " %02x:", Offset)); + for (Bank =3D 0; Bank <=3D 3; ++Bank) { + DEBUG ((DEBUG_ERROR, " %04x", ReadIoReg16 (LanDriver, MakeRegister = (Bank, Offset)))); + } + DEBUG ((DEBUG_ERROR, "\n")); + } +} + +STATIC +VOID +PrintPhyRegisters ( + IN LAN91X_DRIVER *LanDriver + ) +{ + UINTN RegNum; + + DEBUG ((DEBUG_ERROR, "\nLAN91x Phy %d Register Dump:\n", LanDriver->PhyA= d)); + + // Print all Phy registers + for (RegNum =3D 0; RegNum <=3D 5; ++RegNum) { + DEBUG ((DEBUG_ERROR, " %2d: %04x\n", + RegNum, + ReadPhyReg16 (LanDriver, RegNum) + )); + } + for (RegNum =3D 16; RegNum <=3D 20; ++RegNum) { + DEBUG ((DEBUG_ERROR, " %2d: %04x\n", + RegNum, + ReadPhyReg16 (LanDriver, RegNum) + )); + } +} +#endif + +#if LAN91X_PRINT_PACKET_HEADERS +STATIC +VOID +PrintIpDgram ( + IN CONST VOID *DstMac, + IN CONST VOID *SrcMac, + IN CONST VOID *Proto, + IN CONST VOID *IpDgram + ) +{ + CONST UINT8 *Ptr; + UINT16 SrcPort; + UINT16 DstPort; + + Ptr =3D DstMac; + DEBUG ((DEBUG_ERROR, " Dst: %02x-%02x-%02x", + Ptr[0], Ptr[1], Ptr[2])); + DEBUG ((DEBUG_ERROR, "-%02x-%02x-%02x", + Ptr[3], Ptr[4], Ptr[5])); + + Ptr =3D SrcMac; + DEBUG ((DEBUG_ERROR, " Src: %02x-%02x-%02x", + Ptr[0], Ptr[1], Ptr[2])); + DEBUG ((DEBUG_ERROR, "-%02x-%02x-%02x", + Ptr[3], Ptr[4], Ptr[5])); + + Ptr =3D Proto; + DEBUG ((DEBUG_ERROR, " Proto: %02x%02x\n", + Ptr[0], Ptr[1])); + + Ptr =3D IpDgram; + switch (Ptr[9]) { + case EFI_IP_PROTO_ICMP: + DEBUG ((DEBUG_ERROR, " ICMP")); + break; + case EFI_IP_PROTO_TCP: + DEBUG ((DEBUG_ERROR, " TCP")); + break; + case EFI_IP_PROTO_UDP: + DEBUG ((DEBUG_ERROR, " UDP")); + break; + default: + DEBUG ((DEBUG_ERROR, " IpProto %d\n", Ptr[9])); + return; + } + + DEBUG ((DEBUG_ERROR, " SrcIp: %d.%d.%d.%d", + Ptr[12], Ptr[13], Ptr[14], Ptr[15])); + DEBUG ((DEBUG_ERROR, " DstIp: %d.%d.%d.%d", + Ptr[16], Ptr[17], Ptr[18], Ptr[19])); + + SrcPort =3D (Ptr[20] << 8) | Ptr[21]; + DstPort =3D (Ptr[22] << 8) | Ptr[23]; + DEBUG ((DEBUG_ERROR, " SrcPort: %d DstPort: %d\n", SrcPort, DstPort)); +} +#endif + + +/* ---------------- PHY Management Operations ----------------- */ + +STATIC +EFI_STATUS +PhyDetect ( + IN LAN91X_DRIVER *LanDriver + ) +{ + UINT16 PhyId1; + UINT16 PhyId2; + + for (LanDriver->PhyAd =3D 0x1f; LanDriver->PhyAd >=3D 0 ; --LanDriver->P= hyAd) { + PhyId1 =3D ReadPhyReg16 (LanDriver, PHY_INDEX_ID1); + PhyId2 =3D ReadPhyReg16 (LanDriver, PHY_INDEX_ID2); + + if ((PhyId1 !=3D 0x0000) && (PhyId1 !=3D 0xffff) && + (PhyId2 !=3D 0x0000) && (PhyId2 !=3D 0xffff)) { + if ((PhyId1 =3D=3D 0x0016) && ((PhyId2 & 0xfff0) =3D=3D 0xf840)) { + DEBUG ((DEBUG_ERROR, "LAN91x: PHY type LAN83C183 (LAN91C111 Intern= al)\n")); + } else if ((PhyId1 =3D=3D 0x0282) && ((PhyId2 & 0xfff0) =3D=3D 0x1c5= 0)) { + DEBUG ((DEBUG_ERROR, "LAN91x: PHY type LAN83C180\n")); + } else { + DEBUG ((DEBUG_ERROR, "LAN91x: PHY id %04x:%04x\n", PhyId1, PhyId2)= ); + } + return EFI_SUCCESS; + } + } + + DEBUG ((DEBUG_ERROR, "LAN91x: PHY detection failed\n")); + return EFI_NO_MEDIA; +} + + +// Check the Link Status and take appropriate action +STATIC +BOOLEAN +CheckLinkStatus ( + IN LAN91X_DRIVER *LanDriver + ) +{ + UINT16 PhyStatus; + + // Get the PHY Status + PhyStatus =3D ReadPhyReg16 (LanDriver, PHY_INDEX_BASIC_STATUS); + + return (PhyStatus & PHYSTS_LINK_STS) !=3D 0; +} + + +// Do auto-negotiation +STATIC +EFI_STATUS +PhyAutoNegotiate ( + IN LAN91X_DRIVER *LanDriver + ) +{ + UINTN Retries; + UINT16 PhyControl; + UINT16 PhyStatus; + UINT16 PhyAdvert; + + // If there isn't a PHY, don't try to reset it + if (LanDriver->PhyAd =3D=3D LAN91X_NO_PHY) { + return EFI_SUCCESS; + } + + // Next check that auto-negotiation is supported + PhyStatus =3D ReadPhyReg16 (LanDriver, PHY_INDEX_BASIC_STATUS); + if ((PhyStatus & PHYSTS_AUTO_CAP) =3D=3D 0) { + return EFI_SUCCESS; + } + + // Translate capabilities to advertise + PhyAdvert =3D PHYANA_CSMA; + + if ((PhyStatus & PHYSTS_10BASET_HDPLX) !=3D 0) { + PhyAdvert |=3D PHYANA_10BASET; + } + if ((PhyStatus & PHYSTS_10BASET_FDPLX) !=3D 0) { + PhyAdvert |=3D PHYANA_10BASETFD; + } + if ((PhyStatus & PHYSTS_100BASETX_HDPLX) !=3D 0) { + PhyAdvert |=3D PHYANA_100BASETX; + } + if ((PhyStatus & PHYSTS_100BASETX_FDPLX) !=3D 0) { + PhyAdvert |=3D PHYANA_100BASETXFD; + } + if ((PhyStatus & PHYSTS_100BASE_T4) !=3D 0) { + PhyAdvert |=3D PHYANA_100BASET4; + } + + // Set the capabilities to advertise + WritePhyReg16 (LanDriver, PHY_INDEX_AUTO_NEG_ADVERT, PhyAdvert); + (VOID) ReadPhyReg16 (LanDriver, PHY_INDEX_AUTO_NEG_ADVERT); + + // Restart Auto-Negotiation + PhyControl =3D ReadPhyReg16 (LanDriver, PHY_INDEX_BASIC_CTRL); + PhyControl &=3D ~(PHYCR_SPEED_SEL | PHYCR_DUPLEX_MODE); + PhyControl |=3D PHYCR_AUTO_EN | PHYCR_RST_AUTO; + WritePhyReg16 (LanDriver, PHY_INDEX_BASIC_CTRL, PhyControl); + + // Wait up to 2 seconds for the process to complete + Retries =3D 2000000 / (PHY_READ_TIME + 100); + while ((ReadPhyReg16 (LanDriver, PHY_INDEX_BASIC_STATUS) & PHYSTS_AUTO_C= OMP) =3D=3D 0) { + if (--Retries =3D=3D 0) { + DEBUG ((DEBUG_ERROR, "LAN91x: PHY auto-negotiation timed-out\n")); + return EFI_TIMEOUT; + } + gBS->Stall (100); + } + + return EFI_SUCCESS; +} + + +// Perform PHY software reset +STATIC +EFI_STATUS +PhySoftReset ( + IN LAN91X_DRIVER *LanDriver + ) +{ + UINTN Retries; + + // If there isn't a PHY, don't try to reset it + if (LanDriver->PhyAd =3D=3D LAN91X_NO_PHY) { + return EFI_SUCCESS; + } + + // Request a PHY reset + WritePhyReg16 (LanDriver, PHY_INDEX_BASIC_CTRL, PHYCR_RESET); + + // The internal PHY will reset within 50ms. Allow 100ms. + Retries =3D 100000 / (PHY_READ_TIME + 100); + while (ReadPhyReg16 (LanDriver, PHY_INDEX_BASIC_CTRL) & PHYCR_RESET) { + if (--Retries =3D=3D 0) { + DEBUG ((DEBUG_ERROR, "LAN91x: PHY reset timed-out\n")); + return EFI_TIMEOUT; + } + gBS->Stall (100); + } + + return EFI_SUCCESS; +} + + +/* ---------------- General Operations ----------------- */ + +STATIC +EFI_MAC_ADDRESS +GetCurrentMacAddress ( + IN LAN91X_DRIVER *LanDriver + ) +{ + UINTN RegNum; + UINT8 *Addr; + EFI_MAC_ADDRESS MacAddress; + + SetMem (&MacAddress, sizeof(MacAddress), 0); + + Addr =3D &MacAddress.Addr[0]; + for (RegNum =3D LAN91X_IAR0; RegNum <=3D LAN91X_IAR5; ++RegNum) { + *Addr =3D ReadIoReg8 (LanDriver, RegNum); + ++Addr; + } + + return MacAddress; +} + +STATIC +EFI_STATUS +SetCurrentMacAddress ( + IN LAN91X_DRIVER *LanDriver, + IN EFI_MAC_ADDRESS *MacAddress + ) +{ + UINTN RegNum; + UINT8 *Addr; + + Addr =3D &MacAddress->Addr[0]; + for (RegNum =3D LAN91X_IAR0; RegNum <=3D LAN91X_IAR5; ++RegNum) { + WriteIoReg8 (LanDriver, RegNum, *Addr); + ++Addr; + } + + return EFI_SUCCESS; +} + +STATIC +EFI_STATUS +MmuOperation ( + IN LAN91X_DRIVER *LanDriver, + IN UINTN MmuOp + ) +{ + UINTN Polls; + + WriteIoReg16 (LanDriver, LAN91X_MMUCR, MmuOp); + Polls =3D 100; + while ((ReadIoReg16 (LanDriver, LAN91X_MMUCR) & MMUCR_BUSY) !=3D 0) { + if (--Polls =3D=3D 0) { + DEBUG ((DEBUG_ERROR, "LAN91x: MMU operation %04x timed-out\n", MmuOp= )); + return EFI_TIMEOUT; + } + gBS->Stall (LAN91X_STALL); + } + + return EFI_SUCCESS; +} + +// Read bytes from the DATA register +STATIC +EFI_STATUS +ReadIoData ( + IN LAN91X_DRIVER *LanDriver, + IN VOID *Buffer, + IN UINTN BufLen + ) +{ + UINT8 *Ptr; + + Ptr =3D Buffer; + for (; BufLen > 0; --BufLen) { + *Ptr =3D ReadIoReg8 (LanDriver, LAN91X_DATA0); + ++Ptr; + } + + return EFI_SUCCESS; +} + +// Write bytes to the DATA register +STATIC +EFI_STATUS +WriteIoData ( + IN LAN91X_DRIVER *LanDriver, + IN VOID *Buffer, + IN UINTN BufLen + ) +{ + UINT8 *Ptr; + + Ptr =3D Buffer; + for (; BufLen > 0; --BufLen) { + WriteIoReg8 (LanDriver, LAN91X_DATA0, *Ptr); + ++Ptr; + } + + return EFI_SUCCESS; +} + +// Disable the interface +STATIC +EFI_STATUS +ChipDisable ( + IN LAN91X_DRIVER *LanDriver + ) +{ +#ifdef LAN91X_POWER_DOWN + UINT16 Val16; +#endif + + // Stop Rx and Tx operations + WriteIoReg16 (LanDriver, LAN91X_RCR, RCR_CLEAR); + WriteIoReg16 (LanDriver, LAN91X_TCR, TCR_CLEAR); + +#ifdef LAN91X_POWER_DOWN + // Power-down the chip + Val16 =3D ReadIoReg16 (LanDriver, LAN91X_CR); + Val16 &=3D ~CR_EPH_POWER_EN; + WriteIoReg16 (LanDriver, LAN91X_CR, Val16); +#endif + + return EFI_SUCCESS; +} + +// Enable the interface +STATIC +EFI_STATUS +ChipEnable ( + IN LAN91X_DRIVER *LanDriver + ) +{ +#ifdef LAN91X_POWER_DOWN + UINT16 Val16; + + // Power-up the chip + Val16 =3D ReadIoReg16 (LanDriver, LAN91X_CR); + Val16 |=3D CR_EPH_POWER_EN; + WriteIoReg16 (LanDriver, LAN91X_CR, Val16); + gBS->Stall (LAN91X_STALL); +#endif + + // Start Rx and Tx operations + WriteIoReg16 (LanDriver, LAN91X_TCR, TCR_DEFAULT); + WriteIoReg16 (LanDriver, LAN91X_RCR, RCR_DEFAULT); + + return EFI_SUCCESS; +} + + +// Perform software reset on the LAN91x +STATIC +EFI_STATUS +SoftReset ( + IN LAN91X_DRIVER *LanDriver + ) +{ + UINT16 Val16; + + // Issue the reset + WriteIoReg16 (LanDriver, LAN91X_RCR, RCR_SOFT_RST); + gBS->Stall (LAN91X_STALL); + WriteIoReg16 (LanDriver, LAN91X_RCR, RCR_CLEAR); + + // Set the configuration register + WriteIoReg16 (LanDriver, LAN91X_CR, CR_DEFAULT); + gBS->Stall (LAN91X_STALL); + + // Stop Rx and Tx + WriteIoReg16 (LanDriver, LAN91X_RCR, RCR_CLEAR); + WriteIoReg16 (LanDriver, LAN91X_TCR, TCR_CLEAR); + + // Initialize the Control Register + Val16 =3D ReadIoReg16 (LanDriver, LAN91X_CTR); + Val16 |=3D CTR_AUTO_REL; + WriteIoReg16 (LanDriver, LAN91X_CTR, Val16); + + // Reset the MMU + MmuOperation (LanDriver, MMUCR_OP_RESET_MMU); + + return EFI_SUCCESS; +} + +/* +** Probe() +** +** Validate that there is a LAN91x device. +** +*/ +STATIC +EFI_STATUS +Probe ( + IN LAN91X_DRIVER *LanDriver + ) +{ + UINT16 Bank; + UINT16 Val16; + CHAR16 CONST *ChipId; + UINTN ResetTime; + + // First check that the Bank Select register is valid + Bank =3D MmioRead16 (LanDriver->IoBase + LAN91X_BANK_OFFSET); + if ((Bank & 0xff00) !=3D 0x3300) { + DEBUG ((DEBUG_ERROR, "LAN91x: signature error: expecting 33xx, read %0= 4x\n", Bank)); + return EFI_DEVICE_ERROR; + } + + // Try reading the revision register next + LanDriver->BankSel =3D 0xff; + Val16 =3D ReadIoReg16 (LanDriver, LAN91X_REV); + + Bank =3D MmioRead16 (LanDriver->IoBase + LAN91X_BANK_OFFSET); + if ((Bank & 0xff03) !=3D 0x3303) { + DEBUG ((DEBUG_ERROR, "LAN91x: signature error: expecting 33x3, read %0= 4x\n", Bank)); + return EFI_DEVICE_ERROR; + } + + // Validate the revision register + if ((Val16 & 0xff00) !=3D 0x3300) { + DEBUG ((DEBUG_ERROR, "LAN91x: revision error: expecting 33xx, read %04= x\n", Val16)); + return EFI_DEVICE_ERROR; + } + + ChipId =3D ChipIds[(Val16 >> 4) & 0x0f]; + if (ChipId =3D=3D NULL) { + DEBUG ((DEBUG_ERROR, "LAN91x: unrecognized revision: %04x\n", Val16)); + return EFI_DEVICE_ERROR; + } + DEBUG ((DEBUG_ERROR, "LAN91x: detected chip %s rev %d\n", ChipId, Val16 = & 0xf)); + LanDriver->Revision =3D Val16 & 0xff; + + // Reload from EEPROM to get the hardware MAC address + WriteIoReg16 (LanDriver, LAN91X_CTR, CTR_RESERVED | CTR_RELOAD); + ResetTime =3D 1000; + while ((ReadIoReg16 (LanDriver, LAN91X_CTR) & CTR_RELOAD) !=3D 0) { + if (--ResetTime =3D=3D 0) { + DEBUG ((DEBUG_ERROR, "LAN91x: reload from EEPROM timed-out\n")); + WriteIoReg16 (LanDriver, LAN91X_CTR, CTR_RESERVED); + return EFI_DEVICE_ERROR; + } + gBS->Stall (LAN91X_STALL); + } + + // Read and save the Permanent MAC Address + LanDriver->SnpMode.PermanentAddress =3D GetCurrentMacAddress (LanDriver); + LanDriver->SnpMode.CurrentAddress =3D LanDriver->SnpMode.PermanentAddres= s; + DEBUG ((DEBUG_ERROR, //DEBUG_NET | DEBUG_INFO, + "LAN91x: HW MAC Address: %02x-%02x-%02x-%02x-%02x-%02x\n", + LanDriver->SnpMode.PermanentAddress.Addr[0], + LanDriver->SnpMode.PermanentAddress.Addr[1], + LanDriver->SnpMode.PermanentAddress.Addr[2], + LanDriver->SnpMode.PermanentAddress.Addr[3], + LanDriver->SnpMode.PermanentAddress.Addr[4], + LanDriver->SnpMode.PermanentAddress.Addr[5] + )); + + // Reset the device + SoftReset (LanDriver); + + // Try to detect a PHY + if (LanDriver->Revision > (CHIP_91100 << 4)) { + PhyDetect (LanDriver); + } else { + LanDriver->PhyAd =3D LAN91X_NO_PHY; + } + + return EFI_SUCCESS; +} + + + + +/*------------------ Simple Network Driver entry point functions ---------= ---------*/ + +// Refer to the Simple Network Protocol section (21.1) +// in the UEFI 2.3.1 Specification for documentation. + +#define ReturnUnlock(s) do { Status =3D (s); goto exit_unlock; } while(0) + + +/* +** UEFI Start() function +** +*/ +EFI_STATUS +EFIAPI +SnpStart ( + IN EFI_SIMPLE_NETWORK_PROTOCOL* Snp + ) +{ + EFI_SIMPLE_NETWORK_MODE *Mode; + EFI_TPL SavedTpl; + EFI_STATUS Status; + + // Check Snp instance + if (Snp =3D=3D NULL) { + return EFI_INVALID_PARAMETER; + } + + // Serialize access to data and registers + SavedTpl =3D gBS->RaiseTPL (LAN91X_TPL); + Mode =3D Snp->Mode; + + // Check state of the driver + switch (Mode->State) { + case EfiSimpleNetworkStopped: + break; + case EfiSimpleNetworkStarted: + case EfiSimpleNetworkInitialized: + DEBUG ((DEBUG_WARN, "LAN91x: Driver already started\n")); + ReturnUnlock (EFI_ALREADY_STARTED); + default: + DEBUG ((DEBUG_ERROR, "LAN91x: Driver in an invalid state: %u\n", + (UINTN)Snp->Mode->State)); + ReturnUnlock (EFI_DEVICE_ERROR); + } + + + // Change state + Mode->State =3D EfiSimpleNetworkStarted; + Status =3D EFI_SUCCESS; + + // Restore TPL and return +exit_unlock: + gBS->RestoreTPL (SavedTpl); + return Status; +} + +/* +** UEFI Stop() function +** +*/ +EFI_STATUS +EFIAPI +SnpStop ( + IN EFI_SIMPLE_NETWORK_PROTOCOL* Snp + ) +{ + LAN91X_DRIVER *LanDriver; + EFI_TPL SavedTpl; + EFI_STATUS Status; + + // Check Snp Instance + if (Snp =3D=3D NULL) { + return EFI_INVALID_PARAMETER; + } + + // Serialize access to data and registers + SavedTpl =3D gBS->RaiseTPL (LAN91X_TPL); + + // Check state of the driver + switch (Snp->Mode->State) { + case EfiSimpleNetworkStarted: + case EfiSimpleNetworkInitialized: + break; + case EfiSimpleNetworkStopped: + DEBUG ((DEBUG_WARN, "LAN91x: Driver not started\n")); + ReturnUnlock (EFI_NOT_STARTED); + default: + DEBUG ((DEBUG_ERROR, "LAN91x: Driver in an invalid state: %u\n", + (UINTN)Snp->Mode->State)); + ReturnUnlock (EFI_DEVICE_ERROR); + } + + // Find the LanDriver structure + LanDriver =3D INSTANCE_FROM_SNP_THIS(Snp); + + // Stop the Tx and Rx + ChipDisable (LanDriver); + + // Change the state + Snp->Mode->State =3D EfiSimpleNetworkStopped; + Status =3D EFI_SUCCESS; + + // Restore TPL and return +exit_unlock: + gBS->RestoreTPL (SavedTpl); + return Status; +} + +/* +** UEFI Initialize() function +** +*/ +EFI_STATUS +EFIAPI +SnpInitialize ( + IN EFI_SIMPLE_NETWORK_PROTOCOL* Snp, + IN UINTN RxBufferSize OPTIONAL, + IN UINTN TxBufferSize OPTIONAL + ) +{ + LAN91X_DRIVER *LanDriver; + EFI_TPL SavedTpl; + EFI_STATUS Status; + + // Check Snp Instance + if (Snp =3D=3D NULL) { + return EFI_INVALID_PARAMETER; + } + + // Serialize access to data and registers + SavedTpl =3D gBS->RaiseTPL (LAN91X_TPL); + + // Check that driver was started but not initialised + switch (Snp->Mode->State) { + case EfiSimpleNetworkStarted: + break; + case EfiSimpleNetworkInitialized: + DEBUG ((DEBUG_WARN, "LAN91x: Driver already initialized\n")); + ReturnUnlock (EFI_SUCCESS); + case EfiSimpleNetworkStopped: + DEBUG ((DEBUG_WARN, "LAN91x: Driver not started\n")); + ReturnUnlock (EFI_NOT_STARTED); + default: + DEBUG ((DEBUG_ERROR, "LAN91x: Driver in an invalid state: %u\n", + (UINTN)Snp->Mode->State)); + ReturnUnlock (EFI_DEVICE_ERROR); + } + + // Find the LanDriver structure + LanDriver =3D INSTANCE_FROM_SNP_THIS(Snp); + + // Initiate a software reset + Status =3D SoftReset (LanDriver); + if (EFI_ERROR(Status)) { + DEBUG ((DEBUG_WARN, "LAN91x: Soft reset failed\n")); + ReturnUnlock (EFI_DEVICE_ERROR); + } + + // Initiate a PHY reset + if (PhySoftReset (LanDriver) < 0) { + Snp->Mode->State =3D EfiSimpleNetworkStopped; + DEBUG ((DEBUG_WARN, "LAN91x: PHY soft reset timeout\n")); + ReturnUnlock (EFI_NOT_STARTED); + } + + // Do auto-negotiation + Status =3D PhyAutoNegotiate (LanDriver); + if (EFI_ERROR(Status)) { + DEBUG ((DEBUG_WARN, "LAN91x: PHY auto-negotiation failed\n")); + } + + // Enable the receiver and transmitter + ChipEnable (LanDriver); + + // Now acknowledge all interrupts + WriteIoReg8 (LanDriver, LAN91X_IST, 0xFF); + + // Declare the driver as initialized + Snp->Mode->State =3D EfiSimpleNetworkInitialized; + Status =3D EFI_SUCCESS; + + // Restore TPL and return +exit_unlock: + gBS->RestoreTPL (SavedTpl); + return Status; +} + +/* +** UEFI Reset () function +** +*/ +EFI_STATUS +EFIAPI +SnpReset ( + IN EFI_SIMPLE_NETWORK_PROTOCOL* Snp, + IN BOOLEAN Verification + ) +{ + LAN91X_DRIVER *LanDriver; + EFI_TPL SavedTpl; + EFI_STATUS Status; + + // Check Snp Instance + if (Snp =3D=3D NULL) { + return EFI_INVALID_PARAMETER; + } + + // Serialize access to data and registers + SavedTpl =3D gBS->RaiseTPL (LAN91X_TPL); + + // Check that driver was started and initialised + switch (Snp->Mode->State) { + case EfiSimpleNetworkInitialized: + break; + case EfiSimpleNetworkStarted: + DEBUG ((DEBUG_WARN, "LAN91x: Driver not yet initialized\n")); + ReturnUnlock (EFI_DEVICE_ERROR); + case EfiSimpleNetworkStopped: + DEBUG ((DEBUG_WARN, "LAN91x: Driver not started\n")); + ReturnUnlock (EFI_NOT_STARTED); + default: + DEBUG ((DEBUG_ERROR, "LAN91x: Driver in an invalid state: %u\n", + (UINTN)Snp->Mode->State)); + ReturnUnlock (EFI_DEVICE_ERROR); + } + + // Find the LanDriver structure + LanDriver =3D INSTANCE_FROM_SNP_THIS(Snp); + + // Initiate a software reset + if (EFI_ERROR (SoftReset (LanDriver))) { + DEBUG ((DEBUG_WARN, "LAN91x: Soft reset failed\n")); + ReturnUnlock (EFI_DEVICE_ERROR); + } + + // Initiate a PHY reset + if (EFI_ERROR (PhySoftReset (LanDriver))) { + DEBUG ((DEBUG_WARN, "LAN91x: PHY soft reset failed\n")); + ReturnUnlock (EFI_DEVICE_ERROR); + } + + // Enable the receiver and transmitter + Status =3D ChipEnable (LanDriver); + + // Restore TPL and return +exit_unlock: + gBS->RestoreTPL (SavedTpl); + return Status; +} + +/* +** UEFI Shutdown () function +** +*/ +EFI_STATUS +EFIAPI +SnpShutdown ( + IN EFI_SIMPLE_NETWORK_PROTOCOL* Snp + ) +{ + LAN91X_DRIVER *LanDriver; + EFI_TPL SavedTpl; + EFI_STATUS Status; + + // Check Snp Instance + if (Snp =3D=3D NULL) { + return EFI_INVALID_PARAMETER; + } + + // Serialize access to data and registers + SavedTpl =3D gBS->RaiseTPL (LAN91X_TPL); + + // First check that driver has already been initialized + switch (Snp->Mode->State) { + case EfiSimpleNetworkInitialized: + break; + case EfiSimpleNetworkStarted: + DEBUG ((DEBUG_WARN, "LAN91x: Driver not yet initialized\n")); + ReturnUnlock (EFI_DEVICE_ERROR); + case EfiSimpleNetworkStopped: + DEBUG ((DEBUG_WARN, "LAN91x: Driver in stopped state\n")); + ReturnUnlock (EFI_NOT_STARTED); + default: + DEBUG ((DEBUG_ERROR, "LAN91x: Driver in an invalid state: %u\n", + (UINTN)Snp->Mode->State)); + ReturnUnlock (EFI_DEVICE_ERROR); + } + + // Find the LanDriver structure + LanDriver =3D INSTANCE_FROM_SNP_THIS(Snp); + + // Disable the interface + Status =3D ChipDisable (LanDriver); + + // Restore TPL and return +exit_unlock: + gBS->RestoreTPL (SavedTpl); + return Status; +} + + +/* +** UEFI ReceiveFilters() function +** +*/ +EFI_STATUS +EFIAPI +SnpReceiveFilters ( + IN EFI_SIMPLE_NETWORK_PROTOCOL* Snp, + IN UINT32 Enable, + IN UINT32 Disable, + IN BOOLEAN Reset, + IN UINTN NumMfilter OPTIONAL, + IN EFI_MAC_ADDRESS *Mfilter OPTIONAL + ) +{ +#define MCAST_HASH_BYTES 8 + + LAN91X_DRIVER *LanDriver; + EFI_SIMPLE_NETWORK_MODE *SnpMode; + EFI_TPL SavedTpl; + EFI_STATUS Status; + UINTN i; + UINT32 Crc; + UINT16 RcvCtrl; + UINT8 McastHash[MCAST_HASH_BYTES]; + + // Check Snp Instance + if (Snp =3D=3D NULL) { + return EFI_INVALID_PARAMETER; + } + + // Serialize access to data and registers + SavedTpl =3D gBS->RaiseTPL (LAN91X_TPL); + + // First check that driver has already been initialized + switch (Snp->Mode->State) { + case EfiSimpleNetworkInitialized: + break; + case EfiSimpleNetworkStarted: + DEBUG ((DEBUG_WARN, "LAN91x: Driver not yet initialized\n")); + ReturnUnlock (EFI_DEVICE_ERROR); + case EfiSimpleNetworkStopped: + DEBUG ((DEBUG_WARN, "LAN91x: Driver not started\n")); + ReturnUnlock (EFI_NOT_STARTED); + default: + DEBUG ((DEBUG_ERROR, "LAN91x: Driver in an invalid state: %u\n", + (UINTN)Snp->Mode->State)); + ReturnUnlock (EFI_DEVICE_ERROR); + } + + // Find the LanDriver structure + LanDriver =3D INSTANCE_FROM_SNP_THIS(Snp); + SnpMode =3D Snp->Mode; + +#ifdef LAN91X_PRINT_RECEIVE_FILTERS + DEBUG ((DEBUG_ERROR, "LAN91x:SnpReceiveFilters()\n")); + DEBUG ((DEBUG_ERROR, " Enable =3D %08x\n", Enable)); + DEBUG ((DEBUG_ERROR, " Disable =3D %08x\n", Disable)); + DEBUG ((DEBUG_ERROR, " Reset =3D %d\n", Reset)); + DEBUG ((DEBUG_ERROR, " NumMfilter =3D %d\n", NumMfilter)); + for (i =3D 0; i < NumMfilter; ++i) { + DEBUG ((DEBUG_ERROR, + " [%2d] =3D %02x-%02x-%02x-%02x-%02x-%02x\n", + i, + Mfilter[i].Addr[0], + Mfilter[i].Addr[1], + Mfilter[i].Addr[2], + Mfilter[i].Addr[3], + Mfilter[i].Addr[4], + Mfilter[i].Addr[5])); + } +#endif + + // Update the Multicast Hash registers + if (Reset) { + // Clear the hash table + SetMem (McastHash, MCAST_HASH_BYTES, 0); + SnpMode->MCastFilterCount =3D 0; + } else { + // Read the current hash table + for (i =3D 0; i < MCAST_HASH_BYTES; ++i) { + McastHash[i] =3D ReadIoReg8 (LanDriver, LAN91X_MT0 + i); + } + // Set the new additions + for (i =3D 0; i < NumMfilter; ++i) { + Crc =3D MulticastHash (&Mfilter[i], NET_ETHER_ADDR_LEN); + McastHash[(Crc >> 29) & 0x3] |=3D 1 << ((Crc >> 26) & 0x3); + } + SnpMode->MCastFilterCount =3D NumMfilter; + } + // If the hash registers need updating, write them + if (Reset || NumMfilter > 0) { + for (i =3D 0; i < MCAST_HASH_BYTES; ++i) { + WriteIoReg8 (LanDriver, LAN91X_MT0 + i, McastHash[i]); + } + } + + RcvCtrl =3D ReadIoReg16 (LanDriver, LAN91X_RCR); + if ((Enable & EFI_SIMPLE_NETWORK_RECEIVE_PROMISCUOUS) !=3D 0) { + RcvCtrl |=3D RCR_PRMS; + SnpMode->ReceiveFilterSetting |=3D EFI_SIMPLE_NETWORK_RECEIVE_PROMISCU= OUS; + } + if ((Disable & EFI_SIMPLE_NETWORK_RECEIVE_PROMISCUOUS) !=3D 0) { + RcvCtrl &=3D ~RCR_PRMS; + SnpMode->ReceiveFilterSetting &=3D ~EFI_SIMPLE_NETWORK_RECEIVE_PROMISC= UOUS; + } + + if ((Enable & EFI_SIMPLE_NETWORK_RECEIVE_PROMISCUOUS_MULTICAST) !=3D 0) { + RcvCtrl |=3D RCR_ALMUL; + SnpMode->ReceiveFilterSetting |=3D EFI_SIMPLE_NETWORK_RECEIVE_PROMISCU= OUS_MULTICAST; + } + if ((Disable & EFI_SIMPLE_NETWORK_RECEIVE_PROMISCUOUS_MULTICAST) !=3D 0)= { + RcvCtrl &=3D ~RCR_ALMUL; + SnpMode->ReceiveFilterSetting &=3D ~EFI_SIMPLE_NETWORK_RECEIVE_PROMISC= UOUS_MULTICAST; + } + WriteIoReg16 (LanDriver, LAN91X_RCR, RcvCtrl); + + Status =3D SetCurrentMacAddress (LanDriver, &SnpMode->CurrentAddress); + + // Restore TPL and return +exit_unlock: + gBS->RestoreTPL (SavedTpl); + return Status; +} + +/* +** UEFI StationAddress() function +** +*/ +EFI_STATUS +EFIAPI +SnpStationAddress ( + IN EFI_SIMPLE_NETWORK_PROTOCOL *Snp, + IN BOOLEAN Reset, + IN EFI_MAC_ADDRESS *NewMac +) +{ + LAN91X_DRIVER *LanDriver; + EFI_TPL SavedTpl; + EFI_STATUS Status; + + // Check Snp instance + if (Snp =3D=3D NULL) { + return EFI_INVALID_PARAMETER; + } + + // Serialize access to data and registers + SavedTpl =3D gBS->RaiseTPL (LAN91X_TPL); + + // Check that driver was started and initialised + switch (Snp->Mode->State) { + case EfiSimpleNetworkInitialized: + break; + case EfiSimpleNetworkStarted: + DEBUG ((DEBUG_WARN, "LAN91x: Driver not yet initialized\n")); + ReturnUnlock (EFI_DEVICE_ERROR); + case EfiSimpleNetworkStopped: + DEBUG ((DEBUG_WARN, "LAN91x: Driver not started\n")); + ReturnUnlock (EFI_NOT_STARTED); + default: + DEBUG ((DEBUG_ERROR, "LAN91x: Driver in an invalid state: %u\n", + (UINTN)Snp->Mode->State)); + ReturnUnlock (EFI_DEVICE_ERROR); + } + + // Find the LanDriver structure + LanDriver =3D INSTANCE_FROM_SNP_THIS(Snp); + + if (Reset) { + Snp->Mode->CurrentAddress =3D Snp->Mode->PermanentAddress; + } else { + if (NewMac =3D=3D NULL) { + ReturnUnlock (EFI_INVALID_PARAMETER); + } + Snp->Mode->CurrentAddress =3D *NewMac; + } + + Status =3D SetCurrentMacAddress (LanDriver, &Snp->Mode->CurrentAddress); + + // Restore TPL and return +exit_unlock: + gBS->RestoreTPL (SavedTpl); + return Status; +} + +/* +** UEFI Statistics() function +** +*/ +EFI_STATUS +EFIAPI +SnpStatistics ( + IN EFI_SIMPLE_NETWORK_PROTOCOL* Snp, + IN BOOLEAN Reset, + IN OUT UINTN *StatSize, + OUT EFI_NETWORK_STATISTICS *Statistics + ) +{ + LAN91X_DRIVER *LanDriver; + EFI_TPL SavedTpl; + EFI_STATUS Status; + + // Check Snp instance + if (Snp =3D=3D NULL) { + return EFI_INVALID_PARAMETER; + } + + // Check pointless condition + if ((!Reset) && (StatSize =3D=3D NULL) && (Statistics =3D=3D NULL)) { + return EFI_SUCCESS; + } + + // Check the parameters + if ((StatSize =3D=3D NULL) && (Statistics !=3D NULL)) { + return EFI_INVALID_PARAMETER; + } + + // Serialize access to data and registers + SavedTpl =3D gBS->RaiseTPL (LAN91X_TPL); + + // Check that driver was started and initialised + switch (Snp->Mode->State) { + case EfiSimpleNetworkInitialized: + break; + case EfiSimpleNetworkStarted: + DEBUG ((DEBUG_WARN, "LAN91x: Driver not yet initialized\n")); + ReturnUnlock (EFI_DEVICE_ERROR); + case EfiSimpleNetworkStopped: + DEBUG ((DEBUG_WARN, "LAN91x: Driver not started\n")); + ReturnUnlock (EFI_NOT_STARTED); + default: + DEBUG ((DEBUG_ERROR, "LAN91x: Driver in an invalid state: %u\n", + (UINTN)Snp->Mode->State)); + ReturnUnlock (EFI_DEVICE_ERROR); + } + + // Find the LanDriver structure + LanDriver =3D INSTANCE_FROM_SNP_THIS(Snp); + + // Do a reset if required + if (Reset) { + ZeroMem (&LanDriver->Stats, sizeof(EFI_NETWORK_STATISTICS)); + } + + // Check buffer size + if (*StatSize < sizeof(EFI_NETWORK_STATISTICS)) { + *StatSize =3D sizeof(EFI_NETWORK_STATISTICS); + ReturnUnlock (EFI_BUFFER_TOO_SMALL); + goto exit_unlock; + } + + // Fill in the statistics + CopyMem(&Statistics, &LanDriver->Stats, sizeof(EFI_NETWORK_STATISTICS)); + Status =3D EFI_SUCCESS; + + // Restore TPL and return +exit_unlock: + gBS->RestoreTPL (SavedTpl); + return Status; +} + +/* +** UEFI MCastIPtoMAC() function +** +*/ +EFI_STATUS +EFIAPI +SnpMcastIptoMac ( + IN EFI_SIMPLE_NETWORK_PROTOCOL* Snp, + IN BOOLEAN IsIpv6, + IN EFI_IP_ADDRESS *Ip, + OUT EFI_MAC_ADDRESS *McastMac + ) +{ + // Check Snp instance + if (Snp =3D=3D NULL) { + return EFI_INVALID_PARAMETER; + } + + // Check parameters + if ((McastMac =3D=3D NULL) || (Ip =3D=3D NULL)) { + return EFI_INVALID_PARAMETER; + } + + // Make sure MAC address is empty + ZeroMem (McastMac, sizeof(EFI_MAC_ADDRESS)); + + // If we need ipv4 address + if (!IsIpv6) { + // Most significant 25 bits of a multicast HW address are set + McastMac->Addr[0] =3D 0x01; + McastMac->Addr[1] =3D 0x00; + McastMac->Addr[2] =3D 0x5E; + + // Lower 23 bits from ipv4 address + McastMac->Addr[3] =3D (Ip->v4.Addr[1] & 0x7F); // Clear the ms bit (25= th bit of MAC must be 0) + McastMac->Addr[4] =3D Ip->v4.Addr[2]; + McastMac->Addr[5] =3D Ip->v4.Addr[3]; + } else { + // Most significant 16 bits of multicast v6 HW address are set + McastMac->Addr[0] =3D 0x33; + McastMac->Addr[1] =3D 0x33; + + // lower four octets are taken from ipv6 address + McastMac->Addr[2] =3D Ip->v6.Addr[8]; + McastMac->Addr[3] =3D Ip->v6.Addr[9]; + McastMac->Addr[4] =3D Ip->v6.Addr[10]; + McastMac->Addr[5] =3D Ip->v6.Addr[11]; + } + + return EFI_SUCCESS; +} + +/* +** UEFI NvData() function +** +*/ +EFI_STATUS +EFIAPI +SnpNvData ( + IN EFI_SIMPLE_NETWORK_PROTOCOL* pobj, + IN BOOLEAN read_write, + IN UINTN offset, + IN UINTN buff_size, + IN OUT VOID *data + ) +{ + DEBUG ((DEBUG_ERROR, "LAN91x: Non-volatile storage not supported\n")); + + return EFI_UNSUPPORTED; +} + + +/* +** UEFI GetStatus () function +** +*/ +EFI_STATUS +EFIAPI +SnpGetStatus ( + IN EFI_SIMPLE_NETWORK_PROTOCOL *Snp, + OUT UINT32 *IrqStat OPTIONAL, + OUT VOID **TxBuff OPTIONAL + ) +{ + LAN91X_DRIVER *LanDriver; + EFI_TPL SavedTpl; + EFI_STATUS Status; + BOOLEAN MediaPresent; + UINT8 IstReg; + MSK_LINKED_SYSTEM_BUF *LinkedTXRecycleBuff; + + // Check preliminaries + if (Snp =3D=3D NULL) { + return EFI_INVALID_PARAMETER; + } + + // Serialize access to data and registers + SavedTpl =3D gBS->RaiseTPL (LAN91X_TPL); + + // Check that driver was started and initialised + switch (Snp->Mode->State) { + case EfiSimpleNetworkInitialized: + break; + case EfiSimpleNetworkStarted: + DEBUG ((DEBUG_WARN, "LAN91x: Driver not yet initialized\n")); + ReturnUnlock (EFI_DEVICE_ERROR); + case EfiSimpleNetworkStopped: + DEBUG ((DEBUG_WARN, "LAN91x: Driver not started\n")); + ReturnUnlock (EFI_NOT_STARTED); + default: + DEBUG ((DEBUG_ERROR, "LAN91x: Driver in an invalid state: %u\n", + (UINTN)Snp->Mode->State)); + ReturnUnlock (EFI_DEVICE_ERROR); + } + + // Find the LanDriver structure + LanDriver =3D INSTANCE_FROM_SNP_THIS(Snp); + + // Arbitrarily set the interrupt status to 0 + if (IrqStat !=3D NULL) { + *IrqStat =3D 0; + IstReg =3D ReadIoReg8 (LanDriver, LAN91X_IST); + if ((IstReg & IST_RCV) !=3D 0) { + *IrqStat |=3D EFI_SIMPLE_NETWORK_RECEIVE_INTERRUPT; + } + if ((IstReg & IST_TX) !=3D 0) { + *IrqStat |=3D EFI_SIMPLE_NETWORK_TRANSMIT_INTERRUPT; + } + } + + // Pass back the completed buffer address + // The transmit buffer status is not read when TxBuf is NULL + if (TxBuff !=3D NULL) { + *((UINT8 **) TxBuff) =3D (UINT8 *) 0; + if( !IsListEmpty (&LanDriver->TransmitQueueHead)) + { + LinkedTXRecycleBuff =3D CR (GetFirstNode (&LanDriver->TransmitQueueH= ead), MSK_LINKED_SYSTEM_BUF, Link, TX_MBUF_SIGNATURE); + if(LinkedTXRecycleBuff !=3D NULL) { + *TxBuff =3D LinkedTXRecycleBuff->SystemBuf.Buf; + RemoveEntryList (&LinkedTXRecycleBuff->Link); + FreePool (LinkedTXRecycleBuff); + } + } + } + + // Update the media status + MediaPresent =3D CheckLinkStatus (LanDriver); + if (MediaPresent !=3D Snp->Mode->MediaPresent) { + DEBUG ((DEBUG_WARN, "LAN91x: Link %s\n", MediaPresent ? L"up" : L"down= ")); + } + Snp->Mode->MediaPresent =3D MediaPresent; + Status =3D EFI_SUCCESS; + + // Restore TPL and return +exit_unlock: + gBS->RestoreTPL (SavedTpl); + return Status; +} + + +/* +** UEFI Transmit() function +** +*/ +EFI_STATUS +EFIAPI +SnpTransmit ( + IN EFI_SIMPLE_NETWORK_PROTOCOL *Snp, + IN UINTN HdrSize, + IN UINTN BufSize, + IN VOID *BufAddr, + IN EFI_MAC_ADDRESS *SrcAddr OPTIONAL, + IN EFI_MAC_ADDRESS *DstAddr OPTIONAL, + IN UINT16 *Protocol OPTIONAL + ) +{ + LAN91X_DRIVER *LanDriver; + EFI_TPL SavedTpl; + EFI_STATUS Status; + UINT8 *Ptr; + UINTN Len; + UINTN MmuPages; + UINTN Retries; + UINT16 Proto; + UINT8 PktNum; + MSK_LINKED_SYSTEM_BUF *LinkedTXRecycleBuff; + + + // Check preliminaries + if ((Snp =3D=3D NULL) || (BufAddr =3D=3D NULL)) { + DEBUG ((DEBUG_ERROR, "LAN91x: SnpTransmit(): NULL Snp (%p) or BufAddr = (%p)\n", + Snp, BufAddr)); + return EFI_INVALID_PARAMETER; + } + + // Serialize access to data and registers + SavedTpl =3D gBS->RaiseTPL (LAN91X_TPL); + + // Check that driver was started and initialised + switch (Snp->Mode->State) { + case EfiSimpleNetworkInitialized: + break; + case EfiSimpleNetworkStarted: + DEBUG ((DEBUG_WARN, "LAN91x: Driver not yet initialized\n")); + ReturnUnlock (EFI_DEVICE_ERROR); + case EfiSimpleNetworkStopped: + DEBUG ((DEBUG_WARN, "LAN91x: Driver not started\n")); + ReturnUnlock (EFI_NOT_STARTED); + default: + DEBUG ((DEBUG_ERROR, "LAN91x: Driver in an invalid state: %u\n", + (UINTN)Snp->Mode->State)); + ReturnUnlock (EFI_DEVICE_ERROR); + } + + // Find the LanDriver structure + LanDriver =3D INSTANCE_FROM_SNP_THIS(Snp); + + // Ensure header is correct size if non-zero + if (HdrSize !=3D 0) { + if (HdrSize !=3D Snp->Mode->MediaHeaderSize) { + DEBUG ((DEBUG_ERROR, "LAN91x: SnpTransmit(): Invalid HdrSize %d\n", = HdrSize)); + ReturnUnlock (EFI_INVALID_PARAMETER); + } + + if ((DstAddr =3D=3D NULL) || (Protocol =3D=3D NULL)) { + DEBUG ((DEBUG_ERROR, "LAN91x: SnpTransmit(): NULL DstAddr %p or Prot= ocol %p\n", + DstAddr, Protocol)); + ReturnUnlock (EFI_INVALID_PARAMETER); + } + } + + // Before transmitting check the link status + if (!Snp->Mode->MediaPresent) { + DEBUG ((DEBUG_WARN, "LAN91x: SnpTransmit(): Link not ready\n")); + ReturnUnlock (EFI_NOT_READY); + } + + // Calculate the request size in 256-byte "pages" minus 1 + // The 91C111 ignores this, but some older devices need it. + MmuPages =3D ((BufSize & ~1) + LAN91X_PKT_OVERHEAD - 1) >> 8; + if (MmuPages > 7) { + DEBUG ((DEBUG_WARN, "LAN91x: Tx buffer too large (%d bytes)\n", BufSiz= e)); + LanDriver->Stats.TxOversizeFrames +=3D 1; + LanDriver->Stats.TxDroppedFrames +=3D 1; + ReturnUnlock (EFI_BAD_BUFFER_SIZE); + } + + // Request allocation of a transmit buffer + Status =3D MmuOperation (LanDriver, MMUCR_OP_TX_ALLOC | MmuPages); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "LAN91x: Tx buffer request failure: %d\n", Status= )); + ReturnUnlock (EFI_DEVICE_ERROR); + } + + // Wait for allocation request completion + Retries =3D LAN91X_MEMORY_ALLOC_POLLS; + while ((ReadIoReg8 (LanDriver, LAN91X_IST) & IST_ALLOC) =3D=3D 0) { + if (--Retries =3D=3D 0) { + DEBUG ((DEBUG_ERROR, "LAN91x: Tx buffer allocation timeout\n")); + ReturnUnlock (EFI_TIMEOUT); + } + } + + // Check for successful allocation + PktNum =3D ReadIoReg8 (LanDriver, LAN91X_ARR); + if ((PktNum & ARR_FAILED) !=3D 0) { + DEBUG ((DEBUG_ERROR, "LAN91x: Tx buffer allocation failure: %02x\n", P= ktNum)); + ReturnUnlock (EFI_NOT_READY); + } + PktNum &=3D ARR_PACKET; + + // Check for the nature of the frame + // If no destination address, it's ARP broadcast + if(DstAddr !=3D NULL) + { + if (DstAddr->Addr[0] =3D=3D 0xFF) { + LanDriver->Stats.TxBroadcastFrames +=3D 1; + } else if ((DstAddr->Addr[0] & 0x1) =3D=3D 1) { + LanDriver->Stats.TxMulticastFrames +=3D 1; + } else { + LanDriver->Stats.TxUnicastFrames +=3D 1; + } + } else { + LanDriver->Stats.TxBroadcastFrames +=3D 1; + } + + // Set the Packet Number and Pointer registers + WriteIoReg8 (LanDriver, LAN91X_PNR, PktNum); + WriteIoReg16 (LanDriver, LAN91X_PTR, PTR_AUTO_INCR); + + // Set up mutable buffer information variables + Ptr =3D BufAddr; + Len =3D BufSize; + + // Write Status and Byte Count first + WriteIoReg16 (LanDriver, LAN91X_DATA0, 0); + WriteIoReg16 (LanDriver, LAN91X_DATA0, (Len + LAN91X_PKT_OVERHEAD) & BCW= _COUNT); + + // This packet may come with a preconfigured Ethernet header. + // If not, we need to construct one from optional parameters. + if (HdrSize) { + + // Write the destination address + WriteIoData (LanDriver, DstAddr, NET_ETHER_ADDR_LEN); + + // Write the Source Address + if (SrcAddr !=3D NULL) { + WriteIoData (LanDriver, SrcAddr, NET_ETHER_ADDR_LEN); + } else { + WriteIoData (LanDriver, &LanDriver->SnpMode.CurrentAddress, NET_ETHE= R_ADDR_LEN); + } + + // Write the Protocol word + Proto =3D HTONS (*Protocol); + WriteIoReg16 (LanDriver, LAN91X_DATA0, Proto); + + // Adjust the data start and length + Ptr +=3D sizeof(ETHER_HEAD); + Len -=3D sizeof(ETHER_HEAD); + } + + // Copy the remainder data buffer, except the odd byte + WriteIoData (LanDriver, Ptr, Len & ~1); + Ptr +=3D Len & ~1; + Len &=3D 1; + + // Write the Packet Control Word and odd byte + WriteIoReg16 (LanDriver, LAN91X_DATA0, + (Len !=3D 0) ? (PCW_ODD | PCW_CRC | *Ptr) : PCW_CRC); + + // Release the packet for transmission + Status =3D MmuOperation (LanDriver, MMUCR_OP_TX_PUSH); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "LAN91x: Tx buffer release failure: %d\n", Status= )); + ReturnUnlock (EFI_DEVICE_ERROR); + } + + // Update the Tx statistics + LanDriver->Stats.TxTotalBytes +=3D BufSize; + LanDriver->Stats.TxGoodFrames +=3D 1; + + // Update the Tx Buffer cache + LinkedTXRecycleBuff =3D AllocateZeroPool (sizeof (MSK_LINKED_SYSTEM_BUF)= ); + if (LinkedTXRecycleBuff =3D=3D NULL) { + return EFI_OUT_OF_RESOURCES; + } + LinkedTXRecycleBuff->Signature =3D TX_MBUF_SIGNATURE; + // + // Add the passed Buffer to the transmit queue. Don't copy. + // + LinkedTXRecycleBuff->SystemBuf.Buf =3D BufAddr; + LinkedTXRecycleBuff->SystemBuf.Length =3D BufSize; + InsertTailList (&LanDriver->TransmitQueueHead, &LinkedTXRecycleBuff->Lin= k); + + Status =3D EFI_SUCCESS; + + // Dump the packet header +#if LAN91X_PRINT_PACKET_HEADERS + Ptr =3D BufAddr; + DEBUG ((DEBUG_ERROR, "LAN91X:SnpTransmit()\n")); + DEBUG ((DEBUG_ERROR, " HdrSize: %d, SrcAddr: %p, Length: %d, Last byte:= %02x\n", + HdrSize, SrcAddr, BufSize, Ptr[BufSize - 1])); + PrintIpDgram ( + (HdrSize =3D=3D 0) ? (EFI_MAC_ADDRESS *)&Ptr[0] : DstAddr, + (HdrSize =3D=3D 0) ? (EFI_MAC_ADDRESS *)&Ptr[6] : (SrcAddr !=3D NULL= ) ? SrcAddr : &LanDriver->SnpMode.CurrentAddress, + (HdrSize =3D=3D 0) ? (UINT16 *)&Ptr[12] : &Proto, + &Ptr[14] + ); +#endif + + // Restore TPL and return +exit_unlock: + gBS->RestoreTPL (SavedTpl); + return Status; +} + + +/* +** UEFI Receive() function +** +*/ +EFI_STATUS +EFIAPI +SnpReceive ( + IN EFI_SIMPLE_NETWORK_PROTOCOL *Snp, + OUT UINTN *HdrSize OPTIONAL, + IN OUT UINTN *BuffSize, + OUT VOID *Data, + OUT EFI_MAC_ADDRESS *SrcAddr OPTIONAL, + OUT EFI_MAC_ADDRESS *DstAddr OPTIONAL, + OUT UINT16 *Protocol OPTIONAL + ) +{ + EFI_TPL SavedTpl; + EFI_STATUS Status; + LAN91X_DRIVER *LanDriver; + UINT8 *DataPtr; + UINT16 PktStatus; + UINT16 PktLength; + UINT16 PktControl; + UINT8 IstReg; + + // Check preliminaries + if ((Snp =3D=3D NULL) || (Data =3D=3D NULL)) { + return EFI_INVALID_PARAMETER; + } + + // Serialize access to data and registers + SavedTpl =3D gBS->RaiseTPL (LAN91X_TPL); + + // Check that driver was started and initialised + switch (Snp->Mode->State) { + case EfiSimpleNetworkInitialized: + break; + case EfiSimpleNetworkStarted: + DEBUG ((DEBUG_WARN, "LAN91x: Driver not yet initialized\n")); + ReturnUnlock (EFI_DEVICE_ERROR); + case EfiSimpleNetworkStopped: + DEBUG ((DEBUG_WARN, "LAN91x: Driver not started\n")); + ReturnUnlock (EFI_NOT_STARTED); + default: + DEBUG ((DEBUG_ERROR, "LAN91x: Driver in an invalid state: %u\n", + (UINTN)Snp->Mode->State)); + ReturnUnlock (EFI_DEVICE_ERROR); + } + + // Find the LanDriver structure + LanDriver =3D INSTANCE_FROM_SNP_THIS(Snp); + + // Check for Rx Overrun + IstReg =3D ReadIoReg8 (LanDriver, LAN91X_IST); + if ((IstReg & IST_RX_OVRN) !=3D 0) { + LanDriver->Stats.RxTotalFrames +=3D 1; + LanDriver->Stats.RxDroppedFrames +=3D 1; + WriteIoReg8 (LanDriver, LAN91X_IST, IST_RX_OVRN); + DEBUG ((DEBUG_WARN, "LAN91x: Receiver overrun\n")); + } + + // Check for Rx data available + if ((IstReg & IST_RCV) =3D=3D 0) { + ReturnUnlock (EFI_NOT_READY); + } + + // Configure the PTR register for reading + WriteIoReg16 (LanDriver, LAN91X_PTR, PTR_RCV | PTR_AUTO_INCR | PTR_READ); + + // Read the Packet Status and Packet Length words + PktStatus =3D ReadIoReg16 (LanDriver, LAN91X_DATA0); + PktLength =3D ReadIoReg16 (LanDriver, LAN91X_DATA0) & BCW_COUNT; + + // Check for valid received packet + if ((PktStatus =3D=3D 0) && (PktLength =3D=3D 0)) { + DEBUG ((DEBUG_WARN, "LAN91x: Received zero-length packet. IST=3D%04x\n= ", IstReg)); + ReturnUnlock (EFI_NOT_READY); + } + LanDriver->Stats.RxTotalFrames +=3D 1; + + // Check if we got a CRC error + if ((PktStatus & RX_BAD_CRC) !=3D 0) { + DEBUG ((DEBUG_WARN, "LAN91x: Received frame CRC error\n")); + LanDriver->Stats.RxCrcErrorFrames +=3D 1; + LanDriver->Stats.RxDroppedFrames +=3D 1; + Status =3D EFI_DEVICE_ERROR; + goto exit_release; + } + + // Check if we got a too-short frame + if ((PktStatus & RX_TOO_SHORT) !=3D 0) { + DEBUG ((DEBUG_WARN, "LAN91x: Received frame too short (%d bytes)\n", P= ktLength)); + LanDriver->Stats.RxUndersizeFrames +=3D 1; + LanDriver->Stats.RxDroppedFrames +=3D 1; + Status =3D EFI_DEVICE_ERROR; + goto exit_release; + } + + // Check if we got a too-long frame + if ((PktStatus & RX_TOO_LONG) !=3D 0) { + DEBUG ((DEBUG_WARN, "LAN91x: Received frame too long (%d bytes)\n", Pk= tLength)); + LanDriver->Stats.RxOversizeFrames +=3D 1; + LanDriver->Stats.RxDroppedFrames +=3D 1; + Status =3D EFI_DEVICE_ERROR; + goto exit_release; + } + + // Check if we got an alignment error + if ((PktStatus & RX_ALGN_ERR) !=3D 0) { + DEBUG ((DEBUG_WARN, "LAN91x: Received frame alignment error\n")); + // Don't seem to keep track of these specifically + LanDriver->Stats.RxDroppedFrames +=3D 1; + Status =3D EFI_DEVICE_ERROR; + goto exit_release; + } + + // Classify the received fram + if ((PktStatus & RX_MULTICAST) !=3D 0) { + LanDriver->Stats.RxMulticastFrames +=3D 1; + } else if ((PktStatus & RX_BROADCAST) !=3D 0) { + LanDriver->Stats.RxBroadcastFrames +=3D 1; + } else { + LanDriver->Stats.RxUnicastFrames +=3D 1; + } + + // Calculate the received packet data length + PktLength -=3D LAN91X_PKT_OVERHEAD; + if ((PktStatus & RX_ODD_FRAME) !=3D 0) { + PktLength +=3D 1; + } + + // Check buffer size + if (*BuffSize < PktLength) { + DEBUG ((DEBUG_WARN, "LAN91x: Receive buffer too small for packet (%d <= %d)\n", + *BuffSize, PktLength)); + *BuffSize =3D PktLength; + Status =3D EFI_BUFFER_TOO_SMALL; + goto exit_release; + } + + // Transfer the data bytes + DataPtr =3D Data; + ReadIoData (LanDriver, DataPtr, PktLength & ~0x0001); + + // Read the PktControl and Odd Byte from the FIFO + PktControl =3D ReadIoReg16 (LanDriver, LAN91X_DATA0); + if ((PktControl & PCW_ODD) !=3D 0) { + DataPtr[PktLength - 1] =3D PktControl & PCW_ODD_BYTE; + } + + // Update buffer size + *BuffSize =3D PktLength; + + if (HdrSize !=3D NULL) { + *HdrSize =3D LanDriver->SnpMode.MediaHeaderSize; + } + + // Extract the destination address + if (DstAddr !=3D NULL) { + CopyMem (DstAddr, &DataPtr[0], NET_ETHER_ADDR_LEN); + } + + // Get the source address + if (SrcAddr !=3D NULL) { + CopyMem (SrcAddr, &DataPtr[6], NET_ETHER_ADDR_LEN); + } + + // Get the protocol + if (Protocol !=3D NULL) { + *Protocol =3D NTOHS (*(UINT16*)(&DataPtr[12])); + } + + // Update the Rx statistics + LanDriver->Stats.RxTotalBytes +=3D PktLength; + LanDriver->Stats.RxGoodFrames +=3D 1; + Status =3D EFI_SUCCESS; + +#if LAN91X_PRINT_PACKET_HEADERS + // Dump the packet header + DEBUG ((DEBUG_ERROR, "LAN91X:SnpReceive()\n")); + DEBUG ((DEBUG_ERROR, " HdrSize: %p, SrcAddr: %p, DstAddr: %p, Protocol:= %p\n", + HdrSize, SrcAddr, DstAddr, Protocol)); + DEBUG ((DEBUG_ERROR, " Length: %d, Last byte: %02x\n", PktLength, DataP= tr[PktLength - 1])); + PrintIpDgram (&DataPtr[0], &DataPtr[6], &DataPtr[12], &DataPtr[14]); +#endif + + // Release the FIFO buffer +exit_release: + MmuOperation (LanDriver, MMUCR_OP_RX_POP_REL); + + // Restore TPL and return +exit_unlock: + gBS->RestoreTPL (SavedTpl); + return Status; +} + + +/*------------------ Driver Execution Environment main entry point -------= -----------*/ + +/* +** Entry point for the LAN91x driver +** +*/ +EFI_STATUS +Lan91xDxeEntry ( + IN EFI_HANDLE Handle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + EFI_STATUS Status; + LAN91X_DRIVER *LanDriver; + EFI_SIMPLE_NETWORK_PROTOCOL *Snp; + EFI_SIMPLE_NETWORK_MODE *SnpMode; + LAN91X_DEVICE_PATH *Lan91xPath; + + // The PcdLan91xDxeBaseAddress PCD must be defined + ASSERT(PcdGet32 (PcdLan91xDxeBaseAddress) !=3D 0); + + // Allocate Resources + LanDriver =3D AllocateZeroPool (sizeof(LAN91X_DRIVER)); + Lan91xPath =3D AllocateCopyPool (sizeof(LAN91X_DEVICE_PATH), &Lan91xPath= Template); + + // Initialize I/O Space access info + LanDriver->IoBase =3D PcdGet32 (PcdLan91xDxeBaseAddress); + LanDriver->PhyAd =3D LAN91X_NO_PHY; + LanDriver->BankSel =3D 0xff; + + // Initialize pointers + Snp =3D &(LanDriver->Snp); + SnpMode =3D &(LanDriver->SnpMode); + Snp->Mode =3D SnpMode; + + // Set the signature of the LAN Driver structure + LanDriver->Signature =3D LAN91X_SIGNATURE; + + // Probe the device + Status =3D Probe (LanDriver); + if (EFI_ERROR(Status)) { + DEBUG ((DEBUG_ERROR, "LAN91x:Lan91xDxeEntry(): Probe failed with statu= s %d\n", Status)); + return Status; + } + +#ifdef LAN91X_PRINT_REGISTERS + PrintIoRegisters (LanDriver); + PrintPhyRegisters (LanDriver); +#endif + + // Initialize transmit queue + InitializeListHead (&LanDriver->TransmitQueueHead); + + // Assign fields and func pointers + Snp->Revision =3D EFI_SIMPLE_NETWORK_PROTOCOL_REVISION; + Snp->WaitForPacket =3D NULL; + Snp->Initialize =3D SnpInitialize; + Snp->Start =3D SnpStart; + Snp->Stop =3D SnpStop; + Snp->Reset =3D SnpReset; + Snp->Shutdown =3D SnpShutdown; + Snp->ReceiveFilters =3D SnpReceiveFilters; + Snp->StationAddress =3D SnpStationAddress; + Snp->Statistics =3D SnpStatistics; + Snp->MCastIpToMac =3D SnpMcastIptoMac; + Snp->NvData =3D SnpNvData; + Snp->GetStatus =3D SnpGetStatus; + Snp->Transmit =3D SnpTransmit; + Snp->Receive =3D SnpReceive; + + // Fill in simple network mode structure + SnpMode->State =3D EfiSimpleNetworkStopped; + SnpMode->HwAddressSize =3D NET_ETHER_ADDR_LEN; // HW address is 6 byt= es + SnpMode->MediaHeaderSize =3D sizeof(ETHER_HEAD); // Size of an Ethernet= header + SnpMode->MaxPacketSize =3D EFI_PAGE_SIZE; // Ethernet Frame (wit= h VLAN tag +4 bytes) + + // Supported receive filters + SnpMode->ReceiveFilterMask =3D EFI_SIMPLE_NETWORK_RECEIVE_UNICAST | + EFI_SIMPLE_NETWORK_RECEIVE_MULTICAST | + EFI_SIMPLE_NETWORK_RECEIVE_BROADCAST | + EFI_SIMPLE_NETWORK_RECEIVE_PROMISCUOUS | + EFI_SIMPLE_NETWORK_RECEIVE_PROMISCUOUS_MULT= ICAST; + + // Initially-enabled receive filters + SnpMode->ReceiveFilterSetting =3D EFI_SIMPLE_NETWORK_RECEIVE_UNICAST | + EFI_SIMPLE_NETWORK_RECEIVE_MULTICAST | + EFI_SIMPLE_NETWORK_RECEIVE_BROADCAST; + + // LAN91x has 64bit hash table. We can filter an infinite MACs, but + // higher-level software must filter out any hash collisions. + SnpMode->MaxMCastFilterCount =3D MAX_MCAST_FILTER_CNT; + SnpMode->MCastFilterCount =3D 0; + ZeroMem (&SnpMode->MCastFilter, MAX_MCAST_FILTER_CNT * sizeof(EFI_MAC_AD= DRESS)); + + // Set the interface type (1: Ethernet or 6: IEEE 802 Networks) + SnpMode->IfType =3D NET_IFTYPE_ETHERNET; + + // Mac address is changeable + SnpMode->MacAddressChangeable =3D TRUE; + + // We can only transmit one packet at a time + SnpMode->MultipleTxSupported =3D FALSE; + + // MediaPresent checks for cable connection and partner link + SnpMode->MediaPresentSupported =3D TRUE; + SnpMode->MediaPresent =3D FALSE; + + // Set broadcast address + SetMem (&SnpMode->BroadcastAddress, sizeof (EFI_MAC_ADDRESS), 0xFF); + + // Assign fields for device path + Lan91xPath->Lan91x.MacAddress =3D SnpMode->PermanentAddress; + Lan91xPath->Lan91x.IfType =3D SnpMode->IfType; + + // Initialise the protocol + Status =3D gBS->InstallMultipleProtocolInterfaces ( + &LanDriver->ControllerHandle, + &gEfiSimpleNetworkProtocolGuid, Snp, + &gEfiDevicePathProtocolGuid, Lan91xPath, + NULL + ); + + // Say what the status of loading the protocol structure is + if (EFI_ERROR(Status)) { + FreePool (LanDriver); + } + + return Status; +} diff --git a/Platform/ARM/VExpressPkg/Drivers/Lan91xDxe/Lan91xDxe.inf b/Pla= tform/ARM/VExpressPkg/Drivers/Lan91xDxe/Lan91xDxe.inf new file mode 100644 index 000000000000..11a9f74c50f4 --- /dev/null +++ b/Platform/ARM/VExpressPkg/Drivers/Lan91xDxe/Lan91xDxe.inf @@ -0,0 +1,59 @@ +#/** @file +# INF file for the SMSC LAN91x series Network Controller Driver. +# +# WARNING: +# This driver fails to follow the UEFI driver model without a good +# reason, and only remains in the tree because it is still used by +# a small number of platforms. It will be removed when no longer used. +# New platforms should not use it, and no one should use this as +# reference code for developing new drivers. +# +# Copyright (c) 2013-2017 Linaro.org +# +# Derived from the LAN9118 driver. Original sources +# Copyright (c) 2012-2013, ARM Limited. All rights reserved. +# +# SPDX-License-Identifier: BSD-2-Clause-Patent +# +#**/ + +[Defines] + INF_VERSION =3D 0x00010019 + BASE_NAME =3D Lan91xDxe + FILE_GUID =3D 5c12ea2f-9897-48af-8138-25f4ce6ff8d6 + MODULE_TYPE =3D DXE_DRIVER + VERSION_STRING =3D 0.1 + ENTRY_POINT =3D Lan91xDxeEntry + +[Sources.common] + Lan91xDxe.c + Lan91xDxeHw.h + +[Packages] + MdeModulePkg/MdeModulePkg.dec + MdePkg/MdePkg.dec + NetworkPkg/NetworkPkg.dec + Platform/ARM/VExpressPkg/ArmVExpressPkg.dec + +[LibraryClasses] + ArmLib + BaseLib + BaseMemoryLib + DevicePathLib + IoLib + NetLib + TimerLib + UefiDriverEntryPoint + UefiLib + +[Protocols] + gEfiSimpleNetworkProtocolGuid + gEfiMetronomeArchProtocolGuid + gEfiPxeBaseCodeProtocolGuid + gEfiDevicePathProtocolGuid + +[FixedPcd] + gArmVExpressTokenSpaceGuid.PcdLan91xDxeBaseAddress + +[Depex] + TRUE diff --git a/Platform/ARM/VExpressPkg/Drivers/Lan91xDxe/Lan91xDxeHw.h b/Pla= tform/ARM/VExpressPkg/Drivers/Lan91xDxe/Lan91xDxeHw.h new file mode 100644 index 000000000000..23d9713e4d2b --- /dev/null +++ b/Platform/ARM/VExpressPkg/Drivers/Lan91xDxe/Lan91xDxeHw.h @@ -0,0 +1,279 @@ +/** @file +* SMSC LAN91x series Network Controller Driver. +* +* WARNING: +* This driver fails to follow the UEFI driver model without a good +* reason, and only remains in the tree because it is still used by +* a small number of platforms. It will be removed when no longer used. +* New platforms should not use it, and no one should use this as +* reference code for developing new drivers. +* +* Copyright (c) 2013-2017 Linaro.org +* +* SPDX-License-Identifier: BSD-2-Clause-Patent +* +**/ + +#ifndef __LAN91XDXEHW_H__ +#define __LAN91XDXEHW_H__ + +#include + +#define MakeRegister(Bank, Offset) (((Bank) << 8) | (Offset)) +#define RegisterToBank(Register) (((Register) >> 8) & 0x07) +#define RegisterToOffset(Register) ((Register) & 0x0f) + +/*------------------------------------------------------------------------= --------------------------------------------- + + SMSC LAN91x Registers + +--------------------------------------------------------------------------= -------------------------------------------*/ +#define LAN91X_BANK_OFFSET 0xe // Bank Select Reg= ister (all banks) + +#define LAN91X_TCR MakeRegister (0, 0x0) // Transmit Contro= l Register +#define LAN91X_EPHSR MakeRegister (0, 0x2) // EPH Status Regi= ster +#define LAN91X_RCR MakeRegister (0, 0x4) // Receive Control= Register +#define LAN91X_ECR MakeRegister (0, 0x6) // Counter Register +#define LAN91X_MIR MakeRegister (0, 0x8) // Memory Informat= ion Register +#define LAN91X_RPCR MakeRegister (0, 0xa) // Receive/Phy Con= trol Register + +#define LAN91X_CR MakeRegister (1, 0x0) // Configuration R= egister +#define LAN91X_BAR MakeRegister (1, 0x2) // Base Address Re= gister +#define LAN91X_IAR0 MakeRegister (1, 0x4) // Individual Addr= ess Register 0 +#define LAN91X_IAR1 MakeRegister (1, 0x5) // Individual Addr= ess Register 1 +#define LAN91X_IAR2 MakeRegister (1, 0x6) // Individual Addr= ess Register 2 +#define LAN91X_IAR3 MakeRegister (1, 0x7) // Individual Addr= ess Register 3 +#define LAN91X_IAR4 MakeRegister (1, 0x8) // Individual Addr= ess Register 4 +#define LAN91X_IAR5 MakeRegister (1, 0x9) // Individual Addr= ess Register 5 +#define LAN91X_GPR MakeRegister (1, 0xa) // General Purpose= Register +#define LAN91X_CTR MakeRegister (1, 0xc) // Control Register + +#define LAN91X_MMUCR MakeRegister (2, 0x0) // MMU Command Reg= ister +#define LAN91X_PNR MakeRegister (2, 0x2) // Packet Number R= egister +#define LAN91X_ARR MakeRegister (2, 0x3) // Allocation Resu= lt Register +#define LAN91X_FIFO MakeRegister (2, 0x4) // FIFO Ports Regi= ster +#define LAN91X_PTR MakeRegister (2, 0x6) // Pointer Register +#define LAN91X_DATA0 MakeRegister (2, 0x8) // Data Register 0 +#define LAN91X_DATA1 MakeRegister (2, 0x9) // Data Register 1 +#define LAN91X_DATA2 MakeRegister (2, 0xa) // Data Register 2 +#define LAN91X_DATA3 MakeRegister (2, 0xb) // Data Register 3 +#define LAN91X_IST MakeRegister (2, 0xc) // Interrupt Statu= s Register +#define LAN91X_MSK MakeRegister (2, 0xd) // Interrupt Mask = Register + +#define LAN91X_MT0 MakeRegister (3, 0x0) // Multicast Table= Register 0 +#define LAN91X_MT1 MakeRegister (3, 0x1) // Multicast Table= Register 1 +#define LAN91X_MT2 MakeRegister (3, 0x2) // Multicast Table= Register 2 +#define LAN91X_MT3 MakeRegister (3, 0x3) // Multicast Table= Register 3 +#define LAN91X_MT4 MakeRegister (3, 0x4) // Multicast Table= Register 4 +#define LAN91X_MT5 MakeRegister (3, 0x5) // Multicast Table= Register 5 +#define LAN91X_MT6 MakeRegister (3, 0x6) // Multicast Table= Register 6 +#define LAN91X_MT7 MakeRegister (3, 0x7) // Multicast Table= Register 7 +#define LAN91X_MGMT MakeRegister (3, 0x8) // Management Inte= rface Register +#define LAN91X_REV MakeRegister (3, 0xa) // Revision Regist= er +#define LAN91X_RCV MakeRegister (3, 0xc) // RCV Register + +// Transmit Control Register Bits +#define TCR_TXENA BIT0 +#define TCR_LOOP BIT1 +#define TCR_FORCOL BIT2 +#define TCR_PAD_EN BIT7 +#define TCR_NOCRC BIT8 +#define TCR_MON_CSN BIT10 +#define TCR_FDUPLX BIT11 +#define TCR_STP_SQET BIT12 +#define TCR_EPH_LOOP BIT13 +#define TCR_SWFDUP BIT15 + +#define TCR_DEFAULT (TCR_TXENA | TCR_PAD_EN) +#define TCR_CLEAR 0x0 + +// EPH Status Register Bits +#define EPHSR_TX_SUC BIT0 +#define EPHSR_SNGLCOL BIT1 +#define EPHSR_MULCOL BIT2 +#define EPHSR_LTX_MULT BIT3 +#define EPHSR_16COL BIT4 +#define EPHSR_SQET BIT5 +#define EPHSR_LTX_BRD BIT6 +#define EPHSR_TX_DEFR BIT7 +#define EPHSR_LATCOL BIT9 +#define EPHSR_LOST_CARR BIT10 +#define EPHSR_EXC_DEF BIT11 +#define EPHSR_CTR_ROL BIT12 +#define EPHSR_LINK_OK BIT14 + +// Receive Control Register Bits +#define RCR_RX_ABORT BIT0 +#define RCR_PRMS BIT1 +#define RCR_ALMUL BIT2 +#define RCR_RXEN BIT8 +#define RCR_STRIP_CRC BIT9 +#define RCR_ABORT_ENB BIT13 +#define RCR_FILT_CAR BIT14 +#define RCR_SOFT_RST BIT15 + +#define RCR_DEFAULT (RCR_STRIP_CRC | RCR_RXEN) +#define RCR_CLEAR 0x0 + +// Receive/Phy Control Register Bits +#define RPCR_LS0B BIT2 +#define RPCR_LS1B BIT3 +#define RPCR_LS2B BIT4 +#define RPCR_LS0A BIT5 +#define RPCR_LS1A BIT6 +#define RPCR_LS2A BIT7 +#define RPCR_ANEG BIT11 +#define RPCR_DPLX BIT12 +#define RPCR_SPEED BIT13 + +// Configuration Register Bits +#define CR_EXT_PHY BIT9 +#define CR_GPCNTRL BIT10 +#define CR_NO_WAIT BIT12 +#define CR_EPH_POWER_EN BIT15 + +#define CR_DEFAULT (CR_EPH_POWER_EN | CR_NO_WAIT) + +// Control Register Bits +#define CTR_STORE BIT0 +#define CTR_RELOAD BIT1 +#define CTR_EEPROM_SEL BIT2 +#define CTR_TE_ENABLE BIT5 +#define CTR_CR_ENABLE BIT6 +#define CTR_LE_ENABLE BIT7 +#define CTR_AUTO_REL BIT11 +#define CTR_RCV_BAD BIT14 + +#define CTR_RESERVED (BIT12 | BIT9 | BIT4) +#define CTR_DEFAULT (CTR_RESERVED | CTR_AUTO_REL) + +// MMU Command Register Bits +#define MMUCR_BUSY BIT0 + +// MMU Command Register Operaction Codes +#define MMUCR_OP_NOOP (0 << 5) // No operation +#define MMUCR_OP_TX_ALLOC (1 << 5) // Allocate memory for TX +#define MMUCR_OP_RESET_MMU (2 << 5) // Reset MMU to initial st= ate +#define MMUCR_OP_RX_POP (3 << 5) // Remove frame from top o= f RX FIFO +#define MMUCR_OP_RX_POP_REL (4 << 5) // Remove and release fram= e from top of RX FIFO +#define MMUCR_OP_RX_REL (5 << 5) // Release specific RX fra= me +#define MMUCR_OP_TX_PUSH (6 << 5) // Enqueue packet number i= nto TX FIFO +#define MMUCR_OP_TX_RESET (7 << 5) // Reset TX FIFOs + +// Packet Number Register Bits +#define PNR_PACKET (0x3f) + +// Allocation Result Register Bits +#define ARR_PACKET (0x3f) +#define ARR_FAILED BIT7 + +// FIFO Ports Register Bits +#define FIFO_TX_PACKET (0x003f) +#define FIFO_TEMPTY BIT7 +#define FIFO_RX_PACKET (0x3f00) +#define FIFO_REMPTY BIT15 + +// Pointer Register Bits +#define PTR_POINTER (0x07ff) +#define PTR_NOT_EMPTY BIT11 +#define PTR_READ BIT13 +#define PTR_AUTO_INCR BIT14 +#define PTR_RCV BIT15 + +// Interrupt Status and Mask Register Bits +#define IST_RCV BIT0 +#define IST_TX BIT1 +#define IST_TX_EMPTY BIT2 +#define IST_ALLOC BIT3 +#define IST_RX_OVRN BIT4 +#define IST_EPH BIT5 +#define IST_MD BIT7 + +// Management Interface +#define MGMT_MDO BIT0 +#define MGMT_MDI BIT1 +#define MGMT_MCLK BIT2 +#define MGMT_MDOE BIT3 +#define MGMT_MSK_CRS100 BIT14 + +// RCV Register +#define RCV_MBO (0x1f) +#define RCV_RCV_DISCRD BIT7 + +// Packet RX Status word bits +#define RX_MULTICAST BIT0 +#define RX_HASH (0x7e) +#define RX_TOO_SHORT BIT10 +#define RX_TOO_LONG BIT11 +#define RX_ODD_FRAME BIT12 +#define RX_BAD_CRC BIT13 +#define RX_BROADCAST BIT14 +#define RX_ALGN_ERR BIT15 + +// Packet Byte Count word bits +#define BCW_COUNT (0x7fe) + +// Packet Control Word bits +#define PCW_ODD_BYTE (0x00ff) +#define PCW_CRC BIT12 +#define PCW_ODD BIT13 + +/*------------------------------------------------------------------------= --------------------------------------------- + + SMSC PHY Registers + + Most of these should be common, as there is + documented STANDARD for PHY registers! + +--------------------------------------------------------------------------= -------------------------------------------*/ +// +// PHY Register Numbers +// +#define PHY_INDEX_BASIC_CTRL 0 +#define PHY_INDEX_BASIC_STATUS 1 +#define PHY_INDEX_ID1 2 +#define PHY_INDEX_ID2 3 +#define PHY_INDEX_AUTO_NEG_ADVERT 4 +#define PHY_INDEX_AUTO_NEG_LINK_ABILITY 5 + +#define PHY_INDEX_CONFIG1 16 +#define PHY_INDEX_CONFIG2 17 +#define PHY_INDEX_STATUS_OUTPUT 18 +#define PHY_INDEX_MASK 19 + + +// PHY control register bits +#define PHYCR_COLL_TEST BIT7 // Col= lision test enable +#define PHYCR_DUPLEX_MODE BIT8 // Set= Duplex Mode +#define PHYCR_RST_AUTO BIT9 // Res= tart Auto-Negotiation of Link abilities +#define PHYCR_PD BIT11 // Pow= er-Down switch +#define PHYCR_AUTO_EN BIT12 // Aut= o-Negotiation Enable +#define PHYCR_SPEED_SEL BIT13 // Lin= k Speed Selection +#define PHYCR_LOOPBK BIT14 // Set= loopback mode +#define PHYCR_RESET BIT15 // Do = a PHY reset + +// PHY status register bits +#define PHYSTS_EXT_CAP BIT0 // Ext= ended Capabilities Register capability +#define PHYSTS_JABBER BIT1 // Jab= ber condition detected +#define PHYSTS_LINK_STS BIT2 // Lin= k Status +#define PHYSTS_AUTO_CAP BIT3 // Aut= o-Negotiation Capability +#define PHYSTS_REMOTE_FAULT BIT4 // Rem= ote fault detected +#define PHYSTS_AUTO_COMP BIT5 // Aut= o-Negotiation Completed +#define PHYSTS_10BASET_HDPLX BIT11 // 10M= bps Half-Duplex ability +#define PHYSTS_10BASET_FDPLX BIT12 // 10M= bps Full-Duplex ability +#define PHYSTS_100BASETX_HDPLX BIT13 // 100= Mbps Half-Duplex ability +#define PHYSTS_100BASETX_FDPLX BIT14 // 100= Mbps Full-Duplex ability +#define PHYSTS_100BASE_T4 BIT15 // Bas= e T4 ability + +// PHY Auto-Negotiation advertisement +#define PHYANA_SEL_MASK ((UINT32)0x1F) // Lin= k type selector +#define PHYANA_CSMA BIT0 // Adv= ertise CSMA capability +#define PHYANA_10BASET BIT5 // Adv= ertise 10BASET capability +#define PHYANA_10BASETFD BIT6 // Adv= ertise 10BASET Full duplex capability +#define PHYANA_100BASETX BIT7 // Adv= ertise 100BASETX capability +#define PHYANA_100BASETXFD BIT8 // Adv= ertise 100 BASETX Full duplex capability +#define PHYANA_100BASET4 BIT9 // Adv= ertise 100 BASETX Full duplex capability +#define PHYANA_PAUSE_OP_MASK (3 << 10) // Adv= ertise PAUSE frame capability +#define PHYANA_REMOTE_FAULT BIT13 // Rem= ote fault detected + +#endif /* __LAN91XDXEHW_H__ */ --=20 2.17.1 -=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D- Groups.io Links: You receive all messages sent to this group. View/Reply Online (#58454): https://edk2.groups.io/g/devel/message/58454 Mute This Topic: https://groups.io/mt/73380297/1787277 Group Owner: devel+owner@edk2.groups.io Unsubscribe: https://edk2.groups.io/g/devel/unsub [importer@patchew.org] -=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D- From nobody Mon May 6 19:29:01 2024 Delivered-To: importer@patchew.org Received-SPF: pass (zohomail.com: domain of groups.io designates 66.175.222.12 as permitted sender) client-ip=66.175.222.12; envelope-from=bounce+27952+58455+1787277+3901457@groups.io; helo=web01.groups.io; Authentication-Results: mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of groups.io designates 66.175.222.12 as permitted sender) smtp.mailfrom=bounce+27952+58455+1787277+3901457@groups.io ARC-Seal: i=1; a=rsa-sha256; t=1588267029; cv=none; d=zohomail.com; s=zohoarc; b=PM57nvILo+tUXEDqdj9nEm5ZdkpAtu3YnIC3ekx9n5u7trXCklMslVMPuC5ySam+yda/67wbk0qPpg6ucwvZawZ/LdMldUwoC/EEk4WR1f4ejGOR863qZldr9gu71dM2kFeUibWNUjZuU0uKr6LjKUVtINvc6gC5nYprVWbWle4= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1588267029; h=Cc:Date:From:In-Reply-To:List-Id:List-Unsubscribe:Message-ID:Reply-To:References:Sender:Subject:To; bh=oU2MfYurNCRyB1idfKI4QvH8gV3DE3oIgoXg4GsqJgo=; b=K8pNFPBweI/HPeFLbeiZrOAcVdIHZUk4XB9ja9JCCfivUnKXsaAtPcuUbZNYPVxVNlqcApz/hAFRSdLa/8Ks+cHrXNFVmYbOSTH5JhMYFV48W06AYbrAsSslRo4EJ+1z8cEMXfuerMEyrJbohQzJQGoubjUQZ+deFDrC6IdxKs4= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of groups.io designates 66.175.222.12 as permitted sender) smtp.mailfrom=bounce+27952+58455+1787277+3901457@groups.io Received: from web01.groups.io (web01.groups.io [66.175.222.12]) by mx.zohomail.com with SMTPS id 158826702892235.0694441943981; Thu, 30 Apr 2020 10:17:08 -0700 (PDT) Return-Path: X-Received: by 127.0.0.2 with SMTP id JFZjYY1788612x9NiTSIh0Cg; Thu, 30 Apr 2020 10:17:08 -0700 X-Received: from foss.arm.com (foss.arm.com [217.140.110.172]) by mx.groups.io with SMTP id smtpd.web12.757.1588267027719955780 for ; Thu, 30 Apr 2020 10:17:08 -0700 X-Received: from usa-sjc-imap-foss1.foss.arm.com (unknown [10.121.207.14]) by usa-sjc-mx-foss1.foss.arm.com (Postfix) with ESMTP id 67238101E; Thu, 30 Apr 2020 10:17:07 -0700 (PDT) X-Received: from e123331-lin.home (unknown [172.31.20.19]) by usa-sjc-imap-foss1.foss.arm.com (Postfix) with ESMTPSA id 3D6A33F73D; Thu, 30 Apr 2020 10:17:06 -0700 (PDT) From: "Ard Biesheuvel" To: devel@edk2.groups.io Cc: leif@nuviainc.com, Ard Biesheuvel Subject: [edk2-devel] [PATCH edk2-platforms v3 7/8] Platform/ARM/VExpressPkg: incorporate Lan9118 driver Date: Thu, 30 Apr 2020 19:16:48 +0200 Message-Id: <20200430171650.24139-8-ard.biesheuvel@arm.com> In-Reply-To: <20200430171650.24139-1-ard.biesheuvel@arm.com> References: <20200430171650.24139-1-ard.biesheuvel@arm.com> Precedence: Bulk List-Unsubscribe: Sender: devel@edk2.groups.io List-Id: <27952.devel.edk2.groups.io> Mailing-List: list devel@edk2.groups.io; contact devel+owner@edk2.groups.io Reply-To: devel@edk2.groups.io,ard.biesheuvel@arm.com X-Gm-Message-State: mwyqXB3OM8FLCMvvx5RtKeaax1787277AA= DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=groups.io; q=dns/txt; s=20140610; t=1588267028; bh=bOembt9KPCkKTtgc6TOo8dyi1R/odu27Y0ZHl1ot/9c=; h=Cc:Date:From:Reply-To:Subject:To; b=p0eW1EGHqEfvBcpqnLbDn/mdUp/9hnw+RI0LtwaCHjzxzIYOERK0Dejo8zfxTb2nr7l hWGXjHbdOnP7VZ7iBnhHEGhJT3lfDKKfiWTfxpCxdgBPG5Ef1UanFjs2rRQR/SEKF+f2q O5vA5xzjAcDJI1kHafw8C4CP3wsIogN5Emo= X-ZohoMail-DKIM: pass (identity @groups.io) Content-Transfer-Encoding: quoted-printable MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Incorporate the Lan91x driver from EmbeddedPkg, which is only used on obsolete ARM development platforms and does not follow the UEFI driver model. This will allow us to drop if from the core EDK2 repository. Signed-off-by: Ard Biesheuvel Reviewed-by: Leif Lindholm Reviewed-by: Philippe Mathieu-Daude Reviewed-by: Philippe Mathieu-Daud=C3=A9 --- Platform/ARM/JunoPkg/ArmJuno.dsc | 8 +- Platform/ARM/JunoPkg/ArmJuno.fdf | 2 +- Platform/ARM/VExpressPkg/ArmVExpress-CTA15-A7.dsc | 6 +- Platform/ARM/VExpressPkg/ArmVExpress-CTA15-A7.fdf | 2 +- Platform/ARM/VExpressPkg/ArmVExpressPkg.dec | 8 + Platform/ARM/VExpressPkg/Drivers/Lan9118Dxe/Lan9118Dxe.c | 1539 ++++++= ++++++++++++++ Platform/ARM/VExpressPkg/Drivers/Lan9118Dxe/Lan9118Dxe.h | 304 ++++ Platform/ARM/VExpressPkg/Drivers/Lan9118Dxe/Lan9118Dxe.inf | 58 + Platform/ARM/VExpressPkg/Drivers/Lan9118Dxe/Lan9118DxeHw.h | 401 +++++ Platform/ARM/VExpressPkg/Drivers/Lan9118Dxe/Lan9118DxeUtil.c | 1039 ++++++= +++++++ Platform/ARM/VExpressPkg/Drivers/Lan9118Dxe/Lan9118DxeUtil.h | 283 ++++ 11 files changed, 3641 insertions(+), 9 deletions(-) diff --git a/Platform/ARM/JunoPkg/ArmJuno.dsc b/Platform/ARM/JunoPkg/ArmJun= o.dsc index 1c39da4897ed..a6ea957b3832 100644 --- a/Platform/ARM/JunoPkg/ArmJuno.dsc +++ b/Platform/ARM/JunoPkg/ArmJuno.dsc @@ -150,9 +150,9 @@ [PcdsFixedAtBuild.common] !endif =20 # LAN9118 Ethernet Driver - gEmbeddedTokenSpaceGuid.PcdLan9118DxeBaseAddress|0x18000000 - gEmbeddedTokenSpaceGuid.PcdLan9118DefaultMacAddress|0x1215161822242628 - gEmbeddedTokenSpaceGuid.PcdLan9118DefaultNegotiationTimeout|40000 + gArmVExpressTokenSpaceGuid.PcdLan9118DxeBaseAddress|0x18000000 + gArmVExpressTokenSpaceGuid.PcdLan9118DefaultMacAddress|0x1215161822242628 + gArmVExpressTokenSpaceGuid.PcdLan9118DefaultNegotiationTimeout|40000 =20 # # ARM Generic Interrupt Controller @@ -324,7 +324,7 @@ [Components.common] # # Networking stack # - EmbeddedPkg/Drivers/Lan9118Dxe/Lan9118Dxe.inf + Platform/ARM/VExpressPkg/Drivers/Lan9118Dxe/Lan9118Dxe.inf !if 0 OptionRomPkg/MarvellYukonDxe/MarvellYukonDxe.inf !endif diff --git a/Platform/ARM/JunoPkg/ArmJuno.fdf b/Platform/ARM/JunoPkg/ArmJun= o.fdf index d771cbf35790..5d791a4e1607 100644 --- a/Platform/ARM/JunoPkg/ArmJuno.fdf +++ b/Platform/ARM/JunoPkg/ArmJuno.fdf @@ -196,7 +196,7 @@ [FV.FvMain] # !include Platform/ARM/VExpressPkg/ArmVExpress-networking.fdf.inc =20 - INF EmbeddedPkg/Drivers/Lan9118Dxe/Lan9118Dxe.inf + INF Platform/ARM/VExpressPkg/Drivers/Lan9118Dxe/Lan9118Dxe.inf !if 0 INF OptionRomPkg/MarvellYukonDxe/MarvellYukonDxe.inf !endif diff --git a/Platform/ARM/VExpressPkg/ArmVExpress-CTA15-A7.dsc b/Platform/A= RM/VExpressPkg/ArmVExpress-CTA15-A7.dsc index 6dad31026aa5..bee7913feb52 100644 --- a/Platform/ARM/VExpressPkg/ArmVExpress-CTA15-A7.dsc +++ b/Platform/ARM/VExpressPkg/ArmVExpress-CTA15-A7.dsc @@ -160,8 +160,8 @@ [PcdsFixedAtBuild.common] gEmbeddedTokenSpaceGuid.PcdIsp1761BaseAddress|0x1B000000 =20 # Ethernet (SMSC LAN9118) - gEmbeddedTokenSpaceGuid.PcdLan9118DxeBaseAddress|0x1A000000 - gEmbeddedTokenSpaceGuid.PcdLan9118DefaultNegotiationTimeout|400000 + gArmVExpressTokenSpaceGuid.PcdLan9118DxeBaseAddress|0x1A000000 + gArmVExpressTokenSpaceGuid.PcdLan9118DefaultNegotiationTimeout|400000 =20 # # Define the device path to the FDT for the platform @@ -252,7 +252,7 @@ [Components.common] Platform/ARM/VExpressPkg/Drivers/PL180MciDxe/PL180MciDxe.inf =20 # SMSC LAN 9118 - EmbeddedPkg/Drivers/Lan9118Dxe/Lan9118Dxe.inf + Platform/ARM/VExpressPkg/Drivers/Lan9118Dxe/Lan9118Dxe.inf =20 # # FAT filesystem + GPT/MBR partitioning diff --git a/Platform/ARM/VExpressPkg/ArmVExpress-CTA15-A7.fdf b/Platform/A= RM/VExpressPkg/ArmVExpress-CTA15-A7.fdf index 64da1102ff07..b133375e1a11 100644 --- a/Platform/ARM/VExpressPkg/ArmVExpress-CTA15-A7.fdf +++ b/Platform/ARM/VExpressPkg/ArmVExpress-CTA15-A7.fdf @@ -143,7 +143,7 @@ [FV.FvMain] # !include Platform/ARM/VExpressPkg/ArmVExpress-networking.fdf.inc =20 - INF EmbeddedPkg/Drivers/Lan9118Dxe/Lan9118Dxe.inf + INF Platform/ARM/VExpressPkg/Drivers/Lan9118Dxe/Lan9118Dxe.inf =20 # # UEFI application diff --git a/Platform/ARM/VExpressPkg/ArmVExpressPkg.dec b/Platform/ARM/VEx= pressPkg/ArmVExpressPkg.dec index ea000a0e5387..e42905aabf2b 100644 --- a/Platform/ARM/VExpressPkg/ArmVExpressPkg.dec +++ b/Platform/ARM/VExpressPkg/ArmVExpressPkg.dec @@ -59,3 +59,11 @@ [PcdsFixedAtBuild.common] =20 # LAN91x Ethernet Driver PCDs gArmVExpressTokenSpaceGuid.PcdLan91xDxeBaseAddress|0x0|UINT32|0x0000000B + + # LAN9118 Ethernet Driver PCDs + gArmVExpressTokenSpaceGuid.PcdLan9118DxeBaseAddress|0x0|UINT32|0x00000025 + gArmVExpressTokenSpaceGuid.PcdLan9118DefaultMacAddress|0x0|UINT64|0x0000= 0026 + gArmVExpressTokenSpaceGuid.PcdLan9118DefaultNegotiationTimeout|4000|UINT= 32|0x00000027 + # The default feature mask below disables full duplex negotiation, since= full + # duplex operation is suspected to be broken in the driver. + gArmVExpressTokenSpaceGuid.PcdLan9118NegotiationFeatureMask|0xFFFFFEBF|U= INT32|0x00000028 diff --git a/Platform/ARM/VExpressPkg/Drivers/Lan9118Dxe/Lan9118Dxe.c b/Pla= tform/ARM/VExpressPkg/Drivers/Lan9118Dxe/Lan9118Dxe.c new file mode 100644 index 000000000000..b90c32346fab --- /dev/null +++ b/Platform/ARM/VExpressPkg/Drivers/Lan9118Dxe/Lan9118Dxe.c @@ -0,0 +1,1539 @@ +/** @file +* +* WARNING: +* This driver fails to follow the UEFI driver model without a good +* reason, and only remains in the tree because it is still used by +* a small number of platforms. It will be removed when no longer used. +* New platforms should not use it, and no one should use this as +* reference code for developing new drivers. +* +* Copyright (c) 2012-2014, ARM Limited. All rights reserved. +* +* SPDX-License-Identifier: BSD-2-Clause-Patent +* +**/ + +#include "Lan9118Dxe.h" + +typedef struct { + MAC_ADDR_DEVICE_PATH Lan9118; + EFI_DEVICE_PATH_PROTOCOL End; +} LAN9118_DEVICE_PATH; + +LAN9118_DEVICE_PATH Lan9118PathTemplate =3D { + { + { + MESSAGING_DEVICE_PATH, MSG_MAC_ADDR_DP, + { (UINT8) (sizeof(MAC_ADDR_DEVICE_PATH)), (UINT8) ((sizeof(MAC_ADDR_= DEVICE_PATH)) >> 8) } + }, + { { 0 } }, + 0 + }, + { + END_DEVICE_PATH_TYPE, + END_ENTIRE_DEVICE_PATH_SUBTYPE, + { sizeof(EFI_DEVICE_PATH_PROTOCOL), 0 } + } +}; + +/* +** Entry point for the LAN9118 driver +** +*/ +EFI_STATUS +EFIAPI +Lan9118DxeEntry ( + IN EFI_HANDLE Handle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + EFI_STATUS Status; + LAN9118_DRIVER *LanDriver; + EFI_SIMPLE_NETWORK_PROTOCOL *Snp; + EFI_SIMPLE_NETWORK_MODE *SnpMode; + LAN9118_DEVICE_PATH *Lan9118Path; + EFI_HANDLE ControllerHandle; + + // The PcdLan9118DxeBaseAddress PCD must be defined + ASSERT (PcdGet32 (PcdLan9118DxeBaseAddress) !=3D 0); + + // Allocate Resources + LanDriver =3D AllocateZeroPool (sizeof (LAN9118_DRIVER)); + if (LanDriver =3D=3D NULL) { + return EFI_OUT_OF_RESOURCES; + } + Lan9118Path =3D (LAN9118_DEVICE_PATH*)AllocateCopyPool (sizeof (LAN9118_= DEVICE_PATH), &Lan9118PathTemplate); + if (Lan9118Path =3D=3D NULL) { + return EFI_OUT_OF_RESOURCES; + } + + // Initialize pointers + Snp =3D &(LanDriver->Snp); + SnpMode =3D &(LanDriver->SnpMode); + Snp->Mode =3D SnpMode; + + // Set the signature of the LAN Driver structure + LanDriver->Signature =3D LAN9118_SIGNATURE; + + // Assign fields and func pointers + Snp->Revision =3D EFI_SIMPLE_NETWORK_PROTOCOL_REVISION; + Snp->WaitForPacket =3D NULL; + Snp->Initialize =3D SnpInitialize; + Snp->Start =3D SnpStart; + Snp->Stop =3D SnpStop; + Snp->Reset =3D SnpReset; + Snp->Shutdown =3D SnpShutdown; + Snp->ReceiveFilters =3D SnpReceiveFilters; + Snp->StationAddress =3D SnpStationAddress; + Snp->Statistics =3D SnpStatistics; + Snp->MCastIpToMac =3D SnpMcastIptoMac; + Snp->NvData =3D SnpNvData; + Snp->GetStatus =3D SnpGetStatus; + Snp->Transmit =3D SnpTransmit; + Snp->Receive =3D SnpReceive; + + // Start completing simple network mode structure + SnpMode->State =3D EfiSimpleNetworkStopped; + SnpMode->HwAddressSize =3D NET_ETHER_ADDR_LEN; // HW address is 6 bytes + SnpMode->MediaHeaderSize =3D sizeof(ETHER_HEAD); // Not sure of this + SnpMode->MaxPacketSize =3D EFI_PAGE_SIZE; // Preamble + SOF + Ether Fram= e (with VLAN tag +4bytes) + SnpMode->NvRamSize =3D 0; // No NVRAM with this device + SnpMode->NvRamAccessSize =3D 0; // No NVRAM with this device + + // + // Claim that all receive filter settings are supported, though the MULT= ICAST mode + // is not completely supported. The LAN9118 Ethernet controller is only = able to + // do a "hash filtering" and not a perfect filtering on multicast addres= ses. The + // controller does not filter the multicast addresses directly but a has= h value + // of them. The hash value of a multicast address is derived from its CR= C and + // ranges from 0 to 63 included. + // We claim that the perfect MULTICAST filtering mode is supported becau= se + // we do not want the user to switch directly to the PROMISCOUS_MULTICAS= T mode + // and thus not being able to take advantage of the hash filtering. + // + SnpMode->ReceiveFilterMask =3D EFI_SIMPLE_NETWORK_RECEIVE_UNICAST = | + EFI_SIMPLE_NETWORK_RECEIVE_MULTICAST = | + EFI_SIMPLE_NETWORK_RECEIVE_BROADCAST = | + EFI_SIMPLE_NETWORK_RECEIVE_PROMISCUOUS = | + EFI_SIMPLE_NETWORK_RECEIVE_PROMISCUOUS_MULT= ICAST; + + // We do not intend to receive anything for the time being. + SnpMode->ReceiveFilterSetting =3D 0; + + // LAN9118 has 64bit hash table, can filter 64 MCast MAC Addresses + SnpMode->MaxMCastFilterCount =3D MAX_MCAST_FILTER_CNT; + SnpMode->MCastFilterCount =3D 0; + ZeroMem (&SnpMode->MCastFilter, MAX_MCAST_FILTER_CNT * sizeof(EFI_MAC_AD= DRESS)); + + // Set the interface type (1: Ethernet or 6: IEEE 802 Networks) + SnpMode->IfType =3D NET_IFTYPE_ETHERNET; + + // Mac address is changeable as it is loaded from erasable memory + SnpMode->MacAddressChangeable =3D TRUE; + + // Can only transmit one packet at a time + SnpMode->MultipleTxSupported =3D FALSE; + + // MediaPresent checks for cable connection and partner link + SnpMode->MediaPresentSupported =3D TRUE; + SnpMode->MediaPresent =3D FALSE; + + // Set broadcast address + SetMem (&SnpMode->BroadcastAddress, sizeof (EFI_MAC_ADDRESS), 0xFF); + + // Power up the device so we can find the MAC address + Status =3D Lan9118Initialize (Snp); + if (EFI_ERROR (Status)) { + DEBUG ((EFI_D_ERROR, "LAN9118: Error initialising hardware\n")); + return EFI_DEVICE_ERROR; + } + + // Assign fields for device path + CopyMem (&Lan9118Path->Lan9118.MacAddress, &Snp->Mode->CurrentAddress, N= ET_ETHER_ADDR_LEN); + Lan9118Path->Lan9118.IfType =3D Snp->Mode->IfType; + + // Initialise the protocol + ControllerHandle =3D NULL; + Status =3D gBS->InstallMultipleProtocolInterfaces ( + &ControllerHandle, + &gEfiSimpleNetworkProtocolGuid, Snp, + &gEfiDevicePathProtocolGuid, Lan9118Path, + NULL + ); + // Say what the status of loading the protocol structure is + if (EFI_ERROR(Status)) { + FreePool (LanDriver); + } else { + LanDriver->ControllerHandle =3D ControllerHandle; + } + + return Status; +} + +/* + * UEFI Start() function + * + * Parameters: + * + * @param Snp: A pointer to the EFI_SIMPLE_NETWORK_PROTOCOL instance. + * + * Description: + * + * This function starts a network interface. If the network interface s= uccessfully starts, then + * EFI_SUCCESS will be returned. + */ +EFI_STATUS +EFIAPI +SnpStart ( + IN EFI_SIMPLE_NETWORK_PROTOCOL *Snp + ) +{ + // Check Snp instance + if (Snp =3D=3D NULL) { + return EFI_INVALID_PARAMETER; + } + + // Check state + if ((Snp->Mode->State =3D=3D EfiSimpleNetworkStarted) || + (Snp->Mode->State =3D=3D EfiSimpleNetworkInitialized) ) { + return EFI_ALREADY_STARTED; + } + + // Change state + Snp->Mode->State =3D EfiSimpleNetworkStarted; + return EFI_SUCCESS; +} + +/* + * UEFI Stop() function + * + */ +EFI_STATUS +EFIAPI +SnpStop ( + IN EFI_SIMPLE_NETWORK_PROTOCOL* Snp + ) +{ + // Check Snp Instance + if (Snp =3D=3D NULL) { + return EFI_INVALID_PARAMETER; + } + + // Check state of the driver + if (Snp->Mode->State =3D=3D EfiSimpleNetworkStopped) { + return EFI_NOT_STARTED; + } + + // Stop the Tx and Rx + StopTx (STOP_TX_CFG | STOP_TX_MAC, Snp); + StopRx (0, Snp); + + // Change the state + switch (Snp->Mode->State) { + case EfiSimpleNetworkStarted: + case EfiSimpleNetworkInitialized: + Snp->Mode->State =3D EfiSimpleNetworkStopped; + break; + default: + return EFI_DEVICE_ERROR; + } + + // Put the device into a power saving mode ? + return EFI_SUCCESS; +} + + +// Allocated receive and transmit buffers +STATIC UINT32 gTxBuffer =3D 0; + +/* + * UEFI Initialize() function + * + */ +EFI_STATUS +EFIAPI +SnpInitialize ( + IN EFI_SIMPLE_NETWORK_PROTOCOL* Snp, + IN UINTN RxBufferSize OPTIONAL, + IN UINTN TxBufferSize OPTIONAL + ) +{ + EFI_STATUS Status; + UINT32 PmConf; + INT32 AllocResult; + UINT32 RxStatusSize; + UINT32 TxStatusSize; + + // Initialize variables + // Global variables to hold tx and rx FIFO allocation + gTxBuffer =3D 0; + + // Check Snp Instance + if (Snp =3D=3D NULL) { + return EFI_INVALID_PARAMETER; + } + + // First check that driver has not already been initialized + if (Snp->Mode->State =3D=3D EfiSimpleNetworkInitialized) { + DEBUG ((EFI_D_WARN, "LAN9118 Driver already initialized\n")); + return EFI_SUCCESS; + } else + if (Snp->Mode->State =3D=3D EfiSimpleNetworkStopped) { + DEBUG ((EFI_D_WARN, "LAN9118 Driver not started\n")); + return EFI_NOT_STARTED; + } + + // Initiate a PHY reset + Status =3D PhySoftReset (PHY_RESET_PMT, Snp); + if (EFI_ERROR (Status)) { + Snp->Mode->State =3D EfiSimpleNetworkStopped; + DEBUG ((EFI_D_WARN, "Warning: Link not ready after TimeOut. Check ethe= rnet cable\n")); + return EFI_NOT_STARTED; + } + + // Initiate a software reset + Status =3D SoftReset (0, Snp); + if (EFI_ERROR(Status)) { + DEBUG ((EFI_D_WARN, "Soft Reset Failed: Hardware Error\n")); + return EFI_DEVICE_ERROR; + } + + // Read the PM register + PmConf =3D Lan9118MmioRead32 (LAN9118_PMT_CTRL); + + // MPTCTRL_WOL_EN: Allow Wake-On-Lan to detect wake up frames or magic p= ackets + // MPTCTRL_ED_EN: Allow energy detection to allow lowest power consumpt= ion mode + // MPTCTRL_PME_EN: Allow Power Management Events + PmConf =3D 0; + PmConf |=3D (MPTCTRL_WOL_EN | MPTCTRL_ED_EN | MPTCTRL_PME_EN); + + // Write the current configuration to the register + Lan9118MmioWrite32 (LAN9118_PMT_CTRL, PmConf); + + // Configure GPIO and HW + Status =3D ConfigureHardware (HW_CONF_USE_LEDS, Snp); + if (EFI_ERROR(Status)) { + return Status; + } + + // Assign the transmitter buffer size (default values) + TxStatusSize =3D LAN9118_TX_STATUS_SIZE; + RxStatusSize =3D LAN9118_RX_STATUS_SIZE; + + // Check that a buff size was specified + if (TxBufferSize > 0) { + if (RxBufferSize =3D=3D 0) { + RxBufferSize =3D LAN9118_RX_DATA_SIZE; + } + + AllocResult =3D ChangeFifoAllocation ( + ALLOC_USE_FIFOS, + &TxBufferSize, + &RxBufferSize, + &TxStatusSize, + &RxStatusSize, + Snp + ); + + if (AllocResult < 0) { + return EFI_OUT_OF_RESOURCES; + } + } + + // Do auto-negotiation if supported + Status =3D AutoNegotiate (AUTO_NEGOTIATE_ADVERTISE_ALL, Snp); + if (EFI_ERROR(Status)) { + DEBUG ((EFI_D_WARN, "LAN9118: Auto Negotiation failed.\n")); + } + + // Configure flow control depending on speed capabilities + Status =3D ConfigureFlow (0, 0, 0, 0, Snp); + if (EFI_ERROR(Status)) { + return Status; + } + + // Enable the transmitter + Status =3D StartTx (START_TX_MAC | START_TX_CFG, Snp); + if (EFI_ERROR(Status)) { + return Status; + } + + // Now acknowledge all interrupts + Lan9118MmioWrite32 (LAN9118_INT_STS, ~0); + + // Declare the driver as initialized + Snp->Mode->State =3D EfiSimpleNetworkInitialized; + + return Status; +} + +/* + * UEFI Reset () function + * + */ +EFI_STATUS +EFIAPI +SnpReset ( + IN EFI_SIMPLE_NETWORK_PROTOCOL* Snp, + IN BOOLEAN Verification + ) +{ + UINT32 PmConf; + UINT32 HwConf; + UINT32 ResetFlags; + EFI_STATUS Status; + + PmConf =3D 0; + HwConf =3D 0; + ResetFlags =3D 0; + + // Check Snp Instance + if (Snp =3D=3D NULL) { + return EFI_INVALID_PARAMETER; + } + + // First check that driver has not already been initialized + if (Snp->Mode->State =3D=3D EfiSimpleNetworkStarted) { + DEBUG ((EFI_D_WARN, "Warning: LAN9118 Driver not yet initialized\n")); + return EFI_DEVICE_ERROR; + } else if (Snp->Mode->State =3D=3D EfiSimpleNetworkStopped) { + DEBUG ((EFI_D_WARN, "Warning: LAN9118 Driver not started\n")); + return EFI_NOT_STARTED; + } + + // Initiate a PHY reset + Status =3D PhySoftReset (PHY_RESET_PMT, Snp); + if (EFI_ERROR (Status)) { + Snp->Mode->State =3D EfiSimpleNetworkStopped; + return EFI_NOT_STARTED; + } + + // Initiate a software reset + ResetFlags |=3D SOFT_RESET_CHECK_MAC_ADDR_LOAD | SOFT_RESET_CLEAR_INT; + + if (Verification) { + ResetFlags |=3D SOFT_RESET_SELF_TEST; + } + + Status =3D SoftReset (ResetFlags, Snp); + if (EFI_ERROR (Status)) { + DEBUG ((EFI_D_WARN, "Warning: Soft Reset Failed: Hardware Error\n")); + return EFI_DEVICE_ERROR; + } + + // Read the PM register + PmConf =3D Lan9118MmioRead32 (LAN9118_PMT_CTRL); + + // MPTCTRL_WOL_EN: Allow Wake-On-Lan to detect wake up frames or magic p= ackets + // MPTCTRL_ED_EN: Allow energy detection to allow lowest power consumpt= ion mode + // MPTCTRL_PME_EN: Allow Power Management Events + PmConf |=3D (MPTCTRL_WOL_EN | MPTCTRL_ED_EN | MPTCTRL_PME_EN); + + // Write the current configuration to the register + Lan9118MmioWrite32 (LAN9118_PMT_CTRL, PmConf); + + // Reactivate the LEDs + Status =3D ConfigureHardware (HW_CONF_USE_LEDS, Snp); + if (EFI_ERROR (Status)) { + return Status; + } + + // Check that a buffer size was specified in SnpInitialize + if (gTxBuffer !=3D 0) { + HwConf =3D Lan9118MmioRead32 (LAN9118_HW_CFG); // Read the HW r= egister + HwConf &=3D ~HW_CFG_TX_FIFO_SIZE_MASK; // Clear buffer bits fi= rst + HwConf |=3D HW_CFG_TX_FIFO_SIZE(gTxBuffer); // assign size chosen i= n SnpInitialize + + Lan9118MmioWrite32 (LAN9118_HW_CFG, HwConf); // Write the conf + } + + // Enable the receiver and transmitter and clear their contents + StartRx (START_RX_CLEAR, Snp); + StartTx (START_TX_MAC | START_TX_CFG | START_TX_CLEAR, Snp); + + // Now acknowledge all interrupts + Lan9118MmioWrite32 (LAN9118_INT_STS, ~0); + + return EFI_SUCCESS; +} + +/* + * UEFI Shutdown () function + * + */ +EFI_STATUS +EFIAPI +SnpShutdown ( + IN EFI_SIMPLE_NETWORK_PROTOCOL* Snp + ) +{ + EFI_STATUS Status; + + // Check Snp Instance + if (Snp =3D=3D NULL) { + return EFI_INVALID_PARAMETER; + } + + // First check that driver has not already been initialized + if (Snp->Mode->State =3D=3D EfiSimpleNetworkStarted) { + DEBUG ((EFI_D_WARN, "Warning: LAN9118 Driver not yet initialized\n")); + return EFI_DEVICE_ERROR; + } else if (Snp->Mode->State =3D=3D EfiSimpleNetworkStopped) { + DEBUG ((EFI_D_WARN, "Warning: LAN9118 Driver not started\n")); + return EFI_NOT_STARTED; + } + + // Initiate a PHY reset + Status =3D PhySoftReset (PHY_RESET_PMT, Snp); + if (EFI_ERROR (Status)) { + return Status; + } + + // Initiate a software reset + Status =3D SoftReset (0, Snp); + if (EFI_ERROR (Status)) { + DEBUG ((EFI_D_WARN, "Warning: Soft Reset Failed: Hardware Error\n")); + return Status; + } + + // Back to the started and thus not initialized state + Snp->Mode->State =3D EfiSimpleNetworkStarted; + + return EFI_SUCCESS; +} + +/** + Enable and/or disable the receive filters of the LAN9118 + + Please refer to the UEFI specification for the precedence rules among the + Enable, Disable and ResetMCastFilter parameters. + + @param[in] Snp A pointer to the EFI_SIMPLE_NETWORK_PROTOC= OL + instance. + @param[in] Enable A bit mask of receive filters to enable. + @param[in] Disable A bit mask of receive filters to disable. + @param[in] ResetMCastFilter Set to TRUE to reset the contents of the m= ulticast + receive filters on the network interface to + their default values. + @param[in] MCastFilterCnt Number of multicast HW MAC addresses in th= e new + MCastFilter list. This value must be less = than or + equal to the MCastFilterCnt field of + EFI_SIMPLE_NETWORK_MODE. This field is opt= ional if + ResetMCastFilter is TRUE. + @param[in] MCastFilter A pointer to a list of new multicast recei= ve + filter HW MAC addresses. This list will re= place + any existing multicast HW MAC address list= . This + field is optional if ResetMCastFilter is T= RUE. + + @retval EFI_SUCCESS The receive filters of the LAN9118 were = updated. + @retval EFI_NOT_STARTED The LAN9118 has not been started. + @retval EFI_INVALID_PARAMETER One or more of the following conditions = is TRUE : + . This is NULL + . Multicast is being enabled (the + EFI_SIMPLE_NETWORK_RECEIVE_MULTICAST b= it is set in + Enable, it is not set in Disable, and = ResetMCastFilter + is FALSE) and MCastFilterCount is zero. + . Multicast is being enabled and MCastFi= lterCount is + greater than Snp->Mode->MaxMCastFilter= Count. + . Multicast is being enabled and MCastFi= lter is NULL + . Multicast is being enabled and one or = more of the + addresses in the MCastFilter list are = not valid + multicast MAC addresses. + @retval EFI_DEVICE_ERROR The LAN9118 has been started but not ini= tialized. + +**/ +EFI_STATUS +EFIAPI +SnpReceiveFilters ( + IN EFI_SIMPLE_NETWORK_PROTOCOL *Snp, + IN UINT32 Enable, + IN UINT32 Disable, + IN BOOLEAN ResetMCastFilter, + IN UINTN MCastFilterCnt OPTIONAL, + IN EFI_MAC_ADDRESS *MCastFilter OPTIONAL + ) +{ + EFI_SIMPLE_NETWORK_MODE *Mode; + UINT32 MultHashTableHigh; + UINT32 MultHashTableLow; + UINT32 Count; + UINT32 Crc; + UINT8 HashValue; + UINT32 MacCSRValue; + UINT32 ReceiveFilterSetting; + EFI_MAC_ADDRESS *Mac; + EFI_MAC_ADDRESS ZeroMac; + + // Check Snp Instance + if (Snp =3D=3D NULL) { + return EFI_INVALID_PARAMETER; + } + Mode =3D Snp->Mode; + + // Check that driver was started and initialised + if (Mode->State =3D=3D EfiSimpleNetworkStarted) { + DEBUG ((EFI_D_WARN, "Warning: LAN9118 Driver not initialized\n")); + return EFI_DEVICE_ERROR; + } else if (Mode->State =3D=3D EfiSimpleNetworkStopped) { + DEBUG ((EFI_D_WARN, "Warning: LAN9118 Driver in stopped state\n")); + return EFI_NOT_STARTED; + } + + if ((Enable & (~Mode->ReceiveFilterMask)) || + (Disable & (~Mode->ReceiveFilterMask)) ) { + return EFI_INVALID_PARAMETER; + } + + // + // Check the validity of the multicast setting and compute the + // hash values of the multicast mac addresses to listen to. + // + + MultHashTableHigh =3D 0; + MultHashTableLow =3D 0; + if ((!ResetMCastFilter) && + ((Disable & EFI_SIMPLE_NETWORK_RECEIVE_MULTICAST) =3D=3D 0) && + ((Enable & EFI_SIMPLE_NETWORK_RECEIVE_MULTICAST) !=3D 0) ) { + if ((MCastFilterCnt =3D=3D 0) || + (MCastFilterCnt > Mode->MaxMCastFilterCount) || + (MCastFilter =3D=3D NULL) ) { + return EFI_INVALID_PARAMETER; + } + // + // Check the validity of all multicast addresses before to change + // anything. + // + for (Count =3D 0; Count < MCastFilterCnt; Count++) { + if ((MCastFilter[Count].Addr[0] & 1) =3D=3D 0) { + return EFI_INVALID_PARAMETER; + } + } + + // + // Go through each filter address and set appropriate bits on hash tab= le + // + for (Count =3D 0; Count < MCastFilterCnt; Count++) { + Mac =3D &(MCastFilter[Count]); + CopyMem (&Mode->MCastFilter[Count], Mac, sizeof(EFI_MAC_ADDRESS)); + + Crc =3D GenEtherCrc32 (Mac, NET_ETHER_ADDR_LEN); + //gBS->CalculateCrc32 ((VOID*)&Mfilter[Count],6,&Crc); <-- doesn't w= ork as desired + + // + // The most significant 6 bits of the MAC address CRC constitute the= hash + // value of the MAC address. + // + HashValue =3D (Crc >> 26) & 0x3F; + + // Select hashlow register if MSB is not set + if ((HashValue & 0x20) =3D=3D 0) { + MultHashTableLow |=3D (1 << HashValue); + } else { + MultHashTableHigh |=3D (1 << (HashValue & 0x1F)); + } + } + Mode->MCastFilterCount =3D MCastFilterCnt; + } else if (ResetMCastFilter) { + Mode->MCastFilterCount =3D 0; + } else { + MultHashTableLow =3D IndirectMACRead32 (INDIRECT_MAC_INDEX_HASHL); + MultHashTableHigh =3D IndirectMACRead32 (INDIRECT_MAC_INDEX_HASHH); + } + + // + // Before to change anything, stop and reset the reception of + // packets. + // + StopRx (STOP_RX_CLEAR, Snp); + + // + // Write the mask of the selected hash values for the multicast filterin= g. + // The two masks are set to zero if the multicast filtering is not enabl= ed. + // + IndirectMACWrite32 (INDIRECT_MAC_INDEX_HASHL, MultHashTableLow); + IndirectMACWrite32 (INDIRECT_MAC_INDEX_HASHH, MultHashTableHigh); + + ReceiveFilterSetting =3D (Mode->ReceiveFilterSetting | Enable) & (~Disab= le); + + // + // Read MAC controller + // + MacCSRValue =3D IndirectMACRead32 (INDIRECT_MAC_INDEX_CR); + MacCSRValue &=3D ~(MACCR_HPFILT | MACCR_BCAST | MACCR_PRMS | MACCR_MCPAS= ); + + if (ReceiveFilterSetting & EFI_SIMPLE_NETWORK_RECEIVE_UNICAST) { + Lan9118SetMacAddress (&Mode->CurrentAddress, Snp); + DEBUG ((DEBUG_NET, "Allowing Unicast Frame Reception\n")); + } else { + // + // The Unicast packets do not have to be listen to, set the MAC + // address of the LAN9118 to be the "not configured" all zeroes + // ethernet MAC address. + // + ZeroMem (&ZeroMac, NET_ETHER_ADDR_LEN); + Lan9118SetMacAddress (&ZeroMac, Snp); + } + + if (ReceiveFilterSetting & EFI_SIMPLE_NETWORK_RECEIVE_MULTICAST) { + MacCSRValue |=3D MACCR_HPFILT; + DEBUG ((DEBUG_NET, "Allowing Multicast Frame Reception\n")); + } + + if (ReceiveFilterSetting & EFI_SIMPLE_NETWORK_RECEIVE_PROMISCUOUS_MULTIC= AST) { + MacCSRValue |=3D MACCR_MCPAS; + DEBUG ((DEBUG_NET, "Enabling Promiscuous Multicast Mode\n")); + } + + if ((ReceiveFilterSetting & EFI_SIMPLE_NETWORK_RECEIVE_BROADCAST) =3D=3D= 0) { + MacCSRValue |=3D MACCR_BCAST; + } else { + DEBUG ((DEBUG_NET, "Allowing Broadcast Frame Reception\n")); + } + + if (ReceiveFilterSetting & EFI_SIMPLE_NETWORK_RECEIVE_PROMISCUOUS) { + MacCSRValue |=3D MACCR_PRMS; + DEBUG ((DEBUG_NET, "Enabling Promiscuous Mode\n")); + } + + // + // Write the options to the MAC_CSR + // + IndirectMACWrite32 (INDIRECT_MAC_INDEX_CR, MacCSRValue); + + // + // If we have to retrieve something, start packet reception. + // + Mode->ReceiveFilterSetting =3D ReceiveFilterSetting; + if (ReceiveFilterSetting !=3D 0) { + StartRx (0, Snp); + } + + return EFI_SUCCESS; +} + +/** + Modify of reset the current station address + + @param[in] Snp A pointer to the EFI_SIMPLE_NETWORK_PROTOC= OL + instance. + @param[in] Reset Flag used to reset the station address to = the + LAN9118's permanent address. + @param[in] New New station address to be used for the net= work interface. + + @retval EFI_SUCCESS The LAN9118's station address was update= d. + @retval EFI_NOT_STARTED The LAN9118 has not been started. + @retval EFI_INVALID_PARAMETER One or more of the following conditions = is TRUE : + . The "New" station address is invalid. + . "Reset" is FALSE and "New" is NULL. + @retval EFI_DEVICE_ERROR The LAN9118 has been started but not ini= tialized. + +**/ +EFI_STATUS +EFIAPI +SnpStationAddress ( + IN EFI_SIMPLE_NETWORK_PROTOCOL *Snp, + IN BOOLEAN Reset, + IN EFI_MAC_ADDRESS *New +) +{ + UINT32 Count; + UINT8 PermAddr[NET_ETHER_ADDR_LEN]; + + DEBUG ((DEBUG_NET, "SnpStationAddress()\n")); + + // Check Snp instance + if (Snp =3D=3D NULL) { + return EFI_INVALID_PARAMETER; + } + + // Check that driver was started and initialised + if (Snp->Mode->State =3D=3D EfiSimpleNetworkStarted) { + DEBUG ((EFI_D_WARN, "Warning: LAN9118 Driver not initialized\n")); + return EFI_DEVICE_ERROR; + } else if (Snp->Mode->State =3D=3D EfiSimpleNetworkStopped) { + DEBUG ((EFI_D_WARN, "Warning: LAN9118 Driver in stopped state\n")); + return EFI_NOT_STARTED; + } + + // Get the Permanent MAC address if need reset + if (Reset) { + // Try using EEPROM first. Read the first byte of data from EEPROM at = the address 0x0 + if ((IndirectEEPROMRead32 (0) & 0xFF) =3D=3D EEPROM_EXTERNAL_SERIAL_EE= PROM) { + for (Count =3D 0; Count < NET_ETHER_ADDR_LEN; Count++) { + PermAddr[Count] =3D IndirectEEPROMRead32 (Count + 1); + } + New =3D (EFI_MAC_ADDRESS *) PermAddr; + Lan9118SetMacAddress ((EFI_MAC_ADDRESS *) PermAddr, Snp); + } else { + DEBUG ((EFI_D_ERROR, "LAN9118: Warning: No valid MAC address in EEPR= OM, using fallback\n")); + New =3D (EFI_MAC_ADDRESS*) (FixedPcdGet64 (PcdLan9118DefaultMacAddre= ss)); + } + } else { + // Otherwise use the specified new MAC address + if (New =3D=3D NULL) { + return EFI_INVALID_PARAMETER; + } + // + // If it is a multicast address, it is not valid. + // + if (New->Addr[0] & 0x01) { + return EFI_INVALID_PARAMETER; + } + } + + CopyMem (&Snp->Mode->CurrentAddress, New, NET_ETHER_ADDR_LEN); + + // + // If packet reception is currently activated, stop and reset it, + // set the new ethernet address and restart the packet reception. + // Otherwise, nothing to do, the MAC address will be updated in + // SnpReceiveFilters() when the UNICAST packet reception will be + // activated. + // + if (Snp->Mode->ReceiveFilterSetting !=3D 0) { + StopRx (STOP_RX_CLEAR, Snp); + Lan9118SetMacAddress (New, Snp); + StartRx (0, Snp); + } + + return EFI_SUCCESS; +} + +/* + * UEFI Statistics() function + * + */ +EFI_STATUS +EFIAPI +SnpStatistics ( + IN EFI_SIMPLE_NETWORK_PROTOCOL* Snp, + IN BOOLEAN Reset, + IN OUT UINTN *StatSize, + OUT EFI_NETWORK_STATISTICS *Statistics + ) +{ + LAN9118_DRIVER *LanDriver; + EFI_STATUS Status; + + LanDriver =3D INSTANCE_FROM_SNP_THIS (Snp); + + DEBUG ((DEBUG_NET, "SnpStatistics()\n")); + + // Check Snp instance + if (Snp =3D=3D NULL) { + return EFI_INVALID_PARAMETER; + } + + // Check that driver was started and initialised + if (Snp->Mode->State =3D=3D EfiSimpleNetworkStarted) { + DEBUG ((EFI_D_WARN, "Warning: LAN9118 Driver not initialized\n")); + return EFI_DEVICE_ERROR; + } else if (Snp->Mode->State =3D=3D EfiSimpleNetworkStopped) { + DEBUG ((EFI_D_WARN, "Warning: LAN9118 Driver in stopped state\n")); + return EFI_NOT_STARTED; + } + + // + // Do a reset if required. It is not clearly stated in the UEFI specific= ation + // whether the reset has to be done before to copy the statistics in "St= atictics" + // or after. It is a bit strange to do it before but that is what is exp= ected by + // the SCT test on Statistics() with reset : "0x3de76704,0x4bf5,0x42cd,0= x8c,0x89, + // 0x54,0x7e,0x4f,0xad,0x4f,0x24". + // + if (Reset) { + ZeroMem (&LanDriver->Stats, sizeof(EFI_NETWORK_STATISTICS)); + } + + Status =3D EFI_SUCCESS; + if (StatSize =3D=3D NULL) { + if (Statistics !=3D NULL) { + return EFI_INVALID_PARAMETER; + } + } else { + if (Statistics =3D=3D NULL) { + Status =3D EFI_BUFFER_TOO_SMALL; + } else { + // Fill in the statistics + CopyMem ( + Statistics, &LanDriver->Stats, + MIN (*StatSize, sizeof (EFI_NETWORK_STATISTICS)) + ); + if (*StatSize < sizeof (EFI_NETWORK_STATISTICS)) { + Status =3D EFI_BUFFER_TOO_SMALL; + } + } + *StatSize =3D sizeof (EFI_NETWORK_STATISTICS); + } + + return Status; +} + +/* + * UEFI MCastIPtoMAC() function + * + */ +EFI_STATUS +EFIAPI +SnpMcastIptoMac ( + IN EFI_SIMPLE_NETWORK_PROTOCOL* Snp, + IN BOOLEAN IsIpv6, + IN EFI_IP_ADDRESS *Ip, + OUT EFI_MAC_ADDRESS *McastMac + ) +{ + DEBUG ((DEBUG_NET, "SnpMcastIptoMac()\n")); + + // Check Snp instance + if (Snp =3D=3D NULL) { + return EFI_INVALID_PARAMETER; + } + + // Check that driver was started and initialised + if (Snp->Mode->State =3D=3D EfiSimpleNetworkStarted) { + DEBUG ((EFI_D_WARN, "Warning: LAN9118 Driver not initialized\n")); + return EFI_DEVICE_ERROR; + } else if (Snp->Mode->State =3D=3D EfiSimpleNetworkStopped) { + DEBUG ((EFI_D_WARN, "Warning: LAN9118 Driver in stopped state\n")); + return EFI_NOT_STARTED; + } + + // Check parameters + if ((McastMac =3D=3D NULL) || (Ip =3D=3D NULL)) { + return EFI_INVALID_PARAMETER; + } + + // Make sure MAC address is empty + ZeroMem (McastMac, sizeof(EFI_MAC_ADDRESS)); + + // If we need ipv4 address + if (!IsIpv6) { + // Most significant 25 bits of a multicast HW address are set. + // 01-00-5E is the IPv4 Ethernet Multicast Address (see RFC 1112) + McastMac->Addr[0] =3D 0x01; + McastMac->Addr[1] =3D 0x00; + McastMac->Addr[2] =3D 0x5E; + + // Lower 23 bits from ipv4 address + McastMac->Addr[3] =3D (Ip->v4.Addr[1] & 0x7F); // Clear the most signi= ficant bit (25th bit of MAC must be 0) + McastMac->Addr[4] =3D Ip->v4.Addr[2]; + McastMac->Addr[5] =3D Ip->v4.Addr[3]; + } else { + // Most significant 16 bits of multicast v6 HW address are set + // 33-33 is the IPv6 Ethernet Multicast Address (see RFC 2464) + McastMac->Addr[0] =3D 0x33; + McastMac->Addr[1] =3D 0x33; + + // lower four octets are taken from ipv6 address + McastMac->Addr[2] =3D Ip->v6.Addr[8]; + McastMac->Addr[3] =3D Ip->v6.Addr[9]; + McastMac->Addr[4] =3D Ip->v6.Addr[10]; + McastMac->Addr[5] =3D Ip->v6.Addr[11]; + } + + return EFI_SUCCESS; +} + +/* + * UEFI NvData() function + * + */ +EFI_STATUS +EFIAPI +SnpNvData ( + IN EFI_SIMPLE_NETWORK_PROTOCOL* pobj, + IN BOOLEAN read_write, + IN UINTN offset, + IN UINTN buff_size, + IN OUT VOID *data + ) +{ + DEBUG ((DEBUG_NET, "SnpNvData()\n")); + + return EFI_UNSUPPORTED; +} + + +/* + * UEFI GetStatus () function + * + */ +EFI_STATUS +EFIAPI +SnpGetStatus ( + IN EFI_SIMPLE_NETWORK_PROTOCOL *Snp, + OUT UINT32 *IrqStat OPTIONAL, + OUT VOID **TxBuff OPTIONAL + ) +{ + UINT32 FifoInt; + EFI_STATUS Status; + UINTN NumTxStatusEntries; + UINT32 TxStatus; + UINT16 PacketTag; + UINT32 Interrupts; + LAN9118_DRIVER *LanDriver; + + LanDriver =3D INSTANCE_FROM_SNP_THIS (Snp); + + // Check preliminaries + if (Snp =3D=3D NULL) { + return EFI_INVALID_PARAMETER; + } + + // Check that driver was started and initialised + if (Snp->Mode->State =3D=3D EfiSimpleNetworkStarted) { + DEBUG ((EFI_D_WARN, "Warning: LAN9118 Driver not initialized\n")); + return EFI_DEVICE_ERROR; + } else if (Snp->Mode->State =3D=3D EfiSimpleNetworkStopped) { + DEBUG ((EFI_D_WARN, "Warning: LAN9118 Driver in stopped state\n")); + return EFI_NOT_STARTED; + } + + // Check and acknowledge TX Status interrupt (this will happen if the + // consumer of SNP does not call GetStatus.) + // TODO will we lose TxStatuses if this happens? Maybe in SnpTransmit we + // should check for it and dump the TX Status FIFO. + FifoInt =3D Lan9118MmioRead32 (LAN9118_FIFO_INT); + + // Clear the TX Status FIFO Overflow + if ((FifoInt & INSTS_TXSO) =3D=3D 0) { + FifoInt |=3D INSTS_TXSO; + Lan9118MmioWrite32 (LAN9118_FIFO_INT, FifoInt); + } + + // Read interrupt status if IrqStat is not NULL + if (IrqStat !=3D NULL) { + *IrqStat =3D 0; + + // Check for receive interrupt + if (Lan9118MmioRead32 (LAN9118_INT_STS) & INSTS_RSFL) { // Data moved = from rx FIFO + *IrqStat |=3D EFI_SIMPLE_NETWORK_RECEIVE_INTERRUPT; + Lan9118MmioWrite32 (LAN9118_INT_STS,INSTS_RSFL); + } + + // Check for transmit interrupt + if (Lan9118MmioRead32 (LAN9118_INT_STS) & INSTS_TSFL) { + *IrqStat |=3D EFI_SIMPLE_NETWORK_TRANSMIT_INTERRUPT; + Lan9118MmioWrite32 (LAN9118_INT_STS,INSTS_TSFL); + } + + // Check for software interrupt + if (Lan9118MmioRead32 (LAN9118_INT_STS) & INSTS_SW_INT) { + *IrqStat |=3D EFI_SIMPLE_NETWORK_SOFTWARE_INTERRUPT; + Lan9118MmioWrite32 (LAN9118_INT_STS,INSTS_SW_INT); + } + } + + // Check Status of transmitted packets + // (We ignore TXSTATUS_NO_CA has it might happen in Full Duplex) + + NumTxStatusEntries =3D Lan9118MmioRead32(LAN9118_TX_FIFO_INF) & TXFIFOIN= F_TXSUSED_MASK; + if (NumTxStatusEntries > 0) { + TxStatus =3D Lan9118MmioRead32 (LAN9118_TX_STATUS); + PacketTag =3D TxStatus >> 16; + TxStatus =3D TxStatus & 0xFFFF; + if ((TxStatus & TXSTATUS_ES) && (TxStatus !=3D (TXSTATUS_ES | TXSTATUS= _NO_CA))) { + DEBUG ((EFI_D_ERROR, "LAN9118: There was an error transmitting. TxSt= atus=3D0x%08x:", TxStatus)); + if (TxStatus & TXSTATUS_NO_CA) { + DEBUG ((EFI_D_ERROR, "- No carrier\n")); + } + if (TxStatus & TXSTATUS_DEF) { + DEBUG ((EFI_D_ERROR, "- Packet tx was deferred\n")); + } + if (TxStatus & TXSTATUS_EDEF) { + DEBUG ((EFI_D_ERROR, "- Tx ended because of excessive deferral\n")= ); + } + if (TxStatus & TXSTATUS_ECOLL) { + DEBUG ((EFI_D_ERROR, "- Tx ended because of Excessive Collisions\n= ")); + } + if (TxStatus & TXSTATUS_LCOLL) { + DEBUG ((EFI_D_ERROR, "- Packet Tx aborted after coll window of 64 = bytes\n")); + } + if (TxStatus & TXSTATUS_LOST_CA) { + DEBUG ((EFI_D_ERROR, "- Lost carrier during Tx\n")); + } + return EFI_DEVICE_ERROR; + } else if (TxBuff !=3D NULL) { + LanDriver->Stats.TxTotalFrames +=3D 1; + *TxBuff =3D LanDriver->TxRing[PacketTag % LAN9118_TX_RING_NUM_ENTRIE= S]; + } + } else if (TxBuff !=3D NULL) { + *TxBuff =3D NULL; + } + + // Check for a TX Error interrupt + Interrupts =3D Lan9118MmioRead32 (LAN9118_INT_STS); + if (Interrupts & INSTS_TXE) { + DEBUG ((EFI_D_ERROR, "LAN9118: Transmitter error. Restarting...")); + + // Software reset, the TXE interrupt is cleared by the reset. + Status =3D SoftReset (0, Snp); + if (EFI_ERROR (Status)) { + DEBUG ((EFI_D_ERROR, "\n\tSoft Reset Failed: Hardware Error\n")); + return EFI_DEVICE_ERROR; + } + + // Reactivate the LEDs + Status =3D ConfigureHardware (HW_CONF_USE_LEDS, Snp); + if (EFI_ERROR (Status)) { + return Status; + } + + // + // Restart the transmitter and if necessary the receiver. + // Do not ask for FIFO reset as it has already been done + // by SoftReset(). + // + StartTx (START_TX_MAC | START_TX_CFG, Snp); + if (Snp->Mode->ReceiveFilterSetting !=3D 0) { + StartRx (0, Snp); + } + } + + // Update the media status + Status =3D CheckLinkStatus (0, Snp); + if (EFI_ERROR(Status)) { + Snp->Mode->MediaPresent =3D FALSE; + } else { + Snp->Mode->MediaPresent =3D TRUE; + } + + return EFI_SUCCESS; +} + + +/* + * UEFI Transmit() function + * + */ +EFI_STATUS +EFIAPI +SnpTransmit ( + IN EFI_SIMPLE_NETWORK_PROTOCOL *Snp, + IN UINTN HdrSize, + IN UINTN BuffSize, + IN VOID* Data, + IN EFI_MAC_ADDRESS *SrcAddr OPTIONAL, + IN EFI_MAC_ADDRESS *DstAddr OPTIONAL, + IN UINT16 *Protocol OPTIONAL + ) +{ + LAN9118_DRIVER *LanDriver; + UINT32 TxFreeSpace; + UINT32 TxStatusSpace; + INT32 Count; + UINT32 CommandA; + UINT32 CommandB; + UINT16 LocalProtocol; + UINT32 *LocalData; + UINT16 PacketTag; + +#if defined(EVAL_PERFORMANCE) + UINT64 Perf; + UINT64 StartClock; + UINT64 EndClock; + + Perf =3D GetPerformanceCounterProperties (NULL, NULL); + StartClock =3D GetPerformanceCounter (); +#endif + + LanDriver =3D INSTANCE_FROM_SNP_THIS (Snp); + + // Check preliminaries + if ((Snp =3D=3D NULL) || (Data =3D=3D NULL)) { + return EFI_INVALID_PARAMETER; + } + + // Check that driver was started and initialised + if (Snp->Mode->State =3D=3D EfiSimpleNetworkStarted) { + DEBUG ((EFI_D_WARN, "Warning: LAN9118 Driver not initialized\n")); + return EFI_DEVICE_ERROR; + } else if (Snp->Mode->State =3D=3D EfiSimpleNetworkStopped) { + DEBUG ((EFI_D_WARN, "Warning: LAN9118 Driver in stopped state\n")); + return EFI_NOT_STARTED; + } + + // Ensure header is correct size if non-zero + if (HdrSize) { + if (HdrSize !=3D Snp->Mode->MediaHeaderSize) { + return EFI_INVALID_PARAMETER; + } + + if ((DstAddr =3D=3D NULL) || (Protocol =3D=3D NULL)) { + return EFI_INVALID_PARAMETER; + } + } + + // + // Check validity of BufferSize + // + if (BuffSize < Snp->Mode->MediaHeaderSize) { + return EFI_BUFFER_TOO_SMALL; + } + + // Before transmitting check the link status + /*if (CheckLinkStatus (0, Snp) < 0) { + return EFI_NOT_READY; + }*/ + + // Get DATA FIFO free space in bytes + TxFreeSpace =3D TxDataFreeSpace (0, Snp); + if (TxFreeSpace < BuffSize) { + return EFI_NOT_READY; + } + + // Get STATUS FIFO used space in bytes + TxStatusSpace =3D TxStatusUsedSpace (0, Snp); + if (TxStatusSpace > 500) { + return EFI_NOT_READY; + } + + // If DstAddr is not provided, get it from Buffer (we trust that the cal= ler + // has provided a well-formed frame). + if (DstAddr =3D=3D NULL) { + DstAddr =3D (EFI_MAC_ADDRESS *) Data; + } + + // Check for the nature of the frame + if ((DstAddr->Addr[0] & 0x1) =3D=3D 1) { + LanDriver->Stats.TxMulticastFrames +=3D 1; + } else { + LanDriver->Stats.TxUnicastFrames +=3D 1; + } + + // Check if broadcast + if (DstAddr->Addr[0] =3D=3D 0xFF) { + LanDriver->Stats.TxBroadcastFrames +=3D 1; + } + + PacketTag =3D LanDriver->NextPacketTag; + LanDriver->NextPacketTag++; + + if (HdrSize) { + + // Format pointer + LocalData =3D (UINT32*) Data; + LocalProtocol =3D *Protocol; + + // Create first buffer to pass to controller (for the header) + CommandA =3D TX_CMD_A_FIRST_SEGMENT | TX_CMD_A_BUFF_SIZE (HdrSize); + CommandB =3D TX_CMD_B_PACKET_TAG (PacketTag) | TX_CMD_B_PACKET_LENGTH = (BuffSize); + + // Write the commands first + Lan9118MmioWrite32 (LAN9118_TX_DATA, CommandA); + Lan9118MmioWrite32 (LAN9118_TX_DATA, CommandB); + + // Write the destination address + Lan9118MmioWrite32 (LAN9118_TX_DATA, + (DstAddr->Addr[0]) | + (DstAddr->Addr[1] << 8) | + (DstAddr->Addr[2] << 16) | + (DstAddr->Addr[3] << 24) + ); + + Lan9118MmioWrite32 (LAN9118_TX_DATA, + (DstAddr->Addr[4]) | + (DstAddr->Addr[5] << 8) | + (SrcAddr->Addr[0] << 16) | // Write the Source Address + (SrcAddr->Addr[1] << 24) + ); + + Lan9118MmioWrite32 (LAN9118_TX_DATA, + (SrcAddr->Addr[2]) | + (SrcAddr->Addr[3] << 8) | + (SrcAddr->Addr[4] << 16) | + (SrcAddr->Addr[5] << 24) + ); + + // Write the Protocol + Lan9118MmioWrite32 (LAN9118_TX_DATA, (UINT32)(HTONS (LocalProtocol))); + + // Next buffer is the payload + CommandA =3D TX_CMD_A_LAST_SEGMENT | TX_CMD_A_BUFF_SIZE (BuffSize - Hd= rSize) | TX_CMD_A_COMPLETION_INT | TX_CMD_A_DATA_START_OFFSET (2); // 2 byt= es beginning offset + + // Write the commands + Lan9118MmioWrite32 (LAN9118_TX_DATA, CommandA); + Lan9118MmioWrite32 (LAN9118_TX_DATA, CommandB); + + // Write the payload + for (Count =3D 0; Count < ((BuffSize + 3) >> 2) - 3; Count++) { + Lan9118MmioWrite32 (LAN9118_TX_DATA, LocalData[Count + 3]); + } + } else { + // Format pointer + LocalData =3D (UINT32*) Data; + + // Create a buffer to pass to controller + CommandA =3D TX_CMD_A_FIRST_SEGMENT | TX_CMD_A_LAST_SEGMENT | TX_CMD_A= _BUFF_SIZE (BuffSize) | TX_CMD_A_COMPLETION_INT; + CommandB =3D TX_CMD_B_PACKET_TAG (PacketTag) | TX_CMD_B_PACKET_LENGTH = (BuffSize); + + // Write the commands first + Lan9118MmioWrite32 (LAN9118_TX_DATA, CommandA); + Lan9118MmioWrite32 (LAN9118_TX_DATA, CommandB); + + // Write all the data + for (Count =3D 0; Count < ((BuffSize + 3) >> 2); Count++) { + Lan9118MmioWrite32 (LAN9118_TX_DATA, LocalData[Count]); + } + } + + // Save the address of the submitted packet so we can notify the consume= r that + // it has been sent in GetStatus. When the packet tag appears in the Tx = Status + // Fifo, we will return Buffer in the TxBuff parameter of GetStatus. + LanDriver->TxRing[PacketTag % LAN9118_TX_RING_NUM_ENTRIES] =3D Data; + +#if defined(EVAL_PERFORMANCE) + EndClock =3D GetPerformanceCounter (); + DEBUG ((EFI_D_ERROR, "Time processing: %d counts @ %d Hz\n", StartClock = - EndClock,Perf)); +#endif + + LanDriver->Stats.TxGoodFrames +=3D 1; + + return EFI_SUCCESS; +} + + +/* + * UEFI Receive() function + * + */ +EFI_STATUS +EFIAPI +SnpReceive ( + IN EFI_SIMPLE_NETWORK_PROTOCOL* Snp, + OUT UINTN *HdrSize OPTIONAL, + IN OUT UINTN *BuffSize, + OUT VOID *Data, + OUT EFI_MAC_ADDRESS *SrcAddr OPTIONAL, + OUT EFI_MAC_ADDRESS *DstAddr OPTIONAL, + OUT UINT16 *Protocol OPTIONAL + ) +{ + LAN9118_DRIVER *LanDriver; + UINT32 IntSts; + UINT32 RxFifoStatus; + UINT32 NumPackets; + UINT32 RxCfgValue; + UINT32 PLength; // Packet length + UINT32 ReadLimit; + UINT32 Count; + UINT32 Padding; + UINT32 *RawData; + EFI_MAC_ADDRESS Dst; + EFI_MAC_ADDRESS Src; + UINTN DroppedFrames; + EFI_STATUS Status; + + LanDriver =3D INSTANCE_FROM_SNP_THIS (Snp); + +#if defined(EVAL_PERFORMANCE) + UINT64 Perf =3D GetPerformanceCounterProperties (NULL, NULL); + UINT64 StartClock =3D GetPerformanceCounter (); +#endif + + // Check preliminaries + if ((Snp =3D=3D NULL) || (Data =3D=3D NULL) || (BuffSize =3D=3D NULL)) { + return EFI_INVALID_PARAMETER; + } + + // Check that driver was started and initialised + if (Snp->Mode->State =3D=3D EfiSimpleNetworkStarted) { + DEBUG ((EFI_D_WARN, "Warning: LAN9118 Driver not initialized\n")); + return EFI_DEVICE_ERROR; + } else if (Snp->Mode->State =3D=3D EfiSimpleNetworkStopped) { + DEBUG ((EFI_D_WARN, "Warning: LAN9118 Driver in stopped state\n")); + return EFI_NOT_STARTED; + } + + // + // If the receiver raised the RXE error bit, check if the receiver status + // FIFO is full and if not just acknowledge the error. The two other + // conditions to get a RXE error are : + // . the RX data FIFO is read whereas being empty. + // . the RX status FIFO is read whereas being empty. + // The RX data and status FIFO are read by this driver only in the follo= wing + // code of this function. After the readings, the RXE error bit is check= ed + // and if raised, the controller is reset. Thus, at this point, we consi= der + // that the only valid reason to get an RXE error is the receiver status + // FIFO being full. And if this is not the case, we consider that this is + // a spurious error and we just get rid of it. We experienced such 'spur= ious' + // errors when running the driver on an A57 on Juno. No valid reason to + // explain those errors has been found so far and everything seems to + // work perfectly when they are just ignored. + // + IntSts =3D Lan9118MmioRead32 (LAN9118_INT_STS); + if ((IntSts & INSTS_RXE) && (!(IntSts & INSTS_RSFF))) { + Lan9118MmioWrite32 (LAN9118_INT_STS, INSTS_RXE); + } + + // Count dropped frames + DroppedFrames =3D Lan9118MmioRead32 (LAN9118_RX_DROP); + LanDriver->Stats.RxDroppedFrames +=3D DroppedFrames; + + NumPackets =3D RxStatusUsedSpace (0, Snp) / 4; + if (!NumPackets) { + return EFI_NOT_READY; + } + + // Read Rx Status (only if not empty) + RxFifoStatus =3D Lan9118MmioRead32 (LAN9118_RX_STATUS); + LanDriver->Stats.RxTotalFrames +=3D 1; + + // First check for errors + if ((RxFifoStatus & RXSTATUS_MII_ERROR) || + (RxFifoStatus & RXSTATUS_RXW_TO) || + (RxFifoStatus & RXSTATUS_FTL) || + (RxFifoStatus & RXSTATUS_LCOLL) || + (RxFifoStatus & RXSTATUS_LE) || + (RxFifoStatus & RXSTATUS_DB)) + { + DEBUG ((EFI_D_WARN, "Warning: There was an error on frame reception.\n= ")); + return EFI_DEVICE_ERROR; + } + + // Check if we got a CRC error + if (RxFifoStatus & RXSTATUS_CRC_ERROR) { + DEBUG ((EFI_D_WARN, "Warning: Crc Error\n")); + LanDriver->Stats.RxCrcErrorFrames +=3D 1; + LanDriver->Stats.RxDroppedFrames +=3D 1; + return EFI_DEVICE_ERROR; + } + + // Check if we got a runt frame + if (RxFifoStatus & RXSTATUS_RUNT) { + DEBUG ((EFI_D_WARN, "Warning: Runt Frame\n")); + LanDriver->Stats.RxUndersizeFrames +=3D 1; + LanDriver->Stats.RxDroppedFrames +=3D 1; + return EFI_DEVICE_ERROR; + } + + // Check filtering status for this packet + if (RxFifoStatus & RXSTATUS_FILT_FAIL) { + DEBUG ((EFI_D_WARN, "Warning: Frame Failed Filtering\n")); + // fast forward? + } + + // Check if we got a broadcast frame + if (RxFifoStatus & RXSTATUS_BCF) { + LanDriver->Stats.RxBroadcastFrames +=3D 1; + } + + // Check if we got a multicast frame + if (RxFifoStatus & RXSTATUS_MCF) { + LanDriver->Stats.RxMulticastFrames +=3D 1; + } + + // Check if we got a unicast frame + if ((RxFifoStatus & RXSTATUS_BCF) && ((RxFifoStatus & RXSTATUS_MCF) =3D= =3D 0)) { + LanDriver->Stats.RxUnicastFrames +=3D 1; + } + + // Get the received packet length + PLength =3D GET_RXSTATUS_PACKET_LENGTH(RxFifoStatus); + LanDriver->Stats.RxTotalBytes +=3D (PLength - 4); + + // If padding is applied, read more DWORDs + if (PLength % 4) { + Padding =3D 4 - (PLength % 4); + ReadLimit =3D (PLength + Padding)/4; + } else { + ReadLimit =3D PLength/4; + Padding =3D 0; + } + + // Check buffer size + if (*BuffSize < (PLength + Padding)) { + *BuffSize =3D PLength + Padding; + return EFI_BUFFER_TOO_SMALL; + } + + // Set the amount of data to be transferred out of FIFO for THIS packet + // This can be used to trigger an interrupt, and status can be checked + RxCfgValue =3D Lan9118MmioRead32 (LAN9118_RX_CFG); + RxCfgValue &=3D ~(RXCFG_RX_DMA_CNT_MASK); + RxCfgValue |=3D RXCFG_RX_DMA_CNT (ReadLimit); + + // Set end alignment to 4-bytes + RxCfgValue &=3D ~(RXCFG_RX_END_ALIGN_MASK); + Lan9118MmioWrite32 (LAN9118_RX_CFG, RxCfgValue); + + // Update buffer size + *BuffSize =3D PLength; // -4 bytes may be needed: Received in buffer as + // 4 bytes longer than packet actually is, unless + // packet is < 64 bytes + + if (HdrSize !=3D NULL) + *HdrSize =3D Snp->Mode->MediaHeaderSize; + + // Format the pointer + RawData =3D (UINT32*)Data; + + // Read Rx Packet + for (Count =3D 0; Count < ReadLimit; Count++) { + RawData[Count] =3D Lan9118MmioRead32 (LAN9118_RX_DATA); + } + + // Get the destination address + if (DstAddr !=3D NULL) { + Dst.Addr[0] =3D (RawData[0] & 0xFF); + Dst.Addr[1] =3D (RawData[0] & 0xFF00) >> 8; + Dst.Addr[2] =3D (RawData[0] & 0xFF0000) >> 16; + Dst.Addr[3] =3D (RawData[0] & 0xFF000000) >> 24; + Dst.Addr[4] =3D (RawData[1] & 0xFF); + Dst.Addr[5] =3D (RawData[1] & 0xFF00) >> 8; + CopyMem (DstAddr, &Dst, NET_ETHER_ADDR_LEN); + } + + // Get the source address + if (SrcAddr !=3D NULL) { + Src.Addr[0] =3D (RawData[1] & 0xFF0000) >> 16; + Src.Addr[1] =3D (RawData[1] & 0xFF000000) >> 24; + Src.Addr[2] =3D (RawData[2] & 0xFF); + Src.Addr[3] =3D (RawData[2] & 0xFF00) >> 8; + Src.Addr[4] =3D (RawData[2] & 0xFF0000) >> 16; + Src.Addr[5] =3D (RawData[2] & 0xFF000000) >> 24; + CopyMem (SrcAddr, &Src, NET_ETHER_ADDR_LEN); + } + + // Get the protocol + if (Protocol !=3D NULL) { + *Protocol =3D NTOHS (RawData[3] & 0xFFFF); + } + + // Check for Rx errors (worst possible error) + if (Lan9118MmioRead32 (LAN9118_INT_STS) & INSTS_RXE) { + DEBUG ((EFI_D_WARN, "Warning: Receiver Error. Restarting...\n")); + + // Software reset, the RXE interrupt is cleared by the reset. + Status =3D SoftReset (0, Snp); + if (EFI_ERROR (Status)) { + DEBUG ((EFI_D_ERROR, "Error: Soft Reset Failed: Hardware Error.\n")); + return EFI_DEVICE_ERROR; + } + + // Reactivate the LEDs + Status =3D ConfigureHardware (HW_CONF_USE_LEDS, Snp); + if (EFI_ERROR (Status)) { + return Status; + } + + // + // Restart the receiver and the transmitter without resetting the FIFOs + // as it has been done by SoftReset(). + // + StartRx (0, Snp); + StartTx (START_TX_MAC | START_TX_CFG, Snp); + + // Say that command could not be sent + return EFI_DEVICE_ERROR; + } + +#if defined(EVAL_PERFORMANCE) + UINT64 EndClock =3D GetPerformanceCounter (); + DEBUG ((EFI_D_ERROR, "Receive Time processing: %d counts @ %d Hz\n", Sta= rtClock - EndClock,Perf)); +#endif + + LanDriver->Stats.RxGoodFrames +=3D 1; + + return EFI_SUCCESS; +} diff --git a/Platform/ARM/VExpressPkg/Drivers/Lan9118Dxe/Lan9118Dxe.h b/Pla= tform/ARM/VExpressPkg/Drivers/Lan9118Dxe/Lan9118Dxe.h new file mode 100644 index 000000000000..edc106a1df1b --- /dev/null +++ b/Platform/ARM/VExpressPkg/Drivers/Lan9118Dxe/Lan9118Dxe.h @@ -0,0 +1,304 @@ +/** @file +* +* WARNING: +* This driver fails to follow the UEFI driver model without a good +* reason, and only remains in the tree because it is still used by +* a small number of platforms. It will be removed when no longer used. +* New platforms should not use it, and no one should use this as +* reference code for developing new drivers. +* +* Copyright (c) 2012-2014, ARM Limited. All rights reserved. +* +* SPDX-License-Identifier: BSD-2-Clause-Patent +* +**/ + +#ifndef __LAN9118_DXE_H__ +#define __LAN9118_DXE_H__ + +#include +#include +#include + +// Protocols used by this driver +#include +#include +#include +#include + +// Libraries used by this driver +#include +#include +#include +#include +#include +#include +#include +#include + +#include "Lan9118DxeUtil.h" +#include "Lan9118DxeHw.h" + +#define LAN9118_STALL 2 + +#define LAN9118_DEFAULT_MAC_ADDRL 0x00F70200 +#define LAN9118_DEFAULT_MAC_ADDRH 0x00009040 + +#define LAN9118_TX_DATA_SIZE 4608 +#define LAN9118_TX_STATUS_SIZE 512 +#define LAN9118_RX_DATA_SIZE 10560 +#define LAN9118_RX_STATUS_SIZE 704 + +#define LAN9118_TX_RING_NUM_ENTRIES 32 + +/*------------------------------------------------------------------------= ------ + LAN9118 Information Structure +--------------------------------------------------------------------------= ----*/ + +typedef struct { + // Driver signature + UINT32 Signature; + EFI_HANDLE ControllerHandle; + + // EFI SNP protocol instances + EFI_SIMPLE_NETWORK_PROTOCOL Snp; + EFI_SIMPLE_NETWORK_MODE SnpMode; + + // EFI Snp statistics instance + EFI_NETWORK_STATISTICS Stats; + + // Saved transmitted buffers so we can notify consumers when packets hav= e been sent. + UINT16 NextPacketTag; + VOID *TxRing[LAN9118_TX_RING_NUM_ENTRIES]; +} LAN9118_DRIVER; + +#define LAN9118_SIGNATURE SIGNATURE_32('l', 'a', 'n'= , '9') +#define INSTANCE_FROM_SNP_THIS(a) CR(a, LAN9118_DRIVER, Snp,= LAN9118_SIGNATURE) + + +/*------------------------------------------------------------------------= --------------------------------------------- + + UEFI-Compliant functions for EFI_SIMPLE_NETWORK_PROTOCOL + + Refer to the Simple Network Protocol section (21.1) in the UEFI 2.3.1 Sp= ecification for related definitions + +--------------------------------------------------------------------------= -------------------------------------------*/ + + +/* + * UEFI Start() function + * + * Parameters: + * + * @param pobj: A pointer to the EFI_SIMPLE_NETWORK_PROTOCOL instance. + * + * Description: + * + * This function starts a network interface. If the network interface suc= cessfully starts, then + * EFI_SUCCESS will be returned. + */ +EFI_STATUS +EFIAPI +SnpStart ( + IN EFI_SIMPLE_NETWORK_PROTOCOL* Snp + ); + +/* + * UEFI Stop() function + * + */ +EFI_STATUS +EFIAPI +SnpStop ( + IN EFI_SIMPLE_NETWORK_PROTOCOL* Snp + ); + +/* + * UEFI Initialize() function + * + */ +EFI_STATUS +EFIAPI +SnpInitialize ( + IN EFI_SIMPLE_NETWORK_PROTOCOL* Snp, + IN UINTN rx_buff_size, + IN UINTN tx_buff_size + ); + +/* + * UEFI Reset() function + * + */ +EFI_STATUS +EFIAPI +SnpReset ( + IN EFI_SIMPLE_NETWORK_PROTOCOL* Snp, + IN BOOLEAN ext_ver + ); + +/* + * UEFI Shutdown() function + * + */ +EFI_STATUS +EFIAPI +SnpShutdown ( + IN EFI_SIMPLE_NETWORK_PROTOCOL* Snp + ); + +/* + * UEFI ReceiveFilters() function + * + */ +EFI_STATUS +EFIAPI +SnpReceiveFilters ( + IN EFI_SIMPLE_NETWORK_PROTOCOL* Snp, + IN UINT32 enable, + IN UINT32 disable, + IN BOOLEAN reset_mfilter, + IN UINTN num_mfilter, + IN EFI_MAC_ADDRESS *mfilter + ); + +/* + * UEFI StationAddress() function + * + */ +EFI_STATUS +EFIAPI +SnpStationAddress ( + IN EFI_SIMPLE_NETWORK_PROTOCOL* Snp, + IN BOOLEAN reset, + IN EFI_MAC_ADDRESS *new_maddr + ); + +/* + * UEFI Statistics() function + * + */ +EFI_STATUS +EFIAPI +SnpStatistics ( + IN EFI_SIMPLE_NETWORK_PROTOCOL* Snp, + IN BOOLEAN reset, + IN OUT UINTN *stat_size, + OUT EFI_NETWORK_STATISTICS *stat_table + ); + +/* + * UEFI MCastIPtoMAC() function + * + */ +EFI_STATUS +EFIAPI +SnpMcastIptoMac ( + IN EFI_SIMPLE_NETWORK_PROTOCOL* Snp, + IN BOOLEAN use_ipv6, + IN EFI_IP_ADDRESS *ip_addr, + OUT EFI_MAC_ADDRESS *mac_addr + ); + +/* + * UEFI NvData() function + * + */ +EFI_STATUS +EFIAPI +SnpNvData ( + IN EFI_SIMPLE_NETWORK_PROTOCOL* Snp, + IN BOOLEAN read_write, + IN UINTN offset, + IN UINTN buff_size, + IN OUT VOID *data + ); + +/* + * UEFI GetStatus() function + * + */ +EFI_STATUS +EFIAPI +SnpGetStatus ( + IN EFI_SIMPLE_NETWORK_PROTOCOL* Snp, + OUT UINT32 *irq_stat OPTIONAL, + OUT VOID **tx_buff OPTIONAL + ); + +/* + * UEFI Transmit() function + * + */ +EFI_STATUS +EFIAPI +SnpTransmit ( + IN EFI_SIMPLE_NETWORK_PROTOCOL* Snp, + IN UINTN hdr_size, + IN UINTN buff_size, + IN VOID *data, + IN EFI_MAC_ADDRESS *src_addr OPTIONAL, + IN EFI_MAC_ADDRESS *dest_addr OPTIONAL, + IN UINT16 *protocol OPTIONAL + ); + +/* + * UEFI Receive() function + * + */ +EFI_STATUS +EFIAPI +SnpReceive ( + IN EFI_SIMPLE_NETWORK_PROTOCOL* Snp, + OUT UINTN *hdr_size OPTIONAL, + IN OUT UINTN *buff_size, + OUT VOID *data, + OUT EFI_MAC_ADDRESS *src_addr OPTIONAL, + OUT EFI_MAC_ADDRESS *dest_addr OPTIONAL, + OUT UINT16 *protocol OPTIONAL + ); + + +/*------------------------------------------------------------------------= --------------------------------------------- + + UEFI-Compliant functions for EFI_COMPONENT_NAME2_PROTOCOL + + Refer to the Component Name Protocol section (10.5) in the UEFI 2.3.1 Sp= ecification for related definitions + +--------------------------------------------------------------------------= -------------------------------------------*/ + +/* + * UEFI GetDriverName() function + * + */ +EFI_STATUS +EFIAPI +SnpGetDriverName ( + IN EFI_COMPONENT_NAME2_PROTOCOL *Snp, + IN CHAR8 *Lang, + OUT CHAR16 **DriverName + ); + +/* + * UEFI GetControllerName() function + * + */ +EFI_STATUS +EFIAPI +SnpGetControllerName ( + IN EFI_COMPONENT_NAME2_PROTOCOL *Cnp, + IN EFI_HANDLE ControllerHandle, + IN EFI_HANDLE ChildHandle OPTIONAL, + IN CHAR8 *Lang, + OUT CHAR16 **ControllerName + ); + +/*------------------------------------------------------------------------= ------ + Utility functions +--------------------------------------------------------------------------= ----*/ + +EFI_MAC_ADDRESS +GetCurrentMacAddress ( + VOID + ); + +#endif // __LAN9118_DXE_H__ diff --git a/Platform/ARM/VExpressPkg/Drivers/Lan9118Dxe/Lan9118Dxe.inf b/P= latform/ARM/VExpressPkg/Drivers/Lan9118Dxe/Lan9118Dxe.inf new file mode 100644 index 000000000000..b289f80c35a5 --- /dev/null +++ b/Platform/ARM/VExpressPkg/Drivers/Lan9118Dxe/Lan9118Dxe.inf @@ -0,0 +1,58 @@ +#/** @file +# INF file for the LAN9118 Network Controller Driver. +# +# WARNING: +# This driver fails to follow the UEFI driver model without a good +# reason, and only remains in the tree because it is still used by +# a small number of platforms. It will be removed when no longer used. +# New platforms should not use it, and no one should use this as +# reference code for developing new drivers. +# +# Copyright (c) 2012-2015, ARM Limited. All rights reserved. +# +# SPDX-License-Identifier: BSD-2-Clause-Patent +# +#**/ + +[Defines] + INF_VERSION =3D 0x00010006 + BASE_NAME =3D Lan9118Dxe + FILE_GUID =3D 4356b162-d0b2-11e1-8952-4437e6a60ea5 + MODULE_TYPE =3D DXE_DRIVER + VERSION_STRING =3D 0.1 + ENTRY_POINT =3D Lan9118DxeEntry + +[Sources.common] + Lan9118Dxe.c + Lan9118DxeUtil.c + Lan9118Dxe.h + +[Packages] + NetworkPkg/NetworkPkg.dec + MdeModulePkg/MdeModulePkg.dec + MdePkg/MdePkg.dec + Platform/ARM/VExpressPkg/ArmVExpressPkg.dec + +[LibraryClasses] + BaseLib + UefiLib + NetLib + UefiDriverEntryPoint + BaseMemoryLib + IoLib + DevicePathLib + +[Protocols] + gEfiSimpleNetworkProtocolGuid + gEfiMetronomeArchProtocolGuid + gEfiPxeBaseCodeProtocolGuid + gEfiDevicePathProtocolGuid + +[FixedPcd] + gArmVExpressTokenSpaceGuid.PcdLan9118DxeBaseAddress + gArmVExpressTokenSpaceGuid.PcdLan9118DefaultMacAddress + gArmVExpressTokenSpaceGuid.PcdLan9118DefaultNegotiationTimeout + gArmVExpressTokenSpaceGuid.PcdLan9118NegotiationFeatureMask + +[Depex] + TRUE diff --git a/Platform/ARM/VExpressPkg/Drivers/Lan9118Dxe/Lan9118DxeHw.h b/P= latform/ARM/VExpressPkg/Drivers/Lan9118Dxe/Lan9118DxeHw.h new file mode 100644 index 000000000000..b5553be1905a --- /dev/null +++ b/Platform/ARM/VExpressPkg/Drivers/Lan9118Dxe/Lan9118DxeHw.h @@ -0,0 +1,401 @@ +/** @file +* +* WARNING: +* This driver fails to follow the UEFI driver model without a good +* reason, and only remains in the tree because it is still used by +* a small number of platforms. It will be removed when no longer used. +* New platforms should not use it, and no one should use this as +* reference code for developing new drivers. +* +* Copyright (c) 2012-2014, ARM Limited. All rights reserved. +* +* SPDX-License-Identifier: BSD-2-Clause-Patent +* +**/ + +#ifndef __LAN9118_DXE_HW_H__ +#define __LAN9118_DXE_HW_H__ + +/*------------------------------------------------------------------------= ------ + LAN9118 SMCS Registers +--------------------------------------------------------------------------= ----*/ + +// Base address as on the VE board +#define LAN9118_BA ((UINT32) PcdGet32(PcdLan911= 8DxeBaseAddress)) + +/* ------------- Tx and Rx Data and Status Memory Locations --------------= ----*/ +#define LAN9118_RX_DATA (0x00000000 + LAN9118_BA) +#define LAN9118_RX_STATUS (0x00000040 + LAN9118_BA) +#define LAN9118_RX_STATUS_PEEK (0x00000044 + LAN9118_BA) +#define LAN9118_TX_DATA (0x00000020 + LAN9118_BA) +#define LAN9118_TX_STATUS (0x00000048 + LAN9118_BA) +#define LAN9118_TX_STATUS_PEEK (0x0000004C + LAN9118_BA) + +/* ------------- System Control and Status Registers ---------------------= ----*/ +#define LAN9118_ID_REV (0x00000050 + LAN9118_BA) = // Chip ID and Revision +#define LAN9118_IRQ_CFG (0x00000054 + LAN9118_BA) = // Interrupt Configuration +#define LAN9118_INT_STS (0x00000058 + LAN9118_BA) = // Interrupt Status +#define LAN9118_INT_EN (0x0000005C + LAN9118_BA) = // Interrupt Enable +//#define LAN9118_RESERVED (0x00000060) +#define LAN9118_BYTE_TEST (0x00000064 + LAN9118_BA) = // Byte Order Test +#define LAN9118_FIFO_INT (0x00000068 + LAN9118_BA) = // FIFO Level Interrupts +#define LAN9118_RX_CFG (0x0000006C + LAN9118_BA) = // Receive Configuration +#define LAN9118_TX_CFG (0x00000070 + LAN9118_BA) = // Transmit Configuration +#define LAN9118_HW_CFG (0x00000074 + LAN9118_BA) = // Hardware Configuration +#define LAN9118_RX_DP_CTL (0x00000078 + LAN9118_BA) = // Receive Data-Path Configuration +#define LAN9118_RX_FIFO_INF (0x0000007C + LAN9118_BA) = // Receive FIFO Information +#define LAN9118_TX_FIFO_INF (0x00000080 + LAN9118_BA) = // Transmit FIFO Information +#define LAN9118_PMT_CTRL (0x00000084 + LAN9118_BA) = // Power Management Control +#define LAN9118_GPIO_CFG (0x00000088 + LAN9118_BA) = // General Purpose IO Configuration +#define LAN9118_GPT_CFG (0x0000008C + LAN9118_BA) = // General Purpose Timer Configuration +#define LAN9118_GPT_CNT (0x00000090 + LAN9118_BA) = // General Purpose Timer Current Count +#define LAN9118_WORD_SWAP (0x00000098 + LAN9118_BA) = // Word Swap Control +#define LAN9118_FREE_RUN (0x0000009C + LAN9118_BA) = // Free-Run 25MHz Counter +#define LAN9118_RX_DROP (0x000000A0 + LAN9118_BA) = // Receiver Dropped Frames Counter +#define LAN9118_MAC_CSR_CMD (0x000000A4 + LAN9118_BA) = // MAC CSR Synchronizer Command +#define LAN9118_MAC_CSR_DATA (0x000000A8 + LAN9118_BA) = // MAC CSR Synchronizer Data +#define LAN9118_AFC_CFG (0x000000AC + LAN9118_BA) = // Automatic Flow Control Configuration +#define LAN9118_E2P_CMD (0x000000B0 + LAN9118_BA) = // EEPROM Command +#define LAN9118_E2P_DATA (0x000000B4 + LAN9118_BA) = // EEPROM Data + +/* + * Required delays following write cycles (number of BYTE_TEST reads) + * Taken from Table 6.1 in Revision 1.5 (07-11-08) of the LAN9118 datashee= t. + * Where no delay listed, 0 has been assumed. + */ +#define LAN9118_RX_DATA_WR_DELAY 0 +#define LAN9118_RX_STATUS_WR_DELAY 0 +#define LAN9118_RX_STATUS_PEEK_WR_DELAY 0 +#define LAN9118_TX_DATA_WR_DELAY 0 +#define LAN9118_TX_STATUS_WR_DELAY 0 +#define LAN9118_TX_STATUS_PEEK_WR_DELAY 0 +#define LAN9118_ID_REV_WR_DELAY 0 +#define LAN9118_IRQ_CFG_WR_DELAY 3 +#define LAN9118_INT_STS_WR_DELAY 2 +#define LAN9118_INT_EN_WR_DELAY 1 +#define LAN9118_BYTE_TEST_WR_DELAY 0 +#define LAN9118_FIFO_INT_WR_DELAY 1 +#define LAN9118_RX_CFG_WR_DELAY 1 +#define LAN9118_TX_CFG_WR_DELAY 1 +#define LAN9118_HW_CFG_WR_DELAY 1 +#define LAN9118_RX_DP_CTL_WR_DELAY 1 +#define LAN9118_RX_FIFO_INF_WR_DELAY 0 +#define LAN9118_TX_FIFO_INF_WR_DELAY 3 +#define LAN9118_PMT_CTRL_WR_DELAY 7 +#define LAN9118_GPIO_CFG_WR_DELAY 1 +#define LAN9118_GPT_CFG_WR_DELAY 1 +#define LAN9118_GPT_CNT_WR_DELAY 3 +#define LAN9118_WORD_SWAP_WR_DELAY 1 +#define LAN9118_FREE_RUN_WR_DELAY 4 +#define LAN9118_RX_DROP_WR_DELAY 0 +#define LAN9118_MAC_CSR_CMD_WR_DELAY 1 +#define LAN9118_MAC_CSR_DATA_WR_DELAY 1 +#define LAN9118_AFC_CFG_WR_DELAY 1 +#define LAN9118_E2P_CMD_WR_DELAY 1 +#define LAN9118_E2P_DATA_WR_DELAY 1 + +/* + * Required delays following read cycles (number of BYTE_TEST reads) + * Taken from Table 6.2 in Revision 1.5 (07-11-08) of the LAN9118 datashee= t. + * Where no delay listed, 0 has been assumed. + */ +#define LAN9118_RX_DATA_RD_DELAY 3 +#define LAN9118_RX_STATUS_RD_DELAY 3 +#define LAN9118_RX_STATUS_PEEK_RD_DELAY 0 +#define LAN9118_TX_DATA_RD_DELAY 0 +#define LAN9118_TX_STATUS_RD_DELAY 3 +#define LAN9118_TX_STATUS_PEEK_RD_DELAY 0 +#define LAN9118_ID_REV_RD_DELAY 0 +#define LAN9118_IRQ_CFG_RD_DELAY 0 +#define LAN9118_INT_STS_RD_DELAY 0 +#define LAN9118_INT_EN_RD_DELAY 0 +#define LAN9118_BYTE_TEST_RD_DELAY 0 +#define LAN9118_FIFO_INT_RD_DELAY 0 +#define LAN9118_RX_CFG_RD_DELAY 0 +#define LAN9118_TX_CFG_RD_DELAY 0 +#define LAN9118_HW_CFG_RD_DELAY 0 +#define LAN9118_RX_DP_CTL_RD_DELAY 0 +#define LAN9118_RX_FIFO_INF_RD_DELAY 0 +#define LAN9118_TX_FIFO_INF_RD_DELAY 0 +#define LAN9118_PMT_CTRL_RD_DELAY 0 +#define LAN9118_GPIO_CFG_RD_DELAY 0 +#define LAN9118_GPT_CFG_RD_DELAY 0 +#define LAN9118_GPT_CNT_RD_DELAY 0 +#define LAN9118_WORD_SWAP_RD_DELAY 0 +#define LAN9118_FREE_RUN_RD_DELAY 0 +#define LAN9118_RX_DROP_RD_DELAY 4 +#define LAN9118_MAC_CSR_CMD_RD_DELAY 0 +#define LAN9118_MAC_CSR_DATA_RD_DELAY 0 +#define LAN9118_AFC_CFG_RD_DELAY 0 +#define LAN9118_E2P_CMD_RD_DELAY 0 +#define LAN9118_E2P_DATA_RD_DELAY 0 + +// Receiver Status bits +#define RXSTATUS_CRC_ERROR BIT1 //= Cyclic Redundancy Check Error +#define RXSTATUS_DB BIT2 //= Dribbling bit: Frame had non-integer multiple of 8bits +#define RXSTATUS_MII_ERROR BIT3 //= Receive error during interception +#define RXSTATUS_RXW_TO BIT4 //= Incoming frame larger than 2kb +#define RXSTATUS_FT BIT5 //= 1: Ether type / 0: 802.3 type frame +#define RXSTATUS_LCOLL BIT6 //= Late collision detected +#define RXSTATUS_FTL BIT7 //= Frame longer than Ether type +#define RXSTATUS_MCF BIT10 //= Frame has Multicast Address +#define RXSTATUS_RUNT BIT11 //= Bad frame +#define RXSTATUS_LE BIT12 //= Actual length of frame different than it claims +#define RXSTATUS_BCF BIT13 //= Frame has Broadcast Address +#define RXSTATUS_ES BIT15 //= Reports any error from bits 1,6,7 and 11 +#define RXSTATUS_PL_MASK (0x3FFF0000) //= Packet length bit mask +#define GET_RXSTATUS_PACKET_LENGTH(RxStatus) (((RxStatus) >> 16) & 0x3FFF= ) // Packet length bit mask +#define RXSTATUS_FILT_FAIL BIT30 //= The frame failed filtering test + +// Transmitter Status bits +#define TXSTATUS_DEF BIT0 //= Packet tx was deferred +#define TXSTATUS_EDEF BIT2 //= Tx ended because of excessive deferral (> 24288 bit times) +#define TXSTATUS_CC_MASK (0x00000078) //= Collision Count (before Tx) bit mask +#define TXSTATUS_ECOLL BIT8 //= Tx ended because of Excessive Collisions (makes CC_MASK invalid after 16 c= ollisions) +#define TXSTATUS_LCOLL BIT9 //= Packet Tx aborted after coll window of 64 bytes +#define TXSTATUS_NO_CA BIT10 //= Carrier signal not present during Tx (bad?) +#define TXSTATUS_LOST_CA BIT11 //= Lost carrier during Tx +#define TXSTATUS_ES BIT15 //= Reports any errors from bits 1,2,8,9,10 and 11 +#define TXSTATUS_PTAG_MASK (0xFFFF0000) //= Mask for Unique ID of packets (So we know who the packets are for) + +// ID_REV register bits +#define IDREV_ID ((Lan9118MmioRead32(LAN9118_= ID_REV) & 0xFFFF0000) >> 16) +#define IDREV_REV (Lan9118MmioRead32(LAN9118_I= D_REV) & 0x0000FFFF) + +// Interrupt Config Register bits +#define IRQCFG_IRQ_TYPE BIT0 // I= RQ Buffer type +#define IRQCFG_IRQ_POL BIT4 // I= RQ Polarity +#define IRQCFG_IRQ_EN BIT8 // E= nable external interrupt +#define IRQCFG_IRQ_INT BIT12 // S= tate of internal interrupts line +#define IRQCFG_INT_DEAS_STS BIT13 // S= tate of deassertion interval +#define IRQCFG_INT_DEAS_CLR BIT14 // C= lear the deassertion counter +#define IRQCFG_INT_DEAS_MASK (0xFF000000) // I= nterrupt deassertion interval value mask + +// Interrupt Status Register bits +#define INSTS_GPIO_MASK (0x7) // G= PIO interrupts mask +#define INSTS_RSFL (0x8) // R= x Status FIFO Level reached +#define INSTS_RSFF BIT4 // R= x Status FIFO full +#define INSTS_RXDF_INT BIT6 // R= x Frame dropped +#define INSTS_TSFL BIT7 // T= x Status FIFO Level reached +#define INSTS_TSFF BIT8 // T= x Status FIFO full +#define INSTS_TDFA BIT9 // T= x Data FIFO Level exceeded +#define INSTS_TDFO BIT10 // T= x Data FIFO full +#define INSTS_TXE BIT13 // T= ransmitter Error +#define INSTS_RXE BIT14 // R= eceiver Error +#define INSTS_RWT BIT15 // P= acket > 2048 bytes received +#define INSTS_TXSO BIT16 // T= x Status FIFO Overflow +#define INSTS_PME_INT BIT17 // P= ME Signal detected +#define INSTS_PHY_INT BIT18 // I= ndicates PHY Interrupt +#define INSTS_GPT_INT BIT19 // G= P Timer wrapped past 0xFFFF +#define INSTS_RXD_INT BIT20 // I= ndicates that amount of data written to RX_CFG was cleared +#define INSTS_TX_IOC BIT21 // F= inished loading IOC flagged buffer to Tx FIFO +#define INSTS_RXDFH_INT BIT23 // R= x Dropped frames went past 0x7FFFFFFF +#define INSTS_RXSTOP_INT BIT24 // R= x was stopped +#define INSTS_TXSTOP_INT BIT25 // T= x was stopped +#define INSTS_SW_INT BIT31 // S= oftware Interrupt occurred + +// Interrupt Enable Register bits + + +// Hardware Config Register bits +#define HWCFG_SRST BIT0 /= / Software Reset bit (SC) +#define HWCFG_SRST_TO BIT1 /= / Software Reset Timeout bit (RO) +#define HWCFG_BMODE BIT2 /= / 32/16 bit Mode bit (RO) +#define HWCFG_TX_FIFO_SIZE_MASK (~ (UINT32)0xF0000) /= / Mask to Clear FIFO Size +#define HWCFG_MBO BIT20 /= / Must Be One bit + +// Power Management Control Register +#define MPTCTRL_READY BIT0 // Devic= e ready indicator +#define MPTCTRL_PME_EN BIT1 // Enabl= e external PME signals +#define MPTCTRL_PME_POL BIT2 // Set p= olarity of PME signals +#define MPTCTRL_PME_IND BIT3 // Signa= l type of PME (refer to Spec) +#define MPTCTRL_WUPS_MASK (0x18) // Wake = up status indicator mask +#define MPTCTRL_PME_TYPE BIT6 // PME B= uffer type (Open Drain or Push-Pull) +#define MPTCTRL_ED_EN BIT8 // Energ= y-detect enable +#define MPTCTRL_WOL_EN BIT9 // Enabl= e wake-on-lan +#define MPTCTRL_PHY_RST BIT10 // Reset= the PHY +#define MPTCTRL_PM_MODE_MASK (BIT12 | BIT13) // Set t= he power mode + +// PHY control register bits +#define PHYCR_COLL_TEST BIT7 // Col= lision test enable +#define PHYCR_DUPLEX_MODE BIT8 // Set= Duplex Mode +#define PHYCR_RST_AUTO BIT9 // Res= tart Auto-Negotiation of Link abilities +#define PHYCR_PD BIT11 // Pow= er-Down switch +#define PHYCR_AUTO_EN BIT12 // Aut= o-Negotiation Enable +#define PHYCR_SPEED_SEL BIT13 // Lin= k Speed Selection +#define PHYCR_LOOPBK BIT14 // Set= loopback mode +#define PHYCR_RESET BIT15 // Do = a PHY reset + +// PHY status register bits +#define PHYSTS_EXT_CAP BIT0 // Ext= ended Capabilities Register capability +#define PHYSTS_JABBER BIT1 // Jab= ber condition detected +#define PHYSTS_LINK_STS BIT2 // Lin= k Status +#define PHYSTS_AUTO_CAP BIT3 // Aut= o-Negotiation Capability +#define PHYSTS_REMOTE_FAULT BIT4 // Rem= ote fault detected +#define PHYSTS_AUTO_COMP BIT5 // Aut= o-Negotiation Completed +#define PHYSTS_10BASET_HDPLX BIT11 // 10M= bps Half-Duplex ability +#define PHYSTS_10BASET_FDPLX BIT12 // 10M= bps Full-Duplex ability +#define PHYSTS_100BASETX_HDPLX BIT13 // 100= Mbps Half-Duplex ability +#define PHYSTS_100BASETX_FDPLX BIT14 // 100= Mbps Full-Duplex ability +#define PHYSTS_100BASE_T4 BIT15 // Bas= e T4 ability + +// PHY Auto-Negotiation advertisement +#define PHYANA_SEL_MASK ((UINT32)0x1F) // Lin= k type selector +#define PHYANA_10BASET BIT5 // Adv= ertise 10BASET capability +#define PHYANA_10BASETFD BIT6 // Adv= ertise 10BASET Full duplex capability +#define PHYANA_100BASETX BIT7 // Adv= ertise 100BASETX capability +#define PHYANA_100BASETXFD BIT8 // Adv= ertise 100 BASETX Full duplex capability +#define PHYANA_PAUSE_OP_MASK (3 << 10) // Adv= ertise PAUSE frame capability +#define PHYANA_REMOTE_FAULT BIT13 // Rem= ote fault detected + + +// PHY Auto-Negotiation Link Partner Ability + +// PHY Auto-Negotiation Expansion + +// PHY Mode control/status + +// PHY Special Modes + +// PHY Special control/status + +// PHY Interrupt Source Flags + +// PHY Interrupt Mask + +// PHY Super Special control/status +#define PHYSSCS_HCDSPEED_MASK (7 << 2) // Spe= ed indication +#define PHYSSCS_AUTODONE BIT12 // Aut= o-Negotiation Done + + +// MAC control register bits +#define MACCR_RX_EN BIT2 // Enab= le Receiver bit +#define MACCR_TX_EN BIT3 // Enab= le Transmitter bit +#define MACCR_DFCHK BIT5 // Defe= rral Check bit +#define MACCR_PADSTR BIT8 // Auto= matic Pad Stripping bit +#define MACCR_BOLMT_MASK (0xC0) // Back= -Off limit mask +#define MACCR_DISRTY BIT10 // Disa= ble Transmit Retry bit +#define MACCR_BCAST BIT11 // Disa= ble Broadcast Frames bit +#define MACCR_LCOLL BIT12 // Late= Collision Control bit +#define MACCR_HPFILT BIT13 // Hash= /Perfect Filtering Mode bit +#define MACCR_HO BIT15 // Hash= Only Filtering Mode +#define MACCR_PASSBAD BIT16 // Rece= ive all frames that passed filter bit +#define MACCR_INVFILT BIT17 // Enab= le Inverse Filtering bit +#define MACCR_PRMS BIT18 // Prom= iscuous Mode bit +#define MACCR_MCPAS BIT19 // Pass= all Multicast packets bit +#define MACCR_FDPX BIT20 // Full= Duplex Mode bit +#define MACCR_LOOPBK BIT21 // Loop= back operation mode bit +#define MACCR_RCVOWN BIT23 // Disa= ble Receive Own frames bit +#define MACCR_RX_ALL BIT31 // Rece= ive all Packets and route to Filter + +// Wake-Up Control and Status Register +#define WUCSR_MPEN BIT1 // Magi= c Packet enable (allow wake from Magic P) +#define WUCSR_WUEN BIT2 // Allo= w remote wake up using Wake-Up Frames +#define WUCSR_MPR_MASK (0x10) // Rece= ived Magic Packet +#define WUCSR_WUFR_MASK (0x20) // Rece= ived Wake-Up Frame +#define WUCSR_GUE BIT9 // Enab= le wake on global unicast frames + +// RX Configuration Register bits +#define RXCFG_RXDOFF_MASK (0x1F00) // Rx D= ata Offset in Bytes +#define RXCFG_RX_DUMP BIT15 // Clea= r Rx data and status FIFOs +#define RXCFG_RX_DMA_CNT_MASK (0x0FFF0000) // Amou= nt of data to be read from Rx FIFO +#define RXCFG_RX_DMA_CNT(cnt) (((cnt) & 0xFFF) << 16) // Amou= nt of data to be read from Rx FIFO +#define RXCFG_RX_END_ALIGN_MASK (0xC0000000) // Alig= nment to preserve + +// TX Configuration Register bits +#define TXCFG_STOP_TX BIT0 // Stop= the transmitter +#define TXCFG_TX_ON BIT1 // Star= t the transmitter +#define TXCFG_TXSAO BIT2 // Tx S= tatus FIFO full +#define TXCFG_TXD_DUMP BIT14 // Clea= r Tx Data FIFO +#define TXCFG_TXS_DUMP BIT15 // Clea= r Tx Status FIFO + +// Rx FIFO Information Register bits +#define RXFIFOINF_RXDUSED_MASK (0xFFFF) // Rx D= ata FIFO Used Space +#define RXFIFOINF_RXSUSED_MASK (0xFF0000) // Rx S= tatus FIFO Used Space + +// Tx FIFO Information Register bits +#define TXFIFOINF_TDFREE_MASK (0xFFFF) // Tx D= ata FIFO Free Space +#define TXFIFOINF_TXSUSED_MASK (0xFF0000) // Tx S= tatus FIFO Used Space + +// E2P Register +#define E2P_EPC_BUSY BIT31 +#define E2P_EPC_CMD_READ (0) +#define E2P_EPC_TIMEOUT BIT9 +#define E2P_EPC_MAC_ADDRESS_LOADED BIT8 +#define E2P_EPC_ADDRESS(address) ((address) & 0xFFFF) + +// GPIO Configuration register +#define GPIO_GPIO0_PUSH_PULL BIT16 +#define GPIO_GPIO1_PUSH_PULL BIT17 +#define GPIO_GPIO2_PUSH_PULL BIT18 +#define GPIO_LED1_ENABLE BIT28 +#define GPIO_LED2_ENABLE BIT29 +#define GPIO_LED3_ENABLE BIT30 + +// MII_ACC bits +#define MII_ACC_MII_BUSY BIT0 +#define MII_ACC_MII_WRITE BIT1 +#define MII_ACC_MII_READ 0 + +#define MII_ACC_PHY_VALUE BIT11 +#define MII_ACC_MII_REG_INDEX(index) (((index) & 0x1F) << 6) + +// +// PHY Control Indexes +// +#define PHY_INDEX_BASIC_CTRL 0 +#define PHY_INDEX_BASIC_STATUS 1 +#define PHY_INDEX_ID1 2 +#define PHY_INDEX_ID2 3 +#define PHY_INDEX_AUTO_NEG_ADVERT 4 +#define PHY_INDEX_AUTO_NEG_LINK_ABILITY 5 +#define PHY_INDEX_AUTO_NEG_EXP 6 +#define PHY_INDEX_MODE 17 +#define PHY_INDEX_SPECIAL_MODES 18 +#define PHY_INDEX_SPECIAL_CTLR 27 +#define PHY_INDEX_INT_SRC 29 +#define PHY_INDEX_INT_MASK 30 +#define PHY_INDEX_SPECIAL_PHY_CTLR 31 + +// Indirect MAC Indexes +#define INDIRECT_MAC_INDEX_CR 1 +#define INDIRECT_MAC_INDEX_ADDRH 2 +#define INDIRECT_MAC_INDEX_ADDRL 3 +#define INDIRECT_MAC_INDEX_HASHH 4 +#define INDIRECT_MAC_INDEX_HASHL 5 +#define INDIRECT_MAC_INDEX_MII_ACC 6 +#define INDIRECT_MAC_INDEX_MII_DATA 7 + +// +// MAC CSR Synchronizer Command register +// +#define MAC_CSR_BUSY BIT31 +#define MAC_CSR_READ BIT30 +#define MAC_CSR_WRITE 0 +#define MAC_CSR_ADDR(Addr) ((Addr) & 0xFF) + +// +// TX Packet Format +// +#define TX_CMD_A_COMPLETION_INT BIT31 +#define TX_CMD_A_FIRST_SEGMENT BIT13 +#define TX_CMD_A_LAST_SEGMENT BIT12 +#define TX_CMD_A_BUFF_SIZE(size) ((size) & 0x000003FF) +#define TX_CMD_A_DATA_START_OFFSET(offset) (((offset) & 0x1F) << 16) +#define TX_CMD_B_PACKET_LENGTH(size) ((size) & 0x000003FF) +#define TX_CMD_B_PACKET_TAG(tag) (((tag) & 0x3FF) << 16) + +// Hardware Configuration Register +#define HW_CFG_TX_FIFO_SIZE_MASK (0xF << 16) +#define HW_CFG_TX_FIFO_SIZE(size) (((size) & 0xF) << 16) + +// EEPROM Definition +#define EEPROM_EXTERNAL_SERIAL_EEPROM 0xA5 + +// +// Conditional compilation flags +// +//#define EVAL_PERFORMANCE + + +#endif /* __LAN9118_DXE_HDR_H__ */ diff --git a/Platform/ARM/VExpressPkg/Drivers/Lan9118Dxe/Lan9118DxeUtil.c b= /Platform/ARM/VExpressPkg/Drivers/Lan9118Dxe/Lan9118DxeUtil.c new file mode 100644 index 000000000000..4ccbcad6b9e1 --- /dev/null +++ b/Platform/ARM/VExpressPkg/Drivers/Lan9118Dxe/Lan9118DxeUtil.c @@ -0,0 +1,1039 @@ +/** @file +* +* WARNING: +* This driver fails to follow the UEFI driver model without a good +* reason, and only remains in the tree because it is still used by +* a small number of platforms. It will be removed when no longer used. +* New platforms should not use it, and no one should use this as +* reference code for developing new drivers. +* +* Copyright (c) 2012-2014, ARM Limited. All rights reserved. +* +* SPDX-License-Identifier: BSD-2-Clause-Patent +* +**/ + +#include "Lan9118Dxe.h" + +STATIC EFI_MAC_ADDRESS mZeroMac =3D { { 0 } }; + +/** + This internal function reverses bits for 32bit data. + + @param Value The data to be reversed. + + @return Data reversed. + +**/ +UINT32 +ReverseBits ( + UINT32 Value + ) +{ + UINTN Index; + UINT32 NewValue; + + NewValue =3D 0; + for (Index =3D 0; Index < 32; Index++) { + if ((Value & (1 << Index)) !=3D 0) { + NewValue =3D NewValue | (1 << (31 - Index)); + } + } + + return NewValue; +} + +/* +** Create Ethernet CRC +** +** INFO USED: +** 1: http://en.wikipedia.org/wiki/Cyclic_redundancy_check +** +** 2: http://www.erg.abdn.ac.uk/~gorry/eg3567/dl-pages/crc.html +** +** 3: http://en.wikipedia.org/wiki/Computation_of_CRC +*/ +UINT32 +GenEtherCrc32 ( + IN EFI_MAC_ADDRESS *Mac, + IN UINT32 AddrLen + ) +{ + INT32 Iter; + UINT32 Remainder; + UINT8 *Ptr; + + Iter =3D 0; + Remainder =3D 0xFFFFFFFF; // 0xFFFFFFFF is standard seed for Ethernet + + // Convert Mac Address to array of bytes + Ptr =3D (UINT8*)Mac; + + // Generate the Crc bit-by-bit (LSB first) + while (AddrLen--) { + Remainder ^=3D *Ptr++; + for (Iter =3D 0;Iter < 8;Iter++) { + // Check if exponent is set + if (Remainder & 1) { + Remainder =3D (Remainder >> 1) ^ CRC_POLYNOMIAL; + } else { + Remainder =3D (Remainder >> 1) ^ 0; + } + } + } + + // Reverse the bits before returning (to Big Endian) + //TODO: Need to be reviewed. Do we want to do a bit reverse or a byte re= verse (in this case use SwapBytes32()) + return ReverseBits (Remainder); +} + +// Function to read from MAC indirect registers +UINT32 +IndirectMACRead32 ( + UINT32 Index + ) +{ + UINT32 MacCSR; + + // Check index is in the range + ASSERT(Index <=3D 12); + + // Wait until CSR busy bit is cleared + while ((Lan9118MmioRead32 (LAN9118_MAC_CSR_CMD) & MAC_CSR_BUSY) =3D=3D M= AC_CSR_BUSY); + + // Set CSR busy bit to ensure read will occur + // Set the R/W bit to indicate we are reading + // Set the index of CSR Address to access desired register + MacCSR =3D MAC_CSR_BUSY | MAC_CSR_READ | MAC_CSR_ADDR(Index); + + // Write to the register + Lan9118MmioWrite32 (LAN9118_MAC_CSR_CMD, MacCSR); + + // Wait until CSR busy bit is cleared + while ((Lan9118MmioRead32 (LAN9118_MAC_CSR_CMD) & MAC_CSR_BUSY) =3D=3D M= AC_CSR_BUSY); + + // Now read from data register to get read value + return Lan9118MmioRead32 (LAN9118_MAC_CSR_DATA); +} + +/* + * LAN9118 chips have special restrictions on some back-to-back Write/Read= or + * Read/Read pairs of accesses. After a read or write that changes the sta= te of + * the device, there is a period in which stale values may be returned in + * response to a read. This period is dependent on the registers accessed. + * + * We must delay prior reads by this period. This can either be achieved by + * timer-based delays, or by performing dummy reads of the BYTE_TEST regis= ter, + * for which the recommended number of reads is described in the LAN9118 d= ata + * sheet. This is required in addition to any memory barriers. + * + * This function performs a number of dummy reads of the BYTE_TEST registe= r, as + * a building block for the above. + */ +VOID +WaitDummyReads ( + UINTN Count + ) +{ + while (Count--) + MmioRead32(LAN9118_BYTE_TEST); +} + +UINT32 +Lan9118RawMmioRead32( + UINTN Address, + UINTN Delay + ) +{ + UINT32 Value; + + Value =3D MmioRead32(Address); + WaitDummyReads(Delay); + return Value; +} + +UINT32 +Lan9118RawMmioWrite32( + UINTN Address, + UINT32 Value, + UINTN Delay + ) +{ + MmioWrite32(Address, Value); + WaitDummyReads(Delay); + return Value; +} + +// Function to write to MAC indirect registers +UINT32 +IndirectMACWrite32 ( + UINT32 Index, + UINT32 Value + ) +{ + UINT32 ValueWritten; + UINT32 MacCSR; + + // Check index is in the range + ASSERT(Index <=3D 12); + + // Wait until CSR busy bit is cleared + while ((Lan9118MmioRead32 (LAN9118_MAC_CSR_CMD) & MAC_CSR_BUSY) =3D=3D M= AC_CSR_BUSY); + + // Set CSR busy bit to ensure read will occur + // Set the R/W bit to indicate we are writing + // Set the index of CSR Address to access desired register + MacCSR =3D MAC_CSR_BUSY | MAC_CSR_WRITE | MAC_CSR_ADDR(Index); + + // Now write the value to the register before issuing the write command + ValueWritten =3D Lan9118MmioWrite32 (LAN9118_MAC_CSR_DATA, Value); + + // Write the config to the register + Lan9118MmioWrite32 (LAN9118_MAC_CSR_CMD, MacCSR); + + // Wait until CSR busy bit is cleared + while ((Lan9118MmioRead32 (LAN9118_MAC_CSR_CMD) & MAC_CSR_BUSY) =3D=3D M= AC_CSR_BUSY); + + return ValueWritten; +} + +// Function to read from MII register (PHY Access) +UINT32 +IndirectPHYRead32 ( + UINT32 Index + ) +{ + UINT32 ValueRead; + UINT32 MiiAcc; + + // Check it is a valid index + ASSERT(Index < 31); + + // Wait for busy bit to clear + while ((IndirectMACRead32 (INDIRECT_MAC_INDEX_MII_ACC) & MII_ACC_MII_BUS= Y) =3D=3D MII_ACC_MII_BUSY); + + // Clear the R/W bit to indicate we are reading + // Set the index of the MII register + // Set the PHY Address + // Set the MII busy bit to allow read + MiiAcc =3D MII_ACC_MII_READ | MII_ACC_MII_REG_INDEX(Index) | MII_ACC_PHY= _VALUE | MII_ACC_MII_BUSY; + + // Now write this config to register + IndirectMACWrite32 (INDIRECT_MAC_INDEX_MII_ACC, MiiAcc & 0xFFFF); + + // Wait for busy bit to clear + while ((IndirectMACRead32 (INDIRECT_MAC_INDEX_MII_ACC) & MII_ACC_MII_BUS= Y) =3D=3D MII_ACC_MII_BUSY); + + // Now read the value of the register + ValueRead =3D (IndirectMACRead32 (INDIRECT_MAC_INDEX_MII_DATA) & 0xFFFF)= ; // only lower 16 bits are valid for any PHY register + + return ValueRead; +} + + +// Function to write to the MII register (PHY Access) +UINT32 +IndirectPHYWrite32 ( + UINT32 Index, + UINT32 Value + ) +{ + UINT32 MiiAcc; + UINT32 ValueWritten; + + // Check it is a valid index + ASSERT(Index < 31); + + // Wait for busy bit to clear + while ((IndirectMACRead32 (INDIRECT_MAC_INDEX_MII_ACC) & MII_ACC_MII_BUS= Y) =3D=3D MII_ACC_MII_BUSY); + + // Clear the R/W bit to indicate we are reading + // Set the index of the MII register + // Set the PHY Address + // Set the MII busy bit to allow read + MiiAcc =3D MII_ACC_MII_WRITE | MII_ACC_MII_REG_INDEX(Index) | MII_ACC_PH= Y_VALUE | MII_ACC_MII_BUSY; + + // Write the desired value to the register first + ValueWritten =3D IndirectMACWrite32 (INDIRECT_MAC_INDEX_MII_DATA, (Value= & 0xFFFF)); + + // Now write the config to register + IndirectMACWrite32 (INDIRECT_MAC_INDEX_MII_ACC, MiiAcc & 0xFFFF); + + // Wait for operation to terminate + while ((IndirectMACRead32 (INDIRECT_MAC_INDEX_MII_ACC) & MII_ACC_MII_BUS= Y) =3D=3D MII_ACC_MII_BUSY); + + return ValueWritten; +} + + +/* ---------------- EEPROM Operations ------------------ */ + + +// Function to read from EEPROM memory +UINT32 +IndirectEEPROMRead32 ( + UINT32 Index + ) +{ + UINT32 EepromCmd; + + // Set the busy bit to ensure read will occur + EepromCmd =3D E2P_EPC_BUSY | E2P_EPC_CMD_READ; + + // Set the index to access desired EEPROM memory location + EepromCmd |=3D E2P_EPC_ADDRESS(Index); + + // Write to Eeprom command register + Lan9118MmioWrite32 (LAN9118_E2P_CMD, EepromCmd); + + // Wait until operation has completed + while (Lan9118MmioRead32 (LAN9118_E2P_CMD) & E2P_EPC_BUSY); + + // Check that operation didn't time out + if (Lan9118MmioRead32 (LAN9118_E2P_CMD) & E2P_EPC_TIMEOUT) { + DEBUG ((EFI_D_ERROR, "EEPROM Operation Timed out: Read command on inde= x %x\n",Index)); + return 0; + } + + // Wait until operation has completed + while (Lan9118MmioRead32 (LAN9118_E2P_CMD) & E2P_EPC_BUSY); + + // Finally read the value + return Lan9118MmioRead32 (LAN9118_E2P_DATA); +} + +// Function to write to EEPROM memory +UINT32 +IndirectEEPROMWrite32 ( + UINT32 Index, + UINT32 Value + ) +{ + UINT32 ValueWritten; + UINT32 EepromCmd; + + ValueWritten =3D 0; + + // Read the EEPROM Command register + EepromCmd =3D Lan9118MmioRead32 (LAN9118_E2P_CMD); + + // Set the busy bit to ensure read will occur + EepromCmd |=3D ((UINT32)1 << 31); + + // Set the EEPROM command to write(0b011) + EepromCmd &=3D ~(7 << 28); // Clear the command first + EepromCmd |=3D (3 << 28); // Write 011 + + // Set the index to access desired EEPROM memory location + EepromCmd |=3D (Index & 0xF); + + // Write the value to the data register first + ValueWritten =3D Lan9118MmioWrite32 (LAN9118_E2P_DATA, Value); + + // Write to Eeprom command register + Lan9118MmioWrite32 (LAN9118_E2P_CMD, EepromCmd); + + // Wait until operation has completed + while (Lan9118MmioRead32 (LAN9118_E2P_CMD) & E2P_EPC_BUSY); + + // Check that operation didn't time out + if (Lan9118MmioRead32 (LAN9118_E2P_CMD) & E2P_EPC_TIMEOUT) { + DEBUG ((EFI_D_ERROR, "EEPROM Operation Timed out: Write command at mem= loc 0x%x, with value 0x%x\n",Index, Value)); + return 0; + } + + // Wait until operation has completed + while (Lan9118MmioRead32 (LAN9118_E2P_CMD) & E2P_EPC_BUSY); + + return ValueWritten; +} + +/* ---------------- General Operations ----------------- */ + +VOID +Lan9118SetMacAddress ( + EFI_MAC_ADDRESS *Mac, + EFI_SIMPLE_NETWORK_PROTOCOL *Snp + ) +{ + IndirectMACWrite32 (INDIRECT_MAC_INDEX_ADDRL, + (Mac->Addr[0] & 0xFF) | + ((Mac->Addr[1] & 0xFF) << 8) | + ((Mac->Addr[2] & 0xFF) << 16) | + ((Mac->Addr[3] & 0xFF) << 24) + ); + + IndirectMACWrite32 (INDIRECT_MAC_INDEX_ADDRH, + (UINT32)(Mac->Addr[4] & 0xFF) | + ((Mac->Addr[5] & 0xFF) << 8) + ); +} + +VOID +Lan9118ReadMacAddress ( + OUT EFI_MAC_ADDRESS *MacAddress + ) +{ + UINT32 MacAddrHighValue; + UINT32 MacAddrLowValue; + + // Read the Mac Addr high register + MacAddrHighValue =3D (IndirectMACRead32 (INDIRECT_MAC_INDEX_ADDRH) & 0xF= FFF); + // Read the Mac Addr low register + MacAddrLowValue =3D IndirectMACRead32 (INDIRECT_MAC_INDEX_ADDRL); + + SetMem (MacAddress, sizeof(*MacAddress), 0); + MacAddress->Addr[0] =3D (MacAddrLowValue & 0xFF); + MacAddress->Addr[1] =3D (MacAddrLowValue & 0xFF00) >> 8; + MacAddress->Addr[2] =3D (MacAddrLowValue & 0xFF0000) >> 16; + MacAddress->Addr[3] =3D (MacAddrLowValue & 0xFF000000) >> 24; + MacAddress->Addr[4] =3D (MacAddrHighValue & 0xFF); + MacAddress->Addr[5] =3D (MacAddrHighValue & 0xFF00) >> 8; +} + +/* + * Power up the 9118 and find its MAC address. + * + * This operation can be carried out when the LAN9118 is in any power sta= te + * + */ +EFI_STATUS +Lan9118Initialize ( + IN EFI_SIMPLE_NETWORK_PROTOCOL *Snp + ) +{ + UINTN Retries; + UINT64 DefaultMacAddress; + + // Attempt to wake-up the device if it is in a lower power state + if (((Lan9118MmioRead32 (LAN9118_PMT_CTRL) & MPTCTRL_PM_MODE_MASK) >> 12= ) !=3D 0) { + DEBUG ((DEBUG_NET, "Waking from reduced power state.\n")); + Lan9118MmioWrite32 (LAN9118_BYTE_TEST, 0xFFFFFFFF); + } + + // Check that device is active + Retries =3D 20; + while ((Lan9118MmioRead32 (LAN9118_PMT_CTRL) & MPTCTRL_READY) =3D=3D 0 &= & --Retries) { + gBS->Stall (LAN9118_STALL); + } + if (!Retries) { + return EFI_TIMEOUT; + } + + // Check that EEPROM isn't active + Retries =3D 20; + while ((Lan9118MmioRead32 (LAN9118_E2P_CMD) & E2P_EPC_BUSY) && --Retries= ){ + gBS->Stall (LAN9118_STALL); + } + if (!Retries) { + return EFI_TIMEOUT; + } + + // Check if a MAC address was loaded from EEPROM, and if it was, set it = as the + // current address. + if ((Lan9118MmioRead32 (LAN9118_E2P_CMD) & E2P_EPC_MAC_ADDRESS_LOADED) = =3D=3D 0) { + DEBUG ((EFI_D_ERROR, "Warning: There was an error detecting EEPROM or = loading the MAC Address.\n")); + + // If we had an address before (set by StationAddress), continue to us= e it + if (CompareMem (&Snp->Mode->CurrentAddress, &mZeroMac, NET_ETHER_ADDR_= LEN)) { + Lan9118SetMacAddress (&Snp->Mode->CurrentAddress, Snp); + } else { + // If there are no cached addresses, then fall back to a default + DEBUG ((EFI_D_WARN, "Warning: using driver-default MAC address\n")); + DefaultMacAddress =3D FixedPcdGet64 (PcdLan9118DefaultMacAddress); + Lan9118SetMacAddress((EFI_MAC_ADDRESS *) &DefaultMacAddress, Snp); + CopyMem (&Snp->Mode->CurrentAddress, &DefaultMacAddress, NET_ETHER_A= DDR_LEN); + } + } else { + // Store the MAC address that was loaded from EEPROM + Lan9118ReadMacAddress (&Snp->Mode->CurrentAddress); + CopyMem (&Snp->Mode->PermanentAddress, &Snp->Mode->CurrentAddress, NET= _ETHER_ADDR_LEN); + } + + // Clear and acknowledge interrupts + Lan9118MmioWrite32 (LAN9118_INT_EN, 0); + Lan9118MmioWrite32 (LAN9118_IRQ_CFG, 0); + Lan9118MmioWrite32 (LAN9118_INT_STS, 0xFFFFFFFF); + + // Do self tests here? + + return EFI_SUCCESS; +} + + +// Perform software reset on the LAN9118 +// Return 0 on success, -1 on error +EFI_STATUS +SoftReset ( + UINT32 Flags, + EFI_SIMPLE_NETWORK_PROTOCOL *Snp + ) +{ + UINT32 HwConf; + UINT32 ResetTime; + + // Initialize variable + ResetTime =3D 0; + + // Stop Rx and Tx + StopTx (STOP_TX_MAC | STOP_TX_CFG | STOP_TX_CLEAR, Snp); + StopRx (STOP_RX_CLEAR, Snp); // Clear receiver FIFO + + // Issue the reset + HwConf =3D Lan9118MmioRead32 (LAN9118_HW_CFG); + HwConf |=3D 1; + + // Set the Must Be One (MBO) bit + if (((HwConf & HWCFG_MBO) >> 20) =3D=3D 0) { + HwConf |=3D HWCFG_MBO; + } + + // Check that EEPROM isn't active + while (Lan9118MmioRead32 (LAN9118_E2P_CMD) & E2P_EPC_BUSY); + + // Write the configuration + Lan9118MmioWrite32 (LAN9118_HW_CFG, HwConf); + + // Wait for reset to complete + while (Lan9118MmioRead32 (LAN9118_HW_CFG) & HWCFG_SRST) { + + gBS->Stall (LAN9118_STALL); + ResetTime +=3D 1; + + // If time taken exceeds 100us, then there was an error condition + if (ResetTime > 1000) { + Snp->Mode->State =3D EfiSimpleNetworkStopped; + return EFI_TIMEOUT; + } + } + + // Check that EEPROM isn't active + while (Lan9118MmioRead32 (LAN9118_E2P_CMD) & E2P_EPC_BUSY); + + // TODO we probably need to re-set the mac address here. + + // Clear and acknowledge all interrupts + if (Flags & SOFT_RESET_CLEAR_INT) { + Lan9118MmioWrite32 (LAN9118_INT_EN, 0); + Lan9118MmioWrite32 (LAN9118_IRQ_CFG, 0); + Lan9118MmioWrite32 (LAN9118_INT_STS, 0xFFFFFFFF); + } + + // Do self tests here? + if (Flags & SOFT_RESET_SELF_TEST) { + + } + + return EFI_SUCCESS; +} + + +// Perform PHY software reset +EFI_STATUS +PhySoftReset ( + UINT32 Flags, + EFI_SIMPLE_NETWORK_PROTOCOL *Snp + ) +{ + UINT32 PmtCtrl =3D 0; + + // PMT PHY reset takes precedence over BCR + if (Flags & PHY_RESET_PMT) { + PmtCtrl =3D Lan9118MmioRead32 (LAN9118_PMT_CTRL); + PmtCtrl |=3D MPTCTRL_PHY_RST; + Lan9118MmioWrite32 (LAN9118_PMT_CTRL,PmtCtrl); + + // Wait for completion + while (Lan9118MmioRead32 (LAN9118_PMT_CTRL) & MPTCTRL_PHY_RST) { + gBS->Stall (LAN9118_STALL); + } + // PHY Basic Control Register reset + } else if (Flags & PHY_RESET_BCR) { + IndirectPHYWrite32 (PHY_INDEX_BASIC_CTRL, PHYCR_RESET); + + // Wait for completion + while (IndirectPHYRead32 (PHY_INDEX_BASIC_CTRL) & PHYCR_RESET) { + gBS->Stall (LAN9118_STALL); + } + } + + // Clear and acknowledge all interrupts + if (Flags & PHY_SOFT_RESET_CLEAR_INT) { + Lan9118MmioWrite32 (LAN9118_INT_EN, 0); + Lan9118MmioWrite32 (LAN9118_IRQ_CFG, 0); + Lan9118MmioWrite32 (LAN9118_INT_STS, 0xFFFFFFFF); + } + + return EFI_SUCCESS; +} + + +// Configure hardware for LAN9118 +EFI_STATUS +ConfigureHardware ( + UINT32 Flags, + EFI_SIMPLE_NETWORK_PROTOCOL *Snp + ) +{ + UINT32 GpioConf; + + // Check if we want to use LEDs on GPIO + if (Flags & HW_CONF_USE_LEDS) { + GpioConf =3D Lan9118MmioRead32 (LAN9118_GPIO_CFG); + + // Enable GPIO as LEDs and Config as Push-Pull driver + GpioConf |=3D GPIO_GPIO0_PUSH_PULL | GPIO_GPIO1_PUSH_PULL | GPIO_GPIO2= _PUSH_PULL | + GPIO_LED1_ENABLE | GPIO_LED2_ENABLE | GPIO_LED3_ENABLE; + + // Write the configuration + Lan9118MmioWrite32 (LAN9118_GPIO_CFG, GpioConf); + } + + return EFI_SUCCESS; +} + +// Configure flow control +EFI_STATUS +ConfigureFlow ( + UINT32 Flags, + UINT32 HighTrig, + UINT32 LowTrig, + UINT32 BPDuration, + EFI_SIMPLE_NETWORK_PROTOCOL *Snp + ) +{ + return EFI_SUCCESS; +} + +// Do auto-negotiation +EFI_STATUS +AutoNegotiate ( + UINT32 Flags, + EFI_SIMPLE_NETWORK_PROTOCOL *Snp + ) +{ + UINT32 PhyControl; + UINT32 PhyStatus; + UINT32 Features; + UINT32 Retries; + + // First check that auto-negotiation is supported + PhyStatus =3D IndirectPHYRead32 (PHY_INDEX_BASIC_STATUS); + if ((PhyStatus & PHYSTS_AUTO_CAP) =3D=3D 0) { + DEBUG ((EFI_D_ERROR, "Auto-negotiation not supported.\n")); + return EFI_DEVICE_ERROR; + } + + // Check that link is up first + if ((PhyStatus & PHYSTS_LINK_STS) =3D=3D 0) { + // Wait until it is up or until Time Out + Retries =3D FixedPcdGet32 (PcdLan9118DefaultNegotiationTimeout) / LAN9= 118_STALL; + while ((IndirectPHYRead32 (PHY_INDEX_BASIC_STATUS) & PHYSTS_LINK_STS) = =3D=3D 0) { + gBS->Stall (LAN9118_STALL); + Retries--; + if (!Retries) { + DEBUG ((EFI_D_ERROR, "Link timeout in auto-negotiation.\n")); + return EFI_TIMEOUT; + } + } + } + + // Configure features to advertise + Features =3D IndirectPHYRead32 (PHY_INDEX_AUTO_NEG_ADVERT); + + if ((Flags & AUTO_NEGOTIATE_ADVERTISE_ALL) > 0) { + // Link speed capabilities + Features |=3D (PHYANA_10BASET | PHYANA_10BASETFD | PHYANA_100BASETX | = PHYANA_100BASETXFD); + + // Pause frame capabilities + Features &=3D ~(PHYANA_PAUSE_OP_MASK); + Features |=3D 3 << 10; + } + Features &=3D FixedPcdGet32 (PcdLan9118NegotiationFeatureMask); + + // Write the features + IndirectPHYWrite32 (PHY_INDEX_AUTO_NEG_ADVERT, Features); + + // Read control register + PhyControl =3D IndirectPHYRead32 (PHY_INDEX_BASIC_CTRL); + + // Enable Auto-Negotiation + if ((PhyControl & PHYCR_AUTO_EN) =3D=3D 0) { + PhyControl |=3D PHYCR_AUTO_EN; + } + + // Restart auto-negotiation + PhyControl |=3D PHYCR_RST_AUTO; + + // Enable collision test if required to do so + if (Flags & AUTO_NEGOTIATE_COLLISION_TEST) { + PhyControl |=3D PHYCR_COLL_TEST; + } else { + PhyControl &=3D ~ PHYCR_COLL_TEST; + } + + // Write this configuration + IndirectPHYWrite32 (PHY_INDEX_BASIC_CTRL, PhyControl); + + // Wait until process has completed + while ((IndirectPHYRead32 (PHY_INDEX_BASIC_STATUS) & PHYSTS_AUTO_COMP) = =3D=3D 0); + + return EFI_SUCCESS; +} + +// Check the Link Status and take appropriate action +EFI_STATUS +CheckLinkStatus ( + UINT32 Flags, + EFI_SIMPLE_NETWORK_PROTOCOL *Snp + ) +{ + // Get the PHY Status + UINT32 PhyBStatus =3D IndirectPHYRead32 (PHY_INDEX_BASIC_STATUS); + + if (PhyBStatus & PHYSTS_LINK_STS) { + return EFI_SUCCESS; + } else { + return EFI_DEVICE_ERROR; + } +} + +// Stop the transmitter +EFI_STATUS +StopTx ( + UINT32 Flags, + EFI_SIMPLE_NETWORK_PROTOCOL *Snp + ) +{ + UINT32 MacCsr; + UINT32 TxCfg; + + MacCsr =3D 0; + TxCfg =3D 0; + + // Check if we want to clear tx + if (Flags & STOP_TX_CLEAR) { + TxCfg =3D Lan9118MmioRead32 (LAN9118_TX_CFG); + TxCfg |=3D TXCFG_TXS_DUMP | TXCFG_TXD_DUMP; + Lan9118MmioWrite32 (LAN9118_TX_CFG, TxCfg); + } + + // Check if already stopped + if (Flags & STOP_TX_MAC) { + MacCsr =3D IndirectMACRead32 (INDIRECT_MAC_INDEX_CR); + + if (MacCsr & MACCR_TX_EN) { + MacCsr &=3D ~MACCR_TX_EN; + IndirectMACWrite32 (INDIRECT_MAC_INDEX_CR, MacCsr); + } + } + + if (Flags & STOP_TX_CFG) { + TxCfg =3D Lan9118MmioRead32 (LAN9118_TX_CFG); + + if (TxCfg & TXCFG_TX_ON) { + TxCfg |=3D TXCFG_STOP_TX; + Lan9118MmioWrite32 (LAN9118_TX_CFG, TxCfg); + + // Wait for Tx to finish transmitting + while (Lan9118MmioRead32 (LAN9118_TX_CFG) & TXCFG_STOP_TX); + } + } + + return EFI_SUCCESS; +} + +// Stop the receiver +EFI_STATUS +StopRx ( + UINT32 Flags, + EFI_SIMPLE_NETWORK_PROTOCOL *Snp + ) +{ + UINT32 MacCsr; + UINT32 RxCfg; + + RxCfg =3D 0; + + // Check if already stopped + MacCsr =3D IndirectMACRead32 (INDIRECT_MAC_INDEX_CR); + + if (MacCsr & MACCR_RX_EN) { + MacCsr &=3D ~ MACCR_RX_EN; + IndirectMACWrite32 (INDIRECT_MAC_INDEX_CR, MacCsr); + } + + // Check if we want to clear receiver FIFOs + if (Flags & STOP_RX_CLEAR) { + RxCfg =3D Lan9118MmioRead32 (LAN9118_RX_CFG); + RxCfg |=3D RXCFG_RX_DUMP; + Lan9118MmioWrite32 (LAN9118_RX_CFG, RxCfg); + + while (Lan9118MmioRead32 (LAN9118_RX_CFG) & RXCFG_RX_DUMP); + } + + return EFI_SUCCESS; +} + +// Start the transmitter +EFI_STATUS +StartTx ( + UINT32 Flags, + EFI_SIMPLE_NETWORK_PROTOCOL *Snp + ) +{ + UINT32 MacCsr; + UINT32 TxCfg; + + MacCsr =3D 0; + TxCfg =3D 0; + + // Check if we want to clear tx + if (Flags & START_TX_CLEAR) { + TxCfg =3D Lan9118MmioRead32 (LAN9118_TX_CFG); + TxCfg |=3D TXCFG_TXS_DUMP | TXCFG_TXD_DUMP; + Lan9118MmioWrite32 (LAN9118_TX_CFG, TxCfg); + } + + // Check if tx was started from MAC and enable if not + if (Flags & START_TX_MAC) { + MacCsr =3D IndirectMACRead32 (INDIRECT_MAC_INDEX_CR); + if ((MacCsr & MACCR_TX_EN) =3D=3D 0) { + MacCsr |=3D MACCR_TX_EN; + IndirectMACWrite32 (INDIRECT_MAC_INDEX_CR, MacCsr); + } + } + + // Check if tx was started from TX_CFG and enable if not + if (Flags & START_TX_CFG) { + TxCfg =3D Lan9118MmioRead32 (LAN9118_TX_CFG); + if ((TxCfg & TXCFG_TX_ON) =3D=3D 0) { + TxCfg |=3D TXCFG_TX_ON; + Lan9118MmioWrite32 (LAN9118_TX_CFG, TxCfg); + } + } + + // Set the tx data trigger level + + return EFI_SUCCESS; +} + +// Start the receiver +EFI_STATUS +StartRx ( + UINT32 Flags, + EFI_SIMPLE_NETWORK_PROTOCOL *Snp + ) +{ + UINT32 MacCsr; + UINT32 RxCfg; + + RxCfg =3D 0; + + // Check if already started + MacCsr =3D IndirectMACRead32 (INDIRECT_MAC_INDEX_CR); + + if ((MacCsr & MACCR_RX_EN) =3D=3D 0) { + // Check if we want to clear receiver FIFOs before starting + if (Flags & START_RX_CLEAR) { + RxCfg =3D Lan9118MmioRead32 (LAN9118_RX_CFG); + RxCfg |=3D RXCFG_RX_DUMP; + Lan9118MmioWrite32 (LAN9118_RX_CFG, RxCfg); + + while (Lan9118MmioRead32 (LAN9118_RX_CFG) & RXCFG_RX_DUMP); + } + + MacCsr |=3D MACCR_RX_EN; + IndirectMACWrite32 (INDIRECT_MAC_INDEX_CR, MacCsr); + } + + return EFI_SUCCESS; +} + +// Check Tx Data available space +UINT32 +TxDataFreeSpace ( + UINT32 Flags, + EFI_SIMPLE_NETWORK_PROTOCOL *Snp + ) +{ + UINT32 TxInf; + UINT32 FreeSpace; + + // Get the amount of free space from information register + TxInf =3D Lan9118MmioRead32 (LAN9118_TX_FIFO_INF); + FreeSpace =3D (TxInf & TXFIFOINF_TDFREE_MASK); + + return FreeSpace; // Value in bytes +} + +// Check Tx Status used space +UINT32 +TxStatusUsedSpace ( + UINT32 Flags, + EFI_SIMPLE_NETWORK_PROTOCOL *Snp + ) +{ + UINT32 TxInf; + UINT32 UsedSpace; + + // Get the amount of used space from information register + TxInf =3D Lan9118MmioRead32 (LAN9118_TX_FIFO_INF); + UsedSpace =3D (TxInf & TXFIFOINF_TXSUSED_MASK) >> 16; + + return UsedSpace << 2; // Value in bytes +} + +// Check Rx Data used space +UINT32 +RxDataUsedSpace ( + UINT32 Flags, + EFI_SIMPLE_NETWORK_PROTOCOL *Snp + ) +{ + UINT32 RxInf; + UINT32 UsedSpace; + + // Get the amount of used space from information register + RxInf =3D Lan9118MmioRead32 (LAN9118_RX_FIFO_INF); + UsedSpace =3D (RxInf & RXFIFOINF_RXDUSED_MASK); + + return UsedSpace; // Value in bytes (rounded up to nearest DWORD) +} + +// Check Rx Status used space +UINT32 +RxStatusUsedSpace ( + UINT32 Flags, + EFI_SIMPLE_NETWORK_PROTOCOL *Snp + ) +{ + UINT32 RxInf; + UINT32 UsedSpace; + + // Get the amount of used space from information register + RxInf =3D Lan9118MmioRead32 (LAN9118_RX_FIFO_INF); + UsedSpace =3D (RxInf & RXFIFOINF_RXSUSED_MASK) >> 16; + + return UsedSpace << 2; // Value in bytes +} + + +// Change the allocation of FIFOs +EFI_STATUS +ChangeFifoAllocation ( + IN UINT32 Flags, + IN OUT UINTN *TxDataSize OPTIONAL, + IN OUT UINTN *RxDataSize OPTIONAL, + IN OUT UINT32 *TxStatusSize OPTIONAL, + IN OUT UINT32 *RxStatusSize OPTIONAL, + IN OUT EFI_SIMPLE_NETWORK_PROTOCOL *Snp + ) +{ + UINT32 HwConf; + UINT32 TxFifoOption; + + // Check that desired sizes don't exceed limits + if (*TxDataSize > TX_FIFO_MAX_SIZE) + return EFI_INVALID_PARAMETER; + +#if defined(RX_FIFO_MIN_SIZE) && defined(RX_FIFO_MAX_SIZE) + if (*RxDataSize > RX_FIFO_MAX_SIZE) { + return EFI_INVALID_PARAMETER; + } +#endif + + if (Flags & ALLOC_USE_DEFAULT) { + return EFI_SUCCESS; + } + + // If we use the FIFOs (always use this first) + if (Flags & ALLOC_USE_FIFOS) { + // Read the current value of allocation + HwConf =3D Lan9118MmioRead32 (LAN9118_HW_CFG); + TxFifoOption =3D (HwConf >> 16) & 0xF; + + // Choose the correct size (always use larger than requested if possib= le) + if (*TxDataSize < TX_FIFO_MIN_SIZE) { + *TxDataSize =3D TX_FIFO_MIN_SIZE; + *RxDataSize =3D 13440; + *RxStatusSize =3D 896; + TxFifoOption =3D 2; + } else if ((*TxDataSize > TX_FIFO_MIN_SIZE) && (*TxDataSize <=3D 2560)= ) { + *TxDataSize =3D 2560; + *RxDataSize =3D 12480; + *RxStatusSize =3D 832; + TxFifoOption =3D 3; + } else if ((*TxDataSize > 2560) && (*TxDataSize <=3D 3584)) { + *TxDataSize =3D 3584; + *RxDataSize =3D 11520; + *RxStatusSize =3D 768; + TxFifoOption =3D 4; + } else if ((*TxDataSize > 3584) && (*TxDataSize <=3D 4608)) { // defau= lt option + *TxDataSize =3D 4608; + *RxDataSize =3D 10560; + *RxStatusSize =3D 704; + TxFifoOption =3D 5; + } else if ((*TxDataSize > 4608) && (*TxDataSize <=3D 5632)) { + *TxDataSize =3D 5632; + *RxDataSize =3D 9600; + *RxStatusSize =3D 640; + TxFifoOption =3D 6; + } else if ((*TxDataSize > 5632) && (*TxDataSize <=3D 6656)) { + *TxDataSize =3D 6656; + *RxDataSize =3D 8640; + *RxStatusSize =3D 576; + TxFifoOption =3D 7; + } else if ((*TxDataSize > 6656) && (*TxDataSize <=3D 7680)) { + *TxDataSize =3D 7680; + *RxDataSize =3D 7680; + *RxStatusSize =3D 512; + TxFifoOption =3D 8; + } else if ((*TxDataSize > 7680) && (*TxDataSize <=3D 8704)) { + *TxDataSize =3D 8704; + *RxDataSize =3D 6720; + *RxStatusSize =3D 448; + TxFifoOption =3D 9; + } else if ((*TxDataSize > 8704) && (*TxDataSize <=3D 9728)) { + *TxDataSize =3D 9728; + *RxDataSize =3D 5760; + *RxStatusSize =3D 384; + TxFifoOption =3D 10; + } else if ((*TxDataSize > 9728) && (*TxDataSize <=3D 10752)) { + *TxDataSize =3D 10752; + *RxDataSize =3D 4800; + *RxStatusSize =3D 320; + TxFifoOption =3D 11; + } else if ((*TxDataSize > 10752) && (*TxDataSize <=3D 11776)) { + *TxDataSize =3D 11776; + *RxDataSize =3D 3840; + *RxStatusSize =3D 256; + TxFifoOption =3D 12; + } else if ((*TxDataSize > 11776) && (*TxDataSize <=3D 12800)) { + *TxDataSize =3D 12800; + *RxDataSize =3D 2880; + *RxStatusSize =3D 192; + TxFifoOption =3D 13; + } else if ((*TxDataSize > 12800) && (*TxDataSize <=3D 13824)) { + *TxDataSize =3D 13824; + *RxDataSize =3D 1920; + *RxStatusSize =3D 128; + TxFifoOption =3D 14; + } + } else { + ASSERT(0); // Untested code path + HwConf =3D 0; + TxFifoOption =3D 0; + } + + // Do we need DMA? + if (Flags & ALLOC_USE_DMA) { + return EFI_UNSUPPORTED; // Unsupported as of now + } + // Clear and assign the new size option + HwConf &=3D ~(0xF0000); + HwConf |=3D ((TxFifoOption & 0xF) << 16); + Lan9118MmioWrite32 (LAN9118_HW_CFG, HwConf); + + return EFI_SUCCESS; +} diff --git a/Platform/ARM/VExpressPkg/Drivers/Lan9118Dxe/Lan9118DxeUtil.h b= /Platform/ARM/VExpressPkg/Drivers/Lan9118Dxe/Lan9118DxeUtil.h new file mode 100644 index 000000000000..601714c94387 --- /dev/null +++ b/Platform/ARM/VExpressPkg/Drivers/Lan9118Dxe/Lan9118DxeUtil.h @@ -0,0 +1,283 @@ +/** @file +* +* WARNING: +* This driver fails to follow the UEFI driver model without a good +* reason, and only remains in the tree because it is still used by +* a small number of platforms. It will be removed when no longer used. +* New platforms should not use it, and no one should use this as +* reference code for developing new drivers. +* +* Copyright (c) 2012-2014, ARM Limited. All rights reserved. +* +* SPDX-License-Identifier: BSD-2-Clause-Patent +* +**/ + +#ifndef __LAN9118_DXE_UTIL_H__ +#define __LAN9118_DXE_UTIL_H__ + +// Most common CRC32 Polynomial for little endian machines +#define CRC_POLYNOMIAL 0xEDB88320 + +/** + This internal function reverses bits for 32bit data. + + @param Value The data to be reversed. + + @return Data reversed. + +**/ +UINT32 +ReverseBits ( + UINT32 Value + ); + +// Create an Ethernet CRC +UINT32 +GenEtherCrc32 ( + IN EFI_MAC_ADDRESS *Mac, + IN UINT32 AddrLen + ); + +UINT32 +Lan9118RawMmioRead32( + UINTN Address, + UINTN Delay + ); +#define Lan9118MmioRead32(a) \ + Lan9118RawMmioRead32(a, a ## _RD_DELAY) + +UINT32 +Lan9118RawMmioWrite32( + UINTN Address, + UINT32 Value, + UINTN Delay + ); +#define Lan9118MmioWrite32(a, v) \ + Lan9118RawMmioWrite32(a, v, a ## _WR_DELAY) + +/* ------------------ MAC CSR Access ------------------- */ + +// Read from MAC indirect registers +UINT32 +IndirectMACRead32 ( + UINT32 Index + ); + + +// Write to indirect registers +UINT32 +IndirectMACWrite32 ( + UINT32 Index, + UINT32 Value + ); + + +/* --------------- PHY Registers Access ---------------- */ + +// Read from MII register (PHY Access) +UINT32 +IndirectPHYRead32( + UINT32 Index + ); + + +// Write to the MII register (PHY Access) +UINT32 +IndirectPHYWrite32( + UINT32 Index, + UINT32 Value + ); + +/* ---------------- EEPROM Operations ------------------ */ + +// Read from EEPROM memory +UINT32 +IndirectEEPROMRead32 ( + UINT32 Index + ); + +// Write to EEPROM memory +UINT32 +IndirectEEPROMWrite32 ( + UINT32 Index, + UINT32 Value + ); + +/* ---------------- General Operations ----------------- */ + +VOID +Lan9118SetMacAddress ( + EFI_MAC_ADDRESS *Mac, + EFI_SIMPLE_NETWORK_PROTOCOL *Snp + ); + +// Initialise the LAN9118 +EFI_STATUS +Lan9118Initialize ( + IN EFI_SIMPLE_NETWORK_PROTOCOL *Snp + ); + +// Flags for software reset +#define SOFT_RESET_CHECK_MAC_ADDR_LOAD BIT0 +#define SOFT_RESET_CLEAR_INT BIT1 +#define SOFT_RESET_SELF_TEST BIT2 + +// Perform software reset on the LAN9118 +EFI_STATUS +SoftReset ( + UINT32 Flags, + EFI_SIMPLE_NETWORK_PROTOCOL *Snp + ); + +// Flags for PHY reset +#define PHY_RESET_PMT BIT0 +#define PHY_RESET_BCR BIT1 +#define PHY_SOFT_RESET_CLEAR_INT BIT2 + +// Perform PHY software reset +EFI_STATUS +PhySoftReset ( + UINT32 Flags, + EFI_SIMPLE_NETWORK_PROTOCOL *Snp + ); + +// Flags for Hardware configuration +#define HW_CONF_USE_LEDS BIT0 + +// Configure hardware for LAN9118 +EFI_STATUS +ConfigureHardware ( + UINT32 Flags, + EFI_SIMPLE_NETWORK_PROTOCOL *Snp + ); + +// Configure flow control +EFI_STATUS +ConfigureFlow ( + UINT32 Flags, + UINT32 HighTrig, + UINT32 LowTrig, + UINT32 BPDuration, + EFI_SIMPLE_NETWORK_PROTOCOL *Snp + ); + +// Flags for auto negotiation +#define AUTO_NEGOTIATE_COLLISION_TEST BIT0 +#define AUTO_NEGOTIATE_ADVERTISE_ALL BIT1 + +// Do auto-negotiation +EFI_STATUS +AutoNegotiate ( + UINT32 Flags, + EFI_SIMPLE_NETWORK_PROTOCOL *Snp + ); + +// Check the Link Status and take appropriate action +EFI_STATUS +CheckLinkStatus ( + UINT32 Flags, + EFI_SIMPLE_NETWORK_PROTOCOL *Snp + ); + +// Stop transmitter flags +#define STOP_TX_MAC BIT0 +#define STOP_TX_CFG BIT1 +#define STOP_TX_CLEAR BIT2 + +// Stop the transmitter +EFI_STATUS +StopTx ( + UINT32 Flags, + EFI_SIMPLE_NETWORK_PROTOCOL *Snp + ); + +// Stop receiver flags +#define STOP_RX_CLEAR BIT0 + +// Stop the receiver +EFI_STATUS +StopRx ( + UINT32 Flags, + EFI_SIMPLE_NETWORK_PROTOCOL *Snp + ); + +// Start transmitter flags +#define START_TX_MAC BIT0 +#define START_TX_CFG BIT1 +#define START_TX_CLEAR BIT2 + +// Start the transmitter +EFI_STATUS +StartTx ( + UINT32 Flags, + EFI_SIMPLE_NETWORK_PROTOCOL *Snp + ); + +// Stop receiver flags +#define START_RX_CLEAR BIT0 + +// Start the receiver +EFI_STATUS +StartRx ( + UINT32 Flags, + EFI_SIMPLE_NETWORK_PROTOCOL *Snp + ); + +// Check Tx Data available space +UINT32 +TxDataFreeSpace ( + UINT32 Flags, + EFI_SIMPLE_NETWORK_PROTOCOL *Snp + ); + +// Check Tx Status used space +UINT32 +TxStatusUsedSpace ( + UINT32 Flags, + EFI_SIMPLE_NETWORK_PROTOCOL *Snp + ); + +// Check Rx Data used space +UINT32 +RxDataUsedSpace ( + UINT32 Flags, + EFI_SIMPLE_NETWORK_PROTOCOL *Snp + ); + +// Check Rx Status used space +UINT32 +RxStatusUsedSpace ( + UINT32 Flags, + EFI_SIMPLE_NETWORK_PROTOCOL *Snp + ); + + +// Flags for FIFO allocation +#define ALLOC_USE_DEFAULT BIT0 +#define ALLOC_USE_FIFOS BIT1 +#define ALLOC_USE_DMA BIT2 + +// FIFO min and max sizes +#define TX_FIFO_MIN_SIZE 0x00000600 +#define TX_FIFO_MAX_SIZE 0x00003600 +//#define RX_FIFO_MIN_SIZE +//#define RX_FIFO_MAX_SIZE + +// Change the allocation of FIFOs +EFI_STATUS +ChangeFifoAllocation ( + IN UINT32 Flags, + IN OUT UINTN *TxDataSize OPTIONAL, + IN OUT UINTN *RxDataSize OPTIONAL, + IN OUT UINT32 *TxStatusSize OPTIONAL, + IN OUT UINT32 *RxStatusSize OPTIONAL, + IN OUT EFI_SIMPLE_NETWORK_PROTOCOL *Snp + ); + +VOID +Lan9118ReadMacAddress ( + OUT EFI_MAC_ADDRESS *Mac + ); + +#endif // __LAN9118_DXE_UTIL_H__ --=20 2.17.1 -=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D- Groups.io Links: You receive all messages sent to this group. View/Reply Online (#58455): https://edk2.groups.io/g/devel/message/58455 Mute This Topic: https://groups.io/mt/73380299/1787277 Group Owner: devel+owner@edk2.groups.io Unsubscribe: https://edk2.groups.io/g/devel/unsub [importer@patchew.org] -=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D- From nobody Mon May 6 19:29:01 2024 Delivered-To: importer@patchew.org Received-SPF: pass (zohomail.com: domain of groups.io designates 66.175.222.12 as permitted sender) client-ip=66.175.222.12; envelope-from=bounce+27952+58456+1787277+3901457@groups.io; helo=web01.groups.io; Authentication-Results: mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of groups.io designates 66.175.222.12 as permitted sender) smtp.mailfrom=bounce+27952+58456+1787277+3901457@groups.io ARC-Seal: i=1; a=rsa-sha256; t=1588267029; cv=none; d=zohomail.com; s=zohoarc; b=VKAY+RSP9DesJyT9TlEk4drF+P0iz24K695rbPQ83/7q8qIrZ+fKsHfHqWhmPqTLm4/LHw5NfUufPD0rMD9jMInvoY4tOcOmjpBcsADTJ8dgBStq1uhMCEbwDUgpZtE5ERgfIPyOJU3IyTl7JsBqYCZr1pYzl2ogOPrGSiii19Q= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1588267029; h=Cc:Date:From:In-Reply-To:List-Id:List-Unsubscribe:Message-ID:Reply-To:References:Sender:Subject:To; bh=UAeK+haXJ38TLCVN8/wwytSUF7W7iWG6yvWvlZoT8kU=; b=GtJ/gC0312Cf+TOvOfk89DgX2sOuIueUVKLuV8OV01DJuCWfSbHYCjfoJ/0LghGUYIg8fVOQbtWotfCOYd6790UczThdbsTB0BtoXNkGh3GZBpJUmTpP8fwNCE3WeLOhqiA6/kSb0mivk8kaxDN9LjWJ8kVst7BGrUI9POUavVs= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of groups.io designates 66.175.222.12 as permitted sender) smtp.mailfrom=bounce+27952+58456+1787277+3901457@groups.io Received: from web01.groups.io (web01.groups.io [66.175.222.12]) by mx.zohomail.com with SMTPS id 1588267029956514.1282439953166; Thu, 30 Apr 2020 10:17:09 -0700 (PDT) Return-Path: X-Received: by 127.0.0.2 with SMTP id Wxe7YY1788612xcrOlTA7uCK; Thu, 30 Apr 2020 10:17:09 -0700 X-Received: from foss.arm.com (foss.arm.com [217.140.110.172]) by mx.groups.io with SMTP id smtpd.web11.825.1588267028929119765 for ; Thu, 30 Apr 2020 10:17:09 -0700 X-Received: from usa-sjc-imap-foss1.foss.arm.com (unknown [10.121.207.14]) by usa-sjc-mx-foss1.foss.arm.com (Postfix) with ESMTP id 9BF461045; Thu, 30 Apr 2020 10:17:08 -0700 (PDT) X-Received: from e123331-lin.home (unknown [172.31.20.19]) by usa-sjc-imap-foss1.foss.arm.com (Postfix) with ESMTPSA id DA90A3F73D; Thu, 30 Apr 2020 10:17:07 -0700 (PDT) From: "Ard Biesheuvel" To: devel@edk2.groups.io Cc: leif@nuviainc.com, Ard Biesheuvel Subject: [edk2-devel] [PATCH edk2-platforms v3 8/8] Platform/ARM/VExpressPkg: incorporate ISP 1761 USB host driver Date: Thu, 30 Apr 2020 19:16:49 +0200 Message-Id: <20200430171650.24139-9-ard.biesheuvel@arm.com> In-Reply-To: <20200430171650.24139-1-ard.biesheuvel@arm.com> References: <20200430171650.24139-1-ard.biesheuvel@arm.com> Precedence: Bulk List-Unsubscribe: Sender: devel@edk2.groups.io List-Id: <27952.devel.edk2.groups.io> Mailing-List: list devel@edk2.groups.io; contact devel+owner@edk2.groups.io Reply-To: devel@edk2.groups.io,ard.biesheuvel@arm.com X-Gm-Message-State: pgYLfCf0VQQirbMgiywH1hrwx1787277AA= DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=groups.io; q=dns/txt; s=20140610; t=1588267029; bh=B3a2xCiXd0cqQXcYEcIcoaf5juJmaoxlyq9em+9hH/c=; h=Cc:Date:From:Reply-To:Subject:To; b=xHVEIbmu4uJ80UiWEwW0uX53JfP1bsNXVn7PLlkKmaMMgqycCKh4DFTbizSaGxWKEnZ Dk06P4Mm0PskkN79+FbSZqf8d2iA7yLwmUh1qD103/cidjLyJ7fvYm2GP7CDa5k1cCVbA SCog5NiUxtmEPknbmGUw6bZpGJhuyUyrrSQ= X-ZohoMail-DKIM: pass (identity @groups.io) Content-Transfer-Encoding: quoted-printable MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Incorporate the ISP 1761 USB host driver from EmbeddedPkg, which is only used on obsolete ARM development platforms and does not follow the UEFI driver model. This will allow us to drop it from the core EDK2 repository. Signed-off-by: Ard Biesheuvel Reviewed-by: Leif Lindholm --- Platform/ARM/VExpressPkg/ArmVExpress-CTA15-A7.dsc | 2 +- Platform/ARM/VExpressPkg/ArmVExpress-CTA15-A7.fdf | 2 +- Platform/ARM/VExpressPkg/ArmVExpress.dsc.inc | 2 +- Platform/ARM/VExpressPkg/ArmVExpressPkg.dec | 3 + Platform/ARM/VExpressPkg/Drivers/Isp1761UsbDxe/Isp1761UsbDxe.c | 636 +++= +++++++++++++++++ Platform/ARM/VExpressPkg/Drivers/Isp1761UsbDxe/Isp1761UsbDxe.h | 123 ++++ Platform/ARM/VExpressPkg/Drivers/Isp1761UsbDxe/Isp1761UsbDxe.inf | 39 ++ 7 files changed, 804 insertions(+), 3 deletions(-) diff --git a/Platform/ARM/VExpressPkg/ArmVExpress-CTA15-A7.dsc b/Platform/A= RM/VExpressPkg/ArmVExpress-CTA15-A7.dsc index bee7913feb52..144dd4f8b8e9 100644 --- a/Platform/ARM/VExpressPkg/ArmVExpress-CTA15-A7.dsc +++ b/Platform/ARM/VExpressPkg/ArmVExpress-CTA15-A7.dsc @@ -157,7 +157,7 @@ [PcdsFixedAtBuild.common] gArmTokenSpaceGuid.PcdGicInterruptInterfaceBase|0x2C002000 =20 # ISP1761 USB OTG Controller - gEmbeddedTokenSpaceGuid.PcdIsp1761BaseAddress|0x1B000000 + gArmVExpressTokenSpaceGuid.PcdIsp1761BaseAddress|0x1B000000 =20 # Ethernet (SMSC LAN9118) gArmVExpressTokenSpaceGuid.PcdLan9118DxeBaseAddress|0x1A000000 diff --git a/Platform/ARM/VExpressPkg/ArmVExpress-CTA15-A7.fdf b/Platform/A= RM/VExpressPkg/ArmVExpress-CTA15-A7.fdf index b133375e1a11..f98de162e634 100644 --- a/Platform/ARM/VExpressPkg/ArmVExpress-CTA15-A7.fdf +++ b/Platform/ARM/VExpressPkg/ArmVExpress-CTA15-A7.fdf @@ -126,7 +126,7 @@ [FV.FvMain] # # USB support # - INF EmbeddedPkg/Drivers/Isp1761UsbDxe/Isp1761UsbDxe.inf + INF Platform/ARM/VExpressPkg/Drivers/Isp1761UsbDxe/Isp1761UsbDxe.inf =20 # # Android Fastboot diff --git a/Platform/ARM/VExpressPkg/ArmVExpress.dsc.inc b/Platform/ARM/VE= xpressPkg/ArmVExpress.dsc.inc index 912ad5e5a1ec..bde3437b56d7 100644 --- a/Platform/ARM/VExpressPkg/ArmVExpress.dsc.inc +++ b/Platform/ARM/VExpressPkg/ArmVExpress.dsc.inc @@ -455,4 +455,4 @@ [Components.common] [Components.ARM] =20 # ISP1761 USB OTG Controller - EmbeddedPkg/Drivers/Isp1761UsbDxe/Isp1761UsbDxe.inf + Platform/ARM/VExpressPkg/Drivers/Isp1761UsbDxe/Isp1761UsbDxe.inf diff --git a/Platform/ARM/VExpressPkg/ArmVExpressPkg.dec b/Platform/ARM/VEx= pressPkg/ArmVExpressPkg.dec index e42905aabf2b..f78c5ce7c764 100644 --- a/Platform/ARM/VExpressPkg/ArmVExpressPkg.dec +++ b/Platform/ARM/VExpressPkg/ArmVExpressPkg.dec @@ -67,3 +67,6 @@ [PcdsFixedAtBuild.common] # The default feature mask below disables full duplex negotiation, since= full # duplex operation is suspected to be broken in the driver. gArmVExpressTokenSpaceGuid.PcdLan9118NegotiationFeatureMask|0xFFFFFEBF|U= INT32|0x00000028 + + # ISP1761 USB OTG Controller + gArmVExpressTokenSpaceGuid.PcdIsp1761BaseAddress|0|UINT32|0x00000029 diff --git a/Platform/ARM/VExpressPkg/Drivers/Isp1761UsbDxe/Isp1761UsbDxe.c= b/Platform/ARM/VExpressPkg/Drivers/Isp1761UsbDxe/Isp1761UsbDxe.c new file mode 100644 index 000000000000..c23c0ecf737d --- /dev/null +++ b/Platform/ARM/VExpressPkg/Drivers/Isp1761UsbDxe/Isp1761UsbDxe.c @@ -0,0 +1,636 @@ +/** @file + + WARNING: + This driver fails to follow the UEFI driver model without a good + reason, and only remains in the tree because it is still used by + a small number of platforms. It will be removed when no longer used. + New platforms should not use it, and no one should use this as + reference code for developing new drivers. + + Copyright (c) 2013-2015, ARM Ltd. All rights reserved.
+ + SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include +#include +#include +#include +#include + +#include + +#include + +#include "Isp1761UsbDxe.h" + +/* + Driver for using the NXP ISP1761 as a USB Peripheral controller. + Doesn't use USB OTG - just sets it in Pure Peripheral mode. + + The ISP1582 datasheet has a little more info on the Peripheral controller + registers than the ISP1761 datasheet + + We don't do string descriptors. They're optional. + We currently assume the device has one configuration, one interface, one= IN + endpoint, and one OUT endpoint (plus the default control endpoint). + + In fact, this driver is the minimum required to implement fastboot. +*/ + +// TODO Make sure the controller isn't sending empty packets when it shoul= dn't +// (check behaviour in cases when Buffer Length isn't explicitly set) + +// ISP1582 Datasheet: +// "Data transfers preceding the status stage must first be fully +// completed before the STATUS bit can be set." +// This variable stores whether some control data has been pended in the E= P0TX +// Tx buffer, so that when an EP0TX interrupt is received we can set the S= TATUS +// bit to go to the Status stage of the control transfer. +STATIC BOOLEAN mControlTxPending =3D FALSE; + +STATIC USB_DEVICE_DESCRIPTOR *mDeviceDescriptor; + +// The config descriptor, interface descriptor, and endpoint descriptors i= n 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; + +// The time between interrupt polls, in units of 100 nanoseconds +// 10 Microseconds +#define ISP1761_INTERRUPT_POLL_PERIOD 10000 + +STATIC +VOID +SelectEndpoint ( + IN UINT8 Endpoint + ) +{ + // The DMA Endpoint Index must not point to the same as the + // Endpoint Index Register. + WRITE_REG32 (ISP1761_DMA_ENDPOINT_INDEX, ((Endpoint + 2) % ISP1761_NUM_E= NDPOINTS)); + WRITE_REG32 (ISP1761_ENDPOINT_INDEX, Endpoint); +} + +// Enable going to the Data stage of a control transfer +STATIC +VOID +DataStageEnable ( + IN UINT8 Endpoint + ) +{ + SelectEndpoint (Endpoint); + WRITE_REG32 (ISP1761_CTRL_FUNCTION, ISP1761_CTRL_FUNCTION_DSEN); +} + +// Go to the Status stage of a successful control transfer +STATIC +VOID +StatusAcknowledge ( + IN UINT8 Endpoint +) +{ + SelectEndpoint (Endpoint); + WRITE_REG32 (ISP1761_CTRL_FUNCTION, ISP1761_CTRL_FUNCTION_STATUS); +} + +// Read the FIFO for the endpoint indexed by Endpoint, into the buffer poi= nted +// at by Buffer, whose size is *Size bytes. +// +// If *Size is less than the number of bytes in the FIFO, return EFI_BUFFE= R_TOO_SMALL +// +// Update *Size with the number of bytes of data in the FIFO. +STATIC +EFI_STATUS +ReadEndpointBuffer ( + IN UINT8 Endpoint, + IN OUT UINTN *Size, + IN OUT VOID *Buffer + ) +{ + UINT16 NumBytesAvailable; + UINT32 Val32; + UINTN Index; + UINTN NumBytesRead; + + SelectEndpoint (Endpoint); + + NumBytesAvailable =3D READ_REG16 (ISP1761_BUFFER_LENGTH); + + if (NumBytesAvailable > *Size) { + *Size =3D NumBytesAvailable; + return EFI_BUFFER_TOO_SMALL; + } + *Size =3D NumBytesAvailable; + + /* -- NB! -- + The datasheet says the Data Port is 16 bits but it actually appears to + be 32 bits. + */ + + // Read 32-bit chunks + for (Index =3D 0; Index < NumBytesAvailable / 4; Index++) { + ((UINT32 *) Buffer)[Index] =3D READ_REG32 (ISP1761_DATA_PORT); + } + + // Read remaining bytes + + // Round NumBytesAvailable down to nearest power of 4 + NumBytesRead =3D NumBytesAvailable & (~0x3); + if (NumBytesRead !=3D NumBytesAvailable) { + Val32 =3D READ_REG32 (ISP1761_DATA_PORT); + // Copy each required byte of 32-bit word into buffer + for (Index =3D 0; Index < NumBytesAvailable % 4; Index++) { + ((UINT8 *) Buffer)[NumBytesRead + Index] =3D Val32 >> (Index * 8); + } + } + return EFI_SUCCESS; +} + +/* + Write an endpoint buffer. Parameters: + Endpoint Endpoint index (see Endpoint Index Register in datasheet) + MaxPacketSize The MaxPacketSize this endpoint is configured for + Size The size of the Buffer + Buffer The data + + Assumes MaxPacketSize is a multiple of 4. + (It seems that all valid values for MaxPacketSize _are_ multiples of 4) +*/ +STATIC +EFI_STATUS +WriteEndpointBuffer ( + IN UINT8 Endpoint, + IN UINTN MaxPacketSize, + IN UINTN Size, + IN CONST VOID *Buffer + ) +{ + UINTN Index; + UINT32 *DwordBuffer; + + DwordBuffer =3D (UINT32 *) Buffer; + SelectEndpoint (Endpoint); + + /* -- NB! -- + The datasheet says the Data Port is 16 bits but it actually appears to + be 32 bits. + */ + + // Write packets of size MaxPacketSize + while (Size > MaxPacketSize) { + for (Index =3D 0; Index < MaxPacketSize / 4; Index++) { + WRITE_REG32 (ISP1761_DATA_PORT, DwordBuffer[Index]); + } + Size -=3D MaxPacketSize; + DwordBuffer +=3D (MaxPacketSize / sizeof (UINT32)); + } + + // Write remaining data + + if (Size > 0) { + WRITE_REG32 (ISP1761_BUFFER_LENGTH, Size); + + while (Size > 4) { + WRITE_REG32 (ISP1761_DATA_PORT, DwordBuffer[0]); + Size -=3D 4; + DwordBuffer++; + } + + if (Size > 0) { + WRITE_REG32 (ISP1761_DATA_PORT, DwordBuffer[0]); + } + } + + return EFI_SUCCESS; +} + +STATIC +EFI_STATUS +HandleGetDescriptor ( + IN USB_DEVICE_REQUEST *Request + ) +{ + EFI_STATUS Status; + UINT8 DescriptorType; + UINTN ResponseSize; + VOID *ResponseData; + + ResponseSize =3D 0; + ResponseData =3D NULL; + Status =3D EFI_SUCCESS; + + // Pretty confused if bmRequestType is anything but this: + ASSERT (Request->RequestType =3D=3D USB_DEV_GET_DESCRIPTOR_REQ_TYPE); + + // Choose the response + DescriptorType =3D Request->Value >> 8; + switch (DescriptorType) { + case USB_DESC_TYPE_DEVICE: + DEBUG ((EFI_D_INFO, "USB: Got a request for device descriptor\n")); + ResponseSize =3D sizeof (USB_DEVICE_DESCRIPTOR); + ResponseData =3D mDeviceDescriptor; + break; + case USB_DESC_TYPE_CONFIG: + DEBUG ((EFI_D_INFO, "USB: Got a request for config descriptor\n")); + ResponseSize =3D mConfigDescriptor->TotalLength; + ResponseData =3D mDescriptors; + break; + case USB_DESC_TYPE_STRING: + DEBUG ((EFI_D_INFO, "USB: Got a request for String descriptor %d\n", R= equest->Value & 0xFF)); + break; + default: + DEBUG ((EFI_D_INFO, "USB: Didn't understand request for descriptor 0x%= 04x\n", Request->Value)); + Status =3D EFI_NOT_FOUND; + break; + } + + // Send the response + if (ResponseData) { + ASSERT (ResponseSize !=3D 0); + + if (Request->Length < ResponseSize) { + // Truncate response + ResponseSize =3D Request->Length; + } else if (Request->Length > ResponseSize) { + DEBUG ((EFI_D_INFO, "USB: Info: ResponseSize < wLength\n")); + } + + DataStageEnable (ISP1761_EP0TX); + Status =3D WriteEndpointBuffer ( + ISP1761_EP0TX, + MAX_PACKET_SIZE_CONTROL, + ResponseSize, + ResponseData + ); + if (!EFI_ERROR (Status)) { + // Setting this value should cause us to go to the Status stage on t= he + // next EP0TX interrupt + mControlTxPending =3D TRUE; + } + } + + return EFI_SUCCESS; +} + +STATIC +EFI_STATUS +HandleSetAddress ( + IN USB_DEVICE_REQUEST *Request + ) +{ + // Pretty confused if bmRequestType is anything but this: + ASSERT (Request->RequestType =3D=3D USB_DEV_SET_ADDRESS_REQ_TYPE); + // USB Spec: "The USB device does not change its device address until af= ter + // the Status stage of this request is completed successfully." + // ISP1582 datasheet: "The new device address is activated when the + // device receives an acknowledgment from the host for the empty packet + // token". (StatusAcknowledge causes an empty packet to be sent). + // So, we write the Address register _before_ acking the SET_ADDRESS. + DEBUG ((EFI_D_INFO, "USB: Setting address to %d\n", Request->Value)); + WRITE_REG32 (ISP1761_ADDRESS, Request->Value | ISP1761_ADDRESS_DEVEN); + StatusAcknowledge (ISP1761_EP0TX); + + return EFI_SUCCESS; +} + +// Move the device to the Configured state. +// (This code only supports one configuration for a device, so the configu= ration +// index is ignored) +STATIC +EFI_STATUS +HandleSetConfiguration ( + IN USB_DEVICE_REQUEST *Request + ) +{ + USB_ENDPOINT_DESCRIPTOR *EPDesc; + UINTN Index; + UINT8 EndpointIndex; + + ASSERT (Request->RequestType =3D=3D USB_DEV_SET_CONFIGURATION_REQ_TYPE); + DEBUG ((EFI_D_INFO, "USB: Setting configuration.\n")); + + // Configure endpoints + for (Index =3D 0; Index < mInterfaceDescriptor->NumEndpoints; Index++) { + EPDesc =3D &mEndpointDescriptors[Index]; + + // To simplify for now, assume endpoints aren't "sparse", and are in o= rder. + ASSERT ((EPDesc->EndpointAddress & 0xF) =3D=3D ((Index / 2) + 1)); + + // Convert from USB endpoint index to ISP1761 endpoint Index + // USB: Endpoint number is bits [3:0], IN/OUT is bit [7] + // ISP1761: Endpoint number is bits [4:1], IN/OUT is bit [0] + EndpointIndex =3D ((EPDesc->EndpointAddress & 0xF) << 1) | + ((EPDesc->EndpointAddress & BIT7) >> 7); + SelectEndpoint (EndpointIndex); + // Set endpoint type (Bulk/Isochronous/Interrupt) + WRITE_REG32 (ISP1761_ENDPOINT_MAX_PACKET_SIZE, EPDesc->MaxPacketSize); + // Hardware foible (bug?): Although the datasheet seems to suggest it = should + // automatically be set to MaxPacketSize, the Buffer Length register a= ppears + // to be reset to 0, which causes an empty packet to be sent in respon= se to + // the first IN token of the session. The NOEMPKT field of the Endpoin= t Type + // register sounds like it might fix this problem, but it doesn't + // (it's "applicable only in the DMA mode"). + WRITE_REG32 (ISP1761_BUFFER_LENGTH, EPDesc->MaxPacketSize); + WRITE_REG32 (ISP1761_ENDPOINT_TYPE, (EPDesc->Attributes & 0x3) | + ISP1761_ENDPOINT_TYPE_ENABLE); + } + + StatusAcknowledge (ISP1761_EP0TX); + return EFI_SUCCESS; +} + +STATIC +EFI_STATUS +HandleDeviceRequest ( + IN USB_DEVICE_REQUEST *Request + ) +{ + EFI_STATUS Status; + + Status =3D EFI_SUCCESS; + + switch (Request->Request) { + case USB_DEV_GET_DESCRIPTOR: + Status =3D HandleGetDescriptor (Request); + break; + case USB_DEV_SET_ADDRESS: + Status =3D HandleSetAddress (Request); + break; + case USB_DEV_SET_CONFIGURATION: + Status =3D HandleSetConfiguration (Request); + break; + default: + DEBUG ((EFI_D_ERROR, + "Didn't understand RequestType 0x%x Request 0x%x\n", + Request->RequestType, Request->Request)); + Status =3D EFI_INVALID_PARAMETER; + break; + } + + return Status; +} + +// Instead of actually registering interrupt handlers, we poll the control= ler's +// interrupt source register in this function. +STATIC +VOID +CheckInterrupts ( + IN EFI_EVENT Event, + IN VOID *Context + ) +{ + UINT32 DcInterrupts; + UINTN NumBytes; + UINTN MoreBytes; + UINT8 Packet[512]; + VOID *DataPacket; + UINT32 HandledInterrupts; + UINT32 UnhandledInterrupts; + EFI_STATUS Status; + + // Set bits in HandledInterrupts to mark the interrupt source handled. + HandledInterrupts =3D 0; + + WRITE_REG32 (ISP1761_DEVICE_UNLOCK, ISP1761_DEVICE_UNLOCK_MAGIC); + + DcInterrupts =3D READ_REG32 (ISP1761_DC_INTERRUPT); + if (DcInterrupts & ISP1761_DC_INTERRUPT_SUSP) { + DEBUG ((EFI_D_INFO, "USB: Suspend\n")); + HandledInterrupts |=3D ISP1761_DC_INTERRUPT_SUSP; + } + if (DcInterrupts & ISP1761_DC_INTERRUPT_RESUME) { + DEBUG ((EFI_D_INFO, "USB: Resume\n")); + HandledInterrupts |=3D ISP1761_DC_INTERRUPT_RESUME; + } + if (DcInterrupts & ISP1761_DC_INTERRUPT_EP0SETUP) { + NumBytes =3D 512; + ReadEndpointBuffer (0x20, &NumBytes, &Packet); + ASSERT (NumBytes =3D=3D 8); + HandleDeviceRequest ((USB_DEVICE_REQUEST *) Packet); + HandledInterrupts |=3D ISP1761_DC_INTERRUPT_EP0SETUP; + } + if (DcInterrupts & ISP1761_DC_INTERRUPT_EP0RX) { + HandledInterrupts |=3D ISP1761_DC_INTERRUPT_EP0RX; + } + if (DcInterrupts & ISP1761_DC_INTERRUPT_EP0TX) { + if (mControlTxPending) { + // We previously put some data in the Control Endpoint's IN (Tx) FIF= O. + // We assume that that data has now been sent in response to the IN = token + // that triggered this interrupt. We can therefore go to the Status = stage + // of the control transfer. + StatusAcknowledge (ISP1761_EP0TX); + mControlTxPending =3D FALSE; + } + HandledInterrupts |=3D ISP1761_DC_INTERRUPT_EP0TX; + } + if (DcInterrupts & ISP1761_DC_INTERRUPT_EP1RX) { + NumBytes =3D 512; + DataPacket =3D AllocatePool (NumBytes); + Status =3D ReadEndpointBuffer (ISP1761_EP1RX, &NumBytes, DataPacket); + if (EFI_ERROR (Status) || NumBytes =3D=3D 0) { + if (EFI_ERROR (Status)) { + DEBUG ((EFI_D_ERROR, "Couldn't read EP1RX data: %r\n", Status)); + } + FreePool (DataPacket); + } else { + // Signal this event again so we poll again ASAP + gBS->SignalEvent (Event); + mDataReceivedCallback (NumBytes, DataPacket); + } + HandledInterrupts |=3D ISP1761_DC_INTERRUPT_EP1RX; + } + if (DcInterrupts & ISP1761_DC_INTERRUPT_EP1TX) { + mDataSentCallback (1); + HandledInterrupts |=3D ISP1761_DC_INTERRUPT_EP1TX; + } + if (DcInterrupts & (ISP1761_DC_INTERRUPT_SOF | ISP1761_DC_INTERRUPT_PSOF= )) { + // Don't care about SOFs or pseudo-SOFs + HandledInterrupts |=3D (ISP1761_DC_INTERRUPT_SOF | ISP1761_DC_INTERRUP= T_PSOF); + } + if (ISP1761_DC_INTERRUPT_BRESET) { + HandledInterrupts |=3D ISP1761_DC_INTERRUPT_BRESET; + } + if (ISP1761_DC_INTERRUPT_HS_STAT) { + HandledInterrupts |=3D ISP1761_DC_INTERRUPT_HS_STAT; + } + if (ISP1761_DC_INTERRUPT_VBUS) { + HandledInterrupts |=3D ISP1761_DC_INTERRUPT_VBUS; + } + + UnhandledInterrupts =3D DcInterrupts & (~HandledInterrupts) & ISP1761_DC= _INTERRUPT_MASK; + if (UnhandledInterrupts) { + DEBUG ((EFI_D_ERROR, "USB: Unhandled DC Interrupts: 0x%08x\n", + UnhandledInterrupts)); + } + + // Check if we received any more data while we were handling the interru= pt. + SelectEndpoint (ISP1761_EP1RX); + MoreBytes =3D READ_REG16 (ISP1761_BUFFER_LENGTH); + if (MoreBytes) { + HandledInterrupts &=3D ~ISP1761_DC_INTERRUPT_EP1RX; + } + + WRITE_REG32 (ISP1761_DC_INTERRUPT, HandledInterrupts); +} + +EFI_STATUS +Isp1761PeriphSend ( + IN UINT8 EndpointIndex, + IN UINTN Size, + IN CONST VOID *Buffer + ) +{ + return WriteEndpointBuffer ( + (EndpointIndex << 1) | 0x1, //Convert to ISP1761 endpoint index,= Tx + MAX_PACKET_SIZE_BULK, + Size, + Buffer + ); +} + +EFI_STATUS +EFIAPI +Isp1761PeriphStart ( + IN USB_DEVICE_DESCRIPTOR *DeviceDescriptor, + IN VOID **Descriptors, + IN USB_DEVICE_RX_CALLBACK RxCallback, + IN USB_DEVICE_TX_CALLBACK TxCallback + ) +{ + UINT16 OtgStatus; + UINT8 *Ptr; + EFI_STATUS Status; + EFI_EVENT TimerEvent; + + ASSERT (DeviceDescriptor !=3D NULL); + ASSERT (Descriptors[0] !=3D NULL); + ASSERT (RxCallback !=3D NULL); + ASSERT (TxCallback !=3D NULL); + + WRITE_REG32 (ISP1761_DEVICE_UNLOCK, ISP1761_DEVICE_UNLOCK_MAGIC); + + WRITE_REG32 (ISP1761_SW_RESET_REG, ISP1761_SW_RESET_ALL); + while (READ_REG32 (ISP1761_SW_RESET_REG) & ISP1761_SW_RESET_ALL) { + //busy wait + } + WRITE_REG32 (ISP1761_MODE, ISP1761_MODE_SFRESET); + while (READ_REG32 (ISP1761_MODE) & ISP1761_MODE_SFRESET) { + //busy wait + } + DEBUG ((EFI_D_INFO, "USB: Software reset done\n")); + + WRITE_REG32 (ISP1761_DC_INTERRUPT_ENABLE, 0x03FFFFFF); + WRITE_REG32 (ISP1761_OTG_INTERRUPT_ENABLE_RISE, 0x07FF); + + WRITE_REG8 (ISP1761_ADDRESS, ISP1761_ADDRESS_DEVEN); + WRITE_REG8 (ISP1761_MODE, ISP1761_MODE_WKUPCS | ISP1761_MODE_CLKAON); + + // Use port 1 as peripheral controller (magic - disagrees with datasheet) + WRITE_REG32 (ISP1761_OTG_CTRL_SET, 0xffff0000); + WRITE_REG32 (ISP1761_OTG_CTRL_SET, 0x000014d1); + + OtgStatus =3D READ_REG16 (ISP1761_OTG_STATUS); + if ((OtgStatus & ISP1761_OTG_STATUS_B_SESS_END) !=3D 0) { + DEBUG ((EFI_D_ERROR, "USB: Vbus not powered.\n")); + } + if ((OtgStatus & ISP1761_OTG_STATUS_A_B_SESS_VLD) =3D=3D 0) { + DEBUG ((EFI_D_ERROR, "USB: Session not valid.\n")); + } + + // Configure Control endpoints + SelectEndpoint (0x20); + WRITE_REG32 (ISP1761_ENDPOINT_MAX_PACKET_SIZE, MAX_PACKET_SIZE_CONTROL); + WRITE_REG32 (ISP1761_ENDPOINT_TYPE, ISP1761_ENDPOINT_TYPE_ENABLE); + SelectEndpoint (0x0); + WRITE_REG32 (ISP1761_ENDPOINT_MAX_PACKET_SIZE, MAX_PACKET_SIZE_CONTROL); + WRITE_REG32 (ISP1761_ENDPOINT_TYPE, ISP1761_ENDPOINT_TYPE_ENABLE); + SelectEndpoint (0x1); + WRITE_REG32 (ISP1761_ENDPOINT_MAX_PACKET_SIZE, MAX_PACKET_SIZE_CONTROL); + WRITE_REG32 (ISP1761_ENDPOINT_TYPE, ISP1761_ENDPOINT_TYPE_ENABLE); + + // Interrupt on all ACK and NAK + WRITE_REG32 (ISP1761_INTERRUPT_CONFIG, ISP1761_INTERRUPT_CONFIG_ACK_ONLY= ); + + mDeviceDescriptor =3D DeviceDescriptor; + mDescriptors =3D Descriptors[0]; + + // Right now we just support one configuration + ASSERT (mDeviceDescriptor->NumConfigurations =3D=3D 1); + // ... and one interface + mConfigDescriptor =3D (USB_CONFIG_DESCRIPTOR *)mDescriptors; + ASSERT (mConfigDescriptor->NumInterfaces =3D=3D 1); + + Ptr =3D ((UINT8 *) mDescriptors) + sizeof (USB_CONFIG_DESCRIPTOR); + mInterfaceDescriptor =3D (USB_INTERFACE_DESCRIPTOR *) Ptr; + Ptr +=3D sizeof (USB_INTERFACE_DESCRIPTOR); + + mEndpointDescriptors =3D (USB_ENDPOINT_DESCRIPTOR *) Ptr; + + mDataReceivedCallback =3D RxCallback; + mDataSentCallback =3D TxCallback; + + // Register a timer event so CheckInterrupts gets called periodically + Status =3D gBS->CreateEvent ( + EVT_TIMER | EVT_NOTIFY_SIGNAL, + TPL_CALLBACK, + CheckInterrupts, + NULL, + &TimerEvent + ); + ASSERT_EFI_ERROR (Status); + if (EFI_ERROR (Status)) { + return Status; + } + + Status =3D gBS->SetTimer ( + TimerEvent, + TimerPeriodic, + ISP1761_INTERRUPT_POLL_PERIOD + ); + ASSERT_EFI_ERROR (Status); + + return Status; +} + +USB_DEVICE_PROTOCOL mUsbDevice =3D { + Isp1761PeriphStart, + Isp1761PeriphSend +}; + + +EFI_STATUS +EFIAPI +Isp1761PeriphEntryPoint ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + UINT32 DeviceId; + EFI_HANDLE Handle; + + DeviceId =3D READ_REG32 (ISP1761_DEVICE_ID); + + if (DeviceId !=3D ISP1761_DEVICE_ID_VAL) { + DEBUG ((EFI_D_ERROR, + "ERROR: Read incorrect device ID for ISP1761: 0x%08x, expected 0x%08= x\n", + DeviceId , ISP1761_DEVICE_ID_VAL + )); + return EFI_DEVICE_ERROR; + } + + Handle =3D NULL; + return gBS->InstallProtocolInterface ( + &Handle, + &gUsbDeviceProtocolGuid, + EFI_NATIVE_INTERFACE, + &mUsbDevice + ); +} diff --git a/Platform/ARM/VExpressPkg/Drivers/Isp1761UsbDxe/Isp1761UsbDxe.h= b/Platform/ARM/VExpressPkg/Drivers/Isp1761UsbDxe/Isp1761UsbDxe.h new file mode 100644 index 000000000000..f7155d48d8ad --- /dev/null +++ b/Platform/ARM/VExpressPkg/Drivers/Isp1761UsbDxe/Isp1761UsbDxe.h @@ -0,0 +1,123 @@ +/** @file + + WARNING: + This driver fails to follow the UEFI driver model without a good + reason, and only remains in the tree because it is still used by + a small number of platforms. It will be removed when no longer used. + New platforms should not use it, and no one should use this as + reference code for developing new drivers. + + Copyright (c) 2013-2014, ARM Ltd. All rights reserved.
+ + SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#ifndef __ISP1761_USB_DXE_H__ +#define __ISP1761_USB_DXE_H__ + +#define ISP1761_USB_BASE FixedPcdGet32 (PcdIsp1761BaseAddress) + +#define READ_REG32(Offset) MmioRead32 (ISP1761_USB_BASE + Offset) +#define READ_REG16(Offset) (UINT16) READ_REG32 (Offset) +#define WRITE_REG32(Offset, Val) MmioWrite32 (ISP1761_USB_BASE + Offset, = Val) +#define WRITE_REG16(Offset, Val) MmioWrite32 (ISP1761_USB_BASE + Offset, = (UINT32) Val) +#define WRITE_REG8(Offset, Val) MmioWrite32 (ISP1761_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 ISP1761_NUM_ENDPOINTS 16 + +// Endpoint Indexes +#define ISP1761_EP0SETUP 0x20 +#define ISP1761_EP0RX 0x00 +#define ISP1761_EP0TX 0x01 +#define ISP1761_EP1RX 0x02 +#define ISP1761_EP1TX 0x03 + +// DcInterrupt bits +#define ISP1761_DC_INTERRUPT_BRESET BIT0 +#define ISP1761_DC_INTERRUPT_SOF BIT1 +#define ISP1761_DC_INTERRUPT_PSOF BIT2 +#define ISP1761_DC_INTERRUPT_SUSP BIT3 +#define ISP1761_DC_INTERRUPT_RESUME BIT4 +#define ISP1761_DC_INTERRUPT_HS_STAT BIT5 +#define ISP1761_DC_INTERRUPT_DMA BIT6 +#define ISP1761_DC_INTERRUPT_VBUS BIT7 +#define ISP1761_DC_INTERRUPT_EP0SETUP BIT8 +#define ISP1761_DC_INTERRUPT_EP0RX BIT10 +#define ISP1761_DC_INTERRUPT_EP0TX BIT11 +#define ISP1761_DC_INTERRUPT_EP1RX BIT12 +#define ISP1761_DC_INTERRUPT_EP1TX BIT13 +// All valid peripheral controller interrupts +#define ISP1761_DC_INTERRUPT_MASK 0x003FFFDFF + +#define ISP1761_ADDRESS 0x200 +#define ISP1761_ADDRESS_DEVEN BIT7 + +#define ISP1761_MODE 0x20C +#define ISP1761_MODE_DATA_BUS_WIDTH BIT8 +#define ISP1761_MODE_CLKAON BIT7 +#define ISP1761_MODE_SFRESET BIT4 +#define ISP1761_MODE_WKUPCS BIT2 + +#define ISP1761_ENDPOINT_MAX_PACKET_SIZE 0x204 + +#define ISP1761_ENDPOINT_TYPE 0x208 +#define ISP1761_ENDPOINT_TYPE_NOEMPKT BIT4 +#define ISP1761_ENDPOINT_TYPE_ENABLE BIT3 + +#define ISP1761_INTERRUPT_CONFIG 0x210 +// Interrupt config value to only interrupt on ACK of IN and OUT tokens +#define ISP1761_INTERRUPT_CONFIG_ACK_ONLY BIT2 | BIT5 | BIT6 + +#define ISP1761_DC_INTERRUPT 0x218 +#define ISP1761_DC_INTERRUPT_ENABLE 0x214 + +#define ISP1761_CTRL_FUNCTION 0x228 +#define ISP1761_CTRL_FUNCTION_VENDP BIT3 +#define ISP1761_CTRL_FUNCTION_DSEN BIT2 +#define ISP1761_CTRL_FUNCTION_STATUS BIT1 + +#define ISP1761_DEVICE_UNLOCK 0x27C +#define ISP1761_DEVICE_UNLOCK_MAGIC 0xAA37 + +#define ISP1761_SW_RESET_REG 0x30C +#define ISP1761_SW_RESET_ALL BIT0 + +#define ISP1761_DEVICE_ID 0x370 + +#define ISP1761_OTG_CTRL_SET 0x374 +#define ISP1761_OTG_CTRL_CLR OTG_CTRL_SET + 2 +#define ISP1761_OTG_CTRL_OTG_DISABLE BIT10 +#define ISP1761_OTG_CTRL_VBUS_CHRG BIT6 +#define ISP1761_OTG_CTRL_VBUS_DISCHRG BIT5 +#define ISP1761_OTG_CTRL_DM_PULLDOWN BIT2 +#define ISP1761_OTG_CTRL_DP_PULLDOWN BIT1 +#define ISP1761_OTG_CTRL_DP_PULLUP BIT0 + +#define ISP1761_OTG_STATUS 0x378 +#define ISP1761_OTG_STATUS_B_SESS_END BIT7 +#define ISP1761_OTG_STATUS_A_B_SESS_VLD BIT1 + +#define ISP1761_OTG_INTERRUPT_LATCH_SET 0x37C +#define ISP1761_OTG_INTERRUPT_LATCH_CLR 0x37E +#define ISP1761_OTG_INTERRUPT_ENABLE_RISE 0x384 + +#define ISP1761_DMA_ENDPOINT_INDEX 0x258 + +#define ISP1761_ENDPOINT_INDEX 0x22c +#define ISP1761_DATA_PORT 0x220 +#define ISP1761_BUFFER_LENGTH 0x21c + +// Device ID Values +#define PHILLIPS_VENDOR_ID_VAL 0x04cc +#define ISP1761_PRODUCT_ID_VAL 0x1761 +#define ISP1761_DEVICE_ID_VAL ((ISP1761_PRODUCT_ID_VAL << 16) |\ + PHILLIPS_VENDOR_ID_VAL) + +#endif //ifndef __ISP1761_USB_DXE_H__ diff --git a/Platform/ARM/VExpressPkg/Drivers/Isp1761UsbDxe/Isp1761UsbDxe.i= nf b/Platform/ARM/VExpressPkg/Drivers/Isp1761UsbDxe/Isp1761UsbDxe.inf new file mode 100644 index 000000000000..b161547bf73a --- /dev/null +++ b/Platform/ARM/VExpressPkg/Drivers/Isp1761UsbDxe/Isp1761UsbDxe.inf @@ -0,0 +1,39 @@ +#/** @file +# +# Copyright (c) 2013-2015, ARM Ltd. All rights reserved.
+# +# SPDX-License-Identifier: BSD-2-Clause-Patent +# +# +#**/ + +[Defines] + INF_VERSION =3D 0x00010005 + BASE_NAME =3D Isp1761PeriphDxe + FILE_GUID =3D 72d78ea6-4dee-11e3-8100-f3842a48d0a0 + MODULE_TYPE =3D UEFI_DRIVER + VERSION_STRING =3D 1.0 + ENTRY_POINT =3D Isp1761PeriphEntryPoint + +[Sources.common] + Isp1761UsbDxe.c + +[LibraryClasses] + DebugLib + IoLib + MemoryAllocationLib + UefiBootServicesTableLib + UefiDriverEntryPoint + +[Protocols] + gEfiDriverBindingProtocolGuid + gUsbDeviceProtocolGuid + +[Packages] + EmbeddedPkg/EmbeddedPkg.dec + MdePkg/MdePkg.dec + MdeModulePkg/MdeModulePkg.dec + Platform/ARM/VExpressPkg/ArmVExpressPkg.dec + +[Pcd] + gArmVExpressTokenSpaceGuid.PcdIsp1761BaseAddress --=20 2.17.1 -=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D- Groups.io Links: You receive all messages sent to this group. View/Reply Online (#58456): https://edk2.groups.io/g/devel/message/58456 Mute This Topic: https://groups.io/mt/73380300/1787277 Group Owner: devel+owner@edk2.groups.io Unsubscribe: https://edk2.groups.io/g/devel/unsub [importer@patchew.org] -=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-