CONFIG_OMAP=y
CONFIG_BLIZZARD=y
CONFIG_ONENAND=y
+CONFIG_IMX=y
CONFIG_ZAURUS=y
CONFIG_VERSATILE_PCI=y
CONFIG_WDT_IB700=y
CONFIG_PC_SYSFW=y
CONFIG_XEN_I386=$(CONFIG_XEN)
+CONFIG_ISA_DEBUG=y
# Default configuration for lm32-softmmu
+CONFIG_LM32=y
CONFIG_MILKYMIST=y
CONFIG_FRAMEBUFFER=y
CONFIG_PTIMER=y
CONFIG_VIRTIO=y
+CONFIG_SCLPCONSOLE=y
CONFIG_LANCE=y
CONFIG_TCX=y
CONFIG_CS4231=y
+CONFIG_GRLIB=y
CONFIG_WDT_IB700=y
CONFIG_PC_SYSFW=y
CONFIG_XEN_I386=$(CONFIG_XEN)
+CONFIG_ISA_DEBUG=y
obj-y += a9scu.o
obj-y += realview_gic.o arm_sysctl.o arm11mpcore.o a9mpcore.o
obj-y += exynos4210_gic.o exynos4210_combiner.o
-obj-y += exynos4210_uart.o exynos4210_pwm.o
+obj-y += exynos4210_pwm.o
obj-y += exynos4210_pmu.o exynos4210_mct.o
obj-y += exynos4210_rtc.o
obj-y += arm_mptimer.o a15mpcore.o
obj-y += pxa2xx_mmci.o pxa2xx_pcmcia.o pxa2xx_keypad.o
obj-y += zaurus.o
obj-y += omap_dma.o omap_clk.o omap_mmc.o \
- omap_gpio.o omap_intc.o omap_uart.o
+ omap_gpio.o omap_intc.o
obj-y += soc_dma.o omap_gptimer.o omap_synctimer.o \
omap_gpmc.o omap_sdrc.o omap_tap.o omap_l4.o
obj-y += tsc210x.o
obj-y += cbus.o tusb6010.o
obj-y += mst_fpga.o
obj-y += strongarm.o
-obj-y += imx_serial.o imx_ccm.o imx_timer.o imx_avic.o
+obj-y += imx_ccm.o imx_timer.o imx_avic.o
obj-$(CONFIG_KVM) += kvm/arm_gic.o
obj-y := $(addprefix ../,$(obj-y))
common-obj-$(CONFIG_XEN_BACKEND) += xen_console.o
common-obj-$(CONFIG_CADENCE) += cadence_uart.o
+obj-$(CONFIG_EXYNOS4) += exynos4210_uart.o
+obj-$(CONFIG_COLDFIRE) += mcf_uart.o
+obj-$(CONFIG_OMAP) += omap_uart.o
+obj-$(CONFIG_SH4) += sh_serial.o
+obj-$(CONFIG_PSERIES) += spapr_vty.o
+
+common-obj-$(CONFIG_ETRAXFS) += etraxfs_ser.o
+common-obj-$(CONFIG_ISA_DEBUG) += debugcon.o
+common-obj-$(CONFIG_GRLIB) += grlib_apbuart.o
+common-obj-$(CONFIG_IMX) += imx_serial.o
+common-obj-$(CONFIG_LM32) += lm32_juart.o
+common-obj-$(CONFIG_LM32) += lm32_uart.o
+common-obj-$(CONFIG_MILKYMIST) += milkymist-uart.o
+common-obj-$(CONFIG_SCLPCONSOLE) += sclpconsole.o
+
obj-$(CONFIG_VIRTIO) += virtio-serial-bus.o
--- /dev/null
+/*
+ * QEMU Bochs-style debug console ("port E9") emulation
+ *
+ * Copyright (c) 2003-2004 Fabrice Bellard
+ * Copyright (c) 2008 Citrix Systems, Inc.
+ * Copyright (c) Intel Corporation; author: H. Peter Anvin
+ *
+ * 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 "hw/hw.h"
+#include "char/char.h"
+#include "hw/isa/isa.h"
+#include "hw/i386/pc.h"
+
+#define TYPE_ISA_DEBUGCON_DEVICE "isa-debugcon"
+#define ISA_DEBUGCON_DEVICE(obj) \
+ OBJECT_CHECK(ISADebugconState, (obj), TYPE_ISA_DEBUGCON_DEVICE)
+
+//#define DEBUG_DEBUGCON
+
+typedef struct DebugconState {
+ MemoryRegion io;
+ CharDriverState *chr;
+ uint32_t readback;
+} DebugconState;
+
+typedef struct ISADebugconState {
+ ISADevice parent_obj;
+
+ uint32_t iobase;
+ DebugconState state;
+} ISADebugconState;
+
+static void debugcon_ioport_write(void *opaque, hwaddr addr, uint64_t val,
+ unsigned width)
+{
+ DebugconState *s = opaque;
+ unsigned char ch = val;
+
+#ifdef DEBUG_DEBUGCON
+ printf("debugcon: write addr=0x%04x val=0x%02x\n", addr, val);
+#endif
+
+ qemu_chr_fe_write(s->chr, &ch, 1);
+}
+
+
+static uint64_t debugcon_ioport_read(void *opaque, hwaddr addr, unsigned width)
+{
+ DebugconState *s = opaque;
+
+#ifdef DEBUG_DEBUGCON
+ printf("debugcon: read addr=0x%04x\n", addr);
+#endif
+
+ return s->readback;
+}
+
+static const MemoryRegionOps debugcon_ops = {
+ .read = debugcon_ioport_read,
+ .write = debugcon_ioport_write,
+ .valid.min_access_size = 1,
+ .valid.max_access_size = 1,
+ .endianness = DEVICE_LITTLE_ENDIAN,
+};
+
+static void debugcon_init_core(DebugconState *s)
+{
+ if (!s->chr) {
+ fprintf(stderr, "Can't create debugcon device, empty char device\n");
+ exit(1);
+ }
+
+ qemu_chr_add_handlers(s->chr, NULL, NULL, NULL, s);
+}
+
+static int debugcon_isa_initfn(ISADevice *dev)
+{
+ ISADebugconState *isa = ISA_DEBUGCON_DEVICE(dev);
+ DebugconState *s = &isa->state;
+
+ debugcon_init_core(s);
+ memory_region_init_io(&s->io, &debugcon_ops, s,
+ TYPE_ISA_DEBUGCON_DEVICE, 1);
+ memory_region_add_subregion(isa_address_space_io(dev),
+ isa->iobase, &s->io);
+ return 0;
+}
+
+static Property debugcon_isa_properties[] = {
+ DEFINE_PROP_HEX32("iobase", ISADebugconState, iobase, 0xe9),
+ DEFINE_PROP_CHR("chardev", ISADebugconState, state.chr),
+ DEFINE_PROP_HEX32("readback", ISADebugconState, state.readback, 0xe9),
+ DEFINE_PROP_END_OF_LIST(),
+};
+
+static void debugcon_isa_class_initfn(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ ISADeviceClass *ic = ISA_DEVICE_CLASS(klass);
+ ic->init = debugcon_isa_initfn;
+ dc->props = debugcon_isa_properties;
+}
+
+static const TypeInfo debugcon_isa_info = {
+ .name = TYPE_ISA_DEBUGCON_DEVICE,
+ .parent = TYPE_ISA_DEVICE,
+ .instance_size = sizeof(ISADebugconState),
+ .class_init = debugcon_isa_class_initfn,
+};
+
+static void debugcon_register_types(void)
+{
+ type_register_static(&debugcon_isa_info);
+}
+
+type_init(debugcon_register_types)
--- /dev/null
+/*
+ * QEMU ETRAX System Emulator
+ *
+ * Copyright (c) 2007 Edgar E. Iglesias, Axis Communications AB.
+ *
+ * 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 "hw/sysbus.h"
+#include "char/char.h"
+#include "qemu/log.h"
+
+#define D(x)
+
+#define RW_TR_CTRL (0x00 / 4)
+#define RW_TR_DMA_EN (0x04 / 4)
+#define RW_REC_CTRL (0x08 / 4)
+#define RW_DOUT (0x1c / 4)
+#define RS_STAT_DIN (0x20 / 4)
+#define R_STAT_DIN (0x24 / 4)
+#define RW_INTR_MASK (0x2c / 4)
+#define RW_ACK_INTR (0x30 / 4)
+#define R_INTR (0x34 / 4)
+#define R_MASKED_INTR (0x38 / 4)
+#define R_MAX (0x3c / 4)
+
+#define STAT_DAV 16
+#define STAT_TR_IDLE 22
+#define STAT_TR_RDY 24
+
+struct etrax_serial
+{
+ SysBusDevice busdev;
+ MemoryRegion mmio;
+ CharDriverState *chr;
+ qemu_irq irq;
+
+ int pending_tx;
+
+ uint8_t rx_fifo[16];
+ unsigned int rx_fifo_pos;
+ unsigned int rx_fifo_len;
+
+ /* Control registers. */
+ uint32_t regs[R_MAX];
+};
+
+static void ser_update_irq(struct etrax_serial *s)
+{
+
+ if (s->rx_fifo_len) {
+ s->regs[R_INTR] |= 8;
+ } else {
+ s->regs[R_INTR] &= ~8;
+ }
+
+ s->regs[R_MASKED_INTR] = s->regs[R_INTR] & s->regs[RW_INTR_MASK];
+ qemu_set_irq(s->irq, !!s->regs[R_MASKED_INTR]);
+}
+
+static uint64_t
+ser_read(void *opaque, hwaddr addr, unsigned int size)
+{
+ struct etrax_serial *s = opaque;
+ uint32_t r = 0;
+
+ addr >>= 2;
+ switch (addr)
+ {
+ case R_STAT_DIN:
+ r = s->rx_fifo[(s->rx_fifo_pos - s->rx_fifo_len) & 15];
+ if (s->rx_fifo_len) {
+ r |= 1 << STAT_DAV;
+ }
+ r |= 1 << STAT_TR_RDY;
+ r |= 1 << STAT_TR_IDLE;
+ break;
+ case RS_STAT_DIN:
+ r = s->rx_fifo[(s->rx_fifo_pos - s->rx_fifo_len) & 15];
+ if (s->rx_fifo_len) {
+ r |= 1 << STAT_DAV;
+ s->rx_fifo_len--;
+ }
+ r |= 1 << STAT_TR_RDY;
+ r |= 1 << STAT_TR_IDLE;
+ break;
+ default:
+ r = s->regs[addr];
+ D(qemu_log("%s " TARGET_FMT_plx "=%x\n", __func__, addr, r));
+ break;
+ }
+ return r;
+}
+
+static void
+ser_write(void *opaque, hwaddr addr,
+ uint64_t val64, unsigned int size)
+{
+ struct etrax_serial *s = opaque;
+ uint32_t value = val64;
+ unsigned char ch = val64;
+
+ D(qemu_log("%s " TARGET_FMT_plx "=%x\n", __func__, addr, value));
+ addr >>= 2;
+ switch (addr)
+ {
+ case RW_DOUT:
+ qemu_chr_fe_write(s->chr, &ch, 1);
+ s->regs[R_INTR] |= 3;
+ s->pending_tx = 1;
+ s->regs[addr] = value;
+ break;
+ case RW_ACK_INTR:
+ if (s->pending_tx) {
+ value &= ~1;
+ s->pending_tx = 0;
+ D(qemu_log("fixedup value=%x r_intr=%x\n",
+ value, s->regs[R_INTR]));
+ }
+ s->regs[addr] = value;
+ s->regs[R_INTR] &= ~value;
+ D(printf("r_intr=%x\n", s->regs[R_INTR]));
+ break;
+ default:
+ s->regs[addr] = value;
+ break;
+ }
+ ser_update_irq(s);
+}
+
+static const MemoryRegionOps ser_ops = {
+ .read = ser_read,
+ .write = ser_write,
+ .endianness = DEVICE_NATIVE_ENDIAN,
+ .valid = {
+ .min_access_size = 4,
+ .max_access_size = 4
+ }
+};
+
+static void serial_receive(void *opaque, const uint8_t *buf, int size)
+{
+ struct etrax_serial *s = opaque;
+ int i;
+
+ /* Got a byte. */
+ if (s->rx_fifo_len >= 16) {
+ qemu_log("WARNING: UART dropped char.\n");
+ return;
+ }
+
+ for (i = 0; i < size; i++) {
+ s->rx_fifo[s->rx_fifo_pos] = buf[i];
+ s->rx_fifo_pos++;
+ s->rx_fifo_pos &= 15;
+ s->rx_fifo_len++;
+ }
+
+ ser_update_irq(s);
+}
+
+static int serial_can_receive(void *opaque)
+{
+ struct etrax_serial *s = opaque;
+ int r;
+
+ /* Is the receiver enabled? */
+ if (!(s->regs[RW_REC_CTRL] & (1 << 3))) {
+ return 0;
+ }
+
+ r = sizeof(s->rx_fifo) - s->rx_fifo_len;
+ return r;
+}
+
+static void serial_event(void *opaque, int event)
+{
+
+}
+
+static void etraxfs_ser_reset(DeviceState *d)
+{
+ struct etrax_serial *s = container_of(d, typeof(*s), busdev.qdev);
+
+ /* transmitter begins ready and idle. */
+ s->regs[RS_STAT_DIN] |= (1 << STAT_TR_RDY);
+ s->regs[RS_STAT_DIN] |= (1 << STAT_TR_IDLE);
+
+ s->regs[RW_REC_CTRL] = 0x10000;
+
+}
+
+static int etraxfs_ser_init(SysBusDevice *dev)
+{
+ struct etrax_serial *s = FROM_SYSBUS(typeof (*s), dev);
+
+ sysbus_init_irq(dev, &s->irq);
+ memory_region_init_io(&s->mmio, &ser_ops, s, "etraxfs-serial", R_MAX * 4);
+ sysbus_init_mmio(dev, &s->mmio);
+
+ s->chr = qemu_char_get_next_serial();
+ if (s->chr)
+ qemu_chr_add_handlers(s->chr,
+ serial_can_receive, serial_receive,
+ serial_event, s);
+ return 0;
+}
+
+static void etraxfs_ser_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+ k->init = etraxfs_ser_init;
+ dc->reset = etraxfs_ser_reset;
+}
+
+static const TypeInfo etraxfs_ser_info = {
+ .name = "etraxfs,serial",
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(struct etrax_serial),
+ .class_init = etraxfs_ser_class_init,
+};
+
+static void etraxfs_serial_register_types(void)
+{
+ type_register_static(&etraxfs_ser_info);
+}
+
+type_init(etraxfs_serial_register_types)
--- /dev/null
+/*
+ * Exynos4210 UART Emulation
+ *
+ * Copyright (C) 2011 Samsung Electronics Co Ltd.
+ * Maksim Kozlov, <m.kozlov@samsung.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include "hw/sysbus.h"
+#include "sysemu/sysemu.h"
+#include "char/char.h"
+
+#include "hw/arm/exynos4210.h"
+
+#undef DEBUG_UART
+#undef DEBUG_UART_EXTEND
+#undef DEBUG_IRQ
+#undef DEBUG_Rx_DATA
+#undef DEBUG_Tx_DATA
+
+#define DEBUG_UART 0
+#define DEBUG_UART_EXTEND 0
+#define DEBUG_IRQ 0
+#define DEBUG_Rx_DATA 0
+#define DEBUG_Tx_DATA 0
+
+#if DEBUG_UART
+#define PRINT_DEBUG(fmt, args...) \
+ do { \
+ fprintf(stderr, " [%s:%d] "fmt, __func__, __LINE__, ##args); \
+ } while (0)
+
+#if DEBUG_UART_EXTEND
+#define PRINT_DEBUG_EXTEND(fmt, args...) \
+ do { \
+ fprintf(stderr, " [%s:%d] "fmt, __func__, __LINE__, ##args); \
+ } while (0)
+#else
+#define PRINT_DEBUG_EXTEND(fmt, args...) \
+ do {} while (0)
+#endif /* EXTEND */
+
+#else
+#define PRINT_DEBUG(fmt, args...) \
+ do {} while (0)
+#define PRINT_DEBUG_EXTEND(fmt, args...) \
+ do {} while (0)
+#endif
+
+#define PRINT_ERROR(fmt, args...) \
+ do { \
+ fprintf(stderr, " [%s:%d] "fmt, __func__, __LINE__, ##args); \
+ } while (0)
+
+/*
+ * Offsets for UART registers relative to SFR base address
+ * for UARTn
+ *
+ */
+#define ULCON 0x0000 /* Line Control */
+#define UCON 0x0004 /* Control */
+#define UFCON 0x0008 /* FIFO Control */
+#define UMCON 0x000C /* Modem Control */
+#define UTRSTAT 0x0010 /* Tx/Rx Status */
+#define UERSTAT 0x0014 /* UART Error Status */
+#define UFSTAT 0x0018 /* FIFO Status */
+#define UMSTAT 0x001C /* Modem Status */
+#define UTXH 0x0020 /* Transmit Buffer */
+#define URXH 0x0024 /* Receive Buffer */
+#define UBRDIV 0x0028 /* Baud Rate Divisor */
+#define UFRACVAL 0x002C /* Divisor Fractional Value */
+#define UINTP 0x0030 /* Interrupt Pending */
+#define UINTSP 0x0034 /* Interrupt Source Pending */
+#define UINTM 0x0038 /* Interrupt Mask */
+
+/*
+ * for indexing register in the uint32_t array
+ *
+ * 'reg' - register offset (see offsets definitions above)
+ *
+ */
+#define I_(reg) (reg / sizeof(uint32_t))
+
+typedef struct Exynos4210UartReg {
+ const char *name; /* the only reason is the debug output */
+ hwaddr offset;
+ uint32_t reset_value;
+} Exynos4210UartReg;
+
+static Exynos4210UartReg exynos4210_uart_regs[] = {
+ {"ULCON", ULCON, 0x00000000},
+ {"UCON", UCON, 0x00003000},
+ {"UFCON", UFCON, 0x00000000},
+ {"UMCON", UMCON, 0x00000000},
+ {"UTRSTAT", UTRSTAT, 0x00000006}, /* RO */
+ {"UERSTAT", UERSTAT, 0x00000000}, /* RO */
+ {"UFSTAT", UFSTAT, 0x00000000}, /* RO */
+ {"UMSTAT", UMSTAT, 0x00000000}, /* RO */
+ {"UTXH", UTXH, 0x5c5c5c5c}, /* WO, undefined reset value*/
+ {"URXH", URXH, 0x00000000}, /* RO */
+ {"UBRDIV", UBRDIV, 0x00000000},
+ {"UFRACVAL", UFRACVAL, 0x00000000},
+ {"UINTP", UINTP, 0x00000000},
+ {"UINTSP", UINTSP, 0x00000000},
+ {"UINTM", UINTM, 0x00000000},
+};
+
+#define EXYNOS4210_UART_REGS_MEM_SIZE 0x3C
+
+/* UART FIFO Control */
+#define UFCON_FIFO_ENABLE 0x1
+#define UFCON_Rx_FIFO_RESET 0x2
+#define UFCON_Tx_FIFO_RESET 0x4
+#define UFCON_Tx_FIFO_TRIGGER_LEVEL_SHIFT 8
+#define UFCON_Tx_FIFO_TRIGGER_LEVEL (7 << UFCON_Tx_FIFO_TRIGGER_LEVEL_SHIFT)
+#define UFCON_Rx_FIFO_TRIGGER_LEVEL_SHIFT 4
+#define UFCON_Rx_FIFO_TRIGGER_LEVEL (7 << UFCON_Rx_FIFO_TRIGGER_LEVEL_SHIFT)
+
+/* Uart FIFO Status */
+#define UFSTAT_Rx_FIFO_COUNT 0xff
+#define UFSTAT_Rx_FIFO_FULL 0x100
+#define UFSTAT_Rx_FIFO_ERROR 0x200
+#define UFSTAT_Tx_FIFO_COUNT_SHIFT 16
+#define UFSTAT_Tx_FIFO_COUNT (0xff << UFSTAT_Tx_FIFO_COUNT_SHIFT)
+#define UFSTAT_Tx_FIFO_FULL_SHIFT 24
+#define UFSTAT_Tx_FIFO_FULL (1 << UFSTAT_Tx_FIFO_FULL_SHIFT)
+
+/* UART Interrupt Source Pending */
+#define UINTSP_RXD 0x1 /* Receive interrupt */
+#define UINTSP_ERROR 0x2 /* Error interrupt */
+#define UINTSP_TXD 0x4 /* Transmit interrupt */
+#define UINTSP_MODEM 0x8 /* Modem interrupt */
+
+/* UART Line Control */
+#define ULCON_IR_MODE_SHIFT 6
+#define ULCON_PARITY_SHIFT 3
+#define ULCON_STOP_BIT_SHIFT 1
+
+/* UART Tx/Rx Status */
+#define UTRSTAT_TRANSMITTER_EMPTY 0x4
+#define UTRSTAT_Tx_BUFFER_EMPTY 0x2
+#define UTRSTAT_Rx_BUFFER_DATA_READY 0x1
+
+/* UART Error Status */
+#define UERSTAT_OVERRUN 0x1
+#define UERSTAT_PARITY 0x2
+#define UERSTAT_FRAME 0x4
+#define UERSTAT_BREAK 0x8
+
+typedef struct {
+ uint8_t *data;
+ uint32_t sp, rp; /* store and retrieve pointers */
+ uint32_t size;
+} Exynos4210UartFIFO;
+
+typedef struct {
+ SysBusDevice busdev;
+ MemoryRegion iomem;
+
+ uint32_t reg[EXYNOS4210_UART_REGS_MEM_SIZE / sizeof(uint32_t)];
+ Exynos4210UartFIFO rx;
+ Exynos4210UartFIFO tx;
+
+ CharDriverState *chr;
+ qemu_irq irq;
+
+ uint32_t channel;
+
+} Exynos4210UartState;
+
+
+#if DEBUG_UART
+/* Used only for debugging inside PRINT_DEBUG_... macros */
+static const char *exynos4210_uart_regname(hwaddr offset)
+{
+
+ int regs_number = sizeof(exynos4210_uart_regs) / sizeof(Exynos4210UartReg);
+ int i;
+
+ for (i = 0; i < regs_number; i++) {
+ if (offset == exynos4210_uart_regs[i].offset) {
+ return exynos4210_uart_regs[i].name;
+ }
+ }
+
+ return NULL;
+}
+#endif
+
+
+static void fifo_store(Exynos4210UartFIFO *q, uint8_t ch)
+{
+ q->data[q->sp] = ch;
+ q->sp = (q->sp + 1) % q->size;
+}
+
+static uint8_t fifo_retrieve(Exynos4210UartFIFO *q)
+{
+ uint8_t ret = q->data[q->rp];
+ q->rp = (q->rp + 1) % q->size;
+ return ret;
+}
+
+static int fifo_elements_number(Exynos4210UartFIFO *q)
+{
+ if (q->sp < q->rp) {
+ return q->size - q->rp + q->sp;
+ }
+
+ return q->sp - q->rp;
+}
+
+static int fifo_empty_elements_number(Exynos4210UartFIFO *q)
+{
+ return q->size - fifo_elements_number(q);
+}
+
+static void fifo_reset(Exynos4210UartFIFO *q)
+{
+ if (q->data != NULL) {
+ g_free(q->data);
+ q->data = NULL;
+ }
+
+ q->data = (uint8_t *)g_malloc0(q->size);
+
+ q->sp = 0;
+ q->rp = 0;
+}
+
+static uint32_t exynos4210_uart_Tx_FIFO_trigger_level(Exynos4210UartState *s)
+{
+ uint32_t level = 0;
+ uint32_t reg;
+
+ reg = (s->reg[I_(UFCON)] & UFCON_Tx_FIFO_TRIGGER_LEVEL) >>
+ UFCON_Tx_FIFO_TRIGGER_LEVEL_SHIFT;
+
+ switch (s->channel) {
+ case 0:
+ level = reg * 32;
+ break;
+ case 1:
+ case 4:
+ level = reg * 8;
+ break;
+ case 2:
+ case 3:
+ level = reg * 2;
+ break;
+ default:
+ level = 0;
+ PRINT_ERROR("Wrong UART channel number: %d\n", s->channel);
+ }
+
+ return level;
+}
+
+static void exynos4210_uart_update_irq(Exynos4210UartState *s)
+{
+ /*
+ * The Tx interrupt is always requested if the number of data in the
+ * transmit FIFO is smaller than the trigger level.
+ */
+ if (s->reg[I_(UFCON)] & UFCON_FIFO_ENABLE) {
+
+ uint32_t count = (s->reg[I_(UFSTAT)] & UFSTAT_Tx_FIFO_COUNT) >>
+ UFSTAT_Tx_FIFO_COUNT_SHIFT;
+
+ if (count <= exynos4210_uart_Tx_FIFO_trigger_level(s)) {
+ s->reg[I_(UINTSP)] |= UINTSP_TXD;
+ }
+ }
+
+ s->reg[I_(UINTP)] = s->reg[I_(UINTSP)] & ~s->reg[I_(UINTM)];
+
+ if (s->reg[I_(UINTP)]) {
+ qemu_irq_raise(s->irq);
+
+#if DEBUG_IRQ
+ fprintf(stderr, "UART%d: IRQ has been raised: %08x\n",
+ s->channel, s->reg[I_(UINTP)]);
+#endif
+
+ } else {
+ qemu_irq_lower(s->irq);
+ }
+}
+
+static void exynos4210_uart_update_parameters(Exynos4210UartState *s)
+{
+ int speed, parity, data_bits, stop_bits, frame_size;
+ QEMUSerialSetParams ssp;
+ uint64_t uclk_rate;
+
+ if (s->reg[I_(UBRDIV)] == 0) {
+ return;
+ }
+
+ frame_size = 1; /* start bit */
+ if (s->reg[I_(ULCON)] & 0x20) {
+ frame_size++; /* parity bit */
+ if (s->reg[I_(ULCON)] & 0x28) {
+ parity = 'E';
+ } else {
+ parity = 'O';
+ }
+ } else {
+ parity = 'N';
+ }
+
+ if (s->reg[I_(ULCON)] & 0x4) {
+ stop_bits = 2;
+ } else {
+ stop_bits = 1;
+ }
+
+ data_bits = (s->reg[I_(ULCON)] & 0x3) + 5;
+
+ frame_size += data_bits + stop_bits;
+
+ uclk_rate = 24000000;
+
+ speed = uclk_rate / ((16 * (s->reg[I_(UBRDIV)]) & 0xffff) +
+ (s->reg[I_(UFRACVAL)] & 0x7) + 16);
+
+ ssp.speed = speed;
+ ssp.parity = parity;
+ ssp.data_bits = data_bits;
+ ssp.stop_bits = stop_bits;
+
+ qemu_chr_fe_ioctl(s->chr, CHR_IOCTL_SERIAL_SET_PARAMS, &ssp);
+
+ PRINT_DEBUG("UART%d: speed: %d, parity: %c, data: %d, stop: %d\n",
+ s->channel, speed, parity, data_bits, stop_bits);
+}
+
+static void exynos4210_uart_write(void *opaque, hwaddr offset,
+ uint64_t val, unsigned size)
+{
+ Exynos4210UartState *s = (Exynos4210UartState *)opaque;
+ uint8_t ch;
+
+ PRINT_DEBUG_EXTEND("UART%d: <0x%04x> %s <- 0x%08llx\n", s->channel,
+ offset, exynos4210_uart_regname(offset), (long long unsigned int)val);
+
+ switch (offset) {
+ case ULCON:
+ case UBRDIV:
+ case UFRACVAL:
+ s->reg[I_(offset)] = val;
+ exynos4210_uart_update_parameters(s);
+ break;
+ case UFCON:
+ s->reg[I_(UFCON)] = val;
+ if (val & UFCON_Rx_FIFO_RESET) {
+ fifo_reset(&s->rx);
+ s->reg[I_(UFCON)] &= ~UFCON_Rx_FIFO_RESET;
+ PRINT_DEBUG("UART%d: Rx FIFO Reset\n", s->channel);
+ }
+ if (val & UFCON_Tx_FIFO_RESET) {
+ fifo_reset(&s->tx);
+ s->reg[I_(UFCON)] &= ~UFCON_Tx_FIFO_RESET;
+ PRINT_DEBUG("UART%d: Tx FIFO Reset\n", s->channel);
+ }
+ break;
+
+ case UTXH:
+ if (s->chr) {
+ s->reg[I_(UTRSTAT)] &= ~(UTRSTAT_TRANSMITTER_EMPTY |
+ UTRSTAT_Tx_BUFFER_EMPTY);
+ ch = (uint8_t)val;
+ qemu_chr_fe_write(s->chr, &ch, 1);
+#if DEBUG_Tx_DATA
+ fprintf(stderr, "%c", ch);
+#endif
+ s->reg[I_(UTRSTAT)] |= UTRSTAT_TRANSMITTER_EMPTY |
+ UTRSTAT_Tx_BUFFER_EMPTY;
+ s->reg[I_(UINTSP)] |= UINTSP_TXD;
+ exynos4210_uart_update_irq(s);
+ }
+ break;
+
+ case UINTP:
+ s->reg[I_(UINTP)] &= ~val;
+ s->reg[I_(UINTSP)] &= ~val;
+ PRINT_DEBUG("UART%d: UINTP [%04x] have been cleared: %08x\n",
+ s->channel, offset, s->reg[I_(UINTP)]);
+ exynos4210_uart_update_irq(s);
+ break;
+ case UTRSTAT:
+ case UERSTAT:
+ case UFSTAT:
+ case UMSTAT:
+ case URXH:
+ PRINT_DEBUG("UART%d: Trying to write into RO register: %s [%04x]\n",
+ s->channel, exynos4210_uart_regname(offset), offset);
+ break;
+ case UINTSP:
+ s->reg[I_(UINTSP)] &= ~val;
+ break;
+ case UINTM:
+ s->reg[I_(UINTM)] = val;
+ exynos4210_uart_update_irq(s);
+ break;
+ case UCON:
+ case UMCON:
+ default:
+ s->reg[I_(offset)] = val;
+ break;
+ }
+}
+static uint64_t exynos4210_uart_read(void *opaque, hwaddr offset,
+ unsigned size)
+{
+ Exynos4210UartState *s = (Exynos4210UartState *)opaque;
+ uint32_t res;
+
+ switch (offset) {
+ case UERSTAT: /* Read Only */
+ res = s->reg[I_(UERSTAT)];
+ s->reg[I_(UERSTAT)] = 0;
+ return res;
+ case UFSTAT: /* Read Only */
+ s->reg[I_(UFSTAT)] = fifo_elements_number(&s->rx) & 0xff;
+ if (fifo_empty_elements_number(&s->rx) == 0) {
+ s->reg[I_(UFSTAT)] |= UFSTAT_Rx_FIFO_FULL;
+ s->reg[I_(UFSTAT)] &= ~0xff;
+ }
+ return s->reg[I_(UFSTAT)];
+ case URXH:
+ if (s->reg[I_(UFCON)] & UFCON_FIFO_ENABLE) {
+ if (fifo_elements_number(&s->rx)) {
+ res = fifo_retrieve(&s->rx);
+#if DEBUG_Rx_DATA
+ fprintf(stderr, "%c", res);
+#endif
+ if (!fifo_elements_number(&s->rx)) {
+ s->reg[I_(UTRSTAT)] &= ~UTRSTAT_Rx_BUFFER_DATA_READY;
+ } else {
+ s->reg[I_(UTRSTAT)] |= UTRSTAT_Rx_BUFFER_DATA_READY;
+ }
+ } else {
+ s->reg[I_(UINTSP)] |= UINTSP_ERROR;
+ exynos4210_uart_update_irq(s);
+ res = 0;
+ }
+ } else {
+ s->reg[I_(UTRSTAT)] &= ~UTRSTAT_Rx_BUFFER_DATA_READY;
+ res = s->reg[I_(URXH)];
+ }
+ return res;
+ case UTXH:
+ PRINT_DEBUG("UART%d: Trying to read from WO register: %s [%04x]\n",
+ s->channel, exynos4210_uart_regname(offset), offset);
+ break;
+ default:
+ return s->reg[I_(offset)];
+ }
+
+ return 0;
+}
+
+static const MemoryRegionOps exynos4210_uart_ops = {
+ .read = exynos4210_uart_read,
+ .write = exynos4210_uart_write,
+ .endianness = DEVICE_NATIVE_ENDIAN,
+ .valid = {
+ .max_access_size = 4,
+ .unaligned = false
+ },
+};
+
+static int exynos4210_uart_can_receive(void *opaque)
+{
+ Exynos4210UartState *s = (Exynos4210UartState *)opaque;
+
+ return fifo_empty_elements_number(&s->rx);
+}
+
+
+static void exynos4210_uart_receive(void *opaque, const uint8_t *buf, int size)
+{
+ Exynos4210UartState *s = (Exynos4210UartState *)opaque;
+ int i;
+
+ if (s->reg[I_(UFCON)] & UFCON_FIFO_ENABLE) {
+ if (fifo_empty_elements_number(&s->rx) < size) {
+ for (i = 0; i < fifo_empty_elements_number(&s->rx); i++) {
+ fifo_store(&s->rx, buf[i]);
+ }
+ s->reg[I_(UINTSP)] |= UINTSP_ERROR;
+ s->reg[I_(UTRSTAT)] |= UTRSTAT_Rx_BUFFER_DATA_READY;
+ } else {
+ for (i = 0; i < size; i++) {
+ fifo_store(&s->rx, buf[i]);
+ }
+ s->reg[I_(UTRSTAT)] |= UTRSTAT_Rx_BUFFER_DATA_READY;
+ }
+ /* XXX: Around here we maybe should check Rx trigger level */
+ s->reg[I_(UINTSP)] |= UINTSP_RXD;
+ } else {
+ s->reg[I_(URXH)] = buf[0];
+ s->reg[I_(UINTSP)] |= UINTSP_RXD;
+ s->reg[I_(UTRSTAT)] |= UTRSTAT_Rx_BUFFER_DATA_READY;
+ }
+
+ exynos4210_uart_update_irq(s);
+}
+
+
+static void exynos4210_uart_event(void *opaque, int event)
+{
+ Exynos4210UartState *s = (Exynos4210UartState *)opaque;
+
+ if (event == CHR_EVENT_BREAK) {
+ /* When the RxDn is held in logic 0, then a null byte is pushed into the
+ * fifo */
+ fifo_store(&s->rx, '\0');
+ s->reg[I_(UERSTAT)] |= UERSTAT_BREAK;
+ exynos4210_uart_update_irq(s);
+ }
+}
+
+
+static void exynos4210_uart_reset(DeviceState *dev)
+{
+ Exynos4210UartState *s =
+ container_of(dev, Exynos4210UartState, busdev.qdev);
+ int regs_number = sizeof(exynos4210_uart_regs)/sizeof(Exynos4210UartReg);
+ int i;
+
+ for (i = 0; i < regs_number; i++) {
+ s->reg[I_(exynos4210_uart_regs[i].offset)] =
+ exynos4210_uart_regs[i].reset_value;
+ }
+
+ fifo_reset(&s->rx);
+ fifo_reset(&s->tx);
+
+ PRINT_DEBUG("UART%d: Rx FIFO size: %d\n", s->channel, s->rx.size);
+}
+
+static const VMStateDescription vmstate_exynos4210_uart_fifo = {
+ .name = "exynos4210.uart.fifo",
+ .version_id = 1,
+ .minimum_version_id = 1,
+ .minimum_version_id_old = 1,
+ .fields = (VMStateField[]) {
+ VMSTATE_UINT32(sp, Exynos4210UartFIFO),
+ VMSTATE_UINT32(rp, Exynos4210UartFIFO),
+ VMSTATE_VBUFFER_UINT32(data, Exynos4210UartFIFO, 1, NULL, 0, size),
+ VMSTATE_END_OF_LIST()
+ }
+};
+
+static const VMStateDescription vmstate_exynos4210_uart = {
+ .name = "exynos4210.uart",
+ .version_id = 1,
+ .minimum_version_id = 1,
+ .minimum_version_id_old = 1,
+ .fields = (VMStateField[]) {
+ VMSTATE_STRUCT(rx, Exynos4210UartState, 1,
+ vmstate_exynos4210_uart_fifo, Exynos4210UartFIFO),
+ VMSTATE_UINT32_ARRAY(reg, Exynos4210UartState,
+ EXYNOS4210_UART_REGS_MEM_SIZE / sizeof(uint32_t)),
+ VMSTATE_END_OF_LIST()
+ }
+};
+
+DeviceState *exynos4210_uart_create(hwaddr addr,
+ int fifo_size,
+ int channel,
+ CharDriverState *chr,
+ qemu_irq irq)
+{
+ DeviceState *dev;
+ SysBusDevice *bus;
+
+ const char chr_name[] = "serial";
+ char label[ARRAY_SIZE(chr_name) + 1];
+
+ dev = qdev_create(NULL, "exynos4210.uart");
+
+ if (!chr) {
+ if (channel >= MAX_SERIAL_PORTS) {
+ hw_error("Only %d serial ports are supported by QEMU.\n",
+ MAX_SERIAL_PORTS);
+ }
+ chr = serial_hds[channel];
+ if (!chr) {
+ snprintf(label, ARRAY_SIZE(label), "%s%d", chr_name, channel);
+ chr = qemu_chr_new(label, "null", NULL);
+ if (!(chr)) {
+ hw_error("Can't assign serial port to UART%d.\n", channel);
+ }
+ }
+ }
+
+ qdev_prop_set_chr(dev, "chardev", chr);
+ qdev_prop_set_uint32(dev, "channel", channel);
+ qdev_prop_set_uint32(dev, "rx-size", fifo_size);
+ qdev_prop_set_uint32(dev, "tx-size", fifo_size);
+
+ bus = SYS_BUS_DEVICE(dev);
+ qdev_init_nofail(dev);
+ if (addr != (hwaddr)-1) {
+ sysbus_mmio_map(bus, 0, addr);
+ }
+ sysbus_connect_irq(bus, 0, irq);
+
+ return dev;
+}
+
+static int exynos4210_uart_init(SysBusDevice *dev)
+{
+ Exynos4210UartState *s = FROM_SYSBUS(Exynos4210UartState, dev);
+
+ /* memory mapping */
+ memory_region_init_io(&s->iomem, &exynos4210_uart_ops, s, "exynos4210.uart",
+ EXYNOS4210_UART_REGS_MEM_SIZE);
+ sysbus_init_mmio(dev, &s->iomem);
+
+ sysbus_init_irq(dev, &s->irq);
+
+ qemu_chr_add_handlers(s->chr, exynos4210_uart_can_receive,
+ exynos4210_uart_receive, exynos4210_uart_event, s);
+
+ return 0;
+}
+
+static Property exynos4210_uart_properties[] = {
+ DEFINE_PROP_CHR("chardev", Exynos4210UartState, chr),
+ DEFINE_PROP_UINT32("channel", Exynos4210UartState, channel, 0),
+ DEFINE_PROP_UINT32("rx-size", Exynos4210UartState, rx.size, 16),
+ DEFINE_PROP_UINT32("tx-size", Exynos4210UartState, tx.size, 16),
+ DEFINE_PROP_END_OF_LIST(),
+};
+
+static void exynos4210_uart_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+ k->init = exynos4210_uart_init;
+ dc->reset = exynos4210_uart_reset;
+ dc->props = exynos4210_uart_properties;
+ dc->vmsd = &vmstate_exynos4210_uart;
+}
+
+static const TypeInfo exynos4210_uart_info = {
+ .name = "exynos4210.uart",
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(Exynos4210UartState),
+ .class_init = exynos4210_uart_class_init,
+};
+
+static void exynos4210_uart_register(void)
+{
+ type_register_static(&exynos4210_uart_info);
+}
+
+type_init(exynos4210_uart_register)
--- /dev/null
+/*
+ * 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 "hw/sysbus.h"
+#include "char/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 */
+
+#define FIFO_LENGTH 1024
+
+typedef struct UART {
+ SysBusDevice busdev;
+ MemoryRegion iomem;
+ qemu_irq irq;
+
+ CharDriverState *chr;
+
+ /* registers */
+ uint32_t status;
+ uint32_t control;
+
+ /* FIFO */
+ char buffer[FIFO_LENGTH];
+ int len;
+ int current;
+} UART;
+
+static int uart_data_to_read(UART *uart)
+{
+ return uart->current < uart->len;
+}
+
+static char uart_pop(UART *uart)
+{
+ char ret;
+
+ if (uart->len == 0) {
+ uart->status &= ~UART_DATA_READY;
+ return 0;
+ }
+
+ ret = uart->buffer[uart->current++];
+
+ if (uart->current >= uart->len) {
+ /* Flush */
+ uart->len = 0;
+ uart->current = 0;
+ }
+
+ if (!uart_data_to_read(uart)) {
+ uart->status &= ~UART_DATA_READY;
+ }
+
+ return ret;
+}
+
+static void uart_add_to_fifo(UART *uart,
+ const uint8_t *buffer,
+ int length)
+{
+ if (uart->len + length > FIFO_LENGTH) {
+ abort();
+ }
+ memcpy(uart->buffer + uart->len, buffer, length);
+ uart->len += length;
+}
+
+static int grlib_apbuart_can_receive(void *opaque)
+{
+ UART *uart = opaque;
+
+ return FIFO_LENGTH - uart->len;
+}
+
+static void grlib_apbuart_receive(void *opaque, const uint8_t *buf, int size)
+{
+ UART *uart = opaque;
+
+ if (uart->control & UART_RECEIVE_ENABLE) {
+ uart_add_to_fifo(uart, buf, size);
+
+ 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 uint64_t grlib_apbuart_read(void *opaque, hwaddr addr,
+ unsigned size)
+{
+ UART *uart = opaque;
+
+ addr &= 0xff;
+
+ /* Unit registers */
+ switch (addr) {
+ case DATA_OFFSET:
+ case DATA_OFFSET + 3: /* when only one byte read */
+ return uart_pop(uart);
+
+ case STATUS_OFFSET:
+ /* Read Only */
+ return uart->status;
+
+ case CONTROL_OFFSET:
+ return uart->control;
+
+ case SCALER_OFFSET:
+ /* Not supported */
+ return 0;
+
+ default:
+ trace_grlib_apbuart_readl_unknown(addr);
+ return 0;
+ }
+}
+
+static void grlib_apbuart_write(void *opaque, hwaddr addr,
+ uint64_t value, unsigned size)
+{
+ UART *uart = opaque;
+ unsigned char c = 0;
+
+ addr &= 0xff;
+
+ /* Unit registers */
+ switch (addr) {
+ case DATA_OFFSET:
+ case DATA_OFFSET + 3: /* When only one byte write */
+ /* Transmit when character device available and transmitter enabled */
+ if ((uart->chr) && (uart->control & UART_TRANSMIT_ENABLE)) {
+ c = value & 0xFF;
+ qemu_chr_fe_write(uart->chr, &c, 1);
+ /* Generate interrupt */
+ if (uart->control & UART_TRANSMIT_INTERRUPT) {
+ qemu_irq_pulse(uart->irq);
+ }
+ }
+ return;
+
+ case STATUS_OFFSET:
+ /* Read Only */
+ return;
+
+ case CONTROL_OFFSET:
+ uart->control = value;
+ return;
+
+ case SCALER_OFFSET:
+ /* Not supported */
+ return;
+
+ default:
+ break;
+ }
+
+ trace_grlib_apbuart_writel_unknown(addr, value);
+}
+
+static const MemoryRegionOps grlib_apbuart_ops = {
+ .write = grlib_apbuart_write,
+ .read = grlib_apbuart_read,
+ .endianness = DEVICE_NATIVE_ENDIAN,
+};
+
+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);
+
+ memory_region_init_io(&uart->iomem, &grlib_apbuart_ops, uart,
+ "uart", UART_REG_SIZE);
+
+ sysbus_init_mmio(dev, &uart->iomem);
+
+ return 0;
+}
+
+static void grlib_apbuart_reset(DeviceState *d)
+{
+ UART *uart = container_of(d, UART, busdev.qdev);
+
+ /* Transmitter FIFO and shift registers are always empty in QEMU */
+ uart->status = UART_TRANSMIT_FIFO_EMPTY | UART_TRANSMIT_SHIFT_EMPTY;
+ /* Everything is off */
+ uart->control = 0;
+ /* Flush receive FIFO */
+ uart->len = 0;
+ uart->current = 0;
+}
+
+static Property grlib_apbuart_properties[] = {
+ DEFINE_PROP_CHR("chrdev", UART, chr),
+ DEFINE_PROP_END_OF_LIST(),
+};
+
+static void grlib_apbuart_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+ k->init = grlib_apbuart_init;
+ dc->reset = grlib_apbuart_reset;
+ dc->props = grlib_apbuart_properties;
+}
+
+static const TypeInfo grlib_apbuart_info = {
+ .name = "grlib,apbuart",
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(UART),
+ .class_init = grlib_apbuart_class_init,
+};
+
+static void grlib_apbuart_register_types(void)
+{
+ type_register_static(&grlib_apbuart_info);
+}
+
+type_init(grlib_apbuart_register_types)
--- /dev/null
+/*
+ * IMX31 UARTS
+ *
+ * Copyright (c) 2008 OKL
+ * Originally Written by Hans Jiang
+ * Copyright (c) 2011 NICTA Pty Ltd.
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ *
+ * This is a `bare-bones' implementation of the IMX series serial ports.
+ * TODO:
+ * -- implement FIFOs. The real hardware has 32 word transmit
+ * and receive FIFOs; we currently use a 1-char buffer
+ * -- implement DMA
+ * -- implement BAUD-rate and modem lines, for when the backend
+ * is a real serial device.
+ */
+
+#include "hw/hw.h"
+#include "hw/sysbus.h"
+#include "sysemu/sysemu.h"
+#include "char/char.h"
+#include "hw/arm/imx.h"
+
+//#define DEBUG_SERIAL 1
+#ifdef DEBUG_SERIAL
+#define DPRINTF(fmt, args...) \
+do { printf("imx_serial: " fmt , ##args); } while (0)
+#else
+#define DPRINTF(fmt, args...) do {} while (0)
+#endif
+
+/*
+ * Define to 1 for messages about attempts to
+ * access unimplemented registers or similar.
+ */
+//#define DEBUG_IMPLEMENTATION 1
+#ifdef DEBUG_IMPLEMENTATION
+# define IPRINTF(fmt, args...) \
+ do { fprintf(stderr, "imx_serial: " fmt, ##args); } while (0)
+#else
+# define IPRINTF(fmt, args...) do {} while (0)
+#endif
+
+typedef struct {
+ SysBusDevice busdev;
+ MemoryRegion iomem;
+ int32_t readbuff;
+
+ uint32_t usr1;
+ uint32_t usr2;
+ uint32_t ucr1;
+ uint32_t ucr2;
+ uint32_t uts1;
+
+ /*
+ * The registers below are implemented just so that the
+ * guest OS sees what it has written
+ */
+ uint32_t onems;
+ uint32_t ufcr;
+ uint32_t ubmr;
+ uint32_t ubrc;
+ uint32_t ucr3;
+
+ qemu_irq irq;
+ CharDriverState *chr;
+} IMXSerialState;
+
+static const VMStateDescription vmstate_imx_serial = {
+ .name = "imx-serial",
+ .version_id = 1,
+ .minimum_version_id = 1,
+ .minimum_version_id_old = 1,
+ .fields = (VMStateField[]) {
+ VMSTATE_INT32(readbuff, IMXSerialState),
+ VMSTATE_UINT32(usr1, IMXSerialState),
+ VMSTATE_UINT32(usr2, IMXSerialState),
+ VMSTATE_UINT32(ucr1, IMXSerialState),
+ VMSTATE_UINT32(uts1, IMXSerialState),
+ VMSTATE_UINT32(onems, IMXSerialState),
+ VMSTATE_UINT32(ufcr, IMXSerialState),
+ VMSTATE_UINT32(ubmr, IMXSerialState),
+ VMSTATE_UINT32(ubrc, IMXSerialState),
+ VMSTATE_UINT32(ucr3, IMXSerialState),
+ VMSTATE_END_OF_LIST()
+ },
+};
+
+
+#define URXD_CHARRDY (1<<15) /* character read is valid */
+#define URXD_ERR (1<<14) /* Character has error */
+#define URXD_BRK (1<<11) /* Break received */
+
+#define USR1_PARTYER (1<<15) /* Parity Error */
+#define USR1_RTSS (1<<14) /* RTS pin status */
+#define USR1_TRDY (1<<13) /* Tx ready */
+#define USR1_RTSD (1<<12) /* RTS delta: pin changed state */
+#define USR1_ESCF (1<<11) /* Escape sequence interrupt */
+#define USR1_FRAMERR (1<<10) /* Framing error */
+#define USR1_RRDY (1<<9) /* receiver ready */
+#define USR1_AGTIM (1<<8) /* Aging timer interrupt */
+#define USR1_DTRD (1<<7) /* DTR changed */
+#define USR1_RXDS (1<<6) /* Receiver is idle */
+#define USR1_AIRINT (1<<5) /* Aysnch IR interrupt */
+#define USR1_AWAKE (1<<4) /* Falling edge detected on RXd pin */
+
+#define USR2_ADET (1<<15) /* Autobaud complete */
+#define USR2_TXFE (1<<14) /* Transmit FIFO empty */
+#define USR2_DTRF (1<<13) /* DTR/DSR transition */
+#define USR2_IDLE (1<<12) /* UART has been idle for too long */
+#define USR2_ACST (1<<11) /* Autobaud counter stopped */
+#define USR2_RIDELT (1<<10) /* Ring Indicator delta */
+#define USR2_RIIN (1<<9) /* Ring Indicator Input */
+#define USR2_IRINT (1<<8) /* Serial Infrared Interrupt */
+#define USR2_WAKE (1<<7) /* Start bit detected */
+#define USR2_DCDDELT (1<<6) /* Data Carrier Detect delta */
+#define USR2_DCDIN (1<<5) /* Data Carrier Detect Input */
+#define USR2_RTSF (1<<4) /* RTS transition */
+#define USR2_TXDC (1<<3) /* Transmission complete */
+#define USR2_BRCD (1<<2) /* Break condition detected */
+#define USR2_ORE (1<<1) /* Overrun error */
+#define USR2_RDR (1<<0) /* Receive data ready */
+
+#define UCR1_TRDYEN (1<<13) /* Tx Ready Interrupt Enable */
+#define UCR1_RRDYEN (1<<9) /* Rx Ready Interrupt Enable */
+#define UCR1_TXMPTYEN (1<<6) /* Tx Empty Interrupt Enable */
+#define UCR1_UARTEN (1<<0) /* UART Enable */
+
+#define UCR2_TXEN (1<<2) /* Transmitter enable */
+#define UCR2_RXEN (1<<1) /* Receiver enable */
+#define UCR2_SRST (1<<0) /* Reset complete */
+
+#define UTS1_TXEMPTY (1<<6)
+#define UTS1_RXEMPTY (1<<5)
+#define UTS1_TXFULL (1<<4)
+#define UTS1_RXFULL (1<<3)
+
+static void imx_update(IMXSerialState *s)
+{
+ uint32_t flags;
+
+ flags = (s->usr1 & s->ucr1) & (USR1_TRDY|USR1_RRDY);
+ if (!(s->ucr1 & UCR1_TXMPTYEN)) {
+ flags &= ~USR1_TRDY;
+ }
+
+ qemu_set_irq(s->irq, !!flags);
+}
+
+static void imx_serial_reset(IMXSerialState *s)
+{
+
+ s->usr1 = USR1_TRDY | USR1_RXDS;
+ /*
+ * Fake attachment of a terminal: assert RTS.
+ */
+ s->usr1 |= USR1_RTSS;
+ s->usr2 = USR2_TXFE | USR2_TXDC | USR2_DCDIN;
+ s->uts1 = UTS1_RXEMPTY | UTS1_TXEMPTY;
+ s->ucr1 = 0;
+ s->ucr2 = UCR2_SRST;
+ s->ucr3 = 0x700;
+ s->ubmr = 0;
+ s->ubrc = 4;
+ s->readbuff = URXD_ERR;
+}
+
+static void imx_serial_reset_at_boot(DeviceState *dev)
+{
+ IMXSerialState *s = container_of(dev, IMXSerialState, busdev.qdev);
+
+ imx_serial_reset(s);
+
+ /*
+ * enable the uart on boot, so messages from the linux decompresser
+ * are visible. On real hardware this is done by the boot rom
+ * before anything else is loaded.
+ */
+ s->ucr1 = UCR1_UARTEN;
+ s->ucr2 = UCR2_TXEN;
+
+}
+
+static uint64_t imx_serial_read(void *opaque, hwaddr offset,
+ unsigned size)
+{
+ IMXSerialState *s = (IMXSerialState *)opaque;
+ uint32_t c;
+
+ DPRINTF("read(offset=%x)\n", offset >> 2);
+ switch (offset >> 2) {
+ case 0x0: /* URXD */
+ c = s->readbuff;
+ if (!(s->uts1 & UTS1_RXEMPTY)) {
+ /* Character is valid */
+ c |= URXD_CHARRDY;
+ s->usr1 &= ~USR1_RRDY;
+ s->usr2 &= ~USR2_RDR;
+ s->uts1 |= UTS1_RXEMPTY;
+ imx_update(s);
+ qemu_chr_accept_input(s->chr);
+ }
+ return c;
+
+ case 0x20: /* UCR1 */
+ return s->ucr1;
+
+ case 0x21: /* UCR2 */
+ return s->ucr2;
+
+ case 0x25: /* USR1 */
+ return s->usr1;
+
+ case 0x26: /* USR2 */
+ return s->usr2;
+
+ case 0x2A: /* BRM Modulator */
+ return s->ubmr;
+
+ case 0x2B: /* Baud Rate Count */
+ return s->ubrc;
+
+ case 0x2d: /* Test register */
+ return s->uts1;
+
+ case 0x24: /* UFCR */
+ return s->ufcr;
+
+ case 0x2c:
+ return s->onems;
+
+ case 0x22: /* UCR3 */
+ return s->ucr3;
+
+ case 0x23: /* UCR4 */
+ case 0x29: /* BRM Incremental */
+ return 0x0; /* TODO */
+
+ default:
+ IPRINTF("imx_serial_read: bad offset: 0x%x\n", (int)offset);
+ return 0;
+ }
+}
+
+static void imx_serial_write(void *opaque, hwaddr offset,
+ uint64_t value, unsigned size)
+{
+ IMXSerialState *s = (IMXSerialState *)opaque;
+ unsigned char ch;
+
+ DPRINTF("write(offset=%x, value = %x) to %s\n",
+ offset >> 2,
+ (unsigned int)value, s->chr ? s->chr->label : "NODEV");
+
+ switch (offset >> 2) {
+ case 0x10: /* UTXD */
+ ch = value;
+ if (s->ucr2 & UCR2_TXEN) {
+ if (s->chr) {
+ qemu_chr_fe_write(s->chr, &ch, 1);
+ }
+ s->usr1 &= ~USR1_TRDY;
+ imx_update(s);
+ s->usr1 |= USR1_TRDY;
+ imx_update(s);
+ }
+ break;
+
+ case 0x20: /* UCR1 */
+ s->ucr1 = value & 0xffff;
+ DPRINTF("write(ucr1=%x)\n", (unsigned int)value);
+ imx_update(s);
+ break;
+
+ case 0x21: /* UCR2 */
+ /*
+ * Only a few bits in control register 2 are implemented as yet.
+ * If it's intended to use a real serial device as a back-end, this
+ * register will have to be implemented more fully.
+ */
+ if (!(value & UCR2_SRST)) {
+ imx_serial_reset(s);
+ imx_update(s);
+ value |= UCR2_SRST;
+ }
+ if (value & UCR2_RXEN) {
+ if (!(s->ucr2 & UCR2_RXEN)) {
+ qemu_chr_accept_input(s->chr);
+ }
+ }
+ s->ucr2 = value & 0xffff;
+ break;
+
+ case 0x25: /* USR1 */
+ value &= USR1_AWAKE | USR1_AIRINT | USR1_DTRD | USR1_AGTIM |
+ USR1_FRAMERR | USR1_ESCF | USR1_RTSD | USR1_PARTYER;
+ s->usr1 &= ~value;
+ break;
+
+ case 0x26: /* USR2 */
+ /*
+ * Writing 1 to some bits clears them; all other
+ * values are ignored
+ */
+ value &= USR2_ADET | USR2_DTRF | USR2_IDLE | USR2_ACST |
+ USR2_RIDELT | USR2_IRINT | USR2_WAKE |
+ USR2_DCDDELT | USR2_RTSF | USR2_BRCD | USR2_ORE;
+ s->usr2 &= ~value;
+ break;
+
+ /*
+ * Linux expects to see what it writes to these registers
+ * We don't currently alter the baud rate
+ */
+ case 0x29: /* UBIR */
+ s->ubrc = value & 0xffff;
+ break;
+
+ case 0x2a: /* UBMR */
+ s->ubmr = value & 0xffff;
+ break;
+
+ case 0x2c: /* One ms reg */
+ s->onems = value & 0xffff;
+ break;
+
+ case 0x24: /* FIFO control register */
+ s->ufcr = value & 0xffff;
+ break;
+
+ case 0x22: /* UCR3 */
+ s->ucr3 = value & 0xffff;
+ break;
+
+ case 0x2d: /* UTS1 */
+ case 0x23: /* UCR4 */
+ IPRINTF("Unimplemented Register %x written to\n", offset >> 2);
+ /* TODO */
+ break;
+
+ default:
+ IPRINTF("imx_serial_write: Bad offset 0x%x\n", (int)offset);
+ }
+}
+
+static int imx_can_receive(void *opaque)
+{
+ IMXSerialState *s = (IMXSerialState *)opaque;
+ return !(s->usr1 & USR1_RRDY);
+}
+
+static void imx_put_data(void *opaque, uint32_t value)
+{
+ IMXSerialState *s = (IMXSerialState *)opaque;
+ DPRINTF("received char\n");
+ s->usr1 |= USR1_RRDY;
+ s->usr2 |= USR2_RDR;
+ s->uts1 &= ~UTS1_RXEMPTY;
+ s->readbuff = value;
+ imx_update(s);
+}
+
+static void imx_receive(void *opaque, const uint8_t *buf, int size)
+{
+ imx_put_data(opaque, *buf);
+}
+
+static void imx_event(void *opaque, int event)
+{
+ if (event == CHR_EVENT_BREAK) {
+ imx_put_data(opaque, URXD_BRK);
+ }
+}
+
+
+static const struct MemoryRegionOps imx_serial_ops = {
+ .read = imx_serial_read,
+ .write = imx_serial_write,
+ .endianness = DEVICE_NATIVE_ENDIAN,
+};
+
+static int imx_serial_init(SysBusDevice *dev)
+{
+ IMXSerialState *s = FROM_SYSBUS(IMXSerialState, dev);
+
+
+ memory_region_init_io(&s->iomem, &imx_serial_ops, s, "imx-serial", 0x1000);
+ sysbus_init_mmio(dev, &s->iomem);
+ sysbus_init_irq(dev, &s->irq);
+
+ if (s->chr) {
+ qemu_chr_add_handlers(s->chr, imx_can_receive, imx_receive,
+ imx_event, s);
+ } else {
+ DPRINTF("No char dev for uart at 0x%lx\n",
+ (unsigned long)s->iomem.ram_addr);
+ }
+
+ return 0;
+}
+
+void imx_serial_create(int uart, const hwaddr addr, qemu_irq irq)
+{
+ DeviceState *dev;
+ SysBusDevice *bus;
+ CharDriverState *chr;
+ const char chr_name[] = "serial";
+ char label[ARRAY_SIZE(chr_name) + 1];
+
+ dev = qdev_create(NULL, "imx-serial");
+
+ if (uart >= MAX_SERIAL_PORTS) {
+ hw_error("Cannot assign uart %d: QEMU supports only %d ports\n",
+ uart, MAX_SERIAL_PORTS);
+ }
+ chr = serial_hds[uart];
+ if (!chr) {
+ snprintf(label, ARRAY_SIZE(label), "%s%d", chr_name, uart);
+ chr = qemu_chr_new(label, "null", NULL);
+ if (!(chr)) {
+ hw_error("Can't assign serial port to imx-uart%d.\n", uart);
+ }
+ }
+
+ qdev_prop_set_chr(dev, "chardev", chr);
+ bus = SYS_BUS_DEVICE(dev);
+ qdev_init_nofail(dev);
+ if (addr != (hwaddr)-1) {
+ sysbus_mmio_map(bus, 0, addr);
+ }
+ sysbus_connect_irq(bus, 0, irq);
+
+}
+
+
+static Property imx32_serial_properties[] = {
+ DEFINE_PROP_CHR("chardev", IMXSerialState, chr),
+ DEFINE_PROP_END_OF_LIST(),
+};
+
+static void imx_serial_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+ k->init = imx_serial_init;
+ dc->vmsd = &vmstate_imx_serial;
+ dc->reset = imx_serial_reset_at_boot;
+ dc->desc = "i.MX series UART";
+ dc->props = imx32_serial_properties;
+}
+
+static const TypeInfo imx_serial_info = {
+ .name = "imx-serial",
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(IMXSerialState),
+ .class_init = imx_serial_class_init,
+};
+
+static void imx_serial_register_types(void)
+{
+ type_register_static(&imx_serial_info);
+}
+
+type_init(imx_serial_register_types)
--- /dev/null
+/*
+ * LatticeMico32 JTAG UART model.
+ *
+ * Copyright (c) 2010 Michael Walle <michael@walle.cc>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "hw/hw.h"
+#include "hw/sysbus.h"
+#include "trace.h"
+#include "char/char.h"
+
+#include "hw/lm32/lm32_juart.h"
+
+enum {
+ LM32_JUART_MIN_SAVE_VERSION = 0,
+ LM32_JUART_CURRENT_SAVE_VERSION = 0,
+ LM32_JUART_MAX_SAVE_VERSION = 0,
+};
+
+enum {
+ JTX_FULL = (1<<8),
+};
+
+enum {
+ JRX_FULL = (1<<8),
+};
+
+struct LM32JuartState {
+ SysBusDevice busdev;
+ CharDriverState *chr;
+
+ uint32_t jtx;
+ uint32_t jrx;
+};
+typedef struct LM32JuartState LM32JuartState;
+
+uint32_t lm32_juart_get_jtx(DeviceState *d)
+{
+ LM32JuartState *s = container_of(d, LM32JuartState, busdev.qdev);
+
+ trace_lm32_juart_get_jtx(s->jtx);
+ return s->jtx;
+}
+
+uint32_t lm32_juart_get_jrx(DeviceState *d)
+{
+ LM32JuartState *s = container_of(d, LM32JuartState, busdev.qdev);
+
+ trace_lm32_juart_get_jrx(s->jrx);
+ return s->jrx;
+}
+
+void lm32_juart_set_jtx(DeviceState *d, uint32_t jtx)
+{
+ LM32JuartState *s = container_of(d, LM32JuartState, busdev.qdev);
+ unsigned char ch = jtx & 0xff;
+
+ trace_lm32_juart_set_jtx(s->jtx);
+
+ s->jtx = jtx;
+ if (s->chr) {
+ qemu_chr_fe_write(s->chr, &ch, 1);
+ }
+}
+
+void lm32_juart_set_jrx(DeviceState *d, uint32_t jtx)
+{
+ LM32JuartState *s = container_of(d, LM32JuartState, busdev.qdev);
+
+ trace_lm32_juart_set_jrx(s->jrx);
+ s->jrx &= ~JRX_FULL;
+}
+
+static void juart_rx(void *opaque, const uint8_t *buf, int size)
+{
+ LM32JuartState *s = opaque;
+
+ s->jrx = *buf | JRX_FULL;
+}
+
+static int juart_can_rx(void *opaque)
+{
+ LM32JuartState *s = opaque;
+
+ return !(s->jrx & JRX_FULL);
+}
+
+static void juart_event(void *opaque, int event)
+{
+}
+
+static void juart_reset(DeviceState *d)
+{
+ LM32JuartState *s = container_of(d, LM32JuartState, busdev.qdev);
+
+ s->jtx = 0;
+ s->jrx = 0;
+}
+
+static int lm32_juart_init(SysBusDevice *dev)
+{
+ LM32JuartState *s = FROM_SYSBUS(typeof(*s), dev);
+
+ s->chr = qemu_char_get_next_serial();
+ if (s->chr) {
+ qemu_chr_add_handlers(s->chr, juart_can_rx, juart_rx, juart_event, s);
+ }
+
+ return 0;
+}
+
+static const VMStateDescription vmstate_lm32_juart = {
+ .name = "lm32-juart",
+ .version_id = 1,
+ .minimum_version_id = 1,
+ .minimum_version_id_old = 1,
+ .fields = (VMStateField[]) {
+ VMSTATE_UINT32(jtx, LM32JuartState),
+ VMSTATE_UINT32(jrx, LM32JuartState),
+ VMSTATE_END_OF_LIST()
+ }
+};
+
+static void lm32_juart_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+ k->init = lm32_juart_init;
+ dc->reset = juart_reset;
+ dc->vmsd = &vmstate_lm32_juart;
+}
+
+static const TypeInfo lm32_juart_info = {
+ .name = "lm32-juart",
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(LM32JuartState),
+ .class_init = lm32_juart_class_init,
+};
+
+static void lm32_juart_register_types(void)
+{
+ type_register_static(&lm32_juart_info);
+}
+
+type_init(lm32_juart_register_types)
--- /dev/null
+/*
+ * QEMU model of the LatticeMico32 UART block.
+ *
+ * Copyright (c) 2010 Michael Walle <michael@walle.cc>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ *
+ *
+ * Specification available at:
+ * http://www.latticesemi.com/documents/mico32uart.pdf
+ */
+
+
+#include "hw/hw.h"
+#include "hw/sysbus.h"
+#include "trace.h"
+#include "char/char.h"
+#include "qemu/error-report.h"
+
+enum {
+ R_RXTX = 0,
+ R_IER,
+ R_IIR,
+ R_LCR,
+ R_MCR,
+ R_LSR,
+ R_MSR,
+ R_DIV,
+ R_MAX
+};
+
+enum {
+ IER_RBRI = (1<<0),
+ IER_THRI = (1<<1),
+ IER_RLSI = (1<<2),
+ IER_MSI = (1<<3),
+};
+
+enum {
+ IIR_STAT = (1<<0),
+ IIR_ID0 = (1<<1),
+ IIR_ID1 = (1<<2),
+};
+
+enum {
+ LCR_WLS0 = (1<<0),
+ LCR_WLS1 = (1<<1),
+ LCR_STB = (1<<2),
+ LCR_PEN = (1<<3),
+ LCR_EPS = (1<<4),
+ LCR_SP = (1<<5),
+ LCR_SB = (1<<6),
+};
+
+enum {
+ MCR_DTR = (1<<0),
+ MCR_RTS = (1<<1),
+};
+
+enum {
+ LSR_DR = (1<<0),
+ LSR_OE = (1<<1),
+ LSR_PE = (1<<2),
+ LSR_FE = (1<<3),
+ LSR_BI = (1<<4),
+ LSR_THRE = (1<<5),
+ LSR_TEMT = (1<<6),
+};
+
+enum {
+ MSR_DCTS = (1<<0),
+ MSR_DDSR = (1<<1),
+ MSR_TERI = (1<<2),
+ MSR_DDCD = (1<<3),
+ MSR_CTS = (1<<4),
+ MSR_DSR = (1<<5),
+ MSR_RI = (1<<6),
+ MSR_DCD = (1<<7),
+};
+
+struct LM32UartState {
+ SysBusDevice busdev;
+ MemoryRegion iomem;
+ CharDriverState *chr;
+ qemu_irq irq;
+
+ uint32_t regs[R_MAX];
+};
+typedef struct LM32UartState LM32UartState;
+
+static void uart_update_irq(LM32UartState *s)
+{
+ unsigned int irq;
+
+ if ((s->regs[R_LSR] & (LSR_OE | LSR_PE | LSR_FE | LSR_BI))
+ && (s->regs[R_IER] & IER_RLSI)) {
+ irq = 1;
+ s->regs[R_IIR] = IIR_ID1 | IIR_ID0;
+ } else if ((s->regs[R_LSR] & LSR_DR) && (s->regs[R_IER] & IER_RBRI)) {
+ irq = 1;
+ s->regs[R_IIR] = IIR_ID1;
+ } else if ((s->regs[R_LSR] & LSR_THRE) && (s->regs[R_IER] & IER_THRI)) {
+ irq = 1;
+ s->regs[R_IIR] = IIR_ID0;
+ } else if ((s->regs[R_MSR] & 0x0f) && (s->regs[R_IER] & IER_MSI)) {
+ irq = 1;
+ s->regs[R_IIR] = 0;
+ } else {
+ irq = 0;
+ s->regs[R_IIR] = IIR_STAT;
+ }
+
+ trace_lm32_uart_irq_state(irq);
+ qemu_set_irq(s->irq, irq);
+}
+
+static uint64_t uart_read(void *opaque, hwaddr addr,
+ unsigned size)
+{
+ LM32UartState *s = opaque;
+ uint32_t r = 0;
+
+ addr >>= 2;
+ switch (addr) {
+ case R_RXTX:
+ r = s->regs[R_RXTX];
+ s->regs[R_LSR] &= ~LSR_DR;
+ uart_update_irq(s);
+ qemu_chr_accept_input(s->chr);
+ break;
+ case R_IIR:
+ case R_LSR:
+ case R_MSR:
+ r = s->regs[addr];
+ break;
+ case R_IER:
+ case R_LCR:
+ case R_MCR:
+ case R_DIV:
+ error_report("lm32_uart: read access to write only register 0x"
+ TARGET_FMT_plx, addr << 2);
+ break;
+ default:
+ error_report("lm32_uart: read access to unknown register 0x"
+ TARGET_FMT_plx, addr << 2);
+ break;
+ }
+
+ trace_lm32_uart_memory_read(addr << 2, r);
+ return r;
+}
+
+static void uart_write(void *opaque, hwaddr addr,
+ uint64_t value, unsigned size)
+{
+ LM32UartState *s = opaque;
+ unsigned char ch = value;
+
+ trace_lm32_uart_memory_write(addr, value);
+
+ addr >>= 2;
+ switch (addr) {
+ case R_RXTX:
+ if (s->chr) {
+ qemu_chr_fe_write(s->chr, &ch, 1);
+ }
+ break;
+ case R_IER:
+ case R_LCR:
+ case R_MCR:
+ case R_DIV:
+ s->regs[addr] = value;
+ break;
+ case R_IIR:
+ case R_LSR:
+ case R_MSR:
+ error_report("lm32_uart: write access to read only register 0x"
+ TARGET_FMT_plx, addr << 2);
+ break;
+ default:
+ error_report("lm32_uart: write access to unknown register 0x"
+ TARGET_FMT_plx, addr << 2);
+ break;
+ }
+ uart_update_irq(s);
+}
+
+static const MemoryRegionOps uart_ops = {
+ .read = uart_read,
+ .write = uart_write,
+ .endianness = DEVICE_NATIVE_ENDIAN,
+ .valid = {
+ .min_access_size = 4,
+ .max_access_size = 4,
+ },
+};
+
+static void uart_rx(void *opaque, const uint8_t *buf, int size)
+{
+ LM32UartState *s = opaque;
+
+ if (s->regs[R_LSR] & LSR_DR) {
+ s->regs[R_LSR] |= LSR_OE;
+ }
+
+ s->regs[R_LSR] |= LSR_DR;
+ s->regs[R_RXTX] = *buf;
+
+ uart_update_irq(s);
+}
+
+static int uart_can_rx(void *opaque)
+{
+ LM32UartState *s = opaque;
+
+ return !(s->regs[R_LSR] & LSR_DR);
+}
+
+static void uart_event(void *opaque, int event)
+{
+}
+
+static void uart_reset(DeviceState *d)
+{
+ LM32UartState *s = container_of(d, LM32UartState, busdev.qdev);
+ int i;
+
+ for (i = 0; i < R_MAX; i++) {
+ s->regs[i] = 0;
+ }
+
+ /* defaults */
+ s->regs[R_LSR] = LSR_THRE | LSR_TEMT;
+}
+
+static int lm32_uart_init(SysBusDevice *dev)
+{
+ LM32UartState *s = FROM_SYSBUS(typeof(*s), dev);
+
+ sysbus_init_irq(dev, &s->irq);
+
+ memory_region_init_io(&s->iomem, &uart_ops, s, "uart", R_MAX * 4);
+ sysbus_init_mmio(dev, &s->iomem);
+
+ s->chr = qemu_char_get_next_serial();
+ if (s->chr) {
+ qemu_chr_add_handlers(s->chr, uart_can_rx, uart_rx, uart_event, s);
+ }
+
+ return 0;
+}
+
+static const VMStateDescription vmstate_lm32_uart = {
+ .name = "lm32-uart",
+ .version_id = 1,
+ .minimum_version_id = 1,
+ .minimum_version_id_old = 1,
+ .fields = (VMStateField[]) {
+ VMSTATE_UINT32_ARRAY(regs, LM32UartState, R_MAX),
+ VMSTATE_END_OF_LIST()
+ }
+};
+
+static void lm32_uart_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+ k->init = lm32_uart_init;
+ dc->reset = uart_reset;
+ dc->vmsd = &vmstate_lm32_uart;
+}
+
+static const TypeInfo lm32_uart_info = {
+ .name = "lm32-uart",
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(LM32UartState),
+ .class_init = lm32_uart_class_init,
+};
+
+static void lm32_uart_register_types(void)
+{
+ type_register_static(&lm32_uart_info);
+}
+
+type_init(lm32_uart_register_types)
--- /dev/null
+/*
+ * ColdFire UART emulation.
+ *
+ * Copyright (c) 2007 CodeSourcery.
+ *
+ * This code is licensed under the GPL
+ */
+#include "hw/hw.h"
+#include "hw/m68k/mcf.h"
+#include "char/char.h"
+#include "exec/address-spaces.h"
+
+typedef struct {
+ MemoryRegion iomem;
+ uint8_t mr[2];
+ uint8_t sr;
+ uint8_t isr;
+ uint8_t imr;
+ uint8_t bg1;
+ uint8_t bg2;
+ uint8_t fifo[4];
+ uint8_t tb;
+ int current_mr;
+ int fifo_len;
+ int tx_enabled;
+ int rx_enabled;
+ qemu_irq irq;
+ CharDriverState *chr;
+} mcf_uart_state;
+
+/* UART Status Register bits. */
+#define MCF_UART_RxRDY 0x01
+#define MCF_UART_FFULL 0x02
+#define MCF_UART_TxRDY 0x04
+#define MCF_UART_TxEMP 0x08
+#define MCF_UART_OE 0x10
+#define MCF_UART_PE 0x20
+#define MCF_UART_FE 0x40
+#define MCF_UART_RB 0x80
+
+/* Interrupt flags. */
+#define MCF_UART_TxINT 0x01
+#define MCF_UART_RxINT 0x02
+#define MCF_UART_DBINT 0x04
+#define MCF_UART_COSINT 0x80
+
+/* UMR1 flags. */
+#define MCF_UART_BC0 0x01
+#define MCF_UART_BC1 0x02
+#define MCF_UART_PT 0x04
+#define MCF_UART_PM0 0x08
+#define MCF_UART_PM1 0x10
+#define MCF_UART_ERR 0x20
+#define MCF_UART_RxIRQ 0x40
+#define MCF_UART_RxRTS 0x80
+
+static void mcf_uart_update(mcf_uart_state *s)
+{
+ s->isr &= ~(MCF_UART_TxINT | MCF_UART_RxINT);
+ if (s->sr & MCF_UART_TxRDY)
+ s->isr |= MCF_UART_TxINT;
+ if ((s->sr & ((s->mr[0] & MCF_UART_RxIRQ)
+ ? MCF_UART_FFULL : MCF_UART_RxRDY)) != 0)
+ s->isr |= MCF_UART_RxINT;
+
+ qemu_set_irq(s->irq, (s->isr & s->imr) != 0);
+}
+
+uint64_t mcf_uart_read(void *opaque, hwaddr addr,
+ unsigned size)
+{
+ mcf_uart_state *s = (mcf_uart_state *)opaque;
+ switch (addr & 0x3f) {
+ case 0x00:
+ return s->mr[s->current_mr];
+ case 0x04:
+ return s->sr;
+ case 0x0c:
+ {
+ uint8_t val;
+ int i;
+
+ if (s->fifo_len == 0)
+ return 0;
+
+ val = s->fifo[0];
+ s->fifo_len--;
+ for (i = 0; i < s->fifo_len; i++)
+ s->fifo[i] = s->fifo[i + 1];
+ s->sr &= ~MCF_UART_FFULL;
+ if (s->fifo_len == 0)
+ s->sr &= ~MCF_UART_RxRDY;
+ mcf_uart_update(s);
+ qemu_chr_accept_input(s->chr);
+ return val;
+ }
+ case 0x10:
+ /* TODO: Implement IPCR. */
+ return 0;
+ case 0x14:
+ return s->isr;
+ case 0x18:
+ return s->bg1;
+ case 0x1c:
+ return s->bg2;
+ default:
+ return 0;
+ }
+}
+
+/* Update TxRDY flag and set data if present and enabled. */
+static void mcf_uart_do_tx(mcf_uart_state *s)
+{
+ if (s->tx_enabled && (s->sr & MCF_UART_TxEMP) == 0) {
+ if (s->chr)
+ qemu_chr_fe_write(s->chr, (unsigned char *)&s->tb, 1);
+ s->sr |= MCF_UART_TxEMP;
+ }
+ if (s->tx_enabled) {
+ s->sr |= MCF_UART_TxRDY;
+ } else {
+ s->sr &= ~MCF_UART_TxRDY;
+ }
+}
+
+static void mcf_do_command(mcf_uart_state *s, uint8_t cmd)
+{
+ /* Misc command. */
+ switch ((cmd >> 4) & 3) {
+ case 0: /* No-op. */
+ break;
+ case 1: /* Reset mode register pointer. */
+ s->current_mr = 0;
+ break;
+ case 2: /* Reset receiver. */
+ s->rx_enabled = 0;
+ s->fifo_len = 0;
+ s->sr &= ~(MCF_UART_RxRDY | MCF_UART_FFULL);
+ break;
+ case 3: /* Reset transmitter. */
+ s->tx_enabled = 0;
+ s->sr |= MCF_UART_TxEMP;
+ s->sr &= ~MCF_UART_TxRDY;
+ break;
+ case 4: /* Reset error status. */
+ break;
+ case 5: /* Reset break-change interrupt. */
+ s->isr &= ~MCF_UART_DBINT;
+ break;
+ case 6: /* Start break. */
+ case 7: /* Stop break. */
+ break;
+ }
+
+ /* Transmitter command. */
+ switch ((cmd >> 2) & 3) {
+ case 0: /* No-op. */
+ break;
+ case 1: /* Enable. */
+ s->tx_enabled = 1;
+ mcf_uart_do_tx(s);
+ break;
+ case 2: /* Disable. */
+ s->tx_enabled = 0;
+ mcf_uart_do_tx(s);
+ break;
+ case 3: /* Reserved. */
+ fprintf(stderr, "mcf_uart: Bad TX command\n");
+ break;
+ }
+
+ /* Receiver command. */
+ switch (cmd & 3) {
+ case 0: /* No-op. */
+ break;
+ case 1: /* Enable. */
+ s->rx_enabled = 1;
+ break;
+ case 2:
+ s->rx_enabled = 0;
+ break;
+ case 3: /* Reserved. */
+ fprintf(stderr, "mcf_uart: Bad RX command\n");
+ break;
+ }
+}
+
+void mcf_uart_write(void *opaque, hwaddr addr,
+ uint64_t val, unsigned size)
+{
+ mcf_uart_state *s = (mcf_uart_state *)opaque;
+ switch (addr & 0x3f) {
+ case 0x00:
+ s->mr[s->current_mr] = val;
+ s->current_mr = 1;
+ break;
+ case 0x04:
+ /* CSR is ignored. */
+ break;
+ case 0x08: /* Command Register. */
+ mcf_do_command(s, val);
+ break;
+ case 0x0c: /* Transmit Buffer. */
+ s->sr &= ~MCF_UART_TxEMP;
+ s->tb = val;
+ mcf_uart_do_tx(s);
+ break;
+ case 0x10:
+ /* ACR is ignored. */
+ break;
+ case 0x14:
+ s->imr = val;
+ break;
+ default:
+ break;
+ }
+ mcf_uart_update(s);
+}
+
+static void mcf_uart_reset(mcf_uart_state *s)
+{
+ s->fifo_len = 0;
+ s->mr[0] = 0;
+ s->mr[1] = 0;
+ s->sr = MCF_UART_TxEMP;
+ s->tx_enabled = 0;
+ s->rx_enabled = 0;
+ s->isr = 0;
+ s->imr = 0;
+}
+
+static void mcf_uart_push_byte(mcf_uart_state *s, uint8_t data)
+{
+ /* Break events overwrite the last byte if the fifo is full. */
+ if (s->fifo_len == 4)
+ s->fifo_len--;
+
+ s->fifo[s->fifo_len] = data;
+ s->fifo_len++;
+ s->sr |= MCF_UART_RxRDY;
+ if (s->fifo_len == 4)
+ s->sr |= MCF_UART_FFULL;
+
+ mcf_uart_update(s);
+}
+
+static void mcf_uart_event(void *opaque, int event)
+{
+ mcf_uart_state *s = (mcf_uart_state *)opaque;
+
+ switch (event) {
+ case CHR_EVENT_BREAK:
+ s->isr |= MCF_UART_DBINT;
+ mcf_uart_push_byte(s, 0);
+ break;
+ default:
+ break;
+ }
+}
+
+static int mcf_uart_can_receive(void *opaque)
+{
+ mcf_uart_state *s = (mcf_uart_state *)opaque;
+
+ return s->rx_enabled && (s->sr & MCF_UART_FFULL) == 0;
+}
+
+static void mcf_uart_receive(void *opaque, const uint8_t *buf, int size)
+{
+ mcf_uart_state *s = (mcf_uart_state *)opaque;
+
+ mcf_uart_push_byte(s, buf[0]);
+}
+
+void *mcf_uart_init(qemu_irq irq, CharDriverState *chr)
+{
+ mcf_uart_state *s;
+
+ s = g_malloc0(sizeof(mcf_uart_state));
+ s->chr = chr;
+ s->irq = irq;
+ if (chr) {
+ qemu_chr_fe_claim_no_fail(chr);
+ qemu_chr_add_handlers(chr, mcf_uart_can_receive, mcf_uart_receive,
+ mcf_uart_event, s);
+ }
+ mcf_uart_reset(s);
+ return s;
+}
+
+static const MemoryRegionOps mcf_uart_ops = {
+ .read = mcf_uart_read,
+ .write = mcf_uart_write,
+ .endianness = DEVICE_NATIVE_ENDIAN,
+};
+
+void mcf_uart_mm_init(MemoryRegion *sysmem,
+ hwaddr base,
+ qemu_irq irq,
+ CharDriverState *chr)
+{
+ mcf_uart_state *s;
+
+ s = mcf_uart_init(irq, chr);
+ memory_region_init_io(&s->iomem, &mcf_uart_ops, s, "uart", 0x40);
+ memory_region_add_subregion(sysmem, base, &s->iomem);
+}
--- /dev/null
+/*
+ * QEMU model of the Milkymist UART block.
+ *
+ * Copyright (c) 2010 Michael Walle <michael@walle.cc>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ *
+ *
+ * Specification available at:
+ * http://www.milkymist.org/socdoc/uart.pdf
+ */
+
+#include "hw/hw.h"
+#include "hw/sysbus.h"
+#include "trace.h"
+#include "char/char.h"
+#include "qemu/error-report.h"
+
+enum {
+ R_RXTX = 0,
+ R_DIV,
+ R_STAT,
+ R_CTRL,
+ R_DBG,
+ R_MAX
+};
+
+enum {
+ STAT_THRE = (1<<0),
+ STAT_RX_EVT = (1<<1),
+ STAT_TX_EVT = (1<<2),
+};
+
+enum {
+ CTRL_RX_IRQ_EN = (1<<0),
+ CTRL_TX_IRQ_EN = (1<<1),
+ CTRL_THRU_EN = (1<<2),
+};
+
+enum {
+ DBG_BREAK_EN = (1<<0),
+};
+
+struct MilkymistUartState {
+ SysBusDevice busdev;
+ MemoryRegion regs_region;
+ CharDriverState *chr;
+ qemu_irq irq;
+
+ uint32_t regs[R_MAX];
+};
+typedef struct MilkymistUartState MilkymistUartState;
+
+static void uart_update_irq(MilkymistUartState *s)
+{
+ int rx_event = s->regs[R_STAT] & STAT_RX_EVT;
+ int tx_event = s->regs[R_STAT] & STAT_TX_EVT;
+ int rx_irq_en = s->regs[R_CTRL] & CTRL_RX_IRQ_EN;
+ int tx_irq_en = s->regs[R_CTRL] & CTRL_TX_IRQ_EN;
+
+ if ((rx_irq_en && rx_event) || (tx_irq_en && tx_event)) {
+ trace_milkymist_uart_raise_irq();
+ qemu_irq_raise(s->irq);
+ } else {
+ trace_milkymist_uart_lower_irq();
+ qemu_irq_lower(s->irq);
+ }
+}
+
+static uint64_t uart_read(void *opaque, hwaddr addr,
+ unsigned size)
+{
+ MilkymistUartState *s = opaque;
+ uint32_t r = 0;
+
+ addr >>= 2;
+ switch (addr) {
+ case R_RXTX:
+ r = s->regs[addr];
+ break;
+ case R_DIV:
+ case R_STAT:
+ case R_CTRL:
+ case R_DBG:
+ r = s->regs[addr];
+ break;
+
+ default:
+ error_report("milkymist_uart: read access to unknown register 0x"
+ TARGET_FMT_plx, addr << 2);
+ break;
+ }
+
+ trace_milkymist_uart_memory_read(addr << 2, r);
+
+ return r;
+}
+
+static void uart_write(void *opaque, hwaddr addr, uint64_t value,
+ unsigned size)
+{
+ MilkymistUartState *s = opaque;
+ unsigned char ch = value;
+
+ trace_milkymist_uart_memory_write(addr, value);
+
+ addr >>= 2;
+ switch (addr) {
+ case R_RXTX:
+ if (s->chr) {
+ qemu_chr_fe_write(s->chr, &ch, 1);
+ }
+ s->regs[R_STAT] |= STAT_TX_EVT;
+ break;
+ case R_DIV:
+ case R_CTRL:
+ case R_DBG:
+ s->regs[addr] = value;
+ break;
+
+ case R_STAT:
+ /* write one to clear bits */
+ s->regs[addr] &= ~(value & (STAT_RX_EVT | STAT_TX_EVT));
+ qemu_chr_accept_input(s->chr);
+ break;
+
+ default:
+ error_report("milkymist_uart: write access to unknown register 0x"
+ TARGET_FMT_plx, addr << 2);
+ break;
+ }
+
+ uart_update_irq(s);
+}
+
+static const MemoryRegionOps uart_mmio_ops = {
+ .read = uart_read,
+ .write = uart_write,
+ .valid = {
+ .min_access_size = 4,
+ .max_access_size = 4,
+ },
+ .endianness = DEVICE_NATIVE_ENDIAN,
+};
+
+static void uart_rx(void *opaque, const uint8_t *buf, int size)
+{
+ MilkymistUartState *s = opaque;
+
+ assert(!(s->regs[R_STAT] & STAT_RX_EVT));
+
+ s->regs[R_STAT] |= STAT_RX_EVT;
+ s->regs[R_RXTX] = *buf;
+
+ uart_update_irq(s);
+}
+
+static int uart_can_rx(void *opaque)
+{
+ MilkymistUartState *s = opaque;
+
+ return !(s->regs[R_STAT] & STAT_RX_EVT);
+}
+
+static void uart_event(void *opaque, int event)
+{
+}
+
+static void milkymist_uart_reset(DeviceState *d)
+{
+ MilkymistUartState *s = container_of(d, MilkymistUartState, busdev.qdev);
+ int i;
+
+ for (i = 0; i < R_MAX; i++) {
+ s->regs[i] = 0;
+ }
+
+ /* THRE is always set */
+ s->regs[R_STAT] = STAT_THRE;
+}
+
+static int milkymist_uart_init(SysBusDevice *dev)
+{
+ MilkymistUartState *s = FROM_SYSBUS(typeof(*s), dev);
+
+ sysbus_init_irq(dev, &s->irq);
+
+ memory_region_init_io(&s->regs_region, &uart_mmio_ops, s,
+ "milkymist-uart", R_MAX * 4);
+ sysbus_init_mmio(dev, &s->regs_region);
+
+ s->chr = qemu_char_get_next_serial();
+ if (s->chr) {
+ qemu_chr_add_handlers(s->chr, uart_can_rx, uart_rx, uart_event, s);
+ }
+
+ return 0;
+}
+
+static const VMStateDescription vmstate_milkymist_uart = {
+ .name = "milkymist-uart",
+ .version_id = 1,
+ .minimum_version_id = 1,
+ .minimum_version_id_old = 1,
+ .fields = (VMStateField[]) {
+ VMSTATE_UINT32_ARRAY(regs, MilkymistUartState, R_MAX),
+ VMSTATE_END_OF_LIST()
+ }
+};
+
+static void milkymist_uart_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+ k->init = milkymist_uart_init;
+ dc->reset = milkymist_uart_reset;
+ dc->vmsd = &vmstate_milkymist_uart;
+}
+
+static const TypeInfo milkymist_uart_info = {
+ .name = "milkymist-uart",
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(MilkymistUartState),
+ .class_init = milkymist_uart_class_init,
+};
+
+static void milkymist_uart_register_types(void)
+{
+ type_register_static(&milkymist_uart_info);
+}
+
+type_init(milkymist_uart_register_types)
--- /dev/null
+/*
+ * TI OMAP processors UART emulation.
+ *
+ * Copyright (C) 2006-2008 Andrzej Zaborowski <balrog@zabor.org>
+ * Copyright (C) 2007-2009 Nokia Corporation
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 or
+ * (at your option) version 3 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+#include "char/char.h"
+#include "hw/hw.h"
+#include "hw/arm/omap.h"
+#include "hw/char/serial.h"
+#include "exec/address-spaces.h"
+
+/* UARTs */
+struct omap_uart_s {
+ MemoryRegion iomem;
+ hwaddr base;
+ SerialState *serial; /* TODO */
+ struct omap_target_agent_s *ta;
+ omap_clk fclk;
+ qemu_irq irq;
+
+ uint8_t eblr;
+ uint8_t syscontrol;
+ uint8_t wkup;
+ uint8_t cfps;
+ uint8_t mdr[2];
+ uint8_t scr;
+ uint8_t clksel;
+};
+
+void omap_uart_reset(struct omap_uart_s *s)
+{
+ s->eblr = 0x00;
+ s->syscontrol = 0;
+ s->wkup = 0x3f;
+ s->cfps = 0x69;
+ s->clksel = 0;
+}
+
+struct omap_uart_s *omap_uart_init(hwaddr base,
+ qemu_irq irq, omap_clk fclk, omap_clk iclk,
+ qemu_irq txdma, qemu_irq rxdma,
+ const char *label, CharDriverState *chr)
+{
+ struct omap_uart_s *s = (struct omap_uart_s *)
+ g_malloc0(sizeof(struct omap_uart_s));
+
+ s->base = base;
+ s->fclk = fclk;
+ s->irq = irq;
+ s->serial = serial_mm_init(get_system_memory(), base, 2, irq,
+ omap_clk_getrate(fclk)/16,
+ chr ?: qemu_chr_new(label, "null", NULL),
+ DEVICE_NATIVE_ENDIAN);
+ return s;
+}
+
+static uint64_t omap_uart_read(void *opaque, hwaddr addr,
+ unsigned size)
+{
+ struct omap_uart_s *s = (struct omap_uart_s *) opaque;
+
+ if (size == 4) {
+ return omap_badwidth_read8(opaque, addr);
+ }
+
+ switch (addr) {
+ case 0x20: /* MDR1 */
+ return s->mdr[0];
+ case 0x24: /* MDR2 */
+ return s->mdr[1];
+ case 0x40: /* SCR */
+ return s->scr;
+ case 0x44: /* SSR */
+ return 0x0;
+ case 0x48: /* EBLR (OMAP2) */
+ return s->eblr;
+ case 0x4C: /* OSC_12M_SEL (OMAP1) */
+ return s->clksel;
+ case 0x50: /* MVR */
+ return 0x30;
+ case 0x54: /* SYSC (OMAP2) */
+ return s->syscontrol;
+ case 0x58: /* SYSS (OMAP2) */
+ return 1;
+ case 0x5c: /* WER (OMAP2) */
+ return s->wkup;
+ case 0x60: /* CFPS (OMAP2) */
+ return s->cfps;
+ }
+
+ OMAP_BAD_REG(addr);
+ return 0;
+}
+
+static void omap_uart_write(void *opaque, hwaddr addr,
+ uint64_t value, unsigned size)
+{
+ struct omap_uart_s *s = (struct omap_uart_s *) opaque;
+
+ if (size == 4) {
+ return omap_badwidth_write8(opaque, addr, value);
+ }
+
+ switch (addr) {
+ case 0x20: /* MDR1 */
+ s->mdr[0] = value & 0x7f;
+ break;
+ case 0x24: /* MDR2 */
+ s->mdr[1] = value & 0xff;
+ break;
+ case 0x40: /* SCR */
+ s->scr = value & 0xff;
+ break;
+ case 0x48: /* EBLR (OMAP2) */
+ s->eblr = value & 0xff;
+ break;
+ case 0x4C: /* OSC_12M_SEL (OMAP1) */
+ s->clksel = value & 1;
+ break;
+ case 0x44: /* SSR */
+ case 0x50: /* MVR */
+ case 0x58: /* SYSS (OMAP2) */
+ OMAP_RO_REG(addr);
+ break;
+ case 0x54: /* SYSC (OMAP2) */
+ s->syscontrol = value & 0x1d;
+ if (value & 2)
+ omap_uart_reset(s);
+ break;
+ case 0x5c: /* WER (OMAP2) */
+ s->wkup = value & 0x7f;
+ break;
+ case 0x60: /* CFPS (OMAP2) */
+ s->cfps = value & 0xff;
+ break;
+ default:
+ OMAP_BAD_REG(addr);
+ }
+}
+
+static const MemoryRegionOps omap_uart_ops = {
+ .read = omap_uart_read,
+ .write = omap_uart_write,
+ .endianness = DEVICE_NATIVE_ENDIAN,
+};
+
+struct omap_uart_s *omap2_uart_init(MemoryRegion *sysmem,
+ struct omap_target_agent_s *ta,
+ qemu_irq irq, omap_clk fclk, omap_clk iclk,
+ qemu_irq txdma, qemu_irq rxdma,
+ const char *label, CharDriverState *chr)
+{
+ hwaddr base = omap_l4_attach(ta, 0, NULL);
+ struct omap_uart_s *s = omap_uart_init(base, irq,
+ fclk, iclk, txdma, rxdma, label, chr);
+
+ memory_region_init_io(&s->iomem, &omap_uart_ops, s, "omap.uart", 0x100);
+
+ s->ta = ta;
+
+ memory_region_add_subregion(sysmem, base + 0x20, &s->iomem);
+
+ return s;
+}
+
+void omap_uart_attach(struct omap_uart_s *s, CharDriverState *chr)
+{
+ /* TODO: Should reuse or destroy current s->serial */
+ s->serial = serial_mm_init(get_system_memory(), s->base, 2, s->irq,
+ omap_clk_getrate(s->fclk) / 16,
+ chr ?: qemu_chr_new("null", "null", NULL),
+ DEVICE_NATIVE_ENDIAN);
+}
--- /dev/null
+/*
+ * SCLP event type
+ * Ascii Console Data (VT220 Console)
+ *
+ * Copyright IBM, Corp. 2012
+ *
+ * Authors:
+ * Heinz Graalfs <graalfs@de.ibm.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or (at your
+ * option) any later version. See the COPYING file in the top-level directory.
+ *
+ */
+
+#include <hw/qdev.h>
+#include "qemu/thread.h"
+#include "qemu/error-report.h"
+
+#include "hw/s390x/sclp.h"
+#include "hw/s390x/event-facility.h"
+#include "char/char.h"
+
+typedef struct ASCIIConsoleData {
+ EventBufferHeader ebh;
+ char data[0];
+} QEMU_PACKED ASCIIConsoleData;
+
+/* max size for ASCII data in 4K SCCB page */
+#define SIZE_BUFFER_VT220 4080
+
+typedef struct SCLPConsole {
+ SCLPEvent event;
+ CharDriverState *chr;
+ /* io vector */
+ uint8_t *iov; /* iov buffer pointer */
+ uint8_t *iov_sclp; /* pointer to SCLP read offset */
+ uint8_t *iov_bs; /* pointer byte stream read offset */
+ uint32_t iov_data_len; /* length of byte stream in buffer */
+ uint32_t iov_sclp_rest; /* length of byte stream not read via SCLP */
+ qemu_irq irq_read_vt220;
+} SCLPConsole;
+
+/* character layer call-back functions */
+
+/* Return number of bytes that fit into iov buffer */
+static int chr_can_read(void *opaque)
+{
+ SCLPConsole *scon = opaque;
+
+ return scon->iov ? SIZE_BUFFER_VT220 - scon->iov_data_len : 0;
+}
+
+/* Receive n bytes from character layer, save in iov buffer,
+ * and set event pending */
+static void receive_from_chr_layer(SCLPConsole *scon, const uint8_t *buf,
+ int size)
+{
+ assert(scon->iov);
+
+ /* read data must fit into current buffer */
+ assert(size <= SIZE_BUFFER_VT220 - scon->iov_data_len);
+
+ /* put byte-stream from character layer into buffer */
+ memcpy(scon->iov_bs, buf, size);
+ scon->iov_data_len += size;
+ scon->iov_sclp_rest += size;
+ scon->iov_bs += size;
+ scon->event.event_pending = true;
+}
+
+/* Send data from a char device over to the guest */
+static void chr_read(void *opaque, const uint8_t *buf, int size)
+{
+ SCLPConsole *scon = opaque;
+
+ assert(scon);
+
+ receive_from_chr_layer(scon, buf, size);
+ /* trigger SCLP read operation */
+ qemu_irq_raise(scon->irq_read_vt220);
+}
+
+static void chr_event(void *opaque, int event)
+{
+ SCLPConsole *scon = opaque;
+
+ switch (event) {
+ case CHR_EVENT_OPENED:
+ if (!scon->iov) {
+ scon->iov = g_malloc0(SIZE_BUFFER_VT220);
+ scon->iov_sclp = scon->iov;
+ scon->iov_bs = scon->iov;
+ scon->iov_data_len = 0;
+ scon->iov_sclp_rest = 0;
+ }
+ break;
+ case CHR_EVENT_CLOSED:
+ if (scon->iov) {
+ g_free(scon->iov);
+ scon->iov = NULL;
+ }
+ break;
+ }
+}
+
+/* functions to be called by event facility */
+
+static int event_type(void)
+{
+ return SCLP_EVENT_ASCII_CONSOLE_DATA;
+}
+
+static unsigned int send_mask(void)
+{
+ return SCLP_EVENT_MASK_MSG_ASCII;
+}
+
+static unsigned int receive_mask(void)
+{
+ return SCLP_EVENT_MASK_MSG_ASCII;
+}
+
+/* triggered by SCLP's read_event_data -
+ * copy console data byte-stream into provided (SCLP) buffer
+ */
+static void get_console_data(SCLPEvent *event, uint8_t *buf, size_t *size,
+ int avail)
+{
+ SCLPConsole *cons = DO_UPCAST(SCLPConsole, event, event);
+
+ /* first byte is hex 0 saying an ascii string follows */
+ *buf++ = '\0';
+ avail--;
+ /* if all data fit into provided SCLP buffer */
+ if (avail >= cons->iov_sclp_rest) {
+ /* copy character byte-stream to SCLP buffer */
+ memcpy(buf, cons->iov_sclp, cons->iov_sclp_rest);
+ *size = cons->iov_sclp_rest + 1;
+ cons->iov_sclp = cons->iov;
+ cons->iov_bs = cons->iov;
+ cons->iov_data_len = 0;
+ cons->iov_sclp_rest = 0;
+ event->event_pending = false;
+ /* data provided and no more data pending */
+ } else {
+ /* if provided buffer is too small, just copy part */
+ memcpy(buf, cons->iov_sclp, avail);
+ *size = avail + 1;
+ cons->iov_sclp_rest -= avail;
+ cons->iov_sclp += avail;
+ /* more data pending */
+ }
+}
+
+static int read_event_data(SCLPEvent *event, EventBufferHeader *evt_buf_hdr,
+ int *slen)
+{
+ int avail;
+ size_t src_len;
+ uint8_t *to;
+ ASCIIConsoleData *acd = (ASCIIConsoleData *) evt_buf_hdr;
+
+ if (!event->event_pending) {
+ /* no data pending */
+ return 0;
+ }
+
+ to = (uint8_t *)&acd->data;
+ avail = *slen - sizeof(ASCIIConsoleData);
+ get_console_data(event, to, &src_len, avail);
+
+ acd->ebh.length = cpu_to_be16(sizeof(ASCIIConsoleData) + src_len);
+ acd->ebh.type = SCLP_EVENT_ASCII_CONSOLE_DATA;
+ acd->ebh.flags |= SCLP_EVENT_BUFFER_ACCEPTED;
+ *slen = avail - src_len;
+
+ return 1;
+}
+
+/* triggered by SCLP's write_event_data
+ * - write console data to character layer
+ * returns < 0 if an error occurred
+ */
+static ssize_t write_console_data(SCLPEvent *event, const uint8_t *buf,
+ size_t len)
+{
+ ssize_t ret = 0;
+ const uint8_t *iov_offset;
+ SCLPConsole *scon = DO_UPCAST(SCLPConsole, event, event);
+
+ if (!scon->chr) {
+ /* If there's no backend, we can just say we consumed all data. */
+ return len;
+ }
+
+ iov_offset = buf;
+ while (len > 0) {
+ ret = qemu_chr_fe_write(scon->chr, buf, len);
+ if (ret == 0) {
+ /* a pty doesn't seem to be connected - no error */
+ len = 0;
+ } else if (ret == -EAGAIN || (ret > 0 && ret < len)) {
+ len -= ret;
+ iov_offset += ret;
+ } else {
+ len = 0;
+ }
+ }
+
+ return ret;
+}
+
+static int write_event_data(SCLPEvent *event, EventBufferHeader *evt_buf_hdr)
+{
+ int rc;
+ int length;
+ ssize_t written;
+ ASCIIConsoleData *acd = (ASCIIConsoleData *) evt_buf_hdr;
+
+ length = be16_to_cpu(evt_buf_hdr->length) - sizeof(EventBufferHeader);
+ written = write_console_data(event, (uint8_t *)acd->data, length);
+
+ rc = SCLP_RC_NORMAL_COMPLETION;
+ /* set event buffer accepted flag */
+ evt_buf_hdr->flags |= SCLP_EVENT_BUFFER_ACCEPTED;
+
+ /* written will be zero if a pty is not connected - don't treat as error */
+ if (written < 0) {
+ /* event buffer not accepted due to error in character layer */
+ evt_buf_hdr->flags &= ~(SCLP_EVENT_BUFFER_ACCEPTED);
+ rc = SCLP_RC_CONTAINED_EQUIPMENT_CHECK;
+ }
+
+ return rc;
+}
+
+static void trigger_ascii_console_data(void *opaque, int n, int level)
+{
+ sclp_service_interrupt(0);
+}
+
+/* qemu object creation and initialization functions */
+
+/* tell character layer our call-back functions */
+static int console_init(SCLPEvent *event)
+{
+ static bool console_available;
+
+ SCLPConsole *scon = DO_UPCAST(SCLPConsole, event, event);
+
+ if (console_available) {
+ error_report("Multiple VT220 operator consoles are not supported");
+ return -1;
+ }
+ console_available = true;
+ event->event_type = SCLP_EVENT_ASCII_CONSOLE_DATA;
+ if (scon->chr) {
+ qemu_chr_add_handlers(scon->chr, chr_can_read,
+ chr_read, chr_event, scon);
+ }
+ scon->irq_read_vt220 = *qemu_allocate_irqs(trigger_ascii_console_data,
+ NULL, 1);
+
+ return 0;
+}
+
+static int console_exit(SCLPEvent *event)
+{
+ return 0;
+}
+
+static Property console_properties[] = {
+ DEFINE_PROP_CHR("chardev", SCLPConsole, chr),
+ DEFINE_PROP_END_OF_LIST(),
+};
+
+static void console_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ SCLPEventClass *ec = SCLP_EVENT_CLASS(klass);
+
+ dc->props = console_properties;
+ ec->init = console_init;
+ ec->exit = console_exit;
+ ec->get_send_mask = send_mask;
+ ec->get_receive_mask = receive_mask;
+ ec->event_type = event_type;
+ ec->read_event_data = read_event_data;
+ ec->write_event_data = write_event_data;
+}
+
+static const TypeInfo sclp_console_info = {
+ .name = "sclpconsole",
+ .parent = TYPE_SCLP_EVENT,
+ .instance_size = sizeof(SCLPConsole),
+ .class_init = console_class_init,
+ .class_size = sizeof(SCLPEventClass),
+};
+
+static void register_types(void)
+{
+ type_register_static(&sclp_console_info);
+}
+
+type_init(register_types)
--- /dev/null
+/*
+ * QEMU SCI/SCIF serial port emulation
+ *
+ * Copyright (c) 2007 Magnus Damm
+ *
+ * Based on serial.c - QEMU 16450 UART emulation
+ * Copyright (c) 2003-2004 Fabrice Bellard
+ *
+ * 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 "hw/hw.h"
+#include "hw/sh4/sh.h"
+#include "char/char.h"
+#include "exec/address-spaces.h"
+
+//#define DEBUG_SERIAL
+
+#define SH_SERIAL_FLAG_TEND (1 << 0)
+#define SH_SERIAL_FLAG_TDE (1 << 1)
+#define SH_SERIAL_FLAG_RDF (1 << 2)
+#define SH_SERIAL_FLAG_BRK (1 << 3)
+#define SH_SERIAL_FLAG_DR (1 << 4)
+
+#define SH_RX_FIFO_LENGTH (16)
+
+typedef struct {
+ MemoryRegion iomem;
+ MemoryRegion iomem_p4;
+ MemoryRegion iomem_a7;
+ uint8_t smr;
+ uint8_t brr;
+ uint8_t scr;
+ uint8_t dr; /* ftdr / tdr */
+ uint8_t sr; /* fsr / ssr */
+ uint16_t fcr;
+ uint8_t sptr;
+
+ uint8_t rx_fifo[SH_RX_FIFO_LENGTH]; /* frdr / rdr */
+ uint8_t rx_cnt;
+ uint8_t rx_tail;
+ uint8_t rx_head;
+
+ int freq;
+ int feat;
+ int flags;
+ int rtrg;
+
+ CharDriverState *chr;
+
+ qemu_irq eri;
+ qemu_irq rxi;
+ qemu_irq txi;
+ qemu_irq tei;
+ qemu_irq bri;
+} sh_serial_state;
+
+static void sh_serial_clear_fifo(sh_serial_state * s)
+{
+ memset(s->rx_fifo, 0, SH_RX_FIFO_LENGTH);
+ s->rx_cnt = 0;
+ s->rx_head = 0;
+ s->rx_tail = 0;
+}
+
+static void sh_serial_write(void *opaque, hwaddr offs,
+ uint64_t val, unsigned size)
+{
+ sh_serial_state *s = opaque;
+ unsigned char ch;
+
+#ifdef DEBUG_SERIAL
+ printf("sh_serial: write offs=0x%02x val=0x%02x\n",
+ offs, val);
+#endif
+ switch(offs) {
+ case 0x00: /* SMR */
+ s->smr = val & ((s->feat & SH_SERIAL_FEAT_SCIF) ? 0x7b : 0xff);
+ return;
+ case 0x04: /* BRR */
+ s->brr = val;
+ return;
+ case 0x08: /* SCR */
+ /* TODO : For SH7751, SCIF mask should be 0xfb. */
+ s->scr = val & ((s->feat & SH_SERIAL_FEAT_SCIF) ? 0xfa : 0xff);
+ if (!(val & (1 << 5)))
+ s->flags |= SH_SERIAL_FLAG_TEND;
+ if ((s->feat & SH_SERIAL_FEAT_SCIF) && s->txi) {
+ qemu_set_irq(s->txi, val & (1 << 7));
+ }
+ if (!(val & (1 << 6))) {
+ qemu_set_irq(s->rxi, 0);
+ }
+ return;
+ case 0x0c: /* FTDR / TDR */
+ if (s->chr) {
+ ch = val;
+ qemu_chr_fe_write(s->chr, &ch, 1);
+ }
+ s->dr = val;
+ s->flags &= ~SH_SERIAL_FLAG_TDE;
+ return;
+#if 0
+ case 0x14: /* FRDR / RDR */
+ ret = 0;
+ break;
+#endif
+ }
+ if (s->feat & SH_SERIAL_FEAT_SCIF) {
+ switch(offs) {
+ case 0x10: /* FSR */
+ if (!(val & (1 << 6)))
+ s->flags &= ~SH_SERIAL_FLAG_TEND;
+ if (!(val & (1 << 5)))
+ s->flags &= ~SH_SERIAL_FLAG_TDE;
+ if (!(val & (1 << 4)))
+ s->flags &= ~SH_SERIAL_FLAG_BRK;
+ if (!(val & (1 << 1)))
+ s->flags &= ~SH_SERIAL_FLAG_RDF;
+ if (!(val & (1 << 0)))
+ s->flags &= ~SH_SERIAL_FLAG_DR;
+
+ if (!(val & (1 << 1)) || !(val & (1 << 0))) {
+ if (s->rxi) {
+ qemu_set_irq(s->rxi, 0);
+ }
+ }
+ return;
+ case 0x18: /* FCR */
+ s->fcr = val;
+ switch ((val >> 6) & 3) {
+ case 0:
+ s->rtrg = 1;
+ break;
+ case 1:
+ s->rtrg = 4;
+ break;
+ case 2:
+ s->rtrg = 8;
+ break;
+ case 3:
+ s->rtrg = 14;
+ break;
+ }
+ if (val & (1 << 1)) {
+ sh_serial_clear_fifo(s);
+ s->sr &= ~(1 << 1);
+ }
+
+ return;
+ case 0x20: /* SPTR */
+ s->sptr = val & 0xf3;
+ return;
+ case 0x24: /* LSR */
+ return;
+ }
+ }
+ else {
+ switch(offs) {
+#if 0
+ case 0x0c:
+ ret = s->dr;
+ break;
+ case 0x10:
+ ret = 0;
+ break;
+#endif
+ case 0x1c:
+ s->sptr = val & 0x8f;
+ return;
+ }
+ }
+
+ fprintf(stderr, "sh_serial: unsupported write to 0x%02"
+ HWADDR_PRIx "\n", offs);
+ abort();
+}
+
+static uint64_t sh_serial_read(void *opaque, hwaddr offs,
+ unsigned size)
+{
+ sh_serial_state *s = opaque;
+ uint32_t ret = ~0;
+
+#if 0
+ switch(offs) {
+ case 0x00:
+ ret = s->smr;
+ break;
+ case 0x04:
+ ret = s->brr;
+ break;
+ case 0x08:
+ ret = s->scr;
+ break;
+ case 0x14:
+ ret = 0;
+ break;
+ }
+#endif
+ if (s->feat & SH_SERIAL_FEAT_SCIF) {
+ switch(offs) {
+ case 0x00: /* SMR */
+ ret = s->smr;
+ break;
+ case 0x08: /* SCR */
+ ret = s->scr;
+ break;
+ case 0x10: /* FSR */
+ ret = 0;
+ if (s->flags & SH_SERIAL_FLAG_TEND)
+ ret |= (1 << 6);
+ if (s->flags & SH_SERIAL_FLAG_TDE)
+ ret |= (1 << 5);
+ if (s->flags & SH_SERIAL_FLAG_BRK)
+ ret |= (1 << 4);
+ if (s->flags & SH_SERIAL_FLAG_RDF)
+ ret |= (1 << 1);
+ if (s->flags & SH_SERIAL_FLAG_DR)
+ ret |= (1 << 0);
+
+ if (s->scr & (1 << 5))
+ s->flags |= SH_SERIAL_FLAG_TDE | SH_SERIAL_FLAG_TEND;
+
+ break;
+ case 0x14:
+ if (s->rx_cnt > 0) {
+ ret = s->rx_fifo[s->rx_tail++];
+ s->rx_cnt--;
+ if (s->rx_tail == SH_RX_FIFO_LENGTH)
+ s->rx_tail = 0;
+ if (s->rx_cnt < s->rtrg)
+ s->flags &= ~SH_SERIAL_FLAG_RDF;
+ }
+ break;
+#if 0
+ case 0x18:
+ ret = s->fcr;
+ break;
+#endif
+ case 0x1c:
+ ret = s->rx_cnt;
+ break;
+ case 0x20:
+ ret = s->sptr;
+ break;
+ case 0x24:
+ ret = 0;
+ break;
+ }
+ }
+ else {
+ switch(offs) {
+#if 0
+ case 0x0c:
+ ret = s->dr;
+ break;
+ case 0x10:
+ ret = 0;
+ break;
+ case 0x14:
+ ret = s->rx_fifo[0];
+ break;
+#endif
+ case 0x1c:
+ ret = s->sptr;
+ break;
+ }
+ }
+#ifdef DEBUG_SERIAL
+ printf("sh_serial: read offs=0x%02x val=0x%x\n",
+ offs, ret);
+#endif
+
+ if (ret & ~((1 << 16) - 1)) {
+ fprintf(stderr, "sh_serial: unsupported read from 0x%02"
+ HWADDR_PRIx "\n", offs);
+ abort();
+ }
+
+ return ret;
+}
+
+static int sh_serial_can_receive(sh_serial_state *s)
+{
+ return s->scr & (1 << 4);
+}
+
+static void sh_serial_receive_break(sh_serial_state *s)
+{
+ if (s->feat & SH_SERIAL_FEAT_SCIF)
+ s->sr |= (1 << 4);
+}
+
+static int sh_serial_can_receive1(void *opaque)
+{
+ sh_serial_state *s = opaque;
+ return sh_serial_can_receive(s);
+}
+
+static void sh_serial_receive1(void *opaque, const uint8_t *buf, int size)
+{
+ sh_serial_state *s = opaque;
+
+ if (s->feat & SH_SERIAL_FEAT_SCIF) {
+ int i;
+ for (i = 0; i < size; i++) {
+ if (s->rx_cnt < SH_RX_FIFO_LENGTH) {
+ s->rx_fifo[s->rx_head++] = buf[i];
+ if (s->rx_head == SH_RX_FIFO_LENGTH) {
+ s->rx_head = 0;
+ }
+ s->rx_cnt++;
+ if (s->rx_cnt >= s->rtrg) {
+ s->flags |= SH_SERIAL_FLAG_RDF;
+ if (s->scr & (1 << 6) && s->rxi) {
+ qemu_set_irq(s->rxi, 1);
+ }
+ }
+ }
+ }
+ } else {
+ s->rx_fifo[0] = buf[0];
+ }
+}
+
+static void sh_serial_event(void *opaque, int event)
+{
+ sh_serial_state *s = opaque;
+ if (event == CHR_EVENT_BREAK)
+ sh_serial_receive_break(s);
+}
+
+static const MemoryRegionOps sh_serial_ops = {
+ .read = sh_serial_read,
+ .write = sh_serial_write,
+ .endianness = DEVICE_NATIVE_ENDIAN,
+};
+
+void sh_serial_init(MemoryRegion *sysmem,
+ hwaddr base, int feat,
+ uint32_t freq, CharDriverState *chr,
+ qemu_irq eri_source,
+ qemu_irq rxi_source,
+ qemu_irq txi_source,
+ qemu_irq tei_source,
+ qemu_irq bri_source)
+{
+ sh_serial_state *s;
+
+ s = g_malloc0(sizeof(sh_serial_state));
+
+ s->feat = feat;
+ s->flags = SH_SERIAL_FLAG_TEND | SH_SERIAL_FLAG_TDE;
+ s->rtrg = 1;
+
+ s->smr = 0;
+ s->brr = 0xff;
+ s->scr = 1 << 5; /* pretend that TX is enabled so early printk works */
+ s->sptr = 0;
+
+ if (feat & SH_SERIAL_FEAT_SCIF) {
+ s->fcr = 0;
+ }
+ else {
+ s->dr = 0xff;
+ }
+
+ sh_serial_clear_fifo(s);
+
+ memory_region_init_io(&s->iomem, &sh_serial_ops, s,
+ "serial", 0x100000000ULL);
+
+ memory_region_init_alias(&s->iomem_p4, "serial-p4", &s->iomem,
+ 0, 0x28);
+ memory_region_add_subregion(sysmem, P4ADDR(base), &s->iomem_p4);
+
+ memory_region_init_alias(&s->iomem_a7, "serial-a7", &s->iomem,
+ 0, 0x28);
+ memory_region_add_subregion(sysmem, A7ADDR(base), &s->iomem_a7);
+
+ s->chr = chr;
+
+ if (chr) {
+ qemu_chr_fe_claim_no_fail(chr);
+ qemu_chr_add_handlers(chr, sh_serial_can_receive1, sh_serial_receive1,
+ sh_serial_event, s);
+ }
+
+ s->eri = eri_source;
+ s->rxi = rxi_source;
+ s->txi = txi_source;
+ s->tei = tei_source;
+ s->bri = bri_source;
+}
--- /dev/null
+#include "hw/qdev.h"
+#include "char/char.h"
+#include "hw/ppc/spapr.h"
+#include "hw/ppc/spapr_vio.h"
+
+#define VTERM_BUFSIZE 16
+
+typedef struct VIOsPAPRVTYDevice {
+ VIOsPAPRDevice sdev;
+ CharDriverState *chardev;
+ uint32_t in, out;
+ uint8_t buf[VTERM_BUFSIZE];
+} VIOsPAPRVTYDevice;
+
+static int vty_can_receive(void *opaque)
+{
+ VIOsPAPRVTYDevice *dev = (VIOsPAPRVTYDevice *)opaque;
+
+ return (dev->in - dev->out) < VTERM_BUFSIZE;
+}
+
+static void vty_receive(void *opaque, const uint8_t *buf, int size)
+{
+ VIOsPAPRVTYDevice *dev = (VIOsPAPRVTYDevice *)opaque;
+ int i;
+
+ if ((dev->in == dev->out) && size) {
+ /* toggle line to simulate edge interrupt */
+ qemu_irq_pulse(spapr_vio_qirq(&dev->sdev));
+ }
+ for (i = 0; i < size; i++) {
+ assert((dev->in - dev->out) < VTERM_BUFSIZE);
+ dev->buf[dev->in++ % VTERM_BUFSIZE] = buf[i];
+ }
+}
+
+static int vty_getchars(VIOsPAPRDevice *sdev, uint8_t *buf, int max)
+{
+ VIOsPAPRVTYDevice *dev = (VIOsPAPRVTYDevice *)sdev;
+ int n = 0;
+
+ while ((n < max) && (dev->out != dev->in)) {
+ buf[n++] = dev->buf[dev->out++ % VTERM_BUFSIZE];
+ }
+
+ return n;
+}
+
+void vty_putchars(VIOsPAPRDevice *sdev, uint8_t *buf, int len)
+{
+ VIOsPAPRVTYDevice *dev = (VIOsPAPRVTYDevice *)sdev;
+
+ /* FIXME: should check the qemu_chr_fe_write() return value */
+ qemu_chr_fe_write(dev->chardev, buf, len);
+}
+
+static int spapr_vty_init(VIOsPAPRDevice *sdev)
+{
+ VIOsPAPRVTYDevice *dev = (VIOsPAPRVTYDevice *)sdev;
+
+ if (!dev->chardev) {
+ fprintf(stderr, "spapr-vty: Can't create vty without a chardev!\n");
+ exit(1);
+ }
+
+ qemu_chr_add_handlers(dev->chardev, vty_can_receive,
+ vty_receive, NULL, dev);
+
+ return 0;
+}
+
+/* Forward declaration */
+static target_ulong h_put_term_char(PowerPCCPU *cpu, sPAPREnvironment *spapr,
+ target_ulong opcode, target_ulong *args)
+{
+ target_ulong reg = args[0];
+ target_ulong len = args[1];
+ target_ulong char0_7 = args[2];
+ target_ulong char8_15 = args[3];
+ VIOsPAPRDevice *sdev;
+ uint8_t buf[16];
+
+ sdev = vty_lookup(spapr, reg);
+ if (!sdev) {
+ return H_PARAMETER;
+ }
+
+ if (len > 16) {
+ return H_PARAMETER;
+ }
+
+ *((uint64_t *)buf) = cpu_to_be64(char0_7);
+ *((uint64_t *)buf + 1) = cpu_to_be64(char8_15);
+
+ vty_putchars(sdev, buf, len);
+
+ return H_SUCCESS;
+}
+
+static target_ulong h_get_term_char(PowerPCCPU *cpu, sPAPREnvironment *spapr,
+ target_ulong opcode, target_ulong *args)
+{
+ target_ulong reg = args[0];
+ target_ulong *len = args + 0;
+ target_ulong *char0_7 = args + 1;
+ target_ulong *char8_15 = args + 2;
+ VIOsPAPRDevice *sdev;
+ uint8_t buf[16];
+
+ sdev = vty_lookup(spapr, reg);
+ if (!sdev) {
+ return H_PARAMETER;
+ }
+
+ *len = vty_getchars(sdev, buf, sizeof(buf));
+ if (*len < 16) {
+ memset(buf + *len, 0, 16 - *len);
+ }
+
+ *char0_7 = be64_to_cpu(*((uint64_t *)buf));
+ *char8_15 = be64_to_cpu(*((uint64_t *)buf + 1));
+
+ return H_SUCCESS;
+}
+
+void spapr_vty_create(VIOsPAPRBus *bus, CharDriverState *chardev)
+{
+ DeviceState *dev;
+
+ dev = qdev_create(&bus->bus, "spapr-vty");
+ qdev_prop_set_chr(dev, "chardev", chardev);
+ qdev_init_nofail(dev);
+}
+
+static Property spapr_vty_properties[] = {
+ DEFINE_SPAPR_PROPERTIES(VIOsPAPRVTYDevice, sdev),
+ DEFINE_PROP_CHR("chardev", VIOsPAPRVTYDevice, chardev),
+ DEFINE_PROP_END_OF_LIST(),
+};
+
+static void spapr_vty_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ VIOsPAPRDeviceClass *k = VIO_SPAPR_DEVICE_CLASS(klass);
+
+ k->init = spapr_vty_init;
+ k->dt_name = "vty";
+ k->dt_type = "serial";
+ k->dt_compatible = "hvterm1";
+ dc->props = spapr_vty_properties;
+}
+
+static const TypeInfo spapr_vty_info = {
+ .name = "spapr-vty",
+ .parent = TYPE_VIO_SPAPR_DEVICE,
+ .instance_size = sizeof(VIOsPAPRVTYDevice),
+ .class_init = spapr_vty_class_init,
+};
+
+VIOsPAPRDevice *spapr_vty_get_default(VIOsPAPRBus *bus)
+{
+ VIOsPAPRDevice *sdev, *selected;
+ BusChild *kid;
+
+ /*
+ * To avoid the console bouncing around we want one VTY to be
+ * the "default". We haven't really got anything to go on, so
+ * arbitrarily choose the one with the lowest reg value.
+ */
+
+ selected = NULL;
+ QTAILQ_FOREACH(kid, &bus->bus.children, sibling) {
+ DeviceState *iter = kid->child;
+
+ /* Only look at VTY devices */
+ if (!object_dynamic_cast(OBJECT(iter), "spapr-vty")) {
+ continue;
+ }
+
+ sdev = DO_UPCAST(VIOsPAPRDevice, qdev, iter);
+
+ /* First VTY we've found, so it is selected for now */
+ if (!selected) {
+ selected = sdev;
+ continue;
+ }
+
+ /* Choose VTY with lowest reg value */
+ if (sdev->reg < selected->reg) {
+ selected = sdev;
+ }
+ }
+
+ return selected;
+}
+
+VIOsPAPRDevice *vty_lookup(sPAPREnvironment *spapr, target_ulong reg)
+{
+ VIOsPAPRDevice *sdev;
+
+ sdev = spapr_vio_find_by_reg(spapr->vio_bus, reg);
+ if (!sdev && reg == 0) {
+ /* Hack for kernel early debug, which always specifies reg==0.
+ * We search all VIO devices, and grab the vty with the lowest
+ * reg. This attempts to mimic existing PowerVM behaviour
+ * (early debug does work there, despite having no vty with
+ * reg==0. */
+ return spapr_vty_get_default(spapr->vio_bus);
+ }
+
+ return sdev;
+}
+
+static void spapr_vty_register_types(void)
+{
+ spapr_register_hypercall(H_PUT_TERM_CHAR, h_put_term_char);
+ spapr_register_hypercall(H_GET_TERM_CHAR, h_get_term_char);
+ type_register_static(&spapr_vty_info);
+}
+
+type_init(spapr_vty_register_types)
obj-y += etraxfs_dma.o
obj-y += etraxfs_pic.o
obj-y += etraxfs_timer.o
-obj-y += etraxfs_ser.o
obj-y := $(addprefix ../,$(obj-y))
+++ /dev/null
-/*
- * QEMU Bochs-style debug console ("port E9") emulation
- *
- * Copyright (c) 2003-2004 Fabrice Bellard
- * Copyright (c) 2008 Citrix Systems, Inc.
- * Copyright (c) Intel Corporation; author: H. Peter Anvin
- *
- * 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 "hw/hw.h"
-#include "char/char.h"
-#include "hw/isa/isa.h"
-#include "hw/i386/pc.h"
-
-#define TYPE_ISA_DEBUGCON_DEVICE "isa-debugcon"
-#define ISA_DEBUGCON_DEVICE(obj) \
- OBJECT_CHECK(ISADebugconState, (obj), TYPE_ISA_DEBUGCON_DEVICE)
-
-//#define DEBUG_DEBUGCON
-
-typedef struct DebugconState {
- MemoryRegion io;
- CharDriverState *chr;
- uint32_t readback;
-} DebugconState;
-
-typedef struct ISADebugconState {
- ISADevice parent_obj;
-
- uint32_t iobase;
- DebugconState state;
-} ISADebugconState;
-
-static void debugcon_ioport_write(void *opaque, hwaddr addr, uint64_t val,
- unsigned width)
-{
- DebugconState *s = opaque;
- unsigned char ch = val;
-
-#ifdef DEBUG_DEBUGCON
- printf("debugcon: write addr=0x%04x val=0x%02x\n", addr, val);
-#endif
-
- qemu_chr_fe_write(s->chr, &ch, 1);
-}
-
-
-static uint64_t debugcon_ioport_read(void *opaque, hwaddr addr, unsigned width)
-{
- DebugconState *s = opaque;
-
-#ifdef DEBUG_DEBUGCON
- printf("debugcon: read addr=0x%04x\n", addr);
-#endif
-
- return s->readback;
-}
-
-static const MemoryRegionOps debugcon_ops = {
- .read = debugcon_ioport_read,
- .write = debugcon_ioport_write,
- .valid.min_access_size = 1,
- .valid.max_access_size = 1,
- .endianness = DEVICE_LITTLE_ENDIAN,
-};
-
-static void debugcon_init_core(DebugconState *s)
-{
- if (!s->chr) {
- fprintf(stderr, "Can't create debugcon device, empty char device\n");
- exit(1);
- }
-
- qemu_chr_add_handlers(s->chr, NULL, NULL, NULL, s);
-}
-
-static int debugcon_isa_initfn(ISADevice *dev)
-{
- ISADebugconState *isa = ISA_DEBUGCON_DEVICE(dev);
- DebugconState *s = &isa->state;
-
- debugcon_init_core(s);
- memory_region_init_io(&s->io, &debugcon_ops, s,
- TYPE_ISA_DEBUGCON_DEVICE, 1);
- memory_region_add_subregion(isa_address_space_io(dev),
- isa->iobase, &s->io);
- return 0;
-}
-
-static Property debugcon_isa_properties[] = {
- DEFINE_PROP_HEX32("iobase", ISADebugconState, iobase, 0xe9),
- DEFINE_PROP_CHR("chardev", ISADebugconState, state.chr),
- DEFINE_PROP_HEX32("readback", ISADebugconState, state.readback, 0xe9),
- DEFINE_PROP_END_OF_LIST(),
-};
-
-static void debugcon_isa_class_initfn(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
- ISADeviceClass *ic = ISA_DEVICE_CLASS(klass);
- ic->init = debugcon_isa_initfn;
- dc->props = debugcon_isa_properties;
-}
-
-static const TypeInfo debugcon_isa_info = {
- .name = TYPE_ISA_DEBUGCON_DEVICE,
- .parent = TYPE_ISA_DEVICE,
- .instance_size = sizeof(ISADebugconState),
- .class_init = debugcon_isa_class_initfn,
-};
-
-static void debugcon_register_types(void)
-{
- type_register_static(&debugcon_isa_info);
-}
-
-type_init(debugcon_register_types)
+++ /dev/null
-/*
- * QEMU ETRAX System Emulator
- *
- * Copyright (c) 2007 Edgar E. Iglesias, Axis Communications AB.
- *
- * 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 "hw/sysbus.h"
-#include "char/char.h"
-#include "qemu/log.h"
-
-#define D(x)
-
-#define RW_TR_CTRL (0x00 / 4)
-#define RW_TR_DMA_EN (0x04 / 4)
-#define RW_REC_CTRL (0x08 / 4)
-#define RW_DOUT (0x1c / 4)
-#define RS_STAT_DIN (0x20 / 4)
-#define R_STAT_DIN (0x24 / 4)
-#define RW_INTR_MASK (0x2c / 4)
-#define RW_ACK_INTR (0x30 / 4)
-#define R_INTR (0x34 / 4)
-#define R_MASKED_INTR (0x38 / 4)
-#define R_MAX (0x3c / 4)
-
-#define STAT_DAV 16
-#define STAT_TR_IDLE 22
-#define STAT_TR_RDY 24
-
-struct etrax_serial
-{
- SysBusDevice busdev;
- MemoryRegion mmio;
- CharDriverState *chr;
- qemu_irq irq;
-
- int pending_tx;
-
- uint8_t rx_fifo[16];
- unsigned int rx_fifo_pos;
- unsigned int rx_fifo_len;
-
- /* Control registers. */
- uint32_t regs[R_MAX];
-};
-
-static void ser_update_irq(struct etrax_serial *s)
-{
-
- if (s->rx_fifo_len) {
- s->regs[R_INTR] |= 8;
- } else {
- s->regs[R_INTR] &= ~8;
- }
-
- s->regs[R_MASKED_INTR] = s->regs[R_INTR] & s->regs[RW_INTR_MASK];
- qemu_set_irq(s->irq, !!s->regs[R_MASKED_INTR]);
-}
-
-static uint64_t
-ser_read(void *opaque, hwaddr addr, unsigned int size)
-{
- struct etrax_serial *s = opaque;
- D(CPUCRISState *env = s->env);
- uint32_t r = 0;
-
- addr >>= 2;
- switch (addr)
- {
- case R_STAT_DIN:
- r = s->rx_fifo[(s->rx_fifo_pos - s->rx_fifo_len) & 15];
- if (s->rx_fifo_len) {
- r |= 1 << STAT_DAV;
- }
- r |= 1 << STAT_TR_RDY;
- r |= 1 << STAT_TR_IDLE;
- break;
- case RS_STAT_DIN:
- r = s->rx_fifo[(s->rx_fifo_pos - s->rx_fifo_len) & 15];
- if (s->rx_fifo_len) {
- r |= 1 << STAT_DAV;
- s->rx_fifo_len--;
- }
- r |= 1 << STAT_TR_RDY;
- r |= 1 << STAT_TR_IDLE;
- break;
- default:
- r = s->regs[addr];
- D(qemu_log("%s " TARGET_FMT_plx "=%x\n", __func__, addr, r));
- break;
- }
- return r;
-}
-
-static void
-ser_write(void *opaque, hwaddr addr,
- uint64_t val64, unsigned int size)
-{
- struct etrax_serial *s = opaque;
- uint32_t value = val64;
- unsigned char ch = val64;
- D(CPUCRISState *env = s->env);
-
- D(qemu_log("%s " TARGET_FMT_plx "=%x\n", __func__, addr, value));
- addr >>= 2;
- switch (addr)
- {
- case RW_DOUT:
- qemu_chr_fe_write(s->chr, &ch, 1);
- s->regs[R_INTR] |= 3;
- s->pending_tx = 1;
- s->regs[addr] = value;
- break;
- case RW_ACK_INTR:
- if (s->pending_tx) {
- value &= ~1;
- s->pending_tx = 0;
- D(qemu_log("fixedup value=%x r_intr=%x\n",
- value, s->regs[R_INTR]));
- }
- s->regs[addr] = value;
- s->regs[R_INTR] &= ~value;
- D(printf("r_intr=%x\n", s->regs[R_INTR]));
- break;
- default:
- s->regs[addr] = value;
- break;
- }
- ser_update_irq(s);
-}
-
-static const MemoryRegionOps ser_ops = {
- .read = ser_read,
- .write = ser_write,
- .endianness = DEVICE_NATIVE_ENDIAN,
- .valid = {
- .min_access_size = 4,
- .max_access_size = 4
- }
-};
-
-static void serial_receive(void *opaque, const uint8_t *buf, int size)
-{
- struct etrax_serial *s = opaque;
- int i;
-
- /* Got a byte. */
- if (s->rx_fifo_len >= 16) {
- qemu_log("WARNING: UART dropped char.\n");
- return;
- }
-
- for (i = 0; i < size; i++) {
- s->rx_fifo[s->rx_fifo_pos] = buf[i];
- s->rx_fifo_pos++;
- s->rx_fifo_pos &= 15;
- s->rx_fifo_len++;
- }
-
- ser_update_irq(s);
-}
-
-static int serial_can_receive(void *opaque)
-{
- struct etrax_serial *s = opaque;
- int r;
-
- /* Is the receiver enabled? */
- if (!(s->regs[RW_REC_CTRL] & (1 << 3))) {
- return 0;
- }
-
- r = sizeof(s->rx_fifo) - s->rx_fifo_len;
- return r;
-}
-
-static void serial_event(void *opaque, int event)
-{
-
-}
-
-static void etraxfs_ser_reset(DeviceState *d)
-{
- struct etrax_serial *s = container_of(d, typeof(*s), busdev.qdev);
-
- /* transmitter begins ready and idle. */
- s->regs[RS_STAT_DIN] |= (1 << STAT_TR_RDY);
- s->regs[RS_STAT_DIN] |= (1 << STAT_TR_IDLE);
-
- s->regs[RW_REC_CTRL] = 0x10000;
-
-}
-
-static int etraxfs_ser_init(SysBusDevice *dev)
-{
- struct etrax_serial *s = FROM_SYSBUS(typeof (*s), dev);
-
- sysbus_init_irq(dev, &s->irq);
- memory_region_init_io(&s->mmio, &ser_ops, s, "etraxfs-serial", R_MAX * 4);
- sysbus_init_mmio(dev, &s->mmio);
-
- s->chr = qemu_char_get_next_serial();
- if (s->chr)
- qemu_chr_add_handlers(s->chr,
- serial_can_receive, serial_receive,
- serial_event, s);
- return 0;
-}
-
-static void etraxfs_ser_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
- SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
-
- k->init = etraxfs_ser_init;
- dc->reset = etraxfs_ser_reset;
-}
-
-static const TypeInfo etraxfs_ser_info = {
- .name = "etraxfs,serial",
- .parent = TYPE_SYS_BUS_DEVICE,
- .instance_size = sizeof(struct etrax_serial),
- .class_init = etraxfs_ser_class_init,
-};
-
-static void etraxfs_serial_register_types(void)
-{
- type_register_static(&etraxfs_ser_info);
-}
-
-type_init(etraxfs_serial_register_types)
+++ /dev/null
-/*
- * Exynos4210 UART Emulation
- *
- * Copyright (C) 2011 Samsung Electronics Co Ltd.
- * Maksim Kozlov, <m.kozlov@samsung.com>
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the
- * Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, see <http://www.gnu.org/licenses/>.
- *
- */
-
-#include "hw/sysbus.h"
-#include "sysemu/sysemu.h"
-#include "char/char.h"
-
-#include "hw/arm/exynos4210.h"
-
-#undef DEBUG_UART
-#undef DEBUG_UART_EXTEND
-#undef DEBUG_IRQ
-#undef DEBUG_Rx_DATA
-#undef DEBUG_Tx_DATA
-
-#define DEBUG_UART 0
-#define DEBUG_UART_EXTEND 0
-#define DEBUG_IRQ 0
-#define DEBUG_Rx_DATA 0
-#define DEBUG_Tx_DATA 0
-
-#if DEBUG_UART
-#define PRINT_DEBUG(fmt, args...) \
- do { \
- fprintf(stderr, " [%s:%d] "fmt, __func__, __LINE__, ##args); \
- } while (0)
-
-#if DEBUG_UART_EXTEND
-#define PRINT_DEBUG_EXTEND(fmt, args...) \
- do { \
- fprintf(stderr, " [%s:%d] "fmt, __func__, __LINE__, ##args); \
- } while (0)
-#else
-#define PRINT_DEBUG_EXTEND(fmt, args...) \
- do {} while (0)
-#endif /* EXTEND */
-
-#else
-#define PRINT_DEBUG(fmt, args...) \
- do {} while (0)
-#define PRINT_DEBUG_EXTEND(fmt, args...) \
- do {} while (0)
-#endif
-
-#define PRINT_ERROR(fmt, args...) \
- do { \
- fprintf(stderr, " [%s:%d] "fmt, __func__, __LINE__, ##args); \
- } while (0)
-
-/*
- * Offsets for UART registers relative to SFR base address
- * for UARTn
- *
- */
-#define ULCON 0x0000 /* Line Control */
-#define UCON 0x0004 /* Control */
-#define UFCON 0x0008 /* FIFO Control */
-#define UMCON 0x000C /* Modem Control */
-#define UTRSTAT 0x0010 /* Tx/Rx Status */
-#define UERSTAT 0x0014 /* UART Error Status */
-#define UFSTAT 0x0018 /* FIFO Status */
-#define UMSTAT 0x001C /* Modem Status */
-#define UTXH 0x0020 /* Transmit Buffer */
-#define URXH 0x0024 /* Receive Buffer */
-#define UBRDIV 0x0028 /* Baud Rate Divisor */
-#define UFRACVAL 0x002C /* Divisor Fractional Value */
-#define UINTP 0x0030 /* Interrupt Pending */
-#define UINTSP 0x0034 /* Interrupt Source Pending */
-#define UINTM 0x0038 /* Interrupt Mask */
-
-/*
- * for indexing register in the uint32_t array
- *
- * 'reg' - register offset (see offsets definitions above)
- *
- */
-#define I_(reg) (reg / sizeof(uint32_t))
-
-typedef struct Exynos4210UartReg {
- const char *name; /* the only reason is the debug output */
- hwaddr offset;
- uint32_t reset_value;
-} Exynos4210UartReg;
-
-static Exynos4210UartReg exynos4210_uart_regs[] = {
- {"ULCON", ULCON, 0x00000000},
- {"UCON", UCON, 0x00003000},
- {"UFCON", UFCON, 0x00000000},
- {"UMCON", UMCON, 0x00000000},
- {"UTRSTAT", UTRSTAT, 0x00000006}, /* RO */
- {"UERSTAT", UERSTAT, 0x00000000}, /* RO */
- {"UFSTAT", UFSTAT, 0x00000000}, /* RO */
- {"UMSTAT", UMSTAT, 0x00000000}, /* RO */
- {"UTXH", UTXH, 0x5c5c5c5c}, /* WO, undefined reset value*/
- {"URXH", URXH, 0x00000000}, /* RO */
- {"UBRDIV", UBRDIV, 0x00000000},
- {"UFRACVAL", UFRACVAL, 0x00000000},
- {"UINTP", UINTP, 0x00000000},
- {"UINTSP", UINTSP, 0x00000000},
- {"UINTM", UINTM, 0x00000000},
-};
-
-#define EXYNOS4210_UART_REGS_MEM_SIZE 0x3C
-
-/* UART FIFO Control */
-#define UFCON_FIFO_ENABLE 0x1
-#define UFCON_Rx_FIFO_RESET 0x2
-#define UFCON_Tx_FIFO_RESET 0x4
-#define UFCON_Tx_FIFO_TRIGGER_LEVEL_SHIFT 8
-#define UFCON_Tx_FIFO_TRIGGER_LEVEL (7 << UFCON_Tx_FIFO_TRIGGER_LEVEL_SHIFT)
-#define UFCON_Rx_FIFO_TRIGGER_LEVEL_SHIFT 4
-#define UFCON_Rx_FIFO_TRIGGER_LEVEL (7 << UFCON_Rx_FIFO_TRIGGER_LEVEL_SHIFT)
-
-/* Uart FIFO Status */
-#define UFSTAT_Rx_FIFO_COUNT 0xff
-#define UFSTAT_Rx_FIFO_FULL 0x100
-#define UFSTAT_Rx_FIFO_ERROR 0x200
-#define UFSTAT_Tx_FIFO_COUNT_SHIFT 16
-#define UFSTAT_Tx_FIFO_COUNT (0xff << UFSTAT_Tx_FIFO_COUNT_SHIFT)
-#define UFSTAT_Tx_FIFO_FULL_SHIFT 24
-#define UFSTAT_Tx_FIFO_FULL (1 << UFSTAT_Tx_FIFO_FULL_SHIFT)
-
-/* UART Interrupt Source Pending */
-#define UINTSP_RXD 0x1 /* Receive interrupt */
-#define UINTSP_ERROR 0x2 /* Error interrupt */
-#define UINTSP_TXD 0x4 /* Transmit interrupt */
-#define UINTSP_MODEM 0x8 /* Modem interrupt */
-
-/* UART Line Control */
-#define ULCON_IR_MODE_SHIFT 6
-#define ULCON_PARITY_SHIFT 3
-#define ULCON_STOP_BIT_SHIFT 1
-
-/* UART Tx/Rx Status */
-#define UTRSTAT_TRANSMITTER_EMPTY 0x4
-#define UTRSTAT_Tx_BUFFER_EMPTY 0x2
-#define UTRSTAT_Rx_BUFFER_DATA_READY 0x1
-
-/* UART Error Status */
-#define UERSTAT_OVERRUN 0x1
-#define UERSTAT_PARITY 0x2
-#define UERSTAT_FRAME 0x4
-#define UERSTAT_BREAK 0x8
-
-typedef struct {
- uint8_t *data;
- uint32_t sp, rp; /* store and retrieve pointers */
- uint32_t size;
-} Exynos4210UartFIFO;
-
-typedef struct {
- SysBusDevice busdev;
- MemoryRegion iomem;
-
- uint32_t reg[EXYNOS4210_UART_REGS_MEM_SIZE / sizeof(uint32_t)];
- Exynos4210UartFIFO rx;
- Exynos4210UartFIFO tx;
-
- CharDriverState *chr;
- qemu_irq irq;
-
- uint32_t channel;
-
-} Exynos4210UartState;
-
-
-#if DEBUG_UART
-/* Used only for debugging inside PRINT_DEBUG_... macros */
-static const char *exynos4210_uart_regname(hwaddr offset)
-{
-
- int regs_number = sizeof(exynos4210_uart_regs) / sizeof(Exynos4210UartReg);
- int i;
-
- for (i = 0; i < regs_number; i++) {
- if (offset == exynos4210_uart_regs[i].offset) {
- return exynos4210_uart_regs[i].name;
- }
- }
-
- return NULL;
-}
-#endif
-
-
-static void fifo_store(Exynos4210UartFIFO *q, uint8_t ch)
-{
- q->data[q->sp] = ch;
- q->sp = (q->sp + 1) % q->size;
-}
-
-static uint8_t fifo_retrieve(Exynos4210UartFIFO *q)
-{
- uint8_t ret = q->data[q->rp];
- q->rp = (q->rp + 1) % q->size;
- return ret;
-}
-
-static int fifo_elements_number(Exynos4210UartFIFO *q)
-{
- if (q->sp < q->rp) {
- return q->size - q->rp + q->sp;
- }
-
- return q->sp - q->rp;
-}
-
-static int fifo_empty_elements_number(Exynos4210UartFIFO *q)
-{
- return q->size - fifo_elements_number(q);
-}
-
-static void fifo_reset(Exynos4210UartFIFO *q)
-{
- if (q->data != NULL) {
- g_free(q->data);
- q->data = NULL;
- }
-
- q->data = (uint8_t *)g_malloc0(q->size);
-
- q->sp = 0;
- q->rp = 0;
-}
-
-static uint32_t exynos4210_uart_Tx_FIFO_trigger_level(Exynos4210UartState *s)
-{
- uint32_t level = 0;
- uint32_t reg;
-
- reg = (s->reg[I_(UFCON)] & UFCON_Tx_FIFO_TRIGGER_LEVEL) >>
- UFCON_Tx_FIFO_TRIGGER_LEVEL_SHIFT;
-
- switch (s->channel) {
- case 0:
- level = reg * 32;
- break;
- case 1:
- case 4:
- level = reg * 8;
- break;
- case 2:
- case 3:
- level = reg * 2;
- break;
- default:
- level = 0;
- PRINT_ERROR("Wrong UART channel number: %d\n", s->channel);
- }
-
- return level;
-}
-
-static void exynos4210_uart_update_irq(Exynos4210UartState *s)
-{
- /*
- * The Tx interrupt is always requested if the number of data in the
- * transmit FIFO is smaller than the trigger level.
- */
- if (s->reg[I_(UFCON)] & UFCON_FIFO_ENABLE) {
-
- uint32_t count = (s->reg[I_(UFSTAT)] & UFSTAT_Tx_FIFO_COUNT) >>
- UFSTAT_Tx_FIFO_COUNT_SHIFT;
-
- if (count <= exynos4210_uart_Tx_FIFO_trigger_level(s)) {
- s->reg[I_(UINTSP)] |= UINTSP_TXD;
- }
- }
-
- s->reg[I_(UINTP)] = s->reg[I_(UINTSP)] & ~s->reg[I_(UINTM)];
-
- if (s->reg[I_(UINTP)]) {
- qemu_irq_raise(s->irq);
-
-#if DEBUG_IRQ
- fprintf(stderr, "UART%d: IRQ has been raised: %08x\n",
- s->channel, s->reg[I_(UINTP)]);
-#endif
-
- } else {
- qemu_irq_lower(s->irq);
- }
-}
-
-static void exynos4210_uart_update_parameters(Exynos4210UartState *s)
-{
- int speed, parity, data_bits, stop_bits, frame_size;
- QEMUSerialSetParams ssp;
- uint64_t uclk_rate;
-
- if (s->reg[I_(UBRDIV)] == 0) {
- return;
- }
-
- frame_size = 1; /* start bit */
- if (s->reg[I_(ULCON)] & 0x20) {
- frame_size++; /* parity bit */
- if (s->reg[I_(ULCON)] & 0x28) {
- parity = 'E';
- } else {
- parity = 'O';
- }
- } else {
- parity = 'N';
- }
-
- if (s->reg[I_(ULCON)] & 0x4) {
- stop_bits = 2;
- } else {
- stop_bits = 1;
- }
-
- data_bits = (s->reg[I_(ULCON)] & 0x3) + 5;
-
- frame_size += data_bits + stop_bits;
-
- uclk_rate = 24000000;
-
- speed = uclk_rate / ((16 * (s->reg[I_(UBRDIV)]) & 0xffff) +
- (s->reg[I_(UFRACVAL)] & 0x7) + 16);
-
- ssp.speed = speed;
- ssp.parity = parity;
- ssp.data_bits = data_bits;
- ssp.stop_bits = stop_bits;
-
- qemu_chr_fe_ioctl(s->chr, CHR_IOCTL_SERIAL_SET_PARAMS, &ssp);
-
- PRINT_DEBUG("UART%d: speed: %d, parity: %c, data: %d, stop: %d\n",
- s->channel, speed, parity, data_bits, stop_bits);
-}
-
-static void exynos4210_uart_write(void *opaque, hwaddr offset,
- uint64_t val, unsigned size)
-{
- Exynos4210UartState *s = (Exynos4210UartState *)opaque;
- uint8_t ch;
-
- PRINT_DEBUG_EXTEND("UART%d: <0x%04x> %s <- 0x%08llx\n", s->channel,
- offset, exynos4210_uart_regname(offset), (long long unsigned int)val);
-
- switch (offset) {
- case ULCON:
- case UBRDIV:
- case UFRACVAL:
- s->reg[I_(offset)] = val;
- exynos4210_uart_update_parameters(s);
- break;
- case UFCON:
- s->reg[I_(UFCON)] = val;
- if (val & UFCON_Rx_FIFO_RESET) {
- fifo_reset(&s->rx);
- s->reg[I_(UFCON)] &= ~UFCON_Rx_FIFO_RESET;
- PRINT_DEBUG("UART%d: Rx FIFO Reset\n", s->channel);
- }
- if (val & UFCON_Tx_FIFO_RESET) {
- fifo_reset(&s->tx);
- s->reg[I_(UFCON)] &= ~UFCON_Tx_FIFO_RESET;
- PRINT_DEBUG("UART%d: Tx FIFO Reset\n", s->channel);
- }
- break;
-
- case UTXH:
- if (s->chr) {
- s->reg[I_(UTRSTAT)] &= ~(UTRSTAT_TRANSMITTER_EMPTY |
- UTRSTAT_Tx_BUFFER_EMPTY);
- ch = (uint8_t)val;
- qemu_chr_fe_write(s->chr, &ch, 1);
-#if DEBUG_Tx_DATA
- fprintf(stderr, "%c", ch);
-#endif
- s->reg[I_(UTRSTAT)] |= UTRSTAT_TRANSMITTER_EMPTY |
- UTRSTAT_Tx_BUFFER_EMPTY;
- s->reg[I_(UINTSP)] |= UINTSP_TXD;
- exynos4210_uart_update_irq(s);
- }
- break;
-
- case UINTP:
- s->reg[I_(UINTP)] &= ~val;
- s->reg[I_(UINTSP)] &= ~val;
- PRINT_DEBUG("UART%d: UINTP [%04x] have been cleared: %08x\n",
- s->channel, offset, s->reg[I_(UINTP)]);
- exynos4210_uart_update_irq(s);
- break;
- case UTRSTAT:
- case UERSTAT:
- case UFSTAT:
- case UMSTAT:
- case URXH:
- PRINT_DEBUG("UART%d: Trying to write into RO register: %s [%04x]\n",
- s->channel, exynos4210_uart_regname(offset), offset);
- break;
- case UINTSP:
- s->reg[I_(UINTSP)] &= ~val;
- break;
- case UINTM:
- s->reg[I_(UINTM)] = val;
- exynos4210_uart_update_irq(s);
- break;
- case UCON:
- case UMCON:
- default:
- s->reg[I_(offset)] = val;
- break;
- }
-}
-static uint64_t exynos4210_uart_read(void *opaque, hwaddr offset,
- unsigned size)
-{
- Exynos4210UartState *s = (Exynos4210UartState *)opaque;
- uint32_t res;
-
- switch (offset) {
- case UERSTAT: /* Read Only */
- res = s->reg[I_(UERSTAT)];
- s->reg[I_(UERSTAT)] = 0;
- return res;
- case UFSTAT: /* Read Only */
- s->reg[I_(UFSTAT)] = fifo_elements_number(&s->rx) & 0xff;
- if (fifo_empty_elements_number(&s->rx) == 0) {
- s->reg[I_(UFSTAT)] |= UFSTAT_Rx_FIFO_FULL;
- s->reg[I_(UFSTAT)] &= ~0xff;
- }
- return s->reg[I_(UFSTAT)];
- case URXH:
- if (s->reg[I_(UFCON)] & UFCON_FIFO_ENABLE) {
- if (fifo_elements_number(&s->rx)) {
- res = fifo_retrieve(&s->rx);
-#if DEBUG_Rx_DATA
- fprintf(stderr, "%c", res);
-#endif
- if (!fifo_elements_number(&s->rx)) {
- s->reg[I_(UTRSTAT)] &= ~UTRSTAT_Rx_BUFFER_DATA_READY;
- } else {
- s->reg[I_(UTRSTAT)] |= UTRSTAT_Rx_BUFFER_DATA_READY;
- }
- } else {
- s->reg[I_(UINTSP)] |= UINTSP_ERROR;
- exynos4210_uart_update_irq(s);
- res = 0;
- }
- } else {
- s->reg[I_(UTRSTAT)] &= ~UTRSTAT_Rx_BUFFER_DATA_READY;
- res = s->reg[I_(URXH)];
- }
- return res;
- case UTXH:
- PRINT_DEBUG("UART%d: Trying to read from WO register: %s [%04x]\n",
- s->channel, exynos4210_uart_regname(offset), offset);
- break;
- default:
- return s->reg[I_(offset)];
- }
-
- return 0;
-}
-
-static const MemoryRegionOps exynos4210_uart_ops = {
- .read = exynos4210_uart_read,
- .write = exynos4210_uart_write,
- .endianness = DEVICE_NATIVE_ENDIAN,
- .valid = {
- .max_access_size = 4,
- .unaligned = false
- },
-};
-
-static int exynos4210_uart_can_receive(void *opaque)
-{
- Exynos4210UartState *s = (Exynos4210UartState *)opaque;
-
- return fifo_empty_elements_number(&s->rx);
-}
-
-
-static void exynos4210_uart_receive(void *opaque, const uint8_t *buf, int size)
-{
- Exynos4210UartState *s = (Exynos4210UartState *)opaque;
- int i;
-
- if (s->reg[I_(UFCON)] & UFCON_FIFO_ENABLE) {
- if (fifo_empty_elements_number(&s->rx) < size) {
- for (i = 0; i < fifo_empty_elements_number(&s->rx); i++) {
- fifo_store(&s->rx, buf[i]);
- }
- s->reg[I_(UINTSP)] |= UINTSP_ERROR;
- s->reg[I_(UTRSTAT)] |= UTRSTAT_Rx_BUFFER_DATA_READY;
- } else {
- for (i = 0; i < size; i++) {
- fifo_store(&s->rx, buf[i]);
- }
- s->reg[I_(UTRSTAT)] |= UTRSTAT_Rx_BUFFER_DATA_READY;
- }
- /* XXX: Around here we maybe should check Rx trigger level */
- s->reg[I_(UINTSP)] |= UINTSP_RXD;
- } else {
- s->reg[I_(URXH)] = buf[0];
- s->reg[I_(UINTSP)] |= UINTSP_RXD;
- s->reg[I_(UTRSTAT)] |= UTRSTAT_Rx_BUFFER_DATA_READY;
- }
-
- exynos4210_uart_update_irq(s);
-}
-
-
-static void exynos4210_uart_event(void *opaque, int event)
-{
- Exynos4210UartState *s = (Exynos4210UartState *)opaque;
-
- if (event == CHR_EVENT_BREAK) {
- /* When the RxDn is held in logic 0, then a null byte is pushed into the
- * fifo */
- fifo_store(&s->rx, '\0');
- s->reg[I_(UERSTAT)] |= UERSTAT_BREAK;
- exynos4210_uart_update_irq(s);
- }
-}
-
-
-static void exynos4210_uart_reset(DeviceState *dev)
-{
- Exynos4210UartState *s =
- container_of(dev, Exynos4210UartState, busdev.qdev);
- int regs_number = sizeof(exynos4210_uart_regs)/sizeof(Exynos4210UartReg);
- int i;
-
- for (i = 0; i < regs_number; i++) {
- s->reg[I_(exynos4210_uart_regs[i].offset)] =
- exynos4210_uart_regs[i].reset_value;
- }
-
- fifo_reset(&s->rx);
- fifo_reset(&s->tx);
-
- PRINT_DEBUG("UART%d: Rx FIFO size: %d\n", s->channel, s->rx.size);
-}
-
-static const VMStateDescription vmstate_exynos4210_uart_fifo = {
- .name = "exynos4210.uart.fifo",
- .version_id = 1,
- .minimum_version_id = 1,
- .minimum_version_id_old = 1,
- .fields = (VMStateField[]) {
- VMSTATE_UINT32(sp, Exynos4210UartFIFO),
- VMSTATE_UINT32(rp, Exynos4210UartFIFO),
- VMSTATE_VBUFFER_UINT32(data, Exynos4210UartFIFO, 1, NULL, 0, size),
- VMSTATE_END_OF_LIST()
- }
-};
-
-static const VMStateDescription vmstate_exynos4210_uart = {
- .name = "exynos4210.uart",
- .version_id = 1,
- .minimum_version_id = 1,
- .minimum_version_id_old = 1,
- .fields = (VMStateField[]) {
- VMSTATE_STRUCT(rx, Exynos4210UartState, 1,
- vmstate_exynos4210_uart_fifo, Exynos4210UartFIFO),
- VMSTATE_UINT32_ARRAY(reg, Exynos4210UartState,
- EXYNOS4210_UART_REGS_MEM_SIZE / sizeof(uint32_t)),
- VMSTATE_END_OF_LIST()
- }
-};
-
-DeviceState *exynos4210_uart_create(hwaddr addr,
- int fifo_size,
- int channel,
- CharDriverState *chr,
- qemu_irq irq)
-{
- DeviceState *dev;
- SysBusDevice *bus;
-
- const char chr_name[] = "serial";
- char label[ARRAY_SIZE(chr_name) + 1];
-
- dev = qdev_create(NULL, "exynos4210.uart");
-
- if (!chr) {
- if (channel >= MAX_SERIAL_PORTS) {
- hw_error("Only %d serial ports are supported by QEMU.\n",
- MAX_SERIAL_PORTS);
- }
- chr = serial_hds[channel];
- if (!chr) {
- snprintf(label, ARRAY_SIZE(label), "%s%d", chr_name, channel);
- chr = qemu_chr_new(label, "null", NULL);
- if (!(chr)) {
- hw_error("Can't assign serial port to UART%d.\n", channel);
- }
- }
- }
-
- qdev_prop_set_chr(dev, "chardev", chr);
- qdev_prop_set_uint32(dev, "channel", channel);
- qdev_prop_set_uint32(dev, "rx-size", fifo_size);
- qdev_prop_set_uint32(dev, "tx-size", fifo_size);
-
- bus = SYS_BUS_DEVICE(dev);
- qdev_init_nofail(dev);
- if (addr != (hwaddr)-1) {
- sysbus_mmio_map(bus, 0, addr);
- }
- sysbus_connect_irq(bus, 0, irq);
-
- return dev;
-}
-
-static int exynos4210_uart_init(SysBusDevice *dev)
-{
- Exynos4210UartState *s = FROM_SYSBUS(Exynos4210UartState, dev);
-
- /* memory mapping */
- memory_region_init_io(&s->iomem, &exynos4210_uart_ops, s, "exynos4210.uart",
- EXYNOS4210_UART_REGS_MEM_SIZE);
- sysbus_init_mmio(dev, &s->iomem);
-
- sysbus_init_irq(dev, &s->irq);
-
- qemu_chr_add_handlers(s->chr, exynos4210_uart_can_receive,
- exynos4210_uart_receive, exynos4210_uart_event, s);
-
- return 0;
-}
-
-static Property exynos4210_uart_properties[] = {
- DEFINE_PROP_CHR("chardev", Exynos4210UartState, chr),
- DEFINE_PROP_UINT32("channel", Exynos4210UartState, channel, 0),
- DEFINE_PROP_UINT32("rx-size", Exynos4210UartState, rx.size, 16),
- DEFINE_PROP_UINT32("tx-size", Exynos4210UartState, tx.size, 16),
- DEFINE_PROP_END_OF_LIST(),
-};
-
-static void exynos4210_uart_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
- SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
-
- k->init = exynos4210_uart_init;
- dc->reset = exynos4210_uart_reset;
- dc->props = exynos4210_uart_properties;
- dc->vmsd = &vmstate_exynos4210_uart;
-}
-
-static const TypeInfo exynos4210_uart_info = {
- .name = "exynos4210.uart",
- .parent = TYPE_SYS_BUS_DEVICE,
- .instance_size = sizeof(Exynos4210UartState),
- .class_init = exynos4210_uart_class_init,
-};
-
-static void exynos4210_uart_register(void)
-{
- type_register_static(&exynos4210_uart_info);
-}
-
-type_init(exynos4210_uart_register)
+++ /dev/null
-/*
- * 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 "hw/sysbus.h"
-#include "char/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 */
-
-#define FIFO_LENGTH 1024
-
-typedef struct UART {
- SysBusDevice busdev;
- MemoryRegion iomem;
- qemu_irq irq;
-
- CharDriverState *chr;
-
- /* registers */
- uint32_t status;
- uint32_t control;
-
- /* FIFO */
- char buffer[FIFO_LENGTH];
- int len;
- int current;
-} UART;
-
-static int uart_data_to_read(UART *uart)
-{
- return uart->current < uart->len;
-}
-
-static char uart_pop(UART *uart)
-{
- char ret;
-
- if (uart->len == 0) {
- uart->status &= ~UART_DATA_READY;
- return 0;
- }
-
- ret = uart->buffer[uart->current++];
-
- if (uart->current >= uart->len) {
- /* Flush */
- uart->len = 0;
- uart->current = 0;
- }
-
- if (!uart_data_to_read(uart)) {
- uart->status &= ~UART_DATA_READY;
- }
-
- return ret;
-}
-
-static void uart_add_to_fifo(UART *uart,
- const uint8_t *buffer,
- int length)
-{
- if (uart->len + length > FIFO_LENGTH) {
- abort();
- }
- memcpy(uart->buffer + uart->len, buffer, length);
- uart->len += length;
-}
-
-static int grlib_apbuart_can_receive(void *opaque)
-{
- UART *uart = opaque;
-
- return FIFO_LENGTH - uart->len;
-}
-
-static void grlib_apbuart_receive(void *opaque, const uint8_t *buf, int size)
-{
- UART *uart = opaque;
-
- if (uart->control & UART_RECEIVE_ENABLE) {
- uart_add_to_fifo(uart, buf, size);
-
- 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 uint64_t grlib_apbuart_read(void *opaque, hwaddr addr,
- unsigned size)
-{
- UART *uart = opaque;
-
- addr &= 0xff;
-
- /* Unit registers */
- switch (addr) {
- case DATA_OFFSET:
- case DATA_OFFSET + 3: /* when only one byte read */
- return uart_pop(uart);
-
- case STATUS_OFFSET:
- /* Read Only */
- return uart->status;
-
- case CONTROL_OFFSET:
- return uart->control;
-
- case SCALER_OFFSET:
- /* Not supported */
- return 0;
-
- default:
- trace_grlib_apbuart_readl_unknown(addr);
- return 0;
- }
-}
-
-static void grlib_apbuart_write(void *opaque, hwaddr addr,
- uint64_t value, unsigned size)
-{
- UART *uart = opaque;
- unsigned char c = 0;
-
- addr &= 0xff;
-
- /* Unit registers */
- switch (addr) {
- case DATA_OFFSET:
- case DATA_OFFSET + 3: /* When only one byte write */
- /* Transmit when character device available and transmitter enabled */
- if ((uart->chr) && (uart->control & UART_TRANSMIT_ENABLE)) {
- c = value & 0xFF;
- qemu_chr_fe_write(uart->chr, &c, 1);
- /* Generate interrupt */
- if (uart->control & UART_TRANSMIT_INTERRUPT) {
- qemu_irq_pulse(uart->irq);
- }
- }
- return;
-
- case STATUS_OFFSET:
- /* Read Only */
- return;
-
- case CONTROL_OFFSET:
- uart->control = value;
- return;
-
- case SCALER_OFFSET:
- /* Not supported */
- return;
-
- default:
- break;
- }
-
- trace_grlib_apbuart_writel_unknown(addr, value);
-}
-
-static const MemoryRegionOps grlib_apbuart_ops = {
- .write = grlib_apbuart_write,
- .read = grlib_apbuart_read,
- .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-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);
-
- memory_region_init_io(&uart->iomem, &grlib_apbuart_ops, uart,
- "uart", UART_REG_SIZE);
-
- sysbus_init_mmio(dev, &uart->iomem);
-
- return 0;
-}
-
-static void grlib_apbuart_reset(DeviceState *d)
-{
- UART *uart = container_of(d, UART, busdev.qdev);
-
- /* Transmitter FIFO and shift registers are always empty in QEMU */
- uart->status = UART_TRANSMIT_FIFO_EMPTY | UART_TRANSMIT_SHIFT_EMPTY;
- /* Everything is off */
- uart->control = 0;
- /* Flush receive FIFO */
- uart->len = 0;
- uart->current = 0;
-}
-
-static Property grlib_apbuart_properties[] = {
- DEFINE_PROP_CHR("chrdev", UART, chr),
- DEFINE_PROP_END_OF_LIST(),
-};
-
-static void grlib_apbuart_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
- SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
-
- k->init = grlib_apbuart_init;
- dc->reset = grlib_apbuart_reset;
- dc->props = grlib_apbuart_properties;
-}
-
-static const TypeInfo grlib_apbuart_info = {
- .name = "grlib,apbuart",
- .parent = TYPE_SYS_BUS_DEVICE,
- .instance_size = sizeof(UART),
- .class_init = grlib_apbuart_class_init,
-};
-
-static void grlib_apbuart_register_types(void)
-{
- type_register_static(&grlib_apbuart_info);
-}
-
-type_init(grlib_apbuart_register_types)
obj-y += apic_common.o apic.o
obj-y += sga.o ioapic_common.o ioapic.o piix_pci.o
obj-y += vmport.o
-obj-y += debugcon.o debugexit.o
+obj-y += debugexit.o
obj-y += lpc_ich9.o q35.o
obj-y += kvm/
obj-y += pc-testdev.o
+++ /dev/null
-/*
- * IMX31 UARTS
- *
- * Copyright (c) 2008 OKL
- * Originally Written by Hans Jiang
- * Copyright (c) 2011 NICTA Pty Ltd.
- *
- * This work is licensed under the terms of the GNU GPL, version 2 or later.
- * See the COPYING file in the top-level directory.
- *
- * This is a `bare-bones' implementation of the IMX series serial ports.
- * TODO:
- * -- implement FIFOs. The real hardware has 32 word transmit
- * and receive FIFOs; we currently use a 1-char buffer
- * -- implement DMA
- * -- implement BAUD-rate and modem lines, for when the backend
- * is a real serial device.
- */
-
-#include "hw/hw.h"
-#include "hw/sysbus.h"
-#include "sysemu/sysemu.h"
-#include "char/char.h"
-#include "hw/arm/imx.h"
-
-//#define DEBUG_SERIAL 1
-#ifdef DEBUG_SERIAL
-#define DPRINTF(fmt, args...) \
-do { printf("imx_serial: " fmt , ##args); } while (0)
-#else
-#define DPRINTF(fmt, args...) do {} while (0)
-#endif
-
-/*
- * Define to 1 for messages about attempts to
- * access unimplemented registers or similar.
- */
-//#define DEBUG_IMPLEMENTATION 1
-#ifdef DEBUG_IMPLEMENTATION
-# define IPRINTF(fmt, args...) \
- do { fprintf(stderr, "imx_serial: " fmt, ##args); } while (0)
-#else
-# define IPRINTF(fmt, args...) do {} while (0)
-#endif
-
-typedef struct {
- SysBusDevice busdev;
- MemoryRegion iomem;
- int32_t readbuff;
-
- uint32_t usr1;
- uint32_t usr2;
- uint32_t ucr1;
- uint32_t ucr2;
- uint32_t uts1;
-
- /*
- * The registers below are implemented just so that the
- * guest OS sees what it has written
- */
- uint32_t onems;
- uint32_t ufcr;
- uint32_t ubmr;
- uint32_t ubrc;
- uint32_t ucr3;
-
- qemu_irq irq;
- CharDriverState *chr;
-} IMXSerialState;
-
-static const VMStateDescription vmstate_imx_serial = {
- .name = "imx-serial",
- .version_id = 1,
- .minimum_version_id = 1,
- .minimum_version_id_old = 1,
- .fields = (VMStateField[]) {
- VMSTATE_INT32(readbuff, IMXSerialState),
- VMSTATE_UINT32(usr1, IMXSerialState),
- VMSTATE_UINT32(usr2, IMXSerialState),
- VMSTATE_UINT32(ucr1, IMXSerialState),
- VMSTATE_UINT32(uts1, IMXSerialState),
- VMSTATE_UINT32(onems, IMXSerialState),
- VMSTATE_UINT32(ufcr, IMXSerialState),
- VMSTATE_UINT32(ubmr, IMXSerialState),
- VMSTATE_UINT32(ubrc, IMXSerialState),
- VMSTATE_UINT32(ucr3, IMXSerialState),
- VMSTATE_END_OF_LIST()
- },
-};
-
-
-#define URXD_CHARRDY (1<<15) /* character read is valid */
-#define URXD_ERR (1<<14) /* Character has error */
-#define URXD_BRK (1<<11) /* Break received */
-
-#define USR1_PARTYER (1<<15) /* Parity Error */
-#define USR1_RTSS (1<<14) /* RTS pin status */
-#define USR1_TRDY (1<<13) /* Tx ready */
-#define USR1_RTSD (1<<12) /* RTS delta: pin changed state */
-#define USR1_ESCF (1<<11) /* Escape sequence interrupt */
-#define USR1_FRAMERR (1<<10) /* Framing error */
-#define USR1_RRDY (1<<9) /* receiver ready */
-#define USR1_AGTIM (1<<8) /* Aging timer interrupt */
-#define USR1_DTRD (1<<7) /* DTR changed */
-#define USR1_RXDS (1<<6) /* Receiver is idle */
-#define USR1_AIRINT (1<<5) /* Aysnch IR interrupt */
-#define USR1_AWAKE (1<<4) /* Falling edge detected on RXd pin */
-
-#define USR2_ADET (1<<15) /* Autobaud complete */
-#define USR2_TXFE (1<<14) /* Transmit FIFO empty */
-#define USR2_DTRF (1<<13) /* DTR/DSR transition */
-#define USR2_IDLE (1<<12) /* UART has been idle for too long */
-#define USR2_ACST (1<<11) /* Autobaud counter stopped */
-#define USR2_RIDELT (1<<10) /* Ring Indicator delta */
-#define USR2_RIIN (1<<9) /* Ring Indicator Input */
-#define USR2_IRINT (1<<8) /* Serial Infrared Interrupt */
-#define USR2_WAKE (1<<7) /* Start bit detected */
-#define USR2_DCDDELT (1<<6) /* Data Carrier Detect delta */
-#define USR2_DCDIN (1<<5) /* Data Carrier Detect Input */
-#define USR2_RTSF (1<<4) /* RTS transition */
-#define USR2_TXDC (1<<3) /* Transmission complete */
-#define USR2_BRCD (1<<2) /* Break condition detected */
-#define USR2_ORE (1<<1) /* Overrun error */
-#define USR2_RDR (1<<0) /* Receive data ready */
-
-#define UCR1_TRDYEN (1<<13) /* Tx Ready Interrupt Enable */
-#define UCR1_RRDYEN (1<<9) /* Rx Ready Interrupt Enable */
-#define UCR1_TXMPTYEN (1<<6) /* Tx Empty Interrupt Enable */
-#define UCR1_UARTEN (1<<0) /* UART Enable */
-
-#define UCR2_TXEN (1<<2) /* Transmitter enable */
-#define UCR2_RXEN (1<<1) /* Receiver enable */
-#define UCR2_SRST (1<<0) /* Reset complete */
-
-#define UTS1_TXEMPTY (1<<6)
-#define UTS1_RXEMPTY (1<<5)
-#define UTS1_TXFULL (1<<4)
-#define UTS1_RXFULL (1<<3)
-
-static void imx_update(IMXSerialState *s)
-{
- uint32_t flags;
-
- flags = (s->usr1 & s->ucr1) & (USR1_TRDY|USR1_RRDY);
- if (!(s->ucr1 & UCR1_TXMPTYEN)) {
- flags &= ~USR1_TRDY;
- }
-
- qemu_set_irq(s->irq, !!flags);
-}
-
-static void imx_serial_reset(IMXSerialState *s)
-{
-
- s->usr1 = USR1_TRDY | USR1_RXDS;
- /*
- * Fake attachment of a terminal: assert RTS.
- */
- s->usr1 |= USR1_RTSS;
- s->usr2 = USR2_TXFE | USR2_TXDC | USR2_DCDIN;
- s->uts1 = UTS1_RXEMPTY | UTS1_TXEMPTY;
- s->ucr1 = 0;
- s->ucr2 = UCR2_SRST;
- s->ucr3 = 0x700;
- s->ubmr = 0;
- s->ubrc = 4;
- s->readbuff = URXD_ERR;
-}
-
-static void imx_serial_reset_at_boot(DeviceState *dev)
-{
- IMXSerialState *s = container_of(dev, IMXSerialState, busdev.qdev);
-
- imx_serial_reset(s);
-
- /*
- * enable the uart on boot, so messages from the linux decompresser
- * are visible. On real hardware this is done by the boot rom
- * before anything else is loaded.
- */
- s->ucr1 = UCR1_UARTEN;
- s->ucr2 = UCR2_TXEN;
-
-}
-
-static uint64_t imx_serial_read(void *opaque, hwaddr offset,
- unsigned size)
-{
- IMXSerialState *s = (IMXSerialState *)opaque;
- uint32_t c;
-
- DPRINTF("read(offset=%x)\n", offset >> 2);
- switch (offset >> 2) {
- case 0x0: /* URXD */
- c = s->readbuff;
- if (!(s->uts1 & UTS1_RXEMPTY)) {
- /* Character is valid */
- c |= URXD_CHARRDY;
- s->usr1 &= ~USR1_RRDY;
- s->usr2 &= ~USR2_RDR;
- s->uts1 |= UTS1_RXEMPTY;
- imx_update(s);
- qemu_chr_accept_input(s->chr);
- }
- return c;
-
- case 0x20: /* UCR1 */
- return s->ucr1;
-
- case 0x21: /* UCR2 */
- return s->ucr2;
-
- case 0x25: /* USR1 */
- return s->usr1;
-
- case 0x26: /* USR2 */
- return s->usr2;
-
- case 0x2A: /* BRM Modulator */
- return s->ubmr;
-
- case 0x2B: /* Baud Rate Count */
- return s->ubrc;
-
- case 0x2d: /* Test register */
- return s->uts1;
-
- case 0x24: /* UFCR */
- return s->ufcr;
-
- case 0x2c:
- return s->onems;
-
- case 0x22: /* UCR3 */
- return s->ucr3;
-
- case 0x23: /* UCR4 */
- case 0x29: /* BRM Incremental */
- return 0x0; /* TODO */
-
- default:
- IPRINTF("imx_serial_read: bad offset: 0x%x\n", (int)offset);
- return 0;
- }
-}
-
-static void imx_serial_write(void *opaque, hwaddr offset,
- uint64_t value, unsigned size)
-{
- IMXSerialState *s = (IMXSerialState *)opaque;
- unsigned char ch;
-
- DPRINTF("write(offset=%x, value = %x) to %s\n",
- offset >> 2,
- (unsigned int)value, s->chr ? s->chr->label : "NODEV");
-
- switch (offset >> 2) {
- case 0x10: /* UTXD */
- ch = value;
- if (s->ucr2 & UCR2_TXEN) {
- if (s->chr) {
- qemu_chr_fe_write(s->chr, &ch, 1);
- }
- s->usr1 &= ~USR1_TRDY;
- imx_update(s);
- s->usr1 |= USR1_TRDY;
- imx_update(s);
- }
- break;
-
- case 0x20: /* UCR1 */
- s->ucr1 = value & 0xffff;
- DPRINTF("write(ucr1=%x)\n", (unsigned int)value);
- imx_update(s);
- break;
-
- case 0x21: /* UCR2 */
- /*
- * Only a few bits in control register 2 are implemented as yet.
- * If it's intended to use a real serial device as a back-end, this
- * register will have to be implemented more fully.
- */
- if (!(value & UCR2_SRST)) {
- imx_serial_reset(s);
- imx_update(s);
- value |= UCR2_SRST;
- }
- if (value & UCR2_RXEN) {
- if (!(s->ucr2 & UCR2_RXEN)) {
- qemu_chr_accept_input(s->chr);
- }
- }
- s->ucr2 = value & 0xffff;
- break;
-
- case 0x25: /* USR1 */
- value &= USR1_AWAKE | USR1_AIRINT | USR1_DTRD | USR1_AGTIM |
- USR1_FRAMERR | USR1_ESCF | USR1_RTSD | USR1_PARTYER;
- s->usr1 &= ~value;
- break;
-
- case 0x26: /* USR2 */
- /*
- * Writing 1 to some bits clears them; all other
- * values are ignored
- */
- value &= USR2_ADET | USR2_DTRF | USR2_IDLE | USR2_ACST |
- USR2_RIDELT | USR2_IRINT | USR2_WAKE |
- USR2_DCDDELT | USR2_RTSF | USR2_BRCD | USR2_ORE;
- s->usr2 &= ~value;
- break;
-
- /*
- * Linux expects to see what it writes to these registers
- * We don't currently alter the baud rate
- */
- case 0x29: /* UBIR */
- s->ubrc = value & 0xffff;
- break;
-
- case 0x2a: /* UBMR */
- s->ubmr = value & 0xffff;
- break;
-
- case 0x2c: /* One ms reg */
- s->onems = value & 0xffff;
- break;
-
- case 0x24: /* FIFO control register */
- s->ufcr = value & 0xffff;
- break;
-
- case 0x22: /* UCR3 */
- s->ucr3 = value & 0xffff;
- break;
-
- case 0x2d: /* UTS1 */
- case 0x23: /* UCR4 */
- IPRINTF("Unimplemented Register %x written to\n", offset >> 2);
- /* TODO */
- break;
-
- default:
- IPRINTF("imx_serial_write: Bad offset 0x%x\n", (int)offset);
- }
-}
-
-static int imx_can_receive(void *opaque)
-{
- IMXSerialState *s = (IMXSerialState *)opaque;
- return !(s->usr1 & USR1_RRDY);
-}
-
-static void imx_put_data(void *opaque, uint32_t value)
-{
- IMXSerialState *s = (IMXSerialState *)opaque;
- DPRINTF("received char\n");
- s->usr1 |= USR1_RRDY;
- s->usr2 |= USR2_RDR;
- s->uts1 &= ~UTS1_RXEMPTY;
- s->readbuff = value;
- imx_update(s);
-}
-
-static void imx_receive(void *opaque, const uint8_t *buf, int size)
-{
- imx_put_data(opaque, *buf);
-}
-
-static void imx_event(void *opaque, int event)
-{
- if (event == CHR_EVENT_BREAK) {
- imx_put_data(opaque, URXD_BRK);
- }
-}
-
-
-static const struct MemoryRegionOps imx_serial_ops = {
- .read = imx_serial_read,
- .write = imx_serial_write,
- .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-static int imx_serial_init(SysBusDevice *dev)
-{
- IMXSerialState *s = FROM_SYSBUS(IMXSerialState, dev);
-
-
- memory_region_init_io(&s->iomem, &imx_serial_ops, s, "imx-serial", 0x1000);
- sysbus_init_mmio(dev, &s->iomem);
- sysbus_init_irq(dev, &s->irq);
-
- if (s->chr) {
- qemu_chr_add_handlers(s->chr, imx_can_receive, imx_receive,
- imx_event, s);
- } else {
- DPRINTF("No char dev for uart at 0x%lx\n",
- (unsigned long)s->iomem.ram_addr);
- }
-
- return 0;
-}
-
-void imx_serial_create(int uart, const hwaddr addr, qemu_irq irq)
-{
- DeviceState *dev;
- SysBusDevice *bus;
- CharDriverState *chr;
- const char chr_name[] = "serial";
- char label[ARRAY_SIZE(chr_name) + 1];
-
- dev = qdev_create(NULL, "imx-serial");
-
- if (uart >= MAX_SERIAL_PORTS) {
- hw_error("Cannot assign uart %d: QEMU supports only %d ports\n",
- uart, MAX_SERIAL_PORTS);
- }
- chr = serial_hds[uart];
- if (!chr) {
- snprintf(label, ARRAY_SIZE(label), "%s%d", chr_name, uart);
- chr = qemu_chr_new(label, "null", NULL);
- if (!(chr)) {
- hw_error("Can't assign serial port to imx-uart%d.\n", uart);
- }
- }
-
- qdev_prop_set_chr(dev, "chardev", chr);
- bus = SYS_BUS_DEVICE(dev);
- qdev_init_nofail(dev);
- if (addr != (hwaddr)-1) {
- sysbus_mmio_map(bus, 0, addr);
- }
- sysbus_connect_irq(bus, 0, irq);
-
-}
-
-
-static Property imx32_serial_properties[] = {
- DEFINE_PROP_CHR("chardev", IMXSerialState, chr),
- DEFINE_PROP_END_OF_LIST(),
-};
-
-static void imx_serial_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
- SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
-
- k->init = imx_serial_init;
- dc->vmsd = &vmstate_imx_serial;
- dc->reset = imx_serial_reset_at_boot;
- dc->desc = "i.MX series UART";
- dc->props = imx32_serial_properties;
-}
-
-static const TypeInfo imx_serial_info = {
- .name = "imx-serial",
- .parent = TYPE_SYS_BUS_DEVICE,
- .instance_size = sizeof(IMXSerialState),
- .class_init = imx_serial_class_init,
-};
-
-static void imx_serial_register_types(void)
-{
- type_register_static(&imx_serial_info);
-}
-
-type_init(imx_serial_register_types)
# LM32 peripherals
obj-y += lm32_pic.o
-obj-y += lm32_juart.o
obj-y += lm32_timer.o
-obj-y += lm32_uart.o
obj-y += lm32_sys.o
obj-y += milkymist-hpdmc.o
obj-y += milkymist-memcard.o
obj-y += milkymist-pfpu.o
obj-y += milkymist-softusb.o
obj-y += milkymist-sysctl.o
-obj-y += milkymist-uart.o
obj-y := $(addprefix ../,$(obj-y))
+++ /dev/null
-/*
- * LatticeMico32 JTAG UART model.
- *
- * Copyright (c) 2010 Michael Walle <michael@walle.cc>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, see <http://www.gnu.org/licenses/>.
- */
-
-#include "hw/hw.h"
-#include "hw/sysbus.h"
-#include "trace.h"
-#include "char/char.h"
-
-#include "hw/lm32/lm32_juart.h"
-
-enum {
- LM32_JUART_MIN_SAVE_VERSION = 0,
- LM32_JUART_CURRENT_SAVE_VERSION = 0,
- LM32_JUART_MAX_SAVE_VERSION = 0,
-};
-
-enum {
- JTX_FULL = (1<<8),
-};
-
-enum {
- JRX_FULL = (1<<8),
-};
-
-struct LM32JuartState {
- SysBusDevice busdev;
- CharDriverState *chr;
-
- uint32_t jtx;
- uint32_t jrx;
-};
-typedef struct LM32JuartState LM32JuartState;
-
-uint32_t lm32_juart_get_jtx(DeviceState *d)
-{
- LM32JuartState *s = container_of(d, LM32JuartState, busdev.qdev);
-
- trace_lm32_juart_get_jtx(s->jtx);
- return s->jtx;
-}
-
-uint32_t lm32_juart_get_jrx(DeviceState *d)
-{
- LM32JuartState *s = container_of(d, LM32JuartState, busdev.qdev);
-
- trace_lm32_juart_get_jrx(s->jrx);
- return s->jrx;
-}
-
-void lm32_juart_set_jtx(DeviceState *d, uint32_t jtx)
-{
- LM32JuartState *s = container_of(d, LM32JuartState, busdev.qdev);
- unsigned char ch = jtx & 0xff;
-
- trace_lm32_juart_set_jtx(s->jtx);
-
- s->jtx = jtx;
- if (s->chr) {
- qemu_chr_fe_write(s->chr, &ch, 1);
- }
-}
-
-void lm32_juart_set_jrx(DeviceState *d, uint32_t jtx)
-{
- LM32JuartState *s = container_of(d, LM32JuartState, busdev.qdev);
-
- trace_lm32_juart_set_jrx(s->jrx);
- s->jrx &= ~JRX_FULL;
-}
-
-static void juart_rx(void *opaque, const uint8_t *buf, int size)
-{
- LM32JuartState *s = opaque;
-
- s->jrx = *buf | JRX_FULL;
-}
-
-static int juart_can_rx(void *opaque)
-{
- LM32JuartState *s = opaque;
-
- return !(s->jrx & JRX_FULL);
-}
-
-static void juart_event(void *opaque, int event)
-{
-}
-
-static void juart_reset(DeviceState *d)
-{
- LM32JuartState *s = container_of(d, LM32JuartState, busdev.qdev);
-
- s->jtx = 0;
- s->jrx = 0;
-}
-
-static int lm32_juart_init(SysBusDevice *dev)
-{
- LM32JuartState *s = FROM_SYSBUS(typeof(*s), dev);
-
- s->chr = qemu_char_get_next_serial();
- if (s->chr) {
- qemu_chr_add_handlers(s->chr, juart_can_rx, juart_rx, juart_event, s);
- }
-
- return 0;
-}
-
-static const VMStateDescription vmstate_lm32_juart = {
- .name = "lm32-juart",
- .version_id = 1,
- .minimum_version_id = 1,
- .minimum_version_id_old = 1,
- .fields = (VMStateField[]) {
- VMSTATE_UINT32(jtx, LM32JuartState),
- VMSTATE_UINT32(jrx, LM32JuartState),
- VMSTATE_END_OF_LIST()
- }
-};
-
-static void lm32_juart_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
- SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
-
- k->init = lm32_juart_init;
- dc->reset = juart_reset;
- dc->vmsd = &vmstate_lm32_juart;
-}
-
-static const TypeInfo lm32_juart_info = {
- .name = "lm32-juart",
- .parent = TYPE_SYS_BUS_DEVICE,
- .instance_size = sizeof(LM32JuartState),
- .class_init = lm32_juart_class_init,
-};
-
-static void lm32_juart_register_types(void)
-{
- type_register_static(&lm32_juart_info);
-}
-
-type_init(lm32_juart_register_types)
+++ /dev/null
-/*
- * QEMU model of the LatticeMico32 UART block.
- *
- * Copyright (c) 2010 Michael Walle <michael@walle.cc>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, see <http://www.gnu.org/licenses/>.
- *
- *
- * Specification available at:
- * http://www.latticesemi.com/documents/mico32uart.pdf
- */
-
-
-#include "hw/hw.h"
-#include "hw/sysbus.h"
-#include "trace.h"
-#include "char/char.h"
-#include "qemu/error-report.h"
-
-enum {
- R_RXTX = 0,
- R_IER,
- R_IIR,
- R_LCR,
- R_MCR,
- R_LSR,
- R_MSR,
- R_DIV,
- R_MAX
-};
-
-enum {
- IER_RBRI = (1<<0),
- IER_THRI = (1<<1),
- IER_RLSI = (1<<2),
- IER_MSI = (1<<3),
-};
-
-enum {
- IIR_STAT = (1<<0),
- IIR_ID0 = (1<<1),
- IIR_ID1 = (1<<2),
-};
-
-enum {
- LCR_WLS0 = (1<<0),
- LCR_WLS1 = (1<<1),
- LCR_STB = (1<<2),
- LCR_PEN = (1<<3),
- LCR_EPS = (1<<4),
- LCR_SP = (1<<5),
- LCR_SB = (1<<6),
-};
-
-enum {
- MCR_DTR = (1<<0),
- MCR_RTS = (1<<1),
-};
-
-enum {
- LSR_DR = (1<<0),
- LSR_OE = (1<<1),
- LSR_PE = (1<<2),
- LSR_FE = (1<<3),
- LSR_BI = (1<<4),
- LSR_THRE = (1<<5),
- LSR_TEMT = (1<<6),
-};
-
-enum {
- MSR_DCTS = (1<<0),
- MSR_DDSR = (1<<1),
- MSR_TERI = (1<<2),
- MSR_DDCD = (1<<3),
- MSR_CTS = (1<<4),
- MSR_DSR = (1<<5),
- MSR_RI = (1<<6),
- MSR_DCD = (1<<7),
-};
-
-struct LM32UartState {
- SysBusDevice busdev;
- MemoryRegion iomem;
- CharDriverState *chr;
- qemu_irq irq;
-
- uint32_t regs[R_MAX];
-};
-typedef struct LM32UartState LM32UartState;
-
-static void uart_update_irq(LM32UartState *s)
-{
- unsigned int irq;
-
- if ((s->regs[R_LSR] & (LSR_OE | LSR_PE | LSR_FE | LSR_BI))
- && (s->regs[R_IER] & IER_RLSI)) {
- irq = 1;
- s->regs[R_IIR] = IIR_ID1 | IIR_ID0;
- } else if ((s->regs[R_LSR] & LSR_DR) && (s->regs[R_IER] & IER_RBRI)) {
- irq = 1;
- s->regs[R_IIR] = IIR_ID1;
- } else if ((s->regs[R_LSR] & LSR_THRE) && (s->regs[R_IER] & IER_THRI)) {
- irq = 1;
- s->regs[R_IIR] = IIR_ID0;
- } else if ((s->regs[R_MSR] & 0x0f) && (s->regs[R_IER] & IER_MSI)) {
- irq = 1;
- s->regs[R_IIR] = 0;
- } else {
- irq = 0;
- s->regs[R_IIR] = IIR_STAT;
- }
-
- trace_lm32_uart_irq_state(irq);
- qemu_set_irq(s->irq, irq);
-}
-
-static uint64_t uart_read(void *opaque, hwaddr addr,
- unsigned size)
-{
- LM32UartState *s = opaque;
- uint32_t r = 0;
-
- addr >>= 2;
- switch (addr) {
- case R_RXTX:
- r = s->regs[R_RXTX];
- s->regs[R_LSR] &= ~LSR_DR;
- uart_update_irq(s);
- qemu_chr_accept_input(s->chr);
- break;
- case R_IIR:
- case R_LSR:
- case R_MSR:
- r = s->regs[addr];
- break;
- case R_IER:
- case R_LCR:
- case R_MCR:
- case R_DIV:
- error_report("lm32_uart: read access to write only register 0x"
- TARGET_FMT_plx, addr << 2);
- break;
- default:
- error_report("lm32_uart: read access to unknown register 0x"
- TARGET_FMT_plx, addr << 2);
- break;
- }
-
- trace_lm32_uart_memory_read(addr << 2, r);
- return r;
-}
-
-static void uart_write(void *opaque, hwaddr addr,
- uint64_t value, unsigned size)
-{
- LM32UartState *s = opaque;
- unsigned char ch = value;
-
- trace_lm32_uart_memory_write(addr, value);
-
- addr >>= 2;
- switch (addr) {
- case R_RXTX:
- if (s->chr) {
- qemu_chr_fe_write(s->chr, &ch, 1);
- }
- break;
- case R_IER:
- case R_LCR:
- case R_MCR:
- case R_DIV:
- s->regs[addr] = value;
- break;
- case R_IIR:
- case R_LSR:
- case R_MSR:
- error_report("lm32_uart: write access to read only register 0x"
- TARGET_FMT_plx, addr << 2);
- break;
- default:
- error_report("lm32_uart: write access to unknown register 0x"
- TARGET_FMT_plx, addr << 2);
- break;
- }
- uart_update_irq(s);
-}
-
-static const MemoryRegionOps uart_ops = {
- .read = uart_read,
- .write = uart_write,
- .endianness = DEVICE_NATIVE_ENDIAN,
- .valid = {
- .min_access_size = 4,
- .max_access_size = 4,
- },
-};
-
-static void uart_rx(void *opaque, const uint8_t *buf, int size)
-{
- LM32UartState *s = opaque;
-
- if (s->regs[R_LSR] & LSR_DR) {
- s->regs[R_LSR] |= LSR_OE;
- }
-
- s->regs[R_LSR] |= LSR_DR;
- s->regs[R_RXTX] = *buf;
-
- uart_update_irq(s);
-}
-
-static int uart_can_rx(void *opaque)
-{
- LM32UartState *s = opaque;
-
- return !(s->regs[R_LSR] & LSR_DR);
-}
-
-static void uart_event(void *opaque, int event)
-{
-}
-
-static void uart_reset(DeviceState *d)
-{
- LM32UartState *s = container_of(d, LM32UartState, busdev.qdev);
- int i;
-
- for (i = 0; i < R_MAX; i++) {
- s->regs[i] = 0;
- }
-
- /* defaults */
- s->regs[R_LSR] = LSR_THRE | LSR_TEMT;
-}
-
-static int lm32_uart_init(SysBusDevice *dev)
-{
- LM32UartState *s = FROM_SYSBUS(typeof(*s), dev);
-
- sysbus_init_irq(dev, &s->irq);
-
- memory_region_init_io(&s->iomem, &uart_ops, s, "uart", R_MAX * 4);
- sysbus_init_mmio(dev, &s->iomem);
-
- s->chr = qemu_char_get_next_serial();
- if (s->chr) {
- qemu_chr_add_handlers(s->chr, uart_can_rx, uart_rx, uart_event, s);
- }
-
- return 0;
-}
-
-static const VMStateDescription vmstate_lm32_uart = {
- .name = "lm32-uart",
- .version_id = 1,
- .minimum_version_id = 1,
- .minimum_version_id_old = 1,
- .fields = (VMStateField[]) {
- VMSTATE_UINT32_ARRAY(regs, LM32UartState, R_MAX),
- VMSTATE_END_OF_LIST()
- }
-};
-
-static void lm32_uart_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
- SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
-
- k->init = lm32_uart_init;
- dc->reset = uart_reset;
- dc->vmsd = &vmstate_lm32_uart;
-}
-
-static const TypeInfo lm32_uart_info = {
- .name = "lm32-uart",
- .parent = TYPE_SYS_BUS_DEVICE,
- .instance_size = sizeof(LM32UartState),
- .class_init = lm32_uart_class_init,
-};
-
-static void lm32_uart_register_types(void)
-{
- type_register_static(&lm32_uart_info);
-}
-
-type_init(lm32_uart_register_types)
-obj-y = mcf_uart.o
-
-obj-y := $(addprefix ../,$(obj-y))
-
obj-y += an5206.o mcf5208.o
obj-y += dummy_m68k.o
+++ /dev/null
-/*
- * ColdFire UART emulation.
- *
- * Copyright (c) 2007 CodeSourcery.
- *
- * This code is licensed under the GPL
- */
-#include "hw/hw.h"
-#include "hw/m68k/mcf.h"
-#include "char/char.h"
-#include "exec/address-spaces.h"
-
-typedef struct {
- MemoryRegion iomem;
- uint8_t mr[2];
- uint8_t sr;
- uint8_t isr;
- uint8_t imr;
- uint8_t bg1;
- uint8_t bg2;
- uint8_t fifo[4];
- uint8_t tb;
- int current_mr;
- int fifo_len;
- int tx_enabled;
- int rx_enabled;
- qemu_irq irq;
- CharDriverState *chr;
-} mcf_uart_state;
-
-/* UART Status Register bits. */
-#define MCF_UART_RxRDY 0x01
-#define MCF_UART_FFULL 0x02
-#define MCF_UART_TxRDY 0x04
-#define MCF_UART_TxEMP 0x08
-#define MCF_UART_OE 0x10
-#define MCF_UART_PE 0x20
-#define MCF_UART_FE 0x40
-#define MCF_UART_RB 0x80
-
-/* Interrupt flags. */
-#define MCF_UART_TxINT 0x01
-#define MCF_UART_RxINT 0x02
-#define MCF_UART_DBINT 0x04
-#define MCF_UART_COSINT 0x80
-
-/* UMR1 flags. */
-#define MCF_UART_BC0 0x01
-#define MCF_UART_BC1 0x02
-#define MCF_UART_PT 0x04
-#define MCF_UART_PM0 0x08
-#define MCF_UART_PM1 0x10
-#define MCF_UART_ERR 0x20
-#define MCF_UART_RxIRQ 0x40
-#define MCF_UART_RxRTS 0x80
-
-static void mcf_uart_update(mcf_uart_state *s)
-{
- s->isr &= ~(MCF_UART_TxINT | MCF_UART_RxINT);
- if (s->sr & MCF_UART_TxRDY)
- s->isr |= MCF_UART_TxINT;
- if ((s->sr & ((s->mr[0] & MCF_UART_RxIRQ)
- ? MCF_UART_FFULL : MCF_UART_RxRDY)) != 0)
- s->isr |= MCF_UART_RxINT;
-
- qemu_set_irq(s->irq, (s->isr & s->imr) != 0);
-}
-
-uint64_t mcf_uart_read(void *opaque, hwaddr addr,
- unsigned size)
-{
- mcf_uart_state *s = (mcf_uart_state *)opaque;
- switch (addr & 0x3f) {
- case 0x00:
- return s->mr[s->current_mr];
- case 0x04:
- return s->sr;
- case 0x0c:
- {
- uint8_t val;
- int i;
-
- if (s->fifo_len == 0)
- return 0;
-
- val = s->fifo[0];
- s->fifo_len--;
- for (i = 0; i < s->fifo_len; i++)
- s->fifo[i] = s->fifo[i + 1];
- s->sr &= ~MCF_UART_FFULL;
- if (s->fifo_len == 0)
- s->sr &= ~MCF_UART_RxRDY;
- mcf_uart_update(s);
- qemu_chr_accept_input(s->chr);
- return val;
- }
- case 0x10:
- /* TODO: Implement IPCR. */
- return 0;
- case 0x14:
- return s->isr;
- case 0x18:
- return s->bg1;
- case 0x1c:
- return s->bg2;
- default:
- return 0;
- }
-}
-
-/* Update TxRDY flag and set data if present and enabled. */
-static void mcf_uart_do_tx(mcf_uart_state *s)
-{
- if (s->tx_enabled && (s->sr & MCF_UART_TxEMP) == 0) {
- if (s->chr)
- qemu_chr_fe_write(s->chr, (unsigned char *)&s->tb, 1);
- s->sr |= MCF_UART_TxEMP;
- }
- if (s->tx_enabled) {
- s->sr |= MCF_UART_TxRDY;
- } else {
- s->sr &= ~MCF_UART_TxRDY;
- }
-}
-
-static void mcf_do_command(mcf_uart_state *s, uint8_t cmd)
-{
- /* Misc command. */
- switch ((cmd >> 4) & 3) {
- case 0: /* No-op. */
- break;
- case 1: /* Reset mode register pointer. */
- s->current_mr = 0;
- break;
- case 2: /* Reset receiver. */
- s->rx_enabled = 0;
- s->fifo_len = 0;
- s->sr &= ~(MCF_UART_RxRDY | MCF_UART_FFULL);
- break;
- case 3: /* Reset transmitter. */
- s->tx_enabled = 0;
- s->sr |= MCF_UART_TxEMP;
- s->sr &= ~MCF_UART_TxRDY;
- break;
- case 4: /* Reset error status. */
- break;
- case 5: /* Reset break-change interrupt. */
- s->isr &= ~MCF_UART_DBINT;
- break;
- case 6: /* Start break. */
- case 7: /* Stop break. */
- break;
- }
-
- /* Transmitter command. */
- switch ((cmd >> 2) & 3) {
- case 0: /* No-op. */
- break;
- case 1: /* Enable. */
- s->tx_enabled = 1;
- mcf_uart_do_tx(s);
- break;
- case 2: /* Disable. */
- s->tx_enabled = 0;
- mcf_uart_do_tx(s);
- break;
- case 3: /* Reserved. */
- fprintf(stderr, "mcf_uart: Bad TX command\n");
- break;
- }
-
- /* Receiver command. */
- switch (cmd & 3) {
- case 0: /* No-op. */
- break;
- case 1: /* Enable. */
- s->rx_enabled = 1;
- break;
- case 2:
- s->rx_enabled = 0;
- break;
- case 3: /* Reserved. */
- fprintf(stderr, "mcf_uart: Bad RX command\n");
- break;
- }
-}
-
-void mcf_uart_write(void *opaque, hwaddr addr,
- uint64_t val, unsigned size)
-{
- mcf_uart_state *s = (mcf_uart_state *)opaque;
- switch (addr & 0x3f) {
- case 0x00:
- s->mr[s->current_mr] = val;
- s->current_mr = 1;
- break;
- case 0x04:
- /* CSR is ignored. */
- break;
- case 0x08: /* Command Register. */
- mcf_do_command(s, val);
- break;
- case 0x0c: /* Transmit Buffer. */
- s->sr &= ~MCF_UART_TxEMP;
- s->tb = val;
- mcf_uart_do_tx(s);
- break;
- case 0x10:
- /* ACR is ignored. */
- break;
- case 0x14:
- s->imr = val;
- break;
- default:
- break;
- }
- mcf_uart_update(s);
-}
-
-static void mcf_uart_reset(mcf_uart_state *s)
-{
- s->fifo_len = 0;
- s->mr[0] = 0;
- s->mr[1] = 0;
- s->sr = MCF_UART_TxEMP;
- s->tx_enabled = 0;
- s->rx_enabled = 0;
- s->isr = 0;
- s->imr = 0;
-}
-
-static void mcf_uart_push_byte(mcf_uart_state *s, uint8_t data)
-{
- /* Break events overwrite the last byte if the fifo is full. */
- if (s->fifo_len == 4)
- s->fifo_len--;
-
- s->fifo[s->fifo_len] = data;
- s->fifo_len++;
- s->sr |= MCF_UART_RxRDY;
- if (s->fifo_len == 4)
- s->sr |= MCF_UART_FFULL;
-
- mcf_uart_update(s);
-}
-
-static void mcf_uart_event(void *opaque, int event)
-{
- mcf_uart_state *s = (mcf_uart_state *)opaque;
-
- switch (event) {
- case CHR_EVENT_BREAK:
- s->isr |= MCF_UART_DBINT;
- mcf_uart_push_byte(s, 0);
- break;
- default:
- break;
- }
-}
-
-static int mcf_uart_can_receive(void *opaque)
-{
- mcf_uart_state *s = (mcf_uart_state *)opaque;
-
- return s->rx_enabled && (s->sr & MCF_UART_FFULL) == 0;
-}
-
-static void mcf_uart_receive(void *opaque, const uint8_t *buf, int size)
-{
- mcf_uart_state *s = (mcf_uart_state *)opaque;
-
- mcf_uart_push_byte(s, buf[0]);
-}
-
-void *mcf_uart_init(qemu_irq irq, CharDriverState *chr)
-{
- mcf_uart_state *s;
-
- s = g_malloc0(sizeof(mcf_uart_state));
- s->chr = chr;
- s->irq = irq;
- if (chr) {
- qemu_chr_fe_claim_no_fail(chr);
- qemu_chr_add_handlers(chr, mcf_uart_can_receive, mcf_uart_receive,
- mcf_uart_event, s);
- }
- mcf_uart_reset(s);
- return s;
-}
-
-static const MemoryRegionOps mcf_uart_ops = {
- .read = mcf_uart_read,
- .write = mcf_uart_write,
- .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-void mcf_uart_mm_init(MemoryRegion *sysmem,
- hwaddr base,
- qemu_irq irq,
- CharDriverState *chr)
-{
- mcf_uart_state *s;
-
- s = mcf_uart_init(irq, chr);
- memory_region_init_io(&s->iomem, &mcf_uart_ops, s, "uart", 0x40);
- memory_region_add_subregion(sysmem, base, &s->iomem);
-}
+++ /dev/null
-/*
- * QEMU model of the Milkymist UART block.
- *
- * Copyright (c) 2010 Michael Walle <michael@walle.cc>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, see <http://www.gnu.org/licenses/>.
- *
- *
- * Specification available at:
- * http://www.milkymist.org/socdoc/uart.pdf
- */
-
-#include "hw/hw.h"
-#include "hw/sysbus.h"
-#include "trace.h"
-#include "char/char.h"
-#include "qemu/error-report.h"
-
-enum {
- R_RXTX = 0,
- R_DIV,
- R_STAT,
- R_CTRL,
- R_DBG,
- R_MAX
-};
-
-enum {
- STAT_THRE = (1<<0),
- STAT_RX_EVT = (1<<1),
- STAT_TX_EVT = (1<<2),
-};
-
-enum {
- CTRL_RX_IRQ_EN = (1<<0),
- CTRL_TX_IRQ_EN = (1<<1),
- CTRL_THRU_EN = (1<<2),
-};
-
-enum {
- DBG_BREAK_EN = (1<<0),
-};
-
-struct MilkymistUartState {
- SysBusDevice busdev;
- MemoryRegion regs_region;
- CharDriverState *chr;
- qemu_irq irq;
-
- uint32_t regs[R_MAX];
-};
-typedef struct MilkymistUartState MilkymistUartState;
-
-static void uart_update_irq(MilkymistUartState *s)
-{
- int rx_event = s->regs[R_STAT] & STAT_RX_EVT;
- int tx_event = s->regs[R_STAT] & STAT_TX_EVT;
- int rx_irq_en = s->regs[R_CTRL] & CTRL_RX_IRQ_EN;
- int tx_irq_en = s->regs[R_CTRL] & CTRL_TX_IRQ_EN;
-
- if ((rx_irq_en && rx_event) || (tx_irq_en && tx_event)) {
- trace_milkymist_uart_raise_irq();
- qemu_irq_raise(s->irq);
- } else {
- trace_milkymist_uart_lower_irq();
- qemu_irq_lower(s->irq);
- }
-}
-
-static uint64_t uart_read(void *opaque, hwaddr addr,
- unsigned size)
-{
- MilkymistUartState *s = opaque;
- uint32_t r = 0;
-
- addr >>= 2;
- switch (addr) {
- case R_RXTX:
- r = s->regs[addr];
- break;
- case R_DIV:
- case R_STAT:
- case R_CTRL:
- case R_DBG:
- r = s->regs[addr];
- break;
-
- default:
- error_report("milkymist_uart: read access to unknown register 0x"
- TARGET_FMT_plx, addr << 2);
- break;
- }
-
- trace_milkymist_uart_memory_read(addr << 2, r);
-
- return r;
-}
-
-static void uart_write(void *opaque, hwaddr addr, uint64_t value,
- unsigned size)
-{
- MilkymistUartState *s = opaque;
- unsigned char ch = value;
-
- trace_milkymist_uart_memory_write(addr, value);
-
- addr >>= 2;
- switch (addr) {
- case R_RXTX:
- if (s->chr) {
- qemu_chr_fe_write(s->chr, &ch, 1);
- }
- s->regs[R_STAT] |= STAT_TX_EVT;
- break;
- case R_DIV:
- case R_CTRL:
- case R_DBG:
- s->regs[addr] = value;
- break;
-
- case R_STAT:
- /* write one to clear bits */
- s->regs[addr] &= ~(value & (STAT_RX_EVT | STAT_TX_EVT));
- qemu_chr_accept_input(s->chr);
- break;
-
- default:
- error_report("milkymist_uart: write access to unknown register 0x"
- TARGET_FMT_plx, addr << 2);
- break;
- }
-
- uart_update_irq(s);
-}
-
-static const MemoryRegionOps uart_mmio_ops = {
- .read = uart_read,
- .write = uart_write,
- .valid = {
- .min_access_size = 4,
- .max_access_size = 4,
- },
- .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-static void uart_rx(void *opaque, const uint8_t *buf, int size)
-{
- MilkymistUartState *s = opaque;
-
- assert(!(s->regs[R_STAT] & STAT_RX_EVT));
-
- s->regs[R_STAT] |= STAT_RX_EVT;
- s->regs[R_RXTX] = *buf;
-
- uart_update_irq(s);
-}
-
-static int uart_can_rx(void *opaque)
-{
- MilkymistUartState *s = opaque;
-
- return !(s->regs[R_STAT] & STAT_RX_EVT);
-}
-
-static void uart_event(void *opaque, int event)
-{
-}
-
-static void milkymist_uart_reset(DeviceState *d)
-{
- MilkymistUartState *s = container_of(d, MilkymistUartState, busdev.qdev);
- int i;
-
- for (i = 0; i < R_MAX; i++) {
- s->regs[i] = 0;
- }
-
- /* THRE is always set */
- s->regs[R_STAT] = STAT_THRE;
-}
-
-static int milkymist_uart_init(SysBusDevice *dev)
-{
- MilkymistUartState *s = FROM_SYSBUS(typeof(*s), dev);
-
- sysbus_init_irq(dev, &s->irq);
-
- memory_region_init_io(&s->regs_region, &uart_mmio_ops, s,
- "milkymist-uart", R_MAX * 4);
- sysbus_init_mmio(dev, &s->regs_region);
-
- s->chr = qemu_char_get_next_serial();
- if (s->chr) {
- qemu_chr_add_handlers(s->chr, uart_can_rx, uart_rx, uart_event, s);
- }
-
- return 0;
-}
-
-static const VMStateDescription vmstate_milkymist_uart = {
- .name = "milkymist-uart",
- .version_id = 1,
- .minimum_version_id = 1,
- .minimum_version_id_old = 1,
- .fields = (VMStateField[]) {
- VMSTATE_UINT32_ARRAY(regs, MilkymistUartState, R_MAX),
- VMSTATE_END_OF_LIST()
- }
-};
-
-static void milkymist_uart_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
- SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
-
- k->init = milkymist_uart_init;
- dc->reset = milkymist_uart_reset;
- dc->vmsd = &vmstate_milkymist_uart;
-}
-
-static const TypeInfo milkymist_uart_info = {
- .name = "milkymist-uart",
- .parent = TYPE_SYS_BUS_DEVICE,
- .instance_size = sizeof(MilkymistUartState),
- .class_init = milkymist_uart_class_init,
-};
-
-static void milkymist_uart_register_types(void)
-{
- type_register_static(&milkymist_uart_info);
-}
-
-type_init(milkymist_uart_register_types)
+++ /dev/null
-/*
- * TI OMAP processors UART emulation.
- *
- * Copyright (C) 2006-2008 Andrzej Zaborowski <balrog@zabor.org>
- * Copyright (C) 2007-2009 Nokia Corporation
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation; either version 2 or
- * (at your option) version 3 of the License.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, see <http://www.gnu.org/licenses/>.
- */
-#include "char/char.h"
-#include "hw/hw.h"
-#include "hw/arm/omap.h"
-#include "hw/char/serial.h"
-#include "exec/address-spaces.h"
-
-/* UARTs */
-struct omap_uart_s {
- MemoryRegion iomem;
- hwaddr base;
- SerialState *serial; /* TODO */
- struct omap_target_agent_s *ta;
- omap_clk fclk;
- qemu_irq irq;
-
- uint8_t eblr;
- uint8_t syscontrol;
- uint8_t wkup;
- uint8_t cfps;
- uint8_t mdr[2];
- uint8_t scr;
- uint8_t clksel;
-};
-
-void omap_uart_reset(struct omap_uart_s *s)
-{
- s->eblr = 0x00;
- s->syscontrol = 0;
- s->wkup = 0x3f;
- s->cfps = 0x69;
- s->clksel = 0;
-}
-
-struct omap_uart_s *omap_uart_init(hwaddr base,
- qemu_irq irq, omap_clk fclk, omap_clk iclk,
- qemu_irq txdma, qemu_irq rxdma,
- const char *label, CharDriverState *chr)
-{
- struct omap_uart_s *s = (struct omap_uart_s *)
- g_malloc0(sizeof(struct omap_uart_s));
-
- s->base = base;
- s->fclk = fclk;
- s->irq = irq;
- s->serial = serial_mm_init(get_system_memory(), base, 2, irq,
- omap_clk_getrate(fclk)/16,
- chr ?: qemu_chr_new(label, "null", NULL),
- DEVICE_NATIVE_ENDIAN);
- return s;
-}
-
-static uint64_t omap_uart_read(void *opaque, hwaddr addr,
- unsigned size)
-{
- struct omap_uart_s *s = (struct omap_uart_s *) opaque;
-
- if (size == 4) {
- return omap_badwidth_read8(opaque, addr);
- }
-
- switch (addr) {
- case 0x20: /* MDR1 */
- return s->mdr[0];
- case 0x24: /* MDR2 */
- return s->mdr[1];
- case 0x40: /* SCR */
- return s->scr;
- case 0x44: /* SSR */
- return 0x0;
- case 0x48: /* EBLR (OMAP2) */
- return s->eblr;
- case 0x4C: /* OSC_12M_SEL (OMAP1) */
- return s->clksel;
- case 0x50: /* MVR */
- return 0x30;
- case 0x54: /* SYSC (OMAP2) */
- return s->syscontrol;
- case 0x58: /* SYSS (OMAP2) */
- return 1;
- case 0x5c: /* WER (OMAP2) */
- return s->wkup;
- case 0x60: /* CFPS (OMAP2) */
- return s->cfps;
- }
-
- OMAP_BAD_REG(addr);
- return 0;
-}
-
-static void omap_uart_write(void *opaque, hwaddr addr,
- uint64_t value, unsigned size)
-{
- struct omap_uart_s *s = (struct omap_uart_s *) opaque;
-
- if (size == 4) {
- return omap_badwidth_write8(opaque, addr, value);
- }
-
- switch (addr) {
- case 0x20: /* MDR1 */
- s->mdr[0] = value & 0x7f;
- break;
- case 0x24: /* MDR2 */
- s->mdr[1] = value & 0xff;
- break;
- case 0x40: /* SCR */
- s->scr = value & 0xff;
- break;
- case 0x48: /* EBLR (OMAP2) */
- s->eblr = value & 0xff;
- break;
- case 0x4C: /* OSC_12M_SEL (OMAP1) */
- s->clksel = value & 1;
- break;
- case 0x44: /* SSR */
- case 0x50: /* MVR */
- case 0x58: /* SYSS (OMAP2) */
- OMAP_RO_REG(addr);
- break;
- case 0x54: /* SYSC (OMAP2) */
- s->syscontrol = value & 0x1d;
- if (value & 2)
- omap_uart_reset(s);
- break;
- case 0x5c: /* WER (OMAP2) */
- s->wkup = value & 0x7f;
- break;
- case 0x60: /* CFPS (OMAP2) */
- s->cfps = value & 0xff;
- break;
- default:
- OMAP_BAD_REG(addr);
- }
-}
-
-static const MemoryRegionOps omap_uart_ops = {
- .read = omap_uart_read,
- .write = omap_uart_write,
- .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-struct omap_uart_s *omap2_uart_init(MemoryRegion *sysmem,
- struct omap_target_agent_s *ta,
- qemu_irq irq, omap_clk fclk, omap_clk iclk,
- qemu_irq txdma, qemu_irq rxdma,
- const char *label, CharDriverState *chr)
-{
- hwaddr base = omap_l4_attach(ta, 0, NULL);
- struct omap_uart_s *s = omap_uart_init(base, irq,
- fclk, iclk, txdma, rxdma, label, chr);
-
- memory_region_init_io(&s->iomem, &omap_uart_ops, s, "omap.uart", 0x100);
-
- s->ta = ta;
-
- memory_region_add_subregion(sysmem, base + 0x20, &s->iomem);
-
- return s;
-}
-
-void omap_uart_attach(struct omap_uart_s *s, CharDriverState *chr)
-{
- /* TODO: Should reuse or destroy current s->serial */
- s->serial = serial_mm_init(get_system_memory(), s->base, 2, s->irq,
- omap_clk_getrate(s->fclk) / 16,
- chr ?: qemu_chr_new("null", "null", NULL),
- DEVICE_NATIVE_ENDIAN);
-}
# IBM pSeries (sPAPR)
-obj-$(CONFIG_PSERIES) += spapr_vty.o
obj-$(CONFIG_PSERIES) += spapr_pci.o
obj-$(CONFIG_PSERIES) += spapr_nvram.o
# PowerPC 4xx boards
obj-y += s390-virtio-hcall.o
obj-y += sclp.o
obj-y += event-facility.o
-obj-y += sclpquiesce.o sclpconsole.o
+obj-y += sclpquiesce.o
obj-y += ipl.o
obj-y += css.o
obj-y += s390-virtio-ccw.o
+++ /dev/null
-/*
- * SCLP event type
- * Ascii Console Data (VT220 Console)
- *
- * Copyright IBM, Corp. 2012
- *
- * Authors:
- * Heinz Graalfs <graalfs@de.ibm.com>
- *
- * This work is licensed under the terms of the GNU GPL, version 2 or (at your
- * option) any later version. See the COPYING file in the top-level directory.
- *
- */
-
-#include <hw/qdev.h>
-#include "qemu/thread.h"
-#include "qemu/error-report.h"
-
-#include "hw/s390x/sclp.h"
-#include "hw/s390x/event-facility.h"
-#include "char/char.h"
-
-typedef struct ASCIIConsoleData {
- EventBufferHeader ebh;
- char data[0];
-} QEMU_PACKED ASCIIConsoleData;
-
-/* max size for ASCII data in 4K SCCB page */
-#define SIZE_BUFFER_VT220 4080
-
-typedef struct SCLPConsole {
- SCLPEvent event;
- CharDriverState *chr;
- /* io vector */
- uint8_t *iov; /* iov buffer pointer */
- uint8_t *iov_sclp; /* pointer to SCLP read offset */
- uint8_t *iov_bs; /* pointer byte stream read offset */
- uint32_t iov_data_len; /* length of byte stream in buffer */
- uint32_t iov_sclp_rest; /* length of byte stream not read via SCLP */
- qemu_irq irq_read_vt220;
-} SCLPConsole;
-
-/* character layer call-back functions */
-
-/* Return number of bytes that fit into iov buffer */
-static int chr_can_read(void *opaque)
-{
- SCLPConsole *scon = opaque;
-
- return scon->iov ? SIZE_BUFFER_VT220 - scon->iov_data_len : 0;
-}
-
-/* Receive n bytes from character layer, save in iov buffer,
- * and set event pending */
-static void receive_from_chr_layer(SCLPConsole *scon, const uint8_t *buf,
- int size)
-{
- assert(scon->iov);
-
- /* read data must fit into current buffer */
- assert(size <= SIZE_BUFFER_VT220 - scon->iov_data_len);
-
- /* put byte-stream from character layer into buffer */
- memcpy(scon->iov_bs, buf, size);
- scon->iov_data_len += size;
- scon->iov_sclp_rest += size;
- scon->iov_bs += size;
- scon->event.event_pending = true;
-}
-
-/* Send data from a char device over to the guest */
-static void chr_read(void *opaque, const uint8_t *buf, int size)
-{
- SCLPConsole *scon = opaque;
-
- assert(scon);
-
- receive_from_chr_layer(scon, buf, size);
- /* trigger SCLP read operation */
- qemu_irq_raise(scon->irq_read_vt220);
-}
-
-static void chr_event(void *opaque, int event)
-{
- SCLPConsole *scon = opaque;
-
- switch (event) {
- case CHR_EVENT_OPENED:
- if (!scon->iov) {
- scon->iov = g_malloc0(SIZE_BUFFER_VT220);
- scon->iov_sclp = scon->iov;
- scon->iov_bs = scon->iov;
- scon->iov_data_len = 0;
- scon->iov_sclp_rest = 0;
- }
- break;
- case CHR_EVENT_CLOSED:
- if (scon->iov) {
- g_free(scon->iov);
- scon->iov = NULL;
- }
- break;
- }
-}
-
-/* functions to be called by event facility */
-
-static int event_type(void)
-{
- return SCLP_EVENT_ASCII_CONSOLE_DATA;
-}
-
-static unsigned int send_mask(void)
-{
- return SCLP_EVENT_MASK_MSG_ASCII;
-}
-
-static unsigned int receive_mask(void)
-{
- return SCLP_EVENT_MASK_MSG_ASCII;
-}
-
-/* triggered by SCLP's read_event_data -
- * copy console data byte-stream into provided (SCLP) buffer
- */
-static void get_console_data(SCLPEvent *event, uint8_t *buf, size_t *size,
- int avail)
-{
- SCLPConsole *cons = DO_UPCAST(SCLPConsole, event, event);
-
- /* first byte is hex 0 saying an ascii string follows */
- *buf++ = '\0';
- avail--;
- /* if all data fit into provided SCLP buffer */
- if (avail >= cons->iov_sclp_rest) {
- /* copy character byte-stream to SCLP buffer */
- memcpy(buf, cons->iov_sclp, cons->iov_sclp_rest);
- *size = cons->iov_sclp_rest + 1;
- cons->iov_sclp = cons->iov;
- cons->iov_bs = cons->iov;
- cons->iov_data_len = 0;
- cons->iov_sclp_rest = 0;
- event->event_pending = false;
- /* data provided and no more data pending */
- } else {
- /* if provided buffer is too small, just copy part */
- memcpy(buf, cons->iov_sclp, avail);
- *size = avail + 1;
- cons->iov_sclp_rest -= avail;
- cons->iov_sclp += avail;
- /* more data pending */
- }
-}
-
-static int read_event_data(SCLPEvent *event, EventBufferHeader *evt_buf_hdr,
- int *slen)
-{
- int avail;
- size_t src_len;
- uint8_t *to;
- ASCIIConsoleData *acd = (ASCIIConsoleData *) evt_buf_hdr;
-
- if (!event->event_pending) {
- /* no data pending */
- return 0;
- }
-
- to = (uint8_t *)&acd->data;
- avail = *slen - sizeof(ASCIIConsoleData);
- get_console_data(event, to, &src_len, avail);
-
- acd->ebh.length = cpu_to_be16(sizeof(ASCIIConsoleData) + src_len);
- acd->ebh.type = SCLP_EVENT_ASCII_CONSOLE_DATA;
- acd->ebh.flags |= SCLP_EVENT_BUFFER_ACCEPTED;
- *slen = avail - src_len;
-
- return 1;
-}
-
-/* triggered by SCLP's write_event_data
- * - write console data to character layer
- * returns < 0 if an error occurred
- */
-static ssize_t write_console_data(SCLPEvent *event, const uint8_t *buf,
- size_t len)
-{
- ssize_t ret = 0;
- const uint8_t *iov_offset;
- SCLPConsole *scon = DO_UPCAST(SCLPConsole, event, event);
-
- if (!scon->chr) {
- /* If there's no backend, we can just say we consumed all data. */
- return len;
- }
-
- iov_offset = buf;
- while (len > 0) {
- ret = qemu_chr_fe_write(scon->chr, buf, len);
- if (ret == 0) {
- /* a pty doesn't seem to be connected - no error */
- len = 0;
- } else if (ret == -EAGAIN || (ret > 0 && ret < len)) {
- len -= ret;
- iov_offset += ret;
- } else {
- len = 0;
- }
- }
-
- return ret;
-}
-
-static int write_event_data(SCLPEvent *event, EventBufferHeader *evt_buf_hdr)
-{
- int rc;
- int length;
- ssize_t written;
- ASCIIConsoleData *acd = (ASCIIConsoleData *) evt_buf_hdr;
-
- length = be16_to_cpu(evt_buf_hdr->length) - sizeof(EventBufferHeader);
- written = write_console_data(event, (uint8_t *)acd->data, length);
-
- rc = SCLP_RC_NORMAL_COMPLETION;
- /* set event buffer accepted flag */
- evt_buf_hdr->flags |= SCLP_EVENT_BUFFER_ACCEPTED;
-
- /* written will be zero if a pty is not connected - don't treat as error */
- if (written < 0) {
- /* event buffer not accepted due to error in character layer */
- evt_buf_hdr->flags &= ~(SCLP_EVENT_BUFFER_ACCEPTED);
- rc = SCLP_RC_CONTAINED_EQUIPMENT_CHECK;
- }
-
- return rc;
-}
-
-static void trigger_ascii_console_data(void *env, int n, int level)
-{
- sclp_service_interrupt(0);
-}
-
-/* qemu object creation and initialization functions */
-
-/* tell character layer our call-back functions */
-static int console_init(SCLPEvent *event)
-{
- static bool console_available;
-
- SCLPConsole *scon = DO_UPCAST(SCLPConsole, event, event);
-
- if (console_available) {
- error_report("Multiple VT220 operator consoles are not supported");
- return -1;
- }
- console_available = true;
- event->event_type = SCLP_EVENT_ASCII_CONSOLE_DATA;
- if (scon->chr) {
- qemu_chr_add_handlers(scon->chr, chr_can_read,
- chr_read, chr_event, scon);
- }
- scon->irq_read_vt220 = *qemu_allocate_irqs(trigger_ascii_console_data,
- NULL, 1);
-
- return 0;
-}
-
-static int console_exit(SCLPEvent *event)
-{
- return 0;
-}
-
-static Property console_properties[] = {
- DEFINE_PROP_CHR("chardev", SCLPConsole, chr),
- DEFINE_PROP_END_OF_LIST(),
-};
-
-static void console_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
- SCLPEventClass *ec = SCLP_EVENT_CLASS(klass);
-
- dc->props = console_properties;
- ec->init = console_init;
- ec->exit = console_exit;
- ec->get_send_mask = send_mask;
- ec->get_receive_mask = receive_mask;
- ec->event_type = event_type;
- ec->read_event_data = read_event_data;
- ec->write_event_data = write_event_data;
-}
-
-static const TypeInfo sclp_console_info = {
- .name = "sclpconsole",
- .parent = TYPE_SCLP_EVENT,
- .instance_size = sizeof(SCLPConsole),
- .class_init = console_class_init,
- .class_size = sizeof(SCLPEventClass),
-};
-
-static void register_types(void)
-{
- type_register_static(&sclp_console_info);
-}
-
-type_init(register_types)
-obj-y += sh_timer.o sh_serial.o sh_intc.o sh_pci.o
+obj-y += sh_timer.o sh_intc.o sh_pci.o
obj-y := $(addprefix ../,$(obj-y))
+++ /dev/null
-/*
- * QEMU SCI/SCIF serial port emulation
- *
- * Copyright (c) 2007 Magnus Damm
- *
- * Based on serial.c - QEMU 16450 UART emulation
- * Copyright (c) 2003-2004 Fabrice Bellard
- *
- * 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 "hw/hw.h"
-#include "hw/sh4/sh.h"
-#include "char/char.h"
-#include "exec/address-spaces.h"
-
-//#define DEBUG_SERIAL
-
-#define SH_SERIAL_FLAG_TEND (1 << 0)
-#define SH_SERIAL_FLAG_TDE (1 << 1)
-#define SH_SERIAL_FLAG_RDF (1 << 2)
-#define SH_SERIAL_FLAG_BRK (1 << 3)
-#define SH_SERIAL_FLAG_DR (1 << 4)
-
-#define SH_RX_FIFO_LENGTH (16)
-
-typedef struct {
- MemoryRegion iomem;
- MemoryRegion iomem_p4;
- MemoryRegion iomem_a7;
- uint8_t smr;
- uint8_t brr;
- uint8_t scr;
- uint8_t dr; /* ftdr / tdr */
- uint8_t sr; /* fsr / ssr */
- uint16_t fcr;
- uint8_t sptr;
-
- uint8_t rx_fifo[SH_RX_FIFO_LENGTH]; /* frdr / rdr */
- uint8_t rx_cnt;
- uint8_t rx_tail;
- uint8_t rx_head;
-
- int freq;
- int feat;
- int flags;
- int rtrg;
-
- CharDriverState *chr;
-
- qemu_irq eri;
- qemu_irq rxi;
- qemu_irq txi;
- qemu_irq tei;
- qemu_irq bri;
-} sh_serial_state;
-
-static void sh_serial_clear_fifo(sh_serial_state * s)
-{
- memset(s->rx_fifo, 0, SH_RX_FIFO_LENGTH);
- s->rx_cnt = 0;
- s->rx_head = 0;
- s->rx_tail = 0;
-}
-
-static void sh_serial_write(void *opaque, hwaddr offs,
- uint64_t val, unsigned size)
-{
- sh_serial_state *s = opaque;
- unsigned char ch;
-
-#ifdef DEBUG_SERIAL
- printf("sh_serial: write offs=0x%02x val=0x%02x\n",
- offs, val);
-#endif
- switch(offs) {
- case 0x00: /* SMR */
- s->smr = val & ((s->feat & SH_SERIAL_FEAT_SCIF) ? 0x7b : 0xff);
- return;
- case 0x04: /* BRR */
- s->brr = val;
- return;
- case 0x08: /* SCR */
- /* TODO : For SH7751, SCIF mask should be 0xfb. */
- s->scr = val & ((s->feat & SH_SERIAL_FEAT_SCIF) ? 0xfa : 0xff);
- if (!(val & (1 << 5)))
- s->flags |= SH_SERIAL_FLAG_TEND;
- if ((s->feat & SH_SERIAL_FEAT_SCIF) && s->txi) {
- qemu_set_irq(s->txi, val & (1 << 7));
- }
- if (!(val & (1 << 6))) {
- qemu_set_irq(s->rxi, 0);
- }
- return;
- case 0x0c: /* FTDR / TDR */
- if (s->chr) {
- ch = val;
- qemu_chr_fe_write(s->chr, &ch, 1);
- }
- s->dr = val;
- s->flags &= ~SH_SERIAL_FLAG_TDE;
- return;
-#if 0
- case 0x14: /* FRDR / RDR */
- ret = 0;
- break;
-#endif
- }
- if (s->feat & SH_SERIAL_FEAT_SCIF) {
- switch(offs) {
- case 0x10: /* FSR */
- if (!(val & (1 << 6)))
- s->flags &= ~SH_SERIAL_FLAG_TEND;
- if (!(val & (1 << 5)))
- s->flags &= ~SH_SERIAL_FLAG_TDE;
- if (!(val & (1 << 4)))
- s->flags &= ~SH_SERIAL_FLAG_BRK;
- if (!(val & (1 << 1)))
- s->flags &= ~SH_SERIAL_FLAG_RDF;
- if (!(val & (1 << 0)))
- s->flags &= ~SH_SERIAL_FLAG_DR;
-
- if (!(val & (1 << 1)) || !(val & (1 << 0))) {
- if (s->rxi) {
- qemu_set_irq(s->rxi, 0);
- }
- }
- return;
- case 0x18: /* FCR */
- s->fcr = val;
- switch ((val >> 6) & 3) {
- case 0:
- s->rtrg = 1;
- break;
- case 1:
- s->rtrg = 4;
- break;
- case 2:
- s->rtrg = 8;
- break;
- case 3:
- s->rtrg = 14;
- break;
- }
- if (val & (1 << 1)) {
- sh_serial_clear_fifo(s);
- s->sr &= ~(1 << 1);
- }
-
- return;
- case 0x20: /* SPTR */
- s->sptr = val & 0xf3;
- return;
- case 0x24: /* LSR */
- return;
- }
- }
- else {
- switch(offs) {
-#if 0
- case 0x0c:
- ret = s->dr;
- break;
- case 0x10:
- ret = 0;
- break;
-#endif
- case 0x1c:
- s->sptr = val & 0x8f;
- return;
- }
- }
-
- fprintf(stderr, "sh_serial: unsupported write to 0x%02"
- HWADDR_PRIx "\n", offs);
- abort();
-}
-
-static uint64_t sh_serial_read(void *opaque, hwaddr offs,
- unsigned size)
-{
- sh_serial_state *s = opaque;
- uint32_t ret = ~0;
-
-#if 0
- switch(offs) {
- case 0x00:
- ret = s->smr;
- break;
- case 0x04:
- ret = s->brr;
- break;
- case 0x08:
- ret = s->scr;
- break;
- case 0x14:
- ret = 0;
- break;
- }
-#endif
- if (s->feat & SH_SERIAL_FEAT_SCIF) {
- switch(offs) {
- case 0x00: /* SMR */
- ret = s->smr;
- break;
- case 0x08: /* SCR */
- ret = s->scr;
- break;
- case 0x10: /* FSR */
- ret = 0;
- if (s->flags & SH_SERIAL_FLAG_TEND)
- ret |= (1 << 6);
- if (s->flags & SH_SERIAL_FLAG_TDE)
- ret |= (1 << 5);
- if (s->flags & SH_SERIAL_FLAG_BRK)
- ret |= (1 << 4);
- if (s->flags & SH_SERIAL_FLAG_RDF)
- ret |= (1 << 1);
- if (s->flags & SH_SERIAL_FLAG_DR)
- ret |= (1 << 0);
-
- if (s->scr & (1 << 5))
- s->flags |= SH_SERIAL_FLAG_TDE | SH_SERIAL_FLAG_TEND;
-
- break;
- case 0x14:
- if (s->rx_cnt > 0) {
- ret = s->rx_fifo[s->rx_tail++];
- s->rx_cnt--;
- if (s->rx_tail == SH_RX_FIFO_LENGTH)
- s->rx_tail = 0;
- if (s->rx_cnt < s->rtrg)
- s->flags &= ~SH_SERIAL_FLAG_RDF;
- }
- break;
-#if 0
- case 0x18:
- ret = s->fcr;
- break;
-#endif
- case 0x1c:
- ret = s->rx_cnt;
- break;
- case 0x20:
- ret = s->sptr;
- break;
- case 0x24:
- ret = 0;
- break;
- }
- }
- else {
- switch(offs) {
-#if 0
- case 0x0c:
- ret = s->dr;
- break;
- case 0x10:
- ret = 0;
- break;
- case 0x14:
- ret = s->rx_fifo[0];
- break;
-#endif
- case 0x1c:
- ret = s->sptr;
- break;
- }
- }
-#ifdef DEBUG_SERIAL
- printf("sh_serial: read offs=0x%02x val=0x%x\n",
- offs, ret);
-#endif
-
- if (ret & ~((1 << 16) - 1)) {
- fprintf(stderr, "sh_serial: unsupported read from 0x%02"
- HWADDR_PRIx "\n", offs);
- abort();
- }
-
- return ret;
-}
-
-static int sh_serial_can_receive(sh_serial_state *s)
-{
- return s->scr & (1 << 4);
-}
-
-static void sh_serial_receive_break(sh_serial_state *s)
-{
- if (s->feat & SH_SERIAL_FEAT_SCIF)
- s->sr |= (1 << 4);
-}
-
-static int sh_serial_can_receive1(void *opaque)
-{
- sh_serial_state *s = opaque;
- return sh_serial_can_receive(s);
-}
-
-static void sh_serial_receive1(void *opaque, const uint8_t *buf, int size)
-{
- sh_serial_state *s = opaque;
-
- if (s->feat & SH_SERIAL_FEAT_SCIF) {
- int i;
- for (i = 0; i < size; i++) {
- if (s->rx_cnt < SH_RX_FIFO_LENGTH) {
- s->rx_fifo[s->rx_head++] = buf[i];
- if (s->rx_head == SH_RX_FIFO_LENGTH) {
- s->rx_head = 0;
- }
- s->rx_cnt++;
- if (s->rx_cnt >= s->rtrg) {
- s->flags |= SH_SERIAL_FLAG_RDF;
- if (s->scr & (1 << 6) && s->rxi) {
- qemu_set_irq(s->rxi, 1);
- }
- }
- }
- }
- } else {
- s->rx_fifo[0] = buf[0];
- }
-}
-
-static void sh_serial_event(void *opaque, int event)
-{
- sh_serial_state *s = opaque;
- if (event == CHR_EVENT_BREAK)
- sh_serial_receive_break(s);
-}
-
-static const MemoryRegionOps sh_serial_ops = {
- .read = sh_serial_read,
- .write = sh_serial_write,
- .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-void sh_serial_init(MemoryRegion *sysmem,
- hwaddr base, int feat,
- uint32_t freq, CharDriverState *chr,
- qemu_irq eri_source,
- qemu_irq rxi_source,
- qemu_irq txi_source,
- qemu_irq tei_source,
- qemu_irq bri_source)
-{
- sh_serial_state *s;
-
- s = g_malloc0(sizeof(sh_serial_state));
-
- s->feat = feat;
- s->flags = SH_SERIAL_FLAG_TEND | SH_SERIAL_FLAG_TDE;
- s->rtrg = 1;
-
- s->smr = 0;
- s->brr = 0xff;
- s->scr = 1 << 5; /* pretend that TX is enabled so early printk works */
- s->sptr = 0;
-
- if (feat & SH_SERIAL_FEAT_SCIF) {
- s->fcr = 0;
- }
- else {
- s->dr = 0xff;
- }
-
- sh_serial_clear_fifo(s);
-
- memory_region_init_io(&s->iomem, &sh_serial_ops, s,
- "serial", 0x100000000ULL);
-
- memory_region_init_alias(&s->iomem_p4, "serial-p4", &s->iomem,
- 0, 0x28);
- memory_region_add_subregion(sysmem, P4ADDR(base), &s->iomem_p4);
-
- memory_region_init_alias(&s->iomem_a7, "serial-a7", &s->iomem,
- 0, 0x28);
- memory_region_add_subregion(sysmem, A7ADDR(base), &s->iomem_a7);
-
- s->chr = chr;
-
- if (chr) {
- qemu_chr_fe_claim_no_fail(chr);
- qemu_chr_add_handlers(chr, sh_serial_can_receive1, sh_serial_receive1,
- sh_serial_event, s);
- }
-
- s->eri = eri_source;
- s->rxi = rxi_source;
- s->txi = txi_source;
- s->tei = tei_source;
- s->bri = bri_source;
-}
+++ /dev/null
-#include "hw/qdev.h"
-#include "char/char.h"
-#include "hw/ppc/spapr.h"
-#include "hw/ppc/spapr_vio.h"
-
-#define VTERM_BUFSIZE 16
-
-typedef struct VIOsPAPRVTYDevice {
- VIOsPAPRDevice sdev;
- CharDriverState *chardev;
- uint32_t in, out;
- uint8_t buf[VTERM_BUFSIZE];
-} VIOsPAPRVTYDevice;
-
-static int vty_can_receive(void *opaque)
-{
- VIOsPAPRVTYDevice *dev = (VIOsPAPRVTYDevice *)opaque;
-
- return (dev->in - dev->out) < VTERM_BUFSIZE;
-}
-
-static void vty_receive(void *opaque, const uint8_t *buf, int size)
-{
- VIOsPAPRVTYDevice *dev = (VIOsPAPRVTYDevice *)opaque;
- int i;
-
- if ((dev->in == dev->out) && size) {
- /* toggle line to simulate edge interrupt */
- qemu_irq_pulse(spapr_vio_qirq(&dev->sdev));
- }
- for (i = 0; i < size; i++) {
- assert((dev->in - dev->out) < VTERM_BUFSIZE);
- dev->buf[dev->in++ % VTERM_BUFSIZE] = buf[i];
- }
-}
-
-static int vty_getchars(VIOsPAPRDevice *sdev, uint8_t *buf, int max)
-{
- VIOsPAPRVTYDevice *dev = (VIOsPAPRVTYDevice *)sdev;
- int n = 0;
-
- while ((n < max) && (dev->out != dev->in)) {
- buf[n++] = dev->buf[dev->out++ % VTERM_BUFSIZE];
- }
-
- return n;
-}
-
-void vty_putchars(VIOsPAPRDevice *sdev, uint8_t *buf, int len)
-{
- VIOsPAPRVTYDevice *dev = (VIOsPAPRVTYDevice *)sdev;
-
- /* FIXME: should check the qemu_chr_fe_write() return value */
- qemu_chr_fe_write(dev->chardev, buf, len);
-}
-
-static int spapr_vty_init(VIOsPAPRDevice *sdev)
-{
- VIOsPAPRVTYDevice *dev = (VIOsPAPRVTYDevice *)sdev;
-
- if (!dev->chardev) {
- fprintf(stderr, "spapr-vty: Can't create vty without a chardev!\n");
- exit(1);
- }
-
- qemu_chr_add_handlers(dev->chardev, vty_can_receive,
- vty_receive, NULL, dev);
-
- return 0;
-}
-
-/* Forward declaration */
-static target_ulong h_put_term_char(PowerPCCPU *cpu, sPAPREnvironment *spapr,
- target_ulong opcode, target_ulong *args)
-{
- target_ulong reg = args[0];
- target_ulong len = args[1];
- target_ulong char0_7 = args[2];
- target_ulong char8_15 = args[3];
- VIOsPAPRDevice *sdev;
- uint8_t buf[16];
-
- sdev = vty_lookup(spapr, reg);
- if (!sdev) {
- return H_PARAMETER;
- }
-
- if (len > 16) {
- return H_PARAMETER;
- }
-
- *((uint64_t *)buf) = cpu_to_be64(char0_7);
- *((uint64_t *)buf + 1) = cpu_to_be64(char8_15);
-
- vty_putchars(sdev, buf, len);
-
- return H_SUCCESS;
-}
-
-static target_ulong h_get_term_char(PowerPCCPU *cpu, sPAPREnvironment *spapr,
- target_ulong opcode, target_ulong *args)
-{
- target_ulong reg = args[0];
- target_ulong *len = args + 0;
- target_ulong *char0_7 = args + 1;
- target_ulong *char8_15 = args + 2;
- VIOsPAPRDevice *sdev;
- uint8_t buf[16];
-
- sdev = vty_lookup(spapr, reg);
- if (!sdev) {
- return H_PARAMETER;
- }
-
- *len = vty_getchars(sdev, buf, sizeof(buf));
- if (*len < 16) {
- memset(buf + *len, 0, 16 - *len);
- }
-
- *char0_7 = be64_to_cpu(*((uint64_t *)buf));
- *char8_15 = be64_to_cpu(*((uint64_t *)buf + 1));
-
- return H_SUCCESS;
-}
-
-void spapr_vty_create(VIOsPAPRBus *bus, CharDriverState *chardev)
-{
- DeviceState *dev;
-
- dev = qdev_create(&bus->bus, "spapr-vty");
- qdev_prop_set_chr(dev, "chardev", chardev);
- qdev_init_nofail(dev);
-}
-
-static Property spapr_vty_properties[] = {
- DEFINE_SPAPR_PROPERTIES(VIOsPAPRVTYDevice, sdev),
- DEFINE_PROP_CHR("chardev", VIOsPAPRVTYDevice, chardev),
- DEFINE_PROP_END_OF_LIST(),
-};
-
-static void spapr_vty_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
- VIOsPAPRDeviceClass *k = VIO_SPAPR_DEVICE_CLASS(klass);
-
- k->init = spapr_vty_init;
- k->dt_name = "vty";
- k->dt_type = "serial";
- k->dt_compatible = "hvterm1";
- dc->props = spapr_vty_properties;
-}
-
-static const TypeInfo spapr_vty_info = {
- .name = "spapr-vty",
- .parent = TYPE_VIO_SPAPR_DEVICE,
- .instance_size = sizeof(VIOsPAPRVTYDevice),
- .class_init = spapr_vty_class_init,
-};
-
-VIOsPAPRDevice *spapr_vty_get_default(VIOsPAPRBus *bus)
-{
- VIOsPAPRDevice *sdev, *selected;
- BusChild *kid;
-
- /*
- * To avoid the console bouncing around we want one VTY to be
- * the "default". We haven't really got anything to go on, so
- * arbitrarily choose the one with the lowest reg value.
- */
-
- selected = NULL;
- QTAILQ_FOREACH(kid, &bus->bus.children, sibling) {
- DeviceState *iter = kid->child;
-
- /* Only look at VTY devices */
- if (!object_dynamic_cast(OBJECT(iter), "spapr-vty")) {
- continue;
- }
-
- sdev = DO_UPCAST(VIOsPAPRDevice, qdev, iter);
-
- /* First VTY we've found, so it is selected for now */
- if (!selected) {
- selected = sdev;
- continue;
- }
-
- /* Choose VTY with lowest reg value */
- if (sdev->reg < selected->reg) {
- selected = sdev;
- }
- }
-
- return selected;
-}
-
-VIOsPAPRDevice *vty_lookup(sPAPREnvironment *spapr, target_ulong reg)
-{
- VIOsPAPRDevice *sdev;
-
- sdev = spapr_vio_find_by_reg(spapr->vio_bus, reg);
- if (!sdev && reg == 0) {
- /* Hack for kernel early debug, which always specifies reg==0.
- * We search all VIO devices, and grab the vty with the lowest
- * reg. This attempts to mimic existing PowerVM behaviour
- * (early debug does work there, despite having no vty with
- * reg==0. */
- return spapr_vty_get_default(spapr->vio_bus);
- }
-
- return sdev;
-}
-
-static void spapr_vty_register_types(void)
-{
- spapr_register_hypercall(H_PUT_TERM_CHAR, h_put_term_char);
- spapr_register_hypercall(H_GET_TERM_CHAR, h_get_term_char);
- type_register_static(&spapr_vty_info);
-}
-
-type_init(spapr_vty_register_types)
obj-y += eccmemctl.o sbi.o sun4c_intctl.o
# GRLIB
-obj-y += grlib_gptimer.o grlib_irqmp.o grlib_apbuart.o
+obj-y += grlib_gptimer.o grlib_irqmp.o
obj-y := $(addprefix ../,$(obj-y))