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