1bc4e68d3SJeuk Kim /* 2bc4e68d3SJeuk Kim * QEMU UFS 3bc4e68d3SJeuk Kim * 4bc4e68d3SJeuk Kim * Copyright (c) 2023 Samsung Electronics Co., Ltd. All rights reserved. 5bc4e68d3SJeuk Kim * 6bc4e68d3SJeuk Kim * Written by Jeuk Kim <jeuk20.kim@samsung.com> 7bc4e68d3SJeuk Kim * 8bc4e68d3SJeuk Kim * SPDX-License-Identifier: GPL-2.0-or-later 9bc4e68d3SJeuk Kim */ 10bc4e68d3SJeuk Kim 11bc4e68d3SJeuk Kim #ifndef HW_UFS_UFS_H 12bc4e68d3SJeuk Kim #define HW_UFS_UFS_H 13bc4e68d3SJeuk Kim 14bc4e68d3SJeuk Kim #include "hw/pci/pci_device.h" 15bc4e68d3SJeuk Kim #include "hw/scsi/scsi.h" 16bc4e68d3SJeuk Kim #include "block/ufs.h" 17bc4e68d3SJeuk Kim 18bc4e68d3SJeuk Kim #define UFS_MAX_LUS 32 195c079578SMinwoo Im #define UFS_MAX_MCQ_QNUM 32 20096434feSJeuk Kim #define UFS_BLOCK_SIZE_SHIFT 12 21096434feSJeuk Kim #define UFS_BLOCK_SIZE (1 << UFS_BLOCK_SIZE_SHIFT) 22bc4e68d3SJeuk Kim 232a8b36a4SJeuk Kim typedef struct UfsBusClass { 242a8b36a4SJeuk Kim BusClass parent_class; 252a8b36a4SJeuk Kim bool (*parent_check_address)(BusState *bus, DeviceState *dev, Error **errp); 262a8b36a4SJeuk Kim } UfsBusClass; 272a8b36a4SJeuk Kim 282a8b36a4SJeuk Kim typedef struct UfsBus { 29096434feSJeuk Kim BusState parent_bus; 302a8b36a4SJeuk Kim } UfsBus; 312a8b36a4SJeuk Kim 322a8b36a4SJeuk Kim #define TYPE_UFS_BUS "ufs-bus" 332a8b36a4SJeuk Kim DECLARE_OBJ_CHECKERS(UfsBus, UfsBusClass, UFS_BUS, TYPE_UFS_BUS) 342a8b36a4SJeuk Kim 35329f1662SJeuk Kim typedef enum UfsRequestState { 36329f1662SJeuk Kim UFS_REQUEST_IDLE = 0, 37329f1662SJeuk Kim UFS_REQUEST_READY = 1, 38329f1662SJeuk Kim UFS_REQUEST_RUNNING = 2, 39329f1662SJeuk Kim UFS_REQUEST_COMPLETE = 3, 40329f1662SJeuk Kim UFS_REQUEST_ERROR = 4, 41329f1662SJeuk Kim } UfsRequestState; 42329f1662SJeuk Kim 43329f1662SJeuk Kim typedef enum UfsReqResult { 44329f1662SJeuk Kim UFS_REQUEST_SUCCESS = 0, 45329f1662SJeuk Kim UFS_REQUEST_FAIL = 1, 462a8b36a4SJeuk Kim UFS_REQUEST_NO_COMPLETE = 2, 47329f1662SJeuk Kim } UfsReqResult; 48329f1662SJeuk Kim 495c079578SMinwoo Im #define UFS_INVALID_SLOT (-1) 50329f1662SJeuk Kim typedef struct UfsRequest { 51329f1662SJeuk Kim struct UfsHc *hc; 52329f1662SJeuk Kim UfsRequestState state; 535c079578SMinwoo Im int slot; /* -1 when it's a MCQ request */ 54329f1662SJeuk Kim 55329f1662SJeuk Kim UtpTransferReqDesc utrd; 56329f1662SJeuk Kim UtpUpiuReq req_upiu; 57329f1662SJeuk Kim UtpUpiuRsp rsp_upiu; 58329f1662SJeuk Kim 59329f1662SJeuk Kim /* for scsi command */ 60329f1662SJeuk Kim QEMUSGList *sg; 61096434feSJeuk Kim uint32_t data_len; 625c079578SMinwoo Im 635c079578SMinwoo Im /* for MCQ */ 645c079578SMinwoo Im struct UfsSq *sq; 655c079578SMinwoo Im struct UfsCqEntry cqe; 665c079578SMinwoo Im QTAILQ_ENTRY(UfsRequest) entry; 67329f1662SJeuk Kim } UfsRequest; 68329f1662SJeuk Kim 695c079578SMinwoo Im static inline bool ufs_mcq_req(UfsRequest *req) 705c079578SMinwoo Im { 715c079578SMinwoo Im return req->sq != NULL; 725c079578SMinwoo Im } 735c079578SMinwoo Im 74096434feSJeuk Kim struct UfsLu; 75096434feSJeuk Kim typedef UfsReqResult (*UfsScsiOp)(struct UfsLu *, UfsRequest *); 76096434feSJeuk Kim 772a8b36a4SJeuk Kim typedef struct UfsLu { 78096434feSJeuk Kim DeviceState qdev; 792a8b36a4SJeuk Kim uint8_t lun; 802a8b36a4SJeuk Kim UnitDescriptor unit_desc; 81096434feSJeuk Kim SCSIBus bus; 82096434feSJeuk Kim SCSIDevice *scsi_dev; 83096434feSJeuk Kim BlockConf conf; 84096434feSJeuk Kim UfsScsiOp scsi_op; 852a8b36a4SJeuk Kim } UfsLu; 862a8b36a4SJeuk Kim 87bc4e68d3SJeuk Kim typedef struct UfsParams { 88bc4e68d3SJeuk Kim char *serial; 89bc4e68d3SJeuk Kim uint8_t nutrs; /* Number of UTP Transfer Request Slots */ 90bc4e68d3SJeuk Kim uint8_t nutmrs; /* Number of UTP Task Management Request Slots */ 915c079578SMinwoo Im bool mcq; /* Multiple Command Queue support */ 925c079578SMinwoo Im uint8_t mcq_qcfgptr; /* MCQ Queue Configuration Pointer in MCQCAP */ 935c079578SMinwoo Im uint8_t mcq_maxq; /* MCQ Maximum number of Queues */ 94bc4e68d3SJeuk Kim } UfsParams; 95bc4e68d3SJeuk Kim 965c079578SMinwoo Im /* 975c079578SMinwoo Im * MCQ Properties 985c079578SMinwoo Im */ 995c079578SMinwoo Im typedef struct UfsSq { 1005c079578SMinwoo Im struct UfsHc *u; 1015c079578SMinwoo Im uint8_t sqid; 1025c079578SMinwoo Im struct UfsCq *cq; 1035c079578SMinwoo Im uint64_t addr; 1045c079578SMinwoo Im uint16_t size; /* A number of entries (qdepth) */ 1055c079578SMinwoo Im 1065c079578SMinwoo Im QEMUBH *bh; /* Bottom half to process requests in async */ 1075c079578SMinwoo Im UfsRequest *req; 1085c079578SMinwoo Im QTAILQ_HEAD(, UfsRequest) req_list; /* Free request list */ 1095c079578SMinwoo Im } UfsSq; 1105c079578SMinwoo Im 1115c079578SMinwoo Im typedef struct UfsCq { 1125c079578SMinwoo Im struct UfsHc *u; 1135c079578SMinwoo Im uint8_t cqid; 1145c079578SMinwoo Im uint64_t addr; 1155c079578SMinwoo Im uint16_t size; /* A number of entries (qdepth) */ 1165c079578SMinwoo Im 1175c079578SMinwoo Im QEMUBH *bh; 1185c079578SMinwoo Im QTAILQ_HEAD(, UfsRequest) req_list; 1195c079578SMinwoo Im } UfsCq; 1205c079578SMinwoo Im 121bc4e68d3SJeuk Kim typedef struct UfsHc { 122bc4e68d3SJeuk Kim PCIDevice parent_obj; 1232a8b36a4SJeuk Kim UfsBus bus; 124bc4e68d3SJeuk Kim MemoryRegion iomem; 125bc4e68d3SJeuk Kim UfsReg reg; 1265c079578SMinwoo Im UfsMcqReg mcq_reg[UFS_MAX_MCQ_QNUM]; 1275c079578SMinwoo Im UfsMcqOpReg mcq_op_reg[UFS_MAX_MCQ_QNUM]; 128bc4e68d3SJeuk Kim UfsParams params; 129bc4e68d3SJeuk Kim uint32_t reg_size; 130329f1662SJeuk Kim UfsRequest *req_list; 131329f1662SJeuk Kim 1322a8b36a4SJeuk Kim UfsLu *lus[UFS_MAX_LUS]; 133096434feSJeuk Kim UfsLu report_wlu; 134096434feSJeuk Kim UfsLu dev_wlu; 135096434feSJeuk Kim UfsLu boot_wlu; 136096434feSJeuk Kim UfsLu rpmb_wlu; 137329f1662SJeuk Kim DeviceDescriptor device_desc; 138329f1662SJeuk Kim GeometryDescriptor geometry_desc; 139329f1662SJeuk Kim Attributes attributes; 140329f1662SJeuk Kim Flags flags; 141bc4e68d3SJeuk Kim 142bc4e68d3SJeuk Kim qemu_irq irq; 143bc4e68d3SJeuk Kim QEMUBH *doorbell_bh; 144bc4e68d3SJeuk Kim QEMUBH *complete_bh; 1455c079578SMinwoo Im 1465c079578SMinwoo Im /* MCQ properties */ 1475c079578SMinwoo Im UfsSq *sq[UFS_MAX_MCQ_QNUM]; 1485c079578SMinwoo Im UfsCq *cq[UFS_MAX_MCQ_QNUM]; 149bc4e68d3SJeuk Kim } UfsHc; 150bc4e68d3SJeuk Kim 1515c079578SMinwoo Im static inline uint32_t ufs_mcq_sq_tail(UfsHc *u, uint32_t qid) 1525c079578SMinwoo Im { 1535c079578SMinwoo Im return u->mcq_op_reg[qid].sq.tp; 1545c079578SMinwoo Im } 1555c079578SMinwoo Im 1565c079578SMinwoo Im static inline void ufs_mcq_update_sq_tail(UfsHc *u, uint32_t qid, uint32_t db) 1575c079578SMinwoo Im { 1585c079578SMinwoo Im u->mcq_op_reg[qid].sq.tp = db; 1595c079578SMinwoo Im } 1605c079578SMinwoo Im 1615c079578SMinwoo Im static inline uint32_t ufs_mcq_sq_head(UfsHc *u, uint32_t qid) 1625c079578SMinwoo Im { 1635c079578SMinwoo Im return u->mcq_op_reg[qid].sq.hp; 1645c079578SMinwoo Im } 1655c079578SMinwoo Im 1665c079578SMinwoo Im static inline void ufs_mcq_update_sq_head(UfsHc *u, uint32_t qid, uint32_t db) 1675c079578SMinwoo Im { 1685c079578SMinwoo Im u->mcq_op_reg[qid].sq.hp = db; 1695c079578SMinwoo Im } 1705c079578SMinwoo Im 1715c079578SMinwoo Im static inline bool ufs_mcq_sq_empty(UfsHc *u, uint32_t qid) 1725c079578SMinwoo Im { 1735c079578SMinwoo Im return ufs_mcq_sq_tail(u, qid) == ufs_mcq_sq_head(u, qid); 1745c079578SMinwoo Im } 1755c079578SMinwoo Im 1765c079578SMinwoo Im static inline uint32_t ufs_mcq_cq_tail(UfsHc *u, uint32_t qid) 1775c079578SMinwoo Im { 1785c079578SMinwoo Im return u->mcq_op_reg[qid].cq.tp; 1795c079578SMinwoo Im } 1805c079578SMinwoo Im 1815c079578SMinwoo Im static inline void ufs_mcq_update_cq_tail(UfsHc *u, uint32_t qid, uint32_t db) 1825c079578SMinwoo Im { 1835c079578SMinwoo Im u->mcq_op_reg[qid].cq.tp = db; 1845c079578SMinwoo Im } 1855c079578SMinwoo Im 1865c079578SMinwoo Im static inline uint32_t ufs_mcq_cq_head(UfsHc *u, uint32_t qid) 1875c079578SMinwoo Im { 1885c079578SMinwoo Im return u->mcq_op_reg[qid].cq.hp; 1895c079578SMinwoo Im } 1905c079578SMinwoo Im 1915c079578SMinwoo Im static inline void ufs_mcq_update_cq_head(UfsHc *u, uint32_t qid, uint32_t db) 1925c079578SMinwoo Im { 1935c079578SMinwoo Im u->mcq_op_reg[qid].cq.hp = db; 1945c079578SMinwoo Im } 1955c079578SMinwoo Im 1965c079578SMinwoo Im static inline bool ufs_mcq_cq_empty(UfsHc *u, uint32_t qid) 1975c079578SMinwoo Im { 1985c079578SMinwoo Im return ufs_mcq_cq_tail(u, qid) == ufs_mcq_cq_head(u, qid); 1995c079578SMinwoo Im } 2005c079578SMinwoo Im 201bc4e68d3SJeuk Kim #define TYPE_UFS "ufs" 202bc4e68d3SJeuk Kim #define UFS(obj) OBJECT_CHECK(UfsHc, (obj), TYPE_UFS) 203bc4e68d3SJeuk Kim 2042a8b36a4SJeuk Kim #define TYPE_UFS_LU "ufs-lu" 2052a8b36a4SJeuk Kim #define UFSLU(obj) OBJECT_CHECK(UfsLu, (obj), TYPE_UFS_LU) 2062a8b36a4SJeuk Kim 207329f1662SJeuk Kim typedef enum UfsQueryFlagPerm { 208329f1662SJeuk Kim UFS_QUERY_FLAG_NONE = 0x0, 209329f1662SJeuk Kim UFS_QUERY_FLAG_READ = 0x1, 210329f1662SJeuk Kim UFS_QUERY_FLAG_SET = 0x2, 211329f1662SJeuk Kim UFS_QUERY_FLAG_CLEAR = 0x4, 212329f1662SJeuk Kim UFS_QUERY_FLAG_TOGGLE = 0x8, 213329f1662SJeuk Kim } UfsQueryFlagPerm; 214329f1662SJeuk Kim 215329f1662SJeuk Kim typedef enum UfsQueryAttrPerm { 216329f1662SJeuk Kim UFS_QUERY_ATTR_NONE = 0x0, 217329f1662SJeuk Kim UFS_QUERY_ATTR_READ = 0x1, 218329f1662SJeuk Kim UFS_QUERY_ATTR_WRITE = 0x2, 219329f1662SJeuk Kim } UfsQueryAttrPerm; 220329f1662SJeuk Kim 2212a8b36a4SJeuk Kim static inline bool is_wlun(uint8_t lun) 2222a8b36a4SJeuk Kim { 2232a8b36a4SJeuk Kim return (lun == UFS_UPIU_REPORT_LUNS_WLUN || 2242a8b36a4SJeuk Kim lun == UFS_UPIU_UFS_DEVICE_WLUN || lun == UFS_UPIU_BOOT_WLUN || 2252a8b36a4SJeuk Kim lun == UFS_UPIU_RPMB_WLUN); 2262a8b36a4SJeuk Kim } 2272a8b36a4SJeuk Kim 228096434feSJeuk Kim void ufs_build_upiu_header(UfsRequest *req, uint8_t trans_type, uint8_t flags, 229096434feSJeuk Kim uint8_t response, uint8_t scsi_status, 230096434feSJeuk Kim uint16_t data_segment_length); 231*de2cc407SKyoungrul Kim void ufs_build_query_response(UfsRequest *req); 232096434feSJeuk Kim void ufs_complete_req(UfsRequest *req, UfsReqResult req_result); 233096434feSJeuk Kim void ufs_init_wlu(UfsLu *wlu, uint8_t wlun); 234bc4e68d3SJeuk Kim #endif /* HW_UFS_UFS_H */ 235