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 22c52aaabdSJoe Komlodi REG32(DEVICE_CTRL, 0x00) 2359b8d0c9SJoe Komlodi FIELD(DEVICE_CTRL, I3C_BROADCAST_ADDR_INC, 0, 1) 2459b8d0c9SJoe Komlodi FIELD(DEVICE_CTRL, I2C_SLAVE_PRESENT, 7, 1) 2559b8d0c9SJoe Komlodi FIELD(DEVICE_CTRL, HOT_JOIN_ACK_NACK_CTRL, 8, 1) 2659b8d0c9SJoe Komlodi FIELD(DEVICE_CTRL, IDLE_CNT_MULTIPLIER, 24, 2) 2759b8d0c9SJoe Komlodi FIELD(DEVICE_CTRL, SLV_ADAPT_TO_I2C_I3C_MODE, 27, 1) 2859b8d0c9SJoe Komlodi FIELD(DEVICE_CTRL, DMA_HANDSHAKE_EN, 28, 1) 2959b8d0c9SJoe Komlodi FIELD(DEVICE_CTRL, I3C_ABORT, 29, 1) 3059b8d0c9SJoe Komlodi FIELD(DEVICE_CTRL, I3C_RESUME, 30, 1) 3159b8d0c9SJoe Komlodi FIELD(DEVICE_CTRL, I3C_EN, 31, 1) 32c52aaabdSJoe Komlodi REG32(DEVICE_ADDR, 0x04) 3359b8d0c9SJoe Komlodi FIELD(DEVICE_ADDR, STATIC_ADDR, 0, 7) 3459b8d0c9SJoe Komlodi FIELD(DEVICE_ADDR, STATIC_ADDR_VALID, 15, 1) 3559b8d0c9SJoe Komlodi FIELD(DEVICE_ADDR, DYNAMIC_ADDR, 16, 7) 3659b8d0c9SJoe Komlodi FIELD(DEVICE_ADDR, DYNAMIC_ADDR_VALID, 15, 1) 37c52aaabdSJoe Komlodi REG32(HW_CAPABILITY, 0x08) 3859b8d0c9SJoe Komlodi FIELD(HW_CAPABILITY, DEVICE_ROLE_CONFIG, 0, 2) 3959b8d0c9SJoe Komlodi FIELD(HW_CAPABILITY, HDR_DDR, 3, 1) 4059b8d0c9SJoe Komlodi FIELD(HW_CAPABILITY, HDR_TS, 4, 1) 41c52aaabdSJoe Komlodi REG32(COMMAND_QUEUE_PORT, 0x0c) 4259b8d0c9SJoe Komlodi FIELD(COMMAND_QUEUE_PORT, CMD_ATTR, 0, 3) 4359b8d0c9SJoe Komlodi /* Transfer command structure */ 4459b8d0c9SJoe Komlodi FIELD(COMMAND_QUEUE_PORT, TID, 3, 4) 4559b8d0c9SJoe Komlodi FIELD(COMMAND_QUEUE_PORT, CMD, 7, 8) 4659b8d0c9SJoe Komlodi FIELD(COMMAND_QUEUE_PORT, CP, 15, 1) 4759b8d0c9SJoe Komlodi FIELD(COMMAND_QUEUE_PORT, DEV_INDEX, 16, 5) 4859b8d0c9SJoe Komlodi FIELD(COMMAND_QUEUE_PORT, SPEED, 21, 3) 4959b8d0c9SJoe Komlodi FIELD(COMMAND_QUEUE_PORT, ROC, 26, 1) 5059b8d0c9SJoe Komlodi FIELD(COMMAND_QUEUE_PORT, SDAP, 27, 1) 5159b8d0c9SJoe Komlodi FIELD(COMMAND_QUEUE_PORT, RNW, 28, 1) 5259b8d0c9SJoe Komlodi FIELD(COMMAND_QUEUE_PORT, TOC, 30, 1) 5359b8d0c9SJoe Komlodi FIELD(COMMAND_QUEUE_PORT, PEC, 31, 1) 5459b8d0c9SJoe Komlodi /* Transfer argument data structure */ 5559b8d0c9SJoe Komlodi FIELD(COMMAND_QUEUE_PORT, DB, 8, 8) 5659b8d0c9SJoe Komlodi FIELD(COMMAND_QUEUE_PORT, DL, 16, 16) 5759b8d0c9SJoe Komlodi /* Short data argument data structure */ 5859b8d0c9SJoe Komlodi FIELD(COMMAND_QUEUE_PORT, BYTE_STRB, 3, 3) 5959b8d0c9SJoe Komlodi FIELD(COMMAND_QUEUE_PORT, BYTE0, 8, 8) 6059b8d0c9SJoe Komlodi FIELD(COMMAND_QUEUE_PORT, BYTE1, 16, 8) 6159b8d0c9SJoe Komlodi FIELD(COMMAND_QUEUE_PORT, BYTE2, 24, 8) 6259b8d0c9SJoe Komlodi /* Address assignment command structure */ 6359b8d0c9SJoe Komlodi /* 6459b8d0c9SJoe Komlodi * bits 3..21 and 26..31 are the same as the transfer command structure, or 6559b8d0c9SJoe Komlodi * marked as reserved. 6659b8d0c9SJoe Komlodi */ 6759b8d0c9SJoe Komlodi FIELD(COMMAND_QUEUE_PORT, DEV_COUNT, 21, 3) 68c52aaabdSJoe Komlodi REG32(RESPONSE_QUEUE_PORT, 0x10) 6959b8d0c9SJoe Komlodi FIELD(RESPONSE_QUEUE_PORT, DL, 0, 16) 7059b8d0c9SJoe Komlodi FIELD(RESPONSE_QUEUE_PORT, CCCT, 16, 8) 7159b8d0c9SJoe Komlodi FIELD(RESPONSE_QUEUE_PORT, TID, 24, 4) 7259b8d0c9SJoe Komlodi FIELD(RESPONSE_QUEUE_PORT, ERR_STATUS, 28, 4) 73c52aaabdSJoe Komlodi REG32(RX_TX_DATA_PORT, 0x14) 74c52aaabdSJoe Komlodi REG32(IBI_QUEUE_STATUS, 0x18) 7559b8d0c9SJoe Komlodi FIELD(IBI_QUEUE_STATUS, IBI_DATA_LEN, 0, 8) 7659b8d0c9SJoe Komlodi FIELD(IBI_QUEUE_STATUS, IBI_ID, 8, 8) 7759b8d0c9SJoe Komlodi FIELD(IBI_QUEUE_STATUS, LAST_STATUS, 24, 1) 7859b8d0c9SJoe Komlodi FIELD(IBI_QUEUE_STATUS, ERROR, 30, 1) 7959b8d0c9SJoe Komlodi FIELD(IBI_QUEUE_STATUS, IBI_STATUS, 31, 1) 80c52aaabdSJoe Komlodi REG32(IBI_QUEUE_DATA, 0x18) 81c52aaabdSJoe Komlodi REG32(QUEUE_THLD_CTRL, 0x1c) 8259b8d0c9SJoe Komlodi FIELD(QUEUE_THLD_CTRL, CMD_BUF_EMPTY_THLD, 0, 8); 8359b8d0c9SJoe Komlodi FIELD(QUEUE_THLD_CTRL, RESP_BUF_THLD, 8, 8); 8459b8d0c9SJoe Komlodi FIELD(QUEUE_THLD_CTRL, IBI_DATA_THLD, 16, 8); 8559b8d0c9SJoe Komlodi FIELD(QUEUE_THLD_CTRL, IBI_STATUS_THLD, 24, 8); 86c52aaabdSJoe Komlodi REG32(DATA_BUFFER_THLD_CTRL, 0x20) 8759b8d0c9SJoe Komlodi FIELD(DATA_BUFFER_THLD_CTRL, TX_BUF_THLD, 0, 3) 8859b8d0c9SJoe Komlodi FIELD(DATA_BUFFER_THLD_CTRL, RX_BUF_THLD, 10, 3) 8959b8d0c9SJoe Komlodi FIELD(DATA_BUFFER_THLD_CTRL, TX_START_THLD, 16, 3) 9059b8d0c9SJoe Komlodi FIELD(DATA_BUFFER_THLD_CTRL, RX_START_THLD, 24, 3) 91c52aaabdSJoe Komlodi REG32(IBI_QUEUE_CTRL, 0x24) 9259b8d0c9SJoe Komlodi FIELD(IBI_QUEUE_CTRL, NOTIFY_REJECTED_HOT_JOIN, 0, 1) 9359b8d0c9SJoe Komlodi FIELD(IBI_QUEUE_CTRL, NOTIFY_REJECTED_MASTER_REQ, 1, 1) 9459b8d0c9SJoe Komlodi FIELD(IBI_QUEUE_CTRL, NOTIFY_REJECTED_SLAVE_IRQ, 3, 1) 95c52aaabdSJoe Komlodi REG32(IBI_MR_REQ_REJECT, 0x2c) 96c52aaabdSJoe Komlodi REG32(IBI_SIR_REQ_REJECT, 0x30) 97c52aaabdSJoe Komlodi REG32(RESET_CTRL, 0x34) 9859b8d0c9SJoe Komlodi FIELD(RESET_CTRL, CORE_RESET, 0, 1) 9959b8d0c9SJoe Komlodi FIELD(RESET_CTRL, CMD_QUEUE_RESET, 1, 1) 10059b8d0c9SJoe Komlodi FIELD(RESET_CTRL, RESP_QUEUE_RESET, 2, 1) 10159b8d0c9SJoe Komlodi FIELD(RESET_CTRL, TX_BUF_RESET, 3, 1) 10259b8d0c9SJoe Komlodi FIELD(RESET_CTRL, RX_BUF_RESET, 4, 1) 10359b8d0c9SJoe Komlodi FIELD(RESET_CTRL, IBI_QUEUE_RESET, 5, 1) 104c52aaabdSJoe Komlodi REG32(SLV_EVENT_CTRL, 0x38) 10559b8d0c9SJoe Komlodi FIELD(SLV_EVENT_CTRL, SLV_INTERRUPT, 0, 1) 10659b8d0c9SJoe Komlodi FIELD(SLV_EVENT_CTRL, MASTER_INTERRUPT, 1, 1) 10759b8d0c9SJoe Komlodi FIELD(SLV_EVENT_CTRL, HOT_JOIN_INTERRUPT, 3, 1) 10859b8d0c9SJoe Komlodi FIELD(SLV_EVENT_CTRL, ACTIVITY_STATE, 4, 2) 10959b8d0c9SJoe Komlodi FIELD(SLV_EVENT_CTRL, MRL_UPDATED, 6, 1) 11059b8d0c9SJoe Komlodi FIELD(SLV_EVENT_CTRL, MWL_UPDATED, 7, 1) 111c52aaabdSJoe Komlodi REG32(INTR_STATUS, 0x3c) 11259b8d0c9SJoe Komlodi FIELD(INTR_STATUS, TX_THLD, 0, 1) 11359b8d0c9SJoe Komlodi FIELD(INTR_STATUS, RX_THLD, 1, 1) 11459b8d0c9SJoe Komlodi FIELD(INTR_STATUS, IBI_THLD, 2, 1) 11559b8d0c9SJoe Komlodi FIELD(INTR_STATUS, CMD_QUEUE_RDY, 3, 1) 11659b8d0c9SJoe Komlodi FIELD(INTR_STATUS, RESP_RDY, 4, 1) 11759b8d0c9SJoe Komlodi FIELD(INTR_STATUS, TRANSFER_ABORT, 5, 1) 11859b8d0c9SJoe Komlodi FIELD(INTR_STATUS, CCC_UPDATED, 6, 1) 11959b8d0c9SJoe Komlodi FIELD(INTR_STATUS, DYN_ADDR_ASSGN, 8, 1) 12059b8d0c9SJoe Komlodi FIELD(INTR_STATUS, TRANSFER_ERR, 9, 1) 12159b8d0c9SJoe Komlodi FIELD(INTR_STATUS, DEFSLV, 10, 1) 12259b8d0c9SJoe Komlodi FIELD(INTR_STATUS, READ_REQ_RECV, 11, 1) 12359b8d0c9SJoe Komlodi FIELD(INTR_STATUS, IBI_UPDATED, 12, 1) 12459b8d0c9SJoe Komlodi FIELD(INTR_STATUS, BUSOWNER_UPDATED, 13, 1) 125c52aaabdSJoe Komlodi REG32(INTR_STATUS_EN, 0x40) 12659b8d0c9SJoe Komlodi FIELD(INTR_STATUS_EN, TX_THLD, 0, 1) 12759b8d0c9SJoe Komlodi FIELD(INTR_STATUS_EN, RX_THLD, 1, 1) 12859b8d0c9SJoe Komlodi FIELD(INTR_STATUS_EN, IBI_THLD, 2, 1) 12959b8d0c9SJoe Komlodi FIELD(INTR_STATUS_EN, CMD_QUEUE_RDY, 3, 1) 13059b8d0c9SJoe Komlodi FIELD(INTR_STATUS_EN, RESP_RDY, 4, 1) 13159b8d0c9SJoe Komlodi FIELD(INTR_STATUS_EN, TRANSFER_ABORT, 5, 1) 13259b8d0c9SJoe Komlodi FIELD(INTR_STATUS_EN, CCC_UPDATED, 6, 1) 13359b8d0c9SJoe Komlodi FIELD(INTR_STATUS_EN, DYN_ADDR_ASSGN, 8, 1) 13459b8d0c9SJoe Komlodi FIELD(INTR_STATUS_EN, TRANSFER_ERR, 9, 1) 13559b8d0c9SJoe Komlodi FIELD(INTR_STATUS_EN, DEFSLV, 10, 1) 13659b8d0c9SJoe Komlodi FIELD(INTR_STATUS_EN, READ_REQ_RECV, 11, 1) 13759b8d0c9SJoe Komlodi FIELD(INTR_STATUS_EN, IBI_UPDATED, 12, 1) 13859b8d0c9SJoe Komlodi FIELD(INTR_STATUS_EN, BUSOWNER_UPDATED, 13, 1) 139c52aaabdSJoe Komlodi REG32(INTR_SIGNAL_EN, 0x44) 14059b8d0c9SJoe Komlodi FIELD(INTR_SIGNAL_EN, TX_THLD, 0, 1) 14159b8d0c9SJoe Komlodi FIELD(INTR_SIGNAL_EN, RX_THLD, 1, 1) 14259b8d0c9SJoe Komlodi FIELD(INTR_SIGNAL_EN, IBI_THLD, 2, 1) 14359b8d0c9SJoe Komlodi FIELD(INTR_SIGNAL_EN, CMD_QUEUE_RDY, 3, 1) 14459b8d0c9SJoe Komlodi FIELD(INTR_SIGNAL_EN, RESP_RDY, 4, 1) 14559b8d0c9SJoe Komlodi FIELD(INTR_SIGNAL_EN, TRANSFER_ABORT, 5, 1) 14659b8d0c9SJoe Komlodi FIELD(INTR_SIGNAL_EN, CCC_UPDATED, 6, 1) 14759b8d0c9SJoe Komlodi FIELD(INTR_SIGNAL_EN, DYN_ADDR_ASSGN, 8, 1) 14859b8d0c9SJoe Komlodi FIELD(INTR_SIGNAL_EN, TRANSFER_ERR, 9, 1) 14959b8d0c9SJoe Komlodi FIELD(INTR_SIGNAL_EN, DEFSLV, 10, 1) 15059b8d0c9SJoe Komlodi FIELD(INTR_SIGNAL_EN, READ_REQ_RECV, 11, 1) 15159b8d0c9SJoe Komlodi FIELD(INTR_SIGNAL_EN, IBI_UPDATED, 12, 1) 15259b8d0c9SJoe Komlodi FIELD(INTR_SIGNAL_EN, BUSOWNER_UPDATED, 13, 1) 153c52aaabdSJoe Komlodi REG32(INTR_FORCE, 0x48) 15459b8d0c9SJoe Komlodi FIELD(INTR_FORCE, TX_THLD, 0, 1) 15559b8d0c9SJoe Komlodi FIELD(INTR_FORCE, RX_THLD, 1, 1) 15659b8d0c9SJoe Komlodi FIELD(INTR_FORCE, IBI_THLD, 2, 1) 15759b8d0c9SJoe Komlodi FIELD(INTR_FORCE, CMD_QUEUE_RDY, 3, 1) 15859b8d0c9SJoe Komlodi FIELD(INTR_FORCE, RESP_RDY, 4, 1) 15959b8d0c9SJoe Komlodi FIELD(INTR_FORCE, TRANSFER_ABORT, 5, 1) 16059b8d0c9SJoe Komlodi FIELD(INTR_FORCE, CCC_UPDATED, 6, 1) 16159b8d0c9SJoe Komlodi FIELD(INTR_FORCE, DYN_ADDR_ASSGN, 8, 1) 16259b8d0c9SJoe Komlodi FIELD(INTR_FORCE, TRANSFER_ERR, 9, 1) 16359b8d0c9SJoe Komlodi FIELD(INTR_FORCE, DEFSLV, 10, 1) 16459b8d0c9SJoe Komlodi FIELD(INTR_FORCE, READ_REQ_RECV, 11, 1) 16559b8d0c9SJoe Komlodi FIELD(INTR_FORCE, IBI_UPDATED, 12, 1) 16659b8d0c9SJoe Komlodi FIELD(INTR_FORCE, BUSOWNER_UPDATED, 13, 1) 167c52aaabdSJoe Komlodi REG32(QUEUE_STATUS_LEVEL, 0x4c) 16859b8d0c9SJoe Komlodi FIELD(QUEUE_STATUS_LEVEL, CMD_QUEUE_EMPTY_LOC, 0, 8) 16959b8d0c9SJoe Komlodi FIELD(QUEUE_STATUS_LEVEL, RESP_BUF_BLR, 8, 8) 17059b8d0c9SJoe Komlodi FIELD(QUEUE_STATUS_LEVEL, IBI_BUF_BLR, 16, 8) 17159b8d0c9SJoe Komlodi FIELD(QUEUE_STATUS_LEVEL, IBI_STATUS_CNT, 24, 5) 172c52aaabdSJoe Komlodi REG32(DATA_BUFFER_STATUS_LEVEL, 0x50) 17359b8d0c9SJoe Komlodi FIELD(DATA_BUFFER_STATUS_LEVEL, TX_BUF_EMPTY_LOC, 0, 8) 17459b8d0c9SJoe Komlodi FIELD(DATA_BUFFER_STATUS_LEVEL, RX_BUF_BLR, 16, 8) 175c52aaabdSJoe Komlodi REG32(PRESENT_STATE, 0x54) 17659b8d0c9SJoe Komlodi FIELD(PRESENT_STATE, SCL_LINE_SIGNAL_LEVEL, 0, 1) 17759b8d0c9SJoe Komlodi FIELD(PRESENT_STATE, SDA_LINE_SIGNAL_LEVEL, 1, 1) 17859b8d0c9SJoe Komlodi FIELD(PRESENT_STATE, CURRENT_MASTER, 2, 1) 17959b8d0c9SJoe Komlodi FIELD(PRESENT_STATE, CM_TFR_STATUS, 8, 6) 18059b8d0c9SJoe Komlodi FIELD(PRESENT_STATE, CM_TFR_ST_STATUS, 16, 6) 18159b8d0c9SJoe Komlodi FIELD(PRESENT_STATE, CMD_TID, 24, 4) 182c52aaabdSJoe Komlodi REG32(CCC_DEVICE_STATUS, 0x58) 18359b8d0c9SJoe Komlodi FIELD(CCC_DEVICE_STATUS, PENDING_INTR, 0, 4) 18459b8d0c9SJoe Komlodi FIELD(CCC_DEVICE_STATUS, PROTOCOL_ERR, 4, 2) 18559b8d0c9SJoe Komlodi FIELD(CCC_DEVICE_STATUS, ACTIVITY_MODE, 6, 2) 18659b8d0c9SJoe Komlodi FIELD(CCC_DEVICE_STATUS, UNDER_ERR, 8, 1) 18759b8d0c9SJoe Komlodi FIELD(CCC_DEVICE_STATUS, SLV_BUSY, 9, 1) 18859b8d0c9SJoe Komlodi FIELD(CCC_DEVICE_STATUS, OVERFLOW_ERR, 10, 1) 18959b8d0c9SJoe Komlodi FIELD(CCC_DEVICE_STATUS, DATA_NOT_READY, 11, 1) 19059b8d0c9SJoe Komlodi FIELD(CCC_DEVICE_STATUS, BUFFER_NOT_AVAIL, 12, 1) 191c52aaabdSJoe Komlodi REG32(DEVICE_ADDR_TABLE_POINTER, 0x5c) 192c52aaabdSJoe Komlodi FIELD(DEVICE_ADDR_TABLE_POINTER, DEPTH, 16, 16) 193c52aaabdSJoe Komlodi FIELD(DEVICE_ADDR_TABLE_POINTER, ADDR, 0, 16) 194c52aaabdSJoe Komlodi REG32(DEV_CHAR_TABLE_POINTER, 0x60) 19559b8d0c9SJoe Komlodi FIELD(DEV_CHAR_TABLE_POINTER, P_DEV_CHAR_TABLE_START_ADDR, 0, 12) 19659b8d0c9SJoe Komlodi FIELD(DEV_CHAR_TABLE_POINTER, DEV_CHAR_TABLE_DEPTH, 12, 7) 19759b8d0c9SJoe Komlodi FIELD(DEV_CHAR_TABLE_POINTER, PRESENT_DEV_CHAR_TABLE_INDEX, 19, 3) 198c52aaabdSJoe Komlodi REG32(VENDOR_SPECIFIC_REG_POINTER, 0x6c) 19959b8d0c9SJoe Komlodi FIELD(VENDOR_SPECIFIC_REG_POINTER, P_VENDOR_REG_START_ADDR, 0, 16) 200c52aaabdSJoe Komlodi REG32(SLV_MIPI_PID_VALUE, 0x70) 201c52aaabdSJoe Komlodi REG32(SLV_PID_VALUE, 0x74) 20259b8d0c9SJoe Komlodi FIELD(SLV_PID_VALUE, SLV_PID_DCR, 0, 12) 20359b8d0c9SJoe Komlodi FIELD(SLV_PID_VALUE, SLV_INST_ID, 12, 4) 20459b8d0c9SJoe Komlodi FIELD(SLV_PID_VALUE, SLV_PART_ID, 16, 16) 205c52aaabdSJoe Komlodi REG32(SLV_CHAR_CTRL, 0x78) 20659b8d0c9SJoe Komlodi FIELD(SLV_CHAR_CTRL, BCR, 0, 8) 20759b8d0c9SJoe Komlodi FIELD(SLV_CHAR_CTRL, DCR, 8, 8) 20859b8d0c9SJoe Komlodi FIELD(SLV_CHAR_CTRL, HDR_CAP, 16, 8) 209c52aaabdSJoe Komlodi REG32(SLV_MAX_LEN, 0x7c) 21059b8d0c9SJoe Komlodi FIELD(SLV_MAX_LEN, MWL, 0, 16) 21159b8d0c9SJoe Komlodi FIELD(SLV_MAX_LEN, MRL, 16, 16) 212c52aaabdSJoe Komlodi REG32(MAX_READ_TURNAROUND, 0x80) 213c52aaabdSJoe Komlodi REG32(MAX_DATA_SPEED, 0x84) 214c52aaabdSJoe Komlodi REG32(SLV_DEBUG_STATUS, 0x88) 215c52aaabdSJoe Komlodi REG32(SLV_INTR_REQ, 0x8c) 21659b8d0c9SJoe Komlodi FIELD(SLV_INTR_REQ, SIR, 0, 1) 21759b8d0c9SJoe Komlodi FIELD(SLV_INTR_REQ, SIR_CTRL, 1, 2) 21859b8d0c9SJoe Komlodi FIELD(SLV_INTR_REQ, MIR, 3, 1) 21959b8d0c9SJoe Komlodi FIELD(SLV_INTR_REQ, TS, 4, 1) 22059b8d0c9SJoe Komlodi FIELD(SLV_INTR_REQ, IBI_STS, 8, 2) 22159b8d0c9SJoe Komlodi FIELD(SLV_INTR_REQ, MDB, 8, 8) 22259b8d0c9SJoe Komlodi FIELD(SLV_INTR_REQ, SIR_DATA_LEN, 16, 8) 22359b8d0c9SJoe Komlodi REG32(SLV_TSX_SYMBL_TIMING, 0x90) 22459b8d0c9SJoe Komlodi FIELD(SLV_TSX_SYMBL_TIMING, SLV_TSX_SYMBL_CNT, 0, 6) 22559b8d0c9SJoe Komlodi REG32(SLV_SIR_DATA, 0x94) 22659b8d0c9SJoe Komlodi FIELD(SLV_SIR_DATA, SIR_DATA_BYTE0, 0, 8) 22759b8d0c9SJoe Komlodi FIELD(SLV_SIR_DATA, SIR_DATA_BYTE1, 8, 8) 22859b8d0c9SJoe Komlodi FIELD(SLV_SIR_DATA, SIR_DATA_BYTE2, 16, 8) 22959b8d0c9SJoe Komlodi FIELD(SLV_SIR_DATA, SIR_DATA_BYTE3, 24, 8) 23059b8d0c9SJoe Komlodi REG32(SLV_IBI_RESP, 0x98) 23159b8d0c9SJoe Komlodi FIELD(SLV_IBI_RESP, IBI_STS, 0, 2) 23259b8d0c9SJoe Komlodi FIELD(SLV_IBI_RESP, SIR_RESP_DATA_LEN, 8, 16) 233c52aaabdSJoe Komlodi REG32(DEVICE_CTRL_EXTENDED, 0xb0) 23459b8d0c9SJoe Komlodi FIELD(DEVICE_CTRL_EXTENDED, MODE, 0, 2) 23559b8d0c9SJoe Komlodi FIELD(DEVICE_CTRL_EXTENDED, REQMST_ACK_CTRL, 3, 1) 236c52aaabdSJoe Komlodi REG32(SCL_I3C_OD_TIMING, 0xb4) 23759b8d0c9SJoe Komlodi FIELD(SCL_I3C_OD_TIMING, I3C_OD_LCNT, 0, 8) 23859b8d0c9SJoe Komlodi FIELD(SCL_I3C_OD_TIMING, I3C_OD_HCNT, 16, 8) 239c52aaabdSJoe Komlodi REG32(SCL_I3C_PP_TIMING, 0xb8) 24059b8d0c9SJoe Komlodi FIELD(SCL_I3C_PP_TIMING, I3C_PP_LCNT, 0, 8) 24159b8d0c9SJoe Komlodi FIELD(SCL_I3C_PP_TIMING, I3C_PP_HCNT, 16, 8) 242c52aaabdSJoe Komlodi REG32(SCL_I2C_FM_TIMING, 0xbc) 243c52aaabdSJoe Komlodi REG32(SCL_I2C_FMP_TIMING, 0xc0) 24459b8d0c9SJoe Komlodi FIELD(SCL_I2C_FMP_TIMING, I2C_FMP_LCNT, 0, 16) 24559b8d0c9SJoe Komlodi FIELD(SCL_I2C_FMP_TIMING, I2C_FMP_HCNT, 16, 8) 246c52aaabdSJoe Komlodi REG32(SCL_EXT_LCNT_TIMING, 0xc8) 247c52aaabdSJoe Komlodi REG32(SCL_EXT_TERMN_LCNT_TIMING, 0xcc) 248c52aaabdSJoe Komlodi REG32(BUS_FREE_TIMING, 0xd4) 249c52aaabdSJoe Komlodi REG32(BUS_IDLE_TIMING, 0xd8) 25059b8d0c9SJoe Komlodi FIELD(BUS_IDLE_TIMING, BUS_IDLE_TIME, 0, 20) 251c52aaabdSJoe Komlodi REG32(I3C_VER_ID, 0xe0) 252c52aaabdSJoe Komlodi REG32(I3C_VER_TYPE, 0xe4) 253c52aaabdSJoe Komlodi REG32(EXTENDED_CAPABILITY, 0xe8) 25459b8d0c9SJoe Komlodi FIELD(EXTENDED_CAPABILITY, APP_IF_MODE, 0, 2) 25559b8d0c9SJoe Komlodi FIELD(EXTENDED_CAPABILITY, APP_IF_DATA_WIDTH, 2, 2) 25659b8d0c9SJoe Komlodi FIELD(EXTENDED_CAPABILITY, OPERATION_MODE, 4, 2) 25759b8d0c9SJoe Komlodi FIELD(EXTENDED_CAPABILITY, CLK_PERIOD, 8, 6) 258c52aaabdSJoe Komlodi REG32(SLAVE_CONFIG, 0xec) 25959b8d0c9SJoe Komlodi FIELD(SLAVE_CONFIG, DMA_EN, 0, 1) 26059b8d0c9SJoe Komlodi FIELD(SLAVE_CONFIG, HJ_CAP, 0, 1) 26159b8d0c9SJoe Komlodi FIELD(SLAVE_CONFIG, CLK_PERIOD, 2, 14) 26259b8d0c9SJoe Komlodi /* Device characteristic table fields */ 26359b8d0c9SJoe Komlodi REG32(DEVICE_CHARACTERISTIC_TABLE_LOC1, 0x200) 26459b8d0c9SJoe Komlodi REG32(DEVICE_CHARACTERISTIC_TABLE_LOC_SECONDARY, 0x200) 26559b8d0c9SJoe Komlodi FIELD(DEVICE_CHARACTERISTIC_TABLE_LOC_SECONDARY, DYNAMIC_ADDR, 0, 8) 26659b8d0c9SJoe Komlodi FIELD(DEVICE_CHARACTERISTIC_TABLE_LOC_SECONDARY, DCR, 8, 8) 26759b8d0c9SJoe Komlodi FIELD(DEVICE_CHARACTERISTIC_TABLE_LOC_SECONDARY, BCR, 16, 8) 26859b8d0c9SJoe Komlodi FIELD(DEVICE_CHARACTERISTIC_TABLE_LOC_SECONDARY, STATIC_ADDR, 24, 8) 26959b8d0c9SJoe Komlodi REG32(DEVICE_CHARACTERISTIC_TABLE_LOC2, 0x204) 27059b8d0c9SJoe Komlodi FIELD(DEVICE_CHARACTERISTIC_TABLE_LOC2, MSB_PID, 0, 16) 27159b8d0c9SJoe Komlodi REG32(DEVICE_CHARACTERISTIC_TABLE_LOC3, 0x208) 27259b8d0c9SJoe Komlodi FIELD(DEVICE_CHARACTERISTIC_TABLE_LOC3, DCR, 0, 8) 27359b8d0c9SJoe Komlodi FIELD(DEVICE_CHARACTERISTIC_TABLE_LOC3, BCR, 8, 8) 27459b8d0c9SJoe Komlodi REG32(DEVICE_CHARACTERISTIC_TABLE_LOC4, 0x20c) 27559b8d0c9SJoe Komlodi FIELD(DEVICE_CHARACTERISTIC_TABLE_LOC4, DEV_DYNAMIC_ADDR, 0, 8) 27659b8d0c9SJoe Komlodi /* Dev addr table fields */ 27759b8d0c9SJoe Komlodi REG32(DEVICE_ADDR_TABLE_LOC1, 0x280) 27859b8d0c9SJoe Komlodi FIELD(DEVICE_ADDR_TABLE_LOC1, DEV_STATIC_ADDR, 0, 7) 27959b8d0c9SJoe Komlodi FIELD(DEVICE_ADDR_TABLE_LOC1, IBI_PEC_EN, 11, 1) 28059b8d0c9SJoe Komlodi FIELD(DEVICE_ADDR_TABLE_LOC1, IBI_WITH_DATA, 12, 1) 28159b8d0c9SJoe Komlodi FIELD(DEVICE_ADDR_TABLE_LOC1, SIR_REJECT, 13, 1) 28259b8d0c9SJoe Komlodi FIELD(DEVICE_ADDR_TABLE_LOC1, MR_REJECT, 14, 1) 28359b8d0c9SJoe Komlodi FIELD(DEVICE_ADDR_TABLE_LOC1, DEV_DYNAMIC_ADDR, 16, 8) 28459b8d0c9SJoe Komlodi FIELD(DEVICE_ADDR_TABLE_LOC1, IBI_ADDR_MASK, 24, 2) 28559b8d0c9SJoe Komlodi FIELD(DEVICE_ADDR_TABLE_LOC1, DEV_NACK_RETRY_CNT, 29, 2) 28659b8d0c9SJoe Komlodi FIELD(DEVICE_ADDR_TABLE_LOC1, LEGACY_I2C_DEVICE, 31, 1) 287c52aaabdSJoe Komlodi 288c52aaabdSJoe Komlodi static const uint32_t dw_i3c_resets[DW_I3C_NR_REGS] = { 28973a38a9bSJoe Komlodi /* Target mode is not supported, don't advertise it for now. */ 29073a38a9bSJoe Komlodi [R_HW_CAPABILITY] = 0x000e00b9, 291c52aaabdSJoe Komlodi [R_QUEUE_THLD_CTRL] = 0x01000101, 29273a38a9bSJoe Komlodi [R_DATA_BUFFER_THLD_CTRL] = 0x01010100, 29373a38a9bSJoe Komlodi [R_SLV_EVENT_CTRL] = 0x0000000b, 29473a38a9bSJoe Komlodi [R_QUEUE_STATUS_LEVEL] = 0x00000002, 29573a38a9bSJoe Komlodi [R_DATA_BUFFER_STATUS_LEVEL] = 0x00000010, 29673a38a9bSJoe Komlodi [R_PRESENT_STATE] = 0x00000003, 297c52aaabdSJoe Komlodi [R_I3C_VER_ID] = 0x3130302a, 298c52aaabdSJoe Komlodi [R_I3C_VER_TYPE] = 0x6c633033, 299c52aaabdSJoe Komlodi [R_DEVICE_ADDR_TABLE_POINTER] = 0x00080280, 300c52aaabdSJoe Komlodi [R_DEV_CHAR_TABLE_POINTER] = 0x00020200, 30173a38a9bSJoe Komlodi [R_SLV_CHAR_CTRL] = 0x00010000, 302c52aaabdSJoe Komlodi [A_VENDOR_SPECIFIC_REG_POINTER] = 0x000000b0, 303c52aaabdSJoe Komlodi [R_SLV_MAX_LEN] = 0x00ff00ff, 30473a38a9bSJoe Komlodi [R_SLV_TSX_SYMBL_TIMING] = 0x0000003f, 30573a38a9bSJoe Komlodi [R_SCL_I3C_OD_TIMING] = 0x000a0010, 30673a38a9bSJoe Komlodi [R_SCL_I3C_PP_TIMING] = 0x000a000a, 30773a38a9bSJoe Komlodi [R_SCL_I2C_FM_TIMING] = 0x00100010, 30873a38a9bSJoe Komlodi [R_SCL_I2C_FMP_TIMING] = 0x00100010, 30973a38a9bSJoe Komlodi [R_SCL_EXT_LCNT_TIMING] = 0x20202020, 31073a38a9bSJoe Komlodi [R_SCL_EXT_TERMN_LCNT_TIMING] = 0x00300000, 31173a38a9bSJoe Komlodi [R_BUS_FREE_TIMING] = 0x00200020, 31273a38a9bSJoe Komlodi [R_BUS_IDLE_TIMING] = 0x00000020, 31373a38a9bSJoe Komlodi [R_EXTENDED_CAPABILITY] = 0x00000239, 31473a38a9bSJoe Komlodi [R_SLAVE_CONFIG] = 0x00000023, 315c52aaabdSJoe Komlodi }; 316c52aaabdSJoe Komlodi 317ef77491fSJoe Komlodi static const uint32_t dw_i3c_ro[DW_I3C_NR_REGS] = { 318ef77491fSJoe Komlodi [R_DEVICE_CTRL] = 0x04fffe00, 319ef77491fSJoe Komlodi [R_DEVICE_ADDR] = 0x7f807f80, 320ef77491fSJoe Komlodi [R_HW_CAPABILITY] = 0xffffffff, 321ef77491fSJoe Komlodi [R_IBI_QUEUE_STATUS] = 0xffffffff, 322ef77491fSJoe Komlodi [R_DATA_BUFFER_THLD_CTRL] = 0xf8f8f8f8, 323ef77491fSJoe Komlodi [R_IBI_QUEUE_CTRL] = 0xfffffff0, 324ef77491fSJoe Komlodi [R_RESET_CTRL] = 0xffffffc0, 325ef77491fSJoe Komlodi [R_SLV_EVENT_CTRL] = 0xffffff3f, 326ef77491fSJoe Komlodi [R_INTR_STATUS] = 0xffff809f, 327ef77491fSJoe Komlodi [R_INTR_STATUS_EN] = 0xffff8080, 328ef77491fSJoe Komlodi [R_INTR_SIGNAL_EN] = 0xffff8080, 329ef77491fSJoe Komlodi [R_INTR_FORCE] = 0xffff8000, 330ef77491fSJoe Komlodi [R_QUEUE_STATUS_LEVEL] = 0xffffffff, 331ef77491fSJoe Komlodi [R_DATA_BUFFER_STATUS_LEVEL] = 0xffffffff, 332ef77491fSJoe Komlodi [R_PRESENT_STATE] = 0xffffffff, 333ef77491fSJoe Komlodi [R_CCC_DEVICE_STATUS] = 0xffffffff, 334ef77491fSJoe Komlodi [R_I3C_VER_ID] = 0xffffffff, 335ef77491fSJoe Komlodi [R_I3C_VER_TYPE] = 0xffffffff, 336ef77491fSJoe Komlodi [R_DEVICE_ADDR_TABLE_POINTER] = 0xffffffff, 337ef77491fSJoe Komlodi [R_DEV_CHAR_TABLE_POINTER] = 0xffcbffff, 338ef77491fSJoe Komlodi [R_SLV_PID_VALUE] = 0xffff0fff, 339ef77491fSJoe Komlodi [R_SLV_CHAR_CTRL] = 0xffffffff, 340ef77491fSJoe Komlodi [A_VENDOR_SPECIFIC_REG_POINTER] = 0xffffffff, 341ef77491fSJoe Komlodi [R_SLV_MAX_LEN] = 0xffffffff, 342ef77491fSJoe Komlodi [R_MAX_READ_TURNAROUND] = 0xffffffff, 343ef77491fSJoe Komlodi [R_MAX_DATA_SPEED] = 0xffffffff, 344ef77491fSJoe Komlodi [R_SLV_INTR_REQ] = 0xfffffff0, 345ef77491fSJoe Komlodi [R_SLV_TSX_SYMBL_TIMING] = 0xffffffc0, 346ef77491fSJoe Komlodi [R_DEVICE_CTRL_EXTENDED] = 0xfffffff8, 347ef77491fSJoe Komlodi [R_SCL_I3C_OD_TIMING] = 0xff00ff00, 348ef77491fSJoe Komlodi [R_SCL_I3C_PP_TIMING] = 0xff00ff00, 349ef77491fSJoe Komlodi [R_SCL_I2C_FMP_TIMING] = 0xff000000, 350ef77491fSJoe Komlodi [R_SCL_EXT_TERMN_LCNT_TIMING] = 0x0000fff0, 351ef77491fSJoe Komlodi [R_BUS_IDLE_TIMING] = 0xfff00000, 352ef77491fSJoe Komlodi [R_EXTENDED_CAPABILITY] = 0xffffffff, 353ef77491fSJoe Komlodi [R_SLAVE_CONFIG] = 0xffffffff, 354ef77491fSJoe Komlodi }; 355ef77491fSJoe Komlodi 356*9c0476a2SJoe Komlodi static inline bool dw_i3c_has_hdr_ts(DWI3C *s) 357*9c0476a2SJoe Komlodi { 358*9c0476a2SJoe Komlodi return ARRAY_FIELD_EX32(s->regs, HW_CAPABILITY, HDR_TS); 359*9c0476a2SJoe Komlodi } 360*9c0476a2SJoe Komlodi 361*9c0476a2SJoe Komlodi static inline bool dw_i3c_has_hdr_ddr(DWI3C *s) 362*9c0476a2SJoe Komlodi { 363*9c0476a2SJoe Komlodi return ARRAY_FIELD_EX32(s->regs, HW_CAPABILITY, HDR_DDR); 364*9c0476a2SJoe Komlodi } 365*9c0476a2SJoe Komlodi 366*9c0476a2SJoe Komlodi static inline bool dw_i3c_can_transmit(DWI3C *s) 367*9c0476a2SJoe Komlodi { 368*9c0476a2SJoe Komlodi /* 369*9c0476a2SJoe Komlodi * We can only transmit if we're enabled and the resume bit is cleared. 370*9c0476a2SJoe Komlodi * The resume bit is set on a transaction error, and software must clear it. 371*9c0476a2SJoe Komlodi */ 372*9c0476a2SJoe Komlodi return ARRAY_FIELD_EX32(s->regs, DEVICE_CTRL, I3C_EN) && 373*9c0476a2SJoe Komlodi !ARRAY_FIELD_EX32(s->regs, DEVICE_CTRL, I3C_RESUME); 374*9c0476a2SJoe Komlodi } 375*9c0476a2SJoe Komlodi 376*9c0476a2SJoe Komlodi static inline uint8_t dw_i3c_fifo_threshold_from_reg(uint8_t regval) 377*9c0476a2SJoe Komlodi { 378*9c0476a2SJoe Komlodi return regval = regval ? (2 << regval) : 1; 379*9c0476a2SJoe Komlodi } 380*9c0476a2SJoe Komlodi 381a825bbb7SJoe Komlodi static void dw_i3c_update_irq(DWI3C *s) 382a825bbb7SJoe Komlodi { 383a825bbb7SJoe Komlodi bool level = !!(s->regs[R_INTR_SIGNAL_EN] & s->regs[R_INTR_STATUS]); 384a825bbb7SJoe Komlodi qemu_set_irq(s->irq, level); 385a825bbb7SJoe Komlodi } 386a825bbb7SJoe Komlodi 387*9c0476a2SJoe Komlodi static void dw_i3c_end_transfer(DWI3C *s, bool is_i2c) 388*9c0476a2SJoe Komlodi { 389*9c0476a2SJoe Komlodi if (is_i2c) { 390*9c0476a2SJoe Komlodi legacy_i2c_end_transfer(s->bus); 391*9c0476a2SJoe Komlodi } else { 392*9c0476a2SJoe Komlodi i3c_end_transfer(s->bus); 393*9c0476a2SJoe Komlodi } 394*9c0476a2SJoe Komlodi } 395*9c0476a2SJoe Komlodi 396*9c0476a2SJoe Komlodi static int dw_i3c_send_start(DWI3C *s, uint8_t addr, bool is_recv, bool is_i2c) 397*9c0476a2SJoe Komlodi { 398*9c0476a2SJoe Komlodi int ret; 399*9c0476a2SJoe Komlodi 400*9c0476a2SJoe Komlodi if (is_i2c) { 401*9c0476a2SJoe Komlodi ret = legacy_i2c_start_transfer(s->bus, addr, is_recv); 402*9c0476a2SJoe Komlodi } else { 403*9c0476a2SJoe Komlodi ret = i3c_start_transfer(s->bus, addr, is_recv); 404*9c0476a2SJoe Komlodi } 405*9c0476a2SJoe Komlodi if (ret) { 406*9c0476a2SJoe Komlodi g_autofree char *path = object_get_canonical_path(OBJECT(s)); 407*9c0476a2SJoe Komlodi qemu_log_mask(LOG_GUEST_ERROR, "%s: NACKed on TX with addr 0x%.2x\n", 408*9c0476a2SJoe Komlodi path, addr); 409*9c0476a2SJoe Komlodi ARRAY_FIELD_DP32(s->regs, PRESENT_STATE, CM_TFR_ST_STATUS, 410*9c0476a2SJoe Komlodi DW_I3C_TRANSFER_STATE_HALT); 411*9c0476a2SJoe Komlodi ARRAY_FIELD_DP32(s->regs, PRESENT_STATE, CM_TFR_STATUS, 412*9c0476a2SJoe Komlodi DW_I3C_TRANSFER_STATUS_HALT); 413*9c0476a2SJoe Komlodi ARRAY_FIELD_DP32(s->regs, INTR_STATUS, TRANSFER_ERR, 1); 414*9c0476a2SJoe Komlodi ARRAY_FIELD_DP32(s->regs, DEVICE_CTRL, I3C_RESUME, 1); 415*9c0476a2SJoe Komlodi } 416*9c0476a2SJoe Komlodi 417*9c0476a2SJoe Komlodi return ret; 418*9c0476a2SJoe Komlodi } 419*9c0476a2SJoe Komlodi 420*9c0476a2SJoe Komlodi static int dw_i3c_send(DWI3C *s, const uint8_t *data, uint32_t num_to_send, 421*9c0476a2SJoe Komlodi uint32_t *num_sent, bool is_i2c) 422*9c0476a2SJoe Komlodi { 423*9c0476a2SJoe Komlodi int ret; 424*9c0476a2SJoe Komlodi uint32_t i; 425*9c0476a2SJoe Komlodi 426*9c0476a2SJoe Komlodi *num_sent = 0; 427*9c0476a2SJoe Komlodi if (is_i2c) { 428*9c0476a2SJoe Komlodi /* Legacy I2C must be byte-by-byte. */ 429*9c0476a2SJoe Komlodi for (i = 0; i < num_to_send; i++) { 430*9c0476a2SJoe Komlodi ret = legacy_i2c_send(s->bus, data[i]); 431*9c0476a2SJoe Komlodi if (ret) { 432*9c0476a2SJoe Komlodi break; 433*9c0476a2SJoe Komlodi } 434*9c0476a2SJoe Komlodi (*num_sent)++; 435*9c0476a2SJoe Komlodi } 436*9c0476a2SJoe Komlodi } else { 437*9c0476a2SJoe Komlodi ret = i3c_send(s->bus, data, num_to_send, num_sent); 438*9c0476a2SJoe Komlodi } 439*9c0476a2SJoe Komlodi if (ret) { 440*9c0476a2SJoe Komlodi g_autofree char *path = object_get_canonical_path(OBJECT(s)); 441*9c0476a2SJoe Komlodi qemu_log_mask(LOG_GUEST_ERROR, "%s: NACKed sending byte 0x%.2x\n", 442*9c0476a2SJoe Komlodi path, data[*num_sent]); 443*9c0476a2SJoe Komlodi ARRAY_FIELD_DP32(s->regs, PRESENT_STATE, CM_TFR_ST_STATUS, 444*9c0476a2SJoe Komlodi DW_I3C_TRANSFER_STATE_HALT); 445*9c0476a2SJoe Komlodi ARRAY_FIELD_DP32(s->regs, PRESENT_STATE, CM_TFR_STATUS, 446*9c0476a2SJoe Komlodi DW_I3C_TRANSFER_STATUS_HALT); 447*9c0476a2SJoe Komlodi ARRAY_FIELD_DP32(s->regs, INTR_STATUS, TRANSFER_ERR, 1); 448*9c0476a2SJoe Komlodi ARRAY_FIELD_DP32(s->regs, DEVICE_CTRL, I3C_RESUME, 1); 449*9c0476a2SJoe Komlodi } 450*9c0476a2SJoe Komlodi 451*9c0476a2SJoe Komlodi trace_dw_i3c_send(s->cfg.id, *num_sent); 452*9c0476a2SJoe Komlodi 453*9c0476a2SJoe Komlodi return ret; 454*9c0476a2SJoe Komlodi } 455*9c0476a2SJoe Komlodi 456*9c0476a2SJoe Komlodi static int dw_i3c_send_byte(DWI3C *s, uint8_t byte, bool is_i2c) 457*9c0476a2SJoe Komlodi { 458*9c0476a2SJoe Komlodi /* 459*9c0476a2SJoe Komlodi * Ignored, the caller will know if we sent 0 or 1 bytes depending on if 460*9c0476a2SJoe Komlodi * we were ACKed/NACKed. 461*9c0476a2SJoe Komlodi */ 462*9c0476a2SJoe Komlodi uint32_t num_sent; 463*9c0476a2SJoe Komlodi return dw_i3c_send(s, &byte, 1, &num_sent, is_i2c); 464*9c0476a2SJoe Komlodi } 465*9c0476a2SJoe Komlodi 466*9c0476a2SJoe Komlodi static int dw_i3c_recv_data(DWI3C *s, bool is_i2c, uint8_t *data, 467*9c0476a2SJoe Komlodi uint16_t num_to_read, uint32_t *num_read) 468*9c0476a2SJoe Komlodi { 469*9c0476a2SJoe Komlodi int ret; 470*9c0476a2SJoe Komlodi 471*9c0476a2SJoe Komlodi if (is_i2c) { 472*9c0476a2SJoe Komlodi for (uint16_t i = 0; i < num_to_read; i++) { 473*9c0476a2SJoe Komlodi data[i] = legacy_i2c_recv(s->bus); 474*9c0476a2SJoe Komlodi } 475*9c0476a2SJoe Komlodi /* I2C devices can neither NACK a read, nor end transfers early. */ 476*9c0476a2SJoe Komlodi *num_read = num_to_read; 477*9c0476a2SJoe Komlodi trace_dw_i3c_recv_data(s->cfg.id, *num_read); 478*9c0476a2SJoe Komlodi return 0; 479*9c0476a2SJoe Komlodi } 480*9c0476a2SJoe Komlodi /* I3C devices can NACK if the controller sends an unsupported CCC. */ 481*9c0476a2SJoe Komlodi ret = i3c_recv(s->bus, data, num_to_read, num_read); 482*9c0476a2SJoe Komlodi if (ret) { 483*9c0476a2SJoe Komlodi qemu_log_mask(LOG_GUEST_ERROR, "%s: NACKed receiving byte\n", 484*9c0476a2SJoe Komlodi object_get_canonical_path(OBJECT(s))); 485*9c0476a2SJoe Komlodi ARRAY_FIELD_DP32(s->regs, PRESENT_STATE, CM_TFR_ST_STATUS, 486*9c0476a2SJoe Komlodi DW_I3C_TRANSFER_STATE_HALT); 487*9c0476a2SJoe Komlodi ARRAY_FIELD_DP32(s->regs, PRESENT_STATE, CM_TFR_STATUS, 488*9c0476a2SJoe Komlodi DW_I3C_TRANSFER_STATUS_HALT); 489*9c0476a2SJoe Komlodi ARRAY_FIELD_DP32(s->regs, INTR_STATUS, TRANSFER_ERR, 1); 490*9c0476a2SJoe Komlodi ARRAY_FIELD_DP32(s->regs, DEVICE_CTRL, I3C_RESUME, 1); 491*9c0476a2SJoe Komlodi } 492*9c0476a2SJoe Komlodi 493*9c0476a2SJoe Komlodi trace_dw_i3c_recv_data(s->cfg.id, *num_read); 494*9c0476a2SJoe Komlodi 495*9c0476a2SJoe Komlodi return ret; 496*9c0476a2SJoe Komlodi } 497*9c0476a2SJoe Komlodi 498*9c0476a2SJoe Komlodi static inline bool dw_i3c_target_is_i2c(DWI3C *s, uint16_t offset) 499*9c0476a2SJoe Komlodi { 500*9c0476a2SJoe Komlodi /* / sizeof(uint32_t) because we're indexing into our 32-bit reg array. */ 501*9c0476a2SJoe Komlodi uint16_t dev_index = (ARRAY_FIELD_EX32(s->regs, DEVICE_ADDR_TABLE_POINTER, 502*9c0476a2SJoe Komlodi ADDR) / sizeof(uint32_t)) + offset; 503*9c0476a2SJoe Komlodi return FIELD_EX32(s->regs[dev_index], DEVICE_ADDR_TABLE_LOC1, 504*9c0476a2SJoe Komlodi LEGACY_I2C_DEVICE); 505*9c0476a2SJoe Komlodi } 506*9c0476a2SJoe Komlodi 507*9c0476a2SJoe Komlodi static uint8_t dw_i3c_target_addr(DWI3C *s, uint16_t offset) 508*9c0476a2SJoe Komlodi { 509*9c0476a2SJoe Komlodi if (offset > s->cfg.num_addressable_devices) { 510*9c0476a2SJoe Komlodi g_autofree char *path = object_get_canonical_path(OBJECT(s)); 511*9c0476a2SJoe Komlodi qemu_log_mask(LOG_GUEST_ERROR, "%s: Device addr table offset %d out of " 512*9c0476a2SJoe Komlodi "bounds\n", path, offset); 513*9c0476a2SJoe Komlodi /* If we're out of bounds, return an address of 0. */ 514*9c0476a2SJoe Komlodi return 0; 515*9c0476a2SJoe Komlodi } 516*9c0476a2SJoe Komlodi 517*9c0476a2SJoe Komlodi /* / sizeof(uint32_t) because we're indexing into our 32-bit reg array. */ 518*9c0476a2SJoe Komlodi uint16_t dev_index = (ARRAY_FIELD_EX32(s->regs, DEVICE_ADDR_TABLE_POINTER, 519*9c0476a2SJoe Komlodi ADDR) / sizeof(uint32_t)) + offset; 520*9c0476a2SJoe Komlodi /* I2C devices use a static address. */ 521*9c0476a2SJoe Komlodi if (dw_i3c_target_is_i2c(s, offset)) { 522*9c0476a2SJoe Komlodi return FIELD_EX32(s->regs[dev_index], DEVICE_ADDR_TABLE_LOC1, 523*9c0476a2SJoe Komlodi DEV_STATIC_ADDR); 524*9c0476a2SJoe Komlodi } 525*9c0476a2SJoe Komlodi return FIELD_EX32(s->regs[dev_index], DEVICE_ADDR_TABLE_LOC1, 526*9c0476a2SJoe Komlodi DEV_DYNAMIC_ADDR); 527*9c0476a2SJoe Komlodi } 528*9c0476a2SJoe Komlodi 529a825bbb7SJoe Komlodi static uint32_t dw_i3c_intr_status_r(DWI3C *s) 530a825bbb7SJoe Komlodi { 531a825bbb7SJoe Komlodi /* Only return the status whose corresponding EN bits are set. */ 532a825bbb7SJoe Komlodi return s->regs[R_INTR_STATUS] & s->regs[R_INTR_STATUS_EN]; 533a825bbb7SJoe Komlodi } 534a825bbb7SJoe Komlodi 535a825bbb7SJoe Komlodi static void dw_i3c_intr_status_w(DWI3C *s, uint32_t val) 536a825bbb7SJoe Komlodi { 537a825bbb7SJoe Komlodi /* INTR_STATUS[13:5] is w1c, other bits are RO. */ 538a825bbb7SJoe Komlodi val &= 0x3fe0; 539a825bbb7SJoe Komlodi s->regs[R_INTR_STATUS] &= ~val; 540a825bbb7SJoe Komlodi 541a825bbb7SJoe Komlodi dw_i3c_update_irq(s); 542a825bbb7SJoe Komlodi } 543a825bbb7SJoe Komlodi 544a825bbb7SJoe Komlodi static void dw_i3c_intr_status_en_w(DWI3C *s, uint32_t val) 545a825bbb7SJoe Komlodi { 546a825bbb7SJoe Komlodi s->regs[R_INTR_STATUS_EN] = val; 547a825bbb7SJoe Komlodi dw_i3c_update_irq(s); 548a825bbb7SJoe Komlodi } 549a825bbb7SJoe Komlodi 550a825bbb7SJoe Komlodi static void dw_i3c_intr_signal_en_w(DWI3C *s, uint32_t val) 551a825bbb7SJoe Komlodi { 552a825bbb7SJoe Komlodi s->regs[R_INTR_SIGNAL_EN] = val; 553a825bbb7SJoe Komlodi dw_i3c_update_irq(s); 554a825bbb7SJoe Komlodi } 555a825bbb7SJoe Komlodi 556a825bbb7SJoe Komlodi static void dw_i3c_intr_force_w(DWI3C *s, uint32_t val) 557a825bbb7SJoe Komlodi { 558a825bbb7SJoe Komlodi /* INTR_FORCE is WO, just set the corresponding INTR_STATUS bits. */ 559a825bbb7SJoe Komlodi s->regs[R_INTR_STATUS] = val; 560a825bbb7SJoe Komlodi dw_i3c_update_irq(s); 561a825bbb7SJoe Komlodi } 562a825bbb7SJoe Komlodi 563*9c0476a2SJoe Komlodi static uint32_t dw_i3c_pop_rx(DWI3C *s) 564*9c0476a2SJoe Komlodi { 565*9c0476a2SJoe Komlodi if (fifo32_is_empty(&s->rx_queue)) { 566*9c0476a2SJoe Komlodi g_autofree char *path = object_get_canonical_path(OBJECT(s)); 567*9c0476a2SJoe Komlodi qemu_log_mask(LOG_GUEST_ERROR, "%s: Tried to read RX FIFO when empty\n", 568*9c0476a2SJoe Komlodi path); 569*9c0476a2SJoe Komlodi return 0; 570*9c0476a2SJoe Komlodi } 571*9c0476a2SJoe Komlodi 572*9c0476a2SJoe Komlodi uint32_t val = fifo32_pop(&s->rx_queue); 573*9c0476a2SJoe Komlodi ARRAY_FIELD_DP32(s->regs, DATA_BUFFER_STATUS_LEVEL, RX_BUF_BLR, 574*9c0476a2SJoe Komlodi fifo32_num_used(&s->rx_queue)); 575*9c0476a2SJoe Komlodi 576*9c0476a2SJoe Komlodi /* Threshold is 2^RX_BUF_THLD. */ 577*9c0476a2SJoe Komlodi uint8_t threshold = ARRAY_FIELD_EX32(s->regs, DATA_BUFFER_THLD_CTRL, 578*9c0476a2SJoe Komlodi RX_BUF_THLD); 579*9c0476a2SJoe Komlodi threshold = dw_i3c_fifo_threshold_from_reg(threshold); 580*9c0476a2SJoe Komlodi if (fifo32_num_used(&s->rx_queue) < threshold) { 581*9c0476a2SJoe Komlodi ARRAY_FIELD_DP32(s->regs, INTR_STATUS, RX_THLD, 0); 582*9c0476a2SJoe Komlodi dw_i3c_update_irq(s); 583*9c0476a2SJoe Komlodi } 584*9c0476a2SJoe Komlodi 585*9c0476a2SJoe Komlodi trace_dw_i3c_pop_rx(s->cfg.id, val); 586*9c0476a2SJoe Komlodi return val; 587*9c0476a2SJoe Komlodi } 588*9c0476a2SJoe Komlodi 589*9c0476a2SJoe Komlodi static uint32_t dw_i3c_resp_queue_port_r(DWI3C *s) 590*9c0476a2SJoe Komlodi { 591*9c0476a2SJoe Komlodi if (fifo32_is_empty(&s->resp_queue)) { 592*9c0476a2SJoe Komlodi g_autofree char *path = object_get_canonical_path(OBJECT(s)); 593*9c0476a2SJoe Komlodi qemu_log_mask(LOG_GUEST_ERROR, "%s: Tried to read response FIFO when " 594*9c0476a2SJoe Komlodi "empty\n", path); 595*9c0476a2SJoe Komlodi return 0; 596*9c0476a2SJoe Komlodi } 597*9c0476a2SJoe Komlodi 598*9c0476a2SJoe Komlodi uint32_t val = fifo32_pop(&s->resp_queue); 599*9c0476a2SJoe Komlodi ARRAY_FIELD_DP32(s->regs, QUEUE_STATUS_LEVEL, RESP_BUF_BLR, 600*9c0476a2SJoe Komlodi fifo32_num_used(&s->resp_queue)); 601*9c0476a2SJoe Komlodi 602*9c0476a2SJoe Komlodi /* Threshold is the register value + 1. */ 603*9c0476a2SJoe Komlodi uint8_t threshold = ARRAY_FIELD_EX32(s->regs, QUEUE_THLD_CTRL, 604*9c0476a2SJoe Komlodi RESP_BUF_THLD) + 1; 605*9c0476a2SJoe Komlodi if (fifo32_num_used(&s->resp_queue) < threshold) { 606*9c0476a2SJoe Komlodi ARRAY_FIELD_DP32(s->regs, INTR_STATUS, RESP_RDY, 0); 607*9c0476a2SJoe Komlodi dw_i3c_update_irq(s); 608*9c0476a2SJoe Komlodi } 609*9c0476a2SJoe Komlodi 610*9c0476a2SJoe Komlodi return val; 611*9c0476a2SJoe Komlodi } 612*9c0476a2SJoe Komlodi 613c52aaabdSJoe Komlodi static uint64_t dw_i3c_read(void *opaque, hwaddr offset, unsigned size) 614c52aaabdSJoe Komlodi { 615c52aaabdSJoe Komlodi DWI3C *s = DW_I3C(opaque); 616c52aaabdSJoe Komlodi uint32_t addr = offset >> 2; 617c52aaabdSJoe Komlodi uint64_t value; 618c52aaabdSJoe Komlodi 619c52aaabdSJoe Komlodi switch (addr) { 6205f31322eSJoe Komlodi /* RAZ */ 621c52aaabdSJoe Komlodi case R_COMMAND_QUEUE_PORT: 6225f31322eSJoe Komlodi case R_RESET_CTRL: 6235f31322eSJoe Komlodi case R_INTR_FORCE: 624c52aaabdSJoe Komlodi value = 0; 625c52aaabdSJoe Komlodi break; 626a825bbb7SJoe Komlodi case R_INTR_STATUS: 627a825bbb7SJoe Komlodi value = dw_i3c_intr_status_r(s); 628a825bbb7SJoe Komlodi break; 629*9c0476a2SJoe Komlodi case R_RX_TX_DATA_PORT: 630*9c0476a2SJoe Komlodi value = dw_i3c_pop_rx(s); 631*9c0476a2SJoe Komlodi break; 632*9c0476a2SJoe Komlodi case R_RESPONSE_QUEUE_PORT: 633*9c0476a2SJoe Komlodi value = dw_i3c_resp_queue_port_r(s); 634*9c0476a2SJoe Komlodi break; 635c52aaabdSJoe Komlodi default: 636c52aaabdSJoe Komlodi value = s->regs[addr]; 637c52aaabdSJoe Komlodi break; 638c52aaabdSJoe Komlodi } 639c52aaabdSJoe Komlodi 640*9c0476a2SJoe Komlodi trace_dw_i3c_read(s->cfg.id, offset, value); 641c52aaabdSJoe Komlodi 642c52aaabdSJoe Komlodi return value; 643c52aaabdSJoe Komlodi } 644c52aaabdSJoe Komlodi 645*9c0476a2SJoe Komlodi static void dw_i3c_resp_queue_push(DWI3C *s, uint8_t err, uint8_t tid, 646*9c0476a2SJoe Komlodi uint8_t ccc_type, uint16_t data_len) 647*9c0476a2SJoe Komlodi { 648*9c0476a2SJoe Komlodi uint32_t val = 0; 649*9c0476a2SJoe Komlodi val = FIELD_DP32(val, RESPONSE_QUEUE_PORT, ERR_STATUS, err); 650*9c0476a2SJoe Komlodi val = FIELD_DP32(val, RESPONSE_QUEUE_PORT, TID, tid); 651*9c0476a2SJoe Komlodi val = FIELD_DP32(val, RESPONSE_QUEUE_PORT, CCCT, ccc_type); 652*9c0476a2SJoe Komlodi val = FIELD_DP32(val, RESPONSE_QUEUE_PORT, DL, data_len); 653*9c0476a2SJoe Komlodi if (!fifo32_is_full(&s->resp_queue)) { 654*9c0476a2SJoe Komlodi trace_dw_i3c_resp_queue_push(s->cfg.id, val); 655*9c0476a2SJoe Komlodi fifo32_push(&s->resp_queue, val); 656*9c0476a2SJoe Komlodi } 657*9c0476a2SJoe Komlodi 658*9c0476a2SJoe Komlodi ARRAY_FIELD_DP32(s->regs, QUEUE_STATUS_LEVEL, RESP_BUF_BLR, 659*9c0476a2SJoe Komlodi fifo32_num_used(&s->resp_queue)); 660*9c0476a2SJoe Komlodi /* Threshold is the register value + 1. */ 661*9c0476a2SJoe Komlodi uint8_t threshold = ARRAY_FIELD_EX32(s->regs, QUEUE_THLD_CTRL, 662*9c0476a2SJoe Komlodi RESP_BUF_THLD) + 1; 663*9c0476a2SJoe Komlodi if (fifo32_num_used(&s->resp_queue) >= threshold) { 664*9c0476a2SJoe Komlodi ARRAY_FIELD_DP32(s->regs, INTR_STATUS, RESP_RDY, 1); 665*9c0476a2SJoe Komlodi dw_i3c_update_irq(s); 666*9c0476a2SJoe Komlodi } 667*9c0476a2SJoe Komlodi } 668*9c0476a2SJoe Komlodi 669*9c0476a2SJoe Komlodi static void dw_i3c_push_tx(DWI3C *s, uint32_t val) 670*9c0476a2SJoe Komlodi { 671*9c0476a2SJoe Komlodi if (fifo32_is_full(&s->tx_queue)) { 672*9c0476a2SJoe Komlodi qemu_log_mask(LOG_GUEST_ERROR, "%s: Tried to push to TX FIFO when " 673*9c0476a2SJoe Komlodi "full\n", object_get_canonical_path(OBJECT(s))); 674*9c0476a2SJoe Komlodi return; 675*9c0476a2SJoe Komlodi } 676*9c0476a2SJoe Komlodi 677*9c0476a2SJoe Komlodi trace_dw_i3c_push_tx(s->cfg.id, val); 678*9c0476a2SJoe Komlodi fifo32_push(&s->tx_queue, val); 679*9c0476a2SJoe Komlodi ARRAY_FIELD_DP32(s->regs, DATA_BUFFER_STATUS_LEVEL, TX_BUF_EMPTY_LOC, 680*9c0476a2SJoe Komlodi fifo32_num_free(&s->tx_queue)); 681*9c0476a2SJoe Komlodi 682*9c0476a2SJoe Komlodi /* Threshold is 2^TX_BUF_THLD. */ 683*9c0476a2SJoe Komlodi uint8_t empty_threshold = ARRAY_FIELD_EX32(s->regs, DATA_BUFFER_THLD_CTRL, 684*9c0476a2SJoe Komlodi TX_BUF_THLD); 685*9c0476a2SJoe Komlodi empty_threshold = 686*9c0476a2SJoe Komlodi dw_i3c_fifo_threshold_from_reg(empty_threshold); 687*9c0476a2SJoe Komlodi if (fifo32_num_free(&s->tx_queue) < empty_threshold) { 688*9c0476a2SJoe Komlodi ARRAY_FIELD_DP32(s->regs, INTR_STATUS, TX_THLD, 0); 689*9c0476a2SJoe Komlodi dw_i3c_update_irq(s); 690*9c0476a2SJoe Komlodi } 691*9c0476a2SJoe Komlodi } 692*9c0476a2SJoe Komlodi 693*9c0476a2SJoe Komlodi static uint32_t dw_i3c_pop_tx(DWI3C *s) 694*9c0476a2SJoe Komlodi { 695*9c0476a2SJoe Komlodi if (fifo32_is_empty(&s->tx_queue)) { 696*9c0476a2SJoe Komlodi g_autofree char *path = object_get_canonical_path(OBJECT(s)); 697*9c0476a2SJoe Komlodi qemu_log_mask(LOG_GUEST_ERROR, "%s: Tried to pop from TX FIFO when " 698*9c0476a2SJoe Komlodi "empty\n", path); 699*9c0476a2SJoe Komlodi return 0; 700*9c0476a2SJoe Komlodi } 701*9c0476a2SJoe Komlodi 702*9c0476a2SJoe Komlodi uint32_t val = fifo32_pop(&s->tx_queue); 703*9c0476a2SJoe Komlodi trace_dw_i3c_pop_tx(s->cfg.id, val); 704*9c0476a2SJoe Komlodi ARRAY_FIELD_DP32(s->regs, DATA_BUFFER_STATUS_LEVEL, TX_BUF_EMPTY_LOC, 705*9c0476a2SJoe Komlodi fifo32_num_free(&s->tx_queue)); 706*9c0476a2SJoe Komlodi 707*9c0476a2SJoe Komlodi /* Threshold is 2^TX_BUF_THLD. */ 708*9c0476a2SJoe Komlodi uint8_t empty_threshold = ARRAY_FIELD_EX32(s->regs, DATA_BUFFER_THLD_CTRL, 709*9c0476a2SJoe Komlodi TX_BUF_THLD); 710*9c0476a2SJoe Komlodi empty_threshold = 711*9c0476a2SJoe Komlodi dw_i3c_fifo_threshold_from_reg(empty_threshold); 712*9c0476a2SJoe Komlodi if (fifo32_num_free(&s->tx_queue) >= empty_threshold) { 713*9c0476a2SJoe Komlodi ARRAY_FIELD_DP32(s->regs, INTR_STATUS, TX_THLD, 1); 714*9c0476a2SJoe Komlodi dw_i3c_update_irq(s); 715*9c0476a2SJoe Komlodi } 716*9c0476a2SJoe Komlodi return val; 717*9c0476a2SJoe Komlodi } 718*9c0476a2SJoe Komlodi 719*9c0476a2SJoe Komlodi static void dw_i3c_push_rx(DWI3C *s, uint32_t val) 720*9c0476a2SJoe Komlodi { 721*9c0476a2SJoe Komlodi if (fifo32_is_full(&s->rx_queue)) { 722*9c0476a2SJoe Komlodi g_autofree char *path = object_get_canonical_path(OBJECT(s)); 723*9c0476a2SJoe Komlodi qemu_log_mask(LOG_GUEST_ERROR, "%s: Tried to push to RX FIFO when " 724*9c0476a2SJoe Komlodi "full\n", path); 725*9c0476a2SJoe Komlodi return; 726*9c0476a2SJoe Komlodi } 727*9c0476a2SJoe Komlodi trace_dw_i3c_push_rx(s->cfg.id, val); 728*9c0476a2SJoe Komlodi fifo32_push(&s->rx_queue, val); 729*9c0476a2SJoe Komlodi 730*9c0476a2SJoe Komlodi ARRAY_FIELD_DP32(s->regs, DATA_BUFFER_STATUS_LEVEL, RX_BUF_BLR, 731*9c0476a2SJoe Komlodi fifo32_num_used(&s->rx_queue)); 732*9c0476a2SJoe Komlodi /* Threshold is 2^RX_BUF_THLD. */ 733*9c0476a2SJoe Komlodi uint8_t threshold = ARRAY_FIELD_EX32(s->regs, DATA_BUFFER_THLD_CTRL, 734*9c0476a2SJoe Komlodi RX_BUF_THLD); 735*9c0476a2SJoe Komlodi threshold = dw_i3c_fifo_threshold_from_reg(threshold); 736*9c0476a2SJoe Komlodi if (fifo32_num_used(&s->rx_queue) >= threshold) { 737*9c0476a2SJoe Komlodi ARRAY_FIELD_DP32(s->regs, INTR_STATUS, RX_THLD, 1); 738*9c0476a2SJoe Komlodi dw_i3c_update_irq(s); 739*9c0476a2SJoe Komlodi } 740*9c0476a2SJoe Komlodi } 741*9c0476a2SJoe Komlodi 742*9c0476a2SJoe Komlodi static void dw_i3c_short_transfer(DWI3C *s, DWI3CTransferCmd cmd, 743*9c0476a2SJoe Komlodi DWI3CShortArg arg) 744*9c0476a2SJoe Komlodi { 745*9c0476a2SJoe Komlodi uint8_t err = DW_I3C_RESP_QUEUE_ERR_NONE; 746*9c0476a2SJoe Komlodi uint8_t addr = dw_i3c_target_addr(s, cmd.dev_index); 747*9c0476a2SJoe Komlodi bool is_i2c = dw_i3c_target_is_i2c(s, cmd.dev_index); 748*9c0476a2SJoe Komlodi uint8_t data[4]; /* Max we can send on a short transfer is 4 bytes. */ 749*9c0476a2SJoe Komlodi uint8_t len = 0; 750*9c0476a2SJoe Komlodi uint32_t bytes_sent; /* Ignored on short transfers. */ 751*9c0476a2SJoe Komlodi 752*9c0476a2SJoe Komlodi /* Can't do reads on a short transfer. */ 753*9c0476a2SJoe Komlodi if (cmd.rnw) { 754*9c0476a2SJoe Komlodi g_autofree char *path = object_get_canonical_path(OBJECT(s)); 755*9c0476a2SJoe Komlodi qemu_log_mask(LOG_GUEST_ERROR, "%s: Cannot do a read on a short " 756*9c0476a2SJoe Komlodi "transfer\n", path); 757*9c0476a2SJoe Komlodi return; 758*9c0476a2SJoe Komlodi } 759*9c0476a2SJoe Komlodi 760*9c0476a2SJoe Komlodi if (dw_i3c_send_start(s, addr, /*is_recv=*/false, is_i2c)) { 761*9c0476a2SJoe Komlodi err = DW_I3C_RESP_QUEUE_ERR_I2C_NACK; 762*9c0476a2SJoe Komlodi goto transfer_done; 763*9c0476a2SJoe Komlodi } 764*9c0476a2SJoe Komlodi 765*9c0476a2SJoe Komlodi /* Are we sending a command? */ 766*9c0476a2SJoe Komlodi if (cmd.cp) { 767*9c0476a2SJoe Komlodi data[len] = cmd.cmd; 768*9c0476a2SJoe Komlodi len++; 769*9c0476a2SJoe Komlodi /* 770*9c0476a2SJoe Komlodi * byte0 is the defining byte for a command, and is only sent if a 771*9c0476a2SJoe Komlodi * command is present and if the command has a defining byte present. 772*9c0476a2SJoe Komlodi * (byte_strb & 0x01) is always treated as set by the controller, and is 773*9c0476a2SJoe Komlodi * ignored. 774*9c0476a2SJoe Komlodi */ 775*9c0476a2SJoe Komlodi if (cmd.dbp) { 776*9c0476a2SJoe Komlodi data[len] += arg.byte0; 777*9c0476a2SJoe Komlodi len++; 778*9c0476a2SJoe Komlodi } 779*9c0476a2SJoe Komlodi } 780*9c0476a2SJoe Komlodi 781*9c0476a2SJoe Komlodi /* Send the bytes passed in the argument. */ 782*9c0476a2SJoe Komlodi if (arg.byte_strb & 0x02) { 783*9c0476a2SJoe Komlodi data[len] = arg.byte1; 784*9c0476a2SJoe Komlodi len++; 785*9c0476a2SJoe Komlodi } 786*9c0476a2SJoe Komlodi if (arg.byte_strb & 0x04) { 787*9c0476a2SJoe Komlodi data[len] = arg.byte2; 788*9c0476a2SJoe Komlodi len++; 789*9c0476a2SJoe Komlodi } 790*9c0476a2SJoe Komlodi 791*9c0476a2SJoe Komlodi if (dw_i3c_send(s, data, len, &bytes_sent, is_i2c)) { 792*9c0476a2SJoe Komlodi err = DW_I3C_RESP_QUEUE_ERR_I2C_NACK; 793*9c0476a2SJoe Komlodi } else { 794*9c0476a2SJoe Komlodi /* Only go to an idle state on a successful transfer. */ 795*9c0476a2SJoe Komlodi ARRAY_FIELD_DP32(s->regs, PRESENT_STATE, CM_TFR_ST_STATUS, 796*9c0476a2SJoe Komlodi DW_I3C_TRANSFER_STATE_IDLE); 797*9c0476a2SJoe Komlodi } 798*9c0476a2SJoe Komlodi 799*9c0476a2SJoe Komlodi transfer_done: 800*9c0476a2SJoe Komlodi if (cmd.toc) { 801*9c0476a2SJoe Komlodi dw_i3c_end_transfer(s, is_i2c); 802*9c0476a2SJoe Komlodi } 803*9c0476a2SJoe Komlodi if (cmd.roc) { 804*9c0476a2SJoe Komlodi /* 805*9c0476a2SJoe Komlodi * ccc_type is always 0 in controller mode, data_len is 0 in short 806*9c0476a2SJoe Komlodi * transfers. 807*9c0476a2SJoe Komlodi */ 808*9c0476a2SJoe Komlodi dw_i3c_resp_queue_push(s, err, cmd.tid, /*ccc_type=*/0, 809*9c0476a2SJoe Komlodi /*data_len=*/0); 810*9c0476a2SJoe Komlodi } 811*9c0476a2SJoe Komlodi } 812*9c0476a2SJoe Komlodi 813*9c0476a2SJoe Komlodi /* Returns number of bytes transmitted. */ 814*9c0476a2SJoe Komlodi static uint16_t dw_i3c_tx(DWI3C *s, uint16_t num, bool is_i2c) 815*9c0476a2SJoe Komlodi { 816*9c0476a2SJoe Komlodi uint16_t bytes_sent = 0; 817*9c0476a2SJoe Komlodi union { 818*9c0476a2SJoe Komlodi uint8_t b[sizeof(uint32_t)]; 819*9c0476a2SJoe Komlodi uint32_t val; 820*9c0476a2SJoe Komlodi } val32; 821*9c0476a2SJoe Komlodi 822*9c0476a2SJoe Komlodi while (bytes_sent < num) { 823*9c0476a2SJoe Komlodi val32.val = dw_i3c_pop_tx(s); 824*9c0476a2SJoe Komlodi for (uint8_t i = 0; i < sizeof(val32.val); i++) { 825*9c0476a2SJoe Komlodi if (dw_i3c_send_byte(s, val32.b[i], is_i2c)) { 826*9c0476a2SJoe Komlodi return bytes_sent; 827*9c0476a2SJoe Komlodi } 828*9c0476a2SJoe Komlodi bytes_sent++; 829*9c0476a2SJoe Komlodi 830*9c0476a2SJoe Komlodi /* We're not sending the full 32-bits, break early. */ 831*9c0476a2SJoe Komlodi if (bytes_sent >= num) { 832*9c0476a2SJoe Komlodi break; 833*9c0476a2SJoe Komlodi } 834*9c0476a2SJoe Komlodi } 835*9c0476a2SJoe Komlodi } 836*9c0476a2SJoe Komlodi 837*9c0476a2SJoe Komlodi return bytes_sent; 838*9c0476a2SJoe Komlodi } 839*9c0476a2SJoe Komlodi 840*9c0476a2SJoe Komlodi /* Returns number of bytes received. */ 841*9c0476a2SJoe Komlodi static uint16_t dw_i3c_rx(DWI3C *s, uint16_t num, bool is_i2c) 842*9c0476a2SJoe Komlodi { 843*9c0476a2SJoe Komlodi /* 844*9c0476a2SJoe Komlodi * Allocate a temporary buffer to read data from the target. 845*9c0476a2SJoe Komlodi * Zero it and word-align it as well in case we're reading unaligned data. 846*9c0476a2SJoe Komlodi */ 847*9c0476a2SJoe Komlodi g_autofree uint8_t *data = g_new0(uint8_t, num + (4 - (num & 0x03))); 848*9c0476a2SJoe Komlodi uint32_t *data32 = (uint32_t *)data; 849*9c0476a2SJoe Komlodi /* 850*9c0476a2SJoe Komlodi * 32-bits since the I3C API wants a 32-bit number, even though the 851*9c0476a2SJoe Komlodi * controller can only do 16-bit transfers. 852*9c0476a2SJoe Komlodi */ 853*9c0476a2SJoe Komlodi uint32_t num_read = 0; 854*9c0476a2SJoe Komlodi 855*9c0476a2SJoe Komlodi /* Can NACK if the target receives an unsupported CCC. */ 856*9c0476a2SJoe Komlodi if (dw_i3c_recv_data(s, is_i2c, data, num, &num_read)) { 857*9c0476a2SJoe Komlodi return 0; 858*9c0476a2SJoe Komlodi } 859*9c0476a2SJoe Komlodi 860*9c0476a2SJoe Komlodi for (uint16_t i = 0; i < num_read / 4; i++) { 861*9c0476a2SJoe Komlodi dw_i3c_push_rx(s, *data32); 862*9c0476a2SJoe Komlodi data32++; 863*9c0476a2SJoe Komlodi } 864*9c0476a2SJoe Komlodi /* 865*9c0476a2SJoe Komlodi * If we're pushing data that isn't 32-bit aligned, push what's left. 866*9c0476a2SJoe Komlodi * It's software's responsibility to know what bits are valid in the partial 867*9c0476a2SJoe Komlodi * data. 868*9c0476a2SJoe Komlodi */ 869*9c0476a2SJoe Komlodi if (num_read & 0x03) { 870*9c0476a2SJoe Komlodi dw_i3c_push_rx(s, *data32); 871*9c0476a2SJoe Komlodi } 872*9c0476a2SJoe Komlodi 873*9c0476a2SJoe Komlodi return num_read; 874*9c0476a2SJoe Komlodi } 875*9c0476a2SJoe Komlodi 876*9c0476a2SJoe Komlodi static int dw_i3c_transfer_ccc(DWI3C *s, DWI3CTransferCmd cmd, 877*9c0476a2SJoe Komlodi DWI3CTransferArg arg) 878*9c0476a2SJoe Komlodi { 879*9c0476a2SJoe Komlodi /* CCC start is always a write. CCCs cannot be done on I2C devices. */ 880*9c0476a2SJoe Komlodi if (dw_i3c_send_start(s, I3C_BROADCAST, /*is_recv=*/false, 881*9c0476a2SJoe Komlodi /*is_i2c=*/false)) { 882*9c0476a2SJoe Komlodi return DW_I3C_RESP_QUEUE_ERR_BROADCAST_NACK; 883*9c0476a2SJoe Komlodi } 884*9c0476a2SJoe Komlodi trace_dw_i3c_transfer_ccc(s->cfg.id, cmd.cmd); 885*9c0476a2SJoe Komlodi if (dw_i3c_send_byte(s, cmd.cmd, /*is_i2c=*/false)) { 886*9c0476a2SJoe Komlodi return DW_I3C_RESP_QUEUE_ERR_I2C_NACK; 887*9c0476a2SJoe Komlodi } 888*9c0476a2SJoe Komlodi 889*9c0476a2SJoe Komlodi /* On a direct CCC, we do a restart and then send the target's address. */ 890*9c0476a2SJoe Komlodi if (CCC_IS_DIRECT(cmd.cmd)) { 891*9c0476a2SJoe Komlodi bool is_recv = cmd.rnw; 892*9c0476a2SJoe Komlodi uint8_t addr = dw_i3c_target_addr(s, cmd.dev_index); 893*9c0476a2SJoe Komlodi if (dw_i3c_send_start(s, addr, is_recv, /*is_i2c=*/false)) { 894*9c0476a2SJoe Komlodi return DW_I3C_RESP_QUEUE_ERR_BROADCAST_NACK; 895*9c0476a2SJoe Komlodi } 896*9c0476a2SJoe Komlodi } 897*9c0476a2SJoe Komlodi 898*9c0476a2SJoe Komlodi return DW_I3C_RESP_QUEUE_ERR_NONE; 899*9c0476a2SJoe Komlodi } 900*9c0476a2SJoe Komlodi 901*9c0476a2SJoe Komlodi static void dw_i3c_transfer(DWI3C *s, DWI3CTransferCmd cmd, 902*9c0476a2SJoe Komlodi DWI3CTransferArg arg) 903*9c0476a2SJoe Komlodi { 904*9c0476a2SJoe Komlodi bool is_recv = cmd.rnw; 905*9c0476a2SJoe Komlodi uint8_t err = DW_I3C_RESP_QUEUE_ERR_NONE; 906*9c0476a2SJoe Komlodi uint8_t addr = dw_i3c_target_addr(s, cmd.dev_index); 907*9c0476a2SJoe Komlodi bool is_i2c = dw_i3c_target_is_i2c(s, cmd.dev_index); 908*9c0476a2SJoe Komlodi uint16_t bytes_transferred = 0; 909*9c0476a2SJoe Komlodi 910*9c0476a2SJoe Komlodi if (cmd.cp) { 911*9c0476a2SJoe Komlodi /* We're sending a CCC. */ 912*9c0476a2SJoe Komlodi err = dw_i3c_transfer_ccc(s, cmd, arg); 913*9c0476a2SJoe Komlodi if (err != DW_I3C_RESP_QUEUE_ERR_NONE) { 914*9c0476a2SJoe Komlodi goto transfer_done; 915*9c0476a2SJoe Komlodi } 916*9c0476a2SJoe Komlodi } else { 917*9c0476a2SJoe Komlodi if (ARRAY_FIELD_EX32(s->regs, DEVICE_CTRL, I3C_BROADCAST_ADDR_INC) && 918*9c0476a2SJoe Komlodi is_i2c == false) { 919*9c0476a2SJoe Komlodi if (dw_i3c_send_start(s, I3C_BROADCAST, 920*9c0476a2SJoe Komlodi /*is_recv=*/false, is_i2c)) { 921*9c0476a2SJoe Komlodi err = DW_I3C_RESP_QUEUE_ERR_I2C_NACK; 922*9c0476a2SJoe Komlodi goto transfer_done; 923*9c0476a2SJoe Komlodi } 924*9c0476a2SJoe Komlodi } 925*9c0476a2SJoe Komlodi /* Otherwise we're doing a private transfer. */ 926*9c0476a2SJoe Komlodi if (dw_i3c_send_start(s, addr, is_recv, is_i2c)) { 927*9c0476a2SJoe Komlodi err = DW_I3C_RESP_QUEUE_ERR_I2C_NACK; 928*9c0476a2SJoe Komlodi goto transfer_done; 929*9c0476a2SJoe Komlodi } 930*9c0476a2SJoe Komlodi } 931*9c0476a2SJoe Komlodi 932*9c0476a2SJoe Komlodi if (is_recv) { 933*9c0476a2SJoe Komlodi bytes_transferred = dw_i3c_rx(s, arg.data_len, is_i2c); 934*9c0476a2SJoe Komlodi } else { 935*9c0476a2SJoe Komlodi bytes_transferred = dw_i3c_tx(s, arg.data_len, is_i2c); 936*9c0476a2SJoe Komlodi } 937*9c0476a2SJoe Komlodi 938*9c0476a2SJoe Komlodi ARRAY_FIELD_DP32(s->regs, PRESENT_STATE, CM_TFR_ST_STATUS, 939*9c0476a2SJoe Komlodi DW_I3C_TRANSFER_STATE_IDLE); 940*9c0476a2SJoe Komlodi 941*9c0476a2SJoe Komlodi transfer_done: 942*9c0476a2SJoe Komlodi if (cmd.toc) { 943*9c0476a2SJoe Komlodi dw_i3c_end_transfer(s, is_i2c); 944*9c0476a2SJoe Komlodi } 945*9c0476a2SJoe Komlodi if (cmd.roc) { 946*9c0476a2SJoe Komlodi /* 947*9c0476a2SJoe Komlodi * data_len is the number of bytes that still need to be TX'd, or the 948*9c0476a2SJoe Komlodi * number of bytes RX'd. 949*9c0476a2SJoe Komlodi */ 950*9c0476a2SJoe Komlodi uint16_t data_len = is_recv ? bytes_transferred : arg.data_len - 951*9c0476a2SJoe Komlodi bytes_transferred; 952*9c0476a2SJoe Komlodi /* CCCT is always 0 in controller mode. */ 953*9c0476a2SJoe Komlodi dw_i3c_resp_queue_push(s, err, cmd.tid, /*ccc_type=*/0, 954*9c0476a2SJoe Komlodi data_len); 955*9c0476a2SJoe Komlodi } 956*9c0476a2SJoe Komlodi 957*9c0476a2SJoe Komlodi dw_i3c_update_irq(s); 958*9c0476a2SJoe Komlodi } 959*9c0476a2SJoe Komlodi 960*9c0476a2SJoe Komlodi static void dw_i3c_transfer_cmd(DWI3C *s, DWI3CTransferCmd cmd, 961*9c0476a2SJoe Komlodi DWI3CCmdQueueData arg) 962*9c0476a2SJoe Komlodi { 963*9c0476a2SJoe Komlodi uint8_t arg_attr = FIELD_EX32(arg.word, COMMAND_QUEUE_PORT, CMD_ATTR); 964*9c0476a2SJoe Komlodi 965*9c0476a2SJoe Komlodi ARRAY_FIELD_DP32(s->regs, PRESENT_STATE, CMD_TID, cmd.tid); 966*9c0476a2SJoe Komlodi 967*9c0476a2SJoe Komlodi /* User is trying to do HDR transfers, see if we can do them. */ 968*9c0476a2SJoe Komlodi if (cmd.speed == 0x06 && !dw_i3c_has_hdr_ddr(s)) { 969*9c0476a2SJoe Komlodi g_autofree char *path = object_get_canonical_path(OBJECT(s)); 970*9c0476a2SJoe Komlodi qemu_log_mask(LOG_GUEST_ERROR, "%s: HDR DDR is not supported\n", path); 971*9c0476a2SJoe Komlodi ARRAY_FIELD_DP32(s->regs, PRESENT_STATE, CM_TFR_ST_STATUS, 972*9c0476a2SJoe Komlodi DW_I3C_TRANSFER_STATE_HALT); 973*9c0476a2SJoe Komlodi return; 974*9c0476a2SJoe Komlodi } 975*9c0476a2SJoe Komlodi if (cmd.speed == 0x05 && !dw_i3c_has_hdr_ts(s)) { 976*9c0476a2SJoe Komlodi g_autofree char *path = object_get_canonical_path(OBJECT(s)); 977*9c0476a2SJoe Komlodi qemu_log_mask(LOG_GUEST_ERROR, "%s: HDR TS is not supported\n", path); 978*9c0476a2SJoe Komlodi ARRAY_FIELD_DP32(s->regs, PRESENT_STATE, CM_TFR_ST_STATUS, 979*9c0476a2SJoe Komlodi DW_I3C_TRANSFER_STATE_HALT); 980*9c0476a2SJoe Komlodi return; 981*9c0476a2SJoe Komlodi } 982*9c0476a2SJoe Komlodi 983*9c0476a2SJoe Komlodi if (arg_attr == DW_I3C_CMD_ATTR_TRANSFER_ARG) { 984*9c0476a2SJoe Komlodi dw_i3c_transfer(s, cmd, arg.transfer_arg); 985*9c0476a2SJoe Komlodi } else if (arg_attr == DW_I3C_CMD_ATTR_SHORT_DATA_ARG) { 986*9c0476a2SJoe Komlodi dw_i3c_short_transfer(s, cmd, arg.short_arg); 987*9c0476a2SJoe Komlodi } else { 988*9c0476a2SJoe Komlodi g_autofree char *path = object_get_canonical_path(OBJECT(s)); 989*9c0476a2SJoe Komlodi qemu_log_mask(LOG_GUEST_ERROR, "%s: Unknown command queue cmd_attr 0x%x" 990*9c0476a2SJoe Komlodi "\n", path, arg_attr); 991*9c0476a2SJoe Komlodi ARRAY_FIELD_DP32(s->regs, PRESENT_STATE, CM_TFR_ST_STATUS, 992*9c0476a2SJoe Komlodi DW_I3C_TRANSFER_STATE_HALT); 993*9c0476a2SJoe Komlodi } 994*9c0476a2SJoe Komlodi } 995*9c0476a2SJoe Komlodi 996*9c0476a2SJoe Komlodi static void dw_i3c_update_char_table(DWI3C *s, uint8_t offset, uint64_t pid, 997*9c0476a2SJoe Komlodi uint8_t bcr, uint8_t dcr, uint8_t addr) 998*9c0476a2SJoe Komlodi { 999*9c0476a2SJoe Komlodi if (offset > s->cfg.num_addressable_devices) { 1000*9c0476a2SJoe Komlodi g_autofree char *path = object_get_canonical_path(OBJECT(s)); 1001*9c0476a2SJoe Komlodi qemu_log_mask(LOG_GUEST_ERROR, "%s: Device char table offset %d out of " 1002*9c0476a2SJoe Komlodi "bounds\n", path, offset); 1003*9c0476a2SJoe Komlodi /* If we're out of bounds, do nothing. */ 1004*9c0476a2SJoe Komlodi return; 1005*9c0476a2SJoe Komlodi } 1006*9c0476a2SJoe Komlodi 1007*9c0476a2SJoe Komlodi /* 1008*9c0476a2SJoe Komlodi * Each device offset is 128 bits apart in the table, since each device gets 1009*9c0476a2SJoe Komlodi * 4 * 32-bits of entries in the table. 1010*9c0476a2SJoe Komlodi * / sizeof(uint32_t) because we're indexing into our 32-bit reg array. 1011*9c0476a2SJoe Komlodi */ 1012*9c0476a2SJoe Komlodi uint16_t dev_index = (ARRAY_FIELD_EX32(s->regs, DEV_CHAR_TABLE_POINTER, 1013*9c0476a2SJoe Komlodi P_DEV_CHAR_TABLE_START_ADDR) / 1014*9c0476a2SJoe Komlodi sizeof(uint32_t)) + 1015*9c0476a2SJoe Komlodi (offset * sizeof(uint32_t)); 1016*9c0476a2SJoe Komlodi s->regs[dev_index] = pid & 0xffffffff; 1017*9c0476a2SJoe Komlodi pid >>= 32; 1018*9c0476a2SJoe Komlodi s->regs[dev_index + 1] = FIELD_DP32(s->regs[dev_index + 1], 1019*9c0476a2SJoe Komlodi DEVICE_CHARACTERISTIC_TABLE_LOC2, 1020*9c0476a2SJoe Komlodi MSB_PID, pid); 1021*9c0476a2SJoe Komlodi s->regs[dev_index + 2] = FIELD_DP32(s->regs[dev_index + 2], 1022*9c0476a2SJoe Komlodi DEVICE_CHARACTERISTIC_TABLE_LOC3, DCR, 1023*9c0476a2SJoe Komlodi dcr); 1024*9c0476a2SJoe Komlodi s->regs[dev_index + 2] = FIELD_DP32(s->regs[dev_index + 2], 1025*9c0476a2SJoe Komlodi DEVICE_CHARACTERISTIC_TABLE_LOC3, BCR, 1026*9c0476a2SJoe Komlodi bcr); 1027*9c0476a2SJoe Komlodi s->regs[dev_index + 3] = FIELD_DP32(s->regs[dev_index + 3], 1028*9c0476a2SJoe Komlodi DEVICE_CHARACTERISTIC_TABLE_LOC4, 1029*9c0476a2SJoe Komlodi DEV_DYNAMIC_ADDR, addr); 1030*9c0476a2SJoe Komlodi 1031*9c0476a2SJoe Komlodi /* Increment PRESENT_DEV_CHAR_TABLE_INDEX. */ 1032*9c0476a2SJoe Komlodi uint8_t idx = ARRAY_FIELD_EX32(s->regs, DEV_CHAR_TABLE_POINTER, 1033*9c0476a2SJoe Komlodi PRESENT_DEV_CHAR_TABLE_INDEX); 1034*9c0476a2SJoe Komlodi /* Increment and rollover. */ 1035*9c0476a2SJoe Komlodi idx++; 1036*9c0476a2SJoe Komlodi if (idx >= ARRAY_FIELD_EX32(s->regs, DEV_CHAR_TABLE_POINTER, 1037*9c0476a2SJoe Komlodi DEV_CHAR_TABLE_DEPTH) / 4) { 1038*9c0476a2SJoe Komlodi idx = 0; 1039*9c0476a2SJoe Komlodi } 1040*9c0476a2SJoe Komlodi ARRAY_FIELD_DP32(s->regs, DEV_CHAR_TABLE_POINTER, 1041*9c0476a2SJoe Komlodi PRESENT_DEV_CHAR_TABLE_INDEX, idx); 1042*9c0476a2SJoe Komlodi } 1043*9c0476a2SJoe Komlodi 1044*9c0476a2SJoe Komlodi static void dw_i3c_addr_assign_cmd(DWI3C *s, DWI3CAddrAssignCmd cmd) 1045*9c0476a2SJoe Komlodi { 1046*9c0476a2SJoe Komlodi uint8_t i = 0; 1047*9c0476a2SJoe Komlodi uint8_t err = DW_I3C_RESP_QUEUE_ERR_NONE; 1048*9c0476a2SJoe Komlodi 1049*9c0476a2SJoe Komlodi /* Tell everyone to ENTDAA. If these error, no one is on the bus. */ 1050*9c0476a2SJoe Komlodi if (dw_i3c_send_start(s, I3C_BROADCAST, /*is_recv=*/false, 1051*9c0476a2SJoe Komlodi /*is_i2c=*/false)) { 1052*9c0476a2SJoe Komlodi err = DW_I3C_RESP_QUEUE_ERR_BROADCAST_NACK; 1053*9c0476a2SJoe Komlodi goto transfer_done; 1054*9c0476a2SJoe Komlodi } 1055*9c0476a2SJoe Komlodi if (dw_i3c_send_byte(s, cmd.cmd, /*is_i2c=*/false)) { 1056*9c0476a2SJoe Komlodi err = DW_I3C_RESP_QUEUE_ERR_BROADCAST_NACK; 1057*9c0476a2SJoe Komlodi goto transfer_done; 1058*9c0476a2SJoe Komlodi } 1059*9c0476a2SJoe Komlodi 1060*9c0476a2SJoe Komlodi /* Go through each device in the table and assign it an address. */ 1061*9c0476a2SJoe Komlodi for (i = 0; i < cmd.dev_count; i++) { 1062*9c0476a2SJoe Komlodi uint8_t addr = dw_i3c_target_addr(s, cmd.dev_index + i); 1063*9c0476a2SJoe Komlodi union { 1064*9c0476a2SJoe Komlodi uint64_t pid:48; 1065*9c0476a2SJoe Komlodi uint8_t bcr; 1066*9c0476a2SJoe Komlodi uint8_t dcr; 1067*9c0476a2SJoe Komlodi uint32_t w[2]; 1068*9c0476a2SJoe Komlodi uint8_t b[8]; 1069*9c0476a2SJoe Komlodi } target_info; 1070*9c0476a2SJoe Komlodi 1071*9c0476a2SJoe Komlodi /* If this fails, there was no one left to ENTDAA. */ 1072*9c0476a2SJoe Komlodi if (dw_i3c_send_start(s, I3C_BROADCAST, /*is_recv=*/false, 1073*9c0476a2SJoe Komlodi /*is_i2c=*/false)) { 1074*9c0476a2SJoe Komlodi err = DW_I3C_RESP_QUEUE_ERR_BROADCAST_NACK; 1075*9c0476a2SJoe Komlodi break; 1076*9c0476a2SJoe Komlodi } 1077*9c0476a2SJoe Komlodi 1078*9c0476a2SJoe Komlodi /* 1079*9c0476a2SJoe Komlodi * In ENTDAA, we read 8 bytes from the target, which will be the 1080*9c0476a2SJoe Komlodi * target's PID, BCR, and DCR. After that, we send it the dynamic 1081*9c0476a2SJoe Komlodi * address. 1082*9c0476a2SJoe Komlodi * Don't bother checking the number of bytes received, it must send 8 1083*9c0476a2SJoe Komlodi * bytes during ENTDAA. 1084*9c0476a2SJoe Komlodi */ 1085*9c0476a2SJoe Komlodi uint32_t num_read; 1086*9c0476a2SJoe Komlodi if (dw_i3c_recv_data(s, /*is_i2c=*/false, target_info.b, 1087*9c0476a2SJoe Komlodi I3C_ENTDAA_SIZE, &num_read)) { 1088*9c0476a2SJoe Komlodi g_autofree char *path = object_get_canonical_path(OBJECT(s)); 1089*9c0476a2SJoe Komlodi qemu_log_mask(LOG_GUEST_ERROR, "%s: Target NACKed ENTDAA CCC\n", 1090*9c0476a2SJoe Komlodi path); 1091*9c0476a2SJoe Komlodi err = DW_I3C_RESP_QUEUE_ERR_DAA_NACK; 1092*9c0476a2SJoe Komlodi goto transfer_done; 1093*9c0476a2SJoe Komlodi } 1094*9c0476a2SJoe Komlodi if (dw_i3c_send_byte(s, addr, /*is_i2c=*/false)) { 1095*9c0476a2SJoe Komlodi g_autofree char *path = object_get_canonical_path(OBJECT(s)); 1096*9c0476a2SJoe Komlodi qemu_log_mask(LOG_GUEST_ERROR, "%s: Target NACKed addr 0x%.2x " 1097*9c0476a2SJoe Komlodi "during ENTDAA\n", path, addr); 1098*9c0476a2SJoe Komlodi err = DW_I3C_RESP_QUEUE_ERR_DAA_NACK; 1099*9c0476a2SJoe Komlodi break; 1100*9c0476a2SJoe Komlodi } 1101*9c0476a2SJoe Komlodi dw_i3c_update_char_table(s, cmd.dev_index + i, 1102*9c0476a2SJoe Komlodi target_info.pid, target_info.bcr, 1103*9c0476a2SJoe Komlodi target_info.dcr, addr); 1104*9c0476a2SJoe Komlodi 1105*9c0476a2SJoe Komlodi /* Push the PID, BCR, and DCR to the RX queue. */ 1106*9c0476a2SJoe Komlodi dw_i3c_push_rx(s, target_info.w[0]); 1107*9c0476a2SJoe Komlodi dw_i3c_push_rx(s, target_info.w[1]); 1108*9c0476a2SJoe Komlodi } 1109*9c0476a2SJoe Komlodi 1110*9c0476a2SJoe Komlodi transfer_done: 1111*9c0476a2SJoe Komlodi /* Do we send a STOP? */ 1112*9c0476a2SJoe Komlodi if (cmd.toc) { 1113*9c0476a2SJoe Komlodi dw_i3c_end_transfer(s, /*is_i2c=*/false); 1114*9c0476a2SJoe Komlodi } 1115*9c0476a2SJoe Komlodi /* 1116*9c0476a2SJoe Komlodi * For addr assign commands, the length field is the number of devices 1117*9c0476a2SJoe Komlodi * left to assign. CCCT is always 0 in controller mode. 1118*9c0476a2SJoe Komlodi */ 1119*9c0476a2SJoe Komlodi if (cmd.roc) { 1120*9c0476a2SJoe Komlodi dw_i3c_resp_queue_push(s, err, cmd.tid, /*ccc_type=*/0, 1121*9c0476a2SJoe Komlodi cmd.dev_count - i); 1122*9c0476a2SJoe Komlodi } 1123*9c0476a2SJoe Komlodi } 1124*9c0476a2SJoe Komlodi 1125*9c0476a2SJoe Komlodi static uint32_t dw_i3c_cmd_queue_pop(DWI3C *s) 1126*9c0476a2SJoe Komlodi { 1127*9c0476a2SJoe Komlodi if (fifo32_is_empty(&s->cmd_queue)) { 1128*9c0476a2SJoe Komlodi g_autofree char *path = object_get_canonical_path(OBJECT(s)); 1129*9c0476a2SJoe Komlodi qemu_log_mask(LOG_GUEST_ERROR, "%s: Tried to dequeue command queue " 1130*9c0476a2SJoe Komlodi "when it was empty\n", path); 1131*9c0476a2SJoe Komlodi return 0; 1132*9c0476a2SJoe Komlodi } 1133*9c0476a2SJoe Komlodi uint32_t val = fifo32_pop(&s->cmd_queue); 1134*9c0476a2SJoe Komlodi 1135*9c0476a2SJoe Komlodi uint8_t empty_threshold = ARRAY_FIELD_EX32(s->regs, QUEUE_THLD_CTRL, 1136*9c0476a2SJoe Komlodi CMD_BUF_EMPTY_THLD); 1137*9c0476a2SJoe Komlodi uint8_t cmd_queue_empty_loc = ARRAY_FIELD_EX32(s->regs, 1138*9c0476a2SJoe Komlodi QUEUE_STATUS_LEVEL, 1139*9c0476a2SJoe Komlodi CMD_QUEUE_EMPTY_LOC); 1140*9c0476a2SJoe Komlodi cmd_queue_empty_loc++; 1141*9c0476a2SJoe Komlodi ARRAY_FIELD_DP32(s->regs, QUEUE_STATUS_LEVEL, CMD_QUEUE_EMPTY_LOC, 1142*9c0476a2SJoe Komlodi cmd_queue_empty_loc); 1143*9c0476a2SJoe Komlodi if (cmd_queue_empty_loc >= empty_threshold) { 1144*9c0476a2SJoe Komlodi ARRAY_FIELD_DP32(s->regs, INTR_STATUS, CMD_QUEUE_RDY, 1); 1145*9c0476a2SJoe Komlodi dw_i3c_update_irq(s); 1146*9c0476a2SJoe Komlodi } 1147*9c0476a2SJoe Komlodi 1148*9c0476a2SJoe Komlodi return val; 1149*9c0476a2SJoe Komlodi } 1150*9c0476a2SJoe Komlodi 1151*9c0476a2SJoe Komlodi static void dw_i3c_cmd_queue_execute(DWI3C *s) 1152*9c0476a2SJoe Komlodi { 1153*9c0476a2SJoe Komlodi ARRAY_FIELD_DP32(s->regs, PRESENT_STATE, CM_TFR_ST_STATUS, 1154*9c0476a2SJoe Komlodi DW_I3C_TRANSFER_STATE_IDLE); 1155*9c0476a2SJoe Komlodi if (!dw_i3c_can_transmit(s)) { 1156*9c0476a2SJoe Komlodi return; 1157*9c0476a2SJoe Komlodi } 1158*9c0476a2SJoe Komlodi 1159*9c0476a2SJoe Komlodi /* 1160*9c0476a2SJoe Komlodi * We only start executing when a command is passed into the FIFO. 1161*9c0476a2SJoe Komlodi * We expect there to be a multiple of 2 items in the queue. The first item 1162*9c0476a2SJoe Komlodi * should be an argument to a command, and the command should be the second 1163*9c0476a2SJoe Komlodi * item. 1164*9c0476a2SJoe Komlodi */ 1165*9c0476a2SJoe Komlodi if (fifo32_num_used(&s->cmd_queue) & 1) { 1166*9c0476a2SJoe Komlodi return; 1167*9c0476a2SJoe Komlodi } 1168*9c0476a2SJoe Komlodi 1169*9c0476a2SJoe Komlodi while (!fifo32_is_empty(&s->cmd_queue)) { 1170*9c0476a2SJoe Komlodi DWI3CCmdQueueData arg; 1171*9c0476a2SJoe Komlodi arg.word = dw_i3c_cmd_queue_pop(s); 1172*9c0476a2SJoe Komlodi DWI3CCmdQueueData cmd; 1173*9c0476a2SJoe Komlodi cmd.word = dw_i3c_cmd_queue_pop(s); 1174*9c0476a2SJoe Komlodi trace_dw_i3c_cmd_queue_execute(s->cfg.id, cmd.word, arg.word); 1175*9c0476a2SJoe Komlodi 1176*9c0476a2SJoe Komlodi uint8_t cmd_attr = FIELD_EX32(cmd.word, COMMAND_QUEUE_PORT, CMD_ATTR); 1177*9c0476a2SJoe Komlodi switch (cmd_attr) { 1178*9c0476a2SJoe Komlodi case DW_I3C_CMD_ATTR_TRANSFER_CMD: 1179*9c0476a2SJoe Komlodi dw_i3c_transfer_cmd(s, cmd.transfer_cmd, arg); 1180*9c0476a2SJoe Komlodi break; 1181*9c0476a2SJoe Komlodi case DW_I3C_CMD_ATTR_ADDR_ASSIGN_CMD: 1182*9c0476a2SJoe Komlodi /* Arg is discarded for addr assign commands. */ 1183*9c0476a2SJoe Komlodi dw_i3c_addr_assign_cmd(s, cmd.addr_assign_cmd); 1184*9c0476a2SJoe Komlodi break; 1185*9c0476a2SJoe Komlodi case DW_I3C_CMD_ATTR_TRANSFER_ARG: 1186*9c0476a2SJoe Komlodi case DW_I3C_CMD_ATTR_SHORT_DATA_ARG: 1187*9c0476a2SJoe Komlodi { 1188*9c0476a2SJoe Komlodi g_autofree char *path = object_get_canonical_path(OBJECT(s)); 1189*9c0476a2SJoe Komlodi qemu_log_mask(LOG_GUEST_ERROR, "%s: Command queue received " 1190*9c0476a2SJoe Komlodi "argument packet when it expected a command " 1191*9c0476a2SJoe Komlodi "packet\n", path); 1192*9c0476a2SJoe Komlodi } 1193*9c0476a2SJoe Komlodi break; 1194*9c0476a2SJoe Komlodi default: 1195*9c0476a2SJoe Komlodi /* 1196*9c0476a2SJoe Komlodi * The caller's check before queueing an item should prevent this 1197*9c0476a2SJoe Komlodi * from happening. 1198*9c0476a2SJoe Komlodi */ 1199*9c0476a2SJoe Komlodi g_assert_not_reached(); 1200*9c0476a2SJoe Komlodi break; 1201*9c0476a2SJoe Komlodi } 1202*9c0476a2SJoe Komlodi } 1203*9c0476a2SJoe Komlodi } 1204*9c0476a2SJoe Komlodi 1205*9c0476a2SJoe Komlodi static void dw_i3c_cmd_queue_push(DWI3C *s, uint32_t val) 1206*9c0476a2SJoe Komlodi { 1207*9c0476a2SJoe Komlodi if (fifo32_is_full(&s->cmd_queue)) { 1208*9c0476a2SJoe Komlodi g_autofree char *path = object_get_canonical_path(OBJECT(s)); 1209*9c0476a2SJoe Komlodi qemu_log_mask(LOG_GUEST_ERROR, "%s: Command queue received packet when " 1210*9c0476a2SJoe Komlodi "already full\n", path); 1211*9c0476a2SJoe Komlodi return; 1212*9c0476a2SJoe Komlodi } 1213*9c0476a2SJoe Komlodi trace_dw_i3c_cmd_queue_push(s->cfg.id, val); 1214*9c0476a2SJoe Komlodi fifo32_push(&s->cmd_queue, val); 1215*9c0476a2SJoe Komlodi 1216*9c0476a2SJoe Komlodi uint8_t empty_threshold = ARRAY_FIELD_EX32(s->regs, QUEUE_THLD_CTRL, 1217*9c0476a2SJoe Komlodi CMD_BUF_EMPTY_THLD); 1218*9c0476a2SJoe Komlodi uint8_t cmd_queue_empty_loc = ARRAY_FIELD_EX32(s->regs, 1219*9c0476a2SJoe Komlodi QUEUE_STATUS_LEVEL, 1220*9c0476a2SJoe Komlodi CMD_QUEUE_EMPTY_LOC); 1221*9c0476a2SJoe Komlodi if (cmd_queue_empty_loc) { 1222*9c0476a2SJoe Komlodi cmd_queue_empty_loc--; 1223*9c0476a2SJoe Komlodi ARRAY_FIELD_DP32(s->regs, QUEUE_STATUS_LEVEL, CMD_QUEUE_EMPTY_LOC, 1224*9c0476a2SJoe Komlodi cmd_queue_empty_loc); 1225*9c0476a2SJoe Komlodi } 1226*9c0476a2SJoe Komlodi if (cmd_queue_empty_loc < empty_threshold) { 1227*9c0476a2SJoe Komlodi ARRAY_FIELD_DP32(s->regs, INTR_STATUS, CMD_QUEUE_RDY, 0); 1228*9c0476a2SJoe Komlodi dw_i3c_update_irq(s); 1229*9c0476a2SJoe Komlodi } 1230*9c0476a2SJoe Komlodi } 1231*9c0476a2SJoe Komlodi 1232*9c0476a2SJoe Komlodi static void dw_i3c_cmd_queue_port_w(DWI3C *s, uint32_t val) 1233*9c0476a2SJoe Komlodi { 1234*9c0476a2SJoe Komlodi uint8_t cmd_attr = FIELD_EX32(val, COMMAND_QUEUE_PORT, CMD_ATTR); 1235*9c0476a2SJoe Komlodi 1236*9c0476a2SJoe Komlodi switch (cmd_attr) { 1237*9c0476a2SJoe Komlodi /* If a command is received we can start executing it. */ 1238*9c0476a2SJoe Komlodi case DW_I3C_CMD_ATTR_TRANSFER_CMD: 1239*9c0476a2SJoe Komlodi case DW_I3C_CMD_ATTR_ADDR_ASSIGN_CMD: 1240*9c0476a2SJoe Komlodi dw_i3c_cmd_queue_push(s, val); 1241*9c0476a2SJoe Komlodi dw_i3c_cmd_queue_execute(s); 1242*9c0476a2SJoe Komlodi break; 1243*9c0476a2SJoe Komlodi /* If we get an argument just push it. */ 1244*9c0476a2SJoe Komlodi case DW_I3C_CMD_ATTR_TRANSFER_ARG: 1245*9c0476a2SJoe Komlodi case DW_I3C_CMD_ATTR_SHORT_DATA_ARG: 1246*9c0476a2SJoe Komlodi dw_i3c_cmd_queue_push(s, val); 1247*9c0476a2SJoe Komlodi break; 1248*9c0476a2SJoe Komlodi default: 1249*9c0476a2SJoe Komlodi { 1250*9c0476a2SJoe Komlodi g_autofree char *path = object_get_canonical_path(OBJECT(s)); 1251*9c0476a2SJoe Komlodi qemu_log_mask(LOG_GUEST_ERROR, "%s: Command queue received packet " 1252*9c0476a2SJoe Komlodi "with unknown cmd attr 0x%x\n", path, cmd_attr); 1253*9c0476a2SJoe Komlodi } 1254*9c0476a2SJoe Komlodi break; 1255*9c0476a2SJoe Komlodi } 1256*9c0476a2SJoe Komlodi } 1257*9c0476a2SJoe Komlodi 1258c52aaabdSJoe Komlodi static void dw_i3c_write(void *opaque, hwaddr offset, uint64_t value, 1259c52aaabdSJoe Komlodi unsigned size) 1260c52aaabdSJoe Komlodi { 1261c52aaabdSJoe Komlodi DWI3C *s = DW_I3C(opaque); 1262c52aaabdSJoe Komlodi uint32_t addr = offset >> 2; 12637e5e02dbSJoe Komlodi uint32_t val32 = (uint32_t)value; 1264c52aaabdSJoe Komlodi 1265*9c0476a2SJoe Komlodi trace_dw_i3c_write(s->cfg.id, offset, value); 1266c52aaabdSJoe Komlodi 12677e5e02dbSJoe Komlodi val32 &= ~dw_i3c_ro[addr]; 1268c52aaabdSJoe Komlodi switch (addr) { 1269c52aaabdSJoe Komlodi case R_HW_CAPABILITY: 1270c52aaabdSJoe Komlodi case R_RESPONSE_QUEUE_PORT: 1271c52aaabdSJoe Komlodi case R_IBI_QUEUE_DATA: 1272c52aaabdSJoe Komlodi case R_QUEUE_STATUS_LEVEL: 1273c52aaabdSJoe Komlodi case R_PRESENT_STATE: 1274c52aaabdSJoe Komlodi case R_CCC_DEVICE_STATUS: 1275c52aaabdSJoe Komlodi case R_DEVICE_ADDR_TABLE_POINTER: 1276c52aaabdSJoe Komlodi case R_VENDOR_SPECIFIC_REG_POINTER: 1277c52aaabdSJoe Komlodi case R_SLV_CHAR_CTRL: 1278c52aaabdSJoe Komlodi case R_SLV_MAX_LEN: 1279c52aaabdSJoe Komlodi case R_MAX_READ_TURNAROUND: 1280c52aaabdSJoe Komlodi case R_I3C_VER_ID: 1281c52aaabdSJoe Komlodi case R_I3C_VER_TYPE: 1282c52aaabdSJoe Komlodi case R_EXTENDED_CAPABILITY: 1283c52aaabdSJoe Komlodi qemu_log_mask(LOG_GUEST_ERROR, 1284c52aaabdSJoe Komlodi "%s: write to readonly register[0x%02" HWADDR_PRIx 1285c52aaabdSJoe Komlodi "] = 0x%08" PRIx64 "\n", 1286c52aaabdSJoe Komlodi __func__, offset, value); 1287c52aaabdSJoe Komlodi break; 1288c52aaabdSJoe Komlodi case R_RX_TX_DATA_PORT: 1289*9c0476a2SJoe Komlodi dw_i3c_push_tx(s, val32); 1290*9c0476a2SJoe Komlodi break; 1291*9c0476a2SJoe Komlodi case R_COMMAND_QUEUE_PORT: 1292*9c0476a2SJoe Komlodi dw_i3c_cmd_queue_port_w(s, val32); 1293c52aaabdSJoe Komlodi break; 1294c52aaabdSJoe Komlodi case R_RESET_CTRL: 1295c52aaabdSJoe Komlodi break; 1296a825bbb7SJoe Komlodi case R_INTR_STATUS: 1297a825bbb7SJoe Komlodi dw_i3c_intr_status_w(s, val32); 1298a825bbb7SJoe Komlodi break; 1299a825bbb7SJoe Komlodi case R_INTR_STATUS_EN: 1300a825bbb7SJoe Komlodi dw_i3c_intr_status_en_w(s, val32); 1301a825bbb7SJoe Komlodi break; 1302a825bbb7SJoe Komlodi case R_INTR_SIGNAL_EN: 1303a825bbb7SJoe Komlodi dw_i3c_intr_signal_en_w(s, val32); 1304a825bbb7SJoe Komlodi break; 1305a825bbb7SJoe Komlodi case R_INTR_FORCE: 1306a825bbb7SJoe Komlodi dw_i3c_intr_force_w(s, val32); 1307a825bbb7SJoe Komlodi break; 1308c52aaabdSJoe Komlodi default: 13097e5e02dbSJoe Komlodi s->regs[addr] = val32; 1310c52aaabdSJoe Komlodi break; 1311c52aaabdSJoe Komlodi } 1312c52aaabdSJoe Komlodi } 1313c52aaabdSJoe Komlodi 1314c52aaabdSJoe Komlodi const VMStateDescription vmstate_dw_i3c = { 1315c52aaabdSJoe Komlodi .name = TYPE_DW_I3C, 1316c52aaabdSJoe Komlodi .version_id = 1, 1317c52aaabdSJoe Komlodi .minimum_version_id = 1, 1318c52aaabdSJoe Komlodi .fields = (VMStateField[]){ 1319c52aaabdSJoe Komlodi VMSTATE_UINT32_ARRAY(regs, DWI3C, DW_I3C_NR_REGS), 1320c52aaabdSJoe Komlodi VMSTATE_END_OF_LIST(), 1321c52aaabdSJoe Komlodi } 1322c52aaabdSJoe Komlodi }; 1323c52aaabdSJoe Komlodi 1324c52aaabdSJoe Komlodi static const MemoryRegionOps dw_i3c_ops = { 1325c52aaabdSJoe Komlodi .read = dw_i3c_read, 1326c52aaabdSJoe Komlodi .write = dw_i3c_write, 1327c52aaabdSJoe Komlodi .endianness = DEVICE_LITTLE_ENDIAN, 1328c52aaabdSJoe Komlodi }; 1329c52aaabdSJoe Komlodi 1330c52aaabdSJoe Komlodi static void dw_i3c_reset_enter(Object *obj, ResetType type) 1331c52aaabdSJoe Komlodi { 1332c52aaabdSJoe Komlodi DWI3C *s = DW_I3C(obj); 1333c52aaabdSJoe Komlodi 1334c52aaabdSJoe Komlodi memcpy(s->regs, dw_i3c_resets, sizeof(s->regs)); 1335*9c0476a2SJoe Komlodi /* 1336*9c0476a2SJoe Komlodi * The user config for these may differ from our resets array, set them 1337*9c0476a2SJoe Komlodi * manually. 1338*9c0476a2SJoe Komlodi */ 1339*9c0476a2SJoe Komlodi ARRAY_FIELD_DP32(s->regs, DEVICE_ADDR_TABLE_POINTER, ADDR, 1340*9c0476a2SJoe Komlodi s->cfg.dev_addr_table_pointer); 1341*9c0476a2SJoe Komlodi ARRAY_FIELD_DP32(s->regs, DEVICE_ADDR_TABLE_POINTER, DEPTH, 1342*9c0476a2SJoe Komlodi s->cfg.dev_addr_table_depth); 1343*9c0476a2SJoe Komlodi ARRAY_FIELD_DP32(s->regs, DEV_CHAR_TABLE_POINTER, 1344*9c0476a2SJoe Komlodi P_DEV_CHAR_TABLE_START_ADDR, 1345*9c0476a2SJoe Komlodi s->cfg.dev_char_table_pointer); 1346*9c0476a2SJoe Komlodi ARRAY_FIELD_DP32(s->regs, DEV_CHAR_TABLE_POINTER, DEV_CHAR_TABLE_DEPTH, 1347*9c0476a2SJoe Komlodi s->cfg.dev_char_table_depth); 1348c52aaabdSJoe Komlodi } 1349c52aaabdSJoe Komlodi 1350c52aaabdSJoe Komlodi static void dw_i3c_realize(DeviceState *dev, Error **errp) 1351c52aaabdSJoe Komlodi { 1352c52aaabdSJoe Komlodi DWI3C *s = DW_I3C(dev); 1353*9c0476a2SJoe Komlodi g_autofree char *name = g_strdup_printf(TYPE_DW_I3C ".%d", s->cfg.id); 1354c52aaabdSJoe Komlodi 1355c52aaabdSJoe Komlodi sysbus_init_irq(SYS_BUS_DEVICE(dev), &s->irq); 1356c52aaabdSJoe Komlodi 1357c52aaabdSJoe Komlodi memory_region_init_io(&s->mr, OBJECT(s), &dw_i3c_ops, s, name, 1358c52aaabdSJoe Komlodi DW_I3C_NR_REGS << 2); 1359c52aaabdSJoe Komlodi sysbus_init_mmio(SYS_BUS_DEVICE(dev), &s->mr); 1360*9c0476a2SJoe Komlodi 1361*9c0476a2SJoe Komlodi fifo32_create(&s->cmd_queue, s->cfg.cmd_resp_queue_capacity_bytes); 1362*9c0476a2SJoe Komlodi fifo32_create(&s->resp_queue, s->cfg.cmd_resp_queue_capacity_bytes); 1363*9c0476a2SJoe Komlodi fifo32_create(&s->tx_queue, s->cfg.tx_rx_queue_capacity_bytes); 1364*9c0476a2SJoe Komlodi fifo32_create(&s->rx_queue, s->cfg.tx_rx_queue_capacity_bytes); 1365*9c0476a2SJoe Komlodi 1366*9c0476a2SJoe Komlodi s->bus = i3c_init_bus(DEVICE(s), name); 1367c52aaabdSJoe Komlodi } 1368c52aaabdSJoe Komlodi 1369c52aaabdSJoe Komlodi static const Property dw_i3c_properties[] = { 1370*9c0476a2SJoe Komlodi DEFINE_PROP_UINT8("device-id", DWI3C, cfg.id, 0), 1371*9c0476a2SJoe Komlodi DEFINE_PROP_UINT8("command-response-queue-capacity-bytes", DWI3C, 1372*9c0476a2SJoe Komlodi cfg.cmd_resp_queue_capacity_bytes, 0x10), 1373*9c0476a2SJoe Komlodi DEFINE_PROP_UINT16("tx-rx-queue-capacity-bytes", DWI3C, 1374*9c0476a2SJoe Komlodi cfg.tx_rx_queue_capacity_bytes, 0x40), 1375*9c0476a2SJoe Komlodi DEFINE_PROP_UINT8("num-addressable-devices", DWI3C, 1376*9c0476a2SJoe Komlodi cfg.num_addressable_devices, 8), 1377*9c0476a2SJoe Komlodi DEFINE_PROP_UINT16("dev-addr-table-pointer", DWI3C, 1378*9c0476a2SJoe Komlodi cfg.dev_addr_table_pointer, 0x280), 1379*9c0476a2SJoe Komlodi DEFINE_PROP_UINT16("dev-addr-table-depth", DWI3C, 1380*9c0476a2SJoe Komlodi cfg.dev_addr_table_depth, 0x08), 1381*9c0476a2SJoe Komlodi DEFINE_PROP_UINT16("dev-char-table-pointer", DWI3C, 1382*9c0476a2SJoe Komlodi cfg.dev_char_table_pointer, 0x200), 1383*9c0476a2SJoe Komlodi DEFINE_PROP_UINT16("dev-char-table-depth", DWI3C, 1384*9c0476a2SJoe Komlodi cfg.dev_char_table_depth, 0x20), 1385c52aaabdSJoe Komlodi }; 1386c52aaabdSJoe Komlodi 1387c52aaabdSJoe Komlodi static void dw_i3c_class_init(ObjectClass *klass, const void *data) 1388c52aaabdSJoe Komlodi { 1389c52aaabdSJoe Komlodi DeviceClass *dc = DEVICE_CLASS(klass); 1390c52aaabdSJoe Komlodi ResettableClass *rc = RESETTABLE_CLASS(klass); 1391c52aaabdSJoe Komlodi 1392c52aaabdSJoe Komlodi rc->phases.enter = dw_i3c_reset_enter; 1393c52aaabdSJoe Komlodi 1394c52aaabdSJoe Komlodi dc->desc = "DesignWare I3C Controller"; 1395c52aaabdSJoe Komlodi dc->realize = dw_i3c_realize; 1396c52aaabdSJoe Komlodi dc->vmsd = &vmstate_dw_i3c; 1397c52aaabdSJoe Komlodi device_class_set_props(dc, dw_i3c_properties); 1398c52aaabdSJoe Komlodi } 1399c52aaabdSJoe Komlodi 1400c52aaabdSJoe Komlodi static const TypeInfo dw_i3c_info = { 1401c52aaabdSJoe Komlodi .name = TYPE_DW_I3C, 1402c52aaabdSJoe Komlodi .parent = TYPE_SYS_BUS_DEVICE, 1403c52aaabdSJoe Komlodi .instance_size = sizeof(DWI3C), 1404c52aaabdSJoe Komlodi .class_init = dw_i3c_class_init, 1405c52aaabdSJoe Komlodi }; 1406c52aaabdSJoe Komlodi 1407c52aaabdSJoe Komlodi static void dw_i3c_register_types(void) 1408c52aaabdSJoe Komlodi { 1409c52aaabdSJoe Komlodi type_register_static(&dw_i3c_info); 1410c52aaabdSJoe Komlodi } 1411c52aaabdSJoe Komlodi 1412c52aaabdSJoe Komlodi type_init(dw_i3c_register_types); 1413