Annotation of qemu/hw/pl011.c, revision 1.1

1.1     ! root        1: /* 
        !             2:  * Arm PrimeCell PL011 UART
        !             3:  *
        !             4:  * Copyright (c) 2006 CodeSourcery.
        !             5:  * Written by Paul Brook
        !             6:  *
        !             7:  * This code is licenced under the GPL.
        !             8:  */
        !             9: 
        !            10: #include "vl.h"
        !            11: 
        !            12: typedef struct {
        !            13:     uint32_t base;
        !            14:     uint32_t readbuff;
        !            15:     uint32_t flags;
        !            16:     uint32_t lcr;
        !            17:     uint32_t cr;
        !            18:     uint32_t dmacr;
        !            19:     uint32_t int_enabled;
        !            20:     uint32_t int_level;
        !            21:     uint32_t read_fifo[16];
        !            22:     uint32_t ilpr;
        !            23:     uint32_t ibrd;
        !            24:     uint32_t fbrd;
        !            25:     uint32_t ifl;
        !            26:     int read_pos;
        !            27:     int read_count;
        !            28:     int read_trigger;
        !            29:     CharDriverState *chr;
        !            30:     void *pic;
        !            31:     int irq;
        !            32: } pl011_state;
        !            33: 
        !            34: #define PL011_INT_TX 0x20
        !            35: #define PL011_INT_RX 0x10
        !            36: 
        !            37: #define PL011_FLAG_TXFE 0x80
        !            38: #define PL011_FLAG_RXFF 0x40
        !            39: #define PL011_FLAG_TXFF 0x20
        !            40: #define PL011_FLAG_RXFE 0x10
        !            41: 
        !            42: static const unsigned char pl011_id[] =
        !            43: { 0x11, 0x10, 0x14, 0x00, 0x0d, 0xf0, 0x05, 0xb1 };
        !            44: 
        !            45: static void pl011_update(pl011_state *s)
        !            46: {
        !            47:     uint32_t flags;
        !            48:     
        !            49:     flags = s->int_level & s->int_enabled;
        !            50:     pic_set_irq_new(s->pic, s->irq, flags != 0);
        !            51: }
        !            52: 
        !            53: static uint32_t pl011_read(void *opaque, target_phys_addr_t offset)
        !            54: {
        !            55:     pl011_state *s = (pl011_state *)opaque;
        !            56:     uint32_t c;
        !            57: 
        !            58:     offset -= s->base;
        !            59:     if (offset >= 0xfe0 && offset < 0x1000) {
        !            60:         return pl011_id[(offset - 0xfe0) >> 2];
        !            61:     }
        !            62:     switch (offset >> 2) {
        !            63:     case 0: /* UARTDR */
        !            64:         s->flags &= ~PL011_FLAG_RXFF;
        !            65:         c = s->read_fifo[s->read_pos];
        !            66:         if (s->read_count > 0) {
        !            67:             s->read_count--;
        !            68:             if (++s->read_pos == 16)
        !            69:                 s->read_pos = 0;
        !            70:         }
        !            71:         if (s->read_count == 0) {
        !            72:             s->flags |= PL011_FLAG_RXFE;
        !            73:         }
        !            74:         if (s->read_count == s->read_trigger - 1)
        !            75:             s->int_level &= ~ PL011_INT_RX;
        !            76:         pl011_update(s);
        !            77:         return c;
        !            78:     case 1: /* UARTCR */
        !            79:         return 0;
        !            80:     case 6: /* UARTFR */
        !            81:         return s->flags;
        !            82:     case 8: /* UARTILPR */
        !            83:         return s->ilpr;
        !            84:     case 9: /* UARTIBRD */
        !            85:         return s->ibrd;
        !            86:     case 10: /* UARTFBRD */
        !            87:         return s->fbrd;
        !            88:     case 11: /* UARTLCR_H */
        !            89:         return s->lcr;
        !            90:     case 12: /* UARTCR */
        !            91:         return s->cr;
        !            92:     case 13: /* UARTIFLS */
        !            93:         return s->ifl;
        !            94:     case 14: /* UARTIMSC */
        !            95:         return s->int_enabled;
        !            96:     case 15: /* UARTRIS */
        !            97:         return s->int_level;
        !            98:     case 16: /* UARTMIS */
        !            99:         return s->int_level & s->int_enabled;
        !           100:     case 18: /* UARTDMACR */
        !           101:         return s->dmacr;
        !           102:     default:
        !           103:         cpu_abort (cpu_single_env, "pl011_read: Bad offset %x\n", offset);
        !           104:         return 0;
        !           105:     }
        !           106: }
        !           107: 
        !           108: static void pl011_set_read_trigger(pl011_state *s)
        !           109: {
        !           110: #if 0
        !           111:     /* The docs say the RX interrupt is triggered when the FIFO exceeds
        !           112:        the threshold.  However linux only reads the FIFO in response to an
        !           113:        interrupt.  Triggering the interrupt when the FIFO is non-empty seems
        !           114:        to make things work.  */
        !           115:     if (s->lcr & 0x10)
        !           116:         s->read_trigger = (s->ifl >> 1) & 0x1c;
        !           117:     else
        !           118: #endif
        !           119:         s->read_trigger = 1;
        !           120: }
        !           121: 
        !           122: static void pl011_write(void *opaque, target_phys_addr_t offset,
        !           123:                           uint32_t value)
        !           124: {
        !           125:     pl011_state *s = (pl011_state *)opaque;
        !           126:     unsigned char ch;
        !           127: 
        !           128:     offset -= s->base;
        !           129:     switch (offset >> 2) {
        !           130:     case 0: /* UARTDR */
        !           131:         /* ??? Check if transmitter is enabled.  */
        !           132:         ch = value;
        !           133:         if (s->chr)
        !           134:             qemu_chr_write(s->chr, &ch, 1);
        !           135:         s->int_level |= PL011_INT_TX;
        !           136:         pl011_update(s);
        !           137:         break;
        !           138:     case 1: /* UARTCR */
        !           139:         s->cr = value;
        !           140:         break;
        !           141:     case 8: /* UARTUARTILPR */
        !           142:         s->ilpr = value;
        !           143:         break;
        !           144:     case 9: /* UARTIBRD */
        !           145:         s->ibrd = value;
        !           146:         break;
        !           147:     case 10: /* UARTFBRD */
        !           148:         s->fbrd = value;
        !           149:         break;
        !           150:     case 11: /* UARTLCR_H */
        !           151:         s->lcr = value;
        !           152:         pl011_set_read_trigger(s);
        !           153:         break;
        !           154:     case 12: /* UARTCR */
        !           155:         /* ??? Need to implement the enable and loopback bits.  */
        !           156:         s->cr = value;
        !           157:         break;
        !           158:     case 13: /* UARTIFS */
        !           159:         s->ifl = value;
        !           160:         pl011_set_read_trigger(s);
        !           161:         break;
        !           162:     case 14: /* UARTIMSC */
        !           163:         s->int_enabled = value;
        !           164:         pl011_update(s);
        !           165:         break;
        !           166:     case 17: /* UARTICR */
        !           167:         s->int_level &= ~value;
        !           168:         pl011_update(s);
        !           169:         break;
        !           170:     case 18: /* UARTDMACR */
        !           171:         s->dmacr = value;
        !           172:         if (value & 3)
        !           173:             cpu_abort(cpu_single_env, "PL011: DMA not implemented\n");
        !           174:         break;
        !           175:     default:
        !           176:         cpu_abort (cpu_single_env, "pl011_write: Bad offset %x\n", offset);
        !           177:     }
        !           178: }
        !           179: 
        !           180: static int pl011_can_recieve(void *opaque)
        !           181: {
        !           182:     pl011_state *s = (pl011_state *)opaque;
        !           183: 
        !           184:     if (s->lcr & 0x10)
        !           185:         return s->read_count < 16;
        !           186:     else
        !           187:         return s->read_count < 1;
        !           188: }
        !           189: 
        !           190: static void pl011_recieve(void *opaque, const uint8_t *buf, int size)
        !           191: {
        !           192:     pl011_state *s = (pl011_state *)opaque;
        !           193:     int slot;
        !           194: 
        !           195:     slot = s->read_pos + s->read_count;
        !           196:     if (slot >= 16)
        !           197:         slot -= 16;
        !           198:     s->read_fifo[slot] = *buf;
        !           199:     s->read_count++;
        !           200:     s->flags &= ~PL011_FLAG_RXFE;
        !           201:     if (s->cr & 0x10 || s->read_count == 16) {
        !           202:         s->flags |= PL011_FLAG_RXFF;
        !           203:     }
        !           204:     if (s->read_count == s->read_trigger) {
        !           205:         s->int_level |= PL011_INT_RX;
        !           206:         pl011_update(s);
        !           207:     }
        !           208: }
        !           209: 
        !           210: static void pl011_event(void *opaque, int event)
        !           211: {
        !           212:     /* ??? Should probably implement break.  */
        !           213: }
        !           214: 
        !           215: static CPUReadMemoryFunc *pl011_readfn[] = {
        !           216:    pl011_read,
        !           217:    pl011_read,
        !           218:    pl011_read
        !           219: };
        !           220: 
        !           221: static CPUWriteMemoryFunc *pl011_writefn[] = {
        !           222:    pl011_write,
        !           223:    pl011_write,
        !           224:    pl011_write
        !           225: };
        !           226: 
        !           227: void pl011_init(uint32_t base, void *pic, int irq,
        !           228:                 CharDriverState *chr)
        !           229: {
        !           230:     int iomemtype;
        !           231:     pl011_state *s;
        !           232: 
        !           233:     s = (pl011_state *)qemu_mallocz(sizeof(pl011_state));
        !           234:     iomemtype = cpu_register_io_memory(0, pl011_readfn,
        !           235:                                        pl011_writefn, s);
        !           236:     cpu_register_physical_memory(base, 0x00000fff, iomemtype);
        !           237:     s->base = base;
        !           238:     s->pic = pic;
        !           239:     s->irq = irq;
        !           240:     s->chr = chr;
        !           241:     s->read_trigger = 1;
        !           242:     s->ifl = 0x12;
        !           243:     s->cr = 0x300;
        !           244:     s->flags = 0x90;
        !           245:     if (chr){ 
        !           246:         qemu_chr_add_read_handler(chr, pl011_can_recieve, pl011_recieve, s);
        !           247:         qemu_chr_add_event_handler(chr, pl011_event);
        !           248:     }
        !           249:     /* ??? Save/restore.  */
        !           250: }
        !           251: 

unix.superglobalmegacorp.com

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