[PATCH v4 3/8] hv: support 12 hour mode


Zhao, Yuanyuan
 

Add support for hour format.
Bit 1 of register B indicates the hour byte format. When it's 0,
twelve-hour mode is selected. Then the seventh bit of hour register
presents AM as 0 and PM as 1.

Signed-off-by: Yuanyuan Zhao <yuanyuan.zhao@...>
---
hypervisor/dm/vrtc.c | 76 +++++++++++++++++++++++++++--
hypervisor/include/dm/mc146818rtc.h | 1 +
2 files changed, 74 insertions(+), 3 deletions(-)

diff --git a/hypervisor/dm/vrtc.c b/hypervisor/dm/vrtc.c
index 9ba31ae03..8d42db44d 100644
--- a/hypervisor/dm/vrtc.c
+++ b/hypervisor/dm/vrtc.c
@@ -239,12 +239,12 @@ static time_t rtc_to_secs(const struct acrn_vrtc *vrtc)
struct clktime ct;
time_t second = VRTC_BROKEN_TIME;
const struct rtcdev *rtc= &vrtc->rtcdev;
- int32_t err = 0;
+ int32_t err = 0, hour = 0, pm = 0;
uint32_t century = 0, year = 0;

do {
if (rtcget(rtc, rtc->sec, &ct.sec) < 0 || rtcget(rtc, rtc->min, &ct.min) < 0 ||
- rtcget(rtc, rtc->hour, &ct.hour) < 0 || rtcget(rtc, rtc->day_of_month, &ct.day) < 0 ||
+ rtcget(rtc, rtc->day_of_month, &ct.day) < 0 ||
rtcget(rtc, rtc->month, &ct.mon) < 0 || rtcget(rtc, rtc->year, &year) < 0 ||
rtcget(rtc, rtc->century, &century) < 0) {
RTC_ERR("Invalid RTC sec %#x hour %#x day %#x mon %#x year %#x century %#x\n",
@@ -254,6 +254,47 @@ static time_t rtc_to_secs(const struct acrn_vrtc *vrtc)
break;
}

+ /*
+ * If 12 hour format is inuse, translate it to 24 hour format here.
+ */
+ pm = 0;
+ hour = rtc->hour;
+ if ((rtc->reg_b & RTCSB_24HR) == 0) {
+ if (hour & 0x80U) {
+ hour &= ~0x80U;
+ pm = 1;
+ }
+ }
+ err = rtcget(rtc, hour, &ct.hour);
+ if (err) {
+ RTC_ERR("Invalid RTC hour %#x/%d\n", rtc->hour, ct.hour);
+ break;
+ }
+ if ((rtc->reg_b & RTCSB_24HR) == 0) {
+ if (ct.hour >= 1 && ct.hour <= 12) {
+ /*
+ * Convert from 12-hour format to internal 24-hour
+ * representation as follows:
+ *
+ * 12-hour format ct.hour
+ * 12 AM 0
+ * 1 - 11 AM 1 - 11
+ * 12 PM 12
+ * 1 - 11 PM 13 - 23
+ */
+ if (ct.hour == 12) {
+ ct.hour = 0;
+ }
+ if (pm) {
+ ct.hour += 12;
+ }
+ } else {
+ RTC_ERR("Invalid RTC 12-hour format %#x/%d\n",
+ rtc->hour, ct.hour);
+ break;
+ }
+ }
+
/*
* Ignore 'rtc->dow' because some guests like Linux don't bother
* setting it at all while others like OpenBSD/i386 set it incorrectly.
@@ -289,12 +330,41 @@ static void secs_to_rtc(time_t rtctime, struct acrn_vrtc *vrtc)
{
struct clktime ct;
struct rtcdev *rtc;
+ int32_t hour;

if (rtctime > 0 && clk_ts_to_ct(rtctime, &ct) == 0) {
rtc = &vrtc->rtcdev;
rtc->sec = rtcset(rtc, ct.sec);
rtc->min = rtcset(rtc, ct.min);
- rtc->hour = rtcset(rtc, ct.hour);
+
+ if (rtc->reg_b & RTCSB_24HR) {
+ hour = ct.hour;
+ } else {
+ /*
+ * Convert to the 12-hour format.
+ */
+ switch (ct.hour) {
+ case 0: /* 12 AM */
+ case 12: /* 12 PM */
+ hour = 12;
+ break;
+ default:
+ /*
+ * The remaining 'ct.hour' values are interpreted as:
+ * [1 - 11] -> 1 - 11 AM
+ * [13 - 23] -> 1 - 11 PM
+ */
+ hour = ct.hour % 12;
+ break;
+ }
+ }
+
+ rtc->hour = rtcset(rtc, hour);
+
+ if ((rtc->reg_b & RTCSB_24HR) == 0 && ct.hour >= 12) {
+ rtc->hour |= 0x80; /* set MSB to indicate PM */
+ }
+
rtc->day_of_week = rtcset(rtc, ct.dow + 1);
rtc->day_of_month = rtcset(rtc, ct.day);
rtc->month = rtcset(rtc, ct.mon);
diff --git a/hypervisor/include/dm/mc146818rtc.h b/hypervisor/include/dm/mc146818rtc.h
index 4baf9de69..b23f90d34 100644
--- a/hypervisor/include/dm/mc146818rtc.h
+++ b/hypervisor/include/dm/mc146818rtc.h
@@ -58,6 +58,7 @@
#define RTCSA_TUP 0x80 /* time update, don't look now */

#define RTC_STATUSB 0x0b /* status register B */
+#define RTCSB_24HR 0x02 /* 0 = 12 hours, 1 = 24 hours */
#define RTCSB_BCD 0x04 /* 0 = BCD, 1 = Binary coded time */

#define RTC_INTR 0x0c /* status register C (R) interrupt source */
--
2.25.1

Join acrn-dev@lists.projectacrn.org to automatically receive all group messages.