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 909*5d337540SJamin 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++) { 917*5d337540SJamin 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 923*5d337540SJamin 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++) { 930*5d337540SJamin Lin s->share_pool[offset + i] = (value >> (8 * i)) & 0xFF; 9316054fc73SCédric Le Goater } 9326054fc73SCédric Le Goater } 9336054fc73SCédric Le Goater 934*5d337540SJamin Lin static const MemoryRegionOps aspeed_i2c_share_pool_ops = { 935*5d337540SJamin Lin .read = aspeed_i2c_share_pool_read, 936*5d337540SJamin 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 94416020011SCédric Le Goater static const VMStateDescription aspeed_i2c_bus_vmstate = { 94516020011SCédric Le Goater .name = TYPE_ASPEED_I2C, 946ba2cccd6SJoe Komlodi .version_id = 5, 947ba2cccd6SJoe Komlodi .minimum_version_id = 5, 94801d9442aSRichard Henderson .fields = (const VMStateField[]) { 949ba2cccd6SJoe Komlodi VMSTATE_UINT32_ARRAY(regs, AspeedI2CBus, ASPEED_I2C_NEW_NUM_REG), 95016020011SCédric Le Goater VMSTATE_END_OF_LIST() 95116020011SCédric Le Goater } 95216020011SCédric Le Goater }; 95316020011SCédric Le Goater 95416020011SCédric Le Goater static const VMStateDescription aspeed_i2c_vmstate = { 95516020011SCédric Le Goater .name = TYPE_ASPEED_I2C, 956*5d337540SJamin Lin .version_id = 3, 957*5d337540SJamin Lin .minimum_version_id = 3, 95801d9442aSRichard Henderson .fields = (const VMStateField[]) { 95916020011SCédric Le Goater VMSTATE_UINT32(intr_status, AspeedI2CState), 96016020011SCédric Le Goater VMSTATE_STRUCT_ARRAY(busses, AspeedI2CState, 96116020011SCédric Le Goater ASPEED_I2C_NR_BUSSES, 1, aspeed_i2c_bus_vmstate, 96216020011SCédric Le Goater AspeedI2CBus), 963*5d337540SJamin Lin VMSTATE_UINT8_ARRAY(share_pool, AspeedI2CState, 964*5d337540SJamin Lin ASPEED_I2C_SHARE_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 999*5d337540SJamin Lin * 0x200 ... 0x2FF: Buffer Pool (AST2500 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 1007*5d337540SJamin Lin * 0x800 ... 0xFFF: Buffer Pool (AST2400 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, 1018f2202be2SJamin Lin "aspeed.i2c", aic->mem_size); 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 1041*5d337540SJamin Lin memory_region_init_io(&s->pool_iomem, OBJECT(s), 1042*5d337540SJamin Lin &aspeed_i2c_share_pool_ops, s, 1043*5d337540SJamin Lin "aspeed.i2c-share-pool", aic->pool_size); 10446054fc73SCédric Le Goater memory_region_add_subregion(&s->iomem, aic->pool_base, &s->pool_iomem); 1045545d6befSCédric Le Goater 1046545d6befSCédric Le Goater if (aic->has_dma) { 1047545d6befSCédric Le Goater if (!s->dram_mr) { 1048545d6befSCédric Le Goater error_setg(errp, TYPE_ASPEED_I2C ": 'dram' link not set"); 1049545d6befSCédric Le Goater return; 105016020011SCédric Le Goater } 105116020011SCédric Le Goater 10523f7a53b2SCédric Le Goater address_space_init(&s->dram_as, s->dram_mr, 10533f7a53b2SCédric Le Goater TYPE_ASPEED_I2C "-dma-dram"); 1054545d6befSCédric Le Goater } 1055545d6befSCédric Le Goater } 1056545d6befSCédric Le Goater 1057545d6befSCédric Le Goater static Property aspeed_i2c_properties[] = { 1058545d6befSCédric Le Goater DEFINE_PROP_LINK("dram", AspeedI2CState, dram_mr, 1059545d6befSCédric Le Goater TYPE_MEMORY_REGION, MemoryRegion *), 1060545d6befSCédric Le Goater DEFINE_PROP_END_OF_LIST(), 1061545d6befSCédric Le Goater }; 1062545d6befSCédric Le Goater 106316020011SCédric Le Goater static void aspeed_i2c_class_init(ObjectClass *klass, void *data) 106416020011SCédric Le Goater { 106516020011SCédric Le Goater DeviceClass *dc = DEVICE_CLASS(klass); 106616020011SCédric Le Goater 106716020011SCédric Le Goater dc->vmsd = &aspeed_i2c_vmstate; 106816020011SCédric Le Goater dc->reset = aspeed_i2c_reset; 10694f67d30bSMarc-André Lureau device_class_set_props(dc, aspeed_i2c_properties); 107016020011SCédric Le Goater dc->realize = aspeed_i2c_realize; 107116020011SCédric Le Goater dc->desc = "Aspeed I2C Controller"; 107216020011SCédric Le Goater } 107316020011SCédric Le Goater 107416020011SCédric Le Goater static const TypeInfo aspeed_i2c_info = { 107516020011SCédric Le Goater .name = TYPE_ASPEED_I2C, 107616020011SCédric Le Goater .parent = TYPE_SYS_BUS_DEVICE, 107760261038SCédric Le Goater .instance_init = aspeed_i2c_instance_init, 107816020011SCédric Le Goater .instance_size = sizeof(AspeedI2CState), 107916020011SCédric Le Goater .class_init = aspeed_i2c_class_init, 1080f7da1aa8SCédric Le Goater .class_size = sizeof(AspeedI2CClass), 1081f7da1aa8SCédric Le Goater .abstract = true, 1082f7da1aa8SCédric Le Goater }; 1083f7da1aa8SCédric Le Goater 10841c5d909fSPeter Delevoryas static int aspeed_i2c_bus_new_slave_event(AspeedI2CBus *bus, 10851c5d909fSPeter Delevoryas enum i2c_event event) 10861c5d909fSPeter Delevoryas { 10871c5d909fSPeter Delevoryas switch (event) { 10881c5d909fSPeter Delevoryas case I2C_START_SEND_ASYNC: 10891c5d909fSPeter Delevoryas if (!SHARED_ARRAY_FIELD_EX32(bus->regs, R_I2CS_CMD, RX_DMA_EN)) { 10901c5d909fSPeter Delevoryas qemu_log_mask(LOG_GUEST_ERROR, 10911c5d909fSPeter Delevoryas "%s: Slave mode RX DMA is not enabled\n", __func__); 10921c5d909fSPeter Delevoryas return -1; 10931c5d909fSPeter Delevoryas } 10941c5d909fSPeter Delevoryas ARRAY_FIELD_DP32(bus->regs, I2CS_DMA_LEN_STS, RX_LEN, 0); 10951c5d909fSPeter Delevoryas bus->regs[R_I2CC_DMA_ADDR] = 10961c5d909fSPeter Delevoryas ARRAY_FIELD_EX32(bus->regs, I2CS_DMA_RX_ADDR, ADDR); 10971c5d909fSPeter Delevoryas bus->regs[R_I2CC_DMA_LEN] = 10981c5d909fSPeter Delevoryas ARRAY_FIELD_EX32(bus->regs, I2CS_DMA_LEN, RX_BUF_LEN) + 1; 10991c5d909fSPeter Delevoryas i2c_ack(bus->bus); 11001c5d909fSPeter Delevoryas break; 11011c5d909fSPeter Delevoryas case I2C_FINISH: 11021c5d909fSPeter Delevoryas ARRAY_FIELD_DP32(bus->regs, I2CS_INTR_STS, PKT_CMD_DONE, 1); 11031c5d909fSPeter Delevoryas ARRAY_FIELD_DP32(bus->regs, I2CS_INTR_STS, SLAVE_ADDR_RX_MATCH, 1); 11041c5d909fSPeter Delevoryas SHARED_ARRAY_FIELD_DP32(bus->regs, R_I2CS_INTR_STS, NORMAL_STOP, 1); 11051c5d909fSPeter Delevoryas SHARED_ARRAY_FIELD_DP32(bus->regs, R_I2CS_INTR_STS, RX_DONE, 1); 11061c5d909fSPeter Delevoryas aspeed_i2c_bus_raise_slave_interrupt(bus); 11071c5d909fSPeter Delevoryas break; 11081c5d909fSPeter Delevoryas default: 11091c5d909fSPeter Delevoryas qemu_log_mask(LOG_UNIMP, "%s: i2c event %d unimplemented\n", 11101c5d909fSPeter Delevoryas __func__, event); 11111c5d909fSPeter Delevoryas return -1; 11121c5d909fSPeter Delevoryas } 11131c5d909fSPeter Delevoryas 11141c5d909fSPeter Delevoryas return 0; 11151c5d909fSPeter Delevoryas } 11161c5d909fSPeter Delevoryas 1117a8d48f59SKlaus Jensen static int aspeed_i2c_bus_slave_event(I2CSlave *slave, enum i2c_event event) 1118a8d48f59SKlaus Jensen { 1119a8d48f59SKlaus Jensen BusState *qbus = qdev_get_parent_bus(DEVICE(slave)); 1120a8d48f59SKlaus Jensen AspeedI2CBus *bus = ASPEED_I2C_BUS(qbus->parent); 1121a8d48f59SKlaus Jensen uint32_t reg_intr_sts = aspeed_i2c_bus_intr_sts_offset(bus); 1122a8d48f59SKlaus Jensen uint32_t reg_byte_buf = aspeed_i2c_bus_byte_buf_offset(bus); 11233648d31fSPeter Delevoryas uint32_t reg_dev_addr = aspeed_i2c_bus_dev_addr_offset(bus); 11243648d31fSPeter Delevoryas uint32_t dev_addr = SHARED_ARRAY_FIELD_EX32(bus->regs, reg_dev_addr, 11253648d31fSPeter Delevoryas SLAVE_DEV_ADDR1); 1126a8d48f59SKlaus Jensen 11271c5d909fSPeter Delevoryas if (aspeed_i2c_is_new_mode(bus->controller)) { 11281c5d909fSPeter Delevoryas return aspeed_i2c_bus_new_slave_event(bus, event); 11291c5d909fSPeter Delevoryas } 11301c5d909fSPeter Delevoryas 1131a8d48f59SKlaus Jensen switch (event) { 1132a8d48f59SKlaus Jensen case I2C_START_SEND_ASYNC: 11333648d31fSPeter Delevoryas /* Bit[0] == 0 indicates "send". */ 11343648d31fSPeter Delevoryas SHARED_ARRAY_FIELD_DP32(bus->regs, reg_byte_buf, RX_BUF, dev_addr << 1); 1135a8d48f59SKlaus Jensen 1136a8d48f59SKlaus Jensen ARRAY_FIELD_DP32(bus->regs, I2CD_INTR_STS, SLAVE_ADDR_RX_MATCH, 1); 1137a8d48f59SKlaus Jensen SHARED_ARRAY_FIELD_DP32(bus->regs, reg_intr_sts, RX_DONE, 1); 1138a8d48f59SKlaus Jensen 1139a8d48f59SKlaus Jensen aspeed_i2c_set_state(bus, I2CD_STXD); 1140a8d48f59SKlaus Jensen 1141a8d48f59SKlaus Jensen break; 1142a8d48f59SKlaus Jensen 1143a8d48f59SKlaus Jensen case I2C_FINISH: 1144a8d48f59SKlaus Jensen SHARED_ARRAY_FIELD_DP32(bus->regs, reg_intr_sts, NORMAL_STOP, 1); 1145a8d48f59SKlaus Jensen 1146a8d48f59SKlaus Jensen aspeed_i2c_set_state(bus, I2CD_IDLE); 1147a8d48f59SKlaus Jensen 1148a8d48f59SKlaus Jensen break; 1149a8d48f59SKlaus Jensen 1150a8d48f59SKlaus Jensen default: 1151a8d48f59SKlaus Jensen return -1; 1152a8d48f59SKlaus Jensen } 1153a8d48f59SKlaus Jensen 1154a8d48f59SKlaus Jensen aspeed_i2c_bus_raise_interrupt(bus); 1155a8d48f59SKlaus Jensen 1156a8d48f59SKlaus Jensen return 0; 1157a8d48f59SKlaus Jensen } 1158a8d48f59SKlaus Jensen 11591c5d909fSPeter Delevoryas static void aspeed_i2c_bus_new_slave_send_async(AspeedI2CBus *bus, uint8_t data) 11601c5d909fSPeter Delevoryas { 11611c5d909fSPeter Delevoryas assert(address_space_write(&bus->controller->dram_as, 11621c5d909fSPeter Delevoryas bus->regs[R_I2CC_DMA_ADDR], 11631c5d909fSPeter Delevoryas MEMTXATTRS_UNSPECIFIED, &data, 1) == MEMTX_OK); 11641c5d909fSPeter Delevoryas 11651c5d909fSPeter Delevoryas bus->regs[R_I2CC_DMA_ADDR]++; 11661c5d909fSPeter Delevoryas bus->regs[R_I2CC_DMA_LEN]--; 11671c5d909fSPeter Delevoryas ARRAY_FIELD_DP32(bus->regs, I2CS_DMA_LEN_STS, RX_LEN, 11681c5d909fSPeter Delevoryas ARRAY_FIELD_EX32(bus->regs, I2CS_DMA_LEN_STS, RX_LEN) + 1); 11691c5d909fSPeter Delevoryas i2c_ack(bus->bus); 11701c5d909fSPeter Delevoryas } 11711c5d909fSPeter Delevoryas 1172a8d48f59SKlaus Jensen static void aspeed_i2c_bus_slave_send_async(I2CSlave *slave, uint8_t data) 1173a8d48f59SKlaus Jensen { 1174a8d48f59SKlaus Jensen BusState *qbus = qdev_get_parent_bus(DEVICE(slave)); 1175a8d48f59SKlaus Jensen AspeedI2CBus *bus = ASPEED_I2C_BUS(qbus->parent); 1176a8d48f59SKlaus Jensen uint32_t reg_intr_sts = aspeed_i2c_bus_intr_sts_offset(bus); 1177a8d48f59SKlaus Jensen uint32_t reg_byte_buf = aspeed_i2c_bus_byte_buf_offset(bus); 1178a8d48f59SKlaus Jensen 11791c5d909fSPeter Delevoryas if (aspeed_i2c_is_new_mode(bus->controller)) { 11801c5d909fSPeter Delevoryas return aspeed_i2c_bus_new_slave_send_async(bus, data); 11811c5d909fSPeter Delevoryas } 11821c5d909fSPeter Delevoryas 1183a8d48f59SKlaus Jensen SHARED_ARRAY_FIELD_DP32(bus->regs, reg_byte_buf, RX_BUF, data); 1184a8d48f59SKlaus Jensen SHARED_ARRAY_FIELD_DP32(bus->regs, reg_intr_sts, RX_DONE, 1); 1185a8d48f59SKlaus Jensen 1186a8d48f59SKlaus Jensen aspeed_i2c_bus_raise_interrupt(bus); 1187a8d48f59SKlaus Jensen } 1188a8d48f59SKlaus Jensen 1189a8d48f59SKlaus Jensen static void aspeed_i2c_bus_slave_class_init(ObjectClass *klass, void *data) 1190a8d48f59SKlaus Jensen { 1191a8d48f59SKlaus Jensen DeviceClass *dc = DEVICE_CLASS(klass); 1192a8d48f59SKlaus Jensen I2CSlaveClass *sc = I2C_SLAVE_CLASS(klass); 1193a8d48f59SKlaus Jensen 1194a8d48f59SKlaus Jensen dc->desc = "Aspeed I2C Bus Slave"; 1195a8d48f59SKlaus Jensen 1196a8d48f59SKlaus Jensen sc->event = aspeed_i2c_bus_slave_event; 1197a8d48f59SKlaus Jensen sc->send_async = aspeed_i2c_bus_slave_send_async; 1198a8d48f59SKlaus Jensen } 1199a8d48f59SKlaus Jensen 1200a8d48f59SKlaus Jensen static const TypeInfo aspeed_i2c_bus_slave_info = { 1201a8d48f59SKlaus Jensen .name = TYPE_ASPEED_I2C_BUS_SLAVE, 1202a8d48f59SKlaus Jensen .parent = TYPE_I2C_SLAVE, 1203a8d48f59SKlaus Jensen .instance_size = sizeof(AspeedI2CBusSlave), 1204a8d48f59SKlaus Jensen .class_init = aspeed_i2c_bus_slave_class_init, 1205a8d48f59SKlaus Jensen }; 1206a8d48f59SKlaus Jensen 120760261038SCédric Le Goater static void aspeed_i2c_bus_reset(DeviceState *dev) 120860261038SCédric Le Goater { 120960261038SCédric Le Goater AspeedI2CBus *s = ASPEED_I2C_BUS(dev); 121060261038SCédric Le Goater 12112260fc6fSJoe Komlodi memset(s->regs, 0, sizeof(s->regs)); 121260261038SCédric Le Goater i2c_end_transfer(s->bus); 121360261038SCédric Le Goater } 121460261038SCédric Le Goater 121560261038SCédric Le Goater static void aspeed_i2c_bus_realize(DeviceState *dev, Error **errp) 121660261038SCédric Le Goater { 121760261038SCédric Le Goater AspeedI2CBus *s = ASPEED_I2C_BUS(dev); 121860261038SCédric Le Goater AspeedI2CClass *aic; 121960261038SCédric Le Goater g_autofree char *name = g_strdup_printf(TYPE_ASPEED_I2C_BUS ".%d", s->id); 122060261038SCédric Le Goater 122160261038SCédric Le Goater if (!s->controller) { 122260261038SCédric Le Goater error_setg(errp, TYPE_ASPEED_I2C_BUS ": 'controller' link not set"); 122360261038SCédric Le Goater return; 122460261038SCédric Le Goater } 122560261038SCédric Le Goater 122660261038SCédric Le Goater aic = ASPEED_I2C_GET_CLASS(s->controller); 122760261038SCédric Le Goater 122860261038SCédric Le Goater sysbus_init_irq(SYS_BUS_DEVICE(dev), &s->irq); 122960261038SCédric Le Goater 123060261038SCédric Le Goater s->bus = i2c_init_bus(dev, name); 1231a8d48f59SKlaus Jensen s->slave = i2c_slave_create_simple(s->bus, TYPE_ASPEED_I2C_BUS_SLAVE, 1232a8d48f59SKlaus Jensen 0xff); 123360261038SCédric Le Goater 123460261038SCédric Le Goater memory_region_init_io(&s->mr, OBJECT(s), &aspeed_i2c_bus_ops, 123560261038SCédric Le Goater s, name, aic->reg_size); 123660261038SCédric Le Goater sysbus_init_mmio(SYS_BUS_DEVICE(dev), &s->mr); 123760261038SCédric Le Goater } 123860261038SCédric Le Goater 123960261038SCédric Le Goater static Property aspeed_i2c_bus_properties[] = { 124060261038SCédric Le Goater DEFINE_PROP_UINT8("bus-id", AspeedI2CBus, id, 0), 124160261038SCédric Le Goater DEFINE_PROP_LINK("controller", AspeedI2CBus, controller, TYPE_ASPEED_I2C, 124260261038SCédric Le Goater AspeedI2CState *), 124360261038SCédric Le Goater DEFINE_PROP_END_OF_LIST(), 124460261038SCédric Le Goater }; 124560261038SCédric Le Goater 124660261038SCédric Le Goater static void aspeed_i2c_bus_class_init(ObjectClass *klass, void *data) 124760261038SCédric Le Goater { 124860261038SCédric Le Goater DeviceClass *dc = DEVICE_CLASS(klass); 124960261038SCédric Le Goater 125060261038SCédric Le Goater dc->desc = "Aspeed I2C Bus"; 125160261038SCédric Le Goater dc->realize = aspeed_i2c_bus_realize; 125260261038SCédric Le Goater dc->reset = aspeed_i2c_bus_reset; 125360261038SCédric Le Goater device_class_set_props(dc, aspeed_i2c_bus_properties); 125460261038SCédric Le Goater } 125560261038SCédric Le Goater 125660261038SCédric Le Goater static const TypeInfo aspeed_i2c_bus_info = { 125760261038SCédric Le Goater .name = TYPE_ASPEED_I2C_BUS, 125860261038SCédric Le Goater .parent = TYPE_SYS_BUS_DEVICE, 125960261038SCédric Le Goater .instance_size = sizeof(AspeedI2CBus), 126060261038SCédric Le Goater .class_init = aspeed_i2c_bus_class_init, 126160261038SCédric Le Goater }; 126260261038SCédric Le Goater 126351dd4923SCédric Le Goater static qemu_irq aspeed_2400_i2c_bus_get_irq(AspeedI2CBus *bus) 126451dd4923SCédric Le Goater { 126551dd4923SCédric Le Goater return bus->controller->irq; 126651dd4923SCédric Le Goater } 126751dd4923SCédric Le Goater 12686054fc73SCédric Le Goater static uint8_t *aspeed_2400_i2c_bus_pool_base(AspeedI2CBus *bus) 12696054fc73SCédric Le Goater { 12706054fc73SCédric Le Goater uint8_t *pool_page = 1271*5d337540SJamin Lin &bus->controller->share_pool[ARRAY_FIELD_EX32(bus->regs, 1272*5d337540SJamin Lin I2CD_FUN_CTRL, 12733be3d6ccSJoe Komlodi POOL_PAGE_SEL) * 0x100]; 12746054fc73SCédric Le Goater 12752260fc6fSJoe Komlodi return &pool_page[ARRAY_FIELD_EX32(bus->regs, I2CD_POOL_CTRL, OFFSET)]; 12766054fc73SCédric Le Goater } 12776054fc73SCédric Le Goater 1278f7da1aa8SCédric Le Goater static void aspeed_2400_i2c_class_init(ObjectClass *klass, void *data) 1279f7da1aa8SCédric Le Goater { 1280f7da1aa8SCédric Le Goater DeviceClass *dc = DEVICE_CLASS(klass); 1281f7da1aa8SCédric Le Goater AspeedI2CClass *aic = ASPEED_I2C_CLASS(klass); 1282f7da1aa8SCédric Le Goater 1283f7da1aa8SCédric Le Goater dc->desc = "ASPEED 2400 I2C Controller"; 1284f7da1aa8SCédric Le Goater 1285f7da1aa8SCédric Le Goater aic->num_busses = 14; 1286f7da1aa8SCédric Le Goater aic->reg_size = 0x40; 1287f7da1aa8SCédric Le Goater aic->gap = 7; 128851dd4923SCédric Le Goater aic->bus_get_irq = aspeed_2400_i2c_bus_get_irq; 12896054fc73SCédric Le Goater aic->pool_size = 0x800; 12906054fc73SCédric Le Goater aic->pool_base = 0x800; 12916054fc73SCédric Le Goater aic->bus_pool_base = aspeed_2400_i2c_bus_pool_base; 1292f2202be2SJamin Lin aic->mem_size = 0x1000; 1293f7da1aa8SCédric Le Goater } 1294f7da1aa8SCédric Le Goater 1295f7da1aa8SCédric Le Goater static const TypeInfo aspeed_2400_i2c_info = { 1296f7da1aa8SCédric Le Goater .name = TYPE_ASPEED_2400_I2C, 1297f7da1aa8SCédric Le Goater .parent = TYPE_ASPEED_I2C, 1298f7da1aa8SCédric Le Goater .class_init = aspeed_2400_i2c_class_init, 1299f7da1aa8SCédric Le Goater }; 1300f7da1aa8SCédric Le Goater 130151dd4923SCédric Le Goater static qemu_irq aspeed_2500_i2c_bus_get_irq(AspeedI2CBus *bus) 130251dd4923SCédric Le Goater { 130351dd4923SCédric Le Goater return bus->controller->irq; 130451dd4923SCédric Le Goater } 130551dd4923SCédric Le Goater 13066054fc73SCédric Le Goater static uint8_t *aspeed_2500_i2c_bus_pool_base(AspeedI2CBus *bus) 13076054fc73SCédric Le Goater { 1308*5d337540SJamin Lin return &bus->controller->share_pool[bus->id * 0x10]; 13096054fc73SCédric Le Goater } 13106054fc73SCédric Le Goater 1311f7da1aa8SCédric Le Goater static void aspeed_2500_i2c_class_init(ObjectClass *klass, void *data) 1312f7da1aa8SCédric Le Goater { 1313f7da1aa8SCédric Le Goater DeviceClass *dc = DEVICE_CLASS(klass); 1314f7da1aa8SCédric Le Goater AspeedI2CClass *aic = ASPEED_I2C_CLASS(klass); 1315f7da1aa8SCédric Le Goater 1316f7da1aa8SCédric Le Goater dc->desc = "ASPEED 2500 I2C Controller"; 1317f7da1aa8SCédric Le Goater 1318f7da1aa8SCédric Le Goater aic->num_busses = 14; 1319f7da1aa8SCédric Le Goater aic->reg_size = 0x40; 1320f7da1aa8SCédric Le Goater aic->gap = 7; 132151dd4923SCédric Le Goater aic->bus_get_irq = aspeed_2500_i2c_bus_get_irq; 13226054fc73SCédric Le Goater aic->pool_size = 0x100; 13236054fc73SCédric Le Goater aic->pool_base = 0x200; 13246054fc73SCédric Le Goater aic->bus_pool_base = aspeed_2500_i2c_bus_pool_base; 1325aab90b1cSCédric Le Goater aic->check_sram = true; 1326545d6befSCédric Le Goater aic->has_dma = true; 1327f2202be2SJamin Lin aic->mem_size = 0x1000; 1328f7da1aa8SCédric Le Goater } 1329f7da1aa8SCédric Le Goater 1330f7da1aa8SCédric Le Goater static const TypeInfo aspeed_2500_i2c_info = { 1331f7da1aa8SCédric Le Goater .name = TYPE_ASPEED_2500_I2C, 1332f7da1aa8SCédric Le Goater .parent = TYPE_ASPEED_I2C, 1333f7da1aa8SCédric Le Goater .class_init = aspeed_2500_i2c_class_init, 133416020011SCédric Le Goater }; 133516020011SCédric Le Goater 133651dd4923SCédric Le Goater static qemu_irq aspeed_2600_i2c_bus_get_irq(AspeedI2CBus *bus) 133751dd4923SCédric Le Goater { 133851dd4923SCédric Le Goater return bus->irq; 133951dd4923SCédric Le Goater } 134051dd4923SCédric Le Goater 13416054fc73SCédric Le Goater static uint8_t *aspeed_2600_i2c_bus_pool_base(AspeedI2CBus *bus) 13426054fc73SCédric Le Goater { 1343*5d337540SJamin Lin return &bus->controller->share_pool[bus->id * 0x20]; 13446054fc73SCédric Le Goater } 13456054fc73SCédric Le Goater 134651dd4923SCédric Le Goater static void aspeed_2600_i2c_class_init(ObjectClass *klass, void *data) 134751dd4923SCédric Le Goater { 134851dd4923SCédric Le Goater DeviceClass *dc = DEVICE_CLASS(klass); 134951dd4923SCédric Le Goater AspeedI2CClass *aic = ASPEED_I2C_CLASS(klass); 135051dd4923SCédric Le Goater 135151dd4923SCédric Le Goater dc->desc = "ASPEED 2600 I2C Controller"; 135251dd4923SCédric Le Goater 135351dd4923SCédric Le Goater aic->num_busses = 16; 135451dd4923SCédric Le Goater aic->reg_size = 0x80; 135551dd4923SCédric Le Goater aic->gap = -1; /* no gap */ 135651dd4923SCédric Le Goater aic->bus_get_irq = aspeed_2600_i2c_bus_get_irq; 13576054fc73SCédric Le Goater aic->pool_size = 0x200; 13586054fc73SCédric Le Goater aic->pool_base = 0xC00; 13596054fc73SCédric Le Goater aic->bus_pool_base = aspeed_2600_i2c_bus_pool_base; 1360545d6befSCédric Le Goater aic->has_dma = true; 1361f2202be2SJamin Lin aic->mem_size = 0x1000; 136251dd4923SCédric Le Goater } 136351dd4923SCédric Le Goater 136451dd4923SCédric Le Goater static const TypeInfo aspeed_2600_i2c_info = { 136551dd4923SCédric Le Goater .name = TYPE_ASPEED_2600_I2C, 136651dd4923SCédric Le Goater .parent = TYPE_ASPEED_I2C, 136751dd4923SCédric Le Goater .class_init = aspeed_2600_i2c_class_init, 136851dd4923SCédric Le Goater }; 136951dd4923SCédric Le Goater 1370b35802ceSCédric Le Goater static void aspeed_1030_i2c_class_init(ObjectClass *klass, void *data) 1371b35802ceSCédric Le Goater { 1372b35802ceSCédric Le Goater DeviceClass *dc = DEVICE_CLASS(klass); 1373b35802ceSCédric Le Goater AspeedI2CClass *aic = ASPEED_I2C_CLASS(klass); 1374b35802ceSCédric Le Goater 1375b35802ceSCédric Le Goater dc->desc = "ASPEED 1030 I2C Controller"; 1376b35802ceSCédric Le Goater 1377b35802ceSCédric Le Goater aic->num_busses = 14; 1378b35802ceSCédric Le Goater aic->reg_size = 0x80; 1379b35802ceSCédric Le Goater aic->gap = -1; /* no gap */ 1380b35802ceSCédric Le Goater aic->bus_get_irq = aspeed_2600_i2c_bus_get_irq; 1381b35802ceSCédric Le Goater aic->pool_size = 0x200; 1382b35802ceSCédric Le Goater aic->pool_base = 0xC00; 1383b35802ceSCédric Le Goater aic->bus_pool_base = aspeed_2600_i2c_bus_pool_base; 1384b35802ceSCédric Le Goater aic->has_dma = true; 1385f2202be2SJamin Lin aic->mem_size = 0x10000; 1386b35802ceSCédric Le Goater } 1387b35802ceSCédric Le Goater 1388b35802ceSCédric Le Goater static const TypeInfo aspeed_1030_i2c_info = { 1389b35802ceSCédric Le Goater .name = TYPE_ASPEED_1030_I2C, 1390b35802ceSCédric Le Goater .parent = TYPE_ASPEED_I2C, 1391b35802ceSCédric Le Goater .class_init = aspeed_1030_i2c_class_init, 1392b35802ceSCédric Le Goater }; 1393b35802ceSCédric Le Goater 139416020011SCédric Le Goater static void aspeed_i2c_register_types(void) 139516020011SCédric Le Goater { 139660261038SCédric Le Goater type_register_static(&aspeed_i2c_bus_info); 1397a8d48f59SKlaus Jensen type_register_static(&aspeed_i2c_bus_slave_info); 139816020011SCédric Le Goater type_register_static(&aspeed_i2c_info); 1399f7da1aa8SCédric Le Goater type_register_static(&aspeed_2400_i2c_info); 1400f7da1aa8SCédric Le Goater type_register_static(&aspeed_2500_i2c_info); 140151dd4923SCédric Le Goater type_register_static(&aspeed_2600_i2c_info); 1402b35802ceSCédric Le Goater type_register_static(&aspeed_1030_i2c_info); 140316020011SCédric Le Goater } 140416020011SCédric Le Goater 140516020011SCédric Le Goater type_init(aspeed_i2c_register_types) 140616020011SCédric Le Goater 140716020011SCédric Le Goater 14087a204cbdSPhilippe Mathieu-Daudé I2CBus *aspeed_i2c_get_bus(AspeedI2CState *s, int busnr) 140916020011SCédric Le Goater { 1410f7da1aa8SCédric Le Goater AspeedI2CClass *aic = ASPEED_I2C_GET_CLASS(s); 141116020011SCédric Le Goater I2CBus *bus = NULL; 141216020011SCédric Le Goater 1413f7da1aa8SCédric Le Goater if (busnr >= 0 && busnr < aic->num_busses) { 141416020011SCédric Le Goater bus = s->busses[busnr].bus; 141516020011SCédric Le Goater } 141616020011SCédric Le Goater 141716020011SCédric Le Goater return bus; 141816020011SCédric Le Goater } 1419