~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/arch/powerpc/kernel/btext.c

Version: ~ [ linux-6.11.5 ] ~ [ linux-6.10.14 ] ~ [ linux-6.9.12 ] ~ [ linux-6.8.12 ] ~ [ linux-6.7.12 ] ~ [ linux-6.6.58 ] ~ [ linux-6.5.13 ] ~ [ linux-6.4.16 ] ~ [ linux-6.3.13 ] ~ [ linux-6.2.16 ] ~ [ linux-6.1.114 ] ~ [ linux-6.0.19 ] ~ [ linux-5.19.17 ] ~ [ linux-5.18.19 ] ~ [ linux-5.17.15 ] ~ [ linux-5.16.20 ] ~ [ linux-5.15.169 ] ~ [ linux-5.14.21 ] ~ [ linux-5.13.19 ] ~ [ linux-5.12.19 ] ~ [ linux-5.11.22 ] ~ [ linux-5.10.228 ] ~ [ linux-5.9.16 ] ~ [ linux-5.8.18 ] ~ [ linux-5.7.19 ] ~ [ linux-5.6.19 ] ~ [ linux-5.5.19 ] ~ [ linux-5.4.284 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.322 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.336 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.337 ] ~ [ linux-4.4.302 ] ~ [ linux-3.10.108 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.9 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  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/init.h>
 10 #include <linux/export.h>
 11 #include <linux/font.h>
 12 #include <linux/memblock.h>
 13 #include <linux/pgtable.h>
 14 #include <linux/of.h>
 15 
 16 #include <asm/sections.h>
 17 #include <asm/btext.h>
 18 #include <asm/page.h>
 19 #include <asm/mmu.h>
 20 #include <asm/io.h>
 21 #include <asm/processor.h>
 22 #include <asm/udbg.h>
 23 
 24 #define NO_SCROLL
 25 
 26 #ifndef NO_SCROLL
 27 static void scrollscreen(void);
 28 #endif
 29 
 30 #define __force_data __section(".data")
 31 
 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;
 36 
 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;
 42 
 43 unsigned long disp_BAT[2] __initdata = {0, 0};
 44 
 45 static int boot_text_mapped __force_data;
 46 
 47 extern void rmci_on(void);
 48 extern void rmci_off(void);
 49 
 50 static inline void rmci_maybe_on(void)
 51 {
 52 #if defined(CONFIG_PPC_EARLY_DEBUG_BOOTX) && defined(CONFIG_PPC64)
 53         if (!(mfmsr() & MSR_DR))
 54                 rmci_on();
 55 #endif
 56 }
 57 
 58 static inline void rmci_maybe_off(void)
 59 {
 60 #if defined(CONFIG_PPC_EARLY_DEBUG_BOOTX) && defined(CONFIG_PPC64)
 61         if (!(mfmsr() & MSR_DR))
 62                 rmci_off();
 63 #endif
 64 }
 65 
 66 
 67 #ifdef CONFIG_PPC32
 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()
 71  *
 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.
 77  *
 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
 81  * yet.
 82  */
 83 void __init btext_prepare_BAT(void)
 84 {
 85         unsigned long vaddr = PAGE_OFFSET + 0x10000000;
 86         unsigned long addr;
 87         unsigned long lowbits;
 88 
 89         addr = (unsigned long)dispDeviceBase;
 90         if (!addr) {
 91                 boot_text_mapped = 0;
 92                 return;
 93         }
 94         lowbits = addr & ~0xFF000000UL;
 95         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);
 99 }
