LF-13910-7: drivers: firmware: imx: add support for i.MX95 soc

add support for i.MX95 soc

Signed-off-by: Pankaj Gupta <pankaj.gupta@nxp.com>
Acked-by: Rahul Kumar Yadav <rahulkumar.yadav@nxp.com>
Acked-by: Vabhav Sharma <vabhav.sharma@nxp.com>
Acked-by: Meenakshi Aggarwal <meenakshi.aggarwal@nxp.com>
Reviewed-by: Gaurav Jain <gaurav.jain@nxp.com>
Acked-by: Jason Liu <jason.hui.liu@nxp.com>
This commit is contained in:
Pankaj Gupta 2024-11-12 16:11:33 +05:30 committed by Jason Liu
parent b47a70ecb1
commit 9e7d5cc9f6
11 changed files with 406 additions and 11 deletions

View File

@ -48,7 +48,7 @@ config IMX_SEC_ENCLAVE
help
It is possible to use APIs exposed by the iMX Secure Enclave HW IP called:
- EdgeLock Enclave Firmware (for i.MX8ULP, i.MX93),
- EdgeLock Enclave Firmware (for i.MX8ULP, i.MX93, i.MX95),
like base, HSM, V2X & SHE using the SAB protocol via the shared Messaging
Unit. This driver exposes these interfaces via a set of file descriptors
allowing to configure shared memory, send and receive messages.

View File

@ -4,6 +4,6 @@ obj-$(CONFIG_IMX_SCU) += imx-scu.o misc.o imx-scu-irq.o rm.o imx-scu-soc.o seco
obj-${CONFIG_IMX_SCMI_MISC_CONTROL} += sm-misc.o
obj-$(CONFIG_IMX_SCMI_BBM_CONTROL) += sm-bbm.o
obj-$(CONFIG_IMX_ISPMU) += isp-mu.o
sec_enclave-objs = se_ctrl.o ele_common.o ele_base_msg.o ele_fw_api.o
sec_enclave-objs = se_ctrl.o ele_common.o ele_base_msg.o ele_fw_api.o v2x_base_msg.o v2x_common.o
obj-${CONFIG_IMX_SEC_ENCLAVE} += sec_enclave.o
sec_enclave-${CONFIG_IMX_ELE_TRNG} += ele_trng.o

View File

@ -702,3 +702,53 @@ int imx_se_voltage_change_req(void *se_if_data, bool start)
return ele_voltage_change_req((struct se_if_priv *)se_if_data, start);
}
EXPORT_SYMBOL_GPL(imx_se_voltage_change_req);
int ele_get_v2x_fw_state(struct se_if_priv *priv, uint32_t *state)
{
struct se_api_msg *tx_msg __free(kfree) = NULL;
struct se_api_msg *rx_msg __free(kfree) = NULL;
int ret = 0;
if (!priv) {
ret = -EINVAL;
goto exit;
}
tx_msg = kzalloc(ELE_GET_STATE_REQ_SZ, GFP_KERNEL);
if (!tx_msg) {
ret = -ENOMEM;
goto exit;
}
rx_msg = kzalloc(ELE_GET_STATE_RSP_SZ, GFP_KERNEL);
if (!rx_msg) {
ret = -ENOMEM;
goto exit;
}
ret = se_fill_cmd_msg_hdr(priv,
(struct se_msg_hdr *)&tx_msg->header,
ELE_GET_STATE,
ELE_GET_STATE_REQ_SZ,
true);
if (ret)
goto exit;
ret = ele_msg_send_rcv(priv->priv_dev_ctx,
tx_msg,
ELE_GET_STATE_REQ_SZ,
rx_msg,
ELE_GET_STATE_RSP_SZ);
if (ret < 0)
goto exit;
ret = se_val_rsp_hdr_n_status(priv,
rx_msg,
ELE_GET_STATE,
ELE_GET_STATE_RSP_SZ,
true);
if (!ret)
*state = 0xFF & rx_msg->data[1];
exit:
return ret;
}

View File

