1c52aaabdSJoe Komlodi /* 2c52aaabdSJoe Komlodi * DesignWare I3C Controller 3c52aaabdSJoe Komlodi * 4c52aaabdSJoe Komlodi * Copyright (C) 2021 ASPEED Technology Inc. 5c52aaabdSJoe Komlodi * Copyright (C) 2025 Google, LLC 6c52aaabdSJoe Komlodi * 7c52aaabdSJoe Komlodi * SPDX-License-Identifier: GPL-2.0-or-later 8c52aaabdSJoe Komlodi */ 9c52aaabdSJoe Komlodi 10c52aaabdSJoe Komlodi #include "qemu/osdep.h" 11c52aaabdSJoe Komlodi #include "qemu/log.h" 12c52aaabdSJoe Komlodi #include "qemu/error-report.h" 13c52aaabdSJoe Komlodi #include "hw/i3c/i3c.h" 14c52aaabdSJoe Komlodi #include "hw/i3c/dw-i3c.h" 15c52aaabdSJoe Komlodi #include "hw/registerfields.h" 16c52aaabdSJoe Komlodi #include "hw/qdev-properties.h" 17c52aaabdSJoe Komlodi #include "qapi/error.h" 18c52aaabdSJoe Komlodi #include "migration/vmstate.h" 19c52aaabdSJoe Komlodi #include "trace.h" 20a825bbb7SJoe Komlodi #include "hw/irq.h" 21c52aaabdSJoe Komlodi 225a2a5453SJoe Komlodi /* 235a2a5453SJoe Komlodi * Disable event command values. sent along with a DISEC CCC to disable certain 245a2a5453SJoe Komlodi * events on targets. 255a2a5453SJoe Komlodi */ 265a2a5453SJoe Komlodi #define DISEC_HJ 0x08 275a2a5453SJoe Komlodi #define DISEC_CR 0x02 285a2a5453SJoe Komlodi #define DISEC_INT 0x01 295a2a5453SJoe Komlodi 30c52aaabdSJoe Komlodi REG32(DEVICE_CTRL, 0x00) 3159b8d0c9SJoe Komlodi FIELD(DEVICE_CTRL, I3C_BROADCAST_ADDR_INC, 0, 1) 3259b8d0c9SJoe Komlodi FIELD(DEVICE_CTRL, I2C_SLAVE_PRESENT, 7, 1) 3359b8d0c9SJoe Komlodi FIELD(DEVICE_CTRL, HOT_JOIN_ACK_NACK_CTRL, 8, 1) 3459b8d0c9SJoe Komlodi FIELD(DEVICE_CTRL, IDLE_CNT_MULTIPLIER, 24, 2) 3559b8d0c9SJoe Komlodi FIELD(DEVICE_CTRL, SLV_ADAPT_TO_I2C_I3C_MODE, 27, 1) 3659b8d0c9SJoe Komlodi FIELD(DEVICE_CTRL, DMA_HANDSHAKE_EN, 28, 1) 3759b8d0c9SJoe Komlodi FIELD(DEVICE_CTRL, I3C_ABORT, 29, 1) 3859b8d0c9SJoe Komlodi FIELD(DEVICE_CTRL, I3C_RESUME, 30, 1) 3959b8d0c9SJoe Komlodi FIELD(DEVICE_CTRL, I3C_EN, 31, 1) 40c52aaabdSJoe Komlodi REG32(DEVICE_ADDR, 0x04) 4159b8d0c9SJoe Komlodi FIELD(DEVICE_ADDR, STATIC_ADDR, 0, 7) 4259b8d0c9SJoe Komlodi FIELD(DEVICE_ADDR, STATIC_ADDR_VALID, 15, 1) 4359b8d0c9SJoe Komlodi FIELD(DEVICE_ADDR, DYNAMIC_ADDR, 16, 7) 4459b8d0c9SJoe Komlodi FIELD(DEVICE_ADDR, DYNAMIC_ADDR_VALID, 15, 1) 45c52aaabdSJoe Komlodi REG32(HW_CAPABILITY, 0x08) 4659b8d0c9SJoe Komlodi FIELD(HW_CAPABILITY, DEVICE_ROLE_CONFIG, 0, 2) 4759b8d0c9SJoe Komlodi FIELD(HW_CAPABILITY, HDR_DDR, 3, 1) 4859b8d0c9SJoe Komlodi FIELD(HW_CAPABILITY, HDR_TS, 4, 1) 49c52aaabdSJoe Komlodi REG32(COMMAND_QUEUE_PORT, 0x0c) 5059b8d0c9SJoe Komlodi FIELD(COMMAND_QUEUE_PORT, CMD_ATTR, 0, 3) 5159b8d0c9SJoe Komlodi /* Transfer command structure */ 5259b8d0c9SJoe Komlodi FIELD(COMMAND_QUEUE_PORT, TID, 3, 4) 5359b8d0c9SJoe Komlodi FIELD(COMMAND_QUEUE_PORT, CMD, 7, 8) 5459b8d0c9SJoe Komlodi FIELD(COMMAND_QUEUE_PORT, CP, 15, 1) 5559b8d0c9SJoe Komlodi FIELD(COMMAND_QUEUE_PORT, DEV_INDEX, 16, 5) 5659b8d0c9SJoe Komlodi FIELD(COMMAND_QUEUE_PORT, SPEED, 21, 3) 5759b8d0c9SJoe Komlodi FIELD(COMMAND_QUEUE_PORT, ROC, 26, 1) 5859b8d0c9SJoe Komlodi FIELD(COMMAND_QUEUE_PORT, SDAP, 27, 1) 5959b8d0c9SJoe Komlodi FIELD(COMMAND_QUEUE_PORT, RNW, 28, 1) 6059b8d0c9SJoe Komlodi FIELD(COMMAND_QUEUE_PORT, TOC, 30, 1) 6159b8d0c9SJoe Komlodi FIELD(COMMAND_QUEUE_PORT, PEC, 31, 1) 6259b8d0c9SJoe Komlodi /* Transfer argument data structure */ 6359b8d0c9SJoe Komlodi FIELD(COMMAND_QUEUE_PORT, DB, 8, 8) 6459b8d0c9SJoe Komlodi FIELD(COMMAND_QUEUE_PORT, DL, 16, 16) 6559b8d0c9SJoe Komlodi /* Short data argument data structure */ 6659b8d0c9SJoe Komlodi FIELD(COMMAND_QUEUE_PORT, BYTE_STRB, 3, 3) 6759b8d0c9SJoe Komlodi FIELD(COMMAND_QUEUE_PORT, BYTE0, 8, 8) 6859b8d0c9SJoe Komlodi FIELD(COMMAND_QUEUE_PORT, BYTE1, 16, 8) 6959b8d0c9SJoe Komlodi FIELD(COMMAND_QUEUE_PORT, BYTE2, 24, 8) 7059b8d0c9SJoe Komlodi /* Address assignment command structure */ 7159b8d0c9SJoe Komlodi /* 7259b8d0c9SJoe Komlodi * bits 3..21 and 26..31 are the same as the transfer command structure, or 7359b8d0c9SJoe Komlodi * marked as reserved. 7459b8d0c9SJoe Komlodi */ 7559b8d0c9SJoe Komlodi FIELD(COMMAND_QUEUE_PORT, DEV_COUNT, 21, 3) 76c52aaabdSJoe Komlodi REG32(RESPONSE_QUEUE_PORT, 0x10) 7759b8d0c9SJoe Komlodi FIELD(RESPONSE_QUEUE_PORT, DL, 0, 16) 7859b8d0c9SJoe Komlodi FIELD(RESPONSE_QUEUE_PORT, CCCT, 16, 8) 7959b8d0c9SJoe Komlodi FIELD(RESPONSE_QUEUE_PORT, TID, 24, 4) 8059b8d0c9SJoe Komlodi FIELD(RESPONSE_QUEUE_PORT, ERR_STATUS, 28, 4) 81c52aaabdSJoe Komlodi REG32(RX_TX_DATA_PORT, 0x14) 82c52aaabdSJoe Komlodi REG32(IBI_QUEUE_STATUS, 0x18) 8359b8d0c9SJoe Komlodi FIELD(IBI_QUEUE_STATUS, IBI_DATA_LEN, 0, 8) 8459b8d0c9SJoe Komlodi FIELD(IBI_QUEUE_STATUS, IBI_ID, 8, 8) 8559b8d0c9SJoe Komlodi FIELD(IBI_QUEUE_STATUS, LAST_STATUS, 24, 1) 8659b8d0c9SJoe Komlodi FIELD(IBI_QUEUE_STATUS, ERROR, 30, 1) 8759b8d0c9SJoe Komlodi FIELD(IBI_QUEUE_STATUS, IBI_STATUS, 31, 1) 88c52aaabdSJoe Komlodi REG32(IBI_QUEUE_DATA, 0x18) 89c52aaabdSJoe Komlodi REG32(QUEUE_THLD_CTRL, 0x1c) 9059b8d0c9SJoe Komlodi FIELD(QUEUE_THLD_CTRL, CMD_BUF_EMPTY_THLD, 0, 8); 9159b8d0c9SJoe Komlodi FIELD(QUEUE_THLD_CTRL, RESP_BUF_THLD, 8, 8); 9259b8d0c9SJoe Komlodi FIELD(QUEUE_THLD_CTRL, IBI_DATA_THLD, 16, 8); 9359b8d0c9SJoe Komlodi FIELD(QUEUE_THLD_CTRL, IBI_STATUS_THLD, 24, 8); 94c52aaabdSJoe Komlodi REG32(DATA_BUFFER_THLD_CTRL, 0x20) 9559b8d0c9SJoe Komlodi FIELD(DATA_BUFFER_THLD_CTRL, TX_BUF_THLD, 0, 3) 9659b8d0c9SJoe Komlodi FIELD(DATA_BUFFER_THLD_CTRL, RX_BUF_THLD, 10, 3) 9759b8d0c9SJoe Komlodi FIELD(DATA_BUFFER_THLD_CTRL, TX_START_THLD, 16, 3) 9859b8d0c9SJoe Komlodi FIELD(DATA_BUFFER_THLD_CTRL, RX_START_THLD, 24, 3) 99c52aaabdSJoe Komlodi REG32(IBI_QUEUE_CTRL, 0x24) 10059b8d0c9SJoe Komlodi FIELD(IBI_QUEUE_CTRL, NOTIFY_REJECTED_HOT_JOIN, 0, 1) 10159b8d0c9SJoe Komlodi FIELD(IBI_QUEUE_CTRL, NOTIFY_REJECTED_MASTER_REQ, 1, 1) 10259b8d0c9SJoe Komlodi FIELD(IBI_QUEUE_CTRL, NOTIFY_REJECTED_SLAVE_IRQ, 3, 1) 103c52aaabdSJoe Komlodi REG32(IBI_MR_REQ_REJECT, 0x2c) 104c52aaabdSJoe Komlodi REG32(IBI_SIR_REQ_REJECT, 0x30) 105c52aaabdSJoe Komlodi REG32(RESET_CTRL, 0x34) 10659b8d0c9SJoe Komlodi FIELD(RESET_CTRL, CORE_RESET, 0, 1) 10759b8d0c9SJoe Komlodi FIELD(RESET_CTRL, CMD_QUEUE_RESET, 1, 1) 10859b8d0c9SJoe Komlodi FIELD(RESET_CTRL, RESP_QUEUE_RESET, 2, 1) 10959b8d0c9SJoe Komlodi FIELD(RESET_CTRL, TX_BUF_RESET, 3, 1) 11059b8d0c9SJoe Komlodi FIELD(RESET_CTRL, RX_BUF_RESET, 4, 1) 11159b8d0c9SJoe Komlodi FIELD(RESET_CTRL, IBI_QUEUE_RESET, 5, 1) 112c52aaabdSJoe Komlodi REG32(SLV_EVENT_CTRL, 0x38) 11359b8d0c9SJoe Komlodi FIELD(SLV_EVENT_CTRL, SLV_INTERRUPT, 0, 1) 11459b8d0c9SJoe Komlodi FIELD(SLV_EVENT_CTRL, MASTER_INTERRUPT, 1, 1) 11559b8d0c9SJoe Komlodi FIELD(SLV_EVENT_CTRL, HOT_JOIN_INTERRUPT, 3, 1) 11659b8d0c9SJoe Komlodi FIELD(SLV_EVENT_CTRL, ACTIVITY_STATE, 4, 2) 11759b8d0c9SJoe Komlodi FIELD(SLV_EVENT_CTRL, MRL_UPDATED, 6, 1) 11859b8d0c9SJoe Komlodi FIELD(SLV_EVENT_CTRL, MWL_UPDATED, 7, 1) 119c52aaabdSJoe Komlodi REG32(INTR_STATUS, 0x3c) 12059b8d0c9SJoe Komlodi FIELD(INTR_STATUS, TX_THLD, 0, 1) 12159b8d0c9SJoe Komlodi FIELD(INTR_STATUS, RX_THLD, 1, 1) 12259b8d0c9SJoe Komlodi FIELD(INTR_STATUS, IBI_THLD, 2, 1) 12359b8d0c9SJoe Komlodi FIELD(INTR_STATUS, CMD_QUEUE_RDY, 3, 1) 12459b8d0c9SJoe Komlodi FIELD(INTR_STATUS, RESP_RDY, 4, 1) 12559b8d0c9SJoe Komlodi FIELD(INTR_STATUS, TRANSFER_ABORT, 5, 1) 12659b8d0c9SJoe Komlodi FIELD(INTR_STATUS, CCC_UPDATED, 6, 1) 12759b8d0c9SJoe Komlodi FIELD(INTR_STATUS, DYN_ADDR_ASSGN, 8, 1) 12859b8d0c9SJoe Komlodi FIELD(INTR_STATUS, TRANSFER_ERR, 9, 1) 12959b8d0c9SJoe Komlodi FIELD(INTR_STATUS, DEFSLV, 10, 1) 13059b8d0c9SJoe Komlodi FIELD(INTR_STATUS, READ_REQ_RECV, 11, 1) 13159b8d0c9SJoe Komlodi FIELD(INTR_STATUS, IBI_UPDATED, 12, 1) 13259b8d0c9SJoe Komlodi FIELD(INTR_STATUS, BUSOWNER_UPDATED, 13, 1) 133c52aaabdSJoe Komlodi REG32(INTR_STATUS_EN, 0x40) 13459b8d0c9SJoe Komlodi FIELD(INTR_STATUS_EN, TX_THLD, 0, 1) 13559b8d0c9SJoe Komlodi FIELD(INTR_STATUS_EN, RX_THLD, 1, 1) 13659b8d0c9SJoe Komlodi FIELD(INTR_STATUS_EN, IBI_THLD, 2, 1) 13759b8d0c9SJoe Komlodi FIELD(INTR_STATUS_EN, CMD_QUEUE_RDY, 3, 1) 13859b8d0c9SJoe Komlodi FIELD(INTR_STATUS_EN, RESP_RDY, 4, 1) 13959b8d0c9SJoe Komlodi FIELD(INTR_STATUS_EN, TRANSFER_ABORT, 5, 1) 14059b8d0c9SJoe Komlodi FIELD(INTR_STATUS_EN, CCC_UPDATED, 6, 1) 14159b8d0c9SJoe Komlodi FIELD(INTR_STATUS_EN, DYN_ADDR_ASSGN, 8, 1) 14259b8d0c9SJoe Komlodi FIELD(INTR_STATUS_EN, TRANSFER_ERR, 9, 1) 14359b8d0c9SJoe Komlodi FIELD(INTR_STATUS_EN, DEFSLV, 10, 1) 14459b8d0c9SJoe Komlodi FIELD(INTR_STATUS_EN, READ_REQ_RECV, 11, 1) 14559b8d0c9SJoe Komlodi FIELD(INTR_STATUS_EN, IBI_UPDATED, 12, 1) 14659b8d0c9SJoe Komlodi FIELD(INTR_STATUS_EN, BUSOWNER_UPDATED, 13, 1) 147c52aaabdSJoe Komlodi REG32(INTR_SIGNAL_EN, 0x44) 14859b8d0c9SJoe Komlodi FIELD(INTR_SIGNAL_EN, TX_THLD, 0, 1) 14959b8d0c9SJoe Komlodi FIELD(INTR_SIGNAL_EN, RX_THLD, 1, 1) 15059b8d0c9SJoe Komlodi FIELD(INTR_SIGNAL_EN, IBI_THLD, 2, 1) 15159b8d0c9SJoe Komlodi FIELD(INTR_SIGNAL_EN, CMD_QUEUE_RDY, 3, 1) 15259b8d0c9SJoe Komlodi FIELD(INTR_SIGNAL_EN, RESP_RDY, 4, 1) 15359b8d0c9SJoe Komlodi FIELD(INTR_SIGNAL_EN, TRANSFER_ABORT, 5, 1) 15459b8d0c9SJoe Komlodi FIELD(INTR_SIGNAL_EN, CCC_UPDATED, 6, 1) 15559b8d0c9SJoe Komlodi FIELD(INTR_SIGNAL_EN, DYN_ADDR_ASSGN, 8, 1) 15659b8d0c9SJoe Komlodi FIELD(INTR_SIGNAL_EN, TRANSFER_ERR, 9, 1) 15759b8d0c9SJoe Komlodi FIELD(INTR_SIGNAL_EN, DEFSLV, 10, 1) 15859b8d0c9SJoe Komlodi FIELD(INTR_SIGNAL_EN, READ_REQ_RECV, 11, 1) 15959b8d0c9SJoe Komlodi FIELD(INTR_SIGNAL_EN, IBI_UPDATED, 12, 1) 16059b8d0c9SJoe Komlodi FIELD(INTR_SIGNAL_EN, BUSOWNER_UPDATED, 13, 1) 161c52aaabdSJoe Komlodi REG32(INTR_FORCE, 0x48) 16259b8d0c9SJoe Komlodi FIELD(INTR_FORCE, TX_THLD, 0, 1) 16359b8d0c9SJoe Komlodi FIELD(INTR_FORCE, RX_THLD, 1, 1) 16459b8d0c9SJoe Komlodi FIELD(INTR_FORCE, IBI_THLD, 2, 1) 16559b8d0c9SJoe Komlodi FIELD(INTR_FORCE, CMD_QUEUE_RDY, 3, 1) 16659b8d0c9SJoe Komlodi FIELD(INTR_FORCE, RESP_RDY, 4, 1) 16759b8d0c9SJoe Komlodi FIELD(INTR_FORCE, TRANSFER_ABORT, 5, 1) 16859b8d0c9SJoe Komlodi FIELD(INTR_FORCE, CCC_UPDATED, 6, 1) 16959b8d0c9SJoe Komlodi FIELD(INTR_FORCE, DYN_ADDR_ASSGN, 8, 1) 17059b8d0c9SJoe Komlodi FIELD(INTR_FORCE, TRANSFER_ERR, 9, 1) 17159b8d0c9SJoe Komlodi FIELD(INTR_FORCE, DEFSLV, 10, 1) 17259b8d0c9SJoe Komlodi FIELD(INTR_FORCE, READ_REQ_RECV, 11, 1) 17359b8d0c9SJoe Komlodi FIELD(INTR_FORCE, IBI_UPDATED, 12, 1) 17459b8d0c9SJoe Komlodi FIELD(INTR_FORCE, BUSOWNER_UPDATED, 13, 1) 175c52aaabdSJoe Komlodi REG32(QUEUE_STATUS_LEVEL, 0x4c) 17659b8d0c9SJoe Komlodi FIELD(QUEUE_STATUS_LEVEL, CMD_QUEUE_EMPTY_LOC, 0, 8) 17759b8d0c9SJoe Komlodi FIELD(QUEUE_STATUS_LEVEL, RESP_BUF_BLR, 8, 8) 17859b8d0c9SJoe Komlodi FIELD(QUEUE_STATUS_LEVEL, IBI_BUF_BLR, 16, 8) 17959b8d0c9SJoe Komlodi FIELD(QUEUE_STATUS_LEVEL, IBI_STATUS_CNT, 24, 5) 180c52aaabdSJoe Komlodi REG32(DATA_BUFFER_STATUS_LEVEL, 0x50) 18159b8d0c9SJoe Komlodi FIELD(DATA_BUFFER_STATUS_LEVEL, TX_BUF_EMPTY_LOC, 0, 8) 18259b8d0c9SJoe Komlodi FIELD(DATA_BUFFER_STATUS_LEVEL, RX_BUF_BLR, 16, 8) 183c52aaabdSJoe Komlodi REG32(PRESENT_STATE, 0x54) 18459b8d0c9SJoe Komlodi FIELD(PRESENT_STATE, SCL_LINE_SIGNAL_LEVEL, 0, 1) 18559b8d0c9SJoe Komlodi FIELD(PRESENT_STATE, SDA_LINE_SIGNAL_LEVEL, 1, 1) 18659b8d0c9SJoe Komlodi FIELD(PRESENT_STATE, CURRENT_MASTER, 2, 1) 18759b8d0c9SJoe Komlodi FIELD(PRESENT_STATE, CM_TFR_STATUS, 8, 6) 18859b8d0c9SJoe Komlodi FIELD(PRESENT_STATE, CM_TFR_ST_STATUS, 16, 6) 18959b8d0c9SJoe Komlodi FIELD(PRESENT_STATE, CMD_TID, 24, 4) 190c52aaabdSJoe Komlodi REG32(CCC_DEVICE_STATUS, 0x58) 19159b8d0c9SJoe Komlodi FIELD(CCC_DEVICE_STATUS, PENDING_INTR, 0, 4) 19259b8d0c9SJoe Komlodi FIELD(CCC_DEVICE_STATUS, PROTOCOL_ERR, 4, 2) 19359b8d0c9SJoe Komlodi FIELD(CCC_DEVICE_STATUS, ACTIVITY_MODE, 6, 2) 19459b8d0c9SJoe Komlodi FIELD(CCC_DEVICE_STATUS, UNDER_ERR, 8, 1) 19559b8d0c9SJoe Komlodi FIELD(CCC_DEVICE_STATUS, SLV_BUSY, 9, 1) 19659b8d0c9SJoe Komlodi FIELD(CCC_DEVICE_STATUS, OVERFLOW_ERR, 10, 1) 19759b8d0c9SJoe Komlodi FIELD(CCC_DEVICE_STATUS, DATA_NOT_READY, 11, 1) 19859b8d0c9SJoe Komlodi FIELD(CCC_DEVICE_STATUS, BUFFER_NOT_AVAIL, 12, 1) 199c52aaabdSJoe Komlodi REG32(DEVICE_ADDR_TABLE_POINTER, 0x5c) 200c52aaabdSJoe Komlodi FIELD(DEVICE_ADDR_TABLE_POINTER, DEPTH, 16, 16) 201c52aaabdSJoe Komlodi FIELD(DEVICE_ADDR_TABLE_POINTER, ADDR, 0, 16) 202c52aaabdSJoe Komlodi REG32(DEV_CHAR_TABLE_POINTER, 0x60) 20359b8d0c9SJoe Komlodi FIELD(DEV_CHAR_TABLE_POINTER, P_DEV_CHAR_TABLE_START_ADDR, 0, 12) 20459b8d0c9SJoe Komlodi FIELD(DEV_CHAR_TABLE_POINTER, DEV_CHAR_TABLE_DEPTH, 12, 7) 20559b8d0c9SJoe Komlodi FIELD(DEV_CHAR_TABLE_POINTER, PRESENT_DEV_CHAR_TABLE_INDEX, 19, 3) 206c52aaabdSJoe Komlodi REG32(VENDOR_SPECIFIC_REG_POINTER, 0x6c) 20759b8d0c9SJoe Komlodi FIELD(VENDOR_SPECIFIC_REG_POINTER, P_VENDOR_REG_START_ADDR, 0, 16) 208c52aaabdSJoe Komlodi REG32(SLV_MIPI_PID_VALUE, 0x70) 209c52aaabdSJoe Komlodi REG32(SLV_PID_VALUE, 0x74) 21059b8d0c9SJoe Komlodi FIELD(SLV_PID_VALUE, SLV_PID_DCR, 0, 12) 21159b8d0c9SJoe Komlodi FIELD(SLV_PID_VALUE, SLV_INST_ID, 12, 4) 21259b8d0c9SJoe Komlodi FIELD(SLV_PID_VALUE, SLV_PART_ID, 16, 16) 213c52aaabdSJoe Komlodi REG32(SLV_CHAR_CTRL, 0x78) 21459b8d0c9SJoe Komlodi FIELD(SLV_CHAR_CTRL, BCR, 0, 8) 21559b8d0c9SJoe Komlodi FIELD(SLV_CHAR_CTRL, DCR, 8, 8) 21659b8d0c9SJoe Komlodi FIELD(SLV_CHAR_CTRL, HDR_CAP, 16, 8) 217c52aaabdSJoe Komlodi REG32(SLV_MAX_LEN, 0x7c) 21859b8d0c9SJoe Komlodi FIELD(SLV_MAX_LEN, MWL, 0, 16) 21959b8d0c9SJoe Komlodi FIELD(SLV_MAX_LEN, MRL, 16, 16) 220c52aaabdSJoe Komlodi REG32(MAX_READ_TURNAROUND, 0x80) 221c52aaabdSJoe Komlodi REG32(MAX_DATA_SPEED, 0x84) 222c52aaabdSJoe Komlodi REG32(SLV_DEBUG_STATUS, 0x88) 223c52aaabdSJoe Komlodi REG32(SLV_INTR_REQ, 0x8c) 22459b8d0c9SJoe Komlodi FIELD(SLV_INTR_REQ, SIR, 0, 1) 22559b8d0c9SJoe Komlodi FIELD(SLV_INTR_REQ, SIR_CTRL, 1, 2) 22659b8d0c9SJoe Komlodi FIELD(SLV_INTR_REQ, MIR, 3, 1) 22759b8d0c9SJoe Komlodi FIELD(SLV_INTR_REQ, TS, 4, 1) 22859b8d0c9SJoe Komlodi FIELD(SLV_INTR_REQ, IBI_STS, 8, 2) 22959b8d0c9SJoe Komlodi FIELD(SLV_INTR_REQ, MDB, 8, 8) 23059b8d0c9SJoe Komlodi FIELD(SLV_INTR_REQ, SIR_DATA_LEN, 16, 8) 23159b8d0c9SJoe Komlodi REG32(SLV_TSX_SYMBL_TIMING, 0x90) 23259b8d0c9SJoe Komlodi FIELD(SLV_TSX_SYMBL_TIMING, SLV_TSX_SYMBL_CNT, 0, 6) 23359b8d0c9SJoe Komlodi REG32(SLV_SIR_DATA, 0x94) 23459b8d0c9SJoe Komlodi FIELD(SLV_SIR_DATA, SIR_DATA_BYTE0, 0, 8) 23559b8d0c9SJoe Komlodi FIELD(SLV_SIR_DATA, SIR_DATA_BYTE1, 8, 8) 23659b8d0c9SJoe Komlodi FIELD(SLV_SIR_DATA, SIR_DATA_BYTE2, 16, 8) 23759b8d0c9SJoe Komlodi FIELD(SLV_SIR_DATA, SIR_DATA_BYTE3, 24, 8) 23859b8d0c9SJoe Komlodi REG32(SLV_IBI_RESP, 0x98) 23959b8d0c9SJoe Komlodi FIELD(SLV_IBI_RESP, IBI_STS, 0, 2) 24059b8d0c9SJoe Komlodi FIELD(SLV_IBI_RESP, SIR_RESP_DATA_LEN, 8, 16) 241c52aaabdSJoe Komlodi REG32(DEVICE_CTRL_EXTENDED, 0xb0) 24259b8d0c9SJoe Komlodi FIELD(DEVICE_CTRL_EXTENDED, MODE, 0, 2) 24359b8d0c9SJoe Komlodi FIELD(DEVICE_CTRL_EXTENDED, REQMST_ACK_CTRL, 3, 1) 244c52aaabdSJoe Komlodi REG32(SCL_I3C_OD_TIMING, 0xb4) 24559b8d0c9SJoe Komlodi FIELD(SCL_I3C_OD_TIMING, I3C_OD_LCNT, 0, 8) 24659b8d0c9SJoe Komlodi FIELD(SCL_I3C_OD_TIMING, I3C_OD_HCNT, 16, 8) 247c52aaabdSJoe Komlodi REG32(SCL_I3C_PP_TIMING, 0xb8) 24859b8d0c9SJoe Komlodi FIELD(SCL_I3C_PP_TIMING, I3C_PP_LCNT, 0, 8) 24959b8d0c9SJoe Komlodi FIELD(SCL_I3C_PP_TIMING, I3C_PP_HCNT, 16, 8) 250c52aaabdSJoe Komlodi REG32(SCL_I2C_FM_TIMING, 0xbc) 251c52aaabdSJoe Komlodi REG32(SCL_I2C_FMP_TIMING, 0xc0) 25259b8d0c9SJoe Komlodi FIELD(SCL_I2C_FMP_TIMING, I2C_FMP_LCNT, 0, 16) 25359b8d0c9SJoe Komlodi FIELD(SCL_I2C_FMP_TIMING, I2C_FMP_HCNT, 16, 8) 254c52aaabdSJoe Komlodi REG32(SCL_EXT_LCNT_TIMING, 0xc8) 255c52aaabdSJoe Komlodi REG32(SCL_EXT_TERMN_LCNT_TIMING, 0xcc) 256c52aaabdSJoe Komlodi REG32(BUS_FREE_TIMING, 0xd4) 257c52aaabdSJoe Komlodi REG32(BUS_IDLE_TIMING, 0xd8) 25859b8d0c9SJoe Komlodi FIELD(BUS_IDLE_TIMING, BUS_IDLE_TIME, 0, 20) 259c52aaabdSJoe Komlodi REG32(I3C_VER_ID, 0xe0) 260c52aaabdSJoe Komlodi REG32(I3C_VER_TYPE, 0xe4) 261c52aaabdSJoe Komlodi REG32(EXTENDED_CAPABILITY, 0xe8) 26259b8d0c9SJoe Komlodi FIELD(EXTENDED_CAPABILITY, APP_IF_MODE, 0, 2) 26359b8d0c9SJoe Komlodi FIELD(EXTENDED_CAPABILITY, APP_IF_DATA_WIDTH, 2, 2) 26459b8d0c9SJoe Komlodi FIELD(EXTENDED_CAPABILITY, OPERATION_MODE, 4, 2) 26559b8d0c9SJoe Komlodi FIELD(EXTENDED_CAPABILITY, CLK_PERIOD, 8, 6) 266c52aaabdSJoe Komlodi REG32(SLAVE_CONFIG, 0xec) 26759b8d0c9SJoe Komlodi FIELD(SLAVE_CONFIG, DMA_EN, 0, 1) 26859b8d0c9SJoe Komlodi FIELD(SLAVE_CONFIG, HJ_CAP, 0, 1) 26959b8d0c9SJoe Komlodi FIELD(SLAVE_CONFIG, CLK_PERIOD, 2, 14) 27059b8d0c9SJoe Komlodi /* Device characteristic table fields */ 27159b8d0c9SJoe Komlodi REG32(DEVICE_CHARACTERISTIC_TABLE_LOC1, 0x200) 27259b8d0c9SJoe Komlodi REG32(DEVICE_CHARACTERISTIC_TABLE_LOC_SECONDARY, 0x200) 27359b8d0c9SJoe Komlodi FIELD(DEVICE_CHARACTERISTIC_TABLE_LOC_SECONDARY, DYNAMIC_ADDR, 0, 8) 27459b8d0c9SJoe Komlodi FIELD(DEVICE_CHARACTERISTIC_TABLE_LOC_SECONDARY, DCR, 8, 8) 27559b8d0c9SJoe Komlodi FIELD(DEVICE_CHARACTERISTIC_TABLE_LOC_SECONDARY, BCR, 16, 8) 27659b8d0c9SJoe Komlodi FIELD(DEVICE_CHARACTERISTIC_TABLE_LOC_SECONDARY, STATIC_ADDR, 24, 8) 27759b8d0c9SJoe Komlodi REG32(DEVICE_CHARACTERISTIC_TABLE_LOC2, 0x204) 27859b8d0c9SJoe Komlodi FIELD(DEVICE_CHARACTERISTIC_TABLE_LOC2, MSB_PID, 0, 16) 27959b8d0c9SJoe Komlodi REG32(DEVICE_CHARACTERISTIC_TABLE_LOC3, 0x208) 28059b8d0c9SJoe Komlodi FIELD(DEVICE_CHARACTERISTIC_TABLE_LOC3, DCR, 0, 8) 28159b8d0c9SJoe Komlodi FIELD(DEVICE_CHARACTERISTIC_TABLE_LOC3, BCR, 8, 8) 28259b8d0c9SJoe Komlodi REG32(DEVICE_CHARACTERISTIC_TABLE_LOC4, 0x20c) 28359b8d0c9SJoe Komlodi FIELD(DEVICE_CHARACTERISTIC_TABLE_LOC4, DEV_DYNAMIC_ADDR, 0, 8) 28459b8d0c9SJoe Komlodi /* Dev addr table fields */ 28559b8d0c9SJoe Komlodi REG32(DEVICE_ADDR_TABLE_LOC1, 0x280) 28659b8d0c9SJoe Komlodi FIELD(DEVICE_ADDR_TABLE_LOC1, DEV_STATIC_ADDR, 0, 7) 28759b8d0c9SJoe Komlodi FIELD(DEVICE_ADDR_TABLE_LOC1, IBI_PEC_EN, 11, 1) 28859b8d0c9SJoe Komlodi FIELD(DEVICE_ADDR_TABLE_LOC1, IBI_WITH_DATA, 12, 1) 28959b8d0c9SJoe Komlodi FIELD(DEVICE_ADDR_TABLE_LOC1, SIR_REJECT, 13, 1) 29059b8d0c9SJoe Komlodi FIELD(DEVICE_ADDR_TABLE_LOC1, MR_REJECT, 14, 1) 29159b8d0c9SJoe Komlodi FIELD(DEVICE_ADDR_TABLE_LOC1, DEV_DYNAMIC_ADDR, 16, 8) 29259b8d0c9SJoe Komlodi FIELD(DEVICE_ADDR_TABLE_LOC1, IBI_ADDR_MASK, 24, 2) 29359b8d0c9SJoe Komlodi FIELD(DEVICE_ADDR_TABLE_LOC1, DEV_NACK_RETRY_CNT, 29, 2) 29459b8d0c9SJoe Komlodi FIELD(DEVICE_ADDR_TABLE_LOC1, LEGACY_I2C_DEVICE, 31, 1) 295c52aaabdSJoe Komlodi 296c52aaabdSJoe Komlodi static const uint32_t dw_i3c_resets[DW_I3C_NR_REGS] = { 29773a38a9bSJoe Komlodi /* Target mode is not supported, don't advertise it for now. */ 29873a38a9bSJoe Komlodi [R_HW_CAPABILITY] = 0x000e00b9, 299c52aaabdSJoe Komlodi [R_QUEUE_THLD_CTRL] = 0x01000101, 30073a38a9bSJoe Komlodi [R_DATA_BUFFER_THLD_CTRL] = 0x01010100, 30173a38a9bSJoe Komlodi [R_SLV_EVENT_CTRL] = 0x0000000b, 30273a38a9bSJoe Komlodi [R_QUEUE_STATUS_LEVEL] = 0x00000002, 30373a38a9bSJoe Komlodi [R_DATA_BUFFER_STATUS_LEVEL] = 0x00000010, 30473a38a9bSJoe Komlodi [R_PRESENT_STATE] = 0x00000003, 305c52aaabdSJoe Komlodi [R_I3C_VER_ID] = 0x3130302a, 306c52aaabdSJoe Komlodi [R_I3C_VER_TYPE] = 0x6c633033, 307c52aaabdSJoe Komlodi [R_DEVICE_ADDR_TABLE_POINTER] = 0x00080280, 308c52aaabdSJoe Komlodi [R_DEV_CHAR_TABLE_POINTER] = 0x00020200, 30973a38a9bSJoe Komlodi [R_SLV_CHAR_CTRL] = 0x00010000, 310c52aaabdSJoe Komlodi [A_VENDOR_SPECIFIC_REG_POINTER] = 0x000000b0, 311c52aaabdSJoe Komlodi [R_SLV_MAX_LEN] = 0x00ff00ff, 31273a38a9bSJoe Komlodi [R_SLV_TSX_SYMBL_TIMING] = 0x0000003f, 31373a38a9bSJoe Komlodi [R_SCL_I3C_OD_TIMING] = 0x000a0010, 31473a38a9bSJoe Komlodi [R_SCL_I3C_PP_TIMING] = 0x000a000a, 31573a38a9bSJoe Komlodi [R_SCL_I2C_FM_TIMING] = 0x00100010, 31673a38a9bSJoe Komlodi [R_SCL_I2C_FMP_TIMING] = 0x00100010, 31773a38a9bSJoe Komlodi [R_SCL_EXT_LCNT_TIMING] = 0x20202020, 31873a38a9bSJoe Komlodi [R_SCL_EXT_TERMN_LCNT_TIMING] = 0x00300000, 31973a38a9bSJoe Komlodi [R_BUS_FREE_TIMING] = 0x00200020, 32073a38a9bSJoe Komlodi [R_BUS_IDLE_TIMING] = 0x00000020, 32173a38a9bSJoe Komlodi [R_EXTENDED_CAPABILITY] = 0x00000239, 32273a38a9bSJoe Komlodi [R_SLAVE_CONFIG] = 0x00000023, 323c52aaabdSJoe Komlodi }; 324c52aaabdSJoe Komlodi 325ef77491fSJoe Komlodi static const uint32_t dw_i3c_ro[DW_I3C_NR_REGS] = { 326ef77491fSJoe Komlodi [R_DEVICE_CTRL] = 0x04fffe00, 327ef77491fSJoe Komlodi [R_DEVICE_ADDR] = 0x7f807f80, 328ef77491fSJoe Komlodi [R_HW_CAPABILITY] = 0xffffffff, 329ef77491fSJoe Komlodi [R_IBI_QUEUE_STATUS] = 0xffffffff, 330ef77491fSJoe Komlodi [R_DATA_BUFFER_THLD_CTRL] = 0xf8f8f8f8, 331ef77491fSJoe Komlodi [R_IBI_QUEUE_CTRL] = 0xfffffff0, 332ef77491fSJoe Komlodi [R_RESET_CTRL] = 0xffffffc0, 333ef77491fSJoe Komlodi [R_SLV_EVENT_CTRL] = 0xffffff3f, 334ef77491fSJoe Komlodi [R_INTR_STATUS] = 0xffff809f, 335ef77491fSJoe Komlodi [R_INTR_STATUS_EN] = 0xffff8080, 336ef77491fSJoe Komlodi [R_INTR_SIGNAL_EN] = 0xffff8080, 337ef77491fSJoe Komlodi [R_INTR_FORCE] = 0xffff8000, 338ef77491fSJoe Komlodi [R_QUEUE_STATUS_LEVEL] = 0xffffffff, 339ef77491fSJoe Komlodi [R_DATA_BUFFER_STATUS_LEVEL] = 0xffffffff, 340ef77491fSJoe Komlodi [R_PRESENT_STATE] = 0xffffffff, 341ef77491fSJoe Komlodi [R_CCC_DEVICE_STATUS] = 0xffffffff, 342ef77491fSJoe Komlodi [R_I3C_VER_ID] = 0xffffffff, 343ef77491fSJoe Komlodi [R_I3C_VER_TYPE] = 0xffffffff, 344ef77491fSJoe Komlodi [R_DEVICE_ADDR_TABLE_POINTER] = 0xffffffff, 345ef77491fSJoe Komlodi [R_DEV_CHAR_TABLE_POINTER] = 0xffcbffff, 346ef77491fSJoe Komlodi [R_SLV_PID_VALUE] = 0xffff0fff, 347ef77491fSJoe Komlodi [R_SLV_CHAR_CTRL] = 0xffffffff, 348ef77491fSJoe Komlodi [A_VENDOR_SPECIFIC_REG_POINTER] = 0xffffffff, 349ef77491fSJoe Komlodi [R_SLV_MAX_LEN] = 0xffffffff, 350ef77491fSJoe Komlodi [R_MAX_READ_TURNAROUND] = 0xffffffff, 351ef77491fSJoe Komlodi [R_MAX_DATA_SPEED] = 0xffffffff, 352ef77491fSJoe Komlodi [R_SLV_INTR_REQ] = 0xfffffff0, 353ef77491fSJoe Komlodi [R_SLV_TSX_SYMBL_TIMING] = 0xffffffc0, 354ef77491fSJoe Komlodi [R_DEVICE_CTRL_EXTENDED] = 0xfffffff8, 355ef77491fSJoe Komlodi [R_SCL_I3C_OD_TIMING] = 0xff00ff00, 356ef77491fSJoe Komlodi [R_SCL_I3C_PP_TIMING] = 0xff00ff00, 357ef77491fSJoe Komlodi [R_SCL_I2C_FMP_TIMING] = 0xff000000, 358ef77491fSJoe Komlodi [R_SCL_EXT_TERMN_LCNT_TIMING] = 0x0000fff0, 359ef77491fSJoe Komlodi [R_BUS_IDLE_TIMING] = 0xfff00000, 360ef77491fSJoe Komlodi [R_EXTENDED_CAPABILITY] = 0xffffffff, 361ef77491fSJoe Komlodi [R_SLAVE_CONFIG] = 0xffffffff, 362ef77491fSJoe Komlodi }; 363ef77491fSJoe Komlodi 364*a59884aaSJoe Komlodi static void dw_i3c_cmd_queue_execute(DWI3C *s); 365*a59884aaSJoe Komlodi 3669c0476a2SJoe Komlodi static inline bool dw_i3c_has_hdr_ts(DWI3C *s) 3679c0476a2SJoe Komlodi { 3689c0476a2SJoe Komlodi return ARRAY_FIELD_EX32(s->regs, HW_CAPABILITY, HDR_TS); 3699c0476a2SJoe Komlodi } 3709c0476a2SJoe Komlodi 3719c0476a2SJoe Komlodi static inline bool dw_i3c_has_hdr_ddr(DWI3C *s) 3729c0476a2SJoe Komlodi { 3739c0476a2SJoe Komlodi return ARRAY_FIELD_EX32(s->regs, HW_CAPABILITY, HDR_DDR); 3749c0476a2SJoe Komlodi } 3759c0476a2SJoe Komlodi 3769c0476a2SJoe Komlodi static inline bool dw_i3c_can_transmit(DWI3C *s) 3779c0476a2SJoe Komlodi { 3789c0476a2SJoe Komlodi /* 3799c0476a2SJoe Komlodi * We can only transmit if we're enabled and the resume bit is cleared. 3809c0476a2SJoe Komlodi * The resume bit is set on a transaction error, and software must clear it. 3819c0476a2SJoe Komlodi */ 3829c0476a2SJoe Komlodi return ARRAY_FIELD_EX32(s->regs, DEVICE_CTRL, I3C_EN) && 3839c0476a2SJoe Komlodi !ARRAY_FIELD_EX32(s->regs, DEVICE_CTRL, I3C_RESUME); 3849c0476a2SJoe Komlodi } 3859c0476a2SJoe Komlodi 3865a2a5453SJoe Komlodi static inline uint8_t dw_i3c_ibi_slice_size(DWI3C *s) 3875a2a5453SJoe Komlodi { 3885a2a5453SJoe Komlodi uint8_t ibi_slice_size = ARRAY_FIELD_EX32(s->regs, QUEUE_THLD_CTRL, 3895a2a5453SJoe Komlodi IBI_DATA_THLD); 3905a2a5453SJoe Komlodi /* The minimum supported slice size is 4 bytes. */ 3915a2a5453SJoe Komlodi if (ibi_slice_size == 0) { 3925a2a5453SJoe Komlodi ibi_slice_size = 1; 3935a2a5453SJoe Komlodi } 3945a2a5453SJoe Komlodi ibi_slice_size *= sizeof(uint32_t); 3955a2a5453SJoe Komlodi /* maximum supported size is 63 bytes. */ 3965a2a5453SJoe Komlodi if (ibi_slice_size >= 64) { 3975a2a5453SJoe Komlodi ibi_slice_size = 63; 3985a2a5453SJoe Komlodi } 3995a2a5453SJoe Komlodi 4005a2a5453SJoe Komlodi return ibi_slice_size; 4015a2a5453SJoe Komlodi } 4025a2a5453SJoe Komlodi 4039c0476a2SJoe Komlodi static inline uint8_t dw_i3c_fifo_threshold_from_reg(uint8_t regval) 4049c0476a2SJoe Komlodi { 4059c0476a2SJoe Komlodi return regval = regval ? (2 << regval) : 1; 4069c0476a2SJoe Komlodi } 4079c0476a2SJoe Komlodi 408a825bbb7SJoe Komlodi static void dw_i3c_update_irq(DWI3C *s) 409a825bbb7SJoe Komlodi { 410a825bbb7SJoe Komlodi bool level = !!(s->regs[R_INTR_SIGNAL_EN] & s->regs[R_INTR_STATUS]); 411a825bbb7SJoe Komlodi qemu_set_irq(s->irq, level); 412a825bbb7SJoe Komlodi } 413a825bbb7SJoe Komlodi 4149c0476a2SJoe Komlodi static void dw_i3c_end_transfer(DWI3C *s, bool is_i2c) 4159c0476a2SJoe Komlodi { 4169c0476a2SJoe Komlodi if (is_i2c) { 4179c0476a2SJoe Komlodi legacy_i2c_end_transfer(s->bus); 4189c0476a2SJoe Komlodi } else { 4199c0476a2SJoe Komlodi i3c_end_transfer(s->bus); 4209c0476a2SJoe Komlodi } 4219c0476a2SJoe Komlodi } 4229c0476a2SJoe Komlodi 4239c0476a2SJoe Komlodi static int dw_i3c_send_start(DWI3C *s, uint8_t addr, bool is_recv, bool is_i2c) 4249c0476a2SJoe Komlodi { 4259c0476a2SJoe Komlodi int ret; 4269c0476a2SJoe Komlodi 4279c0476a2SJoe Komlodi if (is_i2c) { 4289c0476a2SJoe Komlodi ret = legacy_i2c_start_transfer(s->bus, addr, is_recv); 4299c0476a2SJoe Komlodi } else { 4309c0476a2SJoe Komlodi ret = i3c_start_transfer(s->bus, addr, is_recv); 4319c0476a2SJoe Komlodi } 4329c0476a2SJoe Komlodi if (ret) { 4339c0476a2SJoe Komlodi g_autofree char *path = object_get_canonical_path(OBJECT(s)); 4349c0476a2SJoe Komlodi qemu_log_mask(LOG_GUEST_ERROR, "%s: NACKed on TX with addr 0x%.2x\n", 4359c0476a2SJoe Komlodi path, addr); 4369c0476a2SJoe Komlodi ARRAY_FIELD_DP32(s->regs, PRESENT_STATE, CM_TFR_ST_STATUS, 4379c0476a2SJoe Komlodi DW_I3C_TRANSFER_STATE_HALT); 4389c0476a2SJoe Komlodi ARRAY_FIELD_DP32(s->regs, PRESENT_STATE, CM_TFR_STATUS, 4399c0476a2SJoe Komlodi DW_I3C_TRANSFER_STATUS_HALT); 4409c0476a2SJoe Komlodi ARRAY_FIELD_DP32(s->regs, INTR_STATUS, TRANSFER_ERR, 1); 4419c0476a2SJoe Komlodi ARRAY_FIELD_DP32(s->regs, DEVICE_CTRL, I3C_RESUME, 1); 4429c0476a2SJoe Komlodi } 4439c0476a2SJoe Komlodi 4449c0476a2SJoe Komlodi return ret; 4459c0476a2SJoe Komlodi } 4469c0476a2SJoe Komlodi 4479c0476a2SJoe Komlodi static int dw_i3c_send(DWI3C *s, const uint8_t *data, uint32_t num_to_send, 4489c0476a2SJoe Komlodi uint32_t *num_sent, bool is_i2c) 4499c0476a2SJoe Komlodi { 4509c0476a2SJoe Komlodi int ret; 4519c0476a2SJoe Komlodi uint32_t i; 4529c0476a2SJoe Komlodi 4539c0476a2SJoe Komlodi *num_sent = 0; 4549c0476a2SJoe Komlodi if (is_i2c) { 4559c0476a2SJoe Komlodi /* Legacy I2C must be byte-by-byte. */ 4569c0476a2SJoe Komlodi for (i = 0; i < num_to_send; i++) { 4579c0476a2SJoe Komlodi ret = legacy_i2c_send(s->bus, data[i]); 4589c0476a2SJoe Komlodi if (ret) { 4599c0476a2SJoe Komlodi break; 4609c0476a2SJoe Komlodi } 4619c0476a2SJoe Komlodi (*num_sent)++; 4629c0476a2SJoe Komlodi } 4639c0476a2SJoe Komlodi } else { 4649c0476a2SJoe Komlodi ret = i3c_send(s->bus, data, num_to_send, num_sent); 4659c0476a2SJoe Komlodi } 4669c0476a2SJoe Komlodi if (ret) { 4679c0476a2SJoe Komlodi g_autofree char *path = object_get_canonical_path(OBJECT(s)); 4689c0476a2SJoe Komlodi qemu_log_mask(LOG_GUEST_ERROR, "%s: NACKed sending byte 0x%.2x\n", 4699c0476a2SJoe Komlodi path, data[*num_sent]); 4709c0476a2SJoe Komlodi ARRAY_FIELD_DP32(s->regs, PRESENT_STATE, CM_TFR_ST_STATUS, 4719c0476a2SJoe Komlodi DW_I3C_TRANSFER_STATE_HALT); 4729c0476a2SJoe Komlodi ARRAY_FIELD_DP32(s->regs, PRESENT_STATE, CM_TFR_STATUS, 4739c0476a2SJoe Komlodi DW_I3C_TRANSFER_STATUS_HALT); 4749c0476a2SJoe Komlodi ARRAY_FIELD_DP32(s->regs, INTR_STATUS, TRANSFER_ERR, 1); 4759c0476a2SJoe Komlodi ARRAY_FIELD_DP32(s->regs, DEVICE_CTRL, I3C_RESUME, 1); 4769c0476a2SJoe Komlodi } 4779c0476a2SJoe Komlodi 4789c0476a2SJoe Komlodi trace_dw_i3c_send(s->cfg.id, *num_sent); 4799c0476a2SJoe Komlodi 4809c0476a2SJoe Komlodi return ret; 4819c0476a2SJoe Komlodi } 4829c0476a2SJoe Komlodi 4839c0476a2SJoe Komlodi static int dw_i3c_send_byte(DWI3C *s, uint8_t byte, bool is_i2c) 4849c0476a2SJoe Komlodi { 4859c0476a2SJoe Komlodi /* 4869c0476a2SJoe Komlodi * Ignored, the caller will know if we sent 0 or 1 bytes depending on if 4879c0476a2SJoe Komlodi * we were ACKed/NACKed. 4889c0476a2SJoe Komlodi */ 4899c0476a2SJoe Komlodi uint32_t num_sent; 4909c0476a2SJoe Komlodi return dw_i3c_send(s, &byte, 1, &num_sent, is_i2c); 4919c0476a2SJoe Komlodi } 4929c0476a2SJoe Komlodi 4939c0476a2SJoe Komlodi static int dw_i3c_recv_data(DWI3C *s, bool is_i2c, uint8_t *data, 4949c0476a2SJoe Komlodi uint16_t num_to_read, uint32_t *num_read) 4959c0476a2SJoe Komlodi { 4969c0476a2SJoe Komlodi int ret; 4979c0476a2SJoe Komlodi 4989c0476a2SJoe Komlodi if (is_i2c) { 4999c0476a2SJoe Komlodi for (uint16_t i = 0; i < num_to_read; i++) { 5009c0476a2SJoe Komlodi data[i] = legacy_i2c_recv(s->bus); 5019c0476a2SJoe Komlodi } 5029c0476a2SJoe Komlodi /* I2C devices can neither NACK a read, nor end transfers early. */ 5039c0476a2SJoe Komlodi *num_read = num_to_read; 5049c0476a2SJoe Komlodi trace_dw_i3c_recv_data(s->cfg.id, *num_read); 5059c0476a2SJoe Komlodi return 0; 5069c0476a2SJoe Komlodi } 5079c0476a2SJoe Komlodi /* I3C devices can NACK if the controller sends an unsupported CCC. */ 5089c0476a2SJoe Komlodi ret = i3c_recv(s->bus, data, num_to_read, num_read); 5099c0476a2SJoe Komlodi if (ret) { 5109c0476a2SJoe Komlodi qemu_log_mask(LOG_GUEST_ERROR, "%s: NACKed receiving byte\n", 5119c0476a2SJoe Komlodi object_get_canonical_path(OBJECT(s))); 5129c0476a2SJoe Komlodi ARRAY_FIELD_DP32(s->regs, PRESENT_STATE, CM_TFR_ST_STATUS, 5139c0476a2SJoe Komlodi DW_I3C_TRANSFER_STATE_HALT); 5149c0476a2SJoe Komlodi ARRAY_FIELD_DP32(s->regs, PRESENT_STATE, CM_TFR_STATUS, 5159c0476a2SJoe Komlodi DW_I3C_TRANSFER_STATUS_HALT); 5169c0476a2SJoe Komlodi ARRAY_FIELD_DP32(s->regs, INTR_STATUS, TRANSFER_ERR, 1); 5179c0476a2SJoe Komlodi ARRAY_FIELD_DP32(s->regs, DEVICE_CTRL, I3C_RESUME, 1); 5189c0476a2SJoe Komlodi } 5199c0476a2SJoe Komlodi 5209c0476a2SJoe Komlodi trace_dw_i3c_recv_data(s->cfg.id, *num_read); 5219c0476a2SJoe Komlodi 5229c0476a2SJoe Komlodi return ret; 5239c0476a2SJoe Komlodi } 5249c0476a2SJoe Komlodi 525*a59884aaSJoe Komlodi static void dw_i3c_ctrl_w(DWI3C *s, uint32_t val) 526*a59884aaSJoe Komlodi { 527*a59884aaSJoe Komlodi /* 528*a59884aaSJoe Komlodi * If the user is setting I3C_RESUME, the controller was halted. 529*a59884aaSJoe Komlodi * Try and resume execution and leave the bit cleared. 530*a59884aaSJoe Komlodi */ 531*a59884aaSJoe Komlodi if (FIELD_EX32(val, DEVICE_CTRL, I3C_RESUME)) { 532*a59884aaSJoe Komlodi dw_i3c_cmd_queue_execute(s); 533*a59884aaSJoe Komlodi val = FIELD_DP32(val, DEVICE_CTRL, I3C_RESUME, 0); 534*a59884aaSJoe Komlodi } 535*a59884aaSJoe Komlodi /* 536*a59884aaSJoe Komlodi * I3C_ABORT being set sends an I3C STOP. It's cleared when the STOP is 537*a59884aaSJoe Komlodi * sent. 538*a59884aaSJoe Komlodi */ 539*a59884aaSJoe Komlodi if (FIELD_EX32(val, DEVICE_CTRL, I3C_ABORT)) { 540*a59884aaSJoe Komlodi dw_i3c_end_transfer(s, /*is_i2c=*/true); 541*a59884aaSJoe Komlodi dw_i3c_end_transfer(s, /*is_i2c=*/false); 542*a59884aaSJoe Komlodi val = FIELD_DP32(val, DEVICE_CTRL, I3C_ABORT, 0); 543*a59884aaSJoe Komlodi ARRAY_FIELD_DP32(s->regs, INTR_STATUS, TRANSFER_ABORT, 1); 544*a59884aaSJoe Komlodi dw_i3c_update_irq(s); 545*a59884aaSJoe Komlodi } 546*a59884aaSJoe Komlodi /* Update present state. */ 547*a59884aaSJoe Komlodi ARRAY_FIELD_DP32(s->regs, PRESENT_STATE, CM_TFR_ST_STATUS, 548*a59884aaSJoe Komlodi DW_I3C_TRANSFER_STATE_IDLE); 549*a59884aaSJoe Komlodi ARRAY_FIELD_DP32(s->regs, PRESENT_STATE, CM_TFR_STATUS, 550*a59884aaSJoe Komlodi DW_I3C_TRANSFER_STATUS_IDLE); 551*a59884aaSJoe Komlodi 552*a59884aaSJoe Komlodi s->regs[R_DEVICE_CTRL] = val; 553*a59884aaSJoe Komlodi } 554*a59884aaSJoe Komlodi 5559c0476a2SJoe Komlodi static inline bool dw_i3c_target_is_i2c(DWI3C *s, uint16_t offset) 5569c0476a2SJoe Komlodi { 5579c0476a2SJoe Komlodi /* / sizeof(uint32_t) because we're indexing into our 32-bit reg array. */ 5589c0476a2SJoe Komlodi uint16_t dev_index = (ARRAY_FIELD_EX32(s->regs, DEVICE_ADDR_TABLE_POINTER, 5599c0476a2SJoe Komlodi ADDR) / sizeof(uint32_t)) + offset; 5609c0476a2SJoe Komlodi return FIELD_EX32(s->regs[dev_index], DEVICE_ADDR_TABLE_LOC1, 5619c0476a2SJoe Komlodi LEGACY_I2C_DEVICE); 5629c0476a2SJoe Komlodi } 5639c0476a2SJoe Komlodi 5649c0476a2SJoe Komlodi static uint8_t dw_i3c_target_addr(DWI3C *s, uint16_t offset) 5659c0476a2SJoe Komlodi { 5669c0476a2SJoe Komlodi if (offset > s->cfg.num_addressable_devices) { 5679c0476a2SJoe Komlodi g_autofree char *path = object_get_canonical_path(OBJECT(s)); 5689c0476a2SJoe Komlodi qemu_log_mask(LOG_GUEST_ERROR, "%s: Device addr table offset %d out of " 5699c0476a2SJoe Komlodi "bounds\n", path, offset); 5709c0476a2SJoe Komlodi /* If we're out of bounds, return an address of 0. */ 5719c0476a2SJoe Komlodi return 0; 5729c0476a2SJoe Komlodi } 5739c0476a2SJoe Komlodi 5749c0476a2SJoe Komlodi /* / sizeof(uint32_t) because we're indexing into our 32-bit reg array. */ 5759c0476a2SJoe Komlodi uint16_t dev_index = (ARRAY_FIELD_EX32(s->regs, DEVICE_ADDR_TABLE_POINTER, 5769c0476a2SJoe Komlodi ADDR) / sizeof(uint32_t)) + offset; 5779c0476a2SJoe Komlodi /* I2C devices use a static address. */ 5789c0476a2SJoe Komlodi if (dw_i3c_target_is_i2c(s, offset)) { 5799c0476a2SJoe Komlodi return FIELD_EX32(s->regs[dev_index], DEVICE_ADDR_TABLE_LOC1, 5809c0476a2SJoe Komlodi DEV_STATIC_ADDR); 5819c0476a2SJoe Komlodi } 5829c0476a2SJoe Komlodi return FIELD_EX32(s->regs[dev_index], DEVICE_ADDR_TABLE_LOC1, 5839c0476a2SJoe Komlodi DEV_DYNAMIC_ADDR); 5849c0476a2SJoe Komlodi } 5859c0476a2SJoe Komlodi 5865a2a5453SJoe Komlodi static int dw_i3c_addr_table_index_from_addr(DWI3C *s, uint8_t addr) 5875a2a5453SJoe Komlodi { 5885a2a5453SJoe Komlodi uint8_t table_size = ARRAY_FIELD_EX32(s->regs, DEVICE_ADDR_TABLE_POINTER, 5895a2a5453SJoe Komlodi DEPTH); 5905a2a5453SJoe Komlodi for (uint8_t i = 0; i < table_size; i++) { 5915a2a5453SJoe Komlodi if (dw_i3c_target_addr(s, i) == addr) { 5925a2a5453SJoe Komlodi return i; 5935a2a5453SJoe Komlodi } 5945a2a5453SJoe Komlodi } 5955a2a5453SJoe Komlodi return -1; 5965a2a5453SJoe Komlodi } 5975a2a5453SJoe Komlodi 5985a2a5453SJoe Komlodi static void dw_i3c_send_disec(DWI3C *s) 5995a2a5453SJoe Komlodi { 6005a2a5453SJoe Komlodi uint8_t ccc = I3C_CCC_DISEC; 6015a2a5453SJoe Komlodi if (s->ibi_data.send_direct_disec) { 6025a2a5453SJoe Komlodi ccc = I3C_CCCD_DISEC; 6035a2a5453SJoe Komlodi } 6045a2a5453SJoe Komlodi 6055a2a5453SJoe Komlodi dw_i3c_send_start(s, I3C_BROADCAST, /*is_recv=*/false, 6065a2a5453SJoe Komlodi /*is_i2c=*/false); 6075a2a5453SJoe Komlodi dw_i3c_send_byte(s, ccc, /*is_i2c=*/false); 6085a2a5453SJoe Komlodi if (s->ibi_data.send_direct_disec) { 6095a2a5453SJoe Komlodi dw_i3c_send_start(s, s->ibi_data.disec_addr, 6105a2a5453SJoe Komlodi /*is_recv=*/false, /*is_i2c=*/false); 6115a2a5453SJoe Komlodi } 6125a2a5453SJoe Komlodi dw_i3c_send_byte(s, s->ibi_data.disec_byte, /*is_i2c=*/false); 6135a2a5453SJoe Komlodi } 6145a2a5453SJoe Komlodi 6155a2a5453SJoe Komlodi static int dw_i3c_handle_hj(DWI3C *s) 6165a2a5453SJoe Komlodi { 6175a2a5453SJoe Komlodi if (ARRAY_FIELD_EX32(s->regs, IBI_QUEUE_CTRL, NOTIFY_REJECTED_HOT_JOIN)) { 6185a2a5453SJoe Komlodi s->ibi_data.notify_ibi_nack = true; 6195a2a5453SJoe Komlodi } 6205a2a5453SJoe Komlodi 6215a2a5453SJoe Komlodi bool nack_and_disable = ARRAY_FIELD_EX32(s->regs, DEVICE_CTRL, 6225a2a5453SJoe Komlodi HOT_JOIN_ACK_NACK_CTRL); 6235a2a5453SJoe Komlodi if (nack_and_disable) { 6245a2a5453SJoe Komlodi s->ibi_data.ibi_queue_status = FIELD_DP32(s->ibi_data.ibi_queue_status, 6255a2a5453SJoe Komlodi IBI_QUEUE_STATUS, 6265a2a5453SJoe Komlodi IBI_STATUS, 1); 6275a2a5453SJoe Komlodi s->ibi_data.ibi_nacked = true; 6285a2a5453SJoe Komlodi s->ibi_data.disec_byte = DISEC_HJ; 6295a2a5453SJoe Komlodi return -1; 6305a2a5453SJoe Komlodi } 6315a2a5453SJoe Komlodi return 0; 6325a2a5453SJoe Komlodi } 6335a2a5453SJoe Komlodi 6345a2a5453SJoe Komlodi static int dw_i3c_handle_ctlr_req(DWI3C *s, uint8_t addr) 6355a2a5453SJoe Komlodi { 6365a2a5453SJoe Komlodi if (ARRAY_FIELD_EX32(s->regs, IBI_QUEUE_CTRL, NOTIFY_REJECTED_MASTER_REQ)) { 6375a2a5453SJoe Komlodi s->ibi_data.notify_ibi_nack = true; 6385a2a5453SJoe Komlodi } 6395a2a5453SJoe Komlodi 6405a2a5453SJoe Komlodi int table_offset = dw_i3c_addr_table_index_from_addr(s, addr); 6415a2a5453SJoe Komlodi /* Doesn't exist in the table, NACK it, don't DISEC. */ 6425a2a5453SJoe Komlodi if (table_offset < 0) { 6435a2a5453SJoe Komlodi return -1; 6445a2a5453SJoe Komlodi } 6455a2a5453SJoe Komlodi 6465a2a5453SJoe Komlodi /* / sizeof(uint32_t) because we're indexing into our 32-bit reg array. */ 6475a2a5453SJoe Komlodi table_offset += (ARRAY_FIELD_EX32(s->regs, DEVICE_ADDR_TABLE_POINTER, 6485a2a5453SJoe Komlodi ADDR) / sizeof(uint32_t)); 6495a2a5453SJoe Komlodi if (FIELD_EX32(s->regs[table_offset], DEVICE_ADDR_TABLE_LOC1, MR_REJECT)) { 6505a2a5453SJoe Komlodi s->ibi_data.ibi_queue_status = FIELD_DP32(s->ibi_data.ibi_queue_status, 6515a2a5453SJoe Komlodi IBI_QUEUE_STATUS, 6525a2a5453SJoe Komlodi IBI_STATUS, 1); 6535a2a5453SJoe Komlodi s->ibi_data.ibi_nacked = true; 6545a2a5453SJoe Komlodi s->ibi_data.disec_addr = addr; 6555a2a5453SJoe Komlodi /* Tell the requester to disable controller role requests. */ 6565a2a5453SJoe Komlodi s->ibi_data.disec_byte = DISEC_CR; 6575a2a5453SJoe Komlodi s->ibi_data.send_direct_disec = true; 6585a2a5453SJoe Komlodi return -1; 6595a2a5453SJoe Komlodi } 6605a2a5453SJoe Komlodi return 0; 6615a2a5453SJoe Komlodi } 6625a2a5453SJoe Komlodi 6635a2a5453SJoe Komlodi static int dw_i3c_handle_targ_irq(DWI3C *s, uint8_t addr) 6645a2a5453SJoe Komlodi { 6655a2a5453SJoe Komlodi if (ARRAY_FIELD_EX32(s->regs, IBI_QUEUE_CTRL, NOTIFY_REJECTED_SLAVE_IRQ)) { 6665a2a5453SJoe Komlodi s->ibi_data.notify_ibi_nack = true; 6675a2a5453SJoe Komlodi } 6685a2a5453SJoe Komlodi 6695a2a5453SJoe Komlodi int table_offset = dw_i3c_addr_table_index_from_addr(s, addr); 6705a2a5453SJoe Komlodi /* Doesn't exist in the table, NACK it, don't DISEC. */ 6715a2a5453SJoe Komlodi if (table_offset < 0) { 6725a2a5453SJoe Komlodi return -1; 6735a2a5453SJoe Komlodi } 6745a2a5453SJoe Komlodi 6755a2a5453SJoe Komlodi /* / sizeof(uint32_t) because we're indexing into our 32-bit reg array. */ 6765a2a5453SJoe Komlodi table_offset += (ARRAY_FIELD_EX32(s->regs, DEVICE_ADDR_TABLE_POINTER, 6775a2a5453SJoe Komlodi ADDR) / sizeof(uint32_t)); 6785a2a5453SJoe Komlodi if (FIELD_EX32(s->regs[table_offset], DEVICE_ADDR_TABLE_LOC1, SIR_REJECT)) { 6795a2a5453SJoe Komlodi s->ibi_data.ibi_queue_status = FIELD_DP32(s->ibi_data.ibi_queue_status, 6805a2a5453SJoe Komlodi IBI_QUEUE_STATUS, 6815a2a5453SJoe Komlodi IBI_STATUS, 1); 6825a2a5453SJoe Komlodi s->ibi_data.ibi_nacked = true; 6835a2a5453SJoe Komlodi s->ibi_data.disec_addr = addr; 6845a2a5453SJoe Komlodi /* Tell the requester to disable interrupts. */ 6855a2a5453SJoe Komlodi s->ibi_data.disec_byte = DISEC_INT; 6865a2a5453SJoe Komlodi s->ibi_data.send_direct_disec = true; 6875a2a5453SJoe Komlodi return -1; 6885a2a5453SJoe Komlodi } 6895a2a5453SJoe Komlodi return 0; 6905a2a5453SJoe Komlodi } 6915a2a5453SJoe Komlodi 6925a2a5453SJoe Komlodi static int dw_i3c_ibi_handle(I3CBus *bus, uint8_t addr, bool is_recv) 6935a2a5453SJoe Komlodi { 6945a2a5453SJoe Komlodi DWI3C *s = DW_I3C(bus->qbus.parent); 6955a2a5453SJoe Komlodi 6965a2a5453SJoe Komlodi trace_dw_i3c_ibi_handle(s->cfg.id, addr, is_recv); 6975a2a5453SJoe Komlodi s->ibi_data.ibi_queue_status = FIELD_DP32(s->ibi_data.ibi_queue_status, 6985a2a5453SJoe Komlodi IBI_QUEUE_STATUS, IBI_ID, 6995a2a5453SJoe Komlodi (addr << 1) | is_recv); 7005a2a5453SJoe Komlodi /* Is this a hot join request? */ 7015a2a5453SJoe Komlodi if (addr == I3C_HJ_ADDR) { 7025a2a5453SJoe Komlodi return dw_i3c_handle_hj(s); 7035a2a5453SJoe Komlodi } 7045a2a5453SJoe Komlodi /* Is secondary controller requesting access? */ 7055a2a5453SJoe Komlodi if (!is_recv) { 7065a2a5453SJoe Komlodi return dw_i3c_handle_ctlr_req(s, addr); 7075a2a5453SJoe Komlodi } 7085a2a5453SJoe Komlodi /* Is this a target IRQ? */ 7095a2a5453SJoe Komlodi if (is_recv) { 7105a2a5453SJoe Komlodi return dw_i3c_handle_targ_irq(s, addr); 7115a2a5453SJoe Komlodi } 7125a2a5453SJoe Komlodi 7135a2a5453SJoe Komlodi /* At this point the IBI should have been ACKed or NACKed. */ 7145a2a5453SJoe Komlodi g_assert_not_reached(); 7155a2a5453SJoe Komlodi return -1; 7165a2a5453SJoe Komlodi } 7175a2a5453SJoe Komlodi 7185a2a5453SJoe Komlodi static int dw_i3c_ibi_recv(I3CBus *bus, uint8_t data) 7195a2a5453SJoe Komlodi { 7205a2a5453SJoe Komlodi DWI3C *s = DW_I3C(bus->qbus.parent); 7215a2a5453SJoe Komlodi if (fifo8_is_full(&s->ibi_data.ibi_intermediate_queue)) { 7225a2a5453SJoe Komlodi return -1; 7235a2a5453SJoe Komlodi } 7245a2a5453SJoe Komlodi 7255a2a5453SJoe Komlodi fifo8_push(&s->ibi_data.ibi_intermediate_queue, data); 7265a2a5453SJoe Komlodi trace_dw_i3c_ibi_recv(s->cfg.id, data); 7275a2a5453SJoe Komlodi return 0; 7285a2a5453SJoe Komlodi } 7295a2a5453SJoe Komlodi 7305a2a5453SJoe Komlodi static void dw_i3c_ibi_queue_push(DWI3C *s) 7315a2a5453SJoe Komlodi { 7325a2a5453SJoe Komlodi /* Stored value is in 32-bit chunks, convert it to byte chunks. */ 7335a2a5453SJoe Komlodi uint8_t ibi_slice_size = dw_i3c_ibi_slice_size(s); 7345a2a5453SJoe Komlodi uint8_t num_slices = (fifo8_num_used(&s->ibi_data.ibi_intermediate_queue) / 7355a2a5453SJoe Komlodi ibi_slice_size) + 7365a2a5453SJoe Komlodi ((fifo8_num_used(&s->ibi_data.ibi_intermediate_queue) % 7375a2a5453SJoe Komlodi ibi_slice_size) ? 1 : 0); 7385a2a5453SJoe Komlodi uint8_t ibi_status_count = num_slices; 7395a2a5453SJoe Komlodi union { 7405a2a5453SJoe Komlodi uint8_t b[sizeof(uint32_t)]; 7415a2a5453SJoe Komlodi uint32_t val32; 7425a2a5453SJoe Komlodi } ibi_data = { 7435a2a5453SJoe Komlodi .val32 = 0 7445a2a5453SJoe Komlodi }; 7455a2a5453SJoe Komlodi 7465a2a5453SJoe Komlodi /* The report was suppressed, do nothing. */ 7475a2a5453SJoe Komlodi if (s->ibi_data.ibi_nacked && !s->ibi_data.notify_ibi_nack) { 7485a2a5453SJoe Komlodi ARRAY_FIELD_DP32(s->regs, PRESENT_STATE, CM_TFR_ST_STATUS, 7495a2a5453SJoe Komlodi DW_I3C_TRANSFER_STATE_IDLE); 7505a2a5453SJoe Komlodi ARRAY_FIELD_DP32(s->regs, PRESENT_STATE, CM_TFR_STATUS, 7515a2a5453SJoe Komlodi DW_I3C_TRANSFER_STATUS_IDLE); 7525a2a5453SJoe Komlodi return; 7535a2a5453SJoe Komlodi } 7545a2a5453SJoe Komlodi 7555a2a5453SJoe Komlodi /* If we don't have any slices to push, just push the status. */ 7565a2a5453SJoe Komlodi if (num_slices == 0) { 7575a2a5453SJoe Komlodi s->ibi_data.ibi_queue_status = 7585a2a5453SJoe Komlodi FIELD_DP32(s->ibi_data.ibi_queue_status, IBI_QUEUE_STATUS, 7595a2a5453SJoe Komlodi LAST_STATUS, 1); 7605a2a5453SJoe Komlodi fifo32_push(&s->ibi_queue, s->ibi_data.ibi_queue_status); 7615a2a5453SJoe Komlodi ibi_status_count = 1; 7625a2a5453SJoe Komlodi } 7635a2a5453SJoe Komlodi 7645a2a5453SJoe Komlodi for (uint8_t i = 0; i < num_slices; i++) { 7655a2a5453SJoe Komlodi /* If this is the last slice, set LAST_STATUS. */ 7665a2a5453SJoe Komlodi if (fifo8_num_used(&s->ibi_data.ibi_intermediate_queue) < 7675a2a5453SJoe Komlodi ibi_slice_size) { 7685a2a5453SJoe Komlodi s->ibi_data.ibi_queue_status = 7695a2a5453SJoe Komlodi FIELD_DP32(s->ibi_data.ibi_queue_status, IBI_QUEUE_STATUS, 7705a2a5453SJoe Komlodi IBI_DATA_LEN, 7715a2a5453SJoe Komlodi fifo8_num_used(&s->ibi_data.ibi_intermediate_queue)); 7725a2a5453SJoe Komlodi s->ibi_data.ibi_queue_status = 7735a2a5453SJoe Komlodi FIELD_DP32(s->ibi_data.ibi_queue_status, IBI_QUEUE_STATUS, 7745a2a5453SJoe Komlodi LAST_STATUS, 1); 7755a2a5453SJoe Komlodi } else { 7765a2a5453SJoe Komlodi s->ibi_data.ibi_queue_status = 7775a2a5453SJoe Komlodi FIELD_DP32(s->ibi_data.ibi_queue_status, IBI_QUEUE_STATUS, 7785a2a5453SJoe Komlodi IBI_DATA_LEN, ibi_slice_size); 7795a2a5453SJoe Komlodi } 7805a2a5453SJoe Komlodi 7815a2a5453SJoe Komlodi /* Push the IBI status header. */ 7825a2a5453SJoe Komlodi fifo32_push(&s->ibi_queue, s->ibi_data.ibi_queue_status); 7835a2a5453SJoe Komlodi /* Move each IBI byte into a 32-bit word and push it into the queue. */ 7845a2a5453SJoe Komlodi for (uint8_t j = 0; j < ibi_slice_size; ++j) { 7855a2a5453SJoe Komlodi if (fifo8_is_empty(&s->ibi_data.ibi_intermediate_queue)) { 7865a2a5453SJoe Komlodi break; 7875a2a5453SJoe Komlodi } 7885a2a5453SJoe Komlodi 7895a2a5453SJoe Komlodi ibi_data.b[j & 3] = fifo8_pop(&s->ibi_data.ibi_intermediate_queue); 7905a2a5453SJoe Komlodi /* We have 32-bits, push it to the IBI FIFO. */ 7915a2a5453SJoe Komlodi if ((j & 0x03) == 0x03) { 7925a2a5453SJoe Komlodi fifo32_push(&s->ibi_queue, ibi_data.val32); 7935a2a5453SJoe Komlodi ibi_data.val32 = 0; 7945a2a5453SJoe Komlodi } 7955a2a5453SJoe Komlodi } 7965a2a5453SJoe Komlodi /* If the data isn't 32-bit aligned, push the leftover bytes. */ 7975a2a5453SJoe Komlodi if (ibi_slice_size & 0x03) { 7985a2a5453SJoe Komlodi fifo32_push(&s->ibi_queue, ibi_data.val32); 7995a2a5453SJoe Komlodi } 8005a2a5453SJoe Komlodi 8015a2a5453SJoe Komlodi /* Clear out the data length for the next iteration. */ 8025a2a5453SJoe Komlodi s->ibi_data.ibi_queue_status = FIELD_DP32(s->ibi_data.ibi_queue_status, 8035a2a5453SJoe Komlodi IBI_QUEUE_STATUS, IBI_DATA_LEN, 0); 8045a2a5453SJoe Komlodi } 8055a2a5453SJoe Komlodi 8065a2a5453SJoe Komlodi ARRAY_FIELD_DP32(s->regs, QUEUE_STATUS_LEVEL, IBI_BUF_BLR, 8075a2a5453SJoe Komlodi fifo32_num_used(&s->ibi_queue)); 8085a2a5453SJoe Komlodi ARRAY_FIELD_DP32(s->regs, QUEUE_STATUS_LEVEL, IBI_STATUS_CNT, 8095a2a5453SJoe Komlodi ibi_status_count); 8105a2a5453SJoe Komlodi /* Threshold is the register value + 1. */ 8115a2a5453SJoe Komlodi uint8_t threshold = ARRAY_FIELD_EX32(s->regs, QUEUE_THLD_CTRL, 8125a2a5453SJoe Komlodi IBI_STATUS_THLD) + 1; 8135a2a5453SJoe Komlodi if (fifo32_num_used(&s->ibi_queue) >= threshold) { 8145a2a5453SJoe Komlodi ARRAY_FIELD_DP32(s->regs, INTR_STATUS, IBI_THLD, 1); 8155a2a5453SJoe Komlodi dw_i3c_update_irq(s); 8165a2a5453SJoe Komlodi } 8175a2a5453SJoe Komlodi 8185a2a5453SJoe Komlodi /* State update. */ 8195a2a5453SJoe Komlodi ARRAY_FIELD_DP32(s->regs, PRESENT_STATE, CM_TFR_ST_STATUS, 8205a2a5453SJoe Komlodi DW_I3C_TRANSFER_STATE_IDLE); 8215a2a5453SJoe Komlodi ARRAY_FIELD_DP32(s->regs, PRESENT_STATE, CM_TFR_STATUS, 8225a2a5453SJoe Komlodi DW_I3C_TRANSFER_STATUS_IDLE); 8235a2a5453SJoe Komlodi } 8245a2a5453SJoe Komlodi 8255a2a5453SJoe Komlodi static int dw_i3c_ibi_finish(I3CBus *bus) 8265a2a5453SJoe Komlodi { 8275a2a5453SJoe Komlodi DWI3C *s = DW_I3C(bus->qbus.parent); 8285a2a5453SJoe Komlodi bool nack_and_disable_hj = ARRAY_FIELD_EX32(s->regs, DEVICE_CTRL, 8295a2a5453SJoe Komlodi HOT_JOIN_ACK_NACK_CTRL); 8305a2a5453SJoe Komlodi if (nack_and_disable_hj || s->ibi_data.send_direct_disec) { 8315a2a5453SJoe Komlodi dw_i3c_send_disec(s); 8325a2a5453SJoe Komlodi } 8335a2a5453SJoe Komlodi dw_i3c_ibi_queue_push(s); 8345a2a5453SJoe Komlodi 8355a2a5453SJoe Komlodi /* Clear out the intermediate values. */ 8365a2a5453SJoe Komlodi s->ibi_data.ibi_queue_status = 0; 8375a2a5453SJoe Komlodi s->ibi_data.disec_addr = 0; 8385a2a5453SJoe Komlodi s->ibi_data.disec_byte = 0; 8395a2a5453SJoe Komlodi s->ibi_data.send_direct_disec = false; 8405a2a5453SJoe Komlodi s->ibi_data.notify_ibi_nack = false; 8415a2a5453SJoe Komlodi s->ibi_data.ibi_nacked = false; 8425a2a5453SJoe Komlodi 8435a2a5453SJoe Komlodi return 0; 8445a2a5453SJoe Komlodi } 8455a2a5453SJoe Komlodi 846a825bbb7SJoe Komlodi static uint32_t dw_i3c_intr_status_r(DWI3C *s) 847a825bbb7SJoe Komlodi { 848a825bbb7SJoe Komlodi /* Only return the status whose corresponding EN bits are set. */ 849a825bbb7SJoe Komlodi return s->regs[R_INTR_STATUS] & s->regs[R_INTR_STATUS_EN]; 850a825bbb7SJoe Komlodi } 851a825bbb7SJoe Komlodi 852a825bbb7SJoe Komlodi static void dw_i3c_intr_status_w(DWI3C *s, uint32_t val) 853a825bbb7SJoe Komlodi { 854a825bbb7SJoe Komlodi /* INTR_STATUS[13:5] is w1c, other bits are RO. */ 855a825bbb7SJoe Komlodi val &= 0x3fe0; 856a825bbb7SJoe Komlodi s->regs[R_INTR_STATUS] &= ~val; 857a825bbb7SJoe Komlodi 858a825bbb7SJoe Komlodi dw_i3c_update_irq(s); 859a825bbb7SJoe Komlodi } 860a825bbb7SJoe Komlodi 861a825bbb7SJoe Komlodi static void dw_i3c_intr_status_en_w(DWI3C *s, uint32_t val) 862a825bbb7SJoe Komlodi { 863a825bbb7SJoe Komlodi s->regs[R_INTR_STATUS_EN] = val; 864a825bbb7SJoe Komlodi dw_i3c_update_irq(s); 865a825bbb7SJoe Komlodi } 866a825bbb7SJoe Komlodi 867a825bbb7SJoe Komlodi static void dw_i3c_intr_signal_en_w(DWI3C *s, uint32_t val) 868a825bbb7SJoe Komlodi { 869a825bbb7SJoe Komlodi s->regs[R_INTR_SIGNAL_EN] = val; 870a825bbb7SJoe Komlodi dw_i3c_update_irq(s); 871a825bbb7SJoe Komlodi } 872a825bbb7SJoe Komlodi 873a825bbb7SJoe Komlodi static void dw_i3c_intr_force_w(DWI3C *s, uint32_t val) 874a825bbb7SJoe Komlodi { 875a825bbb7SJoe Komlodi /* INTR_FORCE is WO, just set the corresponding INTR_STATUS bits. */ 876a825bbb7SJoe Komlodi s->regs[R_INTR_STATUS] = val; 877a825bbb7SJoe Komlodi dw_i3c_update_irq(s); 878a825bbb7SJoe Komlodi } 879a825bbb7SJoe Komlodi 8809c0476a2SJoe Komlodi static uint32_t dw_i3c_pop_rx(DWI3C *s) 8819c0476a2SJoe Komlodi { 8829c0476a2SJoe Komlodi if (fifo32_is_empty(&s->rx_queue)) { 8839c0476a2SJoe Komlodi g_autofree char *path = object_get_canonical_path(OBJECT(s)); 8849c0476a2SJoe Komlodi qemu_log_mask(LOG_GUEST_ERROR, "%s: Tried to read RX FIFO when empty\n", 8859c0476a2SJoe Komlodi path); 8869c0476a2SJoe Komlodi return 0; 8879c0476a2SJoe Komlodi } 8889c0476a2SJoe Komlodi 8899c0476a2SJoe Komlodi uint32_t val = fifo32_pop(&s->rx_queue); 8909c0476a2SJoe Komlodi ARRAY_FIELD_DP32(s->regs, DATA_BUFFER_STATUS_LEVEL, RX_BUF_BLR, 8919c0476a2SJoe Komlodi fifo32_num_used(&s->rx_queue)); 8929c0476a2SJoe Komlodi 8939c0476a2SJoe Komlodi /* Threshold is 2^RX_BUF_THLD. */ 8949c0476a2SJoe Komlodi uint8_t threshold = ARRAY_FIELD_EX32(s->regs, DATA_BUFFER_THLD_CTRL, 8959c0476a2SJoe Komlodi RX_BUF_THLD); 8969c0476a2SJoe Komlodi threshold = dw_i3c_fifo_threshold_from_reg(threshold); 8979c0476a2SJoe Komlodi if (fifo32_num_used(&s->rx_queue) < threshold) { 8989c0476a2SJoe Komlodi ARRAY_FIELD_DP32(s->regs, INTR_STATUS, RX_THLD, 0); 8999c0476a2SJoe Komlodi dw_i3c_update_irq(s); 9009c0476a2SJoe Komlodi } 9019c0476a2SJoe Komlodi 9029c0476a2SJoe Komlodi trace_dw_i3c_pop_rx(s->cfg.id, val); 9039c0476a2SJoe Komlodi return val; 9049c0476a2SJoe Komlodi } 9059c0476a2SJoe Komlodi 9065a2a5453SJoe Komlodi static uint32_t dw_i3c_ibi_queue_r(DWI3C *s) 9075a2a5453SJoe Komlodi { 9085a2a5453SJoe Komlodi if (fifo32_is_empty(&s->ibi_queue)) { 9095a2a5453SJoe Komlodi return 0; 9105a2a5453SJoe Komlodi } 9115a2a5453SJoe Komlodi 9125a2a5453SJoe Komlodi uint32_t val = fifo32_pop(&s->ibi_queue); 9135a2a5453SJoe Komlodi ARRAY_FIELD_DP32(s->regs, QUEUE_STATUS_LEVEL, IBI_BUF_BLR, 9145a2a5453SJoe Komlodi fifo32_num_used(&s->ibi_queue)); 9155a2a5453SJoe Komlodi /* Threshold is the register value + 1. */ 9165a2a5453SJoe Komlodi uint8_t threshold = ARRAY_FIELD_EX32(s->regs, QUEUE_THLD_CTRL, 9175a2a5453SJoe Komlodi IBI_STATUS_THLD) + 1; 9185a2a5453SJoe Komlodi if (fifo32_num_used(&s->ibi_queue) < threshold) { 9195a2a5453SJoe Komlodi ARRAY_FIELD_DP32(s->regs, INTR_STATUS, IBI_THLD, 0); 9205a2a5453SJoe Komlodi dw_i3c_update_irq(s); 9215a2a5453SJoe Komlodi } 9225a2a5453SJoe Komlodi return val; 9235a2a5453SJoe Komlodi } 9245a2a5453SJoe Komlodi 9259c0476a2SJoe Komlodi static uint32_t dw_i3c_resp_queue_port_r(DWI3C *s) 9269c0476a2SJoe Komlodi { 9279c0476a2SJoe Komlodi if (fifo32_is_empty(&s->resp_queue)) { 9289c0476a2SJoe Komlodi g_autofree char *path = object_get_canonical_path(OBJECT(s)); 9299c0476a2SJoe Komlodi qemu_log_mask(LOG_GUEST_ERROR, "%s: Tried to read response FIFO when " 9309c0476a2SJoe Komlodi "empty\n", path); 9319c0476a2SJoe Komlodi return 0; 9329c0476a2SJoe Komlodi } 9339c0476a2SJoe Komlodi 9349c0476a2SJoe Komlodi uint32_t val = fifo32_pop(&s->resp_queue); 9359c0476a2SJoe Komlodi ARRAY_FIELD_DP32(s->regs, QUEUE_STATUS_LEVEL, RESP_BUF_BLR, 9369c0476a2SJoe Komlodi fifo32_num_used(&s->resp_queue)); 9379c0476a2SJoe Komlodi 9389c0476a2SJoe Komlodi /* Threshold is the register value + 1. */ 9399c0476a2SJoe Komlodi uint8_t threshold = ARRAY_FIELD_EX32(s->regs, QUEUE_THLD_CTRL, 9409c0476a2SJoe Komlodi RESP_BUF_THLD) + 1; 9419c0476a2SJoe Komlodi if (fifo32_num_used(&s->resp_queue) < threshold) { 9429c0476a2SJoe Komlodi ARRAY_FIELD_DP32(s->regs, INTR_STATUS, RESP_RDY, 0); 9439c0476a2SJoe Komlodi dw_i3c_update_irq(s); 9449c0476a2SJoe Komlodi } 9459c0476a2SJoe Komlodi 9469c0476a2SJoe Komlodi return val; 9479c0476a2SJoe Komlodi } 9489c0476a2SJoe Komlodi 949c52aaabdSJoe Komlodi static uint64_t dw_i3c_read(void *opaque, hwaddr offset, unsigned size) 950c52aaabdSJoe Komlodi { 951c52aaabdSJoe Komlodi DWI3C *s = DW_I3C(opaque); 952c52aaabdSJoe Komlodi uint32_t addr = offset >> 2; 953c52aaabdSJoe Komlodi uint64_t value; 954c52aaabdSJoe Komlodi 955c52aaabdSJoe Komlodi switch (addr) { 9565f31322eSJoe Komlodi /* RAZ */ 957c52aaabdSJoe Komlodi case R_COMMAND_QUEUE_PORT: 9585f31322eSJoe Komlodi case R_RESET_CTRL: 9595f31322eSJoe Komlodi case R_INTR_FORCE: 960c52aaabdSJoe Komlodi value = 0; 961c52aaabdSJoe Komlodi break; 9625a2a5453SJoe Komlodi case R_IBI_QUEUE_DATA: 9635a2a5453SJoe Komlodi value = dw_i3c_ibi_queue_r(s); 9645a2a5453SJoe Komlodi break; 965a825bbb7SJoe Komlodi case R_INTR_STATUS: 966a825bbb7SJoe Komlodi value = dw_i3c_intr_status_r(s); 967a825bbb7SJoe Komlodi break; 9689c0476a2SJoe Komlodi case R_RX_TX_DATA_PORT: 9699c0476a2SJoe Komlodi value = dw_i3c_pop_rx(s); 9709c0476a2SJoe Komlodi break; 9719c0476a2SJoe Komlodi case R_RESPONSE_QUEUE_PORT: 9729c0476a2SJoe Komlodi value = dw_i3c_resp_queue_port_r(s); 9739c0476a2SJoe Komlodi break; 974c52aaabdSJoe Komlodi default: 975c52aaabdSJoe Komlodi value = s->regs[addr]; 976c52aaabdSJoe Komlodi break; 977c52aaabdSJoe Komlodi } 978c52aaabdSJoe Komlodi 9799c0476a2SJoe Komlodi trace_dw_i3c_read(s->cfg.id, offset, value); 980c52aaabdSJoe Komlodi 981c52aaabdSJoe Komlodi return value; 982c52aaabdSJoe Komlodi } 983c52aaabdSJoe Komlodi 9849c0476a2SJoe Komlodi static void dw_i3c_resp_queue_push(DWI3C *s, uint8_t err, uint8_t tid, 9859c0476a2SJoe Komlodi uint8_t ccc_type, uint16_t data_len) 9869c0476a2SJoe Komlodi { 9879c0476a2SJoe Komlodi uint32_t val = 0; 9889c0476a2SJoe Komlodi val = FIELD_DP32(val, RESPONSE_QUEUE_PORT, ERR_STATUS, err); 9899c0476a2SJoe Komlodi val = FIELD_DP32(val, RESPONSE_QUEUE_PORT, TID, tid); 9909c0476a2SJoe Komlodi val = FIELD_DP32(val, RESPONSE_QUEUE_PORT, CCCT, ccc_type); 9919c0476a2SJoe Komlodi val = FIELD_DP32(val, RESPONSE_QUEUE_PORT, DL, data_len); 9929c0476a2SJoe Komlodi if (!fifo32_is_full(&s->resp_queue)) { 9939c0476a2SJoe Komlodi trace_dw_i3c_resp_queue_push(s->cfg.id, val); 9949c0476a2SJoe Komlodi fifo32_push(&s->resp_queue, val); 9959c0476a2SJoe Komlodi } 9969c0476a2SJoe Komlodi 9979c0476a2SJoe Komlodi ARRAY_FIELD_DP32(s->regs, QUEUE_STATUS_LEVEL, RESP_BUF_BLR, 9989c0476a2SJoe Komlodi fifo32_num_used(&s->resp_queue)); 9999c0476a2SJoe Komlodi /* Threshold is the register value + 1. */ 10009c0476a2SJoe Komlodi uint8_t threshold = ARRAY_FIELD_EX32(s->regs, QUEUE_THLD_CTRL, 10019c0476a2SJoe Komlodi RESP_BUF_THLD) + 1; 10029c0476a2SJoe Komlodi if (fifo32_num_used(&s->resp_queue) >= threshold) { 10039c0476a2SJoe Komlodi ARRAY_FIELD_DP32(s->regs, INTR_STATUS, RESP_RDY, 1); 10049c0476a2SJoe Komlodi dw_i3c_update_irq(s); 10059c0476a2SJoe Komlodi } 10069c0476a2SJoe Komlodi } 10079c0476a2SJoe Komlodi 10089c0476a2SJoe Komlodi static void dw_i3c_push_tx(DWI3C *s, uint32_t val) 10099c0476a2SJoe Komlodi { 10109c0476a2SJoe Komlodi if (fifo32_is_full(&s->tx_queue)) { 10119c0476a2SJoe Komlodi qemu_log_mask(LOG_GUEST_ERROR, "%s: Tried to push to TX FIFO when " 10129c0476a2SJoe Komlodi "full\n", object_get_canonical_path(OBJECT(s))); 10139c0476a2SJoe Komlodi return; 10149c0476a2SJoe Komlodi } 10159c0476a2SJoe Komlodi 10169c0476a2SJoe Komlodi trace_dw_i3c_push_tx(s->cfg.id, val); 10179c0476a2SJoe Komlodi fifo32_push(&s->tx_queue, val); 10189c0476a2SJoe Komlodi ARRAY_FIELD_DP32(s->regs, DATA_BUFFER_STATUS_LEVEL, TX_BUF_EMPTY_LOC, 10199c0476a2SJoe Komlodi fifo32_num_free(&s->tx_queue)); 10209c0476a2SJoe Komlodi 10219c0476a2SJoe Komlodi /* Threshold is 2^TX_BUF_THLD. */ 10229c0476a2SJoe Komlodi uint8_t empty_threshold = ARRAY_FIELD_EX32(s->regs, DATA_BUFFER_THLD_CTRL, 10239c0476a2SJoe Komlodi TX_BUF_THLD); 10249c0476a2SJoe Komlodi empty_threshold = 10259c0476a2SJoe Komlodi dw_i3c_fifo_threshold_from_reg(empty_threshold); 10269c0476a2SJoe Komlodi if (fifo32_num_free(&s->tx_queue) < empty_threshold) { 10279c0476a2SJoe Komlodi ARRAY_FIELD_DP32(s->regs, INTR_STATUS, TX_THLD, 0); 10289c0476a2SJoe Komlodi dw_i3c_update_irq(s); 10299c0476a2SJoe Komlodi } 10309c0476a2SJoe Komlodi } 10319c0476a2SJoe Komlodi 10329c0476a2SJoe Komlodi static uint32_t dw_i3c_pop_tx(DWI3C *s) 10339c0476a2SJoe Komlodi { 10349c0476a2SJoe Komlodi if (fifo32_is_empty(&s->tx_queue)) { 10359c0476a2SJoe Komlodi g_autofree char *path = object_get_canonical_path(OBJECT(s)); 10369c0476a2SJoe Komlodi qemu_log_mask(LOG_GUEST_ERROR, "%s: Tried to pop from TX FIFO when " 10379c0476a2SJoe Komlodi "empty\n", path); 10389c0476a2SJoe Komlodi return 0; 10399c0476a2SJoe Komlodi } 10409c0476a2SJoe Komlodi 10419c0476a2SJoe Komlodi uint32_t val = fifo32_pop(&s->tx_queue); 10429c0476a2SJoe Komlodi trace_dw_i3c_pop_tx(s->cfg.id, val); 10439c0476a2SJoe Komlodi ARRAY_FIELD_DP32(s->regs, DATA_BUFFER_STATUS_LEVEL, TX_BUF_EMPTY_LOC, 10449c0476a2SJoe Komlodi fifo32_num_free(&s->tx_queue)); 10459c0476a2SJoe Komlodi 10469c0476a2SJoe Komlodi /* Threshold is 2^TX_BUF_THLD. */ 10479c0476a2SJoe Komlodi uint8_t empty_threshold = ARRAY_FIELD_EX32(s->regs, DATA_BUFFER_THLD_CTRL, 10489c0476a2SJoe Komlodi TX_BUF_THLD); 10499c0476a2SJoe Komlodi empty_threshold = 10509c0476a2SJoe Komlodi dw_i3c_fifo_threshold_from_reg(empty_threshold); 10519c0476a2SJoe Komlodi if (fifo32_num_free(&s->tx_queue) >= empty_threshold) { 10529c0476a2SJoe Komlodi ARRAY_FIELD_DP32(s->regs, INTR_STATUS, TX_THLD, 1); 10539c0476a2SJoe Komlodi dw_i3c_update_irq(s); 10549c0476a2SJoe Komlodi } 10559c0476a2SJoe Komlodi return val; 10569c0476a2SJoe Komlodi } 10579c0476a2SJoe Komlodi 10589c0476a2SJoe Komlodi static void dw_i3c_push_rx(DWI3C *s, uint32_t val) 10599c0476a2SJoe Komlodi { 10609c0476a2SJoe Komlodi if (fifo32_is_full(&s->rx_queue)) { 10619c0476a2SJoe Komlodi g_autofree char *path = object_get_canonical_path(OBJECT(s)); 10629c0476a2SJoe Komlodi qemu_log_mask(LOG_GUEST_ERROR, "%s: Tried to push to RX FIFO when " 10639c0476a2SJoe Komlodi "full\n", path); 10649c0476a2SJoe Komlodi return; 10659c0476a2SJoe Komlodi } 10669c0476a2SJoe Komlodi trace_dw_i3c_push_rx(s->cfg.id, val); 10679c0476a2SJoe Komlodi fifo32_push(&s->rx_queue, val); 10689c0476a2SJoe Komlodi 10699c0476a2SJoe Komlodi ARRAY_FIELD_DP32(s->regs, DATA_BUFFER_STATUS_LEVEL, RX_BUF_BLR, 10709c0476a2SJoe Komlodi fifo32_num_used(&s->rx_queue)); 10719c0476a2SJoe Komlodi /* Threshold is 2^RX_BUF_THLD. */ 10729c0476a2SJoe Komlodi uint8_t threshold = ARRAY_FIELD_EX32(s->regs, DATA_BUFFER_THLD_CTRL, 10739c0476a2SJoe Komlodi RX_BUF_THLD); 10749c0476a2SJoe Komlodi threshold = dw_i3c_fifo_threshold_from_reg(threshold); 10759c0476a2SJoe Komlodi if (fifo32_num_used(&s->rx_queue) >= threshold) { 10769c0476a2SJoe Komlodi ARRAY_FIELD_DP32(s->regs, INTR_STATUS, RX_THLD, 1); 10779c0476a2SJoe Komlodi dw_i3c_update_irq(s); 10789c0476a2SJoe Komlodi } 10799c0476a2SJoe Komlodi } 10809c0476a2SJoe Komlodi 10819c0476a2SJoe Komlodi static void dw_i3c_short_transfer(DWI3C *s, DWI3CTransferCmd cmd, 10829c0476a2SJoe Komlodi DWI3CShortArg arg) 10839c0476a2SJoe Komlodi { 10849c0476a2SJoe Komlodi uint8_t err = DW_I3C_RESP_QUEUE_ERR_NONE; 10859c0476a2SJoe Komlodi uint8_t addr = dw_i3c_target_addr(s, cmd.dev_index); 10869c0476a2SJoe Komlodi bool is_i2c = dw_i3c_target_is_i2c(s, cmd.dev_index); 10879c0476a2SJoe Komlodi uint8_t data[4]; /* Max we can send on a short transfer is 4 bytes. */ 10889c0476a2SJoe Komlodi uint8_t len = 0; 10899c0476a2SJoe Komlodi uint32_t bytes_sent; /* Ignored on short transfers. */ 10909c0476a2SJoe Komlodi 10919c0476a2SJoe Komlodi /* Can't do reads on a short transfer. */ 10929c0476a2SJoe Komlodi if (cmd.rnw) { 10939c0476a2SJoe Komlodi g_autofree char *path = object_get_canonical_path(OBJECT(s)); 10949c0476a2SJoe Komlodi qemu_log_mask(LOG_GUEST_ERROR, "%s: Cannot do a read on a short " 10959c0476a2SJoe Komlodi "transfer\n", path); 10969c0476a2SJoe Komlodi return; 10979c0476a2SJoe Komlodi } 10989c0476a2SJoe Komlodi 10999c0476a2SJoe Komlodi if (dw_i3c_send_start(s, addr, /*is_recv=*/false, is_i2c)) { 11009c0476a2SJoe Komlodi err = DW_I3C_RESP_QUEUE_ERR_I2C_NACK; 11019c0476a2SJoe Komlodi goto transfer_done; 11029c0476a2SJoe Komlodi } 11039c0476a2SJoe Komlodi 11049c0476a2SJoe Komlodi /* Are we sending a command? */ 11059c0476a2SJoe Komlodi if (cmd.cp) { 11069c0476a2SJoe Komlodi data[len] = cmd.cmd; 11079c0476a2SJoe Komlodi len++; 11089c0476a2SJoe Komlodi /* 11099c0476a2SJoe Komlodi * byte0 is the defining byte for a command, and is only sent if a 11109c0476a2SJoe Komlodi * command is present and if the command has a defining byte present. 11119c0476a2SJoe Komlodi * (byte_strb & 0x01) is always treated as set by the controller, and is 11129c0476a2SJoe Komlodi * ignored. 11139c0476a2SJoe Komlodi */ 11149c0476a2SJoe Komlodi if (cmd.dbp) { 11159c0476a2SJoe Komlodi data[len] += arg.byte0; 11169c0476a2SJoe Komlodi len++; 11179c0476a2SJoe Komlodi } 11189c0476a2SJoe Komlodi } 11199c0476a2SJoe Komlodi 11209c0476a2SJoe Komlodi /* Send the bytes passed in the argument. */ 11219c0476a2SJoe Komlodi if (arg.byte_strb & 0x02) { 11229c0476a2SJoe Komlodi data[len] = arg.byte1; 11239c0476a2SJoe Komlodi len++; 11249c0476a2SJoe Komlodi } 11259c0476a2SJoe Komlodi if (arg.byte_strb & 0x04) { 11269c0476a2SJoe Komlodi data[len] = arg.byte2; 11279c0476a2SJoe Komlodi len++; 11289c0476a2SJoe Komlodi } 11299c0476a2SJoe Komlodi 11309c0476a2SJoe Komlodi if (dw_i3c_send(s, data, len, &bytes_sent, is_i2c)) { 11319c0476a2SJoe Komlodi err = DW_I3C_RESP_QUEUE_ERR_I2C_NACK; 11329c0476a2SJoe Komlodi } else { 11339c0476a2SJoe Komlodi /* Only go to an idle state on a successful transfer. */ 11349c0476a2SJoe Komlodi ARRAY_FIELD_DP32(s->regs, PRESENT_STATE, CM_TFR_ST_STATUS, 11359c0476a2SJoe Komlodi DW_I3C_TRANSFER_STATE_IDLE); 11369c0476a2SJoe Komlodi } 11379c0476a2SJoe Komlodi 11389c0476a2SJoe Komlodi transfer_done: 11399c0476a2SJoe Komlodi if (cmd.toc) { 11409c0476a2SJoe Komlodi dw_i3c_end_transfer(s, is_i2c); 11419c0476a2SJoe Komlodi } 11429c0476a2SJoe Komlodi if (cmd.roc) { 11439c0476a2SJoe Komlodi /* 11449c0476a2SJoe Komlodi * ccc_type is always 0 in controller mode, data_len is 0 in short 11459c0476a2SJoe Komlodi * transfers. 11469c0476a2SJoe Komlodi */ 11479c0476a2SJoe Komlodi dw_i3c_resp_queue_push(s, err, cmd.tid, /*ccc_type=*/0, 11489c0476a2SJoe Komlodi /*data_len=*/0); 11499c0476a2SJoe Komlodi } 11509c0476a2SJoe Komlodi } 11519c0476a2SJoe Komlodi 11529c0476a2SJoe Komlodi /* Returns number of bytes transmitted. */ 11539c0476a2SJoe Komlodi static uint16_t dw_i3c_tx(DWI3C *s, uint16_t num, bool is_i2c) 11549c0476a2SJoe Komlodi { 11559c0476a2SJoe Komlodi uint16_t bytes_sent = 0; 11569c0476a2SJoe Komlodi union { 11579c0476a2SJoe Komlodi uint8_t b[sizeof(uint32_t)]; 11589c0476a2SJoe Komlodi uint32_t val; 11599c0476a2SJoe Komlodi } val32; 11609c0476a2SJoe Komlodi 11619c0476a2SJoe Komlodi while (bytes_sent < num) { 11629c0476a2SJoe Komlodi val32.val = dw_i3c_pop_tx(s); 11639c0476a2SJoe Komlodi for (uint8_t i = 0; i < sizeof(val32.val); i++) { 11649c0476a2SJoe Komlodi if (dw_i3c_send_byte(s, val32.b[i], is_i2c)) { 11659c0476a2SJoe Komlodi return bytes_sent; 11669c0476a2SJoe Komlodi } 11679c0476a2SJoe Komlodi bytes_sent++; 11689c0476a2SJoe Komlodi 11699c0476a2SJoe Komlodi /* We're not sending the full 32-bits, break early. */ 11709c0476a2SJoe Komlodi if (bytes_sent >= num) { 11719c0476a2SJoe Komlodi break; 11729c0476a2SJoe Komlodi } 11739c0476a2SJoe Komlodi } 11749c0476a2SJoe Komlodi } 11759c0476a2SJoe Komlodi 11769c0476a2SJoe Komlodi return bytes_sent; 11779c0476a2SJoe Komlodi } 11789c0476a2SJoe Komlodi 11799c0476a2SJoe Komlodi /* Returns number of bytes received. */ 11809c0476a2SJoe Komlodi static uint16_t dw_i3c_rx(DWI3C *s, uint16_t num, bool is_i2c) 11819c0476a2SJoe Komlodi { 11829c0476a2SJoe Komlodi /* 11839c0476a2SJoe Komlodi * Allocate a temporary buffer to read data from the target. 11849c0476a2SJoe Komlodi * Zero it and word-align it as well in case we're reading unaligned data. 11859c0476a2SJoe Komlodi */ 11869c0476a2SJoe Komlodi g_autofree uint8_t *data = g_new0(uint8_t, num + (4 - (num & 0x03))); 11879c0476a2SJoe Komlodi uint32_t *data32 = (uint32_t *)data; 11889c0476a2SJoe Komlodi /* 11899c0476a2SJoe Komlodi * 32-bits since the I3C API wants a 32-bit number, even though the 11909c0476a2SJoe Komlodi * controller can only do 16-bit transfers. 11919c0476a2SJoe Komlodi */ 11929c0476a2SJoe Komlodi uint32_t num_read = 0; 11939c0476a2SJoe Komlodi 11949c0476a2SJoe Komlodi /* Can NACK if the target receives an unsupported CCC. */ 11959c0476a2SJoe Komlodi if (dw_i3c_recv_data(s, is_i2c, data, num, &num_read)) { 11969c0476a2SJoe Komlodi return 0; 11979c0476a2SJoe Komlodi } 11989c0476a2SJoe Komlodi 11999c0476a2SJoe Komlodi for (uint16_t i = 0; i < num_read / 4; i++) { 12009c0476a2SJoe Komlodi dw_i3c_push_rx(s, *data32); 12019c0476a2SJoe Komlodi data32++; 12029c0476a2SJoe Komlodi } 12039c0476a2SJoe Komlodi /* 12049c0476a2SJoe Komlodi * If we're pushing data that isn't 32-bit aligned, push what's left. 12059c0476a2SJoe Komlodi * It's software's responsibility to know what bits are valid in the partial 12069c0476a2SJoe Komlodi * data. 12079c0476a2SJoe Komlodi */ 12089c0476a2SJoe Komlodi if (num_read & 0x03) { 12099c0476a2SJoe Komlodi dw_i3c_push_rx(s, *data32); 12109c0476a2SJoe Komlodi } 12119c0476a2SJoe Komlodi 12129c0476a2SJoe Komlodi return num_read; 12139c0476a2SJoe Komlodi } 12149c0476a2SJoe Komlodi 12159c0476a2SJoe Komlodi static int dw_i3c_transfer_ccc(DWI3C *s, DWI3CTransferCmd cmd, 12169c0476a2SJoe Komlodi DWI3CTransferArg arg) 12179c0476a2SJoe Komlodi { 12189c0476a2SJoe Komlodi /* CCC start is always a write. CCCs cannot be done on I2C devices. */ 12199c0476a2SJoe Komlodi if (dw_i3c_send_start(s, I3C_BROADCAST, /*is_recv=*/false, 12209c0476a2SJoe Komlodi /*is_i2c=*/false)) { 12219c0476a2SJoe Komlodi return DW_I3C_RESP_QUEUE_ERR_BROADCAST_NACK; 12229c0476a2SJoe Komlodi } 12239c0476a2SJoe Komlodi trace_dw_i3c_transfer_ccc(s->cfg.id, cmd.cmd); 12249c0476a2SJoe Komlodi if (dw_i3c_send_byte(s, cmd.cmd, /*is_i2c=*/false)) { 12259c0476a2SJoe Komlodi return DW_I3C_RESP_QUEUE_ERR_I2C_NACK; 12269c0476a2SJoe Komlodi } 12279c0476a2SJoe Komlodi 12289c0476a2SJoe Komlodi /* On a direct CCC, we do a restart and then send the target's address. */ 12299c0476a2SJoe Komlodi if (CCC_IS_DIRECT(cmd.cmd)) { 12309c0476a2SJoe Komlodi bool is_recv = cmd.rnw; 12319c0476a2SJoe Komlodi uint8_t addr = dw_i3c_target_addr(s, cmd.dev_index); 12329c0476a2SJoe Komlodi if (dw_i3c_send_start(s, addr, is_recv, /*is_i2c=*/false)) { 12339c0476a2SJoe Komlodi return DW_I3C_RESP_QUEUE_ERR_BROADCAST_NACK; 12349c0476a2SJoe Komlodi } 12359c0476a2SJoe Komlodi } 12369c0476a2SJoe Komlodi 12379c0476a2SJoe Komlodi return DW_I3C_RESP_QUEUE_ERR_NONE; 12389c0476a2SJoe Komlodi } 12399c0476a2SJoe Komlodi 12409c0476a2SJoe Komlodi static void dw_i3c_transfer(DWI3C *s, DWI3CTransferCmd cmd, 12419c0476a2SJoe Komlodi DWI3CTransferArg arg) 12429c0476a2SJoe Komlodi { 12439c0476a2SJoe Komlodi bool is_recv = cmd.rnw; 12449c0476a2SJoe Komlodi uint8_t err = DW_I3C_RESP_QUEUE_ERR_NONE; 12459c0476a2SJoe Komlodi uint8_t addr = dw_i3c_target_addr(s, cmd.dev_index); 12469c0476a2SJoe Komlodi bool is_i2c = dw_i3c_target_is_i2c(s, cmd.dev_index); 12479c0476a2SJoe Komlodi uint16_t bytes_transferred = 0; 12489c0476a2SJoe Komlodi 12499c0476a2SJoe Komlodi if (cmd.cp) { 12509c0476a2SJoe Komlodi /* We're sending a CCC. */ 12519c0476a2SJoe Komlodi err = dw_i3c_transfer_ccc(s, cmd, arg); 12529c0476a2SJoe Komlodi if (err != DW_I3C_RESP_QUEUE_ERR_NONE) { 12539c0476a2SJoe Komlodi goto transfer_done; 12549c0476a2SJoe Komlodi } 12559c0476a2SJoe Komlodi } else { 12569c0476a2SJoe Komlodi if (ARRAY_FIELD_EX32(s->regs, DEVICE_CTRL, I3C_BROADCAST_ADDR_INC) && 12579c0476a2SJoe Komlodi is_i2c == false) { 12589c0476a2SJoe Komlodi if (dw_i3c_send_start(s, I3C_BROADCAST, 12599c0476a2SJoe Komlodi /*is_recv=*/false, is_i2c)) { 12609c0476a2SJoe Komlodi err = DW_I3C_RESP_QUEUE_ERR_I2C_NACK; 12619c0476a2SJoe Komlodi goto transfer_done; 12629c0476a2SJoe Komlodi } 12639c0476a2SJoe Komlodi } 12649c0476a2SJoe Komlodi /* Otherwise we're doing a private transfer. */ 12659c0476a2SJoe Komlodi if (dw_i3c_send_start(s, addr, is_recv, is_i2c)) { 12669c0476a2SJoe Komlodi err = DW_I3C_RESP_QUEUE_ERR_I2C_NACK; 12679c0476a2SJoe Komlodi goto transfer_done; 12689c0476a2SJoe Komlodi } 12699c0476a2SJoe Komlodi } 12709c0476a2SJoe Komlodi 12719c0476a2SJoe Komlodi if (is_recv) { 12729c0476a2SJoe Komlodi bytes_transferred = dw_i3c_rx(s, arg.data_len, is_i2c); 12739c0476a2SJoe Komlodi } else { 12749c0476a2SJoe Komlodi bytes_transferred = dw_i3c_tx(s, arg.data_len, is_i2c); 12759c0476a2SJoe Komlodi } 12769c0476a2SJoe Komlodi 12779c0476a2SJoe Komlodi ARRAY_FIELD_DP32(s->regs, PRESENT_STATE, CM_TFR_ST_STATUS, 12789c0476a2SJoe Komlodi DW_I3C_TRANSFER_STATE_IDLE); 12799c0476a2SJoe Komlodi 12809c0476a2SJoe Komlodi transfer_done: 12819c0476a2SJoe Komlodi if (cmd.toc) { 12829c0476a2SJoe Komlodi dw_i3c_end_transfer(s, is_i2c); 12839c0476a2SJoe Komlodi } 12849c0476a2SJoe Komlodi if (cmd.roc) { 12859c0476a2SJoe Komlodi /* 12869c0476a2SJoe Komlodi * data_len is the number of bytes that still need to be TX'd, or the 12879c0476a2SJoe Komlodi * number of bytes RX'd. 12889c0476a2SJoe Komlodi */ 12899c0476a2SJoe Komlodi uint16_t data_len = is_recv ? bytes_transferred : arg.data_len - 12909c0476a2SJoe Komlodi bytes_transferred; 12919c0476a2SJoe Komlodi /* CCCT is always 0 in controller mode. */ 12929c0476a2SJoe Komlodi dw_i3c_resp_queue_push(s, err, cmd.tid, /*ccc_type=*/0, 12939c0476a2SJoe Komlodi data_len); 12949c0476a2SJoe Komlodi } 12959c0476a2SJoe Komlodi 12969c0476a2SJoe Komlodi dw_i3c_update_irq(s); 12979c0476a2SJoe Komlodi } 12989c0476a2SJoe Komlodi 12999c0476a2SJoe Komlodi static void dw_i3c_transfer_cmd(DWI3C *s, DWI3CTransferCmd cmd, 13009c0476a2SJoe Komlodi DWI3CCmdQueueData arg) 13019c0476a2SJoe Komlodi { 13029c0476a2SJoe Komlodi uint8_t arg_attr = FIELD_EX32(arg.word, COMMAND_QUEUE_PORT, CMD_ATTR); 13039c0476a2SJoe Komlodi 13049c0476a2SJoe Komlodi ARRAY_FIELD_DP32(s->regs, PRESENT_STATE, CMD_TID, cmd.tid); 13059c0476a2SJoe Komlodi 13069c0476a2SJoe Komlodi /* User is trying to do HDR transfers, see if we can do them. */ 13079c0476a2SJoe Komlodi if (cmd.speed == 0x06 && !dw_i3c_has_hdr_ddr(s)) { 13089c0476a2SJoe Komlodi g_autofree char *path = object_get_canonical_path(OBJECT(s)); 13099c0476a2SJoe Komlodi qemu_log_mask(LOG_GUEST_ERROR, "%s: HDR DDR is not supported\n", path); 13109c0476a2SJoe Komlodi ARRAY_FIELD_DP32(s->regs, PRESENT_STATE, CM_TFR_ST_STATUS, 13119c0476a2SJoe Komlodi DW_I3C_TRANSFER_STATE_HALT); 13129c0476a2SJoe Komlodi return; 13139c0476a2SJoe Komlodi } 13149c0476a2SJoe Komlodi if (cmd.speed == 0x05 && !dw_i3c_has_hdr_ts(s)) { 13159c0476a2SJoe Komlodi g_autofree char *path = object_get_canonical_path(OBJECT(s)); 13169c0476a2SJoe Komlodi qemu_log_mask(LOG_GUEST_ERROR, "%s: HDR TS is not supported\n", path); 13179c0476a2SJoe Komlodi ARRAY_FIELD_DP32(s->regs, PRESENT_STATE, CM_TFR_ST_STATUS, 13189c0476a2SJoe Komlodi DW_I3C_TRANSFER_STATE_HALT); 13199c0476a2SJoe Komlodi return; 13209c0476a2SJoe Komlodi } 13219c0476a2SJoe Komlodi 13229c0476a2SJoe Komlodi if (arg_attr == DW_I3C_CMD_ATTR_TRANSFER_ARG) { 13239c0476a2SJoe Komlodi dw_i3c_transfer(s, cmd, arg.transfer_arg); 13249c0476a2SJoe Komlodi } else if (arg_attr == DW_I3C_CMD_ATTR_SHORT_DATA_ARG) { 13259c0476a2SJoe Komlodi dw_i3c_short_transfer(s, cmd, arg.short_arg); 13269c0476a2SJoe Komlodi } else { 13279c0476a2SJoe Komlodi g_autofree char *path = object_get_canonical_path(OBJECT(s)); 13289c0476a2SJoe Komlodi qemu_log_mask(LOG_GUEST_ERROR, "%s: Unknown command queue cmd_attr 0x%x" 13299c0476a2SJoe Komlodi "\n", path, arg_attr); 13309c0476a2SJoe Komlodi ARRAY_FIELD_DP32(s->regs, PRESENT_STATE, CM_TFR_ST_STATUS, 13319c0476a2SJoe Komlodi DW_I3C_TRANSFER_STATE_HALT); 13329c0476a2SJoe Komlodi } 13339c0476a2SJoe Komlodi } 13349c0476a2SJoe Komlodi 13359c0476a2SJoe Komlodi static void dw_i3c_update_char_table(DWI3C *s, uint8_t offset, uint64_t pid, 13369c0476a2SJoe Komlodi uint8_t bcr, uint8_t dcr, uint8_t addr) 13379c0476a2SJoe Komlodi { 13389c0476a2SJoe Komlodi if (offset > s->cfg.num_addressable_devices) { 13399c0476a2SJoe Komlodi g_autofree char *path = object_get_canonical_path(OBJECT(s)); 13409c0476a2SJoe Komlodi qemu_log_mask(LOG_GUEST_ERROR, "%s: Device char table offset %d out of " 13419c0476a2SJoe Komlodi "bounds\n", path, offset); 13429c0476a2SJoe Komlodi /* If we're out of bounds, do nothing. */ 13439c0476a2SJoe Komlodi return; 13449c0476a2SJoe Komlodi } 13459c0476a2SJoe Komlodi 13469c0476a2SJoe Komlodi /* 13479c0476a2SJoe Komlodi * Each device offset is 128 bits apart in the table, since each device gets 13489c0476a2SJoe Komlodi * 4 * 32-bits of entries in the table. 13499c0476a2SJoe Komlodi * / sizeof(uint32_t) because we're indexing into our 32-bit reg array. 13509c0476a2SJoe Komlodi */ 13519c0476a2SJoe Komlodi uint16_t dev_index = (ARRAY_FIELD_EX32(s->regs, DEV_CHAR_TABLE_POINTER, 13529c0476a2SJoe Komlodi P_DEV_CHAR_TABLE_START_ADDR) / 13539c0476a2SJoe Komlodi sizeof(uint32_t)) + 13549c0476a2SJoe Komlodi (offset * sizeof(uint32_t)); 13559c0476a2SJoe Komlodi s->regs[dev_index] = pid & 0xffffffff; 13569c0476a2SJoe Komlodi pid >>= 32; 13579c0476a2SJoe Komlodi s->regs[dev_index + 1] = FIELD_DP32(s->regs[dev_index + 1], 13589c0476a2SJoe Komlodi DEVICE_CHARACTERISTIC_TABLE_LOC2, 13599c0476a2SJoe Komlodi MSB_PID, pid); 13609c0476a2SJoe Komlodi s->regs[dev_index + 2] = FIELD_DP32(s->regs[dev_index + 2], 13619c0476a2SJoe Komlodi DEVICE_CHARACTERISTIC_TABLE_LOC3, DCR, 13629c0476a2SJoe Komlodi dcr); 13639c0476a2SJoe Komlodi s->regs[dev_index + 2] = FIELD_DP32(s->regs[dev_index + 2], 13649c0476a2SJoe Komlodi DEVICE_CHARACTERISTIC_TABLE_LOC3, BCR, 13659c0476a2SJoe Komlodi bcr); 13669c0476a2SJoe Komlodi s->regs[dev_index + 3] = FIELD_DP32(s->regs[dev_index + 3], 13679c0476a2SJoe Komlodi DEVICE_CHARACTERISTIC_TABLE_LOC4, 13689c0476a2SJoe Komlodi DEV_DYNAMIC_ADDR, addr); 13699c0476a2SJoe Komlodi 13709c0476a2SJoe Komlodi /* Increment PRESENT_DEV_CHAR_TABLE_INDEX. */ 13719c0476a2SJoe Komlodi uint8_t idx = ARRAY_FIELD_EX32(s->regs, DEV_CHAR_TABLE_POINTER, 13729c0476a2SJoe Komlodi PRESENT_DEV_CHAR_TABLE_INDEX); 13739c0476a2SJoe Komlodi /* Increment and rollover. */ 13749c0476a2SJoe Komlodi idx++; 13759c0476a2SJoe Komlodi if (idx >= ARRAY_FIELD_EX32(s->regs, DEV_CHAR_TABLE_POINTER, 13769c0476a2SJoe Komlodi DEV_CHAR_TABLE_DEPTH) / 4) { 13779c0476a2SJoe Komlodi idx = 0; 13789c0476a2SJoe Komlodi } 13799c0476a2SJoe Komlodi ARRAY_FIELD_DP32(s->regs, DEV_CHAR_TABLE_POINTER, 13809c0476a2SJoe Komlodi PRESENT_DEV_CHAR_TABLE_INDEX, idx); 13819c0476a2SJoe Komlodi } 13829c0476a2SJoe Komlodi 13839c0476a2SJoe Komlodi static void dw_i3c_addr_assign_cmd(DWI3C *s, DWI3CAddrAssignCmd cmd) 13849c0476a2SJoe Komlodi { 13859c0476a2SJoe Komlodi uint8_t i = 0; 13869c0476a2SJoe Komlodi uint8_t err = DW_I3C_RESP_QUEUE_ERR_NONE; 13879c0476a2SJoe Komlodi 13889c0476a2SJoe Komlodi /* Tell everyone to ENTDAA. If these error, no one is on the bus. */ 13899c0476a2SJoe Komlodi if (dw_i3c_send_start(s, I3C_BROADCAST, /*is_recv=*/false, 13909c0476a2SJoe Komlodi /*is_i2c=*/false)) { 13919c0476a2SJoe Komlodi err = DW_I3C_RESP_QUEUE_ERR_BROADCAST_NACK; 13929c0476a2SJoe Komlodi goto transfer_done; 13939c0476a2SJoe Komlodi } 13949c0476a2SJoe Komlodi if (dw_i3c_send_byte(s, cmd.cmd, /*is_i2c=*/false)) { 13959c0476a2SJoe Komlodi err = DW_I3C_RESP_QUEUE_ERR_BROADCAST_NACK; 13969c0476a2SJoe Komlodi goto transfer_done; 13979c0476a2SJoe Komlodi } 13989c0476a2SJoe Komlodi 13999c0476a2SJoe Komlodi /* Go through each device in the table and assign it an address. */ 14009c0476a2SJoe Komlodi for (i = 0; i < cmd.dev_count; i++) { 14019c0476a2SJoe Komlodi uint8_t addr = dw_i3c_target_addr(s, cmd.dev_index + i); 14029c0476a2SJoe Komlodi union { 14039c0476a2SJoe Komlodi uint64_t pid:48; 14049c0476a2SJoe Komlodi uint8_t bcr; 14059c0476a2SJoe Komlodi uint8_t dcr; 14069c0476a2SJoe Komlodi uint32_t w[2]; 14079c0476a2SJoe Komlodi uint8_t b[8]; 14089c0476a2SJoe Komlodi } target_info; 14099c0476a2SJoe Komlodi 14109c0476a2SJoe Komlodi /* If this fails, there was no one left to ENTDAA. */ 14119c0476a2SJoe Komlodi if (dw_i3c_send_start(s, I3C_BROADCAST, /*is_recv=*/false, 14129c0476a2SJoe Komlodi /*is_i2c=*/false)) { 14139c0476a2SJoe Komlodi err = DW_I3C_RESP_QUEUE_ERR_BROADCAST_NACK; 14149c0476a2SJoe Komlodi break; 14159c0476a2SJoe Komlodi } 14169c0476a2SJoe Komlodi 14179c0476a2SJoe Komlodi /* 14189c0476a2SJoe Komlodi * In ENTDAA, we read 8 bytes from the target, which will be the 14199c0476a2SJoe Komlodi * target's PID, BCR, and DCR. After that, we send it the dynamic 14209c0476a2SJoe Komlodi * address. 14219c0476a2SJoe Komlodi * Don't bother checking the number of bytes received, it must send 8 14229c0476a2SJoe Komlodi * bytes during ENTDAA. 14239c0476a2SJoe Komlodi */ 14249c0476a2SJoe Komlodi uint32_t num_read; 14259c0476a2SJoe Komlodi if (dw_i3c_recv_data(s, /*is_i2c=*/false, target_info.b, 14269c0476a2SJoe Komlodi I3C_ENTDAA_SIZE, &num_read)) { 14279c0476a2SJoe Komlodi g_autofree char *path = object_get_canonical_path(OBJECT(s)); 14289c0476a2SJoe Komlodi qemu_log_mask(LOG_GUEST_ERROR, "%s: Target NACKed ENTDAA CCC\n", 14299c0476a2SJoe Komlodi path); 14309c0476a2SJoe Komlodi err = DW_I3C_RESP_QUEUE_ERR_DAA_NACK; 14319c0476a2SJoe Komlodi goto transfer_done; 14329c0476a2SJoe Komlodi } 14339c0476a2SJoe Komlodi if (dw_i3c_send_byte(s, addr, /*is_i2c=*/false)) { 14349c0476a2SJoe Komlodi g_autofree char *path = object_get_canonical_path(OBJECT(s)); 14359c0476a2SJoe Komlodi qemu_log_mask(LOG_GUEST_ERROR, "%s: Target NACKed addr 0x%.2x " 14369c0476a2SJoe Komlodi "during ENTDAA\n", path, addr); 14379c0476a2SJoe Komlodi err = DW_I3C_RESP_QUEUE_ERR_DAA_NACK; 14389c0476a2SJoe Komlodi break; 14399c0476a2SJoe Komlodi } 14409c0476a2SJoe Komlodi dw_i3c_update_char_table(s, cmd.dev_index + i, 14419c0476a2SJoe Komlodi target_info.pid, target_info.bcr, 14429c0476a2SJoe Komlodi target_info.dcr, addr); 14439c0476a2SJoe Komlodi 14449c0476a2SJoe Komlodi /* Push the PID, BCR, and DCR to the RX queue. */ 14459c0476a2SJoe Komlodi dw_i3c_push_rx(s, target_info.w[0]); 14469c0476a2SJoe Komlodi dw_i3c_push_rx(s, target_info.w[1]); 14479c0476a2SJoe Komlodi } 14489c0476a2SJoe Komlodi 14499c0476a2SJoe Komlodi transfer_done: 14509c0476a2SJoe Komlodi /* Do we send a STOP? */ 14519c0476a2SJoe Komlodi if (cmd.toc) { 14529c0476a2SJoe Komlodi dw_i3c_end_transfer(s, /*is_i2c=*/false); 14539c0476a2SJoe Komlodi } 14549c0476a2SJoe Komlodi /* 14559c0476a2SJoe Komlodi * For addr assign commands, the length field is the number of devices 14569c0476a2SJoe Komlodi * left to assign. CCCT is always 0 in controller mode. 14579c0476a2SJoe Komlodi */ 14589c0476a2SJoe Komlodi if (cmd.roc) { 14599c0476a2SJoe Komlodi dw_i3c_resp_queue_push(s, err, cmd.tid, /*ccc_type=*/0, 14609c0476a2SJoe Komlodi cmd.dev_count - i); 14619c0476a2SJoe Komlodi } 14629c0476a2SJoe Komlodi } 14639c0476a2SJoe Komlodi 14649c0476a2SJoe Komlodi static uint32_t dw_i3c_cmd_queue_pop(DWI3C *s) 14659c0476a2SJoe Komlodi { 14669c0476a2SJoe Komlodi if (fifo32_is_empty(&s->cmd_queue)) { 14679c0476a2SJoe Komlodi g_autofree char *path = object_get_canonical_path(OBJECT(s)); 14689c0476a2SJoe Komlodi qemu_log_mask(LOG_GUEST_ERROR, "%s: Tried to dequeue command queue " 14699c0476a2SJoe Komlodi "when it was empty\n", path); 14709c0476a2SJoe Komlodi return 0; 14719c0476a2SJoe Komlodi } 14729c0476a2SJoe Komlodi uint32_t val = fifo32_pop(&s->cmd_queue); 14739c0476a2SJoe Komlodi 14749c0476a2SJoe Komlodi uint8_t empty_threshold = ARRAY_FIELD_EX32(s->regs, QUEUE_THLD_CTRL, 14759c0476a2SJoe Komlodi CMD_BUF_EMPTY_THLD); 14769c0476a2SJoe Komlodi uint8_t cmd_queue_empty_loc = ARRAY_FIELD_EX32(s->regs, 14779c0476a2SJoe Komlodi QUEUE_STATUS_LEVEL, 14789c0476a2SJoe Komlodi CMD_QUEUE_EMPTY_LOC); 14799c0476a2SJoe Komlodi cmd_queue_empty_loc++; 14809c0476a2SJoe Komlodi ARRAY_FIELD_DP32(s->regs, QUEUE_STATUS_LEVEL, CMD_QUEUE_EMPTY_LOC, 14819c0476a2SJoe Komlodi cmd_queue_empty_loc); 14829c0476a2SJoe Komlodi if (cmd_queue_empty_loc >= empty_threshold) { 14839c0476a2SJoe Komlodi ARRAY_FIELD_DP32(s->regs, INTR_STATUS, CMD_QUEUE_RDY, 1); 14849c0476a2SJoe Komlodi dw_i3c_update_irq(s); 14859c0476a2SJoe Komlodi } 14869c0476a2SJoe Komlodi 14879c0476a2SJoe Komlodi return val; 14889c0476a2SJoe Komlodi } 14899c0476a2SJoe Komlodi 14909c0476a2SJoe Komlodi static void dw_i3c_cmd_queue_execute(DWI3C *s) 14919c0476a2SJoe Komlodi { 14929c0476a2SJoe Komlodi ARRAY_FIELD_DP32(s->regs, PRESENT_STATE, CM_TFR_ST_STATUS, 14939c0476a2SJoe Komlodi DW_I3C_TRANSFER_STATE_IDLE); 14949c0476a2SJoe Komlodi if (!dw_i3c_can_transmit(s)) { 14959c0476a2SJoe Komlodi return; 14969c0476a2SJoe Komlodi } 14979c0476a2SJoe Komlodi 14989c0476a2SJoe Komlodi /* 14999c0476a2SJoe Komlodi * We only start executing when a command is passed into the FIFO. 15009c0476a2SJoe Komlodi * We expect there to be a multiple of 2 items in the queue. The first item 15019c0476a2SJoe Komlodi * should be an argument to a command, and the command should be the second 15029c0476a2SJoe Komlodi * item. 15039c0476a2SJoe Komlodi */ 15049c0476a2SJoe Komlodi if (fifo32_num_used(&s->cmd_queue) & 1) { 15059c0476a2SJoe Komlodi return; 15069c0476a2SJoe Komlodi } 15079c0476a2SJoe Komlodi 15089c0476a2SJoe Komlodi while (!fifo32_is_empty(&s->cmd_queue)) { 15099c0476a2SJoe Komlodi DWI3CCmdQueueData arg; 15109c0476a2SJoe Komlodi arg.word = dw_i3c_cmd_queue_pop(s); 15119c0476a2SJoe Komlodi DWI3CCmdQueueData cmd; 15129c0476a2SJoe Komlodi cmd.word = dw_i3c_cmd_queue_pop(s); 15139c0476a2SJoe Komlodi trace_dw_i3c_cmd_queue_execute(s->cfg.id, cmd.word, arg.word); 15149c0476a2SJoe Komlodi 15159c0476a2SJoe Komlodi uint8_t cmd_attr = FIELD_EX32(cmd.word, COMMAND_QUEUE_PORT, CMD_ATTR); 15169c0476a2SJoe Komlodi switch (cmd_attr) { 15179c0476a2SJoe Komlodi case DW_I3C_CMD_ATTR_TRANSFER_CMD: 15189c0476a2SJoe Komlodi dw_i3c_transfer_cmd(s, cmd.transfer_cmd, arg); 15199c0476a2SJoe Komlodi break; 15209c0476a2SJoe Komlodi case DW_I3C_CMD_ATTR_ADDR_ASSIGN_CMD: 15219c0476a2SJoe Komlodi /* Arg is discarded for addr assign commands. */ 15229c0476a2SJoe Komlodi dw_i3c_addr_assign_cmd(s, cmd.addr_assign_cmd); 15239c0476a2SJoe Komlodi break; 15249c0476a2SJoe Komlodi case DW_I3C_CMD_ATTR_TRANSFER_ARG: 15259c0476a2SJoe Komlodi case DW_I3C_CMD_ATTR_SHORT_DATA_ARG: 15269c0476a2SJoe Komlodi { 15279c0476a2SJoe Komlodi g_autofree char *path = object_get_canonical_path(OBJECT(s)); 15289c0476a2SJoe Komlodi qemu_log_mask(LOG_GUEST_ERROR, "%s: Command queue received " 15299c0476a2SJoe Komlodi "argument packet when it expected a command " 15309c0476a2SJoe Komlodi "packet\n", path); 15319c0476a2SJoe Komlodi } 15329c0476a2SJoe Komlodi break; 15339c0476a2SJoe Komlodi default: 15349c0476a2SJoe Komlodi /* 15359c0476a2SJoe Komlodi * The caller's check before queueing an item should prevent this 15369c0476a2SJoe Komlodi * from happening. 15379c0476a2SJoe Komlodi */ 15389c0476a2SJoe Komlodi g_assert_not_reached(); 15399c0476a2SJoe Komlodi break; 15409c0476a2SJoe Komlodi } 15419c0476a2SJoe Komlodi } 15429c0476a2SJoe Komlodi } 15439c0476a2SJoe Komlodi 15449c0476a2SJoe Komlodi static void dw_i3c_cmd_queue_push(DWI3C *s, uint32_t val) 15459c0476a2SJoe Komlodi { 15469c0476a2SJoe Komlodi if (fifo32_is_full(&s->cmd_queue)) { 15479c0476a2SJoe Komlodi g_autofree char *path = object_get_canonical_path(OBJECT(s)); 15489c0476a2SJoe Komlodi qemu_log_mask(LOG_GUEST_ERROR, "%s: Command queue received packet when " 15499c0476a2SJoe Komlodi "already full\n", path); 15509c0476a2SJoe Komlodi return; 15519c0476a2SJoe Komlodi } 15529c0476a2SJoe Komlodi trace_dw_i3c_cmd_queue_push(s->cfg.id, val); 15539c0476a2SJoe Komlodi fifo32_push(&s->cmd_queue, val); 15549c0476a2SJoe Komlodi 15559c0476a2SJoe Komlodi uint8_t empty_threshold = ARRAY_FIELD_EX32(s->regs, QUEUE_THLD_CTRL, 15569c0476a2SJoe Komlodi CMD_BUF_EMPTY_THLD); 15579c0476a2SJoe Komlodi uint8_t cmd_queue_empty_loc = ARRAY_FIELD_EX32(s->regs, 15589c0476a2SJoe Komlodi QUEUE_STATUS_LEVEL, 15599c0476a2SJoe Komlodi CMD_QUEUE_EMPTY_LOC); 15609c0476a2SJoe Komlodi if (cmd_queue_empty_loc) { 15619c0476a2SJoe Komlodi cmd_queue_empty_loc--; 15629c0476a2SJoe Komlodi ARRAY_FIELD_DP32(s->regs, QUEUE_STATUS_LEVEL, CMD_QUEUE_EMPTY_LOC, 15639c0476a2SJoe Komlodi cmd_queue_empty_loc); 15649c0476a2SJoe Komlodi } 15659c0476a2SJoe Komlodi if (cmd_queue_empty_loc < empty_threshold) { 15669c0476a2SJoe Komlodi ARRAY_FIELD_DP32(s->regs, INTR_STATUS, CMD_QUEUE_RDY, 0); 15679c0476a2SJoe Komlodi dw_i3c_update_irq(s); 15689c0476a2SJoe Komlodi } 15699c0476a2SJoe Komlodi } 15709c0476a2SJoe Komlodi 15719c0476a2SJoe Komlodi static void dw_i3c_cmd_queue_port_w(DWI3C *s, uint32_t val) 15729c0476a2SJoe Komlodi { 15739c0476a2SJoe Komlodi uint8_t cmd_attr = FIELD_EX32(val, COMMAND_QUEUE_PORT, CMD_ATTR); 15749c0476a2SJoe Komlodi 15759c0476a2SJoe Komlodi switch (cmd_attr) { 15769c0476a2SJoe Komlodi /* If a command is received we can start executing it. */ 15779c0476a2SJoe Komlodi case DW_I3C_CMD_ATTR_TRANSFER_CMD: 15789c0476a2SJoe Komlodi case DW_I3C_CMD_ATTR_ADDR_ASSIGN_CMD: 15799c0476a2SJoe Komlodi dw_i3c_cmd_queue_push(s, val); 15809c0476a2SJoe Komlodi dw_i3c_cmd_queue_execute(s); 15819c0476a2SJoe Komlodi break; 15829c0476a2SJoe Komlodi /* If we get an argument just push it. */ 15839c0476a2SJoe Komlodi case DW_I3C_CMD_ATTR_TRANSFER_ARG: 15849c0476a2SJoe Komlodi case DW_I3C_CMD_ATTR_SHORT_DATA_ARG: 15859c0476a2SJoe Komlodi dw_i3c_cmd_queue_push(s, val); 15869c0476a2SJoe Komlodi break; 15879c0476a2SJoe Komlodi default: 15889c0476a2SJoe Komlodi { 15899c0476a2SJoe Komlodi g_autofree char *path = object_get_canonical_path(OBJECT(s)); 15909c0476a2SJoe Komlodi qemu_log_mask(LOG_GUEST_ERROR, "%s: Command queue received packet " 15919c0476a2SJoe Komlodi "with unknown cmd attr 0x%x\n", path, cmd_attr); 15929c0476a2SJoe Komlodi } 15939c0476a2SJoe Komlodi break; 15949c0476a2SJoe Komlodi } 15959c0476a2SJoe Komlodi } 15969c0476a2SJoe Komlodi 1597c52aaabdSJoe Komlodi static void dw_i3c_write(void *opaque, hwaddr offset, uint64_t value, 1598c52aaabdSJoe Komlodi unsigned size) 1599c52aaabdSJoe Komlodi { 1600c52aaabdSJoe Komlodi DWI3C *s = DW_I3C(opaque); 1601c52aaabdSJoe Komlodi uint32_t addr = offset >> 2; 16027e5e02dbSJoe Komlodi uint32_t val32 = (uint32_t)value; 1603c52aaabdSJoe Komlodi 16049c0476a2SJoe Komlodi trace_dw_i3c_write(s->cfg.id, offset, value); 1605c52aaabdSJoe Komlodi 16067e5e02dbSJoe Komlodi val32 &= ~dw_i3c_ro[addr]; 1607c52aaabdSJoe Komlodi switch (addr) { 1608c52aaabdSJoe Komlodi case R_HW_CAPABILITY: 1609c52aaabdSJoe Komlodi case R_RESPONSE_QUEUE_PORT: 1610c52aaabdSJoe Komlodi case R_IBI_QUEUE_DATA: 1611c52aaabdSJoe Komlodi case R_QUEUE_STATUS_LEVEL: 1612c52aaabdSJoe Komlodi case R_PRESENT_STATE: 1613c52aaabdSJoe Komlodi case R_CCC_DEVICE_STATUS: 1614c52aaabdSJoe Komlodi case R_DEVICE_ADDR_TABLE_POINTER: 1615c52aaabdSJoe Komlodi case R_VENDOR_SPECIFIC_REG_POINTER: 1616c52aaabdSJoe Komlodi case R_SLV_CHAR_CTRL: 1617c52aaabdSJoe Komlodi case R_SLV_MAX_LEN: 1618c52aaabdSJoe Komlodi case R_MAX_READ_TURNAROUND: 1619c52aaabdSJoe Komlodi case R_I3C_VER_ID: 1620c52aaabdSJoe Komlodi case R_I3C_VER_TYPE: 1621c52aaabdSJoe Komlodi case R_EXTENDED_CAPABILITY: 1622c52aaabdSJoe Komlodi qemu_log_mask(LOG_GUEST_ERROR, 1623c52aaabdSJoe Komlodi "%s: write to readonly register[0x%02" HWADDR_PRIx 1624c52aaabdSJoe Komlodi "] = 0x%08" PRIx64 "\n", 1625c52aaabdSJoe Komlodi __func__, offset, value); 1626c52aaabdSJoe Komlodi break; 1627*a59884aaSJoe Komlodi case R_DEVICE_CTRL: 1628*a59884aaSJoe Komlodi dw_i3c_ctrl_w(s, val32); 1629*a59884aaSJoe Komlodi break; 1630c52aaabdSJoe Komlodi case R_RX_TX_DATA_PORT: 16319c0476a2SJoe Komlodi dw_i3c_push_tx(s, val32); 16329c0476a2SJoe Komlodi break; 16339c0476a2SJoe Komlodi case R_COMMAND_QUEUE_PORT: 16349c0476a2SJoe Komlodi dw_i3c_cmd_queue_port_w(s, val32); 1635c52aaabdSJoe Komlodi break; 1636c52aaabdSJoe Komlodi case R_RESET_CTRL: 1637c52aaabdSJoe Komlodi break; 1638a825bbb7SJoe Komlodi case R_INTR_STATUS: 1639a825bbb7SJoe Komlodi dw_i3c_intr_status_w(s, val32); 1640a825bbb7SJoe Komlodi break; 1641a825bbb7SJoe Komlodi case R_INTR_STATUS_EN: 1642a825bbb7SJoe Komlodi dw_i3c_intr_status_en_w(s, val32); 1643a825bbb7SJoe Komlodi break; 1644a825bbb7SJoe Komlodi case R_INTR_SIGNAL_EN: 1645a825bbb7SJoe Komlodi dw_i3c_intr_signal_en_w(s, val32); 1646a825bbb7SJoe Komlodi break; 1647a825bbb7SJoe Komlodi case R_INTR_FORCE: 1648a825bbb7SJoe Komlodi dw_i3c_intr_force_w(s, val32); 1649a825bbb7SJoe Komlodi break; 1650c52aaabdSJoe Komlodi default: 16517e5e02dbSJoe Komlodi s->regs[addr] = val32; 1652c52aaabdSJoe Komlodi break; 1653c52aaabdSJoe Komlodi } 1654c52aaabdSJoe Komlodi } 1655c52aaabdSJoe Komlodi 1656c52aaabdSJoe Komlodi const VMStateDescription vmstate_dw_i3c = { 1657c52aaabdSJoe Komlodi .name = TYPE_DW_I3C, 1658c52aaabdSJoe Komlodi .version_id = 1, 1659c52aaabdSJoe Komlodi .minimum_version_id = 1, 1660c52aaabdSJoe Komlodi .fields = (VMStateField[]){ 1661c52aaabdSJoe Komlodi VMSTATE_UINT32_ARRAY(regs, DWI3C, DW_I3C_NR_REGS), 1662c52aaabdSJoe Komlodi VMSTATE_END_OF_LIST(), 1663c52aaabdSJoe Komlodi } 1664c52aaabdSJoe Komlodi }; 1665c52aaabdSJoe Komlodi 1666c52aaabdSJoe Komlodi static const MemoryRegionOps dw_i3c_ops = { 1667c52aaabdSJoe Komlodi .read = dw_i3c_read, 1668c52aaabdSJoe Komlodi .write = dw_i3c_write, 1669c52aaabdSJoe Komlodi .endianness = DEVICE_LITTLE_ENDIAN, 1670c52aaabdSJoe Komlodi }; 1671c52aaabdSJoe Komlodi 1672c52aaabdSJoe Komlodi static void dw_i3c_reset_enter(Object *obj, ResetType type) 1673c52aaabdSJoe Komlodi { 1674c52aaabdSJoe Komlodi DWI3C *s = DW_I3C(obj); 1675c52aaabdSJoe Komlodi 1676c52aaabdSJoe Komlodi memcpy(s->regs, dw_i3c_resets, sizeof(s->regs)); 16779c0476a2SJoe Komlodi /* 16789c0476a2SJoe Komlodi * The user config for these may differ from our resets array, set them 16799c0476a2SJoe Komlodi * manually. 16809c0476a2SJoe Komlodi */ 16819c0476a2SJoe Komlodi ARRAY_FIELD_DP32(s->regs, DEVICE_ADDR_TABLE_POINTER, ADDR, 16829c0476a2SJoe Komlodi s->cfg.dev_addr_table_pointer); 16839c0476a2SJoe Komlodi ARRAY_FIELD_DP32(s->regs, DEVICE_ADDR_TABLE_POINTER, DEPTH, 16849c0476a2SJoe Komlodi s->cfg.dev_addr_table_depth); 16859c0476a2SJoe Komlodi ARRAY_FIELD_DP32(s->regs, DEV_CHAR_TABLE_POINTER, 16869c0476a2SJoe Komlodi P_DEV_CHAR_TABLE_START_ADDR, 16879c0476a2SJoe Komlodi s->cfg.dev_char_table_pointer); 16889c0476a2SJoe Komlodi ARRAY_FIELD_DP32(s->regs, DEV_CHAR_TABLE_POINTER, DEV_CHAR_TABLE_DEPTH, 16899c0476a2SJoe Komlodi s->cfg.dev_char_table_depth); 1690c52aaabdSJoe Komlodi } 1691c52aaabdSJoe Komlodi 1692c52aaabdSJoe Komlodi static void dw_i3c_realize(DeviceState *dev, Error **errp) 1693c52aaabdSJoe Komlodi { 1694c52aaabdSJoe Komlodi DWI3C *s = DW_I3C(dev); 16959c0476a2SJoe Komlodi g_autofree char *name = g_strdup_printf(TYPE_DW_I3C ".%d", s->cfg.id); 1696c52aaabdSJoe Komlodi 1697c52aaabdSJoe Komlodi sysbus_init_irq(SYS_BUS_DEVICE(dev), &s->irq); 1698c52aaabdSJoe Komlodi 1699c52aaabdSJoe Komlodi memory_region_init_io(&s->mr, OBJECT(s), &dw_i3c_ops, s, name, 1700c52aaabdSJoe Komlodi DW_I3C_NR_REGS << 2); 1701c52aaabdSJoe Komlodi sysbus_init_mmio(SYS_BUS_DEVICE(dev), &s->mr); 17029c0476a2SJoe Komlodi 17039c0476a2SJoe Komlodi fifo32_create(&s->cmd_queue, s->cfg.cmd_resp_queue_capacity_bytes); 17049c0476a2SJoe Komlodi fifo32_create(&s->resp_queue, s->cfg.cmd_resp_queue_capacity_bytes); 17059c0476a2SJoe Komlodi fifo32_create(&s->tx_queue, s->cfg.tx_rx_queue_capacity_bytes); 17069c0476a2SJoe Komlodi fifo32_create(&s->rx_queue, s->cfg.tx_rx_queue_capacity_bytes); 17075a2a5453SJoe Komlodi fifo32_create(&s->ibi_queue, s->cfg.ibi_queue_capacity_bytes); 17085a2a5453SJoe Komlodi /* Arbitrarily large enough to not be an issue. */ 17095a2a5453SJoe Komlodi fifo8_create(&s->ibi_data.ibi_intermediate_queue, 17105a2a5453SJoe Komlodi s->cfg.ibi_queue_capacity_bytes * 8); 17119c0476a2SJoe Komlodi 17129c0476a2SJoe Komlodi s->bus = i3c_init_bus(DEVICE(s), name); 17135a2a5453SJoe Komlodi I3CBusClass *bc = I3C_BUS_GET_CLASS(s->bus); 17145a2a5453SJoe Komlodi bc->ibi_handle = dw_i3c_ibi_handle; 17155a2a5453SJoe Komlodi bc->ibi_recv = dw_i3c_ibi_recv; 17165a2a5453SJoe Komlodi bc->ibi_finish = dw_i3c_ibi_finish; 1717c52aaabdSJoe Komlodi } 1718c52aaabdSJoe Komlodi 1719c52aaabdSJoe Komlodi static const Property dw_i3c_properties[] = { 17209c0476a2SJoe Komlodi DEFINE_PROP_UINT8("device-id", DWI3C, cfg.id, 0), 17219c0476a2SJoe Komlodi DEFINE_PROP_UINT8("command-response-queue-capacity-bytes", DWI3C, 17229c0476a2SJoe Komlodi cfg.cmd_resp_queue_capacity_bytes, 0x10), 17239c0476a2SJoe Komlodi DEFINE_PROP_UINT16("tx-rx-queue-capacity-bytes", DWI3C, 17249c0476a2SJoe Komlodi cfg.tx_rx_queue_capacity_bytes, 0x40), 17255a2a5453SJoe Komlodi DEFINE_PROP_UINT8("ibi-queue-capacity-bytes", DWI3C, 17265a2a5453SJoe Komlodi cfg.ibi_queue_capacity_bytes, 0x10), 17279c0476a2SJoe Komlodi DEFINE_PROP_UINT8("num-addressable-devices", DWI3C, 17289c0476a2SJoe Komlodi cfg.num_addressable_devices, 8), 17299c0476a2SJoe Komlodi DEFINE_PROP_UINT16("dev-addr-table-pointer", DWI3C, 17309c0476a2SJoe Komlodi cfg.dev_addr_table_pointer, 0x280), 17319c0476a2SJoe Komlodi DEFINE_PROP_UINT16("dev-addr-table-depth", DWI3C, 17329c0476a2SJoe Komlodi cfg.dev_addr_table_depth, 0x08), 17339c0476a2SJoe Komlodi DEFINE_PROP_UINT16("dev-char-table-pointer", DWI3C, 17349c0476a2SJoe Komlodi cfg.dev_char_table_pointer, 0x200), 17359c0476a2SJoe Komlodi DEFINE_PROP_UINT16("dev-char-table-depth", DWI3C, 17369c0476a2SJoe Komlodi cfg.dev_char_table_depth, 0x20), 1737c52aaabdSJoe Komlodi }; 1738c52aaabdSJoe Komlodi 1739c52aaabdSJoe Komlodi static void dw_i3c_class_init(ObjectClass *klass, const void *data) 1740c52aaabdSJoe Komlodi { 1741c52aaabdSJoe Komlodi DeviceClass *dc = DEVICE_CLASS(klass); 1742c52aaabdSJoe Komlodi ResettableClass *rc = RESETTABLE_CLASS(klass); 1743c52aaabdSJoe Komlodi 1744c52aaabdSJoe Komlodi rc->phases.enter = dw_i3c_reset_enter; 1745c52aaabdSJoe Komlodi 1746c52aaabdSJoe Komlodi dc->desc = "DesignWare I3C Controller"; 1747c52aaabdSJoe Komlodi dc->realize = dw_i3c_realize; 1748c52aaabdSJoe Komlodi dc->vmsd = &vmstate_dw_i3c; 1749c52aaabdSJoe Komlodi device_class_set_props(dc, dw_i3c_properties); 1750c52aaabdSJoe Komlodi } 1751c52aaabdSJoe Komlodi 1752c52aaabdSJoe Komlodi static const TypeInfo dw_i3c_info = { 1753c52aaabdSJoe Komlodi .name = TYPE_DW_I3C, 1754c52aaabdSJoe Komlodi .parent = TYPE_SYS_BUS_DEVICE, 1755c52aaabdSJoe Komlodi .instance_size = sizeof(DWI3C), 1756c52aaabdSJoe Komlodi .class_init = dw_i3c_class_init, 1757c52aaabdSJoe Komlodi }; 1758c52aaabdSJoe Komlodi 1759c52aaabdSJoe Komlodi static void dw_i3c_register_types(void) 1760c52aaabdSJoe Komlodi { 1761c52aaabdSJoe Komlodi type_register_static(&dw_i3c_info); 1762c52aaabdSJoe Komlodi } 1763c52aaabdSJoe Komlodi 1764c52aaabdSJoe Komlodi type_init(dw_i3c_register_types); 1765