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