Back to home page

LXR

 
 

    


File indexing completed on 2025-05-11 08:23:05

0001 /* SPDX-License-Identifier: BSD-2-Clause */
0002 
0003 /*
0004  * Copyright (c) 2013 embedded brains GmbH & Co. KG
0005  *
0006  * Redistribution and use in source and binary forms, with or without
0007  * modification, are permitted provided that the following conditions
0008  * are met:
0009  * 1. Redistributions of source code must retain the above copyright
0010  *    notice, this list of conditions and the following disclaimer.
0011  * 2. Redistributions in binary form must reproduce the above copyright
0012  *    notice, this list of conditions and the following disclaimer in the
0013  *    documentation and/or other materials provided with the distribution.
0014  *
0015  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
0016  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
0017  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
0018  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
0019  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
0020  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
0021  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
0022  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
0023  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
0024  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
0025  * POSSIBILITY OF SUCH DAMAGE.
0026  */
0027 
0028 #include <errno.h>
0029 #include <assert.h>
0030 #include <stdlib.h>
0031 #include <string.h>
0032 
0033 #include <rtems/framebuffer.h>
0034 #include <rtems/fb.h>
0035 #include <rtems/libio.h>
0036 
0037 #include <bsp.h>
0038 #include <bsp/arm-pl111-fb.h>
0039 #include <bsp/fatal.h>
0040 
0041 typedef struct {
0042   rtems_id semaphore;
0043   void *frame_buffer;
0044 } pl111_fb_context;
0045 
0046 static pl111_fb_context pl111_fb_instance;
0047 
0048 static const uint8_t pl111_bits_per_pixel[] = { 1, 2, 4, 8, 16, 24, 16, 12 };
0049 
0050 static uint32_t pl111_fb_get_width(const pl111_fb_config *cfg)
0051 {
0052   return 16U * (PL111_LCD_TIMING0_PPL_GET(cfg->timing0) + 1U);
0053 }
0054 
0055 static uint32_t pl111_fb_get_height(const pl111_fb_config *cfg)
0056 {
0057   return PL111_LCD_TIMING1_LPP_GET(cfg->timing1) + 1U;
0058 }
0059 
0060 static uint32_t pl111_fb_get_bits_per_pixel(const pl111_fb_config *cfg)
0061 {
0062   return pl111_bits_per_pixel[PL111_LCD_CONTROL_LCD_BPP_GET(cfg->control)];
0063 }
0064 
0065 static uint32_t pl111_fb_get_line_length_in_bytes(const pl111_fb_config *cfg)
0066 {
0067   uint32_t width = pl111_fb_get_width(cfg);
0068   uint32_t bits_per_pixel = pl111_fb_get_bits_per_pixel(cfg);
0069 
0070   return width * ((bits_per_pixel + 7U) / 8U);
0071 }
0072 
0073 static uint32_t pl111_fb_get_frame_buffer_size(const pl111_fb_config *cfg)
0074 {
0075   uint32_t line_length_in_bytes = pl111_fb_get_line_length_in_bytes(cfg);
0076   uint32_t height = pl111_fb_get_height(cfg);
0077 
0078   return height * line_length_in_bytes;
0079 }
0080 
0081 static void pl111_fb_power_delay(const pl111_fb_config *cfg)
0082 {
0083   rtems_interval delay = (cfg->power_delay_in_us + 1)
0084     / rtems_configuration_get_microseconds_per_tick();
0085   rtems_status_code sc = rtems_task_wake_after(delay);
0086   assert(sc == RTEMS_SUCCESSFUL);
0087 }
0088 
0089 static rtems_status_code pl111_fb_initialize(pl111_fb_context *ctx)
0090 {
0091   rtems_status_code sc = RTEMS_SUCCESSFUL;
0092   const pl111_fb_config *cfg = arm_pl111_fb_get_config();
0093 
0094   ctx->frame_buffer = calloc(1, pl111_fb_get_frame_buffer_size(cfg));
0095   if (ctx->frame_buffer != NULL) {
0096     volatile pl111 *regs = cfg->regs;
0097 
0098     (*cfg->set_up)(cfg);
0099 
0100     regs->lcd.upbase = (uint32_t) ctx->frame_buffer;
0101 
0102     regs->lcd.timing0 = cfg->timing0;
0103     regs->lcd.timing1 = cfg->timing1;
0104     regs->lcd.timing2 = cfg->timing2;
0105     regs->lcd.timing3 = cfg->timing3;
0106     regs->lcd.control = cfg->control;
0107 
0108     (*cfg->pins_set_up)(cfg);
0109 
0110     regs->lcd.control = cfg->control
0111       | PL111_LCD_CONTROL_LCD_EN;
0112 
0113     pl111_fb_power_delay(cfg);
0114 
0115     regs->lcd.control = cfg->control
0116       | PL111_LCD_CONTROL_LCD_EN
0117       | PL111_LCD_CONTROL_LCD_PWR;
0118   } else {
0119     sc = RTEMS_NO_MEMORY;
0120   }
0121 
0122   return sc;
0123 }
0124 
0125 static void pl111_fb_destroy(const pl111_fb_context *ctx)
0126 {
0127   const pl111_fb_config *cfg = arm_pl111_fb_get_config();
0128   volatile pl111 *regs = cfg->regs;
0129 
0130   free(ctx->frame_buffer);
0131 
0132   regs->lcd.control = cfg->control
0133     | PL111_LCD_CONTROL_LCD_EN;
0134 
0135   pl111_fb_power_delay(cfg);
0136 
0137   regs->lcd.control = cfg->control;
0138 
0139   (*cfg->pins_tear_down)(cfg);
0140   (*cfg->tear_down)(cfg);
0141 }
0142 
0143 static void pl111_fb_get_fix_screen_info(struct fb_fix_screeninfo *info)
0144 {
0145   const pl111_fb_config *cfg = arm_pl111_fb_get_config();
0146   const pl111_fb_context *ctx = &pl111_fb_instance;
0147 
0148   memset(info, 0, sizeof(*info));
0149 
0150   info->smem_start = ctx->frame_buffer;
0151   info->smem_len = pl111_fb_get_frame_buffer_size(cfg);
0152   info->type = FB_TYPE_PACKED_PIXELS;
0153   info->visual = FB_VISUAL_TRUECOLOR;
0154   info->line_length = pl111_fb_get_line_length_in_bytes(cfg);
0155 }
0156 
0157 static void pl111_fb_get_var_screen_info(struct fb_var_screeninfo *info)
0158 {
0159   const pl111_fb_config *cfg = arm_pl111_fb_get_config();
0160 
0161   memset(info, 0, sizeof(*info));
0162 
0163   info->xres = pl111_fb_get_width(cfg);
0164   info->yres = pl111_fb_get_height(cfg);
0165   info->bits_per_pixel = pl111_fb_get_bits_per_pixel(cfg);
0166 }
0167 
0168 static void pl111_fb_release(const pl111_fb_context *ctx)
0169 {
0170   rtems_status_code sc = rtems_semaphore_release(ctx->semaphore);
0171   if (sc != RTEMS_SUCCESSFUL) {
0172     bsp_fatal(BSP_ARM_PL111_FATAL_SEM_RELEASE);
0173   }
0174 }
0175 
0176 rtems_device_driver frame_buffer_initialize(
0177   rtems_device_major_number major,
0178   rtems_device_minor_number minor,
0179   void *arg
0180 )
0181 {
0182   rtems_status_code sc;
0183   pl111_fb_context *ctx = &pl111_fb_instance;
0184 
0185   sc = rtems_io_register_name(FRAMEBUFFER_DEVICE_0_NAME, major, 0);
0186   if (sc != RTEMS_SUCCESSFUL) {
0187     bsp_fatal(BSP_ARM_PL111_FATAL_REGISTER_DEV);
0188   }
0189 
0190   sc = rtems_semaphore_create(
0191     rtems_build_name('F', 'B', ' ', ' '),
0192     1,
0193     RTEMS_COUNTING_SEMAPHORE,
0194     0,
0195     &ctx->semaphore
0196   );
0197   if (sc != RTEMS_SUCCESSFUL) {
0198     bsp_fatal(BSP_ARM_PL111_FATAL_SEM_CREATE);
0199   }
0200 
0201   return sc;
0202 }
0203 
0204 rtems_device_driver frame_buffer_open(
0205   rtems_device_major_number major,
0206   rtems_device_minor_number minor,
0207   void *arg
0208 )
0209 {
0210   rtems_status_code sc;
0211   pl111_fb_context *ctx = &pl111_fb_instance;
0212 
0213   sc = rtems_semaphore_obtain(
0214     ctx->semaphore,
0215     RTEMS_WAIT,
0216     RTEMS_NO_TIMEOUT
0217   );
0218   if (sc == RTEMS_SUCCESSFUL) {
0219     sc = pl111_fb_initialize(ctx);
0220     if (sc != RTEMS_SUCCESSFUL) {
0221       pl111_fb_release(ctx);
0222     }
0223   }
0224 
0225   return sc;
0226 }
0227 
0228 rtems_device_driver frame_buffer_close(
0229   rtems_device_major_number major,
0230   rtems_device_minor_number minor,
0231   void *arg
0232 )
0233 {
0234   const pl111_fb_context *ctx = &pl111_fb_instance;
0235 
0236   pl111_fb_destroy(ctx);
0237   pl111_fb_release(ctx);
0238 
0239   return RTEMS_SUCCESSFUL;
0240 }
0241 
0242 rtems_device_driver frame_buffer_read(
0243   rtems_device_major_number major,
0244   rtems_device_minor_number minor,
0245   void *arg
0246 )
0247 {
0248   return RTEMS_IO_ERROR;
0249 }
0250 
0251 rtems_device_driver frame_buffer_write(
0252   rtems_device_major_number major,
0253   rtems_device_minor_number minor,
0254   void *arg
0255 )
0256 {
0257   return RTEMS_IO_ERROR;
0258 }
0259 
0260 rtems_device_driver frame_buffer_control(
0261   rtems_device_major_number major,
0262   rtems_device_minor_number minor,
0263   void *arg
0264 )
0265 {
0266   rtems_libio_ioctl_args_t *ioctl_arg = arg;
0267   int eno = 0;
0268 
0269   switch (ioctl_arg->command) {
0270     case FBIOGET_FSCREENINFO:
0271       pl111_fb_get_fix_screen_info(ioctl_arg->buffer);
0272       break;
0273     case FBIOGET_VSCREENINFO:
0274       pl111_fb_get_var_screen_info(ioctl_arg->buffer);
0275       break;
0276     default:
0277       eno = EINVAL;
0278       break;
0279   }
0280 
0281   if (eno == 0) {
0282     ioctl_arg->ioctl_return = 0;
0283   } else {
0284     ioctl_arg->ioctl_return = -1;
0285     errno = eno;
0286   }
0287 
0288   return RTEMS_SUCCESSFUL;
0289 }