From c1a9f6a1286625bc3d623870c23d98672f5af3b9 Mon Sep 17 00:00:00 2001 From: YANG Qiao Date: Thu, 13 Aug 2015 00:06:10 +0200 Subject: arm/raspberrypi: add VideoCore framebuffer without initialization --- c/src/lib/libbsp/arm/raspberrypi/Makefile.am | 2 + c/src/lib/libbsp/arm/raspberrypi/console/fb.c | 409 ++++++++++++++++++++++ c/src/lib/libbsp/arm/raspberrypi/include/rpi-fb.h | 54 +++ c/src/lib/libbsp/arm/raspberrypi/preinstall.am | 4 + 4 files changed, 469 insertions(+) create mode 100644 c/src/lib/libbsp/arm/raspberrypi/console/fb.c create mode 100644 c/src/lib/libbsp/arm/raspberrypi/include/rpi-fb.h diff --git a/c/src/lib/libbsp/arm/raspberrypi/Makefile.am b/c/src/lib/libbsp/arm/raspberrypi/Makefile.am index 258f8a05c8..285da4fe76 100644 --- a/c/src/lib/libbsp/arm/raspberrypi/Makefile.am +++ b/c/src/lib/libbsp/arm/raspberrypi/Makefile.am @@ -50,6 +50,7 @@ include_bsp_HEADERS += include/i2c.h include_bsp_HEADERS += include/spi.h include_bsp_HEADERS += include/mailbox.h include_bsp_HEADERS += include/vc.h +include_bsp_HEADERS += include/rpi-fb.h include_libcpu_HEADERS = ../../../libcpu/arm/shared/include/cache_.h \ ../../../libcpu/arm/shared/include/arm-cp15.h @@ -114,6 +115,7 @@ libbsp_a_SOURCES += ../../shared/console_select.c libbsp_a_SOURCES += ../../shared/console_write.c libbsp_a_SOURCES += console/console-config.c libbsp_a_SOURCES += console/usart.c +libbsp_a_SOURCES += console/fb.c # Mailbox libbsp_a_SOURCES += misc/mailbox.c diff --git a/c/src/lib/libbsp/arm/raspberrypi/console/fb.c b/c/src/lib/libbsp/arm/raspberrypi/console/fb.c new file mode 100644 index 0000000000..185db29ac8 --- /dev/null +++ b/c/src/lib/libbsp/arm/raspberrypi/console/fb.c @@ -0,0 +1,409 @@ +/** + * @file + * + * @ingroup raspberrypi + * + * @brief framebuffer support. + */ + +/* + * Copyright (c) 2015 Yang Qiao + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * + * http://www.rtems.org/license/LICENSE + * + */ + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include + +#include +#include +#include +#include +#include + +#define SCREEN_WIDTH 1024 +#define SCREEN_HEIGHT 768 +#define BPP 32 + +/* flag to limit driver to protect against multiple opens */ +static Atomic_Flag driver_mutex; + +/* + * screen information for the driver (fb0). + */ + +static struct fb_var_screeninfo fb_var_info = { + .xres = SCREEN_WIDTH, + .yres = SCREEN_HEIGHT, + .bits_per_pixel = BPP +}; + +static struct fb_fix_screeninfo fb_fix_info = { + .smem_start = (void *) NULL, + .smem_len = 0, + .type = FB_TYPE_PACKED_PIXELS, + .visual = FB_VISUAL_TRUECOLOR, + .line_length = 0 +}; + +typedef enum { + NO_SUITABLE_MODE = -1, + BAD_FORMAT = -2, + AUTO_SELECT = -3, + DONT_INIT = -4, + NO_MODE_REQ = -5, +} mode_err_ret_val; + +int rpi_get_fix_screen_info( struct fb_fix_screeninfo *info ) +{ + *info = fb_fix_info; + return 0; +} + +int rpi_get_var_screen_info( struct fb_var_screeninfo *info ) +{ + *info = fb_var_info; + return 0; +} + +/** + * @brief Find mode given in string format. + * + * expected format + * x[-] + * numbers , and are decadic + * + * @param[out] fb_var_ptr pointer to variable mode part filled by function + * @param[in] video_string string to be parsed + * @retval video mode number to be set + * @retval -1 no suitable mode found + * @retval -2 bad format of the video_string + * @retval -3 automatic mode selection requested + * @retval -4 request to not initialize graphics + * @retval -5 no mode requested/empty video string + */ + +static int parse_mode_from_string( + struct fb_var_screeninfo *fb_var_ptr, + const char *video_string +) +{ + const char *opt; + char *endptr; + uint32_t width; + uint32_t height; + uint32_t bpp = 0; + + opt = video_string; + + if ( opt == NULL ) + return NO_MODE_REQ; + + if ( strncmp( opt, "auto", 4 ) == 0 ) + return AUTO_SELECT; + + if ( strncmp( opt, "none", 4 ) == 0 || + strncmp( opt, "off", 3 ) == 0 ) + return DONT_INIT; + + width = strtol( opt, &endptr, 10 ); + + if ( *endptr != 'x' ) { + return BAD_FORMAT; + } + + opt = endptr + 1; + height = strtol( opt, &endptr, 10 ); + + switch ( *endptr ) { + case '-': + opt = endptr + 1; + endptr = NULL; + bpp = strtol( opt, &endptr, 10 ); + + if ( ( endptr == opt ) || ( endptr == NULL ) ) + return BAD_FORMAT; + + if ( *endptr && ( *endptr != ' ' ) ) + return BAD_FORMAT; + + break; + case ' ': + case 0: + break; + default: + return BAD_FORMAT; + } + + fb_var_ptr->xres = width; + fb_var_ptr->yres = height; + + if ( bpp != 0 ) + fb_var_ptr->bits_per_pixel = bpp; + + return 0; +} + +static int find_mode_from_vc( void ) +{ + bcm2835_get_display_size_entries entries; + + bcm2835_mailbox_get_display_size( &entries ); + unsigned int width = entries.width; + unsigned int height = entries.height; + + if ( width == 0 || height == 0 ) { + fb_var_info.xres = SCREEN_WIDTH; + fb_var_info.yres = SCREEN_HEIGHT; + } else { + fb_var_info.xres = width; + fb_var_info.yres = height; + } + + return 0; +} + +bool rpi_fb_hdmi_is_present( void ) +{ + bcm2835_get_display_size_entries entries; + + memset( &entries, 0, sizeof( entries ) ); + bcm2835_mailbox_get_display_size( &entries ); + + /* Impossible display dimension */ + if ( ( entries.width < 10 ) || ( entries.height < 10 ) ) + return false; + + /* Know default values reported when monitor is not present */ + if ( ( entries.width == 0x290 ) && ( entries.height == 0x1A0 ) ) + return false; + + return true; +} + +int rpi_fb_init( void ) +{ + int mode_from_cmdline; + bcm2835_init_frame_buffer_entries init_frame_buffer_entries; + + if ( fb_fix_info.smem_start != NULL ) { + return RPI_FB_INIT_ALREADY_INITIALIZED; + } + + if ( rpi_fb_hdmi_is_present() == false ) { + return RPI_FB_INIT_NO_DISPLAY; + } + + mode_from_cmdline = parse_mode_from_string( &fb_var_info, + rpi_cmdline_get_arg( "--video=" ) ); + + switch ( mode_from_cmdline ) { + case BAD_FORMAT: + return RPI_FB_INIT_CMDLINE_BAD_FORMAT; + case AUTO_SELECT: + break; + case DONT_INIT: + return RPI_FB_INIT_CMDLINE_DONT_INIT; + case NO_MODE_REQ: + return RPI_FB_INIT_CMDLINE_NO_MODE_REQ; + } + + if ( mode_from_cmdline ) { + if ( find_mode_from_vc() ) + return RPI_FB_INIT_MODE_PROBE_ERROR; + } + + memset( &init_frame_buffer_entries, 0, sizeof( init_frame_buffer_entries ) ); + init_frame_buffer_entries.xres = fb_var_info.xres; + init_frame_buffer_entries.yres = fb_var_info.yres; + init_frame_buffer_entries.xvirt = fb_var_info.xres; + init_frame_buffer_entries.yvirt = fb_var_info.yres; + init_frame_buffer_entries.depth = fb_var_info.bits_per_pixel; + init_frame_buffer_entries.pixel_order = bcm2835_mailbox_pixel_order_rgb; + init_frame_buffer_entries.alpha_mode = bcm2835_mailbox_alpha_mode_0_opaque; + init_frame_buffer_entries.voffset_x = 0; + init_frame_buffer_entries.voffset_y = 0; + init_frame_buffer_entries.overscan_left = 0; + init_frame_buffer_entries.overscan_right = 0; + init_frame_buffer_entries.overscan_top = 0; + init_frame_buffer_entries.overscan_bottom = 0; + bcm2835_mailbox_init_frame_buffer( &init_frame_buffer_entries ); + + bcm2835_get_pitch_entries get_pitch_entries; + bcm2835_mailbox_get_pitch( &get_pitch_entries ); + + fb_var_info.xres = init_frame_buffer_entries.xres; + fb_var_info.yres = init_frame_buffer_entries.yres; + fb_var_info.bits_per_pixel = init_frame_buffer_entries.depth; + fb_fix_info.smem_start = (void *) init_frame_buffer_entries.base; + fb_fix_info.smem_len = init_frame_buffer_entries.size; + fb_fix_info.line_length = get_pitch_entries.pitch; + + if ( fb_fix_info.smem_start == NULL ) + return RPI_FB_INIT_START_ADDR_UNKNOWN; + + arm_cp15_set_translation_table_entries( (void *) fb_fix_info.smem_start, + (void *) fb_fix_info.smem_start + + fb_fix_info.smem_len, + ARMV7_MMU_DATA_READ_WRITE_CACHED ); + + return RPI_FB_INIT_OK; +} + +/* + * fbds device driver initialize entry point. + */ + +rtems_device_driver frame_buffer_initialize( + rtems_device_major_number major, + rtems_device_minor_number minor, + void *arg +) +{ + rtems_status_code status; + + /* register the devices */ + status = rtems_io_register_name( FRAMEBUFFER_DEVICE_0_NAME, major, 0 ); + + if ( status != RTEMS_SUCCESSFUL ) { + printk( "[!] error registering framebuffer\n" ); + rtems_fatal_error_occurred( status ); + } + + _Atomic_Flag_clear( &driver_mutex, ATOMIC_ORDER_RELEASE ); + return RTEMS_SUCCESSFUL; +} + +/* + * fbds device driver open operation. + */ + +rtems_device_driver frame_buffer_open( + rtems_device_major_number major, + rtems_device_minor_number minor, + void *arg +) +{ + if ( _Atomic_Flag_test_and_set( &driver_mutex, + ATOMIC_ORDER_ACQUIRE ) != 0 ) { + printk( "FB_CIRRUS could not lock driver_mutex\n" ); + return RTEMS_UNSATISFIED; + } + + memset( (void *) fb_fix_info.smem_start, 0, fb_fix_info.smem_len ); + return RTEMS_SUCCESSFUL; +} + +/* + * fbds device driver close operation. + */ + +rtems_device_driver frame_buffer_close( + rtems_device_major_number major, + rtems_device_minor_number minor, + void *arg +) +{ + /* restore previous state. for VGA this means return to text mode. + * leave out if graphics hardware has been initialized in + * frame_buffer_initialize() */ + memset( (void *) fb_fix_info.smem_start, 0, fb_fix_info.smem_len ); + _Atomic_Flag_clear( &driver_mutex, ATOMIC_ORDER_RELEASE ); + return RTEMS_SUCCESSFUL; +} + +/* + * fbds device driver read operation. + */ + +rtems_device_driver frame_buffer_read( + rtems_device_major_number major, + rtems_device_minor_number minor, + void *arg +) +{ + rtems_libio_rw_args_t *rw_args = (rtems_libio_rw_args_t *) arg; + + rw_args->bytes_moved = + ( ( rw_args->offset + rw_args->count ) > fb_fix_info.smem_len ) ? + ( fb_fix_info.smem_len - rw_args->offset ) : rw_args->count; + memcpy( rw_args->buffer, + (const void *) ( fb_fix_info.smem_start + rw_args->offset ), + rw_args->bytes_moved ); + return RTEMS_SUCCESSFUL; +} + +/* + * fbds device driver write operation. + */ + +rtems_device_driver frame_buffer_write( + rtems_device_major_number major, + rtems_device_minor_number minor, + void *arg +) +{ + rtems_libio_rw_args_t *rw_args = (rtems_libio_rw_args_t *) arg; + + rw_args->bytes_moved = + ( ( rw_args->offset + rw_args->count ) > fb_fix_info.smem_len ) ? + ( fb_fix_info.smem_len - rw_args->offset ) : rw_args->count; + memcpy( (void *) ( fb_fix_info.smem_start + rw_args->offset ), + rw_args->buffer, + rw_args->bytes_moved ); + return RTEMS_SUCCESSFUL; +} + +/* + * ioctl entry point. + */ + +rtems_device_driver frame_buffer_control( + rtems_device_major_number major, + rtems_device_minor_number minor, + void *arg +) +{ + rtems_libio_ioctl_args_t *args = arg; + + /* XXX check minor */ + + switch ( args->command ) { + case FBIOGET_VSCREENINFO: + memcpy( args->buffer, &fb_var_info, sizeof( fb_var_info ) ); + args->ioctl_return = 0; + break; + case FBIOGET_FSCREENINFO: + memcpy( args->buffer, &fb_fix_info, sizeof( fb_fix_info ) ); + args->ioctl_return = 0; + break; + case FBIOGETCMAP: + /* no palette - truecolor mode */ + args->ioctl_return = -1; + return RTEMS_UNSATISFIED; + case FBIOPUTCMAP: + /* no palette - truecolor mode */ + args->ioctl_return = -1; + return RTEMS_UNSATISFIED; + default: + args->ioctl_return = -1; + return RTEMS_UNSATISFIED; + } + + return RTEMS_SUCCESSFUL; +} diff --git a/c/src/lib/libbsp/arm/raspberrypi/include/rpi-fb.h b/c/src/lib/libbsp/arm/raspberrypi/include/rpi-fb.h new file mode 100644 index 0000000000..fa9a939682 --- /dev/null +++ b/c/src/lib/libbsp/arm/raspberrypi/include/rpi-fb.h @@ -0,0 +1,54 @@ +/** + * @file + * + * @ingroup raspberrypi_fb + * + * @brief framebuffer support and setup + * + */ + +/* + * Copyright (c) 2015 Yang Qiao + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * + * http://www.rtems.org/license/LICENSE + * + */ + +#ifndef LIBBSP_ARM_RASPBERRYPI_FB_H +#define LIBBSP_ARM_RASPBERRYPI_FB_H + +#include + +/** + * @defgroup raspberrypi_fb + * + * @ingroup arm_raspberrypi + * + * @brief Framebuffer support and setup + * + * @{ + */ + +enum rpi_fb_init_result { + RPI_FB_INIT_OK = 0, + RPI_FB_INIT_ALREADY_INITIALIZED = 1, + RPI_FB_INIT_GENERIC_ERROR = -1, + RPI_FB_INIT_NO_DISPLAY = -2, + RPI_FB_INIT_CMDLINE_BAD_FORMAT = -3, + RPI_FB_INIT_CMDLINE_DONT_INIT = -4, + RPI_FB_INIT_CMDLINE_NO_MODE_REQ = -5, + RPI_FB_INIT_MODE_PROBE_ERROR = -6, + RPI_FB_INIT_START_ADDR_UNKNOWN = -7, +}; + +int rpi_fb_init( void ); +int rpi_get_fix_screen_info( struct fb_fix_screeninfo *info ); +int rpi_get_var_screen_info( struct fb_var_screeninfo *info ); +bool rpi_fb_hdmi_is_present( void ); + +/** @} */ + +#endif /* LIBBSP_ARM_RASPBERRYPI_FB_H */ diff --git a/c/src/lib/libbsp/arm/raspberrypi/preinstall.am b/c/src/lib/libbsp/arm/raspberrypi/preinstall.am index 979cba3109..cbfa79fbc2 100644 --- a/c/src/lib/libbsp/arm/raspberrypi/preinstall.am +++ b/c/src/lib/libbsp/arm/raspberrypi/preinstall.am @@ -154,6 +154,10 @@ $(PROJECT_INCLUDE)/bsp/vc.h: include/vc.h $(PROJECT_INCLUDE)/bsp/$(dirstamp) $(INSTALL_DATA) $< $(PROJECT_INCLUDE)/bsp/vc.h PREINSTALL_FILES += $(PROJECT_INCLUDE)/bsp/vc.h +$(PROJECT_INCLUDE)/bsp/rpi-fb.h: include/rpi-fb.h $(PROJECT_INCLUDE)/bsp/$(dirstamp) + $(INSTALL_DATA) $< $(PROJECT_INCLUDE)/bsp/rpi-fb.h +PREINSTALL_FILES += $(PROJECT_INCLUDE)/bsp/rpi-fb.h + $(PROJECT_INCLUDE)/libcpu/cache_.h: ../../../libcpu/arm/shared/include/cache_.h $(PROJECT_INCLUDE)/libcpu/$(dirstamp) $(INSTALL_DATA) $< $(PROJECT_INCLUDE)/libcpu/cache_.h PREINSTALL_FILES += $(PROJECT_INCLUDE)/libcpu/cache_.h -- cgit v1.2.3