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

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

unix.superglobalmegacorp.com

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