@ -106,6 +106,10 @@ struct ele_dev_info {
#define ELE_VOLT_CHANGE_REQ_MSG_SZ 0x4
#define ELE_VOLT_CHANGE_RSP_MSG_SZ 0x8
#define ELE_GET_STATE 0xB2
#define ELE_GET_STATE_REQ_SZ 0x04
#define ELE_GET_STATE_RSP_SZ 0x10
int ele_get_info(struct se_if_priv *priv, struct ele_dev_info *s_info);
int ele_fetch_soc_info(struct se_if_priv *priv, void *data);
int ele_ping(struct se_if_priv *priv);
@ -120,4 +124,5 @@ int ele_write_fuse(struct se_if_priv *priv, u16 fuse_index,
int ele_voltage_change_req(struct se_if_priv *priv, bool start);
int read_common_fuse(struct se_if_priv *priv,
u16 fuse_id, u32 *value);
int ele_get_v2x_fw_state(struct se_if_priv *priv, uint32_t *state);
#endif

View File

@ -3,8 +3,11 @@
* Copyright 2024-2025 NXP
*/
#include <uapi/linux/se_ioctl.h>
#include "ele_base_msg.h"
#include "ele_common.h"
#include "v2x_base_msg.h"
extern u32 se_rcv_msg_timeout;
@ -194,6 +197,12 @@ void se_if_rx_callback(struct mbox_client *mbox_cl, void *msg)
header = msg;
rx_msg_sz = header->size << 2;
if (priv->if_defs->se_if_type == SE_TYPE_ID_V2X_DBG &&
header->tag == V2X_DBG_MU_MSG_RSP_TAG) {
header->tag = priv->if_defs->rsp_tag;
header->ver = priv->if_defs->base_api_ver;
}
/* Incoming command: wake up the receiver if any. */
if (header->tag == priv->if_defs->cmd_tag) {
se_clbk_hdl = &priv->cmd_receiver_clbk_hdl;

View File

@ -31,6 +31,8 @@
#include "ele_fw_api.h"
#include "ele_trng.h"
#include "se_ctrl.h"
#include "v2x_base_msg.h"
#include "v2x_common.h"
#define MAX_SOC_INFO_DATA_SZ 256
#define MBOX_TX_NAME "tx"
@ -61,6 +63,7 @@ struct se_if_node_info {
u8 se_if_did;
struct se_if_defines if_defs;
u8 *pool_name;
u32 mu_buff_size;
bool reserved_dma_ranges;
int (*start_rng)(struct se_if_priv *priv);
int (*init_trng)(struct se_if_priv *priv);
@ -112,6 +115,7 @@ static struct se_if_node_info_list imx8ulp_info = {
{
.se_if_id = 0,
.se_if_did = 7,
.mu_buff_size = 0,
.if_defs = {
.se_if_type = SE_TYPE_ID_HSM,
.se_instance_id = 0,
@ -139,6 +143,7 @@ static struct se_if_node_info_list imx93_info = {
.info = {
{
.se_if_id = 0,
.mu_buff_size = 0,
.if_defs = {
.se_if_type = SE_TYPE_ID_HSM,
.se_instance_id = 0,
@ -157,9 +162,97 @@ static struct se_if_node_info_list imx93_info = {
},
};
static struct se_if_node_info_list imx95_info = {
.num_mu = 4,
.soc_id = SOC_ID_OF_IMX95,
.soc_register = false,
.se_fetch_soc_info = ele_fetch_soc_info,
.load_hsm_fw = {
.prim_fw_nm_in_rfs = NULL,
.seco_fw_nm_in_rfs = NULL,
.is_fw_loaded = true,
.handle_susp_resm = false,
},
.info = {
{
.se_if_id = 0,
.mu_buff_size = 0,
.if_defs = {
.se_if_type = SE_TYPE_ID_HSM,
.se_instance_id = 0,
.cmd_tag = 0x17,
.rsp_tag = 0xe1,
.success_tag = ELE_SUCCESS_IND,
.base_api_ver = MESSAGING_VERSION_6,
.fw_api_ver = MESSAGING_VERSION_7,
},
.reserved_dma_ranges = false,
.start_rng = ele_start_rng,
.init_trng = ele_trng_init,
.se_if_early_init = NULL,
.se_if_late_init = v2x_late_init,
},
{
.se_if_id = 1,
.mu_buff_size = 0,
.if_defs = {
.se_if_type = SE_TYPE_ID_V2X_DBG,
.se_instance_id = 0,
.cmd_tag = 0x1a,
.rsp_tag = 0xe4,
.success_tag = ELE_SUCCESS_IND,
.base_api_ver = MESSAGING_VERSION_2,
.fw_api_ver = MESSAGING_VERSION_2,
},
.reserved_dma_ranges = false,
.start_rng = v2x_start_rng,
.init_trng = NULL,
.se_if_early_init = v2x_early_init,
.se_if_late_init = NULL,
},
{
.se_if_id = 2,
.mu_buff_size = 16,
.if_defs = {
.se_if_type = SE_TYPE_ID_V2X_SV,
.se_instance_id = 0,
.cmd_tag = 0x18,
.rsp_tag = 0xe2,
.success_tag = ELE_SUCCESS_IND,
.base_api_ver = MESSAGING_VERSION_2,
.fw_api_ver = MESSAGING_VERSION_2,
},
.reserved_dma_ranges = false,
.start_rng = NULL,
.init_trng = NULL,
.se_if_early_init = v2x_early_init,
.se_if_late_init = NULL,
},
{
.se_if_id = 3,
.mu_buff_size = 256,
.if_defs = {
.se_if_type = SE_TYPE_ID_V2X_SHE,
.se_instance_id = 0,
.cmd_tag = 0x1a,
.rsp_tag = 0xe4,
.success_tag = ELE_SUCCESS_IND,
.base_api_ver = MESSAGING_VERSION_2,
.fw_api_ver = MESSAGING_VERSION_2,
},
.reserved_dma_ranges = false,
.start_rng = NULL,
.init_trng = NULL,
.se_if_early_init = v2x_early_init,
.se_if_late_init = NULL,
},
},
};
static const struct of_device_id se_match[] = {
{ .compatible = "fsl,imx8ulp-se", .data = (void *)&imx8ulp_info},
{ .compatible = "fsl,imx93-se", .data = (void *)&imx93_info},
{ .compatible = "fsl,imx95-se", .data = (void *)&imx95_info},
{},
};
@ -303,6 +396,8 @@ void *imx_get_se_data_info(u32 soc_id, u32 idx)
info_list = &imx8ulp_info; break;
case SOC_ID_OF_IMX93:
info_list = &imx93_info; break;
case SOC_ID_OF_IMX95:
info_list = &imx95_info; break;
default:
return NULL;
}
@ -665,8 +760,12 @@ static int se_dev_ctx_cpy_out_data(struct se_if_device_ctx *dev_ctx)
}
}
if (b_desc->shared_buf_ptr)
memset(b_desc->shared_buf_ptr, 0, b_desc->size);
if (b_desc->shared_buf_ptr) {
if (dev_ctx->priv->mu_mem.pos)
memset_io(b_desc->shared_buf_ptr, 0, b_desc->size);
else
memset(b_desc->shared_buf_ptr, 0, b_desc->size);
}
list_del(&b_desc->link);
kfree(b_desc);
@ -689,10 +788,13 @@ static void se_dev_ctx_shared_mem_cleanup(struct se_if_device_ctx *dev_ctx)
int i;
for (i = 0; i < 2; i++) {
list_for_each_entry_safe(b_desc, temp,
pending_lists[i], link) {
if (b_desc->shared_buf_ptr)
memset(b_desc->shared_buf_ptr, 0, b_desc->size);
list_for_each_entry_safe(b_desc, temp, pending_lists[i], link) {
if (b_desc->shared_buf_ptr) {
if (dev_ctx->priv->mu_mem.pos)
memset_io(b_desc->shared_buf_ptr, 0, b_desc->size);
else
memset(b_desc->shared_buf_ptr, 0, b_desc->size);
}
list_del(&b_desc->link);
kfree(b_desc);
@ -928,6 +1030,7 @@ static int se_ioctl_cmd_snd_rcv_rsp_handler(struct se_if_device_ctx *dev_ctx,
exit:
se_dev_ctx_shared_mem_cleanup(dev_ctx);
priv->mu_mem.pos = 0;
if (copy_to_user((void __user *)arg, &cmd_snd_rcv_rsp_info,
sizeof(cmd_snd_rcv_rsp_info))) {
@ -1014,8 +1117,11 @@ static int se_ioctl_setup_iobuf_handler(struct se_if_device_ctx *dev_ctx,
goto copy;
}
/* No specific requirement for this buffer. */
shared_mem = &dev_ctx->se_shared_mem_mgmt.non_secure_mem;
/* Select the shared memory to be used for this buffer. */
if (io.flags & SE_IO_BUF_FLAGS_USE_MU_BUF)
shared_mem = &dev_ctx->priv->mu_mem;
else
shared_mem = &dev_ctx->se_shared_mem_mgmt.non_secure_mem;
/* Check there is enough space in the shared memory. */
dev_dbg(dev_ctx->priv->dev,
@ -1038,7 +1144,11 @@ static int se_ioctl_setup_iobuf_handler(struct se_if_device_ctx *dev_ctx,
shared_mem->pos += round_up(io.length, 8u);
io.ele_addr = (u64)shared_mem->dma_addr + pos;
memset(shared_mem->ptr + pos, 0, io.length);
if (dev_ctx->priv->mu_mem.pos)
memset_io(shared_mem->ptr + pos, 0, io.length);
else
memset(shared_mem->ptr + pos, 0, io.length);
if ((io.flags & SE_IO_BUF_FLAGS_IS_INPUT) ||
(io.flags & SE_IO_BUF_FLAGS_IS_IN_OUT)) {
/*
@ -1479,6 +1589,13 @@ static int se_if_probe(struct platform_device *pdev)
priv->if_defs = &info->if_defs;
dev_set_drvdata(dev, priv);
if (info->se_if_early_init) {
/* start initializing ele fw */
ret = info->se_if_early_init(priv);
if (ret)
goto exit;
}
list_add_tail(&priv->priv_data, &priv_data_list);
ret = devm_add_action(dev, se_if_probe_cleanup, pdev);
@ -1501,6 +1618,12 @@ static int se_if_probe(struct platform_device *pdev)
if (ret)
goto exit;
if (info->mu_buff_size) {
/* TODO: to get func get_mu_buf(), part of imx-mailbox.c */
priv->mu_mem.ptr = get_mu_buf(priv->tx_chan);
priv->mu_mem.size = info->mu_buff_size;
priv->mu_mem.dma_addr = (u64)priv->mu_mem.ptr;
}
mutex_init(&priv->se_if_cmd_lock);
init_completion(&priv->waiting_rsp_clbk_hdl.done);
@ -1619,6 +1742,12 @@ static int se_suspend(struct device *dev)
int ret = 0;
se_rcv_msg_timeout = SE_RCV_MSG_DEFAULT_TIMEOUT;
if (priv->if_defs->se_if_type == SE_TYPE_ID_V2X_DBG) {
dev_err(dev, "V2X-FW: Suspend/resume not supported.");
return -EPERM;
}
load_fw = get_load_fw_instance(priv);
if (load_fw->imem_mgmt)

View File

@ -15,6 +15,7 @@
#define RES_STATUS(x) FIELD_GET(0x000000ff, x)
#define MAX_DATA_SIZE_PER_USER (65 * 1024)
#define MAX_NVM_MSG_LEN (256)
#define MESSAGING_VERSION_2 0x2
#define MESSAGING_VERSION_6 0x6
#define MESSAGING_VERSION_7 0x7
#define NODE_NAME "secure-enclave"
@ -130,6 +131,7 @@ struct se_if_priv {
struct mbox_client se_mb_cl;
struct mbox_chan *tx_chan, *rx_chan;
struct se_shared_mem mu_mem;
struct gen_pool *mem_pool;
const struct se_if_defines *if_defs;
struct se_lg_fl_info lg_fl_info;

View File

@ -0,0 +1,75 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* Copyright 2024 NXP
*/
#include <linux/types.h>
#include <linux/completion.h>
#include "ele_common.h"
#include "v2x_base_msg.h"
/*
* v2x_start_rng() - prepare and send the command to start
* initialization of the ELE RNG context
*
* returns: 0 on success.
*/
int v2x_start_rng(struct se_if_priv *priv)
{
struct se_api_msg *tx_msg __free(kfree) = NULL;
struct se_api_msg *rx_msg __free(kfree) = NULL;
int ret = 0;
if (!priv) {
ret = -EINVAL;
goto exit;
}
tx_msg = kzalloc(V2X_START_RNG_REQ_MSG_SZ, GFP_KERNEL);
if (!tx_msg) {
ret = -ENOMEM;
goto exit;
}
rx_msg = kzalloc(V2X_START_RNG_RSP_MSG_SZ, GFP_KERNEL);
if (!rx_msg) {
ret = -ENOMEM;
goto exit;
}
ret = se_fill_cmd_msg_hdr(priv,
(struct se_msg_hdr *)&tx_msg->header,
V2X_START_RNG_REQ,
V2X_START_RNG_REQ_MSG_SZ,
true);
if (ret)
goto exit;
ret = ele_msg_send_rcv(priv->priv_dev_ctx,
tx_msg,
V2X_START_RNG_REQ_MSG_SZ,
rx_msg,
V2X_START_RNG_RSP_MSG_SZ);
if (ret < 0)
goto exit;
ret = se_val_rsp_hdr_n_status(priv,
rx_msg,
V2X_START_RNG_REQ,
V2X_START_RNG_RSP_MSG_SZ,
true);
if (ret) {
/* Initialization in progress for:
* P-TRNG at bit 0
* S-TRNG at bit 1
* Any of the bit is set, it in progress.
*/
if (rx_msg->data[1] & 0x3)
goto exit;
ret = -1;
}
exit:
return ret;
}

View File

@ -0,0 +1,18 @@
/* SPDX-License-Identifier: GPL-2.0+ */
/*
* Copyright 2024 NXP
*
* Header file for the V2X Base API(s).
*/
#ifndef V2X_BASE_MSG_H
#define V2X_BASE_MSG_H
#include <linux/types.h>
#define V2X_START_RNG_REQ 0x0E
#define V2X_START_RNG_REQ_MSG_SZ 0x04
#define V2X_START_RNG_RSP_MSG_SZ 0x0C
int v2x_start_rng(struct se_if_priv *priv);
#endif

View File

@ -0,0 +1,90 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* Copyright 2024 NXP
*/
#include <linux/firmware/imx/se_api.h>
#include <uapi/linux/se_ioctl.h>
#include "ele_base_msg.h"
#include "ele_fw_api.h"
#include "v2x_base_msg.h"
#include "v2x_common.h"
static u32 v2x_fw_state;
#define V2X_FW_AUTH_DBG_COMPLETE 0x15
#define V2X_FW_AUTH_NORM_COMPLETE 0x13
static bool is_v2x_fw_running(u32 v2x_fw_state)
{
if (v2x_fw_state == V2X_FW_AUTH_DBG_COMPLETE ||
v2x_fw_state == V2X_FW_AUTH_NORM_COMPLETE)
return true;
return false;
}
int v2x_early_init(struct se_if_priv *priv)
{
struct se_if_priv *ele_priv;
int ret = 0;
if (!is_v2x_fw_running(v2x_fw_state)) {
ele_priv = imx_get_se_data_info(get_se_soc_id(priv), 0);
if (!ele_priv) {
ret = -EPERM;
goto exit;
}
ret = ele_v2x_fw_authenticate(ele_priv, V2X_FW_IMG_DDR_ADDR);
if (ret) {
dev_err(ele_priv->dev,
"failure: v2x fw loading.");
ret = -EPERM;
goto exit;
}
ret = ele_get_v2x_fw_state(ele_priv, &v2x_fw_state);
if (ret)
dev_warn(priv->dev, "Failed to fetch the v2x-fw-state via ELE.");
if (!is_v2x_fw_running(v2x_fw_state)) {
dev_err(priv->dev,
"failure: v2x fw state [0x%x]is not loaded.",
v2x_fw_state);
ret = -EPERM;
}
}
exit:
return ret;
}
int v2x_late_init(struct se_if_priv *priv)
{
int ret = 0;
if (priv->if_defs->se_if_type == SE_TYPE_ID_HSM) {
ret = ele_init_fw(priv);
if (ret) {
dev_err(priv->dev, "ELE INIT FW failed.");
ret = -EPERM;
goto exit;
}
if (ele_get_v2x_fw_state(priv, &v2x_fw_state)) {
dev_warn(priv->dev, "Failed to fetch the v2x-fw-state via ELE.");
v2x_fw_state = V2X_FW_STATE_UNKNOWN;
}
}
if (!is_v2x_fw_running(v2x_fw_state)) {
if (ele_v2x_fw_authenticate(priv, V2X_FW_IMG_DDR_ADDR))
dev_warn(priv->dev, "failure: v2x fw loading.");
if (ele_get_v2x_fw_state(priv, &v2x_fw_state)) {
dev_warn(priv->dev, "Failed to fetch the v2x-fw-state via ELE.");
v2x_fw_state = V2X_FW_STATE_UNKNOWN;
}
}
exit:
return ret;
}

View File

@ -0,0 +1,17 @@
/* SPDX-License-Identifier: GPL-2.0+ */
/*
* Copyright 2024 NXP
*/
#ifndef __V2X_COMMON_H__
#define __V2X_COMMON_H__
#include "se_ctrl.h"
#define V2X_FW_STATE_UNKNOWN 0x00
#define V2X_FW_STATE_RUNNING 0x15
int v2x_early_init(struct se_if_priv *priv);
int v2x_late_init(struct se_if_priv *priv);
#endif /*__V2X_COMMON_H__ */