Skip to content

Commit

Permalink
LF-12620 firmware: se_fw: Fix 8ULP iMEM issue when RTD is power down
Browse files Browse the repository at this point in the history
When RTD is power down, 64kB over the 96kB of ELE FW RAM are lost and
must be restored at resume. However when kernel (APD) is poweroff,
current implementation does not restore the ELE RAM, so cause failure
when trying to load externd FW.

To fix the issue, this patch checks the iMEM state from ELE get info API
to determine loading extend FW or restore iMEM. It also saves ELE iMEM RAM
to file on rootfs at ELE driver probe and resume.

Signed-off-by: Ye Li <[email protected]>
Reviewed-by: Pankaj Gupta <[email protected]>
Tested-by: Jacky Bai <[email protected]>
Acked-by: Jason Liu <[email protected]>
  • Loading branch information
Ye Li authored and Jason Liu committed Jun 7, 2024
1 parent da4e1bb commit b586a52
Show file tree
Hide file tree
Showing 2 changed files with 183 additions and 15 deletions.
197 changes: 182 additions & 15 deletions drivers/firmware/imx/se_fw.c
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
#include <linux/slab.h>
#include <linux/string.h>
#include <linux/sys_soc.h>
#include <linux/fs_struct.h>

#include "ele_common.h"
#include "ele_fw_api.h"
Expand Down Expand Up @@ -70,7 +71,9 @@ struct imx_info {
int (*start_rng)(struct device *dev);
bool enable_ele_trng;
bool imem_mgmt;
bool imem_restore;
uint8_t *fw_name_in_rfs;
uint8_t *imem_save_rfs;
};

