Annotation of tme/ic/isil7170.c, revision 1.1.1.3

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: }

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.