|
|
1.1 ! root 1: /* $Id: isil7170.c,v 1.3 2005/05/10 00:37:43 fredette Exp $ */ ! 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> ! 37: _TME_RCSID("$Id: isil7170.c,v 1.3 2005/05/10 00:37:43 fredette Exp $"); ! 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: */ ! 225: conn_bus = TME_ATOMIC_READ(struct tme_bus_connection *, ! 226: isil7170->tme_isil7170_device.tme_bus_device_connection); ! 227: ! 228: /* loop forever: */ ! 229: for (again = TRUE; again;) { ! 230: again = FALSE; ! 231: ! 232: /* see if there are any pending, unmasked interrupts: */ ! 233: int_asserted = (isil7170->tme_isil7170_regs[TME_ISIL7170_REG_INT] ! 234: & isil7170->tme_isil7170_int_mask); ! 235: ! 236: /* update our interrupt-pending flag: */ ! 237: if (int_asserted) { ! 238: isil7170->tme_isil7170_regs[TME_ISIL7170_REG_INT] ! 239: = ((isil7170->tme_isil7170_regs[TME_ISIL7170_REG_INT] ! 240: & ~TME_ISIL7170_INT_PENDING) ! 241: | (int_asserted ! 242: ? TME_ISIL7170_INT_PENDING ! 243: : 0)); ! 244: } ! 245: ! 246: /* see if our interrupt signal should be asserted: */ ! 247: int_asserted ! 248: = (int_asserted ! 249: && (isil7170->tme_isil7170_regs[TME_ISIL7170_REG_CMD] ! 250: & TME_ISIL7170_CMD_INTENA)); ! 251: ! 252: /* if our interrupt signal has changed: */ ! 253: if (!int_asserted != !isil7170->tme_isil7170_int_asserted) { ! 254: ! 255: /* unlock our mutex: */ ! 256: tme_mutex_unlock(&isil7170->tme_isil7170_mutex); ! 257: ! 258: rc = (*conn_bus->tme_bus_signal) ! 259: (conn_bus, ! 260: isil7170->tme_isil7170_int_signal ! 261: | (int_asserted ! 262: ? TME_BUS_SIGNAL_LEVEL_ASSERTED ! 263: : TME_BUS_SIGNAL_LEVEL_NEGATED)); ! 264: ! 265: /* lock our mutex: */ ! 266: tme_mutex_lock(&isil7170->tme_isil7170_mutex); ! 267: ! 268: /* if this call out succeeded, update the interrupt-asserted flag: */ ! 269: if (rc == TME_OK) { ! 270: isil7170->tme_isil7170_int_asserted = int_asserted; ! 271: again = TRUE; ! 272: } ! 273: } ! 274: } ! 275: ! 276: /* there are no more callouts to make: */ ! 277: isil7170->tme_isil7170_callouts_running = FALSE; ! 278: } ! 279: ! 280: /* this resets an isil7170: */ ! 281: static void ! 282: _tme_isil7170_reset(struct tme_isil7170 *isil7170) ! 283: { ! 284: ! 285: /* clear the interrupt mask: */ ! 286: isil7170->tme_isil7170_int_mask = 0; ! 287: ! 288: /* clear the command register: */ ! 289: isil7170->tme_isil7170_regs[TME_ISIL7170_REG_CMD] = 0; ! 290: ! 291: /* update the frequency: */ ! 292: _tme_isil7170_freq(isil7170); ! 293: ! 294: /* callout to update our interrupt signal: */ ! 295: _tme_isil7170_callout(isil7170); ! 296: } ! 297: ! 298: /* the isil7170 timer thread: */ ! 299: static void ! 300: _tme_isil7170_th_timer(struct tme_isil7170 *isil7170) ! 301: { ! 302: tme_uint8_t int_mask; ! 303: tme_uint32_t sleep_usec; ! 304: #ifdef TME_ISIL7170_TRACK_INT_RATE ! 305: struct timeval now; ! 306: #endif /* TME_ISIL7170_TRACK_INT_RATE */ ! 307: ! 308: /* lock the mutex: */ ! 309: tme_mutex_lock(&isil7170->tme_isil7170_mutex); ! 310: ! 311: /* loop forever: */ ! 312: for (;;) { ! 313: ! 314: /* if we were sleeping: */ ! 315: int_mask = isil7170->tme_isil7170_timer_sleeping; ! 316: isil7170->tme_isil7170_timer_sleeping = 0; ! 317: if (int_mask) { ! 318: ! 319: #ifdef TME_ISIL7170_TRACK_INT_RATE ! 320: ! 321: /* if no interrupt is pending, and this interrupt is not masked, ! 322: we will deliver another interrupt: */ ! 323: if (!(isil7170->tme_isil7170_regs[TME_ISIL7170_REG_INT] ! 324: & TME_ISIL7170_INT_PENDING) ! 325: && (int_mask ! 326: & isil7170->tme_isil7170_int_mask)) { ! 327: isil7170->tme_isil7170_int_sample++; ! 328: } ! 329: ! 330: /* if the sample time has finished, report on the interrupt rate: */ ! 331: gettimeofday(&now, NULL); ! 332: if (now.tv_sec > isil7170->tme_isil7170_int_sample_time.tv_sec ! 333: || (now.tv_sec == isil7170->tme_isil7170_int_sample_time.tv_sec ! 334: && now.tv_usec > isil7170->tme_isil7170_int_sample_time.tv_usec)) { ! 335: if (isil7170->tme_isil7170_int_sample > 0) { ! 336: tme_log(TME_ISIL7170_LOG_HANDLE(isil7170), ! 337: 0, TME_OK, ! 338: (TME_ISIL7170_LOG_HANDLE(isil7170), ! 339: "timer interrupt rate: %ld/sec", ! 340: (isil7170->tme_isil7170_int_sample ! 341: / (TME_ISIL7170_TRACK_INT_RATE ! 342: + now.tv_sec ! 343: - isil7170->tme_isil7170_int_sample_time.tv_sec)))); ! 344: } ! 345: ! 346: /* reset the sample: */ ! 347: isil7170->tme_isil7170_int_sample_time.tv_sec = now.tv_sec + TME_ISIL7170_TRACK_INT_RATE; ! 348: isil7170->tme_isil7170_int_sample_time.tv_usec = now.tv_usec; ! 349: isil7170->tme_isil7170_int_sample = 0; ! 350: } ! 351: ! 352: #endif /* TME_ISIL7170_TRACK_INT_RATE */ ! 353: ! 354: /* update the interrupt register: */ ! 355: isil7170->tme_isil7170_regs[TME_ISIL7170_REG_INT] |= int_mask; ! 356: ! 357: /* callout to update our interrupt signal: */ ! 358: _tme_isil7170_callout(isil7170); ! 359: } ! 360: ! 361: /* get the interrupt mask: */ ! 362: int_mask = isil7170->tme_isil7170_int_mask; ! 363: ! 364: /* if the 1/100 second periodic interrupt is unmasked: */ ! 365: if (int_mask & TME_ISIL7170_INT_HSEC) { ! 366: int_mask = TME_ISIL7170_INT_HSEC; ! 367: sleep_usec = isil7170->tme_isil7170_clock_hsec_usec; ! 368: } ! 369: ! 370: /* if the 1/10 second periodic interrupt is unmasked: */ ! 371: else if (int_mask & TME_ISIL7170_INT_TSEC) { ! 372: int_mask = TME_ISIL7170_INT_TSEC; ! 373: sleep_usec = isil7170->tme_isil7170_clock_tsec_usec; ! 374: } ! 375: ! 376: /* otherwise, all periodic interrupts are masked. wait until one ! 377: of them is not: */ ! 378: else { ! 379: tme_cond_wait_yield(&isil7170->tme_isil7170_cond_timer, ! 380: &isil7170->tme_isil7170_mutex); ! 381: continue; ! 382: } ! 383: ! 384: /* we are sleeping: */ ! 385: isil7170->tme_isil7170_timer_sleeping = int_mask; ! 386: ! 387: /* unlock our mutex: */ ! 388: tme_mutex_unlock(&isil7170->tme_isil7170_mutex); ! 389: ! 390: /* sleep: */ ! 391: tme_thread_sleep_yield(0, sleep_usec); ! 392: ! 393: /* lock our mutex: */ ! 394: tme_mutex_unlock(&isil7170->tme_isil7170_mutex); ! 395: } ! 396: /* NOTREACHED */ ! 397: } ! 398: ! 399: /* the isil7170 bus cycle handler: */ ! 400: static int ! 401: _tme_isil7170_bus_cycle(void *_isil7170, struct tme_bus_cycle *cycle_init) ! 402: { ! 403: struct tme_isil7170 *isil7170; ! 404: tme_bus_addr_t address, isil7170_address_last; ! 405: tme_uint8_t buffer, value, value_old; ! 406: struct tme_bus_cycle cycle_resp; ! 407: unsigned int reg; ! 408: struct timeval now; ! 409: time_t _now; ! 410: struct tm *now_tm, now_tm_buffer; ! 411: ! 412: /* recover our data structure: */ ! 413: isil7170 = (struct tme_isil7170 *) _isil7170; ! 414: ! 415: /* the requested cycle must be within range: */ ! 416: isil7170_address_last = isil7170->tme_isil7170_device.tme_bus_device_address_last; ! 417: assert(cycle_init->tme_bus_cycle_address <= isil7170_address_last); ! 418: assert(cycle_init->tme_bus_cycle_size <= (isil7170_address_last - cycle_init->tme_bus_cycle_address) + 1); ! 419: ! 420: /* get the register being accessed: */ ! 421: address = cycle_init->tme_bus_cycle_address; ! 422: reg = address >> isil7170->tme_isil7170_addr_shift; ! 423: ! 424: /* lock the mutex: */ ! 425: tme_mutex_lock(&isil7170->tme_isil7170_mutex); ! 426: ! 427: /* if the clock is running and this address is in the time-of-day ! 428: registers, or if this is a write to the command register: */ ! 429: if (((isil7170->tme_isil7170_regs[TME_ISIL7170_REG_CMD] & TME_ISIL7170_CMD_RUN) ! 430: && reg <= TME_ISIL7170_REG_DOW) ! 431: || (cycle_init->tme_bus_cycle_type == TME_BUS_CYCLE_WRITE ! 432: && reg == TME_ISIL7170_REG_CMD)) { ! 433: ! 434: /* sample the time of day: */ ! 435: gettimeofday(&now, NULL); ! 436: _now = now.tv_sec; ! 437: now_tm = gmtime_r(&_now, &now_tm_buffer); ! 438: ! 439: /* put the time-of-day into the registers: */ ! 440: isil7170->tme_isil7170_regs[TME_ISIL7170_REG_CSEC] = now.tv_usec / 10000; ! 441: isil7170->tme_isil7170_regs[TME_ISIL7170_REG_HOUR] = now_tm->tm_hour; ! 442: isil7170->tme_isil7170_regs[TME_ISIL7170_REG_MIN] = now_tm->tm_min; ! 443: isil7170->tme_isil7170_regs[TME_ISIL7170_REG_SEC] = now_tm->tm_sec; ! 444: isil7170->tme_isil7170_regs[TME_ISIL7170_REG_MON] = now_tm->tm_mon + 1; ! 445: isil7170->tme_isil7170_regs[TME_ISIL7170_REG_DAY] = now_tm->tm_mday; ! 446: isil7170->tme_isil7170_regs[TME_ISIL7170_REG_YEAR] = (1900 + now_tm->tm_year) - TME_ISIL7170_REG_YEAR_0; ! 447: isil7170->tme_isil7170_regs[TME_ISIL7170_REG_DOW] = now_tm->tm_wday; ! 448: } ! 449: ! 450: /* if this is a write: */ ! 451: if (cycle_init->tme_bus_cycle_type == TME_BUS_CYCLE_WRITE) { ! 452: ! 453: /* run the bus cycle: */ ! 454: cycle_resp.tme_bus_cycle_buffer = &buffer; ! 455: cycle_resp.tme_bus_cycle_lane_routing = tme_isil7170_router; ! 456: cycle_resp.tme_bus_cycle_address = 0; ! 457: cycle_resp.tme_bus_cycle_buffer_increment = 1; ! 458: cycle_resp.tme_bus_cycle_type = TME_BUS_CYCLE_READ; ! 459: cycle_resp.tme_bus_cycle_size = sizeof(buffer); ! 460: cycle_resp.tme_bus_cycle_port = ! 461: TME_BUS_CYCLE_PORT(isil7170->tme_isil7170_port_least_lane, ! 462: TME_BUS8_LOG2); ! 463: tme_bus_cycle_xfer(cycle_init, &cycle_resp); ! 464: value = buffer; ! 465: ! 466: /* log this write: */ ! 467: tme_log(TME_ISIL7170_LOG_HANDLE(isil7170), 100000, TME_OK, ! 468: (TME_ISIL7170_LOG_HANDLE(isil7170), ! 469: "reg %d write %02x", ! 470: reg, value)); ! 471: ! 472: /* dispatch on the register: */ ! 473: switch (reg) { ! 474: ! 475: case TME_ISIL7170_REG_CSEC: ! 476: case TME_ISIL7170_REG_HOUR: ! 477: case TME_ISIL7170_REG_MIN: ! 478: case TME_ISIL7170_REG_SEC: ! 479: case TME_ISIL7170_REG_MON: ! 480: case TME_ISIL7170_REG_DAY: ! 481: case TME_ISIL7170_REG_YEAR: ! 482: case TME_ISIL7170_REG_DOW: ! 483: ! 484: /* flag that the time-of-day needs to be updated: */ ! 485: isil7170->tme_isil7170_tod_update = TRUE; ! 486: ! 487: /* FALLTHROUGH */ ! 488: ! 489: case TME_ISIL7170_REG_CMP_CSEC: ! 490: case TME_ISIL7170_REG_CMP_HOUR: ! 491: case TME_ISIL7170_REG_CMP_MIN: ! 492: case TME_ISIL7170_REG_CMP_SEC: ! 493: case TME_ISIL7170_REG_CMP_MON: ! 494: case TME_ISIL7170_REG_CMP_DAY: ! 495: case TME_ISIL7170_REG_CMP_YEAR: ! 496: case TME_ISIL7170_REG_CMP_DOW: ! 497: ! 498: /* update the register: */ ! 499: isil7170->tme_isil7170_regs[reg] = value; ! 500: break; ! 501: ! 502: case TME_ISIL7170_REG_INT: ! 503: ! 504: /* we don't support the alarm interrupt, or any of the daily, ! 505: hourly, etc., interrupts: */ ! 506: if (value & (TME_ISIL7170_INT_DAY ! 507: | TME_ISIL7170_INT_HOUR ! 508: | TME_ISIL7170_INT_MIN ! 509: | TME_ISIL7170_INT_SEC ! 510: | TME_ISIL7170_INT_ALARM)) { ! 511: abort(); ! 512: } ! 513: ! 514: /* update the interrupt mask: */ ! 515: isil7170->tme_isil7170_int_mask = (value & ~TME_ISIL7170_INT_PENDING); ! 516: ! 517: /* callout to update our interrupt signal: */ ! 518: _tme_isil7170_callout(isil7170); ! 519: ! 520: /* notify the timer thread: */ ! 521: tme_cond_notify(&isil7170->tme_isil7170_cond_timer, FALSE); ! 522: ! 523: break; ! 524: ! 525: case TME_ISIL7170_REG_CMD: ! 526: ! 527: /* we don't support the test mode: */ ! 528: if (value & TME_ISIL7170_CMD_TEST) { ! 529: abort(); ! 530: } ! 531: ! 532: /* update the command register: */ ! 533: value_old = isil7170->tme_isil7170_regs[TME_ISIL7170_REG_CMD]; ! 534: isil7170->tme_isil7170_regs[TME_ISIL7170_REG_CMD] = value; ! 535: ! 536: /* if the frequency changed, update our periodic intervals: */ ! 537: if ((value_old ^ value) & TME_ISIL7170_CMD_FREQ_MASK) { ! 538: _tme_isil7170_freq(isil7170); ! 539: } ! 540: ! 541: /* if the interrupt enable changed, callout to update our ! 542: interrupt signal: */ ! 543: if ((value_old ^ value) & TME_ISIL7170_CMD_INTENA) { ! 544: _tme_isil7170_callout(isil7170); ! 545: } ! 546: ! 547: break; ! 548: ! 549: default: ! 550: /* ignore */ ! 551: break; ! 552: } ! 553: } ! 554: ! 555: /* otherwise, this is a read: */ ! 556: else { ! 557: assert(cycle_init->tme_bus_cycle_type == TME_BUS_CYCLE_READ); ! 558: ! 559: /* dispatch on the register: */ ! 560: switch (reg) { ! 561: ! 562: case TME_ISIL7170_REG_CSEC: ! 563: case TME_ISIL7170_REG_HOUR: ! 564: case TME_ISIL7170_REG_MIN: ! 565: case TME_ISIL7170_REG_SEC: ! 566: case TME_ISIL7170_REG_MON: ! 567: case TME_ISIL7170_REG_DAY: ! 568: case TME_ISIL7170_REG_YEAR: ! 569: case TME_ISIL7170_REG_DOW: ! 570: case TME_ISIL7170_REG_CMP_CSEC: ! 571: case TME_ISIL7170_REG_CMP_HOUR: ! 572: case TME_ISIL7170_REG_CMP_MIN: ! 573: case TME_ISIL7170_REG_CMP_SEC: ! 574: case TME_ISIL7170_REG_CMP_MON: ! 575: case TME_ISIL7170_REG_CMP_DAY: ! 576: case TME_ISIL7170_REG_CMP_YEAR: ! 577: case TME_ISIL7170_REG_CMP_DOW: ! 578: ! 579: /* read the register: */ ! 580: value = isil7170->tme_isil7170_regs[reg]; ! 581: break; ! 582: ! 583: case TME_ISIL7170_REG_INT: ! 584: ! 585: /* reading the Interrupt register clears the interrupt: */ ! 586: value = isil7170->tme_isil7170_regs[TME_ISIL7170_REG_INT]; ! 587: isil7170->tme_isil7170_regs[TME_ISIL7170_REG_INT] = 0; ! 588: ! 589: /* callout to update our interrupt signal: */ ! 590: _tme_isil7170_callout(isil7170); ! 591: ! 592: break; ! 593: ! 594: /* the Command register, and all undefined registers, return ! 595: garbage when read: */ ! 596: case TME_ISIL7170_REG_CMD: ! 597: default: ! 598: value = 0xff; ! 599: break; ! 600: } ! 601: ! 602: /* log this read: */ ! 603: tme_log(TME_ISIL7170_LOG_HANDLE(isil7170), 100000, TME_OK, ! 604: (TME_ISIL7170_LOG_HANDLE(isil7170), ! 605: "reg %d read %02x", ! 606: reg, value)); ! 607: ! 608: /* run the bus cycle: */ ! 609: buffer = value; ! 610: cycle_resp.tme_bus_cycle_buffer = &buffer; ! 611: cycle_resp.tme_bus_cycle_lane_routing = tme_isil7170_router; ! 612: cycle_resp.tme_bus_cycle_address = 0; ! 613: cycle_resp.tme_bus_cycle_buffer_increment = 1; ! 614: cycle_resp.tme_bus_cycle_type = TME_BUS_CYCLE_WRITE; ! 615: cycle_resp.tme_bus_cycle_size = sizeof(buffer); ! 616: cycle_resp.tme_bus_cycle_port = ! 617: TME_BUS_CYCLE_PORT(isil7170->tme_isil7170_port_least_lane, ! 618: TME_BUS8_LOG2); ! 619: tme_bus_cycle_xfer(cycle_init, &cycle_resp); ! 620: } ! 621: ! 622: /* if the time-of-day registers have been updated, and the clock ! 623: is running: */ ! 624: if (isil7170->tme_isil7170_tod_update ! 625: && (isil7170->tme_isil7170_regs[TME_ISIL7170_REG_CMD] ! 626: & TME_ISIL7170_CMD_RUN)) { ! 627: ! 628: /* XXX update the host's time-of-day clock? */ ! 629: isil7170->tme_isil7170_tod_update = FALSE; ! 630: } ! 631: ! 632: /* unlock the mutex: */ ! 633: tme_mutex_unlock(&isil7170->tme_isil7170_mutex); ! 634: ! 635: /* no faults: */ ! 636: return (TME_OK); ! 637: } ! 638: ! 639: /* the isil7170 TLB filler: */ ! 640: static int ! 641: _tme_isil7170_tlb_fill(void *_isil7170, struct tme_bus_tlb *tlb, ! 642: tme_bus_addr_t address, unsigned int cycles) ! 643: { ! 644: struct tme_isil7170 *isil7170; ! 645: tme_bus_addr_t isil7170_address_last; ! 646: ! 647: /* recover our data structure: */ ! 648: isil7170 = (struct tme_isil7170 *) _isil7170; ! 649: ! 650: /* the address must be within range: */ ! 651: isil7170_address_last = isil7170->tme_isil7170_device.tme_bus_device_address_last; ! 652: assert(address <= isil7170_address_last); ! 653: ! 654: /* initialize the TLB entry: */ ! 655: tme_bus_tlb_initialize(tlb); ! 656: ! 657: /* this TLB entry can cover the whole device: */ ! 658: TME_ATOMIC_WRITE(tme_bus_addr_t, tlb->tme_bus_tlb_addr_first, 0); ! 659: TME_ATOMIC_WRITE(tme_bus_addr_t, tlb->tme_bus_tlb_addr_last, isil7170_address_last); ! 660: ! 661: /* allow reading and writing: */ ! 662: tlb->tme_bus_tlb_cycles_ok = TME_BUS_CYCLE_READ | TME_BUS_CYCLE_WRITE; ! 663: ! 664: /* our bus cycle handler: */ ! 665: tlb->tme_bus_tlb_cycle_private = isil7170; ! 666: tlb->tme_bus_tlb_cycle = _tme_isil7170_bus_cycle; ! 667: ! 668: return (TME_OK); ! 669: } ! 670: ! 671: /* the new isil7170 element function: */ ! 672: TME_ELEMENT_NEW_DECL(tme_ic_isil7170) { ! 673: const struct tme_isil7170_socket *socket; ! 674: struct tme_isil7170 *isil7170; ! 675: struct tme_isil7170_socket socket_real; ! 676: tme_bus_addr_t address_mask; ! 677: unsigned long scale; ! 678: int arg_i; ! 679: int usage; ! 680: ! 681: /* dispatch on our socket version: */ ! 682: socket = (const struct tme_isil7170_socket *) extra; ! 683: if (socket == NULL) { ! 684: tme_output_append_error(_output, _("need an ic socket")); ! 685: return (ENXIO); ! 686: } ! 687: switch (socket->tme_isil7170_socket_version) { ! 688: case TME_ISIL7170_SOCKET_0: ! 689: socket_real = *socket; ! 690: break; ! 691: default: ! 692: tme_output_append_error(_output, _("socket type")); ! 693: return (EOPNOTSUPP); ! 694: } ! 695: ! 696: /* check our arguments: */ ! 697: usage = 0; ! 698: scale = 1; ! 699: arg_i = 1; ! 700: for (;;) { ! 701: ! 702: /* a scale factor: */ ! 703: if (TME_ARG_IS(args[arg_i + 0], "scale")) { ! 704: scale = tme_misc_unumber_parse(args[arg_i + 1], 0); ! 705: if (scale == 0) { ! 706: usage = TRUE; ! 707: break; ! 708: } ! 709: arg_i += 2; ! 710: } ! 711: ! 712: /* if we ran out of arguments: */ ! 713: else if (args[arg_i] == NULL) { ! 714: ! 715: break; ! 716: } ! 717: ! 718: /* otherwise this is a bad argument: */ ! 719: else { ! 720: tme_output_append_error(_output, ! 721: "%s %s, ", ! 722: args[arg_i], ! 723: _("unexpected")); ! 724: usage = TRUE; ! 725: break; ! 726: } ! 727: } ! 728: ! 729: if (usage) { ! 730: tme_output_append_error(_output, ! 731: "%s %s [ scale %s ]", ! 732: _("usage:"), ! 733: args[0], ! 734: _("SCALE")); ! 735: return (EINVAL); ! 736: } ! 737: ! 738: /* start the isil7170 structure: */ ! 739: isil7170 = tme_new0(struct tme_isil7170, 1); ! 740: isil7170->tme_isil7170_socket = socket_real; ! 741: isil7170->tme_isil7170_element = element; ! 742: isil7170->tme_isil7170_clock_scale = scale; ! 743: _tme_isil7170_reset(isil7170); ! 744: ! 745: /* figure our address mask, up to the nearest power of two: */ ! 746: address_mask = TME_ISIL7170_REGS_COUNT << isil7170->tme_isil7170_addr_shift; ! 747: if (address_mask & (address_mask - 1)) { ! 748: for (; address_mask & (address_mask - 1); address_mask &= (address_mask - 1)); ! 749: address_mask <<= 1; ! 750: } ! 751: address_mask -= 1; ! 752: ! 753: /* initialize our simple bus device descriptor: */ ! 754: isil7170->tme_isil7170_device.tme_bus_device_tlb_fill = _tme_isil7170_tlb_fill; ! 755: isil7170->tme_isil7170_device.tme_bus_device_address_last = address_mask; ! 756: ! 757: /* start the timer thread: */ ! 758: tme_mutex_init(&isil7170->tme_isil7170_mutex); ! 759: tme_cond_init(&isil7170->tme_isil7170_cond_reader); ! 760: tme_thread_create((tme_thread_t) _tme_isil7170_th_timer, isil7170); ! 761: ! 762: /* fill the element: */ ! 763: element->tme_element_private = isil7170; ! 764: element->tme_element_connections_new = tme_bus_device_connections_new; ! 765: ! 766: return (TME_OK); ! 767: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.