qemu-devel.nongnu.org archive mirror
 help / color / mirror / Atom feed
From: "Cédric Le Goater" <clg@kaod.org>
To: Klaus Jensen <its@irrelevant.dk>, <qemu-devel@nongnu.org>
Cc: Peter Maydell <peter.maydell@linaro.org>,
	Arun Kumar Kashinath Agasar <arun.kka@samsung.com>,
	Corey Minyard <cminyard@mvista.com>,
	Andrew Jeffery <andrew@aj.id.au>,
	Klaus Jensen <k.jensen@samsung.com>,
	qemu-arm@nongnu.org, Joel Stanley <joel@jms.id.au>,
	Padmakar Kalghatgi <p.kalghatgi@samsung.com>,
	Matt Johnston <matt@codeconstruct.com.au>,
	Jeremy Kerr <jk@ozlabs.org>
Subject: Re: [RFC PATCH 3/4] hw/i2c: add slave mode for aspeed_i2c
Date: Wed, 6 Apr 2022 08:14:02 +0200	[thread overview]
Message-ID: <356b3f59-b915-3da1-7155-8082b55932fb@kaod.org> (raw)
In-Reply-To: <20220331165737.1073520-4-its@irrelevant.dk>

Hello Klaus,

On 3/31/22 18:57, Klaus Jensen wrote:
> From: Klaus Jensen <k.jensen@samsung.com>
> 
> Add slave mode functionality for the Aspeed I2C controller. This is
> implemented by creating an Aspeed I2C Slave device that attaches to the
> bus.
> 
> This i2c slave device only implements the asynchronous version of
> i2c_send() and the event callback.
> 
> Signed-off-by: Klaus Jensen <k.jensen@samsung.com>
> ---
>   hw/i2c/aspeed_i2c.c         | 95 +++++++++++++++++++++++++++++++++----
>   hw/i2c/trace-events         |  2 +-
>   hw/misc/meson.build         |  2 +
>   include/hw/i2c/aspeed_i2c.h |  8 ++++
>   4 files changed, 97 insertions(+), 10 deletions(-)
> 
> diff --git a/hw/i2c/aspeed_i2c.c b/hw/i2c/aspeed_i2c.c
> index 03a4f5a91010..61b6424434f7 100644
> --- a/hw/i2c/aspeed_i2c.c
> +++ b/hw/i2c/aspeed_i2c.c
> @@ -163,10 +163,15 @@ static inline void aspeed_i2c_bus_raise_interrupt(AspeedI2CBus *bus)
>             bus->intr_status & I2CD_INTR_TX_NAK ? "nak|" : "",
>             bus->intr_status & I2CD_INTR_TX_ACK ? "ack|" : "",
>             bus->intr_status & I2CD_INTR_RX_DONE ? "done|" : "",
> +          bus->intr_status & I2CD_INTR_SLAVE_ADDR_RX_MATCH ? "slave-match|" : "",
>             bus->intr_status & I2CD_INTR_NORMAL_STOP ? "normal|" : "",
>             bus->intr_status & I2CD_INTR_ABNORMAL ? "abnormal" : "");

Troy introduced a similar change in his "new mode" proposal. I think
it is time to change the 'aspeed_i2c_bus_raise_interrupt' trace event

Could you please update trace_aspeed_i2c_bus_raise_interrupt() to take
a single status string ?

> -    bus->intr_status &= bus->intr_ctrl;
> +    /*
> +     * WORKAROUND: the Linux Aspeed I2C driver masks SLAVE_ADDR_RX_MATCH for
> +     * some reason, not sure if it is a bug...
> +     */
> +    bus->intr_status &= (bus->intr_ctrl | I2CD_INTR_SLAVE_ADDR_RX_MATCH);

It comes from the initial support for the AST2400 SoC.

We should introduce a 'intr_ctrl_mask' attribute in AspeedI2CClass and
fix the AST24000 value to 0x7FFF ...

