1 /* $OpenBSD: octrtc.c,v 1.11 2017/11/20 15:20:03 visa Exp $ */ 2 3 /* 4 * Copyright (c) 2013, 2014 Paul Irofti. 5 * 6 * Permission to use, copy, modify, and distribute this software for any 7 * purpose with or without fee is hereby granted, provided that the above 8 * copyright notice and this permission notice appear in all copies. 9 * 10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 */ 18 19 #include <sys/param.h> 20 #include <sys/systm.h> 21 #include <sys/device.h> 22 #include <sys/proc.h> 23 24 #include <mips64/dev/clockvar.h> 25 26 #include <machine/bus.h> 27 #include <machine/autoconf.h> 28 #include <machine/octeonvar.h> 29 30 #ifdef OCTRTC_DEBUG 31 #define DPRINTF(x) printf x 32 #else 33 #define DPRINTF(x) 34 #endif 35 36 #define MIO_TWS_SW_TWSI 0x0001180000001000ULL 37 #define MIO_TWS_SW_TWSI_EXT 0x0001180000001018ULL 38 #define OCTRTC_REG 0x68 39 40 struct cfdriver octrtc_cd = { 41 NULL, "octrtc", DV_DULL 42 }; 43 44 int octrtc_match(struct device *, void *, void *); 45 void octrtc_attach(struct device *, struct device *, void *); 46 47 void octrtc_gettime(void *, time_t, struct tod_time *); 48 int octrtc_read(uint8_t *, char); 49 50 void octrtc_settime(void *, struct tod_time *); 51 int octrtc_write(uint8_t); 52 53 54 struct cfattach octrtc_ca = { 55 sizeof(struct device), octrtc_match, octrtc_attach, 56 }; 57 58 59 union mio_tws_sw_twsi_reg { 60 uint64_t reg; 61 struct cvmx_mio_twsx_sw_twsi_s { 62 uint64_t v:1; /* Valid bit */ 63 uint64_t slonly:1; /* Slave Only Mode */ 64 uint64_t eia:1; /* Extended Internal Address */ 65 uint64_t op:4; /* Opcode field */ 66 uint64_t r:1; /* Read bit or result */ 67 uint64_t sovr:1; /* Size Override */ 68 uint64_t size:3; /* Size in bytes */ 69 uint64_t scr:2; /* Scratch, unused */ 70 uint64_t a:10; /* Address field */ 71 uint64_t ia:5; /* Internal Address */ 72 uint64_t eop_ia:3; /* Extra opcode */ 73 uint64_t d:32; /* Data Field */ 74 } field; 75 }; 76 77 78 static const uint16_t no_rtc_boards[] = { 79 BOARD_TYPE_UBIQUITI_E100, 80 BOARD_TYPE_UBIQUITI_E120, 81 BOARD_TYPE_UBIQUITI_E200, 82 BOARD_TYPE_UBIQUITI_E220, 83 BOARD_TYPE_UBIQUITI_E300, 84 BOARD_TYPE_UBIQUITI_E1000, 85 BOARD_TYPE_RHINOLABS_SHASTA 86 }; 87 88 int 89 octrtc_match(struct device *parent, void *match, void *aux) 90 { 91 struct mainbus_attach_args *maa = aux; 92 struct cfdata *cf = match; 93 int i; 94 95 if (strcmp(maa->maa_name, cf->cf_driver->cd_name) != 0) 96 return 0; 97 for (i = 0; i < nitems(no_rtc_boards); i++) 98 if (octeon_boot_info->board_type == no_rtc_boards[i]) 99 return 0; 100 return 1; 101 } 102 103 void 104 octrtc_attach(struct device *parent, struct device *self, void *aux) 105 { 106 struct octrtc_softc *sc = (struct octrtc_softc *)self; 107 108 sys_tod.tod_cookie = sc; 109 sys_tod.tod_get = octrtc_gettime; 110 sys_tod.tod_set = octrtc_settime; 111 112 printf(": DS1337\n"); 113 } 114 115 void 116 octrtc_gettime(void *cookie, time_t unused, struct tod_time *tt) 117 { 118 uint8_t tod[8]; 119 uint8_t check; 120 int i, rc; 121 122 int nretries = 2; 123 124 DPRINTF(("\nTOD: ")); 125 while (nretries--) { 126 rc = octrtc_read(&tod[0], 1); /* ia read */ 127 if (rc) { 128 DPRINTF(("octrtc_read(0) failed %d", rc)); 129 return; 130 } 131 132 for (i = 1; i < 8; i++) { 133 rc = octrtc_read(&tod[i], 0); /* current address */ 134 if (rc) { 135 DPRINTF(("octrtc_read(%d) failed %d", i, rc)); 136 return; 137 } 138 DPRINTF(("%#X ", tod[i])); 139 } 140 141 /* Check against time-wrap */ 142 rc = octrtc_read(&check, 1); /* ia read */ 143 if (rc) { 144 DPRINTF(("octrtc_read(check) failed %d", i, rc)); 145 return; 146 } 147 if ((check & 0xf) == (tod[0] & 0xf)) 148 break; 149 } 150 DPRINTF(("\n")); 151 152 DPRINTF(("Time: %d %d %d (%d) %02d:%02d:%02d\n", 153 ((tod[5] & 0x80) ? 2000 : 1900) + FROMBCD(tod[6]), /* year */ 154 FROMBCD(tod[5] & 0x1f), /* month */ 155 FROMBCD(tod[4] & 0x3f), /* day */ 156 (tod[3] & 0x7), /* day of the week */ 157 FROMBCD(tod[2] & 0x3f), /* hour */ 158 FROMBCD(tod[1] & 0x7f), /* minute */ 159 FROMBCD(tod[0] & 0x7f))); /* second */ 160 161 tt->year = ((tod[5] & 0x80) ? 100 : 0) + FROMBCD(tod[6]); 162 tt->mon = FROMBCD(tod[5] & 0x1f); 163 tt->day = FROMBCD(tod[4] & 0x3f); 164 tt->dow = (tod[3] & 0x7); 165 tt->hour = FROMBCD(tod[2] & 0x3f); 166 if ((tod[2] & 0x40) && (tod[2] & 0x20)) /* adjust AM/PM format */ 167 tt->hour = (tt->hour + 12) % 24; 168 tt->min = FROMBCD(tod[1] & 0x7f); 169 tt->sec = FROMBCD(tod[0] & 0x7f); 170 } 171 172 int 173 octrtc_read(uint8_t *data, char ia) 174 { 175 int nretries = 5; 176 union mio_tws_sw_twsi_reg twsi; 177 178 again: 179 twsi.reg = 0; 180 twsi.field.v = 1; 181 twsi.field.r = 1; 182 twsi.field.sovr = 1; 183 twsi.field.a = OCTRTC_REG; 184 if (ia) { 185 twsi.field.op = 1; 186 } 187 188 octeon_xkphys_write_8(MIO_TWS_SW_TWSI, twsi.reg); 189 /* The 1st bit is cleared when the operation is complete */ 190 do { 191 delay(1000); 192 twsi.reg = octeon_xkphys_read_8(MIO_TWS_SW_TWSI); 193 } while (twsi.field.v); 194 DPRINTF(("%#llX ", twsi.reg)); 195 196 /* 197 * The data field is in the upper 32 bits and we're only 198 * interested in the first byte. 199 */ 200 *data = twsi.field.d & 0xff; 201 202 /* 8th bit is the read result: 1 = success, 0 = failure */ 203 if (twsi.field.r == 0) { 204 /* 205 * Lost arbitration : 0x38, 0x68, 0xB0, 0x78 206 * Core busy as slave: 0x80, 0x88, 0xA0, 0xA8, 0xB8, 0xC0, 0xC8 207 */ 208 if (*data == 0x38 || *data == 0x68 || *data == 0xB0 || 209 *data == 0x78 || *data == 0x80 || *data == 0x88 || 210 *data == 0xA0 || *data == 0xA8 || *data == 0xB8 || 211 *data == 0xC0 || *data == 0xC8) 212 if (nretries--) 213 goto again; 214 return EIO; 215 } 216 217 return 0; 218 } 219 220 void 221 octrtc_settime(void *cookie, struct tod_time *tt) 222 { 223 int nretries = 2; 224 int rc, i; 225 uint8_t tod[8]; 226 uint8_t check; 227 228 DPRINTF(("settime: %d %d %d (%d) %02d:%02d:%02d\n", 229 tt->year, tt->mon, tt->day, tt->dow, 230 tt->hour, tt->min, tt->sec)); 231 232 tod[0] = TOBCD(tt->sec); 233 tod[1] = TOBCD(tt->min); 234 tod[2] = TOBCD(tt->hour); 235 tod[3] = TOBCD(tt->dow); 236 tod[4] = TOBCD(tt->day); 237 tod[5] = TOBCD(tt->mon); 238 if (tt->year >= 100) 239 tod[5] |= 0x80; 240 tod[6] = TOBCD(tt->year % 100); 241 242 while (nretries--) { 243 for (i = 0; i < 7; i++) { 244 rc = octrtc_write(tod[i]); 245 if (rc) { 246 DPRINTF(("octrtc_write(%d) failed %d", i, rc)); 247 return; 248 } 249 } 250 251 rc = octrtc_read(&check, 1); 252 if (rc) { 253 DPRINTF(("octrtc_read(check) failed %d", rc)); 254 return; 255 } 256 257 if ((check & 0xf) == (tod[0] & 0xf)) 258 break; 259 } 260 } 261 262 int 263 octrtc_write(uint8_t data) 264 { 265 union mio_tws_sw_twsi_reg twsi; 266 int npoll = 128; 267 268 twsi.reg = 0; 269 twsi.field.v = 1; 270 twsi.field.sovr = 1; 271 twsi.field.op = 1; 272 twsi.field.a = OCTRTC_REG; 273 twsi.field.d = data & 0xffffffff; 274 275 octeon_xkphys_write_8(MIO_TWS_SW_TWSI_EXT, 0); 276 octeon_xkphys_write_8(MIO_TWS_SW_TWSI, twsi.reg); 277 do { 278 delay(1000); 279 twsi.reg = octeon_xkphys_read_8(MIO_TWS_SW_TWSI); 280 } while (twsi.field.v); 281 282 /* Try to read back */ 283 while (npoll-- && octrtc_read(&data, 0)); 284 285 return npoll ? 0 : EIO; 286 } 287