Source code of Windows XP (NT5)
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.

1007 lines
25 KiB

  1. /*++
  2. Copyright (c) 1993, 1994 Weitek Corporation
  3. Module Name:
  4. clock.c
  5. Abstract:
  6. This module contains clock generator specific functions for the
  7. Weitek P9 miniport device driver.
  8. Environment:
  9. Kernel mode
  10. Revision History may be found at the end of this file.
  11. --*/
  12. #include "p9.h"
  13. #include "p9gbl.h"
  14. #include "clock.h"
  15. #include "vga.h"
  16. #include "ibm525.h"
  17. #include "p91regs.h"
  18. extern UCHAR
  19. ReadIBM525(
  20. PHW_DEVICE_EXTENSION HwDeviceExtension,
  21. USHORT index
  22. );
  23. extern VOID
  24. WriteIBM525(
  25. PHW_DEVICE_EXTENSION HwDeviceExtension,
  26. USHORT index,
  27. UCHAR value
  28. );
  29. extern UCHAR
  30. ReadP9ConfigRegister(
  31. PHW_DEVICE_EXTENSION HwDeviceExtension,
  32. UCHAR regnum
  33. );
  34. extern VOID
  35. WriteP9ConfigRegister(
  36. PHW_DEVICE_EXTENSION HwDeviceExtension,
  37. UCHAR regnum,
  38. UCHAR jValue
  39. );
  40. extern ULONG
  41. Read9100FreqSel(
  42. PHW_DEVICE_EXTENSION HwDeviceExtension
  43. );
  44. VOID
  45. Write525PLL(
  46. PHW_DEVICE_EXTENSION HwDeviceExtension,
  47. USHORT usFreq
  48. );
  49. VOID
  50. Write9100FreqSel(
  51. PHW_DEVICE_EXTENSION HwDeviceExtension,
  52. ULONG cs
  53. );
  54. VOID
  55. P91WriteICD(
  56. PHW_DEVICE_EXTENSION HwDeviceExtension,
  57. ULONG data
  58. );
  59. VOID
  60. P90WriteICD(
  61. PHW_DEVICE_EXTENSION HwDeviceExtension,
  62. ULONG data
  63. );
  64. VOID
  65. ProgramClockSynth(
  66. PHW_DEVICE_EXTENSION HwDeviceExtension,
  67. USHORT usFrequency,
  68. BOOLEAN bSetMemclk,
  69. BOOLEAN bUseClockDoubler
  70. )
  71. /*++
  72. Routine Description:
  73. Program a custom frequency into a clock synthesizer. Either MEMCLK
  74. or Pixel clock, determined by bSetMemclk.
  75. Arguments:
  76. HwDeviceExtension - Pointer to the miniport driver's device extension.
  77. usFrequency = Frequency in Mhz, (this shoud be kept in the registry),
  78. bSetMemclk == TRUE == MEMCLK.
  79. Return Value:
  80. None.
  81. --*/
  82. {
  83. VideoDebugPrint((2, "ProgramClockSynth - Entry\n"));
  84. switch (HwDeviceExtension->p91State.usClockID)
  85. {
  86. case CLK_ID_ICD2061A:
  87. VideoDebugPrint((2, "ProgramClockSynth: Clock = CLK_ID_ICD2061A\n"));
  88. if ((HwDeviceExtension->Dac.bRamdacUsePLL) &&
  89. (HwDeviceExtension->Dac.usRamdacID == DAC_ID_IBM525) && (!bSetMemclk))
  90. {
  91. VideoDebugPrint((2, "ProgramClockSynth: DAC_ID_IBM525\n"));
  92. VideoDebugPrint((2, "ProgramClockSynth: PLL Freq = %d\n", usFrequency));
  93. Write525PLL(HwDeviceExtension, usFrequency);
  94. //
  95. // Check if there is an override value for the PLL Reference
  96. // Divider. If so, set the reference frequency accordingly...
  97. //
  98. if (HwDeviceExtension->VideoData.ul525RefClkCnt != 0xFFFFFFFF)
  99. {
  100. VideoDebugPrint((2, "ProgramClockSynth: 525RefClkCnt = %ld\n",
  101. HwDeviceExtension->VideoData.ul525RefClkCnt * 200L));
  102. usFrequency = (USHORT) (HwDeviceExtension->VideoData.ul525RefClkCnt * 200L);
  103. }
  104. else
  105. {
  106. //
  107. // Set reference frequency to 5000 Mhz...
  108. //
  109. usFrequency = 5000;
  110. }
  111. VideoDebugPrint((2, "ProgramClockSynth: 525 Ref Frequency = %d\n", usFrequency));
  112. }
  113. DevSetClock(HwDeviceExtension,
  114. usFrequency,
  115. bSetMemclk,
  116. bUseClockDoubler);
  117. //
  118. // Select custom frequency
  119. //
  120. Write9100FreqSel(HwDeviceExtension, ICD2061_EXTSEL9100);
  121. break;
  122. case CLK_ID_FIXED_MEMCLK:
  123. //
  124. // People using the IBM RGB525 RAMDAC with a fixed
  125. // external oscillator will be using the RGB525's internal
  126. // PLL. So the MEMCLK cannot be changed, and the pixel
  127. // clock must be programmed through the RAMDAC.
  128. // NOTE: This code will work even if the RAMDAC's
  129. // internal PLL is bypassed and an external oscillator
  130. // is used.
  131. //
  132. // NOTE: We don't print out any kind of error message
  133. // if an attempt is made to program the memory clock
  134. // frequency.
  135. //
  136. // We assume that the reference frequency is 50 MHz.
  137. //
  138. VideoDebugPrint((2, "ProgramClockSynth: Clock = CLK_ID_FIXED_MEMCLKC\n"));
  139. if ((HwDeviceExtension->Dac.usRamdacID == DAC_ID_IBM525) &&
  140. (!bSetMemclk))
  141. {
  142. Write525PLL(HwDeviceExtension, usFrequency);
  143. }
  144. if ((HwDeviceExtension->Dac.bRamdacUsePLL) &&
  145. (HwDeviceExtension->Dac.usRamdacID == DAC_ID_IBM525) &&
  146. (!bSetMemclk))
  147. {
  148. VideoDebugPrint((2, "ERROR: Trying to select a pixclk with RGB525 disabled.\n"));
  149. }
  150. break;
  151. }
  152. VideoDebugPrint((2, "ProgramClockSynth - Exit\n"));
  153. } // End of ProgramClockSynth()
  154. VOID
  155. DevSetClock(
  156. PHW_DEVICE_EXTENSION HwDeviceExtension,
  157. USHORT usFrequency,
  158. BOOLEAN bSetMemclk,
  159. BOOLEAN bUseClockDoubler
  160. )
  161. /*++
  162. Routine Description:
  163. Set the frequency synthesizer to the proper state for the current
  164. video mode.
  165. Arguments:
  166. usFrequency == frequency.
  167. bUseClockDoubler == TRUE == use clock doubler if appropriate.
  168. Return Value:
  169. None.
  170. --*/
  171. {
  172. USHORT ftab[16]=
  173. {
  174. 5100,5320,5850,6070,6440,6680,7350,7560,8090,
  175. 8320,9150,10000,12000,12000,12000,12000
  176. };
  177. USHORT ref = 5727; // reference freq 2*14.31818 *100*2
  178. int i = 0; // index preset field
  179. int m = 0; // power of 2 divisor field
  180. int p; // multiplier field
  181. int q; // divisor field
  182. int qs; // starting q to prevent integer overflow
  183. int bestq = 0; // best q so far
  184. int bestp = 0; // best p so far
  185. int bestd = 10000; // distance to best combination so far
  186. int curd; // current distance
  187. int curf; // current frequency
  188. int j; // loop counter
  189. ULONG data;
  190. VideoDebugPrint((2, "DevSetClock - Entry\n"));
  191. if (usFrequency == 0) // Prevent 0 from hanging us!
  192. usFrequency = 3150;
  193. if ((usFrequency > HwDeviceExtension->Dac.ulMaxClkFreq) &&
  194. (bUseClockDoubler) &&
  195. (HwDeviceExtension->Dac.usRamdacID != DAC_ID_IBM525))
  196. {
  197. //
  198. // Enable the DAC clock doubler mode.
  199. //
  200. HwDeviceExtension->Dac.DACSetClkDblMode(HwDeviceExtension);
  201. // 2x Clock multiplier enabled
  202. usFrequency /= 2; // Use 1/2 the freq.
  203. }
  204. else
  205. {
  206. //
  207. // Disable the DAC clock doubler mode.
  208. //
  209. HwDeviceExtension->Dac.DACClrClkDblMode(HwDeviceExtension);
  210. }
  211. while(usFrequency < 5000) // if they need a small frequency,
  212. {
  213. m += 1; // the hardware can divide by 2 to-the m
  214. usFrequency *= 2; // so try for a higher frequency
  215. }
  216. for (j = 0; j < 16; j++) // find the range that best fits this frequency
  217. {
  218. if (usFrequency < ftab[j]) // when you find the frequency
  219. {
  220. i = j; // remember the table index
  221. break; // and stop looking.
  222. }
  223. }
  224. for (p = 0; p < 128; p++) // try all possible frequencies!
  225. {
  226. //well, start q high to avoid overflow
  227. qs = div32(mul32((SHORT) ref, (SHORT) (p+3)), 0x7fff);
  228. for (q = qs; q < 128; q++)
  229. {
  230. //
  231. // calculate how good each frequency is
  232. //
  233. curf = div32(mul32((SHORT) ref, (SHORT) (p+3)), (SHORT) ((q + 2) << 1));
  234. curd = usFrequency - curf;
  235. if (curd < 0)
  236. {
  237. curd = -curd; // always calc a positive distance
  238. }
  239. if (curd < bestd) // if it's best of all so far
  240. {
  241. bestd = curd; // then remember everything about it
  242. bestp = p; // but especially the multiplier
  243. bestq = q; // and divisor
  244. }
  245. }
  246. }
  247. data = ((((long) i) << 17) | (((long) bestp) << 10) | (m << 7) | bestq);
  248. VideoDebugPrint((2, "ProgramClockSynth: usFrequency = %d\n", usFrequency));
  249. VideoDebugPrint((2, "ProgramClockSynth: data = %lx\n", data));
  250. if (bSetMemclk)
  251. {
  252. data = data | IC_MREG; // Memclk
  253. }
  254. else
  255. {
  256. data = data | IC_REG2; // Pixclk
  257. }
  258. if (IS_DEV_P9100)
  259. {
  260. P91WriteICD(HwDeviceExtension, data);
  261. }
  262. else
  263. {
  264. P90WriteICD(HwDeviceExtension, data);
  265. }
  266. VideoDebugPrint((2, "DevSetClock - Exit\n"));
  267. return;
  268. } // End of DevSetClock()
  269. VOID P91WriteICD(
  270. PHW_DEVICE_EXTENSION HwDeviceExtension,
  271. ULONG data
  272. )
  273. /*++
  274. Routine Description:
  275. Program the ICD2061a Frequency Synthesizer.
  276. Arguments:
  277. HwDeviceExtension - Pointer to the miniport driver's device extension.
  278. data - Data to be written.
  279. Return Value:
  280. None.
  281. --*/
  282. {
  283. int i;
  284. ULONG savestate;
  285. //
  286. // Note: We might have to disable interrupts to preclude the ICD's
  287. // watchdog timer from expiring resulting in the ICD resetting to the
  288. // idle state.
  289. //
  290. savestate = Read9100FreqSel(HwDeviceExtension);
  291. //
  292. // First, send the "Unlock sequence" to the clock chip.
  293. // Raise the data bit and send 5 unlock bits.
  294. //
  295. Write9100FreqSel(HwDeviceExtension, ICD2061_DATA9100);
  296. for (i = 0; i < 5; i++) // send at least 5 unlock bits
  297. {
  298. //
  299. // Hold the data while lowering and raising the clock
  300. //
  301. Write9100FreqSel(HwDeviceExtension, ICD2061_DATA9100);
  302. Write9100FreqSel(HwDeviceExtension, ICD2061_DATA9100 |
  303. ICD2061_CLOCK9100);
  304. }
  305. //
  306. // Then turn the data clock off and turn the clock on one more time...
  307. //
  308. Write9100FreqSel(HwDeviceExtension, 0);
  309. Write9100FreqSel(HwDeviceExtension, ICD2061_CLOCK9100);
  310. //
  311. // Now send the start bit: Leave data off, adn lower the clock.
  312. //
  313. Write9100FreqSel(HwDeviceExtension, 0);
  314. //
  315. // Leave data off and raise the clock.
  316. //
  317. Write9100FreqSel(HwDeviceExtension, ICD2061_CLOCK9100);
  318. //
  319. // Localbus position for hacking bits out
  320. // Next, send the 24 data bits.
  321. //
  322. for (i = 0; i < 24; i++)
  323. {
  324. //
  325. // Leaving the clock high, raise the inverse of the data bit
  326. //
  327. Write9100FreqSel(HwDeviceExtension,
  328. ((~data << ICD2061_DATASHIFT9100) &
  329. ICD2061_DATA9100) | ICD2061_CLOCK9100);
  330. //
  331. // Leaving the inverse data in place, lower the clock.
  332. //
  333. Write9100FreqSel(HwDeviceExtension,
  334. (~data << ICD2061_DATASHIFT9100) & ICD2061_DATA9100);
  335. //
  336. // Leaving the clock low, rais the data bit.
  337. //
  338. Write9100FreqSel(HwDeviceExtension,
  339. (data << ICD2061_DATASHIFT9100) & ICD2061_DATA9100);
  340. //
  341. // Leaving the data bit in place, raise the clock.
  342. //
  343. Write9100FreqSel(HwDeviceExtension,
  344. ((data << ICD2061_DATASHIFT9100) & ICD2061_DATA9100)
  345. | ICD2061_CLOCK9100);
  346. data >>= 1; // get the next bit of the data
  347. }
  348. //
  349. // Leaving the clock high, raise the data bit.
  350. //
  351. Write9100FreqSel(HwDeviceExtension,
  352. ICD2061_CLOCK9100 | ICD2061_DATA9100);
  353. //
  354. // Leaving the data high, drop the clock low, then high again.
  355. //
  356. Write9100FreqSel(HwDeviceExtension, ICD2061_DATA9100);
  357. Write9100FreqSel(HwDeviceExtension,
  358. ICD2061_CLOCK9100 | ICD2061_DATA9100);
  359. //
  360. // Note: if interrupts were disabled, enable them here.
  361. // before restoring the
  362. // original value or the ICD
  363. // will freak out.
  364. Write9100FreqSel(HwDeviceExtension, savestate); // restore orig register value
  365. return;
  366. } // End of WriteICD()
  367. VOID
  368. P90WriteICD(
  369. PHW_DEVICE_EXTENSION HwDeviceExtension,
  370. ULONG data
  371. )
  372. /*++
  373. Routine Description:
  374. Program the ICD2061a Frequency Synthesizer for the Power 9000.
  375. Arguments:
  376. HwDeviceExtension - Pointer to the miniport driver's device extension.
  377. data - Data to be written.
  378. Return Value:
  379. None.
  380. --*/
  381. {
  382. int i;
  383. int oldstate, savestate;
  384. savestate = RD_ICD();
  385. oldstate = savestate & ~(MISCD | MISCC);
  386. // First, send the "Unlock sequence" to the clock chip.
  387. WR_ICD(oldstate | MISCD); // raise the data bit
  388. for (i = 0;i < 5;i++) // send at least 5 unlock bits
  389. {
  390. WR_ICD(oldstate | MISCD); // hold the data on while
  391. WR_ICD(oldstate | MISCD | MISCC); // lowering and raising the clock
  392. }
  393. WR_ICD(oldstate); // then turn the data and clock off
  394. WR_ICD(oldstate | MISCC); // and turn the clock on one more time.
  395. // now send the start bit:
  396. WR_ICD(oldstate); // leave data off, and lower the clock
  397. WR_ICD(oldstate | MISCC); // leave data off, and raise the clock
  398. // localbus position for hacking bits out
  399. // Next, send the 24 data bits.
  400. for (i = 0; i < 24; i++)
  401. {
  402. // leaving the clock high, raise the inverse of the data bit
  403. WR_ICD(oldstate | ((~(((short) data) << 3)) & MISCD) | MISCC);
  404. // leaving the inverse data in place, lower the clock
  405. WR_ICD(oldstate | (~(((short) data) << 3)) & MISCD);
  406. // leaving the clock low, rais the data bit
  407. WR_ICD(oldstate | (((short) data) << 3) & MISCD);
  408. // leaving the data bit in place, raise the clock
  409. WR_ICD(oldstate | ((((short)data) << 3) & MISCD) | MISCC);
  410. data >>= 1; // get the next bit of the data
  411. }
  412. // leaving the clock high, raise the data bit
  413. WR_ICD(oldstate | MISCD | MISCC);
  414. // leaving the data high, drop the clock low, then high again
  415. WR_ICD(oldstate | MISCD);
  416. WR_ICD(oldstate | MISCD | MISCC);
  417. WR_ICD(oldstate | MISCD | MISCC); // Seem to need a delay
  418. // before restoring the
  419. // original value or the ICD
  420. // will freak out.
  421. WR_ICD(savestate); // restore original register value
  422. return;
  423. } // End of P90WriteICD()
  424. VOID
  425. Write9100FreqSel(
  426. PHW_DEVICE_EXTENSION HwDeviceExtension,
  427. ULONG cs
  428. )
  429. /*++
  430. Routine Description:
  431. Write to the P9100 clock select register preserving the video coprocessor
  432. enable bit.
  433. Statically:
  434. Bits [1:0] go to frequency select
  435. Dynamically:
  436. Bit 1: data
  437. Bit 0: clock
  438. Arguments:
  439. HwDeviceExtension - Pointer to the miniport driver's device extension.
  440. Clock select value to write.
  441. Return Value:
  442. None.
  443. --*/
  444. {
  445. //
  446. // Set the frequency select bits in the P9100 configuration
  447. //
  448. WriteP9ConfigRegister(HwDeviceExtension,
  449. P91_CONFIG_CKSEL,
  450. (UCHAR) ((cs << 2) |
  451. HwDeviceExtension->p91State.bVideoPowerEnabled));
  452. return;
  453. } // End of Write9100FreqSel()
  454. ULONG
  455. Read9100FreqSel(
  456. PHW_DEVICE_EXTENSION HwDeviceExtension
  457. )
  458. /*++
  459. Routine Description:
  460. Read from the P9100 clock select register.
  461. Arguments:
  462. HwDeviceExtension - Pointer to the miniport driver's device extension.
  463. Return Value:
  464. None.
  465. --*/
  466. {
  467. //
  468. // Since the frequency select bits are in the P9100 configuration
  469. // space, you have to treat VL and PCI differently.
  470. //
  471. return((ULONG)(ReadP9ConfigRegister(HwDeviceExtension, P91_CONFIG_CKSEL)
  472. >> 2) & 0x03);
  473. } // End of Read9100FreqSel()
  474. VOID
  475. Write525PLL(
  476. PHW_DEVICE_EXTENSION HwDeviceExtension,
  477. USHORT usFreq
  478. )
  479. /*++
  480. Routine Description:
  481. This function programs the IBM RGB525 Ramdac to generate and use the
  482. specified frequency as its pixel clock frequency.
  483. Arguments:
  484. Frequency.
  485. Return Value:
  486. None.
  487. --*/
  488. {
  489. USHORT usDesiredFreq;
  490. USHORT usOutputFreq;
  491. USHORT usRoundedFreq;
  492. USHORT usVCODivCount;
  493. ULONG ulValue;
  494. VideoDebugPrint((2, "Write525PLL------\n"));
  495. usOutputFreq = usFreq;
  496. //
  497. // Calculate the DF and VCO Divide count for the specified output
  498. // frequency. The calculations are based on the following table:
  499. //
  500. // DF | VCO Divide Count | Frequency Range | Step (MHz)
  501. // ----+-------------------+---------------------+------------
  502. // 00 | (4 x VF) - 65 | 16.25 - 32.00 MHz | 0.25
  503. // 01 | (2 x VF) - 65 | 32.50 - 64.00 MHz | 0.50
  504. // 10 | VF - 65 | 65.00 - 128.00 MHz | 1.00
  505. // 11 | (VF / 2) - 65 | 130.00 - 250.00 MHz | 2.00
  506. // -----------------------------------------------------------
  507. // VF = Desired Video Frequency
  508. // -----------------------------------------------------------
  509. //
  510. if ((usOutputFreq >= IBM525_DF0_LOW) &&
  511. (usOutputFreq <= IBM525_DF0_HIGH))
  512. {
  513. //
  514. // The requested frequency is in the DF0 frequency range.
  515. //
  516. usDesiredFreq = IBM525_FREQ_DF_0;
  517. //
  518. // Round the requested frequency to the nearest frequency step
  519. // boundry.
  520. //
  521. usRoundedFreq = (usOutputFreq / IBM525_DF0_STEP) * IBM525_DF0_STEP;
  522. if ((usOutputFreq - usRoundedFreq) >= (IBM525_DF0_STEP / 2))
  523. {
  524. //
  525. // Round up.
  526. //
  527. usRoundedFreq += IBM525_DF0_STEP;
  528. }
  529. //
  530. // Calculate the VCO Divide Count register value for the requested
  531. // frequency.
  532. //
  533. usVCODivCount = ((usRoundedFreq * 4) - 6500) / 100;
  534. }
  535. else if ((usOutputFreq >= IBM525_DF1_LOW) &&
  536. (usOutputFreq <= IBM525_DF1_HIGH))
  537. {
  538. //
  539. // The requested frequency is in the DF1 frequency range.
  540. //
  541. usDesiredFreq = IBM525_FREQ_DF_1;
  542. //
  543. // Round the requested frequency to the nearest frequency step
  544. // boundry.
  545. //
  546. usRoundedFreq = (usOutputFreq / IBM525_DF1_STEP) * IBM525_DF1_STEP;
  547. if ((usOutputFreq - usRoundedFreq) >= (IBM525_DF1_STEP / 2))
  548. {
  549. //
  550. // Round up.
  551. //
  552. usRoundedFreq += IBM525_DF1_STEP;
  553. }
  554. //
  555. // Calculate the VCO Divide Count register value for the requested
  556. // frequency.
  557. //
  558. usVCODivCount = ((usRoundedFreq * 2) - 6500) / 100;
  559. }
  560. else if ((usOutputFreq >= IBM525_DF2_LOW) &&
  561. (usOutputFreq <= IBM525_DF2_HIGH))
  562. {
  563. //
  564. // The requested frequency is in the DF2 frequency range.
  565. //
  566. usDesiredFreq = IBM525_FREQ_DF_2;
  567. //
  568. // Round the requested frequency to the nearest frequency step
  569. // boundry.
  570. //
  571. usRoundedFreq = (usOutputFreq / IBM525_DF2_STEP) * IBM525_DF2_STEP;
  572. if ((usOutputFreq - usRoundedFreq) >= (IBM525_DF2_STEP / 2))
  573. {
  574. //
  575. // Round up.
  576. //
  577. usRoundedFreq += IBM525_DF2_STEP;
  578. }
  579. //
  580. // Calculate the VCO Divide Count register value for the requested
  581. // frequency.
  582. //
  583. usVCODivCount = (usRoundedFreq - 6500) / 100;
  584. }
  585. else if ((usOutputFreq >= IBM525_DF3_LOW) &&
  586. (usOutputFreq <= IBM525_DF3_HIGH))
  587. {
  588. //
  589. // The requested frequency is in the DF3 frequency range.
  590. //
  591. usDesiredFreq = IBM525_FREQ_DF_3;
  592. //
  593. // Round the requested frequency to the nearest frequency step
  594. // boundry.
  595. //
  596. usRoundedFreq = (usOutputFreq / IBM525_DF3_STEP) * IBM525_DF3_STEP;
  597. if ((usOutputFreq - usRoundedFreq) >= (IBM525_DF3_STEP / 2))
  598. {
  599. //
  600. // Round up.
  601. //
  602. usRoundedFreq += IBM525_DF3_STEP;
  603. }
  604. //
  605. // Calculate the VCO Divide Count register value for the requested
  606. // frequency.
  607. //
  608. usVCODivCount = ((usRoundedFreq / 2) - 6500) / 100;
  609. }
  610. else
  611. {
  612. //
  613. // The requested frequency is not supported...
  614. //
  615. VideoDebugPrint((2, "Write525PLL: Freq %d is not supported!\n", usFreq));
  616. }
  617. VideoDebugPrint((2, "Write525PLL: usRoundedFreq = %d\n", usRoundedFreq));
  618. VideoDebugPrint((2, "Write525PLL: usVCODivCount = %d\n", usVCODivCount));
  619. //
  620. // Setup for writing to the PLL Reference Divider register.
  621. //
  622. //
  623. // Check if there is an override value for the PLL Reference Divider.
  624. //
  625. if (HwDeviceExtension->VideoData.ul525RefClkCnt != 0xFFFFFFFF)
  626. {
  627. //
  628. // Program REFCLK to the specified override...
  629. //
  630. WriteIBM525(HwDeviceExtension,
  631. RGB525_FIXED_PLL_REF_DIV,
  632. (UCHAR) HwDeviceExtension->VideoData.ul525RefClkCnt);
  633. VideoDebugPrint((2, "ProgramClockSynth: 525RefClkCnt = %lx\n",
  634. HwDeviceExtension->VideoData.ul525RefClkCnt));
  635. }
  636. else
  637. {
  638. //
  639. // Program REFCLK to a fixed 50MHz.
  640. //
  641. WriteIBM525(HwDeviceExtension, RGB525_FIXED_PLL_REF_DIV,
  642. IBM525_PLLD_50MHZ);
  643. }
  644. //
  645. // Set up for programming frequency register 9.
  646. //
  647. //
  648. // Check if there is an override value for the VCO Divide Count Register.
  649. //
  650. if (HwDeviceExtension->VideoData.ul525VidClkFreq != 0xFFFFFFFF)
  651. {
  652. //
  653. // Program the VCO Divide count register to the specified override...
  654. //
  655. WriteIBM525(HwDeviceExtension,
  656. RGB525_F9,
  657. (UCHAR) HwDeviceExtension->VideoData.ul525VidClkFreq);
  658. }
  659. else
  660. {
  661. //
  662. // No override value, so use the calculated value.
  663. //
  664. WriteIBM525(HwDeviceExtension,
  665. RGB525_F9,
  666. (UCHAR) (usDesiredFreq | usVCODivCount));
  667. }
  668. //
  669. // Program PLL Control Register 2.
  670. //
  671. WriteIBM525(HwDeviceExtension, RGB525_PLL_CTL2, IBM525_PLL2_F9_REG);
  672. //
  673. // Program PLL Control Register 1.
  674. //
  675. WriteIBM525(HwDeviceExtension, RGB525_PLL_CTL1,
  676. (IBM525_PLL1_REFCLK_INPUT |
  677. IBM525_PLL1_INT_FS) );
  678. //
  679. // Program DAC Operation Register.
  680. //
  681. WriteIBM525(HwDeviceExtension, RGB525_DAC_OPER, IBM525_DO_DSR_FAST);
  682. //
  683. // Program Miscellaneous Control Register 1.
  684. //
  685. WriteIBM525(HwDeviceExtension, RGB525_MISC_CTL1, IBM525_MC1_VRAM_64_BITS);
  686. //
  687. // Program Miscellaneous Clock Control Register.
  688. //
  689. ulValue = ReadIBM525(HwDeviceExtension, RGB525_MISC_CLOCK_CTL);
  690. //
  691. // Now decide how to divide the PLL clock output.
  692. //
  693. if (!HwDeviceExtension->Dac.bRamdacDivides)
  694. {
  695. if (HwDeviceExtension->usBitsPixel == 24)
  696. {
  697. //
  698. // 24 Bpp = 3 Byte Per Pixel
  699. //
  700. // At 24 Bpp, divide the clock by 8.
  701. //
  702. ulValue |= IBM525_MCC_PLL_DIV_8 | IBM525_MCC_PLL_ENABLE;
  703. }
  704. else
  705. {
  706. //
  707. // Don't divide the clock when the P9100 is doing the dividing.
  708. //
  709. ulValue |= IBM525_MCC_PLL_DIV_1 | IBM525_MCC_PLL_ENABLE;
  710. }
  711. }
  712. else
  713. {
  714. switch (HwDeviceExtension->usBitsPixel)
  715. {
  716. //
  717. // 8 Bpp = 1 Byte Per Pixel
  718. //
  719. case 8:
  720. {
  721. //
  722. // At 8 Bpp, divide the clock by 8.
  723. //
  724. ulValue |= IBM525_MCC_PLL_DIV_8 | IBM525_MCC_PLL_ENABLE;
  725. break;
  726. }
  727. //
  728. // 16 Bpp = 2 Byte Per Pixel
  729. //
  730. case 15:
  731. case 16:
  732. {
  733. //
  734. // At 16 Bpp, divide the clock by 4.
  735. //
  736. ulValue |= IBM525_MCC_PLL_DIV_4 | IBM525_MCC_PLL_ENABLE;
  737. break;
  738. }
  739. //
  740. // 24 Bpp = 3 Byte Per Pixel
  741. //
  742. case 24:
  743. {
  744. //
  745. // At 24 Bpp, divide the clock by 8.
  746. //
  747. ulValue |= IBM525_MCC_PLL_DIV_8 | IBM525_MCC_PLL_ENABLE;
  748. break;
  749. }
  750. //
  751. // 32 Bpp = 4 Byte Per Pixel
  752. //
  753. case 32:
  754. {
  755. //
  756. // At 32 Bpp, divide the clock by 2.
  757. //
  758. ulValue |= IBM525_MCC_PLL_DIV_2 | IBM525_MCC_PLL_ENABLE;
  759. break;
  760. }
  761. }
  762. }
  763. WriteIBM525(HwDeviceExtension,
  764. RGB525_MISC_CLOCK_CTL,
  765. (UCHAR) ulValue);
  766. return;
  767. } // End of Write525PLL()