Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1274 lines
36 KiB

  1. /***************************************************************************\
  2. *
  3. * ************************
  4. * * MINIPORT SAMPLE CODE *
  5. * ************************
  6. *
  7. * Module Name:
  8. *
  9. * video.c
  10. *
  11. * Abstract:
  12. *
  13. * This module contains the code to setup the timing values for chips
  14. * and RAMDACs
  15. *
  16. * Environment:
  17. *
  18. * Kernel mode
  19. *
  20. *
  21. * Copyright (c) 1994-1999 3Dlabs Inc. Ltd. All rights reserved.
  22. * Copyright (c) 1995-2003 Microsoft Corporation. All Rights Reserved.
  23. *
  24. \***************************************************************************/
  25. #include "perm3.h"
  26. #if defined(ALLOC_PRAGMA)
  27. #pragma alloc_text(PAGE,InitializeVideo)
  28. #pragma alloc_text(PAGE,P3RD_CalculateMNPForClock)
  29. #pragma alloc_text(PAGE,P4RD_CalculateMNPForClock)
  30. #pragma alloc_text(PAGE,SwitchToHiResMode)
  31. #pragma alloc_text(PAGE,Program_P3RD)
  32. #endif
  33. #define ROTATE_LEFT_DWORD(dWord,cnt) (((cnt) < 0) ? (dWord) >> ((-cnt)) : (dWord) << (cnt))
  34. #define ROTATE_RTIGHT_DWORD(dWord,cnt) (((cnt) < 0) ? (dWord) << ((-cnt)) : (dWord) >> (cnt))
  35. #define INITIALFREQERR 100000
  36. BOOLEAN
  37. InitializeVideo(
  38. PHW_DEVICE_EXTENSION HwDeviceExtension,
  39. PPERM3_VIDEO_FREQUENCIES VideoMode
  40. )
  41. {
  42. PHW_DEVICE_EXTENSION hwDeviceExtension = HwDeviceExtension;
  43. PVIDEO_MODE_INFORMATION VideoModeInfo = &VideoMode->ModeEntry->ModeInformation;
  44. LONG dShift, dStrideShift;
  45. VESA_TIMING_STANDARD VESATimings;
  46. ULONG ulValue;
  47. ULONG Htot, Hss, Hse, Hbe, Hsp;
  48. ULONG Vtot, Vss, Vse, Vbe, Vsp;
  49. ULONG PixelClock, Freq, MemClock;
  50. ULONG RefClkSpeed, SystemClock; // Speed of clocks in 100Hz units
  51. ULONG VTGPolarity;
  52. ULONG M, N, P, C, Q;
  53. ULONG DacDepth, depth, xRes, yRes;
  54. ULONG xStride;
  55. ULONG pixelData;
  56. ULONG ulMiscCtl;
  57. ULONG highWater, loWater;
  58. pPerm3ControlRegMap pCtrlRegs = hwDeviceExtension->ctrlRegBase[0];
  59. depth = VideoMode->BitsPerPel;
  60. xRes = VideoMode->ScreenWidth;
  61. yRes = VideoMode->ScreenHeight;
  62. Freq = VideoMode->ScreenFrequency;
  63. //
  64. // For timing calculations need full depth in bits
  65. //
  66. if ((DacDepth = depth) == 15) {
  67. DacDepth = 16;
  68. } else if (depth == 12) {
  69. DacDepth = 32;
  70. }
  71. //
  72. // Convert screen stride from bytes to pixels
  73. //
  74. xStride = (8 * VideoModeInfo->ScreenStride) / DacDepth;
  75. VideoDebugPrint((3, "Perm3: InitializeVideo called: depth %d, xres %d, yres %d, freq %d, xStride %d\n",
  76. depth, xRes, yRes, Freq, xStride));
  77. //
  78. // Ensure minimum frequency of 60 Hz
  79. //
  80. if ((Freq < 60) &&
  81. !(hwDeviceExtension->Perm3Capabilities & PERM3_DFP_MON_ATTACHED)) {
  82. VideoDebugPrint((3, "Perm3: Frequency raised to minimum of 60Hz\n"));
  83. Freq = 60;
  84. }
  85. //
  86. // Get the video timing, from the registry, if an entry exists, or from
  87. // the list of defaults, if it doesn't.
  88. //
  89. if( !GetVideoTiming(HwDeviceExtension,
  90. xRes,
  91. yRes,
  92. Freq,
  93. DacDepth,
  94. &VESATimings)) {
  95. VideoDebugPrint((0, "Perm3: GetVideoTiming failed."));
  96. return (FALSE);
  97. }
  98. //
  99. // We have got a valid set of VESA timigs
  100. // Extract timings from VESA list in a form that can be programmed into
  101. // the Perm3 timing generator.
  102. //
  103. Htot = GetHtotFromVESA (&VESATimings);
  104. Hss = GetHssFromVESA (&VESATimings);
  105. Hse = GetHseFromVESA (&VESATimings);
  106. Hbe = GetHbeFromVESA (&VESATimings);
  107. Hsp = GetHspFromVESA (&VESATimings);
  108. Vtot = GetVtotFromVESA (&VESATimings);
  109. Vss = GetVssFromVESA (&VESATimings);
  110. Vse = GetVseFromVESA (&VESATimings);
  111. Vbe = GetVbeFromVESA (&VESATimings);
  112. Vsp = GetVspFromVESA (&VESATimings);
  113. PixelClock = VESATimings.pClk;
  114. //
  115. // At 8BPP, if any of the horizontal parameters have any the bottom
  116. // bit set then we need to put the chip into 64-bit, pixel-doubling mode.
  117. //
  118. hwDeviceExtension->Perm3Capabilities &= ~PERM3_USE_BYTE_DOUBLING;
  119. //
  120. // If this resolution requires is one that requires pixel doubling then
  121. // set the flag
  122. //
  123. if (P3RD_CHECK_BYTE_DOUBLING(hwDeviceExtension, DacDepth, &VESATimings)) {
  124. hwDeviceExtension->Perm3Capabilities |= PERM3_USE_BYTE_DOUBLING;
  125. }
  126. VideoDebugPrint((3, "Perm3: P3RD %s require pixel-doubling, PXRXCaps 0x%x\n",
  127. (hwDeviceExtension->Perm3Capabilities & PERM3_USE_BYTE_DOUBLING) ? "Do" : "Don't",
  128. hwDeviceExtension->Perm3Capabilities));
  129. //
  130. // if we're zooming by 2 in Y then double the vertical timing values.
  131. //
  132. if (VideoModeInfo->DriverSpecificAttributeFlags & CAPS_ZOOM_Y_BY2) {
  133. Vtot *= 2;
  134. Vss *= 2;
  135. Vse *= 2;
  136. Vbe *= 2;
  137. PixelClock *= 2;
  138. }
  139. pixelData = PixelClock * (DacDepth / 8);
  140. if (pixelData > P3_MAX_PIXELDATA) {
  141. //
  142. // Failed pixelData validation
  143. //
  144. return (FALSE);
  145. }
  146. RefClkSpeed = hwDeviceExtension->RefClockSpeed / 100; // 100Hz units
  147. SystemClock = hwDeviceExtension->ChipClockSpeed / 100; // 100Hz units
  148. //
  149. // We do some basic initialization before setting up MCLK.
  150. //
  151. //
  152. // disable the video control register
  153. //
  154. hwDeviceExtension->VideoControl = 0;
  155. VideoPortWriteRegisterUlong( VIDEO_CONTROL,
  156. hwDeviceExtension->VideoControl );
  157. SwitchToHiResMode(hwDeviceExtension, TRUE);
  158. //
  159. // Setup Ramdac.
  160. //
  161. if(!Program_P3RD(HwDeviceExtension,
  162. VideoMode,
  163. Hsp,
  164. Vsp,
  165. RefClkSpeed,
  166. &SystemClock,
  167. &PixelClock,
  168. &MemClock)) {
  169. return(FALSE);
  170. }
  171. //
  172. // Set the LUT cache size to 256 and the first entry to zero, then
  173. // write the LUT cache to the LUT
  174. //
  175. LUT_CACHE_SETSIZE (256);
  176. LUT_CACHE_SETFIRST (0);
  177. (VOID) Perm3SetColorLookup (hwDeviceExtension,
  178. &(hwDeviceExtension->LUTCache.LUTCache),
  179. sizeof (hwDeviceExtension->LUTCache),
  180. TRUE, // Always update RAMDAC
  181. FALSE); // Don't Update cache entries
  182. //
  183. // Setup VTG
  184. //
  185. //
  186. // We have to set or clear byte doubling for Perm3,depending on
  187. //the whether the byte doubling capabilities flag is set.
  188. //
  189. ulMiscCtl = VideoPortReadRegisterUlong(MISC_CONTROL);
  190. ulMiscCtl &= ~PXRX_MISC_CONTROL_BYTE_DBL_ENABLE;
  191. ulMiscCtl |= (hwDeviceExtension->Perm3Capabilities & PERM3_USE_BYTE_DOUBLING) ?
  192. PXRX_MISC_CONTROL_BYTE_DBL_ENABLE : 0;
  193. VideoPortWriteRegisterUlong(MISC_CONTROL, ulMiscCtl);
  194. //
  195. // RAMDAC pll pins for VClkCtl
  196. //
  197. ulValue = 3;
  198. //
  199. // dShift is now used as a rotate count (it can be negative), instead of a
  200. // shift count. This means it won't work with 24-bit packed framebuffer
  201. // layouts.
  202. //
  203. if (hwDeviceExtension->Perm3Capabilities & PERM3_USE_BYTE_DOUBLING) {
  204. //
  205. // Pretend we have a 64-bit pixel bus
  206. //
  207. dShift = DacDepth >> 4;
  208. } else if (DacDepth > 8) {
  209. //
  210. // 128-bit pixel bus
  211. //
  212. dShift = DacDepth >> 5;
  213. } else {
  214. //
  215. // We need a shift right not left
  216. //
  217. dShift = -1;
  218. }
  219. //
  220. // Stride & screenBase in 128-bit units
  221. //
  222. dStrideShift = 4;
  223. //
  224. // must load HgEnd before ScreenBase
  225. //
  226. VideoPortWriteRegisterUlong(HG_END, ROTATE_LEFT_DWORD (Hbe, dShift));
  227. VideoPortWriteRegisterUlong(V_CLK_CTL, ulValue);
  228. //
  229. // We just load the right screenbase with zero (the same as the left).
  230. // The display driver will update this when stereo buffers have been
  231. // allocated and stereo apps start running.
  232. //
  233. VideoPortWriteRegisterUlong(SCREEN_BASE_RIGHT, 0);
  234. VideoPortWriteRegisterUlong(SCREEN_BASE,0);
  235. VideoPortWriteRegisterUlong(SCREEN_STRIDE, (xStride >> dStrideShift) * (DacDepth >> 3)); // 64-bit units
  236. VideoPortWriteRegisterUlong(H_TOTAL,(ROTATE_LEFT_DWORD (Htot, dShift)) - 1);
  237. VideoPortWriteRegisterUlong(HS_START, ROTATE_LEFT_DWORD (Hss, dShift));
  238. VideoPortWriteRegisterUlong(HS_END, ROTATE_LEFT_DWORD (Hse, dShift));
  239. VideoPortWriteRegisterUlong(HB_END, ROTATE_LEFT_DWORD (Hbe, dShift));
  240. VideoPortWriteRegisterUlong(V_TOTAL, Vtot - 1);
  241. VideoPortWriteRegisterUlong(VS_START, Vss - 1);
  242. VideoPortWriteRegisterUlong(VS_END, Vse - 1);
  243. VideoPortWriteRegisterUlong(VB_END, Vbe);
  244. //
  245. // We need this to ensure that we get interrupts at the right time
  246. //
  247. VideoPortWriteRegisterUlong (INTERRUPT_LINE, 0);
  248. //
  249. // Set up video fifo stuff for Perm3
  250. //
  251. if(hwDeviceExtension->Capabilities & CAPS_INTERRUPTS) {
  252. //
  253. // We can use our reiterative formula. We start by setting
  254. // the thresholds to sensible values for a lo-res mode
  255. // (640x480x8) then turn on the FIFO underrun error interrupt
  256. // (we do this after the mode change to avoid spurious
  257. // interrupts). In the interrupt routine we adjust the
  258. // thresholds whenever we get an underrun error
  259. //
  260. loWater = 8;
  261. highWater = 28;
  262. hwDeviceExtension->VideoFifoControl = (1 << 16) | (highWater << 8) | loWater;
  263. //
  264. // we'll want check for video FIFO errors via the error
  265. // interrupt only for a short time as P3/R3 generates a
  266. // lot of spurious interrupts too. Use the VBLANK interrupt
  267. // to time the period that we keep error interrupts enabled
  268. //
  269. hwDeviceExtension->VideoFifoControlCountdown = 20 * Freq;
  270. //
  271. // Don't actually update this register until we've left
  272. // InitializeVideo - we don't want to enable error interrupts
  273. // until the mode change has settled
  274. //
  275. hwDeviceExtension->IntEnable |= INTR_ERROR_SET | INTR_VBLANK_SET;
  276. //
  277. // We want VBLANK interrupts permanently enabled so that we
  278. // can monitor error flags for video FIFO underruns
  279. //
  280. hwDeviceExtension->InterruptControl.ControlBlock.Control |= PXRX_CHECK_VFIFO_IN_VBLANK;
  281. } else {
  282. //
  283. // We don't have interrupts calculate safe thresholds for
  284. // this mode. The high threshold can be determined using
  285. // the following formula.
  286. //
  287. highWater = ((PixelClock / 80) * (33 * DacDepth)) / MemClock;
  288. if (highWater < 28) {
  289. highWater = 28 - highWater;
  290. //
  291. // Low threshhold should be the lower of highWater/2 or 8.
  292. //
  293. loWater = (highWater + 1) / 2;
  294. if (loWater > 8)
  295. loWater = 8;
  296. } else {
  297. //
  298. // We don't have an algorithm for this so choose a safe value
  299. //
  300. highWater = 0x01;
  301. loWater = 0x01;
  302. }
  303. hwDeviceExtension->VideoFifoControl = (highWater << 8) | loWater;
  304. }
  305. VideoPortWriteRegisterUlong(VIDEO_FIFO_CTL, hwDeviceExtension->VideoFifoControl);
  306. //
  307. // On a Perm3 set up the memory refresh counter
  308. // Memory refresh needs to be 64000 times per second.
  309. //
  310. ulValue = ((MemClock/640) - 16) / 32;
  311. VideoPortWriteRegisterUlong(PXRX_LOCAL_MEM_REFRESH, (ulValue << 1) | 1);
  312. VideoDebugPrint((3, "Perm3: Setting LocalMemRefresh to 0x%x\n",
  313. (ulValue << 1) | 1));
  314. //
  315. // enable H & V syncs to active high (the RAMDAC will invert these as necessary)
  316. // Enable video out.
  317. //
  318. VTGPolarity = (1 << 5) | (1 << 3) | 1;
  319. //
  320. // Set BufferSwapCtl to FreeRunning
  321. //
  322. VTGPolarity |= (1 << 9);
  323. //
  324. // Set up pixel size, this register is only on PXRX.
  325. //
  326. if (DacDepth == 8) {
  327. VTGPolarity |= (0 << 19);
  328. } else if (DacDepth == 16) {
  329. VTGPolarity |= (1 << 19);
  330. } else if (DacDepth == 32) {
  331. VTGPolarity |= (2 << 19);
  332. }
  333. //
  334. // Do not Pitch
  335. //
  336. VTGPolarity |= (0 << 18);
  337. //
  338. // Set the stereo bit if it's enabled.
  339. //
  340. if(hwDeviceExtension->Capabilities & CAPS_STEREO) {
  341. VTGPolarity |= (1 << 11);
  342. //
  343. // Set RightEyeCtl bit to 1 as default
  344. //
  345. VTGPolarity |= (1 << 12);
  346. }
  347. if (VideoModeInfo->DriverSpecificAttributeFlags & CAPS_ZOOM_Y_BY2) {
  348. VTGPolarity |= (1 << 2);
  349. }
  350. hwDeviceExtension->VideoControlMonitorON = VTGPolarity & VC_DPMS_MASK;
  351. hwDeviceExtension->VideoControl = VTGPolarity;
  352. VideoPortWriteRegisterUlong( VIDEO_CONTROL,
  353. hwDeviceExtension->VideoControl );
  354. //
  355. // Record the final chip clock in the registry
  356. //
  357. SystemClock *= 100;
  358. VideoPortSetRegistryParameters(HwDeviceExtension,
  359. L"HardwareInformation.CurrentChipClockSpeed",
  360. &SystemClock,
  361. sizeof(ULONG));
  362. MemClock *= 100;
  363. VideoPortSetRegistryParameters(HwDeviceExtension,
  364. L"HardwareInformation.CurrentMemClockSpeed",
  365. &MemClock,
  366. sizeof(ULONG));
  367. PixelClock *= 100;
  368. VideoPortSetRegistryParameters(HwDeviceExtension,
  369. L"HardwareInformation.CurrentPixelClockSpeed",
  370. &PixelClock,
  371. sizeof(ULONG));
  372. hwDeviceExtension->bVTGRunning = TRUE;
  373. VideoDebugPrint((3, "Perm3: InitializeVideo Finished\n"));
  374. return(TRUE);
  375. }
  376. ULONG
  377. P3RD_CalculateMNPForClock(
  378. PVOID HwDeviceExtension,
  379. ULONG RefClock, // In 100Hz units
  380. ULONG ReqClock, // In 100Hz units
  381. ULONG *rM, // M Out (feedback scaler)
  382. ULONG *rN, // N Out (prescaler)
  383. ULONG *rP // P Out (postscaler)
  384. )
  385. /*+++
  386. Routine Description:
  387. Calculates prescaler, feedback scaler and postscaler values for the
  388. STMACRO PLL71FS used by P3RD.
  389. ---*/
  390. {
  391. const ULONG fMinVCO = 2000000; // min fVCO is 200MHz (in 100Hz units)
  392. const ULONG fMaxVCO = 6220000; // max fVCO is 622MHz (in 100Hz units)
  393. const ULONG fMinINTREF = 10000; // min fINTREF is 1MHz (in 100Hz units)
  394. const ULONG fMaxINTREF = 20000; // max fINTREF is 2MHz (in 100Hz units)
  395. ULONG M, N, P;
  396. ULONG fINTREF;
  397. ULONG fVCO;
  398. ULONG ActualClock;
  399. LONG Error;
  400. LONG LowestError = INITIALFREQERR;
  401. BOOLEAN bFoundFreq = FALSE;
  402. LONG cInnerLoopIterations = 0;
  403. LONG LoopCount;
  404. ULONG fVCOLowest, fVCOHighest;
  405. for(P = 0; P <= 5; ++P) {
  406. //
  407. // it's pointless going through the main loop if all values of
  408. // N produce an fVCO outside the acceptable range
  409. //
  410. N = 1;
  411. M = (N * (1 << P) * ReqClock) / (2 * RefClock);
  412. fVCOLowest = (2 * RefClock * M) / N;
  413. N = 255;
  414. M = (N * (1 << P) * ReqClock) / (2 * RefClock);
  415. fVCOHighest = (2 * RefClock * M) / N;
  416. if(fVCOHighest < fMinVCO || fVCOLowest > fMaxVCO) {
  417. continue;
  418. }
  419. for(N = 1; N <= 255; ++N, ++cInnerLoopIterations) {
  420. fINTREF = RefClock / N;
  421. if(fINTREF < fMinINTREF || fINTREF > fMaxINTREF) {
  422. if(fINTREF > fMaxINTREF){
  423. //
  424. // hopefully we'll get into range as the prescale value
  425. // increases
  426. //
  427. continue;
  428. } else {
  429. //
  430. // already below minimum and it'll only get worse: move to
  431. // the next postscale value
  432. //
  433. break;
  434. }
  435. }
  436. M = (N * (1 << P) * ReqClock) / (2 * RefClock);
  437. if(M > 255) {
  438. //
  439. // M, N & P registers are only 8 bits wide
  440. //
  441. break;
  442. }
  443. //
  444. // We can expect rounding errors in calculating M, which will
  445. // always be rounded down. So we'll checkout our calculated
  446. // value of M along with (M+1)
  447. //
  448. for(LoopCount = (M == 255) ? 1 : 2; --LoopCount >= 0; ++M) {
  449. fVCO = (2 * RefClock * M) / N;
  450. if(fVCO >= fMinVCO && fVCO <= fMaxVCO) {
  451. ActualClock = fVCO / (1 << P);
  452. Error = ActualClock - ReqClock;
  453. if(Error < 0)
  454. Error = -Error;
  455. if(Error < LowestError) {
  456. bFoundFreq = TRUE;
  457. LowestError = Error;
  458. *rM = M;
  459. *rN = N;
  460. *rP = P;
  461. if(Error == 0)
  462. goto Done;
  463. }
  464. }
  465. }
  466. }
  467. }
  468. Done:
  469. if(bFoundFreq)
  470. ActualClock = (2 * RefClock * (*rM)) / ((*rN) * (1 << (*rP)));
  471. else
  472. ActualClock = 0;
  473. return(ActualClock);
  474. }
  475. ULONG P4RD_CalculateMNPForClock(
  476. PVOID hwDeviceExtension,
  477. ULONG RefClock, // In 100Hz units
  478. ULONG ReqClock, // In 100Hz units
  479. ULONG *rM, // M Out (feedback scaler)
  480. ULONG *rN, // N Out (prescaler)
  481. ULONG *rP // P Out (postscaler)
  482. )
  483. /*+++
  484. Routine Description:
  485. Calculates prescaler, feedback scaler and postscaler values for the
  486. nurlogic NLC_PLL260i used by P4RD.
  487. ---*/
  488. {
  489. const ULONG fMinVCO = 2000000; // min fVCO is 200MHz (in 100Hz units)
  490. const ULONG fMaxVCO = 4000000; // max fVCO is 400MHz (in 100Hz units)
  491. const ULONG fMinINTREF = 10000; // min fINTREF is 1MHz (in 100Hz units)
  492. const ULONG fMaxINTREF = 20000; // max fINTREF is 2MHz (in 100Hz units)
  493. ULONG M, N, P;
  494. ULONG fINTREF;
  495. ULONG fVCO;
  496. ULONG ActualClock;
  497. LONG Error;
  498. LONG LowestError = INITIALFREQERR;
  499. BOOLEAN bFoundFreq = FALSE;
  500. LONG cInnerLoopIterations = 0;
  501. LONG LoopCount;
  502. //
  503. // Actual Equations:
  504. // fVCO = (RefClock * M)/(N+1)
  505. // PIXELCLOCK = fVCO/(1<<p)
  506. // 200 <= fVCO <= 400
  507. // 24 <= M <= 80
  508. // 1 <= N <= 15
  509. // 0 <= P <= 3
  510. // 1Mhz < RefClock/(N+1) <= 2Mhz - not used
  511. //
  512. // For refclk == 14.318 we have the tighter equations:
  513. // 32 <= M <= 80
  514. // 3 <= N <= 12
  515. #define P4RD_PLL_MIN_P 0
  516. #define P4RD_PLL_MAX_P 3
  517. #define P4RD_PLL_MIN_N 1
  518. #define P4RD_PLL_MAX_N 12
  519. #define P4RD_PLL_MIN_M 24
  520. #define P4RD_PLL_MAX_M 80
  521. for(P = P4RD_PLL_MIN_P; P <= P4RD_PLL_MAX_P; ++P) {
  522. ULONG fVCOLowest, fVCOHighest;
  523. //
  524. // It's pointless going through the main loop if all values
  525. // of N produce an fVCO outside the acceptable range
  526. //
  527. N = P4RD_PLL_MIN_N;
  528. M = ((N + 1) * (1 << P) * ReqClock) / RefClock;
  529. fVCOLowest = (RefClock * M) / (N + 1);
  530. N = P4RD_PLL_MAX_N;
  531. M = ((N + 1) * (1 << P) * ReqClock) / RefClock;
  532. fVCOHighest = (RefClock * M) / (N + 1);
  533. if(fVCOHighest < fMinVCO || fVCOLowest > fMaxVCO) {
  534. continue;
  535. }
  536. for( N = P4RD_PLL_MIN_N;
  537. N <= P4RD_PLL_MAX_N;
  538. ++N, ++cInnerLoopIterations ) {
  539. M = ((N + 1) * (1 << P) * ReqClock) / RefClock;
  540. if(M > P4RD_PLL_MAX_M || M < P4RD_PLL_MIN_M) {
  541. //
  542. // M is only 7 bits wide
  543. //
  544. continue;
  545. }
  546. //
  547. // We can expect rounding errors in calculating M, which
  548. // will always be rounded down. So we'll checkout our
  549. // calculated value of M along with (M+1)
  550. //
  551. for( LoopCount = (M == P4RD_PLL_MAX_M) ? 1 : 2;
  552. --LoopCount >= 0;
  553. ++M ) {
  554. fVCO = (RefClock * M) / (N + 1);
  555. if(fVCO >= fMinVCO && fVCO <= fMaxVCO) {
  556. ActualClock = fVCO / (1 << P);
  557. Error = ActualClock - ReqClock;
  558. if(Error < 0)
  559. Error = -Error;
  560. //
  561. // It is desirable that we use the lowest value of N if the
  562. // frequencies are the same.
  563. //
  564. if((Error < LowestError) ||
  565. (Error == LowestError && N < *rN)) {
  566. bFoundFreq = TRUE;
  567. LowestError = Error;
  568. *rM = M;
  569. *rN = N;
  570. *rP = P;
  571. if(Error == 0)
  572. goto Done;
  573. }
  574. }
  575. }
  576. }
  577. }
  578. Done:
  579. if(bFoundFreq)
  580. ActualClock = (RefClock * (*rM)) / (((*rN) + 1) * (1 <<(*rP)));
  581. else
  582. ActualClock = 0;
  583. return(ActualClock);
  584. }
  585. BOOLEAN Program_P3RD(
  586. PHW_DEVICE_EXTENSION HwDeviceExtension,
  587. PPERM3_VIDEO_FREQUENCIES VideoMode,
  588. ULONG Hsp,
  589. ULONG Vsp,
  590. ULONG RefClkSpeed,
  591. PULONG pSystemClock,
  592. PULONG pPixelClock,
  593. PULONG pMemClock
  594. )
  595. /*+++
  596. Routine Description:
  597. Initializes the P3RD registers and programs the DClk (pixel clock)
  598. and MClk (system clock) PLLs. After programming the MClk, the
  599. contents of all registers in the graphics core, the memory controller
  600. and the video control should be assumed to be undefined
  601. ---*/
  602. {
  603. PHW_DEVICE_EXTENSION hwDeviceExtension = HwDeviceExtension;
  604. PVIDEO_MODE_INFORMATION VideoModeInfo = &VideoMode->ModeEntry->ModeInformation;
  605. ULONG DacDepth, depth;
  606. ULONG index;
  607. ULONG color;
  608. ULONG ulValue;
  609. UCHAR pixelCtrl;
  610. ULONG mClkSrc = 0, sClkSrc = 0;
  611. VP_STATUS status;
  612. ULONG M, N, P;
  613. //
  614. // If we are using 64-bit mode then we need to double the pixel
  615. // clock and set the pixel doubling bit in the RAMDAC.
  616. //
  617. ULONG pixelClock = (hwDeviceExtension->Perm3Capabilities & PERM3_USE_BYTE_DOUBLING) ? (*pPixelClock) << 1 : (*pPixelClock);
  618. //
  619. // Double the desired system clock as P3 has a divider, which divides
  620. // this down again.
  621. //
  622. ULONG coreClock = (*pSystemClock << 1);
  623. pPerm3ControlRegMap pCtrlRegs = hwDeviceExtension->ctrlRegBase[0];
  624. P3RDRAMDAC *pP3RDRegs = (P3RDRAMDAC *)hwDeviceExtension->pRamdac;
  625. mClkSrc = (hwDeviceExtension->bHaveExtendedClocks ? hwDeviceExtension->ulPXRXMemoryClockSrc : P3RD_DEFAULT_MCLK_SRC);
  626. sClkSrc = (hwDeviceExtension->bHaveExtendedClocks ? hwDeviceExtension->ulPXRXSetupClockSrc: P3RD_DEFAULT_SCLK_SRC);
  627. depth = VideoMode->BitsPerPel;
  628. //
  629. // For timing calculations need full depth in bits
  630. //
  631. if ((DacDepth = depth) == 15) {
  632. DacDepth = 16;
  633. }
  634. else if (depth == 12) {
  635. DacDepth = 32;
  636. }
  637. //
  638. // Set up Misc Control
  639. //
  640. P3RD_READ_INDEX_REG(P3RD_MISC_CONTROL, ulValue);
  641. ulValue &= ~( P3RD_MISC_CONTROL_HIGHCOLORRES |
  642. P3RD_MISC_CONTROL_DIRECT_COLOR_ENABLED |
  643. P3RD_MISC_CONTROL_PIXEL_DOUBLE );
  644. P3RD_LOAD_INDEX_REG(P3RD_MISC_CONTROL,
  645. ulValue |
  646. P3RD_MISC_CONTROL_HIGHCOLORRES |
  647. P3RD_MISC_CONTROL_DIRECT_COLOR_ENABLED);
  648. VideoPortWriteRegisterUlong(P3RD_INDEX_CONTROL,
  649. P3RD_IDX_CTL_AUTOINCREMENT_ENABLED);
  650. ulValue = (Hsp ? P3RD_SYNC_CONTROL_HSYNC_ACTIVE_HIGH : P3RD_SYNC_CONTROL_HSYNC_ACTIVE_LOW) |
  651. (Vsp ? P3RD_SYNC_CONTROL_VSYNC_ACTIVE_HIGH : P3RD_SYNC_CONTROL_VSYNC_ACTIVE_LOW);
  652. P3RD_LOAD_INDEX_REG(P3RD_SYNC_CONTROL, ulValue);
  653. P3RD_LOAD_INDEX_REG(P3RD_DAC_CONTROL,
  654. P3RD_DAC_CONTROL_BLANK_PEDESTAL_ENABLED);
  655. ulValue = 0;
  656. if (hwDeviceExtension->Perm3Capabilities & PERM3_USE_BYTE_DOUBLING) {
  657. ulValue |= P3RD_CURSOR_CONTROL_DOUBLE_X;
  658. }
  659. if (VideoModeInfo->DriverSpecificAttributeFlags & CAPS_ZOOM_Y_BY2) {
  660. ulValue |= P3RD_CURSOR_CONTROL_DOUBLE_Y;
  661. }
  662. P3RD_LOAD_INDEX_REG(P3RD_CURSOR_CONTROL, ulValue);
  663. P3RD_LOAD_INDEX_REG(P3RD_CURSOR_MODE, 0);
  664. P3RD_LOAD_INDEX_REG(P3RD_CURSOR_X_LOW, 0);
  665. P3RD_LOAD_INDEX_REG(P3RD_CURSOR_X_HIGH, 0);
  666. P3RD_LOAD_INDEX_REG(P3RD_CURSOR_Y_LOW, 0);
  667. P3RD_LOAD_INDEX_REG(P3RD_CURSOR_Y_HIGH, 0xff);
  668. P3RD_LOAD_INDEX_REG(P3RD_CURSOR_HOTSPOT_X, 0);
  669. P3RD_LOAD_INDEX_REG(P3RD_CURSOR_HOTSPOT_Y, 0);
  670. P3RD_LOAD_INDEX_REG(P3RD_PAN, 0);
  671. //
  672. // The first 3-color cursor is the mini cursor which is always
  673. // black & white. Set it up here
  674. P3RD_CURSOR_PALETTE_CURSOR_RGB(P3RD_CALCULATE_LUT_INDEX(0), 0x00,0x00,0x00);
  675. P3RD_CURSOR_PALETTE_CURSOR_RGB(P3RD_CALCULATE_LUT_INDEX(1), 0xff,0xff,0xff);
  676. //
  677. // Stop all clocks
  678. //
  679. P3RD_LOAD_INDEX_REG(P3RD_DCLK_CONTROL, 0);
  680. P3RD_LOAD_INDEX_REG(P3RD_KCLK_CONTROL, 0);
  681. P3RD_LOAD_INDEX_REG(P3RD_MCLK_CONTROL, 0);
  682. P3RD_LOAD_INDEX_REG(P3RD_SCLK_CONTROL, 0);
  683. //
  684. // Belt and braces let's set MCLK to something just in case
  685. // Let's enable SCLK and MCLK.
  686. //
  687. *pMemClock = PERMEDIA3_DEFAULT_MCLK_SPEED / 100; // Convert from Hz to 100 Hz
  688. VideoDebugPrint((3, "Perm3: Program_P3RD: mClkSrc 0x%x, sClkSrc 0x%x, mspeed %d00\n",
  689. mClkSrc, sClkSrc, *pMemClock));
  690. P3RD_LOAD_INDEX_REG(P3RD_MCLK_CONTROL,
  691. P3RD_MCLK_CONTROL_ENABLED |
  692. P3RD_MCLK_CONTROL_RUN | mClkSrc);
  693. P3RD_LOAD_INDEX_REG(P3RD_SCLK_CONTROL,
  694. P3RD_SCLK_CONTROL_ENABLED |
  695. P3RD_SCLK_CONTROL_RUN |
  696. sClkSrc);
  697. if (hwDeviceExtension->deviceInfo.DeviceId == PERMEDIA3_ID ) {
  698. pixelClock = P3RD_CalculateMNPForClock(HwDeviceExtension,
  699. RefClkSpeed,
  700. pixelClock,
  701. &M,
  702. &N,
  703. &P);
  704. } else {
  705. pixelClock = P4RD_CalculateMNPForClock(HwDeviceExtension,
  706. RefClkSpeed,
  707. pixelClock,
  708. &M,
  709. &N,
  710. &P);
  711. }
  712. if(pixelClock == 0) {
  713. VideoDebugPrint((0, "Perm3: Program_P3RD: P3RD_CalculateMNPForClock(PixelClock) failed\n"));
  714. return(FALSE);
  715. }
  716. //
  717. // load both copies of the dot clock with our times (DCLK0 & DCLK1 reserved for VGA only)
  718. //
  719. P3RD_LOAD_INDEX_REG(P3RD_DCLK2_PRE_SCALE, N);
  720. P3RD_LOAD_INDEX_REG(P3RD_DCLK2_FEEDBACK_SCALE, M);
  721. P3RD_LOAD_INDEX_REG(P3RD_DCLK2_POST_SCALE, P);
  722. P3RD_LOAD_INDEX_REG(P3RD_DCLK3_PRE_SCALE, N);
  723. P3RD_LOAD_INDEX_REG(P3RD_DCLK3_FEEDBACK_SCALE, M);
  724. P3RD_LOAD_INDEX_REG(P3RD_DCLK3_POST_SCALE, P);
  725. if (hwDeviceExtension->deviceInfo.DeviceId == PERMEDIA3_ID ) {
  726. coreClock = P3RD_CalculateMNPForClock(HwDeviceExtension,
  727. RefClkSpeed,
  728. coreClock,
  729. &M,
  730. &N,
  731. &P);
  732. } else {
  733. coreClock = P4RD_CalculateMNPForClock(HwDeviceExtension,
  734. RefClkSpeed,
  735. coreClock,
  736. &M,
  737. &N,
  738. &P);
  739. }
  740. if(coreClock == 0) {
  741. VideoDebugPrint((0, "Perm3: Program_P3RD: P3RD_CalculateMNPForClock(SystemClock) failed\n"));
  742. return(FALSE);
  743. }
  744. //
  745. // load the core clock
  746. //
  747. P3RD_LOAD_INDEX_REG(P3RD_KCLK_PRE_SCALE, N);
  748. P3RD_LOAD_INDEX_REG(P3RD_KCLK_FEEDBACK_SCALE, M);
  749. P3RD_LOAD_INDEX_REG(P3RD_KCLK_POST_SCALE, P);
  750. //
  751. // Enable the dot clock
  752. //
  753. P3RD_LOAD_INDEX_REG(P3RD_DCLK_CONTROL,
  754. P3RD_DCLK_CONTROL_ENABLED | P3RD_DCLK_CONTROL_RUN);
  755. M = 0x100000;
  756. do {
  757. P3RD_READ_INDEX_REG(P3RD_DCLK_CONTROL, ulValue);
  758. }
  759. while((ulValue & P3RD_DCLK_CONTROL_LOCKED) == FALSE && --M);
  760. if((ulValue & P3RD_DCLK_CONTROL_LOCKED) == FALSE) {
  761. VideoDebugPrint((0, "Perm3: Program_P3RD: PixelClock failed to lock\n"));
  762. return(FALSE);
  763. }
  764. //
  765. // Enable the core clock
  766. //
  767. P3RD_LOAD_INDEX_REG(P3RD_KCLK_CONTROL,
  768. P3RD_KCLK_CONTROL_ENABLED |
  769. P3RD_KCLK_CONTROL_RUN |
  770. P3RD_KCLK_CONTROL_PLL);
  771. M = 0x100000;
  772. do {
  773. P3RD_READ_INDEX_REG(P3RD_KCLK_CONTROL, ulValue);
  774. }
  775. while((ulValue & P3RD_KCLK_CONTROL_LOCKED) == FALSE && --M);
  776. if((ulValue & P3RD_KCLK_CONTROL_LOCKED) == FALSE) {
  777. VideoDebugPrint((0, "Perm3: Program_P3RD: SystemClock failed to lock\n"));
  778. return(FALSE);
  779. }
  780. switch (depth) {
  781. case 8:
  782. P3RD_READ_INDEX_REG(P3RD_MISC_CONTROL, ulValue);
  783. ulValue &= ~P3RD_MISC_CONTROL_DIRECT_COLOR_ENABLED;
  784. P3RD_LOAD_INDEX_REG(P3RD_MISC_CONTROL, ulValue);
  785. P3RD_LOAD_INDEX_REG(P3RD_PIXEL_SIZE, P3RD_PIXEL_SIZE_8BPP);
  786. //
  787. // Color indexed mode
  788. //
  789. P3RD_LOAD_INDEX_REG(P3RD_COLOR_FORMAT,
  790. P3RD_COLOR_FORMAT_CI8 | P3RD_COLOR_FORMAT_RGB);
  791. break;
  792. case 15:
  793. case 16:
  794. P3RD_LOAD_INDEX_REG(P3RD_PIXEL_SIZE, P3RD_PIXEL_SIZE_16BPP);
  795. #if GAMMA_CORRECTION
  796. P3RD_READ_INDEX_REG(P3RD_MISC_CONTROL, ulValue);
  797. ulValue &= ~P3RD_MISC_CONTROL_DIRECT_COLOR_ENABLED;
  798. P3RD_LOAD_INDEX_REG(P3RD_MISC_CONTROL, ulValue);
  799. //
  800. // load linear ramp into LUT as default
  801. //
  802. for (index = 0; index <= 0xff; ++index) {
  803. LUT_CACHE_SETRGB (index, index, index, index);
  804. }
  805. pixelCtrl = 0;
  806. #else
  807. P3RD_READ_INDEX_REG(P3RD_MISC_CONTROL, ulValue);
  808. ulValue |= P3RD_MISC_CONTROL_DIRECT_COLOR_ENABLED;
  809. P3RD_LOAD_INDEX_REG(P3RD_MISC_CONTROL, ulValue);
  810. pixelCtrl = P3RD_COLOR_FORMAT_LINEAR_EXT;
  811. #endif
  812. pixelCtrl |= (depth == 16) ? P3RD_COLOR_FORMAT_16BPP : P3RD_COLOR_FORMAT_15BPP;
  813. pixelCtrl |= P3RD_COLOR_FORMAT_RGB;
  814. VideoDebugPrint((3, "Perm3: P3RD_COLOR_FORMAT = 0x%x\n", pixelCtrl));
  815. P3RD_LOAD_INDEX_REG(P3RD_COLOR_FORMAT, pixelCtrl);
  816. break;
  817. case 12:
  818. case 24:
  819. case 32:
  820. P3RD_LOAD_INDEX_REG(P3RD_PIXEL_SIZE, P3RD_PIXEL_SIZE_32BPP);
  821. P3RD_LOAD_INDEX_REG(P3RD_COLOR_FORMAT,
  822. P3RD_COLOR_FORMAT_32BPP | P3RD_COLOR_FORMAT_RGB);
  823. if (depth == 12) {
  824. USHORT cacheIndex;
  825. P3RD_READ_INDEX_REG(P3RD_MISC_CONTROL, ulValue);
  826. ulValue &= ~P3RD_MISC_CONTROL_DIRECT_COLOR_ENABLED;
  827. P3RD_LOAD_INDEX_REG(P3RD_MISC_CONTROL, ulValue);
  828. //
  829. // use auto-increment to load a ramp into entries 0 to 15
  830. //
  831. VideoDebugPrint((3, "Perm3: 12 BPP. loading palette\n"));
  832. for (index = 0, cacheIndex = 0;
  833. index <= 0xff;
  834. index += 0x11, cacheIndex++) {
  835. LUT_CACHE_SETRGB (index, index, index, index);
  836. }
  837. //
  838. // load ramp in every 16th entry from 16 to 240
  839. //
  840. color = 0x11;
  841. for (index = 0x10; index <= 0xf0; index += 0x10, color += 0x11) {
  842. LUT_CACHE_SETRGB (index, color, color, color);
  843. }
  844. P3RD_SET_PIXEL_READMASK(0x0f);
  845. } else {
  846. #if GAMMA_CORRECTION
  847. P3RD_READ_INDEX_REG(P3RD_MISC_CONTROL, ulValue);
  848. ulValue &= ~P3RD_MISC_CONTROL_DIRECT_COLOR_ENABLED;
  849. P3RD_LOAD_INDEX_REG(P3RD_MISC_CONTROL, ulValue);
  850. //
  851. // load linear ramp into LUT as default
  852. //
  853. for (index = 0; index <= 0xff; ++index) {
  854. LUT_CACHE_SETRGB (index, index, index, index);
  855. }
  856. #else
  857. P3RD_READ_INDEX_REG(P3RD_MISC_CONTROL, ulValue);
  858. ulValue |= P3RD_MISC_CONTROL_DIRECT_COLOR_ENABLED;
  859. P3RD_LOAD_INDEX_REG(P3RD_MISC_CONTROL, ulValue);
  860. #endif // GAMMA_CORRECTION
  861. }
  862. break;
  863. default:
  864. VideoDebugPrint((0, "Perm3: Program_P3RD: bad depth %d \n", depth));
  865. return(FALSE);
  866. }
  867. //
  868. // Blank the analogue display if we are using a DFP, also re-program the
  869. // DFPO because the BIOS may have trashed some of the registers
  870. // that we programmed at start of day.
  871. //
  872. if( hwDeviceExtension->Perm3Capabilities & PERM3_DFP_MON_ATTACHED ) {
  873. //
  874. // Only blank the CRT if the mode is less than 60Hz refresh.
  875. //
  876. if( VideoMode->ScreenFrequency < 60 ) {
  877. P3RD_LOAD_INDEX_REG(P3RD_DAC_CONTROL, 1);
  878. }
  879. ProgramDFP (hwDeviceExtension);
  880. }
  881. //
  882. // Return these values
  883. // *pPixelClock = pixelClock;
  884. // *pSystemClock = coreClock;
  885. //
  886. switch( mClkSrc ) {
  887. case P3RD_MCLK_CONTROL_HALF_PCLK:
  888. *pMemClock = 33 * 10000;
  889. break;
  890. case P3RD_MCLK_CONTROL_PCLK:
  891. *pMemClock = 66 * 10000;
  892. break;
  893. case P3RD_MCLK_CONTROL_HALF_EXTMCLK:
  894. *pMemClock = *pMemClock / 2;
  895. break;
  896. case P3RD_MCLK_CONTROL_EXTMCLK:
  897. //*pMemClock = *pMemClock;
  898. break;
  899. case P3RD_MCLK_CONTROL_HALF_KCLK:
  900. *pMemClock = (coreClock >> 1) / 2;
  901. break;
  902. case P3RD_MCLK_CONTROL_KCLK:
  903. *pMemClock = (coreClock >> 1);
  904. break;
  905. }
  906. return(TRUE);
  907. }
  908. VOID
  909. SwitchToHiResMode(
  910. PHW_DEVICE_EXTENSION hwDeviceExtension,
  911. BOOLEAN bHiRes)
  912. /*+++
  913. Routine Description:
  914. This function switches into and out of hi-res mode
  915. ---*/
  916. {
  917. USHORT usData;
  918. pPerm3ControlRegMap pCtrlRegs = hwDeviceExtension->ctrlRegBase[0];
  919. //
  920. // Enable graphics mode, disable VGA
  921. //
  922. // We have to unlock VGA registers on P3 before we can use them
  923. //
  924. UNLOCK_VGA_REGISTERS();
  925. VideoPortWriteRegisterUchar(PERMEDIA_MMVGA_INDEX_REG, PERMEDIA_VGA_CTRL_INDEX);
  926. usData = (USHORT)VideoPortReadRegisterUchar(PERMEDIA_MMVGA_DATA_REG);
  927. if(bHiRes) {
  928. usData &= ~PERMEDIA_VGA_ENABLE;
  929. } else {
  930. usData |= PERMEDIA_VGA_ENABLE;
  931. }
  932. usData = (usData << 8) | PERMEDIA_VGA_CTRL_INDEX;
  933. VideoPortWriteRegisterUshort(PERMEDIA_MMVGA_INDEX_REG, usData);
  934. //
  935. // We must lock VGA registers on P3 after use
  936. //
  937. LOCK_VGA_REGISTERS();
  938. }