source: rtems/c/src/lib/libbsp/arm/shared/arm-pl111-fb.c @ df40cc9

4.115
Last change on this file since df40cc9 was c499856, checked in by Chris Johns <chrisj@…>, on 03/20/14 at 21:10:47

Change all references of rtems.com to rtems.org.

  • Property mode set to 100644
File size: 6.2 KB
Line 
1/*
2 * Copyright (c) 2013 embedded brains GmbH.  All rights reserved.
3 *
4 *  embedded brains GmbH
5 *  Dornierstr. 4
6 *  82178 Puchheim
7 *  Germany
8 *  <info@embedded-brains.de>
9 *
10 * The license and distribution terms for this file may be
11 * found in the file LICENSE in this distribution or at
12 * http://www.rtems.org/license/LICENSE.
13 */
14
15#include <errno.h>
16#include <assert.h>
17#include <stdlib.h>
18
19#include <rtems/framebuffer.h>
20#include <rtems/fb.h>
21#include <rtems/libio.h>
22
23#include <bsp.h>
24#include <bsp/arm-pl111-fb.h>
25#include <bsp/fatal.h>
26
27typedef struct {
28  rtems_id semaphore;
29  void *frame_buffer;
30} pl111_fb_context;
31
32static pl111_fb_context pl111_fb_instance;
33
34static const uint8_t pl111_bits_per_pixel[] = { 1, 2, 4, 8, 16, 24, 16, 12 };
35
36static uint32_t pl111_fb_get_width(const pl111_fb_config *cfg)
37{
38  return 16U * (PL111_LCD_TIMING0_PPL_GET(cfg->timing0) + 1U);
39}
40
41static uint32_t pl111_fb_get_height(const pl111_fb_config *cfg)
42{
43  return PL111_LCD_TIMING1_LPP_GET(cfg->timing1) + 1U;
44}
45
46static uint32_t pl111_fb_get_bits_per_pixel(const pl111_fb_config *cfg)
47{
48  return pl111_bits_per_pixel[PL111_LCD_CONTROL_LCD_BPP_GET(cfg->control)];
49}
50
51static uint32_t pl111_fb_get_line_length_in_bytes(const pl111_fb_config *cfg)
52{
53  uint32_t width = pl111_fb_get_width(cfg);
54  uint32_t bits_per_pixel = pl111_fb_get_bits_per_pixel(cfg);
55
56  return width * ((bits_per_pixel + 7U) / 8U);
57}
58
59static uint32_t pl111_fb_get_frame_buffer_size(const pl111_fb_config *cfg)
60{
61  uint32_t line_length_in_bytes = pl111_fb_get_line_length_in_bytes(cfg);
62  uint32_t height = pl111_fb_get_height(cfg);
63
64  return height * line_length_in_bytes;
65}
66
67static void pl111_fb_power_delay(const pl111_fb_config *cfg)
68{
69  rtems_interval delay = (cfg->power_delay_in_us + 1)
70    / rtems_configuration_get_microseconds_per_tick();
71  rtems_status_code sc = rtems_task_wake_after(delay);
72  assert(sc == RTEMS_SUCCESSFUL);
73}
74
75static rtems_status_code pl111_fb_initialize(pl111_fb_context *ctx)
76{
77  rtems_status_code sc = RTEMS_SUCCESSFUL;
78  const pl111_fb_config *cfg = arm_pl111_fb_get_config();
79
80  ctx->frame_buffer = calloc(1, pl111_fb_get_frame_buffer_size(cfg));
81  if (ctx->frame_buffer != NULL) {
82    volatile pl111 *regs = cfg->regs;
83
84    (*cfg->set_up)(cfg);
85
86    regs->lcd.upbase = (uint32_t) ctx->frame_buffer;
87
88    regs->lcd.timing0 = cfg->timing0;
89    regs->lcd.timing1 = cfg->timing1;
90    regs->lcd.timing2 = cfg->timing2;
91    regs->lcd.timing3 = cfg->timing3;
92    regs->lcd.control = cfg->control;
93
94    (*cfg->pins_set_up)(cfg);
95
96    regs->lcd.control = cfg->control
97      | PL111_LCD_CONTROL_LCD_EN;
98
99    pl111_fb_power_delay(cfg);
100
101    regs->lcd.control = cfg->control
102      | PL111_LCD_CONTROL_LCD_EN
103      | PL111_LCD_CONTROL_LCD_PWR;
104  } else {
105    sc = RTEMS_NO_MEMORY;
106  }
107
108  return sc;
109}
110
111static void pl111_fb_destroy(const pl111_fb_context *ctx)
112{
113  const pl111_fb_config *cfg = arm_pl111_fb_get_config();
114  volatile pl111 *regs = cfg->regs;
115
116  free(ctx->frame_buffer);
117
118  regs->lcd.control = cfg->control
119    | PL111_LCD_CONTROL_LCD_EN;
120
121  pl111_fb_power_delay(cfg);
122
123  regs->lcd.control = cfg->control;
124
125  (*cfg->pins_tear_down)(cfg);
126  (*cfg->tear_down)(cfg);
127}
128
129static void pl111_fb_get_fix_screen_info(struct fb_fix_screeninfo *info)
130{
131  const pl111_fb_config *cfg = arm_pl111_fb_get_config();
132  const pl111_fb_context *ctx = &pl111_fb_instance;
133
134  memset(info, 0, sizeof(*info));
135
136  info->smem_start = ctx->frame_buffer;
137  info->smem_len = pl111_fb_get_frame_buffer_size(cfg);
138  info->type = FB_TYPE_PACKED_PIXELS;
139  info->visual = FB_VISUAL_TRUECOLOR;
140  info->line_length = pl111_fb_get_line_length_in_bytes(cfg);
141}
142
143static void pl111_fb_get_var_screen_info(struct fb_var_screeninfo *info)
144{
145  const pl111_fb_config *cfg = arm_pl111_fb_get_config();
146
147  memset(info, 0, sizeof(*info));
148
149  info->xres = pl111_fb_get_width(cfg);
150  info->yres = pl111_fb_get_height(cfg);
151  info->bits_per_pixel = pl111_fb_get_bits_per_pixel(cfg);
152}
153
154static void pl111_fb_release(const pl111_fb_context *ctx)
155{
156  rtems_status_code sc = rtems_semaphore_release(ctx->semaphore);
157  if (sc != RTEMS_SUCCESSFUL) {
158    bsp_fatal(BSP_ARM_PL111_FATAL_SEM_RELEASE);
159  }
160}
161
162rtems_device_driver frame_buffer_initialize(
163  rtems_device_major_number major,
164  rtems_device_minor_number minor,
165  void *arg
166)
167{
168  rtems_status_code sc;
169  pl111_fb_context *ctx = &pl111_fb_instance;
170
171  sc = rtems_io_register_name(FRAMEBUFFER_DEVICE_0_NAME, major, 0);
172  if (sc != RTEMS_SUCCESSFUL) {
173    bsp_fatal(BSP_ARM_PL111_FATAL_REGISTER_DEV);
174  }
175
176  sc = rtems_semaphore_create(
177    rtems_build_name('F', 'B', ' ', ' '),
178    1,
179    RTEMS_COUNTING_SEMAPHORE,
180    0,
181    &ctx->semaphore
182  );
183  if (sc != RTEMS_SUCCESSFUL) {
184    bsp_fatal(BSP_ARM_PL111_FATAL_SEM_CREATE);
185  }
186
187  return sc;
188}
189
190rtems_device_driver frame_buffer_open(
191  rtems_device_major_number major,
192  rtems_device_minor_number minor,
193  void *arg
194)
195{
196  rtems_status_code sc;
197  pl111_fb_context *ctx = &pl111_fb_instance;
198
199  sc = rtems_semaphore_obtain(
200    ctx->semaphore,
201    RTEMS_WAIT,
202    RTEMS_NO_TIMEOUT
203  );
204  if (sc == RTEMS_SUCCESSFUL) {
205    sc = pl111_fb_initialize(ctx);
206    if (sc != RTEMS_SUCCESSFUL) {
207      pl111_fb_release(ctx);
208    }
209  }
210
211  return sc;
212}
213
214rtems_device_driver frame_buffer_close(
215  rtems_device_major_number major,
216  rtems_device_minor_number minor,
217  void *arg
218)
219{
220  const pl111_fb_context *ctx = &pl111_fb_instance;
221
222  pl111_fb_destroy(ctx);
223  pl111_fb_release(ctx);
224
225  return RTEMS_SUCCESSFUL;
226}
227
228rtems_device_driver frame_buffer_read(
229  rtems_device_major_number major,
230  rtems_device_minor_number minor,
231  void *arg
232)
233{
234  return RTEMS_IO_ERROR;
235}
236
237rtems_device_driver frame_buffer_write(
238  rtems_device_major_number major,
239  rtems_device_minor_number minor,
240  void *arg
241)
242{
243  return RTEMS_IO_ERROR;
244}
245
246rtems_device_driver frame_buffer_control(
247  rtems_device_major_number major,
248  rtems_device_minor_number minor,
249  void *arg
250)
251{
252  rtems_libio_ioctl_args_t *ioctl_arg = arg;
253  int eno = 0;
254
255  switch (ioctl_arg->command) {
256    case FBIOGET_FSCREENINFO:
257      pl111_fb_get_fix_screen_info(ioctl_arg->buffer);
258      break;
259    case FBIOGET_VSCREENINFO:
260      pl111_fb_get_var_screen_info(ioctl_arg->buffer);
261      break;
262    default:
263      eno = EINVAL;
264      break;
265  }
266
267  if (eno == 0) {
268    ioctl_arg->ioctl_return = 0;
269  } else {
270    ioctl_arg->ioctl_return = -1;
271    errno = eno;
272  }
273
274  return RTEMS_SUCCESSFUL;
275}
Note: See TracBrowser for help on using the repository browser.