1 /* 2 * Arm PrimeCell PL011 UART 3 * 4 * Copyright (c) 2006 CodeSourcery. 5 * Written by Paul Brook 6 * 7 * This code is licensed under the GPL. 8 */ 9 10 #include "hw/sysbus.h" 11 #include "char/char.h" 12 13 typedef struct { 14 SysBusDevice busdev; 15 MemoryRegion iomem; 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; 32 qemu_irq irq; 33 const unsigned char *id; 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 44 static const unsigned char pl011_id_arm[8] = 45 { 0x11, 0x10, 0x14, 0x00, 0x0d, 0xf0, 0x05, 0xb1 }; 46 static const unsigned char pl011_id_luminary[8] = 47 { 0x11, 0x00, 0x18, 0x01, 0x0d, 0xf0, 0x05, 0xb1 }; 48 49 static void pl011_update(pl011_state *s) 50 { 51 uint32_t flags; 52 53 flags = s->int_level & s->int_enabled; 54 qemu_set_irq(s->irq, flags != 0); 55 } 56 57 static uint64_t pl011_read(void *opaque, hwaddr offset, 58 unsigned size) 59 { 60 pl011_state *s = (pl011_state *)opaque; 61 uint32_t c; 62 63 if (offset >= 0xfe0 && offset < 0x1000) { 64 return s->id[(offset - 0xfe0) >> 2]; 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); 81 if (s->chr) { 82 qemu_chr_accept_input(s->chr); 83 } 84 return c; 85 case 1: /* UARTCR */ 86 return 0; 87 case 6: /* UARTFR */ 88 return s->flags; 89 case 8: /* UARTILPR */ 90 return s->ilpr; 91 case 9: /* UARTIBRD */ 92 return s->ibrd; 93 case 10: /* UARTFBRD */ 94 return s->fbrd; 95 case 11: /* UARTLCR_H */ 96 return s->lcr; 97 case 12: /* UARTCR */ 98 return s->cr; 99 case 13: /* UARTIFLS */ 100 return s->ifl; 101 case 14: /* UARTIMSC */ 102 return s->int_enabled; 103 case 15: /* UARTRIS */ 104 return s->int_level; 105 case 16: /* UARTMIS */ 106 return s->int_level & s->int_enabled; 107 case 18: /* UARTDMACR */ 108 return s->dmacr; 109 default: 110 qemu_log_mask(LOG_GUEST_ERROR, 111 "pl011_read: Bad offset %x\n", (int)offset); 112 return 0; 113 } 114 } 115 116 static void pl011_set_read_trigger(pl011_state *s) 117 { 118 #if 0 119 /* The docs say the RX interrupt is triggered when the FIFO exceeds 120 the threshold. However linux only reads the FIFO in response to an 121 interrupt. Triggering the interrupt when the FIFO is non-empty seems 122 to make things work. */ 123 if (s->lcr & 0x10) 124 s->read_trigger = (s->ifl >> 1) & 0x1c; 125 else 126 #endif 127 s->read_trigger = 1; 128 } 129 130 static void pl011_write(void *opaque, hwaddr offset, 131 uint64_t value, unsigned size) 132 { 133 pl011_state *s = (pl011_state *)opaque; 134 unsigned char ch; 135 136 switch (offset >> 2) { 137 case 0: /* UARTDR */ 138 /* ??? Check if transmitter is enabled. */ 139 ch = value; 140 if (s->chr) 141 qemu_chr_fe_write(s->chr, &ch, 1); 142 s->int_level |= PL011_INT_TX; 143 pl011_update(s); 144 break; 145 case 1: /* UARTCR */ 146 s->cr = value; 147 break; 148 case 6: /* UARTFR */ 149 /* Writes to Flag register are ignored. */ 150 break; 151 case 8: /* UARTUARTILPR */ 152 s->ilpr = value; 153 break; 154 case 9: /* UARTIBRD */ 155 s->ibrd = value; 156 break; 157 case 10: /* UARTFBRD */ 158 s->fbrd = value; 159 break; 160 case 11: /* UARTLCR_H */ 161 s->lcr = value; 162 pl011_set_read_trigger(s); 163 break; 164 case 12: /* UARTCR */ 165 /* ??? Need to implement the enable and loopback bits. */ 166 s->cr = value; 167 break; 168 case 13: /* UARTIFS */ 169 s->ifl = value; 170 pl011_set_read_trigger(s); 171 break; 172 case 14: /* UARTIMSC */ 173 s->int_enabled = value; 174 pl011_update(s); 175 break; 176 case 17: /* UARTICR */ 177 s->int_level &= ~value; 178 pl011_update(s); 179 break; 180 case 18: /* UARTDMACR */ 181 s->dmacr = value; 182 if (value & 3) { 183 qemu_log_mask(LOG_UNIMP, "pl011: DMA not implemented\n"); 184 } 185 break; 186 default: 187 qemu_log_mask(LOG_GUEST_ERROR, 188 "pl011_write: Bad offset %x\n", (int)offset); 189 } 190 } 191 192 static int pl011_can_receive(void *opaque) 193 { 194 pl011_state *s = (pl011_state *)opaque; 195 196 if (s->lcr & 0x10) 197 return s->read_count < 16; 198 else 199 return s->read_count < 1; 200 } 201 202 static void pl011_put_fifo(void *opaque, uint32_t value) 203 { 204 pl011_state *s = (pl011_state *)opaque; 205 int slot; 206 207 slot = s->read_pos + s->read_count; 208 if (slot >= 16) 209 slot -= 16; 210 s->read_fifo[slot] = value; 211 s->read_count++; 212 s->flags &= ~PL011_FLAG_RXFE; 213 if (s->cr & 0x10 || s->read_count == 16) { 214 s->flags |= PL011_FLAG_RXFF; 215 } 216 if (s->read_count == s->read_trigger) { 217 s->int_level |= PL011_INT_RX; 218 pl011_update(s); 219 } 220 } 221 222 static void pl011_receive(void *opaque, const uint8_t *buf, int size) 223 { 224 pl011_put_fifo(opaque, *buf); 225 } 226 227 static void pl011_event(void *opaque, int event) 228 { 229 if (event == CHR_EVENT_BREAK) 230 pl011_put_fifo(opaque, 0x400); 231 } 232 233 static const MemoryRegionOps pl011_ops = { 234 .read = pl011_read, 235 .write = pl011_write, 236 .endianness = DEVICE_NATIVE_ENDIAN, 237 }; 238 239 static const VMStateDescription vmstate_pl011 = { 240 .name = "pl011", 241 .version_id = 1, 242 .minimum_version_id = 1, 243 .minimum_version_id_old = 1, 244 .fields = (VMStateField[]) { 245 VMSTATE_UINT32(readbuff, pl011_state), 246 VMSTATE_UINT32(flags, pl011_state), 247 VMSTATE_UINT32(lcr, pl011_state), 248 VMSTATE_UINT32(cr, pl011_state), 249 VMSTATE_UINT32(dmacr, pl011_state), 250 VMSTATE_UINT32(int_enabled, pl011_state), 251 VMSTATE_UINT32(int_level, pl011_state), 252 VMSTATE_UINT32_ARRAY(read_fifo, pl011_state, 16), 253 VMSTATE_UINT32(ilpr, pl011_state), 254 VMSTATE_UINT32(ibrd, pl011_state), 255 VMSTATE_UINT32(fbrd, pl011_state), 256 VMSTATE_UINT32(ifl, pl011_state), 257 VMSTATE_INT32(read_pos, pl011_state), 258 VMSTATE_INT32(read_count, pl011_state), 259 VMSTATE_INT32(read_trigger, pl011_state), 260 VMSTATE_END_OF_LIST() 261 } 262 }; 263 264 static int pl011_init(SysBusDevice *dev, const unsigned char *id) 265 { 266 pl011_state *s = FROM_SYSBUS(pl011_state, dev); 267 268 memory_region_init_io(&s->iomem, &pl011_ops, s, "pl011", 0x1000); 269 sysbus_init_mmio(dev, &s->iomem); 270 sysbus_init_irq(dev, &s->irq); 271 s->id = id; 272 s->chr = qemu_char_get_next_serial(); 273 274 s->read_trigger = 1; 275 s->ifl = 0x12; 276 s->cr = 0x300; 277 s->flags = 0x90; 278 if (s->chr) { 279 qemu_chr_add_handlers(s->chr, pl011_can_receive, pl011_receive, 280 pl011_event, s); 281 } 282 vmstate_register(&dev->qdev, -1, &vmstate_pl011, s); 283 return 0; 284 } 285 286 static int pl011_arm_init(SysBusDevice *dev) 287 { 288 return pl011_init(dev, pl011_id_arm); 289 } 290 291 static int pl011_luminary_init(SysBusDevice *dev) 292 { 293 return pl011_init(dev, pl011_id_luminary); 294 } 295 296 static void pl011_arm_class_init(ObjectClass *klass, void *data) 297 { 298 SysBusDeviceClass *sdc = SYS_BUS_DEVICE_CLASS(klass); 299 300 sdc->init = pl011_arm_init; 301 } 302 303 static const TypeInfo pl011_arm_info = { 304 .name = "pl011", 305 .parent = TYPE_SYS_BUS_DEVICE, 306 .instance_size = sizeof(pl011_state), 307 .class_init = pl011_arm_class_init, 308 }; 309 310 static void pl011_luminary_class_init(ObjectClass *klass, void *data) 311 { 312 SysBusDeviceClass *sdc = SYS_BUS_DEVICE_CLASS(klass); 313 314 sdc->init = pl011_luminary_init; 315 } 316 317 static const TypeInfo pl011_luminary_info = { 318 .name = "pl011_luminary", 319 .parent = TYPE_SYS_BUS_DEVICE, 320 .instance_size = sizeof(pl011_state), 321 .class_init = pl011_luminary_class_init, 322 }; 323 324 static void pl011_register_types(void) 325 { 326 type_register_static(&pl011_arm_info); 327 type_register_static(&pl011_luminary_info); 328 } 329 330 type_init(pl011_register_types) 331