17d87775fSJoe Komlodi /* 27d87775fSJoe Komlodi * ASPEED I3C Controller 37d87775fSJoe Komlodi * 47d87775fSJoe Komlodi * Copyright (C) 2021 ASPEED Technology Inc. 5e7b1406cSJoe Komlodi * Copyright (C) 2023 Google LLC 67d87775fSJoe Komlodi * 77d87775fSJoe Komlodi * This code is licensed under the GPL version 2 or later. See 87d87775fSJoe Komlodi * the COPYING file in the top-level directory. 97d87775fSJoe Komlodi */ 107d87775fSJoe Komlodi 117d87775fSJoe Komlodi #include "qemu/osdep.h" 127d87775fSJoe Komlodi #include "qemu/log.h" 137d87775fSJoe Komlodi #include "qemu/error-report.h" 147d87775fSJoe Komlodi #include "hw/i3c/aspeed_i3c.h" 157d87775fSJoe Komlodi #include "hw/registerfields.h" 167d87775fSJoe Komlodi #include "hw/qdev-properties.h" 177d87775fSJoe Komlodi #include "qapi/error.h" 187d87775fSJoe Komlodi #include "migration/vmstate.h" 197d87775fSJoe Komlodi #include "trace.h" 203816bedaSJoe Komlodi #include "hw/i3c/i3c.h" 213816bedaSJoe Komlodi #include "hw/irq.h" 227d87775fSJoe Komlodi 23*93ec6949SJoe Komlodi /* 24*93ec6949SJoe Komlodi * Disable event command values. sent along with a DISEC CCC to disable certain 25*93ec6949SJoe Komlodi * events on targets. 26*93ec6949SJoe Komlodi */ 27*93ec6949SJoe Komlodi #define DISEC_HJ 0x08 28*93ec6949SJoe Komlodi #define DISEC_CR 0x02 29*93ec6949SJoe Komlodi #define DISEC_INT 0x01 30*93ec6949SJoe Komlodi 317d87775fSJoe Komlodi /* I3C Controller Registers */ 327d87775fSJoe Komlodi REG32(I3C1_REG0, 0x10) 337d87775fSJoe Komlodi REG32(I3C1_REG1, 0x14) 347d87775fSJoe Komlodi FIELD(I3C1_REG1, I2C_MODE, 0, 1) 35e7b1406cSJoe Komlodi FIELD(I3C1_REG1, SLV_TEST_MODE, 1, 1) 36e7b1406cSJoe Komlodi FIELD(I3C1_REG1, ACT_MODE, 2, 2) 37e7b1406cSJoe Komlodi FIELD(I3C1_REG1, PENDING_INT, 4, 4) 38e7b1406cSJoe Komlodi FIELD(I3C1_REG1, SA, 8, 7) 397d87775fSJoe Komlodi FIELD(I3C1_REG1, SA_EN, 15, 1) 40e7b1406cSJoe Komlodi FIELD(I3C1_REG1, INST_ID, 16, 4) 417d87775fSJoe Komlodi REG32(I3C2_REG0, 0x20) 427d87775fSJoe Komlodi REG32(I3C2_REG1, 0x24) 437d87775fSJoe Komlodi FIELD(I3C2_REG1, I2C_MODE, 0, 1) 44e7b1406cSJoe Komlodi FIELD(I3C2_REG1, SLV_TEST_MODE, 1, 1) 45e7b1406cSJoe Komlodi FIELD(I3C2_REG1, ACT_MODE, 2, 2) 46e7b1406cSJoe Komlodi FIELD(I3C2_REG1, PENDING_INT, 4, 4) 47e7b1406cSJoe Komlodi FIELD(I3C2_REG1, SA, 8, 7) 487d87775fSJoe Komlodi FIELD(I3C2_REG1, SA_EN, 15, 1) 49e7b1406cSJoe Komlodi FIELD(I3C2_REG1, INST_ID, 16, 4) 507d87775fSJoe Komlodi REG32(I3C3_REG0, 0x30) 517d87775fSJoe Komlodi REG32(I3C3_REG1, 0x34) 527d87775fSJoe Komlodi FIELD(I3C3_REG1, I2C_MODE, 0, 1) 53e7b1406cSJoe Komlodi FIELD(I3C3_REG1, SLV_TEST_MODE, 1, 1) 54e7b1406cSJoe Komlodi FIELD(I3C3_REG1, ACT_MODE, 2, 2) 55e7b1406cSJoe Komlodi FIELD(I3C3_REG1, PENDING_INT, 4, 4) 56e7b1406cSJoe Komlodi FIELD(I3C3_REG1, SA, 8, 7) 577d87775fSJoe Komlodi FIELD(I3C3_REG1, SA_EN, 15, 1) 58e7b1406cSJoe Komlodi FIELD(I3C3_REG1, INST_ID, 16, 4) 597d87775fSJoe Komlodi REG32(I3C4_REG0, 0x40) 607d87775fSJoe Komlodi REG32(I3C4_REG1, 0x44) 617d87775fSJoe Komlodi FIELD(I3C4_REG1, I2C_MODE, 0, 1) 62e7b1406cSJoe Komlodi FIELD(I3C4_REG1, SLV_TEST_MODE, 1, 1) 63e7b1406cSJoe Komlodi FIELD(I3C4_REG1, ACT_MODE, 2, 2) 64e7b1406cSJoe Komlodi FIELD(I3C4_REG1, PENDING_INT, 4, 4) 65e7b1406cSJoe Komlodi FIELD(I3C4_REG1, SA, 8, 7) 667d87775fSJoe Komlodi FIELD(I3C4_REG1, SA_EN, 15, 1) 67e7b1406cSJoe Komlodi FIELD(I3C4_REG1, INST_ID, 16, 4) 687d87775fSJoe Komlodi REG32(I3C5_REG0, 0x50) 697d87775fSJoe Komlodi REG32(I3C5_REG1, 0x54) 707d87775fSJoe Komlodi FIELD(I3C5_REG1, I2C_MODE, 0, 1) 71e7b1406cSJoe Komlodi FIELD(I3C5_REG1, SLV_TEST_MODE, 1, 1) 72e7b1406cSJoe Komlodi FIELD(I3C5_REG1, ACT_MODE, 2, 2) 73e7b1406cSJoe Komlodi FIELD(I3C5_REG1, PENDING_INT, 4, 4) 74e7b1406cSJoe Komlodi FIELD(I3C5_REG1, SA, 8, 7) 757d87775fSJoe Komlodi FIELD(I3C5_REG1, SA_EN, 15, 1) 76e7b1406cSJoe Komlodi FIELD(I3C5_REG1, INST_ID, 16, 4) 777d87775fSJoe Komlodi REG32(I3C6_REG0, 0x60) 787d87775fSJoe Komlodi REG32(I3C6_REG1, 0x64) 797d87775fSJoe Komlodi FIELD(I3C6_REG1, I2C_MODE, 0, 1) 80e7b1406cSJoe Komlodi FIELD(I3C6_REG1, SLV_TEST_MODE, 1, 1) 81e7b1406cSJoe Komlodi FIELD(I3C6_REG1, ACT_MODE, 2, 2) 82e7b1406cSJoe Komlodi FIELD(I3C6_REG1, PENDING_INT, 4, 4) 83e7b1406cSJoe Komlodi FIELD(I3C6_REG1, SA, 8, 7) 847d87775fSJoe Komlodi FIELD(I3C6_REG1, SA_EN, 15, 1) 85e7b1406cSJoe Komlodi FIELD(I3C6_REG1, INST_ID, 16, 4) 867d87775fSJoe Komlodi 877d87775fSJoe Komlodi /* I3C Device Registers */ 887d87775fSJoe Komlodi REG32(DEVICE_CTRL, 0x00) 89e7b1406cSJoe Komlodi FIELD(DEVICE_CTRL, I3C_BROADCAST_ADDR_INC, 0, 1) 90e7b1406cSJoe Komlodi FIELD(DEVICE_CTRL, I2C_SLAVE_PRESENT, 7, 1) 91e7b1406cSJoe Komlodi FIELD(DEVICE_CTRL, HOT_JOIN_ACK_NACK_CTRL, 8, 1) 92e7b1406cSJoe Komlodi FIELD(DEVICE_CTRL, IDLE_CNT_MULTIPLIER, 24, 2) 93e7b1406cSJoe Komlodi FIELD(DEVICE_CTRL, SLV_ADAPT_TO_I2C_I3C_MODE, 27, 1) 94e7b1406cSJoe Komlodi FIELD(DEVICE_CTRL, DMA_HANDSHAKE_EN, 28, 1) 95e7b1406cSJoe Komlodi FIELD(DEVICE_CTRL, I3C_ABORT, 29, 1) 96e7b1406cSJoe Komlodi FIELD(DEVICE_CTRL, I3C_RESUME, 30, 1) 97e7b1406cSJoe Komlodi FIELD(DEVICE_CTRL, I3C_EN, 31, 1) 987d87775fSJoe Komlodi REG32(DEVICE_ADDR, 0x04) 99e7b1406cSJoe Komlodi FIELD(DEVICE_ADDR, STATIC_ADDR, 0, 7) 100e7b1406cSJoe Komlodi FIELD(DEVICE_ADDR, STATIC_ADDR_VALID, 15, 1) 101e7b1406cSJoe Komlodi FIELD(DEVICE_ADDR, DYNAMIC_ADDR, 16, 7) 102e7b1406cSJoe Komlodi FIELD(DEVICE_ADDR, DYNAMIC_ADDR_VALID, 15, 1) 1037d87775fSJoe Komlodi REG32(HW_CAPABILITY, 0x08) 104e7b1406cSJoe Komlodi FIELD(HW_CAPABILITY, ENTDAA, 0, 1) 105e7b1406cSJoe Komlodi FIELD(HW_CAPABILITY, HDR_DDR, 3, 1) 106e7b1406cSJoe Komlodi FIELD(HW_CAPABILITY, HDR_TS, 4, 1) 1077d87775fSJoe Komlodi REG32(COMMAND_QUEUE_PORT, 0x0c) 108e7b1406cSJoe Komlodi FIELD(COMMAND_QUEUE_PORT, CMD_ATTR, 0, 3) 109e7b1406cSJoe Komlodi /* Transfer command structure */ 110e7b1406cSJoe Komlodi FIELD(COMMAND_QUEUE_PORT, TID, 3, 4) 111e7b1406cSJoe Komlodi FIELD(COMMAND_QUEUE_PORT, CMD, 7, 8) 112e7b1406cSJoe Komlodi FIELD(COMMAND_QUEUE_PORT, CP, 15, 1) 113e7b1406cSJoe Komlodi FIELD(COMMAND_QUEUE_PORT, DEV_INDEX, 16, 5) 114e7b1406cSJoe Komlodi FIELD(COMMAND_QUEUE_PORT, SPEED, 21, 3) 115e7b1406cSJoe Komlodi FIELD(COMMAND_QUEUE_PORT, ROC, 26, 1) 116e7b1406cSJoe Komlodi FIELD(COMMAND_QUEUE_PORT, SDAP, 27, 1) 117e7b1406cSJoe Komlodi FIELD(COMMAND_QUEUE_PORT, RNW, 28, 1) 118e7b1406cSJoe Komlodi FIELD(COMMAND_QUEUE_PORT, TOC, 30, 1) 119e7b1406cSJoe Komlodi FIELD(COMMAND_QUEUE_PORT, PEC, 31, 1) 120e7b1406cSJoe Komlodi /* Transfer argument data structure */ 121e7b1406cSJoe Komlodi FIELD(COMMAND_QUEUE_PORT, DB, 8, 8) 122e7b1406cSJoe Komlodi FIELD(COMMAND_QUEUE_PORT, DL, 16, 16) 123e7b1406cSJoe Komlodi /* Short data argument data structure */ 124e7b1406cSJoe Komlodi FIELD(COMMAND_QUEUE_PORT, BYTE_STRB, 3, 3) 125e7b1406cSJoe Komlodi FIELD(COMMAND_QUEUE_PORT, BYTE0, 8, 8) 126e7b1406cSJoe Komlodi FIELD(COMMAND_QUEUE_PORT, BYTE1, 16, 8) 127e7b1406cSJoe Komlodi FIELD(COMMAND_QUEUE_PORT, BYTE2, 24, 8) 128e7b1406cSJoe Komlodi /* Address assignment command structure */ 129e7b1406cSJoe Komlodi /* 130e7b1406cSJoe Komlodi * bits 3..21 and 26..31 are the same as the transfer command structure, or 131e7b1406cSJoe Komlodi * marked as reserved. 132e7b1406cSJoe Komlodi */ 133e7b1406cSJoe Komlodi FIELD(COMMAND_QUEUE_PORT, DEV_COUNT, 21, 3) 1347d87775fSJoe Komlodi REG32(RESPONSE_QUEUE_PORT, 0x10) 135e7b1406cSJoe Komlodi FIELD(RESPONSE_QUEUE_PORT, DL, 0, 16) 136e7b1406cSJoe Komlodi FIELD(RESPONSE_QUEUE_PORT, CCCT, 16, 8) 137e7b1406cSJoe Komlodi FIELD(RESPONSE_QUEUE_PORT, TID, 24, 4) 138e7b1406cSJoe Komlodi FIELD(RESPONSE_QUEUE_PORT, ERR_STATUS, 28, 4) 1397d87775fSJoe Komlodi REG32(RX_TX_DATA_PORT, 0x14) 1407d87775fSJoe Komlodi REG32(IBI_QUEUE_STATUS, 0x18) 141e7b1406cSJoe Komlodi FIELD(IBI_QUEUE_STATUS, IBI_DATA_LEN, 0, 8) 142e7b1406cSJoe Komlodi FIELD(IBI_QUEUE_STATUS, IBI_ID, 8, 8) 143e7b1406cSJoe Komlodi FIELD(IBI_QUEUE_STATUS, LAST_STATUS, 24, 1) 144e7b1406cSJoe Komlodi FIELD(IBI_QUEUE_STATUS, ERROR, 30, 1) 145e7b1406cSJoe Komlodi FIELD(IBI_QUEUE_STATUS, IBI_STATUS, 31, 1) 1467d87775fSJoe Komlodi REG32(IBI_QUEUE_DATA, 0x18) 1477d87775fSJoe Komlodi REG32(QUEUE_THLD_CTRL, 0x1c) 148e7b1406cSJoe Komlodi FIELD(QUEUE_THLD_CTRL, CMD_BUF_EMPTY_THLD, 0, 8); 149e7b1406cSJoe Komlodi FIELD(QUEUE_THLD_CTRL, RESP_BUF_THLD, 8, 8); 150e7b1406cSJoe Komlodi FIELD(QUEUE_THLD_CTRL, IBI_DATA_THLD, 16, 8); 151e7b1406cSJoe Komlodi FIELD(QUEUE_THLD_CTRL, IBI_STATUS_THLD, 24, 8); 1527d87775fSJoe Komlodi REG32(DATA_BUFFER_THLD_CTRL, 0x20) 153e7b1406cSJoe Komlodi FIELD(DATA_BUFFER_THLD_CTRL, TX_BUF_THLD, 0, 3) 154e7b1406cSJoe Komlodi FIELD(DATA_BUFFER_THLD_CTRL, RX_BUF_THLD, 10, 3) 155e7b1406cSJoe Komlodi FIELD(DATA_BUFFER_THLD_CTRL, TX_START_THLD, 16, 3) 156e7b1406cSJoe Komlodi FIELD(DATA_BUFFER_THLD_CTRL, RX_START_THLD, 24, 3) 1577d87775fSJoe Komlodi REG32(IBI_QUEUE_CTRL, 0x24) 158e7b1406cSJoe Komlodi FIELD(IBI_QUEUE_CTRL, NOTIFY_REJECTED_HOT_JOIN, 0, 1) 159e7b1406cSJoe Komlodi FIELD(IBI_QUEUE_CTRL, NOTIFY_REJECTED_MASTER_REQ, 1, 1) 160e7b1406cSJoe Komlodi FIELD(IBI_QUEUE_CTRL, NOTIFY_REJECTED_SLAVE_IRQ, 3, 1) 1617d87775fSJoe Komlodi REG32(IBI_MR_REQ_REJECT, 0x2c) 1627d87775fSJoe Komlodi REG32(IBI_SIR_REQ_REJECT, 0x30) 1637d87775fSJoe Komlodi REG32(RESET_CTRL, 0x34) 164e7b1406cSJoe Komlodi FIELD(RESET_CTRL, CORE_RESET, 0, 1) 165e7b1406cSJoe Komlodi FIELD(RESET_CTRL, CMD_QUEUE_RESET, 1, 1) 166e7b1406cSJoe Komlodi FIELD(RESET_CTRL, RESP_QUEUE_RESET, 2, 1) 167e7b1406cSJoe Komlodi FIELD(RESET_CTRL, TX_BUF_RESET, 3, 1) 168e7b1406cSJoe Komlodi FIELD(RESET_CTRL, RX_BUF_RESET, 4, 1) 169e7b1406cSJoe Komlodi FIELD(RESET_CTRL, IBI_QUEUE_RESET, 5, 1) 1707d87775fSJoe Komlodi REG32(SLV_EVENT_CTRL, 0x38) 171e7b1406cSJoe Komlodi FIELD(SLV_EVENT_CTRL, SLV_INTERRUPT, 0, 1) 172e7b1406cSJoe Komlodi FIELD(SLV_EVENT_CTRL, MASTER_INTERRUPT, 1, 1) 173e7b1406cSJoe Komlodi FIELD(SLV_EVENT_CTRL, HOT_JOIN_INTERRUPT, 3, 1) 174e7b1406cSJoe Komlodi FIELD(SLV_EVENT_CTRL, ACTIVITY_STATE, 4, 2) 175e7b1406cSJoe Komlodi FIELD(SLV_EVENT_CTRL, MRL_UPDATED, 6, 1) 176e7b1406cSJoe Komlodi FIELD(SLV_EVENT_CTRL, MWL_UPDATED, 7, 1) 1777d87775fSJoe Komlodi REG32(INTR_STATUS, 0x3c) 178e7b1406cSJoe Komlodi FIELD(INTR_STATUS, TX_THLD, 0, 1) 179e7b1406cSJoe Komlodi FIELD(INTR_STATUS, RX_THLD, 1, 1) 180e7b1406cSJoe Komlodi FIELD(INTR_STATUS, IBI_THLD, 2, 1) 181e7b1406cSJoe Komlodi FIELD(INTR_STATUS, CMD_QUEUE_RDY, 3, 1) 182e7b1406cSJoe Komlodi FIELD(INTR_STATUS, RESP_RDY, 4, 1) 183e7b1406cSJoe Komlodi FIELD(INTR_STATUS, TRANSFER_ABORT, 5, 1) 184e7b1406cSJoe Komlodi FIELD(INTR_STATUS, CCC_UPDATED, 6, 1) 185e7b1406cSJoe Komlodi FIELD(INTR_STATUS, DYN_ADDR_ASSGN, 8, 1) 186e7b1406cSJoe Komlodi FIELD(INTR_STATUS, TRANSFER_ERR, 9, 1) 187e7b1406cSJoe Komlodi FIELD(INTR_STATUS, DEFSLV, 10, 1) 188e7b1406cSJoe Komlodi FIELD(INTR_STATUS, READ_REQ_RECV, 11, 1) 189e7b1406cSJoe Komlodi FIELD(INTR_STATUS, IBI_UPDATED, 12, 1) 190e7b1406cSJoe Komlodi FIELD(INTR_STATUS, BUSOWNER_UPDATED, 13, 1) 1917d87775fSJoe Komlodi REG32(INTR_STATUS_EN, 0x40) 192e7b1406cSJoe Komlodi FIELD(INTR_STATUS_EN, TX_THLD, 0, 1) 193e7b1406cSJoe Komlodi FIELD(INTR_STATUS_EN, RX_THLD, 1, 1) 194e7b1406cSJoe Komlodi FIELD(INTR_STATUS_EN, IBI_THLD, 2, 1) 195e7b1406cSJoe Komlodi FIELD(INTR_STATUS_EN, CMD_QUEUE_RDY, 3, 1) 196e7b1406cSJoe Komlodi FIELD(INTR_STATUS_EN, RESP_RDY, 4, 1) 197e7b1406cSJoe Komlodi FIELD(INTR_STATUS_EN, TRANSFER_ABORT, 5, 1) 198e7b1406cSJoe Komlodi FIELD(INTR_STATUS_EN, CCC_UPDATED, 6, 1) 199e7b1406cSJoe Komlodi FIELD(INTR_STATUS_EN, DYN_ADDR_ASSGN, 8, 1) 200e7b1406cSJoe Komlodi FIELD(INTR_STATUS_EN, TRANSFER_ERR, 9, 1) 201e7b1406cSJoe Komlodi FIELD(INTR_STATUS_EN, DEFSLV, 10, 1) 202e7b1406cSJoe Komlodi FIELD(INTR_STATUS_EN, READ_REQ_RECV, 11, 1) 203e7b1406cSJoe Komlodi FIELD(INTR_STATUS_EN, IBI_UPDATED, 12, 1) 204e7b1406cSJoe Komlodi FIELD(INTR_STATUS_EN, BUSOWNER_UPDATED, 13, 1) 2057d87775fSJoe Komlodi REG32(INTR_SIGNAL_EN, 0x44) 206e7b1406cSJoe Komlodi FIELD(INTR_SIGNAL_EN, TX_THLD, 0, 1) 207e7b1406cSJoe Komlodi FIELD(INTR_SIGNAL_EN, RX_THLD, 1, 1) 208e7b1406cSJoe Komlodi FIELD(INTR_SIGNAL_EN, IBI_THLD, 2, 1) 209e7b1406cSJoe Komlodi FIELD(INTR_SIGNAL_EN, CMD_QUEUE_RDY, 3, 1) 210e7b1406cSJoe Komlodi FIELD(INTR_SIGNAL_EN, RESP_RDY, 4, 1) 211e7b1406cSJoe Komlodi FIELD(INTR_SIGNAL_EN, TRANSFER_ABORT, 5, 1) 212e7b1406cSJoe Komlodi FIELD(INTR_SIGNAL_EN, CCC_UPDATED, 6, 1) 213e7b1406cSJoe Komlodi FIELD(INTR_SIGNAL_EN, DYN_ADDR_ASSGN, 8, 1) 214e7b1406cSJoe Komlodi FIELD(INTR_SIGNAL_EN, TRANSFER_ERR, 9, 1) 215e7b1406cSJoe Komlodi FIELD(INTR_SIGNAL_EN, DEFSLV, 10, 1) 216e7b1406cSJoe Komlodi FIELD(INTR_SIGNAL_EN, READ_REQ_RECV, 11, 1) 217e7b1406cSJoe Komlodi FIELD(INTR_SIGNAL_EN, IBI_UPDATED, 12, 1) 218e7b1406cSJoe Komlodi FIELD(INTR_SIGNAL_EN, BUSOWNER_UPDATED, 13, 1) 2197d87775fSJoe Komlodi REG32(INTR_FORCE, 0x48) 220e7b1406cSJoe Komlodi FIELD(INTR_FORCE, TX_THLD, 0, 1) 221e7b1406cSJoe Komlodi FIELD(INTR_FORCE, RX_THLD, 1, 1) 222e7b1406cSJoe Komlodi FIELD(INTR_FORCE, IBI_THLD, 2, 1) 223e7b1406cSJoe Komlodi FIELD(INTR_FORCE, CMD_QUEUE_RDY, 3, 1) 224e7b1406cSJoe Komlodi FIELD(INTR_FORCE, RESP_RDY, 4, 1) 225e7b1406cSJoe Komlodi FIELD(INTR_FORCE, TRANSFER_ABORT, 5, 1) 226e7b1406cSJoe Komlodi FIELD(INTR_FORCE, CCC_UPDATED, 6, 1) 227e7b1406cSJoe Komlodi FIELD(INTR_FORCE, DYN_ADDR_ASSGN, 8, 1) 228e7b1406cSJoe Komlodi FIELD(INTR_FORCE, TRANSFER_ERR, 9, 1) 229e7b1406cSJoe Komlodi FIELD(INTR_FORCE, DEFSLV, 10, 1) 230e7b1406cSJoe Komlodi FIELD(INTR_FORCE, READ_REQ_RECV, 11, 1) 231e7b1406cSJoe Komlodi FIELD(INTR_FORCE, IBI_UPDATED, 12, 1) 232e7b1406cSJoe Komlodi FIELD(INTR_FORCE, BUSOWNER_UPDATED, 13, 1) 2337d87775fSJoe Komlodi REG32(QUEUE_STATUS_LEVEL, 0x4c) 234e7b1406cSJoe Komlodi FIELD(QUEUE_STATUS_LEVEL, CMD_QUEUE_EMPTY_LOC, 0, 8) 235e7b1406cSJoe Komlodi FIELD(QUEUE_STATUS_LEVEL, RESP_BUF_BLR, 8, 8) 236e7b1406cSJoe Komlodi FIELD(QUEUE_STATUS_LEVEL, IBI_BUF_BLR, 16, 8) 237e7b1406cSJoe Komlodi FIELD(QUEUE_STATUS_LEVEL, IBI_STATUS_CNT, 24, 5) 2387d87775fSJoe Komlodi REG32(DATA_BUFFER_STATUS_LEVEL, 0x50) 239e7b1406cSJoe Komlodi FIELD(DATA_BUFFER_STATUS_LEVEL, TX_BUF_EMPTY_LOC, 0, 8) 240e7b1406cSJoe Komlodi FIELD(DATA_BUFFER_STATUS_LEVEL, RX_BUF_BLR, 16, 8) 2417d87775fSJoe Komlodi REG32(PRESENT_STATE, 0x54) 242e7b1406cSJoe Komlodi FIELD(PRESENT_STATE, SCL_LINE_SIGNAL_LEVEL, 0, 1) 243e7b1406cSJoe Komlodi FIELD(PRESENT_STATE, SDA_LINE_SIGNAL_LEVEL, 1, 1) 244e7b1406cSJoe Komlodi FIELD(PRESENT_STATE, CURRENT_MASTER, 2, 1) 245e7b1406cSJoe Komlodi FIELD(PRESENT_STATE, CM_TFR_STATUS, 8, 6) 246e7b1406cSJoe Komlodi FIELD(PRESENT_STATE, CM_TFR_ST_STATUS, 16, 6) 247e7b1406cSJoe Komlodi FIELD(PRESENT_STATE, CMD_TID, 24, 4) 2487d87775fSJoe Komlodi REG32(CCC_DEVICE_STATUS, 0x58) 249e7b1406cSJoe Komlodi FIELD(CCC_DEVICE_STATUS, PENDING_INTR, 0, 4) 250e7b1406cSJoe Komlodi FIELD(CCC_DEVICE_STATUS, PROTOCOL_ERR, 4, 2) 251e7b1406cSJoe Komlodi FIELD(CCC_DEVICE_STATUS, ACTIVITY_MODE, 6, 2) 252e7b1406cSJoe Komlodi FIELD(CCC_DEVICE_STATUS, UNDER_ERR, 8, 1) 253e7b1406cSJoe Komlodi FIELD(CCC_DEVICE_STATUS, SLV_BUSY, 9, 1) 254e7b1406cSJoe Komlodi FIELD(CCC_DEVICE_STATUS, OVERFLOW_ERR, 10, 1) 255e7b1406cSJoe Komlodi FIELD(CCC_DEVICE_STATUS, DATA_NOT_READY, 11, 1) 256e7b1406cSJoe Komlodi FIELD(CCC_DEVICE_STATUS, BUFFER_NOT_AVAIL, 12, 1) 2577d87775fSJoe Komlodi REG32(DEVICE_ADDR_TABLE_POINTER, 0x5c) 2587d87775fSJoe Komlodi FIELD(DEVICE_ADDR_TABLE_POINTER, DEPTH, 16, 16) 2597d87775fSJoe Komlodi FIELD(DEVICE_ADDR_TABLE_POINTER, ADDR, 0, 16) 2607d87775fSJoe Komlodi REG32(DEV_CHAR_TABLE_POINTER, 0x60) 261e7b1406cSJoe Komlodi FIELD(DEV_CHAR_TABLE_POINTER, P_DEV_CHAR_TABLE_START_ADDR, 0, 12) 262e7b1406cSJoe Komlodi FIELD(DEV_CHAR_TABLE_POINTER, DEV_CHAR_TABLE_DEPTH, 12, 7) 263e7b1406cSJoe Komlodi FIELD(DEV_CHAR_TABLE_POINTER, PRESENT_DEV_CHAR_TABLE_INDEX, 19, 3) 2647d87775fSJoe Komlodi REG32(VENDOR_SPECIFIC_REG_POINTER, 0x6c) 265e7b1406cSJoe Komlodi FIELD(VENDOR_SPECIFIC_REG_POINTER, P_VENDOR_REG_START_ADDR, 0, 16) 2667d87775fSJoe Komlodi REG32(SLV_MIPI_PID_VALUE, 0x70) 2677d87775fSJoe Komlodi REG32(SLV_PID_VALUE, 0x74) 268e7b1406cSJoe Komlodi FIELD(SLV_PID_VALUE, SLV_PID_DCR, 0, 12) 269e7b1406cSJoe Komlodi FIELD(SLV_PID_VALUE, SLV_INST_ID, 12, 4) 270e7b1406cSJoe Komlodi FIELD(SLV_PID_VALUE, SLV_PART_ID, 16, 16) 2717d87775fSJoe Komlodi REG32(SLV_CHAR_CTRL, 0x78) 272e7b1406cSJoe Komlodi FIELD(SLV_CHAR_CTRL, BCR, 0, 8) 273e7b1406cSJoe Komlodi FIELD(SLV_CHAR_CTRL, DCR, 8, 8) 274e7b1406cSJoe Komlodi FIELD(SLV_CHAR_CTRL, HDR_CAP, 16, 8) 2757d87775fSJoe Komlodi REG32(SLV_MAX_LEN, 0x7c) 276e7b1406cSJoe Komlodi FIELD(SLV_MAX_LEN, MWL, 0, 16) 277e7b1406cSJoe Komlodi FIELD(SLV_MAX_LEN, MRL, 16, 16) 2787d87775fSJoe Komlodi REG32(MAX_READ_TURNAROUND, 0x80) 2797d87775fSJoe Komlodi REG32(MAX_DATA_SPEED, 0x84) 2807d87775fSJoe Komlodi REG32(SLV_DEBUG_STATUS, 0x88) 2817d87775fSJoe Komlodi REG32(SLV_INTR_REQ, 0x8c) 282e7b1406cSJoe Komlodi FIELD(SLV_INTR_REQ, SIR, 0, 1) 283e7b1406cSJoe Komlodi FIELD(SLV_INTR_REQ, SIR_CTRL, 1, 2) 284e7b1406cSJoe Komlodi FIELD(SLV_INTR_REQ, MIR, 3, 1) 285e7b1406cSJoe Komlodi FIELD(SLV_INTR_REQ, IBI_STS, 8, 2) 286e7b1406cSJoe Komlodi REG32(SLV_TSX_SYMBL_TIMING, 0x90) 287e7b1406cSJoe Komlodi FIELD(SLV_TSX_SYMBL_TIMING, SLV_TSX_SYMBL_CNT, 0, 6) 2887d87775fSJoe Komlodi REG32(DEVICE_CTRL_EXTENDED, 0xb0) 289e7b1406cSJoe Komlodi FIELD(DEVICE_CTRL_EXTENDED, MODE, 0, 2) 290e7b1406cSJoe Komlodi FIELD(DEVICE_CTRL_EXTENDED, REQMST_ACK_CTRL, 3, 1) 2917d87775fSJoe Komlodi REG32(SCL_I3C_OD_TIMING, 0xb4) 292e7b1406cSJoe Komlodi FIELD(SCL_I3C_OD_TIMING, I3C_OD_LCNT, 0, 8) 293e7b1406cSJoe Komlodi FIELD(SCL_I3C_OD_TIMING, I3C_OD_HCNT, 16, 8) 2947d87775fSJoe Komlodi REG32(SCL_I3C_PP_TIMING, 0xb8) 295e7b1406cSJoe Komlodi FIELD(SCL_I3C_PP_TIMING, I3C_PP_LCNT, 0, 8) 296e7b1406cSJoe Komlodi FIELD(SCL_I3C_PP_TIMING, I3C_PP_HCNT, 16, 8) 2977d87775fSJoe Komlodi REG32(SCL_I2C_FM_TIMING, 0xbc) 2987d87775fSJoe Komlodi REG32(SCL_I2C_FMP_TIMING, 0xc0) 299e7b1406cSJoe Komlodi FIELD(SCL_I2C_FMP_TIMING, I2C_FMP_LCNT, 0, 16) 300e7b1406cSJoe Komlodi FIELD(SCL_I2C_FMP_TIMING, I2C_FMP_HCNT, 16, 8) 3017d87775fSJoe Komlodi REG32(SCL_EXT_LCNT_TIMING, 0xc8) 3027d87775fSJoe Komlodi REG32(SCL_EXT_TERMN_LCNT_TIMING, 0xcc) 3037d87775fSJoe Komlodi REG32(BUS_FREE_TIMING, 0xd4) 3047d87775fSJoe Komlodi REG32(BUS_IDLE_TIMING, 0xd8) 305e7b1406cSJoe Komlodi FIELD(BUS_IDLE_TIMING, BUS_IDLE_TIME, 0, 20) 3067d87775fSJoe Komlodi REG32(I3C_VER_ID, 0xe0) 3077d87775fSJoe Komlodi REG32(I3C_VER_TYPE, 0xe4) 3087d87775fSJoe Komlodi REG32(EXTENDED_CAPABILITY, 0xe8) 309e7b1406cSJoe Komlodi FIELD(EXTENDED_CAPABILITY, APP_IF_MODE, 0, 2) 310e7b1406cSJoe Komlodi FIELD(EXTENDED_CAPABILITY, APP_IF_DATA_WIDTH, 2, 2) 311e7b1406cSJoe Komlodi FIELD(EXTENDED_CAPABILITY, OPERATION_MODE, 4, 2) 312e7b1406cSJoe Komlodi FIELD(EXTENDED_CAPABILITY, CLK_PERIOD, 8, 6) 3137d87775fSJoe Komlodi REG32(SLAVE_CONFIG, 0xec) 314e7b1406cSJoe Komlodi FIELD(SLAVE_CONFIG, DMA_EN, 0, 1) 315e7b1406cSJoe Komlodi FIELD(SLAVE_CONFIG, HJ_CAP, 0, 1) 316e7b1406cSJoe Komlodi FIELD(SLAVE_CONFIG, CLK_PERIOD, 2, 14) 317e7b1406cSJoe Komlodi /* Device characteristic table fields */ 318e7b1406cSJoe Komlodi REG32(DEVICE_CHARACTERISTIC_TABLE_LOC1, 0x200) 319e7b1406cSJoe Komlodi REG32(DEVICE_CHARACTERISTIC_TABLE_LOC_SECONDARY, 0x200) 320e7b1406cSJoe Komlodi FIELD(DEVICE_CHARACTERISTIC_TABLE_LOC_SECONDARY, DYNAMIC_ADDR, 0, 8) 321e7b1406cSJoe Komlodi FIELD(DEVICE_CHARACTERISTIC_TABLE_LOC_SECONDARY, DCR, 8, 8) 322e7b1406cSJoe Komlodi FIELD(DEVICE_CHARACTERISTIC_TABLE_LOC_SECONDARY, BCR, 16, 8) 323e7b1406cSJoe Komlodi FIELD(DEVICE_CHARACTERISTIC_TABLE_LOC_SECONDARY, STATIC_ADDR, 24, 8) 324e7b1406cSJoe Komlodi REG32(DEVICE_CHARACTERISTIC_TABLE_LOC2, 0x204) 325e7b1406cSJoe Komlodi FIELD(DEVICE_CHARACTERISTIC_TABLE_LOC2, MSB_PID, 0, 16) 326e7b1406cSJoe Komlodi REG32(DEVICE_CHARACTERISTIC_TABLE_LOC3, 0x208) 327e7b1406cSJoe Komlodi FIELD(DEVICE_CHARACTERISTIC_TABLE_LOC3, DCR, 0, 8) 328e7b1406cSJoe Komlodi FIELD(DEVICE_CHARACTERISTIC_TABLE_LOC3, BCR, 8, 8) 329e7b1406cSJoe Komlodi REG32(DEVICE_CHARACTERISTIC_TABLE_LOC4, 0x20c) 330e7b1406cSJoe Komlodi FIELD(DEVICE_CHARACTERISTIC_TABLE_LOC4, DEV_DYNAMIC_ADDR, 0, 8) 331e7b1406cSJoe Komlodi /* Dev addr table fields */ 332e7b1406cSJoe Komlodi REG32(DEVICE_ADDR_TABLE_LOC1, 0x280) 333e7b1406cSJoe Komlodi FIELD(DEVICE_ADDR_TABLE_LOC1, DEV_STATIC_ADDR, 0, 7) 334e7b1406cSJoe Komlodi FIELD(DEVICE_ADDR_TABLE_LOC1, IBI_PEC_EN, 11, 1) 335e7b1406cSJoe Komlodi FIELD(DEVICE_ADDR_TABLE_LOC1, IBI_WITH_DATA, 12, 1) 336e7b1406cSJoe Komlodi FIELD(DEVICE_ADDR_TABLE_LOC1, SIR_REJECT, 13, 1) 337e7b1406cSJoe Komlodi FIELD(DEVICE_ADDR_TABLE_LOC1, MR_REJECT, 14, 1) 338e7b1406cSJoe Komlodi FIELD(DEVICE_ADDR_TABLE_LOC1, DEV_DYNAMIC_ADDR, 16, 8) 339e7b1406cSJoe Komlodi FIELD(DEVICE_ADDR_TABLE_LOC1, IBI_ADDR_MASK, 24, 2) 340e7b1406cSJoe Komlodi FIELD(DEVICE_ADDR_TABLE_LOC1, DEV_NACK_RETRY_CNT, 29, 2) 341e7b1406cSJoe Komlodi FIELD(DEVICE_ADDR_TABLE_LOC1, LEGACY_I2C_DEVICE, 31, 1) 3427d87775fSJoe Komlodi 343a9d3f922SJoe Komlodi static const uint32_t ast2600_i3c_controller_ro[ASPEED_I3C_DEVICE_NR_REGS] = { 344a9d3f922SJoe Komlodi [R_I3C1_REG0] = 0xfc000000, 345a9d3f922SJoe Komlodi [R_I3C1_REG1] = 0xfff00000, 346a9d3f922SJoe Komlodi [R_I3C2_REG0] = 0xfc000000, 347a9d3f922SJoe Komlodi [R_I3C2_REG1] = 0xfff00000, 348a9d3f922SJoe Komlodi [R_I3C3_REG0] = 0xfc000000, 349a9d3f922SJoe Komlodi [R_I3C3_REG1] = 0xfff00000, 350a9d3f922SJoe Komlodi [R_I3C4_REG0] = 0xfc000000, 351a9d3f922SJoe Komlodi [R_I3C4_REG1] = 0xfff00000, 352a9d3f922SJoe Komlodi [R_I3C5_REG0] = 0xfc000000, 353a9d3f922SJoe Komlodi [R_I3C5_REG1] = 0xfff00000, 354a9d3f922SJoe Komlodi [R_I3C6_REG0] = 0xfc000000, 355a9d3f922SJoe Komlodi [R_I3C6_REG1] = 0xfff00000, 356a9d3f922SJoe Komlodi }; 357a9d3f922SJoe Komlodi 3587d87775fSJoe Komlodi static const uint32_t ast2600_i3c_device_resets[ASPEED_I3C_DEVICE_NR_REGS] = { 3597d87775fSJoe Komlodi [R_HW_CAPABILITY] = 0x000e00bf, 3607d87775fSJoe Komlodi [R_QUEUE_THLD_CTRL] = 0x01000101, 3611032d6d6SJoe Komlodi [R_DATA_BUFFER_THLD_CTRL] = 0x01010100, 3621032d6d6SJoe Komlodi [R_SLV_EVENT_CTRL] = 0x0000000b, 3631032d6d6SJoe Komlodi [R_QUEUE_STATUS_LEVEL] = 0x00000002, 3641032d6d6SJoe Komlodi [R_DATA_BUFFER_STATUS_LEVEL] = 0x00000010, 3651032d6d6SJoe Komlodi [R_PRESENT_STATE] = 0x00000003, 3667d87775fSJoe Komlodi [R_I3C_VER_ID] = 0x3130302a, 3677d87775fSJoe Komlodi [R_I3C_VER_TYPE] = 0x6c633033, 3687d87775fSJoe Komlodi [R_DEVICE_ADDR_TABLE_POINTER] = 0x00080280, 3697d87775fSJoe Komlodi [R_DEV_CHAR_TABLE_POINTER] = 0x00020200, 3701032d6d6SJoe Komlodi [R_SLV_CHAR_CTRL] = 0x00010000, 3717d87775fSJoe Komlodi [A_VENDOR_SPECIFIC_REG_POINTER] = 0x000000b0, 3727d87775fSJoe Komlodi [R_SLV_MAX_LEN] = 0x00ff00ff, 3731032d6d6SJoe Komlodi [R_SLV_TSX_SYMBL_TIMING] = 0x0000003f, 3741032d6d6SJoe Komlodi [R_SCL_I3C_OD_TIMING] = 0x000a0010, 3751032d6d6SJoe Komlodi [R_SCL_I3C_PP_TIMING] = 0x000a000a, 3761032d6d6SJoe Komlodi [R_SCL_I2C_FM_TIMING] = 0x00100010, 3771032d6d6SJoe Komlodi [R_SCL_I2C_FMP_TIMING] = 0x00100010, 3781032d6d6SJoe Komlodi [R_SCL_EXT_LCNT_TIMING] = 0x20202020, 3791032d6d6SJoe Komlodi [R_SCL_EXT_TERMN_LCNT_TIMING] = 0x00300000, 3801032d6d6SJoe Komlodi [R_BUS_FREE_TIMING] = 0x00200020, 3811032d6d6SJoe Komlodi [R_BUS_IDLE_TIMING] = 0x00000020, 3821032d6d6SJoe Komlodi [R_EXTENDED_CAPABILITY] = 0x00000239, 3831032d6d6SJoe Komlodi [R_SLAVE_CONFIG] = 0x00000023, 3847d87775fSJoe Komlodi }; 3857d87775fSJoe Komlodi 386a9d3f922SJoe Komlodi static const uint32_t ast2600_i3c_device_ro[ASPEED_I3C_DEVICE_NR_REGS] = { 387a9d3f922SJoe Komlodi [R_DEVICE_CTRL] = 0x04fffe00, 388a9d3f922SJoe Komlodi [R_DEVICE_ADDR] = 0x7f807f80, 389a9d3f922SJoe Komlodi [R_HW_CAPABILITY] = 0xffffffff, 390a9d3f922SJoe Komlodi [R_IBI_QUEUE_STATUS] = 0xffffffff, 391a9d3f922SJoe Komlodi [R_DATA_BUFFER_THLD_CTRL] = 0xf8f8f8f8, 392a9d3f922SJoe Komlodi [R_IBI_QUEUE_CTRL] = 0xfffffff0, 393a9d3f922SJoe Komlodi [R_RESET_CTRL] = 0xffffffc0, 394a9d3f922SJoe Komlodi [R_SLV_EVENT_CTRL] = 0xffffff3f, 395a9d3f922SJoe Komlodi [R_INTR_STATUS] = 0xffff809f, 396a9d3f922SJoe Komlodi [R_INTR_STATUS_EN] = 0xffff8080, 397a9d3f922SJoe Komlodi [R_INTR_SIGNAL_EN] = 0xffff8080, 398a9d3f922SJoe Komlodi [R_INTR_FORCE] = 0xffff8000, 399a9d3f922SJoe Komlodi [R_QUEUE_STATUS_LEVEL] = 0xffffffff, 400a9d3f922SJoe Komlodi [R_DATA_BUFFER_STATUS_LEVEL] = 0xffffffff, 401a9d3f922SJoe Komlodi [R_PRESENT_STATE] = 0xffffffff, 402a9d3f922SJoe Komlodi [R_CCC_DEVICE_STATUS] = 0xffffffff, 403a9d3f922SJoe Komlodi [R_I3C_VER_ID] = 0xffffffff, 404a9d3f922SJoe Komlodi [R_I3C_VER_TYPE] = 0xffffffff, 405a9d3f922SJoe Komlodi [R_DEVICE_ADDR_TABLE_POINTER] = 0xffffffff, 406a9d3f922SJoe Komlodi [R_DEV_CHAR_TABLE_POINTER] = 0xffcbffff, 407a9d3f922SJoe Komlodi [R_SLV_PID_VALUE] = 0xffff0fff, 408a9d3f922SJoe Komlodi [R_SLV_CHAR_CTRL] = 0xffffffff, 409a9d3f922SJoe Komlodi [A_VENDOR_SPECIFIC_REG_POINTER] = 0xffffffff, 410a9d3f922SJoe Komlodi [R_SLV_MAX_LEN] = 0xffffffff, 411a9d3f922SJoe Komlodi [R_MAX_READ_TURNAROUND] = 0xffffffff, 412a9d3f922SJoe Komlodi [R_MAX_DATA_SPEED] = 0xffffffff, 413a9d3f922SJoe Komlodi [R_SLV_INTR_REQ] = 0xfffffff0, 414a9d3f922SJoe Komlodi [R_SLV_TSX_SYMBL_TIMING] = 0xffffffc0, 415a9d3f922SJoe Komlodi [R_DEVICE_CTRL_EXTENDED] = 0xfffffff8, 416a9d3f922SJoe Komlodi [R_SCL_I3C_OD_TIMING] = 0xff00ff00, 417a9d3f922SJoe Komlodi [R_SCL_I3C_PP_TIMING] = 0xff00ff00, 418a9d3f922SJoe Komlodi [R_SCL_I2C_FMP_TIMING] = 0xff000000, 419a9d3f922SJoe Komlodi [R_SCL_EXT_TERMN_LCNT_TIMING] = 0x0000fff0, 420a9d3f922SJoe Komlodi [R_BUS_IDLE_TIMING] = 0xfff00000, 421a9d3f922SJoe Komlodi [R_EXTENDED_CAPABILITY] = 0xffffffff, 422a9d3f922SJoe Komlodi [R_SLAVE_CONFIG] = 0xffffffff, 423a9d3f922SJoe Komlodi }; 424a9d3f922SJoe Komlodi 4254ba25376SJoe Komlodi static inline bool aspeed_i3c_device_has_entdaa(AspeedI3CDevice *s) 4264ba25376SJoe Komlodi { 4274ba25376SJoe Komlodi return ARRAY_FIELD_EX32(s->regs, HW_CAPABILITY, ENTDAA); 4284ba25376SJoe Komlodi } 4294ba25376SJoe Komlodi 4304ba25376SJoe Komlodi static inline bool aspeed_i3c_device_has_hdr_ts(AspeedI3CDevice *s) 4314ba25376SJoe Komlodi { 4324ba25376SJoe Komlodi return ARRAY_FIELD_EX32(s->regs, HW_CAPABILITY, HDR_TS); 4334ba25376SJoe Komlodi } 4344ba25376SJoe Komlodi 4354ba25376SJoe Komlodi static inline bool aspeed_i3c_device_has_hdr_ddr(AspeedI3CDevice *s) 4364ba25376SJoe Komlodi { 4374ba25376SJoe Komlodi return ARRAY_FIELD_EX32(s->regs, HW_CAPABILITY, HDR_DDR); 4384ba25376SJoe Komlodi } 4394ba25376SJoe Komlodi 4404ba25376SJoe Komlodi static inline bool aspeed_i3c_device_can_transmit(AspeedI3CDevice *s) 4414ba25376SJoe Komlodi { 4424ba25376SJoe Komlodi /* 4434ba25376SJoe Komlodi * We can only transmit if we're enabled and the resume bit is cleared. 4444ba25376SJoe Komlodi * The resume bit is set on a transaction error, and software must clear it. 4454ba25376SJoe Komlodi */ 4464ba25376SJoe Komlodi return ARRAY_FIELD_EX32(s->regs, DEVICE_CTRL, I3C_EN) && 4474ba25376SJoe Komlodi !ARRAY_FIELD_EX32(s->regs, DEVICE_CTRL, I3C_RESUME); 4484ba25376SJoe Komlodi } 4494ba25376SJoe Komlodi 4504ba25376SJoe Komlodi static inline uint8_t aspeed_i3c_device_fifo_threshold_from_reg(uint8_t regval) 4514ba25376SJoe Komlodi { 4524ba25376SJoe Komlodi return regval = regval ? (2 << regval) : 1; 4534ba25376SJoe Komlodi } 4544ba25376SJoe Komlodi 455*93ec6949SJoe Komlodi static inline uint8_t aspeed_i3c_device_ibi_slice_size(AspeedI3CDevice *s) 456*93ec6949SJoe Komlodi { 457*93ec6949SJoe Komlodi uint8_t ibi_slice_size = ARRAY_FIELD_EX32(s->regs, QUEUE_THLD_CTRL, 458*93ec6949SJoe Komlodi IBI_DATA_THLD); 459*93ec6949SJoe Komlodi /* The minimum supported slice size is 4 bytes. */ 460*93ec6949SJoe Komlodi if (ibi_slice_size == 0) { 461*93ec6949SJoe Komlodi ibi_slice_size = 1; 462*93ec6949SJoe Komlodi } 463*93ec6949SJoe Komlodi ibi_slice_size *= sizeof(uint32_t); 464*93ec6949SJoe Komlodi /* maximum supported size is 63 bytes. */ 465*93ec6949SJoe Komlodi if (ibi_slice_size >= 64) { 466*93ec6949SJoe Komlodi ibi_slice_size = 63; 467*93ec6949SJoe Komlodi } 468*93ec6949SJoe Komlodi 469*93ec6949SJoe Komlodi return ibi_slice_size; 470*93ec6949SJoe Komlodi } 471*93ec6949SJoe Komlodi 4723816bedaSJoe Komlodi static void aspeed_i3c_device_update_irq(AspeedI3CDevice *s) 4733816bedaSJoe Komlodi { 4743816bedaSJoe Komlodi bool level = !!(s->regs[R_INTR_SIGNAL_EN] & s->regs[R_INTR_STATUS]); 4753816bedaSJoe Komlodi qemu_set_irq(s->irq, level); 4763816bedaSJoe Komlodi } 4773816bedaSJoe Komlodi 4784ba25376SJoe Komlodi static void aspeed_i3c_device_end_transfer(AspeedI3CDevice *s, bool is_i2c) 4794ba25376SJoe Komlodi { 4804ba25376SJoe Komlodi if (is_i2c) { 4814ba25376SJoe Komlodi legacy_i2c_end_transfer(s->bus); 4824ba25376SJoe Komlodi } else { 4834ba25376SJoe Komlodi i3c_end_transfer(s->bus); 4844ba25376SJoe Komlodi } 4854ba25376SJoe Komlodi } 4864ba25376SJoe Komlodi 4874ba25376SJoe Komlodi static int aspeed_i3c_device_send_start(AspeedI3CDevice *s, uint8_t addr, 4884ba25376SJoe Komlodi bool is_recv, bool is_i2c) 4894ba25376SJoe Komlodi { 4904ba25376SJoe Komlodi int ret; 4914ba25376SJoe Komlodi 4924ba25376SJoe Komlodi if (is_i2c) { 4934ba25376SJoe Komlodi ret = legacy_i2c_start_transfer(s->bus, addr, is_recv); 4944ba25376SJoe Komlodi } else { 4954ba25376SJoe Komlodi ret = i3c_start_transfer(s->bus, addr, is_recv); 4964ba25376SJoe Komlodi } 4974ba25376SJoe Komlodi if (ret) { 4984ba25376SJoe Komlodi qemu_log_mask(LOG_GUEST_ERROR, "%s: NACKed on TX with addr 0x%.2x\n", 4994ba25376SJoe Komlodi object_get_canonical_path(OBJECT(s)), addr); 5004ba25376SJoe Komlodi ARRAY_FIELD_DP32(s->regs, PRESENT_STATE, CM_TFR_ST_STATUS, 5014ba25376SJoe Komlodi ASPEED_I3C_TRANSFER_STATE_HALT); 5024ba25376SJoe Komlodi ARRAY_FIELD_DP32(s->regs, PRESENT_STATE, CM_TFR_STATUS, 5034ba25376SJoe Komlodi ASPEED_I3C_TRANSFER_STATUS_HALT); 5044ba25376SJoe Komlodi ARRAY_FIELD_DP32(s->regs, INTR_STATUS, TRANSFER_ERR, 1); 5054ba25376SJoe Komlodi ARRAY_FIELD_DP32(s->regs, DEVICE_CTRL, I3C_RESUME, 1); 5064ba25376SJoe Komlodi } 5074ba25376SJoe Komlodi 5084ba25376SJoe Komlodi return ret; 5094ba25376SJoe Komlodi } 5104ba25376SJoe Komlodi 5114ba25376SJoe Komlodi static int aspeed_i3c_device_send(AspeedI3CDevice *s, const uint8_t *data, 5124ba25376SJoe Komlodi uint32_t num_to_send, uint32_t *num_sent, 5134ba25376SJoe Komlodi bool is_i2c) 5144ba25376SJoe Komlodi { 5154ba25376SJoe Komlodi int ret; 5164ba25376SJoe Komlodi uint32_t i; 5174ba25376SJoe Komlodi 5184ba25376SJoe Komlodi *num_sent = 0; 5194ba25376SJoe Komlodi if (is_i2c) { 5204ba25376SJoe Komlodi /* Legacy I2C must be byte-by-byte. */ 5214ba25376SJoe Komlodi for (i = 0; i < num_to_send; i++) { 5224ba25376SJoe Komlodi ret = legacy_i2c_send(s->bus, data[i]); 5234ba25376SJoe Komlodi if (ret) { 5244ba25376SJoe Komlodi break; 5254ba25376SJoe Komlodi } 5264ba25376SJoe Komlodi (*num_sent)++; 5274ba25376SJoe Komlodi } 5284ba25376SJoe Komlodi } else { 5294ba25376SJoe Komlodi ret = i3c_send(s->bus, data, num_to_send, num_sent); 5304ba25376SJoe Komlodi } 5314ba25376SJoe Komlodi if (ret) { 5324ba25376SJoe Komlodi qemu_log_mask(LOG_GUEST_ERROR, "%s: NACKed sending byte 0x%.2x\n", 5334ba25376SJoe Komlodi object_get_canonical_path(OBJECT(s)), data[*num_sent]); 5344ba25376SJoe Komlodi ARRAY_FIELD_DP32(s->regs, PRESENT_STATE, CM_TFR_ST_STATUS, 5354ba25376SJoe Komlodi ASPEED_I3C_TRANSFER_STATE_HALT); 5364ba25376SJoe Komlodi ARRAY_FIELD_DP32(s->regs, PRESENT_STATE, CM_TFR_STATUS, 5374ba25376SJoe Komlodi ASPEED_I3C_TRANSFER_STATUS_HALT); 5384ba25376SJoe Komlodi ARRAY_FIELD_DP32(s->regs, INTR_STATUS, TRANSFER_ERR, 1); 5394ba25376SJoe Komlodi ARRAY_FIELD_DP32(s->regs, DEVICE_CTRL, I3C_RESUME, 1); 5404ba25376SJoe Komlodi } 5414ba25376SJoe Komlodi 5424ba25376SJoe Komlodi trace_aspeed_i3c_device_send(s->id, *num_sent); 5434ba25376SJoe Komlodi 5444ba25376SJoe Komlodi return ret; 5454ba25376SJoe Komlodi } 5464ba25376SJoe Komlodi 5474ba25376SJoe Komlodi static int aspeed_i3c_device_send_byte(AspeedI3CDevice *s, uint8_t byte, 5484ba25376SJoe Komlodi bool is_i2c) 5494ba25376SJoe Komlodi { 5504ba25376SJoe Komlodi /* 5514ba25376SJoe Komlodi * Ignored, the caller will know if we sent 0 or 1 bytes depending on if 5524ba25376SJoe Komlodi * we were ACKed/NACKed. 5534ba25376SJoe Komlodi */ 5544ba25376SJoe Komlodi uint32_t num_sent; 5554ba25376SJoe Komlodi return aspeed_i3c_device_send(s, &byte, 1, &num_sent, is_i2c); 5564ba25376SJoe Komlodi } 5574ba25376SJoe Komlodi 5584ba25376SJoe Komlodi static int aspeed_i3c_device_recv_data(AspeedI3CDevice *s, bool is_i2c, 5594ba25376SJoe Komlodi uint8_t *data, uint16_t num_to_read, 5604ba25376SJoe Komlodi uint32_t *num_read) 5614ba25376SJoe Komlodi { 5624ba25376SJoe Komlodi int ret; 5634ba25376SJoe Komlodi 5644ba25376SJoe Komlodi if (is_i2c) { 5654ba25376SJoe Komlodi for (uint16_t i = 0; i < num_to_read; i++) { 5664ba25376SJoe Komlodi data[i] = legacy_i2c_recv(s->bus); 5674ba25376SJoe Komlodi } 5684ba25376SJoe Komlodi /* I2C devices can neither NACK a read, nor end transfers early. */ 5694ba25376SJoe Komlodi *num_read = num_to_read; 5704ba25376SJoe Komlodi trace_aspeed_i3c_device_recv_data(s->id, *num_read); 5714ba25376SJoe Komlodi return 0; 5724ba25376SJoe Komlodi } 5734ba25376SJoe Komlodi /* I3C devices can NACK if the controller sends an unsupported CCC. */ 5744ba25376SJoe Komlodi ret = i3c_recv(s->bus, data, num_to_read, num_read); 5754ba25376SJoe Komlodi if (ret) { 5764ba25376SJoe Komlodi qemu_log_mask(LOG_GUEST_ERROR, "%s: NACKed receiving byte\n", 5774ba25376SJoe Komlodi object_get_canonical_path(OBJECT(s))); 5784ba25376SJoe Komlodi ARRAY_FIELD_DP32(s->regs, PRESENT_STATE, CM_TFR_ST_STATUS, 5794ba25376SJoe Komlodi ASPEED_I3C_TRANSFER_STATE_HALT); 5804ba25376SJoe Komlodi ARRAY_FIELD_DP32(s->regs, PRESENT_STATE, CM_TFR_STATUS, 5814ba25376SJoe Komlodi ASPEED_I3C_TRANSFER_STATUS_HALT); 5824ba25376SJoe Komlodi ARRAY_FIELD_DP32(s->regs, INTR_STATUS, TRANSFER_ERR, 1); 5834ba25376SJoe Komlodi ARRAY_FIELD_DP32(s->regs, DEVICE_CTRL, I3C_RESUME, 1); 5844ba25376SJoe Komlodi } 5854ba25376SJoe Komlodi 5864ba25376SJoe Komlodi trace_aspeed_i3c_device_recv_data(s->id, *num_read); 5874ba25376SJoe Komlodi 5884ba25376SJoe Komlodi return ret; 5894ba25376SJoe Komlodi } 5904ba25376SJoe Komlodi 5914ba25376SJoe Komlodi static inline bool aspeed_i3c_device_target_is_i2c(AspeedI3CDevice *s, 5924ba25376SJoe Komlodi uint16_t offset) 5934ba25376SJoe Komlodi { 5944ba25376SJoe Komlodi uint16_t dev_index = R_DEVICE_ADDR_TABLE_LOC1 + offset; 5954ba25376SJoe Komlodi return FIELD_EX32(s->regs[dev_index], DEVICE_ADDR_TABLE_LOC1, 5964ba25376SJoe Komlodi LEGACY_I2C_DEVICE); 5974ba25376SJoe Komlodi } 5984ba25376SJoe Komlodi 5994ba25376SJoe Komlodi static uint8_t aspeed_i3c_device_target_addr(AspeedI3CDevice *s, 6004ba25376SJoe Komlodi uint16_t offset) 6014ba25376SJoe Komlodi { 6024ba25376SJoe Komlodi if (offset > ASPEED_I3C_NR_DEVICES) { 6034ba25376SJoe Komlodi qemu_log_mask(LOG_GUEST_ERROR, "%s: Device addr table offset %d out of " 6044ba25376SJoe Komlodi "bounds\n", object_get_canonical_path(OBJECT(s)), offset); 6054ba25376SJoe Komlodi /* If we're out of bounds, return an address of 0. */ 6064ba25376SJoe Komlodi return 0; 6074ba25376SJoe Komlodi } 6084ba25376SJoe Komlodi 6094ba25376SJoe Komlodi uint16_t dev_index = R_DEVICE_ADDR_TABLE_LOC1 + offset; 6104ba25376SJoe Komlodi /* I2C devices use a static address. */ 6114ba25376SJoe Komlodi if (aspeed_i3c_device_target_is_i2c(s, offset)) { 6124ba25376SJoe Komlodi return FIELD_EX32(s->regs[dev_index], DEVICE_ADDR_TABLE_LOC1, 6134ba25376SJoe Komlodi DEV_STATIC_ADDR); 6144ba25376SJoe Komlodi } 6154ba25376SJoe Komlodi return FIELD_EX32(s->regs[dev_index], DEVICE_ADDR_TABLE_LOC1, 6164ba25376SJoe Komlodi DEV_DYNAMIC_ADDR); 6174ba25376SJoe Komlodi } 6184ba25376SJoe Komlodi 619*93ec6949SJoe Komlodi static int aspeed_i3c_device_addr_table_index_from_addr(AspeedI3CDevice *s, 620*93ec6949SJoe Komlodi uint8_t addr) 621*93ec6949SJoe Komlodi { 622*93ec6949SJoe Komlodi uint8_t table_size = ARRAY_FIELD_EX32(s->regs, DEVICE_ADDR_TABLE_POINTER, 623*93ec6949SJoe Komlodi DEPTH); 624*93ec6949SJoe Komlodi for (uint8_t i = 0; i < table_size; i++) { 625*93ec6949SJoe Komlodi if (aspeed_i3c_device_target_addr(s, i) == addr) { 626*93ec6949SJoe Komlodi return i; 627*93ec6949SJoe Komlodi } 628*93ec6949SJoe Komlodi } 629*93ec6949SJoe Komlodi return -1; 630*93ec6949SJoe Komlodi } 631*93ec6949SJoe Komlodi 632*93ec6949SJoe Komlodi static void aspeed_i3c_device_send_disec(AspeedI3CDevice *s) 633*93ec6949SJoe Komlodi { 634*93ec6949SJoe Komlodi uint8_t ccc = I3C_CCC_DISEC; 635*93ec6949SJoe Komlodi if (s->ibi_data.send_direct_disec) { 636*93ec6949SJoe Komlodi ccc = I3C_CCCD_DISEC; 637*93ec6949SJoe Komlodi } 638*93ec6949SJoe Komlodi 639*93ec6949SJoe Komlodi aspeed_i3c_device_send_start(s, I3C_BROADCAST, /*is_recv=*/false, 640*93ec6949SJoe Komlodi /*is_i2c=*/false); 641*93ec6949SJoe Komlodi aspeed_i3c_device_send_byte(s, ccc, /*is_i2c=*/false); 642*93ec6949SJoe Komlodi if (s->ibi_data.send_direct_disec) { 643*93ec6949SJoe Komlodi aspeed_i3c_device_send_start(s, s->ibi_data.disec_addr, 644*93ec6949SJoe Komlodi /*is_recv=*/false, /*is_i2c=*/false); 645*93ec6949SJoe Komlodi } 646*93ec6949SJoe Komlodi aspeed_i3c_device_send_byte(s, s->ibi_data.disec_byte, /*is_i2c=*/false); 647*93ec6949SJoe Komlodi } 648*93ec6949SJoe Komlodi 649*93ec6949SJoe Komlodi static int aspeed_i3c_device_handle_hj(AspeedI3CDevice *s) 650*93ec6949SJoe Komlodi { 651*93ec6949SJoe Komlodi if (ARRAY_FIELD_EX32(s->regs, IBI_QUEUE_CTRL, NOTIFY_REJECTED_HOT_JOIN)) { 652*93ec6949SJoe Komlodi s->ibi_data.notify_ibi_nack = true; 653*93ec6949SJoe Komlodi } 654*93ec6949SJoe Komlodi 655*93ec6949SJoe Komlodi bool nack_and_disable = ARRAY_FIELD_EX32(s->regs, DEVICE_CTRL, 656*93ec6949SJoe Komlodi HOT_JOIN_ACK_NACK_CTRL); 657*93ec6949SJoe Komlodi if (nack_and_disable) { 658*93ec6949SJoe Komlodi s->ibi_data.ibi_queue_status = FIELD_DP32(s->ibi_data.ibi_queue_status, 659*93ec6949SJoe Komlodi IBI_QUEUE_STATUS, 660*93ec6949SJoe Komlodi IBI_STATUS, 1); 661*93ec6949SJoe Komlodi s->ibi_data.ibi_nacked = true; 662*93ec6949SJoe Komlodi s->ibi_data.disec_byte = DISEC_HJ; 663*93ec6949SJoe Komlodi return -1; 664*93ec6949SJoe Komlodi } 665*93ec6949SJoe Komlodi return 0; 666*93ec6949SJoe Komlodi } 667*93ec6949SJoe Komlodi 668*93ec6949SJoe Komlodi static int aspeed_i3c_device_handle_ctlr_req(AspeedI3CDevice *s, uint8_t addr) 669*93ec6949SJoe Komlodi { 670*93ec6949SJoe Komlodi if (ARRAY_FIELD_EX32(s->regs, IBI_QUEUE_CTRL, NOTIFY_REJECTED_MASTER_REQ)) { 671*93ec6949SJoe Komlodi s->ibi_data.notify_ibi_nack = true; 672*93ec6949SJoe Komlodi } 673*93ec6949SJoe Komlodi 674*93ec6949SJoe Komlodi int table_offset = aspeed_i3c_device_addr_table_index_from_addr(s, addr); 675*93ec6949SJoe Komlodi /* Doesn't exist in the table, NACK it, don't DISEC. */ 676*93ec6949SJoe Komlodi if (table_offset < 0) { 677*93ec6949SJoe Komlodi return -1; 678*93ec6949SJoe Komlodi } 679*93ec6949SJoe Komlodi 680*93ec6949SJoe Komlodi table_offset += R_DEVICE_ADDR_TABLE_LOC1; 681*93ec6949SJoe Komlodi if (FIELD_EX32(s->regs[table_offset], DEVICE_ADDR_TABLE_LOC1, MR_REJECT)) { 682*93ec6949SJoe Komlodi s->ibi_data.ibi_queue_status = FIELD_DP32(s->ibi_data.ibi_queue_status, 683*93ec6949SJoe Komlodi IBI_QUEUE_STATUS, 684*93ec6949SJoe Komlodi IBI_STATUS, 1); 685*93ec6949SJoe Komlodi s->ibi_data.ibi_nacked = true; 686*93ec6949SJoe Komlodi s->ibi_data.disec_addr = addr; 687*93ec6949SJoe Komlodi /* Tell the requester to disable controller role requests. */ 688*93ec6949SJoe Komlodi s->ibi_data.disec_byte = DISEC_CR; 689*93ec6949SJoe Komlodi s->ibi_data.send_direct_disec = true; 690*93ec6949SJoe Komlodi return -1; 691*93ec6949SJoe Komlodi } 692*93ec6949SJoe Komlodi return 0; 693*93ec6949SJoe Komlodi } 694*93ec6949SJoe Komlodi 695*93ec6949SJoe Komlodi static int aspeed_i3c_device_handle_targ_irq(AspeedI3CDevice *s, uint8_t addr) 696*93ec6949SJoe Komlodi { 697*93ec6949SJoe Komlodi if (ARRAY_FIELD_EX32(s->regs, IBI_QUEUE_CTRL, NOTIFY_REJECTED_SLAVE_IRQ)) { 698*93ec6949SJoe Komlodi s->ibi_data.notify_ibi_nack = true; 699*93ec6949SJoe Komlodi } 700*93ec6949SJoe Komlodi 701*93ec6949SJoe Komlodi int table_offset = aspeed_i3c_device_addr_table_index_from_addr(s, addr); 702*93ec6949SJoe Komlodi /* Doesn't exist in the table, NACK it, don't DISEC. */ 703*93ec6949SJoe Komlodi if (table_offset < 0) { 704*93ec6949SJoe Komlodi return -1; 705*93ec6949SJoe Komlodi } 706*93ec6949SJoe Komlodi 707*93ec6949SJoe Komlodi table_offset += R_DEVICE_ADDR_TABLE_LOC1; 708*93ec6949SJoe Komlodi if (FIELD_EX32(s->regs[table_offset], DEVICE_ADDR_TABLE_LOC1, SIR_REJECT)) { 709*93ec6949SJoe Komlodi s->ibi_data.ibi_queue_status = FIELD_DP32(s->ibi_data.ibi_queue_status, 710*93ec6949SJoe Komlodi IBI_QUEUE_STATUS, 711*93ec6949SJoe Komlodi IBI_STATUS, 1); 712*93ec6949SJoe Komlodi s->ibi_data.ibi_nacked = true; 713*93ec6949SJoe Komlodi s->ibi_data.disec_addr = addr; 714*93ec6949SJoe Komlodi /* Tell the requester to disable interrupts. */ 715*93ec6949SJoe Komlodi s->ibi_data.disec_byte = DISEC_INT; 716*93ec6949SJoe Komlodi s->ibi_data.send_direct_disec = true; 717*93ec6949SJoe Komlodi return -1; 718*93ec6949SJoe Komlodi } 719*93ec6949SJoe Komlodi return 0; 720*93ec6949SJoe Komlodi } 721*93ec6949SJoe Komlodi 722*93ec6949SJoe Komlodi static int aspeed_i3c_device_ibi_handle(I3CBus *bus, I3CTarget *target, 723*93ec6949SJoe Komlodi uint8_t addr, bool is_recv) 724*93ec6949SJoe Komlodi { 725*93ec6949SJoe Komlodi AspeedI3CDevice *s = ASPEED_I3C_DEVICE(bus->qbus.parent); 726*93ec6949SJoe Komlodi 727*93ec6949SJoe Komlodi trace_aspeed_i3c_device_ibi_handle(s->id, addr, is_recv); 728*93ec6949SJoe Komlodi s->ibi_data.ibi_queue_status = FIELD_DP32(s->ibi_data.ibi_queue_status, 729*93ec6949SJoe Komlodi IBI_QUEUE_STATUS, IBI_ID, 730*93ec6949SJoe Komlodi (addr << 1) | is_recv); 731*93ec6949SJoe Komlodi /* Is this a hot join request? */ 732*93ec6949SJoe Komlodi if (addr == I3C_HJ_ADDR) { 733*93ec6949SJoe Komlodi return aspeed_i3c_device_handle_hj(s); 734*93ec6949SJoe Komlodi } 735*93ec6949SJoe Komlodi /* Is secondary controller requesting access? */ 736*93ec6949SJoe Komlodi if (addr == target->address && !is_recv) { 737*93ec6949SJoe Komlodi return aspeed_i3c_device_handle_ctlr_req(s, addr); 738*93ec6949SJoe Komlodi } 739*93ec6949SJoe Komlodi /* Is this a target IRQ? */ 740*93ec6949SJoe Komlodi if (addr == target->address && is_recv) { 741*93ec6949SJoe Komlodi return aspeed_i3c_device_handle_targ_irq(s, addr); 742*93ec6949SJoe Komlodi } 743*93ec6949SJoe Komlodi 744*93ec6949SJoe Komlodi /* Not sure what this is, NACK it. */ 745*93ec6949SJoe Komlodi return -1; 746*93ec6949SJoe Komlodi } 747*93ec6949SJoe Komlodi 748*93ec6949SJoe Komlodi static int aspeed_i3c_device_ibi_recv(I3CBus *bus, uint8_t data) 749*93ec6949SJoe Komlodi { 750*93ec6949SJoe Komlodi AspeedI3CDevice *s = ASPEED_I3C_DEVICE(bus->qbus.parent); 751*93ec6949SJoe Komlodi if (fifo8_is_full(&s->ibi_data.ibi_intermediate_queue)) { 752*93ec6949SJoe Komlodi return -1; 753*93ec6949SJoe Komlodi } 754*93ec6949SJoe Komlodi 755*93ec6949SJoe Komlodi fifo8_push(&s->ibi_data.ibi_intermediate_queue, data); 756*93ec6949SJoe Komlodi trace_aspeed_i3c_device_ibi_recv(s->id, data); 757*93ec6949SJoe Komlodi return 0; 758*93ec6949SJoe Komlodi } 759*93ec6949SJoe Komlodi 760*93ec6949SJoe Komlodi static void aspeed_i3c_device_ibi_queue_push(AspeedI3CDevice *s) 761*93ec6949SJoe Komlodi { 762*93ec6949SJoe Komlodi /* Stored value is in 32-bit chunks, convert it to byte chunks. */ 763*93ec6949SJoe Komlodi uint8_t ibi_slice_size = aspeed_i3c_device_ibi_slice_size(s); 764*93ec6949SJoe Komlodi uint8_t num_slices = fifo8_num_used(&s->ibi_data.ibi_intermediate_queue) / 765*93ec6949SJoe Komlodi ibi_slice_size; 766*93ec6949SJoe Komlodi uint8_t ibi_status_count = num_slices; 767*93ec6949SJoe Komlodi union { 768*93ec6949SJoe Komlodi uint8_t b[sizeof(uint32_t)]; 769*93ec6949SJoe Komlodi uint32_t val32; 770*93ec6949SJoe Komlodi } ibi_data = { 771*93ec6949SJoe Komlodi .val32 = 0 772*93ec6949SJoe Komlodi }; 773*93ec6949SJoe Komlodi 774*93ec6949SJoe Komlodi /* The report was suppressed, do nothing. */ 775*93ec6949SJoe Komlodi if (s->ibi_data.ibi_nacked && !s->ibi_data.notify_ibi_nack) { 776*93ec6949SJoe Komlodi ARRAY_FIELD_DP32(s->regs, PRESENT_STATE, CM_TFR_ST_STATUS, 777*93ec6949SJoe Komlodi ASPEED_I3C_TRANSFER_STATE_IDLE); 778*93ec6949SJoe Komlodi ARRAY_FIELD_DP32(s->regs, PRESENT_STATE, CM_TFR_STATUS, 779*93ec6949SJoe Komlodi ASPEED_I3C_TRANSFER_STATUS_IDLE); 780*93ec6949SJoe Komlodi return; 781*93ec6949SJoe Komlodi } 782*93ec6949SJoe Komlodi 783*93ec6949SJoe Komlodi /* If we don't have any slices to push, just push the status. */ 784*93ec6949SJoe Komlodi if (num_slices == 0) { 785*93ec6949SJoe Komlodi s->ibi_data.ibi_queue_status = 786*93ec6949SJoe Komlodi FIELD_DP32(s->ibi_data.ibi_queue_status, IBI_QUEUE_STATUS, 787*93ec6949SJoe Komlodi LAST_STATUS, 1); 788*93ec6949SJoe Komlodi fifo32_push(&s->ibi_queue, s->ibi_data.ibi_queue_status); 789*93ec6949SJoe Komlodi ibi_status_count = 1; 790*93ec6949SJoe Komlodi } 791*93ec6949SJoe Komlodi 792*93ec6949SJoe Komlodi for (uint8_t i = 0; i < num_slices; i++) { 793*93ec6949SJoe Komlodi /* If this is the last slice, set LAST_STATUS. */ 794*93ec6949SJoe Komlodi if (fifo8_num_used(&s->ibi_data.ibi_intermediate_queue) < 795*93ec6949SJoe Komlodi ibi_slice_size) { 796*93ec6949SJoe Komlodi s->ibi_data.ibi_queue_status = 797*93ec6949SJoe Komlodi FIELD_DP32(s->ibi_data.ibi_queue_status, IBI_QUEUE_STATUS, 798*93ec6949SJoe Komlodi IBI_DATA_LEN, 799*93ec6949SJoe Komlodi fifo8_num_used(&s->ibi_data.ibi_intermediate_queue)); 800*93ec6949SJoe Komlodi s->ibi_data.ibi_queue_status = 801*93ec6949SJoe Komlodi FIELD_DP32(s->ibi_data.ibi_queue_status, IBI_QUEUE_STATUS, 802*93ec6949SJoe Komlodi LAST_STATUS, 1); 803*93ec6949SJoe Komlodi } else { 804*93ec6949SJoe Komlodi s->ibi_data.ibi_queue_status = 805*93ec6949SJoe Komlodi FIELD_DP32(s->ibi_data.ibi_queue_status, IBI_QUEUE_STATUS, 806*93ec6949SJoe Komlodi IBI_DATA_LEN, ibi_slice_size); 807*93ec6949SJoe Komlodi } 808*93ec6949SJoe Komlodi 809*93ec6949SJoe Komlodi /* Push the IBI status header. */ 810*93ec6949SJoe Komlodi fifo32_push(&s->ibi_queue, s->ibi_data.ibi_queue_status); 811*93ec6949SJoe Komlodi /* Move each IBI byte into a 32-bit word and push it into the queue. */ 812*93ec6949SJoe Komlodi for (uint8_t j = 0; j < ibi_slice_size; ++j) { 813*93ec6949SJoe Komlodi if (fifo8_is_empty(&s->ibi_data.ibi_intermediate_queue)) { 814*93ec6949SJoe Komlodi break; 815*93ec6949SJoe Komlodi } 816*93ec6949SJoe Komlodi 817*93ec6949SJoe Komlodi ibi_data.b[j & 3] = fifo8_pop(&s->ibi_data.ibi_intermediate_queue); 818*93ec6949SJoe Komlodi /* We have 32-bits, push it to the IBI FIFO. */ 819*93ec6949SJoe Komlodi if ((j & 0x03) == 0x03) { 820*93ec6949SJoe Komlodi fifo32_push(&s->ibi_queue, ibi_data.val32); 821*93ec6949SJoe Komlodi ibi_data.val32 = 0; 822*93ec6949SJoe Komlodi } 823*93ec6949SJoe Komlodi } 824*93ec6949SJoe Komlodi /* If the data isn't 32-bit aligned, push the leftover bytes. */ 825*93ec6949SJoe Komlodi if (ibi_slice_size & 0x03) { 826*93ec6949SJoe Komlodi fifo32_push(&s->ibi_queue, ibi_data.val32); 827*93ec6949SJoe Komlodi } 828*93ec6949SJoe Komlodi 829*93ec6949SJoe Komlodi /* Clear out the data length for the next iteration. */ 830*93ec6949SJoe Komlodi s->ibi_data.ibi_queue_status = FIELD_DP32(s->ibi_data.ibi_queue_status, 831*93ec6949SJoe Komlodi IBI_QUEUE_STATUS, IBI_DATA_LEN, 0); 832*93ec6949SJoe Komlodi } 833*93ec6949SJoe Komlodi 834*93ec6949SJoe Komlodi ARRAY_FIELD_DP32(s->regs, QUEUE_STATUS_LEVEL, IBI_BUF_BLR, 835*93ec6949SJoe Komlodi fifo32_num_used(&s->ibi_queue)); 836*93ec6949SJoe Komlodi ARRAY_FIELD_DP32(s->regs, QUEUE_STATUS_LEVEL, IBI_STATUS_CNT, 837*93ec6949SJoe Komlodi ibi_status_count); 838*93ec6949SJoe Komlodi /* Threshold is the register value + 1. */ 839*93ec6949SJoe Komlodi uint8_t threshold = ARRAY_FIELD_EX32(s->regs, QUEUE_THLD_CTRL, 840*93ec6949SJoe Komlodi IBI_STATUS_THLD) + 1; 841*93ec6949SJoe Komlodi if (fifo32_num_used(&s->ibi_queue) >= threshold) { 842*93ec6949SJoe Komlodi ARRAY_FIELD_DP32(s->regs, INTR_STATUS, IBI_THLD, 1); 843*93ec6949SJoe Komlodi aspeed_i3c_device_update_irq(s); 844*93ec6949SJoe Komlodi } 845*93ec6949SJoe Komlodi 846*93ec6949SJoe Komlodi /* State update. */ 847*93ec6949SJoe Komlodi ARRAY_FIELD_DP32(s->regs, PRESENT_STATE, CM_TFR_ST_STATUS, 848*93ec6949SJoe Komlodi ASPEED_I3C_TRANSFER_STATE_IDLE); 849*93ec6949SJoe Komlodi ARRAY_FIELD_DP32(s->regs, PRESENT_STATE, CM_TFR_STATUS, 850*93ec6949SJoe Komlodi ASPEED_I3C_TRANSFER_STATUS_IDLE); 851*93ec6949SJoe Komlodi } 852*93ec6949SJoe Komlodi 853*93ec6949SJoe Komlodi static int aspeed_i3c_device_ibi_finish(I3CBus *bus) 854*93ec6949SJoe Komlodi { 855*93ec6949SJoe Komlodi AspeedI3CDevice *s = ASPEED_I3C_DEVICE(bus->qbus.parent); 856*93ec6949SJoe Komlodi bool nack_and_disable_hj = ARRAY_FIELD_EX32(s->regs, DEVICE_CTRL, 857*93ec6949SJoe Komlodi HOT_JOIN_ACK_NACK_CTRL); 858*93ec6949SJoe Komlodi if (nack_and_disable_hj || s->ibi_data.send_direct_disec) { 859*93ec6949SJoe Komlodi aspeed_i3c_device_send_disec(s); 860*93ec6949SJoe Komlodi } 861*93ec6949SJoe Komlodi aspeed_i3c_device_ibi_queue_push(s); 862*93ec6949SJoe Komlodi 863*93ec6949SJoe Komlodi /* Clear out the intermediate values. */ 864*93ec6949SJoe Komlodi s->ibi_data.ibi_queue_status = 0; 865*93ec6949SJoe Komlodi s->ibi_data.disec_addr = 0; 866*93ec6949SJoe Komlodi s->ibi_data.disec_byte = 0; 867*93ec6949SJoe Komlodi s->ibi_data.send_direct_disec = false; 868*93ec6949SJoe Komlodi s->ibi_data.notify_ibi_nack = false; 869*93ec6949SJoe Komlodi s->ibi_data.ibi_nacked = false; 870*93ec6949SJoe Komlodi 871*93ec6949SJoe Komlodi return 0; 872*93ec6949SJoe Komlodi } 873*93ec6949SJoe Komlodi 8743816bedaSJoe Komlodi static uint32_t aspeed_i3c_device_intr_status_r(AspeedI3CDevice *s) 8753816bedaSJoe Komlodi { 8763816bedaSJoe Komlodi /* Only return the status whose corresponding EN bits are set. */ 8773816bedaSJoe Komlodi return s->regs[R_INTR_STATUS] & s->regs[R_INTR_STATUS_EN]; 8783816bedaSJoe Komlodi } 8793816bedaSJoe Komlodi 8803816bedaSJoe Komlodi static void aspeed_i3c_device_intr_status_w(AspeedI3CDevice *s, uint32_t val) 8813816bedaSJoe Komlodi { 8823816bedaSJoe Komlodi /* INTR_STATUS[13:5] is w1c, other bits are RO. */ 8833816bedaSJoe Komlodi val &= 0x3fe0; 8843816bedaSJoe Komlodi s->regs[R_INTR_STATUS] &= ~val; 8853816bedaSJoe Komlodi 8863816bedaSJoe Komlodi aspeed_i3c_device_update_irq(s); 8873816bedaSJoe Komlodi } 8883816bedaSJoe Komlodi 8893816bedaSJoe Komlodi static void aspeed_i3c_device_intr_status_en_w(AspeedI3CDevice *s, uint32_t val) 8903816bedaSJoe Komlodi { 8913816bedaSJoe Komlodi s->regs[R_INTR_STATUS_EN] = val; 8923816bedaSJoe Komlodi aspeed_i3c_device_update_irq(s); 8933816bedaSJoe Komlodi } 8943816bedaSJoe Komlodi 8953816bedaSJoe Komlodi static void aspeed_i3c_device_intr_signal_en_w(AspeedI3CDevice *s, uint32_t val) 8963816bedaSJoe Komlodi { 8973816bedaSJoe Komlodi s->regs[R_INTR_SIGNAL_EN] = val; 8983816bedaSJoe Komlodi aspeed_i3c_device_update_irq(s); 8993816bedaSJoe Komlodi } 9003816bedaSJoe Komlodi 9013816bedaSJoe Komlodi static void aspeed_i3c_device_intr_force_w(AspeedI3CDevice *s, uint32_t val) 9023816bedaSJoe Komlodi { 9033816bedaSJoe Komlodi /* INTR_FORCE is WO, just set the corresponding INTR_STATUS bits. */ 9043816bedaSJoe Komlodi s->regs[R_INTR_STATUS] = val; 9053816bedaSJoe Komlodi aspeed_i3c_device_update_irq(s); 9063816bedaSJoe Komlodi } 9073816bedaSJoe Komlodi 9084ba25376SJoe Komlodi static uint32_t aspeed_i3c_device_pop_rx(AspeedI3CDevice *s) 9094ba25376SJoe Komlodi { 9104ba25376SJoe Komlodi if (fifo32_is_empty(&s->rx_queue)) { 9114ba25376SJoe Komlodi qemu_log_mask(LOG_GUEST_ERROR, "%s: Tried to read RX FIFO when empty\n", 9124ba25376SJoe Komlodi object_get_canonical_path(OBJECT(s))); 9134ba25376SJoe Komlodi return 0; 9144ba25376SJoe Komlodi } 9154ba25376SJoe Komlodi 9164ba25376SJoe Komlodi uint32_t val = fifo32_pop(&s->rx_queue); 9174ba25376SJoe Komlodi ARRAY_FIELD_DP32(s->regs, DATA_BUFFER_STATUS_LEVEL, RX_BUF_BLR, 9184ba25376SJoe Komlodi fifo32_num_used(&s->rx_queue)); 9194ba25376SJoe Komlodi 9204ba25376SJoe Komlodi /* Threshold is 2^RX_BUF_THLD. */ 9214ba25376SJoe Komlodi uint8_t threshold = ARRAY_FIELD_EX32(s->regs, DATA_BUFFER_THLD_CTRL, 9224ba25376SJoe Komlodi RX_BUF_THLD); 9234ba25376SJoe Komlodi threshold = aspeed_i3c_device_fifo_threshold_from_reg(threshold); 9244ba25376SJoe Komlodi if (fifo32_num_used(&s->rx_queue) < threshold) { 9254ba25376SJoe Komlodi ARRAY_FIELD_DP32(s->regs, INTR_STATUS, RX_THLD, 0); 9264ba25376SJoe Komlodi aspeed_i3c_device_update_irq(s); 9274ba25376SJoe Komlodi } 9284ba25376SJoe Komlodi 9294ba25376SJoe Komlodi trace_aspeed_i3c_device_pop_rx(s->id, val); 9304ba25376SJoe Komlodi return val; 9314ba25376SJoe Komlodi } 9324ba25376SJoe Komlodi 933*93ec6949SJoe Komlodi static uint32_t aspeed_i3c_device_ibi_queue_r(AspeedI3CDevice *s) 934*93ec6949SJoe Komlodi { 935*93ec6949SJoe Komlodi if (fifo32_is_empty(&s->ibi_queue)) { 936*93ec6949SJoe Komlodi return 0; 937*93ec6949SJoe Komlodi } 938*93ec6949SJoe Komlodi 939*93ec6949SJoe Komlodi uint32_t val = fifo32_pop(&s->ibi_queue); 940*93ec6949SJoe Komlodi ARRAY_FIELD_DP32(s->regs, QUEUE_STATUS_LEVEL, IBI_BUF_BLR, 941*93ec6949SJoe Komlodi fifo32_num_used(&s->ibi_queue)); 942*93ec6949SJoe Komlodi /* Threshold is the register value + 1. */ 943*93ec6949SJoe Komlodi uint8_t threshold = ARRAY_FIELD_EX32(s->regs, QUEUE_THLD_CTRL, 944*93ec6949SJoe Komlodi IBI_STATUS_THLD) + 1; 945*93ec6949SJoe Komlodi if (fifo32_num_used(&s->ibi_queue) < threshold) { 946*93ec6949SJoe Komlodi ARRAY_FIELD_DP32(s->regs, INTR_STATUS, IBI_THLD, 0); 947*93ec6949SJoe Komlodi aspeed_i3c_device_update_irq(s); 948*93ec6949SJoe Komlodi } 949*93ec6949SJoe Komlodi return val; 950*93ec6949SJoe Komlodi } 951*93ec6949SJoe Komlodi 9524ba25376SJoe Komlodi static uint32_t aspeed_i3c_device_resp_queue_port_r(AspeedI3CDevice *s) 9534ba25376SJoe Komlodi { 9544ba25376SJoe Komlodi if (fifo32_is_empty(&s->resp_queue)) { 9554ba25376SJoe Komlodi qemu_log_mask(LOG_GUEST_ERROR, "%s: Tried to read response FIFO when " 9564ba25376SJoe Komlodi "empty\n", object_get_canonical_path(OBJECT(s))); 9574ba25376SJoe Komlodi return 0; 9584ba25376SJoe Komlodi } 9594ba25376SJoe Komlodi 9604ba25376SJoe Komlodi uint32_t val = fifo32_pop(&s->resp_queue); 9614ba25376SJoe Komlodi ARRAY_FIELD_DP32(s->regs, QUEUE_STATUS_LEVEL, RESP_BUF_BLR, 9624ba25376SJoe Komlodi fifo32_num_used(&s->resp_queue)); 9634ba25376SJoe Komlodi 9644ba25376SJoe Komlodi /* Threshold is the register value + 1. */ 9654ba25376SJoe Komlodi uint8_t threshold = ARRAY_FIELD_EX32(s->regs, QUEUE_THLD_CTRL, 9664ba25376SJoe Komlodi RESP_BUF_THLD) + 1; 9674ba25376SJoe Komlodi if (fifo32_num_used(&s->resp_queue) < threshold) { 9684ba25376SJoe Komlodi ARRAY_FIELD_DP32(s->regs, INTR_STATUS, RESP_RDY, 0); 9694ba25376SJoe Komlodi aspeed_i3c_device_update_irq(s); 9704ba25376SJoe Komlodi } 9714ba25376SJoe Komlodi 9724ba25376SJoe Komlodi return val; 9734ba25376SJoe Komlodi } 9744ba25376SJoe Komlodi 9757d87775fSJoe Komlodi static uint64_t aspeed_i3c_device_read(void *opaque, hwaddr offset, 9767d87775fSJoe Komlodi unsigned size) 9777d87775fSJoe Komlodi { 9787d87775fSJoe Komlodi AspeedI3CDevice *s = ASPEED_I3C_DEVICE(opaque); 9797d87775fSJoe Komlodi uint32_t addr = offset >> 2; 9807d87775fSJoe Komlodi uint64_t value; 9817d87775fSJoe Komlodi 9827d87775fSJoe Komlodi switch (addr) { 98309467a8aSJoe Komlodi /* RAZ */ 9847d87775fSJoe Komlodi case R_COMMAND_QUEUE_PORT: 98509467a8aSJoe Komlodi case R_RESET_CTRL: 98609467a8aSJoe Komlodi case R_INTR_FORCE: 9877d87775fSJoe Komlodi value = 0; 9887d87775fSJoe Komlodi break; 989*93ec6949SJoe Komlodi case R_IBI_QUEUE_DATA: 990*93ec6949SJoe Komlodi value = aspeed_i3c_device_ibi_queue_r(s); 991*93ec6949SJoe Komlodi break; 9923816bedaSJoe Komlodi case R_INTR_STATUS: 9933816bedaSJoe Komlodi value = aspeed_i3c_device_intr_status_r(s); 9943816bedaSJoe Komlodi break; 9954ba25376SJoe Komlodi case R_RX_TX_DATA_PORT: 9964ba25376SJoe Komlodi value = aspeed_i3c_device_pop_rx(s); 9974ba25376SJoe Komlodi break; 9984ba25376SJoe Komlodi case R_RESPONSE_QUEUE_PORT: 9994ba25376SJoe Komlodi value = aspeed_i3c_device_resp_queue_port_r(s); 10004ba25376SJoe Komlodi break; 10017d87775fSJoe Komlodi default: 10027d87775fSJoe Komlodi value = s->regs[addr]; 10037d87775fSJoe Komlodi break; 10047d87775fSJoe Komlodi } 10057d87775fSJoe Komlodi 10067d87775fSJoe Komlodi trace_aspeed_i3c_device_read(s->id, offset, value); 10077d87775fSJoe Komlodi 10087d87775fSJoe Komlodi return value; 10097d87775fSJoe Komlodi } 10107d87775fSJoe Komlodi 10114ba25376SJoe Komlodi static void aspeed_i3c_device_resp_queue_push(AspeedI3CDevice *s, 10124ba25376SJoe Komlodi uint8_t err, uint8_t tid, 10134ba25376SJoe Komlodi uint8_t ccc_type, 10144ba25376SJoe Komlodi uint16_t data_len) 10154ba25376SJoe Komlodi { 10164ba25376SJoe Komlodi uint32_t val = 0; 10174ba25376SJoe Komlodi val = FIELD_DP32(val, RESPONSE_QUEUE_PORT, ERR_STATUS, err); 10184ba25376SJoe Komlodi val = FIELD_DP32(val, RESPONSE_QUEUE_PORT, TID, tid); 10194ba25376SJoe Komlodi val = FIELD_DP32(val, RESPONSE_QUEUE_PORT, CCCT, ccc_type); 10204ba25376SJoe Komlodi val = FIELD_DP32(val, RESPONSE_QUEUE_PORT, DL, data_len); 10214ba25376SJoe Komlodi if (!fifo32_is_full(&s->resp_queue)) { 10224ba25376SJoe Komlodi trace_aspeed_i3c_device_resp_queue_push(s->id, val); 10234ba25376SJoe Komlodi fifo32_push(&s->resp_queue, val); 10244ba25376SJoe Komlodi } 10254ba25376SJoe Komlodi 10264ba25376SJoe Komlodi ARRAY_FIELD_DP32(s->regs, QUEUE_STATUS_LEVEL, RESP_BUF_BLR, 10274ba25376SJoe Komlodi fifo32_num_used(&s->resp_queue)); 10284ba25376SJoe Komlodi /* Threshold is the register value + 1. */ 10294ba25376SJoe Komlodi uint8_t threshold = ARRAY_FIELD_EX32(s->regs, QUEUE_THLD_CTRL, 10304ba25376SJoe Komlodi RESP_BUF_THLD) + 1; 10314ba25376SJoe Komlodi if (fifo32_num_used(&s->resp_queue) >= threshold) { 10324ba25376SJoe Komlodi ARRAY_FIELD_DP32(s->regs, INTR_STATUS, RESP_RDY, 1); 10334ba25376SJoe Komlodi aspeed_i3c_device_update_irq(s); 10344ba25376SJoe Komlodi } 10354ba25376SJoe Komlodi } 10364ba25376SJoe Komlodi 10374ba25376SJoe Komlodi static void aspeed_i3c_device_push_tx(AspeedI3CDevice *s, uint32_t val) 10384ba25376SJoe Komlodi { 10394ba25376SJoe Komlodi if (fifo32_is_full(&s->tx_queue)) { 10404ba25376SJoe Komlodi qemu_log_mask(LOG_GUEST_ERROR, "%s: Tried to push to TX FIFO when " 10414ba25376SJoe Komlodi "full\n", object_get_canonical_path(OBJECT(s))); 10424ba25376SJoe Komlodi return; 10434ba25376SJoe Komlodi } 10444ba25376SJoe Komlodi 10454ba25376SJoe Komlodi trace_aspeed_i3c_device_push_tx(s->id, val); 10464ba25376SJoe Komlodi fifo32_push(&s->tx_queue, val); 10474ba25376SJoe Komlodi ARRAY_FIELD_DP32(s->regs, DATA_BUFFER_STATUS_LEVEL, TX_BUF_EMPTY_LOC, 10484ba25376SJoe Komlodi fifo32_num_free(&s->tx_queue)); 10494ba25376SJoe Komlodi 10504ba25376SJoe Komlodi /* Threshold is 2^TX_BUF_THLD. */ 10514ba25376SJoe Komlodi uint8_t empty_threshold = ARRAY_FIELD_EX32(s->regs, DATA_BUFFER_THLD_CTRL, 10524ba25376SJoe Komlodi TX_BUF_THLD); 10534ba25376SJoe Komlodi empty_threshold = 10544ba25376SJoe Komlodi aspeed_i3c_device_fifo_threshold_from_reg(empty_threshold); 10554ba25376SJoe Komlodi if (fifo32_num_free(&s->tx_queue) < empty_threshold) { 10564ba25376SJoe Komlodi ARRAY_FIELD_DP32(s->regs, INTR_STATUS, TX_THLD, 0); 10574ba25376SJoe Komlodi aspeed_i3c_device_update_irq(s); 10584ba25376SJoe Komlodi } 10594ba25376SJoe Komlodi } 10604ba25376SJoe Komlodi 10614ba25376SJoe Komlodi static uint32_t aspeed_i3c_device_pop_tx(AspeedI3CDevice *s) 10624ba25376SJoe Komlodi { 10634ba25376SJoe Komlodi if (fifo32_is_empty(&s->tx_queue)) { 10644ba25376SJoe Komlodi qemu_log_mask(LOG_GUEST_ERROR, "%s: Tried to pop from TX FIFO when " 10654ba25376SJoe Komlodi "empty\n", object_get_canonical_path(OBJECT(s))); 10664ba25376SJoe Komlodi return 0; 10674ba25376SJoe Komlodi } 10684ba25376SJoe Komlodi 10694ba25376SJoe Komlodi uint32_t val = fifo32_pop(&s->tx_queue); 10704ba25376SJoe Komlodi trace_aspeed_i3c_device_pop_tx(s->id, val); 10714ba25376SJoe Komlodi ARRAY_FIELD_DP32(s->regs, DATA_BUFFER_STATUS_LEVEL, TX_BUF_EMPTY_LOC, 10724ba25376SJoe Komlodi fifo32_num_free(&s->tx_queue)); 10734ba25376SJoe Komlodi 10744ba25376SJoe Komlodi /* Threshold is 2^TX_BUF_THLD. */ 10754ba25376SJoe Komlodi uint8_t empty_threshold = ARRAY_FIELD_EX32(s->regs, DATA_BUFFER_THLD_CTRL, 10764ba25376SJoe Komlodi TX_BUF_THLD); 10774ba25376SJoe Komlodi empty_threshold = 10784ba25376SJoe Komlodi aspeed_i3c_device_fifo_threshold_from_reg(empty_threshold); 10794ba25376SJoe Komlodi if (fifo32_num_free(&s->tx_queue) >= empty_threshold) { 10804ba25376SJoe Komlodi ARRAY_FIELD_DP32(s->regs, INTR_STATUS, TX_THLD, 1); 10814ba25376SJoe Komlodi aspeed_i3c_device_update_irq(s); 10824ba25376SJoe Komlodi } 10834ba25376SJoe Komlodi return val; 10844ba25376SJoe Komlodi } 10854ba25376SJoe Komlodi 10864ba25376SJoe Komlodi static void aspeed_i3c_device_push_rx(AspeedI3CDevice *s, uint32_t val) 10874ba25376SJoe Komlodi { 10884ba25376SJoe Komlodi if (fifo32_is_full(&s->rx_queue)) { 10894ba25376SJoe Komlodi qemu_log_mask(LOG_GUEST_ERROR, "%s: Tried to push to RX FIFO when " 10904ba25376SJoe Komlodi "full\n", object_get_canonical_path(OBJECT(s))); 10914ba25376SJoe Komlodi return; 10924ba25376SJoe Komlodi } 10934ba25376SJoe Komlodi trace_aspeed_i3c_device_push_rx(s->id, val); 10944ba25376SJoe Komlodi fifo32_push(&s->rx_queue, val); 10954ba25376SJoe Komlodi 10964ba25376SJoe Komlodi ARRAY_FIELD_DP32(s->regs, DATA_BUFFER_STATUS_LEVEL, RX_BUF_BLR, 10974ba25376SJoe Komlodi fifo32_num_used(&s->rx_queue)); 10984ba25376SJoe Komlodi /* Threshold is 2^RX_BUF_THLD. */ 10994ba25376SJoe Komlodi uint8_t threshold = ARRAY_FIELD_EX32(s->regs, DATA_BUFFER_THLD_CTRL, 11004ba25376SJoe Komlodi RX_BUF_THLD); 11014ba25376SJoe Komlodi threshold = aspeed_i3c_device_fifo_threshold_from_reg(threshold); 11024ba25376SJoe Komlodi if (fifo32_num_used(&s->rx_queue) >= threshold) { 11034ba25376SJoe Komlodi ARRAY_FIELD_DP32(s->regs, INTR_STATUS, RX_THLD, 1); 11044ba25376SJoe Komlodi aspeed_i3c_device_update_irq(s); 11054ba25376SJoe Komlodi } 11064ba25376SJoe Komlodi } 11074ba25376SJoe Komlodi 11084ba25376SJoe Komlodi static void aspeed_i3c_device_short_transfer(AspeedI3CDevice *s, 11094ba25376SJoe Komlodi AspeedI3CTransferCmd cmd, 11104ba25376SJoe Komlodi AspeedI3CShortArg arg) 11114ba25376SJoe Komlodi { 11124ba25376SJoe Komlodi uint8_t err = ASPEED_I3C_RESP_QUEUE_ERR_NONE; 11134ba25376SJoe Komlodi uint8_t addr = aspeed_i3c_device_target_addr(s, cmd.dev_index); 11144ba25376SJoe Komlodi bool is_i2c = aspeed_i3c_device_target_is_i2c(s, cmd.dev_index); 11154ba25376SJoe Komlodi uint8_t data[4]; /* Max we can send on a short transfer is 4 bytes. */ 11164ba25376SJoe Komlodi uint8_t len = 0; 11174ba25376SJoe Komlodi uint32_t bytes_sent; /* Ignored on short transfers. */ 11184ba25376SJoe Komlodi 11194ba25376SJoe Komlodi /* Can't do reads on a short transfer. */ 11204ba25376SJoe Komlodi if (cmd.rnw) { 11214ba25376SJoe Komlodi qemu_log_mask(LOG_GUEST_ERROR, "%s: Cannot do a read on a short " 11224ba25376SJoe Komlodi "transfer\n", object_get_canonical_path(OBJECT(s))); 11234ba25376SJoe Komlodi return; 11244ba25376SJoe Komlodi } 11254ba25376SJoe Komlodi 11264ba25376SJoe Komlodi if (aspeed_i3c_device_send_start(s, addr, /*is_recv=*/false, is_i2c)) { 11274ba25376SJoe Komlodi err = ASPEED_I3C_RESP_QUEUE_ERR_I2C_NACK; 11284ba25376SJoe Komlodi goto transfer_done; 11294ba25376SJoe Komlodi } 11304ba25376SJoe Komlodi 11314ba25376SJoe Komlodi /* Are we sending a command? */ 11324ba25376SJoe Komlodi if (cmd.cp) { 11334ba25376SJoe Komlodi data[len] = cmd.cmd; 11344ba25376SJoe Komlodi len++; 11354ba25376SJoe Komlodi /* 11364ba25376SJoe Komlodi * byte0 is the defining byte for a command, and is only sent if a 11374ba25376SJoe Komlodi * command is present and if the command has a defining byte present. 11384ba25376SJoe Komlodi * (byte_strb & 0x01) is always treated as set by the controller, and is 11394ba25376SJoe Komlodi * ignored. 11404ba25376SJoe Komlodi */ 11414ba25376SJoe Komlodi if (cmd.dbp) { 11424ba25376SJoe Komlodi data[len] += arg.byte0; 11434ba25376SJoe Komlodi len++; 11444ba25376SJoe Komlodi } 11454ba25376SJoe Komlodi } 11464ba25376SJoe Komlodi 11474ba25376SJoe Komlodi /* Send the bytes passed in the argument. */ 11484ba25376SJoe Komlodi if (arg.byte_strb & 0x02) { 11494ba25376SJoe Komlodi data[len] = arg.byte1; 11504ba25376SJoe Komlodi len++; 11514ba25376SJoe Komlodi } 11524ba25376SJoe Komlodi if (arg.byte_strb & 0x04) { 11534ba25376SJoe Komlodi data[len] = arg.byte2; 11544ba25376SJoe Komlodi len++; 11554ba25376SJoe Komlodi } 11564ba25376SJoe Komlodi 11574ba25376SJoe Komlodi if (aspeed_i3c_device_send(s, data, len, &bytes_sent, is_i2c)) { 11584ba25376SJoe Komlodi err = ASPEED_I3C_RESP_QUEUE_ERR_I2C_NACK; 11594ba25376SJoe Komlodi } else { 11604ba25376SJoe Komlodi /* Only go to an idle state on a successful transfer. */ 11614ba25376SJoe Komlodi ARRAY_FIELD_DP32(s->regs, PRESENT_STATE, CM_TFR_ST_STATUS, 11624ba25376SJoe Komlodi ASPEED_I3C_TRANSFER_STATE_IDLE); 11634ba25376SJoe Komlodi } 11644ba25376SJoe Komlodi 11654ba25376SJoe Komlodi transfer_done: 11664ba25376SJoe Komlodi if (cmd.toc) { 11674ba25376SJoe Komlodi aspeed_i3c_device_end_transfer(s, is_i2c); 11684ba25376SJoe Komlodi } 11694ba25376SJoe Komlodi if (cmd.roc) { 11704ba25376SJoe Komlodi /* 11714ba25376SJoe Komlodi * ccc_type is always 0 in controller mode, data_len is 0 in short 11724ba25376SJoe Komlodi * transfers. 11734ba25376SJoe Komlodi */ 11744ba25376SJoe Komlodi aspeed_i3c_device_resp_queue_push(s, err, cmd.tid, /*ccc_type=*/0, 11754ba25376SJoe Komlodi /*data_len=*/0); 11764ba25376SJoe Komlodi } 11774ba25376SJoe Komlodi } 11784ba25376SJoe Komlodi 11794ba25376SJoe Komlodi /* Returns number of bytes transmitted. */ 11804ba25376SJoe Komlodi static uint16_t aspeed_i3c_device_tx(AspeedI3CDevice *s, uint16_t num, 11814ba25376SJoe Komlodi bool is_i2c) 11824ba25376SJoe Komlodi { 11834ba25376SJoe Komlodi uint16_t bytes_sent = 0; 11844ba25376SJoe Komlodi union { 11854ba25376SJoe Komlodi uint8_t b[sizeof(uint32_t)]; 11864ba25376SJoe Komlodi uint32_t val; 11874ba25376SJoe Komlodi } val32; 11884ba25376SJoe Komlodi 11894ba25376SJoe Komlodi while (bytes_sent < num) { 11904ba25376SJoe Komlodi val32.val = aspeed_i3c_device_pop_tx(s); 11914ba25376SJoe Komlodi for (uint8_t i = 0; i < sizeof(val32.val); i++) { 11924ba25376SJoe Komlodi if (aspeed_i3c_device_send_byte(s, val32.b[i], is_i2c)) { 11934ba25376SJoe Komlodi return bytes_sent; 11944ba25376SJoe Komlodi } 11954ba25376SJoe Komlodi bytes_sent++; 11964ba25376SJoe Komlodi 11974ba25376SJoe Komlodi /* We're not sending the full 32-bits, break early. */ 11984ba25376SJoe Komlodi if (bytes_sent >= num) { 11994ba25376SJoe Komlodi break; 12004ba25376SJoe Komlodi } 12014ba25376SJoe Komlodi } 12024ba25376SJoe Komlodi } 12034ba25376SJoe Komlodi 12044ba25376SJoe Komlodi return bytes_sent; 12054ba25376SJoe Komlodi } 12064ba25376SJoe Komlodi 12074ba25376SJoe Komlodi /* Returns number of bytes received. */ 12084ba25376SJoe Komlodi static uint16_t aspeed_i3c_device_rx(AspeedI3CDevice *s, uint16_t num, 12094ba25376SJoe Komlodi bool is_i2c) 12104ba25376SJoe Komlodi { 12114ba25376SJoe Komlodi /* 12124ba25376SJoe Komlodi * Allocate a temporary buffer to read data from the target. 12134ba25376SJoe Komlodi * Zero it and word-align it as well in case we're reading unaligned data. 12144ba25376SJoe Komlodi */ 12154ba25376SJoe Komlodi g_autofree uint8_t *data = g_new0(uint8_t, num + (num & 0x03)); 12164ba25376SJoe Komlodi uint32_t *data32 = (uint32_t *)data; 12174ba25376SJoe Komlodi /* 12184ba25376SJoe Komlodi * 32-bits since the I3C API wants a 32-bit number, even though the 12194ba25376SJoe Komlodi * controller can only do 16-bit transfers. 12204ba25376SJoe Komlodi */ 12214ba25376SJoe Komlodi uint32_t num_read = 0; 12224ba25376SJoe Komlodi 12234ba25376SJoe Komlodi /* Can NACK if the target receives an unsupported CCC. */ 12244ba25376SJoe Komlodi if (aspeed_i3c_device_recv_data(s, is_i2c, data, num, &num_read)) { 12254ba25376SJoe Komlodi return 0; 12264ba25376SJoe Komlodi } 12274ba25376SJoe Komlodi 12284ba25376SJoe Komlodi for (uint16_t i = 0; i < num_read / 4; i++) { 12294ba25376SJoe Komlodi aspeed_i3c_device_push_rx(s, *data32); 12304ba25376SJoe Komlodi data32++; 12314ba25376SJoe Komlodi } 12324ba25376SJoe Komlodi /* 12334ba25376SJoe Komlodi * If we're pushing data that isn't 32-bit aligned, push what's left. 12344ba25376SJoe Komlodi * It's software's responsibility to know what bits are valid in the partial 12354ba25376SJoe Komlodi * data. 12364ba25376SJoe Komlodi */ 12374ba25376SJoe Komlodi if (num_read & 0x03) { 12384ba25376SJoe Komlodi aspeed_i3c_device_push_rx(s, *data32); 12394ba25376SJoe Komlodi } 12404ba25376SJoe Komlodi 12414ba25376SJoe Komlodi return num_read; 12424ba25376SJoe Komlodi } 12434ba25376SJoe Komlodi 12444ba25376SJoe Komlodi static int aspeed_i3c_device_transfer_ccc(AspeedI3CDevice *s, 12454ba25376SJoe Komlodi AspeedI3CTransferCmd cmd, 12464ba25376SJoe Komlodi AspeedI3CTransferArg arg) 12474ba25376SJoe Komlodi { 12484ba25376SJoe Komlodi /* CCC start is always a write. CCCs cannot be done on I2C devices. */ 12494ba25376SJoe Komlodi if (aspeed_i3c_device_send_start(s, I3C_BROADCAST, /*is_recv=*/false, 12504ba25376SJoe Komlodi /*is_i2c=*/false)) { 12514ba25376SJoe Komlodi return ASPEED_I3C_RESP_QUEUE_ERR_BROADCAST_NACK; 12524ba25376SJoe Komlodi } 12534ba25376SJoe Komlodi trace_aspeed_i3c_device_transfer_ccc(s->id, cmd.cmd); 12544ba25376SJoe Komlodi if (aspeed_i3c_device_send_byte(s, cmd.cmd, /*is_i2c=*/false)) { 12554ba25376SJoe Komlodi return ASPEED_I3C_RESP_QUEUE_ERR_I2C_NACK; 12564ba25376SJoe Komlodi } 12574ba25376SJoe Komlodi 12584ba25376SJoe Komlodi /* On a direct CCC, we do a restart and then send the target's address. */ 12594ba25376SJoe Komlodi if (CCC_IS_DIRECT(cmd.cmd)) { 12604ba25376SJoe Komlodi bool is_recv = cmd.rnw; 12614ba25376SJoe Komlodi uint8_t addr = aspeed_i3c_device_target_addr(s, cmd.dev_index); 12624ba25376SJoe Komlodi if (aspeed_i3c_device_send_start(s, addr, is_recv, /*is_i2c=*/false)) { 12634ba25376SJoe Komlodi return ASPEED_I3C_RESP_QUEUE_ERR_BROADCAST_NACK; 12644ba25376SJoe Komlodi } 12654ba25376SJoe Komlodi } 12664ba25376SJoe Komlodi 12674ba25376SJoe Komlodi return ASPEED_I3C_RESP_QUEUE_ERR_NONE; 12684ba25376SJoe Komlodi } 12694ba25376SJoe Komlodi 12704ba25376SJoe Komlodi static void aspeed_i3c_device_transfer(AspeedI3CDevice *s, 12714ba25376SJoe Komlodi AspeedI3CTransferCmd cmd, 12724ba25376SJoe Komlodi AspeedI3CTransferArg arg) 12734ba25376SJoe Komlodi { 12744ba25376SJoe Komlodi bool is_recv = cmd.rnw; 12754ba25376SJoe Komlodi uint8_t err = ASPEED_I3C_RESP_QUEUE_ERR_NONE; 12764ba25376SJoe Komlodi uint8_t addr = aspeed_i3c_device_target_addr(s, cmd.dev_index); 12774ba25376SJoe Komlodi bool is_i2c = aspeed_i3c_device_target_is_i2c(s, cmd.dev_index); 12784ba25376SJoe Komlodi uint16_t bytes_transferred = 0; 12794ba25376SJoe Komlodi 12804ba25376SJoe Komlodi if (cmd.cp) { 12814ba25376SJoe Komlodi /* We're sending a CCC. */ 12824ba25376SJoe Komlodi err = aspeed_i3c_device_transfer_ccc(s, cmd, arg); 12834ba25376SJoe Komlodi if (err != ASPEED_I3C_RESP_QUEUE_ERR_NONE) { 12844ba25376SJoe Komlodi goto transfer_done; 12854ba25376SJoe Komlodi } 12864ba25376SJoe Komlodi } else { 12874ba25376SJoe Komlodi if (ARRAY_FIELD_EX32(s->regs, DEVICE_CTRL, I3C_BROADCAST_ADDR_INC) && 12884ba25376SJoe Komlodi is_i2c == false) { 12894ba25376SJoe Komlodi if (aspeed_i3c_device_send_start(s, I3C_BROADCAST, 12904ba25376SJoe Komlodi /*is_recv=*/false, is_i2c)) { 12914ba25376SJoe Komlodi err = ASPEED_I3C_RESP_QUEUE_ERR_I2C_NACK; 12924ba25376SJoe Komlodi goto transfer_done; 12934ba25376SJoe Komlodi } 12944ba25376SJoe Komlodi } 12954ba25376SJoe Komlodi /* Otherwise we're doing a private transfer. */ 12964ba25376SJoe Komlodi if (aspeed_i3c_device_send_start(s, addr, is_recv, is_i2c)) { 12974ba25376SJoe Komlodi err = ASPEED_I3C_RESP_QUEUE_ERR_I2C_NACK; 12984ba25376SJoe Komlodi goto transfer_done; 12994ba25376SJoe Komlodi } 13004ba25376SJoe Komlodi } 13014ba25376SJoe Komlodi 13024ba25376SJoe Komlodi if (is_recv) { 13034ba25376SJoe Komlodi bytes_transferred = aspeed_i3c_device_rx(s, arg.data_len, is_i2c); 13044ba25376SJoe Komlodi } else { 13054ba25376SJoe Komlodi bytes_transferred = aspeed_i3c_device_tx(s, arg.data_len, is_i2c); 13064ba25376SJoe Komlodi } 13074ba25376SJoe Komlodi 13084ba25376SJoe Komlodi ARRAY_FIELD_DP32(s->regs, PRESENT_STATE, CM_TFR_ST_STATUS, 13094ba25376SJoe Komlodi ASPEED_I3C_TRANSFER_STATE_IDLE); 13104ba25376SJoe Komlodi 13114ba25376SJoe Komlodi transfer_done: 13124ba25376SJoe Komlodi if (cmd.toc) { 13134ba25376SJoe Komlodi aspeed_i3c_device_end_transfer(s, is_i2c); 13144ba25376SJoe Komlodi } 13154ba25376SJoe Komlodi if (cmd.roc) { 13164ba25376SJoe Komlodi /* 13174ba25376SJoe Komlodi * data_len is the number of bytes that still need to be TX'd, or the 13184ba25376SJoe Komlodi * number of bytes RX'd. 13194ba25376SJoe Komlodi */ 13204ba25376SJoe Komlodi uint16_t data_len = is_recv ? bytes_transferred : arg.data_len - 13214ba25376SJoe Komlodi bytes_transferred; 13224ba25376SJoe Komlodi /* CCCT is always 0 in controller mode. */ 13234ba25376SJoe Komlodi aspeed_i3c_device_resp_queue_push(s, err, cmd.tid, /*ccc_type=*/0, 13244ba25376SJoe Komlodi data_len); 13254ba25376SJoe Komlodi } 13264ba25376SJoe Komlodi 13274ba25376SJoe Komlodi aspeed_i3c_device_update_irq(s); 13284ba25376SJoe Komlodi } 13294ba25376SJoe Komlodi 13304ba25376SJoe Komlodi static void aspeed_i3c_device_transfer_cmd(AspeedI3CDevice *s, 13314ba25376SJoe Komlodi AspeedI3CTransferCmd cmd, 13324ba25376SJoe Komlodi AspeedI3CCmdQueueData arg) 13334ba25376SJoe Komlodi { 13344ba25376SJoe Komlodi uint8_t arg_attr = FIELD_EX32(arg.word, COMMAND_QUEUE_PORT, CMD_ATTR); 13354ba25376SJoe Komlodi 13364ba25376SJoe Komlodi ARRAY_FIELD_DP32(s->regs, PRESENT_STATE, CMD_TID, cmd.tid); 13374ba25376SJoe Komlodi 13384ba25376SJoe Komlodi /* User is trying to do HDR transfers, see if we can do them. */ 13394ba25376SJoe Komlodi if (cmd.speed == 0x06 && !aspeed_i3c_device_has_hdr_ddr(s)) { 13404ba25376SJoe Komlodi qemu_log_mask(LOG_GUEST_ERROR, "%s: HDR DDR is not supported\n", 13414ba25376SJoe Komlodi object_get_canonical_path(OBJECT(s))); 13424ba25376SJoe Komlodi ARRAY_FIELD_DP32(s->regs, PRESENT_STATE, CM_TFR_ST_STATUS, 13434ba25376SJoe Komlodi ASPEED_I3C_TRANSFER_STATE_HALT); 13444ba25376SJoe Komlodi return; 13454ba25376SJoe Komlodi } 13464ba25376SJoe Komlodi if (cmd.speed == 0x05 && !aspeed_i3c_device_has_hdr_ts(s)) { 13474ba25376SJoe Komlodi qemu_log_mask(LOG_GUEST_ERROR, "%s: HDR TS is not supported\n", 13484ba25376SJoe Komlodi object_get_canonical_path(OBJECT(s))); 13494ba25376SJoe Komlodi ARRAY_FIELD_DP32(s->regs, PRESENT_STATE, CM_TFR_ST_STATUS, 13504ba25376SJoe Komlodi ASPEED_I3C_TRANSFER_STATE_HALT); 13514ba25376SJoe Komlodi return; 13524ba25376SJoe Komlodi } 13534ba25376SJoe Komlodi 13544ba25376SJoe Komlodi if (arg_attr == ASPEED_I3C_CMD_ATTR_TRANSFER_ARG) { 13554ba25376SJoe Komlodi aspeed_i3c_device_transfer(s, cmd, arg.transfer_arg); 13564ba25376SJoe Komlodi } else if (arg_attr == ASPEED_I3C_CMD_ATTR_SHORT_DATA_ARG) { 13574ba25376SJoe Komlodi aspeed_i3c_device_short_transfer(s, cmd, arg.short_arg); 13584ba25376SJoe Komlodi } else { 13594ba25376SJoe Komlodi qemu_log_mask(LOG_GUEST_ERROR, "%s: Unknown command queue cmd_attr 0x%x" 13604ba25376SJoe Komlodi "\n", object_get_canonical_path(OBJECT(s)), arg_attr); 13614ba25376SJoe Komlodi ARRAY_FIELD_DP32(s->regs, PRESENT_STATE, CM_TFR_ST_STATUS, 13624ba25376SJoe Komlodi ASPEED_I3C_TRANSFER_STATE_HALT); 13634ba25376SJoe Komlodi } 13644ba25376SJoe Komlodi } 13654ba25376SJoe Komlodi 13664ba25376SJoe Komlodi static void aspeed_i3c_device_update_char_table(AspeedI3CDevice *s, 13674ba25376SJoe Komlodi uint8_t offset, uint64_t pid, 13684ba25376SJoe Komlodi uint8_t bcr, uint8_t dcr, 13694ba25376SJoe Komlodi uint8_t addr) 13704ba25376SJoe Komlodi { 13714ba25376SJoe Komlodi if (offset > ASPEED_I3C_NR_DEVICES) { 13724ba25376SJoe Komlodi qemu_log_mask(LOG_GUEST_ERROR, "%s: Device char table offset %d out of " 13734ba25376SJoe Komlodi "bounds\n", object_get_canonical_path(OBJECT(s)), offset); 13744ba25376SJoe Komlodi /* If we're out of bounds, do nothing. */ 13754ba25376SJoe Komlodi return; 13764ba25376SJoe Komlodi } 13774ba25376SJoe Komlodi 13784ba25376SJoe Komlodi /* Each char table index is 128 bits apart. */ 13794ba25376SJoe Komlodi uint16_t dev_index = R_DEVICE_CHARACTERISTIC_TABLE_LOC1 + offset * 13804ba25376SJoe Komlodi sizeof(uint32_t); 13814ba25376SJoe Komlodi s->regs[dev_index] = pid & 0xffffffff; 13824ba25376SJoe Komlodi pid >>= 32; 13834ba25376SJoe Komlodi s->regs[dev_index + 1] = FIELD_DP32(s->regs[dev_index + 1], 13844ba25376SJoe Komlodi DEVICE_CHARACTERISTIC_TABLE_LOC2, 13854ba25376SJoe Komlodi MSB_PID, pid); 13864ba25376SJoe Komlodi s->regs[dev_index + 2] = FIELD_DP32(s->regs[dev_index + 2], 13874ba25376SJoe Komlodi DEVICE_CHARACTERISTIC_TABLE_LOC3, DCR, 13884ba25376SJoe Komlodi dcr); 13894ba25376SJoe Komlodi s->regs[dev_index + 2] = FIELD_DP32(s->regs[dev_index + 2], 13904ba25376SJoe Komlodi DEVICE_CHARACTERISTIC_TABLE_LOC3, BCR, 13914ba25376SJoe Komlodi bcr); 13924ba25376SJoe Komlodi s->regs[dev_index + 3] = FIELD_DP32(s->regs[dev_index + 3], 13934ba25376SJoe Komlodi DEVICE_CHARACTERISTIC_TABLE_LOC4, 13944ba25376SJoe Komlodi DEV_DYNAMIC_ADDR, addr); 13954ba25376SJoe Komlodi 13964ba25376SJoe Komlodi /* Increment PRESENT_DEV_CHAR_TABLE_INDEX. */ 13974ba25376SJoe Komlodi uint8_t idx = ARRAY_FIELD_EX32(s->regs, DEV_CHAR_TABLE_POINTER, 13984ba25376SJoe Komlodi PRESENT_DEV_CHAR_TABLE_INDEX); 13994ba25376SJoe Komlodi /* Increment and rollover. */ 14004ba25376SJoe Komlodi idx++; 14014ba25376SJoe Komlodi if (idx >= ARRAY_FIELD_EX32(s->regs, DEV_CHAR_TABLE_POINTER, 14024ba25376SJoe Komlodi DEV_CHAR_TABLE_DEPTH) / 4) { 14034ba25376SJoe Komlodi idx = 0; 14044ba25376SJoe Komlodi } 14054ba25376SJoe Komlodi ARRAY_FIELD_DP32(s->regs, DEV_CHAR_TABLE_POINTER, 14064ba25376SJoe Komlodi PRESENT_DEV_CHAR_TABLE_INDEX, idx); 14074ba25376SJoe Komlodi } 14084ba25376SJoe Komlodi 14094ba25376SJoe Komlodi static void aspeed_i3c_device_addr_assign_cmd(AspeedI3CDevice *s, 14104ba25376SJoe Komlodi AspeedI3CAddrAssignCmd cmd) 14114ba25376SJoe Komlodi { 14124ba25376SJoe Komlodi uint8_t i = 0; 14134ba25376SJoe Komlodi uint8_t err = ASPEED_I3C_RESP_QUEUE_ERR_NONE; 14144ba25376SJoe Komlodi 14154ba25376SJoe Komlodi if (!aspeed_i3c_device_has_entdaa(s)) { 14164ba25376SJoe Komlodi qemu_log_mask(LOG_GUEST_ERROR, "%s: ENTDAA is not supported\n", 14174ba25376SJoe Komlodi object_get_canonical_path(OBJECT(s))); 14184ba25376SJoe Komlodi return; 14194ba25376SJoe Komlodi } 14204ba25376SJoe Komlodi 14214ba25376SJoe Komlodi /* Tell everyone to ENTDAA. If these error, no one is on the bus. */ 14224ba25376SJoe Komlodi if (aspeed_i3c_device_send_start(s, I3C_BROADCAST, /*is_recv=*/false, 14234ba25376SJoe Komlodi /*is_i2c=*/false)) { 14244ba25376SJoe Komlodi err = ASPEED_I3C_RESP_QUEUE_ERR_BROADCAST_NACK; 14254ba25376SJoe Komlodi goto transfer_done; 14264ba25376SJoe Komlodi } 14274ba25376SJoe Komlodi if (aspeed_i3c_device_send_byte(s, cmd.cmd, /*is_i2c=*/false)) { 14284ba25376SJoe Komlodi err = ASPEED_I3C_RESP_QUEUE_ERR_BROADCAST_NACK; 14294ba25376SJoe Komlodi goto transfer_done; 14304ba25376SJoe Komlodi } 14314ba25376SJoe Komlodi 14324ba25376SJoe Komlodi /* Go through each device in the table and assign it an address. */ 14334ba25376SJoe Komlodi for (i = 0; i < cmd.dev_count; i++) { 14344ba25376SJoe Komlodi uint8_t addr = aspeed_i3c_device_target_addr(s, cmd.dev_index + i); 14354ba25376SJoe Komlodi union { 14364ba25376SJoe Komlodi uint64_t pid:48; 14374ba25376SJoe Komlodi uint8_t bcr; 14384ba25376SJoe Komlodi uint8_t dcr; 14394ba25376SJoe Komlodi uint32_t w[2]; 14404ba25376SJoe Komlodi uint8_t b[8]; 14414ba25376SJoe Komlodi } target_info; 14424ba25376SJoe Komlodi 14434ba25376SJoe Komlodi /* If this fails, there was no one left to ENTDAA. */ 14444ba25376SJoe Komlodi if (aspeed_i3c_device_send_start(s, I3C_BROADCAST, /*is_recv=*/false, 14454ba25376SJoe Komlodi /*is_i2c=*/false)) { 14464ba25376SJoe Komlodi err = ASPEED_I3C_RESP_QUEUE_ERR_BROADCAST_NACK; 14474ba25376SJoe Komlodi break; 14484ba25376SJoe Komlodi } 14494ba25376SJoe Komlodi 14504ba25376SJoe Komlodi /* 14514ba25376SJoe Komlodi * In ENTDAA, we read 8 bytes from the target, which will be the 14524ba25376SJoe Komlodi * target's PID, BCR, and DCR. After that, we send it the dynamic 14534ba25376SJoe Komlodi * address. 14544ba25376SJoe Komlodi * Don't bother checking the number of bytes received, it must send 8 14554ba25376SJoe Komlodi * bytes during ENTDAA. 14564ba25376SJoe Komlodi */ 14574ba25376SJoe Komlodi uint32_t num_read; 14584ba25376SJoe Komlodi if (aspeed_i3c_device_recv_data(s, /*is_i2c=*/false, target_info.b, 14594ba25376SJoe Komlodi I3C_ENTDAA_SIZE, &num_read)) { 14604ba25376SJoe Komlodi qemu_log_mask(LOG_GUEST_ERROR, "%s: Target NACKed ENTDAA CCC\n", 14614ba25376SJoe Komlodi object_get_canonical_path(OBJECT(s))); 14624ba25376SJoe Komlodi err = ASPEED_I3C_RESP_QUEUE_ERR_DAA_NACK; 14634ba25376SJoe Komlodi goto transfer_done; 14644ba25376SJoe Komlodi } 14654ba25376SJoe Komlodi if (aspeed_i3c_device_send_byte(s, addr, /*is_i2c=*/false)) { 14664ba25376SJoe Komlodi qemu_log_mask(LOG_GUEST_ERROR, "%s: Target NACKed addr 0x%.2x " 14674ba25376SJoe Komlodi "during ENTDAA\n", 14684ba25376SJoe Komlodi object_get_canonical_path(OBJECT(s)), addr); 14694ba25376SJoe Komlodi err = ASPEED_I3C_RESP_QUEUE_ERR_DAA_NACK; 14704ba25376SJoe Komlodi break; 14714ba25376SJoe Komlodi } 14724ba25376SJoe Komlodi aspeed_i3c_device_update_char_table(s, cmd.dev_index + i, 14734ba25376SJoe Komlodi target_info.pid, target_info.bcr, 14744ba25376SJoe Komlodi target_info.dcr, addr); 14754ba25376SJoe Komlodi 14764ba25376SJoe Komlodi /* Push the PID, BCR, and DCR to the RX queue. */ 14774ba25376SJoe Komlodi aspeed_i3c_device_push_rx(s, target_info.w[0]); 14784ba25376SJoe Komlodi aspeed_i3c_device_push_rx(s, target_info.w[1]); 14794ba25376SJoe Komlodi } 14804ba25376SJoe Komlodi 14814ba25376SJoe Komlodi transfer_done: 14824ba25376SJoe Komlodi /* Do we send a STOP? */ 14834ba25376SJoe Komlodi if (cmd.toc) { 14844ba25376SJoe Komlodi aspeed_i3c_device_end_transfer(s, /*is_i2c=*/false); 14854ba25376SJoe Komlodi } 14864ba25376SJoe Komlodi /* 14874ba25376SJoe Komlodi * For addr assign commands, the length field is the number of devices 14884ba25376SJoe Komlodi * left to assign. CCCT is always 0 in controller mode. 14894ba25376SJoe Komlodi */ 14904ba25376SJoe Komlodi if (cmd.roc) { 14914ba25376SJoe Komlodi aspeed_i3c_device_resp_queue_push(s, err, cmd.tid, /*ccc_type=*/0, 14924ba25376SJoe Komlodi cmd.dev_count - i); 14934ba25376SJoe Komlodi } 14944ba25376SJoe Komlodi } 14954ba25376SJoe Komlodi 14964ba25376SJoe Komlodi static uint32_t aspeed_i3c_device_cmd_queue_pop(AspeedI3CDevice *s) 14974ba25376SJoe Komlodi { 14984ba25376SJoe Komlodi if (fifo32_is_empty(&s->cmd_queue)) { 14994ba25376SJoe Komlodi qemu_log_mask(LOG_GUEST_ERROR, "%s: Tried to dequeue command queue " 15004ba25376SJoe Komlodi "when it was empty\n", 15014ba25376SJoe Komlodi object_get_canonical_path(OBJECT(s))); 15024ba25376SJoe Komlodi return 0; 15034ba25376SJoe Komlodi } 15044ba25376SJoe Komlodi uint32_t val = fifo32_pop(&s->cmd_queue); 15054ba25376SJoe Komlodi 15064ba25376SJoe Komlodi uint8_t empty_threshold = ARRAY_FIELD_EX32(s->regs, QUEUE_THLD_CTRL, 15074ba25376SJoe Komlodi CMD_BUF_EMPTY_THLD); 15084ba25376SJoe Komlodi uint8_t cmd_queue_empty_loc = ARRAY_FIELD_EX32(s->regs, 15094ba25376SJoe Komlodi QUEUE_STATUS_LEVEL, 15104ba25376SJoe Komlodi CMD_QUEUE_EMPTY_LOC); 15114ba25376SJoe Komlodi cmd_queue_empty_loc++; 15124ba25376SJoe Komlodi ARRAY_FIELD_DP32(s->regs, QUEUE_STATUS_LEVEL, CMD_QUEUE_EMPTY_LOC, 15134ba25376SJoe Komlodi cmd_queue_empty_loc); 15144ba25376SJoe Komlodi if (cmd_queue_empty_loc >= empty_threshold) { 15154ba25376SJoe Komlodi ARRAY_FIELD_DP32(s->regs, INTR_STATUS, CMD_QUEUE_RDY, 1); 15164ba25376SJoe Komlodi aspeed_i3c_device_update_irq(s); 15174ba25376SJoe Komlodi } 15184ba25376SJoe Komlodi 15194ba25376SJoe Komlodi return val; 15204ba25376SJoe Komlodi } 15214ba25376SJoe Komlodi 15224ba25376SJoe Komlodi static void aspeed_i3c_device_cmd_queue_execute(AspeedI3CDevice *s) 15234ba25376SJoe Komlodi { 15244ba25376SJoe Komlodi ARRAY_FIELD_DP32(s->regs, PRESENT_STATE, CM_TFR_ST_STATUS, 15254ba25376SJoe Komlodi ASPEED_I3C_TRANSFER_STATE_IDLE); 15264ba25376SJoe Komlodi if (!aspeed_i3c_device_can_transmit(s)) { 15274ba25376SJoe Komlodi return; 15284ba25376SJoe Komlodi } 15294ba25376SJoe Komlodi 15304ba25376SJoe Komlodi /* 15314ba25376SJoe Komlodi * We only start executing when a command is passed into the FIFO. 15324ba25376SJoe Komlodi * We expect there to be a multiple of 2 items in the queue. The first item 15334ba25376SJoe Komlodi * should be an argument to a command, and the command should be the second 15344ba25376SJoe Komlodi * item. 15354ba25376SJoe Komlodi */ 15364ba25376SJoe Komlodi if (fifo32_num_used(&s->cmd_queue) & 1) { 15374ba25376SJoe Komlodi return; 15384ba25376SJoe Komlodi } 15394ba25376SJoe Komlodi 15404ba25376SJoe Komlodi while (!fifo32_is_empty(&s->cmd_queue)) { 15414ba25376SJoe Komlodi AspeedI3CCmdQueueData arg; 15424ba25376SJoe Komlodi arg.word = aspeed_i3c_device_cmd_queue_pop(s); 15434ba25376SJoe Komlodi AspeedI3CCmdQueueData cmd; 15444ba25376SJoe Komlodi cmd.word = aspeed_i3c_device_cmd_queue_pop(s); 15454ba25376SJoe Komlodi trace_aspeed_i3c_device_cmd_queue_execute(s->id, cmd.word, arg.word); 15464ba25376SJoe Komlodi 15474ba25376SJoe Komlodi uint8_t cmd_attr = FIELD_EX32(cmd.word, COMMAND_QUEUE_PORT, CMD_ATTR); 15484ba25376SJoe Komlodi switch (cmd_attr) { 15494ba25376SJoe Komlodi case ASPEED_I3C_CMD_ATTR_TRANSFER_CMD: 15504ba25376SJoe Komlodi aspeed_i3c_device_transfer_cmd(s, cmd.transfer_cmd, arg); 15514ba25376SJoe Komlodi break; 15524ba25376SJoe Komlodi case ASPEED_I3C_CMD_ATTR_ADDR_ASSIGN_CMD: 15534ba25376SJoe Komlodi /* Arg is discarded for addr assign commands. */ 15544ba25376SJoe Komlodi aspeed_i3c_device_addr_assign_cmd(s, cmd.addr_assign_cmd); 15554ba25376SJoe Komlodi break; 15564ba25376SJoe Komlodi case ASPEED_I3C_CMD_ATTR_TRANSFER_ARG: 15574ba25376SJoe Komlodi case ASPEED_I3C_CMD_ATTR_SHORT_DATA_ARG: 15584ba25376SJoe Komlodi qemu_log_mask(LOG_GUEST_ERROR, "%s: Command queue received argument" 15594ba25376SJoe Komlodi " packet when it expected a command packet\n", 15604ba25376SJoe Komlodi object_get_canonical_path(OBJECT(s))); 15614ba25376SJoe Komlodi break; 15624ba25376SJoe Komlodi default: 15634ba25376SJoe Komlodi /* 15644ba25376SJoe Komlodi * The caller's check before queueing an item should prevent this 15654ba25376SJoe Komlodi * from happening. 15664ba25376SJoe Komlodi */ 15674ba25376SJoe Komlodi g_assert_not_reached(); 15684ba25376SJoe Komlodi break; 15694ba25376SJoe Komlodi } 15704ba25376SJoe Komlodi } 15714ba25376SJoe Komlodi } 15724ba25376SJoe Komlodi 15734ba25376SJoe Komlodi static void aspeed_i3c_device_cmd_queue_push(AspeedI3CDevice *s, uint32_t val) 15744ba25376SJoe Komlodi { 15754ba25376SJoe Komlodi if (fifo32_is_full(&s->cmd_queue)) { 15764ba25376SJoe Komlodi qemu_log_mask(LOG_GUEST_ERROR, "%s: Command queue received packet when " 15774ba25376SJoe Komlodi "already full\n", object_get_canonical_path(OBJECT(s))); 15784ba25376SJoe Komlodi return; 15794ba25376SJoe Komlodi } 15804ba25376SJoe Komlodi trace_aspeed_i3c_device_cmd_queue_push(s->id, val); 15814ba25376SJoe Komlodi fifo32_push(&s->cmd_queue, val); 15824ba25376SJoe Komlodi 15834ba25376SJoe Komlodi uint8_t empty_threshold = ARRAY_FIELD_EX32(s->regs, QUEUE_THLD_CTRL, 15844ba25376SJoe Komlodi CMD_BUF_EMPTY_THLD); 15854ba25376SJoe Komlodi uint8_t cmd_queue_empty_loc = ARRAY_FIELD_EX32(s->regs, 15864ba25376SJoe Komlodi QUEUE_STATUS_LEVEL, 15874ba25376SJoe Komlodi CMD_QUEUE_EMPTY_LOC); 15884ba25376SJoe Komlodi if (cmd_queue_empty_loc) { 15894ba25376SJoe Komlodi cmd_queue_empty_loc--; 15904ba25376SJoe Komlodi ARRAY_FIELD_DP32(s->regs, QUEUE_STATUS_LEVEL, CMD_QUEUE_EMPTY_LOC, 15914ba25376SJoe Komlodi cmd_queue_empty_loc); 15924ba25376SJoe Komlodi } 15934ba25376SJoe Komlodi if (cmd_queue_empty_loc < empty_threshold) { 15944ba25376SJoe Komlodi ARRAY_FIELD_DP32(s->regs, INTR_STATUS, CMD_QUEUE_RDY, 0); 15954ba25376SJoe Komlodi aspeed_i3c_device_update_irq(s); 15964ba25376SJoe Komlodi } 15974ba25376SJoe Komlodi } 15984ba25376SJoe Komlodi 15994ba25376SJoe Komlodi static void aspeed_i3c_device_cmd_queue_port_w(AspeedI3CDevice *s, uint32_t val) 16004ba25376SJoe Komlodi { 16014ba25376SJoe Komlodi uint8_t cmd_attr = FIELD_EX32(val, COMMAND_QUEUE_PORT, CMD_ATTR); 16024ba25376SJoe Komlodi 16034ba25376SJoe Komlodi switch (cmd_attr) { 16044ba25376SJoe Komlodi /* If a command is received we can start executing it. */ 16054ba25376SJoe Komlodi case ASPEED_I3C_CMD_ATTR_TRANSFER_CMD: 16064ba25376SJoe Komlodi case ASPEED_I3C_CMD_ATTR_ADDR_ASSIGN_CMD: 16074ba25376SJoe Komlodi aspeed_i3c_device_cmd_queue_push(s, val); 16084ba25376SJoe Komlodi aspeed_i3c_device_cmd_queue_execute(s); 16094ba25376SJoe Komlodi break; 16104ba25376SJoe Komlodi /* If we get an argument just push it. */ 16114ba25376SJoe Komlodi case ASPEED_I3C_CMD_ATTR_TRANSFER_ARG: 16124ba25376SJoe Komlodi case ASPEED_I3C_CMD_ATTR_SHORT_DATA_ARG: 16134ba25376SJoe Komlodi aspeed_i3c_device_cmd_queue_push(s, val); 16144ba25376SJoe Komlodi break; 16154ba25376SJoe Komlodi default: 16164ba25376SJoe Komlodi qemu_log_mask(LOG_GUEST_ERROR, "%s: Command queue received packet with " 16174ba25376SJoe Komlodi "unknown cmd attr 0x%x\n", 16184ba25376SJoe Komlodi object_get_canonical_path(OBJECT(s)), cmd_attr); 16194ba25376SJoe Komlodi break; 16204ba25376SJoe Komlodi } 16214ba25376SJoe Komlodi } 16224ba25376SJoe Komlodi 16237d87775fSJoe Komlodi static void aspeed_i3c_device_write(void *opaque, hwaddr offset, 16247d87775fSJoe Komlodi uint64_t value, unsigned size) 16257d87775fSJoe Komlodi { 16267d87775fSJoe Komlodi AspeedI3CDevice *s = ASPEED_I3C_DEVICE(opaque); 16277d87775fSJoe Komlodi uint32_t addr = offset >> 2; 162897fb7498SJoe Komlodi uint32_t val32 = (uint32_t)value; 16297d87775fSJoe Komlodi 16307d87775fSJoe Komlodi trace_aspeed_i3c_device_write(s->id, offset, value); 16317d87775fSJoe Komlodi 163297fb7498SJoe Komlodi val32 &= ~ast2600_i3c_device_ro[addr]; 16337d87775fSJoe Komlodi switch (addr) { 16347d87775fSJoe Komlodi case R_HW_CAPABILITY: 16357d87775fSJoe Komlodi case R_RESPONSE_QUEUE_PORT: 16367d87775fSJoe Komlodi case R_IBI_QUEUE_DATA: 16377d87775fSJoe Komlodi case R_QUEUE_STATUS_LEVEL: 16387d87775fSJoe Komlodi case R_PRESENT_STATE: 16397d87775fSJoe Komlodi case R_CCC_DEVICE_STATUS: 16407d87775fSJoe Komlodi case R_DEVICE_ADDR_TABLE_POINTER: 16417d87775fSJoe Komlodi case R_VENDOR_SPECIFIC_REG_POINTER: 16427d87775fSJoe Komlodi case R_SLV_CHAR_CTRL: 16437d87775fSJoe Komlodi case R_SLV_MAX_LEN: 16447d87775fSJoe Komlodi case R_MAX_READ_TURNAROUND: 16457d87775fSJoe Komlodi case R_I3C_VER_ID: 16467d87775fSJoe Komlodi case R_I3C_VER_TYPE: 16477d87775fSJoe Komlodi case R_EXTENDED_CAPABILITY: 16487d87775fSJoe Komlodi qemu_log_mask(LOG_GUEST_ERROR, 16497d87775fSJoe Komlodi "%s: write to readonly register[0x%02" HWADDR_PRIx 16507d87775fSJoe Komlodi "] = 0x%08" PRIx64 "\n", 16517d87775fSJoe Komlodi __func__, offset, value); 16527d87775fSJoe Komlodi break; 16537d87775fSJoe Komlodi case R_RX_TX_DATA_PORT: 16544ba25376SJoe Komlodi aspeed_i3c_device_push_tx(s, val32); 16554ba25376SJoe Komlodi break; 16564ba25376SJoe Komlodi case R_COMMAND_QUEUE_PORT: 16574ba25376SJoe Komlodi aspeed_i3c_device_cmd_queue_port_w(s, val32); 16587d87775fSJoe Komlodi break; 16597d87775fSJoe Komlodi case R_RESET_CTRL: 16607d87775fSJoe Komlodi break; 16613816bedaSJoe Komlodi case R_INTR_STATUS: 16623816bedaSJoe Komlodi aspeed_i3c_device_intr_status_w(s, val32); 16633816bedaSJoe Komlodi break; 16643816bedaSJoe Komlodi case R_INTR_STATUS_EN: 16653816bedaSJoe Komlodi aspeed_i3c_device_intr_status_en_w(s, val32); 16663816bedaSJoe Komlodi break; 16673816bedaSJoe Komlodi case R_INTR_SIGNAL_EN: 16683816bedaSJoe Komlodi aspeed_i3c_device_intr_signal_en_w(s, val32); 16693816bedaSJoe Komlodi break; 16703816bedaSJoe Komlodi case R_INTR_FORCE: 16713816bedaSJoe Komlodi aspeed_i3c_device_intr_force_w(s, val32); 16723816bedaSJoe Komlodi break; 16737d87775fSJoe Komlodi default: 167497fb7498SJoe Komlodi s->regs[addr] = val32; 16757d87775fSJoe Komlodi break; 16767d87775fSJoe Komlodi } 16777d87775fSJoe Komlodi } 16787d87775fSJoe Komlodi 16797d87775fSJoe Komlodi static const VMStateDescription aspeed_i3c_device_vmstate = { 16807d87775fSJoe Komlodi .name = TYPE_ASPEED_I3C, 16817d87775fSJoe Komlodi .version_id = 1, 16827d87775fSJoe Komlodi .minimum_version_id = 1, 16837d87775fSJoe Komlodi .fields = (const VMStateField[]){ 16847d87775fSJoe Komlodi VMSTATE_UINT32_ARRAY(regs, AspeedI3CDevice, ASPEED_I3C_DEVICE_NR_REGS), 16857d87775fSJoe Komlodi VMSTATE_END_OF_LIST(), 16867d87775fSJoe Komlodi } 16877d87775fSJoe Komlodi }; 16887d87775fSJoe Komlodi 16897d87775fSJoe Komlodi static const MemoryRegionOps aspeed_i3c_device_ops = { 16907d87775fSJoe Komlodi .read = aspeed_i3c_device_read, 16917d87775fSJoe Komlodi .write = aspeed_i3c_device_write, 16927d87775fSJoe Komlodi .endianness = DEVICE_LITTLE_ENDIAN, 16937d87775fSJoe Komlodi }; 16947d87775fSJoe Komlodi 16957d87775fSJoe Komlodi static void aspeed_i3c_device_reset(DeviceState *dev) 16967d87775fSJoe Komlodi { 16977d87775fSJoe Komlodi AspeedI3CDevice *s = ASPEED_I3C_DEVICE(dev); 16987d87775fSJoe Komlodi 16997d87775fSJoe Komlodi memcpy(s->regs, ast2600_i3c_device_resets, sizeof(s->regs)); 17007d87775fSJoe Komlodi } 17017d87775fSJoe Komlodi 17027d87775fSJoe Komlodi static void aspeed_i3c_device_realize(DeviceState *dev, Error **errp) 17037d87775fSJoe Komlodi { 17047d87775fSJoe Komlodi AspeedI3CDevice *s = ASPEED_I3C_DEVICE(dev); 17057d87775fSJoe Komlodi g_autofree char *name = g_strdup_printf(TYPE_ASPEED_I3C_DEVICE ".%d", 17067d87775fSJoe Komlodi s->id); 17077d87775fSJoe Komlodi 17087d87775fSJoe Komlodi sysbus_init_irq(SYS_BUS_DEVICE(dev), &s->irq); 17097d87775fSJoe Komlodi 17107d87775fSJoe Komlodi memory_region_init_io(&s->mr, OBJECT(s), &aspeed_i3c_device_ops, 17117d87775fSJoe Komlodi s, name, ASPEED_I3C_DEVICE_NR_REGS << 2); 17124ba25376SJoe Komlodi 17134ba25376SJoe Komlodi fifo32_create(&s->cmd_queue, ASPEED_I3C_CMD_QUEUE_CAPACITY); 17144ba25376SJoe Komlodi fifo32_create(&s->resp_queue, ASPEED_I3C_RESP_QUEUE_CAPACITY); 17154ba25376SJoe Komlodi fifo32_create(&s->tx_queue, ASPEED_I3C_TX_QUEUE_CAPACITY); 17164ba25376SJoe Komlodi fifo32_create(&s->rx_queue, ASPEED_I3C_RX_QUEUE_CAPACITY); 1717*93ec6949SJoe Komlodi fifo32_create(&s->ibi_queue, ASPEED_I3C_IBI_QUEUE_CAPACITY); 1718*93ec6949SJoe Komlodi /* Arbitrarily large enough to not be an issue. */ 1719*93ec6949SJoe Komlodi fifo8_create(&s->ibi_data.ibi_intermediate_queue, 1720*93ec6949SJoe Komlodi ASPEED_I3C_IBI_QUEUE_CAPACITY * 8); 17214ba25376SJoe Komlodi 17224ba25376SJoe Komlodi s->bus = i3c_init_bus(DEVICE(s), name); 1723*93ec6949SJoe Komlodi I3CBusClass *bc = I3C_BUS_GET_CLASS(s->bus); 1724*93ec6949SJoe Komlodi bc->ibi_handle = aspeed_i3c_device_ibi_handle; 1725*93ec6949SJoe Komlodi bc->ibi_recv = aspeed_i3c_device_ibi_recv; 1726*93ec6949SJoe Komlodi bc->ibi_finish = aspeed_i3c_device_ibi_finish; 17277d87775fSJoe Komlodi } 17287d87775fSJoe Komlodi 17297d87775fSJoe Komlodi static uint64_t aspeed_i3c_read(void *opaque, hwaddr addr, unsigned int size) 17307d87775fSJoe Komlodi { 17317d87775fSJoe Komlodi AspeedI3CState *s = ASPEED_I3C(opaque); 17327d87775fSJoe Komlodi uint64_t val = 0; 17337d87775fSJoe Komlodi 17347d87775fSJoe Komlodi val = s->regs[addr >> 2]; 17357d87775fSJoe Komlodi 17367d87775fSJoe Komlodi trace_aspeed_i3c_read(addr, val); 17377d87775fSJoe Komlodi 17387d87775fSJoe Komlodi return val; 17397d87775fSJoe Komlodi } 17407d87775fSJoe Komlodi 17417d87775fSJoe Komlodi static void aspeed_i3c_write(void *opaque, 17427d87775fSJoe Komlodi hwaddr addr, 17437d87775fSJoe Komlodi uint64_t data, 17447d87775fSJoe Komlodi unsigned int size) 17457d87775fSJoe Komlodi { 17467d87775fSJoe Komlodi AspeedI3CState *s = ASPEED_I3C(opaque); 17477d87775fSJoe Komlodi 17487d87775fSJoe Komlodi trace_aspeed_i3c_write(addr, data); 17497d87775fSJoe Komlodi 17507d87775fSJoe Komlodi addr >>= 2; 17517d87775fSJoe Komlodi 1752a9d3f922SJoe Komlodi data &= ~ast2600_i3c_controller_ro[addr]; 17537d87775fSJoe Komlodi /* I3C controller register */ 17547d87775fSJoe Komlodi switch (addr) { 17557d87775fSJoe Komlodi case R_I3C1_REG1: 17567d87775fSJoe Komlodi case R_I3C2_REG1: 17577d87775fSJoe Komlodi case R_I3C3_REG1: 17587d87775fSJoe Komlodi case R_I3C4_REG1: 17597d87775fSJoe Komlodi case R_I3C5_REG1: 17607d87775fSJoe Komlodi case R_I3C6_REG1: 17617d87775fSJoe Komlodi if (data & R_I3C1_REG1_I2C_MODE_MASK) { 17627d87775fSJoe Komlodi qemu_log_mask(LOG_UNIMP, 17637d87775fSJoe Komlodi "%s: Unsupported I2C mode [0x%08" HWADDR_PRIx 17647d87775fSJoe Komlodi "]=%08" PRIx64 "\n", 17657d87775fSJoe Komlodi __func__, addr << 2, data); 17667d87775fSJoe Komlodi break; 17677d87775fSJoe Komlodi } 17687d87775fSJoe Komlodi if (data & R_I3C1_REG1_SA_EN_MASK) { 17697d87775fSJoe Komlodi qemu_log_mask(LOG_UNIMP, 17707d87775fSJoe Komlodi "%s: Unsupported slave mode [%08" HWADDR_PRIx 17717d87775fSJoe Komlodi "]=0x%08" PRIx64 "\n", 17727d87775fSJoe Komlodi __func__, addr << 2, data); 17737d87775fSJoe Komlodi break; 17747d87775fSJoe Komlodi } 17757d87775fSJoe Komlodi s->regs[addr] = data; 17767d87775fSJoe Komlodi break; 17777d87775fSJoe Komlodi default: 17787d87775fSJoe Komlodi s->regs[addr] = data; 17797d87775fSJoe Komlodi break; 17807d87775fSJoe Komlodi } 17817d87775fSJoe Komlodi } 17827d87775fSJoe Komlodi 17837d87775fSJoe Komlodi static const MemoryRegionOps aspeed_i3c_ops = { 17847d87775fSJoe Komlodi .read = aspeed_i3c_read, 17857d87775fSJoe Komlodi .write = aspeed_i3c_write, 17867d87775fSJoe Komlodi .endianness = DEVICE_LITTLE_ENDIAN, 17877d87775fSJoe Komlodi .valid = { 17887d87775fSJoe Komlodi .min_access_size = 1, 17897d87775fSJoe Komlodi .max_access_size = 4, 17907d87775fSJoe Komlodi } 17917d87775fSJoe Komlodi }; 17927d87775fSJoe Komlodi 17937d87775fSJoe Komlodi static void aspeed_i3c_reset(DeviceState *dev) 17947d87775fSJoe Komlodi { 17957d87775fSJoe Komlodi AspeedI3CState *s = ASPEED_I3C(dev); 17967d87775fSJoe Komlodi memset(s->regs, 0, sizeof(s->regs)); 17977d87775fSJoe Komlodi } 17987d87775fSJoe Komlodi 17997d87775fSJoe Komlodi static void aspeed_i3c_instance_init(Object *obj) 18007d87775fSJoe Komlodi { 18017d87775fSJoe Komlodi AspeedI3CState *s = ASPEED_I3C(obj); 18027d87775fSJoe Komlodi int i; 18037d87775fSJoe Komlodi 18047d87775fSJoe Komlodi for (i = 0; i < ASPEED_I3C_NR_DEVICES; ++i) { 18057d87775fSJoe Komlodi object_initialize_child(obj, "device[*]", &s->devices[i], 18067d87775fSJoe Komlodi TYPE_ASPEED_I3C_DEVICE); 18077d87775fSJoe Komlodi } 18087d87775fSJoe Komlodi } 18097d87775fSJoe Komlodi 18107d87775fSJoe Komlodi static void aspeed_i3c_realize(DeviceState *dev, Error **errp) 18117d87775fSJoe Komlodi { 18127d87775fSJoe Komlodi int i; 18137d87775fSJoe Komlodi AspeedI3CState *s = ASPEED_I3C(dev); 18147d87775fSJoe Komlodi SysBusDevice *sbd = SYS_BUS_DEVICE(dev); 18157d87775fSJoe Komlodi 18167d87775fSJoe Komlodi memory_region_init(&s->iomem_container, OBJECT(s), 18177d87775fSJoe Komlodi TYPE_ASPEED_I3C ".container", 0x8000); 18187d87775fSJoe Komlodi 18197d87775fSJoe Komlodi sysbus_init_mmio(sbd, &s->iomem_container); 18207d87775fSJoe Komlodi 18217d87775fSJoe Komlodi memory_region_init_io(&s->iomem, OBJECT(s), &aspeed_i3c_ops, s, 18227d87775fSJoe Komlodi TYPE_ASPEED_I3C ".regs", ASPEED_I3C_NR_REGS << 2); 18237d87775fSJoe Komlodi 18247d87775fSJoe Komlodi memory_region_add_subregion(&s->iomem_container, 0x0, &s->iomem); 18257d87775fSJoe Komlodi 18267d87775fSJoe Komlodi for (i = 0; i < ASPEED_I3C_NR_DEVICES; ++i) { 18277d87775fSJoe Komlodi Object *i3c_dev = OBJECT(&s->devices[i]); 18287d87775fSJoe Komlodi 18297d87775fSJoe Komlodi if (!object_property_set_uint(i3c_dev, "device-id", i, errp)) { 18307d87775fSJoe Komlodi return; 18317d87775fSJoe Komlodi } 18327d87775fSJoe Komlodi 18337d87775fSJoe Komlodi if (!sysbus_realize(SYS_BUS_DEVICE(i3c_dev), errp)) { 18347d87775fSJoe Komlodi return; 18357d87775fSJoe Komlodi } 18367d87775fSJoe Komlodi 18377d87775fSJoe Komlodi /* 18387d87775fSJoe Komlodi * Register Address of I3CX Device = 18397d87775fSJoe Komlodi * (Base Address of Global Register) + (Offset of I3CX) + Offset 18407d87775fSJoe Komlodi * X = 0, 1, 2, 3, 4, 5 18417d87775fSJoe Komlodi * Offset of I3C0 = 0x2000 18427d87775fSJoe Komlodi * Offset of I3C1 = 0x3000 18437d87775fSJoe Komlodi * Offset of I3C2 = 0x4000 18447d87775fSJoe Komlodi * Offset of I3C3 = 0x5000 18457d87775fSJoe Komlodi * Offset of I3C4 = 0x6000 18467d87775fSJoe Komlodi * Offset of I3C5 = 0x7000 18477d87775fSJoe Komlodi */ 18487d87775fSJoe Komlodi memory_region_add_subregion(&s->iomem_container, 18497d87775fSJoe Komlodi 0x2000 + i * 0x1000, &s->devices[i].mr); 18507d87775fSJoe Komlodi } 18517d87775fSJoe Komlodi 18527d87775fSJoe Komlodi } 18537d87775fSJoe Komlodi 18547d87775fSJoe Komlodi static Property aspeed_i3c_device_properties[] = { 18557d87775fSJoe Komlodi DEFINE_PROP_UINT8("device-id", AspeedI3CDevice, id, 0), 18567d87775fSJoe Komlodi DEFINE_PROP_END_OF_LIST(), 18577d87775fSJoe Komlodi }; 18587d87775fSJoe Komlodi 18597d87775fSJoe Komlodi static void aspeed_i3c_device_class_init(ObjectClass *klass, void *data) 18607d87775fSJoe Komlodi { 18617d87775fSJoe Komlodi DeviceClass *dc = DEVICE_CLASS(klass); 18627d87775fSJoe Komlodi 18637d87775fSJoe Komlodi dc->desc = "Aspeed I3C Device"; 18647d87775fSJoe Komlodi dc->realize = aspeed_i3c_device_realize; 18657d87775fSJoe Komlodi device_class_set_legacy_reset(dc, aspeed_i3c_device_reset); 18667d87775fSJoe Komlodi device_class_set_props(dc, aspeed_i3c_device_properties); 18677d87775fSJoe Komlodi } 18687d87775fSJoe Komlodi 18697d87775fSJoe Komlodi static const TypeInfo aspeed_i3c_device_info = { 18707d87775fSJoe Komlodi .name = TYPE_ASPEED_I3C_DEVICE, 18717d87775fSJoe Komlodi .parent = TYPE_SYS_BUS_DEVICE, 18727d87775fSJoe Komlodi .instance_size = sizeof(AspeedI3CDevice), 18737d87775fSJoe Komlodi .class_init = aspeed_i3c_device_class_init, 18747d87775fSJoe Komlodi }; 18757d87775fSJoe Komlodi 18767d87775fSJoe Komlodi static const VMStateDescription vmstate_aspeed_i3c = { 18777d87775fSJoe Komlodi .name = TYPE_ASPEED_I3C, 18787d87775fSJoe Komlodi .version_id = 1, 18797d87775fSJoe Komlodi .minimum_version_id = 1, 18807d87775fSJoe Komlodi .fields = (const VMStateField[]) { 18817d87775fSJoe Komlodi VMSTATE_UINT32_ARRAY(regs, AspeedI3CState, ASPEED_I3C_NR_REGS), 18827d87775fSJoe Komlodi VMSTATE_STRUCT_ARRAY(devices, AspeedI3CState, ASPEED_I3C_NR_DEVICES, 1, 18837d87775fSJoe Komlodi aspeed_i3c_device_vmstate, AspeedI3CDevice), 18847d87775fSJoe Komlodi VMSTATE_END_OF_LIST(), 18857d87775fSJoe Komlodi } 18867d87775fSJoe Komlodi }; 18877d87775fSJoe Komlodi 18887d87775fSJoe Komlodi static void aspeed_i3c_class_init(ObjectClass *klass, void *data) 18897d87775fSJoe Komlodi { 18907d87775fSJoe Komlodi DeviceClass *dc = DEVICE_CLASS(klass); 18917d87775fSJoe Komlodi 18927d87775fSJoe Komlodi dc->realize = aspeed_i3c_realize; 18937d87775fSJoe Komlodi device_class_set_legacy_reset(dc, aspeed_i3c_reset); 18947d87775fSJoe Komlodi dc->desc = "Aspeed I3C Controller"; 18957d87775fSJoe Komlodi dc->vmsd = &vmstate_aspeed_i3c; 18967d87775fSJoe Komlodi } 18977d87775fSJoe Komlodi 18987d87775fSJoe Komlodi static const TypeInfo aspeed_i3c_info = { 18997d87775fSJoe Komlodi .name = TYPE_ASPEED_I3C, 19007d87775fSJoe Komlodi .parent = TYPE_SYS_BUS_DEVICE, 19017d87775fSJoe Komlodi .instance_init = aspeed_i3c_instance_init, 19027d87775fSJoe Komlodi .instance_size = sizeof(AspeedI3CState), 19037d87775fSJoe Komlodi .class_init = aspeed_i3c_class_init, 19047d87775fSJoe Komlodi }; 19057d87775fSJoe Komlodi 19067d87775fSJoe Komlodi static void aspeed_i3c_register_types(void) 19077d87775fSJoe Komlodi { 19087d87775fSJoe Komlodi type_register_static(&aspeed_i3c_device_info); 19097d87775fSJoe Komlodi type_register_static(&aspeed_i3c_info); 19107d87775fSJoe Komlodi } 19117d87775fSJoe Komlodi 19127d87775fSJoe Komlodi type_init(aspeed_i3c_register_types); 1913