diff options
Diffstat (limited to 'qemu/hw/i2c')
-rw-r--r-- | qemu/hw/i2c/Makefile.objs | 8 | ||||
-rw-r--r-- | qemu/hw/i2c/bitbang_i2c.c | 253 | ||||
-rw-r--r-- | qemu/hw/i2c/bitbang_i2c.h | 14 | ||||
-rw-r--r-- | qemu/hw/i2c/core.c | 246 | ||||
-rw-r--r-- | qemu/hw/i2c/exynos4210_i2c.c | 337 | ||||
-rw-r--r-- | qemu/hw/i2c/imx_i2c.c | 337 | ||||
-rw-r--r-- | qemu/hw/i2c/omap_i2c.c | 509 | ||||
-rw-r--r-- | qemu/hw/i2c/pm_smbus.c | 228 | ||||
-rw-r--r-- | qemu/hw/i2c/smbus.c | 362 | ||||
-rw-r--r-- | qemu/hw/i2c/smbus_eeprom.c | 159 | ||||
-rw-r--r-- | qemu/hw/i2c/smbus_ich9.c | 130 | ||||
-rw-r--r-- | qemu/hw/i2c/versatile_i2c.c | 114 |
12 files changed, 0 insertions, 2697 deletions
diff --git a/qemu/hw/i2c/Makefile.objs b/qemu/hw/i2c/Makefile.objs deleted file mode 100644 index aeb8f38d7..000000000 --- a/qemu/hw/i2c/Makefile.objs +++ /dev/null @@ -1,8 +0,0 @@ -common-obj-y += core.o smbus.o smbus_eeprom.o -common-obj-$(CONFIG_VERSATILE_I2C) += versatile_i2c.o -common-obj-$(CONFIG_ACPI_X86) += smbus_ich9.o -common-obj-$(CONFIG_APM) += pm_smbus.o -common-obj-$(CONFIG_BITBANG_I2C) += bitbang_i2c.o -common-obj-$(CONFIG_EXYNOS4) += exynos4210_i2c.o -common-obj-$(CONFIG_IMX_I2C) += imx_i2c.o -obj-$(CONFIG_OMAP) += omap_i2c.o diff --git a/qemu/hw/i2c/bitbang_i2c.c b/qemu/hw/i2c/bitbang_i2c.c deleted file mode 100644 index 6ed206020..000000000 --- a/qemu/hw/i2c/bitbang_i2c.c +++ /dev/null @@ -1,253 +0,0 @@ -/* - * Bit-Bang i2c emulation extracted from - * Marvell MV88W8618 / Freecom MusicPal emulation. - * - * Copyright (c) 2008 Jan Kiszka - * - * This code is licensed under the GNU GPL v2. - * - * Contributions after 2012-01-13 are licensed under the terms of the - * GNU GPL, version 2 or (at your option) any later version. - */ -#include "qemu/osdep.h" -#include "hw/hw.h" -#include "bitbang_i2c.h" -#include "hw/sysbus.h" - -//#define DEBUG_BITBANG_I2C - -#ifdef DEBUG_BITBANG_I2C -#define DPRINTF(fmt, ...) \ -do { printf("bitbang_i2c: " fmt , ## __VA_ARGS__); } while (0) -#else -#define DPRINTF(fmt, ...) do {} while(0) -#endif - -typedef enum bitbang_i2c_state { - STOPPED = 0, - SENDING_BIT7, - SENDING_BIT6, - SENDING_BIT5, - SENDING_BIT4, - SENDING_BIT3, - SENDING_BIT2, - SENDING_BIT1, - SENDING_BIT0, - WAITING_FOR_ACK, - RECEIVING_BIT7, - RECEIVING_BIT6, - RECEIVING_BIT5, - RECEIVING_BIT4, - RECEIVING_BIT3, - RECEIVING_BIT2, - RECEIVING_BIT1, - RECEIVING_BIT0, - SENDING_ACK, - SENT_NACK -} bitbang_i2c_state; - -struct bitbang_i2c_interface { - I2CBus *bus; - bitbang_i2c_state state; - int last_data; - int last_clock; - int device_out; - uint8_t buffer; - int current_addr; -}; - -static void bitbang_i2c_enter_stop(bitbang_i2c_interface *i2c) -{ - DPRINTF("STOP\n"); - if (i2c->current_addr >= 0) - i2c_end_transfer(i2c->bus); - i2c->current_addr = -1; - i2c->state = STOPPED; -} - -/* Set device data pin. */ -static int bitbang_i2c_ret(bitbang_i2c_interface *i2c, int level) -{ - i2c->device_out = level; - //DPRINTF("%d %d %d\n", i2c->last_clock, i2c->last_data, i2c->device_out); - return level & i2c->last_data; -} - -/* Leave device data pin unodified. */ -static int bitbang_i2c_nop(bitbang_i2c_interface *i2c) -{ - return bitbang_i2c_ret(i2c, i2c->device_out); -} - -/* Returns data line level. */ -int bitbang_i2c_set(bitbang_i2c_interface *i2c, int line, int level) -{ - int data; - - if (level != 0 && level != 1) { - abort(); - } - - if (line == BITBANG_I2C_SDA) { - if (level == i2c->last_data) { - return bitbang_i2c_nop(i2c); - } - i2c->last_data = level; - if (i2c->last_clock == 0) { - return bitbang_i2c_nop(i2c); - } - if (level == 0) { - DPRINTF("START\n"); - /* START condition. */ - i2c->state = SENDING_BIT7; - i2c->current_addr = -1; - } else { - /* STOP condition. */ - bitbang_i2c_enter_stop(i2c); - } - return bitbang_i2c_ret(i2c, 1); - } - - data = i2c->last_data; - if (i2c->last_clock == level) { - return bitbang_i2c_nop(i2c); - } - i2c->last_clock = level; - if (level == 0) { - /* State is set/read at the start of the clock pulse. - release the data line at the end. */ - return bitbang_i2c_ret(i2c, 1); - } - switch (i2c->state) { - case STOPPED: - case SENT_NACK: - return bitbang_i2c_ret(i2c, 1); - - case SENDING_BIT7 ... SENDING_BIT0: - i2c->buffer = (i2c->buffer << 1) | data; - /* will end up in WAITING_FOR_ACK */ - i2c->state++; - return bitbang_i2c_ret(i2c, 1); - - case WAITING_FOR_ACK: - if (i2c->current_addr < 0) { - i2c->current_addr = i2c->buffer; - DPRINTF("Address 0x%02x\n", i2c->current_addr); - i2c_start_transfer(i2c->bus, i2c->current_addr >> 1, - i2c->current_addr & 1); - } else { - DPRINTF("Sent 0x%02x\n", i2c->buffer); - i2c_send(i2c->bus, i2c->buffer); - } - if (i2c->current_addr & 1) { - i2c->state = RECEIVING_BIT7; - } else { - i2c->state = SENDING_BIT7; - } - return bitbang_i2c_ret(i2c, 0); - - case RECEIVING_BIT7: - i2c->buffer = i2c_recv(i2c->bus); - DPRINTF("RX byte 0x%02x\n", i2c->buffer); - /* Fall through... */ - case RECEIVING_BIT6 ... RECEIVING_BIT0: - data = i2c->buffer >> 7; - /* will end up in SENDING_ACK */ - i2c->state++; - i2c->buffer <<= 1; - return bitbang_i2c_ret(i2c, data); - - case SENDING_ACK: - i2c->state = RECEIVING_BIT7; - if (data != 0) { - DPRINTF("NACKED\n"); - i2c->state = SENT_NACK; - i2c_nack(i2c->bus); - } else { - DPRINTF("ACKED\n"); - } - return bitbang_i2c_ret(i2c, 1); - } - abort(); -} - -bitbang_i2c_interface *bitbang_i2c_init(I2CBus *bus) -{ - bitbang_i2c_interface *s; - - s = g_malloc0(sizeof(bitbang_i2c_interface)); - - s->bus = bus; - s->last_data = 1; - s->last_clock = 1; - s->device_out = 1; - - return s; -} - -/* GPIO interface. */ - -#define TYPE_GPIO_I2C "gpio_i2c" -#define GPIO_I2C(obj) OBJECT_CHECK(GPIOI2CState, (obj), TYPE_GPIO_I2C) - -typedef struct GPIOI2CState { - SysBusDevice parent_obj; - - MemoryRegion dummy_iomem; - bitbang_i2c_interface *bitbang; - int last_level; - qemu_irq out; -} GPIOI2CState; - -static void bitbang_i2c_gpio_set(void *opaque, int irq, int level) -{ - GPIOI2CState *s = opaque; - - level = bitbang_i2c_set(s->bitbang, irq, level); - if (level != s->last_level) { - s->last_level = level; - qemu_set_irq(s->out, level); - } -} - -static int gpio_i2c_init(SysBusDevice *sbd) -{ - DeviceState *dev = DEVICE(sbd); - GPIOI2CState *s = GPIO_I2C(dev); - I2CBus *bus; - - memory_region_init(&s->dummy_iomem, OBJECT(s), "gpio_i2c", 0); - sysbus_init_mmio(sbd, &s->dummy_iomem); - - bus = i2c_init_bus(dev, "i2c"); - s->bitbang = bitbang_i2c_init(bus); - - qdev_init_gpio_in(dev, bitbang_i2c_gpio_set, 2); - qdev_init_gpio_out(dev, &s->out, 1); - - return 0; -} - -static void gpio_i2c_class_init(ObjectClass *klass, void *data) -{ - DeviceClass *dc = DEVICE_CLASS(klass); - SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass); - - k->init = gpio_i2c_init; - set_bit(DEVICE_CATEGORY_BRIDGE, dc->categories); - dc->desc = "Virtual GPIO to I2C bridge"; -} - -static const TypeInfo gpio_i2c_info = { - .name = TYPE_GPIO_I2C, - .parent = TYPE_SYS_BUS_DEVICE, - .instance_size = sizeof(GPIOI2CState), - .class_init = gpio_i2c_class_init, -}; - -static void bitbang_i2c_register_types(void) -{ - type_register_static(&gpio_i2c_info); -} - -type_init(bitbang_i2c_register_types) diff --git a/qemu/hw/i2c/bitbang_i2c.h b/qemu/hw/i2c/bitbang_i2c.h deleted file mode 100644 index 3a7126d5d..000000000 --- a/qemu/hw/i2c/bitbang_i2c.h +++ /dev/null @@ -1,14 +0,0 @@ -#ifndef BITBANG_I2C_H -#define BITBANG_I2C_H - -#include "hw/i2c/i2c.h" - -typedef struct bitbang_i2c_interface bitbang_i2c_interface; - -#define BITBANG_I2C_SDA 0 -#define BITBANG_I2C_SCL 1 - -bitbang_i2c_interface *bitbang_i2c_init(I2CBus *bus); -int bitbang_i2c_set(bitbang_i2c_interface *i2c, int line, int level); - -#endif diff --git a/qemu/hw/i2c/core.c b/qemu/hw/i2c/core.c deleted file mode 100644 index ba22104af..000000000 --- a/qemu/hw/i2c/core.c +++ /dev/null @@ -1,246 +0,0 @@ -/* - * QEMU I2C bus interface. - * - * Copyright (c) 2007 CodeSourcery. - * Written by Paul Brook - * - * This code is licensed under the LGPL. - */ - -#include "qemu/osdep.h" -#include "hw/i2c/i2c.h" - -struct I2CBus -{ - BusState qbus; - I2CSlave *current_dev; - I2CSlave *dev; - uint8_t saved_address; -}; - -static Property i2c_props[] = { - DEFINE_PROP_UINT8("address", struct I2CSlave, address, 0), - DEFINE_PROP_END_OF_LIST(), -}; - -#define TYPE_I2C_BUS "i2c-bus" -#define I2C_BUS(obj) OBJECT_CHECK(I2CBus, (obj), TYPE_I2C_BUS) - -static const TypeInfo i2c_bus_info = { - .name = TYPE_I2C_BUS, - .parent = TYPE_BUS, - .instance_size = sizeof(I2CBus), -}; - -static void i2c_bus_pre_save(void *opaque) -{ - I2CBus *bus = opaque; - - bus->saved_address = bus->current_dev ? bus->current_dev->address : -1; -} - -static int i2c_bus_post_load(void *opaque, int version_id) -{ - I2CBus *bus = opaque; - - /* The bus is loaded before attached devices, so load and save the - current device id. Devices will check themselves as loaded. */ - bus->current_dev = NULL; - return 0; -} - -static const VMStateDescription vmstate_i2c_bus = { - .name = "i2c_bus", - .version_id = 1, - .minimum_version_id = 1, - .pre_save = i2c_bus_pre_save, - .post_load = i2c_bus_post_load, - .fields = (VMStateField[]) { - VMSTATE_UINT8(saved_address, I2CBus), - VMSTATE_END_OF_LIST() - } -}; - -/* Create a new I2C bus. */ -I2CBus *i2c_init_bus(DeviceState *parent, const char *name) -{ - I2CBus *bus; - - bus = I2C_BUS(qbus_create(TYPE_I2C_BUS, parent, name)); - vmstate_register(NULL, -1, &vmstate_i2c_bus, bus); - return bus; -} - -void i2c_set_slave_address(I2CSlave *dev, uint8_t address) -{ - dev->address = address; -} - -/* Return nonzero if bus is busy. */ -int i2c_bus_busy(I2CBus *bus) -{ - return bus->current_dev != NULL; -} - -/* Returns non-zero if the address is not valid. */ -/* TODO: Make this handle multiple masters. */ -int i2c_start_transfer(I2CBus *bus, uint8_t address, int recv) -{ - BusChild *kid; - I2CSlave *slave = NULL; - I2CSlaveClass *sc; - - QTAILQ_FOREACH(kid, &bus->qbus.children, sibling) { - DeviceState *qdev = kid->child; - I2CSlave *candidate = I2C_SLAVE(qdev); - if (candidate->address == address) { - slave = candidate; - break; - } - } - - if (!slave) { - return 1; - } - - sc = I2C_SLAVE_GET_CLASS(slave); - /* If the bus is already busy, assume this is a repeated - start condition. */ - bus->current_dev = slave; - if (sc->event) { - sc->event(slave, recv ? I2C_START_RECV : I2C_START_SEND); - } - return 0; -} - -void i2c_end_transfer(I2CBus *bus) -{ - I2CSlave *dev = bus->current_dev; - I2CSlaveClass *sc; - - if (!dev) { - return; - } - - sc = I2C_SLAVE_GET_CLASS(dev); - if (sc->event) { - sc->event(dev, I2C_FINISH); - } - - bus->current_dev = NULL; -} - -int i2c_send(I2CBus *bus, uint8_t data) -{ - I2CSlave *dev = bus->current_dev; - I2CSlaveClass *sc; - - if (!dev) { - return -1; - } - - sc = I2C_SLAVE_GET_CLASS(dev); - if (sc->send) { - return sc->send(dev, data); - } - - return -1; -} - -int i2c_recv(I2CBus *bus) -{ - I2CSlave *dev = bus->current_dev; - I2CSlaveClass *sc; - - if (!dev) { - return -1; - } - - sc = I2C_SLAVE_GET_CLASS(dev); - if (sc->recv) { - return sc->recv(dev); - } - - return -1; -} - -void i2c_nack(I2CBus *bus) -{ - I2CSlave *dev = bus->current_dev; - I2CSlaveClass *sc; - - if (!dev) { - return; - } - - sc = I2C_SLAVE_GET_CLASS(dev); - if (sc->event) { - sc->event(dev, I2C_NACK); - } -} - -static int i2c_slave_post_load(void *opaque, int version_id) -{ - I2CSlave *dev = opaque; - I2CBus *bus; - bus = I2C_BUS(qdev_get_parent_bus(DEVICE(dev))); - if (bus->saved_address == dev->address) { - bus->current_dev = dev; - } - return 0; -} - -const VMStateDescription vmstate_i2c_slave = { - .name = "I2CSlave", - .version_id = 1, - .minimum_version_id = 1, - .post_load = i2c_slave_post_load, - .fields = (VMStateField[]) { - VMSTATE_UINT8(address, I2CSlave), - VMSTATE_END_OF_LIST() - } -}; - -static int i2c_slave_qdev_init(DeviceState *dev) -{ - I2CSlave *s = I2C_SLAVE(dev); - I2CSlaveClass *sc = I2C_SLAVE_GET_CLASS(s); - - return sc->init(s); -} - -DeviceState *i2c_create_slave(I2CBus *bus, const char *name, uint8_t addr) -{ - DeviceState *dev; - - dev = qdev_create(&bus->qbus, name); - qdev_prop_set_uint8(dev, "address", addr); - qdev_init_nofail(dev); - return dev; -} - -static void i2c_slave_class_init(ObjectClass *klass, void *data) -{ - DeviceClass *k = DEVICE_CLASS(klass); - k->init = i2c_slave_qdev_init; - set_bit(DEVICE_CATEGORY_MISC, k->categories); - k->bus_type = TYPE_I2C_BUS; - k->props = i2c_props; -} - -static const TypeInfo i2c_slave_type_info = { - .name = TYPE_I2C_SLAVE, - .parent = TYPE_DEVICE, - .instance_size = sizeof(I2CSlave), - .abstract = true, - .class_size = sizeof(I2CSlaveClass), - .class_init = i2c_slave_class_init, -}; - -static void i2c_slave_register_types(void) -{ - type_register_static(&i2c_bus_info); - type_register_static(&i2c_slave_type_info); -} - -type_init(i2c_slave_register_types) diff --git a/qemu/hw/i2c/exynos4210_i2c.c b/qemu/hw/i2c/exynos4210_i2c.c deleted file mode 100644 index 8c2a2c163..000000000 --- a/qemu/hw/i2c/exynos4210_i2c.c +++ /dev/null @@ -1,337 +0,0 @@ -/* - * Exynos4210 I2C Bus Serial Interface Emulation - * - * Copyright (C) 2012 Samsung Electronics Co Ltd. - * Maksim Kozlov, <m.kozlov@samsung.com> - * Igor Mitsyanko, <i.mitsyanko@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 "qemu/osdep.h" -#include "qemu/timer.h" -#include "hw/sysbus.h" -#include "hw/i2c/i2c.h" - -#ifndef EXYNOS4_I2C_DEBUG -#define EXYNOS4_I2C_DEBUG 0 -#endif - -#define TYPE_EXYNOS4_I2C "exynos4210.i2c" -#define EXYNOS4_I2C(obj) \ - OBJECT_CHECK(Exynos4210I2CState, (obj), TYPE_EXYNOS4_I2C) - -/* Exynos4210 I2C memory map */ -#define EXYNOS4_I2C_MEM_SIZE 0x14 -#define I2CCON_ADDR 0x00 /* control register */ -#define I2CSTAT_ADDR 0x04 /* control/status register */ -#define I2CADD_ADDR 0x08 /* address register */ -#define I2CDS_ADDR 0x0c /* data shift register */ -#define I2CLC_ADDR 0x10 /* line control register */ - -#define I2CCON_ACK_GEN (1 << 7) -#define I2CCON_INTRS_EN (1 << 5) -#define I2CCON_INT_PEND (1 << 4) - -#define EXYNOS4_I2C_MODE(reg) (((reg) >> 6) & 3) -#define I2C_IN_MASTER_MODE(reg) (((reg) >> 6) & 2) -#define I2CMODE_MASTER_Rx 0x2 -#define I2CMODE_MASTER_Tx 0x3 -#define I2CSTAT_LAST_BIT (1 << 0) -#define I2CSTAT_OUTPUT_EN (1 << 4) -#define I2CSTAT_START_BUSY (1 << 5) - - -#if EXYNOS4_I2C_DEBUG -#define DPRINT(fmt, args...) \ - do { fprintf(stderr, "QEMU I2C: "fmt, ## args); } while (0) - -static const char *exynos4_i2c_get_regname(unsigned offset) -{ - switch (offset) { - case I2CCON_ADDR: - return "I2CCON"; - case I2CSTAT_ADDR: - return "I2CSTAT"; - case I2CADD_ADDR: - return "I2CADD"; - case I2CDS_ADDR: - return "I2CDS"; - case I2CLC_ADDR: - return "I2CLC"; - default: - return "[?]"; - } -} - -#else -#define DPRINT(fmt, args...) do { } while (0) -#endif - -typedef struct Exynos4210I2CState { - SysBusDevice parent_obj; - - MemoryRegion iomem; - I2CBus *bus; - qemu_irq irq; - - uint8_t i2ccon; - uint8_t i2cstat; - uint8_t i2cadd; - uint8_t i2cds; - uint8_t i2clc; - bool scl_free; -} Exynos4210I2CState; - -static inline void exynos4210_i2c_raise_interrupt(Exynos4210I2CState *s) -{ - if (s->i2ccon & I2CCON_INTRS_EN) { - s->i2ccon |= I2CCON_INT_PEND; - qemu_irq_raise(s->irq); - } -} - -static void exynos4210_i2c_data_receive(void *opaque) -{ - Exynos4210I2CState *s = (Exynos4210I2CState *)opaque; - int ret; - - s->i2cstat &= ~I2CSTAT_LAST_BIT; - s->scl_free = false; - ret = i2c_recv(s->bus); - if (ret < 0 && (s->i2ccon & I2CCON_ACK_GEN)) { - s->i2cstat |= I2CSTAT_LAST_BIT; /* Data is not acknowledged */ - } else { - s->i2cds = ret; - } - exynos4210_i2c_raise_interrupt(s); -} - -static void exynos4210_i2c_data_send(void *opaque) -{ - Exynos4210I2CState *s = (Exynos4210I2CState *)opaque; - - s->i2cstat &= ~I2CSTAT_LAST_BIT; - s->scl_free = false; - if (i2c_send(s->bus, s->i2cds) < 0 && (s->i2ccon & I2CCON_ACK_GEN)) { - s->i2cstat |= I2CSTAT_LAST_BIT; - } - exynos4210_i2c_raise_interrupt(s); -} - -static uint64_t exynos4210_i2c_read(void *opaque, hwaddr offset, - unsigned size) -{ - Exynos4210I2CState *s = (Exynos4210I2CState *)opaque; - uint8_t value; - - switch (offset) { - case I2CCON_ADDR: - value = s->i2ccon; - break; - case I2CSTAT_ADDR: - value = s->i2cstat; - break; - case I2CADD_ADDR: - value = s->i2cadd; - break; - case I2CDS_ADDR: - value = s->i2cds; - s->scl_free = true; - if (EXYNOS4_I2C_MODE(s->i2cstat) == I2CMODE_MASTER_Rx && - (s->i2cstat & I2CSTAT_START_BUSY) && - !(s->i2ccon & I2CCON_INT_PEND)) { - exynos4210_i2c_data_receive(s); - } - break; - case I2CLC_ADDR: - value = s->i2clc; - break; - default: - value = 0; - DPRINT("ERROR: Bad read offset 0x%x\n", (unsigned int)offset); - break; - } - - DPRINT("read %s [0x%02x] -> 0x%02x\n", exynos4_i2c_get_regname(offset), - (unsigned int)offset, value); - return value; -} - -static void exynos4210_i2c_write(void *opaque, hwaddr offset, - uint64_t value, unsigned size) -{ - Exynos4210I2CState *s = (Exynos4210I2CState *)opaque; - uint8_t v = value & 0xff; - - DPRINT("write %s [0x%02x] <- 0x%02x\n", exynos4_i2c_get_regname(offset), - (unsigned int)offset, v); - - switch (offset) { - case I2CCON_ADDR: - s->i2ccon = (v & ~I2CCON_INT_PEND) | (s->i2ccon & I2CCON_INT_PEND); - if ((s->i2ccon & I2CCON_INT_PEND) && !(v & I2CCON_INT_PEND)) { - s->i2ccon &= ~I2CCON_INT_PEND; - qemu_irq_lower(s->irq); - if (!(s->i2ccon & I2CCON_INTRS_EN)) { - s->i2cstat &= ~I2CSTAT_START_BUSY; - } - - if (s->i2cstat & I2CSTAT_START_BUSY) { - if (s->scl_free) { - if (EXYNOS4_I2C_MODE(s->i2cstat) == I2CMODE_MASTER_Tx) { - exynos4210_i2c_data_send(s); - } else if (EXYNOS4_I2C_MODE(s->i2cstat) == - I2CMODE_MASTER_Rx) { - exynos4210_i2c_data_receive(s); - } - } else { - s->i2ccon |= I2CCON_INT_PEND; - qemu_irq_raise(s->irq); - } - } - } - break; - case I2CSTAT_ADDR: - s->i2cstat = - (s->i2cstat & I2CSTAT_START_BUSY) | (v & ~I2CSTAT_START_BUSY); - - if (!(s->i2cstat & I2CSTAT_OUTPUT_EN)) { - s->i2cstat &= ~I2CSTAT_START_BUSY; - s->scl_free = true; - qemu_irq_lower(s->irq); - break; - } - - /* Nothing to do if in i2c slave mode */ - if (!I2C_IN_MASTER_MODE(s->i2cstat)) { - break; - } - - if (v & I2CSTAT_START_BUSY) { - s->i2cstat &= ~I2CSTAT_LAST_BIT; - s->i2cstat |= I2CSTAT_START_BUSY; /* Line is busy */ - s->scl_free = false; - - /* Generate start bit and send slave address */ - if (i2c_start_transfer(s->bus, s->i2cds >> 1, s->i2cds & 0x1) && - (s->i2ccon & I2CCON_ACK_GEN)) { - s->i2cstat |= I2CSTAT_LAST_BIT; - } else if (EXYNOS4_I2C_MODE(s->i2cstat) == I2CMODE_MASTER_Rx) { - exynos4210_i2c_data_receive(s); - } - exynos4210_i2c_raise_interrupt(s); - } else { - i2c_end_transfer(s->bus); - if (!(s->i2ccon & I2CCON_INT_PEND)) { - s->i2cstat &= ~I2CSTAT_START_BUSY; - } - s->scl_free = true; - } - break; - case I2CADD_ADDR: - if ((s->i2cstat & I2CSTAT_OUTPUT_EN) == 0) { - s->i2cadd = v; - } - break; - case I2CDS_ADDR: - if (s->i2cstat & I2CSTAT_OUTPUT_EN) { - s->i2cds = v; - s->scl_free = true; - if (EXYNOS4_I2C_MODE(s->i2cstat) == I2CMODE_MASTER_Tx && - (s->i2cstat & I2CSTAT_START_BUSY) && - !(s->i2ccon & I2CCON_INT_PEND)) { - exynos4210_i2c_data_send(s); - } - } - break; - case I2CLC_ADDR: - s->i2clc = v; - break; - default: - DPRINT("ERROR: Bad write offset 0x%x\n", (unsigned int)offset); - break; - } -} - -static const MemoryRegionOps exynos4210_i2c_ops = { - .read = exynos4210_i2c_read, - .write = exynos4210_i2c_write, - .endianness = DEVICE_NATIVE_ENDIAN, -}; - -static const VMStateDescription exynos4210_i2c_vmstate = { - .name = "exynos4210.i2c", - .version_id = 1, - .minimum_version_id = 1, - .fields = (VMStateField[]) { - VMSTATE_UINT8(i2ccon, Exynos4210I2CState), - VMSTATE_UINT8(i2cstat, Exynos4210I2CState), - VMSTATE_UINT8(i2cds, Exynos4210I2CState), - VMSTATE_UINT8(i2cadd, Exynos4210I2CState), - VMSTATE_UINT8(i2clc, Exynos4210I2CState), - VMSTATE_BOOL(scl_free, Exynos4210I2CState), - VMSTATE_END_OF_LIST() - } -}; - -static void exynos4210_i2c_reset(DeviceState *d) -{ - Exynos4210I2CState *s = EXYNOS4_I2C(d); - - s->i2ccon = 0x00; - s->i2cstat = 0x00; - s->i2cds = 0xFF; - s->i2clc = 0x00; - s->i2cadd = 0xFF; - s->scl_free = true; -} - -static int exynos4210_i2c_realize(SysBusDevice *sbd) -{ - DeviceState *dev = DEVICE(sbd); - Exynos4210I2CState *s = EXYNOS4_I2C(dev); - - memory_region_init_io(&s->iomem, OBJECT(s), &exynos4210_i2c_ops, s, - TYPE_EXYNOS4_I2C, EXYNOS4_I2C_MEM_SIZE); - sysbus_init_mmio(sbd, &s->iomem); - sysbus_init_irq(sbd, &s->irq); - s->bus = i2c_init_bus(dev, "i2c"); - return 0; -} - -static void exynos4210_i2c_class_init(ObjectClass *klass, void *data) -{ - DeviceClass *dc = DEVICE_CLASS(klass); - SysBusDeviceClass *sbdc = SYS_BUS_DEVICE_CLASS(klass); - - dc->vmsd = &exynos4210_i2c_vmstate; - dc->reset = exynos4210_i2c_reset; - sbdc->init = exynos4210_i2c_realize; -} - -static const TypeInfo exynos4210_i2c_type_info = { - .name = TYPE_EXYNOS4_I2C, - .parent = TYPE_SYS_BUS_DEVICE, - .instance_size = sizeof(Exynos4210I2CState), - .class_init = exynos4210_i2c_class_init, -}; - -static void exynos4210_i2c_register_types(void) -{ - type_register_static(&exynos4210_i2c_type_info); -} - -type_init(exynos4210_i2c_register_types) diff --git a/qemu/hw/i2c/imx_i2c.c b/qemu/hw/i2c/imx_i2c.c deleted file mode 100644 index a01e43ebe..000000000 --- a/qemu/hw/i2c/imx_i2c.c +++ /dev/null @@ -1,337 +0,0 @@ -/* - * i.MX I2C Bus Serial Interface Emulation - * - * Copyright (C) 2013 Jean-Christophe Dubois. <jcd@tribudubois.net> - * - * 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 "qemu/osdep.h" -#include "hw/i2c/imx_i2c.h" -#include "hw/i2c/i2c.h" - -#ifndef DEBUG_IMX_I2C -#define DEBUG_IMX_I2C 0 -#endif - -#define DPRINTF(fmt, args...) \ - do { \ - if (DEBUG_IMX_I2C) { \ - fprintf(stderr, "[%s]%s: " fmt , TYPE_IMX_I2C, \ - __func__, ##args); \ - } \ - } while (0) - -static const char *imx_i2c_get_regname(unsigned offset) -{ - switch (offset) { - case IADR_ADDR: - return "IADR"; - case IFDR_ADDR: - return "IFDR"; - case I2CR_ADDR: - return "I2CR"; - case I2SR_ADDR: - return "I2SR"; - case I2DR_ADDR: - return "I2DR"; - default: - return "[?]"; - } -} - -static inline bool imx_i2c_is_enabled(IMXI2CState *s) -{ - return s->i2cr & I2CR_IEN; -} - -static inline bool imx_i2c_interrupt_is_enabled(IMXI2CState *s) -{ - return s->i2cr & I2CR_IIEN; -} - -static inline bool imx_i2c_is_master(IMXI2CState *s) -{ - return s->i2cr & I2CR_MSTA; -} - -static void imx_i2c_reset(DeviceState *dev) -{ - IMXI2CState *s = IMX_I2C(dev); - - if (s->address != ADDR_RESET) { - i2c_end_transfer(s->bus); - } - - s->address = ADDR_RESET; - s->iadr = IADR_RESET; - s->ifdr = IFDR_RESET; - s->i2cr = I2CR_RESET; - s->i2sr = I2SR_RESET; - s->i2dr_read = I2DR_RESET; - s->i2dr_write = I2DR_RESET; -} - -static inline void imx_i2c_raise_interrupt(IMXI2CState *s) -{ - /* - * raise an interrupt if the device is enabled and it is configured - * to generate some interrupts. - */ - if (imx_i2c_is_enabled(s) && imx_i2c_interrupt_is_enabled(s)) { - s->i2sr |= I2SR_IIF; - qemu_irq_raise(s->irq); - } -} - -static uint64_t imx_i2c_read(void *opaque, hwaddr offset, - unsigned size) -{ - uint16_t value; - IMXI2CState *s = IMX_I2C(opaque); - - switch (offset) { - case IADR_ADDR: - value = s->iadr; - break; - case IFDR_ADDR: - value = s->ifdr; - break; - case I2CR_ADDR: - value = s->i2cr; - break; - case I2SR_ADDR: - value = s->i2sr; - break; - case I2DR_ADDR: - value = s->i2dr_read; - - if (imx_i2c_is_master(s)) { - int ret = 0xff; - - if (s->address == ADDR_RESET) { - /* something is wrong as the address is not set */ - qemu_log_mask(LOG_GUEST_ERROR, "[%s]%s: Trying to read " - "without specifying the slave address\n", - TYPE_IMX_I2C, __func__); - } else if (s->i2cr & I2CR_MTX) { - qemu_log_mask(LOG_GUEST_ERROR, "[%s]%s: Trying to read " - "but MTX is set\n", TYPE_IMX_I2C, __func__); - } else { - /* get the next byte */ - ret = i2c_recv(s->bus); - - if (ret >= 0) { - imx_i2c_raise_interrupt(s); - } else { - qemu_log_mask(LOG_GUEST_ERROR, "[%s]%s: read failed " - "for device 0x%02x\n", TYPE_IMX_I2C, - __func__, s->address); - ret = 0xff; - } - } - - s->i2dr_read = ret; - } else { - qemu_log_mask(LOG_UNIMP, "[%s]%s: slave mode not implemented\n", - TYPE_IMX_I2C, __func__); - } - break; - default: - qemu_log_mask(LOG_GUEST_ERROR, "[%s]%s: Bad address at offset 0x%" - HWADDR_PRIx "\n", TYPE_IMX_I2C, __func__, offset); - value = 0; - break; - } - - DPRINTF("read %s [0x%" HWADDR_PRIx "] -> 0x%02x\n", - imx_i2c_get_regname(offset), offset, value); - - return (uint64_t)value; -} - -static void imx_i2c_write(void *opaque, hwaddr offset, - uint64_t value, unsigned size) -{ - IMXI2CState *s = IMX_I2C(opaque); - - DPRINTF("write %s [0x%" HWADDR_PRIx "] <- 0x%02x\n", - imx_i2c_get_regname(offset), offset, (int)value); - - value &= 0xff; - - switch (offset) { - case IADR_ADDR: - s->iadr = value & IADR_MASK; - /* i2c_set_slave_address(s->bus, (uint8_t)s->iadr); */ - break; - case IFDR_ADDR: - s->ifdr = value & IFDR_MASK; - break; - case I2CR_ADDR: - if (imx_i2c_is_enabled(s) && ((value & I2CR_IEN) == 0)) { - /* This is a soft reset. IADR is preserved during soft resets */ - uint16_t iadr = s->iadr; - imx_i2c_reset(DEVICE(s)); - s->iadr = iadr; - } else { /* normal write */ - s->i2cr = value & I2CR_MASK; - - if (imx_i2c_is_master(s)) { - /* set the bus to busy */ - s->i2sr |= I2SR_IBB; - } else { /* slave mode */ - /* bus is not busy anymore */ - s->i2sr &= ~I2SR_IBB; - - /* - * if we unset the master mode then it ends the ongoing - * transfer if any - */ - if (s->address != ADDR_RESET) { - i2c_end_transfer(s->bus); - s->address = ADDR_RESET; - } - } - - if (s->i2cr & I2CR_RSTA) { /* Restart */ - /* if this is a restart then it ends the ongoing transfer */ - if (s->address != ADDR_RESET) { - i2c_end_transfer(s->bus); - s->address = ADDR_RESET; - s->i2cr &= ~I2CR_RSTA; - } - } - } - break; - case I2SR_ADDR: - /* - * if the user writes 0 to IIF then lower the interrupt and - * reset the bit - */ - if ((s->i2sr & I2SR_IIF) && !(value & I2SR_IIF)) { - s->i2sr &= ~I2SR_IIF; - qemu_irq_lower(s->irq); - } - - /* - * if the user writes 0 to IAL, reset the bit - */ - if ((s->i2sr & I2SR_IAL) && !(value & I2SR_IAL)) { - s->i2sr &= ~I2SR_IAL; - } - - break; - case I2DR_ADDR: - /* if the device is not enabled, nothing to do */ - if (!imx_i2c_is_enabled(s)) { - break; - } - - s->i2dr_write = value & I2DR_MASK; - - if (imx_i2c_is_master(s)) { - /* If this is the first write cycle then it is the slave addr */ - if (s->address == ADDR_RESET) { - if (i2c_start_transfer(s->bus, extract32(s->i2dr_write, 1, 7), - extract32(s->i2dr_write, 0, 1))) { - /* if non zero is returned, the adress is not valid */ - s->i2sr |= I2SR_RXAK; - } else { - s->address = s->i2dr_write; - s->i2sr &= ~I2SR_RXAK; - imx_i2c_raise_interrupt(s); - } - } else { /* This is a normal data write */ - if (i2c_send(s->bus, s->i2dr_write)) { - /* if the target return non zero then end the transfer */ - s->i2sr |= I2SR_RXAK; - s->address = ADDR_RESET; - i2c_end_transfer(s->bus); - } else { - s->i2sr &= ~I2SR_RXAK; - imx_i2c_raise_interrupt(s); - } - } - } else { - qemu_log_mask(LOG_UNIMP, "[%s]%s: slave mode not implemented\n", - TYPE_IMX_I2C, __func__); - } - break; - default: - qemu_log_mask(LOG_GUEST_ERROR, "[%s]%s: Bad address at offset 0x%" - HWADDR_PRIx "\n", TYPE_IMX_I2C, __func__, offset); - break; - } -} - -static const MemoryRegionOps imx_i2c_ops = { - .read = imx_i2c_read, - .write = imx_i2c_write, - .valid.min_access_size = 1, - .valid.max_access_size = 2, - .endianness = DEVICE_NATIVE_ENDIAN, -}; - -static const VMStateDescription imx_i2c_vmstate = { - .name = TYPE_IMX_I2C, - .version_id = 1, - .minimum_version_id = 1, - .fields = (VMStateField[]) { - VMSTATE_UINT16(address, IMXI2CState), - VMSTATE_UINT16(iadr, IMXI2CState), - VMSTATE_UINT16(ifdr, IMXI2CState), - VMSTATE_UINT16(i2cr, IMXI2CState), - VMSTATE_UINT16(i2sr, IMXI2CState), - VMSTATE_UINT16(i2dr_read, IMXI2CState), - VMSTATE_UINT16(i2dr_write, IMXI2CState), - VMSTATE_END_OF_LIST() - } -}; - -static void imx_i2c_realize(DeviceState *dev, Error **errp) -{ - IMXI2CState *s = IMX_I2C(dev); - - memory_region_init_io(&s->iomem, OBJECT(s), &imx_i2c_ops, s, TYPE_IMX_I2C, - IMX_I2C_MEM_SIZE); - sysbus_init_mmio(SYS_BUS_DEVICE(dev), &s->iomem); - sysbus_init_irq(SYS_BUS_DEVICE(dev), &s->irq); - s->bus = i2c_init_bus(DEVICE(dev), "i2c"); -} - -static void imx_i2c_class_init(ObjectClass *klass, void *data) -{ - DeviceClass *dc = DEVICE_CLASS(klass); - - dc->vmsd = &imx_i2c_vmstate; - dc->reset = imx_i2c_reset; - dc->realize = imx_i2c_realize; - dc->desc = "i.MX I2C Controller"; -} - -static const TypeInfo imx_i2c_type_info = { - .name = TYPE_IMX_I2C, - .parent = TYPE_SYS_BUS_DEVICE, - .instance_size = sizeof(IMXI2CState), - .class_init = imx_i2c_class_init, -}; - -static void imx_i2c_register_types(void) -{ - type_register_static(&imx_i2c_type_info); -} - -type_init(imx_i2c_register_types) diff --git a/qemu/hw/i2c/omap_i2c.c b/qemu/hw/i2c/omap_i2c.c deleted file mode 100644 index 67fbbff8e..000000000 --- a/qemu/hw/i2c/omap_i2c.c +++ /dev/null @@ -1,509 +0,0 @@ -/* - * TI OMAP on-chip I2C controller. Only "new I2C" mode supported. - * - * Copyright (C) 2007 Andrzej Zaborowski <balrog@zabor.org> - * - * 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 "qemu/osdep.h" -#include "hw/hw.h" -#include "hw/i2c/i2c.h" -#include "hw/arm/omap.h" -#include "hw/sysbus.h" -#include "qemu/error-report.h" - -#define TYPE_OMAP_I2C "omap_i2c" -#define OMAP_I2C(obj) OBJECT_CHECK(OMAPI2CState, (obj), TYPE_OMAP_I2C) - -typedef struct OMAPI2CState { - SysBusDevice parent_obj; - - MemoryRegion iomem; - qemu_irq irq; - qemu_irq drq[2]; - I2CBus *bus; - - uint8_t revision; - void *iclk; - void *fclk; - - uint8_t mask; - uint16_t stat; - uint16_t dma; - uint16_t count; - int count_cur; - uint32_t fifo; - int rxlen; - int txlen; - uint16_t control; - uint16_t addr[2]; - uint8_t divider; - uint8_t times[2]; - uint16_t test; -} OMAPI2CState; - -#define OMAP2_INTR_REV 0x34 -#define OMAP2_GC_REV 0x34 - -static void omap_i2c_interrupts_update(OMAPI2CState *s) -{ - qemu_set_irq(s->irq, s->stat & s->mask); - if ((s->dma >> 15) & 1) /* RDMA_EN */ - qemu_set_irq(s->drq[0], (s->stat >> 3) & 1); /* RRDY */ - if ((s->dma >> 7) & 1) /* XDMA_EN */ - qemu_set_irq(s->drq[1], (s->stat >> 4) & 1); /* XRDY */ -} - -static void omap_i2c_fifo_run(OMAPI2CState *s) -{ - int ack = 1; - - if (!i2c_bus_busy(s->bus)) - return; - - if ((s->control >> 2) & 1) { /* RM */ - if ((s->control >> 1) & 1) { /* STP */ - i2c_end_transfer(s->bus); - s->control &= ~(1 << 1); /* STP */ - s->count_cur = s->count; - s->txlen = 0; - } else if ((s->control >> 9) & 1) { /* TRX */ - while (ack && s->txlen) - ack = (i2c_send(s->bus, - (s->fifo >> ((-- s->txlen) << 3)) & - 0xff) >= 0); - s->stat |= 1 << 4; /* XRDY */ - } else { - while (s->rxlen < 4) - s->fifo |= i2c_recv(s->bus) << ((s->rxlen ++) << 3); - s->stat |= 1 << 3; /* RRDY */ - } - } else { - if ((s->control >> 9) & 1) { /* TRX */ - while (ack && s->count_cur && s->txlen) { - ack = (i2c_send(s->bus, - (s->fifo >> ((-- s->txlen) << 3)) & - 0xff) >= 0); - s->count_cur --; - } - if (ack && s->count_cur) - s->stat |= 1 << 4; /* XRDY */ - else - s->stat &= ~(1 << 4); /* XRDY */ - if (!s->count_cur) { - s->stat |= 1 << 2; /* ARDY */ - s->control &= ~(1 << 10); /* MST */ - } - } else { - while (s->count_cur && s->rxlen < 4) { - s->fifo |= i2c_recv(s->bus) << ((s->rxlen ++) << 3); - s->count_cur --; - } - if (s->rxlen) - s->stat |= 1 << 3; /* RRDY */ - else - s->stat &= ~(1 << 3); /* RRDY */ - } - if (!s->count_cur) { - if ((s->control >> 1) & 1) { /* STP */ - i2c_end_transfer(s->bus); - s->control &= ~(1 << 1); /* STP */ - s->count_cur = s->count; - s->txlen = 0; - } else { - s->stat |= 1 << 2; /* ARDY */ - s->control &= ~(1 << 10); /* MST */ - } - } - } - - s->stat |= (!ack) << 1; /* NACK */ - if (!ack) - s->control &= ~(1 << 1); /* STP */ -} - -static void omap_i2c_reset(DeviceState *dev) -{ - OMAPI2CState *s = OMAP_I2C(dev); - - s->mask = 0; - s->stat = 0; - s->dma = 0; - s->count = 0; - s->count_cur = 0; - s->fifo = 0; - s->rxlen = 0; - s->txlen = 0; - s->control = 0; - s->addr[0] = 0; - s->addr[1] = 0; - s->divider = 0; - s->times[0] = 0; - s->times[1] = 0; - s->test = 0; -} - -static uint32_t omap_i2c_read(void *opaque, hwaddr addr) -{ - OMAPI2CState *s = opaque; - int offset = addr & OMAP_MPUI_REG_MASK; - uint16_t ret; - - switch (offset) { - case 0x00: /* I2C_REV */ - return s->revision; /* REV */ - - case 0x04: /* I2C_IE */ - return s->mask; - - case 0x08: /* I2C_STAT */ - return s->stat | (i2c_bus_busy(s->bus) << 12); - - case 0x0c: /* I2C_IV */ - if (s->revision >= OMAP2_INTR_REV) - break; - ret = ctz32(s->stat & s->mask); - if (ret != 32) { - s->stat ^= 1 << ret; - ret++; - } else { - ret = 0; - } - omap_i2c_interrupts_update(s); - return ret; - - case 0x10: /* I2C_SYSS */ - return (s->control >> 15) & 1; /* I2C_EN */ - - case 0x14: /* I2C_BUF */ - return s->dma; - - case 0x18: /* I2C_CNT */ - return s->count_cur; /* DCOUNT */ - - case 0x1c: /* I2C_DATA */ - ret = 0; - if (s->control & (1 << 14)) { /* BE */ - ret |= ((s->fifo >> 0) & 0xff) << 8; - ret |= ((s->fifo >> 8) & 0xff) << 0; - } else { - ret |= ((s->fifo >> 8) & 0xff) << 8; - ret |= ((s->fifo >> 0) & 0xff) << 0; - } - if (s->rxlen == 1) { - s->stat |= 1 << 15; /* SBD */ - s->rxlen = 0; - } else if (s->rxlen > 1) { - if (s->rxlen > 2) - s->fifo >>= 16; - s->rxlen -= 2; - } else { - /* XXX: remote access (qualifier) error - what's that? */ - } - if (!s->rxlen) { - s->stat &= ~(1 << 3); /* RRDY */ - if (((s->control >> 10) & 1) && /* MST */ - ((~s->control >> 9) & 1)) { /* TRX */ - s->stat |= 1 << 2; /* ARDY */ - s->control &= ~(1 << 10); /* MST */ - } - } - s->stat &= ~(1 << 11); /* ROVR */ - omap_i2c_fifo_run(s); - omap_i2c_interrupts_update(s); - return ret; - - case 0x20: /* I2C_SYSC */ - return 0; - - case 0x24: /* I2C_CON */ - return s->control; - - case 0x28: /* I2C_OA */ - return s->addr[0]; - - case 0x2c: /* I2C_SA */ - return s->addr[1]; - - case 0x30: /* I2C_PSC */ - return s->divider; - - case 0x34: /* I2C_SCLL */ - return s->times[0]; - - case 0x38: /* I2C_SCLH */ - return s->times[1]; - - case 0x3c: /* I2C_SYSTEST */ - if (s->test & (1 << 15)) { /* ST_EN */ - s->test ^= 0xa; - return s->test; - } else - return s->test & ~0x300f; - } - - OMAP_BAD_REG(addr); - return 0; -} - -static void omap_i2c_write(void *opaque, hwaddr addr, - uint32_t value) -{ - OMAPI2CState *s = opaque; - int offset = addr & OMAP_MPUI_REG_MASK; - int nack; - - switch (offset) { - case 0x00: /* I2C_REV */ - case 0x0c: /* I2C_IV */ - case 0x10: /* I2C_SYSS */ - OMAP_RO_REG(addr); - return; - - case 0x04: /* I2C_IE */ - s->mask = value & (s->revision < OMAP2_GC_REV ? 0x1f : 0x3f); - break; - - case 0x08: /* I2C_STAT */ - if (s->revision < OMAP2_INTR_REV) { - OMAP_RO_REG(addr); - return; - } - - /* RRDY and XRDY are reset by hardware. (in all versions???) */ - s->stat &= ~(value & 0x27); - omap_i2c_interrupts_update(s); - break; - - case 0x14: /* I2C_BUF */ - s->dma = value & 0x8080; - if (value & (1 << 15)) /* RDMA_EN */ - s->mask &= ~(1 << 3); /* RRDY_IE */ - if (value & (1 << 7)) /* XDMA_EN */ - s->mask &= ~(1 << 4); /* XRDY_IE */ - break; - - case 0x18: /* I2C_CNT */ - s->count = value; /* DCOUNT */ - break; - - case 0x1c: /* I2C_DATA */ - if (s->txlen > 2) { - /* XXX: remote access (qualifier) error - what's that? */ - break; - } - s->fifo <<= 16; - s->txlen += 2; - if (s->control & (1 << 14)) { /* BE */ - s->fifo |= ((value >> 8) & 0xff) << 8; - s->fifo |= ((value >> 0) & 0xff) << 0; - } else { - s->fifo |= ((value >> 0) & 0xff) << 8; - s->fifo |= ((value >> 8) & 0xff) << 0; - } - s->stat &= ~(1 << 10); /* XUDF */ - if (s->txlen > 2) - s->stat &= ~(1 << 4); /* XRDY */ - omap_i2c_fifo_run(s); - omap_i2c_interrupts_update(s); - break; - - case 0x20: /* I2C_SYSC */ - if (s->revision < OMAP2_INTR_REV) { - OMAP_BAD_REG(addr); - return; - } - - if (value & 2) { - omap_i2c_reset(DEVICE(s)); - } - break; - - case 0x24: /* I2C_CON */ - s->control = value & 0xcf87; - if (~value & (1 << 15)) { /* I2C_EN */ - if (s->revision < OMAP2_INTR_REV) { - omap_i2c_reset(DEVICE(s)); - } - break; - } - if ((value & (1 << 15)) && !(value & (1 << 10))) { /* MST */ - fprintf(stderr, "%s: I^2C slave mode not supported\n", - __FUNCTION__); - break; - } - if ((value & (1 << 15)) && value & (1 << 8)) { /* XA */ - fprintf(stderr, "%s: 10-bit addressing mode not supported\n", - __FUNCTION__); - break; - } - if ((value & (1 << 15)) && value & (1 << 0)) { /* STT */ - nack = !!i2c_start_transfer(s->bus, s->addr[1], /* SA */ - (~value >> 9) & 1); /* TRX */ - s->stat |= nack << 1; /* NACK */ - s->control &= ~(1 << 0); /* STT */ - s->fifo = 0; - if (nack) - s->control &= ~(1 << 1); /* STP */ - else { - s->count_cur = s->count; - omap_i2c_fifo_run(s); - } - omap_i2c_interrupts_update(s); - } - break; - - case 0x28: /* I2C_OA */ - s->addr[0] = value & 0x3ff; - break; - - case 0x2c: /* I2C_SA */ - s->addr[1] = value & 0x3ff; - break; - - case 0x30: /* I2C_PSC */ - s->divider = value; - break; - - case 0x34: /* I2C_SCLL */ - s->times[0] = value; - break; - - case 0x38: /* I2C_SCLH */ - s->times[1] = value; - break; - - case 0x3c: /* I2C_SYSTEST */ - s->test = value & 0xf80f; - if (value & (1 << 11)) /* SBB */ - if (s->revision >= OMAP2_INTR_REV) { - s->stat |= 0x3f; - omap_i2c_interrupts_update(s); - } - if (value & (1 << 15)) /* ST_EN */ - fprintf(stderr, "%s: System Test not supported\n", __FUNCTION__); - break; - - default: - OMAP_BAD_REG(addr); - return; - } -} - -static void omap_i2c_writeb(void *opaque, hwaddr addr, - uint32_t value) -{ - OMAPI2CState *s = opaque; - int offset = addr & OMAP_MPUI_REG_MASK; - - switch (offset) { - case 0x1c: /* I2C_DATA */ - if (s->txlen > 2) { - /* XXX: remote access (qualifier) error - what's that? */ - break; - } - s->fifo <<= 8; - s->txlen += 1; - s->fifo |= value & 0xff; - s->stat &= ~(1 << 10); /* XUDF */ - if (s->txlen > 2) - s->stat &= ~(1 << 4); /* XRDY */ - omap_i2c_fifo_run(s); - omap_i2c_interrupts_update(s); - break; - - default: - OMAP_BAD_REG(addr); - return; - } -} - -static const MemoryRegionOps omap_i2c_ops = { - .old_mmio = { - .read = { - omap_badwidth_read16, - omap_i2c_read, - omap_badwidth_read16, - }, - .write = { - omap_i2c_writeb, /* Only the last fifo write can be 8 bit. */ - omap_i2c_write, - omap_badwidth_write16, - }, - }, - .endianness = DEVICE_NATIVE_ENDIAN, -}; - -static int omap_i2c_init(SysBusDevice *sbd) -{ - DeviceState *dev = DEVICE(sbd); - OMAPI2CState *s = OMAP_I2C(dev); - - if (!s->fclk) { - error_report("omap_i2c: fclk not connected"); - return -1; - } - if (s->revision >= OMAP2_INTR_REV && !s->iclk) { - /* Note that OMAP1 doesn't have a separate interface clock */ - error_report("omap_i2c: iclk not connected"); - return -1; - } - - sysbus_init_irq(sbd, &s->irq); - sysbus_init_irq(sbd, &s->drq[0]); - sysbus_init_irq(sbd, &s->drq[1]); - memory_region_init_io(&s->iomem, OBJECT(s), &omap_i2c_ops, s, "omap.i2c", - (s->revision < OMAP2_INTR_REV) ? 0x800 : 0x1000); - sysbus_init_mmio(sbd, &s->iomem); - s->bus = i2c_init_bus(dev, NULL); - return 0; -} - -static Property omap_i2c_properties[] = { - DEFINE_PROP_UINT8("revision", OMAPI2CState, revision, 0), - DEFINE_PROP_PTR("iclk", OMAPI2CState, iclk), - DEFINE_PROP_PTR("fclk", OMAPI2CState, fclk), - DEFINE_PROP_END_OF_LIST(), -}; - -static void omap_i2c_class_init(ObjectClass *klass, void *data) -{ - DeviceClass *dc = DEVICE_CLASS(klass); - SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass); - k->init = omap_i2c_init; - dc->props = omap_i2c_properties; - dc->reset = omap_i2c_reset; - /* Reason: pointer properties "iclk", "fclk" */ - dc->cannot_instantiate_with_device_add_yet = true; -} - -static const TypeInfo omap_i2c_info = { - .name = TYPE_OMAP_I2C, - .parent = TYPE_SYS_BUS_DEVICE, - .instance_size = sizeof(OMAPI2CState), - .class_init = omap_i2c_class_init, -}; - -static void omap_i2c_register_types(void) -{ - type_register_static(&omap_i2c_info); -} - -I2CBus *omap_i2c_bus(DeviceState *omap_i2c) -{ - OMAPI2CState *s = OMAP_I2C(omap_i2c); - return s->bus; -} - -type_init(omap_i2c_register_types) diff --git a/qemu/hw/i2c/pm_smbus.c b/qemu/hw/i2c/pm_smbus.c deleted file mode 100644 index 6fc3923f5..000000000 --- a/qemu/hw/i2c/pm_smbus.c +++ /dev/null @@ -1,228 +0,0 @@ -/* - * PC SMBus implementation - * splitted from acpi.c - * - * Copyright (c) 2006 Fabrice Bellard - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License version 2 as published by the Free Software Foundation. - * - * 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 "qemu/osdep.h" -#include "hw/hw.h" -#include "hw/i386/pc.h" -#include "hw/i2c/pm_smbus.h" -#include "hw/i2c/smbus.h" - -/* no save/load? */ - -#define SMBHSTSTS 0x00 -#define SMBHSTCNT 0x02 -#define SMBHSTCMD 0x03 -#define SMBHSTADD 0x04 -#define SMBHSTDAT0 0x05 -#define SMBHSTDAT1 0x06 -#define SMBBLKDAT 0x07 - -#define STS_HOST_BUSY (1) -#define STS_INTR (1<<1) -#define STS_DEV_ERR (1<<2) -#define STS_BUS_ERR (1<<3) -#define STS_FAILED (1<<4) -#define STS_SMBALERT (1<<5) -#define STS_INUSE_STS (1<<6) -#define STS_BYTE_DONE (1<<7) -/* Signs of successfully transaction end : -* ByteDoneStatus = 1 (STS_BYTE_DONE) and INTR = 1 (STS_INTR ) -*/ - -//#define DEBUG - -#ifdef DEBUG -# define SMBUS_DPRINTF(format, ...) printf(format, ## __VA_ARGS__) -#else -# define SMBUS_DPRINTF(format, ...) do { } while (0) -#endif - - -static void smb_transaction(PMSMBus *s) -{ - uint8_t prot = (s->smb_ctl >> 2) & 0x07; - uint8_t read = s->smb_addr & 0x01; - uint8_t cmd = s->smb_cmd; - uint8_t addr = s->smb_addr >> 1; - I2CBus *bus = s->smbus; - int ret; - - SMBUS_DPRINTF("SMBus trans addr=0x%02x prot=0x%02x\n", addr, prot); - /* Transaction isn't exec if STS_DEV_ERR bit set */ - if ((s->smb_stat & STS_DEV_ERR) != 0) { - goto error; - } - switch(prot) { - case 0x0: - ret = smbus_quick_command(bus, addr, read); - goto done; - case 0x1: - if (read) { - ret = smbus_receive_byte(bus, addr); - goto data8; - } else { - ret = smbus_send_byte(bus, addr, cmd); - goto done; - } - case 0x2: - if (read) { - ret = smbus_read_byte(bus, addr, cmd); - goto data8; - } else { - ret = smbus_write_byte(bus, addr, cmd, s->smb_data0); - goto done; - } - break; - case 0x3: - if (read) { - ret = smbus_read_word(bus, addr, cmd); - goto data16; - } else { - ret = smbus_write_word(bus, addr, cmd, (s->smb_data1 << 8) | s->smb_data0); - goto done; - } - break; - case 0x5: - if (read) { - ret = smbus_read_block(bus, addr, cmd, s->smb_data); - goto data8; - } else { - ret = smbus_write_block(bus, addr, cmd, s->smb_data, s->smb_data0); - goto done; - } - break; - default: - goto error; - } - abort(); - -data16: - if (ret < 0) { - goto error; - } - s->smb_data1 = ret >> 8; -data8: - if (ret < 0) { - goto error; - } - s->smb_data0 = ret; -done: - if (ret < 0) { - goto error; - } - s->smb_stat |= STS_BYTE_DONE | STS_INTR; - return; - -error: - s->smb_stat |= STS_DEV_ERR; - return; - -} - -static void smb_ioport_writeb(void *opaque, hwaddr addr, uint64_t val, - unsigned width) -{ - PMSMBus *s = opaque; - - SMBUS_DPRINTF("SMB writeb port=0x%04" HWADDR_PRIx - " val=0x%02" PRIx64 "\n", addr, val); - switch(addr) { - case SMBHSTSTS: - s->smb_stat = (~(val & 0xff)) & s->smb_stat; - s->smb_index = 0; - break; - case SMBHSTCNT: - s->smb_ctl = val; - if (val & 0x40) - smb_transaction(s); - break; - case SMBHSTCMD: - s->smb_cmd = val; - break; - case SMBHSTADD: - s->smb_addr = val; - break; - case SMBHSTDAT0: - s->smb_data0 = val; - break; - case SMBHSTDAT1: - s->smb_data1 = val; - break; - case SMBBLKDAT: - s->smb_data[s->smb_index++] = val; - if (s->smb_index > 31) - s->smb_index = 0; - break; - default: - break; - } -} - -static uint64_t smb_ioport_readb(void *opaque, hwaddr addr, unsigned width) -{ - PMSMBus *s = opaque; - uint32_t val; - - switch(addr) { - case SMBHSTSTS: - val = s->smb_stat; - break; - case SMBHSTCNT: - s->smb_index = 0; - val = s->smb_ctl & 0x1f; - break; - case SMBHSTCMD: - val = s->smb_cmd; - break; - case SMBHSTADD: - val = s->smb_addr; - break; - case SMBHSTDAT0: - val = s->smb_data0; - break; - case SMBHSTDAT1: - val = s->smb_data1; - break; - case SMBBLKDAT: - val = s->smb_data[s->smb_index++]; - if (s->smb_index > 31) - s->smb_index = 0; - break; - default: - val = 0; - break; - } - SMBUS_DPRINTF("SMB readb port=0x%04" HWADDR_PRIx " val=0x%02x\n", addr, val); - return val; -} - -static const MemoryRegionOps pm_smbus_ops = { - .read = smb_ioport_readb, - .write = smb_ioport_writeb, - .valid.min_access_size = 1, - .valid.max_access_size = 1, - .endianness = DEVICE_LITTLE_ENDIAN, -}; - -void pm_smbus_init(DeviceState *parent, PMSMBus *smb) -{ - smb->smbus = i2c_init_bus(parent, "i2c"); - memory_region_init_io(&smb->io, OBJECT(parent), &pm_smbus_ops, smb, - "pm-smbus", 64); -} diff --git a/qemu/hw/i2c/smbus.c b/qemu/hw/i2c/smbus.c deleted file mode 100644 index 3979b3dad..000000000 --- a/qemu/hw/i2c/smbus.c +++ /dev/null @@ -1,362 +0,0 @@ -/* - * QEMU SMBus device emulation. - * - * Copyright (c) 2007 CodeSourcery. - * Written by Paul Brook - * - * This code is licensed under the LGPL. - */ - -/* TODO: Implement PEC. */ - -#include "qemu/osdep.h" -#include "hw/hw.h" -#include "hw/i2c/i2c.h" -#include "hw/i2c/smbus.h" - -//#define DEBUG_SMBUS 1 - -#ifdef DEBUG_SMBUS -#define DPRINTF(fmt, ...) \ -do { printf("smbus(%02x): " fmt , dev->i2c.address, ## __VA_ARGS__); } while (0) -#define BADF(fmt, ...) \ -do { fprintf(stderr, "smbus: error: " fmt , ## __VA_ARGS__); exit(1);} while (0) -#else -#define DPRINTF(fmt, ...) do {} while(0) -#define BADF(fmt, ...) \ -do { fprintf(stderr, "smbus: error: " fmt , ## __VA_ARGS__);} while (0) -#endif - -enum { - SMBUS_IDLE, - SMBUS_WRITE_DATA, - SMBUS_RECV_BYTE, - SMBUS_READ_DATA, - SMBUS_DONE, - SMBUS_CONFUSED = -1 -}; - -static void smbus_do_quick_cmd(SMBusDevice *dev, int recv) -{ - SMBusDeviceClass *sc = SMBUS_DEVICE_GET_CLASS(dev); - - DPRINTF("Quick Command %d\n", recv); - if (sc->quick_cmd) { - sc->quick_cmd(dev, recv); - } -} - -static void smbus_do_write(SMBusDevice *dev) -{ - SMBusDeviceClass *sc = SMBUS_DEVICE_GET_CLASS(dev); - - if (dev->data_len == 0) { - smbus_do_quick_cmd(dev, 0); - } else if (dev->data_len == 1) { - DPRINTF("Send Byte\n"); - if (sc->send_byte) { - sc->send_byte(dev, dev->data_buf[0]); - } - } else { - dev->command = dev->data_buf[0]; - DPRINTF("Command %d len %d\n", dev->command, dev->data_len - 1); - if (sc->write_data) { - sc->write_data(dev, dev->command, dev->data_buf + 1, - dev->data_len - 1); - } - } -} - -static void smbus_i2c_event(I2CSlave *s, enum i2c_event event) -{ - SMBusDevice *dev = SMBUS_DEVICE(s); - - switch (event) { - case I2C_START_SEND: - switch (dev->mode) { - case SMBUS_IDLE: - DPRINTF("Incoming data\n"); - dev->mode = SMBUS_WRITE_DATA; - break; - default: - BADF("Unexpected send start condition in state %d\n", dev->mode); - dev->mode = SMBUS_CONFUSED; - break; - } - break; - - case I2C_START_RECV: - switch (dev->mode) { - case SMBUS_IDLE: - DPRINTF("Read mode\n"); - dev->mode = SMBUS_RECV_BYTE; - break; - case SMBUS_WRITE_DATA: - if (dev->data_len == 0) { - BADF("Read after write with no data\n"); - dev->mode = SMBUS_CONFUSED; - } else { - if (dev->data_len > 1) { - smbus_do_write(dev); - } else { - dev->command = dev->data_buf[0]; - DPRINTF("%02x: Command %d\n", dev->i2c.address, - dev->command); - } - DPRINTF("Read mode\n"); - dev->data_len = 0; - dev->mode = SMBUS_READ_DATA; - } - break; - default: - BADF("Unexpected recv start condition in state %d\n", dev->mode); - dev->mode = SMBUS_CONFUSED; - break; - } - break; - - case I2C_FINISH: - switch (dev->mode) { - case SMBUS_WRITE_DATA: - smbus_do_write(dev); - break; - case SMBUS_RECV_BYTE: - smbus_do_quick_cmd(dev, 1); - break; - case SMBUS_READ_DATA: - BADF("Unexpected stop during receive\n"); - break; - default: - /* Nothing to do. */ - break; - } - dev->mode = SMBUS_IDLE; - dev->data_len = 0; - break; - - case I2C_NACK: - switch (dev->mode) { - case SMBUS_DONE: - /* Nothing to do. */ - break; - case SMBUS_READ_DATA: - dev->mode = SMBUS_DONE; - break; - default: - BADF("Unexpected NACK in state %d\n", dev->mode); - dev->mode = SMBUS_CONFUSED; - break; - } - } -} - -static int smbus_i2c_recv(I2CSlave *s) -{ - SMBusDevice *dev = SMBUS_DEVICE(s); - SMBusDeviceClass *sc = SMBUS_DEVICE_GET_CLASS(dev); - int ret; - - switch (dev->mode) { - case SMBUS_RECV_BYTE: - if (sc->receive_byte) { - ret = sc->receive_byte(dev); - } else { - ret = 0; - } - DPRINTF("Receive Byte %02x\n", ret); - dev->mode = SMBUS_DONE; - break; - case SMBUS_READ_DATA: - if (sc->read_data) { - ret = sc->read_data(dev, dev->command, dev->data_len); - dev->data_len++; - } else { - ret = 0; - } - DPRINTF("Read data %02x\n", ret); - break; - default: - BADF("Unexpected read in state %d\n", dev->mode); - dev->mode = SMBUS_CONFUSED; - ret = 0; - break; - } - return ret; -} - -static int smbus_i2c_send(I2CSlave *s, uint8_t data) -{ - SMBusDevice *dev = SMBUS_DEVICE(s); - - switch (dev->mode) { - case SMBUS_WRITE_DATA: - DPRINTF("Write data %02x\n", data); - dev->data_buf[dev->data_len++] = data; - break; - default: - BADF("Unexpected write in state %d\n", dev->mode); - break; - } - return 0; -} - -static int smbus_device_init(I2CSlave *i2c) -{ - SMBusDevice *dev = SMBUS_DEVICE(i2c); - SMBusDeviceClass *sc = SMBUS_DEVICE_GET_CLASS(dev); - - return sc->init(dev); -} - -/* Master device commands. */ -int smbus_quick_command(I2CBus *bus, uint8_t addr, int read) -{ - if (i2c_start_transfer(bus, addr, read)) { - return -1; - } - i2c_end_transfer(bus); - return 0; -} - -int smbus_receive_byte(I2CBus *bus, uint8_t addr) -{ - uint8_t data; - - if (i2c_start_transfer(bus, addr, 1)) { - return -1; - } - data = i2c_recv(bus); - i2c_nack(bus); - i2c_end_transfer(bus); - return data; -} - -int smbus_send_byte(I2CBus *bus, uint8_t addr, uint8_t data) -{ - if (i2c_start_transfer(bus, addr, 0)) { - return -1; - } - i2c_send(bus, data); - i2c_end_transfer(bus); - return 0; -} - -int smbus_read_byte(I2CBus *bus, uint8_t addr, uint8_t command) -{ - uint8_t data; - if (i2c_start_transfer(bus, addr, 0)) { - return -1; - } - i2c_send(bus, command); - i2c_start_transfer(bus, addr, 1); - data = i2c_recv(bus); - i2c_nack(bus); - i2c_end_transfer(bus); - return data; -} - -int smbus_write_byte(I2CBus *bus, uint8_t addr, uint8_t command, uint8_t data) -{ - if (i2c_start_transfer(bus, addr, 0)) { - return -1; - } - i2c_send(bus, command); - i2c_send(bus, data); - i2c_end_transfer(bus); - return 0; -} - -int smbus_read_word(I2CBus *bus, uint8_t addr, uint8_t command) -{ - uint16_t data; - if (i2c_start_transfer(bus, addr, 0)) { - return -1; - } - i2c_send(bus, command); - i2c_start_transfer(bus, addr, 1); - data = i2c_recv(bus); - data |= i2c_recv(bus) << 8; - i2c_nack(bus); - i2c_end_transfer(bus); - return data; -} - -int smbus_write_word(I2CBus *bus, uint8_t addr, uint8_t command, uint16_t data) -{ - if (i2c_start_transfer(bus, addr, 0)) { - return -1; - } - i2c_send(bus, command); - i2c_send(bus, data & 0xff); - i2c_send(bus, data >> 8); - i2c_end_transfer(bus); - return 0; -} - -int smbus_read_block(I2CBus *bus, uint8_t addr, uint8_t command, uint8_t *data) -{ - int len; - int i; - - if (i2c_start_transfer(bus, addr, 0)) { - return -1; - } - i2c_send(bus, command); - i2c_start_transfer(bus, addr, 1); - len = i2c_recv(bus); - if (len > 32) { - len = 0; - } - for (i = 0; i < len; i++) { - data[i] = i2c_recv(bus); - } - i2c_nack(bus); - i2c_end_transfer(bus); - return len; -} - -int smbus_write_block(I2CBus *bus, uint8_t addr, uint8_t command, uint8_t *data, - int len) -{ - int i; - - if (len > 32) - len = 32; - - if (i2c_start_transfer(bus, addr, 0)) { - return -1; - } - i2c_send(bus, command); - i2c_send(bus, len); - for (i = 0; i < len; i++) { - i2c_send(bus, data[i]); - } - i2c_end_transfer(bus); - return 0; -} - -static void smbus_device_class_init(ObjectClass *klass, void *data) -{ - I2CSlaveClass *sc = I2C_SLAVE_CLASS(klass); - - sc->init = smbus_device_init; - sc->event = smbus_i2c_event; - sc->recv = smbus_i2c_recv; - sc->send = smbus_i2c_send; -} - -static const TypeInfo smbus_device_type_info = { - .name = TYPE_SMBUS_DEVICE, - .parent = TYPE_I2C_SLAVE, - .instance_size = sizeof(SMBusDevice), - .abstract = true, - .class_size = sizeof(SMBusDeviceClass), - .class_init = smbus_device_class_init, -}; - -static void smbus_device_register_types(void) -{ - type_register_static(&smbus_device_type_info); -} - -type_init(smbus_device_register_types) diff --git a/qemu/hw/i2c/smbus_eeprom.c b/qemu/hw/i2c/smbus_eeprom.c deleted file mode 100644 index 5b7bd891b..000000000 --- a/qemu/hw/i2c/smbus_eeprom.c +++ /dev/null @@ -1,159 +0,0 @@ -/* - * QEMU SMBus EEPROM device - * - * Copyright (c) 2007 Arastra, Inc. - * - * 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 "qemu/osdep.h" -#include "hw/hw.h" -#include "hw/i2c/i2c.h" -#include "hw/i2c/smbus.h" - -//#define DEBUG - -typedef struct SMBusEEPROMDevice { - SMBusDevice smbusdev; - void *data; - uint8_t offset; -} SMBusEEPROMDevice; - -static void eeprom_quick_cmd(SMBusDevice *dev, uint8_t read) -{ -#ifdef DEBUG - printf("eeprom_quick_cmd: addr=0x%02x read=%d\n", dev->i2c.address, read); -#endif -} - -static void eeprom_send_byte(SMBusDevice *dev, uint8_t val) -{ - SMBusEEPROMDevice *eeprom = (SMBusEEPROMDevice *) dev; -#ifdef DEBUG - printf("eeprom_send_byte: addr=0x%02x val=0x%02x\n", - dev->i2c.address, val); -#endif - eeprom->offset = val; -} - -static uint8_t eeprom_receive_byte(SMBusDevice *dev) -{ - SMBusEEPROMDevice *eeprom = (SMBusEEPROMDevice *) dev; - uint8_t *data = eeprom->data; - uint8_t val = data[eeprom->offset++]; -#ifdef DEBUG - printf("eeprom_receive_byte: addr=0x%02x val=0x%02x\n", - dev->i2c.address, val); -#endif - return val; -} - -static void eeprom_write_data(SMBusDevice *dev, uint8_t cmd, uint8_t *buf, int len) -{ - SMBusEEPROMDevice *eeprom = (SMBusEEPROMDevice *) dev; - int n; -#ifdef DEBUG - printf("eeprom_write_byte: addr=0x%02x cmd=0x%02x val=0x%02x\n", - dev->i2c.address, cmd, buf[0]); -#endif - /* A page write operation is not a valid SMBus command. - It is a block write without a length byte. Fortunately we - get the full block anyway. */ - /* TODO: Should this set the current location? */ - if (cmd + len > 256) - n = 256 - cmd; - else - n = len; - memcpy(eeprom->data + cmd, buf, n); - len -= n; - if (len) - memcpy(eeprom->data, buf + n, len); -} - -static uint8_t eeprom_read_data(SMBusDevice *dev, uint8_t cmd, int n) -{ - SMBusEEPROMDevice *eeprom = (SMBusEEPROMDevice *) dev; - /* If this is the first byte then set the current position. */ - if (n == 0) - eeprom->offset = cmd; - /* As with writes, we implement block reads without the - SMBus length byte. */ - return eeprom_receive_byte(dev); -} - -static int smbus_eeprom_initfn(SMBusDevice *dev) -{ - SMBusEEPROMDevice *eeprom = (SMBusEEPROMDevice *)dev; - - eeprom->offset = 0; - return 0; -} - -static Property smbus_eeprom_properties[] = { - DEFINE_PROP_PTR("data", SMBusEEPROMDevice, data), - DEFINE_PROP_END_OF_LIST(), -}; - -static void smbus_eeprom_class_initfn(ObjectClass *klass, void *data) -{ - DeviceClass *dc = DEVICE_CLASS(klass); - SMBusDeviceClass *sc = SMBUS_DEVICE_CLASS(klass); - - sc->init = smbus_eeprom_initfn; - sc->quick_cmd = eeprom_quick_cmd; - sc->send_byte = eeprom_send_byte; - sc->receive_byte = eeprom_receive_byte; - sc->write_data = eeprom_write_data; - sc->read_data = eeprom_read_data; - dc->props = smbus_eeprom_properties; - /* Reason: pointer property "data" */ - dc->cannot_instantiate_with_device_add_yet = true; -} - -static const TypeInfo smbus_eeprom_info = { - .name = "smbus-eeprom", - .parent = TYPE_SMBUS_DEVICE, - .instance_size = sizeof(SMBusEEPROMDevice), - .class_init = smbus_eeprom_class_initfn, -}; - -static void smbus_eeprom_register_types(void) -{ - type_register_static(&smbus_eeprom_info); -} - -type_init(smbus_eeprom_register_types) - -void smbus_eeprom_init(I2CBus *smbus, int nb_eeprom, - const uint8_t *eeprom_spd, int eeprom_spd_size) -{ - int i; - uint8_t *eeprom_buf = g_malloc0(8 * 256); /* XXX: make this persistent */ - if (eeprom_spd_size > 0) { - memcpy(eeprom_buf, eeprom_spd, eeprom_spd_size); - } - - for (i = 0; i < nb_eeprom; i++) { - DeviceState *eeprom; - eeprom = qdev_create((BusState *)smbus, "smbus-eeprom"); - qdev_prop_set_uint8(eeprom, "address", 0x50 + i); - qdev_prop_set_ptr(eeprom, "data", eeprom_buf + (i * 256)); - qdev_init_nofail(eeprom); - } -} diff --git a/qemu/hw/i2c/smbus_ich9.c b/qemu/hw/i2c/smbus_ich9.c deleted file mode 100644 index 498f03e83..000000000 --- a/qemu/hw/i2c/smbus_ich9.c +++ /dev/null @@ -1,130 +0,0 @@ -/* - * ACPI implementation - * - * Copyright (c) 2006 Fabrice Bellard - * Copyright (c) 2009 Isaku Yamahata <yamahata at valinux co jp> - * VA Linux Systems Japan K.K. - * Copyright (C) 2012 Jason Baron <jbaron@redhat.com> - * - * This is based on acpi.c, but heavily rewritten. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License version 2 as published by the Free Software Foundation. - * - * 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/> - * - * Contributions after 2012-01-13 are licensed under the terms of the - * GNU GPL, version 2 or (at your option) any later version. - * - */ -#include "qemu/osdep.h" -#include "hw/hw.h" -#include "hw/i386/pc.h" -#include "hw/i2c/pm_smbus.h" -#include "hw/pci/pci.h" -#include "sysemu/sysemu.h" -#include "hw/i2c/i2c.h" -#include "hw/i2c/smbus.h" - -#include "hw/i386/ich9.h" - -#define TYPE_ICH9_SMB_DEVICE "ICH9 SMB" -#define ICH9_SMB_DEVICE(obj) \ - OBJECT_CHECK(ICH9SMBState, (obj), TYPE_ICH9_SMB_DEVICE) - -typedef struct ICH9SMBState { - PCIDevice dev; - - PMSMBus smb; -} ICH9SMBState; - -static const VMStateDescription vmstate_ich9_smbus = { - .name = "ich9_smb", - .version_id = 1, - .minimum_version_id = 1, - .fields = (VMStateField[]) { - VMSTATE_PCI_DEVICE(dev, struct ICH9SMBState), - VMSTATE_END_OF_LIST() - } -}; - -static void ich9_smbus_write_config(PCIDevice *d, uint32_t address, - uint32_t val, int len) -{ - ICH9SMBState *s = ICH9_SMB_DEVICE(d); - - pci_default_write_config(d, address, val, len); - if (range_covers_byte(address, len, ICH9_SMB_HOSTC)) { - uint8_t hostc = s->dev.config[ICH9_SMB_HOSTC]; - if ((hostc & ICH9_SMB_HOSTC_HST_EN) && - !(hostc & ICH9_SMB_HOSTC_I2C_EN)) { - memory_region_set_enabled(&s->smb.io, true); - } else { - memory_region_set_enabled(&s->smb.io, false); - } - } -} - -static void ich9_smbus_realize(PCIDevice *d, Error **errp) -{ - ICH9SMBState *s = ICH9_SMB_DEVICE(d); - - /* TODO? D31IP.SMIP in chipset configuration space */ - pci_config_set_interrupt_pin(d->config, 0x01); /* interrupt pin 1 */ - - pci_set_byte(d->config + ICH9_SMB_HOSTC, 0); - /* TODO bar0, bar1: 64bit BAR support*/ - - pm_smbus_init(&d->qdev, &s->smb); - pci_register_bar(d, ICH9_SMB_SMB_BASE_BAR, PCI_BASE_ADDRESS_SPACE_IO, - &s->smb.io); -} - -static void ich9_smb_class_init(ObjectClass *klass, void *data) -{ - DeviceClass *dc = DEVICE_CLASS(klass); - PCIDeviceClass *k = PCI_DEVICE_CLASS(klass); - - k->vendor_id = PCI_VENDOR_ID_INTEL; - k->device_id = PCI_DEVICE_ID_INTEL_ICH9_6; - k->revision = ICH9_A2_SMB_REVISION; - k->class_id = PCI_CLASS_SERIAL_SMBUS; - dc->vmsd = &vmstate_ich9_smbus; - dc->desc = "ICH9 SMBUS Bridge"; - k->realize = ich9_smbus_realize; - k->config_write = ich9_smbus_write_config; - /* - * Reason: part of ICH9 southbridge, needs to be wired up by - * pc_q35_init() - */ - dc->cannot_instantiate_with_device_add_yet = true; -} - -I2CBus *ich9_smb_init(PCIBus *bus, int devfn, uint32_t smb_io_base) -{ - PCIDevice *d = - pci_create_simple_multifunction(bus, devfn, true, TYPE_ICH9_SMB_DEVICE); - ICH9SMBState *s = ICH9_SMB_DEVICE(d); - return s->smb.smbus; -} - -static const TypeInfo ich9_smb_info = { - .name = TYPE_ICH9_SMB_DEVICE, - .parent = TYPE_PCI_DEVICE, - .instance_size = sizeof(ICH9SMBState), - .class_init = ich9_smb_class_init, -}; - -static void ich9_smb_register(void) -{ - type_register_static(&ich9_smb_info); -} - -type_init(ich9_smb_register); diff --git a/qemu/hw/i2c/versatile_i2c.c b/qemu/hw/i2c/versatile_i2c.c deleted file mode 100644 index fee3bc761..000000000 --- a/qemu/hw/i2c/versatile_i2c.c +++ /dev/null @@ -1,114 +0,0 @@ -/* - * ARM Versatile I2C controller - * - * Copyright (c) 2006-2007 CodeSourcery. - * Copyright (c) 2012 Oskar Andero <oskar.andero@gmail.com> - * - * This file is derived from hw/realview.c by Paul Brook - * - * 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 "qemu/osdep.h" -#include "hw/sysbus.h" -#include "bitbang_i2c.h" - -#define TYPE_VERSATILE_I2C "versatile_i2c" -#define VERSATILE_I2C(obj) \ - OBJECT_CHECK(VersatileI2CState, (obj), TYPE_VERSATILE_I2C) - -typedef struct VersatileI2CState { - SysBusDevice parent_obj; - - MemoryRegion iomem; - bitbang_i2c_interface *bitbang; - int out; - int in; -} VersatileI2CState; - -static uint64_t versatile_i2c_read(void *opaque, hwaddr offset, - unsigned size) -{ - VersatileI2CState *s = (VersatileI2CState *)opaque; - - if (offset == 0) { - return (s->out & 1) | (s->in << 1); - } else { - qemu_log_mask(LOG_GUEST_ERROR, - "%s: Bad offset 0x%x\n", __func__, (int)offset); - return -1; - } -} - -static void versatile_i2c_write(void *opaque, hwaddr offset, - uint64_t value, unsigned size) -{ - VersatileI2CState *s = (VersatileI2CState *)opaque; - - switch (offset) { - case 0: - s->out |= value & 3; - break; - case 4: - s->out &= ~value; - break; - default: - qemu_log_mask(LOG_GUEST_ERROR, - "%s: Bad offset 0x%x\n", __func__, (int)offset); - } - bitbang_i2c_set(s->bitbang, BITBANG_I2C_SCL, (s->out & 1) != 0); - s->in = bitbang_i2c_set(s->bitbang, BITBANG_I2C_SDA, (s->out & 2) != 0); -} - -static const MemoryRegionOps versatile_i2c_ops = { - .read = versatile_i2c_read, - .write = versatile_i2c_write, - .endianness = DEVICE_NATIVE_ENDIAN, -}; - -static int versatile_i2c_init(SysBusDevice *sbd) -{ - DeviceState *dev = DEVICE(sbd); - VersatileI2CState *s = VERSATILE_I2C(dev); - I2CBus *bus; - - bus = i2c_init_bus(dev, "i2c"); - s->bitbang = bitbang_i2c_init(bus); - memory_region_init_io(&s->iomem, OBJECT(s), &versatile_i2c_ops, s, - "versatile_i2c", 0x1000); - sysbus_init_mmio(sbd, &s->iomem); - return 0; -} - -static void versatile_i2c_class_init(ObjectClass *klass, void *data) -{ - SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass); - - k->init = versatile_i2c_init; -} - -static const TypeInfo versatile_i2c_info = { - .name = TYPE_VERSATILE_I2C, - .parent = TYPE_SYS_BUS_DEVICE, - .instance_size = sizeof(VersatileI2CState), - .class_init = versatile_i2c_class_init, -}; - -static void versatile_i2c_register_types(void) -{ - type_register_static(&versatile_i2c_info); -} - -type_init(versatile_i2c_register_types) |