struct imx_info_list {
Expand Down Expand Up @@ -111,6 +114,7 @@ static const struct imx_info_list imx8ulp_info = {
.mu_buff_size = 0,
.fw_name_in_rfs = IMX_ELE_FW_DIR\
"mx8ulpa2ext-ahab-container.img",
.imem_save_rfs = IMX_ELE_FW_DIR"mx8ulp-imem.img",
},
},
};
Expand Down Expand Up @@ -143,6 +147,7 @@ static const struct imx_info_list imx93_info = {
.imem_mgmt = false,
.mu_buff_size = 0,
.fw_name_in_rfs = NULL,
.imem_save_rfs = NULL,
},
},
};
Expand Down Expand Up @@ -175,6 +180,7 @@ static const struct imx_info_list imx8dxl_info = {
.imem_mgmt = false,
.mu_buff_size = 0,
.fw_name_in_rfs = NULL,
.imem_save_rfs = NULL,
},
{
.pdev_name = {"se-fw2"},
Expand All @@ -200,6 +206,7 @@ static const struct imx_info_list imx8dxl_info = {
.imem_mgmt = false,
.mu_buff_size = 0,
.fw_name_in_rfs = NULL,
.imem_save_rfs = NULL,
},
{
.pdev_name = {"v2x-sv0"},
Expand All @@ -225,6 +232,7 @@ static const struct imx_info_list imx8dxl_info = {
.imem_mgmt = false,
.mu_buff_size = 0,
.fw_name_in_rfs = NULL,
.imem_save_rfs = NULL,
},
{
.pdev_name = {"v2x-sv1"},
Expand All @@ -250,6 +258,7 @@ static const struct imx_info_list imx8dxl_info = {
.imem_mgmt = false,
.mu_buff_size = 0,
.fw_name_in_rfs = NULL,
.imem_save_rfs = NULL,
},
{
.pdev_name = {"v2x-she"},
Expand All @@ -275,6 +284,7 @@ static const struct imx_info_list imx8dxl_info = {
.imem_mgmt = false,
.mu_buff_size = 16,
.fw_name_in_rfs = NULL,
.imem_save_rfs = NULL,
},
{
.pdev_name = {"v2x-sg0"},
Expand All @@ -300,6 +310,7 @@ static const struct imx_info_list imx8dxl_info = {
.imem_mgmt = false,
.mu_buff_size = 0,
.fw_name_in_rfs = NULL,
.imem_save_rfs = NULL,
},
{
.pdev_name = {"v2x-sg1"},
Expand All @@ -325,6 +336,7 @@ static const struct imx_info_list imx8dxl_info = {
.imem_mgmt = false,
.mu_buff_size = 0,
.fw_name_in_rfs = NULL,
.imem_save_rfs = NULL,
},
},
};
Expand Down Expand Up @@ -357,6 +369,7 @@ static const struct imx_info_list imx95_info = {
.imem_mgmt = false,
.mu_buff_size = 0,
.fw_name_in_rfs = NULL,
.imem_save_rfs = NULL,
},
{
.pdev_name = {"v2x-fw0"},
Expand All @@ -382,6 +395,7 @@ static const struct imx_info_list imx95_info = {
.imem_mgmt = false,
.mu_buff_size = 0,
.fw_name_in_rfs = NULL,
.imem_save_rfs = NULL,
},
{
.pdev_name = {"v2x-fw4"},
Expand All @@ -407,6 +421,7 @@ static const struct imx_info_list imx95_info = {
.imem_mgmt = false,
.mu_buff_size = 16,
.fw_name_in_rfs = NULL,
.imem_save_rfs = NULL,
},
{
.pdev_name = {"v2x-fw6"},
Expand All @@ -432,6 +447,7 @@ static const struct imx_info_list imx95_info = {
.imem_mgmt = false,
.mu_buff_size = 256,
.fw_name_in_rfs = NULL,
.imem_save_rfs = NULL,
},
}
};
Expand Down Expand Up @@ -597,7 +613,7 @@ void free_phybuf_mem_pool(struct device *dev,
}

static int imx_fetch_soc_info(struct device *dev,
struct imx_info *info)
struct imx_info *info, u32 *state)
{
struct soc_device_attribute *attr;
struct soc_device *sdev = NULL;
Expand Down Expand Up @@ -670,6 +686,8 @@ static int imx_fetch_soc_info(struct device *dev,
"i.MX95");
break;
}

*state = get_info_data[39];
}

err = of_property_read_string(of_root, "model",
Expand Down Expand Up @@ -1691,6 +1709,44 @@ static int init_device_context(struct device *dev)
return ret;
}

static int se_save_imem_to_file(const char *path,
const void *buf, size_t buf_size)
{
struct file *file;
struct path root;
ssize_t wret;
loff_t offset = 0;

if (!path || !*path)
return -EINVAL;

task_lock(&init_task);
get_fs_root(init_task.fs, &root);
task_unlock(&init_task);

file = file_open_root(&root, path, O_CREAT | O_WRONLY, 0);
path_put(&root);
if (IS_ERR(file)) {
pr_err("open file %s failed\n", path);
return PTR_ERR(file);
}

wret = kernel_write(file, buf, buf_size, &offset);
if (wret < 0) {
pr_err("Error writing to imem file\n");
} else if (wret != buf_size) {
pr_err("Wrote only 0x%lx bytes of 0x%lx writing to imem file %s\n",
wret, buf_size, path);
}

wret = filp_close(file, NULL);
if (wret)
pr_err("Error %pe closing imem file\n",
ERR_PTR(wret));

return 0;
}

static void se_load_firmware(const struct firmware *fw, void *context)
{
struct ele_mu_priv *priv = context;
Expand Down Expand Up @@ -1743,6 +1799,81 @@ static void se_load_firmware(const struct firmware *fw, void *context)
ele_fw_phyaddr);

release_firmware(fw);

if (info->imem_mgmt && info->imem_save_rfs) {
priv->imem.size = save_imem(priv->dev);
se_save_imem_to_file(info->imem_save_rfs, priv->imem.buf, priv->imem.size);
}
}

static void se_load_imem_file(const struct firmware *fw, void *context)
{
struct ele_mu_priv *priv = context;
const struct imx_info *info = priv->info;

if (!fw) {
if (priv->fw_fail)
dev_dbg(priv->dev,
"External iMEM FW not found, using ROM FW.\n");
else {
/*add a bit delay to wait for firmware priv released */
msleep(20);

/* Load firmware one more time if timeout */
request_firmware_nowait(THIS_MODULE,
FW_ACTION_UEVENT, info->imem_save_rfs,
priv->dev, GFP_KERNEL, priv,
se_load_imem_file);
priv->fw_fail++;
dev_dbg(priv->dev, "Value of retries = 0x%x\n",
priv->fw_fail);
}

return;
}

dev_dbg(priv->dev, "load imem file ok, size 0x%lx\n", fw->size);
memcpy(priv->imem.buf, fw->data, fw->size);
priv->imem.size = fw->size;

restore_imem(priv->dev, info->pool_name);
dev_dbg(priv->dev, "restore imem done\n");

release_firmware(fw);
}

static void se_save_imem_file(const struct firmware *fw, void *context)
{
struct ele_mu_priv *priv = context;
const struct imx_info *info = priv->info;

if (!fw) {
if (priv->fw_fail)
dev_dbg(priv->dev,
"External iMEM FW not found, using ROM FW.\n");
else {
/*add a bit delay to wait for firmware priv released */
msleep(20);

/* Load firmware one more time if timeout */
request_firmware_nowait(THIS_MODULE,
FW_ACTION_UEVENT, info->imem_save_rfs,
priv->dev, GFP_KERNEL, priv,
se_save_imem_file);
priv->fw_fail++;
dev_dbg(priv->dev, "Value of retries = 0x%x\n",
priv->fw_fail);
}
return;
}

dev_dbg(priv->dev, "check imem file ok, size 0x%lx\n", fw->size);
release_firmware(fw);

priv->imem.size = save_imem(priv->dev);
se_save_imem_to_file(info->imem_save_rfs, priv->imem.buf, priv->imem.size);

dev_dbg(priv->dev, "save imem file done\n");
}

static int se_fw_probe(struct platform_device *pdev)
Expand All @@ -1753,6 +1884,7 @@ static int se_fw_probe(struct platform_device *pdev)
struct imx_info *info = NULL;
int ret;
struct device_node *np;
u32 ele_state;

info = get_imx_info((struct imx_info_list *)of_id->data,
pdev->name, strlen(pdev->name) + 1);
Expand Down Expand Up @@ -1873,13 +2005,24 @@ static int se_fw_probe(struct platform_device *pdev)
}
}

