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