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/console.h>
11 #include <linux/font.h>
13 #include <asm/btext.h>
14 #include <asm/oplib.h>
20 static void scrollscreen(void);
23 static void draw_byte(unsigned char c, long locX, long locY);
24 static void draw_byte_32(const unsigned char *bits, unsigned int *base, int rb);
25 static void draw_byte_16(const unsigned char *bits, unsigned int *base, int rb);
26 static void draw_byte_8(const unsigned char *bits, unsigned int *base, int rb);
28 #define __force_data __section(".data")
30 static int g_loc_X __force_data;
31 static int g_loc_Y __force_data;
32 static int g_max_loc_X __force_data;
33 static int g_max_loc_Y __force_data;
35 static int dispDeviceRowBytes __force_data;
36 static int dispDeviceDepth __force_data;
37 static int dispDeviceRect[4] __force_data;
38 static unsigned char *dispDeviceBase __force_data;
40 static int __init btext_initialize(phandle node)
42 unsigned int width, height, depth, pitch;
43 unsigned long address = 0;
46 if (prom_getproperty(node, "width", (char *)&width, 4) < 0)
48 if (prom_getproperty(node, "height", (char *)&height, 4) < 0)
50 if (prom_getproperty(node, "depth", (char *)&depth, 4) < 0)
52 pitch = width * ((depth + 7) / 8);
54 if (prom_getproperty(node, "linebytes", (char *)&prop, 4) >= 0 &&
61 if (prom_getproperty(node, "address", (char *)&prop, 4) >= 0)
64 /* FIXME: Add support for PCI reg properties. Right now, only
72 g_max_loc_X = width / 8;
73 g_max_loc_Y = height / 16;
74 dispDeviceBase = (unsigned char *)address;
75 dispDeviceRowBytes = pitch;
76 dispDeviceDepth = depth == 15 ? 16 : depth;
77 dispDeviceRect[0] = dispDeviceRect[1] = 0;
78 dispDeviceRect[2] = width;
79 dispDeviceRect[3] = height;
84 /* Calc the base address of a given point (x,y) */
85 static unsigned char * calc_base(int x, int y)
87 unsigned char *base = dispDeviceBase;
89 base += (x + dispDeviceRect[0]) * (dispDeviceDepth >> 3);
90 base += (y + dispDeviceRect[1]) * dispDeviceRowBytes;
94 static void btext_clearscreen(void)
96 unsigned int *base = (unsigned int *)calc_base(0, 0);
97 unsigned long width = ((dispDeviceRect[2] - dispDeviceRect[0]) *
98 (dispDeviceDepth >> 3)) >> 2;
101 for (i=0; i<(dispDeviceRect[3] - dispDeviceRect[1]); i++)
103 unsigned int *ptr = base;
106 base += (dispDeviceRowBytes >> 2);
111 static void scrollscreen(void)
113 unsigned int *src = (unsigned int *)calc_base(0,16);
114 unsigned int *dst = (unsigned int *)calc_base(0,0);
115 unsigned long width = ((dispDeviceRect[2] - dispDeviceRect[0]) *
116 (dispDeviceDepth >> 3)) >> 2;
119 for (i=0; i<(dispDeviceRect[3] - dispDeviceRect[1] - 16); i++)
121 unsigned int *src_ptr = src;
122 unsigned int *dst_ptr = dst;
124 *(dst_ptr++) = *(src_ptr++);
125 src += (dispDeviceRowBytes >> 2);
126 dst += (dispDeviceRowBytes >> 2);
130 unsigned int *dst_ptr = dst;
133 dst += (dispDeviceRowBytes >> 2);
136 #endif /* ndef NO_SCROLL */
138 static void btext_drawchar(char c)
150 g_loc_X = (g_loc_X & -8) + 8;
161 draw_byte(c, g_loc_X++, g_loc_Y);
163 if (g_loc_X >= g_max_loc_X) {
169 while (g_loc_Y >= g_max_loc_Y) {
174 /* wrap around from bottom to top of screen so we don't
175 waste time scrolling each line. -- paulus. */
176 if (g_loc_Y >= g_max_loc_Y)
179 for (x = 0; x < g_max_loc_X; ++x)
180 draw_byte(' ', x, g_loc_Y);
185 static void btext_drawtext(const char *c, unsigned int len)
188 btext_drawchar(*c++);
191 static void draw_byte(unsigned char c, long locX, long locY)
193 unsigned char *base = calc_base(locX << 3, locY << 4);
194 unsigned int font_index = c * 16;
195 const unsigned char *font = font_sun_8x16.data + font_index;
196 int rb = dispDeviceRowBytes;
198 switch(dispDeviceDepth) {
201 draw_byte_32(font, (unsigned int *)base, rb);
205 draw_byte_16(font, (unsigned int *)base, rb);
208 draw_byte_8(font, (unsigned int *)base, rb);
213 static unsigned int expand_bits_8[16] = {
232 static unsigned int expand_bits_16[4] = {
240 static void draw_byte_32(const unsigned char *font, unsigned int *base, int rb)
243 int fg = 0xFFFFFFFFUL;
244 int bg = 0x00000000UL;
246 for (l = 0; l < 16; ++l)
249 base[0] = (-(bits >> 7) & fg) ^ bg;
250 base[1] = (-((bits >> 6) & 1) & fg) ^ bg;
251 base[2] = (-((bits >> 5) & 1) & fg) ^ bg;
252 base[3] = (-((bits >> 4) & 1) & fg) ^ bg;
253 base[4] = (-((bits >> 3) & 1) & fg) ^ bg;
254 base[5] = (-((bits >> 2) & 1) & fg) ^ bg;
255 base[6] = (-((bits >> 1) & 1) & fg) ^ bg;
256 base[7] = (-(bits & 1) & fg) ^ bg;
257 base = (unsigned int *) ((char *)base + rb);
261 static void draw_byte_16(const unsigned char *font, unsigned int *base, int rb)
264 int fg = 0xFFFFFFFFUL;
265 int bg = 0x00000000UL;
266 unsigned int *eb = (int *)expand_bits_16;
268 for (l = 0; l < 16; ++l)
271 base[0] = (eb[bits >> 6] & fg) ^ bg;
272 base[1] = (eb[(bits >> 4) & 3] & fg) ^ bg;
273 base[2] = (eb[(bits >> 2) & 3] & fg) ^ bg;
274 base[3] = (eb[bits & 3] & fg) ^ bg;
275 base = (unsigned int *) ((char *)base + rb);
279 static void draw_byte_8(const unsigned char *font, unsigned int *base, int rb)
282 int fg = 0x0F0F0F0FUL;
283 int bg = 0x00000000UL;
284 unsigned int *eb = (int *)expand_bits_8;
286 for (l = 0; l < 16; ++l)
289 base[0] = (eb[bits >> 4] & fg) ^ bg;
290 base[1] = (eb[bits & 0xf] & fg) ^ bg;
291 base = (unsigned int *) ((char *)base + rb);
295 static void btext_console_write(struct console *con, const char *s,
298 btext_drawtext(s, n);
301 static struct console btext_console = {
303 .write = btext_console_write,
304 .flags = CON_PRINTBUFFER | CON_ENABLED | CON_BOOT | CON_ANYTIME,
308 int __init btext_find_display(void)
314 node = prom_inst2pkg(prom_stdout);
315 if (prom_getproperty(node, "device_type", type, 32) < 0)
317 if (strcmp(type, "display"))
320 ret = btext_initialize(node);
323 register_console(&btext_console);