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

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"
1.1.1.8 ! root       30: #include "exec-memory.h"
1.1       root       31: 
                     32: //#define DEBUG_SERIAL
                     33: 
                     34: #define SH_SERIAL_FLAG_TEND (1 << 0)
                     35: #define SH_SERIAL_FLAG_TDE  (1 << 1)
                     36: #define SH_SERIAL_FLAG_RDF  (1 << 2)
                     37: #define SH_SERIAL_FLAG_BRK  (1 << 3)
                     38: #define SH_SERIAL_FLAG_DR   (1 << 4)
                     39: 
1.1.1.2   root       40: #define SH_RX_FIFO_LENGTH (16)
                     41: 
1.1       root       42: typedef struct {
1.1.1.8 ! root       43:     MemoryRegion iomem;
        !            44:     MemoryRegion iomem_p4;
        !            45:     MemoryRegion iomem_a7;
1.1       root       46:     uint8_t smr;
                     47:     uint8_t brr;
                     48:     uint8_t scr;
                     49:     uint8_t dr; /* ftdr / tdr */
                     50:     uint8_t sr; /* fsr / ssr */
                     51:     uint16_t fcr;
                     52:     uint8_t sptr;
                     53: 
1.1.1.2   root       54:     uint8_t rx_fifo[SH_RX_FIFO_LENGTH]; /* frdr / rdr */
1.1       root       55:     uint8_t rx_cnt;
1.1.1.2   root       56:     uint8_t rx_tail;
                     57:     uint8_t rx_head;
1.1       root       58: 
                     59:     int freq;
                     60:     int feat;
                     61:     int flags;
1.1.1.2   root       62:     int rtrg;
1.1       root       63: 
                     64:     CharDriverState *chr;
1.1.1.2   root       65: 
                     66:     qemu_irq eri;
                     67:     qemu_irq rxi;
                     68:     qemu_irq txi;
                     69:     qemu_irq tei;
                     70:     qemu_irq bri;
1.1       root       71: } sh_serial_state;
                     72: 
1.1.1.2   root       73: static void sh_serial_clear_fifo(sh_serial_state * s)
                     74: {
                     75:     memset(s->rx_fifo, 0, SH_RX_FIFO_LENGTH);
                     76:     s->rx_cnt = 0;
                     77:     s->rx_head = 0;
                     78:     s->rx_tail = 0;
                     79: }
                     80: 
1.1.1.8 ! root       81: static void sh_serial_write(void *opaque, target_phys_addr_t offs,
        !            82:                             uint64_t val, unsigned size)
