Signed-off-by: Kuo-Jung Su <dant...@faraday-tech.com> --- hw/fti2c010.c | 209 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ hw/fti2c010.h | 77 +++++++++++++++++++++ 2 files changed, 286 insertions(+) create mode 100644 hw/fti2c010.c create mode 100644 hw/fti2c010.h
diff --git a/hw/fti2c010.c b/hw/fti2c010.c new file mode 100644 index 0000000..3073314 --- /dev/null +++ b/hw/fti2c010.c @@ -0,0 +1,209 @@ +/* + * QEMU model of the FTSSP010 Controller + * + * Copyright (C) 2012 Faraday Technology + * Copyright (C) 2012 Dante Su <dant...@faraday-tech.com> + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "sysbus.h" +#include "sysemu/sysemu.h" +#include "i2c.h" +#include "fti2c010.h" + +#define I2C_RD 1 +#define I2C_WR 0 + +typedef struct { + SysBusDevice busdev; + MemoryRegion mmio; + + qemu_irq irq; + i2c_bus *bus; + + uint32_t cr; + uint32_t sr; + uint32_t cdr; + uint32_t dr; + uint32_t tgsr; + + uint8_t recv; /* I2C RD = 1; I2C WR = 0 */ + uint8_t addr; /* 7-bits device address */ + +} fti2c010_state; + +static uint64_t +fti2c010_mem_read(void *opaque, hwaddr addr, unsigned int size) +{ + fti2c010_state *s = opaque; + uint32_t rc = 0; + + switch (addr) { + case REG_CR: + return s->cr; + case REG_SR: + rc = s->sr | (i2c_bus_busy(s->bus) ? SR_BB : 0); + s->sr &= 0xfffff00f; + qemu_set_irq(s->irq, 0); + break; + case REG_CDR: + return s->cdr; + case REG_DR: + return s->dr; + case REG_TGSR: + return s->tgsr; + case REG_BMR: + return 0x00000003; + case 0x30: /* revision register */ + return 0x00011000; + default: + break; + } + + return rc; +} + +static void +fti2c010_mem_write(void *opaque, hwaddr addr, uint64_t val64, unsigned int size) +{ + fti2c010_state *s = opaque; + + switch (addr) { + case REG_CR: + s->cr = (uint32_t)val64; + if (s->cr & CR_I2CRST) { + s->dr = 0; + s->sr = 0; + } else if ((s->cr & (CR_MASTER_EN | CR_TBEN)) == (CR_MASTER_EN | CR_TBEN)) { + s->sr &= ~SR_ACK; + if (s->cr & CR_START) { + s->recv = (s->dr & I2C_RD) ? 1 : 0; + s->addr = (s->dr >> 1) & 0x7f; + if (i2c_start_transfer(s->bus, s->addr, s->recv) == 0) + s->sr |= SR_DT | SR_ACK; + else + s->sr &= ~SR_DT; + } else { + if (s->recv) { + s->dr = i2c_recv(s->bus); + s->sr |= SR_DR; + } else { + i2c_send(s->bus, (uint8_t)s->dr); + s->sr |= SR_DT; + } + if (s->cr & CR_NACK) + i2c_nack(s->bus); + s->sr |= SR_ACK; + if (s->cr & CR_STOP) + i2c_end_transfer(s->bus); + } + } + s->cr &= 0xffffff7e; /* clear TB_EN, I2C_RST */ + if ((s->sr >> 4) & (s->cr >> 8)) + qemu_set_irq(s->irq, 1); + break; + case REG_CDR: + s->cdr = (uint32_t)val64; + break; + case REG_DR: + s->dr = (uint32_t)val64 & 0xff; + break; + case REG_TGSR: + s->tgsr = (uint32_t)val64; + break; + default: + break; + } +} + +static const MemoryRegionOps bus_ops = { + .read = fti2c010_mem_read, + .write = fti2c010_mem_write, + .endianness = DEVICE_LITTLE_ENDIAN, + .valid = { + .min_access_size = 4, + .max_access_size = 4 + } +}; + +static void fti2c010_reset(DeviceState *d) +{ + fti2c010_state *s = DO_UPCAST(fti2c010_state, busdev.qdev, d); + + s->cr = 0; + s->sr = 0; + s->cdr = 0; + s->tgsr = 0x00000401; + + qemu_set_irq(s->irq, 0); +} + +static int fti2c010_init(SysBusDevice *dev) +{ + fti2c010_state *s = FROM_SYSBUS(typeof(*s), dev); + + s->bus = i2c_init_bus(&dev->qdev, "i2c"); + + memory_region_init_io(&s->mmio, &bus_ops, s, "fti2c010", 0x1000); + sysbus_init_mmio(dev, &s->mmio); + sysbus_init_irq(dev, &s->irq); + + return 0; +} + +static const VMStateDescription vmstate_fti2c010 = { + .name = "fti2c010", + .version_id = 1, + .minimum_version_id = 1, + .minimum_version_id_old = 1, + .fields = (VMStateField[]) { + VMSTATE_UINT32(cr, fti2c010_state), + VMSTATE_UINT32(sr, fti2c010_state), + VMSTATE_UINT32(cdr, fti2c010_state), + VMSTATE_UINT32(dr, fti2c010_state), + VMSTATE_UINT32(tgsr, fti2c010_state), + VMSTATE_END_OF_LIST() + } +}; + +static void fti2c010_class_init(ObjectClass *klass, void *data) +{ + SysBusDeviceClass *sdc = SYS_BUS_DEVICE_CLASS(klass); + DeviceClass *k = DEVICE_CLASS(klass); + + sdc->init = fti2c010_init; + k->vmsd = &vmstate_fti2c010; + k->reset = fti2c010_reset; + k->no_user = 1; +} + +static TypeInfo fti2c010_info = { + .name = "fti2c010", + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(fti2c010_state), + .class_init = fti2c010_class_init, +}; + +static void fti2c010_register_types(void) +{ + type_register_static(&fti2c010_info); +} + +type_init(fti2c010_register_types) diff --git a/hw/fti2c010.h b/hw/fti2c010.h new file mode 100644 index 0000000..deb12ec --- /dev/null +++ b/hw/fti2c010.h @@ -0,0 +1,77 @@ +/* + * (C) Copyright 2010 + * Faraday Technology Inc. <www.faraday-tech.com> + * Dante Su <dant...@gmail.com> + * + * See file CREDITS for list of people who contributed to this + * project. + * + * 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, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#ifndef FTI2C010_H +#define FTI2C010_H + +/* + * FTI2C010 registers + */ +#define REG_CR 0x00 +#define REG_SR 0x04 +#define REG_CDR 0x08 +#define REG_DR 0x0C +#define REG_SAR 0x10 +#define REG_TGSR 0x14 +#define REG_BMR 0x18 + +/* + * REG_CR + */ +#define CR_STARTIEN 0x4000 /* start condition */ +#define CR_ALIEN 0x2000 /* Arbitration lose */ +#define CR_SAMIEN 0x1000 /* slave address match */ +#define CR_STOPIEN 0x800 /* stop condition */ +#define CR_BERRIEN 0x400 /* non ACK response */ +#define CR_DRIEN 0x200 /* data receive */ +#define CR_DTIEN 0x100 /* data transmit */ +#define CR_TBEN 0x80 /* transfer byte enable */ +#define CR_NACK 0x40 /* with this bit set, fti2c010 will not drive ACK signal */ +#define CR_STOP 0x20 /* stop */ +#define CR_START 0x10 /* start */ +#define CR_GCEN 0x8 /* general call */ +#define CR_SCLEN 0x4 /* enable clock */ +#define CR_I2CEN 0x2 /* enable I2C */ +#define CR_I2CRST 0x1 /* reset I2C */ +#define CR_MASTER_INTR (CR_ALIEN | CR_BERRIEN | CR_DRIEN | CR_DTIEN) +#define CR_MASTER_EN (CR_SCLEN | CR_I2CEN) +#define CR_MASTER_MODE (CR_MASTER_INTR | CR_MASTER_EN) + +/* + * REG_SR + */ +#define SR_START 0x800 +#define SR_AL 0x400 +#define SR_GC 0x200 +#define SR_SAM 0x100 +#define SR_STOP 0x80 +#define SR_BERR 0x40 +#define SR_DR 0x20 /* received one new data byte */ +#define SR_DT 0x10 /* trandmitted one data byte */ +#define SR_BB 0x8 /* set when i2c bus is busy, but fti2c010 is not */ +#define SR_I2CB 0x4 /* set when fti2c010 is busy */ +#define SR_ACK 0x2 +#define SR_RW 0x1 + +#endif /* EOF */ -- 1.7.9.5 ********************* Confidentiality Notice ************************ This electronic message and any attachments may contain confidential and legally privileged information or information which is otherwise protected from disclosure. If you are not the intended recipient,please do not disclose the contents, either in whole or in part, to anyone,and immediately delete the message and any attachments from your computer system and destroy all hard copies. Thank you for your cooperation. ***********************************************************************