UFS Linux driver

UFS Linux driver

Introduction

The UFS Host Controller core is a standard based Serial Interface Engine for implementing a UFS interface in compliance with the UFS Architecture Specification [UFS] and the UFS Host Controller Specification [UFSHCI]. The UFS Host Controller application layer connects to a UniPro protocol stack and M-PHY. Both, UniPro protocol stack and M-PHY can be considered part of the UFS Host Controller.
The UFS Host Controller IP is a high-performance interface that is primarily used in mobile devices where data is stored on non-volatile mass storage memory device.

The primary blocks of the ufshc core architecture are

  • UFS Transport Protocol Layer

  • UFS InterConnect Layer, which consists of the following:

    • UniPro protocol stack

    • M-PHY

Features Supported in HW

  • Pre-configured for up to 32 task requests

  • Pre-configured for up to 8 task management requests

  • Support to pre-fetch more than one PRD entry (up to 16 PRD entries)

  • Supports the following UFS2.0 features

    • Higher speed up to HS-G3 (High-Speed Gear 3)

    • Symmetric 2RX-2TX lanes

    • Pre-configured for up to 2 TX/RX lanesSupport for the full range of UPIU packets, from 32 byte up to 64 kB

  • Supports the following UFS 3.0 features

    • Higher speed up to HS-G4 (High Speed Gear 4)

  • Supports UFS Card Detection

  • Supports 40-bit RMMI data interface

  • Auto-hibernate entry and exit sequence

  • With the UniPro stack and M-PHY, provides a high performance and reliable connection to the UFS Flash Memory Device.

  • Scatter/Gather DMA to transfer large data blocks

Features supported in driver

  • Supported UPIUs

    • Command/Response

    • Query Request/Query Response

    • Task Management (Not tested)

  • Interrupt mode of operation

  • PHY Configuration setup

  • UIC commands

  • Vendor specific interrupts (CIS, CRS, CTES) handling

  • Manual Hibernate entry and exit

Driver Missing features, Known Issues and Limitations

  • None

Device Configuration

By default, a new UFS device has no accessible storage partitions.

The device must be configured to create one or more Logical Units (LUs).

Each LU is a storage partition that appears as a separate disk in Linux (/dev/sdX), which you can format and use normally.

To make the storage accessible, Logical Units must be enabled and assigned the required amount of memory.

This device configuration can be done in two ways

  • UFS BareMetal application (ufspsxc_setluncfg_example.c)

    • Update “LunEnable“ and “SIZE_MB(size in Mega Bytes)“ array fields in the application as per the requirement.

  • ufs-utils from Linux Terminal (open source utility)

Configuring LUs Using ufs-utils

The configuration descriptor is a binary blob that defines all LU parameters. It is read in human-readable form but must be written back in binary form.

  1. Read the Current Configuration

Dump the configuration descriptor into a binary file (ufsconfig). This also displays the descriptor content in human-readable form on the terminal:

ufs-utils desc -t 1 -D ufsconfig -p /dev/bsg/ufs-bsg0

The terminal output shows field names and values in readable form. The ufsconfig file is the raw binary you will edit in subsequent steps.

