Skip to main content

UFS Driver Debugging Guide

The S100/S600 chip integrates a UFS Host controller, with hardware supporting up to the UFS3.1 protocol, software interface supporting up to 3.0, HS-G4 rate mode, and 2 data lanes. This document describes the development, configuration, and debugging methods for the UFS driver.

UFS Hardware Architecture​

S100/S600 UFS Controller Features​

The S100/S600 chip integrates a UFS Host controller that supports the following features:

FeatureDescription
UFS Protocol VersionSupports UFS 2.0 / 2.1 / 3.0 / 3.1
UniPro VersionSupports UniPro 1.61 / 1.8
M-PHY VersionSupports M-PHY 3.0
Rate ModeHS-G4 (11.6Gbps/lane)
Data Lanes2 data lanes
Functional SupportHigh-speed read/write, secure storage

Hardware Module Composition​

The UFS subsystem consists of the following parts:

  1. UFS Host Controller (UFSHC) - Host Controller

    • Supports UFS 3.0 protocol
    • Supports HS-G4 rate (11.6Gbps/lane)
    • Supports 2 data lanes
    • Built-in SCSI command queue management
  2. MPHY - Physical Layer Interface

    • Supports Rate A and Rate B modes
    • Supports Tx Equalization configuration
    • Supports auto-calibration
  3. System Register Control

    • Clock gating control
    • Reset control
    • AXI cache configuration

Software Architecture​

┌─────────────────────────────────────────────────────────────┐
│ Application Layer │
├─────────────────────────────────────────────────────────────┤
│ File System Layer │
├─────────────────────────────────────────────────────────────┤
│ Block Device Layer │
├─────────────────────────────────────────────────────────────┤
│ SCSI Subsystem │
├─────────────────────────────────────────────────────────────┤
│ UFS Core Layer (ufshcd) │
│ ┌───────────┬───────────┬───────────┬──────────────────┐ │
│ │ UTP Transport │ UIC Control │ DME Management │ Power Management │ │
│ └───────────┴───────────┴───────────┴──────────────────┘ │
├─────────────────────────────────────────────────────────────┤
│ Host Controller Layer │
│ ┌──────────────────────────────┐ │
│ │ Hobot UFS HSI Layer │ │
│ │ (ufs-hobot.c/ufs-hobot-hsi.c)│ │
│ └──────────────────────────────┘ │
├─────────────────────────────────────────────────────────────┤
│ MPHY Physical Layer │
└─────────────────────────────────────────────────────────────┘

Code Paths​

Hobot UFS driver files

hobot-drivers/ufs/ufs-hobot.c          # Main driver file
hobot-drivers/ufs/ufs-hobot.h # Header file
hobot-drivers/ufs/ufs-hobot-hsi.c # HSI layer implementation
hobot-drivers/ufs/ufs-hobot-hsi.h # HSI layer header
hobot-drivers/ufs/Kconfig # Kernel config options
hobot-drivers/ufs/Makefile # Build configuration

Linux kernel UFS core code

drivers/ufs/core/ufshcd.c              # UFS core layer
drivers/ufs/core/ufshcd.h # UFS core header
drivers/ufs/host/ufshcd-pltfrm.c # Platform driver layer

Device tree configuration

kernel-dts/drobot-s100-soc.dtsi        # S100 SoC configuration
kernel-dts/drobot-s600-soc.dtsi        # S600 SoC configuration

Kernel Configuration​

Configuration Options​

hobot-drivers/configs/drobot_s100_defconfig

hobot-drivers/configs/drobot_s600_defconfig

# UFS core support
CONFIG_SCSI_UFSHCD=y # Enable UFS Host Controller driver
CONFIG_SCSI_UFSHCD_PLATFORM=y # Platform driver support

# Hobot UFS driver
CONFIG_SCSI_UFS_HOBOT=y # Hobot UFS Host controller driver
CONFIG_SCSI_UFS_HOBOT_OCS_POLL=n # OCS polling mode (for debugging)

# SCSI and block device support
CONFIG_SCSI=y # SCSI subsystem
CONFIG_BLK_DEV_SD=y # SCSI disk support

