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