以海思hikey960为例来介绍,简单介绍在ATF BL1阶段的初始化处理。
UTP:UFS Transport Protocol
DME:Device Management Entity
UCS:UFS Command Set
UIC:UFS Interconnect
UTRD:UTP Transfer Request Descriptor
UPIU:UFS Protocol Information Unit
https://github.com/ARM-software/arm-trusted-firmware
可以通过下面的命令来下载ATF的代码,或者通过打包下载的方式也可以。
git clone git@github.com:ARM-software/arm-trusted-firmware.git
ufs dme get/set
的cmd参数ufshc_send_uic_cmd
函数中首先等到UIC READY
,然后配置UFS CMD ARG
寄存器以及UIC CMD
寄存器。cmd.op = DME_GET;
ufshc_send_uic_cmd(base, &cmd);
int ufshc_dme_get(unsigned int attr, unsigned int idx, unsigned int *val)
{
uintptr_t base;
int result, retries;
uic_cmd_t cmd;
assert(ufs_params.reg_base != 0);
if (val == NULL)
return -EINVAL;
base = ufs_params.reg_base;
cmd.arg1 = (attr << 16) | GEN_SELECTOR_IDX(idx);
cmd.arg2 = 0;
cmd.arg3 = 0;
cmd.op = DME_GET;
for (retries = 0; retries < UFS_UIC_COMMAND_RETRIES; ++retries) {
result = ufshc_send_uic_cmd(base, &cmd);
if (result == 0)
break;
/* -EIO requires UFS re-init */
if (result == -EIO) {
return result;
}
}
if (retries >= UFS_UIC_COMMAND_RETRIES)
return -EIO;
*val = mmio_read_32(base + UCMDARG3);
return 0;
}
cmd.op = DME_SET;
ufshc_send_uic_cmd(base, &cmd);
int ufshc_dme_set(unsigned int attr, unsigned int idx, unsigned int val)
{
uintptr_t base;
int result, retries;
uic_cmd_t cmd;
assert((ufs_params.reg_base != 0));
base = ufs_params.reg_base;
cmd.arg1 = (attr << 16) | GEN_SELECTOR_IDX(idx);
cmd.arg2 = 0;
cmd.arg3 = val;
cmd.op = DME_SET;
for (retries = 0; retries < UFS_UIC_COMMAND_RETRIES; ++retries) {
result = ufshc_send_uic_cmd(base, &cmd);
if (result == 0)
break;
/* -EIO requires UFS re-init */
if (result == -EIO) {
return result;
}
}
if (retries >= UFS_UIC_COMMAND_RETRIES)
return -EIO;
return 0;
}
data = mmio_read_32(base + HCS);
读取Host Controller Status寄存器的值,仅当UCRDY置位时才继续执行对应的ufs cmd。该位被置位表示当前ufs 主控制器已经准备好处理UIC命令。mmio_write_32(base + IS, ~0);
使能IAGES,CQES,SQES,CEFES,SBFES,HCFES,UTPES,DFES,UCCS,UTMRCS,ULSS,ULLS,UHES,UHXS,UPMS,UTMS,UE,UDEPRI,UTRCSmmio_write_32(base + UCMDARG1, cmd->arg1);
将arg1参数值写入UCMDARG1寄存器中。mmio_write_32(base + UCMDARG2, cmd->arg2);
将arg2参数值写入UCMDARG2寄存器中。
AttrSetType: Indicates whether the attribute value (AttrSet = NORMAL) or the attribute non-volatile reset value (STATIC) setting is requested. See MIPI UniPro Specification for the details of the AttrSetType parameter.
AttrSetType: 表示请求设置属性值(AttrSet = NORMAL)还是属性非易失性重置值(STATIC)。有关 AttrSetType 参数的详细信息,请参阅 MIPI UniPro 规范。
ConfigResultCode: Indicates the result of the UIC configuration command request. It is valid after host controller has set the IS.UCCS bit to ’1’. See MIPI UniPro Specification for the details of the ConfigResultCode parameter.
ConfigResultCode: 表示 UIC 配置命令请求的结果。它在主机控制器将 IS.UCCS 位设置为 "1 "后有效。有关 ConfigResultCode 参数的详细信息,请参见 MIPI UniPro Specification。
GenericErrorCode: Indicates the result of the UIC control command request. It is valid after host controller has set the IS.UCCS bit to ’1’. See MIPI UniPro Specification for the details of the GenericErrorCode parameter.
通用错误代码: 表示 UIC 控制命令请求的结果。它在主机控制器将 IS.UCCS 位设置为 "1 "后有效。有关 GenericErrorCode 参数的详细信息,请参见 MIPI UniPro Specification。
mmio_write_32(base + UCMDARG3, cmd->arg3);
将arg3参数值写入UCMDARG3寄存器中。
MIBvalue_R: Indicates the value of the attribute as returned by the UIC command returned. It is valid after host controller has set the IS.UCCS bit to ’1’. See MIPI UniPro Specification for the details of the MIBvalue parameter.
MIBvalue_R: 表示 UIC 命令返回的属性值。它在主机控制器将 IS.UCCS 位设置为 "1 "后有效。有关 MIBvalue 参数的详细信息,请参阅 MIPI UniPro 规范。
MIBvalue_W: Indicates the value of the attribute to be set. See MIPI UniPro Specification for details of the MIBvalue parameter.
MIBvalue_W: 表示要设置的属性值。有关 MIBvalue 参数的详细信息,请参见 MIPI UniPro Specification。
mmio_write_32(base + UICCMD, cmd->op);
将cmd-ops写入UICCMD寄存器中,使cmd开始处理。
ufs_wait_for_int_status(UFS_INT_UCCS, UIC_CMD_TIMEOUT_MS, cmd->op == DME_SET);
等待期待的中断状态
int ufshc_send_uic_cmd(uintptr_t base, uic_cmd_t *cmd)
{
unsigned int data;
int result, retries;
if (base == 0 || cmd == NULL)
return -EINVAL;
for (retries = 0; retries < 100; retries++) {
data = mmio_read_32(base + HCS);
if ((data & HCS_UCRDY) != 0) {
break;
}
mdelay(1);
}
if (retries >= 100) {
return -EBUSY;
}
mmio_write_32(base + IS, ~0);
mmio_write_32(base + UCMDARG1, cmd->arg1);
mmio_write_32(base + UCMDARG2, cmd->arg2);
mmio_write_32(base + UCMDARG3, cmd->arg3);
mmio_write_32(base + UICCMD, cmd->op);
result = ufs_wait_for_int_status(UFS_INT_UCCS, UIC_CMD_TIMEOUT_MS,
cmd->op == DME_SET);
if (result != 0) {
return result;
}
return mmio_read_32(base + UCMDARG2) & CONFIG_RESULT_CODE_MASK;
}
interrupts_enabled = mmio_read_32(ufs_params.reg_base + IE);
读取中断使能寄存器的值,该寄存器可启用或禁用向主机软件报告相应的中断。当某位被设置(‘1’)且相应的中断条件处于活动状态时,就会产生中断。被禁用(‘0’)的中断源仍会在 IS 寄存器中显示。该寄存器与 IS 寄存器对称。interrupt_status = mmio_read_32(ufs_params.reg_base + IS) & interrupts_enabled;
读取中断状态寄存器的值与中断使能寄存器的值与获取当前中断的状态值。/*
* ufs_wait_for_int_status - wait for expected interrupt status
* @expected: expected interrupt status bit
* @timeout_ms: timeout in milliseconds to poll for
* @ignore_linereset: set to ignore PA_LAYER_GEN_ERR (UIC error)
*
* Returns
* 0 - received expected interrupt and cleared it
* -EIO - fatal error, needs re-init
* -EAGAIN - non-fatal error, caller can retry
* -ETIMEDOUT - timed out waiting for interrupt status
*/
static int ufs_wait_for_int_status(const uint32_t expected_status,
unsigned int timeout_ms,
bool ignore_linereset)
{
uint32_t interrupt_status, interrupts_enabled;
int result = 0;
interrupts_enabled = mmio_read_32(ufs_params.reg_base + IE);
do {
interrupt_status = mmio_read_32(ufs_params.reg_base + IS) & interrupts_enabled;
if (interrupt_status & UFS_INT_ERR) {
mmio_write_32(ufs_params.reg_base + IS, interrupt_status & UFS_INT_ERR);
result = ufs_error_handler(interrupt_status, ignore_linereset);
if (result != 0) {
return result;
}
}
if (interrupt_status & expected_status) {
break;
}
mdelay(1);
} while (timeout_ms-- > 0);
if (!(interrupt_status & expected_status)) {
return -ETIMEDOUT;
}
mmio_write_32(ufs_params.reg_base + IS, expected_status);
return result;
}