1 /* 2 * PROJECT: ReactOS framebuffer driver for NEC PC-98 series 3 * LICENSE: GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later) 4 * PURPOSE: Hardware support code 5 * COPYRIGHT: Copyright 2020 Dmitry Borisov (di.sean@protonmail.com) 6 */ 7 8 /* INCLUDES *******************************************************************/ 9 10 #include "pc98vid.h" 11 12 /* GLOBALS ********************************************************************/ 13 14 #ifdef ALLOC_PRAGMA 15 #pragma alloc_text(PAGE, Pc98VidSetCurrentMode) 16 #pragma alloc_text(PAGE, Pc98VidSetColorRegisters) 17 #pragma alloc_text(PAGE, Pc98VidGetPowerState) 18 #pragma alloc_text(PAGE, Pc98VidSetPowerState) 19 #endif 20 21 #define PEGC_MAX_COLORS 256 22 23 /* FUNCTIONS ******************************************************************/ 24 25 static BOOLEAN 26 GraphGetStatus( 27 _In_ UCHAR Status) 28 { 29 UCHAR Result; 30 31 VideoPortWritePortUchar((PUCHAR)GRAPH_IO_o_STATUS_SELECT, Status); 32 Result = VideoPortReadPortUchar((PUCHAR)GRAPH_IO_i_STATUS); 33 34 return (Result & GRAPH_STATUS_SET) && (Result != 0xFF); 35 } 36 37 static BOOLEAN 38 TestMmio( 39 _In_ PHW_DEVICE_EXTENSION DeviceExtension) 40 { 41 USHORT OldValue, NewValue; 42 43 OldValue = VideoPortReadRegisterUshort((PUSHORT)(DeviceExtension->PegcControlVa + 44 PEGC_MMIO_MODE)); 45 46 /* Bits [15:1] are not writable */ 47 VideoPortWriteRegisterUshort((PUSHORT)(DeviceExtension->PegcControlVa + 48 PEGC_MMIO_MODE), 0x80); 49 NewValue = VideoPortReadRegisterUshort((PUSHORT)(DeviceExtension->PegcControlVa + 50 PEGC_MMIO_MODE)); 51 52 VideoPortWriteRegisterUshort((PUSHORT)(DeviceExtension->PegcControlVa + 53 PEGC_MMIO_MODE), OldValue); 54 55 return !(NewValue & 0x80); 56 } 57 58 static VOID 59 TextSync(VOID) 60 { 61 while (VideoPortReadPortUchar((PUCHAR)GDC1_IO_i_STATUS) & GDC_STATUS_VSYNC) 62 NOTHING; 63 64 while (!(VideoPortReadPortUchar((PUCHAR)GDC1_IO_i_STATUS) & GDC_STATUS_VSYNC)) 65 NOTHING; 66 } 67 68 BOOLEAN 69 NTAPI 70 HasPegcController( 71 _In_ PHW_DEVICE_EXTENSION DeviceExtension) 72 { 73 BOOLEAN Success; 74 75 if (GraphGetStatus(GRAPH_STATUS_PEGC)) 76 return TestMmio(DeviceExtension); 77 78 VideoPortWritePortUchar((PUCHAR)GDC2_IO_o_MODE_FLIPFLOP2, GDC2_EGC_FF_UNPROTECT); 79 VideoPortWritePortUchar((PUCHAR)GDC2_IO_o_MODE_FLIPFLOP2, GDC2_MODE_PEGC_ENABLE); 80 Success = GraphGetStatus(GRAPH_STATUS_PEGC) ? TestMmio(DeviceExtension) : FALSE; 81 VideoPortWritePortUchar((PUCHAR)GDC2_IO_o_MODE_FLIPFLOP2, GDC2_MODE_PEGC_DISABLE); 82 VideoPortWritePortUchar((PUCHAR)GDC2_IO_o_MODE_FLIPFLOP2, GDC2_EGC_FF_PROTECT); 83 84 return Success; 85 } 86 87 VP_STATUS 88 FASTCALL 89 Pc98VidSetCurrentMode( 90 _In_ PHW_DEVICE_EXTENSION DeviceExtension, 91 _In_ PVIDEO_MODE RequestedMode) 92 { 93 SYNCPARAM SyncParameters; 94 CSRFORMPARAM CursorParameters; 95 CSRWPARAM CursorPosition; 96 PITCHPARAM PitchParameters; 97 PRAMPARAM RamParameters; 98 ZOOMPARAM ZoomParameters; 99 UCHAR RelayState; 100 101 PAGED_CODE(); 102 103 VideoDebugPrint((Trace, "%s() Mode %d\n", 104 __FUNCTION__, RequestedMode->RequestedMode)); 105 106 if (RequestedMode->RequestedMode > DeviceExtension->ModeCount) 107 return ERROR_INVALID_PARAMETER; 108 109 /* Blank screen */ 110 VideoPortWritePortUchar((PUCHAR)GDC1_IO_o_MODE_FLIPFLOP1, GRAPH_MODE_DISPLAY_DISABLE); 111 112 /* RESET, without FIFO check */ 113 VideoPortWritePortUchar((PUCHAR)GDC1_IO_o_COMMAND, GDC_COMMAND_RESET1); 114 VideoPortWritePortUchar((PUCHAR)GDC2_IO_o_COMMAND, GDC_COMMAND_RESET1); 115 116 /* Configure chipset */ 117 VideoPortWritePortUchar((PUCHAR)GDC1_IO_o_MODE_FLIPFLOP1, GRAPH_MODE_COLORED); 118 VideoPortWritePortUchar((PUCHAR)GDC1_IO_o_MODE_FLIPFLOP1, GDC2_MODE_ODD_RLINE_SHOW); 119 VideoPortWritePortUchar((PUCHAR)GDC2_IO_o_MODE_FLIPFLOP2, GDC2_MODE_COLORS_16); 120 VideoPortWritePortUchar((PUCHAR)GDC2_IO_o_MODE_FLIPFLOP2, GDC2_MODE_GRCG); 121 VideoPortWritePortUchar((PUCHAR)GDC2_IO_o_MODE_FLIPFLOP2, GDC2_MODE_LCD); 122 VideoPortWritePortUchar((PUCHAR)GDC2_IO_o_MODE_FLIPFLOP2, GDC2_MODE_LINES_400); 123 VideoPortWritePortUchar((PUCHAR)GDC2_IO_o_MODE_FLIPFLOP2, 124 VideoModes[RequestedMode->RequestedMode].Clock1); 125 VideoPortWritePortUchar((PUCHAR)GDC2_IO_o_MODE_FLIPFLOP2, 126 VideoModes[RequestedMode->RequestedMode].Clock2); 127 VideoPortWritePortUchar((PUCHAR)GRAPH_IO_o_HORIZONTAL_SCAN_RATE, 128 VideoModes[RequestedMode->RequestedMode].HorizontalScanRate); 129 VideoPortWritePortUchar((PUCHAR)GDC2_IO_o_VIDEO_PAGE, 0); 130 VideoPortWritePortUchar((PUCHAR)GDC2_IO_o_VIDEO_PAGE_ACCESS, 0); 131 132 /* =========================== MASTER ============================ */ 133 134 /* MASTER */ 135 WRITE_GDC1_COMMAND(GDC_COMMAND_MASTER); 136 137 /* SYNC */ 138 SyncParameters = VideoModes[RequestedMode->RequestedMode].TextSyncParameters; 139 SyncParameters.Flags = SYNC_DISPLAY_MODE_GRAPHICS_AND_CHARACTERS | SYNC_VIDEO_FRAMING_NONINTERLACED | 140 SYNC_DRAW_ONLY_DURING_RETRACE_BLANKING | SYNC_STATIC_RAM_NO_REFRESH; 141 WRITE_GDC1_COMMAND(GDC_COMMAND_SYNC_ON); 142 WRITE_GDC_SYNC((PUCHAR)GDC1_IO_o_PARAM, &SyncParameters); 143 144 /* CSRFORM */ 145 CursorParameters.Show = FALSE; 146 CursorParameters.Blink = FALSE; 147 CursorParameters.BlinkRate = 12; 148 CursorParameters.LinesPerRow = 16; 149 CursorParameters.StartScanLine = 0; 150 CursorParameters.EndScanLine = 15; 151 WRITE_GDC1_COMMAND(GDC_COMMAND_CSRFORM); 152 WRITE_GDC_CSRFORM((PUCHAR)GDC1_IO_o_PARAM, &CursorParameters); 153 154 /* PITCH */ 155 PitchParameters.WordsPerScanline = 80; 156 WRITE_GDC1_COMMAND(GDC_COMMAND_PITCH); 157 WRITE_GDC_PITCH((PUCHAR)GDC1_IO_o_PARAM, &PitchParameters); 158 159 /* PRAM */ 160 RamParameters.StartingAddress = 0; 161 RamParameters.Length = 1023; 162 RamParameters.ImageBit = FALSE; 163 RamParameters.WideDisplay = FALSE; 164 WRITE_GDC1_COMMAND(GDC_COMMAND_PRAM); 165 WRITE_GDC_PRAM((PUCHAR)GDC1_IO_o_PARAM, &RamParameters); 166 167 /* ZOOM */ 168 ZoomParameters.DisplayZoomFactor = 0; 169 ZoomParameters.WritingZoomFactor = 0; 170 WRITE_GDC1_COMMAND(GDC_COMMAND_ZOOM); 171 WRITE_GDC_ZOOM((PUCHAR)GDC1_IO_o_PARAM, &ZoomParameters); 172 173 /* CSRW */ 174 CursorPosition.CursorAddress = 0; 175 CursorPosition.DotAddress = 0; 176 WRITE_GDC1_COMMAND(GDC_COMMAND_CSRW); 177 WRITE_GDC_CSRW((PUCHAR)GDC1_IO_o_PARAM, &CursorPosition); 178 179 /* START */ 180 WRITE_GDC1_COMMAND(GDC_COMMAND_BCTRL_START); 181 182 /* ============================ SLAVE ============================ */ 183 184 /* SLAVE */ 185 WRITE_GDC2_COMMAND(GDC_COMMAND_SLAVE); 186 187 /* SYNC */ 188 SyncParameters = VideoModes[RequestedMode->RequestedMode].VideoSyncParameters; 189 SyncParameters.Flags = SYNC_DISPLAY_MODE_GRAPHICS | SYNC_VIDEO_FRAMING_NONINTERLACED | 190 SYNC_DRAW_DURING_ACTIVE_DISPLAY_TIME_AND_RETRACE_BLANKING | 191 SYNC_STATIC_RAM_NO_REFRESH; 192 WRITE_GDC2_COMMAND(GDC_COMMAND_SYNC_ON); 193 WRITE_GDC_SYNC((PUCHAR)GDC2_IO_o_PARAM, &SyncParameters); 194 195 /* CSRFORM */ 196 CursorParameters.Show = FALSE; 197 CursorParameters.Blink = FALSE; 198 CursorParameters.BlinkRate = 0; 199 CursorParameters.LinesPerRow = 1; 200 CursorParameters.StartScanLine = 0; 201 CursorParameters.EndScanLine = 0; 202 WRITE_GDC2_COMMAND(GDC_COMMAND_CSRFORM); 203 WRITE_GDC_CSRFORM((PUCHAR)GDC2_IO_o_PARAM, &CursorParameters); 204 205 /* PITCH */ 206 PitchParameters.WordsPerScanline = 80; 207 WRITE_GDC2_COMMAND(GDC_COMMAND_PITCH); 208 WRITE_GDC_PITCH((PUCHAR)GDC2_IO_o_PARAM, &PitchParameters); 209 210 /* PRAM */ 211 RamParameters.StartingAddress = 0; 212 RamParameters.Length = 1023; 213 RamParameters.ImageBit = TRUE; 214 RamParameters.WideDisplay = FALSE; 215 WRITE_GDC2_COMMAND(GDC_COMMAND_PRAM); 216 WRITE_GDC_PRAM((PUCHAR)GDC2_IO_o_PARAM, &RamParameters); 217 218 /* ZOOM */ 219 ZoomParameters.DisplayZoomFactor = 0; 220 ZoomParameters.WritingZoomFactor = 0; 221 WRITE_GDC2_COMMAND(GDC_COMMAND_ZOOM); 222 WRITE_GDC_ZOOM((PUCHAR)GDC2_IO_o_PARAM, &ZoomParameters); 223 224 /* CSRW */ 225 CursorPosition.CursorAddress = 0; 226 CursorPosition.DotAddress = 0; 227 WRITE_GDC2_COMMAND(GDC_COMMAND_CSRW); 228 WRITE_GDC_CSRW((PUCHAR)GDC2_IO_o_PARAM, &CursorPosition); 229 230 /* Synchronize the master sync source */ 231 TextSync(); 232 TextSync(); 233 TextSync(); 234 TextSync(); 235 236 /* START */ 237 WRITE_GDC2_COMMAND(GDC_COMMAND_BCTRL_START); 238 239 /* 256 colors, packed pixel */ 240 VideoPortWritePortUchar((PUCHAR)GDC2_IO_o_MODE_FLIPFLOP2, GDC2_EGC_FF_UNPROTECT); 241 VideoPortWritePortUchar((PUCHAR)GDC2_IO_o_MODE_FLIPFLOP2, GDC2_MODE_PEGC_ENABLE); 242 VideoPortWritePortUchar((PUCHAR)GDC2_IO_o_MODE_FLIPFLOP2, 243 VideoModes[RequestedMode->RequestedMode].Mem); 244 VideoPortWritePortUchar((PUCHAR)GDC2_IO_o_MODE_FLIPFLOP2, GDC2_EGC_FF_PROTECT); 245 VideoPortWriteRegisterUshort((PUSHORT)(DeviceExtension->PegcControlVa + 246 PEGC_MMIO_MODE), PEGC_MODE_PACKED); 247 VideoPortWriteRegisterUshort((PUSHORT)(DeviceExtension->PegcControlVa + 248 PEGC_MMIO_FRAMEBUFFER), PEGC_FB_MAP); 249 250 /* Select the video source */ 251 RelayState = VideoPortReadPortUchar((PUCHAR)GRAPH_IO_i_RELAY) & 252 ~(GRAPH_RELAY_0 | GRAPH_RELAY_1); 253 RelayState |= GRAPH_VID_SRC_INTERNAL | GRAPH_SRC_GDC; 254 VideoPortWritePortUchar((PUCHAR)GRAPH_IO_o_RELAY, RelayState); 255 256 /* Unblank screen */ 257 VideoPortWritePortUchar((PUCHAR)GDC1_IO_o_MODE_FLIPFLOP1, GRAPH_MODE_DISPLAY_ENABLE); 258 259 DeviceExtension->CurrentMode = RequestedMode->RequestedMode; 260 261 return NO_ERROR; 262 } 263 264 VP_STATUS 265 FASTCALL 266 Pc98VidSetColorRegisters( 267 _In_ PVIDEO_CLUT ColorLookUpTable) 268 { 269 USHORT Entry; 270 271 PAGED_CODE(); 272 273 VideoDebugPrint((Trace, "%s()\n", __FUNCTION__)); 274 275 if (ColorLookUpTable->NumEntries > PEGC_MAX_COLORS) 276 return ERROR_INVALID_PARAMETER; 277 278 for (Entry = ColorLookUpTable->FirstEntry; 279 Entry < ColorLookUpTable->FirstEntry + ColorLookUpTable->NumEntries; 280 ++Entry) 281 { 282 VideoPortWritePortUchar((PUCHAR)GDC2_IO_o_PALETTE_INDEX, Entry); 283 VideoPortWritePortUchar((PUCHAR)GDC2_IO_o_RED, 284 ColorLookUpTable->LookupTable[Entry].RgbArray.Red); 285 VideoPortWritePortUchar((PUCHAR)GDC2_IO_o_GREEN, 286 ColorLookUpTable->LookupTable[Entry].RgbArray.Green); 287 VideoPortWritePortUchar((PUCHAR)GDC2_IO_o_BLUE, 288 ColorLookUpTable->LookupTable[Entry].RgbArray.Blue); 289 } 290 291 return NO_ERROR; 292 } 293 294 VP_STATUS 295 NTAPI 296 Pc98VidGetPowerState( 297 _In_ PVOID HwDeviceExtension, 298 _In_ ULONG HwId, 299 _In_ PVIDEO_POWER_MANAGEMENT VideoPowerControl) 300 { 301 PAGED_CODE(); 302 303 VideoDebugPrint((Trace, "%s() Id %lX, State %x\n", 304 __FUNCTION__, HwId, VideoPowerControl->PowerState)); 305 306 if (HwId == MONITOR_HW_ID || HwId == DISPLAY_ADAPTER_HW_ID) 307 { 308 switch (VideoPowerControl->PowerState) 309 { 310 case VideoPowerOn: 311 case VideoPowerStandBy: 312 case VideoPowerSuspend: 313 case VideoPowerOff: 314 case VideoPowerShutdown: 315 return NO_ERROR; 316 } 317 } 318 319 return ERROR_DEVICE_REINITIALIZATION_NEEDED; 320 } 321 322 VP_STATUS 323 NTAPI 324 Pc98VidSetPowerState( 325 _In_ PVOID HwDeviceExtension, 326 _In_ ULONG HwId, 327 _In_ PVIDEO_POWER_MANAGEMENT VideoPowerControl) 328 { 329 UCHAR Dpms; 330 331 PAGED_CODE(); 332 333 VideoDebugPrint((Trace, "%s() Id %lX, State %x\n", 334 __FUNCTION__, HwId, VideoPowerControl->PowerState)); 335 336 if (HwId == MONITOR_HW_ID) 337 { 338 Dpms = VideoPortReadPortUchar((PUCHAR)GRAPH_IO_i_DPMS); 339 340 switch (VideoPowerControl->PowerState) 341 { 342 case VideoPowerOn: 343 /* Turn on HS/VS signals */ 344 Dpms &= ~(GRAPH_DPMS_HSYNC_MASK | GRAPH_DPMS_VSYNC_MASK); 345 VideoPortWritePortUchar((PUCHAR)GRAPH_IO_o_DPMS, Dpms); 346 347 /* Unblank screen */ 348 VideoPortWritePortUchar((PUCHAR)GDC1_IO_o_MODE_FLIPFLOP1, 349 GRAPH_MODE_DISPLAY_ENABLE); 350 break; 351 352 case VideoPowerStandBy: 353 /* Disable HS signal */ 354 Dpms = (Dpms | GRAPH_DPMS_HSYNC_MASK) & ~GRAPH_DPMS_VSYNC_MASK; 355 VideoPortWritePortUchar((PUCHAR)GRAPH_IO_o_DPMS, Dpms); 356 break; 357 358 case VideoPowerSuspend: 359 /* Disable VS signal */ 360 Dpms = (Dpms | GRAPH_DPMS_VSYNC_MASK) & ~GRAPH_DPMS_HSYNC_MASK; 361 VideoPortWritePortUchar((PUCHAR)GRAPH_IO_o_DPMS, Dpms); 362 break; 363 364 case VideoPowerOff: 365 case VideoPowerShutdown: 366 /* Turn off HS/VS signals */ 367 Dpms |= GRAPH_DPMS_HSYNC_MASK | GRAPH_DPMS_VSYNC_MASK; 368 VideoPortWritePortUchar((PUCHAR)GRAPH_IO_o_DPMS, Dpms); 369 370 /* Blank screen */ 371 VideoPortWritePortUchar((PUCHAR)GDC1_IO_o_MODE_FLIPFLOP1, 372 GRAPH_MODE_DISPLAY_DISABLE); 373 break; 374 } 375 } 376 377 return NO_ERROR; 378 } 379