File indexing completed on 2025-05-11 08:23:05
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019
0020
0021
0022
0023
0024
0025
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 }