ATF BL1 UFS初始化分析
- 1 ATF的下載鏈接
- 2 ATF BL1 UFS 初始化簡易流程圖
- 3 ATF BL1 ufs初始化簡單過程分析
- 3.1 調用過程
- 3.2 hikey960_ufs_init
- 3.3 dw_ufs_init
- 3.3 ufs_init
以海思hikey960為例來介紹,簡單介紹在ATF BL1階段的初始化處理。
1 ATF的下載鏈接
https://github.com/ARM-software/arm-trusted-firmware
可以通過下面的命令來下載ATF的代碼,或者通過打包下載的方式也可以。
git clone git@github.com:ARM-software/arm-trusted-firmware.git
2 ATF BL1 UFS 初始化簡易流程圖
3 ATF BL1 ufs初始化簡單過程分析
3.1 調用過程
以以海思hikey960為例來介紹ATF BL1 ufs 初始化的調用關系
| -- bl1_main -------- bl1_main.c| - bl1_platform_setup -------- plat/hisilicon/hikey960/hikey960_bl1_setup.c| - hikey960_ufs_init -------- plat/hisilicon/hikey960/hikey960_bl1_setup.c| - hikey960_ufs_reset -------- plat/hisilicon/hikey960/hikey960_bl1_setup.c| - dw_ufs_init -------- drivers/synopsys/ufs/dw_ufs.c| - ufs_init -------- drivers/synopsys/ufs/dw_ufs.c
3.2 hikey960_ufs_init
UFS_REG_BASE
表示UFS 配置空間的基地址HIKEY960_UFS_DESC_BASE
表示ufs 描述符的基地址HIKEY960_UFS_DESC_SIZE
表示ufs描述符的大小(ufs_params.flags & UFS_FLAGS_SKIPINIT) == 0
當前ufs驅動的flag如果是skipinit則先去做復位操作,對于hikey960來說是不會參與該處理流程的。dw_ufs_init(&ufs_params);
dw ufs的初始化處理
static void hikey960_ufs_init(void)
{dw_ufs_params_t ufs_params;memset(&ufs_params, 0, sizeof(ufs_params));ufs_params.reg_base = UFS_REG_BASE;ufs_params.desc_base = HIKEY960_UFS_DESC_BASE; ufs_params.desc_size = HIKEY960_UFS_DESC_SIZE;if ((ufs_params.flags & UFS_FLAGS_SKIPINIT) == 0)hikey960_ufs_reset();dw_ufs_init(&ufs_params);
}
3.3 dw_ufs_init
.phy_init
ufs phy初始化的處理.phy_set_pwr_mode
ufs phy 電源模式設置ufs_init(&dw_ufs_ops, &ufs_params);
dw ufs以dw_ufs_ops
作為初始化ops以及ufs_params
配置參數去做對應的dw ufs初始化操作。
static const ufs_ops_t dw_ufs_ops = {.phy_init = dwufs_phy_init,.phy_set_pwr_mode = dwufs_phy_set_pwr_mode,
};int dw_ufs_init(dw_ufs_params_t *params)
{ ufs_params_t ufs_params;memset(&ufs_params, 0, sizeof(ufs_params));ufs_params.reg_base = params->reg_base;ufs_params.desc_base = params->desc_base;ufs_params.desc_size = params->desc_size;ufs_params.flags = params->flags; ufs_init(&dw_ufs_ops, &ufs_params);return 0;
}
3.3 ufs_init
nutrs = (mmio_read_32(ufs_params.reg_base + CAP) & CAP_NUTRS_MASK) + 1;
讀取CAP寄存器去獲取UTP傳輸請求槽數量Number of UTP Transfer Request Slots (NUTRS)
。當前在BL1階段采用的是Legacy Single Doorbell mode
。
Number of UTP Transfer Request Slots (NUTRS): For Legacy Single Doorbell mode, this indicates the number of slots provided by the UTP Transfer Request List. A minimum of 1 and maximum of 32 slots may be supported.
UTP傳輸請求槽數 (NUTRS): 對于傳統單門鈴模式,它表示UTP 傳輸請求列表提供的槽數量。可支持最少 1 個、最多 32 個插槽。
For MCQ mode, this field specifies how many active transfer tasks the Host HW controller is capable of managing in parallel. The minimum of 1 and maximum of 256 slots may be supported.
對于 MCQ 模式,該字段指定主機硬件控制器能夠并行管理的活動傳輸任務數量。最少可支持 1 個插槽,最多可支持 256 個插槽。
ufshc_reset(ufs_params.reg_base);
ufs 復位操作ops->phy_init(&ufs_params);
ufs phy初始化,這個會調用在dw_ufs_init注冊的ops的phy_init接口,即dwufs_phy_init
ufshc_link_startup(ufs_params.reg_base);
執行linkstartupufs_get_device_info(&card);
獲取當前UFS設備的設備描述符ops->phy_set_pwr_mode(&ufs_params);
設置當前ufs的工作電源模式,會調用到dw_ufs_init注冊的opsphy_set_pwr_mode接口,即dwufs_phy_set_pwr_mode
函數
int ufs_init(const ufs_ops_t *ops, ufs_params_t *params)
{int result;unsigned int data;uic_cmd_t cmd;struct ufs_dev_desc card = {0};assert((params != NULL) &&(params->reg_base != 0) &&(params->desc_base != 0) &&(params->desc_size >= UFS_DESC_SIZE));memcpy(&ufs_params, params, sizeof(ufs_params_t));/* 0 means 1 slot */nutrs = (mmio_read_32(ufs_params.reg_base + CAP) & CAP_NUTRS_MASK) + 1;if (nutrs > (ufs_params.desc_size / UFS_DESC_SIZE)) {nutrs = ufs_params.desc_size / UFS_DESC_SIZE;}if (ufs_params.flags & UFS_FLAGS_SKIPINIT) {mmio_write_32(ufs_params.reg_base + UTRLBA,ufs_params.desc_base & UINT32_MAX);mmio_write_32(ufs_params.reg_base + UTRLBAU,(ufs_params.desc_base >> 32) & UINT32_MAX);result = ufshc_dme_get(0x1571, 0, &data);assert(result == 0);result = ufshc_dme_get(0x41, 0, &data);assert(result == 0);if (data == 1) {/* prepare to exit hibernate mode */memset(&cmd, 0, sizeof(uic_cmd_t));cmd.op = DME_HIBERNATE_EXIT; result = ufshc_send_uic_cmd(ufs_params.reg_base,&cmd);assert(result == 0);data = mmio_read_32(ufs_params.reg_base + UCMDARG2);assert(data == 0);do {data = mmio_read_32(ufs_params.reg_base + IS);} while ((data & UFS_INT_UHXS) == 0);mmio_write_32(ufs_params.reg_base + IS, UFS_INT_UHXS);data = mmio_read_32(ufs_params.reg_base + HCS);assert((data & HCS_UPMCRS_MASK) == HCS_PWR_LOCAL);}result = ufshc_dme_get(0x1568, 0, &data);assert(result == 0);assert((data > 0) && (data <= 3));} else {assert((ops != NULL) && (ops->phy_init != NULL) &&(ops->phy_set_pwr_mode != NULL));result = ufshc_reset(ufs_params.reg_base);assert(result == 0);ops->phy_init(&ufs_params);result = ufshc_link_startup(ufs_params.reg_base);assert(result == 0);/* enable all interrupts */data = UFS_INT_UCCS | UFS_INT_UHES | UFS_INT_UHXS | UFS_INT_UPMS;data |= UFS_INT_UTRCS | UFS_INT_ERR;mmio_write_32(ufs_params.reg_base + IE, data);ufs_enum();ufs_get_device_info(&card);if (card.wmanufacturerid == UFS_VENDOR_SKHYNIX) {ufs_params.flags |= UFS_FLAGS_VENDOR_SKHYNIX;}ops->phy_set_pwr_mode(&ufs_params);}(void)result;return 0;
}