OSDN Git Service

net: wwan: iosm: fw flashing support
authorM Chetan Kumar <m.chetan.kumar@linux.intel.com>
Sun, 19 Sep 2021 17:27:05 +0000 (22:57 +0530)
committerDavid S. Miller <davem@davemloft.net>
Mon, 20 Sep 2021 09:03:37 +0000 (10:03 +0100)
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>
drivers/net/wwan/iosm/iosm_ipc_flash.c [new file with mode: 0644]
drivers/net/wwan/iosm/iosm_ipc_flash.h [new file with mode: 0644]

diff --git a/drivers/net/wwan/iosm/iosm_ipc_flash.c b/drivers/net/wwan/iosm/iosm_ipc_flash.c
new file mode 100644 (file)
index 0000000..3d2f1ec
--- /dev/null
@@ -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;
+}
diff --git a/drivers/net/wwan/iosm/iosm_ipc_flash.h b/drivers/net/wwan/iosm/iosm_ipc_flash.h
new file mode 100644 (file)
index 0000000..aee8489
--- /dev/null
@@ -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