ATF BL1 UFS初始化简单分析

news2024/11/25 22:29:24

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);执行linkstartup
  • ufs_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;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/878136.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

“解引用“空指针一定会导致段错误吗?

可能有些朋友看见这个标题第一反应是嵌入式的某些内存中,0地址也是可以被正常访问的,所以对0地址的解引用不会发生错误,但我要说的情况不是这个,而是指一个真正的空指针,不仅是c/c中的0,(void*)0,NULL,还有nullptr,一个真正的空指针. 在c语言中,想获得某结构体的成员变量相对偏…

HTTP 协议的基本格式和 fiddler 的用法

目录 一. HTTP 协议 1. HTTP协议是什么 2. HTTP协议的基本格式 HTTP请求 首行 GET和POST方法&#xff1a; 其他方法 经典面试题&#xff1a; URL Header(请求报头)部分 空行 ​HTTP响应 状态码总结: 二、Fiddler的用法 1.Fidder的安装 2.Fidder的使用 一. HTTP 协议 1. H…

netty学习分享(一)

TCP与UDP TCP 是面向连接的、可靠的流协议&#xff0c;通过三次握手建立连接&#xff0c;通讯完成时要拆除连接。 UDP是面向无连接的通讯协议&#xff0c;UDP通讯时不需要接收方确认&#xff0c;属于不可靠的传输&#xff0c;可能会出现丢包现象 端口号&#xff1a; 端口号用…

软考:中级软件设计师:文件管理,索引文件结构,树型文件结构,位示图,数据传输方式,微内核

软考&#xff1a;中级软件设计师: 提示&#xff1a;系列被面试官问的问题&#xff0c;我自己当时不会&#xff0c;所以下来自己复盘一下&#xff0c;认真学习和总结&#xff0c;以应对未来更多的可能性 关于互联网大厂的笔试面试&#xff0c;都是需要细心准备的 &#xff08;1…

数学运算1

正确答案&#xff1a;F 你的答案&#xff1a;E 参考答案&#xff1a;最大排列为100 1 99 2 98 3…51 49 50 所以和为999897…1(100-50)因为是一个圈所以&#xff0c;100和50相接&#xff0c;所以等于5000 知识点&#xff1a;数学运算

工作经验总结:RH850中SP、LP、PC寄存器间联系与入栈出栈操作简单整理

一、RH850系列中SP、LP、PC寄存器简介 SP&#xff1a;栈顶寄存器&#xff0c;保存最新栈顶的地址 LP&#xff1a;链接寄存器&#xff0c;保存函数跳转的地址&#xff08;当没发生调用子函数的操作时候&#xff0c;你可以通过单步调试发现&#xff0c;该寄存器的值不变&#x…

Golang-使用 gvm 进行版本控制

当你想为每个项目切换 go 版本时&#xff0c;gvm (Go Version Manager) 很方便。 这里&#xff0c;我将介绍“如何在Mac上安装gvm”和“如何使用gvm” 使用准备 仅适用于 Mac 的准备工作 按照MacOSX 要求中的说明执行以下命令。 xcode-select --install brew update brew …

JavaFx基础学习【一】:基本认识

一、介绍 JavaFX 是一个开源的下一代客户端应用平台&#xff0c;适用于基于Java构建的桌面、移动端和嵌入式系统。 它是许多个人和公司的共同努力的成果&#xff0c;目的是为开发丰富的客户端应用提供一个现代、高效、功能齐全的工具包。 二、JavaFx应用基本结构 想要开发一款…

浅谈医用IT隔离电源在医院特殊场所接地系统的应用

贾丽丽 安科瑞电气股份有限公司 上海嘉定 201801 【摘要】我们国家大部分医院的临床救治和确诊都是利用了医疗电气类设备和医用的医疗仪器&#xff0c;因此这些地方的接地问题应该引起我们的高度的重视。IT系统主要是利用了中性点没有直接接地的方式&#xff0c;所以可以减少电…

【【verilog 典型电路设计之加法器树乘法器】】

