| 
									
										
										
										
											2011-01-24 12:56:54 +01:00
										 |  |  | /*
 | 
					
						
							|  |  |  |  * QEMU GRLIB APB UART Emulator | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * Copyright (c) 2010-2011 AdaCore | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * Permission is hereby granted, free of charge, to any person obtaining a copy | 
					
						
							|  |  |  |  * of this software and associated documentation files (the "Software"), to deal | 
					
						
							|  |  |  |  * in the Software without restriction, including without limitation the rights | 
					
						
							|  |  |  |  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | 
					
						
							|  |  |  |  * copies of the Software, and to permit persons to whom the Software is | 
					
						
							|  |  |  |  * furnished to do so, subject to the following conditions: | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * The above copyright notice and this permission notice shall be included in | 
					
						
							|  |  |  |  * all copies or substantial portions of the Software. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | 
					
						
							|  |  |  |  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | 
					
						
							|  |  |  |  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | 
					
						
							|  |  |  |  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | 
					
						
							|  |  |  |  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | 
					
						
							|  |  |  |  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | 
					
						
							|  |  |  |  * THE SOFTWARE. | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #include "sysbus.h"
 | 
					
						
							|  |  |  | #include "qemu-char.h"
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #include "trace.h"
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #define UART_REG_SIZE 20     /* Size of memory mapped registers */
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /* UART status register fields */ | 
					
						
							|  |  |  | #define UART_DATA_READY           (1 <<  0)
 | 
					
						
							|  |  |  | #define UART_TRANSMIT_SHIFT_EMPTY (1 <<  1)
 | 
					
						
							|  |  |  | #define UART_TRANSMIT_FIFO_EMPTY  (1 <<  2)
 | 
					
						
							|  |  |  | #define UART_BREAK_RECEIVED       (1 <<  3)
 | 
					
						
							|  |  |  | #define UART_OVERRUN              (1 <<  4)
 | 
					
						
							|  |  |  | #define UART_PARITY_ERROR         (1 <<  5)
 | 
					
						
							|  |  |  | #define UART_FRAMING_ERROR        (1 <<  6)
 | 
					
						
							|  |  |  | #define UART_TRANSMIT_FIFO_HALF   (1 <<  7)
 | 
					
						
							|  |  |  | #define UART_RECEIVE_FIFO_HALF    (1 <<  8)
 | 
					
						
							|  |  |  | #define UART_TRANSMIT_FIFO_FULL   (1 <<  9)
 | 
					
						
							|  |  |  | #define UART_RECEIVE_FIFO_FULL    (1 << 10)
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /* UART control register fields */ | 
					
						
							|  |  |  | #define UART_RECEIVE_ENABLE          (1 <<  0)
 | 
					
						
							|  |  |  | #define UART_TRANSMIT_ENABLE         (1 <<  1)
 | 
					
						
							|  |  |  | #define UART_RECEIVE_INTERRUPT       (1 <<  2)
 | 
					
						
							|  |  |  | #define UART_TRANSMIT_INTERRUPT      (1 <<  3)
 | 
					
						
							|  |  |  | #define UART_PARITY_SELECT           (1 <<  4)
 | 
					
						
							|  |  |  | #define UART_PARITY_ENABLE           (1 <<  5)
 | 
					
						
							|  |  |  | #define UART_FLOW_CONTROL            (1 <<  6)
 | 
					
						
							|  |  |  | #define UART_LOOPBACK                (1 <<  7)
 | 
					
						
							|  |  |  | #define UART_EXTERNAL_CLOCK          (1 <<  8)
 | 
					
						
							|  |  |  | #define UART_RECEIVE_FIFO_INTERRUPT  (1 <<  9)
 | 
					
						
							|  |  |  | #define UART_TRANSMIT_FIFO_INTERRUPT (1 << 10)
 | 
					
						
							|  |  |  | #define UART_FIFO_DEBUG_MODE         (1 << 11)
 | 
					
						
							|  |  |  | #define UART_OUTPUT_ENABLE           (1 << 12)
 | 
					
						
							|  |  |  | #define UART_FIFO_AVAILABLE          (1 << 31)
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /* Memory mapped register offsets */ | 
					
						
							|  |  |  | #define DATA_OFFSET       0x00
 | 
					
						
							|  |  |  | #define STATUS_OFFSET     0x04
 | 
					
						
							|  |  |  | #define CONTROL_OFFSET    0x08
 | 
					
						
							|  |  |  | #define SCALER_OFFSET     0x0C  /* not supported */
 | 
					
						
							|  |  |  | #define FIFO_DEBUG_OFFSET 0x10  /* not supported */
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | typedef struct UART { | 
					
						
							|  |  |  |     SysBusDevice busdev; | 
					
						
							| 
									
										
										
										
											2011-11-14 13:10:13 +02:00
										 |  |  |     MemoryRegion iomem; | 
					
						
							| 
									
										
										
										
											2011-01-24 12:56:54 +01:00
										 |  |  |     qemu_irq irq; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     CharDriverState *chr; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /* registers */ | 
					
						
							|  |  |  |     uint32_t receive; | 
					
						
							|  |  |  |     uint32_t status; | 
					
						
							|  |  |  |     uint32_t control; | 
					
						
							|  |  |  | } UART; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static int grlib_apbuart_can_receive(void *opaque) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     UART *uart = opaque; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     return !!(uart->status & UART_DATA_READY); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static void grlib_apbuart_receive(void *opaque, const uint8_t *buf, int size) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     UART *uart = opaque; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     uart->receive  = *buf; | 
					
						
							|  |  |  |     uart->status  |= UART_DATA_READY; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (uart->control & UART_RECEIVE_INTERRUPT) { | 
					
						
							|  |  |  |         qemu_irq_pulse(uart->irq); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static void grlib_apbuart_event(void *opaque, int event) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     trace_grlib_apbuart_event(event); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static void | 
					
						
							| 
									
										
										
										
											2011-11-14 13:10:13 +02:00
										 |  |  | grlib_apbuart_write(void *opaque, target_phys_addr_t addr, | 
					
						
							|  |  |  |                     uint64_t value, unsigned size) | 
					
						
							| 
									
										
										
										
											2011-01-24 12:56:54 +01:00
										 |  |  | { | 
					
						
							|  |  |  |     UART          *uart = opaque; | 
					
						
							|  |  |  |     unsigned char  c    = 0; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     addr &= 0xff; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /* Unit registers */ | 
					
						
							|  |  |  |     switch (addr) { | 
					
						
							|  |  |  |     case DATA_OFFSET: | 
					
						
							|  |  |  |         c = value & 0xFF; | 
					
						
							| 
									
										
										
										
											2011-08-15 11:17:28 -05:00
										 |  |  |         qemu_chr_fe_write(uart->chr, &c, 1); | 
					
						
							| 
									
										
										
										
											2011-01-24 12:56:54 +01:00
										 |  |  |         return; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     case STATUS_OFFSET: | 
					
						
							|  |  |  |         /* Read Only */ | 
					
						
							|  |  |  |         return; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     case CONTROL_OFFSET: | 
					
						
							|  |  |  |         /* Not supported */ | 
					
						
							|  |  |  |         return; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     case SCALER_OFFSET: | 
					
						
							|  |  |  |         /* Not supported */ | 
					
						
							|  |  |  |         return; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     default: | 
					
						
							|  |  |  |         break; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-04-14 18:11:00 +01:00
										 |  |  |     trace_grlib_apbuart_writel_unknown(addr, value); | 
					
						
							| 
									
										
										
										
											2011-01-24 12:56:54 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-11-14 13:10:13 +02:00
										 |  |  | static bool grlib_apbuart_accepts(void *opaque, target_phys_addr_t addr, | 
					
						
							|  |  |  |                                   unsigned size, bool is_write) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     return is_write && size == 4; | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2011-01-24 12:56:54 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-11-14 13:10:13 +02:00
										 |  |  | static const MemoryRegionOps grlib_apbuart_ops = { | 
					
						
							|  |  |  |     .write = grlib_apbuart_write, | 
					
						
							|  |  |  |     .valid.accepts = grlib_apbuart_accepts, | 
					
						
							|  |  |  |     .endianness = DEVICE_NATIVE_ENDIAN, | 
					
						
							| 
									
										
										
										
											2011-01-24 12:56:54 +01:00
										 |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static int grlib_apbuart_init(SysBusDevice *dev) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     UART *uart      = FROM_SYSBUS(typeof(*uart), dev); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     qemu_chr_add_handlers(uart->chr, | 
					
						
							|  |  |  |                           grlib_apbuart_can_receive, | 
					
						
							|  |  |  |                           grlib_apbuart_receive, | 
					
						
							|  |  |  |                           grlib_apbuart_event, | 
					
						
							|  |  |  |                           uart); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     sysbus_init_irq(dev, &uart->irq); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-11-14 13:10:13 +02:00
										 |  |  |     memory_region_init_io(&uart->iomem, &grlib_apbuart_ops, uart, | 
					
						
							|  |  |  |                           "uart", UART_REG_SIZE); | 
					
						
							| 
									
										
										
										
											2011-01-24 12:56:54 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-11-27 11:38:10 +02:00
										 |  |  |     sysbus_init_mmio(dev, &uart->iomem); | 
					
						
							| 
									
										
										
										
											2011-01-24 12:56:54 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |     return 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static SysBusDeviceInfo grlib_gptimer_info = { | 
					
						
							|  |  |  |     .init       = grlib_apbuart_init, | 
					
						
							|  |  |  |     .qdev.name  = "grlib,apbuart", | 
					
						
							|  |  |  |     .qdev.size  = sizeof(UART), | 
					
						
							|  |  |  |     .qdev.props = (Property[]) { | 
					
						
							|  |  |  |         DEFINE_PROP_CHR("chrdev", UART, chr), | 
					
						
							|  |  |  |         DEFINE_PROP_END_OF_LIST() | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static void grlib_gptimer_register(void) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     sysbus_register_withprop(&grlib_gptimer_info); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | device_init(grlib_gptimer_register) |