1 /*
2  * Copyright (c) 2006-2021, RT-Thread Development Team
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  *
6  * Change Logs:
7  * Date           Author         Notes
8  * 2019-08-29     zdzn           first version
9  */
10 
11 #include <rthw.h>
12 #include <rtthread.h>
13 #include <rtdevice.h>
14 
15 #include "mbox.h"
16 #include "drv_fb.h"
17 #include "mmu.h"
18 
19 #define CHAR_W          8
20 #define CHAR_H          12
21 
22 #define COLOR_DELTA     0.05
23 static struct rt_hdmi_fb_device _hdmi;
24 fb_t fb_info;
25 
26 // https://github.com/xinu-os/xinu/blob/1789b7a50b5b73c2ea76ebd764c54a034097d04d/device/framebuffer_rpi/font.c
27 unsigned char FONT[] = {
28 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /*' '*/
29 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /*' '*/
30 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /*' '*/
31 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /*' '*/
32 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /*' '*/
33 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /*' '*/
34 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /*' '*/
35 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /*' '*/
36 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /*' '*/
37 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /*' '*/
38 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /*' '*/
39 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /*' '*/
40 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /*' '*/
41 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /*' '*/
42 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /*' '*/
43 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /*' '*/
44 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /*' '*/
45 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /*' '*/
46 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /*' '*/
47 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /*' '*/
48 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /*' '*/
49 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /*' '*/
50 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /*' '*/
51 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /*' '*/
52 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /*' '*/
53 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /*' '*/
54 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /*' '*/
55 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /*' '*/
56 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /*' '*/
57 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /*' '*/
58 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /*' '*/
59 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /*' '*/
60 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /*' '*/
61 0x00, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x00, 0x08, 0x00, 0x00, 0x00, /*'!'*/
62 0x00, 0x14, 0x14, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /*'"'*/
63 0x00, 0x00, 0x14, 0x14, 0x3e, 0x14, 0x3e, 0x14, 0x14, 0x00, 0x00, 0x00, /*'#'*/
64 0x00, 0x00, 0x08, 0x3c, 0x0a, 0x1c, 0x28, 0x1e, 0x08, 0x00, 0x00, 0x00, /*'$'*/
65 0x00, 0x00, 0x06, 0x26, 0x10, 0x08, 0x04, 0x32, 0x30, 0x00, 0x00, 0x00, /*'%'*/
66 0x00, 0x00, 0x1c, 0x02, 0x02, 0x04, 0x2a, 0x12, 0x2c, 0x00, 0x00, 0x00, /*'&'*/
67 0x00, 0x18, 0x08, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /*'''*/
68 0x20, 0x10, 0x10, 0x08, 0x08, 0x08, 0x08, 0x08, 0x10, 0x10, 0x20, 0x00, /*'('*/
69 0x02, 0x04, 0x04, 0x08, 0x08, 0x08, 0x08, 0x08, 0x04, 0x04, 0x02, 0x00, /*')'*/
70 0x00, 0x00, 0x00, 0x08, 0x2a, 0x1c, 0x2a, 0x08, 0x00, 0x00, 0x00, 0x00, /*'*'*/
71 0x00, 0x00, 0x00, 0x08, 0x08, 0x3e, 0x08, 0x08, 0x00, 0x00, 0x00, 0x00, /*'+'*/
72 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x08, 0x04, 0x00, /*','*/
73 0x00, 0x00, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /*'-'*/
74 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, /*'.'*/
75 0x20, 0x20, 0x10, 0x10, 0x08, 0x08, 0x04, 0x04, 0x02, 0x02, 0x00, 0x00, /*'/'*/
76 0x00, 0x1c, 0x22, 0x32, 0x2a, 0x26, 0x22, 0x22, 0x1c, 0x00, 0x00, 0x00, /*'0'*/
77 0x00, 0x08, 0x0c, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x00, 0x00, 0x00, /*'1'*/
78 0x00, 0x1c, 0x22, 0x20, 0x10, 0x08, 0x04, 0x02, 0x3e, 0x00, 0x00, 0x00, /*'2'*/
79 0x00, 0x1c, 0x22, 0x20, 0x18, 0x20, 0x20, 0x22, 0x1c, 0x00, 0x00, 0x00, /*'3'*/
80 0x00, 0x10, 0x18, 0x18, 0x14, 0x14, 0x3e, 0x10, 0x38, 0x00, 0x00, 0x00, /*'4'*/
81 0x00, 0x3e, 0x02, 0x02, 0x1e, 0x20, 0x20, 0x22, 0x1c, 0x00, 0x00, 0x00, /*'5'*/
82 0x00, 0x18, 0x04, 0x02, 0x1e, 0x22, 0x22, 0x22, 0x1c, 0x00, 0x00, 0x00, /*'6'*/
83 0x00, 0x3e, 0x22, 0x20, 0x20, 0x10, 0x10, 0x08, 0x08, 0x00, 0x00, 0x00, /*'7'*/
84 0x00, 0x1c, 0x22, 0x22, 0x1c, 0x22, 0x22, 0x22, 0x1c, 0x00, 0x00, 0x00, /*'8'*/
85 0x00, 0x1c, 0x22, 0x22, 0x22, 0x3c, 0x20, 0x10, 0x0c, 0x00, 0x00, 0x00, /*'9'*/
86 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, /*':'*/
87 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x18, 0x18, 0x08, 0x04, 0x00, /*';'*/
88 0x00, 0x00, 0x00, 0x30, 0x0c, 0x03, 0x0c, 0x30, 0x00, 0x00, 0x00, 0x00, /*'<'*/
89 0x00, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x3e, 0x00, 0x00, 0x00, 0x00, 0x00, /*'='*/
90 0x00, 0x00, 0x00, 0x03, 0x0c, 0x30, 0x0c, 0x03, 0x00, 0x00, 0x00, 0x00, /*'>'*/
91 0x00, 0x1c, 0x22, 0x20, 0x10, 0x08, 0x08, 0x00, 0x08, 0x00, 0x00, 0x00, /*'?'*/
92 0x00, 0x00, 0x1c, 0x22, 0x3a, 0x3a, 0x1a, 0x02, 0x1c, 0x00, 0x00, 0x00, /*'@'*/
93 0x00, 0x00, 0x08, 0x14, 0x22, 0x22, 0x3e, 0x22, 0x22, 0x00, 0x00, 0x00, /*'A'*/
94 0x00, 0x00, 0x1e, 0x22, 0x22, 0x1e, 0x22, 0x22, 0x1e, 0x00, 0x00, 0x00, /*'B'*/
95 0x00, 0x00, 0x1c, 0x22, 0x02, 0x02, 0x02, 0x22, 0x1c, 0x00, 0x00, 0x00, /*'C'*/
96 0x00, 0x00, 0x0e, 0x12, 0x22, 0x22, 0x22, 0x12, 0x0e, 0x00, 0x00, 0x00, /*'D'*/
97 0x00, 0x00, 0x3e, 0x02, 0x02, 0x1e, 0x02, 0x02, 0x3e, 0x00, 0x00, 0x00, /*'E'*/
98 0x00, 0x00, 0x3e, 0x02, 0x02, 0x1e, 0x02, 0x02, 0x02, 0x00, 0x00, 0x00, /*'F'*/
99 0x00, 0x00, 0x1c, 0x22, 0x02, 0x32, 0x22, 0x22, 0x3c, 0x00, 0x00, 0x00, /*'G'*/
100 0x00, 0x00, 0x22, 0x22, 0x22, 0x3e, 0x22, 0x22, 0x22, 0x00, 0x00, 0x00, /*'H'*/
101 0x00, 0x00, 0x3e, 0x08, 0x08, 0x08, 0x08, 0x08, 0x3e, 0x00, 0x00, 0x00, /*'I'*/
102 0x00, 0x00, 0x38, 0x20, 0x20, 0x20, 0x22, 0x22, 0x1c, 0x00, 0x00, 0x00, /*'J'*/
103 0x00, 0x00, 0x22, 0x12, 0x0a, 0x06, 0x0a, 0x12, 0x22, 0x00, 0x00, 0x00, /*'K'*/
104 0x00, 0x00, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x3e, 0x00, 0x00, 0x00, /*'L'*/
105 0x00, 0x00, 0x22, 0x36, 0x2a, 0x2a, 0x22, 0x22, 0x22, 0x00, 0x00, 0x00, /*'M'*/
106 0x00, 0x00, 0x22, 0x26, 0x26, 0x2a, 0x32, 0x32, 0x22, 0x00, 0x00, 0x00, /*'N'*/
107 0x00, 0x00, 0x1c, 0x22, 0x22, 0x22, 0x22, 0x22, 0x1c, 0x00, 0x00, 0x00, /*'O'*/
108 0x00, 0x00, 0x1e, 0x22, 0x22, 0x1e, 0x02, 0x02, 0x02, 0x00, 0x00, 0x00, /*'P'*/
109 0x00, 0x00, 0x1c, 0x22, 0x22, 0x22, 0x22, 0x22, 0x1c, 0x30, 0x00, 0x00, /*'Q'*/
110 0x00, 0x00, 0x1e, 0x22, 0x22, 0x1e, 0x0a, 0x12, 0x22, 0x00, 0x00, 0x00, /*'R'*/
111 0x00, 0x00, 0x1c, 0x22, 0x02, 0x1c, 0x20, 0x22, 0x1c, 0x00, 0x00, 0x00, /*'S'*/
112 0x00, 0x00, 0x3e, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x00, 0x00, 0x00, /*'T'*/
113 0x00, 0x00, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x1c, 0x00, 0x00, 0x00, /*'U'*/
114 0x00, 0x00, 0x22, 0x22, 0x22, 0x14, 0x14, 0x08, 0x08, 0x00, 0x00, 0x00, /*'V'*/
115 0x00, 0x00, 0x22, 0x22, 0x22, 0x2a, 0x2a, 0x36, 0x22, 0x00, 0x00, 0x00, /*'W'*/
116 0x00, 0x00, 0x22, 0x22, 0x14, 0x08, 0x14, 0x22, 0x22, 0x00, 0x00, 0x00, /*'X'*/
117 0x00, 0x00, 0x22, 0x22, 0x14, 0x08, 0x08, 0x08, 0x08, 0x00, 0x00, 0x00, /*'Y'*/
118 0x00, 0x00, 0x3e, 0x20, 0x10, 0x08, 0x04, 0x02, 0x3e, 0x00, 0x00, 0x00, /*'Z'*/
119 0x38, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x38, 0x00, /*'['*/
120 0x02, 0x02, 0x04, 0x04, 0x08, 0x08, 0x10, 0x10, 0x20, 0x20, 0x00, 0x00, /*'\'*/
121 0x0e, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x0e, 0x00, /*']'*/
122 0x00, 0x08, 0x14, 0x22, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /*'^'*/
123 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0x00, 0x00, /*'_'*/
124 0x00, 0x0c, 0x08, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /*'`'*/
125 0x00, 0x00, 0x00, 0x00, 0x3c, 0x22, 0x22, 0x32, 0x2c, 0x00, 0x00, 0x00, /*'a'*/
126 0x00, 0x02, 0x02, 0x02, 0x1e, 0x22, 0x22, 0x22, 0x1e, 0x00, 0x00, 0x00, /*'b'*/
127 0x00, 0x00, 0x00, 0x00, 0x3c, 0x02, 0x02, 0x02, 0x3c, 0x00, 0x00, 0x00, /*'c'*/
128 0x00, 0x20, 0x20, 0x20, 0x3c, 0x22, 0x22, 0x22, 0x3c, 0x00, 0x00, 0x00, /*'d'*/
129 0x00, 0x00, 0x00, 0x00, 0x1c, 0x22, 0x3e, 0x02, 0x1c, 0x00, 0x00, 0x00, /*'e'*/
130 0x00, 0x38, 0x04, 0x04, 0x1e, 0x04, 0x04, 0x04, 0x04, 0x00, 0x00, 0x00, /*'f'*/
131 0x00, 0x00, 0x00, 0x00, 0x3c, 0x22, 0x22, 0x22, 0x3c, 0x20, 0x20, 0x1c, /*'g'*/
132 0x00, 0x02, 0x02, 0x02, 0x1e, 0x22, 0x22, 0x22, 0x22, 0x00, 0x00, 0x00, /*'h'*/
133 0x00, 0x08, 0x08, 0x00, 0x0c, 0x08, 0x08, 0x08, 0x1c, 0x00, 0x00, 0x00, /*'i'*/
134 0x00, 0x10, 0x10, 0x00, 0x1c, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x0e, /*'j'*/
135 0x00, 0x02, 0x02, 0x02, 0x12, 0x0a, 0x06, 0x0a, 0x12, 0x00, 0x00, 0x00, /*'k'*/
136 0x00, 0x0c, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x1c, 0x00, 0x00, 0x00, /*'l'*/
137 0x00, 0x00, 0x00, 0x00, 0x16, 0x2a, 0x2a, 0x2a, 0x22, 0x00, 0x00, 0x00, /*'m'*/
138 0x00, 0x00, 0x00, 0x00, 0x1a, 0x26, 0x22, 0x22, 0x22, 0x00, 0x00, 0x00, /*'n'*/
139 0x00, 0x00, 0x00, 0x00, 0x1c, 0x22, 0x22, 0x22, 0x1c, 0x00, 0x00, 0x00, /*'o'*/
140 0x00, 0x00, 0x00, 0x00, 0x1e, 0x22, 0x22, 0x22, 0x1e, 0x02, 0x02, 0x02, /*'p'*/
141 0x00, 0x00, 0x00, 0x00, 0x3c, 0x22, 0x22, 0x22, 0x3c, 0x20, 0x20, 0x20, /*'q'*/
142 0x00, 0x00, 0x00, 0x00, 0x1a, 0x06, 0x02, 0x02, 0x02, 0x00, 0x00, 0x00, /*'r'*/
143 0x00, 0x00, 0x00, 0x00, 0x3c, 0x02, 0x1c, 0x20, 0x1e, 0x00, 0x00, 0x00, /*'s'*/
144 0x00, 0x08, 0x08, 0x08, 0x3e, 0x08, 0x08, 0x08, 0x30, 0x00, 0x00, 0x00, /*'t'*/
145 0x00, 0x00, 0x00, 0x00, 0x22, 0x22, 0x22, 0x32, 0x2c, 0x00, 0x00, 0x00, /*'u'*/
146 0x00, 0x00, 0x00, 0x00, 0x36, 0x14, 0x14, 0x08, 0x08, 0x00, 0x00, 0x00, /*'v'*/
147 0x00, 0x00, 0x00, 0x00, 0x22, 0x2a, 0x2a, 0x2a, 0x14, 0x00, 0x00, 0x00, /*'w'*/
148 0x00, 0x00, 0x00, 0x00, 0x22, 0x14, 0x08, 0x14, 0x22, 0x00, 0x00, 0x00, /*'x'*/
149 0x00, 0x00, 0x00, 0x00, 0x22, 0x22, 0x22, 0x22, 0x3c, 0x20, 0x20, 0x1c, /*'y'*/
150 0x00, 0x00, 0x00, 0x00, 0x3e, 0x10, 0x08, 0x04, 0x3e, 0x00, 0x00, 0x00, /*'z'*/
151 0x20, 0x10, 0x10, 0x10, 0x10, 0x08, 0x10, 0x10, 0x10, 0x10, 0x20, 0x00, /*'{'*/
152 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x00, /*'|'*/
153 0x02, 0x04, 0x04, 0x04, 0x04, 0x08, 0x04, 0x04, 0x04, 0x04, 0x02, 0x00, /*'}'*/
154 0x00, 0x04, 0x2a, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /*'~'*/
155 0x00, 0x00, 0x00, 0x08, 0x08, 0x14, 0x14, 0x22, 0x3e, 0x00, 0x00, 0x00, /*DEL*/
156 };
157 
newline(fb_t * fb)158 void newline(fb_t* fb)
159 {
160     uint8_t* to;
161     uint8_t* from;
162     int i;
163     fb->y++;
164     fb->x = 0;
165 
166     if (fb->y == (fb->height / CHAR_H))
167     {
168 
169         to = (uint8_t*) fb->addr;
170         from = to + (CHAR_H * fb->pitch);
171 
172         for (i = 0; i < ((fb->height - CHAR_H) * fb->pitch); i++)
173         {
174             *to++ = *from++;
175         }
176 
177         uint32_t *addr = (uint32_t*) (fb->addr) + (fb->height - CHAR_H) * fb->width;
178 
179         for (i = 0; i < (CHAR_H * fb->width); i++)
180         {
181             *addr++ = fb->back;
182         }
183 
184         fb->y--;
185     }
186 }
187 
clear_line(fb_t * fb,const int line)188 void clear_line(fb_t *fb, const int line)
189 {
190     int i;
191     uint32_t* addr;
192     if (line > fb->height / CHAR_H)
193     {
194         fb->y = 0;
195     }
196     else
197     {
198         fb->y = line;
199     }
200 
201     fb->x = 0;
202 
203     addr = (uint32_t*) (fb->addr + (line * CHAR_H * fb->depth * fb->width));
204     for (i = 0; i < (CHAR_H * fb->width); i++)
205     {
206         *addr++ = fb->back;
207     }
208 
209 }
210 
fb_draw_char(fb_t * fb,char s)211 void fb_draw_char(fb_t *fb, char s)
212 {
213     unsigned char* addr = (unsigned char*) fb->addr;
214     unsigned char *glyph = (unsigned char*) FONT + (s) * 12;
215     // calculate the offset on screen
216     int offs = (fb->y * CHAR_H * fb->pitch) + (fb->x * (CHAR_W + 1) * 4);
217     // variables
218     int i, j, line, mask, bytesperline = (CHAR_W + 7) / 8;
219     // display a character
220     for (j = 0; j < CHAR_H; j++)
221     {
222         // display one row
223         line = offs;
224         mask = 1;
225         for (i = 0; i < CHAR_W; i++)
226         {
227             // if bit set, we use white color, otherwise black
228             *((unsigned int*) (addr + line)) = ((int) *glyph) & mask ? fb->fore : fb->back;
229             mask <<= 1;
230             line += 4;
231         }
232         // adjust to next line
233         glyph += bytesperline;
234         offs += fb->pitch;
235     }
236 }
237 
fb_print(fb_t * fb,char * s)238 void fb_print(fb_t *fb, char *s)
239 {
240 
241     // draw next character if it's not zero
242     while (*s)
243     {
244         // handle carrige return
245         if (*s == '\r')
246         {
247             fb->x = 0;
248         }
249         else if (*s == '\n')
250         {
251             newline(fb);
252         }
253         else if (*s == '\t')
254         {
255             fb->x = ((fb->x + 4) >> 2) << 2;
256         }
257         else if (*s == '\b')
258         {
259             if (fb->x)
260             {
261                 fb->x--;
262                 fb_draw_char(fb, ' ');
263             }
264         }
265         else
266         {
267             fb_draw_char(fb, *s);
268             fb->x++;
269         }
270         // next character
271         if (fb->x == fb->width / CHAR_W)
272         {
273             newline(fb);
274         }
275         s++;
276     }
277 }
278 
hdmi_fb_open(rt_device_t dev,rt_uint16_t oflag)279 rt_err_t hdmi_fb_open(rt_device_t dev, rt_uint16_t oflag)
280 {
281     return RT_EOK;
282 }
283 
hdmi_fb_close(rt_device_t dev)284 rt_err_t hdmi_fb_close(rt_device_t dev)
285 {
286     return RT_EOK;
287 }
288 
hdmi_fb_read(rt_device_t dev,rt_off_t pos,void * buf,rt_size_t size)289 rt_size_t hdmi_fb_read(rt_device_t dev, rt_off_t pos, void *buf, rt_size_t size)
290 {
291     return 0;
292 }
293 
hdmi_fb_write(rt_device_t dev,rt_off_t pos,const void * buffer,rt_size_t size)294 rt_size_t hdmi_fb_write(rt_device_t dev, rt_off_t pos, const void *buffer, rt_size_t size)
295 {
296     fb_print(&_hdmi.fb, (char *) buffer);
297 #ifdef BSP_USING_HDMI_DISPLAY
298     rt_device_t uart = rt_device_find("uart1");
299     int old_flag = uart->open_flag;
300     uart->open_flag |= RT_DEVICE_FLAG_STREAM;
301     rt_device_write(uart, 0, buffer, size);
302     uart->open_flag = old_flag;
303 #endif
304     return size;
305 }
306 
hdmi_fb_control(rt_device_t dev,int cmd,void * args)307 rt_err_t hdmi_fb_control(rt_device_t dev, int cmd, void *args)
308 {
309     return RT_EOK;
310 }
311 
312 const static struct rt_device_ops hdmi_fb_ops =
313 {
314     RT_NULL,
315     hdmi_fb_open,
316     hdmi_fb_close,
317     hdmi_fb_read,
318     hdmi_fb_write,
319     hdmi_fb_control
320 };
321 
322 static struct rt_device_graphic_info _hdmi_info;
323 
hdmi_draw_rect(const char * pixel,int x1,int y1,int x2,int y2)324 static void hdmi_draw_rect(const char* pixel, int x1, int y1, int x2, int y2)
325 {
326     int i, j;
327     int line;
328     for (j = y1; j <= y2; j++)
329     {
330         line = (j * _hdmi.fb.pitch) + (x1 * 4);
331         for (i = x1; i <= x2; i++)
332         {
333             // if bit set, we use white color, otherwise black
334             *((unsigned int*) (_hdmi_info.framebuffer + line)) = *(unsigned int*) pixel;
335             line += 4;
336         }
337     }
338 
339 }
340 
hdmi_set_pixel(const char * pixel,int x,int y)341 static void hdmi_set_pixel(const char* pixel, int x, int y)
342 {
343     *(uint32_t*) (_hdmi.fb.addr + (y * _hdmi.fb.pitch + x * 4)) = *(uint32_t *) pixel;
344 }
345 
hdmi_get_pixel(char * pixel,int x,int y)346 static void hdmi_get_pixel(char* pixel, int x, int y)
347 {
348     uint32_t ret = 0;
349     ret = (*(uint32_t*) (_hdmi.fb.addr + (y * _hdmi.fb.pitch + x * 4)) & 0x00FFFFFF);
350     *pixel = ret;
351 }
352 
hdmi_draw_hline(const char * pixel,int x1,int x2,int y)353 static void hdmi_draw_hline(const char* pixel, int x1, int x2, int y)
354 {
355     hdmi_draw_rect(pixel, x1, y, x2, y);
356 }
357 
hdmi_draw_vline(const char * pixel,int x,int y1,int y2)358 static void hdmi_draw_vline(const char* pixel, int x, int y1, int y2)
359 {
360     hdmi_draw_rect(pixel, x, y1, x, y2);
361 }
362 
hdmi_blit_line(const char * pixels,int x,int y,rt_size_t size)363 static void hdmi_blit_line(const char* pixels, int x, int y, rt_size_t size)
364 {
365     int i = 0;
366     uint32_t *pixel_base = (uint32_t*) (_hdmi.fb.addr + (y * _hdmi.fb.pitch + x * 4));
367     uint32_t *colors = (uint32_t *) pixels;
368     for (i = 0; i < size; i++)
369     {
370         pixel_base[i] = colors[i];
371     }
372 }
373 
374 static struct rt_device_graphic_ops hdmi_ops =
375 {
376     hdmi_set_pixel,
377     hdmi_get_pixel,
378     hdmi_draw_hline,
379     hdmi_draw_vline,
380     hdmi_blit_line
381 };
382 
rt_hdmi_fb_device_init(struct rt_hdmi_fb_device * hdmi_fb,const char * name)383 rt_err_t rt_hdmi_fb_device_init(struct rt_hdmi_fb_device *hdmi_fb, const char *name)
384 {
385     struct rt_device *device;
386     RT_ASSERT(hdmi_fb != RT_NULL);
387 
388     device = &hdmi_fb->parent;
389     device->user_data = &hdmi_ops;
390 
391     /* set device type */
392     device->type = RT_Device_Class_Graphic;
393     /* initialize device interface */
394 #ifdef RT_USING_DEVICE_OPS
395     device->ops = &hdmi_fb_ops;
396 #else
397     device->init = RT_NULL;
398     device->open = hdmi_fb_open;
399     device->close = hdmi_fb_close;
400     device->read = hdmi_fb_read;
401     device->write = hdmi_fb_write;
402     device->control = hdmi_fb_control;
403 #endif
404 
405     /* register to device manager */
406     rt_device_register(device, name, RT_DEVICE_FLAG_RDWR);
407 
408     return RT_EOK;
409 }
410 
411 /**
412  * Show a picture
413  */
print_fb_info()414 void print_fb_info()
415 {
416     rt_kprintf("FrameBuffer Info: \n \t width %x\t height %x\t depth %x\t addr %x\t size %x\t \n", fb_info.width,
417             fb_info.height, fb_info.depth, fb_info.addr, fb_info.size);
418     rt_kprintf("call mbox:%x,%x,%x,%x,%x\n", mbox[0], mbox[1], mbox[2], mbox[3], mbox[4]);
419 }
420 
hdmi_fb_init()421 int hdmi_fb_init()
422 {
423     unsigned int *mbox = (unsigned int*) MBOX_ADDR;
424     mbox[0] = 35 * 4;
425     mbox[1] = MBOX_REQUEST;
426 
427     mbox[2] = 0x48003;  //set phy wh
428     mbox[3] = 8;
429     mbox[4] = 8;
430     mbox[5] = 640;         //FrameBufferInfo.width
431     mbox[6] = 480;          //FrameBufferInfo.height
432 
433     mbox[7] = 0x48004;  //set virt wh
434     mbox[8] = 8;
435     mbox[9] = 8;
436     mbox[10] = 640;        //FrameBufferInfo.virtual_width
437     mbox[11] = 480;         //FrameBufferInfo.virtual_height
438 
439     mbox[12] = 0x48009; //set virt offset
440     mbox[13] = 8;
441     mbox[14] = 8;
442     mbox[15] = 0;           //FrameBufferInfo.x_offset
443     mbox[16] = 0;           //FrameBufferInfo.y.offset
444 
445     mbox[17] = 0x48005; //set depth
446     mbox[18] = 4;
447     mbox[19] = 4;
448     mbox[20] = 32;          //FrameBufferInfo.depth
449 
450     mbox[21] = 0x48006; //set pixel order
451     mbox[22] = 4;
452     mbox[23] = 4;
453     mbox[24] = 1;           //RGB, not BGR preferably
454 
455     mbox[25] = 0x40001; //get framebuffer, gets alignment on request
456     mbox[26] = 8;
457     mbox[27] = 8;
458     mbox[28] = 4096;        //FrameBufferInfo.pointer
459     mbox[29] = 0;           //FrameBufferInfo.size
460 
461     mbox[30] = 0x40008; //get pitch
462     mbox[31] = 4;
463     mbox[32] = 4;
464     mbox[33] = 0;           //FrameBufferInfo.pitch
465 
466     mbox[34] = MBOX_TAG_LAST;
467     if (mbox_call(MBOX_CH_PROP, MMU_DISABLE) && mbox[20] == 32 && mbox[28] != 0)
468     {
469         mbox[28] &= 0x3FFFFFFF;
470         _hdmi.fb.width = mbox[5];
471         _hdmi.fb.height = mbox[6];
472         _hdmi.fb.pitch = mbox[33];
473         //_hdmi.fb.addr = (void*)((unsigned long)mbox[28]);
474         _hdmi.fb.addr = (rt_uint32_t) mbox[28];
475         _hdmi.fb.size = mbox[29];
476         _hdmi.fb.depth = 32;
477         _hdmi.fb.x = 0;
478         _hdmi.fb.y = 0;
479         _hdmi.fb.fore = CONSOLE_WHITE;
480         _hdmi.fb.back = CONSOLE_BLACK;
481         rt_hdmi_fb_device_init(&_hdmi, "hdmi");
482         rt_hw_change_mmu_table(_hdmi.fb.addr, _hdmi.fb.size, _hdmi.fb.addr, DEVICE_MEM);
483         fb_info.width = _hdmi.fb.width;
484         fb_info.height = _hdmi.fb.height;
485         fb_info.addr = _hdmi.fb.addr;
486         fb_info.size = _hdmi.fb.size;
487         fb_info.pitch = _hdmi.fb.pitch;
488         fb_info.depth = _hdmi.fb.depth;
489         _hdmi_info.pixel_format = RTGRAPHIC_PIXEL_FORMAT_RGB888;
490         _hdmi_info.bits_per_pixel = _hdmi.fb.depth;
491         _hdmi_info.width = _hdmi.fb.width;
492         _hdmi_info.height = _hdmi.fb.height;
493         _hdmi_info.framebuffer = (rt_uint8_t *) _hdmi.fb.addr;
494     }
495     return 0;
496 }
497 
498 INIT_DEVICE_EXPORT(hdmi_fb_init);
499