verilog 典型电路设计之加法器树乘法器 加法器树乘法器 加法器树乘法器的设计思想是“移位后加”&#xff0c;并且加法运算采用加法器树的形式。乘法运算的过程是&#xff0c;被乘数与乘数的每一位相乘并且乘以相应的权值&#xff0c;最后将所得的结果相加&#xff0c;便得到了…

日常BUG——微信小程序提交代码报错

&#x1f61c;作 者&#xff1a;是江迪呀✒️本文关键词&#xff1a;日常BUG、BUG、问题分析☀️每日 一言 &#xff1a;存在错误说明你在进步&#xff01; 一、问题描述 在使用微信小程序开发工具进行提交代码时&#xff0c;报出如下错误&#xff1a; Invalid a…

DDR5内存升级看光威,两款超值DDR5内存条,价格实惠性能强劲

DDR4内存条现在用的人应该占多数&#xff0c;但是时候升级DDR5了&#xff0c;都已经2023年了&#xff0c;国产内存早就崛起了&#xff0c;超值的DDR5内存条选择非常多&#xff0c;特别适合游戏玩家使用&#xff0c;像是光威前段时间推出的两款高端DDR5&#xff0c;神策DDR5 和神…

Java面向对象(内部类)(枚举)(泛型)

内部类 内部类是五大成员之一&#xff08;成员变量、方法、构造方法、代码块、内部类&#xff09;&#xff1b; 一个类定义在另一个类的内部&#xff0c;就叫做内部类&#xff1b; 当一个类的内部&#xff0c;包含一个完整的事物&#xff0c;且这个事务不必单独设计&#xf…

折线分割平面

一、题目 我们看到过很多直线分割平面的题目&#xff0c;今天的这个题目稍微有些变化&#xff0c;我们要求的是n条折线分割平面的最大数目。比如&#xff0c;一条折线可以将平面分成两部分&#xff0c;两条折线最多可以将平面分成7部分&#xff0c;具体如下所示。 Input 输入…

计算机竞赛 python 机器视觉 车牌识别 - opencv 深度学习 机器学习

1 前言 &#x1f525; 优质竞赛项目系列&#xff0c;今天要分享的是 &#x1f6a9; 基于python 机器视觉 的车牌识别系统 &#x1f947;学长这里给一个题目综合评分(每项满分5分) 难度系数&#xff1a;3分工作量&#xff1a;3分创新点&#xff1a;3分 &#x1f9ff; 更多资…

Docker自动化部署安装(十)之安装SonarQube

这里选择的是&#xff1a; sonarqube:9.1.0-community (推荐使用) postgres:9.6.23 数据库(sonarqube7.9及以后便不再支持mysql&#xff0c;版本太低的话里面的一些插件会下载不成功的) 1、docker-sonarqube.yml文件 version: 3 services:sonarqube:container_name: sonar…

打造专属企业展示小程序

在当今的数字化时代&#xff0c;企业展示小程序已经成为了推广企业形象和吸引客户的重要工具。而如何打造一个专属的企业展示小程序呢&#xff1f;下面将带您一步步操作&#xff0c;通过乔拓云网来实现这一目标。 首先&#xff0c;您需要注册登录乔拓云网并进入操作后台。在乔拓…

如何修复损坏的DOC和DOCX格式Word文件?

我们日常办公中&#xff0c;经常用到Word文档。但是有时会遇到word文件损坏、无法打开的情况。这时该怎么办&#xff1f;接着往下看&#xff0c;小编在这里就给大家带来最简单的Word文件修复方法&#xff01; 很多时候DOC和DOCX Word文件会无缘无故的损坏无法打开&#xff0c;一…

String、StringBuffer、StringBuilder三者的异同?

String字符串 不可变的字符序列在 jdk1.8&#xff0c;我们底层用 char [ ] 存储在 jdk 17&#xff0c;我们底层用 byte [ ] 存储 StringBuffer字符串缓冲区类 可变的字符序列&#xff0c;线程安全的&#xff08;synchronized&#xff09;&#xff0c;效率低在 jdk1.8&#xf…