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 229961faf3dSHang Yu static int aspeed_i2c_bus_send(AspeedI2CBus *bus) 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, 23997b8aa5aSHang Yu TX_COUNT) + 1; 2406054fc73SCédric Le Goater 241ba2cccd6SJoe Komlodi if (SHARED_ARRAY_FIELD_EX32(bus->regs, reg_cmd, TX_BUFF_EN)) { 242961faf3dSHang Yu for (i = 0; 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 { 276961faf3dSHang Yu trace_aspeed_i2c_bus_send("BYTE", 0, 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, 29697b8aa5aSHang Yu RX_SIZE) + 1; 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); 300*acc3d20aSHang Yu if (SHARED_ARRAY_FIELD_EX32(bus->regs, reg_pool_ctrl, 301*acc3d20aSHang Yu BUF_ORGANIZATION)) { 302*acc3d20aSHang Yu pool_base += 16; 303*acc3d20aSHang Yu } 3046054fc73SCédric Le Goater 3053be3d6ccSJoe Komlodi for (i = 0; i < pool_rx_count; i++) { 3066054fc73SCédric Le Goater pool_base[i] = i2c_recv(bus->bus); 3073be3d6ccSJoe Komlodi trace_aspeed_i2c_bus_recv("BUF", i + 1, pool_rx_count, 30866cc84a1SCédric Le Goater pool_base[i]); 3096054fc73SCédric Le Goater } 3106054fc73SCédric Le Goater 3116054fc73SCédric Le Goater /* Update RX count */ 312ba2cccd6SJoe Komlodi SHARED_ARRAY_FIELD_DP32(bus->regs, reg_pool_ctrl, RX_COUNT, i & 0xff); 313ba2cccd6SJoe Komlodi SHARED_ARRAY_FIELD_DP32(bus->regs, reg_cmd, RX_BUFF_EN, 0); 314ba2cccd6SJoe Komlodi } else if (SHARED_ARRAY_FIELD_EX32(bus->regs, reg_cmd, RX_DMA_EN)) { 315545d6befSCédric Le Goater uint8_t data; 316ba2cccd6SJoe Komlodi /* In new mode, clear how many bytes we RXed */ 317ba2cccd6SJoe Komlodi if (aspeed_i2c_is_new_mode(bus->controller)) { 318ba2cccd6SJoe Komlodi ARRAY_FIELD_DP32(bus->regs, I2CM_DMA_LEN_STS, RX_LEN, 0); 319ba2cccd6SJoe Komlodi } 320545d6befSCédric Le Goater 321ba2cccd6SJoe Komlodi while (bus->regs[reg_dma_len]) { 322545d6befSCédric Le Goater MemTxResult result; 323545d6befSCédric Le Goater 324545d6befSCédric Le Goater data = i2c_recv(bus->bus); 325ba2cccd6SJoe Komlodi trace_aspeed_i2c_bus_recv("DMA", bus->regs[reg_dma_len], 326ba2cccd6SJoe Komlodi bus->regs[reg_dma_len], data); 327ba2cccd6SJoe Komlodi result = address_space_write(&s->dram_as, bus->regs[reg_dma_addr], 328545d6befSCédric Le Goater MEMTXATTRS_UNSPECIFIED, &data, 1); 329545d6befSCédric Le Goater if (result != MEMTX_OK) { 330545d6befSCédric Le Goater qemu_log_mask(LOG_GUEST_ERROR, "%s: DRAM write failed @%08x\n", 331ba2cccd6SJoe Komlodi __func__, bus->regs[reg_dma_addr]); 332545d6befSCédric Le Goater return; 333545d6befSCédric Le Goater } 334ba2cccd6SJoe Komlodi bus->regs[reg_dma_addr]++; 335ba2cccd6SJoe Komlodi bus->regs[reg_dma_len]--; 336ba2cccd6SJoe Komlodi /* In new mode, keep track of how many bytes we RXed */ 337ba2cccd6SJoe Komlodi if (aspeed_i2c_is_new_mode(bus->controller)) { 338ba2cccd6SJoe Komlodi ARRAY_FIELD_DP32(bus->regs, I2CM_DMA_LEN_STS, RX_LEN, 339ba2cccd6SJoe Komlodi ARRAY_FIELD_EX32(bus->regs, I2CM_DMA_LEN_STS, 340ba2cccd6SJoe Komlodi RX_LEN) + 1); 341545d6befSCédric Le Goater } 342ba2cccd6SJoe Komlodi } 343ba2cccd6SJoe Komlodi SHARED_ARRAY_FIELD_DP32(bus->regs, reg_cmd, RX_DMA_EN, 0); 3446054fc73SCédric Le Goater } else { 3456054fc73SCédric Le Goater data = i2c_recv(bus->bus); 346ba2cccd6SJoe Komlodi trace_aspeed_i2c_bus_recv("BYTE", 1, 1, bus->regs[reg_byte_buf]); 347ba2cccd6SJoe Komlodi SHARED_ARRAY_FIELD_DP32(bus->regs, reg_byte_buf, RX_BUF, data); 3486054fc73SCédric Le Goater } 3496054fc73SCédric Le Goater } 3506054fc73SCédric Le Goater 3517bd9c60dSGuenter Roeck static void aspeed_i2c_handle_rx_cmd(AspeedI2CBus *bus) 3527bd9c60dSGuenter Roeck { 353ba2cccd6SJoe Komlodi uint32_t reg_cmd = aspeed_i2c_bus_cmd_offset(bus); 354ba2cccd6SJoe Komlodi uint32_t reg_intr_sts = aspeed_i2c_bus_intr_sts_offset(bus); 355ba2cccd6SJoe Komlodi 3567bd9c60dSGuenter Roeck aspeed_i2c_set_state(bus, I2CD_MRXD); 3576054fc73SCédric Le Goater aspeed_i2c_bus_recv(bus); 358ba2cccd6SJoe Komlodi SHARED_ARRAY_FIELD_DP32(bus->regs, reg_intr_sts, RX_DONE, 1); 359ba2cccd6SJoe Komlodi if (SHARED_ARRAY_FIELD_EX32(bus->regs, reg_cmd, M_S_RX_CMD_LAST)) { 3607bd9c60dSGuenter Roeck i2c_nack(bus->bus); 3617bd9c60dSGuenter Roeck } 362ba2cccd6SJoe Komlodi SHARED_ARRAY_FIELD_DP32(bus->regs, reg_cmd, M_RX_CMD, 0); 363ba2cccd6SJoe Komlodi SHARED_ARRAY_FIELD_DP32(bus->regs, reg_cmd, M_S_RX_CMD_LAST, 0); 3647bd9c60dSGuenter Roeck aspeed_i2c_set_state(bus, I2CD_MACTIVE); 3657bd9c60dSGuenter Roeck } 3667bd9c60dSGuenter Roeck 3676054fc73SCédric Le Goater static uint8_t aspeed_i2c_get_addr(AspeedI2CBus *bus) 3686054fc73SCédric Le Goater { 3696054fc73SCédric Le Goater AspeedI2CClass *aic = ASPEED_I2C_GET_CLASS(bus->controller); 370ba2cccd6SJoe Komlodi uint32_t reg_byte_buf = aspeed_i2c_bus_byte_buf_offset(bus); 371ba2cccd6SJoe Komlodi uint32_t reg_cmd = aspeed_i2c_bus_cmd_offset(bus); 3726054fc73SCédric Le Goater 373ba2cccd6SJoe Komlodi if (aspeed_i2c_bus_pkt_mode_en(bus)) { 374ba2cccd6SJoe Komlodi return (ARRAY_FIELD_EX32(bus->regs, I2CM_CMD, PKT_DEV_ADDR) << 1) | 375ba2cccd6SJoe Komlodi SHARED_ARRAY_FIELD_EX32(bus->regs, reg_cmd, M_RX_CMD); 376ba2cccd6SJoe Komlodi } 377ba2cccd6SJoe Komlodi if (SHARED_ARRAY_FIELD_EX32(bus->regs, reg_cmd, TX_BUFF_EN)) { 3786054fc73SCédric Le Goater uint8_t *pool_base = aic->bus_pool_base(bus); 3796054fc73SCédric Le Goater 3806054fc73SCédric Le Goater return pool_base[0]; 381ba2cccd6SJoe Komlodi } else if (SHARED_ARRAY_FIELD_EX32(bus->regs, reg_cmd, TX_DMA_EN)) { 382545d6befSCédric Le Goater uint8_t data; 383545d6befSCédric Le Goater 384545d6befSCédric Le Goater aspeed_i2c_dma_read(bus, &data); 385545d6befSCédric Le Goater return data; 3866054fc73SCédric Le Goater } else { 387ba2cccd6SJoe Komlodi return bus->regs[reg_byte_buf]; 3886054fc73SCédric Le Goater } 3896054fc73SCédric Le Goater } 3906054fc73SCédric Le Goater 391aab90b1cSCédric Le Goater static bool aspeed_i2c_check_sram(AspeedI2CBus *bus) 392aab90b1cSCédric Le Goater { 393aab90b1cSCédric Le Goater AspeedI2CState *s = bus->controller; 394aab90b1cSCédric Le Goater AspeedI2CClass *aic = ASPEED_I2C_GET_CLASS(s); 395ba2cccd6SJoe Komlodi uint32_t reg_cmd = aspeed_i2c_bus_cmd_offset(bus); 396ba2cccd6SJoe Komlodi bool dma_en = SHARED_ARRAY_FIELD_EX32(bus->regs, reg_cmd, RX_DMA_EN) || 397ba2cccd6SJoe Komlodi SHARED_ARRAY_FIELD_EX32(bus->regs, reg_cmd, TX_DMA_EN) || 398ba2cccd6SJoe Komlodi SHARED_ARRAY_FIELD_EX32(bus->regs, reg_cmd, RX_BUFF_EN) || 399ba2cccd6SJoe Komlodi SHARED_ARRAY_FIELD_EX32(bus->regs, reg_cmd, TX_BUFF_EN); 400aab90b1cSCédric Le Goater if (!aic->check_sram) { 401aab90b1cSCédric Le Goater return true; 402aab90b1cSCédric Le Goater } 403aab90b1cSCédric Le Goater 404aab90b1cSCédric Le Goater /* 405aab90b1cSCédric Le Goater * AST2500: SRAM must be enabled before using the Buffer Pool or 406aab90b1cSCédric Le Goater * DMA mode. 407aab90b1cSCédric Le Goater */ 4083be3d6ccSJoe Komlodi if (!FIELD_EX32(s->ctrl_global, I2C_CTRL_GLOBAL, SRAM_EN) && dma_en) { 409aab90b1cSCédric Le Goater qemu_log_mask(LOG_GUEST_ERROR, "%s: SRAM is not enabled\n", __func__); 410aab90b1cSCédric Le Goater return false; 411aab90b1cSCédric Le Goater } 412aab90b1cSCédric Le Goater 413aab90b1cSCédric Le Goater return true; 414aab90b1cSCédric Le Goater } 415aab90b1cSCédric Le Goater 41666cc84a1SCédric Le Goater static void aspeed_i2c_bus_cmd_dump(AspeedI2CBus *bus) 41766cc84a1SCédric Le Goater { 418f821bac4SMiroslav Rezanina g_autofree char *cmd_flags = NULL; 41966cc84a1SCédric Le Goater uint32_t count; 420ba2cccd6SJoe Komlodi uint32_t reg_cmd = aspeed_i2c_bus_cmd_offset(bus); 421ba2cccd6SJoe Komlodi uint32_t reg_pool_ctrl = aspeed_i2c_bus_pool_ctrl_offset(bus); 422ba2cccd6SJoe Komlodi uint32_t reg_intr_sts = aspeed_i2c_bus_intr_sts_offset(bus); 423ba2cccd6SJoe Komlodi uint32_t reg_dma_len = aspeed_i2c_bus_dma_len_offset(bus); 424ba2cccd6SJoe Komlodi if (SHARED_ARRAY_FIELD_EX32(bus->regs, reg_cmd, RX_BUFF_EN)) { 42597b8aa5aSHang Yu count = SHARED_ARRAY_FIELD_EX32(bus->regs, reg_pool_ctrl, TX_COUNT) + 1; 426ba2cccd6SJoe Komlodi } else if (SHARED_ARRAY_FIELD_EX32(bus->regs, reg_cmd, RX_DMA_EN)) { 427ba2cccd6SJoe Komlodi count = bus->regs[reg_dma_len]; 42866cc84a1SCédric Le Goater } else { /* BYTE mode */ 42966cc84a1SCédric Le Goater count = 1; 43066cc84a1SCédric Le Goater } 43166cc84a1SCédric Le Goater 43266cc84a1SCédric Le Goater cmd_flags = g_strdup_printf("%s%s%s%s%s%s%s%s%s", 433ba2cccd6SJoe Komlodi SHARED_ARRAY_FIELD_EX32(bus->regs, reg_cmd, M_START_CMD) ? "start|" : "", 434ba2cccd6SJoe Komlodi SHARED_ARRAY_FIELD_EX32(bus->regs, reg_cmd, RX_DMA_EN) ? "rxdma|" : "", 435ba2cccd6SJoe Komlodi SHARED_ARRAY_FIELD_EX32(bus->regs, reg_cmd, TX_DMA_EN) ? "txdma|" : "", 436ba2cccd6SJoe Komlodi SHARED_ARRAY_FIELD_EX32(bus->regs, reg_cmd, RX_BUFF_EN) ? "rxbuf|" : "", 437ba2cccd6SJoe Komlodi SHARED_ARRAY_FIELD_EX32(bus->regs, reg_cmd, TX_BUFF_EN) ? "txbuf|" : "", 438ba2cccd6SJoe Komlodi SHARED_ARRAY_FIELD_EX32(bus->regs, reg_cmd, M_TX_CMD) ? "tx|" : "", 439ba2cccd6SJoe Komlodi SHARED_ARRAY_FIELD_EX32(bus->regs, reg_cmd, M_RX_CMD) ? "rx|" : "", 440ba2cccd6SJoe Komlodi SHARED_ARRAY_FIELD_EX32(bus->regs, reg_cmd, M_S_RX_CMD_LAST) ? "last|" : "", 441ba2cccd6SJoe Komlodi SHARED_ARRAY_FIELD_EX32(bus->regs, reg_cmd, M_STOP_CMD) ? "stop|" : ""); 44266cc84a1SCédric Le Goater 443ba2cccd6SJoe Komlodi trace_aspeed_i2c_bus_cmd(bus->regs[reg_cmd], cmd_flags, count, 444ba2cccd6SJoe Komlodi bus->regs[reg_intr_sts]); 44566cc84a1SCédric Le Goater } 44666cc84a1SCédric Le Goater 4474960f084SCédric Le Goater /* 4484960f084SCédric Le Goater * The state machine needs some refinement. It is only used to track 4494960f084SCédric Le Goater * invalid STOP commands for the moment. 4504960f084SCédric Le Goater */ 45116020011SCédric Le Goater static void aspeed_i2c_bus_handle_cmd(AspeedI2CBus *bus, uint64_t value) 45216020011SCédric Le Goater { 453ba2cccd6SJoe Komlodi uint32_t reg_intr_sts = aspeed_i2c_bus_intr_sts_offset(bus); 454ba2cccd6SJoe Komlodi uint32_t reg_cmd = aspeed_i2c_bus_cmd_offset(bus); 455ba2cccd6SJoe Komlodi uint32_t reg_dma_len = aspeed_i2c_bus_dma_len_offset(bus); 45616020011SCédric Le Goater 457aab90b1cSCédric Le Goater if (!aspeed_i2c_check_sram(bus)) { 458aab90b1cSCédric Le Goater return; 459aab90b1cSCédric Le Goater } 460aab90b1cSCédric Le Goater 46166cc84a1SCédric Le Goater if (trace_event_get_state_backends(TRACE_ASPEED_I2C_BUS_CMD)) { 46266cc84a1SCédric Le Goater aspeed_i2c_bus_cmd_dump(bus); 46366cc84a1SCédric Le Goater } 46466cc84a1SCédric Le Goater 465ba2cccd6SJoe Komlodi if (SHARED_ARRAY_FIELD_EX32(bus->regs, reg_cmd, M_START_CMD)) { 4664960f084SCédric Le Goater uint8_t state = aspeed_i2c_get_state(bus) & I2CD_MACTIVE ? 4674960f084SCédric Le Goater I2CD_MSTARTR : I2CD_MSTART; 4686054fc73SCédric Le Goater uint8_t addr; 4694960f084SCédric Le Goater 4704960f084SCédric Le Goater aspeed_i2c_set_state(bus, state); 4714960f084SCédric Le Goater 4726054fc73SCédric Le Goater addr = aspeed_i2c_get_addr(bus); 4736054fc73SCédric Le Goater if (i2c_start_transfer(bus->bus, extract32(addr, 1, 7), 4746054fc73SCédric Le Goater extract32(addr, 0, 1))) { 475ba2cccd6SJoe Komlodi SHARED_ARRAY_FIELD_DP32(bus->regs, reg_intr_sts, TX_NAK, 1); 476ba2cccd6SJoe Komlodi if (aspeed_i2c_bus_pkt_mode_en(bus)) { 477ba2cccd6SJoe Komlodi ARRAY_FIELD_DP32(bus->regs, I2CM_INTR_STS, PKT_CMD_FAIL, 1); 478ba2cccd6SJoe Komlodi } 47916020011SCédric Le Goater } else { 480ba2cccd6SJoe Komlodi /* START doesn't set TX_ACK in packet mode */ 481ba2cccd6SJoe Komlodi if (!aspeed_i2c_bus_pkt_mode_en(bus)) { 482ba2cccd6SJoe Komlodi SHARED_ARRAY_FIELD_DP32(bus->regs, reg_intr_sts, TX_ACK, 1); 483ba2cccd6SJoe Komlodi } 48416020011SCédric Le Goater } 48516020011SCédric Le Goater 486ba2cccd6SJoe Komlodi SHARED_ARRAY_FIELD_DP32(bus->regs, reg_cmd, M_START_CMD, 0); 4876054fc73SCédric Le Goater 488961faf3dSHang Yu if (SHARED_ARRAY_FIELD_EX32(bus->regs, reg_cmd, TX_DMA_EN)) { 489ba2cccd6SJoe Komlodi if (bus->regs[reg_dma_len] == 0) { 490ba2cccd6SJoe Komlodi SHARED_ARRAY_FIELD_DP32(bus->regs, reg_cmd, M_TX_CMD, 0); 491545d6befSCédric Le Goater } 492961faf3dSHang Yu } else if (!SHARED_ARRAY_FIELD_EX32(bus->regs, reg_cmd, TX_BUFF_EN)) { 493ba2cccd6SJoe Komlodi SHARED_ARRAY_FIELD_DP32(bus->regs, reg_cmd, M_TX_CMD, 0); 4946054fc73SCédric Le Goater } 495ddabca75SCédric Le Goater 496ddabca75SCédric Le Goater /* No slave found */ 497ddabca75SCédric Le Goater if (!i2c_bus_busy(bus->bus)) { 498ba2cccd6SJoe Komlodi if (aspeed_i2c_bus_pkt_mode_en(bus)) { 499ba2cccd6SJoe Komlodi ARRAY_FIELD_DP32(bus->regs, I2CM_INTR_STS, PKT_CMD_FAIL, 1); 500ba2cccd6SJoe Komlodi ARRAY_FIELD_DP32(bus->regs, I2CM_INTR_STS, PKT_CMD_DONE, 1); 501ba2cccd6SJoe Komlodi } 502ddabca75SCédric Le Goater return; 503ddabca75SCédric Le Goater } 5044960f084SCédric Le Goater aspeed_i2c_set_state(bus, I2CD_MACTIVE); 505ddabca75SCédric Le Goater } 506ddabca75SCédric Le Goater 507ba2cccd6SJoe Komlodi if (SHARED_ARRAY_FIELD_EX32(bus->regs, reg_cmd, M_TX_CMD)) { 5084960f084SCédric Le Goater aspeed_i2c_set_state(bus, I2CD_MTXD); 509961faf3dSHang Yu if (aspeed_i2c_bus_send(bus)) { 510ba2cccd6SJoe Komlodi SHARED_ARRAY_FIELD_DP32(bus->regs, reg_intr_sts, TX_NAK, 1); 51116020011SCédric Le Goater i2c_end_transfer(bus->bus); 51216020011SCédric Le Goater } else { 513ba2cccd6SJoe Komlodi SHARED_ARRAY_FIELD_DP32(bus->regs, reg_intr_sts, TX_ACK, 1); 51416020011SCédric Le Goater } 515ba2cccd6SJoe Komlodi SHARED_ARRAY_FIELD_DP32(bus->regs, reg_cmd, M_TX_CMD, 0); 5164960f084SCédric Le Goater aspeed_i2c_set_state(bus, I2CD_MACTIVE); 517ddabca75SCédric Le Goater } 51816020011SCédric Le Goater 519ba2cccd6SJoe Komlodi if ((SHARED_ARRAY_FIELD_EX32(bus->regs, reg_cmd, M_RX_CMD) || 520ba2cccd6SJoe Komlodi SHARED_ARRAY_FIELD_EX32(bus->regs, reg_cmd, M_S_RX_CMD_LAST)) && 521ba2cccd6SJoe Komlodi !SHARED_ARRAY_FIELD_EX32(bus->regs, reg_intr_sts, RX_DONE)) { 5227bd9c60dSGuenter Roeck aspeed_i2c_handle_rx_cmd(bus); 52316020011SCédric Le Goater } 52416020011SCédric Le Goater 525ba2cccd6SJoe Komlodi if (SHARED_ARRAY_FIELD_EX32(bus->regs, reg_cmd, M_STOP_CMD)) { 5264960f084SCédric Le Goater if (!(aspeed_i2c_get_state(bus) & I2CD_MACTIVE)) { 5274960f084SCédric Le Goater qemu_log_mask(LOG_GUEST_ERROR, "%s: abnormal stop\n", __func__); 528ba2cccd6SJoe Komlodi SHARED_ARRAY_FIELD_DP32(bus->regs, reg_intr_sts, ABNORMAL, 1); 529ba2cccd6SJoe Komlodi if (aspeed_i2c_bus_pkt_mode_en(bus)) { 530ba2cccd6SJoe Komlodi ARRAY_FIELD_DP32(bus->regs, I2CM_INTR_STS, PKT_CMD_FAIL, 1); 531ba2cccd6SJoe Komlodi } 53216020011SCédric Le Goater } else { 5334960f084SCédric Le Goater aspeed_i2c_set_state(bus, I2CD_MSTOP); 53416020011SCédric Le Goater i2c_end_transfer(bus->bus); 535ba2cccd6SJoe Komlodi SHARED_ARRAY_FIELD_DP32(bus->regs, reg_intr_sts, NORMAL_STOP, 1); 53616020011SCédric Le Goater } 537ba2cccd6SJoe Komlodi SHARED_ARRAY_FIELD_DP32(bus->regs, reg_cmd, M_STOP_CMD, 0); 5384960f084SCédric Le Goater aspeed_i2c_set_state(bus, I2CD_IDLE); 539791cb95fSKlaus Jensen 540791cb95fSKlaus Jensen i2c_schedule_pending_master(bus->bus); 54116020011SCédric Le Goater } 542ba2cccd6SJoe Komlodi 543ba2cccd6SJoe Komlodi if (aspeed_i2c_bus_pkt_mode_en(bus)) { 544ba2cccd6SJoe Komlodi ARRAY_FIELD_DP32(bus->regs, I2CM_INTR_STS, PKT_CMD_DONE, 1); 545ba2cccd6SJoe Komlodi } 54616020011SCédric Le Goater } 54716020011SCédric Le Goater 548ba2cccd6SJoe Komlodi static void aspeed_i2c_bus_new_write(AspeedI2CBus *bus, hwaddr offset, 54916020011SCédric Le Goater uint64_t value, unsigned size) 55016020011SCédric Le Goater { 551ba2cccd6SJoe Komlodi AspeedI2CClass *aic = ASPEED_I2C_GET_CLASS(bus->controller); 552ba2cccd6SJoe Komlodi bool handle_rx; 553ba2cccd6SJoe Komlodi bool w1t; 554ba2cccd6SJoe Komlodi 555ba2cccd6SJoe Komlodi trace_aspeed_i2c_bus_write(bus->id, offset, size, value); 556ba2cccd6SJoe Komlodi 557ba2cccd6SJoe Komlodi switch (offset) { 558ba2cccd6SJoe Komlodi case A_I2CC_FUN_CTRL: 5591c5d909fSPeter Delevoryas bus->regs[R_I2CC_FUN_CTRL] = value; 560ba2cccd6SJoe Komlodi break; 561ba2cccd6SJoe Komlodi case A_I2CC_AC_TIMING: 562ba2cccd6SJoe Komlodi bus->regs[R_I2CC_AC_TIMING] = value & 0x1ffff0ff; 563ba2cccd6SJoe Komlodi break; 564ba2cccd6SJoe Komlodi case A_I2CC_MS_TXRX_BYTE_BUF: 565ba2cccd6SJoe Komlodi SHARED_ARRAY_FIELD_DP32(bus->regs, R_I2CC_MS_TXRX_BYTE_BUF, TX_BUF, 566ba2cccd6SJoe Komlodi value); 567ba2cccd6SJoe Komlodi break; 568ba2cccd6SJoe Komlodi case A_I2CC_POOL_CTRL: 569ba2cccd6SJoe Komlodi bus->regs[R_I2CC_POOL_CTRL] &= ~0xffffff; 570ba2cccd6SJoe Komlodi bus->regs[R_I2CC_POOL_CTRL] |= (value & 0xffffff); 571ba2cccd6SJoe Komlodi break; 572ba2cccd6SJoe Komlodi case A_I2CM_INTR_CTRL: 573ba2cccd6SJoe Komlodi bus->regs[R_I2CM_INTR_CTRL] = value & 0x0007f07f; 574ba2cccd6SJoe Komlodi break; 575ba2cccd6SJoe Komlodi case A_I2CM_INTR_STS: 576ba2cccd6SJoe Komlodi handle_rx = SHARED_ARRAY_FIELD_EX32(bus->regs, R_I2CM_INTR_STS, RX_DONE) 577ba2cccd6SJoe Komlodi && SHARED_FIELD_EX32(value, RX_DONE); 578ba2cccd6SJoe Komlodi 579ba2cccd6SJoe Komlodi /* In packet mode, clearing PKT_CMD_DONE clears other interrupts. */ 580ba2cccd6SJoe Komlodi if (aspeed_i2c_bus_pkt_mode_en(bus) && 581ba2cccd6SJoe Komlodi FIELD_EX32(value, I2CM_INTR_STS, PKT_CMD_DONE)) { 582ba2cccd6SJoe Komlodi bus->regs[R_I2CM_INTR_STS] &= 0xf0001000; 583ba2cccd6SJoe Komlodi if (!bus->regs[R_I2CM_INTR_STS]) { 584ba2cccd6SJoe Komlodi bus->controller->intr_status &= ~(1 << bus->id); 585ba2cccd6SJoe Komlodi qemu_irq_lower(aic->bus_get_irq(bus)); 586ba2cccd6SJoe Komlodi } 5871c5d909fSPeter Delevoryas aspeed_i2c_bus_raise_slave_interrupt(bus); 588ba2cccd6SJoe Komlodi break; 589ba2cccd6SJoe Komlodi } 590ba2cccd6SJoe Komlodi bus->regs[R_I2CM_INTR_STS] &= ~(value & 0xf007f07f); 591ba2cccd6SJoe Komlodi if (!bus->regs[R_I2CM_INTR_STS]) { 592ba2cccd6SJoe Komlodi bus->controller->intr_status &= ~(1 << bus->id); 593ba2cccd6SJoe Komlodi qemu_irq_lower(aic->bus_get_irq(bus)); 594ba2cccd6SJoe Komlodi } 595ba2cccd6SJoe Komlodi if (handle_rx && (SHARED_ARRAY_FIELD_EX32(bus->regs, R_I2CM_CMD, 596ba2cccd6SJoe Komlodi M_RX_CMD) || 597ba2cccd6SJoe Komlodi SHARED_ARRAY_FIELD_EX32(bus->regs, R_I2CM_CMD, 598ba2cccd6SJoe Komlodi M_S_RX_CMD_LAST))) { 599ba2cccd6SJoe Komlodi aspeed_i2c_handle_rx_cmd(bus); 600ba2cccd6SJoe Komlodi aspeed_i2c_bus_raise_interrupt(bus); 601ba2cccd6SJoe Komlodi } 602ba2cccd6SJoe Komlodi break; 603ba2cccd6SJoe Komlodi case A_I2CM_CMD: 604ba2cccd6SJoe Komlodi if (!aspeed_i2c_bus_is_enabled(bus)) { 605ba2cccd6SJoe Komlodi break; 606ba2cccd6SJoe Komlodi } 607ba2cccd6SJoe Komlodi 608ba2cccd6SJoe Komlodi if (!aspeed_i2c_bus_is_master(bus)) { 6090c0f1beeSPeter Delevoryas qemu_log_mask(LOG_GUEST_ERROR, "%s: Master mode is not enabled\n", 610ba2cccd6SJoe Komlodi __func__); 611ba2cccd6SJoe Komlodi break; 612ba2cccd6SJoe Komlodi } 613ba2cccd6SJoe Komlodi 614ba2cccd6SJoe Komlodi if (!aic->has_dma && 615ba2cccd6SJoe Komlodi (SHARED_FIELD_EX32(value, RX_DMA_EN) || 616ba2cccd6SJoe Komlodi SHARED_FIELD_EX32(value, TX_DMA_EN))) { 617ba2cccd6SJoe Komlodi qemu_log_mask(LOG_GUEST_ERROR, "%s: No DMA support\n", __func__); 618ba2cccd6SJoe Komlodi break; 619ba2cccd6SJoe Komlodi } 620ba2cccd6SJoe Komlodi 621ba2cccd6SJoe Komlodi if (bus->regs[R_I2CM_INTR_STS] & 0xffff0000) { 622ba2cccd6SJoe Komlodi qemu_log_mask(LOG_UNIMP, "%s: Packet mode is not implemented\n", 623ba2cccd6SJoe Komlodi __func__); 624ba2cccd6SJoe Komlodi break; 625ba2cccd6SJoe Komlodi } 626ba2cccd6SJoe Komlodi 627ba2cccd6SJoe Komlodi value &= 0xff0ffbfb; 628ba2cccd6SJoe Komlodi if (ARRAY_FIELD_EX32(bus->regs, I2CM_CMD, W1_CTRL)) { 629ba2cccd6SJoe Komlodi bus->regs[R_I2CM_CMD] |= value; 630ba2cccd6SJoe Komlodi } else { 631ba2cccd6SJoe Komlodi bus->regs[R_I2CM_CMD] = value; 632ba2cccd6SJoe Komlodi } 633ba2cccd6SJoe Komlodi 634ba2cccd6SJoe Komlodi aspeed_i2c_bus_handle_cmd(bus, value); 635ba2cccd6SJoe Komlodi aspeed_i2c_bus_raise_interrupt(bus); 636ba2cccd6SJoe Komlodi break; 637ba2cccd6SJoe Komlodi case A_I2CM_DMA_TX_ADDR: 638ba2cccd6SJoe Komlodi bus->regs[R_I2CM_DMA_TX_ADDR] = FIELD_EX32(value, I2CM_DMA_TX_ADDR, 639ba2cccd6SJoe Komlodi ADDR); 640ba2cccd6SJoe Komlodi bus->regs[R_I2CC_DMA_ADDR] = FIELD_EX32(value, I2CM_DMA_TX_ADDR, ADDR); 641ba2cccd6SJoe Komlodi bus->regs[R_I2CC_DMA_LEN] = ARRAY_FIELD_EX32(bus->regs, I2CM_DMA_LEN, 642ba2cccd6SJoe Komlodi TX_BUF_LEN) + 1; 643ba2cccd6SJoe Komlodi break; 644ba2cccd6SJoe Komlodi case A_I2CM_DMA_RX_ADDR: 645ba2cccd6SJoe Komlodi bus->regs[R_I2CM_DMA_RX_ADDR] = FIELD_EX32(value, I2CM_DMA_RX_ADDR, 646ba2cccd6SJoe Komlodi ADDR); 647ba2cccd6SJoe Komlodi bus->regs[R_I2CC_DMA_ADDR] = FIELD_EX32(value, I2CM_DMA_RX_ADDR, ADDR); 648ba2cccd6SJoe Komlodi bus->regs[R_I2CC_DMA_LEN] = ARRAY_FIELD_EX32(bus->regs, I2CM_DMA_LEN, 649ba2cccd6SJoe Komlodi RX_BUF_LEN) + 1; 650ba2cccd6SJoe Komlodi break; 651ba2cccd6SJoe Komlodi case A_I2CM_DMA_LEN: 652b582b7a1SPeter Delevoryas w1t = FIELD_EX32(value, I2CM_DMA_LEN, RX_BUF_LEN_W1T) || 653b582b7a1SPeter Delevoryas FIELD_EX32(value, I2CM_DMA_LEN, TX_BUF_LEN_W1T); 654ba2cccd6SJoe Komlodi /* If none of the w1t bits are set, just write to the reg as normal. */ 655ba2cccd6SJoe Komlodi if (!w1t) { 656ba2cccd6SJoe Komlodi bus->regs[R_I2CM_DMA_LEN] = value; 657ba2cccd6SJoe Komlodi break; 658ba2cccd6SJoe Komlodi } 659b582b7a1SPeter Delevoryas if (FIELD_EX32(value, I2CM_DMA_LEN, RX_BUF_LEN_W1T)) { 660ba2cccd6SJoe Komlodi ARRAY_FIELD_DP32(bus->regs, I2CM_DMA_LEN, RX_BUF_LEN, 661ba2cccd6SJoe Komlodi FIELD_EX32(value, I2CM_DMA_LEN, RX_BUF_LEN)); 662ba2cccd6SJoe Komlodi } 663b582b7a1SPeter Delevoryas if (FIELD_EX32(value, I2CM_DMA_LEN, TX_BUF_LEN_W1T)) { 664ba2cccd6SJoe Komlodi ARRAY_FIELD_DP32(bus->regs, I2CM_DMA_LEN, TX_BUF_LEN, 665ba2cccd6SJoe Komlodi FIELD_EX32(value, I2CM_DMA_LEN, TX_BUF_LEN)); 666ba2cccd6SJoe Komlodi } 667ba2cccd6SJoe Komlodi break; 668ba2cccd6SJoe Komlodi case A_I2CM_DMA_LEN_STS: 669ba2cccd6SJoe Komlodi /* Writes clear to 0 */ 670ba2cccd6SJoe Komlodi bus->regs[R_I2CM_DMA_LEN_STS] = 0; 671ba2cccd6SJoe Komlodi break; 672ba2cccd6SJoe Komlodi case A_I2CC_DMA_ADDR: 673ba2cccd6SJoe Komlodi case A_I2CC_DMA_LEN: 674ba2cccd6SJoe Komlodi /* RO */ 675ba2cccd6SJoe Komlodi break; 676ba2cccd6SJoe Komlodi case A_I2CS_DEV_ADDR: 6771c5d909fSPeter Delevoryas bus->regs[R_I2CS_DEV_ADDR] = value; 6781c5d909fSPeter Delevoryas break; 6791c5d909fSPeter Delevoryas case A_I2CS_DMA_RX_ADDR: 6801c5d909fSPeter Delevoryas bus->regs[R_I2CS_DMA_RX_ADDR] = value; 6811c5d909fSPeter Delevoryas break; 682ba2cccd6SJoe Komlodi case A_I2CS_DMA_LEN: 6831c5d909fSPeter Delevoryas assert(FIELD_EX32(value, I2CS_DMA_LEN, TX_BUF_LEN) == 0); 6841c5d909fSPeter Delevoryas if (FIELD_EX32(value, I2CS_DMA_LEN, RX_BUF_LEN_W1T)) { 6851c5d909fSPeter Delevoryas ARRAY_FIELD_DP32(bus->regs, I2CS_DMA_LEN, RX_BUF_LEN, 6861c5d909fSPeter Delevoryas FIELD_EX32(value, I2CS_DMA_LEN, RX_BUF_LEN)); 6871c5d909fSPeter Delevoryas } else { 6881c5d909fSPeter Delevoryas bus->regs[R_I2CS_DMA_LEN] = value; 6891c5d909fSPeter Delevoryas } 6901c5d909fSPeter Delevoryas break; 6911c5d909fSPeter Delevoryas case A_I2CS_CMD: 6921c5d909fSPeter Delevoryas if (FIELD_EX32(value, I2CS_CMD, W1_CTRL)) { 6931c5d909fSPeter Delevoryas bus->regs[R_I2CS_CMD] |= value; 6941c5d909fSPeter Delevoryas } else { 6951c5d909fSPeter Delevoryas bus->regs[R_I2CS_CMD] = value; 6961c5d909fSPeter Delevoryas } 6971c5d909fSPeter Delevoryas i2c_slave_set_address(bus->slave, bus->regs[R_I2CS_DEV_ADDR]); 6981c5d909fSPeter Delevoryas break; 6991c5d909fSPeter Delevoryas case A_I2CS_INTR_CTRL: 7001c5d909fSPeter Delevoryas bus->regs[R_I2CS_INTR_CTRL] = value; 7011c5d909fSPeter Delevoryas break; 7021c5d909fSPeter Delevoryas 7031c5d909fSPeter Delevoryas case A_I2CS_INTR_STS: 7041c5d909fSPeter Delevoryas if (ARRAY_FIELD_EX32(bus->regs, I2CS_INTR_CTRL, PKT_CMD_DONE)) { 7051c5d909fSPeter Delevoryas if (ARRAY_FIELD_EX32(bus->regs, I2CS_INTR_STS, PKT_CMD_DONE) && 7061c5d909fSPeter Delevoryas FIELD_EX32(value, I2CS_INTR_STS, PKT_CMD_DONE)) { 7071c5d909fSPeter Delevoryas bus->regs[R_I2CS_INTR_STS] &= 0xfffc0000; 7081c5d909fSPeter Delevoryas } 7091c5d909fSPeter Delevoryas } else { 7101c5d909fSPeter Delevoryas bus->regs[R_I2CS_INTR_STS] &= ~value; 7111c5d909fSPeter Delevoryas } 7121c5d909fSPeter Delevoryas if (!bus->regs[R_I2CS_INTR_STS]) { 7131c5d909fSPeter Delevoryas bus->controller->intr_status &= ~(1 << bus->id); 7141c5d909fSPeter Delevoryas qemu_irq_lower(aic->bus_get_irq(bus)); 7151c5d909fSPeter Delevoryas } 7161c5d909fSPeter Delevoryas aspeed_i2c_bus_raise_interrupt(bus); 7171c5d909fSPeter Delevoryas break; 7181c5d909fSPeter Delevoryas case A_I2CS_DMA_LEN_STS: 7191c5d909fSPeter Delevoryas bus->regs[R_I2CS_DMA_LEN_STS] = 0; 7201c5d909fSPeter Delevoryas break; 7211c5d909fSPeter Delevoryas case A_I2CS_DMA_TX_ADDR: 7221c5d909fSPeter Delevoryas qemu_log_mask(LOG_UNIMP, "%s: Slave mode DMA TX is not implemented\n", 723ba2cccd6SJoe Komlodi __func__); 724ba2cccd6SJoe Komlodi break; 725ba2cccd6SJoe Komlodi default: 726ba2cccd6SJoe Komlodi qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad offset 0x%" HWADDR_PRIx "\n", 727ba2cccd6SJoe Komlodi __func__, offset); 728ba2cccd6SJoe Komlodi } 729ba2cccd6SJoe Komlodi } 730ba2cccd6SJoe Komlodi 731ba2cccd6SJoe Komlodi static void aspeed_i2c_bus_old_write(AspeedI2CBus *bus, hwaddr offset, 732ba2cccd6SJoe Komlodi uint64_t value, unsigned size) 733ba2cccd6SJoe Komlodi { 73451dd4923SCédric Le Goater AspeedI2CClass *aic = ASPEED_I2C_GET_CLASS(bus->controller); 735bb626e5bSGuenter Roeck bool handle_rx; 73616020011SCédric Le Goater 73766cc84a1SCédric Le Goater trace_aspeed_i2c_bus_write(bus->id, offset, size, value); 73866cc84a1SCédric Le Goater 73916020011SCédric Le Goater switch (offset) { 7403be3d6ccSJoe Komlodi case A_I2CD_FUN_CTRL: 741ba2cccd6SJoe Komlodi if (SHARED_FIELD_EX32(value, SLAVE_EN)) { 742a8d48f59SKlaus Jensen i2c_slave_set_address(bus->slave, bus->regs[R_I2CD_DEV_ADDR]); 74316020011SCédric Le Goater } 7442260fc6fSJoe Komlodi bus->regs[R_I2CD_FUN_CTRL] = value & 0x0071C3FF; 74516020011SCédric Le Goater break; 7463be3d6ccSJoe Komlodi case A_I2CD_AC_TIMING1: 7472260fc6fSJoe Komlodi bus->regs[R_I2CD_AC_TIMING1] = value & 0xFFFFF0F; 74816020011SCédric Le Goater break; 7493be3d6ccSJoe Komlodi case A_I2CD_AC_TIMING2: 7502260fc6fSJoe Komlodi bus->regs[R_I2CD_AC_TIMING2] = value & 0x7; 75116020011SCédric Le Goater break; 7523be3d6ccSJoe Komlodi case A_I2CD_INTR_CTRL: 7532260fc6fSJoe Komlodi bus->regs[R_I2CD_INTR_CTRL] = value & 0x7FFF; 75416020011SCédric Le Goater break; 7553be3d6ccSJoe Komlodi case A_I2CD_INTR_STS: 756ba2cccd6SJoe Komlodi handle_rx = SHARED_ARRAY_FIELD_EX32(bus->regs, R_I2CD_INTR_STS, RX_DONE) 757ba2cccd6SJoe Komlodi && SHARED_FIELD_EX32(value, RX_DONE); 7582260fc6fSJoe Komlodi bus->regs[R_I2CD_INTR_STS] &= ~(value & 0x7FFF); 7592260fc6fSJoe Komlodi if (!bus->regs[R_I2CD_INTR_STS]) { 76016020011SCédric Le Goater bus->controller->intr_status &= ~(1 << bus->id); 76151dd4923SCédric Le Goater qemu_irq_lower(aic->bus_get_irq(bus)); 7625540cb97SCédric Le Goater } 763a8d48f59SKlaus Jensen if (handle_rx) { 764a8d48f59SKlaus Jensen if (SHARED_ARRAY_FIELD_EX32(bus->regs, R_I2CD_CMD, M_RX_CMD) || 765ba2cccd6SJoe Komlodi SHARED_ARRAY_FIELD_EX32(bus->regs, R_I2CD_CMD, 766a8d48f59SKlaus Jensen M_S_RX_CMD_LAST)) { 767bb626e5bSGuenter Roeck aspeed_i2c_handle_rx_cmd(bus); 768bb626e5bSGuenter Roeck aspeed_i2c_bus_raise_interrupt(bus); 769a8d48f59SKlaus Jensen } else if (aspeed_i2c_get_state(bus) == I2CD_STXD) { 770a8d48f59SKlaus Jensen i2c_ack(bus->bus); 771a8d48f59SKlaus Jensen } 772bb626e5bSGuenter Roeck } 77316020011SCédric Le Goater break; 7743be3d6ccSJoe Komlodi case A_I2CD_DEV_ADDR: 775d72a712cSKlaus Jensen bus->regs[R_I2CD_DEV_ADDR] = value; 77616020011SCédric Le Goater break; 7773be3d6ccSJoe Komlodi case A_I2CD_POOL_CTRL: 7782260fc6fSJoe Komlodi bus->regs[R_I2CD_POOL_CTRL] &= ~0xffffff; 7792260fc6fSJoe Komlodi bus->regs[R_I2CD_POOL_CTRL] |= (value & 0xffffff); 7806054fc73SCédric Le Goater break; 7816054fc73SCédric Le Goater 7823be3d6ccSJoe Komlodi case A_I2CD_BYTE_BUF: 783ba2cccd6SJoe Komlodi SHARED_ARRAY_FIELD_DP32(bus->regs, R_I2CD_BYTE_BUF, TX_BUF, value); 78416020011SCédric Le Goater break; 7853be3d6ccSJoe Komlodi case A_I2CD_CMD: 78616020011SCédric Le Goater if (!aspeed_i2c_bus_is_enabled(bus)) { 78716020011SCédric Le Goater break; 78816020011SCédric Le Goater } 78916020011SCédric Le Goater 79016020011SCédric Le Goater if (!aspeed_i2c_bus_is_master(bus)) { 7910c0f1beeSPeter Delevoryas qemu_log_mask(LOG_GUEST_ERROR, "%s: Master mode is not enabled\n", 79216020011SCédric Le Goater __func__); 79316020011SCédric Le Goater break; 79416020011SCédric Le Goater } 79516020011SCédric Le Goater 796545d6befSCédric Le Goater if (!aic->has_dma && 797ba2cccd6SJoe Komlodi (SHARED_FIELD_EX32(value, RX_DMA_EN) || 798ba2cccd6SJoe Komlodi SHARED_FIELD_EX32(value, TX_DMA_EN))) { 799545d6befSCédric Le Goater qemu_log_mask(LOG_GUEST_ERROR, "%s: No DMA support\n", __func__); 800545d6befSCédric Le Goater break; 801545d6befSCédric Le Goater } 802545d6befSCédric Le Goater 803ba2cccd6SJoe Komlodi bus->regs[R_I2CD_CMD] &= ~0xFFFF; 804ba2cccd6SJoe Komlodi bus->regs[R_I2CD_CMD] |= value & 0xFFFF; 805ba2cccd6SJoe Komlodi 80616020011SCédric Le Goater aspeed_i2c_bus_handle_cmd(bus, value); 807ddabca75SCédric Le Goater aspeed_i2c_bus_raise_interrupt(bus); 80816020011SCédric Le Goater break; 8093be3d6ccSJoe Komlodi case A_I2CD_DMA_ADDR: 810545d6befSCédric Le Goater if (!aic->has_dma) { 811545d6befSCédric Le Goater qemu_log_mask(LOG_GUEST_ERROR, "%s: No DMA support\n", __func__); 812545d6befSCédric Le Goater break; 813545d6befSCédric Le Goater } 814545d6befSCédric Le Goater 8152260fc6fSJoe Komlodi bus->regs[R_I2CD_DMA_ADDR] = value & 0x3ffffffc; 816545d6befSCédric Le Goater break; 817545d6befSCédric Le Goater 8183be3d6ccSJoe Komlodi case A_I2CD_DMA_LEN: 819545d6befSCédric Le Goater if (!aic->has_dma) { 820545d6befSCédric Le Goater qemu_log_mask(LOG_GUEST_ERROR, "%s: No DMA support\n", __func__); 821545d6befSCédric Le Goater break; 822545d6befSCédric Le Goater } 823545d6befSCédric Le Goater 8242260fc6fSJoe Komlodi bus->regs[R_I2CD_DMA_LEN] = value & 0xfff; 8252260fc6fSJoe Komlodi if (!bus->regs[R_I2CD_DMA_LEN]) { 826545d6befSCédric Le Goater qemu_log_mask(LOG_UNIMP, "%s: invalid DMA length\n", __func__); 827545d6befSCédric Le Goater } 828545d6befSCédric Le Goater break; 82916020011SCédric Le Goater 83016020011SCédric Le Goater default: 83116020011SCédric Le Goater qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad offset 0x%" HWADDR_PRIx "\n", 83216020011SCédric Le Goater __func__, offset); 83316020011SCédric Le Goater } 83416020011SCédric Le Goater } 83516020011SCédric Le Goater 836ba2cccd6SJoe Komlodi static void aspeed_i2c_bus_write(void *opaque, hwaddr offset, 837ba2cccd6SJoe Komlodi uint64_t value, unsigned size) 838ba2cccd6SJoe Komlodi { 839ba2cccd6SJoe Komlodi AspeedI2CBus *bus = opaque; 840ba2cccd6SJoe Komlodi if (aspeed_i2c_is_new_mode(bus->controller)) { 841ba2cccd6SJoe Komlodi aspeed_i2c_bus_new_write(bus, offset, value, size); 842ba2cccd6SJoe Komlodi } else { 843ba2cccd6SJoe Komlodi aspeed_i2c_bus_old_write(bus, offset, value, size); 844ba2cccd6SJoe Komlodi } 845ba2cccd6SJoe Komlodi } 846ba2cccd6SJoe Komlodi 84716020011SCédric Le Goater static uint64_t aspeed_i2c_ctrl_read(void *opaque, hwaddr offset, 84816020011SCédric Le Goater unsigned size) 84916020011SCédric Le Goater { 85016020011SCédric Le Goater AspeedI2CState *s = opaque; 85116020011SCédric Le Goater 85216020011SCédric Le Goater switch (offset) { 8533be3d6ccSJoe Komlodi case A_I2C_CTRL_STATUS: 85416020011SCédric Le Goater return s->intr_status; 8553be3d6ccSJoe Komlodi case A_I2C_CTRL_GLOBAL: 856aab90b1cSCédric Le Goater return s->ctrl_global; 857ba2cccd6SJoe Komlodi case A_I2C_CTRL_NEW_CLK_DIVIDER: 858ba2cccd6SJoe Komlodi if (aspeed_i2c_is_new_mode(s)) { 859ba2cccd6SJoe Komlodi return s->new_clk_divider; 860ba2cccd6SJoe Komlodi } 861ba2cccd6SJoe Komlodi qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad offset 0x%" HWADDR_PRIx "\n", 862ba2cccd6SJoe Komlodi __func__, offset); 863ba2cccd6SJoe Komlodi break; 86416020011SCédric Le Goater default: 86516020011SCédric Le Goater qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad offset 0x%" HWADDR_PRIx "\n", 86616020011SCédric Le Goater __func__, offset); 86716020011SCédric Le Goater break; 86816020011SCédric Le Goater } 86916020011SCédric Le Goater 87016020011SCédric Le Goater return -1; 87116020011SCédric Le Goater } 87216020011SCédric Le Goater 87316020011SCédric Le Goater static void aspeed_i2c_ctrl_write(void *opaque, hwaddr offset, 87416020011SCédric Le Goater uint64_t value, unsigned size) 87516020011SCédric Le Goater { 876aab90b1cSCédric Le Goater AspeedI2CState *s = opaque; 877aab90b1cSCédric Le Goater 87816020011SCédric Le Goater switch (offset) { 8793be3d6ccSJoe Komlodi case A_I2C_CTRL_GLOBAL: 880aab90b1cSCédric Le Goater s->ctrl_global = value; 881aab90b1cSCédric Le Goater break; 882ba2cccd6SJoe Komlodi case A_I2C_CTRL_NEW_CLK_DIVIDER: 883ba2cccd6SJoe Komlodi if (aspeed_i2c_is_new_mode(s)) { 884ba2cccd6SJoe Komlodi s->new_clk_divider = value; 885ba2cccd6SJoe Komlodi } else { 886ba2cccd6SJoe Komlodi qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad offset 0x%" HWADDR_PRIx 887ba2cccd6SJoe Komlodi "\n", __func__, offset); 888ba2cccd6SJoe Komlodi } 889ba2cccd6SJoe Komlodi break; 8903be3d6ccSJoe Komlodi case A_I2C_CTRL_STATUS: 89116020011SCédric Le Goater default: 89216020011SCédric Le Goater qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad offset 0x%" HWADDR_PRIx "\n", 89316020011SCédric Le Goater __func__, offset); 89416020011SCédric Le Goater break; 89516020011SCédric Le Goater } 89616020011SCédric Le Goater } 89716020011SCédric Le Goater 89816020011SCédric Le Goater static const MemoryRegionOps aspeed_i2c_bus_ops = { 89916020011SCédric Le Goater .read = aspeed_i2c_bus_read, 90016020011SCédric Le Goater .write = aspeed_i2c_bus_write, 90116020011SCédric Le Goater .endianness = DEVICE_LITTLE_ENDIAN, 90216020011SCédric Le Goater }; 90316020011SCédric Le Goater 90416020011SCédric Le Goater static const MemoryRegionOps aspeed_i2c_ctrl_ops = { 90516020011SCédric Le Goater .read = aspeed_i2c_ctrl_read, 90616020011SCédric Le Goater .write = aspeed_i2c_ctrl_write, 90716020011SCédric Le Goater .endianness = DEVICE_LITTLE_ENDIAN, 90816020011SCédric Le Goater }; 90916020011SCédric Le Goater 9106054fc73SCédric Le Goater static uint64_t aspeed_i2c_pool_read(void *opaque, hwaddr offset, 9116054fc73SCédric Le Goater unsigned size) 9126054fc73SCédric Le Goater { 9136054fc73SCédric Le Goater AspeedI2CState *s = opaque; 9146054fc73SCédric Le Goater uint64_t ret = 0; 9156054fc73SCédric Le Goater int i; 9166054fc73SCédric Le Goater 9176054fc73SCédric Le Goater for (i = 0; i < size; i++) { 9186054fc73SCédric Le Goater ret |= (uint64_t) s->pool[offset + i] << (8 * i); 9196054fc73SCédric Le Goater } 9206054fc73SCédric Le Goater 9216054fc73SCédric Le Goater return ret; 9226054fc73SCédric Le Goater } 9236054fc73SCédric Le Goater 9246054fc73SCédric Le Goater static void aspeed_i2c_pool_write(void *opaque, hwaddr offset, 9256054fc73SCédric Le Goater uint64_t value, unsigned size) 9266054fc73SCédric Le Goater { 9276054fc73SCédric Le Goater AspeedI2CState *s = opaque; 9286054fc73SCédric Le Goater int i; 9296054fc73SCédric Le Goater 9306054fc73SCédric Le Goater for (i = 0; i < size; i++) { 9316054fc73SCédric Le Goater s->pool[offset + i] = (value >> (8 * i)) & 0xFF; 9326054fc73SCédric Le Goater } 9336054fc73SCédric Le Goater } 9346054fc73SCédric Le Goater 9356054fc73SCédric Le Goater static const MemoryRegionOps aspeed_i2c_pool_ops = { 9366054fc73SCédric Le Goater .read = aspeed_i2c_pool_read, 9376054fc73SCédric Le Goater .write = aspeed_i2c_pool_write, 9386054fc73SCédric Le Goater .endianness = DEVICE_LITTLE_ENDIAN, 9396054fc73SCédric Le Goater .valid = { 9406054fc73SCédric Le Goater .min_access_size = 1, 9416054fc73SCédric Le Goater .max_access_size = 4, 9426054fc73SCédric Le Goater }, 9436054fc73SCédric Le Goater }; 9446054fc73SCédric Le Goater 94516020011SCédric Le Goater static const VMStateDescription aspeed_i2c_bus_vmstate = { 94616020011SCédric Le Goater .name = TYPE_ASPEED_I2C, 947ba2cccd6SJoe Komlodi .version_id = 5, 948ba2cccd6SJoe Komlodi .minimum_version_id = 5, 94916020011SCédric Le Goater .fields = (VMStateField[]) { 950ba2cccd6SJoe Komlodi VMSTATE_UINT32_ARRAY(regs, AspeedI2CBus, ASPEED_I2C_NEW_NUM_REG), 95116020011SCédric Le Goater VMSTATE_END_OF_LIST() 95216020011SCédric Le Goater } 95316020011SCédric Le Goater }; 95416020011SCédric Le Goater 95516020011SCédric Le Goater static const VMStateDescription aspeed_i2c_vmstate = { 95616020011SCédric Le Goater .name = TYPE_ASPEED_I2C, 9576054fc73SCédric Le Goater .version_id = 2, 9586054fc73SCédric Le Goater .minimum_version_id = 2, 95916020011SCédric Le Goater .fields = (VMStateField[]) { 96016020011SCédric Le Goater VMSTATE_UINT32(intr_status, AspeedI2CState), 96116020011SCédric Le Goater VMSTATE_STRUCT_ARRAY(busses, AspeedI2CState, 96216020011SCédric Le Goater ASPEED_I2C_NR_BUSSES, 1, aspeed_i2c_bus_vmstate, 96316020011SCédric Le Goater AspeedI2CBus), 9646054fc73SCédric Le Goater VMSTATE_UINT8_ARRAY(pool, AspeedI2CState, ASPEED_I2C_MAX_POOL_SIZE), 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 void aspeed_i2c_reset(DeviceState *dev) 97016020011SCédric Le Goater { 97116020011SCédric Le Goater AspeedI2CState *s = ASPEED_I2C(dev); 97216020011SCédric Le Goater 97316020011SCédric Le Goater s->intr_status = 0; 97460261038SCédric Le Goater } 97560261038SCédric Le Goater 97660261038SCédric Le Goater static void aspeed_i2c_instance_init(Object *obj) 97760261038SCédric Le Goater { 97860261038SCédric Le Goater AspeedI2CState *s = ASPEED_I2C(obj); 97960261038SCédric Le Goater AspeedI2CClass *aic = ASPEED_I2C_GET_CLASS(s); 98060261038SCédric Le Goater int i; 98116020011SCédric Le Goater 982f7da1aa8SCédric Le Goater for (i = 0; i < aic->num_busses; i++) { 98360261038SCédric Le Goater object_initialize_child(obj, "bus[*]", &s->busses[i], 98460261038SCédric Le Goater TYPE_ASPEED_I2C_BUS); 98516020011SCédric Le Goater } 98616020011SCédric Le Goater } 98716020011SCédric Le Goater 98816020011SCédric Le Goater /* 989f7da1aa8SCédric Le Goater * Address Definitions (AST2400 and AST2500) 99016020011SCédric Le Goater * 99116020011SCédric Le Goater * 0x000 ... 0x03F: Global Register 99216020011SCédric Le Goater * 0x040 ... 0x07F: Device 1 99316020011SCédric Le Goater * 0x080 ... 0x0BF: Device 2 99416020011SCédric Le Goater * 0x0C0 ... 0x0FF: Device 3 99516020011SCédric Le Goater * 0x100 ... 0x13F: Device 4 99616020011SCédric Le Goater * 0x140 ... 0x17F: Device 5 99716020011SCédric Le Goater * 0x180 ... 0x1BF: Device 6 99816020011SCédric Le Goater * 0x1C0 ... 0x1FF: Device 7 99916020011SCédric Le Goater * 0x200 ... 0x2FF: Buffer Pool (unused in linux driver) 100016020011SCédric Le Goater * 0x300 ... 0x33F: Device 8 100116020011SCédric Le Goater * 0x340 ... 0x37F: Device 9 100216020011SCédric Le Goater * 0x380 ... 0x3BF: Device 10 100316020011SCédric Le Goater * 0x3C0 ... 0x3FF: Device 11 100416020011SCédric Le Goater * 0x400 ... 0x43F: Device 12 100516020011SCédric Le Goater * 0x440 ... 0x47F: Device 13 100616020011SCédric Le Goater * 0x480 ... 0x4BF: Device 14 100716020011SCédric Le Goater * 0x800 ... 0xFFF: Buffer Pool (unused in linux driver) 100816020011SCédric Le Goater */ 100916020011SCédric Le Goater static void aspeed_i2c_realize(DeviceState *dev, Error **errp) 101016020011SCédric Le Goater { 101116020011SCédric Le Goater int i; 101216020011SCédric Le Goater SysBusDevice *sbd = SYS_BUS_DEVICE(dev); 101316020011SCédric Le Goater AspeedI2CState *s = ASPEED_I2C(dev); 1014f7da1aa8SCédric Le Goater AspeedI2CClass *aic = ASPEED_I2C_GET_CLASS(s); 101516020011SCédric Le Goater 101616020011SCédric Le Goater sysbus_init_irq(sbd, &s->irq); 101716020011SCédric Le Goater memory_region_init_io(&s->iomem, OBJECT(s), &aspeed_i2c_ctrl_ops, s, 101816020011SCédric Le Goater "aspeed.i2c", 0x1000); 101916020011SCédric Le Goater sysbus_init_mmio(sbd, &s->iomem); 102016020011SCédric Le Goater 1021f7da1aa8SCédric Le Goater for (i = 0; i < aic->num_busses; i++) { 102260261038SCédric Le Goater Object *bus = OBJECT(&s->busses[i]); 1023f7da1aa8SCédric Le Goater int offset = i < aic->gap ? 1 : 5; 102451dd4923SCédric Le Goater 102560261038SCédric Le Goater if (!object_property_set_link(bus, "controller", OBJECT(s), errp)) { 102660261038SCédric Le Goater return; 102760261038SCédric Le Goater } 102860261038SCédric Le Goater 102960261038SCédric Le Goater if (!object_property_set_uint(bus, "bus-id", i, errp)) { 103060261038SCédric Le Goater return; 103160261038SCédric Le Goater } 103260261038SCédric Le Goater 103360261038SCédric Le Goater if (!sysbus_realize(SYS_BUS_DEVICE(bus), errp)) { 103460261038SCédric Le Goater return; 103560261038SCédric Le Goater } 103660261038SCédric Le Goater 1037f7da1aa8SCédric Le Goater memory_region_add_subregion(&s->iomem, aic->reg_size * (i + offset), 103816020011SCédric Le Goater &s->busses[i].mr); 103916020011SCédric Le Goater } 10406054fc73SCédric Le Goater 10416054fc73SCédric Le Goater memory_region_init_io(&s->pool_iomem, OBJECT(s), &aspeed_i2c_pool_ops, s, 10426054fc73SCédric Le Goater "aspeed.i2c-pool", aic->pool_size); 10436054fc73SCédric Le Goater memory_region_add_subregion(&s->iomem, aic->pool_base, &s->pool_iomem); 1044545d6befSCédric Le Goater 1045545d6befSCédric Le Goater if (aic->has_dma) { 1046545d6befSCédric Le Goater if (!s->dram_mr) { 1047545d6befSCédric Le Goater error_setg(errp, TYPE_ASPEED_I2C ": 'dram' link not set"); 1048545d6befSCédric Le Goater return; 104916020011SCédric Le Goater } 105016020011SCédric Le Goater 10513f7a53b2SCédric Le Goater address_space_init(&s->dram_as, s->dram_mr, 10523f7a53b2SCédric Le Goater TYPE_ASPEED_I2C "-dma-dram"); 1053545d6befSCédric Le Goater } 1054545d6befSCédric Le Goater } 1055545d6befSCédric Le Goater 1056545d6befSCédric Le Goater static Property aspeed_i2c_properties[] = { 1057545d6befSCédric Le Goater DEFINE_PROP_LINK("dram", AspeedI2CState, dram_mr, 1058545d6befSCédric Le Goater TYPE_MEMORY_REGION, MemoryRegion *), 1059545d6befSCédric Le Goater DEFINE_PROP_END_OF_LIST(), 1060545d6befSCédric Le Goater }; 1061545d6befSCédric Le Goater 106216020011SCédric Le Goater static void aspeed_i2c_class_init(ObjectClass *klass, void *data) 106316020011SCédric Le Goater { 106416020011SCédric Le Goater DeviceClass *dc = DEVICE_CLASS(klass); 106516020011SCédric Le Goater 106616020011SCédric Le Goater dc->vmsd = &aspeed_i2c_vmstate; 106716020011SCédric Le Goater dc->reset = aspeed_i2c_reset; 10684f67d30bSMarc-André Lureau device_class_set_props(dc, aspeed_i2c_properties); 106916020011SCédric Le Goater dc->realize = aspeed_i2c_realize; 107016020011SCédric Le Goater dc->desc = "Aspeed I2C Controller"; 107116020011SCédric Le Goater } 107216020011SCédric Le Goater 107316020011SCédric Le Goater static const TypeInfo aspeed_i2c_info = { 107416020011SCédric Le Goater .name = TYPE_ASPEED_I2C, 107516020011SCédric Le Goater .parent = TYPE_SYS_BUS_DEVICE, 107660261038SCédric Le Goater .instance_init = aspeed_i2c_instance_init, 107716020011SCédric Le Goater .instance_size = sizeof(AspeedI2CState), 107816020011SCédric Le Goater .class_init = aspeed_i2c_class_init, 1079f7da1aa8SCédric Le Goater .class_size = sizeof(AspeedI2CClass), 1080f7da1aa8SCédric Le Goater .abstract = true, 1081f7da1aa8SCédric Le Goater }; 1082f7da1aa8SCédric Le Goater 10831c5d909fSPeter Delevoryas static int aspeed_i2c_bus_new_slave_event(AspeedI2CBus *bus, 10841c5d909fSPeter Delevoryas enum i2c_event event) 10851c5d909fSPeter Delevoryas { 10861c5d909fSPeter Delevoryas switch (event) { 10871c5d909fSPeter Delevoryas case I2C_START_SEND_ASYNC: 10881c5d909fSPeter Delevoryas if (!SHARED_ARRAY_FIELD_EX32(bus->regs, R_I2CS_CMD, RX_DMA_EN)) { 10891c5d909fSPeter Delevoryas qemu_log_mask(LOG_GUEST_ERROR, 10901c5d909fSPeter Delevoryas "%s: Slave mode RX DMA is not enabled\n", __func__); 10911c5d909fSPeter Delevoryas return -1; 10921c5d909fSPeter Delevoryas } 10931c5d909fSPeter Delevoryas ARRAY_FIELD_DP32(bus->regs, I2CS_DMA_LEN_STS, RX_LEN, 0); 10941c5d909fSPeter Delevoryas bus->regs[R_I2CC_DMA_ADDR] = 10951c5d909fSPeter Delevoryas ARRAY_FIELD_EX32(bus->regs, I2CS_DMA_RX_ADDR, ADDR); 10961c5d909fSPeter Delevoryas bus->regs[R_I2CC_DMA_LEN] = 10971c5d909fSPeter Delevoryas ARRAY_FIELD_EX32(bus->regs, I2CS_DMA_LEN, RX_BUF_LEN) + 1; 10981c5d909fSPeter Delevoryas i2c_ack(bus->bus); 10991c5d909fSPeter Delevoryas break; 11001c5d909fSPeter Delevoryas case I2C_FINISH: 11011c5d909fSPeter Delevoryas ARRAY_FIELD_DP32(bus->regs, I2CS_INTR_STS, PKT_CMD_DONE, 1); 11021c5d909fSPeter Delevoryas ARRAY_FIELD_DP32(bus->regs, I2CS_INTR_STS, SLAVE_ADDR_RX_MATCH, 1); 11031c5d909fSPeter Delevoryas SHARED_ARRAY_FIELD_DP32(bus->regs, R_I2CS_INTR_STS, NORMAL_STOP, 1); 11041c5d909fSPeter Delevoryas SHARED_ARRAY_FIELD_DP32(bus->regs, R_I2CS_INTR_STS, RX_DONE, 1); 11051c5d909fSPeter Delevoryas aspeed_i2c_bus_raise_slave_interrupt(bus); 11061c5d909fSPeter Delevoryas break; 11071c5d909fSPeter Delevoryas default: 11081c5d909fSPeter Delevoryas qemu_log_mask(LOG_UNIMP, "%s: i2c event %d unimplemented\n", 11091c5d909fSPeter Delevoryas __func__, event); 11101c5d909fSPeter Delevoryas return -1; 11111c5d909fSPeter Delevoryas } 11121c5d909fSPeter Delevoryas 11131c5d909fSPeter Delevoryas return 0; 11141c5d909fSPeter Delevoryas } 11151c5d909fSPeter Delevoryas 1116a8d48f59SKlaus Jensen static int aspeed_i2c_bus_slave_event(I2CSlave *slave, enum i2c_event event) 1117a8d48f59SKlaus Jensen { 1118a8d48f59SKlaus Jensen BusState *qbus = qdev_get_parent_bus(DEVICE(slave)); 1119a8d48f59SKlaus Jensen AspeedI2CBus *bus = ASPEED_I2C_BUS(qbus->parent); 1120a8d48f59SKlaus Jensen uint32_t reg_intr_sts = aspeed_i2c_bus_intr_sts_offset(bus); 1121a8d48f59SKlaus Jensen uint32_t reg_byte_buf = aspeed_i2c_bus_byte_buf_offset(bus); 11223648d31fSPeter Delevoryas uint32_t reg_dev_addr = aspeed_i2c_bus_dev_addr_offset(bus); 11233648d31fSPeter Delevoryas uint32_t dev_addr = SHARED_ARRAY_FIELD_EX32(bus->regs, reg_dev_addr, 11243648d31fSPeter Delevoryas SLAVE_DEV_ADDR1); 1125a8d48f59SKlaus Jensen 11261c5d909fSPeter Delevoryas if (aspeed_i2c_is_new_mode(bus->controller)) { 11271c5d909fSPeter Delevoryas return aspeed_i2c_bus_new_slave_event(bus, event); 11281c5d909fSPeter Delevoryas } 11291c5d909fSPeter Delevoryas 1130a8d48f59SKlaus Jensen switch (event) { 1131a8d48f59SKlaus Jensen case I2C_START_SEND_ASYNC: 11323648d31fSPeter Delevoryas /* Bit[0] == 0 indicates "send". */ 11333648d31fSPeter Delevoryas SHARED_ARRAY_FIELD_DP32(bus->regs, reg_byte_buf, RX_BUF, dev_addr << 1); 1134a8d48f59SKlaus Jensen 1135a8d48f59SKlaus Jensen ARRAY_FIELD_DP32(bus->regs, I2CD_INTR_STS, SLAVE_ADDR_RX_MATCH, 1); 1136a8d48f59SKlaus Jensen SHARED_ARRAY_FIELD_DP32(bus->regs, reg_intr_sts, RX_DONE, 1); 1137a8d48f59SKlaus Jensen 1138a8d48f59SKlaus Jensen aspeed_i2c_set_state(bus, I2CD_STXD); 1139a8d48f59SKlaus Jensen 1140a8d48f59SKlaus Jensen break; 1141a8d48f59SKlaus Jensen 1142a8d48f59SKlaus Jensen case I2C_FINISH: 1143a8d48f59SKlaus Jensen SHARED_ARRAY_FIELD_DP32(bus->regs, reg_intr_sts, NORMAL_STOP, 1); 1144a8d48f59SKlaus Jensen 1145a8d48f59SKlaus Jensen aspeed_i2c_set_state(bus, I2CD_IDLE); 1146a8d48f59SKlaus Jensen 1147a8d48f59SKlaus Jensen break; 1148a8d48f59SKlaus Jensen 1149a8d48f59SKlaus Jensen default: 1150a8d48f59SKlaus Jensen return -1; 1151a8d48f59SKlaus Jensen } 1152a8d48f59SKlaus Jensen 1153a8d48f59SKlaus Jensen aspeed_i2c_bus_raise_interrupt(bus); 1154a8d48f59SKlaus Jensen 1155a8d48f59SKlaus Jensen return 0; 1156a8d48f59SKlaus Jensen } 1157a8d48f59SKlaus Jensen 11581c5d909fSPeter Delevoryas static void aspeed_i2c_bus_new_slave_send_async(AspeedI2CBus *bus, uint8_t data) 11591c5d909fSPeter Delevoryas { 11601c5d909fSPeter Delevoryas assert(address_space_write(&bus->controller->dram_as, 11611c5d909fSPeter Delevoryas bus->regs[R_I2CC_DMA_ADDR], 11621c5d909fSPeter Delevoryas MEMTXATTRS_UNSPECIFIED, &data, 1) == MEMTX_OK); 11631c5d909fSPeter Delevoryas 11641c5d909fSPeter Delevoryas bus->regs[R_I2CC_DMA_ADDR]++; 11651c5d909fSPeter Delevoryas bus->regs[R_I2CC_DMA_LEN]--; 11661c5d909fSPeter Delevoryas ARRAY_FIELD_DP32(bus->regs, I2CS_DMA_LEN_STS, RX_LEN, 11671c5d909fSPeter Delevoryas ARRAY_FIELD_EX32(bus->regs, I2CS_DMA_LEN_STS, RX_LEN) + 1); 11681c5d909fSPeter Delevoryas i2c_ack(bus->bus); 11691c5d909fSPeter Delevoryas } 11701c5d909fSPeter Delevoryas 1171a8d48f59SKlaus Jensen static void aspeed_i2c_bus_slave_send_async(I2CSlave *slave, uint8_t data) 1172a8d48f59SKlaus Jensen { 1173a8d48f59SKlaus Jensen BusState *qbus = qdev_get_parent_bus(DEVICE(slave)); 1174a8d48f59SKlaus Jensen AspeedI2CBus *bus = ASPEED_I2C_BUS(qbus->parent); 1175a8d48f59SKlaus Jensen uint32_t reg_intr_sts = aspeed_i2c_bus_intr_sts_offset(bus); 1176a8d48f59SKlaus Jensen uint32_t reg_byte_buf = aspeed_i2c_bus_byte_buf_offset(bus); 1177a8d48f59SKlaus Jensen 11781c5d909fSPeter Delevoryas if (aspeed_i2c_is_new_mode(bus->controller)) { 11791c5d909fSPeter Delevoryas return aspeed_i2c_bus_new_slave_send_async(bus, data); 11801c5d909fSPeter Delevoryas } 11811c5d909fSPeter Delevoryas 1182a8d48f59SKlaus Jensen SHARED_ARRAY_FIELD_DP32(bus->regs, reg_byte_buf, RX_BUF, data); 1183a8d48f59SKlaus Jensen SHARED_ARRAY_FIELD_DP32(bus->regs, reg_intr_sts, RX_DONE, 1); 1184a8d48f59SKlaus Jensen 1185a8d48f59SKlaus Jensen aspeed_i2c_bus_raise_interrupt(bus); 1186a8d48f59SKlaus Jensen } 1187a8d48f59SKlaus Jensen 1188a8d48f59SKlaus Jensen static void aspeed_i2c_bus_slave_class_init(ObjectClass *klass, void *data) 1189a8d48f59SKlaus Jensen { 1190a8d48f59SKlaus Jensen DeviceClass *dc = DEVICE_CLASS(klass); 1191a8d48f59SKlaus Jensen I2CSlaveClass *sc = I2C_SLAVE_CLASS(klass); 1192a8d48f59SKlaus Jensen 1193a8d48f59SKlaus Jensen dc->desc = "Aspeed I2C Bus Slave"; 1194a8d48f59SKlaus Jensen 1195a8d48f59SKlaus Jensen sc->event = aspeed_i2c_bus_slave_event; 1196a8d48f59SKlaus Jensen sc->send_async = aspeed_i2c_bus_slave_send_async; 1197a8d48f59SKlaus Jensen } 1198a8d48f59SKlaus Jensen 1199a8d48f59SKlaus Jensen static const TypeInfo aspeed_i2c_bus_slave_info = { 1200a8d48f59SKlaus Jensen .name = TYPE_ASPEED_I2C_BUS_SLAVE, 1201a8d48f59SKlaus Jensen .parent = TYPE_I2C_SLAVE, 1202a8d48f59SKlaus Jensen .instance_size = sizeof(AspeedI2CBusSlave), 1203a8d48f59SKlaus Jensen .class_init = aspeed_i2c_bus_slave_class_init, 1204a8d48f59SKlaus Jensen }; 1205a8d48f59SKlaus Jensen 120660261038SCédric Le Goater static void aspeed_i2c_bus_reset(DeviceState *dev) 120760261038SCédric Le Goater { 120860261038SCédric Le Goater AspeedI2CBus *s = ASPEED_I2C_BUS(dev); 120960261038SCédric Le Goater 12102260fc6fSJoe Komlodi memset(s->regs, 0, sizeof(s->regs)); 121160261038SCédric Le Goater i2c_end_transfer(s->bus); 121260261038SCédric Le Goater } 121360261038SCédric Le Goater 121460261038SCédric Le Goater static void aspeed_i2c_bus_realize(DeviceState *dev, Error **errp) 121560261038SCédric Le Goater { 121660261038SCédric Le Goater AspeedI2CBus *s = ASPEED_I2C_BUS(dev); 121760261038SCédric Le Goater AspeedI2CClass *aic; 121860261038SCédric Le Goater g_autofree char *name = g_strdup_printf(TYPE_ASPEED_I2C_BUS ".%d", s->id); 121960261038SCédric Le Goater 122060261038SCédric Le Goater if (!s->controller) { 122160261038SCédric Le Goater error_setg(errp, TYPE_ASPEED_I2C_BUS ": 'controller' link not set"); 122260261038SCédric Le Goater return; 122360261038SCédric Le Goater } 122460261038SCédric Le Goater 122560261038SCédric Le Goater aic = ASPEED_I2C_GET_CLASS(s->controller); 122660261038SCédric Le Goater 122760261038SCédric Le Goater sysbus_init_irq(SYS_BUS_DEVICE(dev), &s->irq); 122860261038SCédric Le Goater 122960261038SCédric Le Goater s->bus = i2c_init_bus(dev, name); 1230a8d48f59SKlaus Jensen s->slave = i2c_slave_create_simple(s->bus, TYPE_ASPEED_I2C_BUS_SLAVE, 1231a8d48f59SKlaus Jensen 0xff); 123260261038SCédric Le Goater 123360261038SCédric Le Goater memory_region_init_io(&s->mr, OBJECT(s), &aspeed_i2c_bus_ops, 123460261038SCédric Le Goater s, name, aic->reg_size); 123560261038SCédric Le Goater sysbus_init_mmio(SYS_BUS_DEVICE(dev), &s->mr); 123660261038SCédric Le Goater } 123760261038SCédric Le Goater 123860261038SCédric Le Goater static Property aspeed_i2c_bus_properties[] = { 123960261038SCédric Le Goater DEFINE_PROP_UINT8("bus-id", AspeedI2CBus, id, 0), 124060261038SCédric Le Goater DEFINE_PROP_LINK("controller", AspeedI2CBus, controller, TYPE_ASPEED_I2C, 124160261038SCédric Le Goater AspeedI2CState *), 124260261038SCédric Le Goater DEFINE_PROP_END_OF_LIST(), 124360261038SCédric Le Goater }; 124460261038SCédric Le Goater 124560261038SCédric Le Goater static void aspeed_i2c_bus_class_init(ObjectClass *klass, void *data) 124660261038SCédric Le Goater { 124760261038SCédric Le Goater DeviceClass *dc = DEVICE_CLASS(klass); 124860261038SCédric Le Goater 124960261038SCédric Le Goater dc->desc = "Aspeed I2C Bus"; 125060261038SCédric Le Goater dc->realize = aspeed_i2c_bus_realize; 125160261038SCédric Le Goater dc->reset = aspeed_i2c_bus_reset; 125260261038SCédric Le Goater device_class_set_props(dc, aspeed_i2c_bus_properties); 125360261038SCédric Le Goater } 125460261038SCédric Le Goater 125560261038SCédric Le Goater static const TypeInfo aspeed_i2c_bus_info = { 125660261038SCédric Le Goater .name = TYPE_ASPEED_I2C_BUS, 125760261038SCédric Le Goater .parent = TYPE_SYS_BUS_DEVICE, 125860261038SCédric Le Goater .instance_size = sizeof(AspeedI2CBus), 125960261038SCédric Le Goater .class_init = aspeed_i2c_bus_class_init, 126060261038SCédric Le Goater }; 126160261038SCédric Le Goater 126251dd4923SCédric Le Goater static qemu_irq aspeed_2400_i2c_bus_get_irq(AspeedI2CBus *bus) 126351dd4923SCédric Le Goater { 126451dd4923SCédric Le Goater return bus->controller->irq; 126551dd4923SCédric Le Goater } 126651dd4923SCédric Le Goater 12676054fc73SCédric Le Goater static uint8_t *aspeed_2400_i2c_bus_pool_base(AspeedI2CBus *bus) 12686054fc73SCédric Le Goater { 12696054fc73SCédric Le Goater uint8_t *pool_page = 12702260fc6fSJoe Komlodi &bus->controller->pool[ARRAY_FIELD_EX32(bus->regs, I2CD_FUN_CTRL, 12713be3d6ccSJoe Komlodi POOL_PAGE_SEL) * 0x100]; 12726054fc73SCédric Le Goater 12732260fc6fSJoe Komlodi return &pool_page[ARRAY_FIELD_EX32(bus->regs, I2CD_POOL_CTRL, OFFSET)]; 12746054fc73SCédric Le Goater } 12756054fc73SCédric Le Goater 1276f7da1aa8SCédric Le Goater static void aspeed_2400_i2c_class_init(ObjectClass *klass, void *data) 1277f7da1aa8SCédric Le Goater { 1278f7da1aa8SCédric Le Goater DeviceClass *dc = DEVICE_CLASS(klass); 1279f7da1aa8SCédric Le Goater AspeedI2CClass *aic = ASPEED_I2C_CLASS(klass); 1280f7da1aa8SCédric Le Goater 1281f7da1aa8SCédric Le Goater dc->desc = "ASPEED 2400 I2C Controller"; 1282f7da1aa8SCédric Le Goater 1283f7da1aa8SCédric Le Goater aic->num_busses = 14; 1284f7da1aa8SCédric Le Goater aic->reg_size = 0x40; 1285f7da1aa8SCédric Le Goater aic->gap = 7; 128651dd4923SCédric Le Goater aic->bus_get_irq = aspeed_2400_i2c_bus_get_irq; 12876054fc73SCédric Le Goater aic->pool_size = 0x800; 12886054fc73SCédric Le Goater aic->pool_base = 0x800; 12896054fc73SCédric Le Goater aic->bus_pool_base = aspeed_2400_i2c_bus_pool_base; 1290f7da1aa8SCédric Le Goater } 1291f7da1aa8SCédric Le Goater 1292f7da1aa8SCédric Le Goater static const TypeInfo aspeed_2400_i2c_info = { 1293f7da1aa8SCédric Le Goater .name = TYPE_ASPEED_2400_I2C, 1294f7da1aa8SCédric Le Goater .parent = TYPE_ASPEED_I2C, 1295f7da1aa8SCédric Le Goater .class_init = aspeed_2400_i2c_class_init, 1296f7da1aa8SCédric Le Goater }; 1297f7da1aa8SCédric Le Goater 129851dd4923SCédric Le Goater static qemu_irq aspeed_2500_i2c_bus_get_irq(AspeedI2CBus *bus) 129951dd4923SCédric Le Goater { 130051dd4923SCédric Le Goater return bus->controller->irq; 130151dd4923SCédric Le Goater } 130251dd4923SCédric Le Goater 13036054fc73SCédric Le Goater static uint8_t *aspeed_2500_i2c_bus_pool_base(AspeedI2CBus *bus) 13046054fc73SCédric Le Goater { 13056054fc73SCédric Le Goater return &bus->controller->pool[bus->id * 0x10]; 13066054fc73SCédric Le Goater } 13076054fc73SCédric Le Goater 1308f7da1aa8SCédric Le Goater static void aspeed_2500_i2c_class_init(ObjectClass *klass, void *data) 1309f7da1aa8SCédric Le Goater { 1310f7da1aa8SCédric Le Goater DeviceClass *dc = DEVICE_CLASS(klass); 1311f7da1aa8SCédric Le Goater AspeedI2CClass *aic = ASPEED_I2C_CLASS(klass); 1312f7da1aa8SCédric Le Goater 1313f7da1aa8SCédric Le Goater dc->desc = "ASPEED 2500 I2C Controller"; 1314f7da1aa8SCédric Le Goater 1315f7da1aa8SCédric Le Goater aic->num_busses = 14; 1316f7da1aa8SCédric Le Goater aic->reg_size = 0x40; 1317f7da1aa8SCédric Le Goater aic->gap = 7; 131851dd4923SCédric Le Goater aic->bus_get_irq = aspeed_2500_i2c_bus_get_irq; 13196054fc73SCédric Le Goater aic->pool_size = 0x100; 13206054fc73SCédric Le Goater aic->pool_base = 0x200; 13216054fc73SCédric Le Goater aic->bus_pool_base = aspeed_2500_i2c_bus_pool_base; 1322aab90b1cSCédric Le Goater aic->check_sram = true; 1323545d6befSCédric Le Goater aic->has_dma = true; 1324f7da1aa8SCédric Le Goater } 1325f7da1aa8SCédric Le Goater 1326f7da1aa8SCédric Le Goater static const TypeInfo aspeed_2500_i2c_info = { 1327f7da1aa8SCédric Le Goater .name = TYPE_ASPEED_2500_I2C, 1328f7da1aa8SCédric Le Goater .parent = TYPE_ASPEED_I2C, 1329f7da1aa8SCédric Le Goater .class_init = aspeed_2500_i2c_class_init, 133016020011SCédric Le Goater }; 133116020011SCédric Le Goater 133251dd4923SCédric Le Goater static qemu_irq aspeed_2600_i2c_bus_get_irq(AspeedI2CBus *bus) 133351dd4923SCédric Le Goater { 133451dd4923SCédric Le Goater return bus->irq; 133551dd4923SCédric Le Goater } 133651dd4923SCédric Le Goater 13376054fc73SCédric Le Goater static uint8_t *aspeed_2600_i2c_bus_pool_base(AspeedI2CBus *bus) 13386054fc73SCédric Le Goater { 13396054fc73SCédric Le Goater return &bus->controller->pool[bus->id * 0x20]; 13406054fc73SCédric Le Goater } 13416054fc73SCédric Le Goater 134251dd4923SCédric Le Goater static void aspeed_2600_i2c_class_init(ObjectClass *klass, void *data) 134351dd4923SCédric Le Goater { 134451dd4923SCédric Le Goater DeviceClass *dc = DEVICE_CLASS(klass); 134551dd4923SCédric Le Goater AspeedI2CClass *aic = ASPEED_I2C_CLASS(klass); 134651dd4923SCédric Le Goater 134751dd4923SCédric Le Goater dc->desc = "ASPEED 2600 I2C Controller"; 134851dd4923SCédric Le Goater 134951dd4923SCédric Le Goater aic->num_busses = 16; 135051dd4923SCédric Le Goater aic->reg_size = 0x80; 135151dd4923SCédric Le Goater aic->gap = -1; /* no gap */ 135251dd4923SCédric Le Goater aic->bus_get_irq = aspeed_2600_i2c_bus_get_irq; 13536054fc73SCédric Le Goater aic->pool_size = 0x200; 13546054fc73SCédric Le Goater aic->pool_base = 0xC00; 13556054fc73SCédric Le Goater aic->bus_pool_base = aspeed_2600_i2c_bus_pool_base; 1356545d6befSCédric Le Goater aic->has_dma = true; 135751dd4923SCédric Le Goater } 135851dd4923SCédric Le Goater 135951dd4923SCédric Le Goater static const TypeInfo aspeed_2600_i2c_info = { 136051dd4923SCédric Le Goater .name = TYPE_ASPEED_2600_I2C, 136151dd4923SCédric Le Goater .parent = TYPE_ASPEED_I2C, 136251dd4923SCédric Le Goater .class_init = aspeed_2600_i2c_class_init, 136351dd4923SCédric Le Goater }; 136451dd4923SCédric Le Goater 1365b35802ceSCédric Le Goater static void aspeed_1030_i2c_class_init(ObjectClass *klass, void *data) 1366b35802ceSCédric Le Goater { 1367b35802ceSCédric Le Goater DeviceClass *dc = DEVICE_CLASS(klass); 1368b35802ceSCédric Le Goater AspeedI2CClass *aic = ASPEED_I2C_CLASS(klass); 1369b35802ceSCédric Le Goater 1370b35802ceSCédric Le Goater dc->desc = "ASPEED 1030 I2C Controller"; 1371b35802ceSCédric Le Goater 1372b35802ceSCédric Le Goater aic->num_busses = 14; 1373b35802ceSCédric Le Goater aic->reg_size = 0x80; 1374b35802ceSCédric Le Goater aic->gap = -1; /* no gap */ 1375b35802ceSCédric Le Goater aic->bus_get_irq = aspeed_2600_i2c_bus_get_irq; 1376b35802ceSCédric Le Goater aic->pool_size = 0x200; 1377b35802ceSCédric Le Goater aic->pool_base = 0xC00; 1378b35802ceSCédric Le Goater aic->bus_pool_base = aspeed_2600_i2c_bus_pool_base; 1379b35802ceSCédric Le Goater aic->has_dma = true; 1380b35802ceSCédric Le Goater } 1381b35802ceSCédric Le Goater 1382b35802ceSCédric Le Goater static const TypeInfo aspeed_1030_i2c_info = { 1383b35802ceSCédric Le Goater .name = TYPE_ASPEED_1030_I2C, 1384b35802ceSCédric Le Goater .parent = TYPE_ASPEED_I2C, 1385b35802ceSCédric Le Goater .class_init = aspeed_1030_i2c_class_init, 1386b35802ceSCédric Le Goater }; 1387b35802ceSCédric Le Goater 138816020011SCédric Le Goater static void aspeed_i2c_register_types(void) 138916020011SCédric Le Goater { 139060261038SCédric Le Goater type_register_static(&aspeed_i2c_bus_info); 1391a8d48f59SKlaus Jensen type_register_static(&aspeed_i2c_bus_slave_info); 139216020011SCédric Le Goater type_register_static(&aspeed_i2c_info); 1393f7da1aa8SCédric Le Goater type_register_static(&aspeed_2400_i2c_info); 1394f7da1aa8SCédric Le Goater type_register_static(&aspeed_2500_i2c_info); 139551dd4923SCédric Le Goater type_register_static(&aspeed_2600_i2c_info); 1396b35802ceSCédric Le Goater type_register_static(&aspeed_1030_i2c_info); 139716020011SCédric Le Goater } 139816020011SCédric Le Goater 139916020011SCédric Le Goater type_init(aspeed_i2c_register_types) 140016020011SCédric Le Goater 140116020011SCédric Le Goater 14027a204cbdSPhilippe Mathieu-Daudé I2CBus *aspeed_i2c_get_bus(AspeedI2CState *s, int busnr) 140316020011SCédric Le Goater { 1404f7da1aa8SCédric Le Goater AspeedI2CClass *aic = ASPEED_I2C_GET_CLASS(s); 140516020011SCédric Le Goater I2CBus *bus = NULL; 140616020011SCédric Le Goater 1407f7da1aa8SCédric Le Goater if (busnr >= 0 && busnr < aic->num_busses) { 140816020011SCédric Le Goater bus = s->busses[busnr].bus; 140916020011SCédric Le Goater } 141016020011SCédric Le Goater 141116020011SCédric Le Goater return bus; 141216020011SCédric Le Goater } 1413