From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from mail05.groups.io (mail05.groups.io [45.79.224.7]) by spool.mail.gandi.net (Postfix) with ESMTPS id B404EAC1812 for ; Wed, 1 May 2024 19:05:57 +0000 (UTC) DKIM-Signature: a=rsa-sha256; bh=KuYjfc5DC0adCd7FBSmF7Ov2mbzfy3djHZpqDcdLVq4=; c=relaxed/simple; d=groups.io; h=Received-SPF:From:To:CC:Subject:Date:Message-ID:In-Reply-To:References:MIME-Version:Precedence:List-Subscribe:List-Help:Sender:List-Id:Mailing-List:Delivered-To:Resent-Date:Resent-From:Reply-To:List-Unsubscribe-Post:List-Unsubscribe:Content-Transfer-Encoding:Content-Type; s=20240206; t=1714590356; v=1; b=K5DIXrflbITP/kCY0dBUCgBTNuBAp4YNwmPeCcQ1ZRyfrdzXPmJLbMdJa9IgqWsnh4kyQl1h //Ik13REs++2WMwLCmTJcRHmdLiOoxthD21z+aQK/3WmcW1RCukM+pIdKFXSth4ix7+ZHmTI+i3 6cytUzhZ5z87eph+pLTUUspdZ49OoO09Q79O/H4HtXXmg+rpDd6M2cvmnVYitYnFwxIyvNwprW1 NIw094vAo2uGum5Rm4J3sMJslQWp+IHmZBhL3tb2BZ5Sw9m4NcuJuUG8ZIW0lJ73OrESN3Ioy+u MbHArvQfILkEh2dn8K1caIN4vnTHLIwbCu8/cm0HXYnYg== X-Received: by 127.0.0.2 with SMTP id V1bLYY7687511xss1x93wwiP; Wed, 01 May 2024 12:05:56 -0700 X-Received: from NAM04-BN8-obe.outbound.protection.outlook.com (NAM04-BN8-obe.outbound.protection.outlook.com [40.107.100.87]) by mx.groups.io with SMTP id smtpd.web11.5070.1714590350489714712 for ; Wed, 01 May 2024 12:05:50 -0700 X-Received: from SJ0PR05CA0116.namprd05.prod.outlook.com (2603:10b6:a03:334::31) by PH7PR12MB7259.namprd12.prod.outlook.com (2603:10b6:510:207::14) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.7519.35; Wed, 1 May 2024 19:05:45 +0000 X-Received: from SJ5PEPF000001CD.namprd05.prod.outlook.com (2603:10b6:a03:334:cafe::c7) by SJ0PR05CA0116.outlook.office365.com (2603:10b6:a03:334::31) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.7544.28 via Frontend Transport; Wed, 1 May 2024 19:05:45 +0000 X-MS-Exchange-Authentication-Results: spf=pass (sender IP is 165.204.84.17) smtp.mailfrom=amd.com; dkim=none (message not signed) header.d=none;dmarc=pass action=none header.from=amd.com; Received-SPF: Pass (protection.outlook.com: domain of amd.com designates 165.204.84.17 as permitted sender) receiver=protection.outlook.com; client-ip=165.204.84.17; helo=SATLEXMB04.amd.com; pr=C X-Received: from SATLEXMB04.amd.com (165.204.84.17) by SJ5PEPF000001CD.mail.protection.outlook.com (10.167.242.42) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256) id 15.20.7544.18 via Frontend Transport; Wed, 1 May 2024 19:05:44 +0000 X-Received: from AUS-BIOSDEV-68.amd.com (10.180.168.240) by SATLEXMB04.amd.com (10.181.40.145) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256) id 15.1.2507.35; Wed, 1 May 2024 14:05:43 -0500 From: "Chesley, Brit via groups.io" To: CC: Abner Chang , Abdul Lateef Attar Subject: [edk2-devel] [PATCH v1 2/6] MdeModulePkg/Bus/Spi/SpiBus: Adding SpiBus Drivers Date: Wed, 1 May 2024 14:05:23 -0500 Message-ID: <20240501190527.200937-3-brit.chesley@amd.com> In-Reply-To: <20240501190527.200937-1-brit.chesley@amd.com> References: <20240501190527.200937-1-brit.chesley@amd.com> MIME-Version: 1.0 X-Originating-IP: [10.180.168.240] X-ClientProxiedBy: SATLEXMB03.amd.com (10.181.40.144) To SATLEXMB04.amd.com (10.181.40.145) X-EOPAttributedMessage: 0 X-MS-PublicTrafficType: Email X-MS-TrafficTypeDiagnostic: SJ5PEPF000001CD:EE_|PH7PR12MB7259:EE_ X-MS-Office365-Filtering-Correlation-Id: 64907d9c-fb9c-4efc-c3b4-08dc6a11b43c X-MS-Exchange-SenderADCheck: 1 X-MS-Exchange-AntiSpam-Relay: 0 X-Microsoft-Antispam-Message-Info: =?us-ascii?Q?vfecdn350NsNdN1YiciKu0hCis8twZFVVt2WekRNqh+1AEAUbYOpHMe8JAzF?= =?us-ascii?Q?HxEyVJyKneGa+wyVRbjuUe8qq21BRhDnqYT/6xo0Uw7udFsi1uNIX7XvgNBO?= =?us-ascii?Q?ckF2MvVEGNINMCD9AcnNLju1PGIEl3VMDaC+WWXj+bRgd1sc2x+394B6N56q?= =?us-ascii?Q?OZaXmtoqtyTU5JOLSErtCULQCXiJlNYWNKGQ7u8XXnJsTs2LYsdXBYwP0Q7H?= =?us-ascii?Q?syGsYKv9ALNZRM8nYq7/sE/5QMPF8wuRNL3jmwdh/1JSuiOCfupsFSQyAqgN?= =?us-ascii?Q?tFKQYSILhzJJauxOKvfSpluW9/t8aNdJiHdWsmY1o0rrqRJUFIsJtCIEUU9j?= =?us-ascii?Q?UghsKOoX/o+0sv35ciUGK5RDtyRJEoclY2fR2gUbyzwzkTDs0Q9wXum59vc4?= =?us-ascii?Q?91A67e8ehgP/lqd5hdsHaeX2di7Tkc8LoAs6k+Vwu6gEquwoQMnjivknevtM?= =?us-ascii?Q?1bZbGMhfP9l0ngixRD5ZnjpjeDs0panKeE1cU+FCGtTAGLzTdcuq4uV3U/uo?= =?us-ascii?Q?JW9zgy4koFaBFvWfrSImjWxqcw9sjLQVAs1l4/jkNNx4YcXTn9JcWAoaBaTt?= =?us-ascii?Q?UWn6liCSW9Wc2UJMLd80BEbgZlzhbf4+E7bodj6cKd8PiWNm9Xj8I0IaQ5Y5?= =?us-ascii?Q?+FeBIIUCIpFrADshjPOpr5cI6AWdFOCt8lizTKH61zGPxX5fp53dAPYTTvC1?= =?us-ascii?Q?3IzdVIY/9DbXel9jnEz6qQZGIXcmnR8nC+WOLcyN6WlNjUZ1nkLuN4hBCsO3?= =?us-ascii?Q?QocNM06NozRhwP+LUXCWRrSMPCUEUvQGyrAtBPecZC0tv8oijG66oHHxDnM+?= =?us-ascii?Q?abBfaHPtwVULWMFavqTNl8aDsLxbYMhEStrdFg4c+KJ5mwHDNvNleiumpya4?= =?us-ascii?Q?zbPhhzRmN1DqA9ZzF3ICfgcEtVoWnkZ0Igb+J04kKZAq7aREEWK5H5d+Ejj1?= =?us-ascii?Q?SGwoPiM0sZdz3r6ASYiod5F9m4tIB+vaH6g22V7cqdxMdW0s6y/eCwvtegC9?= =?us-ascii?Q?cLwZsiNLeoob0GlGxq1sxcQNP96KR/R6D+xlRS+mS6okxlP/hzP1HGXIY6S8?= =?us-ascii?Q?z8anB3xlAAGKH9LEYnlHyLZbJjvKDYWjN/9H32CrGT5ZMTB5vZqSRgIupdLt?= =?us-ascii?Q?ePz5lSg65ReqL1+dKlOq9sPyQQntb8HeDR9+P2THv0fGxHlxBY5h300VL4Fr?= =?us-ascii?Q?s0qVm2KBDGCXhinSCPatXb9rAEsMbMN7P4/Bc8RbbpCshOKVAjtvtMTrEoBz?= =?us-ascii?Q?VUBlw6lDKclZGKDB7sPlhzTW0Du9jOJCF3qAVXO68qCey4LisA7tHCKFGBt9?= =?us-ascii?Q?2IXB77fAc+YgEEfrzK5IQBGxhlPUZMoGJznkCDkwuDhPMCl1KDYOMkSyW+e3?= =?us-ascii?Q?5TolfbFHk7UK37LA/uoJop+0jjXV?= X-OriginatorOrg: amd.com X-MS-Exchange-CrossTenant-OriginalArrivalTime: 01 May 2024 19:05:44.9387 (UTC) X-MS-Exchange-CrossTenant-Network-Message-Id: 64907d9c-fb9c-4efc-c3b4-08dc6a11b43c X-MS-Exchange-CrossTenant-Id: 3dd8961f-e488-4e60-8e11-a82d994e183d X-MS-Exchange-CrossTenant-OriginalAttributedTenantConnectingIp: TenantId=3dd8961f-e488-4e60-8e11-a82d994e183d;Ip=[165.204.84.17];Helo=[SATLEXMB04.amd.com] X-MS-Exchange-CrossTenant-AuthSource: SJ5PEPF000001CD.namprd05.prod.outlook.com X-MS-Exchange-CrossTenant-AuthAs: Anonymous X-MS-Exchange-CrossTenant-FromEntityHeader: HybridOnPrem X-MS-Exchange-Transport-CrossTenantHeadersStamped: PH7PR12MB7259 Precedence: Bulk List-Subscribe: List-Help: Sender: devel@edk2.groups.io List-Id: Mailing-List: list devel@edk2.groups.io; contact devel+owner@edk2.groups.io Resent-Date: Wed, 01 May 2024 12:05:50 -0700 Resent-From: brit.chesley@amd.com Reply-To: devel@edk2.groups.io,brit.chesley@amd.com List-Unsubscribe-Post: List-Unsubscribe=One-Click List-Unsubscribe: X-Gm-Message-State: PrkkjrBsoLixO2ea4dPCuPLOx7686176AA= Content-Transfer-Encoding: quoted-printable Content-Type: text/plain X-GND-Status: LEGIT Authentication-Results: spool.mail.gandi.net; dkim=pass header.d=groups.io header.s=20240206 header.b=K5DIXrfl; dmarc=pass (policy=none) header.from=groups.io; spf=pass (spool.mail.gandi.net: domain of bounce@groups.io designates 45.79.224.7 as permitted sender) smtp.mailfrom=bounce@groups.io From: Brit Chesley Added SpiBus DXE and SMM drivers. This code translates SPI requests from the application layer into SPI Bus transactions on the SPI host controller. The code is responsible for checking if the transaction is valid, then setting up the SPI clock and chip select properly before passing the bus transaction to the host controller. Platform Initialization Spec 1.7 volume 5 section 18.1.6 Bugzilla #4753 Cc: Abner Chang Cc: Abdul Lateef Attar Signed-off-by: Brit Chesley --- MdeModulePkg/Bus/Spi/SpiBus/SpiBusDxe.inf | 41 ++ MdeModulePkg/Bus/Spi/SpiBus/SpiBusSmm.inf | 41 ++ MdeModulePkg/Bus/Spi/SpiBus/SpiBus.h | 167 +++++++++ MdeModulePkg/Bus/Spi/SpiBus/SpiBus.c | 433 ++++++++++++++++++++++ MdeModulePkg/Bus/Spi/SpiBus/SpiBusDxe.c | 198 ++++++++++ MdeModulePkg/Bus/Spi/SpiBus/SpiBusSmm.c | 162 ++++++++ MdeModulePkg/Bus/Spi/SpiBus/SpiBus.uni | 10 + 7 files changed, 1052 insertions(+) create mode 100644 MdeModulePkg/Bus/Spi/SpiBus/SpiBusDxe.inf create mode 100644 MdeModulePkg/Bus/Spi/SpiBus/SpiBusSmm.inf create mode 100644 MdeModulePkg/Bus/Spi/SpiBus/SpiBus.h create mode 100644 MdeModulePkg/Bus/Spi/SpiBus/SpiBus.c create mode 100644 MdeModulePkg/Bus/Spi/SpiBus/SpiBusDxe.c create mode 100644 MdeModulePkg/Bus/Spi/SpiBus/SpiBusSmm.c create mode 100644 MdeModulePkg/Bus/Spi/SpiBus/SpiBus.uni diff --git a/MdeModulePkg/Bus/Spi/SpiBus/SpiBusDxe.inf b/MdeModulePkg/Bus/S= pi/SpiBus/SpiBusDxe.inf new file mode 100644 index 000000000000..3e2cc2daba1c --- /dev/null +++ b/MdeModulePkg/Bus/Spi/SpiBus/SpiBusDxe.inf @@ -0,0 +1,41 @@ +## @file +# Component description for the SPI BUS DXE module +# +# Copyright (C) 2024 Advanced Micro Devices, Inc. All rights reserved. +# SPDX-License-Identifier: BSD-2-Clause-Patent +# +## +[Defines] + INF_VERSION =3D 1.27 + BASE_NAME =3D SpiBusDxe + FILE_GUID =3D 25CE038C-5C3A-4A9B-A111-90DF5897E058 + MODULE_TYPE =3D DXE_DRIVER + VERSION_STRING =3D 0.1 + PI_SPECIFICATION_VERSION =3D 0x0001000A + ENTRY_POINT =3D SpiBusEntry + +[Packages] + MdePkg/MdePkg.dec + +[LibraryClasses] + DebugLib + DevicePathLib + MemoryAllocationLib + UefiBootServicesTableLib + UefiDriverEntryPoint + +[Sources] + SpiBusDxe.c + SpiBus.c + SpiBus.h + +[Protocols] + gEfiSpiConfigurationProtocolGuid ## CONSUMES + gEfiSpiHcProtocolGuid ## CONSUMES + +[Depex] + gEfiSpiConfigurationProtocolGuid AND + gEfiSpiHcProtocolGuid + +[UserExtensions.TianoCore."ExtraFiles"] + SpiBus.uni diff --git a/MdeModulePkg/Bus/Spi/SpiBus/SpiBusSmm.inf b/MdeModulePkg/Bus/S= pi/SpiBus/SpiBusSmm.inf new file mode 100644 index 000000000000..9e3a5aae7d87 --- /dev/null +++ b/MdeModulePkg/Bus/Spi/SpiBus/SpiBusSmm.inf @@ -0,0 +1,41 @@ +## @file +# Component description for the SPI BUS SMM module +# +# Copyright (C) 2024 Advanced Micro Devices, Inc. All rights reserved. +# SPDX-License-Identifier: BSD-2-Clause-Patent +# +## +[Defines] + INF_VERSION =3D 1.27 + BASE_NAME =3D SpiBusSmm + FILE_GUID =3D 5DBB52E1-3D78-4C9C-A9D7-A43E79E93AC0 + MODULE_TYPE =3D DXE_SMM_DRIVER + VERSION_STRING =3D 0.1 + PI_SPECIFICATION_VERSION =3D 0x0001000A + ENTRY_POINT =3D SpiBusEntry + +[Packages] + MdePkg/MdePkg.dec + +[LibraryClasses] + DebugLib + DevicePathLib + MemoryAllocationLib + MmServicesTableLib + UefiDriverEntryPoint + +[Sources] + SpiBus.h + SpiBus.c + SpiBusSmm.c + +[Protocols] + gEfiSpiSmmConfigurationProtocolGuid ## CONSUME= S + gEfiSpiSmmHcProtocolGuid ## CONSUME= S + +[Depex] + gEfiSpiSmmConfigurationProtocolGuid AND + gEfiSpiSmmHcProtocolGuid + +[UserExtensions.TianoCore."ExtraFiles"] + SpiBus.uni diff --git a/MdeModulePkg/Bus/Spi/SpiBus/SpiBus.h b/MdeModulePkg/Bus/Spi/Sp= iBus/SpiBus.h new file mode 100644 index 000000000000..7a43f66ac750 --- /dev/null +++ b/MdeModulePkg/Bus/Spi/SpiBus/SpiBus.h @@ -0,0 +1,167 @@ +/** @file + + SPI bus driver + + Copyright (C) 2024 Advanced Micro Devices, Inc. All rights reserved.
+ SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#ifndef SPI_BUS_H_ +#define SPI_BUS_H_ + +#include +#include +#include +#include +#include +#include +#include +#include + +#define SPI_IO_SIGNATURE SIGNATURE_32 ('s', 'i', 'o', 'c') + +typedef struct { + UINTN Signature; + EFI_HANDLE Handle; + EFI_SPI_IO_PROTOCOL Protocol; + EFI_SPI_BUS_TRANSACTION BusTransaction; + EFI_SPI_CONFIGURATION_PROTOCOL *SpiConfig; + EFI_SPI_HC_PROTOCOL *SpiHc; + EFI_SPI_BUS *SpiBus; +} SPI_IO_CHIP; + +#define SPI_IO_CHIP_FROM_THIS(a) \ + CR (a, SPI_IO_CHIP, Protocol, \ + SPI_IO_SIGNATURE) + +/** + Checks if two device paths are the same + + @param[in] DevicePath1 First device path to compare + @param[in] DevicePath2 Second device path to compare + + @retval TRUE The device paths share the same nodes and valu= es + @retval FALSE The device paths differ +**/ +BOOLEAN +EFIAPI +DevicePathsAreEqual ( + IN CONST EFI_DEVICE_PATH_PROTOCOL *DevicePath1, + IN CONST EFI_DEVICE_PATH_PROTOCOL *DevicePath2 + ); + +/** + Initiate a SPI transaction between the host and a SPI peripheral. + + This routine must be called at or below TPL_NOTIFY. + This routine works with the SPI bus layer to pass the SPI transaction to= the + SPI controller for execution on the SPI bus. There are four types of + supported transactions supported by this routine: + * Full Duplex: WriteBuffer and ReadBuffer are the same size. + * Write Only: WriteBuffer contains data for SPI peripheral, ReadBytes = =3D 0 + * Read Only: ReadBuffer to receive data from SPI peripheral, WriteBytes = =3D 0 + * Write Then Read: WriteBuffer contains control data to write to SPI + peripheral before data is placed into the ReadBuffer. + Both WriteBytes and ReadBytes must be non-zero. + + @param[in] This Pointer to an EFI_SPI_IO_PROTOCOL structur= e. + @param[in] TransactionType Type of SPI transaction. + @param[in] DebugTransaction Set TRUE only when debugging is desired. + Debugging may be turned on for a single SP= I + transaction. Only this transaction will di= splay + debugging messages. All other transactions= with + this value set to FALSE will not display a= ny + debugging messages. + @param[in] ClockHz Specify the ClockHz value as zero (0) to u= se + the maximum clock frequency supported by t= he + SPI controller and part. Specify a non-zer= o + value only when a specific SPI transaction + requires a reduced clock rate. + @param[in] BusWidth Width of the SPI bus in bits: 1, 2, 4 + @param[in] FrameSize Frame size in bits, range: 1 - 32 + @param[in] WriteBytes The length of the WriteBuffer in bytes. + Specify zero for read-only operations. + @param[in] WriteBuffer The buffer containing data to be sent from= the + host to the SPI chip. Specify NULL for rea= d + only operations. + * Frame sizes 1-8 bits: UINT8 (one byte) p= er + frame + * Frame sizes 7-16 bits: UINT16 (two bytes= ) per + frame + * Frame sizes 17-32 bits: UINT32 (four byt= es) + per frame The transmit frame is in the l= east + significant N bits. + @param[in] ReadBytes The length of the ReadBuffer in bytes. + Specify zero for write-only operations. + @param[out] ReadBuffer The buffer to receeive data from the SPI c= hip + during the transaction. Specify NULL for w= rite + only operations. + * Frame sizes 1-8 bits: UINT8 (one byte) p= er + frame + * Frame sizes 7-16 bits: UINT16 (two bytes= ) per + frame + * Frame sizes 17-32 bits: UINT32 (four byt= es) + per frame The received frame is in the l= east + significant N bits. + + @retval EFI_SUCCESS The SPI transaction completed successfull= y + @retval EFI_BAD_BUFFER_SIZE The writeBytes value was invalid + @retval EFI_BAD_BUFFER_SIZE The ReadBytes value was invalid + @retval EFI_INVALID_PARAMETER TransactionType is not valid, + or BusWidth not supported by SPI peripher= al or + SPI host controller, + or WriteBytes non-zero and WriteBuffer is + NULL, + or ReadBytes non-zero and ReadBuffer is N= ULL, + or ReadBuffer !=3D WriteBuffer for full-d= uplex + type, + or WriteBuffer was NULL, + or TPL is too high + @retval EFI_OUT_OF_RESOURCES Insufficient memory for SPI transaction + @retval EFI_UNSUPPORTED The FrameSize is not supported by the SPI= bus + layer or the SPI host controller + @retval EFI_UNSUPPORTED The SPI controller was not able to suppor= t + +**/ +EFI_STATUS +EFIAPI +Transaction ( + IN CONST EFI_SPI_IO_PROTOCOL *This, + IN EFI_SPI_TRANSACTION_TYPE TransactionType, + IN BOOLEAN DebugTransaction, + IN UINT32 ClockHz OPTIONAL, + IN UINT32 BusWidth, + IN UINT32 FrameSize, + IN UINT32 WriteBytes, + IN UINT8 *WriteBuffer, + IN UINT32 ReadBytes, + OUT UINT8 *ReadBuffer + ); + +/** + Update the SPI peripheral associated with this SPI 10 instance. + + Support socketed SPI parts by allowing the SPI peripheral driver to repl= ace + the SPI peripheral after the connection is made. An example use is socke= ted + SPI NOR flash parts, where the size and parameters change depending upon + device is in the socket. + + @param[in] This Pointer to an EFI_SPI_IO_PROTOCOL structure. + @param[in] SpiPeripheral Pointer to an EFI_SPI_PERIPHERAL structure. + + @retval EFI_SUCCESS The SPI peripheral was updated successful= ly + @retval EFI_INVALID_PARAMETER The SpiPeripheral value is NULL, + or the SpiPeripheral->SpiBus is NULL, + or the SpiPeripheral->SpiBus pointing at + wrong bus, or the SpiPeripheral->SpiPart = is NULL + +**/ +EFI_STATUS +EFIAPI +UpdateSpiPeripheral ( + IN CONST EFI_SPI_IO_PROTOCOL *This, + IN CONST EFI_SPI_PERIPHERAL *SpiPeripheral + ); + +#endif //SPI_BUS_H_ diff --git a/MdeModulePkg/Bus/Spi/SpiBus/SpiBus.c b/MdeModulePkg/Bus/Spi/Sp= iBus/SpiBus.c new file mode 100644 index 000000000000..b183ca182cab --- /dev/null +++ b/MdeModulePkg/Bus/Spi/SpiBus/SpiBus.c @@ -0,0 +1,433 @@ +/** @file + + SpiBus driver + + Copyright (C) 2024 Advanced Micro Devices, Inc. All rights reserved.
+ SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ +#include +#include +#include +#include +#include +#include +#include "SpiBus.h" + +/** + Checks if two device paths are the same. + + @param[in] DevicePath1 First device path to compare + @param[in] DevicePath2 Second device path to compare + + @retval TRUE The device paths share the same nodes and valu= es + @retval FALSE The device paths differ +**/ +BOOLEAN +EFIAPI +DevicePathsAreEqual ( + IN CONST EFI_DEVICE_PATH_PROTOCOL *DevicePath1, + IN CONST EFI_DEVICE_PATH_PROTOCOL *DevicePath2 + ) +{ + UINTN Size1; + UINTN Size2; + + Size1 =3D GetDevicePathSize (DevicePath1); + Size2 =3D GetDevicePathSize (DevicePath2); + + if (Size1 !=3D Size2) { + return FALSE; + } + + if (CompareMem (DevicePath1, DevicePath2, Size1) !=3D 0) { + return FALSE; + } + + return TRUE; +} + +/** + Calls the SpiPeripherals ChipSelect if it is not null, otherwise + calls the Host Controllers ChipSelect function. + + @param[in] SpiChip The SpiChip to place on the bus via asserting = its chip select + @param[in] PinValue Value to place on the chip select pin + + @retval EFI_SUCCESS Chip select pin was placed at reques= ted level + @retval EFI_INVALID_PARAMETER Invalid parameters passed into ChipS= elect function +**/ +EFI_STATUS +EFIAPI +SpiChipSelect ( + IN CONST SPI_IO_CHIP *SpiChip, + IN BOOLEAN PinValue + ) +{ + EFI_STATUS Status; + + // Check which chip select function to use + if (SpiChip->Protocol.SpiPeripheral->ChipSelect !=3D NULL) { + Status =3D SpiChip->Protocol.SpiPeripheral->ChipSelect ( + SpiChip->BusTransaction.Sp= iPeripheral, + PinValue + ); + } else { + Status =3D SpiChip->SpiHc->ChipSelect ( + SpiChip->SpiHc, + SpiChip->BusTransaction.SpiPeripheral, + PinValue + ); + } + + return Status; +} + +/** + Checks the SpiChip's BusTransaction attributes to ensure its a valid SPI= transaction. + + @param[in] SpiChip The SpiChip where a bus transaction is request= ed + + @retval EFI_SUCCESS This is a valid SPI bus transaction + @retval EFI_BAD_BUFFER_SIZE The WriteBytes value was invalid + @retval EFI_BAD_BUFFER_SIZE The ReadBytes value was invalid + @retval EFI_INVALID_PARAMETER TransactionType is not valid, + or BusWidth not supported by SPI peripher= al or + SPI host controller, + or WriteBytes non-zero and WriteBuffer is + NULL, + or ReadBytes non-zero and ReadBuffer is N= ULL, + or ReadBuffer !=3D WriteBuffer for full-d= uplex + type, + or WriteBuffer was NULL, + or TPL is too high + @retval EFI_OUT_OF_RESOURCES Insufficient memory for SPI transaction + @retval EFI_UNSUPPORTED The FrameSize is not supported by the SPI= bus + layer or the SPI host controller + @retval EFI_UNSUPPORTED The SPI controller was not able to suppor= t +**/ +EFI_STATUS +EFIAPI +IsValidSpiTransaction ( + IN SPI_IO_CHIP *SpiChip + ) +{ + // Error checking + if (SpiChip->BusTransaction.TransactionType > SPI_TRANSACTION_WRITE_THEN= _READ) { + return EFI_INVALID_PARAMETER; + } + + if (((SpiChip->BusTransaction.BusWidth !=3D 1) && (SpiChip->BusTransacti= on.BusWidth !=3D 2) && (SpiChip->BusTransaction.BusWidth !=3D 4) && + (SpiChip->BusTransaction.BusWidth !=3D 8)) || (SpiChip->BusTransact= ion.FrameSize =3D=3D 0)) + { + return EFI_INVALID_PARAMETER; + } + + if ((SpiChip->BusTransaction.BusWidth =3D=3D 8) && (((SpiChip->Protocol.= Attributes & SPI_IO_SUPPORTS_8_BIT_DATA_BUS_WIDTH) !=3D SPI_IO_SUPPORTS_8_B= IT_DATA_BUS_WIDTH) || + ((SpiChip->BusTransactio= n.SpiPeripheral->Attributes & SPI_PART_SUPPORTS_8_BIT_DATA_BUS_WIDTH) !=3D = SPI_PART_SUPPORTS_8_BIT_DATA_BUS_WIDTH))) + { + return EFI_INVALID_PARAMETER; + } else if ((SpiChip->BusTransaction.BusWidth =3D=3D 4) && (((SpiChip->Pr= otocol.Attributes & SPI_IO_SUPPORTS_4_BIT_DATA_BUS_WIDTH) !=3D SPI_IO_SUPPO= RTS_4_BIT_DATA_BUS_WIDTH) || + ((SpiChip->BusTra= nsaction.SpiPeripheral->Attributes & SPI_PART_SUPPORTS_4_BIT_DATA_BUS_WIDTH= ) !=3D SPI_PART_SUPPORTS_4_BIT_DATA_BUS_WIDTH))) + { + return EFI_INVALID_PARAMETER; + } else if ((SpiChip->BusTransaction.BusWidth =3D=3D 2) && (((SpiChip->Pr= otocol.Attributes & SPI_IO_SUPPORTS_4_BIT_DATA_BUS_WIDTH) !=3D SPI_IO_SUPPO= RTS_4_BIT_DATA_BUS_WIDTH) || + ((SpiChip->BusTra= nsaction.SpiPeripheral->Attributes & SPI_PART_SUPPORTS_2_BIT_DATA_BUS_WIDTH= ) !=3D SPI_PART_SUPPORTS_2_BIT_DATA_BUS_WIDTH))) + { + return EFI_INVALID_PARAMETER; + } + + if (((SpiChip->BusTransaction.WriteBytes > 0) && (SpiChip->BusTransactio= n.WriteBuffer =3D=3D NULL)) || ((SpiChip->BusTransaction.ReadBytes > 0) && = (SpiChip->BusTransaction.ReadBuffer =3D=3D NULL))) { + return EFI_INVALID_PARAMETER; + } + + if ((SpiChip->BusTransaction.TransactionType =3D=3D SPI_TRANSACTION_FULL= _DUPLEX) && (SpiChip->BusTransaction.ReadBytes !=3D SpiChip->BusTransactio= n.WriteBytes)) { + return EFI_INVALID_PARAMETER; + } + + // Check frame size, passed parameter is in bits + if ((SpiChip->Protocol.FrameSizeSupportMask & (1<<(SpiChip->BusTransacti= on.FrameSize-1))) =3D=3D 0) { + return EFI_UNSUPPORTED; + } + + return EFI_SUCCESS; +} + +/** + Initiate a SPI transaction between the host and a SPI peripheral. + + This routine must be called at or below TPL_NOTIFY. + This routine works with the SPI bus layer to pass the SPI transaction to= the + SPI controller for execution on the SPI bus. There are four types of + supported transactions supported by this routine: + * Full Duplex: WriteBuffer and ReadBuffer are the same size. + * Write Only: WriteBuffer contains data for SPI peripheral, ReadBytes = =3D 0 + * Read Only: ReadBuffer to receive data from SPI peripheral, WriteBytes = =3D 0 + * Write Then Read: WriteBuffer contains control data to write to SPI + peripheral before data is placed into the ReadBuffer. + Both WriteBytes and ReadBytes must be non-zero. + + @param[in] This Pointer to an EFI_SPI_IO_PROTOCOL structur= e. + @param[in] TransactionType Type of SPI transaction. + @param[in] DebugTransaction Set TRUE only when debugging is desired. + Debugging may be turned on for a single SP= I + transaction. Only this transaction will di= splay + debugging messages. All other transactions= with + this value set to FALSE will not display a= ny + debugging messages. + @param[in] ClockHz Specify the ClockHz value as zero (0) to u= se + the maximum clock frequency supported by t= he + SPI controller and part. Specify a non-zer= o + value only when a specific SPI transaction + requires a reduced clock rate. + @param[in] BusWidth Width of the SPI bus in bits: 1, 2, 4 + @param[in] FrameSize Frame size in bits, range: 1 - 32 + @param[in] WriteBytes The length of the WriteBuffer in bytes. + Specify zero for read-only operations. + @param[in] WriteBuffer The buffer containing data to be sent from= the + host to the SPI chip. Specify NULL for rea= d + only operations. + * Frame sizes 1-8 bits: UINT8 (one byte) p= er + frame + * Frame sizes 7-16 bits: UINT16 (two bytes= ) per + frame + * Frame sizes 17-32 bits: UINT32 (four byt= es) + per frame The transmit frame is in the l= east + significant N bits. + @param[in] ReadBytes The length of the ReadBuffer in bytes. + Specify zero for write-only operations. + @param[out] ReadBuffer The buffer to receeive data from the SPI c= hip + during the transaction. Specify NULL for w= rite + only operations. + * Frame sizes 1-8 bits: UINT8 (one byte) p= er + frame + * Frame sizes 7-16 bits: UINT16 (two bytes= ) per + frame + * Frame sizes 17-32 bits: UINT32 (four byt= es) + per frame The received frame is in the l= east + significant N bits. + + @retval EFI_SUCCESS The SPI transaction completed successfull= y + @retval EFI_BAD_BUFFER_SIZE The WriteBytes value was invalid + @retval EFI_BAD_BUFFER_SIZE The ReadBytes value was invalid + @retval EFI_INVALID_PARAMETER TransactionType is not valid, + or BusWidth not supported by SPI peripher= al or + SPI host controller, + or WriteBytes non-zero and WriteBuffer is + NULL, + or ReadBytes non-zero and ReadBuffer is N= ULL, + or ReadBuffer !=3D WriteBuffer for full-d= uplex + type, + or WriteBuffer was NULL, + or TPL is too high + @retval EFI_OUT_OF_RESOURCES Insufficient memory for SPI transaction + @retval EFI_UNSUPPORTED The FrameSize is not supported by the SPI= bus + layer or the SPI host controller + @retval EFI_UNSUPPORTED The SPI controller was not able to suppor= t + +**/ +EFI_STATUS +EFIAPI +Transaction ( + IN CONST EFI_SPI_IO_PROTOCOL *This, + IN EFI_SPI_TRANSACTION_TYPE TransactionType, + IN BOOLEAN DebugTransaction, + IN UINT32 ClockHz OPTIONAL, + IN UINT32 BusWidth, + IN UINT32 FrameSize, + IN UINT32 WriteBytes, + IN UINT8 *WriteBuffer, + IN UINT32 ReadBytes, + OUT UINT8 *ReadBuffer + ) +{ + EFI_STATUS Status; + SPI_IO_CHIP *SpiChip; + UINT32 MaxClockHz; + UINT8 *DummyReadBuffer; + UINT8 *DummyWriteBuffer; + + SpiChip =3D SPI_IO_CHIP_FROM_THIS (This); + SpiChip->BusTransaction.SpiPeripheral =3D + (EFI_SPI_PERIPHERAL *)SpiChip->Protocol.SpiPeripheral; + SpiChip->BusTransaction.TransactionType =3D TransactionType; + SpiChip->BusTransaction.DebugTransaction =3D DebugTransaction; + SpiChip->BusTransaction.BusWidth =3D BusWidth; + SpiChip->BusTransaction.FrameSize =3D FrameSize; + SpiChip->BusTransaction.WriteBytes =3D WriteBytes; + SpiChip->BusTransaction.WriteBuffer =3D WriteBuffer; + SpiChip->BusTransaction.ReadBytes =3D ReadBytes; + SpiChip->BusTransaction.ReadBuffer =3D ReadBuffer; + + // Ensure valid spi transaction parameters + Status =3D IsValidSpiTransaction (SpiChip); + if (EFI_ERROR (Status)) { + return Status; + } + + // Setup the proper clock frequency + if (SpiChip->BusTransaction.SpiPeripheral->MaxClockHz !=3D 0) { + MaxClockHz =3D SpiChip->BusTransaction.SpiPeripheral->MaxClockHz; + } else { + MaxClockHz =3D SpiChip->BusTransaction.SpiPeripheral->SpiPart->MaxCloc= kHz; + } + + // Call proper clock function + if (SpiChip->Protocol.SpiPeripheral->SpiBus->Clock !=3D NULL) { + Status =3D SpiChip->Protocol.SpiPeripheral->SpiBus->Clock ( + SpiChip->BusTransa= ction.SpiPeripheral, + &MaxClockHz + ); + } else { + Status =3D SpiChip->SpiHc->Clock ( + SpiChip->SpiHc, + SpiChip->BusTransaction.SpiPeripheral, + &MaxClockHz + ); + } + + if (EFI_ERROR (Status)) { + return Status; + } + + Status =3D SpiChipSelect (SpiChip, SpiChip->BusTransaction.SpiPeripheral= ->SpiPart->ChipSelectPolarity); + + if (EFI_ERROR (Status)) { + return Status; + } + + // Check transaction types and match to HC capabilities + if ((TransactionType =3D=3D SPI_TRANSACTION_WRITE_ONLY) && + ((SpiChip->SpiHc->Attributes & HC_SUPPORTS_WRITE_ONLY_OPERATIONS) != =3D HC_SUPPORTS_WRITE_ONLY_OPERATIONS)) + { + // Convert to full duplex transaction + SpiChip->BusTransaction.ReadBytes =3D SpiChip->BusTransaction.WriteBy= tes; + SpiChip->BusTransaction.ReadBuffer =3D AllocateZeroPool (SpiChip->BusT= ransaction.ReadBytes); + + Status =3D SpiChip->SpiHc->Transaction ( + SpiChip->SpiHc, + &SpiChip->BusTransaction + ); + + SpiChip->BusTransaction.ReadBytes =3D ReadBytes; // assign to passed p= arameter + FreePool (SpiChip->BusTransaction.ReadBuffer); // Free temporary buffe= r + } else if ((TransactionType =3D=3D SPI_TRANSACTION_READ_ONLY) && + ((SpiChip->SpiHc->Attributes & HC_SUPPORTS_READ_ONLY_OPERATIO= NS) !=3D HC_SUPPORTS_READ_ONLY_OPERATIONS)) + { + // Convert to full duplex transaction + SpiChip->BusTransaction.WriteBytes =3D SpiChip->BusTransaction.WriteB= ytes; + SpiChip->BusTransaction.WriteBuffer =3D AllocateZeroPool (SpiChip->Bus= Transaction.WriteBytes); + + Status =3D SpiChip->SpiHc->Transaction ( + SpiChip->SpiHc, + &SpiChip->BusTransaction + ); + + SpiChip->BusTransaction.WriteBytes =3D WriteBytes; + FreePool (SpiChip->BusTransaction.WriteBuffer); + } else if ((TransactionType =3D=3D SPI_TRANSACTION_WRITE_THEN_READ) && + ((SpiChip->SpiHc->Attributes & HC_SUPPORTS_WRITE_THEN_READ_OP= ERATIONS) !=3D HC_SUPPORTS_WRITE_THEN_READ_OPERATIONS)) + { + // Convert to full duplex transaction + DummyReadBuffer =3D AllocateZeroPool (WriteBytes); + DummyWriteBuffer =3D AllocateZeroPool (ReadBytes); + SpiChip->BusTransaction.ReadBuffer =3D DummyReadBuffer; + SpiChip->BusTransaction.ReadBytes =3D WriteBytes; + + Status =3D SpiChip->SpiHc->Transaction ( + SpiChip->SpiHc, + &SpiChip->BusTransaction + ); + + if (EFI_ERROR (Status)) { + return Status; + } + + // Write is done, now need to read, restore passed in read buffer info + SpiChip->BusTransaction.ReadBuffer =3D ReadBuffer; + SpiChip->BusTransaction.ReadBytes =3D ReadBytes; + + SpiChip->BusTransaction.WriteBuffer =3D DummyWriteBuffer; + SpiChip->BusTransaction.WriteBytes =3D ReadBytes; + + Status =3D SpiChip->SpiHc->Transaction ( + SpiChip->SpiHc, + &SpiChip->BusTransaction + ); + // Restore write data + SpiChip->BusTransaction.WriteBuffer =3D WriteBuffer; + SpiChip->BusTransaction.WriteBytes =3D WriteBytes; + + FreePool (DummyReadBuffer); + FreePool (DummyWriteBuffer); + } else { + // Supported transaction type, just pass info the SPI HC Protocol Tran= saction + Status =3D SpiChip->SpiHc->Transaction ( + SpiChip->SpiHc, + &SpiChip->BusTransaction + ); + } + + if (EFI_ERROR (Status)) { + return Status; + } + + Status =3D SpiChipSelect (SpiChip, !SpiChip->BusTransaction.SpiPeriphera= l->SpiPart->ChipSelectPolarity); + + return Status; +} + +/** + Update the SPI peripheral associated with this SPI 10 SpiChip. + + Support socketed SPI parts by allowing the SPI peripheral driver to repl= ace + the SPI peripheral after the connection is made. An example use is socke= ted + SPI NOR flash parts, where the size and parameters change depending upon + device is in the socket. + + @param[in] This Pointer to an EFI_SPI_IO_PROTOCOL structure. + @param[in] SpiPeripheral Pointer to an EFI_SPI_PERIPHERAL structure. + + @retval EFI_SUCCESS The SPI peripheral was updated successful= ly + @retval EFI_INVALID_PARAMETER The SpiPeripheral value is NULL, + or the SpiPeripheral->SpiBus is NULL, + or the SpiPeripheral->SpiBus pointing at + wrong bus, or the SpiPeripheral->SpiPart = is NULL +**/ +EFI_STATUS +EFIAPI +UpdateSpiPeripheral ( + IN CONST EFI_SPI_IO_PROTOCOL *This, + IN CONST EFI_SPI_PERIPHERAL *SpiPeripheral + ) +{ + EFI_STATUS Status; + SPI_IO_CHIP *SpiChip; + + DEBUG ((DEBUG_VERBOSE, "%a: SPI Bus - Entry\n", __func__)); + + SpiChip =3D SPI_IO_CHIP_FROM_THIS (This); + + if ((SpiPeripheral =3D=3D NULL) || (SpiPeripheral->SpiBus =3D=3D NULL) |= | + (SpiPeripheral->SpiPart =3D=3D NULL)) + { + return EFI_INVALID_PARAMETER; + } + + // EFI_INVALID_PARAMETER if SpiPeripheral->SpiBus is pointing at wrong b= us + if (!DevicePathsAreEqual (SpiPeripheral->SpiBus->ControllerPath, SpiChip= ->SpiBus->ControllerPath)) { + return EFI_INVALID_PARAMETER; + } + + SpiChip->Protocol.OriginalSpiPeripheral =3D SpiChip->Protocol.SpiPeriphe= ral; + SpiChip->Protocol.SpiPeripheral =3D SpiPeripheral; + + Status =3D EFI_SUCCESS; + DEBUG (( + DEBUG_VERBOSE, + "%a: SPI Bus - Exit Status=3D%r\n", + __func__, + Status + )); + return Status; +} diff --git a/MdeModulePkg/Bus/Spi/SpiBus/SpiBusDxe.c b/MdeModulePkg/Bus/Spi= /SpiBus/SpiBusDxe.c new file mode 100644 index 000000000000..cd0a2c99a27b --- /dev/null +++ b/MdeModulePkg/Bus/Spi/SpiBus/SpiBusDxe.c @@ -0,0 +1,198 @@ +/** @file + + SPI bus DXE driver + + Copyright (C) 2024 Advanced Micro Devices, Inc. All rights reserved.
+ SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ +#include +#include +#include +#include +#include +#include +#include +#include +#include "SpiBus.h" + +/** + Entry point of the Spi Bus layer + + @param[in] ImageHandle Image handle of this driver. + @param[in] SystemTable Pointer to standard EFI system table. + + @retval EFI_SUCCESS Succeed. + @retval EFI_DEVICE_ERROR SpiPeripheral is NULL. + @retval EFI_NOT_FOUND Fail to locate SpiHcProtocol or SpiIoConfi= gurationProtocol + @retval EFI_OUT_OF_RESOURCES Failed to allocate SpiIoChip +**/ +EFI_STATUS +EFIAPI +SpiBusEntry ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + EFI_STATUS Status; + SPI_IO_CHIP *SpiChip; + EFI_SPI_HC_PROTOCOL *SpiHc; + EFI_SPI_CONFIGURATION_PROTOCOL *SpiConfiguration; + EFI_SPI_PERIPHERAL *SpiPeripheral; + EFI_SPI_BUS *Bus; + UINTN BusIndex; + UINTN HcIndex; + EFI_HANDLE *SpiHcHandles; + UINTN HandleCount; + EFI_DEVICE_PATH_PROTOCOL *SpiHcDevicePath; + + DEBUG ((DEBUG_VERBOSE, "%a - ENTRY\n", __func__)); + + // Get all SPI HC protocols, could be multiple SPI HC's on a single plat= form + Status =3D gBS->LocateHandleBuffer ( + ByProtocol, + &gEfiSpiHcProtocolGuid, + NULL, + &HandleCount, + &SpiHcHandles + ); + + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_VERBOSE, "No SpiHcProtocol is found\n")); + Status =3D EFI_NOT_FOUND; + goto Exit; + } + + // Locate the SPI Configuration Protocol + Status =3D gBS->LocateProtocol ( + &gEfiSpiConfigurationProtocolGuid, + NULL, + (VOID **)&SpiConfiguration + ); + + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_VERBOSE, "No SpiConfigurationProtocol is found\n")); + Status =3D EFI_NOT_FOUND; + goto Exit; + } + + // Parse through Hc protocols, find correct device path + for (HcIndex =3D 0; HcIndex < HandleCount; HcIndex++) { + Status =3D gBS->HandleProtocol ( + SpiHcHandles[HcIndex], + &gEfiDevicePathProtocolGuid, + (VOID **)&SpiHcDevicePath + ); + + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_VERBOSE, "Error locating EFI device path for this SPI = controller, status=3D%r \n", Status)); + continue; // Continue searching + } + + // Parse through SpiConfiguration's SpiBuses, find matching devicepath= for SpiHc + for (BusIndex =3D 0; BusIndex < SpiConfiguration->BusCount; BusIndex++= ) { + Bus =3D (EFI_SPI_BUS *)SpiConfiguration->Buslist[BusIndex]; + if (!DevicePathsAreEqual (SpiHcDevicePath, Bus->ControllerPath)) { + DEBUG ((DEBUG_VERBOSE, "SpiHc and SpiConfig device paths dont matc= h, continue parsing\n")); + continue; + } + + DEBUG (( + DEBUG_VERBOSE, + "%a: Found matching device paths, Enumerating SPI BUS: %s with Dev= icePath: %s\n", + __func__, + Bus->FriendlyName, + ConvertDevicePathToText (SpiHcDevicePath, FALSE, FALSE) + )); + + // Get SpiHc from the SpiHcHandles + Status =3D gBS->HandleProtocol ( + SpiHcHandles[HcIndex], + &gEfiDevicePathProtocolGuid, + (VOID **)&SpiHc + ); + + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_VERBOSE, "%a - Error getting SpiHc from Handle\n", _= _func__)); + goto Exit; + } + + SpiPeripheral =3D (EFI_SPI_PERIPHERAL *)Bus->Peripherallist; + if (SpiPeripheral !=3D NULL) { + do { + DEBUG (( + DEBUG_VERBOSE, + "%a: Installing SPI IO protocol for %s, by %s, PN=3D%s\n", + __func__, + SpiPeripheral->FriendlyName, + SpiPeripheral->SpiPart->Vendor, + SpiPeripheral->SpiPart->PartNumber + )); + // Allocate the SPI IO Device + SpiChip =3D AllocateZeroPool (sizeof (SPI_IO_CHIP)); + ASSERT (SpiChip !=3D NULL); + if (SpiChip !=3D NULL) { + // Fill in the SpiChip + SpiChip->Signature =3D SPI_IO_SIGNATURE; + SpiChip->SpiConfig =3D SpiConfiguration; + SpiChip->SpiHc =3D SpiHc; + SpiChip->SpiBus =3D Bus; + SpiChip->Protocol.SpiPeripheral =3D SpiPeripheral; + SpiChip->Protocol.OriginalSpiPeripheral =3D SpiPeripheral; + SpiChip->Protocol.FrameSizeSupportMask =3D SpiHc->FrameSizeSu= pportMask; + SpiChip->Protocol.MaximumTransferBytes =3D SpiHc->MaximumTran= sferBytes; + if ((SpiHc->Attributes & HC_TRANSFER_SIZE_INCLUDES_ADDRESS) != =3D 0) { + SpiChip->Protocol.Attributes |=3D SPI_IO_TRANSFER_SIZE_INCLU= DES_ADDRESS; + } + + if ((SpiHc->Attributes & HC_TRANSFER_SIZE_INCLUDES_OPCODE) != =3D 0) { + SpiChip->Protocol.Attributes |=3D SPI_IO_TRANSFER_SIZE_INCLU= DES_OPCODE; + } + + if ((SpiHc->Attributes & HC_SUPPORTS_8_BIT_DATA_BUS_WIDTH) != =3D 0) { + SpiChip->Protocol.Attributes |=3D SPI_IO_SUPPORTS_8_BIT_DATA= _BUS_WIDTH; + } + + if ((SpiHc->Attributes & HC_SUPPORTS_4_BIT_DATA_BUS_WIDTH) != =3D 0) { + SpiChip->Protocol.Attributes |=3D SPI_IO_SUPPORTS_4_BIT_DATA= _BUS_WIDTH; + } + + if ((SpiHc->Attributes & HC_SUPPORTS_2_BIT_DATA_BUS_WIDTH) != =3D 0) { + SpiChip->Protocol.Attributes |=3D SPI_IO_SUPPORTS_2_BIT_DATA= _BUS_WIDTH; + } + + SpiChip->Protocol.Transaction =3D Transaction; + SpiChip->Protocol.UpdateSpiPeripheral =3D UpdateSpiPeripheral; + // Install the SPI IO Protocol + Status =3D gBS->InstallProtocolInterface ( + &SpiChip->Handle, + (GUID *)SpiPeripheral->SpiPeripheralDriverGuid= , + EFI_NATIVE_INTERFACE, + &SpiChip->Protocol + ); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_VERBOSE, "%a - Error installing SpiIoProtocol\= n", __func__)); + continue; + } + } else { + Status =3D EFI_OUT_OF_RESOURCES; + DEBUG (( + DEBUG_ERROR, + "%a: Out of Memory resources\n", + __func__ + )); + break; + } + + SpiPeripheral =3D (EFI_SPI_PERIPHERAL *)SpiPeripheral->NextSpiPe= ripheral; + } while (SpiPeripheral !=3D NULL); + } else { + Status =3D EFI_DEVICE_ERROR; + } + } + } + +Exit: + DEBUG ((DEBUG_VERBOSE, "%a - EXIT (Status =3D %r)\n", __func__, Status))= ; + return Status; +} diff --git a/MdeModulePkg/Bus/Spi/SpiBus/SpiBusSmm.c b/MdeModulePkg/Bus/Spi= /SpiBus/SpiBusSmm.c new file mode 100644 index 000000000000..d9189b984835 --- /dev/null +++ b/MdeModulePkg/Bus/Spi/SpiBus/SpiBusSmm.c @@ -0,0 +1,162 @@ +/** @file + + SPI bus SMM driver + + Copyright (C) 2024 Advanced Micro Devices, Inc. All rights reserved.
+ SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ +#include +#include +#include +#include +#include +#include +#include +#include +#include "SpiBus.h" + +/** + Entry point of the Spi Bus layer + + @param[in] ImageHandle Image handle of this driver. + @param[in] SystemTable Pointer to standard EFI system table. + + @retval EFI_SUCCESS Succeed. + @retval EFI_DEVICE_ERROR Fail to install EFI_SPI_HC_PROTOCOL protocol. + @retval EFI_NOT_FOUND fail to locate SpiHcProtocol or SpiIoConfigura= tionProtocol + @retval EFI_OUT_OF_RESOURCES Failed to allocate SpiIoChip +**/ +EFI_STATUS +EFIAPI +SpiBusEntry ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + EFI_STATUS Status; + SPI_IO_CHIP *SpiChip; + EFI_SPI_HC_PROTOCOL *SpiHc; + EFI_SPI_CONFIGURATION_PROTOCOL *SpiConfiguration; + EFI_SPI_PERIPHERAL *SpiPeripheral; + EFI_SPI_BUS *Bus; + + DEBUG ((DEBUG_VERBOSE, "%a - ENTRY\n", __func__)); + + // Only a single Spi HC protocol in SMM + Status =3D gMmst->MmLocateProtocol ( + &gEfiSpiSmmHcProtocolGuid, + NULL, + (VOID **)&SpiHc + ); + + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_VERBOSE, "No SpiHcProtocol is found\n")); + Status =3D EFI_NOT_FOUND; + goto Exit; + } + + // Locate the SPI Configuration Protocol + Status =3D gMmst->MmLocateProtocol ( + &gEfiSpiSmmConfigurationProtocolGuid, + NULL, + (VOID **)&SpiConfiguration + ); + + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_VERBOSE, "No SpiConfigurationProtocol is found\n")); + Status =3D EFI_NOT_FOUND; + goto Exit; + } + + // Only one SpiBus supported in SMM + if (SpiConfiguration->BusCount !=3D 1) { + DEBUG ((DEBUG_VERBOSE, "Only one SPI Bus supported in SMM\n")); + Status =3D EFI_UNSUPPORTED; + goto Exit; + } + + Bus =3D (EFI_SPI_BUS *)SpiConfiguration->Buslist[0]; + + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_VERBOSE, "%a - Error getting SpiHc from Handle\n", __fun= c__)); + goto Exit; + } + + SpiPeripheral =3D (EFI_SPI_PERIPHERAL *)Bus->Peripherallist; + if (SpiPeripheral !=3D NULL) { + do { + DEBUG (( + DEBUG_VERBOSE, + "%a: Installing SPI IO protocol for %s, by %s, PN=3D%s\n", + __func__, + SpiPeripheral->FriendlyName, + SpiPeripheral->SpiPart->Vendor, + SpiPeripheral->SpiPart->PartNumber + )); + // Allocate the SPI IO Device + SpiChip =3D AllocateZeroPool (sizeof (SPI_IO_CHIP)); + ASSERT (SpiChip !=3D NULL); + if (SpiChip !=3D NULL) { + // Fill in the SpiChip + SpiChip->Signature =3D SPI_IO_SIGNATURE; + SpiChip->SpiConfig =3D SpiConfiguration; + SpiChip->SpiHc =3D SpiHc; + SpiChip->SpiBus =3D Bus; + SpiChip->Protocol.SpiPeripheral =3D SpiPeripheral; + SpiChip->Protocol.OriginalSpiPeripheral =3D SpiPeripheral; + SpiChip->Protocol.FrameSizeSupportMask =3D SpiHc->FrameSizeSuppor= tMask; + SpiChip->Protocol.MaximumTransferBytes =3D SpiHc->MaximumTransfer= Bytes; + if ((SpiHc->Attributes & HC_TRANSFER_SIZE_INCLUDES_ADDRESS) !=3D 0= ) { + SpiChip->Protocol.Attributes |=3D SPI_IO_TRANSFER_SIZE_INCLUDES_= ADDRESS; + } + + if ((SpiHc->Attributes & HC_TRANSFER_SIZE_INCLUDES_OPCODE) !=3D 0)= { + SpiChip->Protocol.Attributes |=3D SPI_IO_TRANSFER_SIZE_INCLUDES_= OPCODE; + } + + if ((SpiHc->Attributes & HC_SUPPORTS_8_BIT_DATA_BUS_WIDTH) !=3D 0)= { + SpiChip->Protocol.Attributes |=3D SPI_IO_SUPPORTS_8_BIT_DATA_BUS= _WIDTH; + } + + if ((SpiHc->Attributes & HC_SUPPORTS_4_BIT_DATA_BUS_WIDTH) !=3D 0)= { + SpiChip->Protocol.Attributes |=3D SPI_IO_SUPPORTS_4_BIT_DATA_BUS= _WIDTH; + } + + if ((SpiHc->Attributes & HC_SUPPORTS_2_BIT_DATA_BUS_WIDTH) !=3D 0)= { + SpiChip->Protocol.Attributes |=3D SPI_IO_SUPPORTS_2_BIT_DATA_BUS= _WIDTH; + } + + SpiChip->Protocol.Transaction =3D Transaction; + SpiChip->Protocol.UpdateSpiPeripheral =3D UpdateSpiPeripheral; + // Install the SPI IO Protocol + Status =3D gMmst->MmInstallProtocolInterface ( + &SpiChip->Handle, + (GUID *)SpiPeripheral->SpiPeripheralDriverGuid, + EFI_NATIVE_INTERFACE, + &SpiChip->Protocol + ); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_VERBOSE, "%a - Error installing SpiIoProtocol\n", = __func__)); + continue; + } + } else { + Status =3D EFI_OUT_OF_RESOURCES; + DEBUG (( + DEBUG_ERROR, + "%a: Out of Memory resources\n", + __func__ + )); + break; + } + + SpiPeripheral =3D (EFI_SPI_PERIPHERAL *)SpiPeripheral->NextSpiPeriph= eral; + } while (SpiPeripheral !=3D NULL); + } else { + Status =3D EFI_DEVICE_ERROR; + } + +Exit: + DEBUG ((DEBUG_VERBOSE, "%a - EXIT (Status =3D %r)\n", __func__, Status))= ; + return Status; +} diff --git a/MdeModulePkg/Bus/Spi/SpiBus/SpiBus.uni b/MdeModulePkg/Bus/Spi/= SpiBus/SpiBus.uni new file mode 100644 index 000000000000..0d913bdbae39 --- /dev/null +++ b/MdeModulePkg/Bus/Spi/SpiBus/SpiBus.uni @@ -0,0 +1,10 @@ +// /** @file +// +// Copyright (C) 2024 Advanced Micro Devices, Inc. All rights reserved. +// +// SPDX-License-Identifier: BSD-2-Clause-Patent +// +// **/ + +#string STR_PROPERTIES_MODULE_NAME +#language en-US "SPI Bus driver" --=20 2.42.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 (#118477): https://edk2.groups.io/g/devel/message/118477 Mute This Topic: https://groups.io/mt/105849135/7686176 Group Owner: devel+owner@edk2.groups.io Unsubscribe: https://edk2.groups.io/g/devel/unsub [rebecca@openfw.io] -=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-