100 #endif
101 
102 
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
106  */
107 void __init btext_setup_display(int width, int height, int depth, int pitch,
108                                 unsigned long address)
109 {
110         g_loc_X = 0;
111         g_loc_Y = 0;
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;
122 }
123 
124 void __init btext_unmap(void)
125 {
126         boot_text_mapped = 0;
127 }
128 
129 /* Here's a small text engine to use during early boot
130  * or for debugging purposes
131  *
132  * todo:
133  *
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
137  *    changes.
138  */
139 
140 void btext_map(void)
141 {
142         unsigned long base, offset, size;
143         unsigned char *vbase;
144 
145         /* By default, we are no longer mapped */
146         boot_text_mapped = 0;
147         if (!dispDeviceBase)
148                 return;
149         base = ((unsigned long) dispDeviceBase) & 0xFFFFF000UL;
150         offset = ((unsigned long) dispDeviceBase) - base;
151         size = dispDeviceRowBytes * dispDeviceRect[3] + offset
152                 + dispDeviceRect[0];
153         vbase = ioremap_wc(base, size);
154         if (!vbase)
155                 return;
156         logicalDisplayBase = vbase + offset;
157         boot_text_mapped = 1;
158 }
159 
160 static int __init btext_initialize(struct device_node *np)
161 {
162         unsigned int width, height, depth, pitch;
163         unsigned long address = 0;
164         const u32 *prop;
165 
166         prop = of_get_property(np, "linux,bootx-width", NULL);
167         if (prop == NULL)
168                 prop = of_get_property(np, "width", NULL);
169         if (prop == NULL)
170                 return -EINVAL;
171         width = *prop;
172         prop = of_get_property(np, "linux,bootx-height", NULL);
173         if (prop == NULL)
174                 prop = of_get_property(np, "height", NULL);
175         if (prop == NULL)
176                 return -EINVAL;
177         height = *prop;
178         prop = of_get_property(np, "linux,bootx-depth", NULL);
179         if (prop == NULL)
180                 prop = of_get_property(np, "depth", NULL);
181         if (prop == NULL)
182                 return -EINVAL;
183         depth = *prop;
184         pitch = width * ((depth + 7) / 8);
185         prop = of_get_property(np, "linux,bootx-linebytes", NULL);
186         if (prop == NULL)
187                 prop = of_get_property(np, "linebytes", NULL);
188         if (prop && *prop != 0xffffffffu)
189                 pitch = *prop;
190         if (pitch == 1)
191                 pitch = 0x1000;
192         prop = of_get_property(np, "linux,bootx-addr", NULL);
193         if (prop == NULL)
194                 prop = of_get_property(np, "address", NULL);
195         if (prop)
196                 address = *prop;
197 
198         /* FIXME: Add support for PCI reg properties. Right now, only
199          * reliable on macs
200          */
201         if (address == 0)
202                 return -EINVAL;
203 
204         g_loc_X = 0;
205         g_loc_Y = 0;
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;
214 
215         btext_map();
216 
217         return 0;
218 }
219 
220 int __init btext_find_display(int allow_nonstdout)
221 {
222         struct device_node *np = of_stdout;
223         int rc = -ENODEV;
224 
225         if (!of_node_is_type(np, "display")) {
226                 printk("boot stdout isn't a display !\n");
227                 np = NULL;
228         }
229         if (np)
230                 rc = btext_initialize(np);
231         if (rc == 0 || !allow_nonstdout)
232                 return rc;
233 
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);
239                 }
240                 if (rc == 0) {
241                         of_node_put(np);
242                         break;
243                 }
244         }
245         return rc;
246 }
247 
248 /* Calc the base address of a given point (x,y) */
249 static unsigned char * calc_base(int x, int y)
250 {
251         unsigned char *base;
252 
253         base = logicalDisplayBase;
254         if (!base)
255                 base = dispDeviceBase;
256         base += (x + dispDeviceRect[0]) * (dispDeviceDepth >> 3);
257         base += (y + dispDeviceRect[1]) * dispDeviceRowBytes;
258         return base;
259 }
260 
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)
264 {
265         if (!dispDeviceBase)
266                 return;
267 
268         /* check it's the same frame buffer (within 256MB) */
269         if ((phys ^ (unsigned long)dispDeviceBase) & 0xf0000000)
270                 return;
271 
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;
282         }
283         btext_map();
284         g_loc_X = 0;
285         g_loc_Y = 0;
286         g_max_loc_X = width / 8;
287         g_max_loc_Y = height / 16;
288 }
289 EXPORT_SYMBOL(btext_update_display);
290 
291 void __init btext_clearscreen(void)
292 {
293         unsigned int *base      = (unsigned int *)calc_base(0, 0);
294         unsigned long width     = ((dispDeviceRect[2] - dispDeviceRect[0]) *
295                                         (dispDeviceDepth >> 3)) >> 2;
296         int i,j;
297 
298         rmci_maybe_on();
299         for (i=0; i<(dispDeviceRect[3] - dispDeviceRect[1]); i++)
300         {
301                 unsigned int *ptr = base;
302                 for(j=width; j; --j)
303                         *(ptr++) = 0;
304                 base += (dispDeviceRowBytes >> 2);
305         }
306         rmci_maybe_off();
307 }
308 
309 void __init btext_flushscreen(void)
310 {
311         unsigned int *base      = (unsigned int *)calc_base(0, 0);
312         unsigned long width     = ((dispDeviceRect[2] - dispDeviceRect[0]) *
313                                         (dispDeviceDepth >> 3)) >> 2;
314         int i,j;
315 
316         for (i=0; i < (dispDeviceRect[3] - dispDeviceRect[1]); i++)
317         {
318                 unsigned int *ptr = base;
319                 for(j = width; j > 0; j -= 8) {
320                         __asm__ __volatile__ ("dcbst 0,%0" :: "r" (ptr));
321                         ptr += 8;
322                 }
323                 base += (dispDeviceRowBytes >> 2);
324         }
325         __asm__ __volatile__ ("sync" ::: "memory");
326 }
327 
328 void __init btext_flushline(void)
329 {
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;
333         int i,j;
334 
335         for (i=0; i < 16; i++)
336         {
337                 unsigned int *ptr = base;
338                 for(j = width; j > 0; j -= 8) {
339                         __asm__ __volatile__ ("dcbst 0,%0" :: "r" (ptr));
340                         ptr += 8;
341                 }
342                 base += (dispDeviceRowBytes >> 2);
343         }
344         __asm__ __volatile__ ("sync" ::: "memory");
345 }
346 
347 
348 #ifndef NO_SCROLL
349 static void scrollscreen(void)
350 {
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;
355         int i,j;
356 
357         rmci_maybe_on();
358 
359         for (i=0; i<(dispDeviceRect[3] - dispDeviceRect[1] - 16); i++)
360         {
361                 unsigned int *src_ptr = src;
362                 unsigned int *dst_ptr = dst;
363                 for(j=width; j; --j)
364                         *(dst_ptr++) = *(src_ptr++);
365                 src += (dispDeviceRowBytes >> 2);
366                 dst += (dispDeviceRowBytes >> 2);
367         }
368         for (i=0; i<16; i++)
369         {
370                 unsigned int *dst_ptr = dst;
371                 for(j=width; j; --j)
372                         *(dst_ptr++) = 0;
373                 dst += (dispDeviceRowBytes >> 2);
374         }
375 
376         rmci_maybe_off();
377 }
378 #endif /* ndef NO_SCROLL */
379 
380 static unsigned int expand_bits_8[16] = {
381         0x00000000,
382         0x000000ff,
383         0x0000ff00,
384         0x0000ffff,
385         0x00ff0000,
386         0x00ff00ff,
387         0x00ffff00,
388         0x00ffffff,
389         0xff000000,
390         0xff0000ff,
391         0xff00ff00,
392         0xff00ffff,
393         0xffff0000,
394         0xffff00ff,
395         0xffffff00,
396         0xffffffff
397 };
398 
399 static unsigned int expand_bits_16[4] = {
400         0x00000000,
401         0x0000ffff,
402         0xffff0000,
403         0xffffffff
404 };
405 
406 
407 static void draw_byte_32(const unsigned char *font, unsigned int *base, int rb)
408 {
409         int l, bits;
410         int fg = 0xFFFFFFFFUL;
411         int bg = 0x00000000UL;
412 
413         for (l = 0; l < 16; ++l)
414         {
415                 bits = *font++;
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);
425         }
426 }
427 
428 static inline void draw_byte_16(const unsigned char *font, unsigned int *base, int rb)
429 {
430         int l, bits;
431         int fg = 0xFFFFFFFFUL;
432         int bg = 0x00000000UL;
433         unsigned int *eb = (int *)expand_bits_16;
434 
435         for (l = 0; l < 16; ++l)
436         {
437                 bits = *font++;
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);
443         }
444 }
445 
446 static inline void draw_byte_8(const unsigned char *font, unsigned int *base, int rb)
447 {
448         int l, bits;
449         int fg = 0x0F0F0F0FUL;
450         int bg = 0x00000000UL;
451         unsigned int *eb = (int *)expand_bits_8;
452 
453         for (l = 0; l < 16; ++l)
454         {
455                 bits = *font++;
456                 base[0] = (eb[bits >> 4] & fg) ^ bg;
457                 base[1] = (eb[bits & 0xf] & fg) ^ bg;
458                 base = (unsigned int *) ((char *)base + rb);
459         }
460 }
461 
462 static noinline void draw_byte(unsigned char c, long locX, long locY)
463 {
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;
468 
469         rmci_maybe_on();
470         switch(dispDeviceDepth) {
471         case 24:
472         case 32:
473                 draw_byte_32(font, (unsigned int *)base, rb);
474                 break;
475         case 15:
476         case 16:
477                 draw_byte_16(font, (unsigned int *)base, rb);
478                 break;
479         case 8:
480                 draw_byte_8(font, (unsigned int *)base, rb);
481                 break;
482         }
483         rmci_maybe_off();
484 }
485 
486 void btext_drawchar(char c)
487 {
488         int cline = 0;
489 #ifdef NO_SCROLL
490         int x;
491 #endif
492         if (!boot_text_mapped)
493                 return;
494 
495         switch (c) {
496         case '\b':
497                 if (g_loc_X > 0)
498                         --g_loc_X;
499                 break;
500         case '\t':
501                 g_loc_X = (g_loc_X & -8) + 8;
502                 break;
503         case '\r':
504                 g_loc_X = 0;
505                 break;
506         case '\n':
507                 g_loc_X = 0;
508                 g_loc_Y++;
509                 cline = 1;
510                 break;
511         default:
512                 draw_byte(c, g_loc_X++, g_loc_Y);
513         }
514         if (g_loc_X >= g_max_loc_X) {
515                 g_loc_X = 0;
516                 g_loc_Y++;
517                 cline = 1;
518         }
519 #ifndef NO_SCROLL
520         while (g_loc_Y >= g_max_loc_Y) {
521                 scrollscreen();
522                 g_loc_Y--;
523         }
524 #else
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)
528                 g_loc_Y = 0;
529         if (cline) {
530                 for (x = 0; x < g_max_loc_X; ++x)
531                         draw_byte(' ', x, g_loc_Y);
532         }
533 #endif
534 }
535 
536 void btext_drawstring(const char *c)
537 {
538         if (!boot_text_mapped)
539                 return;
540         while (*c)
541                 btext_drawchar(*c++);
542 }
543 
544 void __init btext_drawtext(const char *c, unsigned int len)
545 {
546         if (!boot_text_mapped)
547                 return;
548         while (len--)
549                 btext_drawchar(*c++);
550 }
551 
552 void __init btext_drawhex(unsigned long v)
553 {
554         if (!boot_text_mapped)
555                 return;
556 #ifdef CONFIG_PPC64
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));
565 #endif
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));
574         btext_drawchar(' ');
575 }
576 
577 void __init udbg_init_btext(void)
578 {
579         /* If btext is enabled, we might have a BAT setup for early display,
580          * thus we do enable some very basic udbg output
581          */
582         udbg_putc = btext_drawchar;
583 }
584 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

sflogo.php