Annotation of qemu/hw/pl011.c, revision 1.1.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