/** Reads a bit field in a 16-bit PCI configuration, performs a bitwise OR, and writes the result back to the bit field in the 16-bit port. Reads the 16-bit PCI configuration register specified by Address, performs a bitwise OR between the read result and the value specified by OrData, and writes the result to the 16-bit PCI configuration register specified by Address. The value written to the PCI configuration register is returned. This function must guarantee that all PCI read and write operations are serialized. Extra left bits in OrData are stripped. If Address > 0x0FFFFFFF, then ASSERT(). If Address is not aligned on a 16-bit boundary, then ASSERT(). If StartBit is greater than 15, then ASSERT(). If EndBit is greater than 15, then ASSERT(). If EndBit is less than StartBit, then ASSERT(). If OrData is larger than the bitmask value range specified by StartBit and EndBit, then ASSERT(). @param Address The PCI configuration register to write. @param StartBit The ordinal of the least significant bit in the bit field. Range 0..15. @param EndBit The ordinal of the most significant bit in the bit field. Range 0..15. @param OrData The value to OR with the PCI configuration register. @return The value written back to the PCI configuration register. **/ UINT16 EFIAPI PciBitFieldOr16 ( IN UINTN Address, IN UINTN StartBit, IN UINTN EndBit, IN UINT16 OrData ) { return PciWrite16 ( Address, BitFieldOr16 (PciRead16 (Address), StartBit, EndBit, OrData) ); }
/** Writes a bit field to a PCI configuration register. Writes Value to the bit field of the PCI configuration register. The bit field is specified by the StartBit and the EndBit. All other bits in the destination PCI configuration register are preserved. The new value of the 16-bit register is returned. If Address > 0x0FFFFFFF, then ASSERT(). If Address is not aligned on a 16-bit boundary, then ASSERT(). If StartBit is greater than 15, then ASSERT(). If EndBit is greater than 15, then ASSERT(). If EndBit is less than StartBit, then ASSERT(). If Value is larger than the bitmask value range specified by StartBit and EndBit, then ASSERT(). @param Address The PCI configuration register to write. @param StartBit The ordinal of the least significant bit in the bit field. Range 0..15. @param EndBit The ordinal of the most significant bit in the bit field. Range 0..15. @param Value The new value of the bit field. @return The value written back to the PCI configuration register. **/ UINT16 EFIAPI PciBitFieldWrite16 ( IN UINTN Address, IN UINTN StartBit, IN UINTN EndBit, IN UINT16 Value ) { return PciWrite16 ( Address, BitFieldWrite16 (PciRead16 (Address), StartBit, EndBit, Value) ); }
/** Perform USB erratas after MRC init. **/ VOID PlatformUsbErratasPostMrc ( VOID ) { UINT32 Index; UINT32 TempBar0Addr; UINT16 SaveCmdReg; UINT32 SaveBar0Reg; TempBar0Addr = PcdGet32(PcdPeiQNCUsbControllerMemoryBaseAddress); // // Apply EHCI controller erratas. // for (Index = 0; Index < IOH_MAX_EHCI_USB_CONTROLLERS; Index++, TempBar0Addr += IOH_USB_CONTROLLER_MMIO_RANGE) { if ((PciRead16 (IohEhciPciReg[Index] + R_IOH_USB_VENDOR_ID)) != V_IOH_USB_VENDOR_ID) { continue; // Device not enabled, skip. } // // Save current settings for PCI CMD/BAR0 registers // SaveCmdReg = PciRead16 (IohEhciPciReg[Index] + R_IOH_USB_COMMAND); SaveBar0Reg = PciRead32 (IohEhciPciReg[Index] + R_IOH_USB_MEMBAR); // // Temp. assign base address register, Enable Memory Space. // PciWrite32 ((IohEhciPciReg[Index] + R_IOH_USB_MEMBAR), TempBar0Addr); PciWrite16 (IohEhciPciReg[Index] + R_IOH_USB_COMMAND, SaveCmdReg | B_IOH_USB_COMMAND_MSE); // // Set packet buffer OUT/IN thresholds. // MmioAndThenOr32 ( TempBar0Addr + R_IOH_EHCI_INSNREG01, (UINT32) (~(B_IOH_EHCI_INSNREG01_OUT_THRESHOLD_MASK | B_IOH_EHCI_INSNREG01_IN_THRESHOLD_MASK)), (UINT32) ((EHCI_OUT_THRESHOLD_VALUE << B_IOH_EHCI_INSNREG01_OUT_THRESHOLD_BP) | (EHCI_IN_THRESHOLD_VALUE << B_IOH_EHCI_INSNREG01_IN_THRESHOLD_BP)) ); // // Restore settings for PCI CMD/BAR0 registers // PciWrite32 ((IohEhciPciReg[Index] + R_IOH_USB_MEMBAR), SaveBar0Reg); PciWrite16 (IohEhciPciReg[Index] + R_IOH_USB_COMMAND, SaveCmdReg); } // // Apply USB device controller erratas. // for (Index = 0; Index < IOH_MAX_USBDEVICE_USB_CONTROLLERS; Index++, TempBar0Addr += IOH_USB_CONTROLLER_MMIO_RANGE) { if ((PciRead16 (IohUsbDevicePciReg[Index] + R_IOH_USB_VENDOR_ID)) != V_IOH_USB_VENDOR_ID) { continue; // Device not enabled, skip. } // // Save current settings for PCI CMD/BAR0 registers // SaveCmdReg = PciRead16 (IohUsbDevicePciReg[Index] + R_IOH_USB_COMMAND); SaveBar0Reg = PciRead32 (IohUsbDevicePciReg[Index] + R_IOH_USB_MEMBAR); // // Temp. assign base address register, Enable Memory Space. // PciWrite32 ((IohUsbDevicePciReg[Index] + R_IOH_USB_MEMBAR), TempBar0Addr); PciWrite16 (IohUsbDevicePciReg[Index] + R_IOH_USB_COMMAND, SaveCmdReg | B_IOH_USB_COMMAND_MSE); // // Erratas for USB Device interrupt registers. // // // 1st Mask interrupts. // MmioWrite32 ( TempBar0Addr + R_IOH_USBDEVICE_D_INTR_MSK_UDC_REG, V_IOH_USBDEVICE_D_INTR_MSK_UDC_REG ); // // 2nd RW/1C of equivalent status bits. // MmioWrite32 ( TempBar0Addr + R_IOH_USBDEVICE_D_INTR_UDC_REG, V_IOH_USBDEVICE_D_INTR_MSK_UDC_REG ); // // 1st Mask end point interrupts. // MmioWrite32 ( TempBar0Addr + R_IOH_USBDEVICE_EP_INTR_MSK_UDC_REG, V_IOH_USBDEVICE_EP_INTR_MSK_UDC_REG ); // // 2nd RW/1C of equivalent end point status bits. // MmioWrite32 ( TempBar0Addr + R_IOH_USBDEVICE_EP_INTR_UDC_REG, V_IOH_USBDEVICE_EP_INTR_MSK_UDC_REG ); // // Restore settings for PCI CMD/BAR0 registers // PciWrite32 ((IohUsbDevicePciReg[Index] + R_IOH_USB_MEMBAR), SaveBar0Reg); PciWrite16 (IohUsbDevicePciReg[Index] + R_IOH_USB_COMMAND, SaveCmdReg); } }
/* For each function we create a * pci_device and add it to the list */ void PciCheckFunction(list_t *Bridge, uint8_t Bus, uint8_t Device, uint8_t Function) { uint8_t SecondBus; PciNativeHeader_t *Pcs; PciDevice_t *PciDevice; /* Allocate */ Pcs = (PciNativeHeader_t*)kmalloc(sizeof(PciNativeHeader_t)); PciDevice = (PciDevice_t*)kmalloc(sizeof(PciDevice_t)); /* Get full information */ PciReadFunction(Pcs, Bus, Device, Function); /* Set information */ PciDevice->Header = Pcs; PciDevice->Bus = Bus; PciDevice->Device = Device; PciDevice->Function = Function; PciDevice->Children = NULL; /* Info * Ignore the spam of device_id 0x7a0 in VMWare*/ if (Pcs->DeviceId != 0x7a0) { #ifdef X86_PCI_DIAGNOSE printf(" * [%d:%d:%d][%d:%d:%d] Vendor 0x%x, Device 0x%x : %s\n", Pcs->Class, Pcs->Subclass, Pcs->Interface, Bus, Device, Function, Pcs->VendorId, Pcs->DeviceId, PciToString(Pcs->Class, Pcs->Subclass, Pcs->Interface)); #endif } /* Do some disabling, but NOT on the video or bridge */ if ((Pcs->Class != PCI_DEVICE_CLASS_BRIDGE) && (Pcs->Class != PCI_DEVICE_CLASS_VIDEO)) { /* Disable Device untill further notice */ uint16_t PciSettings = PciRead16(Bus, Device, Function, 0x04); PciWrite16(Bus, Device, Function, 0x04, PciSettings | X86_PCI_COMMAND_INTDISABLE); } /* Add to list */ if (Pcs->Class == PCI_DEVICE_CLASS_BRIDGE && Pcs->Subclass == PCI_DEVICE_SUBCLASS_PCI) { PciDevice->Type = X86_PCI_TYPE_BRIDGE; list_append(Bridge, list_create_node(X86_PCI_TYPE_BRIDGE, PciDevice)); } else { PciDevice->Type = X86_PCI_TYPE_DEVICE; list_append(Bridge, list_create_node(X86_PCI_TYPE_DEVICE, PciDevice)); } /* Is this a secondary (PCI) bus */ if ((Pcs->Class == PCI_DEVICE_CLASS_BRIDGE) && (Pcs->Subclass == PCI_DEVICE_SUBCLASS_PCI)) { /* Uh oh, this dude has children */ PciDevice->Children = list_create(LIST_SAFE); SecondBus = PciReadSecondaryBusNumber(Bus, Device, Function); PciCheckBus(PciDevice->Children, SecondBus); } }
/** Copies the data in a caller supplied buffer to a specified range of PCI configuration space. Writes the range of PCI configuration registers specified by StartAddress and Size from the buffer specified by Buffer. This function only allows the PCI configuration registers from a single PCI function to be written. Size is returned. When possible 32-bit PCI configuration write cycles are used to write from StartAdress to StartAddress + Size. Due to alignment restrictions, 8-bit and 16-bit PCI configuration write cycles may be used at the beginning and the end of the range. If StartAddress > 0x0FFFFFFF, then ASSERT(). If ((StartAddress & 0xFFF) + Size) > 0x1000, then ASSERT(). If Size > 0 and Buffer is NULL, then ASSERT(). @param StartAddress The starting address that encodes the PCI Bus, Device, Function and Register. @param Size The size in bytes of the transfer. @param Buffer The pointer to a buffer containing the data to write. @return Size written to StartAddress. **/ UINTN EFIAPI PciWriteBuffer ( IN UINTN StartAddress, IN UINTN Size, IN VOID *Buffer ) { UINTN ReturnValue; ASSERT_INVALID_PCI_ADDRESS (StartAddress, 0); ASSERT (((StartAddress & 0xFFF) + Size) <= 0x1000); if (Size == 0) { return 0; } ASSERT (Buffer != NULL); // // Save Size for return // ReturnValue = Size; if ((StartAddress & BIT0) != 0) { // // Write a byte if StartAddress is byte aligned // PciWrite8 (StartAddress, *(UINT8*)Buffer); StartAddress += sizeof (UINT8); Size -= sizeof (UINT8); Buffer = (UINT8*)Buffer + 1; } if (Size >= sizeof (UINT16) && (StartAddress & BIT1) != 0) { // // Write a word if StartAddress is word aligned // PciWrite16 (StartAddress, ReadUnaligned16 (Buffer)); StartAddress += sizeof (UINT16); Size -= sizeof (UINT16); Buffer = (UINT16*)Buffer + 1; } while (Size >= sizeof (UINT32)) { // // Write as many double words as possible // PciWrite32 (StartAddress, ReadUnaligned32 (Buffer)); StartAddress += sizeof (UINT32); Size -= sizeof (UINT32); Buffer = (UINT32*)Buffer + 1; } if (Size >= sizeof (UINT16)) { // // Write the last remaining word if exist // PciWrite16 (StartAddress, ReadUnaligned16 (Buffer)); StartAddress += sizeof (UINT16); Size -= sizeof (UINT16); Buffer = (UINT16*)Buffer + 1; } if (Size >= sizeof (UINT8)) { // // Write the last remaining byte if exist // PciWrite8 (StartAddress, *(UINT8*)Buffer); } return ReturnValue; }
/** Performs any early platform specific GPIO Controller manipulation. **/ VOID EFIAPI EarlyPlatformGpioCtrlerManipulation ( VOID ) { UINT32 IohGpioBase; UINT32 Data32; UINT32 Addr; UINT32 DevPcieAddr; UINT16 SaveCmdReg; UINT32 SaveBarReg; UINT16 PciVid; UINT16 PciDid; IohGpioBase = (UINT32) PcdGet64 (PcdIohGpioMmioBase); DevPcieAddr = PCI_LIB_ADDRESS ( PcdGet8 (PcdIohGpioBusNumber), PcdGet8 (PcdIohGpioDevNumber), PcdGet8 (PcdIohGpioFunctionNumber), 0 ); // // Do nothing if not a supported device. // PciVid = PciRead16 (DevPcieAddr + PCI_VENDOR_ID_OFFSET); PciDid = PciRead16 (DevPcieAddr + PCI_DEVICE_ID_OFFSET); if((PciVid != V_IOH_I2C_GPIO_VENDOR_ID) || (PciDid != V_IOH_I2C_GPIO_DEVICE_ID)) { return; } // // Save current settings for PCI CMD/BAR registers. // SaveCmdReg = PciRead16 (DevPcieAddr + PCI_COMMAND_OFFSET); SaveBarReg = PciRead32 (DevPcieAddr + PcdGet8 (PcdIohGpioBarRegister)); // // Use predefined tempory memory resource. // PciWrite32 ( DevPcieAddr + PcdGet8 (PcdIohGpioBarRegister), IohGpioBase); PciWrite8 ( DevPcieAddr + PCI_COMMAND_OFFSET, EFI_PCI_COMMAND_MEMORY_SPACE); // // Gpio Controller Manipulation Tasks. // // // Reset Cypress Expander on Galileo Platform // Addr = IohGpioBase + GPIO_SWPORTA_DR; Data32 = *((volatile UINT32 *) (UINTN)(Addr)); Data32 |= BIT4; // Cypress Reset line controlled by GPIO<4> *((volatile UINT32 *) (UINTN)(Addr)) = Data32; Data32 = *((volatile UINT32 *) (UINTN)(Addr)); Data32 &= ~BIT4; // Cypress Reset line controlled by GPIO<4> *((volatile UINT32 *) (UINTN)(Addr)) = Data32; // // Restore settings for PCI CMD/BAR registers // PciWrite32 ((DevPcieAddr + PcdGet8 (PcdIohGpioBarRegister)), SaveBarReg); PciWrite16 (DevPcieAddr + PCI_COMMAND_OFFSET, SaveCmdReg); }
/* For each function we create a * pci_device and add it to the list */ void PciCheckFunction(list_t *Bridge, PciBus_t *BusIo, uint8_t Bus, uint8_t Device, uint8_t Function) { /* Vars */ MCoreDevice_t *mDevice; uint8_t SecondBus; PciNativeHeader_t *Pcs; PciDevice_t *PciDevice; /* Allocate */ Pcs = (PciNativeHeader_t*)kmalloc(sizeof(PciNativeHeader_t)); PciDevice = (PciDevice_t*)kmalloc(sizeof(PciDevice_t)); /* Get full information */ PciReadFunction(Pcs, BusIo, Bus, Device, Function); /* Set information */ PciDevice->PciBus = BusIo; PciDevice->Header = Pcs; PciDevice->Bus = Bus; PciDevice->Device = Device; PciDevice->Function = Function; PciDevice->Children = NULL; /* Info * Ignore the spam of device_id 0x7a0 in VMWare*/ if (Pcs->DeviceId != 0x7a0) { #ifdef X86_PCI_DIAGNOSE printf(" * [%d:%d:%d][%d:%d:%d] Vendor 0x%x, Device 0x%x : %s\n", Pcs->Class, Pcs->Subclass, Pcs->Interface, Bus, Device, Function, Pcs->VendorId, Pcs->DeviceId, PciToString(Pcs->Class, Pcs->Subclass, Pcs->Interface)); #endif } /* Do some disabling, but NOT on the video or bridge */ if ((Pcs->Class != PCI_DEVICE_CLASS_BRIDGE) && (Pcs->Class != PCI_DEVICE_CLASS_VIDEO)) { /* Disable Device untill further notice */ uint16_t PciSettings = PciRead16(BusIo, Bus, Device, Function, 0x04); PciWrite16(BusIo, Bus, Device, Function, 0x04, PciSettings | X86_PCI_COMMAND_INTDISABLE); } /* Add to list */ if (Pcs->Class == PCI_DEVICE_CLASS_BRIDGE && Pcs->Subclass == PCI_DEVICE_SUBCLASS_PCI) { PciDevice->Type = X86_PCI_TYPE_BRIDGE; list_append(Bridge, list_create_node(X86_PCI_TYPE_BRIDGE, PciDevice)); /* Uh oh, this dude has children */ PciDevice->Children = list_create(LIST_SAFE); /* Get secondary bus no and iterate */ SecondBus = PciReadSecondaryBusNumber(BusIo, Bus, Device, Function); PciCheckBus(PciDevice->Children, BusIo, SecondBus); } else { /* This is an device */ PciDevice->Type = X86_PCI_TYPE_DEVICE; list_append(Bridge, list_create_node(X86_PCI_TYPE_DEVICE, PciDevice)); /* Register device with the OS */ mDevice = (MCoreDevice_t*)kmalloc(sizeof(MCoreDevice_t)); memset(mDevice, 0, sizeof(MCoreDevice_t)); /* Setup information */ mDevice->VendorId = Pcs->VendorId; mDevice->DeviceId = Pcs->DeviceId; mDevice->Class = Pcs->Class; mDevice->Subclass = Pcs->Subclass; mDevice->Interface = Pcs->Interface; mDevice->Segment = (DevInfo_t)BusIo->Segment; mDevice->Bus = Bus; mDevice->Device = Device; mDevice->Function = Function; mDevice->IrqLine = -1; mDevice->IrqPin = (int)Pcs->InterruptPin; mDevice->IrqAvailable[0] = Pcs->InterruptLine; /* Type */ mDevice->Type = DeviceUnknown; mDevice->Data = NULL; /* Save bus information */ mDevice->BusInformation = PciDevice; /* Initial */ mDevice->Driver.Name = NULL; mDevice->Driver.Version = -1; mDevice->Driver.Data = NULL; mDevice->Driver.Status = DriverNone; /* Read Bars */ PciReadBars(BusIo, mDevice, Pcs->HeaderType); /* Register */ DmCreateDevice((char*)PciToString(Pcs->Class, Pcs->Subclass, Pcs->Interface), mDevice); } }