Annotation of qemu/hw/sh_serial.c, revision 1.1.1.6

1.1       root        1: /*
                      2:  * QEMU SCI/SCIF serial port emulation
                      3:  *
                      4:  * Copyright (c) 2007 Magnus Damm
                      5:  *
                      6:  * Based on serial.c - QEMU 16450 UART emulation
                      7:  * Copyright (c) 2003-2004 Fabrice Bellard
                      8:  *
                      9:  * Permission is hereby granted, free of charge, to any person obtaining a copy
                     10:  * of this software and associated documentation files (the "Software"), to deal
                     11:  * in the Software without restriction, including without limitation the rights
                     12:  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
                     13:  * copies of the Software, and to permit persons to whom the Software is
                     14:  * furnished to do so, subject to the following conditions:
                     15:  *
                     16:  * The above copyright notice and this permission notice shall be included in
                     17:  * all copies or substantial portions of the Software.
                     18:  *
                     19:  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
                     20:  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
                     21:  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
                     22:  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
                     23:  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
                     24:  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
                     25:  * THE SOFTWARE.
                     26:  */
                     27: #include "hw.h"
                     28: #include "sh.h"
                     29: #include "qemu-char.h"
                     30: 
                     31: //#define DEBUG_SERIAL
                     32: 
                     33: #define SH_SERIAL_FLAG_TEND (1 << 0)
                     34: #define SH_SERIAL_FLAG_TDE  (1 << 1)
                     35: #define SH_SERIAL_FLAG_RDF  (1 << 2)
                     36: #define SH_SERIAL_FLAG_BRK  (1 << 3)
                     37: #define SH_SERIAL_FLAG_DR   (1 << 4)
                     38: 
1.1.1.2   root       39: #define SH_RX_FIFO_LENGTH (16)
                     40: 
1.1       root       41: typedef struct {
                     42:     uint8_t smr;
                     43:     uint8_t brr;
                     44:     uint8_t scr;
                     45:     uint8_t dr; /* ftdr / tdr */
                     46:     uint8_t sr; /* fsr / ssr */
                     47:     uint16_t fcr;
                     48:     uint8_t sptr;
                     49: 
1.1.1.2   root       50:     uint8_t rx_fifo[SH_RX_FIFO_LENGTH]; /* frdr / rdr */
1.1       root       51:     uint8_t rx_cnt;
1.1.1.2   root       52:     uint8_t rx_tail;
                     53:     uint8_t rx_head;
1.1       root       54: 
                     55:     int freq;
                     56:     int feat;
                     57:     int flags;
1.1.1.2   root       58:     int rtrg;
1.1       root       59: 
                     60:     CharDriverState *chr;
1.1.1.2   root       61: 
                     62:     qemu_irq eri;
                     63:     qemu_irq rxi;
                     64:     qemu_irq txi;
                     65:     qemu_irq tei;
                     66:     qemu_irq bri;
1.1       root       67: } sh_serial_state;
                     68: 
1.1.1.2   root       69: static void sh_serial_clear_fifo(sh_serial_state * s)
                     70: {
                     71:     memset(s->rx_fifo, 0, SH_RX_FIFO_LENGTH);
                     72:     s->rx_cnt = 0;
                     73:     s->rx_head = 0;
                     74:     s->rx_tail = 0;
                     75: }
                     76: 
