Merge tag 'linux_kselftest-fixes-6.10-rc7' of git://git.kernel.org/pub/scm/linux...
[linux-block.git] / arch / sparc / kernel / btext.c
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/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 }