ret = imx_fetch_soc_info(dev, info);
ret = imx_fetch_soc_info(dev, info, &ele_state);
if (ret) {
dev_err(dev,
"failed[%d] to register SoC device\n", ret);
goto exit;
}

if (((ele_state >> 16) & 0xFF) == 0xFE)
priv->imem_restore = true;
else if (((ele_state >> 16) & 0xFF) == 0xCA)
priv->imem_restore = false;
else {
dev_info(dev,
"Unknown state 0x%x\n", ele_state);
priv->imem_restore = false;
}
dev_info(dev, "ele_state 0x%x, imem_restore %d\n", ele_state, priv->imem_restore);

/* Assumed v2x_state_check is enabled for i.MX95 only. */
if (info->v2x_state_check) {
if (v2x_fw_state == V2X_FW_STATE_UNKNOWN &&
Expand All @@ -1900,17 +2043,6 @@ static int se_fw_probe(struct platform_device *pdev)
}
}

if (info->fw_name_in_rfs) {
ret = request_firmware_nowait(THIS_MODULE,
FW_ACTION_UEVENT,
info->fw_name_in_rfs,
dev, GFP_KERNEL, priv,
se_load_firmware);
if (ret)
dev_warn(dev, "Failed to get firmware [%s].\n",
info->fw_name_in_rfs);
}

/* start ele rng */
if (info->start_rng) {
ret = info->start_rng(dev);
Expand All @@ -1935,6 +2067,29 @@ static int se_fw_probe(struct platform_device *pdev)
ret = -ENOMEM;
goto exit;
}

if (priv->imem_restore && info->imem_save_rfs) {
ret = request_firmware_nowait(THIS_MODULE,
FW_ACTION_UEVENT,
info->imem_save_rfs,
dev, GFP_KERNEL, priv,
se_load_imem_file);
if (ret)
dev_warn(dev, "Failed to get imem firmware [%s].\n",
info->imem_save_rfs);
}

}

if (!priv->imem_restore && info->fw_name_in_rfs) {
ret = request_firmware_nowait(THIS_MODULE,
FW_ACTION_UEVENT,
info->fw_name_in_rfs,
dev, GFP_KERNEL, priv,
se_load_firmware);
if (ret)
dev_warn(dev, "Failed to get firmware [%s].\n",
info->fw_name_in_rfs);
}

if (info->max_dev_ctx) {
Expand Down Expand Up @@ -2011,13 +2166,25 @@ static int se_fw_resume(struct device *dev)
{
struct ele_mu_priv *priv = dev_get_drvdata(dev);
const struct imx_info *info = priv->info;
int i;
int i, ret;

for (i = 0; i < priv->max_dev_ctx; i++)
wake_up_interruptible(&priv->ctxs[i]->wq);

if (info && info->imem_mgmt)
if (info && info->imem_mgmt) {
restore_imem(dev, info->pool_name);
if (info->imem_save_rfs) {
priv->fw_fail = 0;
ret = request_firmware_nowait(THIS_MODULE,
FW_ACTION_UEVENT,
info->imem_save_rfs,
dev, GFP_KERNEL, priv,
se_save_imem_file);
if (ret)
dev_warn(dev, "Failed to get imem firmware [%s].\n",
info->imem_save_rfs);
}
}

return 0;
}
Expand Down
1 change: 1 addition & 0 deletions drivers/firmware/imx/se_fw.h
Original file line number Diff line number Diff line change
Expand Up @@ -154,6 +154,7 @@ struct ele_mu_priv {
struct perf_time_frame time_frame;
struct imx_sc_ipc *ipc_scu;
u8 part_owner;
bool imem_restore;
};

uint32_t get_se_soc_id(struct device *dev);
Expand Down

0 comments on commit b586a52

Please sign in to comment.