/*++ Copyright (c) 1993, 1994 Weitek Corporation Module Name: p9100.c Abstract: This module contains the code specific to the Weitek P9100. Environment: Kernel mode Revision History may be found at the end of this file. --*/ #include "p9.h" #include "p9gbl.h" #include "p91regs.h" #include "vga.h" #include "wtkp9xvl.h" VOID InitP9100( PHW_DEVICE_EXTENSION HwDeviceExtension ) /*++ Routine Description: Initialize the P9100. Arguments: HwDeviceExtension - Pointer to the miniport driver's device extension. Return Value: None. --*/ { VideoDebugPrint((2, "InitP9100------\n")); P9_WR_REG(P91_INTERRUPT_EN, 0x00000080L); //INTERRUPT-EN = disabled P9_WR_REG(P91_PREHRZC, 0x00000000L); //PREHRZC = 0 P9_WR_REG(P91_PREVRTC, 0x00000000L); //PREVRTC = 0 // // Initialize the P9100 registers. // P9_WR_REG(P91_RFPERIOD, 0x00000186L); //RFPERIOD = P9_WR_REG(P91_RLMAX, 0x000000FAL); //RLMAX = P9_WR_REG(P91_DE_PMASK, 0xFFFFFFFFL); //allow writing in all 8 planes P9_WR_REG(P91_DE_DRAW_MODE, P91_WR_INSIDE_WINDOW | P91_DE_DRAW_BUFF_0); P9_WR_REG(P91_PE_W_OFF_XY, 0x00000000L); //disable any co-ord offset return; } VOID P91_WriteTiming( PHW_DEVICE_EXTENSION HwDeviceExtension ) /*++ Routine Description: Initializes the P9100 Crtc timing registers. Arguments: HwDeviceExtension - Pointer to the miniport driver's device extension. Return Value: None. --*/ { int num, den, bpp; ULONG ulValueRead, ulValueWritten; ULONG ulHRZSR; ULONG ulHRZBR; ULONG ulHRZBF; ULONG ulHRZT; VideoDebugPrint((2, "P91_WriteTiming - Entry\n")); bpp = HwDeviceExtension->usBitsPixel / 8; // Need bytes per pixel // // 24-bit color // if (bpp == 3) { num = 3; den = HwDeviceExtension->Dac.usRamdacWidth/8; } else { num = 1; den = HwDeviceExtension->Dac.usRamdacWidth/(bpp * 8); } // // Calculate HRZSR. // ulHRZSR = (ULONG) (HwDeviceExtension->VideoData.hsyncp / (ULONG) den) * (ULONG) num; ulHRZSR -= HwDeviceExtension->p91State.ulBlnkDlyAdj; // // Calculate HRZBR. // ulHRZBR = (ULONG) ((HwDeviceExtension->VideoData.hsyncp + HwDeviceExtension->VideoData.hbp) / (ULONG) den) * (ULONG) num; ulHRZBR -= HwDeviceExtension->p91State.ulBlnkDlyAdj; // ulHRZBR -= 4; ulHRZBF = (ULONG) ( (HwDeviceExtension->VideoData.hsyncp+ HwDeviceExtension->VideoData.hbp+ HwDeviceExtension->VideoData.XSize) / (ULONG) den) * (ULONG) num; // // Calculate HRZBF. // ulHRZBF -= HwDeviceExtension->p91State.ulBlnkDlyAdj; // ulHRZBF -= 4; ulHRZT = (ULONG) ( (HwDeviceExtension->VideoData.hsyncp+ HwDeviceExtension->VideoData.hbp+ HwDeviceExtension->VideoData.XSize+ HwDeviceExtension->VideoData.hfp) / (ULONG) den) * (ULONG) num; --ulHRZT; // // Changes requested by Rober Embry, Jan 26 Spec. // if (HwDeviceExtension->Dac.ulDacId == DAC_ID_BT489) { // // Fix for fussy screen problem, Per Sam Jenson // ulHRZT = 2 * (ulHRZT>>1) + 1; } if ((HwDeviceExtension->Dac.ulDacId == DAC_ID_BT489) || (HwDeviceExtension->Dac.ulDacId == DAC_ID_BT485)) { if (bpp == 1) { ulHRZBR -= 12 * num / den; ulHRZBF -= 12 * num / den; } else { ulHRZBR -= 9 * num / den; ulHRZBF -= 9 * num / den; } } // // By robert embry 12/1/94 // // The hardware configuration (Power 9100 version and DAC type) affects // the minimum horizontal back porch timing that a board can support. // The most flexible (able to support the smallest back porch) // configuration is with Power 9100 A4 with the IBM or ATT DAC. // // The Power 9100 A2 increases the front porch minimum by one. // The Brooktree DAC increases the front porch minimum by one, also. // // Configuration Min. Back Porch // ----------------- --------------- // P9100 A4, IBM/ATT DAC 40 pixels (5 CRTC clocks) // P9100 A2, IBM/ATT DAC 48 pixels (6 CRTC clocks) // P9100 A4, BT485/9 DAC 48 pixels (6 CRTC clocks) // P9100 A2, BT485/9 DAC 56 pixels (7 CRTC clocks) // // Since we want one P9x00RES.DAT file AND we don't want to penalize the // most common configuration, the driver needs to choose the best fit // when the P9x00RES.DAT file specifies a set of parameters that are not // supported. // // Algorithm for BEST FIT: // // First, time must be taken from something else. Either by shortening // the pulse width or the front porch (shifts line to right.) The // largest value of the two is decreased, sync pulse if equal. // // A given P9x00RES.DAT file will result in valid register values // in one hardware configuration, but not in another. This code // adjusts these register values so the P9x00RES.DAT file parameters // work for all boards, but not necesarily giving the requested timing. // The P9100 A4 silicon with an IBM or ATT DAC is the best case. // When the P9100 A2 or a Brooktree DAC is present then the // minimum supportable horizontal back porch is enlarged. // // psuedo BASIC code: // // This is parameter checking code for the Power 9100's hrzSR and hrzBR // registers. The following equation must be satisfied: hrzSR < hrzBR. // // If this equation is violated in the presence of the Power 9100 A2 // silicon or a non-pipelined DAC (BT485/9) then these register values // are modified. // // This code should go just before the registers are written. // The register values may need to be modified by up to 2 counts. // // IF (DacType=BT485 OR DacType=BT485A OR DacType=BT489 OR _ // SiliconVerion=A2) THEN { // WHILE hrzSR >= hrzBR { // IF hsp>hfp THEN DECR hrzSR _ ;shrink sync pulse width // ELSE INCR hrzBR :INCR hrzBF ;shorten front porch // } } // if ((HwDeviceExtension->Dac.ulDacId == DAC_ID_BT489) || (HwDeviceExtension->Dac.ulDacId == DAC_ID_BT485) || (HwDeviceExtension->p91State.usRevisionID < WTK_9100_REV3)) { while (ulHRZSR >= ulHRZBR) { if (HwDeviceExtension->VideoData.hsyncp > HwDeviceExtension->VideoData.hfp) { ulHRZSR--; } else { ulHRZBR++; ulHRZBF++; } } } // // Write to the video timing registers // do { P9_WR_REG(P91_HRZSR, ulHRZSR); ulValueRead = (ULONG) P9_RD_REG(P91_HRZSR); } while (ulValueRead != ulHRZSR); do { P9_WR_REG(P91_HRZBR, ulHRZBR); ulValueRead = (ULONG) P9_RD_REG(P91_HRZBR); } while (ulValueRead != ulHRZBR); do { P9_WR_REG(P91_HRZBF, ulHRZBF); ulValueRead = (ULONG) P9_RD_REG(P91_HRZBF); } while (ulValueRead != ulHRZBF); do { P9_WR_REG(P91_HRZT, ulHRZT); ulValueRead = (ULONG) P9_RD_REG(P91_HRZT); } while (ulValueRead != ulHRZT); ulValueWritten = (ULONG) HwDeviceExtension->VideoData.vsp; do { P9_WR_REG(P91_VRTSR, ulValueWritten); ulValueRead = (ULONG) P9_RD_REG(P91_VRTSR); } while (ulValueRead != ulValueWritten); ulValueWritten = (ULONG) HwDeviceExtension->VideoData.vsp+ HwDeviceExtension->VideoData.vbp; do { P9_WR_REG(P91_VRTBR, ulValueWritten); ulValueRead = (ULONG) P9_RD_REG(P91_VRTBR); } while (ulValueRead != ulValueWritten); ulValueWritten = (ULONG) HwDeviceExtension->VideoData.vsp+ HwDeviceExtension->VideoData.vbp+ HwDeviceExtension->VideoData.YSize; do { P9_WR_REG(P91_VRTBF, ulValueWritten); ulValueRead = (ULONG) P9_RD_REG(P91_VRTBF); } while (ulValueRead != ulValueWritten); ulValueWritten = (ULONG) HwDeviceExtension->VideoData.vsp+ HwDeviceExtension->VideoData.vbp+ HwDeviceExtension->VideoData.YSize+ HwDeviceExtension->VideoData.vfp; do { P9_WR_REG(P91_VRTT, ulValueWritten); ulValueRead = (ULONG) P9_RD_REG(P91_VRTT); } while (ulValueRead != ulValueWritten); VideoDebugPrint((2, "P91_WriteTiming - Exit\n")); return; } // End of P91_WriteTimings() VOID P91_SysConf( PHW_DEVICE_EXTENSION HwDeviceExtension ) /*++ Routine Description: Syscon converts the ->XSize value into the correct bits in the System Configuration Register and writes the register (This register contains the XSize of the display.) Half-word and byte swapping are set via bits: 12 & 13; The shift control fields are set to the size of the scanline in bytes; And pixel size is set to bits per pixel. XSize and ulFrameBufferSize must be set prior to entering this routine. This routine also initializes the clipping registers. Arguments: HwDeviceExtension - Pointer to the miniport driver's device extension. Return Value: None. --*/ { int i, j, iBytesPerPixel; // loop counters long sysval; // swap bytes and words for little endian PC int xtem = (int) HwDeviceExtension->VideoData.XSize; long ClipMax; // clipping register value for NotBusy to restore iBytesPerPixel = (int) HwDeviceExtension->usBitsPixel / 8; // Calc Bytes/pixel xtem *= iBytesPerPixel; VideoDebugPrint((2, "P91_SysConf------\n")); // // The following sets up the System Configuration Register // for BPP with byte and half-word swapping. This swapping // is usually what is needed since the frame-buffer is stored // in big endian pixel format and the 80x86 software usually // expects little endian pixel format. // if (iBytesPerPixel == 1) sysval = SYSCFG_BPP_8; else if (iBytesPerPixel == 2) sysval = SYSCFG_BPP_16; else if (iBytesPerPixel == 3) sysval = SYSCFG_BPP_24; else // if (iBytesPerPixel == 4) sysval = SYSCFG_BPP_32; // // Now set the Shift3, Shift0, Shift1 & Shift2 multipliers. // // Each field in the sysconfig can only set a limited // range of bits in the size. // if (xtem & 0x1c00) // 7168 { // // Look at all the bits for shift control 3 // j=3; for (i=4096;i>=1024;i>>=1) { // // If this bit is on... // if (i & xtem) { // // Use this field to set it and // remove the bit from the size. Each // field can only set one bit. // sysval |= ((long)j)<<29; xtem &= ~i; break; } j=j-1; } } if (xtem & 0xf80) // each field in the sysconreg can only set { // a limited range of bits in the size j = 7; // each field is 3 bits wide // // Look at all the bits for shift control 0 // for (i = 2048; i >= 128;i >>= 1) // look at all the bits field 3 can effect { if (i & xtem) // if this bit is on, { sysval |= ((long) j) << 20; // use this field to set it xtem &= ~i; // and remove the bit from the size break; // each field can only set one bit } j -= 1; } } if (xtem & 0x7C0) // do the same thing for field 2 { // // Do the same thing for shift control 1 // j = 6; // each field is 3 bits wide for (i = 1024; i >= 64; i >>= 1) // look at all the bits field 2 can effect { if (i & xtem) // if this bit is on, { sysval |= ((long)j)<<17; // use this field to set it xtem &= ~i; // and remove the bit from the size break; // each field can only set one bit } j -= 1; } } if (xtem & 0x3E0) // do the same thing for field 1 { j = 5; // each field is 3 bits wide // // do the same thing for shift control 2 // for (i = 512; i >= 32;i >>= 1) // look at all the bits field 1 can effect { if (i & xtem) // if this bit is on, { sysval |= ((long) j) << 14; // use this field to set it xtem &= ~i; // and remove the bit from the size break; // each field can only set one bit } j -= 1; } } // // If there are bits left, it is an illegal x size. This just means // that we cannot handle it because we have not implemented a // full multiplier. However, the vast majority of screen sizes can be // expressed as a sum of few powers of two. // if (xtem != 0) // if there are bits left, it is an return; // illegal x size. VideoDebugPrint((2, "P91_SysConf:sysval = 0x%lx\n", sysval)); P9_WR_REG(P91_SYSCONFIG, sysval); // send data to the register xtem = (int) (HwDeviceExtension->VideoData.XSize * (ULONG) iBytesPerPixel); // // Now calculate and set the max clipping to allow access to all of // the extra memory. // // There are two sets of clipping registers. The first takes the // horizontal diemnsion in pixels and the vertical dimension in // scanlines. // ClipMax=((long) HwDeviceExtension->VideoData.XSize - 1L) << 16 | (div32(HwDeviceExtension->FrameLength, (USHORT) xtem) - 1L); P9_WR_REG(P91_DE_P_W_MIN, 0L); P9_WR_REG(P91_DE_P_W_MAX, ClipMax); // // The second set takes the horizontal dimension in bytes and the // vertical dimension in scanlines. // ClipMax=((long) xtem -1L) << 16 | (div32(HwDeviceExtension->FrameLength, (USHORT) xtem) - 1L); // calc and set max P9_WR_REG(P91_DE_B_W_MIN, 0L); P9_WR_REG(P91_DE_B_W_MAX, ClipMax); return; } // End of P91_SysConf() #define RESTORE_DAC 1 //#define SAVE_INDEX_REGS 1 /***************************************************************************\ * * * Save & Restore VGA registers routines * * * * this is to avoid "blind" boot end * * * \***************************************************************************/ void P91SaveVGARegs(PHW_DEVICE_EXTENSION HwDeviceExtension,VGA_REGS * SaveVGARegisters) { UCHAR ucIndex ; ULONG ulIndex ; UCHAR temp; #ifdef SAVE_INDEX_REGS // Save index registers. temp = VGA_RD_REG(0x004); VideoDebugPrint((1, "Save, 3c4:%x\n", temp)); temp = VGA_RD_REG(0x00e); VideoDebugPrint((1, "Save, 3ce:%x\n", temp)); temp = VGA_RD_REG(0x014); VideoDebugPrint((1, "Save, 3d4:%x\n", temp)); #endif /* Miscellaneous Output Register: [3C2]w, [3CC]r */ SaveVGARegisters->MiscOut = VGA_RD_REG(0x00C) ; /* CRT Controller Registers 0-18: index [3D4], data [3D5] */ for (ucIndex = 0 ; ucIndex < 0x18 ; ucIndex ++) { VGA_WR_REG(0x014 ,ucIndex) ; SaveVGARegisters->CR[ucIndex] = VGA_RD_REG(0x015) ; } /* Sequencer Registers 1-4: index [3C4], data [3C5] */ for (ucIndex = 1 ; ucIndex < 4 ; ucIndex ++) { VGA_WR_REG(0x004 ,ucIndex) ; SaveVGARegisters->SR[ucIndex] = VGA_RD_REG(0x005) ; } /* Graphics Controller Registers 0-8: index [3CE], data [3CF] */ for (ucIndex = 0 ; ucIndex < 8 ; ucIndex ++) { VGA_WR_REG(0x00E ,ucIndex) ; SaveVGARegisters->GR[ucIndex] = VGA_RD_REG(0x00F) ; } /* Attribute Controller Registers 0-14: index and data [3C0]w, [3C1]r */ VGA_RD_REG(0x01A) ; /* set toggle to index mode */ for (ucIndex = 0 ; ucIndex < 0x14 ; ucIndex ++) { VGA_WR_REG(0x000 ,ucIndex) ; /* write index */ SaveVGARegisters->AR[ucIndex] = VGA_RD_REG(0x001) ; /* read data */ VGA_WR_REG(0x000 ,SaveVGARegisters->AR[ucIndex]) ; /* toggle */ } #ifdef RESTORE_DAC //Look-Up Table: Read Index [3C7]w, Write Index [3C8], Data [3C9] VGA_WR_REG(0x007 ,0) ; //set read index to 0 for (ulIndex = 0 ; ulIndex < (3 * 256) ; ulIndex ++) { SaveVGARegisters->LUT[ulIndex] = VGA_RD_REG(0x009) ; } #endif //RESTORE_DAC } void P91RestoreVGAregs(PHW_DEVICE_EXTENSION HwDeviceExtension,VGA_REGS * SaveVGARegisters) { UCHAR ucIndex ; ULONG ulIndex ; UCHAR temp; WriteP9ConfigRegister(HwDeviceExtension,P91_CONFIG_MODE,0x2); /* Put the VGA back in color mode for our PROM */ VGA_WR_REG(MISCOUT ,1) ; /* Enable VGA Registers: [3C3] = 1 */ VGA_WR_REG(0x003 ,1) ; /* Miscellaneous Output Register: [3C2]w, [3CC]r */ VGA_WR_REG(0x002 ,SaveVGARegisters->MiscOut) ; /* Enable CR0-CR7: CR11[7] = 0 */ VGA_WR_REG(0x014 ,0x11) ; VGA_WR_REG(0x015 ,SaveVGARegisters->CR[0x11] & 0x7F) ; /* CRT Controller Registers 0-18: index [3D4], data [3D5] */ for (ucIndex = 0 ; ucIndex < 0x18 ; ucIndex ++) { VGA_WR_REG(0x014 ,ucIndex) ; VGA_WR_REG(0x015 ,SaveVGARegisters->CR[ucIndex]) ; } /* Synchronous Reset: SR0 = 1 */ VGA_WR_REG(0x004 ,0) ; VGA_WR_REG(0x005 ,1) ; /* ClockMode: SR1 */ VGA_WR_REG(0x004 ,1) ; VGA_WR_REG(0x005 ,SaveVGARegisters->SR[1]) ; /* Non Reset Mode: SR0 = 0 */ VGA_WR_REG(0x004 ,0) ; VGA_WR_REG(0x005 ,0) ; /* Sequencer Registers 2-4: index [3C4], data [3C5] */ for (ucIndex = 2 ; ucIndex < 4 ; ucIndex ++) { VGA_WR_REG(0x004 ,ucIndex) ; VGA_WR_REG(0x005 ,SaveVGARegisters->SR[ucIndex]) ; } /* Graphics Controller Regs 0-8: index [3CE], data [3CF] */ VGA_WR_REG(0x00E ,1) ; VGA_WR_REG(0x00F ,0x0F) ; /* enable all 4 planes for GR0 */ for (ucIndex = 0 ; ucIndex < 8 ; ucIndex ++) { VGA_WR_REG(0x00E ,ucIndex) ; VGA_WR_REG(0x00F ,SaveVGARegisters->GR[ucIndex]) ; } /* Attrib Controller Regs 0-14:index and data [3C0]w,[3C1]r */ VGA_RD_REG(0x01A) ; /* set toggle to index mode */ for (ucIndex = 0 ; ucIndex < 0x14 ; ucIndex ++) { VGA_WR_REG(0x000 ,ucIndex) ; /* write index */ VGA_WR_REG(0x000 ,SaveVGARegisters->AR[ucIndex]) ; /* write data */ } VGA_WR_REG(0x000 ,0x20) ; /* set index[5] to 1 */ #ifdef SAVE_INDEX_REGS // Restore index registers. VGA_WR_REG(0x004, 0x002); temp = VGA_RD_REG(0x004); VideoDebugPrint((1, "Restore: 3c4:%x\n", temp)); VGA_WR_REG(0x00e, 0x005); temp = VGA_RD_REG(0x00e); VideoDebugPrint((1, "Restore: 3ce:%x\n", temp)); VGA_WR_REG(0x014, 0x0011); temp = VGA_RD_REG(0x014); VideoDebugPrint((1, "Restore: 3d4:%x\n", temp)); #endif #ifdef RESTORE_DAC //Look-Up Table: //Read Index [3C7]w, Write Index [3C8], Data [3C9] VGA_WR_REG(0x008 ,0) ; // set write index to 0 for (ulIndex = 0 ; ulIndex < (3 * 256) ; ulIndex ++) { VGA_WR_REG(0x009 ,SaveVGARegisters->LUT[ulIndex]) ; } #endif //RESTORE_DAC }