1 /*
2 * Copyright (C) 2015-2020 manufacturername
3 */
4
5 #include <stdio.h>
6 #include <stdbool.h>
7 #include <stdint.h>
8 #include <aos/kernel.h>
9 #include <ulog/ulog.h>
10 #include <fcntl.h>
11 // #include <sys/mman.h>
12 #include "udisplay.h"
13 #include "udisplay_cli.h"
14
15 static udisplay_context_t g_udisplay_ctx;
16
17
udisplay_get_context(void)18 udisplay_context_t *udisplay_get_context(void)
19 {
20 return &g_udisplay_ctx;
21 }
22
get_display_buffer_addr(int32_t num)23 static uint8_t *get_display_buffer_addr(int32_t num)
24 {
25 udisplay_context_t *ctx = udisplay_get_context();
26
27 if (num == 0)
28 return (uint8_t *)ctx->framebuffer;
29 else if (num == 1)
30 return (uint8_t *)(ctx->framebuffer + ctx->framebuffer_size / 2);
31
32 return NULL;
33 }
34
display_draw_rect(uint32_t x1,uint32_t y1,uint32_t h,uint32_t w,uint8_t * buf)35 static void display_draw_rect(uint32_t x1, uint32_t y1,
36 uint32_t h, uint32_t w,
37 uint8_t *buf)
38 {
39 udisplay_context_t *ctx = udisplay_get_context();
40 int32_t line_length = 0;
41 uint32_t location = 0;
42 uint32_t byte_location = 0;
43 uint8_t bit_location = 0;
44 uint8_t *fbaddr = NULL;
45
46 fbaddr = get_display_buffer_addr(ctx->fb_id);
47 line_length = w * ctx->var.bits_per_pixel / 8;
48
49 if ((x1 > ctx->var.xres) || (y1 > ctx->var.yres) || \
50 ((x1 + w) > ctx->var.xres) || ((y1 + h) > ctx->var.yres)) {
51 LOGE("udisplay", "[%s]x1, y1, h, or w is not correct : \
52 %d, %d, %d, %d\n", __func__, x1, y1, h, w);
53 return;
54 }
55
56 /*32 or 24 bit per pixel*/
57 if (ctx->var.bits_per_pixel == 32 || ctx->var.bits_per_pixel == 24) {
58 uint32_t * fbp32 = (uint32_t *)fbaddr;
59 uint32_t *pbuf = buf;
60 int32_t y;
61
62 for (y = y1; y <= h + y1; y++) {
63 location = (x1 + ctx->var.xoffset) + \
64 (y + ctx->var.yoffset) * line_length / 4;
65 memcpy(&fbp32[location], (uint32_t *)pbuf, w * 4);
66 pbuf += w;
67 }
68 }
69 /*16 bit per pixel*/
70 else if (ctx->var.bits_per_pixel == 16) {
71 uint16_t * fbp16 = (uint16_t *)fbaddr;
72 uint16_t *pbuf = buf;
73 int32_t y;
74 for (y = y1; y <= h + y1; y++) {
75 location = (x1 + ctx->var.xoffset) + \
76 (y + ctx->var.yoffset) * line_length / 2;
77 memcpy(&fbp16[location], (uint16_t *)pbuf, w * 2);
78 pbuf += w;
79 }
80 }
81 /*8 bit per pixel*/
82 else if (ctx->var.bits_per_pixel == 8) {
83 uint8_t * fbp8 = (uint8_t *)fbaddr;
84 uint8_t *pbuf = buf;
85 int32_t y;
86 for (y = y1; y <= h + y1; y++) {
87 location = (x1 + ctx->var.xoffset) + \
88 (y + ctx->var.yoffset) * line_length;
89 memcpy(&fbp8[location], (uint32_t *)pbuf, w);
90 pbuf += w;
91 }
92 }
93 /*1 bit per pixel*/
94 else if (ctx->var.bits_per_pixel == 1) {
95 uint8_t * fbp8 = (uint8_t *)fbaddr;
96 uint8_t *pbuf = buf;
97 int32_t x;
98 int32_t y;
99 for (y = y1; y <= y1 + h; y++) {
100 for (x = x1; x <= x1 + w; x++) {
101 location = (x + ctx->var.xoffset) + \
102 (y + ctx->var.yoffset) * ctx->var.xres;
103 /* find the byte we need to change */
104 byte_location = location / 8;
105 /* inside the byte found, find the bit we need to change */
106 bit_location = location % 8;
107 fbp8[byte_location] &= ~(((uint8_t)(1)) << bit_location);
108 fbp8[byte_location] |= ((uint8_t)pbuf) << bit_location;
109 pbuf++;
110 }
111
112 pbuf += w;
113 }
114 } else {
115 /*Not supported bit per pixel*/
116 }
117 }
118
udisplay_draw_rgb32(uint8_t * in,uint32_t x0,uint32_t y0,uint32_t width,uint32_t height,int32_t color)119 static void udisplay_draw_rgb32(uint8_t *in, uint32_t x0, uint32_t y0,
120 uint32_t width, uint32_t height,
121 int32_t color)
122 {
123 int32_t x, y;
124 udisplay_context_t *ctx = udisplay_get_context();
125 const int32_t bytesPerPixel = ctx->var.bits_per_pixel / 8;
126 const int32_t line_length = width * ctx->var.bits_per_pixel / 8;
127 const int32_t stride = line_length / bytesPerPixel;
128 uint32_t *dest = (uint32_t *)in;
129
130 for (y = y0; y < height; ++y) {
131 for (x = x0; x < width; ++x)
132 dest[x] = color;
133
134 dest += stride;
135 }
136 }
137
udisplay_draw_rgb16(uint8_t * in,uint32_t x0,uint32_t y0,uint32_t width,uint32_t height,int32_t color)138 static void udisplay_draw_rgb16(uint8_t *in, uint32_t x0, uint32_t y0,
139 uint32_t width, uint32_t height,
140 int32_t color)
141 {
142 int32_t x, y;
143 udisplay_context_t *ctx = udisplay_get_context();
144 const int32_t bytesPerPixel = ctx->var.bits_per_pixel / 8;
145 const int32_t line_length = width * ctx->var.bits_per_pixel / 8;
146 const int32_t stride = line_length / bytesPerPixel;
147 // const int32_t red = (color & 0xff0000) >> (16 + 3);
148 // const int32_t green = (color & 0xff00) >> (8 + 2);
149 // const int32_t blue = (color & 0xff) >> 3;
150 // const short color16 = blue | (green << 5) | (red << (5 + 6));
151
152 short *dest = (short *) (in);
153
154 for (y = y0; y < height; ++y) {
155 for (x = x0; x < width; ++x)
156 dest[x] = color;
157
158 dest += stride;
159 }
160 }
161
udisplay_set_prefb_addr(uint8_t * buf)162 static int32_t udisplay_set_prefb_addr(uint8_t *buf)
163 {
164 int32_t ret;
165 udisplay_context_t *ctx = udisplay_get_context();
166
167 ret = ioctl(ctx->fd, FBIOPUT_PREFB_ADDR, (unsigned long)buf);
168 if (ret < 0) {
169 LOGE("udisplay", "[%s]ioctl fail, ret = %d\n", __func__, ret);
170 return -1;
171 }
172 return ret;
173 }
174
udisplay_init(void)175 int32_t udisplay_init(void)
176 {
177 int32_t fd;
178 int32_t ret;
179 int32_t fb_size;
180 uint8_t *fbaddr = NULL;
181 fb_var_screeninfo_t fb_var;
182 udisplay_context_t *ctx = udisplay_get_context();
183
184 memset(ctx, 0 , sizeof(udisplay_context_t));
185
186 if (aos_mutex_new(&ctx->mutex) != 0) {
187 LOGE("udisplay", "[%s]create mutex error\n", __func__);
188 return -1;
189 }
190
191 /*open framebuffer device*/
192 fd = open(FB_PATH, O_RDWR);
193 if (fd < 0) {
194 LOGE("udisplay", "[%s]open %s fail, fd : %d\n", __func__, FB_PATH, fd);
195 return -1;
196 }
197
198 /*get framebuffer size*/
199 ret = ioctl(fd, FBIOGET_VSCREENINFO, (unsigned long)&fb_var);
200 if (ret < 0) {
201 close(fd);
202 LOGE("udisplay", "[%s]VSCREENINFO fail, ret : %d\n", __func__, ret);
203 return -1;
204 }
205
206 fb_size = fb_var.xres_virtual * fb_var.yres_virtual
207 * fb_var.bits_per_pixel / 8;
208
209 // need set fd first becaseof udisplay_set_prefb_addr function used
210 ctx->fd = fd;
211
212 #ifdef ENABLE_MICRO_KERNEL
213 fbaddr = (uint8_t *)mmap(NULL, fb_size, 0, 0, fd, 0);
214 if (!fbaddr) {
215 close(fd);
216 return -1;
217 }
218 LOGE("udisplay", "[%s]mmap addr : %p\r\n", __func__, fbaddr);
219 ctx->framebuffer = fbaddr;
220 ctx->framebuffer_size = fb_size;
221 #endif
222
223 ctx->swap = ((fb_var.xres_virtual * fb_var.yres_virtual) /
224 (fb_var.xres * fb_var.yres) == 2) ?
225 true : false;
226 ctx->fb_id = 0;
227
228 memcpy(&ctx->var, &fb_var, sizeof(fb_var_screeninfo_t));
229
230 return 0;
231 }
232
wait_vsync(void)233 static int32_t wait_vsync(void)
234 {
235 int32_t ret;
236 udisplay_context_t *ctx = udisplay_get_context();
237
238 ret = ioctl(ctx->fd, FBIO_WAITFORVSYNC, (unsigned long)&ctx->var);
239 if (ret < 0)
240 LOGE("udisplay", "[%s]ioctl fail, ret : %d\n", __func__, ret);
241
242 return ret;
243 }
244
udisplay_pan_display(uint8_t fb_id)245 static int32_t udisplay_pan_display(uint8_t fb_id)
246 {
247 int32_t ret;
248 udisplay_context_t *ctx = udisplay_get_context();
249 fb_var_screeninfo_t *var = &ctx->var;
250 #ifdef CONFIG_UDISPLAY_TIME_MEASURE
251 long long start, end;
252 start = aos_now_ms();
253 #endif
254 var->yoffset = (fb_id > 0) ? fb_id * var->yres : 0;
255 ret = ioctl(ctx->fd, FBIOPAN_DISPLAY, (unsigned long)var);
256 if (ret < 0)
257 LOGE("udisplay", "[%s]aos_ioctl fail, ret : %d\n", __func__, ret);
258
259 #ifdef CONFIG_UDISPLAY_TIME_MEASURE
260 end = aos_now_ms();
261 LOGD("udisplay", "[%s]ioctl time gap: %lld ms\r\n", __func__, end - start);
262 #endif
263 #ifdef CONFIG_UDISPLAY_TIME_MEASURE
264 start = aos_now_ms();
265 #endif
266 /*check if enable swap buffer*/
267 if (ctx->swap) {
268 wait_vsync();
269 ctx->fb_id = !fb_id;
270 }
271 #ifdef CONFIG_UDISPLAY_TIME_MEASURE
272 end = aos_now_ms();
273 LOGD("udisplay", "[%s]wait vsync time gap: %lld ms\r\n", \
274 __func__, end - start);
275 #endif
276 return ret;
277 }
278
udisplay_show_rect(uint8_t * buf,uint32_t x,uint32_t y,uint32_t w,uint32_t h,bool rotate)279 int32_t udisplay_show_rect(uint8_t *buf, uint32_t x, uint32_t y, uint32_t w, \
280 uint32_t h, bool rotate)
281 {
282 int32_t ret;
283 udisplay_context_t *ctx = udisplay_get_context();
284 #ifdef CONFIG_UDISPLAY_TIME_MEASURE
285 long long start, end;
286 start = aos_now_ms();
287 #endif
288
289 if (!buf)
290 return -1;
291
292 if (aos_mutex_lock(&ctx->mutex, AOS_WAIT_FOREVER) != 0)
293 return -1;
294
295 if (rotate) {
296 ret = udisplay_set_prefb_addr(buf);
297 if (ret < 0) {
298 LOGE("udisplay", "[%s]set prefb addr fail\n", __func__);
299 aos_mutex_unlock(&ctx->mutex);
300 return -1;
301 }
302 } else {
303 #ifdef ENABLE_MICRO_KERNEL
304 if ((x == 0) && (y == 0)) {
305 memcpy(get_display_buffer_addr(ctx->fb_id), buf, \
306 ctx->var.xres * \
307 ctx->var.yres * \
308 ctx->var.bits_per_pixel / 8);
309 } else {
310 display_draw_rect(x, y, w, h, buf);
311 }
312 #else
313 ret = udisplay_set_prefb_addr(buf);
314 if (ret < 0) {
315 LOGE("udisplay", "[%s]set prefb addr fail\n", __func__);
316 aos_mutex_unlock(&ctx->mutex);
317 return -1;
318 }
319 #endif
320 }
321
322 ret = udisplay_pan_display(ctx->fb_id);
323 #ifdef CONFIG_UDISPLAY_TIME_MEASURE
324 end = aos_now_ms();
325 LOGD("udisplay", "[%s]time gap: %lld ms\r\n", __func__, end - start);
326 #endif
327 aos_mutex_unlock(&ctx->mutex);
328 return ret;
329 }
330
udisplay_show(void)331 int32_t udisplay_show(void)
332 {
333 int32_t ret;
334 udisplay_context_t *ctx = udisplay_get_context();
335
336 if (aos_mutex_lock(&ctx->mutex, AOS_WAIT_FOREVER) != 0)
337 return -1;
338 ret = udisplay_pan_display(ctx->fb_id);
339 aos_mutex_unlock(&ctx->mutex);
340
341 return ret;
342 }
343
udisplay_get_framebuffer(void)344 uint8_t *udisplay_get_framebuffer(void)
345 {
346 uint8_t *fb = NULL;
347 udisplay_context_t *ctx = udisplay_get_context();
348
349 if (aos_mutex_lock(&ctx->mutex, AOS_WAIT_FOREVER) != 0)
350 return NULL;
351
352 fb = get_display_buffer_addr(ctx->fb_id);
353 aos_mutex_unlock(&ctx->mutex);
354 return fb;
355 }
356
udisplay_pattern_rgb32(uint32_t color,bool rotate)357 int32_t udisplay_pattern_rgb32(uint32_t color, bool rotate)
358 {
359 int32_t ret;
360 uint8_t *buf = NULL;
361 udisplay_context_t *ctx = udisplay_get_context();
362 fb_var_screeninfo_t *var = &ctx->var;
363
364 if (aos_mutex_lock(&ctx->mutex, AOS_WAIT_FOREVER) != 0)
365 return -1;
366
367 if (rotate) {
368 #ifdef CONFIG_UDISPLAY_TIME_MEASURE
369 long long start, end;
370 start = aos_now_ms();
371 #endif
372 buf = (uint8_t *)aos_malloc(var->xres * var->yres * \
373 var->bits_per_pixel / 8);
374 if (!buf) {
375 LOGE("udisplay", "[%s]no memory allocated\n", __func__);
376 aos_mutex_unlock(&ctx->mutex);
377 return -1;
378 }
379 udisplay_draw_rgb32(buf, 0, 0, var->yres, var->xres, color);
380 ret = udisplay_set_prefb_addr(buf);
381 if (ret < 0) {
382 aos_free(buf);
383 LOGE("udisplay", "[%s]set prefb addr fail\n", __func__);
384 aos_mutex_unlock(&ctx->mutex);
385 return -1;
386 }
387 aos_free(buf);
388 #ifdef CONFIG_UDISPLAY_TIME_MEASURE
389 end = aos_now_ms();
390 LOGD("udisplay", "[%s]from malloc and free time gap: %lld ms\r\n", \
391 __func__, end - start);
392 #endif
393 } else {
394 buf = get_display_buffer_addr(ctx->fb_id);
395 udisplay_draw_rgb32(buf, 0, 0, var->xres, var->yres, color);
396 }
397 ret = udisplay_pan_display(ctx->fb_id);
398 aos_mutex_unlock(&ctx->mutex);
399 return ret;
400 }
401
udisplay_pattern_rgb16(uint32_t color,bool rotate)402 int32_t udisplay_pattern_rgb16(uint32_t color, bool rotate)
403 {
404 int32_t ret;
405 uint8_t *buf = NULL;
406 udisplay_context_t *ctx = udisplay_get_context();
407 fb_var_screeninfo_t *var = &ctx->var;
408
409 if (aos_mutex_lock(&ctx->mutex, AOS_WAIT_FOREVER) != 0) {
410 LOGE("udisplay", "[%s]aos_mutex_lock failed\n", __func__);
411 return -1;
412 }
413
414 #ifdef ENABLE_MICRO_KERNEL
415 buf = get_display_buffer_addr(g_udisplay_ctx.fb_id);
416 #else
417 buf = (uint8_t *)aos_malloc(var->xres * var->yres *
418 var->bits_per_pixel / 8);
419 if (!buf) {
420 LOGE("udisplay", "[%s]no memory allocated\n", __func__);
421 aos_mutex_unlock(&ctx->mutex);
422 return -1;
423 }
424 #endif
425
426 ret = udisplay_set_prefb_addr(buf);
427 if (ret < 0) {
428 #ifndef ENABLE_MICRO_KERNEL
429 aos_free(buf);
430 #endif
431 LOGE("udisplay", "[%s]set prefb addr fail\n", __func__);
432 aos_mutex_unlock(&ctx->mutex);
433 return -1;
434 }
435 udisplay_draw_rgb16(buf, 0, 0, var->yres, var->xres, color);
436 ret = udisplay_pan_display(ctx->fb_id);
437 if (ret < 0) {
438 #ifndef ENABLE_MICRO_KERNEL
439 aos_free(buf);
440 #endif
441 LOGE("udisplay", "[%s]udisplay_pan_display fail\n", __func__);
442 aos_mutex_unlock(&ctx->mutex);
443 return -1;
444 }
445 #ifndef ENABLE_MICRO_KERNEL
446 aos_free(buf);
447 #endif
448 aos_mutex_unlock(&ctx->mutex);
449 LOGE("udisplay", "[%s]udisplay_pattern_rgb16 finish\n", __func__);
450 return ret;
451 }
452
udisplay_set_brightness(int32_t brightness)453 int32_t udisplay_set_brightness(int32_t brightness)
454 {
455 int32_t ret;
456 udisplay_context_t *ctx = udisplay_get_context();
457
458 ret = ioctl(ctx->fd, FBIOPUT_BRIGHTNESS, (unsigned long)&brightness);
459 if (ret < 0)
460 LOGE("udisplay", "[%s]aos_ioctl fail, ret : %d\n", __func__, ret);
461
462 return ret;
463 }
464
udisplay_get_brightness(void)465 int32_t udisplay_get_brightness(void)
466 {
467 int32_t ret;
468 int32_t brightness;
469 udisplay_context_t *ctx = udisplay_get_context();
470
471 ret = ioctl(ctx->fd, FBIOGET_BRIGHTNESS, (unsigned long)&brightness);
472 if (ret < 0) {
473 LOGE("udisplay", "[%s]aos_ioctl fail, ret : %d\n", __func__, ret);
474 return ret;
475 }
476
477 return brightness;
478 }
479
udisplay_enable_backlight(void)480 int32_t udisplay_enable_backlight(void)
481 {
482 int32_t ret;
483 udisplay_context_t *ctx = udisplay_get_context();
484
485 ret = ioctl(ctx->fd, FBIOENABLE_BACKLIGHT, NULL);
486 if (ret < 0)
487 LOGE("udisplay", "[%s]aos_ioctl fail, ret : %d\n", __func__, ret);
488
489 return ret;
490 }
491
udisplay_disable_backlight(void)492 int32_t udisplay_disable_backlight(void)
493 {
494 int32_t ret;
495 udisplay_context_t *ctx = udisplay_get_context();
496
497 ret = ioctl(ctx->fd, FBIODISABLE_BACKLIGHT, NULL);
498 if (ret < 0)
499 LOGE("udisplay", "[%s]aos_ioctl fail, ret : %d\n", __func__, ret);
500
501 return ret;
502 }
503
504