* [Qemu-devel] Forward-porting RTC device for eppc500 ?
@ 2019-03-02 11:21 Andrew Randrianasulu
2019-03-02 16:59 ` [Qemu-devel] [Qemu-ppc] " BALATON Zoltan
[not found] ` <201903022144.45897.randrianasulu@gmail.com>
0 siblings, 2 replies; 5+ messages in thread
From: Andrew Randrianasulu @ 2019-03-02 11:21 UTC (permalink / raw)
To: Amit.Tomar, qemu-ppc@nongnu.org, qemu-devel
[-- Attachment #1: Type: text/plain, Size: 15391 bytes --]
Hello, all!
I stumbled upon this email from 2015 (trying to understand why my emulated
ppce500 machine failed to set clock correctly:
https://lists.gnu.org/archive/html/qemu-devel/2015-01/msg02642.html
Now, after some quite blind trial-and-error I applied ('forward-ported') this
patch to qemu git commit 0f6a6d5db853c0cbe438c1831c70710bfb6530ee without
actually porting it to new qemu device abstraction model.
It seems to work!
But because I copy-pasted patch from web archive of list - some strings
become "address@hidden", I hope I corrected them right?
---------------------------
diff --git a/default-configs/ppc-softmmu.mak b/default-configs/ppc-softmmu.mak
index 52acb7cf39..a560971f0c 100644
--- a/default-configs/ppc-softmmu.mak
+++ b/default-configs/ppc-softmmu.mak
@@ -8,6 +8,8 @@ include usb.mak
CONFIG_PPC4XX=y
CONFIG_M48T59=y
CONFIG_SERIAL=y
+CONFIG_MPC_I2C=y
+CONFIG_DS1338=y
CONFIG_I8257=y
CONFIG_OPENPIC=y
CONFIG_PPCE500_PCI=y
diff --git a/hw/i2c/Makefile.objs b/hw/i2c/Makefile.objs
index cecee486f7..55473fc6b2 100644
--- a/hw/i2c/Makefile.objs
+++ b/hw/i2c/Makefile.objs
@@ -9,5 +9,6 @@ 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-$(CONFIG_NRF51_SOC) += microbit_i2c.o
+common-obj-$(CONFIG_MPC_I2C) += mpc_i2c.o
obj-$(CONFIG_OMAP) += omap_i2c.o
obj-$(CONFIG_PPC4XX) += ppc4xx_i2c.o
diff --git a/hw/i2c/mpc_i2c.c b/hw/i2c/mpc_i2c.c
new file mode 100644
index 0000000000..54d7a9aabd
--- /dev/null
+++ b/hw/i2c/mpc_i2c.c
@@ -0,0 +1,360 @@
+/*
+ * Copyright (C) 2014 Freescale Semiconductor, Inc. All rights reserved.
+ *
+ * Author: Amit Tomar, <Amit.Tomar@freescale.com>
+ *
+ * Description:
+ * This file is derived from IMX I2C controller,
+ * by Jean-Christophe DUBOIS .
+ *
+ * Thanks to Scott Wood and Alexander Graf for their kind help on this.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License, version 2 or later,
+ * as published by the Free Software Foundation.
+ *
+ * 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/i2c/imx_i2c.h"
+#include "hw/i2c/i2c.h"
+#include "qemu/log.h"
+#include "hw/sysbus.h"
+
+/* #define DEBUG_I2C */
+
+#ifdef DEBUG_I2C
+#define DPRINTF(fmt, ...) \
+ do { fprintf(stderr, "mpc_i2c[%s]: " fmt, __func__, ## __VA_ARGS__); \
+ } while (0)
+#else
+#define DPRINTF(fmt, ...) do {} while (0)
+#endif
+
+#define TYPE_MPC_I2C "mpc-i2c"
+#define MPC_I2C(obj) \
+ OBJECT_CHECK(MPCI2CState, (obj), TYPE_MPC_I2C)
+
+#define MPC_I2C_ADR 0x00
+#define MPC_I2C_FDR 0x04
+#define MPC_I2C_CR 0x08
+#define MPC_I2C_SR 0x0c
+#define MPC_I2C_DR 0x10
+#define MPC_I2C_DFSRR 0x14
+
+#define CCR_MEN (1<<7)
+#define CCR_MIEN (1<<6)
+#define CCR_MSTA (1<<5)
+#define CCR_MTX (1<<4)
+#define CCR_TXAK (1<<3)
+#define CCR_RSTA (1<<2)
+#define CCR_BCST (1<<0)
+
+#define CSR_MCF (1<<7)
+#define CSR_MAAS (1<<6)
+#define CSR_MBB (1<<5)
+#define CSR_MAL (1<<4)
+#define CSR_SRW (1<<2)
+#define CSR_MIF (1<<1)
+#define CSR_RXAK (1<<0)
+
+#define CADR_MASK 0xFE
+#define CFDR_MASK 0x3F
+#define CCR_MASK 0xFC
+#define CSR_MASK 0xED
+#define CDR_MASK 0xFF
+
+#define CYCLE_RESET 0xFF
+
+typedef struct MPCI2CState {
+ SysBusDevice parent_obj;
+
+ I2CBus *bus;
+ qemu_irq irq;
+ MemoryRegion iomem;
+
+ uint8_t address;
+ uint8_t adr;
+ uint8_t fdr;
+ uint8_t cr;
+ uint8_t sr;
+ uint8_t dr;
+ uint8_t dfssr;
+} MPCI2CState;
+
+static bool mpc_i2c_is_enabled(MPCI2CState *s)
+{
+ return s->cr & CCR_MEN;
+}
+
+static bool mpc_i2c_is_master(MPCI2CState *s)
+{
+ return s->cr & CCR_MSTA;
+}
+
+static bool mpc_i2c_direction_is_tx(MPCI2CState *s)
+{
+ return s->cr & CCR_MTX;
+}
+
+static bool mpc_i2c_irq_pending(MPCI2CState *s)
+{
+ return s->sr & CSR_MIF;
+}
+
+static bool mpc_i2c_irq_is_enabled(MPCI2CState *s)
+{
+ return s->cr & CCR_MIEN;
+}
+
+static void mpc_i2c_reset(DeviceState *dev)
+{
+ MPCI2CState *i2c = MPC_I2C(dev);
+
+ i2c->address = 0xFF;
+ i2c->adr = 0x00;
+ i2c->fdr = 0x00;
+ i2c->cr = 0x00;
+ i2c->sr = 0x81;
+ i2c->dr = 0x00;
+}
+
+static void mpc_i2c_irq(MPCI2CState *s)
+{
+ bool irq_active = false;
+
+ if (mpc_i2c_is_enabled(s) && mpc_i2c_irq_is_enabled(s)
+ && mpc_i2c_irq_pending(s)) {
+ irq_active = true;
+ }
+
+ if (irq_active) {
+ qemu_irq_raise(s->irq);
+ } else {
+ qemu_irq_lower(s->irq);
+ }
+}
+
+static void mpc_i2c_soft_reset(MPCI2CState *s)
+{
+ /* This is a soft reset. ADR is preserved during soft resets */
+ uint8_t adr = s->adr;
+ mpc_i2c_reset(DEVICE(s));
+ s->adr = adr;
+}
+
+static void mpc_i2c_address_send(MPCI2CState *s)
+{
+ /* if returns non zero slave address is not right */
+ if (i2c_start_transfer(s->bus, s->dr >> 1, s->dr & (0x01))) {
+ s->sr |= CSR_RXAK;
+ } else {
+ s->address = s->dr;
+ s->sr &= ~CSR_RXAK;
+ s->sr |= CSR_MCF; /* Set after Byte Transfer is completed */
+ s->sr |= CSR_MIF; /* Set after Byte Transfer is completed */
+ mpc_i2c_irq(s);
+ }
+}
+
+static void mpc_i2c_data_send(MPCI2CState *s)
+{
+ if (i2c_send(s->bus, s->dr)) {
+ /* End of transfer */
+ s->sr |= CSR_RXAK;
+ i2c_end_transfer(s->bus);
+ } else {
+ s->sr &= ~CSR_RXAK;
+ s->sr |= CSR_MCF; /* Set after Byte Transfer is completed */
+ s->sr |= CSR_MIF; /* Set after Byte Transfer is completed */
+ mpc_i2c_irq(s);
+ }
+}
+
+static void mpc_i2c_data_recive(MPCI2CState *s)
+{
+ int ret;
+ /* get the next byte */
+ ret = i2c_recv(s->bus);
+ if (ret >= 0) {
+ s->sr |= CSR_MCF; /* Set after Byte Transfer is completed */
+ s->sr |= CSR_MIF; /* Set after Byte Transfer is completed */
+ mpc_i2c_irq(s);
+ } else {
+ DPRINTF("read failed for device");
+ ret = 0xff;
+ }
+ s->dr = ret;
+}
+
+static uint64_t mpc_i2c_read(void *opaque, hwaddr addr, unsigned size)
+{
+ MPCI2CState *s = opaque;
+ uint8_t value;
+
+ switch (addr) {
+ case MPC_I2C_ADR:
+ value = s->adr;
+ break;
+ case MPC_I2C_FDR:
+ value = s->fdr;
+ break;
+ case MPC_I2C_CR:
+ value = s->cr;
+ break;
+ case MPC_I2C_SR:
+ value = s->sr;
+ break;
+ case MPC_I2C_DR:
+ value = s->dr;
+ if (mpc_i2c_is_master(s)) { /* master mode */
+ if (mpc_i2c_direction_is_tx(s)) {
+ DPRINTF("MTX is set not in recv mode\n");
+ } else {
+ mpc_i2c_data_recive(s);
+ }
+ }
+ break;
+ default:
+ value = 0;
+ DPRINTF("ERROR: Bad read addr 0x%x\n", (unsigned int)addr);
+ break;
+ }
+
+ DPRINTF("%s: addr " TARGET_FMT_plx " %02" PRIx32 "\n", __func__,
+ addr, value);
+ return (uint64_t)value;
+}
+
+static void mpc_i2c_write(void *opaque, hwaddr addr,
+ uint64_t value, unsigned size)
+{
+ MPCI2CState *s = opaque;
+
+ DPRINTF("%s: addr " TARGET_FMT_plx " val %08" PRIx64 "\n", __func__,
+ addr, value);
+ switch (addr) {
+ case MPC_I2C_ADR:
+ s->adr = value & CADR_MASK;
+ break;
+ case MPC_I2C_FDR:
+ s->fdr = value & CFDR_MASK;
+ break;
+ case MPC_I2C_CR:
+ if (mpc_i2c_is_enabled(s) && ((value & CCR_MEN) == 0)) {
+ mpc_i2c_soft_reset(s);
+ break;
+ }
+ /* normal write */
+ s->cr = value & CCR_MASK;
+ if (mpc_i2c_is_master(s)) { /* master mode */
+ /* set the bus to busy after master is set as per RM */
+ s->sr |= CSR_MBB;
+ } else {
+ /* bus is not busy anymore */
+ s->sr &= ~CSR_MBB;
+ /* Reset the address for fresh write/read cycle */
+ if (s->address != CYCLE_RESET) {
+ i2c_end_transfer(s->bus);
+ s->address = CYCLE_RESET;
+ }
+ }
+ /* For restart end the onging transfer */
+ if (s->cr & CCR_RSTA) {
+ if (s->address != CYCLE_RESET) {
+ s->address = CYCLE_RESET;
+ i2c_end_transfer(s->bus);
+ s->cr &= ~CCR_RSTA;
+ }
+ }
+ break;
+ case MPC_I2C_SR:
+ s->sr = value & CSR_MASK;
+ /* Lower the interrupt */
+ if (!(s->sr & CSR_MIF) || !(s->sr & CSR_MAL)) {
+ mpc_i2c_irq(s);
+ }
+ break;
+ case MPC_I2C_DR:
+ /* if the device is not enabled, nothing to do */
+ if (!mpc_i2c_is_enabled(s)) {
+ break;
+ }
+ s->dr = value & CDR_MASK;
+ if (mpc_i2c_is_master(s)) { /* master mode */
+ if (s->address == CYCLE_RESET) {
+ mpc_i2c_address_send(s);
+ } else {
+ mpc_i2c_data_send(s);
+ }
+ }
+ break;
+ case MPC_I2C_DFSRR:
+ s->dfssr = value;
+ break;
+ default:
+ DPRINTF("ERROR: Bad write addr 0x%x\n", (unsigned int)addr);
+ break;
+ }
+}
+
+static const MemoryRegionOps i2c_ops = {
+ .read = mpc_i2c_read,
+ .write = mpc_i2c_write,
+ .valid.max_access_size = 1,
+ .endianness = DEVICE_NATIVE_ENDIAN,
+};
+
+static const VMStateDescription mpc_i2c_vmstate = {
+ .name = TYPE_MPC_I2C,
+ .version_id = 1,
+ .minimum_version_id = 1,
+ .fields = (VMStateField[]) {
+ VMSTATE_UINT8(address, MPCI2CState),
+ VMSTATE_UINT8(adr, MPCI2CState),
+ VMSTATE_UINT8(fdr, MPCI2CState),
+ VMSTATE_UINT8(cr, MPCI2CState),
+ VMSTATE_UINT8(sr, MPCI2CState),
+ VMSTATE_UINT8(dr, MPCI2CState),
+ VMSTATE_UINT8(dfssr, MPCI2CState),
+ VMSTATE_END_OF_LIST()
+ }
+};
+
+static void mpc_i2c_realize(DeviceState *dev, Error **errp)
+{
+
+ MPCI2CState *i2c = MPC_I2C(dev);
+
+ sysbus_init_irq(SYS_BUS_DEVICE(dev), &i2c->irq);
+ memory_region_init_io(&i2c->iomem, OBJECT(i2c), &i2c_ops, i2c,
+ "mpc-i2c", 0x14);
+ sysbus_init_mmio(SYS_BUS_DEVICE(dev), &i2c->iomem);
+ i2c->bus = i2c_init_bus(DEVICE(dev), "i2c");
+}
+
+static void mpc_i2c_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+
+ dc->vmsd = &mpc_i2c_vmstate ;
+ dc->reset = mpc_i2c_reset;
+ dc->realize = mpc_i2c_realize;
+ dc->desc = "MPC I2C Controller";
+}
+
+static const TypeInfo mpc_i2c_type_info = {
+ .name = TYPE_MPC_I2C,
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(MPCI2CState),
+ .class_init = mpc_i2c_class_init,
+};
+
+static void mpc_i2c_register_types(void)
+{
+ type_register_static(&mpc_i2c_type_info);
+}
+
+type_init(mpc_i2c_register_types)
diff --git a/hw/ppc/e500.c b/hw/ppc/e500.c
index 7553f674c9..c8e8563f95 100644
--- a/hw/ppc/e500.c
+++ b/hw/ppc/e500.c
@@ -42,6 +42,7 @@
#include "qemu/error-report.h"
#include "hw/platform-bus.h"
#include "hw/net/fsl_etsec/etsec.h"
+#include "hw/i2c/i2c.h"
#define EPAPR_MAGIC (0x45504150)
#define BINARY_DEVICE_TREE_FILE "mpc8544ds.dtb"
@@ -63,7 +64,10 @@
#define MPC8544_PCI_REGS_SIZE 0x1000ULL
#define MPC8544_UTIL_OFFSET 0xe0000ULL
#define MPC8XXX_GPIO_OFFSET 0x000FF000ULL
+#define MPC8544_I2C_REGS_OFFSET 0x3000ULL
#define MPC8XXX_GPIO_IRQ 47
+#define MPC8544_I2C_IRQ 43
+#define RTC_REGS_OFFSET 0x68
struct boot_info
{
@@ -161,6 +165,39 @@ static void create_dt_mpc8xxx_gpio(void *fdt, const char
*soc, const char *mpic)
g_free(poweroff);
}
+static void dt_rtc_create(void *fdt, const char *i2c, const char *alias)
+{
+ int offset = RTC_REGS_OFFSET;
+
+ gchar *rtc = g_strdup_printf("%s/rtc@%"PRIx32, i2c, offset);
+ qemu_fdt_add_subnode(fdt, rtc);
+ qemu_fdt_setprop_string(fdt, rtc, "compatible", "pericom,pt7c4338");
+ qemu_fdt_setprop_cells(fdt, rtc, "reg", offset);
+ qemu_fdt_setprop_string(fdt, "/aliases", alias, rtc);
+
+ g_free(rtc);
+}
+
+static void dt_i2c_create(void *fdt, const char *soc, const char *mpic,
+ const char *alias)
+{
+ hwaddr mmio0 = MPC8544_I2C_REGS_OFFSET;
+ int irq0 = MPC8544_I2C_IRQ;
+
+ gchar *i2c = g_strdup_printf("%s/i2c@%"PRIx64, soc, mmio0);
+ qemu_fdt_add_subnode(fdt, i2c);
+ qemu_fdt_setprop_string(fdt, i2c, "device_type", "i2c");
+ qemu_fdt_setprop_string(fdt, i2c, "compatible", "fsl-i2c");
+ qemu_fdt_setprop_cells(fdt, i2c, "reg", mmio0, 0x14);
+ qemu_fdt_setprop_cells(fdt, i2c, "cell-index", 0);
+ qemu_fdt_setprop_cells(fdt, i2c, "interrupts", irq0, 0x2);
+ qemu_fdt_setprop_phandle(fdt, i2c, "interrupt-parent", mpic);
+ qemu_fdt_setprop_string(fdt, "/aliases", alias, i2c);
+
+ g_free(i2c);
+}
+
+
typedef struct PlatformDevtreeData {
void *fdt;
const char *mpic;
@@ -463,6 +500,12 @@ static int ppce500_load_device_tree(PPCE500MachineState
*pms,
dt_serial_create(fdt, MPC8544_SERIAL0_REGS_OFFSET,
soc, mpic, "serial0", 0, true);
}
+
+ /* i2c */
+ dt_i2c_create(fdt, soc, mpic, "i2c");
+
+ dt_rtc_create(fdt, "i2c", "rtc");
+
gutil = g_strdup_printf("%s/global-utilities@%llx", soc,
MPC8544_UTIL_OFFSET);
@@ -812,6 +855,7 @@ void ppce500_init(MachineState *machine)
MemoryRegion *ccsr_addr_space;
SysBusDevice *s;
PPCE500CCSRState *ccsr;
+ I2CBus *i2c;
irqs = g_new0(IrqLines, smp_cpus);
for (i = 0; i < smp_cpus; i++) {
@@ -887,6 +931,16 @@ void ppce500_init(MachineState *machine)
0, qdev_get_gpio_in(mpicdev, 42), 399193,
serial_hd(1), DEVICE_BIG_ENDIAN);
}
+ /* I2C */
+ dev = qdev_create(NULL, "mpc-i2c");
+ s = SYS_BUS_DEVICE(dev);
+ qdev_init_nofail(dev);
+ sysbus_connect_irq(s, 0, qdev_get_gpio_in(mpicdev, MPC8544_I2C_IRQ));
+ memory_region_add_subregion(ccsr_addr_space, MPC8544_I2C_REGS_OFFSET,
+ sysbus_mmio_get_region(s, 0));
+ i2c = (I2CBus *)qdev_get_child_bus(dev, "i2c");
+ i2c_create_slave(i2c, "ds1338", RTC_REGS_OFFSET);
+
/* General Utility device */
dev = qdev_create(NULL, "mpc8544-guts");
----------------
Test kernel I used:
http://www.xenosoft.de/linux-image-4.20.12-X1000_X5000.tar.gz
(unpack and use uImage)
guest@slax:/dev/shm/qemu$ ppc64-softmmu/qemu-system-ppc64 -M ppce500 -cpu
e5500 -kernel /mnt/sdb1/PPC-img/linux-image-4.20.12-X1000_X5000/X5000_and_QEMU_e5500/uImage-4.20 -nographic
also, I think I found reason why some of my tests resulted in blue or green-ish
image: -sdl,gl=on was causing troubles sometimes. It was ok with stdvga , but
not for virtio-gpu.
At least in linux virtio-gpu driver disables "3d" (virgl) part of itself on BE
machine. Guess sdl2 video output in qemu has no idea about guest's action, so
it acts wrongly with BE guests and gives intensively blue console with
offb-enabled LE guest. (on ppc64 machine).
[-- Attachment #2: Freescale_i2c_patch-real.diff --]
[-- Type: text/x-diff, Size: 14027 bytes --]
diff --git a/default-configs/ppc-softmmu.mak b/default-configs/ppc-softmmu.mak
index 52acb7cf39..a560971f0c 100644
--- a/default-configs/ppc-softmmu.mak
+++ b/default-configs/ppc-softmmu.mak
@@ -8,6 +8,8 @@ include usb.mak
CONFIG_PPC4XX=y
CONFIG_M48T59=y
CONFIG_SERIAL=y
+CONFIG_MPC_I2C=y
+CONFIG_DS1338=y
CONFIG_I8257=y
CONFIG_OPENPIC=y
CONFIG_PPCE500_PCI=y
diff --git a/hw/i2c/Makefile.objs b/hw/i2c/Makefile.objs
index cecee486f7..55473fc6b2 100644
--- a/hw/i2c/Makefile.objs
+++ b/hw/i2c/Makefile.objs
@@ -9,5 +9,6 @@ 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-$(CONFIG_NRF51_SOC) += microbit_i2c.o
+common-obj-$(CONFIG_MPC_I2C) += mpc_i2c.o
obj-$(CONFIG_OMAP) += omap_i2c.o
obj-$(CONFIG_PPC4XX) += ppc4xx_i2c.o
diff --git a/hw/i2c/mpc_i2c.c b/hw/i2c/mpc_i2c.c
new file mode 100644
index 0000000000..54d7a9aabd
--- /dev/null
+++ b/hw/i2c/mpc_i2c.c
@@ -0,0 +1,360 @@
+/*
+ * Copyright (C) 2014 Freescale Semiconductor, Inc. All rights reserved.
+ *
+ * Author: Amit Tomar, <Amit.Tomar@freescale.com>
+ *
+ * Description:
+ * This file is derived from IMX I2C controller,
+ * by Jean-Christophe DUBOIS .
+ *
+ * Thanks to Scott Wood and Alexander Graf for their kind help on this.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License, version 2 or later,
+ * as published by the Free Software Foundation.
+ *
+ * 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/i2c/imx_i2c.h"
+#include "hw/i2c/i2c.h"
+#include "qemu/log.h"
+#include "hw/sysbus.h"
+
+/* #define DEBUG_I2C */
+
+#ifdef DEBUG_I2C
+#define DPRINTF(fmt, ...) \
+ do { fprintf(stderr, "mpc_i2c[%s]: " fmt, __func__, ## __VA_ARGS__); \
+ } while (0)
+#else
+#define DPRINTF(fmt, ...) do {} while (0)
+#endif
+
+#define TYPE_MPC_I2C "mpc-i2c"
+#define MPC_I2C(obj) \
+ OBJECT_CHECK(MPCI2CState, (obj), TYPE_MPC_I2C)
+
+#define MPC_I2C_ADR 0x00
+#define MPC_I2C_FDR 0x04
+#define MPC_I2C_CR 0x08
+#define MPC_I2C_SR 0x0c
+#define MPC_I2C_DR 0x10
+#define MPC_I2C_DFSRR 0x14
+
+#define CCR_MEN (1<<7)
+#define CCR_MIEN (1<<6)
+#define CCR_MSTA (1<<5)
+#define CCR_MTX (1<<4)
+#define CCR_TXAK (1<<3)
+#define CCR_RSTA (1<<2)
+#define CCR_BCST (1<<0)
+
+#define CSR_MCF (1<<7)
+#define CSR_MAAS (1<<6)
+#define CSR_MBB (1<<5)
+#define CSR_MAL (1<<4)
+#define CSR_SRW (1<<2)
+#define CSR_MIF (1<<1)
+#define CSR_RXAK (1<<0)
+
+#define CADR_MASK 0xFE
+#define CFDR_MASK 0x3F
+#define CCR_MASK 0xFC
+#define CSR_MASK 0xED
+#define CDR_MASK 0xFF
+
+#define CYCLE_RESET 0xFF
+
+typedef struct MPCI2CState {
+ SysBusDevice parent_obj;
+
+ I2CBus *bus;
+ qemu_irq irq;
+ MemoryRegion iomem;
+
+ uint8_t address;
+ uint8_t adr;
+ uint8_t fdr;
+ uint8_t cr;
+ uint8_t sr;
+ uint8_t dr;
+ uint8_t dfssr;
+} MPCI2CState;
+
+static bool mpc_i2c_is_enabled(MPCI2CState *s)
+{
+ return s->cr & CCR_MEN;
+}
+
+static bool mpc_i2c_is_master(MPCI2CState *s)
+{
+ return s->cr & CCR_MSTA;
+}
+
+static bool mpc_i2c_direction_is_tx(MPCI2CState *s)
+{
+ return s->cr & CCR_MTX;
+}
+
+static bool mpc_i2c_irq_pending(MPCI2CState *s)
+{
+ return s->sr & CSR_MIF;
+}
+
+static bool mpc_i2c_irq_is_enabled(MPCI2CState *s)
+{
+ return s->cr & CCR_MIEN;
+}
+
+static void mpc_i2c_reset(DeviceState *dev)
+{
+ MPCI2CState *i2c = MPC_I2C(dev);
+
+ i2c->address = 0xFF;
+ i2c->adr = 0x00;
+ i2c->fdr = 0x00;
+ i2c->cr = 0x00;
+ i2c->sr = 0x81;
+ i2c->dr = 0x00;
+}
+
+static void mpc_i2c_irq(MPCI2CState *s)
+{
+ bool irq_active = false;
+
+ if (mpc_i2c_is_enabled(s) && mpc_i2c_irq_is_enabled(s)
+ && mpc_i2c_irq_pending(s)) {
+ irq_active = true;
+ }
+
+ if (irq_active) {
+ qemu_irq_raise(s->irq);
+ } else {
+ qemu_irq_lower(s->irq);
+ }
+}
+
+static void mpc_i2c_soft_reset(MPCI2CState *s)
+{
+ /* This is a soft reset. ADR is preserved during soft resets */
+ uint8_t adr = s->adr;
+ mpc_i2c_reset(DEVICE(s));
+ s->adr = adr;
+}
+
+static void mpc_i2c_address_send(MPCI2CState *s)
+{
+ /* if returns non zero slave address is not right */
+ if (i2c_start_transfer(s->bus, s->dr >> 1, s->dr & (0x01))) {
+ s->sr |= CSR_RXAK;
+ } else {
+ s->address = s->dr;
+ s->sr &= ~CSR_RXAK;
+ s->sr |= CSR_MCF; /* Set after Byte Transfer is completed */
+ s->sr |= CSR_MIF; /* Set after Byte Transfer is completed */
+ mpc_i2c_irq(s);
+ }
+}
+
+static void mpc_i2c_data_send(MPCI2CState *s)
+{
+ if (i2c_send(s->bus, s->dr)) {
+ /* End of transfer */
+ s->sr |= CSR_RXAK;
+ i2c_end_transfer(s->bus);
+ } else {
+ s->sr &= ~CSR_RXAK;
+ s->sr |= CSR_MCF; /* Set after Byte Transfer is completed */
+ s->sr |= CSR_MIF; /* Set after Byte Transfer is completed */
+ mpc_i2c_irq(s);
+ }
+}
+
+static void mpc_i2c_data_recive(MPCI2CState *s)
+{
+ int ret;
+ /* get the next byte */
+ ret = i2c_recv(s->bus);
+ if (ret >= 0) {
+ s->sr |= CSR_MCF; /* Set after Byte Transfer is completed */
+ s->sr |= CSR_MIF; /* Set after Byte Transfer is completed */
+ mpc_i2c_irq(s);
+ } else {
+ DPRINTF("read failed for device");
+ ret = 0xff;
+ }
+ s->dr = ret;
+}
+
+static uint64_t mpc_i2c_read(void *opaque, hwaddr addr, unsigned size)
+{
+ MPCI2CState *s = opaque;
+ uint8_t value;
+
+ switch (addr) {
+ case MPC_I2C_ADR:
+ value = s->adr;
+ break;
+ case MPC_I2C_FDR:
+ value = s->fdr;
+ break;
+ case MPC_I2C_CR:
+ value = s->cr;
+ break;
+ case MPC_I2C_SR:
+ value = s->sr;
+ break;
+ case MPC_I2C_DR:
+ value = s->dr;
+ if (mpc_i2c_is_master(s)) { /* master mode */
+ if (mpc_i2c_direction_is_tx(s)) {
+ DPRINTF("MTX is set not in recv mode\n");
+ } else {
+ mpc_i2c_data_recive(s);
+ }
+ }
+ break;
+ default:
+ value = 0;
+ DPRINTF("ERROR: Bad read addr 0x%x\n", (unsigned int)addr);
+ break;
+ }
+
+ DPRINTF("%s: addr " TARGET_FMT_plx " %02" PRIx32 "\n", __func__,
+ addr, value);
+ return (uint64_t)value;
+}
+
+static void mpc_i2c_write(void *opaque, hwaddr addr,
+ uint64_t value, unsigned size)
+{
+ MPCI2CState *s = opaque;
+
+ DPRINTF("%s: addr " TARGET_FMT_plx " val %08" PRIx64 "\n", __func__,
+ addr, value);
+ switch (addr) {
+ case MPC_I2C_ADR:
+ s->adr = value & CADR_MASK;
+ break;
+ case MPC_I2C_FDR:
+ s->fdr = value & CFDR_MASK;
+ break;
+ case MPC_I2C_CR:
+ if (mpc_i2c_is_enabled(s) && ((value & CCR_MEN) == 0)) {
+ mpc_i2c_soft_reset(s);
+ break;
+ }
+ /* normal write */
+ s->cr = value & CCR_MASK;
+ if (mpc_i2c_is_master(s)) { /* master mode */
+ /* set the bus to busy after master is set as per RM */
+ s->sr |= CSR_MBB;
+ } else {
+ /* bus is not busy anymore */
+ s->sr &= ~CSR_MBB;
+ /* Reset the address for fresh write/read cycle */
+ if (s->address != CYCLE_RESET) {
+ i2c_end_transfer(s->bus);
+ s->address = CYCLE_RESET;
+ }
+ }
+ /* For restart end the onging transfer */
+ if (s->cr & CCR_RSTA) {
+ if (s->address != CYCLE_RESET) {
+ s->address = CYCLE_RESET;
+ i2c_end_transfer(s->bus);
+ s->cr &= ~CCR_RSTA;
+ }
+ }
+ break;
+ case MPC_I2C_SR:
+ s->sr = value & CSR_MASK;
+ /* Lower the interrupt */
+ if (!(s->sr & CSR_MIF) || !(s->sr & CSR_MAL)) {
+ mpc_i2c_irq(s);
+ }
+ break;
+ case MPC_I2C_DR:
+ /* if the device is not enabled, nothing to do */
+ if (!mpc_i2c_is_enabled(s)) {
+ break;
+ }
+ s->dr = value & CDR_MASK;
+ if (mpc_i2c_is_master(s)) { /* master mode */
+ if (s->address == CYCLE_RESET) {
+ mpc_i2c_address_send(s);
+ } else {
+ mpc_i2c_data_send(s);
+ }
+ }
+ break;
+ case MPC_I2C_DFSRR:
+ s->dfssr = value;
+ break;
+ default:
+ DPRINTF("ERROR: Bad write addr 0x%x\n", (unsigned int)addr);
+ break;
+ }
+}
+
+static const MemoryRegionOps i2c_ops = {
+ .read = mpc_i2c_read,
+ .write = mpc_i2c_write,
+ .valid.max_access_size = 1,
+ .endianness = DEVICE_NATIVE_ENDIAN,
+};
+
+static const VMStateDescription mpc_i2c_vmstate = {
+ .name = TYPE_MPC_I2C,
+ .version_id = 1,
+ .minimum_version_id = 1,
+ .fields = (VMStateField[]) {
+ VMSTATE_UINT8(address, MPCI2CState),
+ VMSTATE_UINT8(adr, MPCI2CState),
+ VMSTATE_UINT8(fdr, MPCI2CState),
+ VMSTATE_UINT8(cr, MPCI2CState),
+ VMSTATE_UINT8(sr, MPCI2CState),
+ VMSTATE_UINT8(dr, MPCI2CState),
+ VMSTATE_UINT8(dfssr, MPCI2CState),
+ VMSTATE_END_OF_LIST()
+ }
+};
+
+static void mpc_i2c_realize(DeviceState *dev, Error **errp)
+{
+
+ MPCI2CState *i2c = MPC_I2C(dev);
+
+ sysbus_init_irq(SYS_BUS_DEVICE(dev), &i2c->irq);
+ memory_region_init_io(&i2c->iomem, OBJECT(i2c), &i2c_ops, i2c,
+ "mpc-i2c", 0x14);
+ sysbus_init_mmio(SYS_BUS_DEVICE(dev), &i2c->iomem);
+ i2c->bus = i2c_init_bus(DEVICE(dev), "i2c");
+}
+
+static void mpc_i2c_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+
+ dc->vmsd = &mpc_i2c_vmstate ;
+ dc->reset = mpc_i2c_reset;
+ dc->realize = mpc_i2c_realize;
+ dc->desc = "MPC I2C Controller";
+}
+
+static const TypeInfo mpc_i2c_type_info = {
+ .name = TYPE_MPC_I2C,
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(MPCI2CState),
+ .class_init = mpc_i2c_class_init,
+};
+
+static void mpc_i2c_register_types(void)
+{
+ type_register_static(&mpc_i2c_type_info);
+}
+
+type_init(mpc_i2c_register_types)
diff --git a/hw/ppc/e500.c b/hw/ppc/e500.c
index 7553f674c9..c8e8563f95 100644
--- a/hw/ppc/e500.c
+++ b/hw/ppc/e500.c
@@ -42,6 +42,7 @@
#include "qemu/error-report.h"
#include "hw/platform-bus.h"
#include "hw/net/fsl_etsec/etsec.h"
+#include "hw/i2c/i2c.h"
#define EPAPR_MAGIC (0x45504150)
#define BINARY_DEVICE_TREE_FILE "mpc8544ds.dtb"
@@ -63,7 +64,10 @@
#define MPC8544_PCI_REGS_SIZE 0x1000ULL
#define MPC8544_UTIL_OFFSET 0xe0000ULL
#define MPC8XXX_GPIO_OFFSET 0x000FF000ULL
+#define MPC8544_I2C_REGS_OFFSET 0x3000ULL
#define MPC8XXX_GPIO_IRQ 47
+#define MPC8544_I2C_IRQ 43
+#define RTC_REGS_OFFSET 0x68
struct boot_info
{
@@ -161,6 +165,39 @@ static void create_dt_mpc8xxx_gpio(void *fdt, const char *soc, const char *mpic)
g_free(poweroff);
}
+static void dt_rtc_create(void *fdt, const char *i2c, const char *alias)
+{
+ int offset = RTC_REGS_OFFSET;
+
+ gchar *rtc = g_strdup_printf("%s/rtc@%"PRIx32, i2c, offset);
+ qemu_fdt_add_subnode(fdt, rtc);
+ qemu_fdt_setprop_string(fdt, rtc, "compatible", "pericom,pt7c4338");
+ qemu_fdt_setprop_cells(fdt, rtc, "reg", offset);
+ qemu_fdt_setprop_string(fdt, "/aliases", alias, rtc);
+
+ g_free(rtc);
+}
+
+static void dt_i2c_create(void *fdt, const char *soc, const char *mpic,
+ const char *alias)
+{
+ hwaddr mmio0 = MPC8544_I2C_REGS_OFFSET;
+ int irq0 = MPC8544_I2C_IRQ;
+
+ gchar *i2c = g_strdup_printf("%s/i2c@%"PRIx64, soc, mmio0);
+ qemu_fdt_add_subnode(fdt, i2c);
+ qemu_fdt_setprop_string(fdt, i2c, "device_type", "i2c");
+ qemu_fdt_setprop_string(fdt, i2c, "compatible", "fsl-i2c");
+ qemu_fdt_setprop_cells(fdt, i2c, "reg", mmio0, 0x14);
+ qemu_fdt_setprop_cells(fdt, i2c, "cell-index", 0);
+ qemu_fdt_setprop_cells(fdt, i2c, "interrupts", irq0, 0x2);
+ qemu_fdt_setprop_phandle(fdt, i2c, "interrupt-parent", mpic);
+ qemu_fdt_setprop_string(fdt, "/aliases", alias, i2c);
+
+ g_free(i2c);
+}
+
+
typedef struct PlatformDevtreeData {
void *fdt;
const char *mpic;
@@ -463,6 +500,12 @@ static int ppce500_load_device_tree(PPCE500MachineState *pms,
dt_serial_create(fdt, MPC8544_SERIAL0_REGS_OFFSET,
soc, mpic, "serial0", 0, true);
}
+
+ /* i2c */
+ dt_i2c_create(fdt, soc, mpic, "i2c");
+
+ dt_rtc_create(fdt, "i2c", "rtc");
+
gutil = g_strdup_printf("%s/global-utilities@%llx", soc,
MPC8544_UTIL_OFFSET);
@@ -812,6 +855,7 @@ void ppce500_init(MachineState *machine)
MemoryRegion *ccsr_addr_space;
SysBusDevice *s;
PPCE500CCSRState *ccsr;
+ I2CBus *i2c;
irqs = g_new0(IrqLines, smp_cpus);
for (i = 0; i < smp_cpus; i++) {
@@ -887,6 +931,16 @@ void ppce500_init(MachineState *machine)
0, qdev_get_gpio_in(mpicdev, 42), 399193,
serial_hd(1), DEVICE_BIG_ENDIAN);
}
+ /* I2C */
+ dev = qdev_create(NULL, "mpc-i2c");
+ s = SYS_BUS_DEVICE(dev);
+ qdev_init_nofail(dev);
+ sysbus_connect_irq(s, 0, qdev_get_gpio_in(mpicdev, MPC8544_I2C_IRQ));
+ memory_region_add_subregion(ccsr_addr_space, MPC8544_I2C_REGS_OFFSET,
+ sysbus_mmio_get_region(s, 0));
+ i2c = (I2CBus *)qdev_get_child_bus(dev, "i2c");
+ i2c_create_slave(i2c, "ds1338", RTC_REGS_OFFSET);
+
/* General Utility device */
dev = qdev_create(NULL, "mpc8544-guts");
^ permalink raw reply related [flat|nested] 5+ messages in thread
* Re: [Qemu-devel] [Qemu-ppc] Forward-porting RTC device for eppc500 ?
2019-03-02 11:21 [Qemu-devel] Forward-porting RTC device for eppc500 ? Andrew Randrianasulu
@ 2019-03-02 16:59 ` BALATON Zoltan
[not found] ` <201903022144.45897.randrianasulu@gmail.com>
1 sibling, 0 replies; 5+ messages in thread
From: BALATON Zoltan @ 2019-03-02 16:59 UTC (permalink / raw)
To: Andrew Randrianasulu
Cc: Amit.Tomar, qemu-ppc@nongnu.org, qemu-devel, David Gibson
Hello,
On Sat, 2 Mar 2019, Andrew Randrianasulu wrote:
> Hello, all!
>
> I stumbled upon this email from 2015 (trying to understand why my emulated
> ppce500 machine failed to set clock correctly:
>
> https://lists.gnu.org/archive/html/qemu-devel/2015-01/msg02642.html
>
> Now, after some quite blind trial-and-error I applied ('forward-ported') this
> patch to qemu git commit 0f6a6d5db853c0cbe438c1831c70710bfb6530ee without
> actually porting it to new qemu device abstraction model.
>
> It seems to work!
>
> But because I copy-pasted patch from web archive of list - some strings
> become "address@hidden", I hope I corrected them right?
You can get all patches submitted to the list from patchew, the original
of this one is here:
http://patchwork.ozlabs.org/patch/431475/
The mbox format patch for git am is at the mbox link:
http://patchwork.ozlabs.org/patch/431475/mbox/
I think you could try to apply that patch with git am, fix any conflicts
due to changes in QEMU since the original patch to get an updated commit,
then use git format-patch to get a current patch you can submit to the
list for inclusion. The detailed description of how to send a patch is
here: https://wiki.qemu.org/Contribute/SubmitAPatch
Basically you should make sure you have an email that can be applied with
git am as that's what maintainers do. It should also have your
Signed-off-by if you made any changes to the patch after the original
Signed-off-by of the original author (you can add it e.g. with git commit
-s or git format-patch -s). Check the patch with scripts/checkpatch.pl
before sending and fix all errors and cc maintainers that you can get with
scripts/get_maintainer.pl. For PPC related stuff you should usually cc
qemu-ppc@nongnu.org and David Gibson besides sending to
qemu-devel@nongnu.org to make sure it's not lost.
I don't have any comments to the patch, some more comments below the other
topic at the end.
>
> ---------------------------
> diff --git a/default-configs/ppc-softmmu.mak b/default-configs/ppc-softmmu.mak
> index 52acb7cf39..a560971f0c 100644
> --- a/default-configs/ppc-softmmu.mak
> +++ b/default-configs/ppc-softmmu.mak
> @@ -8,6 +8,8 @@ include usb.mak
> CONFIG_PPC4XX=y
> CONFIG_M48T59=y
> CONFIG_SERIAL=y
> +CONFIG_MPC_I2C=y
> +CONFIG_DS1338=y
> CONFIG_I8257=y
> CONFIG_OPENPIC=y
> CONFIG_PPCE500_PCI=y
> diff --git a/hw/i2c/Makefile.objs b/hw/i2c/Makefile.objs
> index cecee486f7..55473fc6b2 100644
> --- a/hw/i2c/Makefile.objs
> +++ b/hw/i2c/Makefile.objs
> @@ -9,5 +9,6 @@ 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-$(CONFIG_NRF51_SOC) += microbit_i2c.o
> +common-obj-$(CONFIG_MPC_I2C) += mpc_i2c.o
> obj-$(CONFIG_OMAP) += omap_i2c.o
> obj-$(CONFIG_PPC4XX) += ppc4xx_i2c.o
> diff --git a/hw/i2c/mpc_i2c.c b/hw/i2c/mpc_i2c.c
> new file mode 100644
> index 0000000000..54d7a9aabd
> --- /dev/null
> +++ b/hw/i2c/mpc_i2c.c
> @@ -0,0 +1,360 @@
> +/*
> + * Copyright (C) 2014 Freescale Semiconductor, Inc. All rights reserved.
> + *
> + * Author: Amit Tomar, <Amit.Tomar@freescale.com>
> + *
> + * Description:
> + * This file is derived from IMX I2C controller,
> + * by Jean-Christophe DUBOIS .
> + *
> + * Thanks to Scott Wood and Alexander Graf for their kind help on this.
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License, version 2 or later,
> + * as published by the Free Software Foundation.
> + *
> + * 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/i2c/imx_i2c.h"
> +#include "hw/i2c/i2c.h"
> +#include "qemu/log.h"
> +#include "hw/sysbus.h"
> +
> +/* #define DEBUG_I2C */
> +
> +#ifdef DEBUG_I2C
> +#define DPRINTF(fmt, ...) \
> + do { fprintf(stderr, "mpc_i2c[%s]: " fmt, __func__, ## __VA_ARGS__); \
> + } while (0)
> +#else
> +#define DPRINTF(fmt, ...) do {} while (0)
> +#endif
> +
> +#define TYPE_MPC_I2C "mpc-i2c"
> +#define MPC_I2C(obj) \
> + OBJECT_CHECK(MPCI2CState, (obj), TYPE_MPC_I2C)
> +
> +#define MPC_I2C_ADR 0x00
> +#define MPC_I2C_FDR 0x04
> +#define MPC_I2C_CR 0x08
> +#define MPC_I2C_SR 0x0c
> +#define MPC_I2C_DR 0x10
> +#define MPC_I2C_DFSRR 0x14
> +
> +#define CCR_MEN (1<<7)
> +#define CCR_MIEN (1<<6)
> +#define CCR_MSTA (1<<5)
> +#define CCR_MTX (1<<4)
> +#define CCR_TXAK (1<<3)
> +#define CCR_RSTA (1<<2)
> +#define CCR_BCST (1<<0)
> +
> +#define CSR_MCF (1<<7)
> +#define CSR_MAAS (1<<6)
> +#define CSR_MBB (1<<5)
> +#define CSR_MAL (1<<4)
> +#define CSR_SRW (1<<2)
> +#define CSR_MIF (1<<1)
> +#define CSR_RXAK (1<<0)
> +
> +#define CADR_MASK 0xFE
> +#define CFDR_MASK 0x3F
> +#define CCR_MASK 0xFC
> +#define CSR_MASK 0xED
> +#define CDR_MASK 0xFF
> +
> +#define CYCLE_RESET 0xFF
> +
> +typedef struct MPCI2CState {
> + SysBusDevice parent_obj;
> +
> + I2CBus *bus;
> + qemu_irq irq;
> + MemoryRegion iomem;
> +
> + uint8_t address;
> + uint8_t adr;
> + uint8_t fdr;
> + uint8_t cr;
> + uint8_t sr;
> + uint8_t dr;
> + uint8_t dfssr;
> +} MPCI2CState;
> +
> +static bool mpc_i2c_is_enabled(MPCI2CState *s)
> +{
> + return s->cr & CCR_MEN;
> +}
> +
> +static bool mpc_i2c_is_master(MPCI2CState *s)
> +{
> + return s->cr & CCR_MSTA;
> +}
> +
> +static bool mpc_i2c_direction_is_tx(MPCI2CState *s)
> +{
> + return s->cr & CCR_MTX;
> +}
> +
> +static bool mpc_i2c_irq_pending(MPCI2CState *s)
> +{
> + return s->sr & CSR_MIF;
> +}
> +
> +static bool mpc_i2c_irq_is_enabled(MPCI2CState *s)
> +{
> + return s->cr & CCR_MIEN;
> +}
> +
> +static void mpc_i2c_reset(DeviceState *dev)
> +{
> + MPCI2CState *i2c = MPC_I2C(dev);
> +
> + i2c->address = 0xFF;
> + i2c->adr = 0x00;
> + i2c->fdr = 0x00;
> + i2c->cr = 0x00;
> + i2c->sr = 0x81;
> + i2c->dr = 0x00;
> +}
> +
> +static void mpc_i2c_irq(MPCI2CState *s)
> +{
> + bool irq_active = false;
> +
> + if (mpc_i2c_is_enabled(s) && mpc_i2c_irq_is_enabled(s)
> + && mpc_i2c_irq_pending(s)) {
> + irq_active = true;
> + }
> +
> + if (irq_active) {
> + qemu_irq_raise(s->irq);
> + } else {
> + qemu_irq_lower(s->irq);
> + }
> +}
> +
> +static void mpc_i2c_soft_reset(MPCI2CState *s)
> +{
> + /* This is a soft reset. ADR is preserved during soft resets */
> + uint8_t adr = s->adr;
> + mpc_i2c_reset(DEVICE(s));
> + s->adr = adr;
> +}
> +
> +static void mpc_i2c_address_send(MPCI2CState *s)
> +{
> + /* if returns non zero slave address is not right */
> + if (i2c_start_transfer(s->bus, s->dr >> 1, s->dr & (0x01))) {
> + s->sr |= CSR_RXAK;
> + } else {
> + s->address = s->dr;
> + s->sr &= ~CSR_RXAK;
> + s->sr |= CSR_MCF; /* Set after Byte Transfer is completed */
> + s->sr |= CSR_MIF; /* Set after Byte Transfer is completed */
> + mpc_i2c_irq(s);
> + }
> +}
> +
> +static void mpc_i2c_data_send(MPCI2CState *s)
> +{
> + if (i2c_send(s->bus, s->dr)) {
> + /* End of transfer */
> + s->sr |= CSR_RXAK;
> + i2c_end_transfer(s->bus);
> + } else {
> + s->sr &= ~CSR_RXAK;
> + s->sr |= CSR_MCF; /* Set after Byte Transfer is completed */
> + s->sr |= CSR_MIF; /* Set after Byte Transfer is completed */
> + mpc_i2c_irq(s);
> + }
> +}
> +
> +static void mpc_i2c_data_recive(MPCI2CState *s)
> +{
> + int ret;
> + /* get the next byte */
> + ret = i2c_recv(s->bus);
> + if (ret >= 0) {
> + s->sr |= CSR_MCF; /* Set after Byte Transfer is completed */
> + s->sr |= CSR_MIF; /* Set after Byte Transfer is completed */
> + mpc_i2c_irq(s);
> + } else {
> + DPRINTF("read failed for device");
> + ret = 0xff;
> + }
> + s->dr = ret;
> +}
> +
> +static uint64_t mpc_i2c_read(void *opaque, hwaddr addr, unsigned size)
> +{
> + MPCI2CState *s = opaque;
> + uint8_t value;
> +
> + switch (addr) {
> + case MPC_I2C_ADR:
> + value = s->adr;
> + break;
> + case MPC_I2C_FDR:
> + value = s->fdr;
> + break;
> + case MPC_I2C_CR:
> + value = s->cr;
> + break;
> + case MPC_I2C_SR:
> + value = s->sr;
> + break;
> + case MPC_I2C_DR:
> + value = s->dr;
> + if (mpc_i2c_is_master(s)) { /* master mode */
> + if (mpc_i2c_direction_is_tx(s)) {
> + DPRINTF("MTX is set not in recv mode\n");
> + } else {
> + mpc_i2c_data_recive(s);
> + }
> + }
> + break;
> + default:
> + value = 0;
> + DPRINTF("ERROR: Bad read addr 0x%x\n", (unsigned int)addr);
> + break;
> + }
> +
> + DPRINTF("%s: addr " TARGET_FMT_plx " %02" PRIx32 "\n", __func__,
> + addr, value);
> + return (uint64_t)value;
> +}
> +
> +static void mpc_i2c_write(void *opaque, hwaddr addr,
> + uint64_t value, unsigned size)
> +{
> + MPCI2CState *s = opaque;
> +
> + DPRINTF("%s: addr " TARGET_FMT_plx " val %08" PRIx64 "\n", __func__,
> + addr, value);
> + switch (addr) {
> + case MPC_I2C_ADR:
> + s->adr = value & CADR_MASK;
> + break;
> + case MPC_I2C_FDR:
> + s->fdr = value & CFDR_MASK;
> + break;
> + case MPC_I2C_CR:
> + if (mpc_i2c_is_enabled(s) && ((value & CCR_MEN) == 0)) {
> + mpc_i2c_soft_reset(s);
> + break;
> + }
> + /* normal write */
> + s->cr = value & CCR_MASK;
> + if (mpc_i2c_is_master(s)) { /* master mode */
> + /* set the bus to busy after master is set as per RM */
> + s->sr |= CSR_MBB;
> + } else {
> + /* bus is not busy anymore */
> + s->sr &= ~CSR_MBB;
> + /* Reset the address for fresh write/read cycle */
> + if (s->address != CYCLE_RESET) {
> + i2c_end_transfer(s->bus);
> + s->address = CYCLE_RESET;
> + }
> + }
> + /* For restart end the onging transfer */
> + if (s->cr & CCR_RSTA) {
> + if (s->address != CYCLE_RESET) {
> + s->address = CYCLE_RESET;
> + i2c_end_transfer(s->bus);
> + s->cr &= ~CCR_RSTA;
> + }
> + }
> + break;
> + case MPC_I2C_SR:
> + s->sr = value & CSR_MASK;
> + /* Lower the interrupt */
> + if (!(s->sr & CSR_MIF) || !(s->sr & CSR_MAL)) {
> + mpc_i2c_irq(s);
> + }
> + break;
> + case MPC_I2C_DR:
> + /* if the device is not enabled, nothing to do */
> + if (!mpc_i2c_is_enabled(s)) {
> + break;
> + }
> + s->dr = value & CDR_MASK;
> + if (mpc_i2c_is_master(s)) { /* master mode */
> + if (s->address == CYCLE_RESET) {
> + mpc_i2c_address_send(s);
> + } else {
> + mpc_i2c_data_send(s);
> + }
> + }
> + break;
> + case MPC_I2C_DFSRR:
> + s->dfssr = value;
> + break;
> + default:
> + DPRINTF("ERROR: Bad write addr 0x%x\n", (unsigned int)addr);
> + break;
> + }
> +}
> +
> +static const MemoryRegionOps i2c_ops = {
> + .read = mpc_i2c_read,
> + .write = mpc_i2c_write,
> + .valid.max_access_size = 1,
> + .endianness = DEVICE_NATIVE_ENDIAN,
> +};
> +
> +static const VMStateDescription mpc_i2c_vmstate = {
> + .name = TYPE_MPC_I2C,
> + .version_id = 1,
> + .minimum_version_id = 1,
> + .fields = (VMStateField[]) {
> + VMSTATE_UINT8(address, MPCI2CState),
> + VMSTATE_UINT8(adr, MPCI2CState),
> + VMSTATE_UINT8(fdr, MPCI2CState),
> + VMSTATE_UINT8(cr, MPCI2CState),
> + VMSTATE_UINT8(sr, MPCI2CState),
> + VMSTATE_UINT8(dr, MPCI2CState),
> + VMSTATE_UINT8(dfssr, MPCI2CState),
> + VMSTATE_END_OF_LIST()
> + }
> +};
> +
> +static void mpc_i2c_realize(DeviceState *dev, Error **errp)
> +{
> +
> + MPCI2CState *i2c = MPC_I2C(dev);
> +
> + sysbus_init_irq(SYS_BUS_DEVICE(dev), &i2c->irq);
> + memory_region_init_io(&i2c->iomem, OBJECT(i2c), &i2c_ops, i2c,
> + "mpc-i2c", 0x14);
> + sysbus_init_mmio(SYS_BUS_DEVICE(dev), &i2c->iomem);
> + i2c->bus = i2c_init_bus(DEVICE(dev), "i2c");
> +}
> +
> +static void mpc_i2c_class_init(ObjectClass *klass, void *data)
> +{
> + DeviceClass *dc = DEVICE_CLASS(klass);
> +
> + dc->vmsd = &mpc_i2c_vmstate ;
> + dc->reset = mpc_i2c_reset;
> + dc->realize = mpc_i2c_realize;
> + dc->desc = "MPC I2C Controller";
> +}
> +
> +static const TypeInfo mpc_i2c_type_info = {
> + .name = TYPE_MPC_I2C,
> + .parent = TYPE_SYS_BUS_DEVICE,
> + .instance_size = sizeof(MPCI2CState),
> + .class_init = mpc_i2c_class_init,
> +};
> +
> +static void mpc_i2c_register_types(void)
> +{
> + type_register_static(&mpc_i2c_type_info);
> +}
> +
> +type_init(mpc_i2c_register_types)
> diff --git a/hw/ppc/e500.c b/hw/ppc/e500.c
> index 7553f674c9..c8e8563f95 100644
> --- a/hw/ppc/e500.c
> +++ b/hw/ppc/e500.c
> @@ -42,6 +42,7 @@
> #include "qemu/error-report.h"
> #include "hw/platform-bus.h"
> #include "hw/net/fsl_etsec/etsec.h"
> +#include "hw/i2c/i2c.h"
>
> #define EPAPR_MAGIC (0x45504150)
> #define BINARY_DEVICE_TREE_FILE "mpc8544ds.dtb"
> @@ -63,7 +64,10 @@
> #define MPC8544_PCI_REGS_SIZE 0x1000ULL
> #define MPC8544_UTIL_OFFSET 0xe0000ULL
> #define MPC8XXX_GPIO_OFFSET 0x000FF000ULL
> +#define MPC8544_I2C_REGS_OFFSET 0x3000ULL
> #define MPC8XXX_GPIO_IRQ 47
> +#define MPC8544_I2C_IRQ 43
> +#define RTC_REGS_OFFSET 0x68
>
> struct boot_info
> {
> @@ -161,6 +165,39 @@ static void create_dt_mpc8xxx_gpio(void *fdt, const char
> *soc, const char *mpic)
> g_free(poweroff);
> }
>
> +static void dt_rtc_create(void *fdt, const char *i2c, const char *alias)
> +{
> + int offset = RTC_REGS_OFFSET;
> +
> + gchar *rtc = g_strdup_printf("%s/rtc@%"PRIx32, i2c, offset);
> + qemu_fdt_add_subnode(fdt, rtc);
> + qemu_fdt_setprop_string(fdt, rtc, "compatible", "pericom,pt7c4338");
> + qemu_fdt_setprop_cells(fdt, rtc, "reg", offset);
> + qemu_fdt_setprop_string(fdt, "/aliases", alias, rtc);
> +
> + g_free(rtc);
> +}
> +
> +static void dt_i2c_create(void *fdt, const char *soc, const char *mpic,
> + const char *alias)
> +{
> + hwaddr mmio0 = MPC8544_I2C_REGS_OFFSET;
> + int irq0 = MPC8544_I2C_IRQ;
> +
> + gchar *i2c = g_strdup_printf("%s/i2c@%"PRIx64, soc, mmio0);
> + qemu_fdt_add_subnode(fdt, i2c);
> + qemu_fdt_setprop_string(fdt, i2c, "device_type", "i2c");
> + qemu_fdt_setprop_string(fdt, i2c, "compatible", "fsl-i2c");
> + qemu_fdt_setprop_cells(fdt, i2c, "reg", mmio0, 0x14);
> + qemu_fdt_setprop_cells(fdt, i2c, "cell-index", 0);
> + qemu_fdt_setprop_cells(fdt, i2c, "interrupts", irq0, 0x2);
> + qemu_fdt_setprop_phandle(fdt, i2c, "interrupt-parent", mpic);
> + qemu_fdt_setprop_string(fdt, "/aliases", alias, i2c);
> +
> + g_free(i2c);
> +}
> +
> +
> typedef struct PlatformDevtreeData {
> void *fdt;
> const char *mpic;
> @@ -463,6 +500,12 @@ static int ppce500_load_device_tree(PPCE500MachineState
> *pms,
> dt_serial_create(fdt, MPC8544_SERIAL0_REGS_OFFSET,
> soc, mpic, "serial0", 0, true);
> }
> +
> + /* i2c */
> + dt_i2c_create(fdt, soc, mpic, "i2c");
> +
> + dt_rtc_create(fdt, "i2c", "rtc");
> +
>
> gutil = g_strdup_printf("%s/global-utilities@%llx", soc,
> MPC8544_UTIL_OFFSET);
> @@ -812,6 +855,7 @@ void ppce500_init(MachineState *machine)
> MemoryRegion *ccsr_addr_space;
> SysBusDevice *s;
> PPCE500CCSRState *ccsr;
> + I2CBus *i2c;
>
> irqs = g_new0(IrqLines, smp_cpus);
> for (i = 0; i < smp_cpus; i++) {
> @@ -887,6 +931,16 @@ void ppce500_init(MachineState *machine)
> 0, qdev_get_gpio_in(mpicdev, 42), 399193,
> serial_hd(1), DEVICE_BIG_ENDIAN);
> }
> + /* I2C */
> + dev = qdev_create(NULL, "mpc-i2c");
> + s = SYS_BUS_DEVICE(dev);
> + qdev_init_nofail(dev);
> + sysbus_connect_irq(s, 0, qdev_get_gpio_in(mpicdev, MPC8544_I2C_IRQ));
> + memory_region_add_subregion(ccsr_addr_space, MPC8544_I2C_REGS_OFFSET,
> + sysbus_mmio_get_region(s, 0));
> + i2c = (I2CBus *)qdev_get_child_bus(dev, "i2c");
> + i2c_create_slave(i2c, "ds1338", RTC_REGS_OFFSET);
> +
>
> /* General Utility device */
> dev = qdev_create(NULL, "mpc8544-guts");
>
> ----------------
>
> Test kernel I used:
> http://www.xenosoft.de/linux-image-4.20.12-X1000_X5000.tar.gz
> (unpack and use uImage)
>
> guest@slax:/dev/shm/qemu$ ppc64-softmmu/qemu-system-ppc64 -M ppce500 -cpu
> e5500 -kernel /mnt/sdb1/PPC-img/linux-image-4.20.12-X1000_X5000/X5000_and_QEMU_e5500/uImage-4.20 -nographic
>
> also, I think I found reason why some of my tests resulted in blue or green-ish
> image: -sdl,gl=on was causing troubles sometimes. It was ok with stdvga , but
> not for virtio-gpu.
>
> At least in linux virtio-gpu driver disables "3d" (virgl) part of itself on BE
> machine. Guess sdl2 video output in qemu has no idea about guest's action, so
> it acts wrongly with BE guests and gives intensively blue console with
> offb-enabled LE guest. (on ppc64 machine).
There could be different endianness issues both in QEMU or in the Linux
driver (BE systems are not well supported nowadays). I don't think SDL
itself would play a role but I really don't know. Maybe you should post
this question separately with details on how to reproduce it on qemu-devel
list cc-ing the graphics maintainer Gerd Hoffmann <kraxel@redhat.com>
otherwise it's easy to miss this at the end of an unrelated patch and
likely no one will reply. (It's possible nobody will reply to a separate
thread either as people may not use similar setup but the chances are
higher to get some reply that way.)
Regards,
BALATON Zoltan
^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: [Qemu-devel] [Qemu-ppc] Forward-porting RTC device for eppc500 ?
[not found] ` <alpine.BSF.2.21.9999.1903022116110.13215@zero.eik.bme.hu>
@ 2019-03-02 21:50 ` Andrew Randrianasulu
2019-03-03 0:17 ` BALATON Zoltan
0 siblings, 1 reply; 5+ messages in thread
From: Andrew Randrianasulu @ 2019-03-02 21:50 UTC (permalink / raw)
To: BALATON Zoltan, qemu-devel
В сообщении от Saturday 02 March 2019 23:40:47 BALATON Zoltan написал(а):
[snip]
>
> On Sat, 2 Mar 2019, Andrew Randrianasulu wrote:
> > Should I fix those?
>
> [...]
>
> > total: 14 errors, 2 warnings, 462 lines checked
> >
> > 0001-Re-applying-of-Freescale-PPC500-i2c-RTC-patch-writte.patch has style
> > problems, please review. If any of these errors
> > are false positives report them to the maintainer, see
> > CHECKPATCH in MAINTAINERS.
>
> Yes, patches submitted to the list should pass checkpatch otherwise they
> will be rejected by automated build tests. These are simple to fix, just
> add spaces as checkpatch suggests: (1 << 0) and so on.
>
> (It's better to keep the list cc-d on reply so others can also answer your
> questions or correct my answers if I missed something which is not
> possible if you reply to me off list.)
Posted to list, arrived as
https://lists.gnu.org/archive/html/qemu-devel/2019-03/msg00413.html
I used (in specifically created branch)
git reset origin
git reset --hard
git apply \
/home/guest/botva/src/src/qemu/0001-Re-applying-Freescale-PPC500-i2c-RTC-patch-written-b.patch
rm hw/i2c/mpc_i2c.c (leftover from my previous attempt at commiting)
again
git apply \
/home/guest/botva/src/src/qemu/0001-Re-applying-Freescale-PPC500-i2c-RTC-patch-written-b.patch
{now it applies cleanly)
git add hw/i2c/mpc_i2c.c
make
ppc64-softmmu/qemu-system-ppc64 -M ppce500 -cpu
e5500 -kernel /mnt/sdb1/PPC-img/linux-image-4.20.12-X1000_X5000/X5000_and_QEMU_e5500/uImage-4.20 -nographic
git commit -a --author="Amit Singh Tomar <amit.tomar@freescale.com>"
git format-patch -s 20b084c4b1401b7f8fbc385649d48c67b6f43d44
scripts/checkpatch.pl 0001-Re-applying-Freescale-PPC-E500-i2c-RTC-patch.patch
After this I created new message in Kmail and inserted 0001 file, edited it a
bit more (adding patchwork link and mentioning fact I actually boot-tested
patch), and then send out.
Guess next time I better to add second "-s" to git format-patch, so first
signed-off-by-line from original will be around too?
Or ..lets wait what actual maintainers will say.
>
> Regards,
> BALATON Zoltan
^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: [Qemu-devel] [Qemu-ppc] Forward-porting RTC device for eppc500 ?
2019-03-02 21:50 ` Andrew Randrianasulu
@ 2019-03-03 0:17 ` BALATON Zoltan
2019-03-03 0:21 ` Andrew Randrianasulu
0 siblings, 1 reply; 5+ messages in thread
From: BALATON Zoltan @ 2019-03-03 0:17 UTC (permalink / raw)
To: Andrew Randrianasulu; +Cc: qemu-devel
On Sun, 3 Mar 2019, Andrew Randrianasulu wrote:
> git commit -a --author="Amit Singh Tomar <amit.tomar@freescale.com>"
> git format-patch -s 20b084c4b1401b7f8fbc385649d48c67b6f43d44
>
> scripts/checkpatch.pl 0001-Re-applying-Freescale-PPC-E500-i2c-RTC-patch.patch
>
> After this I created new message in Kmail and inserted 0001 file, edited it a
> bit more (adding patchwork link and mentioning fact I actually boot-tested
> patch), and then send out.
When sending patches to list make sure your mailer sends them as plain
text and does not try to break up lines or alter white space because that
breaks the patch and it won't apply with git am. You can check it in
patchew (linked from SubmitAPatch wiki page):
https://patchew.org/QEMU/201903030021.22070.randrianasulu@gmail.com/
Not sure if Kmail can do this, maybe it has some settings for this but
it's usually better to do all editing on the git commit and send patch
mails with git send-email.
> Guess next time I better to add second "-s" to git format-patch, so first
> signed-off-by-line from original will be around too?
>
> Or ..lets wait what actual maintainers will say.
Yes, I'll let actual maintainers to comment then you can do a corrected
version with any requested fixes or Reviewed-by tags added. I think for
next revision you should leave original author's Signed-off-by in commit
message and add yours with -s after that. (When sending another version of
a patch use -v2 option of git format-patch to add v2 to the patch
subject and so on for higher revisions if needed.)
Regards,
BALATON Zoltan
^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: [Qemu-devel] [Qemu-ppc] Forward-porting RTC device for eppc500 ?
2019-03-03 0:17 ` BALATON Zoltan
@ 2019-03-03 0:21 ` Andrew Randrianasulu
0 siblings, 0 replies; 5+ messages in thread
From: Andrew Randrianasulu @ 2019-03-03 0:21 UTC (permalink / raw)
To: BALATON Zoltan; +Cc: qemu-devel
В сообщении от Sunday 03 March 2019 03:17:47 BALATON Zoltan написал(а):
> On Sun, 3 Mar 2019, Andrew Randrianasulu wrote:
> > git commit -a --author="Amit Singh Tomar <amit.tomar@freescale.com>"
> > git format-patch -s 20b084c4b1401b7f8fbc385649d48c67b6f43d44
> >
> > scripts/checkpatch.pl
> > 0001-Re-applying-Freescale-PPC-E500-i2c-RTC-patch.patch
> >
> > After this I created new message in Kmail and inserted 0001 file, edited
> > it a bit more (adding patchwork link and mentioning fact I actually
> > boot-tested patch), and then send out.
>
> When sending patches to list make sure your mailer sends them as plain
> text and does not try to break up lines or alter white space because that
> breaks the patch and it won't apply with git am. You can check it in
> patchew (linked from SubmitAPatch wiki page):
>
> https://patchew.org/QEMU/201903030021.22070.randrianasulu@gmail.com/
>
> Not sure if Kmail can do this, maybe it has some settings for this but
> it's usually better to do all editing on the git commit and send patch
> mails with git send-email.
I see, it failed to apply. Will try to convince git send-mail to work (last time
it failed for me, but it was long time ago)
>
> > Guess next time I better to add second "-s" to git format-patch, so first
> > signed-off-by-line from original will be around too?
> >
> > Or ..lets wait what actual maintainers will say.
>
> Yes, I'll let actual maintainers to comment then you can do a corrected
> version with any requested fixes or Reviewed-by tags added. I think for
> next revision you should leave original author's Signed-off-by in commit
> message and add yours with -s after that. (When sending another version of
> a patch use -v2 option of git format-patch to add v2 to the patch
> subject and so on for higher revisions if needed.)
Thanks.
>
> Regards,
> BALATON Zoltan
^ permalink raw reply [flat|nested] 5+ messages in thread
end of thread, other threads:[~2019-03-03 0:26 UTC | newest]
Thread overview: 5+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2019-03-02 11:21 [Qemu-devel] Forward-porting RTC device for eppc500 ? Andrew Randrianasulu
2019-03-02 16:59 ` [Qemu-devel] [Qemu-ppc] " BALATON Zoltan
[not found] ` <201903022144.45897.randrianasulu@gmail.com>
[not found] ` <alpine.BSF.2.21.9999.1903022116110.13215@zero.eik.bme.hu>
2019-03-02 21:50 ` Andrew Randrianasulu
2019-03-03 0:17 ` BALATON Zoltan
2019-03-03 0:21 ` Andrew Randrianasulu
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).