mode.c

来自「WinCE 3.0 BSP, 包含Inter SA1110, Intel_815」· C语言 代码 · 共 1,370 行 · 第 1/3 页

C
1,370
字号

PERM3_SURFACE *
GetPrimarySurface()
{
  // GetPrimarySurface
  // This function returns a PERM_SURFACE structure for the primary surface.
  // This can be used in the various drawing operation parameter structures,
  // as well as for other purposes. Includes virtual address of video memory
  // currently being DAC'd out of. No Enter/Exit semantics for inlined
  // functions.

  return (&l_PrimarySurface);
}

void
SetMode(
  ULONG DisplayMode
  )
{
  // SetMode
  // This routine changes the current display mode to the mode whose number is
  // passed.

  // Local variables.

  PERM3_BLT_PARAM BltParameters;
  RECT            DestRect;
  USHORT VideoMode;
  USHORT PixelFormat;

  // Check parameters.

  Assert(DisplayMode < GetDisplayModeCount());

  Enter(L"SetMode");

  VideoMode = l_DisplayModeTable[DisplayMode].VideoMode;
  PixelFormat = l_DisplayModeTable[DisplayMode].PixelFormat;

  // Disable the video for the duration of the mode set operation.

  WriteMaskedRegUlong(r_VideoControl, 
                      b_VideoControl_Enable,
                      0);

  // Step 1 : Program the RAMDAC, including the LUT.

  RamdacSetMode(VideoMode, PixelFormat);

  // Step 2 : Setup video.

  VideoSetMode(VideoMode, PixelFormat);

  // Step 3 : Program the primary surface.

  PrimarySurfaceSetMode(VideoMode, PixelFormat);

  // Step 4 : Setup everything else.

  MiscSetMode(VideoMode, PixelFormat);

  // Enable video!

  WriteMaskedRegUlong(r_VideoControl,
                      b_VideoControl_Enable,
                      b_VideoControl_Enable);

  // We're done. Store the new mode number.

  l_CurrentDisplayMode = DisplayMode;

  // Clear the primary surface with one quick blt.

  DestRect.left = 0;
  DestRect.top = 0;
  DestRect.right = l_PrimarySurface.Size.cx;
  DestRect.bottom = l_PrimarySurface.Size.cy;

  memset(&BltParameters, 0, sizeof(PERM3_BLT_PARAM));

  BltParameters.Destination = (const SURFACE *)&l_PrimarySurface;
  BltParameters.DestRect    = &DestRect;
  BltParameters.Rop         = 0x0000F0F0;  // PATCOPY
  BltParameters.PatternType = SolidPattern;
  BltParameters.FillValue   = 0x00000000;  // 0 is always black.

  HardwareBlt(&BltParameters);

  Exit(L"SetMode");
}

ULONG
ComputeStride(
  USHORT VideoMode,
  USHORT PixelFormat
  )
{
  // ComputeStride
  // This function computes the number of bytes necessary to provide enough
  // color data for one scan line in the display mode defined by the supplied
  // VideoMode and PixelFormat. Currently uses a simplistic formula: pixels
  // per line times bytes per pixel. This function returns an unsigned
  // number as we never use bottom-up bitmaps for the primary surface.

  // Local variables.

  ULONG Stride;  // Return value for this function.

  // Check parameters.

  Assert(VideoMode < l_NumVideoModeTable);
  Assert(PixelFormat < l_NumPixelTable);

  Enter(L"ComputeStride");

  Stride = l_VideoModeTable[VideoMode].HResolution * l_PixelTable[PixelFormat].BitsPerPixel / 8;

  Exit(L"ComputeStride");

  return Stride;
}

ULONG
ComputeMemRequired(
  USHORT VideoMode,
  USHORT PixelFormat
  )
{
  // ComputeMemRequired
  // This function computes the amount of video memory that's necessary for
  // a given display mode, as defined by the video mode and the pixel format
  // passed. Currently, this is a simplistic computation. It will become more
  // complex if palettized primaries are supported: you'll need space for the
  // palette.

  // Local variables.

  ULONG BytesRequired;  // Return value for this function.

  // Check parameters.

  Assert(VideoMode < l_NumVideoModeTable);
  Assert(PixelFormat < l_NumPixelTable);

  Enter(L"ComputeMemRequired");

  BytesRequired = ComputeStride(VideoMode, PixelFormat) * l_VideoModeTable[VideoMode].VResolution;

  Exit(L"ComputeMemRequired");

  return BytesRequired;
}

