File indexing completed on 2025-05-11 08:24:09
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019
0020
0021
0022
0023
0024
0025
0026
0027
0028
0029
0030
0031
0032
0033
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
0196 args->ioctl_return = -1;
0197 return RTEMS_UNSATISFIED;
0198 case FBIOPUTCMAP:
0199
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
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
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
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