116020011SCédric Le Goater /* 216020011SCédric Le Goater * ARM Aspeed I2C controller 316020011SCédric Le Goater * 416020011SCédric Le Goater * Copyright (C) 2016 IBM Corp. 516020011SCédric Le Goater * 616020011SCédric Le Goater * This program is free software; you can redistribute it and/or 716020011SCédric Le Goater * modify it under the terms of the GNU General Public License 816020011SCédric Le Goater * as published by the Free Software Foundation; either version 2 916020011SCédric Le Goater * of the License, or (at your option) any later version. 1016020011SCédric Le Goater * 1116020011SCédric Le Goater * This program is distributed in the hope that it will be useful, 1216020011SCédric Le Goater * but WITHOUT ANY WARRANTY; without even the implied warranty of 1316020011SCédric Le Goater * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 1416020011SCédric Le Goater * GNU General Public License for more details. 1516020011SCédric Le Goater * 1616020011SCédric Le Goater * You should have received a copy of the GNU General Public License 1716020011SCédric Le Goater * along with this program; if not, see <http://www.gnu.org/licenses/>. 1816020011SCédric Le Goater * 1916020011SCédric Le Goater */ 2016020011SCédric Le Goater 2116020011SCédric Le Goater #include "qemu/osdep.h" 2216020011SCédric Le Goater #include "hw/sysbus.h" 23d6454270SMarkus Armbruster #include "migration/vmstate.h" 24b03ec4ffSKlaus Jensen #include "qemu/cutils.h" 2516020011SCédric Le Goater #include "qemu/log.h" 260b8fa32fSMarkus Armbruster #include "qemu/module.h" 27545d6befSCédric Le Goater #include "qemu/error-report.h" 28545d6befSCédric Le Goater #include "qapi/error.h" 2916020011SCédric Le Goater #include "hw/i2c/aspeed_i2c.h" 3064552b6bSMarkus Armbruster #include "hw/irq.h" 31545d6befSCédric Le Goater #include "hw/qdev-properties.h" 323be3d6ccSJoe Komlodi #include "hw/registerfields.h" 3366cc84a1SCédric Le Goater #include "trace.h" 3416020011SCédric Le Goater 3533e30f11SCédric Le Goater /* Enable SLAVE_ADDR_RX_MATCH always */ 3633e30f11SCédric Le Goater #define R_I2CD_INTR_STS_ALWAYS_ENABLE R_I2CD_INTR_STS_SLAVE_ADDR_RX_MATCH_MASK 3733e30f11SCédric Le Goater 3816020011SCédric Le Goater static inline void aspeed_i2c_bus_raise_interrupt(AspeedI2CBus *bus) 3916020011SCédric Le Goater { 4051dd4923SCédric Le Goater AspeedI2CClass *aic = ASPEED_I2C_GET_CLASS(bus->controller); 41ba2cccd6SJoe Komlodi uint32_t reg_intr_sts = aspeed_i2c_bus_intr_sts_offset(bus); 42ba2cccd6SJoe Komlodi uint32_t intr_ctrl_reg = aspeed_i2c_bus_intr_ctrl_offset(bus); 4333e30f11SCédric Le Goater uint32_t intr_ctrl_mask = bus->regs[intr_ctrl_reg] | 4433e30f11SCédric Le Goater R_I2CD_INTR_STS_ALWAYS_ENABLE; 45ba2cccd6SJoe Komlodi bool raise_irq; 4651dd4923SCédric Le Goater 47b03ec4ffSKlaus Jensen if (trace_event_get_state_backends(TRACE_ASPEED_I2C_BUS_RAISE_INTERRUPT)) { 4833e30f11SCédric Le Goater g_autofree char *buf = g_strdup_printf("%s%s%s%s%s%s%s", 490efec47bSJoe Komlodi aspeed_i2c_bus_pkt_mode_en(bus) && 500efec47bSJoe Komlodi ARRAY_FIELD_EX32(bus->regs, I2CM_INTR_STS, PKT_CMD_DONE) ? 510efec47bSJoe Komlodi "pktdone|" : "", 52b03ec4ffSKlaus Jensen SHARED_ARRAY_FIELD_EX32(bus->regs, reg_intr_sts, TX_NAK) ? 53b03ec4ffSKlaus Jensen "nak|" : "", 54b03ec4ffSKlaus Jensen SHARED_ARRAY_FIELD_EX32(bus->regs, reg_intr_sts, TX_ACK) ? 55b03ec4ffSKlaus Jensen "ack|" : "", 56b03ec4ffSKlaus Jensen SHARED_ARRAY_FIELD_EX32(bus->regs, reg_intr_sts, RX_DONE) ? 57b03ec4ffSKlaus Jensen "done|" : "", 5833e30f11SCédric Le Goater ARRAY_FIELD_EX32(bus->regs, I2CD_INTR_STS, SLAVE_ADDR_RX_MATCH) ? 5933e30f11SCédric Le Goater "slave-match|" : "", 60ba2cccd6SJoe Komlodi SHARED_ARRAY_FIELD_EX32(bus->regs, reg_intr_sts, NORMAL_STOP) ? 616743af9bSCédric Le Goater "stop|" : "", 62b03ec4ffSKlaus Jensen SHARED_ARRAY_FIELD_EX32(bus->regs, reg_intr_sts, ABNORMAL) ? 63b03ec4ffSKlaus Jensen "abnormal" : ""); 64b03ec4ffSKlaus Jensen 65b03ec4ffSKlaus Jensen trace_aspeed_i2c_bus_raise_interrupt(bus->regs[reg_intr_sts], buf); 66b03ec4ffSKlaus Jensen } 67b03ec4ffSKlaus Jensen 6833e30f11SCédric Le Goater raise_irq = bus->regs[reg_intr_sts] & intr_ctrl_mask ; 69b03ec4ffSKlaus Jensen 70ba2cccd6SJoe Komlodi /* In packet mode we don't mask off INTR_STS */ 71ba2cccd6SJoe Komlodi if (!aspeed_i2c_bus_pkt_mode_en(bus)) { 7233e30f11SCédric Le Goater bus->regs[reg_intr_sts] &= intr_ctrl_mask; 73ba2cccd6SJoe Komlodi } 74b03ec4ffSKlaus Jensen 75ba2cccd6SJoe Komlodi if (raise_irq) { 7616020011SCédric Le Goater bus->controller->intr_status |= 1 << bus->id; 7751dd4923SCédric Le Goater qemu_irq_raise(aic->bus_get_irq(bus)); 7816020011SCédric Le Goater } 7916020011SCédric Le Goater } 8016020011SCédric Le Goater 811c5d909fSPeter Delevoryas static inline void aspeed_i2c_bus_raise_slave_interrupt(AspeedI2CBus *bus) 821c5d909fSPeter Delevoryas { 831c5d909fSPeter Delevoryas AspeedI2CClass *aic = ASPEED_I2C_GET_CLASS(bus->controller); 841c5d909fSPeter Delevoryas 851c5d909fSPeter Delevoryas if (!bus->regs[R_I2CS_INTR_STS]) { 861c5d909fSPeter Delevoryas return; 871c5d909fSPeter Delevoryas } 881c5d909fSPeter Delevoryas 891c5d909fSPeter Delevoryas bus->controller->intr_status |= 1 << bus->id; 901c5d909fSPeter Delevoryas qemu_irq_raise(aic->bus_get_irq(bus)); 911c5d909fSPeter Delevoryas } 921c5d909fSPeter Delevoryas 93ba2cccd6SJoe Komlodi static uint64_t aspeed_i2c_bus_old_read(AspeedI2CBus *bus, hwaddr offset, 9416020011SCédric Le Goater unsigned size) 9516020011SCédric Le Goater { 96545d6befSCédric Le Goater AspeedI2CClass *aic = ASPEED_I2C_GET_CLASS(bus->controller); 972260fc6fSJoe Komlodi uint64_t value = bus->regs[offset / sizeof(*bus->regs)]; 9816020011SCédric Le Goater 9916020011SCédric Le Goater switch (offset) { 1003be3d6ccSJoe Komlodi case A_I2CD_FUN_CTRL: 1013be3d6ccSJoe Komlodi case A_I2CD_AC_TIMING1: 1023be3d6ccSJoe Komlodi case A_I2CD_AC_TIMING2: 1033be3d6ccSJoe Komlodi case A_I2CD_INTR_CTRL: 1043be3d6ccSJoe Komlodi case A_I2CD_INTR_STS: 105d72a712cSKlaus Jensen case A_I2CD_DEV_ADDR: 1063be3d6ccSJoe Komlodi case A_I2CD_POOL_CTRL: 1073be3d6ccSJoe Komlodi case A_I2CD_BYTE_BUF: 1082260fc6fSJoe Komlodi /* Value is already set, don't do anything. */ 10966cc84a1SCédric Le Goater break; 1103be3d6ccSJoe Komlodi case A_I2CD_CMD: 111ba2cccd6SJoe Komlodi value = SHARED_FIELD_DP32(value, BUS_BUSY_STS, i2c_bus_busy(bus->bus)); 11266cc84a1SCédric Le Goater break; 1133be3d6ccSJoe Komlodi case A_I2CD_DMA_ADDR: 114545d6befSCédric Le Goater if (!aic->has_dma) { 115545d6befSCédric Le Goater qemu_log_mask(LOG_GUEST_ERROR, "%s: No DMA support\n", __func__); 1162260fc6fSJoe Komlodi value = -1; 117545d6befSCédric Le Goater } 11866cc84a1SCédric Le Goater break; 1193be3d6ccSJoe Komlodi case A_I2CD_DMA_LEN: 120545d6befSCédric Le Goater if (!aic->has_dma) { 121545d6befSCédric Le Goater qemu_log_mask(LOG_GUEST_ERROR, "%s: No DMA support\n", __func__); 1222260fc6fSJoe Komlodi value = -1; 123545d6befSCédric Le Goater } 12466cc84a1SCédric Le Goater break; 12566cc84a1SCédric Le Goater 12616020011SCédric Le Goater default: 12716020011SCédric Le Goater qemu_log_mask(LOG_GUEST_ERROR, 12816020011SCédric Le Goater "%s: Bad offset 0x%" HWADDR_PRIx "\n", __func__, offset); 12966cc84a1SCédric Le Goater value = -1; 13066cc84a1SCédric Le Goater break; 13116020011SCédric Le Goater } 13266cc84a1SCédric Le Goater 13366cc84a1SCédric Le Goater trace_aspeed_i2c_bus_read(bus->id, offset, size, value); 13466cc84a1SCédric Le Goater return value; 13516020011SCédric Le Goater } 13616020011SCédric Le Goater 137ba2cccd6SJoe Komlodi static uint64_t aspeed_i2c_bus_new_read(AspeedI2CBus *bus, hwaddr offset, 138ba2cccd6SJoe Komlodi unsigned size) 139ba2cccd6SJoe Komlodi { 140ba2cccd6SJoe Komlodi uint64_t value = bus->regs[offset / sizeof(*bus->regs)]; 141ba2cccd6SJoe Komlodi 142ba2cccd6SJoe Komlodi switch (offset) { 143ba2cccd6SJoe Komlodi case A_I2CC_FUN_CTRL: 144ba2cccd6SJoe Komlodi case A_I2CC_AC_TIMING: 145ba2cccd6SJoe Komlodi case A_I2CC_POOL_CTRL: 146ba2cccd6SJoe Komlodi case A_I2CM_INTR_CTRL: 147ba2cccd6SJoe Komlodi case A_I2CM_INTR_STS: 148ba2cccd6SJoe Komlodi case A_I2CC_MS_TXRX_BYTE_BUF: 149ba2cccd6SJoe Komlodi case A_I2CM_DMA_LEN: 150ba2cccd6SJoe Komlodi case A_I2CM_DMA_TX_ADDR: 151ba2cccd6SJoe Komlodi case A_I2CM_DMA_RX_ADDR: 152ba2cccd6SJoe Komlodi case A_I2CM_DMA_LEN_STS: 153ba2cccd6SJoe Komlodi case A_I2CC_DMA_ADDR: 154ba2cccd6SJoe Komlodi case A_I2CC_DMA_LEN: 1551c5d909fSPeter Delevoryas 1561c5d909fSPeter Delevoryas case A_I2CS_DEV_ADDR: 1571c5d909fSPeter Delevoryas case A_I2CS_DMA_RX_ADDR: 1581c5d909fSPeter Delevoryas case A_I2CS_DMA_LEN: 1591c5d909fSPeter Delevoryas case A_I2CS_CMD: 1601c5d909fSPeter Delevoryas case A_I2CS_INTR_CTRL: 1611c5d909fSPeter Delevoryas case A_I2CS_DMA_LEN_STS: 162ba2cccd6SJoe Komlodi /* Value is already set, don't do anything. */ 163ba2cccd6SJoe Komlodi break; 1641c5d909fSPeter Delevoryas case A_I2CS_INTR_STS: 1651c5d909fSPeter Delevoryas break; 166ba2cccd6SJoe Komlodi case A_I2CM_CMD: 167ba2cccd6SJoe Komlodi value = SHARED_FIELD_DP32(value, BUS_BUSY_STS, i2c_bus_busy(bus->bus)); 168ba2cccd6SJoe Komlodi break; 169ba2cccd6SJoe Komlodi default: 170ba2cccd6SJoe Komlodi qemu_log_mask(LOG_GUEST_ERROR, 171ba2cccd6SJoe Komlodi "%s: Bad offset 0x%" HWADDR_PRIx "\n", __func__, offset); 172ba2cccd6SJoe Komlodi value = -1; 173ba2cccd6SJoe Komlodi break; 174ba2cccd6SJoe Komlodi } 175ba2cccd6SJoe Komlodi 176ba2cccd6SJoe Komlodi trace_aspeed_i2c_bus_read(bus->id, offset, size, value); 177ba2cccd6SJoe Komlodi return value; 178ba2cccd6SJoe Komlodi } 179ba2cccd6SJoe Komlodi 180ba2cccd6SJoe Komlodi static uint64_t aspeed_i2c_bus_read(void *opaque, hwaddr offset, 181ba2cccd6SJoe Komlodi unsigned size) 182ba2cccd6SJoe Komlodi { 183ba2cccd6SJoe Komlodi AspeedI2CBus *bus = opaque; 184ba2cccd6SJoe Komlodi if (aspeed_i2c_is_new_mode(bus->controller)) { 185ba2cccd6SJoe Komlodi return aspeed_i2c_bus_new_read(bus, offset, size); 186ba2cccd6SJoe Komlodi } 187ba2cccd6SJoe Komlodi return aspeed_i2c_bus_old_read(bus, offset, size); 188ba2cccd6SJoe Komlodi } 189ba2cccd6SJoe Komlodi 1904960f084SCédric Le Goater static void aspeed_i2c_set_state(AspeedI2CBus *bus, uint8_t state) 1914960f084SCédric Le Goater { 192ba2cccd6SJoe Komlodi if (aspeed_i2c_is_new_mode(bus->controller)) { 193ba2cccd6SJoe Komlodi SHARED_ARRAY_FIELD_DP32(bus->regs, R_I2CC_MS_TXRX_BYTE_BUF, TX_STATE, 194ba2cccd6SJoe Komlodi state); 195ba2cccd6SJoe Komlodi } else { 196ba2cccd6SJoe Komlodi SHARED_ARRAY_FIELD_DP32(bus->regs, R_I2CD_CMD, TX_STATE, state); 197ba2cccd6SJoe Komlodi } 1984960f084SCédric Le Goater } 1994960f084SCédric Le Goater 2004960f084SCédric Le Goater static uint8_t aspeed_i2c_get_state(AspeedI2CBus *bus) 2014960f084SCédric Le Goater { 202ba2cccd6SJoe Komlodi if (aspeed_i2c_is_new_mode(bus->controller)) { 203ba2cccd6SJoe Komlodi return SHARED_ARRAY_FIELD_EX32(bus->regs, R_I2CC_MS_TXRX_BYTE_BUF, 204ba2cccd6SJoe Komlodi TX_STATE); 205ba2cccd6SJoe Komlodi } 206ba2cccd6SJoe Komlodi return SHARED_ARRAY_FIELD_EX32(bus->regs, R_I2CD_CMD, TX_STATE); 2074960f084SCédric Le Goater } 2084960f084SCédric Le Goater 209545d6befSCédric Le Goater static int aspeed_i2c_dma_read(AspeedI2CBus *bus, uint8_t *data) 210545d6befSCédric Le Goater { 211545d6befSCédric Le Goater MemTxResult result; 212545d6befSCédric Le Goater AspeedI2CState *s = bus->controller; 213ba2cccd6SJoe Komlodi uint32_t reg_dma_addr = aspeed_i2c_bus_dma_addr_offset(bus); 214ba2cccd6SJoe Komlodi uint32_t reg_dma_len = aspeed_i2c_bus_dma_len_offset(bus); 215545d6befSCédric Le Goater 216ba2cccd6SJoe Komlodi result = address_space_read(&s->dram_as, bus->regs[reg_dma_addr], 217545d6befSCédric Le Goater MEMTXATTRS_UNSPECIFIED, data, 1); 218545d6befSCédric Le Goater if (result != MEMTX_OK) { 219545d6befSCédric Le Goater qemu_log_mask(LOG_GUEST_ERROR, "%s: DRAM read failed @%08x\n", 220ba2cccd6SJoe Komlodi __func__, bus->regs[reg_dma_addr]); 221545d6befSCédric Le Goater return -1; 222545d6befSCédric Le Goater } 223545d6befSCédric Le Goater 224ba2cccd6SJoe Komlodi bus->regs[reg_dma_addr]++; 225ba2cccd6SJoe Komlodi bus->regs[reg_dma_len]--; 226545d6befSCédric Le Goater return 0; 227545d6befSCédric Le Goater } 228545d6befSCédric Le Goater 2296054fc73SCédric Le Goater static int aspeed_i2c_bus_send(AspeedI2CBus *bus, uint8_t pool_start) 2306054fc73SCédric Le Goater { 2316054fc73SCédric Le Goater AspeedI2CClass *aic = ASPEED_I2C_GET_CLASS(bus->controller); 2326054fc73SCédric Le Goater int ret = -1; 2336054fc73SCédric Le Goater int i; 234ba2cccd6SJoe Komlodi uint32_t reg_cmd = aspeed_i2c_bus_cmd_offset(bus); 235ba2cccd6SJoe Komlodi uint32_t reg_pool_ctrl = aspeed_i2c_bus_pool_ctrl_offset(bus); 236ba2cccd6SJoe Komlodi uint32_t reg_byte_buf = aspeed_i2c_bus_byte_buf_offset(bus); 237ba2cccd6SJoe Komlodi uint32_t reg_dma_len = aspeed_i2c_bus_dma_len_offset(bus); 238ba2cccd6SJoe Komlodi int pool_tx_count = SHARED_ARRAY_FIELD_EX32(bus->regs, reg_pool_ctrl, 239ba2cccd6SJoe Komlodi TX_COUNT); 2406054fc73SCédric Le Goater 241ba2cccd6SJoe Komlodi if (SHARED_ARRAY_FIELD_EX32(bus->regs, reg_cmd, TX_BUFF_EN)) { 2423be3d6ccSJoe Komlodi for (i = pool_start; i < pool_tx_count; i++) { 2436054fc73SCédric Le Goater uint8_t *pool_base = aic->bus_pool_base(bus); 2446054fc73SCédric Le Goater 2453be3d6ccSJoe Komlodi trace_aspeed_i2c_bus_send("BUF", i + 1, pool_tx_count, 24666cc84a1SCédric Le Goater pool_base[i]); 2476054fc73SCédric Le Goater ret = i2c_send(bus->bus, pool_base[i]); 2486054fc73SCédric Le Goater if (ret) { 2496054fc73SCédric Le Goater break; 2506054fc73SCédric Le Goater } 2516054fc73SCédric Le Goater } 252ba2cccd6SJoe Komlodi SHARED_ARRAY_FIELD_DP32(bus->regs, reg_cmd, TX_BUFF_EN, 0); 253ba2cccd6SJoe Komlodi } else if (SHARED_ARRAY_FIELD_EX32(bus->regs, reg_cmd, TX_DMA_EN)) { 254ba2cccd6SJoe Komlodi /* In new mode, clear how many bytes we TXed */ 255ba2cccd6SJoe Komlodi if (aspeed_i2c_is_new_mode(bus->controller)) { 256ba2cccd6SJoe Komlodi ARRAY_FIELD_DP32(bus->regs, I2CM_DMA_LEN_STS, TX_LEN, 0); 257ba2cccd6SJoe Komlodi } 258ba2cccd6SJoe Komlodi while (bus->regs[reg_dma_len]) { 259545d6befSCédric Le Goater uint8_t data; 260545d6befSCédric Le Goater aspeed_i2c_dma_read(bus, &data); 261ba2cccd6SJoe Komlodi trace_aspeed_i2c_bus_send("DMA", bus->regs[reg_dma_len], 262ba2cccd6SJoe Komlodi bus->regs[reg_dma_len], data); 263545d6befSCédric Le Goater ret = i2c_send(bus->bus, data); 264545d6befSCédric Le Goater if (ret) { 265545d6befSCédric Le Goater break; 266545d6befSCédric Le Goater } 267ba2cccd6SJoe Komlodi /* In new mode, keep track of how many bytes we TXed */ 268ba2cccd6SJoe Komlodi if (aspeed_i2c_is_new_mode(bus->controller)) { 269ba2cccd6SJoe Komlodi ARRAY_FIELD_DP32(bus->regs, I2CM_DMA_LEN_STS, TX_LEN, 270ba2cccd6SJoe Komlodi ARRAY_FIELD_EX32(bus->regs, I2CM_DMA_LEN_STS, 271ba2cccd6SJoe Komlodi TX_LEN) + 1); 272545d6befSCédric Le Goater } 273ba2cccd6SJoe Komlodi } 274ba2cccd6SJoe Komlodi SHARED_ARRAY_FIELD_DP32(bus->regs, reg_cmd, TX_DMA_EN, 0); 2756054fc73SCédric Le Goater } else { 2762260fc6fSJoe Komlodi trace_aspeed_i2c_bus_send("BYTE", pool_start, 1, 277ba2cccd6SJoe Komlodi bus->regs[reg_byte_buf]); 278ba2cccd6SJoe Komlodi ret = i2c_send(bus->bus, bus->regs[reg_byte_buf]); 2796054fc73SCédric Le Goater } 2806054fc73SCédric Le Goater 2816054fc73SCédric Le Goater return ret; 2826054fc73SCédric Le Goater } 2836054fc73SCédric Le Goater 2846054fc73SCédric Le Goater static void aspeed_i2c_bus_recv(AspeedI2CBus *bus) 2856054fc73SCédric Le Goater { 2866054fc73SCédric Le Goater AspeedI2CState *s = bus->controller; 2876054fc73SCédric Le Goater AspeedI2CClass *aic = ASPEED_I2C_GET_CLASS(s); 2886054fc73SCédric Le Goater uint8_t data; 2896054fc73SCédric Le Goater int i; 290ba2cccd6SJoe Komlodi uint32_t reg_cmd = aspeed_i2c_bus_cmd_offset(bus); 291ba2cccd6SJoe Komlodi uint32_t reg_pool_ctrl = aspeed_i2c_bus_pool_ctrl_offset(bus); 292ba2cccd6SJoe Komlodi uint32_t reg_byte_buf = aspeed_i2c_bus_byte_buf_offset(bus); 293ba2cccd6SJoe Komlodi uint32_t reg_dma_len = aspeed_i2c_bus_dma_len_offset(bus); 294ba2cccd6SJoe Komlodi uint32_t reg_dma_addr = aspeed_i2c_bus_dma_addr_offset(bus); 295ba2cccd6SJoe Komlodi int pool_rx_count = SHARED_ARRAY_FIELD_EX32(bus->regs, reg_pool_ctrl, 296ba2cccd6SJoe Komlodi RX_COUNT); 2976054fc73SCédric Le Goater 298ba2cccd6SJoe Komlodi if (SHARED_ARRAY_FIELD_EX32(bus->regs, reg_cmd, RX_BUFF_EN)) { 2996054fc73SCédric Le Goater uint8_t *pool_base = aic->bus_pool_base(bus); 3006054fc73SCédric Le Goater 3013be3d6ccSJoe Komlodi for (i = 0; i < pool_rx_count; i++) { 3026054fc73SCédric Le Goater pool_base[i] = i2c_recv(bus->bus); 3033be3d6ccSJoe Komlodi trace_aspeed_i2c_bus_recv("BUF", i + 1, pool_rx_count, 30466cc84a1SCédric Le Goater pool_base[i]); 3056054fc73SCédric Le Goater } 3066054fc73SCédric Le Goater 3076054fc73SCédric Le Goater /* Update RX count */ 308ba2cccd6SJoe Komlodi SHARED_ARRAY_FIELD_DP32(bus->regs, reg_pool_ctrl, RX_COUNT, i & 0xff); 309ba2cccd6SJoe Komlodi SHARED_ARRAY_FIELD_DP32(bus->regs, reg_cmd, RX_BUFF_EN, 0); 310ba2cccd6SJoe Komlodi } else if (SHARED_ARRAY_FIELD_EX32(bus->regs, reg_cmd, RX_DMA_EN)) { 311545d6befSCédric Le Goater uint8_t data; 312ba2cccd6SJoe Komlodi /* In new mode, clear how many bytes we RXed */ 313ba2cccd6SJoe Komlodi if (aspeed_i2c_is_new_mode(bus->controller)) { 314ba2cccd6SJoe Komlodi ARRAY_FIELD_DP32(bus->regs, I2CM_DMA_LEN_STS, RX_LEN, 0); 315ba2cccd6SJoe Komlodi } 316545d6befSCédric Le Goater 317ba2cccd6SJoe Komlodi while (bus->regs[reg_dma_len]) { 318545d6befSCédric Le Goater MemTxResult result; 319545d6befSCédric Le Goater 320545d6befSCédric Le Goater data = i2c_recv(bus->bus); 321ba2cccd6SJoe Komlodi trace_aspeed_i2c_bus_recv("DMA", bus->regs[reg_dma_len], 322ba2cccd6SJoe Komlodi bus->regs[reg_dma_len], data); 323ba2cccd6SJoe Komlodi result = address_space_write(&s->dram_as, bus->regs[reg_dma_addr], 324545d6befSCédric Le Goater MEMTXATTRS_UNSPECIFIED, &data, 1); 325545d6befSCédric Le Goater if (result != MEMTX_OK) { 326545d6befSCédric Le Goater qemu_log_mask(LOG_GUEST_ERROR, "%s: DRAM write failed @%08x\n", 327ba2cccd6SJoe Komlodi __func__, bus->regs[reg_dma_addr]); 328545d6befSCédric Le Goater return; 329545d6befSCédric Le Goater } 330ba2cccd6SJoe Komlodi bus->regs[reg_dma_addr]++; 331ba2cccd6SJoe Komlodi bus->regs[reg_dma_len]--; 332ba2cccd6SJoe Komlodi /* In new mode, keep track of how many bytes we RXed */ 333ba2cccd6SJoe Komlodi if (aspeed_i2c_is_new_mode(bus->controller)) { 334ba2cccd6SJoe Komlodi ARRAY_FIELD_DP32(bus->regs, I2CM_DMA_LEN_STS, RX_LEN, 335ba2cccd6SJoe Komlodi ARRAY_FIELD_EX32(bus->regs, I2CM_DMA_LEN_STS, 336ba2cccd6SJoe Komlodi RX_LEN) + 1); 337545d6befSCédric Le Goater } 338ba2cccd6SJoe Komlodi } 339ba2cccd6SJoe Komlodi SHARED_ARRAY_FIELD_DP32(bus->regs, reg_cmd, RX_DMA_EN, 0); 3406054fc73SCédric Le Goater } else { 3416054fc73SCédric Le Goater data = i2c_recv(bus->bus); 342ba2cccd6SJoe Komlodi trace_aspeed_i2c_bus_recv("BYTE", 1, 1, bus->regs[reg_byte_buf]); 343ba2cccd6SJoe Komlodi SHARED_ARRAY_FIELD_DP32(bus->regs, reg_byte_buf, RX_BUF, data); 3446054fc73SCédric Le Goater } 3456054fc73SCédric Le Goater } 3466054fc73SCédric Le Goater 3477bd9c60dSGuenter Roeck static void aspeed_i2c_handle_rx_cmd(AspeedI2CBus *bus) 3487bd9c60dSGuenter Roeck { 349ba2cccd6SJoe Komlodi uint32_t reg_cmd = aspeed_i2c_bus_cmd_offset(bus); 350ba2cccd6SJoe Komlodi uint32_t reg_intr_sts = aspeed_i2c_bus_intr_sts_offset(bus); 351ba2cccd6SJoe Komlodi 3527bd9c60dSGuenter Roeck aspeed_i2c_set_state(bus, I2CD_MRXD); 3536054fc73SCédric Le Goater aspeed_i2c_bus_recv(bus); 354ba2cccd6SJoe Komlodi SHARED_ARRAY_FIELD_DP32(bus->regs, reg_intr_sts, RX_DONE, 1); 355ba2cccd6SJoe Komlodi if (SHARED_ARRAY_FIELD_EX32(bus->regs, reg_cmd, M_S_RX_CMD_LAST)) { 3567bd9c60dSGuenter Roeck i2c_nack(bus->bus); 3577bd9c60dSGuenter Roeck } 358ba2cccd6SJoe Komlodi SHARED_ARRAY_FIELD_DP32(bus->regs, reg_cmd, M_RX_CMD, 0); 359ba2cccd6SJoe Komlodi SHARED_ARRAY_FIELD_DP32(bus->regs, reg_cmd, M_S_RX_CMD_LAST, 0); 3607bd9c60dSGuenter Roeck aspeed_i2c_set_state(bus, I2CD_MACTIVE); 3617bd9c60dSGuenter Roeck } 3627bd9c60dSGuenter Roeck 3636054fc73SCédric Le Goater static uint8_t aspeed_i2c_get_addr(AspeedI2CBus *bus) 3646054fc73SCédric Le Goater { 3656054fc73SCédric Le Goater AspeedI2CClass *aic = ASPEED_I2C_GET_CLASS(bus->controller); 366ba2cccd6SJoe Komlodi uint32_t reg_byte_buf = aspeed_i2c_bus_byte_buf_offset(bus); 367ba2cccd6SJoe Komlodi uint32_t reg_cmd = aspeed_i2c_bus_cmd_offset(bus); 3686054fc73SCédric Le Goater 369ba2cccd6SJoe Komlodi if (aspeed_i2c_bus_pkt_mode_en(bus)) { 370ba2cccd6SJoe Komlodi return (ARRAY_FIELD_EX32(bus->regs, I2CM_CMD, PKT_DEV_ADDR) << 1) | 371ba2cccd6SJoe Komlodi SHARED_ARRAY_FIELD_EX32(bus->regs, reg_cmd, M_RX_CMD); 372ba2cccd6SJoe Komlodi } 373ba2cccd6SJoe Komlodi if (SHARED_ARRAY_FIELD_EX32(bus->regs, reg_cmd, TX_BUFF_EN)) { 3746054fc73SCédric Le Goater uint8_t *pool_base = aic->bus_pool_base(bus); 3756054fc73SCédric Le Goater 3766054fc73SCédric Le Goater return pool_base[0]; 377ba2cccd6SJoe Komlodi } else if (SHARED_ARRAY_FIELD_EX32(bus->regs, reg_cmd, TX_DMA_EN)) { 378545d6befSCédric Le Goater uint8_t data; 379545d6befSCédric Le Goater 380545d6befSCédric Le Goater aspeed_i2c_dma_read(bus, &data); 381545d6befSCédric Le Goater return data; 3826054fc73SCédric Le Goater } else { 383ba2cccd6SJoe Komlodi return bus->regs[reg_byte_buf]; 3846054fc73SCédric Le Goater } 3856054fc73SCédric Le Goater } 3866054fc73SCédric Le Goater 387aab90b1cSCédric Le Goater static bool aspeed_i2c_check_sram(AspeedI2CBus *bus) 388aab90b1cSCédric Le Goater { 389aab90b1cSCédric Le Goater AspeedI2CState *s = bus->controller; 390aab90b1cSCédric Le Goater AspeedI2CClass *aic = ASPEED_I2C_GET_CLASS(s); 391ba2cccd6SJoe Komlodi uint32_t reg_cmd = aspeed_i2c_bus_cmd_offset(bus); 392ba2cccd6SJoe Komlodi bool dma_en = SHARED_ARRAY_FIELD_EX32(bus->regs, reg_cmd, RX_DMA_EN) || 393ba2cccd6SJoe Komlodi SHARED_ARRAY_FIELD_EX32(bus->regs, reg_cmd, TX_DMA_EN) || 394ba2cccd6SJoe Komlodi SHARED_ARRAY_FIELD_EX32(bus->regs, reg_cmd, RX_BUFF_EN) || 395ba2cccd6SJoe Komlodi SHARED_ARRAY_FIELD_EX32(bus->regs, reg_cmd, TX_BUFF_EN); 396aab90b1cSCédric Le Goater if (!aic->check_sram) { 397aab90b1cSCédric Le Goater return true; 398aab90b1cSCédric Le Goater } 399aab90b1cSCédric Le Goater 400aab90b1cSCédric Le Goater /* 401aab90b1cSCédric Le Goater * AST2500: SRAM must be enabled before using the Buffer Pool or 402aab90b1cSCédric Le Goater * DMA mode. 403aab90b1cSCédric Le Goater */ 4043be3d6ccSJoe Komlodi if (!FIELD_EX32(s->ctrl_global, I2C_CTRL_GLOBAL, SRAM_EN) && dma_en) { 405aab90b1cSCédric Le Goater qemu_log_mask(LOG_GUEST_ERROR, "%s: SRAM is not enabled\n", __func__); 406aab90b1cSCédric Le Goater return false; 407aab90b1cSCédric Le Goater } 408aab90b1cSCédric Le Goater 409aab90b1cSCédric Le Goater return true; 410aab90b1cSCédric Le Goater } 411aab90b1cSCédric Le Goater 41266cc84a1SCédric Le Goater static void aspeed_i2c_bus_cmd_dump(AspeedI2CBus *bus) 41366cc84a1SCédric Le Goater { 414f821bac4SMiroslav Rezanina g_autofree char *cmd_flags = NULL; 41566cc84a1SCédric Le Goater uint32_t count; 416ba2cccd6SJoe Komlodi uint32_t reg_cmd = aspeed_i2c_bus_cmd_offset(bus); 417ba2cccd6SJoe Komlodi uint32_t reg_pool_ctrl = aspeed_i2c_bus_pool_ctrl_offset(bus); 418ba2cccd6SJoe Komlodi uint32_t reg_intr_sts = aspeed_i2c_bus_intr_sts_offset(bus); 419ba2cccd6SJoe Komlodi uint32_t reg_dma_len = aspeed_i2c_bus_dma_len_offset(bus); 420ba2cccd6SJoe Komlodi if (SHARED_ARRAY_FIELD_EX32(bus->regs, reg_cmd, RX_BUFF_EN)) { 421ba2cccd6SJoe Komlodi count = SHARED_ARRAY_FIELD_EX32(bus->regs, reg_pool_ctrl, TX_COUNT); 422ba2cccd6SJoe Komlodi } else if (SHARED_ARRAY_FIELD_EX32(bus->regs, reg_cmd, RX_DMA_EN)) { 423ba2cccd6SJoe Komlodi count = bus->regs[reg_dma_len]; 42466cc84a1SCédric Le Goater } else { /* BYTE mode */ 42566cc84a1SCédric Le Goater count = 1; 42666cc84a1SCédric Le Goater } 42766cc84a1SCédric Le Goater 42866cc84a1SCédric Le Goater cmd_flags = g_strdup_printf("%s%s%s%s%s%s%s%s%s", 429ba2cccd6SJoe Komlodi SHARED_ARRAY_FIELD_EX32(bus->regs, reg_cmd, M_START_CMD) ? "start|" : "", 430ba2cccd6SJoe Komlodi SHARED_ARRAY_FIELD_EX32(bus->regs, reg_cmd, RX_DMA_EN) ? "rxdma|" : "", 431ba2cccd6SJoe Komlodi SHARED_ARRAY_FIELD_EX32(bus->regs, reg_cmd, TX_DMA_EN) ? "txdma|" : "", 432ba2cccd6SJoe Komlodi SHARED_ARRAY_FIELD_EX32(bus->regs, reg_cmd, RX_BUFF_EN) ? "rxbuf|" : "", 433ba2cccd6SJoe Komlodi SHARED_ARRAY_FIELD_EX32(bus->regs, reg_cmd, TX_BUFF_EN) ? "txbuf|" : "", 434ba2cccd6SJoe Komlodi SHARED_ARRAY_FIELD_EX32(bus->regs, reg_cmd, M_TX_CMD) ? "tx|" : "", 435ba2cccd6SJoe Komlodi SHARED_ARRAY_FIELD_EX32(bus->regs, reg_cmd, M_RX_CMD) ? "rx|" : "", 436ba2cccd6SJoe Komlodi SHARED_ARRAY_FIELD_EX32(bus->regs, reg_cmd, M_S_RX_CMD_LAST) ? "last|" : "", 437ba2cccd6SJoe Komlodi SHARED_ARRAY_FIELD_EX32(bus->regs, reg_cmd, M_STOP_CMD) ? "stop|" : ""); 43866cc84a1SCédric Le Goater 439ba2cccd6SJoe Komlodi trace_aspeed_i2c_bus_cmd(bus->regs[reg_cmd], cmd_flags, count, 440ba2cccd6SJoe Komlodi bus->regs[reg_intr_sts]); 44166cc84a1SCédric Le Goater } 44266cc84a1SCédric Le Goater 4434960f084SCédric Le Goater /* 4444960f084SCédric Le Goater * The state machine needs some refinement. It is only used to track 4454960f084SCédric Le Goater * invalid STOP commands for the moment. 4464960f084SCédric Le Goater */ 44716020011SCédric Le Goater static void aspeed_i2c_bus_handle_cmd(AspeedI2CBus *bus, uint64_t value) 44816020011SCédric Le Goater { 4496054fc73SCédric Le Goater uint8_t pool_start = 0; 450ba2cccd6SJoe Komlodi uint32_t reg_intr_sts = aspeed_i2c_bus_intr_sts_offset(bus); 451ba2cccd6SJoe Komlodi uint32_t reg_cmd = aspeed_i2c_bus_cmd_offset(bus); 452ba2cccd6SJoe Komlodi uint32_t reg_pool_ctrl = aspeed_i2c_bus_pool_ctrl_offset(bus); 453ba2cccd6SJoe Komlodi uint32_t reg_dma_len = aspeed_i2c_bus_dma_len_offset(bus); 45416020011SCédric Le Goater 455aab90b1cSCédric Le Goater if (!aspeed_i2c_check_sram(bus)) { 456aab90b1cSCédric Le Goater return; 457aab90b1cSCédric Le Goater } 458aab90b1cSCédric Le Goater 45966cc84a1SCédric Le Goater if (trace_event_get_state_backends(TRACE_ASPEED_I2C_BUS_CMD)) { 46066cc84a1SCédric Le Goater aspeed_i2c_bus_cmd_dump(bus); 46166cc84a1SCédric Le Goater } 46266cc84a1SCédric Le Goater 463ba2cccd6SJoe Komlodi if (SHARED_ARRAY_FIELD_EX32(bus->regs, reg_cmd, M_START_CMD)) { 4644960f084SCédric Le Goater uint8_t state = aspeed_i2c_get_state(bus) & I2CD_MACTIVE ? 4654960f084SCédric Le Goater I2CD_MSTARTR : I2CD_MSTART; 4666054fc73SCédric Le Goater uint8_t addr; 4674960f084SCédric Le Goater 4684960f084SCédric Le Goater aspeed_i2c_set_state(bus, state); 4694960f084SCédric Le Goater 4706054fc73SCédric Le Goater addr = aspeed_i2c_get_addr(bus); 4716054fc73SCédric Le Goater if (i2c_start_transfer(bus->bus, extract32(addr, 1, 7), 4726054fc73SCédric Le Goater extract32(addr, 0, 1))) { 473ba2cccd6SJoe Komlodi SHARED_ARRAY_FIELD_DP32(bus->regs, reg_intr_sts, TX_NAK, 1); 474ba2cccd6SJoe Komlodi if (aspeed_i2c_bus_pkt_mode_en(bus)) { 475ba2cccd6SJoe Komlodi ARRAY_FIELD_DP32(bus->regs, I2CM_INTR_STS, PKT_CMD_FAIL, 1); 476ba2cccd6SJoe Komlodi } 47716020011SCédric Le Goater } else { 478ba2cccd6SJoe Komlodi /* START doesn't set TX_ACK in packet mode */ 479ba2cccd6SJoe Komlodi if (!aspeed_i2c_bus_pkt_mode_en(bus)) { 480ba2cccd6SJoe Komlodi SHARED_ARRAY_FIELD_DP32(bus->regs, reg_intr_sts, TX_ACK, 1); 481ba2cccd6SJoe Komlodi } 48216020011SCédric Le Goater } 48316020011SCédric Le Goater 484ba2cccd6SJoe Komlodi SHARED_ARRAY_FIELD_DP32(bus->regs, reg_cmd, M_START_CMD, 0); 4856054fc73SCédric Le Goater 4866054fc73SCédric Le Goater /* 4876054fc73SCédric Le Goater * The START command is also a TX command, as the slave 4886054fc73SCédric Le Goater * address is sent on the bus. Drop the TX flag if nothing 4896054fc73SCédric Le Goater * else needs to be sent in this sequence. 4906054fc73SCédric Le Goater */ 491ba2cccd6SJoe Komlodi if (SHARED_ARRAY_FIELD_EX32(bus->regs, reg_cmd, TX_BUFF_EN)) { 492ba2cccd6SJoe Komlodi if (SHARED_ARRAY_FIELD_EX32(bus->regs, reg_pool_ctrl, TX_COUNT) 493ba2cccd6SJoe Komlodi == 1) { 494ba2cccd6SJoe Komlodi SHARED_ARRAY_FIELD_DP32(bus->regs, reg_cmd, M_TX_CMD, 0); 4956054fc73SCédric Le Goater } else { 4966054fc73SCédric Le Goater /* 4976054fc73SCédric Le Goater * Increase the start index in the TX pool buffer to 4986054fc73SCédric Le Goater * skip the address byte. 4996054fc73SCédric Le Goater */ 5006054fc73SCédric Le Goater pool_start++; 5016054fc73SCédric Le Goater } 502ba2cccd6SJoe Komlodi } else if (SHARED_ARRAY_FIELD_EX32(bus->regs, reg_cmd, TX_DMA_EN)) { 503ba2cccd6SJoe Komlodi if (bus->regs[reg_dma_len] == 0) { 504ba2cccd6SJoe Komlodi SHARED_ARRAY_FIELD_DP32(bus->regs, reg_cmd, M_TX_CMD, 0); 505545d6befSCédric Le Goater } 5066054fc73SCédric Le Goater } else { 507ba2cccd6SJoe Komlodi SHARED_ARRAY_FIELD_DP32(bus->regs, reg_cmd, M_TX_CMD, 0); 5086054fc73SCédric Le Goater } 509ddabca75SCédric Le Goater 510ddabca75SCédric Le Goater /* No slave found */ 511ddabca75SCédric Le Goater if (!i2c_bus_busy(bus->bus)) { 512ba2cccd6SJoe Komlodi if (aspeed_i2c_bus_pkt_mode_en(bus)) { 513ba2cccd6SJoe Komlodi ARRAY_FIELD_DP32(bus->regs, I2CM_INTR_STS, PKT_CMD_FAIL, 1); 514ba2cccd6SJoe Komlodi ARRAY_FIELD_DP32(bus->regs, I2CM_INTR_STS, PKT_CMD_DONE, 1); 515ba2cccd6SJoe Komlodi } 516ddabca75SCédric Le Goater return; 517ddabca75SCédric Le Goater } 5184960f084SCédric Le Goater aspeed_i2c_set_state(bus, I2CD_MACTIVE); 519ddabca75SCédric Le Goater } 520ddabca75SCédric Le Goater 521ba2cccd6SJoe Komlodi if (SHARED_ARRAY_FIELD_EX32(bus->regs, reg_cmd, M_TX_CMD)) { 5224960f084SCédric Le Goater aspeed_i2c_set_state(bus, I2CD_MTXD); 5236054fc73SCédric Le Goater if (aspeed_i2c_bus_send(bus, pool_start)) { 524ba2cccd6SJoe Komlodi SHARED_ARRAY_FIELD_DP32(bus->regs, reg_intr_sts, TX_NAK, 1); 52516020011SCédric Le Goater i2c_end_transfer(bus->bus); 52616020011SCédric Le Goater } else { 527ba2cccd6SJoe Komlodi SHARED_ARRAY_FIELD_DP32(bus->regs, reg_intr_sts, TX_ACK, 1); 52816020011SCédric Le Goater } 529ba2cccd6SJoe Komlodi SHARED_ARRAY_FIELD_DP32(bus->regs, reg_cmd, M_TX_CMD, 0); 5304960f084SCédric Le Goater aspeed_i2c_set_state(bus, I2CD_MACTIVE); 531ddabca75SCédric Le Goater } 53216020011SCédric Le Goater 533ba2cccd6SJoe Komlodi if ((SHARED_ARRAY_FIELD_EX32(bus->regs, reg_cmd, M_RX_CMD) || 534ba2cccd6SJoe Komlodi SHARED_ARRAY_FIELD_EX32(bus->regs, reg_cmd, M_S_RX_CMD_LAST)) && 535ba2cccd6SJoe Komlodi !SHARED_ARRAY_FIELD_EX32(bus->regs, reg_intr_sts, RX_DONE)) { 5367bd9c60dSGuenter Roeck aspeed_i2c_handle_rx_cmd(bus); 53716020011SCédric Le Goater } 53816020011SCédric Le Goater 539ba2cccd6SJoe Komlodi if (SHARED_ARRAY_FIELD_EX32(bus->regs, reg_cmd, M_STOP_CMD)) { 5404960f084SCédric Le Goater if (!(aspeed_i2c_get_state(bus) & I2CD_MACTIVE)) { 5414960f084SCédric Le Goater qemu_log_mask(LOG_GUEST_ERROR, "%s: abnormal stop\n", __func__); 542ba2cccd6SJoe Komlodi SHARED_ARRAY_FIELD_DP32(bus->regs, reg_intr_sts, ABNORMAL, 1); 543ba2cccd6SJoe Komlodi if (aspeed_i2c_bus_pkt_mode_en(bus)) { 544ba2cccd6SJoe Komlodi ARRAY_FIELD_DP32(bus->regs, I2CM_INTR_STS, PKT_CMD_FAIL, 1); 545ba2cccd6SJoe Komlodi } 54616020011SCédric Le Goater } else { 5474960f084SCédric Le Goater aspeed_i2c_set_state(bus, I2CD_MSTOP); 54816020011SCédric Le Goater i2c_end_transfer(bus->bus); 549ba2cccd6SJoe Komlodi SHARED_ARRAY_FIELD_DP32(bus->regs, reg_intr_sts, NORMAL_STOP, 1); 55016020011SCédric Le Goater } 551ba2cccd6SJoe Komlodi SHARED_ARRAY_FIELD_DP32(bus->regs, reg_cmd, M_STOP_CMD, 0); 5524960f084SCédric Le Goater aspeed_i2c_set_state(bus, I2CD_IDLE); 553*791cb95fSKlaus Jensen 554*791cb95fSKlaus Jensen i2c_schedule_pending_master(bus->bus); 55516020011SCédric Le Goater } 556ba2cccd6SJoe Komlodi 557ba2cccd6SJoe Komlodi if (aspeed_i2c_bus_pkt_mode_en(bus)) { 558ba2cccd6SJoe Komlodi ARRAY_FIELD_DP32(bus->regs, I2CM_INTR_STS, PKT_CMD_DONE, 1); 559ba2cccd6SJoe Komlodi } 56016020011SCédric Le Goater } 56116020011SCédric Le Goater 562ba2cccd6SJoe Komlodi static void aspeed_i2c_bus_new_write(AspeedI2CBus *bus, hwaddr offset, 56316020011SCédric Le Goater uint64_t value, unsigned size) 56416020011SCédric Le Goater { 565ba2cccd6SJoe Komlodi AspeedI2CClass *aic = ASPEED_I2C_GET_CLASS(bus->controller); 566ba2cccd6SJoe Komlodi bool handle_rx; 567ba2cccd6SJoe Komlodi bool w1t; 568ba2cccd6SJoe Komlodi 569ba2cccd6SJoe Komlodi trace_aspeed_i2c_bus_write(bus->id, offset, size, value); 570ba2cccd6SJoe Komlodi 571ba2cccd6SJoe Komlodi switch (offset) { 572ba2cccd6SJoe Komlodi case A_I2CC_FUN_CTRL: 5731c5d909fSPeter Delevoryas bus->regs[R_I2CC_FUN_CTRL] = value; 574ba2cccd6SJoe Komlodi break; 575ba2cccd6SJoe Komlodi case A_I2CC_AC_TIMING: 576ba2cccd6SJoe Komlodi bus->regs[R_I2CC_AC_TIMING] = value & 0x1ffff0ff; 577ba2cccd6SJoe Komlodi break; 578ba2cccd6SJoe Komlodi case A_I2CC_MS_TXRX_BYTE_BUF: 579ba2cccd6SJoe Komlodi SHARED_ARRAY_FIELD_DP32(bus->regs, R_I2CC_MS_TXRX_BYTE_BUF, TX_BUF, 580ba2cccd6SJoe Komlodi value); 581ba2cccd6SJoe Komlodi break; 582ba2cccd6SJoe Komlodi case A_I2CC_POOL_CTRL: 583ba2cccd6SJoe Komlodi bus->regs[R_I2CC_POOL_CTRL] &= ~0xffffff; 584ba2cccd6SJoe Komlodi bus->regs[R_I2CC_POOL_CTRL] |= (value & 0xffffff); 585ba2cccd6SJoe Komlodi break; 586ba2cccd6SJoe Komlodi case A_I2CM_INTR_CTRL: 587ba2cccd6SJoe Komlodi bus->regs[R_I2CM_INTR_CTRL] = value & 0x0007f07f; 588ba2cccd6SJoe Komlodi break; 589ba2cccd6SJoe Komlodi case A_I2CM_INTR_STS: 590ba2cccd6SJoe Komlodi handle_rx = SHARED_ARRAY_FIELD_EX32(bus->regs, R_I2CM_INTR_STS, RX_DONE) 591ba2cccd6SJoe Komlodi && SHARED_FIELD_EX32(value, RX_DONE); 592ba2cccd6SJoe Komlodi 593ba2cccd6SJoe Komlodi /* In packet mode, clearing PKT_CMD_DONE clears other interrupts. */ 594ba2cccd6SJoe Komlodi if (aspeed_i2c_bus_pkt_mode_en(bus) && 595ba2cccd6SJoe Komlodi FIELD_EX32(value, I2CM_INTR_STS, PKT_CMD_DONE)) { 596ba2cccd6SJoe Komlodi bus->regs[R_I2CM_INTR_STS] &= 0xf0001000; 597ba2cccd6SJoe Komlodi if (!bus->regs[R_I2CM_INTR_STS]) { 598ba2cccd6SJoe Komlodi bus->controller->intr_status &= ~(1 << bus->id); 599ba2cccd6SJoe Komlodi qemu_irq_lower(aic->bus_get_irq(bus)); 600ba2cccd6SJoe Komlodi } 6011c5d909fSPeter Delevoryas aspeed_i2c_bus_raise_slave_interrupt(bus); 602ba2cccd6SJoe Komlodi break; 603ba2cccd6SJoe Komlodi } 604ba2cccd6SJoe Komlodi bus->regs[R_I2CM_INTR_STS] &= ~(value & 0xf007f07f); 605ba2cccd6SJoe Komlodi if (!bus->regs[R_I2CM_INTR_STS]) { 606ba2cccd6SJoe Komlodi bus->controller->intr_status &= ~(1 << bus->id); 607ba2cccd6SJoe Komlodi qemu_irq_lower(aic->bus_get_irq(bus)); 608ba2cccd6SJoe Komlodi } 609ba2cccd6SJoe Komlodi if (handle_rx && (SHARED_ARRAY_FIELD_EX32(bus->regs, R_I2CM_CMD, 610ba2cccd6SJoe Komlodi M_RX_CMD) || 611ba2cccd6SJoe Komlodi SHARED_ARRAY_FIELD_EX32(bus->regs, R_I2CM_CMD, 612ba2cccd6SJoe Komlodi M_S_RX_CMD_LAST))) { 613ba2cccd6SJoe Komlodi aspeed_i2c_handle_rx_cmd(bus); 614ba2cccd6SJoe Komlodi aspeed_i2c_bus_raise_interrupt(bus); 615ba2cccd6SJoe Komlodi } 616ba2cccd6SJoe Komlodi break; 617ba2cccd6SJoe Komlodi case A_I2CM_CMD: 618ba2cccd6SJoe Komlodi if (!aspeed_i2c_bus_is_enabled(bus)) { 619ba2cccd6SJoe Komlodi break; 620ba2cccd6SJoe Komlodi } 621ba2cccd6SJoe Komlodi 622ba2cccd6SJoe Komlodi if (!aspeed_i2c_bus_is_master(bus)) { 6230c0f1beeSPeter Delevoryas qemu_log_mask(LOG_GUEST_ERROR, "%s: Master mode is not enabled\n", 624ba2cccd6SJoe Komlodi __func__); 625ba2cccd6SJoe Komlodi break; 626ba2cccd6SJoe Komlodi } 627ba2cccd6SJoe Komlodi 628ba2cccd6SJoe Komlodi if (!aic->has_dma && 629ba2cccd6SJoe Komlodi (SHARED_FIELD_EX32(value, RX_DMA_EN) || 630ba2cccd6SJoe Komlodi SHARED_FIELD_EX32(value, TX_DMA_EN))) { 631ba2cccd6SJoe Komlodi qemu_log_mask(LOG_GUEST_ERROR, "%s: No DMA support\n", __func__); 632ba2cccd6SJoe Komlodi break; 633ba2cccd6SJoe Komlodi } 634ba2cccd6SJoe Komlodi 635ba2cccd6SJoe Komlodi if (bus->regs[R_I2CM_INTR_STS] & 0xffff0000) { 636ba2cccd6SJoe Komlodi qemu_log_mask(LOG_UNIMP, "%s: Packet mode is not implemented\n", 637ba2cccd6SJoe Komlodi __func__); 638ba2cccd6SJoe Komlodi break; 639ba2cccd6SJoe Komlodi } 640ba2cccd6SJoe Komlodi 641ba2cccd6SJoe Komlodi value &= 0xff0ffbfb; 642ba2cccd6SJoe Komlodi if (ARRAY_FIELD_EX32(bus->regs, I2CM_CMD, W1_CTRL)) { 643ba2cccd6SJoe Komlodi bus->regs[R_I2CM_CMD] |= value; 644ba2cccd6SJoe Komlodi } else { 645ba2cccd6SJoe Komlodi bus->regs[R_I2CM_CMD] = value; 646ba2cccd6SJoe Komlodi } 647ba2cccd6SJoe Komlodi 648ba2cccd6SJoe Komlodi aspeed_i2c_bus_handle_cmd(bus, value); 649ba2cccd6SJoe Komlodi aspeed_i2c_bus_raise_interrupt(bus); 650ba2cccd6SJoe Komlodi break; 651ba2cccd6SJoe Komlodi case A_I2CM_DMA_TX_ADDR: 652ba2cccd6SJoe Komlodi bus->regs[R_I2CM_DMA_TX_ADDR] = FIELD_EX32(value, I2CM_DMA_TX_ADDR, 653ba2cccd6SJoe Komlodi ADDR); 654ba2cccd6SJoe Komlodi bus->regs[R_I2CC_DMA_ADDR] = FIELD_EX32(value, I2CM_DMA_TX_ADDR, ADDR); 655ba2cccd6SJoe Komlodi bus->regs[R_I2CC_DMA_LEN] = ARRAY_FIELD_EX32(bus->regs, I2CM_DMA_LEN, 656ba2cccd6SJoe Komlodi TX_BUF_LEN) + 1; 657ba2cccd6SJoe Komlodi break; 658ba2cccd6SJoe Komlodi case A_I2CM_DMA_RX_ADDR: 659ba2cccd6SJoe Komlodi bus->regs[R_I2CM_DMA_RX_ADDR] = FIELD_EX32(value, I2CM_DMA_RX_ADDR, 660ba2cccd6SJoe Komlodi ADDR); 661ba2cccd6SJoe Komlodi bus->regs[R_I2CC_DMA_ADDR] = FIELD_EX32(value, I2CM_DMA_RX_ADDR, ADDR); 662ba2cccd6SJoe Komlodi bus->regs[R_I2CC_DMA_LEN] = ARRAY_FIELD_EX32(bus->regs, I2CM_DMA_LEN, 663ba2cccd6SJoe Komlodi RX_BUF_LEN) + 1; 664ba2cccd6SJoe Komlodi break; 665ba2cccd6SJoe Komlodi case A_I2CM_DMA_LEN: 666b582b7a1SPeter Delevoryas w1t = FIELD_EX32(value, I2CM_DMA_LEN, RX_BUF_LEN_W1T) || 667b582b7a1SPeter Delevoryas FIELD_EX32(value, I2CM_DMA_LEN, TX_BUF_LEN_W1T); 668ba2cccd6SJoe Komlodi /* If none of the w1t bits are set, just write to the reg as normal. */ 669ba2cccd6SJoe Komlodi if (!w1t) { 670ba2cccd6SJoe Komlodi bus->regs[R_I2CM_DMA_LEN] = value; 671ba2cccd6SJoe Komlodi break; 672ba2cccd6SJoe Komlodi } 673b582b7a1SPeter Delevoryas if (FIELD_EX32(value, I2CM_DMA_LEN, RX_BUF_LEN_W1T)) { 674ba2cccd6SJoe Komlodi ARRAY_FIELD_DP32(bus->regs, I2CM_DMA_LEN, RX_BUF_LEN, 675ba2cccd6SJoe Komlodi FIELD_EX32(value, I2CM_DMA_LEN, RX_BUF_LEN)); 676ba2cccd6SJoe Komlodi } 677b582b7a1SPeter Delevoryas if (FIELD_EX32(value, I2CM_DMA_LEN, TX_BUF_LEN_W1T)) { 678ba2cccd6SJoe Komlodi ARRAY_FIELD_DP32(bus->regs, I2CM_DMA_LEN, TX_BUF_LEN, 679ba2cccd6SJoe Komlodi FIELD_EX32(value, I2CM_DMA_LEN, TX_BUF_LEN)); 680ba2cccd6SJoe Komlodi } 681ba2cccd6SJoe Komlodi break; 682ba2cccd6SJoe Komlodi case A_I2CM_DMA_LEN_STS: 683ba2cccd6SJoe Komlodi /* Writes clear to 0 */ 684ba2cccd6SJoe Komlodi bus->regs[R_I2CM_DMA_LEN_STS] = 0; 685ba2cccd6SJoe Komlodi break; 686ba2cccd6SJoe Komlodi case A_I2CC_DMA_ADDR: 687ba2cccd6SJoe Komlodi case A_I2CC_DMA_LEN: 688ba2cccd6SJoe Komlodi /* RO */ 689ba2cccd6SJoe Komlodi break; 690ba2cccd6SJoe Komlodi case A_I2CS_DEV_ADDR: 6911c5d909fSPeter Delevoryas bus->regs[R_I2CS_DEV_ADDR] = value; 6921c5d909fSPeter Delevoryas break; 6931c5d909fSPeter Delevoryas case A_I2CS_DMA_RX_ADDR: 6941c5d909fSPeter Delevoryas bus->regs[R_I2CS_DMA_RX_ADDR] = value; 6951c5d909fSPeter Delevoryas break; 696ba2cccd6SJoe Komlodi case A_I2CS_DMA_LEN: 6971c5d909fSPeter Delevoryas assert(FIELD_EX32(value, I2CS_DMA_LEN, TX_BUF_LEN) == 0); 6981c5d909fSPeter Delevoryas if (FIELD_EX32(value, I2CS_DMA_LEN, RX_BUF_LEN_W1T)) { 6991c5d909fSPeter Delevoryas ARRAY_FIELD_DP32(bus->regs, I2CS_DMA_LEN, RX_BUF_LEN, 7001c5d909fSPeter Delevoryas FIELD_EX32(value, I2CS_DMA_LEN, RX_BUF_LEN)); 7011c5d909fSPeter Delevoryas } else { 7021c5d909fSPeter Delevoryas bus->regs[R_I2CS_DMA_LEN] = value; 7031c5d909fSPeter Delevoryas } 7041c5d909fSPeter Delevoryas break; 7051c5d909fSPeter Delevoryas case A_I2CS_CMD: 7061c5d909fSPeter Delevoryas if (FIELD_EX32(value, I2CS_CMD, W1_CTRL)) { 7071c5d909fSPeter Delevoryas bus->regs[R_I2CS_CMD] |= value; 7081c5d909fSPeter Delevoryas } else { 7091c5d909fSPeter Delevoryas bus->regs[R_I2CS_CMD] = value; 7101c5d909fSPeter Delevoryas } 7111c5d909fSPeter Delevoryas i2c_slave_set_address(bus->slave, bus->regs[R_I2CS_DEV_ADDR]); 7121c5d909fSPeter Delevoryas break; 7131c5d909fSPeter Delevoryas case A_I2CS_INTR_CTRL: 7141c5d909fSPeter Delevoryas bus->regs[R_I2CS_INTR_CTRL] = value; 7151c5d909fSPeter Delevoryas break; 7161c5d909fSPeter Delevoryas 7171c5d909fSPeter Delevoryas case A_I2CS_INTR_STS: 7181c5d909fSPeter Delevoryas if (ARRAY_FIELD_EX32(bus->regs, I2CS_INTR_CTRL, PKT_CMD_DONE)) { 7191c5d909fSPeter Delevoryas if (ARRAY_FIELD_EX32(bus->regs, I2CS_INTR_STS, PKT_CMD_DONE) && 7201c5d909fSPeter Delevoryas FIELD_EX32(value, I2CS_INTR_STS, PKT_CMD_DONE)) { 7211c5d909fSPeter Delevoryas bus->regs[R_I2CS_INTR_STS] &= 0xfffc0000; 7221c5d909fSPeter Delevoryas } 7231c5d909fSPeter Delevoryas } else { 7241c5d909fSPeter Delevoryas bus->regs[R_I2CS_INTR_STS] &= ~value; 7251c5d909fSPeter Delevoryas } 7261c5d909fSPeter Delevoryas if (!bus->regs[R_I2CS_INTR_STS]) { 7271c5d909fSPeter Delevoryas bus->controller->intr_status &= ~(1 << bus->id); 7281c5d909fSPeter Delevoryas qemu_irq_lower(aic->bus_get_irq(bus)); 7291c5d909fSPeter Delevoryas } 7301c5d909fSPeter Delevoryas aspeed_i2c_bus_raise_interrupt(bus); 7311c5d909fSPeter Delevoryas break; 7321c5d909fSPeter Delevoryas case A_I2CS_DMA_LEN_STS: 7331c5d909fSPeter Delevoryas bus->regs[R_I2CS_DMA_LEN_STS] = 0; 7341c5d909fSPeter Delevoryas break; 7351c5d909fSPeter Delevoryas case A_I2CS_DMA_TX_ADDR: 7361c5d909fSPeter Delevoryas qemu_log_mask(LOG_UNIMP, "%s: Slave mode DMA TX is not implemented\n", 737ba2cccd6SJoe Komlodi __func__); 738ba2cccd6SJoe Komlodi break; 739ba2cccd6SJoe Komlodi default: 740ba2cccd6SJoe Komlodi qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad offset 0x%" HWADDR_PRIx "\n", 741ba2cccd6SJoe Komlodi __func__, offset); 742ba2cccd6SJoe Komlodi } 743ba2cccd6SJoe Komlodi } 744ba2cccd6SJoe Komlodi 745ba2cccd6SJoe Komlodi static void aspeed_i2c_bus_old_write(AspeedI2CBus *bus, hwaddr offset, 746ba2cccd6SJoe Komlodi uint64_t value, unsigned size) 747ba2cccd6SJoe Komlodi { 74851dd4923SCédric Le Goater AspeedI2CClass *aic = ASPEED_I2C_GET_CLASS(bus->controller); 749bb626e5bSGuenter Roeck bool handle_rx; 75016020011SCédric Le Goater 75166cc84a1SCédric Le Goater trace_aspeed_i2c_bus_write(bus->id, offset, size, value); 75266cc84a1SCédric Le Goater 75316020011SCédric Le Goater switch (offset) { 7543be3d6ccSJoe Komlodi case A_I2CD_FUN_CTRL: 755ba2cccd6SJoe Komlodi if (SHARED_FIELD_EX32(value, SLAVE_EN)) { 756a8d48f59SKlaus Jensen i2c_slave_set_address(bus->slave, bus->regs[R_I2CD_DEV_ADDR]); 75716020011SCédric Le Goater } 7582260fc6fSJoe Komlodi bus->regs[R_I2CD_FUN_CTRL] = value & 0x0071C3FF; 75916020011SCédric Le Goater break; 7603be3d6ccSJoe Komlodi case A_I2CD_AC_TIMING1: 7612260fc6fSJoe Komlodi bus->regs[R_I2CD_AC_TIMING1] = value & 0xFFFFF0F; 76216020011SCédric Le Goater break; 7633be3d6ccSJoe Komlodi case A_I2CD_AC_TIMING2: 7642260fc6fSJoe Komlodi bus->regs[R_I2CD_AC_TIMING2] = value & 0x7; 76516020011SCédric Le Goater break; 7663be3d6ccSJoe Komlodi case A_I2CD_INTR_CTRL: 7672260fc6fSJoe Komlodi bus->regs[R_I2CD_INTR_CTRL] = value & 0x7FFF; 76816020011SCédric Le Goater break; 7693be3d6ccSJoe Komlodi case A_I2CD_INTR_STS: 770ba2cccd6SJoe Komlodi handle_rx = SHARED_ARRAY_FIELD_EX32(bus->regs, R_I2CD_INTR_STS, RX_DONE) 771ba2cccd6SJoe Komlodi && SHARED_FIELD_EX32(value, RX_DONE); 7722260fc6fSJoe Komlodi bus->regs[R_I2CD_INTR_STS] &= ~(value & 0x7FFF); 7732260fc6fSJoe Komlodi if (!bus->regs[R_I2CD_INTR_STS]) { 77416020011SCédric Le Goater bus->controller->intr_status &= ~(1 << bus->id); 77551dd4923SCédric Le Goater qemu_irq_lower(aic->bus_get_irq(bus)); 7765540cb97SCédric Le Goater } 777a8d48f59SKlaus Jensen if (handle_rx) { 778a8d48f59SKlaus Jensen if (SHARED_ARRAY_FIELD_EX32(bus->regs, R_I2CD_CMD, M_RX_CMD) || 779ba2cccd6SJoe Komlodi SHARED_ARRAY_FIELD_EX32(bus->regs, R_I2CD_CMD, 780a8d48f59SKlaus Jensen M_S_RX_CMD_LAST)) { 781bb626e5bSGuenter Roeck aspeed_i2c_handle_rx_cmd(bus); 782bb626e5bSGuenter Roeck aspeed_i2c_bus_raise_interrupt(bus); 783a8d48f59SKlaus Jensen } else if (aspeed_i2c_get_state(bus) == I2CD_STXD) { 784a8d48f59SKlaus Jensen i2c_ack(bus->bus); 785a8d48f59SKlaus Jensen } 786bb626e5bSGuenter Roeck } 78716020011SCédric Le Goater break; 7883be3d6ccSJoe Komlodi case A_I2CD_DEV_ADDR: 789d72a712cSKlaus Jensen bus->regs[R_I2CD_DEV_ADDR] = value; 79016020011SCédric Le Goater break; 7913be3d6ccSJoe Komlodi case A_I2CD_POOL_CTRL: 7922260fc6fSJoe Komlodi bus->regs[R_I2CD_POOL_CTRL] &= ~0xffffff; 7932260fc6fSJoe Komlodi bus->regs[R_I2CD_POOL_CTRL] |= (value & 0xffffff); 7946054fc73SCédric Le Goater break; 7956054fc73SCédric Le Goater 7963be3d6ccSJoe Komlodi case A_I2CD_BYTE_BUF: 797ba2cccd6SJoe Komlodi SHARED_ARRAY_FIELD_DP32(bus->regs, R_I2CD_BYTE_BUF, TX_BUF, value); 79816020011SCédric Le Goater break; 7993be3d6ccSJoe Komlodi case A_I2CD_CMD: 80016020011SCédric Le Goater if (!aspeed_i2c_bus_is_enabled(bus)) { 80116020011SCédric Le Goater break; 80216020011SCédric Le Goater } 80316020011SCédric Le Goater 80416020011SCédric Le Goater if (!aspeed_i2c_bus_is_master(bus)) { 8050c0f1beeSPeter Delevoryas qemu_log_mask(LOG_GUEST_ERROR, "%s: Master mode is not enabled\n", 80616020011SCédric Le Goater __func__); 80716020011SCédric Le Goater break; 80816020011SCédric Le Goater } 80916020011SCédric Le Goater 810545d6befSCédric Le Goater if (!aic->has_dma && 811ba2cccd6SJoe Komlodi (SHARED_FIELD_EX32(value, RX_DMA_EN) || 812ba2cccd6SJoe Komlodi SHARED_FIELD_EX32(value, TX_DMA_EN))) { 813545d6befSCédric Le Goater qemu_log_mask(LOG_GUEST_ERROR, "%s: No DMA support\n", __func__); 814545d6befSCédric Le Goater break; 815545d6befSCédric Le Goater } 816545d6befSCédric Le Goater 817ba2cccd6SJoe Komlodi bus->regs[R_I2CD_CMD] &= ~0xFFFF; 818ba2cccd6SJoe Komlodi bus->regs[R_I2CD_CMD] |= value & 0xFFFF; 819ba2cccd6SJoe Komlodi 82016020011SCédric Le Goater aspeed_i2c_bus_handle_cmd(bus, value); 821ddabca75SCédric Le Goater aspeed_i2c_bus_raise_interrupt(bus); 82216020011SCédric Le Goater break; 8233be3d6ccSJoe Komlodi case A_I2CD_DMA_ADDR: 824545d6befSCédric Le Goater if (!aic->has_dma) { 825545d6befSCédric Le Goater qemu_log_mask(LOG_GUEST_ERROR, "%s: No DMA support\n", __func__); 826545d6befSCédric Le Goater break; 827545d6befSCédric Le Goater } 828545d6befSCédric Le Goater 8292260fc6fSJoe Komlodi bus->regs[R_I2CD_DMA_ADDR] = value & 0x3ffffffc; 830545d6befSCédric Le Goater break; 831545d6befSCédric Le Goater 8323be3d6ccSJoe Komlodi case A_I2CD_DMA_LEN: 833545d6befSCédric Le Goater if (!aic->has_dma) { 834545d6befSCédric Le Goater qemu_log_mask(LOG_GUEST_ERROR, "%s: No DMA support\n", __func__); 835545d6befSCédric Le Goater break; 836545d6befSCédric Le Goater } 837545d6befSCédric Le Goater 8382260fc6fSJoe Komlodi bus->regs[R_I2CD_DMA_LEN] = value & 0xfff; 8392260fc6fSJoe Komlodi if (!bus->regs[R_I2CD_DMA_LEN]) { 840545d6befSCédric Le Goater qemu_log_mask(LOG_UNIMP, "%s: invalid DMA length\n", __func__); 841545d6befSCédric Le Goater } 842545d6befSCédric Le Goater break; 84316020011SCédric Le Goater 84416020011SCédric Le Goater default: 84516020011SCédric Le Goater qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad offset 0x%" HWADDR_PRIx "\n", 84616020011SCédric Le Goater __func__, offset); 84716020011SCédric Le Goater } 84816020011SCédric Le Goater } 84916020011SCédric Le Goater 850ba2cccd6SJoe Komlodi static void aspeed_i2c_bus_write(void *opaque, hwaddr offset, 851ba2cccd6SJoe Komlodi uint64_t value, unsigned size) 852ba2cccd6SJoe Komlodi { 853ba2cccd6SJoe Komlodi AspeedI2CBus *bus = opaque; 854ba2cccd6SJoe Komlodi if (aspeed_i2c_is_new_mode(bus->controller)) { 855ba2cccd6SJoe Komlodi aspeed_i2c_bus_new_write(bus, offset, value, size); 856ba2cccd6SJoe Komlodi } else { 857ba2cccd6SJoe Komlodi aspeed_i2c_bus_old_write(bus, offset, value, size); 858ba2cccd6SJoe Komlodi } 859ba2cccd6SJoe Komlodi } 860ba2cccd6SJoe Komlodi 86116020011SCédric Le Goater static uint64_t aspeed_i2c_ctrl_read(void *opaque, hwaddr offset, 86216020011SCédric Le Goater unsigned size) 86316020011SCédric Le Goater { 86416020011SCédric Le Goater AspeedI2CState *s = opaque; 86516020011SCédric Le Goater 86616020011SCédric Le Goater switch (offset) { 8673be3d6ccSJoe Komlodi case A_I2C_CTRL_STATUS: 86816020011SCédric Le Goater return s->intr_status; 8693be3d6ccSJoe Komlodi case A_I2C_CTRL_GLOBAL: 870aab90b1cSCédric Le Goater return s->ctrl_global; 871ba2cccd6SJoe Komlodi case A_I2C_CTRL_NEW_CLK_DIVIDER: 872ba2cccd6SJoe Komlodi if (aspeed_i2c_is_new_mode(s)) { 873ba2cccd6SJoe Komlodi return s->new_clk_divider; 874ba2cccd6SJoe Komlodi } 875ba2cccd6SJoe Komlodi qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad offset 0x%" HWADDR_PRIx "\n", 876ba2cccd6SJoe Komlodi __func__, offset); 877ba2cccd6SJoe Komlodi break; 87816020011SCédric Le Goater default: 87916020011SCédric Le Goater qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad offset 0x%" HWADDR_PRIx "\n", 88016020011SCédric Le Goater __func__, offset); 88116020011SCédric Le Goater break; 88216020011SCédric Le Goater } 88316020011SCédric Le Goater 88416020011SCédric Le Goater return -1; 88516020011SCédric Le Goater } 88616020011SCédric Le Goater 88716020011SCédric Le Goater static void aspeed_i2c_ctrl_write(void *opaque, hwaddr offset, 88816020011SCédric Le Goater uint64_t value, unsigned size) 88916020011SCédric Le Goater { 890aab90b1cSCédric Le Goater AspeedI2CState *s = opaque; 891aab90b1cSCédric Le Goater 89216020011SCédric Le Goater switch (offset) { 8933be3d6ccSJoe Komlodi case A_I2C_CTRL_GLOBAL: 894aab90b1cSCédric Le Goater s->ctrl_global = value; 895aab90b1cSCédric Le Goater break; 896ba2cccd6SJoe Komlodi case A_I2C_CTRL_NEW_CLK_DIVIDER: 897ba2cccd6SJoe Komlodi if (aspeed_i2c_is_new_mode(s)) { 898ba2cccd6SJoe Komlodi s->new_clk_divider = value; 899ba2cccd6SJoe Komlodi } else { 900ba2cccd6SJoe Komlodi qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad offset 0x%" HWADDR_PRIx 901ba2cccd6SJoe Komlodi "\n", __func__, offset); 902ba2cccd6SJoe Komlodi } 903ba2cccd6SJoe Komlodi break; 9043be3d6ccSJoe Komlodi case A_I2C_CTRL_STATUS: 90516020011SCédric Le Goater default: 90616020011SCédric Le Goater qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad offset 0x%" HWADDR_PRIx "\n", 90716020011SCédric Le Goater __func__, offset); 90816020011SCédric Le Goater break; 90916020011SCédric Le Goater } 91016020011SCédric Le Goater } 91116020011SCédric Le Goater 91216020011SCédric Le Goater static const MemoryRegionOps aspeed_i2c_bus_ops = { 91316020011SCédric Le Goater .read = aspeed_i2c_bus_read, 91416020011SCédric Le Goater .write = aspeed_i2c_bus_write, 91516020011SCédric Le Goater .endianness = DEVICE_LITTLE_ENDIAN, 91616020011SCédric Le Goater }; 91716020011SCédric Le Goater 91816020011SCédric Le Goater static const MemoryRegionOps aspeed_i2c_ctrl_ops = { 91916020011SCédric Le Goater .read = aspeed_i2c_ctrl_read, 92016020011SCédric Le Goater .write = aspeed_i2c_ctrl_write, 92116020011SCédric Le Goater .endianness = DEVICE_LITTLE_ENDIAN, 92216020011SCédric Le Goater }; 92316020011SCédric Le Goater 9246054fc73SCédric Le Goater static uint64_t aspeed_i2c_pool_read(void *opaque, hwaddr offset, 9256054fc73SCédric Le Goater unsigned size) 9266054fc73SCédric Le Goater { 9276054fc73SCédric Le Goater AspeedI2CState *s = opaque; 9286054fc73SCédric Le Goater uint64_t ret = 0; 9296054fc73SCédric Le Goater int i; 9306054fc73SCédric Le Goater 9316054fc73SCédric Le Goater for (i = 0; i < size; i++) { 9326054fc73SCédric Le Goater ret |= (uint64_t) s->pool[offset + i] << (8 * i); 9336054fc73SCédric Le Goater } 9346054fc73SCédric Le Goater 9356054fc73SCédric Le Goater return ret; 9366054fc73SCédric Le Goater } 9376054fc73SCédric Le Goater 9386054fc73SCédric Le Goater static void aspeed_i2c_pool_write(void *opaque, hwaddr offset, 9396054fc73SCédric Le Goater uint64_t value, unsigned size) 9406054fc73SCédric Le Goater { 9416054fc73SCédric Le Goater AspeedI2CState *s = opaque; 9426054fc73SCédric Le Goater int i; 9436054fc73SCédric Le Goater 9446054fc73SCédric Le Goater for (i = 0; i < size; i++) { 9456054fc73SCédric Le Goater s->pool[offset + i] = (value >> (8 * i)) & 0xFF; 9466054fc73SCédric Le Goater } 9476054fc73SCédric Le Goater } 9486054fc73SCédric Le Goater 9496054fc73SCédric Le Goater static const MemoryRegionOps aspeed_i2c_pool_ops = { 9506054fc73SCédric Le Goater .read = aspeed_i2c_pool_read, 9516054fc73SCédric Le Goater .write = aspeed_i2c_pool_write, 9526054fc73SCédric Le Goater .endianness = DEVICE_LITTLE_ENDIAN, 9536054fc73SCédric Le Goater .valid = { 9546054fc73SCédric Le Goater .min_access_size = 1, 9556054fc73SCédric Le Goater .max_access_size = 4, 9566054fc73SCédric Le Goater }, 9576054fc73SCédric Le Goater }; 9586054fc73SCédric Le Goater 95916020011SCédric Le Goater static const VMStateDescription aspeed_i2c_bus_vmstate = { 96016020011SCédric Le Goater .name = TYPE_ASPEED_I2C, 961ba2cccd6SJoe Komlodi .version_id = 5, 962ba2cccd6SJoe Komlodi .minimum_version_id = 5, 96316020011SCédric Le Goater .fields = (VMStateField[]) { 964ba2cccd6SJoe Komlodi VMSTATE_UINT32_ARRAY(regs, AspeedI2CBus, ASPEED_I2C_NEW_NUM_REG), 96516020011SCédric Le Goater VMSTATE_END_OF_LIST() 96616020011SCédric Le Goater } 96716020011SCédric Le Goater }; 96816020011SCédric Le Goater 96916020011SCédric Le Goater static const VMStateDescription aspeed_i2c_vmstate = { 97016020011SCédric Le Goater .name = TYPE_ASPEED_I2C, 9716054fc73SCédric Le Goater .version_id = 2, 9726054fc73SCédric Le Goater .minimum_version_id = 2, 97316020011SCédric Le Goater .fields = (VMStateField[]) { 97416020011SCédric Le Goater VMSTATE_UINT32(intr_status, AspeedI2CState), 97516020011SCédric Le Goater VMSTATE_STRUCT_ARRAY(busses, AspeedI2CState, 97616020011SCédric Le Goater ASPEED_I2C_NR_BUSSES, 1, aspeed_i2c_bus_vmstate, 97716020011SCédric Le Goater AspeedI2CBus), 9786054fc73SCédric Le Goater VMSTATE_UINT8_ARRAY(pool, AspeedI2CState, ASPEED_I2C_MAX_POOL_SIZE), 97916020011SCédric Le Goater VMSTATE_END_OF_LIST() 98016020011SCédric Le Goater } 98116020011SCédric Le Goater }; 98216020011SCédric Le Goater 98316020011SCédric Le Goater static void aspeed_i2c_reset(DeviceState *dev) 98416020011SCédric Le Goater { 98516020011SCédric Le Goater AspeedI2CState *s = ASPEED_I2C(dev); 98616020011SCédric Le Goater 98716020011SCédric Le Goater s->intr_status = 0; 98860261038SCédric Le Goater } 98960261038SCédric Le Goater 99060261038SCédric Le Goater static void aspeed_i2c_instance_init(Object *obj) 99160261038SCédric Le Goater { 99260261038SCédric Le Goater AspeedI2CState *s = ASPEED_I2C(obj); 99360261038SCédric Le Goater AspeedI2CClass *aic = ASPEED_I2C_GET_CLASS(s); 99460261038SCédric Le Goater int i; 99516020011SCédric Le Goater 996f7da1aa8SCédric Le Goater for (i = 0; i < aic->num_busses; i++) { 99760261038SCédric Le Goater object_initialize_child(obj, "bus[*]", &s->busses[i], 99860261038SCédric Le Goater TYPE_ASPEED_I2C_BUS); 99916020011SCédric Le Goater } 100016020011SCédric Le Goater } 100116020011SCédric Le Goater 100216020011SCédric Le Goater /* 1003f7da1aa8SCédric Le Goater * Address Definitions (AST2400 and AST2500) 100416020011SCédric Le Goater * 100516020011SCédric Le Goater * 0x000 ... 0x03F: Global Register 100616020011SCédric Le Goater * 0x040 ... 0x07F: Device 1 100716020011SCédric Le Goater * 0x080 ... 0x0BF: Device 2 100816020011SCédric Le Goater * 0x0C0 ... 0x0FF: Device 3 100916020011SCédric Le Goater * 0x100 ... 0x13F: Device 4 101016020011SCédric Le Goater * 0x140 ... 0x17F: Device 5 101116020011SCédric Le Goater * 0x180 ... 0x1BF: Device 6 101216020011SCédric Le Goater * 0x1C0 ... 0x1FF: Device 7 101316020011SCédric Le Goater * 0x200 ... 0x2FF: Buffer Pool (unused in linux driver) 101416020011SCédric Le Goater * 0x300 ... 0x33F: Device 8 101516020011SCédric Le Goater * 0x340 ... 0x37F: Device 9 101616020011SCédric Le Goater * 0x380 ... 0x3BF: Device 10 101716020011SCédric Le Goater * 0x3C0 ... 0x3FF: Device 11 101816020011SCédric Le Goater * 0x400 ... 0x43F: Device 12 101916020011SCédric Le Goater * 0x440 ... 0x47F: Device 13 102016020011SCédric Le Goater * 0x480 ... 0x4BF: Device 14 102116020011SCédric Le Goater * 0x800 ... 0xFFF: Buffer Pool (unused in linux driver) 102216020011SCédric Le Goater */ 102316020011SCédric Le Goater static void aspeed_i2c_realize(DeviceState *dev, Error **errp) 102416020011SCédric Le Goater { 102516020011SCédric Le Goater int i; 102616020011SCédric Le Goater SysBusDevice *sbd = SYS_BUS_DEVICE(dev); 102716020011SCédric Le Goater AspeedI2CState *s = ASPEED_I2C(dev); 1028f7da1aa8SCédric Le Goater AspeedI2CClass *aic = ASPEED_I2C_GET_CLASS(s); 102916020011SCédric Le Goater 103016020011SCédric Le Goater sysbus_init_irq(sbd, &s->irq); 103116020011SCédric Le Goater memory_region_init_io(&s->iomem, OBJECT(s), &aspeed_i2c_ctrl_ops, s, 103216020011SCédric Le Goater "aspeed.i2c", 0x1000); 103316020011SCédric Le Goater sysbus_init_mmio(sbd, &s->iomem); 103416020011SCédric Le Goater 1035f7da1aa8SCédric Le Goater for (i = 0; i < aic->num_busses; i++) { 103660261038SCédric Le Goater Object *bus = OBJECT(&s->busses[i]); 1037f7da1aa8SCédric Le Goater int offset = i < aic->gap ? 1 : 5; 103851dd4923SCédric Le Goater 103960261038SCédric Le Goater if (!object_property_set_link(bus, "controller", OBJECT(s), errp)) { 104060261038SCédric Le Goater return; 104160261038SCédric Le Goater } 104260261038SCédric Le Goater 104360261038SCédric Le Goater if (!object_property_set_uint(bus, "bus-id", i, errp)) { 104460261038SCédric Le Goater return; 104560261038SCédric Le Goater } 104660261038SCédric Le Goater 104760261038SCédric Le Goater if (!sysbus_realize(SYS_BUS_DEVICE(bus), errp)) { 104860261038SCédric Le Goater return; 104960261038SCédric Le Goater } 105060261038SCédric Le Goater 1051f7da1aa8SCédric Le Goater memory_region_add_subregion(&s->iomem, aic->reg_size * (i + offset), 105216020011SCédric Le Goater &s->busses[i].mr); 105316020011SCédric Le Goater } 10546054fc73SCédric Le Goater 10556054fc73SCédric Le Goater memory_region_init_io(&s->pool_iomem, OBJECT(s), &aspeed_i2c_pool_ops, s, 10566054fc73SCédric Le Goater "aspeed.i2c-pool", aic->pool_size); 10576054fc73SCédric Le Goater memory_region_add_subregion(&s->iomem, aic->pool_base, &s->pool_iomem); 1058545d6befSCédric Le Goater 1059545d6befSCédric Le Goater if (aic->has_dma) { 1060545d6befSCédric Le Goater if (!s->dram_mr) { 1061545d6befSCédric Le Goater error_setg(errp, TYPE_ASPEED_I2C ": 'dram' link not set"); 1062545d6befSCédric Le Goater return; 106316020011SCédric Le Goater } 106416020011SCédric Le Goater 10653f7a53b2SCédric Le Goater address_space_init(&s->dram_as, s->dram_mr, 10663f7a53b2SCédric Le Goater TYPE_ASPEED_I2C "-dma-dram"); 1067545d6befSCédric Le Goater } 1068545d6befSCédric Le Goater } 1069545d6befSCédric Le Goater 1070545d6befSCédric Le Goater static Property aspeed_i2c_properties[] = { 1071545d6befSCédric Le Goater DEFINE_PROP_LINK("dram", AspeedI2CState, dram_mr, 1072545d6befSCédric Le Goater TYPE_MEMORY_REGION, MemoryRegion *), 1073545d6befSCédric Le Goater DEFINE_PROP_END_OF_LIST(), 1074545d6befSCédric Le Goater }; 1075545d6befSCédric Le Goater 107616020011SCédric Le Goater static void aspeed_i2c_class_init(ObjectClass *klass, void *data) 107716020011SCédric Le Goater { 107816020011SCédric Le Goater DeviceClass *dc = DEVICE_CLASS(klass); 107916020011SCédric Le Goater 108016020011SCédric Le Goater dc->vmsd = &aspeed_i2c_vmstate; 108116020011SCédric Le Goater dc->reset = aspeed_i2c_reset; 10824f67d30bSMarc-André Lureau device_class_set_props(dc, aspeed_i2c_properties); 108316020011SCédric Le Goater dc->realize = aspeed_i2c_realize; 108416020011SCédric Le Goater dc->desc = "Aspeed I2C Controller"; 108516020011SCédric Le Goater } 108616020011SCédric Le Goater 108716020011SCédric Le Goater static const TypeInfo aspeed_i2c_info = { 108816020011SCédric Le Goater .name = TYPE_ASPEED_I2C, 108916020011SCédric Le Goater .parent = TYPE_SYS_BUS_DEVICE, 109060261038SCédric Le Goater .instance_init = aspeed_i2c_instance_init, 109116020011SCédric Le Goater .instance_size = sizeof(AspeedI2CState), 109216020011SCédric Le Goater .class_init = aspeed_i2c_class_init, 1093f7da1aa8SCédric Le Goater .class_size = sizeof(AspeedI2CClass), 1094f7da1aa8SCédric Le Goater .abstract = true, 1095f7da1aa8SCédric Le Goater }; 1096f7da1aa8SCédric Le Goater 10971c5d909fSPeter Delevoryas static int aspeed_i2c_bus_new_slave_event(AspeedI2CBus *bus, 10981c5d909fSPeter Delevoryas enum i2c_event event) 10991c5d909fSPeter Delevoryas { 11001c5d909fSPeter Delevoryas switch (event) { 11011c5d909fSPeter Delevoryas case I2C_START_SEND_ASYNC: 11021c5d909fSPeter Delevoryas if (!SHARED_ARRAY_FIELD_EX32(bus->regs, R_I2CS_CMD, RX_DMA_EN)) { 11031c5d909fSPeter Delevoryas qemu_log_mask(LOG_GUEST_ERROR, 11041c5d909fSPeter Delevoryas "%s: Slave mode RX DMA is not enabled\n", __func__); 11051c5d909fSPeter Delevoryas return -1; 11061c5d909fSPeter Delevoryas } 11071c5d909fSPeter Delevoryas ARRAY_FIELD_DP32(bus->regs, I2CS_DMA_LEN_STS, RX_LEN, 0); 11081c5d909fSPeter Delevoryas bus->regs[R_I2CC_DMA_ADDR] = 11091c5d909fSPeter Delevoryas ARRAY_FIELD_EX32(bus->regs, I2CS_DMA_RX_ADDR, ADDR); 11101c5d909fSPeter Delevoryas bus->regs[R_I2CC_DMA_LEN] = 11111c5d909fSPeter Delevoryas ARRAY_FIELD_EX32(bus->regs, I2CS_DMA_LEN, RX_BUF_LEN) + 1; 11121c5d909fSPeter Delevoryas i2c_ack(bus->bus); 11131c5d909fSPeter Delevoryas break; 11141c5d909fSPeter Delevoryas case I2C_FINISH: 11151c5d909fSPeter Delevoryas ARRAY_FIELD_DP32(bus->regs, I2CS_INTR_STS, PKT_CMD_DONE, 1); 11161c5d909fSPeter Delevoryas ARRAY_FIELD_DP32(bus->regs, I2CS_INTR_STS, SLAVE_ADDR_RX_MATCH, 1); 11171c5d909fSPeter Delevoryas SHARED_ARRAY_FIELD_DP32(bus->regs, R_I2CS_INTR_STS, NORMAL_STOP, 1); 11181c5d909fSPeter Delevoryas SHARED_ARRAY_FIELD_DP32(bus->regs, R_I2CS_INTR_STS, RX_DONE, 1); 11191c5d909fSPeter Delevoryas aspeed_i2c_bus_raise_slave_interrupt(bus); 11201c5d909fSPeter Delevoryas break; 11211c5d909fSPeter Delevoryas default: 11221c5d909fSPeter Delevoryas qemu_log_mask(LOG_UNIMP, "%s: i2c event %d unimplemented\n", 11231c5d909fSPeter Delevoryas __func__, event); 11241c5d909fSPeter Delevoryas return -1; 11251c5d909fSPeter Delevoryas } 11261c5d909fSPeter Delevoryas 11271c5d909fSPeter Delevoryas return 0; 11281c5d909fSPeter Delevoryas } 11291c5d909fSPeter Delevoryas 1130a8d48f59SKlaus Jensen static int aspeed_i2c_bus_slave_event(I2CSlave *slave, enum i2c_event event) 1131a8d48f59SKlaus Jensen { 1132a8d48f59SKlaus Jensen BusState *qbus = qdev_get_parent_bus(DEVICE(slave)); 1133a8d48f59SKlaus Jensen AspeedI2CBus *bus = ASPEED_I2C_BUS(qbus->parent); 1134a8d48f59SKlaus Jensen uint32_t reg_intr_sts = aspeed_i2c_bus_intr_sts_offset(bus); 1135a8d48f59SKlaus Jensen uint32_t reg_byte_buf = aspeed_i2c_bus_byte_buf_offset(bus); 11363648d31fSPeter Delevoryas uint32_t reg_dev_addr = aspeed_i2c_bus_dev_addr_offset(bus); 11373648d31fSPeter Delevoryas uint32_t dev_addr = SHARED_ARRAY_FIELD_EX32(bus->regs, reg_dev_addr, 11383648d31fSPeter Delevoryas SLAVE_DEV_ADDR1); 1139a8d48f59SKlaus Jensen 11401c5d909fSPeter Delevoryas if (aspeed_i2c_is_new_mode(bus->controller)) { 11411c5d909fSPeter Delevoryas return aspeed_i2c_bus_new_slave_event(bus, event); 11421c5d909fSPeter Delevoryas } 11431c5d909fSPeter Delevoryas 1144a8d48f59SKlaus Jensen switch (event) { 1145a8d48f59SKlaus Jensen case I2C_START_SEND_ASYNC: 11463648d31fSPeter Delevoryas /* Bit[0] == 0 indicates "send". */ 11473648d31fSPeter Delevoryas SHARED_ARRAY_FIELD_DP32(bus->regs, reg_byte_buf, RX_BUF, dev_addr << 1); 1148a8d48f59SKlaus Jensen 1149a8d48f59SKlaus Jensen ARRAY_FIELD_DP32(bus->regs, I2CD_INTR_STS, SLAVE_ADDR_RX_MATCH, 1); 1150a8d48f59SKlaus Jensen SHARED_ARRAY_FIELD_DP32(bus->regs, reg_intr_sts, RX_DONE, 1); 1151a8d48f59SKlaus Jensen 1152a8d48f59SKlaus Jensen aspeed_i2c_set_state(bus, I2CD_STXD); 1153a8d48f59SKlaus Jensen 1154a8d48f59SKlaus Jensen break; 1155a8d48f59SKlaus Jensen 1156a8d48f59SKlaus Jensen case I2C_FINISH: 1157a8d48f59SKlaus Jensen SHARED_ARRAY_FIELD_DP32(bus->regs, reg_intr_sts, NORMAL_STOP, 1); 1158a8d48f59SKlaus Jensen 1159a8d48f59SKlaus Jensen aspeed_i2c_set_state(bus, I2CD_IDLE); 1160a8d48f59SKlaus Jensen 1161a8d48f59SKlaus Jensen break; 1162a8d48f59SKlaus Jensen 1163a8d48f59SKlaus Jensen default: 1164a8d48f59SKlaus Jensen return -1; 1165a8d48f59SKlaus Jensen } 1166a8d48f59SKlaus Jensen 1167a8d48f59SKlaus Jensen aspeed_i2c_bus_raise_interrupt(bus); 1168a8d48f59SKlaus Jensen 1169a8d48f59SKlaus Jensen return 0; 1170a8d48f59SKlaus Jensen } 1171a8d48f59SKlaus Jensen 11721c5d909fSPeter Delevoryas static void aspeed_i2c_bus_new_slave_send_async(AspeedI2CBus *bus, uint8_t data) 11731c5d909fSPeter Delevoryas { 11741c5d909fSPeter Delevoryas assert(address_space_write(&bus->controller->dram_as, 11751c5d909fSPeter Delevoryas bus->regs[R_I2CC_DMA_ADDR], 11761c5d909fSPeter Delevoryas MEMTXATTRS_UNSPECIFIED, &data, 1) == MEMTX_OK); 11771c5d909fSPeter Delevoryas 11781c5d909fSPeter Delevoryas bus->regs[R_I2CC_DMA_ADDR]++; 11791c5d909fSPeter Delevoryas bus->regs[R_I2CC_DMA_LEN]--; 11801c5d909fSPeter Delevoryas ARRAY_FIELD_DP32(bus->regs, I2CS_DMA_LEN_STS, RX_LEN, 11811c5d909fSPeter Delevoryas ARRAY_FIELD_EX32(bus->regs, I2CS_DMA_LEN_STS, RX_LEN) + 1); 11821c5d909fSPeter Delevoryas i2c_ack(bus->bus); 11831c5d909fSPeter Delevoryas } 11841c5d909fSPeter Delevoryas 1185a8d48f59SKlaus Jensen static void aspeed_i2c_bus_slave_send_async(I2CSlave *slave, uint8_t data) 1186a8d48f59SKlaus Jensen { 1187a8d48f59SKlaus Jensen BusState *qbus = qdev_get_parent_bus(DEVICE(slave)); 1188a8d48f59SKlaus Jensen AspeedI2CBus *bus = ASPEED_I2C_BUS(qbus->parent); 1189a8d48f59SKlaus Jensen uint32_t reg_intr_sts = aspeed_i2c_bus_intr_sts_offset(bus); 1190a8d48f59SKlaus Jensen uint32_t reg_byte_buf = aspeed_i2c_bus_byte_buf_offset(bus); 1191a8d48f59SKlaus Jensen 11921c5d909fSPeter Delevoryas if (aspeed_i2c_is_new_mode(bus->controller)) { 11931c5d909fSPeter Delevoryas return aspeed_i2c_bus_new_slave_send_async(bus, data); 11941c5d909fSPeter Delevoryas } 11951c5d909fSPeter Delevoryas 1196a8d48f59SKlaus Jensen SHARED_ARRAY_FIELD_DP32(bus->regs, reg_byte_buf, RX_BUF, data); 1197a8d48f59SKlaus Jensen SHARED_ARRAY_FIELD_DP32(bus->regs, reg_intr_sts, RX_DONE, 1); 1198a8d48f59SKlaus Jensen 1199a8d48f59SKlaus Jensen aspeed_i2c_bus_raise_interrupt(bus); 1200a8d48f59SKlaus Jensen } 1201a8d48f59SKlaus Jensen 1202a8d48f59SKlaus Jensen static void aspeed_i2c_bus_slave_class_init(ObjectClass *klass, void *data) 1203a8d48f59SKlaus Jensen { 1204a8d48f59SKlaus Jensen DeviceClass *dc = DEVICE_CLASS(klass); 1205a8d48f59SKlaus Jensen I2CSlaveClass *sc = I2C_SLAVE_CLASS(klass); 1206a8d48f59SKlaus Jensen 1207a8d48f59SKlaus Jensen dc->desc = "Aspeed I2C Bus Slave"; 1208a8d48f59SKlaus Jensen 1209a8d48f59SKlaus Jensen sc->event = aspeed_i2c_bus_slave_event; 1210a8d48f59SKlaus Jensen sc->send_async = aspeed_i2c_bus_slave_send_async; 1211a8d48f59SKlaus Jensen } 1212a8d48f59SKlaus Jensen 1213a8d48f59SKlaus Jensen static const TypeInfo aspeed_i2c_bus_slave_info = { 1214a8d48f59SKlaus Jensen .name = TYPE_ASPEED_I2C_BUS_SLAVE, 1215a8d48f59SKlaus Jensen .parent = TYPE_I2C_SLAVE, 1216a8d48f59SKlaus Jensen .instance_size = sizeof(AspeedI2CBusSlave), 1217a8d48f59SKlaus Jensen .class_init = aspeed_i2c_bus_slave_class_init, 1218a8d48f59SKlaus Jensen }; 1219a8d48f59SKlaus Jensen 122060261038SCédric Le Goater static void aspeed_i2c_bus_reset(DeviceState *dev) 122160261038SCédric Le Goater { 122260261038SCédric Le Goater AspeedI2CBus *s = ASPEED_I2C_BUS(dev); 122360261038SCédric Le Goater 12242260fc6fSJoe Komlodi memset(s->regs, 0, sizeof(s->regs)); 122560261038SCédric Le Goater i2c_end_transfer(s->bus); 122660261038SCédric Le Goater } 122760261038SCédric Le Goater 122860261038SCédric Le Goater static void aspeed_i2c_bus_realize(DeviceState *dev, Error **errp) 122960261038SCédric Le Goater { 123060261038SCédric Le Goater AspeedI2CBus *s = ASPEED_I2C_BUS(dev); 123160261038SCédric Le Goater AspeedI2CClass *aic; 123260261038SCédric Le Goater g_autofree char *name = g_strdup_printf(TYPE_ASPEED_I2C_BUS ".%d", s->id); 123360261038SCédric Le Goater 123460261038SCédric Le Goater if (!s->controller) { 123560261038SCédric Le Goater error_setg(errp, TYPE_ASPEED_I2C_BUS ": 'controller' link not set"); 123660261038SCédric Le Goater return; 123760261038SCédric Le Goater } 123860261038SCédric Le Goater 123960261038SCédric Le Goater aic = ASPEED_I2C_GET_CLASS(s->controller); 124060261038SCédric Le Goater 124160261038SCédric Le Goater sysbus_init_irq(SYS_BUS_DEVICE(dev), &s->irq); 124260261038SCédric Le Goater 124360261038SCédric Le Goater s->bus = i2c_init_bus(dev, name); 1244a8d48f59SKlaus Jensen s->slave = i2c_slave_create_simple(s->bus, TYPE_ASPEED_I2C_BUS_SLAVE, 1245a8d48f59SKlaus Jensen 0xff); 124660261038SCédric Le Goater 124760261038SCédric Le Goater memory_region_init_io(&s->mr, OBJECT(s), &aspeed_i2c_bus_ops, 124860261038SCédric Le Goater s, name, aic->reg_size); 124960261038SCédric Le Goater sysbus_init_mmio(SYS_BUS_DEVICE(dev), &s->mr); 125060261038SCédric Le Goater } 125160261038SCédric Le Goater 125260261038SCédric Le Goater static Property aspeed_i2c_bus_properties[] = { 125360261038SCédric Le Goater DEFINE_PROP_UINT8("bus-id", AspeedI2CBus, id, 0), 125460261038SCédric Le Goater DEFINE_PROP_LINK("controller", AspeedI2CBus, controller, TYPE_ASPEED_I2C, 125560261038SCédric Le Goater AspeedI2CState *), 125660261038SCédric Le Goater DEFINE_PROP_END_OF_LIST(), 125760261038SCédric Le Goater }; 125860261038SCédric Le Goater 125960261038SCédric Le Goater static void aspeed_i2c_bus_class_init(ObjectClass *klass, void *data) 126060261038SCédric Le Goater { 126160261038SCédric Le Goater DeviceClass *dc = DEVICE_CLASS(klass); 126260261038SCédric Le Goater 126360261038SCédric Le Goater dc->desc = "Aspeed I2C Bus"; 126460261038SCédric Le Goater dc->realize = aspeed_i2c_bus_realize; 126560261038SCédric Le Goater dc->reset = aspeed_i2c_bus_reset; 126660261038SCédric Le Goater device_class_set_props(dc, aspeed_i2c_bus_properties); 126760261038SCédric Le Goater } 126860261038SCédric Le Goater 126960261038SCédric Le Goater static const TypeInfo aspeed_i2c_bus_info = { 127060261038SCédric Le Goater .name = TYPE_ASPEED_I2C_BUS, 127160261038SCédric Le Goater .parent = TYPE_SYS_BUS_DEVICE, 127260261038SCédric Le Goater .instance_size = sizeof(AspeedI2CBus), 127360261038SCédric Le Goater .class_init = aspeed_i2c_bus_class_init, 127460261038SCédric Le Goater }; 127560261038SCédric Le Goater 127651dd4923SCédric Le Goater static qemu_irq aspeed_2400_i2c_bus_get_irq(AspeedI2CBus *bus) 127751dd4923SCédric Le Goater { 127851dd4923SCédric Le Goater return bus->controller->irq; 127951dd4923SCédric Le Goater } 128051dd4923SCédric Le Goater 12816054fc73SCédric Le Goater static uint8_t *aspeed_2400_i2c_bus_pool_base(AspeedI2CBus *bus) 12826054fc73SCédric Le Goater { 12836054fc73SCédric Le Goater uint8_t *pool_page = 12842260fc6fSJoe Komlodi &bus->controller->pool[ARRAY_FIELD_EX32(bus->regs, I2CD_FUN_CTRL, 12853be3d6ccSJoe Komlodi POOL_PAGE_SEL) * 0x100]; 12866054fc73SCédric Le Goater 12872260fc6fSJoe Komlodi return &pool_page[ARRAY_FIELD_EX32(bus->regs, I2CD_POOL_CTRL, OFFSET)]; 12886054fc73SCédric Le Goater } 12896054fc73SCédric Le Goater 1290f7da1aa8SCédric Le Goater static void aspeed_2400_i2c_class_init(ObjectClass *klass, void *data) 1291f7da1aa8SCédric Le Goater { 1292f7da1aa8SCédric Le Goater DeviceClass *dc = DEVICE_CLASS(klass); 1293f7da1aa8SCédric Le Goater AspeedI2CClass *aic = ASPEED_I2C_CLASS(klass); 1294f7da1aa8SCédric Le Goater 1295f7da1aa8SCédric Le Goater dc->desc = "ASPEED 2400 I2C Controller"; 1296f7da1aa8SCédric Le Goater 1297f7da1aa8SCédric Le Goater aic->num_busses = 14; 1298f7da1aa8SCédric Le Goater aic->reg_size = 0x40; 1299f7da1aa8SCédric Le Goater aic->gap = 7; 130051dd4923SCédric Le Goater aic->bus_get_irq = aspeed_2400_i2c_bus_get_irq; 13016054fc73SCédric Le Goater aic->pool_size = 0x800; 13026054fc73SCédric Le Goater aic->pool_base = 0x800; 13036054fc73SCédric Le Goater aic->bus_pool_base = aspeed_2400_i2c_bus_pool_base; 1304f7da1aa8SCédric Le Goater } 1305f7da1aa8SCédric Le Goater 1306f7da1aa8SCédric Le Goater static const TypeInfo aspeed_2400_i2c_info = { 1307f7da1aa8SCédric Le Goater .name = TYPE_ASPEED_2400_I2C, 1308f7da1aa8SCédric Le Goater .parent = TYPE_ASPEED_I2C, 1309f7da1aa8SCédric Le Goater .class_init = aspeed_2400_i2c_class_init, 1310f7da1aa8SCédric Le Goater }; 1311f7da1aa8SCédric Le Goater 131251dd4923SCédric Le Goater static qemu_irq aspeed_2500_i2c_bus_get_irq(AspeedI2CBus *bus) 131351dd4923SCédric Le Goater { 131451dd4923SCédric Le Goater return bus->controller->irq; 131551dd4923SCédric Le Goater } 131651dd4923SCédric Le Goater 13176054fc73SCédric Le Goater static uint8_t *aspeed_2500_i2c_bus_pool_base(AspeedI2CBus *bus) 13186054fc73SCédric Le Goater { 13196054fc73SCédric Le Goater return &bus->controller->pool[bus->id * 0x10]; 13206054fc73SCédric Le Goater } 13216054fc73SCédric Le Goater 1322f7da1aa8SCédric Le Goater static void aspeed_2500_i2c_class_init(ObjectClass *klass, void *data) 1323f7da1aa8SCédric Le Goater { 1324f7da1aa8SCédric Le Goater DeviceClass *dc = DEVICE_CLASS(klass); 1325f7da1aa8SCédric Le Goater AspeedI2CClass *aic = ASPEED_I2C_CLASS(klass); 1326f7da1aa8SCédric Le Goater 1327f7da1aa8SCédric Le Goater dc->desc = "ASPEED 2500 I2C Controller"; 1328f7da1aa8SCédric Le Goater 1329f7da1aa8SCédric Le Goater aic->num_busses = 14; 1330f7da1aa8SCédric Le Goater aic->reg_size = 0x40; 1331f7da1aa8SCédric Le Goater aic->gap = 7; 133251dd4923SCédric Le Goater aic->bus_get_irq = aspeed_2500_i2c_bus_get_irq; 13336054fc73SCédric Le Goater aic->pool_size = 0x100; 13346054fc73SCédric Le Goater aic->pool_base = 0x200; 13356054fc73SCédric Le Goater aic->bus_pool_base = aspeed_2500_i2c_bus_pool_base; 1336aab90b1cSCédric Le Goater aic->check_sram = true; 1337545d6befSCédric Le Goater aic->has_dma = true; 1338f7da1aa8SCédric Le Goater } 1339f7da1aa8SCédric Le Goater 1340f7da1aa8SCédric Le Goater static const TypeInfo aspeed_2500_i2c_info = { 1341f7da1aa8SCédric Le Goater .name = TYPE_ASPEED_2500_I2C, 1342f7da1aa8SCédric Le Goater .parent = TYPE_ASPEED_I2C, 1343f7da1aa8SCédric Le Goater .class_init = aspeed_2500_i2c_class_init, 134416020011SCédric Le Goater }; 134516020011SCédric Le Goater 134651dd4923SCédric Le Goater static qemu_irq aspeed_2600_i2c_bus_get_irq(AspeedI2CBus *bus) 134751dd4923SCédric Le Goater { 134851dd4923SCédric Le Goater return bus->irq; 134951dd4923SCédric Le Goater } 135051dd4923SCédric Le Goater 13516054fc73SCédric Le Goater static uint8_t *aspeed_2600_i2c_bus_pool_base(AspeedI2CBus *bus) 13526054fc73SCédric Le Goater { 13536054fc73SCédric Le Goater return &bus->controller->pool[bus->id * 0x20]; 13546054fc73SCédric Le Goater } 13556054fc73SCédric Le Goater 135651dd4923SCédric Le Goater static void aspeed_2600_i2c_class_init(ObjectClass *klass, void *data) 135751dd4923SCédric Le Goater { 135851dd4923SCédric Le Goater DeviceClass *dc = DEVICE_CLASS(klass); 135951dd4923SCédric Le Goater AspeedI2CClass *aic = ASPEED_I2C_CLASS(klass); 136051dd4923SCédric Le Goater 136151dd4923SCédric Le Goater dc->desc = "ASPEED 2600 I2C Controller"; 136251dd4923SCédric Le Goater 136351dd4923SCédric Le Goater aic->num_busses = 16; 136451dd4923SCédric Le Goater aic->reg_size = 0x80; 136551dd4923SCédric Le Goater aic->gap = -1; /* no gap */ 136651dd4923SCédric Le Goater aic->bus_get_irq = aspeed_2600_i2c_bus_get_irq; 13676054fc73SCédric Le Goater aic->pool_size = 0x200; 13686054fc73SCédric Le Goater aic->pool_base = 0xC00; 13696054fc73SCédric Le Goater aic->bus_pool_base = aspeed_2600_i2c_bus_pool_base; 1370545d6befSCédric Le Goater aic->has_dma = true; 137151dd4923SCédric Le Goater } 137251dd4923SCédric Le Goater 137351dd4923SCédric Le Goater static const TypeInfo aspeed_2600_i2c_info = { 137451dd4923SCédric Le Goater .name = TYPE_ASPEED_2600_I2C, 137551dd4923SCédric Le Goater .parent = TYPE_ASPEED_I2C, 137651dd4923SCédric Le Goater .class_init = aspeed_2600_i2c_class_init, 137751dd4923SCédric Le Goater }; 137851dd4923SCédric Le Goater 1379b35802ceSCédric Le Goater static void aspeed_1030_i2c_class_init(ObjectClass *klass, void *data) 1380b35802ceSCédric Le Goater { 1381b35802ceSCédric Le Goater DeviceClass *dc = DEVICE_CLASS(klass); 1382b35802ceSCédric Le Goater AspeedI2CClass *aic = ASPEED_I2C_CLASS(klass); 1383b35802ceSCédric Le Goater 1384b35802ceSCédric Le Goater dc->desc = "ASPEED 1030 I2C Controller"; 1385b35802ceSCédric Le Goater 1386b35802ceSCédric Le Goater aic->num_busses = 14; 1387b35802ceSCédric Le Goater aic->reg_size = 0x80; 1388b35802ceSCédric Le Goater aic->gap = -1; /* no gap */ 1389b35802ceSCédric Le Goater aic->bus_get_irq = aspeed_2600_i2c_bus_get_irq; 1390b35802ceSCédric Le Goater aic->pool_size = 0x200; 1391b35802ceSCédric Le Goater aic->pool_base = 0xC00; 1392b35802ceSCédric Le Goater aic->bus_pool_base = aspeed_2600_i2c_bus_pool_base; 1393b35802ceSCédric Le Goater aic->has_dma = true; 1394b35802ceSCédric Le Goater } 1395b35802ceSCédric Le Goater 1396b35802ceSCédric Le Goater static const TypeInfo aspeed_1030_i2c_info = { 1397b35802ceSCédric Le Goater .name = TYPE_ASPEED_1030_I2C, 1398b35802ceSCédric Le Goater .parent = TYPE_ASPEED_I2C, 1399b35802ceSCédric Le Goater .class_init = aspeed_1030_i2c_class_init, 1400b35802ceSCédric Le Goater }; 1401b35802ceSCédric Le Goater 140216020011SCédric Le Goater static void aspeed_i2c_register_types(void) 140316020011SCédric Le Goater { 140460261038SCédric Le Goater type_register_static(&aspeed_i2c_bus_info); 1405a8d48f59SKlaus Jensen type_register_static(&aspeed_i2c_bus_slave_info); 140616020011SCédric Le Goater type_register_static(&aspeed_i2c_info); 1407f7da1aa8SCédric Le Goater type_register_static(&aspeed_2400_i2c_info); 1408f7da1aa8SCédric Le Goater type_register_static(&aspeed_2500_i2c_info); 140951dd4923SCédric Le Goater type_register_static(&aspeed_2600_i2c_info); 1410b35802ceSCédric Le Goater type_register_static(&aspeed_1030_i2c_info); 141116020011SCédric Le Goater } 141216020011SCédric Le Goater 141316020011SCédric Le Goater type_init(aspeed_i2c_register_types) 141416020011SCédric Le Goater 141516020011SCédric Le Goater 14167a204cbdSPhilippe Mathieu-Daudé I2CBus *aspeed_i2c_get_bus(AspeedI2CState *s, int busnr) 141716020011SCédric Le Goater { 1418f7da1aa8SCédric Le Goater AspeedI2CClass *aic = ASPEED_I2C_GET_CLASS(s); 141916020011SCédric Le Goater I2CBus *bus = NULL; 142016020011SCédric Le Goater 1421f7da1aa8SCédric Le Goater if (busnr >= 0 && busnr < aic->num_busses) { 142216020011SCédric Le Goater bus = s->busses[busnr].bus; 142316020011SCédric Le Goater } 142416020011SCédric Le Goater 142516020011SCédric Le Goater return bus; 142616020011SCédric Le Goater } 1427