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