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

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       root       77: static void sh_serial_ioport_write(void *opaque, uint32_t offs, uint32_t val)
                     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);
                    185:     assert(0);
                    186: }
                    187: 
                    188: static uint32_t sh_serial_ioport_read(void *opaque, uint32_t offs)
                    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);
                    285:        assert(0);
                    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_byte(sh_serial_state *s, int ch)
                    297: {
1.1.1.2   root      298:     if (s->feat & SH_SERIAL_FEAT_SCIF) {
                    299:         if (s->rx_cnt < SH_RX_FIFO_LENGTH) {
                    300:             s->rx_fifo[s->rx_head++] = ch;
                    301:             if (s->rx_head == SH_RX_FIFO_LENGTH)
                    302:                 s->rx_head = 0;
                    303:             s->rx_cnt++;
                    304:             if (s->rx_cnt >= s->rtrg) {
                    305:                 s->flags |= SH_SERIAL_FLAG_RDF;
                    306:                 if (s->scr & (1 << 6) && s->rxi) {
                    307:                     qemu_set_irq(s->rxi, 1);
                    308:                 }
                    309:             }
                    310:         }
                    311:     } else {
                    312:         s->rx_fifo[0] = ch;
                    313:     }
1.1       root      314: }
                    315: 
                    316: static void sh_serial_receive_break(sh_serial_state *s)
                    317: {
1.1.1.2   root      318:     if (s->feat & SH_SERIAL_FEAT_SCIF)
                    319:         s->sr |= (1 << 4);
1.1       root      320: }
                    321: 
                    322: static int sh_serial_can_receive1(void *opaque)
                    323: {
                    324:     sh_serial_state *s = opaque;
                    325:     return sh_serial_can_receive(s);
                    326: }
                    327: 
                    328: static void sh_serial_receive1(void *opaque, const uint8_t *buf, int size)
                    329: {
                    330:     sh_serial_state *s = opaque;
                    331:     sh_serial_receive_byte(s, buf[0]);
                    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: 
                    341: static uint32_t sh_serial_read (void *opaque, target_phys_addr_t addr)
                    342: {
                    343:     sh_serial_state *s = opaque;
1.1.1.2   root      344:     return sh_serial_ioport_read(s, addr);
1.1       root      345: }
                    346: 
                    347: static void sh_serial_write (void *opaque,
                    348:                              target_phys_addr_t addr, uint32_t value)
                    349: {
                    350:     sh_serial_state *s = opaque;
1.1.1.2   root      351:     sh_serial_ioport_write(s, addr, value);
1.1       root      352: }
                    353: 
                    354: static CPUReadMemoryFunc *sh_serial_readfn[] = {
                    355:     &sh_serial_read,
                    356:     &sh_serial_read,
                    357:     &sh_serial_read,
                    358: };
                    359: 
                    360: static CPUWriteMemoryFunc *sh_serial_writefn[] = {
                    361:     &sh_serial_write,
                    362:     &sh_serial_write,
                    363:     &sh_serial_write,
                    364: };
                    365: 
                    366: void sh_serial_init (target_phys_addr_t base, int feat,
1.1.1.2   root      367:                     uint32_t freq, CharDriverState *chr,
                    368:                     qemu_irq eri_source,
                    369:                     qemu_irq rxi_source,
                    370:                     qemu_irq txi_source,
                    371:                     qemu_irq tei_source,
                    372:                     qemu_irq bri_source)
1.1       root      373: {
                    374:     sh_serial_state *s;
                    375:     int s_io_memory;
                    376: 
                    377:     s = qemu_mallocz(sizeof(sh_serial_state));
                    378: 
                    379:     s->feat = feat;
                    380:     s->flags = SH_SERIAL_FLAG_TEND | SH_SERIAL_FLAG_TDE;
1.1.1.2   root      381:     s->rtrg = 1;
1.1       root      382: 
                    383:     s->smr = 0;
                    384:     s->brr = 0xff;
                    385:     s->scr = 1 << 5; /* pretend that TX is enabled so early printk works */
                    386:     s->sptr = 0;
                    387: 
                    388:     if (feat & SH_SERIAL_FEAT_SCIF) {
                    389:         s->fcr = 0;
                    390:     }
                    391:     else {
                    392:         s->dr = 0xff;
                    393:     }
                    394: 
1.1.1.2   root      395:     sh_serial_clear_fifo(s);
1.1       root      396: 
1.1.1.3 ! root      397:     s_io_memory = cpu_register_io_memory(sh_serial_readfn,
1.1       root      398:                                         sh_serial_writefn, s);
1.1.1.2   root      399:     cpu_register_physical_memory(P4ADDR(base), 0x28, s_io_memory);
                    400:     cpu_register_physical_memory(A7ADDR(base), 0x28, s_io_memory);
1.1       root      401: 
                    402:     s->chr = chr;
                    403: 
                    404:     if (chr)
                    405:         qemu_chr_add_handlers(chr, sh_serial_can_receive1, sh_serial_receive1,
                    406:                              sh_serial_event, s);
1.1.1.2   root      407: 
                    408:     s->eri = eri_source;
                    409:     s->rxi = rxi_source;
                    410:     s->txi = txi_source;
                    411:     s->tei = tei_source;
                    412:     s->bri = bri_source;
1.1       root      413: }

unix.superglobalmegacorp.com

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