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 <stdint.h>
13 #include <rtthread.h>
14 #include <rtdevice.h>
15 #include "mbox.h"
16 #include "drv_fb.h"
17 #include "mmu.h"
18 #include "cache.h"
19
20 #define LCD_WIDTH (800)
21 #define LCD_HEIGHT (480)
22 #define LCD_DEPTH (32)
23 #define LCD_BPP (32)
24
25 #define TAG_ALLOCATE_BUFFER 0x00040001
26 #define TAG_SET_PHYS_WIDTH_HEIGHT 0x00048003
27 #define TAG_SET_VIRT_WIDTH_HEIGHT 0x00048004
28 #define TAG_SET_DEPTH 0x00048005
29 #define TAG_SET_PIXEL_ORDER 0x00048006
30 #define TAG_GET_PITCH 0x00040008
31 #define TAG_SET_VIRT_OFFSET 0x00048009
32 #define TAG_END 0x00000000
33
34
35 enum {
36 MBOX_TAG_FB_GET_GPIOVIRT = 0x00040010,
37 MBOX_TAG_FB_ALLOCATE_BUFFER = 0x00040001,
38 MBOX_TAG_FB_RELEASE_BUFFER = 0x00048001,
39 MBOX_TAG_FB_BLANK_SCREEN = 0x00040002,
40 MBOX_TAG_FB_GET_PHYS_WH = 0x00040003,
41 MBOX_TAG_FB_TEST_PHYS_WH = 0x00044003,
42 MBOX_TAG_FB_SET_PHYS_WH = 0x00048003,
43 MBOX_TAG_FB_GET_VIRT_WH = 0x00040004,
44 MBOX_TAG_FB_TEST_VIRT_WH = 0x00044004,
45 MBOX_TAG_FB_SET_VIRT_WH = 0x00048004,
46 MBOX_TAG_FB_GET_DEPTH = 0x00040005,
47 MBOX_TAG_FB_TEST_DEPTH = 0x00044005,
48 MBOX_TAG_FB_SET_DEPTH = 0x00048005,
49 MBOX_TAG_FB_GET_PIXEL_ORDER = 0x00040006,
50 MBOX_TAG_FB_TEST_PIXEL_ORDER = 0x00044006,
51 MBOX_TAG_FB_SET_PIXEL_ORDER = 0x00048006,
52 MBOX_TAG_FB_GET_ALPHA_MODE = 0x00040007,
53 MBOX_TAG_FB_TEST_ALPHA_MODE = 0x00044007,
54 MBOX_TAG_FB_SET_ALPHA_MODE = 0x00048007,
55 MBOX_TAG_FB_GET_PITCH = 0x00040008,
56 MBOX_TAG_FB_GET_VIRT_OFFSET = 0x00040009,
57 MBOX_TAG_FB_TEST_VIRT_OFFSET = 0x00044009,
58 MBOX_TAG_FB_SET_VIRT_OFFSET = 0x00048009,
59 MBOX_TAG_FB_GET_OVERSCAN = 0x0004000a,
60 MBOX_TAG_FB_TEST_OVERSCAN = 0x0004400a,
61 MBOX_TAG_FB_SET_OVERSCAN = 0x0004800a,
62 MBOX_TAG_FB_GET_PALETTE = 0x0004000b,
63 MBOX_TAG_FB_TEST_PALETTE = 0x0004400b,
64 MBOX_TAG_FB_SET_PALETTE = 0x0004800b,
65 };
66
67 #define LCD_DEVICE(dev) (struct rt_hdmi_fb_device*)(dev)
68
69 static struct rt_hdmi_fb_device _hdmi;
70
71 typedef rt_uint16_t color_t;
72
hdmi_fb_open(rt_device_t dev,rt_uint16_t oflag)73 rt_err_t hdmi_fb_open(rt_device_t dev, rt_uint16_t oflag)
74 {
75 return RT_EOK;
76 }
77
hdmi_fb_close(rt_device_t dev)78 rt_err_t hdmi_fb_close(rt_device_t dev)
79 {
80 return RT_EOK;
81 }
82
hdmi_fb_read(rt_device_t dev,rt_off_t pos,void * buf,rt_size_t size)83 rt_size_t hdmi_fb_read(rt_device_t dev, rt_off_t pos, void *buf, rt_size_t size)
84 {
85 return 0;
86 }
87
hdmi_fb_write(rt_device_t dev,rt_off_t pos,const void * buffer,rt_size_t size)88 rt_size_t hdmi_fb_write(rt_device_t dev, rt_off_t pos, const void *buffer, rt_size_t size)
89 {
90 return size;
91 }
92
hdmi_fb_control(rt_device_t dev,int cmd,void * args)93 rt_err_t hdmi_fb_control(rt_device_t dev, int cmd, void *args)
94 {
95 struct rt_hdmi_fb_device *lcd = LCD_DEVICE(dev);
96 switch (cmd)
97 {
98 case RTGRAPHIC_CTRL_RECT_UPDATE:
99 {
100 struct rt_device_rect_info *info = (struct rt_device_rect_info*)args;
101 info = info;
102 }
103 break;
104
105 case RTGRAPHIC_CTRL_GET_INFO:
106 {
107 struct rt_device_graphic_info* info = (struct rt_device_graphic_info*)args;
108
109 RT_ASSERT(info != RT_NULL);
110 info->pixel_format = RTGRAPHIC_PIXEL_FORMAT_RGB888;
111 info->bits_per_pixel= LCD_DEPTH;
112 info->width = lcd->width;
113 info->height = lcd->height;
114 info->framebuffer = lcd->fb;
115 }
116 break;
117 }
118 return RT_EOK;
119 }
120
121 const static struct rt_device_ops hdmi_fb_ops =
122 {
123 RT_NULL,
124 hdmi_fb_open,
125 hdmi_fb_close,
126 hdmi_fb_read,
127 hdmi_fb_write,
128 hdmi_fb_control
129 };
130
rt_hdmi_fb_device_init(struct rt_hdmi_fb_device * hdmi_fb,const char * name)131 rt_err_t rt_hdmi_fb_device_init(struct rt_hdmi_fb_device *hdmi_fb, const char *name)
132 {
133 struct rt_device *device;
134 RT_ASSERT(hdmi_fb != RT_NULL);
135
136 device = &hdmi_fb->parent;
137
138 /* set device type */
139 device->type = RT_Device_Class_Graphic;
140 /* initialize device interface */
141 #ifdef RT_USING_DEVICE_OPS
142 device->ops = &hdmi_fb_ops;
143 #else
144 device->init = RT_NULL;
145 device->open = hdmi_fb_open;
146 device->close = hdmi_fb_close;
147 device->read = hdmi_fb_read;
148 device->write = hdmi_fb_write;
149 device->control = hdmi_fb_control;
150 #endif
151
152 /* register to device manager */
153 rt_device_register(device, name, RT_DEVICE_FLAG_RDWR);
154
155 return RT_EOK;
156 }
157
bcm283x_mbox_fb_get_gpiovirt(void)158 rt_uint32_t bcm283x_mbox_fb_get_gpiovirt(void)
159 {
160 mbox[0] = 8*4; // length of the message
161 mbox[1] = MBOX_REQUEST; // this is a request message
162
163 mbox[2] = MBOX_TAG_FB_GET_GPIOVIRT;
164 mbox[3] = 4; // buffer size
165 mbox[4] = 0; // len
166
167 mbox[5] = 0; // id
168 mbox[6] = 0;
169
170 mbox[7] = MBOX_TAG_LAST;
171 mbox_call(8, MMU_DISABLE);
172 return (mbox[5] & 0x3fffffff);
173 }
174
bcm283x_mbox_fb_get_pitch(void)175 rt_uint32_t bcm283x_mbox_fb_get_pitch(void)
176 {
177 mbox[0] = 8*4; // length of the message
178 mbox[1] = MBOX_REQUEST; // this is a request message
179
180 mbox[2] = MBOX_TAG_FB_GET_PITCH;
181 mbox[3] = 4; // buffer size
182 mbox[4] = 0; // len
183
184 mbox[5] = 0; // id
185 mbox[6] = 0;
186
187 mbox[7] = MBOX_TAG_LAST;
188 mbox_call(8, MMU_DISABLE);
189 return mbox[5];
190 }
191
bcm283x_mbox_fb_set_porder(int rgb)192 void bcm283x_mbox_fb_set_porder(int rgb)
193 {
194 mbox[0] = 8*4; // length of the message
195 mbox[1] = MBOX_REQUEST; // this is a request message
196
197 mbox[2] = MBOX_TAG_FB_SET_PIXEL_ORDER;
198 mbox[3] = 4; // buffer size
199 mbox[4] = 4; // len
200
201 mbox[5] = rgb; // id
202 mbox[6] = 0;
203
204 mbox[7] = MBOX_TAG_LAST;
205 mbox_call(8, MMU_DISABLE);
206 }
207
bcm283x_mbox_fb_setoffset(int xoffset,int yoffset)208 void bcm283x_mbox_fb_setoffset(int xoffset, int yoffset)
209 {
210 mbox[0] = 8*4; // length of the message
211 mbox[1] = MBOX_REQUEST; // this is a request message
212
213 mbox[2] = MBOX_TAG_FB_SET_VIRT_OFFSET;
214 mbox[3] = 8; // buffer size
215 mbox[4] = 8; // len
216
217 mbox[5] = xoffset; // id
218 mbox[6] = yoffset;
219
220 mbox[7] = MBOX_TAG_LAST;
221 mbox_call(8, MMU_DISABLE);
222 }
223
224
bcm283x_mbox_fb_setalpha(int alpha)225 void bcm283x_mbox_fb_setalpha(int alpha)
226 {
227
228 mbox[0] = 8*4; // length of the message
229 mbox[1] = MBOX_REQUEST; // this is a request message
230
231 mbox[2] = MBOX_TAG_FB_SET_ALPHA_MODE;
232 mbox[3] = 4; // buffer size
233 mbox[4] = 4; // len
234
235 mbox[5] = alpha; // id
236 mbox[6] = 0;
237
238 mbox[7] = MBOX_TAG_LAST;
239 mbox_call(8, MMU_DISABLE);
240 }
241
bcm283x_mbox_fb_alloc(int width,int height,int bpp,int nrender)242 void *bcm283x_mbox_fb_alloc(int width, int height, int bpp, int nrender)
243 {
244 mbox[0] = 4 * 35;
245 mbox[1] = MBOX_REQUEST;
246
247 mbox[2] = TAG_ALLOCATE_BUFFER;//get framebuffer, gets alignment on request
248 mbox[3] = 8; //size
249 mbox[4] = 4; //len
250 mbox[5] = 4096; //The design of MBOX driver forces us to give the virtual address 0x3C100000
251 mbox[6] = 0; //FrameBufferInfo.size
252
253 mbox[7] = TAG_SET_PHYS_WIDTH_HEIGHT;
254 mbox[8] = 8;
255 mbox[9] = 8;
256 mbox[10] = width;
257 mbox[11] = height;
258
259 mbox[12] = TAG_SET_VIRT_WIDTH_HEIGHT;
260 mbox[13] = 8;
261 mbox[14] = 8;
262 mbox[15] = width;
263 mbox[16] = height * nrender;
264
265 mbox[17] = TAG_SET_DEPTH;
266 mbox[18] = 4;
267 mbox[19] = 4;
268 mbox[20] = bpp;
269
270 mbox[21] = TAG_SET_PIXEL_ORDER;
271 mbox[22] = 4;
272 mbox[23] = 0;
273 mbox[24] = 0; //RGB, not BGR preferably
274
275 mbox[25] = TAG_GET_PITCH;
276 mbox[26] = 4;
277 mbox[27] = 0;
278 mbox[28] = 0;
279
280 mbox[29] = TAG_SET_VIRT_OFFSET;
281 mbox[30] = 8;
282 mbox[31] = 8;
283 mbox[32] = 0;
284 mbox[33] = 0;
285
286 mbox[34] = TAG_END;
287
288 mbox_call(MBOX_CH_PROP, MMU_DISABLE);
289
290 return (void *)((rt_uint64_t)(mbox[5] & 0x3fffffff));
291 }
292
hdmi_fb_init(void)293 int hdmi_fb_init(void)
294 {
295 _hdmi.fb = (rt_uint8_t *)bcm283x_mbox_fb_alloc(LCD_WIDTH, LCD_HEIGHT, LCD_BPP, 1);
296 bcm283x_mbox_fb_setoffset(0, 0);
297 bcm283x_mbox_fb_set_porder(0);
298 _hdmi.width = LCD_WIDTH;
299 _hdmi.height = LCD_HEIGHT;
300 _hdmi.depth = LCD_DEPTH;
301 _hdmi.pitch = 0;
302 _hdmi.pixel_format = RTGRAPHIC_PIXEL_FORMAT_RGB888;
303
304 // rt_hw_mmu_map(&mmu_info, (unsigned long)_hdmi.fb, (void *)0x200000, DEVICE_MEM);
305
306 rt_hw_cpu_dcache_invalidate((unsigned long)_hdmi.fb,LCD_WIDTH * LCD_HEIGHT * 3);
307
308 //rt_kprintf("_hdmi.fb is %p\n", _hdmi.fb);
309 rt_hdmi_fb_device_init(&_hdmi, "lcd");
310
311 return 0;
312 }
313
314 INIT_DEVICE_EXPORT(hdmi_fb_init);
315