1210311Sjmallett/***********************license start*************** 2210311Sjmallett * Copyright (c) 2003-2008 Cavium Networks (support@cavium.com). All rights 3210311Sjmallett * reserved. 4210311Sjmallett * 5210311Sjmallett * 6210311Sjmallett * Redistribution and use in source and binary forms, with or without 7210311Sjmallett * modification, are permitted provided that the following conditions are 8210311Sjmallett * met: 9210311Sjmallett * 10210311Sjmallett * * Redistributions of source code must retain the above copyright 11210311Sjmallett * notice, this list of conditions and the following disclaimer. 12210311Sjmallett * 13210311Sjmallett * * Redistributions in binary form must reproduce the above 14210311Sjmallett * copyright notice, this list of conditions and the following 15210311Sjmallett * disclaimer in the documentation and/or other materials provided 16210311Sjmallett * with the distribution. 17210311Sjmallett * 18210311Sjmallett * * Neither the name of Cavium Networks nor the names of 19210311Sjmallett * its contributors may be used to endorse or promote products 20210311Sjmallett * derived from this software without specific prior written 21210311Sjmallett * permission. 22210311Sjmallett * 23210311Sjmallett * TO THE MAXIMUM EXTENT PERMITTED BY LAW, THE SOFTWARE IS PROVIDED "AS IS" 24210311Sjmallett * AND WITH ALL FAULTS AND CAVIUM NETWORKS MAKES NO PROMISES, REPRESENTATIONS 25210311Sjmallett * OR WARRANTIES, EITHER EXPRESS, IMPLIED, STATUTORY, OR OTHERWISE, WITH 26210311Sjmallett * RESPECT TO THE SOFTWARE, INCLUDING ITS CONDITION, ITS CONFORMITY TO ANY 27210311Sjmallett * REPRESENTATION OR DESCRIPTION, OR THE EXISTENCE OF ANY LATENT OR PATENT 28210311Sjmallett * DEFECTS, AND CAVIUM SPECIFICALLY DISCLAIMS ALL IMPLIED (IF ANY) WARRANTIES 29210311Sjmallett * OF TITLE, MERCHANTABILITY, NONINFRINGEMENT, FITNESS FOR A PARTICULAR 30210311Sjmallett * PURPOSE, LACK OF VIRUSES, ACCURACY OR COMPLETENESS, QUIET ENJOYMENT, QUIET 31210311Sjmallett * POSSESSION OR CORRESPONDENCE TO DESCRIPTION. THE ENTIRE RISK ARISING OUT 32210311Sjmallett * OF USE OR PERFORMANCE OF THE SOFTWARE LIES WITH YOU. 33210311Sjmallett * 34210311Sjmallett * 35210311Sjmallett * For any questions regarding licensing please contact marketing@caviumnetworks.com 36210311Sjmallett * 37210311Sjmallett ***********************license end**************************************/ 38210311Sjmallett 39210311Sjmallett 40210311Sjmallett 41210311Sjmallett 42210311Sjmallett 43210311Sjmallett 44210311Sjmallett/** 45210311Sjmallett * @file 46210311Sjmallett * 47210311Sjmallett * Interface to the EBH-30xx specific devices 48210311Sjmallett * 49210311Sjmallett * <hr>$Revision: 41586 $<hr> 50210311Sjmallett * 51210311Sjmallett */ 52210311Sjmallett 53210311Sjmallett#include <sys/cdefs.h> 54210311Sjmallett__FBSDID("$FreeBSD$"); 55210311Sjmallett 56210311Sjmallett#include <sys/param.h> 57210311Sjmallett#include <sys/timespec.h> 58210311Sjmallett#include <sys/clock.h> 59210311Sjmallett#include <sys/libkern.h> 60210311Sjmallett 61210311Sjmallett#include <contrib/octeon-sdk/cvmx.h> 62210311Sjmallett#include <contrib/octeon-sdk/cvmx-cn3010-evb-hs5.h> 63210311Sjmallett#include <contrib/octeon-sdk/cvmx-twsi.h> 64210311Sjmallett 65210311Sjmallett#define CT_CHECK(_expr, _msg) \ 66210311Sjmallett do { \ 67210311Sjmallett if (_expr) { \ 68210311Sjmallett cvmx_dprintf("Warning: RTC has invalid %s field\n", (_msg)); \ 69210311Sjmallett rc = -1; \ 70210311Sjmallett } \ 71210311Sjmallett } while(0); 72210311Sjmallett 73210311Sjmallettstatic int validate_ct_struct(struct clocktime *ct) 74210311Sjmallett{ 75210311Sjmallett int rc = 0; 76210311Sjmallett 77210311Sjmallett if (!ct) 78210311Sjmallett return -1; 79210311Sjmallett 80210311Sjmallett CT_CHECK(ct->sec < 0 || ct->sec > 60, "second"); /* + Leap sec */ 81210311Sjmallett CT_CHECK(ct->min < 0 || ct->min > 59, "minute"); 82210311Sjmallett CT_CHECK(ct->hour < 0 || ct->hour > 23, "hour"); 83210311Sjmallett CT_CHECK(ct->day < 1 || ct->day > 31, "day"); 84271562Skan CT_CHECK(ct->dow < 0 || ct->dow > 6, "day of week"); 85229161Sgonzo CT_CHECK(ct->mon < 1 || ct->mon > 12, "month"); 86229161Sgonzo CT_CHECK(ct->year > 2037,"year"); 87210311Sjmallett 88210311Sjmallett return rc; 89210311Sjmallett} 90210311Sjmallett 91210311Sjmallett/* 92210311Sjmallett * Board-specifc RTC read 93210311Sjmallett * Time is expressed in seconds from epoch (Jan 1 1970 at 00:00:00 UTC) 94210311Sjmallett * and converted internally to calendar format. 95210311Sjmallett */ 96210311Sjmallettuint32_t cvmx_rtc_ds1337_read(void) 97210311Sjmallett{ 98210311Sjmallett int i, retry; 99210311Sjmallett uint8_t reg[8]; 100210311Sjmallett uint8_t sec; 101210311Sjmallett struct clocktime ct; 102210311Sjmallett struct timespec ts; 103210311Sjmallett 104210311Sjmallett 105210311Sjmallett memset(®, 0, sizeof(reg)); 106210311Sjmallett memset(&ct, 0, sizeof(ct)); 107210311Sjmallett 108210311Sjmallett for(retry=0; retry<2; retry++) 109210311Sjmallett { 110210311Sjmallett /* Lockless read: detects the infrequent roll-over and retries */ 111210311Sjmallett reg[0] = cvmx_twsi_read8(CVMX_RTC_DS1337_ADDR, 0x0); 112210311Sjmallett for(i=1; i<7; i++) 113210311Sjmallett reg[i] = cvmx_twsi_read8_cur_addr(CVMX_RTC_DS1337_ADDR); 114210311Sjmallett 115210311Sjmallett sec = cvmx_twsi_read8(CVMX_RTC_DS1337_ADDR, 0x0); 116210311Sjmallett if ((sec & 0xf) == (reg[0] & 0xf)) 117210311Sjmallett break; /* Time did not roll-over, value is correct */ 118210311Sjmallett } 119210311Sjmallett 120210311Sjmallett ct.sec = bcd2bin(reg[0] & 0x7f); 121210311Sjmallett ct.min = bcd2bin(reg[1] & 0x7f); 122210311Sjmallett ct.hour = bcd2bin(reg[2] & 0x3f); 123210311Sjmallett if ((reg[2] & 0x40) && (reg[2] & 0x20)) /* AM/PM format and is PM time */ 124210311Sjmallett { 125210311Sjmallett ct.hour = (ct.hour + 12) % 24; 126210311Sjmallett } 127271562Skan ct.dow = (reg[3] & 0x7) - 1; /* Day of week field is 0..6 */ 128210311Sjmallett ct.day = bcd2bin(reg[4] & 0x3f); 129229161Sgonzo ct.mon = bcd2bin(reg[5] & 0x1f); /* Month field is 1..12 */ 130229161Sgonzo#if defined(OCTEON_BOARD_CAPK_0100ND) 131229161Sgonzo /* 132229161Sgonzo * CAPK-0100ND uses DS1307 that does not have century bit 133229161Sgonzo */ 134229161Sgonzo ct.year = 2000 + bcd2bin(reg[6]); 135229161Sgonzo#else 136229161Sgonzo ct.year = ((reg[5] & 0x80) ? 2000 : 1900) + bcd2bin(reg[6]); 137229161Sgonzo#endif 138210311Sjmallett 139210311Sjmallett if (validate_ct_struct(&ct)) 140210311Sjmallett cvmx_dprintf("Warning: RTC calendar is not configured properly\n"); 141210311Sjmallett 142210311Sjmallett if (clock_ct_to_ts(&ct, &ts) != 0) { 143210311Sjmallett cvmx_dprintf("Warning: RTC calendar is not configured properly\n"); 144210311Sjmallett return 0; 145210311Sjmallett } 146210311Sjmallett 147210311Sjmallett return ts.tv_sec; 148210311Sjmallett} 149210311Sjmallett 150210311Sjmallett/* 151210311Sjmallett * Board-specific RTC write 152210311Sjmallett * Time returned is in seconds from epoch (Jan 1 1970 at 00:00:00 UTC) 153210311Sjmallett */ 154210311Sjmallettint cvmx_rtc_ds1337_write(uint32_t time) 155210311Sjmallett{ 156210311Sjmallett struct clocktime ct; 157210311Sjmallett struct timespec ts; 158210311Sjmallett int i, rc, retry; 159210311Sjmallett uint8_t reg[8]; 160210311Sjmallett uint8_t sec; 161210311Sjmallett 162210311Sjmallett ts.tv_sec = time; 163210311Sjmallett ts.tv_nsec = 0; 164210311Sjmallett 165210311Sjmallett clock_ts_to_ct(&ts, &ct); 166210311Sjmallett 167210311Sjmallett if (validate_ct_struct(&ct)) 168210311Sjmallett { 169210311Sjmallett cvmx_dprintf("Error: RTC was passed wrong calendar values, write failed\n"); 170210311Sjmallett goto ct_invalid; 171210311Sjmallett } 172210311Sjmallett 173210311Sjmallett reg[0] = bin2bcd(ct.sec); 174210311Sjmallett reg[1] = bin2bcd(ct.min); 175229161Sgonzo reg[2] = bin2bcd(ct.hour); /* Force 0..23 format even if using AM/PM */ 176271562Skan reg[3] = bin2bcd(ct.dow + 1); 177210311Sjmallett reg[4] = bin2bcd(ct.day); 178229161Sgonzo reg[5] = bin2bcd(ct.mon); 179271562Skan#if !defined(OCTEON_BOARD_CAPK_0100ND) 180229161Sgonzo if (ct.year >= 2000) /* Set century bit*/ 181210311Sjmallett { 182210311Sjmallett reg[5] |= 0x80; 183210311Sjmallett } 184271562Skan#endif 185210311Sjmallett reg[6] = bin2bcd(ct.year % 100); 186210311Sjmallett 187210311Sjmallett /* Lockless write: detects the infrequent roll-over and retries */ 188210311Sjmallett for(retry=0; retry<2; retry++) 189210311Sjmallett { 190210311Sjmallett rc = 0; 191210311Sjmallett for(i=0; i<7; i++) 192210311Sjmallett { 193210311Sjmallett rc |= cvmx_twsi_write8(CVMX_RTC_DS1337_ADDR, i, reg[i]); 194210311Sjmallett } 195210311Sjmallett 196210311Sjmallett sec = cvmx_twsi_read8(CVMX_RTC_DS1337_ADDR, 0x0); 197210311Sjmallett if ((sec & 0xf) == (reg[0] & 0xf)) 198210311Sjmallett break; /* Time did not roll-over, value is correct */ 199210311Sjmallett } 200210311Sjmallett 201210311Sjmallett return (rc ? -1 : 0); 202210311Sjmallett 203210311Sjmallett ct_invalid: 204210311Sjmallett return -1; 205210311Sjmallett} 206210311Sjmallett 207210311Sjmallett#ifdef CVMX_RTC_DEBUG 208210311Sjmallett 209210311Sjmallettvoid cvmx_rtc_ds1337_dump_state(void) 210210311Sjmallett{ 211210311Sjmallett int i = 0; 212210311Sjmallett 213210311Sjmallett printf("RTC:\n"); 214210311Sjmallett printf("%d : %02X ", i, cvmx_twsi_read8(CVMX_RTC_DS1337_ADDR, 0x0)); 215210311Sjmallett for(i=1; i<16; i++) { 216210311Sjmallett printf("%02X ", cvmx_twsi_read8_cur_addr(CVMX_RTC_DS1337_ADDR)); 217210311Sjmallett } 218210311Sjmallett printf("\n"); 219210311Sjmallett} 220210311Sjmallett 221210311Sjmallett#endif /* CVMX_RTC_DEBUG */ 222