# Power management
CONFIG_PM=y # Power management support
CONFIG_PM_RUNTIME=y # Runtime power management

Using mk_kernel for Configuration​

# Open menuconfig interface
./mk_kernel.sh menuconfig

# Search for UFS-related configurations
# In the menuconfig interface, press / to search and enter "UFS"

Using UFS in U-Boot​

UFS runs in HS-GEAR4 mode under U-Boot, supporting standard SCSI commands to access UFS devices via the U-Boot console.

Common SCSI Commands​

CommandDescriptionExample
scsi infoView all available UFS device informationscsi info
scsi device [dev]Switch the selected UFS devicescsi device 0
scsi part [dev]View partition information of UFS devicescsi part 0
scsi read addr blk# cntRead data from UFS to memoryscsi read 0x80000000 0x1000 0x100
scsi write addr blk# cntWrite memory data to UFSscsi write 0x80000000 0x1000 0x100

ext4 File System Operations in U-Boot​

# View ext4 partition contents
ext4ls scsi 0:17

# Load file from ext4 partition to memory
ext4load scsi 0:17 0x80000000 /boot/Image

# Write memory data to ext4 partition
ext4write scsi 0:17 0x80000000 /newfile 0x10000

DTS Device Node Configuration​

S100 SoC Configuration (drobot-s100-soc.dtsi)​

ufs: ufs@0x39410000 {
power-domains = <&scmi_smc_pd PD_IDX_LSPERI_TOP>;
status = "okay";
compatible = "drobot,s100-ufshc";
reg = <0 0x39410000 0 0x10000>, /* UFS controller registers */
<0x0 0x39010000 0x0 0x1000>, /* UFS system registers */
<0x0 0x39000000 0x0 0x1000>; /* UFS clock registers */
interrupt-parent = <&gic>;
interrupts = <0 PERISYS_UFSHC_S_INTR PERISYS_UFSHC_S_INTR_TRIG_TYPE>;
ref-clk-freq = <26000000>; /* Reference clock frequency 26MHz */
lanes-per-direction = <2>; /* 2 data lanes */
pinctrl-names = "default";
pinctrl-0 = <&peri_ufs>; /* Pin configuration */

/* Get MPHY calibration values from eFuse */
ufstrim_flag_reg_pa = <0xCDF704C>; /* Calibration flag register address */
ufstrim_reg_pa = <0xCDF7014>; /* Calibration value register address */

/* Transmitter equalizer configuration */
tx_eq_main_pre_post = <35 0 0>; /* main=35, pre=0, post=0 */
};

S600 SoC 配置 (drobot-s600-soc.dtsi)​

		ufs: ufs@0x33700000 {
// power-domains = <&scmi_smc_pd PD_IDX_LSPERI_TOP>;
status = "okay";
compatible = "drobot-s600-ufshc";
reg = <0 0x33700000 0 0x10000>,
<0x0 0x33000000 0x0 0x1000>, // ufs sys reg
<0x0 0x34830000 0x0 0x1000>, // ufs clk reg
<0x0 0x33710000 0x0 0x1000>; // ufs wrap reg
interrupt-parent = <&gic>;
interrupts = <0 HSISYS_UFSHC_S_INTR IRQ_TYPE_LEVEL_HIGH>;
ref-clk-freq = <26000000>;
lanes-per-direction = <2>;
pinctrl-names = "default";
pinctrl-0 = <&hsi_ufs>;
ufstrim_reg_pa = <0xCDF701C>;
tx_eq_main_pre_post = <29 0 6>;
};

DTS Parameter Description​

ParameterDescriptionExample Value
compatibleDriver match string"drobot,s100-ufshc"
regRegister address rangeController/System/Clock registers
interruptsInterrupt configurationGIC SPI interrupt
ref-clk-freqReference clock frequency26000000 (26MHz)
lanes-per-directionNumber of data lanes per direction2
ufstrim_flag_reg_paCalibration flag register physical address0xCDF704C
ufstrim_reg_paCalibration value register physical address0xCDF7014
tx_eq_main_pre_postTransmitter equalizer parameters<main pre post>
ParameterDescriptionExample Value
compatibleDriver match string"drobot,s600-ufshc"
regRegister address rangeController/system/clock registers
interruptsInterrupt configurationGIC SPI interrupt
ref-clk-freqReference clock frequency26000000 (26MHz)
lanes-per-directionNumber of data lanes per direction2
ufstrim_reg_paCalibration value register physical address0xCDF701C
tx_eq_main_pre_postTransmitter equalizer parameters<main pre post>

