Skip to content

Commit 493a731

Browse files
authored
feat(rtc): add init/readtime/settime (#632)
* add readtime,settime Signed-off-by: Koichi <koichi.imai.2@tier4.jp> * add init and fix Signed-off-by: Koichi Imai <koichi.imai.2@tier4.jp> * add rtc init Signed-off-by: Koichi Imai <koichi.imai.2@tier4.jp> * fix Signed-off-by: Koichi <koichi.imai.2@tier4.jp> * fix Signed-off-by: Koichi <koichi.imai.2@tier4.jp> * skip week of day calculation Signed-off-by: Koichi <koichi.imai.2@tier4.jp> * add comments Signed-off-by: Koichi <koichi.imai.2@tier4.jp> * interrupt guard Signed-off-by: Koichi <koichi.imai.2@tier4.jp> * minimize interrupt guard and delete comments Signed-off-by: Koichi <koichi.imai.2@tier4.jp> --------- Signed-off-by: Koichi <koichi.imai.2@tier4.jp> Signed-off-by: Koichi Imai <koichi.imai.2@tier4.jp>
1 parent c441c1c commit 493a731

File tree

2 files changed

+112
-40
lines changed

2 files changed

+112
-40
lines changed
Lines changed: 90 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -1,36 +1,37 @@
11
//! MC146818-compatible CMOS RTC driver for x86_64, x86
22
3-
use super::RtcError;
3+
use super::{DateTime, RtcError};
4+
use awkernel_lib::interrupt::InterruptGuard;
45
use core::arch::asm;
56

6-
const _IO_RTC: u16 = 0x070;
7+
const IO_RTC: u16 = 0x070;
78

89
// The registers, and the bits within each register.
910

10-
const _MC_SEC: u8 = 0x00; // Time of year: seconds (0-59)
11-
const _MC_MIN: u8 = 0x02; // Time of year: minutes (0-59)
12-
const _MC_HOUR: u8 = 0x04; // Time of year: hour (see above)
13-
const _MC_DOW: u8 = 0x06; // Time of year: day of week (1-7)
14-
const _MC_DOM: u8 = 0x07; // Time of year: day of month (1-31)
15-
const _MC_MONTH: u8 = 0x08; // Time of year: month (1-12)
16-
const _MC_YEAR: u8 = 0x09; // Time of year: year in century (0-99)
11+
const MC_SEC: u8 = 0x00; // Time of year: seconds (0-59)
12+
const MC_MIN: u8 = 0x02; // Time of year: minutes (0-59)
13+
const MC_HOUR: u8 = 0x04; // Time of year: hour (see above)
14+
const MC_DOW: u8 = 0x06; // Time of year: day of week (1-7)
15+
const MC_DOM: u8 = 0x07; // Time of year: day of month (1-31)
16+
const MC_MONTH: u8 = 0x08; // Time of year: month (1-12)
17+
const MC_YEAR: u8 = 0x09; // Time of year: year in century (0-99)
1718

18-
const _MC_REGA: u8 = 0x0a; // Control register A
19+
const MC_REGA: u8 = 0x0a; // Control register A
1920

2021
const _MC_REGA_RSMASK: u8 = 0x0f; // Interrupt rate select mask
2122
const _MC_REGA_DVMASK: u8 = 0x70; // Divisor select mask
22-
const _MC_REGA_UIP: u8 = 0x80; // Update in progress; read only
23+
const MC_REGA_UIP: u8 = 0x80; // Update in progress; read only
2324

24-
const _MC_REGB: u8 = 0x0b; // Control register B
25+
const MC_REGB: u8 = 0x0b; // Control register B
2526

2627
const _MC_REGB_DSE: u8 = 0x01; // Daylight Saving Enable
27-
const _MC_REGB_24HR: u8 = 0x02; // 24-hour mode (AM/PM mode when clear)
28+
const MC_REGB_24HR: u8 = 0x02; // 24-hour mode (AM/PM mode when clear)
2829
const _MC_REGB_DM: u8 = 0x04; // Binary mode (BCD mode when clear)
2930
const _MC_REGB_SQWE: u8 = 0x08; // Square wave enable, ONLY in BQ3285E
3031
const _MC_REGB_UIE: u8 = 0x10; // Update End interrupt enable
3132
const _MC_REGB_AIE: u8 = 0x20; // Alarm interrupt enable
3233
const _MC_REGB_PIE: u8 = 0x40; // Periodic interrupt enable
33-
const _MC_REGB_SET: u8 = 0x80; // Allow time to be set; stops updates
34+
const MC_REGB_SET: u8 = 0x80; // Allow time to be set; stops updates
3435

3536
const _MC_REGC: u8 = 0x0c; // Control register C
3637

@@ -39,17 +40,16 @@ const _MC_REGC_AF: u8 = 0x20; // Alarm interrupt flag
3940
const _MC_REGC_PF: u8 = 0x40; // Periodic interrupt flag
4041
const _MC_REGC_IRQF: u8 = 0x80; // Interrupt request pending flag
4142

42-
const _MC_REGD: u8 = 0x0d; // Control register D
43+
const MC_REGD: u8 = 0x0d; // Control register D
4344

4445
// MC_REGD_UNUSED 0x7f UNUSED
45-
const _MC_REGD_VRT: u8 = 0x80; // Valid RAM and Time bit
46+
const MC_REGD_VRT: u8 = 0x80; // Valid RAM and Time bit
4647

4748
// Number of TOD registers
4849
const _MC_NREGS: usize = 0xe; // 14 registers; CMOS follows
49-
const _MC_NTODREGS: usize = 0xa; // 10 of those are for TOD and alarm
50+
const MC_NTODREGS: usize = 0xa; // 10 of those are for TOD and alarm
5051

51-
#[allow(dead_code)]
52-
type McTodRegs = [u8; _MC_NTODREGS];
52+
type McTodRegs = [u8; MC_NTODREGS];
5353

5454
pub struct Mc146818Rtc;
5555

@@ -65,11 +65,11 @@ impl Default for Mc146818Rtc {
6565
}
6666
}
6767
impl Mc146818Rtc {
68-
fn _mc146818_read(reg: u8) -> u8 {
68+
fn mc146818_read(reg: u8) -> u8 {
6969
unsafe {
7070
asm!(
7171
"out dx, al",
72-
in("dx") _IO_RTC,
72+
in("dx") IO_RTC,
7373
in("al") reg,
7474
options(nostack, preserves_flags)
7575
);
@@ -79,19 +79,19 @@ impl Mc146818Rtc {
7979
let value: u8;
8080
asm!(
8181
"in al, dx",
82-
in("dx") _IO_RTC + 1,
82+
in("dx") IO_RTC + 1,
8383
out("al") value,
8484
options(nostack, preserves_flags)
8585
);
8686
value
8787
}
8888
}
8989

90-
fn _mc146818_write(reg: u8, value: u8) {
90+
fn mc146818_write(reg: u8, value: u8) {
9191
unsafe {
9292
asm!(
9393
"out dx, al",
94-
in("dx") _IO_RTC,
94+
in("dx") IO_RTC,
9595
in("al") reg,
9696
options(nostack, preserves_flags)
9797
);
@@ -100,7 +100,7 @@ impl Mc146818Rtc {
100100

101101
asm!(
102102
"out dx, al",
103-
in("dx") _IO_RTC + 1,
103+
in("dx") IO_RTC + 1,
104104
in("al") value,
105105
options(nostack, preserves_flags)
106106
);
@@ -109,52 +109,103 @@ impl Mc146818Rtc {
109109
}
110110
}
111111

112-
fn _bcdtobin(bcd: u8) -> u8 {
112+
fn bcdtobin(bcd: u8) -> u8 {
113113
(((bcd >> 4) & 0x0f) * 10) + (bcd & 0x0f)
114114
}
115115

116-
fn _bintobcd(bin: u8) -> u8 {
116+
fn bintobcd(bin: u8) -> u8 {
117117
(((bin / 10) << 4) & 0xf0) | ((bin % 10) & 0x0f)
118118
}
119119

120-
fn _rtcget() -> Result<McTodRegs, RtcError> {
121-
let mut regs = [0u8; _MC_NTODREGS];
120+
fn rtcget() -> Result<McTodRegs, RtcError> {
121+
let mut regs = [0u8; MC_NTODREGS];
122122

123-
if (Self::_mc146818_read(_MC_REGD) & _MC_REGD_VRT) == 0 {
123+
if (Self::mc146818_read(MC_REGD) & MC_REGD_VRT) == 0 {
124124
return Err(RtcError::HardwareError);
125125
}
126126

127127
// update in progress; spin loop
128-
while (Self::_mc146818_read(_MC_REGA) & _MC_REGA_UIP) != 0 {
128+
while (Self::mc146818_read(MC_REGA) & MC_REGA_UIP) != 0 {
129129
continue;
130130
}
131131

132132
loop {
133133
// read all of the tod/alarm regs
134-
for (i, reg) in regs.iter_mut().enumerate().take(_MC_NTODREGS) {
135-
*reg = Self::_mc146818_read(i as u8);
134+
for (i, reg) in regs.iter_mut().enumerate().take(MC_NTODREGS) {
135+
*reg = Self::mc146818_read(i as u8);
136136
}
137137

138-
if regs[_MC_SEC as usize] == Self::_mc146818_read(_MC_SEC) {
138+
if regs[MC_SEC as usize] == Self::mc146818_read(MC_SEC) {
139139
break;
140140
}
141141
}
142142

143143
Ok(regs)
144144
}
145145

146-
fn _rtcput(regs: &McTodRegs) -> Result<(), RtcError> {
146+
fn rtcput(regs: &McTodRegs) -> Result<(), RtcError> {
147147
// stop updates while setting
148-
Self::_mc146818_write(_MC_REGB, Self::_mc146818_read(_MC_REGB) | _MC_REGB_SET);
148+
Self::mc146818_write(MC_REGB, Self::mc146818_read(MC_REGB) | MC_REGB_SET);
149149

150150
// write all of the tod/alarm regs
151-
for (i, &reg) in regs.iter().enumerate().take(_MC_NTODREGS) {
152-
Self::_mc146818_write(i as u8, reg);
151+
for (i, &reg) in regs.iter().enumerate().take(MC_NTODREGS) {
152+
Self::mc146818_write(i as u8, reg);
153153
}
154154

155155
// reenable updates
156-
Self::_mc146818_write(_MC_REGB, Self::_mc146818_read(_MC_REGB) & !_MC_REGB_SET);
156+
Self::mc146818_write(MC_REGB, Self::mc146818_read(MC_REGB) & !MC_REGB_SET);
157157

158158
Ok(())
159159
}
160+
161+
pub fn gettime(&self) -> Result<DateTime, RtcError> {
162+
let regs = {
163+
let _guard = InterruptGuard::new();
164+
Self::rtcget()?
165+
};
166+
167+
let second = Self::bcdtobin(regs[MC_SEC as usize]);
168+
let minute = Self::bcdtobin(regs[MC_MIN as usize]);
169+
let hour = Self::bcdtobin(regs[MC_HOUR as usize]);
170+
let day = Self::bcdtobin(regs[MC_DOM as usize]);
171+
let month = Self::bcdtobin(regs[MC_MONTH as usize]);
172+
let year = Self::bcdtobin(regs[MC_YEAR as usize]);
173+
174+
// TODO: clock_expandyear()
175+
let full_year = 2000 + year as u16;
176+
177+
Ok(DateTime::new(full_year, month, day, hour, minute, second))
178+
}
179+
180+
pub fn settime(&self, time: &DateTime) -> Result<(), RtcError> {
181+
let mut regs = [0u8; MC_NTODREGS];
182+
183+
regs[MC_SEC as usize] = Self::bintobcd(time.second);
184+
regs[MC_MIN as usize] = Self::bintobcd(time.minute);
185+
regs[MC_HOUR as usize] = Self::bintobcd(time.hour);
186+
regs[MC_DOM as usize] = Self::bintobcd(time.day);
187+
regs[MC_MONTH as usize] = Self::bintobcd(time.month);
188+
regs[MC_YEAR as usize] = Self::bintobcd((time.year % 100) as u8);
189+
190+
// Day of week (1-7) - not calculated currently, just using placeholder
191+
// NOTE: Implement day of week calculation if needed
192+
regs[MC_DOW as usize] = 1;
193+
194+
regs[7] = 0;
195+
regs[8] = 0;
196+
regs[9] = 0;
197+
198+
{
199+
let _guard = InterruptGuard::new();
200+
Self::rtcput(&regs)?;
201+
}
202+
203+
// TODO: century byte update
204+
205+
Ok(())
206+
}
207+
208+
pub fn init(&self) {
209+
Self::mc146818_write(MC_REGB, MC_REGB_24HR);
210+
}
160211
}

kernel/src/arch/x86_64/kernel_main.rs

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -340,7 +340,28 @@ fn kernel_main2(
340340
num_cpu: non_primary_cpus.len() + 1,
341341
};
342342

343-
// 19. Call `crate::main()`.
343+
// 19. Initialize RTC.
344+
use awkernel_drivers::rtc::Mc146818Rtc;
345+
let rtc = Mc146818Rtc::new();
346+
rtc.init();
347+
match rtc.gettime() {
348+
Ok(time) => {
349+
log::info!(
350+
"RTC time: {:04}-{:02}-{:02} {:02}:{:02}:{:02}",
351+
time.year,
352+
time.month,
353+
time.day,
354+
time.hour,
355+
time.minute,
356+
time.second
357+
);
358+
}
359+
Err(e) => {
360+
log::warn!("Failed to read RTC time: {e:?}");
361+
}
362+
}
363+
364+
// 20. Call `crate::main()`.
344365
crate::main(kernel_info);
345366
}
346367

0 commit comments

Comments
 (0)