bus: mhi: host: Add a policy to enable image transfer via BHIe in PBL
authorMatthew Leung <quic_mattleun@quicinc.com>
Fri, 17 Jan 2025 17:09:38 +0000 (10:09 -0700)
committerJeffrey Hugo <quic_jhugo@quicinc.com>
Fri, 31 Jan 2025 17:06:08 +0000 (10:06 -0700)
Currently, MHI host only performs firmware transfer via BHI in PBL and
BHIe from SBL. To support BHIe transfer directly from PBL, a policy
needs to be added.

With this policy, BHIe will be used to transfer firmware in PBL if the
MHI controller has BHIe regs, sets seg_len, and does not set
fbc_download. The intention is to transfer firmware using BHIe in PBL
without further BHIe transfers in SBL.

Signed-off-by: Matthew Leung <quic_mattleun@quicinc.com>
Reviewed-by: Youssef Samir <quic_yabdulra@quicinc.com>
Reviewed-by: Jeffrey Hugo <quic_jhugo@quicinc.com>
Signed-off-by: Jeffrey Hugo <quic_jhugo@quicinc.com>
Reviewed-by: Jacek Lawrynowicz <jacek.lawrynowicz@linux.intel.com>
Reviewed-by: Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org>
Link: https://patchwork.freedesktop.org/patch/msgid/20250117170943.2643280-3-quic_jhugo@quicinc.com
drivers/bus/mhi/host/boot.c
drivers/bus/mhi/host/init.c
drivers/bus/mhi/host/internal.h

index 9fe13d3f09f059ad13d1bf28cf4f0f24142f9f8d..a206c3f0fcfdbf49d13fc3091fcdc96001317c5f 100644 (file)
@@ -440,12 +440,59 @@ static void mhi_firmware_copy_bhie(struct mhi_controller *mhi_cntrl,
        }
 }
 