Debugging Methods​

1. Check UFS Device Recognition​

# Check if UFS device is correctly recognized
ls /dev/sda*
# Should display /dev/sda and partitions (e.g., /dev/sda1, /dev/sda2)

# View block device information
lsblk
# Should show UFS disk and its partitions

# View SCSI devices
cat /proc/scsi/scsi
# Should display UFS device information

2. Check UFS Driver Loading Status​

# Check if driver is loaded
lsmod | grep ufs
# Should display ufs_hobot module

# View UFS-related information in kernel logs
dmesg | grep -i ufs

# Check UFS controller status
cat /sys/class/scsi_host/host*/proc_name
# Should display "ufshcd"

3. File System Operations​

Formatting UFS Partition​

# Format UFS partition as ext4 (e.g., partition 17) Note: This will erase all data:
mkfs.ext4 /dev/sda17

Mounting UFS Partition​

# Mount UFS partition to specified directory
mkdir -p /userdata
mount -t ext4 /dev/sda17 /userdata

# Check mount status
mount | grep sda

File System Exception Handling​

When the file system is corrupted and cannot be mounted, handle it as follows:

# Use fsck tool to check and repair ext4 file system
fsck.ext4 -f /dev/sda17

# If fsck cannot repair, consider formatting (Note: This will erase all data)
mkfs.ext4 /dev/sda17

4. Using ufs-utils Tool​

# View UFS device attributes
ufs-utils -p /dev/sda info

# View UFS health status
ufs-utils -p /dev/sda health

# View UFS configuration descriptor
ufs-utils -p /dev/sda desc

5. UFS Reliability Assessment (Lifetime Analysis)​

Since UFS wear leveling algorithms vary by manufacturer, UFS lifetime is model-dependent and should be determined based on the specific UFS device datasheet.

Checking UFS Health Status​

The Linux system automatically updates the health status nodes under the UFS device after each boot:

