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