versal2-common:/home/basecamp# ufs-utils desc -t 1 -D ufsconfig -p /dev/bsg/ufs-bsg0 Config Device Descriptor: [Byte offset 0x0]: bLength = 0xe6 Config Device Descriptor: [Byte offset 0x1]: bDescriptorType = 0x1 Config Device Descriptor: [Byte offset 0x2]: bConfDescContinue = 0x0 Config Device Descriptor: [Byte offset 0x3]: bBootEnable = 0x1 Config Device Descriptor: [Byte offset 0x4]: bDescrAccessEn = 0x0 Config Device Descriptor: [Byte offset 0x5]: bInitPowerMode = 0x1 Config Device Descriptor: [Byte offset 0x6]: bHighPriorityLUN = 0x7f Config Device Descriptor: [Byte offset 0x7]: bSecureRemovalType = 0x0 Config Device Descriptor: [Byte offset 0x8]: bInitActiveICCLevel = 0x0 Config Device Descriptor: [Byte offset 0x9]: wPeriodicRTCUpdate = 0x0 Config Device Descriptor: [Byte offset 0xb]: bHPBControl = 0x1 Config Device Descriptor: [Byte offset 0xc]: bRPMBRegionEnable = 0x0 Config Device Descriptor: [Byte offset 0xd]: bRPMBRegion1Size = 0x0 Config Device Descriptor: [Byte offset 0xe]: bRPMBRegion2Size = 0x0 Config Device Descriptor: [Byte offset 0xf]: bRPMBRegion3Size = 0x0 Config Device Descriptor: [Byte offset 0x10]: bWriteBoosterBufferPreserveUserSpaceEn = 0x0 Config Device Descriptor: [Byte offset 0x11]: bWriteBoosterBufferType = 0x0 Config Device Descriptor: [Byte offset 0x12]: dNumSharedWriteBoosterBufferAllocUnits = 0x0 Config 0 Unit Descriptor: Config Descriptor: [Byte offset 0x0]: bLUEnable = 0x1 Config Descriptor: [Byte offset 0x1]: bBootLunID = 0x1 Config Descriptor: [Byte offset 0x2]: bLUWriteProtect = 0x0 Config Descriptor: [Byte offset 0x3]: bMemoryType = 0x0 Config Descriptor: [Byte offset 0x4]: dNumAllocUnits = 0x1400 Config Descriptor: [Byte offset 0x8]: bDataReliability = 0x0 Config Descriptor: [Byte offset 0x9]: bLogicalBlockSize = 0xc Config Descriptor: [Byte offset 0xa]: bProvisioningType = 0x0 Config Descriptor: [Byte offset 0xb]: wContextCapabilities = 0x0 Config Descriptor: [Byte offset 0x10]: wLUMaxActiveHPBRegions = 0x0 Config Descriptor: [Byte offset 0x12]: wHPBPinnedRegionStartIdx = 0x0 Config Descriptor: [Byte offset 0x14]: wNumHPBPinnedRegions = 0x0 Config Descriptor: [Byte offset 0x16]: dLUNumWriteBoosterBufferAllocUnits = 0x0 Config 1 Unit Descriptor: Config Descriptor: [Byte offset 0x0]: bLUEnable = 0x1 Config Descriptor: [Byte offset 0x1]: bBootLunID = 0x0 Config Descriptor: [Byte offset 0x2]: bLUWriteProtect = 0x0 Config Descriptor: [Byte offset 0x3]: bMemoryType = 0x0 Config Descriptor: [Byte offset 0x4]: dNumAllocUnits = 0x100 Config Descriptor: [Byte offset 0x8]: bDataReliability = 0x0 Config Descriptor: [Byte offset 0x9]: bLogicalBlockSize = 0xc Config Descriptor: [Byte offset 0xa]: bProvisioningType = 0x0 Config Descriptor: [Byte offset 0xb]: wContextCapabilities = 0x0 Config Descriptor: [Byte offset 0x10]: wLUMaxActiveHPBRegions = 0x0 Config Descriptor: [Byte offset 0x12]: wHPBPinnedRegionStartIdx = 0x0 Config Descriptor: [Byte offset 0x14]: wNumHPBPinnedRegions = 0x0 Config Descriptor: [Byte offset 0x16]: dLUNumWriteBoosterBufferAllocUnits = 0x0 Config 2 Unit Descriptor: Config Descriptor: [Byte offset 0x0]: bLUEnable = 0x1 Config Descriptor: [Byte offset 0x1]: bBootLunID = 0x0 Config Descriptor: [Byte offset 0x2]: bLUWriteProtect = 0x0 Config Descriptor: [Byte offset 0x3]: bMemoryType = 0x0 Config Descriptor: [Byte offset 0x4]: dNumAllocUnits = 0x400 Config Descriptor: [Byte offset 0x8]: bDataReliability = 0x0 Config Descriptor: [Byte offset 0x9]: bLogicalBlockSize = 0xc Config Descriptor: [Byte offset 0xa]: bProvisioningType = 0x0 Config Descriptor: [Byte offset 0xb]: wContextCapabilities = 0x0 Config Descriptor: [Byte offset 0x10]: wLUMaxActiveHPBRegions = 0x0 Config Descriptor: [Byte offset 0x12]: wHPBPinnedRegionStartIdx = 0x0 Config Descriptor: [Byte offset 0x14]: wNumHPBPinnedRegions = 0x0 Config Descriptor: [Byte offset 0x16]: dLUNumWriteBoosterBufferAllocUnits = 0x0 Config 3 Unit Descriptor: Config Descriptor: [Byte offset 0x0]: bLUEnable = 0x0 Config Descriptor: [Byte offset 0x1]: bBootLunID = 0x0 Config Descriptor: [Byte offset 0x2]: bLUWriteProtect = 0x0 Config Descriptor: [Byte offset 0x3]: bMemoryType = 0x0 Config Descriptor: [Byte offset 0x4]: dNumAllocUnits = 0x0 Config Descriptor: [Byte offset 0x8]: bDataReliability = 0x0 Config Descriptor: [Byte offset 0x9]: bLogicalBlockSize = 0xc Config Descriptor: [Byte offset 0xa]: bProvisioningType = 0x0 Config Descriptor: [Byte offset 0xb]: wContextCapabilities = 0x0 Config Descriptor: [Byte offset 0x10]: wLUMaxActiveHPBRegions = 0x0 Config Descriptor: [Byte offset 0x12]: wHPBPinnedRegionStartIdx = 0x0 Config Descriptor: [Byte offset 0x14]: wNumHPBPinnedRegions = 0x0 Config Descriptor: [Byte offset 0x16]: dLUNumWriteBoosterBufferAllocUnits = 0x0 Config 4 Unit Descriptor: Config Descriptor: [Byte offset 0x0]: bLUEnable = 0x0 Config Descriptor: [Byte offset 0x1]: bBootLunID = 0x0 Config Descriptor: [Byte offset 0x2]: bLUWriteProtect = 0x0 Config Descriptor: [Byte offset 0x3]: bMemoryType = 0x0 Config Descriptor: [Byte offset 0x4]: dNumAllocUnits = 0x0 Config Descriptor: [Byte offset 0x8]: bDataReliability = 0x0 Config Descriptor: [Byte offset 0x9]: bLogicalBlockSize = 0xc Config Descriptor: [Byte offset 0xa]: bProvisioningType = 0x0 Config Descriptor: [Byte offset 0xb]: wContextCapabilities = 0x0 Config Descriptor: [Byte offset 0x10]: wLUMaxActiveHPBRegions = 0x0 Config Descriptor: [Byte offset 0x12]: wHPBPinnedRegionStartIdx = 0x0 Config Descriptor: [Byte offset 0x14]: wNumHPBPinnedRegions = 0x0 Config Descriptor: [Byte offset 0x16]: dLUNumWriteBoosterBufferAllocUnits = 0x0 Config 5 Unit Descriptor: Config Descriptor: [Byte offset 0x0]: bLUEnable = 0x0 Config Descriptor: [Byte offset 0x1]: bBootLunID = 0x0 Config Descriptor: [Byte offset 0x2]: bLUWriteProtect = 0x0 Config Descriptor: [Byte offset 0x3]: bMemoryType = 0x0 Config Descriptor: [Byte offset 0x4]: dNumAllocUnits = 0x0 Config Descriptor: [Byte offset 0x8]: bDataReliability = 0x0 Config Descriptor: [Byte offset 0x9]: bLogicalBlockSize = 0xc Config Descriptor: [Byte offset 0xa]: bProvisioningType = 0x0 Config Descriptor: [Byte offset 0xb]: wContextCapabilities = 0x0 Config Descriptor: [Byte offset 0x10]: wLUMaxActiveHPBRegions = 0x0 Config Descriptor: [Byte offset 0x12]: wHPBPinnedRegionStartIdx = 0x0 Config Descriptor: [Byte offset 0x14]: wNumHPBPinnedRegions = 0x0 Config Descriptor: [Byte offset 0x16]: dLUNumWriteBoosterBufferAllocUnits = 0x0 Config 6 Unit Descriptor: Config Descriptor: [Byte offset 0x0]: bLUEnable = 0x0 Config Descriptor: [Byte offset 0x1]: bBootLunID = 0x0 Config Descriptor: [Byte offset 0x2]: bLUWriteProtect = 0x0 Config Descriptor: [Byte offset 0x3]: bMemoryType = 0x0 Config Descriptor: [Byte offset 0x4]: dNumAllocUnits = 0x0 Config Descriptor: [Byte offset 0x8]: bDataReliability = 0x0 Config Descriptor: [Byte offset 0x9]: bLogicalBlockSize = 0xc Config Descriptor: [Byte offset 0xa]: bProvisioningType = 0x0 Config Descriptor: [Byte offset 0xb]: wContextCapabilities = 0x0 Config Descriptor: [Byte offset 0x10]: wLUMaxActiveHPBRegions = 0x0 Config Descriptor: [Byte offset 0x12]: wHPBPinnedRegionStartIdx = 0x0 Config Descriptor: [Byte offset 0x14]: wNumHPBPinnedRegions = 0x0 Config Descriptor: [Byte offset 0x16]: dLUNumWriteBoosterBufferAllocUnits = 0x0 Config 7 Unit Descriptor: Config Descriptor: [Byte offset 0x0]: bLUEnable = 0x0 Config Descriptor: [Byte offset 0x1]: bBootLunID = 0x0 Config Descriptor: [Byte offset 0x2]: bLUWriteProtect = 0x0 Config Descriptor: [Byte offset 0x3]: bMemoryType = 0x0 Config Descriptor: [Byte offset 0x4]: dNumAllocUnits = 0x0 Config Descriptor: [Byte offset 0x8]: bDataReliability = 0x0 Config Descriptor: [Byte offset 0x9]: bLogicalBlockSize = 0xc Config Descriptor: [Byte offset 0xa]: bProvisioningType = 0x0 Config Descriptor: [Byte offset 0xb]: wContextCapabilities = 0x0 Config Descriptor: [Byte offset 0x10]: wLUMaxActiveHPBRegions = 0x0 Config Descriptor: [Byte offset 0x12]: wHPBPinnedRegionStartIdx = 0x0 Config Descriptor: [Byte offset 0x14]: wNumHPBPinnedRegions = 0x0 Config Descriptor: [Byte offset 0x16]: dLUNumWriteBoosterBufferAllocUnits = 0x0 Config Descriptor was written into ufsconfig file versal2-common:/home/basecamp#
  1. Enabling the Logical Unit

  • Set bLUEnable= 0x1 at the offset for the LU(Logical Unit) you want to enable:

