net: wwan: iosm: fw flashing support
Implements protocol for fw flashing and PSI injection for coredump collection. Signed-off-by: M Chetan Kumar <m.chetan.kumar@linux.intel.com> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
parent
4dcd183fbd
commit
b557347455
561
drivers/net/wwan/iosm/iosm_ipc_flash.c
Normal file
561
drivers/net/wwan/iosm/iosm_ipc_flash.c
Normal file
@ -0,0 +1,561 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
/*
|
||||
* Copyright (C) 2020-2021 Intel Corporation.
|
||||
*/
|
||||
|
||||
#include "iosm_ipc_coredump.h"
|
||||
#include "iosm_ipc_devlink.h"
|
||||
#include "iosm_ipc_flash.h"
|
||||
|
||||
/* This function will pack the data to be sent to the modem using the
|
||||
* payload, payload length and pack id
|
||||
*/
|
||||
static int ipc_flash_proc_format_ebl_pack(struct iosm_flash_data *flash_req,
|
||||
u32 pack_length, u16 pack_id,
|
||||
u8 *payload, u32 payload_length)
|
||||
{
|
||||
u16 checksum = pack_id;
|
||||
u32 i;
|
||||
|
||||
if (payload_length + IOSM_EBL_HEAD_SIZE > pack_length)
|
||||
return -EINVAL;
|
||||
|
||||
flash_req->pack_id = cpu_to_le16(pack_id);
|
||||
flash_req->msg_length = cpu_to_le32(payload_length);
|
||||
checksum += (payload_length >> IOSM_EBL_PAYL_SHIFT) +
|
||||
(payload_length & IOSM_EBL_CKSM);
|
||||
|
||||
for (i = 0; i < payload_length; i++)
|
||||
checksum += payload[i];
|
||||
|
||||
flash_req->checksum = cpu_to_le16(checksum);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* validate the response received from modem and
|
||||
* check the type of errors received
|
||||
*/
|
||||
static int ipc_flash_proc_check_ebl_rsp(void *hdr_rsp, void *payload_rsp)
|
||||
{
|
||||
struct iosm_ebl_error *err_info = payload_rsp;
|
||||
u16 *rsp_code = hdr_rsp;
|
||||
int res = 0;
|
||||
u32 i;
|
||||
|
||||
if (*rsp_code == IOSM_EBL_RSP_BUFF) {
|
||||
for (i = 0; i < IOSM_MAX_ERRORS; i++) {
|
||||
if (!err_info->error[i].error_code) {
|
||||
pr_err("EBL: error_class = %d, error_code = %d",
|
||||
err_info->error[i].error_class,
|
||||
err_info->error[i].error_code);
|
||||
}
|
||||
}
|
||||
res = -EINVAL;
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
/* Send data to the modem */
|
||||
static int ipc_flash_send_data(struct iosm_devlink *ipc_devlink, u32 size,
|
||||
u16 pack_id, u8 *payload, u32 payload_length)
|
||||
{
|
||||
struct iosm_flash_data flash_req;
|
||||
int ret;
|
||||
|
||||
ret = ipc_flash_proc_format_ebl_pack(&flash_req, size,
|
||||
pack_id, payload, payload_length);
|
||||
if (ret) {
|
||||
dev_err(ipc_devlink->dev, "EBL2 pack failed for pack_id:%d",
|
||||
pack_id);
|
||||
goto ipc_free_payload;
|
||||
}
|
||||
|
||||
ret = ipc_imem_sys_devlink_write(ipc_devlink, (u8 *)&flash_req,
|
||||
IOSM_EBL_HEAD_SIZE);
|
||||
if (ret) {
|
||||
dev_err(ipc_devlink->dev, "EBL Header write failed for Id:%x",
|
||||
pack_id);
|
||||
goto ipc_free_payload;
|
||||
}
|
||||
|
||||
ret = ipc_imem_sys_devlink_write(ipc_devlink, payload, payload_length);
|
||||
if (ret) {
|
||||
dev_err(ipc_devlink->dev, "EBL Payload write failed for Id:%x",
|
||||
pack_id);
|
||||
}
|
||||
|
||||
ipc_free_payload:
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Allocate flash channel and read LER data from modem */
|
||||
int ipc_flash_link_establish(struct iosm_imem *ipc_imem)
|
||||
{
|
||||
u8 ler_data[IOSM_LER_RSP_SIZE];
|
||||
u32 bytes_read;
|
||||
|
||||
/* Allocate channel for flashing/cd collection */
|
||||
ipc_imem->ipc_devlink->devlink_sio.channel =
|
||||
ipc_imem_sys_devlink_open(ipc_imem);
|
||||
|
||||
if (!ipc_imem->ipc_devlink->devlink_sio.channel)
|
||||
goto chl_open_fail;
|
||||
|
||||
if (ipc_imem_sys_devlink_read(ipc_imem->ipc_devlink, ler_data,
|
||||
IOSM_LER_RSP_SIZE, &bytes_read))
|
||||
goto devlink_read_fail;
|
||||
|
||||
if (bytes_read != IOSM_LER_RSP_SIZE)
|
||||
goto devlink_read_fail;
|
||||
return 0;
|
||||
|
||||
devlink_read_fail:
|
||||
ipc_imem_sys_devlink_close(ipc_imem->ipc_devlink);
|
||||
chl_open_fail:
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
/* Receive data from the modem */
|
||||
static int ipc_flash_receive_data(struct iosm_devlink *ipc_devlink, u32 size,
|
||||
u8 *mdm_rsp)
|
||||
{
|
||||
u8 mdm_rsp_hdr[IOSM_EBL_HEAD_SIZE];
|
||||
u32 bytes_read;
|
||||
int ret;
|
||||
|
||||
ret = ipc_imem_sys_devlink_read(ipc_devlink, mdm_rsp_hdr,
|
||||
IOSM_EBL_HEAD_SIZE, &bytes_read);
|
||||
if (ret) {
|
||||
dev_err(ipc_devlink->dev, "EBL rsp to read %d bytes failed",
|
||||
IOSM_EBL_HEAD_SIZE);
|
||||
goto ipc_flash_recv_err;
|
||||
}
|
||||
|
||||
if (bytes_read != IOSM_EBL_HEAD_SIZE) {
|
||||
ret = -EINVAL;
|
||||
goto ipc_flash_recv_err;
|
||||
}
|
||||
|
||||
ret = ipc_imem_sys_devlink_read(ipc_devlink, mdm_rsp, size,
|
||||
&bytes_read);
|
||||
if (ret) {
|
||||
dev_err(ipc_devlink->dev, "EBL rsp to read %d bytes failed",
|
||||
size);
|
||||
goto ipc_flash_recv_err;
|
||||
}
|
||||
|
||||
if (bytes_read != size) {
|
||||
ret = -EINVAL;
|
||||
goto ipc_flash_recv_err;
|
||||
}
|
||||
|
||||
ret = ipc_flash_proc_check_ebl_rsp(mdm_rsp_hdr + 2, mdm_rsp);
|
||||
|
||||
ipc_flash_recv_err:
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Function to send command to modem and receive response */
|
||||
static int ipc_flash_send_receive(struct iosm_devlink *ipc_devlink, u16 pack_id,
|
||||
u8 *payload, u32 payload_length, u8 *mdm_rsp)
|
||||
{
|
||||
size_t frame_len = IOSM_EBL_DW_PACK_SIZE;
|
||||
int ret;
|
||||
|
||||
if (pack_id == FLASH_SET_PROT_CONF)
|
||||
frame_len = IOSM_EBL_W_PACK_SIZE;
|
||||
|
||||
ret = ipc_flash_send_data(ipc_devlink, frame_len, pack_id, payload,
|
||||
payload_length);
|
||||
if (ret)
|
||||
goto ipc_flash_send_rcv;
|
||||
|
||||
ret = ipc_flash_receive_data(ipc_devlink,
|
||||
frame_len - IOSM_EBL_HEAD_SIZE, mdm_rsp);
|
||||
|
||||
ipc_flash_send_rcv:
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Set the capabilities for the EBL */
|
||||
int ipc_flash_boot_set_capabilities(struct iosm_devlink *ipc_devlink,
|
||||
u8 *mdm_rsp)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ipc_devlink->ebl_ctx.ebl_sw_info_version =
|
||||
ipc_devlink->ebl_ctx.m_ebl_resp[EBL_RSP_SW_INFO_VER];
|
||||
ipc_devlink->ebl_ctx.m_ebl_resp[EBL_SKIP_ERASE] = IOSM_CAP_NOT_ENHANCED;
|
||||
ipc_devlink->ebl_ctx.m_ebl_resp[EBL_SKIP_CRC] = IOSM_CAP_NOT_ENHANCED;
|
||||
|
||||
if (ipc_devlink->ebl_ctx.m_ebl_resp[EBL_CAPS_FLAG] &
|
||||
IOSM_CAP_USE_EXT_CAP) {
|
||||
if (ipc_devlink->param.erase_full_flash)
|
||||
ipc_devlink->ebl_ctx.m_ebl_resp[EBL_OOS_CONFIG] &=
|
||||
~((u8)IOSM_EXT_CAP_ERASE_ALL);
|
||||
else
|
||||
ipc_devlink->ebl_ctx.m_ebl_resp[EBL_OOS_CONFIG] &=
|
||||
~((u8)IOSM_EXT_CAP_COMMIT_ALL);
|
||||
ipc_devlink->ebl_ctx.m_ebl_resp[EBL_EXT_CAPS_HANDLED] =
|
||||
IOSM_CAP_USE_EXT_CAP;
|
||||
}
|
||||
|
||||
/* Write back the EBL capability to modem
|
||||
* Request Set Protcnf command
|
||||
*/
|
||||
ret = ipc_flash_send_receive(ipc_devlink, FLASH_SET_PROT_CONF,
|
||||
ipc_devlink->ebl_ctx.m_ebl_resp,
|
||||
IOSM_EBL_RSP_SIZE, mdm_rsp);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Read the SWID type and SWID value from the EBL */
|
||||
int ipc_flash_read_swid(struct iosm_devlink *ipc_devlink, u8 *mdm_rsp)
|
||||
{
|
||||
struct iosm_flash_msg_control cmd_msg;
|
||||
struct iosm_swid_table *swid;
|
||||
char ebl_swid[IOSM_SWID_STR];
|
||||
int ret;
|
||||
|
||||
if (ipc_devlink->ebl_ctx.ebl_sw_info_version !=
|
||||
IOSM_EXT_CAP_SWID_OOS_PACK)
|
||||
return -EINVAL;
|
||||
|
||||
cmd_msg.action = cpu_to_le32(FLASH_OOSC_ACTION_READ);
|
||||
cmd_msg.type = cpu_to_le32(FLASH_OOSC_TYPE_SWID_TABLE);
|
||||
cmd_msg.length = cpu_to_le32(IOSM_MSG_LEN_ARG);
|
||||
cmd_msg.arguments = cpu_to_le32(IOSM_MSG_LEN_ARG);
|
||||
|
||||
ret = ipc_flash_send_receive(ipc_devlink, FLASH_OOS_CONTROL,
|
||||
(u8 *)&cmd_msg, IOSM_MDM_SEND_16, mdm_rsp);
|
||||
if (ret)
|
||||
goto ipc_swid_err;
|
||||
|
||||
cmd_msg.action = cpu_to_le32(*((u32 *)mdm_rsp));
|
||||
|
||||
ret = ipc_flash_send_receive(ipc_devlink, FLASH_OOS_DATA_READ,
|
||||
(u8 *)&cmd_msg, IOSM_MDM_SEND_4, mdm_rsp);
|
||||
if (ret)
|
||||
goto ipc_swid_err;
|
||||
|
||||
swid = (struct iosm_swid_table *)mdm_rsp;
|
||||
dev_dbg(ipc_devlink->dev, "SWID %x RF_ENGINE_ID %x", swid->sw_id_val,
|
||||
swid->rf_engine_id_val);
|
||||
|
||||
snprintf(ebl_swid, sizeof(ebl_swid), "SWID: %x, RF_ENGINE_ID: %x",
|
||||
swid->sw_id_val, swid->rf_engine_id_val);
|
||||
|
||||
devlink_flash_update_status_notify(ipc_devlink->devlink_ctx, ebl_swid,
|
||||
NULL, 0, 0);
|
||||
ipc_swid_err:
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Function to check if full erase or conditional erase was successful */
|
||||
static int ipc_flash_erase_check(struct iosm_devlink *ipc_devlink, u8 *mdm_rsp)
|
||||
{
|
||||
int ret, count = 0;
|
||||
u16 mdm_rsp_data;
|
||||
|
||||
/* Request Flash Erase Check */
|
||||
do {
|
||||
mdm_rsp_data = IOSM_MDM_SEND_DATA;
|
||||
ret = ipc_flash_send_receive(ipc_devlink, FLASH_ERASE_CHECK,
|
||||
(u8 *)&mdm_rsp_data,
|
||||
IOSM_MDM_SEND_2, mdm_rsp);
|
||||
if (ret)
|
||||
goto ipc_erase_chk_err;
|
||||
|
||||
mdm_rsp_data = *((u16 *)mdm_rsp);
|
||||
if (mdm_rsp_data > IOSM_MDM_ERASE_RSP) {
|
||||
dev_err(ipc_devlink->dev,
|
||||
"Flash Erase Check resp wrong 0x%04X",
|
||||
mdm_rsp_data);
|
||||
ret = -EINVAL;
|
||||
goto ipc_erase_chk_err;
|
||||
}
|
||||
count++;
|
||||
msleep(IOSM_FLASH_ERASE_CHECK_INTERVAL);
|
||||
} while ((mdm_rsp_data != IOSM_MDM_ERASE_RSP) &&
|
||||
(count < (IOSM_FLASH_ERASE_CHECK_TIMEOUT /
|
||||
IOSM_FLASH_ERASE_CHECK_INTERVAL)));
|
||||
|
||||
if (mdm_rsp_data != IOSM_MDM_ERASE_RSP) {
|
||||
dev_err(ipc_devlink->dev, "Modem erase check timeout failure!");
|
||||
ret = -ETIMEDOUT;
|
||||
}
|
||||
|
||||
ipc_erase_chk_err:
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Full erase function which will erase the nand flash through EBL command */
|
||||
static int ipc_flash_full_erase(struct iosm_devlink *ipc_devlink, u8 *mdm_rsp)
|
||||
{
|
||||
u32 erase_address = IOSM_ERASE_START_ADDR;
|
||||
struct iosm_flash_msg_control cmd_msg;
|
||||
u32 erase_length = IOSM_ERASE_LEN;
|
||||
int ret;
|
||||
|
||||
dev_dbg(ipc_devlink->dev, "Erase full nand flash");
|
||||
cmd_msg.action = cpu_to_le32(FLASH_OOSC_ACTION_ERASE);
|
||||
cmd_msg.type = cpu_to_le32(FLASH_OOSC_TYPE_ALL_FLASH);
|
||||
cmd_msg.length = cpu_to_le32(erase_length);
|
||||
cmd_msg.arguments = cpu_to_le32(erase_address);
|
||||
|
||||
ret = ipc_flash_send_receive(ipc_devlink, FLASH_OOS_CONTROL,
|
||||
(unsigned char *)&cmd_msg,
|
||||
IOSM_MDM_SEND_16, mdm_rsp);
|
||||
if (ret)
|
||||
goto ipc_flash_erase_err;
|
||||
|
||||
ipc_devlink->param.erase_full_flash_done = IOSM_SET_FLAG;
|
||||
ret = ipc_flash_erase_check(ipc_devlink, mdm_rsp);
|
||||
|
||||
ipc_flash_erase_err:
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Logic for flashing all the Loadmaps available for individual fls file */
|
||||
static int ipc_flash_download_region(struct iosm_devlink *ipc_devlink,
|
||||
const struct firmware *fw, u8 *mdm_rsp)
|
||||
{
|
||||
__le32 reg_info[2]; /* 0th position region address, 1st position size */
|
||||
char *file_ptr;
|
||||
u32 rest_len;
|
||||
u32 raw_len;
|
||||
int ret;
|
||||
|
||||
file_ptr = (char *)fw->data;
|
||||
reg_info[0] = cpu_to_le32(ipc_devlink->param.address);
|
||||
|
||||
if (!ipc_devlink->param.erase_full_flash_done) {
|
||||
reg_info[1] = cpu_to_le32(ipc_devlink->param.address +
|
||||
fw->size - 2);
|
||||
ret = ipc_flash_send_receive(ipc_devlink, FLASH_ERASE_START,
|
||||
(u8 *)reg_info, IOSM_MDM_SEND_8,
|
||||
mdm_rsp);
|
||||
if (ret)
|
||||
goto dl_region_fail;
|
||||
|
||||
ret = ipc_flash_erase_check(ipc_devlink, mdm_rsp);
|
||||
if (ret)
|
||||
goto dl_region_fail;
|
||||
}
|
||||
|
||||
/* Request Flash Set Address */
|
||||
ret = ipc_flash_send_receive(ipc_devlink, FLASH_SET_ADDRESS,
|
||||
(u8 *)reg_info, IOSM_MDM_SEND_4, mdm_rsp);
|
||||
if (ret)
|
||||
goto dl_region_fail;
|
||||
|
||||
rest_len = fw->size;
|
||||
|
||||
/* Request Flash Write Raw Image */
|
||||
ret = ipc_flash_send_data(ipc_devlink, IOSM_EBL_DW_PACK_SIZE,
|
||||
FLASH_WRITE_IMAGE_RAW, (u8 *)&rest_len,
|
||||
IOSM_MDM_SEND_4);
|
||||
if (ret)
|
||||
goto dl_region_fail;
|
||||
|
||||
do {
|
||||
raw_len = (rest_len > IOSM_FLS_BUF_SIZE) ? IOSM_FLS_BUF_SIZE :
|
||||
rest_len;
|
||||
ret = ipc_imem_sys_devlink_write(ipc_devlink, file_ptr,
|
||||
raw_len);
|
||||
if (ret) {
|
||||
dev_err(ipc_devlink->dev, "Image write failed");
|
||||
goto dl_region_fail;
|
||||
}
|
||||
file_ptr += raw_len;
|
||||
rest_len -= raw_len;
|
||||
} while (rest_len);
|
||||
|
||||
ret = ipc_flash_receive_data(ipc_devlink, IOSM_EBL_DW_PAYL_SIZE,
|
||||
mdm_rsp);
|
||||
|
||||
dl_region_fail:
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Flash the individual fls files */
|
||||
int ipc_flash_send_fls(struct iosm_devlink *ipc_devlink,
|
||||
const struct firmware *fw, u8 *mdm_rsp)
|
||||
{
|
||||
u16 flash_cmd;
|
||||
int ret;
|
||||
|
||||
if (ipc_devlink->param.erase_full_flash) {
|
||||
ipc_devlink->param.erase_full_flash = false;
|
||||
ret = ipc_flash_full_erase(ipc_devlink, mdm_rsp);
|
||||
if (ret)
|
||||
goto ipc_flash_err;
|
||||
}
|
||||
|
||||
/* Request Sec Start */
|
||||
if (!ipc_devlink->param.download_region) {
|
||||
ret = ipc_flash_send_receive(ipc_devlink, FLASH_SEC_START,
|
||||
(u8 *)fw->data, fw->size, mdm_rsp);
|
||||
if (ret)
|
||||
goto ipc_flash_err;
|
||||
} else {
|
||||
/* Download regions */
|
||||
ipc_devlink->param.region_count -= IOSM_SET_FLAG;
|
||||
ret = ipc_flash_download_region(ipc_devlink, fw, mdm_rsp);
|
||||
if (ret)
|
||||
goto ipc_flash_err;
|
||||
|
||||
if (!ipc_devlink->param.region_count) {
|
||||
/* Request Sec End */
|
||||
flash_cmd = IOSM_MDM_SEND_DATA;
|
||||
ret = ipc_flash_send_receive(ipc_devlink, FLASH_SEC_END,
|
||||
(u8 *)&flash_cmd,
|
||||
IOSM_MDM_SEND_2, mdm_rsp);
|
||||
}
|
||||
}
|
||||
|
||||
ipc_flash_err:
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Inject RPSI */
|
||||
int ipc_flash_boot_psi(struct iosm_devlink *ipc_devlink,
|
||||
const struct firmware *fw)
|
||||
{
|
||||
u8 psi_ack_byte[IOSM_PSI_ACK], read_data[2];
|
||||
u32 bytes_read;
|
||||
u8 *psi_code;
|
||||
int ret;
|
||||
|
||||
dev_dbg(ipc_devlink->dev, "Boot transfer PSI");
|
||||
psi_code = kmemdup(fw->data, fw->size, GFP_KERNEL);
|
||||
if (!psi_code)
|
||||
return -ENOMEM;
|
||||
|
||||
ret = ipc_imem_sys_devlink_write(ipc_devlink, psi_code, fw->size);
|
||||
if (ret) {
|
||||
dev_err(ipc_devlink->dev, "RPSI Image write failed");
|
||||
goto ipc_flash_psi_free;
|
||||
}
|
||||
|
||||
ret = ipc_imem_sys_devlink_read(ipc_devlink, read_data,
|
||||
IOSM_LER_ACK_SIZE, &bytes_read);
|
||||
if (ret) {
|
||||
dev_err(ipc_devlink->dev, "ipc_devlink_sio_read ACK failed");
|
||||
goto ipc_flash_psi_free;
|
||||
}
|
||||
|
||||
if (bytes_read != IOSM_LER_ACK_SIZE) {
|
||||
ret = -EINVAL;
|
||||
goto ipc_flash_psi_free;
|
||||
}
|
||||
|
||||
snprintf(psi_ack_byte, sizeof(psi_ack_byte), "%x%x", read_data[0],
|
||||
read_data[1]);
|
||||
devlink_flash_update_status_notify(ipc_devlink->devlink_ctx,
|
||||
psi_ack_byte, "PSI ACK", 0, 0);
|
||||
|
||||
if (read_data[0] == 0x00 && read_data[1] == 0xCD) {
|
||||
dev_dbg(ipc_devlink->dev, "Coredump detected");
|
||||
ret = ipc_coredump_get_list(ipc_devlink,
|
||||
rpsi_cmd_coredump_start);
|
||||
if (ret)
|
||||
dev_err(ipc_devlink->dev, "Failed to get cd list");
|
||||
}
|
||||
|
||||
ipc_flash_psi_free:
|
||||
kfree(psi_code);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Inject EBL */
|
||||
int ipc_flash_boot_ebl(struct iosm_devlink *ipc_devlink,
|
||||
const struct firmware *fw)
|
||||
{
|
||||
u32 ebl_size = fw->size;
|
||||
u8 read_data[2];
|
||||
u32 bytes_read;
|
||||
int ret;
|
||||
|
||||
if (ipc_mmio_get_exec_stage(ipc_devlink->pcie->imem->mmio) !=
|
||||
IPC_MEM_EXEC_STAGE_PSI) {
|
||||
devlink_flash_update_status_notify(ipc_devlink->devlink_ctx,
|
||||
"Invalid execution stage",
|
||||
NULL, 0, 0);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
dev_dbg(ipc_devlink->dev, "Boot transfer EBL");
|
||||
ret = ipc_devlink_send_cmd(ipc_devlink, rpsi_cmd_code_ebl,
|
||||
IOSM_RPSI_LOAD_SIZE);
|
||||
if (ret) {
|
||||
dev_err(ipc_devlink->dev, "Sending rpsi_cmd_code_ebl failed");
|
||||
goto ipc_flash_ebl_err;
|
||||
}
|
||||
|
||||
ret = ipc_imem_sys_devlink_read(ipc_devlink, read_data, IOSM_READ_SIZE,
|
||||
&bytes_read);
|
||||
if (ret) {
|
||||
dev_err(ipc_devlink->dev, "rpsi_cmd_code_ebl read failed");
|
||||
goto ipc_flash_ebl_err;
|
||||
}
|
||||
|
||||
if (bytes_read != IOSM_READ_SIZE) {
|
||||
ret = -EINVAL;
|
||||
goto ipc_flash_ebl_err;
|
||||
}
|
||||
|
||||
ret = ipc_imem_sys_devlink_write(ipc_devlink, (u8 *)&ebl_size,
|
||||
sizeof(ebl_size));
|
||||
if (ret) {
|
||||
dev_err(ipc_devlink->dev, "EBL length write failed");
|
||||
goto ipc_flash_ebl_err;
|
||||
}
|
||||
|
||||
ret = ipc_imem_sys_devlink_read(ipc_devlink, read_data, IOSM_READ_SIZE,
|
||||
&bytes_read);
|
||||
if (ret) {
|
||||
dev_err(ipc_devlink->dev, "EBL read failed");
|
||||
goto ipc_flash_ebl_err;
|
||||
}
|
||||
|
||||
if (bytes_read != IOSM_READ_SIZE) {
|
||||
ret = -EINVAL;
|
||||
goto ipc_flash_ebl_err;
|
||||
}
|
||||
|
||||
ret = ipc_imem_sys_devlink_write(ipc_devlink, (unsigned char *)fw->data,
|
||||
fw->size);
|
||||
if (ret) {
|
||||
dev_err(ipc_devlink->dev, "EBL data transfer failed");
|
||||
goto ipc_flash_ebl_err;
|
||||
}
|
||||
|
||||
ret = ipc_imem_sys_devlink_read(ipc_devlink, read_data, IOSM_READ_SIZE,
|
||||
&bytes_read);
|
||||
if (ret) {
|
||||
dev_err(ipc_devlink->dev, "EBL read failed");
|
||||
goto ipc_flash_ebl_err;
|
||||
}
|
||||
|
||||
if (bytes_read != IOSM_READ_SIZE) {
|
||||
ret = -EINVAL;
|
||||
goto ipc_flash_ebl_err;
|
||||
}
|
||||
|
||||
ret = ipc_imem_sys_devlink_read(ipc_devlink,
|
||||
ipc_devlink->ebl_ctx.m_ebl_resp,
|
||||
IOSM_EBL_RSP_SIZE, &bytes_read);
|
||||
if (ret) {
|
||||
dev_err(ipc_devlink->dev, "EBL response read failed");
|
||||
goto ipc_flash_ebl_err;
|
||||
}
|
||||
|
||||
if (bytes_read != IOSM_EBL_RSP_SIZE)
|
||||
ret = -EINVAL;
|
||||
|
||||
ipc_flash_ebl_err:
|
||||
return ret;
|
||||
}
|
271
drivers/net/wwan/iosm/iosm_ipc_flash.h
Normal file
271
drivers/net/wwan/iosm/iosm_ipc_flash.h
Normal file
@ -0,0 +1,271 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-only
|
||||
*
|
||||
* Copyright (C) 2020-2021 Intel Corporation.
|
||||
*/
|
||||
|
||||
#ifndef _IOSM_IPC_FLASH_H
|
||||
#define _IOSM_IPC_FLASH_H
|
||||
|
||||
/* Buffer size used to read the fls image */
|
||||
#define IOSM_FLS_BUF_SIZE 0x00100000
|
||||
/* Full erase start address */
|
||||
#define IOSM_ERASE_START_ADDR 0x00000000
|
||||
/* Erase length for NAND flash */
|
||||
#define IOSM_ERASE_LEN 0xFFFFFFFF
|
||||
/* EBL response Header size */
|
||||
#define IOSM_EBL_HEAD_SIZE 8
|
||||
/* EBL payload size */
|
||||
#define IOSM_EBL_W_PAYL_SIZE 2048
|
||||
/* Total EBL pack size */
|
||||
#define IOSM_EBL_W_PACK_SIZE (IOSM_EBL_HEAD_SIZE + IOSM_EBL_W_PAYL_SIZE)
|
||||
/* EBL payload size */
|
||||
#define IOSM_EBL_DW_PAYL_SIZE 16384
|
||||
/* Total EBL pack size */
|
||||
#define IOSM_EBL_DW_PACK_SIZE (IOSM_EBL_HEAD_SIZE + IOSM_EBL_DW_PAYL_SIZE)
|
||||
/* EBL name size */
|
||||
#define IOSM_EBL_NAME 32
|
||||
/* Maximum supported error types */
|
||||
#define IOSM_MAX_ERRORS 8
|
||||
/* Read size for RPSI/EBL response */
|
||||
#define IOSM_READ_SIZE 2
|
||||
/* Link establishment response ack size */
|
||||
#define IOSM_LER_ACK_SIZE 2
|
||||
/* PSI ACK len */
|
||||
#define IOSM_PSI_ACK 8
|
||||
/* SWID capability for packed swid type */
|
||||
#define IOSM_EXT_CAP_SWID_OOS_PACK 0x02
|
||||
/* EBL error response buffer */
|
||||
#define IOSM_EBL_RSP_BUFF 0x0041
|
||||
/* SWID string length */
|
||||
#define IOSM_SWID_STR 64
|
||||
/* Load EBL command size */
|
||||
#define IOSM_RPSI_LOAD_SIZE 0
|
||||
/* EBL payload checksum */
|
||||
#define IOSM_EBL_CKSM 0x0000FFFF
|
||||
/* SWID msg len and argument */
|
||||
#define IOSM_MSG_LEN_ARG 0
|
||||
/* Data to be sent to modem */
|
||||
#define IOSM_MDM_SEND_DATA 0x0000
|
||||
/* Data received from modem as part of erase check */
|
||||
#define IOSM_MDM_ERASE_RSP 0x0001
|
||||
/* Bit shift to calculate Checksum */
|
||||
#define IOSM_EBL_PAYL_SHIFT 16
|
||||
/* Flag To be set */
|
||||
#define IOSM_SET_FLAG 1
|
||||
/* Set flash erase check timeout to 100 msec */
|
||||
#define IOSM_FLASH_ERASE_CHECK_TIMEOUT 100
|
||||
/* Set flash erase check interval to 20 msec */
|
||||
#define IOSM_FLASH_ERASE_CHECK_INTERVAL 20
|
||||
/* Link establishment response ack size */
|
||||
#define IOSM_LER_RSP_SIZE 60
|
||||
|
||||
/**
|
||||
* enum iosm_flash_package_type - Enum for the flashing operations
|
||||
* @FLASH_SET_PROT_CONF: Write EBL capabilities
|
||||
* @FLASH_SEC_START: Start writing the secpack
|
||||
* @FLASH_SEC_END: Validate secpack end
|
||||
* @FLASH_SET_ADDRESS: Set the address for flashing
|
||||
* @FLASH_ERASE_START: Start erase before flashing
|
||||
* @FLASH_ERASE_CHECK: Validate the erase functionality
|
||||
* @FLASH_OOS_CONTROL: Retrieve data based on oos actions
|
||||
* @FLASH_OOS_DATA_READ: Read data from EBL
|
||||
* @FLASH_WRITE_IMAGE_RAW: Write the raw image to flash
|
||||
*/
|
||||
enum iosm_flash_package_type {
|
||||
FLASH_SET_PROT_CONF = 0x0086,
|
||||
FLASH_SEC_START = 0x0204,
|
||||
FLASH_SEC_END,
|
||||
FLASH_SET_ADDRESS = 0x0802,
|
||||
FLASH_ERASE_START = 0x0805,
|
||||
FLASH_ERASE_CHECK,
|
||||
FLASH_OOS_CONTROL = 0x080C,
|
||||
FLASH_OOS_DATA_READ = 0x080E,
|
||||
FLASH_WRITE_IMAGE_RAW,
|
||||
};
|
||||
|
||||
/**
|
||||
* enum iosm_out_of_session_action - Actions possible over the
|
||||
* OutOfSession command interface
|
||||
* @FLASH_OOSC_ACTION_READ: Read data according to its type
|
||||
* @FLASH_OOSC_ACTION_ERASE: Erase data according to its type
|
||||
*/
|
||||
enum iosm_out_of_session_action {
|
||||
FLASH_OOSC_ACTION_READ = 2,
|
||||
FLASH_OOSC_ACTION_ERASE = 3,
|
||||
};
|
||||
|
||||
/**
|
||||
* enum iosm_out_of_session_type - Data types that can be handled over the
|
||||
* Out Of Session command Interface
|
||||
* @FLASH_OOSC_TYPE_ALL_FLASH: The whole flash area
|
||||
* @FLASH_OOSC_TYPE_SWID_TABLE: Read the swid table from the target
|
||||
*/
|
||||
enum iosm_out_of_session_type {
|
||||
FLASH_OOSC_TYPE_ALL_FLASH = 8,
|
||||
FLASH_OOSC_TYPE_SWID_TABLE = 16,
|
||||
};
|
||||
|
||||
/**
|
||||
* enum iosm_ebl_caps - EBL capability settings
|
||||
* @IOSM_CAP_NOT_ENHANCED: If capability not supported
|
||||
* @IOSM_CAP_USE_EXT_CAP: To be set if extended capability is set
|
||||
* @IOSM_EXT_CAP_ERASE_ALL: Set Erase all capability
|
||||
* @IOSM_EXT_CAP_COMMIT_ALL: Set the commit all capability
|
||||
*/
|
||||
enum iosm_ebl_caps {
|
||||
IOSM_CAP_NOT_ENHANCED = 0x00,
|
||||
IOSM_CAP_USE_EXT_CAP = 0x01,
|
||||
IOSM_EXT_CAP_ERASE_ALL = 0x08,
|
||||
IOSM_EXT_CAP_COMMIT_ALL = 0x20,
|
||||
};
|
||||
|
||||
/**
|
||||
* enum iosm_ebl_rsp - EBL response field
|
||||
* @EBL_CAPS_FLAG: EBL capability flag
|
||||
* @EBL_SKIP_ERASE: EBL skip erase flag
|
||||
* @EBL_SKIP_CRC: EBL skip wr_pack crc
|
||||
* @EBL_EXT_CAPS_HANDLED: EBL extended capability handled flag
|
||||
* @EBL_OOS_CONFIG: EBL oos configuration
|
||||
* @EBL_RSP_SW_INFO_VER: EBL SW info version
|
||||
*/
|
||||
enum iosm_ebl_rsp {
|
||||
EBL_CAPS_FLAG = 50,
|
||||
EBL_SKIP_ERASE = 54,
|
||||
EBL_SKIP_CRC = 55,
|
||||
EBL_EXT_CAPS_HANDLED = 57,
|
||||
EBL_OOS_CONFIG = 64,
|
||||
EBL_RSP_SW_INFO_VER = 70,
|
||||
};
|
||||
|
||||
/**
|
||||
* enum iosm_mdm_send_recv_data - Data to send to modem
|
||||
* @IOSM_MDM_SEND_2: Send 2 bytes of payload
|
||||
* @IOSM_MDM_SEND_4: Send 4 bytes of payload
|
||||
* @IOSM_MDM_SEND_8: Send 8 bytes of payload
|
||||
* @IOSM_MDM_SEND_16: Send 16 bytes of payload
|
||||
*/
|
||||
enum iosm_mdm_send_recv_data {
|
||||
IOSM_MDM_SEND_2 = 2,
|
||||
IOSM_MDM_SEND_4 = 4,
|
||||
IOSM_MDM_SEND_8 = 8,
|
||||
IOSM_MDM_SEND_16 = 16,
|
||||
};
|
||||
|
||||
/**
|
||||
* struct iosm_ebl_one_error - Structure containing error details
|
||||
* @error_class: Error type- standard, security and text error
|
||||
* @error_code: Specific error from error type
|
||||
*/
|
||||
struct iosm_ebl_one_error {
|
||||
u16 error_class;
|
||||
u16 error_code;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct iosm_ebl_error- Structure with max error type supported
|
||||
* @error: Array of one_error structure with max errors
|
||||
*/
|
||||
struct iosm_ebl_error {
|
||||
struct iosm_ebl_one_error error[IOSM_MAX_ERRORS];
|
||||
};
|
||||
|
||||
/**
|
||||
* struct iosm_swid_table - SWID table data for modem
|
||||
* @number_of_data_sets: Number of swid types
|
||||
* @sw_id_type: SWID type - SWID
|
||||
* @sw_id_val: SWID value
|
||||
* @rf_engine_id_type: RF engine ID type - RF_ENGINE_ID
|
||||
* @rf_engine_id_val: RF engine ID value
|
||||
*/
|
||||
struct iosm_swid_table {
|
||||
u32 number_of_data_sets;
|
||||
char sw_id_type[IOSM_EBL_NAME];
|
||||
u32 sw_id_val;
|
||||
char rf_engine_id_type[IOSM_EBL_NAME];
|
||||
u32 rf_engine_id_val;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct iosm_flash_msg_control - Data sent to modem
|
||||
* @action: Action to be performed
|
||||
* @type: Type of action
|
||||
* @length: Length of the action
|
||||
* @arguments: Argument value sent to modem
|
||||
*/
|
||||
struct iosm_flash_msg_control {
|
||||
__le32 action;
|
||||
__le32 type;
|
||||
__le32 length;
|
||||
__le32 arguments;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct iosm_flash_data - Header Data to be sent to modem
|
||||
* @checksum: Checksum value calculated for the payload data
|
||||
* @pack_id: Flash Action type
|
||||
* @msg_length: Payload length
|
||||
*/
|
||||
struct iosm_flash_data {
|
||||
__le16 checksum;
|
||||
__le16 pack_id;
|
||||
__le32 msg_length;
|
||||
};
|
||||
|
||||
/**
|
||||
* ipc_flash_boot_psi - Inject PSI image
|
||||
* @ipc_devlink: Pointer to devlink structure
|
||||
* @fw: FW image
|
||||
*
|
||||
* Returns: 0 on success and failure value on error
|
||||
*/
|
||||
int ipc_flash_boot_psi(struct iosm_devlink *ipc_devlink,
|
||||
const struct firmware *fw);
|
||||
|
||||
/**
|
||||
* ipc_flash_boot_ebl - Inject EBL image
|
||||
* @ipc_devlink: Pointer to devlink structure
|
||||
* @fw: FW image
|
||||
*
|
||||
* Returns: 0 on success and failure value on error
|
||||
*/
|
||||
int ipc_flash_boot_ebl(struct iosm_devlink *ipc_devlink,
|
||||
const struct firmware *fw);
|
||||
|
||||
/**
|
||||
* ipc_flash_boot_set_capabilities - Set modem bool capabilities in flash
|
||||
* @ipc_devlink: Pointer to devlink structure
|
||||
* @mdm_rsp: Pointer to modem response buffer
|
||||
*
|
||||
* Returns: 0 on success and failure value on error
|
||||
*/
|
||||
int ipc_flash_boot_set_capabilities(struct iosm_devlink *ipc_devlink,
|
||||
u8 *mdm_rsp);
|
||||
|
||||
/**
|
||||
* ipc_flash_link_establish - Flash link establishment
|
||||
* @ipc_imem: Pointer to struct iosm_imem
|
||||
*
|
||||
* Returns: 0 on success and failure value on error
|
||||
*/
|
||||
int ipc_flash_link_establish(struct iosm_imem *ipc_imem);
|
||||
|
||||
/**
|
||||
* ipc_flash_read_swid - Get swid during flash phase
|
||||
* @ipc_devlink: Pointer to devlink structure
|
||||
* @mdm_rsp: Pointer to modem response buffer
|
||||
*
|
||||
* Returns: 0 on success and failure value on error
|
||||
*/
|
||||
int ipc_flash_read_swid(struct iosm_devlink *ipc_devlink, u8 *mdm_rsp);
|
||||
|
||||
/**
|
||||
* ipc_flash_send_fls - Inject Modem subsystem fls file to device
|
||||
* @ipc_devlink: Pointer to devlink structure
|
||||
* @fw: FW image
|
||||
* @mdm_rsp: Pointer to modem response buffer
|
||||
*
|
||||
* Returns: 0 on success and failure value on error
|
||||
*/
|
||||
int ipc_flash_send_fls(struct iosm_devlink *ipc_devlink,
|
||||
const struct firmware *fw, u8 *mdm_rsp);
|
||||
#endif
|
Loading…
x
Reference in New Issue
Block a user