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