diff options
Diffstat (limited to 'drivers/bus')
-rw-r--r-- | drivers/bus/fsl-mc/fsl-mc-bus.c | 3 | ||||
-rw-r--r-- | drivers/bus/mhi/host/boot.c | 203 | ||||
-rw-r--r-- | drivers/bus/mhi/host/init.c | 2 | ||||
-rw-r--r-- | drivers/bus/mhi/host/internal.h | 7 | ||||
-rw-r--r-- | drivers/bus/qcom-ssc-block-bus.c | 34 |
5 files changed, 179 insertions, 70 deletions
diff --git a/drivers/bus/fsl-mc/fsl-mc-bus.c b/drivers/bus/fsl-mc/fsl-mc-bus.c index d1f3d327ddd1..a8be8cf246fb 100644 --- a/drivers/bus/fsl-mc/fsl-mc-bus.c +++ b/drivers/bus/fsl-mc/fsl-mc-bus.c @@ -153,7 +153,8 @@ static int fsl_mc_dma_configure(struct device *dev) else ret = acpi_dma_configure_id(dev, DEV_DMA_COHERENT, &input_id); - if (!ret && !mc_drv->driver_managed_dma) { + /* @mc_drv may not be valid when we're called from the IOMMU layer */ + if (!ret && dev->driver && !mc_drv->driver_managed_dma) { ret = iommu_device_use_default_domain(dev); if (ret) arch_teardown_dma_ops(dev); 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; } diff --git a/drivers/bus/mhi/host/init.c b/drivers/bus/mhi/host/init.c index a9b1f8beee7b..13e7a55f54ff 100644 --- a/drivers/bus/mhi/host/init.c +++ b/drivers/bus/mhi/host/init.c @@ -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) { diff --git a/drivers/bus/mhi/host/internal.h b/drivers/bus/mhi/host/internal.h index 3134f111be35..ce566f7d2e92 100644 --- a/drivers/bus/mhi/host/internal.h +++ b/drivers/bus/mhi/host/internal.h @@ -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, diff --git a/drivers/bus/qcom-ssc-block-bus.c b/drivers/bus/qcom-ssc-block-bus.c index 85d781a32df4..7f5fd4e0940d 100644 --- a/drivers/bus/qcom-ssc-block-bus.c +++ b/drivers/bus/qcom-ssc-block-bus.c @@ -264,18 +264,6 @@ static int qcom_ssc_block_bus_probe(struct platform_device *pdev) platform_set_drvdata(pdev, data); - data->pd_names = qcom_ssc_block_pd_names; - data->num_pds = ARRAY_SIZE(qcom_ssc_block_pd_names); - - /* power domains */ - ret = qcom_ssc_block_bus_pds_attach(&pdev->dev, data->pds, data->pd_names, data->num_pds); - if (ret < 0) - return dev_err_probe(&pdev->dev, ret, "error when attaching power domains\n"); - - ret = qcom_ssc_block_bus_pds_enable(data->pds, data->num_pds); - if (ret < 0) - return dev_err_probe(&pdev->dev, ret, "error when enabling power domains\n"); - /* low level overrides for when the HW logic doesn't "just work" */ res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "mpm_sscaon_config0"); data->reg_mpm_sscaon_config0 = devm_ioremap_resource(&pdev->dev, res); @@ -343,11 +331,30 @@ static int qcom_ssc_block_bus_probe(struct platform_device *pdev) data->ssc_axi_halt = halt_args.args[0]; + /* power domains */ + data->pd_names = qcom_ssc_block_pd_names; + data->num_pds = ARRAY_SIZE(qcom_ssc_block_pd_names); + + ret = qcom_ssc_block_bus_pds_attach(&pdev->dev, data->pds, data->pd_names, data->num_pds); + if (ret < 0) + return dev_err_probe(&pdev->dev, ret, "error when attaching power domains\n"); + + ret = qcom_ssc_block_bus_pds_enable(data->pds, data->num_pds); + if (ret < 0) { + dev_err_probe(&pdev->dev, ret, "error when enabling power domains\n"); + goto err_detach_pds_bus; + } + qcom_ssc_block_bus_init(&pdev->dev); of_platform_populate(np, NULL, NULL, &pdev->dev); return 0; + +err_detach_pds_bus: + qcom_ssc_block_bus_pds_detach(&pdev->dev, data->pds, data->num_pds); + + return ret; } static void qcom_ssc_block_bus_remove(struct platform_device *pdev) @@ -356,9 +363,6 @@ static void qcom_ssc_block_bus_remove(struct platform_device *pdev) qcom_ssc_block_bus_deinit(&pdev->dev); - iounmap(data->reg_mpm_sscaon_config0); - iounmap(data->reg_mpm_sscaon_config1); - qcom_ssc_block_bus_pds_disable(data->pds, data->num_pds); qcom_ssc_block_bus_pds_detach(&pdev->dev, data->pds, data->num_pds); pm_runtime_disable(&pdev->dev); |