From cc20ffb01c0c1c973351b19dac70e87c9672f626 Mon Sep 17 00:00:00 2001 From: Tim 'mithro' Ansell Date: Tue, 21 Mar 2017 18:18:54 +1100 Subject: [PATCH] Kind of working litex_i2c --- hw/i2c/Makefile.objs | 3 +- hw/i2c/litex_i2c.c | 129 +++++++++++++++++++++++++++++++++++++++++++ hw/lm32/litex-hw.h | 40 ++++++++++++++ hw/lm32/litex.c | 2 + 4 files changed, 173 insertions(+), 1 deletion(-) create mode 100644 hw/i2c/litex_i2c.c diff --git a/hw/i2c/Makefile.objs b/hw/i2c/Makefile.objs index a081b8ef2c..d7c0296681 100644 --- a/hw/i2c/Makefile.objs +++ b/hw/i2c/Makefile.objs @@ -3,8 +3,9 @@ common-obj-$(CONFIG_DDC) += i2c-ddc.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-y += bitbang_i2c.o common-obj-$(CONFIG_EXYNOS4) += exynos4210_i2c.o common-obj-$(CONFIG_IMX_I2C) += imx_i2c.o common-obj-$(CONFIG_ASPEED_SOC) += aspeed_i2c.o +common-obj-y += litex_i2c.o obj-$(CONFIG_OMAP) += omap_i2c.o diff --git a/hw/i2c/litex_i2c.c b/hw/i2c/litex_i2c.c new file mode 100644 index 0000000000..3ba1624b29 --- /dev/null +++ b/hw/i2c/litex_i2c.c @@ -0,0 +1,129 @@ +/* + * LiteX Bit-Banging I2C controller + * + * Copyright (c) 2006-2007 CodeSourcery. + * Copyright (c) 2012 Oskar Andero + * + * 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 . + * + */ + +#include "qemu/osdep.h" +#include "hw/sysbus.h" +#include "bitbang_i2c.h" +#include "qemu/log.h" + +#define TYPE_LITEX_I2C "litex_i2c" +#define LITEX_I2C(obj) \ + OBJECT_CHECK(LiteXI2CState, (obj), TYPE_LITEX_I2C) + +enum { + R_OPSIS_I2C_MASTER_W, + R_OPSIS_I2C_MASTER_R, + R_MAX, +}; + +#define I2C_SCL 0x01 +#define I2C_SDAOE 0x02 +#define I2C_SDAOUT 0x04 + +#define I2C_SDAIN 0x01 + +typedef struct LiteXI2CState { + SysBusDevice parent_obj; + + MemoryRegion iomem; + bitbang_i2c_interface *bitbang; + uint32_t regs[R_MAX]; + +} LiteXI2CState; + +static uint64_t litex_i2c_read(void *opaque, hwaddr addr, unsigned size) +{ + LiteXI2CState *s = (LiteXI2CState *)opaque; + addr >>= 2; + if (addr >= R_MAX) { + printf("Tried to access invalid address %08x\n", (unsigned int)addr); + return 0; + } + + uint64_t r = s->regs[addr]; + return r; +} + +static void litex_i2c_write(void *opaque, hwaddr addr, uint64_t value, unsigned size) +{ + int scl, sda_oe, sda_out, sda_in; + LiteXI2CState *s = (LiteXI2CState *)opaque; + addr >>= 2; + + if (addr >= R_MAX) { + printf("Tried to access invalid address %08x\n", (unsigned int)addr); + return; + } + + s->regs[addr] = value & 0xff; + switch(addr) + { + case R_OPSIS_I2C_MASTER_W: + scl = (value & I2C_SCL) ? 1 : 0; + sda_oe = (s->regs[addr] & I2C_SDAOE) ? 1 : 0; + sda_out = (s->regs[addr] & I2C_SDAOUT) ? 1 : 0; + + bitbang_i2c_set(s->bitbang, BITBANG_I2C_SCL, scl); + sda_in = bitbang_i2c_set(s->bitbang, BITBANG_I2C_SDA, sda_oe ? sda_out : 1); + if (!sda_oe) { + s->regs[R_OPSIS_I2C_MASTER_R] = sda_in; // FIXME: Shift? + } + } +} + +static const MemoryRegionOps litex_i2c_ops = { + .read = litex_i2c_read, + .write = litex_i2c_write, + .valid = { + .min_access_size = 4, + .max_access_size = 4, + }, + .endianness = DEVICE_NATIVE_ENDIAN, +}; + +static void litex_i2c_init(Object *obj) +{ + DeviceState *dev = DEVICE(obj); + LiteXI2CState *s = LITEX_I2C(obj); + SysBusDevice *sbd = SYS_BUS_DEVICE(obj); + I2CBus *bus; + + bus = i2c_init_bus(dev, "i2c"); + s->bitbang = bitbang_i2c_init(bus); + memory_region_init_io(&s->iomem, OBJECT(dev), &litex_i2c_ops, s, "litex_i2c", R_MAX * 4); + sysbus_init_mmio(sbd, &s->iomem); +} + +static const TypeInfo litex_i2c_info = { + .name = TYPE_LITEX_I2C, + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(LiteXI2CState), + .instance_init = litex_i2c_init, +}; + +static void litex_i2c_register_types(void) +{ + type_register_static(&litex_i2c_info); +} + +type_init(litex_i2c_register_types) diff --git a/hw/lm32/litex-hw.h b/hw/lm32/litex-hw.h index bb920707fe..6975368fa0 100644 --- a/hw/lm32/litex-hw.h +++ b/hw/lm32/litex-hw.h @@ -1,6 +1,7 @@ #ifndef QEMU_HW_LITEX_HW_H #define QEMU_HW_LITEX_HW_H +#include "hw/i2c/smbus.h" #include "hw/qdev.h" #include "net/net.h" @@ -51,6 +52,45 @@ static inline DeviceState *litex_liteeth_create(hwaddr reg_base, hwaddr phy_bas return dev; } +uint8_t eeprom_contents[256] = { + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, + 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, + 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, + 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, + 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, + 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, + 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, + 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, + 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, + 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, + 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, + 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, + 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, + 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, + 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, + 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, + 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, + 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, + 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, + 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, + 200, 201, 202, 203, 204, 205, 206, 207, 208, 209, + 210, 211, 212, 213, 214, 215, 216, 217, 218, 219, + 220, 221, 222, 223, 224, 225, 226, 227, 228, 229, + 230, 231, 232, 233, 234, 235, 236, 237, 238, 239, + 240, 241, 242, 243, 244, 245, 246, 247, 248, 249, + 250, 251, 252, 253, 254, 255}; + +static inline DeviceState *litex_i2c_create(hwaddr reg_base) +{ + DeviceState *dev; + I2CBus *i2c; + + dev = sysbus_create_simple("litex_i2c", reg_base, NULL); + i2c = (I2CBus *)qdev_get_child_bus(dev, "i2c"); + + smbus_eeprom_init(i2c, 1, eeprom_contents, 256); + return dev; +} /* static inline DeviceState *litex_qspi_create(hwaddr base, qemu_irq qspi_irq) diff --git a/hw/lm32/litex.c b/hw/lm32/litex.c index 6f0ce044b7..44f6fb671c 100644 --- a/hw/lm32/litex.c +++ b/hw/lm32/litex.c @@ -164,6 +164,8 @@ litex_init(MachineState *machine) litex_liteeth_create(CSR_ETHMAC_BASE & 0x7FFFFFFF, CSR_ETHPHY_BASE & 0x7FFFFFFF, ETHMAC_BASE & 0x7FFFFFFF, irq[ETHMAC_INTERRUPT]); #endif + litex_i2c_create(CSR_OPSIS_I2C_BASE & 0x7FFFFFFF); + /* make sure juart isn't the first chardev */ env->juart_state = lm32_juart_init(serial_hds[1]);