File indexing completed on 2025-05-11 08:23:04
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019 #include <stdlib.h>
0020 #include <string.h>
0021 #include <stdio.h>
0022 #include <errno.h>
0023 #include <sys/types.h>
0024
0025 #include <bsp.h>
0026 #include <bsp/raspberrypi.h>
0027 #include <bsp/mailbox.h>
0028 #include <bsp/vc.h>
0029 #include <bsp/rpi-fb.h>
0030
0031 #include <libcpu/arm-cp15.h>
0032
0033 #include <rtems.h>
0034 #include <rtems/libio.h>
0035 #include <rtems/fb.h>
0036 #include <rtems/framebuffer.h>
0037 #include <rtems/score/atomic.h>
0038 #include <rtems/bspIo.h>
0039
0040 #define SCREEN_WIDTH 1024
0041 #define SCREEN_HEIGHT 768
0042 #define BPP 32
0043
0044
0045 static Atomic_Flag driver_mutex;
0046
0047
0048
0049
0050
0051 static struct fb_var_screeninfo fb_var_info = {
0052 .xres = SCREEN_WIDTH,
0053 .yres = SCREEN_HEIGHT,
0054 .bits_per_pixel = BPP
0055 };
0056
0057 static struct fb_fix_screeninfo fb_fix_info = {
0058 .smem_start = (void *) NULL,
0059 .smem_len = 0,
0060 .type = FB_TYPE_PACKED_PIXELS,
0061 .visual = FB_VISUAL_TRUECOLOR,
0062 .line_length = 0
0063 };
0064
0065 typedef enum {
0066 NO_SUITABLE_MODE = -1,
0067 BAD_FORMAT = -2,
0068 AUTO_SELECT = -3,
0069 DONT_INIT = -4,
0070 NO_MODE_REQ = -5,
0071 } mode_err_ret_val;
0072
0073 int rpi_get_fix_screen_info( struct fb_fix_screeninfo *info )
0074 {
0075 *info = fb_fix_info;
0076 return 0;
0077 }
0078
0079 int rpi_get_var_screen_info( struct fb_var_screeninfo *info )
0080 {
0081 *info = fb_var_info;
0082 return 0;
0083 }
0084
0085
0086
0087
0088
0089
0090
0091
0092
0093
0094
0095
0096
0097
0098
0099
0100
0101
0102 static int parse_mode_from_string(
0103 struct fb_var_screeninfo *fb_var_ptr,
0104 const char *video_string
0105 )
0106 {
0107 const char *opt;
0108 char *endptr;
0109 uint32_t width;
0110 uint32_t height;
0111 uint32_t bpp = 0;
0112
0113 opt = video_string;
0114
0115 if ( opt == NULL )
0116 return NO_MODE_REQ;
0117
0118 if ( strncmp( opt, "auto", 4 ) == 0 )
0119 return AUTO_SELECT;
0120
0121 if ( strncmp( opt, "none", 4 ) == 0 ||
0122 strncmp( opt, "off", 3 ) == 0 )
0123 return DONT_INIT;
0124
0125 width = strtol( opt, &endptr, 10 );
0126
0127 if ( *endptr != 'x' ) {
0128 return BAD_FORMAT;
0129 }
0130
0131 opt = endptr + 1;
0132 height = strtol( opt, &endptr, 10 );
0133
0134 switch ( *endptr ) {
0135 case '-':
0136 opt = endptr + 1;
0137 endptr = NULL;
0138 bpp = strtol( opt, &endptr, 10 );
0139
0140 if ( ( endptr == opt ) || ( endptr == NULL ) )
0141 return BAD_FORMAT;
0142
0143 if ( *endptr && ( *endptr != ' ' ) )
0144 return BAD_FORMAT;
0145
0146 break;
0147 case ' ':
0148 case 0:
0149 break;
0150 default:
0151 return BAD_FORMAT;
0152 }
0153
0154 fb_var_ptr->xres = width;
0155 fb_var_ptr->yres = height;
0156
0157 if ( bpp != 0 )
0158 fb_var_ptr->bits_per_pixel = bpp;
0159
0160 return 0;
0161 }
0162
0163 static int find_mode_from_vc( void )
0164 {
0165 int res;
0166 unsigned int width;
0167 unsigned int height;
0168 bcm2835_get_display_size_entries entries;
0169
0170 res = bcm2835_mailbox_get_display_size( &entries );
0171
0172 width = entries.width;
0173 height = entries.height;
0174
0175 if ( width == 0 || height == 0 ) {
0176 fb_var_info.xres = SCREEN_WIDTH;
0177 fb_var_info.yres = SCREEN_HEIGHT;
0178 } else {
0179 fb_var_info.xres = width;
0180 fb_var_info.yres = height;
0181 }
0182 printk("find_mode_from_vc %u x %u, res %d\n", width, height, res);
0183
0184 return res;
0185 }
0186
0187 bool rpi_fb_hdmi_is_present( void )
0188 {
0189 bcm2835_get_display_size_entries entries;
0190
0191 memset( &entries, 0, sizeof( entries ) );
0192 bcm2835_mailbox_get_display_size( &entries );
0193
0194
0195 if ( ( entries.width < 10 ) || ( entries.height < 10 ) )
0196 return false;
0197
0198
0199 if ( ( entries.width == 0x290 ) && ( entries.height == 0x1A0 ) )
0200 return false;
0201
0202 return true;
0203 }
0204
0205 int rpi_fb_init( void )
0206 {
0207 int res;
0208 int mode_from_cmdline;
0209 bcm2835_init_frame_buffer_entries init_frame_buffer_entries;
0210
0211 if ( fb_fix_info.smem_start != NULL ) {
0212 return RPI_FB_INIT_ALREADY_INITIALIZED;
0213 }
0214
0215 if ( rpi_fb_hdmi_is_present() == false ) {
0216 return RPI_FB_INIT_NO_DISPLAY;
0217 }
0218
0219 mode_from_cmdline = parse_mode_from_string( &fb_var_info,
0220 rpi_cmdline_get_arg( "--video=" ) );
0221
0222 switch ( mode_from_cmdline ) {
0223 case BAD_FORMAT:
0224 return RPI_FB_INIT_CMDLINE_BAD_FORMAT;
0225 case AUTO_SELECT:
0226 break;
0227 case DONT_INIT:
0228 return RPI_FB_INIT_CMDLINE_DONT_INIT;
0229 case NO_MODE_REQ:
0230 return RPI_FB_INIT_CMDLINE_NO_MODE_REQ;
0231 }
0232
0233 if ( mode_from_cmdline ) {
0234 if ( find_mode_from_vc() )
0235 return RPI_FB_INIT_MODE_PROBE_ERROR;
0236 }
0237
0238 memset( &init_frame_buffer_entries, 0, sizeof( init_frame_buffer_entries ) );
0239 init_frame_buffer_entries.xres = fb_var_info.xres;
0240 init_frame_buffer_entries.yres = fb_var_info.yres;
0241 init_frame_buffer_entries.xvirt = fb_var_info.xres;
0242 init_frame_buffer_entries.yvirt = fb_var_info.yres;
0243 init_frame_buffer_entries.depth = fb_var_info.bits_per_pixel;
0244 init_frame_buffer_entries.pixel_order = bcm2835_mailbox_pixel_order_rgb;
0245 init_frame_buffer_entries.alpha_mode = bcm2835_mailbox_alpha_mode_0_opaque;
0246 init_frame_buffer_entries.voffset_x = 0;
0247 init_frame_buffer_entries.voffset_y = 0;
0248 init_frame_buffer_entries.overscan_left = 0;
0249 init_frame_buffer_entries.overscan_right = 0;
0250 init_frame_buffer_entries.overscan_top = 0;
0251 init_frame_buffer_entries.overscan_bottom = 0;
0252 printk("bcm2835_mailbox_init_frame_buffer ...\n");
0253 res = bcm2835_mailbox_init_frame_buffer( &init_frame_buffer_entries );
0254 printk("bcm2835_mailbox_init_frame_buffer returned %d\n", res);
0255 if (res != 0) {
0256 printk("bcm2835_mailbox_init_frame_buffer retry ...\n");
0257 res = bcm2835_mailbox_init_frame_buffer( &init_frame_buffer_entries );
0258 printk("bcm2835_mailbox_init_frame_buffer returned %d\n", res);
0259 if (res != 0)
0260 return RPI_FB_INIT_SETUP_FAILED;
0261 }
0262
0263 bcm2835_get_pitch_entries get_pitch_entries;
0264 bcm2835_mailbox_get_pitch( &get_pitch_entries );
0265
0266 fb_var_info.xres = init_frame_buffer_entries.xres;
0267 fb_var_info.yres = init_frame_buffer_entries.yres;
0268 fb_var_info.bits_per_pixel = init_frame_buffer_entries.depth;
0269 fb_fix_info.smem_start = (void *) init_frame_buffer_entries.base;
0270 fb_fix_info.smem_len = init_frame_buffer_entries.size;
0271 fb_fix_info.line_length = get_pitch_entries.pitch;
0272
0273 if ( fb_fix_info.smem_start == NULL )
0274 return RPI_FB_INIT_START_ADDR_UNKNOWN;
0275
0276 printk("fb_fix_info.smem_start %p\n", fb_fix_info.smem_start);
0277
0278 arm_cp15_set_translation_table_entries( (void *) fb_fix_info.smem_start,
0279 (void *) fb_fix_info.smem_start +
0280 fb_fix_info.smem_len,
0281 ARMV7_MMU_DATA_READ_WRITE_CACHED );
0282
0283 return RPI_FB_INIT_OK;
0284 }
0285
0286
0287
0288
0289
0290 rtems_device_driver frame_buffer_initialize(
0291 rtems_device_major_number major,
0292 rtems_device_minor_number minor,
0293 void *arg
0294 )
0295 {
0296 rtems_status_code status;
0297
0298
0299 status = rtems_io_register_name( FRAMEBUFFER_DEVICE_0_NAME, major, 0 );
0300
0301 if ( status != RTEMS_SUCCESSFUL ) {
0302 printk( "[!] error registering framebuffer\n" );
0303 rtems_fatal_error_occurred( status );
0304 }
0305
0306 _Atomic_Flag_clear( &driver_mutex, ATOMIC_ORDER_RELEASE );
0307 return RTEMS_SUCCESSFUL;
0308 }
0309
0310
0311
0312
0313
0314 rtems_device_driver frame_buffer_open(
0315 rtems_device_major_number major,
0316 rtems_device_minor_number minor,
0317 void *arg
0318 )
0319 {
0320 if ( _Atomic_Flag_test_and_set( &driver_mutex,
0321 ATOMIC_ORDER_ACQUIRE ) != 0 ) {
0322 printk( "RaspberryPi framebuffer could not lock driver_mutex\n" );
0323 return RTEMS_UNSATISFIED;
0324 }
0325
0326 if ( fb_fix_info.smem_start == NULL ) {
0327 int res;
0328 res = rpi_fb_init();
0329 if ( (res < RPI_FB_INIT_OK) || (fb_fix_info.smem_start == NULL) ) {
0330 _Atomic_Flag_clear( &driver_mutex, ATOMIC_ORDER_RELEASE );
0331 printk( "RaspberryPi framebuffer initialization failed\n" );
0332 return RTEMS_UNSATISFIED;
0333 }
0334 }
0335
0336 memset( (void *) fb_fix_info.smem_start, 0, fb_fix_info.smem_len );
0337 return RTEMS_SUCCESSFUL;
0338 }
0339
0340
0341
0342
0343
0344 rtems_device_driver frame_buffer_close(
0345 rtems_device_major_number major,
0346 rtems_device_minor_number minor,
0347 void *arg
0348 )
0349 {
0350
0351
0352
0353 memset( (void *) fb_fix_info.smem_start, 0, fb_fix_info.smem_len );
0354 _Atomic_Flag_clear( &driver_mutex, ATOMIC_ORDER_RELEASE );
0355 return RTEMS_SUCCESSFUL;
0356 }
0357
0358
0359
0360
0361
0362 rtems_device_driver frame_buffer_read(
0363 rtems_device_major_number major,
0364 rtems_device_minor_number minor,
0365 void *arg
0366 )
0367 {
0368 rtems_libio_rw_args_t *rw_args = (rtems_libio_rw_args_t *) arg;
0369
0370 rw_args->bytes_moved =
0371 ( ( rw_args->offset + rw_args->count ) > fb_fix_info.smem_len ) ?
0372 ( fb_fix_info.smem_len - rw_args->offset ) : rw_args->count;
0373 memcpy( rw_args->buffer,
0374 (const void *) ( fb_fix_info.smem_start + rw_args->offset ),
0375 rw_args->bytes_moved );
0376 return RTEMS_SUCCESSFUL;
0377 }
0378
0379
0380
0381
0382
0383 rtems_device_driver frame_buffer_write(
0384 rtems_device_major_number major,
0385 rtems_device_minor_number minor,
0386 void *arg
0387 )
0388 {
0389 rtems_libio_rw_args_t *rw_args = (rtems_libio_rw_args_t *) arg;
0390
0391 rw_args->bytes_moved =
0392 ( ( rw_args->offset + rw_args->count ) > fb_fix_info.smem_len ) ?
0393 ( fb_fix_info.smem_len - rw_args->offset ) : rw_args->count;
0394 memcpy( (void *) ( fb_fix_info.smem_start + rw_args->offset ),
0395 rw_args->buffer,
0396 rw_args->bytes_moved );
0397 return RTEMS_SUCCESSFUL;
0398 }
0399
0400
0401
0402
0403
0404 rtems_device_driver frame_buffer_control(
0405 rtems_device_major_number major,
0406 rtems_device_minor_number minor,
0407 void *arg
0408 )
0409 {
0410 rtems_libio_ioctl_args_t *args = arg;
0411
0412
0413
0414 switch ( args->command ) {
0415 case FBIOGET_VSCREENINFO:
0416 memcpy( args->buffer, &fb_var_info, sizeof( fb_var_info ) );
0417 args->ioctl_return = 0;
0418 break;
0419 case FBIOGET_FSCREENINFO:
0420 memcpy( args->buffer, &fb_fix_info, sizeof( fb_fix_info ) );
0421 args->ioctl_return = 0;
0422 break;
0423 case FBIOGETCMAP:
0424
0425 args->ioctl_return = -1;
0426 return RTEMS_UNSATISFIED;
0427 case FBIOPUTCMAP:
0428
0429 args->ioctl_return = -1;
0430 return RTEMS_UNSATISFIED;
0431 default:
0432 args->ioctl_return = -1;
0433 return RTEMS_UNSATISFIED;
0434 }
0435
0436 return RTEMS_SUCCESSFUL;
0437 }