reactos/drivers/base/bootvid/arm/bootvid.c

563 lines
12 KiB
C

#include "precomp.h"
#define NDEBUG
#include <debug.h>
#define LCDTIMING0_PPL(x) ((((x) / 16 - 1) & 0x3f) << 2)
#define LCDTIMING1_LPP(x) (((x) & 0x3ff) - 1)
#define LCDCONTROL_LCDPWR (1 << 11)
#define LCDCONTROL_LCDEN (1)
#define LCDCONTROL_LCDBPP(x) (((x) & 7) << 1)
#define LCDCONTROL_LCDTFT (1 << 5)
#define PL110_LCDTIMING0 (PVOID)0xE0020000
#define PL110_LCDTIMING1 (PVOID)0xE0020004
#define PL110_LCDTIMING2 (PVOID)0xE0020008
#define PL110_LCDUPBASE (PVOID)0xE0020010
#define PL110_LCDLPBASE (PVOID)0xE0020014
#define PL110_LCDCONTROL (PVOID)0xE0020018
#define READ_REGISTER_ULONG(r) (*(volatile ULONG * const)(r))
#define WRITE_REGISTER_ULONG(r, v) (*(volatile ULONG *)(r) = (v))
#define READ_REGISTER_USHORT(r) (*(volatile USHORT * const)(r))
#define WRITE_REGISTER_USHORT(r, v) (*(volatile USHORT *)(r) = (v))
PUSHORT VgaArmBase;
PHYSICAL_ADDRESS VgaPhysical;
BOOLEAN NextLine = FALSE;
UCHAR VidpTextColor = 0xF;
ULONG VidpCurrentX = 0;
ULONG VidpCurrentY = 0;
ULONG VidpScrollRegion[4] =
{
0,
0,
640 - 1,
480 - 1
};
typedef struct _VGA_COLOR
{
UCHAR Red;
UCHAR Green;
UCHAR Blue;
} VGA_COLOR;
VGA_COLOR VidpVga8To16BitTransform[16] =
{
{0x00, 0x00, 0x00}, // Black
{0x00, 0x00, 0x08}, // Blue
{0x00, 0x08, 0x00}, // Green
{0x00, 0x08, 0x08}, // Cyan
{0x08, 0x00, 0x00}, // Red
{0x08, 0x00, 0x08}, // Magenta
{0x0B, 0x0D, 0x0F}, // Brown
{0x10, 0x10, 0x10}, // Light Gray
{0x08, 0x08, 0x08}, // Dark Gray
{0x00, 0x00, 0x1F}, // Light Blue
{0x00, 0x1F, 0x00}, // Light Green
{0x00, 0x1F, 0x1F}, // Light Cyan
{0x1F, 0x00, 0x00}, // Light Red
{0x1F, 0x00, 0x1F}, // Light Magenta
{0x1F, 0x1F, 0x00}, // Yellow
{0x1F, 0x1F, 0x1F}, // White
};
/* PRIVATE FUNCTIONS *********************************************************/
USHORT
FORCEINLINE
VidpBuildColor(IN UCHAR Color)
{
UCHAR Red, Green, Blue;
//
// Extract color components
//
Red = VidpVga8To16BitTransform[Color].Red;
Green = VidpVga8To16BitTransform[Color].Green;
Blue = VidpVga8To16BitTransform[Color].Blue;
//
// Build the 16-bit color mask
//
return ((Red & 0x1F) << 11) | ((Green & 0x1F) << 6) | ((Blue & 0x1F));
}
VOID
FORCEINLINE
VidpSetPixel(IN ULONG Left,
IN ULONG Top,
IN UCHAR Color)
{
PUSHORT PixelPosition;
//
// Calculate the pixel position
//
PixelPosition = &VgaArmBase[Left + (Top * 640)];
//
// Set our color
//
WRITE_REGISTER_USHORT(PixelPosition, VidpBuildColor(Color));
}
VOID
NTAPI
DisplayCharacter(IN CHAR Character,
IN ULONG Left,
IN ULONG Top,
IN ULONG TextColor,
IN ULONG BackTextColor)
{
PUCHAR FontChar;
ULONG i, j, XOffset;
/* Get the font line for this character */
FontChar = &FontData[Character * 13 - Top];
/* Loop each pixel height */
i = 13;
do
{
/* Loop each pixel width */
j = 128;
XOffset = Left;
do
{
/* Check if we should draw this pixel */
if (FontChar[Top] & (UCHAR)j)
{
/* We do, use the given Text Color */
VidpSetPixel(XOffset, Top, (UCHAR)TextColor);
}
else if (BackTextColor < 16)
{
/* This is a background pixel. We're drawing it unless it's */
/* transparent. */
VidpSetPixel(XOffset, Top, (UCHAR)BackTextColor);
}
/* Increase X Offset */
XOffset++;
} while (j >>= 1);
/* Move to the next Y ordinate */
Top++;
} while (--i);
}
VOID
NTAPI
VgaScroll(IN ULONG Scroll)
{
ULONG Top, Offset;
PUSHORT SourceOffset, DestOffset;
PUSHORT i, j;
/* Set memory positions of the scroll */
SourceOffset = &VgaArmBase[(VidpScrollRegion[1] * 80) + (VidpScrollRegion[0] >> 3)];
DestOffset = &SourceOffset[Scroll * 80];
/* Save top and check if it's above the bottom */
Top = VidpScrollRegion[1];
if (Top > VidpScrollRegion[3]) return;
/* Start loop */
do
{
/* Set number of bytes to loop and start offset */
Offset = VidpScrollRegion[0] >> 3;
j = SourceOffset;
/* Check if this is part of the scroll region */
if (Offset <= (VidpScrollRegion[2] >> 3))
{
/* Update position */
i = (PUSHORT)(DestOffset - SourceOffset);
/* Loop the X axis */
do
{
/* Write value in the new position so that we can do the scroll */
WRITE_REGISTER_USHORT(j, READ_REGISTER_USHORT(j + (ULONG_PTR)i));
/* Move to the next memory location to write to */
j++;
/* Move to the next byte in the region */
Offset++;
/* Make sure we don't go past the scroll region */
} while (Offset <= (VidpScrollRegion[2] >> 3));
}
/* Move to the next line */
SourceOffset += 80;
DestOffset += 80;
/* Increase top */
Top++;
/* Make sure we don't go past the scroll region */
} while (Top <= VidpScrollRegion[3]);
}
VOID
NTAPI
PreserveRow(IN ULONG CurrentTop,
IN ULONG TopDelta,
IN BOOLEAN Direction)
{
PUSHORT Position1, Position2;
ULONG Count;
/* Check which way we're preserving */
if (Direction)
{
/* Calculate the position in memory for the row */
Position1 = &VgaArmBase[CurrentTop * 80];
Position2 = &VgaArmBase[0x9600];
}
else
{
/* Calculate the position in memory for the row */
Position1 = &VgaArmBase[0x9600];
Position2 = &VgaArmBase[CurrentTop * 80];
}
/* Set the count and loop every pixel */
Count = TopDelta * 80;
while (Count--)
{
/* Write the data back on the other position */
WRITE_REGISTER_USHORT(Position1, READ_REGISTER_USHORT(Position2));
/* Increase both positions */
Position1++;
Position2++;
}
}
VOID
NTAPI
VidpInitializeDisplay(VOID)
{
//
// Set framebuffer address
//
WRITE_REGISTER_ULONG(PL110_LCDUPBASE, VgaPhysical.LowPart);
WRITE_REGISTER_ULONG(PL110_LCDLPBASE, VgaPhysical.LowPart);
//
// Initialize timings to 640x480
//
WRITE_REGISTER_ULONG(PL110_LCDTIMING0, LCDTIMING0_PPL(640));
WRITE_REGISTER_ULONG(PL110_LCDTIMING1, LCDTIMING1_LPP(480));
//
// Enable the LCD Display
//
WRITE_REGISTER_ULONG(PL110_LCDCONTROL,
LCDCONTROL_LCDEN |
LCDCONTROL_LCDTFT |
LCDCONTROL_LCDPWR |
LCDCONTROL_LCDBPP(4));
}
/* PUBLIC FUNCTIONS **********************************************************/
/*
* @implemented
*/
BOOLEAN
NTAPI
VidInitialize(IN BOOLEAN SetMode)
{
DPRINT1("bv-arm v0.1\n");
//
// Allocate framebuffer
// 600kb works out to 640x480@16bpp
//
VgaPhysical.QuadPart = -1;
VgaArmBase = MmAllocateContiguousMemory(600 * 1024, VgaPhysical);
if (!VgaArmBase) return FALSE;
//
// Get physical address
//
VgaPhysical = MmGetPhysicalAddress(VgaArmBase);
if (!VgaPhysical.QuadPart) return FALSE;
DPRINT1("[BV-ARM] Frame Buffer @ 0x%p 0p%p\n", VgaArmBase, VgaPhysical.LowPart);
//
// Setup the display
//
VidpInitializeDisplay();
//
// We are done!
//
return TRUE;
}
/*
* @implemented
*/
VOID
NTAPI
VidResetDisplay(IN BOOLEAN HalReset)
{
//
// Clear the current position
//
VidpCurrentX = 0;
VidpCurrentY = 0;
//
// Re-initialize the VGA Display
//
VidpInitializeDisplay();
//
// Re-initialize the palette and fill the screen black
//
//InitializePalette();
VidSolidColorFill(0, 0, 639, 479, 0);
}
/*
* @implemented
*/
ULONG
NTAPI
VidSetTextColor(IN ULONG Color)
{
UCHAR OldColor;
//
// Save the old, set the new
//
OldColor = VidpTextColor;
VidpTextColor = Color;
//
// Return the old text color
//
return OldColor;
}
/*
* @implemented
*/
VOID
NTAPI
VidDisplayStringXY(IN PUCHAR String,
IN ULONG Left,
IN ULONG Top,
IN BOOLEAN Transparent)
{
UNIMPLEMENTED;
while (TRUE);
}
/*
* @implemented
*/
VOID
NTAPI
VidSetScrollRegion(IN ULONG Left,
IN ULONG Top,
IN ULONG Right,
IN ULONG Bottom)
{
/* Assert alignment */
ASSERT((Left & 0x7) == 0);
ASSERT((Right & 0x7) == 7);
/* Set Scroll Region */
VidpScrollRegion[0] = Left;
VidpScrollRegion[1] = Top;
VidpScrollRegion[2] = Right;
VidpScrollRegion[3] = Bottom;
/* Set current X and Y */
VidpCurrentX = Left;
VidpCurrentY = Top;
}
/*
* @implemented
*/
VOID
NTAPI
VidCleanUp(VOID)
{
UNIMPLEMENTED;
while (TRUE);
}
/*
* @implemented
*/
VOID
NTAPI
VidBufferToScreenBlt(IN PUCHAR Buffer,
IN ULONG Left,
IN ULONG Top,
IN ULONG Width,
IN ULONG Height,
IN ULONG Delta)
{
UNIMPLEMENTED;
while (TRUE);
}
/*
* @implemented
*/
VOID
NTAPI
VidDisplayString(IN PUCHAR String)
{
ULONG TopDelta = 14;
/* Start looping the string */
while (*String)
{
/* Treat new-line separately */
if (*String == '\n')
{
/* Modify Y position */
VidpCurrentY += TopDelta;
if (VidpCurrentY >= VidpScrollRegion[3])
{
/* Scroll the view */
VgaScroll(TopDelta);
VidpCurrentY -= TopDelta;
/* Preserve row */
PreserveRow(VidpCurrentY, TopDelta, TRUE);
}
/* Update current X */
VidpCurrentX = VidpScrollRegion[0];
/* Preserve the current row */
PreserveRow(VidpCurrentY, TopDelta, FALSE);
}
else if (*String == '\r')
{
/* Update current X */
VidpCurrentX = VidpScrollRegion[0];
/* Check if we're being followed by a new line */
if (String[1] != '\n') NextLine = TRUE;
}
else
{
/* Check if we had a \n\r last time */
if (NextLine)
{
/* We did, preserve the current row */
PreserveRow(VidpCurrentY, TopDelta, TRUE);
NextLine = FALSE;
}
/* Display this character */
DisplayCharacter(*String,
VidpCurrentX,
VidpCurrentY,
VidpTextColor,
16);
VidpCurrentX += 8;
/* Check if we should scroll */
if (VidpCurrentX > VidpScrollRegion[2])
{
/* Update Y position and check if we should scroll it */
VidpCurrentY += TopDelta;
if (VidpCurrentY > VidpScrollRegion[3])
{
/* Do the scroll */
VgaScroll(TopDelta);
VidpCurrentY -= TopDelta;
/* Save the row */
PreserveRow(VidpCurrentY, TopDelta, TRUE);
}
/* Update X */
VidpCurrentX = VidpScrollRegion[0];
}
}
/* Get the next character */
String++;
}
}
/*
* @implemented
*/
VOID
NTAPI
VidBitBlt(IN PUCHAR Buffer,
IN ULONG Left,
IN ULONG Top)
{
UNIMPLEMENTED;
//while (TRUE);
}
/*
* @implemented
*/
VOID
NTAPI
VidScreenToBufferBlt(IN PUCHAR Buffer,
IN ULONG Left,
IN ULONG Top,
IN ULONG Width,
IN ULONG Height,
IN ULONG Delta)
{
UNIMPLEMENTED;
while (TRUE);
}
/*
* @implemented
*/
VOID
NTAPI
VidSolidColorFill(IN ULONG Left,
IN ULONG Top,
IN ULONG Right,
IN ULONG Bottom,
IN UCHAR Color)
{
int y, x;
//
// Loop along the Y-axis
//
for (y = Top; y <= Bottom; y++)
{
//
// Loop along the X-axis
//
for (x = Left; x <= Right; x++)
{
//
// Draw the pixel
//
VidpSetPixel(x, y, Color);
}
}
}