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