LU / Offset

UFS >= 3.1

UFS <3.1

LU / Offset

UFS >= 3.1

UFS <3.1

LU0

0x16

0x10

LU1

0x30

0x28

LU2

0x4A

0x40

bLUEnable Offset for LU-N

  • UFS ≥3.1 - UFS Storage Device

    • 0x16 + (N × 0x1A)

  • UFS <3.1 - UFS Storage Device

    • 0x10 + (N × 0x18)

  1. Assigning the memory to the Logical Unit

  • Set dNumAllocUnits with the computed value for the desired LU size at the corresponding offset (4 bytes, big-endian)

LU / Offset

UFS >=3.1

UFS <3.1

LU / Offset

UFS >=3.1

UFS <3.1

LU0

0x1A-0x1D

0x14-0x17

LU1

0x34-0x37

0x2C-0x2F

LU2

0x4E-0x51

0x44-0x47

dNumAllocUnits Offset for LU-N

  • UFS ≥3.1 - UFS Storage Device

    • 0x1A + (N × 0x1A)

  • UFS <3.1 - UFS Storage Device

    • 0x14 + (N × 0x18)

Calculating the value of dNumAllocUnits Value

image-20250213-100844.png

Input

Source

Input

Source

LUCapacity

User choice (desired LU size in bytes)

