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" 2416020011SCédric Le Goater #include "qemu/log.h" 250b8fa32fSMarkus Armbruster #include "qemu/module.h" 26545d6befSCédric Le Goater #include "qemu/error-report.h" 27545d6befSCédric Le Goater #include "qapi/error.h" 2816020011SCédric Le Goater #include "hw/i2c/aspeed_i2c.h" 2964552b6bSMarkus Armbruster #include "hw/irq.h" 30545d6befSCédric Le Goater #include "hw/qdev-properties.h" 313be3d6ccSJoe Komlodi #include "hw/registerfields.h" 3266cc84a1SCédric Le Goater #include "trace.h" 3316020011SCédric Le Goater 343be3d6ccSJoe Komlodi /* Tx State Machine */ 3516020011SCédric Le Goater #define I2CD_TX_STATE_MASK 0xf 3616020011SCédric Le Goater #define I2CD_IDLE 0x0 3716020011SCédric Le Goater #define I2CD_MACTIVE 0x8 3816020011SCédric Le Goater #define I2CD_MSTART 0x9 3916020011SCédric Le Goater #define I2CD_MSTARTR 0xa 4016020011SCédric Le Goater #define I2CD_MSTOP 0xb 4116020011SCédric Le Goater #define I2CD_MTXD 0xc 4216020011SCédric Le Goater #define I2CD_MRXACK 0xd 4316020011SCédric Le Goater #define I2CD_MRXD 0xe 4416020011SCédric Le Goater #define I2CD_MTXACK 0xf 4516020011SCédric Le Goater #define I2CD_SWAIT 0x1 4616020011SCédric Le Goater #define I2CD_SRXD 0x4 4716020011SCédric Le Goater #define I2CD_STXACK 0x5 4816020011SCédric Le Goater #define I2CD_STXD 0x6 4916020011SCédric Le Goater #define I2CD_SRXACK 0x7 5016020011SCédric Le Goater #define I2CD_RECOVER 0x3 51ba2cccd6SJoe Komlodi 52ba2cccd6SJoe Komlodi /* I2C Global Register */ 53ba2cccd6SJoe Komlodi REG32(I2C_CTRL_STATUS, 0x0) /* Device Interrupt Status */ 54ba2cccd6SJoe Komlodi REG32(I2C_CTRL_ASSIGN, 0x8) /* Device Interrupt Target Assignment */ 55ba2cccd6SJoe Komlodi REG32(I2C_CTRL_GLOBAL, 0xC) /* Global Control Register */ 56ba2cccd6SJoe Komlodi FIELD(I2C_CTRL_GLOBAL, REG_MODE, 2, 1) 57ba2cccd6SJoe Komlodi FIELD(I2C_CTRL_GLOBAL, SRAM_EN, 0, 1) 58ba2cccd6SJoe Komlodi REG32(I2C_CTRL_NEW_CLK_DIVIDER, 0x10) /* New mode clock divider */ 59ba2cccd6SJoe Komlodi 60ba2cccd6SJoe Komlodi /* I2C Old Mode Device (Bus) Register */ 61ba2cccd6SJoe Komlodi REG32(I2CD_FUN_CTRL, 0x0) /* I2CD Function Control */ 62ba2cccd6SJoe Komlodi FIELD(I2CD_FUN_CTRL, POOL_PAGE_SEL, 20, 3) /* AST2400 */ 63ba2cccd6SJoe Komlodi SHARED_FIELD(M_SDA_LOCK_EN, 16, 1) 64ba2cccd6SJoe Komlodi SHARED_FIELD(MULTI_MASTER_DIS, 15, 1) 65ba2cccd6SJoe Komlodi SHARED_FIELD(M_SCL_DRIVE_EN, 14, 1) 66ba2cccd6SJoe Komlodi SHARED_FIELD(MSB_STS, 9, 1) 67ba2cccd6SJoe Komlodi SHARED_FIELD(SDA_DRIVE_IT_EN, 8, 1) 68ba2cccd6SJoe Komlodi SHARED_FIELD(M_SDA_DRIVE_IT_EN, 7, 1) 69ba2cccd6SJoe Komlodi SHARED_FIELD(M_HIGH_SPEED_EN, 6, 1) 70ba2cccd6SJoe Komlodi SHARED_FIELD(DEF_ADDR_EN, 5, 1) 71ba2cccd6SJoe Komlodi SHARED_FIELD(DEF_ALERT_EN, 4, 1) 72ba2cccd6SJoe Komlodi SHARED_FIELD(DEF_ARP_EN, 3, 1) 73ba2cccd6SJoe Komlodi SHARED_FIELD(DEF_GCALL_EN, 2, 1) 74ba2cccd6SJoe Komlodi SHARED_FIELD(SLAVE_EN, 1, 1) 75ba2cccd6SJoe Komlodi SHARED_FIELD(MASTER_EN, 0, 1) 76ba2cccd6SJoe Komlodi REG32(I2CD_AC_TIMING1, 0x04) /* Clock and AC Timing Control #1 */ 77ba2cccd6SJoe Komlodi REG32(I2CD_AC_TIMING2, 0x08) /* Clock and AC Timing Control #2 */ 78ba2cccd6SJoe Komlodi REG32(I2CD_INTR_CTRL, 0x0C) /* I2CD Interrupt Control */ 79ba2cccd6SJoe Komlodi REG32(I2CD_INTR_STS, 0x10) /* I2CD Interrupt Status */ 80ba2cccd6SJoe Komlodi SHARED_FIELD(SLAVE_ADDR_MATCH, 31, 1) /* 0: addr1 1: addr2 */ 81ba2cccd6SJoe Komlodi SHARED_FIELD(SLAVE_ADDR_RX_PENDING, 29, 1) 82ba2cccd6SJoe Komlodi SHARED_FIELD(SLAVE_INACTIVE_TIMEOUT, 15, 1) 83ba2cccd6SJoe Komlodi SHARED_FIELD(SDA_DL_TIMEOUT, 14, 1) 84ba2cccd6SJoe Komlodi SHARED_FIELD(BUS_RECOVER_DONE, 13, 1) 85ba2cccd6SJoe Komlodi SHARED_FIELD(SMBUS_ALERT, 12, 1) /* Bus [0-3] only */ 86ba2cccd6SJoe Komlodi FIELD(I2CD_INTR_STS, SMBUS_ARP_ADDR, 11, 1) /* Removed */ 87ba2cccd6SJoe Komlodi FIELD(I2CD_INTR_STS, SMBUS_DEV_ALERT_ADDR, 10, 1) /* Removed */ 88ba2cccd6SJoe Komlodi FIELD(I2CD_INTR_STS, SMBUS_DEF_ADDR, 9, 1) /* Removed */ 89ba2cccd6SJoe Komlodi FIELD(I2CD_INTR_STS, GCALL_ADDR, 8, 1) /* Removed */ 90ba2cccd6SJoe Komlodi FIELD(I2CD_INTR_STS, SLAVE_ADDR_RX_MATCH, 7, 1) /* use RX_DONE */ 91ba2cccd6SJoe Komlodi SHARED_FIELD(SCL_TIMEOUT, 6, 1) 92ba2cccd6SJoe Komlodi SHARED_FIELD(ABNORMAL, 5, 1) 93ba2cccd6SJoe Komlodi SHARED_FIELD(NORMAL_STOP, 4, 1) 94ba2cccd6SJoe Komlodi SHARED_FIELD(ARBIT_LOSS, 3, 1) 95ba2cccd6SJoe Komlodi SHARED_FIELD(RX_DONE, 2, 1) 96ba2cccd6SJoe Komlodi SHARED_FIELD(TX_NAK, 1, 1) 97ba2cccd6SJoe Komlodi SHARED_FIELD(TX_ACK, 0, 1) 98ba2cccd6SJoe Komlodi REG32(I2CD_CMD, 0x14) /* I2CD Command/Status */ 99ba2cccd6SJoe Komlodi SHARED_FIELD(SDA_OE, 28, 1) 100ba2cccd6SJoe Komlodi SHARED_FIELD(SDA_O, 27, 1) 101ba2cccd6SJoe Komlodi SHARED_FIELD(SCL_OE, 26, 1) 102ba2cccd6SJoe Komlodi SHARED_FIELD(SCL_O, 25, 1) 103ba2cccd6SJoe Komlodi SHARED_FIELD(TX_TIMING, 23, 2) 104ba2cccd6SJoe Komlodi SHARED_FIELD(TX_STATE, 19, 4) 105ba2cccd6SJoe Komlodi SHARED_FIELD(SCL_LINE_STS, 18, 1) 106ba2cccd6SJoe Komlodi SHARED_FIELD(SDA_LINE_STS, 17, 1) 107ba2cccd6SJoe Komlodi SHARED_FIELD(BUS_BUSY_STS, 16, 1) 108ba2cccd6SJoe Komlodi SHARED_FIELD(SDA_OE_OUT_DIR, 15, 1) 109ba2cccd6SJoe Komlodi SHARED_FIELD(SDA_O_OUT_DIR, 14, 1) 110ba2cccd6SJoe Komlodi SHARED_FIELD(SCL_OE_OUT_DIR, 13, 1) 111ba2cccd6SJoe Komlodi SHARED_FIELD(SCL_O_OUT_DIR, 12, 1) 112ba2cccd6SJoe Komlodi SHARED_FIELD(BUS_RECOVER_CMD_EN, 11, 1) 113ba2cccd6SJoe Komlodi SHARED_FIELD(S_ALT_EN, 10, 1) 1143be3d6ccSJoe Komlodi /* Command Bits */ 115ba2cccd6SJoe Komlodi SHARED_FIELD(RX_DMA_EN, 9, 1) 116ba2cccd6SJoe Komlodi SHARED_FIELD(TX_DMA_EN, 8, 1) 117ba2cccd6SJoe Komlodi SHARED_FIELD(RX_BUFF_EN, 7, 1) 118ba2cccd6SJoe Komlodi SHARED_FIELD(TX_BUFF_EN, 6, 1) 119ba2cccd6SJoe Komlodi SHARED_FIELD(M_STOP_CMD, 5, 1) 120ba2cccd6SJoe Komlodi SHARED_FIELD(M_S_RX_CMD_LAST, 4, 1) 121ba2cccd6SJoe Komlodi SHARED_FIELD(M_RX_CMD, 3, 1) 122ba2cccd6SJoe Komlodi SHARED_FIELD(S_TX_CMD, 2, 1) 123ba2cccd6SJoe Komlodi SHARED_FIELD(M_TX_CMD, 1, 1) 124ba2cccd6SJoe Komlodi SHARED_FIELD(M_START_CMD, 0, 1) 1253be3d6ccSJoe Komlodi REG32(I2CD_DEV_ADDR, 0x18) /* Slave Device Address */ 1263be3d6ccSJoe Komlodi REG32(I2CD_POOL_CTRL, 0x1C) /* Pool Buffer Control */ 127ba2cccd6SJoe Komlodi SHARED_FIELD(RX_COUNT, 24, 5) 128ba2cccd6SJoe Komlodi SHARED_FIELD(RX_SIZE, 16, 5) 129ba2cccd6SJoe Komlodi SHARED_FIELD(TX_COUNT, 9, 5) 1303be3d6ccSJoe Komlodi FIELD(I2CD_POOL_CTRL, OFFSET, 2, 6) /* AST2400 */ 1313be3d6ccSJoe Komlodi REG32(I2CD_BYTE_BUF, 0x20) /* Transmit/Receive Byte Buffer */ 132ba2cccd6SJoe Komlodi SHARED_FIELD(RX_BUF, 8, 8) 133ba2cccd6SJoe Komlodi SHARED_FIELD(TX_BUF, 0, 8) 1343be3d6ccSJoe Komlodi REG32(I2CD_DMA_ADDR, 0x24) /* DMA Buffer Address */ 1353be3d6ccSJoe Komlodi REG32(I2CD_DMA_LEN, 0x28) /* DMA Transfer Length < 4KB */ 13616020011SCédric Le Goater 137ba2cccd6SJoe Komlodi /* I2C New Mode Device (Bus) Register */ 138ba2cccd6SJoe Komlodi REG32(I2CC_FUN_CTRL, 0x0) 139ba2cccd6SJoe Komlodi FIELD(I2CC_FUN_CTRL, RB_EARLY_DONE_EN, 22, 1) 140ba2cccd6SJoe Komlodi FIELD(I2CC_FUN_CTRL, DMA_DIS_AUTO_RECOVER, 21, 1) 141ba2cccd6SJoe Komlodi FIELD(I2CC_FUN_CTRL, S_SAVE_ADDR, 20, 1) 142ba2cccd6SJoe Komlodi FIELD(I2CC_FUN_CTRL, M_PKT_RETRY_CNT, 18, 2) 143ba2cccd6SJoe Komlodi /* 17:0 shared with I2CD_FUN_CTRL[17:0] */ 144ba2cccd6SJoe Komlodi REG32(I2CC_AC_TIMING, 0x04) 145ba2cccd6SJoe Komlodi REG32(I2CC_MS_TXRX_BYTE_BUF, 0x08) 146ba2cccd6SJoe Komlodi /* 31:16 shared with I2CD_CMD[31:16] */ 147ba2cccd6SJoe Komlodi /* 15:0 shared with I2CD_BYTE_BUF[15:0] */ 148ba2cccd6SJoe Komlodi REG32(I2CC_POOL_CTRL, 0x0c) 149ba2cccd6SJoe Komlodi /* 31:0 shared with I2CD_POOL_CTRL[31:0] */ 150ba2cccd6SJoe Komlodi REG32(I2CM_INTR_CTRL, 0x10) 151ba2cccd6SJoe Komlodi REG32(I2CM_INTR_STS, 0x14) 152ba2cccd6SJoe Komlodi FIELD(I2CM_INTR_STS, PKT_STATE, 28, 4) 153ba2cccd6SJoe Komlodi FIELD(I2CM_INTR_STS, PKT_CMD_TIMEOUT, 18, 1) 154ba2cccd6SJoe Komlodi FIELD(I2CM_INTR_STS, PKT_CMD_FAIL, 17, 1) 155ba2cccd6SJoe Komlodi FIELD(I2CM_INTR_STS, PKT_CMD_DONE, 16, 1) 156ba2cccd6SJoe Komlodi FIELD(I2CM_INTR_STS, BUS_RECOVER_FAIL, 15, 1) 157ba2cccd6SJoe Komlodi /* 14:0 shared with I2CD_INTR_STS[14:0] */ 158ba2cccd6SJoe Komlodi REG32(I2CM_CMD, 0x18) 159ba2cccd6SJoe Komlodi FIELD(I2CM_CMD, W1_CTRL, 31, 1) 160ba2cccd6SJoe Komlodi FIELD(I2CM_CMD, PKT_DEV_ADDR, 24, 7) 161ba2cccd6SJoe Komlodi FIELD(I2CM_CMD, HS_MASTER_MODE_LSB, 17, 3) 162ba2cccd6SJoe Komlodi FIELD(I2CM_CMD, PKT_OP_EN, 16, 1) 163ba2cccd6SJoe Komlodi /* 15:0 shared with I2CD_CMD[15:0] */ 164ba2cccd6SJoe Komlodi REG32(I2CM_DMA_LEN, 0x1c) 165ba2cccd6SJoe Komlodi FIELD(I2CM_DMA_LEN, RX_BUF_LEN_W1T, 31, 1) 166ba2cccd6SJoe Komlodi FIELD(I2CM_DMA_LEN, RX_BUF_LEN, 16, 11) 167ba2cccd6SJoe Komlodi FIELD(I2CM_DMA_LEN, TX_BUF_LEN_W1T, 15, 1) 168ba2cccd6SJoe Komlodi FIELD(I2CM_DMA_LEN, TX_BUF_LEN, 0, 11) 169ba2cccd6SJoe Komlodi REG32(I2CS_INTR_CTRL, 0x20) 170ba2cccd6SJoe Komlodi REG32(I2CS_INTR_STS, 0x24) 171ba2cccd6SJoe Komlodi /* 31:29 shared with I2CD_INTR_STS[31:29] */ 172ba2cccd6SJoe Komlodi FIELD(I2CS_INTR_STS, SLAVE_PARKING_STS, 24, 2) 173ba2cccd6SJoe Komlodi FIELD(I2CS_INTR_STS, SLAVE_ADDR3_NAK, 22, 1) 174ba2cccd6SJoe Komlodi FIELD(I2CS_INTR_STS, SLAVE_ADDR2_NAK, 21, 1) 175ba2cccd6SJoe Komlodi FIELD(I2CS_INTR_STS, SLAVE_ADDR1_NAK, 20, 1) 176ba2cccd6SJoe Komlodi FIELD(I2CS_INTR_STS, SLAVE_ADDR_INDICATOR, 18, 2) 177ba2cccd6SJoe Komlodi FIELD(I2CS_INTR_STS, PKT_CMD_FAIL, 17, 1) 178ba2cccd6SJoe Komlodi FIELD(I2CS_INTR_STS, PKT_CMD_DONE, 16, 1) 179ba2cccd6SJoe Komlodi /* 14:0 shared with I2CD_INTR_STS[14:0] */ 180ba2cccd6SJoe Komlodi REG32(I2CS_CMD, 0x28) 181ba2cccd6SJoe Komlodi FIELD(I2CS_CMD, W1_CTRL, 31, 1) 182ba2cccd6SJoe Komlodi FIELD(I2CS_CMD, PKT_MODE_ACTIVE_ADDR, 17, 2) 183ba2cccd6SJoe Komlodi FIELD(I2CS_CMD, PKT_MODE_EN, 16, 1) 184ba2cccd6SJoe Komlodi FIELD(I2CS_CMD, AUTO_NAK_INACTIVE_ADDR, 15, 1) 185ba2cccd6SJoe Komlodi FIELD(I2CS_CMD, AUTO_NAK_ACTIVE_ADDR, 14, 1) 186ba2cccd6SJoe Komlodi /* 13:0 shared with I2CD_CMD[13:0] */ 187ba2cccd6SJoe Komlodi REG32(I2CS_DMA_LEN, 0x2c) 188ba2cccd6SJoe Komlodi FIELD(I2CS_DMA_LEN, RX_BUF_LEN_W1T, 31, 1) 189ba2cccd6SJoe Komlodi FIELD(I2CS_DMA_LEN, RX_BUF_LEN, 16, 11) 190ba2cccd6SJoe Komlodi FIELD(I2CS_DMA_LEN, TX_BUF_LEN_W1T, 15, 1) 191ba2cccd6SJoe Komlodi FIELD(I2CS_DMA_LEN, TX_BUF_LEN, 0, 11) 192ba2cccd6SJoe Komlodi REG32(I2CM_DMA_TX_ADDR, 0x30) 193ba2cccd6SJoe Komlodi FIELD(I2CM_DMA_TX_ADDR, ADDR, 0, 31) 194ba2cccd6SJoe Komlodi REG32(I2CM_DMA_RX_ADDR, 0x34) 195ba2cccd6SJoe Komlodi FIELD(I2CM_DMA_RX_ADDR, ADDR, 0, 31) 196ba2cccd6SJoe Komlodi REG32(I2CS_DMA_TX_ADDR, 0x38) 197ba2cccd6SJoe Komlodi FIELD(I2CS_DMA_TX_ADDR, ADDR, 0, 31) 198ba2cccd6SJoe Komlodi REG32(I2CS_DMA_RX_ADDR, 0x3c) 199ba2cccd6SJoe Komlodi FIELD(I2CS_DMA_RX_ADDR, ADDR, 0, 31) 200ba2cccd6SJoe Komlodi REG32(I2CS_DEV_ADDR, 0x40) 201ba2cccd6SJoe Komlodi REG32(I2CM_DMA_LEN_STS, 0x48) 202ba2cccd6SJoe Komlodi FIELD(I2CM_DMA_LEN_STS, RX_LEN, 16, 13) 203ba2cccd6SJoe Komlodi FIELD(I2CM_DMA_LEN_STS, TX_LEN, 0, 13) 204ba2cccd6SJoe Komlodi REG32(I2CS_DMA_LEN_STS, 0x4c) 205ba2cccd6SJoe Komlodi FIELD(I2CS_DMA_LEN_STS, RX_LEN, 16, 13) 206ba2cccd6SJoe Komlodi FIELD(I2CS_DMA_LEN_STS, TX_LEN, 0, 13) 207ba2cccd6SJoe Komlodi REG32(I2CC_DMA_ADDR, 0x50) 208ba2cccd6SJoe Komlodi REG32(I2CC_DMA_LEN, 0x54) 209ba2cccd6SJoe Komlodi 210ba2cccd6SJoe Komlodi static inline bool aspeed_i2c_is_new_mode(AspeedI2CState *s) 211ba2cccd6SJoe Komlodi { 212ba2cccd6SJoe Komlodi return FIELD_EX32(s->ctrl_global, I2C_CTRL_GLOBAL, REG_MODE); 213ba2cccd6SJoe Komlodi } 214ba2cccd6SJoe Komlodi 215ba2cccd6SJoe Komlodi static inline bool aspeed_i2c_bus_pkt_mode_en(AspeedI2CBus *bus) 216ba2cccd6SJoe Komlodi { 217ba2cccd6SJoe Komlodi if (aspeed_i2c_is_new_mode(bus->controller)) { 218ba2cccd6SJoe Komlodi return ARRAY_FIELD_EX32(bus->regs, I2CM_CMD, PKT_OP_EN); 219ba2cccd6SJoe Komlodi } 220ba2cccd6SJoe Komlodi return false; 221ba2cccd6SJoe Komlodi } 222ba2cccd6SJoe Komlodi 223ba2cccd6SJoe Komlodi static inline uint32_t aspeed_i2c_bus_ctrl_offset(AspeedI2CBus *bus) 224ba2cccd6SJoe Komlodi { 225ba2cccd6SJoe Komlodi if (aspeed_i2c_is_new_mode(bus->controller)) { 226ba2cccd6SJoe Komlodi return R_I2CC_FUN_CTRL; 227ba2cccd6SJoe Komlodi } 228ba2cccd6SJoe Komlodi return R_I2CD_FUN_CTRL; 229ba2cccd6SJoe Komlodi } 230ba2cccd6SJoe Komlodi 231ba2cccd6SJoe Komlodi static inline uint32_t aspeed_i2c_bus_cmd_offset(AspeedI2CBus *bus) 232ba2cccd6SJoe Komlodi { 233ba2cccd6SJoe Komlodi if (aspeed_i2c_is_new_mode(bus->controller)) { 234ba2cccd6SJoe Komlodi return R_I2CM_CMD; 235ba2cccd6SJoe Komlodi } 236ba2cccd6SJoe Komlodi return R_I2CD_CMD; 237ba2cccd6SJoe Komlodi } 238ba2cccd6SJoe Komlodi 239ba2cccd6SJoe Komlodi static inline uint32_t aspeed_i2c_bus_intr_ctrl_offset(AspeedI2CBus *bus) 240ba2cccd6SJoe Komlodi { 241ba2cccd6SJoe Komlodi if (aspeed_i2c_is_new_mode(bus->controller)) { 242ba2cccd6SJoe Komlodi return R_I2CM_INTR_CTRL; 243ba2cccd6SJoe Komlodi } 244ba2cccd6SJoe Komlodi return R_I2CD_INTR_CTRL; 245ba2cccd6SJoe Komlodi } 246ba2cccd6SJoe Komlodi 247ba2cccd6SJoe Komlodi static inline uint32_t aspeed_i2c_bus_intr_sts_offset(AspeedI2CBus *bus) 248ba2cccd6SJoe Komlodi { 249ba2cccd6SJoe Komlodi if (aspeed_i2c_is_new_mode(bus->controller)) { 250ba2cccd6SJoe Komlodi return R_I2CM_INTR_STS; 251ba2cccd6SJoe Komlodi } 252ba2cccd6SJoe Komlodi return R_I2CD_INTR_STS; 253ba2cccd6SJoe Komlodi } 254ba2cccd6SJoe Komlodi 255ba2cccd6SJoe Komlodi static inline uint32_t aspeed_i2c_bus_pool_ctrl_offset(AspeedI2CBus *bus) 256ba2cccd6SJoe Komlodi { 257ba2cccd6SJoe Komlodi if (aspeed_i2c_is_new_mode(bus->controller)) { 258ba2cccd6SJoe Komlodi return R_I2CC_POOL_CTRL; 259ba2cccd6SJoe Komlodi } 260ba2cccd6SJoe Komlodi return R_I2CD_POOL_CTRL; 261ba2cccd6SJoe Komlodi } 262ba2cccd6SJoe Komlodi 263ba2cccd6SJoe Komlodi static inline uint32_t aspeed_i2c_bus_byte_buf_offset(AspeedI2CBus *bus) 264ba2cccd6SJoe Komlodi { 265ba2cccd6SJoe Komlodi if (aspeed_i2c_is_new_mode(bus->controller)) { 266ba2cccd6SJoe Komlodi return R_I2CC_MS_TXRX_BYTE_BUF; 267ba2cccd6SJoe Komlodi } 268ba2cccd6SJoe Komlodi return R_I2CD_BYTE_BUF; 269ba2cccd6SJoe Komlodi } 270ba2cccd6SJoe Komlodi 271ba2cccd6SJoe Komlodi static inline uint32_t aspeed_i2c_bus_dma_len_offset(AspeedI2CBus *bus) 272ba2cccd6SJoe Komlodi { 273ba2cccd6SJoe Komlodi if (aspeed_i2c_is_new_mode(bus->controller)) { 274ba2cccd6SJoe Komlodi return R_I2CC_DMA_LEN; 275ba2cccd6SJoe Komlodi } 276ba2cccd6SJoe Komlodi return R_I2CD_DMA_LEN; 277ba2cccd6SJoe Komlodi } 278ba2cccd6SJoe Komlodi 279ba2cccd6SJoe Komlodi static inline uint32_t aspeed_i2c_bus_dma_addr_offset(AspeedI2CBus *bus) 280ba2cccd6SJoe Komlodi { 281ba2cccd6SJoe Komlodi if (aspeed_i2c_is_new_mode(bus->controller)) { 282ba2cccd6SJoe Komlodi return R_I2CC_DMA_ADDR; 283ba2cccd6SJoe Komlodi } 284ba2cccd6SJoe Komlodi return R_I2CD_DMA_ADDR; 285ba2cccd6SJoe Komlodi } 286ba2cccd6SJoe Komlodi 28716020011SCédric Le Goater static inline bool aspeed_i2c_bus_is_master(AspeedI2CBus *bus) 28816020011SCédric Le Goater { 289ba2cccd6SJoe Komlodi return SHARED_ARRAY_FIELD_EX32(bus->regs, aspeed_i2c_bus_ctrl_offset(bus), 290ba2cccd6SJoe Komlodi MASTER_EN); 29116020011SCédric Le Goater } 29216020011SCédric Le Goater 29316020011SCédric Le Goater static inline bool aspeed_i2c_bus_is_enabled(AspeedI2CBus *bus) 29416020011SCédric Le Goater { 295ba2cccd6SJoe Komlodi uint32_t ctrl_reg = aspeed_i2c_bus_ctrl_offset(bus); 296ba2cccd6SJoe Komlodi return SHARED_ARRAY_FIELD_EX32(bus->regs, ctrl_reg, MASTER_EN) || 297ba2cccd6SJoe Komlodi SHARED_ARRAY_FIELD_EX32(bus->regs, ctrl_reg, SLAVE_EN); 29816020011SCédric Le Goater } 29916020011SCédric Le Goater 30016020011SCédric Le Goater static inline void aspeed_i2c_bus_raise_interrupt(AspeedI2CBus *bus) 30116020011SCédric Le Goater { 30251dd4923SCédric Le Goater AspeedI2CClass *aic = ASPEED_I2C_GET_CLASS(bus->controller); 303ba2cccd6SJoe Komlodi uint32_t reg_intr_sts = aspeed_i2c_bus_intr_sts_offset(bus); 304ba2cccd6SJoe Komlodi uint32_t intr_ctrl_reg = aspeed_i2c_bus_intr_ctrl_offset(bus); 305ba2cccd6SJoe Komlodi bool raise_irq; 30651dd4923SCédric Le Goater 307ba2cccd6SJoe Komlodi trace_aspeed_i2c_bus_raise_interrupt(bus->regs[reg_intr_sts], 308*0efec47bSJoe Komlodi aspeed_i2c_bus_pkt_mode_en(bus) && 309*0efec47bSJoe Komlodi ARRAY_FIELD_EX32(bus->regs, I2CM_INTR_STS, PKT_CMD_DONE) ? 310*0efec47bSJoe Komlodi "pktdone|" : "", 311ba2cccd6SJoe Komlodi SHARED_ARRAY_FIELD_EX32(bus->regs, reg_intr_sts, TX_NAK) ? "nak|" : "", 312ba2cccd6SJoe Komlodi SHARED_ARRAY_FIELD_EX32(bus->regs, reg_intr_sts, TX_ACK) ? "ack|" : "", 313ba2cccd6SJoe Komlodi SHARED_ARRAY_FIELD_EX32(bus->regs, reg_intr_sts, RX_DONE) ? "done|" 3143be3d6ccSJoe Komlodi : "", 315ba2cccd6SJoe Komlodi SHARED_ARRAY_FIELD_EX32(bus->regs, reg_intr_sts, NORMAL_STOP) ? 316ba2cccd6SJoe Komlodi "normal|" : "", 317ba2cccd6SJoe Komlodi SHARED_ARRAY_FIELD_EX32(bus->regs, reg_intr_sts, ABNORMAL) ? "abnormal" 3183be3d6ccSJoe Komlodi : ""); 319ba2cccd6SJoe Komlodi raise_irq = bus->regs[reg_intr_sts] & bus->regs[intr_ctrl_reg]; 320ba2cccd6SJoe Komlodi /* In packet mode we don't mask off INTR_STS */ 321ba2cccd6SJoe Komlodi if (!aspeed_i2c_bus_pkt_mode_en(bus)) { 322ba2cccd6SJoe Komlodi bus->regs[reg_intr_sts] &= bus->regs[intr_ctrl_reg]; 323ba2cccd6SJoe Komlodi } 324ba2cccd6SJoe Komlodi if (raise_irq) { 32516020011SCédric Le Goater bus->controller->intr_status |= 1 << bus->id; 32651dd4923SCédric Le Goater qemu_irq_raise(aic->bus_get_irq(bus)); 32716020011SCédric Le Goater } 32816020011SCédric Le Goater } 32916020011SCédric Le Goater 330ba2cccd6SJoe Komlodi static uint64_t aspeed_i2c_bus_old_read(AspeedI2CBus *bus, hwaddr offset, 33116020011SCédric Le Goater unsigned size) 33216020011SCédric Le Goater { 333545d6befSCédric Le Goater AspeedI2CClass *aic = ASPEED_I2C_GET_CLASS(bus->controller); 3342260fc6fSJoe Komlodi uint64_t value = bus->regs[offset / sizeof(*bus->regs)]; 33516020011SCédric Le Goater 33616020011SCédric Le Goater switch (offset) { 3373be3d6ccSJoe Komlodi case A_I2CD_FUN_CTRL: 3383be3d6ccSJoe Komlodi case A_I2CD_AC_TIMING1: 3393be3d6ccSJoe Komlodi case A_I2CD_AC_TIMING2: 3403be3d6ccSJoe Komlodi case A_I2CD_INTR_CTRL: 3413be3d6ccSJoe Komlodi case A_I2CD_INTR_STS: 3423be3d6ccSJoe Komlodi case A_I2CD_POOL_CTRL: 3433be3d6ccSJoe Komlodi case A_I2CD_BYTE_BUF: 3442260fc6fSJoe Komlodi /* Value is already set, don't do anything. */ 34566cc84a1SCédric Le Goater break; 3463be3d6ccSJoe Komlodi case A_I2CD_CMD: 347ba2cccd6SJoe Komlodi value = SHARED_FIELD_DP32(value, BUS_BUSY_STS, i2c_bus_busy(bus->bus)); 34866cc84a1SCédric Le Goater break; 3493be3d6ccSJoe Komlodi case A_I2CD_DMA_ADDR: 350545d6befSCédric Le Goater if (!aic->has_dma) { 351545d6befSCédric Le Goater qemu_log_mask(LOG_GUEST_ERROR, "%s: No DMA support\n", __func__); 3522260fc6fSJoe Komlodi value = -1; 353545d6befSCédric Le Goater } 35466cc84a1SCédric Le Goater break; 3553be3d6ccSJoe Komlodi case A_I2CD_DMA_LEN: 356545d6befSCédric Le Goater if (!aic->has_dma) { 357545d6befSCédric Le Goater qemu_log_mask(LOG_GUEST_ERROR, "%s: No DMA support\n", __func__); 3582260fc6fSJoe Komlodi value = -1; 359545d6befSCédric Le Goater } 36066cc84a1SCédric Le Goater break; 36166cc84a1SCédric Le Goater 36216020011SCédric Le Goater default: 36316020011SCédric Le Goater qemu_log_mask(LOG_GUEST_ERROR, 36416020011SCédric Le Goater "%s: Bad offset 0x%" HWADDR_PRIx "\n", __func__, offset); 36566cc84a1SCédric Le Goater value = -1; 36666cc84a1SCédric Le Goater break; 36716020011SCédric Le Goater } 36866cc84a1SCédric Le Goater 36966cc84a1SCédric Le Goater trace_aspeed_i2c_bus_read(bus->id, offset, size, value); 37066cc84a1SCédric Le Goater return value; 37116020011SCédric Le Goater } 37216020011SCédric Le Goater 373ba2cccd6SJoe Komlodi static uint64_t aspeed_i2c_bus_new_read(AspeedI2CBus *bus, hwaddr offset, 374ba2cccd6SJoe Komlodi unsigned size) 375ba2cccd6SJoe Komlodi { 376ba2cccd6SJoe Komlodi uint64_t value = bus->regs[offset / sizeof(*bus->regs)]; 377ba2cccd6SJoe Komlodi 378ba2cccd6SJoe Komlodi switch (offset) { 379ba2cccd6SJoe Komlodi case A_I2CC_FUN_CTRL: 380ba2cccd6SJoe Komlodi case A_I2CC_AC_TIMING: 381ba2cccd6SJoe Komlodi case A_I2CC_POOL_CTRL: 382ba2cccd6SJoe Komlodi case A_I2CM_INTR_CTRL: 383ba2cccd6SJoe Komlodi case A_I2CM_INTR_STS: 384ba2cccd6SJoe Komlodi case A_I2CC_MS_TXRX_BYTE_BUF: 385ba2cccd6SJoe Komlodi case A_I2CM_DMA_LEN: 386ba2cccd6SJoe Komlodi case A_I2CM_DMA_TX_ADDR: 387ba2cccd6SJoe Komlodi case A_I2CM_DMA_RX_ADDR: 388ba2cccd6SJoe Komlodi case A_I2CM_DMA_LEN_STS: 389ba2cccd6SJoe Komlodi case A_I2CC_DMA_ADDR: 390ba2cccd6SJoe Komlodi case A_I2CC_DMA_LEN: 391ba2cccd6SJoe Komlodi /* Value is already set, don't do anything. */ 392ba2cccd6SJoe Komlodi break; 393ba2cccd6SJoe Komlodi case A_I2CM_CMD: 394ba2cccd6SJoe Komlodi value = SHARED_FIELD_DP32(value, BUS_BUSY_STS, i2c_bus_busy(bus->bus)); 395ba2cccd6SJoe Komlodi break; 396ba2cccd6SJoe Komlodi default: 397ba2cccd6SJoe Komlodi qemu_log_mask(LOG_GUEST_ERROR, 398ba2cccd6SJoe Komlodi "%s: Bad offset 0x%" HWADDR_PRIx "\n", __func__, offset); 399ba2cccd6SJoe Komlodi value = -1; 400ba2cccd6SJoe Komlodi break; 401ba2cccd6SJoe Komlodi } 402ba2cccd6SJoe Komlodi 403ba2cccd6SJoe Komlodi trace_aspeed_i2c_bus_read(bus->id, offset, size, value); 404ba2cccd6SJoe Komlodi return value; 405ba2cccd6SJoe Komlodi } 406ba2cccd6SJoe Komlodi 407ba2cccd6SJoe Komlodi static uint64_t aspeed_i2c_bus_read(void *opaque, hwaddr offset, 408ba2cccd6SJoe Komlodi unsigned size) 409ba2cccd6SJoe Komlodi { 410ba2cccd6SJoe Komlodi AspeedI2CBus *bus = opaque; 411ba2cccd6SJoe Komlodi if (aspeed_i2c_is_new_mode(bus->controller)) { 412ba2cccd6SJoe Komlodi return aspeed_i2c_bus_new_read(bus, offset, size); 413ba2cccd6SJoe Komlodi } 414ba2cccd6SJoe Komlodi return aspeed_i2c_bus_old_read(bus, offset, size); 415ba2cccd6SJoe Komlodi } 416ba2cccd6SJoe Komlodi 4174960f084SCédric Le Goater static void aspeed_i2c_set_state(AspeedI2CBus *bus, uint8_t state) 4184960f084SCédric Le Goater { 419ba2cccd6SJoe Komlodi if (aspeed_i2c_is_new_mode(bus->controller)) { 420ba2cccd6SJoe Komlodi SHARED_ARRAY_FIELD_DP32(bus->regs, R_I2CC_MS_TXRX_BYTE_BUF, TX_STATE, 421ba2cccd6SJoe Komlodi state); 422ba2cccd6SJoe Komlodi } else { 423ba2cccd6SJoe Komlodi SHARED_ARRAY_FIELD_DP32(bus->regs, R_I2CD_CMD, TX_STATE, state); 424ba2cccd6SJoe Komlodi } 4254960f084SCédric Le Goater } 4264960f084SCédric Le Goater 4274960f084SCédric Le Goater static uint8_t aspeed_i2c_get_state(AspeedI2CBus *bus) 4284960f084SCédric Le Goater { 429ba2cccd6SJoe Komlodi if (aspeed_i2c_is_new_mode(bus->controller)) { 430ba2cccd6SJoe Komlodi return SHARED_ARRAY_FIELD_EX32(bus->regs, R_I2CC_MS_TXRX_BYTE_BUF, 431ba2cccd6SJoe Komlodi TX_STATE); 432ba2cccd6SJoe Komlodi } 433ba2cccd6SJoe Komlodi return SHARED_ARRAY_FIELD_EX32(bus->regs, R_I2CD_CMD, TX_STATE); 4344960f084SCédric Le Goater } 4354960f084SCédric Le Goater 436545d6befSCédric Le Goater static int aspeed_i2c_dma_read(AspeedI2CBus *bus, uint8_t *data) 437545d6befSCédric Le Goater { 438545d6befSCédric Le Goater MemTxResult result; 439545d6befSCédric Le Goater AspeedI2CState *s = bus->controller; 440ba2cccd6SJoe Komlodi uint32_t reg_dma_addr = aspeed_i2c_bus_dma_addr_offset(bus); 441ba2cccd6SJoe Komlodi uint32_t reg_dma_len = aspeed_i2c_bus_dma_len_offset(bus); 442545d6befSCédric Le Goater 443ba2cccd6SJoe Komlodi result = address_space_read(&s->dram_as, bus->regs[reg_dma_addr], 444545d6befSCédric Le Goater MEMTXATTRS_UNSPECIFIED, data, 1); 445545d6befSCédric Le Goater if (result != MEMTX_OK) { 446545d6befSCédric Le Goater qemu_log_mask(LOG_GUEST_ERROR, "%s: DRAM read failed @%08x\n", 447ba2cccd6SJoe Komlodi __func__, bus->regs[reg_dma_addr]); 448545d6befSCédric Le Goater return -1; 449545d6befSCédric Le Goater } 450545d6befSCédric Le Goater 451ba2cccd6SJoe Komlodi bus->regs[reg_dma_addr]++; 452ba2cccd6SJoe Komlodi bus->regs[reg_dma_len]--; 453545d6befSCédric Le Goater return 0; 454545d6befSCédric Le Goater } 455545d6befSCédric Le Goater 4566054fc73SCédric Le Goater static int aspeed_i2c_bus_send(AspeedI2CBus *bus, uint8_t pool_start) 4576054fc73SCédric Le Goater { 4586054fc73SCédric Le Goater AspeedI2CClass *aic = ASPEED_I2C_GET_CLASS(bus->controller); 4596054fc73SCédric Le Goater int ret = -1; 4606054fc73SCédric Le Goater int i; 461ba2cccd6SJoe Komlodi uint32_t reg_cmd = aspeed_i2c_bus_cmd_offset(bus); 462ba2cccd6SJoe Komlodi uint32_t reg_pool_ctrl = aspeed_i2c_bus_pool_ctrl_offset(bus); 463ba2cccd6SJoe Komlodi uint32_t reg_byte_buf = aspeed_i2c_bus_byte_buf_offset(bus); 464ba2cccd6SJoe Komlodi uint32_t reg_dma_len = aspeed_i2c_bus_dma_len_offset(bus); 465ba2cccd6SJoe Komlodi int pool_tx_count = SHARED_ARRAY_FIELD_EX32(bus->regs, reg_pool_ctrl, 466ba2cccd6SJoe Komlodi TX_COUNT); 4676054fc73SCédric Le Goater 468ba2cccd6SJoe Komlodi if (SHARED_ARRAY_FIELD_EX32(bus->regs, reg_cmd, TX_BUFF_EN)) { 4693be3d6ccSJoe Komlodi for (i = pool_start; i < pool_tx_count; i++) { 4706054fc73SCédric Le Goater uint8_t *pool_base = aic->bus_pool_base(bus); 4716054fc73SCédric Le Goater 4723be3d6ccSJoe Komlodi trace_aspeed_i2c_bus_send("BUF", i + 1, pool_tx_count, 47366cc84a1SCédric Le Goater pool_base[i]); 4746054fc73SCédric Le Goater ret = i2c_send(bus->bus, pool_base[i]); 4756054fc73SCédric Le Goater if (ret) { 4766054fc73SCédric Le Goater break; 4776054fc73SCédric Le Goater } 4786054fc73SCédric Le Goater } 479ba2cccd6SJoe Komlodi SHARED_ARRAY_FIELD_DP32(bus->regs, reg_cmd, TX_BUFF_EN, 0); 480ba2cccd6SJoe Komlodi } else if (SHARED_ARRAY_FIELD_EX32(bus->regs, reg_cmd, TX_DMA_EN)) { 481ba2cccd6SJoe Komlodi /* In new mode, clear how many bytes we TXed */ 482ba2cccd6SJoe Komlodi if (aspeed_i2c_is_new_mode(bus->controller)) { 483ba2cccd6SJoe Komlodi ARRAY_FIELD_DP32(bus->regs, I2CM_DMA_LEN_STS, TX_LEN, 0); 484ba2cccd6SJoe Komlodi } 485ba2cccd6SJoe Komlodi while (bus->regs[reg_dma_len]) { 486545d6befSCédric Le Goater uint8_t data; 487545d6befSCédric Le Goater aspeed_i2c_dma_read(bus, &data); 488ba2cccd6SJoe Komlodi trace_aspeed_i2c_bus_send("DMA", bus->regs[reg_dma_len], 489ba2cccd6SJoe Komlodi bus->regs[reg_dma_len], data); 490545d6befSCédric Le Goater ret = i2c_send(bus->bus, data); 491545d6befSCédric Le Goater if (ret) { 492545d6befSCédric Le Goater break; 493545d6befSCédric Le Goater } 494ba2cccd6SJoe Komlodi /* In new mode, keep track of how many bytes we TXed */ 495ba2cccd6SJoe Komlodi if (aspeed_i2c_is_new_mode(bus->controller)) { 496ba2cccd6SJoe Komlodi ARRAY_FIELD_DP32(bus->regs, I2CM_DMA_LEN_STS, TX_LEN, 497ba2cccd6SJoe Komlodi ARRAY_FIELD_EX32(bus->regs, I2CM_DMA_LEN_STS, 498ba2cccd6SJoe Komlodi TX_LEN) + 1); 499545d6befSCédric Le Goater } 500ba2cccd6SJoe Komlodi } 501ba2cccd6SJoe Komlodi SHARED_ARRAY_FIELD_DP32(bus->regs, reg_cmd, TX_DMA_EN, 0); 5026054fc73SCédric Le Goater } else { 5032260fc6fSJoe Komlodi trace_aspeed_i2c_bus_send("BYTE", pool_start, 1, 504ba2cccd6SJoe Komlodi bus->regs[reg_byte_buf]); 505ba2cccd6SJoe Komlodi ret = i2c_send(bus->bus, bus->regs[reg_byte_buf]); 5066054fc73SCédric Le Goater } 5076054fc73SCédric Le Goater 5086054fc73SCédric Le Goater return ret; 5096054fc73SCédric Le Goater } 5106054fc73SCédric Le Goater 5116054fc73SCédric Le Goater static void aspeed_i2c_bus_recv(AspeedI2CBus *bus) 5126054fc73SCédric Le Goater { 5136054fc73SCédric Le Goater AspeedI2CState *s = bus->controller; 5146054fc73SCédric Le Goater AspeedI2CClass *aic = ASPEED_I2C_GET_CLASS(s); 5156054fc73SCédric Le Goater uint8_t data; 5166054fc73SCédric Le Goater int i; 517ba2cccd6SJoe Komlodi uint32_t reg_cmd = aspeed_i2c_bus_cmd_offset(bus); 518ba2cccd6SJoe Komlodi uint32_t reg_pool_ctrl = aspeed_i2c_bus_pool_ctrl_offset(bus); 519ba2cccd6SJoe Komlodi uint32_t reg_byte_buf = aspeed_i2c_bus_byte_buf_offset(bus); 520ba2cccd6SJoe Komlodi uint32_t reg_dma_len = aspeed_i2c_bus_dma_len_offset(bus); 521ba2cccd6SJoe Komlodi uint32_t reg_dma_addr = aspeed_i2c_bus_dma_addr_offset(bus); 522ba2cccd6SJoe Komlodi int pool_rx_count = SHARED_ARRAY_FIELD_EX32(bus->regs, reg_pool_ctrl, 523ba2cccd6SJoe Komlodi RX_COUNT); 5246054fc73SCédric Le Goater 525ba2cccd6SJoe Komlodi if (SHARED_ARRAY_FIELD_EX32(bus->regs, reg_cmd, RX_BUFF_EN)) { 5266054fc73SCédric Le Goater uint8_t *pool_base = aic->bus_pool_base(bus); 5276054fc73SCédric Le Goater 5283be3d6ccSJoe Komlodi for (i = 0; i < pool_rx_count; i++) { 5296054fc73SCédric Le Goater pool_base[i] = i2c_recv(bus->bus); 5303be3d6ccSJoe Komlodi trace_aspeed_i2c_bus_recv("BUF", i + 1, pool_rx_count, 53166cc84a1SCédric Le Goater pool_base[i]); 5326054fc73SCédric Le Goater } 5336054fc73SCédric Le Goater 5346054fc73SCédric Le Goater /* Update RX count */ 535ba2cccd6SJoe Komlodi SHARED_ARRAY_FIELD_DP32(bus->regs, reg_pool_ctrl, RX_COUNT, i & 0xff); 536ba2cccd6SJoe Komlodi SHARED_ARRAY_FIELD_DP32(bus->regs, reg_cmd, RX_BUFF_EN, 0); 537ba2cccd6SJoe Komlodi } else if (SHARED_ARRAY_FIELD_EX32(bus->regs, reg_cmd, RX_DMA_EN)) { 538545d6befSCédric Le Goater uint8_t data; 539ba2cccd6SJoe Komlodi /* In new mode, clear how many bytes we RXed */ 540ba2cccd6SJoe Komlodi if (aspeed_i2c_is_new_mode(bus->controller)) { 541ba2cccd6SJoe Komlodi ARRAY_FIELD_DP32(bus->regs, I2CM_DMA_LEN_STS, RX_LEN, 0); 542ba2cccd6SJoe Komlodi } 543545d6befSCédric Le Goater 544ba2cccd6SJoe Komlodi while (bus->regs[reg_dma_len]) { 545545d6befSCédric Le Goater MemTxResult result; 546545d6befSCédric Le Goater 547545d6befSCédric Le Goater data = i2c_recv(bus->bus); 548ba2cccd6SJoe Komlodi trace_aspeed_i2c_bus_recv("DMA", bus->regs[reg_dma_len], 549ba2cccd6SJoe Komlodi bus->regs[reg_dma_len], data); 550ba2cccd6SJoe Komlodi result = address_space_write(&s->dram_as, bus->regs[reg_dma_addr], 551545d6befSCédric Le Goater MEMTXATTRS_UNSPECIFIED, &data, 1); 552545d6befSCédric Le Goater if (result != MEMTX_OK) { 553545d6befSCédric Le Goater qemu_log_mask(LOG_GUEST_ERROR, "%s: DRAM write failed @%08x\n", 554ba2cccd6SJoe Komlodi __func__, bus->regs[reg_dma_addr]); 555545d6befSCédric Le Goater return; 556545d6befSCédric Le Goater } 557ba2cccd6SJoe Komlodi bus->regs[reg_dma_addr]++; 558ba2cccd6SJoe Komlodi bus->regs[reg_dma_len]--; 559ba2cccd6SJoe Komlodi /* In new mode, keep track of how many bytes we RXed */ 560ba2cccd6SJoe Komlodi if (aspeed_i2c_is_new_mode(bus->controller)) { 561ba2cccd6SJoe Komlodi ARRAY_FIELD_DP32(bus->regs, I2CM_DMA_LEN_STS, RX_LEN, 562ba2cccd6SJoe Komlodi ARRAY_FIELD_EX32(bus->regs, I2CM_DMA_LEN_STS, 563ba2cccd6SJoe Komlodi RX_LEN) + 1); 564545d6befSCédric Le Goater } 565ba2cccd6SJoe Komlodi } 566ba2cccd6SJoe Komlodi SHARED_ARRAY_FIELD_DP32(bus->regs, reg_cmd, RX_DMA_EN, 0); 5676054fc73SCédric Le Goater } else { 5686054fc73SCédric Le Goater data = i2c_recv(bus->bus); 569ba2cccd6SJoe Komlodi trace_aspeed_i2c_bus_recv("BYTE", 1, 1, bus->regs[reg_byte_buf]); 570ba2cccd6SJoe Komlodi SHARED_ARRAY_FIELD_DP32(bus->regs, reg_byte_buf, RX_BUF, data); 5716054fc73SCédric Le Goater } 5726054fc73SCédric Le Goater } 5736054fc73SCédric Le Goater 5747bd9c60dSGuenter Roeck static void aspeed_i2c_handle_rx_cmd(AspeedI2CBus *bus) 5757bd9c60dSGuenter Roeck { 576ba2cccd6SJoe Komlodi uint32_t reg_cmd = aspeed_i2c_bus_cmd_offset(bus); 577ba2cccd6SJoe Komlodi uint32_t reg_intr_sts = aspeed_i2c_bus_intr_sts_offset(bus); 578ba2cccd6SJoe Komlodi 5797bd9c60dSGuenter Roeck aspeed_i2c_set_state(bus, I2CD_MRXD); 5806054fc73SCédric Le Goater aspeed_i2c_bus_recv(bus); 581ba2cccd6SJoe Komlodi SHARED_ARRAY_FIELD_DP32(bus->regs, reg_intr_sts, RX_DONE, 1); 582ba2cccd6SJoe Komlodi if (SHARED_ARRAY_FIELD_EX32(bus->regs, reg_cmd, M_S_RX_CMD_LAST)) { 5837bd9c60dSGuenter Roeck i2c_nack(bus->bus); 5847bd9c60dSGuenter Roeck } 585ba2cccd6SJoe Komlodi SHARED_ARRAY_FIELD_DP32(bus->regs, reg_cmd, M_RX_CMD, 0); 586ba2cccd6SJoe Komlodi SHARED_ARRAY_FIELD_DP32(bus->regs, reg_cmd, M_S_RX_CMD_LAST, 0); 5877bd9c60dSGuenter Roeck aspeed_i2c_set_state(bus, I2CD_MACTIVE); 5887bd9c60dSGuenter Roeck } 5897bd9c60dSGuenter Roeck 5906054fc73SCédric Le Goater static uint8_t aspeed_i2c_get_addr(AspeedI2CBus *bus) 5916054fc73SCédric Le Goater { 5926054fc73SCédric Le Goater AspeedI2CClass *aic = ASPEED_I2C_GET_CLASS(bus->controller); 593ba2cccd6SJoe Komlodi uint32_t reg_byte_buf = aspeed_i2c_bus_byte_buf_offset(bus); 594ba2cccd6SJoe Komlodi uint32_t reg_cmd = aspeed_i2c_bus_cmd_offset(bus); 5956054fc73SCédric Le Goater 596ba2cccd6SJoe Komlodi if (aspeed_i2c_bus_pkt_mode_en(bus)) { 597ba2cccd6SJoe Komlodi return (ARRAY_FIELD_EX32(bus->regs, I2CM_CMD, PKT_DEV_ADDR) << 1) | 598ba2cccd6SJoe Komlodi SHARED_ARRAY_FIELD_EX32(bus->regs, reg_cmd, M_RX_CMD); 599ba2cccd6SJoe Komlodi } 600ba2cccd6SJoe Komlodi if (SHARED_ARRAY_FIELD_EX32(bus->regs, reg_cmd, TX_BUFF_EN)) { 6016054fc73SCédric Le Goater uint8_t *pool_base = aic->bus_pool_base(bus); 6026054fc73SCédric Le Goater 6036054fc73SCédric Le Goater return pool_base[0]; 604ba2cccd6SJoe Komlodi } else if (SHARED_ARRAY_FIELD_EX32(bus->regs, reg_cmd, TX_DMA_EN)) { 605545d6befSCédric Le Goater uint8_t data; 606545d6befSCédric Le Goater 607545d6befSCédric Le Goater aspeed_i2c_dma_read(bus, &data); 608545d6befSCédric Le Goater return data; 6096054fc73SCédric Le Goater } else { 610ba2cccd6SJoe Komlodi return bus->regs[reg_byte_buf]; 6116054fc73SCédric Le Goater } 6126054fc73SCédric Le Goater } 6136054fc73SCédric Le Goater 614aab90b1cSCédric Le Goater static bool aspeed_i2c_check_sram(AspeedI2CBus *bus) 615aab90b1cSCédric Le Goater { 616aab90b1cSCédric Le Goater AspeedI2CState *s = bus->controller; 617aab90b1cSCédric Le Goater AspeedI2CClass *aic = ASPEED_I2C_GET_CLASS(s); 618ba2cccd6SJoe Komlodi uint32_t reg_cmd = aspeed_i2c_bus_cmd_offset(bus); 619ba2cccd6SJoe Komlodi bool dma_en = SHARED_ARRAY_FIELD_EX32(bus->regs, reg_cmd, RX_DMA_EN) || 620ba2cccd6SJoe Komlodi SHARED_ARRAY_FIELD_EX32(bus->regs, reg_cmd, TX_DMA_EN) || 621ba2cccd6SJoe Komlodi SHARED_ARRAY_FIELD_EX32(bus->regs, reg_cmd, RX_BUFF_EN) || 622ba2cccd6SJoe Komlodi SHARED_ARRAY_FIELD_EX32(bus->regs, reg_cmd, TX_BUFF_EN); 623aab90b1cSCédric Le Goater if (!aic->check_sram) { 624aab90b1cSCédric Le Goater return true; 625aab90b1cSCédric Le Goater } 626aab90b1cSCédric Le Goater 627aab90b1cSCédric Le Goater /* 628aab90b1cSCédric Le Goater * AST2500: SRAM must be enabled before using the Buffer Pool or 629aab90b1cSCédric Le Goater * DMA mode. 630aab90b1cSCédric Le Goater */ 6313be3d6ccSJoe Komlodi if (!FIELD_EX32(s->ctrl_global, I2C_CTRL_GLOBAL, SRAM_EN) && dma_en) { 632aab90b1cSCédric Le Goater qemu_log_mask(LOG_GUEST_ERROR, "%s: SRAM is not enabled\n", __func__); 633aab90b1cSCédric Le Goater return false; 634aab90b1cSCédric Le Goater } 635aab90b1cSCédric Le Goater 636aab90b1cSCédric Le Goater return true; 637aab90b1cSCédric Le Goater } 638aab90b1cSCédric Le Goater 63966cc84a1SCédric Le Goater static void aspeed_i2c_bus_cmd_dump(AspeedI2CBus *bus) 64066cc84a1SCédric Le Goater { 641f821bac4SMiroslav Rezanina g_autofree char *cmd_flags = NULL; 64266cc84a1SCédric Le Goater uint32_t count; 643ba2cccd6SJoe Komlodi uint32_t reg_cmd = aspeed_i2c_bus_cmd_offset(bus); 644ba2cccd6SJoe Komlodi uint32_t reg_pool_ctrl = aspeed_i2c_bus_pool_ctrl_offset(bus); 645ba2cccd6SJoe Komlodi uint32_t reg_intr_sts = aspeed_i2c_bus_intr_sts_offset(bus); 646ba2cccd6SJoe Komlodi uint32_t reg_dma_len = aspeed_i2c_bus_dma_len_offset(bus); 647ba2cccd6SJoe Komlodi if (SHARED_ARRAY_FIELD_EX32(bus->regs, reg_cmd, RX_BUFF_EN)) { 648ba2cccd6SJoe Komlodi count = SHARED_ARRAY_FIELD_EX32(bus->regs, reg_pool_ctrl, TX_COUNT); 649ba2cccd6SJoe Komlodi } else if (SHARED_ARRAY_FIELD_EX32(bus->regs, reg_cmd, RX_DMA_EN)) { 650ba2cccd6SJoe Komlodi count = bus->regs[reg_dma_len]; 65166cc84a1SCédric Le Goater } else { /* BYTE mode */ 65266cc84a1SCédric Le Goater count = 1; 65366cc84a1SCédric Le Goater } 65466cc84a1SCédric Le Goater 65566cc84a1SCédric Le Goater cmd_flags = g_strdup_printf("%s%s%s%s%s%s%s%s%s", 656ba2cccd6SJoe Komlodi SHARED_ARRAY_FIELD_EX32(bus->regs, reg_cmd, M_START_CMD) ? "start|" : "", 657ba2cccd6SJoe Komlodi SHARED_ARRAY_FIELD_EX32(bus->regs, reg_cmd, RX_DMA_EN) ? "rxdma|" : "", 658ba2cccd6SJoe Komlodi SHARED_ARRAY_FIELD_EX32(bus->regs, reg_cmd, TX_DMA_EN) ? "txdma|" : "", 659ba2cccd6SJoe Komlodi SHARED_ARRAY_FIELD_EX32(bus->regs, reg_cmd, RX_BUFF_EN) ? "rxbuf|" : "", 660ba2cccd6SJoe Komlodi SHARED_ARRAY_FIELD_EX32(bus->regs, reg_cmd, TX_BUFF_EN) ? "txbuf|" : "", 661ba2cccd6SJoe Komlodi SHARED_ARRAY_FIELD_EX32(bus->regs, reg_cmd, M_TX_CMD) ? "tx|" : "", 662ba2cccd6SJoe Komlodi SHARED_ARRAY_FIELD_EX32(bus->regs, reg_cmd, M_RX_CMD) ? "rx|" : "", 663ba2cccd6SJoe Komlodi SHARED_ARRAY_FIELD_EX32(bus->regs, reg_cmd, M_S_RX_CMD_LAST) ? "last|" : "", 664ba2cccd6SJoe Komlodi SHARED_ARRAY_FIELD_EX32(bus->regs, reg_cmd, M_STOP_CMD) ? "stop|" : ""); 66566cc84a1SCédric Le Goater 666ba2cccd6SJoe Komlodi trace_aspeed_i2c_bus_cmd(bus->regs[reg_cmd], cmd_flags, count, 667ba2cccd6SJoe Komlodi bus->regs[reg_intr_sts]); 66866cc84a1SCédric Le Goater } 66966cc84a1SCédric Le Goater 6704960f084SCédric Le Goater /* 6714960f084SCédric Le Goater * The state machine needs some refinement. It is only used to track 6724960f084SCédric Le Goater * invalid STOP commands for the moment. 6734960f084SCédric Le Goater */ 67416020011SCédric Le Goater static void aspeed_i2c_bus_handle_cmd(AspeedI2CBus *bus, uint64_t value) 67516020011SCédric Le Goater { 6766054fc73SCédric Le Goater uint8_t pool_start = 0; 677ba2cccd6SJoe Komlodi uint32_t reg_intr_sts = aspeed_i2c_bus_intr_sts_offset(bus); 678ba2cccd6SJoe Komlodi uint32_t reg_cmd = aspeed_i2c_bus_cmd_offset(bus); 679ba2cccd6SJoe Komlodi uint32_t reg_pool_ctrl = aspeed_i2c_bus_pool_ctrl_offset(bus); 680ba2cccd6SJoe Komlodi uint32_t reg_dma_len = aspeed_i2c_bus_dma_len_offset(bus); 68116020011SCédric Le Goater 682aab90b1cSCédric Le Goater if (!aspeed_i2c_check_sram(bus)) { 683aab90b1cSCédric Le Goater return; 684aab90b1cSCédric Le Goater } 685aab90b1cSCédric Le Goater 68666cc84a1SCédric Le Goater if (trace_event_get_state_backends(TRACE_ASPEED_I2C_BUS_CMD)) { 68766cc84a1SCédric Le Goater aspeed_i2c_bus_cmd_dump(bus); 68866cc84a1SCédric Le Goater } 68966cc84a1SCédric Le Goater 690ba2cccd6SJoe Komlodi if (SHARED_ARRAY_FIELD_EX32(bus->regs, reg_cmd, M_START_CMD)) { 6914960f084SCédric Le Goater uint8_t state = aspeed_i2c_get_state(bus) & I2CD_MACTIVE ? 6924960f084SCédric Le Goater I2CD_MSTARTR : I2CD_MSTART; 6936054fc73SCédric Le Goater uint8_t addr; 6944960f084SCédric Le Goater 6954960f084SCédric Le Goater aspeed_i2c_set_state(bus, state); 6964960f084SCédric Le Goater 6976054fc73SCédric Le Goater addr = aspeed_i2c_get_addr(bus); 6986054fc73SCédric Le Goater if (i2c_start_transfer(bus->bus, extract32(addr, 1, 7), 6996054fc73SCédric Le Goater extract32(addr, 0, 1))) { 700ba2cccd6SJoe Komlodi SHARED_ARRAY_FIELD_DP32(bus->regs, reg_intr_sts, TX_NAK, 1); 701ba2cccd6SJoe Komlodi if (aspeed_i2c_bus_pkt_mode_en(bus)) { 702ba2cccd6SJoe Komlodi ARRAY_FIELD_DP32(bus->regs, I2CM_INTR_STS, PKT_CMD_FAIL, 1); 703ba2cccd6SJoe Komlodi } 70416020011SCédric Le Goater } else { 705ba2cccd6SJoe Komlodi /* START doesn't set TX_ACK in packet mode */ 706ba2cccd6SJoe Komlodi if (!aspeed_i2c_bus_pkt_mode_en(bus)) { 707ba2cccd6SJoe Komlodi SHARED_ARRAY_FIELD_DP32(bus->regs, reg_intr_sts, TX_ACK, 1); 708ba2cccd6SJoe Komlodi } 70916020011SCédric Le Goater } 71016020011SCédric Le Goater 711ba2cccd6SJoe Komlodi SHARED_ARRAY_FIELD_DP32(bus->regs, reg_cmd, M_START_CMD, 0); 7126054fc73SCédric Le Goater 7136054fc73SCédric Le Goater /* 7146054fc73SCédric Le Goater * The START command is also a TX command, as the slave 7156054fc73SCédric Le Goater * address is sent on the bus. Drop the TX flag if nothing 7166054fc73SCédric Le Goater * else needs to be sent in this sequence. 7176054fc73SCédric Le Goater */ 718ba2cccd6SJoe Komlodi if (SHARED_ARRAY_FIELD_EX32(bus->regs, reg_cmd, TX_BUFF_EN)) { 719ba2cccd6SJoe Komlodi if (SHARED_ARRAY_FIELD_EX32(bus->regs, reg_pool_ctrl, TX_COUNT) 720ba2cccd6SJoe Komlodi == 1) { 721ba2cccd6SJoe Komlodi SHARED_ARRAY_FIELD_DP32(bus->regs, reg_cmd, M_TX_CMD, 0); 7226054fc73SCédric Le Goater } else { 7236054fc73SCédric Le Goater /* 7246054fc73SCédric Le Goater * Increase the start index in the TX pool buffer to 7256054fc73SCédric Le Goater * skip the address byte. 7266054fc73SCédric Le Goater */ 7276054fc73SCédric Le Goater pool_start++; 7286054fc73SCédric Le Goater } 729ba2cccd6SJoe Komlodi } else if (SHARED_ARRAY_FIELD_EX32(bus->regs, reg_cmd, TX_DMA_EN)) { 730ba2cccd6SJoe Komlodi if (bus->regs[reg_dma_len] == 0) { 731ba2cccd6SJoe Komlodi SHARED_ARRAY_FIELD_DP32(bus->regs, reg_cmd, M_TX_CMD, 0); 732545d6befSCédric Le Goater } 7336054fc73SCédric Le Goater } else { 734ba2cccd6SJoe Komlodi SHARED_ARRAY_FIELD_DP32(bus->regs, reg_cmd, M_TX_CMD, 0); 7356054fc73SCédric Le Goater } 736ddabca75SCédric Le Goater 737ddabca75SCédric Le Goater /* No slave found */ 738ddabca75SCédric Le Goater if (!i2c_bus_busy(bus->bus)) { 739ba2cccd6SJoe Komlodi if (aspeed_i2c_bus_pkt_mode_en(bus)) { 740ba2cccd6SJoe Komlodi ARRAY_FIELD_DP32(bus->regs, I2CM_INTR_STS, PKT_CMD_FAIL, 1); 741ba2cccd6SJoe Komlodi ARRAY_FIELD_DP32(bus->regs, I2CM_INTR_STS, PKT_CMD_DONE, 1); 742ba2cccd6SJoe Komlodi } 743ddabca75SCédric Le Goater return; 744ddabca75SCédric Le Goater } 7454960f084SCédric Le Goater aspeed_i2c_set_state(bus, I2CD_MACTIVE); 746ddabca75SCédric Le Goater } 747ddabca75SCédric Le Goater 748ba2cccd6SJoe Komlodi if (SHARED_ARRAY_FIELD_EX32(bus->regs, reg_cmd, M_TX_CMD)) { 7494960f084SCédric Le Goater aspeed_i2c_set_state(bus, I2CD_MTXD); 7506054fc73SCédric Le Goater if (aspeed_i2c_bus_send(bus, pool_start)) { 751ba2cccd6SJoe Komlodi SHARED_ARRAY_FIELD_DP32(bus->regs, reg_intr_sts, TX_NAK, 1); 75216020011SCédric Le Goater i2c_end_transfer(bus->bus); 75316020011SCédric Le Goater } else { 754ba2cccd6SJoe Komlodi SHARED_ARRAY_FIELD_DP32(bus->regs, reg_intr_sts, TX_ACK, 1); 75516020011SCédric Le Goater } 756ba2cccd6SJoe Komlodi SHARED_ARRAY_FIELD_DP32(bus->regs, reg_cmd, M_TX_CMD, 0); 7574960f084SCédric Le Goater aspeed_i2c_set_state(bus, I2CD_MACTIVE); 758ddabca75SCédric Le Goater } 75916020011SCédric Le Goater 760ba2cccd6SJoe Komlodi if ((SHARED_ARRAY_FIELD_EX32(bus->regs, reg_cmd, M_RX_CMD) || 761ba2cccd6SJoe Komlodi SHARED_ARRAY_FIELD_EX32(bus->regs, reg_cmd, M_S_RX_CMD_LAST)) && 762ba2cccd6SJoe Komlodi !SHARED_ARRAY_FIELD_EX32(bus->regs, reg_intr_sts, RX_DONE)) { 7637bd9c60dSGuenter Roeck aspeed_i2c_handle_rx_cmd(bus); 76416020011SCédric Le Goater } 76516020011SCédric Le Goater 766ba2cccd6SJoe Komlodi if (SHARED_ARRAY_FIELD_EX32(bus->regs, reg_cmd, M_STOP_CMD)) { 7674960f084SCédric Le Goater if (!(aspeed_i2c_get_state(bus) & I2CD_MACTIVE)) { 7684960f084SCédric Le Goater qemu_log_mask(LOG_GUEST_ERROR, "%s: abnormal stop\n", __func__); 769ba2cccd6SJoe Komlodi SHARED_ARRAY_FIELD_DP32(bus->regs, reg_intr_sts, ABNORMAL, 1); 770ba2cccd6SJoe Komlodi if (aspeed_i2c_bus_pkt_mode_en(bus)) { 771ba2cccd6SJoe Komlodi ARRAY_FIELD_DP32(bus->regs, I2CM_INTR_STS, PKT_CMD_FAIL, 1); 772ba2cccd6SJoe Komlodi } 77316020011SCédric Le Goater } else { 7744960f084SCédric Le Goater aspeed_i2c_set_state(bus, I2CD_MSTOP); 77516020011SCédric Le Goater i2c_end_transfer(bus->bus); 776ba2cccd6SJoe Komlodi SHARED_ARRAY_FIELD_DP32(bus->regs, reg_intr_sts, NORMAL_STOP, 1); 77716020011SCédric Le Goater } 778ba2cccd6SJoe Komlodi SHARED_ARRAY_FIELD_DP32(bus->regs, reg_cmd, M_STOP_CMD, 0); 7794960f084SCédric Le Goater aspeed_i2c_set_state(bus, I2CD_IDLE); 78016020011SCédric Le Goater } 781ba2cccd6SJoe Komlodi 782ba2cccd6SJoe Komlodi if (aspeed_i2c_bus_pkt_mode_en(bus)) { 783ba2cccd6SJoe Komlodi ARRAY_FIELD_DP32(bus->regs, I2CM_INTR_STS, PKT_CMD_DONE, 1); 784ba2cccd6SJoe Komlodi } 78516020011SCédric Le Goater } 78616020011SCédric Le Goater 787ba2cccd6SJoe Komlodi static void aspeed_i2c_bus_new_write(AspeedI2CBus *bus, hwaddr offset, 78816020011SCédric Le Goater uint64_t value, unsigned size) 78916020011SCédric Le Goater { 790ba2cccd6SJoe Komlodi AspeedI2CClass *aic = ASPEED_I2C_GET_CLASS(bus->controller); 791ba2cccd6SJoe Komlodi bool handle_rx; 792ba2cccd6SJoe Komlodi bool w1t; 793ba2cccd6SJoe Komlodi 794ba2cccd6SJoe Komlodi trace_aspeed_i2c_bus_write(bus->id, offset, size, value); 795ba2cccd6SJoe Komlodi 796ba2cccd6SJoe Komlodi switch (offset) { 797ba2cccd6SJoe Komlodi case A_I2CC_FUN_CTRL: 798ba2cccd6SJoe Komlodi if (SHARED_FIELD_EX32(value, SLAVE_EN)) { 799ba2cccd6SJoe Komlodi qemu_log_mask(LOG_UNIMP, "%s: slave mode not implemented\n", 800ba2cccd6SJoe Komlodi __func__); 801ba2cccd6SJoe Komlodi break; 802ba2cccd6SJoe Komlodi } 803ba2cccd6SJoe Komlodi bus->regs[R_I2CD_FUN_CTRL] = value & 0x007dc3ff; 804ba2cccd6SJoe Komlodi break; 805ba2cccd6SJoe Komlodi case A_I2CC_AC_TIMING: 806ba2cccd6SJoe Komlodi bus->regs[R_I2CC_AC_TIMING] = value & 0x1ffff0ff; 807ba2cccd6SJoe Komlodi break; 808ba2cccd6SJoe Komlodi case A_I2CC_MS_TXRX_BYTE_BUF: 809ba2cccd6SJoe Komlodi SHARED_ARRAY_FIELD_DP32(bus->regs, R_I2CC_MS_TXRX_BYTE_BUF, TX_BUF, 810ba2cccd6SJoe Komlodi value); 811ba2cccd6SJoe Komlodi break; 812ba2cccd6SJoe Komlodi case A_I2CC_POOL_CTRL: 813ba2cccd6SJoe Komlodi bus->regs[R_I2CC_POOL_CTRL] &= ~0xffffff; 814ba2cccd6SJoe Komlodi bus->regs[R_I2CC_POOL_CTRL] |= (value & 0xffffff); 815ba2cccd6SJoe Komlodi break; 816ba2cccd6SJoe Komlodi case A_I2CM_INTR_CTRL: 817ba2cccd6SJoe Komlodi bus->regs[R_I2CM_INTR_CTRL] = value & 0x0007f07f; 818ba2cccd6SJoe Komlodi break; 819ba2cccd6SJoe Komlodi case A_I2CM_INTR_STS: 820ba2cccd6SJoe Komlodi handle_rx = SHARED_ARRAY_FIELD_EX32(bus->regs, R_I2CM_INTR_STS, RX_DONE) 821ba2cccd6SJoe Komlodi && SHARED_FIELD_EX32(value, RX_DONE); 822ba2cccd6SJoe Komlodi 823ba2cccd6SJoe Komlodi /* In packet mode, clearing PKT_CMD_DONE clears other interrupts. */ 824ba2cccd6SJoe Komlodi if (aspeed_i2c_bus_pkt_mode_en(bus) && 825ba2cccd6SJoe Komlodi FIELD_EX32(value, I2CM_INTR_STS, PKT_CMD_DONE)) { 826ba2cccd6SJoe Komlodi bus->regs[R_I2CM_INTR_STS] &= 0xf0001000; 827ba2cccd6SJoe Komlodi if (!bus->regs[R_I2CM_INTR_STS]) { 828ba2cccd6SJoe Komlodi bus->controller->intr_status &= ~(1 << bus->id); 829ba2cccd6SJoe Komlodi qemu_irq_lower(aic->bus_get_irq(bus)); 830ba2cccd6SJoe Komlodi } 831ba2cccd6SJoe Komlodi break; 832ba2cccd6SJoe Komlodi } 833ba2cccd6SJoe Komlodi bus->regs[R_I2CM_INTR_STS] &= ~(value & 0xf007f07f); 834ba2cccd6SJoe Komlodi if (!bus->regs[R_I2CM_INTR_STS]) { 835ba2cccd6SJoe Komlodi bus->controller->intr_status &= ~(1 << bus->id); 836ba2cccd6SJoe Komlodi qemu_irq_lower(aic->bus_get_irq(bus)); 837ba2cccd6SJoe Komlodi } 838ba2cccd6SJoe Komlodi if (handle_rx && (SHARED_ARRAY_FIELD_EX32(bus->regs, R_I2CM_CMD, 839ba2cccd6SJoe Komlodi M_RX_CMD) || 840ba2cccd6SJoe Komlodi SHARED_ARRAY_FIELD_EX32(bus->regs, R_I2CM_CMD, 841ba2cccd6SJoe Komlodi M_S_RX_CMD_LAST))) { 842ba2cccd6SJoe Komlodi aspeed_i2c_handle_rx_cmd(bus); 843ba2cccd6SJoe Komlodi aspeed_i2c_bus_raise_interrupt(bus); 844ba2cccd6SJoe Komlodi } 845ba2cccd6SJoe Komlodi break; 846ba2cccd6SJoe Komlodi case A_I2CM_CMD: 847ba2cccd6SJoe Komlodi if (!aspeed_i2c_bus_is_enabled(bus)) { 848ba2cccd6SJoe Komlodi break; 849ba2cccd6SJoe Komlodi } 850ba2cccd6SJoe Komlodi 851ba2cccd6SJoe Komlodi if (!aspeed_i2c_bus_is_master(bus)) { 852ba2cccd6SJoe Komlodi qemu_log_mask(LOG_UNIMP, "%s: slave mode not implemented\n", 853ba2cccd6SJoe Komlodi __func__); 854ba2cccd6SJoe Komlodi break; 855ba2cccd6SJoe Komlodi } 856ba2cccd6SJoe Komlodi 857ba2cccd6SJoe Komlodi if (!aic->has_dma && 858ba2cccd6SJoe Komlodi (SHARED_FIELD_EX32(value, RX_DMA_EN) || 859ba2cccd6SJoe Komlodi SHARED_FIELD_EX32(value, TX_DMA_EN))) { 860ba2cccd6SJoe Komlodi qemu_log_mask(LOG_GUEST_ERROR, "%s: No DMA support\n", __func__); 861ba2cccd6SJoe Komlodi break; 862ba2cccd6SJoe Komlodi } 863ba2cccd6SJoe Komlodi 864ba2cccd6SJoe Komlodi if (bus->regs[R_I2CM_INTR_STS] & 0xffff0000) { 865ba2cccd6SJoe Komlodi qemu_log_mask(LOG_UNIMP, "%s: Packet mode is not implemented\n", 866ba2cccd6SJoe Komlodi __func__); 867ba2cccd6SJoe Komlodi break; 868ba2cccd6SJoe Komlodi } 869ba2cccd6SJoe Komlodi 870ba2cccd6SJoe Komlodi value &= 0xff0ffbfb; 871ba2cccd6SJoe Komlodi if (ARRAY_FIELD_EX32(bus->regs, I2CM_CMD, W1_CTRL)) { 872ba2cccd6SJoe Komlodi bus->regs[R_I2CM_CMD] |= value; 873ba2cccd6SJoe Komlodi } else { 874ba2cccd6SJoe Komlodi bus->regs[R_I2CM_CMD] = value; 875ba2cccd6SJoe Komlodi } 876ba2cccd6SJoe Komlodi 877ba2cccd6SJoe Komlodi aspeed_i2c_bus_handle_cmd(bus, value); 878ba2cccd6SJoe Komlodi aspeed_i2c_bus_raise_interrupt(bus); 879ba2cccd6SJoe Komlodi break; 880ba2cccd6SJoe Komlodi case A_I2CM_DMA_TX_ADDR: 881ba2cccd6SJoe Komlodi bus->regs[R_I2CM_DMA_TX_ADDR] = FIELD_EX32(value, I2CM_DMA_TX_ADDR, 882ba2cccd6SJoe Komlodi ADDR); 883ba2cccd6SJoe Komlodi bus->regs[R_I2CC_DMA_ADDR] = FIELD_EX32(value, I2CM_DMA_TX_ADDR, ADDR); 884ba2cccd6SJoe Komlodi bus->regs[R_I2CC_DMA_LEN] = ARRAY_FIELD_EX32(bus->regs, I2CM_DMA_LEN, 885ba2cccd6SJoe Komlodi TX_BUF_LEN) + 1; 886ba2cccd6SJoe Komlodi break; 887ba2cccd6SJoe Komlodi case A_I2CM_DMA_RX_ADDR: 888ba2cccd6SJoe Komlodi bus->regs[R_I2CM_DMA_RX_ADDR] = FIELD_EX32(value, I2CM_DMA_RX_ADDR, 889ba2cccd6SJoe Komlodi ADDR); 890ba2cccd6SJoe Komlodi bus->regs[R_I2CC_DMA_ADDR] = FIELD_EX32(value, I2CM_DMA_RX_ADDR, ADDR); 891ba2cccd6SJoe Komlodi bus->regs[R_I2CC_DMA_LEN] = ARRAY_FIELD_EX32(bus->regs, I2CM_DMA_LEN, 892ba2cccd6SJoe Komlodi RX_BUF_LEN) + 1; 893ba2cccd6SJoe Komlodi break; 894ba2cccd6SJoe Komlodi case A_I2CM_DMA_LEN: 895ba2cccd6SJoe Komlodi w1t = ARRAY_FIELD_EX32(bus->regs, I2CM_DMA_LEN, RX_BUF_LEN_W1T) || 896ba2cccd6SJoe Komlodi ARRAY_FIELD_EX32(bus->regs, I2CM_DMA_LEN, TX_BUF_LEN_W1T); 897ba2cccd6SJoe Komlodi /* If none of the w1t bits are set, just write to the reg as normal. */ 898ba2cccd6SJoe Komlodi if (!w1t) { 899ba2cccd6SJoe Komlodi bus->regs[R_I2CM_DMA_LEN] = value; 900ba2cccd6SJoe Komlodi break; 901ba2cccd6SJoe Komlodi } 902ba2cccd6SJoe Komlodi if (ARRAY_FIELD_EX32(bus->regs, I2CM_DMA_LEN, RX_BUF_LEN_W1T)) { 903ba2cccd6SJoe Komlodi ARRAY_FIELD_DP32(bus->regs, I2CM_DMA_LEN, RX_BUF_LEN, 904ba2cccd6SJoe Komlodi FIELD_EX32(value, I2CM_DMA_LEN, RX_BUF_LEN)); 905ba2cccd6SJoe Komlodi } 906ba2cccd6SJoe Komlodi if (ARRAY_FIELD_EX32(bus->regs, I2CM_DMA_LEN, TX_BUF_LEN_W1T)) { 907ba2cccd6SJoe Komlodi ARRAY_FIELD_DP32(bus->regs, I2CM_DMA_LEN, TX_BUF_LEN, 908ba2cccd6SJoe Komlodi FIELD_EX32(value, I2CM_DMA_LEN, TX_BUF_LEN)); 909ba2cccd6SJoe Komlodi } 910ba2cccd6SJoe Komlodi break; 911ba2cccd6SJoe Komlodi case A_I2CM_DMA_LEN_STS: 912ba2cccd6SJoe Komlodi /* Writes clear to 0 */ 913ba2cccd6SJoe Komlodi bus->regs[R_I2CM_DMA_LEN_STS] = 0; 914ba2cccd6SJoe Komlodi break; 915ba2cccd6SJoe Komlodi case A_I2CC_DMA_ADDR: 916ba2cccd6SJoe Komlodi case A_I2CC_DMA_LEN: 917ba2cccd6SJoe Komlodi /* RO */ 918ba2cccd6SJoe Komlodi break; 919ba2cccd6SJoe Komlodi case A_I2CS_DMA_LEN_STS: 920ba2cccd6SJoe Komlodi case A_I2CS_DMA_TX_ADDR: 921ba2cccd6SJoe Komlodi case A_I2CS_DMA_RX_ADDR: 922ba2cccd6SJoe Komlodi case A_I2CS_DEV_ADDR: 923ba2cccd6SJoe Komlodi case A_I2CS_INTR_CTRL: 924ba2cccd6SJoe Komlodi case A_I2CS_INTR_STS: 925ba2cccd6SJoe Komlodi case A_I2CS_CMD: 926ba2cccd6SJoe Komlodi case A_I2CS_DMA_LEN: 927ba2cccd6SJoe Komlodi qemu_log_mask(LOG_UNIMP, "%s: Slave mode is not implemented\n", 928ba2cccd6SJoe Komlodi __func__); 929ba2cccd6SJoe Komlodi break; 930ba2cccd6SJoe Komlodi default: 931ba2cccd6SJoe Komlodi qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad offset 0x%" HWADDR_PRIx "\n", 932ba2cccd6SJoe Komlodi __func__, offset); 933ba2cccd6SJoe Komlodi } 934ba2cccd6SJoe Komlodi } 935ba2cccd6SJoe Komlodi 936ba2cccd6SJoe Komlodi static void aspeed_i2c_bus_old_write(AspeedI2CBus *bus, hwaddr offset, 937ba2cccd6SJoe Komlodi uint64_t value, unsigned size) 938ba2cccd6SJoe Komlodi { 93951dd4923SCédric Le Goater AspeedI2CClass *aic = ASPEED_I2C_GET_CLASS(bus->controller); 940bb626e5bSGuenter Roeck bool handle_rx; 94116020011SCédric Le Goater 94266cc84a1SCédric Le Goater trace_aspeed_i2c_bus_write(bus->id, offset, size, value); 94366cc84a1SCédric Le Goater 94416020011SCédric Le Goater switch (offset) { 9453be3d6ccSJoe Komlodi case A_I2CD_FUN_CTRL: 946ba2cccd6SJoe Komlodi if (SHARED_FIELD_EX32(value, SLAVE_EN)) { 94716020011SCédric Le Goater qemu_log_mask(LOG_UNIMP, "%s: slave mode not implemented\n", 94816020011SCédric Le Goater __func__); 94916020011SCédric Le Goater break; 95016020011SCédric Le Goater } 9512260fc6fSJoe Komlodi bus->regs[R_I2CD_FUN_CTRL] = value & 0x0071C3FF; 95216020011SCédric Le Goater break; 9533be3d6ccSJoe Komlodi case A_I2CD_AC_TIMING1: 9542260fc6fSJoe Komlodi bus->regs[R_I2CD_AC_TIMING1] = value & 0xFFFFF0F; 95516020011SCédric Le Goater break; 9563be3d6ccSJoe Komlodi case A_I2CD_AC_TIMING2: 9572260fc6fSJoe Komlodi bus->regs[R_I2CD_AC_TIMING2] = value & 0x7; 95816020011SCédric Le Goater break; 9593be3d6ccSJoe Komlodi case A_I2CD_INTR_CTRL: 9602260fc6fSJoe Komlodi bus->regs[R_I2CD_INTR_CTRL] = value & 0x7FFF; 96116020011SCédric Le Goater break; 9623be3d6ccSJoe Komlodi case A_I2CD_INTR_STS: 963ba2cccd6SJoe Komlodi handle_rx = SHARED_ARRAY_FIELD_EX32(bus->regs, R_I2CD_INTR_STS, RX_DONE) 964ba2cccd6SJoe Komlodi && SHARED_FIELD_EX32(value, RX_DONE); 9652260fc6fSJoe Komlodi bus->regs[R_I2CD_INTR_STS] &= ~(value & 0x7FFF); 9662260fc6fSJoe Komlodi if (!bus->regs[R_I2CD_INTR_STS]) { 96716020011SCédric Le Goater bus->controller->intr_status &= ~(1 << bus->id); 96851dd4923SCédric Le Goater qemu_irq_lower(aic->bus_get_irq(bus)); 9695540cb97SCédric Le Goater } 970ba2cccd6SJoe Komlodi if (handle_rx && (SHARED_ARRAY_FIELD_EX32(bus->regs, R_I2CD_CMD, 971ba2cccd6SJoe Komlodi M_RX_CMD) || 972ba2cccd6SJoe Komlodi SHARED_ARRAY_FIELD_EX32(bus->regs, R_I2CD_CMD, 973ba2cccd6SJoe Komlodi M_S_RX_CMD_LAST))) { 974bb626e5bSGuenter Roeck aspeed_i2c_handle_rx_cmd(bus); 975bb626e5bSGuenter Roeck aspeed_i2c_bus_raise_interrupt(bus); 976bb626e5bSGuenter Roeck } 97716020011SCédric Le Goater break; 9783be3d6ccSJoe Komlodi case A_I2CD_DEV_ADDR: 97916020011SCédric Le Goater qemu_log_mask(LOG_UNIMP, "%s: slave mode not implemented\n", 98016020011SCédric Le Goater __func__); 98116020011SCédric Le Goater break; 9823be3d6ccSJoe Komlodi case A_I2CD_POOL_CTRL: 9832260fc6fSJoe Komlodi bus->regs[R_I2CD_POOL_CTRL] &= ~0xffffff; 9842260fc6fSJoe Komlodi bus->regs[R_I2CD_POOL_CTRL] |= (value & 0xffffff); 9856054fc73SCédric Le Goater break; 9866054fc73SCédric Le Goater 9873be3d6ccSJoe Komlodi case A_I2CD_BYTE_BUF: 988ba2cccd6SJoe Komlodi SHARED_ARRAY_FIELD_DP32(bus->regs, R_I2CD_BYTE_BUF, TX_BUF, value); 98916020011SCédric Le Goater break; 9903be3d6ccSJoe Komlodi case A_I2CD_CMD: 99116020011SCédric Le Goater if (!aspeed_i2c_bus_is_enabled(bus)) { 99216020011SCédric Le Goater break; 99316020011SCédric Le Goater } 99416020011SCédric Le Goater 99516020011SCédric Le Goater if (!aspeed_i2c_bus_is_master(bus)) { 99616020011SCédric Le Goater qemu_log_mask(LOG_UNIMP, "%s: slave mode not implemented\n", 99716020011SCédric Le Goater __func__); 99816020011SCédric Le Goater break; 99916020011SCédric Le Goater } 100016020011SCédric Le Goater 1001545d6befSCédric Le Goater if (!aic->has_dma && 1002ba2cccd6SJoe Komlodi (SHARED_FIELD_EX32(value, RX_DMA_EN) || 1003ba2cccd6SJoe Komlodi SHARED_FIELD_EX32(value, TX_DMA_EN))) { 1004545d6befSCédric Le Goater qemu_log_mask(LOG_GUEST_ERROR, "%s: No DMA support\n", __func__); 1005545d6befSCédric Le Goater break; 1006545d6befSCédric Le Goater } 1007545d6befSCédric Le Goater 1008ba2cccd6SJoe Komlodi bus->regs[R_I2CD_CMD] &= ~0xFFFF; 1009ba2cccd6SJoe Komlodi bus->regs[R_I2CD_CMD] |= value & 0xFFFF; 1010ba2cccd6SJoe Komlodi 101116020011SCédric Le Goater aspeed_i2c_bus_handle_cmd(bus, value); 1012ddabca75SCédric Le Goater aspeed_i2c_bus_raise_interrupt(bus); 101316020011SCédric Le Goater break; 10143be3d6ccSJoe Komlodi case A_I2CD_DMA_ADDR: 1015545d6befSCédric Le Goater if (!aic->has_dma) { 1016545d6befSCédric Le Goater qemu_log_mask(LOG_GUEST_ERROR, "%s: No DMA support\n", __func__); 1017545d6befSCédric Le Goater break; 1018545d6befSCédric Le Goater } 1019545d6befSCédric Le Goater 10202260fc6fSJoe Komlodi bus->regs[R_I2CD_DMA_ADDR] = value & 0x3ffffffc; 1021545d6befSCédric Le Goater break; 1022545d6befSCédric Le Goater 10233be3d6ccSJoe Komlodi case A_I2CD_DMA_LEN: 1024545d6befSCédric Le Goater if (!aic->has_dma) { 1025545d6befSCédric Le Goater qemu_log_mask(LOG_GUEST_ERROR, "%s: No DMA support\n", __func__); 1026545d6befSCédric Le Goater break; 1027545d6befSCédric Le Goater } 1028545d6befSCédric Le Goater 10292260fc6fSJoe Komlodi bus->regs[R_I2CD_DMA_LEN] = value & 0xfff; 10302260fc6fSJoe Komlodi if (!bus->regs[R_I2CD_DMA_LEN]) { 1031545d6befSCédric Le Goater qemu_log_mask(LOG_UNIMP, "%s: invalid DMA length\n", __func__); 1032545d6befSCédric Le Goater } 1033545d6befSCédric Le Goater break; 103416020011SCédric Le Goater 103516020011SCédric Le Goater default: 103616020011SCédric Le Goater qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad offset 0x%" HWADDR_PRIx "\n", 103716020011SCédric Le Goater __func__, offset); 103816020011SCédric Le Goater } 103916020011SCédric Le Goater } 104016020011SCédric Le Goater 1041ba2cccd6SJoe Komlodi static void aspeed_i2c_bus_write(void *opaque, hwaddr offset, 1042ba2cccd6SJoe Komlodi uint64_t value, unsigned size) 1043ba2cccd6SJoe Komlodi { 1044ba2cccd6SJoe Komlodi AspeedI2CBus *bus = opaque; 1045ba2cccd6SJoe Komlodi if (aspeed_i2c_is_new_mode(bus->controller)) { 1046ba2cccd6SJoe Komlodi aspeed_i2c_bus_new_write(bus, offset, value, size); 1047ba2cccd6SJoe Komlodi } else { 1048ba2cccd6SJoe Komlodi aspeed_i2c_bus_old_write(bus, offset, value, size); 1049ba2cccd6SJoe Komlodi } 1050ba2cccd6SJoe Komlodi } 1051ba2cccd6SJoe Komlodi 105216020011SCédric Le Goater static uint64_t aspeed_i2c_ctrl_read(void *opaque, hwaddr offset, 105316020011SCédric Le Goater unsigned size) 105416020011SCédric Le Goater { 105516020011SCédric Le Goater AspeedI2CState *s = opaque; 105616020011SCédric Le Goater 105716020011SCédric Le Goater switch (offset) { 10583be3d6ccSJoe Komlodi case A_I2C_CTRL_STATUS: 105916020011SCédric Le Goater return s->intr_status; 10603be3d6ccSJoe Komlodi case A_I2C_CTRL_GLOBAL: 1061aab90b1cSCédric Le Goater return s->ctrl_global; 1062ba2cccd6SJoe Komlodi case A_I2C_CTRL_NEW_CLK_DIVIDER: 1063ba2cccd6SJoe Komlodi if (aspeed_i2c_is_new_mode(s)) { 1064ba2cccd6SJoe Komlodi return s->new_clk_divider; 1065ba2cccd6SJoe Komlodi } 1066ba2cccd6SJoe Komlodi qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad offset 0x%" HWADDR_PRIx "\n", 1067ba2cccd6SJoe Komlodi __func__, offset); 1068ba2cccd6SJoe Komlodi break; 106916020011SCédric Le Goater default: 107016020011SCédric Le Goater qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad offset 0x%" HWADDR_PRIx "\n", 107116020011SCédric Le Goater __func__, offset); 107216020011SCédric Le Goater break; 107316020011SCédric Le Goater } 107416020011SCédric Le Goater 107516020011SCédric Le Goater return -1; 107616020011SCédric Le Goater } 107716020011SCédric Le Goater 107816020011SCédric Le Goater static void aspeed_i2c_ctrl_write(void *opaque, hwaddr offset, 107916020011SCédric Le Goater uint64_t value, unsigned size) 108016020011SCédric Le Goater { 1081aab90b1cSCédric Le Goater AspeedI2CState *s = opaque; 1082aab90b1cSCédric Le Goater 108316020011SCédric Le Goater switch (offset) { 10843be3d6ccSJoe Komlodi case A_I2C_CTRL_GLOBAL: 1085aab90b1cSCédric Le Goater s->ctrl_global = value; 1086aab90b1cSCédric Le Goater break; 1087ba2cccd6SJoe Komlodi case A_I2C_CTRL_NEW_CLK_DIVIDER: 1088ba2cccd6SJoe Komlodi if (aspeed_i2c_is_new_mode(s)) { 1089ba2cccd6SJoe Komlodi s->new_clk_divider = value; 1090ba2cccd6SJoe Komlodi } else { 1091ba2cccd6SJoe Komlodi qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad offset 0x%" HWADDR_PRIx 1092ba2cccd6SJoe Komlodi "\n", __func__, offset); 1093ba2cccd6SJoe Komlodi } 1094ba2cccd6SJoe Komlodi break; 10953be3d6ccSJoe Komlodi case A_I2C_CTRL_STATUS: 109616020011SCédric Le Goater default: 109716020011SCédric Le Goater qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad offset 0x%" HWADDR_PRIx "\n", 109816020011SCédric Le Goater __func__, offset); 109916020011SCédric Le Goater break; 110016020011SCédric Le Goater } 110116020011SCédric Le Goater } 110216020011SCédric Le Goater 110316020011SCédric Le Goater static const MemoryRegionOps aspeed_i2c_bus_ops = { 110416020011SCédric Le Goater .read = aspeed_i2c_bus_read, 110516020011SCédric Le Goater .write = aspeed_i2c_bus_write, 110616020011SCédric Le Goater .endianness = DEVICE_LITTLE_ENDIAN, 110716020011SCédric Le Goater }; 110816020011SCédric Le Goater 110916020011SCédric Le Goater static const MemoryRegionOps aspeed_i2c_ctrl_ops = { 111016020011SCédric Le Goater .read = aspeed_i2c_ctrl_read, 111116020011SCédric Le Goater .write = aspeed_i2c_ctrl_write, 111216020011SCédric Le Goater .endianness = DEVICE_LITTLE_ENDIAN, 111316020011SCédric Le Goater }; 111416020011SCédric Le Goater 11156054fc73SCédric Le Goater static uint64_t aspeed_i2c_pool_read(void *opaque, hwaddr offset, 11166054fc73SCédric Le Goater unsigned size) 11176054fc73SCédric Le Goater { 11186054fc73SCédric Le Goater AspeedI2CState *s = opaque; 11196054fc73SCédric Le Goater uint64_t ret = 0; 11206054fc73SCédric Le Goater int i; 11216054fc73SCédric Le Goater 11226054fc73SCédric Le Goater for (i = 0; i < size; i++) { 11236054fc73SCédric Le Goater ret |= (uint64_t) s->pool[offset + i] << (8 * i); 11246054fc73SCédric Le Goater } 11256054fc73SCédric Le Goater 11266054fc73SCédric Le Goater return ret; 11276054fc73SCédric Le Goater } 11286054fc73SCédric Le Goater 11296054fc73SCédric Le Goater static void aspeed_i2c_pool_write(void *opaque, hwaddr offset, 11306054fc73SCédric Le Goater uint64_t value, unsigned size) 11316054fc73SCédric Le Goater { 11326054fc73SCédric Le Goater AspeedI2CState *s = opaque; 11336054fc73SCédric Le Goater int i; 11346054fc73SCédric Le Goater 11356054fc73SCédric Le Goater for (i = 0; i < size; i++) { 11366054fc73SCédric Le Goater s->pool[offset + i] = (value >> (8 * i)) & 0xFF; 11376054fc73SCédric Le Goater } 11386054fc73SCédric Le Goater } 11396054fc73SCédric Le Goater 11406054fc73SCédric Le Goater static const MemoryRegionOps aspeed_i2c_pool_ops = { 11416054fc73SCédric Le Goater .read = aspeed_i2c_pool_read, 11426054fc73SCédric Le Goater .write = aspeed_i2c_pool_write, 11436054fc73SCédric Le Goater .endianness = DEVICE_LITTLE_ENDIAN, 11446054fc73SCédric Le Goater .valid = { 11456054fc73SCédric Le Goater .min_access_size = 1, 11466054fc73SCédric Le Goater .max_access_size = 4, 11476054fc73SCédric Le Goater }, 11486054fc73SCédric Le Goater }; 11496054fc73SCédric Le Goater 115016020011SCédric Le Goater static const VMStateDescription aspeed_i2c_bus_vmstate = { 115116020011SCédric Le Goater .name = TYPE_ASPEED_I2C, 1152ba2cccd6SJoe Komlodi .version_id = 5, 1153ba2cccd6SJoe Komlodi .minimum_version_id = 5, 115416020011SCédric Le Goater .fields = (VMStateField[]) { 1155ba2cccd6SJoe Komlodi VMSTATE_UINT32_ARRAY(regs, AspeedI2CBus, ASPEED_I2C_NEW_NUM_REG), 115616020011SCédric Le Goater VMSTATE_END_OF_LIST() 115716020011SCédric Le Goater } 115816020011SCédric Le Goater }; 115916020011SCédric Le Goater 116016020011SCédric Le Goater static const VMStateDescription aspeed_i2c_vmstate = { 116116020011SCédric Le Goater .name = TYPE_ASPEED_I2C, 11626054fc73SCédric Le Goater .version_id = 2, 11636054fc73SCédric Le Goater .minimum_version_id = 2, 116416020011SCédric Le Goater .fields = (VMStateField[]) { 116516020011SCédric Le Goater VMSTATE_UINT32(intr_status, AspeedI2CState), 116616020011SCédric Le Goater VMSTATE_STRUCT_ARRAY(busses, AspeedI2CState, 116716020011SCédric Le Goater ASPEED_I2C_NR_BUSSES, 1, aspeed_i2c_bus_vmstate, 116816020011SCédric Le Goater AspeedI2CBus), 11696054fc73SCédric Le Goater VMSTATE_UINT8_ARRAY(pool, AspeedI2CState, ASPEED_I2C_MAX_POOL_SIZE), 117016020011SCédric Le Goater VMSTATE_END_OF_LIST() 117116020011SCédric Le Goater } 117216020011SCédric Le Goater }; 117316020011SCédric Le Goater 117416020011SCédric Le Goater static void aspeed_i2c_reset(DeviceState *dev) 117516020011SCédric Le Goater { 117616020011SCédric Le Goater AspeedI2CState *s = ASPEED_I2C(dev); 117716020011SCédric Le Goater 117816020011SCédric Le Goater s->intr_status = 0; 117960261038SCédric Le Goater } 118060261038SCédric Le Goater 118160261038SCédric Le Goater static void aspeed_i2c_instance_init(Object *obj) 118260261038SCédric Le Goater { 118360261038SCédric Le Goater AspeedI2CState *s = ASPEED_I2C(obj); 118460261038SCédric Le Goater AspeedI2CClass *aic = ASPEED_I2C_GET_CLASS(s); 118560261038SCédric Le Goater int i; 118616020011SCédric Le Goater 1187f7da1aa8SCédric Le Goater for (i = 0; i < aic->num_busses; i++) { 118860261038SCédric Le Goater object_initialize_child(obj, "bus[*]", &s->busses[i], 118960261038SCédric Le Goater TYPE_ASPEED_I2C_BUS); 119016020011SCédric Le Goater } 119116020011SCédric Le Goater } 119216020011SCédric Le Goater 119316020011SCédric Le Goater /* 1194f7da1aa8SCédric Le Goater * Address Definitions (AST2400 and AST2500) 119516020011SCédric Le Goater * 119616020011SCédric Le Goater * 0x000 ... 0x03F: Global Register 119716020011SCédric Le Goater * 0x040 ... 0x07F: Device 1 119816020011SCédric Le Goater * 0x080 ... 0x0BF: Device 2 119916020011SCédric Le Goater * 0x0C0 ... 0x0FF: Device 3 120016020011SCédric Le Goater * 0x100 ... 0x13F: Device 4 120116020011SCédric Le Goater * 0x140 ... 0x17F: Device 5 120216020011SCédric Le Goater * 0x180 ... 0x1BF: Device 6 120316020011SCédric Le Goater * 0x1C0 ... 0x1FF: Device 7 120416020011SCédric Le Goater * 0x200 ... 0x2FF: Buffer Pool (unused in linux driver) 120516020011SCédric Le Goater * 0x300 ... 0x33F: Device 8 120616020011SCédric Le Goater * 0x340 ... 0x37F: Device 9 120716020011SCédric Le Goater * 0x380 ... 0x3BF: Device 10 120816020011SCédric Le Goater * 0x3C0 ... 0x3FF: Device 11 120916020011SCédric Le Goater * 0x400 ... 0x43F: Device 12 121016020011SCédric Le Goater * 0x440 ... 0x47F: Device 13 121116020011SCédric Le Goater * 0x480 ... 0x4BF: Device 14 121216020011SCédric Le Goater * 0x800 ... 0xFFF: Buffer Pool (unused in linux driver) 121316020011SCédric Le Goater */ 121416020011SCédric Le Goater static void aspeed_i2c_realize(DeviceState *dev, Error **errp) 121516020011SCédric Le Goater { 121616020011SCédric Le Goater int i; 121716020011SCédric Le Goater SysBusDevice *sbd = SYS_BUS_DEVICE(dev); 121816020011SCédric Le Goater AspeedI2CState *s = ASPEED_I2C(dev); 1219f7da1aa8SCédric Le Goater AspeedI2CClass *aic = ASPEED_I2C_GET_CLASS(s); 122016020011SCédric Le Goater 122116020011SCédric Le Goater sysbus_init_irq(sbd, &s->irq); 122216020011SCédric Le Goater memory_region_init_io(&s->iomem, OBJECT(s), &aspeed_i2c_ctrl_ops, s, 122316020011SCédric Le Goater "aspeed.i2c", 0x1000); 122416020011SCédric Le Goater sysbus_init_mmio(sbd, &s->iomem); 122516020011SCédric Le Goater 1226f7da1aa8SCédric Le Goater for (i = 0; i < aic->num_busses; i++) { 122760261038SCédric Le Goater Object *bus = OBJECT(&s->busses[i]); 1228f7da1aa8SCédric Le Goater int offset = i < aic->gap ? 1 : 5; 122951dd4923SCédric Le Goater 123060261038SCédric Le Goater if (!object_property_set_link(bus, "controller", OBJECT(s), errp)) { 123160261038SCédric Le Goater return; 123260261038SCédric Le Goater } 123360261038SCédric Le Goater 123460261038SCédric Le Goater if (!object_property_set_uint(bus, "bus-id", i, errp)) { 123560261038SCédric Le Goater return; 123660261038SCédric Le Goater } 123760261038SCédric Le Goater 123860261038SCédric Le Goater if (!sysbus_realize(SYS_BUS_DEVICE(bus), errp)) { 123960261038SCédric Le Goater return; 124060261038SCédric Le Goater } 124160261038SCédric Le Goater 1242f7da1aa8SCédric Le Goater memory_region_add_subregion(&s->iomem, aic->reg_size * (i + offset), 124316020011SCédric Le Goater &s->busses[i].mr); 124416020011SCédric Le Goater } 12456054fc73SCédric Le Goater 12466054fc73SCédric Le Goater memory_region_init_io(&s->pool_iomem, OBJECT(s), &aspeed_i2c_pool_ops, s, 12476054fc73SCédric Le Goater "aspeed.i2c-pool", aic->pool_size); 12486054fc73SCédric Le Goater memory_region_add_subregion(&s->iomem, aic->pool_base, &s->pool_iomem); 1249545d6befSCédric Le Goater 1250545d6befSCédric Le Goater if (aic->has_dma) { 1251545d6befSCédric Le Goater if (!s->dram_mr) { 1252545d6befSCédric Le Goater error_setg(errp, TYPE_ASPEED_I2C ": 'dram' link not set"); 1253545d6befSCédric Le Goater return; 125416020011SCédric Le Goater } 125516020011SCédric Le Goater 12563f7a53b2SCédric Le Goater address_space_init(&s->dram_as, s->dram_mr, 12573f7a53b2SCédric Le Goater TYPE_ASPEED_I2C "-dma-dram"); 1258545d6befSCédric Le Goater } 1259545d6befSCédric Le Goater } 1260545d6befSCédric Le Goater 1261545d6befSCédric Le Goater static Property aspeed_i2c_properties[] = { 1262545d6befSCédric Le Goater DEFINE_PROP_LINK("dram", AspeedI2CState, dram_mr, 1263545d6befSCédric Le Goater TYPE_MEMORY_REGION, MemoryRegion *), 1264545d6befSCédric Le Goater DEFINE_PROP_END_OF_LIST(), 1265545d6befSCédric Le Goater }; 1266545d6befSCédric Le Goater 126716020011SCédric Le Goater static void aspeed_i2c_class_init(ObjectClass *klass, void *data) 126816020011SCédric Le Goater { 126916020011SCédric Le Goater DeviceClass *dc = DEVICE_CLASS(klass); 127016020011SCédric Le Goater 127116020011SCédric Le Goater dc->vmsd = &aspeed_i2c_vmstate; 127216020011SCédric Le Goater dc->reset = aspeed_i2c_reset; 12734f67d30bSMarc-André Lureau device_class_set_props(dc, aspeed_i2c_properties); 127416020011SCédric Le Goater dc->realize = aspeed_i2c_realize; 127516020011SCédric Le Goater dc->desc = "Aspeed I2C Controller"; 127616020011SCédric Le Goater } 127716020011SCédric Le Goater 127816020011SCédric Le Goater static const TypeInfo aspeed_i2c_info = { 127916020011SCédric Le Goater .name = TYPE_ASPEED_I2C, 128016020011SCédric Le Goater .parent = TYPE_SYS_BUS_DEVICE, 128160261038SCédric Le Goater .instance_init = aspeed_i2c_instance_init, 128216020011SCédric Le Goater .instance_size = sizeof(AspeedI2CState), 128316020011SCédric Le Goater .class_init = aspeed_i2c_class_init, 1284f7da1aa8SCédric Le Goater .class_size = sizeof(AspeedI2CClass), 1285f7da1aa8SCédric Le Goater .abstract = true, 1286f7da1aa8SCédric Le Goater }; 1287f7da1aa8SCédric Le Goater 128860261038SCédric Le Goater static void aspeed_i2c_bus_reset(DeviceState *dev) 128960261038SCédric Le Goater { 129060261038SCédric Le Goater AspeedI2CBus *s = ASPEED_I2C_BUS(dev); 129160261038SCédric Le Goater 12922260fc6fSJoe Komlodi memset(s->regs, 0, sizeof(s->regs)); 129360261038SCédric Le Goater i2c_end_transfer(s->bus); 129460261038SCédric Le Goater } 129560261038SCédric Le Goater 129660261038SCédric Le Goater static void aspeed_i2c_bus_realize(DeviceState *dev, Error **errp) 129760261038SCédric Le Goater { 129860261038SCédric Le Goater AspeedI2CBus *s = ASPEED_I2C_BUS(dev); 129960261038SCédric Le Goater AspeedI2CClass *aic; 130060261038SCédric Le Goater g_autofree char *name = g_strdup_printf(TYPE_ASPEED_I2C_BUS ".%d", s->id); 130160261038SCédric Le Goater 130260261038SCédric Le Goater if (!s->controller) { 130360261038SCédric Le Goater error_setg(errp, TYPE_ASPEED_I2C_BUS ": 'controller' link not set"); 130460261038SCédric Le Goater return; 130560261038SCédric Le Goater } 130660261038SCédric Le Goater 130760261038SCédric Le Goater aic = ASPEED_I2C_GET_CLASS(s->controller); 130860261038SCédric Le Goater 130960261038SCédric Le Goater sysbus_init_irq(SYS_BUS_DEVICE(dev), &s->irq); 131060261038SCédric Le Goater 131160261038SCédric Le Goater s->bus = i2c_init_bus(dev, name); 131260261038SCédric Le Goater 131360261038SCédric Le Goater memory_region_init_io(&s->mr, OBJECT(s), &aspeed_i2c_bus_ops, 131460261038SCédric Le Goater s, name, aic->reg_size); 131560261038SCédric Le Goater sysbus_init_mmio(SYS_BUS_DEVICE(dev), &s->mr); 131660261038SCédric Le Goater } 131760261038SCédric Le Goater 131860261038SCédric Le Goater static Property aspeed_i2c_bus_properties[] = { 131960261038SCédric Le Goater DEFINE_PROP_UINT8("bus-id", AspeedI2CBus, id, 0), 132060261038SCédric Le Goater DEFINE_PROP_LINK("controller", AspeedI2CBus, controller, TYPE_ASPEED_I2C, 132160261038SCédric Le Goater AspeedI2CState *), 132260261038SCédric Le Goater DEFINE_PROP_END_OF_LIST(), 132360261038SCédric Le Goater }; 132460261038SCédric Le Goater 132560261038SCédric Le Goater static void aspeed_i2c_bus_class_init(ObjectClass *klass, void *data) 132660261038SCédric Le Goater { 132760261038SCédric Le Goater DeviceClass *dc = DEVICE_CLASS(klass); 132860261038SCédric Le Goater 132960261038SCédric Le Goater dc->desc = "Aspeed I2C Bus"; 133060261038SCédric Le Goater dc->realize = aspeed_i2c_bus_realize; 133160261038SCédric Le Goater dc->reset = aspeed_i2c_bus_reset; 133260261038SCédric Le Goater device_class_set_props(dc, aspeed_i2c_bus_properties); 133360261038SCédric Le Goater } 133460261038SCédric Le Goater 133560261038SCédric Le Goater static const TypeInfo aspeed_i2c_bus_info = { 133660261038SCédric Le Goater .name = TYPE_ASPEED_I2C_BUS, 133760261038SCédric Le Goater .parent = TYPE_SYS_BUS_DEVICE, 133860261038SCédric Le Goater .instance_size = sizeof(AspeedI2CBus), 133960261038SCédric Le Goater .class_init = aspeed_i2c_bus_class_init, 134060261038SCédric Le Goater }; 134160261038SCédric Le Goater 134251dd4923SCédric Le Goater static qemu_irq aspeed_2400_i2c_bus_get_irq(AspeedI2CBus *bus) 134351dd4923SCédric Le Goater { 134451dd4923SCédric Le Goater return bus->controller->irq; 134551dd4923SCédric Le Goater } 134651dd4923SCédric Le Goater 13476054fc73SCédric Le Goater static uint8_t *aspeed_2400_i2c_bus_pool_base(AspeedI2CBus *bus) 13486054fc73SCédric Le Goater { 13496054fc73SCédric Le Goater uint8_t *pool_page = 13502260fc6fSJoe Komlodi &bus->controller->pool[ARRAY_FIELD_EX32(bus->regs, I2CD_FUN_CTRL, 13513be3d6ccSJoe Komlodi POOL_PAGE_SEL) * 0x100]; 13526054fc73SCédric Le Goater 13532260fc6fSJoe Komlodi return &pool_page[ARRAY_FIELD_EX32(bus->regs, I2CD_POOL_CTRL, OFFSET)]; 13546054fc73SCédric Le Goater } 13556054fc73SCédric Le Goater 1356f7da1aa8SCédric Le Goater static void aspeed_2400_i2c_class_init(ObjectClass *klass, void *data) 1357f7da1aa8SCédric Le Goater { 1358f7da1aa8SCédric Le Goater DeviceClass *dc = DEVICE_CLASS(klass); 1359f7da1aa8SCédric Le Goater AspeedI2CClass *aic = ASPEED_I2C_CLASS(klass); 1360f7da1aa8SCédric Le Goater 1361f7da1aa8SCédric Le Goater dc->desc = "ASPEED 2400 I2C Controller"; 1362f7da1aa8SCédric Le Goater 1363f7da1aa8SCédric Le Goater aic->num_busses = 14; 1364f7da1aa8SCédric Le Goater aic->reg_size = 0x40; 1365f7da1aa8SCédric Le Goater aic->gap = 7; 136651dd4923SCédric Le Goater aic->bus_get_irq = aspeed_2400_i2c_bus_get_irq; 13676054fc73SCédric Le Goater aic->pool_size = 0x800; 13686054fc73SCédric Le Goater aic->pool_base = 0x800; 13696054fc73SCédric Le Goater aic->bus_pool_base = aspeed_2400_i2c_bus_pool_base; 1370f7da1aa8SCédric Le Goater } 1371f7da1aa8SCédric Le Goater 1372f7da1aa8SCédric Le Goater static const TypeInfo aspeed_2400_i2c_info = { 1373f7da1aa8SCédric Le Goater .name = TYPE_ASPEED_2400_I2C, 1374f7da1aa8SCédric Le Goater .parent = TYPE_ASPEED_I2C, 1375f7da1aa8SCédric Le Goater .class_init = aspeed_2400_i2c_class_init, 1376f7da1aa8SCédric Le Goater }; 1377f7da1aa8SCédric Le Goater 137851dd4923SCédric Le Goater static qemu_irq aspeed_2500_i2c_bus_get_irq(AspeedI2CBus *bus) 137951dd4923SCédric Le Goater { 138051dd4923SCédric Le Goater return bus->controller->irq; 138151dd4923SCédric Le Goater } 138251dd4923SCédric Le Goater 13836054fc73SCédric Le Goater static uint8_t *aspeed_2500_i2c_bus_pool_base(AspeedI2CBus *bus) 13846054fc73SCédric Le Goater { 13856054fc73SCédric Le Goater return &bus->controller->pool[bus->id * 0x10]; 13866054fc73SCédric Le Goater } 13876054fc73SCédric Le Goater 1388f7da1aa8SCédric Le Goater static void aspeed_2500_i2c_class_init(ObjectClass *klass, void *data) 1389f7da1aa8SCédric Le Goater { 1390f7da1aa8SCédric Le Goater DeviceClass *dc = DEVICE_CLASS(klass); 1391f7da1aa8SCédric Le Goater AspeedI2CClass *aic = ASPEED_I2C_CLASS(klass); 1392f7da1aa8SCédric Le Goater 1393f7da1aa8SCédric Le Goater dc->desc = "ASPEED 2500 I2C Controller"; 1394f7da1aa8SCédric Le Goater 1395f7da1aa8SCédric Le Goater aic->num_busses = 14; 1396f7da1aa8SCédric Le Goater aic->reg_size = 0x40; 1397f7da1aa8SCédric Le Goater aic->gap = 7; 139851dd4923SCédric Le Goater aic->bus_get_irq = aspeed_2500_i2c_bus_get_irq; 13996054fc73SCédric Le Goater aic->pool_size = 0x100; 14006054fc73SCédric Le Goater aic->pool_base = 0x200; 14016054fc73SCédric Le Goater aic->bus_pool_base = aspeed_2500_i2c_bus_pool_base; 1402aab90b1cSCédric Le Goater aic->check_sram = true; 1403545d6befSCédric Le Goater aic->has_dma = true; 1404f7da1aa8SCédric Le Goater } 1405f7da1aa8SCédric Le Goater 1406f7da1aa8SCédric Le Goater static const TypeInfo aspeed_2500_i2c_info = { 1407f7da1aa8SCédric Le Goater .name = TYPE_ASPEED_2500_I2C, 1408f7da1aa8SCédric Le Goater .parent = TYPE_ASPEED_I2C, 1409f7da1aa8SCédric Le Goater .class_init = aspeed_2500_i2c_class_init, 141016020011SCédric Le Goater }; 141116020011SCédric Le Goater 141251dd4923SCédric Le Goater static qemu_irq aspeed_2600_i2c_bus_get_irq(AspeedI2CBus *bus) 141351dd4923SCédric Le Goater { 141451dd4923SCédric Le Goater return bus->irq; 141551dd4923SCédric Le Goater } 141651dd4923SCédric Le Goater 14176054fc73SCédric Le Goater static uint8_t *aspeed_2600_i2c_bus_pool_base(AspeedI2CBus *bus) 14186054fc73SCédric Le Goater { 14196054fc73SCédric Le Goater return &bus->controller->pool[bus->id * 0x20]; 14206054fc73SCédric Le Goater } 14216054fc73SCédric Le Goater 142251dd4923SCédric Le Goater static void aspeed_2600_i2c_class_init(ObjectClass *klass, void *data) 142351dd4923SCédric Le Goater { 142451dd4923SCédric Le Goater DeviceClass *dc = DEVICE_CLASS(klass); 142551dd4923SCédric Le Goater AspeedI2CClass *aic = ASPEED_I2C_CLASS(klass); 142651dd4923SCédric Le Goater 142751dd4923SCédric Le Goater dc->desc = "ASPEED 2600 I2C Controller"; 142851dd4923SCédric Le Goater 142951dd4923SCédric Le Goater aic->num_busses = 16; 143051dd4923SCédric Le Goater aic->reg_size = 0x80; 143151dd4923SCédric Le Goater aic->gap = -1; /* no gap */ 143251dd4923SCédric Le Goater aic->bus_get_irq = aspeed_2600_i2c_bus_get_irq; 14336054fc73SCédric Le Goater aic->pool_size = 0x200; 14346054fc73SCédric Le Goater aic->pool_base = 0xC00; 14356054fc73SCédric Le Goater aic->bus_pool_base = aspeed_2600_i2c_bus_pool_base; 1436545d6befSCédric Le Goater aic->has_dma = true; 143751dd4923SCédric Le Goater } 143851dd4923SCédric Le Goater 143951dd4923SCédric Le Goater static const TypeInfo aspeed_2600_i2c_info = { 144051dd4923SCédric Le Goater .name = TYPE_ASPEED_2600_I2C, 144151dd4923SCédric Le Goater .parent = TYPE_ASPEED_I2C, 144251dd4923SCédric Le Goater .class_init = aspeed_2600_i2c_class_init, 144351dd4923SCédric Le Goater }; 144451dd4923SCédric Le Goater 144516020011SCédric Le Goater static void aspeed_i2c_register_types(void) 144616020011SCédric Le Goater { 144760261038SCédric Le Goater type_register_static(&aspeed_i2c_bus_info); 144816020011SCédric Le Goater type_register_static(&aspeed_i2c_info); 1449f7da1aa8SCédric Le Goater type_register_static(&aspeed_2400_i2c_info); 1450f7da1aa8SCédric Le Goater type_register_static(&aspeed_2500_i2c_info); 145151dd4923SCédric Le Goater type_register_static(&aspeed_2600_i2c_info); 145216020011SCédric Le Goater } 145316020011SCédric Le Goater 145416020011SCédric Le Goater type_init(aspeed_i2c_register_types) 145516020011SCédric Le Goater 145616020011SCédric Le Goater 14577a204cbdSPhilippe Mathieu-Daudé I2CBus *aspeed_i2c_get_bus(AspeedI2CState *s, int busnr) 145816020011SCédric Le Goater { 1459f7da1aa8SCédric Le Goater AspeedI2CClass *aic = ASPEED_I2C_GET_CLASS(s); 146016020011SCédric Le Goater I2CBus *bus = NULL; 146116020011SCédric Le Goater 1462f7da1aa8SCédric Le Goater if (busnr >= 0 && busnr < aic->num_busses) { 146316020011SCédric Le Goater bus = s->busses[busnr].bus; 146416020011SCédric Le Goater } 146516020011SCédric Le Goater 146616020011SCédric Le Goater return bus; 146716020011SCédric Le Goater } 1468