diff options
28 files changed, 323 insertions, 29 deletions
diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp40.c b/drivers/media/platform/msm/camera_v2/isp/msm_isp40.c index f5533fd9062e..981832b5a586 100644 --- a/drivers/media/platform/msm/camera_v2/isp/msm_isp40.c +++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp40.c @@ -702,6 +702,12 @@ static void msm_vfe40_reg_update(struct vfe_device *vfe_dev, vfe_dev->reg_update_requested; if ((vfe_dev->is_split && vfe_dev->pdev->id == ISP_VFE1) && ((frame_src == VFE_PIX_0) || (frame_src == VFE_SRC_MAX))) { + if (!vfe_dev->common_data->dual_vfe_res->vfe_base[ISP_VFE0]) { + pr_err("%s vfe_base for ISP_VFE0 is NULL\n", __func__); + spin_unlock_irqrestore(&vfe_dev->reg_update_lock, + flags); + return; + } msm_camera_io_w_mb(update_mask, vfe_dev->common_data->dual_vfe_res->vfe_base[ISP_VFE0] + 0x378); diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp44.c b/drivers/media/platform/msm/camera_v2/isp/msm_isp44.c index c85bf1655b8c..cc4dd5eaf93e 100644 --- a/drivers/media/platform/msm/camera_v2/isp/msm_isp44.c +++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp44.c @@ -560,6 +560,12 @@ static void msm_vfe44_reg_update(struct vfe_device *vfe_dev, vfe_dev->reg_update_requested; if ((vfe_dev->is_split && vfe_dev->pdev->id == ISP_VFE1) && ((frame_src == VFE_PIX_0) || (frame_src == VFE_SRC_MAX))) { + if (!vfe_dev->common_data->dual_vfe_res->vfe_base[ISP_VFE0]) { + pr_err("%s vfe_base for ISP_VFE0 is NULL\n", __func__); + spin_unlock_irqrestore(&vfe_dev->reg_update_lock, + flags); + return; + } msm_camera_io_w_mb(update_mask, vfe_dev->common_data->dual_vfe_res->vfe_base[ISP_VFE0] + 0x378); diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp46.c b/drivers/media/platform/msm/camera_v2/isp/msm_isp46.c index 72ce32940c29..632624034a04 100644 --- a/drivers/media/platform/msm/camera_v2/isp/msm_isp46.c +++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp46.c @@ -499,6 +499,12 @@ static void msm_vfe46_reg_update(struct vfe_device *vfe_dev, vfe_dev->reg_update_requested; if ((vfe_dev->is_split && vfe_dev->pdev->id == ISP_VFE1) && ((frame_src == VFE_PIX_0) || (frame_src == VFE_SRC_MAX))) { + if (!vfe_dev->common_data->dual_vfe_res->vfe_base[ISP_VFE0]) { + pr_err("%s vfe_base for ISP_VFE0 is NULL\n", __func__); + spin_unlock_irqrestore(&vfe_dev->reg_update_lock, + flags); + return; + } msm_camera_io_w_mb(update_mask, vfe_dev->common_data->dual_vfe_res->vfe_base[ISP_VFE0] + 0x3D8); diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp47.c b/drivers/media/platform/msm/camera_v2/isp/msm_isp47.c index 24d1c6cba84d..6716bb6caad6 100644 --- a/drivers/media/platform/msm/camera_v2/isp/msm_isp47.c +++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp47.c @@ -735,6 +735,12 @@ void msm_vfe47_reg_update(struct vfe_device *vfe_dev, vfe_dev->reg_update_requested; if ((vfe_dev->is_split && vfe_dev->pdev->id == ISP_VFE1) && ((frame_src == VFE_PIX_0) || (frame_src == VFE_SRC_MAX))) { + if (!vfe_dev->common_data->dual_vfe_res->vfe_base[ISP_VFE0]) { + pr_err("%s vfe_base for ISP_VFE0 is NULL\n", __func__); + spin_unlock_irqrestore(&vfe_dev->reg_update_lock, + flags); + return; + } msm_camera_io_w_mb(update_mask, vfe_dev->common_data->dual_vfe_res->vfe_base[ISP_VFE0] + 0x4AC); diff --git a/drivers/media/platform/msm/vidc/msm_vdec.c b/drivers/media/platform/msm/vidc/msm_vdec.c index 78cced2abd47..c80f535d95e1 100644 --- a/drivers/media/platform/msm/vidc/msm_vdec.c +++ b/drivers/media/platform/msm/vidc/msm_vdec.c @@ -847,6 +847,14 @@ int msm_vdec_streamoff(struct msm_vidc_inst *inst, enum v4l2_buf_type i) return -EINVAL; } dprintk(VIDC_DBG, "Calling streamoff\n"); + + if (!inst->in_reconfig) { + rc = msm_comm_try_state(inst, MSM_VIDC_RELEASE_RESOURCES_DONE); + if (rc) + dprintk(VIDC_ERR, + "Failed to move inst: %pK to res done state\n", inst); + } + mutex_lock(&q->lock); rc = vb2_streamoff(&q->vb2_bufq, i); mutex_unlock(&q->lock); diff --git a/drivers/media/platform/msm/vidc/msm_venc.c b/drivers/media/platform/msm/vidc/msm_venc.c index e4698e0cdcd8..947ade9c99ed 100644 --- a/drivers/media/platform/msm/vidc/msm_venc.c +++ b/drivers/media/platform/msm/vidc/msm_venc.c @@ -4620,6 +4620,12 @@ int msm_venc_streamoff(struct msm_vidc_inst *inst, enum v4l2_buf_type i) return -EINVAL; } dprintk(VIDC_DBG, "Calling streamoff on port: %d\n", i); + + rc = msm_comm_try_state(inst, MSM_VIDC_RELEASE_RESOURCES_DONE); + if (rc) + dprintk(VIDC_ERR, + "Failed to move inst: %pK to res done state\n", inst); + mutex_lock(&q->lock); rc = vb2_streamoff(&q->vb2_bufq, i); mutex_unlock(&q->lock); diff --git a/drivers/media/platform/msm/vidc/msm_vidc_common.c b/drivers/media/platform/msm/vidc/msm_vidc_common.c index 1d910f4b235c..4cb8f92c4e38 100644 --- a/drivers/media/platform/msm/vidc/msm_vidc_common.c +++ b/drivers/media/platform/msm/vidc/msm_vidc_common.c @@ -1179,7 +1179,7 @@ static void handle_event_change(enum hal_command_response cmd, void *data) __func__, inst, &event_notify->packet_buffer, &event_notify->extra_data_buffer); - if (inst->state == MSM_VIDC_CORE_INVALID || + if (inst->state >= MSM_VIDC_STOP || inst->core->state == VIDC_CORE_INVALID) { dprintk(VIDC_DBG, "Event release buf ref received in invalid state - discard\n"); diff --git a/drivers/mmc/card/block.c b/drivers/mmc/card/block.c index d39b4056c169..c002fa5ff602 100644 --- a/drivers/mmc/card/block.c +++ b/drivers/mmc/card/block.c @@ -3894,6 +3894,7 @@ static inline int mmc_blk_cmdq_part_switch(struct mmc_card *card, struct mmc_host *host = card->host; struct mmc_cmdq_context_info *ctx = &host->cmdq_ctx; u8 part_config = card->ext_csd.part_config; + int ret = 0, err = 0; if ((main_md->part_curr == md->part_type) && (card->part_curr == md->part_type)) @@ -3903,40 +3904,70 @@ static inline int mmc_blk_cmdq_part_switch(struct mmc_card *card, card->ext_csd.cmdq_support && (md->flags & MMC_BLK_CMD_QUEUE))); - if (!test_bit(CMDQ_STATE_HALT, &ctx->curr_state)) - WARN_ON(mmc_cmdq_halt(host, true)); + if (!test_bit(CMDQ_STATE_HALT, &ctx->curr_state)) { + ret = mmc_cmdq_halt(host, true); + if (ret) { + pr_err("%s: %s: halt: failed: %d\n", + mmc_hostname(host), __func__, ret); + goto out; + } + } /* disable CQ mode in card */ if (mmc_card_cmdq(card)) { - WARN_ON(mmc_switch(card, EXT_CSD_CMD_SET_NORMAL, + ret = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_CMDQ, 0, - card->ext_csd.generic_cmd6_time)); + card->ext_csd.generic_cmd6_time); + if (ret) { + pr_err("%s: %s: cmdq mode disable failed %d\n", + mmc_hostname(host), __func__, ret); + goto cmdq_unhalt; + } mmc_card_clr_cmdq(card); } part_config &= ~EXT_CSD_PART_CONFIG_ACC_MASK; part_config |= md->part_type; - WARN_ON(mmc_switch(card, EXT_CSD_CMD_SET_NORMAL, + ret = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_PART_CONFIG, part_config, - card->ext_csd.part_time)); + card->ext_csd.part_time); + if (ret) { + pr_err("%s: %s: mmc_switch failure, %d -> %d , err = %d\n", + mmc_hostname(host), __func__, main_md->part_curr, + md->part_type, ret); + goto cmdq_switch; + } card->ext_csd.part_config = part_config; card->part_curr = md->part_type; main_md->part_curr = md->part_type; - WARN_ON(mmc_blk_cmdq_switch(card, md, true)); - WARN_ON(mmc_cmdq_halt(host, false)); - - return 0; +cmdq_switch: + err = mmc_blk_cmdq_switch(card, md, true); + if (err) { + pr_err("%s: %s: mmc_blk_cmdq_switch failed: %d\n", + mmc_hostname(host), __func__, err); + ret = err; + } +cmdq_unhalt: + err = mmc_cmdq_halt(host, false); + if (err) { + pr_err("%s: %s: unhalt: failed: %d\n", + mmc_hostname(host), __func__, err); + ret = err; + } +out: + return ret; } static int mmc_blk_cmdq_issue_rq(struct mmc_queue *mq, struct request *req) { - int ret; + int ret, err = 0; struct mmc_blk_data *md = mq->data; struct mmc_card *card = md->queue.card; + struct mmc_host *host = card->host; unsigned int cmd_flags = req ? req->cmd_flags : 0; mmc_get_card(card); @@ -3958,9 +3989,20 @@ static int mmc_blk_cmdq_issue_rq(struct mmc_queue *mq, struct request *req) ret = mmc_blk_cmdq_part_switch(card, md); if (ret) { - pr_err("%s: %s: partition switch failed %d\n", + pr_err("%s: %s: partition switch failed %d, resetting cmdq\n", md->disk->disk_name, __func__, ret); - goto out; + + mmc_blk_cmdq_reset(host, false); + err = mmc_blk_cmdq_part_switch(card, md); + if (!err) { + pr_err("%s: %s: partition switch success err = %d\n", + md->disk->disk_name, __func__, err); + } else { + pr_err("%s: %s: partition switch failed err = %d\n", + md->disk->disk_name, __func__, err); + ret = 0; + goto out; + } } if (req) { diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c index a28d6b98a042..6f4f81a370d8 100644 --- a/drivers/mmc/core/mmc.c +++ b/drivers/mmc/core/mmc.c @@ -2056,11 +2056,11 @@ reinit: } card->clk_scaling_lowest = host->f_min; - if ((card->mmc_avail_type | EXT_CSD_CARD_TYPE_HS400) || - (card->mmc_avail_type | EXT_CSD_CARD_TYPE_HS200)) + if ((card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS400) || + (card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS200)) card->clk_scaling_highest = card->ext_csd.hs200_max_dtr; - else if ((card->mmc_avail_type | EXT_CSD_CARD_TYPE_HS) || - (card->mmc_avail_type | EXT_CSD_CARD_TYPE_DDR_52)) + else if ((card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS) || + (card->mmc_avail_type & EXT_CSD_CARD_TYPE_DDR_52)) card->clk_scaling_highest = card->ext_csd.hs_max_dtr; else card->clk_scaling_highest = card->csd.max_dtr; diff --git a/drivers/mmc/host/sdhci-msm.c b/drivers/mmc/host/sdhci-msm.c index c86a800fc203..df3fce93b6d1 100644 --- a/drivers/mmc/host/sdhci-msm.c +++ b/drivers/mmc/host/sdhci-msm.c @@ -142,6 +142,7 @@ #define CORE_START_CDC_TRAFFIC (1 << 6) #define CORE_PWRSAVE_DLL (1 << 3) +#define CORE_FIFO_ALT_EN (1 << 10) #define CORE_CMDEN_HS400_INPUT_MASK_CNT (1 << 13) #define CORE_DDR_CAL_EN (1 << 0) @@ -4154,7 +4155,7 @@ static void sdhci_set_default_hw_caps(struct sdhci_msm_host *msm_host, * starts coming. */ if ((major == 1) && ((minor == 0x42) || (minor == 0x46) || - (minor == 0x49))) + (minor == 0x49) || (minor >= 0x6b))) msm_host->use_14lpp_dll = true; /* Fake 3.0V support for SDIO devices which requires such voltage */ @@ -4484,6 +4485,14 @@ static int sdhci_msm_probe(struct platform_device *pdev) writel_relaxed(CORE_VENDOR_SPEC_POR_VAL, host->ioaddr + msm_host_offset->CORE_VENDOR_SPEC); + /* + * Ensure SDHCI FIFO is enabled by disabling alternative FIFO + */ + writel_relaxed((readl_relaxed(host->ioaddr + + msm_host_offset->CORE_VENDOR_SPEC3) & + ~CORE_FIFO_ALT_EN), host->ioaddr + + msm_host_offset->CORE_VENDOR_SPEC3); + if (!msm_host->mci_removed) { /* Set HC_MODE_EN bit in HC_MODE register */ writel_relaxed(HC_MODE_EN, (msm_host->core_mem + CORE_HC_MODE)); diff --git a/drivers/platform/msm/ipa/ipa_api.c b/drivers/platform/msm/ipa/ipa_api.c index 1a6ba1a915a0..bc0263c371a1 100644 --- a/drivers/platform/msm/ipa/ipa_api.c +++ b/drivers/platform/msm/ipa/ipa_api.c @@ -2943,6 +2943,25 @@ struct device *ipa_get_pdev(void) } EXPORT_SYMBOL(ipa_get_pdev); +int ipa_ntn_uc_reg_rdyCB(void (*ipauc_ready_cb)(void *user_data), + void *user_data) +{ + int ret; + + IPA_API_DISPATCH_RETURN(ipa_ntn_uc_reg_rdyCB, + ipauc_ready_cb, user_data); + + return ret; +} +EXPORT_SYMBOL(ipa_ntn_uc_reg_rdyCB); + +void ipa_ntn_uc_dereg_rdyCB(void) +{ + IPA_API_DISPATCH(ipa_ntn_uc_dereg_rdyCB); +} +EXPORT_SYMBOL(ipa_ntn_uc_dereg_rdyCB); + + static const struct dev_pm_ops ipa_pm_ops = { .suspend_noirq = ipa_ap_suspend, .resume_noirq = ipa_ap_resume, diff --git a/drivers/platform/msm/ipa/ipa_api.h b/drivers/platform/msm/ipa/ipa_api.h index 69bc4ae1fa6a..1fb0e7122042 100644 --- a/drivers/platform/msm/ipa/ipa_api.h +++ b/drivers/platform/msm/ipa/ipa_api.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2015-2016, The Linux Foundation. All rights reserved. +/* Copyright (c) 2015-2017, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -374,6 +374,11 @@ struct ipa_api_controller { int ipa_ep_idx_dl); struct device *(*ipa_get_pdev)(void); + + int (*ipa_ntn_uc_reg_rdyCB)(void (*ipauc_ready_cb)(void *user_data), + void *user_data); + + void (*ipa_ntn_uc_dereg_rdyCB)(void); }; #ifdef CONFIG_IPA diff --git a/drivers/platform/msm/ipa/ipa_clients/ipa_uc_offload.c b/drivers/platform/msm/ipa/ipa_clients/ipa_uc_offload.c index 51c930a81c8d..3a1e38f32321 100644 --- a/drivers/platform/msm/ipa/ipa_clients/ipa_uc_offload.c +++ b/drivers/platform/msm/ipa/ipa_clients/ipa_uc_offload.c @@ -622,3 +622,41 @@ int ipa_uc_offload_cleanup(u32 clnt_hdl) return ret; } EXPORT_SYMBOL(ipa_uc_offload_cleanup); + +/** + * ipa_uc_offload_uc_rdyCB() - To register uC ready CB if uC not + * ready + * @inout: [in/out] input/output parameters + * from/to client + * + * Returns: 0 on success, negative on failure + * + */ +int ipa_uc_offload_reg_rdyCB(struct ipa_uc_ready_params *inp) +{ + int ret = 0; + + if (!inp) { + IPA_UC_OFFLOAD_ERR("Invalid input\n"); + return -EINVAL; + } + + if (inp->proto == IPA_UC_NTN) + ret = ipa_ntn_uc_reg_rdyCB(inp->notify, inp->priv); + + if (ret == -EEXIST) { + inp->is_uC_ready = true; + ret = 0; + } else + inp->is_uC_ready = false; + + return ret; +} +EXPORT_SYMBOL(ipa_uc_offload_reg_rdyCB); + +void ipa_uc_offload_dereg_rdyCB(enum ipa_uc_offload_proto proto) +{ + if (proto == IPA_UC_NTN) + ipa_ntn_uc_dereg_rdyCB(); +} +EXPORT_SYMBOL(ipa_uc_offload_dereg_rdyCB); diff --git a/drivers/platform/msm/ipa/ipa_common_i.h b/drivers/platform/msm/ipa/ipa_common_i.h index d5f102eaaac6..911db0b19079 100644 --- a/drivers/platform/msm/ipa/ipa_common_i.h +++ b/drivers/platform/msm/ipa/ipa_common_i.h @@ -379,6 +379,9 @@ u8 *ipa_write_16(u16 hw, u8 *dest); u8 *ipa_write_8(u8 b, u8 *dest); u8 *ipa_pad_to_64(u8 *dest); u8 *ipa_pad_to_32(u8 *dest); +int ipa_ntn_uc_reg_rdyCB(void (*ipauc_ready_cb)(void *user_data), + void *user_data); +void ipa_ntn_uc_dereg_rdyCB(void); const char *ipa_get_version_string(enum ipa_hw_type ver); #endif /* _IPA_COMMON_I_H_ */ diff --git a/drivers/platform/msm/ipa/ipa_uc_offload_common_i.h b/drivers/platform/msm/ipa/ipa_uc_offload_common_i.h index ae6cfc4fcd50..0bc4b768e847 100644 --- a/drivers/platform/msm/ipa/ipa_uc_offload_common_i.h +++ b/drivers/platform/msm/ipa/ipa_uc_offload_common_i.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2012-2016, The Linux Foundation. All rights reserved. +/* Copyright (c) 2012-2017, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -21,4 +21,7 @@ int ipa_setup_uc_ntn_pipes(struct ipa_ntn_conn_in_params *in, struct ipa_ntn_conn_out_params *outp); int ipa_tear_down_uc_offload_pipes(int ipa_ep_idx_ul, int ipa_ep_idx_dl); +int ipa_ntn_uc_reg_rdyCB(void (*ipauc_ready_cb)(void *user_data), + void *user_data); +void ipa_ntn_uc_dereg_rdyCB(void); #endif /* _IPA_UC_OFFLOAD_COMMON_I_H_ */ diff --git a/drivers/platform/msm/ipa/ipa_v2/ipa_i.h b/drivers/platform/msm/ipa/ipa_v2/ipa_i.h index 39d82fab325f..28689eb83d4e 100644 --- a/drivers/platform/msm/ipa/ipa_v2/ipa_i.h +++ b/drivers/platform/msm/ipa/ipa_v2/ipa_i.h @@ -1576,6 +1576,8 @@ int ipa2_setup_uc_ntn_pipes(struct ipa_ntn_conn_in_params *inp, ipa_notify_cb notify, void *priv, u8 hdr_len, struct ipa_ntn_conn_out_params *outp); int ipa2_tear_down_uc_offload_pipes(int ipa_ep_idx_ul, int ipa_ep_idx_dl); +int ipa2_ntn_uc_reg_rdyCB(void (*ipauc_ready_cb)(void *), void *priv); +void ipa2_ntn_uc_dereg_rdyCB(void); /* * To retrieve doorbell physical address of diff --git a/drivers/platform/msm/ipa/ipa_v2/ipa_uc_ntn.c b/drivers/platform/msm/ipa/ipa_v2/ipa_uc_ntn.c index 0b46ab2a8439..2aedfe04b5a3 100644 --- a/drivers/platform/msm/ipa/ipa_v2/ipa_uc_ntn.c +++ b/drivers/platform/msm/ipa/ipa_v2/ipa_uc_ntn.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2016, The Linux Foundation. All rights reserved. +/* Copyright (c) 2016-2017, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -165,6 +165,17 @@ int ipa2_register_ipa_ready_cb(void (*ipa_ready_cb)(void *), void *user_data) return -EEXIST; } +int ipa2_ntn_uc_reg_rdyCB(void (*ipauc_ready_cb)(void *), void *priv) +{ + return ipa2_register_ipa_ready_cb(ipauc_ready_cb, priv); +} + +void ipa2_ntn_uc_dereg_rdyCB(void) +{ + ipa_ctx->uc_ntn_ctx.uc_ready_cb = NULL; + ipa_ctx->uc_ntn_ctx.priv = NULL; +} + static void ipa_uc_ntn_loaded_handler(void) { if (!ipa_ctx) { diff --git a/drivers/platform/msm/ipa/ipa_v2/ipa_utils.c b/drivers/platform/msm/ipa/ipa_v2/ipa_utils.c index 50a8e46d3b12..a9bd0e11b330 100644 --- a/drivers/platform/msm/ipa/ipa_v2/ipa_utils.c +++ b/drivers/platform/msm/ipa/ipa_v2/ipa_utils.c @@ -5155,6 +5155,8 @@ int ipa2_bind_api_controller(enum ipa_hw_type ipa_hw_type, api_ctrl->ipa_tear_down_uc_offload_pipes = ipa2_tear_down_uc_offload_pipes; api_ctrl->ipa_get_pdev = ipa2_get_pdev; + api_ctrl->ipa_ntn_uc_reg_rdyCB = ipa2_ntn_uc_reg_rdyCB; + api_ctrl->ipa_ntn_uc_dereg_rdyCB = ipa2_ntn_uc_dereg_rdyCB; return 0; } diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_i.h b/drivers/platform/msm/ipa/ipa_v3/ipa_i.h index 8ae714d4e7cc..5ff926a60129 100644 --- a/drivers/platform/msm/ipa/ipa_v3/ipa_i.h +++ b/drivers/platform/msm/ipa/ipa_v3/ipa_i.h @@ -1733,6 +1733,8 @@ int ipa3_setup_uc_ntn_pipes(struct ipa_ntn_conn_in_params *in, ipa_notify_cb notify, void *priv, u8 hdr_len, struct ipa_ntn_conn_out_params *outp); int ipa3_tear_down_uc_offload_pipes(int ipa_ep_idx_ul, int ipa_ep_idx_dl); +int ipa3_ntn_uc_reg_rdyCB(void (*ipauc_ready_cb)(void *), void *priv); +void ipa3_ntn_uc_dereg_rdyCB(void); /* * To retrieve doorbell physical address of diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_uc_ntn.c b/drivers/platform/msm/ipa/ipa_v3/ipa_uc_ntn.c index fdb6d05f683d..d4ff9c6ff851 100644 --- a/drivers/platform/msm/ipa/ipa_v3/ipa_uc_ntn.c +++ b/drivers/platform/msm/ipa/ipa_v3/ipa_uc_ntn.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2016, The Linux Foundation. All rights reserved. +/* Copyright (c) 2016-2017, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -149,6 +149,49 @@ int ipa3_get_ntn_stats(struct Ipa3HwStatsNTNInfoData_t *stats) return 0; } + +int ipa3_ntn_uc_reg_rdyCB(void (*ipa_ready_cb)(void *), void *user_data) +{ + int ret; + + if (!ipa3_ctx) { + IPAERR("IPA ctx is null\n"); + return -ENXIO; + } + + ret = ipa3_uc_state_check(); + if (ret) { + ipa3_ctx->uc_ntn_ctx.uc_ready_cb = ipa_ready_cb; + ipa3_ctx->uc_ntn_ctx.priv = user_data; + return 0; + } + + return -EEXIST; +} + +void ipa3_ntn_uc_dereg_rdyCB(void) +{ + ipa3_ctx->uc_ntn_ctx.uc_ready_cb = NULL; + ipa3_ctx->uc_ntn_ctx.priv = NULL; +} + +static void ipa3_uc_ntn_loaded_handler(void) +{ + if (!ipa3_ctx) { + IPAERR("IPA ctx is null\n"); + return; + } + + if (ipa3_ctx->uc_ntn_ctx.uc_ready_cb) { + ipa3_ctx->uc_ntn_ctx.uc_ready_cb( + ipa3_ctx->uc_ntn_ctx.priv); + + ipa3_ctx->uc_ntn_ctx.uc_ready_cb = + NULL; + ipa3_ctx->uc_ntn_ctx.priv = NULL; + } +} + int ipa3_ntn_init(void) { struct ipa3_uc_hdlrs uc_ntn_cbs = { 0 }; @@ -156,6 +199,8 @@ int ipa3_ntn_init(void) uc_ntn_cbs.ipa_uc_event_hdlr = ipa3_uc_ntn_event_handler; uc_ntn_cbs.ipa_uc_event_log_info_hdlr = ipa3_uc_ntn_event_log_info_handler; + uc_ntn_cbs.ipa_uc_loaded_hdlr = + ipa3_uc_ntn_loaded_handler; ipa3_uc_register_handlers(IPA_HW_FEATURE_NTN, &uc_ntn_cbs); diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_utils.c b/drivers/platform/msm/ipa/ipa_v3/ipa_utils.c index 4979f62b928f..29f2046610c8 100644 --- a/drivers/platform/msm/ipa/ipa_v3/ipa_utils.c +++ b/drivers/platform/msm/ipa/ipa_v3/ipa_utils.c @@ -3287,6 +3287,8 @@ int ipa3_bind_api_controller(enum ipa_hw_type ipa_hw_type, api_ctrl->ipa_tear_down_uc_offload_pipes = ipa3_tear_down_uc_offload_pipes; api_ctrl->ipa_get_pdev = ipa3_get_pdev; + api_ctrl->ipa_ntn_uc_reg_rdyCB = ipa3_ntn_uc_reg_rdyCB; + api_ctrl->ipa_ntn_uc_dereg_rdyCB = ipa3_ntn_uc_dereg_rdyCB; return 0; } diff --git a/drivers/power/supply/qcom/qpnp-fg-gen3.c b/drivers/power/supply/qcom/qpnp-fg-gen3.c index 8afd4b274335..626926e8b97d 100644 --- a/drivers/power/supply/qcom/qpnp-fg-gen3.c +++ b/drivers/power/supply/qcom/qpnp-fg-gen3.c @@ -1750,12 +1750,12 @@ static int fg_charge_full_update(struct fg_chip *chip) /* We need 2 most significant bytes here */ bsoc = (u32)bsoc >> 16; - rc = fg_get_msoc(chip, &msoc); + rc = fg_get_msoc_raw(chip, &msoc_raw); if (rc < 0) { - pr_err("Error in getting msoc, rc=%d\n", rc); + pr_err("Error in getting msoc_raw, rc=%d\n", rc); goto out; } - msoc_raw = DIV_ROUND_CLOSEST(msoc * FULL_SOC_RAW, FULL_CAPACITY); + msoc = DIV_ROUND_CLOSEST(msoc_raw * FULL_CAPACITY, FULL_SOC_RAW); fg_dbg(chip, FG_STATUS, "msoc: %d bsoc: %x health: %d status: %d full: %d\n", msoc, bsoc, chip->health, chip->charge_status, diff --git a/drivers/scsi/ufs/ufs-qcom.h b/drivers/scsi/ufs/ufs-qcom.h index 460213536e14..9d532691f001 100644 --- a/drivers/scsi/ufs/ufs-qcom.h +++ b/drivers/scsi/ufs/ufs-qcom.h @@ -21,6 +21,7 @@ #define MAX_UFS_QCOM_HOSTS 1 #define MAX_U32 (~(u32)0) #define MPHY_TX_FSM_STATE 0x41 +#define MPHY_RX_FSM_STATE 0xC1 #define TX_FSM_HIBERN8 0x1 #define HBRN8_POLL_TOUT_MS 100 #define DEFAULT_CLK_RATE_HZ 1000000 diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c index c23023f43d30..523a2cff44a3 100644 --- a/drivers/scsi/ufs/ufshcd.c +++ b/drivers/scsi/ufs/ufshcd.c @@ -839,6 +839,24 @@ static void ufshcd_print_tmrs(struct ufs_hba *hba, unsigned long bitmap) } } +static void ufshcd_print_fsm_state(struct ufs_hba *hba) +{ + int err = 0, tx_fsm_val = 0, rx_fsm_val = 0; + + err = ufshcd_dme_get(hba, + UIC_ARG_MIB_SEL(MPHY_TX_FSM_STATE, + UIC_ARG_MPHY_TX_GEN_SEL_INDEX(0)), + &tx_fsm_val); + dev_err(hba->dev, "%s: TX_FSM_STATE = %u, err = %d\n", __func__, + tx_fsm_val, err); + err = ufshcd_dme_get(hba, + UIC_ARG_MIB_SEL(MPHY_RX_FSM_STATE, + UIC_ARG_MPHY_RX_GEN_SEL_INDEX(0)), + &rx_fsm_val); + dev_err(hba->dev, "%s: RX_FSM_STATE = %u, err = %d\n", __func__, + rx_fsm_val, err); +} + static void ufshcd_print_host_state(struct ufs_hba *hba) { if (!(hba->ufshcd_dbg_print & UFSHCD_DBG_PRINT_HOST_STATE_EN)) @@ -863,6 +881,7 @@ static void ufshcd_print_host_state(struct ufs_hba *hba) hba->capabilities, hba->caps); dev_err(hba->dev, "quirks=0x%x, dev. quirks=0x%x\n", hba->quirks, hba->dev_quirks); + ufshcd_print_fsm_state(hba); } /** diff --git a/drivers/usb/dwc3/dwc3-msm.c b/drivers/usb/dwc3/dwc3-msm.c index 5ad68df298cd..3c0f68deee34 100644 --- a/drivers/usb/dwc3/dwc3-msm.c +++ b/drivers/usb/dwc3/dwc3-msm.c @@ -233,6 +233,7 @@ struct dwc3_msm { struct pm_qos_request pm_qos_req_dma; struct delayed_work perf_vote_work; struct delayed_work sdp_check; + struct mutex suspend_resume_mutex; }; #define USB_HSPHY_3P3_VOL_MIN 3050000 /* uV */ @@ -1997,8 +1998,10 @@ static int dwc3_msm_suspend(struct dwc3_msm *mdwc) dbg_event(0xFF, "Ctl Sus", atomic_read(&dwc->in_lpm)); + mutex_lock(&mdwc->suspend_resume_mutex); if (atomic_read(&dwc->in_lpm)) { dev_dbg(mdwc->dev, "%s: Already suspended\n", __func__); + mutex_unlock(&mdwc->suspend_resume_mutex); return 0; } @@ -2015,6 +2018,7 @@ static int dwc3_msm_suspend(struct dwc3_msm *mdwc) __func__, evt->count / 4); dbg_print_reg("PENDING DEVICE EVENT", *(u32 *)(evt->buf + evt->lpos)); + mutex_unlock(&mdwc->suspend_resume_mutex); return -EBUSY; } } @@ -2034,6 +2038,7 @@ static int dwc3_msm_suspend(struct dwc3_msm *mdwc) dev_dbg(mdwc->dev, "%s: cable disconnected while not in idle otg state\n", __func__); + mutex_unlock(&mdwc->suspend_resume_mutex); return -EBUSY; } @@ -2047,12 +2052,15 @@ static int dwc3_msm_suspend(struct dwc3_msm *mdwc) pr_err("%s(): Trying to go in LPM with state:%d\n", __func__, dwc->gadget.state); pr_err("%s(): LPM is not performed.\n", __func__); + mutex_unlock(&mdwc->suspend_resume_mutex); return -EBUSY; } ret = dwc3_msm_prepare_suspend(mdwc); - if (ret) + if (ret) { + mutex_unlock(&mdwc->suspend_resume_mutex); return ret; + } /* Initialize variables here */ can_suspend_ssphy = !(mdwc->in_host_mode && @@ -2153,6 +2161,7 @@ static int dwc3_msm_suspend(struct dwc3_msm *mdwc) } dev_info(mdwc->dev, "DWC3 in low power mode\n"); + mutex_unlock(&mdwc->suspend_resume_mutex); return 0; } @@ -2164,8 +2173,10 @@ static int dwc3_msm_resume(struct dwc3_msm *mdwc) dev_dbg(mdwc->dev, "%s: exiting lpm\n", __func__); + mutex_lock(&mdwc->suspend_resume_mutex); if (!atomic_read(&dwc->in_lpm)) { dev_dbg(mdwc->dev, "%s: Already resumed\n", __func__); + mutex_unlock(&mdwc->suspend_resume_mutex); return 0; } @@ -2300,6 +2311,7 @@ static int dwc3_msm_resume(struct dwc3_msm *mdwc) msecs_to_jiffies(1000 * PM_QOS_SAMPLE_SEC)); dbg_event(0xFF, "Ctl Res", atomic_read(&dwc->in_lpm)); + mutex_unlock(&mdwc->suspend_resume_mutex); return 0; } @@ -3179,6 +3191,7 @@ static int dwc3_msm_probe(struct platform_device *pdev) POWER_SUPPLY_PROP_PRESENT, &pval); } + mutex_init(&mdwc->suspend_resume_mutex); /* Update initial VBUS/ID state from extcon */ if (mdwc->extcon_vbus && extcon_get_cable_state_(mdwc->extcon_vbus, EXTCON_USB)) diff --git a/drivers/usb/gadget/composite.c b/drivers/usb/gadget/composite.c index 442d44278f33..22ba45f40f0b 100644 --- a/drivers/usb/gadget/composite.c +++ b/drivers/usb/gadget/composite.c @@ -2088,7 +2088,7 @@ static ssize_t suspended_show(struct device *dev, struct device_attribute *attr, struct usb_gadget *gadget = dev_to_usb_gadget(dev); struct usb_composite_dev *cdev = get_gadget_data(gadget); - return sprintf(buf, "%d\n", cdev->suspended); + return snprintf(buf, PAGE_SIZE, "%d\n", cdev->suspended); } static DEVICE_ATTR_RO(suspended); diff --git a/drivers/video/fbdev/msm/mdss_hdmi_tx.c b/drivers/video/fbdev/msm/mdss_hdmi_tx.c index 13c57f811a81..af95a4a6dccd 100644 --- a/drivers/video/fbdev/msm/mdss_hdmi_tx.c +++ b/drivers/video/fbdev/msm/mdss_hdmi_tx.c @@ -3160,6 +3160,10 @@ static int hdmi_tx_power_off(struct hdmi_tx_ctrl *hdmi_ctrl) if (hdmi_ctrl->panel_ops.off) hdmi_ctrl->panel_ops.off(pdata); + hdmi_tx_set_mode(hdmi_ctrl, false); + hdmi_tx_phy_reset(hdmi_ctrl); + hdmi_tx_set_mode(hdmi_ctrl, true); + hdmi_tx_core_off(hdmi_ctrl); hdmi_ctrl->panel_power_on = false; diff --git a/include/linux/ipa_uc_offload.h b/include/linux/ipa_uc_offload.h index 0277e87a2570..85d0ce92e6f6 100644 --- a/include/linux/ipa_uc_offload.h +++ b/include/linux/ipa_uc_offload.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2016, The Linux Foundation. All rights reserved. +/* Copyright (c) 2016-2017, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -163,6 +163,20 @@ struct ipa_perf_profile { u32 max_supported_bw_mbps; }; +/** + * struct ipa_uc_ready_params - uC ready CB parameters + * @is_uC_ready: uC loaded or not + * @priv : callback cookie + * @notify: callback + * @proto: uC offload protocol type + */ +struct ipa_uc_ready_params { + bool is_uC_ready; + void *priv; + ipa_uc_ready_cb notify; + enum ipa_uc_offload_proto proto; +}; + #if defined CONFIG_IPA || defined CONFIG_IPA3 /** @@ -223,6 +237,19 @@ int ipa_uc_offload_disconn_pipes(u32 clnt_hdl); */ int ipa_set_perf_profile(struct ipa_perf_profile *profile); + +/* + * To register uC ready callback if uC not ready + * and also check uC readiness + * if uC not ready only, register callback + */ +int ipa_uc_offload_reg_rdyCB(struct ipa_uc_ready_params *param); + +/* + * To de-register uC ready callback + */ +void ipa_uc_offload_dereg_rdyCB(enum ipa_uc_offload_proto proto); + #else /* (CONFIG_IPA || CONFIG_IPA3) */ static inline int ipa_uc_offload_reg_intf( @@ -254,6 +281,15 @@ static inline int ipa_set_perf_profile(struct ipa_perf_profile *profile) return -EPERM; } +static inline int ipa_uc_offload_reg_rdyCB(struct ipa_uc_ready_params *param) +{ + return -EPERM; +} + +static void ipa_uc_offload_dereg_rdyCB(enum ipa_uc_offload_proto proto) +{ +} + #endif /* CONFIG_IPA3 */ #endif /* _IPA_UC_OFFLOAD_H_ */ |
