]> CyberLeo.Net >> Repos - FreeBSD/releng/8.2.git/blob - sys/contrib/octeon-sdk/cvmx-cn3010-evb-hs5.c
Copy stable/8 to releng/8.2 in preparation for FreeBSD-8.2 release.
[FreeBSD/releng/8.2.git] / sys / contrib / octeon-sdk / cvmx-cn3010-evb-hs5.c
1 /***********************license start***************
2  *  Copyright (c) 2003-2008 Cavium Networks (support@cavium.com). All rights
3  *  reserved.
4  *
5  *
6  *  Redistribution and use in source and binary forms, with or without
7  *  modification, are permitted provided that the following conditions are
8  *  met:
9  *
10  *      * Redistributions of source code must retain the above copyright
11  *        notice, this list of conditions and the following disclaimer.
12  *
13  *      * Redistributions in binary form must reproduce the above
14  *        copyright notice, this list of conditions and the following
15  *        disclaimer in the documentation and/or other materials provided
16  *        with the distribution.
17  *
18  *      * Neither the name of Cavium Networks nor the names of
19  *        its contributors may be used to endorse or promote products
20  *        derived from this software without specific prior written
21  *        permission.
22  *
23  *  TO THE MAXIMUM EXTENT PERMITTED BY LAW, THE SOFTWARE IS PROVIDED "AS IS"
24  *  AND WITH ALL FAULTS AND CAVIUM NETWORKS MAKES NO PROMISES, REPRESENTATIONS
25  *  OR WARRANTIES, EITHER EXPRESS, IMPLIED, STATUTORY, OR OTHERWISE, WITH
26  *  RESPECT TO THE SOFTWARE, INCLUDING ITS CONDITION, ITS CONFORMITY TO ANY
27  *  REPRESENTATION OR DESCRIPTION, OR THE EXISTENCE OF ANY LATENT OR PATENT
28  *  DEFECTS, AND CAVIUM SPECIFICALLY DISCLAIMS ALL IMPLIED (IF ANY) WARRANTIES
29  *  OF TITLE, MERCHANTABILITY, NONINFRINGEMENT, FITNESS FOR A PARTICULAR
30  *  PURPOSE, LACK OF VIRUSES, ACCURACY OR COMPLETENESS, QUIET ENJOYMENT, QUIET
31  *  POSSESSION OR CORRESPONDENCE TO DESCRIPTION.  THE ENTIRE RISK ARISING OUT
32  *  OF USE OR PERFORMANCE OF THE SOFTWARE LIES WITH YOU.
33  *
34  *
35  *  For any questions regarding licensing please contact marketing@caviumnetworks.com
36  *
37  ***********************license end**************************************/
38
39
40
41
42
43
44 /**
45  * @file
46  *
47  * Interface to the EBH-30xx specific devices
48  *
49  * <hr>$Revision: 41586 $<hr>
50  *
51  */
52
53 #include <time.h>
54 #include "cvmx-config.h"
55 #include "cvmx.h"
56 #include "cvmx-sysinfo.h"
57 #include "cvmx-cn3010-evb-hs5.h"
58 #include "cvmx-twsi.h"
59
60
61 static inline uint8_t bin2bcd(uint8_t bin)
62 {
63     return (bin / 10) << 4 | (bin % 10);
64 }
65
66 static inline uint8_t bcd2bin(uint8_t bcd)
67 {
68     return (bcd >> 4) * 10 + (bcd & 0xf);
69 }
70
71 #define TM_CHECK(_expr, _msg) \
72         do { \
73             if (_expr) { \
74                 cvmx_dprintf("Warning: RTC has invalid %s field\n", (_msg)); \
75                 rc = -1; \
76             } \
77         } while(0);
78
79 static int validate_tm_struct(struct tm * tms)
80 {
81     int rc = 0;
82
83     if (!tms)
84         return -1;
85
86     TM_CHECK(tms->tm_sec < 0  || tms->tm_sec > 60,  "second"); /* + Leap sec */
87     TM_CHECK(tms->tm_min < 0  || tms->tm_min > 59,  "minute");
88     TM_CHECK(tms->tm_hour < 0 || tms->tm_hour > 23, "hour");
89     TM_CHECK(tms->tm_mday < 1 || tms->tm_mday > 31, "day");
90     TM_CHECK(tms->tm_wday < 0 || tms->tm_wday > 6,  "day of week");
91     TM_CHECK(tms->tm_mon < 0  || tms->tm_mon > 11,  "month");
92     TM_CHECK(tms->tm_year < 0 || tms->tm_year > 200,"year");
93
94     return rc;
95 }
96
97 /*
98  * Board-specifc RTC read
99  * Time is expressed in seconds from epoch (Jan 1 1970 at 00:00:00 UTC)
100  * and converted internally to calendar format.
101  */
102 uint32_t cvmx_rtc_ds1337_read(void)
103 {
104     int       i, retry;
105     uint32_t  time;
106     uint8_t   reg[8];
107     uint8_t   sec;
108     struct tm tms;
109
110
111     memset(&reg, 0, sizeof(reg));
112     memset(&tms, 0, sizeof(struct tm));
113
114     for(retry=0; retry<2; retry++)
115     {
116         /* Lockless read: detects the infrequent roll-over and retries */
117         reg[0] = cvmx_twsi_read8(CVMX_RTC_DS1337_ADDR, 0x0);
118         for(i=1; i<7; i++)
119             reg[i] = cvmx_twsi_read8_cur_addr(CVMX_RTC_DS1337_ADDR);
120
121         sec = cvmx_twsi_read8(CVMX_RTC_DS1337_ADDR, 0x0);
122         if ((sec & 0xf) == (reg[0] & 0xf))
123             break; /* Time did not roll-over, value is correct */
124     }
125
126     tms.tm_sec  = bcd2bin(reg[0] & 0x7f);
127     tms.tm_min  = bcd2bin(reg[1] & 0x7f);
128     tms.tm_hour = bcd2bin(reg[2] & 0x3f);
129     if ((reg[2] & 0x40) && (reg[2] & 0x20))   /* AM/PM format and is PM time */
130     {
131         tms.tm_hour = (tms.tm_hour + 12) % 24;
132     }
133     tms.tm_wday = (reg[3] & 0x7) - 1;         /* Day of week field is 0..6 */
134     tms.tm_mday = bcd2bin(reg[4] & 0x3f);
135     tms.tm_mon  = bcd2bin(reg[5] & 0x1f) - 1; /* Month field is 0..11 */
136     tms.tm_year = ((reg[5] & 0x80) ? 100 : 0) + bcd2bin(reg[6]);
137
138
139     if (validate_tm_struct(&tms))
140         cvmx_dprintf("Warning: RTC calendar is not configured properly\n");
141
142     time = mktime(&tms);
143
144     return time;
145 }
146
147 /*
148  * Board-specific RTC write
149  * Time returned is in seconds from epoch (Jan 1 1970 at 00:00:00 UTC)
150  */
151 int cvmx_rtc_ds1337_write(uint32_t time)
152 {
153     int       i, rc, retry;
154     struct tm tms;
155     uint8_t   reg[8];
156     uint8_t   sec;
157     time_t    time_from_epoch = time;
158
159
160     localtime_r(&time_from_epoch, &tms);
161
162     if (validate_tm_struct(&tms))
163     {
164         cvmx_dprintf("Error: RTC was passed wrong calendar values, write failed\n");
165         goto tm_invalid;
166     }
167
168     reg[0] = bin2bcd(tms.tm_sec);
169     reg[1] = bin2bcd(tms.tm_min);
170     reg[2] = bin2bcd(tms.tm_hour);      /* Force 0..23 format even if using AM/PM */
171     reg[3] = bin2bcd(tms.tm_wday + 1);
172     reg[4] = bin2bcd(tms.tm_mday);
173     reg[5] = bin2bcd(tms.tm_mon + 1);
174     if (tms.tm_year >= 100)             /* Set century bit*/
175     {
176         reg[5] |= 0x80;
177     }
178     reg[6] = bin2bcd(tms.tm_year % 100);
179
180     /* Lockless write: detects the infrequent roll-over and retries */
181     for(retry=0; retry<2; retry++)
182     {
183         rc = 0;
184         for(i=0; i<7; i++)
185         {
186             rc |= cvmx_twsi_write8(CVMX_RTC_DS1337_ADDR, i, reg[i]);
187         }
188
189         sec = cvmx_twsi_read8(CVMX_RTC_DS1337_ADDR, 0x0);
190         if ((sec & 0xf) == (reg[0] & 0xf))
191             break; /* Time did not roll-over, value is correct */
192     }
193
194     return (rc ? -1 : 0);
195
196  tm_invalid:
197     return -1;
198 }
199
200 #ifdef CVMX_RTC_DEBUG
201
202 void cvmx_rtc_ds1337_dump_state(void)
203 {
204     int i = 0;
205
206     printf("RTC:\n");
207     printf("%d : %02X ", i, cvmx_twsi_read8(CVMX_RTC_DS1337_ADDR, 0x0));
208     for(i=1; i<16; i++) {
209         printf("%02X ", cvmx_twsi_read8_cur_addr(CVMX_RTC_DS1337_ADDR));
210     }
211     printf("\n");
212 }
213
214 #endif /* CVMX_RTC_DEBUG */