From mboxrd@z Thu Jan 1 00:00:00 1970 Authentication-Results: mx.groups.io; dkim=pass header.i=@semihalf-com.20150623.gappssmtp.com header.s=20150623 header.b=iwGphNhi; spf=none, err=SPF record not found (domain: semihalf.com, ip: 209.85.222.193, mailfrom: mw@semihalf.com) Received: from mail-qk1-f193.google.com (mail-qk1-f193.google.com [209.85.222.193]) by groups.io with SMTP; Wed, 17 Apr 2019 12:34:02 -0700 Received: by mail-qk1-f193.google.com with SMTP id a71so15108366qkg.2 for ; Wed, 17 Apr 2019 12:34:01 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=semihalf-com.20150623.gappssmtp.com; s=20150623; h=mime-version:references:in-reply-to:from:date:message-id:subject:to :cc:content-transfer-encoding; bh=dSikYfyDXMyUccguR6JOklwnCnZwUrAGIDXfffswqps=; b=iwGphNhixEbNS904i9F2R2w10ivYUrWj+hNmzz7lhbugz+h1BnTjOf2TysViXTF/Y/ ZRMDomoJCySdqFG5/ItJ1udkSCWP1+N9ZR/LavaRVZ5+7sun3JBzIo67evTxCoDAQGDb Dty4m9xztFGZ7P8UNZib1SqDRQPeOHWeq22DrPjF3/sofwIz/yeARxH01OYob45D9AA7 wojBl3z9UXEYuZW+5orOPhkyZpSwWUlUT2VHnVtnAUQ37scSCyH5yjgN59Piz28ThgcY SIh2dgGpB1K+LV3OGPLl3irqlBPvj0LIvC1m3rEuVe0u58SbIWvPmji2PSrq7d4IB9KG jlzw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:mime-version:references:in-reply-to:from:date :message-id:subject:to:cc:content-transfer-encoding; bh=dSikYfyDXMyUccguR6JOklwnCnZwUrAGIDXfffswqps=; b=k9kz4xn/csNsmikTqJ1oDBmSZCcqZhcAYeXLZnfjuPUP6ZFEvWmNZ1xEGnCjTrm+7U FsK07pTpdltEy4AokKfa8OmDwNHgwOP8HPex3NI1Yt1pYE+SimNnqR+jv7Dscbd7AYuN SayW8VZj9SDYlKoKTNWL4LqN/pB7jJp+KquZVLTr4YS4ntJinv5TMfvUZxW0KdvdVnxB Sbm4weD4LA+9/ZcWBGFtj6vh/5dFFDAL5O3mKyCrtKYuWV0BFOzDyJ0s6GYKx4jiSvH5 ESZZKGFGPeul+HQCZte6BytypOsNcXjJbS66qHHcFtkaXBUj2/gYh3VxDIftWJe/TNVz SZlw== X-Gm-Message-State: APjAAAUb+J/73QVDNeG9AjJp2P0dlX45pkLIDqrEC76brJdKtFiHJZgv 18ButO0yQgkijlcJogiYXcm7XOVSJTF+/Wy1Jx7ndQ== X-Google-Smtp-Source: APXvYqxS9HFwZ6s/lbIE7MqNc+HFdA976rto17RrdWI3TIeevS/x8VpAa4B9AB3BM8K+NDjJzHUSM1JrfdP71i3zqLQ= X-Received: by 2002:a37:8d06:: with SMTP id p6mr64969590qkd.120.1555529640822; Wed, 17 Apr 2019 12:34:00 -0700 (PDT) MIME-Version: 1.0 References: <1555524356-1740-1-git-send-email-mw@semihalf.com> <1555524356-1740-3-git-send-email-mw@semihalf.com> In-Reply-To: From: "Marcin Wojtas" Date: Wed, 17 Apr 2019 21:33:49 +0200 Message-ID: Subject: Re: [edk2-platforms: PATCH 2/3] Marvell/Drivers: MvSpiOrionDxe: Keep clock enabled at runtime To: Ard Biesheuvel Cc: edk2-devel-groups-io , Leif Lindholm , Nadav Haklai , =?UTF-8?B?SmFuIETEhWJyb8Wb?= , Grzegorz Jaszczyk , Kostya Porotchkin , Jici Gao Content-Type: text/plain; charset="UTF-8" Content-Transfer-Encoding: quoted-printable Ard, =C5=9Br., 17 kwi 2019 o 20:30 Ard Biesheuvel na= pisa=C5=82(a): > > On Wed, 17 Apr 2019 at 11:27, Ard Biesheuvel = wrote: > > > > On Wed, 17 Apr 2019 at 11:06, Marcin Wojtas wrote: > > > > > > Linux MTD subsystem enables the SPI controller clock > > > only when explicitly accessing the device. Because of that, > > > using variables stored in the SPI flash could cause a hang > > > when this clock remained disabled. > > > > > > Such issue was prevented when booting with the default > > > DTB - see commit 124073e4d440 ("Marvell/Armada7k8k: DeviceTree: > > > Use fixed clocks"). However in case someone wishes to > > > try a different DTB, the issue can become problematic again. > > > > > > Fix above problem by enabling the clock when accessing > > > SPI controller registers or mapped memory region > > > AtRuntime. For this purpose add required callbacks > > > to the SpiMaster and SpiFlash protocols that are > > > called from MvFvbDxe driver. > > > > > > Contributed-under: TianoCore Contribution Agreement 1.1 > > > Signed-off-by: Marcin Wojtas > > > > This is really not the right solution. Linux runs UEFI runtime > > services on a single core with interrupts enabled, and it thinks it > > owns the SPI subsystem if you describe it in the DT, and may decide to > > access it at the same time, either in interrupt ot softirq context, or > > from another core. > > I'm aware of that. Maybe I phrased the commit message not clear enough, but this patch actually handles a case where the only owner/user of the SPI device is UEFI. OS, when using variables, is totally unaware of it, hence there is noone, who can enable the clock feeding SPI interface. To overcome that we can: a. Use DT with fake clock tree (and so unused clocks won't be disabled in HW) - we already do it in the default DT provided by UEFI. b. Append clk_ignore_unused to commandline on every boot - even if doable, I cannot think of any nice implementations. c. Make sure in UEFI the SPI clock is enabled every time the OS tries to access the variables. This patch implements c. > > Note that this applies to just the clock as well. So if c. is illegal, do you see any other option that dropping the patch? Best regards, Marcin > > > > > > --- > > > Silicon/Marvell/Marvell.dec | 3 + > > > Silicon/Marvell/Drivers/Spi/MvSpiOrionDxe/MvSpiOrionDxe.inf | 3 + > > > Silicon/Marvell/Include/Protocol/Spi.h | 10 +++= + > > > Silicon/Marvell/Include/Protocol/SpiFlash.h | 7 +++ > > > Silicon/Marvell/Drivers/Spi/MvFvbDxe/MvFvbDxe.c | 34 +++= ++++++++ > > > Silicon/Marvell/Drivers/Spi/MvSpiFlashDxe/MvSpiFlashDxe.c | 11 +++= + > > > Silicon/Marvell/Drivers/Spi/MvSpiOrionDxe/MvSpiOrionDxe.c | 63 +++= ++++++++++++++++- > > > 7 files changed, 129 insertions(+), 2 deletions(-) > > > > > > diff --git a/Silicon/Marvell/Marvell.dec b/Silicon/Marvell/Marvell.de= c > > > index 7210ba2..201a62f 100644 > > > --- a/Silicon/Marvell/Marvell.dec > > > +++ b/Silicon/Marvell/Marvell.dec > > > @@ -138,6 +138,9 @@ > > > gMarvellTokenSpaceGuid.PcdI2cBusCount|0|UINT32|0x3000183 > > > > > > #SPI > > > + gMarvellTokenSpaceGuid.PcdSpiClockFixed|TRUE|BOOLEAN|0x30000054 > > > + gMarvellTokenSpaceGuid.PcdSpiClockMask|0|UINT32|0x30000055 > > > + gMarvellTokenSpaceGuid.PcdSpiClockRegBase|0|UINT64|0x30000056 > > > gMarvellTokenSpaceGuid.PcdSpiRegBase|0|UINT32|0x3000051 > > > gMarvellTokenSpaceGuid.PcdSpiMemoryBase|0|UINT64|0x3000059 > > > gMarvellTokenSpaceGuid.PcdSpiMaxFrequency|0|UINT32|0x30000052 > > > diff --git a/Silicon/Marvell/Drivers/Spi/MvSpiOrionDxe/MvSpiOrionDxe.= inf b/Silicon/Marvell/Drivers/Spi/MvSpiOrionDxe/MvSpiOrionDxe.inf > > > index 4779371..1857484 100644 > > > --- a/Silicon/Marvell/Drivers/Spi/MvSpiOrionDxe/MvSpiOrionDxe.inf > > > +++ b/Silicon/Marvell/Drivers/Spi/MvSpiOrionDxe/MvSpiOrionDxe.inf > > > @@ -59,7 +59,10 @@ > > > UefiRuntimeLib > > > > > > [FixedPcd] > > > + gMarvellTokenSpaceGuid.PcdSpiClockFixed > > > gMarvellTokenSpaceGuid.PcdSpiClockFrequency > > > + gMarvellTokenSpaceGuid.PcdSpiClockMask > > > + gMarvellTokenSpaceGuid.PcdSpiClockRegBase > > > gMarvellTokenSpaceGuid.PcdSpiMaxFrequency > > > gMarvellTokenSpaceGuid.PcdSpiRegBase > > > > > > diff --git a/Silicon/Marvell/Include/Protocol/Spi.h b/Silicon/Marvell= /Include/Protocol/Spi.h > > > index abbad19..4d66f7f 100644 > > > --- a/Silicon/Marvell/Include/Protocol/Spi.h > > > +++ b/Silicon/Marvell/Include/Protocol/Spi.h > > > @@ -54,6 +54,9 @@ typedef struct { > > > UINT32 AddrSize; > > > NOR_FLASH_INFO *Info; > > > UINTN HostRegisterBaseAddress; > > > + BOOLEAN HostClockFixed; > > > + UINTN HostClockEnableRegister; > > > + UINT32 HostClockEnableMask; > > > UINTN CoreClock; > > > } SPI_DEVICE; > > > > > > @@ -107,6 +110,12 @@ EFI_STATUS > > > IN SPI_DEVICE *SpiDev > > > ); > > > > > > +typedef > > > +EFI_STATUS > > > +(EFIAPI *MV_SPI_POWER_ON) ( > > > + IN SPI_DEVICE *SpiDev > > > + ); > > > + > > > struct _MARVELL_SPI_MASTER_PROTOCOL { > > > MV_SPI_INIT Init; > > > MV_SPI_READ_WRITE ReadWrite; > > > @@ -114,6 +123,7 @@ struct _MARVELL_SPI_MASTER_PROTOCOL { > > > MV_SPI_SETUP_DEVICE SetupDevice; > > > MV_SPI_FREE_DEVICE FreeDevice; > > > MV_SPI_CONFIG_RT ConfigRuntime; > > > + MV_SPI_POWER_ON ControllerPowerOn; > > > }; > > > > > > #endif // __MARVELL_SPI_MASTER_PROTOCOL_H__ > > > diff --git a/Silicon/Marvell/Include/Protocol/SpiFlash.h b/Silicon/Ma= rvell/Include/Protocol/SpiFlash.h > > > index e703330..0336dda 100644 > > > --- a/Silicon/Marvell/Include/Protocol/SpiFlash.h > > > +++ b/Silicon/Marvell/Include/Protocol/SpiFlash.h > > > @@ -102,6 +102,12 @@ EFI_STATUS > > > IN UINTN EndPercentage > > > ); > > > > > > +typedef > > > +EFI_STATUS > > > +(EFIAPI *MV_SPI_FLASH_POWER_ON) ( > > > + IN SPI_DEVICE *SpiDev > > > + ); > > > + > > > struct _MARVELL_SPI_FLASH_PROTOCOL { > > > MV_SPI_FLASH_INIT Init; > > > MV_SPI_FLASH_READ_ID ReadId; > > > @@ -110,6 +116,7 @@ struct _MARVELL_SPI_FLASH_PROTOCOL { > > > MV_SPI_FLASH_ERASE Erase; > > > MV_SPI_FLASH_UPDATE Update; > > > MV_SPI_FLASH_UPDATE_WITH_PROGRESS UpdateWithProgress; > > > + MV_SPI_FLASH_POWER_ON FlashPowerOn; > > > }; > > > > > > #endif // __MV_SPI_FLASH__ > > > diff --git a/Silicon/Marvell/Drivers/Spi/MvFvbDxe/MvFvbDxe.c b/Silico= n/Marvell/Drivers/Spi/MvFvbDxe/MvFvbDxe.c > > > index cb006cd..b57f415 100644 > > > --- a/Silicon/Marvell/Drivers/Spi/MvFvbDxe/MvFvbDxe.c > > > +++ b/Silicon/Marvell/Drivers/Spi/MvFvbDxe/MvFvbDxe.c > > > @@ -311,6 +311,11 @@ MvFvbGetAttributes ( > > > > > > FlashInstance =3D INSTANCE_FROM_FVB_THIS (This); > > > > > > + // Ensure proper access to the flash device from OS level > > > + if (EfiAtRuntime ()) { > > > + FlashInstance->SpiFlashProtocol->FlashPowerOn (&FlashInstance->S= piDevice); > > > + } > > > + > > > FwVolHeader =3D (EFI_FIRMWARE_VOLUME_HEADER *)FlashInstance->Regio= nBaseAddress; > > > FlashFvbAttributes =3D (EFI_FVB_ATTRIBUTES_2 *)&(FwVolHeader->Attr= ibutes); > > > > > > @@ -349,10 +354,18 @@ MvFvbSetAttributes ( > > > EFI_FVB_ATTRIBUTES_2 OldAttributes; > > > EFI_FVB_ATTRIBUTES_2 FlashFvbAttributes; > > > EFI_FVB_ATTRIBUTES_2 UnchangedAttributes; > > > + FVB_DEVICE *FlashInstance; > > > UINT32 Capabilities; > > > UINT32 OldStatus; > > > UINT32 NewStatus; > > > > > > + FlashInstance =3D INSTANCE_FROM_FVB_THIS (This); > > > + > > > + // Ensure proper access to the flash device from OS level > > > + if (EfiAtRuntime ()) { > > > + FlashInstance->SpiFlashProtocol->FlashPowerOn (&FlashInstance->S= piDevice); > > > + } > > > + > > > // > > > // Obtain attributes from FVB header > > > // > > > @@ -468,6 +481,11 @@ MvFvbGetPhysicalAddress ( > > > > > > FlashInstance =3D INSTANCE_FROM_FVB_THIS (This); > > > > > > + // Ensure proper access to the flash device from OS level > > > + if (EfiAtRuntime ()) { > > > + FlashInstance->SpiFlashProtocol->FlashPowerOn (&FlashInstance->S= piDevice); > > > + } > > > + > > > *Address =3D FlashInstance->RegionBaseAddress; > > > > > > return EFI_SUCCESS; > > > @@ -588,6 +606,10 @@ MvFvbRead ( > > > > > > FlashInstance =3D INSTANCE_FROM_FVB_THIS (This); > > > > > > + // Ensure proper access to the flash device from OS level > > > + if (EfiAtRuntime ()) { > > > + FlashInstance->SpiFlashProtocol->FlashPowerOn (&FlashInstance->S= piDevice); > > > + } > > > > > > // Cache the block size to avoid de-referencing pointers all the t= ime > > > BlockSize =3D FlashInstance->Media.BlockSize; > > > @@ -697,6 +719,11 @@ MvFvbWrite ( > > > > > > FlashInstance =3D INSTANCE_FROM_FVB_THIS (This); > > > > > > + // Ensure proper access to the flash device from OS level > > > + if (EfiAtRuntime ()) { > > > + FlashInstance->SpiFlashProtocol->FlashPowerOn (&FlashInstance->S= piDevice); > > > + } > > > + > > > DataOffset =3D GET_DATA_OFFSET (FlashInstance->FvbOffset + Offset, > > > FlashInstance->StartLba + Lba, > > > FlashInstance->Media.BlockSize); > > > @@ -770,6 +797,11 @@ MvFvbEraseBlocks ( > > > > > > FlashInstance =3D INSTANCE_FROM_FVB_THIS (This); > > > > > > + // Ensure proper access to the flash device from OS level > > > + if (EfiAtRuntime ()) { > > > + FlashInstance->SpiFlashProtocol->FlashPowerOn (&FlashInstance->S= piDevice); > > > + } > > > + > > > Status =3D EFI_SUCCESS; > > > > > > // Detect WriteDisabled state > > > @@ -882,11 +914,13 @@ MvFvbVirtualNotifyEvent ( > > > // Convert SPI device description > > > EfiConvertPointer (0x0, (VOID**)&mFvbDevice->SpiDevice.Info); > > > EfiConvertPointer (0x0, (VOID**)&mFvbDevice->SpiDevice.HostRegiste= rBaseAddress); > > > + EfiConvertPointer (0x0, (VOID**)&mFvbDevice->SpiDevice.HostClockEn= ableRegister); > > > EfiConvertPointer (0x0, (VOID**)&mFvbDevice->SpiDevice); > > > > > > // Convert SpiFlashProtocol > > > EfiConvertPointer (0x0, (VOID**)&mFvbDevice->SpiFlashProtocol->Era= se); > > > EfiConvertPointer (0x0, (VOID**)&mFvbDevice->SpiFlashProtocol->Wri= te); > > > + EfiConvertPointer (0x0, (VOID**)&mFvbDevice->SpiFlashProtocol->Fla= shPowerOn); > > > EfiConvertPointer (0x0, (VOID**)&mFvbDevice->SpiFlashProtocol); > > > > > > return; > > > diff --git a/Silicon/Marvell/Drivers/Spi/MvSpiFlashDxe/MvSpiFlashDxe.= c b/Silicon/Marvell/Drivers/Spi/MvSpiFlashDxe/MvSpiFlashDxe.c > > > index d81f6e3..4cc897f 100755 > > > --- a/Silicon/Marvell/Drivers/Spi/MvSpiFlashDxe/MvSpiFlashDxe.c > > > +++ b/Silicon/Marvell/Drivers/Spi/MvSpiFlashDxe/MvSpiFlashDxe.c > > > @@ -548,6 +548,15 @@ MvSpiFlashInit ( > > > } > > > > > > EFI_STATUS > > > +EFIAPI > > > +MvSpiFlashPowerOn ( > > > + IN SPI_DEVICE *Slave > > > + ) > > > +{ > > > + return SpiMasterProtocol->ControllerPowerOn (Slave); > > > +} > > > + > > > +EFI_STATUS > > > MvSpiFlashInitProtocol ( > > > IN MARVELL_SPI_FLASH_PROTOCOL *SpiFlashProtocol > > > ) > > > @@ -560,6 +569,7 @@ MvSpiFlashInitProtocol ( > > > SpiFlashProtocol->Erase =3D MvSpiFlashErase; > > > SpiFlashProtocol->Update =3D MvSpiFlashUpdate; > > > SpiFlashProtocol->UpdateWithProgress =3D MvSpiFlashUpdateWithProgr= ess; > > > + SpiFlashProtocol->FlashPowerOn =3D MvSpiFlashPowerOn; > > > > > > return EFI_SUCCESS; > > > } > > > @@ -586,6 +596,7 @@ MvSpiFlashVirtualNotifyEvent ( > > > // > > > EfiConvertPointer (0x0, (VOID**)&SpiMasterProtocol->ReadWrite); > > > EfiConvertPointer (0x0, (VOID**)&SpiMasterProtocol->Transfer); > > > + EfiConvertPointer (0x0, (VOID**)&SpiMasterProtocol->ControllerPowe= rOn); > > > EfiConvertPointer (0x0, (VOID**)&SpiMasterProtocol); > > > > > > return; > > > diff --git a/Silicon/Marvell/Drivers/Spi/MvSpiOrionDxe/MvSpiOrionDxe.= c b/Silicon/Marvell/Drivers/Spi/MvSpiOrionDxe/MvSpiOrionDxe.c > > > index cbf403f..3f7f67e 100755 > > > --- a/Silicon/Marvell/Drivers/Spi/MvSpiOrionDxe/MvSpiOrionDxe.c > > > +++ b/Silicon/Marvell/Drivers/Spi/MvSpiOrionDxe/MvSpiOrionDxe.c > > > @@ -323,6 +323,11 @@ MvSpiSetupSlave ( > > > } > > > > > > Slave->HostRegisterBaseAddress =3D PcdGet32 (PcdSpiRegBase); > > > + Slave->HostClockFixed =3D PcdGetBool (PcdSpiClockFixed); > > > + if (!Slave->HostClockFixed) { > > > + Slave->HostClockEnableRegister =3D PcdGet64 (PcdSpiClockRegBase)= ; > > > + Slave->HostClockEnableMask =3D PcdGet32 (PcdSpiClockMask); > > > + } > > > Slave->CoreClock =3D PcdGet32 (PcdSpiClockFrequency); > > > Slave->MaxFreq =3D PcdGet32 (PcdSpiMaxFrequency); > > > > > > @@ -344,12 +349,26 @@ MvSpiFreeSlave ( > > > > > > EFI_STATUS > > > EFIAPI > > > +MvSpiControllerPowerOn ( > > > + IN SPI_DEVICE *Slave > > > + ) > > > +{ > > > + if (!Slave->HostClockFixed) { > > > + MmioOr32 (Slave->HostClockEnableRegister, Slave->HostClockEnable= Mask); > > > + } > > > + > > > + return EFI_SUCCESS; > > > +} > > > + > > > +EFI_STATUS > > > +EFIAPI > > > MvSpiConfigRuntime ( > > > IN SPI_DEVICE *Slave > > > ) > > > { > > > EFI_STATUS Status; > > > UINTN AlignedAddress; > > > + UINTN ClockEnableAlignedAddress; > > > > > > // > > > // Host register base may be not aligned to the page size, > > > @@ -373,11 +392,50 @@ MvSpiConfigRuntime ( > > > EFI_MEMORY_UC | EFI_MEMORY_RUNTIME); > > > if (EFI_ERROR (Status)) { > > > DEBUG ((DEBUG_ERROR, "%a: Failed to set memory attributes\n", __= FUNCTION__)); > > > - gDS->RemoveMemorySpace (AlignedAddress, SIZE_4KB); > > > - return Status; > > > + goto ErrorSetHostMemorySpace; > > > + } > > > + > > > + // > > > + // In case a clock feeding the SPI interface is always on, skip it= s > > > + // configuration for Runtime. > > > + // > > > + if (Slave->HostClockFixed) { > > > + return EFI_SUCCESS; > > > + } > > > + > > > + // > > > + // Make sure about an alignment of the memory space needed for clo= ck enabling. > > > + // Add one aligned page of memory space which covers the clock ena= bling > > > + // register. > > > + // > > > + ClockEnableAlignedAddress =3D Slave->HostClockEnableRegister & ~(S= IZE_4KB - 1); > > > + > > > + Status =3D gDS->AddMemorySpace (EfiGcdMemoryTypeMemoryMappedIo, > > > + ClockEnableAlignedAddress, > > > + SIZE_4KB, > > > + EFI_MEMORY_UC | EFI_MEMORY_RUNTIME); > > > + if (EFI_ERROR (Status)) { > > > + DEBUG ((DEBUG_ERROR, "%a: Failed to add memory space\n", __FUNCT= ION__)); > > > + goto ErrorSetHostMemorySpace; > > > + } > > > + > > > + Status =3D gDS->SetMemorySpaceAttributes (ClockEnableAlignedAddres= s, > > > + SIZE_4KB, > > > + EFI_MEMORY_UC | EFI_MEMORY_RUNTIME); > > > + if (EFI_ERROR (Status)) { > > > + DEBUG ((DEBUG_ERROR, "%a: Failed to set memory attributes\n", __= FUNCTION__)); > > > + goto ErrorSetClockMemorySpace; > > > } > > > > > > return EFI_SUCCESS; > > > + > > > +ErrorSetClockMemorySpace: > > > + gDS->RemoveMemorySpace (ClockEnableAlignedAddress, SIZE_4KB); > > > + > > > +ErrorSetHostMemorySpace: > > > + gDS->RemoveMemorySpace (AlignedAddress, SIZE_4KB); > > > + > > > + return Status; > > > } > > > > > > STATIC > > > @@ -393,6 +451,7 @@ SpiMasterInitProtocol ( > > > SpiMasterProtocol->Transfer =3D MvSpiTransfer; > > > SpiMasterProtocol->ReadWrite =3D MvSpiReadWrite; > > > SpiMasterProtocol->ConfigRuntime =3D MvSpiConfigRuntime; > > > + SpiMasterProtocol->ControllerPowerOn =3D MvSpiControllerPowerOn; > > > > > > return EFI_SUCCESS; > > > } > > > -- > > > 2.7.4 > > >