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
;