xref: /reactos/drivers/base/bootvid/arm/bootvid.c (revision 845faec4)
1 #include "precomp.h"
2 
3 #define NDEBUG
4 #include <debug.h>
5 
6 #define LCDTIMING0_PPL(x)       ((((x) / 16 - 1) & 0x3f) << 2)
7 #define LCDTIMING1_LPP(x)       (((x) & 0x3ff) - 1)
8 #define LCDCONTROL_LCDPWR       (1 << 11)
9 #define LCDCONTROL_LCDEN        (1)
10 #define LCDCONTROL_LCDBPP(x)    (((x) & 7) << 1)
11 #define LCDCONTROL_LCDTFT       (1 << 5)
12 
13 #define PL110_LCDTIMING0    (PVOID)0xE0020000
14 #define PL110_LCDTIMING1    (PVOID)0xE0020004
15 #define PL110_LCDTIMING2    (PVOID)0xE0020008
16 #define PL110_LCDUPBASE     (PVOID)0xE0020010
17 #define PL110_LCDLPBASE     (PVOID)0xE0020014
18 #define PL110_LCDCONTROL    (PVOID)0xE0020018
19 
20 #define READ_REGISTER_ULONG(r) (*(volatile ULONG * const)(r))
21 #define WRITE_REGISTER_ULONG(r, v) (*(volatile ULONG *)(r) = (v))
22 
23 #define READ_REGISTER_USHORT(r) (*(volatile USHORT * const)(r))
24 #define WRITE_REGISTER_USHORT(r, v) (*(volatile USHORT *)(r) = (v))
25 
26 PUSHORT VgaArmBase;
27 PHYSICAL_ADDRESS VgaPhysical;
28 BOOLEAN NextLine = FALSE;
29 UCHAR VidpTextColor = 0xF;
30 ULONG VidpCurrentX = 0;
31 ULONG VidpCurrentY = 0;
32 ULONG VidpScrollRegion[4] =
33 {
34     0,
35     0,
36     640 - 1,
37     480 - 1
38 };
39 
40 typedef struct _VGA_COLOR
41 {
42     UCHAR Red;
43     UCHAR Green;
44     UCHAR Blue;
45 } VGA_COLOR;
46 
47 VGA_COLOR VidpVga8To16BitTransform[16] =
48 {
49     {0x00, 0x00, 0x00}, // Black
50     {0x00, 0x00, 0x08}, // Blue
51     {0x00, 0x08, 0x00}, // Green
52     {0x00, 0x08, 0x08}, // Cyan
53     {0x08, 0x00, 0x00}, // Red
54     {0x08, 0x00, 0x08}, // Magenta
55     {0x0B, 0x0D, 0x0F}, // Brown
56     {0x10, 0x10, 0x10}, // Light Gray
57     {0x08, 0x08, 0x08}, // Dark Gray
58     {0x00, 0x00, 0x1F}, // Light Blue
59     {0x00, 0x1F, 0x00}, // Light Green
60     {0x00, 0x1F, 0x1F}, // Light Cyan
61     {0x1F, 0x00, 0x00}, // Light Red
62     {0x1F, 0x00, 0x1F}, // Light Magenta
63     {0x1F, 0x1F, 0x00}, // Yellow
64     {0x1F, 0x1F, 0x1F}, // White
65 };
66 
67 /* PRIVATE FUNCTIONS *********************************************************/
68 
69 USHORT
70 FORCEINLINE
71 VidpBuildColor(IN UCHAR Color)
72 {
73     UCHAR Red, Green, Blue;
74 
75     //
76     // Extract color components
77     //
78     Red = VidpVga8To16BitTransform[Color].Red;
79     Green = VidpVga8To16BitTransform[Color].Green;
80     Blue = VidpVga8To16BitTransform[Color].Blue;
81 
82     //
83     // Build the 16-bit color mask
84     //
85     return ((Red & 0x1F) << 11) | ((Green & 0x1F) << 6) | ((Blue & 0x1F));
86 }
87 
88 
89 VOID
90 FORCEINLINE
91 VidpSetPixel(IN ULONG Left,
92              IN ULONG Top,
93              IN UCHAR Color)
94 {
95     PUSHORT PixelPosition;
96 
97     //
98     // Calculate the pixel position
99     //
100     PixelPosition = &VgaArmBase[Left + (Top * 640)];
101 
102     //
103     // Set our color
104     //
105     WRITE_REGISTER_USHORT(PixelPosition, VidpBuildColor(Color));
106 }
107 
108 VOID
109 NTAPI
110 DisplayCharacter(IN CHAR Character,
111                  IN ULONG Left,
112                  IN ULONG Top,
113                  IN ULONG TextColor,
114                  IN ULONG BackTextColor)
115 {
116     PUCHAR FontChar;
117     ULONG i, j, XOffset;
118 
119     /* Get the font line for this character */
120     FontChar = &FontData[Character * 13 - Top];
121 
122     /* Loop each pixel height */
123     i = 13;
124     do
125     {
126         /* Loop each pixel width */
127         j = 128;
128         XOffset = Left;
129         do
130         {
131             /* Check if we should draw this pixel */
132             if (FontChar[Top] & (UCHAR)j)
133             {
134                 /* We do, use the given Text Color */
135                 VidpSetPixel(XOffset, Top, (UCHAR)TextColor);
136             }
137             else if (BackTextColor < 16)
138             {
139                 /* This is a background pixel. We're drawing it unless it's */
140                 /* transparent. */
141                 VidpSetPixel(XOffset, Top, (UCHAR)BackTextColor);
142             }
143 
144             /* Increase X Offset */
145             XOffset++;
146         } while (j >>= 1);
147 
148         /* Move to the next Y ordinate */
149         Top++;
150     } while (--i);
151 }
152 
153 VOID
154 NTAPI
155 VgaScroll(IN ULONG Scroll)
156 {
157     ULONG Top, Offset;
158     PUSHORT SourceOffset, DestOffset;
159     PUSHORT i, j;
160 
161     /* Set memory positions of the scroll */
162     SourceOffset = &VgaArmBase[(VidpScrollRegion[1] * 80) + (VidpScrollRegion[0] >> 3)];
163     DestOffset = &SourceOffset[Scroll * 80];
164 
165     /* Save top and check if it's above the bottom */
166     Top = VidpScrollRegion[1];
167     if (Top > VidpScrollRegion[3]) return;
168 
169     /* Start loop */
170     do
171     {
172         /* Set number of bytes to loop and start offset */
173         Offset = VidpScrollRegion[0] >> 3;
174         j = SourceOffset;
175 
176         /* Check if this is part of the scroll region */
177         if (Offset <= (VidpScrollRegion[2] >> 3))
178         {
179             /* Update position */
180             i = (PUSHORT)(DestOffset - SourceOffset);
181 
182             /* Loop the X axis */
183             do
184             {
185                 /* Write value in the new position so that we can do the scroll */
186                 WRITE_REGISTER_USHORT(j, READ_REGISTER_USHORT(j + (ULONG_PTR)i));
187 
188                 /* Move to the next memory location to write to */
189                 j++;
190 
191                 /* Move to the next byte in the region */
192                 Offset++;
193 
194                 /* Make sure we don't go past the scroll region */
195             } while (Offset <= (VidpScrollRegion[2] >> 3));
196         }
197 
198         /* Move to the next line */
199         SourceOffset += 80;
200         DestOffset += 80;
201 
202         /* Increase top */
203         Top++;
204 
205         /* Make sure we don't go past the scroll region */
206     } while (Top <= VidpScrollRegion[3]);
207 }
208 
209 VOID
210 NTAPI
211 PreserveRow(IN ULONG CurrentTop,
212             IN ULONG TopDelta,
213             IN BOOLEAN Direction)
214 {
215     PUSHORT Position1, Position2;
216     ULONG Count;
217 
218     /* Check which way we're preserving */
219     if (Direction)
220     {
221         /* Calculate the position in memory for the row */
222         Position1 = &VgaArmBase[CurrentTop * 80];
223         Position2 = &VgaArmBase[0x9600];
224     }
225     else
226     {
227         /* Calculate the position in memory for the row */
228         Position1 = &VgaArmBase[0x9600];
229         Position2 = &VgaArmBase[CurrentTop * 80];
230     }
231 
232     /* Set the count and loop every pixel */
233     Count = TopDelta * 80;
234     while (Count--)
235     {
236         /* Write the data back on the other position */
237         WRITE_REGISTER_USHORT(Position1, READ_REGISTER_USHORT(Position2));
238 
239         /* Increase both positions */
240         Position1++;
241         Position2++;
242     }
243 }
244 
245 VOID
246 NTAPI
247 VidpInitializeDisplay(VOID)
248 {
249     //
250     // Set framebuffer address
251     //
252     WRITE_REGISTER_ULONG(PL110_LCDUPBASE, VgaPhysical.LowPart);
253     WRITE_REGISTER_ULONG(PL110_LCDLPBASE, VgaPhysical.LowPart);
254 
255     //
256     // Initialize timings to 640x480
257     //
258     WRITE_REGISTER_ULONG(PL110_LCDTIMING0, LCDTIMING0_PPL(640));
259     WRITE_REGISTER_ULONG(PL110_LCDTIMING1, LCDTIMING1_LPP(480));
260 
261     //
262     // Enable the LCD Display
263     //
264     WRITE_REGISTER_ULONG(PL110_LCDCONTROL,
265                          LCDCONTROL_LCDEN |
266                          LCDCONTROL_LCDTFT |
267                          LCDCONTROL_LCDPWR |
268                          LCDCONTROL_LCDBPP(4));
269 }
270 
271 /* PUBLIC FUNCTIONS **********************************************************/
272 
273 /*
274  * @implemented
275  */
276 BOOLEAN
277 NTAPI
278 VidInitialize(IN BOOLEAN SetMode)
279 {
280     DPRINT1("bv-arm v0.1\n");
281 
282     //
283     // Allocate framebuffer
284     // 600kb works out to 640x480@16bpp
285     //
286     VgaPhysical.QuadPart = -1;
287     VgaArmBase = MmAllocateContiguousMemory(600 * 1024, VgaPhysical);
288     if (!VgaArmBase) return FALSE;
289 
290     //
291     // Get physical address
292     //
293     VgaPhysical = MmGetPhysicalAddress(VgaArmBase);
294     if (!VgaPhysical.QuadPart) return FALSE;
295     DPRINT1("[BV-ARM] Frame Buffer @ 0x%p 0p%p\n", VgaArmBase, VgaPhysical.LowPart);
296 
297     //
298     // Setup the display
299     //
300     VidpInitializeDisplay();
301 
302     //
303     // We are done!
304     //
305     return TRUE;
306 }
307 
308 /*
309  * @implemented
310  */
311 VOID
312 NTAPI
313 VidResetDisplay(IN BOOLEAN HalReset)
314 {
315     //
316     // Clear the current position
317     //
318     VidpCurrentX = 0;
319     VidpCurrentY = 0;
320 
321     //
322     // Re-initialize the VGA Display
323     //
324     VidpInitializeDisplay();
325 
326     //
327     // Re-initialize the palette and fill the screen black
328     //
329     //InitializePalette();
330     VidSolidColorFill(0, 0, 639, 479, 0);
331 }
332 
333 /*
334  * @implemented
335  */
336 ULONG
337 NTAPI
338 VidSetTextColor(IN ULONG Color)
339 {
340     UCHAR OldColor;
341 
342     //
343     // Save the old, set the new
344     //
345     OldColor = VidpTextColor;
346     VidpTextColor = Color;
347 
348     //
349     // Return the old text color
350     //
351     return OldColor;
352 }
353 
354 /*
355  * @implemented
356  */
357 VOID
358 NTAPI
359 VidDisplayStringXY(IN PUCHAR String,
360                    IN ULONG Left,
361                    IN ULONG Top,
362                    IN BOOLEAN Transparent)
363 {
364     UNIMPLEMENTED;
365     while (TRUE);
366 }
367 
368 /*
369  * @implemented
370  */
371 VOID
372 NTAPI
373 VidSetScrollRegion(IN ULONG Left,
374                    IN ULONG Top,
375                    IN ULONG Right,
376                    IN ULONG Bottom)
377 {
378     /* Assert alignment */
379     ASSERT((Left  & 0x7) == 0);
380     ASSERT((Right & 0x7) == 7);
381 
382     /* Set Scroll Region */
383     VidpScrollRegion[0] = Left;
384     VidpScrollRegion[1] = Top;
385     VidpScrollRegion[2] = Right;
386     VidpScrollRegion[3] = Bottom;
387 
388     /* Set current X and Y */
389     VidpCurrentX = Left;
390     VidpCurrentY = Top;
391 }
392 
393 /*
394  * @implemented
395  */
396 VOID
397 NTAPI
398 VidCleanUp(VOID)
399 {
400     UNIMPLEMENTED;
401     while (TRUE);
402 }
403 
404 /*
405  * @implemented
406  */
407 VOID
408 NTAPI
409 VidBufferToScreenBlt(IN PUCHAR Buffer,
410                      IN ULONG Left,
411                      IN ULONG Top,
412                      IN ULONG Width,
413                      IN ULONG Height,
414                      IN ULONG Delta)
415 {
416     UNIMPLEMENTED;
417     while (TRUE);
418 }
419 
420 /*
421  * @implemented
422  */
423 VOID
424 NTAPI
425 VidDisplayString(IN PUCHAR String)
426 {
427     ULONG TopDelta = 14;
428 
429     /* Start looping the string */
430     while (*String)
431     {
432         /* Treat new-line separately */
433         if (*String == '\n')
434         {
435             /* Modify Y position */
436             VidpCurrentY += TopDelta;
437             if (VidpCurrentY >= VidpScrollRegion[3])
438             {
439                 /* Scroll the view */
440                 VgaScroll(TopDelta);
441                 VidpCurrentY -= TopDelta;
442 
443                 /* Preserve row */
444                 PreserveRow(VidpCurrentY, TopDelta, TRUE);
445             }
446 
447             /* Update current X */
448             VidpCurrentX = VidpScrollRegion[0];
449 
450             /* Preserve the current row */
451             PreserveRow(VidpCurrentY, TopDelta, FALSE);
452         }
453         else if (*String == '\r')
454         {
455             /* Update current X */
456             VidpCurrentX = VidpScrollRegion[0];
457 
458             /* Check if we're being followed by a new line */
459             if (String[1] != '\n') NextLine = TRUE;
460         }
461         else
462         {
463             /* Check if we had a \n\r last time */
464             if (NextLine)
465             {
466                 /* We did, preserve the current row */
467                 PreserveRow(VidpCurrentY, TopDelta, TRUE);
468                 NextLine = FALSE;
469             }
470 
471             /* Display this character */
472             DisplayCharacter(*String,
473                              VidpCurrentX,
474                              VidpCurrentY,
475                              VidpTextColor,
476                              16);
477             VidpCurrentX += 8;
478 
479             /* Check if we should scroll */
480             if (VidpCurrentX > VidpScrollRegion[2])
481             {
482                 /* Update Y position and check if we should scroll it */
483                 VidpCurrentY += TopDelta;
484                 if (VidpCurrentY > VidpScrollRegion[3])
485                 {
486                     /* Do the scroll */
487                     VgaScroll(TopDelta);
488                     VidpCurrentY -= TopDelta;
489 
490                     /* Save the row */
491                     PreserveRow(VidpCurrentY, TopDelta, TRUE);
492                 }
493 
494                 /* Update X */
495                 VidpCurrentX = VidpScrollRegion[0];
496             }
497         }
498 
499         /* Get the next character */
500         String++;
501     }
502 }
503 
504 /*
505  * @implemented
506  */
507 VOID
508 NTAPI
509 VidBitBlt(IN PUCHAR Buffer,
510           IN ULONG Left,
511           IN ULONG Top)
512 {
513     UNIMPLEMENTED;
514     //while (TRUE);
515 }
516 
517 /*
518  * @implemented
519  */
520 VOID
521 NTAPI
522 VidScreenToBufferBlt(IN PUCHAR Buffer,
523                      IN ULONG Left,
524                      IN ULONG Top,
525                      IN ULONG Width,
526                      IN ULONG Height,
527                      IN ULONG Delta)
528 {
529     UNIMPLEMENTED;
530     while (TRUE);
531 }
532 
533 /*
534  * @implemented
535  */
536 VOID
537 NTAPI
538 VidSolidColorFill(IN ULONG Left,
539                   IN ULONG Top,
540                   IN ULONG Right,
541                   IN ULONG Bottom,
542                   IN UCHAR Color)
543 {
544     int y, x;
545 
546     //
547     // Loop along the Y-axis
548     //
549     for (y = Top; y <= Bottom; y++)
550     {
551         //
552         // Loop along the X-axis
553         //
554         for (x = Left; x <= Right; x++)
555         {
556             //
557             // Draw the pixel
558             //
559             VidpSetPixel(x, y, Color);
560         }
561     }
562 }
563