2 * PROJECT: NEC PC-98 series HAL
3 * LICENSE: GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later)
4 * PURPOSE: RTC and NVRAM access routines
5 * COPYRIGHT: Copyright 2020 Dmitry Borisov (di.sean@protonmail.com)
8 /* INCLUDES ******************************************************************/
15 /* GLOBALS *******************************************************************/
18 * The PC-98 hardware maps data from the NVRAM directly into the text video
19 * memory address space. Every fourth byte is a "writable data".
21 * |0x2FE2|0x2FE3|0x2FE4|0x2FE5|0x2FE6|0x2FE7| .... |0x2FFD|0x2FFE|
22 * | D | | | | D | | .... | | D |
24 * Most of these bits of the NVRAM are already used. There are some reserved
25 * bits in the 0x3FE6 and 0x3FFE that we can use.
27 #define NVRAM_START 0x3FE2
28 #define NVRAM_SIZE 0x1C
29 #define NVRAM_UNUSED_REG 0x14
30 #define NVRAM_UNUSED_BIT 0x80
32 static ULONG_PTR MappedNvram
;
34 /* PRIVATE FUNCTIONS *********************************************************/
36 /* Avoid double calls */
42 return ((Bcd
& 0xF0) >> 4) * 10 + (Bcd
& 0x0F);
50 return READ_REGISTER_UCHAR((PUCHAR
)(MappedNvram
+ Register
));
53 _Requires_lock_held_(HalpSystemHardwareLock
)
60 __outbyte(GDC1_IO_o_MODE_FLIPFLOP1
, GDC1_NVRAM_UNPROTECT
);
61 WRITE_REGISTER_UCHAR((PUCHAR
)(MappedNvram
+ Register
), Value
);
62 __outbyte(GDC1_IO_o_MODE_FLIPFLOP1
, GDC1_NVRAM_PROTECT
);
65 _Requires_lock_held_(HalpSystemHardwareLock
)
73 /* Read byte from single wire bus */
74 for (i
= 0; i
< 8; i
++)
76 Byte
|= (__inbyte(PPI_IO_i_PORT_B
) & 1) << i
;
78 __outbyte(RTC_IO_o_DATA
, RTC_CLOCK
| RTC_CMD_SERIAL_TRANSFER_MODE
);
79 KeStallExecutionProcessor(1);
81 __outbyte(RTC_IO_o_DATA
, RTC_CMD_SERIAL_TRANSFER_MODE
);
82 KeStallExecutionProcessor(1);
88 _Requires_lock_held_(HalpSystemHardwareLock
)
96 __outbyte(RTC_IO_o_DATA
, Bit
| RTC_CMD_SERIAL_TRANSFER_MODE
);
97 KeStallExecutionProcessor(1);
99 __outbyte(RTC_IO_o_DATA
, Bit
| RTC_CLOCK
| RTC_CMD_SERIAL_TRANSFER_MODE
);
100 KeStallExecutionProcessor(1);
103 _Requires_lock_held_(HalpSystemHardwareLock
)
111 for (i
= 0; i
< 4; i
++)
112 HalpRtcWriteBit(Command
>> i
);
114 __outbyte(RTC_IO_o_DATA
, RTC_STROBE
| RTC_CMD_SERIAL_TRANSFER_MODE
);
115 KeStallExecutionProcessor(1);
117 __outbyte(RTC_IO_o_DATA
, RTC_CMD_SERIAL_TRANSFER_MODE
);
118 KeStallExecutionProcessor(1);
126 /* Not supported by hardware */
136 /* Not supported by hardware */
143 _In_ ULONG BusNumber
,
144 _In_ ULONG SlotNumber
,
145 _Out_writes_bytes_(Length
) PVOID Buffer
,
148 /* Not supported by hardware */
155 _In_ ULONG BusNumber
,
156 _In_ ULONG SlotNumber
,
157 _In_reads_bytes_(Length
) PVOID Buffer
,
160 /* Not supported by hardware */
167 HalpInitializeCmos(VOID
)
169 PHYSICAL_ADDRESS PhysicalAddress
;
171 /* TODO: Detect TVRAM address */
173 PhysicalAddress
.QuadPart
= VRAM_NORMAL_TEXT
+ NVRAM_START
;
175 PhysicalAddress
.QuadPart
= VRAM_HI_RESO_TEXT
+ NVRAM_START
;
176 MappedNvram
= (ULONG_PTR
)HalpMapPhysicalMemory64(PhysicalAddress
, BYTES_TO_PAGES(NVRAM_SIZE
));
179 /* PUBLIC FUNCTIONS **********************************************************/
183 HalGetEnvironmentVariable(
185 _In_ USHORT ValueLength
,
186 _Out_writes_z_(ValueLength
) PCH Value
)
190 /* Only variable supported on x86 */
191 if (_stricmp(Name
, "LastKnownGood"))
197 HalpAcquireCmosSpinLock();
199 Val
= HalpReadNvram(NVRAM_UNUSED_REG
) & NVRAM_UNUSED_BIT
;
201 HalpReleaseCmosSpinLock();
205 strncpy(Value
, "FALSE", ValueLength
);
207 strncpy(Value
, "TRUE", ValueLength
);
214 HalSetEnvironmentVariable(
220 /* Only variable supported on x86 */
221 if (_stricmp(Name
, "LastKnownGood"))
227 /* Check if this is true or false */
228 if (!_stricmp(Value
, "TRUE"))
230 HalpAcquireCmosSpinLock();
232 Val
= HalpReadNvram(NVRAM_UNUSED_REG
) | NVRAM_UNUSED_BIT
;
234 else if (!_stricmp(Value
, "FALSE"))
236 HalpAcquireCmosSpinLock();
238 Val
= HalpReadNvram(NVRAM_UNUSED_REG
) & ~NVRAM_UNUSED_BIT
;
246 HalpWriteNvram(NVRAM_UNUSED_REG
, Val
);
248 HalpReleaseCmosSpinLock();
255 HalQueryRealTimeClock(
256 _Out_ PTIME_FIELDS Time
)
260 HalpAcquireCmosSpinLock();
262 HalpRtcWriteCommand(RTC_CMD_TIME_READ
);
263 HalpRtcWriteCommand(RTC_CMD_REGISTER_SHIFT
);
264 KeStallExecutionProcessor(19);
266 /* Set the time data */
267 Time
->Second
= BCD_INT(HalpRtcReadByte());
268 Time
->Minute
= BCD_INT(HalpRtcReadByte());
269 Time
->Hour
= BCD_INT(HalpRtcReadByte());
270 Time
->Day
= BCD_INT(HalpRtcReadByte());
271 Temp
= HalpRtcReadByte();
272 Time
->Weekday
= Temp
& 0x0F;
273 Time
->Month
= Temp
>> 4;
274 Time
->Year
= BCD_INT(HalpRtcReadByte());
275 Time
->Milliseconds
= 0;
277 Time
->Year
+= (Time
->Year
>= 80) ? 1900 : 2000;
279 HalpRtcWriteCommand(RTC_CMD_REGISTER_HOLD
);
281 HalpReleaseCmosSpinLock();
289 _In_ PTIME_FIELDS Time
)
294 HalpAcquireCmosSpinLock();
296 HalpRtcWriteCommand(RTC_CMD_REGISTER_SHIFT
);
298 SysTime
[0] = INT_BCD(Time
->Second
);
299 SysTime
[1] = INT_BCD(Time
->Minute
);
300 SysTime
[2] = INT_BCD(Time
->Hour
);
301 SysTime
[3] = INT_BCD(Time
->Day
);
302 SysTime
[4] = (Time
->Month
<< 4) | (Time
->Weekday
& 0x0F);
303 SysTime
[5] = INT_BCD(Time
->Year
% 100);
305 /* Write time fields to RTC */
306 for (i
= 0; i
< 6; i
++)
308 for (j
= 0; j
< 8; j
++)
309 HalpRtcWriteBit(SysTime
[i
] >> j
);
312 HalpRtcWriteCommand(RTC_CMD_TIME_SET_COUNTER_HOLD
);
313 HalpRtcWriteCommand(RTC_CMD_REGISTER_HOLD
);
315 HalpReleaseCmosSpinLock();