On Sat, Dec 16, 2017 at 11:42:14PM +0100, BALATON Zoltan wrote: > Enough to please U-Boot and make it able to detect SDRAM SPD EEPROMs > > Signed-off-by: François Revol <re...@free.fr> > Signed-off-by: BALATON Zoltan <bala...@eik.bme.hu> > Reviewed-by: David Gibson <da...@gibson.dropbear.id.au>
Applied to ppc-for-2.12, thanks. > --- > v2: > - Removed DPRINTFs, no other change > - R-b from: > http://lists.nongnu.org/archive/html/qemu-ppc/2017-08/msg00193.html > > hw/i2c/ppc4xx_i2c.c | 198 > +++++++++++++++++++++++++++++++++++++------- > include/hw/i2c/ppc4xx_i2c.h | 3 + > 2 files changed, 171 insertions(+), 30 deletions(-) > > diff --git a/hw/i2c/ppc4xx_i2c.c b/hw/i2c/ppc4xx_i2c.c > index 5a6bde9..e873a44 100644 > --- a/hw/i2c/ppc4xx_i2c.c > +++ b/hw/i2c/ppc4xx_i2c.c > @@ -2,6 +2,8 @@ > * PPC4xx I2C controller emulation > * > * Copyright (c) 2007 Jocelyn Mayer > + * Copyright (c) 2012 François Revol > + * Copyright (c) 2016 BALATON Zoltan > * > * Permission is hereby granted, free of charge, to any person obtaining a > copy > * of this software and associated documentation files (the "Software"), to > deal > @@ -25,26 +27,118 @@ > #include "qemu/osdep.h" > #include "qapi/error.h" > #include "qemu-common.h" > +#include "qemu/log.h" > #include "cpu.h" > #include "hw/hw.h" > #include "hw/i2c/ppc4xx_i2c.h" > > -/*#define DEBUG_I2C*/ > +#define PPC4xx_I2C_MEM_SIZE 0x12 > > -#define PPC4xx_I2C_MEM_SIZE 0x11 > +#define IIC_CNTL_PT (1 << 0) > +#define IIC_CNTL_READ (1 << 1) > +#define IIC_CNTL_CHT (1 << 2) > +#define IIC_CNTL_RPST (1 << 3) > + > +#define IIC_STS_PT (1 << 0) > +#define IIC_STS_ERR (1 << 2) > +#define IIC_STS_MDBS (1 << 5) > + > +#define IIC_EXTSTS_XFRA (1 << 0) > + > +#define IIC_XTCNTLSS_SRST (1 << 0) > + > +static void ppc4xx_i2c_reset(DeviceState *s) > +{ > + PPC4xxI2CState *i2c = PPC4xx_I2C(s); > + > + /* FIXME: Should also reset bus? > + *if (s->address != ADDR_RESET) { > + * i2c_end_transfer(s->bus); > + *} > + */ > + > + i2c->mdata = 0; > + i2c->lmadr = 0; > + i2c->hmadr = 0; > + i2c->cntl = 0; > + i2c->mdcntl = 0; > + i2c->sts = 0; > + i2c->extsts = 0x8f; > + i2c->sdata = 0; > + i2c->lsadr = 0; > + i2c->hsadr = 0; > + i2c->clkdiv = 0; > + i2c->intrmsk = 0; > + i2c->xfrcnt = 0; > + i2c->xtcntlss = 0; > + i2c->directcntl = 0x0f; > + i2c->intr = 0; > +} > + > +static inline bool ppc4xx_i2c_is_master(PPC4xxI2CState *i2c) > +{ > + return true; > +} > > static uint64_t ppc4xx_i2c_readb(void *opaque, hwaddr addr, unsigned int > size) > { > PPC4xxI2CState *i2c = PPC4xx_I2C(opaque); > uint64_t ret; > > -#ifdef DEBUG_I2C > - printf("%s: addr " TARGET_FMT_plx "\n", __func__, addr); > -#endif > switch (addr) { > case 0x00: > - /*i2c_readbyte(&i2c->mdata);*/ > ret = i2c->mdata; > + if (ppc4xx_i2c_is_master(i2c)) { > + ret = 0xff; > + > + if (!(i2c->sts & IIC_STS_MDBS)) { > + qemu_log_mask(LOG_GUEST_ERROR, "[%s]%s: Trying to read " > + "without starting transfer\n", > + TYPE_PPC4xx_I2C, __func__); > + } else { > + int pending = (i2c->cntl >> 4) & 3; > + > + /* get the next byte */ > + int byte = i2c_recv(i2c->bus); > + > + if (byte < 0) { > + qemu_log_mask(LOG_GUEST_ERROR, "[%s]%s: read failed " > + "for device 0x%02x\n", TYPE_PPC4xx_I2C, > + __func__, i2c->lmadr); > + ret = 0xff; > + } else { > + ret = byte; > + /* Raise interrupt if enabled */ > + /*ppc4xx_i2c_raise_interrupt(i2c)*/; > + } > + > + if (!pending) { > + i2c->sts &= ~IIC_STS_MDBS; > + /*i2c_end_transfer(i2c->bus);*/ > + /*} else if (i2c->cntl & (IIC_CNTL_RPST | IIC_CNTL_CHT)) {*/ > + } else if (pending) { > + /* current smbus implementation doesn't like > + multibyte xfer repeated start */ > + i2c_end_transfer(i2c->bus); > + if (i2c_start_transfer(i2c->bus, i2c->lmadr >> 1, 1)) { > + /* if non zero is returned, the adress is not valid > */ > + i2c->sts &= ~IIC_STS_PT; > + i2c->sts |= IIC_STS_ERR; > + i2c->extsts |= IIC_EXTSTS_XFRA; > + } else { > + /*i2c->sts |= IIC_STS_PT;*/ > + i2c->sts |= IIC_STS_MDBS; > + i2c->sts &= ~IIC_STS_ERR; > + i2c->extsts = 0; > + } > + } > + pending--; > + i2c->cntl = (i2c->cntl & 0xcf) | (pending << 4); > + } > + } else { > + qemu_log_mask(LOG_UNIMP, "[%s]%s: slave mode not implemented\n", > + TYPE_PPC4xx_I2C, __func__); > + } > break; > case 0x02: > ret = i2c->sdata; > @@ -88,13 +182,15 @@ static uint64_t ppc4xx_i2c_readb(void *opaque, hwaddr > addr, unsigned int size) > case 0x10: > ret = i2c->directcntl; > break; > + case 0x11: > + ret = i2c->intr; > + break; > default: > - ret = 0x00; > + qemu_log_mask(LOG_GUEST_ERROR, "[%s]%s: Bad address at offset 0x%" > + HWADDR_PRIx "\n", TYPE_PPC4xx_I2C, __func__, addr); > + ret = 0; > break; > } > -#ifdef DEBUG_I2C > - printf("%s: addr " TARGET_FMT_plx " %02" PRIx64 "\n", __func__, addr, > ret); > -#endif > > return ret; > } > @@ -103,26 +199,70 @@ static void ppc4xx_i2c_writeb(void *opaque, hwaddr > addr, uint64_t value, > unsigned int size) > { > PPC4xxI2CState *i2c = opaque; > -#ifdef DEBUG_I2C > - printf("%s: addr " TARGET_FMT_plx " val %08" PRIx64 "\n", > - __func__, addr, value); > -#endif > + > switch (addr) { > case 0x00: > i2c->mdata = value; > - /*i2c_sendbyte(&i2c->mdata);*/ > + if (!i2c_bus_busy(i2c->bus)) { > + /* assume we start a write transfer */ > + if (i2c_start_transfer(i2c->bus, i2c->lmadr >> 1, 0)) { > + /* if non zero is returned, the adress is not valid */ > + i2c->sts &= ~IIC_STS_PT; > + i2c->sts |= IIC_STS_ERR; > + i2c->extsts |= IIC_EXTSTS_XFRA; > + } else { > + i2c->sts |= IIC_STS_PT; > + i2c->sts &= ~IIC_STS_ERR; > + i2c->extsts = 0; > + } > + } > + if (i2c_bus_busy(i2c->bus)) { > + if (i2c_send(i2c->bus, i2c->mdata)) { > + /* if the target return non zero then end the transfer */ > + i2c->sts &= ~IIC_STS_PT; > + i2c->sts |= IIC_STS_ERR; > + i2c->extsts |= IIC_EXTSTS_XFRA; > + i2c_end_transfer(i2c->bus); > + } > + } > break; > case 0x02: > i2c->sdata = value; > break; > case 0x04: > i2c->lmadr = value; > + if (i2c_bus_busy(i2c->bus)) { > + i2c_end_transfer(i2c->bus); > + } > break; > case 0x05: > i2c->hmadr = value; > break; > case 0x06: > i2c->cntl = value; > + if (i2c->cntl & IIC_CNTL_PT) { > + if (i2c->cntl & IIC_CNTL_READ) { > + if (i2c_bus_busy(i2c->bus)) { > + /* end previous transfer */ > + i2c->sts &= ~IIC_STS_PT; > + i2c_end_transfer(i2c->bus); > + } > + if (i2c_start_transfer(i2c->bus, i2c->lmadr >> 1, 1)) { > + /* if non zero is returned, the adress is not valid */ > + i2c->sts &= ~IIC_STS_PT; > + i2c->sts |= IIC_STS_ERR; > + i2c->extsts |= IIC_EXTSTS_XFRA; > + } else { > + /*i2c->sts |= IIC_STS_PT;*/ > + i2c->sts |= IIC_STS_MDBS; > + i2c->sts &= ~IIC_STS_ERR; > + i2c->extsts = 0; > + } > + } else { > + /* we actually already did the write transfer... */ > + i2c->sts &= ~IIC_STS_PT; > + } > + } > break; > case 0x07: > i2c->mdcntl = value & 0xDF; > @@ -135,6 +275,7 @@ static void ppc4xx_i2c_writeb(void *opaque, hwaddr addr, > uint64_t value, > break; > case 0x0A: > i2c->lsadr = value; > + /*i2c_set_slave_address(i2c->bus, i2c->lsadr);*/ > break; > case 0x0B: > i2c->hsadr = value; > @@ -149,11 +290,23 @@ static void ppc4xx_i2c_writeb(void *opaque, hwaddr > addr, uint64_t value, > i2c->xfrcnt = value & 0x77; > break; > case 0x0F: > + if (value & IIC_XTCNTLSS_SRST) { > + /* Is it actually a full reset? U-Boot sets some regs before */ > + ppc4xx_i2c_reset(DEVICE(i2c)); > + break; > + } > i2c->xtcntlss = value; > break; > case 0x10: > i2c->directcntl = value & 0x7; > break; > + case 0x11: > + i2c->intr = value; > + break; > + default: > + qemu_log_mask(LOG_GUEST_ERROR, "[%s]%s: Bad address at offset 0x%" > + HWADDR_PRIx "\n", TYPE_PPC4xx_I2C, __func__, addr); > + break; > } > } > > @@ -167,21 +320,6 @@ static const MemoryRegionOps ppc4xx_i2c_ops = { > .endianness = DEVICE_NATIVE_ENDIAN, > }; > > -static void ppc4xx_i2c_reset(DeviceState *s) > -{ > - PPC4xxI2CState *i2c = PPC4xx_I2C(s); > - > - i2c->mdata = 0x00; > - i2c->sdata = 0x00; > - i2c->cntl = 0x00; > - i2c->mdcntl = 0x00; > - i2c->sts = 0x00; > - i2c->extsts = 0x00; > - i2c->clkdiv = 0x00; > - i2c->xfrcnt = 0x00; > - i2c->directcntl = 0x0F; > -} > - > static void ppc4xx_i2c_init(Object *o) > { > PPC4xxI2CState *s = PPC4xx_I2C(o); > diff --git a/include/hw/i2c/ppc4xx_i2c.h b/include/hw/i2c/ppc4xx_i2c.h > index e53042f..71fb392 100644 > --- a/include/hw/i2c/ppc4xx_i2c.h > +++ b/include/hw/i2c/ppc4xx_i2c.h > @@ -2,6 +2,8 @@ > * PPC4xx I2C controller emulation > * > * Copyright (c) 2007 Jocelyn Mayer > + * Copyright (c) 2012 François Revol > + * Copyright (c) 2016 BALATON Zoltan > * > * Permission is hereby granted, free of charge, to any person obtaining a > copy > * of this software and associated documentation files (the "Software"), to > deal > @@ -56,6 +58,7 @@ typedef struct PPC4xxI2CState { > uint8_t xfrcnt; > uint8_t xtcntlss; > uint8_t directcntl; > + uint8_t intr; > } PPC4xxI2CState; > > #endif /* PPC4XX_I2C_H */ -- David Gibson | I'll have my music baroque, and my code david AT gibson.dropbear.id.au | minimalist, thank you. NOT _the_ _other_ | _way_ _around_! http://www.ozlabs.org/~dgibson
signature.asc
Description: PGP signature