From 93d987e6adf91d1f00b207242965ec9be22882b0 Mon Sep 17 00:00:00 2001 From: Ard Biesheuvel Date: Wed, 24 Jan 2018 09:53:35 +0000 Subject: Silicon/SynQuacer/PlatformDxe: enable spread spectrum mode for ASM1061 SATA The ASM1061 SATA controller integrated into the DeveloperBox board emits too much electromagnetic radiation, so it needs spread spectrum mode enabled. Contributed-under: TianoCore Contribution Agreement 1.1 Signed-off-by: Ard Biesheuvel Reviewed-by: Leif Lindholm --- .../SynQuacer/Drivers/PlatformDxe/Asmedia118x.c | 140 ---------------- .../Socionext/SynQuacer/Drivers/PlatformDxe/Pci.c | 183 +++++++++++++++++++++ .../SynQuacer/Drivers/PlatformDxe/PlatformDxe.inf | 2 +- 3 files changed, 184 insertions(+), 141 deletions(-) delete mode 100644 Silicon/Socionext/SynQuacer/Drivers/PlatformDxe/Asmedia118x.c create mode 100644 Silicon/Socionext/SynQuacer/Drivers/PlatformDxe/Pci.c (limited to 'Silicon/Socionext/SynQuacer') diff --git a/Silicon/Socionext/SynQuacer/Drivers/PlatformDxe/Asmedia118x.c b/Silicon/Socionext/SynQuacer/Drivers/PlatformDxe/Asmedia118x.c deleted file mode 100644 index 874e83a649..0000000000 --- a/Silicon/Socionext/SynQuacer/Drivers/PlatformDxe/Asmedia118x.c +++ /dev/null @@ -1,140 +0,0 @@ - /** @file - SynQuacer DXE platform driver - PCIe support - - Copyright (c) 2017, Linaro, Ltd. All rights reserved.
- - This program and the accompanying materials are licensed and made available - under the terms and conditions of the BSD License which accompanies this - distribution. The full text of the license may be found at - http://opensource.org/licenses/bsd-license.php - - THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, - WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. -**/ - -#include "PlatformDxe.h" - -#define ASMEDIA_VID 0x1b21 -#define ASM1182E_PID 0x1182 -#define ASM1184E_PID 0x1184 - -#define ASM118x_PCIE_CAPABILITY_OFFSET 0x80 -#define ASM118x_PCIE_LINK_CONTROL_OFFSET (ASM118x_PCIE_CAPABILITY_OFFSET + \ - OFFSET_OF (PCI_CAPABILITY_PCIEXP, \ - LinkControl)) - -STATIC VOID *mPciProtocolNotifyRegistration; -STATIC EFI_EVENT mPciProtocolNotifyEvent; - -#pragma pack(1) -typedef struct { - EFI_PCI_CAPABILITY_HDR CapHdr; - PCI_REG_PCIE_CAPABILITY Pcie; -} PCIE_CAP; -#pragma pack() - -STATIC -VOID -RetrainAsm1184eDownstreamPort ( - IN EFI_PCI_IO_PROTOCOL *PciIo - ) -{ - UINT16 PciVidPid[2]; - EFI_STATUS Status; - PCIE_CAP Cap; - PCI_REG_PCIE_LINK_CONTROL LinkControl; - - Status = PciIo->Pci.Read (PciIo, EfiPciIoWidthUint16, PCI_VENDOR_ID_OFFSET, - ARRAY_SIZE (PciVidPid), &PciVidPid); - if (EFI_ERROR (Status)) { - DEBUG ((DEBUG_WARN, "%a: failed to read PCI vendor/product ID - %r\n", - __FUNCTION__, Status)); - return; - } - - if (PciVidPid[0] != ASMEDIA_VID || - (PciVidPid[1] != ASM1182E_PID && PciVidPid[1] != ASM1184E_PID)) { - return; - } - - // - // The upstream and downstream ports share the same PID/VID, so check - // the port type. This assumes the PCIe Express capability block lives - // at offset 0x80 in the port's config space, which is known to be the - // case for these particular chips. - // - ASSERT (sizeof (Cap) == sizeof (UINT32)); - ASSERT (sizeof (LinkControl) == sizeof (UINT16)); - - Status = PciIo->Pci.Read (PciIo, EfiPciIoWidthUint32, - ASM118x_PCIE_CAPABILITY_OFFSET, 1, &Cap); - ASSERT_EFI_ERROR (Status); - ASSERT (Cap.CapHdr.CapabilityID == EFI_PCI_CAPABILITY_ID_PCIEXP); - - if (Cap.Pcie.Bits.DevicePortType != PCIE_DEVICE_PORT_TYPE_DOWNSTREAM_PORT) { - return; - } - - DEBUG ((DEBUG_INFO, "%a: retraining ASM118x downstream PCIe port\n", - __FUNCTION__)); - - Status = PciIo->Pci.Read (PciIo, EfiPciIoWidthUint16, - ASM118x_PCIE_LINK_CONTROL_OFFSET, 1, &LinkControl); - ASSERT_EFI_ERROR (Status); - - LinkControl.Bits.RetrainLink = 1; - - Status = PciIo->Pci.Write (PciIo, EfiPciIoWidthUint16, - ASM118x_PCIE_LINK_CONTROL_OFFSET, 1, &LinkControl); - ASSERT_EFI_ERROR (Status); -} - -STATIC -VOID -EFIAPI -OnPciIoProtocolNotify ( - IN EFI_EVENT Event, - IN VOID *Context - ) -{ - EFI_PCI_IO_PROTOCOL *PciIo; - EFI_STATUS Status; - EFI_HANDLE HandleBuffer; - UINTN BufferSize; - - while (TRUE) { - BufferSize = sizeof (EFI_HANDLE); - Status = gBS->LocateHandle (ByRegisterNotify, NULL, - mPciProtocolNotifyRegistration, &BufferSize, &HandleBuffer); - if (EFI_ERROR (Status)) { - break; - } - - Status = gBS->HandleProtocol (HandleBuffer, &gEfiPciIoProtocolGuid, - (VOID **)&PciIo); - ASSERT_EFI_ERROR (Status); - - // - // The ASM1184E 4-port PCIe switch on the DeveloperBox board (and its - // 2-port sibling of which samples were used in development) needs a - // little nudge to get it to train the downstream links at Gen2 speed. - // - RetrainAsm1184eDownstreamPort (PciIo); - } -} - -EFI_STATUS -EFIAPI -RegisterPcieNotifier ( - VOID - ) -{ - mPciProtocolNotifyEvent = EfiCreateProtocolNotifyEvent ( - &gEfiPciIoProtocolGuid, - TPL_CALLBACK, - OnPciIoProtocolNotify, - NULL, - &mPciProtocolNotifyRegistration); - - return EFI_SUCCESS; -} diff --git a/Silicon/Socionext/SynQuacer/Drivers/PlatformDxe/Pci.c b/Silicon/Socionext/SynQuacer/Drivers/PlatformDxe/Pci.c new file mode 100644 index 0000000000..9af3dd942c --- /dev/null +++ b/Silicon/Socionext/SynQuacer/Drivers/PlatformDxe/Pci.c @@ -0,0 +1,183 @@ + /** @file + SynQuacer DXE platform driver - PCIe support + + Copyright (c) 2017, Linaro, Ltd. All rights reserved.
+ + This program and the accompanying materials are licensed and made available + under the terms and conditions of the BSD License which accompanies this + distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +**/ + +#include "PlatformDxe.h" + +#define ASMEDIA_VID 0x1b21 +#define ASM1061_PID 0x0612 +#define ASM1182E_PID 0x1182 +#define ASM1184E_PID 0x1184 + +#define ASM1061_SSC_OFFSET 0xA10 + +#define ASM118x_PCIE_CAPABILITY_OFFSET 0x80 +#define ASM118x_PCIE_LINK_CONTROL_OFFSET (ASM118x_PCIE_CAPABILITY_OFFSET + \ + OFFSET_OF (PCI_CAPABILITY_PCIEXP, \ + LinkControl)) + +STATIC VOID *mPciProtocolNotifyRegistration; +STATIC EFI_EVENT mPciProtocolNotifyEvent; + +#pragma pack(1) +typedef struct { + EFI_PCI_CAPABILITY_HDR CapHdr; + PCI_REG_PCIE_CAPABILITY Pcie; +} PCIE_CAP; +#pragma pack() + +STATIC +VOID +RetrainAsm1184eDownstreamPort ( + IN EFI_PCI_IO_PROTOCOL *PciIo + ) +{ + EFI_STATUS Status; + PCIE_CAP Cap; + PCI_REG_PCIE_LINK_CONTROL LinkControl; + + // + // The upstream and downstream ports share the same PID/VID, so check + // the port type. This assumes the PCIe Express capability block lives + // at offset 0x80 in the port's config space, which is known to be the + // case for these particular chips. + // + ASSERT (sizeof (Cap) == sizeof (UINT32)); + ASSERT (sizeof (LinkControl) == sizeof (UINT16)); + + Status = PciIo->Pci.Read (PciIo, EfiPciIoWidthUint32, + ASM118x_PCIE_CAPABILITY_OFFSET, 1, &Cap); + ASSERT_EFI_ERROR (Status); + ASSERT (Cap.CapHdr.CapabilityID == EFI_PCI_CAPABILITY_ID_PCIEXP); + + if (Cap.Pcie.Bits.DevicePortType != PCIE_DEVICE_PORT_TYPE_DOWNSTREAM_PORT) { + return; + } + + DEBUG ((DEBUG_INFO, "%a: retraining ASM118x downstream PCIe port\n", + __FUNCTION__)); + + Status = PciIo->Pci.Read (PciIo, EfiPciIoWidthUint16, + ASM118x_PCIE_LINK_CONTROL_OFFSET, 1, &LinkControl); + ASSERT_EFI_ERROR (Status); + + LinkControl.Bits.RetrainLink = 1; + + Status = PciIo->Pci.Write (PciIo, EfiPciIoWidthUint16, + ASM118x_PCIE_LINK_CONTROL_OFFSET, 1, &LinkControl); + ASSERT_EFI_ERROR (Status); +} + +STATIC +VOID +EnableAsm1061SpreadSpectrum ( + IN EFI_PCI_IO_PROTOCOL *PciIo + ) +{ + EFI_STATUS Status; + UINT8 SscVal; + + DEBUG ((DEBUG_INFO, "%a: enabling spread spectrum mode 0 for ASM1061\n", + __FUNCTION__)); + + // SSC mode 0~-4000 ppm, 1:1 modulation + + SscVal = 0; + Status = PciIo->Pci.Write (PciIo, EfiPciIoWidthUint8, ASM1061_SSC_OFFSET, 1, + &SscVal); + ASSERT_EFI_ERROR (Status); + + MemoryFence (); + gBS->Stall (1); // delay at least 100 ns between writes of the same register + + SscVal = 1; + Status = PciIo->Pci.Write (PciIo, EfiPciIoWidthUint8, ASM1061_SSC_OFFSET, 1, + &SscVal); + ASSERT_EFI_ERROR (Status); +} + +STATIC +VOID +EFIAPI +OnPciIoProtocolNotify ( + IN EFI_EVENT Event, + IN VOID *Context + ) +{ + EFI_PCI_IO_PROTOCOL *PciIo; + EFI_STATUS Status; + EFI_HANDLE HandleBuffer; + UINTN BufferSize; + UINT16 PciVidPid[2]; + + while (TRUE) { + BufferSize = sizeof (EFI_HANDLE); + Status = gBS->LocateHandle (ByRegisterNotify, NULL, + mPciProtocolNotifyRegistration, &BufferSize, &HandleBuffer); + if (EFI_ERROR (Status)) { + break; + } + + Status = gBS->HandleProtocol (HandleBuffer, &gEfiPciIoProtocolGuid, + (VOID **)&PciIo); + ASSERT_EFI_ERROR (Status); + + Status = PciIo->Pci.Read (PciIo, EfiPciIoWidthUint16, PCI_VENDOR_ID_OFFSET, + ARRAY_SIZE (PciVidPid), &PciVidPid); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_WARN, "%a: failed to read PCI vendor/product ID - %r\n", + __FUNCTION__, Status)); + continue; + } + + if (PciVidPid[0] != ASMEDIA_VID) { + continue; + } + + switch (PciVidPid[1]) { + case ASM1061_PID: + // + // The ASM1061 SATA controller as integrated into the DeveloperBox design + // emits too much electromagnetic radiation. So enable spread spectrum + // mode. + // + EnableAsm1061SpreadSpectrum (PciIo); + break; + case ASM1182E_PID: + case ASM1184E_PID: + // + // The ASM1184E 4-port PCIe switch on the DeveloperBox board (and its + // 2-port sibling of which samples were used in development) needs a + // little nudge to get it to train the downstream links at Gen2 speed. + // + RetrainAsm1184eDownstreamPort (PciIo); + break; + } + } +} + +EFI_STATUS +EFIAPI +RegisterPcieNotifier ( + VOID + ) +{ + mPciProtocolNotifyEvent = EfiCreateProtocolNotifyEvent ( + &gEfiPciIoProtocolGuid, + TPL_CALLBACK, + OnPciIoProtocolNotify, + NULL, + &mPciProtocolNotifyRegistration); + + return EFI_SUCCESS; +} diff --git a/Silicon/Socionext/SynQuacer/Drivers/PlatformDxe/PlatformDxe.inf b/Silicon/Socionext/SynQuacer/Drivers/PlatformDxe/PlatformDxe.inf index 7d3b88a5b5..766f4041c8 100644 --- a/Silicon/Socionext/SynQuacer/Drivers/PlatformDxe/PlatformDxe.inf +++ b/Silicon/Socionext/SynQuacer/Drivers/PlatformDxe/PlatformDxe.inf @@ -23,7 +23,7 @@ ENTRY_POINT = PlatformDxeEntryPoint [Sources] - Asmedia118x.c + Pci.c PlatformDxe.c [Packages] -- cgit v1.2.3