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