[PATCH 2/5] arm/raspberrypi: add VideoCore framebuffer without initialization

Gedare Bloom gedare at rtems.org
Sat May 21 12:56:49 UTC 2016


On Sat, May 21, 2016 at 6:54 AM,  <ppisa4lists at pikron.com> wrote:
> 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     | 385 ++++++++++++++++++++++
>  c/src/lib/libbsp/arm/raspberrypi/include/rpi-fb.h |  53 +++
>  c/src/lib/libbsp/arm/raspberrypi/preinstall.am    |   4 +
>  4 files changed, 444 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..ba285e7
> --- /dev/null
> +++ b/c/src/lib/libbsp/arm/raspberrypi/console/fb.c
> @@ -0,0 +1,385 @@
> +/**
> + * @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 <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 raspberrypi_get_fix_screen_info( struct fb_fix_screeninfo *info )
> +{
> +  *info = fb_fix_info;
> +  return 0;
> +}
> +
> +int raspberrypi_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)
> +  {
A minor issue is the inconsistent style in fb.c. mainly I saw that the
opening { is sometimes on the next line and sometimes the same line as
a conditional expression.

> +    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;
> +}
> +
> +static bool
> +hdmi_is_present(void)
> +{
> +  bcm2835_get_display_size_entries entries;
> +  bcm2835_mailbox_get_display_size(&entries);
> +  if(entries.width == 0x290 && entries.height ==0x1A0 )
> +  {
> +    return false;
> +  }
> +  else
> +  {
> +    return true;
> +  }
> +}
> +
> +int
> +raspberrypi_fb_init(void)
> +{
> +  int mode_from_cmdline;
> +
> +  if (fb_fix_info.smem_start != NULL)
> +  {
> +    return RASPBERRYPI_FB_INIT_ALREADY_INITIALIZED;
> +  }
> +
> +  if (hdmi_is_present() == false)
> +  {
> +    return RASPBERRYPI_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 RASPBERRYPI_FB_INIT_CMDLINE_BAD_FORMAT;
> +    case AUTO_SELECT:
> +      break;
> +    case DONT_INIT:
> +      return RASPBERRYPI_FB_INIT_CMDLINE_DONT_INIT;
> +    case NO_MODE_REQ:
> +      return RASPBERRYPI_FB_INIT_CMDLINE_NO_MODE_REQ;
> +  }
> +
> +  if (mode_from_cmdline)
> +  {
> +    if(find_mode_from_vc())
> +      return RASPBERRYPI_FB_INIT_MODE_PROBE_ERROR;
> +  }
> +
> +  bcm2835_init_frame_buffer_entries  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 RASPBERRYPI_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 RASPBERRYPI_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() */
> +  _Atomic_Flag_clear(&driver_mutex, ATOMIC_ORDER_RELEASE);
> +  memset ((void *)fb_fix_info.smem_start, 0, fb_fix_info.smem_len);
I'm not sure about the mutex flag, but I suspect the memset should go
before clearing the flag?

> +  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:
> +    args->ioctl_return = 0;
> +    break;
> +  case FBIOPUTCMAP:
> +    args->ioctl_return = 0;
> +    break;
are these nops? should they return an "unimplemented" error?

> +
> +  default:
> +    args->ioctl_return = 0;
> +    break;
> +
> +  }
> +  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..3d2e5e9
> --- /dev/null
> +++ b/c/src/lib/libbsp/arm/raspberrypi/include/rpi-fb.h
> @@ -0,0 +1,53 @@
> +/**
> + * @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 raspberrypi_fb_init_result {
> +  RASPBERRYPI_FB_INIT_OK = 0,
> +  RASPBERRYPI_FB_INIT_ALREADY_INITIALIZED = 1,
> +  RASPBERRYPI_FB_INIT_GENERIC_ERROR = -1,
> +  RASPBERRYPI_FB_INIT_NO_DISPLAY = -2,
> +  RASPBERRYPI_FB_INIT_CMDLINE_BAD_FORMAT = -3,
> +  RASPBERRYPI_FB_INIT_CMDLINE_DONT_INIT = -4,
> +  RASPBERRYPI_FB_INIT_CMDLINE_NO_MODE_REQ = -5,
> +  RASPBERRYPI_FB_INIT_MODE_PROBE_ERROR = -6,
> +  RASPBERRYPI_FB_INIT_START_ADDR_UNKNOWN = -7,
> +};
> +
> +int raspberrypi_fb_init(void);
> +int raspberrypi_get_fix_screen_info( struct fb_fix_screeninfo *info );
> +int raspberrypi_get_var_screen_info( struct fb_var_screeninfo *info );
> +
> +/** @} */
> +
> +#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