1.1.1.6 ! root       77: static void sh_serial_write(void *opaque, uint32_t offs, uint32_t val)
1.1       root       78: {
                     79:     sh_serial_state *s = opaque;
                     80:     unsigned char ch;
                     81: 
                     82: #ifdef DEBUG_SERIAL
1.1.1.2   root       83:     printf("sh_serial: write offs=0x%02x val=0x%02x\n",
                     84:           offs, val);
1.1       root       85: #endif
                     86:     switch(offs) {
                     87:     case 0x00: /* SMR */
                     88:         s->smr = val & ((s->feat & SH_SERIAL_FEAT_SCIF) ? 0x7b : 0xff);
                     89:         return;
                     90:     case 0x04: /* BRR */
                     91:         s->brr = val;
                     92:        return;
                     93:     case 0x08: /* SCR */
1.1.1.2   root       94:         /* TODO : For SH7751, SCIF mask should be 0xfb. */
                     95:         s->scr = val & ((s->feat & SH_SERIAL_FEAT_SCIF) ? 0xfa : 0xff);
1.1       root       96:         if (!(val & (1 << 5)))
                     97:             s->flags |= SH_SERIAL_FLAG_TEND;
1.1.1.2   root       98:         if ((s->feat & SH_SERIAL_FEAT_SCIF) && s->txi) {
                     99:            qemu_set_irq(s->txi, val & (1 << 7));
                    100:         }
                    101:         if (!(val & (1 << 6))) {
                    102:            qemu_set_irq(s->rxi, 0);
                    103:         }
1.1       root      104:         return;
                    105:     case 0x0c: /* FTDR / TDR */
                    106:         if (s->chr) {
                    107:             ch = val;
                    108:             qemu_chr_write(s->chr, &ch, 1);
                    109:        }
                    110:        s->dr = val;
                    111:        s->flags &= ~SH_SERIAL_FLAG_TDE;
                    112:         return;
                    113: #if 0
                    114:     case 0x14: /* FRDR / RDR */
                    115:         ret = 0;
                    116:         break;
                    117: #endif
                    118:     }
                    119:     if (s->feat & SH_SERIAL_FEAT_SCIF) {
                    120:         switch(offs) {
                    121:         case 0x10: /* FSR */
                    122:             if (!(val & (1 << 6)))
                    123:                 s->flags &= ~SH_SERIAL_FLAG_TEND;
                    124:             if (!(val & (1 << 5)))
                    125:                 s->flags &= ~SH_SERIAL_FLAG_TDE;
                    126:             if (!(val & (1 << 4)))
                    127:                 s->flags &= ~SH_SERIAL_FLAG_BRK;
                    128:             if (!(val & (1 << 1)))
                    129:                 s->flags &= ~SH_SERIAL_FLAG_RDF;
                    130:             if (!(val & (1 << 0)))
                    131:                 s->flags &= ~SH_SERIAL_FLAG_DR;
1.1.1.2   root      132: 
                    133:             if (!(val & (1 << 1)) || !(val & (1 << 0))) {
                    134:                 if (s->rxi) {
                    135:                     qemu_set_irq(s->rxi, 0);
                    136:                 }
                    137:             }
1.1       root      138:             return;
                    139:         case 0x18: /* FCR */
                    140:             s->fcr = val;
1.1.1.2   root      141:             switch ((val >> 6) & 3) {
                    142:             case 0:
                    143:                 s->rtrg = 1;
                    144:                 break;
                    145:             case 1:
                    146:                 s->rtrg = 4;
                    147:                 break;
                    148:             case 2:
                    149:                 s->rtrg = 8;
                    150:                 break;
                    151:             case 3:
                    152:                 s->rtrg = 14;
                    153:                 break;
                    154:             }
                    155:             if (val & (1 << 1)) {
                    156:                 sh_serial_clear_fifo(s);
                    157:                 s->sr &= ~(1 << 1);
                    158:             }
                    159: 
1.1       root      160:             return;
                    161:         case 0x20: /* SPTR */
1.1.1.2   root      162:             s->sptr = val & 0xf3;
1.1       root      163:             return;
                    164:         case 0x24: /* LSR */
                    165:             return;
                    166:         }
                    167:     }
                    168:     else {
                    169:         switch(offs) {
1.1.1.2   root      170: #if 0
1.1       root      171:         case 0x0c:
                    172:             ret = s->dr;
                    173:             break;
                    174:         case 0x10:
                    175:             ret = 0;
                    176:             break;
1.1.1.2   root      177: #endif
1.1       root      178:         case 0x1c:
1.1.1.2   root      179:             s->sptr = val & 0x8f;
                    180:             return;
1.1       root      181:         }
                    182:     }
                    183: 
                    184:     fprintf(stderr, "sh_serial: unsupported write to 0x%02x\n", offs);
1.1.1.5   root      185:     abort();
1.1       root      186: }
                    187: 
