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