2 * Copyright (C) 2013 Intel Corporation; author Matt Fleming
4 * This file is part of the Linux kernel, and is made available under
5 * the terms of the GNU General Public License version 2.
8 #include <linux/console.h>
10 #include <linux/font.h>
12 #include <linux/kernel.h>
13 #include <asm/setup.h>
15 static const struct font_desc
*font
;
16 static u32 efi_x
, efi_y
;
18 static bool early_efi_keep
;
21 * efi earlyprintk need use early_ioremap to map the framebuffer.
22 * But early_ioremap is not usable for earlyprintk=efi,keep, ioremap should
23 * be used instead. ioremap will be available after paging_init() which is
24 * earlier than initcall callbacks. Thus adding this early initcall function
25 * early_efi_map_fb to map the whole efi framebuffer.
27 static __init
int early_efi_map_fb(void)
34 base
= boot_params
.screen_info
.lfb_base
;
35 if (boot_params
.screen_info
.capabilities
& VIDEO_CAPABILITY_64BIT_BASE
)
36 base
|= (u64
)boot_params
.screen_info
.ext_lfb_base
<< 32;
37 size
= boot_params
.screen_info
.lfb_size
;
38 efi_fb
= ioremap(base
, size
);
40 return efi_fb
? 0 : -ENOMEM
;
42 early_initcall(early_efi_map_fb
);
45 * early_efi_map maps efi framebuffer region [start, start + len -1]
46 * In case earlyprintk=efi,keep we have the whole framebuffer mapped already
47 * so just return the offset efi_fb + start.
49 static __ref
void *early_efi_map(unsigned long start
, unsigned long len
)
53 base
= boot_params
.screen_info
.lfb_base
;
54 if (boot_params
.screen_info
.capabilities
& VIDEO_CAPABILITY_64BIT_BASE
)
55 base
|= (u64
)boot_params
.screen_info
.ext_lfb_base
<< 32;
58 return (efi_fb
+ start
);
60 return early_ioremap(base
+ start
, len
);
63 static __ref
void early_efi_unmap(void *addr
, unsigned long len
)
66 early_iounmap(addr
, len
);
69 static void early_efi_clear_scanline(unsigned int y
)
74 len
= boot_params
.screen_info
.lfb_linelength
;
75 dst
= early_efi_map(y
*len
, len
);
80 early_efi_unmap(dst
, len
);
83 static void early_efi_scroll_up(void)
85 unsigned long *dst
, *src
;
89 len
= boot_params
.screen_info
.lfb_linelength
;
90 height
= boot_params
.screen_info
.lfb_height
;
92 for (i
= 0; i
< height
- font
->height
; i
++) {
93 dst
= early_efi_map(i
*len
, len
);
97 src
= early_efi_map((i
+ font
->height
) * len
, len
);
99 early_efi_unmap(dst
, len
);
103 memmove(dst
, src
, len
);
105 early_efi_unmap(src
, len
);
106 early_efi_unmap(dst
, len
);
110 static void early_efi_write_char(u32
*dst
, unsigned char c
, unsigned int h
)
112 const u32 color_black
= 0x00000000;
113 const u32 color_white
= 0x00ffffff;
118 src
= font
->data
+ c
* font
->height
;
121 for (m
= 0; m
< 8; m
++) {
122 if ((s8
>> (7 - m
)) & 1)
131 early_efi_write(struct console
*con
, const char *str
, unsigned int num
)
133 struct screen_info
*si
;
138 si
= &boot_params
.screen_info
;
139 len
= si
->lfb_linelength
;
142 unsigned int linemax
;
143 unsigned int h
, count
= 0;
145 for (s
= str
; *s
&& *s
!= '\n'; s
++) {
151 linemax
= (si
->lfb_width
- efi_x
) / font
->width
;
155 for (h
= 0; h
< font
->height
; h
++) {
158 dst
= early_efi_map((efi_y
+ h
) * len
, len
);
167 early_efi_write_char(dst
+ x
*4, *s
, h
);
172 early_efi_unmap(dst
, len
);
176 efi_x
+= count
* font
->width
;
179 if (num
> 0 && *s
== '\n') {
181 efi_y
+= font
->height
;
186 if (efi_x
>= si
->lfb_width
) {
188 efi_y
+= font
->height
;
191 if (efi_y
+ font
->height
> si
->lfb_height
) {
194 efi_y
-= font
->height
;
195 early_efi_scroll_up();
197 for (i
= 0; i
< font
->height
; i
++)
198 early_efi_clear_scanline(efi_y
+ i
);
203 static __init
int early_efi_setup(struct console
*con
, char *options
)
205 struct screen_info
*si
;
209 si
= &boot_params
.screen_info
;
210 xres
= si
->lfb_width
;
211 yres
= si
->lfb_height
;
214 * early_efi_write_char() implicitly assumes a framebuffer with
217 if (si
->lfb_depth
!= 32)
220 font
= get_default_font(xres
, yres
, -1, -1);
224 efi_y
= rounddown(yres
, font
->height
) - font
->height
;
225 for (i
= 0; i
< (yres
- efi_y
) / font
->height
; i
++)
226 early_efi_scroll_up();
228 /* early_console_register will unset CON_BOOT in case ,keep */
229 if (!(con
->flags
& CON_BOOT
))
230 early_efi_keep
= true;
234 struct console early_efi_console
= {
236 .write
= early_efi_write
,
237 .setup
= early_efi_setup
,
238 .flags
= CON_PRINTBUFFER
,