Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/arch/sparc/kernel/btext.c
26424 views
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 <[email protected]>
6
*/
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>
12
13
#include <asm/btext.h>
14
#include <asm/oplib.h>
15
#include <asm/io.h>
16
17
#define NO_SCROLL
18
19
#ifndef NO_SCROLL
20
static void scrollscreen(void);
21
#endif
22
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);
27
28
#define __force_data __section(".data")
29
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;
34
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;
39
40
static int __init btext_initialize(phandle node)
41
{
42
unsigned int width, height, depth, pitch;
43
unsigned long address = 0;
44
u32 prop;
45
46
if (prom_getproperty(node, "width", (char *)&width, 4) < 0)
47
return -EINVAL;
48
if (prom_getproperty(node, "height", (char *)&height, 4) < 0)
49
return -EINVAL;
50
if (prom_getproperty(node, "depth", (char *)&depth, 4) < 0)
51
return -EINVAL;
52
pitch = width * ((depth + 7) / 8);
53
54
if (prom_getproperty(node, "linebytes", (char *)&prop, 4) >= 0 &&
55
prop != 0xffffffffu)
56
pitch = prop;
57
58
if (pitch == 1)
59
pitch = 0x1000;
60
61
if (prom_getproperty(node, "address", (char *)&prop, 4) >= 0)
62
address = prop;
63
64
/* FIXME: Add support for PCI reg properties. Right now, only
65
* reliable on macs
66
*/
67
if (address == 0)
68
return -EINVAL;
69
70
g_loc_X = 0;
71
g_loc_Y = 0;
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;
80
81
return 0;
82
}
83
84
/* Calc the base address of a given point (x,y) */
85
static unsigned char * calc_base(int x, int y)
86
{
87
unsigned char *base = dispDeviceBase;
88
89
base += (x + dispDeviceRect[0]) * (dispDeviceDepth >> 3);
90
base += (y + dispDeviceRect[1]) * dispDeviceRowBytes;
91
return base;
92
}
93
94
static void btext_clearscreen(void)
95
{
96
unsigned int *base = (unsigned int *)calc_base(0, 0);
97
unsigned long width = ((dispDeviceRect[2] - dispDeviceRect[0]) *
98
(dispDeviceDepth >> 3)) >> 2;
99
int i,j;
100
101
for (i=0; i<(dispDeviceRect[3] - dispDeviceRect[1]); i++)
102
{
103
unsigned int *ptr = base;
104
for(j=width; j; --j)
105
*(ptr++) = 0;
106
base += (dispDeviceRowBytes >> 2);
107
}
108
}
109
110
#ifndef NO_SCROLL
111
static void scrollscreen(void)
112
{
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;
117
int i,j;
118
119
for (i=0; i<(dispDeviceRect[3] - dispDeviceRect[1] - 16); i++)
120
{
121
unsigned int *src_ptr = src;
122
unsigned int *dst_ptr = dst;
123
for(j=width; j; --j)
124
*(dst_ptr++) = *(src_ptr++);
125
src += (dispDeviceRowBytes >> 2);
126
dst += (dispDeviceRowBytes >> 2);
127
}
128
for (i=0; i<16; i++)
129
{
130
unsigned int *dst_ptr = dst;
131
for(j=width; j; --j)
132
*(dst_ptr++) = 0;
133
dst += (dispDeviceRowBytes >> 2);
134
}
135
}
136
#endif /* ndef NO_SCROLL */
137
138
static void btext_drawchar(char c)
139
{
140
int cline = 0;
141
#ifdef NO_SCROLL
142
int x;
143
#endif
144
switch (c) {
145
case '\b':
146
if (g_loc_X > 0)
147
--g_loc_X;
148
break;
149
case '\t':
150
g_loc_X = (g_loc_X & -8) + 8;
151
break;
152
case '\r':
153
g_loc_X = 0;
154
break;
155
case '\n':
156
g_loc_X = 0;
157
g_loc_Y++;
158
cline = 1;
159
break;
160
default:
161
draw_byte(c, g_loc_X++, g_loc_Y);
162
}
163
if (g_loc_X >= g_max_loc_X) {
164
g_loc_X = 0;
165
g_loc_Y++;
166
cline = 1;
167
}
168
#ifndef NO_SCROLL
169
while (g_loc_Y >= g_max_loc_Y) {
170
scrollscreen();
171
g_loc_Y--;
172
}
173
#else
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)
177
g_loc_Y = 0;
178
if (cline) {
179
for (x = 0; x < g_max_loc_X; ++x)
180
draw_byte(' ', x, g_loc_Y);
181
}
182
#endif
183
}
184
185
static void btext_drawtext(const char *c, unsigned int len)
186
{
187
while (len--)
188
btext_drawchar(*c++);
189
}
190
191
static void draw_byte(unsigned char c, long locX, long locY)
192
{
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;
197
198
switch(dispDeviceDepth) {
199
case 24:
200
case 32:
201
draw_byte_32(font, (unsigned int *)base, rb);
202
break;
203
case 15:
204
case 16:
205
draw_byte_16(font, (unsigned int *)base, rb);
206
break;
207
case 8:
208
draw_byte_8(font, (unsigned int *)base, rb);
209
break;
210
}
211
}
212
213
static unsigned int expand_bits_8[16] = {
214
0x00000000,
215
0x000000ff,
216
0x0000ff00,
217
0x0000ffff,
218
0x00ff0000,
219
0x00ff00ff,
220
0x00ffff00,
221
0x00ffffff,
222
0xff000000,
223
0xff0000ff,
224
0xff00ff00,
225
0xff00ffff,
226
0xffff0000,
227
0xffff00ff,
228
0xffffff00,
229
0xffffffff
230
};
231
232
static unsigned int expand_bits_16[4] = {
233
0x00000000,
234
0x0000ffff,
235
0xffff0000,
236
0xffffffff
237
};
238
239
240
static void draw_byte_32(const unsigned char *font, unsigned int *base, int rb)
241
{
242
int l, bits;
243
int fg = 0xFFFFFFFFUL;
244
int bg = 0x00000000UL;
245
246
for (l = 0; l < 16; ++l)
247
{
248
bits = *font++;
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);
258
}
259
}
260
261
static void draw_byte_16(const unsigned char *font, unsigned int *base, int rb)
262
{
263
int l, bits;
264
int fg = 0xFFFFFFFFUL;
265
int bg = 0x00000000UL;
266
unsigned int *eb = (int *)expand_bits_16;
267
268
for (l = 0; l < 16; ++l)
269
{
270
bits = *font++;
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);
276
}
277
}
278
279
static void draw_byte_8(const unsigned char *font, unsigned int *base, int rb)
280
{
281
int l, bits;
282
int fg = 0x0F0F0F0FUL;
283
int bg = 0x00000000UL;
284
unsigned int *eb = (int *)expand_bits_8;
285
286
for (l = 0; l < 16; ++l)
287
{
288
bits = *font++;
289
base[0] = (eb[bits >> 4] & fg) ^ bg;
290
base[1] = (eb[bits & 0xf] & fg) ^ bg;
291
base = (unsigned int *) ((char *)base + rb);
292
}
293
}
294
295
static void btext_console_write(struct console *con, const char *s,
296
unsigned int n)
297
{
298
btext_drawtext(s, n);
299
}
300
301
static struct console btext_console = {
302
.name = "btext",
303
.write = btext_console_write,
304
.flags = CON_PRINTBUFFER | CON_ENABLED | CON_BOOT | CON_ANYTIME,
305
.index = 0,
306
};
307
308
int __init btext_find_display(void)
309
{
310
phandle node;
311
char type[32];
312
int ret;
313
314
node = prom_inst2pkg(prom_stdout);
315
if (prom_getproperty(node, "device_type", type, 32) < 0)
316
return -ENODEV;
317
if (strcmp(type, "display"))
318
return -ENODEV;
319
320
ret = btext_initialize(node);
321
if (!ret) {
322
btext_clearscreen();
323
register_console(&btext_console);
324
}
325
return ret;
326
}
327
328