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

1.1     ! root        1: /* $Id: ad184x.c,v 1.1 2009/06/17 22:41:30 fredette Exp $ */
        !             2: 
        !             3: /* ic/ad184x.c - Analog Devices 184x (and Crystal Semiconductors 4248
        !             4:    and 423x) implementation: */
        !             5: 
        !             6: /*
        !             7:  * Copyright (c) 2009 Matt Fredette
        !             8:  * All rights reserved.
        !             9:  *
        !            10:  * Redistribution and use in source and binary forms, with or without
        !            11:  * modification, are permitted provided that the following conditions
        !            12:  * are met:
        !            13:  * 1. Redistributions of source code must retain the above copyright
        !            14:  *    notice, this list of conditions and the following disclaimer.
        !            15:  * 2. Redistributions in binary form must reproduce the above copyright
        !            16:  *    notice, this list of conditions and the following disclaimer in the
        !            17:  *    documentation and/or other materials provided with the distribution.
        !            18:  * 3. All advertising materials mentioning features or use of this software
        !            19:  *    must display the following acknowledgement:
        !            20:  *      This product includes software developed by Matt Fredette.
        !            21:  * 4. The name of the author may not be used to endorse or promote products
        !            22:  *    derived from this software without specific prior written permission.
        !            23:  *
        !            24:  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
        !            25:  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
        !            26:  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
        !            27:  * DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
        !            28:  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
        !            29:  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
        !            30:  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
        !            31:  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
        !            32:  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
        !            33:  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
        !            34:  * POSSIBILITY OF SUCH DAMAGE.
        !            35:  */
        !            36: 
        !            37: #include <tme/common.h>
        !            38: _TME_RCSID("$Id: ad184x.c,v 1.1 2009/06/17 22:41:30 fredette Exp $");
        !            39: 
        !            40: /* includes: */
        !            41: #include <tme/completion.h>
        !            42: #include <tme/generic/bus-device.h>
        !            43: 
        !            44: /* macros: */
        !            45: 
        !            46: /* the different parts: */
        !            47: #define TME_AD184X_PART_AD1848                 (0)
        !            48: #define TME_AD184X_PART_CS4231                 (10)
        !            49: #define TME_AD184X_PART_CS4231A                        (11)
        !            50: 
        !            51: /* direct registers: */
        !            52: #define TME_AD184X_REG_IADDR                   (0)
        !            53: #define TME_AD184X_REG_IDATA                   (1)
        !            54: #define TME_AD184X_REG_STATUS                  (2)
        !            55: #define TME_AD184X_REG_PIO                     (3)
        !            56: #define TME_AD184X_SIZ                         (4)
        !            57: 
        !            58: /* the IADDR register: */
        !            59: #define TME_AD184X_IADDR_INIT                  (1 << 7)
        !            60: #define TME_AD184X_IADDR_MCE                   (1 << 6)
        !            61: #define TME_AD184X_IADDR_TRD                   (1 << 5)
        !            62: #define TME_AD184X_IADDR_IXA                   (0x0f)
        !            63: #define TME_CS423X_IADDR_IXA                   (0x1f)
        !            64: 
        !            65: /* inputs: */
        !            66: #define TME_AD184X_INPUT_MAIN                  (0)
        !            67: #define TME_AD184X_INPUT_AUX1                  (1)
        !            68: #define TME_AD184X_INPUT_AUX2                  (2)
        !            69: 
        !            70: /* channels: */
        !            71: #define TME_AD184X_CHANNEL_L                   (0)
        !            72: #define TME_AD184X_CHANNEL_R                   (1)
        !            73: #define TME_AD184X_CHANNEL_COUNT               (2)
        !            74: 
        !            75: /* the indirect registers: */
        !            76: #define TME_AD184X_IREG_INPUT(input, channel)  (((input) * 2) + (channel))
        !            77: #define TME_AD184X_IREG_OUTPUT(channel)                (6 + (channel))
        !            78: #define TME_AD184X_IREG_CLOCK_DATA             (8)
        !            79: #define TME_AD184X_IREG_INTERFACE              (9)
        !            80: #define TME_AD184X_IREG_PINCONTROL             (10)
        !            81: #define TME_AD184X_IREG_TEST_INIT              (11)
        !            82: #define TME_AD184X_IREG_MISC                   (12)
        !            83: #define TME_AD184X_IREG_DIGITALMIX             (13)
        !            84: #define TME_AD184X_IREG_BASECOUNT_UPPER                (14)
        !            85: #define TME_AD184X_IREG_BASECOUNT_LOWER                (15)
        !            86: #define TME_CS423X_IREG_VERSION_ID             (25)
        !            87: #define TME_CS423X_SIZ_IREG                    (32)
        !            88: 
        !            89: /* the MISC register: */
        !            90: #define TME_AD184X_MISC_CS423X_MODE2           (1 << 6)
        !            91: 
        !            92: #define TME_AD184X_LOG_HANDLE(ad184x) (&(ad184x)->tme_ad184x_element->tme_element_log_handle)
        !            93: 
        !            94: #define TME_AD184X_BUS_TRANSITION              (1)
        !            95: 
        !            96: /* structures: */
        !            97: 
        !            98: /* the device: */
        !            99: struct tme_ad184x {
        !           100: 
        !           101:   /* our simple bus device header: */
        !           102:   struct tme_bus_device tme_ad184x_device;
        !           103: #define tme_ad184x_element tme_ad184x_device.tme_bus_device_element
        !           104: 
        !           105:   /* the mutex: */
        !           106:   tme_mutex_t tme_ad184x_mutex;
        !           107: 
        !           108:   /* the part: */
        !           109:   unsigned int tme_ad184x_part;
        !           110: #define TME_AD184X_IS_AD184X(ad184x)   ((ad184x)->tme_ad184x_part < TME_AD184X_PART_CS4231)
        !           111: #define TME_AD184X_IS_CS423X(ad184x)   ((ad184x)->tme_ad184x_part >= TME_AD184X_PART_CS4231)
        !           112: #define TME_AD184X_IS_CS4231A(ad184x)  ((ad184x)->tme_ad184x_part == TME_AD184X_PART_CS4231A)
        !           113: 
        !           114:   /* the IADDR register: */
        !           115:   tme_uint8_t tme_ad184x_iaddr;
        !           116: 
        !           117:   /* the STATUS register: */
        !           118:   tme_uint8_t tme_ad184x_status;
        !           119: 
        !           120:   /* the indirect registers: */
        !           121:   tme_uint8_t tme_ad184x_ireg[TME_CS423X_SIZ_IREG];
        !           122: };
        !           123: 
        !           124: /* this resets: */
        !           125: static void
        !           126: _tme_ad184x_reset(struct tme_ad184x *ad184x)
        !           127: {
        !           128: }
        !           129: 
        !           130: /* this enters: */
        !           131: static struct tme_ad184x *
        !           132: _tme_ad184x_enter(struct tme_ad184x *ad184x)
        !           133: {
        !           134: 
        !           135:   /* lock the mutex: */
        !           136:   tme_mutex_lock(&ad184x->tme_ad184x_mutex);
        !           137: 
        !           138:   return (ad184x);
        !           139: }
        !           140: #define _tme_ad184x_enter_bus(conn_bus) \
        !           141:   ((struct tme_ad184x *) _tme_ad184x_enter((struct tme_ad184x *) (conn_bus)->tme_bus_connection.tme_connection_element->tme_element_private))
        !           142: 
        !           143: /* this leaves: */
        !           144: #define _tme_ad184x_leave(ad184x) tme_mutex_unlock(&(ad184x)->tme_ad184x_mutex)
        !           145: 
        !           146: /* this busies a generic bus connection: */
        !           147: #define _tme_ad184x_busy_bus(ad184x, conn_index) \
        !           148:   ((ad184x)->tme_ad184x_conns[conn_index])
        !           149: 
        !           150: /* this unbusies a generic bus connection: */
        !           151: #define _tme_ad184x_unbusy_bus(ad184x, conn_bus) \
        !           152:   do { } while (/* CONSTCOND */ 0 && (ad184x)->tme_ad184x_element && (conn_bus)->tme_bus_connection.tme_connection_element)
        !           153: 
        !           154: /* this returns the current indirect register: */
        !           155: static unsigned int
        !           156: _tme_ad184x_ireg(const struct tme_ad184x *ad184x)
        !           157: {
        !           158:   return (ad184x->tme_ad184x_iaddr
        !           159:          & ((TME_AD184X_IS_CS423X(ad184x)
        !           160:              && (ad184x->tme_ad184x_ireg[TME_AD184X_IREG_MISC]
        !           161:                  & TME_AD184X_MISC_CS423X_MODE2))
        !           162:             ? TME_CS423X_IADDR_IXA
        !           163:             : TME_AD184X_IADDR_IXA));
        !           164: }
        !           165: 
        !           166: /* the bus cycle handler: */
        !           167: static void
        !           168: _tme_ad184x_cycle(struct tme_bus_connection *master_conn_bus,
        !           169:                  struct tme_bus_cycle *master_cycle,
        !           170:                  tme_uint32_t *_master_fast_cycle_types,
        !           171:                  struct tme_completion *master_completion)
        !           172: {
        !           173:   struct tme_ad184x *ad184x;
        !           174:   tme_uint32_t address;
        !           175:   tme_uint8_t value;
        !           176:   const char *reg;
        !           177:   tme_uint32_t ireg;
        !           178: 
        !           179:   /* enter: */
        !           180:   ad184x = _tme_ad184x_enter_bus(master_conn_bus);
        !           181: 
        !           182:   /* this must be an eight-bit cycle: */
        !           183:   if (master_cycle->tme_bus_cycle_size != sizeof(tme_uint8_t)) {
        !           184:     abort();
        !           185:   }
        !           186: 
        !           187:   /* get the address: */
        !           188:   address = master_cycle->tme_bus_cycle_address;
        !           189: 
        !           190:   /* if this is a write: */
        !           191:   if (master_cycle->tme_bus_cycle_type == TME_BUS_CYCLE_WRITE) {
        !           192: 
        !           193:     /* run the bus cycle: */
        !           194:     tme_bus_cycle_xfer_reg(master_cycle, 
        !           195:                           &value,
        !           196:                           TME_BUS8_LOG2);
        !           197: 
        !           198:     /* dispatch on the register: */
        !           199:     switch (address) {
        !           200:     default: assert(FALSE);
        !           201: 
        !           202:     case TME_AD184X_REG_IADDR:
        !           203:       ad184x->tme_ad184x_iaddr
        !           204:        = ((ad184x->tme_ad184x_iaddr
        !           205:            & TME_AD184X_IADDR_INIT)
        !           206:           | (value
        !           207:              & ~TME_AD184X_IADDR_INIT));
        !           208:       reg = "IADDR";
        !           209:       break;
        !           210: 
        !           211:     case TME_AD184X_REG_IDATA:
        !           212:       ireg = _tme_ad184x_ireg(ad184x);
        !           213:       reg = "(IDATA)";
        !           214: 
        !           215:       /* if this is an input or output control: */
        !           216:       if (ireg <= TME_AD184X_IREG_OUTPUT(TME_AD184X_CHANNEL_COUNT - 1)) {
        !           217: 
        !           218:        /* write the new control: */
        !           219:        ad184x->tme_ad184x_ireg[ireg] = value;
        !           220:       }
        !           221: 
        !           222:       /* otherwise, this is another register: */
        !           223:       else {
        !           224:        switch (ireg) {
        !           225: 
        !           226:        default: 
        !           227:          /* temporarily, just write any unknown registers: */
        !           228:          ad184x->tme_ad184x_ireg[ireg] = value;
        !           229:          break;
        !           230:        }
        !           231:       }
        !           232:       break;
        !           233: 
        !           234:     case TME_AD184X_REG_STATUS:
        !           235:       reg = "STATUS";
        !           236:       break;
        !           237: 
        !           238:     case TME_AD184X_REG_PIO:
        !           239:       reg = "PIO";
        !           240:       break;
        !           241:     }
        !           242: 
        !           243:     tme_log(TME_AD184X_LOG_HANDLE(ad184x), 1000, TME_OK,
        !           244:            (TME_AD184X_LOG_HANDLE(ad184x),
        !           245:             _("%s <- 0x%02x"),
        !           246:             reg,
        !           247:             value));
        !           248:   }
        !           249: 
        !           250:   /* otherwise, this must be a read: */
        !           251:   else {
        !           252:     assert (master_cycle->tme_bus_cycle_type == TME_BUS_CYCLE_READ);
        !           253: 
        !           254:     /* dispatch on the register: */
        !           255:     switch (address) {
        !           256:     default: assert(FALSE);
        !           257: 
        !           258:     case TME_AD184X_REG_IADDR:
        !           259:       value = ad184x->tme_ad184x_iaddr;
        !           260:       reg = "IADDR";
        !           261:       break;
        !           262: 
        !           263:     case TME_AD184X_REG_IDATA:
        !           264:       ireg = _tme_ad184x_ireg(ad184x);
        !           265:       reg = "(IDATA)";
        !           266: 
        !           267:       /* assume that this is a simple read: */
        !           268:       value = ad184x->tme_ad184x_ireg[ireg];
        !           269: 
        !           270:       switch (ireg) {
        !           271:       default: 
        !           272:        break;
        !           273:       case TME_CS423X_IREG_VERSION_ID:
        !           274:        value = 0xa0;
        !           275:        reg = "VERSION_ID";
        !           276:        break;
        !           277:       }
        !           278:       break;
        !           279: 
        !           280:     case TME_AD184X_REG_STATUS:
        !           281:       value = ad184x->tme_ad184x_status;
        !           282:       reg = "STATUS";
        !           283:       break;
        !           284: 
        !           285:     case TME_AD184X_REG_PIO:
        !           286:       abort();
        !           287:       reg = "PIO";
        !           288:       break;
        !           289:     }
        !           290: 
        !           291:     /* run the bus cycle: */
        !           292:     tme_bus_cycle_xfer_reg(master_cycle, 
        !           293:                           &value,
        !           294:                           TME_BUS8_LOG2);
        !           295: 
        !           296:     tme_log(TME_AD184X_LOG_HANDLE(ad184x), 1000, TME_OK,
        !           297:            (TME_AD184X_LOG_HANDLE(ad184x),
        !           298:             _("%s -> 0x%02x"),
        !           299:             reg,
        !           300:             value));
        !           301:   }
        !           302: 
        !           303:   /* complete the cycle: */
        !           304:   master_completion->tme_completion_error = TME_OK;
        !           305:   tme_memory_barrier(master_completion, sizeof(*master_completion), TME_MEMORY_BARRIER_WRITE_BEFORE_WRITE);
        !           306:   tme_completion_validate(master_completion);
        !           307:   *_master_fast_cycle_types = 0;
        !           308: 
        !           309:   /* leave: */
        !           310:   _tme_ad184x_leave(ad184x);
        !           311: }
        !           312: 
        !           313: /* this fills a TLB entry: */
        !           314: static void
        !           315: _tme_ad184x_tlb_fill(struct tme_bus_connection *agent_conn_bus,
        !           316:                     struct tme_bus_tlb *tlb,
        !           317:                     tme_bus_addr_t address_wider,
        !           318:                     unsigned int cycle_type)
        !           319: {
        !           320: 
        !           321:   /* initialize the TLB entry: */
        !           322:   tme_bus_tlb_initialize(tlb);
        !           323: 
        !           324:   /* this TLB entry covers only this address: */
        !           325:   tlb->tme_bus_tlb_addr_first = address_wider;
        !           326:   tlb->tme_bus_tlb_addr_last = address_wider;
        !           327: }
        !           328: 
        !           329: #if TME_AD184X_BUS_TRANSITION
        !           330: 
        !           331: /* this is the bus cycle transition glue: */
        !           332: static int
        !           333: _tme_ad184x_cycle_transition(void *_master_conn_bus,
        !           334:                             struct tme_bus_cycle *master_cycle)
        !           335: {
        !           336:   struct tme_completion completion_buffer;
        !           337:   struct tme_ad184x *ad184x;
        !           338:   struct tme_bus_connection *master_conn_bus;
        !           339:   tme_uint32_t master_fast_cycle_types;
        !           340: 
        !           341:   tme_completion_init(&completion_buffer);
        !           342: 
        !           343:   master_conn_bus = (struct tme_bus_connection *) _master_conn_bus;
        !           344:   ad184x = (struct tme_ad184x *) master_conn_bus->tme_bus_connection.tme_connection_element->tme_element_private;
        !           345:   _tme_ad184x_cycle(master_conn_bus,
        !           346:                    master_cycle,
        !           347:                    &master_fast_cycle_types,
        !           348:                    &completion_buffer);
        !           349:   return (completion_buffer.tme_completion_error);
        !           350: }
        !           351: 
        !           352: /* this is the TLB fill transition glue: */
        !           353: static int
        !           354: _tme_ad184x_tlb_fill_transition(void *_ad184x,
        !           355:                                struct tme_bus_tlb *tlb,
        !           356:                                tme_bus_addr_t address_wider,
        !           357:                                unsigned int cycle_type)
        !           358: {
        !           359:   struct tme_ad184x *ad184x;
        !           360:   struct tme_bus_connection *agent_conn_bus;
        !           361: 
        !           362:   ad184x = (struct tme_ad184x *) _ad184x;
        !           363:   agent_conn_bus = (struct tme_bus_connection *) ad184x->tme_ad184x_device.tme_bus_device_connection->tme_bus_connection.tme_connection_other;
        !           364: 
        !           365:   _tme_ad184x_tlb_fill(agent_conn_bus,
        !           366:                       tlb,
        !           367:                       address_wider,
        !           368:                       cycle_type);
        !           369: 
        !           370:   /* we always handle any slow cycles: */
        !           371:   tlb->tme_bus_tlb_cycles_ok |= cycle_type;
        !           372:   tlb->tme_bus_tlb_addr_offset = 0;
        !           373:   tlb->tme_bus_tlb_addr_shift = 0;
        !           374:   tlb->tme_bus_tlb_cycle = _tme_ad184x_cycle_transition;
        !           375:   tlb->tme_bus_tlb_cycle_private = agent_conn_bus;
        !           376:   assert (tlb->tme_bus_tlb_fault_handler_count == 0);
        !           377: 
        !           378:   return (TME_OK);
        !           379: }
        !           380: #define _tme_ad184x_tlb_fill _tme_ad184x_tlb_fill_transition
        !           381: 
        !           382: #endif /* TME_AD184X_BUS_TRANSITION */
        !           383: 
        !           384: /* the new ad184x function: */
        !           385: static int
        !           386: _tme_ad184x_new(struct tme_element *element,
        !           387:                const char * const *args,
        !           388:                const void *extra,
        !           389:                char **_output,
        !           390:                unsigned int part)
        !           391: {
        !           392:   struct tme_ad184x *ad184x;
        !           393:   int arg_i;
        !           394:   int usage;
        !           395:   const char *type;
        !           396: 
        !           397:   /* check our arguments: */
        !           398:   usage = 0;
        !           399:   arg_i = 1;
        !           400:   type = NULL;
        !           401:   for (;;) {
        !           402: 
        !           403:     if (0) {
        !           404:     }
        !           405: 
        !           406:     /* if we ran out of arguments: */
        !           407:     else if (args[arg_i] == NULL) {
        !           408: 
        !           409:       break;
        !           410:     }
        !           411: 
        !           412:     /* otherwise this is a bad argument: */
        !           413:     else {
        !           414:       tme_output_append_error(_output,
        !           415:                              "%s %s, ",
        !           416:                              args[arg_i],
        !           417:                              _("unexpected"));
        !           418:       usage = TRUE;
        !           419:       break;
        !           420:     }
        !           421:   }
        !           422: 
        !           423:   if (usage) {
        !           424:     tme_output_append_error(_output, 
        !           425:                            "%s %s",
        !           426:                            _("usage:"),
        !           427:                            args[0]);
        !           428:     return (EINVAL);
        !           429:   }
        !           430: 
        !           431:   /* start the ad184x structure: */
        !           432:   ad184x = tme_new0(struct tme_ad184x, 1);
        !           433:   tme_mutex_init(&ad184x->tme_ad184x_mutex);
        !           434:   ad184x->tme_ad184x_part = part;
        !           435:   ad184x->tme_ad184x_element = element;
        !           436:   _tme_ad184x_reset(ad184x);
        !           437: 
        !           438:   /* initialize our simple bus device descriptor: */
        !           439:   ad184x->tme_ad184x_device.tme_bus_device_tlb_fill = _tme_ad184x_tlb_fill;
        !           440:   ad184x->tme_ad184x_device.tme_bus_device_address_last = TME_AD184X_SIZ - 1;
        !           441: 
        !           442:   /* fill the element: */
        !           443:   element->tme_element_private = ad184x;
        !           444:   element->tme_element_connections_new = tme_bus_device_connections_new;
        !           445: 
        !           446:   return (TME_OK);
        !           447: }
        !           448: 
        !           449: TME_ELEMENT_X_NEW_DECL(tme_ic_,ad184x,cs4231A) {
        !           450:   return (_tme_ad184x_new(element, args, extra, _output, TME_AD184X_PART_CS4231A));
        !           451: }

unix.superglobalmegacorp.com

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