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); 300acc3d20aSHang Yu if (SHARED_ARRAY_FIELD_EX32(bus->regs, reg_pool_ctrl, 301acc3d20aSHang Yu BUF_ORGANIZATION)) { 302acc3d20aSHang Yu pool_base += 16; 303acc3d20aSHang 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)) { 315ba2cccd6SJoe Komlodi /* In new mode, clear how many bytes we RXed */ 316ba2cccd6SJoe Komlodi if (aspeed_i2c_is_new_mode(bus->controller)) { 317ba2cccd6SJoe Komlodi ARRAY_FIELD_DP32(bus->regs, I2CM_DMA_LEN_STS, RX_LEN, 0); 318ba2cccd6SJoe Komlodi } 319545d6befSCédric Le Goater 320ba2cccd6SJoe Komlodi while (bus->regs[reg_dma_len]) { 321545d6befSCédric Le Goater MemTxResult result; 322545d6befSCédric Le Goater 323545d6befSCédric Le Goater data = i2c_recv(bus->bus); 324ba2cccd6SJoe Komlodi trace_aspeed_i2c_bus_recv("DMA", bus->regs[reg_dma_len], 325ba2cccd6SJoe Komlodi bus->regs[reg_dma_len], data); 326ba2cccd6SJoe Komlodi result = address_space_write(&s->dram_as, bus->regs[reg_dma_addr], 327545d6befSCédric Le Goater MEMTXATTRS_UNSPECIFIED, &data, 1); 328545d6befSCédric Le Goater if (result != MEMTX_OK) { 329545d6befSCédric Le Goater qemu_log_mask(LOG_GUEST_ERROR, "%s: DRAM write failed @%08x\n", 330ba2cccd6SJoe Komlodi __func__, bus->regs[reg_dma_addr]); 331545d6befSCédric Le Goater return; 332545d6befSCédric Le Goater } 333ba2cccd6SJoe Komlodi bus->regs[reg_dma_addr]++; 334ba2cccd6SJoe Komlodi bus->regs[reg_dma_len]--; 335ba2cccd6SJoe Komlodi /* In new mode, keep track of how many bytes we RXed */ 336ba2cccd6SJoe Komlodi if (aspeed_i2c_is_new_mode(bus->controller)) { 337ba2cccd6SJoe Komlodi ARRAY_FIELD_DP32(bus->regs, I2CM_DMA_LEN_STS, RX_LEN, 338ba2cccd6SJoe Komlodi ARRAY_FIELD_EX32(bus->regs, I2CM_DMA_LEN_STS, 339ba2cccd6SJoe Komlodi RX_LEN) + 1); 340545d6befSCédric Le Goater } 341ba2cccd6SJoe Komlodi } 342ba2cccd6SJoe Komlodi SHARED_ARRAY_FIELD_DP32(bus->regs, reg_cmd, RX_DMA_EN, 0); 3436054fc73SCédric Le Goater } else { 3446054fc73SCédric Le Goater data = i2c_recv(bus->bus); 345ba2cccd6SJoe Komlodi trace_aspeed_i2c_bus_recv("BYTE", 1, 1, bus->regs[reg_byte_buf]); 346ba2cccd6SJoe Komlodi SHARED_ARRAY_FIELD_DP32(bus->regs, reg_byte_buf, RX_BUF, data); 3476054fc73SCédric Le Goater } 3486054fc73SCédric Le Goater } 3496054fc73SCédric Le Goater 3507bd9c60dSGuenter Roeck static void aspeed_i2c_handle_rx_cmd(AspeedI2CBus *bus) 3517bd9c60dSGuenter Roeck { 352ba2cccd6SJoe Komlodi uint32_t reg_cmd = aspeed_i2c_bus_cmd_offset(bus); 353ba2cccd6SJoe Komlodi uint32_t reg_intr_sts = aspeed_i2c_bus_intr_sts_offset(bus); 354ba2cccd6SJoe Komlodi 3557bd9c60dSGuenter Roeck aspeed_i2c_set_state(bus, I2CD_MRXD); 3566054fc73SCédric Le Goater aspeed_i2c_bus_recv(bus); 357ba2cccd6SJoe Komlodi SHARED_ARRAY_FIELD_DP32(bus->regs, reg_intr_sts, RX_DONE, 1); 358ba2cccd6SJoe Komlodi if (SHARED_ARRAY_FIELD_EX32(bus->regs, reg_cmd, M_S_RX_CMD_LAST)) { 3597bd9c60dSGuenter Roeck i2c_nack(bus->bus); 3607bd9c60dSGuenter Roeck } 361ba2cccd6SJoe Komlodi SHARED_ARRAY_FIELD_DP32(bus->regs, reg_cmd, M_RX_CMD, 0); 362ba2cccd6SJoe Komlodi SHARED_ARRAY_FIELD_DP32(bus->regs, reg_cmd, M_S_RX_CMD_LAST, 0); 3637bd9c60dSGuenter Roeck aspeed_i2c_set_state(bus, I2CD_MACTIVE); 3647bd9c60dSGuenter Roeck } 3657bd9c60dSGuenter Roeck 3666054fc73SCédric Le Goater static uint8_t aspeed_i2c_get_addr(AspeedI2CBus *bus) 3676054fc73SCédric Le Goater { 3686054fc73SCédric Le Goater AspeedI2CClass *aic = ASPEED_I2C_GET_CLASS(bus->controller); 369ba2cccd6SJoe Komlodi uint32_t reg_byte_buf = aspeed_i2c_bus_byte_buf_offset(bus); 370ba2cccd6SJoe Komlodi uint32_t reg_cmd = aspeed_i2c_bus_cmd_offset(bus); 3716054fc73SCédric Le Goater 372ba2cccd6SJoe Komlodi if (aspeed_i2c_bus_pkt_mode_en(bus)) { 373ba2cccd6SJoe Komlodi return (ARRAY_FIELD_EX32(bus->regs, I2CM_CMD, PKT_DEV_ADDR) << 1) | 374ba2cccd6SJoe Komlodi SHARED_ARRAY_FIELD_EX32(bus->regs, reg_cmd, M_RX_CMD); 375ba2cccd6SJoe Komlodi } 376ba2cccd6SJoe Komlodi if (SHARED_ARRAY_FIELD_EX32(bus->regs, reg_cmd, TX_BUFF_EN)) { 3776054fc73SCédric Le Goater uint8_t *pool_base = aic->bus_pool_base(bus); 3786054fc73SCédric Le Goater 3796054fc73SCédric Le Goater return pool_base[0]; 380ba2cccd6SJoe Komlodi } else if (SHARED_ARRAY_FIELD_EX32(bus->regs, reg_cmd, TX_DMA_EN)) { 381545d6befSCédric Le Goater uint8_t data; 382545d6befSCédric Le Goater 383545d6befSCédric Le Goater aspeed_i2c_dma_read(bus, &data); 384545d6befSCédric Le Goater return data; 3856054fc73SCédric Le Goater } else { 386ba2cccd6SJoe Komlodi return bus->regs[reg_byte_buf]; 3876054fc73SCédric Le Goater } 3886054fc73SCédric Le Goater } 3896054fc73SCédric Le Goater 390aab90b1cSCédric Le Goater static bool aspeed_i2c_check_sram(AspeedI2CBus *bus) 391aab90b1cSCédric Le Goater { 392aab90b1cSCédric Le Goater AspeedI2CState *s = bus->controller; 393aab90b1cSCédric Le Goater AspeedI2CClass *aic = ASPEED_I2C_GET_CLASS(s); 394ba2cccd6SJoe Komlodi uint32_t reg_cmd = aspeed_i2c_bus_cmd_offset(bus); 395ba2cccd6SJoe Komlodi bool dma_en = SHARED_ARRAY_FIELD_EX32(bus->regs, reg_cmd, RX_DMA_EN) || 396ba2cccd6SJoe Komlodi SHARED_ARRAY_FIELD_EX32(bus->regs, reg_cmd, TX_DMA_EN) || 397ba2cccd6SJoe Komlodi SHARED_ARRAY_FIELD_EX32(bus->regs, reg_cmd, RX_BUFF_EN) || 398ba2cccd6SJoe Komlodi SHARED_ARRAY_FIELD_EX32(bus->regs, reg_cmd, TX_BUFF_EN); 399aab90b1cSCédric Le Goater if (!aic->check_sram) { 400aab90b1cSCédric Le Goater return true; 401aab90b1cSCédric Le Goater } 402aab90b1cSCédric Le Goater 403aab90b1cSCédric Le Goater /* 404aab90b1cSCédric Le Goater * AST2500: SRAM must be enabled before using the Buffer Pool or 405aab90b1cSCédric Le Goater * DMA mode. 406aab90b1cSCédric Le Goater */ 4073be3d6ccSJoe Komlodi if (!FIELD_EX32(s->ctrl_global, I2C_CTRL_GLOBAL, SRAM_EN) && dma_en) { 408aab90b1cSCédric Le Goater qemu_log_mask(LOG_GUEST_ERROR, "%s: SRAM is not enabled\n", __func__); 409aab90b1cSCédric Le Goater return false; 410aab90b1cSCédric Le Goater } 411aab90b1cSCédric Le Goater 412aab90b1cSCédric Le Goater return true; 413aab90b1cSCédric Le Goater } 414aab90b1cSCédric Le Goater 41566cc84a1SCédric Le Goater static void aspeed_i2c_bus_cmd_dump(AspeedI2CBus *bus) 41666cc84a1SCédric Le Goater { 417f821bac4SMiroslav Rezanina g_autofree char *cmd_flags = NULL; 41866cc84a1SCédric Le Goater uint32_t count; 419ba2cccd6SJoe Komlodi uint32_t reg_cmd = aspeed_i2c_bus_cmd_offset(bus); 420ba2cccd6SJoe Komlodi uint32_t reg_pool_ctrl = aspeed_i2c_bus_pool_ctrl_offset(bus); 421ba2cccd6SJoe Komlodi uint32_t reg_intr_sts = aspeed_i2c_bus_intr_sts_offset(bus); 422ba2cccd6SJoe Komlodi uint32_t reg_dma_len = aspeed_i2c_bus_dma_len_offset(bus); 423ba2cccd6SJoe Komlodi if (SHARED_ARRAY_FIELD_EX32(bus->regs, reg_cmd, RX_BUFF_EN)) { 42497b8aa5aSHang Yu count = SHARED_ARRAY_FIELD_EX32(bus->regs, reg_pool_ctrl, TX_COUNT) + 1; 425ba2cccd6SJoe Komlodi } else if (SHARED_ARRAY_FIELD_EX32(bus->regs, reg_cmd, RX_DMA_EN)) { 426ba2cccd6SJoe Komlodi count = bus->regs[reg_dma_len]; 42766cc84a1SCédric Le Goater } else { /* BYTE mode */ 42866cc84a1SCédric Le Goater count = 1; 42966cc84a1SCédric Le Goater } 43066cc84a1SCédric Le Goater 43166cc84a1SCédric Le Goater cmd_flags = g_strdup_printf("%s%s%s%s%s%s%s%s%s", 432ba2cccd6SJoe Komlodi SHARED_ARRAY_FIELD_EX32(bus->regs, reg_cmd, M_START_CMD) ? "start|" : "", 433ba2cccd6SJoe Komlodi SHARED_ARRAY_FIELD_EX32(bus->regs, reg_cmd, RX_DMA_EN) ? "rxdma|" : "", 434ba2cccd6SJoe Komlodi SHARED_ARRAY_FIELD_EX32(bus->regs, reg_cmd, TX_DMA_EN) ? "txdma|" : "", 435ba2cccd6SJoe Komlodi SHARED_ARRAY_FIELD_EX32(bus->regs, reg_cmd, RX_BUFF_EN) ? "rxbuf|" : "", 436ba2cccd6SJoe Komlodi SHARED_ARRAY_FIELD_EX32(bus->regs, reg_cmd, TX_BUFF_EN) ? "txbuf|" : "", 437ba2cccd6SJoe Komlodi SHARED_ARRAY_FIELD_EX32(bus->regs, reg_cmd, M_TX_CMD) ? "tx|" : "", 438ba2cccd6SJoe Komlodi SHARED_ARRAY_FIELD_EX32(bus->regs, reg_cmd, M_RX_CMD) ? "rx|" : "", 439ba2cccd6SJoe Komlodi SHARED_ARRAY_FIELD_EX32(bus->regs, reg_cmd, M_S_RX_CMD_LAST) ? "last|" : "", 440ba2cccd6SJoe Komlodi SHARED_ARRAY_FIELD_EX32(bus->regs, reg_cmd, M_STOP_CMD) ? "stop|" : ""); 44166cc84a1SCédric Le Goater 442ba2cccd6SJoe Komlodi trace_aspeed_i2c_bus_cmd(bus->regs[reg_cmd], cmd_flags, count, 443ba2cccd6SJoe Komlodi bus->regs[reg_intr_sts]); 44466cc84a1SCédric Le Goater } 44566cc84a1SCédric Le Goater 4464960f084SCédric Le Goater /* 4474960f084SCédric Le Goater * The state machine needs some refinement. It is only used to track 4484960f084SCédric Le Goater * invalid STOP commands for the moment. 4494960f084SCédric Le Goater */ 45016020011SCédric Le Goater static void aspeed_i2c_bus_handle_cmd(AspeedI2CBus *bus, uint64_t value) 45116020011SCédric Le Goater { 452ba2cccd6SJoe Komlodi uint32_t reg_intr_sts = aspeed_i2c_bus_intr_sts_offset(bus); 453ba2cccd6SJoe Komlodi uint32_t reg_cmd = aspeed_i2c_bus_cmd_offset(bus); 454ba2cccd6SJoe Komlodi uint32_t reg_dma_len = aspeed_i2c_bus_dma_len_offset(bus); 45516020011SCédric Le Goater 456aab90b1cSCédric Le Goater if (!aspeed_i2c_check_sram(bus)) { 457aab90b1cSCédric Le Goater return; 458aab90b1cSCédric Le Goater } 459aab90b1cSCédric Le Goater 46066cc84a1SCédric Le Goater if (trace_event_get_state_backends(TRACE_ASPEED_I2C_BUS_CMD)) { 46166cc84a1SCédric Le Goater aspeed_i2c_bus_cmd_dump(bus); 46266cc84a1SCédric Le Goater } 46366cc84a1SCédric Le Goater 464ba2cccd6SJoe Komlodi if (SHARED_ARRAY_FIELD_EX32(bus->regs, reg_cmd, M_START_CMD)) { 4654960f084SCédric Le Goater uint8_t state = aspeed_i2c_get_state(bus) & I2CD_MACTIVE ? 4664960f084SCédric Le Goater I2CD_MSTARTR : I2CD_MSTART; 4676054fc73SCédric Le Goater uint8_t addr; 4684960f084SCédric Le Goater 4694960f084SCédric Le Goater aspeed_i2c_set_state(bus, state); 4704960f084SCédric Le Goater 4716054fc73SCédric Le Goater addr = aspeed_i2c_get_addr(bus); 4726054fc73SCédric Le Goater if (i2c_start_transfer(bus->bus, extract32(addr, 1, 7), 4736054fc73SCédric Le Goater extract32(addr, 0, 1))) { 474ba2cccd6SJoe Komlodi SHARED_ARRAY_FIELD_DP32(bus->regs, reg_intr_sts, TX_NAK, 1); 475ba2cccd6SJoe Komlodi if (aspeed_i2c_bus_pkt_mode_en(bus)) { 476ba2cccd6SJoe Komlodi ARRAY_FIELD_DP32(bus->regs, I2CM_INTR_STS, PKT_CMD_FAIL, 1); 477ba2cccd6SJoe Komlodi } 47816020011SCédric Le Goater } else { 479ba2cccd6SJoe Komlodi /* START doesn't set TX_ACK in packet mode */ 480ba2cccd6SJoe Komlodi if (!aspeed_i2c_bus_pkt_mode_en(bus)) { 481ba2cccd6SJoe Komlodi SHARED_ARRAY_FIELD_DP32(bus->regs, reg_intr_sts, TX_ACK, 1); 482ba2cccd6SJoe Komlodi } 48316020011SCédric Le Goater } 48416020011SCédric Le Goater 485ba2cccd6SJoe Komlodi SHARED_ARRAY_FIELD_DP32(bus->regs, reg_cmd, M_START_CMD, 0); 4866054fc73SCédric Le Goater 487961faf3dSHang Yu if (SHARED_ARRAY_FIELD_EX32(bus->regs, reg_cmd, TX_DMA_EN)) { 488ba2cccd6SJoe Komlodi if (bus->regs[reg_dma_len] == 0) { 489ba2cccd6SJoe Komlodi SHARED_ARRAY_FIELD_DP32(bus->regs, reg_cmd, M_TX_CMD, 0); 490545d6befSCédric Le Goater } 491961faf3dSHang Yu } else if (!SHARED_ARRAY_FIELD_EX32(bus->regs, reg_cmd, TX_BUFF_EN)) { 492ba2cccd6SJoe Komlodi SHARED_ARRAY_FIELD_DP32(bus->regs, reg_cmd, M_TX_CMD, 0); 4936054fc73SCédric Le Goater } 494ddabca75SCédric Le Goater 495ddabca75SCédric Le Goater /* No slave found */ 496ddabca75SCédric Le Goater if (!i2c_bus_busy(bus->bus)) { 497ba2cccd6SJoe Komlodi if (aspeed_i2c_bus_pkt_mode_en(bus)) { 498ba2cccd6SJoe Komlodi ARRAY_FIELD_DP32(bus->regs, I2CM_INTR_STS, PKT_CMD_FAIL, 1); 499ba2cccd6SJoe Komlodi ARRAY_FIELD_DP32(bus->regs, I2CM_INTR_STS, PKT_CMD_DONE, 1); 500ba2cccd6SJoe Komlodi } 501ddabca75SCédric Le Goater return; 502ddabca75SCédric Le Goater } 5034960f084SCédric Le Goater aspeed_i2c_set_state(bus, I2CD_MACTIVE); 504ddabca75SCédric Le Goater } 505ddabca75SCédric Le Goater 506ba2cccd6SJoe Komlodi if (SHARED_ARRAY_FIELD_EX32(bus->regs, reg_cmd, M_TX_CMD)) { 5074960f084SCédric Le Goater aspeed_i2c_set_state(bus, I2CD_MTXD); 508961faf3dSHang Yu if (aspeed_i2c_bus_send(bus)) { 509ba2cccd6SJoe Komlodi SHARED_ARRAY_FIELD_DP32(bus->regs, reg_intr_sts, TX_NAK, 1); 51016020011SCédric Le Goater i2c_end_transfer(bus->bus); 51116020011SCédric Le Goater } else { 512ba2cccd6SJoe Komlodi SHARED_ARRAY_FIELD_DP32(bus->regs, reg_intr_sts, TX_ACK, 1); 51316020011SCédric Le Goater } 514ba2cccd6SJoe Komlodi SHARED_ARRAY_FIELD_DP32(bus->regs, reg_cmd, M_TX_CMD, 0); 5154960f084SCédric Le Goater aspeed_i2c_set_state(bus, I2CD_MACTIVE); 516ddabca75SCédric Le Goater } 51716020011SCédric Le Goater 518ba2cccd6SJoe Komlodi if ((SHARED_ARRAY_FIELD_EX32(bus->regs, reg_cmd, M_RX_CMD) || 519ba2cccd6SJoe Komlodi SHARED_ARRAY_FIELD_EX32(bus->regs, reg_cmd, M_S_RX_CMD_LAST)) && 520ba2cccd6SJoe Komlodi !SHARED_ARRAY_FIELD_EX32(bus->regs, reg_intr_sts, RX_DONE)) { 5217bd9c60dSGuenter Roeck aspeed_i2c_handle_rx_cmd(bus); 52216020011SCédric Le Goater } 52316020011SCédric Le Goater 524ba2cccd6SJoe Komlodi if (SHARED_ARRAY_FIELD_EX32(bus->regs, reg_cmd, M_STOP_CMD)) { 5254960f084SCédric Le Goater if (!(aspeed_i2c_get_state(bus) & I2CD_MACTIVE)) { 5264960f084SCédric Le Goater qemu_log_mask(LOG_GUEST_ERROR, "%s: abnormal stop\n", __func__); 527ba2cccd6SJoe Komlodi SHARED_ARRAY_FIELD_DP32(bus->regs, reg_intr_sts, ABNORMAL, 1); 528ba2cccd6SJoe Komlodi if (aspeed_i2c_bus_pkt_mode_en(bus)) { 529ba2cccd6SJoe Komlodi ARRAY_FIELD_DP32(bus->regs, I2CM_INTR_STS, PKT_CMD_FAIL, 1); 530ba2cccd6SJoe Komlodi } 53116020011SCédric Le Goater } else { 5324960f084SCédric Le Goater aspeed_i2c_set_state(bus, I2CD_MSTOP); 53316020011SCédric Le Goater i2c_end_transfer(bus->bus); 534ba2cccd6SJoe Komlodi SHARED_ARRAY_FIELD_DP32(bus->regs, reg_intr_sts, NORMAL_STOP, 1); 53516020011SCédric Le Goater } 536ba2cccd6SJoe Komlodi SHARED_ARRAY_FIELD_DP32(bus->regs, reg_cmd, M_STOP_CMD, 0); 5374960f084SCédric Le Goater aspeed_i2c_set_state(bus, I2CD_IDLE); 538791cb95fSKlaus Jensen 539791cb95fSKlaus Jensen i2c_schedule_pending_master(bus->bus); 54016020011SCédric Le Goater } 541ba2cccd6SJoe Komlodi 542ba2cccd6SJoe Komlodi if (aspeed_i2c_bus_pkt_mode_en(bus)) { 543ba2cccd6SJoe Komlodi ARRAY_FIELD_DP32(bus->regs, I2CM_INTR_STS, PKT_CMD_DONE, 1); 544ba2cccd6SJoe Komlodi } 54516020011SCédric Le Goater } 54616020011SCédric Le Goater 547ba2cccd6SJoe Komlodi static void aspeed_i2c_bus_new_write(AspeedI2CBus *bus, hwaddr offset, 54816020011SCédric Le Goater uint64_t value, unsigned size) 54916020011SCédric Le Goater { 550ba2cccd6SJoe Komlodi AspeedI2CClass *aic = ASPEED_I2C_GET_CLASS(bus->controller); 551ba2cccd6SJoe Komlodi bool handle_rx; 552ba2cccd6SJoe Komlodi bool w1t; 553ba2cccd6SJoe Komlodi 554ba2cccd6SJoe Komlodi trace_aspeed_i2c_bus_write(bus->id, offset, size, value); 555ba2cccd6SJoe Komlodi 556ba2cccd6SJoe Komlodi switch (offset) { 557ba2cccd6SJoe Komlodi case A_I2CC_FUN_CTRL: 5581c5d909fSPeter Delevoryas bus->regs[R_I2CC_FUN_CTRL] = value; 559ba2cccd6SJoe Komlodi break; 560ba2cccd6SJoe Komlodi case A_I2CC_AC_TIMING: 561ba2cccd6SJoe Komlodi bus->regs[R_I2CC_AC_TIMING] = value & 0x1ffff0ff; 562ba2cccd6SJoe Komlodi break; 563ba2cccd6SJoe Komlodi case A_I2CC_MS_TXRX_BYTE_BUF: 564ba2cccd6SJoe Komlodi SHARED_ARRAY_FIELD_DP32(bus->regs, R_I2CC_MS_TXRX_BYTE_BUF, TX_BUF, 565ba2cccd6SJoe Komlodi value); 566ba2cccd6SJoe Komlodi break; 567ba2cccd6SJoe Komlodi case A_I2CC_POOL_CTRL: 568ba2cccd6SJoe Komlodi bus->regs[R_I2CC_POOL_CTRL] &= ~0xffffff; 569ba2cccd6SJoe Komlodi bus->regs[R_I2CC_POOL_CTRL] |= (value & 0xffffff); 570ba2cccd6SJoe Komlodi break; 571ba2cccd6SJoe Komlodi case A_I2CM_INTR_CTRL: 572ba2cccd6SJoe Komlodi bus->regs[R_I2CM_INTR_CTRL] = value & 0x0007f07f; 573ba2cccd6SJoe Komlodi break; 574ba2cccd6SJoe Komlodi case A_I2CM_INTR_STS: 575ba2cccd6SJoe Komlodi handle_rx = SHARED_ARRAY_FIELD_EX32(bus->regs, R_I2CM_INTR_STS, RX_DONE) 576ba2cccd6SJoe Komlodi && SHARED_FIELD_EX32(value, RX_DONE); 577ba2cccd6SJoe Komlodi 578ba2cccd6SJoe Komlodi /* In packet mode, clearing PKT_CMD_DONE clears other interrupts. */ 579ba2cccd6SJoe Komlodi if (aspeed_i2c_bus_pkt_mode_en(bus) && 580ba2cccd6SJoe Komlodi FIELD_EX32(value, I2CM_INTR_STS, PKT_CMD_DONE)) { 581ba2cccd6SJoe Komlodi bus->regs[R_I2CM_INTR_STS] &= 0xf0001000; 582ba2cccd6SJoe Komlodi if (!bus->regs[R_I2CM_INTR_STS]) { 583ba2cccd6SJoe Komlodi bus->controller->intr_status &= ~(1 << bus->id); 584ba2cccd6SJoe Komlodi qemu_irq_lower(aic->bus_get_irq(bus)); 585ba2cccd6SJoe Komlodi } 5861c5d909fSPeter Delevoryas aspeed_i2c_bus_raise_slave_interrupt(bus); 587ba2cccd6SJoe Komlodi break; 588ba2cccd6SJoe Komlodi } 589ba2cccd6SJoe Komlodi bus->regs[R_I2CM_INTR_STS] &= ~(value & 0xf007f07f); 590ba2cccd6SJoe Komlodi if (!bus->regs[R_I2CM_INTR_STS]) { 591ba2cccd6SJoe Komlodi bus->controller->intr_status &= ~(1 << bus->id); 592ba2cccd6SJoe Komlodi qemu_irq_lower(aic->bus_get_irq(bus)); 593ba2cccd6SJoe Komlodi } 594ba2cccd6SJoe Komlodi if (handle_rx && (SHARED_ARRAY_FIELD_EX32(bus->regs, R_I2CM_CMD, 595ba2cccd6SJoe Komlodi M_RX_CMD) || 596ba2cccd6SJoe Komlodi SHARED_ARRAY_FIELD_EX32(bus->regs, R_I2CM_CMD, 597ba2cccd6SJoe Komlodi M_S_RX_CMD_LAST))) { 598ba2cccd6SJoe Komlodi aspeed_i2c_handle_rx_cmd(bus); 599ba2cccd6SJoe Komlodi aspeed_i2c_bus_raise_interrupt(bus); 600ba2cccd6SJoe Komlodi } 601ba2cccd6SJoe Komlodi break; 602ba2cccd6SJoe Komlodi case A_I2CM_CMD: 603ba2cccd6SJoe Komlodi if (!aspeed_i2c_bus_is_enabled(bus)) { 604ba2cccd6SJoe Komlodi break; 605ba2cccd6SJoe Komlodi } 606ba2cccd6SJoe Komlodi 607ba2cccd6SJoe Komlodi if (!aspeed_i2c_bus_is_master(bus)) { 6080c0f1beeSPeter Delevoryas qemu_log_mask(LOG_GUEST_ERROR, "%s: Master mode is not enabled\n", 609ba2cccd6SJoe Komlodi __func__); 610ba2cccd6SJoe Komlodi break; 611ba2cccd6SJoe Komlodi } 612ba2cccd6SJoe Komlodi 613ba2cccd6SJoe Komlodi if (!aic->has_dma && 614ba2cccd6SJoe Komlodi (SHARED_FIELD_EX32(value, RX_DMA_EN) || 615ba2cccd6SJoe Komlodi SHARED_FIELD_EX32(value, TX_DMA_EN))) { 616ba2cccd6SJoe Komlodi qemu_log_mask(LOG_GUEST_ERROR, "%s: No DMA support\n", __func__); 617ba2cccd6SJoe Komlodi break; 618ba2cccd6SJoe Komlodi } 619ba2cccd6SJoe Komlodi 620ba2cccd6SJoe Komlodi if (bus->regs[R_I2CM_INTR_STS] & 0xffff0000) { 621ba2cccd6SJoe Komlodi qemu_log_mask(LOG_UNIMP, "%s: Packet mode is not implemented\n", 622ba2cccd6SJoe Komlodi __func__); 623ba2cccd6SJoe Komlodi break; 624ba2cccd6SJoe Komlodi } 625ba2cccd6SJoe Komlodi 626ba2cccd6SJoe Komlodi value &= 0xff0ffbfb; 627ba2cccd6SJoe Komlodi if (ARRAY_FIELD_EX32(bus->regs, I2CM_CMD, W1_CTRL)) { 628ba2cccd6SJoe Komlodi bus->regs[R_I2CM_CMD] |= value; 629ba2cccd6SJoe Komlodi } else { 630ba2cccd6SJoe Komlodi bus->regs[R_I2CM_CMD] = value; 631ba2cccd6SJoe Komlodi } 632ba2cccd6SJoe Komlodi 633ba2cccd6SJoe Komlodi aspeed_i2c_bus_handle_cmd(bus, value); 634ba2cccd6SJoe Komlodi aspeed_i2c_bus_raise_interrupt(bus); 635ba2cccd6SJoe Komlodi break; 636ba2cccd6SJoe Komlodi case A_I2CM_DMA_TX_ADDR: 637ba2cccd6SJoe Komlodi bus->regs[R_I2CM_DMA_TX_ADDR] = FIELD_EX32(value, I2CM_DMA_TX_ADDR, 638ba2cccd6SJoe Komlodi ADDR); 639ba2cccd6SJoe Komlodi bus->regs[R_I2CC_DMA_ADDR] = FIELD_EX32(value, I2CM_DMA_TX_ADDR, ADDR); 640ba2cccd6SJoe Komlodi bus->regs[R_I2CC_DMA_LEN] = ARRAY_FIELD_EX32(bus->regs, I2CM_DMA_LEN, 641ba2cccd6SJoe Komlodi TX_BUF_LEN) + 1; 642ba2cccd6SJoe Komlodi break; 643ba2cccd6SJoe Komlodi case A_I2CM_DMA_RX_ADDR: 644ba2cccd6SJoe Komlodi bus->regs[R_I2CM_DMA_RX_ADDR] = FIELD_EX32(value, I2CM_DMA_RX_ADDR, 645ba2cccd6SJoe Komlodi ADDR); 646ba2cccd6SJoe Komlodi bus->regs[R_I2CC_DMA_ADDR] = FIELD_EX32(value, I2CM_DMA_RX_ADDR, ADDR); 647ba2cccd6SJoe Komlodi bus->regs[R_I2CC_DMA_LEN] = ARRAY_FIELD_EX32(bus->regs, I2CM_DMA_LEN, 648ba2cccd6SJoe Komlodi RX_BUF_LEN) + 1; 649ba2cccd6SJoe Komlodi break; 650ba2cccd6SJoe Komlodi case A_I2CM_DMA_LEN: 651b582b7a1SPeter Delevoryas w1t = FIELD_EX32(value, I2CM_DMA_LEN, RX_BUF_LEN_W1T) || 652b582b7a1SPeter Delevoryas FIELD_EX32(value, I2CM_DMA_LEN, TX_BUF_LEN_W1T); 653ba2cccd6SJoe Komlodi /* If none of the w1t bits are set, just write to the reg as normal. */ 654ba2cccd6SJoe Komlodi if (!w1t) { 655ba2cccd6SJoe Komlodi bus->regs[R_I2CM_DMA_LEN] = value; 656ba2cccd6SJoe Komlodi break; 657ba2cccd6SJoe Komlodi } 658b582b7a1SPeter Delevoryas if (FIELD_EX32(value, I2CM_DMA_LEN, RX_BUF_LEN_W1T)) { 659ba2cccd6SJoe Komlodi ARRAY_FIELD_DP32(bus->regs, I2CM_DMA_LEN, RX_BUF_LEN, 660ba2cccd6SJoe Komlodi FIELD_EX32(value, I2CM_DMA_LEN, RX_BUF_LEN)); 661ba2cccd6SJoe Komlodi } 662b582b7a1SPeter Delevoryas if (FIELD_EX32(value, I2CM_DMA_LEN, TX_BUF_LEN_W1T)) { 663ba2cccd6SJoe Komlodi ARRAY_FIELD_DP32(bus->regs, I2CM_DMA_LEN, TX_BUF_LEN, 664ba2cccd6SJoe Komlodi FIELD_EX32(value, I2CM_DMA_LEN, TX_BUF_LEN)); 665ba2cccd6SJoe Komlodi } 666ba2cccd6SJoe Komlodi break; 667ba2cccd6SJoe Komlodi case A_I2CM_DMA_LEN_STS: 668ba2cccd6SJoe Komlodi /* Writes clear to 0 */ 669ba2cccd6SJoe Komlodi bus->regs[R_I2CM_DMA_LEN_STS] = 0; 670ba2cccd6SJoe Komlodi break; 671ba2cccd6SJoe Komlodi case A_I2CC_DMA_ADDR: 672ba2cccd6SJoe Komlodi case A_I2CC_DMA_LEN: 673ba2cccd6SJoe Komlodi /* RO */ 674ba2cccd6SJoe Komlodi break; 675ba2cccd6SJoe Komlodi case A_I2CS_DEV_ADDR: 6761c5d909fSPeter Delevoryas bus->regs[R_I2CS_DEV_ADDR] = value; 6771c5d909fSPeter Delevoryas break; 6781c5d909fSPeter Delevoryas case A_I2CS_DMA_RX_ADDR: 6791c5d909fSPeter Delevoryas bus->regs[R_I2CS_DMA_RX_ADDR] = value; 6801c5d909fSPeter Delevoryas break; 681ba2cccd6SJoe Komlodi case A_I2CS_DMA_LEN: 6821c5d909fSPeter Delevoryas assert(FIELD_EX32(value, I2CS_DMA_LEN, TX_BUF_LEN) == 0); 6831c5d909fSPeter Delevoryas if (FIELD_EX32(value, I2CS_DMA_LEN, RX_BUF_LEN_W1T)) { 6841c5d909fSPeter Delevoryas ARRAY_FIELD_DP32(bus->regs, I2CS_DMA_LEN, RX_BUF_LEN, 6851c5d909fSPeter Delevoryas FIELD_EX32(value, I2CS_DMA_LEN, RX_BUF_LEN)); 6861c5d909fSPeter Delevoryas } else { 6871c5d909fSPeter Delevoryas bus->regs[R_I2CS_DMA_LEN] = value; 6881c5d909fSPeter Delevoryas } 6891c5d909fSPeter Delevoryas break; 6901c5d909fSPeter Delevoryas case A_I2CS_CMD: 6911c5d909fSPeter Delevoryas if (FIELD_EX32(value, I2CS_CMD, W1_CTRL)) { 6921c5d909fSPeter Delevoryas bus->regs[R_I2CS_CMD] |= value; 6931c5d909fSPeter Delevoryas } else { 6941c5d909fSPeter Delevoryas bus->regs[R_I2CS_CMD] = value; 6951c5d909fSPeter Delevoryas } 6961c5d909fSPeter Delevoryas i2c_slave_set_address(bus->slave, bus->regs[R_I2CS_DEV_ADDR]); 6971c5d909fSPeter Delevoryas break; 6981c5d909fSPeter Delevoryas case A_I2CS_INTR_CTRL: 6991c5d909fSPeter Delevoryas bus->regs[R_I2CS_INTR_CTRL] = value; 7001c5d909fSPeter Delevoryas break; 7011c5d909fSPeter Delevoryas 7021c5d909fSPeter Delevoryas case A_I2CS_INTR_STS: 7031c5d909fSPeter Delevoryas if (ARRAY_FIELD_EX32(bus->regs, I2CS_INTR_CTRL, PKT_CMD_DONE)) { 7041c5d909fSPeter Delevoryas if (ARRAY_FIELD_EX32(bus->regs, I2CS_INTR_STS, PKT_CMD_DONE) && 7051c5d909fSPeter Delevoryas FIELD_EX32(value, I2CS_INTR_STS, PKT_CMD_DONE)) { 7061c5d909fSPeter Delevoryas bus->regs[R_I2CS_INTR_STS] &= 0xfffc0000; 7071c5d909fSPeter Delevoryas } 7081c5d909fSPeter Delevoryas } else { 7091c5d909fSPeter Delevoryas bus->regs[R_I2CS_INTR_STS] &= ~value; 7101c5d909fSPeter Delevoryas } 7111c5d909fSPeter Delevoryas if (!bus->regs[R_I2CS_INTR_STS]) { 7121c5d909fSPeter Delevoryas bus->controller->intr_status &= ~(1 << bus->id); 7131c5d909fSPeter Delevoryas qemu_irq_lower(aic->bus_get_irq(bus)); 7141c5d909fSPeter Delevoryas } 7151c5d909fSPeter Delevoryas aspeed_i2c_bus_raise_interrupt(bus); 7161c5d909fSPeter Delevoryas break; 7171c5d909fSPeter Delevoryas case A_I2CS_DMA_LEN_STS: 7181c5d909fSPeter Delevoryas bus->regs[R_I2CS_DMA_LEN_STS] = 0; 7191c5d909fSPeter Delevoryas break; 7201c5d909fSPeter Delevoryas case A_I2CS_DMA_TX_ADDR: 7211c5d909fSPeter Delevoryas qemu_log_mask(LOG_UNIMP, "%s: Slave mode DMA TX is not implemented\n", 722ba2cccd6SJoe Komlodi __func__); 723ba2cccd6SJoe Komlodi break; 724ba2cccd6SJoe Komlodi default: 725ba2cccd6SJoe Komlodi qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad offset 0x%" HWADDR_PRIx "\n", 726ba2cccd6SJoe Komlodi __func__, offset); 727ba2cccd6SJoe Komlodi } 728ba2cccd6SJoe Komlodi } 729ba2cccd6SJoe Komlodi 730ba2cccd6SJoe Komlodi static void aspeed_i2c_bus_old_write(AspeedI2CBus *bus, hwaddr offset, 731ba2cccd6SJoe Komlodi uint64_t value, unsigned size) 732ba2cccd6SJoe Komlodi { 73351dd4923SCédric Le Goater AspeedI2CClass *aic = ASPEED_I2C_GET_CLASS(bus->controller); 734bb626e5bSGuenter Roeck bool handle_rx; 73516020011SCédric Le Goater 73666cc84a1SCédric Le Goater trace_aspeed_i2c_bus_write(bus->id, offset, size, value); 73766cc84a1SCédric Le Goater 73816020011SCédric Le Goater switch (offset) { 7393be3d6ccSJoe Komlodi case A_I2CD_FUN_CTRL: 740ba2cccd6SJoe Komlodi if (SHARED_FIELD_EX32(value, SLAVE_EN)) { 741a8d48f59SKlaus Jensen i2c_slave_set_address(bus->slave, bus->regs[R_I2CD_DEV_ADDR]); 74216020011SCédric Le Goater } 7432260fc6fSJoe Komlodi bus->regs[R_I2CD_FUN_CTRL] = value & 0x0071C3FF; 74416020011SCédric Le Goater break; 7453be3d6ccSJoe Komlodi case A_I2CD_AC_TIMING1: 7462260fc6fSJoe Komlodi bus->regs[R_I2CD_AC_TIMING1] = value & 0xFFFFF0F; 74716020011SCédric Le Goater break; 7483be3d6ccSJoe Komlodi case A_I2CD_AC_TIMING2: 7492260fc6fSJoe Komlodi bus->regs[R_I2CD_AC_TIMING2] = value & 0x7; 75016020011SCédric Le Goater break; 7513be3d6ccSJoe Komlodi case A_I2CD_INTR_CTRL: 7522260fc6fSJoe Komlodi bus->regs[R_I2CD_INTR_CTRL] = value & 0x7FFF; 75316020011SCédric Le Goater break; 7543be3d6ccSJoe Komlodi case A_I2CD_INTR_STS: 755ba2cccd6SJoe Komlodi handle_rx = SHARED_ARRAY_FIELD_EX32(bus->regs, R_I2CD_INTR_STS, RX_DONE) 756ba2cccd6SJoe Komlodi && SHARED_FIELD_EX32(value, RX_DONE); 7572260fc6fSJoe Komlodi bus->regs[R_I2CD_INTR_STS] &= ~(value & 0x7FFF); 7582260fc6fSJoe Komlodi if (!bus->regs[R_I2CD_INTR_STS]) { 75916020011SCédric Le Goater bus->controller->intr_status &= ~(1 << bus->id); 76051dd4923SCédric Le Goater qemu_irq_lower(aic->bus_get_irq(bus)); 7615540cb97SCédric Le Goater } 762a8d48f59SKlaus Jensen if (handle_rx) { 763a8d48f59SKlaus Jensen if (SHARED_ARRAY_FIELD_EX32(bus->regs, R_I2CD_CMD, M_RX_CMD) || 764ba2cccd6SJoe Komlodi SHARED_ARRAY_FIELD_EX32(bus->regs, R_I2CD_CMD, 765a8d48f59SKlaus Jensen M_S_RX_CMD_LAST)) { 766bb626e5bSGuenter Roeck aspeed_i2c_handle_rx_cmd(bus); 767bb626e5bSGuenter Roeck aspeed_i2c_bus_raise_interrupt(bus); 768a8d48f59SKlaus Jensen } else if (aspeed_i2c_get_state(bus) == I2CD_STXD) { 769a8d48f59SKlaus Jensen i2c_ack(bus->bus); 770a8d48f59SKlaus Jensen } 771bb626e5bSGuenter Roeck } 77216020011SCédric Le Goater break; 7733be3d6ccSJoe Komlodi case A_I2CD_DEV_ADDR: 774d72a712cSKlaus Jensen bus->regs[R_I2CD_DEV_ADDR] = value; 77516020011SCédric Le Goater break; 7763be3d6ccSJoe Komlodi case A_I2CD_POOL_CTRL: 7772260fc6fSJoe Komlodi bus->regs[R_I2CD_POOL_CTRL] &= ~0xffffff; 7782260fc6fSJoe Komlodi bus->regs[R_I2CD_POOL_CTRL] |= (value & 0xffffff); 7796054fc73SCédric Le Goater break; 7806054fc73SCédric Le Goater 7813be3d6ccSJoe Komlodi case A_I2CD_BYTE_BUF: 782ba2cccd6SJoe Komlodi SHARED_ARRAY_FIELD_DP32(bus->regs, R_I2CD_BYTE_BUF, TX_BUF, value); 78316020011SCédric Le Goater break; 7843be3d6ccSJoe Komlodi case A_I2CD_CMD: 78516020011SCédric Le Goater if (!aspeed_i2c_bus_is_enabled(bus)) { 78616020011SCédric Le Goater break; 78716020011SCédric Le Goater } 78816020011SCédric Le Goater 78916020011SCédric Le Goater if (!aspeed_i2c_bus_is_master(bus)) { 7900c0f1beeSPeter Delevoryas qemu_log_mask(LOG_GUEST_ERROR, "%s: Master mode is not enabled\n", 79116020011SCédric Le Goater __func__); 79216020011SCédric Le Goater break; 79316020011SCédric Le Goater } 79416020011SCédric Le Goater 795545d6befSCédric Le Goater if (!aic->has_dma && 796ba2cccd6SJoe Komlodi (SHARED_FIELD_EX32(value, RX_DMA_EN) || 797ba2cccd6SJoe Komlodi SHARED_FIELD_EX32(value, TX_DMA_EN))) { 798545d6befSCédric Le Goater qemu_log_mask(LOG_GUEST_ERROR, "%s: No DMA support\n", __func__); 799545d6befSCédric Le Goater break; 800545d6befSCédric Le Goater } 801545d6befSCédric Le Goater 802ba2cccd6SJoe Komlodi bus->regs[R_I2CD_CMD] &= ~0xFFFF; 803ba2cccd6SJoe Komlodi bus->regs[R_I2CD_CMD] |= value & 0xFFFF; 804ba2cccd6SJoe Komlodi 80516020011SCédric Le Goater aspeed_i2c_bus_handle_cmd(bus, value); 806ddabca75SCédric Le Goater aspeed_i2c_bus_raise_interrupt(bus); 80716020011SCédric Le Goater break; 8083be3d6ccSJoe Komlodi case A_I2CD_DMA_ADDR: 809545d6befSCédric Le Goater if (!aic->has_dma) { 810545d6befSCédric Le Goater qemu_log_mask(LOG_GUEST_ERROR, "%s: No DMA support\n", __func__); 811545d6befSCédric Le Goater break; 812545d6befSCédric Le Goater } 813545d6befSCédric Le Goater 8142260fc6fSJoe Komlodi bus->regs[R_I2CD_DMA_ADDR] = value & 0x3ffffffc; 815545d6befSCédric Le Goater break; 816545d6befSCédric Le Goater 8173be3d6ccSJoe Komlodi case A_I2CD_DMA_LEN: 818545d6befSCédric Le Goater if (!aic->has_dma) { 819545d6befSCédric Le Goater qemu_log_mask(LOG_GUEST_ERROR, "%s: No DMA support\n", __func__); 820545d6befSCédric Le Goater break; 821545d6befSCédric Le Goater } 822545d6befSCédric Le Goater 8232260fc6fSJoe Komlodi bus->regs[R_I2CD_DMA_LEN] = value & 0xfff; 8242260fc6fSJoe Komlodi if (!bus->regs[R_I2CD_DMA_LEN]) { 825545d6befSCédric Le Goater qemu_log_mask(LOG_UNIMP, "%s: invalid DMA length\n", __func__); 826545d6befSCédric Le Goater } 827545d6befSCédric Le Goater break; 82816020011SCédric Le Goater 82916020011SCédric Le Goater default: 83016020011SCédric Le Goater qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad offset 0x%" HWADDR_PRIx "\n", 83116020011SCédric Le Goater __func__, offset); 83216020011SCédric Le Goater } 83316020011SCédric Le Goater } 83416020011SCédric Le Goater 835ba2cccd6SJoe Komlodi static void aspeed_i2c_bus_write(void *opaque, hwaddr offset, 836ba2cccd6SJoe Komlodi uint64_t value, unsigned size) 837ba2cccd6SJoe Komlodi { 838ba2cccd6SJoe Komlodi AspeedI2CBus *bus = opaque; 839ba2cccd6SJoe Komlodi if (aspeed_i2c_is_new_mode(bus->controller)) { 840ba2cccd6SJoe Komlodi aspeed_i2c_bus_new_write(bus, offset, value, size); 841ba2cccd6SJoe Komlodi } else { 842ba2cccd6SJoe Komlodi aspeed_i2c_bus_old_write(bus, offset, value, size); 843ba2cccd6SJoe Komlodi } 844ba2cccd6SJoe Komlodi } 845ba2cccd6SJoe Komlodi 84616020011SCédric Le Goater static uint64_t aspeed_i2c_ctrl_read(void *opaque, hwaddr offset, 84716020011SCédric Le Goater unsigned size) 84816020011SCédric Le Goater { 84916020011SCédric Le Goater AspeedI2CState *s = opaque; 85016020011SCédric Le Goater 85116020011SCédric Le Goater switch (offset) { 8523be3d6ccSJoe Komlodi case A_I2C_CTRL_STATUS: 85316020011SCédric Le Goater return s->intr_status; 8543be3d6ccSJoe Komlodi case A_I2C_CTRL_GLOBAL: 855aab90b1cSCédric Le Goater return s->ctrl_global; 856ba2cccd6SJoe Komlodi case A_I2C_CTRL_NEW_CLK_DIVIDER: 857ba2cccd6SJoe Komlodi if (aspeed_i2c_is_new_mode(s)) { 858ba2cccd6SJoe Komlodi return s->new_clk_divider; 859ba2cccd6SJoe Komlodi } 860ba2cccd6SJoe Komlodi qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad offset 0x%" HWADDR_PRIx "\n", 861ba2cccd6SJoe Komlodi __func__, offset); 862ba2cccd6SJoe Komlodi break; 86316020011SCédric Le Goater default: 86416020011SCédric Le Goater qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad offset 0x%" HWADDR_PRIx "\n", 86516020011SCédric Le Goater __func__, offset); 86616020011SCédric Le Goater break; 86716020011SCédric Le Goater } 86816020011SCédric Le Goater 86916020011SCédric Le Goater return -1; 87016020011SCédric Le Goater } 87116020011SCédric Le Goater 87216020011SCédric Le Goater static void aspeed_i2c_ctrl_write(void *opaque, hwaddr offset, 87316020011SCédric Le Goater uint64_t value, unsigned size) 87416020011SCédric Le Goater { 875aab90b1cSCédric Le Goater AspeedI2CState *s = opaque; 876aab90b1cSCédric Le Goater 87716020011SCédric Le Goater switch (offset) { 8783be3d6ccSJoe Komlodi case A_I2C_CTRL_GLOBAL: 879aab90b1cSCédric Le Goater s->ctrl_global = value; 880aab90b1cSCédric Le Goater break; 881ba2cccd6SJoe Komlodi case A_I2C_CTRL_NEW_CLK_DIVIDER: 882ba2cccd6SJoe Komlodi if (aspeed_i2c_is_new_mode(s)) { 883ba2cccd6SJoe Komlodi s->new_clk_divider = value; 884ba2cccd6SJoe Komlodi } else { 885ba2cccd6SJoe Komlodi qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad offset 0x%" HWADDR_PRIx 886ba2cccd6SJoe Komlodi "\n", __func__, offset); 887ba2cccd6SJoe Komlodi } 888ba2cccd6SJoe Komlodi break; 8893be3d6ccSJoe Komlodi case A_I2C_CTRL_STATUS: 89016020011SCédric Le Goater default: 89116020011SCédric Le Goater qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad offset 0x%" HWADDR_PRIx "\n", 89216020011SCédric Le Goater __func__, offset); 89316020011SCédric Le Goater break; 89416020011SCédric Le Goater } 89516020011SCédric Le Goater } 89616020011SCédric Le Goater 89716020011SCédric Le Goater static const MemoryRegionOps aspeed_i2c_bus_ops = { 89816020011SCédric Le Goater .read = aspeed_i2c_bus_read, 89916020011SCédric Le Goater .write = aspeed_i2c_bus_write, 90016020011SCédric Le Goater .endianness = DEVICE_LITTLE_ENDIAN, 90116020011SCédric Le Goater }; 90216020011SCédric Le Goater 90316020011SCédric Le Goater static const MemoryRegionOps aspeed_i2c_ctrl_ops = { 90416020011SCédric Le Goater .read = aspeed_i2c_ctrl_read, 90516020011SCédric Le Goater .write = aspeed_i2c_ctrl_write, 90616020011SCédric Le Goater .endianness = DEVICE_LITTLE_ENDIAN, 90716020011SCédric Le Goater }; 90816020011SCédric Le Goater 9095d337540SJamin Lin static uint64_t aspeed_i2c_share_pool_read(void *opaque, hwaddr offset, 9106054fc73SCédric Le Goater unsigned size) 9116054fc73SCédric Le Goater { 9126054fc73SCédric Le Goater AspeedI2CState *s = opaque; 9136054fc73SCédric Le Goater uint64_t ret = 0; 9146054fc73SCédric Le Goater int i; 9156054fc73SCédric Le Goater 9166054fc73SCédric Le Goater for (i = 0; i < size; i++) { 9175d337540SJamin Lin ret |= (uint64_t) s->share_pool[offset + i] << (8 * i); 9186054fc73SCédric Le Goater } 9196054fc73SCédric Le Goater 9206054fc73SCédric Le Goater return ret; 9216054fc73SCédric Le Goater } 9226054fc73SCédric Le Goater 9235d337540SJamin Lin static void aspeed_i2c_share_pool_write(void *opaque, hwaddr offset, 9246054fc73SCédric Le Goater uint64_t value, unsigned size) 9256054fc73SCédric Le Goater { 9266054fc73SCédric Le Goater AspeedI2CState *s = opaque; 9276054fc73SCédric Le Goater int i; 9286054fc73SCédric Le Goater 9296054fc73SCédric Le Goater for (i = 0; i < size; i++) { 9305d337540SJamin Lin s->share_pool[offset + i] = (value >> (8 * i)) & 0xFF; 9316054fc73SCédric Le Goater } 9326054fc73SCédric Le Goater } 9336054fc73SCédric Le Goater 9345d337540SJamin Lin static const MemoryRegionOps aspeed_i2c_share_pool_ops = { 9355d337540SJamin Lin .read = aspeed_i2c_share_pool_read, 9365d337540SJamin Lin .write = aspeed_i2c_share_pool_write, 9376054fc73SCédric Le Goater .endianness = DEVICE_LITTLE_ENDIAN, 9386054fc73SCédric Le Goater .valid = { 9396054fc73SCédric Le Goater .min_access_size = 1, 9406054fc73SCédric Le Goater .max_access_size = 4, 9416054fc73SCédric Le Goater }, 9426054fc73SCédric Le Goater }; 9436054fc73SCédric Le Goater 944*62c0c65dSJamin Lin static uint64_t aspeed_i2c_bus_pool_read(void *opaque, hwaddr offset, 945*62c0c65dSJamin Lin unsigned size) 946*62c0c65dSJamin Lin { 947*62c0c65dSJamin Lin AspeedI2CBus *s = opaque; 948*62c0c65dSJamin Lin uint64_t ret = 0; 949*62c0c65dSJamin Lin int i; 950*62c0c65dSJamin Lin 951*62c0c65dSJamin Lin for (i = 0; i < size; i++) { 952*62c0c65dSJamin Lin ret |= (uint64_t) s->pool[offset + i] << (8 * i); 953*62c0c65dSJamin Lin } 954*62c0c65dSJamin Lin 955*62c0c65dSJamin Lin return ret; 956*62c0c65dSJamin Lin } 957*62c0c65dSJamin Lin 958*62c0c65dSJamin Lin static void aspeed_i2c_bus_pool_write(void *opaque, hwaddr offset, 959*62c0c65dSJamin Lin uint64_t value, unsigned size) 960*62c0c65dSJamin Lin { 961*62c0c65dSJamin Lin AspeedI2CBus *s = opaque; 962*62c0c65dSJamin Lin int i; 963*62c0c65dSJamin Lin 964*62c0c65dSJamin Lin for (i = 0; i < size; i++) { 965*62c0c65dSJamin Lin s->pool[offset + i] = (value >> (8 * i)) & 0xFF; 966*62c0c65dSJamin Lin } 967*62c0c65dSJamin Lin } 968*62c0c65dSJamin Lin 969*62c0c65dSJamin Lin static const MemoryRegionOps aspeed_i2c_bus_pool_ops = { 970*62c0c65dSJamin Lin .read = aspeed_i2c_bus_pool_read, 971*62c0c65dSJamin Lin .write = aspeed_i2c_bus_pool_write, 972*62c0c65dSJamin Lin .endianness = DEVICE_LITTLE_ENDIAN, 973*62c0c65dSJamin Lin .valid = { 974*62c0c65dSJamin Lin .min_access_size = 1, 975*62c0c65dSJamin Lin .max_access_size = 4, 976*62c0c65dSJamin Lin }, 977*62c0c65dSJamin Lin }; 978*62c0c65dSJamin Lin 97916020011SCédric Le Goater static const VMStateDescription aspeed_i2c_bus_vmstate = { 98016020011SCédric Le Goater .name = TYPE_ASPEED_I2C, 981*62c0c65dSJamin Lin .version_id = 6, 982*62c0c65dSJamin Lin .minimum_version_id = 6, 98301d9442aSRichard Henderson .fields = (const VMStateField[]) { 984ba2cccd6SJoe Komlodi VMSTATE_UINT32_ARRAY(regs, AspeedI2CBus, ASPEED_I2C_NEW_NUM_REG), 985*62c0c65dSJamin Lin VMSTATE_UINT8_ARRAY(pool, AspeedI2CBus, ASPEED_I2C_BUS_POOL_SIZE), 98616020011SCédric Le Goater VMSTATE_END_OF_LIST() 98716020011SCédric Le Goater } 98816020011SCédric Le Goater }; 98916020011SCédric Le Goater 99016020011SCédric Le Goater static const VMStateDescription aspeed_i2c_vmstate = { 99116020011SCédric Le Goater .name = TYPE_ASPEED_I2C, 9925d337540SJamin Lin .version_id = 3, 9935d337540SJamin Lin .minimum_version_id = 3, 99401d9442aSRichard Henderson .fields = (const VMStateField[]) { 99516020011SCédric Le Goater VMSTATE_UINT32(intr_status, AspeedI2CState), 99616020011SCédric Le Goater VMSTATE_STRUCT_ARRAY(busses, AspeedI2CState, 99716020011SCédric Le Goater ASPEED_I2C_NR_BUSSES, 1, aspeed_i2c_bus_vmstate, 99816020011SCédric Le Goater AspeedI2CBus), 9995d337540SJamin Lin VMSTATE_UINT8_ARRAY(share_pool, AspeedI2CState, 10005d337540SJamin Lin ASPEED_I2C_SHARE_POOL_SIZE), 100116020011SCédric Le Goater VMSTATE_END_OF_LIST() 100216020011SCédric Le Goater } 100316020011SCédric Le Goater }; 100416020011SCédric Le Goater 100516020011SCédric Le Goater static void aspeed_i2c_reset(DeviceState *dev) 100616020011SCédric Le Goater { 100716020011SCédric Le Goater AspeedI2CState *s = ASPEED_I2C(dev); 100816020011SCédric Le Goater 100916020011SCédric Le Goater s->intr_status = 0; 101060261038SCédric Le Goater } 101160261038SCédric Le Goater 101260261038SCédric Le Goater static void aspeed_i2c_instance_init(Object *obj) 101360261038SCédric Le Goater { 101460261038SCédric Le Goater AspeedI2CState *s = ASPEED_I2C(obj); 101560261038SCédric Le Goater AspeedI2CClass *aic = ASPEED_I2C_GET_CLASS(s); 101660261038SCédric Le Goater int i; 101716020011SCédric Le Goater 1018f7da1aa8SCédric Le Goater for (i = 0; i < aic->num_busses; i++) { 101960261038SCédric Le Goater object_initialize_child(obj, "bus[*]", &s->busses[i], 102060261038SCédric Le Goater TYPE_ASPEED_I2C_BUS); 102116020011SCédric Le Goater } 102216020011SCédric Le Goater } 102316020011SCédric Le Goater 102416020011SCédric Le Goater /* 1025f7da1aa8SCédric Le Goater * Address Definitions (AST2400 and AST2500) 102616020011SCédric Le Goater * 102716020011SCédric Le Goater * 0x000 ... 0x03F: Global Register 102816020011SCédric Le Goater * 0x040 ... 0x07F: Device 1 102916020011SCédric Le Goater * 0x080 ... 0x0BF: Device 2 103016020011SCédric Le Goater * 0x0C0 ... 0x0FF: Device 3 103116020011SCédric Le Goater * 0x100 ... 0x13F: Device 4 103216020011SCédric Le Goater * 0x140 ... 0x17F: Device 5 103316020011SCédric Le Goater * 0x180 ... 0x1BF: Device 6 103416020011SCédric Le Goater * 0x1C0 ... 0x1FF: Device 7 1035*62c0c65dSJamin Lin * 0x200 ... 0x20F: Device 1 buffer (AST2500 unused in linux driver) 1036*62c0c65dSJamin Lin * 0x210 ... 0x21F: Device 2 buffer 1037*62c0c65dSJamin Lin * 0x220 ... 0x22F: Device 3 buffer 1038*62c0c65dSJamin Lin * 0x230 ... 0x23F: Device 4 buffer 1039*62c0c65dSJamin Lin * 0x240 ... 0x24F: Device 5 buffer 1040*62c0c65dSJamin Lin * 0x250 ... 0x25F: Device 6 buffer 1041*62c0c65dSJamin Lin * 0x260 ... 0x26F: Device 7 buffer 1042*62c0c65dSJamin Lin * 0x270 ... 0x27F: Device 8 buffer 1043*62c0c65dSJamin Lin * 0x280 ... 0x28F: Device 9 buffer 1044*62c0c65dSJamin Lin * 0x290 ... 0x29F: Device 10 buffer 1045*62c0c65dSJamin Lin * 0x2A0 ... 0x2AF: Device 11 buffer 1046*62c0c65dSJamin Lin * 0x2B0 ... 0x2BF: Device 12 buffer 1047*62c0c65dSJamin Lin * 0x2C0 ... 0x2CF: Device 13 buffer 1048*62c0c65dSJamin Lin * 0x2D0 ... 0x2DF: Device 14 buffer 1049*62c0c65dSJamin Lin * 0x2E0 ... 0x2FF: Reserved 105016020011SCédric Le Goater * 0x300 ... 0x33F: Device 8 105116020011SCédric Le Goater * 0x340 ... 0x37F: Device 9 105216020011SCédric Le Goater * 0x380 ... 0x3BF: Device 10 105316020011SCédric Le Goater * 0x3C0 ... 0x3FF: Device 11 105416020011SCédric Le Goater * 0x400 ... 0x43F: Device 12 105516020011SCédric Le Goater * 0x440 ... 0x47F: Device 13 105616020011SCédric Le Goater * 0x480 ... 0x4BF: Device 14 10575d337540SJamin Lin * 0x800 ... 0xFFF: Buffer Pool (AST2400 unused in linux driver) 1058*62c0c65dSJamin Lin * 1059*62c0c65dSJamin Lin * Address Definitions (AST2600 and AST1030) 1060*62c0c65dSJamin Lin * 0x000 ... 0x07F: Global Register 1061*62c0c65dSJamin Lin * 0x080 ... 0x0FF: Device 1 1062*62c0c65dSJamin Lin * 0x100 ... 0x17F: Device 2 1063*62c0c65dSJamin Lin * 0x180 ... 0x1FF: Device 3 1064*62c0c65dSJamin Lin * 0x200 ... 0x27F: Device 4 1065*62c0c65dSJamin Lin * 0x280 ... 0x2FF: Device 5 1066*62c0c65dSJamin Lin * 0x300 ... 0x37F: Device 6 1067*62c0c65dSJamin Lin * 0x380 ... 0x3FF: Device 7 1068*62c0c65dSJamin Lin * 0x400 ... 0x47F: Device 8 1069*62c0c65dSJamin Lin * 0x480 ... 0x4FF: Device 9 1070*62c0c65dSJamin Lin * 0x500 ... 0x57F: Device 10 1071*62c0c65dSJamin Lin * 0x580 ... 0x5FF: Device 11 1072*62c0c65dSJamin Lin * 0x600 ... 0x67F: Device 12 1073*62c0c65dSJamin Lin * 0x680 ... 0x6FF: Device 13 1074*62c0c65dSJamin Lin * 0x700 ... 0x77F: Device 14 1075*62c0c65dSJamin Lin * 0x780 ... 0x7FF: Device 15 (15 and 16 unused in AST1030) 1076*62c0c65dSJamin Lin * 0x800 ... 0x87F: Device 16 1077*62c0c65dSJamin Lin * 0xC00 ... 0xC1F: Device 1 buffer 1078*62c0c65dSJamin Lin * 0xC20 ... 0xC3F: Device 2 buffer 1079*62c0c65dSJamin Lin * 0xC40 ... 0xC5F: Device 3 buffer 1080*62c0c65dSJamin Lin * 0xC60 ... 0xC7F: Device 4 buffer 1081*62c0c65dSJamin Lin * 0xC80 ... 0xC9F: Device 5 buffer 1082*62c0c65dSJamin Lin * 0xCA0 ... 0xCBF: Device 6 buffer 1083*62c0c65dSJamin Lin * 0xCC0 ... 0xCDF: Device 7 buffer 1084*62c0c65dSJamin Lin * 0xCE0 ... 0xCFF: Device 8 buffer 1085*62c0c65dSJamin Lin * 0xD00 ... 0xD1F: Device 9 buffer 1086*62c0c65dSJamin Lin * 0xD20 ... 0xD3F: Device 10 buffer 1087*62c0c65dSJamin Lin * 0xD40 ... 0xD5F: Device 11 buffer 1088*62c0c65dSJamin Lin * 0xD60 ... 0xD7F: Device 12 buffer 1089*62c0c65dSJamin Lin * 0xD80 ... 0xD9F: Device 13 buffer 1090*62c0c65dSJamin Lin * 0xDA0 ... 0xDBF: Device 14 buffer 1091*62c0c65dSJamin Lin * 0xDC0 ... 0xDDF: Device 15 buffer (15 and 16 unused in AST1030) 1092*62c0c65dSJamin Lin * 0xDE0 ... 0xDFF: Device 16 buffer 109316020011SCédric Le Goater */ 109416020011SCédric Le Goater static void aspeed_i2c_realize(DeviceState *dev, Error **errp) 109516020011SCédric Le Goater { 109616020011SCédric Le Goater int i; 109716020011SCédric Le Goater SysBusDevice *sbd = SYS_BUS_DEVICE(dev); 109816020011SCédric Le Goater AspeedI2CState *s = ASPEED_I2C(dev); 1099f7da1aa8SCédric Le Goater AspeedI2CClass *aic = ASPEED_I2C_GET_CLASS(s); 110094500e83SJamin Lin uint32_t reg_offset = aic->reg_size + aic->reg_gap_size; 110116020011SCédric Le Goater 110216020011SCédric Le Goater sysbus_init_irq(sbd, &s->irq); 110316020011SCédric Le Goater memory_region_init_io(&s->iomem, OBJECT(s), &aspeed_i2c_ctrl_ops, s, 1104f2202be2SJamin Lin "aspeed.i2c", aic->mem_size); 110516020011SCédric Le Goater sysbus_init_mmio(sbd, &s->iomem); 110616020011SCédric Le Goater 1107f7da1aa8SCédric Le Goater for (i = 0; i < aic->num_busses; i++) { 110860261038SCédric Le Goater Object *bus = OBJECT(&s->busses[i]); 1109f7da1aa8SCédric Le Goater int offset = i < aic->gap ? 1 : 5; 111051dd4923SCédric Le Goater 111160261038SCédric Le Goater if (!object_property_set_link(bus, "controller", OBJECT(s), errp)) { 111260261038SCédric Le Goater return; 111360261038SCédric Le Goater } 111460261038SCédric Le Goater 111560261038SCédric Le Goater if (!object_property_set_uint(bus, "bus-id", i, errp)) { 111660261038SCédric Le Goater return; 111760261038SCédric Le Goater } 111860261038SCédric Le Goater 111960261038SCédric Le Goater if (!sysbus_realize(SYS_BUS_DEVICE(bus), errp)) { 112060261038SCédric Le Goater return; 112160261038SCédric Le Goater } 112260261038SCédric Le Goater 112394500e83SJamin Lin memory_region_add_subregion(&s->iomem, reg_offset * (i + offset), 112416020011SCédric Le Goater &s->busses[i].mr); 112516020011SCédric Le Goater } 11266054fc73SCédric Le Goater 1127*62c0c65dSJamin Lin if (aic->has_share_pool) { 11285d337540SJamin Lin memory_region_init_io(&s->pool_iomem, OBJECT(s), 11295d337540SJamin Lin &aspeed_i2c_share_pool_ops, s, 11305d337540SJamin Lin "aspeed.i2c-share-pool", aic->pool_size); 1131*62c0c65dSJamin Lin memory_region_add_subregion(&s->iomem, aic->pool_base, 1132*62c0c65dSJamin Lin &s->pool_iomem); 1133*62c0c65dSJamin Lin } else { 1134*62c0c65dSJamin Lin for (i = 0; i < aic->num_busses; i++) { 1135*62c0c65dSJamin Lin memory_region_add_subregion(&s->iomem, 1136*62c0c65dSJamin Lin aic->pool_base + (aic->pool_size * i), 1137*62c0c65dSJamin Lin &s->busses[i].mr_pool); 1138*62c0c65dSJamin Lin } 1139*62c0c65dSJamin Lin } 1140545d6befSCédric Le Goater 1141545d6befSCédric Le Goater if (aic->has_dma) { 1142545d6befSCédric Le Goater if (!s->dram_mr) { 1143545d6befSCédric Le Goater error_setg(errp, TYPE_ASPEED_I2C ": 'dram' link not set"); 1144545d6befSCédric Le Goater return; 114516020011SCédric Le Goater } 114616020011SCédric Le Goater 11473f7a53b2SCédric Le Goater address_space_init(&s->dram_as, s->dram_mr, 11483f7a53b2SCédric Le Goater TYPE_ASPEED_I2C "-dma-dram"); 1149545d6befSCédric Le Goater } 1150545d6befSCédric Le Goater } 1151545d6befSCédric Le Goater 1152545d6befSCédric Le Goater static Property aspeed_i2c_properties[] = { 1153545d6befSCédric Le Goater DEFINE_PROP_LINK("dram", AspeedI2CState, dram_mr, 1154545d6befSCédric Le Goater TYPE_MEMORY_REGION, MemoryRegion *), 1155545d6befSCédric Le Goater DEFINE_PROP_END_OF_LIST(), 1156545d6befSCédric Le Goater }; 1157545d6befSCédric Le Goater 115816020011SCédric Le Goater static void aspeed_i2c_class_init(ObjectClass *klass, void *data) 115916020011SCédric Le Goater { 116016020011SCédric Le Goater DeviceClass *dc = DEVICE_CLASS(klass); 116116020011SCédric Le Goater 116216020011SCédric Le Goater dc->vmsd = &aspeed_i2c_vmstate; 1163e3d08143SPeter Maydell device_class_set_legacy_reset(dc, aspeed_i2c_reset); 11644f67d30bSMarc-André Lureau device_class_set_props(dc, aspeed_i2c_properties); 116516020011SCédric Le Goater dc->realize = aspeed_i2c_realize; 116616020011SCédric Le Goater dc->desc = "Aspeed I2C Controller"; 116716020011SCédric Le Goater } 116816020011SCédric Le Goater 116916020011SCédric Le Goater static const TypeInfo aspeed_i2c_info = { 117016020011SCédric Le Goater .name = TYPE_ASPEED_I2C, 117116020011SCédric Le Goater .parent = TYPE_SYS_BUS_DEVICE, 117260261038SCédric Le Goater .instance_init = aspeed_i2c_instance_init, 117316020011SCédric Le Goater .instance_size = sizeof(AspeedI2CState), 117416020011SCédric Le Goater .class_init = aspeed_i2c_class_init, 1175f7da1aa8SCédric Le Goater .class_size = sizeof(AspeedI2CClass), 1176f7da1aa8SCédric Le Goater .abstract = true, 1177f7da1aa8SCédric Le Goater }; 1178f7da1aa8SCédric Le Goater 11791c5d909fSPeter Delevoryas static int aspeed_i2c_bus_new_slave_event(AspeedI2CBus *bus, 11801c5d909fSPeter Delevoryas enum i2c_event event) 11811c5d909fSPeter Delevoryas { 11821c5d909fSPeter Delevoryas switch (event) { 11831c5d909fSPeter Delevoryas case I2C_START_SEND_ASYNC: 11841c5d909fSPeter Delevoryas if (!SHARED_ARRAY_FIELD_EX32(bus->regs, R_I2CS_CMD, RX_DMA_EN)) { 11851c5d909fSPeter Delevoryas qemu_log_mask(LOG_GUEST_ERROR, 11861c5d909fSPeter Delevoryas "%s: Slave mode RX DMA is not enabled\n", __func__); 11871c5d909fSPeter Delevoryas return -1; 11881c5d909fSPeter Delevoryas } 11891c5d909fSPeter Delevoryas ARRAY_FIELD_DP32(bus->regs, I2CS_DMA_LEN_STS, RX_LEN, 0); 11901c5d909fSPeter Delevoryas bus->regs[R_I2CC_DMA_ADDR] = 11911c5d909fSPeter Delevoryas ARRAY_FIELD_EX32(bus->regs, I2CS_DMA_RX_ADDR, ADDR); 11921c5d909fSPeter Delevoryas bus->regs[R_I2CC_DMA_LEN] = 11931c5d909fSPeter Delevoryas ARRAY_FIELD_EX32(bus->regs, I2CS_DMA_LEN, RX_BUF_LEN) + 1; 11941c5d909fSPeter Delevoryas i2c_ack(bus->bus); 11951c5d909fSPeter Delevoryas break; 11961c5d909fSPeter Delevoryas case I2C_FINISH: 11971c5d909fSPeter Delevoryas ARRAY_FIELD_DP32(bus->regs, I2CS_INTR_STS, PKT_CMD_DONE, 1); 11981c5d909fSPeter Delevoryas ARRAY_FIELD_DP32(bus->regs, I2CS_INTR_STS, SLAVE_ADDR_RX_MATCH, 1); 11991c5d909fSPeter Delevoryas SHARED_ARRAY_FIELD_DP32(bus->regs, R_I2CS_INTR_STS, NORMAL_STOP, 1); 12001c5d909fSPeter Delevoryas SHARED_ARRAY_FIELD_DP32(bus->regs, R_I2CS_INTR_STS, RX_DONE, 1); 12011c5d909fSPeter Delevoryas aspeed_i2c_bus_raise_slave_interrupt(bus); 12021c5d909fSPeter Delevoryas break; 12031c5d909fSPeter Delevoryas default: 12041c5d909fSPeter Delevoryas qemu_log_mask(LOG_UNIMP, "%s: i2c event %d unimplemented\n", 12051c5d909fSPeter Delevoryas __func__, event); 12061c5d909fSPeter Delevoryas return -1; 12071c5d909fSPeter Delevoryas } 12081c5d909fSPeter Delevoryas 12091c5d909fSPeter Delevoryas return 0; 12101c5d909fSPeter Delevoryas } 12111c5d909fSPeter Delevoryas 1212a8d48f59SKlaus Jensen static int aspeed_i2c_bus_slave_event(I2CSlave *slave, enum i2c_event event) 1213a8d48f59SKlaus Jensen { 1214a8d48f59SKlaus Jensen BusState *qbus = qdev_get_parent_bus(DEVICE(slave)); 1215a8d48f59SKlaus Jensen AspeedI2CBus *bus = ASPEED_I2C_BUS(qbus->parent); 1216a8d48f59SKlaus Jensen uint32_t reg_intr_sts = aspeed_i2c_bus_intr_sts_offset(bus); 1217a8d48f59SKlaus Jensen uint32_t reg_byte_buf = aspeed_i2c_bus_byte_buf_offset(bus); 12183648d31fSPeter Delevoryas uint32_t reg_dev_addr = aspeed_i2c_bus_dev_addr_offset(bus); 12193648d31fSPeter Delevoryas uint32_t dev_addr = SHARED_ARRAY_FIELD_EX32(bus->regs, reg_dev_addr, 12203648d31fSPeter Delevoryas SLAVE_DEV_ADDR1); 1221a8d48f59SKlaus Jensen 12221c5d909fSPeter Delevoryas if (aspeed_i2c_is_new_mode(bus->controller)) { 12231c5d909fSPeter Delevoryas return aspeed_i2c_bus_new_slave_event(bus, event); 12241c5d909fSPeter Delevoryas } 12251c5d909fSPeter Delevoryas 1226a8d48f59SKlaus Jensen switch (event) { 1227a8d48f59SKlaus Jensen case I2C_START_SEND_ASYNC: 12283648d31fSPeter Delevoryas /* Bit[0] == 0 indicates "send". */ 12293648d31fSPeter Delevoryas SHARED_ARRAY_FIELD_DP32(bus->regs, reg_byte_buf, RX_BUF, dev_addr << 1); 1230a8d48f59SKlaus Jensen 1231a8d48f59SKlaus Jensen ARRAY_FIELD_DP32(bus->regs, I2CD_INTR_STS, SLAVE_ADDR_RX_MATCH, 1); 1232a8d48f59SKlaus Jensen SHARED_ARRAY_FIELD_DP32(bus->regs, reg_intr_sts, RX_DONE, 1); 1233a8d48f59SKlaus Jensen 1234a8d48f59SKlaus Jensen aspeed_i2c_set_state(bus, I2CD_STXD); 1235a8d48f59SKlaus Jensen 1236a8d48f59SKlaus Jensen break; 1237a8d48f59SKlaus Jensen 1238a8d48f59SKlaus Jensen case I2C_FINISH: 1239a8d48f59SKlaus Jensen SHARED_ARRAY_FIELD_DP32(bus->regs, reg_intr_sts, NORMAL_STOP, 1); 1240a8d48f59SKlaus Jensen 1241a8d48f59SKlaus Jensen aspeed_i2c_set_state(bus, I2CD_IDLE); 1242a8d48f59SKlaus Jensen 1243a8d48f59SKlaus Jensen break; 1244a8d48f59SKlaus Jensen 1245a8d48f59SKlaus Jensen default: 1246a8d48f59SKlaus Jensen return -1; 1247a8d48f59SKlaus Jensen } 1248a8d48f59SKlaus Jensen 1249a8d48f59SKlaus Jensen aspeed_i2c_bus_raise_interrupt(bus); 1250a8d48f59SKlaus Jensen 1251a8d48f59SKlaus Jensen return 0; 1252a8d48f59SKlaus Jensen } 1253a8d48f59SKlaus Jensen 12541c5d909fSPeter Delevoryas static void aspeed_i2c_bus_new_slave_send_async(AspeedI2CBus *bus, uint8_t data) 12551c5d909fSPeter Delevoryas { 12561c5d909fSPeter Delevoryas assert(address_space_write(&bus->controller->dram_as, 12571c5d909fSPeter Delevoryas bus->regs[R_I2CC_DMA_ADDR], 12581c5d909fSPeter Delevoryas MEMTXATTRS_UNSPECIFIED, &data, 1) == MEMTX_OK); 12591c5d909fSPeter Delevoryas 12601c5d909fSPeter Delevoryas bus->regs[R_I2CC_DMA_ADDR]++; 12611c5d909fSPeter Delevoryas bus->regs[R_I2CC_DMA_LEN]--; 12621c5d909fSPeter Delevoryas ARRAY_FIELD_DP32(bus->regs, I2CS_DMA_LEN_STS, RX_LEN, 12631c5d909fSPeter Delevoryas ARRAY_FIELD_EX32(bus->regs, I2CS_DMA_LEN_STS, RX_LEN) + 1); 12641c5d909fSPeter Delevoryas i2c_ack(bus->bus); 12651c5d909fSPeter Delevoryas } 12661c5d909fSPeter Delevoryas 1267a8d48f59SKlaus Jensen static void aspeed_i2c_bus_slave_send_async(I2CSlave *slave, uint8_t data) 1268a8d48f59SKlaus Jensen { 1269a8d48f59SKlaus Jensen BusState *qbus = qdev_get_parent_bus(DEVICE(slave)); 1270a8d48f59SKlaus Jensen AspeedI2CBus *bus = ASPEED_I2C_BUS(qbus->parent); 1271a8d48f59SKlaus Jensen uint32_t reg_intr_sts = aspeed_i2c_bus_intr_sts_offset(bus); 1272a8d48f59SKlaus Jensen uint32_t reg_byte_buf = aspeed_i2c_bus_byte_buf_offset(bus); 1273a8d48f59SKlaus Jensen 12741c5d909fSPeter Delevoryas if (aspeed_i2c_is_new_mode(bus->controller)) { 12751c5d909fSPeter Delevoryas return aspeed_i2c_bus_new_slave_send_async(bus, data); 12761c5d909fSPeter Delevoryas } 12771c5d909fSPeter Delevoryas 1278a8d48f59SKlaus Jensen SHARED_ARRAY_FIELD_DP32(bus->regs, reg_byte_buf, RX_BUF, data); 1279a8d48f59SKlaus Jensen SHARED_ARRAY_FIELD_DP32(bus->regs, reg_intr_sts, RX_DONE, 1); 1280a8d48f59SKlaus Jensen 1281a8d48f59SKlaus Jensen aspeed_i2c_bus_raise_interrupt(bus); 1282a8d48f59SKlaus Jensen } 1283a8d48f59SKlaus Jensen 1284a8d48f59SKlaus Jensen static void aspeed_i2c_bus_slave_class_init(ObjectClass *klass, void *data) 1285a8d48f59SKlaus Jensen { 1286a8d48f59SKlaus Jensen DeviceClass *dc = DEVICE_CLASS(klass); 1287a8d48f59SKlaus Jensen I2CSlaveClass *sc = I2C_SLAVE_CLASS(klass); 1288a8d48f59SKlaus Jensen 1289a8d48f59SKlaus Jensen dc->desc = "Aspeed I2C Bus Slave"; 1290a8d48f59SKlaus Jensen 1291a8d48f59SKlaus Jensen sc->event = aspeed_i2c_bus_slave_event; 1292a8d48f59SKlaus Jensen sc->send_async = aspeed_i2c_bus_slave_send_async; 1293a8d48f59SKlaus Jensen } 1294a8d48f59SKlaus Jensen 1295a8d48f59SKlaus Jensen static const TypeInfo aspeed_i2c_bus_slave_info = { 1296a8d48f59SKlaus Jensen .name = TYPE_ASPEED_I2C_BUS_SLAVE, 1297a8d48f59SKlaus Jensen .parent = TYPE_I2C_SLAVE, 1298a8d48f59SKlaus Jensen .instance_size = sizeof(AspeedI2CBusSlave), 1299a8d48f59SKlaus Jensen .class_init = aspeed_i2c_bus_slave_class_init, 1300a8d48f59SKlaus Jensen }; 1301a8d48f59SKlaus Jensen 130260261038SCédric Le Goater static void aspeed_i2c_bus_reset(DeviceState *dev) 130360261038SCédric Le Goater { 130460261038SCédric Le Goater AspeedI2CBus *s = ASPEED_I2C_BUS(dev); 130560261038SCédric Le Goater 13062260fc6fSJoe Komlodi memset(s->regs, 0, sizeof(s->regs)); 130760261038SCédric Le Goater i2c_end_transfer(s->bus); 130860261038SCédric Le Goater } 130960261038SCédric Le Goater 131060261038SCédric Le Goater static void aspeed_i2c_bus_realize(DeviceState *dev, Error **errp) 131160261038SCédric Le Goater { 131260261038SCédric Le Goater AspeedI2CBus *s = ASPEED_I2C_BUS(dev); 131360261038SCédric Le Goater AspeedI2CClass *aic; 131460261038SCédric Le Goater g_autofree char *name = g_strdup_printf(TYPE_ASPEED_I2C_BUS ".%d", s->id); 1315*62c0c65dSJamin Lin g_autofree char *pool_name = g_strdup_printf("%s.pool", name); 131660261038SCédric Le Goater 131760261038SCédric Le Goater if (!s->controller) { 131860261038SCédric Le Goater error_setg(errp, TYPE_ASPEED_I2C_BUS ": 'controller' link not set"); 131960261038SCédric Le Goater return; 132060261038SCédric Le Goater } 132160261038SCédric Le Goater 132260261038SCédric Le Goater aic = ASPEED_I2C_GET_CLASS(s->controller); 132360261038SCédric Le Goater 132460261038SCédric Le Goater sysbus_init_irq(SYS_BUS_DEVICE(dev), &s->irq); 132560261038SCédric Le Goater 132660261038SCédric Le Goater s->bus = i2c_init_bus(dev, name); 1327a8d48f59SKlaus Jensen s->slave = i2c_slave_create_simple(s->bus, TYPE_ASPEED_I2C_BUS_SLAVE, 1328a8d48f59SKlaus Jensen 0xff); 132960261038SCédric Le Goater 133060261038SCédric Le Goater memory_region_init_io(&s->mr, OBJECT(s), &aspeed_i2c_bus_ops, 133160261038SCédric Le Goater s, name, aic->reg_size); 133260261038SCédric Le Goater sysbus_init_mmio(SYS_BUS_DEVICE(dev), &s->mr); 1333*62c0c65dSJamin Lin 1334*62c0c65dSJamin Lin memory_region_init_io(&s->mr_pool, OBJECT(s), &aspeed_i2c_bus_pool_ops, 1335*62c0c65dSJamin Lin s, pool_name, aic->pool_size); 1336*62c0c65dSJamin Lin sysbus_init_mmio(SYS_BUS_DEVICE(dev), &s->mr_pool); 133760261038SCédric Le Goater } 133860261038SCédric Le Goater 133960261038SCédric Le Goater static Property aspeed_i2c_bus_properties[] = { 134060261038SCédric Le Goater DEFINE_PROP_UINT8("bus-id", AspeedI2CBus, id, 0), 134160261038SCédric Le Goater DEFINE_PROP_LINK("controller", AspeedI2CBus, controller, TYPE_ASPEED_I2C, 134260261038SCédric Le Goater AspeedI2CState *), 134360261038SCédric Le Goater DEFINE_PROP_END_OF_LIST(), 134460261038SCédric Le Goater }; 134560261038SCédric Le Goater 134660261038SCédric Le Goater static void aspeed_i2c_bus_class_init(ObjectClass *klass, void *data) 134760261038SCédric Le Goater { 134860261038SCédric Le Goater DeviceClass *dc = DEVICE_CLASS(klass); 134960261038SCédric Le Goater 135060261038SCédric Le Goater dc->desc = "Aspeed I2C Bus"; 135160261038SCédric Le Goater dc->realize = aspeed_i2c_bus_realize; 1352e3d08143SPeter Maydell device_class_set_legacy_reset(dc, aspeed_i2c_bus_reset); 135360261038SCédric Le Goater device_class_set_props(dc, aspeed_i2c_bus_properties); 135460261038SCédric Le Goater } 135560261038SCédric Le Goater 135660261038SCédric Le Goater static const TypeInfo aspeed_i2c_bus_info = { 135760261038SCédric Le Goater .name = TYPE_ASPEED_I2C_BUS, 135860261038SCédric Le Goater .parent = TYPE_SYS_BUS_DEVICE, 135960261038SCédric Le Goater .instance_size = sizeof(AspeedI2CBus), 136060261038SCédric Le Goater .class_init = aspeed_i2c_bus_class_init, 136160261038SCédric Le Goater }; 136260261038SCédric Le Goater 136351dd4923SCédric Le Goater static qemu_irq aspeed_2400_i2c_bus_get_irq(AspeedI2CBus *bus) 136451dd4923SCédric Le Goater { 136551dd4923SCédric Le Goater return bus->controller->irq; 136651dd4923SCédric Le Goater } 136751dd4923SCédric Le Goater 13686054fc73SCédric Le Goater static uint8_t *aspeed_2400_i2c_bus_pool_base(AspeedI2CBus *bus) 13696054fc73SCédric Le Goater { 13706054fc73SCédric Le Goater uint8_t *pool_page = 13715d337540SJamin Lin &bus->controller->share_pool[ARRAY_FIELD_EX32(bus->regs, 13725d337540SJamin Lin I2CD_FUN_CTRL, 13733be3d6ccSJoe Komlodi POOL_PAGE_SEL) * 0x100]; 13746054fc73SCédric Le Goater 13752260fc6fSJoe Komlodi return &pool_page[ARRAY_FIELD_EX32(bus->regs, I2CD_POOL_CTRL, OFFSET)]; 13766054fc73SCédric Le Goater } 13776054fc73SCédric Le Goater 1378f7da1aa8SCédric Le Goater static void aspeed_2400_i2c_class_init(ObjectClass *klass, void *data) 1379f7da1aa8SCédric Le Goater { 1380f7da1aa8SCédric Le Goater DeviceClass *dc = DEVICE_CLASS(klass); 1381f7da1aa8SCédric Le Goater AspeedI2CClass *aic = ASPEED_I2C_CLASS(klass); 1382f7da1aa8SCédric Le Goater 1383f7da1aa8SCédric Le Goater dc->desc = "ASPEED 2400 I2C Controller"; 1384f7da1aa8SCédric Le Goater 1385f7da1aa8SCédric Le Goater aic->num_busses = 14; 1386f7da1aa8SCédric Le Goater aic->reg_size = 0x40; 1387f7da1aa8SCédric Le Goater aic->gap = 7; 138851dd4923SCédric Le Goater aic->bus_get_irq = aspeed_2400_i2c_bus_get_irq; 1389*62c0c65dSJamin Lin aic->has_share_pool = true; 13906054fc73SCédric Le Goater aic->pool_size = 0x800; 13916054fc73SCédric Le Goater aic->pool_base = 0x800; 13926054fc73SCédric Le Goater aic->bus_pool_base = aspeed_2400_i2c_bus_pool_base; 1393f2202be2SJamin Lin aic->mem_size = 0x1000; 1394f7da1aa8SCédric Le Goater } 1395f7da1aa8SCédric Le Goater 1396f7da1aa8SCédric Le Goater static const TypeInfo aspeed_2400_i2c_info = { 1397f7da1aa8SCédric Le Goater .name = TYPE_ASPEED_2400_I2C, 1398f7da1aa8SCédric Le Goater .parent = TYPE_ASPEED_I2C, 1399f7da1aa8SCédric Le Goater .class_init = aspeed_2400_i2c_class_init, 1400f7da1aa8SCédric Le Goater }; 1401f7da1aa8SCédric Le Goater 140251dd4923SCédric Le Goater static qemu_irq aspeed_2500_i2c_bus_get_irq(AspeedI2CBus *bus) 140351dd4923SCédric Le Goater { 140451dd4923SCédric Le Goater return bus->controller->irq; 140551dd4923SCédric Le Goater } 140651dd4923SCédric Le Goater 14076054fc73SCédric Le Goater static uint8_t *aspeed_2500_i2c_bus_pool_base(AspeedI2CBus *bus) 14086054fc73SCédric Le Goater { 1409*62c0c65dSJamin Lin return bus->pool; 14106054fc73SCédric Le Goater } 14116054fc73SCédric Le Goater 1412f7da1aa8SCédric Le Goater static void aspeed_2500_i2c_class_init(ObjectClass *klass, void *data) 1413f7da1aa8SCédric Le Goater { 1414f7da1aa8SCédric Le Goater DeviceClass *dc = DEVICE_CLASS(klass); 1415f7da1aa8SCédric Le Goater AspeedI2CClass *aic = ASPEED_I2C_CLASS(klass); 1416f7da1aa8SCédric Le Goater 1417f7da1aa8SCédric Le Goater dc->desc = "ASPEED 2500 I2C Controller"; 1418f7da1aa8SCédric Le Goater 1419f7da1aa8SCédric Le Goater aic->num_busses = 14; 1420f7da1aa8SCédric Le Goater aic->reg_size = 0x40; 1421f7da1aa8SCédric Le Goater aic->gap = 7; 142251dd4923SCédric Le Goater aic->bus_get_irq = aspeed_2500_i2c_bus_get_irq; 1423*62c0c65dSJamin Lin aic->pool_size = 0x10; 14246054fc73SCédric Le Goater aic->pool_base = 0x200; 14256054fc73SCédric Le Goater aic->bus_pool_base = aspeed_2500_i2c_bus_pool_base; 1426aab90b1cSCédric Le Goater aic->check_sram = true; 1427545d6befSCédric Le Goater aic->has_dma = true; 1428f2202be2SJamin Lin aic->mem_size = 0x1000; 1429f7da1aa8SCédric Le Goater } 1430f7da1aa8SCédric Le Goater 1431f7da1aa8SCédric Le Goater static const TypeInfo aspeed_2500_i2c_info = { 1432f7da1aa8SCédric Le Goater .name = TYPE_ASPEED_2500_I2C, 1433f7da1aa8SCédric Le Goater .parent = TYPE_ASPEED_I2C, 1434f7da1aa8SCédric Le Goater .class_init = aspeed_2500_i2c_class_init, 143516020011SCédric Le Goater }; 143616020011SCédric Le Goater 143751dd4923SCédric Le Goater static qemu_irq aspeed_2600_i2c_bus_get_irq(AspeedI2CBus *bus) 143851dd4923SCédric Le Goater { 143951dd4923SCédric Le Goater return bus->irq; 144051dd4923SCédric Le Goater } 144151dd4923SCédric Le Goater 144251dd4923SCédric Le Goater static void aspeed_2600_i2c_class_init(ObjectClass *klass, void *data) 144351dd4923SCédric Le Goater { 144451dd4923SCédric Le Goater DeviceClass *dc = DEVICE_CLASS(klass); 144551dd4923SCédric Le Goater AspeedI2CClass *aic = ASPEED_I2C_CLASS(klass); 144651dd4923SCédric Le Goater 144751dd4923SCédric Le Goater dc->desc = "ASPEED 2600 I2C Controller"; 144851dd4923SCédric Le Goater 144951dd4923SCédric Le Goater aic->num_busses = 16; 145051dd4923SCédric Le Goater aic->reg_size = 0x80; 145151dd4923SCédric Le Goater aic->gap = -1; /* no gap */ 145251dd4923SCédric Le Goater aic->bus_get_irq = aspeed_2600_i2c_bus_get_irq; 1453*62c0c65dSJamin Lin aic->pool_size = 0x20; 14546054fc73SCédric Le Goater aic->pool_base = 0xC00; 1455*62c0c65dSJamin Lin aic->bus_pool_base = aspeed_2500_i2c_bus_pool_base; 1456545d6befSCédric Le Goater aic->has_dma = true; 1457f2202be2SJamin Lin aic->mem_size = 0x1000; 145851dd4923SCédric Le Goater } 145951dd4923SCédric Le Goater 146051dd4923SCédric Le Goater static const TypeInfo aspeed_2600_i2c_info = { 146151dd4923SCédric Le Goater .name = TYPE_ASPEED_2600_I2C, 146251dd4923SCédric Le Goater .parent = TYPE_ASPEED_I2C, 146351dd4923SCédric Le Goater .class_init = aspeed_2600_i2c_class_init, 146451dd4923SCédric Le Goater }; 146551dd4923SCédric Le Goater 1466b35802ceSCédric Le Goater static void aspeed_1030_i2c_class_init(ObjectClass *klass, void *data) 1467b35802ceSCédric Le Goater { 1468b35802ceSCédric Le Goater DeviceClass *dc = DEVICE_CLASS(klass); 1469b35802ceSCédric Le Goater AspeedI2CClass *aic = ASPEED_I2C_CLASS(klass); 1470b35802ceSCédric Le Goater 1471b35802ceSCédric Le Goater dc->desc = "ASPEED 1030 I2C Controller"; 1472b35802ceSCédric Le Goater 1473b35802ceSCédric Le Goater aic->num_busses = 14; 1474b35802ceSCédric Le Goater aic->reg_size = 0x80; 1475b35802ceSCédric Le Goater aic->gap = -1; /* no gap */ 1476b35802ceSCédric Le Goater aic->bus_get_irq = aspeed_2600_i2c_bus_get_irq; 1477*62c0c65dSJamin Lin aic->pool_size = 0x20; 1478b35802ceSCédric Le Goater aic->pool_base = 0xC00; 1479*62c0c65dSJamin Lin aic->bus_pool_base = aspeed_2500_i2c_bus_pool_base; 1480b35802ceSCédric Le Goater aic->has_dma = true; 1481f2202be2SJamin Lin aic->mem_size = 0x10000; 1482b35802ceSCédric Le Goater } 1483b35802ceSCédric Le Goater 1484b35802ceSCédric Le Goater static const TypeInfo aspeed_1030_i2c_info = { 1485b35802ceSCédric Le Goater .name = TYPE_ASPEED_1030_I2C, 1486b35802ceSCédric Le Goater .parent = TYPE_ASPEED_I2C, 1487b35802ceSCédric Le Goater .class_init = aspeed_1030_i2c_class_init, 1488b35802ceSCédric Le Goater }; 1489b35802ceSCédric Le Goater 149016020011SCédric Le Goater static void aspeed_i2c_register_types(void) 149116020011SCédric Le Goater { 149260261038SCédric Le Goater type_register_static(&aspeed_i2c_bus_info); 1493a8d48f59SKlaus Jensen type_register_static(&aspeed_i2c_bus_slave_info); 149416020011SCédric Le Goater type_register_static(&aspeed_i2c_info); 1495f7da1aa8SCédric Le Goater type_register_static(&aspeed_2400_i2c_info); 1496f7da1aa8SCédric Le Goater type_register_static(&aspeed_2500_i2c_info); 149751dd4923SCédric Le Goater type_register_static(&aspeed_2600_i2c_info); 1498b35802ceSCédric Le Goater type_register_static(&aspeed_1030_i2c_info); 149916020011SCédric Le Goater } 150016020011SCédric Le Goater 150116020011SCédric Le Goater type_init(aspeed_i2c_register_types) 150216020011SCédric Le Goater 150316020011SCédric Le Goater 15047a204cbdSPhilippe Mathieu-Daudé I2CBus *aspeed_i2c_get_bus(AspeedI2CState *s, int busnr) 150516020011SCédric Le Goater { 1506f7da1aa8SCédric Le Goater AspeedI2CClass *aic = ASPEED_I2C_GET_CLASS(s); 150716020011SCédric Le Goater I2CBus *bus = NULL; 150816020011SCédric Le Goater 1509f7da1aa8SCédric Le Goater if (busnr >= 0 && busnr < aic->num_busses) { 151016020011SCédric Le Goater bus = s->busses[busnr].bus; 151116020011SCédric Le Goater } 151216020011SCédric Le Goater 151316020011SCédric Le Goater return bus; 151416020011SCédric Le Goater } 1515