1
/* Copyright 2015 IBM Corp.
3
* Licensed under the Apache License, Version 2.0 (the "License");
4
* you may not use this file except in compliance with the License.
5
* You may obtain a copy of the License at
7
* http://www.apache.org/licenses/LICENSE-2.0
9
* Unless required by applicable law or agreed to in writing, software
10
* distributed under the License is distributed on an "AS IS" BASIS,
11
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
13
* See the License for the specific language governing permissions and
14
* limitations under the License.
21
#include <time-utils.h>
29
/* Legacy RTC registers */
30
#define RTC_REG_SECONDS 0
31
#define RTC_REG_MINUTES 2
32
#define RTC_REG_HOURS 4
33
#define RTC_REG_DAY_OF_WEEK 6
34
#define RTC_REG_DAY_OF_MONTH 7
35
#define RTC_REG_MONTH 8
36
#define RTC_REG_YEAR 9
38
#define RTC_REG_A_UIP 0x80
40
#define RTC_REG_B_DIS_UPD 0x80
41
#define RTC_REG_B_PIE 0x40
42
#define RTC_REG_B_AIE 0x20
43
#define RTC_REG_B_UIE 0x10
44
#define RTC_REG_B_SQWE 0x08
45
#define RTC_REG_B_DM_BINARY 0x04
46
#define RTC_REG_B_24H 0x02
47
#define RTC_REG_B_DST_EN 0x01
50
#define RTC_REG_D_VALID 0x80
52
/* Init value is no interrupts, 24H mode, updates enabled */
53
#define RTC_REG_B_INIT (RTC_REG_B_24H)
56
static struct lock rtc_lock = LOCK_UNLOCKED;
58
static uint8_t rtc_read(uint8_t reg)
60
lpc_outb(reg, rtc_port);
61
return lpc_inb(rtc_port + 1);
64
static void rtc_write(uint8_t reg, uint8_t val)
66
lpc_outb(reg, rtc_port);
67
lpc_outb(val, rtc_port + 1);
70
static bool lpc_rtc_read_tm(struct tm *tm)
73
unsigned int loops = 0;
75
/* Read until two series provide identical values, this
76
* should deal with update races in all practical cases
80
tm->tm_sec = rtc_read(RTC_REG_SECONDS);
81
tm->tm_min = rtc_read(RTC_REG_MINUTES);
82
tm->tm_hour = rtc_read(RTC_REG_HOURS);
83
tm->tm_mday = rtc_read(RTC_REG_DAY_OF_MONTH);
84
tm->tm_mon = rtc_read(RTC_REG_MONTH);
85
tm->tm_year = rtc_read(RTC_REG_YEAR);
86
if (loops > 0 && memcmp(&tm2, tm, sizeof(struct tm)) == 0)
90
prerror("RTC: Failed to obtain stable values\n");
94
tm->tm_sec = bcd_byte(tm->tm_sec, 0);
95
tm->tm_min = bcd_byte(tm->tm_min, 0);
96
tm->tm_hour = bcd_byte(tm->tm_hour, 0);
97
tm->tm_mday = bcd_byte(tm->tm_mday, 0);
98
tm->tm_mon = bcd_byte(tm->tm_mon, 0) - 1;
99
tm->tm_year = bcd_byte(tm->tm_year, 0);
102
if (tm->tm_year < 69)
111
static void lpc_rtc_write_tm(struct tm *tm __unused)
116
static void lpc_init_time(void)
122
memset(&tm, 0, sizeof(tm));
126
/* If update is in progress, wait a bit */
127
val = rtc_read(RTC_REG_A);
128
if (val & RTC_REG_A_UIP)
132
valid = lpc_rtc_read_tm(&tm);
138
rtc_cache_update(&tm);
141
static void lpc_init_hw(void)
145
/* Set REG B to a suitable default */
146
rtc_write(RTC_REG_B, RTC_REG_B_INIT);
151
static int64_t lpc_opal_rtc_read(uint32_t *y_m_d,
155
int64_t rc = OPAL_SUCCESS;
158
if (!y_m_d || !h_m_s_m)
159
return OPAL_PARAMETER;
161
/* Return busy if updating. This is somewhat racy, but will
162
* do for now, most RTCs nowadays are smart enough to atomically
163
* update. Alternatively we could just read from the cache...
166
val = rtc_read(RTC_REG_A);
167
if (val & RTC_REG_A_UIP) {
169
return OPAL_BUSY_EVENT;
173
if (lpc_rtc_read_tm(&tm))
179
if (rc == OPAL_SUCCESS) {
181
rtc_cache_update(&tm);
183
/* Convert to OPAL time */
184
tm_to_datetime(&tm, y_m_d, h_m_s_m);
190
static int64_t lpc_opal_rtc_write(uint32_t year_month_day,
191
uint64_t hour_minute_second_millisecond)
195
/* Convert to struct tm */
196
datetime_to_tm(year_month_day, hour_minute_second_millisecond, &tm);
200
lpc_rtc_write_tm(&tm);
206
void lpc_rtc_init(void)
208
struct dt_node *rtc_node, *np;
213
/* We support only one */
214
rtc_node = dt_find_compatible_node(dt_root, NULL, "pnpPNP,b00");
219
rtc_port = dt_prop_get_cell_def(rtc_node, "reg", 1, 0);
221
prerror("RTC: Can't find reg property\n");
224
if (dt_prop_get_cell_def(rtc_node, "reg", 0, 0) != OPAL_LPC_IO) {
225
prerror("RTC: Unsupported address type\n");
232
/* Create OPAL API node and register OPAL calls */
233
np = dt_new(opal_node, "rtc");
234
dt_add_property_strings(np, "compatible", "ibm,opal-rtc");
236
opal_register(OPAL_RTC_READ, lpc_opal_rtc_read, 2);
237
opal_register(OPAL_RTC_WRITE, lpc_opal_rtc_write, 2);
239
/* Initialise the rtc cache */