91d078a9d5f38358b22bceb3c1bb4c11f8ae280e
[platform/kernel/u-boot.git] / drivers / video / video-uclass.c
1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3  * Copyright (c) 2015 Google, Inc
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_compat.h>
19 #include <dm/device-internal.h>
20 #include <dm/uclass-internal.h>
21 #ifdef CONFIG_SANDBOX
22 #include <asm/sdl.h>
23 #endif
24
25 /*
26  * Theory of operation:
27  *
28  * Before relocation each device is bound. The driver for each device must
29  * set the @align and @size values in struct video_uc_plat. This
30  * information represents the requires size and alignment of the frame buffer
31  * for the device. The values can be an over-estimate but cannot be too
32  * small. The actual values will be suppled (in the same manner) by the bind()
33  * method after relocation.
34  *
35  * This information is then picked up by video_reserve() which works out how
36  * much memory is needed for all devices. This is allocated between
37  * gd->video_bottom and gd->video_top.
38  *
39  * After relocation the same process occurs. The driver supplies the same
40  * @size and @align information and this time video_post_bind() checks that
41  * the drivers does not overflow the allocated memory.
42  *
43  * The frame buffer address is actually set (to plat->base) in
44  * video_post_probe(). This function also clears the frame buffer and
45  * allocates a suitable text console device. This can then be used to write
46  * text to the video device.
47  */
48 DECLARE_GLOBAL_DATA_PTR;
49
50 /**
51  * struct video_uc_priv - Information for the video uclass
52  *
53  * @video_ptr: Current allocation position of the video framebuffer pointer.
54  *      While binding devices after relocation, this points to the next
55  *      available address to use for a device's framebuffer. It starts at
56  *      gd->video_top and works downwards, running out of space when it hits
57  *      gd->video_bottom.
58  */
59 struct video_uc_priv {
60         ulong video_ptr;
61 };
62
63 void video_set_flush_dcache(struct udevice *dev, bool flush)
64 {
65         struct video_priv *priv = dev_get_uclass_priv(dev);
66
67         priv->flush_dcache = flush;
68 }
69
70 static ulong alloc_fb(struct udevice *dev, ulong *addrp)
71 {
72         struct video_uc_plat *plat = dev_get_uclass_plat(dev);
73         ulong base, align, size;
74
75         if (!plat->size)
76                 return 0;
77
78         align = plat->align ? plat->align : 1 << 20;
79         base = *addrp - plat->size;
80         base &= ~(align - 1);
81         plat->base = base;
82         size = *addrp - base;
83         *addrp = base;
84
85         return size;
86 }
87
88 int video_reserve(ulong *addrp)
89 {
90         struct udevice *dev;
91         ulong size;
92
93         gd->video_top = *addrp;
94         for (uclass_find_first_device(UCLASS_VIDEO, &dev);
95              dev;
96              uclass_find_next_device(&dev)) {
97                 size = alloc_fb(dev, addrp);
98                 debug("%s: Reserving %lx bytes at %lx for video device '%s'\n",
99                       __func__, size, *addrp, dev->name);
100         }
101
102         /* Allocate space for PCI video devices in case there were not bound */
103         if (*addrp == gd->video_top)
104                 *addrp -= CONFIG_VIDEO_PCI_DEFAULT_FB_SIZE;
105
106         gd->video_bottom = *addrp;
107         gd->fb_base = *addrp;
108         debug("Video frame buffers from %lx to %lx\n", gd->video_bottom,
109               gd->video_top);
110
111         return 0;
112 }
113
114 int video_clear(struct udevice *dev)
115 {
116         struct video_priv *priv = dev_get_uclass_priv(dev);
117         int ret;
118
119         switch (priv->bpix) {
120         case VIDEO_BPP16:
121                 if (IS_ENABLED(CONFIG_VIDEO_BPP16)) {
122                         u16 *ppix = priv->fb;
123                         u16 *end = priv->fb + priv->fb_size;
124
125                         while (ppix < end)
126                                 *ppix++ = priv->colour_bg;
127                         break;
128                 }
129         case VIDEO_BPP32:
130                 if (IS_ENABLED(CONFIG_VIDEO_BPP32)) {
131                         u32 *ppix = priv->fb;
132                         u32 *end = priv->fb + priv->fb_size;
133
134                         while (ppix < end)
135                                 *ppix++ = priv->colour_bg;
136                         break;
137                 }
138         default:
139                 memset(priv->fb, priv->colour_bg, priv->fb_size);
140                 break;
141         }
142         ret = video_sync_copy(dev, priv->fb, priv->fb + priv->fb_size);
143         if (ret)
144                 return ret;
145
146         return video_sync(dev, false);
147 }
148
149 void video_set_default_colors(struct udevice *dev, bool invert)
150 {
151         struct video_priv *priv = dev_get_uclass_priv(dev);
152         int fore, back;
153
154         if (CONFIG_IS_ENABLED(SYS_WHITE_ON_BLACK)) {
155                 /* White is used when switching to bold, use light gray here */
156                 fore = VID_LIGHT_GRAY;
157                 back = VID_BLACK;
158         } else {
159                 fore = VID_BLACK;
160                 back = VID_WHITE;
161         }
162         if (invert) {
163                 int temp;
164
165                 temp = fore;
166                 fore = back;
167                 back = temp;
168         }
169         priv->fg_col_idx = fore;
170         priv->bg_col_idx = back;
171         priv->colour_fg = vid_console_color(priv, fore);
172         priv->colour_bg = vid_console_color(priv, back);
173 }
174
175 /* Flush video activity to the caches */
176 int video_sync(struct udevice *vid, bool force)
177 {
178         struct video_ops *ops = video_get_ops(vid);
179         int ret;
180
181         if (ops && ops->video_sync) {
182                 ret = ops->video_sync(vid);
183                 if (ret)
184                         return ret;
185         }
186
187         /*
188          * flush_dcache_range() is declared in common.h but it seems that some
189          * architectures do not actually implement it. Is there a way to find
190          * out whether it exists? For now, ARM is safe.
191          */
192 #if defined(CONFIG_ARM) && !CONFIG_IS_ENABLED(SYS_DCACHE_OFF)
193         struct video_priv *priv = dev_get_uclass_priv(vid);
194
195         if (priv->flush_dcache) {
196                 flush_dcache_range((ulong)priv->fb,
197                                    ALIGN((ulong)priv->fb + priv->fb_size,
198                                          CONFIG_SYS_CACHELINE_SIZE));
199         }
200 #elif defined(CONFIG_VIDEO_SANDBOX_SDL)
201         struct video_priv *priv = dev_get_uclass_priv(vid);
202         static ulong last_sync;
203
204         if (force || get_timer(last_sync) > 10) {
205                 sandbox_sdl_sync(priv->fb);
206                 last_sync = get_timer(0);
207         }
208 #endif
209         return 0;
210 }
211
212 void video_sync_all(void)
213 {
214         struct udevice *dev;
215         int ret;
216
217         for (uclass_find_first_device(UCLASS_VIDEO, &dev);
218              dev;
219              uclass_find_next_device(&dev)) {
220                 if (device_active(dev)) {
221                         ret = video_sync(dev, true);
222                         if (ret)
223                                 dev_dbg(dev, "Video sync failed\n");
224                 }
225         }
226 }
227
228 int video_get_xsize(struct udevice *dev)
229 {
230         struct video_priv *priv = dev_get_uclass_priv(dev);
231
232         return priv->xsize;
233 }
234
235 int video_get_ysize(struct udevice *dev)
236 {
237         struct video_priv *priv = dev_get_uclass_priv(dev);
238
239         return priv->ysize;
240 }
241
242 #ifdef CONFIG_VIDEO_COPY
243 int video_sync_copy(struct udevice *dev, void *from, void *to)
244 {
245         struct video_priv *priv = dev_get_uclass_priv(dev);
246
247         if (priv->copy_fb) {
248                 long offset, size;
249
250                 /* Find the offset of the first byte to copy */
251                 if ((ulong)to > (ulong)from) {
252                         size = to - from;
253                         offset = from - priv->fb;
254                 } else {
255                         size = from - to;
256                         offset = to - priv->fb;
257                 }
258
259                 /*
260                  * Allow a bit of leeway for valid requests somewhere near the
261                  * frame buffer
262                  */
263                 if (offset < -priv->fb_size || offset > 2 * priv->fb_size) {
264 #ifdef DEBUG
265                         char str[80];
266
267                         snprintf(str, sizeof(str),
268                                  "[sync_copy fb=%p, from=%p, to=%p, offset=%lx]",
269                                  priv->fb, from, to, offset);
270                         console_puts_select_stderr(true, str);
271 #endif
272                         return -EFAULT;
273                 }
274
275                 /*
276                  * Silently crop the memcpy. This allows callers to avoid doing
277                  * this themselves. It is common for the end pointer to go a
278                  * few lines after the end of the frame buffer, since most of
279                  * the update algorithms terminate a line after their last write
280                  */
281                 if (offset + size > priv->fb_size) {
282                         size = priv->fb_size - offset;
283                 } else if (offset < 0) {
284                         size += offset;
285                         offset = 0;
286                 }
287
288                 memcpy(priv->copy_fb + offset, priv->fb + offset, size);
289         }
290
291         return 0;
292 }
293
294 int video_sync_copy_all(struct udevice *dev)
295 {
296         struct video_priv *priv = dev_get_uclass_priv(dev);
297
298         video_sync_copy(dev, priv->fb, priv->fb + priv->fb_size);
299
300         return 0;
301 }
302
303 #endif
304
305 /* Set up the colour map */
306 static int video_pre_probe(struct udevice *dev)
307 {
308         struct video_priv *priv = dev_get_uclass_priv(dev);
309
310         priv->cmap = calloc(256, sizeof(ushort));
311         if (!priv->cmap)
312                 return -ENOMEM;
313
314         return 0;
315 }
316
317 static int video_pre_remove(struct udevice *dev)
318 {
319         struct video_priv *priv = dev_get_uclass_priv(dev);
320
321         free(priv->cmap);
322
323         return 0;
324 }
325
326 /* Set up the display ready for use */
327 static int video_post_probe(struct udevice *dev)
328 {
329         struct video_uc_plat *plat = dev_get_uclass_plat(dev);
330         struct video_priv *priv = dev_get_uclass_priv(dev);
331         char name[30], drv[15], *str;
332         const char *drv_name = drv;
333         struct udevice *cons;
334         int ret;
335
336         /* Set up the line and display size */
337         priv->fb = map_sysmem(plat->base, plat->size);
338         if (!priv->line_length)
339                 priv->line_length = priv->xsize * VNBYTES(priv->bpix);
340
341         priv->fb_size = priv->line_length * priv->ysize;
342
343         if (IS_ENABLED(CONFIG_VIDEO_COPY) && plat->copy_base)
344                 priv->copy_fb = map_sysmem(plat->copy_base, plat->size);
345
346         /* Set up colors  */
347         video_set_default_colors(dev, false);
348
349         if (!CONFIG_IS_ENABLED(NO_FB_CLEAR))
350                 video_clear(dev);
351
352         /*
353          * Create a text console device. For now we always do this, although
354          * it might be useful to support only bitmap drawing on the device
355          * for boards that don't need to display text. We create a TrueType
356          * console if enabled, a rotated console if the video driver requests
357          * it, otherwise a normal console.
358          *
359          * The console can be override by setting vidconsole_drv_name before
360          * probing this video driver, or in the probe() method.
361          *
362          * TrueType does not support rotation at present so fall back to the
363          * rotated console in that case.
364          */
365         if (!priv->rot && IS_ENABLED(CONFIG_CONSOLE_TRUETYPE)) {
366                 snprintf(name, sizeof(name), "%s.vidconsole_tt", dev->name);
367                 strcpy(drv, "vidconsole_tt");
368         } else {
369                 snprintf(name, sizeof(name), "%s.vidconsole%d", dev->name,
370                          priv->rot);
371                 snprintf(drv, sizeof(drv), "vidconsole%d", priv->rot);
372         }
373
374         str = strdup(name);
375         if (!str)
376                 return -ENOMEM;
377         if (priv->vidconsole_drv_name)
378                 drv_name = priv->vidconsole_drv_name;
379         ret = device_bind_driver(dev, drv_name, str, &cons);
380         if (ret) {
381                 debug("%s: Cannot bind console driver\n", __func__);
382                 return ret;
383         }
384
385         ret = device_probe(cons);
386         if (ret) {
387                 debug("%s: Cannot probe console driver\n", __func__);
388                 return ret;
389         }
390
391         return 0;
392 };
393
394 /* Post-relocation, allocate memory for the frame buffer */
395 static int video_post_bind(struct udevice *dev)
396 {
397         struct video_uc_priv *uc_priv;
398         ulong addr;
399         ulong size;
400
401         /* Before relocation there is nothing to do here */
402         if (!(gd->flags & GD_FLG_RELOC))
403                 return 0;
404
405         /* Set up the video pointer, if this is the first device */
406         uc_priv = uclass_get_priv(dev->uclass);
407         if (!uc_priv->video_ptr)
408                 uc_priv->video_ptr = gd->video_top;
409
410         /* Allocate framebuffer space for this device */
411         addr = uc_priv->video_ptr;
412         size = alloc_fb(dev, &addr);
413         if (addr < gd->video_bottom) {
414                 /* Device tree node may need the 'u-boot,dm-pre-reloc' or
415                  * 'u-boot,dm-pre-proper' tag
416                  */
417                 printf("Video device '%s' cannot allocate frame buffer memory -ensure the device is set up before relocation\n",
418                        dev->name);
419                 return -ENOSPC;
420         }
421         debug("%s: Claiming %lx bytes at %lx for video device '%s'\n",
422               __func__, size, addr, dev->name);
423         uc_priv->video_ptr = addr;
424
425         return 0;
426 }
427
428 UCLASS_DRIVER(video) = {
429         .id             = UCLASS_VIDEO,
430         .name           = "video",
431         .flags          = DM_UC_FLAG_SEQ_ALIAS,
432         .post_bind      = video_post_bind,
433         .pre_probe      = video_pre_probe,
434         .post_probe     = video_post_probe,
435         .pre_remove     = video_pre_remove,
436         .priv_auto      = sizeof(struct video_uc_priv),
437         .per_device_auto        = sizeof(struct video_priv),
438         .per_device_plat_auto   = sizeof(struct video_uc_plat),
439 };