mode.c
来自「WinCE 3.0 BSP, 包含Inter SA1110, Intel_815」· C语言 代码 · 共 1,370 行 · 第 1/3 页
C
1,370 行
// INTREF is the input frequency to the PLL core (it's the frequency of the
// reference clock after it's been divided by the prescaler, N).
// Local constants.
const ULONG MinVCO = 2000000; // min VCO is 200MHz (in 100Hz units)
const ULONG MaxVCO = 6220000; // max VCO is 622MHz (in 100Hz units)
const ULONG MinINTREF = 10000; // min INTREF is 1MHz (in 100Hz units)
const ULONG MaxINTREF = 20000; // max INTREF is 2MHz (in 100Hz units)
const ULONG InitialFreqError = 100000; // An arbitrary constant.
// Local variables.
ULONG M, N, P;
ULONG INTREF;
ULONG VCO;
ULONG ActualClock; // Return value for this function.
LONG Error; // Error values might be negative.
LONG LowestError = InitialFreqError;
BOOL FoundFreq = FALSE;
ULONG InnerLoopIterations = 0;
LONG LoopCount;
ULONG VCOLowest, VCOHighest;
// Check parameters.
AssertWritePtr(ReturnM, sizeof(ULONG));
AssertWritePtr(ReturnN, sizeof(ULONG));
AssertWritePtr(ReturnP, sizeof(ULONG));
Enter(L"CalculateMNPForClock");
for (P = 0; P <= 5; P++) {
// It's pointless going through the main loop if all values of N produce
// an VCO outside the acceptable range
N = 1;
M = (N * (1 << P) * RequiredFrequency) / (2 * RefClockFrequency);
VCOLowest = (2 * RefClockFrequency * M) / N;
N = 255;
M = (N * (1 << P) * RequiredFrequency) / (2 * RefClockFrequency);
VCOHighest = (2 * RefClockFrequency * M) / N;
if (VCOHighest < MinVCO || VCOLowest > MaxVCO) {
continue;
}
for (N = 1; N <= 255; N++, InnerLoopIterations++) {
INTREF = RefClockFrequency / N;
if (INTREF < MinINTREF || INTREF > MaxINTREF) {
if (INTREF > MaxINTREF) {
// Hopefully we'll get into range as the prescale value increases.
continue;
}
else {
// Already below minimum and it'll only get worse: move to the next
// postscale value
break;
}
}
M = (N * (1 << P) * RequiredFrequency) / (2 * RefClockFrequency);
if (M > 255) {
// M, N & P registers are only 8 bits wide
break;
}
// We can expect rounding errors in calculating M, which will
// always be rounded down. So we'll checkout our calculated
// value of M along with (M+1)
for (LoopCount = (M == 255) ? 1 : 2; --LoopCount >= 0; M++) {
VCO = (2 * RefClockFrequency * M) / N;
if (VCO >= MinVCO && VCO <= MaxVCO) {
ActualClock = VCO / (1 << P);
Error = ActualClock - RequiredFrequency;
if (Error < 0) Error = -Error;
if (Error < LowestError) {
FoundFreq = TRUE;
LowestError = Error;
// Code above protects us from truncation here.
*ReturnM = (BYTE)M;
*ReturnN = (BYTE)N;
*ReturnP = (BYTE)P;
// Escape the madness if we have a perfect match.
if (Error == 0) goto Done;
}
}
}
}
}
Done:
if (FoundFreq)
ActualClock = (2 * RefClockFrequency * (*ReturnM)) / ((*ReturnN) * (1 << (*ReturnP)));
else
ActualClock = 0;
Exit(L"CalculateMNPForClock");
return (ActualClock);
}
void
PrimarySurfaceSetMode(
USHORT VideoMode,
USHORT PixelFormat
)
{
// PrimarySurfaceSetMode
// This function handles allocating a primary surface for the given display
// mode. It also programs the RAMDAC to use the new primary. This function
// is not intended to be reused. Rather, it makes the SetMode function easir
// to read.
// Local variables.
LPVOID PrimaryAddress;
// Check parameters.
Assert(VideoMode < l_NumVideoModeTable);
Assert(PixelFormat < l_NumPixelTable);
Enter(L"PrimarySurfaceSetMode");
// Free up the previous primary surface.
if (l_PrimarySurface.Ptr != NULL) {
VideoFree(l_PrimarySurface.Ptr);
}
// Allocate new primary surface.
PrimaryAddress = VideoAlloc(ComputeMemRequired(VideoMode, PixelFormat), 16);
if (PrimaryAddress != NULL) {
// No need to wait for vsync to call SetScreenBase, as video is disabled.
SetScreenBase(PrimaryAddress);
// Fill out the module local primary surface structure.
l_PrimarySurface.Ptr = PrimaryAddress;
l_PrimarySurface.Size.cx = l_VideoModeTable[VideoMode].HResolution;
l_PrimarySurface.Size.cy = l_VideoModeTable[VideoMode].VResolution;
l_PrimarySurface.Format = (const FORMAT *)&l_PixelTable[PixelFormat];
l_PrimarySurface.FreeFormat = FALSE;
l_PrimarySurface.Stride = (LONG)ComputeStride(VideoMode, PixelFormat);
l_PrimarySurface.Type = VideoMemory;
l_PrimarySurface.ColorKeyType = NoColorKey;
memset(&l_PrimarySurface.SourceColorKey, 0, sizeof(COLOR_SPACE));
memset(&l_PrimarySurface.DestColorKey, 0, sizeof(COLOR_SPACE));
}
else {
Error(L"Failed to allocate video memory for use as primary surface!\n");
}
Exit(L"PrimarySurfaceSetMode");
}
void
SetScreenBase(
LPVOID NewPrimary
)
{
// SetScreenBase
// This function takes a virtual address of a video memory allocation that
// the DAC will start reading out of. We assume that it has the correct
// dimensions and bits per pixel. We do check in debug builds that the
// pointer is valid, is in video memory, and is 128 bit aligned. This is
// the final function called in a primary surface flip. This should be
// called in vsync, as we set up flipping for free running.
// Local variables.
ULONG NewPrimaryOffset;
// Check parameters.
AssertVideoPtr(NewPrimary);
Enter(L"SetScreenBase");
NewPrimaryOffset = VirtualToOffset(NewPrimary);
// Should be on 128 bit boundary : convert to 128 bit units.
Assert((NewPrimaryOffset % 16) == 0);
NewPrimaryOffset >>= 4;
// Program the offset into the Permedia3.
WaitForInputFIFO(2);
WriteRegUlong(r_ScreenBase, NewPrimaryOffset);
WriteRegUlong(r_ScreenBaseRight, NewPrimaryOffset);
Exit(L"SetScreenBase");
}
void
VideoSetMode(
USHORT VideoMode,
USHORT PixelFormat
)
{
// VideoSetMode
// This function handles programming the video timing parameters into the
// RAMDAC. It is not intended to be reuseable, rather, it makes the SetMode
// function easir to read.
// Local variables.
const PERM3_VIDEO_MODE * VideoModeIndirect;
ULONG HBlankWidth;
ULONG HSyncEnd;
ULONG VBlankWidth;
ULONG VSyncEnd;
// Check parameters.
Assert(VideoMode < l_NumVideoModeTable);
Assert(PixelFormat < l_NumPixelTable);
Enter(L"VideoSetMode");
// Save some array lookups.
VideoModeIndirect = &l_VideoModeTable[VideoMode];
WaitForInputFIFO(11);
// Make sure we do NOT use byte doubling. This is only useful for 8 bpp
// modes where we would violate VESA timing requirements by fetching 128
// bits at a time : it's too many pixels. Byte doubling causes the RAMDAC
// to fetch only 64 bits doubled. We only support 32 and 16 bpp modes, so
// we don't need it. (It would impact programming the pixel clock as well.)
// This write turns off striping as well, which is only important in
// systems with multiple rasterization chips.
WriteRegUlong(r_MiscControl, 0);
// We need to program the video parameters (specifically HgEnd,) before the
// ScreenBase is set.
// Note that all of the video parameter registers need to be programmed in
// terms of 128 bit units. All of the timing parameters are given in chars,
// so convert. Also, we also require the last line on screen on in a period
// rather than the width, so note the use of - 1 terms in those cases.
// We are not panning, so HgEnd == HbEnd.
HSyncEnd = VideoModeIndirect->HFrontPorch + VideoModeIndirect->HSyncTime;
HBlankWidth = HSyncEnd + VideoModeIndirect->HBackPorch;
WriteRegUlong(r_HgEnd, CharToOctWord(HBlankWidth, PixelFormat));
WriteRegUlong(r_HTotal, CharToOctWord(VideoModeIndirect->HTotalTime, PixelFormat) - 1);
WriteRegUlong(r_HsStart, CharToOctWord(VideoModeIndirect->HFrontPorch, PixelFormat));
WriteRegUlong(r_HsEnd, CharToOctWord(HSyncEnd, PixelFormat));
WriteRegUlong(r_HbEnd, CharToOctWord(HBlankWidth, PixelFormat));
VSyncEnd = VideoModeIndirect->VFrontPorch + VideoModeIndirect->VSyncTime;
VBlankWidth = VSyncEnd + VideoModeIndirect->VBackPorch;
WriteRegUlong(r_VTotal, VideoModeIndirect->VTotalTime - 1);
WriteRegUlong(r_VsStart, VideoModeIndirect->VFrontPorch - 1);
WriteRegUlong(r_VsEnd, VSyncEnd - 1);
WriteRegUlong(r_VbEnd, VBlankWidth);
// Setup the stride. Again, programed in 128 bit units (OctWords.)
WriteRegUlong(r_ScreenStride, ComputeStride(VideoMode, PixelFormat) / 16);
Exit(L"VideoSetMode");
}
ULONG
CharToOctWord(
ULONG CharCount,
USHORT PixelFormat
)
{
// CharToOctWord
// This function converts a character count into a 128 bit unit count. This
// conversion uses the current number of bits per pixel.
// Local variables.
ULONG OctWordCount; // Return value for this function.
// Check parameters.
Assert(PixelFormat < l_NumPixelTable);
Enter(L"CharToOctWord");
OctWordCount = (CharCount * PIXELS_PER_CHAR * l_PixelTable[PixelFormat].BitsPerPixel) / 128;
Exit(L"CharToOctWord");
return OctWordCount;
}
void
MiscSetMode(
USHORT VideoMode,
USHORT PixelFormat
)
{
// MiscSetMode
// This function handles all of the other misceleneous SetMode tasks not
// handled by the other *SetMode functions. This includes the interrupts
// and video FIFO. This function is not intended to be reuseable, but
// rather, serves to simplefy the SetMode call.
// Local variables.
ULONG VideoControl;
ULONG PixelSize;
ULONG AperturePixelSize;
// Check parameters.
Assert(VideoMode < l_NumVideoModeTable);
Assert(PixelFormat < l_NumPixelTable);
Enter(L"MiscSetMode");
WaitForInputFIFO(7);
// !TODO! Do something real here instead of just writing defaults. See
// video.c::360 for the iterative FifoControl formula for when interrupts
// are enabled.
WriteRegUlong(r_InterruptLine, 0);
// The << 8 sticks the high threshold value over the
// b_FifoControl_HighThreshold bits.
WriteMaskedRegUlong(r_FifoControl,
b_FifoControl_LowThreshold | b_FifoControl_HighThreshold,
(0x01) | (0x01 << 8));
// Set up video control. We do everything but renable the GP, which is done
// in the top level SetMode function.
VideoControl = 0;
// Set vertical and horizontal sync control to Active High. The RAMDAC will
// invert if necessary.
VideoControl |= (1 << 5);
VideoControl |= (1 << 3);
// Set buffer swap control to free running. We will use the interrupt to
// insure our flips are during the vertical blank period.
VideoControl |= (1 << 9);
// Set the SyncMode to SyncToVSA (!TODO! Why? What is this?)
VideoControl |= (1 << 16);
// Set the PixelSize appropriately.
PixelSize = 0;
switch (l_PixelTable[PixelFormat].BitsPerPixel) {
case 8:
VideoControl |= (0 << 19);
PixelSize |= 2;
AperturePixelSize = 0;
break;
case 16:
VideoControl |= (1 << 19);
PixelSize |= 1;
AperturePixelSize = 1;
break;
case 32:
VideoControl |= (2 << 19);
AperturePixelSize = 2;
break;
default:
Error(L"Unknown bits per pixel detected!\n");
break;
};
WriteMaskedRegUlong(r_VideoControl,
b_VideoControl_PixelSize |
b_VideoControl_SyncMode |
b_VideoControl_BufferSwap |
b_VideoControl_HSyncCtl |
b_VideoControl_VSyncCtl,
VideoControl);
// Drawing registers related to the display mode.
// Setup the screen scissor clipping.
WriteRegUlong(r_ScissorModeOr,
b_ScissorModeOr_ScreenScissorEnable);
WriteRegUlong(r_ScreenSize, PackXY(l_VideoModeTable[VideoMode].HResolution,
l_VideoModeTable[VideoMode].VResolution));
// Setup the pixel size in the drawing units.
WriteRegUlong(r_PixelSize, PixelSize);
// Setup the memory bypass registers.
WriteRegUlong(r_MemBypassWriteMask, 0xFFFFFFFF);
WriteRegUlong(r_ByAperture1Mode,
(AperturePixelSize << 5));
WriteRegUlong(r_ByAperture2Mode,
(AperturePixelSize << 5));
Exit(L"MiscSetMode");
}
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?