void
RamdacSetMode(
  USHORT VideoMode,
  USHORT PixelFormat
  )
{
  // RamdacSetMode
  // This function is the first step in setting a display mode : it programs
  // the Permedia3's Ramdac, including all of the clock setup including the
  // dot clock (DClk.) This function is not intended to be reuseable, rather
  // it makes the SetMode function much easir to read.

  // Local variables.

  ULONG LockTimeout;

  ULONG RefClkFrequency;

  ULONG DClkFrequency;
  ULONG KClkFrequency;
  ULONG SClkFrequency;
  ULONG MClkFrequency;

  ULONG i;
  
  BYTE  LinearRamp[NUM_LUT_ENTRIES];

  BYTE  DClkControl;
  BYTE  KClkControl;
  BYTE  SClkControl;
  BYTE  MClkControl;

  BYTE  M, N, P;

  BYTE  SyncControl;

  // Check parameters.

  Assert(VideoMode < l_NumVideoModeTable);
  Assert(PixelFormat < l_NumPixelTable);

  Enter(L"RamdacSetMode");
 
  // !TODO!  WaitForInputFIFO()

  // Make certain we do NOT autoincrement the index. It would mess up our
  // masked reads and writes.

  WriteRegByte(r_RDIndexControl, 0);

  // Setup sync signal polarity. (The shift left by 3 is to position the
  // vysnc polarity value over the b_RDSyncControl_VSyncCtl register.)

  SyncControl = (BYTE)(
                       (l_VideoModeTable[VideoMode].HSyncPolarity) |
                       (l_VideoModeTable[VideoMode].VSyncPolarity << 3)
                      );

  WriteMaskedRdReg(r_RDSyncControl,
                   b_RDSyncControl_HSyncCtl | b_RDSyncControl_VSyncCtl,
                   SyncControl);

  // Enable blank level pedestal.

  WriteMaskedRdReg(r_RDDACControl,
                   b_RDDACControl_BlankPedestal,
                   b_RDDACControl_BlankPedestal);

  // Stop all clocks.

  WriteRdReg(r_RDDClkControl, 0);
  WriteRdReg(r_RDKClkControl, 0);
  WriteRdReg(r_RDMClkControl, 0);
  WriteRdReg(r_RDSClkControl, 0);

  // !TODO! Use the HaveExtendedClocks and related data members of
  // PERM3_CONFIG.

  RefClkFrequency = DEFAULT_REFCLK_FREQUENCY; // 100 Hrtz units.
  SClkFrequency = DEFAULT_SCLK_FREQUENCY; // 100 Hrtz units.
  MClkFrequency = DEFAULT_MCLK_FREQUENCY; // 100 Hrtz units.

  // Startup the setup clock.

  SClkControl = 0;
  
  // The default source for the setup clock (SClk.) is KClk.
  // 6 << 4 is the same as setting b_RDSClkControl_Source = 6, or KClk.

  SClkControl |= (0x6 << 4);

  // Setting the b_RDSClkControl_Clock bit starts the clock.

  SClkControl |= b_RDSClkControl_Clock;

  // (2 << 2) is the bits to set b_RDSClkControl_State to 2 or Run.

  SClkControl |= (2 << 2);

  WriteMaskedRdReg(r_RDSClkControl,
                   b_RDSClkControl_Clock | 
                   b_RDSClkControl_State | 
                   b_RDSClkControl_Source,
                   SClkControl);

  // Startup the memory clock.

  MClkControl = 0;

  // The default source for the memory clock (MClk.) is KClk.
  // 6 << 4 is the same as setting b_RDMClkControl_Source = 6, or KClk.

  MClkControl |= (0x6 << 4);

   // Setting the b_RDMClkControl_Clock bit starts the clock.

  MClkControl |= b_RDMClkControl_Clock;

  // (2 << 2) is the bits to set b_RDMClkControl_State to 2 or Run.

  MClkControl |= (2 << 2);

  WriteMaskedRdReg(r_RDMClkControl,
                   b_RDMClkControl_Clock | 
                   b_RDMClkControl_State | 
                   b_RDMClkControl_Source,
                   MClkControl);

  // Now, we need to set up the pixel (or dot) clock (DClk.) We load both
  // of the selctable dot clock scale factors (Dclk2 and DClk3.)

  DClkFrequency = l_VideoModeTable[VideoMode].PixelClock;

  if (CalculateMNPForClock(RefClkFrequency,
                           DClkFrequency,
                           &M, &N, &P) == 0) {
    Error(L"Invalid dot clock!\n");
  }

  WriteRdReg(r_RDDClk2PreScale,      N);
  WriteRdReg(r_RDDClk2FeedbackScale, M);
  WriteMaskedRdReg(r_RDDClk2PostScale, b_RDDClk2PostScale_Scale, P);

  WriteRdReg(r_RDDClk3PreScale,      N);
  WriteRdReg(r_RDDClk3FeedbackScale, M);
  WriteMaskedRdReg(r_RDDClk3PostScale, b_RDDClk3PostScale_Scale, P);

  // Pick the RAMDAC control registers to control the DClk Pll.
  // We'll use set #3 (RDDClk3PreScale, RDDClk3PostScale, and 
  // RDDClk3FeedbackScale.)

  WriteRegUlong(r_VClkRDacCtl, 3);

  // Set up the KClk.

  // !TODO! Use the HaveExtendedClocks and related data members of
  // PERM3_CONFIG.

  KClkFrequency = DEFAULT_KCLK_FREQUENCY;  // In 100 Hrtz. units

  if (CalculateMNPForClock(RefClkFrequency,
                           KClkFrequency,
                           &M, &N, &P) == 0) {
    Error(L"Invalid core clock!\n");
  }


  WriteRdReg(r_RDKClkPreScale,      N);
  WriteRdReg(r_RDKClkFeedbackScale, M);
  WriteMaskedRdReg(r_RDKClkPostScale, b_RDKClkPostScale_Scale, P);

  // Enable the dot clock (DClk) then verify that it is working (by
  // waiting for it to lock.)

  DClkControl = 0;

  // Setting the b_RDDClkControl_Clock bit starts the clock.

  DClkControl |= b_RDDClkControl_Clock;

  // (2 << 2) is the bits to set b_RDDClkControl_State to 2 or Run.

  DClkControl |= (2 << 2);

  WriteMaskedRdReg(r_RDDClkControl,
                   b_RDDClkControl_Clock | 
                   b_RDDClkControl_State,
                   DClkControl);

  LockTimeout = LOCK_TIMEOUT;
  while ((ReadRdReg(r_RDDClkControl) & b_RDDClkControl_Lock) == 0 &&
         --LockTimeout);

  if (LockTimeout == 0) {
    Error(L"Pixel clock failed to lock.\n");
  }

  // Enable the core clock (KClk) then verify that it is working (by
  // waiting for it to lock.)

  KClkControl = 0;

  // Setting the b_RDKClkControl_Clock bit starts the clock.

  KClkControl |= b_RDKClkControl_Clock;

  // (2 << 2) is the bits to set b_RDKClkControl_State to 2 or Run.

  KClkControl |= (2 << 2);

  // (2 << 4) is the bits to set b_RDKClkControl_Source to 2, or the PLL.

  KClkControl |= (2 << 4);

  WriteMaskedRdReg(r_RDKClkControl,
                   b_RDKClkControl_Clock | 
                   b_RDKClkControl_State | 
                   b_RDKClkControl_Source,
                   KClkControl);

  LockTimeout = LOCK_TIMEOUT;
  while ((ReadRdReg(r_RDKClkControl) & b_RDKClkControl_Lock) == 0 &&
         --LockTimeout);

  if (LockTimeout == 0) {
    Error(L"Core clock failed to lock.\n");
  }

  // Setup the color format.

  WriteRdReg(r_RDColorFormat, l_PixelTable[PixelFormat].RDColorFormat);

  // Disable direct color. We do this for all bits per pixel sizes because,
  // we need the LUTs for gamma correction. Also, we need all 8 bits for
  // each entry in the palette, so enable "HighColorResolution"

  WriteMaskedRdReg(r_RDMiscControl,
                   b_RDMiscControl_DirectColor |
                   b_RDMiscControl_HighColorResolution,
                   b_RDMiscControl_HighColorResolution);

  // Setup the pixel size in the RAMDAC.

  if (l_PixelTable[PixelFormat].BitsPerPixel == 16) {

    WriteRdReg(r_RDPixelSize, 1);  // 1 == 16 Bpp.
  }
  else if (l_PixelTable[PixelFormat].BitsPerPixel == 32) {

    WriteRdReg(r_RDPixelSize, 2);  // 2 == 32 Bpp.
  }
  else {

    Error(L"Unknown bits per pixel detected!\n");
  }

  // Make sure we setup the pixel mask so that no bits are turned off by
  // the mask.

  WriteRegByte(r_RDPixelMask, 0xFF);

  // Setup the default LUT values for gamma correction. We will default to
  // a linear ramp for all three components as a default.

  for (i = 0; i < NUM_LUT_ENTRIES; i++) LinearRamp[i] = (BYTE)i;

  // No need to wait for v-sync for SetGammaRamp. The video is disabled.

  SetGammaRamp(LinearRamp, LinearRamp, LinearRamp);

  Exit(L"RamdacSetMode");
}

ULONG
CalculateMNPForClock(
  ULONG   RefClockFrequency,
  ULONG   RequiredFrequency,
  BYTE *  ReturnM,
  BYTE *  ReturnN,
  BYTE *  ReturnP
  )
{
  // CalculateMNPForClock
  // This function takes a desired clock frequency, the frequency of the
  // refrence clock and computes the necessary feedback scaler (M,)
  // prescaler (N,) and postscaler (P.) It usees the formula (from pg. 89
  // Permedia3 Programmer's Guide)
  //
  // OutputFrequency = (Refrence Clock Frequency * M) / (N * (1 << P))
  //
  // Both the desired frequency and the refrence clock frequency must be passed
  // in 100 Hrtz. units.
  //
  // We use an extra 2 in the computation for M becuase there is a clock
  // multiplier in the P3 that we need to consider. This is to say, we must
  // compute M, N and P as if we desired a clock speed 1/2 of what was given
  // to us. The Permedia will double the resulting frequency from the PLL. 
  //
  // Because we cannot match the exact frequency desired, we return the actual
  // frequncy that the values of M, N, and P returned will result in.
  //
  // VCO is the output frequency of the PLL. (it's the frequency of the
  // refrence clock after it's been multiplied by M and divided by N.)
  //

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?