CapacityAdjFactor

1 for Normal Memory (bMemoryType = 0x0)

dSegmentSize

Geometry Descriptor, offset 0x0d

bAllocationUnitSize

Geometry Descriptor, offset 0x11

Read the Geometry Descriptor to get device-specific values

ufs-utils desc -t 7 -p /dev/bsg/ufs-bsg0
/* Sample Output for Geometry Descriptor */ amd-edf:/home/amd-edf# ufs-utils desc -t 7 -p /dev/bsg/ufs-bsg0 Geometry Descriptor [Byte offset 0x0]: bLength = 0x57 Geometry Descriptor [Byte offset 0x1]: bDescriptorType = 0x7 Geometry Descriptor [Byte offset 0x2]: bMediaTechnology = 0x0 Geometry Descriptor [Byte offset 0x4]: qTotalRawDeviceCapacity = 0x7734000 Geometry Descriptor [Byte offset 0xc]: bMaxNumberLU = 0x1 Geometry Descriptor [Byte offset 0xd]: dSegmentSize = 0x2000 Geometry Descriptor [Byte offset 0x11]: bAllocationUnitSize = 0x1 Geometry Descriptor [Byte offset 0x12]: bMinAddrBlockSize = 0x8 Geometry Descriptor [Byte offset 0x13]: bOptimalReadBlockSize = 0x80 Geometry Descriptor [Byte offset 0x14]: bOptimalWriteBlockSize = 0x80 Geometry Descriptor [Byte offset 0x15]: bMaxInBufferSize = 0x40 Geometry Descriptor [Byte offset 0x16]: bMaxOutBufferSize = 0x40 Geometry Descriptor [Byte offset 0x17]: bRPMB_ReadWriteSize = 0x20 Geometry Descriptor [Byte offset 0x18]: bDynamicCapacityResourcePolicy = 0x1 Geometry Descriptor [Byte offset 0x19]: bDataOrdering = 0x0 Geometry Descriptor [Byte offset 0x1a]: bMaxContexIDNumber = 0x20 Geometry Descriptor [Byte offset 0x1b]: bSysDataTagUnitSize = 0x0 Geometry Descriptor [Byte offset 0x1c]: bSysDataTagResSize = 0x6 Geometry Descriptor [Byte offset 0x1d]: bSupportedSecRTypes = 0x9 Geometry Descriptor [Byte offset 0x1e]: wSupportedMemoryTypes = 0x8009 Geometry Descriptor [Byte offset 0x20]: dSystemCodeMaxNAllocU = 0x0 Geometry Descriptor [Byte offset 0x24]: wSystemCodeCapAdjFac = 0x0 Geometry Descriptor [Byte offset 0x26]: dNonPersistMaxNAllocU = 0x0 Geometry Descriptor [Byte offset 0x2a]: wNonPersistCapAdjFac = 0x0 Geometry Descriptor [Byte offset 0x2c]: dEnhanced1MaxNAllocU = 0x3b9a Geometry Descriptor [Byte offset 0x30]: wEnhanced1CapAdjFac = 0x300 Geometry Descriptor [Byte offset 0x32]: dEnhanced2MaxNAllocU = 0x0 Geometry Descriptor [Byte offset 0x36]: wEnhanced2CapAdjFac = 0x0 Geometry Descriptor [Byte offset 0x38]: dEnhanced3MaxNAllocU = 0x0 Geometry Descriptor [Byte offset 0x3c]: wEnhanced3CapAdjFac = 0x0 Geometry Descriptor [Byte offset 0x3e]: dEnhanced4MaxNAllocU = 0x0 Geometry Descriptor [Byte offset 0x42]: wEnhanced4CapAdjFac = 0x0 Geometry Descriptor [Byte offset 0x44]: dOptimalLogicalBlockSize = 0x0 Geometry Descriptor [Byte offset 0x48]: bHPBRegionSize = 0x13 Geometry Descriptor [Byte offset 0x49]: bHPBNumberLU = 0x20 Geometry Descriptor [Byte offset 0x4a]: bHPBSubRegionSize = 0x13 Geometry Descriptor [Byte offset 0x4b]: wDeviceMaxActiveHPBRegions = 0xef Geometry Descriptor [Byte offset 0x4d]: Reserved = 0x0 Geometry Descriptor [Byte offset 0x4f]: dWriteBoosterBufferMaxNAllocUnits = 0xee6 Geometry Descriptor [Byte offset 0x53]: bDeviceMaxWriteBoosterLUs = 0x1 Geometry Descriptor [Byte offset 0x54]: bWriteBoosterBufferCapAdjFac = 0x3 Geometry Descriptor [Byte offset 0x55]: bSupportedWriteBoosterBufferUserSpaceReductionTypes = 0x2 Geometry Descriptor [Byte offset 0x56]: bSupportedWriteBoosterBufferTypes = 0x2 amd-edf:/home/amd-edf#

