1210284Sjmallett/***********************license start***************
2232812Sjmallett * Copyright (c) 2003-2010  Cavium Inc. (support@cavium.com). All rights
3215990Sjmallett * reserved.
4210284Sjmallett *
5210284Sjmallett *
6215990Sjmallett * Redistribution and use in source and binary forms, with or without
7215990Sjmallett * modification, are permitted provided that the following conditions are
8215990Sjmallett * met:
9210284Sjmallett *
10215990Sjmallett *   * Redistributions of source code must retain the above copyright
11215990Sjmallett *     notice, this list of conditions and the following disclaimer.
12210284Sjmallett *
13215990Sjmallett *   * Redistributions in binary form must reproduce the above
14215990Sjmallett *     copyright notice, this list of conditions and the following
15215990Sjmallett *     disclaimer in the documentation and/or other materials provided
16215990Sjmallett *     with the distribution.
17215990Sjmallett
18232812Sjmallett *   * Neither the name of Cavium Inc. nor the names of
19215990Sjmallett *     its contributors may be used to endorse or promote products
20215990Sjmallett *     derived from this software without specific prior written
21215990Sjmallett *     permission.
22215990Sjmallett
23215990Sjmallett * This Software, including technical data, may be subject to U.S. export  control
24215990Sjmallett * laws, including the U.S. Export Administration Act and its  associated
25215990Sjmallett * regulations, and may be subject to export or import  regulations in other
26215990Sjmallett * countries.
27215990Sjmallett
28215990Sjmallett * TO THE MAXIMUM EXTENT PERMITTED BY LAW, THE SOFTWARE IS PROVIDED "AS IS"
29232812Sjmallett * AND WITH ALL FAULTS AND CAVIUM INC. MAKES NO PROMISES, REPRESENTATIONS OR
30215990Sjmallett * WARRANTIES, EITHER EXPRESS, IMPLIED, STATUTORY, OR OTHERWISE, WITH RESPECT TO
31215990Sjmallett * THE SOFTWARE, INCLUDING ITS CONDITION, ITS CONFORMITY TO ANY REPRESENTATION OR
32215990Sjmallett * DESCRIPTION, OR THE EXISTENCE OF ANY LATENT OR PATENT DEFECTS, AND CAVIUM
33215990Sjmallett * SPECIFICALLY DISCLAIMS ALL IMPLIED (IF ANY) WARRANTIES OF TITLE,
34215990Sjmallett * MERCHANTABILITY, NONINFRINGEMENT, FITNESS FOR A PARTICULAR PURPOSE, LACK OF
35215990Sjmallett * VIRUSES, ACCURACY OR COMPLETENESS, QUIET ENJOYMENT, QUIET POSSESSION OR
36215990Sjmallett * CORRESPONDENCE TO DESCRIPTION. THE ENTIRE  RISK ARISING OUT OF USE OR
37215990Sjmallett * PERFORMANCE OF THE SOFTWARE LIES WITH YOU.
38210284Sjmallett ***********************license end**************************************/
39210284Sjmallett
40210284Sjmallett
41210284Sjmallett
42210284Sjmallett
43210284Sjmallett
44210284Sjmallett
45215990Sjmallett
46210284Sjmallett/**
47210284Sjmallett * @file
48210284Sjmallett *
49210284Sjmallett * Interface to the EBH-30xx specific devices
50210284Sjmallett *
51232812Sjmallett * <hr>$Revision: 70030 $<hr>
52210284Sjmallett *
53210284Sjmallett */
54210284Sjmallett
55210284Sjmallett#include <time.h>
56210284Sjmallett#include "cvmx-config.h"
57210284Sjmallett#include "cvmx.h"
58210284Sjmallett#include "cvmx-sysinfo.h"
59210284Sjmallett#include "cvmx-cn3010-evb-hs5.h"
60210284Sjmallett#include "cvmx-twsi.h"
61210284Sjmallett
62210284Sjmallett
63210284Sjmallettstatic inline uint8_t bin2bcd(uint8_t bin)
64210284Sjmallett{
65210284Sjmallett    return (bin / 10) << 4 | (bin % 10);
66210284Sjmallett}
67210284Sjmallett
68210284Sjmallettstatic inline uint8_t bcd2bin(uint8_t bcd)
69210284Sjmallett{
70210284Sjmallett    return (bcd >> 4) * 10 + (bcd & 0xf);
71210284Sjmallett}
72210284Sjmallett
73210284Sjmallett#define TM_CHECK(_expr, _msg) \
74210284Sjmallett        do { \
75210284Sjmallett            if (_expr) { \
76210284Sjmallett                cvmx_dprintf("Warning: RTC has invalid %s field\n", (_msg)); \
77210284Sjmallett                rc = -1; \
78210284Sjmallett            } \
79210284Sjmallett        } while(0);
80210284Sjmallett
81210284Sjmallettstatic int validate_tm_struct(struct tm * tms)
82210284Sjmallett{
83210284Sjmallett    int rc = 0;
84210284Sjmallett
85210284Sjmallett    if (!tms)
86210284Sjmallett	return -1;
87210284Sjmallett
88210284Sjmallett    TM_CHECK(tms->tm_sec < 0  || tms->tm_sec > 60,  "second"); /* + Leap sec */
89210284Sjmallett    TM_CHECK(tms->tm_min < 0  || tms->tm_min > 59,  "minute");
90210284Sjmallett    TM_CHECK(tms->tm_hour < 0 || tms->tm_hour > 23, "hour");
91210284Sjmallett    TM_CHECK(tms->tm_mday < 1 || tms->tm_mday > 31, "day");
92210284Sjmallett    TM_CHECK(tms->tm_wday < 0 || tms->tm_wday > 6,  "day of week");
93210284Sjmallett    TM_CHECK(tms->tm_mon < 0  || tms->tm_mon > 11,  "month");
94210284Sjmallett    TM_CHECK(tms->tm_year < 0 || tms->tm_year > 200,"year");
95210284Sjmallett
96210284Sjmallett    return rc;
97210284Sjmallett}
98210284Sjmallett
99210284Sjmallett/*
100210284Sjmallett * Board-specifc RTC read
101210284Sjmallett * Time is expressed in seconds from epoch (Jan 1 1970 at 00:00:00 UTC)
102210284Sjmallett * and converted internally to calendar format.
103210284Sjmallett */
104210284Sjmallettuint32_t cvmx_rtc_ds1337_read(void)
105210284Sjmallett{
106210284Sjmallett    int       i, retry;
107210284Sjmallett    uint32_t  time;
108210284Sjmallett    uint8_t   reg[8];
109210284Sjmallett    uint8_t   sec;
110210284Sjmallett    struct tm tms;
111210284Sjmallett
112210284Sjmallett
113210284Sjmallett    memset(&reg, 0, sizeof(reg));
114210284Sjmallett    memset(&tms, 0, sizeof(struct tm));
115210284Sjmallett
116210284Sjmallett    for(retry=0; retry<2; retry++)
117210284Sjmallett    {
118210284Sjmallett	/* Lockless read: detects the infrequent roll-over and retries */
119210284Sjmallett	reg[0] = cvmx_twsi_read8(CVMX_RTC_DS1337_ADDR, 0x0);
120210284Sjmallett	for(i=1; i<7; i++)
121210284Sjmallett	    reg[i] = cvmx_twsi_read8_cur_addr(CVMX_RTC_DS1337_ADDR);
122210284Sjmallett
123210284Sjmallett	sec = cvmx_twsi_read8(CVMX_RTC_DS1337_ADDR, 0x0);
124210284Sjmallett	if ((sec & 0xf) == (reg[0] & 0xf))
125210284Sjmallett	    break; /* Time did not roll-over, value is correct */
126210284Sjmallett    }
127210284Sjmallett
128210284Sjmallett    tms.tm_sec  = bcd2bin(reg[0] & 0x7f);
129210284Sjmallett    tms.tm_min  = bcd2bin(reg[1] & 0x7f);
130210284Sjmallett    tms.tm_hour = bcd2bin(reg[2] & 0x3f);
131210284Sjmallett    if ((reg[2] & 0x40) && (reg[2] & 0x20))   /* AM/PM format and is PM time */
132210284Sjmallett    {
133210284Sjmallett	tms.tm_hour = (tms.tm_hour + 12) % 24;
134210284Sjmallett    }
135210284Sjmallett    tms.tm_wday = (reg[3] & 0x7) - 1;         /* Day of week field is 0..6 */
136210284Sjmallett    tms.tm_mday = bcd2bin(reg[4] & 0x3f);
137210284Sjmallett    tms.tm_mon  = bcd2bin(reg[5] & 0x1f) - 1; /* Month field is 0..11 */
138210284Sjmallett    tms.tm_year = ((reg[5] & 0x80) ? 100 : 0) + bcd2bin(reg[6]);
139210284Sjmallett
140210284Sjmallett
141210284Sjmallett    if (validate_tm_struct(&tms))
142210284Sjmallett	cvmx_dprintf("Warning: RTC calendar is not configured properly\n");
143210284Sjmallett
144210284Sjmallett    time = mktime(&tms);
145210284Sjmallett
146210284Sjmallett    return time;
147210284Sjmallett}
148210284Sjmallett
149210284Sjmallett/*
150210284Sjmallett * Board-specific RTC write
151210284Sjmallett * Time returned is in seconds from epoch (Jan 1 1970 at 00:00:00 UTC)
152210284Sjmallett */
153210284Sjmallettint cvmx_rtc_ds1337_write(uint32_t time)
154210284Sjmallett{
155210284Sjmallett    int       i, rc, retry;
156210284Sjmallett    struct tm tms;
157210284Sjmallett    uint8_t   reg[8];
158210284Sjmallett    uint8_t   sec;
159210284Sjmallett    time_t    time_from_epoch = time;
160210284Sjmallett
161210284Sjmallett
162210284Sjmallett    localtime_r(&time_from_epoch, &tms);
163210284Sjmallett
164210284Sjmallett    if (validate_tm_struct(&tms))
165210284Sjmallett    {
166210284Sjmallett	cvmx_dprintf("Error: RTC was passed wrong calendar values, write failed\n");
167210284Sjmallett	goto tm_invalid;
168210284Sjmallett    }
169210284Sjmallett
170210284Sjmallett    reg[0] = bin2bcd(tms.tm_sec);
171210284Sjmallett    reg[1] = bin2bcd(tms.tm_min);
172210284Sjmallett    reg[2] = bin2bcd(tms.tm_hour);      /* Force 0..23 format even if using AM/PM */
173210284Sjmallett    reg[3] = bin2bcd(tms.tm_wday + 1);
174210284Sjmallett    reg[4] = bin2bcd(tms.tm_mday);
175210284Sjmallett    reg[5] = bin2bcd(tms.tm_mon + 1);
176210284Sjmallett    if (tms.tm_year >= 100)             /* Set century bit*/
177210284Sjmallett    {
178210284Sjmallett	reg[5] |= 0x80;
179210284Sjmallett    }
180210284Sjmallett    reg[6] = bin2bcd(tms.tm_year % 100);
181210284Sjmallett
182210284Sjmallett    /* Lockless write: detects the infrequent roll-over and retries */
183210284Sjmallett    for(retry=0; retry<2; retry++)
184210284Sjmallett    {
185210284Sjmallett	rc = 0;
186210284Sjmallett	for(i=0; i<7; i++)
187210284Sjmallett	{
188210284Sjmallett	    rc |= cvmx_twsi_write8(CVMX_RTC_DS1337_ADDR, i, reg[i]);
189210284Sjmallett	}
190210284Sjmallett
191210284Sjmallett	sec = cvmx_twsi_read8(CVMX_RTC_DS1337_ADDR, 0x0);
192210284Sjmallett	if ((sec & 0xf) == (reg[0] & 0xf))
193210284Sjmallett	    break; /* Time did not roll-over, value is correct */
194210284Sjmallett    }
195210284Sjmallett
196210284Sjmallett    return (rc ? -1 : 0);
197210284Sjmallett
198210284Sjmallett tm_invalid:
199210284Sjmallett    return -1;
200210284Sjmallett}
201210284Sjmallett
202210284Sjmallett#ifdef CVMX_RTC_DEBUG
203210284Sjmallett
204210284Sjmallettvoid cvmx_rtc_ds1337_dump_state(void)
205210284Sjmallett{
206210284Sjmallett    int i = 0;
207210284Sjmallett
208210284Sjmallett    printf("RTC:\n");
209210284Sjmallett    printf("%d : %02X ", i, cvmx_twsi_read8(CVMX_RTC_DS1337_ADDR, 0x0));
210210284Sjmallett    for(i=1; i<16; i++) {
211210284Sjmallett	printf("%02X ", cvmx_twsi_read8_cur_addr(CVMX_RTC_DS1337_ADDR));
212210284Sjmallett    }
213210284Sjmallett    printf("\n");
214210284Sjmallett}
215210284Sjmallett
216210284Sjmallett#endif /* CVMX_RTC_DEBUG */
217