|
|
1.1 ! root 1: /* $Id: mm58167.c,v 1.4 2003/05/16 21:48:10 fredette Exp $ */ ! 2: ! 3: /* ic/ic-vol0/mm58167.c - implementation of National Semiconductor MM58167 emulation: */ ! 4: ! 5: /* ! 6: * Copyright (c) 2003 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: mm58167.c,v 1.4 2003/05/16 21:48:10 fredette Exp $"); ! 38: ! 39: /* includes: */ ! 40: #include <tme/generic/bus-device.h> ! 41: #include <tme/ic/mm58167.h> ! 42: #include <time.h> ! 43: ! 44: /* macros: */ ! 45: ! 46: /* register addresses: */ ! 47: #define TME_MM58167_REG_MSEC_XXX (0) ! 48: #define TME_MM58167_REG_CSEC (1) ! 49: #define TME_MM58167_REG_SEC (2) ! 50: #define TME_MM58167_REG_MIN (3) ! 51: #define TME_MM58167_REG_HOUR (4) ! 52: #define TME_MM58167_REG_WDAY (5) ! 53: #define TME_MM58167_REG_DAY (6) ! 54: #define TME_MM58167_REG_MON (7) ! 55: #define TME_MM58167_REG_STATUS (20) ! 56: #define TME_MM58167_REG_GO (21) ! 57: #define TME_MM58167_REG_BANK_SZ (24) ! 58: ! 59: /* bits in the status register: */ ! 60: #define TME_MM58167_STATUS_RIPPLING TME_BIT(0) ! 61: ! 62: #define TME_MM58167_LOG_HANDLE(mm) (&(mm)->tme_mm58167_element->tme_element_log_handle) ! 63: ! 64: /* structures: */ ! 65: ! 66: struct tme_mm58167 { ! 67: ! 68: /* our simple bus device header: */ ! 69: struct tme_bus_device tme_mm58167_device; ! 70: #define tme_mm58167_element tme_mm58167_device.tme_bus_device_element ! 71: ! 72: /* our socket: */ ! 73: struct tme_mm58167_socket tme_mm58167_socket; ! 74: #define tme_mm58167_addr_shift tme_mm58167_socket.tme_mm58167_socket_addr_shift ! 75: #define tme_mm58167_port_least_lane tme_mm58167_socket.tme_mm58167_socket_port_least_lane ! 76: ! 77: /* the mutex protecting the chip: */ ! 78: tme_mutex_t tme_mm58167_mutex; ! 79: ! 80: /* the last time sampled: */ ! 81: time_t tme_mm58167_sampled_time; ! 82: ! 83: /* the struct tm for the last time sampled: */ ! 84: struct tm tme_mm58167_sampled_tm; ! 85: ! 86: /* the status register: */ ! 87: tme_uint8_t tme_mm58167_status; ! 88: }; ! 89: ! 90: /* the mm58167 bus router: */ ! 91: static const tme_bus_lane_t tme_mm58167_router[TME_BUS_ROUTER_SIZE(TME_BUS8_LOG2)] = { ! 92: ! 93: /* [gen] initiator port size: 8 bits ! 94: [gen] initiator port least lane: 0: */ ! 95: /* D7-D0 */ TME_BUS_LANE_ROUTE(0), ! 96: }; ! 97: ! 98: /* the mm58167 bus cycle handler: */ ! 99: static int ! 100: _tme_mm58167_bus_cycle(void *_mm58167, struct tme_bus_cycle *cycle_init) ! 101: { ! 102: struct tme_mm58167 *mm58167; ! 103: tme_bus_addr_t address, mm58167_address_last; ! 104: tme_uint8_t buffer, value; ! 105: struct tme_bus_cycle cycle_resp; ! 106: unsigned int reg; ! 107: time_t now; ! 108: struct tm *now_tm; ! 109: int reg_is_bcd; ! 110: ! 111: /* recover our data structure: */ ! 112: mm58167 = (struct tme_mm58167 *) _mm58167; ! 113: ! 114: /* the requested cycle must be within range: */ ! 115: mm58167_address_last = mm58167->tme_mm58167_device.tme_bus_device_address_last; ! 116: assert(cycle_init->tme_bus_cycle_address <= mm58167_address_last); ! 117: assert(cycle_init->tme_bus_cycle_size <= (mm58167_address_last - cycle_init->tme_bus_cycle_address) + 1); ! 118: ! 119: /* get the register being accessed: */ ! 120: address = cycle_init->tme_bus_cycle_address; ! 121: reg = address >> mm58167->tme_mm58167_addr_shift; ! 122: reg_is_bcd = (reg <= TME_MM58167_REG_MON); ! 123: ! 124: /* lock the mutex: */ ! 125: tme_mutex_lock(&mm58167->tme_mm58167_mutex); ! 126: ! 127: /* sample the time. if it's changed, update our status: */ ! 128: now = time(NULL); ! 129: if (now == mm58167->tme_mm58167_sampled_time) { ! 130: now_tm = &mm58167->tme_mm58167_sampled_tm; ! 131: } ! 132: else { ! 133: mm58167->tme_mm58167_status |= TME_MM58167_STATUS_RIPPLING; ! 134: mm58167->tme_mm58167_sampled_time = now; ! 135: now_tm = gmtime_r(&now, &mm58167->tme_mm58167_sampled_tm); ! 136: if (now_tm != &mm58167->tme_mm58167_sampled_tm) { ! 137: mm58167->tme_mm58167_sampled_tm = *now_tm; ! 138: } ! 139: } ! 140: ! 141: /* if this is a write: */ ! 142: if (cycle_init->tme_bus_cycle_type == TME_BUS_CYCLE_WRITE) { ! 143: ! 144: /* run the bus cycle: */ ! 145: cycle_resp.tme_bus_cycle_buffer = &buffer; ! 146: cycle_resp.tme_bus_cycle_lane_routing = tme_mm58167_router; ! 147: cycle_resp.tme_bus_cycle_address = 0; ! 148: cycle_resp.tme_bus_cycle_buffer_increment = 1; ! 149: cycle_resp.tme_bus_cycle_type = TME_BUS_CYCLE_READ; ! 150: cycle_resp.tme_bus_cycle_size = sizeof(buffer); ! 151: cycle_resp.tme_bus_cycle_port = ! 152: TME_BUS_CYCLE_PORT(mm58167->tme_mm58167_port_least_lane, ! 153: TME_BUS8_LOG2); ! 154: tme_bus_cycle_xfer(cycle_init, &cycle_resp); ! 155: value = buffer; ! 156: ! 157: /* log this write: */ ! 158: tme_log(TME_MM58167_LOG_HANDLE(mm58167), 100000, TME_OK, ! 159: (TME_MM58167_LOG_HANDLE(mm58167), ! 160: "reg %d write %02x", ! 161: reg, value)); ! 162: ! 163: /* otherwise, ignore writes for now: */ ! 164: } ! 165: ! 166: ! 167: /* otherwise, this is a read: */ ! 168: else { ! 169: assert(cycle_init->tme_bus_cycle_type == TME_BUS_CYCLE_READ); ! 170: ! 171: /* dispatch on the register: */ ! 172: switch (reg) { ! 173: case TME_MM58167_REG_MSEC_XXX: ! 174: case TME_MM58167_REG_CSEC: ! 175: value = 0; ! 176: break; ! 177: case TME_MM58167_REG_SEC: ! 178: value = now_tm->tm_sec; ! 179: break; ! 180: case TME_MM58167_REG_MIN: ! 181: value = now_tm->tm_min; ! 182: break; ! 183: case TME_MM58167_REG_HOUR: ! 184: value = now_tm->tm_hour; ! 185: break; ! 186: case TME_MM58167_REG_WDAY: ! 187: value = now_tm->tm_wday; ! 188: break; ! 189: case TME_MM58167_REG_DAY: ! 190: value = now_tm->tm_mday; ! 191: break; ! 192: case TME_MM58167_REG_MON: ! 193: value = now_tm->tm_mon + 1; ! 194: break; ! 195: case TME_MM58167_REG_STATUS: ! 196: value = mm58167->tme_mm58167_status; ! 197: mm58167->tme_mm58167_status = 0; ! 198: break; ! 199: default: ! 200: abort(); ! 201: } ! 202: ! 203: /* if needed, convert this value to BCD: */ ! 204: if (reg_is_bcd) { ! 205: value = (value % 10) + ((value / 10) << 4); ! 206: } ! 207: ! 208: /* log this read: */ ! 209: tme_log(TME_MM58167_LOG_HANDLE(mm58167), 100000, TME_OK, ! 210: (TME_MM58167_LOG_HANDLE(mm58167), ! 211: "reg %d read %02x", ! 212: reg, value)); ! 213: ! 214: /* run the bus cycle: */ ! 215: buffer = value; ! 216: cycle_resp.tme_bus_cycle_buffer = &buffer; ! 217: cycle_resp.tme_bus_cycle_lane_routing = tme_mm58167_router; ! 218: cycle_resp.tme_bus_cycle_address = 0; ! 219: cycle_resp.tme_bus_cycle_buffer_increment = 1; ! 220: cycle_resp.tme_bus_cycle_type = TME_BUS_CYCLE_WRITE; ! 221: cycle_resp.tme_bus_cycle_size = sizeof(buffer); ! 222: cycle_resp.tme_bus_cycle_port = ! 223: TME_BUS_CYCLE_PORT(mm58167->tme_mm58167_port_least_lane, ! 224: TME_BUS8_LOG2); ! 225: tme_bus_cycle_xfer(cycle_init, &cycle_resp); ! 226: } ! 227: ! 228: /* unlock the mutex: */ ! 229: tme_mutex_unlock(&mm58167->tme_mm58167_mutex); ! 230: ! 231: /* no faults: */ ! 232: return (TME_OK); ! 233: } ! 234: ! 235: /* the mm58167 TLB filler: */ ! 236: static int ! 237: _tme_mm58167_tlb_fill(void *_mm58167, struct tme_bus_tlb *tlb, ! 238: tme_bus_addr_t address, unsigned int cycles) ! 239: { ! 240: struct tme_mm58167 *mm58167; ! 241: tme_bus_addr_t mm58167_address_last; ! 242: ! 243: /* recover our data structure: */ ! 244: mm58167 = (struct tme_mm58167 *) _mm58167; ! 245: ! 246: /* the address must be within range: */ ! 247: mm58167_address_last = mm58167->tme_mm58167_device.tme_bus_device_address_last; ! 248: assert(address <= mm58167_address_last); ! 249: ! 250: /* initialize the TLB entry: */ ! 251: tme_bus_tlb_initialize(tlb); ! 252: ! 253: /* this TLB entry can cover the whole device: */ ! 254: TME_ATOMIC_WRITE(tme_bus_addr_t, tlb->tme_bus_tlb_addr_first, 0); ! 255: TME_ATOMIC_WRITE(tme_bus_addr_t, tlb->tme_bus_tlb_addr_last, mm58167_address_last); ! 256: ! 257: /* allow reading and writing: */ ! 258: tlb->tme_bus_tlb_cycles_ok = TME_BUS_CYCLE_READ | TME_BUS_CYCLE_WRITE; ! 259: ! 260: /* our bus cycle handler: */ ! 261: tlb->tme_bus_tlb_cycle_private = mm58167; ! 262: tlb->tme_bus_tlb_cycle = _tme_mm58167_bus_cycle; ! 263: ! 264: return (TME_OK); ! 265: } ! 266: ! 267: /* the new mm58167 function: */ ! 268: TME_ELEMENT_NEW_DECL(tme_ic_mm58167) { ! 269: const struct tme_mm58167_socket *socket; ! 270: struct tme_mm58167 *mm58167; ! 271: struct tme_mm58167_socket socket_real; ! 272: tme_bus_addr_t address_mask; ! 273: ! 274: /* dispatch on our socket version: */ ! 275: socket = (const struct tme_mm58167_socket *) extra; ! 276: if (socket == NULL) { ! 277: tme_output_append_error(_output, _("need an ic socket")); ! 278: return (ENXIO); ! 279: } ! 280: switch (socket->tme_mm58167_socket_version) { ! 281: case TME_MM58167_SOCKET_0: ! 282: socket_real = *socket; ! 283: break; ! 284: default: ! 285: tme_output_append_error(_output, _("socket type")); ! 286: return (EOPNOTSUPP); ! 287: } ! 288: ! 289: /* we take no arguments: */ ! 290: if (args[1] != NULL) { ! 291: tme_output_append_error(_output, ! 292: "%s %s, %s %s", ! 293: args[1], ! 294: _("unexpected"), ! 295: _("usage:"), ! 296: args[0]); ! 297: return (EINVAL); ! 298: } ! 299: ! 300: /* start the mm58167 structure: */ ! 301: mm58167 = tme_new0(struct tme_mm58167, 1); ! 302: tme_mutex_init(&mm58167->tme_mm58167_mutex); ! 303: mm58167->tme_mm58167_socket = socket_real; ! 304: ! 305: /* figure our address mask, up to the nearest power of two: */ ! 306: address_mask = TME_MM58167_REG_BANK_SZ * mm58167->tme_mm58167_addr_shift; ! 307: if (address_mask & (address_mask - 1)) { ! 308: for (; address_mask & (address_mask - 1); address_mask &= (address_mask - 1)); ! 309: address_mask <<= 1; ! 310: } ! 311: address_mask -= 1; ! 312: ! 313: /* initialize our simple bus device descriptor: */ ! 314: mm58167->tme_mm58167_device.tme_bus_device_element = element; ! 315: mm58167->tme_mm58167_device.tme_bus_device_tlb_fill = _tme_mm58167_tlb_fill; ! 316: mm58167->tme_mm58167_device.tme_bus_device_address_last = address_mask; ! 317: ! 318: /* fill the element: */ ! 319: element->tme_element_private = mm58167; ! 320: element->tme_element_connections_new = tme_bus_device_connections_new; ! 321: ! 322: return (TME_OK); ! 323: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.