1.1       root       83: {
                     84:     sh_serial_state *s = opaque;
                     85:     unsigned char ch;
                     86: 
                     87: #ifdef DEBUG_SERIAL
1.1.1.2   root       88:     printf("sh_serial: write offs=0x%02x val=0x%02x\n",
                     89:           offs, val);
1.1       root       90: #endif
                     91:     switch(offs) {
                     92:     case 0x00: /* SMR */
                     93:         s->smr = val & ((s->feat & SH_SERIAL_FEAT_SCIF) ? 0x7b : 0xff);
                     94:         return;
                     95:     case 0x04: /* BRR */
                     96:         s->brr = val;
                     97:        return;
                     98:     case 0x08: /* SCR */
1.1.1.2   root       99:         /* TODO : For SH7751, SCIF mask should be 0xfb. */
                    100:         s->scr = val & ((s->feat & SH_SERIAL_FEAT_SCIF) ? 0xfa : 0xff);
1.1       root      101:         if (!(val & (1 << 5)))
                    102:             s->flags |= SH_SERIAL_FLAG_TEND;
1.1.1.2   root      103:         if ((s->feat & SH_SERIAL_FEAT_SCIF) && s->txi) {
                    104:            qemu_set_irq(s->txi, val & (1 << 7));
                    105:         }
                    106:         if (!(val & (1 << 6))) {
                    107:            qemu_set_irq(s->rxi, 0);
                    108:         }
1.1       root      109:         return;
                    110:     case 0x0c: /* FTDR / TDR */
                    111:         if (s->chr) {
                    112:             ch = val;
1.1.1.7   root      113:             qemu_chr_fe_write(s->chr, &ch, 1);
1.1       root      114:        }
                    115:        s->dr = val;
                    116:        s->flags &= ~SH_SERIAL_FLAG_TDE;
                    117:         return;
                    118: #if 0
                    119:     case 0x14: /* FRDR / RDR */
                    120:         ret = 0;
                    121:         break;
                    122: #endif
                    123:     }
                    124:     if (s->feat & SH_SERIAL_FEAT_SCIF) {
                    125:         switch(offs) {
                    126:         case 0x10: /* FSR */
                    127:             if (!(val & (1 << 6)))
                    128:                 s->flags &= ~SH_SERIAL_FLAG_TEND;
                    129:             if (!(val & (1 << 5)))
                    130:                 s->flags &= ~SH_SERIAL_FLAG_TDE;
                    131:             if (!(val & (1 << 4)))
                    132:                 s->flags &= ~SH_SERIAL_FLAG_BRK;
                    133:             if (!(val & (1 << 1)))
                    134:                 s->flags &= ~SH_SERIAL_FLAG_RDF;
                    135:             if (!(val & (1 << 0)))
                    136:                 s->flags &= ~SH_SERIAL_FLAG_DR;
1.1.1.2   root      137: 
                    138:             if (!(val & (1 << 1)) || !(val & (1 << 0))) {
                    139:                 if (s->rxi) {
                    140:                     qemu_set_irq(s->rxi, 0);
                    141:                 }
                    142:             }
1.1       root      143:             return;
                    144:         case 0x18: /* FCR */
                    145:             s->fcr = val;
1.1.1.2   root      146:             switch ((val >> 6) & 3) {
                    147:             case 0:
                    148:                 s->rtrg = 1;
                    149:                 break;
                    150:             case 1:
                    151:                 s->rtrg = 4;
                    152:                 break;
                    153:             case 2:
                    154:                 s->rtrg = 8;
                    155:                 break;
                    156:             case 3:
                    157:                 s->rtrg = 14;
                    158:                 break;
                    159:             }
                    160:             if (val & (1 << 1)) {
                    161:                 sh_serial_clear_fifo(s);
                    162:                 s->sr &= ~(1 << 1);
                    163:             }
                    164: 
1.1       root      165:             return;
                    166:         case 0x20: /* SPTR */
1.1.1.2   root      167:             s->sptr = val & 0xf3;
1.1       root      168:             return;
                    169:         case 0x24: /* LSR */
                    170:             return;
                    171:         }
                    172:     }
                    173:     else {
                    174:         switch(offs) {
1.1.1.2   root      175: #if 0
1.1       root      176:         case 0x0c:
                    177:             ret = s->dr;
                    178:             break;
                    179:         case 0x10:
                    180:             ret = 0;
                    181:             break;
1.1.1.2   root      182: #endif
1.1       root      183:         case 0x1c:
1.1.1.2   root      184:             s->sptr = val & 0x8f;
                    185:             return;
1.1       root      186:         }
                    187:     }
                    188: 
                    189:     fprintf(stderr, "sh_serial: unsupported write to 0x%02x\n", offs);
1.1.1.5   root      190:     abort();
1.1       root      191: }
                    192: 
1.1.1.8 ! root      193: static uint64_t sh_serial_read(void *opaque, target_phys_addr_t offs,
        !           194:                                unsigned size)
