/* SimpleFbDxe: Simple FrameBuffer */ #include #include #include #include #include #include #include #include #include #include #include #include "Library/FrameBufferBltLib.h" #include /// Defines /* * Convert enum video_log2_bpp to bytes and bits. Note we omit the outer * brackets to allow multiplication by fractional pixels. */ #define VNBYTES(bpix) (1 << (bpix)) / 8 #define VNBITS(bpix) (1 << (bpix)) #define FB_BITS_PER_PIXEL (32) #define FB_BYTES_PER_PIXEL (FB_BITS_PER_PIXEL / 8) /* * Bits per pixel selector. Each value n is such that the bits-per-pixel is * 2 ^ n */ enum video_log2_bpp { VIDEO_BPP1 = 0, VIDEO_BPP2, VIDEO_BPP4, VIDEO_BPP8, VIDEO_BPP16, VIDEO_BPP32, }; typedef struct { VENDOR_DEVICE_PATH DisplayDevicePath; EFI_DEVICE_PATH EndDevicePath; } DISPLAY_DEVICE_PATH; DISPLAY_DEVICE_PATH mDisplayDevicePath = { { { HARDWARE_DEVICE_PATH, HW_VENDOR_DP, { (UINT8)(sizeof(VENDOR_DEVICE_PATH)), (UINT8)((sizeof(VENDOR_DEVICE_PATH)) >> 8), } }, EFI_GRAPHICS_OUTPUT_PROTOCOL_GUID }, { END_DEVICE_PATH_TYPE, END_ENTIRE_DEVICE_PATH_SUBTYPE, { sizeof(EFI_DEVICE_PATH_PROTOCOL), 0 } } }; /// DeclaresSimpleFbDxe/SimpleFbDxe.c STATIC FRAME_BUFFER_CONFIGURE *mFrameBufferBltLibConfigure; STATIC UINTN mFrameBufferBltLibConfigureSize; STATIC EFI_STATUS EFIAPI DisplayQueryMode ( IN EFI_GRAPHICS_OUTPUT_PROTOCOL *This, IN UINT32 ModeNumber, OUT UINTN *SizeOfInfo, OUT EFI_GRAPHICS_OUTPUT_MODE_INFORMATION **Info ); STATIC EFI_STATUS EFIAPI DisplaySetMode ( IN EFI_GRAPHICS_OUTPUT_PROTOCOL *This, IN UINT32 ModeNumber ); STATIC EFI_STATUS EFIAPI DisplayBlt ( IN EFI_GRAPHICS_OUTPUT_PROTOCOL *This, IN EFI_GRAPHICS_OUTPUT_BLT_PIXEL *BltBuffer, OPTIONAL IN EFI_GRAPHICS_OUTPUT_BLT_OPERATION BltOperation, IN UINTN SourceX, IN UINTN SourceY, IN UINTN DestinationX, IN UINTN DestinationY, IN UINTN Width, IN UINTN Height, IN UINTN Delta OPTIONAL ); STATIC EFI_GRAPHICS_OUTPUT_PROTOCOL mDisplay = { DisplayQueryMode, DisplaySetMode, DisplayBlt, NULL }; STATIC EFI_STATUS EFIAPI DisplayQueryMode ( IN EFI_GRAPHICS_OUTPUT_PROTOCOL *This, IN UINT32 ModeNumber, OUT UINTN *SizeOfInfo, OUT EFI_GRAPHICS_OUTPUT_MODE_INFORMATION **Info ) { EFI_STATUS Status; Status = gBS->AllocatePool( EfiBootServicesData, sizeof(EFI_GRAPHICS_OUTPUT_MODE_INFORMATION), (VOID **) Info); ASSERT_EFI_ERROR(Status); *SizeOfInfo = sizeof(EFI_GRAPHICS_OUTPUT_MODE_INFORMATION); (*Info)->Version = This->Mode->Info->Version; (*Info)->HorizontalResolution = This->Mode->Info->HorizontalResolution; (*Info)->VerticalResolution = This->Mode->Info->VerticalResolution; (*Info)->PixelFormat = This->Mode->Info->PixelFormat; (*Info)->PixelsPerScanLine = This->Mode->Info->PixelsPerScanLine; return EFI_SUCCESS; } STATIC EFI_STATUS EFIAPI DisplaySetMode ( IN EFI_GRAPHICS_OUTPUT_PROTOCOL *This, IN UINT32 ModeNumber ) { return EFI_SUCCESS; } STATIC EFI_STATUS EFIAPI DisplayBlt ( IN EFI_GRAPHICS_OUTPUT_PROTOCOL *This, IN EFI_GRAPHICS_OUTPUT_BLT_PIXEL *BltBuffer, OPTIONAL IN EFI_GRAPHICS_OUTPUT_BLT_OPERATION BltOperation, IN UINTN SourceX, IN UINTN SourceY, IN UINTN DestinationX, IN UINTN DestinationY, IN UINTN Width, IN UINTN Height, IN UINTN Delta OPTIONAL ) { RETURN_STATUS Status; EFI_TPL Tpl; // // We have to raise to TPL_NOTIFY, so we make an atomic write to the frame buffer. // We would not want a timer based event (Cursor, ...) to come in while we are // doing this operation. // Tpl = gBS->RaiseTPL (TPL_NOTIFY); Status = FrameBufferBlt ( mFrameBufferBltLibConfigure, BltBuffer, BltOperation, SourceX, SourceY, DestinationX, DestinationY, Width, Height, Delta ); gBS->RestoreTPL (Tpl); // zhuowei: hack: flush the cache manually since my memory maps are still broken WriteBackInvalidateDataCacheRange((void*)mDisplay.Mode->FrameBufferBase, mDisplay.Mode->FrameBufferSize); // zhuowei: end hack return RETURN_ERROR (Status) ? EFI_INVALID_PARAMETER : EFI_SUCCESS; } EFI_STATUS EFIAPI SimpleFbDxeInitialize ( IN EFI_HANDLE ImageHandle, IN EFI_SYSTEM_TABLE *SystemTable ) { EFI_STATUS Status = EFI_SUCCESS; EFI_HANDLE hUEFIDisplayHandle = NULL; /* Retrieve simple frame buffer from pre-SEC bootloader */ DEBUG((EFI_D_ERROR, "SimpleFbDxe: Retrieve MIPI FrameBuffer parameters from PCD\n")); UINT32 MipiFrameBufferAddr = FixedPcdGet32(PcdMipiFrameBufferAddress); UINT32 MipiFrameBufferWidth = FixedPcdGet32(PcdMipiFrameBufferWidth); UINT32 MipiFrameBufferHeight = FixedPcdGet32(PcdMipiFrameBufferHeight); /* Sanity check */ if (MipiFrameBufferAddr == 0 || MipiFrameBufferWidth == 0 || MipiFrameBufferHeight == 0) { DEBUG((EFI_D_ERROR, "SimpleFbDxe: Invalid FrameBuffer parameters\n")); return EFI_DEVICE_ERROR; } /* Prepare struct */ if (mDisplay.Mode == NULL) { Status = gBS->AllocatePool( EfiBootServicesData, sizeof(EFI_GRAPHICS_OUTPUT_PROTOCOL_MODE), (VOID **) &mDisplay.Mode ); ASSERT_EFI_ERROR(Status); if (EFI_ERROR(Status)) return Status; ZeroMem(mDisplay.Mode, sizeof(EFI_GRAPHICS_OUTPUT_PROTOCOL_MODE)); } if (mDisplay.Mode->Info == NULL) { Status = gBS->AllocatePool( EfiBootServicesData, sizeof(EFI_GRAPHICS_OUTPUT_MODE_INFORMATION), (VOID **) &mDisplay.Mode->Info ); ASSERT_EFI_ERROR(Status); if (EFI_ERROR(Status)) return Status; ZeroMem(mDisplay.Mode->Info, sizeof(EFI_GRAPHICS_OUTPUT_MODE_INFORMATION)); } /* Set information */ mDisplay.Mode->MaxMode = 1; mDisplay.Mode->Mode = 0; mDisplay.Mode->Info->Version = 0; mDisplay.Mode->Info->HorizontalResolution = MipiFrameBufferWidth; mDisplay.Mode->Info->VerticalResolution = MipiFrameBufferHeight; /* SimpleFB runs on a8r8g8b8 (VIDEO_BPP32) for DB410c */ UINT32 LineLength = MipiFrameBufferWidth * VNBYTES(VIDEO_BPP32); UINT32 FrameBufferSize = LineLength * MipiFrameBufferHeight; EFI_PHYSICAL_ADDRESS FrameBufferAddress = MipiFrameBufferAddr; mDisplay.Mode->Info->PixelsPerScanLine = MipiFrameBufferWidth; mDisplay.Mode->Info->PixelFormat = PixelBlueGreenRedReserved8BitPerColor; mDisplay.Mode->SizeOfInfo = sizeof(EFI_GRAPHICS_OUTPUT_MODE_INFORMATION); mDisplay.Mode->FrameBufferBase = FrameBufferAddress; mDisplay.Mode->FrameBufferSize = FrameBufferSize; // // Create the FrameBufferBltLib configuration. // Status = FrameBufferBltConfigure ( (VOID *) (UINTN) mDisplay.Mode->FrameBufferBase, mDisplay.Mode->Info, mFrameBufferBltLibConfigure, &mFrameBufferBltLibConfigureSize ); if (Status == RETURN_BUFFER_TOO_SMALL) { mFrameBufferBltLibConfigure = AllocatePool (mFrameBufferBltLibConfigureSize); if (mFrameBufferBltLibConfigure != NULL) { Status = FrameBufferBltConfigure ( (VOID *) (UINTN) mDisplay.Mode->FrameBufferBase, mDisplay.Mode->Info, mFrameBufferBltLibConfigure, &mFrameBufferBltLibConfigureSize ); } } ASSERT_EFI_ERROR (Status); // zhuowei: clear the screen to black // UEFI standard requires this, since text is white - see OvmfPkg/QemuVideoDxe/Gop.c ZeroMem((void*)FrameBufferAddress, FrameBufferSize); // hack: clear cache WriteBackInvalidateDataCacheRange((void*)FrameBufferAddress, FrameBufferSize); // zhuowei: end /* Register handle */ Status = gBS->InstallMultipleProtocolInterfaces( &hUEFIDisplayHandle, &gEfiDevicePathProtocolGuid, &mDisplayDevicePath, &gEfiGraphicsOutputProtocolGuid, &mDisplay, NULL); ASSERT_EFI_ERROR (Status); return Status; }