1
2
3
4
5
6#include <common.h>
7#include <console.h>
8#include <cpu_func.h>
9#include <dm.h>
10#include <log.h>
11#include <malloc.h>
12#include <mapmem.h>
13#include <stdio_dev.h>
14#include <video.h>
15#include <video_console.h>
16#include <asm/cache.h>
17#include <dm/lists.h>
18#include <dm/device-internal.h>
19#include <dm/uclass-internal.h>
20#ifdef CONFIG_SANDBOX
21#include <asm/sdl.h>
22#endif
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47DECLARE_GLOBAL_DATA_PTR;
48
49
50
51
52
53
54
55
56
57
58struct video_uc_priv {
59 ulong video_ptr;
60};
61
62void video_set_flush_dcache(struct udevice *dev, bool flush)
63{
64 struct video_priv *priv = dev_get_uclass_priv(dev);
65
66 priv->flush_dcache = flush;
67}
68
69static ulong alloc_fb(struct udevice *dev, ulong *addrp)
70{
71 struct video_uc_platdata *plat = dev_get_uclass_platdata(dev);
72 ulong base, align, size;
73
74 if (!plat->size)
75 return 0;
76
77 align = plat->align ? plat->align : 1 << 20;
78 base = *addrp - plat->size;
79 base &= ~(align - 1);
80 plat->base = base;
81 size = *addrp - base;
82 *addrp = base;
83
84 return size;
85}
86
87int video_reserve(ulong *addrp)
88{
89 struct udevice *dev;
90 ulong size;
91
92 gd->video_top = *addrp;
93 for (uclass_find_first_device(UCLASS_VIDEO, &dev);
94 dev;
95 uclass_find_next_device(&dev)) {
96 size = alloc_fb(dev, addrp);
97 debug("%s: Reserving %lx bytes at %lx for video device '%s'\n",
98 __func__, size, *addrp, dev->name);
99 }
100
101
102 if (*addrp == gd->video_top)
103 *addrp -= CONFIG_VIDEO_PCI_DEFAULT_FB_SIZE;
104
105 gd->video_bottom = *addrp;
106 gd->fb_base = *addrp;
107 debug("Video frame buffers from %lx to %lx\n", gd->video_bottom,
108 gd->video_top);
109
110 return 0;
111}
112
113int video_clear(struct udevice *dev)
114{
115 struct video_priv *priv = dev_get_uclass_priv(dev);
116 int ret;
117
118 switch (priv->bpix) {
119 case VIDEO_BPP16:
120 if (IS_ENABLED(CONFIG_VIDEO_BPP16)) {
121 u16 *ppix = priv->fb;
122 u16 *end = priv->fb + priv->fb_size;
123
124 while (ppix < end)
125 *ppix++ = priv->colour_bg;
126 break;
127 }
128 case VIDEO_BPP32:
129 if (IS_ENABLED(CONFIG_VIDEO_BPP32)) {
130 u32 *ppix = priv->fb;
131 u32 *end = priv->fb + priv->fb_size;
132
133 while (ppix < end)
134 *ppix++ = priv->colour_bg;
135 break;
136 }
137 default:
138 memset(priv->fb, priv->colour_bg, priv->fb_size);
139 break;
140 }
141 ret = video_sync_copy(dev, priv->fb, priv->fb + priv->fb_size);
142 if (ret)
143 return ret;
144
145 return 0;
146}
147
148void video_set_default_colors(struct udevice *dev, bool invert)
149{
150 struct video_priv *priv = dev_get_uclass_priv(dev);
151 int fore, back;
152
153 if (CONFIG_IS_ENABLED(SYS_WHITE_ON_BLACK)) {
154
155 fore = VID_LIGHT_GRAY;
156 back = VID_BLACK;
157 } else {
158 fore = VID_BLACK;
159 back = VID_WHITE;
160 }
161 if (invert) {
162 int temp;
163
164 temp = fore;
165 fore = back;
166 back = temp;
167 }
168 priv->fg_col_idx = fore;
169 priv->bg_col_idx = back;
170 priv->colour_fg = vid_console_color(priv, fore);
171 priv->colour_bg = vid_console_color(priv, back);
172}
173
174
175void video_sync(struct udevice *vid, bool force)
176{
177
178
179
180
181
182#if defined(CONFIG_ARM) && !CONFIG_IS_ENABLED(SYS_DCACHE_OFF)
183 struct video_priv *priv = dev_get_uclass_priv(vid);
184
185 if (priv->flush_dcache) {
186 flush_dcache_range((ulong)priv->fb,
187 ALIGN((ulong)priv->fb + priv->fb_size,
188 CONFIG_SYS_CACHELINE_SIZE));
189 }
190#elif defined(CONFIG_VIDEO_SANDBOX_SDL)
191 struct video_priv *priv = dev_get_uclass_priv(vid);
192 static ulong last_sync;
193
194 if (force || get_timer(last_sync) > 10) {
195 sandbox_sdl_sync(priv->fb);
196 last_sync = get_timer(0);
197 }
198#endif
199}
200
201void video_sync_all(void)
202{
203 struct udevice *dev;
204
205 for (uclass_find_first_device(UCLASS_VIDEO, &dev);
206 dev;
207 uclass_find_next_device(&dev)) {
208 if (device_active(dev))
209 video_sync(dev, true);
210 }
211}
212
213int video_get_xsize(struct udevice *dev)
214{
215 struct video_priv *priv = dev_get_uclass_priv(dev);
216
217 return priv->xsize;
218}
219
220int video_get_ysize(struct udevice *dev)
221{
222 struct video_priv *priv = dev_get_uclass_priv(dev);
223
224 return priv->ysize;
225}
226
227#ifdef CONFIG_VIDEO_COPY
228int video_sync_copy(struct udevice *dev, void *from, void *to)
229{
230 struct video_priv *priv = dev_get_uclass_priv(dev);
231
232 if (priv->copy_fb) {
233 long offset, size;
234
235
236 if ((ulong)to > (ulong)from) {
237 size = to - from;
238 offset = from - priv->fb;
239 } else {
240 size = from - to;
241 offset = to - priv->fb;
242 }
243
244
245
246
247
248 if (offset < -priv->fb_size || offset > 2 * priv->fb_size) {
249#ifdef DEBUG
250 char str[80];
251
252 snprintf(str, sizeof(str),
253 "[sync_copy fb=%p, from=%p, to=%p, offset=%lx]",
254 priv->fb, from, to, offset);
255 console_puts_select_stderr(true, str);
256#endif
257 return -EFAULT;
258 }
259
260
261
262
263
264
265
266 if (offset + size > priv->fb_size) {
267 size = priv->fb_size - offset;
268 } else if (offset < 0) {
269 size += offset;
270 offset = 0;
271 }
272
273 memcpy(priv->copy_fb + offset, priv->fb + offset, size);
274 }
275
276 return 0;
277}
278#endif
279
280
281static int video_pre_probe(struct udevice *dev)
282{
283 struct video_priv *priv = dev_get_uclass_priv(dev);
284
285 priv->cmap = calloc(256, sizeof(ushort));
286 if (!priv->cmap)
287 return -ENOMEM;
288
289 return 0;
290}
291
292static int video_pre_remove(struct udevice *dev)
293{
294 struct video_priv *priv = dev_get_uclass_priv(dev);
295
296 free(priv->cmap);
297
298 return 0;
299}
300
301
302static int video_post_probe(struct udevice *dev)
303{
304 struct video_uc_platdata *plat = dev_get_uclass_platdata(dev);
305 struct video_priv *priv = dev_get_uclass_priv(dev);
306 char name[30], drv[15], *str;
307 const char *drv_name = drv;
308 struct udevice *cons;
309 int ret;
310
311
312 priv->fb = map_sysmem(plat->base, plat->size);
313 if (!priv->line_length)
314 priv->line_length = priv->xsize * VNBYTES(priv->bpix);
315
316 priv->fb_size = priv->line_length * priv->ysize;
317
318 if (IS_ENABLED(CONFIG_VIDEO_COPY) && plat->copy_base)
319 priv->copy_fb = map_sysmem(plat->copy_base, plat->size);
320
321
322 video_set_default_colors(dev, false);
323
324 if (!CONFIG_IS_ENABLED(NO_FB_CLEAR))
325 video_clear(dev);
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340 if (!priv->rot && IS_ENABLED(CONFIG_CONSOLE_TRUETYPE)) {
341 snprintf(name, sizeof(name), "%s.vidconsole_tt", dev->name);
342 strcpy(drv, "vidconsole_tt");
343 } else {
344 snprintf(name, sizeof(name), "%s.vidconsole%d", dev->name,
345 priv->rot);
346 snprintf(drv, sizeof(drv), "vidconsole%d", priv->rot);
347 }
348
349 str = strdup(name);
350 if (!str)
351 return -ENOMEM;
352 if (priv->vidconsole_drv_name)
353 drv_name = priv->vidconsole_drv_name;
354 ret = device_bind_driver(dev, drv_name, str, &cons);
355 if (ret) {
356 debug("%s: Cannot bind console driver\n", __func__);
357 return ret;
358 }
359
360 ret = device_probe(cons);
361 if (ret) {
362 debug("%s: Cannot probe console driver\n", __func__);
363 return ret;
364 }
365
366 return 0;
367};
368
369
370static int video_post_bind(struct udevice *dev)
371{
372 struct video_uc_priv *uc_priv;
373 ulong addr;
374 ulong size;
375
376
377 if (!(gd->flags & GD_FLG_RELOC))
378 return 0;
379
380
381 uc_priv = dev->uclass->priv;
382 if (!uc_priv->video_ptr)
383 uc_priv->video_ptr = gd->video_top;
384
385
386 addr = uc_priv->video_ptr;
387 size = alloc_fb(dev, &addr);
388 if (addr < gd->video_bottom) {
389
390
391
392 printf("Video device '%s' cannot allocate frame buffer memory -ensure the device is set up before relocation\n",
393 dev->name);
394 return -ENOSPC;
395 }
396 debug("%s: Claiming %lx bytes at %lx for video device '%s'\n",
397 __func__, size, addr, dev->name);
398 uc_priv->video_ptr = addr;
399
400 return 0;
401}
402
403UCLASS_DRIVER(video) = {
404 .id = UCLASS_VIDEO,
405 .name = "video",
406 .flags = DM_UC_FLAG_SEQ_ALIAS,
407 .post_bind = video_post_bind,
408 .pre_probe = video_pre_probe,
409 .post_probe = video_post_probe,
410 .pre_remove = video_pre_remove,
411 .priv_auto_alloc_size = sizeof(struct video_uc_priv),
412 .per_device_auto_alloc_size = sizeof(struct video_priv),
413 .per_device_platdata_auto_alloc_size = sizeof(struct video_uc_platdata),
414};
415