Back to home page

LXR

 
 

    


File indexing completed on 2025-05-11 08:24:09

0001 /* SPDX-License-Identifier: BSD-2-Clause */
0002 
0003 /**
0004  * @file
0005  *
0006  * @ingroup RTEMSBSPsX8664AMD64EFI
0007  *
0008  * @brief EFI GOP implementation
0009  */
0010 
0011 /*
0012  * Copyright (C) 2023 Karel Gardas
0013  *
0014  * Redistribution and use in source and binary forms, with or without
0015  * modification, are permitted provided that the following conditions
0016  * are met:
0017  * 1. Redistributions of source code must retain the above copyright
0018  *    notice, this list of conditions and the following disclaimer.
0019  * 2. Redistributions in binary form must reproduce the above copyright
0020  *    notice, this list of conditions and the following disclaimer in the
0021  *    documentation and/or other materials provided with the distribution.
0022  *
0023  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
0024  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
0025  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
0026  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
0027  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
0028  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
0029  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
0030  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
0031  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
0032  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
0033  * POSSIBILITY OF SUCH DAMAGE.
0034  */
0035 
0036 #include <bsp.h>
0037 
0038 #include <efi.h>
0039 
0040 #include <rtems/bspIo.h>
0041 
0042 #include <rtems/framebuffer.h>
0043 #include <rtems/fb.h>
0044 #include <rtems/score/atomic.h>
0045 #include <rtems/libio.h>
0046 
0047 #include <efigop.h>
0048 
0049 #include <stdio.h>
0050 #include <string.h>
0051 #include <stdlib.h>
0052 
0053 #ifdef BSP_USE_EFI_BOOT_SERVICES
0054 
0055 static Atomic_Flag driver_mutex;
0056 
0057 extern EFI_SYSTEM_TABLE         *ST;
0058 extern EFI_BOOT_SERVICES        *BS;
0059 
0060 static struct fb_var_screeninfo gopfb_var = {
0061                                              .xres = 0,
0062                                              .yres = 0,
0063                                              .bits_per_pixel = 32
0064 };
0065 
0066 static struct fb_fix_screeninfo gopfb_fix = {
0067                                              .smem_start = NULL,
0068                                              .smem_len = 0,
0069                                              .type = FB_TYPE_PACKED_PIXELS,
0070                                              .visual = FB_VISUAL_TRUECOLOR,
0071                                              .line_length = 0
0072 };
0073 
0074 static EFI_GRAPHICS_OUTPUT*
0075 find_gop(void);
0076 
0077 static int
0078 init_gop(EFI_GRAPHICS_OUTPUT*, int);
0079 
0080 static int
0081 init_fb_from_gop(EFI_GRAPHICS_OUTPUT *gop, struct fb_var_screeninfo* fbvar, struct fb_fix_screeninfo* fbfix);
0082 
0083 extern void rpi_fb_outch(char);
0084 extern void rpi_video_init(void);
0085 
0086 void
0087 efi_graphic_output_char(char c)
0088 {
0089     rpi_fb_outch(c);
0090 }
0091 
0092 rtems_device_driver
0093 frame_buffer_initialize
0094 (rtems_device_major_number major,
0095  rtems_device_minor_number minor,
0096  void *arg)
0097 {
0098     rtems_status_code status;
0099 
0100     status = rtems_io_register_name(FRAMEBUFFER_DEVICE_0_NAME, major, 0);
0101     if (status != RTEMS_SUCCESSFUL) {
0102         printf("EFI/GOP: error: can't register /dev/fb0 device.\n");
0103         rtems_fatal_error_occurred(status);
0104     }
0105     _Atomic_Flag_clear( &driver_mutex, ATOMIC_ORDER_RELEASE );
0106     if (_Atomic_Flag_test_and_set(&driver_mutex, ATOMIC_ORDER_ACQUIRE) != 0) {
0107         printf("EFI/GOP: error: can't lock device mutex.\n" );
0108         return RTEMS_UNSATISFIED;
0109     }
0110 
0111     return RTEMS_SUCCESSFUL;
0112 }
0113 
0114 rtems_device_driver
0115 frame_buffer_open
0116 (rtems_device_major_number major,
0117  rtems_device_minor_number minor,
0118  void *arg)
0119 {
0120     if (_Atomic_Flag_test_and_set(&driver_mutex, ATOMIC_ORDER_ACQUIRE) != 0) {
0121         printf("EFI/GOP: error: can't lock device mutex.\n" );
0122         return RTEMS_UNSATISFIED;
0123     }
0124     if (gopfb_fix.smem_start == NULL) {
0125         _Atomic_Flag_clear( &driver_mutex, ATOMIC_ORDER_RELEASE );
0126         printf( "EFI/GOP: framebuffer initialization failed.\n" );
0127             return RTEMS_UNSATISFIED;
0128     }
0129     memset( (void *) gopfb_fix.smem_start, 255, gopfb_fix.smem_len );
0130     return RTEMS_SUCCESSFUL;
0131 }
0132 
0133 rtems_device_driver
0134 frame_buffer_close
0135 (rtems_device_major_number major,
0136  rtems_device_minor_number minor,
0137  void *arg)
0138 {
0139     _Atomic_Flag_clear( &driver_mutex, ATOMIC_ORDER_RELEASE );
0140     return RTEMS_SUCCESSFUL;
0141 }
0142 
0143 rtems_device_driver
0144 frame_buffer_read
0145 (rtems_device_major_number major,
0146  rtems_device_minor_number minor,
0147  void *arg)
0148 {
0149     rtems_libio_rw_args_t* rw_args = (rtems_libio_rw_args_t*)arg;
0150 
0151     rw_args->bytes_moved =
0152         (( rw_args->offset + rw_args->count) > gopfb_fix.smem_len) ?
0153         (gopfb_fix.smem_len - rw_args->offset) : rw_args->count;
0154     memcpy( rw_args->buffer,
0155             (const void *)(gopfb_fix.smem_start + rw_args->offset),
0156             rw_args->bytes_moved);
0157     return RTEMS_SUCCESSFUL;
0158 }
0159 
0160 rtems_device_driver
0161 frame_buffer_write
0162 (rtems_device_major_number major,
0163  rtems_device_minor_number minor,
0164  void *arg)
0165 {
0166     rtems_libio_rw_args_t* rw_args = (rtems_libio_rw_args_t*)arg;
0167 
0168     rw_args->bytes_moved =
0169         ((rw_args->offset + rw_args->count) > gopfb_fix.smem_len) ?
0170         (gopfb_fix.smem_len - rw_args->offset) : rw_args->count;
0171     memcpy((void *)(gopfb_fix.smem_start + rw_args->offset),
0172            rw_args->buffer,
0173            rw_args->bytes_moved);
0174     return RTEMS_SUCCESSFUL;
0175 }
0176 
0177 rtems_device_driver
0178 frame_buffer_control
0179 (rtems_device_major_number major,
0180  rtems_device_minor_number minor,
0181  void *arg)
0182 {
0183     rtems_libio_ioctl_args_t* args = (rtems_libio_ioctl_args_t*)arg;
0184 
0185     switch (args->command) {
0186     case FBIOGET_VSCREENINFO:
0187         memcpy(args->buffer, &gopfb_var, sizeof(struct fb_var_screeninfo));
0188         args->ioctl_return = 0;
0189         break;
0190     case FBIOGET_FSCREENINFO:
0191         memcpy(args->buffer, &gopfb_fix, sizeof(struct fb_fix_screeninfo));
0192         args->ioctl_return = 0;
0193         break;
0194     case FBIOGETCMAP:
0195         /* no palette - truecolor mode */
0196         args->ioctl_return = -1;
0197         return RTEMS_UNSATISFIED;
0198     case FBIOPUTCMAP:
0199         /* no palette - truecolor mode */
0200         args->ioctl_return = -1;
0201         return RTEMS_UNSATISFIED;
0202     default:
0203         args->ioctl_return = -1;
0204         return RTEMS_UNSATISFIED;
0205     }
0206     return RTEMS_SUCCESSFUL;
0207 }
0208 
0209 int
0210 efi_init_graphic_output(int hint)
0211 {
0212     EFI_GRAPHICS_OUTPUT* gop = find_gop();
0213     if (gop == NULL) {
0214         printf("EFI: GOP is not available\n");
0215         return RTEMS_UNSATISFIED;
0216     }
0217     if (init_gop(gop, hint) < 0) {
0218         return RTEMS_UNSATISFIED;
0219     }
0220     init_fb_from_gop(gop, &gopfb_var, &gopfb_fix);
0221     /* init RPi based character output */
0222     rpi_video_init();
0223     memset( (void *) gopfb_fix.smem_start, 255, gopfb_fix.smem_len );
0224     return RTEMS_SUCCESSFUL;
0225 }
0226 
0227 static int
0228 init_gop(EFI_GRAPHICS_OUTPUT *gop, int hint)
0229 {
0230     EFI_STATUS status;
0231     if (gop == NULL)
0232         return -1;
0233 
0234     int imax = gop->Mode->MaxMode - 1;
0235 
0236     if (hint != -1) {
0237         /* hint got from command-line does have highest priority */
0238         status = gop->SetMode(gop, hint);
0239         if (EFI_ERROR(status)) {
0240             printf("EFI/GOP: can't set mode to: %d which was set on command line.\n", hint);
0241             return -1;
0242         }
0243     }
0244     else if (strcmp(BSP_EFI_GRAPHICS_OUTPUT_MODE_VALUE, "MAX") == 0) {
0245         status = gop->SetMode(gop, imax);
0246         if (EFI_ERROR(status)) {
0247             printf("EFI/GOP: can't set mode to: %d which should be MAX\n", imax);
0248             return -1;
0249         }
0250     }
0251     else if (strcmp(BSP_EFI_GRAPHICS_OUTPUT_MODE_VALUE, "AUTO") == 0) {
0252         status = gop->SetMode(gop, gop->Mode->Mode);
0253         if (EFI_ERROR(status)) {
0254             printf("EFI/GOP: can't set mode to: %d which should be AUTO (platform preferred value)\n", imax);
0255             return -1;
0256         }
0257     }
0258     else {
0259         int vmode = atoi(BSP_EFI_GRAPHICS_OUTPUT_MODE_VALUE);
0260         status = gop->SetMode(gop, vmode);
0261         if (EFI_ERROR(status)) {
0262             printf("EFI/GOP: can't set mode to: %d which is used supplied value.\n", vmode);
0263             return -1;
0264         }
0265     }
0266     return 0;
0267 }
0268 
0269 static int
0270 init_fb_from_gop(EFI_GRAPHICS_OUTPUT *gop, struct fb_var_screeninfo* fbvar, struct fb_fix_screeninfo* fbfix)
0271 {
0272     int i, imax;
0273     EFI_STATUS status;
0274 
0275     if (gop == NULL)
0276         return -1;
0277     imax = gop->Mode->MaxMode;
0278 
0279     printf("RTEMS: graphic output: current mode: %d, max mode: %d.\n", gop->Mode->Mode, (imax - 1));
0280 
0281     for (i = 0; i < imax; i++) {
0282          EFI_GRAPHICS_OUTPUT_MODE_INFORMATION *Info = NULL;
0283          UINTN SizeOfInfo = 0;
0284 
0285          status = gop->QueryMode(gop, i, &SizeOfInfo, &Info);
0286          if (EFI_ERROR(status) && status == EFI_NOT_STARTED) {
0287              gop->SetMode(gop, gop->Mode->Mode);
0288              status = gop->QueryMode(gop, i, &SizeOfInfo, &Info);
0289          }
0290 
0291          if (EFI_ERROR(status)) {
0292              printf("ERROR: Bad response from QueryMode: %ld\n", status);
0293              continue;
0294          }
0295          printf("%s%d: %dx%d ", memcmp(Info,gop->Mode->Info,sizeof(*Info)) == 0 ? " -> " : "    ", i,
0296                 Info->HorizontalResolution,
0297                 Info->VerticalResolution);
0298          switch(Info->PixelFormat) {
0299              case PixelRedGreenBlueReserved8BitPerColor:
0300                  printf("RGBR format, FB @ %p, size: %ld", (void*)gop->Mode->FrameBufferBase, gop->Mode->FrameBufferSize);
0301                  break;
0302              case PixelBlueGreenRedReserved8BitPerColor:
0303                  printf("BGRR format, FB @ %p, size: %ld", (void*)gop->Mode->FrameBufferBase, gop->Mode->FrameBufferSize);
0304                  break;
0305              case PixelBitMask:
0306                  printf("Red:%08x Green:%08x Blue:%08x Reserved:%08x",
0307                         Info->PixelInformation.RedMask,
0308                         Info->PixelInformation.GreenMask,
0309                         Info->PixelInformation.BlueMask,
0310                         Info->PixelInformation.ReservedMask);
0311                  break;
0312              case PixelBltOnly:
0313                  printf("(linear fb not available)");
0314                  break;
0315              default:
0316                  printf("(invalid format)");
0317                  break;
0318         }
0319         printf(", %d pixels per line\n", Info->PixelsPerScanLine);
0320     }
0321     fbvar->xres = gop->Mode->Info->HorizontalResolution;
0322     fbvar->yres = gop->Mode->Info->VerticalResolution;
0323     fbfix->smem_start = (void*)gop->Mode->FrameBufferBase;
0324     fbfix->smem_len = gop->Mode->FrameBufferSize;
0325     fbfix->line_length = gop->Mode->Info->PixelsPerScanLine;
0326     return EFI_SUCCESS;
0327 }
0328 
0329 static EFI_GRAPHICS_OUTPUT*
0330 find_gop()
0331 {
0332     EFI_HANDLE *HandleBuffer = NULL;
0333     UINTN HandleCount = 0;
0334     EFI_STATUS status = EFI_SUCCESS;
0335     EFI_GRAPHICS_OUTPUT *gop = NULL;
0336 
0337     EFI_GUID gop_guid = EFI_GRAPHICS_OUTPUT_PROTOCOL_GUID;
0338 
0339     status = BS->HandleProtocol(ST->ConsoleOutHandle,
0340                                 &gop_guid,
0341                                 (VOID **)&gop);
0342     if (!EFI_ERROR (status) && gop != NULL) {
0343         return gop;
0344     }
0345     status = BS->LocateProtocol(&gop_guid, NULL, (void**)&gop);
0346     if (!EFI_ERROR (status) && gop != NULL) {
0347         return gop;
0348     }
0349     // try locating by handle
0350     status = BS->LocateHandleBuffer(ByProtocol,
0351                                     &gop_guid,
0352                                     NULL,
0353                                     &HandleCount,
0354                                     &HandleBuffer);
0355     if (!EFI_ERROR (status)) {
0356         for (int i = 0; i < HandleCount; i++) {
0357             status = BS->HandleProtocol( HandleBuffer[i],
0358                                          &gop_guid,
0359                                          (VOID*)&gop);
0360             if (!EFI_ERROR (status)) {
0361                 break;
0362             }
0363         }
0364         BS->FreePool(HandleBuffer);
0365         return gop;
0366     }
0367     return NULL;
0368 }
0369 
0370 void
0371 rpi_get_var_screen_info(struct fb_var_screeninfo* info)
0372 {
0373     *info = gopfb_var;
0374 }
0375 
0376 void
0377 rpi_get_fix_screen_info(struct fb_fix_screeninfo* info)
0378 {
0379     *info = gopfb_fix;
0380 }
0381 
0382 #endif