+static enum mhi_fw_load_type mhi_fw_load_type_get(const struct mhi_controller *mhi_cntrl)
+{
+       if (mhi_cntrl->fbc_download) {
+               return MHI_FW_LOAD_FBC;
+       } else {
+               if (mhi_cntrl->seg_len)
+                       return MHI_FW_LOAD_BHIE;
+               else
+                       return MHI_FW_LOAD_BHI;
+       }
+}
+
+static int mhi_load_image_bhi(struct mhi_controller *mhi_cntrl, const u8 *fw_data, size_t size)
+{
+       struct image_info *image;
+       int ret;
+
+       ret = mhi_alloc_bhi_buffer(mhi_cntrl, &image, size);
+       if (ret)
+               return ret;
+
+       /* Load the firmware into BHI vec table */
+       memcpy(image->mhi_buf->buf, fw_data, size);
+
+       ret = mhi_fw_load_bhi(mhi_cntrl, &image->mhi_buf[image->entries - 1]);
+       mhi_free_bhi_buffer(mhi_cntrl, image);
+
+       return ret;
+}
+
+static int mhi_load_image_bhie(struct mhi_controller *mhi_cntrl, const u8 *fw_data, size_t size)
+{
+       struct image_info *image;
+       int ret;
+
+       ret = mhi_alloc_bhie_table(mhi_cntrl, &image, size);
+       if (ret)
+               return ret;
+
+       mhi_firmware_copy_bhie(mhi_cntrl, fw_data, size, image);
+
+       ret = mhi_fw_load_bhie(mhi_cntrl, &image->mhi_buf[image->entries - 1]);
+       mhi_free_bhie_table(mhi_cntrl, image);
+
+       return ret;
+}
+
 void mhi_fw_load_handler(struct mhi_controller *mhi_cntrl)
 {
        const struct firmware *firmware = NULL;
        struct device *dev = &mhi_cntrl->mhi_dev->dev;
+       enum mhi_fw_load_type fw_load_type;
        enum mhi_pm_state new_state;
-       struct image_info *image;
        const char *fw_name;
        const u8 *fw_data;
        size_t size, fw_sz;
@@ -506,21 +553,17 @@ void mhi_fw_load_handler(struct mhi_controller *mhi_cntrl)
        fw_sz = firmware->size;
 
 skip_req_fw:
-       ret = mhi_alloc_bhi_buffer(mhi_cntrl, &image, size);
-       if (ret) {
-               release_firmware(firmware);
-               goto error_fw_load;
-       }
-       /* Load the firmware into BHI vec table */
-       memcpy(image->mhi_buf->buf, fw_data, size);
-
-       /* Download image using BHI */
-       ret = mhi_fw_load_bhi(mhi_cntrl, image->mhi_buf);
-       mhi_free_bhi_buffer(mhi_cntrl, image);
+       fw_load_type = mhi_fw_load_type_get(mhi_cntrl);
+       if (fw_load_type == MHI_FW_LOAD_BHIE)
+               ret = mhi_load_image_bhie(mhi_cntrl, fw_data, size);
+       else
+               ret = mhi_load_image_bhi(mhi_cntrl, fw_data, size);
 
        /* Error or in EDL mode, we're done */
        if (ret) {
-               dev_err(dev, "MHI did not load image over BHI, ret: %d\n", ret);
+               dev_err(dev, "MHI did not load image over BHI%s, ret: %d\n",
+                       fw_load_type == MHI_FW_LOAD_BHIE ? "e" : "",
+                       ret);
                release_firmware(firmware);
                goto error_fw_load;
        }
@@ -539,7 +582,7 @@ skip_req_fw:
         * If we're doing fbc, populate vector tables while
         * device transitioning into MHI READY state
         */
-       if (mhi_cntrl->fbc_download) {
+       if (fw_load_type == MHI_FW_LOAD_FBC) {
                ret = mhi_alloc_bhie_table(mhi_cntrl, &mhi_cntrl->fbc_image, fw_sz);
                if (ret) {
                        release_firmware(firmware);
@@ -564,7 +607,7 @@ fw_load_ready_state:
        return;
 
 error_ready_state:
-       if (mhi_cntrl->fbc_download) {
+       if (fw_load_type == MHI_FW_LOAD_FBC) {
                mhi_free_bhie_table(mhi_cntrl, mhi_cntrl->fbc_image);
                mhi_cntrl->fbc_image = NULL;
        }
index a9b1f8beee7bc9788328e04f9cf37c995acf35ce..13e7a55f54ff45b83b3f18b97e2cdd83d4836fe3 100644 (file)
@@ -1144,7 +1144,7 @@ int mhi_prepare_for_power_up(struct mhi_controller *mhi_cntrl)
        }
        mhi_cntrl->bhi = mhi_cntrl->regs + bhi_off;
 
-       if (mhi_cntrl->fbc_download || mhi_cntrl->rddm_size) {
+       if (mhi_cntrl->fbc_download || mhi_cntrl->rddm_size || mhi_cntrl->seg_len) {
                ret = mhi_read_reg(mhi_cntrl, mhi_cntrl->regs, BHIEOFF,
                                   &bhie_off);
                if (ret) {
index 3134f111be3533afdb6d4af74b749dab91821ecd..ce566f7d2e9240c64044407aa4124ad3cdb98003 100644 (file)
@@ -29,6 +29,13 @@ struct bhi_vec_entry {
        u64 size;
 };
 
+enum mhi_fw_load_type {
+       MHI_FW_LOAD_BHI,        /* BHI only in PBL */
+       MHI_FW_LOAD_BHIE,       /* BHIe only in PBL */
+       MHI_FW_LOAD_FBC,        /* BHI in PBL followed by BHIe in SBL */
+       MHI_FW_LOAD_MAX,
+};
+
 enum mhi_ch_state_type {
        MHI_CH_STATE_TYPE_RESET,
        MHI_CH_STATE_TYPE_STOP,