>       if (bus->intr_status) {
>           bus->controller->intr_status |= 1 << bus->id;
>           qemu_irq_raise(aic->bus_get_irq(bus));
> @@ -196,6 +201,9 @@ static uint64_t aspeed_i2c_bus_read(void *opaque, hwaddr offset,
>       case I2CD_INTR_STS_REG:
>           value = bus->intr_status;
>           break;
> +    case I2CD_DEV_ADDR_REG:
> +        value = bus->dev_addr;
> +        break;

You can introduce support for this register in a preliminary patch but
keep the slave activation for later (I2CD_SLAVE_EN bit)

>       case I2CD_POOL_CTRL_REG:
>           value = bus->pool_ctrl;
>           break;
> @@ -535,10 +543,9 @@ static void aspeed_i2c_bus_write(void *opaque, hwaddr offset,
>       switch (offset) {
>       case I2CD_FUN_CTRL_REG:
>           if (value & I2CD_SLAVE_EN) {
> -            qemu_log_mask(LOG_UNIMP, "%s: slave mode not implemented\n",
> -                          __func__);
> -            break;
> +            i2c_slave_set_address(&bus->slave->i2c, bus->dev_addr);
>           }
> +
>           bus->ctrl = value & 0x0071C3FF;
>           break;
>       case I2CD_AC_TIMING_REG1:
> @@ -558,14 +565,19 @@ static void aspeed_i2c_bus_write(void *opaque, hwaddr offset,
>               bus->controller->intr_status &= ~(1 << bus->id);
>               qemu_irq_lower(aic->bus_get_irq(bus));
>           }
> -        if (handle_rx && (bus->cmd & (I2CD_M_RX_CMD | I2CD_M_S_RX_CMD_LAST))) {
> -            aspeed_i2c_handle_rx_cmd(bus);
> -            aspeed_i2c_bus_raise_interrupt(bus);
> +
> +        if (handle_rx) {
> +            if (bus->cmd & (I2CD_M_RX_CMD | I2CD_M_S_RX_CMD_LAST)) {
> +                aspeed_i2c_handle_rx_cmd(bus);
> +                aspeed_i2c_bus_raise_interrupt(bus);
> +            } else if (aspeed_i2c_get_state(bus) == I2CD_STXD) {
> +                i2c_ack(bus->bus);
> +            }
>           }
> +
>
>           break;
>       case I2CD_DEV_ADDR_REG:
> -        qemu_log_mask(LOG_UNIMP, "%s: slave mode not implemented\n",
> -                      __func__);
> +        bus->dev_addr = value;
>           break;
>       case I2CD_POOL_CTRL_REG:
>           bus->pool_ctrl &= ~0xffffff;
> @@ -852,12 +864,74 @@ static const TypeInfo aspeed_i2c_info = {
>       .abstract   = true,
>   };
>   
> +static int aspeed_i2c_slave_event(I2CSlave *slave, enum i2c_event event)
> +{
> +    AspeedI2CSlave *s = ASPEED_I2C_SLAVE(slave);
> +    AspeedI2CBus *bus = s->bus;
> +
> +    switch (event) {
> +    case I2C_START_SEND:
> +        bus->buf = bus->dev_addr << 1;
> +
> +        bus->buf &= I2CD_BYTE_BUF_RX_MASK;
> +        bus->buf <<= I2CD_BYTE_BUF_RX_SHIFT;
> +
> +        bus->intr_status |= (I2CD_INTR_SLAVE_ADDR_RX_MATCH | I2CD_INTR_RX_DONE);
> +        aspeed_i2c_set_state(bus, I2CD_STXD);
> +
> +        break;
> +
> +    case I2C_FINISH:
> +        bus->intr_status |= I2CD_INTR_NORMAL_STOP;
> +        aspeed_i2c_set_state(bus, I2CD_IDLE);
> +
> +        break;
> +
> +    default:
> +        return -1;
> +    }
> +
> +    aspeed_i2c_bus_raise_interrupt(bus);
> +
> +    return 0;
> +}
> +
> +static void aspeed_i2c_slave_send_async(I2CSlave *slave, uint8_t data)
> +{
> +    AspeedI2CSlave *s = ASPEED_I2C_SLAVE(slave);
> +    AspeedI2CBus *bus = s->bus;
> +
> +    bus->buf = (data & I2CD_BYTE_BUF_RX_MASK) << I2CD_BYTE_BUF_RX_SHIFT;
> +    bus->intr_status |= I2CD_INTR_RX_DONE;
> +
> +    aspeed_i2c_bus_raise_interrupt(bus);
> +}
> +
> +static void aspeed_i2c_slave_class_init(ObjectClass *klass, void *Data)
> +{
> +    DeviceClass *dc = DEVICE_CLASS(klass);
> +    I2CSlaveClass *sc = I2C_SLAVE_CLASS(klass);
> +
> +    dc->desc = "Aspeed I2C Bus Slave";
> +
> +    sc->event = aspeed_i2c_slave_event;
> +    sc->send_async = aspeed_i2c_slave_send_async;
> +}
> +
> +static const TypeInfo aspeed_i2c_slave_info = {
> +    .name          = TYPE_ASPEED_I2C_SLAVE,
> +    .parent        = TYPE_I2C_SLAVE,
> +    .instance_size = sizeof(AspeedI2CSlave),
> +    .class_init    = aspeed_i2c_slave_class_init,
> +};
> +
>   static void aspeed_i2c_bus_reset(DeviceState *dev)
>   {
>       AspeedI2CBus *s = ASPEED_I2C_BUS(dev);
>   
>       s->intr_ctrl = 0;
>       s->intr_status = 0;
> +    s->dev_addr = 0;

Please include the new reg in vmstate.

>       s->cmd = 0;
>       s->buf = 0;
>       s->dma_addr = 0;
> @@ -881,6 +955,8 @@ static void aspeed_i2c_bus_realize(DeviceState *dev, Error **errp)
>       sysbus_init_irq(SYS_BUS_DEVICE(dev), &s->irq);
>   
>       s->bus = i2c_init_bus(dev, name);
> +    s->slave = ASPEED_I2C_SLAVE(i2c_slave_create_simple(s->bus, TYPE_ASPEED_I2C_SLAVE, 0xff));
> +    s->slave->bus = s;
>   
>       memory_region_init_io(&s->mr, OBJECT(s), &aspeed_i2c_bus_ops,
>                             s, name, aic->reg_size);
> @@ -1016,6 +1092,7 @@ static const TypeInfo aspeed_2600_i2c_info = {
>   static void aspeed_i2c_register_types(void)
>   {
>       type_register_static(&aspeed_i2c_bus_info);
> +    type_register_static(&aspeed_i2c_slave_info);
>       type_register_static(&aspeed_i2c_info);
>       type_register_static(&aspeed_2400_i2c_info);
>       type_register_static(&aspeed_2500_i2c_info);
> diff --git a/hw/i2c/trace-events b/hw/i2c/trace-events
> index 7d8907c1eede..85e4bddff936 100644
> --- a/hw/i2c/trace-events
> +++ b/hw/i2c/trace-events
> @@ -9,7 +9,7 @@ i2c_recv(uint8_t address, uint8_t data) "recv(addr:0x%02x) data:0x%02x"
>   # aspeed_i2c.c
>   
>   aspeed_i2c_bus_cmd(uint32_t cmd, const char *cmd_flags, uint32_t count, uint32_t intr_status) "handling cmd=0x%x %s count=%d intr=0x%x"
> -aspeed_i2c_bus_raise_interrupt(uint32_t intr_status, const char *str1, const char *str2, const char *str3, const char *str4, const char *str5) "handled intr=0x%x %s%s%s%s%s"
> +aspeed_i2c_bus_raise_interrupt(uint32_t intr_status, const char *str1, const char *str2, const char *str3, const char *str4, const char *str5, const char *str6) "handled intr=0x%x %s%s%s%s%s%s"
>   aspeed_i2c_bus_read(uint32_t busid, uint64_t offset, unsigned size, uint64_t value) "bus[%d]: To 0x%" PRIx64 " of size %u: 0x%" PRIx64
>   aspeed_i2c_bus_write(uint32_t busid, uint64_t offset, unsigned size, uint64_t value) "bus[%d]: To 0x%" PRIx64 " of size %u: 0x%" PRIx64
>   aspeed_i2c_bus_send(const char *mode, int i, int count, uint8_t byte) "%s send %d/%d 0x%02x"
> diff --git a/hw/misc/meson.build b/hw/misc/meson.build
> index 6fb69612e064..c1c1abea41dd 100644
> --- a/hw/misc/meson.build
> +++ b/hw/misc/meson.build
> @@ -122,6 +122,8 @@ softmmu_ss.add(when: 'CONFIG_NRF51_SOC', if_true: files('nrf51_rng.c'))
>   
>   softmmu_ss.add(when: 'CONFIG_GRLIB', if_true: files('grlib_ahb_apb_pnp.c'))
>   
> +softmmu_ss.add(when: 'CONFIG_I2C', if_true: files('i2c-echo.c'))

That's for another patch.

> +
>   specific_ss.add(when: 'CONFIG_AVR_POWER', if_true: files('avr_power.c'))
>   
>   specific_ss.add(when: 'CONFIG_IMX', if_true: files('imx6_src.c'))
> diff --git a/include/hw/i2c/aspeed_i2c.h b/include/hw/i2c/aspeed_i2c.h
> index 4b9be09274c7..3f1a9c07a00b 100644
> --- a/include/hw/i2c/aspeed_i2c.h
> +++ b/include/hw/i2c/aspeed_i2c.h
> @@ -42,6 +42,7 @@ struct AspeedI2CBus {
>       SysBusDevice parent_obj;
>   
>       struct AspeedI2CState *controller;
> +    struct AspeedI2CSlave *slave;
>   
>       MemoryRegion mr;
>   
> @@ -53,6 +54,7 @@ struct AspeedI2CBus {
>       uint32_t timing[2];
>       uint32_t intr_ctrl;
>       uint32_t intr_status;
> +    uint32_t dev_addr;
>       uint32_t cmd;
>       uint32_t buf;
>       uint32_t pool_ctrl;
> @@ -76,6 +78,12 @@ struct AspeedI2CState {
>       AddressSpace dram_as;
>   };
>   
> +#define TYPE_ASPEED_I2C_SLAVE "aspeed.i2c.slave"
> +OBJECT_DECLARE_SIMPLE_TYPE(AspeedI2CSlave, ASPEED_I2C_SLAVE)
> +struct AspeedI2CSlave {
> +    I2CSlave i2c;
> +    AspeedI2CBus *bus;
> +};

AFAICT, AspeedI2CSlave is not that useful since it doesn't maintain any
state. The QOM interface proposal looks like a better approach.

>   struct AspeedI2CClass {
>       SysBusDeviceClass parent_class;


If you could send these 3 patches :
  
   - aspeed_i2c_bus_raise_interrupt trace event rework
   - intr_ctrl_mask class attribute
   - dev_addr support

I will queue them quickly and we will focus on adding slave support only.


Thanks,

C.


  parent reply	other threads:[~2022-04-06  6:56 UTC|newest]

Thread overview: 24+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2022-03-31 16:57 [RFC PATCH 0/4] hw/i2c: i2c slave mode support Klaus Jensen
2022-03-31 16:57 ` [RFC PATCH 1/4] hw/i2c: support multiple masters Klaus Jensen
2022-03-31 16:57 ` [RFC PATCH 2/4] hw/i2c: add async send Klaus Jensen
2022-03-31 16:57 ` [RFC PATCH 3/4] hw/i2c: add slave mode for aspeed_i2c Klaus Jensen
2022-03-31 20:44   ` Philippe Mathieu-Daudé
2022-04-01  6:30     ` Klaus Jensen
2022-04-06  6:14   ` Cédric Le Goater [this message]
2022-04-06  7:40     ` Klaus Jensen
2022-04-06  8:52       ` Cédric Le Goater
2022-04-06  9:16         ` Klaus Jensen
2022-04-06  9:44           ` Cédric Le Goater
2022-03-31 16:57 ` [RFC PATCH 4/4] hw/misc: add a toy i2c echo device Klaus Jensen
2022-03-31 20:32 ` [RFC PATCH 0/4] hw/i2c: i2c slave mode support Corey Minyard
2022-04-01  6:29   ` Klaus Jensen
2022-04-01  8:58     ` Damien Hedde
2022-04-01  9:05       ` Klaus Jensen
2022-04-01 13:06     ` Corey Minyard
2022-04-05 20:52 ` Peter Delevoryas
2022-04-06  6:07   ` Klaus Jensen
2022-04-06 17:03     ` Peter Delevoryas
2022-04-06 18:41       ` Klaus Jensen
2022-04-06 22:06         ` Peter Delevoryas
2022-05-06 14:07 ` Jonathan Cameron via
2022-05-06 16:49   ` Cédric Le Goater

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=356b3f59-b915-3da1-7155-8082b55932fb@kaod.org \
    --to=clg@kaod.org \
    --cc=andrew@aj.id.au \
    --cc=arun.kka@samsung.com \
    --cc=cminyard@mvista.com \
    --cc=its@irrelevant.dk \
    --cc=jk@ozlabs.org \
    --cc=joel@jms.id.au \
    --cc=k.jensen@samsung.com \
    --cc=matt@codeconstruct.com.au \
    --cc=p.kalghatgi@samsung.com \
    --cc=peter.maydell@linaro.org \
    --cc=qemu-arm@nongnu.org \
    --cc=qemu-devel@nongnu.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
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).