|
|
1.1.1.2 ! root 1: /* $Id: mk48txx.c,v 1.4 2010/06/05 14:54:10 fredette Exp $ */ 1.1 root 2: 3: /* ic/mk48txx.c - implementation of Mostek 48Txx emulation: */ 4: 5: /* 6: * Copyright (c) 2006 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.2 ! root 37: _TME_RCSID("$Id: mk48txx.c,v 1.4 2010/06/05 14:54:10 fredette Exp $"); 1.1 root 38: 39: /* includes: */ 40: #include <tme/generic/bus-device.h> 41: #include <tme/ic/mk48txx.h> 42: #include <tme/misc.h> 43: #include <time.h> 44: #include <sys/time.h> 45: 46: /* macros: */ 47: 48: /* the different parts: */ 49: #define TME_MK48TXX_PART_02 (02) 1.1.1.2 ! root 50: #define TME_MK48TXX_PART_59 (59) 1.1 root 51: 52: /* register addresses: */ 1.1.1.2 ! root 53: #define TME_MK48TXX_REGS_COUNT (16) /* maximum number of registers */ 1.1 root 54: #define TME_MK48TXX_REG_YEAR (TME_MK48TXX_REGS_COUNT - 1) /* BCD year */ 55: #define TME_MK48TXX_REG_MON (TME_MK48TXX_REGS_COUNT - 2) /* BCD month */ 56: #define TME_MK48TXX_REG_DAY (TME_MK48TXX_REGS_COUNT - 3) /* BCD day in month */ 57: #define TME_MK48TXX_REG_WDAY (TME_MK48TXX_REGS_COUNT - 4) /* weekday */ 58: #define TME_MK48TXX_REG_HOUR (TME_MK48TXX_REGS_COUNT - 5) /* BCD hour */ 59: #define TME_MK48TXX_REG_MIN (TME_MK48TXX_REGS_COUNT - 6) /* BCD minutes */ 60: #define TME_MK48TXX_REG_SEC (TME_MK48TXX_REGS_COUNT - 7) /* BCD seconds */ 61: #define TME_MK48TXX_REG_CSR (TME_MK48TXX_REGS_COUNT - 8) /* control register */ 1.1.1.2 ! root 62: #define TME_MK48TXX_REG_WDOG (TME_MK48TXX_REGS_COUNT - 9) /* watchdog */ ! 63: #define TME_MK48TXX_REG_INTR (TME_MK48TXX_REGS_COUNT - 10) /* interrupts */ ! 64: #define TME_MK48TXX_REG_ADAY (TME_MK48TXX_REGS_COUNT - 11) /* BCD alarm day */ ! 65: #define TME_MK48TXX_REG_AHOUR (TME_MK48TXX_REGS_COUNT - 12) /* BCD alarm hour */ ! 66: #define TME_MK48TXX_REG_AMIN (TME_MK48TXX_REGS_COUNT - 13) /* BCD alarm minutes */ ! 67: #define TME_MK48TXX_REG_ASEC (TME_MK48TXX_REGS_COUNT - 14) /* BCD alarm seconds */ ! 68: /* (TME_MK48TXX_REGS_COUNT - 15) unused */ ! 69: #define TME_MK48TXX_REG_FLAGS (TME_MK48TXX_REGS_COUNT - 16) /* flags */ 1.1 root 70: 71: /* the first register implemented by a part: */ 1.1.1.2 ! root 72: #define TME_MK48TXX_REG_FIRST(part) \ ! 73: ((part) == TME_MK48TXX_PART_59 \ ! 74: ? TME_MK48TXX_REG_FLAGS \ ! 75: : TME_MK48TXX_REG_CSR) 1.1 root 76: 77: /* bits in the CSR: */ 78: #define TME_MK48TXX_CSR_WRITE TME_BIT(7) /* start writing */ 79: #define TME_MK48TXX_CSR_READ TME_BIT(6) /* start reading */ 80: 81: /* bits in the weekday register: */ 82: #define TME_MK48TXX_WDAY_FTEST TME_BIT(6) /* 512Hz frequency test */ 83: 84: /* bits in the seconds register: */ 85: #define TME_MK48TXX_SEC_STOP TME_BIT(7) /* all stop */ 86: 87: #define TME_MK48TXX_LOG_HANDLE(am) (&(am)->tme_mk48txx_element->tme_element_log_handle) 88: 89: /* structures: */ 90: struct tme_mk48txx { 91: 92: /* our simple bus device header: */ 93: struct tme_bus_device tme_mk48txx_device; 94: #define tme_mk48txx_element tme_mk48txx_device.tme_bus_device_element 95: 96: /* our socket: */ 97: struct tme_mk48txx_socket tme_mk48txx_socket; 98: #define tme_mk48txx_addr_shift tme_mk48txx_socket.tme_mk48txx_socket_addr_shift 99: #define tme_mk48txx_port_least_lane tme_mk48txx_socket.tme_mk48txx_socket_port_least_lane 100: #define tme_mk48txx_year_zero tme_mk48txx_socket.tme_mk48txx_socket_year_zero 101: 102: /* our mutex: */ 103: tme_mutex_t tme_mk48txx_mutex; 104: 105: /* the part emulated: */ 106: unsigned int tme_mk48txx_part; 107: 108: /* our timer condition: */ 109: tme_cond_t tme_mk48txx_cond_timer; 110: 111: /* it's easiest to just model the chip as a chunk of memory: */ 112: tme_uint8_t tme_mk48txx_regs[TME_MK48TXX_REGS_COUNT]; 113: 114: /* if nonzero, the internal time-of-day needs to be updated: */ 115: tme_uint8_t tme_mk48txx_tod_update; 116: }; 117: 118: /* the mk48txx bus router: */ 119: static const tme_bus_lane_t tme_mk48txx_router[TME_BUS_ROUTER_SIZE(TME_BUS8_LOG2)] = { 120: 121: /* [gen] initiator port size: 8 bits 122: [gen] initiator port least lane: 0: */ 123: /* D7-D0 */ TME_BUS_LANE_ROUTE(0), 124: }; 125: 126: /* these convert values to and from BCD: */ 127: static inline tme_uint8_t 128: _tme_mk48txx_bcd_out(unsigned int value) 129: { 130: return ((value % 10) 131: + ((value / 10) * 16)); 132: } 133: static inline unsigned int 134: _tme_mk48txx_bcd_in(tme_uint8_t value) 135: { 136: return ((value % 16) 137: + ((value / 16) * 10)); 138: } 139: 140: /* this resets an mk48txx: */ 141: static void 142: _tme_mk48txx_reset(struct tme_mk48txx *mk48txx) 143: { 144: 145: /* clear the CSR: */ 146: mk48txx->tme_mk48txx_regs[TME_MK48TXX_REG_CSR] = 0; 147: 148: /* start the clock running normally: */ 149: mk48txx->tme_mk48txx_regs[TME_MK48TXX_REG_WDAY] = 0; 1.1.1.2 ! root 150: mk48txx->tme_mk48txx_regs[TME_MK48TXX_REG_SEC] = !TME_MK48TXX_SEC_STOP; 1.1 root 151: } 152: 153: /* the mk48txx bus cycle handler: */ 154: static int 155: _tme_mk48txx_bus_cycle(void *_mk48txx, struct tme_bus_cycle *cycle_init) 156: { 157: struct tme_mk48txx *mk48txx; 1.1.1.2 ! root 158: tme_bus_addr32_t address, mk48txx_address_last; 1.1 root 159: tme_uint8_t buffer, value; 160: struct tme_bus_cycle cycle_resp; 161: unsigned int reg; 162: struct timeval now; 163: time_t _now; 164: struct tm *now_tm, now_tm_buffer; 165: 166: /* recover our data structure: */ 167: mk48txx = (struct tme_mk48txx *) _mk48txx; 168: 169: /* the requested cycle must be within range: */ 170: mk48txx_address_last = mk48txx->tme_mk48txx_device.tme_bus_device_address_last; 171: assert(cycle_init->tme_bus_cycle_address <= mk48txx_address_last); 172: assert(cycle_init->tme_bus_cycle_size <= (mk48txx_address_last - cycle_init->tme_bus_cycle_address) + 1); 173: 174: /* get the register being accessed: */ 175: address = cycle_init->tme_bus_cycle_address; 176: reg = (address >> mk48txx->tme_mk48txx_addr_shift) + TME_MK48TXX_REG_FIRST(mk48txx->tme_mk48txx_part); 177: 178: /* lock the mutex: */ 179: tme_mutex_lock(&mk48txx->tme_mk48txx_mutex); 180: 181: /* if the clock is not being read or written: */ 182: if ((mk48txx->tme_mk48txx_regs[TME_MK48TXX_REG_CSR] 183: & (TME_MK48TXX_CSR_READ 184: | TME_MK48TXX_CSR_WRITE)) == 0) { 185: 186: /* sample the time of day: */ 187: gettimeofday(&now, NULL); 188: _now = now.tv_sec; 189: now_tm = gmtime_r(&_now, &now_tm_buffer); 190: 191: /* put the time-of-day into the registers: */ 192: mk48txx->tme_mk48txx_regs[TME_MK48TXX_REG_HOUR] = _tme_mk48txx_bcd_out(now_tm->tm_hour); 193: mk48txx->tme_mk48txx_regs[TME_MK48TXX_REG_MIN] = _tme_mk48txx_bcd_out(now_tm->tm_min); 194: mk48txx->tme_mk48txx_regs[TME_MK48TXX_REG_SEC] = _tme_mk48txx_bcd_out(now_tm->tm_sec); 195: mk48txx->tme_mk48txx_regs[TME_MK48TXX_REG_MON] = _tme_mk48txx_bcd_out(now_tm->tm_mon + 1); 196: mk48txx->tme_mk48txx_regs[TME_MK48TXX_REG_DAY] = _tme_mk48txx_bcd_out(now_tm->tm_mday); 197: mk48txx->tme_mk48txx_regs[TME_MK48TXX_REG_YEAR] 198: = _tme_mk48txx_bcd_out((1900 + now_tm->tm_year) - mk48txx->tme_mk48txx_year_zero); 199: mk48txx->tme_mk48txx_regs[TME_MK48TXX_REG_WDAY] = now_tm->tm_wday; 200: } 201: 202: /* if this is a write: */ 203: if (cycle_init->tme_bus_cycle_type == TME_BUS_CYCLE_WRITE) { 204: 205: /* run the bus cycle: */ 206: cycle_resp.tme_bus_cycle_buffer = &buffer; 207: cycle_resp.tme_bus_cycle_lane_routing = tme_mk48txx_router; 208: cycle_resp.tme_bus_cycle_address = 0; 209: cycle_resp.tme_bus_cycle_buffer_increment = 1; 210: cycle_resp.tme_bus_cycle_type = TME_BUS_CYCLE_READ; 211: cycle_resp.tme_bus_cycle_size = sizeof(buffer); 212: cycle_resp.tme_bus_cycle_port = 213: TME_BUS_CYCLE_PORT(mk48txx->tme_mk48txx_port_least_lane, 214: TME_BUS8_LOG2); 215: tme_bus_cycle_xfer(cycle_init, &cycle_resp); 216: value = buffer; 217: 218: /* log this write: */ 219: tme_log(TME_MK48TXX_LOG_HANDLE(mk48txx), 100000, TME_OK, 220: (TME_MK48TXX_LOG_HANDLE(mk48txx), 221: "reg %d write %02x", 222: reg, value)); 223: 224: /* dispatch on the register: */ 225: switch (reg) { 226: 227: case TME_MK48TXX_REG_WDAY: 228: 229: /* flag that the time-of-day needs to be updated: */ 230: mk48txx->tme_mk48txx_tod_update = TRUE; 231: 232: /* update the register: */ 233: mk48txx->tme_mk48txx_regs[reg] = value; 234: break; 235: 236: case TME_MK48TXX_REG_HOUR: 237: case TME_MK48TXX_REG_MIN: 238: case TME_MK48TXX_REG_SEC: 239: case TME_MK48TXX_REG_MON: 240: case TME_MK48TXX_REG_DAY: 241: case TME_MK48TXX_REG_YEAR: 242: 243: /* flag that the time-of-day needs to be updated: */ 244: mk48txx->tme_mk48txx_tod_update = TRUE; 245: 246: /* update the register: */ 247: mk48txx->tme_mk48txx_regs[reg] = value; 248: break; 249: 250: case TME_MK48TXX_REG_CSR: 251: 252: /* update the CSR: */ 253: mk48txx->tme_mk48txx_regs[TME_MK48TXX_REG_CSR] = value; 254: 255: break; 256: 1.1.1.2 ! root 257: case TME_MK48TXX_REG_ADAY: ! 258: case TME_MK48TXX_REG_AHOUR: ! 259: case TME_MK48TXX_REG_AMIN: ! 260: case TME_MK48TXX_REG_ASEC: ! 261: case TME_MK48TXX_REG_WDOG: ! 262: case TME_MK48TXX_REG_INTR: ! 263: case TME_MK48TXX_REG_FLAGS: ! 264: ! 265: /* update the register: */ ! 266: mk48txx->tme_mk48txx_regs[reg] = value; ! 267: break; ! 268: 1.1 root 269: default: 270: /* ignore */ 271: break; 272: } 273: } 274: 275: /* otherwise, this is a read: */ 276: else { 277: assert(cycle_init->tme_bus_cycle_type == TME_BUS_CYCLE_READ); 278: 279: /* dispatch on the register: */ 280: switch (reg) { 281: 282: case TME_MK48TXX_REG_HOUR: 283: case TME_MK48TXX_REG_MIN: 284: case TME_MK48TXX_REG_SEC: 285: case TME_MK48TXX_REG_MON: 286: case TME_MK48TXX_REG_DAY: 287: case TME_MK48TXX_REG_YEAR: 288: case TME_MK48TXX_REG_WDAY: 1.1.1.2 ! root 289: case TME_MK48TXX_REG_ADAY: ! 290: case TME_MK48TXX_REG_AHOUR: ! 291: case TME_MK48TXX_REG_AMIN: ! 292: case TME_MK48TXX_REG_ASEC: ! 293: case TME_MK48TXX_REG_WDOG: ! 294: case TME_MK48TXX_REG_INTR: ! 295: case TME_MK48TXX_REG_FLAGS: 1.1 root 296: 297: /* read the register: */ 298: value = mk48txx->tme_mk48txx_regs[reg]; 299: break; 300: 301: case TME_MK48TXX_REG_CSR: 302: 303: /* read the register: */ 304: value = mk48txx->tme_mk48txx_regs[reg]; 305: break; 306: 307: /* undefined registers return garbage when read: */ 308: default: 309: value = 0xff; 310: break; 311: } 312: 313: /* log this read: */ 314: tme_log(TME_MK48TXX_LOG_HANDLE(mk48txx), 100000, TME_OK, 315: (TME_MK48TXX_LOG_HANDLE(mk48txx), 316: "reg %d read %02x", 317: reg, value)); 318: 319: /* run the bus cycle: */ 320: buffer = value; 321: cycle_resp.tme_bus_cycle_buffer = &buffer; 322: cycle_resp.tme_bus_cycle_lane_routing = tme_mk48txx_router; 323: cycle_resp.tme_bus_cycle_address = 0; 324: cycle_resp.tme_bus_cycle_buffer_increment = 1; 325: cycle_resp.tme_bus_cycle_type = TME_BUS_CYCLE_WRITE; 326: cycle_resp.tme_bus_cycle_size = sizeof(buffer); 327: cycle_resp.tme_bus_cycle_port = 328: TME_BUS_CYCLE_PORT(mk48txx->tme_mk48txx_port_least_lane, 329: TME_BUS8_LOG2); 330: tme_bus_cycle_xfer(cycle_init, &cycle_resp); 331: } 332: 333: /* if the time-of-day registers have been updated, and the clock 334: is running: */ 335: if (mk48txx->tme_mk48txx_tod_update 336: && ((mk48txx->tme_mk48txx_regs[TME_MK48TXX_REG_CSR] 337: & (TME_MK48TXX_CSR_READ 338: | TME_MK48TXX_CSR_WRITE)) == 0)) { 339: 340: /* XXX update the host's time-of-day clock? */ 341: mk48txx->tme_mk48txx_tod_update = FALSE; 342: } 343: 344: /* unlock the mutex: */ 345: tme_mutex_unlock(&mk48txx->tme_mk48txx_mutex); 346: 347: /* no faults: */ 348: return (TME_OK); 349: } 350: 351: /* the mk48txx TLB filler: */ 352: static int 353: _tme_mk48txx_tlb_fill(void *_mk48txx, struct tme_bus_tlb *tlb, 354: tme_bus_addr_t address, unsigned int cycles) 355: { 356: struct tme_mk48txx *mk48txx; 1.1.1.2 ! root 357: tme_bus_addr32_t mk48txx_address_last; 1.1 root 358: 359: /* recover our data structure: */ 360: mk48txx = (struct tme_mk48txx *) _mk48txx; 361: 362: /* the address must be within range: */ 363: mk48txx_address_last = mk48txx->tme_mk48txx_device.tme_bus_device_address_last; 364: assert(address <= mk48txx_address_last); 365: 366: /* initialize the TLB entry: */ 367: tme_bus_tlb_initialize(tlb); 368: 369: /* this TLB entry can cover the whole device: */ 370: tlb->tme_bus_tlb_addr_first = 0; 371: tlb->tme_bus_tlb_addr_last = mk48txx_address_last; 372: 373: /* allow reading and writing: */ 374: tlb->tme_bus_tlb_cycles_ok = TME_BUS_CYCLE_READ | TME_BUS_CYCLE_WRITE; 375: 376: /* our bus cycle handler: */ 377: tlb->tme_bus_tlb_cycle_private = mk48txx; 378: tlb->tme_bus_tlb_cycle = _tme_mk48txx_bus_cycle; 379: 380: return (TME_OK); 381: } 382: 383: /* the new mk48txx element function: */ 384: static int 385: _tme_mk48txx_new(struct tme_element *element, 386: const char * const *args, 387: const void *extra, 388: char **_output, 389: unsigned int part) 390: { 391: const struct tme_mk48txx_socket *socket; 392: struct tme_mk48txx *mk48txx; 393: struct tme_mk48txx_socket socket_real; 394: tme_bus_addr_t address_mask; 395: int arg_i; 396: int usage; 397: 398: /* dispatch on our socket version: */ 399: socket = (const struct tme_mk48txx_socket *) extra; 400: if (socket == NULL) { 401: tme_output_append_error(_output, _("need an ic socket")); 402: return (ENXIO); 403: } 404: switch (socket->tme_mk48txx_socket_version) { 405: case TME_MK48TXX_SOCKET_0: 406: socket_real = *socket; 407: break; 408: default: 409: tme_output_append_error(_output, _("socket type")); 410: return (EOPNOTSUPP); 411: } 412: 413: /* check our arguments: */ 414: usage = 0; 415: arg_i = 1; 416: for (;;) { 417: 418: if (0) { 419: } 420: 421: /* if we ran out of arguments: */ 422: else if (args[arg_i] == NULL) { 423: 424: break; 425: } 426: 427: /* otherwise this is a bad argument: */ 428: else { 429: tme_output_append_error(_output, 430: "%s %s, ", 431: args[arg_i], 432: _("unexpected")); 433: usage = TRUE; 434: break; 435: } 436: } 437: 438: if (usage) { 439: tme_output_append_error(_output, 440: "%s %s", 441: _("usage:"), 442: args[0]); 443: return (EINVAL); 444: } 445: 446: /* start the mk48txx structure: */ 447: mk48txx = tme_new0(struct tme_mk48txx, 1); 448: tme_mutex_init(&mk48txx->tme_mk48txx_mutex); 449: mk48txx->tme_mk48txx_part = part; 450: mk48txx->tme_mk48txx_socket = socket_real; 451: mk48txx->tme_mk48txx_element = element; 452: _tme_mk48txx_reset(mk48txx); 453: 454: /* figure our address mask, up to the nearest power of two: */ 455: address_mask = (TME_MK48TXX_REGS_COUNT - TME_MK48TXX_REG_FIRST(part)) << mk48txx->tme_mk48txx_addr_shift; 456: if (address_mask & (address_mask - 1)) { 457: for (; address_mask & (address_mask - 1); address_mask &= (address_mask - 1)); 458: address_mask <<= 1; 459: } 460: address_mask -= 1; 461: 462: /* initialize our simple bus device descriptor: */ 463: mk48txx->tme_mk48txx_device.tme_bus_device_tlb_fill = _tme_mk48txx_tlb_fill; 464: mk48txx->tme_mk48txx_device.tme_bus_device_address_last = address_mask; 465: 466: /* fill the element: */ 467: element->tme_element_private = mk48txx; 468: element->tme_element_connections_new = tme_bus_device_connections_new; 469: 470: return (TME_OK); 471: } 472: 473: TME_ELEMENT_X_NEW_DECL(tme_ic_,mk48txx,mk48t02) { 474: return (_tme_mk48txx_new(element, args, extra, _output, TME_MK48TXX_PART_02)); 475: } 1.1.1.2 ! root 476: ! 477: TME_ELEMENT_X_NEW_DECL(tme_ic_,mk48txx,mk48t59) { ! 478: return (_tme_mk48txx_new(element, args, extra, _output, TME_MK48TXX_PART_59)); ! 479: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.