1.1       root      195: {
                    196:     sh_serial_state *s = opaque;
                    197:     uint32_t ret = ~0;
                    198: 
                    199: #if 0
                    200:     switch(offs) {
                    201:     case 0x00:
                    202:         ret = s->smr;
                    203:         break;
                    204:     case 0x04:
                    205:         ret = s->brr;
                    206:        break;
                    207:     case 0x08:
                    208:         ret = s->scr;
                    209:         break;
                    210:     case 0x14:
                    211:         ret = 0;
                    212:         break;
                    213:     }
                    214: #endif
                    215:     if (s->feat & SH_SERIAL_FEAT_SCIF) {
                    216:         switch(offs) {
1.1.1.2   root      217:         case 0x00: /* SMR */
                    218:             ret = s->smr;
                    219:             break;
                    220:         case 0x08: /* SCR */
                    221:             ret = s->scr;
                    222:             break;
1.1       root      223:         case 0x10: /* FSR */
                    224:             ret = 0;
                    225:             if (s->flags & SH_SERIAL_FLAG_TEND)
                    226:                 ret |= (1 << 6);
                    227:             if (s->flags & SH_SERIAL_FLAG_TDE)
                    228:                 ret |= (1 << 5);
                    229:             if (s->flags & SH_SERIAL_FLAG_BRK)
                    230:                 ret |= (1 << 4);
                    231:             if (s->flags & SH_SERIAL_FLAG_RDF)
                    232:                 ret |= (1 << 1);
                    233:             if (s->flags & SH_SERIAL_FLAG_DR)
                    234:                 ret |= (1 << 0);
                    235: 
1.1.1.2   root      236:             if (s->scr & (1 << 5))
1.1       root      237:                 s->flags |= SH_SERIAL_FLAG_TDE | SH_SERIAL_FLAG_TEND;
                    238: 
                    239:             break;
1.1.1.2   root      240:         case 0x14:
                    241:             if (s->rx_cnt > 0) {
                    242:                 ret = s->rx_fifo[s->rx_tail++];
                    243:                 s->rx_cnt--;
                    244:                 if (s->rx_tail == SH_RX_FIFO_LENGTH)
                    245:                     s->rx_tail = 0;
                    246:                 if (s->rx_cnt < s->rtrg)
                    247:                     s->flags &= ~SH_SERIAL_FLAG_RDF;
                    248:             }
                    249:             break;
1.1       root      250: #if 0
                    251:         case 0x18:
                    252:             ret = s->fcr;
                    253:             break;
                    254: #endif
                    255:         case 0x1c:
                    256:             ret = s->rx_cnt;
                    257:             break;
                    258:         case 0x20:
                    259:             ret = s->sptr;
                    260:             break;
                    261:         case 0x24:
                    262:             ret = 0;
                    263:             break;
                    264:         }
                    265:     }
                    266:     else {
                    267:         switch(offs) {
1.1.1.2   root      268: #if 0
1.1       root      269:         case 0x0c:
                    270:             ret = s->dr;
                    271:             break;
                    272:         case 0x10:
                    273:             ret = 0;
                    274:             break;
1.1.1.2   root      275:         case 0x14:
                    276:             ret = s->rx_fifo[0];
                    277:             break;
                    278: #endif
1.1       root      279:         case 0x1c:
                    280:             ret = s->sptr;
                    281:             break;
                    282:         }
                    283:     }
                    284: #ifdef DEBUG_SERIAL
1.1.1.2   root      285:     printf("sh_serial: read offs=0x%02x val=0x%x\n",
                    286:           offs, ret);
1.1       root      287: #endif
                    288: 
                    289:     if (ret & ~((1 << 16) - 1)) {
                    290:         fprintf(stderr, "sh_serial: unsupported read from 0x%02x\n", offs);
1.1.1.5   root      291:         abort();
1.1       root      292:     }
                    293: 
                    294:     return ret;
                    295: }
                    296: 
                    297: static int sh_serial_can_receive(sh_serial_state *s)
                    298: {
1.1.1.2   root      299:     return s->scr & (1 << 4);
1.1       root      300: }
                    301: 
                    302: static void sh_serial_receive_break(sh_serial_state *s)
                    303: {
1.1.1.2   root      304:     if (s->feat & SH_SERIAL_FEAT_SCIF)
                    305:         s->sr |= (1 << 4);
1.1       root      306: }
                    307: 
                    308: static int sh_serial_can_receive1(void *opaque)
                    309: {
                    310:     sh_serial_state *s = opaque;
                    311:     return sh_serial_can_receive(s);
                    312: }
                    313: 
                    314: static void sh_serial_receive1(void *opaque, const uint8_t *buf, int size)
                    315: {
                    316:     sh_serial_state *s = opaque;
1.1.1.6   root      317: 
                    318:     if (s->feat & SH_SERIAL_FEAT_SCIF) {
                    319:         int i;
                    320:         for (i = 0; i < size; i++) {
                    321:             if (s->rx_cnt < SH_RX_FIFO_LENGTH) {
                    322:                 s->rx_fifo[s->rx_head++] = buf[i];
                    323:                 if (s->rx_head == SH_RX_FIFO_LENGTH) {
                    324:                     s->rx_head = 0;
                    325:                 }
                    326:                 s->rx_cnt++;
                    327:                 if (s->rx_cnt >= s->rtrg) {
                    328:                     s->flags |= SH_SERIAL_FLAG_RDF;
                    329:                     if (s->scr & (1 << 6) && s->rxi) {
                    330:                         qemu_set_irq(s->rxi, 1);
                    331:                     }
                    332:                 }
                    333:             }
                    334:         }
                    335:     } else {
                    336:         s->rx_fifo[0] = buf[0];
                    337:     }
1.1       root      338: }
                    339: 
                    340: static void sh_serial_event(void *opaque, int event)
                    341: {
                    342:     sh_serial_state *s = opaque;
                    343:     if (event == CHR_EVENT_BREAK)
                    344:         sh_serial_receive_break(s);
                    345: }
                    346: 
