|
|
1.1.1.3 ! root 1: /* $Id: isil7170.c,v 1.6 2010/06/05 14:37:27 fredette Exp $ */ 1.1 root 2: 3: /* ic/isil7170.c - implementation of Intersil 7170 emulation: */ 4: 5: /* 6: * Copyright (c) 2004 Matt Fredette 7: * All rights reserved. 8: * 9: * Redistribution and use in source and binary forms, with or without 10: * modification, are permitted provided that the following conditions 11: * are met: 12: * 1. Redistributions of source code must retain the above copyright 13: * notice, this list of conditions and the following disclaimer. 14: * 2. Redistributions in binary form must reproduce the above copyright 15: * notice, this list of conditions and the following disclaimer in the 16: * documentation and/or other materials provided with the distribution. 17: * 3. All advertising materials mentioning features or use of this software 18: * must display the following acknowledgement: 19: * This product includes software developed by Matt Fredette. 20: * 4. The name of the author may not be used to endorse or promote products 21: * derived from this software without specific prior written permission. 22: * 23: * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 24: * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 25: * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 26: * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, 27: * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 28: * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 29: * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 30: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 31: * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 32: * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 33: * POSSIBILITY OF SUCH DAMAGE. 34: */ 35: 36: #include <tme/common.h> 1.1.1.3 ! root 37: _TME_RCSID("$Id: isil7170.c,v 1.6 2010/06/05 14:37:27 fredette Exp $"); 1.1 root 38: 39: /* includes: */ 40: #include <tme/generic/bus-device.h> 41: #include <tme/ic/isil7170.h> 42: #include <tme/misc.h> 43: #include <time.h> 44: #include <sys/time.h> 45: 46: /* macros: */ 47: 48: /* register addresses: */ 49: #define TME_ISIL7170_REG_CSEC (0) 50: #define TME_ISIL7170_REG_HOUR (1) 51: #define TME_ISIL7170_REG_MIN (2) 52: #define TME_ISIL7170_REG_SEC (3) 53: #define TME_ISIL7170_REG_MON (4) 54: #define TME_ISIL7170_REG_DAY (5) 55: #define TME_ISIL7170_REG_YEAR (6) 56: #define TME_ISIL7170_REG_DOW (7) 57: #define TME_ISIL7170_REG_CMP_CSEC (8) 58: #define TME_ISIL7170_REG_CMP_HOUR (9) 59: #define TME_ISIL7170_REG_CMP_MIN (10) 60: #define TME_ISIL7170_REG_CMP_SEC (11) 61: #define TME_ISIL7170_REG_CMP_MON (12) 62: #define TME_ISIL7170_REG_CMP_DAY (13) 63: #define TME_ISIL7170_REG_CMP_YEAR (14) 64: #define TME_ISIL7170_REG_CMP_DOW (15) 65: #define TME_ISIL7170_REG_INT (16) 66: #define TME_ISIL7170_REG_CMD (17) 67: #define TME_ISIL7170_REGS_COUNT (32) 68: 69: /* bits in the Interrupt register: */ 70: #define TME_ISIL7170_INT_PENDING TME_BIT(7) /* interrupt pending */ 71: #define TME_ISIL7170_INT_DAY TME_BIT(6) /* day periodic interrupt */ 72: #define TME_ISIL7170_INT_HOUR TME_BIT(5) /* hour periodic interrupt */ 73: #define TME_ISIL7170_INT_MIN TME_BIT(4) /* minute periodic interrupt */ 74: #define TME_ISIL7170_INT_SEC TME_BIT(3) /* second periodic interrupt */ 75: #define TME_ISIL7170_INT_TSEC TME_BIT(2) /* 1/10 second periodic interrupt */ 76: #define TME_ISIL7170_INT_HSEC TME_BIT(1) /* 1/100 periodic second interrupt */ 77: #define TME_ISIL7170_INT_ALARM TME_BIT(0) /* time match interrupt */ 78: 79: /* bits in the Command register: */ 80: #define TME_ISIL7170_CMD_TEST TME_BIT(5) /* test mode */ 81: #define TME_ISIL7170_CMD_INTENA TME_BIT(4) /* interrupt enable */ 82: #define TME_ISIL7170_CMD_RUN TME_BIT(3) /* running */ 83: #define TME_ISIL7170_CMD_FMT24 TME_BIT(2) /* 24-hour format (instead of 12-hour) */ 84: #define TME_ISIL7170_CMD_FREQ_MASK (0x3) /* frequency mask */ 85: #define TME_ISIL7170_CMD_FREQ_4M (0x3) /* frequency 4.194304MHz */ 86: #define TME_ISIL7170_CMD_FREQ_2M (0x2) /* frequency 2.097152MHz */ 87: #define TME_ISIL7170_CMD_FREQ_1M (0x1) /* frequency 1.048576MHz */ 88: #define TME_ISIL7170_CMD_FREQ_32K (0x0) /* frequency 32.768KHz */ 89: 90: /* year zero in the chip corresponds to 1968: */ 91: #define TME_ISIL7170_REG_YEAR_0 (1968) 92: 93: /* define this to track interrupt rates, reporting once every N 94: seconds: */ 95: #if 1 96: #define TME_ISIL7170_TRACK_INT_RATE (10) 97: #endif 98: 99: #define TME_ISIL7170_LOG_HANDLE(am) (&(am)->tme_isil7170_element->tme_element_log_handle) 100: 101: /* structures: */ 102: struct tme_isil7170 { 103: 104: /* our simple bus device header: */ 105: struct tme_bus_device tme_isil7170_device; 106: #define tme_isil7170_element tme_isil7170_device.tme_bus_device_element 107: 108: /* our socket: */ 109: struct tme_isil7170_socket tme_isil7170_socket; 110: #define tme_isil7170_addr_shift tme_isil7170_socket.tme_isil7170_socket_addr_shift 111: #define tme_isil7170_port_least_lane tme_isil7170_socket.tme_isil7170_socket_port_least_lane 112: #define tme_isil7170_clock_basic tme_isil7170_socket.tme_isil7170_socket_clock_basic 113: #define tme_isil7170_int_signal tme_isil7170_socket.tme_isil7170_socket_int_signal 114: 115: /* our mutex: */ 116: tme_mutex_t tme_isil7170_mutex; 117: 118: /* our timer condition: */ 119: tme_cond_t tme_isil7170_cond_timer; 120: 121: /* this is nonzero iff callouts are running: */ 122: int tme_isil7170_callouts_running; 123: 124: /* it's easiest to just model the chip as a chunk of memory: */ 125: tme_uint8_t tme_isil7170_regs[TME_ISIL7170_REGS_COUNT]; 126: 127: /* the real-time durations, in microseconds, of a hundredth of a 128: second and a tenth of a second: */ 129: unsigned long tme_isil7170_clock_hsec_usec; 130: unsigned long tme_isil7170_clock_tsec_usec; 131: 132: /* if nonzero, the internal time-of-day needs to be updated: */ 133: tme_uint8_t tme_isil7170_tod_update; 134: 135: /* if nonzero, the interrupt the timer thread is sleeping for: */ 136: tme_uint8_t tme_isil7170_timer_sleeping; 137: 138: /* the interrupt mask: */ 139: tme_uint8_t tme_isil7170_int_mask; 140: 141: /* nonzero if the interrupt signal is asserted: */ 142: int tme_isil7170_int_asserted; 143: 144: /* any scaling factor: */ 145: unsigned long tme_isil7170_clock_scale; 146: 147: #ifdef TME_ISIL7170_TRACK_INT_RATE 148: 149: /* the end time of this sample: */ 150: struct timeval tme_isil7170_int_sample_time; 151: 152: /* the number of distinct interrupts that have been delivered during 153: this sample: */ 154: unsigned long tme_isil7170_int_sample; 155: #endif /* TME_ISIL7170_TRACK_INT_RATE */ 156: }; 157: 158: /* the isil7170 bus router: */ 159: static const tme_bus_lane_t tme_isil7170_router[TME_BUS_ROUTER_SIZE(TME_BUS8_LOG2)] = { 160: 161: /* [gen] initiator port size: 8 bits 162: [gen] initiator port least lane: 0: */ 163: /* D7-D0 */ TME_BUS_LANE_ROUTE(0), 164: }; 165: 166: /* this sets the frequency on an isil7170: */ 167: static void 168: _tme_isil7170_freq(struct tme_isil7170 *isil7170) 169: { 170: tme_uint32_t clock_user, clock_basic; 171: unsigned long hsec_usec, tsec_usec; 172: 173: /* get the user clock frequency: */ 174: switch (isil7170->tme_isil7170_regs[TME_ISIL7170_REG_CMD] & TME_ISIL7170_CMD_FREQ_MASK) { 175: case TME_ISIL7170_CMD_FREQ_4M: clock_user = TME_ISIL7170_FREQ_4M; break; 176: case TME_ISIL7170_CMD_FREQ_2M: clock_user = TME_ISIL7170_FREQ_2M; break; 177: case TME_ISIL7170_CMD_FREQ_1M: clock_user = TME_ISIL7170_FREQ_1M; break; 178: default: 179: case TME_ISIL7170_CMD_FREQ_32K: clock_user = TME_ISIL7170_FREQ_32K; break; 180: } 181: 182: /* get the hardware basic clock frequency: */ 183: clock_basic = isil7170->tme_isil7170_clock_basic; 184: 185: /* calculate the real-time durations, in microseconds, of a tenth 186: and hundredth of a second, given the actual basic clock into the 187: chip, and what the user claims is the basic clock into the chip. 188: we have to be careful to avoid overflow here: */ 189: if (clock_user == clock_basic) { 190: hsec_usec = 10000; 191: tsec_usec = 100000; 192: } 193: else { 194: hsec_usec = ((1000 * clock_user) / (clock_basic / 10)); 195: tsec_usec = ((1000 * clock_user) / (clock_basic / 100)); 196: } 197: 198: /* scale the result: */ 199: hsec_usec *= isil7170->tme_isil7170_clock_scale; 200: tsec_usec *= isil7170->tme_isil7170_clock_scale; 201: 202: isil7170->tme_isil7170_clock_hsec_usec = hsec_usec; 203: isil7170->tme_isil7170_clock_tsec_usec = tsec_usec; 204: } 205: 206: /* this makes isil7170 callouts. it must be called with the mutex held: */ 207: static void 208: _tme_isil7170_callout(struct tme_isil7170 *isil7170) 209: { 210: struct tme_bus_connection *conn_bus; 211: int again; 212: int int_asserted; 213: int rc; 214: 215: /* if this function is already running in another thread, return 216: now. the other thread will do our work: */ 217: if (isil7170->tme_isil7170_callouts_running) { 218: return; 219: } 220: 221: /* callouts are now running: */ 222: isil7170->tme_isil7170_callouts_running = TRUE; 223: 224: /* get our bus connection: */ 1.1.1.2 root 225: conn_bus = tme_memory_atomic_pointer_read(struct tme_bus_connection *, 226: isil7170->tme_isil7170_device.tme_bus_device_connection, 227: &isil7170->tme_isil7170_device.tme_bus_device_connection_rwlock); 1.1 root 228: 229: /* loop forever: */ 230: for (again = TRUE; again;) { 231: again = FALSE; 232: 233: /* see if there are any pending, unmasked interrupts: */ 234: int_asserted = (isil7170->tme_isil7170_regs[TME_ISIL7170_REG_INT] 235: & isil7170->tme_isil7170_int_mask); 236: 237: /* update our interrupt-pending flag: */ 238: if (int_asserted) { 239: isil7170->tme_isil7170_regs[TME_ISIL7170_REG_INT] 240: = ((isil7170->tme_isil7170_regs[TME_ISIL7170_REG_INT] 241: & ~TME_ISIL7170_INT_PENDING) 242: | (int_asserted 243: ? TME_ISIL7170_INT_PENDING 244: : 0)); 245: } 246: 247: /* see if our interrupt signal should be asserted: */ 248: int_asserted 249: = (int_asserted 250: && (isil7170->tme_isil7170_regs[TME_ISIL7170_REG_CMD] 251: & TME_ISIL7170_CMD_INTENA)); 252: 253: /* if our interrupt signal has changed: */ 254: if (!int_asserted != !isil7170->tme_isil7170_int_asserted) { 255: 256: /* unlock our mutex: */ 257: tme_mutex_unlock(&isil7170->tme_isil7170_mutex); 258: 259: rc = (*conn_bus->tme_bus_signal) 260: (conn_bus, 261: isil7170->tme_isil7170_int_signal 262: | (int_asserted 263: ? TME_BUS_SIGNAL_LEVEL_ASSERTED 264: : TME_BUS_SIGNAL_LEVEL_NEGATED)); 265: 266: /* lock our mutex: */ 267: tme_mutex_lock(&isil7170->tme_isil7170_mutex); 268: 269: /* if this call out succeeded, update the interrupt-asserted flag: */ 270: if (rc == TME_OK) { 271: isil7170->tme_isil7170_int_asserted = int_asserted; 272: again = TRUE; 273: } 274: } 275: } 276: 277: /* there are no more callouts to make: */ 278: isil7170->tme_isil7170_callouts_running = FALSE; 279: } 280: 281: /* this resets an isil7170: */ 282: static void 283: _tme_isil7170_reset(struct tme_isil7170 *isil7170) 284: { 285: 286: /* clear the interrupt mask: */ 287: isil7170->tme_isil7170_int_mask = 0; 288: 289: /* clear the command register: */ 290: isil7170->tme_isil7170_regs[TME_ISIL7170_REG_CMD] = 0; 291: 292: /* update the frequency: */ 293: _tme_isil7170_freq(isil7170); 294: 295: /* callout to update our interrupt signal: */ 296: _tme_isil7170_callout(isil7170); 297: } 298: 299: /* the isil7170 timer thread: */ 300: static void 301: _tme_isil7170_th_timer(struct tme_isil7170 *isil7170) 302: { 303: tme_uint8_t int_mask; 304: tme_uint32_t sleep_usec; 305: #ifdef TME_ISIL7170_TRACK_INT_RATE 306: struct timeval now; 307: #endif /* TME_ISIL7170_TRACK_INT_RATE */ 308: 309: /* lock the mutex: */ 310: tme_mutex_lock(&isil7170->tme_isil7170_mutex); 311: 312: /* loop forever: */ 313: for (;;) { 314: 315: /* if we were sleeping: */ 316: int_mask = isil7170->tme_isil7170_timer_sleeping; 317: isil7170->tme_isil7170_timer_sleeping = 0; 318: if (int_mask) { 319: 320: #ifdef TME_ISIL7170_TRACK_INT_RATE 321: 322: /* if no interrupt is pending, and this interrupt is not masked, 323: we will deliver another interrupt: */ 324: if (!(isil7170->tme_isil7170_regs[TME_ISIL7170_REG_INT] 325: & TME_ISIL7170_INT_PENDING) 326: && (int_mask 327: & isil7170->tme_isil7170_int_mask)) { 328: isil7170->tme_isil7170_int_sample++; 329: } 330: 331: /* if the sample time has finished, report on the interrupt rate: */ 332: gettimeofday(&now, NULL); 333: if (now.tv_sec > isil7170->tme_isil7170_int_sample_time.tv_sec 334: || (now.tv_sec == isil7170->tme_isil7170_int_sample_time.tv_sec 335: && now.tv_usec > isil7170->tme_isil7170_int_sample_time.tv_usec)) { 336: if (isil7170->tme_isil7170_int_sample > 0) { 337: tme_log(TME_ISIL7170_LOG_HANDLE(isil7170), 338: 0, TME_OK, 339: (TME_ISIL7170_LOG_HANDLE(isil7170), 340: "timer interrupt rate: %ld/sec", 341: (isil7170->tme_isil7170_int_sample 342: / (TME_ISIL7170_TRACK_INT_RATE 1.1.1.3 ! root 343: + (unsigned long) (now.tv_sec ! 344: - isil7170->tme_isil7170_int_sample_time.tv_sec))))); 1.1 root 345: } 346: 347: /* reset the sample: */ 348: isil7170->tme_isil7170_int_sample_time.tv_sec = now.tv_sec + TME_ISIL7170_TRACK_INT_RATE; 349: isil7170->tme_isil7170_int_sample_time.tv_usec = now.tv_usec; 350: isil7170->tme_isil7170_int_sample = 0; 351: } 352: 353: #endif /* TME_ISIL7170_TRACK_INT_RATE */ 354: 355: /* update the interrupt register: */ 356: isil7170->tme_isil7170_regs[TME_ISIL7170_REG_INT] |= int_mask; 357: 358: /* callout to update our interrupt signal: */ 359: _tme_isil7170_callout(isil7170); 360: } 361: 362: /* get the interrupt mask: */ 363: int_mask = isil7170->tme_isil7170_int_mask; 364: 365: /* if the 1/100 second periodic interrupt is unmasked: */ 366: if (int_mask & TME_ISIL7170_INT_HSEC) { 367: int_mask = TME_ISIL7170_INT_HSEC; 368: sleep_usec = isil7170->tme_isil7170_clock_hsec_usec; 369: } 370: 371: /* if the 1/10 second periodic interrupt is unmasked: */ 372: else if (int_mask & TME_ISIL7170_INT_TSEC) { 373: int_mask = TME_ISIL7170_INT_TSEC; 374: sleep_usec = isil7170->tme_isil7170_clock_tsec_usec; 375: } 376: 377: /* otherwise, all periodic interrupts are masked. wait until one 378: of them is not: */ 379: else { 380: tme_cond_wait_yield(&isil7170->tme_isil7170_cond_timer, 381: &isil7170->tme_isil7170_mutex); 382: continue; 383: } 384: 385: /* we are sleeping: */ 386: isil7170->tme_isil7170_timer_sleeping = int_mask; 387: 388: /* unlock our mutex: */ 389: tme_mutex_unlock(&isil7170->tme_isil7170_mutex); 390: 391: /* sleep: */ 392: tme_thread_sleep_yield(0, sleep_usec); 393: 394: /* lock our mutex: */ 395: tme_mutex_unlock(&isil7170->tme_isil7170_mutex); 396: } 397: /* NOTREACHED */ 398: } 399: 400: /* the isil7170 bus cycle handler: */ 401: static int 402: _tme_isil7170_bus_cycle(void *_isil7170, struct tme_bus_cycle *cycle_init) 403: { 404: struct tme_isil7170 *isil7170; 1.1.1.3 ! root 405: tme_bus_addr32_t address, isil7170_address_last; 1.1 root 406: tme_uint8_t buffer, value, value_old; 407: struct tme_bus_cycle cycle_resp; 408: unsigned int reg; 409: struct timeval now; 410: time_t _now; 411: struct tm *now_tm, now_tm_buffer; 412: 413: /* recover our data structure: */ 414: isil7170 = (struct tme_isil7170 *) _isil7170; 415: 416: /* the requested cycle must be within range: */ 417: isil7170_address_last = isil7170->tme_isil7170_device.tme_bus_device_address_last; 418: assert(cycle_init->tme_bus_cycle_address <= isil7170_address_last); 419: assert(cycle_init->tme_bus_cycle_size <= (isil7170_address_last - cycle_init->tme_bus_cycle_address) + 1); 420: 421: /* get the register being accessed: */ 422: address = cycle_init->tme_bus_cycle_address; 423: reg = address >> isil7170->tme_isil7170_addr_shift; 424: 425: /* lock the mutex: */ 426: tme_mutex_lock(&isil7170->tme_isil7170_mutex); 427: 428: /* if the clock is running and this address is in the time-of-day 429: registers, or if this is a write to the command register: */ 430: if (((isil7170->tme_isil7170_regs[TME_ISIL7170_REG_CMD] & TME_ISIL7170_CMD_RUN) 431: && reg <= TME_ISIL7170_REG_DOW) 432: || (cycle_init->tme_bus_cycle_type == TME_BUS_CYCLE_WRITE 433: && reg == TME_ISIL7170_REG_CMD)) { 434: 435: /* sample the time of day: */ 436: gettimeofday(&now, NULL); 437: _now = now.tv_sec; 438: now_tm = gmtime_r(&_now, &now_tm_buffer); 439: 440: /* put the time-of-day into the registers: */ 441: isil7170->tme_isil7170_regs[TME_ISIL7170_REG_CSEC] = now.tv_usec / 10000; 442: isil7170->tme_isil7170_regs[TME_ISIL7170_REG_HOUR] = now_tm->tm_hour; 443: isil7170->tme_isil7170_regs[TME_ISIL7170_REG_MIN] = now_tm->tm_min; 444: isil7170->tme_isil7170_regs[TME_ISIL7170_REG_SEC] = now_tm->tm_sec; 445: isil7170->tme_isil7170_regs[TME_ISIL7170_REG_MON] = now_tm->tm_mon + 1; 446: isil7170->tme_isil7170_regs[TME_ISIL7170_REG_DAY] = now_tm->tm_mday; 447: isil7170->tme_isil7170_regs[TME_ISIL7170_REG_YEAR] = (1900 + now_tm->tm_year) - TME_ISIL7170_REG_YEAR_0; 448: isil7170->tme_isil7170_regs[TME_ISIL7170_REG_DOW] = now_tm->tm_wday; 449: } 450: 451: /* if this is a write: */ 452: if (cycle_init->tme_bus_cycle_type == TME_BUS_CYCLE_WRITE) { 453: 454: /* run the bus cycle: */ 455: cycle_resp.tme_bus_cycle_buffer = &buffer; 456: cycle_resp.tme_bus_cycle_lane_routing = tme_isil7170_router; 457: cycle_resp.tme_bus_cycle_address = 0; 458: cycle_resp.tme_bus_cycle_buffer_increment = 1; 459: cycle_resp.tme_bus_cycle_type = TME_BUS_CYCLE_READ; 460: cycle_resp.tme_bus_cycle_size = sizeof(buffer); 461: cycle_resp.tme_bus_cycle_port = 462: TME_BUS_CYCLE_PORT(isil7170->tme_isil7170_port_least_lane, 463: TME_BUS8_LOG2); 464: tme_bus_cycle_xfer(cycle_init, &cycle_resp); 465: value = buffer; 466: 467: /* log this write: */ 468: tme_log(TME_ISIL7170_LOG_HANDLE(isil7170), 100000, TME_OK, 469: (TME_ISIL7170_LOG_HANDLE(isil7170), 470: "reg %d write %02x", 471: reg, value)); 472: 473: /* dispatch on the register: */ 474: switch (reg) { 475: 476: case TME_ISIL7170_REG_CSEC: 477: case TME_ISIL7170_REG_HOUR: 478: case TME_ISIL7170_REG_MIN: 479: case TME_ISIL7170_REG_SEC: 480: case TME_ISIL7170_REG_MON: 481: case TME_ISIL7170_REG_DAY: 482: case TME_ISIL7170_REG_YEAR: 483: case TME_ISIL7170_REG_DOW: 484: 485: /* flag that the time-of-day needs to be updated: */ 486: isil7170->tme_isil7170_tod_update = TRUE; 487: 488: /* FALLTHROUGH */ 489: 490: case TME_ISIL7170_REG_CMP_CSEC: 491: case TME_ISIL7170_REG_CMP_HOUR: 492: case TME_ISIL7170_REG_CMP_MIN: 493: case TME_ISIL7170_REG_CMP_SEC: 494: case TME_ISIL7170_REG_CMP_MON: 495: case TME_ISIL7170_REG_CMP_DAY: 496: case TME_ISIL7170_REG_CMP_YEAR: 497: case TME_ISIL7170_REG_CMP_DOW: 498: 499: /* update the register: */ 500: isil7170->tme_isil7170_regs[reg] = value; 501: break; 502: 503: case TME_ISIL7170_REG_INT: 504: 505: /* we don't support the alarm interrupt, or any of the daily, 506: hourly, etc., interrupts: */ 507: if (value & (TME_ISIL7170_INT_DAY 508: | TME_ISIL7170_INT_HOUR 509: | TME_ISIL7170_INT_MIN 510: | TME_ISIL7170_INT_SEC 511: | TME_ISIL7170_INT_ALARM)) { 512: abort(); 513: } 514: 515: /* update the interrupt mask: */ 516: isil7170->tme_isil7170_int_mask = (value & ~TME_ISIL7170_INT_PENDING); 517: 518: /* callout to update our interrupt signal: */ 519: _tme_isil7170_callout(isil7170); 520: 521: /* notify the timer thread: */ 522: tme_cond_notify(&isil7170->tme_isil7170_cond_timer, FALSE); 523: 524: break; 525: 526: case TME_ISIL7170_REG_CMD: 527: 528: /* we don't support the test mode: */ 529: if (value & TME_ISIL7170_CMD_TEST) { 530: abort(); 531: } 532: 533: /* update the command register: */ 534: value_old = isil7170->tme_isil7170_regs[TME_ISIL7170_REG_CMD]; 535: isil7170->tme_isil7170_regs[TME_ISIL7170_REG_CMD] = value; 536: 537: /* if the frequency changed, update our periodic intervals: */ 538: if ((value_old ^ value) & TME_ISIL7170_CMD_FREQ_MASK) { 539: _tme_isil7170_freq(isil7170); 540: } 541: 542: /* if the interrupt enable changed, callout to update our 543: interrupt signal: */ 544: if ((value_old ^ value) & TME_ISIL7170_CMD_INTENA) { 545: _tme_isil7170_callout(isil7170); 546: } 547: 548: break; 549: 550: default: 551: /* ignore */ 552: break; 553: } 554: } 555: 556: /* otherwise, this is a read: */ 557: else { 558: assert(cycle_init->tme_bus_cycle_type == TME_BUS_CYCLE_READ); 559: 560: /* dispatch on the register: */ 561: switch (reg) { 562: 563: case TME_ISIL7170_REG_CSEC: 564: case TME_ISIL7170_REG_HOUR: 565: case TME_ISIL7170_REG_MIN: 566: case TME_ISIL7170_REG_SEC: 567: case TME_ISIL7170_REG_MON: 568: case TME_ISIL7170_REG_DAY: 569: case TME_ISIL7170_REG_YEAR: 570: case TME_ISIL7170_REG_DOW: 571: case TME_ISIL7170_REG_CMP_CSEC: 572: case TME_ISIL7170_REG_CMP_HOUR: 573: case TME_ISIL7170_REG_CMP_MIN: 574: case TME_ISIL7170_REG_CMP_SEC: 575: case TME_ISIL7170_REG_CMP_MON: 576: case TME_ISIL7170_REG_CMP_DAY: 577: case TME_ISIL7170_REG_CMP_YEAR: 578: case TME_ISIL7170_REG_CMP_DOW: 579: 580: /* read the register: */ 581: value = isil7170->tme_isil7170_regs[reg]; 582: break; 583: 584: case TME_ISIL7170_REG_INT: 585: 586: /* reading the Interrupt register clears the interrupt: */ 587: value = isil7170->tme_isil7170_regs[TME_ISIL7170_REG_INT]; 588: isil7170->tme_isil7170_regs[TME_ISIL7170_REG_INT] = 0; 589: 590: /* callout to update our interrupt signal: */ 591: _tme_isil7170_callout(isil7170); 592: 593: break; 594: 595: /* the Command register, and all undefined registers, return 596: garbage when read: */ 597: case TME_ISIL7170_REG_CMD: 598: default: 599: value = 0xff; 600: break; 601: } 602: 603: /* log this read: */ 604: tme_log(TME_ISIL7170_LOG_HANDLE(isil7170), 100000, TME_OK, 605: (TME_ISIL7170_LOG_HANDLE(isil7170), 606: "reg %d read %02x", 607: reg, value)); 608: 609: /* run the bus cycle: */ 610: buffer = value; 611: cycle_resp.tme_bus_cycle_buffer = &buffer; 612: cycle_resp.tme_bus_cycle_lane_routing = tme_isil7170_router; 613: cycle_resp.tme_bus_cycle_address = 0; 614: cycle_resp.tme_bus_cycle_buffer_increment = 1; 615: cycle_resp.tme_bus_cycle_type = TME_BUS_CYCLE_WRITE; 616: cycle_resp.tme_bus_cycle_size = sizeof(buffer); 617: cycle_resp.tme_bus_cycle_port = 618: TME_BUS_CYCLE_PORT(isil7170->tme_isil7170_port_least_lane, 619: TME_BUS8_LOG2); 620: tme_bus_cycle_xfer(cycle_init, &cycle_resp); 621: } 622: 623: /* if the time-of-day registers have been updated, and the clock 624: is running: */ 625: if (isil7170->tme_isil7170_tod_update 626: && (isil7170->tme_isil7170_regs[TME_ISIL7170_REG_CMD] 627: & TME_ISIL7170_CMD_RUN)) { 628: 629: /* XXX update the host's time-of-day clock? */ 630: isil7170->tme_isil7170_tod_update = FALSE; 631: } 632: 633: /* unlock the mutex: */ 634: tme_mutex_unlock(&isil7170->tme_isil7170_mutex); 635: 636: /* no faults: */ 637: return (TME_OK); 638: } 639: 640: /* the isil7170 TLB filler: */ 641: static int 642: _tme_isil7170_tlb_fill(void *_isil7170, struct tme_bus_tlb *tlb, 643: tme_bus_addr_t address, unsigned int cycles) 644: { 645: struct tme_isil7170 *isil7170; 1.1.1.3 ! root 646: tme_bus_addr32_t isil7170_address_last; 1.1 root 647: 648: /* recover our data structure: */ 649: isil7170 = (struct tme_isil7170 *) _isil7170; 650: 651: /* the address must be within range: */ 652: isil7170_address_last = isil7170->tme_isil7170_device.tme_bus_device_address_last; 653: assert(address <= isil7170_address_last); 654: 655: /* initialize the TLB entry: */ 656: tme_bus_tlb_initialize(tlb); 657: 658: /* this TLB entry can cover the whole device: */ 1.1.1.2 root 659: tlb->tme_bus_tlb_addr_first = 0; 660: tlb->tme_bus_tlb_addr_last = isil7170_address_last; 1.1 root 661: 662: /* allow reading and writing: */ 663: tlb->tme_bus_tlb_cycles_ok = TME_BUS_CYCLE_READ | TME_BUS_CYCLE_WRITE; 664: 665: /* our bus cycle handler: */ 666: tlb->tme_bus_tlb_cycle_private = isil7170; 667: tlb->tme_bus_tlb_cycle = _tme_isil7170_bus_cycle; 668: 669: return (TME_OK); 670: } 671: 672: /* the new isil7170 element function: */ 673: TME_ELEMENT_NEW_DECL(tme_ic_isil7170) { 674: const struct tme_isil7170_socket *socket; 675: struct tme_isil7170 *isil7170; 676: struct tme_isil7170_socket socket_real; 677: tme_bus_addr_t address_mask; 678: unsigned long scale; 679: int arg_i; 680: int usage; 681: 682: /* dispatch on our socket version: */ 683: socket = (const struct tme_isil7170_socket *) extra; 684: if (socket == NULL) { 685: tme_output_append_error(_output, _("need an ic socket")); 686: return (ENXIO); 687: } 688: switch (socket->tme_isil7170_socket_version) { 689: case TME_ISIL7170_SOCKET_0: 690: socket_real = *socket; 691: break; 692: default: 693: tme_output_append_error(_output, _("socket type")); 694: return (EOPNOTSUPP); 695: } 696: 697: /* check our arguments: */ 698: usage = 0; 699: scale = 1; 700: arg_i = 1; 701: for (;;) { 702: 703: /* a scale factor: */ 704: if (TME_ARG_IS(args[arg_i + 0], "scale")) { 705: scale = tme_misc_unumber_parse(args[arg_i + 1], 0); 706: if (scale == 0) { 707: usage = TRUE; 708: break; 709: } 710: arg_i += 2; 711: } 712: 713: /* if we ran out of arguments: */ 714: else if (args[arg_i] == NULL) { 715: 716: break; 717: } 718: 719: /* otherwise this is a bad argument: */ 720: else { 721: tme_output_append_error(_output, 722: "%s %s, ", 723: args[arg_i], 724: _("unexpected")); 725: usage = TRUE; 726: break; 727: } 728: } 729: 730: if (usage) { 731: tme_output_append_error(_output, 732: "%s %s [ scale %s ]", 733: _("usage:"), 734: args[0], 735: _("SCALE")); 736: return (EINVAL); 737: } 738: 739: /* start the isil7170 structure: */ 740: isil7170 = tme_new0(struct tme_isil7170, 1); 741: isil7170->tme_isil7170_socket = socket_real; 742: isil7170->tme_isil7170_element = element; 743: isil7170->tme_isil7170_clock_scale = scale; 744: _tme_isil7170_reset(isil7170); 745: 746: /* figure our address mask, up to the nearest power of two: */ 747: address_mask = TME_ISIL7170_REGS_COUNT << isil7170->tme_isil7170_addr_shift; 748: if (address_mask & (address_mask - 1)) { 749: for (; address_mask & (address_mask - 1); address_mask &= (address_mask - 1)); 750: address_mask <<= 1; 751: } 752: address_mask -= 1; 753: 754: /* initialize our simple bus device descriptor: */ 755: isil7170->tme_isil7170_device.tme_bus_device_tlb_fill = _tme_isil7170_tlb_fill; 756: isil7170->tme_isil7170_device.tme_bus_device_address_last = address_mask; 757: 758: /* start the timer thread: */ 759: tme_mutex_init(&isil7170->tme_isil7170_mutex); 760: tme_cond_init(&isil7170->tme_isil7170_cond_reader); 761: tme_thread_create((tme_thread_t) _tme_isil7170_th_timer, isil7170); 762: 763: /* fill the element: */ 764: element->tme_element_private = isil7170; 765: element->tme_element_connections_new = tme_bus_device_connections_new; 766: 767: return (TME_OK); 768: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.