Worked Example: 64GB device (UFS 3.1), configuring LU0=20GB, LU1=1GB, LU2=4GB**

  Given (from Geometry Descriptor):

  • dSegmentSize = 0x2000 (8192)

  • bAllocationUnitSize = 0x1

  • CapacityAdjFactor = 1 (Normal Memory, bMemoryType = 0x0)

Allocation Unit size = dSegmentSize × bAllocationUnitSize × 512 × CapacityAdjFactor = 8192 × 1 × 512 × 1 = 4,194,304 bytes (4 MB)

dNumAllocUnits = LU_size_bytes / Allocation Unit size

LU

Desired Size

Calculation

dNumAllocUnits

Hex (big-endian)

LU

Desired Size

Calculation

dNumAllocUnits

Hex (big-endian)

LU0

20 GB

20 × 10243 / 4,194,304

5120

00 00 14 00

LU1

1 GB

1 × 1024³ / 4,194,304

256

00 00 01 00

LU2

4 GB

4 × 1024³ / 4,194,304 

1024

00 00 04 00

  1. Edit the “ufsconfig” binary file using hexedit utility (update the contents as per the requirement)

For example, below file (UFS >= 3.1) updated to enable 3 LUs with LU0 - 20GB, LU1 - 1GB and LU2 - 4GB.

versal2-common:/home/basecamp# hexedit ufsconfig /* This will open the editor to edit the file */ 00000000 E6 01 00 01 00 01 7F 00 00 00 00 01 00 00 00 00 00 00 00 00 00 00 01 00 ........................ 00000018 00 00 00 00 14 00 00 0C 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ........................ 00000030 01 00 00 00 00 00 01 00 00 0C 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ........................ 00000048 00 00 01 00 00 00 00 00 04 00 00 0C 00 00 00 00 00 00 00 00 00 00 00 00 ........................ 00000060 00 00 00 00 00 00 00 00 00 00 00 00 00 0C 00 00 00 00 00 00 00 00 00 00 ........................ 00000078 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0C 00 00 00 00 00 00 00 00 ........................ 00000090 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0C 00 00 00 00 00 00 ........................ 000000A8 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0C 00 00 00 00 ........................ 000000C0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0C 00 00 ........................ 000000D8 00 00 00 00 00 00 00 00 00 00 00 00 00 00 .............. 000000F0 00000108 00000120 00000138
  1. Verifying with hexdump

