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

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

unix.superglobalmegacorp.com

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