1.1.1.8 ! root      347: static const MemoryRegionOps sh_serial_ops = {
        !           348:     .read = sh_serial_read,
        !           349:     .write = sh_serial_write,
        !           350:     .endianness = DEVICE_NATIVE_ENDIAN,
1.1       root      351: };
                    352: 
1.1.1.8 ! root      353: void sh_serial_init(MemoryRegion *sysmem,
        !           354:                     target_phys_addr_t base, int feat,
        !           355:                     uint32_t freq, CharDriverState *chr,
        !           356:                     qemu_irq eri_source,
        !           357:                     qemu_irq rxi_source,
        !           358:                     qemu_irq txi_source,
        !           359:                     qemu_irq tei_source,
        !           360:                     qemu_irq bri_source)
1.1       root      361: {
                    362:     sh_serial_state *s;
                    363: 
1.1.1.7   root      364:     s = g_malloc0(sizeof(sh_serial_state));
1.1       root      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.8 ! root      384:     memory_region_init_io(&s->iomem, &sh_serial_ops, s,
        !           385:                           "serial", 0x100000000ULL);
        !           386: 
        !           387:     memory_region_init_alias(&s->iomem_p4, "serial-p4", &s->iomem,
        !           388:                              0, 0x28);
        !           389:     memory_region_add_subregion(sysmem, P4ADDR(base), &s->iomem_p4);
        !           390: 
        !           391:     memory_region_init_alias(&s->iomem_a7, "serial-a7", &s->iomem,
        !           392:                              0, 0x28);
        !           393:     memory_region_add_subregion(sysmem, A7ADDR(base), &s->iomem_a7);
1.1       root      394: 
                    395:     s->chr = chr;
                    396: 
                    397:     if (chr)
                    398:         qemu_chr_add_handlers(chr, sh_serial_can_receive1, sh_serial_receive1,
                    399:                              sh_serial_event, s);
1.1.1.2   root      400: 
                    401:     s->eri = eri_source;
                    402:     s->rxi = rxi_source;
                    403:     s->txi = txi_source;
                    404:     s->tei = tei_source;
                    405:     s->bri = bri_source;
1.1       root      406: }

unix.superglobalmegacorp.com

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