1 // SPDX-License-Identifier: GPL-2.0
3 * Procedures for drawing on the screen early on in the boot process.
5 * Benjamin Herrenschmidt <benh@kernel.crashing.org>
7 #include <linux/kernel.h>
8 #include <linux/string.h>
9 #include <linux/init.h>
10 #include <linux/export.h>
11 #include <linux/font.h>
12 #include <linux/memblock.h>
13 #include <linux/pgtable.h>
16 #include <asm/sections.h>
17 #include <asm/btext.h>
21 #include <asm/processor.h>
27 static void scrollscreen(void);
30 #define __force_data __section(".data")
32 static int g_loc_X __force_data;
33 static int g_loc_Y __force_data;
34 static int g_max_loc_X __force_data;
35 static int g_max_loc_Y __force_data;
37 static int dispDeviceRowBytes __force_data;
38 static int dispDeviceDepth __force_data;
39 static int dispDeviceRect[4] __force_data;
40 static unsigned char *dispDeviceBase __force_data;
41 static unsigned char *logicalDisplayBase __force_data;
43 unsigned long disp_BAT[2] __initdata = {0, 0};
45 static int boot_text_mapped __force_data;
47 extern void rmci_on(void);
48 extern void rmci_off(void);
50 static inline void rmci_maybe_on(void)
52 #if defined(CONFIG_PPC_EARLY_DEBUG_BOOTX) && defined(CONFIG_PPC64)
53 if (!(mfmsr() & MSR_DR))
58 static inline void rmci_maybe_off(void)
60 #if defined(CONFIG_PPC_EARLY_DEBUG_BOOTX) && defined(CONFIG_PPC64)
61 if (!(mfmsr() & MSR_DR))
68 /* Calc BAT values for mapping the display and store them
69 * in disp_BAT. Those values are then used from head.S to map
70 * the display during identify_machine() and MMU_Init()
72 * The display is mapped to virtual address 0xD0000000, rather
73 * than 1:1, because some CHRP machines put the frame buffer
74 * in the region starting at 0xC0000000 (PAGE_OFFSET).
75 * This mapping is temporary and will disappear as soon as the
76 * setup done by MMU_Init() is applied.
78 * For now, we align the BAT and then map 8Mb on 601 and 16Mb
79 * on other PPCs. This may cause trouble if the framebuffer
80 * is really badly aligned, but I didn't encounter this case
83 void __init btext_prepare_BAT(void)
85 unsigned long vaddr = PAGE_OFFSET + 0x10000000;
87 unsigned long lowbits;
89 addr = (unsigned long)dispDeviceBase;
94 lowbits = addr & ~0xFF000000UL;
96 disp_BAT[0] = vaddr | (BL_16M<<2) | 2;
97 disp_BAT[1] = addr | (_PAGE_NO_CACHE | _PAGE_GUARDED | BPP_RW);
98 logicalDisplayBase = (void *) (vaddr + lowbits);
103 /* This function can be used to enable the early boot text when doing
104 * OF booting or within bootx init. It must be followed by a btext_unmap()
105 * call before the logical address becomes unusable
107 void __init btext_setup_display(int width, int height, int depth, int pitch,
108 unsigned long address)
112 g_max_loc_X = width / 8;
113 g_max_loc_Y = height / 16;
114 logicalDisplayBase = (unsigned char *)address;
115 dispDeviceBase = (unsigned char *)address;
116 dispDeviceRowBytes = pitch;
117 dispDeviceDepth = depth == 15 ? 16 : depth;
118 dispDeviceRect[0] = dispDeviceRect[1] = 0;
119 dispDeviceRect[2] = width;
120 dispDeviceRect[3] = height;
121 boot_text_mapped = 1;
124 void __init btext_unmap(void)
126 boot_text_mapped = 0;
129 /* Here's a small text engine to use during early boot
130 * or for debugging purposes
134 * - build some kind of vgacon with it to enable early printk
135 * - move to a separate file
136 * - add a few video driver hooks to keep in sync with display
142 unsigned long base, offset, size;
143 unsigned char *vbase;
145 /* By default, we are no longer mapped */
146 boot_text_mapped = 0;
149 base = ((unsigned long) dispDeviceBase) & 0xFFFFF000UL;
150 offset = ((unsigned long) dispDeviceBase) - base;
151 size = dispDeviceRowBytes * dispDeviceRect[3] + offset
153 vbase = ioremap_wc(base, size);
156 logicalDisplayBase = vbase + offset;
157 boot_text_mapped = 1;
160 static int __init btext_initialize(struct device_node *np)
162 unsigned int width, height, depth, pitch;
163 unsigned long address = 0;
166 prop = of_get_property(np, "linux,bootx-width", NULL);
168 prop = of_get_property(np, "width", NULL);
172 prop = of_get_property(np, "linux,bootx-height", NULL);
174 prop = of_get_property(np, "height", NULL);
178 prop = of_get_property(np, "linux,bootx-depth", NULL);
180 prop = of_get_property(np, "depth", NULL);
184 pitch = width * ((depth + 7) / 8);
185 prop = of_get_property(np, "linux,bootx-linebytes", NULL);
187 prop = of_get_property(np, "linebytes", NULL);
188 if (prop && *prop != 0xffffffffu)
192 prop = of_get_property(np, "linux,bootx-addr", NULL);
194 prop = of_get_property(np, "address", NULL);
198 /* FIXME: Add support for PCI reg properties. Right now, only
206 g_max_loc_X = width / 8;
207 g_max_loc_Y = height / 16;
208 dispDeviceBase = (unsigned char *)address;
209 dispDeviceRowBytes = pitch;
210 dispDeviceDepth = depth == 15 ? 16 : depth;
211 dispDeviceRect[0] = dispDeviceRect[1] = 0;
212 dispDeviceRect[2] = width;
213 dispDeviceRect[3] = height;
220 int __init btext_find_display(int allow_nonstdout)
222 struct device_node *np = of_stdout;
225 if (!of_node_is_type(np, "display")) {
226 printk("boot stdout isn't a display !\n");
230 rc = btext_initialize(np);
231 if (rc == 0 || !allow_nonstdout)
234 for_each_node_by_type(np, "display") {
235 if (of_property_read_bool(np, "linux,opened")) {
236 printk("trying %pOF ...\n", np);
237 rc = btext_initialize(np);
238 printk("result: %d\n", rc);
248 /* Calc the base address of a given point (x,y) */
249 static unsigned char * calc_base(int x, int y)
253 base = logicalDisplayBase;
255 base = dispDeviceBase;
256 base += (x + dispDeviceRect[0]) * (dispDeviceDepth >> 3);
257 base += (y + dispDeviceRect[1]) * dispDeviceRowBytes;
261 /* Adjust the display to a new resolution */
262 void btext_update_display(unsigned long phys, int width, int height,
263 int depth, int pitch)
268 /* check it's the same frame buffer (within 256MB) */
269 if ((phys ^ (unsigned long)dispDeviceBase) & 0xf0000000)
272 dispDeviceBase = (__u8 *) phys;
273 dispDeviceRect[0] = 0;
274 dispDeviceRect[1] = 0;
275 dispDeviceRect[2] = width;
276 dispDeviceRect[3] = height;
277 dispDeviceDepth = depth;
278 dispDeviceRowBytes = pitch;
279 if (boot_text_mapped) {
280 iounmap(logicalDisplayBase);
281 boot_text_mapped = 0;
286 g_max_loc_X = width / 8;
287 g_max_loc_Y = height / 16;
289 EXPORT_SYMBOL(btext_update_display);
291 void __init btext_clearscreen(void)
293 unsigned int *base = (unsigned int *)calc_base(0, 0);
294 unsigned long width = ((dispDeviceRect[2] - dispDeviceRect[0]) *
295 (dispDeviceDepth >> 3)) >> 2;
299 for (i=0; i<(dispDeviceRect[3] - dispDeviceRect[1]); i++)
301 unsigned int *ptr = base;
304 base += (dispDeviceRowBytes >> 2);
309 void __init btext_flushscreen(void)
311 unsigned int *base = (unsigned int *)calc_base(0, 0);
312 unsigned long width = ((dispDeviceRect[2] - dispDeviceRect[0]) *
313 (dispDeviceDepth >> 3)) >> 2;
316 for (i=0; i < (dispDeviceRect[3] - dispDeviceRect[1]); i++)
318 unsigned int *ptr = base;
319 for(j = width; j > 0; j -= 8) {
320 __asm__ __volatile__ ("dcbst 0,%0" :: "r" (ptr));
323 base += (dispDeviceRowBytes >> 2);
325 __asm__ __volatile__ ("sync" ::: "memory");
328 void __init btext_flushline(void)
330 unsigned int *base = (unsigned int *)calc_base(0, g_loc_Y << 4);
331 unsigned long width = ((dispDeviceRect[2] - dispDeviceRect[0]) *
332 (dispDeviceDepth >> 3)) >> 2;
335 for (i=0; i < 16; i++)
337 unsigned int *ptr = base;
338 for(j = width; j > 0; j -= 8) {
339 __asm__ __volatile__ ("dcbst 0,%0" :: "r" (ptr));
342 base += (dispDeviceRowBytes >> 2);
344 __asm__ __volatile__ ("sync" ::: "memory");
349 static void scrollscreen(void)
351 unsigned int *src = (unsigned int *)calc_base(0,16);
352 unsigned int *dst = (unsigned int *)calc_base(0,0);
353 unsigned long width = ((dispDeviceRect[2] - dispDeviceRect[0]) *
354 (dispDeviceDepth >> 3)) >> 2;
359 for (i=0; i<(dispDeviceRect[3] - dispDeviceRect[1] - 16); i++)
361 unsigned int *src_ptr = src;
362 unsigned int *dst_ptr = dst;
364 *(dst_ptr++) = *(src_ptr++);
365 src += (dispDeviceRowBytes >> 2);
366 dst += (dispDeviceRowBytes >> 2);
370 unsigned int *dst_ptr = dst;
373 dst += (dispDeviceRowBytes >> 2);
378 #endif /* ndef NO_SCROLL */
380 static unsigned int expand_bits_8[16] = {
399 static unsigned int expand_bits_16[4] = {
407 static void draw_byte_32(const unsigned char *font, unsigned int *base, int rb)
410 int fg = 0xFFFFFFFFUL;
411 int bg = 0x00000000UL;
413 for (l = 0; l < 16; ++l)
416 base[0] = (-(bits >> 7) & fg) ^ bg;
417 base[1] = (-((bits >> 6) & 1) & fg) ^ bg;
418 base[2] = (-((bits >> 5) & 1) & fg) ^ bg;
419 base[3] = (-((bits >> 4) & 1) & fg) ^ bg;
420 base[4] = (-((bits >> 3) & 1) & fg) ^ bg;
421 base[5] = (-((bits >> 2) & 1) & fg) ^ bg;
422 base[6] = (-((bits >> 1) & 1) & fg) ^ bg;
423 base[7] = (-(bits & 1) & fg) ^ bg;
424 base = (unsigned int *) ((char *)base + rb);
428 static inline void draw_byte_16(const unsigned char *font, unsigned int *base, int rb)
431 int fg = 0xFFFFFFFFUL;
432 int bg = 0x00000000UL;
433 unsigned int *eb = (int *)expand_bits_16;
435 for (l = 0; l < 16; ++l)
438 base[0] = (eb[bits >> 6] & fg) ^ bg;
439 base[1] = (eb[(bits >> 4) & 3] & fg) ^ bg;
440 base[2] = (eb[(bits >> 2) & 3] & fg) ^ bg;
441 base[3] = (eb[bits & 3] & fg) ^ bg;
442 base = (unsigned int *) ((char *)base + rb);
446 static inline void draw_byte_8(const unsigned char *font, unsigned int *base, int rb)
449 int fg = 0x0F0F0F0FUL;
450 int bg = 0x00000000UL;
451 unsigned int *eb = (int *)expand_bits_8;
453 for (l = 0; l < 16; ++l)
456 base[0] = (eb[bits >> 4] & fg) ^ bg;
457 base[1] = (eb[bits & 0xf] & fg) ^ bg;
458 base = (unsigned int *) ((char *)base + rb);
462 static noinline void draw_byte(unsigned char c, long locX, long locY)
464 unsigned char *base = calc_base(locX << 3, locY << 4);
465 unsigned int font_index = c * 16;
466 const unsigned char *font = font_sun_8x16.data + font_index;
467 int rb = dispDeviceRowBytes;
470 switch(dispDeviceDepth) {
473 draw_byte_32(font, (unsigned int *)base, rb);
477 draw_byte_16(font, (unsigned int *)base, rb);
480 draw_byte_8(font, (unsigned int *)base, rb);
486 void btext_drawchar(char c)
492 if (!boot_text_mapped)
501 g_loc_X = (g_loc_X & -8) + 8;
512 draw_byte(c, g_loc_X++, g_loc_Y);
514 if (g_loc_X >= g_max_loc_X) {
520 while (g_loc_Y >= g_max_loc_Y) {
525 /* wrap around from bottom to top of screen so we don't
526 waste time scrolling each line. -- paulus. */
527 if (g_loc_Y >= g_max_loc_Y)
530 for (x = 0; x < g_max_loc_X; ++x)
531 draw_byte(' ', x, g_loc_Y);
536 void btext_drawstring(const char *c)
538 if (!boot_text_mapped)
541 btext_drawchar(*c++);
544 void __init btext_drawtext(const char *c, unsigned int len)
546 if (!boot_text_mapped)
549 btext_drawchar(*c++);
552 void __init btext_drawhex(unsigned long v)
554 if (!boot_text_mapped)
557 btext_drawchar(hex_asc_hi(v >> 56));
558 btext_drawchar(hex_asc_lo(v >> 56));
559 btext_drawchar(hex_asc_hi(v >> 48));
560 btext_drawchar(hex_asc_lo(v >> 48));
561 btext_drawchar(hex_asc_hi(v >> 40));
562 btext_drawchar(hex_asc_lo(v >> 40));
563 btext_drawchar(hex_asc_hi(v >> 32));
564 btext_drawchar(hex_asc_lo(v >> 32));
566 btext_drawchar(hex_asc_hi(v >> 24));
567 btext_drawchar(hex_asc_lo(v >> 24));
568 btext_drawchar(hex_asc_hi(v >> 16));
569 btext_drawchar(hex_asc_lo(v >> 16));
570 btext_drawchar(hex_asc_hi(v >> 8));
571 btext_drawchar(hex_asc_lo(v >> 8));
572 btext_drawchar(hex_asc_hi(v));
573 btext_drawchar(hex_asc_lo(v));
577 void __init udbg_init_btext(void)
579 /* If btext is enabled, we might have a BAT setup for early display,
580 * thus we do enable some very basic udbg output
582 udbg_putc = btext_drawchar;