mirror of
https://github.com/nxp-imx/linux-imx.git
synced 2026-01-27 12:35:36 +01:00
LF-13910-8: drivers: firmware: imx: add support for i.MX8DXL/QXP/QM
add support for i.MX8DXL/QXP/QM 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> Acked-by: Jason Liu <jason.hui.liu@nxp.com>
This commit is contained in:
parent
9e7d5cc9f6
commit
4faa6aeb8b
|
|
@ -49,6 +49,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, i.MX95),
|
||||
- SECO (for i.MX8DXL, i.MXQM, i.MXQXP),
|
||||
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.
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ 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 v2x_base_msg.o v2x_common.o
|
||||
obj-${CONFIG_IMX_SCMI_MISC_DRV} += sm-misc.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 seco_init.o
|
||||
obj-${CONFIG_IMX_SEC_ENCLAVE} += sec_enclave.o
|
||||
sec_enclave-${CONFIG_IMX_ELE_TRNG} += ele_trng.o
|
||||
|
|
|
|||
|
|
@ -31,12 +31,15 @@
|
|||
#include "ele_fw_api.h"
|
||||
#include "ele_trng.h"
|
||||
#include "se_ctrl.h"
|
||||
#include "seco_init.h"
|
||||
#include "v2x_base_msg.h"
|
||||
#include "v2x_common.h"
|
||||
|
||||
#define MAX_SOC_INFO_DATA_SZ 256
|
||||
#define MBOX_TX_NAME "tx"
|
||||
#define MBOX_RX_NAME "rx"
|
||||
#define MBOX_TXDB_NAME "txdb"
|
||||
#define MBOX_RXDB_NAME "rxdb"
|
||||
|
||||
#define SE_RCV_MSG_DEFAULT_TIMEOUT 5000
|
||||
#define SE_RCV_MSG_LONG_TIMEOUT 5000000
|
||||
|
|
@ -167,11 +170,9 @@ static struct se_if_node_info_list imx95_info = {
|
|||
.soc_id = SOC_ID_OF_IMX95,
|
||||
.soc_register = false,
|
||||
.se_fetch_soc_info = ele_fetch_soc_info,
|
||||
.load_hsm_fw = {
|
||||
.se_fw_img_nm = {
|
||||
.prim_fw_nm_in_rfs = NULL,
|
||||
.seco_fw_nm_in_rfs = NULL,
|
||||
.is_fw_loaded = true,
|
||||
.handle_susp_resm = false,
|
||||
},
|
||||
.info = {
|
||||
{
|
||||
|
|
@ -249,10 +250,150 @@ static struct se_if_node_info_list imx95_info = {
|
|||
},
|
||||
};
|
||||
|
||||
static struct se_if_node_info_list imx8dxl_info = {
|
||||
.num_mu = 7,
|
||||
.soc_id = SOC_ID_OF_IMX8DXL,
|
||||
.soc_register = false,
|
||||
.se_fetch_soc_info = seco_fetch_soc_info,
|
||||
.se_fw_img_nm = {
|
||||
.prim_fw_nm_in_rfs = NULL,
|
||||
.seco_fw_nm_in_rfs = NULL,
|
||||
},
|
||||
.info = {
|
||||
{
|
||||
.se_if_id = 0,
|
||||
.mu_buff_size = 0,
|
||||
.if_defs = {
|
||||
.se_if_type = SE_TYPE_ID_SHE,
|
||||
.se_instance_id = 0,
|
||||
.cmd_tag = 0x17,
|
||||
.rsp_tag = 0xe1,
|
||||
.success_tag = SECO_SUCCESS_IND,
|
||||
.base_api_ver = MESSAGING_VERSION_6,
|
||||
.fw_api_ver = MESSAGING_VERSION_7,
|
||||
},
|
||||
.reserved_dma_ranges = false,
|
||||
.start_rng = NULL,
|
||||
.init_trng = NULL,
|
||||
.se_if_early_init = imx_scu_init_fw,
|
||||
.se_if_late_init = NULL,
|
||||
},
|
||||
{
|
||||
.se_if_id = 1,
|
||||
.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 = SECO_SUCCESS_IND,
|
||||
.base_api_ver = MESSAGING_VERSION_6,
|
||||
.fw_api_ver = MESSAGING_VERSION_7,
|
||||
},
|
||||
.reserved_dma_ranges = false,
|
||||
.start_rng = NULL,
|
||||
.init_trng = NULL,
|
||||
.se_if_early_init = imx_scu_init_fw,
|
||||
.se_if_late_init = NULL,
|
||||
},
|
||||
{
|
||||
.se_if_id = 2,
|
||||
.mu_buff_size = 0,
|
||||
.if_defs = {
|
||||
.se_if_type = SE_TYPE_ID_V2X_SV,
|
||||
.se_instance_id = 0,
|
||||
.cmd_tag = 0x18,
|
||||
.rsp_tag = 0xe2,
|
||||
.success_tag = SECO_SUCCESS_IND,
|
||||
.base_api_ver = MESSAGING_VERSION_2,
|
||||
.fw_api_ver = MESSAGING_VERSION_7,
|
||||
},
|
||||
.reserved_dma_ranges = false,
|
||||
.start_rng = NULL,
|
||||
.init_trng = NULL,
|
||||
.se_if_early_init = imx_scu_init_fw,
|
||||
.se_if_late_init = NULL,
|
||||
},
|
||||
{
|
||||
.se_if_id = 3,
|
||||
.mu_buff_size = 0,
|
||||
.if_defs = {
|
||||
.se_if_type = SE_TYPE_ID_V2X_SV,
|
||||
.se_instance_id = 1,
|
||||
.cmd_tag = 0x19,
|
||||
.rsp_tag = 0xe3,
|
||||
.success_tag = SECO_SUCCESS_IND,
|
||||
.base_api_ver = MESSAGING_VERSION_2,
|
||||
.fw_api_ver = MESSAGING_VERSION_7,
|
||||
},
|
||||
.reserved_dma_ranges = false,
|
||||
.start_rng = NULL,
|
||||
.init_trng = NULL,
|
||||
.se_if_early_init = imx_scu_init_fw,
|
||||
.se_if_late_init = NULL,
|
||||
},
|
||||
{
|
||||
.se_if_id = 4,
|
||||
.mu_buff_size = 16,
|
||||
.if_defs = {
|
||||
.se_if_type = SE_TYPE_ID_V2X_SHE,
|
||||
.se_instance_id = 0,
|
||||
.cmd_tag = 0x1a,
|
||||
.rsp_tag = 0xe4,
|
||||
.success_tag = SECO_SUCCESS_IND,
|
||||
.base_api_ver = MESSAGING_VERSION_2,
|
||||
.fw_api_ver = MESSAGING_VERSION_7,
|
||||
},
|
||||
.reserved_dma_ranges = false,
|
||||
.start_rng = NULL,
|
||||
.init_trng = NULL,
|
||||
.se_if_early_init = imx_scu_init_fw,
|
||||
.se_if_late_init = NULL,
|
||||
},
|
||||
{
|
||||
.se_if_id = 5,
|
||||
.mu_buff_size = 0,
|
||||
.if_defs = {
|
||||
.se_if_type = SE_TYPE_ID_V2X_SG,
|
||||
.se_instance_id = 0,
|
||||
.cmd_tag = 0x1d,
|
||||
.rsp_tag = 0xe7,
|
||||
.success_tag = SECO_SUCCESS_IND,
|
||||
.base_api_ver = MESSAGING_VERSION_2,
|
||||
.fw_api_ver = MESSAGING_VERSION_7,
|
||||
},
|
||||
.reserved_dma_ranges = false,
|
||||
.start_rng = NULL,
|
||||
.init_trng = NULL,
|
||||
.se_if_early_init = imx_scu_init_fw,
|
||||
.se_if_late_init = NULL,
|
||||
},
|
||||
{
|
||||
.se_if_id = 6,
|
||||
.mu_buff_size = 0,
|
||||
.if_defs = {
|
||||
.se_if_type = SE_TYPE_ID_V2X_SG,
|
||||
.se_instance_id = 1,
|
||||
.cmd_tag = 0x1e,
|
||||
.rsp_tag = 0xe8,
|
||||
.success_tag = SECO_SUCCESS_IND,
|
||||
.base_api_ver = MESSAGING_VERSION_2,
|
||||
.fw_api_ver = MESSAGING_VERSION_7,
|
||||
},
|
||||
.reserved_dma_ranges = false,
|
||||
.start_rng = NULL,
|
||||
.init_trng = NULL,
|
||||
.se_if_early_init = imx_scu_init_fw,
|
||||
.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},
|
||||
{ .compatible = "fsl,imx8dxl-se", .data = (void *)&imx8dxl_info},
|
||||
{},
|
||||
};
|
||||
|
||||
|
|
@ -398,6 +539,9 @@ void *imx_get_se_data_info(u32 soc_id, u32 idx)
|
|||
info_list = &imx93_info; break;
|
||||
case SOC_ID_OF_IMX95:
|
||||
info_list = &imx95_info; break;
|
||||
case SOC_ID_OF_IMX8DXL:
|
||||
case SOC_ID_OF_IMX8QXP:
|
||||
info_list = &imx8dxl_info; break;
|
||||
default:
|
||||
return NULL;
|
||||
}
|
||||
|
|
@ -445,12 +589,20 @@ static int se_soc_info(struct se_if_priv *priv)
|
|||
dev_err(priv->dev, "Failed to fetch SoC Info.");
|
||||
return err;
|
||||
}
|
||||
if (info_list->soc_id == SOC_ID_OF_IMX8DXL) {
|
||||
struct seco_soc_info *soc_data = (void *)data;
|
||||
|
||||
s_info = (void *)data;
|
||||
var_se_info.board_type = 0;
|
||||
var_se_info.soc_id = info_list->soc_id;
|
||||
var_se_info.soc_rev = s_info->d_info.soc_rev;
|
||||
load_fw->imem.state = s_info->d_addn_info.imem_state;
|
||||
var_se_info.board_type = soc_data->board_type;
|
||||
var_se_info.soc_id = soc_data->soc_id;
|
||||
var_se_info.soc_rev = soc_data->soc_rev;
|
||||
} else {
|
||||
s_info = (void *)data;
|
||||
|
||||
var_se_info.board_type = 0;
|
||||
var_se_info.soc_id = info_list->soc_id;
|
||||
var_se_info.soc_rev = s_info->d_info.soc_rev;
|
||||
load_fw->imem.state = s_info->d_addn_info.imem_state;
|
||||
}
|
||||
} else {
|
||||
dev_err(priv->dev, "Failed to fetch SoC revision.");
|
||||
if (info_list->soc_register)
|
||||
|
|
@ -706,6 +858,15 @@ static int init_se_shared_mem(struct se_if_device_ctx *dev_ctx)
|
|||
if (!se_shared_mem_mgmt->non_secure_mem.ptr)
|
||||
return -ENOMEM;
|
||||
|
||||
if (priv->flags & SCU_MEM_CFG) {
|
||||
if (imx_scu_mem_access(dev_ctx)) {
|
||||
dev_err(dev_ctx->priv->dev,
|
||||
"%s: Failed to share access to shared memory\n",
|
||||
dev_ctx->devname);
|
||||
return -EPERM;
|
||||
}
|
||||
}
|
||||
|
||||
se_shared_mem_mgmt->non_secure_mem.size = MAX_DATA_SIZE_PER_USER;
|
||||
se_shared_mem_mgmt->non_secure_mem.pos = 0;
|
||||
|
||||
|
|
@ -1056,6 +1217,13 @@ static int se_ioctl_get_mu_info(struct se_if_device_ctx *dev_ctx,
|
|||
if_info.se_if_id = 0;
|
||||
if_info.interrupt_idx = 0;
|
||||
if_info.tz = 0;
|
||||
if (get_se_soc_id(priv) == SOC_ID_OF_IMX8DXL ||
|
||||
get_se_soc_id(priv) == SOC_ID_OF_IMX8QXP) {
|
||||
if_info.se_if_id = info->se_if_id + 1;
|
||||
if (priv->if_defs->se_if_type > SE_TYPE_ID_SHE)
|
||||
if_info.se_if_id++;
|
||||
}
|
||||
|
||||
if_info.did = info->se_if_did;
|
||||
if_info.cmd_tag = priv->if_defs->cmd_tag;
|
||||
if_info.rsp_tag = priv->if_defs->rsp_tag;
|
||||
|
|
@ -1118,10 +1286,18 @@ static int se_ioctl_setup_iobuf_handler(struct se_if_device_ctx *dev_ctx,
|
|||
}
|
||||
|
||||
/* Select the shared memory to be used for this buffer. */
|
||||
if (io.flags & SE_IO_BUF_FLAGS_USE_MU_BUF)
|
||||
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;
|
||||
} else {
|
||||
if ((io.flags & SE_IO_BUF_FLAGS_USE_SEC_MEM) &&
|
||||
(dev_ctx->priv->flags & SCU_MEM_CFG)) {
|
||||
/* App requires to use secure memory for this buffer.*/
|
||||
shared_mem = &dev_ctx->se_shared_mem_mgmt.secure_mem;
|
||||
} else {
|
||||
/* No specific requirement for this buffer. */
|
||||
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,
|
||||
|
|
@ -1144,6 +1320,14 @@ 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;
|
||||
|
||||
if (dev_ctx->priv->flags & SCU_MEM_CFG) {
|
||||
if ((io.flags & SE_IO_BUF_FLAGS_USE_SEC_MEM) &&
|
||||
!(io.flags & SE_IO_BUF_FLAGS_USE_SHORT_ADDR)) {
|
||||
/*Add base address to get full address.#TODO: Add API*/
|
||||
io.ele_addr += SECURE_RAM_BASE_ADDRESS_SCU;
|
||||
}
|
||||
}
|
||||
|
||||
if (dev_ctx->priv->mu_mem.pos)
|
||||
memset_io(shared_mem->ptr + pos, 0, io.length);
|
||||
else
|
||||
|
|
@ -1210,6 +1394,69 @@ exit:
|
|||
return err;
|
||||
}
|
||||
|
||||
/* Configure the shared memory according to user config */
|
||||
static int se_ioctl_shared_mem_cfg_handler(struct file *fp,
|
||||
struct se_if_device_ctx *dev_ctx,
|
||||
unsigned long arg)
|
||||
{
|
||||
struct se_ioctl_shared_mem_cfg cfg;
|
||||
int err = -EINVAL;
|
||||
|
||||
/* Check if not already configured. */
|
||||
if (dev_ctx->se_shared_mem_mgmt.secure_mem.dma_addr != 0u) {
|
||||
dev_err(dev_ctx->priv->dev, "Shared memory not configured\n");
|
||||
return err;
|
||||
}
|
||||
|
||||
err = (int)copy_from_user(&cfg, (u8 *)arg, sizeof(cfg));
|
||||
if (err) {
|
||||
dev_err(dev_ctx->priv->dev, "Fail copy memory config\n");
|
||||
err = -EFAULT;
|
||||
return err;
|
||||
}
|
||||
|
||||
dev_dbg(dev_ctx->priv->dev, "cfg offset: %u(%d)\n", cfg.base_offset, cfg.size);
|
||||
|
||||
err = imx_scu_sec_mem_cfg(fp, cfg.base_offset, cfg.size);
|
||||
if (err) {
|
||||
dev_err(dev_ctx->priv->dev, "Failt to map memory\n");
|
||||
err = -ENOMEM;
|
||||
return err;
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static int se_ioctl_signed_msg_handler(struct file *fp,
|
||||
struct se_if_device_ctx *dev_ctx,
|
||||
unsigned long arg)
|
||||
{
|
||||
struct se_ioctl_signed_message msg;
|
||||
int err;
|
||||
|
||||
err = copy_from_user(&msg, (u8 *)arg, sizeof(msg));
|
||||
if (err) {
|
||||
dev_err(dev_ctx->priv->dev, "Failed to copy from user: %d\n", err);
|
||||
return -EFAULT;
|
||||
}
|
||||
|
||||
err = imx_scu_signed_msg(fp, msg.message, msg.msg_size, &msg.error_code);
|
||||
if (err) {
|
||||
dev_err(dev_ctx->priv->dev,
|
||||
"Failed to send signed message: %d\n",
|
||||
err);
|
||||
return err;
|
||||
}
|
||||
|
||||
err = copy_to_user((u8 *)arg, &msg, sizeof(msg));
|
||||
if (err) {
|
||||
dev_err(dev_ctx->priv->dev, "Failed to copy to user: %d\n", err);
|
||||
return -EFAULT;
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
/*
|
||||
* File operations for user-space
|
||||
*/
|
||||
|
|
@ -1438,6 +1685,18 @@ static long se_ioctl(struct file *fp, unsigned int cmd, unsigned long arg)
|
|||
case SE_IOCTL_CMD_SEND_RCV_RSP:
|
||||
err = se_ioctl_cmd_snd_rcv_rsp_handler(dev_ctx, arg);
|
||||
break;
|
||||
case SE_IOCTL_SHARED_BUF_CFG:
|
||||
if (priv->flags & SCU_MEM_CFG)
|
||||
err = se_ioctl_shared_mem_cfg_handler(fp, dev_ctx, arg);
|
||||
else
|
||||
err = -EPERM;
|
||||
break;
|
||||
case SE_IOCTL_SIGNED_MESSAGE:
|
||||
if (priv->flags & SCU_SIGNED_MSG_CFG)
|
||||
err = se_ioctl_signed_msg_handler(fp, dev_ctx, arg);
|
||||
else
|
||||
err = -EPERM;
|
||||
break;
|
||||
default:
|
||||
err = -EINVAL;
|
||||
dev_dbg(priv->dev,
|
||||
|
|
@ -1608,13 +1867,18 @@ static int se_if_probe(struct platform_device *pdev)
|
|||
priv->se_mb_cl.knows_txdone = true;
|
||||
priv->se_mb_cl.rx_callback = se_if_rx_callback;
|
||||
|
||||
ret = se_if_request_channel(dev, &priv->tx_chan, &priv->se_mb_cl,
|
||||
MBOX_TX_NAME);
|
||||
ret = se_if_request_channel(dev, &priv->tx_chan,
|
||||
&priv->se_mb_cl,
|
||||
(info_list->soc_id == SOC_ID_OF_IMX8DXL) ?
|
||||
MBOX_TXDB_NAME : MBOX_TX_NAME);
|
||||
if (ret)
|
||||
goto exit;
|
||||
|
||||
ret = se_if_request_channel(dev, &priv->rx_chan,
|
||||
&priv->se_mb_cl, MBOX_RX_NAME);
|
||||
ret = se_if_request_channel(dev,
|
||||
&priv->rx_chan,
|
||||
&priv->se_mb_cl,
|
||||
(info_list->soc_id == SOC_ID_OF_IMX8DXL) ?
|
||||
MBOX_RXDB_NAME : MBOX_RX_NAME);
|
||||
if (ret)
|
||||
goto exit;
|
||||
|
||||
|
|
|
|||
|
|
@ -131,11 +131,14 @@ struct se_if_priv {
|
|||
struct mbox_client se_mb_cl;
|
||||
struct mbox_chan *tx_chan, *rx_chan;
|
||||
|
||||
u32 flags;
|
||||
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;
|
||||
|
||||
struct imx_sc_ipc *ipc_scu;
|
||||
u8 part_owner;
|
||||
struct se_if_device_ctx *priv_dev_ctx;
|
||||
struct list_head dev_ctx_list;
|
||||
u32 active_devctx_count;
|
||||
|
|
@ -147,7 +150,7 @@ struct se_if_priv {
|
|||
#define SE_DUMP_MU_RCV_BUFS 2
|
||||
#define SE_DUMP_KDEBUG_BUFS 3
|
||||
|
||||
uint32_t get_se_soc_id(struct se_if_priv *priv);
|
||||
u32 get_se_soc_id(struct se_if_priv *priv);
|
||||
int se_dump_to_logfl(struct se_if_device_ctx *dev_ctx,
|
||||
u8 caller_type, int buf_size,
|
||||
const char *buf, ...);
|
||||
|
|
|
|||
262
drivers/firmware/imx/seco_init.c
Normal file
262
drivers/firmware/imx/seco_init.c
Normal file
|
|
@ -0,0 +1,262 @@
|
|||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/*
|
||||
* Copyright 2024 NXP
|
||||
*
|
||||
* File containing client-side RPC functions for the SECO service. These
|
||||
* function are ported to clients that communicate to the SC.
|
||||
*/
|
||||
|
||||
#include <linux/firmware/imx/ipc.h>
|
||||
#include <linux/firmware/imx/se_api.h>
|
||||
#include <linux/firmware/imx/svc/rm.h>
|
||||
#include <linux/nvmem-consumer.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/sys_soc.h>
|
||||
#include <uapi/linux/se_ioctl.h>
|
||||
|
||||
#include "seco_init.h"
|
||||
|
||||
static const struct soc_device_attribute soc_info_matches[] = {
|
||||
{ .soc_id = "i.MX8DXL",
|
||||
.revision = "1.1",
|
||||
.data = &(struct seco_soc_info) {.soc_id = SOC_ID_OF_IMX8DXL, .soc_rev = SOC_REV_A1,}
|
||||
},
|
||||
{ .soc_id = "i.MX8DXL",
|
||||
.revision = "1.2",
|
||||
.data = &(struct seco_soc_info) {.soc_id = SOC_ID_OF_IMX8DXL, .soc_rev = SOC_REV_B0,}
|
||||
},
|
||||
{ .soc_id = "i.MX8QXP",
|
||||
.revision = "1.1",
|
||||
.data = &(struct seco_soc_info) {.soc_id = SOC_ID_OF_IMX8QXP, .soc_rev = SOC_REV_B0,}
|
||||
},
|
||||
{ .soc_id = "i.MX8QXP",
|
||||
.revision = "1.2",
|
||||
.data = &(struct seco_soc_info) {.soc_id = SOC_ID_OF_IMX8QXP, .soc_rev = SOC_REV_C0,}
|
||||
},
|
||||
{ .soc_id = "i.MX8QM",
|
||||
.revision = "1.1",
|
||||
.data = &(struct seco_soc_info) {.soc_id = SOC_ID_OF_IMX8QM, .soc_rev = SOC_REV_B0,}
|
||||
},
|
||||
{ .soc_id = "i.MX8QM",
|
||||
.revision = "1.2",
|
||||
.data = &(struct seco_soc_info) {.soc_id = SOC_ID_OF_IMX8QM, .soc_rev = SOC_REV_C0,}
|
||||
},
|
||||
{ }
|
||||
};
|
||||
|
||||
static int read_fuse(struct se_if_priv *priv, u32 id, u32 *value, u8 mul)
|
||||
{
|
||||
struct nvmem_device *nvmem;
|
||||
u32 size_to_read = mul * sizeof(u32);
|
||||
struct device_node *np;
|
||||
int ret = 0;
|
||||
|
||||
np = priv->dev->of_node;
|
||||
if (!of_get_property(np, "nvmem", NULL))
|
||||
return -EPERM;
|
||||
|
||||
nvmem = devm_nvmem_device_get(priv->dev, NULL);
|
||||
if (IS_ERR(nvmem)) {
|
||||
ret = PTR_ERR(nvmem);
|
||||
|
||||
if (ret != -EPROBE_DEFER)
|
||||
dev_err(priv->dev, "Failed to retrieve nvmem node\n");
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = nvmem_device_read(nvmem, id, size_to_read, value);
|
||||
if (ret < 0) {
|
||||
dev_err(priv->dev, "Failed to read fuse %d: %d\n", id, ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (ret != size_to_read) {
|
||||
dev_err(priv->dev, "Read only %d instead of %d\n", ret,
|
||||
size_to_read);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
dev_dbg(priv->dev, "FUSE value 0x%x 0x%x 0x%x 0x%x\n",
|
||||
value[0], value[1],
|
||||
value[2], value[3]);
|
||||
|
||||
devm_nvmem_device_put(priv->dev, nvmem);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* function to fetch SoC revision on the SECO platform */
|
||||
int seco_fetch_soc_info(struct se_if_priv *priv, void *data)
|
||||
{
|
||||
struct seco_soc_info *soc_data = data;
|
||||
const struct soc_device_attribute *imx_soc_match;
|
||||
u32 fuse_val[4] = {0xFF};
|
||||
int err = 0;
|
||||
|
||||
imx_soc_match = soc_device_match(soc_info_matches);
|
||||
if (!imx_soc_match || !imx_soc_match->data) {
|
||||
err = -EINVAL;
|
||||
goto exit;
|
||||
}
|
||||
err = read_fuse(priv, 8, (u32 *)&fuse_val, 4);
|
||||
if (err) {
|
||||
dev_err(priv->dev, "Fail to read FIPS fuse\n");
|
||||
return err;
|
||||
}
|
||||
|
||||
if (fuse_val[2] & SECO_NON_FIPS)
|
||||
soc_data->board_type = IMX8DXL_DL1;
|
||||
else if (fuse_val[0] & V2X_NON_FIPS)
|
||||
soc_data->board_type = IMX8DXL_DL3;
|
||||
else if (!fuse_val[0] && !fuse_val[2])
|
||||
soc_data->board_type = IMX8DXL_DL2;
|
||||
|
||||
soc_data->soc_id = ((const struct seco_soc_info *)imx_soc_match->data)->soc_id;
|
||||
soc_data->soc_rev = ((const struct seco_soc_info *)imx_soc_match->data)->soc_rev;
|
||||
|
||||
exit:
|
||||
return err;
|
||||
}
|
||||
|
||||
int imx_scu_init_fw(struct se_if_priv *priv)
|
||||
{
|
||||
int ret;
|
||||
|
||||
if (!priv) {
|
||||
ret = -EINVAL;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
ret = imx_scu_get_handle(&priv->ipc_scu);
|
||||
if (ret) {
|
||||
dev_err(priv->dev, "Fail to retrieve IPC handle\n");
|
||||
goto exit;
|
||||
}
|
||||
|
||||
ret = imx_sc_rm_get_resource_owner(priv->ipc_scu, IMX_SC_R_SECO, &priv->part_owner);
|
||||
if (ret) {
|
||||
dev_err(priv->dev, "Fail get owner of SECO resource\n");
|
||||
goto exit;
|
||||
}
|
||||
|
||||
if (!ret) {
|
||||
priv->flags |= SCU_MEM_CFG;
|
||||
|
||||
if (get_se_soc_id(priv) == SOC_ID_OF_IMX8DXL &&
|
||||
(priv->if_defs->se_if_type == SE_TYPE_ID_SHE ||
|
||||
priv->if_defs->se_if_type == SE_TYPE_ID_HSM))
|
||||
priv->flags |= SCU_SIGNED_MSG_CFG;
|
||||
}
|
||||
exit:
|
||||
return ret;
|
||||
}
|
||||
|
||||
int imx_scu_sec_mem_cfg(struct file *fp, u32 offset, u32 size)
|
||||
{
|
||||
struct se_if_device_ctx *dev_ctx = fp->private_data;
|
||||
u64 high_boundary;
|
||||
int ret = 0;
|
||||
|
||||
high_boundary = offset;
|
||||
if (high_boundary > SECURE_RAM_SIZE) {
|
||||
dev_err(dev_ctx->priv->dev, "base offset is over secure memory\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
high_boundary += size;
|
||||
if (high_boundary > SECURE_RAM_SIZE) {
|
||||
dev_err(dev_ctx->priv->dev, "total memory is over secure memory\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
dev_ctx->se_shared_mem_mgmt.secure_mem.dma_addr = (dma_addr_t)offset;
|
||||
dev_ctx->se_shared_mem_mgmt.secure_mem.size = size;
|
||||
dev_ctx->se_shared_mem_mgmt.secure_mem.pos = 0;
|
||||
dev_ctx->se_shared_mem_mgmt.secure_mem.ptr =
|
||||
devm_ioremap(dev_ctx->priv->dev,
|
||||
(phys_addr_t)(SECURE_RAM_BASE_ADDRESS +
|
||||
(u64)dev_ctx->se_shared_mem_mgmt.secure_mem.dma_addr),
|
||||
dev_ctx->se_shared_mem_mgmt.secure_mem.size);
|
||||
if (!dev_ctx->se_shared_mem_mgmt.secure_mem.ptr) {
|
||||
dev_err(dev_ctx->priv->dev, "Failed to map secure memory\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int imx_scu_mem_access(struct se_if_device_ctx *dev_ctx)
|
||||
{
|
||||
struct se_if_priv *priv = dev_ctx->priv;
|
||||
u8 mr;
|
||||
u64 addr;
|
||||
int ret;
|
||||
|
||||
addr = dev_ctx->se_shared_mem_mgmt.non_secure_mem.dma_addr;
|
||||
|
||||
ret = imx_sc_rm_find_memreg(priv->ipc_scu,
|
||||
&mr,
|
||||
addr,
|
||||
addr + MAX_DATA_SIZE_PER_USER);
|
||||
if (ret) {
|
||||
dev_err(dev_ctx->priv->dev,
|
||||
"%s: Fail find memreg\n", dev_ctx->devname);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = imx_sc_rm_set_memreg_permissions(priv->ipc_scu, mr,
|
||||
priv->part_owner,
|
||||
IMX_SC_RM_PERM_FULL);
|
||||
if (ret) {
|
||||
dev_err(dev_ctx->priv->dev,
|
||||
"%s: Fail set permission for resource\n",
|
||||
dev_ctx->devname);
|
||||
return ret;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int imx_scu_signed_msg(struct file *fp,
|
||||
u8 *msg,
|
||||
u32 size,
|
||||
u32 *error)
|
||||
{
|
||||
struct se_if_device_ctx *dev_ctx = fp->private_data;
|
||||
struct se_if_priv *priv = dev_ctx->priv;
|
||||
struct se_shared_mem *shared_mem = &dev_ctx->se_shared_mem_mgmt.non_secure_mem;
|
||||
int err;
|
||||
u64 addr;
|
||||
u32 pos;
|
||||
|
||||
/* Check there is enough space in the shared memory. */
|
||||
if (size >= shared_mem->size - shared_mem->pos) {
|
||||
dev_err(dev_ctx->priv->dev,
|
||||
"Not enough mem: %d left, %d required\n",
|
||||
shared_mem->size - shared_mem->pos, size);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
/* Allocate space in shared memory. 8 bytes aligned. */
|
||||
pos = shared_mem->pos;
|
||||
|
||||
/* get physical address from the pos */
|
||||
addr = (u64)shared_mem->dma_addr + pos;
|
||||
|
||||
/* copy signed message from user space to this allocated buffer */
|
||||
err = copy_from_user(shared_mem->ptr + pos, msg, size);
|
||||
if (err) {
|
||||
dev_err(dev_ctx->priv->dev,
|
||||
"Failed to signed message from user: %d\n",
|
||||
err);
|
||||
return -EFAULT;
|
||||
}
|
||||
|
||||
*error = imx_sc_seco_sab_msg(priv->ipc_scu, addr);
|
||||
err = *error;
|
||||
if (err)
|
||||
dev_err(dev_ctx->priv->dev, "Failt to send signed message\n");
|
||||
|
||||
return err;
|
||||
}
|
||||
44
drivers/firmware/imx/seco_init.h
Normal file
44
drivers/firmware/imx/seco_init.h
Normal file
|
|
@ -0,0 +1,44 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0+ */
|
||||
/*
|
||||
* Copyright 2024 NXP
|
||||
*/
|
||||
|
||||
#ifndef SECO_H
|
||||
#define SECO_H
|
||||
|
||||
#include "se_ctrl.h"
|
||||
|
||||
#define SCU_MEM_CFG BIT(1)
|
||||
#define SCU_SIGNED_MSG_CFG BIT(2)
|
||||
#define SECO_SUCCESS_IND 0x00
|
||||
|
||||
#define SOC_REV_A1 0xA100
|
||||
#define SOC_REV_B0 0xB000
|
||||
#define SOC_REV_C0 0xC000
|
||||
|
||||
#define SECURE_RAM_BASE_ADDRESS (0x31800000ULL)
|
||||
#define SECURE_RAM_BASE_ADDRESS_SCU (0x20800000u)
|
||||
#define SECURE_RAM_SIZE (0x10000ULL)
|
||||
|
||||
#define V2X_NON_FIPS 0x00000c00
|
||||
#define SECO_NON_FIPS 0x00000018
|
||||
|
||||
#define IMX8DXL_DL1 0x1
|
||||
#define IMX8DXL_DL2 0x2
|
||||
#define IMX8DXL_DL3 0x4
|
||||
|
||||
struct seco_soc_info {
|
||||
u16 soc_id;
|
||||
u16 soc_rev;
|
||||
u16 board_type;
|
||||
};
|
||||
|
||||
int seco_fetch_soc_info(struct se_if_priv *priv, void *data);
|
||||
int imx_scu_init_fw(struct se_if_priv *priv);
|
||||
int imx_scu_sec_mem_cfg(struct file *fp, u32 offset, u32 size);
|
||||
int imx_scu_mem_access(struct se_if_device_ctx *dev_ctx);
|
||||
int imx_scu_signed_msg(struct file *fp,
|
||||
u8 *msg,
|
||||
u32 size,
|
||||
u32 *error);
|
||||
#endif
|
||||
|
|
@ -9,7 +9,11 @@
|
|||
#include <linux/types.h>
|
||||
|
||||
#define SOC_ID_OF_IMX8ULP 0x084D
|
||||
#define SOC_ID_OF_IMX8DXL 0xE
|
||||
#define SOC_ID_OF_IMX8QM 0x1
|
||||
#define SOC_ID_OF_IMX8QXP 0x2
|
||||
#define SOC_ID_OF_IMX93 0x9300
|
||||
#define SOC_ID_OF_IMX95 0x9500
|
||||
|
||||
#define OTP_UNIQ_ID 0x01
|
||||
#define OTFAD_CONFIG 0x2
|
||||
|
|
|
|||
|
|
@ -61,6 +61,13 @@ struct se_ioctl_cmd_snd_rcv_rsp_info {
|
|||
struct se_ioctl_get_soc_info {
|
||||
__u16 soc_id;
|
||||
__u16 soc_rev;
|
||||
__u8 board_type;
|
||||
};
|
||||
|
||||
struct se_ioctl_signed_message {
|
||||
__u8 *message;
|
||||
__u32 msg_size;
|
||||
__u32 error_code;
|
||||
};
|
||||
|
||||
/* IO Buffer Flags */
|
||||
|
|
@ -68,6 +75,7 @@ struct se_ioctl_get_soc_info {
|
|||
#define SE_IO_BUF_FLAGS_IS_INPUT (0x01u)
|
||||
#define SE_IO_BUF_FLAGS_USE_SEC_MEM (0x02u)
|
||||
#define SE_IO_BUF_FLAGS_USE_SHORT_ADDR (0x04u)
|
||||
#define SE_IO_BUF_FLAGS_USE_MU_BUF (0x08u)
|
||||
#define SE_IO_BUF_FLAGS_IS_IN_OUT (0x10u)
|
||||
|
||||
/* IOCTLS */
|
||||
|
|
@ -80,6 +88,11 @@ struct se_ioctl_get_soc_info {
|
|||
*/
|
||||
#define SE_IOCTL_ENABLE_CMD_RCV _IO(SE_IOCTL, 0x01)
|
||||
|
||||
/*
|
||||
* ioctl to get configure the SCU shared buffer.
|
||||
*/
|
||||
#define SE_IOCTL_SHARED_BUF_CFG _IOW(SE_IOCTL, 0x02, \
|
||||
struct se_ioctl_shared_mem_cfg)
|
||||
/*
|
||||
* ioctl to get the buffer allocated from the memory, which is shared
|
||||
* between kernel and FW.
|
||||
|
|
@ -99,6 +112,13 @@ struct se_ioctl_get_soc_info {
|
|||
*/
|
||||
#define SE_IOCTL_GET_MU_INFO _IOR(SE_IOCTL, 0x04, \
|
||||
struct se_ioctl_get_if_info)
|
||||
|
||||
/*
|
||||
* ioctl to send signed message to SE.
|
||||
*/
|
||||
#define SE_IOCTL_SIGNED_MESSAGE _IOR(SE_IOCTL, 0x05, \
|
||||
struct se_ioctl_signed_message)
|
||||
|
||||
/*
|
||||
* ioctl to get SoC Info from user-space.
|
||||
*/
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user