This displays canonical hex+ASCII output without byte-swapping, making it straightforward to verify multi-byte fields

amd-edf:/home/amd-edf# hexdump -C ufsconfig 00000000 e6 01 01 01 00 01 7f 00 00 00 00 01 00 00 00 00 |................| 00000010 00 00 00 00 00 00 01 01 00 00 00 00 14 00 00 0c |................| 00000020 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................| 00000030 00 00 00 00 00 00 01 00 00 0c 00 00 00 00 00 00 |................| 00000040 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................| 00000050 04 00 00 0c 00 00 00 00 00 00 00 00 00 00 00 00 |................| 00000060 00 00 00 00 00 00 00 00 00 00 00 00 00 0c 00 00 |................| 00000070 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................| 00000080 00 00 00 00 00 00 00 0c 00 00 00 00 00 00 00 00 |................| 00000090 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................| 000000a0 00 0c 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................| 000000b0 00 00 00 00 00 00 00 00 00 00 00 0c 00 00 00 00 |................| 000000c0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................| 000000d0 00 00 00 00 00 0c 00 00 00 00 00 00 00 00 00 00 |................| 000000e0 00 00 00 00 00 00 |......| 000000e6 amd-edf:/home/amd-edf#

Warning: Ensure bConfDescContinue (offset 0x02) is 0x0 before writing back.

If set to 0x1, the device will not commit the configuration and changes are silently discarded.

  1. Write back the “ufsconfig” file using the below command

versal2-common:/home/basecamp# ufs-utils desc -t 1 -w ufsconfig -p /dev/bsg/ufs-bsg0 Config Descriptor was written to device

Note: Reboot the Linux to see newly configured Logical Units or partitions

Writing and Reading Device Attributes

Device attributes are read/written separately from the configuration descriptor using the `attr` command.

Read an attribute

ufs-utils attr -t <IDN> -p /dev/bsg/ufs-bsg0

Write an attribute 

ufs-utils attr -t <IDN> -w <value> -p /dev/bsg/ufs-bsg0

UFS boot Prerequisites (Device Configurations Required for UFS boot)

For a UFS bootable device, the following must be configured

  1. Enable boot feature

  • The boot feature is enabled if bBootEnable field in the Device Descriptor is set to 01h, user must set this bit

`bBootEnable = 0x1` in Config Device Descriptor (offset 0x03)
  1. Create at least one Boot LU

  • User must create at least one Boot Logical Unit (Max 2 Boot Logical Units can be created) and enable it with the required memory configured to place the Boot Image in it

  • In the Unit Descriptor (ufsconfig) for the chosen LU:

    • `bLUEnable = 0x1`

    • `bBootLunID = 0x1` (Boot LU A) or `0x2` (Boot LU B)

    • `dNumAllocUnits = <calculated value>` (enough to hold boot image)

  1. Activate the Boot LU

  • One of the B-LU should be active (configured by writing the bBootLunEn attribute)

  • Activate Boot LU A

ufs-utils attr -t 0 -w 0x1 -p /dev/bsg/ufs-bsg0 /* verify bBootLunEn */ amd-edf:/home/amd-edf# ufs-utils attr -t 0 -r -p /dev/bsg/ufs-bsg0 bBootLunEn := 0x01 amd-edf:/home/amd-edf#
  • OR Activate Boot LU B

ufs-utils attr -t 0 -w 0x2 -p /dev/bsg/ufs-bsg0
  1. Set reference clock to 26MHz

  • bRefClkFreq Attribute need to be configured to 26MHz.

ufs-utils attr -t 10 -w 0x1 -p /dev/bsg/ufs-bsg0 /* verify bRefClkFreq */ amd-edf:/home/amd-edf# ufs-utils attr -t 10 -r -p /dev/bsg/ufs-bsg0 bRefClkFreq := 0x01 amd-edf:/home/amd-edf#

Note: User can set bRefClkFreq only when in PWM speed mode

Testing

  • Tested basic read/write on QEMU and SPP platforms

QEMU log

