From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received-SPF: Pass (sender SPF authorized) identity=mailfrom; client-ip=104.47.1.71; helo=eur01-ve1-obe.outbound.protection.outlook.com; envelope-from=pankaj.bansal@nxp.com; receiver=edk2-devel@lists.01.org Received: from EUR01-VE1-obe.outbound.protection.outlook.com (mail-ve1eur01on0071.outbound.protection.outlook.com [104.47.1.71]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-SHA384 (256/256 bits)) (No client certificate requested) by ml01.01.org (Postfix) with ESMTPS id B4C38223DB797 for ; Fri, 9 Feb 2018 03:49:29 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=nxp.com; s=selector1; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version; bh=k4Q6OiT9GkWrP4nzMMLPwxn5GQMYxboiTAwFKr5wY14=; b=NHpxTYBSMR1FKuib2iE8Qio0oj8f+7/yjhhrQpMpc+Cxwld1gTW4uimFhTqcRknVgxMzabweaBaFF/js1QrefhH91KWToFP+BzPBvCxjo87eMPoKVKX2lxu613pWZD6FXA0sTF6khaKWEaqSHWBw5GePgS8ypn0zwujkeH8xhCg= Authentication-Results: spf=none (sender IP is ) smtp.mailfrom=pankaj.bansal@nxp.com; Received: from uefi-workstation.ap.freescale.net (192.88.169.1) by VI1PR0402MB3951.eurprd04.prod.outlook.com (2603:10a6:803:23::23) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384_P256) id 15.20.464.11; Fri, 9 Feb 2018 11:55:10 +0000 From: Pankaj Bansal To: edk2-devel@lists.01.org Cc: Pankaj Bansal , Ard Biesheuvel , Leif Lindholm , Michael D Kinney Date: Fri, 9 Feb 2018 17:23:56 +0530 Message-Id: <1518177236-30343-2-git-send-email-pankaj.bansal@nxp.com> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1518177236-30343-1-git-send-email-pankaj.bansal@nxp.com> References: <1518177236-30343-1-git-send-email-pankaj.bansal@nxp.com> MIME-Version: 1.0 X-Originating-IP: [192.88.169.1] X-ClientProxiedBy: BMXPR01CA0004.INDPRD01.PROD.OUTLOOK.COM (2603:1096:b00:d::14) To VI1PR0402MB3951.eurprd04.prod.outlook.com (2603:10a6:803:23::23) X-MS-PublicTrafficType: Email X-MS-Office365-Filtering-HT: Tenant X-MS-Office365-Filtering-Correlation-Id: 8056697e-bd64-4e76-48d9-08d56fb3f973 X-Microsoft-Antispam: UriScan:; BCL:0; PCL:0; RULEID:(7020095)(4652020)(4534165)(4627221)(201703031133081)(201702281549075)(48565401081)(5600026)(4604075)(2017052603307)(7153060)(7193020); SRVR:VI1PR0402MB3951; X-Microsoft-Exchange-Diagnostics: 1; VI1PR0402MB3951; 3:8SCgIjWVWcJbWDVDBNlTqQGMKTgtT4MnqqiDDXVBEUZbWROjQzLPnEVLMzDne3WOLLT+uwPzVJdcKYimiDW8KwEzTdywvuPbFk5nrT8yusPBg6F2xowaxvJjo4dsCOseeJACwYL6Q/ce2X6SXIvUCcgsGs9bZSgsPqhi3ypM7lde2o4FCsW9zv4r63eU+sM7AHuG0Ls66gu1T6PSuRHurl1sBmQtqNobTDhgxS82S6JqmxsAELRR7UGJ9nNOvVlE; 25:HP5HwpKHvjA4qX216M0jtk0P2hGRf1PU+9WR+N3Ko8tosCGh473TW17kwR8ss7ZaqXEFrkVg75YBxer3YyRuq2+DgIN6ppgERdxqpFDecQTJng7G/hwC45aAZWIKwk00TC5NEWkhwJGddeBTojGgyA8uyb+xI7qJbebR61NL7SeHjwnMhOj5wLplasGJymEYQ0JSroLxEm7rTbLX4JdzRz5TCTtifKsKzQiIis3UtX+pEvk3/zcSIXL9fULnuoVNWytwi++7ZEm4vC5IDGxFOoKIkuxTvdSIi+W+pftdUOA9ojUwN6EeddYavryv8hmZ2fyy/vlN+1M3uemkJcmWqA==; 31:FgbM5I5CZhptFKbGP3yD055PX+UbDYMkFmqcnTH5PLCX6OjaPNPqEiXJsNbeN01thgO/cx2uP0nzzhQ5ymHo5//aAtwWSicvhkV/zDD1Id4+aYRn+s/m9r68Lyflga3sGncsN6jghhp4prKuZEoRzgvQnpPYDdXqQgwq1pW5f3/zfD4v2GBh0FYbq3IwEjYmYbN9Ql+Zy6p8rt99w0pYyfIdy5ooXeIonFKZSBB5xfs= X-MS-TrafficTypeDiagnostic: VI1PR0402MB3951: X-Microsoft-Exchange-Diagnostics: 1; VI1PR0402MB3951; 20:UOdsO3NfJ5xy8TT+E2U+nXUxMi+9Envxx24+3dWX6ttAT52z14c8JPn8492n6GGuPfaq1zxWJz95NDWlw+CpmI/FR0AEnydZUcknOcREOFOPRNYfGb3lAWnAoD7OCUec5UndWenudcL0reA+NJhpX0cJvUfGU6Q3Y7XyDZIUYujOtggbLi3n1qHzX8NQovCCaa+Z9kmojgOmOC9dks8HYdgPU3T8gzq0zlSjkaK8as/3PCNOjbbqOK8EagE6MMl58la/RmoWeZpDJR8WcayD47/StM/1eJElrw+L8hQckGutQz+nM/NKf4DgDPgj7vLiAoDkBl3J+iSb92gq85jV3ncViTNESceUl6XchVygXdQe1mZV/xngQKclc1e0HotFRi6sHnkxhu4DR215icThUlhUBqVlr9aOvLO5X6B9N2cLZ2EL3qieI7tzaWidLOtsNO12HOmg5FZddZ/HyPP+MnzIPtPbpv1751WBrKgN1j5ZifljyoPWryr7yl+q5BWA; 4:rNLNifkwfvN2hk6E9pil9Ma1HUdlzgMof/OCnUet57gvPsj9xKeM4DDIGsV2uWPOZT1UbVZO2ufyKQ8QrYBN9BLsYn2jhM6zeeqEWRne907IRWUmXs0aVLaaId7jWCrLTx31WFHVHthwM7YfRV/nLnMJ8voINN0X0X2z2ZBchb/vcCnX8Vf+GLrsJdMSFhkFI98x5lh3WmNz74CZpQ+SBIRa4WdstUJM9rhJJ9gbmViCnU4jhvpiySgA2BJbOA+yQdnolEom+oRLivA/Rh/kTUvR6ADqyaRmkCeaau3X3Jgu77Xz0aN2UmYT6n5KYelHCOpIorHjsl/a4+owuGYb1f3uW3iZjLjOR3SsKLHwsCoflBZQVGuMtuOdjTU9DNyR X-Microsoft-Antispam-PRVS: X-Exchange-Antispam-Report-Test: UriScan:(185117386973197)(788757137089)(228905959029699); X-Exchange-Antispam-Report-CFA-Test: BCL:0; PCL:0; RULEID:(6040501)(2401047)(5005006)(8121501046)(3002001)(3231101)(2400082)(944501161)(10201501046)(93006095)(93001095)(6055026)(6041288)(20161123562045)(20161123564045)(20161123560045)(20161123558120)(201703131423095)(201702281528075)(20161123555045)(201703061421075)(201703061406153)(6072148)(201708071742011); SRVR:VI1PR0402MB3951; BCL:0; PCL:0; RULEID:; SRVR:VI1PR0402MB3951; X-Forefront-PRVS: 057859F9C5 X-Forefront-Antispam-Report: SFV:NSPM; SFS:(10009020)(366004)(346002)(39860400002)(396003)(376002)(39380400002)(199004)(189003)(47776003)(6666003)(53936002)(5660300001)(6916009)(2950100002)(6512007)(53946003)(16200700003)(6306002)(16586007)(6486002)(16526019)(54906003)(186003)(86362001)(36756003)(316002)(575784001)(2906002)(26005)(105586002)(50226002)(8936002)(305945005)(81156014)(81166006)(8676002)(25786009)(7736002)(4326008)(48376002)(16799955002)(50466002)(15188155005)(2351001)(51416003)(386003)(59450400001)(106356001)(76176011)(2361001)(52116002)(97736004)(478600001)(966005)(66066001)(6506007)(68736007)(6116002)(3846002)(551934003)(53376002)(5890100001)(579004)(559001)(569006); DIR:OUT; SFP:1101; SCL:1; SRVR:VI1PR0402MB3951; H:uefi-workstation.ap.freescale.net; FPR:; SPF:None; PTR:InfoNoRecords; A:1; MX:1; LANG:en; Received-SPF: None (protection.outlook.com: nxp.com does not designate permitted sender hosts) X-Microsoft-Exchange-Diagnostics: =?us-ascii?Q?1; VI1PR0402MB3951; 23:9j+meEvh8bSPv6ouJpVuUBg2XWtSfRopdre6iD5?= =?us-ascii?Q?hnvNUb9S+0MB+DJM/yx+XnoLIRY3d4eIZ2BKbr4BmUKoKi8H7KeVOpUiV54M?= =?us-ascii?Q?ku2jk4DFUMukUC5y3JhhVau+cjSawkA03UrDab0gopghj7X9ZdLH23YX8JLv?= =?us-ascii?Q?DHei4uomOyAvpQbfar+supeE8bRAX8U/HpEZuo+D54XVW8yaL30biQx/367E?= =?us-ascii?Q?DkOsvZmhbR8qCr6dAk51CyfLroE8M8HGGyht3CDnm2K7o2IEKiVa1XJx3dL0?= =?us-ascii?Q?sz0FJgn2T9OxzaluSvgfE0MCF14cG+B5oCmlmUHqr9kHvIrCQA3cbQ1LGxAd?= =?us-ascii?Q?MuoySDNUq14Yyd6Z9GhR04MZpUhyxl/yWYOkk7XbDkaZW5y/22QaSDpQVQV4?= =?us-ascii?Q?AWWiM42mN5kzO9AO1zDOdaRsHW+48b/A0INXal5ecUFKGZe6LOdkiAnQLrpa?= =?us-ascii?Q?mKmWDc1+m5kvL4QQyTE0/cP6MgxLd0gIT5K8h0OHCspwtH86BAzDWNS9NP1M?= =?us-ascii?Q?1RXykSreA+4pR2ADrZPU3xWFpvaBatr9HCp6kwSkk2kCLVVzYK1mV4YKihj+?= =?us-ascii?Q?KoW8HDVYcyTOHnf3EbUVJghNHZ0pCWHGI1qsntqYL8jUViRsdnl9qeqtny1l?= =?us-ascii?Q?maqS3Jea3vKFhfO6K4P2aNErK0wK3Z1h9+VE4ebvYCfsPDqIa5kkGYJGOMYm?= =?us-ascii?Q?YdJuLyZUvirLUwPgW9HfGq4UcNnZ1Pb55cR9ZyGdLnpJ9jt09eNdWRW85oMr?= =?us-ascii?Q?jvXuQCd2W5Vo/Un7U/+qGBJUwc0o2NOeNRmsn4CaUh+PBKVLrQ7Wj3IUM0fp?= =?us-ascii?Q?yk3R0JdGrbTB/k8NySLUpMwGjGm/ovEVoT7ZtJu0yg5FP/nw6Iy1Pugn5c22?= =?us-ascii?Q?TythhSsCD4br1PxIFXCWKvYCNfr3muvF8m9oGYJaF1i1aUhP6QEyRrmOEY20?= =?us-ascii?Q?N3xnWSdibToJUEvwRxhhq7dL5zHrvMbJ8enYWiFdY4pPJYQKUuejlddBYuW4?= =?us-ascii?Q?dUEgCjt/tfwuXoU7tU2D6VMLtje6HLqjK+PcJqJDPVGi4M47Jq8LvZByD3Sh?= =?us-ascii?Q?+ZZ81tuP0Zbg71a025eIxIrMdPkLA32UXbVB2AYod9YVWjNBs/OLH8f8FIuz?= =?us-ascii?Q?SAoyXiis06xmO6WUdSWoSUeam18QH2xTDlvyJc90dN7mM4AmFa2sdUBmFrgh?= =?us-ascii?Q?S1XRJpUlKr+0ieii6nVzZgTZRlVzTQPH1OQpJVdScH0ybcF82GYtwgpT4QPy?= =?us-ascii?Q?GVv4h9t1H7sL0zqtHnpJYwvHfqd1Xg1/KPY8leqB3CJgXeVChfTN8qFoM69u?= =?us-ascii?Q?YQ1A6Mp2W/6SfcqohEoHi87r1qAofkPTDTnCPQn5cI7S1p73QLaNatY1KfVi?= =?us-ascii?Q?fJCX3Rgygdo+NXCMryn5MislmU4pZWl3r+0pjxWtk3qZZytQDdttv1/d1vgs?= =?us-ascii?Q?TcmiCwBDmIofXZVuzIt1Px0ZJ8LMXixGgMGhzvcjaeonq8Mfv+Lyv?= X-Microsoft-Exchange-Diagnostics: 1; VI1PR0402MB3951; 6:pRf+8yqaUmgN36TyVR22hXx3nlEQpyTiygQ/ncvbj6NQj3hdO5uiIZt2xMvmw6o7xQjxxtR8odsu8RLGvHfVEbHExyMww6RbD0Ocy0Vk/6dywKLBDjOlHZzpzQQky3gMOvkuTyJ2LO3qvtmix2lxtrapo4OWgJG+pjU8xcxx0/D5P6m+eRDzPhGicuwnisT1g7VzdJPLmQduGNaetcpHWfRd7kXH0k5LtLsmOjj+O0YWQWxbGOt7AWYDfQxFpVgEzZgSNv+J7/LoOs7NNu8o82YLGpCwhzWzryvrxygSNYPuFVJGEUatPDliLHVyaFwyU0mOoodjYWE+Ak7yF9Y4rODBWUioNQ6AoBeopsChnGw=; 5:za/W7ign7mKr6ivs6QCKORdeUn5d2Rtdn/JuVwAjVBvDWeptiBOFO4eomtDaZsCVVW+7tAG1r73S/HPS+YpEw7iLbIw9j+maVcO1kzLMij3Ff8/0G3giOBa+knyTWFs/1uLYcDok2mOTN3j9VbS5QgeJ0kMMnQAZ9fbQhc3zBz0=; 24:aAm/1L8ZTnh8QIvncaFHs3xcZ4rSI++ERqr227tCO5k2ReNTWU6WzzbdpoBVwZF/MlWlaC7gH6AAUYexWGxhG4q3rLVNsWup5nLspak9Sfw=; 7:Gd7GfdvQqWPNJ0HjwJwV6UY6YoFIUw1eWVtirGruLTI6YoHkH6BoLL4HODmZI20w+aH7UK7+o0WL3ltFtgpf4sB4gp2Y+wWU8/PjbOOOzrc4XN0noh95Ox5BkCrMiuKpY6yXcz8BDLFk44g3UCpip0v8hHtMlGEDaz3/o/jQgzhrEj9OdHdwU6nzX8yhjgSzUVG2cvSYNf2HpIYWd8u23sGJ9whK1WCLcYIb4ujtN+5c4GCWt5U8vcoFqP2Cv19K SpamDiagnosticOutput: 1:99 SpamDiagnosticMetadata: NSPM X-OriginatorOrg: nxp.com X-MS-Exchange-CrossTenant-OriginalArrivalTime: 09 Feb 2018 11:55:10.7548 (UTC) X-MS-Exchange-CrossTenant-Network-Message-Id: 8056697e-bd64-4e76-48d9-08d56fb3f973 X-MS-Exchange-CrossTenant-FromEntityHeader: Hosted X-MS-Exchange-CrossTenant-Id: 686ea1d3-bc2b-4c6f-a92c-d99c5c301635 X-MS-Exchange-Transport-CrossTenantHeadersStamped: VI1PR0402MB3951 Subject: [PATCH 2/2] NXP/SpiBusDxe: Add SPI Bus driver. X-BeenThere: edk2-devel@lists.01.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: EDK II Development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Fri, 09 Feb 2018 11:49:31 -0000 Content-Type: text/plain This Driver is based on revised PI 1.6 SPI specs. This driver is DXE_RUNTIME_DRIVER, so that the SPI peripherals that are needed to support runtime services can be used with this driver. This driver follows UEFI driver model and its a Bus Driver that creates all of its child handles on the first call to Start. Cc: Ard Biesheuvel Cc: Leif Lindholm Cc: Michael D Kinney Contributed-under: TianoCore Contribution Agreement 1.1 Signed-off-by: Pankaj Bansal --- Silicon/NXP/Drivers/SpiBusDxe/SpiBusDxe.c | 1548 +++++++++++++++++ Silicon/NXP/Drivers/SpiBusDxe/SpiBusDxe.h | 510 ++++++ Silicon/NXP/Drivers/SpiBusDxe/SpiBusDxe.inf | 53 + 3 files changed, 2111 insertions(+) diff --git a/Silicon/NXP/Drivers/SpiBusDxe/SpiBusDxe.c b/Silicon/NXP/Drivers/SpiBusDxe/SpiBusDxe.c new file mode 100644 index 0000000..70c0aba --- /dev/null +++ b/Silicon/NXP/Drivers/SpiBusDxe/SpiBusDxe.c @@ -0,0 +1,1548 @@ +/** @file + This file implements SPI IO Protocol which enables the user to manipulate a single + SPI device independent of the host controller and SPI design. + + Based on MdeModulePkg/Bus/I2c/I2cDxe/I2cBus.c + + Copyright (c) 2013 - 2015, Intel Corporation. All rights reserved.
+ Copyright 2018 NXP + + This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + + @par Specification Reference: + - UEFI 2.7 errata A, Chapter 8, Runtime Services + - UEFI 2.7 errata A, Chapter 10, Device Path Protocol + - UEFI 2.7 errata A, Chapter 11, UEFI Driver Model + - PI 1.6, Volume 5, Chapter 18 SPI Protocol Stack +**/ +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "SpiBusDxe.h" + +// +// Global Variables +// +extern EFI_COMPONENT_NAME_PROTOCOL gSpiBusComponentName; +extern EFI_COMPONENT_NAME2_PROTOCOL gSpiBusComponentName2; +extern EFI_DRIVER_BINDING_PROTOCOL gSpiBusDriverBinding; + +// +// EFI_DRIVER_BINDING_PROTOCOL instance +// +EFI_DRIVER_BINDING_PROTOCOL gSpiBusDriverBinding = { + .Supported = SpiBusDriverSupported, + .Start = SpiBusDriverStart, + .Stop = SpiBusDriverStop, + .Version = 0x10, + .ImageHandle = NULL, + .DriverBindingHandle = NULL +}; + +// +// Template for SPI Bus Context +// +SPI_BUS_CONTEXT gEfiSpiBusContextTemplate = { + .Signature = SPI_BUS_SIGNATURE, + .SpiHost = NULL, + .SpiBus = NULL, + .Link = { + .ForwardLink = NULL, + .BackLink = NULL + } +}; + +// +// Template for SPI Device Context +// +SPI_DEVICE_CONTEXT gEfiSpiDeviceContextTemplate = { + .Signature = SPI_DEVICE_SIGNATURE, + .Handle = NULL, + .SpiIo = { + .SpiPeripheral = NULL, + .OriginalSpiPeripheral = NULL, + .FrameSizeSupportMask = 0, + .MaximumTransferBytes = 1, + .Attributes = 0, + .LegacySpiProtocol = NULL, + .Transaction = SpiBusTransaction, + .UpdateSpiPeripheral = SpiBusUpdateSpiPeripheral + }, + .SpiBusContext = NULL, + .Link = { + .ForwardLink = NULL, + .BackLink = NULL + } +}; + +STATIC EFI_EVENT mSpiBusVirtualAddrChangeEvent; + +// Link list of SPI Buses that are runtime +STATIC LIST_ENTRY mSpiBusList = INITIALIZE_LIST_HEAD_VARIABLE (mSpiBusList); + +// Link list of SPI Devices that are runtime +STATIC LIST_ENTRY mSpiDeviceList = INITIALIZE_LIST_HEAD_VARIABLE (mSpiDeviceList); + +// +// Driver name table +// +GLOBAL_REMOVE_IF_UNREFERENCED EFI_UNICODE_STRING_TABLE mSpiBusDriverNameTable[] = { + { "eng;en", (CHAR16 *) L"SPI Bus Driver" }, + { NULL , NULL } +}; + +// +// EFI Component Name Protocol +// +GLOBAL_REMOVE_IF_UNREFERENCED EFI_COMPONENT_NAME_PROTOCOL gSpiBusComponentName = { + (EFI_COMPONENT_NAME_GET_DRIVER_NAME) SpiBusComponentNameGetDriverName, + (EFI_COMPONENT_NAME_GET_CONTROLLER_NAME) SpiBusComponentNameGetControllerName, + "eng" +}; + +// +// EFI Component Name 2 Protocol +// +GLOBAL_REMOVE_IF_UNREFERENCED EFI_COMPONENT_NAME2_PROTOCOL gSpiBusComponentName2 = { + SpiBusComponentNameGetDriverName, + SpiBusComponentNameGetControllerName, + "en" +}; + +/** + Retrieves a Unicode string that is the user readable name of the driver. + + This function retrieves the user readable name of a driver in the form of a + Unicode string. If the driver specified by This has a user readable name in + the language specified by Language, then a pointer to the driver name is + returned in DriverName, and EFI_SUCCESS is returned. If the driver specified + by This does not support the language specified by Language, + then EFI_UNSUPPORTED is returned. + + @param This[in] A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or + EFI_COMPONENT_NAME_PROTOCOL instance. + + @param Language[in] A pointer to a Null-terminated ASCII string + array indicating the language. This is the + language of the driver name that the caller is + requesting, and it must match one of the + languages specified in SupportedLanguages. The + number of languages supported by a driver is up + to the driver writer. Language is specified + in RFC 4646 or ISO 639-2 language code format. + + @param DriverName[out] A pointer to the Unicode string to return. + This Unicode string is the name of the + driver specified by This in the language + specified by Language. + + @retval EFI_SUCCESS The Unicode string for the Driver specified by + This and the language specified by Language was + returned in DriverName. + + @retval EFI_INVALID_PARAMETER Language is NULL. + + @retval EFI_INVALID_PARAMETER DriverName is NULL. + + @retval EFI_UNSUPPORTED The driver specified by This does not support + the language specified by Language. + +**/ +EFI_STATUS +EFIAPI +SpiBusComponentNameGetDriverName ( + IN EFI_COMPONENT_NAME2_PROTOCOL *This, + IN CHAR8 *Language, + OUT CHAR16 **DriverName + ) +{ + return LookupUnicodeString2 ( + Language, + This->SupportedLanguages, + mSpiBusDriverNameTable, + DriverName, + (BOOLEAN)(This != &gSpiBusComponentName2) + ); +} + +/** + Retrieves a Unicode string that is the user readable name of the controller + that is being managed by a driver. + + This function retrieves the user readable name of the controller specified by + ControllerHandle and ChildHandle in the form of a Unicode string. If the + driver specified by This has a user readable name in the language specified by + Language, then a pointer to the controller name is returned in ControllerName, + and EFI_SUCCESS is returned. If the driver specified by This is not currently + managing the controller specified by ControllerHandle and ChildHandle, + then EFI_UNSUPPORTED is returned. If the driver specified by This does not + support the language specified by Language, then EFI_UNSUPPORTED is returned. + + @param This[in] A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or + EFI_COMPONENT_NAME_PROTOCOL instance. + + @param ControllerHandle[in] The handle of a controller that the driver + specified by This is managing. This handle + specifies the controller whose name is to be + returned. + + @param ChildHandle[in] The handle of the child controller to retrieve + the name of. This is an optional parameter that + may be NULL. It will be NULL for device + drivers. It will also be NULL for a bus drivers + that wish to retrieve the name of the bus + controller. It will not be NULL for a bus + driver that wishes to retrieve the name of a + child controller. + + @param Language[in] A pointer to a Null-terminated ASCII string + array indicating the language. This is the + language of the driver name that the caller is + requesting, and it must match one of the + languages specified in SupportedLanguages. The + number of languages supported by a driver is up + to the driver writer. Language is specified in + RFC 4646 or ISO 639-2 language code format. + + @param ControllerName[out] A pointer to the Unicode string to return. + This Unicode string is the name of the + controller specified by ControllerHandle and + ChildHandle in the language specified by + Language from the point of view of the driver + specified by This. + + @retval EFI_SUCCESS The Unicode string for the user readable name in + the language specified by Language for the + driver specified by This was returned in + DriverName. + + @retval EFI_INVALID_PARAMETER ControllerHandle is NULL. + + @retval EFI_INVALID_PARAMETER ChildHandle is not NULL and it is not a valid + EFI_HANDLE. + + @retval EFI_INVALID_PARAMETER Language is NULL. + + @retval EFI_INVALID_PARAMETER ControllerName is NULL. + + @retval EFI_UNSUPPORTED The driver specified by This is not currently + managing the controller specified by + ControllerHandle and ChildHandle. + + @retval EFI_UNSUPPORTED The driver specified by This does not support + the language specified by Language. + +**/ +EFI_STATUS +EFIAPI +SpiBusComponentNameGetControllerName ( + IN EFI_COMPONENT_NAME2_PROTOCOL *This, + IN EFI_HANDLE ControllerHandle, + IN EFI_HANDLE ChildHandle OPTIONAL, + IN CHAR8 *Language, + OUT CHAR16 **ControllerName + ) +{ + return EFI_UNSUPPORTED; +} + +/** + Check if the Spi Host controller's device path exists in Spi Bus configuration + + @param[in] SpiBusConfig A pointer to the EFI_SPI_CONFIGURATION_PROTOCOL instance. + @param[in] ParentDevicePath A pointer to the Spi Host controller device path. + @param[Out] SpiBusIndex Index of Spi Bus corresponding to Spi Host controller which controls that SPI bus. + @param[Out] SpiBusRuntime Indicates weather Spi Bus is to be configured for runtime access. + + @retval EFI_SUCCESS Spi Bus Found. + @retval EFI_NOT_FOUND No Spi Bus Found. + @retval EFI_INVALID_PARAMETER Input Pointers are NULL. + +**/ +STATIC +EFI_STATUS +SearchSpiHostController ( + IN EFI_SPI_CONFIGURATION_PROTOCOL *SpiBusConfig, + IN EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath, + OUT UINT32 *SpiBusIndex, + OUT BOOLEAN *SpiBusRuntime + ) +{ + CONST EFI_SPI_BUS *SpiBus; + UINT32 Index; + EFI_STATUS Status; + + if (SpiBusConfig == NULL || ParentDevicePath == NULL || SpiBusIndex == NULL || SpiBusRuntime == NULL) { + return EFI_INVALID_PARAMETER; + } + + if (SpiBusConfig->Buslist == NULL || SpiBusConfig->BusCount == 0) { + return EFI_NOT_FOUND; + } + + for (Index = 0, Status = EFI_NOT_FOUND; Index < SpiBusConfig->BusCount; Index++) { + SpiBus = SpiBusConfig->Buslist[Index]; + if (SpiBus == NULL || SpiBus->ControllerPath == NULL) { + continue; + } + if (CompareMem (ParentDevicePath, SpiBus->ControllerPath, GetDevicePathSize (SpiBus->ControllerPath)) == 0) { + *SpiBusIndex = Index; + Status = EFI_SUCCESS; + if (SpiBus->RuntimePeripherallist != NULL) { + *SpiBusRuntime = TRUE; + } + break; + } + } + + return Status; +} + +/** + Tests to see if this driver supports a given controller. If a child device is provided, + it further tests to see if this driver supports creating a handle for the specified child device. + + This function checks to see if the driver specified by This supports the device specified by + ControllerHandle. Drivers will typically use the device path attached to + ControllerHandle and/or the services from the bus I/O abstraction attached to + ControllerHandle to determine if the driver supports ControllerHandle. This function + may be called many times during platform initialization. In order to reduce boot times, the tests + performed by this function must be very small, and take as little time as possible to execute. This + function must not change the state of any hardware devices, and this function must be aware that the + device specified by ControllerHandle may already be managed by the same driver or a + different driver. This function must match its calls to AllocatePages() with FreePages(), + AllocatePool() with FreePool(), and OpenProtocol() with CloseProtocol(). + Since ControllerHandle may have been previously started by the same driver, if a protocol is + already in the opened state, then it must not be closed with CloseProtocol(). This is required + to guarantee the state of ControllerHandle is not modified by this function. + + @param[in] This A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance. + @param[in] ControllerHandle The handle of the controller to test. This handle + must support a protocol interface that supplies + an I/O abstraction to the driver. + @param[in] RemainingDevicePath A pointer to the remaining portion of a device path. This + parameter is ignored by device drivers, and is optional for bus + drivers. For bus drivers, if this parameter is not NULL, then + the bus driver must determine if the bus controller specified + by ControllerHandle and the child controller specified + by RemainingDevicePath are both supported by this + bus driver. + + @retval EFI_SUCCESS The device specified by ControllerHandle and + RemainingDevicePath is supported by the driver specified by This. + @retval EFI_ALREADY_STARTED The device specified by ControllerHandle and + RemainingDevicePath is already being managed by the driver + specified by This. + @retval EFI_ACCESS_DENIED The device specified by ControllerHandle and + RemainingDevicePath is already being managed by a different + driver or an application that requires exclusive access. + Currently not implemented. + @retval EFI_UNSUPPORTED The device specified by ControllerHandle and + RemainingDevicePath is not supported by the driver specified by This. +**/ +EFI_STATUS +EFIAPI +SpiBusDriverSupported ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE Controller, + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath + ) +{ + EFI_STATUS Status; + EFI_SPI_HC_PROTOCOL *SpiHostController; + EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath; + EFI_DEVICE_PATH_PROTOCOL *DevPathNode; + EFI_HANDLE *Handle; + UINTN HandleCount; + + // + // Determine if the SPI Host controller Protocol is available + // + Status = gBS->OpenProtocol ( + Controller, + &gEfiSpiHcProtocolGuid, + (VOID **) &SpiHostController, + This->DriverBindingHandle, + Controller, + EFI_OPEN_PROTOCOL_BY_DRIVER + ); + if (EFI_ERROR (Status)) { + return Status; + } + + if (!EFI_ERROR (Status)) { + gBS->CloseProtocol ( + Controller, + &gEfiSpiHcProtocolGuid, + This->DriverBindingHandle, + Controller + ); + } + + // + // Determine if the Device Path protocol is available + // + Status = gBS->OpenProtocol ( + Controller, + &gEfiDevicePathProtocolGuid, + (VOID **) &ParentDevicePath, + This->DriverBindingHandle, + Controller, + EFI_OPEN_PROTOCOL_BY_DRIVER + ); + + if (EFI_ERROR (Status)) { + return Status; + } + + if (!EFI_ERROR (Status)) { + gBS->CloseProtocol ( + Controller, + &gEfiDevicePathProtocolGuid, + This->DriverBindingHandle, + Controller + ); + } + + if ((RemainingDevicePath != NULL) && !IsDevicePathEnd (RemainingDevicePath)) { + // + // Check if the first node of RemainingDevicePath is a hardware vendor device path + // + if ((DevicePathType (RemainingDevicePath) != HARDWARE_DEVICE_PATH) || + (DevicePathSubType (RemainingDevicePath) != HW_VENDOR_DP)) { + return EFI_UNSUPPORTED; + } + // + // Check if the second node of RemainingDevicePath is a controller node + // + DevPathNode = NextDevicePathNode (RemainingDevicePath); + if (!IsDevicePathEnd (DevPathNode)) { + if ((DevicePathType (DevPathNode) != HARDWARE_DEVICE_PATH) || + (DevicePathSubType (DevPathNode) != HW_CONTROLLER_DP)) { + return EFI_UNSUPPORTED; + } + } + } + + // + // Determine if the SPI Configuration Protocol is available + // + Status = gBS->LocateHandleBuffer ( + ByProtocol, + &gEfiSpiConfigurationProtocolGuid, + NULL, + &HandleCount, + &Handle + ); + if (EFI_ERROR (Status)) { + return Status; + } + + if (!EFI_ERROR (Status)) { + FreePool (Handle); + // Only one SpiConfiguration protocol is allowed + if (HandleCount != 1) { + Status = EFI_UNSUPPORTED; + } + } + + return Status; +} + +/** + Starts a device controller or a bus controller. + + The Start() function is designed to be invoked from the EFI boot service ConnectController(). + As a result, much of the error checking on the parameters to Start() has been moved into this + common boot service. It is legal to call Start() from other locations, + but the following calling restrictions must be followed or the system behavior will not be deterministic. + 1. ControllerHandle must be a valid EFI_HANDLE. + 2. If RemainingDevicePath is not NULL, then it must be a pointer to a naturally aligned + EFI_DEVICE_PATH_PROTOCOL. + 3. Prior to calling Start(), the Supported() function for the driver specified by This must + have been called with the same calling parameters, and Supported() must have returned EFI_SUCCESS. + + @param[in] This A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance. + @param[in] ControllerHandle The handle of the controller to start. This handle + must support a protocol interface that supplies + an I/O abstraction to the driver. + @param[in] RemainingDevicePath A pointer to the remaining portion of a device path. This + parameter is ignored by device drivers, and is optional for bus + drivers. For a bus driver, if this parameter is NULL, then handles + for all the children of Controller are created by this driver. + If this parameter is not NULL and the first Device Path Node is + not the End of Device Path Node, then only the handle for the + child device specified by the first Device Path Node of + RemainingDevicePath is created by this driver. + If the first Device Path Node of RemainingDevicePath is + the End of Device Path Node, no child handle is created by this + driver. + + @retval EFI_SUCCESS The device was started. + @retval EFI_DEVICE_ERROR The device could not be started due to a device error.Currently not implemented. + @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources. + @retval Others The driver failded to start the device. + +**/ +EFI_STATUS +EFIAPI +SpiBusDriverStart ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE Controller, + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath + ) +{ + SPI_BUS_CONTEXT *SpiBusContext; + EFI_STATUS Status; + EFI_SPI_HC_PROTOCOL *SpiHostController; + EFI_LEGACY_SPI_CONTROLLER_PROTOCOL *LegacySpiHostController; + EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath; + EFI_HANDLE *Handle; + UINTN HandleCount; + EFI_SPI_CONFIGURATION_PROTOCOL *SpiBusConfig; + UINT32 SpiBusIndex; + BOOLEAN SpiBusRuntime; + + SpiBusContext = NULL; + ParentDevicePath = NULL; + SpiHostController = NULL; + SpiBusConfig = NULL; + SpiBusIndex = 0; + SpiBusRuntime = FALSE; + LegacySpiHostController = NULL; + + // + // Determine if the SPI controller is available + // + Status = gBS->OpenProtocol ( + Controller, + &gEfiSpiHcProtocolGuid, + (VOID**)&SpiHostController, + This->DriverBindingHandle, + Controller, + EFI_OPEN_PROTOCOL_BY_DRIVER + ); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "SpiBus: open SPI host Controller error, Status = %r\n", Status)); + return Status; + } + + // + // Get the Device Path protocol + // + Status = gBS->OpenProtocol ( + Controller, + &gEfiDevicePathProtocolGuid, + (VOID **) &ParentDevicePath, + This->DriverBindingHandle, + Controller, + EFI_OPEN_PROTOCOL_BY_DRIVER + ); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "SpiBus: open device path error, Status = %r\n", Status)); + goto ErrorExit; + } + + if ((RemainingDevicePath != NULL) && IsDevicePathEnd (RemainingDevicePath)) { + // + // If RemainingDevicePath is the End of Device Path Node, + // don't create any child device and return EFI_SUCESS + // + return EFI_SUCCESS; + } + + // + // Get the Spi Bus Configuration protocol + // + Status = gBS->LocateHandleBuffer ( + ByProtocol, + &gEfiSpiConfigurationProtocolGuid, + NULL, + &HandleCount, + &Handle + ); + if (EFI_ERROR (Status) || (HandleCount != 1)) { + DEBUG (( + DEBUG_ERROR, + "SpiBus: SPI Configuration Protocol error, Status = %r, HandleCount =%lu\n", + Status, + HandleCount + )); + goto ErrorExit; + } + + // + // Open Spi Configuration Protocol + // + Status = gBS->HandleProtocol ( + Handle[0], + &gEfiSpiConfigurationProtocolGuid, + (VOID **)&SpiBusConfig + ); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "SpiBus: SPI Configuration Protocol error, Status = %r\n", Status)); + goto ErrorExit; + } + + Status = SearchSpiHostController (SpiBusConfig, ParentDevicePath, &SpiBusIndex, &SpiBusRuntime); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "SpiBus: Could not find Spi Host Controller Status = %r\n", Status)); + goto ErrorExit; + } + + // + // Allocate the buffer for SPI_BUS_CONTEXT. + // + if (SpiBusRuntime == FALSE) { + SpiBusContext = AllocateCopyPool (sizeof (SPI_BUS_CONTEXT), &gEfiSpiBusContextTemplate); + } else { + SpiBusContext = AllocateRuntimeCopyPool (sizeof (SPI_BUS_CONTEXT), &gEfiSpiBusContextTemplate); + } + if (SpiBusContext == NULL) { + DEBUG ((DEBUG_ERROR, "SpiBus: there is no enough memory to allocate.\n")); + Status = EFI_OUT_OF_RESOURCES; + goto ErrorExit; + } + + /* + +----------------+ + .->| SPI_BUS_CONTEXT| + | +----------------+ + | + | +----------------------------+ + | | SPI_DEVICE_CONTEXT | + `--| | + | | + | SPI IO Protocol Structure | <----- SPI IO Protocol + | | + +----------------------------+ + + */ + SpiBusContext->SpiHost = SpiHostController; + SpiBusContext->SpiBus = SpiBusConfig->Buslist[SpiBusIndex]; + SpiBusContext->DriverBindingHandle = This->DriverBindingHandle; + + Status = gBS->InstallMultipleProtocolInterfaces ( + &Controller, + &gEfiCallerIdGuid, SpiBusContext, + NULL + ); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "SpiBus: install private protocol error, Status = %r.\n", Status)); + goto ErrorExit; + } + + if (SpiBusRuntime == TRUE) { + InsertTailList (&mSpiBusList, &SpiBusContext->Link); + } + + // + // Determine if the SPI controller has installed Legacy Spi controller protocol + // + Status = gBS->OpenProtocol ( + Controller, + &gEfiLegacySpiControllerProtocolGuid, + (VOID**)&LegacySpiHostController, + This->DriverBindingHandle, + Controller, + EFI_OPEN_PROTOCOL_BY_DRIVER + ); + if (EFI_ERROR (Status) && Status != EFI_UNSUPPORTED) { + DEBUG ((DEBUG_ERROR, "SpiBus: open SPI host Controller error, Status = %r\n", Status)); + goto ErrorExit; + } + + // + // Start the driver + // + Status = RegisterSpiDevice (SpiBusContext, Controller, LegacySpiHostController, FALSE); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "SpiBus: Failed to register SPI peripherals on SPI bus Status = %r\n", Status)); + goto ErrorExit; + } + + if (SpiBusRuntime == TRUE) { + Status = RegisterSpiDevice (SpiBusContext, Controller, LegacySpiHostController, TRUE); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "SpiBus: Failed to register Runtime SPI peripherals on SPI bus Status = %r\n", Status)); + goto ErrorExit; + } + } + +ErrorExit: + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "SpiBus: Start() function failed, Status = %r\n", Status)); + if (ParentDevicePath != NULL) { + gBS->CloseProtocol ( + Controller, + &gEfiDevicePathProtocolGuid, + This->DriverBindingHandle, + Controller + ); + } + + if (SpiHostController != NULL) { + gBS->CloseProtocol ( + Controller, + &gEfiSpiHcProtocolGuid, + This->DriverBindingHandle, + Controller + ); + } + + if (Handle != NULL) { + FreePool (Handle); + } + + if (SpiBusContext != NULL) { + Status = gBS->UninstallMultipleProtocolInterfaces ( + &Controller, + gEfiCallerIdGuid, SpiBusContext, + NULL + ); + if (SpiBusRuntime == TRUE) { + RemoveEntryList (&SpiBusContext->Link); + } + FreePool (SpiBusContext); + } + + if (LegacySpiHostController != NULL) { + gBS->CloseProtocol ( + Controller, + &gEfiLegacySpiControllerProtocolGuid, + This->DriverBindingHandle, + Controller + ); + } + } + + // + // Return the operation status. + // + return Status; +} + + +/** + Stops a device controller or a bus controller. + + The Stop() function is designed to be invoked from the EFI boot service DisconnectController(). + As a result, much of the error checking on the parameters to Stop() has been moved + into this common boot service. It is legal to call Stop() from other locations, + but the following calling restrictions must be followed or the system behavior will not be deterministic. + 1. ControllerHandle must be a valid EFI_HANDLE that was used on a previous call to this + same driver's Start() function. + 2. The first NumberOfChildren handles of ChildHandleBuffer must all be a valid + EFI_HANDLE. In addition, all of these handles must have been created in this driver's + Start() function, and the Start() function must have called OpenProtocol() on + ControllerHandle with an Attribute of EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER. + + @param[in] This A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance. + @param[in] ControllerHandle A handle to the device being stopped. The handle must + support a bus specific I/O protocol for the driver + to use to stop the device. + @param[in] NumberOfChildren The number of child device handles in ChildHandleBuffer. + @param[in] ChildHandleBuffer An array of child handles to be freed. May be NULL + if NumberOfChildren is 0. + + @retval EFI_SUCCESS The device was stopped. + @retval EFI_DEVICE_ERROR The device could not be stopped due to a device error. + +**/ +EFI_STATUS +EFIAPI +SpiBusDriverStop ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE Controller, + IN UINTN NumberOfChildren, + IN EFI_HANDLE *ChildHandleBuffer + ) +{ + SPI_BUS_CONTEXT *SpiBusContext; + BOOLEAN SpiBusRuntime; + EFI_STATUS Status; + BOOLEAN AllChildrenStopped; + UINTN Index; + + if (NumberOfChildren == 0) { + gBS->CloseProtocol ( + Controller, + &gEfiDevicePathProtocolGuid, + This->DriverBindingHandle, + Controller + ); + + gBS->CloseProtocol ( + Controller, + &gEfiSpiHcProtocolGuid, + This->DriverBindingHandle, + Controller + ); + + gBS->CloseProtocol ( + Controller, + &gEfiLegacySpiControllerProtocolGuid, + This->DriverBindingHandle, + Controller + ); + // + // Get our context back + // + Status = gBS->OpenProtocol ( + Controller, + &gEfiCallerIdGuid, + (VOID **) &SpiBusContext, + This->DriverBindingHandle, + Controller, + EFI_OPEN_PROTOCOL_GET_PROTOCOL + ); + if (!EFI_ERROR (Status)) { + SpiBusRuntime = SpiBusContext->SpiBus->RuntimePeripherallist ? TRUE : FALSE; + + gBS->UninstallMultipleProtocolInterfaces ( + Controller, + &gEfiCallerIdGuid, SpiBusContext, + NULL + ); + // + // No more child now, free bus context data. + // + if (SpiBusRuntime) { + RemoveEntryList (&SpiBusContext->Link); + } + FreePool (SpiBusContext); + } + return Status; + } + + AllChildrenStopped = TRUE; + + for (Index = 0; Index < NumberOfChildren; Index++) { + + Status = UnRegisterSpiDevice (This, Controller, ChildHandleBuffer[Index]); + if (EFI_ERROR (Status)) { + AllChildrenStopped = FALSE; + } + } + + if (!AllChildrenStopped) { + return EFI_DEVICE_ERROR; + } + return EFI_SUCCESS; +} + +/** + Enumerate the SPI bus + + This routine walks the platform specific data describing the + SPI bus to create the SPI devices where driver GUIDs were + specified. + + @param[in] SpiBusContext Address of an SPI_BUS_CONTEXT structure + @param[in] Controller Handle to the controller + @param[in] LegacySpiHostController A pointer to the LEGACY_SPI_CONTROLLER_PROTOCOL + interface installed on controller. + @param[in] RegisterRuntime Weather to register runtime SPI devices or non runtime + Spi devices. + + @retval EFI_SUCCESS The bus is successfully configured + +**/ +EFI_STATUS +RegisterSpiDevice ( + IN SPI_BUS_CONTEXT *SpiBusContext, + IN EFI_HANDLE Controller, + IN EFI_LEGACY_SPI_CONTROLLER_PROTOCOL *LegacySpiHostController, + IN BOOLEAN RegisterRuntime + ) +{ + CONST EFI_SPI_PERIPHERAL *SpiPeripheral; + SPI_DEVICE_CONTEXT *SpiDeviceContext; + UINT32 SpiAttributes; + EFI_STATUS Status; + + Status = EFI_SUCCESS; + SpiDeviceContext = NULL; + if (RegisterRuntime == FALSE) { + SpiPeripheral = SpiBusContext->SpiBus->Peripherallist; + } else { + SpiPeripheral = SpiBusContext->SpiBus->RuntimePeripherallist; + } + + // + // Walk the list of SPI devices on this bus + // + for ( ; SpiPeripheral != NULL; SpiPeripheral = SpiPeripheral->NextSpiPeripheral) { + // + // Determine if the device info is valid + // + if ((SpiPeripheral->SpiPeripheralDriverGuid == NULL) + || (SpiPeripheral->SpiPart == NULL) + || (SpiPeripheral->SpiBus != SpiBusContext->SpiBus) + || (SpiPeripheral->ChipSelectParameter == NULL)) + { + DEBUG ((DEBUG_ERROR, "Invalid EFI_SPI_PERIPHERAL reported by Spi Configuration protocol.\n")); + continue; + } + + // + // Build the device context for current SPI device. + // + if (RegisterRuntime == FALSE) { + SpiDeviceContext = AllocateCopyPool (sizeof (SPI_DEVICE_CONTEXT), &gEfiSpiDeviceContextTemplate); + } else { + SpiDeviceContext = AllocateRuntimeCopyPool (sizeof (SPI_DEVICE_CONTEXT), &gEfiSpiDeviceContextTemplate); + } + + if (SpiDeviceContext == NULL) { + DEBUG ((DEBUG_ERROR, "Failed to allocate memory for SPI device context.\n")); + continue; + } + + // + // Initialize the specific device context + // + SpiDeviceContext->SpiBusContext = SpiBusContext; + SpiDeviceContext->SpiIo.SpiPeripheral = SpiPeripheral; + SpiDeviceContext->SpiIo.OriginalSpiPeripheral = SpiPeripheral; + SpiDeviceContext->SpiIo.FrameSizeSupportMask = SpiBusContext->SpiHost->FrameSizeSupportMask; + SpiDeviceContext->SpiIo.MaximumTransferBytes = SpiBusContext->SpiHost->MaximumTransferBytes; + SpiAttributes = SpiBusContext->SpiHost->Attributes; + // SPI Io attributes are least attributes supported by both SPI peripheral and SPI Host controller + SpiAttributes = BitFieldOr32 ( + SpiAttributes, + __builtin_ctz (SPI_HALF_DUPLEX), + __builtin_ctz (SPI_SUPPORTS_READ_ONLY_OPERATIONS), + SpiPeripheral->Attributes + ); + + SpiAttributes = BitFieldAnd32 ( + SpiAttributes, + __builtin_ctz (SPI_SUPPORTS_DTR_OPERATIONS), + __builtin_ctz (SPI_SUPPORTS_8_BIT_DATA_BUS_WIDTH), + SpiPeripheral->Attributes + ); + + SpiDeviceContext->SpiIo.Attributes = SpiAttributes; + SpiDeviceContext->SpiIo.LegacySpiProtocol = LegacySpiHostController; + + // + // Install the protocol + // + Status = gBS->InstallMultipleProtocolInterfaces ( + &SpiDeviceContext->Handle, + SpiPeripheral->SpiPeripheralDriverGuid, &SpiDeviceContext->SpiIo, + &gEfiCallerIdGuid, SpiDeviceContext, + NULL + ); + if (EFI_ERROR (Status)) { + // + // Free resources for this SPI device + // + ReleaseSpiDeviceContext (SpiDeviceContext); + continue; + } + + // + // Create the child handle + // + Status = gBS->OpenProtocol ( + Controller, + &gEfiSpiHcProtocolGuid, + (VOID **) &SpiBusContext->SpiHost, + SpiBusContext->DriverBindingHandle, + SpiDeviceContext->Handle, + EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER + ); + if (EFI_ERROR (Status)) { + Status = gBS->UninstallMultipleProtocolInterfaces ( + SpiDeviceContext->Handle, + SpiPeripheral->SpiPeripheralDriverGuid, &SpiDeviceContext->SpiIo, + &gEfiCallerIdGuid, SpiDeviceContext, + NULL + ); + // + // Free resources for this SPI device + // + ReleaseSpiDeviceContext (SpiDeviceContext); + continue; + } + + // + // Child has been created successfully + // + if (RegisterRuntime == TRUE) { + InsertTailList (&mSpiDeviceList, &SpiDeviceContext->Link); + } + } + + return Status; +} + +/** + 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 transactions to the + SPI controller for execution on the SPI bus. + + @param[in] This Pointer to an EFI_SPI_IO_PROTOCOL structure. + @param[in] RequestPacket Pointer to an EFI_SPI_REQUEST_PACKET + structure describing the SPI transactions. + + @param[in] ClockHz Specify the ClockHz value as zero (0) to use + the maximum clock frequency supported by the + SPI controller and part. Specify a non-zero + value only when a specific SPI transaction + requires a reduced clock rate. + + @retval EFI_SUCCESS The transaction completed successfully. + @retval EFI_ALREADY_STARTED The controller is busy with another transaction. + @retval EFI_BAD_BUFFER_SIZE The Length value in SPI Transaction is wrong. + @retval EFI_DEVICE_ERROR There was an SPI error during the transaction. + @retval EFI_INVALID_PARAMETER The parameters specified in RequestPacket are not + Valid. or the RequestPacket is NULL. + @retval EFI_NOT_READY Support for the chip select is not properly + initialized + @retval EFI_INVALID_PARAMETER The ChipSeLect value or its contents are + invalid + @retval EFI_NO_RESPONSE The SPI device is not responding to the slave + address. EFI_DEVICE_ERROR will be returned if + the controller cannot distinguish when the NACK + occurred. + @retval EFI_UNSUPPORTED The controller does not support the requested + transaction. or The SPI controller was not able to support + the frequency requested by ClockHz +**/ +EFI_STATUS +SpiBusTransaction ( + IN CONST EFI_SPI_IO_PROTOCOL *This, + IN EFI_SPI_REQUEST_PACKET *RequestPacket, + IN UINT32 ClockHz OPTIONAL + ) +{ + EFI_STATUS Status; + SPI_DEVICE_CONTEXT *SpiDeviceContext; + SPI_BUS_CONTEXT *SpiBusContext; + CONST EFI_SPI_HC_PROTOCOL *SpiHostController; + CONST EFI_SPI_BUS *SpiBus; + CONST EFI_SPI_PERIPHERAL *SpiPeripheral; + UINT32 RequestedClockHz; + BOOLEAN ChipSelectPolarity; + + if (This == NULL || RequestPacket == NULL) { + return EFI_INVALID_PARAMETER; + } + + // Backup requested clock frequency + RequestedClockHz = ClockHz; + + SpiPeripheral = This->SpiPeripheral; + ASSERT (SpiPeripheral != NULL || SpiPeripheral->SpiPart != NULL); + + SpiDeviceContext = SPI_DEVICE_CONTEXT_FROM_PROTOCOL (This); + SpiBusContext = SpiDeviceContext->SpiBusContext; + ASSERT (SpiBusContext != NULL); + + SpiHostController = SpiBusContext->SpiHost; + SpiBus = SpiBusContext->SpiBus; + ASSERT (SpiHostController != NULL || SpiBus != NULL); + + // The SPI transaction consists of: + // 1. Adjusting the clock speed, polarity and phase for a SPI peripheral + if (RequestedClockHz == 0) { + if (SpiPeripheral->MaxClockHz != 0) { + ClockHz = MIN (SpiPeripheral->MaxClockHz, SpiPeripheral->SpiPart->MaxClockHz); + } else { + ClockHz = SpiPeripheral->SpiPart->MaxClockHz; + } + RequestedClockHz = ClockHz; + } else { + if (SpiPeripheral->MaxClockHz != 0) { + if (RequestedClockHz > MIN (SpiPeripheral->MaxClockHz, SpiPeripheral->SpiPart->MaxClockHz)) { + return EFI_UNSUPPORTED; + } + } else { + if (RequestedClockHz > SpiPeripheral->SpiPart->MaxClockHz) { + return EFI_UNSUPPORTED; + } + } + } + + if (SpiBus->Clock != NULL) { + Status = SpiBus->Clock (SpiPeripheral, &ClockHz); + } else { + Status = SpiHostController->Clock (SpiHostController, SpiPeripheral, &ClockHz); + } + if (EFI_ERROR (Status)) { + return Status; + } else if (ClockHz > RequestedClockHz) { + return EFI_UNSUPPORTED; + } + + // 2. Use the chip select to enable the SPI peripheral, signaling the transaction start to the chip + ChipSelectPolarity = SpiPeripheral->SpiPart->ChipSelectPolarity; + + if (SpiPeripheral->ChipSelect != NULL) { + Status = SpiPeripheral->ChipSelect (SpiPeripheral, ChipSelectPolarity); + } else { + Status = SpiHostController->ChipSelect (SpiHostController, SpiPeripheral, ChipSelectPolarity); + } + if (EFI_ERROR (Status)) { + return Status; + } + + // 3. Transfer the data in one or both directions simultaneously + Status = SpiHostController->Transaction (SpiHostController, RequestPacket); + if (EFI_ERROR (Status)) { + return Status; + } + + // 4. Remove the chip select from the SPI peripheral signaling the transaction end to the chip + if (SpiPeripheral->ChipSelect != NULL) { + Status = SpiPeripheral->ChipSelect (SpiPeripheral, !ChipSelectPolarity); + } else { + Status = SpiHostController->ChipSelect (SpiHostController, SpiPeripheral, !ChipSelectPolarity); + } + if (EFI_ERROR (Status)) { + return Status; + } + + // 5. Optionally, shutdown the SPI controller's internal clock to reduce power + ClockHz = 0; + if (SpiBus->Clock != NULL) { + Status = SpiBus->Clock (SpiPeripheral, &ClockHz); + } else { + Status = SpiHostController->Clock (SpiHostController, SpiPeripheral, &ClockHz); + } + + // Since its optional for a controller to turn off the clock of spi peripherals + // its not an error if any controller doesn't support this. + if (Status != EFI_UNSUPPORTED) { + return Status; + } + + return EFI_SUCCESS; +} + +/** + Update the SPI peripheral associated with this SPI 10 instance. + + Support socketed SPI parts by allowing the SPI peripheral driver to replace + the SPI peripheral after the connection is made. An example use is socketed + 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 successfully + @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 +SpiBusUpdateSpiPeripheral ( + IN CONST EFI_SPI_IO_PROTOCOL *This, + IN CONST EFI_SPI_PERIPHERAL *SpiPeripheral + ) +{ + SPI_DEVICE_CONTEXT *SpiDeviceContext; + BOOLEAN ReinstallProtocol; + CONST EFI_SPI_PERIPHERAL *ExistingSpiPeripheral; + EFI_STATUS Status; + + if ( (This == NULL) + || (SpiPeripheral == NULL) + || (SpiPeripheral->SpiBus == NULL) + || (SpiPeripheral->SpiPart == NULL) + || (SpiPeripheral->ChipSelectParameter == NULL) + || (SpiPeripheral->SpiPeripheralDriverGuid == NULL)) + { + return EFI_INVALID_PARAMETER; + } + + ExistingSpiPeripheral = This->SpiPeripheral; + ASSERT (ExistingSpiPeripheral != NULL || ExistingSpiPeripheral->SpiBus != NULL); + + if ( (SpiPeripheral->SpiBus != ExistingSpiPeripheral->SpiBus) + || (SpiPeripheral->ChipSelectParameter != ExistingSpiPeripheral->ChipSelectParameter)) + { + return EFI_INVALID_PARAMETER; + } + + SpiDeviceContext = SPI_DEVICE_CONTEXT_FROM_PROTOCOL (This); + + ReinstallProtocol = FALSE; + if (!(CompareGuid (SpiPeripheral->SpiPeripheralDriverGuid, ExistingSpiPeripheral->SpiPeripheralDriverGuid))) { + ReinstallProtocol = TRUE; + } + + if (ReinstallProtocol) { + Status = gBS->UninstallProtocolInterface ( + SpiDeviceContext->Handle, + (EFI_GUID *)ExistingSpiPeripheral->SpiPeripheralDriverGuid, + &SpiDeviceContext->SpiIo + ); + if (EFI_ERROR (Status)) { + return Status; + } + } + + SpiDeviceContext->SpiIo.SpiPeripheral = SpiPeripheral; + + if (SpiDeviceContext->SpiIo.OriginalSpiPeripheral == NULL) { + SpiDeviceContext->SpiIo.OriginalSpiPeripheral = ExistingSpiPeripheral; + } else if (SpiDeviceContext->SpiIo.OriginalSpiPeripheral != ExistingSpiPeripheral) { + if (SpiPeripheral->SpiPart != ExistingSpiPeripheral->SpiPart) { + FreePool ((VOID *)(ExistingSpiPeripheral->SpiPart)); + } + if (SpiPeripheral->ConfigurationData != ExistingSpiPeripheral->ConfigurationData) { + FreePool ((VOID *)(ExistingSpiPeripheral->ConfigurationData)); + } + FreePool ((VOID *)ExistingSpiPeripheral); + } + + if (ReinstallProtocol) { + Status = gBS->InstallProtocolInterface ( + &SpiDeviceContext->Handle, + (EFI_GUID *)SpiPeripheral->SpiPeripheralDriverGuid, + EFI_NATIVE_INTERFACE, + &SpiDeviceContext->SpiIo + ); + if (EFI_ERROR (Status)) { + return Status; + } + } + + return EFI_SUCCESS; +} + +/** + Release all the resources allocated for the SPI device. + + This function releases all the resources allocated for the SPI device. + + @param SpiDeviceContext The SPI child device involved for the operation. + +**/ +VOID +ReleaseSpiDeviceContext ( + IN SPI_DEVICE_CONTEXT *SpiDeviceContext + ) +{ + if (SpiDeviceContext == NULL) { + return; + } + + FreePool (SpiDeviceContext); +} + +/** + Unregister an SPI device. + + This function removes the protocols installed on the controller handle and + frees the resources allocated for the SPI device. + + @param This The pointer to EFI_DRIVER_BINDING_PROTOCOL instance. + @param Controller The controller handle of the SPI device. + @param Handle The child handle. + + @retval EFI_SUCCESS The SPI device is successfully unregistered. + @return Others Some error occurs when unregistering the SPI device. + +**/ +EFI_STATUS +UnRegisterSpiDevice ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE Controller, + IN EFI_HANDLE Handle + ) +{ + EFI_STATUS Status; + SPI_DEVICE_CONTEXT *SpiDeviceContext; + CONST EFI_SPI_PERIPHERAL *SpiPeripheral; + EFI_SPI_HC_PROTOCOL *SpiHost; + + SpiDeviceContext = NULL; + + Status = gBS->OpenProtocol ( + Handle, + &gEfiCallerIdGuid, + (VOID **) &SpiDeviceContext, + This->DriverBindingHandle, + Controller, + EFI_OPEN_PROTOCOL_GET_PROTOCOL + ); + if (EFI_ERROR (Status)) { + return Status; + } + + SpiPeripheral = SpiDeviceContext->SpiIo.SpiPeripheral; + + // + // Close the child handle + // + gBS->CloseProtocol ( + Controller, + &gEfiSpiHcProtocolGuid, + This->DriverBindingHandle, + Handle + ); + + // + // The SPI Bus driver installs the SPI Io and Local Protocol in the DriverBindingStart(). + // Here should uninstall them. + // + Status = gBS->UninstallMultipleProtocolInterfaces ( + Handle, + SpiPeripheral->SpiPeripheralDriverGuid, &SpiDeviceContext->SpiIo, + &gEfiCallerIdGuid, SpiDeviceContext, + NULL + ); + + if (EFI_ERROR (Status)) { + // + // Keep parent and child relationship + // + gBS->OpenProtocol ( + Controller, + &gEfiSpiHcProtocolGuid, + (VOID **) &SpiHost, + This->DriverBindingHandle, + Handle, + EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER + ); + return Status; + } + + // + // Free resources for this SPI device + // + if (SpiDeviceContext->Link.ForwardLink != NULL || SpiDeviceContext->Link.BackLink != NULL) { + RemoveEntryList (&SpiDeviceContext->Link); + } + ReleaseSpiDeviceContext (SpiDeviceContext); + + return EFI_SUCCESS; +} + +/** + Fixup internal data so that EFI can be call in virtual mode. + Call the passed in Child Notify event and convert any pointers in + lib to virtual mode. + + @param[in] Event The Event that is being processed + @param[in] Context Event Context +**/ +VOID +EFIAPI +SpiBusVirtualNotifyEvent ( + IN EFI_EVENT Event, + IN VOID *Context + ) +{ + LIST_ENTRY *Link; + SPI_DEVICE_CONTEXT *SpiDeviceContext; + SPI_BUS_CONTEXT *SpiBusContext; + + for (Link = mSpiBusList.ForwardLink; Link != &mSpiBusList; Link = Link->ForwardLink) { + SpiBusContext = CR (Link, SPI_BUS_CONTEXT, Link, SPI_BUS_SIGNATURE); + + EfiConvertPointer (0x0, (VOID **)&SpiBusContext->SpiHost); + EfiConvertPointer (0x0, (VOID **)&SpiBusContext->SpiBus); + } + + for (Link = mSpiDeviceList.ForwardLink; Link != &mSpiDeviceList; Link = Link->ForwardLink) { + SpiDeviceContext = CR (Link, SPI_DEVICE_CONTEXT, Link, SPI_DEVICE_SIGNATURE); + + EfiConvertPointer (0x0, (VOID **)&SpiDeviceContext->SpiBusContext); + + EfiConvertPointer (0x0, (VOID **)&SpiDeviceContext->SpiIo.SpiPeripheral); + EfiConvertPointer (0x0, (VOID **)&SpiDeviceContext->SpiIo.OriginalSpiPeripheral); + EfiConvertPointer (0x0, (VOID **)&SpiDeviceContext->SpiIo.LegacySpiProtocol); + EfiConvertPointer (0x0, (VOID **)&SpiDeviceContext->SpiIo.Transaction); + EfiConvertPointer (0x0, (VOID **)&SpiDeviceContext->SpiIo.UpdateSpiPeripheral); + } + + return; +} + +/** + The user entry point for the SPI bus module. The user code starts with + this function. + + @param[in] ImageHandle The firmware allocated handle for the EFI image. + @param[in] SystemTable A pointer to the EFI System Table. + + @retval EFI_SUCCESS The entry point is executed successfully. + @retval other Some error occurs when executing this entry point. + +**/ +EFI_STATUS +EFIAPI +InitializeSpiBus( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + EFI_STATUS Status; + + // + // Install driver model protocol(s). + // + Status = EfiLibInstallDriverBindingComponentName2 ( + ImageHandle, + SystemTable, + &gSpiBusDriverBinding, + NULL, + &gSpiBusComponentName, + &gSpiBusComponentName2 + ); + ASSERT_EFI_ERROR (Status); + + // + // Register for the virtual address change event + // + Status = gBS->CreateEventEx ( + EVT_NOTIFY_SIGNAL, + TPL_NOTIFY, + SpiBusVirtualNotifyEvent, + NULL, + &gEfiEventVirtualAddressChangeGuid, + &mSpiBusVirtualAddrChangeEvent + ); + ASSERT_EFI_ERROR (Status); + + return Status; +} + +/** + This is the unload handle for SPI bus module. + + Disconnect the driver specified by ImageHandle from all the devices in the handle database. + Uninstall all the protocols installed in the driver entry point. + + @param[in] ImageHandle The drivers' driver image. + + @retval EFI_SUCCESS The image is unloaded. + @retval Others Failed to unload the image. + +**/ +EFI_STATUS +EFIAPI +SpiBusUnload ( + IN EFI_HANDLE ImageHandle + ) +{ + EFI_STATUS Status; + EFI_HANDLE *DeviceHandleBuffer; + UINTN DeviceHandleCount; + UINTN Index; + EFI_COMPONENT_NAME_PROTOCOL *ComponentName; + EFI_COMPONENT_NAME2_PROTOCOL *ComponentName2; + + // + // Get the list of all SPI Controller handles in the handle database. + // If there is an error getting the list, then the unload + // operation fails. + // + Status = gBS->LocateHandleBuffer ( + ByProtocol, + &gEfiSpiHcProtocolGuid, + NULL, + &DeviceHandleCount, + &DeviceHandleBuffer + ); + + if (!EFI_ERROR (Status)) { + // + // Disconnect the driver specified by Driver BindingHandle from all + // the devices in the handle database. + // + for (Index = 0; Index < DeviceHandleCount; Index++) { + Status = gBS->DisconnectController ( + DeviceHandleBuffer[Index], + gSpiBusDriverBinding.DriverBindingHandle, + NULL + ); + if (EFI_ERROR (Status)) { + goto Done; + } + } + } + + // + // Uninstall all the protocols installed in the driver entry point + // + Status = gBS->UninstallMultipleProtocolInterfaces ( + gSpiBusDriverBinding.DriverBindingHandle, + &gEfiDriverBindingProtocolGuid, + &gSpiBusDriverBinding, + NULL + ); + ASSERT_EFI_ERROR (Status); + + // + // Note we have to one by one uninstall the following protocols. + // It's because some of them are optionally installed based on + // the following PCD settings. + // gEfiMdePkgTokenSpaceGuid.PcdDriverDiagnosticsDisable + // gEfiMdePkgTokenSpaceGuid.PcdComponentNameDisable + // gEfiMdePkgTokenSpaceGuid.PcdDriverDiagnostics2Disable + // gEfiMdePkgTokenSpaceGuid.PcdComponentName2Disable + // + Status = gBS->HandleProtocol ( + gSpiBusDriverBinding.DriverBindingHandle, + &gEfiComponentNameProtocolGuid, + (VOID **) &ComponentName + ); + if (!EFI_ERROR (Status)) { + gBS->UninstallProtocolInterface ( + gSpiBusDriverBinding.DriverBindingHandle, + &gEfiComponentNameProtocolGuid, + ComponentName + ); + } + + Status = gBS->HandleProtocol ( + gSpiBusDriverBinding.DriverBindingHandle, + &gEfiComponentName2ProtocolGuid, + (VOID **) &ComponentName2 + ); + if (!EFI_ERROR (Status)) { + gBS->UninstallProtocolInterface ( + gSpiBusDriverBinding.DriverBindingHandle, + &gEfiComponentName2ProtocolGuid, + ComponentName2 + ); + } + + Status = EFI_SUCCESS; + +Done: + // + // Free the buffer containing the list of handles from the handle database + // + if (DeviceHandleBuffer != NULL) { + gBS->FreePool (DeviceHandleBuffer); + } + + return Status; +} diff --git a/Silicon/NXP/Drivers/SpiBusDxe/SpiBusDxe.h b/Silicon/NXP/Drivers/SpiBusDxe/SpiBusDxe.h new file mode 100644 index 0000000..3d4074e --- /dev/null +++ b/Silicon/NXP/Drivers/SpiBusDxe/SpiBusDxe.h @@ -0,0 +1,510 @@ +/** @file + Private data structures for the SPI DXE driver. + + This file defines common data structures, macro definitions and some module + internal function header files. + + Based on MdeModulePkg/Bus/I2c/I2cDxe/I2cDxe.h + + Copyright (c) 2013, Intel Corporation. All rights reserved.
+ Copyright 2018 NXP + + This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#ifndef __SPI_BUS_DXE_H__ +#define __SPI_BUS_DXE_H__ + +#include +#include +#include +#include + +#define SPI_BUS_SIGNATURE SIGNATURE_32 ('S', 'P', 'I', 'B') +#define SPI_DEVICE_SIGNATURE SIGNATURE_32 ('S', 'P', 'I', 'D') + +/// +/// SPI bus context. This data structure provides connection point +/// between SPI IO protocol (which tells the SPI bus) and SPI host +/// controller protocol. +/// +typedef struct { + /// + /// Structure identification + /// + UINT32 Signature; + + /// + /// Spi Host controller protocol + /// + CONST EFI_SPI_HC_PROTOCOL *SpiHost; + + /// + /// Spi BUS data structure + /// + CONST EFI_SPI_BUS *SpiBus; + + EFI_HANDLE DriverBindingHandle; + + /// + /// Link List of SPI Buses + /// + LIST_ENTRY Link; +} SPI_BUS_CONTEXT; + +/// +/// SPI device context +/// +typedef struct { + /// + /// Structure identification + /// + UINT32 Signature; + + /// + /// Spi device handle + /// + EFI_HANDLE Handle; + + /// + /// Upper level API to support the SPI device I/O + /// + EFI_SPI_IO_PROTOCOL SpiIo; + + /// + /// Context for the common I/O support including the + /// lower level API to the host controller. + /// + SPI_BUS_CONTEXT *SpiBusContext; + + /// + /// Link List of SPI Devices + /// + LIST_ENTRY Link; +} SPI_DEVICE_CONTEXT; + +#define SPI_DEVICE_CONTEXT_FROM_PROTOCOL(a) CR (a, SPI_DEVICE_CONTEXT, SpiIo, SPI_DEVICE_SIGNATURE) + +/** + Enumerate the SPI bus + + This routine walks the platform specific data describing the + SPI bus to create the SPI devices where driver GUIDs were + specified. + + @param[in] SpiBusContext Address of an SPI_BUS_CONTEXT structure + @param[in] Controller Handle to the controller + @param[in] LegacySpiHostController A pointer to the LEGACY_SPI_CONTROLLER_PROTOCOL + interface installed on controller. + @param[in] RegisterRuntime Weather to register runtime SPI devices or non runtime + Spi devices. + + @retval EFI_SUCCESS The bus is successfully configured + +**/ +EFI_STATUS +RegisterSpiDevice ( + IN SPI_BUS_CONTEXT *SpiBusContext, + IN EFI_HANDLE Controller, + IN EFI_LEGACY_SPI_CONTROLLER_PROTOCOL *LegacySpiHostController, + IN BOOLEAN RegisterRuntime + ); + +/** + Unregister an SPI device. + + This function removes the protocols installed on the controller handle and + frees the resources allocated for the SPI device. + + @param This The pointer to EFI_DRIVER_BINDING_PROTOCOL instance. + @param Controller The controller handle of the SPI device. + @param Handle The child handle. + + @retval EFI_SUCCESS The SPI device is successfully unregistered. + @return Others Some error occurs when unregistering the SPI device. + +**/ +EFI_STATUS +UnRegisterSpiDevice ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE Controller, + IN EFI_HANDLE Handle + ); + +/** + Tests to see if this driver supports a given controller. If a child device is provided, + it further tests to see if this driver supports creating a handle for the specified child device. + + This function checks to see if the driver specified by This supports the device specified by + ControllerHandle. Drivers will typically use the device path attached to + ControllerHandle and/or the services from the bus I/O abstraction attached to + ControllerHandle to determine if the driver supports ControllerHandle. This function + may be called many times during platform initialization. In order to reduce boot times, the tests + performed by this function must be very small, and take as little time as possible to execute. This + function must not change the state of any hardware devices, and this function must be aware that the + device specified by ControllerHandle may already be managed by the same driver or a + different driver. This function must match its calls to AllocatePages() with FreePages(), + AllocatePool() with FreePool(), and OpenProtocol() with CloseProtocol(). + Since ControllerHandle may have been previously started by the same driver, if a protocol is + already in the opened state, then it must not be closed with CloseProtocol(). This is required + to guarantee the state of ControllerHandle is not modified by this function. + + @param[in] This A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance. + @param[in] ControllerHandle The handle of the controller to test. This handle + must support a protocol interface that supplies + an I/O abstraction to the driver. + @param[in] RemainingDevicePath A pointer to the remaining portion of a device path. This + parameter is ignored by device drivers, and is optional for bus + drivers. For bus drivers, if this parameter is not NULL, then + the bus driver must determine if the bus controller specified + by ControllerHandle and the child controller specified + by RemainingDevicePath are both supported by this + bus driver. + + @retval EFI_SUCCESS The device specified by ControllerHandle and + RemainingDevicePath is supported by the driver specified by This. + @retval EFI_ALREADY_STARTED The device specified by ControllerHandle and + RemainingDevicePath is already being managed by the driver + specified by This. + @retval EFI_ACCESS_DENIED The device specified by ControllerHandle and + RemainingDevicePath is already being managed by a different + driver or an application that requires exclusive access. + Currently not implemented. + @retval EFI_UNSUPPORTED The device specified by ControllerHandle and + RemainingDevicePath is not supported by the driver specified by This. +**/ +EFI_STATUS +EFIAPI +SpiBusDriverSupported ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE Controller, + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath + ); + +/** + Starts a device controller or a bus controller. + + The Start() function is designed to be invoked from the EFI boot service ConnectController(). + As a result, much of the error checking on the parameters to Start() has been moved into this + common boot service. It is legal to call Start() from other locations, + but the following calling restrictions must be followed or the system behavior will not be deterministic. + 1. ControllerHandle must be a valid EFI_HANDLE. + 2. If RemainingDevicePath is not NULL, then it must be a pointer to a naturally aligned + EFI_DEVICE_PATH_PROTOCOL. + 3. Prior to calling Start(), the Supported() function for the driver specified by This must + have been called with the same calling parameters, and Supported() must have returned EFI_SUCCESS. + + @param[in] This A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance. + @param[in] ControllerHandle The handle of the controller to start. This handle + must support a protocol interface that supplies + an I/O abstraction to the driver. + @param[in] RemainingDevicePath A pointer to the remaining portion of a device path. This + parameter is ignored by device drivers, and is optional for bus + drivers. For a bus driver, if this parameter is NULL, then handles + for all the children of Controller are created by this driver. + If this parameter is not NULL and the first Device Path Node is + not the End of Device Path Node, then only the handle for the + child device specified by the first Device Path Node of + RemainingDevicePath is created by this driver. + If the first Device Path Node of RemainingDevicePath is + the End of Device Path Node, no child handle is created by this + driver. + + @retval EFI_SUCCESS The device was started. + @retval EFI_DEVICE_ERROR The device could not be started due to a device error.Currently not implemented. + @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources. + @retval Others The driver failded to start the device. + +**/ +EFI_STATUS +EFIAPI +SpiBusDriverStart ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE Controller, + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath + ); + +/** + Stops a device controller or a bus controller. + + The Stop() function is designed to be invoked from the EFI boot service DisconnectController(). + As a result, much of the error checking on the parameters to Stop() has been moved + into this common boot service. It is legal to call Stop() from other locations, + but the following calling restrictions must be followed or the system behavior will not be deterministic. + 1. ControllerHandle must be a valid EFI_HANDLE that was used on a previous call to this + same driver's Start() function. + 2. The first NumberOfChildren handles of ChildHandleBuffer must all be a valid + EFI_HANDLE. In addition, all of these handles must have been created in this driver's + Start() function, and the Start() function must have called OpenProtocol() on + ControllerHandle with an Attribute of EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER. + + @param[in] This A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance. + @param[in] ControllerHandle A handle to the device being stopped. The handle must + support a bus specific I/O protocol for the driver + to use to stop the device. + @param[in] NumberOfChildren The number of child device handles in ChildHandleBuffer. + @param[in] ChildHandleBuffer An array of child handles to be freed. May be NULL + if NumberOfChildren is 0. + + @retval EFI_SUCCESS The device was stopped. + @retval EFI_DEVICE_ERROR The device could not be stopped due to a device error. + +**/ +EFI_STATUS +EFIAPI +SpiBusDriverStop ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE Controller, + IN UINTN NumberOfChildren, + IN EFI_HANDLE *ChildHandleBuffer + ); + +/** + Retrieves a Unicode string that is the user readable name of the driver. + + This function retrieves the user readable name of a driver in the form of a + Unicode string. If the driver specified by This has a user readable name in + the language specified by Language, then a pointer to the driver name is + returned in DriverName, and EFI_SUCCESS is returned. If the driver specified + by This does not support the language specified by Language, + then EFI_UNSUPPORTED is returned. + + @param This[in] A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or + EFI_COMPONENT_NAME_PROTOCOL instance. + + @param Language[in] A pointer to a Null-terminated ASCII string + array indicating the language. This is the + language of the driver name that the caller is + requesting, and it must match one of the + languages specified in SupportedLanguages. The + number of languages supported by a driver is up + to the driver writer. Language is specified + in RFC 4646 or ISO 639-2 language code format. + + @param DriverName[out] A pointer to the Unicode string to return. + This Unicode string is the name of the + driver specified by This in the language + specified by Language. + + @retval EFI_SUCCESS The Unicode string for the Driver specified by + This and the language specified by Language was + returned in DriverName. + + @retval EFI_INVALID_PARAMETER Language is NULL. + + @retval EFI_INVALID_PARAMETER DriverName is NULL. + + @retval EFI_UNSUPPORTED The driver specified by This does not support + the language specified by Language. + +**/ +EFI_STATUS +EFIAPI +SpiBusComponentNameGetDriverName ( + IN EFI_COMPONENT_NAME2_PROTOCOL *This, + IN CHAR8 *Language, + OUT CHAR16 **DriverName + ); + +/** + Retrieves a Unicode string that is the user readable name of the controller + that is being managed by a driver. + + This function retrieves the user readable name of the controller specified by + ControllerHandle and ChildHandle in the form of a Unicode string. If the + driver specified by This has a user readable name in the language specified by + Language, then a pointer to the controller name is returned in ControllerName, + and EFI_SUCCESS is returned. If the driver specified by This is not currently + managing the controller specified by ControllerHandle and ChildHandle, + then EFI_UNSUPPORTED is returned. If the driver specified by This does not + support the language specified by Language, then EFI_UNSUPPORTED is returned. + + @param This[in] A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or + EFI_COMPONENT_NAME_PROTOCOL instance. + + @param ControllerHandle[in] The handle of a controller that the driver + specified by This is managing. This handle + specifies the controller whose name is to be + returned. + + @param ChildHandle[in] The handle of the child controller to retrieve + the name of. This is an optional parameter that + may be NULL. It will be NULL for device + drivers. It will also be NULL for a bus drivers + that wish to retrieve the name of the bus + controller. It will not be NULL for a bus + driver that wishes to retrieve the name of a + child controller. + + @param Language[in] A pointer to a Null-terminated ASCII string + array indicating the language. This is the + language of the driver name that the caller is + requesting, and it must match one of the + languages specified in SupportedLanguages. The + number of languages supported by a driver is up + to the driver writer. Language is specified in + RFC 4646 or ISO 639-2 language code format. + + @param ControllerName[out] A pointer to the Unicode string to return. + This Unicode string is the name of the + controller specified by ControllerHandle and + ChildHandle in the language specified by + Language from the point of view of the driver + specified by This. + + @retval EFI_SUCCESS The Unicode string for the user readable name in + the language specified by Language for the + driver specified by This was returned in + DriverName. + + @retval EFI_INVALID_PARAMETER ControllerHandle is NULL. + + @retval EFI_INVALID_PARAMETER ChildHandle is not NULL and it is not a valid + EFI_HANDLE. + + @retval EFI_INVALID_PARAMETER Language is NULL. + + @retval EFI_INVALID_PARAMETER ControllerName is NULL. + + @retval EFI_UNSUPPORTED The driver specified by This is not currently + managing the controller specified by + ControllerHandle and ChildHandle. + + @retval EFI_UNSUPPORTED The driver specified by This does not support + the language specified by Language. + +**/ +EFI_STATUS +EFIAPI +SpiBusComponentNameGetControllerName ( + IN EFI_COMPONENT_NAME2_PROTOCOL *This, + IN EFI_HANDLE ControllerHandle, + IN EFI_HANDLE ChildHandle OPTIONAL, + IN CHAR8 *Language, + OUT CHAR16 **ControllerName + ); + +/** + The user entry point for the SPI bus module. The user code starts with + this function. + + @param[in] ImageHandle The firmware allocated handle for the EFI image. + @param[in] SystemTable A pointer to the EFI System Table. + + @retval EFI_SUCCESS The entry point is executed successfully. + @retval other Some error occurs when executing this entry point. + +**/ +EFI_STATUS +EFIAPI +InitializeSpiBus( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ); + +/** + This is the unload handle for SPI bus module. + + Disconnect the driver specified by ImageHandle from all the devices in the handle database. + Uninstall all the protocols installed in the driver entry point. + + @param[in] ImageHandle The drivers' driver image. + + @retval EFI_SUCCESS The image is unloaded. + @retval Others Failed to unload the image. + +**/ +EFI_STATUS +EFIAPI +SpiBusUnload ( + IN EFI_HANDLE ImageHandle + ); + +/** + Release all the resources allocated for the SPI device. + + This function releases all the resources allocated for the SPI device. + + @param SpiDeviceContext The SPI child device involved for the operation. + +**/ +VOID +ReleaseSpiDeviceContext ( + IN SPI_DEVICE_CONTEXT *SpiDeviceContext + ); + +/** + 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 transactions to the + SPI controller for execution on the SPI bus. + + @param[in] This Pointer to an EFI_SPI_IO_PROTOCOL structure. + @param[in] RequestPacket Pointer to an EFI_SPI_REQUEST_PACKET + structure describing the SPI transactions. + + @param[in] ClockHz Specify the ClockHz value as zero (0) to use + the maximum clock frequency supported by the + SPI controller and part. Specify a non-zero + value only when a specific SPI transaction + requires a reduced clock rate. + + @retval EFI_SUCCESS The transaction completed successfully. + @retval EFI_ALREADY_STARTED The controller is busy with another transaction. + @retval EFI_BAD_BUFFER_SIZE The Length value in SPI Transaction is wrong. + @retval EFI_DEVICE_ERROR There was an SPI error during the transaction. + @retval EFI_INVALID_PARAMETER The parameters specified in RequestPacket are not + Valid. or the RequestPacket is NULL. + @retval EFI_NOT_READY Support for the chip select is not properly + initialized + @retval EFI_INVALID_PARAMETER The ChipSeLect value or its contents are + invalid + @retval EFI_NO_RESPONSE The SPI device is not responding to the slave + address. EFI_DEVICE_ERROR will be returned if + the controller cannot distinguish when the NACK + occurred. + @retval EFI_UNSUPPORTED The controller does not support the requested + transaction. or The SPI controller was not able to support + the frequency requested by ClockHz +**/ +EFI_STATUS +SpiBusTransaction ( + IN CONST EFI_SPI_IO_PROTOCOL *This, + IN EFI_SPI_REQUEST_PACKET *RequestPacket, + IN UINT32 ClockHz OPTIONAL + ); + +/** + Update the SPI peripheral associated with this SPI 10 instance. + + Support socketed SPI parts by allowing the SPI peripheral driver to replace + the SPI peripheral after the connection is made. An example use is socketed + 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 successfully + @retval EFI_INVALID_PARAMETER The SpiPeripheral value is NULL, + or the SpiPeripheral->SpiBus is NULL, + or the SpiP eripheral - >SpiBus pointing at + wrong bus, + or the SpiP eripheral - >SpiPart is NULL + +**/ +EFI_STATUS +SpiBusUpdateSpiPeripheral ( + IN CONST EFI_SPI_IO_PROTOCOL *This, + IN CONST EFI_SPI_PERIPHERAL *SpiPeripheral + ); + +#endif // __SPI_BUS_DXE_H__ diff --git a/Silicon/NXP/Drivers/SpiBusDxe/SpiBusDxe.inf b/Silicon/NXP/Drivers/SpiBusDxe/SpiBusDxe.inf new file mode 100644 index 0000000..37adf6d --- /dev/null +++ b/Silicon/NXP/Drivers/SpiBusDxe/SpiBusDxe.inf @@ -0,0 +1,53 @@ +## @file +# This driver enumerates SPI devices on SPI bus and produce SPI IO Protocol on SPI devices. +# +# Based on MdeModulePkg/Bus/I2c/I2cDxe/I2cBusDxe.inf +# +# Copyright 2018 NXP +# +# This program and the accompanying materials +# are licensed and made available under the terms and conditions of the BSD License +# which accompanies this distribution. The full text of the license may be found at +# http://opensource.org/licenses/bsd-license.php +# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +# +# +## + +[Defines] + INF_VERSION = 0x0001000A + BASE_NAME = SpiBusDxe + FILE_GUID = 5145643e-b84f-4033-86e4-15e9dab163fb + MODULE_TYPE = DXE_RUNTIME_DRIVER + VERSION_STRING = 1.0 + ENTRY_POINT = InitializeSpiBus + UNLOAD_IMAGE = SpiBusUnload + +[Sources.common] + SpiBusDxe.h + SpiBusDxe.c + +[LibraryClasses] + BaseMemoryLib + DebugLib + DevicePathLib + MemoryAllocationLib + UefiBootServicesTableLib + UefiDriverEntryPoint + UefiLib + UefiRuntimeLib + +[Packages] + Platform/NXP/NxpQoriqLs.dec + MdePkg/MdePkg.dec + MdeModulePkg/MdeModulePkg.dec + +[Protocols] + gEfiDevicePathProtocolGuid ## TO_START + gEfiSpiHcProtocolGuid ## TO_START + gEfiSpiConfigurationProtocolGuid ## TO_START + gEfiLegacySpiControllerProtocolGuid ## TO_START + +[Depex] + TRUE -- 2.7.4