source: rtems/bsps/arm/raspberrypi/console/fb.c @ d7d66d7

5
Last change on this file since d7d66d7 was d7d66d7, checked in by Sebastian Huber <sebastian.huber@…>, on 04/19/18 at 04:28:01

bsps: Move console drivers to bsps

This patch is a part of the BSP source reorganization.

Update #3285.

  • Property mode set to 100644
File size: 10.9 KB
Line 
1/**
2 * @file
3 *
4 * @ingroup raspberrypi
5 *
6 * @brief framebuffer support.
7 */
8
9/*
10 * Copyright (c) 2015 Yang Qiao
11 *
12 *  The license and distribution terms for this file may be
13 *  found in the file LICENSE in this distribution or at
14 *
15 *  http://www.rtems.org/license/LICENSE
16 *
17 */
18
19#include <stdlib.h>
20#include <string.h>
21#include <stdio.h>
22#include <errno.h>
23#include <sys/types.h>
24
25#include <bsp.h>
26#include <bsp/raspberrypi.h>
27#include <bsp/mailbox.h>
28#include <bsp/vc.h>
29#include <bsp/rpi-fb.h>
30
31#include <libcpu/arm-cp15.h>
32
33#include <rtems.h>
34#include <rtems/libio.h>
35#include <rtems/fb.h>
36#include <rtems/framebuffer.h>
37#include <rtems/score/atomic.h>
38#include <rtems/bspIo.h>
39
40#define SCREEN_WIDTH 1024
41#define SCREEN_HEIGHT 768
42#define BPP 32
43
44/* flag to limit driver to protect against multiple opens */
45static Atomic_Flag driver_mutex;
46
47/*
48 * screen information for the driver (fb0).
49 */
50
51static struct fb_var_screeninfo fb_var_info = {
52  .xres                = SCREEN_WIDTH,
53  .yres                = SCREEN_HEIGHT,
54  .bits_per_pixel      = BPP
55};
56
57static struct fb_fix_screeninfo fb_fix_info = {
58  .smem_start          = (void *) NULL,
59  .smem_len            = 0,
60  .type                = FB_TYPE_PACKED_PIXELS,
61  .visual              = FB_VISUAL_TRUECOLOR,
62  .line_length         = 0
63};
64
65typedef enum {
66  NO_SUITABLE_MODE     = -1,
67  BAD_FORMAT           = -2,
68  AUTO_SELECT          = -3,
69  DONT_INIT            = -4,
70  NO_MODE_REQ          = -5,
71} mode_err_ret_val;
72
73int rpi_get_fix_screen_info( struct fb_fix_screeninfo *info )
74{
75  *info = fb_fix_info;
76  return 0;
77}
78
79int rpi_get_var_screen_info( struct fb_var_screeninfo *info )
80{
81  *info = fb_var_info;
82  return 0;
83}
84
85/**
86 * @brief Find mode given in string format.
87 *
88 *  expected format
89 *  <resX>x<resY>[-<bpp>]
90 *  numbers <resX>, <resY> and <bpp> are decadic
91 *
92 * @param[out] fb_var_ptr pointer to variable mode part filled by function
93 * @param[in] video_string string to be parsed
94 * @retval video mode number to be set
95 * @retval -1 no suitable mode found
96 * @retval -2 bad format of the video_string
97 * @retval -3 automatic mode selection requested
98 * @retval -4 request to not initialize graphics
99 * @retval -5 no mode requested/empty video string
100 */
101
102static int parse_mode_from_string(
103  struct fb_var_screeninfo *fb_var_ptr,
104  const char               *video_string
105)
106{
107  const char *opt;
108  char       *endptr;
109  uint32_t    width;
110  uint32_t    height;
111  uint32_t    bpp = 0;
112
113  opt = video_string;
114
115  if ( opt == NULL )
116    return NO_MODE_REQ;
117
118  if ( strncmp( opt, "auto", 4 ) == 0 )
119    return AUTO_SELECT;
120
121  if ( strncmp( opt, "none", 4 ) == 0 ||
122       strncmp( opt, "off", 3 ) == 0 )
123    return DONT_INIT;
124
125  width = strtol( opt, &endptr, 10 );
126
127  if ( *endptr != 'x' ) {
128    return BAD_FORMAT;
129  }
130
131  opt = endptr + 1;
132  height = strtol( opt, &endptr, 10 );
133
134  switch ( *endptr ) {
135    case '-':
136      opt = endptr + 1;
137      endptr = NULL;
138      bpp = strtol( opt, &endptr, 10 );
139
140      if ( ( endptr == opt ) || ( endptr == NULL ) )
141        return BAD_FORMAT;
142
143      if ( *endptr && ( *endptr != ' ' ) )
144        return BAD_FORMAT;
145
146      break;
147    case ' ':
148    case 0:
149      break;
150    default:
151      return BAD_FORMAT;
152  }
153
154  fb_var_ptr->xres = width;
155  fb_var_ptr->yres = height;
156
157  if ( bpp != 0 )
158    fb_var_ptr->bits_per_pixel = bpp;
159
160  return 0;
161}
162
163static int find_mode_from_vc( void )
164{
165  int res;
166  unsigned int width;
167  unsigned int height;
168  bcm2835_get_display_size_entries entries;
169
170  res = bcm2835_mailbox_get_display_size( &entries );
171
172  width = entries.width;
173  height = entries.height;
174
175  if ( width == 0 || height == 0 ) {
176    fb_var_info.xres = SCREEN_WIDTH;
177    fb_var_info.yres = SCREEN_HEIGHT;
178  } else {
179    fb_var_info.xres = width;
180    fb_var_info.yres = height;
181  }
182  printk("find_mode_from_vc %u x %u, res %d\n", width, height, res);
183
184  return res;
185}
186
187bool rpi_fb_hdmi_is_present( void )
188{
189  bcm2835_get_display_size_entries entries;
190
191  memset( &entries, 0, sizeof( entries ) );
192  bcm2835_mailbox_get_display_size( &entries );
193
194  /* Impossible display dimension */
195  if ( ( entries.width < 10 ) || ( entries.height < 10 ) )
196    return false;
197
198  /* Know default values reported when monitor is not present */
199  if ( ( entries.width == 0x290 ) && ( entries.height == 0x1A0 ) )
200    return false;
201
202  return true;
203}
204
205int rpi_fb_init( void )
206{
207  int res;
208  int                               mode_from_cmdline;
209  bcm2835_init_frame_buffer_entries init_frame_buffer_entries;
210
211  if ( fb_fix_info.smem_start != NULL ) {
212    return RPI_FB_INIT_ALREADY_INITIALIZED;
213  }
214
215  if ( rpi_fb_hdmi_is_present() == false ) {
216    return RPI_FB_INIT_NO_DISPLAY;
217  }
218
219  mode_from_cmdline = parse_mode_from_string( &fb_var_info,
220    rpi_cmdline_get_arg( "--video=" ) );
221
222  switch ( mode_from_cmdline ) {
223    case BAD_FORMAT:
224      return RPI_FB_INIT_CMDLINE_BAD_FORMAT;
225    case AUTO_SELECT:
226      break;
227    case DONT_INIT:
228      return RPI_FB_INIT_CMDLINE_DONT_INIT;
229    case NO_MODE_REQ:
230      return RPI_FB_INIT_CMDLINE_NO_MODE_REQ;
231  }
232
233  if ( mode_from_cmdline ) {
234    if ( find_mode_from_vc() )
235      return RPI_FB_INIT_MODE_PROBE_ERROR;
236  }
237
238  memset( &init_frame_buffer_entries, 0, sizeof( init_frame_buffer_entries ) );
239  init_frame_buffer_entries.xres = fb_var_info.xres;
240  init_frame_buffer_entries.yres = fb_var_info.yres;
241  init_frame_buffer_entries.xvirt = fb_var_info.xres;
242  init_frame_buffer_entries.yvirt = fb_var_info.yres;
243  init_frame_buffer_entries.depth = fb_var_info.bits_per_pixel;
244  init_frame_buffer_entries.pixel_order = bcm2835_mailbox_pixel_order_rgb;
245  init_frame_buffer_entries.alpha_mode = bcm2835_mailbox_alpha_mode_0_opaque;
246  init_frame_buffer_entries.voffset_x = 0;
247  init_frame_buffer_entries.voffset_y = 0;
248  init_frame_buffer_entries.overscan_left = 0;
249  init_frame_buffer_entries.overscan_right = 0;
250  init_frame_buffer_entries.overscan_top = 0;
251  init_frame_buffer_entries.overscan_bottom = 0;
252  printk("bcm2835_mailbox_init_frame_buffer ...\n");
253  res = bcm2835_mailbox_init_frame_buffer( &init_frame_buffer_entries );
254  printk("bcm2835_mailbox_init_frame_buffer returned %d\n", res);
255  if (res != 0) {
256    printk("bcm2835_mailbox_init_frame_buffer retry ...\n");
257    res = bcm2835_mailbox_init_frame_buffer( &init_frame_buffer_entries );
258    printk("bcm2835_mailbox_init_frame_buffer returned %d\n", res);
259    if (res != 0)
260      return RPI_FB_INIT_SETUP_FAILED;
261  }
262
263  bcm2835_get_pitch_entries get_pitch_entries;
264  bcm2835_mailbox_get_pitch( &get_pitch_entries );
265
266  fb_var_info.xres = init_frame_buffer_entries.xres;
267  fb_var_info.yres = init_frame_buffer_entries.yres;
268  fb_var_info.bits_per_pixel = init_frame_buffer_entries.depth;
269  fb_fix_info.smem_start = (void *) init_frame_buffer_entries.base;
270  fb_fix_info.smem_len = init_frame_buffer_entries.size;
271  fb_fix_info.line_length = get_pitch_entries.pitch;
272
273  if ( fb_fix_info.smem_start == NULL )
274    return RPI_FB_INIT_START_ADDR_UNKNOWN;
275
276  printk("fb_fix_info.smem_start %p\n", fb_fix_info.smem_start);
277
278  arm_cp15_set_translation_table_entries( (void *) fb_fix_info.smem_start,
279    (void *) fb_fix_info.smem_start +
280    fb_fix_info.smem_len,
281    ARMV7_MMU_DATA_READ_WRITE_CACHED );
282
283  return RPI_FB_INIT_OK;
284}
285
286/*
287 * fbds device driver initialize entry point.
288 */
289
290rtems_device_driver frame_buffer_initialize(
291  rtems_device_major_number major,
292  rtems_device_minor_number minor,
293  void                     *arg
294)
295{
296  rtems_status_code status;
297
298  /* register the devices */
299  status = rtems_io_register_name( FRAMEBUFFER_DEVICE_0_NAME, major, 0 );
300
301  if ( status != RTEMS_SUCCESSFUL ) {
302    printk( "[!] error registering framebuffer\n" );
303    rtems_fatal_error_occurred( status );
304  }
305
306  _Atomic_Flag_clear( &driver_mutex, ATOMIC_ORDER_RELEASE );
307  return RTEMS_SUCCESSFUL;
308}
309
310/*
311 * fbds device driver open operation.
312 */
313
314rtems_device_driver frame_buffer_open(
315  rtems_device_major_number major,
316  rtems_device_minor_number minor,
317  void                     *arg
318)
319{
320  if ( _Atomic_Flag_test_and_set( &driver_mutex,
321         ATOMIC_ORDER_ACQUIRE ) != 0 ) {
322    printk( "RaspberryPi framebuffer could not lock driver_mutex\n" );
323    return RTEMS_UNSATISFIED;
324  }
325
326  if ( fb_fix_info.smem_start == NULL ) {
327    int res;
328    res = rpi_fb_init();
329    if ( (res < RPI_FB_INIT_OK) || (fb_fix_info.smem_start == NULL) ) {
330      _Atomic_Flag_clear( &driver_mutex, ATOMIC_ORDER_RELEASE );
331      printk( "RaspberryPi framebuffer initialization failed\n" );
332      return RTEMS_UNSATISFIED;
333    }
334  }
335
336  memset( (void *) fb_fix_info.smem_start, 0, fb_fix_info.smem_len );
337  return RTEMS_SUCCESSFUL;
338}
339
340/*
341 * fbds device driver close operation.
342 */
343
344rtems_device_driver frame_buffer_close(
345  rtems_device_major_number major,
346  rtems_device_minor_number minor,
347  void                     *arg
348)
349{
350  /* restore previous state.  for VGA this means return to text mode.
351   * leave out if graphics hardware has been initialized in
352   * frame_buffer_initialize() */
353  memset( (void *) fb_fix_info.smem_start, 0, fb_fix_info.smem_len );
354  _Atomic_Flag_clear( &driver_mutex, ATOMIC_ORDER_RELEASE );
355  return RTEMS_SUCCESSFUL;
356}
357
358/*
359 * fbds device driver read operation.
360 */
361
362rtems_device_driver frame_buffer_read(
363  rtems_device_major_number major,
364  rtems_device_minor_number minor,
365  void                     *arg
366)
367{
368  rtems_libio_rw_args_t *rw_args = (rtems_libio_rw_args_t *) arg;
369
370  rw_args->bytes_moved =
371    ( ( rw_args->offset + rw_args->count ) > fb_fix_info.smem_len ) ?
372    ( fb_fix_info.smem_len - rw_args->offset ) : rw_args->count;
373  memcpy( rw_args->buffer,
374    (const void *) ( fb_fix_info.smem_start + rw_args->offset ),
375    rw_args->bytes_moved );
376  return RTEMS_SUCCESSFUL;
377}
378
379/*
380 * fbds device driver write operation.
381 */
382
383rtems_device_driver frame_buffer_write(
384  rtems_device_major_number major,
385  rtems_device_minor_number minor,
386  void                     *arg
387)
388{
389  rtems_libio_rw_args_t *rw_args = (rtems_libio_rw_args_t *) arg;
390
391  rw_args->bytes_moved =
392    ( ( rw_args->offset + rw_args->count ) > fb_fix_info.smem_len ) ?
393    ( fb_fix_info.smem_len - rw_args->offset ) : rw_args->count;
394  memcpy( (void *) ( fb_fix_info.smem_start + rw_args->offset ),
395    rw_args->buffer,
396    rw_args->bytes_moved );
397  return RTEMS_SUCCESSFUL;
398}
399
400/*
401 * ioctl entry point.
402 */
403
404rtems_device_driver frame_buffer_control(
405  rtems_device_major_number major,
406  rtems_device_minor_number minor,
407  void                     *arg
408)
409{
410  rtems_libio_ioctl_args_t *args = arg;
411
412  /* XXX check minor */
413
414  switch ( args->command ) {
415    case FBIOGET_VSCREENINFO:
416      memcpy( args->buffer, &fb_var_info, sizeof( fb_var_info ) );
417      args->ioctl_return = 0;
418      break;
419    case FBIOGET_FSCREENINFO:
420      memcpy( args->buffer, &fb_fix_info, sizeof( fb_fix_info ) );
421      args->ioctl_return = 0;
422      break;
423    case FBIOGETCMAP:
424      /* no palette - truecolor mode */
425      args->ioctl_return = -1;
426      return RTEMS_UNSATISFIED;
427    case FBIOPUTCMAP:
428      /* no palette - truecolor mode */
429      args->ioctl_return = -1;
430      return RTEMS_UNSATISFIED;
431    default:
432      args->ioctl_return = -1;
433      return RTEMS_UNSATISFIED;
434  }
435
436  return RTEMS_SUCCESSFUL;
437}
Note: See TracBrowser for help on using the repository browser.