# Check UFS reserved block status
cat /sys/devices/platform/soc/*ufs/health_descriptor/eol_info
# Return value: 0x1 indicates reserved block status is normal

# Check UFS lifetime estimation A
cat /sys/devices/platform/soc/*ufs/health_descriptor/life_time_estimation_a
# Return value range 0x1-0xA indicates normal lifetime

# Check UFS lifetime estimation B
cat /sys/devices/platform/soc/*ufs/health_descriptor/life_time_estimation_b
# Return value range 0x1-0xA indicates normal lifetime

Health Status Parameter Description​

NodeDescriptionNormal RangeNotes
eol_infoReserved block status0x010x01 indicates normal
life_time_estimation_aLifetime estimation A0x01~0x0ASmaller values indicate more remaining life
life_time_estimation_bLifetime estimation B0x01~0x0ASmaller values indicate more remaining life

For specific value meanings, refer to the Device Health Descriptor definition in the UFS device datasheet.

6. Kernel Debug Logging​

# Enable UFS debug logging
echo 'module ufs_hobot +p' > /sys/kernel/debug/dynamic_debug/control
echo 'module ufshcd +p' > /sys/kernel/debug/dynamic_debug/control

# View real-time logs
dmesg -w | grep -i ufs

# Or use journalctl
journalctl -kf | grep -i ufs

7. Performance Testing​

Note: UFS performance testing should be performed on a mounted file system partition. Direct writing to the block device (/dev/sda) is prohibited as it will corrupt the file system.

The RDK S100 series development board has the following partitions by default. The actual partitions are subject to the board's output:

The RDK S600 series development board has the following partitions by default. The actual partitions are subject to the board's output:

Partition NumberDevice NamePartition NameSizeFile SystemMount PointPurpose
17/dev/sda17userdata2GiBext4/userdataUser data
18/dev/sda18systemRemaining disk spaceext4/Root file system

Recommended Test Partitions:

  • userdata partition (/dev/sda17 → /userdata): Preferred, designed for user data
  • system partition (/dev/sda18 → /): Alternative, be careful with system file protection

Preparing the Test Environment​

# Check UFS partition mount status
lsblk
# Example output:
# NAME MAJ:MIN RM SIZE RO TYPE MOUNTPOINT
# sda 8:0 0 3.1G 0 disk
# ├─sda13 8:13 0 15M 0 part /boot
# ├─sda16 8:16 0 512M 0 part /var/log
# ├─sda17 8:17 0 256M 0 part /userdata
# └─sda18 8:18 0 1.3G 0 part /

# Check if userdata partition (/dev/sda17) is mounted
mount | grep userdata
# If not mounted, manually mount:
# mkdir -p /userdata
# mount /dev/sda17 /userdata

# Ensure the test directory exists and has write permissions
mkdir -p /userdata/ufs_test
chmod 777 /userdata/ufs_test
# Navigate to userdata test directory
cd /userdata/ufs_test

# 1. Sequential write test (4K block size, tests small file write performance)
fio --name=seq_write_4k \
--directory=/userdata/ufs_test \
--filename=test_file \
--rw=write \
--bs=4k \
--size=512M \
--numjobs=1 \
--ioengine=libaio \
--direct=1 \
--runtime=60 \
--group_reporting

# 2. Sequential read test (4K block size)
fio --name=seq_read_4k \
--directory=/userdata/ufs_test \
--filename=test_file \
--rw=read \
--bs=4k \
--size=512M \
--numjobs=1 \
--ioengine=libaio \
--direct=1 \
--runtime=60 \
--group_reporting

# 3. Random write test (4K block size, 4 jobs, simulates multi-threaded writing)
fio --name=rand_write_4k \
--directory=/userdata/ufs_test \
--filename=test_file \
--rw=randwrite \
--bs=4k \
--size=512M \
--numjobs=4 \
--ioengine=libaio \
--direct=1 \
--runtime=60 \
--group_reporting

# 4. Random read test (4K block size, 4 jobs)
fio --name=rand_read_4k \
--directory=/userdata/ufs_test \
--filename=test_file \
--rw=randread \
--bs=4k \
--size=512M \
--numjobs=4 \
--ioengine=libaio \
--direct=1 \
--runtime=60 \
--group_reporting

# 5. Mixed read/write test (70% read, 30% write, simulates real application scenarios)
fio --name=mix_rw \
--directory=/userdata/ufs_test \
--filename=test_file \
--rw=randrw \
--rwmixread=70 \
--bs=4k \
--size=512M \
--numjobs=4 \
--ioengine=libaio \
--direct=1 \
--runtime=60 \
--group_reporting

# 6. Large file sequential write test (1M block size, tests peak bandwidth)
# Note: size should not exceed available partition space
fio --name=seq_write_1m \
--directory=/userdata/ufs_test \
--filename=test_file_big \
--rw=write \
--bs=1m \
--size=1G \
--numjobs=1 \
--ioengine=libaio \
--direct=1 \
--runtime=60 \
--group_reporting

# 7. Large file sequential read test (1M block size)
fio --name=seq_read_1m \
--directory=/userdata/ufs_test \
--filename=test_file_big \
--rw=read \
--bs=1m \
--size=1G \
--numjobs=1 \
--ioengine=libaio \
--direct=1 \
--runtime=60 \
--group_reporting

# Clean up test files
rm -f /userdata/ufs_test/test_file /userdata/ufs_test/test_file_big

Testing on system Partition (Alternative)​

If the userdata partition (/dev/sda17) is unavailable, test in the /tmp directory of the system partition (/dev/sda18):

# Use /tmp directory (located on system partition /dev/sda18)
mkdir -p /tmp/ufs_test

# Run fio test (example: 4K random write)
fio --name=rand_write_4k \
--directory=/tmp/ufs_test \
--filename=test_file \
--rw=randwrite \
--bs=4k \
--size=128M \
--numjobs=4 \
--ioengine=libaio \
--direct=1 \
--runtime=60 \
--group_reporting

# Clean up
rm -rf /tmp/ufs_test

Note: The system partition (/dev/sda18) is the root file system (1.25GB). When testing:

  • Control the test file size to avoid filling the root partition
  • Prefer using the /tmp directory, which is automatically cleaned up after system reboot
  • Do not test in system-critical directories (/bin, /sbin, /etc, etc.)

FIO Parameter Description​

ParameterDescriptionCommon Values
--nameTest job nameUser-defined
--directoryTest directory/userdata/ufs_test or /tmp/ufs_test
--filenameTest file nametest_file
--rwRead/write moderead/write/randread/randwrite/randrw
--bsBlock size4k, 128k, 1m
--sizeTest file size512M, 1G
--numjobsNumber of concurrent jobs1, 4, 8
--ioengineIO enginelibaio, sync
--direct=1Direct IO (bypass cache)1
--runtimeTest runtime (seconds)60
--group_reportingAggregate reportEnable
--rwmixreadRead percentage in mixed read/write70 (means 70% read, 30% write)

Result Interpretation​

Key FIO output metrics:

  • BW (Bandwidth): Bandwidth, in KB/s or MB/s
  • IOPS: I/O operations per second
  • lat (latency): Latency, in usec (microseconds) or msec (milliseconds)
  • clat (completion latency): Completion latency, the most important metric

Example output:

seq_write_4k: (groupid=0, jobs=1): err= 0: pid=1234: Mon Jan  1 00:00:00 2024
write: IOPS=50.5k, BW=197MiB/s (207MB/s)(11.5GiB/60001msec)
slat (usec): min=3, max=100, avg= 5.23, stdev= 2.15
clat (usec): min=50, max=5000, avg=180.50, stdev=85.20
lat (usec): min=55, max=5010, avg=185.73, stdev=85.80

Advanced Debugging​

Enabling Detailed Debug Information​

Define debug macros in the driver code:

// Add to ufs-hobot-hsi.h
#define DEBUG

// Or enable in kernel configuration
CONFIG_DYNAMIC_DEBUG=y

Adapting New UFS Devices​

When adapting new UFS device models, follow these requirements:

Hardware Compatibility Requirements​

ItemRequirement
UFS Protocol VersionCompliant with V2.1, V3.0, or V3.1 standards
Electrical CharacteristicsLevel compatible with the UFS controller
Package DimensionsMeet PCB layout requirements

Software Adaptation Steps​

  1. Verify UFS device complies with standard protocols

    • Verify device supports UFS 2.1/3.0/3.1 standards
    • Confirm UniPro and M-PHY version compatibility
  2. Adjust PHY parameters

    • MPHY parameters may need adjustment based on different UFS device electrical characteristics
    • Configure appropriate tx_eq_main_pre_post parameters in DTS
    • Adjust reference clock frequency ref-clk-freq if necessary
  3. Verify signal integrity

    • Check signal quality using an oscilloscope
    • Ensure signal integrity in HS-G4 mode
  4. Perform compatibility testing

    • Execute read/write stress tests
    • Verify power management functionality
    • Check hot-swap protection (though UFS does not support hot-swap)

Reference Documents​

  • UFS Specification Version 2.1/3.0/3.1
  • JEDEC Standard JESD220C
  • UniPro Specification Version 1.61/1.8
  • M-PHY Specification Version 3.1/4.1
  • Linux Kernel Documentation: drivers/scsi/ufs/README

Important Notes​

  1. Power Management: UFS supports multiple low-power modes; ensure power domain configuration is correct
  2. Clock Configuration: UFS requires a stable reference clock; 26MHz is used by default
  3. Signal Integrity: Pay attention to PCB trace design and impedance matching in high-speed mode
  4. Temperature Effects: MPHY calibration values vary with temperature; ensure operation within valid temperature range
  5. Hot-Swap: UFS does not support hot-swap; ensure the device is properly connected before power-on