1.1.1.6 ! root      188: static uint32_t sh_serial_read(void *opaque, uint32_t offs)
1.1       root      189: {
                    190:     sh_serial_state *s = opaque;
                    191:     uint32_t ret = ~0;
                    192: 
                    193: #if 0
                    194:     switch(offs) {
                    195:     case 0x00:
                    196:         ret = s->smr;
                    197:         break;
                    198:     case 0x04:
                    199:         ret = s->brr;
                    200:        break;
                    201:     case 0x08:
                    202:         ret = s->scr;
                    203:         break;
                    204:     case 0x14:
                    205:         ret = 0;
                    206:         break;
                    207:     }
                    208: #endif
                    209:     if (s->feat & SH_SERIAL_FEAT_SCIF) {
                    210:         switch(offs) {
1.1.1.2   root      211:         case 0x00: /* SMR */
                    212:             ret = s->smr;
                    213:             break;
                    214:         case 0x08: /* SCR */
                    215:             ret = s->scr;
                    216:             break;
1.1       root      217:         case 0x10: /* FSR */
                    218:             ret = 0;
                    219:             if (s->flags & SH_SERIAL_FLAG_TEND)
                    220:                 ret |= (1 << 6);
                    221:             if (s->flags & SH_SERIAL_FLAG_TDE)
                    222:                 ret |= (1 << 5);
                    223:             if (s->flags & SH_SERIAL_FLAG_BRK)
                    224:                 ret |= (1 << 4);
                    225:             if (s->flags & SH_SERIAL_FLAG_RDF)
                    226:                 ret |= (1 << 1);
                    227:             if (s->flags & SH_SERIAL_FLAG_DR)
                    228:                 ret |= (1 << 0);
                    229: 
1.1.1.2   root      230:             if (s->scr & (1 << 5))
1.1       root      231:                 s->flags |= SH_SERIAL_FLAG_TDE | SH_SERIAL_FLAG_TEND;
                    232: 
                    233:             break;
1.1.1.2   root      234:         case 0x14:
                    235:             if (s->rx_cnt > 0) {
                    236:                 ret = s->rx_fifo[s->rx_tail++];
                    237:                 s->rx_cnt--;
                    238:                 if (s->rx_tail == SH_RX_FIFO_LENGTH)
                    239:                     s->rx_tail = 0;
                    240:                 if (s->rx_cnt < s->rtrg)
                    241:                     s->flags &= ~SH_SERIAL_FLAG_RDF;
                    242:             }
                    243:             break;
1.1       root      244: #if 0
                    245:         case 0x18:
                    246:             ret = s->fcr;
                    247:             break;
                    248: #endif
                    249:         case 0x1c:
                    250:             ret = s->rx_cnt;
                    251:             break;
                    252:         case 0x20:
                    253:             ret = s->sptr;
                    254:             break;
                    255:         case 0x24:
                    256:             ret = 0;
                    257:             break;
                    258:         }
                    259:     }
                    260:     else {
                    261:         switch(offs) {
1.1.1.2   root      262: #if 0
1.1       root      263:         case 0x0c:
                    264:             ret = s->dr;
                    265:             break;
                    266:         case 0x10:
                    267:             ret = 0;
                    268:             break;
1.1.1.2   root      269:         case 0x14:
                    270:             ret = s->rx_fifo[0];
                    271:             break;
                    272: #endif
1.1       root      273:         case 0x1c:
                    274:             ret = s->sptr;
                    275:             break;
                    276:         }
                    277:     }
                    278: #ifdef DEBUG_SERIAL
1.1.1.2   root      279:     printf("sh_serial: read offs=0x%02x val=0x%x\n",
                    280:           offs, ret);
1.1       root      281: #endif
                    282: 
                    283:     if (ret & ~((1 << 16) - 1)) {
                    284:         fprintf(stderr, "sh_serial: unsupported read from 0x%02x\n", offs);
1.1.1.5   root      285:         abort();
1.1       root      286:     }
                    287: 
                    288:     return ret;
                    289: }
                    290: 
                    291: static int sh_serial_can_receive(sh_serial_state *s)
                    292: {
1.1.1.2   root      293:     return s->scr & (1 << 4);
1.1       root      294: }
                    295: 
                    296: static void sh_serial_receive_break(sh_serial_state *s)
                    297: {
1.1.1.2   root      298:     if (s->feat & SH_SERIAL_FEAT_SCIF)
                    299:         s->sr |= (1 << 4);
1.1       root      300: }
                    301: 
                    302: static int sh_serial_can_receive1(void *opaque)
                    303: {
                    304:     sh_serial_state *s = opaque;
                    305:     return sh_serial_can_receive(s);
                    306: }
                    307: 
                    308: static void sh_serial_receive1(void *opaque, const uint8_t *buf, int size)
                    309: {
                    310:     sh_serial_state *s = opaque;
1.1.1.6 ! root      311: 
        !           312:     if (s->feat & SH_SERIAL_FEAT_SCIF) {
        !           313:         int i;
        !           314:         for (i = 0; i < size; i++) {
        !           315:             if (s->rx_cnt < SH_RX_FIFO_LENGTH) {
        !           316:                 s->rx_fifo[s->rx_head++] = buf[i];
        !           317:                 if (s->rx_head == SH_RX_FIFO_LENGTH) {
        !           318:                     s->rx_head = 0;
        !           319:                 }
        !           320:                 s->rx_cnt++;
        !           321:                 if (s->rx_cnt >= s->rtrg) {
        !           322:                     s->flags |= SH_SERIAL_FLAG_RDF;
        !           323:                     if (s->scr & (1 << 6) && s->rxi) {
        !           324:                         qemu_set_irq(s->rxi, 1);
        !           325:                     }
        !           326:                 }
        !           327:             }
        !           328:         }
        !           329:     } else {
        !           330:         s->rx_fifo[0] = buf[0];
        !           331:     }
1.1       root      332: }
                    333: 
                    334: static void sh_serial_event(void *opaque, int event)
                    335: {
                    336:     sh_serial_state *s = opaque;
                    337:     if (event == CHR_EVENT_BREAK)
                    338:         sh_serial_receive_break(s);
                    339: }
                    340: 
