// SPDX-License-Identifier: GPL-2.0
/*
* Procedures for drawing on the screen early on in the boot process.
*
* Benjamin Herrenschmidt <benh@kernel.crashing.org>
*/
#include <linux/kernel.h>
#include <linux/string.h>
#include <linux/init.h>
#include <linux/console.h>
#include <linux/font.h>
#include <asm /btext.h>
#include <asm /oplib.h>
#include <asm /io.h>
#define NO_SCROLL
#ifndef NO_SCROLL
static void scrollscreen(void );
#endif
static void draw_byte(unsigned char c, long locX, long locY);
static void draw_byte_32(const unsigned char *bits, unsigned int *base, int rb);
static void draw_byte_16(const unsigned char *bits, unsigned int *base, int rb);
static void draw_byte_8(const unsigned char *bits, unsigned int *base, int rb);
#define __force_data __section(".data" )
static int g_loc_X __force_data;
static int g_loc_Y __force_data;
static int g_max_loc_X __force_data;
static int g_max_loc_Y __force_data;
static int dispDeviceRowBytes __force_data;
static int dispDeviceDepth __force_data;
static int dispDeviceRect[4 ] __force_data;
static unsigned char *dispDeviceBase __force_data;
static int __init btext_initialize(phandle node)
{
unsigned int width, height, depth, pitch;
unsigned long address = 0 ;
u32 prop;
if (prom_getproperty(node, "width" , (char *)&width, 4 ) < 0 )
return -EINVAL;
if (prom_getproperty(node, "height" , (char *)&height, 4 ) < 0 )
return -EINVAL;
if (prom_getproperty(node, "depth" , (char *)&depth, 4 ) < 0 )
return -EINVAL;
pitch = width * ((depth + 7 ) / 8 );
if (prom_getproperty(node, "linebytes" , (char *)&prop, 4 ) >= 0 &&
prop != 0 xffffffffu)
pitch = prop;
if (pitch == 1 )
pitch = 0 x1000;
if (prom_getproperty(node, "address" , (char *)&prop, 4 ) >= 0 )
address = prop;
/* FIXME: Add support for PCI reg properties. Right now, only
* reliable on macs
*/
if (address == 0 )
return -EINVAL;
g_loc_X = 0 ;
g_loc_Y = 0 ;
g_max_loc_X = width / 8 ;
g_max_loc_Y = height / 16 ;
dispDeviceBase = (unsigned char *)address;
dispDeviceRowBytes = pitch;
dispDeviceDepth = depth == 15 ? 16 : depth;
dispDeviceRect[0 ] = dispDeviceRect[1 ] = 0 ;
dispDeviceRect[2 ] = width;
dispDeviceRect[3 ] = height;
return 0 ;
}
/* Calc the base address of a given point (x,y) */
static unsigned char * calc_base(int x, int y)
{
unsigned char *base = dispDeviceBase;
base += (x + dispDeviceRect[0 ]) * (dispDeviceDepth >> 3 );
base += (y + dispDeviceRect[1 ]) * dispDeviceRowBytes;
return base;
}
static void btext_clearscreen(void )
{
unsigned int *base = (unsigned int *)calc_base(0 , 0 );
unsigned long width = ((dispDeviceRect[2 ] - dispDeviceRect[0 ]) *
(dispDeviceDepth >> 3 )) >> 2 ;
int i,j;
for (i=0 ; i<(dispDeviceRect[3 ] - dispDeviceRect[1 ]); i++)
{
unsigned int *ptr = base;
for (j=width; j; --j)
*(ptr++) = 0 ;
base += (dispDeviceRowBytes >> 2 );
}
}
#ifndef NO_SCROLL
static void scrollscreen(void )
{
unsigned int *src = (unsigned int *)calc_base(0 ,16 );
unsigned int *dst = (unsigned int *)calc_base(0 ,0 );
unsigned long width = ((dispDeviceRect[2 ] - dispDeviceRect[0 ]) *
(dispDeviceDepth >> 3 )) >> 2 ;
int i,j;
for (i=0 ; i<(dispDeviceRect[3 ] - dispDeviceRect[1 ] - 16 ); i++)
{
unsigned int *src_ptr = src;
unsigned int *dst_ptr = dst;
for (j=width; j; --j)
*(dst_ptr++) = *(src_ptr++);
src += (dispDeviceRowBytes >> 2 );
dst += (dispDeviceRowBytes >> 2 );
}
for (i=0 ; i<16 ; i++)
{
unsigned int *dst_ptr = dst;
for (j=width; j; --j)
*(dst_ptr++) = 0 ;
dst += (dispDeviceRowBytes >> 2 );
}
}
#endif /* ndef NO_SCROLL */
static void btext_drawchar(char c)
{
int cline = 0 ;
#ifdef NO_SCROLL
int x;
#endif
switch (c) {
case '\b' :
if (g_loc_X > 0 )
--g_loc_X;
break ;
case '\t' :
g_loc_X = (g_loc_X & -8 ) + 8 ;
break ;
case '\r' :
g_loc_X = 0 ;
break ;
case '\n' :
g_loc_X = 0 ;
g_loc_Y++;
cline = 1 ;
break ;
default :
draw_byte(c, g_loc_X++, g_loc_Y);
}
if (g_loc_X >= g_max_loc_X) {
g_loc_X = 0 ;
g_loc_Y++;
cline = 1 ;
}
#ifndef NO_SCROLL
while (g_loc_Y >= g_max_loc_Y) {
scrollscreen();
g_loc_Y--;
}
#else
/* wrap around from bottom to top of screen so we don't
waste time scrolling each line. -- paulus. */
if (g_loc_Y >= g_max_loc_Y)
g_loc_Y = 0 ;
if (cline) {
for (x = 0 ; x < g_max_loc_X; ++x)
draw_byte(' ' , x, g_loc_Y);
}
#endif
}
static void btext_drawtext(const char *c, unsigned int len)
{
while (len--)
btext_drawchar(*c++);
}
static void draw_byte(unsigned char c, long locX, long locY)
{
unsigned char *base = calc_base(locX << 3 , locY << 4 );
unsigned int font_index = c * 16 ;
const unsigned char *font = font_sun_8x16.data + font_index;
int rb = dispDeviceRowBytes;
switch (dispDeviceDepth) {
case 24 :
case 32 :
draw_byte_32(font, (unsigned int *)base, rb);
break ;
case 15 :
case 16 :
draw_byte_16(font, (unsigned int *)base, rb);
break ;
case 8 :
draw_byte_8(font, (unsigned int *)base, rb);
break ;
}
}
static unsigned int expand_bits_8[16 ] = {
0 x00000000,
0 x000000ff,
0 x0000ff00,
0 x0000ffff,
0 x00ff0000,
0 x00ff00ff,
0 x00ffff00,
0 x00ffffff,
0 xff000000,
0 xff0000ff,
0 xff00ff00,
0 xff00ffff,
0 xffff0000,
0 xffff00ff,
0 xffffff00,
0 xffffffff
};
static unsigned int expand_bits_16[4 ] = {
0 x00000000,
0 x0000ffff,
0 xffff0000,
0 xffffffff
};
static void draw_byte_32(const unsigned char *font, unsigned int *base, int rb)
{
int l, bits;
int fg = 0 xFFFFFFFFUL;
int bg = 0 x00000000UL;
for (l = 0 ; l < 16 ; ++l)
{
bits = *font++;
base[0 ] = (-(bits >> 7 ) & fg) ^ bg;
base[1 ] = (-((bits >> 6 ) & 1 ) & fg) ^ bg;
base[2 ] = (-((bits >> 5 ) & 1 ) & fg) ^ bg;
base[3 ] = (-((bits >> 4 ) & 1 ) & fg) ^ bg;
base[4 ] = (-((bits >> 3 ) & 1 ) & fg) ^ bg;
base[5 ] = (-((bits >> 2 ) & 1 ) & fg) ^ bg;
base[6 ] = (-((bits >> 1 ) & 1 ) & fg) ^ bg;
base[7 ] = (-(bits & 1 ) & fg) ^ bg;
base = (unsigned int *) ((char *)base + rb);
}
}
static void draw_byte_16(const unsigned char *font, unsigned int *base, int rb)
{
int l, bits;
int fg = 0 xFFFFFFFFUL;
int bg = 0 x00000000UL;
unsigned int *eb = (int *)expand_bits_16;
for (l = 0 ; l < 16 ; ++l)
{
bits = *font++;
base[0 ] = (eb[bits >> 6 ] & fg) ^ bg;
base[1 ] = (eb[(bits >> 4 ) & 3 ] & fg) ^ bg;
base[2 ] = (eb[(bits >> 2 ) & 3 ] & fg) ^ bg;
base[3 ] = (eb[bits & 3 ] & fg) ^ bg;
base = (unsigned int *) ((char *)base + rb);
}
}
static void draw_byte_8(const unsigned char *font, unsigned int *base, int rb)
{
int l, bits;
int fg = 0 x0F0F0F0FUL;
int bg = 0 x00000000UL;
unsigned int *eb = (int *)expand_bits_8;
for (l = 0 ; l < 16 ; ++l)
{
bits = *font++;
base[0 ] = (eb[bits >> 4 ] & fg) ^ bg;
base[1 ] = (eb[bits & 0 xf] & fg) ^ bg;
base = (unsigned int *) ((char *)base + rb);
}
}
static void btext_console_write(struct console *con, const char *s,
unsigned int n)
{
btext_drawtext(s, n);
}
static struct console btext_console = {
.name = "btext" ,
.write = btext_console_write,
.flags = CON_PRINTBUFFER | CON_ENABLED | CON_BOOT | CON_ANYTIME,
.index = 0 ,
};
int __init btext_find_display(void )
{
phandle node;
char type[32 ];
int ret;
node = prom_inst2pkg(prom_stdout);
if (prom_getproperty(node, "device_type" , type, 32 ) < 0 )
return -ENODEV;
if (strcmp(type, "display" ))
return -ENODEV;
ret = btext_initialize(node);
if (!ret) {
btext_clearscreen();
register_console(&btext_console);
}
return ret;
}
Messung V0.5 in Prozent C=89 H=91 G=89
¤ Dauer der Verarbeitung: 0.11 Sekunden
(vorverarbeitet am 2026-06-07)
¤
*© Formatika GbR, Deutschland