/***** Boot Log *****/ [ 3.846772] ufshcd-versal2 f10b0000.ufs: ufshcd_populate_vreg: Unable to find vdd-hba-supply regulator, assuming enabled [ 3.847622] ufshcd-versal2 f10b0000.ufs: ufshcd_populate_vreg: Unable to find vcc-supply regulator, assuming enabled [ 3.848248] ufshcd-versal2 f10b0000.ufs: ufshcd_populate_vreg: Unable to find vccq-supply regulator, assuming enabled [ 3.848879] ufshcd-versal2 f10b0000.ufs: ufshcd_populate_vreg: Unable to find vccq2-supply regulator, assuming enabled NOTICE: SCMI: CLK: id: 16, get_rate: 26000000 NOTICE: SCMI: CLK: id: 14, get_rate: 100000000 [ 3.859747] scsi host0: ufshcd NOTICE: SCMI reset 4/ufs0 set NOTICE: SCMI reset 35/ufsphy0 set NOTICE: SCMI reset 4/ufs0 release NOTICE: SCMI reset 35/ufsphy0 release [ 3.890596] of_cfs_init [ 3.891851] of_cfs_init: OK [ 3.893704] clk: Disabling unused clocks [ 3.894691] ALSA device list: [ 3.895493] No soundcards found. [ 3.900197] ufshcd-versal2 f10b0000.ufs: Undefined ref clk gating wait time, use default 255us [ 3.904870] Before configuring the PWR mode [ 3.908103] uart-pl011 f1920000.serial: no DMA platform data [ 3.910505] [ 3.910505] After configuring the PWR mode [ 3.931345] scsi 0:0:0:49488: Well-known LUN QEMU QEMU UFS PQ: 0 ANSI: 6 [ 3.948062] scsi 0:0:0:49476: Well-known LUN QEMU QEMU UFS PQ: 0 ANSI: 6 [ 3.954786] scsi 0:0:0:49456: scsi_add_lun: correcting incorrect peripheral device type 0x1f for W-LUN 0x c130hN [ 3.955619] scsi 0:0:0:49456: Well-known LUN QEMU QEMU TARGET 2.5 PQ: 1 ANSI: 5 [ 4.095731] scsi 0:0:0:1: Direct-Access QEMU QEMU HARDDISK 2.5+ PQ: 0 ANSI: 5 [ 4.103338] sd 0:0:0:1: [sda] 1048576 4096-byte logical blocks: (4.29 GB/4.00 GiB) [ 4.104745] sd 0:0:0:1: [sda] Write Protect is off [ 4.106060] sd 0:0:0:1: [sda] Write cache: enabled, read cache: enabled, doesn't support DPO or FUA [ 4.122833] sd 0:0:0:1: [sda] Attached SCSI disk /* FAT file system creation */ minRootfs:/home/petalinux# mkfs.vfat -F 32 -S 4096 /dev/sda mkfs.fat 4.2 (2021-01-31) minRootfs:/home/petalinux# [ 99.490635] sda: sda1 /******** Read/Write test log *******/ minRootfs:/home/petalinux# dd if=/dev/urandom of=data.bin bs=1024 count=1024 1024+0 records in 1024+0 records out minRootfs:/home/petalinux# dd of=/dev/sda if=data.bin bs=1024 count=1024 sda sda1 minRootfs:/home/petalinux# dd of=/dev/sda1 if=data.bin bs=1024 count=1024 1024+0 records in 1024+0 records out minRootfs:/home/petalinux# dd if=/dev/sda1 of=data1.bin bs=1024 count=1024 1024+0 records in 1024+0 records out minRootfs:/home/petalinux# md5sum data.bin data1.bin 35668509971b00b7cce23b749d9ef1e4 data.bin 35668509971b00b7cce23b749d9ef1e4 data1.bin /* ext4 file system creation */ minRootfs:/home/petalinux# mkfs.ext4 -b 4096 /dev/sda mke2fs 1.46.5 (30-Dec-2021) Creating filesystem with 5242880 4k blocks and 1310720 inodes Filesystem UUID: f1365c22-01b3-4830-98cd-fe840a17ef3c Superblock backups stored on blocks: 32768, 98304, 163840, 229376, 294912, 819200, 884736, 1605632, 2654208, 4096000 Allocating group tables: done Writing inode tables: done Creating journal (32768 blocks): done Writing superblocks and filesystem accounting information: done minRootfs:/home/petalinux#

Kernel Configuration

CONFIG_SCSI_UFSHCD=y CONFIG_SCSI_UFS_BSG=y CONFIG_SCSI_UFSHCD_PLATFORM=y CONFIG_SCSI_UFS_AMD_VERSAL2=y

Device-tree

Sample Device-tree node for UFS