1.1.1.4   root      341: static CPUReadMemoryFunc * const sh_serial_readfn[] = {
1.1       root      342:     &sh_serial_read,
                    343:     &sh_serial_read,
                    344:     &sh_serial_read,
                    345: };
                    346: 
1.1.1.4   root      347: static CPUWriteMemoryFunc * const sh_serial_writefn[] = {
1.1       root      348:     &sh_serial_write,
                    349:     &sh_serial_write,
                    350:     &sh_serial_write,
                    351: };
                    352: 
                    353: void sh_serial_init (target_phys_addr_t base, int feat,
1.1.1.2   root      354:                     uint32_t freq, CharDriverState *chr,
                    355:                     qemu_irq eri_source,
                    356:                     qemu_irq rxi_source,
                    357:                     qemu_irq txi_source,
                    358:                     qemu_irq tei_source,
                    359:                     qemu_irq bri_source)
1.1       root      360: {
                    361:     sh_serial_state *s;
                    362:     int s_io_memory;
                    363: 
                    364:     s = qemu_mallocz(sizeof(sh_serial_state));
                    365: 
                    366:     s->feat = feat;
                    367:     s->flags = SH_SERIAL_FLAG_TEND | SH_SERIAL_FLAG_TDE;
1.1.1.2   root      368:     s->rtrg = 1;
1.1       root      369: 
                    370:     s->smr = 0;
                    371:     s->brr = 0xff;
                    372:     s->scr = 1 << 5; /* pretend that TX is enabled so early printk works */
                    373:     s->sptr = 0;
                    374: 
                    375:     if (feat & SH_SERIAL_FEAT_SCIF) {
                    376:         s->fcr = 0;
                    377:     }
                    378:     else {
                    379:         s->dr = 0xff;
                    380:     }
                    381: 
1.1.1.2   root      382:     sh_serial_clear_fifo(s);
1.1       root      383: 
1.1.1.3   root      384:     s_io_memory = cpu_register_io_memory(sh_serial_readfn,
1.1.1.6 ! root      385:                                         sh_serial_writefn, s,
        !           386:                                          DEVICE_NATIVE_ENDIAN);
1.1.1.2   root      387:     cpu_register_physical_memory(P4ADDR(base), 0x28, s_io_memory);
                    388:     cpu_register_physical_memory(A7ADDR(base), 0x28, s_io_memory);
1.1       root      389: 
                    390:     s->chr = chr;
                    391: 
                    392:     if (chr)
                    393:         qemu_chr_add_handlers(chr, sh_serial_can_receive1, sh_serial_receive1,
                    394:                              sh_serial_event, s);
1.1.1.2   root      395: 
                    396:     s->eri = eri_source;
                    397:     s->rxi = rxi_source;
                    398:     s->txi = txi_source;
                    399:     s->tei = tei_source;
                    400:     s->bri = bri_source;
1.1       root      401: }

unix.superglobalmegacorp.com

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