diff options
author | Richard Henderson | 2022-06-30 18:34:12 +0200 |
---|---|---|
committer | Richard Henderson | 2022-06-30 18:34:12 +0200 |
commit | d495e432c04a6394126c35cf96517749708b410f (patch) | |
tree | 847312bcb99b4f486ed20bae9dfd4aaf76bef4fc /hw/i2c/core.c | |
parent | Merge tag 'trivial-branch-for-7.1-pull-request' of https://gitlab.com/laurent... (diff) | |
parent | hw/misc/aspeed: Add PECI controller (diff) | |
download | qemu-d495e432c04a6394126c35cf96517749708b410f.tar.gz qemu-d495e432c04a6394126c35cf96517749708b410f.tar.xz qemu-d495e432c04a6394126c35cf96517749708b410f.zip |
Merge tag 'pull-aspeed-20220630' of https://github.com/legoater/qemu into staging
aspeed queue:
* m25p80 improvements (Iris)
* Code cleanup in preparation of multi SoC machine (Peter)
* New MAX31785 model (Mahesh)
* New Qualcomm machines (Jae and Graeme)
* Core I2C slave mode (Klaus)
* Aspeed I2C slave mode for old and new register interface (Peter and Klaus)
* New Aspeed PECI model (Peter)
* Various small fixes
# -----BEGIN PGP SIGNATURE-----
#
# iQIzBAABCAAdFiEEoPZlSPBIlev+awtgUaNDx8/77KEFAmK9UfQACgkQUaNDx8/7
# 7KFYWhAAtlx3aaEacrn/ONNHjk6G9Fxku56gAbaIiuiaIWNOj3/T2frPsnmbO8x8
# EKrgUYB8i8PFve/fJYA5vZUzIddPTaHkULZ12JQoGVg0L9hDBbizslN5lJWRXoSv
# 9r3DF9nahzLKRNvzoBfuKjHDQ2cwHoFgYmKmlYpDcgfmBcl16uzZy8jvxg/Tghur
# umH4IJMjeDNz/kLfINoO/m+kuFPVXmbTJNwl8uK5MUVDTgVSqharywWlUizugBVH
# StLE+GmBPylTuYXyiOzLTkoGJeeHp3sQ1DmyI4DD83odjnfxa0BGMGDVhD35exXi
# 9tLY9FgQ4smATuyN0UGAKZTBmzpI+ov0HMzvH4lUMR8i8daBuEet3RVr/DqkOP4h
# LEVTRWTaTJip24ohgw4K/b86pI9nTJWVPGV56eZGYmnqufnvf/upNU65/nCsF/xD
# i1TdS+zJWxhjgGEepg9cTmxxUlA4jVNNbl6dvAgS5Jr6Igrd1BlCSXjmyhO3NRPZ
# bgOuvCb3RyxAY4+/9wphx2/t5X2VIU6R8EAjnh+7nIgBhOQU5SZ6uefFVYZq8xx+
# IYEDHj3saiRa4FHmyOgeRxRaQj/Vvs83PPti2rPmJuieqiClJmbE+XfTIamoxVIv
# 5USlKmMRRVI69MjsjwFi/gOaV/N1EUgcFoYbnvwZ+Md3fg5+70M=
# =oUKu
# -----END PGP SIGNATURE-----
# gpg: Signature made Thu 30 Jun 2022 01:04:12 PM +0530
# gpg: using RSA key A0F66548F04895EBFE6B0B6051A343C7CFFBECA1
# gpg: Good signature from "Cédric Le Goater <clg@kaod.org>" [undefined]
# gpg: WARNING: This key is not certified with a trusted signature!
# gpg: There is no indication that the signature belongs to the owner.
# Primary key fingerprint: A0F6 6548 F048 95EB FE6B 0B60 51A3 43C7 CFFB ECA1
* tag 'pull-aspeed-20220630' of https://github.com/legoater/qemu: (27 commits)
hw/misc/aspeed: Add PECI controller
hw/i2c/aspeed: Add new-registers DMA slave mode RX support
hw/i2c/aspeed: add slave device in old register mode
hw/i2c: add asynchronous send
hw/i2c: support multiple masters
hw/i2c/aspeed: Fix MASTER_EN missing error message
hw/i2c/aspeed: Fix DMA len write-enable bit handling
hw/i2c/aspeed: Fix R_I2CD_FUN_CTRL reference
hw/arm/aspeed: firework: add I2C MUXes for VR channels
hw/arm/aspeed: firework: Add Thermal Diodes
hw/arm/aspeed: Add MAX31785 Fan controllers
hw/sensor: add Maxim MAX31785 device
hw/i2c: pmbus: Page #255 is valid page for read requests.
hw/arm/aspeed: add Qualcomm Firework BMC machine
hw/arm/aspeed: add support for the Qualcomm DC-SCM v1 board
aspeed: Remove use of qemu_get_cpu
aspeed: Map unimplemented devices in SoC memory
aspeed: Remove usage of sysbus_mmio_map
aspeed: Add memory property to Aspeed SoC
aspeed: Set CPU memory property explicitly
...
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
Diffstat (limited to 'hw/i2c/core.c')
-rw-r--r-- | hw/i2c/core.c | 70 |
1 files changed, 68 insertions, 2 deletions
diff --git a/hw/i2c/core.c b/hw/i2c/core.c index d0cb2d32fa..d4ba8146bf 100644 --- a/hw/i2c/core.c +++ b/hw/i2c/core.c @@ -13,6 +13,7 @@ #include "migration/vmstate.h" #include "qapi/error.h" #include "qemu/module.h" +#include "qemu/main-loop.h" #include "trace.h" #define I2C_BROADCAST 0x00 @@ -62,6 +63,7 @@ I2CBus *i2c_init_bus(DeviceState *parent, const char *name) bus = I2C_BUS(qbus_new(TYPE_I2C_BUS, parent, name)); QLIST_INIT(&bus->current_devs); + QSIMPLEQ_INIT(&bus->pending_masters); vmstate_register(NULL, VMSTATE_INSTANCE_ID_ANY, &vmstate_i2c_bus, bus); return bus; } @@ -74,7 +76,7 @@ void i2c_slave_set_address(I2CSlave *dev, uint8_t address) /* Return nonzero if bus is busy. */ int i2c_bus_busy(I2CBus *bus) { - return !QLIST_EMPTY(&bus->current_devs); + return !QLIST_EMPTY(&bus->current_devs) || bus->bh; } bool i2c_scan_bus(I2CBus *bus, uint8_t address, bool broadcast, @@ -159,7 +161,8 @@ static int i2c_do_start_transfer(I2CBus *bus, uint8_t address, start condition. */ if (sc->event) { - trace_i2c_event("start", s->address); + trace_i2c_event(event == I2C_START_SEND ? "start" : "start_async", + s->address); rv = sc->event(s, event); if (rv && !bus->broadcast) { if (bus_scanned) { @@ -180,6 +183,26 @@ int i2c_start_transfer(I2CBus *bus, uint8_t address, bool is_recv) : I2C_START_SEND); } +void i2c_bus_master(I2CBus *bus, QEMUBH *bh) +{ + if (i2c_bus_busy(bus)) { + I2CPendingMaster *node = g_new(struct I2CPendingMaster, 1); + node->bh = bh; + + QSIMPLEQ_INSERT_TAIL(&bus->pending_masters, node, entry); + + return; + } + + bus->bh = bh; + qemu_bh_schedule(bus->bh); +} + +void i2c_bus_release(I2CBus *bus) +{ + bus->bh = NULL; +} + int i2c_start_recv(I2CBus *bus, uint8_t address) { return i2c_do_start_transfer(bus, address, I2C_START_RECV); @@ -190,6 +213,11 @@ int i2c_start_send(I2CBus *bus, uint8_t address) return i2c_do_start_transfer(bus, address, I2C_START_SEND); } +int i2c_start_send_async(I2CBus *bus, uint8_t address) +{ + return i2c_do_start_transfer(bus, address, I2C_START_SEND_ASYNC); +} + void i2c_end_transfer(I2CBus *bus) { I2CSlaveClass *sc; @@ -206,6 +234,16 @@ void i2c_end_transfer(I2CBus *bus) g_free(node); } bus->broadcast = false; + + if (!QSIMPLEQ_EMPTY(&bus->pending_masters)) { + I2CPendingMaster *node = QSIMPLEQ_FIRST(&bus->pending_masters); + bus->bh = node->bh; + + QSIMPLEQ_REMOVE_HEAD(&bus->pending_masters, entry); + g_free(node); + + qemu_bh_schedule(bus->bh); + } } int i2c_send(I2CBus *bus, uint8_t data) @@ -229,6 +267,23 @@ int i2c_send(I2CBus *bus, uint8_t data) return ret ? -1 : 0; } +int i2c_send_async(I2CBus *bus, uint8_t data) +{ + I2CNode *node = QLIST_FIRST(&bus->current_devs); + I2CSlave *slave = node->elt; + I2CSlaveClass *sc = I2C_SLAVE_GET_CLASS(slave); + + if (!sc->send_async) { + return -1; + } + + trace_i2c_send_async(slave->address, data); + + sc->send_async(slave, data); + + return 0; +} + uint8_t i2c_recv(I2CBus *bus) { uint8_t data = 0xff; @@ -265,6 +320,17 @@ void i2c_nack(I2CBus *bus) } } +void i2c_ack(I2CBus *bus) +{ + if (!bus->bh) { + return; + } + + trace_i2c_ack(); + + qemu_bh_schedule(bus->bh); +} + static int i2c_slave_post_load(void *opaque, int version_id) { I2CSlave *dev = opaque; |