diff options
| author | GuEe-GUI <[email protected]> | 2026-03-29 21:57:54 +0800 |
|---|---|---|
| committer | Rbb666 <[email protected]> | 2026-05-04 18:41:16 +0800 |
| commit | ea13820c2c1f22d3f22b39142c2ee3e0f5172efa (patch) | |
| tree | 88d620f250e9510e3075dc689ec372c5d16d8f54 /components/drivers/include | |
| parent | c1a43bc0deb17e6579d838dd7400618eb13d618c (diff) | |
[dm][ufs] support Universal Flash Storage (UFS)
Support UFS over PCI, too.
Signed-off-by: GuEe-GUI <[email protected]>
Diffstat (limited to 'components/drivers/include')
| -rwxr-xr-x | components/drivers/include/drivers/ufs.h | 662 | ||||
| -rw-r--r-- | components/drivers/include/rtdevice.h | 4 |
2 files changed, 666 insertions, 0 deletions
diff --git a/components/drivers/include/drivers/ufs.h b/components/drivers/include/drivers/ufs.h new file mode 100755 index 0000000000..c38de94e4a --- /dev/null +++ b/components/drivers/include/drivers/ufs.h @@ -0,0 +1,662 @@ +/* + * Copyright (c) 2006-2023, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2023-02-25 GuEe-GUI the first version + */ + +#ifndef __UFS_H__ +#define __UFS_H__ + +#include <rthw.h> +#include <rtthread.h> +#include <drivers/blk.h> +#include <drivers/misc.h> +#include <drivers/scsi.h> +#include <drivers/byteorder.h> + +#define __BIT_FIELD(v, h, l) ((v & RT_GENMASK(h, l)) >> l) + +/* Host Capabilities */ +#define RT_UFS_REG_CAP 0x00 /* Host Controller Capabiities */ +#define RT_UFS_REG_CAP_NUTRS(v) __BIT_FIELD(v, 4, 0) /* Number of UTP Transfer Request Slots */ +#define RT_UFS_REG_CAP_NORTT(v) __BIT_FIELD(v, 15, 8) /* Number of outstanding READY TO TRANSFER requests supported */ +#define RT_UFS_REG_CAP_NUTMRS(v) __BIT_FIELD(v, 18, 16) /* Number of UTP Task Management Request Slots */ +#define RT_UFS_REG_CAP_AUTOH8 RT_BIT(23) /* Auto-Hibernation Support */ +#define RT_UFS_REG_CAP_64AS RT_BIT(24) /* 64-bit addressing supported */ +#define RT_UFS_REG_CAP_OODDS RT_BIT(25) /* Out of order data delivery supported */ +#define RT_UFS_REG_CAP_UICDMETMS RT_BIT(26) /* UIC DME_TEST_MODE command supported */ +#define RT_UFS_REG_CAP_UME RT_BIT(27) /* Reserved for Unified Memory Extension */ +#define RT_UFS_REG_VER 0x08 /* UFS Version */ +#define RT_UFS_REG_VER_VS(v) __BIT_FIELD(v, 03, 0) /* Version Suffix (VS) */ +#define RT_UFS_REG_VER_MNR(v) __BIT_FIELD(v, 07, 4) /* Minor Version Number (MNR) */ +#define RT_UFS_REG_VER_MJR(v) __BIT_FIELD(v, 15, 8) /* Major Version Number (MJR) */ +#define RT_UFS_REG_HCPID 0x10 /* Host Controller Identification Descriptor – Product ID */ +#define RT_UFS_REG_HCMID 0x14 /* Host Controller Identification Descriptor – Manufacturer ID */ +#define RT_UFS_REG_HCMID_MIC(v) __BIT_FIELD(v, 7, 0) /* Manufacturer Identification Code */ +#define RT_UFS_REG_HCMID_BI(v) __BIT_FIELD(v, 15, 8) /* Bank Index */ +#define RT_UFS_REG_AHIT 0x18 /* Auto-Hibernate Idle Timer */ +#define RT_UFS_REG_AHIT_AH8ITV(v) __BIT_FIELD(v, 9, 0) /* Auto-Hibern8 Idle Timer Value */ +#define RT_UFS_REG_AHIT_TS(v) __BIT_FIELD(v, 12, 10) /* Timer scale */ +/* Operation and Runtime */ +#define RT_UFS_REG_IS 0x20 /* Interrupt Status */ +#define RT_UFS_REG_IS_UTRCS RT_BIT(0) /* UTP Transfer Request Completion Status */ +#define RT_UFS_REG_IS_UDEPRI RT_BIT(1) /* UIC DME_ENDPOINTRESET Indication */ +#define RT_UFS_REG_IS_UE RT_BIT(2) /* UIC Error */ +#define RT_UFS_REG_IS_UTMS RT_BIT(3) /* UIC Test Mode Status */ +#define RT_UFS_REG_IS_UPMS RT_BIT(4) /* UIC Power Mode Status */ +#define RT_UFS_REG_IS_UHXS RT_BIT(5) /* UIC Hibernate Exit Status */ +#define RT_UFS_REG_IS_UHES RT_BIT(6) /* UIC Hibernate Enter Status */ +#define RT_UFS_REG_IS_ULLS RT_BIT(7) /* UIC Link Lost Status */ +#define RT_UFS_REG_IS_ULSS RT_BIT(8) /* UIC Link Startup Status */ +#define RT_UFS_REG_IS_UTMRCS RT_BIT(9) /* UTP Task Management Request Completion Status */ +#define RT_UFS_REG_IS_UCCS RT_BIT(10) /* UIC Command Completion Status */ +#define RT_UFS_REG_IS_DFES RT_BIT(11) /* Device Fatal Error Status */ +#define RT_UFS_REG_IS_UTPES RT_BIT(12) /* UTP Error Status */ +#define RT_UFS_REG_IS_HCFES RT_BIT(16) /* Host Controller Fatal Error Status */ +#define RT_UFS_REG_IS_SBFES RT_BIT(17) /* System Bus Fatal Error Status */ +#define RT_UFS_REG_IE 0x24 /* Interrupt Enable */ +#define RT_UFS_REG_IE_UTRCE RT_BIT(0) /* UTP Transfer Request Completion Enable */ +#define RT_UFS_REG_IE_UDEPRIE RT_BIT(1) /* UIC DME_ENDPOINTRESET */ +#define RT_UFS_REG_IE_UEE RT_BIT(2) /* UIC Error Enable */ +#define RT_UFS_REG_IE_UTMSE RT_BIT(3) /* UIC Test Mode Status Enable */ +#define RT_UFS_REG_IE_UPMSE RT_BIT(4) /* UIC Power Mode Status Enable */ +#define RT_UFS_REG_IE_UHXSE RT_BIT(5) /* UIC Hibernate Exit Status Enable */ +#define RT_UFS_REG_IE_UHESE RT_BIT(6) /* UIC Hibernate Enter Status Enable */ +#define RT_UFS_REG_IE_ULLSE RT_BIT(7) /* UIC Link Lost Status Enable */ +#define RT_UFS_REG_IE_ULSSE RT_BIT(8) /* UIC Link Startup Status Enable */ +#define RT_UFS_REG_IE_UTMRCE RT_BIT(9) /* UTP Task Management Request Completion Enable */ +#define RT_UFS_REG_IE_UCCE RT_BIT(10) /* UIC COMMAND Completion Enable */ +#define RT_UFS_REG_IE_DFEE RT_BIT(11) /* Device Fatal Error Enable */ +#define RT_UFS_REG_IE_UTPEE RT_BIT(12) /* UTP Error Enable */ +#define RT_UFS_REG_IE_HCFEE RT_BIT(16) /* Host Controller Fatal Error Enable */ +#define RT_UFS_REG_IE_SBFEE RT_BIT(17) /* System Bus Fatal Error Enable */ +#define RT_UFS_REG_HCS 0x30 /* Host Controller Status */ +#define RT_UFS_REG_HCS_DP RT_BIT(0) /* Device Present */ +#define RT_UFS_REG_HCS_UTRLRDY RT_BIT(1) /* UTP Transfer Request List Ready */ +#define RT_UFS_REG_HCS_UTMRLRDY RT_BIT(2) /* UTP Task Management Request List Ready */ +#define RT_UFS_REG_HCS_UCRDY RT_BIT(3) /* UIC COMMAND Ready */ +#define RT_UFS_REG_HCS_UPMCRS(v) __BIT_FIELD(v, 10, 8) /* UIC Power Mode Change Request Status */ +#define RT_UFS_REG_HCS_UTPEC(v) __BIT_FIELD(v, 15, 12) /* UTP Error Code */ +#define RT_UFS_REG_HCS_TTAGUTPE(v) __BIT_FIELD(v, 23, 16) /* Task Tag of UTP error */ +#define RT_UFS_REG_HCS_TLUNUTPE(v) __BIT_FIELD(v, 31, 24) /* Target LUN of UTP error */ +#define RT_UFS_REG_HCE 0x34 /* Host Controller Enable */ +#define RT_UFS_REG_UECPA 0x38 /* Host UIC Error Code PHY Adapter Layer */ +#define RT_UFS_REG_UECPA_EC(v) __BIT_FIELD(v, 4, 0) /* UIC PHY Adapter Layer Error Code */ +#define RT_UFS_REG_UECPA_ERR RT_BIT(31) /* UIC PHY AdapterA Layer Error */ +#define RT_UFS_REG_UECDL 0x3c /* Host UIC Error Code Data Link Layer */ +#define RT_UFS_REG_UECDL_EC(v) __BIT_FIELD(v, 14, 0) /* UIC Data Link Layer Error Code */ +#define RT_UFS_REG_UECDL_ERR RT_BIT(31) /* UIC Data Link Layer Error */ +#define RT_UFS_REG_UECN 0x40 /* Host UIC Error Code Network Layer */ +#define RT_UFS_REG_UECN_EC(v) __BIT_FIELD(v, 2, 0) /* UIC Network Layer Error Code */ +#define RT_UFS_REG_UECN_ERR RT_BIT(31) /* UIC Network Layer Error */ +#define RT_UFS_REG_UECT 0x44 /* Host UIC Error Code Transport Layer */ +#define RT_UFS_REG_UECT_EC(v) __BIT_FIELD(v, 6, 0) /* UIC Transport Layer Error Code */ +#define RT_UFS_REG_UECT_ERR RT_BIT(31) /* UIC Transport Layer Error */ +#define RT_UFS_REG_UECDME 0x48 /* Host UIC Error Code DME */ +#define RT_UFS_REG_UECDME_EC(v) __BIT_FIELD(v, 0, 0) /* UIC DME Error Code */ +#define RT_UFS_REG_UECDME_ERR RT_BIT(31) /* UIC DME Error */ +#define RT_UFS_REG_UTRIACR 0x4c /* UTP Transfer Request Interrupt Aggregation Control Register */ +#define RT_UFS_REG_UTRIACR_IAEN RT_BIT(31) /* Interrupt Aggregation Enable/Disable */ +#define RT_UFS_REG_UTRIACR_IAPWEN RT_BIT(24) /* Interrupt aggregation parameter write enable */ +#define RT_UFS_REG_UTRIACR_IASB RT_BIT(20) /* Interrupt aggregation status bit */ +#define RT_UFS_REG_UTRIACR_CTR RT_BIT(16) /* Counter and Timer Reset */ +#define RT_UFS_REG_UTRIACR_IACTH(v) __BIT_FIELD(v, 12, 8) /* Interrupt aggregation counter threshold */ +#define RT_UFS_REG_UTRIACR_IATOVAL(v) __BIT_FIELD(v, 7, 0) /* Interrupt aggregation timeout (40us units) */ +/* UTRIACR compose */ +#define RT_UFS_UTRIACR_TIMEOUT_MASK RT_GENMASK(7, 0) +#define RT_UFS_UTRIACR_COUNTER_THLD_MASK RT_GENMASK(12, 8) +#define RT_UFS_UTRIACR_CTR RT_BIT(16) +#define RT_UFS_UTRIACR_IASB RT_BIT(20) +#define RT_UFS_UTRIACR_IAPWEN RT_BIT(24) +#define RT_UFS_UTRIACR_IAEN RT_BIT(31) +#define RT_UFS_UTRIACR_COUNTER_THLD(c) ((((rt_uint32_t)(c)) & 0x1fu) << 8) +#define RT_UFS_UTRIACR_TIMEOUT(t) (((rt_uint32_t)(t)) & 0xffu) +#define RT_UFS_UTRIACR_ENABLE_PARAMS(cnt, to) (RT_UFS_UTRIACR_IAEN | RT_UFS_UTRIACR_IAPWEN | \ + RT_UFS_UTRIACR_COUNTER_THLD(cnt) | RT_UFS_UTRIACR_TIMEOUT(to)) +#define RT_UFS_UTRIACR_RESET (RT_UFS_UTRIACR_IAEN | RT_UFS_UTRIACR_CTR) +/* UTP Transfer */ +#define RT_UFS_REG_UTRLBA 0x50 /* UTP Transfer Request List Base Address */ +#define RT_UFS_REG_UTRLBA_MASK(v) __BIT_FIELD(v, 31, 10) +#define RT_UFS_REG_UTRLBAU 0x54 /* UTP Transfer Request List Base Address Upper 32-Bits */ +#define RT_UFS_REG_UTRLBAU_MASK(v) __BIT_FIELD(v, 31, 0) +#define RT_UFS_REG_UTRLDBR 0x58 /* UTP Transfer Request List Door Bell Register */ +#define RT_UFS_REG_UTRLCLR 0x5c /* UTP Transfer Request List CLear Register */ +#define RT_UFS_REG_UTRLRSR 0x60 /* UTP Transfer Request Run-Stop Register */ +/* UTP Task Managemeng */ +#define RT_UFS_REG_UTMRLBA 0x70 /* UTP Task Management Request List Base Address */ +#define RT_UFS_REG_UTMRLBA_MASK(v) __BIT_FIELD(v, 31, 10) +#define RT_UFS_REG_UTMRLBAU 0x74 /* UTP Task Management Request List Base Address Upper 32-Bits */ +#define RT_UFS_REG_UTMRLBAU_MASK(v) __BIT_FIELD(v, 31, 0) +#define RT_UFS_REG_UTMRLDBR 0x78 /* UTP Task Management Request List Door Bell Register */ +#define RT_UFS_REG_UTMRLCLR 0x7c /* UTP Task Management Request List CLear Register */ +#define RT_UFS_REG_UTMRLRSR 0x80 /* UTP Task Management Run-Stop Register */ +/* UIC Command */ +#define RT_UFS_REG_UICCMD 0x90 /* UIC Command Register */ +#define RT_UFS_REG_UICCMD_CMDOP(v) __BIT_FIELD(v, 7, 0) /* Command Opcode */ +#define RT_UFS_REG_UCMDARG1 0x94 /* UIC Command Argument 1 */ +#define RT_UFS_REG_UCMDARG2 0x98 /* UIC Command Argument 2 */ +#define RT_UFS_REG_UCMDARG3 0x9c /* UIC Command Argument 3 */ +/* UMA */ +#define RT_UFS_REG_UMA_EXT 0xb0 /* Reserved for Unified Memory Extension */ +/* Vendor Specific */ +#define RT_UFS_REG_VS 0xc0 /* Vendor Specific Registers */ + +/* UTP Error Code */ +enum +{ + RT_UFS_UTPEC_ERR_INV_TYPE = 1, +}; + +/* UIC Power Mode Change Request Status */ +enum +{ + RT_UFS_UPMCRS_PWR_OK = 0x0, + RT_UFS_UPMCRS_PWR_LOCAL = 0x1, + RT_UFS_UPMCRS_PWR_REMOTE = 0x2, + RT_UFS_UPMCRS_PWR_BUSY = 0x3, + RT_UFS_UPMCRS_PWR_ERROR_CAP = 0x4, + RT_UFS_UPMCRS_PWR_FATAL_ERROR = 0x5, +}; + +/* UIC PHY Adapter Layer Error Code */ +enum +{ + RT_UFS_UECPA_EC_LANE0 = RT_BIT(0), + RT_UFS_UECPA_EC_LANE1 = RT_BIT(1), + RT_UFS_UECPA_EC_LANE2 = RT_BIT(2), + RT_UFS_UECPA_EC_LANE3 = RT_BIT(3), + RT_UFS_UECPA_EC_GENERIC = RT_BIT(4), +}; + +/* UIC Data Link Layer Error Code */ +enum +{ + RT_UFS_UECDL_EC_NAC_RECEIVED = RT_BIT(0), + RT_UFS_UECDL_EC_TCx_REPLAY_TIMER_EXPIRED = RT_BIT(1), + RT_UFS_UECDL_EC_AFCx_REQUEST_TIMER_EXPIRED = RT_BIT(2), + RT_UFS_UECDL_EC_FCx_PROTECTION_TIMER_EXPIRED = RT_BIT(3), + RT_UFS_UECDL_EC_CRC_ERROR = RT_BIT(4), + RT_UFS_UECDL_EC_RX_BUFFER_OVERFLOW = RT_BIT(5), + RT_UFS_UECDL_EC_MAX_FRAME_LENGTH_EXCEEDED = RT_BIT(6), + RT_UFS_UECDL_EC_WRONG_SEQUENCE_NUMBER = RT_BIT(7), + RT_UFS_UECDL_EC_AFC_FRAME_SYNTAX_ERROR = RT_BIT(8), + RT_UFS_UECDL_EC_NAC_FRAME_SYNTAX_ERROR = RT_BIT(9), + RT_UFS_UECDL_EC_EOF_SYNTAX_ERROR = RT_BIT(10), + RT_UFS_UECDL_EC_FRAME_SYNTAX_ERROR = RT_BIT(11), + RT_UFS_UECDL_EC_BAD_CTRL_SYMBOL_TYPE = RT_BIT(12), + RT_UFS_UECDL_EC_PA_INIT_ERROR = RT_BIT(13), + RT_UFS_UECDL_EC_PA_ERROR_IND_RECEIVED = RT_BIT(14), +}; + +/* UIC Network Layer Error Code */ +enum +{ + RT_UFS_UECN_EC_UNSUPPORTED_HEADER_TYPE = RT_BIT(0), + RT_UFS_UECN_EC_BAD_DEVICEID_ENC = RT_BIT(1), + RT_UFS_UECN_EC_LHDR_TRAP_PACKET_DROPPING = RT_BIT(2), +}; + +/* UIC Transport Layer Error Code */ +enum +{ + RT_UFS_UECT_EC_UNSUPPORTED_HEADER_TYPE = RT_BIT(0), + RT_UFS_UECT_EC_UNKNOWN_CPORTID = RT_BIT(1), + RT_UFS_UECT_EC_NO_CONNECTION_RX = RT_BIT(2), + RT_UFS_UECT_EC_CONTROLLED_SEGMENT_DROPPING = RT_BIT(3), + RT_UFS_UECT_EC_BAD_TC = RT_BIT(4), + RT_UFS_UECT_EC_E2E_CREDIT_OVERFLOW = RT_BIT(5), + RT_UFS_UECT_EC_SAFETY_VALVE_DROPPING = RT_BIT(6), +}; + +/* UIC DME Error Code */ +enum +{ + RT_UFS_UECDME_EC_GENERIC = RT_BIT(0), +}; + +/* UIC Command Opcode */ +enum +{ + /* Configuration */ + RT_UFS_CMDOP_DME_GET = 0x1, + RT_UFS_CMDOP_DME_SET = 0x2, + RT_UFS_CMDOP_DME_PEER_GET = 0x3, + RT_UFS_CMDOP_DME_PEER_SET = 0x4, + /* Control */ + RT_UFS_CMDOP_DME_POWERON = 0x10, + RT_UFS_CMDOP_DME_POWEROFF = 0x11, + RT_UFS_CMDOP_DME_ENABLE = 0x12, + RT_UFS_CMDOP_DME_RESET = 0x14, + RT_UFS_CMDOP_DME_ENDPOINTRESET = 0x15, + RT_UFS_CMDOP_DME_LINKSTARTUP = 0x16, + RT_UFS_CMDOP_DME_HIBERNATE_ENTER = 0x17, + RT_UFS_CMDOP_DME_HIBERNATE_EXIT = 0x18, + RT_UFS_CMDOP_DME_TEST_MODE = 0x1a, +}; + +/* UIC Config result code / Generic error code */ +enum +{ + RT_UFS_CMDRES_SUCCESS = 0x0, + RT_UFS_CMDRES_INVALID_MIB_ATTRIBUTE = 0x1, + RT_UFS_CMDRES_INVALID_MIB_ATTRIBUTE_VALUE = 0x2, + RT_UFS_CMDRES_READ_ONLY_MIB_ATTRIBUTE = 0x3, + RT_UFS_CMDRES_WRITE_ONLY_MIB_ATTRIBUTE = 0x4, + RT_UFS_CMDRES_BAD_INDEX = 0x5, + RT_UFS_CMDRES_LOCKED_MIB_ATTRIBUTE = 0x6, + RT_UFS_CMDRES_BAD_TEST_FEATURE_INDEX = 0x7, + RT_UFS_CMDRES_PEER_COMMUNICATION_FAILURE = 0x8, + RT_UFS_CMDRES_BUSY = 0x9, + RT_UFS_CMDRES_DME_FAILURE = 0xa, + RT_UFS_CMDRES_MASK = 0xff, +}; + +/* + * UIC DME attribute encoding (JEDEC UFS / UniPro PA) + */ +#define RT_UFS_UIC_ARG_MIB_SEL(attr, sel) ((((rt_uint32_t)(attr) & 0xffffU) << 16) | ((rt_uint32_t)(sel) & 0xffffU)) +#define RT_UFS_UIC_ARG_MIB(attr) RT_UFS_UIC_ARG_MIB_SEL(attr, 0) + +/* PHY Adapter — subset used for power / link configuration */ +#define RT_UFS_PA_RXGEAR 0x1583 +#define RT_UFS_PA_TXGEAR 0x1568 +#define RT_UFS_PA_ACTIVERXDATALANES 0x1580 +#define RT_UFS_PA_ACTIVETXDATALANES 0x1560 +#define RT_UFS_PA_RXTERMINATION 0x1584 +#define RT_UFS_PA_TXTERMINATION 0x1569 +#define RT_UFS_PA_HSSERIES 0x156a +#define RT_UFS_PA_PWRMODE 0x1571 +#define RT_UFS_PA_PWRMODEUSERDATA0 0x15b0 +#define RT_UFS_PA_PWRMODEUSERDATA1 0x15b1 +#define RT_UFS_PA_PWRMODEUSERDATA2 0x15b2 +#define RT_UFS_PA_PWRMODEUSERDATA3 0x15b3 +#define RT_UFS_PA_PWRMODEUSERDATA4 0x15b4 +#define RT_UFS_PA_PWRMODEUSERDATA5 0x15b5 +#define RT_UFS_DME_LOCAL_FC0_PROT_TO 0xd041 +#define RT_UFS_DME_LOCAL_TC0_REPLAY_TO 0xd042 +#define RT_UFS_DME_LOCAL_AFC0_REQ_TO 0xd043 + +#define RT_UFS_DL_FC0_PROT_TO_DEFAULT 8191U +#define RT_UFS_DL_TC0_REPLAY_TO_DEFAULT 65535U +#define RT_UFS_DL_AFC0_REQ_TO_DEFAULT 32767U +#define RT_UFS_DL_FC1_PROT_TO_DEFAULT 8191U +#define RT_UFS_DL_TC1_REPLAY_TO_DEFAULT 65535U +#define RT_UFS_DL_AFC1_REQ_TO_DEFAULT 32767U + +enum rt_ufs_pa_pwr_mode +{ + RT_UFS_PA_FAST_MODE = 1, + RT_UFS_PA_SLOW_MODE = 2, + RT_UFS_PA_FASTAUTO_MODE = 4, + RT_UFS_PA_SLOWAUTO_MODE = 5, + RT_UFS_PA_UNCHANGED_MODE = 7, +}; + +enum rt_ufs_pa_hs_rate +{ + RT_UFS_PA_HS_MODE_A = 1, + RT_UFS_PA_HS_MODE_B = 2, +}; + +/* Auto-Hibernate Idle Timer (AHIT) — REG 0x18 */ +#define RT_UFS_AHIT_TIMER_MASK RT_GENMASK(9, 0) +#define RT_UFS_AHIT_SCALE_MASK RT_GENMASK(12, 10) + +rt_inline rt_uint32_t rt_ufs_ahit_encode(rt_uint16_t timer, rt_uint8_t scale) +{ + return ((rt_uint32_t)timer & RT_UFS_AHIT_TIMER_MASK) | (((rt_uint32_t)scale << 10) & RT_UFS_AHIT_SCALE_MASK); +} + +/* 150 * 10^3 us idle before auto-Hibernate8 */ +#define RT_UFS_AHIT_DEFAULT rt_ufs_ahit_encode(150, 3) + +/* + * UTP / UPIU (refer to JEDEC UFS & UFSHCI) + */ +#define RT_UFS_CDB_SIZE 16 +#define RT_UFS_ALIGNED_UPIU_SIZE 512 +#define RT_UFS_SENSE_SIZE 18 + +/* UTP Transfer Request Command Type */ +#define RT_UTP_CMD_TYPE_SCSI 0x0 +#define RT_UTP_CMD_TYPE_UFS_STORAGE 0x1 +#define RT_UTP_CMD_TYPE_DEV_MANAGE 0x2 + +/* UTP Data Direction */ +#define RT_UTP_NO_DATA_TRANSFER 0 +#define RT_UTP_HOST_TO_DEVICE 1 +#define RT_UTP_DEVICE_TO_HOST 2 + +/* Overall Command Status (OCS) in UTRD */ +enum rt_ufs_ocs +{ + RT_UFS_OCS_SUCCESS = 0x0, + RT_UFS_OCS_INVALID_CMD_TABLE_ATTR = 0x1, + RT_UFS_OCS_INVALID_PRDT_ATTR = 0x2, + RT_UFS_OCS_MISMATCH_DATA_BUF_SIZE = 0x3, + RT_UFS_OCS_MISMATCH_RESP_UPIU_SIZE = 0x4, + RT_UFS_OCS_PEER_COMM_FAILURE = 0x5, + RT_UFS_OCS_ABORTED = 0x6, + RT_UFS_OCS_FATAL_ERROR = 0x7, + RT_UFS_OCS_DEVICE_FATAL_ERROR = 0x8, + RT_UFS_OCS_INVALID_COMMAND_STATUS = 0xf, +}; + +/* UPIU Transaction Codes (Initiator to Target) */ +#define RT_UPIU_TRANSACTION_NOP_OUT 0x00 +#define RT_UPIU_TRANSACTION_COMMAND 0x01 +#define RT_UPIU_TRANSACTION_DATA_OUT 0x02 +#define RT_UPIU_TRANSACTION_TASK_REQ 0x04 +#define RT_UPIU_TRANSACTION_QUERY_REQ 0x16 + +/* UPIU Transaction Codes (Target to Initiator) */ +#define RT_UPIU_TRANSACTION_NOP_IN 0x20 +#define RT_UPIU_TRANSACTION_RESPONSE 0x21 +#define RT_UPIU_TRANSACTION_DATA_IN 0x22 +#define RT_UPIU_TRANSACTION_TASK_RSP 0x24 +#define RT_UPIU_TRANSACTION_QUERY_RSP 0x36 + +/* UPIU Command Set Type */ +#define RT_UPIU_COMMAND_SET_TYPE_SCSI 0x0 + +/* UPIU Command flags */ +#define RT_UPIU_CMD_FLAGS_NONE 0x00 +#define RT_UPIU_CMD_FLAGS_WRITE 0x20 +#define RT_UPIU_CMD_FLAGS_READ 0x40 + +/* PRDT: max single entry size 256KB, granularity 4 bytes */ +#define RT_UFS_PRDT_BYTE_COUNT_MAX (256 * 1024) + +/* UPIU header - 12 bytes, big-endian */ +rt_packed(struct rt_utp_upiu_header +{ + rt_uint8_t transaction_code; + rt_uint8_t flags; + rt_uint8_t lun; + rt_uint8_t task_tag; + rt_uint8_t command_set_type; /* 4:0, iid 7:5 in same byte on LE */ + rt_uint8_t query_function; /* or tm_function */ + rt_uint8_t response; + rt_uint8_t status; + rt_uint8_t ehs_length; + rt_uint8_t device_information; + rt_be16_t data_segment_length; +}); + +/* Command UPIU - SCSI CDB */ +rt_packed(struct rt_utp_upiu_cmd +{ + rt_be32_t exp_data_transfer_len; + rt_uint8_t cdb[RT_UFS_CDB_SIZE]; +}); + +/* Request UPIU - command type */ +rt_packed(struct rt_utp_upiu_req +{ + struct rt_utp_upiu_header header; + struct rt_utp_upiu_cmd sc; +}); + +/* Response UPIU - SCSI response (cmd_rsp) */ +rt_packed(struct rt_utp_cmd_rsp +{ + rt_be32_t residual_transfer_count; + rt_be32_t reserved[4]; + rt_be16_t sense_data_len; + rt_uint8_t sense_data[RT_UFS_SENSE_SIZE]; +}); + +rt_packed(struct rt_utp_upiu_rsp +{ + struct rt_utp_upiu_header header; + struct rt_utp_cmd_rsp sr; +}); + +/* Physical Region Descriptor Table entry (LE, used by controller) */ +rt_packed(struct rt_ufs_sg_entry +{ + rt_uint64_t addr; /* LE in memory for UFSHCI */ + rt_uint32_t reserved; + rt_uint32_t size; /* LE */ +}); + +/* Request Descriptor Header - common to UTRD/UTMRD (4DW) */ +rt_packed(struct rt_ufs_request_desc_header +{ + rt_uint32_t dword_0; + rt_uint32_t dword_1; + rt_uint32_t dword_2; + rt_uint32_t dword_3; +}); + +/* UTP Transfer Request Descriptor bits (dword_0) */ +#define RT_UFS_UPIU_COMMAND_TYPE_OFFSET 28 +#define RT_UFS_UTP_REQ_DESC_INT_CMD 0x01000000 + +/* UTP Transfer Request Descriptor (UTRD) - 32 bytes, host byte order for HC (LE in spec) */ +rt_packed(struct rt_utp_transfer_req_desc +{ + struct rt_ufs_request_desc_header header; + /* DW 4-5: UCD base address low/high dwords */ + rt_uint32_t command_desc_base_addr_lo; /* 128-byte aligned, HC reads as LE */ + rt_uint32_t command_desc_base_addr_hi; /* 128-byte aligned, HC reads as LE */ + rt_uint16_t response_upiu_length; + rt_uint16_t response_upiu_offset; + rt_uint16_t prd_table_length; + rt_uint16_t prd_table_offset; +}); + +/* UTP Transfer Command Descriptor (UCD) - command_upiu + response_upiu + prd_table */ +struct rt_utp_transfer_cmd_desc +{ + rt_uint8_t command_upiu[RT_UFS_ALIGNED_UPIU_SIZE]; + rt_uint8_t response_upiu[RT_UFS_ALIGNED_UPIU_SIZE]; + struct rt_ufs_sg_entry prd_table[]; +}; + +/* One slot: UCD size = 512 + 512 + N*16. N=1 for single buffer. */ +/* + * PRDT entries per slot. + * Partition probing may read multiple blocks with buffers not page-aligned, + * so we keep a generous entry count to safely split by page boundaries. + */ +#define RT_UFS_PRDT_ENTRIES_PER_SLOT 32 +#define RT_UFS_UCD_SIZE (RT_UFS_ALIGNED_UPIU_SIZE * 2 + sizeof(struct rt_ufs_sg_entry) * RT_UFS_PRDT_ENTRIES_PER_SLOT) + +struct rt_ufs_ops; +struct rt_ufs_host; + +enum rt_ufs_notify_change_status +{ + RT_UFS_NOTIFY_CHANGE_STATUS_PRE, + RT_UFS_NOTIFY_CHANGE_STATUS_POST, +}; + +/* PA layer attributes for link gear / power mode (ufshcd_change_power_mode) */ +struct rt_ufs_pa_layer_attr +{ + rt_uint32_t gear_rx; + rt_uint32_t gear_tx; + rt_uint32_t lane_rx; + rt_uint32_t lane_tx; + rt_uint32_t pwr_rx; /* enum rt_ufs_pa_pwr_mode */ + rt_uint32_t pwr_tx; + rt_uint32_t hs_rate; /* enum rt_ufs_pa_hs_rate when in FAST* mode */ +}; + +struct rt_ufs_host +{ + struct rt_scsi_host parent; + + void *regs; + int irq; + + rt_uint32_t cap; + rt_uint32_t nutrs; /* Number of UTP transfer request slots, 1..32 */ + + const struct rt_ufs_ops *ops; + + /* UTRL (UTRD list) base (must be 1KB aligned); we use slot0 only */ + struct rt_utp_transfer_req_desc *utrd; /* Points to utrl_base[0] */ + void *utrl_base; /* Full UTRL base */ + rt_size_t utrl_size; /* Bytes */ + rt_ubase_t utrl_handle; + + /* UTMRL (UTMRD list) base (must be 1KB aligned); placeholder for now */ + void *utmrl_base; + rt_size_t utmrl_size; + rt_ubase_t utmrl_handle; + rt_uint8_t utmrl_coherent; + + rt_uint8_t *ucd_base; /* One UCD: command_upiu + response_upiu + prd_table */ + rt_size_t ucd_size; /* RT_UFS_UCD_SIZE or platform value */ + rt_ubase_t ucd_handle; + rt_uint8_t ucd_coherent; + + /* Bounce buffer for small DMA I/O (avoid stack/unmapped buffers) */ + rt_uint8_t *bounce; + rt_size_t bounce_size; + rt_ubase_t bounce_handle; + + /* IRQ status snapshot (written by ISR, read by transfer thread) */ + volatile rt_uint32_t irq_status; + + struct rt_completion done; + struct rt_spinlock lock; + + struct rt_ufs_pa_layer_attr pwr_active; + rt_uint8_t pwr_active_valid; + /** + * Raw AHIT register value. 0 = use RT_UFS_AHIT_DEFAULT when CAP reports Auto-H8 support. + * Write 0 via rt_ufs_auto_hibern8_set() to turn off auto-hibernate. + */ + rt_uint32_t ahit; +}; + +struct rt_ufs_ops +{ + rt_err_t (*init)(struct rt_ufs_host *ufs); + rt_err_t (*exit)(struct rt_ufs_host *ufs); + rt_err_t (*reset)(struct rt_ufs_host *ufs); + rt_err_t (*link_startup_notify)(struct rt_ufs_host *ufs, enum rt_ufs_notify_change_status status); +}; + +rt_err_t rt_ufs_host_register(struct rt_ufs_host *ufs); +rt_err_t rt_ufs_host_unregister(struct rt_ufs_host *ufs); + +/** + * @brief Send a UIC command and wait for completion + * + * Used during controller bring-up and in the link_startup_notify hook (e.g. DME_GET/SET, + * DME_LINK_STARTUP). + * + * @param ufs UFS host controller + * @param cmd UIC opcode (e.g. RT_UFS_CMDOP_DME_LINKSTARTUP) + * @param arg1 UIC command argument 1 + * @param arg2 UIC argument 2; on return, low 8 bits contain the UIC result code + * @param arg3 UIC command argument 3 + * + * @return RT_EOK on success, -RT_ETIMEOUT on timeout, -RT_ERROR on failure + */ +rt_err_t rt_ufs_uic_cmd_send(struct rt_ufs_host *ufs, rt_uint32_t cmd, + rt_uint32_t arg1, rt_uint32_t *arg2, rt_uint32_t arg3); + +/** + * @brief Apply default power/performance settings after the link is up + * + * Programs interrupt aggregation (UTRIACR) and, if the host supports it (CAP Auto-H8), the + * Auto-Hibernate idle timer (AHIT). Called from rt_ufs_host_register(); BSP code may call + * again after custom link training if needed. + * + * @param ufs UFS host controller + */ +void rt_ufs_pm_post_linkup(struct rt_ufs_host *ufs); + +/** + * @brief UIC DME_SET with UIC result check + * + * @param ufs UFS host controller + * @param attr_sel MIB selector (e.g. RT_UFS_UIC_ARG_MIB) + * @param value Attribute value written to UIC argument 3 + * + * @return RT_EOK on success, otherwise an error code + */ +rt_err_t rt_ufs_dme_set(struct rt_ufs_host *ufs, rt_uint32_t attr_sel, rt_uint32_t value); + +/** + * @brief UIC DME_GET + * + * @param ufs UFS host controller + * @param attr_sel MIB selector + * @param value Storage for the attribute value read from UIC argument 3 + * + * @return RT_EOK on success, otherwise an error code + */ +rt_err_t rt_ufs_dme_get(struct rt_ufs_host *ufs, rt_uint32_t attr_sel, rt_uint32_t *value); + +/** + * @brief Set PHY power mode via PA_PWRMODE + * + * @param ufs UFS host controller + * @param mode Encoded as (rx_mode << 4) | tx_mode (see UniPro PA power modes) + * + * @return RT_EOK on success, otherwise an error code + */ +rt_err_t rt_ufs_uic_pa_pwrmode(struct rt_ufs_host *ufs, rt_uint8_t mode); + +/** + * @brief Change PA layer gear, lanes, termination, HS series, and trigger power mode + * + * @param ufs UFS host controller + * @param attr Desired PA layer parameters + * @param force If true, apply even when attr matches the last successful configuration + * + * @return RT_EOK on success, otherwise an error code + */ +rt_err_t rt_ufs_pa_power_mode_set(struct rt_ufs_host *ufs, const struct rt_ufs_pa_layer_attr *attr, rt_bool_t force); + +/** + * @brief Request link Hibernate8 enter (UIC DME_HIBERNATE_ENTER) + * + * @param ufs UFS host controller + * + * @return RT_EOK on success, otherwise an error code + */ +rt_err_t rt_ufs_hibern8_enter(struct rt_ufs_host *ufs); + +/** + * @brief Request link Hibernate8 exit (UIC DME_HIBERNATE_EXIT) + * + * @param ufs UFS host controller + * + * @return RT_EOK on success, otherwise an error code + */ +rt_err_t rt_ufs_hibern8_exit(struct rt_ufs_host *ufs); + +/** + * @brief Program the Auto-Hibernate idle timer register (AHIT) + * + * Requires host capability RT_UFS_REG_CAP_AUTOH8. Pass 0 to disable auto-hibernate. + * + * @param ufs UFS host controller + * @param reg_val Raw AHIT register value + * + * @return RT_EOK on success, -RT_ENOSYS if Auto-H8 is not supported, otherwise an error code + */ +rt_err_t rt_ufs_auto_hibern8_set(struct rt_ufs_host *ufs, rt_uint32_t reg_val); + +/** + * @brief Configure UTP transfer completion interrupt aggregation (UTRIACR, offset 0x4C) + * + * @param ufs UFS host controller + * @param enable RT_TRUE to enable aggregation; RT_FALSE clears the register + * @param cnt Completion counter threshold before an interrupt (0–31) + * @param timeout Aggregation timeout in 40 µs steps (UFSHCI) + */ +void rt_ufs_intr_aggr_configure(struct rt_ufs_host *ufs, rt_bool_t enable, rt_uint8_t cnt, rt_uint8_t timeout); + +#endif /* __UFS_H__ */ diff --git a/components/drivers/include/rtdevice.h b/components/drivers/include/rtdevice.h index 4914fe329c..d83311bcf9 100644 --- a/components/drivers/include/rtdevice.h +++ b/components/drivers/include/rtdevice.h @@ -135,6 +135,10 @@ extern "C" { #include "drivers/thermal.h" #endif /* RT_USING_THERMAL */ +#ifdef RT_USING_UFS +#include "drivers/ufs.h" +#endif /* RT_USING_UFS */ + #ifdef RT_USING_FIRMWARE #ifdef RT_FIRMWARE_ARM_SCMI #include "drivers/scmi.h" |
