1 // SPDX-License-Identifier: GPL-2.0 2 /* 3 * Procedures for drawing on the screen early on in the boot process. 4 * 5 * Benjamin Herrenschmidt <benh@kernel.crashing.org> 6 */ 7 #include <linux/kernel.h> 8 #include <linux/string.h> 9 #include <linux/hex.h> 10 #include <linux/init.h> 11 #include <linux/export.h> 12 #include <linux/font.h> 13 #include <linux/memblock.h> 14 #include <linux/pgtable.h> 15 #include <linux/of.h> 16 17 #include <asm/sections.h> 18 #include <asm/btext.h> 19 #include <asm/page.h> 20 #include <asm/mmu.h> 21 #include <asm/io.h> 22 #include <asm/processor.h> 23 #include <asm/udbg.h> 24 #include <asm/setup.h> 25 26 #define NO_SCROLL 27 28 #ifndef NO_SCROLL 29 static void scrollscreen(void); 30 #endif 31 32 #define __force_data __section(".data") 33 34 static int g_loc_X __force_data; 35 static int g_loc_Y __force_data; 36 static int g_max_loc_X __force_data; 37 static int g_max_loc_Y __force_data; 38 39 static int dispDeviceRowBytes __force_data; 40 static int dispDeviceDepth __force_data; 41 static int dispDeviceRect[4] __force_data; 42 static unsigned char *dispDeviceBase __force_data; 43 static unsigned char *logicalDisplayBase __force_data; 44 45 unsigned long disp_BAT[2] __initdata = {0, 0}; 46 47 static int boot_text_mapped __force_data; 48 49 extern void rmci_on(void); 50 extern void rmci_off(void); 51 52 static inline void rmci_maybe_on(void) 53 { 54 #if defined(CONFIG_PPC_EARLY_DEBUG_BOOTX) && defined(CONFIG_PPC64) 55 if (!(mfmsr() & MSR_DR)) 56 rmci_on(); 57 #endif 58 } 59 60 static inline void rmci_maybe_off(void) 61 { 62 #if defined(CONFIG_PPC_EARLY_DEBUG_BOOTX) && defined(CONFIG_PPC64) 63 if (!(mfmsr() & MSR_DR)) 64 rmci_off(); 65 #endif 66 } 67 68 69 #ifdef CONFIG_PPC32 70 /* Calc BAT values for mapping the display and store them 71 * in disp_BAT. Those values are then used from head.S to map 72 * the display during identify_machine() and MMU_Init() 73 * 74 * The display is mapped to virtual address 0xD0000000, rather 75 * than 1:1, because some CHRP machines put the frame buffer 76 * in the region starting at 0xC0000000 (PAGE_OFFSET). 77 * This mapping is temporary and will disappear as soon as the 78 * setup done by MMU_Init() is applied. 79 * 80 * For now, we align the BAT and then map 8Mb on 601 and 16Mb 81 * on other PPCs. This may cause trouble if the framebuffer 82 * is really badly aligned, but I didn't encounter this case 83 * yet. 84 */ 85 void __init btext_prepare_BAT(void) 86 { 87 unsigned long vaddr = PAGE_OFFSET + 0x10000000; 88 unsigned long addr; 89 unsigned long lowbits; 90 91 addr = (unsigned long)dispDeviceBase; 92 if (!addr) { 93 boot_text_mapped = 0; 94 return; 95 } 96 lowbits = addr & ~0xFF000000UL; 97 addr &= 0xFF000000UL; 98 disp_BAT[0] = vaddr | (BL_16M<<2) | 2; 99 disp_BAT[1] = addr | (_PAGE_NO_CACHE | _PAGE_GUARDED | BPP_RW); 100 logicalDisplayBase = (void *) (vaddr + lowbits); 101 } 102 #endif 103 104 105 /* This function can be used to enable the early boot text when doing 106 * OF booting or within bootx init. It must be followed by a btext_unmap() 107 * call before the logical address becomes unusable 108 */ 109 void __init btext_setup_display(int width, int height, int depth, int pitch, 110 unsigned long address) 111 { 112 g_loc_X = 0; 113 g_loc_Y = 0; 114 g_max_loc_X = width / 8; 115 g_max_loc_Y = height / 16; 116 logicalDisplayBase = (unsigned char *)address; 117 dispDeviceBase = (unsigned char *)address; 118 dispDeviceRowBytes = pitch; 119 dispDeviceDepth = depth == 15 ? 16 : depth; 120 dispDeviceRect[0] = dispDeviceRect[1] = 0; 121 dispDeviceRect[2] = width; 122 dispDeviceRect[3] = height; 123 boot_text_mapped = 1; 124 } 125 126 void __init btext_unmap(void) 127 { 128 boot_text_mapped = 0; 129 } 130 131 /* Here's a small text engine to use during early boot 132 * or for debugging purposes 133 * 134 * todo: 135 * 136 * - build some kind of vgacon with it to enable early printk 137 * - move to a separate file 138 * - add a few video driver hooks to keep in sync with display 139 * changes. 140 */ 141 142 void btext_map(void) 143 { 144 unsigned long base, offset, size; 145 unsigned char *vbase; 146 147 /* By default, we are no longer mapped */ 148 boot_text_mapped = 0; 149 if (!dispDeviceBase) 150 return; 151 base = ((unsigned long) dispDeviceBase) & 0xFFFFF000UL; 152 offset = ((unsigned long) dispDeviceBase) - base; 153 size = dispDeviceRowBytes * dispDeviceRect[3] + offset 154 + dispDeviceRect[0]; 155 vbase = ioremap_wc(base, size); 156 if (!vbase) 157 return; 158 logicalDisplayBase = vbase + offset; 159 boot_text_mapped = 1; 160 } 161 162 static int __init btext_initialize(struct device_node *np) 163 { 164 unsigned int width, height, depth, pitch; 165 unsigned long address = 0; 166 const u32 *prop; 167 168 prop = of_get_property(np, "linux,bootx-width", NULL); 169 if (prop == NULL) 170 prop = of_get_property(np, "width", NULL); 171 if (prop == NULL) 172 return -EINVAL; 173 width = *prop; 174 prop = of_get_property(np, "linux,bootx-height", NULL); 175 if (prop == NULL) 176 prop = of_get_property(np, "height", NULL); 177 if (prop == NULL) 178 return -EINVAL; 179 height = *prop; 180 prop = of_get_property(np, "linux,bootx-depth", NULL); 181 if (prop == NULL) 182 prop = of_get_property(np, "depth", NULL); 183 if (prop == NULL) 184 return -EINVAL; 185 depth = *prop; 186 pitch = width * ((depth + 7) / 8); 187 prop = of_get_property(np, "linux,bootx-linebytes", NULL); 188 if (prop == NULL) 189 prop = of_get_property(np, "linebytes", NULL); 190 if (prop && *prop != 0xffffffffu) 191 pitch = *prop; 192 if (pitch == 1) 193 pitch = 0x1000; 194 prop = of_get_property(np, "linux,bootx-addr", NULL); 195 if (prop == NULL) 196 prop = of_get_property(np, "address", NULL); 197 if (prop) 198 address = *prop; 199 200 /* FIXME: Add support for PCI reg properties. Right now, only 201 * reliable on macs 202 */ 203 if (address == 0) 204 return -EINVAL; 205 206 g_loc_X = 0; 207 g_loc_Y = 0; 208 g_max_loc_X = width / 8; 209 g_max_loc_Y = height / 16; 210 dispDeviceBase = (unsigned char *)address; 211 dispDeviceRowBytes = pitch; 212 dispDeviceDepth = depth == 15 ? 16 : depth; 213 dispDeviceRect[0] = dispDeviceRect[1] = 0; 214 dispDeviceRect[2] = width; 215 dispDeviceRect[3] = height; 216 217 btext_map(); 218 219 return 0; 220 } 221 222 int __init btext_find_display(int allow_nonstdout) 223 { 224 struct device_node *np = of_stdout; 225 int rc = -ENODEV; 226 227 if (!of_node_is_type(np, "display")) { 228 printk("boot stdout isn't a display !\n"); 229 np = NULL; 230 } 231 if (np) 232 rc = btext_initialize(np); 233 if (rc == 0 || !allow_nonstdout) 234 return rc; 235 236 for_each_node_by_type(np, "display") { 237 if (of_property_read_bool(np, "linux,opened")) { 238 printk("trying %pOF ...\n", np); 239 rc = btext_initialize(np); 240 printk("result: %d\n", rc); 241 } 242 if (rc == 0) { 243 of_node_put(np); 244 break; 245 } 246 } 247 return rc; 248 } 249 250 /* Calc the base address of a given point (x,y) */ 251 static unsigned char * calc_base(int x, int y) 252 { 253 unsigned char *base; 254 255 base = logicalDisplayBase; 256 if (!base) 257 base = dispDeviceBase; 258 base += (x + dispDeviceRect[0]) * (dispDeviceDepth >> 3); 259 base += (y + dispDeviceRect[1]) * dispDeviceRowBytes; 260 return base; 261 } 262 263 /* Adjust the display to a new resolution */ 264 void btext_update_display(unsigned long phys, int width, int height, 265 int depth, int pitch) 266 { 267 if (!dispDeviceBase) 268 return; 269 270 /* check it's the same frame buffer (within 256MB) */ 271 if ((phys ^ (unsigned long)dispDeviceBase) & 0xf0000000) 272 return; 273 274 dispDeviceBase = (__u8 *) phys; 275 dispDeviceRect[0] = 0; 276 dispDeviceRect[1] = 0; 277 dispDeviceRect[2] = width; 278 dispDeviceRect[3] = height; 279 dispDeviceDepth = depth; 280 dispDeviceRowBytes = pitch; 281 if (boot_text_mapped) { 282 iounmap(logicalDisplayBase); 283 boot_text_mapped = 0; 284 } 285 btext_map(); 286 g_loc_X = 0; 287 g_loc_Y = 0; 288 g_max_loc_X = width / 8; 289 g_max_loc_Y = height / 16; 290 } 291 EXPORT_SYMBOL(btext_update_display); 292 293 void __init btext_clearscreen(void) 294 { 295 unsigned int *base = (unsigned int *)calc_base(0, 0); 296 unsigned long width = ((dispDeviceRect[2] - dispDeviceRect[0]) * 297 (dispDeviceDepth >> 3)) >> 2; 298 int i,j; 299 300 rmci_maybe_on(); 301 for (i=0; i<(dispDeviceRect[3] - dispDeviceRect[1]); i++) 302 { 303 unsigned int *ptr = base; 304 for(j=width; j; --j) 305 *(ptr++) = 0; 306 base += (dispDeviceRowBytes >> 2); 307 } 308 rmci_maybe_off(); 309 } 310 311 void __init btext_flushscreen(void) 312 { 313 unsigned int *base = (unsigned int *)calc_base(0, 0); 314 unsigned long width = ((dispDeviceRect[2] - dispDeviceRect[0]) * 315 (dispDeviceDepth >> 3)) >> 2; 316 int i,j; 317 318 for (i=0; i < (dispDeviceRect[3] - dispDeviceRect[1]); i++) 319 { 320 unsigned int *ptr = base; 321 for(j = width; j > 0; j -= 8) { 322 __asm__ __volatile__ ("dcbst 0,%0" :: "r" (ptr)); 323 ptr += 8; 324 } 325 base += (dispDeviceRowBytes >> 2); 326 } 327 __asm__ __volatile__ ("sync" ::: "memory"); 328 } 329 330 void __init btext_flushline(void) 331 { 332 unsigned int *base = (unsigned int *)calc_base(0, g_loc_Y << 4); 333 unsigned long width = ((dispDeviceRect[2] - dispDeviceRect[0]) * 334 (dispDeviceDepth >> 3)) >> 2; 335 int i,j; 336 337 for (i=0; i < 16; i++) 338 { 339 unsigned int *ptr = base; 340 for(j = width; j > 0; j -= 8) { 341 __asm__ __volatile__ ("dcbst 0,%0" :: "r" (ptr)); 342 ptr += 8; 343 } 344 base += (dispDeviceRowBytes >> 2); 345 } 346 __asm__ __volatile__ ("sync" ::: "memory"); 347 } 348 349 350 #ifndef NO_SCROLL 351 static void scrollscreen(void) 352 { 353 unsigned int *src = (unsigned int *)calc_base(0,16); 354 unsigned int *dst = (unsigned int *)calc_base(0,0); 355 unsigned long width = ((dispDeviceRect[2] - dispDeviceRect[0]) * 356 (dispDeviceDepth >> 3)) >> 2; 357 int i,j; 358 359 rmci_maybe_on(); 360 361 for (i=0; i<(dispDeviceRect[3] - dispDeviceRect[1] - 16); i++) 362 { 363 unsigned int *src_ptr = src; 364 unsigned int *dst_ptr = dst; 365 for(j=width; j; --j) 366 *(dst_ptr++) = *(src_ptr++); 367 src += (dispDeviceRowBytes >> 2); 368 dst += (dispDeviceRowBytes >> 2); 369 } 370 for (i=0; i<16; i++) 371 { 372 unsigned int *dst_ptr = dst; 373 for(j=width; j; --j) 374 *(dst_ptr++) = 0; 375 dst += (dispDeviceRowBytes >> 2); 376 } 377 378 rmci_maybe_off(); 379 } 380 #endif /* ndef NO_SCROLL */ 381 382 static unsigned int expand_bits_8[16] = { 383 0x00000000, 384 0x000000ff, 385 0x0000ff00, 386 0x0000ffff, 387 0x00ff0000, 388 0x00ff00ff, 389 0x00ffff00, 390 0x00ffffff, 391 0xff000000, 392 0xff0000ff, 393 0xff00ff00, 394 0xff00ffff, 395 0xffff0000, 396 0xffff00ff, 397 0xffffff00, 398 0xffffffff 399 }; 400 401 static unsigned int expand_bits_16[4] = { 402 0x00000000, 403 0x0000ffff, 404 0xffff0000, 405 0xffffffff 406 }; 407 408 409 static void draw_byte_32(const unsigned char *font, unsigned int *base, int rb) 410 { 411 int l, bits; 412 int fg = 0xFFFFFFFFUL; 413 int bg = 0x00000000UL; 414 415 for (l = 0; l < 16; ++l) 416 { 417 bits = *font++; 418 base[0] = (-(bits >> 7) & fg) ^ bg; 419 base[1] = (-((bits >> 6) & 1) & fg) ^ bg; 420 base[2] = (-((bits >> 5) & 1) & fg) ^ bg; 421 base[3] = (-((bits >> 4) & 1) & fg) ^ bg; 422 base[4] = (-((bits >> 3) & 1) & fg) ^ bg; 423 base[5] = (-((bits >> 2) & 1) & fg) ^ bg; 424 base[6] = (-((bits >> 1) & 1) & fg) ^ bg; 425 base[7] = (-(bits & 1) & fg) ^ bg; 426 base = (unsigned int *) ((char *)base + rb); 427 } 428 } 429 430 static inline void draw_byte_16(const unsigned char *font, unsigned int *base, int rb) 431 { 432 int l, bits; 433 int fg = 0xFFFFFFFFUL; 434 int bg = 0x00000000UL; 435 unsigned int *eb = (int *)expand_bits_16; 436 437 for (l = 0; l < 16; ++l) 438 { 439 bits = *font++; 440 base[0] = (eb[bits >> 6] & fg) ^ bg; 441 base[1] = (eb[(bits >> 4) & 3] & fg) ^ bg; 442 base[2] = (eb[(bits >> 2) & 3] & fg) ^ bg; 443 base[3] = (eb[bits & 3] & fg) ^ bg; 444 base = (unsigned int *) ((char *)base + rb); 445 } 446 } 447 448 static inline void draw_byte_8(const unsigned char *font, unsigned int *base, int rb) 449 { 450 int l, bits; 451 int fg = 0x0F0F0F0FUL; 452 int bg = 0x00000000UL; 453 unsigned int *eb = (int *)expand_bits_8; 454 455 for (l = 0; l < 16; ++l) 456 { 457 bits = *font++; 458 base[0] = (eb[bits >> 4] & fg) ^ bg; 459 base[1] = (eb[bits & 0xf] & fg) ^ bg; 460 base = (unsigned int *) ((char *)base + rb); 461 } 462 } 463 464 static noinline void draw_byte(unsigned char c, long locX, long locY) 465 { 466 unsigned char *base = calc_base(locX << 3, locY << 4); 467 unsigned int font_index = c * 16; 468 const unsigned char *font = PTRRELOC(font_sun_8x16.data) + font_index; 469 int rb = dispDeviceRowBytes; 470 471 rmci_maybe_on(); 472 switch(dispDeviceDepth) { 473 case 24: 474 case 32: 475 draw_byte_32(font, (unsigned int *)base, rb); 476 break; 477 case 15: 478 case 16: 479 draw_byte_16(font, (unsigned int *)base, rb); 480 break; 481 case 8: 482 draw_byte_8(font, (unsigned int *)base, rb); 483 break; 484 } 485 rmci_maybe_off(); 486 } 487 488 void btext_drawchar(char c) 489 { 490 int cline = 0; 491 #ifdef NO_SCROLL 492 int x; 493 #endif 494 if (!boot_text_mapped) 495 return; 496 497 switch (c) { 498 case '\b': 499 if (g_loc_X > 0) 500 --g_loc_X; 501 break; 502 case '\t': 503 g_loc_X = (g_loc_X & -8) + 8; 504 break; 505 case '\r': 506 g_loc_X = 0; 507 break; 508 case '\n': 509 g_loc_X = 0; 510 g_loc_Y++; 511 cline = 1; 512 break; 513 default: 514 draw_byte(c, g_loc_X++, g_loc_Y); 515 } 516 if (g_loc_X >= g_max_loc_X) { 517 g_loc_X = 0; 518 g_loc_Y++; 519 cline = 1; 520 } 521 #ifndef NO_SCROLL 522 while (g_loc_Y >= g_max_loc_Y) { 523 scrollscreen(); 524 g_loc_Y--; 525 } 526 #else 527 /* wrap around from bottom to top of screen so we don't 528 waste time scrolling each line. -- paulus. */ 529 if (g_loc_Y >= g_max_loc_Y) 530 g_loc_Y = 0; 531 if (cline) { 532 for (x = 0; x < g_max_loc_X; ++x) 533 draw_byte(' ', x, g_loc_Y); 534 } 535 #endif 536 } 537 538 void btext_drawstring(const char *c) 539 { 540 if (!boot_text_mapped) 541 return; 542 while (*c) 543 btext_drawchar(*c++); 544 } 545 546 void __init btext_drawtext(const char *c, unsigned int len) 547 { 548 if (!boot_text_mapped) 549 return; 550 while (len--) 551 btext_drawchar(*c++); 552 } 553 554 void __init btext_drawhex(unsigned long v) 555 { 556 if (!boot_text_mapped) 557 return; 558 #ifdef CONFIG_PPC64 559 btext_drawchar(hex_asc_hi(v >> 56)); 560 btext_drawchar(hex_asc_lo(v >> 56)); 561 btext_drawchar(hex_asc_hi(v >> 48)); 562 btext_drawchar(hex_asc_lo(v >> 48)); 563 btext_drawchar(hex_asc_hi(v >> 40)); 564 btext_drawchar(hex_asc_lo(v >> 40)); 565 btext_drawchar(hex_asc_hi(v >> 32)); 566 btext_drawchar(hex_asc_lo(v >> 32)); 567 #endif 568 btext_drawchar(hex_asc_hi(v >> 24)); 569 btext_drawchar(hex_asc_lo(v >> 24)); 570 btext_drawchar(hex_asc_hi(v >> 16)); 571 btext_drawchar(hex_asc_lo(v >> 16)); 572 btext_drawchar(hex_asc_hi(v >> 8)); 573 btext_drawchar(hex_asc_lo(v >> 8)); 574 btext_drawchar(hex_asc_hi(v)); 575 btext_drawchar(hex_asc_lo(v)); 576 btext_drawchar(' '); 577 } 578 579 void __init udbg_init_btext(void) 580 { 581 /* If btext is enabled, we might have a BAT setup for early display, 582 * thus we do enable some very basic udbg output 583 */ 584 udbg_putc = btext_drawchar; 585 } 586