diff options
Diffstat (limited to 'drivers/bus/mhi/host/boot.c')
-rw-r--r-- | drivers/bus/mhi/host/boot.c | 203 |
1 files changed, 150 insertions, 53 deletions
diff --git a/drivers/bus/mhi/host/boot.c b/drivers/bus/mhi/host/boot.c index 9dcc7184817d..efa3b6dddf4d 100644 --- a/drivers/bus/mhi/host/boot.c +++ b/drivers/bus/mhi/host/boot.c @@ -177,6 +177,36 @@ int mhi_download_rddm_image(struct mhi_controller *mhi_cntrl, bool in_panic) } EXPORT_SYMBOL_GPL(mhi_download_rddm_image); +static void mhi_fw_load_error_dump(struct mhi_controller *mhi_cntrl) +{ + struct device *dev = &mhi_cntrl->mhi_dev->dev; + rwlock_t *pm_lock = &mhi_cntrl->pm_lock; + void __iomem *base = mhi_cntrl->bhi; + int ret, i; + u32 val; + struct { + char *name; + u32 offset; + } error_reg[] = { + { "ERROR_CODE", BHI_ERRCODE }, + { "ERROR_DBG1", BHI_ERRDBG1 }, + { "ERROR_DBG2", BHI_ERRDBG2 }, + { "ERROR_DBG3", BHI_ERRDBG3 }, + { NULL }, + }; + + read_lock_bh(pm_lock); + if (MHI_REG_ACCESS_VALID(mhi_cntrl->pm_state)) { + for (i = 0; error_reg[i].name; i++) { + ret = mhi_read_reg(mhi_cntrl, base, error_reg[i].offset, &val); + if (ret) + break; + dev_err(dev, "Reg: %s value: 0x%x\n", error_reg[i].name, val); + } + } + read_unlock_bh(pm_lock); +} + static int mhi_fw_load_bhie(struct mhi_controller *mhi_cntrl, const struct mhi_buf *mhi_buf) { @@ -226,24 +256,13 @@ static int mhi_fw_load_bhie(struct mhi_controller *mhi_cntrl, } static int mhi_fw_load_bhi(struct mhi_controller *mhi_cntrl, - dma_addr_t dma_addr, - size_t size) + const struct mhi_buf *mhi_buf) { - u32 tx_status, val, session_id; - int i, ret; - void __iomem *base = mhi_cntrl->bhi; - rwlock_t *pm_lock = &mhi_cntrl->pm_lock; struct device *dev = &mhi_cntrl->mhi_dev->dev; - struct { - char *name; - u32 offset; - } error_reg[] = { - { "ERROR_CODE", BHI_ERRCODE }, - { "ERROR_DBG1", BHI_ERRDBG1 }, - { "ERROR_DBG2", BHI_ERRDBG2 }, - { "ERROR_DBG3", BHI_ERRDBG3 }, - { NULL }, - }; + rwlock_t *pm_lock = &mhi_cntrl->pm_lock; + void __iomem *base = mhi_cntrl->bhi; + u32 tx_status, session_id; + int ret; read_lock_bh(pm_lock); if (!MHI_REG_ACCESS_VALID(mhi_cntrl->pm_state)) { @@ -255,11 +274,9 @@ static int mhi_fw_load_bhi(struct mhi_controller *mhi_cntrl, dev_dbg(dev, "Starting image download via BHI. Session ID: %u\n", session_id); mhi_write_reg(mhi_cntrl, base, BHI_STATUS, 0); - mhi_write_reg(mhi_cntrl, base, BHI_IMGADDR_HIGH, - upper_32_bits(dma_addr)); - mhi_write_reg(mhi_cntrl, base, BHI_IMGADDR_LOW, - lower_32_bits(dma_addr)); - mhi_write_reg(mhi_cntrl, base, BHI_IMGSIZE, size); + mhi_write_reg(mhi_cntrl, base, BHI_IMGADDR_HIGH, upper_32_bits(mhi_buf->dma_addr)); + mhi_write_reg(mhi_cntrl, base, BHI_IMGADDR_LOW, lower_32_bits(mhi_buf->dma_addr)); + mhi_write_reg(mhi_cntrl, base, BHI_IMGSIZE, mhi_buf->len); mhi_write_reg(mhi_cntrl, base, BHI_IMGTXDB, session_id); read_unlock_bh(pm_lock); @@ -274,18 +291,7 @@ static int mhi_fw_load_bhi(struct mhi_controller *mhi_cntrl, if (tx_status == BHI_STATUS_ERROR) { dev_err(dev, "Image transfer failed\n"); - read_lock_bh(pm_lock); - if (MHI_REG_ACCESS_VALID(mhi_cntrl->pm_state)) { - for (i = 0; error_reg[i].name; i++) { - ret = mhi_read_reg(mhi_cntrl, base, - error_reg[i].offset, &val); - if (ret) - break; - dev_err(dev, "Reg: %s value: 0x%x\n", - error_reg[i].name, val); - } - } - read_unlock_bh(pm_lock); + mhi_fw_load_error_dump(mhi_cntrl); goto invalid_pm_state; } @@ -296,6 +302,16 @@ invalid_pm_state: return -EIO; } +static void mhi_free_bhi_buffer(struct mhi_controller *mhi_cntrl, + struct image_info *image_info) +{ + struct mhi_buf *mhi_buf = image_info->mhi_buf; + + dma_free_coherent(mhi_cntrl->cntrl_dev, mhi_buf->len, mhi_buf->buf, mhi_buf->dma_addr); + kfree(image_info->mhi_buf); + kfree(image_info); +} + void mhi_free_bhie_table(struct mhi_controller *mhi_cntrl, struct image_info *image_info) { @@ -310,6 +326,45 @@ void mhi_free_bhie_table(struct mhi_controller *mhi_cntrl, kfree(image_info); } +static int mhi_alloc_bhi_buffer(struct mhi_controller *mhi_cntrl, + struct image_info **image_info, + size_t alloc_size) +{ + struct image_info *img_info; + struct mhi_buf *mhi_buf; + + img_info = kzalloc(sizeof(*img_info), GFP_KERNEL); + if (!img_info) + return -ENOMEM; + + /* Allocate memory for entry */ + img_info->mhi_buf = kzalloc(sizeof(*img_info->mhi_buf), GFP_KERNEL); + if (!img_info->mhi_buf) + goto error_alloc_mhi_buf; + + /* Allocate and populate vector table */ + mhi_buf = img_info->mhi_buf; + + mhi_buf->len = alloc_size; + mhi_buf->buf = dma_alloc_coherent(mhi_cntrl->cntrl_dev, mhi_buf->len, + &mhi_buf->dma_addr, GFP_KERNEL); + if (!mhi_buf->buf) + goto error_alloc_segment; + + img_info->bhi_vec = NULL; + img_info->entries = 1; + *image_info = img_info; + + return 0; + +error_alloc_segment: + kfree(mhi_buf); +error_alloc_mhi_buf: + kfree(img_info); + + return -ENOMEM; +} + int mhi_alloc_bhie_table(struct mhi_controller *mhi_cntrl, struct image_info **image_info, size_t alloc_size) @@ -365,9 +420,9 @@ error_alloc_mhi_buf: return -ENOMEM; } -static void mhi_firmware_copy(struct mhi_controller *mhi_cntrl, - const u8 *buf, size_t remainder, - struct image_info *img_info) +static void mhi_firmware_copy_bhie(struct mhi_controller *mhi_cntrl, + const u8 *buf, size_t remainder, + struct image_info *img_info) { size_t to_cpy; struct mhi_buf *mhi_buf = img_info->mhi_buf; @@ -386,15 +441,61 @@ static void mhi_firmware_copy(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; const char *fw_name; const u8 *fw_data; - void *buf; - dma_addr_t dma_addr; size_t size, fw_sz; int ret; @@ -453,21 +554,17 @@ void mhi_fw_load_handler(struct mhi_controller *mhi_cntrl) fw_sz = firmware->size; skip_req_fw: - buf = dma_alloc_coherent(mhi_cntrl->cntrl_dev, size, &dma_addr, - GFP_KERNEL); - if (!buf) { - release_firmware(firmware); - goto error_fw_load; - } - - /* Download image using BHI */ - memcpy(buf, fw_data, size); - ret = mhi_fw_load_bhi(mhi_cntrl, dma_addr, size); - dma_free_coherent(mhi_cntrl->cntrl_dev, size, buf, dma_addr); + 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; } @@ -486,7 +583,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); @@ -494,7 +591,7 @@ skip_req_fw: } /* Load the firmware into BHIE vec table */ - mhi_firmware_copy(mhi_cntrl, fw_data, fw_sz, mhi_cntrl->fbc_image); + mhi_firmware_copy_bhie(mhi_cntrl, fw_data, fw_sz, mhi_cntrl->fbc_image); } release_firmware(firmware); @@ -511,7 +608,7 @@ fw_load_ready_state: return; error_ready_state: - if (mhi_cntrl->fbc_download) { + if (mhi_cntrl->fbc_image) { mhi_free_bhie_table(mhi_cntrl, mhi_cntrl->fbc_image); mhi_cntrl->fbc_image = NULL; } |