[PATCH v2 4/7] arm/raspberrypi: add VideoCore framebuffer without initialization

ppisa4lists at pikron.com ppisa4lists at pikron.com
Sun May 22 00:13:07 UTC 2016


From: YANG Qiao <yangqiao0505 at me.com>

---
 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 258f8a0..285da4f 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 0000000..185db29
--- /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 <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;
+}
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 0000000..fa9a939
--- /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 <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 */
diff --git a/c/src/lib/libbsp/arm/raspberrypi/preinstall.am b/c/src/lib/libbsp/arm/raspberrypi/preinstall.am
index 979cba3..cbfa79f 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
-- 
1.9.1



More information about the devel mailing list