xref: /openbmc/qemu/hw/ufs/ufs.h (revision de2cc4078240f8b745a7caeed461b02f2577e2d2)
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