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 3516020011SCédric Le Goater static inline void aspeed_i2c_bus_raise_interrupt(AspeedI2CBus *bus) 3616020011SCédric Le Goater { 3751dd4923SCédric Le Goater AspeedI2CClass *aic = ASPEED_I2C_GET_CLASS(bus->controller); 38ba2cccd6SJoe Komlodi uint32_t reg_intr_sts = aspeed_i2c_bus_intr_sts_offset(bus); 39ba2cccd6SJoe Komlodi uint32_t intr_ctrl_reg = aspeed_i2c_bus_intr_ctrl_offset(bus); 40ba2cccd6SJoe Komlodi bool raise_irq; 4151dd4923SCédric Le Goater 42b03ec4ffSKlaus Jensen if (trace_event_get_state_backends(TRACE_ASPEED_I2C_BUS_RAISE_INTERRUPT)) { 43b03ec4ffSKlaus Jensen g_autofree char *buf = g_strdup_printf("%s%s%s%s%s%s", 440efec47bSJoe Komlodi aspeed_i2c_bus_pkt_mode_en(bus) && 450efec47bSJoe Komlodi ARRAY_FIELD_EX32(bus->regs, I2CM_INTR_STS, PKT_CMD_DONE) ? 460efec47bSJoe Komlodi "pktdone|" : "", 47b03ec4ffSKlaus Jensen SHARED_ARRAY_FIELD_EX32(bus->regs, reg_intr_sts, TX_NAK) ? 48b03ec4ffSKlaus Jensen "nak|" : "", 49b03ec4ffSKlaus Jensen SHARED_ARRAY_FIELD_EX32(bus->regs, reg_intr_sts, TX_ACK) ? 50b03ec4ffSKlaus Jensen "ack|" : "", 51b03ec4ffSKlaus Jensen SHARED_ARRAY_FIELD_EX32(bus->regs, reg_intr_sts, RX_DONE) ? 52b03ec4ffSKlaus Jensen "done|" : "", 53ba2cccd6SJoe Komlodi SHARED_ARRAY_FIELD_EX32(bus->regs, reg_intr_sts, NORMAL_STOP) ? 54ba2cccd6SJoe Komlodi "normal|" : "", 55b03ec4ffSKlaus Jensen SHARED_ARRAY_FIELD_EX32(bus->regs, reg_intr_sts, ABNORMAL) ? 56b03ec4ffSKlaus Jensen "abnormal" : ""); 57b03ec4ffSKlaus Jensen 58b03ec4ffSKlaus Jensen trace_aspeed_i2c_bus_raise_interrupt(bus->regs[reg_intr_sts], buf); 59b03ec4ffSKlaus Jensen } 60b03ec4ffSKlaus Jensen 61ba2cccd6SJoe Komlodi raise_irq = bus->regs[reg_intr_sts] & bus->regs[intr_ctrl_reg]; 62b03ec4ffSKlaus Jensen 63ba2cccd6SJoe Komlodi /* In packet mode we don't mask off INTR_STS */ 64ba2cccd6SJoe Komlodi if (!aspeed_i2c_bus_pkt_mode_en(bus)) { 65ba2cccd6SJoe Komlodi bus->regs[reg_intr_sts] &= bus->regs[intr_ctrl_reg]; 66ba2cccd6SJoe Komlodi } 67b03ec4ffSKlaus Jensen 68ba2cccd6SJoe Komlodi if (raise_irq) { 6916020011SCédric Le Goater bus->controller->intr_status |= 1 << bus->id; 7051dd4923SCédric Le Goater qemu_irq_raise(aic->bus_get_irq(bus)); 7116020011SCédric Le Goater } 7216020011SCédric Le Goater } 7316020011SCédric Le Goater 74ba2cccd6SJoe Komlodi static uint64_t aspeed_i2c_bus_old_read(AspeedI2CBus *bus, hwaddr offset, 7516020011SCédric Le Goater unsigned size) 7616020011SCédric Le Goater { 77545d6befSCédric Le Goater AspeedI2CClass *aic = ASPEED_I2C_GET_CLASS(bus->controller); 782260fc6fSJoe Komlodi uint64_t value = bus->regs[offset / sizeof(*bus->regs)]; 7916020011SCédric Le Goater 8016020011SCédric Le Goater switch (offset) { 813be3d6ccSJoe Komlodi case A_I2CD_FUN_CTRL: 823be3d6ccSJoe Komlodi case A_I2CD_AC_TIMING1: 833be3d6ccSJoe Komlodi case A_I2CD_AC_TIMING2: 843be3d6ccSJoe Komlodi case A_I2CD_INTR_CTRL: 853be3d6ccSJoe Komlodi case A_I2CD_INTR_STS: 86*d72a712cSKlaus Jensen case A_I2CD_DEV_ADDR: 873be3d6ccSJoe Komlodi case A_I2CD_POOL_CTRL: 883be3d6ccSJoe Komlodi case A_I2CD_BYTE_BUF: 892260fc6fSJoe Komlodi /* Value is already set, don't do anything. */ 9066cc84a1SCédric Le Goater break; 913be3d6ccSJoe Komlodi case A_I2CD_CMD: 92ba2cccd6SJoe Komlodi value = SHARED_FIELD_DP32(value, BUS_BUSY_STS, i2c_bus_busy(bus->bus)); 9366cc84a1SCédric Le Goater break; 943be3d6ccSJoe Komlodi case A_I2CD_DMA_ADDR: 95545d6befSCédric Le Goater if (!aic->has_dma) { 96545d6befSCédric Le Goater qemu_log_mask(LOG_GUEST_ERROR, "%s: No DMA support\n", __func__); 972260fc6fSJoe Komlodi value = -1; 98545d6befSCédric Le Goater } 9966cc84a1SCédric Le Goater break; 1003be3d6ccSJoe Komlodi case A_I2CD_DMA_LEN: 101545d6befSCédric Le Goater if (!aic->has_dma) { 102545d6befSCédric Le Goater qemu_log_mask(LOG_GUEST_ERROR, "%s: No DMA support\n", __func__); 1032260fc6fSJoe Komlodi value = -1; 104545d6befSCédric Le Goater } 10566cc84a1SCédric Le Goater break; 10666cc84a1SCédric Le Goater 10716020011SCédric Le Goater default: 10816020011SCédric Le Goater qemu_log_mask(LOG_GUEST_ERROR, 10916020011SCédric Le Goater "%s: Bad offset 0x%" HWADDR_PRIx "\n", __func__, offset); 11066cc84a1SCédric Le Goater value = -1; 11166cc84a1SCédric Le Goater break; 11216020011SCédric Le Goater } 11366cc84a1SCédric Le Goater 11466cc84a1SCédric Le Goater trace_aspeed_i2c_bus_read(bus->id, offset, size, value); 11566cc84a1SCédric Le Goater return value; 11616020011SCédric Le Goater } 11716020011SCédric Le Goater 118ba2cccd6SJoe Komlodi static uint64_t aspeed_i2c_bus_new_read(AspeedI2CBus *bus, hwaddr offset, 119ba2cccd6SJoe Komlodi unsigned size) 120ba2cccd6SJoe Komlodi { 121ba2cccd6SJoe Komlodi uint64_t value = bus->regs[offset / sizeof(*bus->regs)]; 122ba2cccd6SJoe Komlodi 123ba2cccd6SJoe Komlodi switch (offset) { 124ba2cccd6SJoe Komlodi case A_I2CC_FUN_CTRL: 125ba2cccd6SJoe Komlodi case A_I2CC_AC_TIMING: 126ba2cccd6SJoe Komlodi case A_I2CC_POOL_CTRL: 127ba2cccd6SJoe Komlodi case A_I2CM_INTR_CTRL: 128ba2cccd6SJoe Komlodi case A_I2CM_INTR_STS: 129ba2cccd6SJoe Komlodi case A_I2CC_MS_TXRX_BYTE_BUF: 130ba2cccd6SJoe Komlodi case A_I2CM_DMA_LEN: 131ba2cccd6SJoe Komlodi case A_I2CM_DMA_TX_ADDR: 132ba2cccd6SJoe Komlodi case A_I2CM_DMA_RX_ADDR: 133ba2cccd6SJoe Komlodi case A_I2CM_DMA_LEN_STS: 134ba2cccd6SJoe Komlodi case A_I2CC_DMA_ADDR: 135ba2cccd6SJoe Komlodi case A_I2CC_DMA_LEN: 136ba2cccd6SJoe Komlodi /* Value is already set, don't do anything. */ 137ba2cccd6SJoe Komlodi break; 138ba2cccd6SJoe Komlodi case A_I2CM_CMD: 139ba2cccd6SJoe Komlodi value = SHARED_FIELD_DP32(value, BUS_BUSY_STS, i2c_bus_busy(bus->bus)); 140ba2cccd6SJoe Komlodi break; 141ba2cccd6SJoe Komlodi default: 142ba2cccd6SJoe Komlodi qemu_log_mask(LOG_GUEST_ERROR, 143ba2cccd6SJoe Komlodi "%s: Bad offset 0x%" HWADDR_PRIx "\n", __func__, offset); 144ba2cccd6SJoe Komlodi value = -1; 145ba2cccd6SJoe Komlodi break; 146ba2cccd6SJoe Komlodi } 147ba2cccd6SJoe Komlodi 148ba2cccd6SJoe Komlodi trace_aspeed_i2c_bus_read(bus->id, offset, size, value); 149ba2cccd6SJoe Komlodi return value; 150ba2cccd6SJoe Komlodi } 151ba2cccd6SJoe Komlodi 152ba2cccd6SJoe Komlodi static uint64_t aspeed_i2c_bus_read(void *opaque, hwaddr offset, 153ba2cccd6SJoe Komlodi unsigned size) 154ba2cccd6SJoe Komlodi { 155ba2cccd6SJoe Komlodi AspeedI2CBus *bus = opaque; 156ba2cccd6SJoe Komlodi if (aspeed_i2c_is_new_mode(bus->controller)) { 157ba2cccd6SJoe Komlodi return aspeed_i2c_bus_new_read(bus, offset, size); 158ba2cccd6SJoe Komlodi } 159ba2cccd6SJoe Komlodi return aspeed_i2c_bus_old_read(bus, offset, size); 160ba2cccd6SJoe Komlodi } 161ba2cccd6SJoe Komlodi 1624960f084SCédric Le Goater static void aspeed_i2c_set_state(AspeedI2CBus *bus, uint8_t state) 1634960f084SCédric Le Goater { 164ba2cccd6SJoe Komlodi if (aspeed_i2c_is_new_mode(bus->controller)) { 165ba2cccd6SJoe Komlodi SHARED_ARRAY_FIELD_DP32(bus->regs, R_I2CC_MS_TXRX_BYTE_BUF, TX_STATE, 166ba2cccd6SJoe Komlodi state); 167ba2cccd6SJoe Komlodi } else { 168ba2cccd6SJoe Komlodi SHARED_ARRAY_FIELD_DP32(bus->regs, R_I2CD_CMD, TX_STATE, state); 169ba2cccd6SJoe Komlodi } 1704960f084SCédric Le Goater } 1714960f084SCédric Le Goater 1724960f084SCédric Le Goater static uint8_t aspeed_i2c_get_state(AspeedI2CBus *bus) 1734960f084SCédric Le Goater { 174ba2cccd6SJoe Komlodi if (aspeed_i2c_is_new_mode(bus->controller)) { 175ba2cccd6SJoe Komlodi return SHARED_ARRAY_FIELD_EX32(bus->regs, R_I2CC_MS_TXRX_BYTE_BUF, 176ba2cccd6SJoe Komlodi TX_STATE); 177ba2cccd6SJoe Komlodi } 178ba2cccd6SJoe Komlodi return SHARED_ARRAY_FIELD_EX32(bus->regs, R_I2CD_CMD, TX_STATE); 1794960f084SCédric Le Goater } 1804960f084SCédric Le Goater 181545d6befSCédric Le Goater static int aspeed_i2c_dma_read(AspeedI2CBus *bus, uint8_t *data) 182545d6befSCédric Le Goater { 183545d6befSCédric Le Goater MemTxResult result; 184545d6befSCédric Le Goater AspeedI2CState *s = bus->controller; 185ba2cccd6SJoe Komlodi uint32_t reg_dma_addr = aspeed_i2c_bus_dma_addr_offset(bus); 186ba2cccd6SJoe Komlodi uint32_t reg_dma_len = aspeed_i2c_bus_dma_len_offset(bus); 187545d6befSCédric Le Goater 188ba2cccd6SJoe Komlodi result = address_space_read(&s->dram_as, bus->regs[reg_dma_addr], 189545d6befSCédric Le Goater MEMTXATTRS_UNSPECIFIED, data, 1); 190545d6befSCédric Le Goater if (result != MEMTX_OK) { 191545d6befSCédric Le Goater qemu_log_mask(LOG_GUEST_ERROR, "%s: DRAM read failed @%08x\n", 192ba2cccd6SJoe Komlodi __func__, bus->regs[reg_dma_addr]); 193545d6befSCédric Le Goater return -1; 194545d6befSCédric Le Goater } 195545d6befSCédric Le Goater 196ba2cccd6SJoe Komlodi bus->regs[reg_dma_addr]++; 197ba2cccd6SJoe Komlodi bus->regs[reg_dma_len]--; 198545d6befSCédric Le Goater return 0; 199545d6befSCédric Le Goater } 200545d6befSCédric Le Goater 2016054fc73SCédric Le Goater static int aspeed_i2c_bus_send(AspeedI2CBus *bus, uint8_t pool_start) 2026054fc73SCédric Le Goater { 2036054fc73SCédric Le Goater AspeedI2CClass *aic = ASPEED_I2C_GET_CLASS(bus->controller); 2046054fc73SCédric Le Goater int ret = -1; 2056054fc73SCédric Le Goater int i; 206ba2cccd6SJoe Komlodi uint32_t reg_cmd = aspeed_i2c_bus_cmd_offset(bus); 207ba2cccd6SJoe Komlodi uint32_t reg_pool_ctrl = aspeed_i2c_bus_pool_ctrl_offset(bus); 208ba2cccd6SJoe Komlodi uint32_t reg_byte_buf = aspeed_i2c_bus_byte_buf_offset(bus); 209ba2cccd6SJoe Komlodi uint32_t reg_dma_len = aspeed_i2c_bus_dma_len_offset(bus); 210ba2cccd6SJoe Komlodi int pool_tx_count = SHARED_ARRAY_FIELD_EX32(bus->regs, reg_pool_ctrl, 211ba2cccd6SJoe Komlodi TX_COUNT); 2126054fc73SCédric Le Goater 213ba2cccd6SJoe Komlodi if (SHARED_ARRAY_FIELD_EX32(bus->regs, reg_cmd, TX_BUFF_EN)) { 2143be3d6ccSJoe Komlodi for (i = pool_start; i < pool_tx_count; i++) { 2156054fc73SCédric Le Goater uint8_t *pool_base = aic->bus_pool_base(bus); 2166054fc73SCédric Le Goater 2173be3d6ccSJoe Komlodi trace_aspeed_i2c_bus_send("BUF", i + 1, pool_tx_count, 21866cc84a1SCédric Le Goater pool_base[i]); 2196054fc73SCédric Le Goater ret = i2c_send(bus->bus, pool_base[i]); 2206054fc73SCédric Le Goater if (ret) { 2216054fc73SCédric Le Goater break; 2226054fc73SCédric Le Goater } 2236054fc73SCédric Le Goater } 224ba2cccd6SJoe Komlodi SHARED_ARRAY_FIELD_DP32(bus->regs, reg_cmd, TX_BUFF_EN, 0); 225ba2cccd6SJoe Komlodi } else if (SHARED_ARRAY_FIELD_EX32(bus->regs, reg_cmd, TX_DMA_EN)) { 226ba2cccd6SJoe Komlodi /* In new mode, clear how many bytes we TXed */ 227ba2cccd6SJoe Komlodi if (aspeed_i2c_is_new_mode(bus->controller)) { 228ba2cccd6SJoe Komlodi ARRAY_FIELD_DP32(bus->regs, I2CM_DMA_LEN_STS, TX_LEN, 0); 229ba2cccd6SJoe Komlodi } 230ba2cccd6SJoe Komlodi while (bus->regs[reg_dma_len]) { 231545d6befSCédric Le Goater uint8_t data; 232545d6befSCédric Le Goater aspeed_i2c_dma_read(bus, &data); 233ba2cccd6SJoe Komlodi trace_aspeed_i2c_bus_send("DMA", bus->regs[reg_dma_len], 234ba2cccd6SJoe Komlodi bus->regs[reg_dma_len], data); 235545d6befSCédric Le Goater ret = i2c_send(bus->bus, data); 236545d6befSCédric Le Goater if (ret) { 237545d6befSCédric Le Goater break; 238545d6befSCédric Le Goater } 239ba2cccd6SJoe Komlodi /* In new mode, keep track of how many bytes we TXed */ 240ba2cccd6SJoe Komlodi if (aspeed_i2c_is_new_mode(bus->controller)) { 241ba2cccd6SJoe Komlodi ARRAY_FIELD_DP32(bus->regs, I2CM_DMA_LEN_STS, TX_LEN, 242ba2cccd6SJoe Komlodi ARRAY_FIELD_EX32(bus->regs, I2CM_DMA_LEN_STS, 243ba2cccd6SJoe Komlodi TX_LEN) + 1); 244545d6befSCédric Le Goater } 245ba2cccd6SJoe Komlodi } 246ba2cccd6SJoe Komlodi SHARED_ARRAY_FIELD_DP32(bus->regs, reg_cmd, TX_DMA_EN, 0); 2476054fc73SCédric Le Goater } else { 2482260fc6fSJoe Komlodi trace_aspeed_i2c_bus_send("BYTE", pool_start, 1, 249ba2cccd6SJoe Komlodi bus->regs[reg_byte_buf]); 250ba2cccd6SJoe Komlodi ret = i2c_send(bus->bus, bus->regs[reg_byte_buf]); 2516054fc73SCédric Le Goater } 2526054fc73SCédric Le Goater 2536054fc73SCédric Le Goater return ret; 2546054fc73SCédric Le Goater } 2556054fc73SCédric Le Goater 2566054fc73SCédric Le Goater static void aspeed_i2c_bus_recv(AspeedI2CBus *bus) 2576054fc73SCédric Le Goater { 2586054fc73SCédric Le Goater AspeedI2CState *s = bus->controller; 2596054fc73SCédric Le Goater AspeedI2CClass *aic = ASPEED_I2C_GET_CLASS(s); 2606054fc73SCédric Le Goater uint8_t data; 2616054fc73SCédric Le Goater int i; 262ba2cccd6SJoe Komlodi uint32_t reg_cmd = aspeed_i2c_bus_cmd_offset(bus); 263ba2cccd6SJoe Komlodi uint32_t reg_pool_ctrl = aspeed_i2c_bus_pool_ctrl_offset(bus); 264ba2cccd6SJoe Komlodi uint32_t reg_byte_buf = aspeed_i2c_bus_byte_buf_offset(bus); 265ba2cccd6SJoe Komlodi uint32_t reg_dma_len = aspeed_i2c_bus_dma_len_offset(bus); 266ba2cccd6SJoe Komlodi uint32_t reg_dma_addr = aspeed_i2c_bus_dma_addr_offset(bus); 267ba2cccd6SJoe Komlodi int pool_rx_count = SHARED_ARRAY_FIELD_EX32(bus->regs, reg_pool_ctrl, 268ba2cccd6SJoe Komlodi RX_COUNT); 2696054fc73SCédric Le Goater 270ba2cccd6SJoe Komlodi if (SHARED_ARRAY_FIELD_EX32(bus->regs, reg_cmd, RX_BUFF_EN)) { 2716054fc73SCédric Le Goater uint8_t *pool_base = aic->bus_pool_base(bus); 2726054fc73SCédric Le Goater 2733be3d6ccSJoe Komlodi for (i = 0; i < pool_rx_count; i++) { 2746054fc73SCédric Le Goater pool_base[i] = i2c_recv(bus->bus); 2753be3d6ccSJoe Komlodi trace_aspeed_i2c_bus_recv("BUF", i + 1, pool_rx_count, 27666cc84a1SCédric Le Goater pool_base[i]); 2776054fc73SCédric Le Goater } 2786054fc73SCédric Le Goater 2796054fc73SCédric Le Goater /* Update RX count */ 280ba2cccd6SJoe Komlodi SHARED_ARRAY_FIELD_DP32(bus->regs, reg_pool_ctrl, RX_COUNT, i & 0xff); 281ba2cccd6SJoe Komlodi SHARED_ARRAY_FIELD_DP32(bus->regs, reg_cmd, RX_BUFF_EN, 0); 282ba2cccd6SJoe Komlodi } else if (SHARED_ARRAY_FIELD_EX32(bus->regs, reg_cmd, RX_DMA_EN)) { 283545d6befSCédric Le Goater uint8_t data; 284ba2cccd6SJoe Komlodi /* In new mode, clear how many bytes we RXed */ 285ba2cccd6SJoe Komlodi if (aspeed_i2c_is_new_mode(bus->controller)) { 286ba2cccd6SJoe Komlodi ARRAY_FIELD_DP32(bus->regs, I2CM_DMA_LEN_STS, RX_LEN, 0); 287ba2cccd6SJoe Komlodi } 288545d6befSCédric Le Goater 289ba2cccd6SJoe Komlodi while (bus->regs[reg_dma_len]) { 290545d6befSCédric Le Goater MemTxResult result; 291545d6befSCédric Le Goater 292545d6befSCédric Le Goater data = i2c_recv(bus->bus); 293ba2cccd6SJoe Komlodi trace_aspeed_i2c_bus_recv("DMA", bus->regs[reg_dma_len], 294ba2cccd6SJoe Komlodi bus->regs[reg_dma_len], data); 295ba2cccd6SJoe Komlodi result = address_space_write(&s->dram_as, bus->regs[reg_dma_addr], 296545d6befSCédric Le Goater MEMTXATTRS_UNSPECIFIED, &data, 1); 297545d6befSCédric Le Goater if (result != MEMTX_OK) { 298545d6befSCédric Le Goater qemu_log_mask(LOG_GUEST_ERROR, "%s: DRAM write failed @%08x\n", 299ba2cccd6SJoe Komlodi __func__, bus->regs[reg_dma_addr]); 300545d6befSCédric Le Goater return; 301545d6befSCédric Le Goater } 302ba2cccd6SJoe Komlodi bus->regs[reg_dma_addr]++; 303ba2cccd6SJoe Komlodi bus->regs[reg_dma_len]--; 304ba2cccd6SJoe Komlodi /* In new mode, keep track of how many bytes we RXed */ 305ba2cccd6SJoe Komlodi if (aspeed_i2c_is_new_mode(bus->controller)) { 306ba2cccd6SJoe Komlodi ARRAY_FIELD_DP32(bus->regs, I2CM_DMA_LEN_STS, RX_LEN, 307ba2cccd6SJoe Komlodi ARRAY_FIELD_EX32(bus->regs, I2CM_DMA_LEN_STS, 308ba2cccd6SJoe Komlodi RX_LEN) + 1); 309545d6befSCédric Le Goater } 310ba2cccd6SJoe Komlodi } 311ba2cccd6SJoe Komlodi SHARED_ARRAY_FIELD_DP32(bus->regs, reg_cmd, RX_DMA_EN, 0); 3126054fc73SCédric Le Goater } else { 3136054fc73SCédric Le Goater data = i2c_recv(bus->bus); 314ba2cccd6SJoe Komlodi trace_aspeed_i2c_bus_recv("BYTE", 1, 1, bus->regs[reg_byte_buf]); 315ba2cccd6SJoe Komlodi SHARED_ARRAY_FIELD_DP32(bus->regs, reg_byte_buf, RX_BUF, data); 3166054fc73SCédric Le Goater } 3176054fc73SCédric Le Goater } 3186054fc73SCédric Le Goater 3197bd9c60dSGuenter Roeck static void aspeed_i2c_handle_rx_cmd(AspeedI2CBus *bus) 3207bd9c60dSGuenter Roeck { 321ba2cccd6SJoe Komlodi uint32_t reg_cmd = aspeed_i2c_bus_cmd_offset(bus); 322ba2cccd6SJoe Komlodi uint32_t reg_intr_sts = aspeed_i2c_bus_intr_sts_offset(bus); 323ba2cccd6SJoe Komlodi 3247bd9c60dSGuenter Roeck aspeed_i2c_set_state(bus, I2CD_MRXD); 3256054fc73SCédric Le Goater aspeed_i2c_bus_recv(bus); 326ba2cccd6SJoe Komlodi SHARED_ARRAY_FIELD_DP32(bus->regs, reg_intr_sts, RX_DONE, 1); 327ba2cccd6SJoe Komlodi if (SHARED_ARRAY_FIELD_EX32(bus->regs, reg_cmd, M_S_RX_CMD_LAST)) { 3287bd9c60dSGuenter Roeck i2c_nack(bus->bus); 3297bd9c60dSGuenter Roeck } 330ba2cccd6SJoe Komlodi SHARED_ARRAY_FIELD_DP32(bus->regs, reg_cmd, M_RX_CMD, 0); 331ba2cccd6SJoe Komlodi SHARED_ARRAY_FIELD_DP32(bus->regs, reg_cmd, M_S_RX_CMD_LAST, 0); 3327bd9c60dSGuenter Roeck aspeed_i2c_set_state(bus, I2CD_MACTIVE); 3337bd9c60dSGuenter Roeck } 3347bd9c60dSGuenter Roeck 3356054fc73SCédric Le Goater static uint8_t aspeed_i2c_get_addr(AspeedI2CBus *bus) 3366054fc73SCédric Le Goater { 3376054fc73SCédric Le Goater AspeedI2CClass *aic = ASPEED_I2C_GET_CLASS(bus->controller); 338ba2cccd6SJoe Komlodi uint32_t reg_byte_buf = aspeed_i2c_bus_byte_buf_offset(bus); 339ba2cccd6SJoe Komlodi uint32_t reg_cmd = aspeed_i2c_bus_cmd_offset(bus); 3406054fc73SCédric Le Goater 341ba2cccd6SJoe Komlodi if (aspeed_i2c_bus_pkt_mode_en(bus)) { 342ba2cccd6SJoe Komlodi return (ARRAY_FIELD_EX32(bus->regs, I2CM_CMD, PKT_DEV_ADDR) << 1) | 343ba2cccd6SJoe Komlodi SHARED_ARRAY_FIELD_EX32(bus->regs, reg_cmd, M_RX_CMD); 344ba2cccd6SJoe Komlodi } 345ba2cccd6SJoe Komlodi if (SHARED_ARRAY_FIELD_EX32(bus->regs, reg_cmd, TX_BUFF_EN)) { 3466054fc73SCédric Le Goater uint8_t *pool_base = aic->bus_pool_base(bus); 3476054fc73SCédric Le Goater 3486054fc73SCédric Le Goater return pool_base[0]; 349ba2cccd6SJoe Komlodi } else if (SHARED_ARRAY_FIELD_EX32(bus->regs, reg_cmd, TX_DMA_EN)) { 350545d6befSCédric Le Goater uint8_t data; 351545d6befSCédric Le Goater 352545d6befSCédric Le Goater aspeed_i2c_dma_read(bus, &data); 353545d6befSCédric Le Goater return data; 3546054fc73SCédric Le Goater } else { 355ba2cccd6SJoe Komlodi return bus->regs[reg_byte_buf]; 3566054fc73SCédric Le Goater } 3576054fc73SCédric Le Goater } 3586054fc73SCédric Le Goater 359aab90b1cSCédric Le Goater static bool aspeed_i2c_check_sram(AspeedI2CBus *bus) 360aab90b1cSCédric Le Goater { 361aab90b1cSCédric Le Goater AspeedI2CState *s = bus->controller; 362aab90b1cSCédric Le Goater AspeedI2CClass *aic = ASPEED_I2C_GET_CLASS(s); 363ba2cccd6SJoe Komlodi uint32_t reg_cmd = aspeed_i2c_bus_cmd_offset(bus); 364ba2cccd6SJoe Komlodi bool dma_en = SHARED_ARRAY_FIELD_EX32(bus->regs, reg_cmd, RX_DMA_EN) || 365ba2cccd6SJoe Komlodi SHARED_ARRAY_FIELD_EX32(bus->regs, reg_cmd, TX_DMA_EN) || 366ba2cccd6SJoe Komlodi SHARED_ARRAY_FIELD_EX32(bus->regs, reg_cmd, RX_BUFF_EN) || 367ba2cccd6SJoe Komlodi SHARED_ARRAY_FIELD_EX32(bus->regs, reg_cmd, TX_BUFF_EN); 368aab90b1cSCédric Le Goater if (!aic->check_sram) { 369aab90b1cSCédric Le Goater return true; 370aab90b1cSCédric Le Goater } 371aab90b1cSCédric Le Goater 372aab90b1cSCédric Le Goater /* 373aab90b1cSCédric Le Goater * AST2500: SRAM must be enabled before using the Buffer Pool or 374aab90b1cSCédric Le Goater * DMA mode. 375aab90b1cSCédric Le Goater */ 3763be3d6ccSJoe Komlodi if (!FIELD_EX32(s->ctrl_global, I2C_CTRL_GLOBAL, SRAM_EN) && dma_en) { 377aab90b1cSCédric Le Goater qemu_log_mask(LOG_GUEST_ERROR, "%s: SRAM is not enabled\n", __func__); 378aab90b1cSCédric Le Goater return false; 379aab90b1cSCédric Le Goater } 380aab90b1cSCédric Le Goater 381aab90b1cSCédric Le Goater return true; 382aab90b1cSCédric Le Goater } 383aab90b1cSCédric Le Goater 38466cc84a1SCédric Le Goater static void aspeed_i2c_bus_cmd_dump(AspeedI2CBus *bus) 38566cc84a1SCédric Le Goater { 386f821bac4SMiroslav Rezanina g_autofree char *cmd_flags = NULL; 38766cc84a1SCédric Le Goater uint32_t count; 388ba2cccd6SJoe Komlodi uint32_t reg_cmd = aspeed_i2c_bus_cmd_offset(bus); 389ba2cccd6SJoe Komlodi uint32_t reg_pool_ctrl = aspeed_i2c_bus_pool_ctrl_offset(bus); 390ba2cccd6SJoe Komlodi uint32_t reg_intr_sts = aspeed_i2c_bus_intr_sts_offset(bus); 391ba2cccd6SJoe Komlodi uint32_t reg_dma_len = aspeed_i2c_bus_dma_len_offset(bus); 392ba2cccd6SJoe Komlodi if (SHARED_ARRAY_FIELD_EX32(bus->regs, reg_cmd, RX_BUFF_EN)) { 393ba2cccd6SJoe Komlodi count = SHARED_ARRAY_FIELD_EX32(bus->regs, reg_pool_ctrl, TX_COUNT); 394ba2cccd6SJoe Komlodi } else if (SHARED_ARRAY_FIELD_EX32(bus->regs, reg_cmd, RX_DMA_EN)) { 395ba2cccd6SJoe Komlodi count = bus->regs[reg_dma_len]; 39666cc84a1SCédric Le Goater } else { /* BYTE mode */ 39766cc84a1SCédric Le Goater count = 1; 39866cc84a1SCédric Le Goater } 39966cc84a1SCédric Le Goater 40066cc84a1SCédric Le Goater cmd_flags = g_strdup_printf("%s%s%s%s%s%s%s%s%s", 401ba2cccd6SJoe Komlodi SHARED_ARRAY_FIELD_EX32(bus->regs, reg_cmd, M_START_CMD) ? "start|" : "", 402ba2cccd6SJoe Komlodi SHARED_ARRAY_FIELD_EX32(bus->regs, reg_cmd, RX_DMA_EN) ? "rxdma|" : "", 403ba2cccd6SJoe Komlodi SHARED_ARRAY_FIELD_EX32(bus->regs, reg_cmd, TX_DMA_EN) ? "txdma|" : "", 404ba2cccd6SJoe Komlodi SHARED_ARRAY_FIELD_EX32(bus->regs, reg_cmd, RX_BUFF_EN) ? "rxbuf|" : "", 405ba2cccd6SJoe Komlodi SHARED_ARRAY_FIELD_EX32(bus->regs, reg_cmd, TX_BUFF_EN) ? "txbuf|" : "", 406ba2cccd6SJoe Komlodi SHARED_ARRAY_FIELD_EX32(bus->regs, reg_cmd, M_TX_CMD) ? "tx|" : "", 407ba2cccd6SJoe Komlodi SHARED_ARRAY_FIELD_EX32(bus->regs, reg_cmd, M_RX_CMD) ? "rx|" : "", 408ba2cccd6SJoe Komlodi SHARED_ARRAY_FIELD_EX32(bus->regs, reg_cmd, M_S_RX_CMD_LAST) ? "last|" : "", 409ba2cccd6SJoe Komlodi SHARED_ARRAY_FIELD_EX32(bus->regs, reg_cmd, M_STOP_CMD) ? "stop|" : ""); 41066cc84a1SCédric Le Goater 411ba2cccd6SJoe Komlodi trace_aspeed_i2c_bus_cmd(bus->regs[reg_cmd], cmd_flags, count, 412ba2cccd6SJoe Komlodi bus->regs[reg_intr_sts]); 41366cc84a1SCédric Le Goater } 41466cc84a1SCédric Le Goater 4154960f084SCédric Le Goater /* 4164960f084SCédric Le Goater * The state machine needs some refinement. It is only used to track 4174960f084SCédric Le Goater * invalid STOP commands for the moment. 4184960f084SCédric Le Goater */ 41916020011SCédric Le Goater static void aspeed_i2c_bus_handle_cmd(AspeedI2CBus *bus, uint64_t value) 42016020011SCédric Le Goater { 4216054fc73SCédric Le Goater uint8_t pool_start = 0; 422ba2cccd6SJoe Komlodi uint32_t reg_intr_sts = aspeed_i2c_bus_intr_sts_offset(bus); 423ba2cccd6SJoe Komlodi uint32_t reg_cmd = aspeed_i2c_bus_cmd_offset(bus); 424ba2cccd6SJoe Komlodi uint32_t reg_pool_ctrl = aspeed_i2c_bus_pool_ctrl_offset(bus); 425ba2cccd6SJoe Komlodi uint32_t reg_dma_len = aspeed_i2c_bus_dma_len_offset(bus); 42616020011SCédric Le Goater 427aab90b1cSCédric Le Goater if (!aspeed_i2c_check_sram(bus)) { 428aab90b1cSCédric Le Goater return; 429aab90b1cSCédric Le Goater } 430aab90b1cSCédric Le Goater 43166cc84a1SCédric Le Goater if (trace_event_get_state_backends(TRACE_ASPEED_I2C_BUS_CMD)) { 43266cc84a1SCédric Le Goater aspeed_i2c_bus_cmd_dump(bus); 43366cc84a1SCédric Le Goater } 43466cc84a1SCédric Le Goater 435ba2cccd6SJoe Komlodi if (SHARED_ARRAY_FIELD_EX32(bus->regs, reg_cmd, M_START_CMD)) { 4364960f084SCédric Le Goater uint8_t state = aspeed_i2c_get_state(bus) & I2CD_MACTIVE ? 4374960f084SCédric Le Goater I2CD_MSTARTR : I2CD_MSTART; 4386054fc73SCédric Le Goater uint8_t addr; 4394960f084SCédric Le Goater 4404960f084SCédric Le Goater aspeed_i2c_set_state(bus, state); 4414960f084SCédric Le Goater 4426054fc73SCédric Le Goater addr = aspeed_i2c_get_addr(bus); 4436054fc73SCédric Le Goater if (i2c_start_transfer(bus->bus, extract32(addr, 1, 7), 4446054fc73SCédric Le Goater extract32(addr, 0, 1))) { 445ba2cccd6SJoe Komlodi SHARED_ARRAY_FIELD_DP32(bus->regs, reg_intr_sts, TX_NAK, 1); 446ba2cccd6SJoe Komlodi if (aspeed_i2c_bus_pkt_mode_en(bus)) { 447ba2cccd6SJoe Komlodi ARRAY_FIELD_DP32(bus->regs, I2CM_INTR_STS, PKT_CMD_FAIL, 1); 448ba2cccd6SJoe Komlodi } 44916020011SCédric Le Goater } else { 450ba2cccd6SJoe Komlodi /* START doesn't set TX_ACK in packet mode */ 451ba2cccd6SJoe Komlodi if (!aspeed_i2c_bus_pkt_mode_en(bus)) { 452ba2cccd6SJoe Komlodi SHARED_ARRAY_FIELD_DP32(bus->regs, reg_intr_sts, TX_ACK, 1); 453ba2cccd6SJoe Komlodi } 45416020011SCédric Le Goater } 45516020011SCédric Le Goater 456ba2cccd6SJoe Komlodi SHARED_ARRAY_FIELD_DP32(bus->regs, reg_cmd, M_START_CMD, 0); 4576054fc73SCédric Le Goater 4586054fc73SCédric Le Goater /* 4596054fc73SCédric Le Goater * The START command is also a TX command, as the slave 4606054fc73SCédric Le Goater * address is sent on the bus. Drop the TX flag if nothing 4616054fc73SCédric Le Goater * else needs to be sent in this sequence. 4626054fc73SCédric Le Goater */ 463ba2cccd6SJoe Komlodi if (SHARED_ARRAY_FIELD_EX32(bus->regs, reg_cmd, TX_BUFF_EN)) { 464ba2cccd6SJoe Komlodi if (SHARED_ARRAY_FIELD_EX32(bus->regs, reg_pool_ctrl, TX_COUNT) 465ba2cccd6SJoe Komlodi == 1) { 466ba2cccd6SJoe Komlodi SHARED_ARRAY_FIELD_DP32(bus->regs, reg_cmd, M_TX_CMD, 0); 4676054fc73SCédric Le Goater } else { 4686054fc73SCédric Le Goater /* 4696054fc73SCédric Le Goater * Increase the start index in the TX pool buffer to 4706054fc73SCédric Le Goater * skip the address byte. 4716054fc73SCédric Le Goater */ 4726054fc73SCédric Le Goater pool_start++; 4736054fc73SCédric Le Goater } 474ba2cccd6SJoe Komlodi } else if (SHARED_ARRAY_FIELD_EX32(bus->regs, reg_cmd, TX_DMA_EN)) { 475ba2cccd6SJoe Komlodi if (bus->regs[reg_dma_len] == 0) { 476ba2cccd6SJoe Komlodi SHARED_ARRAY_FIELD_DP32(bus->regs, reg_cmd, M_TX_CMD, 0); 477545d6befSCédric Le Goater } 4786054fc73SCédric Le Goater } else { 479ba2cccd6SJoe Komlodi SHARED_ARRAY_FIELD_DP32(bus->regs, reg_cmd, M_TX_CMD, 0); 4806054fc73SCédric Le Goater } 481ddabca75SCédric Le Goater 482ddabca75SCédric Le Goater /* No slave found */ 483ddabca75SCédric Le Goater if (!i2c_bus_busy(bus->bus)) { 484ba2cccd6SJoe Komlodi if (aspeed_i2c_bus_pkt_mode_en(bus)) { 485ba2cccd6SJoe Komlodi ARRAY_FIELD_DP32(bus->regs, I2CM_INTR_STS, PKT_CMD_FAIL, 1); 486ba2cccd6SJoe Komlodi ARRAY_FIELD_DP32(bus->regs, I2CM_INTR_STS, PKT_CMD_DONE, 1); 487ba2cccd6SJoe Komlodi } 488ddabca75SCédric Le Goater return; 489ddabca75SCédric Le Goater } 4904960f084SCédric Le Goater aspeed_i2c_set_state(bus, I2CD_MACTIVE); 491ddabca75SCédric Le Goater } 492ddabca75SCédric Le Goater 493ba2cccd6SJoe Komlodi if (SHARED_ARRAY_FIELD_EX32(bus->regs, reg_cmd, M_TX_CMD)) { 4944960f084SCédric Le Goater aspeed_i2c_set_state(bus, I2CD_MTXD); 4956054fc73SCédric Le Goater if (aspeed_i2c_bus_send(bus, pool_start)) { 496ba2cccd6SJoe Komlodi SHARED_ARRAY_FIELD_DP32(bus->regs, reg_intr_sts, TX_NAK, 1); 49716020011SCédric Le Goater i2c_end_transfer(bus->bus); 49816020011SCédric Le Goater } else { 499ba2cccd6SJoe Komlodi SHARED_ARRAY_FIELD_DP32(bus->regs, reg_intr_sts, TX_ACK, 1); 50016020011SCédric Le Goater } 501ba2cccd6SJoe Komlodi SHARED_ARRAY_FIELD_DP32(bus->regs, reg_cmd, M_TX_CMD, 0); 5024960f084SCédric Le Goater aspeed_i2c_set_state(bus, I2CD_MACTIVE); 503ddabca75SCédric Le Goater } 50416020011SCédric Le Goater 505ba2cccd6SJoe Komlodi if ((SHARED_ARRAY_FIELD_EX32(bus->regs, reg_cmd, M_RX_CMD) || 506ba2cccd6SJoe Komlodi SHARED_ARRAY_FIELD_EX32(bus->regs, reg_cmd, M_S_RX_CMD_LAST)) && 507ba2cccd6SJoe Komlodi !SHARED_ARRAY_FIELD_EX32(bus->regs, reg_intr_sts, RX_DONE)) { 5087bd9c60dSGuenter Roeck aspeed_i2c_handle_rx_cmd(bus); 50916020011SCédric Le Goater } 51016020011SCédric Le Goater 511ba2cccd6SJoe Komlodi if (SHARED_ARRAY_FIELD_EX32(bus->regs, reg_cmd, M_STOP_CMD)) { 5124960f084SCédric Le Goater if (!(aspeed_i2c_get_state(bus) & I2CD_MACTIVE)) { 5134960f084SCédric Le Goater qemu_log_mask(LOG_GUEST_ERROR, "%s: abnormal stop\n", __func__); 514ba2cccd6SJoe Komlodi SHARED_ARRAY_FIELD_DP32(bus->regs, reg_intr_sts, ABNORMAL, 1); 515ba2cccd6SJoe Komlodi if (aspeed_i2c_bus_pkt_mode_en(bus)) { 516ba2cccd6SJoe Komlodi ARRAY_FIELD_DP32(bus->regs, I2CM_INTR_STS, PKT_CMD_FAIL, 1); 517ba2cccd6SJoe Komlodi } 51816020011SCédric Le Goater } else { 5194960f084SCédric Le Goater aspeed_i2c_set_state(bus, I2CD_MSTOP); 52016020011SCédric Le Goater i2c_end_transfer(bus->bus); 521ba2cccd6SJoe Komlodi SHARED_ARRAY_FIELD_DP32(bus->regs, reg_intr_sts, NORMAL_STOP, 1); 52216020011SCédric Le Goater } 523ba2cccd6SJoe Komlodi SHARED_ARRAY_FIELD_DP32(bus->regs, reg_cmd, M_STOP_CMD, 0); 5244960f084SCédric Le Goater aspeed_i2c_set_state(bus, I2CD_IDLE); 52516020011SCédric Le Goater } 526ba2cccd6SJoe Komlodi 527ba2cccd6SJoe Komlodi if (aspeed_i2c_bus_pkt_mode_en(bus)) { 528ba2cccd6SJoe Komlodi ARRAY_FIELD_DP32(bus->regs, I2CM_INTR_STS, PKT_CMD_DONE, 1); 529ba2cccd6SJoe Komlodi } 53016020011SCédric Le Goater } 53116020011SCédric Le Goater 532ba2cccd6SJoe Komlodi static void aspeed_i2c_bus_new_write(AspeedI2CBus *bus, hwaddr offset, 53316020011SCédric Le Goater uint64_t value, unsigned size) 53416020011SCédric Le Goater { 535ba2cccd6SJoe Komlodi AspeedI2CClass *aic = ASPEED_I2C_GET_CLASS(bus->controller); 536ba2cccd6SJoe Komlodi bool handle_rx; 537ba2cccd6SJoe Komlodi bool w1t; 538ba2cccd6SJoe Komlodi 539ba2cccd6SJoe Komlodi trace_aspeed_i2c_bus_write(bus->id, offset, size, value); 540ba2cccd6SJoe Komlodi 541ba2cccd6SJoe Komlodi switch (offset) { 542ba2cccd6SJoe Komlodi case A_I2CC_FUN_CTRL: 543ba2cccd6SJoe Komlodi if (SHARED_FIELD_EX32(value, SLAVE_EN)) { 544ba2cccd6SJoe Komlodi qemu_log_mask(LOG_UNIMP, "%s: slave mode not implemented\n", 545ba2cccd6SJoe Komlodi __func__); 546ba2cccd6SJoe Komlodi break; 547ba2cccd6SJoe Komlodi } 548ba2cccd6SJoe Komlodi bus->regs[R_I2CD_FUN_CTRL] = value & 0x007dc3ff; 549ba2cccd6SJoe Komlodi break; 550ba2cccd6SJoe Komlodi case A_I2CC_AC_TIMING: 551ba2cccd6SJoe Komlodi bus->regs[R_I2CC_AC_TIMING] = value & 0x1ffff0ff; 552ba2cccd6SJoe Komlodi break; 553ba2cccd6SJoe Komlodi case A_I2CC_MS_TXRX_BYTE_BUF: 554ba2cccd6SJoe Komlodi SHARED_ARRAY_FIELD_DP32(bus->regs, R_I2CC_MS_TXRX_BYTE_BUF, TX_BUF, 555ba2cccd6SJoe Komlodi value); 556ba2cccd6SJoe Komlodi break; 557ba2cccd6SJoe Komlodi case A_I2CC_POOL_CTRL: 558ba2cccd6SJoe Komlodi bus->regs[R_I2CC_POOL_CTRL] &= ~0xffffff; 559ba2cccd6SJoe Komlodi bus->regs[R_I2CC_POOL_CTRL] |= (value & 0xffffff); 560ba2cccd6SJoe Komlodi break; 561ba2cccd6SJoe Komlodi case A_I2CM_INTR_CTRL: 562ba2cccd6SJoe Komlodi bus->regs[R_I2CM_INTR_CTRL] = value & 0x0007f07f; 563ba2cccd6SJoe Komlodi break; 564ba2cccd6SJoe Komlodi case A_I2CM_INTR_STS: 565ba2cccd6SJoe Komlodi handle_rx = SHARED_ARRAY_FIELD_EX32(bus->regs, R_I2CM_INTR_STS, RX_DONE) 566ba2cccd6SJoe Komlodi && SHARED_FIELD_EX32(value, RX_DONE); 567ba2cccd6SJoe Komlodi 568ba2cccd6SJoe Komlodi /* In packet mode, clearing PKT_CMD_DONE clears other interrupts. */ 569ba2cccd6SJoe Komlodi if (aspeed_i2c_bus_pkt_mode_en(bus) && 570ba2cccd6SJoe Komlodi FIELD_EX32(value, I2CM_INTR_STS, PKT_CMD_DONE)) { 571ba2cccd6SJoe Komlodi bus->regs[R_I2CM_INTR_STS] &= 0xf0001000; 572ba2cccd6SJoe Komlodi if (!bus->regs[R_I2CM_INTR_STS]) { 573ba2cccd6SJoe Komlodi bus->controller->intr_status &= ~(1 << bus->id); 574ba2cccd6SJoe Komlodi qemu_irq_lower(aic->bus_get_irq(bus)); 575ba2cccd6SJoe Komlodi } 576ba2cccd6SJoe Komlodi break; 577ba2cccd6SJoe Komlodi } 578ba2cccd6SJoe Komlodi bus->regs[R_I2CM_INTR_STS] &= ~(value & 0xf007f07f); 579ba2cccd6SJoe Komlodi if (!bus->regs[R_I2CM_INTR_STS]) { 580ba2cccd6SJoe Komlodi bus->controller->intr_status &= ~(1 << bus->id); 581ba2cccd6SJoe Komlodi qemu_irq_lower(aic->bus_get_irq(bus)); 582ba2cccd6SJoe Komlodi } 583ba2cccd6SJoe Komlodi if (handle_rx && (SHARED_ARRAY_FIELD_EX32(bus->regs, R_I2CM_CMD, 584ba2cccd6SJoe Komlodi M_RX_CMD) || 585ba2cccd6SJoe Komlodi SHARED_ARRAY_FIELD_EX32(bus->regs, R_I2CM_CMD, 586ba2cccd6SJoe Komlodi M_S_RX_CMD_LAST))) { 587ba2cccd6SJoe Komlodi aspeed_i2c_handle_rx_cmd(bus); 588ba2cccd6SJoe Komlodi aspeed_i2c_bus_raise_interrupt(bus); 589ba2cccd6SJoe Komlodi } 590ba2cccd6SJoe Komlodi break; 591ba2cccd6SJoe Komlodi case A_I2CM_CMD: 592ba2cccd6SJoe Komlodi if (!aspeed_i2c_bus_is_enabled(bus)) { 593ba2cccd6SJoe Komlodi break; 594ba2cccd6SJoe Komlodi } 595ba2cccd6SJoe Komlodi 596ba2cccd6SJoe Komlodi if (!aspeed_i2c_bus_is_master(bus)) { 597ba2cccd6SJoe Komlodi qemu_log_mask(LOG_UNIMP, "%s: slave mode not implemented\n", 598ba2cccd6SJoe Komlodi __func__); 599ba2cccd6SJoe Komlodi break; 600ba2cccd6SJoe Komlodi } 601ba2cccd6SJoe Komlodi 602ba2cccd6SJoe Komlodi if (!aic->has_dma && 603ba2cccd6SJoe Komlodi (SHARED_FIELD_EX32(value, RX_DMA_EN) || 604ba2cccd6SJoe Komlodi SHARED_FIELD_EX32(value, TX_DMA_EN))) { 605ba2cccd6SJoe Komlodi qemu_log_mask(LOG_GUEST_ERROR, "%s: No DMA support\n", __func__); 606ba2cccd6SJoe Komlodi break; 607ba2cccd6SJoe Komlodi } 608ba2cccd6SJoe Komlodi 609ba2cccd6SJoe Komlodi if (bus->regs[R_I2CM_INTR_STS] & 0xffff0000) { 610ba2cccd6SJoe Komlodi qemu_log_mask(LOG_UNIMP, "%s: Packet mode is not implemented\n", 611ba2cccd6SJoe Komlodi __func__); 612ba2cccd6SJoe Komlodi break; 613ba2cccd6SJoe Komlodi } 614ba2cccd6SJoe Komlodi 615ba2cccd6SJoe Komlodi value &= 0xff0ffbfb; 616ba2cccd6SJoe Komlodi if (ARRAY_FIELD_EX32(bus->regs, I2CM_CMD, W1_CTRL)) { 617ba2cccd6SJoe Komlodi bus->regs[R_I2CM_CMD] |= value; 618ba2cccd6SJoe Komlodi } else { 619ba2cccd6SJoe Komlodi bus->regs[R_I2CM_CMD] = value; 620ba2cccd6SJoe Komlodi } 621ba2cccd6SJoe Komlodi 622ba2cccd6SJoe Komlodi aspeed_i2c_bus_handle_cmd(bus, value); 623ba2cccd6SJoe Komlodi aspeed_i2c_bus_raise_interrupt(bus); 624ba2cccd6SJoe Komlodi break; 625ba2cccd6SJoe Komlodi case A_I2CM_DMA_TX_ADDR: 626ba2cccd6SJoe Komlodi bus->regs[R_I2CM_DMA_TX_ADDR] = FIELD_EX32(value, I2CM_DMA_TX_ADDR, 627ba2cccd6SJoe Komlodi ADDR); 628ba2cccd6SJoe Komlodi bus->regs[R_I2CC_DMA_ADDR] = FIELD_EX32(value, I2CM_DMA_TX_ADDR, ADDR); 629ba2cccd6SJoe Komlodi bus->regs[R_I2CC_DMA_LEN] = ARRAY_FIELD_EX32(bus->regs, I2CM_DMA_LEN, 630ba2cccd6SJoe Komlodi TX_BUF_LEN) + 1; 631ba2cccd6SJoe Komlodi break; 632ba2cccd6SJoe Komlodi case A_I2CM_DMA_RX_ADDR: 633ba2cccd6SJoe Komlodi bus->regs[R_I2CM_DMA_RX_ADDR] = FIELD_EX32(value, I2CM_DMA_RX_ADDR, 634ba2cccd6SJoe Komlodi ADDR); 635ba2cccd6SJoe Komlodi bus->regs[R_I2CC_DMA_ADDR] = FIELD_EX32(value, I2CM_DMA_RX_ADDR, ADDR); 636ba2cccd6SJoe Komlodi bus->regs[R_I2CC_DMA_LEN] = ARRAY_FIELD_EX32(bus->regs, I2CM_DMA_LEN, 637ba2cccd6SJoe Komlodi RX_BUF_LEN) + 1; 638ba2cccd6SJoe Komlodi break; 639ba2cccd6SJoe Komlodi case A_I2CM_DMA_LEN: 640ba2cccd6SJoe Komlodi w1t = ARRAY_FIELD_EX32(bus->regs, I2CM_DMA_LEN, RX_BUF_LEN_W1T) || 641ba2cccd6SJoe Komlodi ARRAY_FIELD_EX32(bus->regs, I2CM_DMA_LEN, TX_BUF_LEN_W1T); 642ba2cccd6SJoe Komlodi /* If none of the w1t bits are set, just write to the reg as normal. */ 643ba2cccd6SJoe Komlodi if (!w1t) { 644ba2cccd6SJoe Komlodi bus->regs[R_I2CM_DMA_LEN] = value; 645ba2cccd6SJoe Komlodi break; 646ba2cccd6SJoe Komlodi } 647ba2cccd6SJoe Komlodi if (ARRAY_FIELD_EX32(bus->regs, I2CM_DMA_LEN, RX_BUF_LEN_W1T)) { 648ba2cccd6SJoe Komlodi ARRAY_FIELD_DP32(bus->regs, I2CM_DMA_LEN, RX_BUF_LEN, 649ba2cccd6SJoe Komlodi FIELD_EX32(value, I2CM_DMA_LEN, RX_BUF_LEN)); 650ba2cccd6SJoe Komlodi } 651ba2cccd6SJoe Komlodi if (ARRAY_FIELD_EX32(bus->regs, I2CM_DMA_LEN, TX_BUF_LEN_W1T)) { 652ba2cccd6SJoe Komlodi ARRAY_FIELD_DP32(bus->regs, I2CM_DMA_LEN, TX_BUF_LEN, 653ba2cccd6SJoe Komlodi FIELD_EX32(value, I2CM_DMA_LEN, TX_BUF_LEN)); 654ba2cccd6SJoe Komlodi } 655ba2cccd6SJoe Komlodi break; 656ba2cccd6SJoe Komlodi case A_I2CM_DMA_LEN_STS: 657ba2cccd6SJoe Komlodi /* Writes clear to 0 */ 658ba2cccd6SJoe Komlodi bus->regs[R_I2CM_DMA_LEN_STS] = 0; 659ba2cccd6SJoe Komlodi break; 660ba2cccd6SJoe Komlodi case A_I2CC_DMA_ADDR: 661ba2cccd6SJoe Komlodi case A_I2CC_DMA_LEN: 662ba2cccd6SJoe Komlodi /* RO */ 663ba2cccd6SJoe Komlodi break; 664ba2cccd6SJoe Komlodi case A_I2CS_DMA_LEN_STS: 665ba2cccd6SJoe Komlodi case A_I2CS_DMA_TX_ADDR: 666ba2cccd6SJoe Komlodi case A_I2CS_DMA_RX_ADDR: 667ba2cccd6SJoe Komlodi case A_I2CS_DEV_ADDR: 668ba2cccd6SJoe Komlodi case A_I2CS_INTR_CTRL: 669ba2cccd6SJoe Komlodi case A_I2CS_INTR_STS: 670ba2cccd6SJoe Komlodi case A_I2CS_CMD: 671ba2cccd6SJoe Komlodi case A_I2CS_DMA_LEN: 672ba2cccd6SJoe Komlodi qemu_log_mask(LOG_UNIMP, "%s: Slave mode is not implemented\n", 673ba2cccd6SJoe Komlodi __func__); 674ba2cccd6SJoe Komlodi break; 675ba2cccd6SJoe Komlodi default: 676ba2cccd6SJoe Komlodi qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad offset 0x%" HWADDR_PRIx "\n", 677ba2cccd6SJoe Komlodi __func__, offset); 678ba2cccd6SJoe Komlodi } 679ba2cccd6SJoe Komlodi } 680ba2cccd6SJoe Komlodi 681ba2cccd6SJoe Komlodi static void aspeed_i2c_bus_old_write(AspeedI2CBus *bus, hwaddr offset, 682ba2cccd6SJoe Komlodi uint64_t value, unsigned size) 683ba2cccd6SJoe Komlodi { 68451dd4923SCédric Le Goater AspeedI2CClass *aic = ASPEED_I2C_GET_CLASS(bus->controller); 685bb626e5bSGuenter Roeck bool handle_rx; 68616020011SCédric Le Goater 68766cc84a1SCédric Le Goater trace_aspeed_i2c_bus_write(bus->id, offset, size, value); 68866cc84a1SCédric Le Goater 68916020011SCédric Le Goater switch (offset) { 6903be3d6ccSJoe Komlodi case A_I2CD_FUN_CTRL: 691ba2cccd6SJoe Komlodi if (SHARED_FIELD_EX32(value, SLAVE_EN)) { 69216020011SCédric Le Goater qemu_log_mask(LOG_UNIMP, "%s: slave mode not implemented\n", 69316020011SCédric Le Goater __func__); 69416020011SCédric Le Goater break; 69516020011SCédric Le Goater } 6962260fc6fSJoe Komlodi bus->regs[R_I2CD_FUN_CTRL] = value & 0x0071C3FF; 69716020011SCédric Le Goater break; 6983be3d6ccSJoe Komlodi case A_I2CD_AC_TIMING1: 6992260fc6fSJoe Komlodi bus->regs[R_I2CD_AC_TIMING1] = value & 0xFFFFF0F; 70016020011SCédric Le Goater break; 7013be3d6ccSJoe Komlodi case A_I2CD_AC_TIMING2: 7022260fc6fSJoe Komlodi bus->regs[R_I2CD_AC_TIMING2] = value & 0x7; 70316020011SCédric Le Goater break; 7043be3d6ccSJoe Komlodi case A_I2CD_INTR_CTRL: 7052260fc6fSJoe Komlodi bus->regs[R_I2CD_INTR_CTRL] = value & 0x7FFF; 70616020011SCédric Le Goater break; 7073be3d6ccSJoe Komlodi case A_I2CD_INTR_STS: 708ba2cccd6SJoe Komlodi handle_rx = SHARED_ARRAY_FIELD_EX32(bus->regs, R_I2CD_INTR_STS, RX_DONE) 709ba2cccd6SJoe Komlodi && SHARED_FIELD_EX32(value, RX_DONE); 7102260fc6fSJoe Komlodi bus->regs[R_I2CD_INTR_STS] &= ~(value & 0x7FFF); 7112260fc6fSJoe Komlodi if (!bus->regs[R_I2CD_INTR_STS]) { 71216020011SCédric Le Goater bus->controller->intr_status &= ~(1 << bus->id); 71351dd4923SCédric Le Goater qemu_irq_lower(aic->bus_get_irq(bus)); 7145540cb97SCédric Le Goater } 715ba2cccd6SJoe Komlodi if (handle_rx && (SHARED_ARRAY_FIELD_EX32(bus->regs, R_I2CD_CMD, 716ba2cccd6SJoe Komlodi M_RX_CMD) || 717ba2cccd6SJoe Komlodi SHARED_ARRAY_FIELD_EX32(bus->regs, R_I2CD_CMD, 718ba2cccd6SJoe Komlodi M_S_RX_CMD_LAST))) { 719bb626e5bSGuenter Roeck aspeed_i2c_handle_rx_cmd(bus); 720bb626e5bSGuenter Roeck aspeed_i2c_bus_raise_interrupt(bus); 721bb626e5bSGuenter Roeck } 72216020011SCédric Le Goater break; 7233be3d6ccSJoe Komlodi case A_I2CD_DEV_ADDR: 724*d72a712cSKlaus Jensen bus->regs[R_I2CD_DEV_ADDR] = value; 72516020011SCédric Le Goater break; 7263be3d6ccSJoe Komlodi case A_I2CD_POOL_CTRL: 7272260fc6fSJoe Komlodi bus->regs[R_I2CD_POOL_CTRL] &= ~0xffffff; 7282260fc6fSJoe Komlodi bus->regs[R_I2CD_POOL_CTRL] |= (value & 0xffffff); 7296054fc73SCédric Le Goater break; 7306054fc73SCédric Le Goater 7313be3d6ccSJoe Komlodi case A_I2CD_BYTE_BUF: 732ba2cccd6SJoe Komlodi SHARED_ARRAY_FIELD_DP32(bus->regs, R_I2CD_BYTE_BUF, TX_BUF, value); 73316020011SCédric Le Goater break; 7343be3d6ccSJoe Komlodi case A_I2CD_CMD: 73516020011SCédric Le Goater if (!aspeed_i2c_bus_is_enabled(bus)) { 73616020011SCédric Le Goater break; 73716020011SCédric Le Goater } 73816020011SCédric Le Goater 73916020011SCédric Le Goater if (!aspeed_i2c_bus_is_master(bus)) { 74016020011SCédric Le Goater qemu_log_mask(LOG_UNIMP, "%s: slave mode not implemented\n", 74116020011SCédric Le Goater __func__); 74216020011SCédric Le Goater break; 74316020011SCédric Le Goater } 74416020011SCédric Le Goater 745545d6befSCédric Le Goater if (!aic->has_dma && 746ba2cccd6SJoe Komlodi (SHARED_FIELD_EX32(value, RX_DMA_EN) || 747ba2cccd6SJoe Komlodi SHARED_FIELD_EX32(value, TX_DMA_EN))) { 748545d6befSCédric Le Goater qemu_log_mask(LOG_GUEST_ERROR, "%s: No DMA support\n", __func__); 749545d6befSCédric Le Goater break; 750545d6befSCédric Le Goater } 751545d6befSCédric Le Goater 752ba2cccd6SJoe Komlodi bus->regs[R_I2CD_CMD] &= ~0xFFFF; 753ba2cccd6SJoe Komlodi bus->regs[R_I2CD_CMD] |= value & 0xFFFF; 754ba2cccd6SJoe Komlodi 75516020011SCédric Le Goater aspeed_i2c_bus_handle_cmd(bus, value); 756ddabca75SCédric Le Goater aspeed_i2c_bus_raise_interrupt(bus); 75716020011SCédric Le Goater break; 7583be3d6ccSJoe Komlodi case A_I2CD_DMA_ADDR: 759545d6befSCédric Le Goater if (!aic->has_dma) { 760545d6befSCédric Le Goater qemu_log_mask(LOG_GUEST_ERROR, "%s: No DMA support\n", __func__); 761545d6befSCédric Le Goater break; 762545d6befSCédric Le Goater } 763545d6befSCédric Le Goater 7642260fc6fSJoe Komlodi bus->regs[R_I2CD_DMA_ADDR] = value & 0x3ffffffc; 765545d6befSCédric Le Goater break; 766545d6befSCédric Le Goater 7673be3d6ccSJoe Komlodi case A_I2CD_DMA_LEN: 768545d6befSCédric Le Goater if (!aic->has_dma) { 769545d6befSCédric Le Goater qemu_log_mask(LOG_GUEST_ERROR, "%s: No DMA support\n", __func__); 770545d6befSCédric Le Goater break; 771545d6befSCédric Le Goater } 772545d6befSCédric Le Goater 7732260fc6fSJoe Komlodi bus->regs[R_I2CD_DMA_LEN] = value & 0xfff; 7742260fc6fSJoe Komlodi if (!bus->regs[R_I2CD_DMA_LEN]) { 775545d6befSCédric Le Goater qemu_log_mask(LOG_UNIMP, "%s: invalid DMA length\n", __func__); 776545d6befSCédric Le Goater } 777545d6befSCédric Le Goater break; 77816020011SCédric Le Goater 77916020011SCédric Le Goater default: 78016020011SCédric Le Goater qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad offset 0x%" HWADDR_PRIx "\n", 78116020011SCédric Le Goater __func__, offset); 78216020011SCédric Le Goater } 78316020011SCédric Le Goater } 78416020011SCédric Le Goater 785ba2cccd6SJoe Komlodi static void aspeed_i2c_bus_write(void *opaque, hwaddr offset, 786ba2cccd6SJoe Komlodi uint64_t value, unsigned size) 787ba2cccd6SJoe Komlodi { 788ba2cccd6SJoe Komlodi AspeedI2CBus *bus = opaque; 789ba2cccd6SJoe Komlodi if (aspeed_i2c_is_new_mode(bus->controller)) { 790ba2cccd6SJoe Komlodi aspeed_i2c_bus_new_write(bus, offset, value, size); 791ba2cccd6SJoe Komlodi } else { 792ba2cccd6SJoe Komlodi aspeed_i2c_bus_old_write(bus, offset, value, size); 793ba2cccd6SJoe Komlodi } 794ba2cccd6SJoe Komlodi } 795ba2cccd6SJoe Komlodi 79616020011SCédric Le Goater static uint64_t aspeed_i2c_ctrl_read(void *opaque, hwaddr offset, 79716020011SCédric Le Goater unsigned size) 79816020011SCédric Le Goater { 79916020011SCédric Le Goater AspeedI2CState *s = opaque; 80016020011SCédric Le Goater 80116020011SCédric Le Goater switch (offset) { 8023be3d6ccSJoe Komlodi case A_I2C_CTRL_STATUS: 80316020011SCédric Le Goater return s->intr_status; 8043be3d6ccSJoe Komlodi case A_I2C_CTRL_GLOBAL: 805aab90b1cSCédric Le Goater return s->ctrl_global; 806ba2cccd6SJoe Komlodi case A_I2C_CTRL_NEW_CLK_DIVIDER: 807ba2cccd6SJoe Komlodi if (aspeed_i2c_is_new_mode(s)) { 808ba2cccd6SJoe Komlodi return s->new_clk_divider; 809ba2cccd6SJoe Komlodi } 810ba2cccd6SJoe Komlodi qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad offset 0x%" HWADDR_PRIx "\n", 811ba2cccd6SJoe Komlodi __func__, offset); 812ba2cccd6SJoe Komlodi break; 81316020011SCédric Le Goater default: 81416020011SCédric Le Goater qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad offset 0x%" HWADDR_PRIx "\n", 81516020011SCédric Le Goater __func__, offset); 81616020011SCédric Le Goater break; 81716020011SCédric Le Goater } 81816020011SCédric Le Goater 81916020011SCédric Le Goater return -1; 82016020011SCédric Le Goater } 82116020011SCédric Le Goater 82216020011SCédric Le Goater static void aspeed_i2c_ctrl_write(void *opaque, hwaddr offset, 82316020011SCédric Le Goater uint64_t value, unsigned size) 82416020011SCédric Le Goater { 825aab90b1cSCédric Le Goater AspeedI2CState *s = opaque; 826aab90b1cSCédric Le Goater 82716020011SCédric Le Goater switch (offset) { 8283be3d6ccSJoe Komlodi case A_I2C_CTRL_GLOBAL: 829aab90b1cSCédric Le Goater s->ctrl_global = value; 830aab90b1cSCédric Le Goater break; 831ba2cccd6SJoe Komlodi case A_I2C_CTRL_NEW_CLK_DIVIDER: 832ba2cccd6SJoe Komlodi if (aspeed_i2c_is_new_mode(s)) { 833ba2cccd6SJoe Komlodi s->new_clk_divider = value; 834ba2cccd6SJoe Komlodi } else { 835ba2cccd6SJoe Komlodi qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad offset 0x%" HWADDR_PRIx 836ba2cccd6SJoe Komlodi "\n", __func__, offset); 837ba2cccd6SJoe Komlodi } 838ba2cccd6SJoe Komlodi break; 8393be3d6ccSJoe Komlodi case A_I2C_CTRL_STATUS: 84016020011SCédric Le Goater default: 84116020011SCédric Le Goater qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad offset 0x%" HWADDR_PRIx "\n", 84216020011SCédric Le Goater __func__, offset); 84316020011SCédric Le Goater break; 84416020011SCédric Le Goater } 84516020011SCédric Le Goater } 84616020011SCédric Le Goater 84716020011SCédric Le Goater static const MemoryRegionOps aspeed_i2c_bus_ops = { 84816020011SCédric Le Goater .read = aspeed_i2c_bus_read, 84916020011SCédric Le Goater .write = aspeed_i2c_bus_write, 85016020011SCédric Le Goater .endianness = DEVICE_LITTLE_ENDIAN, 85116020011SCédric Le Goater }; 85216020011SCédric Le Goater 85316020011SCédric Le Goater static const MemoryRegionOps aspeed_i2c_ctrl_ops = { 85416020011SCédric Le Goater .read = aspeed_i2c_ctrl_read, 85516020011SCédric Le Goater .write = aspeed_i2c_ctrl_write, 85616020011SCédric Le Goater .endianness = DEVICE_LITTLE_ENDIAN, 85716020011SCédric Le Goater }; 85816020011SCédric Le Goater 8596054fc73SCédric Le Goater static uint64_t aspeed_i2c_pool_read(void *opaque, hwaddr offset, 8606054fc73SCédric Le Goater unsigned size) 8616054fc73SCédric Le Goater { 8626054fc73SCédric Le Goater AspeedI2CState *s = opaque; 8636054fc73SCédric Le Goater uint64_t ret = 0; 8646054fc73SCédric Le Goater int i; 8656054fc73SCédric Le Goater 8666054fc73SCédric Le Goater for (i = 0; i < size; i++) { 8676054fc73SCédric Le Goater ret |= (uint64_t) s->pool[offset + i] << (8 * i); 8686054fc73SCédric Le Goater } 8696054fc73SCédric Le Goater 8706054fc73SCédric Le Goater return ret; 8716054fc73SCédric Le Goater } 8726054fc73SCédric Le Goater 8736054fc73SCédric Le Goater static void aspeed_i2c_pool_write(void *opaque, hwaddr offset, 8746054fc73SCédric Le Goater uint64_t value, unsigned size) 8756054fc73SCédric Le Goater { 8766054fc73SCédric Le Goater AspeedI2CState *s = opaque; 8776054fc73SCédric Le Goater int i; 8786054fc73SCédric Le Goater 8796054fc73SCédric Le Goater for (i = 0; i < size; i++) { 8806054fc73SCédric Le Goater s->pool[offset + i] = (value >> (8 * i)) & 0xFF; 8816054fc73SCédric Le Goater } 8826054fc73SCédric Le Goater } 8836054fc73SCédric Le Goater 8846054fc73SCédric Le Goater static const MemoryRegionOps aspeed_i2c_pool_ops = { 8856054fc73SCédric Le Goater .read = aspeed_i2c_pool_read, 8866054fc73SCédric Le Goater .write = aspeed_i2c_pool_write, 8876054fc73SCédric Le Goater .endianness = DEVICE_LITTLE_ENDIAN, 8886054fc73SCédric Le Goater .valid = { 8896054fc73SCédric Le Goater .min_access_size = 1, 8906054fc73SCédric Le Goater .max_access_size = 4, 8916054fc73SCédric Le Goater }, 8926054fc73SCédric Le Goater }; 8936054fc73SCédric Le Goater 89416020011SCédric Le Goater static const VMStateDescription aspeed_i2c_bus_vmstate = { 89516020011SCédric Le Goater .name = TYPE_ASPEED_I2C, 896ba2cccd6SJoe Komlodi .version_id = 5, 897ba2cccd6SJoe Komlodi .minimum_version_id = 5, 89816020011SCédric Le Goater .fields = (VMStateField[]) { 899ba2cccd6SJoe Komlodi VMSTATE_UINT32_ARRAY(regs, AspeedI2CBus, ASPEED_I2C_NEW_NUM_REG), 90016020011SCédric Le Goater VMSTATE_END_OF_LIST() 90116020011SCédric Le Goater } 90216020011SCédric Le Goater }; 90316020011SCédric Le Goater 90416020011SCédric Le Goater static const VMStateDescription aspeed_i2c_vmstate = { 90516020011SCédric Le Goater .name = TYPE_ASPEED_I2C, 9066054fc73SCédric Le Goater .version_id = 2, 9076054fc73SCédric Le Goater .minimum_version_id = 2, 90816020011SCédric Le Goater .fields = (VMStateField[]) { 90916020011SCédric Le Goater VMSTATE_UINT32(intr_status, AspeedI2CState), 91016020011SCédric Le Goater VMSTATE_STRUCT_ARRAY(busses, AspeedI2CState, 91116020011SCédric Le Goater ASPEED_I2C_NR_BUSSES, 1, aspeed_i2c_bus_vmstate, 91216020011SCédric Le Goater AspeedI2CBus), 9136054fc73SCédric Le Goater VMSTATE_UINT8_ARRAY(pool, AspeedI2CState, ASPEED_I2C_MAX_POOL_SIZE), 91416020011SCédric Le Goater VMSTATE_END_OF_LIST() 91516020011SCédric Le Goater } 91616020011SCédric Le Goater }; 91716020011SCédric Le Goater 91816020011SCédric Le Goater static void aspeed_i2c_reset(DeviceState *dev) 91916020011SCédric Le Goater { 92016020011SCédric Le Goater AspeedI2CState *s = ASPEED_I2C(dev); 92116020011SCédric Le Goater 92216020011SCédric Le Goater s->intr_status = 0; 92360261038SCédric Le Goater } 92460261038SCédric Le Goater 92560261038SCédric Le Goater static void aspeed_i2c_instance_init(Object *obj) 92660261038SCédric Le Goater { 92760261038SCédric Le Goater AspeedI2CState *s = ASPEED_I2C(obj); 92860261038SCédric Le Goater AspeedI2CClass *aic = ASPEED_I2C_GET_CLASS(s); 92960261038SCédric Le Goater int i; 93016020011SCédric Le Goater 931f7da1aa8SCédric Le Goater for (i = 0; i < aic->num_busses; i++) { 93260261038SCédric Le Goater object_initialize_child(obj, "bus[*]", &s->busses[i], 93360261038SCédric Le Goater TYPE_ASPEED_I2C_BUS); 93416020011SCédric Le Goater } 93516020011SCédric Le Goater } 93616020011SCédric Le Goater 93716020011SCédric Le Goater /* 938f7da1aa8SCédric Le Goater * Address Definitions (AST2400 and AST2500) 93916020011SCédric Le Goater * 94016020011SCédric Le Goater * 0x000 ... 0x03F: Global Register 94116020011SCédric Le Goater * 0x040 ... 0x07F: Device 1 94216020011SCédric Le Goater * 0x080 ... 0x0BF: Device 2 94316020011SCédric Le Goater * 0x0C0 ... 0x0FF: Device 3 94416020011SCédric Le Goater * 0x100 ... 0x13F: Device 4 94516020011SCédric Le Goater * 0x140 ... 0x17F: Device 5 94616020011SCédric Le Goater * 0x180 ... 0x1BF: Device 6 94716020011SCédric Le Goater * 0x1C0 ... 0x1FF: Device 7 94816020011SCédric Le Goater * 0x200 ... 0x2FF: Buffer Pool (unused in linux driver) 94916020011SCédric Le Goater * 0x300 ... 0x33F: Device 8 95016020011SCédric Le Goater * 0x340 ... 0x37F: Device 9 95116020011SCédric Le Goater * 0x380 ... 0x3BF: Device 10 95216020011SCédric Le Goater * 0x3C0 ... 0x3FF: Device 11 95316020011SCédric Le Goater * 0x400 ... 0x43F: Device 12 95416020011SCédric Le Goater * 0x440 ... 0x47F: Device 13 95516020011SCédric Le Goater * 0x480 ... 0x4BF: Device 14 95616020011SCédric Le Goater * 0x800 ... 0xFFF: Buffer Pool (unused in linux driver) 95716020011SCédric Le Goater */ 95816020011SCédric Le Goater static void aspeed_i2c_realize(DeviceState *dev, Error **errp) 95916020011SCédric Le Goater { 96016020011SCédric Le Goater int i; 96116020011SCédric Le Goater SysBusDevice *sbd = SYS_BUS_DEVICE(dev); 96216020011SCédric Le Goater AspeedI2CState *s = ASPEED_I2C(dev); 963f7da1aa8SCédric Le Goater AspeedI2CClass *aic = ASPEED_I2C_GET_CLASS(s); 96416020011SCédric Le Goater 96516020011SCédric Le Goater sysbus_init_irq(sbd, &s->irq); 96616020011SCédric Le Goater memory_region_init_io(&s->iomem, OBJECT(s), &aspeed_i2c_ctrl_ops, s, 96716020011SCédric Le Goater "aspeed.i2c", 0x1000); 96816020011SCédric Le Goater sysbus_init_mmio(sbd, &s->iomem); 96916020011SCédric Le Goater 970f7da1aa8SCédric Le Goater for (i = 0; i < aic->num_busses; i++) { 97160261038SCédric Le Goater Object *bus = OBJECT(&s->busses[i]); 972f7da1aa8SCédric Le Goater int offset = i < aic->gap ? 1 : 5; 97351dd4923SCédric Le Goater 97460261038SCédric Le Goater if (!object_property_set_link(bus, "controller", OBJECT(s), errp)) { 97560261038SCédric Le Goater return; 97660261038SCédric Le Goater } 97760261038SCédric Le Goater 97860261038SCédric Le Goater if (!object_property_set_uint(bus, "bus-id", i, errp)) { 97960261038SCédric Le Goater return; 98060261038SCédric Le Goater } 98160261038SCédric Le Goater 98260261038SCédric Le Goater if (!sysbus_realize(SYS_BUS_DEVICE(bus), errp)) { 98360261038SCédric Le Goater return; 98460261038SCédric Le Goater } 98560261038SCédric Le Goater 986f7da1aa8SCédric Le Goater memory_region_add_subregion(&s->iomem, aic->reg_size * (i + offset), 98716020011SCédric Le Goater &s->busses[i].mr); 98816020011SCédric Le Goater } 9896054fc73SCédric Le Goater 9906054fc73SCédric Le Goater memory_region_init_io(&s->pool_iomem, OBJECT(s), &aspeed_i2c_pool_ops, s, 9916054fc73SCédric Le Goater "aspeed.i2c-pool", aic->pool_size); 9926054fc73SCédric Le Goater memory_region_add_subregion(&s->iomem, aic->pool_base, &s->pool_iomem); 993545d6befSCédric Le Goater 994545d6befSCédric Le Goater if (aic->has_dma) { 995545d6befSCédric Le Goater if (!s->dram_mr) { 996545d6befSCédric Le Goater error_setg(errp, TYPE_ASPEED_I2C ": 'dram' link not set"); 997545d6befSCédric Le Goater return; 99816020011SCédric Le Goater } 99916020011SCédric Le Goater 10003f7a53b2SCédric Le Goater address_space_init(&s->dram_as, s->dram_mr, 10013f7a53b2SCédric Le Goater TYPE_ASPEED_I2C "-dma-dram"); 1002545d6befSCédric Le Goater } 1003545d6befSCédric Le Goater } 1004545d6befSCédric Le Goater 1005545d6befSCédric Le Goater static Property aspeed_i2c_properties[] = { 1006545d6befSCédric Le Goater DEFINE_PROP_LINK("dram", AspeedI2CState, dram_mr, 1007545d6befSCédric Le Goater TYPE_MEMORY_REGION, MemoryRegion *), 1008545d6befSCédric Le Goater DEFINE_PROP_END_OF_LIST(), 1009545d6befSCédric Le Goater }; 1010545d6befSCédric Le Goater 101116020011SCédric Le Goater static void aspeed_i2c_class_init(ObjectClass *klass, void *data) 101216020011SCédric Le Goater { 101316020011SCédric Le Goater DeviceClass *dc = DEVICE_CLASS(klass); 101416020011SCédric Le Goater 101516020011SCédric Le Goater dc->vmsd = &aspeed_i2c_vmstate; 101616020011SCédric Le Goater dc->reset = aspeed_i2c_reset; 10174f67d30bSMarc-André Lureau device_class_set_props(dc, aspeed_i2c_properties); 101816020011SCédric Le Goater dc->realize = aspeed_i2c_realize; 101916020011SCédric Le Goater dc->desc = "Aspeed I2C Controller"; 102016020011SCédric Le Goater } 102116020011SCédric Le Goater 102216020011SCédric Le Goater static const TypeInfo aspeed_i2c_info = { 102316020011SCédric Le Goater .name = TYPE_ASPEED_I2C, 102416020011SCédric Le Goater .parent = TYPE_SYS_BUS_DEVICE, 102560261038SCédric Le Goater .instance_init = aspeed_i2c_instance_init, 102616020011SCédric Le Goater .instance_size = sizeof(AspeedI2CState), 102716020011SCédric Le Goater .class_init = aspeed_i2c_class_init, 1028f7da1aa8SCédric Le Goater .class_size = sizeof(AspeedI2CClass), 1029f7da1aa8SCédric Le Goater .abstract = true, 1030f7da1aa8SCédric Le Goater }; 1031f7da1aa8SCédric Le Goater 103260261038SCédric Le Goater static void aspeed_i2c_bus_reset(DeviceState *dev) 103360261038SCédric Le Goater { 103460261038SCédric Le Goater AspeedI2CBus *s = ASPEED_I2C_BUS(dev); 103560261038SCédric Le Goater 10362260fc6fSJoe Komlodi memset(s->regs, 0, sizeof(s->regs)); 103760261038SCédric Le Goater i2c_end_transfer(s->bus); 103860261038SCédric Le Goater } 103960261038SCédric Le Goater 104060261038SCédric Le Goater static void aspeed_i2c_bus_realize(DeviceState *dev, Error **errp) 104160261038SCédric Le Goater { 104260261038SCédric Le Goater AspeedI2CBus *s = ASPEED_I2C_BUS(dev); 104360261038SCédric Le Goater AspeedI2CClass *aic; 104460261038SCédric Le Goater g_autofree char *name = g_strdup_printf(TYPE_ASPEED_I2C_BUS ".%d", s->id); 104560261038SCédric Le Goater 104660261038SCédric Le Goater if (!s->controller) { 104760261038SCédric Le Goater error_setg(errp, TYPE_ASPEED_I2C_BUS ": 'controller' link not set"); 104860261038SCédric Le Goater return; 104960261038SCédric Le Goater } 105060261038SCédric Le Goater 105160261038SCédric Le Goater aic = ASPEED_I2C_GET_CLASS(s->controller); 105260261038SCédric Le Goater 105360261038SCédric Le Goater sysbus_init_irq(SYS_BUS_DEVICE(dev), &s->irq); 105460261038SCédric Le Goater 105560261038SCédric Le Goater s->bus = i2c_init_bus(dev, name); 105660261038SCédric Le Goater 105760261038SCédric Le Goater memory_region_init_io(&s->mr, OBJECT(s), &aspeed_i2c_bus_ops, 105860261038SCédric Le Goater s, name, aic->reg_size); 105960261038SCédric Le Goater sysbus_init_mmio(SYS_BUS_DEVICE(dev), &s->mr); 106060261038SCédric Le Goater } 106160261038SCédric Le Goater 106260261038SCédric Le Goater static Property aspeed_i2c_bus_properties[] = { 106360261038SCédric Le Goater DEFINE_PROP_UINT8("bus-id", AspeedI2CBus, id, 0), 106460261038SCédric Le Goater DEFINE_PROP_LINK("controller", AspeedI2CBus, controller, TYPE_ASPEED_I2C, 106560261038SCédric Le Goater AspeedI2CState *), 106660261038SCédric Le Goater DEFINE_PROP_END_OF_LIST(), 106760261038SCédric Le Goater }; 106860261038SCédric Le Goater 106960261038SCédric Le Goater static void aspeed_i2c_bus_class_init(ObjectClass *klass, void *data) 107060261038SCédric Le Goater { 107160261038SCédric Le Goater DeviceClass *dc = DEVICE_CLASS(klass); 107260261038SCédric Le Goater 107360261038SCédric Le Goater dc->desc = "Aspeed I2C Bus"; 107460261038SCédric Le Goater dc->realize = aspeed_i2c_bus_realize; 107560261038SCédric Le Goater dc->reset = aspeed_i2c_bus_reset; 107660261038SCédric Le Goater device_class_set_props(dc, aspeed_i2c_bus_properties); 107760261038SCédric Le Goater } 107860261038SCédric Le Goater 107960261038SCédric Le Goater static const TypeInfo aspeed_i2c_bus_info = { 108060261038SCédric Le Goater .name = TYPE_ASPEED_I2C_BUS, 108160261038SCédric Le Goater .parent = TYPE_SYS_BUS_DEVICE, 108260261038SCédric Le Goater .instance_size = sizeof(AspeedI2CBus), 108360261038SCédric Le Goater .class_init = aspeed_i2c_bus_class_init, 108460261038SCédric Le Goater }; 108560261038SCédric Le Goater 108651dd4923SCédric Le Goater static qemu_irq aspeed_2400_i2c_bus_get_irq(AspeedI2CBus *bus) 108751dd4923SCédric Le Goater { 108851dd4923SCédric Le Goater return bus->controller->irq; 108951dd4923SCédric Le Goater } 109051dd4923SCédric Le Goater 10916054fc73SCédric Le Goater static uint8_t *aspeed_2400_i2c_bus_pool_base(AspeedI2CBus *bus) 10926054fc73SCédric Le Goater { 10936054fc73SCédric Le Goater uint8_t *pool_page = 10942260fc6fSJoe Komlodi &bus->controller->pool[ARRAY_FIELD_EX32(bus->regs, I2CD_FUN_CTRL, 10953be3d6ccSJoe Komlodi POOL_PAGE_SEL) * 0x100]; 10966054fc73SCédric Le Goater 10972260fc6fSJoe Komlodi return &pool_page[ARRAY_FIELD_EX32(bus->regs, I2CD_POOL_CTRL, OFFSET)]; 10986054fc73SCédric Le Goater } 10996054fc73SCédric Le Goater 1100f7da1aa8SCédric Le Goater static void aspeed_2400_i2c_class_init(ObjectClass *klass, void *data) 1101f7da1aa8SCédric Le Goater { 1102f7da1aa8SCédric Le Goater DeviceClass *dc = DEVICE_CLASS(klass); 1103f7da1aa8SCédric Le Goater AspeedI2CClass *aic = ASPEED_I2C_CLASS(klass); 1104f7da1aa8SCédric Le Goater 1105f7da1aa8SCédric Le Goater dc->desc = "ASPEED 2400 I2C Controller"; 1106f7da1aa8SCédric Le Goater 1107f7da1aa8SCédric Le Goater aic->num_busses = 14; 1108f7da1aa8SCédric Le Goater aic->reg_size = 0x40; 1109f7da1aa8SCédric Le Goater aic->gap = 7; 111051dd4923SCédric Le Goater aic->bus_get_irq = aspeed_2400_i2c_bus_get_irq; 11116054fc73SCédric Le Goater aic->pool_size = 0x800; 11126054fc73SCédric Le Goater aic->pool_base = 0x800; 11136054fc73SCédric Le Goater aic->bus_pool_base = aspeed_2400_i2c_bus_pool_base; 1114f7da1aa8SCédric Le Goater } 1115f7da1aa8SCédric Le Goater 1116f7da1aa8SCédric Le Goater static const TypeInfo aspeed_2400_i2c_info = { 1117f7da1aa8SCédric Le Goater .name = TYPE_ASPEED_2400_I2C, 1118f7da1aa8SCédric Le Goater .parent = TYPE_ASPEED_I2C, 1119f7da1aa8SCédric Le Goater .class_init = aspeed_2400_i2c_class_init, 1120f7da1aa8SCédric Le Goater }; 1121f7da1aa8SCédric Le Goater 112251dd4923SCédric Le Goater static qemu_irq aspeed_2500_i2c_bus_get_irq(AspeedI2CBus *bus) 112351dd4923SCédric Le Goater { 112451dd4923SCédric Le Goater return bus->controller->irq; 112551dd4923SCédric Le Goater } 112651dd4923SCédric Le Goater 11276054fc73SCédric Le Goater static uint8_t *aspeed_2500_i2c_bus_pool_base(AspeedI2CBus *bus) 11286054fc73SCédric Le Goater { 11296054fc73SCédric Le Goater return &bus->controller->pool[bus->id * 0x10]; 11306054fc73SCédric Le Goater } 11316054fc73SCédric Le Goater 1132f7da1aa8SCédric Le Goater static void aspeed_2500_i2c_class_init(ObjectClass *klass, void *data) 1133f7da1aa8SCédric Le Goater { 1134f7da1aa8SCédric Le Goater DeviceClass *dc = DEVICE_CLASS(klass); 1135f7da1aa8SCédric Le Goater AspeedI2CClass *aic = ASPEED_I2C_CLASS(klass); 1136f7da1aa8SCédric Le Goater 1137f7da1aa8SCédric Le Goater dc->desc = "ASPEED 2500 I2C Controller"; 1138f7da1aa8SCédric Le Goater 1139f7da1aa8SCédric Le Goater aic->num_busses = 14; 1140f7da1aa8SCédric Le Goater aic->reg_size = 0x40; 1141f7da1aa8SCédric Le Goater aic->gap = 7; 114251dd4923SCédric Le Goater aic->bus_get_irq = aspeed_2500_i2c_bus_get_irq; 11436054fc73SCédric Le Goater aic->pool_size = 0x100; 11446054fc73SCédric Le Goater aic->pool_base = 0x200; 11456054fc73SCédric Le Goater aic->bus_pool_base = aspeed_2500_i2c_bus_pool_base; 1146aab90b1cSCédric Le Goater aic->check_sram = true; 1147545d6befSCédric Le Goater aic->has_dma = true; 1148f7da1aa8SCédric Le Goater } 1149f7da1aa8SCédric Le Goater 1150f7da1aa8SCédric Le Goater static const TypeInfo aspeed_2500_i2c_info = { 1151f7da1aa8SCédric Le Goater .name = TYPE_ASPEED_2500_I2C, 1152f7da1aa8SCédric Le Goater .parent = TYPE_ASPEED_I2C, 1153f7da1aa8SCédric Le Goater .class_init = aspeed_2500_i2c_class_init, 115416020011SCédric Le Goater }; 115516020011SCédric Le Goater 115651dd4923SCédric Le Goater static qemu_irq aspeed_2600_i2c_bus_get_irq(AspeedI2CBus *bus) 115751dd4923SCédric Le Goater { 115851dd4923SCédric Le Goater return bus->irq; 115951dd4923SCédric Le Goater } 116051dd4923SCédric Le Goater 11616054fc73SCédric Le Goater static uint8_t *aspeed_2600_i2c_bus_pool_base(AspeedI2CBus *bus) 11626054fc73SCédric Le Goater { 11636054fc73SCédric Le Goater return &bus->controller->pool[bus->id * 0x20]; 11646054fc73SCédric Le Goater } 11656054fc73SCédric Le Goater 116651dd4923SCédric Le Goater static void aspeed_2600_i2c_class_init(ObjectClass *klass, void *data) 116751dd4923SCédric Le Goater { 116851dd4923SCédric Le Goater DeviceClass *dc = DEVICE_CLASS(klass); 116951dd4923SCédric Le Goater AspeedI2CClass *aic = ASPEED_I2C_CLASS(klass); 117051dd4923SCédric Le Goater 117151dd4923SCédric Le Goater dc->desc = "ASPEED 2600 I2C Controller"; 117251dd4923SCédric Le Goater 117351dd4923SCédric Le Goater aic->num_busses = 16; 117451dd4923SCédric Le Goater aic->reg_size = 0x80; 117551dd4923SCédric Le Goater aic->gap = -1; /* no gap */ 117651dd4923SCédric Le Goater aic->bus_get_irq = aspeed_2600_i2c_bus_get_irq; 11776054fc73SCédric Le Goater aic->pool_size = 0x200; 11786054fc73SCédric Le Goater aic->pool_base = 0xC00; 11796054fc73SCédric Le Goater aic->bus_pool_base = aspeed_2600_i2c_bus_pool_base; 1180545d6befSCédric Le Goater aic->has_dma = true; 118151dd4923SCédric Le Goater } 118251dd4923SCédric Le Goater 118351dd4923SCédric Le Goater static const TypeInfo aspeed_2600_i2c_info = { 118451dd4923SCédric Le Goater .name = TYPE_ASPEED_2600_I2C, 118551dd4923SCédric Le Goater .parent = TYPE_ASPEED_I2C, 118651dd4923SCédric Le Goater .class_init = aspeed_2600_i2c_class_init, 118751dd4923SCédric Le Goater }; 118851dd4923SCédric Le Goater 1189b35802ceSCédric Le Goater static void aspeed_1030_i2c_class_init(ObjectClass *klass, void *data) 1190b35802ceSCédric Le Goater { 1191b35802ceSCédric Le Goater DeviceClass *dc = DEVICE_CLASS(klass); 1192b35802ceSCédric Le Goater AspeedI2CClass *aic = ASPEED_I2C_CLASS(klass); 1193b35802ceSCédric Le Goater 1194b35802ceSCédric Le Goater dc->desc = "ASPEED 1030 I2C Controller"; 1195b35802ceSCédric Le Goater 1196b35802ceSCédric Le Goater aic->num_busses = 14; 1197b35802ceSCédric Le Goater aic->reg_size = 0x80; 1198b35802ceSCédric Le Goater aic->gap = -1; /* no gap */ 1199b35802ceSCédric Le Goater aic->bus_get_irq = aspeed_2600_i2c_bus_get_irq; 1200b35802ceSCédric Le Goater aic->pool_size = 0x200; 1201b35802ceSCédric Le Goater aic->pool_base = 0xC00; 1202b35802ceSCédric Le Goater aic->bus_pool_base = aspeed_2600_i2c_bus_pool_base; 1203b35802ceSCédric Le Goater aic->has_dma = true; 1204b35802ceSCédric Le Goater } 1205b35802ceSCédric Le Goater 1206b35802ceSCédric Le Goater static const TypeInfo aspeed_1030_i2c_info = { 1207b35802ceSCédric Le Goater .name = TYPE_ASPEED_1030_I2C, 1208b35802ceSCédric Le Goater .parent = TYPE_ASPEED_I2C, 1209b35802ceSCédric Le Goater .class_init = aspeed_1030_i2c_class_init, 1210b35802ceSCédric Le Goater }; 1211b35802ceSCédric Le Goater 121216020011SCédric Le Goater static void aspeed_i2c_register_types(void) 121316020011SCédric Le Goater { 121460261038SCédric Le Goater type_register_static(&aspeed_i2c_bus_info); 121516020011SCédric Le Goater type_register_static(&aspeed_i2c_info); 1216f7da1aa8SCédric Le Goater type_register_static(&aspeed_2400_i2c_info); 1217f7da1aa8SCédric Le Goater type_register_static(&aspeed_2500_i2c_info); 121851dd4923SCédric Le Goater type_register_static(&aspeed_2600_i2c_info); 1219b35802ceSCédric Le Goater type_register_static(&aspeed_1030_i2c_info); 122016020011SCédric Le Goater } 122116020011SCédric Le Goater 122216020011SCédric Le Goater type_init(aspeed_i2c_register_types) 122316020011SCédric Le Goater 122416020011SCédric Le Goater 12257a204cbdSPhilippe Mathieu-Daudé I2CBus *aspeed_i2c_get_bus(AspeedI2CState *s, int busnr) 122616020011SCédric Le Goater { 1227f7da1aa8SCédric Le Goater AspeedI2CClass *aic = ASPEED_I2C_GET_CLASS(s); 122816020011SCédric Le Goater I2CBus *bus = NULL; 122916020011SCédric Le Goater 1230f7da1aa8SCédric Le Goater if (busnr >= 0 && busnr < aic->num_busses) { 123116020011SCédric Le Goater bus = s->busses[busnr].bus; 123216020011SCédric Le Goater } 123316020011SCédric Le Goater 123416020011SCédric Le Goater return bus; 123516020011SCédric Le Goater } 1236