aboutsummaryrefslogtreecommitdiff
path: root/core/time-utils.c
blob: 10a4da4ccb13efd99aac0f7302198659e44f5225 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
/* Copyright 2013-2014 IBM Corp.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * 	http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
 * implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include <time-utils.h>

/* MSB is byte 3, LSB is byte 0 */
static unsigned int bcd_byte(uint32_t bcd, int byteno)
{
	bcd >>= byteno * 8;
	return (bcd >> 4 & 0xf) * 10 + (bcd & 0xf);
}

static uint32_t int_to_bcd2(unsigned int x)
{
	return (((x / 10) << 4) & 0xf0) | (x % 10);
}

static uint32_t int_to_bcd4(unsigned int x)
{
	return int_to_bcd2(x / 100) << 8 | int_to_bcd2(x % 100);
}

/*
 * Converts an OPAL formated datetime into a struct tm. We ignore microseconds
 * as Linux doesn't use them anyway.
 *
 *  |      year       | month |   mday   |
 *  +------------------------------------+
 *  |  hour  | minute | secs  | reserved |
 *  +------------------------------------+
 *  |             microseconds           |
 */

void datetime_to_tm(uint32_t y_m_d, uint64_t h_m_s_m, struct tm *tm)
{
	uint32_t x;

	tm->tm_year = bcd_byte(y_m_d, 3) * 100 + bcd_byte(y_m_d, 2);
	tm->tm_mon = bcd_byte(y_m_d, 1) - 1;
	tm->tm_mday = bcd_byte(y_m_d, 0);

	x = h_m_s_m >> 32;
	tm->tm_hour = bcd_byte(x, 3);
	tm->tm_min = bcd_byte(x, 2);
	tm->tm_sec = bcd_byte(x, 1);
}

/*
 * The OPAL API is defined as returned a u64 of a similar
 * format to the FSP message; the 32-bit date field is
 * in the format:
 *
 * |      year        | month |   mday   |
 *
 * ... and the 64-bit time field is in the format
 *
 * |  hour  | minutes | secs  | millisec |
 * | -------------------------------------
 * |        millisec          | reserved |
 *
 * We simply ignore the microseconds/milliseconds for now
 * as I don't quite understand why the OPAL API defines that
 * it needs 6 digits for the milliseconds :-) I suspect the
 * doc got that wrong and it's supposed to be micro but
 * let's ignore it.
 *
 * Note that Linux doesn't use nor set the ms field anyway.
 */
void tm_to_datetime(struct tm *tm, uint32_t *y_m_d, uint64_t *h_m_s_m)
{
	uint64_t h_m_s;
	*y_m_d = int_to_bcd4(tm->tm_year) << 16 |
		 int_to_bcd2(tm->tm_mon + 1) << 8 |
		 int_to_bcd2(tm->tm_mday);

	h_m_s = int_to_bcd2(tm->tm_hour) << 24 |
	        int_to_bcd2(tm->tm_min) << 16 |
	        int_to_bcd2(tm->tm_sec) << 8;

	*h_m_s_m = h_m_s << 32;
}