ufs@f10b0000 { compatible = "amd,versal2-ufs"; status = "okay"; reg = <0xf10b0000 0x1000>; clocks = <&ufs_core_clk>, <&ufs_ref_clk>; clock-names = "core", "ref_clk"; resets = <&scmi_reset 4>, <&scmi_reset 35>; reset-names = "host", "phy"; interrupts = <GIC_SPI 234 IRQ_TYPE_LEVEL_HIGH>; freq-table-hz = <0 0>, <0 0>; };

Performance Details

Configurations

  • UFS Controller reference clock: 300MHz

  • PHY Ref and Config clock (external clocks): 26MHz

  • Number of lanes: 2 Tx and 2 Rx lanes

HS-G4 (Rate B) - Default Speed Gear after enabling the High Speed

versal2-vek385-sdt-seg:/home/basecamp# hdparm -tT /dev/sda

/dev/sda:
Timing cached reads: 10704 MB in 2.00 seconds = 5359.80 MB/sec
Timing buffered disk reads: 1024 MB in 0.63 seconds = 1617.36 MB/sec

amd-edf:/home/amd-edf# dd if=/dev/zero of=/dev/sda bs=200M count=4

4+0 records in

4+0 records out

838860800 bytes (839 MB, 800 MiB) copied, 9.353 s, 89.7 MB/s

HS-G1 (Rate B)

versal2-vek385-sdt-seg:/home/basecamp# hdparm -tT /dev/sda

/dev/sda:
Timing cached reads: 10050 MB in 2.00 seconds = 5031.82 MB/sec
Timing buffered disk reads: 722 MB in 3.00 seconds = 240.62 MB/sec

amd-edf:/home/amd-edf# dd if=/dev/zero of=/dev/sda bs=200M count=4

4+0 records in

4+0 records out

838860800 bytes (839 MB, 800 MiB) copied, 10.035 s, 83.6 MB/s

HS-G4 (Rate A)

versal2-vek385-sdt-seg:/home/basecamp# hdparm -tT /dev/sda

/dev/sda:
Timing cached reads: 11450 MB in 2.00 seconds = 5734.63 MB/sec
Timing buffered disk reads: 4328 MB in 3.00 seconds = 1442.06 MB/sec

amd-edf:/home/amd-edf# dd if=/dev/zero of=/dev/sda bs=200M count=4

4+0 records in

4+0 records out

838860800 bytes (839 MB, 800 MiB) copied, 9.469 s, 88.6 MB/s

HS-G1 (Rate A)

versal2-vek385-sdt-seg:/home/basecamp# hdparm -tT /dev/sda

/dev/sda:
Timing cached reads: 11360 MB in 2.00 seconds = 5689.53 MB/sec
Timing buffered disk reads: 618 MB in 3.00 seconds = 205.98 MB/sec

amd-edf:/home/amd-edf# dd if=/dev/zero of=/dev/sda bs=200M count=4

4+0 records in

4+0 records out

838860800 bytes (839 MB, 800 MiB) copied, 10.219 s, 82.1 MB/s

PWM-G4

/dev/sda:
Timing cached reads: 10156 MB in 2.00 seconds = 5084.37 MB/sec
Timing buffered disk reads: 28 MB in 3.20 seconds = 8.74 MB/sec

amd-edf:/home/amd-edf# dd if=/dev/zero of=/dev/sda bs=1M count=100

100+0 records in

100+0 records out

104857600 bytes (105 MB, 100 MiB) copied, 11.8491 s, 8.8 MB/s

PWM-G1

versal2-vek385-sdt-seg:/home/basecamp# hdparm -tT /dev/sda

/dev/sda:
Timing cached reads: 634 MB in 2.00 seconds = 317.00 MB/sec
Timing buffered disk reads: 4 MB in 3.78 seconds = 1.06 MB/sec

amd-edf:/home/amd-edf# dd if=/dev/zero of=/dev/sda bs=1M count=10

10+0 records in

10+0 records out

10485760 bytes (10 MB, 10 MiB) copied, 9.18965 s, 1.1 MB/s

Mainline Status

The upstream ufs-amd-versal2.c driver is not supported on mainline kernel , due to dependency on SCMI

Change Log

2026.1

Summary

  • Add ref_clk clock property to specify the reference clock frequency supplied to the UFS device

Commits

2025.2

Summary

  • Configure RMMI and M-PHY registers for HS mode

  • Enable AUTO_HIBERN8 and HS modes

Commits

2025.1

Summary

  • Use PM Secure read/write interface instead of IOCTL for accessing secure registers

  • Add MAINTAINERS fragment for AMD Versal2 UFS

Commits

2024.2

Summary

  • Add vendor specific ops to handle interrupts

  • Add AMD Versal Gen 2 UFS support

  • Disable AUTO_HIBERN8 and HS modes

Commits