forked from Imagelibrary/rtems
arm/raspberrypi: add VideoCore framebuffer without initialization
This commit is contained in:
@@ -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
|
||||
|
||||
409
c/src/lib/libbsp/arm/raspberrypi/console/fb.c
Normal file
409
c/src/lib/libbsp/arm/raspberrypi/console/fb.c
Normal file
@@ -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 <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <errno.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#include <bsp.h>
|
||||
#include <bsp/raspberrypi.h>
|
||||
#include <bsp/mailbox.h>
|
||||
#include <bsp/vc.h>
|
||||
#include <bsp/rpi-fb.h>
|
||||
|
||||
#include <libcpu/arm-cp15.h>
|
||||
|
||||
#include <rtems.h>
|
||||
#include <rtems/libio.h>
|
||||
#include <rtems/fb.h>
|
||||
#include <rtems/framebuffer.h>
|
||||
#include <rtems/score/atomic.h>
|
||||
|
||||
#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
|
||||
* <resX>x<resY>[-<bpp>]
|
||||
* numbers <resX>, <resY> and <bpp> 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;
|
||||
}
|
||||
54
c/src/lib/libbsp/arm/raspberrypi/include/rpi-fb.h
Normal file
54
c/src/lib/libbsp/arm/raspberrypi/include/rpi-fb.h
Normal file
@@ -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 <rtems/fb.h>
|
||||
|
||||
/**
|
||||
* @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 */
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user