From 7b28cf7543057bde0693cf906248a0ba5ea5122c Mon Sep 17 00:00:00 2001 From: Ingrid Gallardo Date: Mon, 17 Oct 2016 14:58:58 -0700 Subject: msm: mdss: fix pp timeout during transition from LP1 to power on Skip "ctl setup" during LP1 to Display ON transition, since this causes ping pong timeout due incorrect SW programming; issue happens under following two conditions: 1. When the PP done is not received for the previous frame, reprogramming the non-double buffered registers to default value will cause MDP hang. 2. When last frame before LP1 state was partial update, then we exit LP1 mode, the next frame is also partial update then user-space and kernel do not change the SSPP registers which remain for the partial update frame. However due the "ctl setup", the mixer alone changes to full frame, causing the next frame to hang. This change address both scenarios described above. Change-Id: I031ca48f0e0c39f1b2cb51081ecd55b086fb4c9b Signed-off-by: Ingrid Gallardo --- drivers/video/fbdev/msm/mdss_mdp_ctl.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/drivers/video/fbdev/msm/mdss_mdp_ctl.c b/drivers/video/fbdev/msm/mdss_mdp_ctl.c index eb1e0b5c47a6..9aa7de952cd6 100644 --- a/drivers/video/fbdev/msm/mdss_mdp_ctl.c +++ b/drivers/video/fbdev/msm/mdss_mdp_ctl.c @@ -4178,9 +4178,11 @@ int mdss_mdp_ctl_start(struct mdss_mdp_ctl *ctl, bool handoff) return 0; } - ret = mdss_mdp_ctl_setup(ctl); - if (ret) - return ret; + if (mdss_mdp_ctl_is_power_off(ctl)) { + ret = mdss_mdp_ctl_setup(ctl); + if (ret) + return ret; + } sctl = mdss_mdp_get_split_ctl(ctl); -- cgit v1.2.3 From badf0ba0b466a9c7ee4f6cac7f0279a136508ff7 Mon Sep 17 00:00:00 2001 From: Subhash Jadavani Date: Tue, 18 Oct 2016 18:30:55 -0700 Subject: scsi: ufs: handle LINERESET during hibern8 If LINERESET was detected during Hibern8 operation, link moves to default PWM-G1 mode hence full reinit is required to move link to HS speeds. Change-Id: I4cdcbd31b5fa5ceac0eea7c743ea9286f231b80b Signed-off-by: Subhash Jadavani --- drivers/scsi/ufs/ufshcd.c | 34 +++++++++++++++++++++++++++++----- drivers/scsi/ufs/ufshcd.h | 2 ++ drivers/scsi/ufs/ufshci.h | 1 + 3 files changed, 32 insertions(+), 5 deletions(-) diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c index 862d56e78086..b5d08cfaa694 100644 --- a/drivers/scsi/ufs/ufshcd.c +++ b/drivers/scsi/ufs/ufshcd.c @@ -4132,7 +4132,13 @@ static int __ufshcd_uic_hibern8_enter(struct ufs_hba *hba) trace_ufshcd_profile_hibern8(dev_name(hba->dev), "enter", ktime_to_us(ktime_sub(ktime_get(), start)), ret); - if (ret) { + /* + * Do full reinit if enter failed or if LINERESET was detected during + * Hibern8 operation. After LINERESET, link moves to default PWM-G1 + * mode hence full reinit is required to move link to HS speeds. + */ + if (ret || hba->full_init_linereset) { + hba->full_init_linereset = false; ufshcd_update_error_stats(hba, UFS_ERR_HIBERN8_ENTER); dev_err(hba->dev, "%s: hibern8 enter failed. ret = %d", __func__, ret); @@ -4175,8 +4181,13 @@ int ufshcd_uic_hibern8_exit(struct ufs_hba *hba) ret = ufshcd_uic_pwr_ctrl(hba, &uic_cmd); trace_ufshcd_profile_hibern8(dev_name(hba->dev), "exit", ktime_to_us(ktime_sub(ktime_get(), start)), ret); - - if (ret) { + /* + * Do full reinit if exit failed or if LINERESET was detected during + * Hibern8 operation. After LINERESET, link moves to default PWM-G1 + * mode hence full reinit is required to move link to HS speeds. + */ + if (ret || hba->full_init_linereset) { + hba->full_init_linereset = false; ufshcd_update_error_stats(hba, UFS_ERR_HIBERN8_EXIT); dev_err(hba->dev, "%s: hibern8 exit failed. ret = %d", __func__, ret); @@ -5827,9 +5838,8 @@ static void ufshcd_update_uic_error(struct ufs_hba *hba) /* PHY layer lane error */ reg = ufshcd_readl(hba, REG_UIC_ERROR_CODE_PHY_ADAPTER_LAYER); - /* Ignore LINERESET indication, as this is not an error */ if ((reg & UIC_PHY_ADAPTER_LAYER_ERROR) && - (reg & UIC_PHY_ADAPTER_LAYER_LANE_ERR_MASK)) { + (reg & UIC_PHY_ADAPTER_LAYER_ERROR_CODE_MASK)) { /* * To know whether this error is fatal or not, DB timeout * must be checked but this error is handled separately. @@ -5837,6 +5847,20 @@ static void ufshcd_update_uic_error(struct ufs_hba *hba) dev_dbg(hba->dev, "%s: UIC Lane error reported, reg 0x%x\n", __func__, reg); ufshcd_update_uic_reg_hist(&hba->ufs_stats.pa_err, reg); + + /* Don't ignore LINERESET indication during hibern8 operation */ + if (reg & UIC_PHY_ADAPTER_LAYER_GENERIC_ERROR) { + struct uic_command *cmd = hba->active_uic_cmd; + + if (cmd) { + if ((cmd->command == UIC_CMD_DME_HIBER_ENTER) + || (cmd->command == UIC_CMD_DME_HIBER_EXIT)) { + dev_err(hba->dev, "%s: LINERESET during hibern8, reg 0x%x\n", + __func__, reg); + hba->full_init_linereset = true; + } + } + } } /* PA_INIT_ERROR is fatal and needs UIC reset */ diff --git a/drivers/scsi/ufs/ufshcd.h b/drivers/scsi/ufs/ufshcd.h index c0714b7bea72..94d6d7b67ca6 100644 --- a/drivers/scsi/ufs/ufshcd.h +++ b/drivers/scsi/ufs/ufshcd.h @@ -902,6 +902,8 @@ struct ufs_hba { bool no_ref_clk_gating; int scsi_block_reqs_cnt; + + bool full_init_linereset; }; /* Returns true if clocks can be gated. Otherwise false */ diff --git a/drivers/scsi/ufs/ufshci.h b/drivers/scsi/ufs/ufshci.h index d65dad03bdd2..c0e4650a75ad 100644 --- a/drivers/scsi/ufs/ufshci.h +++ b/drivers/scsi/ufs/ufshci.h @@ -190,6 +190,7 @@ enum { /* UECPA - Host UIC Error Code PHY Adapter Layer 38h */ #define UIC_PHY_ADAPTER_LAYER_ERROR UFS_BIT(31) +#define UIC_PHY_ADAPTER_LAYER_GENERIC_ERROR UFS_BIT(4) #define UIC_PHY_ADAPTER_LAYER_ERROR_CODE_MASK 0x1F #define UIC_PHY_ADAPTER_LAYER_LANE_ERR_MASK 0xF -- cgit v1.2.3 From dd7cca1b85df85a4834f3236fb12d9005759fefd Mon Sep 17 00:00:00 2001 From: Skylar Chang Date: Tue, 4 Oct 2016 14:15:25 -0700 Subject: msm: ipa3: header file change for wdi-stats Add structure changes for querying WDI-stats, wlan needs register the callback functions for IPA to query WDI stats and sets the quota limit on STA mode. Change-Id: I62de66e9b0bb1eeeac3c94d1ac1037285811b631 Signed-off-by: Skylar Chang --- include/linux/ipa.h | 64 ++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 63 insertions(+), 1 deletion(-) diff --git a/include/linux/ipa.h b/include/linux/ipa.h index e66d388651b8..c3ffe51d8069 100644 --- a/include/linux/ipa.h +++ b/include/linux/ipa.h @@ -98,7 +98,7 @@ enum ipa_dp_evt_type { }; /** - * enum hdr_total_len_or_pad_type - type vof alue held by TOTAL_LEN_OR_PAD + * enum hdr_total_len_or_pad_type - type of value held by TOTAL_LEN_OR_PAD * field in header configuration register. * @IPA_HDR_PAD: field is used as padding length * @IPA_HDR_TOTAL_LEN: field is used as total length @@ -432,6 +432,55 @@ struct ipa_ep_cfg_ctrl { typedef void (*ipa_notify_cb)(void *priv, enum ipa_dp_evt_type evt, unsigned long data); +/** + * enum ipa_wdi_meter_evt_type - type of event client callback is + * for AP+STA mode metering + * @IPA_GET_WDI_SAP_STATS: get IPA_stats betwen SAP and STA - + * use ipa_get_wdi_sap_stats structure + * @IPA_SET_WIFI_QUOTA: set quota limit on STA - + * use ipa_set_wifi_quota structure + */ +enum ipa_wdi_meter_evt_type { + IPA_GET_WDI_SAP_STATS, + IPA_SET_WIFI_QUOTA, +}; + +struct ipa_get_wdi_sap_stats { + /* indicate to reset stats after query */ + uint8_t reset_stats; + /* indicate valid stats from wlan-fw */ + uint8_t stats_valid; + /* Tx: SAP->STA */ + uint64_t ipv4_tx_packets; + uint64_t ipv4_tx_bytes; + /* Rx: STA->SAP */ + uint64_t ipv4_rx_packets; + uint64_t ipv4_rx_bytes; + uint64_t ipv6_tx_packets; + uint64_t ipv6_tx_bytes; + uint64_t ipv6_rx_packets; + uint64_t ipv6_rx_bytes; +}; + +/** + * struct ipa_set_wifi_quota - structure used for + * IPA_SET_WIFI_QUOTA. + * + * @quota_bytes: Quota (in bytes) for the STA interface. + * @set_quota: Indicate whether to set the quota (use 1) or + * unset the quota. + * + */ +struct ipa_set_wifi_quota { + uint64_t quota_bytes; + uint8_t set_quota; + /* indicate valid quota set from wlan-fw */ + uint8_t set_valid; +}; + +typedef void (*ipa_wdi_meter_notifier_cb)(enum ipa_wdi_meter_evt_type evt, + void *data); + /** * struct ipa_connect_params - low-level client connect input parameters. Either * client allocates the data and desc FIFO and specifies that in data+desc OR @@ -1001,6 +1050,7 @@ struct ipa_wdi_dl_params_smmu { * @ul_smmu: WDI_RX configuration info when WLAN uses SMMU * @dl_smmu: WDI_TX configuration info when WLAN uses SMMU * @smmu_enabled: true if WLAN uses SMMU + * @ipa_wdi_meter_notifier_cb: Get WDI stats and quato info */ struct ipa_wdi_in_params { struct ipa_sys_connect_params sys; @@ -1011,6 +1061,9 @@ struct ipa_wdi_in_params { struct ipa_wdi_dl_params_smmu dl_smmu; } u; bool smmu_enabled; +#ifdef IPA_WAN_MSG_IPv6_ADDR_GW_LEN + ipa_wdi_meter_notifier_cb wdi_notify; +#endif }; /** @@ -1265,6 +1318,9 @@ int ipa_resume_wdi_pipe(u32 clnt_hdl); int ipa_suspend_wdi_pipe(u32 clnt_hdl); int ipa_get_wdi_stats(struct IpaHwStatsWDIInfoData_t *stats); u16 ipa_get_smem_restr_bytes(void); +int ipa_broadcast_wdi_quota_reach_ind(uint32_t fid, + uint64_t num_bytes); + /* * To retrieve doorbell physical address of * wlan pipes @@ -1845,6 +1901,12 @@ static inline int ipa_suspend_wdi_pipe(u32 clnt_hdl) return -EPERM; } +static inline int ipa_broadcast_wdi_quota_reach_ind(uint32_t fid, + uint64_t num_bytes) +{ + return -EPERM; +} + static inline int ipa_uc_wdi_get_dbpa( struct ipa_wdi_db_params *out) { -- cgit v1.2.3 From 97bbda1d365611e8be4d4a8c4f80325f24b0895f Mon Sep 17 00:00:00 2001 From: Ingrid Gallardo Date: Wed, 26 Oct 2016 16:46:54 -0700 Subject: msm: mdss: fix autorefresh disable during handoff To disable autorefresh feature, driver needs to make sure that no transaction is on-going before disable. This change enforce that the sequence to disable autorefresh is followed during the handoff to kernel. Change-Id: I9aa7a000e75b50c6b26970deaba2131c87087b8c Signed-off-by: Ingrid Gallardo --- drivers/video/fbdev/msm/mdss_mdp_intf_cmd.c | 105 +++++++++++++++++++++------- 1 file changed, 79 insertions(+), 26 deletions(-) diff --git a/drivers/video/fbdev/msm/mdss_mdp_intf_cmd.c b/drivers/video/fbdev/msm/mdss_mdp_intf_cmd.c index 4eb121f01aca..b8e2fac37dc9 100644 --- a/drivers/video/fbdev/msm/mdss_mdp_intf_cmd.c +++ b/drivers/video/fbdev/msm/mdss_mdp_intf_cmd.c @@ -335,6 +335,57 @@ static int mdss_mdp_cmd_tearcheck_cfg(struct mdss_mdp_mixer *mixer, return 0; } +static bool __disable_rd_ptr_from_te(char __iomem *pingpong_base) +{ + u32 cfg; + bool disabled; + + cfg = mdss_mdp_pingpong_read(pingpong_base, + MDSS_MDP_REG_PP_SYNC_CONFIG_VSYNC); + + disabled = BIT(20) & cfg; + cfg &= ~BIT(20); + mdss_mdp_pingpong_write(pingpong_base, + MDSS_MDP_REG_PP_SYNC_CONFIG_VSYNC, cfg); + + return disabled; +} + +static inline void __enable_rd_ptr_from_te(char __iomem *pingpong_base) +{ + u32 cfg; + + cfg = mdss_mdp_pingpong_read(pingpong_base, + MDSS_MDP_REG_PP_SYNC_CONFIG_VSYNC); + cfg |= BIT(20); + mdss_mdp_pingpong_write(pingpong_base, + MDSS_MDP_REG_PP_SYNC_CONFIG_VSYNC, cfg); +} + +/* +* __disable_autorefresh - disables autorefresh feature in the hw. +* +* To disable autorefresh, driver needs to make sure no transactions are +* on-going; for ensuring this, driver must: +* +* 1. Disable listening to the external TE (this gives extra time before +* trigger next transaction). +* 2. Wait for any on-going transaction (wait for ping pong done interrupt). +* 3. Disable auto-refresh. +* 4. Re-enable listening to the external panel TE. +* +* So it is responsability of the caller of this function to only call to disable +* autorefresh if no hw transaction is on-going (wait for ping pong) and if +* the listening for the external TE is disabled in the tear check logic (this +* to prevent any race conditions with the hw), as mentioned in the above +* steps. +*/ +static inline void __disable_autorefresh(char __iomem *pingpong_base) +{ + mdss_mdp_pingpong_write(pingpong_base, + MDSS_MDP_REG_PP_AUTOREFRESH_CONFIG, 0x0); +} + static int mdss_mdp_cmd_tearcheck_setup(struct mdss_mdp_cmd_ctx *ctx, bool locked) { @@ -342,7 +393,7 @@ static int mdss_mdp_cmd_tearcheck_setup(struct mdss_mdp_cmd_ctx *ctx, struct mdss_mdp_mixer *mixer = NULL, *mixer_right = NULL; struct mdss_mdp_ctl *ctl = ctx->ctl; struct mdss_data_type *mdata = mdss_mdp_get_mdata(); - u32 offset = 0; + bool rd_ptr_disabled = false; mixer = mdss_mdp_mixer_get(ctl, MDSS_MDP_MIXER_MUX_LEFT); if (mixer) { @@ -352,21 +403,32 @@ static int mdss_mdp_cmd_tearcheck_setup(struct mdss_mdp_cmd_ctx *ctx, */ if (mdss_mdp_pingpong_read(mixer->pingpong_base, MDSS_MDP_REG_PP_AUTOREFRESH_CONFIG) & BIT(31)) { - offset = MDSS_MDP_REG_PP_AUTOREFRESH_CONFIG; + + /* 1. disable rd pointer from the external te */ + rd_ptr_disabled = + __disable_rd_ptr_from_te(mixer->pingpong_base); + + /* 2. disable autorefresh */ if (is_pingpong_split(ctl->mfd)) - writel_relaxed(0x0, - (mdata->slave_pingpong_base + offset)); + __disable_autorefresh( + mdata->slave_pingpong_base); + if (is_split_lm(ctl->mfd)) { - mixer_right = - mdss_mdp_mixer_get(ctl, - MDSS_MDP_MIXER_MUX_RIGHT); + mixer_right = mdss_mdp_mixer_get(ctl, + MDSS_MDP_MIXER_MUX_RIGHT); + if (mixer_right) - writel_relaxed(0x0, - (mixer_right->pingpong_base + offset)); + __disable_autorefresh( + mixer_right->pingpong_base); } - mdss_mdp_pingpong_write(mixer->pingpong_base, - MDSS_MDP_REG_PP_AUTOREFRESH_CONFIG, 0x0); + + __disable_autorefresh(mixer->pingpong_base); pr_debug("%s: disabling auto refresh\n", __func__); + + /* 2. re-enable rd pointer from te (if was enabled) */ + if (rd_ptr_disabled) + __enable_rd_ptr_from_te(mixer->pingpong_base); + } rc = mdss_mdp_cmd_tearcheck_cfg(mixer, ctx, locked); if (rc) @@ -2350,7 +2412,6 @@ static void mdss_mdp_cmd_pre_programming(struct mdss_mdp_ctl *mctl) struct mdss_mdp_cmd_ctx *ctx = mctl->intf_ctx[MASTER_CTX]; char __iomem *pp_base; u32 autorefresh_state; - u32 cfg; if (!mctl->is_master) return; @@ -2370,11 +2431,8 @@ static void mdss_mdp_cmd_pre_programming(struct mdss_mdp_ctl *mctl) * instruct MDP to ignore the panel TE so the next auto-refresh * is delayed until flush bits are set. */ - cfg = mdss_mdp_pingpong_read(pp_base, - MDSS_MDP_REG_PP_SYNC_CONFIG_VSYNC); - cfg &= ~BIT(20); - mdss_mdp_pingpong_write(pp_base, - MDSS_MDP_REG_PP_SYNC_CONFIG_VSYNC, cfg); + __disable_rd_ptr_from_te(pp_base); + ctx->ignore_external_te = true; } @@ -2386,7 +2444,6 @@ static void mdss_mdp_cmd_post_programming(struct mdss_mdp_ctl *mctl) { struct mdss_mdp_cmd_ctx *ctx = mctl->intf_ctx[MASTER_CTX]; char __iomem *pp_base; - u32 cfg; if (!mctl->is_master) return; @@ -2405,11 +2462,8 @@ static void mdss_mdp_cmd_post_programming(struct mdss_mdp_ctl *mctl) pp_base = mctl->mixer_left->pingpong_base; /* enable MDP to listen to the TE */ - cfg = mdss_mdp_pingpong_read(pp_base, - MDSS_MDP_REG_PP_SYNC_CONFIG_VSYNC); - cfg |= BIT(20); - mdss_mdp_pingpong_write(pp_base, - MDSS_MDP_REG_PP_SYNC_CONFIG_VSYNC, cfg); + __enable_rd_ptr_from_te(pp_base); + ctx->ignore_external_te = false; } } @@ -2661,11 +2715,10 @@ static int mdss_mdp_disable_autorefresh(struct mdss_mdp_ctl *ctl, mdss_mdp_cmd_wait4_autorefresh_pp(sctl); /* disable autorefresh */ - mdss_mdp_pingpong_write(pp_base, MDSS_MDP_REG_PP_AUTOREFRESH_CONFIG, 0); + __disable_autorefresh(pp_base); if (is_pingpong_split(ctl->mfd)) - mdss_mdp_pingpong_write(mdata->slave_pingpong_base, - MDSS_MDP_REG_PP_AUTOREFRESH_CONFIG, 0); + __disable_autorefresh(mdata->slave_pingpong_base); ctx->autorefresh_state = MDP_AUTOREFRESH_OFF; ctx->autorefresh_frame_cnt = 0; -- cgit v1.2.3 From 0cadb95acf9ab6204d35e3c3ead54be96bcb1752 Mon Sep 17 00:00:00 2001 From: Siena Richard Date: Thu, 29 Sep 2016 13:29:26 -0700 Subject: Asoc: clean up bootup errors Fix errors shown during bootup to ensure robustness and enable cleaner bootup process. Change-Id: Idc9ca896b3fe6c1c6a72a066a6e453d27a3173e8 Signed-off-by: Siena Richard CRs-fixed: 1073250 --- sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c | 153 +++++++++++++++++------------ sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.h | 22 +++-- 2 files changed, 102 insertions(+), 73 deletions(-) diff --git a/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c b/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c index 13d4ba27d990..773e942bab8c 100644 --- a/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c +++ b/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c @@ -280,11 +280,19 @@ struct msm_pcm_routing_bdai_data msm_bedais[MSM_BACKEND_DAI_MAX] = { { SLIMBUS_1_RX, 0, 0, {0}, 0, 0, 0, 0, 0, LPASS_BE_SLIMBUS_1_RX}, { SLIMBUS_1_TX, 0, 0, {0}, 0, 0, 0, 0, 0, LPASS_BE_SLIMBUS_1_TX}, { SLIMBUS_2_RX, 0, 0, {0}, 0, 0, 0, 0, 0, LPASS_BE_SLIMBUS_2_RX}, - { SLIMBUS_4_RX, 0, 0, {0}, 0, 0, 0, 0, 0, LPASS_BE_SLIMBUS_4_RX}, - { SLIMBUS_4_TX, 0, 0, {0}, 0, 0, 0, 0, 0, LPASS_BE_SLIMBUS_4_TX}, + { SLIMBUS_2_TX, 0, 0, {0}, 0, 0, 0, 0, 0, LPASS_BE_SLIMBUS_2_TX}, { SLIMBUS_3_RX, 0, 0, {0}, 0, 0, 0, 0, 0, LPASS_BE_SLIMBUS_3_RX}, { SLIMBUS_3_TX, 0, 0, {0}, 0, 0, 0, 0, 0, LPASS_BE_SLIMBUS_3_TX}, + { SLIMBUS_4_RX, 0, 0, {0}, 0, 0, 0, 0, 0, LPASS_BE_SLIMBUS_4_RX}, + { SLIMBUS_4_TX, 0, 0, {0}, 0, 0, 0, 0, 0, LPASS_BE_SLIMBUS_4_TX}, + { SLIMBUS_5_RX, 0, 0, {0}, 0, 0, 0, 0, 0, LPASS_BE_SLIMBUS_5_RX}, { SLIMBUS_5_TX, 0, 0, {0}, 0, 0, 0, 0, 0, LPASS_BE_SLIMBUS_5_TX}, + { SLIMBUS_6_RX, 0, 0, {0}, 0, 0, 0, 0, 0, LPASS_BE_SLIMBUS_6_RX}, + { SLIMBUS_6_TX, 0, 0, {0}, 0, 0, 0, 0, 0, LPASS_BE_SLIMBUS_6_TX}, + { SLIMBUS_7_RX, 0, 0, {0}, 0, 0, 0, 0, 0, LPASS_BE_SLIMBUS_7_RX}, + { SLIMBUS_7_TX, 0, 0, {0}, 0, 0, 0, 0, 0, LPASS_BE_SLIMBUS_7_TX}, + { SLIMBUS_8_RX, 0, 0, {0}, 0, 0, 0, 0, 0, LPASS_BE_SLIMBUS_8_RX}, + { SLIMBUS_8_TX, 0, 0, {0}, 0, 0, 0, 0, 0, LPASS_BE_SLIMBUS_8_TX}, { SLIMBUS_EXTPROC_RX, 0, 0, {0}, 0, 0, 0, 0, 0, LPASS_BE_STUB_RX}, { SLIMBUS_EXTPROC_RX, 0, 0, {0}, 0, 0, 0, 0, 0, LPASS_BE_STUB_TX}, { SLIMBUS_EXTPROC_RX, 0, 0, {0}, 0, 0, 0, 0, 0, LPASS_BE_STUB_1_TX}, @@ -310,12 +318,9 @@ struct msm_pcm_routing_bdai_data msm_bedais[MSM_BACKEND_DAI_MAX] = { LPASS_BE_SEC_AUXPCM_RX}, { AFE_PORT_ID_SECONDARY_PCM_TX, 0, 0, {0}, 0, 0, 0, 0, 0, LPASS_BE_SEC_AUXPCM_TX}, - { SLIMBUS_6_RX, 0, 0, {0}, 0, 0, 0, 0, 0, LPASS_BE_SLIMBUS_6_RX}, - { SLIMBUS_6_TX, 0, 0, {0}, 0, 0, 0, 0, 0, LPASS_BE_SLIMBUS_6_TX}, { AFE_PORT_ID_SPDIF_RX, 0, 0, {0}, 0, 0, 0, 0, 0, LPASS_BE_SPDIF_RX}, { AFE_PORT_ID_SECONDARY_MI2S_RX_SD1, 0, 0, {0}, 0, 0, 0, 0, 0, LPASS_BE_SEC_MI2S_RX_SD1}, - { SLIMBUS_5_RX, 0, 0, {0}, 0, 0, 0, 0, 0, LPASS_BE_SLIMBUS_5_RX}, { AFE_PORT_ID_QUINARY_MI2S_RX, 0, 0, {0}, 0, 0, 0, 0, 0, LPASS_BE_QUIN_MI2S_RX}, { AFE_PORT_ID_QUINARY_MI2S_TX, 0, 0, {0}, 0, 0, 0, 0, 0, @@ -451,10 +456,6 @@ struct msm_pcm_routing_bdai_data msm_bedais[MSM_BACKEND_DAI_MAX] = { { AFE_PORT_ID_QUATERNARY_TDM_TX_7, 0, 0, {0}, 0, 0, 0, 0, 0, LPASS_BE_QUAT_TDM_TX_7}, { INT_BT_A2DP_RX, 0, 0, {0}, 0, 0, 0, 0, 0, LPASS_BE_INT_BT_A2DP_RX}, - { SLIMBUS_7_RX, 0, 0, {0}, 0, 0, 0, 0, 0, LPASS_BE_SLIMBUS_7_RX}, - { SLIMBUS_7_TX, 0, 0, {0}, 0, 0, 0, 0, 0, LPASS_BE_SLIMBUS_7_TX}, - { SLIMBUS_8_RX, 0, 0, {0}, 0, 0, 0, 0, 0, LPASS_BE_SLIMBUS_8_RX}, - { SLIMBUS_8_TX, 0, 0, {0}, 0, 0, 0, 0, 0, LPASS_BE_SLIMBUS_8_TX}, { AFE_PORT_ID_USB_RX, 0, 0, {0}, 0, 0, 0, 0, 0, LPASS_BE_USB_AUDIO_RX}, { AFE_PORT_ID_USB_TX, 0, 0, {0}, 0, 0, 0, 0, 0, LPASS_BE_USB_AUDIO_TX}, { DISPLAY_PORT_RX, 0, 0, {0}, 0, 0, 0, 0, 0, LPASS_BE_DISPLAY_PORT}, @@ -2199,6 +2200,11 @@ static const struct snd_kcontrol_new ext_ec_ref_mux_ul2 = msm_route_ec_ref_rx_enum[0], msm_routing_ec_ref_rx_get, msm_routing_ec_ref_rx_put); +static const struct snd_kcontrol_new ext_ec_ref_mux_ul3 = + SOC_DAPM_ENUM_EXT("AUDIO_REF_EC_UL3 MUX Mux", + msm_route_ec_ref_rx_enum[0], + msm_routing_ec_ref_rx_get, msm_routing_ec_ref_rx_put); + static const struct snd_kcontrol_new ext_ec_ref_mux_ul4 = SOC_DAPM_ENUM_EXT("AUDIO_REF_EC_UL4 MUX Mux", msm_route_ec_ref_rx_enum[0], @@ -2776,9 +2782,15 @@ static const struct snd_kcontrol_new tertiary_mi2s_rx_mixer_controls[] = { SOC_SINGLE_EXT("MultiMedia4", MSM_BACKEND_DAI_TERTIARY_MI2S_RX, MSM_FRONTEND_DAI_MULTIMEDIA4, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), + SOC_SINGLE_EXT("MultiMedia5", MSM_BACKEND_DAI_TERTIARY_MI2S_RX, + MSM_FRONTEND_DAI_MULTIMEDIA5, 1, 0, msm_routing_get_audio_mixer, + msm_routing_put_audio_mixer), SOC_SINGLE_EXT("MultiMedia7", MSM_BACKEND_DAI_TERTIARY_MI2S_RX, MSM_FRONTEND_DAI_MULTIMEDIA7, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), + SOC_SINGLE_EXT("MultiMedia8", MSM_BACKEND_DAI_TERTIARY_MI2S_RX, + MSM_FRONTEND_DAI_MULTIMEDIA8, 1, 0, msm_routing_get_audio_mixer, + msm_routing_put_audio_mixer), SOC_SINGLE_EXT("MultiMedia10", MSM_BACKEND_DAI_TERTIARY_MI2S_RX, MSM_FRONTEND_DAI_MULTIMEDIA10, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), @@ -2859,15 +2871,6 @@ static const struct snd_kcontrol_new secondary_mi2s_rx_mixer_controls[] = { msm_routing_put_audio_mixer), }; -static const struct snd_kcontrol_new mi2s_hl_mixer_controls[] = { - SOC_SINGLE_EXT("PRI_MI2S_TX", MSM_BACKEND_DAI_SECONDARY_MI2S_RX, - MSM_BACKEND_DAI_PRI_MI2S_TX, 1, 0, msm_routing_get_port_mixer, - msm_routing_put_port_mixer), - SOC_SINGLE_EXT("INTERNAL_FM_TX", MSM_BACKEND_DAI_SECONDARY_MI2S_RX, - MSM_BACKEND_DAI_INT_FM_TX, 1, 0, msm_routing_get_port_mixer, - msm_routing_put_port_mixer), -}; - static const struct snd_kcontrol_new primary_mi2s_rx_mixer_controls[] = { SOC_SINGLE_EXT("MultiMedia1", MSM_BACKEND_DAI_PRI_MI2S_RX , MSM_FRONTEND_DAI_MULTIMEDIA1, 1, 0, msm_routing_get_audio_mixer, @@ -4370,10 +4373,10 @@ static const struct snd_kcontrol_new mmul1_mixer_controls[] = { SOC_SINGLE_EXT("SEC_AUX_PCM_UL_TX", MSM_BACKEND_DAI_SEC_AUXPCM_TX, MSM_FRONTEND_DAI_MULTIMEDIA1, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("TERT_AUX_PCM_UL_TX", MSM_BACKEND_DAI_TERT_AUXPCM_TX, + SOC_SINGLE_EXT("TERT_AUXPCM_UL_TX", MSM_BACKEND_DAI_TERT_AUXPCM_TX, MSM_FRONTEND_DAI_MULTIMEDIA1, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("QUAT_AUX_PCM_UL_TX", MSM_BACKEND_DAI_QUAT_AUXPCM_TX, + SOC_SINGLE_EXT("QUAT_AUXPCM_UL_TX", MSM_BACKEND_DAI_QUAT_AUXPCM_TX, MSM_FRONTEND_DAI_MULTIMEDIA1, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), SOC_SINGLE_EXT("INTERNAL_BT_SCO_TX", MSM_BACKEND_DAI_INT_BT_SCO_TX, @@ -4712,10 +4715,10 @@ static const struct snd_kcontrol_new mmul6_mixer_controls[] = { SOC_SINGLE_EXT("SEC_AUX_PCM_UL_TX", MSM_BACKEND_DAI_SEC_AUXPCM_TX, MSM_FRONTEND_DAI_MULTIMEDIA6, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("TERT_AUX_PCM_UL_TX", MSM_BACKEND_DAI_TERT_AUXPCM_TX, + SOC_SINGLE_EXT("TERT_AUXPCM_UL_TX", MSM_BACKEND_DAI_TERT_AUXPCM_TX, MSM_FRONTEND_DAI_MULTIMEDIA6, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("QUAT_AUX_PCM_UL_TX", MSM_BACKEND_DAI_QUAT_AUXPCM_TX, + SOC_SINGLE_EXT("QUAT_AUXPCM_UL_TX", MSM_BACKEND_DAI_QUAT_AUXPCM_TX, MSM_FRONTEND_DAI_MULTIMEDIA6, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), SOC_SINGLE_EXT("TERT_TDM_TX_0", MSM_BACKEND_DAI_TERT_TDM_TX_0, @@ -4889,6 +4892,12 @@ static const struct snd_kcontrol_new sec_mi2s_rx_voice_mixer_controls[] = { SOC_SINGLE_EXT("QCHAT", MSM_BACKEND_DAI_SECONDARY_MI2S_RX, MSM_FRONTEND_DAI_QCHAT, 1, 0, msm_routing_get_voice_mixer, msm_routing_put_voice_mixer), + SOC_SINGLE_EXT("VoiceMMode1", MSM_BACKEND_DAI_SECONDARY_MI2S_RX, + MSM_FRONTEND_DAI_VOICEMMODE1, 1, 0, msm_routing_get_voice_mixer, + msm_routing_put_voice_mixer), + SOC_SINGLE_EXT("VoiceMMode2", MSM_BACKEND_DAI_SECONDARY_MI2S_RX, + MSM_FRONTEND_DAI_VOICEMMODE2, 1, 0, msm_routing_get_voice_mixer, + msm_routing_put_voice_mixer), }; static const struct snd_kcontrol_new slimbus_rx_voice_mixer_controls[] = { @@ -5021,6 +5030,9 @@ static const struct snd_kcontrol_new bt_sco_rx_voice_mixer_controls[] = { SOC_SINGLE_EXT("Voice Stub", MSM_BACKEND_DAI_INT_BT_SCO_RX, MSM_FRONTEND_DAI_VOICE_STUB, 1, 0, msm_routing_get_voice_stub_mixer, msm_routing_put_voice_stub_mixer), + SOC_SINGLE_EXT("Voice2 Stub", MSM_BACKEND_DAI_INT_BT_SCO_RX, + MSM_FRONTEND_DAI_VOICE2_STUB, 1, 0, msm_routing_get_voice_stub_mixer, + msm_routing_put_voice_stub_mixer), SOC_SINGLE_EXT("VoLTE", MSM_BACKEND_DAI_INT_BT_SCO_RX , MSM_FRONTEND_DAI_VOLTE, 1, 0, msm_routing_get_voice_mixer, msm_routing_put_voice_mixer), @@ -5909,10 +5921,10 @@ static const struct snd_kcontrol_new tx_voice_stub_mixer_controls[] = { SOC_SINGLE_EXT("SEC_AUX_PCM_UL_TX", MSM_BACKEND_DAI_SEC_AUXPCM_TX, MSM_FRONTEND_DAI_VOICE_STUB, 1, 0, msm_routing_get_voice_stub_mixer, msm_routing_put_voice_stub_mixer), - SOC_SINGLE_EXT("TERT_AUX_PCM_UL_TX", MSM_BACKEND_DAI_TERT_AUXPCM_TX, + SOC_SINGLE_EXT("TERT_AUXPCM_UL_TX", MSM_BACKEND_DAI_TERT_AUXPCM_TX, MSM_FRONTEND_DAI_VOICE_STUB, 1, 0, msm_routing_get_voice_stub_mixer, msm_routing_put_voice_stub_mixer), - SOC_SINGLE_EXT("QUAT_AUX_PCM_UL_TX", MSM_BACKEND_DAI_QUAT_AUXPCM_TX, + SOC_SINGLE_EXT("QUAT_AUXPCM_UL_TX", MSM_BACKEND_DAI_QUAT_AUXPCM_TX, MSM_FRONTEND_DAI_VOICE_STUB, 1, 0, msm_routing_get_voice_stub_mixer, msm_routing_put_voice_stub_mixer), SOC_SINGLE_EXT("SLIM_0_TX", MSM_BACKEND_DAI_SLIMBUS_0_TX, @@ -5948,10 +5960,10 @@ static const struct snd_kcontrol_new tx_voice2_stub_mixer_controls[] = { SOC_SINGLE_EXT("SEC_AUX_PCM_UL_TX", MSM_BACKEND_DAI_SEC_AUXPCM_TX, MSM_FRONTEND_DAI_VOICE2_STUB, 1, 0, msm_routing_get_voice_stub_mixer, msm_routing_put_voice_stub_mixer), - SOC_SINGLE_EXT("TERT_AUX_PCM_UL_TX", MSM_BACKEND_DAI_TERT_AUXPCM_TX, + SOC_SINGLE_EXT("TERT_AUXPCM_UL_TX", MSM_BACKEND_DAI_TERT_AUXPCM_TX, MSM_FRONTEND_DAI_VOICE2_STUB, 1, 0, msm_routing_get_voice_stub_mixer, msm_routing_put_voice_stub_mixer), - SOC_SINGLE_EXT("QUAT_AUX_PCM_UL_TX", MSM_BACKEND_DAI_QUAT_AUXPCM_TX, + SOC_SINGLE_EXT("QUAT_AUXPCM_UL_TX", MSM_BACKEND_DAI_QUAT_AUXPCM_TX, MSM_FRONTEND_DAI_VOICE2_STUB, 1, 0, msm_routing_get_voice_stub_mixer, msm_routing_put_voice_stub_mixer), SOC_SINGLE_EXT("SLIM_0_TX", MSM_BACKEND_DAI_SLIMBUS_0_TX, @@ -5993,10 +6005,10 @@ static const struct snd_kcontrol_new tx_volte_stub_mixer_controls[] = { SOC_SINGLE_EXT("SEC_AUX_PCM_UL_TX", MSM_BACKEND_DAI_SEC_AUXPCM_TX, MSM_FRONTEND_DAI_VOLTE_STUB, 1, 0, msm_routing_get_voice_stub_mixer, msm_routing_put_voice_stub_mixer), - SOC_SINGLE_EXT("TERT_AUX_PCM_UL_TX", MSM_BACKEND_DAI_TERT_AUXPCM_TX, + SOC_SINGLE_EXT("TERT_AUXPCM_UL_TX", MSM_BACKEND_DAI_TERT_AUXPCM_TX, MSM_FRONTEND_DAI_VOLTE_STUB, 1, 0, msm_routing_get_voice_stub_mixer, msm_routing_put_voice_stub_mixer), - SOC_SINGLE_EXT("QUAT_AUX_PCM_UL_TX", MSM_BACKEND_DAI_QUAT_AUXPCM_TX, + SOC_SINGLE_EXT("QUAT_AUXPCM_UL_TX", MSM_BACKEND_DAI_QUAT_AUXPCM_TX, MSM_FRONTEND_DAI_VOLTE_STUB, 1, 0, msm_routing_get_voice_stub_mixer, msm_routing_put_voice_stub_mixer), SOC_SINGLE_EXT("SLIM_0_TX", MSM_BACKEND_DAI_SLIMBUS_0_TX, @@ -6089,10 +6101,10 @@ static const struct snd_kcontrol_new sbus_0_rx_port_mixer_controls[] = { SOC_SINGLE_EXT("SEC_AUX_PCM_UL_TX", MSM_BACKEND_DAI_SLIMBUS_0_RX, MSM_BACKEND_DAI_SEC_AUXPCM_TX, 1, 0, msm_routing_get_port_mixer, msm_routing_put_port_mixer), - SOC_SINGLE_EXT("TERT_AUX_PCM_UL_TX", MSM_BACKEND_DAI_SLIMBUS_0_RX, + SOC_SINGLE_EXT("TERT_AUXPCM_UL_TX", MSM_BACKEND_DAI_SLIMBUS_0_RX, MSM_BACKEND_DAI_TERT_AUXPCM_TX, 1, 0, msm_routing_get_port_mixer, msm_routing_put_port_mixer), - SOC_SINGLE_EXT("QUAT_AUX_PCM_UL_TX", MSM_BACKEND_DAI_SLIMBUS_0_RX, + SOC_SINGLE_EXT("QUAT_AUXPCM_UL_TX", MSM_BACKEND_DAI_SLIMBUS_0_RX, MSM_BACKEND_DAI_QUAT_AUXPCM_TX, 1, 0, msm_routing_get_port_mixer, msm_routing_put_port_mixer), SOC_SINGLE_EXT("MI2S_TX", MSM_BACKEND_DAI_SLIMBUS_0_RX, @@ -6101,6 +6113,9 @@ static const struct snd_kcontrol_new sbus_0_rx_port_mixer_controls[] = { SOC_SINGLE_EXT("PRI_MI2S_TX", MSM_BACKEND_DAI_SLIMBUS_0_RX, MSM_BACKEND_DAI_PRI_MI2S_TX, 1, 0, msm_routing_get_port_mixer, msm_routing_put_port_mixer), + SOC_SINGLE_EXT("SEC_MI2S_TX", MSM_BACKEND_DAI_SLIMBUS_0_RX, + MSM_BACKEND_DAI_SECONDARY_MI2S_TX, 1, 0, msm_routing_get_port_mixer, + msm_routing_put_port_mixer), SOC_SINGLE_EXT("TERT_MI2S_TX", MSM_BACKEND_DAI_SLIMBUS_0_RX, MSM_BACKEND_DAI_TERTIARY_MI2S_TX, 1, 0, msm_routing_get_port_mixer, msm_routing_put_port_mixer), @@ -6152,7 +6167,7 @@ static const struct snd_kcontrol_new sec_auxpcm_rx_port_mixer_controls[] = { }; static const struct snd_kcontrol_new tert_auxpcm_rx_port_mixer_controls[] = { - SOC_SINGLE_EXT("TERT_AUX_PCM_UL_TX", MSM_BACKEND_DAI_TERT_AUXPCM_RX, + SOC_SINGLE_EXT("TERT_AUXPCM_UL_TX", MSM_BACKEND_DAI_TERT_AUXPCM_RX, MSM_BACKEND_DAI_TERT_AUXPCM_TX, 1, 0, msm_routing_get_port_mixer, msm_routing_put_port_mixer), SOC_SINGLE_EXT("SLIM_0_TX", MSM_BACKEND_DAI_TERT_AUXPCM_RX, @@ -6164,7 +6179,7 @@ static const struct snd_kcontrol_new tert_auxpcm_rx_port_mixer_controls[] = { }; static const struct snd_kcontrol_new quat_auxpcm_rx_port_mixer_controls[] = { - SOC_SINGLE_EXT("QUAT_AUX_PCM_UL_TX", MSM_BACKEND_DAI_QUAT_AUXPCM_RX, + SOC_SINGLE_EXT("QUAT_AUXPCM_UL_TX", MSM_BACKEND_DAI_QUAT_AUXPCM_RX, MSM_BACKEND_DAI_QUAT_AUXPCM_TX, 1, 0, msm_routing_get_port_mixer, msm_routing_put_port_mixer), SOC_SINGLE_EXT("SLIM_0_TX", MSM_BACKEND_DAI_QUAT_AUXPCM_RX, @@ -6188,10 +6203,10 @@ static const struct snd_kcontrol_new sbus_1_rx_port_mixer_controls[] = { SOC_SINGLE_EXT("SEC_AUX_PCM_UL_TX", MSM_BACKEND_DAI_SLIMBUS_1_RX, MSM_BACKEND_DAI_SEC_AUXPCM_TX, 1, 0, msm_routing_get_port_mixer, msm_routing_put_port_mixer), - SOC_SINGLE_EXT("TERT_AUX_PCM_UL_TX", MSM_BACKEND_DAI_SLIMBUS_1_RX, + SOC_SINGLE_EXT("TERT_AUXPCM_UL_TX", MSM_BACKEND_DAI_SLIMBUS_1_RX, MSM_BACKEND_DAI_TERT_AUXPCM_TX, 1, 0, msm_routing_get_port_mixer, msm_routing_put_port_mixer), - SOC_SINGLE_EXT("QUAT_AUX_PCM_UL_TX", MSM_BACKEND_DAI_SLIMBUS_1_RX, + SOC_SINGLE_EXT("QUAT_AUXPCM_UL_TX", MSM_BACKEND_DAI_SLIMBUS_1_RX, MSM_BACKEND_DAI_QUAT_AUXPCM_TX, 1, 0, msm_routing_get_port_mixer, msm_routing_put_port_mixer), }; @@ -6908,17 +6923,20 @@ static const struct snd_kcontrol_new sec_mi2s_rx_port_mixer_controls[] = { SOC_SINGLE_EXT("PRI_MI2S_TX", MSM_BACKEND_DAI_SECONDARY_MI2S_RX, MSM_BACKEND_DAI_PRI_MI2S_TX, 1, 0, msm_routing_get_port_mixer, msm_routing_put_port_mixer), + SOC_SINGLE_EXT("SEC_MI2S_TX", MSM_BACKEND_DAI_SECONDARY_MI2S_RX, + MSM_BACKEND_DAI_SECONDARY_MI2S_TX, 1, 0, msm_routing_get_port_mixer, + msm_routing_put_port_mixer), SOC_SINGLE_EXT("TERT_MI2S_TX", MSM_BACKEND_DAI_SECONDARY_MI2S_RX, MSM_BACKEND_DAI_TERTIARY_MI2S_TX, 1, 0, msm_routing_get_port_mixer, msm_routing_put_port_mixer), - SOC_SINGLE_EXT("SLIM_0_TX", MSM_BACKEND_DAI_SECONDARY_MI2S_RX, - MSM_BACKEND_DAI_SLIMBUS_0_TX, 1, 0, msm_routing_get_port_mixer, - msm_routing_put_port_mixer), SOC_SINGLE_EXT("QUAT_MI2S_TX", MSM_BACKEND_DAI_SECONDARY_MI2S_RX, MSM_BACKEND_DAI_QUATERNARY_MI2S_TX, 1, 0, msm_routing_get_port_mixer, msm_routing_put_port_mixer), - SOC_SINGLE_EXT("SEC_MI2S_TX", MSM_BACKEND_DAI_SECONDARY_MI2S_RX, - MSM_BACKEND_DAI_SECONDARY_MI2S_TX, 1, 0, msm_routing_get_port_mixer, + SOC_SINGLE_EXT("SLIM_0_TX", MSM_BACKEND_DAI_SECONDARY_MI2S_RX, + MSM_BACKEND_DAI_SLIMBUS_0_TX, 1, 0, msm_routing_get_port_mixer, + msm_routing_put_port_mixer), + SOC_SINGLE_EXT("INTERNAL_FM_TX", MSM_BACKEND_DAI_SECONDARY_MI2S_RX, + MSM_BACKEND_DAI_INT_FM_TX, 1, 0, msm_routing_get_port_mixer, msm_routing_put_port_mixer), }; @@ -7060,7 +7078,7 @@ static const struct soc_enum aanc_slim_0_rx_enum = aanc_slim_0_rx_text); static const struct snd_kcontrol_new aanc_slim_0_rx_mux[] = { - SOC_DAPM_ENUM_EXT("AANC_SLIM_0_RX MUX", aanc_slim_0_rx_enum, + SOC_ENUM_EXT("AANC_SLIM_0_RX MUX", aanc_slim_0_rx_enum, msm_routing_slim_0_rx_aanc_mux_get, msm_routing_slim_0_rx_aanc_mux_put) }; @@ -7862,10 +7880,14 @@ static const struct snd_soc_dapm_widget msm_qdsp6_widgets[] = { 0, 0, 0, 0), SND_SOC_DAPM_AIF_OUT("SLIM4_UL_HL", "SLIMBUS4_HOSTLESS Capture", 0, 0, 0, 0), - SND_SOC_DAPM_AIF_OUT("SLIM8_UL_HL", "SLIMBUS8_HOSTLESS Capture", - 0, 0, 0, 0), SND_SOC_DAPM_AIF_IN("SLIM6_DL_HL", "SLIMBUS6_HOSTLESS Playback", 0, 0, 0, 0), + SND_SOC_DAPM_AIF_OUT("SLIM6_UL_HL", "SLIMBUS6_HOSTLESS Capture", + 0, 0, 0, 0), + SND_SOC_DAPM_AIF_IN("SLIM8_DL_HL", "SLIMBUS8_HOSTLESS Playback", + 0, 0, 0, 0), + SND_SOC_DAPM_AIF_OUT("SLIM8_UL_HL", "SLIMBUS8_HOSTLESS Capture", + 0, 0, 0, 0), SND_SOC_DAPM_AIF_IN("INTFM_DL_HL", "INT_FM_HOSTLESS Playback", 0, 0, 0, 0), SND_SOC_DAPM_AIF_OUT("INTFM_UL_HL", "INT_FM_HOSTLESS Capture", @@ -8163,8 +8185,11 @@ static const struct snd_soc_dapm_widget msm_qdsp6_widgets[] = { SND_SOC_DAPM_AIF_IN("SEC_MI2S_TX", "Secondary MI2S Capture", 0, 0, 0, 0), SND_SOC_DAPM_AIF_IN("SLIMBUS_0_TX", "Slimbus Capture", 0, 0, 0, 0), + SND_SOC_DAPM_AIF_IN("SLIMBUS_2_TX", "Slimbus2 Capture", 0, 0, 0, 0), SND_SOC_DAPM_AIF_IN("QUIN_MI2S_TX", "Quinary MI2S Capture", 0, 0, 0, 0), + SND_SOC_DAPM_AIF_IN("SENARY_MI2S_TX", "Senary MI2S Capture", + 0, 0, 0, 0), SND_SOC_DAPM_AIF_OUT("INT_BT_SCO_RX", "Internal BT-SCO Playback", 0, 0, 0 , 0), SND_SOC_DAPM_AIF_IN("INT_BT_SCO_TX", "Internal BT-SCO Capture", @@ -8402,8 +8427,6 @@ static const struct snd_soc_dapm_widget msm_qdsp6_widgets[] = { SND_SOC_DAPM_MUX("LSM6 MUX", SND_SOC_NOPM, 0, 0, &lsm6_mux), SND_SOC_DAPM_MUX("LSM7 MUX", SND_SOC_NOPM, 0, 0, &lsm7_mux), SND_SOC_DAPM_MUX("LSM8 MUX", SND_SOC_NOPM, 0, 0, &lsm8_mux), - SND_SOC_DAPM_MUX("SLIM_0_RX AANC MUX", SND_SOC_NOPM, 0, 0, - aanc_slim_0_rx_mux), /* Mixer definitions */ SND_SOC_DAPM_MIXER("PRI_RX Audio Mixer", SND_SOC_NOPM, 0, 0, @@ -8438,9 +8461,6 @@ static const struct snd_soc_dapm_widget msm_qdsp6_widgets[] = { SND_SOC_DAPM_MIXER("SEC_MI2S_RX_SD1 Audio Mixer", SND_SOC_NOPM, 0, 0, secondary_mi2s_rx2_mixer_controls, ARRAY_SIZE(secondary_mi2s_rx2_mixer_controls)), - SND_SOC_DAPM_MIXER("SEC_MI2S_RX Port Mixer", SND_SOC_NOPM, 0, 0, - mi2s_hl_mixer_controls, - ARRAY_SIZE(mi2s_hl_mixer_controls)), SND_SOC_DAPM_MIXER("PRI_MI2S_RX Audio Mixer", SND_SOC_NOPM, 0, 0, primary_mi2s_rx_mixer_controls, ARRAY_SIZE(primary_mi2s_rx_mixer_controls)), @@ -8747,6 +8767,8 @@ static const struct snd_soc_dapm_widget msm_qdsp6_widgets[] = { &ext_ec_ref_mux_ul1), SND_SOC_DAPM_MUX("AUDIO_REF_EC_UL2 MUX", SND_SOC_NOPM, 0, 0, &ext_ec_ref_mux_ul2), + SND_SOC_DAPM_MUX("AUDIO_REF_EC_UL3 MUX", SND_SOC_NOPM, 0, 0, + &ext_ec_ref_mux_ul3), SND_SOC_DAPM_MUX("AUDIO_REF_EC_UL4 MUX", SND_SOC_NOPM, 0, 0, &ext_ec_ref_mux_ul4), SND_SOC_DAPM_MUX("AUDIO_REF_EC_UL5 MUX", SND_SOC_NOPM, 0, 0, @@ -9370,10 +9392,10 @@ static const struct snd_soc_dapm_route intercon[] = { {"MultiMedia1 Mixer", "SEC_AUX_PCM_UL_TX", "SEC_AUX_PCM_TX"}, {"MultiMedia3 Mixer", "SEC_AUX_PCM_TX", "SEC_AUX_PCM_TX"}, {"MultiMedia5 Mixer", "SEC_AUX_PCM_TX", "SEC_AUX_PCM_TX"}, - {"MultiMedia1 Mixer", "TERT_AUX_PCM_UL_TX", "TERT_AUX_PCM_TX"}, + {"MultiMedia1 Mixer", "TERT_AUXPCM_UL_TX", "TERT_AUX_PCM_TX"}, {"MultiMedia3 Mixer", "TERT_AUX_PCM_TX", "TERT_AUX_PCM_TX"}, {"MultiMedia5 Mixer", "TERT_AUX_PCM_TX", "TERT_AUX_PCM_TX"}, - {"MultiMedia1 Mixer", "QUAT_AUX_PCM_UL_TX", "QUAT_AUX_PCM_TX"}, + {"MultiMedia1 Mixer", "QUAT_AUXPCM_UL_TX", "QUAT_AUX_PCM_TX"}, {"MultiMedia3 Mixer", "QUAT_AUX_PCM_TX", "QUAT_AUX_PCM_TX"}, {"MultiMedia5 Mixer", "QUAT_AUX_PCM_TX", "QUAT_AUX_PCM_TX"}, {"MultiMedia2 Mixer", "SLIM_0_TX", "SLIMBUS_0_TX"}, @@ -9721,6 +9743,8 @@ static const struct snd_soc_dapm_route intercon[] = { {"INTERNAL_BT_SCO_RX_Voice Mixer", "QCHAT", "QCHAT_DL"}, {"INTERNAL_BT_SCO_RX_Voice Mixer", "VoiceMMode1", "VOICEMMODE1_DL"}, {"INTERNAL_BT_SCO_RX_Voice Mixer", "VoiceMMode2", "VOICEMMODE2_DL"}, + {"INTERNAL_BT_SCO_RX_Voice Mixer", "Voice Stub", "VOICE_STUB_DL"}, + {"INTERNAL_BT_SCO_RX_Voice Mixer", "Voice2 Stub", "VOICE2_STUB_DL"}, {"INT_BT_SCO_RX", NULL, "INTERNAL_BT_SCO_RX_Voice Mixer"}, {"AFE_PCM_RX_Voice Mixer", "CSVoice", "CS-VOICE_DL1"}, @@ -9889,6 +9913,11 @@ static const struct snd_soc_dapm_route intercon[] = { {"AUDIO_REF_EC_UL2 MUX", "TERT_MI2S_TX" , "TERT_MI2S_TX"}, {"AUDIO_REF_EC_UL2 MUX", "QUAT_MI2S_TX" , "QUAT_MI2S_TX"}, + {"AUDIO_REF_EC_UL3 MUX", "PRI_MI2S_TX", "PRI_MI2S_TX"}, + {"AUDIO_REF_EC_UL3 MUX", "SEC_MI2S_TX", "SEC_MI2S_TX"}, + {"AUDIO_REF_EC_UL3 MUX", "TERT_MI2S_TX", "TERT_MI2S_TX"}, + {"AUDIO_REF_EC_UL3 MUX", "QUAT_MI2S_TX", "QUAT_MI2S_TX"}, + {"AUDIO_REF_EC_UL4 MUX", "PRI_MI2S_TX" , "PRI_MI2S_TX"}, {"AUDIO_REF_EC_UL4 MUX", "SEC_MI2S_TX" , "SEC_MI2S_TX"}, {"AUDIO_REF_EC_UL4 MUX", "TERT_MI2S_TX" , "TERT_MI2S_TX"}, @@ -10137,11 +10166,11 @@ static const struct snd_soc_dapm_route intercon[] = { {"INT_FM_RX", NULL, "INTFM_DL_HL"}, {"INTFM_UL_HL", NULL, "INT_FM_TX"}, - {"INTHFP_UL_HL", "NULL", "HFP_PRI_AUX_UL_HL"}, + {"INTHFP_UL_HL", NULL, "HFP_PRI_AUX_UL_HL"}, {"HFP_PRI_AUX_UL_HL", "Switch", "AUX_PCM_TX"}, - {"INTHFP_UL_HL", "NULL", "HFP_AUX_UL_HL"}, + {"INTHFP_UL_HL", NULL, "HFP_AUX_UL_HL"}, {"HFP_AUX_UL_HL", "Switch", "SEC_AUX_PCM_TX"}, - {"INTHFP_UL_HL", "NULL", "HFP_INT_UL_HL"}, + {"INTHFP_UL_HL", NULL, "HFP_INT_UL_HL"}, {"HFP_INT_UL_HL", "Switch", "INT_BT_SCO_TX"}, {"AUX_PCM_RX", NULL, "AUXPCM_DL_HL"}, {"AUXPCM_UL_HL", NULL, "AUX_PCM_TX"}, @@ -10339,8 +10368,8 @@ static const struct snd_soc_dapm_route intercon[] = { {"SLIMBUS_0_RX Port Mixer", "SLIM_8_TX", "SLIMBUS_8_TX"}, {"SLIMBUS_0_RX Port Mixer", "AUX_PCM_UL_TX", "AUX_PCM_TX"}, {"SLIMBUS_0_RX Port Mixer", "SEC_AUX_PCM_UL_TX", "SEC_AUX_PCM_TX"}, - {"SLIMBUS_0_RX Port Mixer", "TERT_AUX_PCM_UL_TX", "TERT_AUX_PCM_TX"}, - {"SLIMBUS_0_RX Port Mixer", "QUAT_AUX_PCM_UL_TX", "QUAT_AUX_PCM_TX"}, + {"SLIMBUS_0_RX Port Mixer", "TERT_AUXPCM_UL_TX", "TERT_AUX_PCM_TX"}, + {"SLIMBUS_0_RX Port Mixer", "QUAT_AUXPCM_UL_TX", "QUAT_AUX_PCM_TX"}, {"SLIMBUS_0_RX Port Mixer", "MI2S_TX", "MI2S_TX"}, {"SLIMBUS_0_RX Port Mixer", "PRI_MI2S_TX", "PRI_MI2S_TX"}, {"SLIMBUS_0_RX Port Mixer", "SEC_MI2S_TX", "SEC_MI2S_TX"}, @@ -10364,12 +10393,12 @@ static const struct snd_soc_dapm_route intercon[] = { {"SEC_AUX_PCM_RX", NULL, "SEC_AUXPCM_RX Port Mixer"}, {"TERT_AUXPCM_RX Port Mixer", "AUX_PCM_UL_TX", "AUX_PCM_TX"}, - {"TERT_AUXPCM_RX Port Mixer", "TERT_AUX_PCM_UL_TX", "TERT_AUX_PCM_TX"}, + {"TERT_AUXPCM_RX Port Mixer", "TERT_AUXPCM_UL_TX", "TERT_AUX_PCM_TX"}, {"TERT_AUXPCM_RX Port Mixer", "SLIM_0_TX", "SLIMBUS_0_TX"}, {"TERT_AUX_PCM_RX", NULL, "TERT_AUXPCM_RX Port Mixer"}, {"QUAT_AUXPCM_RX Port Mixer", "AUX_PCM_UL_TX", "AUX_PCM_TX"}, - {"QUAT_AUXPCM_RX Port Mixer", "QUAT_AUX_PCM_UL_TX", "QUAT_AUX_PCM_TX"}, + {"QUAT_AUXPCM_RX Port Mixer", "QUAT_AUXPCM_UL_TX", "QUAT_AUX_PCM_TX"}, {"QUAT_AUXPCM_RX Port Mixer", "SLIM_0_TX", "SLIMBUS_0_TX"}, {"QUAT_AUX_PCM_RX", NULL, "QUAT_AUXPCM_RX Port Mixer"}, @@ -10379,8 +10408,8 @@ static const struct snd_soc_dapm_route intercon[] = { {"Voice Stub Tx Mixer", "STUB_1_TX_HL", "STUB_1_TX"}, {"Voice Stub Tx Mixer", "AUX_PCM_UL_TX", "AUX_PCM_TX"}, {"Voice Stub Tx Mixer", "SEC_AUX_PCM_UL_TX", "SEC_AUX_PCM_TX"}, - {"Voice Stub Tx Mixer", "TERT_AUX_PCM_UL_TX", "TERT_AUX_PCM_TX"}, - {"Voice Stub Tx Mixer", "QUAT_AUX_PCM_UL_TX", "QUAT_AUX_PCM_TX"}, + {"Voice Stub Tx Mixer", "TERT_AUXPCM_UL_TX", "TERT_AUX_PCM_TX"}, + {"Voice Stub Tx Mixer", "QUAT_AUXPCM_UL_TX", "QUAT_AUX_PCM_TX"}, {"Voice Stub Tx Mixer", "MI2S_TX", "MI2S_TX"}, {"Voice Stub Tx Mixer", "PRI_MI2S_TX", "PRI_MI2S_TX"}, {"Voice Stub Tx Mixer", "TERT_MI2S_TX", "TERT_MI2S_TX"}, @@ -10426,8 +10455,6 @@ static const struct snd_soc_dapm_route intercon[] = { {"SLIMBUS_1_RX Mixer", "Voice2 Stub", "VOICE2_STUB_DL"}, {"SLIMBUS_1_RX Mixer", "VoLTE Stub", "VOLTE_STUB_DL"}, {"SLIMBUS_1_RX", NULL, "SLIMBUS_1_RX Mixer"}, - {"INTERNAL_BT_SCO_RX_Voice Mixer", "Voice Stub", "VOICE_STUB_DL"}, - {"INTERNAL_BT_SCO_RX_Voice Mixer", "Voice2 Stub", "VOICE2_STUB_DL"}, {"AFE_PCM_RX_Voice Mixer", "Voice Stub", "VOICE_STUB_DL"}, {"AFE_PCM_RX_Voice Mixer", "Voice2 Stub", "VOICE2_STUB_DL"}, {"AFE_PCM_RX_Voice Mixer", "VoLTE Stub", "VOLTE_STUB_DL"}, @@ -10519,6 +10546,7 @@ static const struct snd_soc_dapm_route intercon[] = { {"SEC_MI2S_RX Port Mixer", "TERT_MI2S_TX", "TERT_MI2S_TX"}, {"SEC_MI2S_RX Port Mixer", "QUAT_MI2S_TX", "QUAT_MI2S_TX"}, {"SEC_MI2S_RX Port Mixer", "SLIM_0_TX", "SLIMBUS_0_TX"}, + {"SEC_MI2S_RX Port Mixer", "INTERNAL_FM_TX", "INT_FM_TX"}, {"SEC_MI2S_RX", NULL, "SEC_MI2S_RX Port Mixer"}, {"TERT_MI2S_RX Port Mixer", "PRI_MI2S_TX", "PRI_MI2S_TX"}, @@ -11050,9 +11078,8 @@ static int msm_routing_probe(struct snd_soc_platform *platform) snd_soc_add_platform_controls(platform, lsm_function, ARRAY_SIZE(lsm_function)); - snd_soc_add_platform_controls(platform, - aanc_slim_0_rx_mux, - ARRAY_SIZE(aanc_slim_0_rx_mux)); + snd_soc_add_platform_controls(platform, aanc_slim_0_rx_mux, + ARRAY_SIZE(aanc_slim_0_rx_mux)); snd_soc_add_platform_controls(platform, msm_voc_session_controls, ARRAY_SIZE(msm_voc_session_controls)); diff --git a/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.h b/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.h index 8e3086849d92..6de9795b5cc7 100644 --- a/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.h +++ b/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.h @@ -59,14 +59,15 @@ #define LPASS_BE_SLIMBUS_1_TX "SLIMBUS_1_TX" #define LPASS_BE_STUB_1_TX "STUB_1_TX" #define LPASS_BE_SLIMBUS_2_RX "SLIMBUS_2_RX" +#define LPASS_BE_SLIMBUS_2_TX "SLIMBUS_2_TX" #define LPASS_BE_SLIMBUS_3_RX "SLIMBUS_3_RX" #define LPASS_BE_SLIMBUS_3_TX "SLIMBUS_3_TX" #define LPASS_BE_SLIMBUS_4_RX "SLIMBUS_4_RX" #define LPASS_BE_SLIMBUS_4_TX "SLIMBUS_4_TX" +#define LPASS_BE_SLIMBUS_5_RX "SLIMBUS_5_RX" #define LPASS_BE_SLIMBUS_5_TX "SLIMBUS_5_TX" #define LPASS_BE_SLIMBUS_6_RX "SLIMBUS_6_RX" #define LPASS_BE_SLIMBUS_6_TX "SLIMBUS_6_TX" -#define LPASS_BE_SLIMBUS_5_RX "SLIMBUS_5_RX" #define LPASS_BE_QUIN_MI2S_RX "QUIN_MI2S_RX" #define LPASS_BE_QUIN_MI2S_TX "QUIN_MI2S_TX" #define LPASS_BE_SENARY_MI2S_TX "SENARY_MI2S_TX" @@ -218,11 +219,19 @@ enum { MSM_BACKEND_DAI_SLIMBUS_1_RX, MSM_BACKEND_DAI_SLIMBUS_1_TX, MSM_BACKEND_DAI_SLIMBUS_2_RX, - MSM_BACKEND_DAI_SLIMBUS_4_RX, - MSM_BACKEND_DAI_SLIMBUS_4_TX, + MSM_BACKEND_DAI_SLIMBUS_2_TX, MSM_BACKEND_DAI_SLIMBUS_3_RX, MSM_BACKEND_DAI_SLIMBUS_3_TX, + MSM_BACKEND_DAI_SLIMBUS_4_RX, + MSM_BACKEND_DAI_SLIMBUS_4_TX, + MSM_BACKEND_DAI_SLIMBUS_5_RX, MSM_BACKEND_DAI_SLIMBUS_5_TX, + MSM_BACKEND_DAI_SLIMBUS_6_RX, + MSM_BACKEND_DAI_SLIMBUS_6_TX, + MSM_BACKEND_DAI_SLIMBUS_7_RX, + MSM_BACKEND_DAI_SLIMBUS_7_TX, + MSM_BACKEND_DAI_SLIMBUS_8_RX, + MSM_BACKEND_DAI_SLIMBUS_8_TX, MSM_BACKEND_DAI_EXTPROC_RX, MSM_BACKEND_DAI_EXTPROC_TX, MSM_BACKEND_DAI_EXTPROC_EC_TX, @@ -237,11 +246,8 @@ enum { MSM_BACKEND_DAI_AUDIO_I2S_RX, MSM_BACKEND_DAI_SEC_AUXPCM_RX, MSM_BACKEND_DAI_SEC_AUXPCM_TX, - MSM_BACKEND_DAI_SLIMBUS_6_RX, - MSM_BACKEND_DAI_SLIMBUS_6_TX, MSM_BACKEND_DAI_SPDIF_RX, MSM_BACKEND_DAI_SECONDARY_MI2S_RX_SD1, - MSM_BACKEND_DAI_SLIMBUS_5_RX, MSM_BACKEND_DAI_QUINARY_MI2S_RX, MSM_BACKEND_DAI_QUINARY_MI2S_TX, MSM_BACKEND_DAI_SENARY_MI2S_TX, @@ -310,10 +316,6 @@ enum { MSM_BACKEND_DAI_QUAT_TDM_RX_7, MSM_BACKEND_DAI_QUAT_TDM_TX_7, MSM_BACKEND_DAI_INT_BT_A2DP_RX, - MSM_BACKEND_DAI_SLIMBUS_7_RX, - MSM_BACKEND_DAI_SLIMBUS_7_TX, - MSM_BACKEND_DAI_SLIMBUS_8_RX, - MSM_BACKEND_DAI_SLIMBUS_8_TX, MSM_BACKEND_DAI_USB_RX, MSM_BACKEND_DAI_USB_TX, MSM_BACKEND_DAI_DISPLAY_PORT_RX, -- cgit v1.2.3 From e141e85de76ff485d867a272bda582d6ed452ee4 Mon Sep 17 00:00:00 2001 From: Jordan Crouse Date: Tue, 31 May 2016 11:24:23 -0600 Subject: msm: kgsl: Fix pagetable member of struct kgsl_memdesc memdesc->pagetable is supposed to help ensure that memory gets unmapped before it is freed, but the pagetable member is being populated at create time not when the buffer gets mapped. This forces the developer to ensure that the same pagetable is used for both the create and map step. Instead, assign the pagetable member when it is first used (to get a GPU address) and put it away when the GPU address is released. Change-Id: Ic0dedbad372fd9029b932dd99633a650049751ed Signed-off-by: Jordan Crouse --- drivers/gpu/msm/adreno_a5xx.c | 2 +- drivers/gpu/msm/kgsl.c | 39 +++++++-------------------------------- drivers/gpu/msm/kgsl_iommu.c | 33 ++++++++++++++++++--------------- drivers/gpu/msm/kgsl_mmu.c | 27 ++++++++++++++++++++++----- drivers/gpu/msm/kgsl_mmu.h | 5 ++--- drivers/gpu/msm/kgsl_sharedmem.c | 33 +++++++-------------------------- drivers/gpu/msm/kgsl_sharedmem.h | 9 +++------ 7 files changed, 60 insertions(+), 88 deletions(-) diff --git a/drivers/gpu/msm/adreno_a5xx.c b/drivers/gpu/msm/adreno_a5xx.c index 2891940b8f5b..38ed2d1e8a99 100644 --- a/drivers/gpu/msm/adreno_a5xx.c +++ b/drivers/gpu/msm/adreno_a5xx.c @@ -252,7 +252,7 @@ static int a5xx_critical_packet_construct(struct adreno_device *adreno_dev) return ret; ret = kgsl_allocate_user(&adreno_dev->dev, &crit_pkts_refbuf0, - NULL, PAGE_SIZE, KGSL_MEMFLAGS_SECURE); + PAGE_SIZE, KGSL_MEMFLAGS_SECURE); if (ret) return ret; diff --git a/drivers/gpu/msm/kgsl.c b/drivers/gpu/msm/kgsl.c index add4590bbb90..01966bb31a09 100644 --- a/drivers/gpu/msm/kgsl.c +++ b/drivers/gpu/msm/kgsl.c @@ -380,24 +380,6 @@ kgsl_mem_entry_track_gpuaddr(struct kgsl_process_private *process, return kgsl_mmu_get_gpuaddr(pagetable, &entry->memdesc); } -/** - * kgsl_mem_entry_untrack_gpuaddr() - Untrack memory that is previously tracked - * process - Pointer to process private to which memory belongs - * entry - Memory entry to untrack - * - * Function just does the opposite of kgsl_mem_entry_track_gpuaddr. Needs to be - * called with processes spin lock held - */ -static void -kgsl_mem_entry_untrack_gpuaddr(struct kgsl_process_private *process, - struct kgsl_mem_entry *entry) -{ - struct kgsl_pagetable *pagetable = entry->memdesc.pagetable; - - if (entry->memdesc.gpuaddr) - kgsl_mmu_put_gpuaddr(pagetable, &entry->memdesc); -} - /* Commit the entry to the process so it can be accessed by other operations */ static void kgsl_mem_entry_commit_process(struct kgsl_mem_entry *entry) { @@ -446,7 +428,7 @@ kgsl_mem_entry_attach_process(struct kgsl_mem_entry *entry, if (id < 0) { ret = id; - kgsl_mem_entry_untrack_gpuaddr(process, entry); + kgsl_mmu_put_gpuaddr(&entry->memdesc); goto err_put_proc_priv; } @@ -485,7 +467,7 @@ err_put_proc_priv: static void kgsl_mem_entry_detach_process(struct kgsl_mem_entry *entry) { unsigned int type; - int ret; + if (entry == NULL) return; @@ -502,14 +484,7 @@ static void kgsl_mem_entry_detach_process(struct kgsl_mem_entry *entry) entry->priv->stats[type].cur -= entry->memdesc.size; spin_unlock(&entry->priv->mem_lock); - ret = kgsl_mmu_unmap(entry->memdesc.pagetable, &entry->memdesc); - /* - * Do not free the gpuaddr/size if unmap fails. Because if we try - * to map this range in future, the iommu driver will throw - * a BUG_ON() because it feels we are overwriting a mapping. - */ - if (ret == 0) - kgsl_mem_entry_untrack_gpuaddr(entry->priv, entry); + kgsl_mmu_put_gpuaddr(&entry->memdesc); kgsl_process_private_put(entry->priv); @@ -3048,7 +3023,7 @@ static struct kgsl_mem_entry *gpumem_alloc_entry( entry->memdesc.priv |= KGSL_MEMDESC_SECURE; ret = kgsl_allocate_user(dev_priv->device, &entry->memdesc, - private->pagetable, size, flags); + size, flags); if (ret != 0) goto err; @@ -3251,7 +3226,7 @@ long kgsl_ioctl_sparse_phys_alloc(struct kgsl_device_private *dev_priv, kgsl_memdesc_set_align(&entry->memdesc, ilog2(param->pagesize)); ret = kgsl_allocate_user(dev_priv->device, &entry->memdesc, - process->pagetable, param->size, entry->memdesc.flags); + param->size, entry->memdesc.flags); if (ret) goto err_remove_idr; @@ -4016,11 +3991,11 @@ static unsigned long _gpu_set_svm_region(struct kgsl_process_private *private, return ret; entry->memdesc.gpuaddr = (uint64_t) addr; + entry->memdesc.pagetable = private->pagetable; ret = kgsl_mmu_map(private->pagetable, &entry->memdesc); if (ret) { - kgsl_mmu_put_gpuaddr(private->pagetable, - &entry->memdesc); + kgsl_mmu_put_gpuaddr(&entry->memdesc); return ret; } diff --git a/drivers/gpu/msm/kgsl_iommu.c b/drivers/gpu/msm/kgsl_iommu.c index 9f35a3197a4c..bc681057250d 100644 --- a/drivers/gpu/msm/kgsl_iommu.c +++ b/drivers/gpu/msm/kgsl_iommu.c @@ -1403,17 +1403,16 @@ static int _setstate_alloc(struct kgsl_device *device, { int ret; - ret = kgsl_sharedmem_alloc_contig(device, &iommu->setstate, NULL, - PAGE_SIZE); - if (ret) - return ret; + ret = kgsl_sharedmem_alloc_contig(device, &iommu->setstate, PAGE_SIZE); - /* Mark the setstate memory as read only */ - iommu->setstate.flags |= KGSL_MEMFLAGS_GPUREADONLY; + if (!ret) { + /* Mark the setstate memory as read only */ + iommu->setstate.flags |= KGSL_MEMFLAGS_GPUREADONLY; - kgsl_sharedmem_set(device, &iommu->setstate, 0, 0, PAGE_SIZE); + kgsl_sharedmem_set(device, &iommu->setstate, 0, 0, PAGE_SIZE); + } - return 0; + return ret; } static int kgsl_iommu_init(struct kgsl_mmu *mmu) @@ -1663,7 +1662,7 @@ static int _iommu_map_guard_page(struct kgsl_pagetable *pt, if (!kgsl_secure_guard_page_memdesc.sgt) { if (kgsl_allocate_user(KGSL_MMU_DEVICE(pt->mmu), - &kgsl_secure_guard_page_memdesc, pt, + &kgsl_secure_guard_page_memdesc, sgp_size, KGSL_MEMFLAGS_SECURE)) { KGSL_CORE_ERR( "Secure guard page alloc failed\n"); @@ -2364,23 +2363,27 @@ static int kgsl_iommu_get_gpuaddr(struct kgsl_pagetable *pagetable, } ret = _insert_gpuaddr(pagetable, addr, size); - if (ret == 0) + if (ret == 0) { memdesc->gpuaddr = addr; + memdesc->pagetable = pagetable; + } out: spin_unlock(&pagetable->lock); return ret; } -static void kgsl_iommu_put_gpuaddr(struct kgsl_pagetable *pagetable, - struct kgsl_memdesc *memdesc) +static void kgsl_iommu_put_gpuaddr(struct kgsl_memdesc *memdesc) { - spin_lock(&pagetable->lock); + if (memdesc->pagetable == NULL) + return; + + spin_lock(&memdesc->pagetable->lock); - if (_remove_gpuaddr(pagetable, memdesc->gpuaddr)) + if (_remove_gpuaddr(memdesc->pagetable, memdesc->gpuaddr)) BUG(); - spin_unlock(&pagetable->lock); + spin_unlock(&memdesc->pagetable->lock); } static int kgsl_iommu_svm_range(struct kgsl_pagetable *pagetable, diff --git a/drivers/gpu/msm/kgsl_mmu.c b/drivers/gpu/msm/kgsl_mmu.c index ba564b2851f9..0df1ad02f16e 100644 --- a/drivers/gpu/msm/kgsl_mmu.c +++ b/drivers/gpu/msm/kgsl_mmu.c @@ -414,17 +414,29 @@ EXPORT_SYMBOL(kgsl_mmu_map); * @pagetable: Pagetable to release the memory from * @memdesc: Memory descriptor containing the GPU address to free */ -void kgsl_mmu_put_gpuaddr(struct kgsl_pagetable *pagetable, - struct kgsl_memdesc *memdesc) +void kgsl_mmu_put_gpuaddr(struct kgsl_memdesc *memdesc) { + struct kgsl_pagetable *pagetable = memdesc->pagetable; + int unmap_fail = 0; + if (memdesc->size == 0 || memdesc->gpuaddr == 0) return; - if (PT_OP_VALID(pagetable, put_gpuaddr)) - pagetable->pt_ops->put_gpuaddr(pagetable, memdesc); + if (!kgsl_memdesc_is_global(memdesc)) + unmap_fail = kgsl_mmu_unmap(pagetable, memdesc); + + /* + * Do not free the gpuaddr/size if unmap fails. Because if we + * try to map this range in future, the iommu driver will throw + * a BUG_ON() because it feels we are overwriting a mapping. + */ + if (PT_OP_VALID(pagetable, put_gpuaddr) && (unmap_fail == 0)) + pagetable->pt_ops->put_gpuaddr(memdesc); if (!kgsl_memdesc_is_global(memdesc)) memdesc->gpuaddr = 0; + + memdesc->pagetable = NULL; } EXPORT_SYMBOL(kgsl_mmu_put_gpuaddr); @@ -610,7 +622,12 @@ static int nommu_get_gpuaddr(struct kgsl_pagetable *pagetable, memdesc->gpuaddr = (uint64_t) sg_phys(memdesc->sgt->sgl); - return memdesc->gpuaddr != 0 ? 0 : -ENOMEM; + if (memdesc->gpuaddr) { + memdesc->pagetable = pagetable; + return 0; + } + + return -ENOMEM; } static struct kgsl_mmu_pt_ops nommu_pt_ops = { diff --git a/drivers/gpu/msm/kgsl_mmu.h b/drivers/gpu/msm/kgsl_mmu.h index 3e32c25b3dbe..bc448d424ccb 100644 --- a/drivers/gpu/msm/kgsl_mmu.h +++ b/drivers/gpu/msm/kgsl_mmu.h @@ -92,7 +92,7 @@ struct kgsl_mmu_pt_ops { u64 (*get_ttbr0)(struct kgsl_pagetable *); u32 (*get_contextidr)(struct kgsl_pagetable *); int (*get_gpuaddr)(struct kgsl_pagetable *, struct kgsl_memdesc *); - void (*put_gpuaddr)(struct kgsl_pagetable *, struct kgsl_memdesc *); + void (*put_gpuaddr)(struct kgsl_memdesc *); uint64_t (*find_svm_region)(struct kgsl_pagetable *, uint64_t, uint64_t, uint64_t, uint64_t); int (*set_svm_region)(struct kgsl_pagetable *, uint64_t, uint64_t); @@ -181,8 +181,7 @@ int kgsl_mmu_map(struct kgsl_pagetable *pagetable, struct kgsl_memdesc *memdesc); int kgsl_mmu_unmap(struct kgsl_pagetable *pagetable, struct kgsl_memdesc *memdesc); -void kgsl_mmu_put_gpuaddr(struct kgsl_pagetable *pagetable, - struct kgsl_memdesc *memdesc); +void kgsl_mmu_put_gpuaddr(struct kgsl_memdesc *memdesc); unsigned int kgsl_virtaddr_to_physaddr(void *virtaddr); unsigned int kgsl_mmu_log_fault_addr(struct kgsl_mmu *mmu, u64 ttbr0, uint64_t addr); diff --git a/drivers/gpu/msm/kgsl_sharedmem.c b/drivers/gpu/msm/kgsl_sharedmem.c index 72895c18119f..b18934fb66ae 100644 --- a/drivers/gpu/msm/kgsl_sharedmem.c +++ b/drivers/gpu/msm/kgsl_sharedmem.c @@ -318,12 +318,11 @@ static int kgsl_cma_alloc_secure(struct kgsl_device *device, static int kgsl_allocate_secure(struct kgsl_device *device, struct kgsl_memdesc *memdesc, - struct kgsl_pagetable *pagetable, uint64_t size) { int ret; if (MMU_FEATURE(&device->mmu, KGSL_MMU_HYP_SECURE_ALLOC)) - ret = kgsl_sharedmem_page_alloc_user(memdesc, pagetable, size); + ret = kgsl_sharedmem_page_alloc_user(memdesc, size); else ret = kgsl_cma_alloc_secure(device, memdesc, size); @@ -332,7 +331,6 @@ static int kgsl_allocate_secure(struct kgsl_device *device, int kgsl_allocate_user(struct kgsl_device *device, struct kgsl_memdesc *memdesc, - struct kgsl_pagetable *pagetable, uint64_t size, uint64_t flags) { int ret; @@ -340,12 +338,11 @@ int kgsl_allocate_user(struct kgsl_device *device, memdesc->flags = flags; if (kgsl_mmu_get_mmutype(device) == KGSL_MMU_TYPE_NONE) - ret = kgsl_sharedmem_alloc_contig(device, memdesc, - pagetable, size); + ret = kgsl_sharedmem_alloc_contig(device, memdesc, size); else if (flags & KGSL_MEMFLAGS_SECURE) - ret = kgsl_allocate_secure(device, memdesc, pagetable, size); + ret = kgsl_allocate_secure(device, memdesc, size); else - ret = kgsl_sharedmem_page_alloc_user(memdesc, pagetable, size); + ret = kgsl_sharedmem_page_alloc_user(memdesc, size); return ret; } @@ -638,7 +635,6 @@ static inline int get_page_size(size_t size, unsigned int align) int kgsl_sharedmem_page_alloc_user(struct kgsl_memdesc *memdesc, - struct kgsl_pagetable *pagetable, uint64_t size) { int ret = 0; @@ -672,7 +668,6 @@ kgsl_sharedmem_page_alloc_user(struct kgsl_memdesc *memdesc, len_alloc = PAGE_ALIGN(size) >> PAGE_SHIFT; - memdesc->pagetable = pagetable; memdesc->ops = &kgsl_page_alloc_ops; /* @@ -806,18 +801,8 @@ void kgsl_sharedmem_free(struct kgsl_memdesc *memdesc) if (memdesc == NULL || memdesc->size == 0) return; - if (memdesc->gpuaddr) { - int ret = 0; - - ret = kgsl_mmu_unmap(memdesc->pagetable, memdesc); - /* - * Do not free the gpuaddr/size if unmap fails. Because if we - * try to map this range in future, the iommu driver will throw - * a BUG_ON() because it feels we are overwriting a mapping. - */ - if (ret == 0) - kgsl_mmu_put_gpuaddr(memdesc->pagetable, memdesc); - } + /* Make sure the memory object has been unmapped */ + kgsl_mmu_put_gpuaddr(memdesc); if (memdesc->ops && memdesc->ops->free) memdesc->ops->free(memdesc); @@ -997,8 +982,7 @@ void kgsl_get_memory_usage(char *name, size_t name_size, uint64_t memflags) EXPORT_SYMBOL(kgsl_get_memory_usage); int kgsl_sharedmem_alloc_contig(struct kgsl_device *device, - struct kgsl_memdesc *memdesc, - struct kgsl_pagetable *pagetable, uint64_t size) + struct kgsl_memdesc *memdesc, uint64_t size) { int result = 0; @@ -1007,7 +991,6 @@ int kgsl_sharedmem_alloc_contig(struct kgsl_device *device, return -EINVAL; memdesc->size = size; - memdesc->pagetable = pagetable; memdesc->ops = &kgsl_cma_ops; memdesc->dev = device->dev->parent; @@ -1098,7 +1081,6 @@ static int kgsl_cma_alloc_secure(struct kgsl_device *device, { struct kgsl_iommu *iommu = KGSL_IOMMU_PRIV(device); int result = 0; - struct kgsl_pagetable *pagetable = device->mmu.securepagetable; size_t aligned; /* Align size to 1M boundaries */ @@ -1118,7 +1100,6 @@ static int kgsl_cma_alloc_secure(struct kgsl_device *device, memdesc->priv &= ~KGSL_MEMDESC_GUARD_PAGE; memdesc->size = aligned; - memdesc->pagetable = pagetable; memdesc->ops = &kgsl_cma_ops; memdesc->dev = iommu->ctx[KGSL_IOMMU_CONTEXT_SECURE].dev; diff --git a/drivers/gpu/msm/kgsl_sharedmem.h b/drivers/gpu/msm/kgsl_sharedmem.h index 9e6817c76df8..03f278ead20f 100644 --- a/drivers/gpu/msm/kgsl_sharedmem.h +++ b/drivers/gpu/msm/kgsl_sharedmem.h @@ -26,7 +26,7 @@ struct kgsl_process_private; int kgsl_sharedmem_alloc_contig(struct kgsl_device *device, struct kgsl_memdesc *memdesc, - struct kgsl_pagetable *pagetable, uint64_t size); + uint64_t size); void kgsl_sharedmem_free(struct kgsl_memdesc *memdesc); @@ -66,13 +66,11 @@ void kgsl_sharedmem_uninit_sysfs(void); int kgsl_allocate_user(struct kgsl_device *device, struct kgsl_memdesc *memdesc, - struct kgsl_pagetable *pagetable, uint64_t size, uint64_t flags); void kgsl_get_memory_usage(char *str, size_t len, uint64_t memflags); int kgsl_sharedmem_page_alloc_user(struct kgsl_memdesc *memdesc, - struct kgsl_pagetable *pagetable, uint64_t size); #define MEMFLAGS(_flags, _mask, _shift) \ @@ -287,11 +285,10 @@ static inline int kgsl_allocate_global(struct kgsl_device *device, memdesc->priv = priv; if ((memdesc->priv & KGSL_MEMDESC_CONTIG) != 0) - ret = kgsl_sharedmem_alloc_contig(device, memdesc, NULL, + ret = kgsl_sharedmem_alloc_contig(device, memdesc, (size_t) size); else { - ret = kgsl_sharedmem_page_alloc_user(memdesc, NULL, - (size_t) size); + ret = kgsl_sharedmem_page_alloc_user(memdesc, (size_t) size); if (ret == 0) kgsl_memdesc_map(memdesc); } -- cgit v1.2.3 From b2949fa9686a3190098f11f513928aca345a22e6 Mon Sep 17 00:00:00 2001 From: Jordan Crouse Date: Tue, 31 May 2016 11:24:24 -0600 Subject: msm: kgsl: Make sure USE_CPU_MAP + MAP_USER_MEM work together If one is mapping anonyomous user memory in the GPU with SVM enabled we want to try to accommodate that request if possible. The memory address was being set up correctly in the memory descriptor but the GPU address was getting tripped up when getting mapped in the process. This is because the memory should be treated like SVM memory so it needs to be registered in the memory tree and the rest of the path needs to accept the address. Change-Id: Ic0dedbad661143977a226d50263c26b5af579ce3 Signed-off-by: Jordan Crouse --- drivers/gpu/msm/kgsl.c | 145 ++++++++++++++++++++++--------------------------- 1 file changed, 65 insertions(+), 80 deletions(-) diff --git a/drivers/gpu/msm/kgsl.c b/drivers/gpu/msm/kgsl.c index 01966bb31a09..d1e9b74ac49c 100644 --- a/drivers/gpu/msm/kgsl.c +++ b/drivers/gpu/msm/kgsl.c @@ -176,9 +176,10 @@ int kgsl_memfree_find_entry(pid_t ptname, uint64_t *gpuaddr, return 0; } -static void kgsl_memfree_purge(pid_t ptname, uint64_t gpuaddr, - uint64_t size) +static void kgsl_memfree_purge(struct kgsl_pagetable *pagetable, + uint64_t gpuaddr, uint64_t size) { + pid_t ptname = pagetable ? pagetable->name : 0; int i; if (memfree.list == NULL) @@ -342,40 +343,22 @@ kgsl_mem_entry_destroy(struct kref *kref) } EXPORT_SYMBOL(kgsl_mem_entry_destroy); -/** - * kgsl_mem_entry_track_gpuaddr - Insert a mem_entry in the address tree and - * assign it with a gpu address space before insertion - * @process: the process that owns the memory - * @entry: the memory entry - * - * @returns - 0 on succcess else error code - * - * Insert the kgsl_mem_entry in to the rb_tree for searching by GPU address. - * The assignment of gpu address and insertion into list needs to - * happen with the memory lock held to avoid race conditions between - * gpu address being selected and some other thread looking through the - * rb list in search of memory based on gpuaddr - * This function should be called with processes memory spinlock held - */ -static int -kgsl_mem_entry_track_gpuaddr(struct kgsl_process_private *process, - struct kgsl_mem_entry *entry) +/* Allocate a IOVA for memory objects that don't use SVM */ +static int kgsl_mem_entry_track_gpuaddr(struct kgsl_device *device, + struct kgsl_process_private *process, + struct kgsl_mem_entry *entry) { - struct kgsl_pagetable *pagetable = process->pagetable; + struct kgsl_pagetable *pagetable; /* - * If cpu=gpu map is used then caller needs to set the - * gpu address + * If SVM is enabled for this object then the address needs to be + * assigned elsewhere */ - if (kgsl_memdesc_use_cpu_map(&entry->memdesc)) { - if (!entry->memdesc.gpuaddr) - return 0; - } else if (entry->memdesc.gpuaddr) { - WARN_ONCE(1, "gpuaddr assigned w/o holding memory lock\n"); - return -EINVAL; - } - if (kgsl_memdesc_is_secured(&entry->memdesc)) - pagetable = pagetable->mmu->securepagetable; + if (kgsl_memdesc_use_cpu_map(&entry->memdesc)) + return 0; + + pagetable = kgsl_memdesc_is_secured(&entry->memdesc) ? + device->mmu.securepagetable : process->pagetable; return kgsl_mmu_get_gpuaddr(pagetable, &entry->memdesc); } @@ -391,33 +374,25 @@ static void kgsl_mem_entry_commit_process(struct kgsl_mem_entry *entry) spin_unlock(&entry->priv->mem_lock); } -/** - * kgsl_mem_entry_attach_process - Attach a mem_entry to its owner process - * @entry: the memory entry - * @process: the owner process - * - * Attach a newly created mem_entry to its owner process so that - * it can be found later. The mem_entry will be added to mem_idr and have - * its 'id' field assigned. - * - * @returns - 0 on success or error code on failure. +/* + * Attach the memory object to a process by (possibly) getting a GPU address and + * (possibly) mapping it */ -int -kgsl_mem_entry_attach_process(struct kgsl_mem_entry *entry, - struct kgsl_device_private *dev_priv) +static int kgsl_mem_entry_attach_process(struct kgsl_device *device, + struct kgsl_process_private *process, + struct kgsl_mem_entry *entry) { - int id; - int ret; - struct kgsl_process_private *process = dev_priv->process_priv; - struct kgsl_pagetable *pagetable = NULL; + int id, ret; ret = kgsl_process_private_get(process); if (!ret) return -EBADF; - ret = kgsl_mem_entry_track_gpuaddr(process, entry); - if (ret) - goto err_put_proc_priv; + ret = kgsl_mem_entry_track_gpuaddr(device, process, entry); + if (ret) { + kgsl_process_private_put(process); + return ret; + } idr_preload(GFP_KERNEL); spin_lock(&process->mem_lock); @@ -427,43 +402,40 @@ kgsl_mem_entry_attach_process(struct kgsl_mem_entry *entry, idr_preload_end(); if (id < 0) { - ret = id; - kgsl_mmu_put_gpuaddr(&entry->memdesc); - goto err_put_proc_priv; + if (!kgsl_memdesc_use_cpu_map(&entry->memdesc)) + kgsl_mmu_put_gpuaddr(&entry->memdesc); + kgsl_process_private_put(process); + return id; } entry->id = id; entry->priv = process; - /* map the memory after unlocking if gpuaddr has been assigned */ + /* + * Map the memory if a GPU address is already assigned, either through + * kgsl_mem_entry_track_gpuaddr() or via some other SVM process + */ if (entry->memdesc.gpuaddr) { - pagetable = process->pagetable; - if (kgsl_memdesc_is_secured(&entry->memdesc)) - pagetable = pagetable->mmu->securepagetable; - - entry->memdesc.pagetable = pagetable; - if (entry->memdesc.flags & KGSL_MEMFLAGS_SPARSE_VIRT) - ret = kgsl_mmu_sparse_dummy_map(pagetable, - &entry->memdesc, 0, entry->memdesc.size); + ret = kgsl_mmu_sparse_dummy_map( + entry->memdesc.pagetable, + &entry->memdesc, 0, + entry->memdesc.size); else if (entry->memdesc.gpuaddr) - ret = kgsl_mmu_map(pagetable, &entry->memdesc); + ret = kgsl_mmu_map(entry->memdesc.pagetable, + &entry->memdesc); + if (ret) kgsl_mem_entry_detach_process(entry); } - kgsl_memfree_purge(pagetable ? pagetable->name : 0, - entry->memdesc.gpuaddr, entry->memdesc.size); + kgsl_memfree_purge(entry->memdesc.pagetable, entry->memdesc.gpuaddr, + entry->memdesc.size); return ret; - -err_put_proc_priv: - kgsl_process_private_put(process); - return ret; } /* Detach a memory entry from a process and unmap it from the MMU */ - static void kgsl_mem_entry_detach_process(struct kgsl_mem_entry *entry) { unsigned int type; @@ -2114,10 +2086,21 @@ static int kgsl_setup_anon_useraddr(struct kgsl_pagetable *pagetable, entry->memdesc.pagetable = pagetable; entry->memdesc.size = (uint64_t) size; entry->memdesc.useraddr = hostptr; - if (kgsl_memdesc_use_cpu_map(&entry->memdesc)) - entry->memdesc.gpuaddr = (uint64_t) entry->memdesc.useraddr; entry->memdesc.flags |= KGSL_MEMFLAGS_USERMEM_ADDR; + if (kgsl_memdesc_use_cpu_map(&entry->memdesc)) { + int ret; + + /* Register the address in the database */ + ret = kgsl_mmu_set_svm_region(pagetable, + (uint64_t) entry->memdesc.useraddr, (uint64_t) size); + + if (ret) + return ret; + + entry->memdesc.gpuaddr = (uint64_t) entry->memdesc.useraddr; + } + return memdesc_sg_virt(&entry->memdesc, NULL); } @@ -2367,7 +2350,7 @@ long kgsl_ioctl_gpuobj_import(struct kgsl_device_private *dev_priv, param->flags = entry->memdesc.flags; - ret = kgsl_mem_entry_attach_process(entry, dev_priv); + ret = kgsl_mem_entry_attach_process(dev_priv->device, private, entry); if (ret) goto unmap; @@ -2630,7 +2613,8 @@ long kgsl_ioctl_map_user_mem(struct kgsl_device_private *dev_priv, /* echo back flags */ param->flags = (unsigned int) entry->memdesc.flags; - result = kgsl_mem_entry_attach_process(entry, dev_priv); + result = kgsl_mem_entry_attach_process(dev_priv->device, private, + entry); if (result) goto error_attach; @@ -3027,7 +3011,7 @@ static struct kgsl_mem_entry *gpumem_alloc_entry( if (ret != 0) goto err; - ret = kgsl_mem_entry_attach_process(entry, dev_priv); + ret = kgsl_mem_entry_attach_process(dev_priv->device, private, entry); if (ret != 0) { kgsl_sharedmem_free(&entry->memdesc); goto err; @@ -3293,6 +3277,7 @@ long kgsl_ioctl_sparse_phys_free(struct kgsl_device_private *dev_priv, long kgsl_ioctl_sparse_virt_alloc(struct kgsl_device_private *dev_priv, unsigned int cmd, void *data) { + struct kgsl_process_private *private = dev_priv->process_priv; struct kgsl_sparse_virt_alloc *param = data; struct kgsl_mem_entry *entry; int ret; @@ -3313,7 +3298,7 @@ long kgsl_ioctl_sparse_virt_alloc(struct kgsl_device_private *dev_priv, spin_lock_init(&entry->bind_lock); entry->bind_tree = RB_ROOT; - ret = kgsl_mem_entry_attach_process(entry, dev_priv); + ret = kgsl_mem_entry_attach_process(dev_priv->device, private, entry); if (ret) { kfree(entry); return ret; @@ -3999,8 +3984,8 @@ static unsigned long _gpu_set_svm_region(struct kgsl_process_private *private, return ret; } - kgsl_memfree_purge(private->pagetable ? private->pagetable->name : 0, - entry->memdesc.gpuaddr, entry->memdesc.size); + kgsl_memfree_purge(private->pagetable, entry->memdesc.gpuaddr, + entry->memdesc.size); return addr; } -- cgit v1.2.3 From cd88f39695983cc369de54bd35175a4f738600d3 Mon Sep 17 00:00:00 2001 From: Venkat Gopalakrishnan Date: Tue, 1 Nov 2016 11:54:27 -0700 Subject: phy: qcom-ufs: update ufs phy 1-lane settings The post silicon validated settings for phy-qcom-ufs-qmp-v3 applies only to the latest 2-lane phy version, revert the changes and keep the original settings for 1-lane phy version. Change-Id: Icb04f6175b66fa46405e77d10fddf06b0051ee5f Signed-off-by: Venkat Gopalakrishnan --- drivers/phy/phy-qcom-ufs-qmp-v3.h | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/drivers/phy/phy-qcom-ufs-qmp-v3.h b/drivers/phy/phy-qcom-ufs-qmp-v3.h index 8b1e03eab639..d5e49c281278 100644 --- a/drivers/phy/phy-qcom-ufs-qmp-v3.h +++ b/drivers/phy/phy-qcom-ufs-qmp-v3.h @@ -225,22 +225,22 @@ static struct ufs_qcom_phy_calibration phy_cal_table_rate_A_3_0_0[] = { UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_VCO_TUNE_INITVAL1, 0xFF), UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_VCO_TUNE_INITVAL2, 0x00), UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_DEC_START_MODE0, 0x82), - UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_CP_CTRL_MODE0, 0x06), + UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_CP_CTRL_MODE0, 0x08), UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_PLL_RCTRL_MODE0, 0x16), - UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_PLL_CCTRL_MODE0, 0x36), + UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_PLL_CCTRL_MODE0, 0x34), UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_INTEGLOOP_GAIN0_MODE0, 0x3F), UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_INTEGLOOP_GAIN1_MODE0, 0x00), - UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_VCO_TUNE1_MODE0, 0xDA), + UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_VCO_TUNE1_MODE0, 0xCB), UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_VCO_TUNE2_MODE0, 0x01), UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_LOCK_CMP1_MODE0, 0xFF), UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_LOCK_CMP2_MODE0, 0x0C), UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_DEC_START_MODE1, 0x98), - UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_CP_CTRL_MODE1, 0x06), + UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_CP_CTRL_MODE1, 0x08), UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_PLL_RCTRL_MODE1, 0x16), - UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_PLL_CCTRL_MODE1, 0x36), + UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_PLL_CCTRL_MODE1, 0x34), UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_INTEGLOOP_GAIN0_MODE1, 0x3F), UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_INTEGLOOP_GAIN1_MODE1, 0x00), - UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_VCO_TUNE1_MODE1, 0xC1), + UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_VCO_TUNE1_MODE1, 0xB2), UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_VCO_TUNE2_MODE1, 0x00), UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_LOCK_CMP1_MODE1, 0x32), UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_LOCK_CMP2_MODE1, 0x0F), -- cgit v1.2.3 From b1af46cf1a4682766de78d0d4aa32928c4e57eec Mon Sep 17 00:00:00 2001 From: Venkat Gopalakrishnan Date: Fri, 4 Nov 2016 12:27:07 -0700 Subject: scsi: ufs: fix sleep in atomic context Make sure spin lock is released before calling print host regs, as that call sleeps while dumping lots of registers. Change-Id: I171c91e700c24ecc213ccda705bbe6188d22a43a Signed-off-by: Venkat Gopalakrishnan --- drivers/scsi/ufs/ufshcd.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c index 862d56e78086..7577f9454626 100644 --- a/drivers/scsi/ufs/ufshcd.c +++ b/drivers/scsi/ufs/ufshcd.c @@ -5696,10 +5696,13 @@ static void ufshcd_err_handler(struct work_struct *work) dev_err(hba->dev, "%s: saved_err 0x%x saved_uic_err 0x%x", __func__, hba->saved_err, hba->saved_uic_err); if (!hba->silence_err_logs) { + /* release lock as print host regs sleeps */ + spin_unlock_irqrestore(hba->host->host_lock, flags); ufshcd_print_host_regs(hba); ufshcd_print_host_state(hba); ufshcd_print_pwr_info(hba); ufshcd_print_tmrs(hba, hba->outstanding_tasks); + spin_lock_irqsave(hba->host->host_lock, flags); } } -- cgit v1.2.3 From 70399030d0c3d4437b763c0206b6d4b6fe1b65af Mon Sep 17 00:00:00 2001 From: Venkat Gopalakrishnan Date: Fri, 4 Nov 2016 12:36:55 -0700 Subject: scsi: ufs: enable auto hibern8 only after device initialization Make sure auto hibern8 is enabled only after both host controller and device initialization is complete. Enabling it before device initialization could cause issues as the device might not be ready to handle hibern8 enter/exit before initialization. Change-Id: Ia3fb69dca00654dacd8d1faae34715e40e097480 Signed-off-by: Venkat Gopalakrishnan --- drivers/scsi/ufs/ufshcd.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c index 862d56e78086..2e041b4e1c78 100644 --- a/drivers/scsi/ufs/ufshcd.c +++ b/drivers/scsi/ufs/ufshcd.c @@ -6908,11 +6908,6 @@ static int ufshcd_probe_hba(struct ufs_hba *hba) if (ret) goto out; - /* Enable auto hibern8 if supported */ - if (ufshcd_is_auto_hibern8_supported(hba)) - ufshcd_set_auto_hibern8_timer(hba, - hba->hibern8_on_idle.delay_ms); - /* Debug counters initialization */ ufshcd_clear_dbg_ufs_stats(hba); /* set the default level for urgent bkops */ @@ -6979,6 +6974,13 @@ static int ufshcd_probe_hba(struct ufs_hba *hba) if (ufshcd_scsi_add_wlus(hba)) goto out; + /* Enable auto hibern8 if supported, after full host and + * device initialization. + */ + if (ufshcd_is_auto_hibern8_supported(hba)) + ufshcd_set_auto_hibern8_timer(hba, + hba->hibern8_on_idle.delay_ms); + /* Initialize devfreq after UFS device is detected */ if (ufshcd_is_clkscaling_supported(hba)) { memcpy(&hba->clk_scaling.saved_pwr_info.info, -- cgit v1.2.3 From 234b682c116244a97fad7758aa339bda3e95d986 Mon Sep 17 00:00:00 2001 From: Rajesh Yadav Date: Tue, 8 Nov 2016 10:46:42 +0530 Subject: msm: mdss: Add systrace for readptr_done Add systrace for readptr_done interrupt for cmd mode panel. Change-Id: I3694952289c76394af8d40cd89fd2175f49ac127 Signed-off-by: Rajesh Yadav --- drivers/video/fbdev/msm/mdss_mdp_intf_cmd.c | 1 + drivers/video/fbdev/msm/mdss_mdp_trace.h | 16 ++++++++++++++++ 2 files changed, 17 insertions(+) diff --git a/drivers/video/fbdev/msm/mdss_mdp_intf_cmd.c b/drivers/video/fbdev/msm/mdss_mdp_intf_cmd.c index 4eb121f01aca..e3896613cbe5 100644 --- a/drivers/video/fbdev/msm/mdss_mdp_intf_cmd.c +++ b/drivers/video/fbdev/msm/mdss_mdp_intf_cmd.c @@ -991,6 +991,7 @@ static void mdss_mdp_cmd_readptr_done(void *arg) vsync_time = ktime_get(); ctl->vsync_cnt++; MDSS_XLOG(ctl->num, atomic_read(&ctx->koff_cnt)); + trace_mdp_cmd_readptr_done(ctl->num, atomic_read(&ctx->koff_cnt)); complete_all(&ctx->rdptr_done); /* If caller is waiting for the read pointer, notify. */ diff --git a/drivers/video/fbdev/msm/mdss_mdp_trace.h b/drivers/video/fbdev/msm/mdss_mdp_trace.h index 648e4fcd1cd2..b79b4c70f5dc 100644 --- a/drivers/video/fbdev/msm/mdss_mdp_trace.h +++ b/drivers/video/fbdev/msm/mdss_mdp_trace.h @@ -372,6 +372,22 @@ TRACE_EVENT(mdp_cmd_pingpong_done, __entry->koff_cnt) ); +TRACE_EVENT(mdp_cmd_readptr_done, + TP_PROTO(u32 ctl_num, int koff_cnt), + TP_ARGS(ctl_num, koff_cnt), + TP_STRUCT__entry( + __field(u32, ctl_num) + __field(int, koff_cnt) + ), + TP_fast_assign( + __entry->ctl_num = ctl_num; + __entry->koff_cnt = koff_cnt; + ), + TP_printk("ctl num:%d kickoff:%d", + __entry->ctl_num, + __entry->koff_cnt) +); + TRACE_EVENT(mdp_cmd_release_bw, TP_PROTO(u32 ctl_num), TP_ARGS(ctl_num), -- cgit v1.2.3 From 057d86887c9086a6aab6c3cbe1032bda29f13359 Mon Sep 17 00:00:00 2001 From: Subhash Jadavani Date: Wed, 26 Oct 2016 16:30:40 -0700 Subject: scsi: ufs-qcom: update clock scaling sequence Update UFS clock frequency scaling sequence as specified in updated Hardware Programming Guide. Change-Id: Ief5df61d91fbd765c595533b3380a602a2540e5e Signed-off-by: Subhash Jadavani --- drivers/scsi/ufs/ufs-qcom.c | 84 +++++++++++++++++++-------------------------- 1 file changed, 36 insertions(+), 48 deletions(-) diff --git a/drivers/scsi/ufs/ufs-qcom.c b/drivers/scsi/ufs/ufs-qcom.c index 873b4615d4a9..603cbe65825b 100644 --- a/drivers/scsi/ufs/ufs-qcom.c +++ b/drivers/scsi/ufs/ufs-qcom.c @@ -412,8 +412,9 @@ static int ufs_qcom_hce_enable_notify(struct ufs_hba *hba, /** * Returns zero for success and non-zero in case of a failure */ -static int ufs_qcom_cfg_timers(struct ufs_hba *hba, u32 gear, - u32 hs, u32 rate, bool update_link_startup_timer) +static int __ufs_qcom_cfg_timers(struct ufs_hba *hba, u32 gear, + u32 hs, u32 rate, bool update_link_startup_timer, + bool is_pre_scale_up) { int ret = 0; struct ufs_qcom_host *host = ufshcd_get_variant(hba); @@ -460,8 +461,12 @@ static int ufs_qcom_cfg_timers(struct ufs_hba *hba, u32 gear, } list_for_each_entry(clki, &hba->clk_list_head, list) { - if (!strcmp(clki->name, "core_clk")) - core_clk_rate = clk_get_rate(clki->clk); + if (!strcmp(clki->name, "core_clk")) { + if (is_pre_scale_up) + core_clk_rate = clki->max_freq; + else + core_clk_rate = clk_get_rate(clki->clk); + } } /* If frequency is smaller than 1MHz, set to 1MHz */ @@ -558,6 +563,13 @@ out: return ret; } +static int ufs_qcom_cfg_timers(struct ufs_hba *hba, u32 gear, + u32 hs, u32 rate, bool update_link_startup_timer) +{ + return __ufs_qcom_cfg_timers(hba, gear, hs, rate, + update_link_startup_timer, false); +} + static int ufs_qcom_link_startup_pre_change(struct ufs_hba *hba) { struct ufs_qcom_host *host = ufshcd_get_variant(hba); @@ -2160,61 +2172,49 @@ out: static int ufs_qcom_clk_scale_up_pre_change(struct ufs_hba *hba) { struct ufs_qcom_host *host = ufshcd_get_variant(hba); + struct ufs_pa_layer_attr *attr = &host->dev_req_params; + int err = 0; if (!ufs_qcom_cap_qunipro(host)) - return 0; - - return ufs_qcom_configure_lpm(hba, false); -} + goto out; -static int ufs_qcom_clk_scale_up_post_change(struct ufs_hba *hba) -{ - struct ufs_qcom_host *host = ufshcd_get_variant(hba); + err = ufs_qcom_configure_lpm(hba, false); + if (err) + goto out; - if (!ufs_qcom_cap_qunipro(host)) - return 0; + if (attr) + __ufs_qcom_cfg_timers(hba, attr->gear_rx, attr->pwr_rx, + attr->hs_rate, false, true); /* set unipro core clock cycles to 150 and clear clock divider */ - return ufs_qcom_set_dme_vs_core_clk_ctrl_clear_div(hba, 150); + err = ufs_qcom_set_dme_vs_core_clk_ctrl_clear_div(hba, 150); +out: + return err; } static int ufs_qcom_clk_scale_down_pre_change(struct ufs_hba *hba) { struct ufs_qcom_host *host = ufshcd_get_variant(hba); - u32 core_clk_ctrl_reg; - int err = 0; if (!ufs_qcom_cap_qunipro(host)) - goto out; - - err = ufs_qcom_configure_lpm(hba, true); - if (err) - goto out; - - err = ufshcd_dme_get(hba, - UIC_ARG_MIB(DME_VS_CORE_CLK_CTRL), - &core_clk_ctrl_reg); + return 0; - /* make sure CORE_CLK_DIV_EN is cleared */ - if (!err && - (core_clk_ctrl_reg & DME_VS_CORE_CLK_CTRL_CORE_CLK_DIV_EN_BIT)) { - core_clk_ctrl_reg &= ~DME_VS_CORE_CLK_CTRL_CORE_CLK_DIV_EN_BIT; - err = ufshcd_dme_set(hba, - UIC_ARG_MIB(DME_VS_CORE_CLK_CTRL), - core_clk_ctrl_reg); - } -out: - return err; + return ufs_qcom_configure_lpm(hba, true); } static int ufs_qcom_clk_scale_down_post_change(struct ufs_hba *hba) { struct ufs_qcom_host *host = ufshcd_get_variant(hba); + struct ufs_pa_layer_attr *attr = &host->dev_req_params; int err = 0; if (!ufs_qcom_cap_qunipro(host)) return 0; + if (attr) + ufs_qcom_cfg_timers(hba, attr->gear_rx, attr->pwr_rx, + attr->hs_rate, false); + if (ufs_qcom_cap_svs2(host)) /* * For SVS2 set unipro core clock cycles to 37 and @@ -2235,7 +2235,6 @@ static int ufs_qcom_clk_scale_notify(struct ufs_hba *hba, bool scale_up, enum ufs_notify_change_status status) { struct ufs_qcom_host *host = ufshcd_get_variant(hba); - struct ufs_pa_layer_attr *dev_req_params = &host->dev_req_params; int err = 0; switch (status) { @@ -2246,19 +2245,9 @@ static int ufs_qcom_clk_scale_notify(struct ufs_hba *hba, err = ufs_qcom_clk_scale_down_pre_change(hba); break; case POST_CHANGE: - if (scale_up) - err = ufs_qcom_clk_scale_up_post_change(hba); - else + if (!scale_up) err = ufs_qcom_clk_scale_down_post_change(hba); - if (err || !dev_req_params) - goto out; - - ufs_qcom_cfg_timers(hba, - dev_req_params->gear_rx, - dev_req_params->pwr_rx, - dev_req_params->hs_rate, - false); ufs_qcom_update_bus_bw_vote(host); break; default: @@ -2267,7 +2256,6 @@ static int ufs_qcom_clk_scale_notify(struct ufs_hba *hba, break; } -out: return err; } -- cgit v1.2.3 From d8bd53c2aea41c1b01279336f1f6cc7400dd3edf Mon Sep 17 00:00:00 2001 From: Ingrid Gallardo Date: Tue, 8 Nov 2016 11:40:48 -0800 Subject: msm: mdss: move warnings and errors out of mdss spinlock Current display driver prints warnings and errors within the mdss spinlock. This causes in random cases to hold the spinlock for long time when multiple errors are printed; Fix this by moving the print of warning and error messages outside of the spinlock. Change-Id: I09359b528b4742f72a76690930f3d0ed90bb2caa Signed-off-by: Ingrid Gallardo --- drivers/video/fbdev/msm/mdss_util.c | 25 ++++++++++++++++++++----- 1 file changed, 20 insertions(+), 5 deletions(-) diff --git a/drivers/video/fbdev/msm/mdss_util.c b/drivers/video/fbdev/msm/mdss_util.c index d2610ff80878..65941601cfdc 100644 --- a/drivers/video/fbdev/msm/mdss_util.c +++ b/drivers/video/fbdev/msm/mdss_util.c @@ -23,6 +23,7 @@ int mdss_register_irq(struct mdss_hw *hw) { unsigned long irq_flags; u32 ndx_bit; + bool err = false; if (!hw || hw->hw_ndx >= MDSS_MAX_HW_BLK) return -EINVAL; @@ -33,10 +34,12 @@ int mdss_register_irq(struct mdss_hw *hw) if (!mdss_irq_handlers[hw->hw_ndx]) mdss_irq_handlers[hw->hw_ndx] = hw; else - pr_err("panel %d's irq at %pK is already registered\n", - hw->hw_ndx, hw->irq_handler); + err = true; spin_unlock_irqrestore(&mdss_lock, irq_flags); + if (err) + pr_err("panel %d's irq at %pK is already registered\n", + hw->hw_ndx, hw->irq_handler); return 0; } @@ -76,6 +79,7 @@ void mdss_disable_irq(struct mdss_hw *hw) { unsigned long irq_flags; u32 ndx_bit; + bool err = false; if (hw->hw_ndx >= MDSS_MAX_HW_BLK) return; @@ -87,7 +91,7 @@ void mdss_disable_irq(struct mdss_hw *hw) spin_lock_irqsave(&mdss_lock, irq_flags); if (!(hw->irq_info->irq_mask & ndx_bit)) { - pr_warn("MDSS HW ndx=%d is NOT set\n", hw->hw_ndx); + err = true; } else { hw->irq_info->irq_mask &= ~ndx_bit; if (hw->irq_info->irq_mask == 0) { @@ -96,12 +100,16 @@ void mdss_disable_irq(struct mdss_hw *hw) } } spin_unlock_irqrestore(&mdss_lock, irq_flags); + + if (err) + pr_warn("MDSS HW ndx=%d is NOT set\n", hw->hw_ndx); } /* called from interrupt context */ void mdss_disable_irq_nosync(struct mdss_hw *hw) { u32 ndx_bit; + bool err = false; if (hw->hw_ndx >= MDSS_MAX_HW_BLK) return; @@ -113,7 +121,7 @@ void mdss_disable_irq_nosync(struct mdss_hw *hw) spin_lock(&mdss_lock); if (!(hw->irq_info->irq_mask & ndx_bit)) { - pr_warn("MDSS HW ndx=%d is NOT set\n", hw->hw_ndx); + err = true; } else { hw->irq_info->irq_mask &= ~ndx_bit; if (hw->irq_info->irq_mask == 0) { @@ -122,6 +130,9 @@ void mdss_disable_irq_nosync(struct mdss_hw *hw) } } spin_unlock(&mdss_lock); + + if (err) + pr_warn("MDSS HW ndx=%d is NOT set\n", hw->hw_ndx); } int mdss_irq_dispatch(u32 hw_ndx, int irq, void *ptr) @@ -176,6 +187,7 @@ void mdss_disable_irq_wake(struct mdss_hw *hw) { unsigned long irq_flags; u32 ndx_bit; + bool err = false; if (hw->hw_ndx >= MDSS_MAX_HW_BLK) return; @@ -188,7 +200,7 @@ void mdss_disable_irq_wake(struct mdss_hw *hw) spin_lock_irqsave(&mdss_lock, irq_flags); if (!(hw->irq_info->irq_wake_mask & ndx_bit)) { - pr_warn("MDSS HW ndx=%d is NOT set\n", hw->hw_ndx); + err = true; } else { hw->irq_info->irq_wake_mask &= ~ndx_bit; if (hw->irq_info->irq_wake_ena) { @@ -197,6 +209,9 @@ void mdss_disable_irq_wake(struct mdss_hw *hw) } } spin_unlock_irqrestore(&mdss_lock, irq_flags); + + if (err) + pr_warn("MDSS HW ndx=%d is NOT set\n", hw->hw_ndx); } struct mdss_util_intf mdss_util = { -- cgit v1.2.3 From 8164972a6c3ead37c6c5aad159b9ff246ccdeff1 Mon Sep 17 00:00:00 2001 From: Meng Wang Date: Wed, 9 Nov 2016 11:00:56 +0800 Subject: ASoC: msm: q6dspv2: fix potentional information leak The heap buffer pointed to out_buffer and in_buffer are allocated but uninitlalized. It may cause information leak. Change to kzalloc instead of kmalloc when allocating kernel buffers to avoid information leak. CRs-Fixed: 1087020 Change-Id: I6f9b7a630158355a7f920dcf9cfffe537b1c6a85 Signed-off-by: Meng Wang --- sound/soc/msm/qdsp6v2/q6asm.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sound/soc/msm/qdsp6v2/q6asm.c b/sound/soc/msm/qdsp6v2/q6asm.c index 2874a334dfdd..93d9efc078cb 100644 --- a/sound/soc/msm/qdsp6v2/q6asm.c +++ b/sound/soc/msm/qdsp6v2/q6asm.c @@ -421,12 +421,12 @@ static void config_debug_fs_write(struct audio_buffer *ab) } static void config_debug_fs_init(void) { - out_buffer = kmalloc(OUT_BUFFER_SIZE, GFP_KERNEL); + out_buffer = kzalloc(OUT_BUFFER_SIZE, GFP_KERNEL); if (out_buffer == NULL) { pr_err("%s: kmalloc() for out_buffer failed\n", __func__); goto outbuf_fail; } - in_buffer = kmalloc(IN_BUFFER_SIZE, GFP_KERNEL); + in_buffer = kzalloc(IN_BUFFER_SIZE, GFP_KERNEL); if (in_buffer == NULL) { pr_err("%s: kmalloc() for in_buffer failed\n", __func__); goto inbuf_fail; -- cgit v1.2.3 From 03d619d6d4cc8c7b485ff12bebd815de62051779 Mon Sep 17 00:00:00 2001 From: Asutosh Das Date: Thu, 15 Sep 2016 12:26:28 +0530 Subject: Revert "scsi: ufs: stub UFS shutdown handler" This reverts commit aa484ff4b600 ("scsi: ufs: stub UFS shutdown handler"). This is reverted so as to enable PON (Power-off Notification). PON would notify the ufs device of the incoming power-down so that the device can prepare for the same before the power to the device is cut. CRs-fixed: 941978 Change-Id: Idee8691d769218d7e732c9b7f936a2c40946b239 Signed-off-by: Asutosh Das --- drivers/scsi/ufs/ufshcd.c | 21 ++++++++++++++++----- 1 file changed, 16 insertions(+), 5 deletions(-) diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c index 862d56e78086..081e1a51ae45 100644 --- a/drivers/scsi/ufs/ufshcd.c +++ b/drivers/scsi/ufs/ufshcd.c @@ -8654,11 +8654,22 @@ static inline void ufshcd_add_sysfs_nodes(struct ufs_hba *hba) */ int ufshcd_shutdown(struct ufs_hba *hba) { - /* - * TODO: This function should send the power down notification to - * UFS device and then power off the UFS link. But we need to be sure - * that there will not be any new UFS requests issued after this. - */ + int ret = 0; + + if (ufshcd_is_ufs_dev_poweroff(hba) && ufshcd_is_link_off(hba)) + goto out; + + if (pm_runtime_suspended(hba->dev)) { + ret = ufshcd_runtime_resume(hba); + if (ret) + goto out; + } + + ret = ufshcd_suspend(hba, UFS_SHUTDOWN_PM); +out: + if (ret) + dev_err(hba->dev, "%s failed, err %d\n", __func__, ret); + /* allow force shutdown even in case of errors */ return 0; } EXPORT_SYMBOL(ufshcd_shutdown); -- cgit v1.2.3 From 6c8569ceccc2792994a340b29ff310822b21a5c8 Mon Sep 17 00:00:00 2001 From: Karthikeyan Mani Date: Wed, 19 Oct 2016 20:14:31 -0700 Subject: ASoC: wcd934x: Fix adie loopback through sidetone src path Interpolator clock is not being enabled for codec adie loopback through sidetone src path. Fix the issue by enabling interpolator clock in DAPM PRE_PMU and disable the clock in the POST_PMD callback function. Change-Id: I822d6280b301b2db6194c845098c935e612ca61c Signed-off-by: Karthikeyan Mani --- sound/soc/codecs/wcd934x/wcd934x.c | 78 ++++++++++++++++++++++++++++---------- 1 file changed, 57 insertions(+), 21 deletions(-) diff --git a/sound/soc/codecs/wcd934x/wcd934x.c b/sound/soc/codecs/wcd934x/wcd934x.c index d989ae3bed6c..900fd1d9c000 100644 --- a/sound/soc/codecs/wcd934x/wcd934x.c +++ b/sound/soc/codecs/wcd934x/wcd934x.c @@ -2366,19 +2366,20 @@ static int __tavil_codec_enable_swr(struct snd_soc_dapm_widget *w, int event) { struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); struct tavil_priv *tavil; - int ch_cnt; + int ch_cnt = 0; tavil = snd_soc_codec_get_drvdata(codec); switch (event) { case SND_SOC_DAPM_PRE_PMU: - if ((strnstr(w->name, "INT7_", sizeof("RX INT7_"))) && - !tavil->swr.rx_7_count) + if (((strnstr(w->name, "INT7_", sizeof("RX INT7_"))) || + (strnstr(w->name, "INT7 MIX2", + sizeof("RX INT7 MIX2"))))) tavil->swr.rx_7_count++; if ((strnstr(w->name, "INT8_", sizeof("RX INT8_"))) && !tavil->swr.rx_8_count) tavil->swr.rx_8_count++; - ch_cnt = tavil->swr.rx_7_count + tavil->swr.rx_8_count; + ch_cnt = !!(tavil->swr.rx_7_count) + tavil->swr.rx_8_count; swrm_wcd_notify(tavil->swr.ctrl_data[0].swr_pdev, SWR_DEVICE_UP, NULL); @@ -2386,21 +2387,22 @@ static int __tavil_codec_enable_swr(struct snd_soc_dapm_widget *w, int event) SWR_SET_NUM_RX_CH, &ch_cnt); break; case SND_SOC_DAPM_POST_PMD: - if ((strnstr(w->name, "INT7_", sizeof("RX INT7_"))) && - tavil->swr.rx_7_count) + if ((strnstr(w->name, "INT7_", sizeof("RX INT7_"))) || + (strnstr(w->name, "INT7 MIX2", + sizeof("RX INT7 MIX2")))) tavil->swr.rx_7_count--; if ((strnstr(w->name, "INT8_", sizeof("RX INT8_"))) && tavil->swr.rx_8_count) tavil->swr.rx_8_count--; - ch_cnt = tavil->swr.rx_7_count + tavil->swr.rx_8_count; + ch_cnt = !!(tavil->swr.rx_7_count) + tavil->swr.rx_8_count; swrm_wcd_notify(tavil->swr.ctrl_data[0].swr_pdev, SWR_SET_NUM_RX_CH, &ch_cnt); break; } - dev_dbg(tavil->dev, "%s: current swr ch cnt: %d\n", - __func__, tavil->swr.rx_7_count + tavil->swr.rx_8_count); + dev_dbg(tavil->dev, "%s: %s: current swr ch cnt: %d\n", + __func__, w->name, ch_cnt); return 0; } @@ -3685,6 +3687,34 @@ static void tavil_tx_mute_update_callback(struct work_struct *work) snd_soc_update_bits(codec, tx_vol_ctl_reg, 0x10, 0x00); } +static int tavil_codec_enable_rx_path_clk(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); + u16 sidetone_reg; + + dev_dbg(codec->dev, "%s %d %d\n", __func__, event, w->shift); + sidetone_reg = WCD934X_CDC_RX0_RX_PATH_CFG1 + 0x14*(w->shift); + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + if (!strcmp(w->name, "RX INT7 MIX2 INP")) + __tavil_codec_enable_swr(w, event); + tavil_codec_enable_interp_clk(codec, event, w->shift); + snd_soc_update_bits(codec, sidetone_reg, 0x10, 0x10); + break; + case SND_SOC_DAPM_POST_PMD: + snd_soc_update_bits(codec, sidetone_reg, 0x10, 0x00); + tavil_codec_enable_interp_clk(codec, event, w->shift); + if (!strcmp(w->name, "RX INT7 MIX2 INP")) + __tavil_codec_enable_swr(w, event); + break; + default: + break; + }; + return 0; +} + static int tavil_codec_enable_dec(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol, int event) { @@ -6630,18 +6660,24 @@ static const struct snd_soc_dapm_widget tavil_dapm_widgets[] = { NULL, 0, tavil_codec_spk_boost_event, SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), - SND_SOC_DAPM_MUX("RX INT0 MIX2 INP", WCD934X_CDC_RX0_RX_PATH_CFG1, 4, - 0, &rx_int0_mix2_inp_mux), - SND_SOC_DAPM_MUX("RX INT1 MIX2 INP", WCD934X_CDC_RX1_RX_PATH_CFG1, 4, - 0, &rx_int1_mix2_inp_mux), - SND_SOC_DAPM_MUX("RX INT2 MIX2 INP", WCD934X_CDC_RX2_RX_PATH_CFG1, 4, - 0, &rx_int2_mix2_inp_mux), - SND_SOC_DAPM_MUX("RX INT3 MIX2 INP", WCD934X_CDC_RX3_RX_PATH_CFG1, 4, - 0, &rx_int3_mix2_inp_mux), - SND_SOC_DAPM_MUX("RX INT4 MIX2 INP", WCD934X_CDC_RX4_RX_PATH_CFG1, 4, - 0, &rx_int4_mix2_inp_mux), - SND_SOC_DAPM_MUX("RX INT7 MIX2 INP", WCD934X_CDC_RX7_RX_PATH_CFG1, 4, - 0, &rx_int7_mix2_inp_mux), + SND_SOC_DAPM_MUX_E("RX INT0 MIX2 INP", SND_SOC_NOPM, INTERP_EAR, + 0, &rx_int0_mix2_inp_mux, tavil_codec_enable_rx_path_clk, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_MUX_E("RX INT1 MIX2 INP", SND_SOC_NOPM, INTERP_HPHL, + 0, &rx_int1_mix2_inp_mux, tavil_codec_enable_rx_path_clk, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_MUX_E("RX INT2 MIX2 INP", SND_SOC_NOPM, INTERP_HPHR, + 0, &rx_int2_mix2_inp_mux, tavil_codec_enable_rx_path_clk, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_MUX_E("RX INT3 MIX2 INP", SND_SOC_NOPM, INTERP_LO1, + 0, &rx_int3_mix2_inp_mux, tavil_codec_enable_rx_path_clk, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_MUX_E("RX INT4 MIX2 INP", SND_SOC_NOPM, INTERP_LO2, + 0, &rx_int4_mix2_inp_mux, tavil_codec_enable_rx_path_clk, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_MUX_E("RX INT7 MIX2 INP", SND_SOC_NOPM, INTERP_SPKR1, + 0, &rx_int7_mix2_inp_mux, tavil_codec_enable_rx_path_clk, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), WCD_DAPM_MUX("CDC_IF TX0 MUX", WCD934X_TX0, cdc_if_tx0), WCD_DAPM_MUX("CDC_IF TX1 MUX", WCD934X_TX1, cdc_if_tx1), -- cgit v1.2.3 From acef8428426c5dad44d940d88b619fcd3282e28a Mon Sep 17 00:00:00 2001 From: Naseer Ahmed Date: Wed, 9 Nov 2016 12:14:31 -0500 Subject: msm: mdss: fix incorrect mutex unlocking during NOTIFY_UPDATE_STOP When servicing NOTIFY_UPDATE_STOP command, if the notify object was uninitialized then mutex lock is obtained on one object but unlock is done on a different object. This change fixes it. CRs-Fixed: 1088059 Change-Id: I66cbe48b7f4910228a6af57610a8427fea7fd1f2 Signed-off-by: Naseer Ahmed --- drivers/video/fbdev/msm/mdss_fb.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/video/fbdev/msm/mdss_fb.c b/drivers/video/fbdev/msm/mdss_fb.c index 08e06c75522a..d528305af798 100644 --- a/drivers/video/fbdev/msm/mdss_fb.c +++ b/drivers/video/fbdev/msm/mdss_fb.c @@ -233,9 +233,11 @@ static int mdss_fb_notify_update(struct msm_fb_data_type *mfd, } } else if (notify == NOTIFY_UPDATE_STOP) { mutex_lock(&mfd->update.lock); - if (mfd->update.init_done) + if (mfd->update.init_done) { + mutex_unlock(&mfd->update.lock); + mutex_lock(&mfd->no_update.lock); reinit_completion(&mfd->no_update.comp); - else { + } else { mutex_unlock(&mfd->update.lock); pr_err("notify update stop called without init\n"); return -EINVAL; -- cgit v1.2.3 From d9ad202490911c8f87cf136cc2c3fa4aa90d449e Mon Sep 17 00:00:00 2001 From: Asutosh Das Date: Tue, 13 Sep 2016 11:44:14 +0530 Subject: scsi: ufs: error out all issued requests after shutdown After PON (power-off notification) is sent, no requests should be issued to the driver. This change errors out all requests except from shutdown context after shutdown is initiated. Change-Id: Id499abc27303bfed72fab4d61abb872bad7d9043 Signed-off-by: Asutosh Das --- drivers/scsi/ufs/ufshcd.c | 122 ++++++++++++++++++++++++++++++++++++++++------ drivers/scsi/ufs/ufshcd.h | 15 +++++- 2 files changed, 121 insertions(+), 16 deletions(-) diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c index 081e1a51ae45..19a8aacf98d0 100644 --- a/drivers/scsi/ufs/ufshcd.c +++ b/drivers/scsi/ufs/ufshcd.c @@ -2632,6 +2632,65 @@ static inline u16 ufshcd_upiu_wlun_to_scsi_wlun(u8 upiu_wlun_id) return (upiu_wlun_id & ~UFS_UPIU_WLUN_ID) | SCSI_W_LUN_BASE; } +/** + * ufshcd_get_write_lock - synchronize between shutdown, scaling & + * arrival of requests + * @hba: ufs host + * + * Lock is predominantly held by shutdown context thus, ensuring + * that no requests from any other context may sneak through. + */ +static void ufshcd_get_write_lock(struct ufs_hba *hba) +{ + down_write(&hba->lock); + hba->issuing_task = current; +} + +/** + * ufshcd_get_read_lock - synchronize between shutdown, scaling & + * arrival of requests + * @hba: ufs host + * + * Returns 1 if acquired, < 0 on contention + * + * After shutdown's initiated, allow requests only from shutdown + * context. The sync between scaling & issue is maintained + * as is and this restructuring syncs shutdown with these too. + */ +static int ufshcd_get_read_lock(struct ufs_hba *hba) +{ + int err = 0; + + err = down_read_trylock(&hba->lock); + if (err > 0) + goto out; + if (hba->issuing_task == current) + return 0; + else if (!ufshcd_is_shutdown_ongoing(hba)) + return -EAGAIN; + else + return -EPERM; + +out: + hba->issuing_task = current; + return err; +} + +/** + * ufshcd_put_read_lock - synchronize between shutdown, scaling & + * arrival of requests + * @hba: ufs host + * + * Returns none + */ +static inline void ufshcd_put_read_lock(struct ufs_hba *hba) +{ + if (!ufshcd_is_shutdown_ongoing(hba)) { + hba->issuing_task = NULL; + up_read(&hba->lock); + } +} + /** * ufshcd_queuecommand - main entry point for SCSI requests * @cmd: command from SCSI Midlayer @@ -2657,8 +2716,16 @@ static int ufshcd_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *cmd) BUG(); } - if (!down_read_trylock(&hba->clk_scaling_lock)) - return SCSI_MLQUEUE_HOST_BUSY; + err = ufshcd_get_read_lock(hba); + if (unlikely(err < 0)) { + if (err == -EPERM) { + set_host_byte(cmd, DID_ERROR); + cmd->scsi_done(cmd); + return 0; + } + if (err == -EAGAIN) + return SCSI_MLQUEUE_HOST_BUSY; + } spin_lock_irqsave(hba->host->host_lock, flags); @@ -2798,7 +2865,7 @@ static int ufshcd_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *cmd) out_unlock: spin_unlock_irqrestore(hba->host->host_lock, flags); out: - up_read(&hba->clk_scaling_lock); + ufshcd_put_read_lock(hba); return err; } @@ -2990,7 +3057,12 @@ static int ufshcd_exec_dev_cmd(struct ufs_hba *hba, struct completion wait; unsigned long flags; - down_read(&hba->clk_scaling_lock); + /* + * May get invoked from shutdown and IOCTL contexts. + * In shutdown context, it comes in with lock acquired. + */ + if (!ufshcd_is_shutdown_ongoing(hba)) + down_read(&hba->lock); /* * Get free slot, sleep if slots are unavailable. @@ -3023,7 +3095,8 @@ static int ufshcd_exec_dev_cmd(struct ufs_hba *hba, out_put_tag: ufshcd_put_dev_cmd_tag(hba, tag); wake_up(&hba->dev_cmd.tag_wq); - up_read(&hba->clk_scaling_lock); + if (!ufshcd_is_shutdown_ongoing(hba)) + up_read(&hba->lock); return err; } @@ -8659,12 +8732,27 @@ int ufshcd_shutdown(struct ufs_hba *hba) if (ufshcd_is_ufs_dev_poweroff(hba) && ufshcd_is_link_off(hba)) goto out; - if (pm_runtime_suspended(hba->dev)) { - ret = ufshcd_runtime_resume(hba); - if (ret) - goto out; - } - + pm_runtime_get_sync(hba->dev); + ufshcd_hold_all(hba); + /** + * (1) Acquire the lock to stop any more requests + * (2) Set state to shutting down + * (3) Suspend clock scaling + * (4) Wait for all issued requests to complete + */ + ufshcd_get_write_lock(hba); + ufshcd_mark_shutdown_ongoing(hba); + ufshcd_scsi_block_requests(hba); + ufshcd_suspend_clkscaling(hba); + ret = ufshcd_wait_for_doorbell_clr(hba, U64_MAX); + if (ret) + dev_err(hba->dev, "%s: waiting for DB clear: failed: %d\n", + __func__, ret); + /* Requests may have errored out above, let it be handled */ + flush_work(&hba->eh_work); + /* reqs issued from contexts other than shutdown will fail from now */ + ufshcd_scsi_unblock_requests(hba); + ufshcd_release_all(hba); ret = ufshcd_suspend(hba, UFS_SHUTDOWN_PM); out: if (ret) @@ -8854,10 +8942,10 @@ static int ufshcd_clock_scaling_prepare(struct ufs_hba *hba) * clock scaling is in progress */ ufshcd_scsi_block_requests(hba); - down_write(&hba->clk_scaling_lock); + down_write(&hba->lock); if (ufshcd_wait_for_doorbell_clr(hba, DOORBELL_CLR_TOUT_US)) { ret = -EBUSY; - up_write(&hba->clk_scaling_lock); + up_write(&hba->lock); ufshcd_scsi_unblock_requests(hba); } @@ -8866,7 +8954,7 @@ static int ufshcd_clock_scaling_prepare(struct ufs_hba *hba) static void ufshcd_clock_scaling_unprepare(struct ufs_hba *hba) { - up_write(&hba->clk_scaling_lock); + up_write(&hba->lock); ufshcd_scsi_unblock_requests(hba); } @@ -9049,6 +9137,10 @@ static void ufshcd_clk_scaling_resume_work(struct work_struct *work) clk_scaling.resume_work); unsigned long irq_flags; + /* Let's not resume scaling if shutdown is ongoing */ + if (ufshcd_is_shutdown_ongoing(hba)) + return; + spin_lock_irqsave(hba->host->host_lock, irq_flags); if (!hba->clk_scaling.is_suspended) { spin_unlock_irqrestore(hba->host->host_lock, irq_flags); @@ -9261,7 +9353,7 @@ int ufshcd_init(struct ufs_hba *hba, void __iomem *mmio_base, unsigned int irq) /* Initialize mutex for device management commands */ mutex_init(&hba->dev_cmd.lock); - init_rwsem(&hba->clk_scaling_lock); + init_rwsem(&hba->lock); /* Initialize device management tag acquire wait queue */ init_waitqueue_head(&hba->dev_cmd.tag_wq); diff --git a/drivers/scsi/ufs/ufshcd.h b/drivers/scsi/ufs/ufshcd.h index c0714b7bea72..74fe46cf34fe 100644 --- a/drivers/scsi/ufs/ufshcd.h +++ b/drivers/scsi/ufs/ufshcd.h @@ -895,7 +895,10 @@ struct ufs_hba { enum bkops_status urgent_bkops_lvl; bool is_urgent_bkops_lvl_checked; - struct rw_semaphore clk_scaling_lock; + /* sync b/w diff contexts */ + struct rw_semaphore lock; + struct task_struct *issuing_task; + unsigned long shutdown_in_prog; struct reset_control *core_reset; /* If set, don't gate device ref_clk during clock gating */ @@ -904,6 +907,16 @@ struct ufs_hba { int scsi_block_reqs_cnt; }; +static inline void ufshcd_mark_shutdown_ongoing(struct ufs_hba *hba) +{ + set_bit(0, &hba->shutdown_in_prog); +} + +static inline bool ufshcd_is_shutdown_ongoing(struct ufs_hba *hba) +{ + return !!(test_bit(0, &hba->shutdown_in_prog)); +} + /* Returns true if clocks can be gated. Otherwise false */ static inline bool ufshcd_is_clkgating_allowed(struct ufs_hba *hba) { -- cgit v1.2.3 From 0cc66e3892775d2fc8c9bc8f4463637370f3484d Mon Sep 17 00:00:00 2001 From: Vijayavardhan Vennapusa Date: Fri, 19 Feb 2016 13:13:32 +0530 Subject: USB: phy: qusb: Turn on vdd along with 1p8/3p3 LDOs when PMI requests QUSB PHY requires VDD, 1p8 and 3p1 regulators to remove any unwanted pull downs on DP/DM lines. These pull downs may result in incorrect charger detection by PMI. Avoid incorrect charger detection by turning on VDD, 1p8 and 3p1 whenever PMI requests DP/DM to be floating. Change-Id: Ibfecfe1846d02b959bd249acac3fe4c57b88aaf0 Signed-off-by: Vijayavardhan Vennapusa --- drivers/usb/phy/phy-msm-qusb.c | 62 ++++++++++++++++++++---------------------- 1 file changed, 29 insertions(+), 33 deletions(-) diff --git a/drivers/usb/phy/phy-msm-qusb.c b/drivers/usb/phy/phy-msm-qusb.c index 5456b9e8733b..97a15355c146 100644 --- a/drivers/usb/phy/phy-msm-qusb.c +++ b/drivers/usb/phy/phy-msm-qusb.c @@ -189,15 +189,14 @@ static int qusb_phy_config_vdd(struct qusb_phy *qphy, int high) return ret; } -static int qusb_phy_enable_power(struct qusb_phy *qphy, bool on, - bool toggle_vdd) +static int qusb_phy_enable_power(struct qusb_phy *qphy, bool on) { int ret = 0; dev_dbg(qphy->phy.dev, "%s turn %s regulators. power_enabled:%d\n", __func__, on ? "on" : "off", qphy->power_enabled); - if (toggle_vdd && qphy->power_enabled == on) { + if (qphy->power_enabled == on) { dev_dbg(qphy->phy.dev, "PHYs' regulators are already ON.\n"); return 0; } @@ -205,19 +204,17 @@ static int qusb_phy_enable_power(struct qusb_phy *qphy, bool on, if (!on) goto disable_vdda33; - if (toggle_vdd) { - ret = qusb_phy_config_vdd(qphy, true); - if (ret) { - dev_err(qphy->phy.dev, "Unable to config VDD:%d\n", - ret); - goto err_vdd; - } + ret = qusb_phy_config_vdd(qphy, true); + if (ret) { + dev_err(qphy->phy.dev, "Unable to config VDD:%d\n", + ret); + goto err_vdd; + } - ret = regulator_enable(qphy->vdd); - if (ret) { - dev_err(qphy->phy.dev, "Unable to enable VDD\n"); - goto unconfig_vdd; - } + ret = regulator_enable(qphy->vdd); + if (ret) { + dev_err(qphy->phy.dev, "Unable to enable VDD\n"); + goto unconfig_vdd; } ret = regulator_set_load(qphy->vdda18, QUSB2PHY_1P8_HPM_LOAD); @@ -260,8 +257,7 @@ static int qusb_phy_enable_power(struct qusb_phy *qphy, bool on, goto unset_vdd33; } - if (toggle_vdd) - qphy->power_enabled = true; + qphy->power_enabled = true; pr_debug("%s(): QUSB PHY's regulators are turned ON.\n", __func__); return ret; @@ -299,21 +295,18 @@ put_vdda18_lpm: dev_err(qphy->phy.dev, "Unable to set LPM of vdda18\n"); disable_vdd: - if (toggle_vdd) { - ret = regulator_disable(qphy->vdd); - if (ret) - dev_err(qphy->phy.dev, "Unable to disable vdd:%d\n", + ret = regulator_disable(qphy->vdd); + if (ret) + dev_err(qphy->phy.dev, "Unable to disable vdd:%d\n", ret); unconfig_vdd: - ret = qusb_phy_config_vdd(qphy, false); - if (ret) - dev_err(qphy->phy.dev, "Unable unconfig VDD:%d\n", + ret = qusb_phy_config_vdd(qphy, false); + if (ret) + dev_err(qphy->phy.dev, "Unable unconfig VDD:%d\n", ret); - } err_vdd: - if (toggle_vdd) - qphy->power_enabled = false; + qphy->power_enabled = false; dev_dbg(qphy->phy.dev, "QUSB PHY's regulators are turned OFF.\n"); return ret; } @@ -330,7 +323,7 @@ static int qusb_phy_update_dpdm(struct usb_phy *phy, int value) case POWER_SUPPLY_DP_DM_DPF_DMF: dev_dbg(phy->dev, "POWER_SUPPLY_DP_DM_DPF_DMF\n"); if (!qphy->rm_pulldown) { - ret = qusb_phy_enable_power(qphy, true, false); + ret = qusb_phy_enable_power(qphy, true); if (ret >= 0) { qphy->rm_pulldown = true; dev_dbg(phy->dev, "DP_DM_F: rm_pulldown:%d\n", @@ -343,7 +336,10 @@ static int qusb_phy_update_dpdm(struct usb_phy *phy, int value) case POWER_SUPPLY_DP_DM_DPR_DMR: dev_dbg(phy->dev, "POWER_SUPPLY_DP_DM_DPR_DMR\n"); if (qphy->rm_pulldown) { - ret = qusb_phy_enable_power(qphy, false, false); + if (!qphy->cable_connected) { + dev_dbg(phy->dev, "turn off for HVDCP case\n"); + ret = qusb_phy_enable_power(qphy, false); + } if (ret >= 0) { qphy->rm_pulldown = false; dev_dbg(phy->dev, "DP_DM_R: rm_pulldown:%d\n", @@ -420,7 +416,7 @@ static int qusb_phy_init(struct usb_phy *phy) dev_dbg(phy->dev, "%s\n", __func__); - ret = qusb_phy_enable_power(qphy, true, true); + ret = qusb_phy_enable_power(qphy, true); if (ret) return ret; @@ -666,7 +662,7 @@ static int qusb_phy_set_suspend(struct usb_phy *phy, int suspend) qusb_phy_enable_clocks(qphy, false); - qusb_phy_enable_power(qphy, false, true); + qusb_phy_enable_power(qphy, false); } qphy->suspended = true; } else { @@ -678,7 +674,7 @@ static int qusb_phy_set_suspend(struct usb_phy *phy, int suspend) writel_relaxed(0x00, qphy->base + QUSB2PHY_PORT_INTR_CTRL); } else { - qusb_phy_enable_power(qphy, true, true); + qusb_phy_enable_power(qphy, true); qusb_phy_enable_clocks(qphy, true); } qphy->suspended = false; @@ -1046,7 +1042,7 @@ static int qusb_phy_remove(struct platform_device *pdev) qphy->clocks_enabled = false; } - qusb_phy_enable_power(qphy, false, true); + qusb_phy_enable_power(qphy, false); return 0; } -- cgit v1.2.3 From 64e8b62cdf1cbc5ab7f8bc3feff9d8f6a9ad7fcb Mon Sep 17 00:00:00 2001 From: Harry Yang Date: Thu, 3 Nov 2016 11:43:57 -0700 Subject: qcom-charger: WA for legacy bit set on hard reboot After cold reboot with typec attached, HW can not tell typec from legacy cable. The workaround is to reset and re-initiate legacy cable detection. CRs-Fixed: 1079373 Change-Id: Ifd7b2b88e7ab4c952b743fede6e24795069d653a Signed-off-by: Harry Yang --- drivers/power/qcom-charger/qpnp-smb2.c | 7 +++++++ drivers/power/qcom-charger/smb-lib.c | 38 ++++++++++++++++++++++++++++++++++ drivers/power/qcom-charger/smb-lib.h | 2 ++ 3 files changed, 47 insertions(+) diff --git a/drivers/power/qcom-charger/qpnp-smb2.c b/drivers/power/qcom-charger/qpnp-smb2.c index a00ad8343a88..37188e236775 100644 --- a/drivers/power/qcom-charger/qpnp-smb2.c +++ b/drivers/power/qcom-charger/qpnp-smb2.c @@ -1256,6 +1256,13 @@ static int smb2_init_hw(struct smb2 *chip) return rc; } + rc = smblib_validate_initial_typec_legacy_status(chg); + if (rc < 0) { + dev_err(chg->dev, "Couldn't validate typec legacy status rc=%d\n", + rc); + return rc; + } + return rc; } diff --git a/drivers/power/qcom-charger/smb-lib.c b/drivers/power/qcom-charger/smb-lib.c index 9cbba5a34195..d254c59514ee 100644 --- a/drivers/power/qcom-charger/smb-lib.c +++ b/drivers/power/qcom-charger/smb-lib.c @@ -16,6 +16,7 @@ #include #include #include +#include #include #include "smb-lib.h" #include "smb-reg.h" @@ -3106,3 +3107,40 @@ int smblib_deinit(struct smb_charger *chg) return 0; } + +int smblib_validate_initial_typec_legacy_status(struct smb_charger *chg) +{ + int rc; + u8 stat; + + + if (qpnp_pon_is_warm_reset()) + return 0; + + rc = smblib_read(chg, TYPE_C_STATUS_5_REG, &stat); + if (rc < 0) { + smblib_err(chg, "Couldn't read TYPE_C_STATUS_5 rc=%d\n", rc); + return rc; + } + + if ((stat & TYPEC_LEGACY_CABLE_STATUS_BIT) == 0) + return 0; + + rc = smblib_masked_write(chg, TYPE_C_INTRPT_ENB_SOFTWARE_CTRL_REG, + TYPEC_DISABLE_CMD_BIT, TYPEC_DISABLE_CMD_BIT); + if (rc < 0) { + smblib_err(chg, "Couldn't disable typec rc=%d\n", rc); + return rc; + } + + usleep_range(150000, 151000); + + rc = smblib_masked_write(chg, TYPE_C_INTRPT_ENB_SOFTWARE_CTRL_REG, + TYPEC_DISABLE_CMD_BIT, 0); + if (rc < 0) { + smblib_err(chg, "Couldn't enable typec rc=%d\n", rc); + return rc; + } + + return 0; +} diff --git a/drivers/power/qcom-charger/smb-lib.h b/drivers/power/qcom-charger/smb-lib.h index 2809ddadbd90..d61c16d93756 100644 --- a/drivers/power/qcom-charger/smb-lib.h +++ b/drivers/power/qcom-charger/smb-lib.h @@ -345,6 +345,8 @@ int smblib_set_prop_pd_in_hard_reset(struct smb_charger *chg, int smblib_get_prop_slave_current_now(struct smb_charger *chg, union power_supply_propval *val); +int smblib_validate_initial_typec_legacy_status(struct smb_charger *chg); + int smblib_init(struct smb_charger *chg); int smblib_deinit(struct smb_charger *chg); #endif /* __SMB2_CHARGER_H */ -- cgit v1.2.3 From b833212e4401d0283eb453eea2ec6e9723634a9f Mon Sep 17 00:00:00 2001 From: Vijayavardhan Vennapusa Date: Thu, 10 Nov 2016 12:49:54 +0530 Subject: usb: phy: qusb: Make sure QUSB PHY is into proper state On some platforms, QUSB PHY's DVDD related power supply (LDO) is not always ON. Hence when this power supply is switched off, QUSB PHY's register configuration is not retained. QUSB PHY state is unknown when required LDOs are turned ON with USB cable connect case and may interfere charger detection. Hence use suggested sequence which involves resetting QUSB PHY and performing few set of QUSB PHY register configuration to bring QUSB PHY into non-driving mode. Also it is required to disable QUSB2PHY level shifter by writing to TCSR_QUSB2PHY_CLAMP_DIG_N_1P8 register during disconnect to avoid leakage current. Hence add support for the same. Change-Id: I30b8488a1c19815601e6a1c5bcbdeed53715f8fa Signed-off-by: Vijayavardhan Vennapusa --- drivers/usb/phy/phy-msm-qusb.c | 86 ++++++++++++++++++++++++++++++++++++------ 1 file changed, 74 insertions(+), 12 deletions(-) diff --git a/drivers/usb/phy/phy-msm-qusb.c b/drivers/usb/phy/phy-msm-qusb.c index 97a15355c146..839d701ec9b5 100644 --- a/drivers/usb/phy/phy-msm-qusb.c +++ b/drivers/usb/phy/phy-msm-qusb.c @@ -109,6 +109,7 @@ struct qusb_phy { void __iomem *base; void __iomem *tune2_efuse_reg; void __iomem *ref_clk_base; + void __iomem *tcsr_clamp_dig_n; struct clk *ref_clk_src; struct clk *ref_clk; @@ -147,6 +148,7 @@ struct qusb_phy { int phy_pll_reset_seq_len; int *emu_dcm_reset_seq; int emu_dcm_reset_seq_len; + bool put_into_high_z_state; }; static void qusb_phy_enable_clocks(struct qusb_phy *qphy, bool on) @@ -329,6 +331,47 @@ static int qusb_phy_update_dpdm(struct usb_phy *phy, int value) dev_dbg(phy->dev, "DP_DM_F: rm_pulldown:%d\n", qphy->rm_pulldown); } + + if (qphy->put_into_high_z_state) { + if (qphy->tcsr_clamp_dig_n) + writel_relaxed(0x1, + qphy->tcsr_clamp_dig_n); + + qusb_phy_enable_clocks(qphy, true); + + dev_dbg(phy->dev, "RESET QUSB PHY\n"); + ret = reset_control_assert(qphy->phy_reset); + if (ret) + dev_err(phy->dev, "phyassert failed\n"); + usleep_range(100, 150); + ret = reset_control_deassert(qphy->phy_reset); + if (ret) + dev_err(phy->dev, "deassert failed\n"); + + /* + * Phy in non-driving mode leaves Dp and Dm + * lines in high-Z state. Controller power + * collapse is not switching phy to non-driving + * mode causing charger detection failure. Bring + * phy to non-driving mode by overriding + * controller output via UTMI interface. + */ + writel_relaxed(TERM_SELECT | XCVR_SELECT_FS | + OP_MODE_NON_DRIVE, + qphy->base + QUSB2PHY_PORT_UTMI_CTRL1); + writel_relaxed(UTMI_ULPI_SEL | + UTMI_TEST_MUX_SEL, + qphy->base + QUSB2PHY_PORT_UTMI_CTRL2); + + /* Disable PHY */ + writel_relaxed(CLAMP_N_EN | FREEZIO_N | + POWER_DOWN, + qphy->base + QUSB2PHY_PORT_POWERDOWN); + /* Make sure that above write is completed */ + wmb(); + + qusb_phy_enable_clocks(qphy, false); + } } break; @@ -337,6 +380,9 @@ static int qusb_phy_update_dpdm(struct usb_phy *phy, int value) dev_dbg(phy->dev, "POWER_SUPPLY_DP_DM_DPR_DMR\n"); if (qphy->rm_pulldown) { if (!qphy->cable_connected) { + if (qphy->tcsr_clamp_dig_n) + writel_relaxed(0x0, + qphy->tcsr_clamp_dig_n); dev_dbg(phy->dev, "turn off for HVDCP case\n"); ret = qusb_phy_enable_power(qphy, false); } @@ -647,22 +693,23 @@ static int qusb_phy_set_suspend(struct usb_phy *phy, int suspend) /* Disable all interrupts */ writel_relaxed(0x00, qphy->base + QUSB2PHY_PORT_INTR_CTRL); - /* - * Phy in non-driving mode leaves Dp and Dm lines in - * high-Z state. Controller power collapse is not - * switching phy to non-driving mode causing charger - * detection failure. Bring phy to non-driving mode by - * overriding controller output via UTMI interface. - */ - writel_relaxed(TERM_SELECT | XCVR_SELECT_FS | - OP_MODE_NON_DRIVE, - qphy->base + QUSB2PHY_PORT_UTMI_CTRL1); - writel_relaxed(UTMI_ULPI_SEL | UTMI_TEST_MUX_SEL, - qphy->base + QUSB2PHY_PORT_UTMI_CTRL2); + /* Make sure that above write is completed */ + wmb(); qusb_phy_enable_clocks(qphy, false); + if (qphy->tcsr_clamp_dig_n) + writel_relaxed(0x0, + qphy->tcsr_clamp_dig_n); qusb_phy_enable_power(qphy, false); + /* + * Set put_into_high_z_state to true so next USB + * cable connect, DPF_DMF request performs PHY + * reset and put it into high-z state. For bootup + * with or without USB cable, it doesn't require + * to put QUSB PHY into high-z state. + */ + qphy->put_into_high_z_state = true; } qphy->suspended = true; } else { @@ -675,6 +722,9 @@ static int qusb_phy_set_suspend(struct usb_phy *phy, int suspend) qphy->base + QUSB2PHY_PORT_INTR_CTRL); } else { qusb_phy_enable_power(qphy, true); + if (qphy->tcsr_clamp_dig_n) + writel_relaxed(0x1, + qphy->tcsr_clamp_dig_n); qusb_phy_enable_clocks(qphy, true); } qphy->suspended = false; @@ -845,6 +895,18 @@ static int qusb_phy_probe(struct platform_device *pdev) } } + res = platform_get_resource_byname(pdev, IORESOURCE_MEM, + "tcsr_clamp_dig_n_1p8"); + if (res) { + qphy->tcsr_clamp_dig_n = devm_ioremap_nocache(dev, + res->start, resource_size(res)); + if (IS_ERR(qphy->tcsr_clamp_dig_n)) { + dev_err(dev, "err reading tcsr_clamp_dig_n\n"); + qphy->tcsr_clamp_dig_n = NULL; + } + } + + qphy->ref_clk_src = devm_clk_get(dev, "ref_clk_src"); if (IS_ERR(qphy->ref_clk_src)) dev_dbg(dev, "clk get failed for ref_clk_src\n"); -- cgit v1.2.3 From 6b9dca0d137deac84f4d6b0bee3c9efcdf474f5d Mon Sep 17 00:00:00 2001 From: Naseer Ahmed Date: Tue, 8 Nov 2016 13:11:18 -0500 Subject: ARM: dts: msm: Add physical dimensions for NT35597 panel The physical dimensions are used to determine the DPI in the framework. If these dimensions are not provided, the framework assumes a default DPI value which may not be suitable for the current panel and lead to some apps drawing incorrectly. Change-Id: Ib14c5b9121190dded5071ff60ecf0be8e5e5c232 CRs-Fixed: 1079438 Signed-off-by: Naseer Ahmed --- arch/arm/boot/dts/qcom/dsi-panel-nt35597-dsc-wqxga-cmd.dtsi | 2 ++ arch/arm/boot/dts/qcom/dsi-panel-nt35597-dsc-wqxga-video.dtsi | 2 ++ arch/arm/boot/dts/qcom/dsi-panel-nt35597-dualmipi-wqxga-cmd.dtsi | 2 ++ arch/arm/boot/dts/qcom/dsi-panel-nt35597-dualmipi-wqxga-video.dtsi | 2 ++ 4 files changed, 8 insertions(+) diff --git a/arch/arm/boot/dts/qcom/dsi-panel-nt35597-dsc-wqxga-cmd.dtsi b/arch/arm/boot/dts/qcom/dsi-panel-nt35597-dsc-wqxga-cmd.dtsi index 9ad9e4adce00..94ca102c9dc0 100644 --- a/arch/arm/boot/dts/qcom/dsi-panel-nt35597-dsc-wqxga-cmd.dtsi +++ b/arch/arm/boot/dts/qcom/dsi-panel-nt35597-dsc-wqxga-cmd.dtsi @@ -44,6 +44,8 @@ qcom,mdss-dsi-dma-trigger = "trigger_sw"; qcom,mdss-dsi-mdp-trigger = "none"; qcom,mdss-dsi-reset-sequence = <1 10>, <0 10>, <1 10>; + qcom,mdss-pan-physical-width-dimension = <74>; + qcom,mdss-pan-physical-height-dimension = <131>; qcom,mdss-dsi-te-pin-select = <1>; qcom,mdss-dsi-wr-mem-start = <0x2c>; qcom,mdss-dsi-wr-mem-continue = <0x3c>; diff --git a/arch/arm/boot/dts/qcom/dsi-panel-nt35597-dsc-wqxga-video.dtsi b/arch/arm/boot/dts/qcom/dsi-panel-nt35597-dsc-wqxga-video.dtsi index 6b549a4af6eb..49130cc96f79 100644 --- a/arch/arm/boot/dts/qcom/dsi-panel-nt35597-dsc-wqxga-video.dtsi +++ b/arch/arm/boot/dts/qcom/dsi-panel-nt35597-dsc-wqxga-video.dtsi @@ -77,6 +77,8 @@ qcom,mdss-dsi-dma-trigger = "trigger_sw"; qcom,mdss-dsi-mdp-trigger = "none"; qcom,mdss-dsi-reset-sequence = <1 10>, <0 10>, <1 10>; + qcom,mdss-pan-physical-width-dimension = <74>; + qcom,mdss-pan-physical-height-dimension = <131>; qcom,compression-mode = "dsc"; qcom,config-select = <&dsi_nt35597_dsc_video_config0>; diff --git a/arch/arm/boot/dts/qcom/dsi-panel-nt35597-dualmipi-wqxga-cmd.dtsi b/arch/arm/boot/dts/qcom/dsi-panel-nt35597-dualmipi-wqxga-cmd.dtsi index 1e42d0846acf..10be9cc183f6 100644 --- a/arch/arm/boot/dts/qcom/dsi-panel-nt35597-dualmipi-wqxga-cmd.dtsi +++ b/arch/arm/boot/dts/qcom/dsi-panel-nt35597-dualmipi-wqxga-cmd.dtsi @@ -47,6 +47,8 @@ 04 00]; qcom,adjust-timer-wakeup-ms = <1>; qcom,mdss-dsi-reset-sequence = <1 10>, <0 10>, <1 10>; + qcom,mdss-pan-physical-width-dimension = <74>; + qcom,mdss-pan-physical-height-dimension = <131>; qcom,mdss-dsi-t-clk-post = <0x0d>; qcom,mdss-dsi-t-clk-pre = <0x2d>; qcom,mdss-dsi-bl-max-level = <4095>; diff --git a/arch/arm/boot/dts/qcom/dsi-panel-nt35597-dualmipi-wqxga-video.dtsi b/arch/arm/boot/dts/qcom/dsi-panel-nt35597-dualmipi-wqxga-video.dtsi index 82413bfbca89..a2cac50325c5 100644 --- a/arch/arm/boot/dts/qcom/dsi-panel-nt35597-dualmipi-wqxga-video.dtsi +++ b/arch/arm/boot/dts/qcom/dsi-panel-nt35597-dualmipi-wqxga-video.dtsi @@ -70,6 +70,8 @@ qcom,mdss-dsi-dma-trigger = "trigger_sw"; qcom,mdss-dsi-mdp-trigger = "none"; qcom,mdss-dsi-reset-sequence = <1 10>, <0 10>, <1 10>; + qcom,mdss-pan-physical-width-dimension = <74>; + qcom,mdss-pan-physical-height-dimension = <131>; qcom,mdss-dsi-min-refresh-rate = <55>; qcom,mdss-dsi-max-refresh-rate = <60>; qcom,mdss-dsi-pan-enable-dynamic-fps; -- cgit v1.2.3 From c8f85b42fec266224f05d20fe2a8461244d391ec Mon Sep 17 00:00:00 2001 From: Fenglin Wu Date: Tue, 8 Nov 2016 16:38:41 +0800 Subject: leds: qpnp-wled: Add support to configure AUTO_GM settings WLED in pmicobalt supports AUTO_GM configuration in CTRL_VLOOP_COMP_GM register. Add two properties to enable auto-gm and set auto-gm threshold. Meanwhile, move "qcom,loop-ea-gm" property outside of AMOLED constraint because WLED in LCD mode also support it. CRs-Fixed: 1081738 Change-Id: Iee99e9d1b999c84ece075d2f17e9cdf6aef9a2ac Signed-off-by: Fenglin Wu --- .../devicetree/bindings/leds/leds-qpnp-wled.txt | 5 +- drivers/leds/leds-qpnp-wled.c | 126 ++++++++++++++++----- 2 files changed, 100 insertions(+), 31 deletions(-) diff --git a/Documentation/devicetree/bindings/leds/leds-qpnp-wled.txt b/Documentation/devicetree/bindings/leds/leds-qpnp-wled.txt index 07f3fd274658..15924f659e61 100644 --- a/Documentation/devicetree/bindings/leds/leds-qpnp-wled.txt +++ b/Documentation/devicetree/bindings/leds/leds-qpnp-wled.txt @@ -68,9 +68,12 @@ Optional properties for WLED: - qcom,cons-sync-write-delay-us : Specify in 'us' the duration of delay between two consecutive writes to SYNC register. - qcom,sc-deb-cycles : debounce time for short circuit detection +- qcom,loop-ea-gm : control the gm for gm stage in control loop. default is 3. +- qcom,loop-auto-gm-en : A boolean property to specify if auto gm is enabled. +- qcom,loop-auto-gm-thresh : Specify auto gm threshold if "loop-auto-gm-en" is defined. + Supported values are: 0 - 3. Optional properties if 'qcom,disp-type-amoled' is mentioned in DT: -- qcom,loop-ea-gm : control the gm for gm stage in control loop. default is 3. - qcom,loop-comp-res-kohm : control to select the compensation resistor in kohm. default is 320. - qcom,vref-psm-mv : reference psm voltage in mv. default for amoled is 450. - qcom,avdd-mode-spmi: Boolean property to enable AMOLED_VOUT programming via SPMI. If not specified, diff --git a/drivers/leds/leds-qpnp-wled.c b/drivers/leds/leds-qpnp-wled.c index 97cfa813f4ce..0e359962ca37 100644 --- a/drivers/leds/leds-qpnp-wled.c +++ b/drivers/leds/leds-qpnp-wled.c @@ -69,11 +69,18 @@ #define QPNP_WLED_LOOP_COMP_RES_STEP_KOHM 20 #define QPNP_WLED_LOOP_COMP_RES_MIN_KOHM 20 #define QPNP_WLED_LOOP_COMP_RES_MAX_KOHM 320 -#define QPNP_WLED_VLOOP_COMP_GM_MASK 0xF0 +#define QPNP_WLED_VLOOP_COMP_GM_MASK GENMASK(3, 0) #define QPNP_WLED_VLOOP_COMP_GM_OVERWRITE 0x80 -#define QPNP_WLED_LOOP_EA_GM_DFLT_AMOLED 0x03 +#define QPNP_WLED_VLOOP_COMP_AUTO_GM_EN BIT(6) +#define QPNP_WLED_VLOOP_COMP_AUTO_GM_THRESH_MASK GENMASK(5, 4) +#define QPNP_WLED_VLOOP_COMP_AUTO_GM_THRESH_SHIFT 4 +#define QPNP_WLED_LOOP_EA_GM_DFLT_AMOLED_PMI8994 0x03 +#define QPNP_WLED_LOOP_GM_DFLT_AMOLED_PMICOBALT 0x09 +#define QPNP_WLED_LOOP_GM_DFLT_WLED 0x09 #define QPNP_WLED_LOOP_EA_GM_MIN 0x0 #define QPNP_WLED_LOOP_EA_GM_MAX 0xF +#define QPNP_WLED_LOOP_AUTO_GM_THRESH_MAX 3 +#define QPNP_WLED_LOOP_AUTO_GM_DFLT_THRESH 1 #define QPNP_WLED_VREF_PSM_MASK 0xF8 #define QPNP_WLED_VREF_PSM_STEP_MV 50 #define QPNP_WLED_VREF_PSM_MIN_MV 400 @@ -319,6 +326,8 @@ static struct wled_vref_setting vref_setting_pmicobalt = { * @ cons_sync_write_delay_us - delay between two consecutive writes to SYNC * @ strings - supported list of strings * @ num_strings - number of strings + * @ loop_auto_gm_thresh - the clamping level for auto gm + * @ loop_auto_gm_en - select if auto gm is enabled * @ avdd_mode_spmi - enable avdd programming via spmi * @ en_9b_dim_res - enable or disable 9bit dimming * @ en_phase_stag - enable or disable phase staggering @@ -362,6 +371,8 @@ struct qpnp_wled { u16 cons_sync_write_delay_us; u8 strings[QPNP_WLED_MAX_STRINGS]; u8 num_strings; + u8 loop_auto_gm_thresh; + bool loop_auto_gm_en; bool avdd_mode_spmi; bool en_9b_dim_res; bool en_phase_stag; @@ -987,24 +998,6 @@ static int qpnp_wled_set_disp(struct qpnp_wled *wled, u16 base_addr) if (rc) return rc; - /* Configure the LOOP COMP GM register for AMOLED */ - if (wled->loop_ea_gm < QPNP_WLED_LOOP_EA_GM_MIN) - wled->loop_ea_gm = QPNP_WLED_LOOP_EA_GM_MIN; - else if (wled->loop_ea_gm > QPNP_WLED_LOOP_EA_GM_MAX) - wled->loop_ea_gm = QPNP_WLED_LOOP_EA_GM_MAX; - - rc = qpnp_wled_read_reg(wled, ®, - QPNP_WLED_VLOOP_COMP_GM_REG(wled->ctrl_base)); - if (rc < 0) - return rc; - - reg &= QPNP_WLED_VLOOP_COMP_GM_MASK; - reg |= (wled->loop_ea_gm | QPNP_WLED_VLOOP_COMP_GM_OVERWRITE); - rc = qpnp_wled_write_reg(wled, reg, - QPNP_WLED_VLOOP_COMP_GM_REG(wled->ctrl_base)); - if (rc) - return rc; - /* Configure the CTRL TEST4 register for AMOLED */ rc = qpnp_wled_read_reg(wled, ®, QPNP_WLED_TEST4_REG(wled->ctrl_base)); @@ -1084,6 +1077,45 @@ static bool is_avdd_trim_adjustment_required(struct qpnp_wled *wled) return !(reg & QPNP_WLED_AVDD_SET_BIT); } +static int qpnp_wled_gm_config(struct qpnp_wled *wled) +{ + int rc; + u8 mask = 0, reg = 0; + + /* Configure the LOOP COMP GM register */ + if (wled->pmic_rev_id->pmic_subtype == PMICOBALT_SUBTYPE || + wled->pmic_rev_id->pmic_subtype == PM2FALCON_SUBTYPE) { + if (wled->loop_auto_gm_en) + reg |= QPNP_WLED_VLOOP_COMP_AUTO_GM_EN; + + if (wled->loop_auto_gm_thresh > + QPNP_WLED_LOOP_AUTO_GM_THRESH_MAX) + wled->loop_auto_gm_thresh = + QPNP_WLED_LOOP_AUTO_GM_THRESH_MAX; + + reg |= wled->loop_auto_gm_thresh << + QPNP_WLED_VLOOP_COMP_AUTO_GM_THRESH_SHIFT; + mask |= QPNP_WLED_VLOOP_COMP_AUTO_GM_EN | + QPNP_WLED_VLOOP_COMP_AUTO_GM_THRESH_MASK; + } + + if (wled->loop_ea_gm < QPNP_WLED_LOOP_EA_GM_MIN) + wled->loop_ea_gm = QPNP_WLED_LOOP_EA_GM_MIN; + else if (wled->loop_ea_gm > QPNP_WLED_LOOP_EA_GM_MAX) + wled->loop_ea_gm = QPNP_WLED_LOOP_EA_GM_MAX; + + reg |= wled->loop_ea_gm | QPNP_WLED_VLOOP_COMP_GM_OVERWRITE; + mask |= QPNP_WLED_VLOOP_COMP_GM_MASK | + QPNP_WLED_VLOOP_COMP_GM_OVERWRITE; + + rc = qpnp_wled_masked_write_reg(wled, mask, ®, + QPNP_WLED_VLOOP_COMP_GM_REG(wled->ctrl_base)); + if (rc) + pr_err("write VLOOP_COMP_GM_REG failed, rc=%d]\n", rc); + + return rc; +} + static int qpnp_wled_ovp_config(struct qpnp_wled *wled) { int rc, i, *ovp_table; @@ -1317,6 +1349,13 @@ static int qpnp_wled_config(struct qpnp_wled *wled) return rc; } + /* Configure VLOOP_COMP_GM register */ + rc = qpnp_wled_gm_config(wled); + if (rc < 0) { + pr_err("Error in configureing wled gm, rc=%d\n", rc); + return rc; + } + /* Configure the ILIM register */ rc = qpnp_wled_ilim_config(wled); if (rc < 0) { @@ -1689,16 +1728,6 @@ static int qpnp_wled_parse_dt(struct qpnp_wled *wled) return rc; } - wled->loop_ea_gm = QPNP_WLED_LOOP_EA_GM_DFLT_AMOLED; - rc = of_property_read_u32(pdev->dev.of_node, - "qcom,loop-ea-gm", &temp_val); - if (!rc) { - wled->loop_ea_gm = temp_val; - } else if (rc != -EINVAL) { - dev_err(&pdev->dev, "Unable to read loop-ea-gm\n"); - return rc; - } - wled->avdd_mode_spmi = of_property_read_bool(pdev->dev.of_node, "qcom,avdd-mode-spmi"); @@ -1713,6 +1742,43 @@ static int qpnp_wled_parse_dt(struct qpnp_wled *wled) } } + if (wled->disp_type_amoled) { + if (wled->pmic_rev_id->pmic_subtype == PMICOBALT_SUBTYPE || + wled->pmic_rev_id->pmic_subtype == PM2FALCON_SUBTYPE) + wled->loop_ea_gm = + QPNP_WLED_LOOP_GM_DFLT_AMOLED_PMICOBALT; + else + wled->loop_ea_gm = + QPNP_WLED_LOOP_EA_GM_DFLT_AMOLED_PMI8994; + } else { + wled->loop_ea_gm = QPNP_WLED_LOOP_GM_DFLT_WLED; + } + + rc = of_property_read_u32(pdev->dev.of_node, + "qcom,loop-ea-gm", &temp_val); + if (!rc) { + wled->loop_ea_gm = temp_val; + } else if (rc != -EINVAL) { + dev_err(&pdev->dev, "Unable to read loop-ea-gm\n"); + return rc; + } + + if (wled->pmic_rev_id->pmic_subtype == PMICOBALT_SUBTYPE || + wled->pmic_rev_id->pmic_subtype == PM2FALCON_SUBTYPE) { + wled->loop_auto_gm_en = + of_property_read_bool(pdev->dev.of_node, + "qcom,loop-auto-gm-en"); + wled->loop_auto_gm_thresh = QPNP_WLED_LOOP_AUTO_GM_DFLT_THRESH; + rc = of_property_read_u8(pdev->dev.of_node, + "qcom,loop-auto-gm-thresh", + &wled->loop_auto_gm_thresh); + if (rc && rc != -EINVAL) { + dev_err(&pdev->dev, + "Unable to read loop-auto-gm-thresh\n"); + return rc; + } + } + wled->sc_deb_cycles = QPNP_WLED_SC_DEB_CYCLES_DFLT; rc = of_property_read_u32(pdev->dev.of_node, "qcom,sc-deb-cycles", &temp_val); -- cgit v1.2.3 From 6f874e20a4b94ae8336801e9cabcecd3e206fcb4 Mon Sep 17 00:00:00 2001 From: Dhaval Patel Date: Thu, 14 Apr 2016 12:31:08 -0700 Subject: msm: mdss: add null check before dereferencing src_fmt Add null check before dereferencing the src_fmt during layer validation. Change-Id: I6482dc3d21fdc3e570fd53022e2fb9427668d939 Signed-off-by: Dhaval Patel --- drivers/video/fbdev/msm/mdss_mdp_layer.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/video/fbdev/msm/mdss_mdp_layer.c b/drivers/video/fbdev/msm/mdss_mdp_layer.c index 20fcc26bb4bf..c63a4a028c9f 100644 --- a/drivers/video/fbdev/msm/mdss_mdp_layer.c +++ b/drivers/video/fbdev/msm/mdss_mdp_layer.c @@ -852,7 +852,7 @@ static int __validate_layer_reconfig(struct mdp_input_layer *layer, */ if (pipe->csc_coeff_set != layer->color_space) { src_fmt = mdss_mdp_get_format_params(layer->buffer.format); - if (pipe->src_fmt->is_yuv && src_fmt->is_yuv) { + if (pipe->src_fmt->is_yuv && src_fmt && src_fmt->is_yuv) { status = -EPERM; pr_err("csc change is not permitted on used pipe\n"); } -- cgit v1.2.3 From e2ef952c4e59f40ed17c9a89a814980668c77366 Mon Sep 17 00:00:00 2001 From: Dhaval Patel Date: Mon, 4 Apr 2016 12:41:33 -0700 Subject: mdss: mdp: avoid panic if recovery handler is uninitialized Recovery handler is uninitialized during ctl stop process. A fifo error occur during stop process leads to panic which is false alarm. These errors do need panic because controller is going to stop/start and invokes the panel power off/power on. This patch removes the panic from the cases where recovery handler is uninitialized. Change-Id: I422d53d008223a9b0520f499e629f681bb6afa05 Signed-off-by: Dhaval Patel --- drivers/video/fbdev/msm/mdss_dsi_host.c | 6 ------ 1 file changed, 6 deletions(-) diff --git a/drivers/video/fbdev/msm/mdss_dsi_host.c b/drivers/video/fbdev/msm/mdss_dsi_host.c index c9168242da60..5f8b45413e32 100644 --- a/drivers/video/fbdev/msm/mdss_dsi_host.c +++ b/drivers/video/fbdev/msm/mdss_dsi_host.c @@ -2811,12 +2811,6 @@ static int dsi_event_thread(void *data) pr_debug("%s: Handling underflow event\n", __func__); __dsi_fifo_error_handler(ctrl, true); - } else { - pr_err("%s: ctrl recovery not defined\n", - __func__); - MDSS_XLOG_TOUT_HANDLER("mdp", "dsi0_ctrl", - "dsi0_phy", "dsi1_ctrl", "dsi1_phy", "vbif", - "vbif_nrt", "dbg_bus", "vbif_dbg_bus", "panic"); } mutex_unlock(&ctrl->mutex); } -- cgit v1.2.3 From 5d2b103d523f4651e9f7101d003ba1377f699206 Mon Sep 17 00:00:00 2001 From: Dhaval Patel Date: Fri, 15 Apr 2016 14:18:47 -0700 Subject: msm: mdss: fix race condition in dsi clk off request DSI clocks are requested from mdp and dsi for different use cases. The master clocks(DSI0 clocks) are refcounted to avoid toggling during slave clock ON/OFF sequence. Same applies to split controller clocks if broadcast mode is enabled. Now, mdp client can remove the dsi client's vote in below case: - MDP requested clocks in ECG state - clk_ctrl has removed both votes from ctrl-0 using dsi client handler. - DSI turns ON clock for ctrl-1 - clk_ctrl turns on clk for ctrl-0 using dsi client handler. - clk_ctrl increase the ctrl-1 refcount to 1 - clk_ctrl turns on clk for ctrl-1 - MDP request to turn OFF the clk for ctrl-1 - clk_ctrl turns on clk for ctrl-0 using dsi client handler - clk_ctrl increase the ctrl-1 refcount to 2 - clk_ctrl turns off clk for ctrl-1 - clk_ctrl turns off clk(twice) for ctrl-0 using dsi client handler. This race condition leads to dsi0 clocks off event when interface is using clocks. This change start tracking extra vote based on calling client id. Change-Id: I4812330453dedacd16dad1d920a2bacc3f67042b Signed-off-by: Dhaval Patel --- drivers/video/fbdev/msm/mdss_dsi.c | 6 ++++ drivers/video/fbdev/msm/mdss_dsi.h | 3 +- drivers/video/fbdev/msm/mdss_dsi_clk.c | 27 ++++++++++++++-- drivers/video/fbdev/msm/mdss_dsi_clk.h | 15 ++++++++- drivers/video/fbdev/msm/msm_mdss_io_8974.c | 52 +++++++++++++++++++++--------- 5 files changed, 83 insertions(+), 20 deletions(-) diff --git a/drivers/video/fbdev/msm/mdss_dsi.c b/drivers/video/fbdev/msm/mdss_dsi.c index cf7a398c13ce..8dccab8a81be 100644 --- a/drivers/video/fbdev/msm/mdss_dsi.c +++ b/drivers/video/fbdev/msm/mdss_dsi.c @@ -2985,6 +2985,12 @@ static int mdss_dsi_cont_splash_config(struct mdss_panel_info *pinfo, mdss_dsi_panel_pwm_enable(ctrl_pdata); ctrl_pdata->ctrl_state |= (CTRL_STATE_PANEL_INIT | CTRL_STATE_MDP_ACTIVE | CTRL_STATE_DSI_ACTIVE); + + /* + * MDP client removes this extra vote during splash reconfigure + * for command mode panel from interface. DSI removes the vote + * during suspend-resume for video mode panel. + */ if (ctrl_pdata->panel_data.panel_info.type == MIPI_CMD_PANEL) clk_handle = ctrl_pdata->mdp_clk_handle; else diff --git a/drivers/video/fbdev/msm/mdss_dsi.h b/drivers/video/fbdev/msm/mdss_dsi.h index 3536cb2d294d..3a347681f434 100644 --- a/drivers/video/fbdev/msm/mdss_dsi.h +++ b/drivers/video/fbdev/msm/mdss_dsi.h @@ -557,7 +557,8 @@ struct mdss_dsi_ctrl_pdata { void *clk_mngr; void *dsi_clk_handle; void *mdp_clk_handle; - int m_vote_cnt; + int m_dsi_vote_cnt; + int m_mdp_vote_cnt; /* debugfs structure */ struct mdss_dsi_debugfs_info *debugfs_info; diff --git a/drivers/video/fbdev/msm/mdss_dsi_clk.c b/drivers/video/fbdev/msm/mdss_dsi_clk.c index a7d1c251fab0..755d6092ea11 100644 --- a/drivers/video/fbdev/msm/mdss_dsi_clk.c +++ b/drivers/video/fbdev/msm/mdss_dsi_clk.c @@ -795,8 +795,29 @@ error: return rc; } +bool is_dsi_clk_in_ecg_state(void *client) +{ + struct mdss_dsi_clk_client_info *c = client; + struct mdss_dsi_clk_mngr *mngr; + bool is_ecg = false; + + if (!client) { + pr_err("Invalid client params\n"); + goto end; + } + + mngr = c->mngr; + + mutex_lock(&mngr->clk_mutex); + is_ecg = (c->core_clk_state == MDSS_DSI_CLK_EARLY_GATE); + mutex_unlock(&mngr->clk_mutex); + +end: + return is_ecg; +} + int mdss_dsi_clk_req_state(void *client, enum mdss_dsi_clk_type clk, - enum mdss_dsi_clk_state state) + enum mdss_dsi_clk_state state, u32 index) { int rc = 0; struct mdss_dsi_clk_client_info *c = client; @@ -817,7 +838,7 @@ int mdss_dsi_clk_req_state(void *client, enum mdss_dsi_clk_type clk, c->name, mngr->name, clk, state, c->core_clk_state, c->link_clk_state); - MDSS_XLOG(clk, state, c->core_clk_state, c->link_clk_state); + MDSS_XLOG(index, clk, state, c->core_clk_state, c->link_clk_state); /* * Refcount handling rules: * 1. Increment refcount whenever ON is called @@ -883,7 +904,7 @@ int mdss_dsi_clk_req_state(void *client, enum mdss_dsi_clk_type clk, pr_debug("[%s]%s: change=%d, Core (ref=%d, state=%d), Link (ref=%d, state=%d)\n", c->name, mngr->name, changed, c->core_refcount, c->core_clk_state, c->link_refcount, c->link_clk_state); - MDSS_XLOG(clk, state, c->core_clk_state, c->link_clk_state); + MDSS_XLOG(index, clk, state, c->core_clk_state, c->link_clk_state); if (changed) { rc = dsi_recheck_clk_state(mngr); diff --git a/drivers/video/fbdev/msm/mdss_dsi_clk.h b/drivers/video/fbdev/msm/mdss_dsi_clk.h index 9fe45254fe6d..0b88ddb57166 100644 --- a/drivers/video/fbdev/msm/mdss_dsi_clk.h +++ b/drivers/video/fbdev/msm/mdss_dsi_clk.h @@ -197,6 +197,7 @@ int mdss_dsi_clk_deregister(void *client); * @client: client handle. * @clk: Type of clock requested (enum mdss_dsi_clk_type). * @state: clock state requested. + * @index: controller index. * * This routine is used to request a new clock state for a specific clock. If * turning ON the clocks, this guarantees that clocks will be on before @@ -206,7 +207,7 @@ int mdss_dsi_clk_deregister(void *client); * @return: error code. */ int mdss_dsi_clk_req_state(void *client, enum mdss_dsi_clk_type clk, - enum mdss_dsi_clk_state state); + enum mdss_dsi_clk_state state, u32 index); /** * mdss_dsi_clk_set_link_rate() - set clock rate for link clocks @@ -238,4 +239,16 @@ int mdss_dsi_clk_set_link_rate(void *client, enum mdss_dsi_link_clk_type clk, * @return:error code. */ int mdss_dsi_clk_force_toggle(void *client, u32 clk); + +/** + * is_dsi_clk_in_ecg_state() - Checks the current state of clocks + * @client: client handle. + * + * This routine returns checks the clocks status for client and return + * success code based on it. + * + * @return:true: if clocks are in ECG state + * false: for all other cases + */ +bool is_dsi_clk_in_ecg_state(void *client); #endif /* _MDSS_DSI_CLK_H_ */ diff --git a/drivers/video/fbdev/msm/msm_mdss_io_8974.c b/drivers/video/fbdev/msm/msm_mdss_io_8974.c index b5b5a026733e..0c43a2642ede 100644 --- a/drivers/video/fbdev/msm/msm_mdss_io_8974.c +++ b/drivers/video/fbdev/msm/msm_mdss_io_8974.c @@ -2081,7 +2081,11 @@ int mdss_dsi_clk_ctrl(struct mdss_dsi_ctrl_pdata *ctrl, void *clk_handle, { int rc = 0; struct mdss_dsi_ctrl_pdata *mctrl = NULL; - int i; + int i, *vote_cnt; + + void *m_clk_handle; + bool is_ecg = false; + int state = MDSS_DSI_CLK_OFF; if (!ctrl) { pr_err("%s: Invalid arg\n", __func__); @@ -2112,6 +2116,18 @@ int mdss_dsi_clk_ctrl(struct mdss_dsi_ctrl_pdata *ctrl, void *clk_handle, __func__); } + /* + * it should add and remove extra votes based on voting clients to avoid + * removal of legitimate vote from DSI client. + */ + if (mctrl && (clk_handle == ctrl->dsi_clk_handle)) { + m_clk_handle = mctrl->dsi_clk_handle; + vote_cnt = &mctrl->m_dsi_vote_cnt; + } else if (mctrl) { + m_clk_handle = mctrl->mdp_clk_handle; + vote_cnt = &mctrl->m_mdp_vote_cnt; + } + /* * When DSI is used in split mode, the link clock for master controller * has to be turned on first before the link clock for slave can be @@ -2124,18 +2140,24 @@ int mdss_dsi_clk_ctrl(struct mdss_dsi_ctrl_pdata *ctrl, void *clk_handle, __func__, ctrl->ndx, clk_type, clk_state, __builtin_return_address(0), mctrl ? 1 : 0); if (mctrl && (clk_type & MDSS_DSI_LINK_CLK)) { - rc = mdss_dsi_clk_req_state(mctrl->dsi_clk_handle, - MDSS_DSI_ALL_CLKS, - MDSS_DSI_CLK_ON); + if (clk_state != MDSS_DSI_CLK_ON) { + /* preserve clk state; do not turn off forcefully */ + is_ecg = is_dsi_clk_in_ecg_state(m_clk_handle); + if (is_ecg) + state = MDSS_DSI_CLK_EARLY_GATE; + } + + rc = mdss_dsi_clk_req_state(m_clk_handle, + MDSS_DSI_ALL_CLKS, MDSS_DSI_CLK_ON, mctrl->ndx); if (rc) { pr_err("%s: failed to turn on mctrl clocks, rc=%d\n", __func__, rc); goto error; } - ctrl->m_vote_cnt++; + (*vote_cnt)++; } - rc = mdss_dsi_clk_req_state(clk_handle, clk_type, clk_state); + rc = mdss_dsi_clk_req_state(clk_handle, clk_type, clk_state, ctrl->ndx); if (rc) { pr_err("%s: failed set clk state, rc = %d\n", __func__, rc); goto error; @@ -2164,24 +2186,24 @@ int mdss_dsi_clk_ctrl(struct mdss_dsi_ctrl_pdata *ctrl, void *clk_handle, * for ON, since the previous ECG state must have * removed two votes to let clocks turn off. * - * To satisfy the above requirement, m_vote_cnt keeps track of + * To satisfy the above requirement, vote_cnt keeps track of * the number of ON votes for master requested by slave. For - * every OFF/ECG state request, Either 2 or m_vote_cnt number of + * every OFF/ECG state request, Either 2 or vote_cnt number of * votes are removed depending on which is lower. */ - for (i = 0; (i < ctrl->m_vote_cnt && i < 2); i++) { - rc = mdss_dsi_clk_req_state(mctrl->dsi_clk_handle, - MDSS_DSI_ALL_CLKS, - MDSS_DSI_CLK_OFF); + for (i = 0; (i < *vote_cnt && i < 2); i++) { + rc = mdss_dsi_clk_req_state(m_clk_handle, + MDSS_DSI_ALL_CLKS, state, mctrl->ndx); if (rc) { pr_err("%s: failed to set mctrl clk state, rc = %d\n", __func__, rc); goto error; } } - ctrl->m_vote_cnt -= i; - pr_debug("%s: ctrl=%d, m_vote_cnt=%d\n", __func__, ctrl->ndx, - ctrl->m_vote_cnt); + (*vote_cnt) -= i; + pr_debug("%s: ctrl=%d, vote_cnt=%d dsi_vote_cnt=%d mdp_vote_cnt:%d\n", + __func__, ctrl->ndx, *vote_cnt, mctrl->m_dsi_vote_cnt, + mctrl->m_mdp_vote_cnt); } error: -- cgit v1.2.3 From 52168e4c325387c27ace51956752462f0898b2b8 Mon Sep 17 00:00:00 2001 From: Deepak Katragadda Date: Tue, 8 Nov 2016 13:20:33 -0800 Subject: clk: msm: Add the CLKFLAG_NO_RATE_CACHE flag for MM clocks on MSM COBALT The clock driver by default returns immediately if a set_rate() request is made for a clock with a frequency that matches the SW frequency state. This is an optimization to avoid performing unnecessary clock configuration updates. Due to a HW limitation of the multimedia block on MSM COBALT, the clock sources or RCGs can end up running at XO frequency after a multimedia power collapse. In order to avoid this, have the multimedia clients call set_rate() prior to enabling their clocks. In addition, add the CLKFLAG_NO_RATE_CACHE flag to the multimedia clocks to remove the above mentioned set_rate() optimization and re-configure the clock source for every rate request, regardless of what rate the RCG is already configured to. CRs-Fixed: 1088709 Change-Id: I21e1c029e6b245cfa26a187b35bb1f6845302484 Signed-off-by: Deepak Katragadda --- drivers/clk/msm/clock-mmss-cobalt.c | 81 +++++++++++++++++++++++++++++++++++++ 1 file changed, 81 insertions(+) diff --git a/drivers/clk/msm/clock-mmss-cobalt.c b/drivers/clk/msm/clock-mmss-cobalt.c index 9c1cdf967fb1..9e2a8fcab2a6 100644 --- a/drivers/clk/msm/clock-mmss-cobalt.c +++ b/drivers/clk/msm/clock-mmss-cobalt.c @@ -245,6 +245,7 @@ static struct rcg_clk ahb_clk_src = { .c = { .dbg_name = "ahb_clk_src", .ops = &clk_ops_rcg, + .flags = CLKFLAG_NO_RATE_CACHE, VDD_DIG_FMAX_MAP3(LOWER, 19200000, LOW, 40000000, NOMINAL, 80800000), CLK_INIT(ahb_clk_src.c), @@ -277,6 +278,7 @@ static struct rcg_clk csi0_clk_src = { .c = { .dbg_name = "csi0_clk_src", .ops = &clk_ops_rcg, + .flags = CLKFLAG_NO_RATE_CACHE, VDD_DIG_FMAX_MAP4(LOWER, 164571429, LOW, 256000000, NOMINAL, 384000000, HIGH, 576000000), CLK_INIT(csi0_clk_src.c), @@ -315,6 +317,7 @@ static struct rcg_clk vfe0_clk_src = { .c = { .dbg_name = "vfe0_clk_src", .ops = &clk_ops_rcg, + .flags = CLKFLAG_NO_RATE_CACHE, VDD_DIG_FMAX_MAP4(LOWER, 200000000, LOW, 384000000, NOMINAL, 576000000, HIGH, 600000000), CLK_INIT(vfe0_clk_src.c), @@ -330,6 +333,7 @@ static struct rcg_clk vfe1_clk_src = { .c = { .dbg_name = "vfe1_clk_src", .ops = &clk_ops_rcg, + .flags = CLKFLAG_NO_RATE_CACHE, VDD_DIG_FMAX_MAP4(LOWER, 200000000, LOW, 384000000, NOMINAL, 576000000, HIGH, 600000000), CLK_INIT(vfe1_clk_src.c), @@ -358,6 +362,7 @@ static struct rcg_clk mdp_clk_src = { .c = { .dbg_name = "mdp_clk_src", .ops = &clk_ops_rcg, + .flags = CLKFLAG_NO_RATE_CACHE, VDD_DIG_FMAX_MAP4(LOWER, 171430000, LOW, 275000000, NOMINAL, 330000000, HIGH, 412500000), CLK_INIT(mdp_clk_src.c), @@ -382,6 +387,7 @@ static struct rcg_clk maxi_clk_src = { .c = { .dbg_name = "maxi_clk_src", .ops = &clk_ops_rcg, + .flags = CLKFLAG_NO_RATE_CACHE, VDD_DIG_FMAX_MAP4(LOWER, 75000000, LOW, 171428571, NOMINAL, 323200000, HIGH, 406000000), CLK_INIT(maxi_clk_src.c), @@ -416,6 +422,7 @@ static struct rcg_clk cpp_clk_src = { .c = { .dbg_name = "cpp_clk_src", .ops = &clk_ops_rcg, + .flags = CLKFLAG_NO_RATE_CACHE, VDD_DIG_FMAX_MAP4(LOWER, 100000000, LOW, 200000000, NOMINAL, 576000000, HIGH, 600000000), CLK_INIT(cpp_clk_src.c), @@ -446,6 +453,7 @@ static struct rcg_clk jpeg0_clk_src = { .c = { .dbg_name = "jpeg0_clk_src", .ops = &clk_ops_rcg, + .flags = CLKFLAG_NO_RATE_CACHE, VDD_DIG_FMAX_MAP3(LOWER, 75000000, LOW, 150000000, NOMINAL, 480000000), CLK_INIT(jpeg0_clk_src.c), @@ -469,6 +477,7 @@ static struct rcg_clk rot_clk_src = { .c = { .dbg_name = "rot_clk_src", .ops = &clk_ops_rcg, + .flags = CLKFLAG_NO_RATE_CACHE, VDD_DIG_FMAX_MAP4(LOWER, 171430000, LOW, 275000000, NOMINAL, 330000000, HIGH, 412500000), CLK_INIT(rot_clk_src.c), @@ -501,6 +510,7 @@ static struct rcg_clk video_core_clk_src = { .c = { .dbg_name = "video_core_clk_src", .ops = &clk_ops_rcg, + .flags = CLKFLAG_NO_RATE_CACHE, VDD_DIG_FMAX_MAP4(LOWER, 100000000, LOW, 186000000, NOMINAL, 360000000, HIGH, 465000000), CLK_INIT(video_core_clk_src.c), @@ -531,6 +541,7 @@ static struct rcg_clk csiphy_clk_src = { .c = { .dbg_name = "csiphy_clk_src", .ops = &clk_ops_rcg, + .flags = CLKFLAG_NO_RATE_CACHE, VDD_DIG_FMAX_MAP3(LOWER, 164570000, LOW, 256000000, NOMINAL, 384000000), CLK_INIT(csiphy_clk_src.c), @@ -546,6 +557,7 @@ static struct rcg_clk csi1_clk_src = { .c = { .dbg_name = "csi1_clk_src", .ops = &clk_ops_rcg, + .flags = CLKFLAG_NO_RATE_CACHE, VDD_DIG_FMAX_MAP4(LOWER, 164570000, LOW, 256000000, NOMINAL, 384000000, HIGH, 576000000), CLK_INIT(csi1_clk_src.c), @@ -561,6 +573,7 @@ static struct rcg_clk csi2_clk_src = { .c = { .dbg_name = "csi2_clk_src", .ops = &clk_ops_rcg, + .flags = CLKFLAG_NO_RATE_CACHE, VDD_DIG_FMAX_MAP4(LOWER, 164570000, LOW, 256000000, NOMINAL, 384000000, HIGH, 576000000), CLK_INIT(csi2_clk_src.c), @@ -576,6 +589,7 @@ static struct rcg_clk csi3_clk_src = { .c = { .dbg_name = "csi3_clk_src", .ops = &clk_ops_rcg, + .flags = CLKFLAG_NO_RATE_CACHE, VDD_DIG_FMAX_MAP4(LOWER, 164570000, LOW, 256000000, NOMINAL, 384000000, HIGH, 576000000), CLK_INIT(csi3_clk_src.c), @@ -607,6 +621,7 @@ static struct rcg_clk fd_core_clk_src = { .c = { .dbg_name = "fd_core_clk_src", .ops = &clk_ops_rcg, + .flags = CLKFLAG_NO_RATE_CACHE, VDD_DIG_FMAX_MAP3(LOWER, 100000000, LOW, 200000000, NOMINAL, 576000000), CLK_INIT(fd_core_clk_src.c), @@ -755,6 +770,7 @@ static struct rcg_clk video_subcore0_clk_src = { .c = { .dbg_name = "video_subcore0_clk_src", .ops = &clk_ops_rcg, + .flags = CLKFLAG_NO_RATE_CACHE, VDD_DIG_FMAX_MAP4(LOWER, 100000000, LOW, 186000000, NOMINAL, 360000000, HIGH, 465000000), CLK_INIT(video_subcore0_clk_src.c), @@ -771,6 +787,7 @@ static struct rcg_clk video_subcore1_clk_src = { .c = { .dbg_name = "video_subcore1_clk_src", .ops = &clk_ops_rcg, + .flags = CLKFLAG_NO_RATE_CACHE, VDD_DIG_FMAX_MAP4(LOWER, 100000000, LOW, 186000000, NOMINAL, 360000000, HIGH, 465000000), CLK_INIT(video_subcore1_clk_src.c), @@ -793,6 +810,7 @@ static struct rcg_clk cci_clk_src = { .c = { .dbg_name = "cci_clk_src", .ops = &clk_ops_rcg_mnd, + .flags = CLKFLAG_NO_RATE_CACHE, VDD_DIG_FMAX_MAP3(LOWER, 37500000, LOW, 50000000, NOMINAL, 100000000), CLK_INIT(cci_clk_src.c), @@ -818,6 +836,7 @@ static struct rcg_clk camss_gp0_clk_src = { .c = { .dbg_name = "camss_gp0_clk_src", .ops = &clk_ops_rcg_mnd, + .flags = CLKFLAG_NO_RATE_CACHE, VDD_DIG_FMAX_MAP3(LOWER, 50000000, LOW, 100000000, NOMINAL, 200000000), CLK_INIT(camss_gp0_clk_src.c), @@ -833,6 +852,7 @@ static struct rcg_clk camss_gp1_clk_src = { .c = { .dbg_name = "camss_gp1_clk_src", .ops = &clk_ops_rcg_mnd, + .flags = CLKFLAG_NO_RATE_CACHE, VDD_DIG_FMAX_MAP3(LOWER, 50000000, LOW, 100000000, NOMINAL, 200000000), CLK_INIT(camss_gp1_clk_src.c), @@ -862,6 +882,7 @@ static struct rcg_clk mclk0_clk_src = { .c = { .dbg_name = "mclk0_clk_src", .ops = &clk_ops_rcg_mnd, + .flags = CLKFLAG_NO_RATE_CACHE, VDD_DIG_FMAX_MAP3(LOWER, 33333333, LOW, 66666667, NOMINAL, 68571429), CLK_INIT(mclk0_clk_src.c), @@ -877,6 +898,7 @@ static struct rcg_clk mclk1_clk_src = { .c = { .dbg_name = "mclk1_clk_src", .ops = &clk_ops_rcg_mnd, + .flags = CLKFLAG_NO_RATE_CACHE, VDD_DIG_FMAX_MAP3(LOWER, 33333333, LOW, 66666667, NOMINAL, 68571429), CLK_INIT(mclk1_clk_src.c), @@ -892,6 +914,7 @@ static struct rcg_clk mclk2_clk_src = { .c = { .dbg_name = "mclk2_clk_src", .ops = &clk_ops_rcg_mnd, + .flags = CLKFLAG_NO_RATE_CACHE, VDD_DIG_FMAX_MAP3(LOWER, 33333333, LOW, 66666667, NOMINAL, 68571429), CLK_INIT(mclk2_clk_src.c), @@ -907,6 +930,7 @@ static struct rcg_clk mclk3_clk_src = { .c = { .dbg_name = "mclk3_clk_src", .ops = &clk_ops_rcg_mnd, + .flags = CLKFLAG_NO_RATE_CACHE, VDD_DIG_FMAX_MAP3(LOWER, 33333333, LOW, 66666667, NOMINAL, 68571429), CLK_INIT(mclk3_clk_src.c), @@ -928,6 +952,7 @@ static struct rcg_clk csi0phytimer_clk_src = { .c = { .dbg_name = "csi0phytimer_clk_src", .ops = &clk_ops_rcg, + .flags = CLKFLAG_NO_RATE_CACHE, VDD_DIG_FMAX_MAP3(LOWER, 100000000, LOW, 200000000, NOMINAL, 269333333), CLK_INIT(csi0phytimer_clk_src.c), @@ -943,6 +968,7 @@ static struct rcg_clk csi1phytimer_clk_src = { .c = { .dbg_name = "csi1phytimer_clk_src", .ops = &clk_ops_rcg, + .flags = CLKFLAG_NO_RATE_CACHE, VDD_DIG_FMAX_MAP3(LOWER, 100000000, LOW, 200000000, NOMINAL, 269333333), CLK_INIT(csi1phytimer_clk_src.c), @@ -958,6 +984,7 @@ static struct rcg_clk csi2phytimer_clk_src = { .c = { .dbg_name = "csi2phytimer_clk_src", .ops = &clk_ops_rcg, + .flags = CLKFLAG_NO_RATE_CACHE, VDD_DIG_FMAX_MAP3(LOWER, 100000000, LOW, 200000000, NOMINAL, 269333333), CLK_INIT(csi2phytimer_clk_src.c), @@ -978,6 +1005,7 @@ static struct rcg_clk dp_gtc_clk_src = { .c = { .dbg_name = "dp_gtc_clk_src", .ops = &clk_ops_rcg, + .flags = CLKFLAG_NO_RATE_CACHE, VDD_DIG_FMAX_MAP2(LOWER, 40000000, LOW, 300000000), CLK_INIT(dp_gtc_clk_src.c), }, @@ -997,6 +1025,7 @@ static struct rcg_clk esc0_clk_src = { .c = { .dbg_name = "esc0_clk_src", .ops = &clk_ops_rcg, + .flags = CLKFLAG_NO_RATE_CACHE, VDD_DIG_FMAX_MAP2(LOWER, 19200000, NOMINAL, 19200000), CLK_INIT(esc0_clk_src.c), }, @@ -1011,6 +1040,7 @@ static struct rcg_clk esc1_clk_src = { .c = { .dbg_name = "esc1_clk_src", .ops = &clk_ops_rcg, + .flags = CLKFLAG_NO_RATE_CACHE, VDD_DIG_FMAX_MAP2(LOWER, 19200000, NOMINAL, 19200000), CLK_INIT(esc1_clk_src.c), }, @@ -1033,6 +1063,7 @@ static struct rcg_clk extpclk_clk_src = { .dbg_name = "extpclk_clk_src", .parent = &ext_extpclk_clk_src.c, .ops = &clk_ops_byte, + .flags = CLKFLAG_NO_RATE_CACHE, VDD_DIG_FMAX_MAP3(LOWER, 150000000, LOW, 300000000, NOMINAL, 600000000), CLK_INIT(extpclk_clk_src.c), @@ -1053,6 +1084,7 @@ static struct rcg_clk hdmi_clk_src = { .c = { .dbg_name = "hdmi_clk_src", .ops = &clk_ops_rcg, + .flags = CLKFLAG_NO_RATE_CACHE, VDD_DIG_FMAX_MAP2(LOWER, 19200000, NOMINAL, 19200000), CLK_INIT(hdmi_clk_src.c), }, @@ -1072,6 +1104,7 @@ static struct rcg_clk vsync_clk_src = { .c = { .dbg_name = "vsync_clk_src", .ops = &clk_ops_rcg, + .flags = CLKFLAG_NO_RATE_CACHE, VDD_DIG_FMAX_MAP2(LOWER, 19200000, NOMINAL, 19200000), CLK_INIT(vsync_clk_src.c), }, @@ -1091,6 +1124,7 @@ static struct rcg_clk dp_aux_clk_src = { .c = { .dbg_name = "dp_aux_clk_src", .ops = &clk_ops_rcg, + .flags = CLKFLAG_NO_RATE_CACHE, VDD_DIG_FMAX_MAP2(LOWER, 19200000, NOMINAL, 19200000), CLK_INIT(dp_aux_clk_src.c), }, @@ -1165,6 +1199,7 @@ static struct rcg_clk dp_crypto_clk_src = { .c = { .dbg_name = "dp_crypto_clk_src", .ops = &clk_ops_rcg_mnd, + .flags = CLKFLAG_NO_RATE_CACHE, VDD_DIG_FMAX_MAP3(LOWER, 101250, LOW, 168750, NOMINAL, 337500), CLK_INIT(dp_crypto_clk_src.c), @@ -1237,6 +1272,7 @@ static struct branch_clk mmss_camss_cci_clk = { .c = { .dbg_name = "mmss_camss_cci_clk", .parent = &cci_clk_src.c, + .flags = CLKFLAG_NO_RATE_CACHE, .ops = &clk_ops_branch, CLK_INIT(mmss_camss_cci_clk.c), }, @@ -1260,6 +1296,7 @@ static struct branch_clk mmss_camss_cpp_clk = { .c = { .dbg_name = "mmss_camss_cpp_clk", .parent = &cpp_clk_src.c, + .flags = CLKFLAG_NO_RATE_CACHE, .ops = &clk_ops_branch, CLK_INIT(mmss_camss_cpp_clk.c), }, @@ -1317,6 +1354,7 @@ static struct branch_clk mmss_camss_csi0_clk = { .c = { .dbg_name = "mmss_camss_csi0_clk", .parent = &csi0_clk_src.c, + .flags = CLKFLAG_NO_RATE_CACHE, .ops = &clk_ops_branch, CLK_INIT(mmss_camss_csi0_clk.c), }, @@ -1376,6 +1414,7 @@ static struct branch_clk mmss_camss_csi1_clk = { .c = { .dbg_name = "mmss_camss_csi1_clk", .parent = &csi1_clk_src.c, + .flags = CLKFLAG_NO_RATE_CACHE, .ops = &clk_ops_branch, CLK_INIT(mmss_camss_csi1_clk.c), }, @@ -1435,6 +1474,7 @@ static struct branch_clk mmss_camss_csi2_clk = { .c = { .dbg_name = "mmss_camss_csi2_clk", .parent = &csi2_clk_src.c, + .flags = CLKFLAG_NO_RATE_CACHE, .ops = &clk_ops_branch, CLK_INIT(mmss_camss_csi2_clk.c), }, @@ -1494,6 +1534,7 @@ static struct branch_clk mmss_camss_csi3_clk = { .c = { .dbg_name = "mmss_camss_csi3_clk", .parent = &csi3_clk_src.c, + .flags = CLKFLAG_NO_RATE_CACHE, .ops = &clk_ops_branch, CLK_INIT(mmss_camss_csi3_clk.c), }, @@ -1555,6 +1596,7 @@ static struct branch_clk mmss_camss_csiphy0_clk = { .c = { .dbg_name = "mmss_camss_csiphy0_clk", .parent = &csiphy_clk_src.c, + .flags = CLKFLAG_NO_RATE_CACHE, .ops = &clk_ops_branch, CLK_INIT(mmss_camss_csiphy0_clk.c), }, @@ -1568,6 +1610,7 @@ static struct branch_clk mmss_camss_csiphy1_clk = { .c = { .dbg_name = "mmss_camss_csiphy1_clk", .parent = &csiphy_clk_src.c, + .flags = CLKFLAG_NO_RATE_CACHE, .ops = &clk_ops_branch, CLK_INIT(mmss_camss_csiphy1_clk.c), }, @@ -1581,6 +1624,7 @@ static struct branch_clk mmss_camss_csiphy2_clk = { .c = { .dbg_name = "mmss_camss_csiphy2_clk", .parent = &csiphy_clk_src.c, + .flags = CLKFLAG_NO_RATE_CACHE, .ops = &clk_ops_branch, CLK_INIT(mmss_camss_csiphy2_clk.c), }, @@ -1604,6 +1648,7 @@ static struct branch_clk mmss_fd_core_clk = { .c = { .dbg_name = "mmss_fd_core_clk", .parent = &fd_core_clk_src.c, + .flags = CLKFLAG_NO_RATE_CACHE, .ops = &clk_ops_branch, CLK_INIT(mmss_fd_core_clk.c), }, @@ -1628,6 +1673,7 @@ static struct branch_clk mmss_camss_gp0_clk = { .c = { .dbg_name = "mmss_camss_gp0_clk", .parent = &camss_gp0_clk_src.c, + .flags = CLKFLAG_NO_RATE_CACHE, .ops = &clk_ops_branch, CLK_INIT(mmss_camss_gp0_clk.c), }, @@ -1640,6 +1686,7 @@ static struct branch_clk mmss_camss_gp1_clk = { .c = { .dbg_name = "mmss_camss_gp1_clk", .parent = &camss_gp1_clk_src.c, + .flags = CLKFLAG_NO_RATE_CACHE, .ops = &clk_ops_branch, CLK_INIT(mmss_camss_gp1_clk.c), }, @@ -1663,6 +1710,7 @@ static struct branch_clk mmss_camss_jpeg0_clk = { .c = { .dbg_name = "mmss_camss_jpeg0_clk", .parent = &jpeg0_clk_src.c, + .flags = CLKFLAG_NO_RATE_CACHE, .ops = &clk_ops_branch, CLK_INIT(mmss_camss_jpeg0_clk.c), }, @@ -1701,6 +1749,7 @@ static struct branch_clk mmss_camss_mclk0_clk = { .c = { .dbg_name = "mmss_camss_mclk0_clk", .parent = &mclk0_clk_src.c, + .flags = CLKFLAG_NO_RATE_CACHE, .ops = &clk_ops_branch, CLK_INIT(mmss_camss_mclk0_clk.c), }, @@ -1713,6 +1762,7 @@ static struct branch_clk mmss_camss_mclk1_clk = { .c = { .dbg_name = "mmss_camss_mclk1_clk", .parent = &mclk1_clk_src.c, + .flags = CLKFLAG_NO_RATE_CACHE, .ops = &clk_ops_branch, CLK_INIT(mmss_camss_mclk1_clk.c), }, @@ -1725,6 +1775,7 @@ static struct branch_clk mmss_camss_mclk2_clk = { .c = { .dbg_name = "mmss_camss_mclk2_clk", .parent = &mclk2_clk_src.c, + .flags = CLKFLAG_NO_RATE_CACHE, .ops = &clk_ops_branch, CLK_INIT(mmss_camss_mclk2_clk.c), }, @@ -1737,6 +1788,7 @@ static struct branch_clk mmss_camss_mclk3_clk = { .c = { .dbg_name = "mmss_camss_mclk3_clk", .parent = &mclk3_clk_src.c, + .flags = CLKFLAG_NO_RATE_CACHE, .ops = &clk_ops_branch, CLK_INIT(mmss_camss_mclk3_clk.c), }, @@ -1760,6 +1812,7 @@ static struct branch_clk mmss_camss_csi0phytimer_clk = { .c = { .dbg_name = "mmss_camss_csi0phytimer_clk", .parent = &csi0phytimer_clk_src.c, + .flags = CLKFLAG_NO_RATE_CACHE, .ops = &clk_ops_branch, CLK_INIT(mmss_camss_csi0phytimer_clk.c), }, @@ -1772,6 +1825,7 @@ static struct branch_clk mmss_camss_csi1phytimer_clk = { .c = { .dbg_name = "mmss_camss_csi1phytimer_clk", .parent = &csi1phytimer_clk_src.c, + .flags = CLKFLAG_NO_RATE_CACHE, .ops = &clk_ops_branch, CLK_INIT(mmss_camss_csi1phytimer_clk.c), }, @@ -1784,6 +1838,7 @@ static struct branch_clk mmss_camss_csi2phytimer_clk = { .c = { .dbg_name = "mmss_camss_csi2phytimer_clk", .parent = &csi2phytimer_clk_src.c, + .flags = CLKFLAG_NO_RATE_CACHE, .ops = &clk_ops_branch, CLK_INIT(mmss_camss_csi2phytimer_clk.c), }, @@ -1818,6 +1873,7 @@ static struct branch_clk mmss_camss_vfe0_clk = { .c = { .dbg_name = "mmss_camss_vfe0_clk", .parent = &vfe0_clk_src.c, + .flags = CLKFLAG_NO_RATE_CACHE, .ops = &clk_ops_branch, CLK_INIT(mmss_camss_vfe0_clk.c), }, @@ -1853,6 +1909,7 @@ static struct branch_clk mmss_camss_vfe1_clk = { .c = { .dbg_name = "mmss_camss_vfe1_clk", .parent = &vfe1_clk_src.c, + .flags = CLKFLAG_NO_RATE_CACHE, .ops = &clk_ops_branch, CLK_INIT(mmss_camss_vfe1_clk.c), }, @@ -1921,6 +1978,7 @@ static struct branch_clk mmss_mdss_byte0_clk = { .c = { .dbg_name = "mmss_mdss_byte0_clk", .parent = &byte0_clk_src.c, + .flags = CLKFLAG_NO_RATE_CACHE, .ops = &clk_ops_branch, CLK_INIT(mmss_mdss_byte0_clk.c), }, @@ -1956,6 +2014,7 @@ static struct branch_clk mmss_mdss_byte0_intf_clk = { .c = { .dbg_name = "mmss_mdss_byte0_intf_clk", .parent = &mmss_mdss_byte0_intf_div_clk.c, + .flags = CLKFLAG_NO_RATE_CACHE, .ops = &clk_ops_branch, CLK_INIT(mmss_mdss_byte0_intf_clk.c), }, @@ -1968,6 +2027,7 @@ static struct branch_clk mmss_mdss_byte1_clk = { .c = { .dbg_name = "mmss_mdss_byte1_clk", .parent = &byte1_clk_src.c, + .flags = CLKFLAG_NO_RATE_CACHE, .ops = &clk_ops_branch, CLK_INIT(mmss_mdss_byte1_clk.c), }, @@ -2003,6 +2063,7 @@ static struct branch_clk mmss_mdss_byte1_intf_clk = { .c = { .dbg_name = "mmss_mdss_byte1_intf_clk", .parent = &mmss_mdss_byte1_intf_div_clk.c, + .flags = CLKFLAG_NO_RATE_CACHE, .ops = &clk_ops_branch, CLK_INIT(mmss_mdss_byte1_intf_clk.c), }, @@ -2015,6 +2076,7 @@ static struct branch_clk mmss_mdss_dp_aux_clk = { .c = { .dbg_name = "mmss_mdss_dp_aux_clk", .parent = &dp_aux_clk_src.c, + .flags = CLKFLAG_NO_RATE_CACHE, .ops = &clk_ops_branch, CLK_INIT(mmss_mdss_dp_aux_clk.c), }, @@ -2066,6 +2128,7 @@ static struct branch_clk mmss_mdss_dp_crypto_clk = { .c = { .dbg_name = "mmss_mdss_dp_crypto_clk", .parent = &dp_crypto_clk_src.c, + .flags = CLKFLAG_NO_RATE_CACHE, .ops = &clk_ops_branch, CLK_INIT(mmss_mdss_dp_crypto_clk.c), }, @@ -2078,6 +2141,7 @@ static struct branch_clk mmss_mdss_dp_gtc_clk = { .c = { .dbg_name = "mmss_mdss_dp_gtc_clk", .parent = &dp_gtc_clk_src.c, + .flags = CLKFLAG_NO_RATE_CACHE, .ops = &clk_ops_branch, CLK_INIT(mmss_mdss_dp_gtc_clk.c), }, @@ -2090,6 +2154,7 @@ static struct branch_clk mmss_mdss_esc0_clk = { .c = { .dbg_name = "mmss_mdss_esc0_clk", .parent = &esc0_clk_src.c, + .flags = CLKFLAG_NO_RATE_CACHE, .ops = &clk_ops_branch, CLK_INIT(mmss_mdss_esc0_clk.c), }, @@ -2102,6 +2167,7 @@ static struct branch_clk mmss_mdss_esc1_clk = { .c = { .dbg_name = "mmss_mdss_esc1_clk", .parent = &esc1_clk_src.c, + .flags = CLKFLAG_NO_RATE_CACHE, .ops = &clk_ops_branch, CLK_INIT(mmss_mdss_esc1_clk.c), }, @@ -2114,6 +2180,7 @@ static struct branch_clk mmss_mdss_extpclk_clk = { .c = { .dbg_name = "mmss_mdss_extpclk_clk", .parent = &extpclk_clk_src.c, + .flags = CLKFLAG_NO_RATE_CACHE, .ops = &clk_ops_branch, CLK_INIT(mmss_mdss_extpclk_clk.c), }, @@ -2126,6 +2193,7 @@ static struct branch_clk mmss_mdss_hdmi_clk = { .c = { .dbg_name = "mmss_mdss_hdmi_clk", .parent = &hdmi_clk_src.c, + .flags = CLKFLAG_NO_RATE_CACHE, .ops = &clk_ops_branch, CLK_INIT(mmss_mdss_hdmi_clk.c), }, @@ -2149,6 +2217,7 @@ static struct branch_clk mmss_mdss_mdp_clk = { .c = { .dbg_name = "mmss_mdss_mdp_clk", .parent = &mdp_clk_src.c, + .flags = CLKFLAG_NO_RATE_CACHE, .ops = &clk_ops_branch, CLK_INIT(mmss_mdss_mdp_clk.c), }, @@ -2175,6 +2244,7 @@ static struct branch_clk mmss_mdss_pclk0_clk = { .c = { .dbg_name = "mmss_mdss_pclk0_clk", .parent = &pclk0_clk_src.c, + .flags = CLKFLAG_NO_RATE_CACHE, .ops = &clk_ops_branch, CLK_INIT(mmss_mdss_pclk0_clk.c), }, @@ -2187,6 +2257,7 @@ static struct branch_clk mmss_mdss_pclk1_clk = { .c = { .dbg_name = "mmss_mdss_pclk1_clk", .parent = &pclk1_clk_src.c, + .flags = CLKFLAG_NO_RATE_CACHE, .ops = &clk_ops_branch, CLK_INIT(mmss_mdss_pclk1_clk.c), }, @@ -2199,6 +2270,7 @@ static struct branch_clk mmss_mdss_rot_clk = { .c = { .dbg_name = "mmss_mdss_rot_clk", .parent = &rot_clk_src.c, + .flags = CLKFLAG_NO_RATE_CACHE, .ops = &clk_ops_branch, CLK_INIT(mmss_mdss_rot_clk.c), }, @@ -2211,6 +2283,7 @@ static struct branch_clk mmss_mdss_vsync_clk = { .c = { .dbg_name = "mmss_mdss_vsync_clk", .parent = &vsync_clk_src.c, + .flags = CLKFLAG_NO_RATE_CACHE, .ops = &clk_ops_branch, CLK_INIT(mmss_mdss_vsync_clk.c), }, @@ -2225,6 +2298,7 @@ static struct branch_clk mmss_mnoc_ahb_clk = { .c = { .dbg_name = "mmss_mnoc_ahb_clk", .parent = &ahb_clk_src.c, + .flags = CLKFLAG_NO_RATE_CACHE, .ops = &clk_ops_branch, CLK_INIT(mmss_mnoc_ahb_clk.c), }, @@ -2260,6 +2334,7 @@ static struct branch_clk mmss_mnoc_maxi_clk = { .c = { .dbg_name = "mmss_mnoc_maxi_clk", .parent = &maxi_clk_src.c, + .flags = CLKFLAG_NO_RATE_CACHE, .ops = &clk_ops_branch, CLK_INIT(mmss_mnoc_maxi_clk.c), }, @@ -2272,6 +2347,7 @@ static struct branch_clk mmss_video_subcore0_clk = { .c = { .dbg_name = "mmss_video_subcore0_clk", .parent = &video_subcore0_clk_src.c, + .flags = CLKFLAG_NO_RATE_CACHE, .ops = &clk_ops_branch, CLK_INIT(mmss_video_subcore0_clk.c), }, @@ -2284,6 +2360,7 @@ static struct branch_clk mmss_video_subcore1_clk = { .c = { .dbg_name = "mmss_video_subcore1_clk", .parent = &video_subcore1_clk_src.c, + .flags = CLKFLAG_NO_RATE_CACHE, .ops = &clk_ops_branch, CLK_INIT(mmss_video_subcore1_clk.c), }, @@ -2318,6 +2395,7 @@ static struct branch_clk mmss_video_core_clk = { .c = { .dbg_name = "mmss_video_core_clk", .parent = &video_core_clk_src.c, + .flags = CLKFLAG_NO_RATE_CACHE, .ops = &clk_ops_branch, CLK_INIT(mmss_video_core_clk.c), }, @@ -2822,6 +2900,9 @@ int msm_mmsscc_cobalt_probe(struct platform_device *pdev) ext_dp_phy_pll_vco.clk_id = "dp_vco_div"; ext_dp_phy_pll_vco.c.flags = CLKFLAG_NO_RATE_CACHE; + mmss_camss_jpeg0_vote_clk.c.flags = CLKFLAG_NO_RATE_CACHE; + mmss_camss_jpeg0_dma_vote_clk.c.flags = CLKFLAG_NO_RATE_CACHE; + is_vq = of_device_is_compatible(pdev->dev.of_node, "qcom,mmsscc-hamster"); if (is_vq) -- cgit v1.2.3 From bcbd7e0f16c57318ab8f222826b6dd4796cb0b29 Mon Sep 17 00:00:00 2001 From: Yeleswarapu Nagaradhesh Date: Thu, 15 Sep 2016 17:27:21 +0530 Subject: ASoC: wcd-mbhc: correct cross connection check Schmitt trigger result is wrong if PA is enabled. So, don't check for cross connection when PA is enabled. CRs-Fixed: 1061507 Change-Id: Iad71abbed72aa40b5c839260f5c297a885f7d128 Signed-off-by: Yeleswarapu Nagaradhesh --- sound/soc/codecs/wcd-mbhc-v2.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/sound/soc/codecs/wcd-mbhc-v2.c b/sound/soc/codecs/wcd-mbhc-v2.c index a1f23685beb5..debb6c5e52d5 100644 --- a/sound/soc/codecs/wcd-mbhc-v2.c +++ b/sound/soc/codecs/wcd-mbhc-v2.c @@ -902,6 +902,11 @@ static int wcd_check_cross_conn(struct wcd_mbhc *mbhc) return -EINVAL; } + /* If PA is enabled, dont check for cross-connection */ + if (mbhc->mbhc_cb->hph_pa_on_status) + if (mbhc->mbhc_cb->hph_pa_on_status(mbhc->codec)) + return false; + WCD_MBHC_REG_READ(WCD_MBHC_ELECT_SCHMT_ISRC, reg1); /* * Check if there is any cross connection, -- cgit v1.2.3 From eeb34111fa6bb9849d971da2aa30a791bed244c0 Mon Sep 17 00:00:00 2001 From: Oleg Perelet Date: Wed, 9 Nov 2016 15:09:34 -0800 Subject: msm: kgsl: preserve ISENSE registers across GPU power collapse After wakeup from power collapse restore ISENSE registers from internal buffer. CRs-Fixed: 1075694 Change-Id: I9cf2f94892bdeb83fab0068902419b1603520364 Signed-off-by: Oleg Perelet --- drivers/gpu/msm/a5xx_reg.h | 6 ++++++ drivers/gpu/msm/adreno_a5xx.c | 38 ++++++++++++++++++++++++++++++++++++++ drivers/gpu/msm/adreno_a5xx.h | 1 + 3 files changed, 45 insertions(+) diff --git a/drivers/gpu/msm/a5xx_reg.h b/drivers/gpu/msm/a5xx_reg.h index f3b4e6622043..1f327d6af875 100644 --- a/drivers/gpu/msm/a5xx_reg.h +++ b/drivers/gpu/msm/a5xx_reg.h @@ -891,6 +891,11 @@ #define A5XX_GDPM_INT_MASK 0xB811 #define A5XX_GPMU_BEC_ENABLE 0xB9A0 +/* ISENSE registers */ +#define A5XX_GPU_CS_DECIMAL_ALIGN 0xC16A +#define A5XX_GPU_CS_SENSOR_PARAM_CORE_1 0xC126 +#define A5XX_GPU_CS_SENSOR_PARAM_CORE_2 0xC127 +#define A5XX_GPU_CS_SW_OV_FUSE_EN 0xC168 #define A5XX_GPU_CS_SENSOR_GENERAL_STATUS 0xC41A #define A5XX_GPU_CS_AMP_CALIBRATION_STATUS1_0 0xC41D #define A5XX_GPU_CS_AMP_CALIBRATION_STATUS1_2 0xC41F @@ -898,5 +903,6 @@ #define A5XX_GPU_CS_ENABLE_REG 0xC520 #define A5XX_GPU_CS_AMP_CALIBRATION_CONTROL1 0xC557 #define A5XX_GPU_CS_AMP_CALIBRATION_DONE 0xC565 +#define A5XX_GPU_CS_ENDPOINT_CALIBRATION_DONE 0xC556 #endif /* _A5XX_REG_H */ diff --git a/drivers/gpu/msm/adreno_a5xx.c b/drivers/gpu/msm/adreno_a5xx.c index 860f6d2925f1..8b6f13cef342 100644 --- a/drivers/gpu/msm/adreno_a5xx.c +++ b/drivers/gpu/msm/adreno_a5xx.c @@ -429,6 +429,43 @@ static int _poll_gdsc_status(struct adreno_device *adreno_dev, return 0; } +static void a5xx_restore_isense_regs(struct adreno_device *adreno_dev) +{ + struct kgsl_device *device = KGSL_DEVICE(adreno_dev); + unsigned int reg, i, ramp = GPMU_ISENSE_SAVE; + static unsigned int isense_regs[6] = {0xFFFF}, isense_reg_addr[] = { + A5XX_GPU_CS_DECIMAL_ALIGN, + A5XX_GPU_CS_SENSOR_PARAM_CORE_1, + A5XX_GPU_CS_SENSOR_PARAM_CORE_2, + A5XX_GPU_CS_SW_OV_FUSE_EN, + A5XX_GPU_CS_ENDPOINT_CALIBRATION_DONE, + A5XX_GPMU_TEMP_SENSOR_CONFIG}; + + if (!adreno_is_a540(adreno_dev)) + return; + + /* read signature */ + kgsl_regread(device, ramp++, ®); + + if (reg == 0xBABEFACE) { + /* store memory locations in buffer */ + for (i = 0; i < ARRAY_SIZE(isense_regs); i++) + kgsl_regread(device, ramp + i, isense_regs + i); + + /* clear signature */ + kgsl_regwrite(device, GPMU_ISENSE_SAVE, 0x0); + } + + /* if we never stored memory locations - do nothing */ + if (isense_regs[0] == 0xFFFF) + return; + + /* restore registers from memory */ + for (i = 0; i < ARRAY_SIZE(isense_reg_addr); i++) + kgsl_regwrite(device, isense_reg_addr[i], isense_regs[i]); + +} + /* * a5xx_regulator_enable() - Enable any necessary HW regulators * @adreno_dev: The adreno device pointer @@ -478,6 +515,7 @@ static int a5xx_regulator_enable(struct adreno_device *adreno_dev) kgsl_regrmw(device, A5XX_GPMU_GPMU_SP_CLOCK_CONTROL, CNTL_IP_CLK_ENABLE, 1); + a5xx_restore_isense_regs(adreno_dev); return 0; } diff --git a/drivers/gpu/msm/adreno_a5xx.h b/drivers/gpu/msm/adreno_a5xx.h index e424e7a9f228..08fd16a83f30 100644 --- a/drivers/gpu/msm/adreno_a5xx.h +++ b/drivers/gpu/msm/adreno_a5xx.h @@ -228,6 +228,7 @@ void a5xx_hwcg_set(struct adreno_device *adreno_dev, bool on); #define LM_SEQUENCE_ID 1 #define MAX_SEQUENCE_ID 3 +#define GPMU_ISENSE_SAVE (A5XX_GPMU_DATA_RAM_BASE + 200/4) /* LM defaults */ #define LM_DEFAULT_LIMIT 6000 #define A530_DEFAULT_LEAKAGE 0x004E001A -- cgit v1.2.3 From 2d6dc48e83fd57c825d9f7d9d95bf9610d9e7a19 Mon Sep 17 00:00:00 2001 From: Sreelakshmi Gownipalli Date: Wed, 19 Oct 2016 17:08:23 -0700 Subject: diag: Call diagmem_exit only if the mempool is initialized Call diagmem_exit in diag_mhi_exit only if the memory pool is initialized earlier. If diag bridge initialization fails allow diag apps to still communicate to other processors without unloading the diag driver. Change-Id: I0eb8b9a357f172984612175d1b03dd872df91b6f Signed-off-by: Sreelakshmi Gownipalli --- drivers/char/diag/diagchar_core.c | 7 ++++--- drivers/char/diag/diagfwd_mhi.c | 6 +++++- drivers/char/diag/diagfwd_mhi.h | 3 ++- 3 files changed, 11 insertions(+), 5 deletions(-) diff --git a/drivers/char/diag/diagchar_core.c b/drivers/char/diag/diagchar_core.c index a5781f6db269..9d0955289796 100644 --- a/drivers/char/diag/diagchar_core.c +++ b/drivers/char/diag/diagchar_core.c @@ -3432,9 +3432,6 @@ static int __init diagchar_init(void) if (ret) goto fail; ret = diagfwd_init(); - if (ret) - goto fail; - ret = diagfwd_bridge_init(); if (ret) goto fail; ret = diagfwd_cntl_init(); @@ -3467,6 +3464,9 @@ static int __init diagchar_init(void) goto fail; pr_debug("diagchar initialized now"); + ret = diagfwd_bridge_init(); + if (ret) + diagfwd_bridge_exit(); return 0; fail: @@ -3482,6 +3482,7 @@ fail: diag_masks_exit(); diag_remote_exit(); return -1; + } static void diagchar_exit(void) diff --git a/drivers/char/diag/diagfwd_mhi.c b/drivers/char/diag/diagfwd_mhi.c index f7b1e98f22b0..df26e2522baf 100644 --- a/drivers/char/diag/diagfwd_mhi.c +++ b/drivers/char/diag/diagfwd_mhi.c @@ -49,6 +49,7 @@ struct diag_mhi_info diag_mhi[NUM_MHI_DEV] = { .enabled = 0, .num_read = 0, .mempool = POOL_TYPE_MDM, + .mempool_init = 0, .mhi_wq = NULL, .read_ch = { .chan = MHI_CLIENT_DIAG_IN, @@ -68,6 +69,7 @@ struct diag_mhi_info diag_mhi[NUM_MHI_DEV] = { .enabled = 0, .num_read = 0, .mempool = POOL_TYPE_MDM_DCI, + .mempool_init = 0, .mhi_wq = NULL, .read_ch = { .chan = MHI_CLIENT_DCI_IN, @@ -684,6 +686,7 @@ int diag_mhi_init() strlcpy(wq_name, "diag_mhi_", DIAG_MHI_STRING_SZ); strlcat(wq_name, mhi_info->name, sizeof(mhi_info->name)); diagmem_init(driver, mhi_info->mempool); + mhi_info->mempool_init = 1; mhi_info->mhi_wq = create_singlethread_workqueue(wq_name); if (!mhi_info->mhi_wq) goto fail; @@ -725,7 +728,8 @@ void diag_mhi_exit() if (mhi_info->mhi_wq) destroy_workqueue(mhi_info->mhi_wq); mhi_close(mhi_info->id); - diagmem_exit(driver, mhi_info->mempool); + if (mhi_info->mempool_init) + diagmem_exit(driver, mhi_info->mempool); } } diff --git a/drivers/char/diag/diagfwd_mhi.h b/drivers/char/diag/diagfwd_mhi.h index 8332efdf5efb..a4466977ca97 100644 --- a/drivers/char/diag/diagfwd_mhi.h +++ b/drivers/char/diag/diagfwd_mhi.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2014-2015, The Linux Foundation. All rights reserved. +/* Copyright (c) 2014-2016, 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 @@ -65,6 +65,7 @@ struct diag_mhi_info { int id; int dev_id; int mempool; + int mempool_init; int num_read; uint8_t enabled; char name[DIAG_MHI_NAME_SZ]; -- cgit v1.2.3 From 73a2595feb408ab41d91a4b13d2a0b99e9fc602f Mon Sep 17 00:00:00 2001 From: Ram Chandrasekar Date: Mon, 14 Nov 2016 10:56:27 -0700 Subject: driver: thermal: msm_thermal: Enable Reliability algorithm The reliability algorithm has a dependency for OSM to be initialized before it is enabled. Enable reliability algorithm in the LMH DCVSh hardware for both the clusters from KTM. KTM is enabled, only after OSM populates the OPP table. So this solves the dependency. Change-Id: I4a382915a6c3a6b9d445ec1f5d57fb499a011f1a Signed-off-by: Ram Chandrasekar --- drivers/thermal/msm_thermal.c | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/drivers/thermal/msm_thermal.c b/drivers/thermal/msm_thermal.c index ced2f23addd4..002cafb08f37 100644 --- a/drivers/thermal/msm_thermal.c +++ b/drivers/thermal/msm_thermal.c @@ -60,6 +60,7 @@ #define MSM_LIMITS_NODE_DCVS 0x44435653 #define MSM_LIMITS_SUB_FN_GENERAL 0x47454E00 #define MSM_LIMITS_SUB_FN_CRNT 0x43524E54 +#define MSM_LIMITS_SUB_FN_REL 0x52454C00 #define MSM_LIMITS_DOMAIN_MAX 0x444D4158 #define MSM_LIMITS_DOMAIN_MIN 0x444D494E #define MSM_LIMITS_CLUSTER_0 0x6370302D @@ -1674,7 +1675,20 @@ static int msm_thermal_lmh_dcvs_init(struct platform_device *pdev) */ devm_clk_put(&pdev->dev, osm_clk); - /* Enable the CRNT algorithm. Again, we dont care if this fails */ + /* Enable the CRNT and Reliability algorithm. Again, we dont + * care if this fails + */ + ret = msm_lmh_dcvs_write(MSM_LIMITS_CLUSTER_0, + MSM_LIMITS_SUB_FN_REL, + MSM_LIMITS_ALGO_MODE_ENABLE, 1); + if (ret) + pr_err("Unable to enable REL algo for cluster0\n"); + ret = msm_lmh_dcvs_write(MSM_LIMITS_CLUSTER_1, + MSM_LIMITS_SUB_FN_REL, + MSM_LIMITS_ALGO_MODE_ENABLE, 1); + if (ret) + pr_err("Unable to enable REL algo for cluster1\n"); + ret = msm_lmh_dcvs_write(MSM_LIMITS_CLUSTER_0, MSM_LIMITS_SUB_FN_CRNT, MSM_LIMITS_ALGO_MODE_ENABLE, 1); -- cgit v1.2.3 From 98ac2b9cfacdcb73fc002c6bbba2c364e1380385 Mon Sep 17 00:00:00 2001 From: Subbaraman Narayanamurthy Date: Mon, 14 Nov 2016 18:43:40 -0800 Subject: leds: qpnp-flash-v2: add support to read pmic revid There are some features which needs to be enabled based on the PMIC. PMIC information such as subtype, revision can be obtained from revid peripheral. Hence add support to read pmic revid. Change-Id: Ie7a94f59e58b8f1b0816afda2496449694629205 Signed-off-by: Subbaraman Narayanamurthy --- .../bindings/leds/leds-qpnp-flash-v2.txt | 2 + arch/arm/boot/dts/qcom/msm-pm2falcon.dtsi | 1 + arch/arm/boot/dts/qcom/msm-pmicobalt.dtsi | 1 + drivers/leds/leds-qpnp-flash-v2.c | 77 ++++++++++++++-------- 4 files changed, 55 insertions(+), 26 deletions(-) diff --git a/Documentation/devicetree/bindings/leds/leds-qpnp-flash-v2.txt b/Documentation/devicetree/bindings/leds/leds-qpnp-flash-v2.txt index 8844a816052e..1091e9428a4a 100644 --- a/Documentation/devicetree/bindings/leds/leds-qpnp-flash-v2.txt +++ b/Documentation/devicetree/bindings/leds/leds-qpnp-flash-v2.txt @@ -11,6 +11,8 @@ Main node: Required properties: - compatible : Should be "qcom,qpnp-flash-led-v2" - reg : Base address and size for flash LED modules +- qcom,pmic-revid : phandle of PMIC revid module. This is used to + identify the PMIC subtype. Optional properties: - interrupts : Specifies the interrupts associated with flash-led. diff --git a/arch/arm/boot/dts/qcom/msm-pm2falcon.dtsi b/arch/arm/boot/dts/qcom/msm-pm2falcon.dtsi index 0e5a999e4642..7bc27196ecaa 100644 --- a/arch/arm/boot/dts/qcom/msm-pm2falcon.dtsi +++ b/arch/arm/boot/dts/qcom/msm-pm2falcon.dtsi @@ -269,6 +269,7 @@ qcom,thermal-derate-en; qcom,thermal-derate-current = <200 500 1000>; qcom,isc-delay = <192>; + qcom,pmic-revid = <&pm2falcon_revid>; status = "disabled"; pm2falcon_flash0: qcom,flash_0 { diff --git a/arch/arm/boot/dts/qcom/msm-pmicobalt.dtsi b/arch/arm/boot/dts/qcom/msm-pmicobalt.dtsi index 640aa53364a5..f453df4aaae0 100644 --- a/arch/arm/boot/dts/qcom/msm-pmicobalt.dtsi +++ b/arch/arm/boot/dts/qcom/msm-pmicobalt.dtsi @@ -657,6 +657,7 @@ qcom,thermal-derate-en; qcom,thermal-derate-current = <200 500 1000>; qcom,isc-delay = <192>; + qcom,pmic-revid = <&pmicobalt_revid>; pmicobalt_flash0: qcom,flash_0 { label = "flash"; diff --git a/drivers/leds/leds-qpnp-flash-v2.c b/drivers/leds/leds-qpnp-flash-v2.c index ea3d0eed47e1..0abb94417d83 100644 --- a/drivers/leds/leds-qpnp-flash-v2.c +++ b/drivers/leds/leds-qpnp-flash-v2.c @@ -27,6 +27,7 @@ #include #include #include +#include #include "leds.h" #define FLASH_LED_REG_LED_STATUS1(base) (base + 0x08) @@ -191,32 +192,33 @@ struct flash_switch_data { * Flash LED configuration read from device tree */ struct flash_led_platform_data { - int *thermal_derate_current; - int all_ramp_up_done_irq; - int all_ramp_down_done_irq; - int led_fault_irq; - int ibatt_ocp_threshold_ua; - int vled_max_uv; - int rpara_uohm; - int lmh_rbatt_threshold_uohm; - int lmh_ocv_threshold_uv; - u32 led1n2_iclamp_low_ma; - u32 led1n2_iclamp_mid_ma; - u32 led3_iclamp_low_ma; - u32 led3_iclamp_mid_ma; - u8 isc_delay; - u8 warmup_delay; - u8 current_derate_en_cfg; - u8 vph_droop_threshold; - u8 vph_droop_hysteresis; - u8 vph_droop_debounce; - u8 lmh_mitigation_sel; - u8 chgr_mitigation_sel; - u8 lmh_level; - u8 iled_thrsh_val; - u8 hw_strobe_option; - bool hdrm_auto_mode_en; - bool thermal_derate_en; + struct pmic_revid_data *pmic_rev_id; + int *thermal_derate_current; + int all_ramp_up_done_irq; + int all_ramp_down_done_irq; + int led_fault_irq; + int ibatt_ocp_threshold_ua; + int vled_max_uv; + int rpara_uohm; + int lmh_rbatt_threshold_uohm; + int lmh_ocv_threshold_uv; + u32 led1n2_iclamp_low_ma; + u32 led1n2_iclamp_mid_ma; + u32 led3_iclamp_low_ma; + u32 led3_iclamp_mid_ma; + u8 isc_delay; + u8 warmup_delay; + u8 current_derate_en_cfg; + u8 vph_droop_threshold; + u8 vph_droop_hysteresis; + u8 vph_droop_debounce; + u8 lmh_mitigation_sel; + u8 chgr_mitigation_sel; + u8 lmh_level; + u8 iled_thrsh_val; + u8 hw_strobe_option; + bool hdrm_auto_mode_en; + bool thermal_derate_en; }; /* @@ -1500,10 +1502,33 @@ static int qpnp_flash_led_parse_and_register_switch(struct qpnp_flash_led *led, static int qpnp_flash_led_parse_common_dt(struct qpnp_flash_led *led, struct device_node *node) { + struct device_node *revid_node; int rc; u32 val; bool short_circuit_det, open_circuit_det, vph_droop_det; + revid_node = of_parse_phandle(node, "qcom,pmic-revid", 0); + if (!revid_node) { + pr_err("Missing qcom,pmic-revid property - driver failed\n"); + return -EINVAL; + } + + led->pdata->pmic_rev_id = get_revid_data(revid_node); + if (IS_ERR_OR_NULL(led->pdata->pmic_rev_id)) { + pr_err("Unable to get pmic_revid rc=%ld\n", + PTR_ERR(led->pdata->pmic_rev_id)); + /* + * the revid peripheral must be registered, any failure + * here only indicates that the rev-id module has not + * probed yet. + */ + return -EPROBE_DEFER; + } + + pr_debug("PMIC subtype %d Digital major %d\n", + led->pdata->pmic_rev_id->pmic_subtype, + led->pdata->pmic_rev_id->rev4); + led->pdata->hdrm_auto_mode_en = of_property_read_bool(node, "qcom,hdrm-auto-mode"); -- cgit v1.2.3 From 5c312a4f748d8b85a08733e601f7b1aae02c522c Mon Sep 17 00:00:00 2001 From: Subbaraman Narayanamurthy Date: Fri, 26 Aug 2016 13:03:37 -0700 Subject: leds: qpnp-flash-v2: Add support for thermal derate features Add support to configure thermal debounce, hysteresis and ramp down rates from device tree. CRs-Fixed: 1060212 Change-Id: Iabe79bae5f9471c3c6128ed21efd04de00739daa Signed-off-by: Devesh Jhunjhunwala Signed-off-by: Subbaraman Narayanamurthy --- .../bindings/leds/leds-qpnp-flash-v2.txt | 21 ++ drivers/leds/leds-qpnp-flash-v2.c | 220 ++++++++++++++++++--- 2 files changed, 216 insertions(+), 25 deletions(-) diff --git a/Documentation/devicetree/bindings/leds/leds-qpnp-flash-v2.txt b/Documentation/devicetree/bindings/leds/leds-qpnp-flash-v2.txt index 1091e9428a4a..2a4a8f83f8da 100644 --- a/Documentation/devicetree/bindings/leds/leds-qpnp-flash-v2.txt +++ b/Documentation/devicetree/bindings/leds/leds-qpnp-flash-v2.txt @@ -78,6 +78,27 @@ Optional properties: - qcom,thermal-derate-current : Array of currrent limits for thermal mitigation. Required if qcom,thermal-derate-en is specified. Unit is mA. Format is qcom,thermal-derate-current = . +- qcom,otst-ramp-back-up-dis : Boolean property to disable current ramp + backup after thermal derate trigger is + deasserted. +- qcom,thermal-derate-slow : Integer property to specify slow ramping + down thermal rate. Unit is in uS. Allowed + values are: 128, 256, 512, 1024, 2048, 4096, + 8192 and 314592. +- qcom,thermal-derate-fast : Integer property to specify fast ramping + down thermal rate. Unit is in uS. Allowed + values are: 32, 64, 96, 128, 256, 384 and + 512. +- qcom,thermal-debounce : Integer property to specify thermal debounce + time. It is only used if qcom,thermal-derate-en + is specified. Unit is in uS. Allowed values + are: 0, 16, 32, 64. +- qcom,thermal-hysteresis : Integer property to specify thermal derating + hysteresis. Unit is in deciDegC. It is only + used if qcom,thermal-derate-en is specified. + Allowed values are: + 0, 15, 30, 45 for pmicobalt. + 0, 20, 40, 60 for pm2falcon. - qcom,hw-strobe-option : Integer type to specify hardware strobe option. Based on the specified value, additional GPIO configuration may be required to provide strobing support. Supported values are: diff --git a/drivers/leds/leds-qpnp-flash-v2.c b/drivers/leds/leds-qpnp-flash-v2.c index 0abb94417d83..b126bf550425 100644 --- a/drivers/leds/leds-qpnp-flash-v2.c +++ b/drivers/leds/leds-qpnp-flash-v2.c @@ -28,6 +28,7 @@ #include #include #include +#include #include "leds.h" #define FLASH_LED_REG_LED_STATUS1(base) (base + 0x08) @@ -44,9 +45,12 @@ #define FLASH_LED_REG_HDRM_AUTO_MODE_CTRL(base) (base + 0x50) #define FLASH_LED_REG_WARMUP_DELAY(base) (base + 0x51) #define FLASH_LED_REG_ISC_DELAY(base) (base + 0x52) +#define FLASH_LED_REG_THERMAL_RMP_DN_RATE(base) (base + 0x55) #define FLASH_LED_REG_THERMAL_THRSH1(base) (base + 0x56) #define FLASH_LED_REG_THERMAL_THRSH2(base) (base + 0x57) #define FLASH_LED_REG_THERMAL_THRSH3(base) (base + 0x58) +#define FLASH_LED_REG_THERMAL_HYSTERESIS(base) (base + 0x59) +#define FLASH_LED_REG_THERMAL_DEBOUNCE(base) (base + 0x5A) #define FLASH_LED_REG_VPH_DROOP_THRESHOLD(base) (base + 0x61) #define FLASH_LED_REG_VPH_DROOP_DEBOUNCE(base) (base + 0x62) #define FLASH_LED_REG_ILED_GRT_THRSH(base) (base + 0x67) @@ -59,13 +63,10 @@ #define FLASH_LED_REG_LMH_LEVEL(base) (base + 0x70) #define FLASH_LED_REG_CURRENT_DERATE_EN(base) (base + 0x76) -#define FLASH_LED_HDRM_MODE_PRGM_MASK GENMASK(7, 0) #define FLASH_LED_HDRM_VOL_MASK GENMASK(7, 4) #define FLASH_LED_CURRENT_MASK GENMASK(6, 0) #define FLASH_LED_ENABLE_MASK GENMASK(2, 0) #define FLASH_HW_STROBE_MASK GENMASK(2, 0) -#define FLASH_LED_SAFETY_TMR_MASK GENMASK(7, 0) -#define FLASH_LED_INT_RT_STS_MASK GENMASK(7, 0) #define FLASH_LED_ISC_WARMUP_DELAY_MASK GENMASK(1, 0) #define FLASH_LED_CURRENT_DERATE_EN_MASK GENMASK(2, 0) #define FLASH_LED_VPH_DROOP_DEBOUNCE_MASK GENMASK(1, 0) @@ -75,13 +76,19 @@ #define FLASH_LED_LMH_LEVEL_MASK GENMASK(1, 0) #define FLASH_LED_VPH_DROOP_HYSTERESIS_MASK GENMASK(5, 4) #define FLASH_LED_VPH_DROOP_THRESHOLD_MASK GENMASK(2, 0) +#define FLASH_LED_THERMAL_HYSTERESIS_MASK GENMASK(1, 0) +#define FLASH_LED_THERMAL_DEBOUNCE_MASK GENMASK(1, 0) #define FLASH_LED_THERMAL_THRSH_MASK GENMASK(2, 0) -#define FLASH_LED_THERMAL_OTST_MASK GENMASK(2, 0) #define FLASH_LED_MOD_CTRL_MASK BIT(7) #define FLASH_LED_HW_SW_STROBE_SEL_BIT BIT(2) #define FLASH_LED_VPH_DROOP_FAULT_MASK BIT(4) #define FLASH_LED_LMH_MITIGATION_EN_MASK BIT(0) #define FLASH_LED_CHGR_MITIGATION_EN_MASK BIT(4) +#define THERMAL_OTST1_RAMP_CTRL_MASK BIT(7) +#define THERMAL_OTST1_RAMP_CTRL_SHIFT 7 +#define THERMAL_DERATE_SLOW_SHIFT 4 +#define THERMAL_DERATE_SLOW_MASK GENMASK(6, 4) +#define THERMAL_DERATE_FAST_MASK GENMASK(2, 0) #define VPH_DROOP_DEBOUNCE_US_TO_VAL(val_us) (val_us / 8) #define VPH_DROOP_HYST_MV_TO_VAL(val_mv) (val_mv / 25) @@ -90,16 +97,22 @@ #define MITIGATION_THRSH_MA_TO_VAL(val_ma) (val_ma / 100) #define CURRENT_MA_TO_REG_VAL(curr_ma, ires_ua) ((curr_ma * 1000) / ires_ua - 1) #define SAFETY_TMR_TO_REG_VAL(duration_ms) ((duration_ms / 10) - 1) +#define THERMAL_HYST_TEMP_TO_VAL(val, divisor) (val / divisor) #define FLASH_LED_ISC_WARMUP_DELAY_SHIFT 6 #define FLASH_LED_WARMUP_DELAY_DEFAULT 2 #define FLASH_LED_ISC_DELAY_DEFAULT 3 #define FLASH_LED_VPH_DROOP_DEBOUNCE_DEFAULT 2 +#define FLASH_LED_VPH_DROOP_HYST_SHIFT 4 #define FLASH_LED_VPH_DROOP_HYST_DEFAULT 2 #define FLASH_LED_VPH_DROOP_THRESH_DEFAULT 5 -#define FLASH_LED_VPH_DROOP_DEBOUNCE_MAX 3 -#define FLASH_LED_VPH_DROOP_HYST_MAX 3 +#define FLASH_LED_DEBOUNCE_MAX 3 +#define FLASH_LED_HYSTERESIS_MAX 3 #define FLASH_LED_VPH_DROOP_THRESH_MAX 7 +#define THERMAL_DERATE_SLOW_MAX 314592 +#define THERMAL_DERATE_FAST_MAX 512 +#define THERMAL_DEBOUNCE_TIME_MAX 64 +#define THERMAL_DERATE_HYSTERESIS_MAX 3 #define FLASH_LED_THERMAL_THRSH_MIN 3 #define FLASH_LED_THERMAL_OTST_LEVELS 3 #define FLASH_LED_VLED_MAX_DEFAULT_UV 3500000 @@ -202,6 +215,10 @@ struct flash_led_platform_data { int rpara_uohm; int lmh_rbatt_threshold_uohm; int lmh_ocv_threshold_uv; + int thermal_derate_slow; + int thermal_derate_fast; + int thermal_hysteresis; + int thermal_debounce; u32 led1n2_iclamp_low_ma; u32 led1n2_iclamp_mid_ma; u32 led3_iclamp_low_ma; @@ -219,6 +236,7 @@ struct flash_led_platform_data { u8 hw_strobe_option; bool hdrm_auto_mode_en; bool thermal_derate_en; + bool otst_ramp_bkup_en; }; /* @@ -241,22 +259,44 @@ struct qpnp_flash_led { bool trigger_chgr; }; -static int -qpnp_flash_led_read(struct qpnp_flash_led *led, u16 addr, u8 *data) +static int thermal_derate_slow_table[] = { + 128, 256, 512, 1024, 2048, 4096, 8192, 314592, +}; + +static int thermal_derate_fast_table[] = { + 32, 64, 96, 128, 256, 384, 512, +}; + +static int qpnp_flash_led_read(struct qpnp_flash_led *led, u16 addr, u8 *data) { int rc; uint val; rc = regmap_read(led->regmap, addr, &val); - if (rc < 0) + if (rc < 0) { dev_err(&led->pdev->dev, "Unable to read from 0x%04X rc = %d\n", addr, rc); - else - dev_dbg(&led->pdev->dev, "Read 0x%02X from addr 0x%04X\n", - val, addr); + return rc; + } + dev_dbg(&led->pdev->dev, "Read 0x%02X from addr 0x%04X\n", val, addr); *data = (u8)val; - return rc; + return 0; +} + +static int qpnp_flash_led_write(struct qpnp_flash_led *led, u16 addr, u8 data) +{ + int rc; + + rc = regmap_write(led->regmap, addr, data); + if (rc < 0) { + dev_err(&led->pdev->dev, "Unable to write to 0x%04X rc = %d\n", + addr, rc); + return rc; + } + + dev_dbg(&led->pdev->dev, "Wrote 0x%02X to addr 0x%04X\n", data, addr); + return 0; } static int @@ -299,13 +339,12 @@ led_brightness qpnp_flash_led_brightness_get(struct led_classdev *led_cdev) static int qpnp_flash_led_init_settings(struct qpnp_flash_led *led) { int rc, i, addr_offset; - u8 val = 0; + u8 val = 0, mask; for (i = 0; i < led->num_fnodes; i++) { addr_offset = led->fnode[i].id; - rc = qpnp_flash_led_masked_write(led, + rc = qpnp_flash_led_write(led, FLASH_LED_REG_HDRM_PRGM(led->base + addr_offset), - FLASH_LED_HDRM_MODE_PRGM_MASK, led->fnode[i].hdrm_val); if (rc < 0) return rc; @@ -313,9 +352,9 @@ static int qpnp_flash_led_init_settings(struct qpnp_flash_led *led) val |= 0x1 << led->fnode[i].id; } - rc = qpnp_flash_led_masked_write(led, + rc = qpnp_flash_led_write(led, FLASH_LED_REG_HDRM_AUTO_MODE_CTRL(led->base), - FLASH_LED_HDRM_MODE_PRGM_MASK, val); + val); if (rc < 0) return rc; @@ -340,6 +379,43 @@ static int qpnp_flash_led_init_settings(struct qpnp_flash_led *led) if (rc < 0) return rc; + val = (led->pdata->otst_ramp_bkup_en << THERMAL_OTST1_RAMP_CTRL_SHIFT); + mask = THERMAL_OTST1_RAMP_CTRL_MASK; + if (led->pdata->thermal_derate_slow >= 0) { + val |= (led->pdata->thermal_derate_slow << + THERMAL_DERATE_SLOW_SHIFT); + mask |= THERMAL_DERATE_SLOW_MASK; + } + + if (led->pdata->thermal_derate_fast >= 0) { + val |= led->pdata->thermal_derate_fast; + mask |= THERMAL_DERATE_FAST_MASK; + } + + rc = qpnp_flash_led_masked_write(led, + FLASH_LED_REG_THERMAL_RMP_DN_RATE(led->base), + mask, val); + if (rc < 0) + return rc; + + if (led->pdata->thermal_debounce >= 0) { + rc = qpnp_flash_led_masked_write(led, + FLASH_LED_REG_THERMAL_DEBOUNCE(led->base), + FLASH_LED_THERMAL_DEBOUNCE_MASK, + led->pdata->thermal_debounce); + if (rc < 0) + return rc; + } + + if (led->pdata->thermal_hysteresis >= 0) { + rc = qpnp_flash_led_masked_write(led, + FLASH_LED_REG_THERMAL_HYSTERESIS(led->base), + FLASH_LED_THERMAL_HYSTERESIS_MASK, + led->pdata->thermal_hysteresis); + if (rc < 0) + return rc; + } + rc = qpnp_flash_led_masked_write(led, FLASH_LED_REG_VPH_DROOP_DEBOUNCE(led->base), FLASH_LED_VPH_DROOP_DEBOUNCE_MASK, @@ -923,9 +999,9 @@ static int qpnp_flash_led_switch_set(struct flash_switch_data *snode, bool on) if (rc < 0) return rc; - rc = qpnp_flash_led_masked_write(led, + rc = qpnp_flash_led_write(led, FLASH_LED_REG_SAFETY_TMR(led->base + addr_offset), - FLASH_LED_SAFETY_TMR_MASK, led->fnode[i].duration); + led->fnode[i].duration); if (rc < 0) return rc; @@ -1499,6 +1575,23 @@ static int qpnp_flash_led_parse_and_register_switch(struct qpnp_flash_led *led, return 0; } +static int get_code_from_table(int *table, int len, int value) +{ + int i; + + for (i = 0; i < len; i++) { + if (value == table[i]) + break; + } + + if (i == len) { + pr_err("Couldn't find %d from table\n", value); + return -ENODATA; + } + + return i; +} + static int qpnp_flash_led_parse_common_dt(struct qpnp_flash_led *led, struct device_node *node) { @@ -1583,6 +1676,81 @@ static int qpnp_flash_led_parse_common_dt(struct qpnp_flash_led *led, } } + led->pdata->otst_ramp_bkup_en = + !of_property_read_bool(node, "qcom,otst-ramp-back-up-dis"); + + led->pdata->thermal_derate_slow = -EINVAL; + rc = of_property_read_u32(node, "qcom,thermal-derate-slow", &val); + if (!rc) { + if (val < 0 || val > THERMAL_DERATE_SLOW_MAX) { + pr_err("Invalid thermal_derate_slow %d\n", val); + return -EINVAL; + } + + led->pdata->thermal_derate_slow = + get_code_from_table(thermal_derate_slow_table, + ARRAY_SIZE(thermal_derate_slow_table), val); + } else if (rc != -EINVAL) { + dev_err(&led->pdev->dev, "Unable to read thermal derate slow, rc=%d\n", + rc); + return rc; + } + + led->pdata->thermal_derate_fast = -EINVAL; + rc = of_property_read_u32(node, "qcom,thermal-derate-fast", &val); + if (!rc) { + if (val < 0 || val > THERMAL_DERATE_FAST_MAX) { + pr_err("Invalid thermal_derate_fast %d\n", val); + return -EINVAL; + } + + led->pdata->thermal_derate_fast = + get_code_from_table(thermal_derate_fast_table, + ARRAY_SIZE(thermal_derate_fast_table), val); + } else if (rc != -EINVAL) { + dev_err(&led->pdev->dev, "Unable to read thermal derate fast, rc=%d\n", + rc); + return rc; + } + + led->pdata->thermal_debounce = -EINVAL; + rc = of_property_read_u32(node, "qcom,thermal-debounce", &val); + if (!rc) { + if (val < 0 || val > THERMAL_DEBOUNCE_TIME_MAX) { + pr_err("Invalid thermal_debounce %d\n", val); + return -EINVAL; + } + + if (val >= 0 && val < 16) + led->pdata->thermal_debounce = 0; + else + led->pdata->thermal_debounce = ilog2(val) - 3; + } else if (rc != -EINVAL) { + dev_err(&led->pdev->dev, "Unable to read thermal debounce, rc=%d\n", + rc); + return rc; + } + + led->pdata->thermal_hysteresis = -EINVAL; + rc = of_property_read_u32(node, "qcom,thermal-hysteresis", &val); + if (!rc) { + if (led->pdata->pmic_rev_id->pmic_subtype == PM2FALCON_SUBTYPE) + val = THERMAL_HYST_TEMP_TO_VAL(val, 20); + else + val = THERMAL_HYST_TEMP_TO_VAL(val, 15); + + if (val < 0 || val > THERMAL_DERATE_HYSTERESIS_MAX) { + pr_err("Invalid thermal_derate_hysteresis %d\n", val); + return -EINVAL; + } + + led->pdata->thermal_hysteresis = val; + } else if (rc != -EINVAL) { + dev_err(&led->pdev->dev, "Unable to read thermal hysteresis, rc=%d\n", + rc); + return rc; + } + led->pdata->vph_droop_debounce = FLASH_LED_VPH_DROOP_DEBOUNCE_DEFAULT; rc = of_property_read_u32(node, "qcom,vph-droop-debounce-us", &val); if (!rc) { @@ -1594,9 +1762,9 @@ static int qpnp_flash_led_parse_common_dt(struct qpnp_flash_led *led, return rc; } - if (led->pdata->vph_droop_debounce > FLASH_LED_VPH_DROOP_DEBOUNCE_MAX) { + if (led->pdata->vph_droop_debounce > FLASH_LED_DEBOUNCE_MAX) { dev_err(&led->pdev->dev, - "Invalid VPH droop debounce specified"); + "Invalid VPH droop debounce specified\n"); return -EINVAL; } @@ -1613,7 +1781,7 @@ static int qpnp_flash_led_parse_common_dt(struct qpnp_flash_led *led, if (led->pdata->vph_droop_threshold > FLASH_LED_VPH_DROOP_THRESH_MAX) { dev_err(&led->pdev->dev, - "Invalid VPH droop threshold specified"); + "Invalid VPH droop threshold specified\n"); return -EINVAL; } @@ -1629,12 +1797,14 @@ static int qpnp_flash_led_parse_common_dt(struct qpnp_flash_led *led, return rc; } - if (led->pdata->vph_droop_hysteresis > FLASH_LED_VPH_DROOP_HYST_MAX) { + if (led->pdata->vph_droop_hysteresis > FLASH_LED_HYSTERESIS_MAX) { dev_err(&led->pdev->dev, - "Invalid VPH droop hysteresis specified"); + "Invalid VPH droop hysteresis specified\n"); return -EINVAL; } + led->pdata->vph_droop_hysteresis <<= FLASH_LED_VPH_DROOP_HYST_SHIFT; + rc = of_property_read_u32(node, "qcom,hw-strobe-option", &val); if (!rc) { led->pdata->hw_strobe_option = (u8)val; -- cgit v1.2.3 From ef5d639067bf5eeef098bf61fb280a42b23fbff9 Mon Sep 17 00:00:00 2001 From: Subbaraman Narayanamurthy Date: Fri, 26 Aug 2016 17:03:14 -0700 Subject: leds: qpnp-flash-v2: Add support for configuring OTST thresholds Add support for configuring the three thermal mitigation thresholds from device tree. CRs-Fixed: 1060212 Change-Id: Iafb7915e196a18b5f8076dda8fb06a4bd71a8e6e Signed-off-by: Devesh Jhunjhunwala Signed-off-by: Subbaraman Narayanamurthy --- .../bindings/leds/leds-qpnp-flash-v2.txt | 12 ++++ drivers/leds/leds-qpnp-flash-v2.c | 79 ++++++++++++++++++++++ 2 files changed, 91 insertions(+) diff --git a/Documentation/devicetree/bindings/leds/leds-qpnp-flash-v2.txt b/Documentation/devicetree/bindings/leds/leds-qpnp-flash-v2.txt index 2a4a8f83f8da..4808d1dda5c1 100644 --- a/Documentation/devicetree/bindings/leds/leds-qpnp-flash-v2.txt +++ b/Documentation/devicetree/bindings/leds/leds-qpnp-flash-v2.txt @@ -99,6 +99,18 @@ Optional properties: Allowed values are: 0, 15, 30, 45 for pmicobalt. 0, 20, 40, 60 for pm2falcon. +- qcom,thermal-thrsh1 : Integer property to specify OTST1 threshold + for thermal mitigation. Unit is in Celsius. + Accepted values are: + 85, 79, 73, 67, 109, 103, 97, 91. +- qcom,thermal-thrsh2 : Integer property to specify OTST2 threshold + for thermal mitigation. Unit is in Celsius. + Accepted values are: + 110, 104, 98, 92, 134, 128, 122, 116. +- qcom,thermal-thrsh3 : Integer property to specify OTST3 threshold + for thermal mitigation. Unit is in Celsius. + Accepted values are: + 125, 119, 113, 107, 149, 143, 137, 131. - qcom,hw-strobe-option : Integer type to specify hardware strobe option. Based on the specified value, additional GPIO configuration may be required to provide strobing support. Supported values are: diff --git a/drivers/leds/leds-qpnp-flash-v2.c b/drivers/leds/leds-qpnp-flash-v2.c index b126bf550425..caa7ea7e99f0 100644 --- a/drivers/leds/leds-qpnp-flash-v2.c +++ b/drivers/leds/leds-qpnp-flash-v2.c @@ -114,6 +114,7 @@ #define THERMAL_DEBOUNCE_TIME_MAX 64 #define THERMAL_DERATE_HYSTERESIS_MAX 3 #define FLASH_LED_THERMAL_THRSH_MIN 3 +#define FLASH_LED_THERMAL_THRSH_MAX 7 #define FLASH_LED_THERMAL_OTST_LEVELS 3 #define FLASH_LED_VLED_MAX_DEFAULT_UV 3500000 #define FLASH_LED_IBATT_OCP_THRESH_DEFAULT_UA 4500000 @@ -219,6 +220,9 @@ struct flash_led_platform_data { int thermal_derate_fast; int thermal_hysteresis; int thermal_debounce; + int thermal_thrsh1; + int thermal_thrsh2; + int thermal_thrsh3; u32 led1n2_iclamp_low_ma; u32 led1n2_iclamp_mid_ma; u32 led3_iclamp_low_ma; @@ -267,6 +271,18 @@ static int thermal_derate_fast_table[] = { 32, 64, 96, 128, 256, 384, 512, }; +static int otst1_threshold_table[] = { + 85, 79, 73, 67, 109, 103, 97, 91, +}; + +static int otst2_threshold_table[] = { + 110, 104, 98, 92, 134, 128, 122, 116, +}; + +static int otst3_threshold_table[] = { + 125, 119, 113, 107, 149, 143, 137, 131, +}; + static int qpnp_flash_led_read(struct qpnp_flash_led *led, u16 addr, u8 *data) { int rc; @@ -416,6 +432,33 @@ static int qpnp_flash_led_init_settings(struct qpnp_flash_led *led) return rc; } + if (led->pdata->thermal_thrsh1 >= 0) { + rc = qpnp_flash_led_masked_write(led, + FLASH_LED_REG_THERMAL_THRSH1(led->base), + FLASH_LED_THERMAL_THRSH_MASK, + led->pdata->thermal_thrsh1); + if (rc < 0) + return rc; + } + + if (led->pdata->thermal_thrsh2 >= 0) { + rc = qpnp_flash_led_masked_write(led, + FLASH_LED_REG_THERMAL_THRSH2(led->base), + FLASH_LED_THERMAL_THRSH_MASK, + led->pdata->thermal_thrsh2); + if (rc < 0) + return rc; + } + + if (led->pdata->thermal_thrsh3 >= 0) { + rc = qpnp_flash_led_masked_write(led, + FLASH_LED_REG_THERMAL_THRSH3(led->base), + FLASH_LED_THERMAL_THRSH_MASK, + led->pdata->thermal_thrsh3); + if (rc < 0) + return rc; + } + rc = qpnp_flash_led_masked_write(led, FLASH_LED_REG_VPH_DROOP_DEBOUNCE(led->base), FLASH_LED_VPH_DROOP_DEBOUNCE_MASK, @@ -1751,6 +1794,42 @@ static int qpnp_flash_led_parse_common_dt(struct qpnp_flash_led *led, return rc; } + led->pdata->thermal_thrsh1 = -EINVAL; + rc = of_property_read_u32(node, "qcom,thermal-thrsh1", &val); + if (!rc) { + led->pdata->thermal_thrsh1 = + get_code_from_table(otst1_threshold_table, + ARRAY_SIZE(otst1_threshold_table), val); + } else if (rc != -EINVAL) { + dev_err(&led->pdev->dev, "Unable to read thermal thrsh1, rc=%d\n", + rc); + return rc; + } + + led->pdata->thermal_thrsh2 = -EINVAL; + rc = of_property_read_u32(node, "qcom,thermal-thrsh2", &val); + if (!rc) { + led->pdata->thermal_thrsh2 = + get_code_from_table(otst2_threshold_table, + ARRAY_SIZE(otst2_threshold_table), val); + } else if (rc != -EINVAL) { + dev_err(&led->pdev->dev, "Unable to read thermal thrsh2, rc=%d\n", + rc); + return rc; + } + + led->pdata->thermal_thrsh3 = -EINVAL; + rc = of_property_read_u32(node, "qcom,thermal-thrsh3", &val); + if (!rc) { + led->pdata->thermal_thrsh3 = + get_code_from_table(otst3_threshold_table, + ARRAY_SIZE(otst3_threshold_table), val); + } else if (rc != -EINVAL) { + dev_err(&led->pdev->dev, "Unable to read thermal thrsh3, rc=%d\n", + rc); + return rc; + } + led->pdata->vph_droop_debounce = FLASH_LED_VPH_DROOP_DEBOUNCE_DEFAULT; rc = of_property_read_u32(node, "qcom,vph-droop-debounce-us", &val); if (!rc) { -- cgit v1.2.3 From 104ce58784cf67e4ada4c4301db080af3185d62d Mon Sep 17 00:00:00 2001 From: Subbaraman Narayanamurthy Date: Mon, 31 Oct 2016 14:56:08 -0700 Subject: leds: qpnp-flash-v2: change from dev_*() to pr_*() for logging Currently, dev_*() variants are used in the flashv2 LED driver for logging. However, it spews the kernel log because of the device name being longer. Logging with device name is also not really needed. Move to using pr_*() variants. Add a pr_fmt() to help that by adding a function name which will be more useful. Change-Id: I42503ccd2b2dcc62c5c868132d202b9698c9d216 Signed-off-by: Subbaraman Narayanamurthy --- drivers/leds/leds-qpnp-flash-v2.c | 330 +++++++++++++++----------------------- 1 file changed, 126 insertions(+), 204 deletions(-) diff --git a/drivers/leds/leds-qpnp-flash-v2.c b/drivers/leds/leds-qpnp-flash-v2.c index caa7ea7e99f0..674ca6161af9 100644 --- a/drivers/leds/leds-qpnp-flash-v2.c +++ b/drivers/leds/leds-qpnp-flash-v2.c @@ -10,6 +10,8 @@ * GNU General Public License for more details. */ +#define pr_fmt(fmt) "flashv2: %s: " fmt, __func__ + #include #include #include @@ -290,12 +292,11 @@ static int qpnp_flash_led_read(struct qpnp_flash_led *led, u16 addr, u8 *data) rc = regmap_read(led->regmap, addr, &val); if (rc < 0) { - dev_err(&led->pdev->dev, "Unable to read from 0x%04X rc = %d\n", - addr, rc); + pr_err("Unable to read from 0x%04X rc = %d\n", addr, rc); return rc; } - dev_dbg(&led->pdev->dev, "Read 0x%02X from addr 0x%04X\n", val, addr); + pr_debug("Read 0x%02X from addr 0x%04X\n", val, addr); *data = (u8)val; return 0; } @@ -306,12 +307,11 @@ static int qpnp_flash_led_write(struct qpnp_flash_led *led, u16 addr, u8 data) rc = regmap_write(led->regmap, addr, data); if (rc < 0) { - dev_err(&led->pdev->dev, "Unable to write to 0x%04X rc = %d\n", - addr, rc); + pr_err("Unable to write to 0x%04X rc = %d\n", addr, rc); return rc; } - dev_dbg(&led->pdev->dev, "Wrote 0x%02X to addr 0x%04X\n", data, addr); + pr_debug("Wrote 0x%02X to addr 0x%04X\n", data, addr); return 0; } @@ -337,11 +337,10 @@ qpnp_flash_led_masked_write(struct qpnp_flash_led *led, u16 addr, u8 mask, rc = regmap_update_bits(led->regmap, addr, mask, val); if (rc < 0) - dev_err(&led->pdev->dev, "Unable to update bits from 0x%04X, rc = %d\n", - addr, rc); + pr_err("Unable to update bits from 0x%04X, rc = %d\n", addr, + rc); else - dev_dbg(&led->pdev->dev, "Wrote 0x%02X to addr 0x%04X\n", - val, addr); + pr_debug("Wrote 0x%02X to addr 0x%04X\n", val, addr); return rc; } @@ -577,8 +576,7 @@ static int qpnp_flash_led_hw_strobe_enable(struct flash_node_data *fnode, on ? fnode->hw_strobe_state_active : fnode->hw_strobe_state_suspend); if (rc < 0) { - dev_err(&fnode->pdev->dev, - "failed to change hw strobe pin state\n"); + pr_err("failed to change hw strobe pin state\n"); return rc; } } @@ -603,7 +601,7 @@ static int qpnp_flash_led_regulator_enable(struct qpnp_flash_led *led, rc = regulator_disable(snode->vreg); if (rc < 0) { - dev_err(&led->pdev->dev, "regulator_%s failed, rc=%d\n", + pr_err("regulator_%s failed, rc=%d\n", on ? "enable" : "disable", rc); return rc; } @@ -619,14 +617,13 @@ static int get_property_from_fg(struct qpnp_flash_led *led, union power_supply_propval pval = {0, }; if (!led->bms_psy) { - dev_err(&led->pdev->dev, "no bms psy found\n"); + pr_err("no bms psy found\n"); return -EINVAL; } rc = power_supply_get_property(led->bms_psy, prop, &pval); if (rc) { - dev_err(&led->pdev->dev, - "bms psy doesn't support reading prop %d rc = %d\n", + pr_err("bms psy doesn't support reading prop %d rc = %d\n", prop, rc); return rc; } @@ -688,8 +685,7 @@ static int qpnp_flash_led_calc_max_current(struct qpnp_flash_led *led) rc = get_property_from_fg(led, POWER_SUPPLY_PROP_RESISTANCE, &rbatt_uohm); if (rc < 0) { - dev_err(&led->pdev->dev, "bms psy does not support resistance, rc=%d\n", - rc); + pr_err("bms psy does not support resistance, rc=%d\n", rc); return rc; } @@ -699,16 +695,14 @@ static int qpnp_flash_led_calc_max_current(struct qpnp_flash_led *led) rc = get_property_from_fg(led, POWER_SUPPLY_PROP_VOLTAGE_OCV, &ocv_uv); if (rc < 0) { - dev_err(&led->pdev->dev, "bms psy does not support OCV, rc=%d\n", - rc); + pr_err("bms psy does not support OCV, rc=%d\n", rc); return rc; } rc = get_property_from_fg(led, POWER_SUPPLY_PROP_CURRENT_NOW, &ibat_now); if (rc < 0) { - dev_err(&led->pdev->dev, "bms psy does not support current, rc=%d\n", - rc); + pr_err("bms psy does not support current, rc=%d\n", rc); return rc; } @@ -727,8 +721,7 @@ static int qpnp_flash_led_calc_max_current(struct qpnp_flash_led *led) FLASH_LED_LMH_MITIGATION_EN_MASK, FLASH_LED_LMH_MITIGATION_ENABLE); if (rc < 0) { - dev_err(&led->pdev->dev, "trigger lmh mitigation failed, rc=%d\n", - rc); + pr_err("trigger lmh mitigation failed, rc=%d\n", rc); return rc; } @@ -773,9 +766,8 @@ static int qpnp_flash_led_calc_max_current(struct qpnp_flash_led *led) * before collapsing the battery. (available power/ flash input voltage) */ avail_flash_ua = div64_s64(avail_flash_power_fw, vin_flash_uv * MCONV); - dev_dbg(&led->pdev->dev, "avail_iflash=%lld, ocv=%d, ibat=%d, rbatt=%d, trigger_lmh=%d\n", - avail_flash_ua, ocv_uv, ibat_now, rbatt_uohm, - led->trigger_lmh); + pr_debug("avail_iflash=%lld, ocv=%d, ibat=%d, rbatt=%d, trigger_lmh=%d\n", + avail_flash_ua, ocv_uv, ibat_now, rbatt_uohm, led->trigger_lmh); return min(FLASH_LED_MAX_TOTAL_CURRENT_MA, (int)(div64_s64(avail_flash_ua, MCONV))); } @@ -917,8 +909,7 @@ static int qpnp_flash_led_switch_disable(struct flash_switch_data *snode) FLASH_LED_LMH_MITIGATION_EN_MASK, FLASH_LED_LMH_MITIGATION_DISABLE); if (rc < 0) { - dev_err(&led->pdev->dev, "disable lmh mitigation failed, rc=%d\n", - rc); + pr_err("disable lmh mitigation failed, rc=%d\n", rc); return rc; } } @@ -929,8 +920,7 @@ static int qpnp_flash_led_switch_disable(struct flash_switch_data *snode) FLASH_LED_CHGR_MITIGATION_EN_MASK, FLASH_LED_CHGR_MITIGATION_DISABLE); if (rc < 0) { - dev_err(&led->pdev->dev, "disable chgr mitigation failed, rc=%d\n", - rc); + pr_err("disable chgr mitigation failed, rc=%d\n", rc); return rc; } } @@ -962,8 +952,7 @@ static int qpnp_flash_led_switch_disable(struct flash_switch_data *snode) rc = pinctrl_select_state(led->fnode[i].pinctrl, led->fnode[i].gpio_state_suspend); if (rc < 0) { - dev_err(&led->pdev->dev, - "failed to disable GPIO, rc=%d\n", rc); + pr_err("failed to disable GPIO, rc=%d\n", rc); return rc; } } @@ -972,8 +961,7 @@ static int qpnp_flash_led_switch_disable(struct flash_switch_data *snode) rc = qpnp_flash_led_hw_strobe_enable(&led->fnode[i], led->pdata->hw_strobe_option, false); if (rc < 0) { - dev_err(&led->pdev->dev, - "Unable to disable hw strobe, rc=%d\n", + pr_err("Unable to disable hw strobe, rc=%d\n", rc); return rc; } @@ -991,8 +979,8 @@ static int qpnp_flash_led_switch_set(struct flash_switch_data *snode, bool on) u8 val, mask; if (snode->enabled == on) { - dev_dbg(&led->pdev->dev, "Switch node is already %s!\n", - on ? "enabled" : "disabled"); + pr_debug("Switch node is already %s!\n", + on ? "enabled" : "disabled"); return 0; } @@ -1054,8 +1042,7 @@ static int qpnp_flash_led_switch_set(struct flash_switch_data *snode, bool on) rc = pinctrl_select_state(led->fnode[i].pinctrl, led->fnode[i].gpio_state_active); if (rc < 0) { - dev_err(&led->pdev->dev, - "failed to enable GPIO\n"); + pr_err("failed to enable GPIO rc=%d\n", rc); return rc; } } @@ -1064,8 +1051,8 @@ static int qpnp_flash_led_switch_set(struct flash_switch_data *snode, bool on) rc = qpnp_flash_led_hw_strobe_enable(&led->fnode[i], led->pdata->hw_strobe_option, true); if (rc < 0) { - dev_err(&led->pdev->dev, - "Unable to enable hw strobe\n"); + pr_err("Unable to enable hw strobe rc=%d\n", + rc); return rc; } } @@ -1086,8 +1073,7 @@ static int qpnp_flash_led_switch_set(struct flash_switch_data *snode, bool on) FLASH_LED_LMH_MITIGATION_EN_MASK, FLASH_LED_LMH_MITIGATION_ENABLE); if (rc < 0) { - dev_err(&led->pdev->dev, "trigger lmh mitigation failed, rc=%d\n", - rc); + pr_err("trigger lmh mitigation failed, rc=%d\n", rc); return rc; } } @@ -1098,8 +1084,7 @@ static int qpnp_flash_led_switch_set(struct flash_switch_data *snode, bool on) FLASH_LED_CHGR_MITIGATION_EN_MASK, FLASH_LED_CHGR_MITIGATION_ENABLE); if (rc < 0) { - dev_err(&led->pdev->dev, "trigger chgr mitigation failed, rc=%d\n", - rc); + pr_err("trigger chgr mitigation failed, rc=%d\n", rc); return rc; } } @@ -1131,15 +1116,14 @@ int qpnp_flash_led_prepare(struct led_trigger *trig, int options, led = dev_get_drvdata(&snode->pdev->dev); if (!(options & FLASH_LED_PREPARE_OPTIONS_MASK)) { - dev_err(&led->pdev->dev, "Invalid options %d\n", options); + pr_err("Invalid options %d\n", options); return -EINVAL; } if (options & ENABLE_REGULATOR) { rc = qpnp_flash_led_regulator_enable(led, snode, true); if (rc < 0) { - dev_err(&led->pdev->dev, - "enable regulator failed, rc=%d\n", rc); + pr_err("enable regulator failed, rc=%d\n", rc); return rc; } } @@ -1147,8 +1131,7 @@ int qpnp_flash_led_prepare(struct led_trigger *trig, int options, if (options & DISABLE_REGULATOR) { rc = qpnp_flash_led_regulator_enable(led, snode, false); if (rc < 0) { - dev_err(&led->pdev->dev, - "disable regulator failed, rc=%d\n", rc); + pr_err("disable regulator failed, rc=%d\n", rc); return rc; } } @@ -1156,8 +1139,7 @@ int qpnp_flash_led_prepare(struct led_trigger *trig, int options, if (options & QUERY_MAX_CURRENT) { rc = qpnp_flash_led_get_max_avail_current(led); if (rc < 0) { - dev_err(&led->pdev->dev, - "query max current failed, rc=%d\n", rc); + pr_err("query max current failed, rc=%d\n", rc); return rc; } *max_current = rc; @@ -1197,8 +1179,7 @@ static void qpnp_flash_led_brightness_set(struct led_classdev *led_cdev, if (snode) { rc = qpnp_flash_led_switch_set(snode, value > 0); if (rc < 0) - dev_err(&led->pdev->dev, - "Failed to set flash LED switch\n"); + pr_err("Failed to set flash LED switch rc=%d\n", rc); } else if (fnode) { qpnp_flash_led_node_set(fnode, value); } @@ -1220,8 +1201,7 @@ static ssize_t qpnp_flash_led_max_current_show(struct device *dev, rc = qpnp_flash_led_get_max_avail_current(led); if (rc < 0) - dev_err(&led->pdev->dev, "query max current failed, rc=%d\n", - rc); + pr_err("query max current failed, rc=%d\n", rc); return snprintf(buf, PAGE_SIZE, "%d\n", rc); } @@ -1245,7 +1225,7 @@ static int flash_led_psy_notifier_call(struct notifier_block *nb, if (!strcmp(psy->desc->name, "bms")) { led->bms_psy = power_supply_get_by_name("bms"); if (!led->bms_psy) - dev_err(&led->pdev->dev, "Failed to get bms power_supply\n"); + pr_err("Failed to get bms power_supply\n"); else power_supply_unreg_notifier(&led->nb); } @@ -1275,13 +1255,12 @@ static irqreturn_t qpnp_flash_led_irq_handler(int irq, void *_led) int rc; u8 irq_status, led_status1, led_status2; - dev_dbg(&led->pdev->dev, "irq received, irq=%d\n", irq); + pr_debug("irq received, irq=%d\n", irq); rc = qpnp_flash_led_read(led, FLASH_LED_REG_INT_RT_STS(led->base), &irq_status); if (rc < 0) { - dev_err(&led->pdev->dev, "Failed to read interrupt status reg, rc=%d\n", - rc); + pr_err("Failed to read interrupt status reg, rc=%d\n", rc); goto exit; } @@ -1300,29 +1279,27 @@ static irqreturn_t qpnp_flash_led_irq_handler(int irq, void *_led) rc = qpnp_flash_led_read(led, FLASH_LED_REG_LED_STATUS1(led->base), &led_status1); if (rc < 0) { - dev_err(&led->pdev->dev, "Failed to read led_status1 reg, rc=%d\n", - rc); + pr_err("Failed to read led_status1 reg, rc=%d\n", rc); goto exit; } rc = qpnp_flash_led_read(led, FLASH_LED_REG_LED_STATUS2(led->base), &led_status2); if (rc < 0) { - dev_err(&led->pdev->dev, "Failed to read led_status2 reg, rc=%d\n", - rc); + pr_err("Failed to read led_status2 reg, rc=%d\n", rc); goto exit; } if (led_status1) - dev_emerg(&led->pdev->dev, "led short/open fault detected! led_status1=%x\n", - led_status1); + pr_emerg("led short/open fault detected! led_status1=%x\n", + led_status1); if (led_status2 & FLASH_LED_VPH_DROOP_FAULT_MASK) - dev_emerg(&led->pdev->dev, "led vph_droop fault detected!\n"); + pr_emerg("led vph_droop fault detected!\n"); } - dev_dbg(&led->pdev->dev, "irq handled, irq_type=%x, irq_status=%x\n", - irq_type, irq_status); + pr_debug("irq handled, irq_type=%x, irq_status=%x\n", irq_type, + irq_status); exit: return IRQ_HANDLED; @@ -1352,7 +1329,7 @@ static int qpnp_flash_led_parse_each_led_dt(struct qpnp_flash_led *led, rc = of_property_read_string(node, "qcom,led-name", &fnode->cdev.name); if (rc < 0) { - dev_err(&led->pdev->dev, "Unable to read flash LED names\n"); + pr_err("Unable to read flash LED names\n"); return rc; } @@ -1363,11 +1340,11 @@ static int qpnp_flash_led_parse_each_led_dt(struct qpnp_flash_led *led, } else if (!strcmp(temp_string, "torch")) { fnode->type = FLASH_LED_TYPE_TORCH; } else { - dev_err(&led->pdev->dev, "Wrong flash LED type\n"); + pr_err("Wrong flash LED type\n"); return rc; } } else { - dev_err(&led->pdev->dev, "Unable to read flash LED label\n"); + pr_err("Unable to read flash LED label\n"); return rc; } @@ -1375,14 +1352,14 @@ static int qpnp_flash_led_parse_each_led_dt(struct qpnp_flash_led *led, if (!rc) { fnode->id = (u8)val; } else { - dev_err(&led->pdev->dev, "Unable to read flash LED ID\n"); + pr_err("Unable to read flash LED ID\n"); return rc; } rc = of_property_read_string(node, "qcom,default-led-trigger", &fnode->cdev.default_trigger); if (rc < 0) { - dev_err(&led->pdev->dev, "Unable to read trigger name\n"); + pr_err("Unable to read trigger name\n"); return rc; } @@ -1394,7 +1371,7 @@ static int qpnp_flash_led_parse_each_led_dt(struct qpnp_flash_led *led, fnode->ires = FLASH_LED_IRES_BASE - (val - FLASH_LED_IRES_MIN_UA) / FLASH_LED_IRES_DIVISOR; } else if (rc != -EINVAL) { - dev_err(&led->pdev->dev, "Unable to read current resolution\n"); + pr_err("Unable to read current resolution rc=%d\n", rc); return rc; } @@ -1405,8 +1382,7 @@ static int qpnp_flash_led_parse_each_led_dt(struct qpnp_flash_led *led, fnode->max_current = val; fnode->cdev.max_brightness = val; } else { - dev_err(&led->pdev->dev, - "Unable to read max current, rc=%d\n", rc); + pr_err("Unable to read max current, rc=%d\n", rc); return rc; } @@ -1414,8 +1390,7 @@ static int qpnp_flash_led_parse_each_led_dt(struct qpnp_flash_led *led, if (!rc) { if (val < FLASH_LED_MIN_CURRENT_MA || val > fnode->max_current) - dev_warn(&led->pdev->dev, - "Invalid operational current specified, capping it\n"); + pr_warn("Invalid operational current specified, capping it\n"); if (val < FLASH_LED_MIN_CURRENT_MA) val = FLASH_LED_MIN_CURRENT_MA; if (val > fnode->max_current) @@ -1423,8 +1398,7 @@ static int qpnp_flash_led_parse_each_led_dt(struct qpnp_flash_led *led, fnode->current_ma = val; fnode->cdev.brightness = val; } else if (rc != -EINVAL) { - dev_err(&led->pdev->dev, - "Unable to read operational current, rc=%d\n", rc); + pr_err("Unable to read operational current, rc=%d\n", rc); return rc; } @@ -1435,13 +1409,11 @@ static int qpnp_flash_led_parse_each_led_dt(struct qpnp_flash_led *led, FLASH_LED_SAFETY_TMR_ENABLE); } else if (rc == -EINVAL) { if (fnode->type == FLASH_LED_TYPE_FLASH) { - dev_err(&led->pdev->dev, - "Timer duration is required for flash LED\n"); + pr_err("Timer duration is required for flash LED\n"); return rc; } } else { - dev_err(&led->pdev->dev, - "Unable to read timer duration\n"); + pr_err("Unable to read timer duration\n"); return rc; } @@ -1453,7 +1425,7 @@ static int qpnp_flash_led_parse_each_led_dt(struct qpnp_flash_led *led, fnode->hdrm_val = (val << FLASH_LED_HDRM_VOL_SHIFT) & FLASH_LED_HDRM_VOL_MASK; } else if (rc != -EINVAL) { - dev_err(&led->pdev->dev, "Unable to read headroom voltage\n"); + pr_err("Unable to read headroom voltage\n"); return rc; } @@ -1464,8 +1436,7 @@ static int qpnp_flash_led_parse_each_led_dt(struct qpnp_flash_led *led, } else if (rc == -EINVAL) { fnode->hdrm_val |= FLASH_LED_HDRM_VOL_HI_LO_WIN_DEFAULT_MV; } else { - dev_err(&led->pdev->dev, - "Unable to read hdrm hi-lo window voltage\n"); + pr_err("Unable to read hdrm hi-lo window voltage\n"); return rc; } @@ -1483,8 +1454,7 @@ static int qpnp_flash_led_parse_each_led_dt(struct qpnp_flash_led *led, fnode->hw_strobe_gpio = of_get_named_gpio(node, "qcom,hw-strobe-gpio", 0); if (fnode->hw_strobe_gpio < 0) { - dev_err(&led->pdev->dev, - "Invalid gpio specified\n"); + pr_err("Invalid gpio specified\n"); return fnode->hw_strobe_gpio; } gpio_direction_output(fnode->hw_strobe_gpio, 0); @@ -1494,8 +1464,7 @@ static int qpnp_flash_led_parse_each_led_dt(struct qpnp_flash_led *led, pinctrl_lookup_state(fnode->pinctrl, "strobe_enable"); if (IS_ERR_OR_NULL(fnode->hw_strobe_state_active)) { - dev_err(&led->pdev->dev, - "No active pin for hardware strobe, rc=%ld\n", + pr_err("No active pin for hardware strobe, rc=%ld\n", PTR_ERR(fnode->hw_strobe_state_active)); fnode->hw_strobe_state_active = NULL; } @@ -1504,8 +1473,7 @@ static int qpnp_flash_led_parse_each_led_dt(struct qpnp_flash_led *led, pinctrl_lookup_state(fnode->pinctrl, "strobe_disable"); if (IS_ERR_OR_NULL(fnode->hw_strobe_state_suspend)) { - dev_err(&led->pdev->dev, - "No suspend pin for hardware strobe, rc=%ld\n", + pr_err("No suspend pin for hardware strobe, rc=%ld\n", PTR_ERR(fnode->hw_strobe_state_suspend) ); fnode->hw_strobe_state_suspend = NULL; @@ -1515,8 +1483,7 @@ static int qpnp_flash_led_parse_each_led_dt(struct qpnp_flash_led *led, rc = led_classdev_register(&led->pdev->dev, &fnode->cdev); if (rc < 0) { - dev_err(&led->pdev->dev, "Unable to register led node %d\n", - fnode->id); + pr_err("Unable to register led node %d\n", fnode->id); return rc; } @@ -1524,14 +1491,13 @@ static int qpnp_flash_led_parse_each_led_dt(struct qpnp_flash_led *led, fnode->pinctrl = devm_pinctrl_get(fnode->cdev.dev); if (IS_ERR_OR_NULL(fnode->pinctrl)) { - dev_dbg(&led->pdev->dev, "No pinctrl defined\n"); + pr_debug("No pinctrl defined\n"); fnode->pinctrl = NULL; } else { fnode->gpio_state_active = pinctrl_lookup_state(fnode->pinctrl, "led_enable"); if (IS_ERR_OR_NULL(fnode->gpio_state_active)) { - dev_err(&led->pdev->dev, - "Cannot lookup LED active state\n"); + pr_err("Cannot lookup LED active state\n"); devm_pinctrl_put(fnode->pinctrl); fnode->pinctrl = NULL; return PTR_ERR(fnode->gpio_state_active); @@ -1540,8 +1506,7 @@ static int qpnp_flash_led_parse_each_led_dt(struct qpnp_flash_led *led, fnode->gpio_state_suspend = pinctrl_lookup_state(fnode->pinctrl, "led_disable"); if (IS_ERR_OR_NULL(fnode->gpio_state_suspend)) { - dev_err(&led->pdev->dev, - "Cannot lookup LED disable state\n"); + pr_err("Cannot lookup LED disable state\n"); devm_pinctrl_put(fnode->pinctrl); fnode->pinctrl = NULL; return PTR_ERR(fnode->gpio_state_suspend); @@ -1560,8 +1525,7 @@ static int qpnp_flash_led_parse_and_register_switch(struct qpnp_flash_led *led, rc = of_property_read_string(node, "qcom,led-name", &snode->cdev.name); if (rc < 0) { - dev_err(&led->pdev->dev, - "Failed to read switch node name, rc=%d\n", rc); + pr_err("Failed to read switch node name, rc=%d\n", rc); return rc; } @@ -1574,19 +1538,18 @@ static int qpnp_flash_led_parse_and_register_switch(struct qpnp_flash_led *led, rc = of_property_read_string(node, "qcom,default-led-trigger", &snode->cdev.default_trigger); if (rc < 0) { - dev_err(&led->pdev->dev, - "Unable to read trigger name, rc=%d\n", rc); + pr_err("Unable to read trigger name, rc=%d\n", rc); return rc; } rc = of_property_read_u32(node, "qcom,led-mask", &snode->led_mask); if (rc < 0) { - dev_err(&led->pdev->dev, "Unable to read led mask rc=%d\n", rc); + pr_err("Unable to read led mask rc=%d\n", rc); return rc; } if (snode->led_mask < 1 || snode->led_mask > 7) { - dev_err(&led->pdev->dev, "Invalid value for led-mask\n"); + pr_err("Invalid value for led-mask\n"); return -EINVAL; } @@ -1597,8 +1560,7 @@ static int qpnp_flash_led_parse_and_register_switch(struct qpnp_flash_led *led, if (IS_ERR_OR_NULL(snode->vreg)) { rc = PTR_ERR(snode->vreg); if (rc != -EPROBE_DEFER) - dev_err(&led->pdev->dev, "Failed to get regulator, rc=%d\n", - rc); + pr_err("Failed to get regulator, rc=%d\n", rc); snode->vreg = NULL; return rc; } @@ -1609,8 +1571,7 @@ static int qpnp_flash_led_parse_and_register_switch(struct qpnp_flash_led *led, snode->cdev.brightness_get = qpnp_flash_led_brightness_get; rc = led_classdev_register(&led->pdev->dev, &snode->cdev); if (rc < 0) { - dev_err(&led->pdev->dev, - "Unable to register led switch node\n"); + pr_err("Unable to register led switch node\n"); return rc; } @@ -1674,8 +1635,7 @@ static int qpnp_flash_led_parse_common_dt(struct qpnp_flash_led *led, led->pdata->isc_delay = val >> FLASH_LED_ISC_WARMUP_DELAY_SHIFT; } else if (rc != -EINVAL) { - dev_err(&led->pdev->dev, - "Unable to read ISC delay, rc=%d\n", rc); + pr_err("Unable to read ISC delay, rc=%d\n", rc); return rc; } @@ -1685,8 +1645,7 @@ static int qpnp_flash_led_parse_common_dt(struct qpnp_flash_led *led, led->pdata->warmup_delay = val >> FLASH_LED_ISC_WARMUP_DELAY_SHIFT; } else if (rc != -EINVAL) { - dev_err(&led->pdev->dev, - "Unable to read WARMUP delay, rc=%d\n", rc); + pr_err("Unable to read WARMUP delay, rc=%d\n", rc); return rc; } @@ -1713,8 +1672,8 @@ static int qpnp_flash_led_parse_common_dt(struct qpnp_flash_led *led, led->pdata->thermal_derate_current, FLASH_LED_THERMAL_OTST_LEVELS); if (rc < 0) { - dev_err(&led->pdev->dev, "Unable to read thermal current limits, rc=%d\n", - rc); + pr_err("Unable to read thermal current limits, rc=%d\n", + rc); return rc; } } @@ -1734,8 +1693,7 @@ static int qpnp_flash_led_parse_common_dt(struct qpnp_flash_led *led, get_code_from_table(thermal_derate_slow_table, ARRAY_SIZE(thermal_derate_slow_table), val); } else if (rc != -EINVAL) { - dev_err(&led->pdev->dev, "Unable to read thermal derate slow, rc=%d\n", - rc); + pr_err("Unable to read thermal derate slow, rc=%d\n", rc); return rc; } @@ -1751,8 +1709,7 @@ static int qpnp_flash_led_parse_common_dt(struct qpnp_flash_led *led, get_code_from_table(thermal_derate_fast_table, ARRAY_SIZE(thermal_derate_fast_table), val); } else if (rc != -EINVAL) { - dev_err(&led->pdev->dev, "Unable to read thermal derate fast, rc=%d\n", - rc); + pr_err("Unable to read thermal derate fast, rc=%d\n", rc); return rc; } @@ -1769,8 +1726,7 @@ static int qpnp_flash_led_parse_common_dt(struct qpnp_flash_led *led, else led->pdata->thermal_debounce = ilog2(val) - 3; } else if (rc != -EINVAL) { - dev_err(&led->pdev->dev, "Unable to read thermal debounce, rc=%d\n", - rc); + pr_err("Unable to read thermal debounce, rc=%d\n", rc); return rc; } @@ -1789,8 +1745,7 @@ static int qpnp_flash_led_parse_common_dt(struct qpnp_flash_led *led, led->pdata->thermal_hysteresis = val; } else if (rc != -EINVAL) { - dev_err(&led->pdev->dev, "Unable to read thermal hysteresis, rc=%d\n", - rc); + pr_err("Unable to read thermal hysteresis, rc=%d\n", rc); return rc; } @@ -1801,8 +1756,7 @@ static int qpnp_flash_led_parse_common_dt(struct qpnp_flash_led *led, get_code_from_table(otst1_threshold_table, ARRAY_SIZE(otst1_threshold_table), val); } else if (rc != -EINVAL) { - dev_err(&led->pdev->dev, "Unable to read thermal thrsh1, rc=%d\n", - rc); + pr_err("Unable to read thermal thrsh1, rc=%d\n", rc); return rc; } @@ -1813,8 +1767,7 @@ static int qpnp_flash_led_parse_common_dt(struct qpnp_flash_led *led, get_code_from_table(otst2_threshold_table, ARRAY_SIZE(otst2_threshold_table), val); } else if (rc != -EINVAL) { - dev_err(&led->pdev->dev, "Unable to read thermal thrsh2, rc=%d\n", - rc); + pr_err("Unable to read thermal thrsh2, rc=%d\n", rc); return rc; } @@ -1825,8 +1778,7 @@ static int qpnp_flash_led_parse_common_dt(struct qpnp_flash_led *led, get_code_from_table(otst3_threshold_table, ARRAY_SIZE(otst3_threshold_table), val); } else if (rc != -EINVAL) { - dev_err(&led->pdev->dev, "Unable to read thermal thrsh3, rc=%d\n", - rc); + pr_err("Unable to read thermal thrsh3, rc=%d\n", rc); return rc; } @@ -1836,14 +1788,12 @@ static int qpnp_flash_led_parse_common_dt(struct qpnp_flash_led *led, led->pdata->vph_droop_debounce = VPH_DROOP_DEBOUNCE_US_TO_VAL(val); } else if (rc != -EINVAL) { - dev_err(&led->pdev->dev, - "Unable to read VPH droop debounce, rc=%d\n", rc); + pr_err("Unable to read VPH droop debounce, rc=%d\n", rc); return rc; } if (led->pdata->vph_droop_debounce > FLASH_LED_DEBOUNCE_MAX) { - dev_err(&led->pdev->dev, - "Invalid VPH droop debounce specified\n"); + pr_err("Invalid VPH droop debounce specified\n"); return -EINVAL; } @@ -1853,14 +1803,12 @@ static int qpnp_flash_led_parse_common_dt(struct qpnp_flash_led *led, led->pdata->vph_droop_threshold = VPH_DROOP_THRESH_MV_TO_VAL(val); } else if (rc != -EINVAL) { - dev_err(&led->pdev->dev, - "Unable to read VPH droop threshold, rc=%d\n", rc); + pr_err("Unable to read VPH droop threshold, rc=%d\n", rc); return rc; } if (led->pdata->vph_droop_threshold > FLASH_LED_VPH_DROOP_THRESH_MAX) { - dev_err(&led->pdev->dev, - "Invalid VPH droop threshold specified\n"); + pr_err("Invalid VPH droop threshold specified\n"); return -EINVAL; } @@ -1871,14 +1819,12 @@ static int qpnp_flash_led_parse_common_dt(struct qpnp_flash_led *led, led->pdata->vph_droop_hysteresis = VPH_DROOP_HYST_MV_TO_VAL(val); } else if (rc != -EINVAL) { - dev_err(&led->pdev->dev, - "Unable to read VPH droop hysteresis, rc=%d\n", rc); + pr_err("Unable to read VPH droop hysteresis, rc=%d\n", rc); return rc; } if (led->pdata->vph_droop_hysteresis > FLASH_LED_HYSTERESIS_MAX) { - dev_err(&led->pdev->dev, - "Invalid VPH droop hysteresis specified\n"); + pr_err("Invalid VPH droop hysteresis specified\n"); return -EINVAL; } @@ -1888,8 +1834,7 @@ static int qpnp_flash_led_parse_common_dt(struct qpnp_flash_led *led, if (!rc) { led->pdata->hw_strobe_option = (u8)val; } else if (rc != -EINVAL) { - dev_err(&led->pdev->dev, - "Unable to parse hw strobe option, rc=%d\n", rc); + pr_err("Unable to parse hw strobe option, rc=%d\n", rc); return rc; } @@ -1897,8 +1842,7 @@ static int qpnp_flash_led_parse_common_dt(struct qpnp_flash_led *led, if (!rc) { led->pdata->led1n2_iclamp_low_ma = val; } else if (rc != -EINVAL) { - dev_err(&led->pdev->dev, "Unable to read led1n2_iclamp_low current, rc=%d\n", - rc); + pr_err("Unable to read led1n2_iclamp_low current, rc=%d\n", rc); return rc; } @@ -1906,8 +1850,7 @@ static int qpnp_flash_led_parse_common_dt(struct qpnp_flash_led *led, if (!rc) { led->pdata->led1n2_iclamp_mid_ma = val; } else if (rc != -EINVAL) { - dev_err(&led->pdev->dev, "Unable to read led1n2_iclamp_mid current, rc=%d\n", - rc); + pr_err("Unable to read led1n2_iclamp_mid current, rc=%d\n", rc); return rc; } @@ -1915,8 +1858,7 @@ static int qpnp_flash_led_parse_common_dt(struct qpnp_flash_led *led, if (!rc) { led->pdata->led3_iclamp_low_ma = val; } else if (rc != -EINVAL) { - dev_err(&led->pdev->dev, "Unable to read led3_iclamp_low current, rc=%d\n", - rc); + pr_err("Unable to read led3_iclamp_low current, rc=%d\n", rc); return rc; } @@ -1924,8 +1866,7 @@ static int qpnp_flash_led_parse_common_dt(struct qpnp_flash_led *led, if (!rc) { led->pdata->led3_iclamp_mid_ma = val; } else if (rc != -EINVAL) { - dev_err(&led->pdev->dev, "Unable to read led3_iclamp_mid current, rc=%d\n", - rc); + pr_err("Unable to read led3_iclamp_mid current, rc=%d\n", rc); return rc; } @@ -1934,8 +1875,7 @@ static int qpnp_flash_led_parse_common_dt(struct qpnp_flash_led *led, if (!rc) { led->pdata->vled_max_uv = val; } else if (rc != -EINVAL) { - dev_err(&led->pdev->dev, "Unable to parse vled_max voltage, rc=%d\n", - rc); + pr_err("Unable to parse vled_max voltage, rc=%d\n", rc); return rc; } @@ -1945,8 +1885,7 @@ static int qpnp_flash_led_parse_common_dt(struct qpnp_flash_led *led, if (!rc) { led->pdata->ibatt_ocp_threshold_ua = val; } else if (rc != -EINVAL) { - dev_err(&led->pdev->dev, "Unable to parse ibatt_ocp threshold, rc=%d\n", - rc); + pr_err("Unable to parse ibatt_ocp threshold, rc=%d\n", rc); return rc; } @@ -1955,8 +1894,7 @@ static int qpnp_flash_led_parse_common_dt(struct qpnp_flash_led *led, if (!rc) { led->pdata->rpara_uohm = val; } else if (rc != -EINVAL) { - dev_err(&led->pdev->dev, "Unable to parse rparasitic, rc=%d\n", - rc); + pr_err("Unable to parse rparasitic, rc=%d\n", rc); return rc; } @@ -1966,8 +1904,7 @@ static int qpnp_flash_led_parse_common_dt(struct qpnp_flash_led *led, if (!rc) { led->pdata->lmh_ocv_threshold_uv = val; } else if (rc != -EINVAL) { - dev_err(&led->pdev->dev, "Unable to parse lmh ocv threshold, rc=%d\n", - rc); + pr_err("Unable to parse lmh ocv threshold, rc=%d\n", rc); return rc; } @@ -1977,8 +1914,7 @@ static int qpnp_flash_led_parse_common_dt(struct qpnp_flash_led *led, if (!rc) { led->pdata->lmh_rbatt_threshold_uohm = val; } else if (rc != -EINVAL) { - dev_err(&led->pdev->dev, "Unable to parse lmh rbatt threshold, rc=%d\n", - rc); + pr_err("Unable to parse lmh rbatt threshold, rc=%d\n", rc); return rc; } @@ -1987,8 +1923,7 @@ static int qpnp_flash_led_parse_common_dt(struct qpnp_flash_led *led, if (!rc) { led->pdata->lmh_level = val; } else if (rc != -EINVAL) { - dev_err(&led->pdev->dev, "Unable to parse lmh_level, rc=%d\n", - rc); + pr_err("Unable to parse lmh_level, rc=%d\n", rc); return rc; } @@ -1997,13 +1932,12 @@ static int qpnp_flash_led_parse_common_dt(struct qpnp_flash_led *led, if (!rc) { led->pdata->lmh_mitigation_sel = val; } else if (rc != -EINVAL) { - dev_err(&led->pdev->dev, "Unable to parse lmh_mitigation_sel, rc=%d\n", - rc); + pr_err("Unable to parse lmh_mitigation_sel, rc=%d\n", rc); return rc; } if (led->pdata->lmh_mitigation_sel > FLASH_LED_MITIGATION_SEL_MAX) { - dev_err(&led->pdev->dev, "Invalid lmh_mitigation_sel specified\n"); + pr_err("Invalid lmh_mitigation_sel specified\n"); return -EINVAL; } @@ -2012,13 +1946,12 @@ static int qpnp_flash_led_parse_common_dt(struct qpnp_flash_led *led, if (!rc) { led->pdata->chgr_mitigation_sel = val; } else if (rc != -EINVAL) { - dev_err(&led->pdev->dev, "Unable to parse chgr_mitigation_sel, rc=%d\n", - rc); + pr_err("Unable to parse chgr_mitigation_sel, rc=%d\n", rc); return rc; } if (led->pdata->chgr_mitigation_sel > FLASH_LED_MITIGATION_SEL_MAX) { - dev_err(&led->pdev->dev, "Invalid chgr_mitigation_sel specified\n"); + pr_err("Invalid chgr_mitigation_sel specified\n"); return -EINVAL; } @@ -2029,30 +1962,29 @@ static int qpnp_flash_led_parse_common_dt(struct qpnp_flash_led *led, if (!rc) { led->pdata->iled_thrsh_val = MITIGATION_THRSH_MA_TO_VAL(val); } else if (rc != -EINVAL) { - dev_err(&led->pdev->dev, "Unable to parse iled_thrsh_val, rc=%d\n", - rc); + pr_err("Unable to parse iled_thrsh_val, rc=%d\n", rc); return rc; } if (led->pdata->iled_thrsh_val > FLASH_LED_MITIGATION_THRSH_MAX) { - dev_err(&led->pdev->dev, "Invalid iled_thrsh_val specified\n"); + pr_err("Invalid iled_thrsh_val specified\n"); return -EINVAL; } led->pdata->all_ramp_up_done_irq = of_irq_get_byname(node, "all-ramp-up-done-irq"); if (led->pdata->all_ramp_up_done_irq < 0) - dev_dbg(&led->pdev->dev, "all-ramp-up-done-irq not used\n"); + pr_debug("all-ramp-up-done-irq not used\n"); led->pdata->all_ramp_down_done_irq = of_irq_get_byname(node, "all-ramp-down-done-irq"); if (led->pdata->all_ramp_down_done_irq < 0) - dev_dbg(&led->pdev->dev, "all-ramp-down-done-irq not used\n"); + pr_debug("all-ramp-down-done-irq not used\n"); led->pdata->led_fault_irq = of_irq_get_byname(node, "led-fault-irq"); if (led->pdata->led_fault_irq < 0) - dev_dbg(&led->pdev->dev, "led-fault-irq not used\n"); + pr_debug("led-fault-irq not used\n"); return 0; } @@ -2067,14 +1999,14 @@ static int qpnp_flash_led_probe(struct platform_device *pdev) node = pdev->dev.of_node; if (!node) { - dev_info(&pdev->dev, "No flash LED nodes defined\n"); + pr_err("No flash LED nodes defined\n"); return -ENODEV; } rc = of_property_read_u32(node, "reg", &base); if (rc < 0) { - dev_err(&pdev->dev, "Couldn't find reg in node %s, rc = %d\n", - node->full_name, rc); + pr_err("Couldn't find reg in node %s, rc = %d\n", + node->full_name, rc); return rc; } @@ -2085,7 +2017,7 @@ static int qpnp_flash_led_probe(struct platform_device *pdev) led->regmap = dev_get_regmap(pdev->dev.parent, NULL); if (!led->regmap) { - dev_err(&pdev->dev, "Couldn't get parent's regmap\n"); + pr_err("Couldn't get parent's regmap\n"); return -EINVAL; } @@ -2098,16 +2030,14 @@ static int qpnp_flash_led_probe(struct platform_device *pdev) rc = qpnp_flash_led_parse_common_dt(led, node); if (rc < 0) { - dev_err(&pdev->dev, - "Failed to parse common flash LED device tree\n"); + pr_err("Failed to parse common flash LED device tree\n"); return rc; } for_each_available_child_of_node(node, temp) { rc = of_property_read_string(temp, "label", &temp_string); if (rc < 0) { - dev_err(&pdev->dev, - "Failed to parse label, rc=%d\n", rc); + pr_err("Failed to parse label, rc=%d\n", rc); return rc; } @@ -2117,14 +2047,13 @@ static int qpnp_flash_led_probe(struct platform_device *pdev) !strcmp("torch", temp_string)) { led->num_fnodes++; } else { - dev_err(&pdev->dev, - "Invalid label for led node\n"); + pr_err("Invalid label for led node\n"); return -EINVAL; } } if (!led->num_fnodes) { - dev_err(&pdev->dev, "No LED nodes defined\n"); + pr_err("No LED nodes defined\n"); return -ECHILD; } @@ -2146,8 +2075,7 @@ static int qpnp_flash_led_probe(struct platform_device *pdev) for_each_available_child_of_node(node, temp) { rc = of_property_read_string(temp, "label", &temp_string); if (rc < 0) { - dev_err(&pdev->dev, - "Failed to parse label, rc=%d\n", rc); + pr_err("Failed to parse label, rc=%d\n", rc); return rc; } @@ -2156,7 +2084,7 @@ static int qpnp_flash_led_probe(struct platform_device *pdev) rc = qpnp_flash_led_parse_each_led_dt(led, &led->fnode[i++], temp); if (rc < 0) { - dev_err(&pdev->dev, "Unable to parse flash node %d rc=%d\n", + pr_err("Unable to parse flash node %d rc=%d\n", i, rc); goto error_led_register; } @@ -2166,7 +2094,7 @@ static int qpnp_flash_led_probe(struct platform_device *pdev) rc = qpnp_flash_led_parse_and_register_switch(led, &led->snode[j++], temp); if (rc < 0) { - dev_err(&pdev->dev, "Unable to parse and register switch node, rc=%d\n", + pr_err("Unable to parse and register switch node, rc=%d\n", rc); goto error_switch_register; } @@ -2181,8 +2109,7 @@ static int qpnp_flash_led_probe(struct platform_device *pdev) IRQF_ONESHOT, "qpnp_flash_led_all_ramp_up_done_irq", led); if (rc < 0) { - dev_err(&pdev->dev, - "Unable to request all_ramp_up_done(%d) IRQ(err:%d)\n", + pr_err("Unable to request all_ramp_up_done(%d) IRQ(err:%d)\n", led->pdata->all_ramp_up_done_irq, rc); goto error_switch_register; } @@ -2195,8 +2122,7 @@ static int qpnp_flash_led_probe(struct platform_device *pdev) IRQF_ONESHOT, "qpnp_flash_led_all_ramp_down_done_irq", led); if (rc < 0) { - dev_err(&pdev->dev, - "Unable to request all_ramp_down_done(%d) IRQ(err:%d)\n", + pr_err("Unable to request all_ramp_down_done(%d) IRQ(err:%d)\n", led->pdata->all_ramp_down_done_irq, rc); goto error_switch_register; } @@ -2209,8 +2135,7 @@ static int qpnp_flash_led_probe(struct platform_device *pdev) IRQF_ONESHOT, "qpnp_flash_led_fault_irq", led); if (rc < 0) { - dev_err(&pdev->dev, - "Unable to request led_fault(%d) IRQ(err:%d)\n", + pr_err("Unable to request led_fault(%d) IRQ(err:%d)\n", led->pdata->led_fault_irq, rc); goto error_switch_register; } @@ -2220,16 +2145,14 @@ static int qpnp_flash_led_probe(struct platform_device *pdev) if (!led->bms_psy) { rc = flash_led_psy_register_notifier(led); if (rc < 0) { - dev_err(&pdev->dev, "Couldn't register psy notifier, rc = %d\n", - rc); + pr_err("Couldn't register psy notifier, rc = %d\n", rc); goto error_switch_register; } } rc = qpnp_flash_led_init_settings(led); if (rc < 0) { - dev_err(&pdev->dev, - "Failed to initialize flash LED, rc=%d\n", rc); + pr_err("Failed to initialize flash LED, rc=%d\n", rc); goto unreg_notifier; } @@ -2238,8 +2161,7 @@ static int qpnp_flash_led_probe(struct platform_device *pdev) rc = sysfs_create_file(&led->snode[i].cdev.dev->kobj, &qpnp_flash_led_attrs[j].attr); if (rc < 0) { - dev_err(&pdev->dev, "sysfs creation failed, rc=%d\n", - rc); + pr_err("sysfs creation failed, rc=%d\n", rc); goto sysfs_fail; } } -- cgit v1.2.3 From b154d78e5dcd30b9515001d5b135d1d5cee0b222 Mon Sep 17 00:00:00 2001 From: Anirudh Ghayal Date: Tue, 8 Nov 2016 16:46:35 +0530 Subject: leds: qpnp-flash: Fix the mask in the flash prepare API Use the correct LED_OPTIONS mask to enable all the supported flash prepare APIs. CRs-Fixed: 1090029 Change-Id: I66f6de42b106fa2027285e7393b6f9fc143d00d8 Signed-off-by: Anirudh Ghayal --- drivers/leds/leds-qpnp-flash.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/leds/leds-qpnp-flash.c b/drivers/leds/leds-qpnp-flash.c index 95b4c42a5adb..98dfa56add51 100644 --- a/drivers/leds/leds-qpnp-flash.c +++ b/drivers/leds/leds-qpnp-flash.c @@ -82,7 +82,6 @@ #define FLASH_LED_HDRM_SNS_ENABLE_MASK 0x81 #define FLASH_MASK_MODULE_CONTRL_MASK 0xE0 #define FLASH_FOLLOW_OTST2_RB_MASK 0x08 -#define FLASH_PREPARE_OPTIONS_MASK 0x08 #define FLASH_LED_TRIGGER_DEFAULT "none" #define FLASH_LED_HEADROOM_DEFAULT_MV 500 @@ -1172,7 +1171,7 @@ int qpnp_flash_led_prepare(struct led_trigger *trig, int options, flash_node = container_of(led_cdev, struct flash_node_data, cdev); led = dev_get_drvdata(&flash_node->pdev->dev); - if (!(options & FLASH_PREPARE_OPTIONS_MASK)) { + if (!(options & FLASH_LED_PREPARE_OPTIONS_MASK)) { dev_err(&led->pdev->dev, "Invalid options %d\n", options); return -EINVAL; } -- cgit v1.2.3 From 9931a7ca47f2e078459f89142fe8fd5ecd6524e7 Mon Sep 17 00:00:00 2001 From: Asutosh Das Date: Mon, 14 Nov 2016 14:56:43 +0530 Subject: ARM: dts: msm: Add ufs regulators for msmfalcon interposer Add device tree support for msmcobalt interposer platform for regulators of UFS. Change-Id: I78d2c27743d30b90a96e3d8df60859f67db7ddb8 Signed-off-by: Asutosh Das --- .../dts/qcom/msmcobalt-interposer-msmfalcon-cdp.dtsi | 16 +++++++--------- .../dts/qcom/msmcobalt-interposer-msmfalcon-mtp.dtsi | 16 +++++++--------- .../arm/boot/dts/qcom/msmcobalt-interposer-pmfalcon.dtsi | 12 ------------ 3 files changed, 14 insertions(+), 30 deletions(-) diff --git a/arch/arm/boot/dts/qcom/msmcobalt-interposer-msmfalcon-cdp.dtsi b/arch/arm/boot/dts/qcom/msmcobalt-interposer-msmfalcon-cdp.dtsi index 4822823aa63f..6336726e6b88 100644 --- a/arch/arm/boot/dts/qcom/msmcobalt-interposer-msmfalcon-cdp.dtsi +++ b/arch/arm/boot/dts/qcom/msmcobalt-interposer-msmfalcon-cdp.dtsi @@ -44,9 +44,9 @@ }; &ufsphy1 { - vdda-phy-supply = <&pmcobalt_l1>; - vdda-pll-supply = <&pmcobalt_l2>; - vddp-ref-clk-supply = <&pmcobalt_l26>; + vdda-phy-supply = <&pm2falcon_l1>; + vdda-pll-supply = <&pmfalcon_l1>; + vddp-ref-clk-supply = <&pmfalcon_l1>; vdda-phy-max-microamp = <51400>; vdda-pll-max-microamp = <14600>; vddp-ref-clk-max-microamp = <100>; @@ -57,12 +57,10 @@ &ufs1 { vdd-hba-supply = <&gdsc_ufs>; vdd-hba-fixed-regulator; - vcc-supply = <&pmcobalt_l20>; - vccq-supply = <&pmcobalt_l26>; - vccq2-supply = <&pmcobalt_s4>; - vcc-max-microamp = <750000>; - vccq-max-microamp = <560000>; - vccq2-max-microamp = <750000>; + vcc-supply = <&pm2falcon_l4>; + vccq2-supply = <&pmfalcon_l8>; + vcc-max-microamp = <500000>; + vccq2-max-microamp = <600000>; status = "ok"; }; diff --git a/arch/arm/boot/dts/qcom/msmcobalt-interposer-msmfalcon-mtp.dtsi b/arch/arm/boot/dts/qcom/msmcobalt-interposer-msmfalcon-mtp.dtsi index b77bab712ecf..07e1d665bb0c 100644 --- a/arch/arm/boot/dts/qcom/msmcobalt-interposer-msmfalcon-mtp.dtsi +++ b/arch/arm/boot/dts/qcom/msmcobalt-interposer-msmfalcon-mtp.dtsi @@ -45,9 +45,9 @@ }; &ufsphy1 { - vdda-phy-supply = <&pmcobalt_l1>; - vdda-pll-supply = <&pmcobalt_l2>; - vddp-ref-clk-supply = <&pmcobalt_l26>; + vdda-phy-supply = <&pm2falcon_l1>; + vdda-pll-supply = <&pmfalcon_l1>; + vddp-ref-clk-supply = <&pmfalcon_l1>; vdda-phy-max-microamp = <51400>; vdda-pll-max-microamp = <14600>; vddp-ref-clk-max-microamp = <100>; @@ -58,12 +58,10 @@ &ufs1 { vdd-hba-supply = <&gdsc_ufs>; vdd-hba-fixed-regulator; - vcc-supply = <&pmcobalt_l20>; - vccq-supply = <&pmcobalt_l26>; - vccq2-supply = <&pmcobalt_s4>; - vcc-max-microamp = <750000>; - vccq-max-microamp = <560000>; - vccq2-max-microamp = <750000>; + vcc-supply = <&pm2falcon_l4>; + vccq2-supply = <&pmfalcon_l8>; + vcc-max-microamp = <500000>; + vccq2-max-microamp = <600000>; status = "ok"; }; diff --git a/arch/arm/boot/dts/qcom/msmcobalt-interposer-pmfalcon.dtsi b/arch/arm/boot/dts/qcom/msmcobalt-interposer-pmfalcon.dtsi index 274281f7c982..ecb30fcc7383 100644 --- a/arch/arm/boot/dts/qcom/msmcobalt-interposer-pmfalcon.dtsi +++ b/arch/arm/boot/dts/qcom/msmcobalt-interposer-pmfalcon.dtsi @@ -81,18 +81,6 @@ /delete-property/qca,bt-chip-pwd-supply; }; -&ufsphy1 { - /delete-property/vdda-phy-supply; - /delete-property/vdda-pll-supply; - /delete-property/vddp-ref-clk-supply; -}; - -&ufs1 { - /delete-property/vcc-supply; - /delete-property/vccq-supply; - /delete-property/vccq2-supply; -}; - &sdhc_2 { /delete-property/vdd-supply; /delete-property/vdd-io-supply; -- cgit v1.2.3 From ef48989c4723145414f5221f0294b4f1615acb2a Mon Sep 17 00:00:00 2001 From: Tony Truong Date: Tue, 4 Oct 2016 13:37:25 -0700 Subject: ARM: dts: msm: enable QGIC MSI for PCIe on msmcobalt Add all SPIs for MSI, the base address, and the base SPI to PCIe node to support and enable QGIC MSI on msmcobalt. Change-Id: I1e74f1b03c3e15880efdac7ff07aca2f628de99d Signed-off-by: Tony Truong --- arch/arm/boot/dts/qcom/msmcobalt.dtsi | 51 ++++++++++++++++++++++++++++++++--- 1 file changed, 48 insertions(+), 3 deletions(-) diff --git a/arch/arm/boot/dts/qcom/msmcobalt.dtsi b/arch/arm/boot/dts/qcom/msmcobalt.dtsi index b3cbe5596007..d390bf20969d 100644 --- a/arch/arm/boot/dts/qcom/msmcobalt.dtsi +++ b/arch/arm/boot/dts/qcom/msmcobalt.dtsi @@ -1461,7 +1461,9 @@ ranges = <0x01000000 0x0 0x1b200000 0x1b200000 0x0 0x100000>, <0x02000000 0x0 0x1b300000 0x1b300000 0x0 0xd00000>; interrupt-parent = <&pcie0>; - interrupts = <0 1 2 3 4 5>; + interrupts = <0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 + 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 + 36 37>; #interrupt-cells = <1>; interrupt-map-mask = <0 0 0 0xffffffff>; interrupt-map = <0 0 0 0 &intc 0 0 405 0 @@ -1469,10 +1471,50 @@ 0 0 0 2 &intc 0 0 136 0 0 0 0 3 &intc 0 0 138 0 0 0 0 4 &intc 0 0 139 0 - 0 0 0 5 &intc 0 0 278 0>; + 0 0 0 5 &intc 0 0 278 0 + 0 0 0 6 &intc 0 0 576 0 + 0 0 0 7 &intc 0 0 577 0 + 0 0 0 8 &intc 0 0 578 0 + 0 0 0 9 &intc 0 0 579 0 + 0 0 0 10 &intc 0 0 580 0 + 0 0 0 11 &intc 0 0 581 0 + 0 0 0 12 &intc 0 0 582 0 + 0 0 0 13 &intc 0 0 583 0 + 0 0 0 14 &intc 0 0 584 0 + 0 0 0 15 &intc 0 0 585 0 + 0 0 0 16 &intc 0 0 586 0 + 0 0 0 17 &intc 0 0 587 0 + 0 0 0 18 &intc 0 0 588 0 + 0 0 0 19 &intc 0 0 589 0 + 0 0 0 20 &intc 0 0 590 0 + 0 0 0 21 &intc 0 0 591 0 + 0 0 0 22 &intc 0 0 592 0 + 0 0 0 23 &intc 0 0 593 0 + 0 0 0 24 &intc 0 0 594 0 + 0 0 0 25 &intc 0 0 595 0 + 0 0 0 26 &intc 0 0 596 0 + 0 0 0 27 &intc 0 0 597 0 + 0 0 0 28 &intc 0 0 598 0 + 0 0 0 29 &intc 0 0 599 0 + 0 0 0 30 &intc 0 0 600 0 + 0 0 0 31 &intc 0 0 601 0 + 0 0 0 32 &intc 0 0 602 0 + 0 0 0 33 &intc 0 0 603 0 + 0 0 0 34 &intc 0 0 604 0 + 0 0 0 35 &intc 0 0 605 0 + 0 0 0 36 &intc 0 0 606 0 + 0 0 0 37 &intc 0 0 607 0>; interrupt-names = "int_msi", "int_a", "int_b", "int_c", - "int_d", "int_global_int"; + "int_d", "int_global_int", + "msi_0", "msi_1", "msi_2", "msi_3", + "msi_4", "msi_5", "msi_6", "msi_7", + "msi_8", "msi_9", "msi_10", "msi_11", + "msi_12", "msi_13", "msi_14", "msi_15", + "msi_16", "msi_17", "msi_18", "msi_19", + "msi_20", "msi_21", "msi_22", "msi_23", + "msi_24", "msi_25", "msi_26", "msi_27", + "msi_28", "msi_29", "msi_30", "msi_31"; qcom,phy-sequence = <0x804 0x01 0x00 0x034 0x14 0x00 @@ -1578,6 +1620,9 @@ linux,pci-domain = <0>; + qcom,msi-gicm-addr = <0x17a00040>; + qcom,msi-gicm-base = <0x260>; + qcom,pcie-phy-ver = <0x20>; qcom,use-19p2mhz-aux-clk; -- cgit v1.2.3 From f7f2185840504e3e87e09001f26ad456cf09cf11 Mon Sep 17 00:00:00 2001 From: Tony Truong Date: Thu, 10 Nov 2016 17:21:13 -0800 Subject: ARM: dts: msm: ensure contiguous MSI for PCIe on msmcobalt PCIe MSI have to be contiguous by spec. Relocated PCIe node so that it receives contiguous MSIs from GIC driver. Change-Id: Ia73ab1ba51df7b501d246bb45141018409496d01 Signed-off-by: Tony Truong --- arch/arm/boot/dts/qcom/msmcobalt.dtsi | 446 +++++++++++++++++----------------- 1 file changed, 223 insertions(+), 223 deletions(-) diff --git a/arch/arm/boot/dts/qcom/msmcobalt.dtsi b/arch/arm/boot/dts/qcom/msmcobalt.dtsi index d390bf20969d..783ecdb8800c 100644 --- a/arch/arm/boot/dts/qcom/msmcobalt.dtsi +++ b/arch/arm/boot/dts/qcom/msmcobalt.dtsi @@ -1441,229 +1441,6 @@ }; }; - pcie0: qcom,pcie@01c00000 { - compatible = "qcom,pci-msm"; - cell-index = <0>; - - reg = <0x1c00000 0x2000>, - <0x1c06000 0x1000>, - <0x1b000000 0xf1d>, - <0x1b000f20 0xa8>, - <0x1b100000 0x100000>, - <0x1b200000 0x100000>, - <0x1b300000 0xd00000>; - - reg-names = "parf", "phy", "dm_core", "elbi", - "conf", "io", "bars"; - - #address-cells = <3>; - #size-cells = <2>; - ranges = <0x01000000 0x0 0x1b200000 0x1b200000 0x0 0x100000>, - <0x02000000 0x0 0x1b300000 0x1b300000 0x0 0xd00000>; - interrupt-parent = <&pcie0>; - interrupts = <0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 - 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 - 36 37>; - #interrupt-cells = <1>; - interrupt-map-mask = <0 0 0 0xffffffff>; - interrupt-map = <0 0 0 0 &intc 0 0 405 0 - 0 0 0 1 &intc 0 0 135 0 - 0 0 0 2 &intc 0 0 136 0 - 0 0 0 3 &intc 0 0 138 0 - 0 0 0 4 &intc 0 0 139 0 - 0 0 0 5 &intc 0 0 278 0 - 0 0 0 6 &intc 0 0 576 0 - 0 0 0 7 &intc 0 0 577 0 - 0 0 0 8 &intc 0 0 578 0 - 0 0 0 9 &intc 0 0 579 0 - 0 0 0 10 &intc 0 0 580 0 - 0 0 0 11 &intc 0 0 581 0 - 0 0 0 12 &intc 0 0 582 0 - 0 0 0 13 &intc 0 0 583 0 - 0 0 0 14 &intc 0 0 584 0 - 0 0 0 15 &intc 0 0 585 0 - 0 0 0 16 &intc 0 0 586 0 - 0 0 0 17 &intc 0 0 587 0 - 0 0 0 18 &intc 0 0 588 0 - 0 0 0 19 &intc 0 0 589 0 - 0 0 0 20 &intc 0 0 590 0 - 0 0 0 21 &intc 0 0 591 0 - 0 0 0 22 &intc 0 0 592 0 - 0 0 0 23 &intc 0 0 593 0 - 0 0 0 24 &intc 0 0 594 0 - 0 0 0 25 &intc 0 0 595 0 - 0 0 0 26 &intc 0 0 596 0 - 0 0 0 27 &intc 0 0 597 0 - 0 0 0 28 &intc 0 0 598 0 - 0 0 0 29 &intc 0 0 599 0 - 0 0 0 30 &intc 0 0 600 0 - 0 0 0 31 &intc 0 0 601 0 - 0 0 0 32 &intc 0 0 602 0 - 0 0 0 33 &intc 0 0 603 0 - 0 0 0 34 &intc 0 0 604 0 - 0 0 0 35 &intc 0 0 605 0 - 0 0 0 36 &intc 0 0 606 0 - 0 0 0 37 &intc 0 0 607 0>; - - interrupt-names = "int_msi", "int_a", "int_b", "int_c", - "int_d", "int_global_int", - "msi_0", "msi_1", "msi_2", "msi_3", - "msi_4", "msi_5", "msi_6", "msi_7", - "msi_8", "msi_9", "msi_10", "msi_11", - "msi_12", "msi_13", "msi_14", "msi_15", - "msi_16", "msi_17", "msi_18", "msi_19", - "msi_20", "msi_21", "msi_22", "msi_23", - "msi_24", "msi_25", "msi_26", "msi_27", - "msi_28", "msi_29", "msi_30", "msi_31"; - - qcom,phy-sequence = <0x804 0x01 0x00 - 0x034 0x14 0x00 - 0x138 0x30 0x00 - 0x048 0x0f 0x00 - 0x15c 0x06 0x00 - 0x090 0x01 0x00 - 0x088 0x20 0x00 - 0x0f0 0x00 0x00 - 0x0f8 0x01 0x00 - 0x0f4 0xc9 0x00 - 0x11c 0xff 0x00 - 0x120 0x3f 0x00 - 0x164 0x01 0x00 - 0x154 0x00 0x00 - 0x148 0x0a 0x00 - 0x05C 0x19 0x00 - 0x038 0x90 0x00 - 0x0b0 0x82 0x00 - 0x0c0 0x03 0x00 - 0x0bc 0x55 0x00 - 0x0b8 0x55 0x00 - 0x0a0 0x00 0x00 - 0x09c 0x0d 0x00 - 0x098 0x04 0x00 - 0x13c 0x00 0x00 - 0x060 0x08 0x00 - 0x068 0x16 0x00 - 0x070 0x34 0x00 - 0x15c 0x06 0x00 - 0x138 0x33 0x00 - 0x03c 0x02 0x00 - 0x040 0x0e 0x00 - 0x080 0x04 0x00 - 0x0dc 0x00 0x00 - 0x0d8 0x3f 0x00 - 0x00c 0x09 0x00 - 0x010 0x01 0x00 - 0x01c 0x40 0x00 - 0x020 0x01 0x00 - 0x014 0x02 0x00 - 0x018 0x00 0x00 - 0x024 0x7e 0x00 - 0x028 0x15 0x00 - 0x244 0x02 0x00 - 0x2a4 0x12 0x00 - 0x260 0x10 0x00 - 0x28c 0x06 0x00 - 0x504 0x03 0x00 - 0x500 0x1c 0x00 - 0x50c 0x14 0x00 - 0x4d4 0x0a 0x00 - 0x4d8 0x04 0x00 - 0x4dc 0x1a 0x00 - 0x434 0x4b 0x00 - 0x414 0x04 0x00 - 0x40c 0x04 0x00 - 0x4f8 0x00 0x00 - 0x4fc 0x80 0x00 - 0x51c 0x40 0x00 - 0x444 0x71 0x00 - 0x43c 0x40 0x00 - 0x854 0x04 0x00 - 0x62c 0x52 0x00 - 0x9ac 0x00 0x00 - 0x8a0 0x01 0x00 - 0x9e0 0x00 0x00 - 0x9dc 0x01 0x00 - 0x9a8 0x00 0x00 - 0x8a4 0x01 0x00 - 0x8a8 0x73 0x00 - 0x9d8 0x99 0x00 - 0x9b0 0x03 0x00 - 0x804 0x03 0x00 - 0x800 0x00 0x00 - 0x808 0x03 0x00>; - - pinctrl-names = "default"; - pinctrl-0 = <&pcie0_clkreq_default - &pcie0_perst_default - &pcie0_wake_default>; - - perst-gpio = <&tlmm 35 0>; - wake-gpio = <&tlmm 37 0>; - - gdsc-vdd-supply = <&gdsc_pcie_0>; - vreg-1.8-supply = <&pmcobalt_l2>; - vreg-0.9-supply = <&pmcobalt_l1>; - vreg-cx-supply = <&pmcobalt_s1_level>; - - qcom,vreg-1.8-voltage-level = <1200000 1200000 24000>; - qcom,vreg-0.9-voltage-level = <880000 880000 24000>; - qcom,vreg-cx-voltage-level = ; - - qcom,l1-supported; - qcom,l1ss-supported; - qcom,aux-clk-sync; - - qcom,ep-latency = <10>; - - qcom,ep-wakeirq; - - linux,pci-domain = <0>; - - qcom,msi-gicm-addr = <0x17a00040>; - qcom,msi-gicm-base = <0x260>; - - qcom,pcie-phy-ver = <0x20>; - qcom,use-19p2mhz-aux-clk; - - iommus = <&anoc1_smmu>; - qcom,smmu-exist; - qcom,smmu-sid-base = <0x1480>; - - qcom,msm-bus,name = "pcie0"; - qcom,msm-bus,num-cases = <2>; - qcom,msm-bus,num-paths = <1>; - qcom,msm-bus,vectors-KBps = - <45 512 0 0>, - <45 512 500 800>; - - clocks = <&clock_gcc clk_gcc_pcie_0_pipe_clk>, - <&clock_gcc clk_ln_bb_clk1>, - <&clock_gcc clk_gcc_pcie_0_aux_clk>, - <&clock_gcc clk_gcc_pcie_0_cfg_ahb_clk>, - <&clock_gcc clk_gcc_pcie_0_mstr_axi_clk>, - <&clock_gcc clk_gcc_pcie_0_slv_axi_clk>, - <&clock_gcc clk_gcc_pcie_clkref_clk>; - - clock-names = "pcie_0_pipe_clk", "pcie_0_ref_clk_src", - "pcie_0_aux_clk", "pcie_0_cfg_ahb_clk", - "pcie_0_mstr_axi_clk", "pcie_0_slv_axi_clk", - "pcie_0_ldo"; - - max-clock-frequency-hz = <0>, <0>, <19200000>, - <0>, <0>, <0>, <0>, <0>, <0>, - <0>, <0>, <0>, <0>, <0>, <0>, - <0>, <0>; - - resets = <&clock_gcc PCIE_PHY_BCR>, - <&clock_gcc PCIE_0_PHY_BCR>, - <&clock_gcc PCIE_0_PHY_BCR>; - - reset-names = "pcie_phy_reset", - "pcie_0_phy_reset", - "pcie_0_phy_pipe_reset"; - }; - qcom,ipc_router { compatible = "qcom,ipc_router"; qcom,node-id = <1>; @@ -2632,6 +2409,229 @@ }; }; + pcie0: qcom,pcie@01c00000 { + compatible = "qcom,pci-msm"; + cell-index = <0>; + + reg = <0x1c00000 0x2000>, + <0x1c06000 0x1000>, + <0x1b000000 0xf1d>, + <0x1b000f20 0xa8>, + <0x1b100000 0x100000>, + <0x1b200000 0x100000>, + <0x1b300000 0xd00000>; + + reg-names = "parf", "phy", "dm_core", "elbi", + "conf", "io", "bars"; + + #address-cells = <3>; + #size-cells = <2>; + ranges = <0x01000000 0x0 0x1b200000 0x1b200000 0x0 0x100000>, + <0x02000000 0x0 0x1b300000 0x1b300000 0x0 0xd00000>; + interrupt-parent = <&pcie0>; + interrupts = <0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 + 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 + 36 37>; + #interrupt-cells = <1>; + interrupt-map-mask = <0 0 0 0xffffffff>; + interrupt-map = <0 0 0 0 &intc 0 0 405 0 + 0 0 0 1 &intc 0 0 135 0 + 0 0 0 2 &intc 0 0 136 0 + 0 0 0 3 &intc 0 0 138 0 + 0 0 0 4 &intc 0 0 139 0 + 0 0 0 5 &intc 0 0 278 0 + 0 0 0 6 &intc 0 0 576 0 + 0 0 0 7 &intc 0 0 577 0 + 0 0 0 8 &intc 0 0 578 0 + 0 0 0 9 &intc 0 0 579 0 + 0 0 0 10 &intc 0 0 580 0 + 0 0 0 11 &intc 0 0 581 0 + 0 0 0 12 &intc 0 0 582 0 + 0 0 0 13 &intc 0 0 583 0 + 0 0 0 14 &intc 0 0 584 0 + 0 0 0 15 &intc 0 0 585 0 + 0 0 0 16 &intc 0 0 586 0 + 0 0 0 17 &intc 0 0 587 0 + 0 0 0 18 &intc 0 0 588 0 + 0 0 0 19 &intc 0 0 589 0 + 0 0 0 20 &intc 0 0 590 0 + 0 0 0 21 &intc 0 0 591 0 + 0 0 0 22 &intc 0 0 592 0 + 0 0 0 23 &intc 0 0 593 0 + 0 0 0 24 &intc 0 0 594 0 + 0 0 0 25 &intc 0 0 595 0 + 0 0 0 26 &intc 0 0 596 0 + 0 0 0 27 &intc 0 0 597 0 + 0 0 0 28 &intc 0 0 598 0 + 0 0 0 29 &intc 0 0 599 0 + 0 0 0 30 &intc 0 0 600 0 + 0 0 0 31 &intc 0 0 601 0 + 0 0 0 32 &intc 0 0 602 0 + 0 0 0 33 &intc 0 0 603 0 + 0 0 0 34 &intc 0 0 604 0 + 0 0 0 35 &intc 0 0 605 0 + 0 0 0 36 &intc 0 0 606 0 + 0 0 0 37 &intc 0 0 607 0>; + + interrupt-names = "int_msi", "int_a", "int_b", "int_c", + "int_d", "int_global_int", + "msi_0", "msi_1", "msi_2", "msi_3", + "msi_4", "msi_5", "msi_6", "msi_7", + "msi_8", "msi_9", "msi_10", "msi_11", + "msi_12", "msi_13", "msi_14", "msi_15", + "msi_16", "msi_17", "msi_18", "msi_19", + "msi_20", "msi_21", "msi_22", "msi_23", + "msi_24", "msi_25", "msi_26", "msi_27", + "msi_28", "msi_29", "msi_30", "msi_31"; + + qcom,phy-sequence = <0x804 0x01 0x00 + 0x034 0x14 0x00 + 0x138 0x30 0x00 + 0x048 0x0f 0x00 + 0x15c 0x06 0x00 + 0x090 0x01 0x00 + 0x088 0x20 0x00 + 0x0f0 0x00 0x00 + 0x0f8 0x01 0x00 + 0x0f4 0xc9 0x00 + 0x11c 0xff 0x00 + 0x120 0x3f 0x00 + 0x164 0x01 0x00 + 0x154 0x00 0x00 + 0x148 0x0a 0x00 + 0x05C 0x19 0x00 + 0x038 0x90 0x00 + 0x0b0 0x82 0x00 + 0x0c0 0x03 0x00 + 0x0bc 0x55 0x00 + 0x0b8 0x55 0x00 + 0x0a0 0x00 0x00 + 0x09c 0x0d 0x00 + 0x098 0x04 0x00 + 0x13c 0x00 0x00 + 0x060 0x08 0x00 + 0x068 0x16 0x00 + 0x070 0x34 0x00 + 0x15c 0x06 0x00 + 0x138 0x33 0x00 + 0x03c 0x02 0x00 + 0x040 0x0e 0x00 + 0x080 0x04 0x00 + 0x0dc 0x00 0x00 + 0x0d8 0x3f 0x00 + 0x00c 0x09 0x00 + 0x010 0x01 0x00 + 0x01c 0x40 0x00 + 0x020 0x01 0x00 + 0x014 0x02 0x00 + 0x018 0x00 0x00 + 0x024 0x7e 0x00 + 0x028 0x15 0x00 + 0x244 0x02 0x00 + 0x2a4 0x12 0x00 + 0x260 0x10 0x00 + 0x28c 0x06 0x00 + 0x504 0x03 0x00 + 0x500 0x1c 0x00 + 0x50c 0x14 0x00 + 0x4d4 0x0a 0x00 + 0x4d8 0x04 0x00 + 0x4dc 0x1a 0x00 + 0x434 0x4b 0x00 + 0x414 0x04 0x00 + 0x40c 0x04 0x00 + 0x4f8 0x00 0x00 + 0x4fc 0x80 0x00 + 0x51c 0x40 0x00 + 0x444 0x71 0x00 + 0x43c 0x40 0x00 + 0x854 0x04 0x00 + 0x62c 0x52 0x00 + 0x9ac 0x00 0x00 + 0x8a0 0x01 0x00 + 0x9e0 0x00 0x00 + 0x9dc 0x01 0x00 + 0x9a8 0x00 0x00 + 0x8a4 0x01 0x00 + 0x8a8 0x73 0x00 + 0x9d8 0x99 0x00 + 0x9b0 0x03 0x00 + 0x804 0x03 0x00 + 0x800 0x00 0x00 + 0x808 0x03 0x00>; + + pinctrl-names = "default"; + pinctrl-0 = <&pcie0_clkreq_default + &pcie0_perst_default + &pcie0_wake_default>; + + perst-gpio = <&tlmm 35 0>; + wake-gpio = <&tlmm 37 0>; + + gdsc-vdd-supply = <&gdsc_pcie_0>; + vreg-1.8-supply = <&pmcobalt_l2>; + vreg-0.9-supply = <&pmcobalt_l1>; + vreg-cx-supply = <&pmcobalt_s1_level>; + + qcom,vreg-1.8-voltage-level = <1200000 1200000 24000>; + qcom,vreg-0.9-voltage-level = <880000 880000 24000>; + qcom,vreg-cx-voltage-level = ; + + qcom,l1-supported; + qcom,l1ss-supported; + qcom,aux-clk-sync; + + qcom,ep-latency = <10>; + + qcom,ep-wakeirq; + + linux,pci-domain = <0>; + + qcom,msi-gicm-addr = <0x17a00040>; + qcom,msi-gicm-base = <0x260>; + + qcom,pcie-phy-ver = <0x20>; + qcom,use-19p2mhz-aux-clk; + + iommus = <&anoc1_smmu>; + qcom,smmu-exist; + qcom,smmu-sid-base = <0x1480>; + + qcom,msm-bus,name = "pcie0"; + qcom,msm-bus,num-cases = <2>; + qcom,msm-bus,num-paths = <1>; + qcom,msm-bus,vectors-KBps = + <45 512 0 0>, + <45 512 500 800>; + + clocks = <&clock_gcc clk_gcc_pcie_0_pipe_clk>, + <&clock_gcc clk_ln_bb_clk1>, + <&clock_gcc clk_gcc_pcie_0_aux_clk>, + <&clock_gcc clk_gcc_pcie_0_cfg_ahb_clk>, + <&clock_gcc clk_gcc_pcie_0_mstr_axi_clk>, + <&clock_gcc clk_gcc_pcie_0_slv_axi_clk>, + <&clock_gcc clk_gcc_pcie_clkref_clk>; + + clock-names = "pcie_0_pipe_clk", "pcie_0_ref_clk_src", + "pcie_0_aux_clk", "pcie_0_cfg_ahb_clk", + "pcie_0_mstr_axi_clk", "pcie_0_slv_axi_clk", + "pcie_0_ldo"; + + max-clock-frequency-hz = <0>, <0>, <19200000>, + <0>, <0>, <0>, <0>, <0>, <0>, + <0>, <0>, <0>, <0>, <0>, <0>, + <0>, <0>; + + resets = <&clock_gcc PCIE_PHY_BCR>, + <&clock_gcc PCIE_0_PHY_BCR>, + <&clock_gcc PCIE_0_PHY_BCR>; + + reset-names = "pcie_phy_reset", + "pcie_0_phy_reset", + "pcie_0_phy_pipe_reset"; + }; + qcom,bcl { compatible = "qcom,bcl"; qcom,bcl-enable; -- cgit v1.2.3 From 16517bb150fee5e315597de4ebfb3588c60b9afb Mon Sep 17 00:00:00 2001 From: Patrick Daly Date: Wed, 2 Nov 2016 18:50:14 -0700 Subject: ARM: dts: msm: Correct interrupt assignments for msmcobalt Some smmu context banks are reserved for use by secure software. Do not attempt to use the interrupts associated with those context banks. Change-Id: I92e98ab46107fbcfd843898423b41716a204c2ae Signed-off-by: Patrick Daly --- arch/arm/boot/dts/qcom/msm-arm-smmu-cobalt.dtsi | 65 ++++++------------------- 1 file changed, 16 insertions(+), 49 deletions(-) diff --git a/arch/arm/boot/dts/qcom/msm-arm-smmu-cobalt.dtsi b/arch/arm/boot/dts/qcom/msm-arm-smmu-cobalt.dtsi index 3de3cd5f8de9..1ad8f99e4186 100644 --- a/arch/arm/boot/dts/qcom/msm-arm-smmu-cobalt.dtsi +++ b/arch/arm/boot/dts/qcom/msm-arm-smmu-cobalt.dtsi @@ -22,17 +22,13 @@ #iommu-cells = <0>; qcom,register-save; qcom,skip-init; - #global-interrupts = <2>; - interrupts = , - , - , + #global-interrupts = <0>; + interrupts = , , , , , - , - , - ; + ; clocks = <&clock_gcc clk_aggre1_noc_clk>; clock-names = "smmu_aggre1_noc_clk"; #clock-cells = <1>; @@ -45,10 +41,8 @@ #iommu-cells = <1>; qcom,register-save; qcom,skip-init; - #global-interrupts = <2>; - interrupts = , - , - , + #global-interrupts = <0>; + interrupts = , , , , @@ -57,17 +51,7 @@ , , , - , - , - , - , - , - , - , - , - , - , - ; + ; clocks = <&clock_gcc clk_aggre2_noc_clk>; clock-names = "smmu_aggre2_noc_clk"; #clock-cells = <1>; @@ -81,10 +65,8 @@ qcom,tz-device-id = "LPASS"; qcom,register-save; qcom,skip-init; - #global-interrupts = <2>; - interrupts = , - , - , + #global-interrupts = <0>; + interrupts = , , , , @@ -96,11 +78,7 @@ , , , - , - , - , - , - ; + ; vdd-supply = <&gdsc_hlos1_vote_lpass_adsp>; clocks = <&clock_gcc clk_hlos1_vote_lpass_adsp_smmu_clk>; clock-names = "lpass_q6_smmu_clk"; @@ -115,10 +93,8 @@ qcom,register-save; qcom,no-smr-check; qcom,skip-init; - #global-interrupts = <2>; - interrupts = , - , - , + #global-interrupts = <0>; + interrupts = , , , , @@ -137,11 +113,7 @@ , , , - , - , - , - , - ; + ; vdd-supply = <&gdsc_bimc_smmu>; clocks = <&clock_mmss clk_mmss_mnoc_ahb_clk>, <&clock_gcc clk_mmssnoc_axi_clk>, @@ -164,15 +136,10 @@ qcom,dynamic; qcom,register-save; qcom,skip-init; - #global-interrupts = <2>; - interrupts = , - , - , - , - , - , - , - ; + #global-interrupts = <0>; + interrupts = , + , + ; vdd-supply = <&gdsc_gpu_cx>; clocks = <&clock_gcc clk_gcc_gpu_cfg_ahb_clk>, <&clock_gcc clk_gcc_bimc_gfx_clk>, -- cgit v1.2.3 From bddd67fc5c5f01d4cc88fe4d27c8b442f35461dd Mon Sep 17 00:00:00 2001 From: Sreelakshmi Gownipalli Date: Thu, 10 Nov 2016 16:29:43 -0800 Subject: diag: Set the diag write buffers to busy state on channel close Set the diag forward write buffers to busy state when glink diag channel receives remote disconnected event. Change-Id: I3c9422f3a790c0c1633ab64d4213a088faaeb9e5 Signed-off-by: Sreelakshmi Gownipalli --- drivers/char/diag/diagfwd_glink.c | 3 +++ drivers/char/diag/diagfwd_peripheral.c | 37 +++++++++++++++++++++++----------- drivers/char/diag/diagfwd_peripheral.h | 1 + 3 files changed, 29 insertions(+), 12 deletions(-) diff --git a/drivers/char/diag/diagfwd_glink.c b/drivers/char/diag/diagfwd_glink.c index a2ffabe43c86..ce523ac35a51 100644 --- a/drivers/char/diag/diagfwd_glink.c +++ b/drivers/char/diag/diagfwd_glink.c @@ -455,6 +455,8 @@ static void diag_glink_transport_notify_state(void *handle, const void *priv, "%s received channel remote disconnect for periph:%d\n", glink_info->name, glink_info->peripheral); atomic_set(&glink_info->opened, 0); + diagfwd_channel_close(glink_info->fwd_ctxt); + atomic_set(&glink_info->tx_intent_ready, 0); break; default: DIAG_LOG(DIAG_DEBUG_PERIPHERALS, @@ -501,6 +503,7 @@ static void diag_glink_close_work_fn(struct work_struct *work) glink_close(glink_info->hdl); atomic_set(&glink_info->opened, 0); + atomic_set(&glink_info->tx_intent_ready, 0); glink_info->hdl = NULL; diagfwd_channel_close(glink_info->fwd_ctxt); } diff --git a/drivers/char/diag/diagfwd_peripheral.c b/drivers/char/diag/diagfwd_peripheral.c index 40fdcbaaf31a..c78a5f4fbe74 100644 --- a/drivers/char/diag/diagfwd_peripheral.c +++ b/drivers/char/diag/diagfwd_peripheral.c @@ -438,6 +438,7 @@ int diagfwd_peripheral_init(void) fwd_info->read_bytes = 0; fwd_info->write_bytes = 0; spin_lock_init(&fwd_info->buf_lock); + spin_lock_init(&fwd_info->write_buf_lock); mutex_init(&fwd_info->data_mutex); } } @@ -453,6 +454,7 @@ int diagfwd_peripheral_init(void) fwd_info->read_bytes = 0; fwd_info->write_bytes = 0; spin_lock_init(&fwd_info->buf_lock); + spin_lock_init(&fwd_info->write_buf_lock); mutex_init(&fwd_info->data_mutex); /* * This state shouldn't be set for Control channels @@ -686,16 +688,19 @@ void *diagfwd_request_write_buf(struct diagfwd_info *fwd_info) { void *buf = NULL; int index; + unsigned long flags; + spin_lock_irqsave(&fwd_info->write_buf_lock, flags); for (index = 0 ; index < NUM_WRITE_BUFFERS; index++) { if (!atomic_read(&(fwd_info->buf_ptr[index]->in_busy))) { + atomic_set(&(fwd_info->buf_ptr[index]->in_busy), 1); buf = fwd_info->buf_ptr[index]->data; if (!buf) return NULL; - atomic_set(&(fwd_info->buf_ptr[index]->in_busy), 1); break; } } + spin_unlock_irqrestore(&fwd_info->write_buf_lock, flags); return buf; } @@ -760,7 +765,6 @@ int diagfwd_write(uint8_t peripheral, uint8_t type, void *buf, int len) static void __diag_fwd_open(struct diagfwd_info *fwd_info) { - int i; if (!fwd_info) return; @@ -775,10 +779,7 @@ static void __diag_fwd_open(struct diagfwd_info *fwd_info) if (fwd_info->p_ops && fwd_info->p_ops->open) fwd_info->p_ops->open(fwd_info->ctxt); - for (i = 0; i < NUM_WRITE_BUFFERS; i++) { - if (fwd_info->buf_ptr[i]) - atomic_set(&fwd_info->buf_ptr[i]->in_busy, 0); - } + diagfwd_queue_read(fwd_info); } @@ -839,6 +840,7 @@ void diagfwd_close(uint8_t peripheral, uint8_t type) int diagfwd_channel_open(struct diagfwd_info *fwd_info) { + int i; if (!fwd_info) return -EIO; @@ -859,6 +861,10 @@ int diagfwd_channel_open(struct diagfwd_info *fwd_info) diagfwd_write_buffers_init(fwd_info); if (fwd_info && fwd_info->c_ops && fwd_info->c_ops->open) fwd_info->c_ops->open(fwd_info); + for (i = 0; i < NUM_WRITE_BUFFERS; i++) { + if (fwd_info->buf_ptr[i]) + atomic_set(&fwd_info->buf_ptr[i]->in_busy, 0); + } diagfwd_queue_read(fwd_info); DIAG_LOG(DIAG_DEBUG_PERIPHERALS, "p: %d t: %d considered opened\n", fwd_info->peripheral, fwd_info->type); @@ -873,6 +879,7 @@ int diagfwd_channel_open(struct diagfwd_info *fwd_info) int diagfwd_channel_close(struct diagfwd_info *fwd_info) { + int i; if (!fwd_info) return -EIO; @@ -885,6 +892,10 @@ int diagfwd_channel_close(struct diagfwd_info *fwd_info) if (fwd_info->buf_2 && fwd_info->buf_2->data) atomic_set(&fwd_info->buf_2->in_busy, 0); + for (i = 0; i < NUM_WRITE_BUFFERS; i++) { + if (fwd_info->buf_ptr[i]) + atomic_set(&fwd_info->buf_ptr[i]->in_busy, 1); + } DIAG_LOG(DIAG_DEBUG_PERIPHERALS, "p: %d t: %d considered closed\n", fwd_info->peripheral, fwd_info->type); @@ -940,10 +951,11 @@ int diagfwd_write_buffer_done(struct diagfwd_info *fwd_info, const void *ptr) int found = 0; int index = 0; + unsigned long flags; if (!fwd_info || !ptr) return found; - + spin_lock_irqsave(&fwd_info->write_buf_lock, flags); for (index = 0; index < NUM_WRITE_BUFFERS; index++) { if (fwd_info->buf_ptr[index]->data == ptr) { atomic_set(&fwd_info->buf_ptr[index]->in_busy, 0); @@ -951,6 +963,7 @@ int diagfwd_write_buffer_done(struct diagfwd_info *fwd_info, const void *ptr) break; } } + spin_unlock_irqrestore(&fwd_info->write_buf_lock, flags); return found; } @@ -1197,7 +1210,7 @@ void diagfwd_write_buffers_init(struct diagfwd_info *fwd_info) return; } - spin_lock_irqsave(&fwd_info->buf_lock, flags); + spin_lock_irqsave(&fwd_info->write_buf_lock, flags); for (i = 0; i < NUM_WRITE_BUFFERS; i++) { if (!fwd_info->buf_ptr[i]) fwd_info->buf_ptr[i] = @@ -1215,11 +1228,11 @@ void diagfwd_write_buffers_init(struct diagfwd_info *fwd_info) kmemleak_not_leak(fwd_info->buf_ptr[i]->data); } } - spin_unlock_irqrestore(&fwd_info->buf_lock, flags); + spin_unlock_irqrestore(&fwd_info->write_buf_lock, flags); return; err: - spin_unlock_irqrestore(&fwd_info->buf_lock, flags); + spin_unlock_irqrestore(&fwd_info->write_buf_lock, flags); pr_err("diag:unable to allocate write buffers\n"); diagfwd_write_buffers_exit(fwd_info); @@ -1233,7 +1246,7 @@ static void diagfwd_write_buffers_exit(struct diagfwd_info *fwd_info) if (!fwd_info) return; - spin_lock_irqsave(&fwd_info->buf_lock, flags); + spin_lock_irqsave(&fwd_info->write_buf_lock, flags); for (i = 0; i < NUM_WRITE_BUFFERS; i++) { if (fwd_info->buf_ptr[i]) { kfree(fwd_info->buf_ptr[i]->data); @@ -1242,5 +1255,5 @@ static void diagfwd_write_buffers_exit(struct diagfwd_info *fwd_info) fwd_info->buf_ptr[i] = NULL; } } - spin_unlock_irqrestore(&fwd_info->buf_lock, flags); + spin_unlock_irqrestore(&fwd_info->write_buf_lock, flags); } diff --git a/drivers/char/diag/diagfwd_peripheral.h b/drivers/char/diag/diagfwd_peripheral.h index b511bf495bc2..cbbab86a9425 100644 --- a/drivers/char/diag/diagfwd_peripheral.h +++ b/drivers/char/diag/diagfwd_peripheral.h @@ -71,6 +71,7 @@ struct diagfwd_info { unsigned long read_bytes; unsigned long write_bytes; spinlock_t buf_lock; + spinlock_t write_buf_lock; struct mutex data_mutex; void *ctxt; struct diagfwd_buf_t *buf_1; -- cgit v1.2.3 From f36f22a49d4d32ae12a6557ab1a630f5a74da857 Mon Sep 17 00:00:00 2001 From: Willem de Bruijn Date: Tue, 15 Nov 2016 14:43:27 -0700 Subject: rose: limit sk_filter trim to payload Sockets can have a filter program attached that drops or trims incoming packets based on the filter program return value. Rose requires data packets to have at least ROSE_MIN_LEN bytes. It verifies this on arrival in rose_route_frame and unconditionally pulls the bytes in rose_recvmsg. The filter can trim packets to below this value in-between, causing pull to fail, leaving the partial header at the time of skb_copy_datagram_msg. Place a lower bound on the size to which sk_filter may trim packets by introducing sk_filter_trim_cap and call this for rose packets. CRs-Fixed: 1089895 Change-Id: Idc52737bc96097a9220dfe47bb76e94ff1026a05 Signed-off-by: Willem de Bruijn Acked-by: Daniel Borkmann Signed-off-by: David S. Miller Git-commit: f4979fcea7fd36d8e2f556abef86f80e0d5af1ba Git-repo: git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git [subashab@codeaurora.org: resolve trivial merge conflicts] Signed-off-by: Subash Abhinov Kasiviswanathan --- include/linux/filter.h | 6 +++++- net/core/filter.c | 9 +++++---- net/rose/rose_in.c | 3 ++- 3 files changed, 12 insertions(+), 6 deletions(-) diff --git a/include/linux/filter.h b/include/linux/filter.h index 5110d4211866..ccb98b459c59 100644 --- a/include/linux/filter.h +++ b/include/linux/filter.h @@ -421,7 +421,11 @@ static inline void bpf_prog_unlock_ro(struct bpf_prog *fp) } #endif /* CONFIG_DEBUG_SET_MODULE_RONX */ -int sk_filter(struct sock *sk, struct sk_buff *skb); +int sk_filter_trim_cap(struct sock *sk, struct sk_buff *skb, unsigned int cap); +static inline int sk_filter(struct sock *sk, struct sk_buff *skb) +{ + return sk_filter_trim_cap(sk, skb, 1); +} int bpf_prog_select_runtime(struct bpf_prog *fp); void bpf_prog_free(struct bpf_prog *fp); diff --git a/net/core/filter.c b/net/core/filter.c index 75e9b2b2336d..eedb05468fcb 100644 --- a/net/core/filter.c +++ b/net/core/filter.c @@ -52,9 +52,10 @@ #include /** - * sk_filter - run a packet through a socket filter + * sk_filter_trim_cap - run a packet through a socket filter * @sk: sock associated with &sk_buff * @skb: buffer to filter + * @cap: limit on how short the eBPF program may trim the packet * * Run the eBPF program and then cut skb->data to correct size returned by * the program. If pkt_len is 0 we toss packet. If skb->len is smaller @@ -63,7 +64,7 @@ * be accepted or -EPERM if the packet should be tossed. * */ -int sk_filter(struct sock *sk, struct sk_buff *skb) +int sk_filter_trim_cap(struct sock *sk, struct sk_buff *skb, unsigned int cap) { int err; struct sk_filter *filter; @@ -85,13 +86,13 @@ int sk_filter(struct sock *sk, struct sk_buff *skb) if (filter) { unsigned int pkt_len = bpf_prog_run_save_cb(filter->prog, skb); - err = pkt_len ? pskb_trim(skb, pkt_len) : -EPERM; + err = pkt_len ? pskb_trim(skb, max(cap, pkt_len)) : -EPERM; } rcu_read_unlock(); return err; } -EXPORT_SYMBOL(sk_filter); +EXPORT_SYMBOL(sk_filter_trim_cap); static u64 __skb_get_pay_offset(u64 ctx, u64 a, u64 x, u64 r4, u64 r5) { diff --git a/net/rose/rose_in.c b/net/rose/rose_in.c index 79c4abcfa6b4..fb31d2ea5a81 100644 --- a/net/rose/rose_in.c +++ b/net/rose/rose_in.c @@ -164,7 +164,8 @@ static int rose_state3_machine(struct sock *sk, struct sk_buff *skb, int framety rose_frames_acked(sk, nr); if (ns == rose->vr) { rose_start_idletimer(sk); - if (sock_queue_rcv_skb(sk, skb) == 0) { + if (sk_filter_trim_cap(sk, skb, ROSE_MIN_LEN) == 0 && + sock_queue_rcv_skb(sk, skb) == 0) { rose->vr = (rose->vr + 1) % ROSE_MODULUS; queued = 1; } else { -- cgit v1.2.3 From 68b87a2b4ab9b0883915656883a5520d4cca3d1a Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Tue, 15 Nov 2016 13:26:28 -0700 Subject: tcp: take care of truncations done by sk_filter() With syzkaller help, Marco Grassi found a bug in TCP stack, crashing in tcp_collapse() Root cause is that sk_filter() can truncate the incoming skb, but TCP stack was not really expecting this to happen. It probably was expecting a simple DROP or ACCEPT behavior. We first need to make sure no part of TCP header could be removed. Then we need to adjust TCP_SKB_CB(skb)->end_seq Many thanks to syzkaller team and Marco for giving us a reproducer. CRs-Fixed: 1089895 Change-Id: I84185558fa6e80b13d7d0078bda9d75143680941 Signed-off-by: Eric Dumazet Reported-by: Marco Grassi Reported-by: Vladis Dronov Signed-off-by: David S. Miller Git-commit: ac6e780070e30e4c35bd395acfe9191e6268bdd3 Git-repo: git://git.kernel.org/pub/scm/linux/kernel/git/next/linux-next.git [subashab@codeaurora.org: resolve trivial merge conflicts] Signed-off-by: Subash Abhinov Kasiviswanathan --- include/net/tcp.h | 1 + net/ipv4/tcp_ipv4.c | 19 ++++++++++++++++++- net/ipv6/tcp_ipv6.c | 6 ++++-- 3 files changed, 23 insertions(+), 3 deletions(-) diff --git a/include/net/tcp.h b/include/net/tcp.h index 5ed36a59b08e..213601d620e0 100644 --- a/include/net/tcp.h +++ b/include/net/tcp.h @@ -1171,6 +1171,7 @@ static inline void tcp_prequeue_init(struct tcp_sock *tp) } bool tcp_prequeue(struct sock *sk, struct sk_buff *skb); +int tcp_filter(struct sock *sk, struct sk_buff *skb); #undef STATE_TRACE diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c index 07408b81bcd7..e3b0b55f2c92 100644 --- a/net/ipv4/tcp_ipv4.c +++ b/net/ipv4/tcp_ipv4.c @@ -1529,6 +1529,21 @@ bool tcp_prequeue(struct sock *sk, struct sk_buff *skb) } EXPORT_SYMBOL(tcp_prequeue); +int tcp_filter(struct sock *sk, struct sk_buff *skb) +{ + struct tcphdr *th = (struct tcphdr *)skb->data; + unsigned int eaten = skb->len; + int err; + + err = sk_filter_trim_cap(sk, skb, th->doff * 4); + if (!err) { + eaten -= skb->len; + TCP_SKB_CB(skb)->end_seq -= eaten; + } + return err; +} +EXPORT_SYMBOL(tcp_filter); + /* * From tcp_input.c */ @@ -1634,8 +1649,10 @@ process: nf_reset(skb); - if (sk_filter(sk, skb)) + if (tcp_filter(sk, skb)) goto discard_and_relse; + th = (const struct tcphdr *)skb->data; + iph = ip_hdr(skb); skb->dev = NULL; diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c index 04955a5d2350..8647afa77db4 100644 --- a/net/ipv6/tcp_ipv6.c +++ b/net/ipv6/tcp_ipv6.c @@ -1199,7 +1199,7 @@ static int tcp_v6_do_rcv(struct sock *sk, struct sk_buff *skb) if (skb->protocol == htons(ETH_P_IP)) return tcp_v4_do_rcv(sk, skb); - if (sk_filter(sk, skb)) + if (tcp_filter(sk, skb)) goto discard; /* @@ -1431,8 +1431,10 @@ process: if (tcp_v6_inbound_md5_hash(sk, skb)) goto discard_and_relse; - if (sk_filter(sk, skb)) + if (tcp_filter(sk, skb)) goto discard_and_relse; + th = (const struct tcphdr *)skb->data; + hdr = ipv6_hdr(skb); skb->dev = NULL; -- cgit v1.2.3 From f50e4f241296461bdf3e50a4a9aec366e0bf4140 Mon Sep 17 00:00:00 2001 From: Jack Pham Date: Sat, 5 Nov 2016 09:03:00 -0700 Subject: usb: pd: Stop processing SVDM if handler found If a client matching the SVID for an incoming SVDM is found, assume it has handled the message completely and simply return. This avoids the case when it handles an Attention message by queuing another VDM request, only to have it inadvertently deleted in the generic handling below. But we also lose tracking of Discover/Enter/Exit Mode exchanges though that was only used for informational purposes. Change-Id: Ie23d473302d7fbda9b243a150e5c52d025007e4f Signed-off-by: Jack Pham --- drivers/usb/pd/policy_engine.c | 66 ++++++++++++++---------------------------- 1 file changed, 22 insertions(+), 44 deletions(-) diff --git a/drivers/usb/pd/policy_engine.c b/drivers/usb/pd/policy_engine.c index b4d7c7d8bddf..517110e76157 100644 --- a/drivers/usb/pd/policy_engine.c +++ b/drivers/usb/pd/policy_engine.c @@ -1039,23 +1039,23 @@ static void handle_vdm_rx(struct usbpd *pd, struct rx_msg *rx_msg) return; } - if (handler && handler->svdm_received) + /* if this interrupts a previous exchange, abort queued response */ + if (cmd_type == SVDM_CMD_TYPE_INITIATOR && pd->vdm_tx) { + usbpd_dbg(&pd->dev, "Discarding previously queued SVDM tx (SVID:0x%04x)\n", + VDM_HDR_SVID(pd->vdm_tx->data[0])); + + kfree(pd->vdm_tx); + pd->vdm_tx = NULL; + } + + if (handler && handler->svdm_received) { handler->svdm_received(handler, cmd, cmd_type, vdos, num_vdos); + return; + } + /* Standard Discovery or unhandled messages go here */ switch (cmd_type) { case SVDM_CMD_TYPE_INITIATOR: - /* - * if this interrupts a previous exchange, abort the previous - * outgoing response - */ - if (pd->vdm_tx) { - usbpd_dbg(&pd->dev, "Discarding previously queued SVDM tx (SVID:0x%04x)\n", - VDM_HDR_SVID(pd->vdm_tx->data[0])); - - kfree(pd->vdm_tx); - pd->vdm_tx = NULL; - } - if (svid == USBPD_SID && cmd == USBPD_SVDM_DISCOVER_IDENTITY) { u32 tx_vdos[3] = { ID_HDR_USB_HOST | ID_HDR_USB_DEVICE | @@ -1074,13 +1074,14 @@ static void handle_vdm_rx(struct usbpd *pd, struct rx_msg *rx_msg) break; case SVDM_CMD_TYPE_RESP_ACK: + if (svid != USBPD_SID) { + usbpd_err(&pd->dev, "unhandled ACK for SVID:0x%x\n", + svid); + break; + } + switch (cmd) { case USBPD_SVDM_DISCOVER_IDENTITY: - if (svid != USBPD_SID) { - usbpd_err(&pd->dev, "invalid VID:0x%x\n", svid); - break; - } - kfree(pd->vdm_tx_retry); pd->vdm_tx_retry = NULL; @@ -1091,11 +1092,6 @@ static void handle_vdm_rx(struct usbpd *pd, struct rx_msg *rx_msg) break; case USBPD_SVDM_DISCOVER_SVIDS: - if (svid != USBPD_SID) { - usbpd_err(&pd->dev, "invalid VID:0x%x\n", svid); - break; - } - pd->vdm_state = DISCOVERED_SVIDS; kfree(pd->vdm_tx_retry); @@ -1181,33 +1177,15 @@ static void handle_vdm_rx(struct usbpd *pd, struct rx_msg *rx_msg) break; - case USBPD_SVDM_DISCOVER_MODES: - usbpd_info(&pd->dev, "SVID:0x%04x VDM Modes discovered\n", - svid); - pd->vdm_state = DISCOVERED_MODES; - break; - - case USBPD_SVDM_ENTER_MODE: - usbpd_info(&pd->dev, "SVID:0x%04x VDM Mode entered\n", - svid); - pd->vdm_state = MODE_ENTERED; - kobject_uevent(&pd->dev.kobj, KOBJ_CHANGE); - break; - - case USBPD_SVDM_EXIT_MODE: - usbpd_info(&pd->dev, "SVID:0x%04x VDM Mode exited\n", - svid); - pd->vdm_state = MODE_EXITED; - kobject_uevent(&pd->dev.kobj, KOBJ_CHANGE); - break; - default: + usbpd_dbg(&pd->dev, "unhandled ACK for command:0x%x\n", + cmd); break; } break; case SVDM_CMD_TYPE_RESP_NAK: - usbpd_info(&pd->dev, "VDM NAK received for SVID:0x%04x command:%d\n", + usbpd_info(&pd->dev, "VDM NAK received for SVID:0x%04x command:0x%x\n", svid, cmd); break; -- cgit v1.2.3 From 770f204fbd1ded8c48a8441e55e86d77ad99d367 Mon Sep 17 00:00:00 2001 From: Taniya Das Date: Mon, 14 Nov 2016 11:26:02 +0530 Subject: clk: add/modify debugfs support for clocks Update clock debugfs to support the below functionalities. - Allow enable/disable a clock. - Allow set_rate on a clock. - Display the list of enabled_clocks along with prepare_count, enable_count and rate. - Display the register contents of all the clocks which support this clock operation. Change-Id: Ib67b3a3409c9e7d8adb710bb524f54f543abf712 Signed-off-by: Taniya Das --- drivers/clk/clk.c | 207 ++++++++++++++++++++++++++++++++++++++++++- include/linux/clk-provider.h | 6 ++ 2 files changed, 209 insertions(+), 4 deletions(-) diff --git a/drivers/clk/clk.c b/drivers/clk/clk.c index 1eb6e32e0d51..620b1c16ab21 100644 --- a/drivers/clk/clk.c +++ b/drivers/clk/clk.c @@ -2409,6 +2409,190 @@ static const struct file_operations clk_dump_fops = { .release = single_release, }; +static int clock_debug_rate_set(void *data, u64 val) +{ + struct clk_core *core = data; + int ret; + + ret = clk_set_rate(core->hw->clk, val); + if (ret) + pr_err("clk_set_rate(%lu) failed (%d)\n", + (unsigned long)val, ret); + + return ret; +} + +static int clock_debug_rate_get(void *data, u64 *val) +{ + struct clk_core *core = data; + + *val = core->hw->core->rate; + + return 0; +} + +DEFINE_SIMPLE_ATTRIBUTE(clock_rate_fops, clock_debug_rate_get, + clock_debug_rate_set, "%llu\n"); + +static ssize_t clock_parent_read(struct file *filp, char __user *ubuf, + size_t cnt, loff_t *ppos) +{ + char name[256] = {0}; + struct clk_core *core = filp->private_data; + struct clk_core *p = core->hw->core->parent; + + snprintf(name, sizeof(name), "%s\n", p ? p->name : "None\n"); + + return simple_read_from_buffer(ubuf, cnt, ppos, name, strlen(name)); +} + +static const struct file_operations clock_parent_fops = { + .open = simple_open, + .read = clock_parent_read, +}; + +static int clock_debug_enable_set(void *data, u64 val) +{ + struct clk_core *core = data; + int rc = 0; + + if (val) + rc = clk_prepare_enable(core->hw->clk); + else + clk_disable_unprepare(core->hw->clk); + + return rc; +} + +static int clock_debug_enable_get(void *data, u64 *val) +{ + struct clk_core *core = data; + int enabled = 0; + + enabled = core->enable_count; + + *val = enabled; + + return 0; +} + +DEFINE_SIMPLE_ATTRIBUTE(clock_enable_fops, clock_debug_enable_get, + clock_debug_enable_set, "%lld\n"); + +#define clock_debug_output(m, c, fmt, ...) \ +do { \ + if (m) \ + seq_printf(m, fmt, ##__VA_ARGS__); \ + else if (c) \ + pr_cont(fmt, ##__VA_ARGS__); \ + else \ + pr_info(fmt, ##__VA_ARGS__); \ +} while (0) + +int clock_debug_print_clock(struct clk_core *c, struct seq_file *s) +{ + char *start = ""; + struct clk *clk; + + if (!c || !c->prepare_count) + return 0; + + clk = c->hw->clk; + + clock_debug_output(s, 0, "\t"); + + do { + clock_debug_output(s, 1, "%s%s:%u:%u [%ld]", start, + clk->core->name, + clk->core->prepare_count, + clk->core->enable_count, + clk->core->rate); + start = " -> "; + } while ((clk = clk_get_parent(clk))); + + clock_debug_output(s, 1, "\n"); + + return 1; +} + +/* + * clock_debug_print_enabled_clocks() - Print names of enabled clocks + */ +static void clock_debug_print_enabled_clocks(struct seq_file *s) +{ + struct clk_core *core; + int cnt = 0; + + clock_debug_output(s, 0, "Enabled clocks:\n"); + + mutex_lock(&clk_debug_lock); + + hlist_for_each_entry(core, &clk_debug_list, debug_node) + cnt += clock_debug_print_clock(core, s); + + mutex_unlock(&clk_debug_lock); + + if (cnt) + clock_debug_output(s, 0, "Enabled clock count: %d\n", cnt); + else + clock_debug_output(s, 0, "No clocks enabled.\n"); +} + +static int enabled_clocks_show(struct seq_file *s, void *unused) +{ + clock_debug_print_enabled_clocks(s); + + return 0; +} + +static int enabled_clocks_open(struct inode *inode, struct file *file) +{ + return single_open(file, enabled_clocks_show, inode->i_private); +} + +static const struct file_operations clk_enabled_list_fops = { + .open = enabled_clocks_open, + .read = seq_read, + .llseek = seq_lseek, + .release = seq_release, +}; + +static void clk_debug_print_hw(struct clk_core *clk, struct seq_file *f) +{ + if (IS_ERR_OR_NULL(clk)) + return; + + clk_debug_print_hw(clk->parent, f); + + clock_debug_output(f, false, "%s\n", clk->name); + + if (!clk->ops->list_registers) + return; + + clk->ops->list_registers(f, clk->hw); +} + +static int print_hw_show(struct seq_file *m, void *unused) +{ + struct clk_core *c = m->private; + + clk_debug_print_hw(c, m); + + return 0; +} + +static int print_hw_open(struct inode *inode, struct file *file) +{ + return single_open(file, print_hw_show, inode->i_private); +} + +static const struct file_operations clock_print_hw_fops = { + .open = print_hw_open, + .read = seq_read, + .llseek = seq_lseek, + .release = seq_release, +}; + static int clk_debug_create_one(struct clk_core *core, struct dentry *pdentry) { struct dentry *d; @@ -2425,8 +2609,8 @@ static int clk_debug_create_one(struct clk_core *core, struct dentry *pdentry) core->dentry = d; - d = debugfs_create_u32("clk_rate", S_IRUGO, core->dentry, - (u32 *)&core->rate); + d = debugfs_create_file("clk_rate", S_IRUGO, core->dentry, core, + &clock_rate_fops); if (!d) goto err_out; @@ -2450,8 +2634,8 @@ static int clk_debug_create_one(struct clk_core *core, struct dentry *pdentry) if (!d) goto err_out; - d = debugfs_create_u32("clk_enable_count", S_IRUGO, core->dentry, - (u32 *)&core->enable_count); + d = debugfs_create_file("clk_enable_count", S_IRUGO, core->dentry, + core, &clock_enable_fops); if (!d) goto err_out; @@ -2460,6 +2644,16 @@ static int clk_debug_create_one(struct clk_core *core, struct dentry *pdentry) if (!d) goto err_out; + d = debugfs_create_file("clk_parent", S_IRUGO, core->dentry, core, + &clock_parent_fops); + if (!d) + goto err_out; + + d = debugfs_create_file("clk_print_regs", S_IRUGO, core->dentry, + core, &clock_print_hw_fops); + if (!d) + goto err_out; + if (core->ops->debug_init) { ret = core->ops->debug_init(core->hw, core->dentry); if (ret) @@ -2570,6 +2764,11 @@ static int __init clk_debug_init(void) if (!d) return -ENOMEM; + d = debugfs_create_file("clk_enabled_list", S_IRUGO, rootdir, + &clk_debug_list, &clk_enabled_list_fops); + if (!d) + return -ENOMEM; + mutex_lock(&clk_debug_lock); hlist_for_each_entry(core, &clk_debug_list, debug_node) clk_debug_create_one(core, rootdir); diff --git a/include/linux/clk-provider.h b/include/linux/clk-provider.h index 2a5acbdc6327..2a4047c049a8 100644 --- a/include/linux/clk-provider.h +++ b/include/linux/clk-provider.h @@ -177,6 +177,10 @@ struct clk_rate_request { * @set_flags: Set custom flags which deals with hardware specifics. Returns 0 * on success, -EEROR otherwise. * + * @list_registers: Queries the hardware to get the current register contents. + * This callback is optional and required clocks could + * add this callback. + * * The clk_enable/clk_disable and clk_prepare/clk_unprepare pairs allow * implementations to split any work between atomic (enable) and sleepable * (prepare) contexts. If enabling a clock requires code that might sleep, @@ -217,6 +221,8 @@ struct clk_ops { void (*init)(struct clk_hw *hw); int (*debug_init)(struct clk_hw *hw, struct dentry *dentry); int (*set_flags)(struct clk_hw *hw, unsigned flags); + void (*list_registers)(struct seq_file *f, + struct clk_hw *hw); }; /** -- cgit v1.2.3 From dba9af81b8765aa65fed6488b29eb4bbfe90267d Mon Sep 17 00:00:00 2001 From: Taniya Das Date: Mon, 14 Nov 2016 11:54:02 +0530 Subject: clk: Add support for list_rates ops for clocks Add support for clocks debugfs to be able to display - rates_max which indicates the frequency to voltage mapping of a clock. - list_rates, the list of clock frequencies supported by root clocks. - Also display the rate_max associated with enabled clocks list. Change-Id: I0a202af6f46c7cf164036d65487db5c40aab4063 Signed-off-by: Taniya Das --- drivers/clk/clk.c | 131 ++++++++++++++++++++++++++++++++++++++++++- include/linux/clk-provider.h | 6 ++ 2 files changed, 136 insertions(+), 1 deletion(-) diff --git a/drivers/clk/clk.c b/drivers/clk/clk.c index 620b1c16ab21..deb935ce6a11 100644 --- a/drivers/clk/clk.c +++ b/drivers/clk/clk.c @@ -2502,7 +2502,15 @@ int clock_debug_print_clock(struct clk_core *c, struct seq_file *s) clock_debug_output(s, 0, "\t"); do { - clock_debug_output(s, 1, "%s%s:%u:%u [%ld]", start, + if (clk->core->vdd_class) + clock_debug_output(s, 1, "%s%s:%u:%u [%ld, %d]", start, + clk->core->name, + clk->core->prepare_count, + clk->core->enable_count, + clk->core->rate, + clk_find_vdd_level(clk->core, clk->core->rate)); + else + clock_debug_output(s, 1, "%s%s:%u:%u [%ld]", start, clk->core->name, clk->core->prepare_count, clk->core->enable_count, @@ -2593,6 +2601,117 @@ static const struct file_operations clock_print_hw_fops = { .release = seq_release, }; +static int list_rates_show(struct seq_file *s, void *unused) +{ + struct clk_core *core = s->private; + int level = 0, i = 0; + unsigned long rate, rate_max = 0; + + /* Find max frequency supported within voltage constraints. */ + if (!core->vdd_class) { + rate_max = ULONG_MAX; + } else { + for (level = 0; level < core->num_rate_max; level++) + if (core->rate_max[level]) + rate_max = core->rate_max[level]; + } + + /* + * List supported frequencies <= rate_max. Higher frequencies may + * appear in the frequency table, but are not valid and should not + * be listed. + */ + while (!IS_ERR_VALUE(rate = + core->ops->list_rate(core->hw, i++, rate_max))) { + if (rate <= 0) + break; + if (rate <= rate_max) + seq_printf(s, "%lu\n", rate); + } + + return 0; +} + +static int list_rates_open(struct inode *inode, struct file *file) +{ + return single_open(file, list_rates_show, inode->i_private); +} + +static const struct file_operations list_rates_fops = { + .open = list_rates_open, + .read = seq_read, + .llseek = seq_lseek, + .release = seq_release, +}; + +static void clock_print_rate_max_by_level(struct seq_file *s, int level) +{ + struct clk_core *core = s->private; + struct clk_vdd_class *vdd_class = core->vdd_class; + int off, i, vdd_level, nregs = vdd_class->num_regulators; + + vdd_level = clk_find_vdd_level(core, core->rate); + + seq_printf(s, "%2s%10lu", vdd_level == level ? "[" : "", + core->rate_max[level]); + + for (i = 0; i < nregs; i++) { + off = nregs*level + i; + if (vdd_class->vdd_uv) + seq_printf(s, "%10u", vdd_class->vdd_uv[off]); + } + + if (vdd_level == level) + seq_puts(s, "]"); + + seq_puts(s, "\n"); +} + +static int rate_max_show(struct seq_file *s, void *unused) +{ + struct clk_core *core = s->private; + struct clk_vdd_class *vdd_class = core->vdd_class; + int level = 0, i, nregs = vdd_class->num_regulators; + char reg_name[10]; + + int vdd_level = clk_find_vdd_level(core, core->rate); + + if (vdd_level < 0) { + seq_printf(s, "could not find_vdd_level for %s, %ld\n", + core->name, core->rate); + return 0; + } + + seq_printf(s, "%12s", ""); + for (i = 0; i < nregs; i++) { + snprintf(reg_name, ARRAY_SIZE(reg_name), "reg %d", i); + seq_printf(s, "%10s", reg_name); + } + + seq_printf(s, "\n%12s", "freq"); + for (i = 0; i < nregs; i++) + seq_printf(s, "%10s", "uV"); + + seq_puts(s, "\n"); + + for (level = 0; level < core->num_rate_max; level++) + clock_print_rate_max_by_level(s, level); + + return 0; +} + +static int rate_max_open(struct inode *inode, struct file *file) +{ + return single_open(file, rate_max_show, inode->i_private); +} + +static const struct file_operations rate_max_fops = { + .open = rate_max_open, + .read = seq_read, + .llseek = seq_lseek, + .release = seq_release, +}; + static int clk_debug_create_one(struct clk_core *core, struct dentry *pdentry) { struct dentry *d; @@ -2614,6 +2733,16 @@ static int clk_debug_create_one(struct clk_core *core, struct dentry *pdentry) if (!d) goto err_out; + if (core->ops->list_rate) { + if (!debugfs_create_file("clk_list_rates", + S_IRUGO, core->dentry, core, &list_rates_fops)) + goto err_out; + } + + if (core->vdd_class && !debugfs_create_file("clk_rate_max", + S_IRUGO, core->dentry, core, &rate_max_fops)) + goto err_out; + d = debugfs_create_u32("clk_accuracy", S_IRUGO, core->dentry, (u32 *)&core->accuracy); if (!d) diff --git a/include/linux/clk-provider.h b/include/linux/clk-provider.h index 2a4047c049a8..fd2eb059b991 100644 --- a/include/linux/clk-provider.h +++ b/include/linux/clk-provider.h @@ -181,6 +181,10 @@ struct clk_rate_request { * This callback is optional and required clocks could * add this callback. * + * @list_rate: Return the nth supported frequency for a given clock which is + * below rate_max on success and -ENXIO in case of no frequency + * table. + * * The clk_enable/clk_disable and clk_prepare/clk_unprepare pairs allow * implementations to split any work between atomic (enable) and sleepable * (prepare) contexts. If enabling a clock requires code that might sleep, @@ -223,6 +227,8 @@ struct clk_ops { int (*set_flags)(struct clk_hw *hw, unsigned flags); void (*list_registers)(struct seq_file *f, struct clk_hw *hw); + long (*list_rate)(struct clk_hw *hw, unsigned n, + unsigned long rate_max); }; /** -- cgit v1.2.3 From b9b1975fe3f2d0ea767be06a494a8e5983cab911 Mon Sep 17 00:00:00 2001 From: Taniya Das Date: Mon, 7 Nov 2016 10:08:30 +0530 Subject: clk: Add support to allow client to print all enabled clocks The clock api clock_debug_print_enabled would allow any client like low power driver to print all the enabled clocks which include the prepare_count/enable_count/rate/rate max vote. Change-Id: I936496e553bc958c10e743fd8a225ffc7fbc0f79 Signed-off-by: Taniya Das --- drivers/clk/clk.c | 20 ++++++++++++++++++++ drivers/clk/clk.h | 4 ++++ 2 files changed, 24 insertions(+) diff --git a/drivers/clk/clk.c b/drivers/clk/clk.c index deb935ce6a11..25ab30063072 100644 --- a/drivers/clk/clk.c +++ b/drivers/clk/clk.c @@ -2267,6 +2267,7 @@ EXPORT_SYMBOL_GPL(clk_set_flags); static struct dentry *rootdir; static int inited = 0; +static u32 debug_suspend; static DEFINE_MUTEX(clk_debug_lock); static HLIST_HEAD(clk_debug_list); @@ -2854,6 +2855,19 @@ struct dentry *clk_debugfs_add_file(struct clk_hw *hw, char *name, umode_t mode, } EXPORT_SYMBOL_GPL(clk_debugfs_add_file); +/* + * Print the names of all enabled clocks and their parents if + * debug_suspend is set from debugfs. + */ +void clock_debug_print_enabled(void) +{ + if (likely(!debug_suspend)) + return; + + clock_debug_print_enabled_clocks(NULL); +} +EXPORT_SYMBOL_GPL(clock_debug_print_enabled); + /** * clk_debug_init - lazily populate the debugfs clk directory * @@ -2898,6 +2912,12 @@ static int __init clk_debug_init(void) if (!d) return -ENOMEM; + + d = debugfs_create_u32("debug_suspend", S_IRUGO | S_IWUSR, + rootdir, &debug_suspend); + if (!d) + return -ENOMEM; + mutex_lock(&clk_debug_lock); hlist_for_each_entry(core, &clk_debug_list, debug_node) clk_debug_create_one(core, rootdir); diff --git a/drivers/clk/clk.h b/drivers/clk/clk.h index 97941b0f8f32..179b27c08022 100644 --- a/drivers/clk/clk.h +++ b/drivers/clk/clk.h @@ -20,6 +20,10 @@ struct clk *__of_clk_get_from_provider(struct of_phandle_args *clkspec, struct clk *__clk_create_clk(struct clk_hw *hw, const char *dev_id, const char *con_id); void __clk_free_clk(struct clk *clk); + +/* Debugfs API to print the enabled clocks */ +void clock_debug_print_enabled(void); + #else /* All these casts to avoid ifdefs in clkdev... */ static inline struct clk * -- cgit v1.2.3 From e03bf33cb9411de0d1b9c1df2b09ebf3e5c5bae4 Mon Sep 17 00:00:00 2001 From: Taniya Das Date: Mon, 7 Nov 2016 10:01:38 +0530 Subject: clk: qcom: Add support for debugfs support Add the clock operation list_registers which would print the register content of a clock. This is supported for PLL/RCG/Branch/Gate clocks. Also add support for list_rate for the RCG clock which would list all the frequencies/rates supported by the SW. Change-Id: I3b4cf83e776750d993d53331142223109bf0862e Signed-off-by: Taniya Das --- drivers/clk/qcom/clk-alpha-pll.c | 37 +++++++++++++++++++++++++ drivers/clk/qcom/clk-branch.c | 59 ++++++++++++++++++++++++++++++++++++++++ drivers/clk/qcom/clk-rcg2.c | 56 ++++++++++++++++++++++++++++++++++++++ drivers/clk/qcom/clk-regmap.h | 8 +++++- 4 files changed, 159 insertions(+), 1 deletion(-) diff --git a/drivers/clk/qcom/clk-alpha-pll.c b/drivers/clk/qcom/clk-alpha-pll.c index 085b9acfb9d5..ac45943dc12e 100644 --- a/drivers/clk/qcom/clk-alpha-pll.c +++ b/drivers/clk/qcom/clk-alpha-pll.c @@ -562,12 +562,48 @@ static long clk_alpha_pll_round_rate(struct clk_hw *hw, unsigned long rate, return clamp(rate, min_freq, max_freq); } +static void clk_alpha_pll_list_registers(struct seq_file *f, struct clk_hw *hw) +{ + struct clk_alpha_pll *pll = to_clk_alpha_pll(hw); + int size, i, val; + + static struct clk_register_data data[] = { + {"PLL_MODE", 0x0}, + {"PLL_L_VAL", 0x4}, + {"PLL_ALPHA_VAL", 0x8}, + {"PLL_ALPHA_VAL_U", 0xC}, + {"PLL_USER_CTL", 0x10}, + {"PLL_CONFIG_CTL", 0x18}, + }; + + static struct clk_register_data data1[] = { + {"APSS_PLL_VOTE", 0x0}, + }; + + size = ARRAY_SIZE(data); + + for (i = 0; i < size; i++) { + regmap_read(pll->clkr.regmap, pll->offset + data[i].offset, + &val); + seq_printf(f, "%20s: 0x%.8x\n", data[i].name, val); + } + + regmap_read(pll->clkr.regmap, pll->offset + data[0].offset, &val); + + if (val & PLL_FSM_ENA) { + regmap_read(pll->clkr.regmap, pll->clkr.enable_reg + + data1[0].offset, &val); + seq_printf(f, "%20s: 0x%.8x\n", data1[0].name, val); + } +} + const struct clk_ops clk_alpha_pll_ops = { .enable = clk_alpha_pll_enable, .disable = clk_alpha_pll_disable, .recalc_rate = clk_alpha_pll_recalc_rate, .round_rate = clk_alpha_pll_round_rate, .set_rate = clk_alpha_pll_set_rate, + .list_registers = clk_alpha_pll_list_registers, }; EXPORT_SYMBOL_GPL(clk_alpha_pll_ops); @@ -577,6 +613,7 @@ const struct clk_ops clk_alpha_pll_hwfsm_ops = { .recalc_rate = clk_alpha_pll_recalc_rate, .round_rate = clk_alpha_pll_round_rate, .set_rate = clk_alpha_pll_set_rate, + .list_registers = clk_alpha_pll_list_registers, }; EXPORT_SYMBOL_GPL(clk_alpha_pll_hwfsm_ops); diff --git a/drivers/clk/qcom/clk-branch.c b/drivers/clk/qcom/clk-branch.c index 8aea1d519311..6a975052cc85 100644 --- a/drivers/clk/qcom/clk-branch.c +++ b/drivers/clk/qcom/clk-branch.c @@ -16,10 +16,12 @@ #include #include #include +#include #include #include #include "clk-branch.h" +#include "clk-regmap.h" static bool clk_branch_in_hwcg_mode(const struct clk_branch *br) { @@ -181,6 +183,43 @@ const struct clk_ops clk_branch_ops = { }; EXPORT_SYMBOL_GPL(clk_branch_ops); +static void clk_branch2_list_registers(struct seq_file *f, struct clk_hw *hw) +{ + struct clk_branch *br = to_clk_branch(hw); + struct clk_regmap *rclk = to_clk_regmap(hw); + int size, i, val; + + static struct clk_register_data data[] = { + {"CBCR", 0x0}, + }; + + static struct clk_register_data data1[] = { + {"APSS_VOTE", 0x0}, + {"APSS_SLEEP_VOTE", 0x4}, + }; + + size = ARRAY_SIZE(data); + + for (i = 0; i < size; i++) { + regmap_read(br->clkr.regmap, br->halt_reg + data[i].offset, + &val); + seq_printf(f, "%20s: 0x%.8x\n", data[i].name, val); + } + + if ((br->halt_check & BRANCH_HALT_VOTED) && + !(br->halt_check & BRANCH_VOTED)) { + if (rclk->enable_reg) { + size = ARRAY_SIZE(data1); + for (i = 0; i < size; i++) { + regmap_read(br->clkr.regmap, rclk->enable_reg + + data1[i].offset, &val); + seq_printf(f, "%20s: 0x%.8x\n", + data1[i].name, val); + } + } + } +} + static int clk_branch2_enable(struct clk_hw *hw) { return clk_branch_toggle(hw, true, clk_branch2_check_halt); @@ -196,6 +235,7 @@ const struct clk_ops clk_branch2_ops = { .disable = clk_branch2_disable, .is_enabled = clk_is_enabled_regmap, .set_flags = clk_branch_set_flags, + .list_registers = clk_branch2_list_registers, }; EXPORT_SYMBOL_GPL(clk_branch2_ops); @@ -228,10 +268,29 @@ static void clk_gate2_disable(struct clk_hw *hw) clk_gate_toggle(hw, false); } +static void clk_gate2_list_registers(struct seq_file *f, struct clk_hw *hw) +{ + struct clk_gate2 *gt = to_clk_gate2(hw); + int size, i, val; + + static struct clk_register_data data[] = { + {"EN_REG", 0x0}, + }; + + size = ARRAY_SIZE(data); + + for (i = 0; i < size; i++) { + regmap_read(gt->clkr.regmap, gt->clkr.enable_reg + + data[i].offset, &val); + seq_printf(f, "%20s: 0x%.8x\n", data[i].name, val); + } +} + const struct clk_ops clk_gate2_ops = { .enable = clk_gate2_enable, .disable = clk_gate2_disable, .is_enabled = clk_is_enabled_regmap, + .list_registers = clk_gate2_list_registers, }; EXPORT_SYMBOL_GPL(clk_gate2_ops); diff --git a/drivers/clk/qcom/clk-rcg2.c b/drivers/clk/qcom/clk-rcg2.c index 6d12ddb3e245..3785a7579ce7 100644 --- a/drivers/clk/qcom/clk-rcg2.c +++ b/drivers/clk/qcom/clk-rcg2.c @@ -317,6 +317,53 @@ static int clk_rcg2_configure(struct clk_rcg2 *rcg, const struct freq_tbl *f) return update_config(rcg); } +static void clk_rcg2_list_registers(struct seq_file *f, struct clk_hw *hw) +{ + struct clk_rcg2 *rcg = to_clk_rcg2(hw); + int i = 0, size = 0, val; + + static struct clk_register_data data[] = { + {"CMD_RCGR", 0x0}, + {"CFG_RCGR", 0x4}, + }; + + static struct clk_register_data data1[] = { + {"CMD_RCGR", 0x0}, + {"CFG_RCGR", 0x4}, + {"M_VAL", 0x8}, + {"N_VAL", 0xC}, + {"D_VAL", 0x10}, + }; + + if (rcg->mnd_width) { + size = ARRAY_SIZE(data1); + for (i = 0; i < size; i++) { + regmap_read(rcg->clkr.regmap, (rcg->cmd_rcgr + + data1[i].offset), &val); + seq_printf(f, "%20s: 0x%.8x\n", data1[i].name, val); + } + } else { + size = ARRAY_SIZE(data); + for (i = 0; i < size; i++) { + regmap_read(rcg->clkr.regmap, (rcg->cmd_rcgr + + data[i].offset), &val); + seq_printf(f, "%20s: 0x%.8x\n", data[i].name, val); + } + } +} + +/* Return the nth supported frequency for a given clock. */ +static long clk_rcg2_list_rate(struct clk_hw *hw, unsigned n, + unsigned long fmax) +{ + struct clk_rcg2 *rcg = to_clk_rcg2(hw); + + if (!rcg->freq_tbl) + return -ENXIO; + + return (rcg->freq_tbl + n)->freq; +} + static int __clk_rcg2_set_rate(struct clk_hw *hw, unsigned long rate) { struct clk_rcg2 *rcg = to_clk_rcg2(hw); @@ -351,6 +398,8 @@ const struct clk_ops clk_rcg2_ops = { .determine_rate = clk_rcg2_determine_rate, .set_rate = clk_rcg2_set_rate, .set_rate_and_parent = clk_rcg2_set_rate_and_parent, + .list_rate = clk_rcg2_list_rate, + .list_registers = clk_rcg2_list_registers, }; EXPORT_SYMBOL_GPL(clk_rcg2_ops); @@ -557,6 +606,7 @@ const struct clk_ops clk_edp_pixel_ops = { .set_rate = clk_edp_pixel_set_rate, .set_rate_and_parent = clk_edp_pixel_set_rate_and_parent, .determine_rate = clk_edp_pixel_determine_rate, + .list_registers = clk_rcg2_list_registers, }; EXPORT_SYMBOL_GPL(clk_edp_pixel_ops); @@ -615,6 +665,7 @@ const struct clk_ops clk_byte_ops = { .set_rate = clk_byte_set_rate, .set_rate_and_parent = clk_byte_set_rate_and_parent, .determine_rate = clk_byte_determine_rate, + .list_registers = clk_rcg2_list_registers, }; EXPORT_SYMBOL_GPL(clk_byte_ops); @@ -685,6 +736,7 @@ const struct clk_ops clk_byte2_ops = { .set_rate = clk_byte2_set_rate, .set_rate_and_parent = clk_byte2_set_rate_and_parent, .determine_rate = clk_byte2_determine_rate, + .list_registers = clk_rcg2_list_registers, }; EXPORT_SYMBOL_GPL(clk_byte2_ops); @@ -775,6 +827,7 @@ const struct clk_ops clk_pixel_ops = { .set_rate = clk_pixel_set_rate, .set_rate_and_parent = clk_pixel_set_rate_and_parent, .determine_rate = clk_pixel_determine_rate, + .list_registers = clk_rcg2_list_registers, }; EXPORT_SYMBOL_GPL(clk_pixel_ops); @@ -864,6 +917,7 @@ const struct clk_ops clk_gfx3d_ops = { .set_rate = clk_gfx3d_set_rate, .set_rate_and_parent = clk_gfx3d_set_rate_and_parent, .determine_rate = clk_gfx3d_determine_rate, + .list_registers = clk_rcg2_list_registers, }; EXPORT_SYMBOL_GPL(clk_gfx3d_ops); @@ -944,5 +998,7 @@ const struct clk_ops clk_gfx3d_src_ops = { .set_rate = clk_gfx3d_set_rate, .set_rate_and_parent = clk_gfx3d_src_set_rate_and_parent, .determine_rate = clk_gfx3d_src_determine_rate, + .list_rate = clk_rcg2_list_rate, + .list_registers = clk_rcg2_list_registers, }; EXPORT_SYMBOL_GPL(clk_gfx3d_src_ops); diff --git a/drivers/clk/qcom/clk-regmap.h b/drivers/clk/qcom/clk-regmap.h index 491a63d537df..8663dea02d79 100644 --- a/drivers/clk/qcom/clk-regmap.h +++ b/drivers/clk/qcom/clk-regmap.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, The Linux Foundation. All rights reserved. + * Copyright (c) 2014, 2016, The Linux Foundation. All rights reserved. * * This software is licensed under the terms of the GNU General Public * License version 2, as published by the Free Software Foundation, and @@ -15,6 +15,7 @@ #define __QCOM_CLK_REGMAP_H__ #include +#include struct regmap; @@ -42,4 +43,9 @@ void clk_disable_regmap(struct clk_hw *hw); struct clk * devm_clk_register_regmap(struct device *dev, struct clk_regmap *rclk); +struct clk_register_data { + char *name; + u32 offset; +}; + #endif -- cgit v1.2.3 From b5d4c54e33a9ad963ad71603c8da33614efb86fe Mon Sep 17 00:00:00 2001 From: Taniya Das Date: Thu, 27 Oct 2016 18:24:47 +0530 Subject: clk: qcom: Add support for RCGs with dynamic and fixed sources Some RCGSs could have sources with dynamic frequencies and fixed sources where if the RCG has the flag of CLK_SET_RATE_PARENT set, it would try to propagate the clock rate to the fixed source PLLs too. To identify sources of the RCGs where the rate should propagate to parent PLL, add a member in freq_tbl to represent source frequency. This would be used by the _freq_tbl_determine_rate to set its parent frequency on the PLL. Change-Id: I7f1c0d9d84607821893a1e5d17934dae5acef5f4 Signed-off-by: Taniya Das --- drivers/clk/qcom/clk-rcg.h | 1 + drivers/clk/qcom/clk-rcg2.c | 18 +++++++++++++++++- 2 files changed, 18 insertions(+), 1 deletion(-) diff --git a/drivers/clk/qcom/clk-rcg.h b/drivers/clk/qcom/clk-rcg.h index da02ab499bff..4589a3b6cec6 100644 --- a/drivers/clk/qcom/clk-rcg.h +++ b/drivers/clk/qcom/clk-rcg.h @@ -24,6 +24,7 @@ struct freq_tbl { u16 m; u16 n; unsigned long src_freq; +#define FIXED_FREQ_SRC 0 }; /** diff --git a/drivers/clk/qcom/clk-rcg2.c b/drivers/clk/qcom/clk-rcg2.c index 6d12ddb3e245..eb8101a69f5e 100644 --- a/drivers/clk/qcom/clk-rcg2.c +++ b/drivers/clk/qcom/clk-rcg2.c @@ -232,9 +232,10 @@ static int _freq_tbl_determine_rate(struct clk_hw *hw, const struct freq_tbl *f, struct clk_rate_request *req) { unsigned long clk_flags, rate = req->rate; + struct clk_rate_request parent_req = { }; struct clk_hw *p; struct clk_rcg2 *rcg = to_clk_rcg2(hw); - int index; + int index, ret = 0; f = qcom_find_freq(f, rate); if (!f) @@ -265,6 +266,21 @@ static int _freq_tbl_determine_rate(struct clk_hw *hw, req->best_parent_rate = rate; req->rate = f->freq; + if (f->src_freq != FIXED_FREQ_SRC) { + rate = parent_req.rate = f->src_freq; + parent_req.best_parent_hw = p; + ret = __clk_determine_rate(p, &parent_req); + if (ret) + return ret; + + ret = clk_set_rate(p->clk, parent_req.rate); + if (ret) { + pr_err("Failed set rate(%lu) on parent for non-fixed source\n", + parent_req.rate); + return ret; + } + } + return 0; } -- cgit v1.2.3 From 72609b4929859621ee4741112fe2746897444083 Mon Sep 17 00:00:00 2001 From: Taniya Das Date: Fri, 7 Oct 2016 13:00:03 +0530 Subject: clk: qcom: Add support to be able to slew PLL Few alpha PLLs would require to be able to slew in the same VCO mode, which means the PLL would be able to update the new frequency L value without turning it off. But to be support this feature the PLL needs to calibrated at the mid of the VCO range and then enabled. Change-Id: I24820bd6254002f8a8db9604d230dcbce59b1beb Signed-off-by: Taniya Das --- drivers/clk/qcom/clk-alpha-pll.c | 179 +++++++++++++++++++++++++++++++++++++++ drivers/clk/qcom/clk-alpha-pll.h | 1 + 2 files changed, 180 insertions(+) diff --git a/drivers/clk/qcom/clk-alpha-pll.c b/drivers/clk/qcom/clk-alpha-pll.c index 085b9acfb9d5..a208b4b01e1c 100644 --- a/drivers/clk/qcom/clk-alpha-pll.c +++ b/drivers/clk/qcom/clk-alpha-pll.c @@ -117,6 +117,11 @@ static int wait_for_pll_latch_ack(struct clk_alpha_pll *pll, u32 mask) return wait_for_pll(pll, mask, 0, "latch_ack"); } +static int wait_for_pll_update(struct clk_alpha_pll *pll, u32 mask) +{ + return wait_for_pll(pll, mask, 1, "update"); +} + /* alpha pll with hwfsm support */ #define PLL_OFFLINE_REQ BIT(7) @@ -633,3 +638,177 @@ const struct clk_ops clk_alpha_pll_postdiv_ops = { .set_rate = clk_alpha_pll_postdiv_set_rate, }; EXPORT_SYMBOL_GPL(clk_alpha_pll_postdiv_ops); + +static int clk_alpha_pll_slew_update(struct clk_alpha_pll *pll) +{ + int ret = 0; + u32 val; + + regmap_update_bits(pll->clkr.regmap, pll->offset + PLL_MODE, + PLL_UPDATE, PLL_UPDATE); + regmap_read(pll->clkr.regmap, pll->offset + PLL_MODE, &val); + + ret = wait_for_pll_update(pll, PLL_UPDATE); + if (ret) + return ret; + /* + * HPG mandates a wait of at least 570ns before polling the LOCK + * detect bit. Have a delay of 1us just to be safe. + */ + mb(); + udelay(1); + + ret = wait_for_pll_enable(pll, PLL_LOCK_DET); + + return ret; +} + +static int clk_alpha_pll_slew_set_rate(struct clk_hw *hw, unsigned long rate, + unsigned long parent_rate) +{ + struct clk_alpha_pll *pll = to_clk_alpha_pll(hw); + unsigned long freq_hz; + const struct pll_vco *curr_vco, *vco; + u32 l; + u64 a; + + freq_hz = alpha_pll_round_rate(rate, parent_rate, &l, &a); + if (freq_hz != rate) { + pr_err("alpha_pll: Call clk_set_rate with rounded rates!\n"); + return -EINVAL; + } + + curr_vco = alpha_pll_find_vco(pll, clk_hw_get_rate(hw)); + if (!curr_vco) { + pr_err("alpha pll: not in a valid vco range\n"); + return -EINVAL; + } + + vco = alpha_pll_find_vco(pll, freq_hz); + if (!vco) { + pr_err("alpha pll: not in a valid vco range\n"); + return -EINVAL; + } + + /* + * Dynamic pll update will not support switching frequencies across + * vco ranges. In those cases fall back to normal alpha set rate. + */ + if (curr_vco->val != vco->val) + return clk_alpha_pll_set_rate(hw, rate, parent_rate); + + a = a << (ALPHA_REG_BITWIDTH - ALPHA_BITWIDTH); + + regmap_write(pll->clkr.regmap, pll->offset + PLL_L_VAL, l); + regmap_write(pll->clkr.regmap, pll->offset + PLL_ALPHA_VAL, a); + regmap_write(pll->clkr.regmap, pll->offset + PLL_ALPHA_VAL_U, a >> 32); + + /* Ensure that the write above goes through before proceeding. */ + mb(); + + if (clk_hw_is_enabled(hw)) + clk_alpha_pll_slew_update(pll); + + return 0; +} + +/* + * Slewing plls should be bought up at frequency which is in the middle of the + * desired VCO range. So after bringing up the pll at calibration freq, set it + * back to desired frequency(that was set by previous clk_set_rate). + */ +static int clk_alpha_pll_calibrate(struct clk_hw *hw) +{ + unsigned long calibration_freq, freq_hz; + struct clk_alpha_pll *pll = to_clk_alpha_pll(hw); + const struct pll_vco *vco; + u64 a; + u32 l; + int rc; + + vco = alpha_pll_find_vco(pll, clk_hw_get_rate(hw)); + if (!vco) { + pr_err("alpha pll: not in a valid vco range\n"); + return -EINVAL; + } + + /* + * As during slewing plls vco_sel won't be allowed to change, vco table + * should have only one entry table, i.e. index = 0, find the + * calibration frequency. + */ + calibration_freq = (pll->vco_table[0].min_freq + + pll->vco_table[0].max_freq)/2; + + freq_hz = alpha_pll_round_rate(calibration_freq, + clk_hw_get_rate(clk_hw_get_parent(hw)), &l, &a); + if (freq_hz != calibration_freq) { + pr_err("alpha_pll: call clk_set_rate with rounded rates!\n"); + return -EINVAL; + } + + /* Setup PLL for calibration frequency */ + a <<= (ALPHA_REG_BITWIDTH - ALPHA_BITWIDTH); + + regmap_write(pll->clkr.regmap, pll->offset + PLL_L_VAL, l); + regmap_write(pll->clkr.regmap, pll->offset + PLL_ALPHA_VAL, a); + regmap_write(pll->clkr.regmap, pll->offset + PLL_ALPHA_VAL_U, a >> 32); + + regmap_update_bits(pll->clkr.regmap, pll->offset + PLL_USER_CTL, + PLL_VCO_MASK << PLL_VCO_SHIFT, + vco->val << PLL_VCO_SHIFT); + + regmap_update_bits(pll->clkr.regmap, pll->offset + PLL_USER_CTL, + PLL_ALPHA_EN, PLL_ALPHA_EN); + + /* Bringup the pll at calibration frequency */ + rc = clk_alpha_pll_enable(hw); + if (rc) { + pr_err("alpha pll calibration failed\n"); + return rc; + } + + /* + * PLL is already running at calibration frequency. + * So slew pll to the previously set frequency. + */ + freq_hz = alpha_pll_round_rate(clk_hw_get_rate(hw), + clk_hw_get_rate(clk_hw_get_parent(hw)), &l, &a); + + pr_debug("pll %s: setting back to required rate %lu, freq_hz %ld\n", + hw->init->name, clk_hw_get_rate(hw), freq_hz); + + /* Setup the PLL for the new frequency */ + a <<= (ALPHA_REG_BITWIDTH - ALPHA_BITWIDTH); + + regmap_write(pll->clkr.regmap, pll->offset + PLL_L_VAL, l); + regmap_write(pll->clkr.regmap, pll->offset + PLL_ALPHA_VAL, a); + regmap_write(pll->clkr.regmap, pll->offset + PLL_ALPHA_VAL_U, a >> 32); + + regmap_update_bits(pll->clkr.regmap, pll->offset + PLL_USER_CTL, + PLL_ALPHA_EN, PLL_ALPHA_EN); + + return clk_alpha_pll_slew_update(pll); +} + +static int clk_alpha_pll_slew_enable(struct clk_hw *hw) +{ + int rc; + + rc = clk_alpha_pll_calibrate(hw); + if (rc) + return rc; + + rc = clk_alpha_pll_enable(hw); + + return rc; +} + +const struct clk_ops clk_alpha_pll_slew_ops = { + .enable = clk_alpha_pll_slew_enable, + .disable = clk_alpha_pll_disable, + .recalc_rate = clk_alpha_pll_recalc_rate, + .round_rate = clk_alpha_pll_round_rate, + .set_rate = clk_alpha_pll_slew_set_rate, +}; +EXPORT_SYMBOL_GPL(clk_alpha_pll_slew_ops); diff --git a/drivers/clk/qcom/clk-alpha-pll.h b/drivers/clk/qcom/clk-alpha-pll.h index 9b1d3ee61cac..dd92bc340f8a 100644 --- a/drivers/clk/qcom/clk-alpha-pll.h +++ b/drivers/clk/qcom/clk-alpha-pll.h @@ -80,6 +80,7 @@ struct clk_alpha_pll_postdiv { extern const struct clk_ops clk_alpha_pll_ops; extern const struct clk_ops clk_alpha_pll_hwfsm_ops; extern const struct clk_ops clk_alpha_pll_postdiv_ops; +extern const struct clk_ops clk_alpha_pll_slew_ops; void clk_alpha_pll_configure(struct clk_alpha_pll *pll, struct regmap *regmap, const struct pll_config *config); -- cgit v1.2.3 From 98ce3216dd5acb6da831fda2317c1fadc3a5ffc7 Mon Sep 17 00:00:00 2001 From: Abhijit Kulkarni Date: Tue, 15 Nov 2016 20:23:13 -0800 Subject: msm: sde: remove secure camera ctrl_id definition Remove the secure_camera ctrl_id unless the support is available from the sde rotator driver. If this id is defined and functionality is not present in the V4L2 driver it causes the rotator use cases to fail. CRs-Fixed: 1090525 Change-Id: I48c50bc320425c0db40cd4865e05c6b7a7fb5da3 Signed-off-by: Abhijit Kulkarni --- include/uapi/media/msm_sde_rotator.h | 6 ------ 1 file changed, 6 deletions(-) diff --git a/include/uapi/media/msm_sde_rotator.h b/include/uapi/media/msm_sde_rotator.h index 12976e3f14d7..4487edf0c854 100644 --- a/include/uapi/media/msm_sde_rotator.h +++ b/include/uapi/media/msm_sde_rotator.h @@ -86,10 +86,4 @@ struct msm_sde_rotator_fence { /* SDE Rotator private control ID's */ #define V4L2_CID_SDE_ROTATOR_SECURE (V4L2_CID_USER_BASE + 0x1000) -/* - * This control Id indicates this context is associated with the - * secure camera - */ -#define V4L2_CID_SDE_ROTATOR_SECURE_CAMERA (V4L2_CID_USER_BASE + 0x2000) - #endif /* __UAPI_MSM_SDE_ROTATOR_H__ */ -- cgit v1.2.3 From abcf426a00d678daa21ce285886ba8af00297e95 Mon Sep 17 00:00:00 2001 From: Mukesh Kumar Savaliya Date: Wed, 5 Oct 2016 12:54:20 +0530 Subject: ARM: dts: msm: specify UART configuration on msmfalcon. Initial support for all BLSP UARTs with default configuration and disabled state such that clients can overwrite and enable respective UART instance as per need. Change-Id: I15ef73049cee76c6ea5b3916d9281bbd9fdfc563 Signed-off-by: Mukesh Kumar Savaliya --- arch/arm/boot/dts/qcom/msmfalcon-blsp.dtsi | 148 ++++++++++++++++++++++++++ arch/arm/boot/dts/qcom/msmfalcon-pinctrl.dtsi | 105 ++++++++++++++++++ 2 files changed, 253 insertions(+) diff --git a/arch/arm/boot/dts/qcom/msmfalcon-blsp.dtsi b/arch/arm/boot/dts/qcom/msmfalcon-blsp.dtsi index 61764a095a29..a37c5be78f63 100644 --- a/arch/arm/boot/dts/qcom/msmfalcon-blsp.dtsi +++ b/arch/arm/boot/dts/qcom/msmfalcon-blsp.dtsi @@ -226,4 +226,152 @@ <&clock_gcc GCC_BLSP2_QUP4_SPI_APPS_CLK>; status = "disabled"; }; + + blsp1_uart1_hs: uart@c16f000 { /* BLSP1 UART1 */ + compatible = "qcom,msm-hsuart-v14"; + reg = <0xc16f000 0x200>, + <0xc144000 0x1f000>; + reg-names = "core_mem", "bam_mem"; + interrupt-names = "core_irq", "bam_irq", "wakeup_irq"; + #address-cells = <0>; + interrupt-parent = <&blsp1_uart1_hs>; + interrupts = <0 1 2>; + #interrupt-cells = <1>; + interrupt-map-mask = <0xffffffff>; + interrupt-map = <0 &intc 0 0 107 0 + 1 &intc 0 0 238 0 + 2 &tlmm 1 0>; + + qcom,inject-rx-on-wakeup; + qcom,rx-char-to-inject = <0xfd>; + + qcom,bam-tx-ep-pipe-index = <0>; + qcom,bam-rx-ep-pipe-index = <1>; + qcom,master-id = <86>; + clock-names = "core_clk", "iface_clk"; + clocks = <&clock_gcc GCC_BLSP1_UART1_APPS_CLK>, + <&clock_gcc GCC_BLSP1_AHB_CLK>; + pinctrl-names = "sleep", "default"; + pinctrl-0 = <&blsp1_uart1_sleep>; + pinctrl-1 = <&blsp1_uart1_active>; + + qcom,msm-bus,name = "buart1"; + qcom,msm-bus,num-cases = <2>; + qcom,msm-bus,num-paths = <1>; + qcom,msm-bus,vectors-KBps = + <86 512 0 0>, + <86 512 500 800>; + status = "disabled"; + }; + + blsp1_uart2_hs: uart@c170000 { /* BLSP1 UART2 */ + compatible = "qcom,msm-hsuart-v14"; + reg = <0xc170000 0x200>, + <0xc144000 0x1f000>; + reg-names = "core_mem", "bam_mem"; + interrupt-names = "core_irq", "bam_irq", "wakeup_irq"; + #address-cells = <0>; + interrupt-parent = <&blsp1_uart2_hs>; + interrupts = <0 1 2>; + #interrupt-cells = <1>; + interrupt-map-mask = <0xffffffff>; + interrupt-map = <0 &intc 0 0 108 0 + 1 &intc 0 0 238 0 + 2 &tlmm 5 0>; + + qcom,inject-rx-on-wakeup; + qcom,rx-char-to-inject = <0xfd>; + + qcom,bam-tx-ep-pipe-index = <2>; + qcom,bam-rx-ep-pipe-index = <3>; + qcom,master-id = <86>; + clock-names = "core_clk", "iface_clk"; + clocks = <&clock_gcc GCC_BLSP1_UART2_APPS_CLK>, + <&clock_gcc GCC_BLSP1_AHB_CLK>; + pinctrl-names = "sleep", "default"; + pinctrl-0 = <&blsp1_uart2_sleep>; + pinctrl-1 = <&blsp1_uart2_active>; + + qcom,msm-bus,name = "buart2"; + qcom,msm-bus,num-cases = <2>; + qcom,msm-bus,num-paths = <1>; + qcom,msm-bus,vectors-KBps = + <86 512 0 0>, + <86 512 500 800>; + status = "disabled"; + }; + + blsp2_uart1_hs: uart@c1af000 { /* BLSP2 UART1 */ + compatible = "qcom,msm-hsuart-v14"; + reg = <0xc1af000 0x200>, + <0xc184000 0x1f000>; + reg-names = "core_mem", "bam_mem"; + interrupt-names = "core_irq", "bam_irq", "wakeup_irq"; + #address-cells = <0>; + interrupt-parent = <&blsp2_uart1_hs>; + interrupts = <0 1 2>; + #interrupt-cells = <1>; + interrupt-map-mask = <0xffffffff>; + interrupt-map = <0 &intc 0 0 113 0 + 1 &intc 0 0 239 0 + 2 &tlmm 17 0>; + + qcom,inject-rx-on-wakeup; + qcom,rx-char-to-inject = <0xfd>; + + qcom,bam-tx-ep-pipe-index = <0>; + qcom,bam-rx-ep-pipe-index = <1>; + qcom,master-id = <84>; + clock-names = "core_clk", "iface_clk"; + clocks = <&clock_gcc GCC_BLSP2_UART1_APPS_CLK>, + <&clock_gcc GCC_BLSP2_AHB_CLK>; + pinctrl-names = "sleep", "default"; + pinctrl-0 = <&blsp2_uart1_sleep>; + pinctrl-1 = <&blsp2_uart1_active>; + + qcom,msm-bus,name = "buart3"; + qcom,msm-bus,num-cases = <2>; + qcom,msm-bus,num-paths = <1>; + qcom,msm-bus,vectors-KBps = + <84 512 0 0>, + <84 512 500 800>; + status = "disabled"; + }; + + blsp2_uart2_hs: uart@c1b0000 { /* BLSP2 UART2 */ + compatible = "qcom,msm-hsuart-v14"; + reg = <0xc1b0000 0x200>, + <0xc184000 0x1f000>; + reg-names = "core_mem", "bam_mem"; + interrupt-names = "core_irq", "bam_irq", "wakeup_irq"; + #address-cells = <0>; + interrupt-parent = <&blsp2_uart2_hs>; + interrupts = <0 1 2>; + #interrupt-cells = <1>; + interrupt-map-mask = <0xffffffff>; + interrupt-map = <0 &intc 0 0 114 0 + 1 &intc 0 0 239 0 + 2 &tlmm 25 0>; + + qcom,inject-rx-on-wakeup; + qcom,rx-char-to-inject = <0xfd>; + + qcom,bam-tx-ep-pipe-index = <2>; + qcom,bam-rx-ep-pipe-index = <3>; + qcom,master-id = <84>; + clock-names = "core_clk", "iface_clk"; + clocks = <&clock_gcc GCC_BLSP2_UART2_APPS_CLK>, + <&clock_gcc GCC_BLSP2_AHB_CLK>; + pinctrl-names = "sleep", "default"; + pinctrl-0 = <&blsp2_uart2_sleep>; + pinctrl-1 = <&blsp2_uart2_active>; + + qcom,msm-bus,name = "buart4"; + qcom,msm-bus,num-cases = <2>; + qcom,msm-bus,num-paths = <1>; + qcom,msm-bus,vectors-KBps = + <84 512 0 0>, + <84 512 500 800>; + status = "disabled"; + }; }; diff --git a/arch/arm/boot/dts/qcom/msmfalcon-pinctrl.dtsi b/arch/arm/boot/dts/qcom/msmfalcon-pinctrl.dtsi index f13e34f8296b..cb8c11106c57 100644 --- a/arch/arm/boot/dts/qcom/msmfalcon-pinctrl.dtsi +++ b/arch/arm/boot/dts/qcom/msmfalcon-pinctrl.dtsi @@ -369,5 +369,110 @@ }; }; }; + + /* HS UART CONFIGURATION */ + blsp1_uart1_active: blsp1_uart1_active { + mux { + pins = "gpio0", "gpio1", "gpio2", "gpio3"; + function = "blsp_uart1"; + }; + + config { + pins = "gpio0", "gpio1", "gpio2", "gpio3"; + drive-strength = <2>; + bias-disable; + }; + }; + + blsp1_uart1_sleep: blsp1_uart1_sleep { + mux { + pins = "gpio0", "gpio1", "gpio2", "gpio3"; + function = "gpio"; + }; + + config { + pins = "gpio0", "gpio1", "gpio2", "gpio3"; + drive-strength = <2>; + bias-disable; + }; + }; + + blsp1_uart2_active: blsp1_uart2_active { + mux { + pins = "gpio4", "gpio5", "gpio6", "gpio7"; + function = "blsp_uart2 "; + }; + + config { + pins = "gpio4", "gpio5", "gpio6", "gpio7"; + drive-strength = <2>; + bias-disable; + }; + }; + + blsp1_uart2_sleep: blsp1_uart2_sleep { + mux { + pins = "gpio4", "gpio5", "gpio6", "gpio7"; + function = "gpio"; + }; + + config { + pins = "gpio4", "gpio5", "gpio6", "gpio7"; + drive-strength = <2>; + bias-disable; + }; + }; + + blsp2_uart1_active: blsp2_uart1_active { + mux { + pins = "gpio16", "gpio17", "gpio18", "gpio19"; + function = "blsp_uart5"; + }; + + config { + pins = "gpio16", "gpio17", "gpio18", "gpio19"; + drive-strength = <2>; + bias-disable; + }; + }; + + blsp2_uart1_sleep: blsp2_uart1_sleep { + mux { + pins = "gpio16", "gpio17", "gpio18", "gpio19"; + function = "gpio"; + }; + + config { + pins = "gpio16", "gpio17", "gpio18", "gpio19"; + drive-strength = <2>; + bias-disable; + }; + }; + + blsp2_uart2_active: blsp2_uart2_active { + mux { + pins = "gpio24", "gpio25", "gpio26", "gpio27"; + function = "blsp_uart6_a"; + }; + + config { + pins = "gpio24", "gpio25", "gpio26", "gpio27"; + drive-strength = <2>; + bias-disable; + }; + }; + + blsp2_uart2_sleep: blsp2_uart2_sleep { + mux { + pins = "gpio24", "gpio25", "gpio26", "gpio27"; + function = "gpio"; + }; + + config { + pins = "gpio24", "gpio25", "gpio26", "gpio27"; + drive-strength = <2>; + bias-disable; + }; + }; }; }; -- cgit v1.2.3 From e75b50d38f09704770f2feaa0dfa408b034af919 Mon Sep 17 00:00:00 2001 From: Mukesh Kumar Savaliya Date: Sun, 16 Oct 2016 17:15:24 +0530 Subject: ARM: dts: msm: specify I2C configuration for msmfalcon Initial support for all BLSP I2Cs with default configuration and disabled state such that clients can overwrite and enable respective I2C instance as per need. Change-Id: If08ff46e72d537254e90707f28c849a86f262853 Signed-off-by: Mukesh Kumar Savaliya --- arch/arm/boot/dts/qcom/msmfalcon-blsp.dtsi | 192 ++++++++++++++++++++++ arch/arm/boot/dts/qcom/msmfalcon-pinctrl.dtsi | 225 ++++++++++++++++++++++++++ arch/arm/boot/dts/qcom/msmfalcon.dtsi | 16 ++ 3 files changed, 433 insertions(+) diff --git a/arch/arm/boot/dts/qcom/msmfalcon-blsp.dtsi b/arch/arm/boot/dts/qcom/msmfalcon-blsp.dtsi index a37c5be78f63..c401d364409b 100644 --- a/arch/arm/boot/dts/qcom/msmfalcon-blsp.dtsi +++ b/arch/arm/boot/dts/qcom/msmfalcon-blsp.dtsi @@ -22,11 +22,203 @@ spi6 = &spi_6; spi7 = &spi_7; spi8 = &spi_8; + i2c1 = &i2c_1; + i2c2 = &i2c_2; + i2c3 = &i2c_3; + i2c4 = &i2c_4; + i2c5 = &i2c_5; + i2c6 = &i2c_6; + i2c7 = &i2c_7; + i2c8 = &i2c_8; }; }; &soc { + i2c_1: i2c@c175000 { /* BLSP1 QUP1 */ + compatible = "qcom,i2c-msm-v2"; + #address-cells = <1>; + #size-cells = <0>; + reg = <0xc175000 0x600>; + reg-names = "qup_phys_addr"; + interrupt-names = "qup_irq"; + interrupts = <0 95 0>; + dmas = <&dma_blsp1 4 64 0x20000020 0x20>, + <&dma_blsp1 5 32 0x20000020 0x20>; + dma-names = "tx", "rx"; + qcom,master-id = <86>; + qcom,clk-freq-out = <400000>; + qcom,clk-freq-in = <19200000>; + clock-names = "iface_clk", "core_clk"; + clocks = <&clock_gcc GCC_BLSP1_AHB_CLK>, + <&clock_gcc GCC_BLSP1_QUP1_I2C_APPS_CLK>; + pinctrl-names = "i2c_active", "i2c_sleep"; + pinctrl-0 = <&i2c_1_active>; + pinctrl-1 = <&i2c_1_sleep>; + status = "disabled"; + }; + + i2c_2: i2c@c176000 { /* BLSP1 QUP2 */ + compatible = "qcom,i2c-msm-v2"; + #address-cells = <1>; + #size-cells = <0>; + reg = <0xc176000 0x600>; + reg-names = "qup_phys_addr"; + interrupt-names = "qup_irq"; + interrupts = <0 96 0>; + dmas = <&dma_blsp1 6 64 0x20000020 0x20>, + <&dma_blsp1 7 32 0x20000020 0x20>; + dma-names = "tx", "rx"; + qcom,master-id = <86>; + qcom,clk-freq-out = <400000>; + qcom,clk-freq-in = <19200000>; + clock-names = "iface_clk", "core_clk"; + clocks = <&clock_gcc GCC_BLSP1_AHB_CLK>, + <&clock_gcc GCC_BLSP1_QUP2_I2C_APPS_CLK>; + pinctrl-names = "i2c_active", "i2c_sleep"; + pinctrl-0 = <&i2c_2_active>; + pinctrl-1 = <&i2c_2_sleep>; + status = "disabled"; + }; + + i2c_3: i2c@c177000 { /* BLSP1 QUP3 */ + compatible = "qcom,i2c-msm-v2"; + #address-cells = <1>; + #size-cells = <0>; + reg = <0xc177000 0x600>; + reg-names = "qup_phys_addr"; + interrupt-names = "qup_irq"; + interrupts = <0 97 0>; + dmas = <&dma_blsp1 8 64 0x20000020 0x20>, + <&dma_blsp1 9 32 0x20000020 0x20>; + dma-names = "tx", "rx"; + qcom,master-id = <86>; + qcom,clk-freq-out = <400000>; + qcom,clk-freq-in = <19200000>; + clock-names = "iface_clk", "core_clk"; + clocks = <&clock_gcc GCC_BLSP1_AHB_CLK>, + <&clock_gcc GCC_BLSP1_QUP3_I2C_APPS_CLK>; + pinctrl-names = "i2c_active", "i2c_sleep"; + pinctrl-0 = <&i2c_3_active>; + pinctrl-1 = <&i2c_3_sleep>; + status = "disabled"; + }; + + i2c_4: i2c@c178000 { /* BLSP1 QUP4 */ + compatible = "qcom,i2c-msm-v2"; + #address-cells = <1>; + #size-cells = <0>; + reg = <0xc178000 0x600>; + reg-names = "qup_phys_addr"; + interrupt-names = "qup_irq"; + interrupts = <0 98 0>; + dmas = <&dma_blsp1 10 64 0x20000020 0x20>, + <&dma_blsp1 11 32 0x20000020 0x20>; + dma-names = "tx", "rx"; + qcom,master-id = <86>; + qcom,clk-freq-out = <400000>; + qcom,clk-freq-in = <19200000>; + clock-names = "iface_clk", "core_clk"; + clocks = <&clock_gcc GCC_BLSP1_AHB_CLK>, + <&clock_gcc GCC_BLSP1_QUP4_I2C_APPS_CLK>; + pinctrl-names = "i2c_active", "i2c_sleep"; + pinctrl-0 = <&i2c_4_active>; + pinctrl-1 = <&i2c_4_sleep>; + status = "disabled"; + }; + + i2c_5: i2c@c1b5000 { /* BLSP2 QUP1 */ + compatible = "qcom,i2c-msm-v2"; + #address-cells = <1>; + #size-cells = <0>; + reg = <0xc1b5000 0x600>; + reg-names = "qup_phys_addr"; + interrupt-names = "qup_irq"; + interrupts = <0 101 0>; + dmas = <&dma_blsp2 4 64 0x20000020 0x20>, + <&dma_blsp2 5 32 0x20000020 0x20>; + dma-names = "tx", "rx"; + qcom,master-id = <84>; + qcom,clk-freq-out = <400000>; + qcom,clk-freq-in = <19200000>; + clock-names = "iface_clk", "core_clk"; + clocks = <&clock_gcc GCC_BLSP2_AHB_CLK>, + <&clock_gcc GCC_BLSP2_QUP1_I2C_APPS_CLK>; + pinctrl-names = "i2c_active", "i2c_sleep"; + pinctrl-0 = <&i2c_5_active>; + pinctrl-1 = <&i2c_5_sleep>; + status = "disabled"; + }; + + i2c_6: i2c@c1b6000 { /* BLSP2 QUP2 */ + compatible = "qcom,i2c-msm-v2"; + #address-cells = <1>; + #size-cells = <0>; + reg = <0xc1b6000 0x600>; + reg-names = "qup_phys_addr"; + interrupt-names = "qup_irq"; + interrupts = <0 102 0>; + dmas = <&dma_blsp2 6 64 0x20000020 0x20>, + <&dma_blsp2 7 32 0x20000020 0x20>; + dma-names = "tx", "rx"; + qcom,master-id = <84>; + qcom,clk-freq-out = <400000>; + qcom,clk-freq-in = <19200000>; + clock-names = "iface_clk", "core_clk"; + clocks = <&clock_gcc GCC_BLSP2_AHB_CLK>, + <&clock_gcc GCC_BLSP2_QUP2_I2C_APPS_CLK>; + pinctrl-names = "i2c_active", "i2c_sleep"; + pinctrl-0 = <&i2c_6_active>; + pinctrl-1 = <&i2c_6_sleep>; + status = "disabled"; + }; + + i2c_7: i2c@c1b7000 { /* BLSP2 QUP3 */ + compatible = "qcom,i2c-msm-v2"; + #address-cells = <1>; + #size-cells = <0>; + reg = <0xc1b7000 0x600>; + reg-names = "qup_phys_addr"; + interrupt-names = "qup_irq"; + interrupts = <0 103 0>; + dmas = <&dma_blsp2 8 64 0x20000020 0x20>, + <&dma_blsp2 9 32 0x20000020 0x20>; + dma-names = "tx", "rx"; + qcom,master-id = <84>; + qcom,clk-freq-out = <400000>; + qcom,clk-freq-in = <19200000>; + clock-names = "iface_clk", "core_clk"; + clocks = <&clock_gcc GCC_BLSP2_AHB_CLK>, + <&clock_gcc GCC_BLSP2_QUP3_I2C_APPS_CLK>; + pinctrl-names = "i2c_active", "i2c_sleep"; + pinctrl-0 = <&i2c_7_active>; + pinctrl-1 = <&i2c_7_sleep>; + status = "disabled"; + }; + + i2c_8: i2c@c1b8000 { /* BLSP2 QUP4 */ + compatible = "qcom,i2c-msm-v2"; + #address-cells = <1>; + #size-cells = <0>; + reg = <0xc1b8000 0x600>; + reg-names = "qup_phys_addr"; + interrupt-names = "qup_irq"; + interrupts = <0 104 0>; + dmas = <&dma_blsp2 10 64 0x20000020 0x20>, + <&dma_blsp2 11 32 0x20000020 0x20>; + dma-names = "tx", "rx"; + qcom,master-id = <84>; + qcom,clk-freq-out = <400000>; + qcom,clk-freq-in = <19200000>; + clock-names = "iface_clk", "core_clk"; + clocks = <&clock_gcc GCC_BLSP2_AHB_CLK>, + <&clock_gcc GCC_BLSP2_QUP4_I2C_APPS_CLK>; + pinctrl-names = "i2c_active", "i2c_sleep"; + pinctrl-0 = <&i2c_8_active>; + pinctrl-1 = <&i2c_8_sleep>; + status = "disabled"; + }; + spi_1: spi@c175000 { /* BLSP1 QUP1 */ compatible = "qcom,spi-qup-v2"; #address-cells = <1>; diff --git a/arch/arm/boot/dts/qcom/msmfalcon-pinctrl.dtsi b/arch/arm/boot/dts/qcom/msmfalcon-pinctrl.dtsi index cb8c11106c57..7a00d1373f15 100644 --- a/arch/arm/boot/dts/qcom/msmfalcon-pinctrl.dtsi +++ b/arch/arm/boot/dts/qcom/msmfalcon-pinctrl.dtsi @@ -113,6 +113,231 @@ }; }; + /* I2C CONFIGURATION */ + i2c_1 { + i2c_1_active: i2c_1_active { + mux { + pins = "gpio2", "gpio3"; + function = "blsp_i2c1"; + }; + + config { + pins = "gpio2", "gpio3"; + drive-strength = <2>; + bias-disable; + }; + }; + + i2c_1_sleep: i2c_1_sleep { + mux { + pins = "gpio2", "gpio3"; + function = "blsp_i2c1"; + }; + + config { + pins = "gpio2", "gpio3"; + drive-strength = <2>; + bias-pull-up; + }; + }; + }; + + i2c_2 { + i2c_2_active: i2c_2_active { + mux { + pins = "gpio6", "gpio7"; + function = "blsp_i2c2"; + }; + + config { + pins = "gpio6", "gpio7"; + drive-strength = <2>; + bias-disable; + }; + }; + + i2c_2_sleep: i2c_2_sleep { + mux { + pins = "gpio6", "gpio7"; + function = "blsp_i2c2"; + }; + + config { + pins = "gpio6", "gpio7"; + drive-strength = <2>; + bias-pull-up; + }; + }; + }; + + i2c_3 { + i2c_3_active: i2c_3_active { + mux { + pins = "gpio10", "gpio11"; + function = "blsp_i2c3"; + }; + + config { + pins = "gpio10", "gpio11"; + drive-strength = <2>; + bias-disable; + }; + }; + + i2c_3_sleep: i2c_3_sleep { + mux { + pins = "gpio10", "gpio11"; + function = "blsp_i2c3"; + }; + + config { + pins = "gpio10", "gpio11"; + drive-strength = <2>; + bias-pull-up; + }; + }; + }; + + i2c_4 { + i2c_4_active: i2c_4_active { + mux { + pins = "gpio14", "gpio15"; + function = "blsp_i2c4"; + }; + + config { + pins = "gpio14", "gpio15"; + drive-strength = <2>; + bias-disable; + }; + }; + + i2c_4_sleep: i2c_4_sleep { + mux { + pins = "gpio14", "gpio15"; + function = "blsp_i2c4"; + }; + + config { + pins = "gpio14", "gpio15"; + drive-strength = <2>; + bias-pull-up; + }; + }; + }; + + i2c_5 { + i2c_5_active: i2c_5_active { + mux { + pins = "gpio18", "gpio19"; + function = "blsp_i2c5"; + }; + + config { + pins = "gpio18", "gpio19"; + drive-strength = <2>; + bias-disable; + }; + }; + + i2c_5_sleep: i2c_5_sleep { + mux { + pins = "gpio18", "gpio19"; + function = "blsp_i2c5"; + }; + + config { + pins = "gpio18", "gpio19"; + drive-strength = <2>; + bias-pull-up; + }; + }; + }; + + i2c_6 { + i2c_6_active: i2c_6_active { + mux { + pins = "gpio22", "gpio23"; + function = "blsp_i2c6"; + }; + + config { + pins = "gpio22", "gpio23"; + drive-strength = <2>; + bias-disable; + }; + }; + + i2c_6_sleep: i2c_6_sleep { + mux { + pins = "gpio22", "gpio23"; + function = "blsp_i2c6"; + }; + + config { + pins = "gpio22", "gpio23"; + drive-strength = <2>; + bias-pull-up; + }; + }; + }; + + i2c_7 { + i2c_7_active: i2c_7_active { + mux { + pins = "gpio26", "gpio27"; + function = "blsp_i2c7"; + }; + + config { + pins = "gpio26", "gpio27"; + drive-strength = <2>; + bias-disable; + }; + }; + + i2c_7_sleep: i2c_7_sleep { + mux { + pins = "gpio26", "gpio27"; + function = "blsp_i2c7"; + }; + + config { + pins = "gpio26", "gpio27"; + drive-strength = <2>; + bias-pull-up; + }; + }; + }; + + i2c_8 { + i2c_8_active: i2c_8_active { + mux { + pins = "gpio30", "gpio31"; + function = "blsp_i2c8_a"; + }; + + config { + pins = "gpio30", "gpio31"; + drive-strength = <2>; + bias-disable; + }; + }; + + i2c_8_sleep: i2c_8_sleep { + mux { + pins = "gpio30", "gpio31"; + function = "blsp_i2c8_a"; + }; + + config { + pins = "gpio30", "gpio31"; + drive-strength = <2>; + bias-pull-up; + }; + }; + }; + /* SPI CONFIGURATION */ spi_1 { spi_1_active: spi_1_active { diff --git a/arch/arm/boot/dts/qcom/msmfalcon.dtsi b/arch/arm/boot/dts/qcom/msmfalcon.dtsi index 473270d6e87d..9f6621b8847b 100644 --- a/arch/arm/boot/dts/qcom/msmfalcon.dtsi +++ b/arch/arm/boot/dts/qcom/msmfalcon.dtsi @@ -249,6 +249,22 @@ clock-frequency = <19200000>; }; + dma_blsp1: qcom,sps-dma@0xc144000{ /* BLSP1 */ + #dma-cells = <4>; + compatible = "qcom,sps-dma"; + reg = <0xc144000 0x1F000>; + interrupts = <0 238 0>; + qcom,summing-threshold = <0x10>; + }; + + dma_blsp2: qcom,sps-dma@0xc184000{ /* BLSP2 */ + #dma-cells = <4>; + compatible = "qcom,sps-dma"; + reg = <0xc184000 0x1F000>; + interrupts = <0 239 0>; + qcom,summing-threshold = <0x10>; + }; + spmi_bus: qcom,spmi@800f000 { compatible = "qcom,spmi-pmic-arb"; reg = <0x800f000 0x1000>, -- cgit v1.2.3 From a67bc21ceacb08ddf71fd128d947d6bede710761 Mon Sep 17 00:00:00 2001 From: Harsh Sahu Date: Fri, 11 Nov 2016 14:10:52 -0800 Subject: msm: mdss: hide additional kernel addresses from unprivileged users Starting commit Ie49eee9478f4657cfb2a994ba60da1ec4c356339 ("msm: mdss: hide kernel addresses from unprevileged users"), display driver removes the %p and uses %pK instead for printing kernel pointers. This change missed some of the prints in some places. This change fixes this by modifying the remaining pointer prints. CRs-Fixed: 987021 Change-Id: I0d1797a4df9ff67f3b162a1b5d26320ca989f54a Signed-off-by: Harsh Sahu Signed-off-by: Abhijit Kulkarni --- drivers/video/fbdev/msm/mdss_dp.c | 2 +- drivers/video/fbdev/msm/mdss_mdp_intf_video.c | 8 ++++---- drivers/video/fbdev/msm/mdss_mdp_overlay.c | 2 +- drivers/video/fbdev/msm/mdss_mdp_pp.c | 14 +++++++------- drivers/video/fbdev/msm/mdss_mdp_pp_cache_config.c | 2 +- drivers/video/fbdev/msm/mhl3/si_mhl2_edid_3d.c | 9 +++++---- 6 files changed, 19 insertions(+), 18 deletions(-) diff --git a/drivers/video/fbdev/msm/mdss_dp.c b/drivers/video/fbdev/msm/mdss_dp.c index 29fc4e6fd65b..b7561e49955b 100644 --- a/drivers/video/fbdev/msm/mdss_dp.c +++ b/drivers/video/fbdev/msm/mdss_dp.c @@ -2068,7 +2068,7 @@ static int mdss_retrieve_dp_ctrl_resources(struct platform_device *pdev, "hdcp_physical")) pr_warn("unable to remap dp hdcp resources\n"); - pr_debug("DP Driver base=%p size=%x\n", + pr_debug("DP Driver base=%pK size=%x\n", dp_drv->base, dp_drv->base_size); mdss_debug_register_base("dp", diff --git a/drivers/video/fbdev/msm/mdss_mdp_intf_video.c b/drivers/video/fbdev/msm/mdss_mdp_intf_video.c index 048e5fce30c6..70b36a08d5ca 100644 --- a/drivers/video/fbdev/msm/mdss_mdp_intf_video.c +++ b/drivers/video/fbdev/msm/mdss_mdp_intf_video.c @@ -960,7 +960,7 @@ static int mdss_mdp_video_intfs_stop(struct mdss_mdp_ctl *ctl, pr_err("Intf %d not in use\n", (inum + MDSS_MDP_INTF0)); return -ENODEV; } - pr_debug("stop ctl=%d video Intf #%d base=%p", ctl->num, ctx->intf_num, + pr_debug("stop ctl=%d video Intf #%d base=%pK", ctl->num, ctx->intf_num, ctx->base); ret = mdss_mdp_video_ctx_stop(ctl, pinfo, ctx); @@ -978,7 +978,7 @@ static int mdss_mdp_video_intfs_stop(struct mdss_mdp_ctl *ctl, pr_err("Intf %d not in use\n", (inum + MDSS_MDP_INTF0)); return -ENODEV; } - pr_debug("stop ctl=%d video Intf #%d base=%p", ctl->num, + pr_debug("stop ctl=%d video Intf #%d base=%pK", ctl->num, sctx->intf_num, sctx->base); ret = mdss_mdp_video_ctx_stop(ctl, pinfo, sctx); @@ -2021,7 +2021,7 @@ static int mdss_mdp_video_intfs_setup(struct mdss_mdp_ctl *ctl, (inum + MDSS_MDP_INTF0)); return -EBUSY; } - pr_debug("video Intf #%d base=%p", ctx->intf_num, ctx->base); + pr_debug("video Intf #%d base=%pK", ctx->intf_num, ctx->base); ctx->ref_cnt++; } else { pr_err("Invalid intf number: %d\n", (inum + MDSS_MDP_INTF0)); @@ -2054,7 +2054,7 @@ static int mdss_mdp_video_intfs_setup(struct mdss_mdp_ctl *ctl, (inum + MDSS_MDP_INTF0)); return -EBUSY; } - pr_debug("video Intf #%d base=%p", ctx->intf_num, ctx->base); + pr_debug("video Intf #%d base=%pK", ctx->intf_num, ctx->base); ctx->ref_cnt++; ctl->intf_ctx[SLAVE_CTX] = ctx; diff --git a/drivers/video/fbdev/msm/mdss_mdp_overlay.c b/drivers/video/fbdev/msm/mdss_mdp_overlay.c index 946e33033ab7..298b8743f0a6 100644 --- a/drivers/video/fbdev/msm/mdss_mdp_overlay.c +++ b/drivers/video/fbdev/msm/mdss_mdp_overlay.c @@ -1533,7 +1533,7 @@ static int __overlay_queue_pipes(struct msm_fb_data_type *mfd) } break; default: - pr_err("invalid state of buf %p=%d\n", + pr_err("invalid state of buf %pK=%d\n", buf, buf->state); BUG(); break; diff --git a/drivers/video/fbdev/msm/mdss_mdp_pp.c b/drivers/video/fbdev/msm/mdss_mdp_pp.c index f79212ea740d..c6bef7c22193 100644 --- a/drivers/video/fbdev/msm/mdss_mdp_pp.c +++ b/drivers/video/fbdev/msm/mdss_mdp_pp.c @@ -2906,7 +2906,7 @@ int mdss_mdp_pp_resume(struct msm_fb_data_type *mfd) mfd->index); return 0; } else if (ret || !ad) { - pr_err("Failed to get ad info: ret = %d, ad = 0x%p.\n", + pr_err("Failed to get ad info: ret = %d, ad = 0x%pK\n", ret, ad); return ret; } @@ -3250,7 +3250,7 @@ static int pp_ad_calc_bl(struct msm_fb_data_type *mfd, int bl_in, int *bl_out, mfd->index); return 0; } else if (ret || !ad) { - pr_err("Failed to get ad info: ret = %d, ad = 0x%p.\n", + pr_err("Failed to get ad info: ret = %d, ad = 0x%pK\n", ret, ad); return ret; } @@ -5754,7 +5754,7 @@ static int pp_ad_invalidate_input(struct msm_fb_data_type *mfd) mfd->index); return 0; } else if (ret || !ad) { - pr_err("Failed to get ad info: ret = %d, ad = 0x%p.\n", + pr_err("Failed to get ad info: ret = %d, ad = 0x%pK\n", ret, ad); return ret; } @@ -5789,7 +5789,7 @@ int mdss_mdp_ad_config(struct msm_fb_data_type *mfd, mfd->index); return ret; } else if (ret || !ad) { - pr_err("Failed to get ad info: ret = %d, ad = 0x%p.\n", + pr_err("Failed to get ad info: ret = %d, ad = 0x%pK\n", ret, ad); return ret; } @@ -5929,7 +5929,7 @@ int mdss_mdp_ad_input(struct msm_fb_data_type *mfd, mfd->index); return ret; } else if (ret || !ad) { - pr_err("Failed to get ad info: ret = %d, ad = 0x%p.\n", + pr_err("Failed to get ad info: ret = %d, ad = 0x%pK\n", ret, ad); return ret; } @@ -6298,7 +6298,7 @@ static int mdss_mdp_ad_ipc_reset(struct msm_fb_data_type *mfd) mfd->index); return 0; } else if (ret || !ad) { - pr_err("Failed to get ad info: ret = %d, ad = 0x%p.\n", + pr_err("Failed to get ad info: ret = %d, ad = 0x%pK\n", ret, ad); return ret; } @@ -6339,7 +6339,7 @@ static int mdss_mdp_ad_setup(struct msm_fb_data_type *mfd) mfd->index); return 0; } else if (ret || !ad) { - pr_err("Failed to get ad info: ret = %d, ad = 0x%p.\n", + pr_err("Failed to get ad info: ret = %d, ad = 0x%pK\n", ret, ad); return ret; } diff --git a/drivers/video/fbdev/msm/mdss_mdp_pp_cache_config.c b/drivers/video/fbdev/msm/mdss_mdp_pp_cache_config.c index 5bd627853c59..e51cf44c2de2 100644 --- a/drivers/video/fbdev/msm/mdss_mdp_pp_cache_config.c +++ b/drivers/video/fbdev/msm/mdss_mdp_pp_cache_config.c @@ -367,7 +367,7 @@ int pp_dither_cache_params(struct mdp_dither_cfg_data *config, { int ret = 0; if (!config || !mdss_pp_res) { - pr_err("invalid param config %pi pp_res %pK\n", + pr_err("invalid param config %pK pp_res %pK\n", config, mdss_pp_res); return -EINVAL; } diff --git a/drivers/video/fbdev/msm/mhl3/si_mhl2_edid_3d.c b/drivers/video/fbdev/msm/mhl3/si_mhl2_edid_3d.c index 20d48575f323..4c9045d6a2a7 100644 --- a/drivers/video/fbdev/msm/mhl3/si_mhl2_edid_3d.c +++ b/drivers/video/fbdev/msm/mhl3/si_mhl2_edid_3d.c @@ -1118,7 +1118,7 @@ static void tx_prune_dtd_list(struct edid_3d_data_t *mhl_edid_3d_data, if ((0 != p_desc->dtd.pixel_clock_low) || (0 != p_desc->dtd.pixel_clock_high)) { MHL_TX_EDID_INFO( - "pix clock non-zero p_desc:%p", p_desc) + "pix clock non-zero p_desc:%pK", p_desc) if ((0 == p_desc->dtd.horz_active_7_0) && (0 == p_desc->dtd.horz_active_blanking_high. horz_active_11_8)) { @@ -1722,9 +1722,10 @@ static void prune_svd_list( ("\n\nInvalid extension size\n\n")); while (pb_src < pb_limit) { MHL_TX_EDID_INFO( - "moving data up %p(0x%02X) " - "<- %p(0x%02X)\n", - pb_dest, (uint16_t)*pb_dest, + "moving data up %pK(0x%02X) ", + pb_dest, (uint16_t)*pb_dest); + MHL_TX_EDID_INFO( + "<- %pK(0x%02X)\n", pb_src, (uint16_t)*pb_src); *pb_dest++ = *pb_src++; } -- cgit v1.2.3 From 268b994d27f35dadadb6246c983be6075b359ad7 Mon Sep 17 00:00:00 2001 From: Zhen Kong Date: Mon, 24 Oct 2016 10:06:45 -0700 Subject: qseecom: improve error checks in qseecom_probe() Make change in qseecom_probe() to improve the error return value checks on some subfunctions, and free memory allocated within qseecom_retrieve_ce_data. CRs-fixed: 1075082 Change-Id: I971e555ec8d02ccf4382e83132a696b065a8ff12 Signed-off-by: Zhen Kong --- drivers/misc/qseecom.c | 47 +++++++++++++++++++++++++++++++++++++---------- 1 file changed, 37 insertions(+), 10 deletions(-) diff --git a/drivers/misc/qseecom.c b/drivers/misc/qseecom.c index 7dc7271b05c1..457629ee4bf5 100644 --- a/drivers/misc/qseecom.c +++ b/drivers/misc/qseecom.c @@ -8125,11 +8125,12 @@ static int qseecom_check_whitelist_feature(void) static int qseecom_probe(struct platform_device *pdev) { int rc; - int ret = 0; + int i; uint32_t feature = 10; struct device *class_dev; struct msm_bus_scale_pdata *qseecom_platform_support = NULL; struct qseecom_command_scm_resp resp; + struct qseecom_ce_info_use *pce_info_use = NULL; qseecom.qsee_bw_count = 0; qseecom.qsee_perf_client = 0; @@ -8171,7 +8172,7 @@ static int qseecom_probe(struct platform_device *pdev) class_dev = device_create(driver_class, NULL, qseecom_device_no, NULL, QSEECOM_DEV); - if (!class_dev) { + if (IS_ERR(class_dev)) { pr_err("class_device_create failed %d\n", rc); rc = -ENOMEM; goto exit_destroy_class; @@ -8210,7 +8211,7 @@ static int qseecom_probe(struct platform_device *pdev) qseecom.pdev = class_dev; /* Create ION msm client */ qseecom.ion_clnt = msm_ion_client_create("qseecom-kernel"); - if (qseecom.ion_clnt == NULL) { + if (IS_ERR_OR_NULL(qseecom.ion_clnt)) { pr_err("Ion client cannot be created\n"); rc = -ENOMEM; goto exit_del_cdev; @@ -8272,14 +8273,14 @@ static int qseecom_probe(struct platform_device *pdev) pr_debug("CE operating frequency is not defined, setting to default 100MHZ\n"); qseecom.ce_opp_freq_hz = QSEE_CE_CLK_100MHZ; } - ret = __qseecom_init_clk(CLK_QSEE); - if (ret) + rc = __qseecom_init_clk(CLK_QSEE); + if (rc) goto exit_destroy_ion_client; if ((qseecom.qsee.instance != qseecom.ce_drv.instance) && (qseecom.support_pfe || qseecom.support_fde)) { - ret = __qseecom_init_clk(CLK_CE_DRV); - if (ret) { + rc = __qseecom_init_clk(CLK_CE_DRV); + if (rc) { __qseecom_deinit_clk(CLK_QSEE); goto exit_destroy_ion_client; } @@ -8333,9 +8334,14 @@ static int qseecom_probe(struct platform_device *pdev) } else { pr_err("Fail to get secure app region info\n"); rc = -EINVAL; - goto exit_destroy_ion_client; + goto exit_deinit_clock; + } + rc = __qseecom_enable_clk(CLK_QSEE); + if (rc) { + pr_err("CLK_QSEE enabling failed (%d)\n", rc); + rc = -EIO; + goto exit_deinit_clock; } - __qseecom_enable_clk(CLK_QSEE); rc = qseecom_scm_call(SCM_SVC_TZSCHEDULER, 1, cmd_buf, cmd_len, &resp, sizeof(resp)); @@ -8344,7 +8350,7 @@ static int qseecom_probe(struct platform_device *pdev) pr_err("send secapp reg fail %d resp.res %d\n", rc, resp.result); rc = -EINVAL; - goto exit_destroy_ion_client; + goto exit_deinit_clock; } } /* @@ -8380,7 +8386,28 @@ static int qseecom_probe(struct platform_device *pdev) atomic_set(&qseecom.qseecom_state, QSEECOM_STATE_READY); return 0; +exit_deinit_clock: + __qseecom_deinit_clk(CLK_QSEE); + if ((qseecom.qsee.instance != qseecom.ce_drv.instance) && + (qseecom.support_pfe || qseecom.support_fde)) + __qseecom_deinit_clk(CLK_CE_DRV); exit_destroy_ion_client: + if (qseecom.ce_info.fde) { + pce_info_use = qseecom.ce_info.fde; + for (i = 0; i < qseecom.ce_info.num_fde; i++) { + kzfree(pce_info_use->ce_pipe_entry); + pce_info_use++; + } + kfree(qseecom.ce_info.fde); + } + if (qseecom.ce_info.pfe) { + pce_info_use = qseecom.ce_info.pfe; + for (i = 0; i < qseecom.ce_info.num_pfe; i++) { + kzfree(pce_info_use->ce_pipe_entry); + pce_info_use++; + } + kfree(qseecom.ce_info.pfe); + } ion_client_destroy(qseecom.ion_clnt); exit_del_cdev: cdev_del(&qseecom.cdev); -- cgit v1.2.3 From 7b553e1abd0af7770907081b4aab83d72043e1fd Mon Sep 17 00:00:00 2001 From: Hemant Kumar Date: Tue, 15 Nov 2016 19:10:42 -0800 Subject: USB: Allow skipping device resume during system resume This allows xHC to remain in low power mode and not resume the bus when system wide resume happens. Controller comes out of low power mode only when usb device issues a remote wakeup or if there is a host initiated bus resume. Change-Id: I96cdcb9e3642906b4afa08d9bde07e123d9b3977 Signed-off-by: Hemant Kumar --- drivers/usb/core/driver.c | 12 ++++++++++++ drivers/usb/host/xhci-plat.c | 4 ++++ include/linux/usb.h | 9 +++++++++ 3 files changed, 25 insertions(+) diff --git a/drivers/usb/core/driver.c b/drivers/usb/core/driver.c index dadd1e8dfe09..26a305f43ff6 100644 --- a/drivers/usb/core/driver.c +++ b/drivers/usb/core/driver.c @@ -1441,6 +1441,9 @@ int usb_suspend(struct device *dev, pm_message_t msg) { struct usb_device *udev = to_usb_device(dev); + if (udev->bus->skip_resume && udev->state == USB_STATE_SUSPENDED) + return 0; + unbind_no_pm_drivers_interfaces(udev); /* From now on we are sure all drivers support suspend/resume @@ -1470,6 +1473,15 @@ int usb_resume(struct device *dev, pm_message_t msg) struct usb_device *udev = to_usb_device(dev); int status; + /* + * Some buses would like to keep their devices in suspend + * state after system resume. Their resume happen when + * a remote wakeup is detected or interface driver start + * I/O. + */ + if (udev->bus->skip_resume) + return 0; + /* For all calls, take the device back to full power and * tell the PM core in case it was autosuspended previously. * Unbind the interfaces that will need rebinding later, diff --git a/drivers/usb/host/xhci-plat.c b/drivers/usb/host/xhci-plat.c index 084dbbc81a6d..1221a80e0bdc 100644 --- a/drivers/usb/host/xhci-plat.c +++ b/drivers/usb/host/xhci-plat.c @@ -167,6 +167,8 @@ static int xhci_plat_probe(struct platform_device *pdev) if (!hcd) return -ENOMEM; + hcd_to_bus(hcd)->skip_resume = true; + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); hcd->regs = devm_ioremap_resource(&pdev->dev, res); if (IS_ERR(hcd->regs)) { @@ -221,6 +223,8 @@ static int xhci_plat_probe(struct platform_device *pdev) goto disable_clk; } + hcd_to_bus(xhci->shared_hcd)->skip_resume = true; + if ((node && of_property_read_bool(node, "usb3-lpm-capable")) || (pdata && pdata->usb3_lpm_capable)) xhci->quirks |= XHCI_LPM_SUPPORT; diff --git a/include/linux/usb.h b/include/linux/usb.h index 440248ba4123..7e6e4665212f 100644 --- a/include/linux/usb.h +++ b/include/linux/usb.h @@ -395,6 +395,15 @@ struct usb_bus { struct mon_bus *mon_bus; /* non-null when associated */ int monitored; /* non-zero when monitored */ #endif + unsigned skip_resume:1; /* All USB devices are brought into full + * power state after system resume. It + * is desirable for some buses to keep + * their devices in suspend state even + * after system resume. The devices + * are resumed later when a remote + * wakeup is detected or an interface + * driver starts I/O. + */ }; struct usb_dev_state; -- cgit v1.2.3 From 76c28263ad5274e8a4b43586c44a4cddeb3036bb Mon Sep 17 00:00:00 2001 From: Skylar Chang Date: Tue, 8 Nov 2016 09:56:24 -0800 Subject: msm: ipa3: linearize large skbs IPA can support scatter-gather of skbs up to the size of the TLV fifo. In case the skb has to many frags, IPA driver will linearize it. Change-Id: I2f994ae0250ffc8f740ea633324815ae429c74be CRs-Fixed: 1088658 Acked-by: Ady Abraham Signed-off-by: Skylar Chang --- drivers/platform/msm/ipa/ipa_v3/ipa_dp.c | 59 ++++++++++++++++++++------------ 1 file changed, 37 insertions(+), 22 deletions(-) diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_dp.c b/drivers/platform/msm/ipa/ipa_v3/ipa_dp.c index 4b0cd46082a3..be2946c873b3 100644 --- a/drivers/platform/msm/ipa/ipa_v3/ipa_dp.c +++ b/drivers/platform/msm/ipa/ipa_v3/ipa_dp.c @@ -1723,6 +1723,7 @@ int ipa3_tx_dp(enum ipa_client_type dst, struct sk_buff *skb, struct ipa3_sys_context *sys; int src_ep_idx; int num_frags, f; + struct ipa_gsi_ep_config *gsi_ep; if (unlikely(!ipa3_ctx)) { IPAERR("IPA3 driver was not initialized\n"); @@ -1734,23 +1735,6 @@ int ipa3_tx_dp(enum ipa_client_type dst, struct sk_buff *skb, return -EINVAL; } - num_frags = skb_shinfo(skb)->nr_frags; - if (num_frags) { - /* 1 desc for tag to resolve status out-of-order issue; - * 1 desc is needed for the linear portion of skb; - * 1 desc may be needed for the PACKET_INIT; - * 1 desc for each frag - */ - desc = kzalloc(sizeof(*desc) * (num_frags + 3), GFP_ATOMIC); - if (!desc) { - IPAERR("failed to alloc desc array\n"); - goto fail_mem; - } - } else { - memset(_desc, 0, 3 * sizeof(struct ipa3_desc)); - desc = &_desc[0]; - } - /* * USB_CONS: PKT_INIT ep_idx = dst pipe * Q6_CONS: PKT_INIT ep_idx = sender pipe @@ -1787,6 +1771,37 @@ int ipa3_tx_dp(enum ipa_client_type dst, struct sk_buff *skb, goto fail_gen; } + num_frags = skb_shinfo(skb)->nr_frags; + /* + * make sure TLV FIFO supports the needed frags. + * 2 descriptors are needed for IP_PACKET_INIT and TAG_STATUS. + * 1 descriptor needed for the linear portion of skb. + */ + gsi_ep = ipa3_get_gsi_ep_info(src_ep_idx); + if (gsi_ep && (num_frags + 3 > gsi_ep->ipa_if_tlv)) { + if (skb_linearize(skb)) { + IPAERR("Failed to linear skb with %d frags\n", + num_frags); + goto fail_gen; + } + num_frags = 0; + } + if (num_frags) { + /* 1 desc for tag to resolve status out-of-order issue; + * 1 desc is needed for the linear portion of skb; + * 1 desc may be needed for the PACKET_INIT; + * 1 desc for each frag + */ + desc = kzalloc(sizeof(*desc) * (num_frags + 3), GFP_ATOMIC); + if (!desc) { + IPAERR("failed to alloc desc array\n"); + goto fail_gen; + } + } else { + memset(_desc, 0, 3 * sizeof(struct ipa3_desc)); + desc = &_desc[0]; + } + if (dst_ep_idx != -1) { /* SW data path */ cmd.destination_pipe_index = dst_ep_idx; @@ -1794,7 +1809,7 @@ int ipa3_tx_dp(enum ipa_client_type dst, struct sk_buff *skb, IPA_IMM_CMD_IP_PACKET_INIT, &cmd, true); if (unlikely(!cmd_pyld)) { IPAERR("failed to construct ip_packet_init imm cmd\n"); - goto fail_gen; + goto fail_mem; } /* the tag field will be populated in ipa3_send() function */ @@ -1863,7 +1878,7 @@ int ipa3_tx_dp(enum ipa_client_type dst, struct sk_buff *skb, if (num_frags == 0) { if (ipa3_send(sys, 2, desc, true)) { IPAERR("fail to send skb %p HWP\n", skb); - goto fail_gen; + goto fail_mem; } } else { for (f = 0; f < num_frags; f++) { @@ -1880,7 +1895,7 @@ int ipa3_tx_dp(enum ipa_client_type dst, struct sk_buff *skb, if (ipa3_send(sys, num_frags + 2, desc, true)) { IPAERR("fail to send skb %p num_frags %u HWP\n", skb, num_frags); - goto fail_gen; + goto fail_mem; } } IPA_STATS_INC_CNT(ipa3_ctx->stats.tx_hw_pkts); @@ -1894,10 +1909,10 @@ int ipa3_tx_dp(enum ipa_client_type dst, struct sk_buff *skb, fail_send: ipahal_destroy_imm_cmd(cmd_pyld); -fail_gen: +fail_mem: if (num_frags) kfree(desc); -fail_mem: +fail_gen: return -EFAULT; } -- cgit v1.2.3 From 8b74c7eb5f0b8badc7d76122d6e359bd43115b58 Mon Sep 17 00:00:00 2001 From: Syed Rameez Mustafa Date: Wed, 9 Nov 2016 17:22:23 -0800 Subject: sched: Remove thread group iteration from colocation Iterating a leader task's thread group in order to add them to a colocation group involves a complex locking chain that ends up causing a deadlock. The deadlock is as follows when the same task is being referenced on three different CPUs: ----- ------ ----- CPU 0 CPU 1 CPU 2 ----- ------ ----- add_task_to_group(p) __schedule(prev = p) write_lock( ttwu(p) related_thread_grp_lock) lock(pi_lock) idle_balance() wait for p->on_cpu load_balance() unable to acquire p->pi_lock send_notification() wait for read_lock( related_thread_grp_lock) unable to set p->on_cpu There are a couple of ways to resolve this deadlock in the kernel, however, they are not trivial. For the sake of simplicity, move the responsibility of thread group iteration back to userspace. This would apply to both adding and removing the leader task from a colocation group. The kernel would continue to automatically add newly forked children of the colocated leader to the colocation group. This still leaves an issue with the locking order of the pi_lock and the related_thread_group_lock. To solve all deadlocks, we need to avoid taking the pi_lock in reset_all_task_stats() and instead rely on a more heavy handed approach of taking all rq locks. The pi_lock was taken to avoid a race between reset_all_task_stats() and sched_exit(). The race can be avoided with rq locks as well. Change-Id: I15323e3ef91401142d3841db59c18fd8fee753fd Signed-off-by: Syed Rameez Mustafa --- kernel/sched/hmp.c | 126 ++++++++++++----------------------------------------- 1 file changed, 28 insertions(+), 98 deletions(-) diff --git a/kernel/sched/hmp.c b/kernel/sched/hmp.c index 30391aae0822..c1c35bb582fb 100644 --- a/kernel/sched/hmp.c +++ b/kernel/sched/hmp.c @@ -3110,37 +3110,9 @@ static void reset_all_task_stats(void) { struct task_struct *g, *p; - read_lock(&tasklist_lock); do_each_thread(g, p) { - raw_spin_lock_irq(&p->pi_lock); reset_task_stats(p); - raw_spin_unlock_irq(&p->pi_lock); } while_each_thread(g, p); - read_unlock(&tasklist_lock); -} - -static void disable_window_stats(void) -{ - unsigned long flags; - int i; - - local_irq_save(flags); - for_each_possible_cpu(i) - raw_spin_lock(&cpu_rq(i)->lock); - - sched_disable_window_stats = 1; - - for_each_possible_cpu(i) - raw_spin_unlock(&cpu_rq(i)->lock); - - local_irq_restore(flags); -} - -/* Called with all cpu's rq->lock held */ -static void enable_window_stats(void) -{ - sched_disable_window_stats = 0; - } enum reset_reason_code { @@ -3166,17 +3138,22 @@ void reset_all_window_stats(u64 window_start, unsigned int window_size) unsigned int old = 0, new = 0; struct related_thread_group *grp; - read_lock(&related_thread_group_lock); - - disable_window_stats(); + local_irq_save(flags); - reset_all_task_stats(); + read_lock(&tasklist_lock); - local_irq_save(flags); + read_lock(&related_thread_group_lock); + /* Taking all runqueue locks prevents race with sched_exit(). */ for_each_possible_cpu(cpu) raw_spin_lock(&cpu_rq(cpu)->lock); + sched_disable_window_stats = 1; + + reset_all_task_stats(); + + read_unlock(&tasklist_lock); + list_for_each_entry(grp, &related_thread_groups, list) { int j; @@ -3196,7 +3173,7 @@ void reset_all_window_stats(u64 window_start, unsigned int window_size) sched_load_granule = sched_ravg_window / NUM_LOAD_INDICES; } - enable_window_stats(); + sched_disable_window_stats = 0; for_each_possible_cpu(cpu) { struct rq *rq = cpu_rq(cpu); @@ -3239,10 +3216,10 @@ void reset_all_window_stats(u64 window_start, unsigned int window_size) for_each_possible_cpu(cpu) raw_spin_unlock(&cpu_rq(cpu)->lock); - local_irq_restore(flags); - read_unlock(&related_thread_group_lock); + local_irq_restore(flags); + trace_sched_reset_all_window_stats(window_start, window_size, sched_ktime_clock() - start_ts, reason, old, new); } @@ -3867,12 +3844,7 @@ static void _set_preferred_cluster(struct related_thread_group *grp) void set_preferred_cluster(struct related_thread_group *grp) { - /* - * Prevent possible deadlock with update_children(). Not updating - * the preferred cluster once is not a big deal. - */ - if (!raw_spin_trylock(&grp->lock)) - return; + raw_spin_lock(&grp->lock); _set_preferred_cluster(grp); raw_spin_unlock(&grp->lock); } @@ -4116,64 +4088,19 @@ static void free_related_thread_group(struct rcu_head *rcu) kfree(grp); } -/* - * The thread group for a task can change while we are here. However, - * add_new_task_to_grp() will take care of any tasks that we miss here. - * When a parent exits, and a child thread is simultaneously exiting, - * sched_set_group_id() will synchronize those operations. - */ -static void update_children(struct task_struct *leader, - struct related_thread_group *grp, int event) -{ - struct task_struct *child; - struct rq *rq; - unsigned long flags; - - if (!thread_group_leader(leader)) - return; - - if (event == ADD_TASK && !sysctl_sched_enable_thread_grouping) - return; - - if (thread_group_empty(leader)) - return; - - child = next_thread(leader); - - do { - rq = task_rq_lock(child, &flags); - - if (event == REM_TASK && child->grp && grp == child->grp) { - transfer_busy_time(rq, grp, child, event); - list_del_init(&child->grp_list); - rcu_assign_pointer(child->grp, NULL); - } else if (event == ADD_TASK && !child->grp) { - transfer_busy_time(rq, grp, child, event); - list_add(&child->grp_list, &grp->tasks); - rcu_assign_pointer(child->grp, grp); - } - - task_rq_unlock(rq, child, &flags); - } while_each_thread(leader, child); - -} - static void remove_task_from_group(struct task_struct *p) { struct related_thread_group *grp = p->grp; struct rq *rq; int empty_group = 1; - unsigned long flags; raw_spin_lock(&grp->lock); - rq = task_rq_lock(p, &flags); + rq = __task_rq_lock(p); transfer_busy_time(rq, p->grp, p, REM_TASK); list_del_init(&p->grp_list); rcu_assign_pointer(p->grp, NULL); - task_rq_unlock(rq, p, &flags); - - update_children(p, grp, REM_TASK); + __task_rq_unlock(rq); if (!list_empty(&grp->tasks)) { empty_group = 0; @@ -4192,7 +4119,6 @@ static int add_task_to_group(struct task_struct *p, struct related_thread_group *grp) { struct rq *rq; - unsigned long flags; raw_spin_lock(&grp->lock); @@ -4200,13 +4126,11 @@ add_task_to_group(struct task_struct *p, struct related_thread_group *grp) * Change p->grp under rq->lock. Will prevent races with read-side * reference of p->grp in various hot-paths */ - rq = task_rq_lock(p, &flags); + rq = __task_rq_lock(p); transfer_busy_time(rq, grp, p, ADD_TASK); list_add(&p->grp_list, &grp->tasks); rcu_assign_pointer(p->grp, grp); - task_rq_unlock(rq, p, &flags); - - update_children(p, grp, ADD_TASK); + __task_rq_unlock(rq); _set_preferred_cluster(grp); @@ -4235,7 +4159,12 @@ void add_new_task_to_grp(struct task_struct *new) grp = task_related_thread_group(parent); rcu_read_unlock(); - /* Its possible that update_children() already added us to the group */ + /* + * It's possible that someone already added the new task to the + * group. A leader's thread group is updated prior to calling + * this function. It's also possible that the leader has exited + * the group. In either case, there is nothing else to do. + */ if (!grp || new->grp) { write_unlock_irqrestore(&related_thread_group_lock, flags); return; @@ -4256,8 +4185,8 @@ int sched_set_group_id(struct task_struct *p, unsigned int group_id) unsigned long flags; struct related_thread_group *grp = NULL; - /* Prevents tasks from exiting while we are managing groups. */ - write_lock_irqsave(&related_thread_group_lock, flags); + raw_spin_lock_irqsave(&p->pi_lock, flags); + write_lock(&related_thread_group_lock); /* Switching from one group to another directly is not permitted */ if ((current != p && p->flags & PF_EXITING) || @@ -4284,7 +4213,8 @@ int sched_set_group_id(struct task_struct *p, unsigned int group_id) BUG_ON(!grp); rc = add_task_to_group(p, grp); done: - write_unlock_irqrestore(&related_thread_group_lock, flags); + write_unlock(&related_thread_group_lock); + raw_spin_unlock_irqrestore(&p->pi_lock, flags); return rc; } -- cgit v1.2.3 From fd5b530593795c9aa145c7f9aa3eb817d3841af3 Mon Sep 17 00:00:00 2001 From: Joonwoo Park Date: Fri, 23 Sep 2016 12:21:55 -0700 Subject: sched: revise boost logic when boost_type is SCHED_BOOST_ON_BIG At present HMP scheduler boost tends to pack tasks by taking into account of power cost and cstate. This is suboptimal to performance as it can lead preemption and higher latency. Revise logic to prefer the least loaded CPU among the big cluster CPUs when boost type is SCHED_BOOST_ON_BIG. New logic still honor the behaviour that scheduler can place tasks on the little CPUs when the big CPUs are all overcommitted. Also, it's found that need_idle with boost can easily return previous CPU when there is no idle CPU found. Fix this issue by making need_idle flag to take precedence over sched_boost. CRs-fixed: 1074879 Change-Id: I470bcd0588e038b4a540d337fe6a412f2fa74920 Signed-off-by: Joonwoo Park Signed-off-by: Syed Rameez Mustafa --- kernel/sched/fair.c | 36 +++++++++++++++++++++++++++++++++--- 1 file changed, 33 insertions(+), 3 deletions(-) diff --git a/kernel/sched/fair.c b/kernel/sched/fair.c index 1674b1054f83..40c2e7ac69e0 100644 --- a/kernel/sched/fair.c +++ b/kernel/sched/fair.c @@ -2596,6 +2596,7 @@ static u32 __compute_runnable_contrib(u64 n) #define SBC_FLAG_COLOC_CLUSTER 0x10000 #define SBC_FLAG_WAKER_CLUSTER 0x20000 #define SBC_FLAG_BACKUP_CLUSTER 0x40000 +#define SBC_FLAG_BOOST_CLUSTER 0x80000 struct cpu_select_env { struct task_struct *p; @@ -2708,6 +2709,18 @@ select_least_power_cluster(struct cpu_select_env *env) env->task_load = scale_load_to_cpu(task_load(env->p), cluster_first_cpu(env->rtg->preferred_cluster)); env->sbc_best_cluster_flag |= SBC_FLAG_COLOC_CLUSTER; + + if (env->boost_type != SCHED_BOOST_NONE) { + for_each_sched_cluster(cluster) { + if (cluster != env->rtg->preferred_cluster) { + __set_bit(cluster->id, + env->backup_list); + __clear_bit(cluster->id, + env->candidate_list); + } + } + } + return env->rtg->preferred_cluster; } @@ -2961,7 +2974,13 @@ static void find_best_cpu_in_cluster(struct sched_cluster *c, update_spare_capacity(stats, env, i, c->capacity, env->cpu_load); - if (env->boost_type == SCHED_BOOST_ON_ALL || + /* + * need_idle takes precedence over sched boost but when both + * are set, idlest CPU with in all the clusters is selected + * when boost_type = BOOST_ON_ALL whereas idlest CPU in the + * big cluster is selected within boost_type = BOOST_ON_BIG. + */ + if ((!env->need_idle && env->boost_type != SCHED_BOOST_NONE) || env->need_waker_cluster || sched_cpu_high_irqload(i) || spill_threshold_crossed(env, cpu_rq(i))) @@ -3178,12 +3197,23 @@ retry: sbc_flag |= env.sbc_best_flag; target = stats.best_cpu; } else { - if (env.rtg) { + if (env.rtg && env.boost_type == SCHED_BOOST_NONE) { env.rtg = NULL; goto retry; } - find_backup_cluster(&env, &stats); + /* + * With boost_type == SCHED_BOOST_ON_BIG, we reach here with + * backup_list = little cluster, candidate_list = none and + * stats->best_capacity_cpu points the best spare capacity + * CPU among the CPUs in the big cluster. + */ + if (env.boost_type == SCHED_BOOST_ON_BIG && + stats.best_capacity_cpu >= 0) + sbc_flag |= SBC_FLAG_BOOST_CLUSTER; + else + find_backup_cluster(&env, &stats); + if (stats.best_capacity_cpu >= 0) { target = stats.best_capacity_cpu; sbc_flag |= SBC_FLAG_BEST_CAP_CPU; -- cgit v1.2.3 From 30fc7742350f45a6b3667880de0a72c68509ccc5 Mon Sep 17 00:00:00 2001 From: Syed Rameez Mustafa Date: Wed, 31 Aug 2016 16:54:12 -0700 Subject: sched/hmp: Enhance co-location and scheduler boost features The recent introduction of the schedtune cgroup controller has provided the scheduler with added flexibility in terms of some of it's placement features. In particular each cgroup under the schedtune controller can now specify: 1) Whether it needs co-location along with other cgroups 2) Whether it is eligible for scheduler boost (sched_boost_enabled) 3) Whether the kernel can override the boost eligibility when necessary (sched_boost_no_override) The scheduler now creates a reserved co-location group at boot. This group is used to co-locate all tasks that form part of any one of the cgroups that have co-location enabled. This reserved group can neither be destroyed nor reused for other purposes. Furthermore, cgroups are only allowed to indicate their co-location preference once at boot. Further updates are disallowed. Since we are now creating co-location groups for an extended period of time, there are a few other factors to consider when determining the preferred cluster for the group. We first exclude any tasks in the group that have not been observed to be running for a significant amount of time. Secondly we introduce the notion of group up and down migrate tunables to allow different migration policies than individual tasks. Lastly we break co-location if a single task in a group exceeds up-migrate but the total load of the group does not exceed group up-migrate. In terms of sched_boost, the scheduler now supports multiple types of boost. These are: 1) FULL_THROTTLE : Force up-migrate tasks belonging any cgroup that has the sched_boost_enabled flag turned on. Little CPUs will only be used when big CPUs can no longer accommodate tasks. Also up-migrate all RT tasks. 2) CONSERVATIVE : Override the sched_boost_enabled flag for all cgroups except those that have the sched_boost_no_override flag set. Force up-migrate all tasks belonging to only those cgroups that still remain eligible for boost. RT tasks do not get force up migrated. 3) RESTRAINED : Start frequency aggregation for co-located tasks. This type of boost does not force up-migrate any task. Finally the boost API removes ref-counting. This means that there can only be a single entity using boost at any given time. If multiple entities are managing boost, they are required to be well behaved so that they don't interfere with one another. Even for a single client, it is not possible to switch directly from one boost type to another. Boost must be first turned off before switching over to a new type. Change-Id: I8d224a70cbef162f27078b62b73acaa22670861d Signed-off-by: Syed Rameez Mustafa --- include/linux/sched/sysctl.h | 2 + include/trace/events/sched.h | 25 +-- kernel/sched/Makefile | 2 +- kernel/sched/boost.c | 226 +++++++++++++++++++++++++ kernel/sched/core.c | 3 +- kernel/sched/fair.c | 131 ++++++++------- kernel/sched/hmp.c | 386 ++++++++++++++++++++----------------------- kernel/sched/rt.c | 12 +- kernel/sched/sched.h | 47 ++++-- kernel/sched/tune.c | 184 +++++++++++++++++++++ kernel/sysctl.c | 19 +++ 11 files changed, 746 insertions(+), 291 deletions(-) create mode 100644 kernel/sched/boost.c diff --git a/include/linux/sched/sysctl.h b/include/linux/sched/sysctl.h index 6848454c5447..5d0899df64ff 100644 --- a/include/linux/sched/sysctl.h +++ b/include/linux/sched/sysctl.h @@ -53,6 +53,8 @@ extern unsigned int sysctl_sched_spill_nr_run; extern unsigned int sysctl_sched_spill_load_pct; extern unsigned int sysctl_sched_upmigrate_pct; extern unsigned int sysctl_sched_downmigrate_pct; +extern unsigned int sysctl_sched_group_upmigrate_pct; +extern unsigned int sysctl_sched_group_downmigrate_pct; extern unsigned int sysctl_early_detection_duration; extern unsigned int sysctl_sched_boost; extern unsigned int sysctl_sched_small_wakee_task_load_pct; diff --git a/include/trace/events/sched.h b/include/trace/events/sched.h index 7778ff3947de..72bbed9ad5db 100644 --- a/include/trace/events/sched.h +++ b/include/trace/events/sched.h @@ -133,6 +133,7 @@ TRACE_EVENT(sched_task_load, __field( u32, flags ) __field( int, best_cpu ) __field( u64, latency ) + __field( int, grp_id ) ), TP_fast_assign( @@ -148,12 +149,13 @@ TRACE_EVENT(sched_task_load, __entry->latency = p->state == TASK_WAKING ? sched_ktime_clock() - p->ravg.mark_start : 0; + __entry->grp_id = p->grp ? p->grp->id : 0; ), - TP_printk("%d (%s): demand=%u boost=%d reason=%d sync=%d need_idle=%d flags=%x best_cpu=%d latency=%llu", + TP_printk("%d (%s): demand=%u boost=%d reason=%d sync=%d need_idle=%d flags=%x grp=%d best_cpu=%d latency=%llu", __entry->pid, __entry->comm, __entry->demand, __entry->boost, __entry->reason, __entry->sync, - __entry->need_idle, __entry->flags, + __entry->need_idle, __entry->flags, __entry->grp_id, __entry->best_cpu, __entry->latency) ); @@ -164,9 +166,12 @@ TRACE_EVENT(sched_set_preferred_cluster, TP_ARGS(grp, total_demand), TP_STRUCT__entry( - __field( int, id ) - __field( u64, demand ) - __field( int, cluster_first_cpu ) + __field( int, id ) + __field( u64, demand ) + __field( int, cluster_first_cpu ) + __array( char, comm, TASK_COMM_LEN ) + __field( pid_t, pid ) + __field(unsigned int, task_demand ) ), TP_fast_assign( @@ -245,19 +250,19 @@ DEFINE_EVENT(sched_cpu_load, sched_cpu_load_cgroup, TRACE_EVENT(sched_set_boost, - TP_PROTO(int ref_count), + TP_PROTO(int type), - TP_ARGS(ref_count), + TP_ARGS(type), TP_STRUCT__entry( - __field(unsigned int, ref_count ) + __field(int, type ) ), TP_fast_assign( - __entry->ref_count = ref_count; + __entry->type = type; ), - TP_printk("ref_count=%d", __entry->ref_count) + TP_printk("type %d", __entry->type) ); #if defined(CREATE_TRACE_POINTS) && defined(CONFIG_SCHED_HMP) diff --git a/kernel/sched/Makefile b/kernel/sched/Makefile index 7d0d34c53e08..7c0382a3eace 100644 --- a/kernel/sched/Makefile +++ b/kernel/sched/Makefile @@ -15,7 +15,7 @@ obj-y += core.o loadavg.o clock.o cputime.o obj-y += idle_task.o fair.o rt.o deadline.o stop_task.o obj-y += wait.o completion.o idle.o sched_avg.o obj-$(CONFIG_SMP) += cpupri.o cpudeadline.o -obj-$(CONFIG_SCHED_HMP) += hmp.o +obj-$(CONFIG_SCHED_HMP) += hmp.o boost.o obj-$(CONFIG_SCHED_AUTOGROUP) += auto_group.o obj-$(CONFIG_SCHEDSTATS) += stats.o obj-$(CONFIG_SCHED_DEBUG) += debug.o diff --git a/kernel/sched/boost.c b/kernel/sched/boost.c new file mode 100644 index 000000000000..fcfda385b74a --- /dev/null +++ b/kernel/sched/boost.c @@ -0,0 +1,226 @@ +/* Copyright (c) 2012-2016, 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 + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include "sched.h" +#include +#include +#include + +/* + * Scheduler boost is a mechanism to temporarily place tasks on CPUs + * with higher capacity than those where a task would have normally + * ended up with their load characteristics. Any entity enabling + * boost is responsible for disabling it as well. + */ + +unsigned int sysctl_sched_boost; +static enum sched_boost_policy boost_policy; +static enum sched_boost_policy boost_policy_dt = SCHED_BOOST_NONE; +static DEFINE_MUTEX(boost_mutex); +static unsigned int freq_aggr_threshold_backup; + +static inline void boost_kick(int cpu) +{ + struct rq *rq = cpu_rq(cpu); + + if (!test_and_set_bit(BOOST_KICK, &rq->hmp_flags)) + smp_send_reschedule(cpu); +} + +static void boost_kick_cpus(void) +{ + int i; + struct cpumask kick_mask; + + if (boost_policy != SCHED_BOOST_ON_BIG) + return; + + cpumask_andnot(&kick_mask, cpu_online_mask, cpu_isolated_mask); + + for_each_cpu(i, &kick_mask) { + if (cpu_capacity(i) != max_capacity) + boost_kick(i); + } +} + +int got_boost_kick(void) +{ + int cpu = smp_processor_id(); + struct rq *rq = cpu_rq(cpu); + + return test_bit(BOOST_KICK, &rq->hmp_flags); +} + +void clear_boost_kick(int cpu) +{ + struct rq *rq = cpu_rq(cpu); + + clear_bit(BOOST_KICK, &rq->hmp_flags); +} + +/* + * Scheduler boost type and boost policy might at first seem unrelated, + * however, there exists a connection between them that will allow us + * to use them interchangeably during placement decisions. We'll explain + * the connection here in one possible way so that the implications are + * clear when looking at placement policies. + * + * When policy = SCHED_BOOST_NONE, type is either none or RESTRAINED + * When policy = SCHED_BOOST_ON_ALL or SCHED_BOOST_ON_BIG, type can + * neither be none nor RESTRAINED. + */ +static void set_boost_policy(int type) +{ + if (type == SCHED_BOOST_NONE || type == RESTRAINED_BOOST) { + boost_policy = SCHED_BOOST_NONE; + return; + } + + if (boost_policy_dt) { + boost_policy = boost_policy_dt; + return; + } + + if (min_possible_efficiency != max_possible_efficiency) { + boost_policy = SCHED_BOOST_ON_BIG; + return; + } + + boost_policy = SCHED_BOOST_ON_ALL; +} + +enum sched_boost_policy sched_boost_policy(void) +{ + return boost_policy; +} + +static bool verify_boost_params(int old_val, int new_val) +{ + /* + * Boost can only be turned on or off. There is no possiblity of + * switching from one boost type to another or to set the same + * kind of boost several times. + */ + return !(!!old_val == !!new_val); +} + +static void _sched_set_boost(int old_val, int type) +{ + switch (type) { + case NO_BOOST: + if (old_val == FULL_THROTTLE_BOOST) + core_ctl_set_boost(false); + else if (old_val == CONSERVATIVE_BOOST) + restore_cgroup_boost_settings(); + else + update_freq_aggregate_threshold( + freq_aggr_threshold_backup); + break; + + case FULL_THROTTLE_BOOST: + core_ctl_set_boost(true); + boost_kick_cpus(); + break; + + case CONSERVATIVE_BOOST: + update_cgroup_boost_settings(); + boost_kick_cpus(); + break; + + case RESTRAINED_BOOST: + freq_aggr_threshold_backup = + update_freq_aggregate_threshold(1); + break; + + default: + WARN_ON(1); + return; + } + + set_boost_policy(type); + sysctl_sched_boost = type; + trace_sched_set_boost(type); +} + +void sched_boost_parse_dt(void) +{ + struct device_node *sn; + const char *boost_policy; + + if (!sched_enable_hmp) + return; + + sn = of_find_node_by_path("/sched-hmp"); + if (!sn) + return; + + if (!of_property_read_string(sn, "boost-policy", &boost_policy)) { + if (!strcmp(boost_policy, "boost-on-big")) + boost_policy_dt = SCHED_BOOST_ON_BIG; + else if (!strcmp(boost_policy, "boost-on-all")) + boost_policy_dt = SCHED_BOOST_ON_ALL; + } +} + +int sched_set_boost(int type) +{ + int ret = 0; + + if (!sched_enable_hmp) + return -EINVAL; + + mutex_lock(&boost_mutex); + + if (verify_boost_params(sysctl_sched_boost, type)) + _sched_set_boost(sysctl_sched_boost, type); + else + ret = -EINVAL; + + mutex_unlock(&boost_mutex); + return ret; +} + +int sched_boost_handler(struct ctl_table *table, int write, + void __user *buffer, size_t *lenp, + loff_t *ppos) +{ + int ret; + unsigned int *data = (unsigned int *)table->data; + unsigned int old_val; + + if (!sched_enable_hmp) + return -EINVAL; + + mutex_lock(&boost_mutex); + + old_val = *data; + ret = proc_dointvec_minmax(table, write, buffer, lenp, ppos); + + if (ret || !write) + goto done; + + if (verify_boost_params(old_val, *data)) { + _sched_set_boost(old_val, *data); + } else { + *data = old_val; + ret = -EINVAL; + } + +done: + mutex_unlock(&boost_mutex); + return ret; +} + +int sched_boost(void) +{ + return sysctl_sched_boost; +} diff --git a/kernel/sched/core.c b/kernel/sched/core.c index 84563da000cf..a5d101e8a5f2 100644 --- a/kernel/sched/core.c +++ b/kernel/sched/core.c @@ -7846,7 +7846,6 @@ void __init sched_init_smp(void) hotcpu_notifier(cpuset_cpu_inactive, CPU_PRI_CPUSET_INACTIVE); update_cluster_topology(); - init_sched_hmp_boost_policy(); init_hrtick(); @@ -7895,7 +7894,7 @@ void __init sched_init(void) BUG_ON(num_possible_cpus() > BITS_PER_LONG); - sched_hmp_parse_dt(); + sched_boost_parse_dt(); init_clusters(); #ifdef CONFIG_FAIR_GROUP_SCHED diff --git a/kernel/sched/fair.c b/kernel/sched/fair.c index 40c2e7ac69e0..3db77aff2433 100644 --- a/kernel/sched/fair.c +++ b/kernel/sched/fair.c @@ -2606,7 +2606,7 @@ struct cpu_select_env { u8 need_waker_cluster:1; u8 sync:1; u8 ignore_prev_cpu:1; - enum sched_boost_type boost_type; + enum sched_boost_policy boost_policy; int prev_cpu; DECLARE_BITMAP(candidate_list, NR_CPUS); DECLARE_BITMAP(backup_list, NR_CPUS); @@ -2706,11 +2706,17 @@ select_least_power_cluster(struct cpu_select_env *env) struct sched_cluster *cluster; if (env->rtg) { - env->task_load = scale_load_to_cpu(task_load(env->p), - cluster_first_cpu(env->rtg->preferred_cluster)); - env->sbc_best_cluster_flag |= SBC_FLAG_COLOC_CLUSTER; + int cpu = cluster_first_cpu(env->rtg->preferred_cluster); + + env->task_load = scale_load_to_cpu(task_load(env->p), cpu); + + if (task_load_will_fit(env->p, env->task_load, + cpu, env->boost_policy)) { + env->sbc_best_cluster_flag |= SBC_FLAG_COLOC_CLUSTER; + + if (env->boost_policy == SCHED_BOOST_NONE) + return env->rtg->preferred_cluster; - if (env->boost_type != SCHED_BOOST_NONE) { for_each_sched_cluster(cluster) { if (cluster != env->rtg->preferred_cluster) { __set_bit(cluster->id, @@ -2719,9 +2725,19 @@ select_least_power_cluster(struct cpu_select_env *env) env->candidate_list); } } + + return env->rtg->preferred_cluster; } - return env->rtg->preferred_cluster; + /* + * Since the task load does not fit on the preferred + * cluster anymore, pretend that the task does not + * have any preferred cluster. This allows the waking + * task to get the appropriate CPU it needs as per the + * non co-location placement policy without having to + * wait until the preferred cluster is updated. + */ + env->rtg = NULL; } for_each_sched_cluster(cluster) { @@ -2731,7 +2747,7 @@ select_least_power_cluster(struct cpu_select_env *env) env->task_load = scale_load_to_cpu(task_load(env->p), cpu); if (task_load_will_fit(env->p, env->task_load, cpu, - env->boost_type)) + env->boost_policy)) return cluster; __set_bit(cluster->id, env->backup_list); @@ -2977,10 +2993,11 @@ static void find_best_cpu_in_cluster(struct sched_cluster *c, /* * need_idle takes precedence over sched boost but when both * are set, idlest CPU with in all the clusters is selected - * when boost_type = BOOST_ON_ALL whereas idlest CPU in the - * big cluster is selected within boost_type = BOOST_ON_BIG. + * when boost_policy = BOOST_ON_ALL whereas idlest CPU in the + * big cluster is selected within boost_policy = BOOST_ON_BIG. */ - if ((!env->need_idle && env->boost_type != SCHED_BOOST_NONE) || + if ((!env->need_idle && + env->boost_policy != SCHED_BOOST_NONE) || env->need_waker_cluster || sched_cpu_high_irqload(i) || spill_threshold_crossed(env, cpu_rq(i))) @@ -3024,7 +3041,7 @@ bias_to_prev_cpu(struct cpu_select_env *env, struct cluster_cpu_stats *stats) struct task_struct *task = env->p; struct sched_cluster *cluster; - if (env->boost_type != SCHED_BOOST_NONE || env->reason || + if (env->boost_policy != SCHED_BOOST_NONE || env->reason || !task->ravg.mark_start || env->need_idle || !sched_short_sleep_task_threshold) return false; @@ -3053,7 +3070,7 @@ bias_to_prev_cpu(struct cpu_select_env *env, struct cluster_cpu_stats *stats) cluster = cpu_rq(prev_cpu)->cluster; if (!task_load_will_fit(task, env->task_load, prev_cpu, - sched_boost_type())) { + sched_boost_policy())) { __set_bit(cluster->id, env->backup_list); __clear_bit(cluster->id, env->candidate_list); @@ -3075,7 +3092,7 @@ bias_to_prev_cpu(struct cpu_select_env *env, struct cluster_cpu_stats *stats) static inline bool wake_to_waker_cluster(struct cpu_select_env *env) { - return env->boost_type == SCHED_BOOST_NONE && + return env->boost_policy == SCHED_BOOST_NONE && !env->need_idle && !env->reason && env->sync && task_load(current) > sched_big_waker_task_load && task_load(env->p) < sched_small_wakee_task_load; @@ -3117,7 +3134,6 @@ static int select_best_cpu(struct task_struct *p, int target, int reason, .reason = reason, .need_idle = wake_to_idle(p), .need_waker_cluster = 0, - .boost_type = sched_boost_type(), .sync = sync, .prev_cpu = target, .ignore_prev_cpu = 0, @@ -3126,6 +3142,9 @@ static int select_best_cpu(struct task_struct *p, int target, int reason, .sbc_best_cluster_flag = 0, }; + env.boost_policy = task_sched_boost(p) ? + sched_boost_policy() : SCHED_BOOST_NONE; + bitmap_copy(env.candidate_list, all_cluster_ids, NR_CPUS); bitmap_zero(env.backup_list, NR_CPUS); @@ -3197,18 +3216,18 @@ retry: sbc_flag |= env.sbc_best_flag; target = stats.best_cpu; } else { - if (env.rtg && env.boost_type == SCHED_BOOST_NONE) { + if (env.rtg && env.boost_policy == SCHED_BOOST_NONE) { env.rtg = NULL; goto retry; } /* - * With boost_type == SCHED_BOOST_ON_BIG, we reach here with + * With boost_policy == SCHED_BOOST_ON_BIG, we reach here with * backup_list = little cluster, candidate_list = none and * stats->best_capacity_cpu points the best spare capacity * CPU among the CPUs in the big cluster. */ - if (env.boost_type == SCHED_BOOST_ON_BIG && + if (env.boost_policy == SCHED_BOOST_ON_BIG && stats.best_capacity_cpu >= 0) sbc_flag |= SBC_FLAG_BOOST_CLUSTER; else @@ -3223,8 +3242,8 @@ retry: out: sbc_flag |= env.sbc_best_cluster_flag; rcu_read_unlock(); - trace_sched_task_load(p, sched_boost(), env.reason, env.sync, - env.need_idle, sbc_flag, target); + trace_sched_task_load(p, sched_boost_policy() && task_sched_boost(p), + env.reason, env.sync, env.need_idle, sbc_flag, target); return target; } @@ -3432,11 +3451,9 @@ static inline int migration_needed(struct task_struct *p, int cpu) if (task_will_be_throttled(p)) return 0; - if (sched_boost_type() == SCHED_BOOST_ON_BIG) { - if (cpu_capacity(cpu) != max_capacity) - return UP_MIGRATION; - return 0; - } + if (sched_boost_policy() == SCHED_BOOST_ON_BIG && + cpu_capacity(cpu) != max_capacity && task_sched_boost(p)) + return UP_MIGRATION; if (sched_cpu_high_irqload(cpu)) return IRQLOAD_MIGRATION; @@ -3450,7 +3467,7 @@ static inline int migration_needed(struct task_struct *p, int cpu) return DOWN_MIGRATION; } - if (!grp && !task_will_fit(p, cpu)) { + if (!task_will_fit(p, cpu)) { rcu_read_unlock(); return UP_MIGRATION; } @@ -6678,10 +6695,7 @@ enum fbq_type { regular, remote, all }; #define LBF_NEED_BREAK 0x02 #define LBF_DST_PINNED 0x04 #define LBF_SOME_PINNED 0x08 -#define LBF_SCHED_BOOST_ACTIVE_BALANCE 0x40 #define LBF_BIG_TASK_ACTIVE_BALANCE 0x80 -#define LBF_HMP_ACTIVE_BALANCE (LBF_SCHED_BOOST_ACTIVE_BALANCE | \ - LBF_BIG_TASK_ACTIVE_BALANCE) #define LBF_IGNORE_BIG_TASKS 0x100 #define LBF_IGNORE_PREFERRED_CLUSTER_TASKS 0x200 #define LBF_MOVED_RELATED_THREAD_GROUP_TASK 0x400 @@ -6712,6 +6726,7 @@ struct lb_env { enum fbq_type fbq_type; struct list_head tasks; + enum sched_boost_policy boost_policy; }; /* @@ -6856,9 +6871,14 @@ int can_migrate_task(struct task_struct *p, struct lb_env *env) /* Record that we found atleast one task that could run on dst_cpu */ env->flags &= ~LBF_ALL_PINNED; - if (cpu_capacity(env->dst_cpu) > cpu_capacity(env->src_cpu) && - nr_big_tasks(env->src_rq) && !is_big_task(p)) - return 0; + if (cpu_capacity(env->dst_cpu) > cpu_capacity(env->src_cpu)) { + if (nr_big_tasks(env->src_rq) && !is_big_task(p)) + return 0; + + if (env->boost_policy == SCHED_BOOST_ON_BIG && + !task_sched_boost(p)) + return 0; + } twf = task_will_fit(p, env->dst_cpu); @@ -6981,8 +7001,7 @@ static int detach_tasks(struct lb_env *env) if (env->imbalance <= 0) return 0; - if (cpu_capacity(env->dst_cpu) < cpu_capacity(env->src_cpu) && - !sched_boost()) + if (cpu_capacity(env->dst_cpu) < cpu_capacity(env->src_cpu)) env->flags |= LBF_IGNORE_BIG_TASKS; else if (!same_cluster(env->dst_cpu, env->src_cpu)) env->flags |= LBF_IGNORE_PREFERRED_CLUSTER_TASKS; @@ -7285,8 +7304,10 @@ bail_inter_cluster_balance(struct lb_env *env, struct sd_lb_stats *sds) int local_capacity, busiest_capacity; int local_pwr_cost, busiest_pwr_cost; int nr_cpus; + int boost = sched_boost(); - if (!sysctl_sched_restrict_cluster_spill || sched_boost()) + if (!sysctl_sched_restrict_cluster_spill || + boost == FULL_THROTTLE_BOOST || boost == CONSERVATIVE_BOOST) return 0; local_cpu = group_first_cpu(sds->local); @@ -7658,11 +7679,6 @@ static bool update_sd_pick_busiest_active_balance(struct lb_env *env, { if (env->idle != CPU_NOT_IDLE && cpu_capacity(env->dst_cpu) > group_rq_capacity(sg)) { - if (sched_boost() && !sds->busiest && sgs->sum_nr_running) { - env->flags |= LBF_SCHED_BOOST_ACTIVE_BALANCE; - return true; - } - if (sgs->sum_nr_big_tasks > sds->busiest_stat.sum_nr_big_tasks) { env->flags |= LBF_BIG_TASK_ACTIVE_BALANCE; @@ -8075,7 +8091,7 @@ static struct sched_group *find_busiest_group(struct lb_env *env) if (!sds.busiest || busiest->sum_nr_running == 0) goto out_balanced; - if (env->flags & LBF_HMP_ACTIVE_BALANCE) + if (env->flags & LBF_BIG_TASK_ACTIVE_BALANCE) goto force_balance; if (bail_inter_cluster_balance(env, &sds)) @@ -8287,7 +8303,7 @@ static int need_active_balance(struct lb_env *env) { struct sched_domain *sd = env->sd; - if (env->flags & LBF_HMP_ACTIVE_BALANCE) + if (env->flags & LBF_BIG_TASK_ACTIVE_BALANCE) return 1; if (env->idle == CPU_NEWLY_IDLE) { @@ -8378,20 +8394,21 @@ static int load_balance(int this_cpu, struct rq *this_rq, struct cpumask *cpus = this_cpu_cpumask_var_ptr(load_balance_mask); struct lb_env env = { - .sd = sd, - .dst_cpu = this_cpu, - .dst_rq = this_rq, - .dst_grpmask = sched_group_cpus(sd->groups), - .idle = idle, - .loop_break = sched_nr_migrate_break, - .cpus = cpus, - .fbq_type = all, - .tasks = LIST_HEAD_INIT(env.tasks), - .imbalance = 0, - .flags = 0, - .loop = 0, + .sd = sd, + .dst_cpu = this_cpu, + .dst_rq = this_rq, + .dst_grpmask = sched_group_cpus(sd->groups), + .idle = idle, + .loop_break = sched_nr_migrate_break, + .cpus = cpus, + .fbq_type = all, + .tasks = LIST_HEAD_INIT(env.tasks), + .imbalance = 0, + .flags = 0, + .loop = 0, .busiest_nr_running = 0, .busiest_grp_capacity = 0, + .boost_policy = sched_boost_policy(), }; /* @@ -8540,7 +8557,7 @@ more_balance: no_move: if (!ld_moved) { - if (!(env.flags & LBF_HMP_ACTIVE_BALANCE)) + if (!(env.flags & LBF_BIG_TASK_ACTIVE_BALANCE)) schedstat_inc(sd, lb_failed[idle]); /* @@ -8550,7 +8567,7 @@ no_move: * excessive cache_hot migrations and active balances. */ if (idle != CPU_NEWLY_IDLE && - !(env.flags & LBF_HMP_ACTIVE_BALANCE)) + !(env.flags & LBF_BIG_TASK_ACTIVE_BALANCE)) sd->nr_balance_failed++; if (need_active_balance(&env)) { @@ -8827,6 +8844,7 @@ static int active_load_balance_cpu_stop(void *data) .busiest_grp_capacity = 0, .flags = 0, .loop = 0, + .boost_policy = sched_boost_policy(), }; bool moved = false; @@ -9302,7 +9320,8 @@ static inline int _nohz_kick_needed_hmp(struct rq *rq, int cpu, int *type) if (rq->nr_running < 2) return 0; - if (!sysctl_sched_restrict_cluster_spill || sched_boost()) + if (!sysctl_sched_restrict_cluster_spill || + sched_boost_policy() == SCHED_BOOST_ON_ALL) return 1; if (cpu_max_power_cost(cpu) == max_power_cost) diff --git a/kernel/sched/hmp.c b/kernel/sched/hmp.c index c1c35bb582fb..968a41e0e81e 100644 --- a/kernel/sched/hmp.c +++ b/kernel/sched/hmp.c @@ -17,8 +17,6 @@ #include #include #include -#include -#include #include "sched.h" @@ -231,52 +229,6 @@ fail: return ret; } -/* - * It is possible that CPUs of the same micro architecture can have slight - * difference in the efficiency due to other factors like cache size. The - * BOOST_ON_BIG policy may not be optimial for such systems. The required - * boost policy can be specified via device tree to handle this. - */ -static int __read_mostly sched_boost_policy = SCHED_BOOST_NONE; - -/* - * This should be called after clusters are populated and - * the respective efficiency values are initialized. - */ -void init_sched_hmp_boost_policy(void) -{ - /* - * Initialize the boost type here if it is not passed from - * device tree. - */ - if (sched_boost_policy == SCHED_BOOST_NONE) { - if (max_possible_efficiency != min_possible_efficiency) - sched_boost_policy = SCHED_BOOST_ON_BIG; - else - sched_boost_policy = SCHED_BOOST_ON_ALL; - } -} - -void sched_hmp_parse_dt(void) -{ - struct device_node *sn; - const char *boost_policy; - - if (!sched_enable_hmp) - return; - - sn = of_find_node_by_path("/sched-hmp"); - if (!sn) - return; - - if (!of_property_read_string(sn, "boost-policy", &boost_policy)) { - if (!strcmp(boost_policy, "boost-on-big")) - sched_boost_policy = SCHED_BOOST_ON_BIG; - else if (!strcmp(boost_policy, "boost-on-all")) - sched_boost_policy = SCHED_BOOST_ON_ALL; - } -} - unsigned int max_possible_efficiency = 1; unsigned int min_possible_efficiency = UINT_MAX; @@ -680,29 +632,6 @@ int __init set_sched_enable_hmp(char *str) early_param("sched_enable_hmp", set_sched_enable_hmp); -int got_boost_kick(void) -{ - int cpu = smp_processor_id(); - struct rq *rq = cpu_rq(cpu); - - return test_bit(BOOST_KICK, &rq->hmp_flags); -} - -inline void clear_boost_kick(int cpu) -{ - struct rq *rq = cpu_rq(cpu); - - clear_bit(BOOST_KICK, &rq->hmp_flags); -} - -inline void boost_kick(int cpu) -{ - struct rq *rq = cpu_rq(cpu); - - if (!test_and_set_bit(BOOST_KICK, &rq->hmp_flags)) - smp_send_reschedule(cpu); -} - /* Clear any HMP scheduler related requests pending from or on cpu */ void clear_hmp_request(int cpu) { @@ -840,6 +769,9 @@ min_max_possible_capacity = 1024; /* min(rq->max_possible_capacity) */ /* Window size (in ns) */ __read_mostly unsigned int sched_ravg_window = MIN_SCHED_RAVG_WINDOW; +/* Maximum allowed threshold before freq aggregation must be enabled */ +#define MAX_FREQ_AGGR_THRESH 1000 + /* Temporarily disable window-stats activity on all cpus */ unsigned int __read_mostly sched_disable_window_stats; @@ -919,8 +851,8 @@ static const unsigned int top_tasks_bitmap_size = * C1 busy time = 5 + 5 + 6 = 16ms * */ -static __read_mostly unsigned int sched_freq_aggregate; -__read_mostly unsigned int sysctl_sched_freq_aggregate; +static __read_mostly unsigned int sched_freq_aggregate = 1; +__read_mostly unsigned int sysctl_sched_freq_aggregate = 1; unsigned int __read_mostly sysctl_sched_freq_aggregate_threshold_pct; static unsigned int __read_mostly sched_freq_aggregate_threshold; @@ -937,14 +869,6 @@ unsigned int max_task_load(void) /* Use this knob to turn on or off HMP-aware task placement logic */ unsigned int __read_mostly sched_enable_hmp; -/* - * Scheduler boost is a mechanism to temporarily place tasks on CPUs - * with higher capacity than those where a task would have normally - * ended up with their load characteristics. Any entity enabling - * boost is responsible for disabling it as well. - */ -unsigned int sysctl_sched_boost; - /* A cpu can no longer accommodate more tasks if: * * rq->nr_running > sysctl_sched_spill_nr_run || @@ -995,6 +919,21 @@ unsigned int __read_mostly sysctl_sched_upmigrate_pct = 80; unsigned int __read_mostly sched_downmigrate; unsigned int __read_mostly sysctl_sched_downmigrate_pct = 60; +/* + * Task groups whose aggregate demand on a cpu is more than + * sched_group_upmigrate need to be up-migrated if possible. + */ +unsigned int __read_mostly sched_group_upmigrate; +unsigned int __read_mostly sysctl_sched_group_upmigrate_pct = 100; + +/* + * Task groups, once up-migrated, will need to drop their aggregate + * demand to less than sched_group_downmigrate before they are "down" + * migrated. + */ +unsigned int __read_mostly sched_group_downmigrate; +unsigned int __read_mostly sysctl_sched_group_downmigrate_pct = 95; + /* * The load scale factor of a CPU gets boosted when its max frequency * is restricted due to which the tasks are migrating to higher capacity @@ -1017,33 +956,46 @@ sched_long_cpu_selection_threshold = 100 * NSEC_PER_MSEC; unsigned int __read_mostly sysctl_sched_restrict_cluster_spill; -void update_up_down_migrate(void) +static void +_update_up_down_migrate(unsigned int *up_migrate, unsigned int *down_migrate) { - unsigned int up_migrate = pct_to_real(sysctl_sched_upmigrate_pct); - unsigned int down_migrate = pct_to_real(sysctl_sched_downmigrate_pct); unsigned int delta; if (up_down_migrate_scale_factor == 1024) - goto done; + return; - delta = up_migrate - down_migrate; + delta = *up_migrate - *down_migrate; - up_migrate /= NSEC_PER_USEC; - up_migrate *= up_down_migrate_scale_factor; - up_migrate >>= 10; - up_migrate *= NSEC_PER_USEC; + *up_migrate /= NSEC_PER_USEC; + *up_migrate *= up_down_migrate_scale_factor; + *up_migrate >>= 10; + *up_migrate *= NSEC_PER_USEC; - up_migrate = min(up_migrate, sched_ravg_window); + *up_migrate = min(*up_migrate, sched_ravg_window); - down_migrate /= NSEC_PER_USEC; - down_migrate *= up_down_migrate_scale_factor; - down_migrate >>= 10; - down_migrate *= NSEC_PER_USEC; + *down_migrate /= NSEC_PER_USEC; + *down_migrate *= up_down_migrate_scale_factor; + *down_migrate >>= 10; + *down_migrate *= NSEC_PER_USEC; - down_migrate = min(down_migrate, up_migrate - delta); -done: + *down_migrate = min(*down_migrate, *up_migrate - delta); +} + +static void update_up_down_migrate(void) +{ + unsigned int up_migrate = pct_to_real(sysctl_sched_upmigrate_pct); + unsigned int down_migrate = pct_to_real(sysctl_sched_downmigrate_pct); + + _update_up_down_migrate(&up_migrate, &down_migrate); sched_upmigrate = up_migrate; sched_downmigrate = down_migrate; + + up_migrate = pct_to_real(sysctl_sched_group_upmigrate_pct); + down_migrate = pct_to_real(sysctl_sched_group_downmigrate_pct); + + _update_up_down_migrate(&up_migrate, &down_migrate); + sched_group_upmigrate = up_migrate; + sched_group_downmigrate = down_migrate; } void set_hmp_defaults(void) @@ -1134,82 +1086,6 @@ u64 cpu_load_sync(int cpu, int sync) return scale_load_to_cpu(cpu_cravg_sync(cpu, sync), cpu); } -static int boost_refcount; -static DEFINE_SPINLOCK(boost_lock); -static DEFINE_MUTEX(boost_mutex); - -static void boost_kick_cpus(void) -{ - int i; - - for_each_online_cpu(i) { - if (cpu_capacity(i) != max_capacity) - boost_kick(i); - } -} - -int sched_boost(void) -{ - return boost_refcount > 0; -} - -int sched_set_boost(int enable) -{ - unsigned long flags; - int ret = 0; - int old_refcount; - - if (!sched_enable_hmp) - return -EINVAL; - - spin_lock_irqsave(&boost_lock, flags); - - old_refcount = boost_refcount; - - if (enable == 1) { - boost_refcount++; - } else if (!enable) { - if (boost_refcount >= 1) - boost_refcount--; - else - ret = -EINVAL; - } else { - ret = -EINVAL; - } - - if (!old_refcount && boost_refcount) - boost_kick_cpus(); - - if (boost_refcount <= 1) - core_ctl_set_boost(boost_refcount == 1); - trace_sched_set_boost(boost_refcount); - spin_unlock_irqrestore(&boost_lock, flags); - - return ret; -} - -int sched_boost_handler(struct ctl_table *table, int write, - void __user *buffer, size_t *lenp, - loff_t *ppos) -{ - int ret; - - mutex_lock(&boost_mutex); - if (!write) - sysctl_sched_boost = sched_boost(); - - ret = proc_dointvec(table, write, buffer, lenp, ppos); - if (ret || !write) - goto done; - - ret = (sysctl_sched_boost <= 1) ? - sched_set_boost(sysctl_sched_boost) : -EINVAL; - -done: - mutex_unlock(&boost_mutex); - return ret; -} - /* * Task will fit on a cpu if it's bandwidth consumption on that cpu * will be less than sched_upmigrate. A big task that was previously @@ -1219,60 +1095,63 @@ done: * tasks with load close to the upmigrate threshold */ int task_load_will_fit(struct task_struct *p, u64 task_load, int cpu, - enum sched_boost_type boost_type) + enum sched_boost_policy boost_policy) { - int upmigrate; + int upmigrate = sched_upmigrate; if (cpu_capacity(cpu) == max_capacity) return 1; - if (boost_type != SCHED_BOOST_ON_BIG) { + if (cpu_capacity(task_cpu(p)) > cpu_capacity(cpu)) + upmigrate = sched_downmigrate; + + if (boost_policy != SCHED_BOOST_ON_BIG) { if (task_nice(p) > SCHED_UPMIGRATE_MIN_NICE || upmigrate_discouraged(p)) return 1; - upmigrate = sched_upmigrate; - if (cpu_capacity(task_cpu(p)) > cpu_capacity(cpu)) - upmigrate = sched_downmigrate; - if (task_load < upmigrate) return 1; + } else { + if (task_sched_boost(p) || task_load >= upmigrate) + return 0; + + return 1; } return 0; } -enum sched_boost_type sched_boost_type(void) -{ - if (sched_boost()) - return sched_boost_policy; - - return SCHED_BOOST_NONE; -} - int task_will_fit(struct task_struct *p, int cpu) { u64 tload = scale_load_to_cpu(task_load(p), cpu); - return task_load_will_fit(p, tload, cpu, sched_boost_type()); + return task_load_will_fit(p, tload, cpu, sched_boost_policy()); } -int group_will_fit(struct sched_cluster *cluster, - struct related_thread_group *grp, u64 demand) +static int +group_will_fit(struct sched_cluster *cluster, struct related_thread_group *grp, + u64 demand, bool group_boost) { int cpu = cluster_first_cpu(cluster); int prev_capacity = 0; - unsigned int threshold = sched_upmigrate; + unsigned int threshold = sched_group_upmigrate; u64 load; if (cluster->capacity == max_capacity) return 1; + if (group_boost) + return 0; + + if (!demand) + return 1; + if (grp->preferred_cluster) prev_capacity = grp->preferred_cluster->capacity; if (cluster->capacity < prev_capacity) - threshold = sched_downmigrate; + threshold = sched_group_downmigrate; load = scale_load_to_cpu(demand, cpu); if (load < threshold) @@ -1495,6 +1374,23 @@ void post_big_task_count_change(const struct cpumask *cpus) DEFINE_MUTEX(policy_mutex); +unsigned int update_freq_aggregate_threshold(unsigned int threshold) +{ + unsigned int old_threshold; + + mutex_lock(&policy_mutex); + + old_threshold = sysctl_sched_freq_aggregate_threshold_pct; + + sysctl_sched_freq_aggregate_threshold_pct = threshold; + sched_freq_aggregate_threshold = + pct_to_real(sysctl_sched_freq_aggregate_threshold_pct); + + mutex_unlock(&policy_mutex); + + return old_threshold; +} + static inline int invalid_value_freq_input(unsigned int *data) { if (data == &sysctl_sched_freq_aggregate) @@ -1578,7 +1474,9 @@ int sched_hmp_proc_update_handler(struct ctl_table *table, int write, if (write && (old_val == *data)) goto done; - if (sysctl_sched_downmigrate_pct > sysctl_sched_upmigrate_pct) { + if (sysctl_sched_downmigrate_pct > sysctl_sched_upmigrate_pct || + sysctl_sched_group_downmigrate_pct > + sysctl_sched_group_upmigrate_pct) { *data = old_val; ret = -EINVAL; goto done; @@ -3801,13 +3699,13 @@ static void check_for_up_down_migrate_update(const struct cpumask *cpus) } /* Return cluster which can offer required capacity for group */ -static struct sched_cluster * -best_cluster(struct related_thread_group *grp, u64 total_demand) +static struct sched_cluster *best_cluster(struct related_thread_group *grp, + u64 total_demand, bool group_boost) { struct sched_cluster *cluster = NULL; for_each_sched_cluster(cluster) { - if (group_will_fit(cluster, grp, total_demand)) + if (group_will_fit(cluster, grp, total_demand, group_boost)) return cluster; } @@ -3818,6 +3716,9 @@ static void _set_preferred_cluster(struct related_thread_group *grp) { struct task_struct *p; u64 combined_demand = 0; + bool boost_on_big = sched_boost_policy() == SCHED_BOOST_ON_BIG; + bool group_boost = false; + u64 wallclock; if (!sysctl_sched_enable_colocation) { grp->last_update = sched_ktime_clock(); @@ -3825,19 +3726,36 @@ static void _set_preferred_cluster(struct related_thread_group *grp) return; } + if (list_empty(&grp->tasks)) + return; + + wallclock = sched_ktime_clock(); + /* * wakeup of two or more related tasks could race with each other and * could result in multiple calls to _set_preferred_cluster being issued * at same time. Avoid overhead in such cases of rechecking preferred * cluster */ - if (sched_ktime_clock() - grp->last_update < sched_ravg_window / 10) + if (wallclock - grp->last_update < sched_ravg_window / 10) return; - list_for_each_entry(p, &grp->tasks, grp_list) + list_for_each_entry(p, &grp->tasks, grp_list) { + if (boost_on_big && task_sched_boost(p)) { + group_boost = true; + break; + } + + if (p->ravg.mark_start < wallclock - + (sched_ravg_window * sched_ravg_hist_size)) + continue; + combined_demand += p->ravg.demand; - grp->preferred_cluster = best_cluster(grp, combined_demand); + } + + grp->preferred_cluster = best_cluster(grp, + combined_demand, group_boost); grp->last_update = sched_ktime_clock(); trace_sched_set_preferred_cluster(grp, combined_demand); } @@ -3852,6 +3770,8 @@ void set_preferred_cluster(struct related_thread_group *grp) #define ADD_TASK 0 #define REM_TASK 1 +#define DEFAULT_CGROUP_COLOC_ID 1 + static inline void free_group_cputime(struct related_thread_group *grp) { free_percpu(grp->cpu_time); @@ -4109,7 +4029,8 @@ static void remove_task_from_group(struct task_struct *p) raw_spin_unlock(&grp->lock); - if (empty_group) { + /* Reserved groups cannot be destroyed */ + if (empty_group && grp->id != DEFAULT_CGROUP_COLOC_ID) { list_del(&grp->list); call_rcu(&grp->rcu, free_related_thread_group); } @@ -4143,20 +4064,25 @@ void add_new_task_to_grp(struct task_struct *new) { unsigned long flags; struct related_thread_group *grp; - struct task_struct *parent; + struct task_struct *leader = new->group_leader; + unsigned int leader_grp_id = sched_get_group_id(leader); - if (!sysctl_sched_enable_thread_grouping) + if (!sysctl_sched_enable_thread_grouping && + leader_grp_id != DEFAULT_CGROUP_COLOC_ID) return; if (thread_group_leader(new)) return; - parent = new->group_leader; + if (leader_grp_id == DEFAULT_CGROUP_COLOC_ID) { + if (!same_schedtune(new, leader)) + return; + } write_lock_irqsave(&related_thread_group_lock, flags); rcu_read_lock(); - grp = task_related_thread_group(parent); + grp = task_related_thread_group(leader); rcu_read_unlock(); /* @@ -4179,6 +4105,47 @@ void add_new_task_to_grp(struct task_struct *new) write_unlock_irqrestore(&related_thread_group_lock, flags); } +#if defined(CONFIG_SCHED_TUNE) && defined(CONFIG_CGROUP_SCHEDTUNE) +/* + * We create a default colocation group at boot. There is no need to + * synchronize tasks between cgroups at creation time because the + * correct cgroup hierarchy is not available at boot. Therefore cgroup + * colocation is turned off by default even though the colocation group + * itself has been allocated. Furthermore this colocation group cannot + * be destroyted once it has been created. All of this has been as part + * of runtime optimizations. + * + * The job of synchronizing tasks to the colocation group is done when + * the colocation flag in the cgroup is turned on. + */ +static int __init create_default_coloc_group(void) +{ + struct related_thread_group *grp = NULL; + unsigned long flags; + + grp = alloc_related_thread_group(DEFAULT_CGROUP_COLOC_ID); + if (IS_ERR(grp)) { + WARN_ON(1); + return -ENOMEM; + } + + write_lock_irqsave(&related_thread_group_lock, flags); + list_add(&grp->list, &related_thread_groups); + write_unlock_irqrestore(&related_thread_group_lock, flags); + + update_freq_aggregate_threshold(MAX_FREQ_AGGR_THRESH); + return 0; +} +late_initcall(create_default_coloc_group); + +int sync_cgroup_colocation(struct task_struct *p, bool insert) +{ + unsigned int grp_id = insert ? DEFAULT_CGROUP_COLOC_ID : 0; + + return sched_set_group_id(p, grp_id); +} +#endif + int sched_set_group_id(struct task_struct *p, unsigned int group_id) { int rc = 0; @@ -4201,6 +4168,12 @@ int sched_set_group_id(struct task_struct *p, unsigned int group_id) grp = lookup_related_thread_group(group_id); if (!grp) { + /* This is a reserved id */ + if (group_id == DEFAULT_CGROUP_COLOC_ID) { + rc = -EINVAL; + goto done; + } + grp = alloc_related_thread_group(group_id); if (IS_ERR(grp)) { rc = -ENOMEM; @@ -4210,7 +4183,6 @@ int sched_set_group_id(struct task_struct *p, unsigned int group_id) list_add(&grp->list, &related_thread_groups); } - BUG_ON(!grp); rc = add_task_to_group(p, grp); done: write_unlock(&related_thread_group_lock); @@ -4459,7 +4431,7 @@ bool early_detection_notify(struct rq *rq, u64 wallclock) struct task_struct *p; int loop_max = 10; - if (!sched_boost() || !rq->cfs.h_nr_running) + if (sched_boost_policy() == SCHED_BOOST_NONE || !rq->cfs.h_nr_running) return 0; rq->ed_task = NULL; diff --git a/kernel/sched/rt.c b/kernel/sched/rt.c index ba4403e910d8..12a04f30ef77 100644 --- a/kernel/sched/rt.c +++ b/kernel/sched/rt.c @@ -1677,8 +1677,13 @@ static int find_lowest_rq_hmp(struct task_struct *task) int prev_cpu = task_cpu(task); u64 cpu_load, min_load = ULLONG_MAX; int i; - int restrict_cluster = sched_boost() ? 0 : - sysctl_sched_restrict_cluster_spill; + int restrict_cluster; + int boost_on_big; + + boost_on_big = sched_boost() == FULL_THROTTLE_BOOST && + sched_boost_policy() == SCHED_BOOST_ON_BIG; + + restrict_cluster = sysctl_sched_restrict_cluster_spill; /* Make sure the mask is initialized first */ if (unlikely(!lowest_mask)) @@ -1697,6 +1702,9 @@ static int find_lowest_rq_hmp(struct task_struct *task) */ for_each_sched_cluster(cluster) { + if (boost_on_big && cluster->capacity != max_possible_capacity) + continue; + cpumask_and(&candidate_mask, &cluster->cpus, lowest_mask); cpumask_andnot(&candidate_mask, &candidate_mask, cpu_isolated_mask); diff --git a/kernel/sched/sched.h b/kernel/sched/sched.h index 4289bf6cd642..30838bb9b442 100644 --- a/kernel/sched/sched.h +++ b/kernel/sched/sched.h @@ -1061,8 +1061,6 @@ extern unsigned int max_load_scale_factor; extern unsigned int max_possible_capacity; extern unsigned int min_max_possible_capacity; extern unsigned int max_power_cost; -extern unsigned int sched_upmigrate; -extern unsigned int sched_downmigrate; extern unsigned int sched_init_task_load_windows; extern unsigned int up_down_migrate_scale_factor; extern unsigned int sysctl_sched_restrict_cluster_spill; @@ -1106,18 +1104,23 @@ extern void sched_account_irqstart(int cpu, struct task_struct *curr, u64 wallclock); extern unsigned int cpu_temp(int cpu); extern unsigned int nr_eligible_big_tasks(int cpu); -extern void update_up_down_migrate(void); extern int update_preferred_cluster(struct related_thread_group *grp, struct task_struct *p, u32 old_load); extern void set_preferred_cluster(struct related_thread_group *grp); extern void add_new_task_to_grp(struct task_struct *new); +extern unsigned int update_freq_aggregate_threshold(unsigned int threshold); -enum sched_boost_type { +enum sched_boost_policy { SCHED_BOOST_NONE, SCHED_BOOST_ON_BIG, SCHED_BOOST_ON_ALL, }; +#define NO_BOOST 0 +#define FULL_THROTTLE_BOOST 1 +#define CONSERVATIVE_BOOST 2 +#define RESTRAINED_BOOST 3 + static inline struct sched_cluster *cpu_cluster(int cpu) { return cpu_rq(cpu)->cluster; @@ -1387,14 +1390,11 @@ extern void set_hmp_defaults(void); extern int power_delta_exceeded(unsigned int cpu_cost, unsigned int base_cost); extern unsigned int power_cost(int cpu, u64 demand); extern void reset_all_window_stats(u64 window_start, unsigned int window_size); -extern void boost_kick(int cpu); extern int sched_boost(void); extern int task_load_will_fit(struct task_struct *p, u64 task_load, int cpu, - enum sched_boost_type boost_type); -extern enum sched_boost_type sched_boost_type(void); + enum sched_boost_policy boost_policy); +extern enum sched_boost_policy sched_boost_policy(void); extern int task_will_fit(struct task_struct *p, int cpu); -extern int group_will_fit(struct sched_cluster *cluster, - struct related_thread_group *grp, u64 demand); extern u64 cpu_load(int cpu); extern u64 cpu_load_sync(int cpu, int sync); extern int preferred_cluster(struct sched_cluster *cluster, @@ -1422,10 +1422,32 @@ extern u64 cpu_upmigrate_discourage_read_u64(struct cgroup_subsys_state *css, struct cftype *cft); extern int cpu_upmigrate_discourage_write_u64(struct cgroup_subsys_state *css, struct cftype *cft, u64 upmigrate_discourage); -extern void sched_hmp_parse_dt(void); -extern void init_sched_hmp_boost_policy(void); +extern void sched_boost_parse_dt(void); extern void clear_top_tasks_bitmap(unsigned long *bitmap); +#if defined(CONFIG_SCHED_TUNE) && defined(CONFIG_CGROUP_SCHEDTUNE) +extern bool task_sched_boost(struct task_struct *p); +extern int sync_cgroup_colocation(struct task_struct *p, bool insert); +extern bool same_schedtune(struct task_struct *tsk1, struct task_struct *tsk2); +extern void update_cgroup_boost_settings(void); +extern void restore_cgroup_boost_settings(void); + +#else +static inline bool +same_schedtune(struct task_struct *tsk1, struct task_struct *tsk2) +{ + return true; +} + +static inline bool task_sched_boost(struct task_struct *p) +{ + return true; +} + +static inline void update_cgroup_boost_settings(void) { } +static inline void restore_cgroup_boost_settings(void) { } +#endif + #else /* CONFIG_SCHED_HMP */ struct hmp_sched_stats; @@ -1615,8 +1637,7 @@ static inline void post_big_task_count_change(void) { } static inline void set_hmp_defaults(void) { } static inline void clear_reserved(int cpu) { } -static inline void sched_hmp_parse_dt(void) {} -static inline void init_sched_hmp_boost_policy(void) {} +static inline void sched_boost_parse_dt(void) {} #define trace_sched_cpu_load(...) #define trace_sched_cpu_load_lb(...) diff --git a/kernel/sched/tune.c b/kernel/sched/tune.c index 4f8182302e5e..ee2af8e0b5ce 100644 --- a/kernel/sched/tune.c +++ b/kernel/sched/tune.c @@ -25,6 +25,33 @@ struct schedtune { /* Boost value for tasks on that SchedTune CGroup */ int boost; +#ifdef CONFIG_SCHED_HMP + /* Toggle ability to override sched boost enabled */ + bool sched_boost_no_override; + + /* + * Controls whether a cgroup is eligible for sched boost or not. This + * can temporariliy be disabled by the kernel based on the no_override + * flag above. + */ + bool sched_boost_enabled; + + /* + * This tracks the default value of sched_boost_enabled and is used + * restore the value following any temporary changes to that flag. + */ + bool sched_boost_enabled_backup; + + /* + * Controls whether tasks of this cgroup should be colocated with each + * other and tasks of other cgroups that have the same flag turned on. + */ + bool colocate; + + /* Controls whether further updates are allowed to the colocate flag */ + bool colocate_update_disabled; +#endif + }; static inline struct schedtune *css_st(struct cgroup_subsys_state *css) @@ -54,6 +81,13 @@ static inline struct schedtune *parent_st(struct schedtune *st) static struct schedtune root_schedtune = { .boost = 0, +#ifdef CONFIG_SCHED_HMP + .sched_boost_no_override = false, + .sched_boost_enabled = true, + .sched_boost_enabled_backup = true, + .colocate = false, + .colocate_update_disabled = false, +#endif }; /* @@ -97,6 +131,121 @@ struct boost_groups { /* Boost groups affecting each CPU in the system */ DEFINE_PER_CPU(struct boost_groups, cpu_boost_groups); +#ifdef CONFIG_SCHED_HMP +static inline void init_sched_boost(struct schedtune *st) +{ + st->sched_boost_no_override = false; + st->sched_boost_enabled = true; + st->sched_boost_enabled_backup = st->sched_boost_enabled; + st->colocate = false; + st->colocate_update_disabled = false; +} + +bool same_schedtune(struct task_struct *tsk1, struct task_struct *tsk2) +{ + return task_schedtune(tsk1) == task_schedtune(tsk2); +} + +void update_cgroup_boost_settings(void) +{ + int i; + + for (i = 0; i < BOOSTGROUPS_COUNT; i++) { + if (!allocated_group[i]) + break; + + if (allocated_group[i]->sched_boost_no_override) + continue; + + allocated_group[i]->sched_boost_enabled = false; + } +} + +void restore_cgroup_boost_settings(void) +{ + int i; + + for (i = 0; i < BOOSTGROUPS_COUNT; i++) { + if (!allocated_group[i]) + break; + + allocated_group[i]->sched_boost_enabled = + allocated_group[i]->sched_boost_enabled_backup; + } +} + +bool task_sched_boost(struct task_struct *p) +{ + struct schedtune *st = task_schedtune(p); + + return st->sched_boost_enabled; +} + +static u64 +sched_boost_override_read(struct cgroup_subsys_state *css, + struct cftype *cft) +{ + struct schedtune *st = css_st(css); + + return st->sched_boost_no_override; +} + +static int sched_boost_override_write(struct cgroup_subsys_state *css, + struct cftype *cft, u64 override) +{ + struct schedtune *st = css_st(css); + + st->sched_boost_no_override = !!override; + + return 0; +} + +static u64 sched_boost_enabled_read(struct cgroup_subsys_state *css, + struct cftype *cft) +{ + struct schedtune *st = css_st(css); + + return st->sched_boost_enabled; +} + +static int sched_boost_enabled_write(struct cgroup_subsys_state *css, + struct cftype *cft, u64 enable) +{ + struct schedtune *st = css_st(css); + + st->sched_boost_enabled = !!enable; + st->sched_boost_enabled_backup = st->sched_boost_enabled; + + return 0; +} + +static u64 sched_colocate_read(struct cgroup_subsys_state *css, + struct cftype *cft) +{ + struct schedtune *st = css_st(css); + + return st->colocate; +} + +static int sched_colocate_write(struct cgroup_subsys_state *css, + struct cftype *cft, u64 colocate) +{ + struct schedtune *st = css_st(css); + + if (st->colocate_update_disabled) + return -EPERM; + + st->colocate = !!colocate; + st->colocate_update_disabled = true; + return 0; +} + +#else /* CONFIG_SCHED_HMP */ + +static inline void init_sched_boost(struct schedtune *st) { } + +#endif /* CONFIG_SCHED_HMP */ + static u64 boost_read(struct cgroup_subsys_state *css, struct cftype *cft) { @@ -121,12 +270,45 @@ boost_write(struct cgroup_subsys_state *css, struct cftype *cft, return 0; } +static void schedtune_attach(struct cgroup_taskset *tset) +{ + struct task_struct *task; + struct cgroup_subsys_state *css; + struct schedtune *st; + bool colocate; + + cgroup_taskset_first(tset, &css); + st = css_st(css); + + colocate = st->colocate; + + cgroup_taskset_for_each(task, css, tset) + sync_cgroup_colocation(task, colocate); +} + static struct cftype files[] = { { .name = "boost", .read_u64 = boost_read, .write_u64 = boost_write, }, +#ifdef CONFIG_SCHED_HMP + { + .name = "sched_boost_no_override", + .read_u64 = sched_boost_override_read, + .write_u64 = sched_boost_override_write, + }, + { + .name = "sched_boost_enabled", + .read_u64 = sched_boost_enabled_read, + .write_u64 = sched_boost_enabled_write, + }, + { + .name = "colocate", + .read_u64 = sched_colocate_read, + .write_u64 = sched_colocate_write, + }, +#endif { } /* terminate */ }; @@ -189,6 +371,7 @@ schedtune_css_alloc(struct cgroup_subsys_state *parent_css) /* Initialize per CPUs boost group support */ st->idx = idx; + init_sched_boost(st); if (schedtune_boostgroup_init(st)) goto release; @@ -222,6 +405,7 @@ struct cgroup_subsys schedtune_cgrp_subsys = { .legacy_cftypes = files, .early_init = 1, .allow_attach = subsys_cgroup_allow_attach, + .attach = schedtune_attach, }; #endif /* CONFIG_CGROUP_SCHEDTUNE */ diff --git a/kernel/sysctl.c b/kernel/sysctl.c index 574316f1c344..b7cbd7940f7b 100644 --- a/kernel/sysctl.c +++ b/kernel/sysctl.c @@ -124,6 +124,7 @@ static int __maybe_unused neg_one = -1; static int zero; static int __maybe_unused one = 1; static int __maybe_unused two = 2; +static int __maybe_unused three = 3; static int __maybe_unused four = 4; static unsigned long one_ul = 1; static int one_hundred = 100; @@ -376,6 +377,22 @@ static struct ctl_table kern_table[] = { .extra1 = &zero, .extra2 = &one_hundred, }, + { + .procname = "sched_group_upmigrate", + .data = &sysctl_sched_group_upmigrate_pct, + .maxlen = sizeof(unsigned int), + .mode = 0644, + .proc_handler = sched_hmp_proc_update_handler, + .extra1 = &zero, + }, + { + .procname = "sched_group_downmigrate", + .data = &sysctl_sched_group_downmigrate_pct, + .maxlen = sizeof(unsigned int), + .mode = 0644, + .proc_handler = sched_hmp_proc_update_handler, + .extra1 = &zero, + }, { .procname = "sched_init_task_load", .data = &sysctl_sched_init_task_load_pct, @@ -487,6 +504,8 @@ static struct ctl_table kern_table[] = { .maxlen = sizeof(unsigned int), .mode = 0644, .proc_handler = sched_boost_handler, + .extra1 = &zero, + .extra2 = &three, }, #endif /* CONFIG_SCHED_HMP */ #ifdef CONFIG_SCHED_DEBUG -- cgit v1.2.3 From e1fa9af20bc3e870e55a16bd7220eb4b1379bea0 Mon Sep 17 00:00:00 2001 From: Venkatesh Yadav Abbarapu Date: Wed, 16 Nov 2016 17:48:48 +0530 Subject: ARM: dts: msm: Add gladiator support on msmfalcon and msmtriton Enable the support for gladiator error reporting. Also enable the gladiator hang detect feature. Change-Id: I7220ad565212c325514301e4c59415b807deb99a Signed-off-by: Venkatesh Yadav Abbarapu --- arch/arm/boot/dts/qcom/msmfalcon.dtsi | 17 +++++++++++++++++ arch/arm/boot/dts/qcom/msmtriton.dtsi | 17 +++++++++++++++++ 2 files changed, 34 insertions(+) diff --git a/arch/arm/boot/dts/qcom/msmfalcon.dtsi b/arch/arm/boot/dts/qcom/msmfalcon.dtsi index 473270d6e87d..c8c756b1bcf2 100644 --- a/arch/arm/boot/dts/qcom/msmfalcon.dtsi +++ b/arch/arm/boot/dts/qcom/msmfalcon.dtsi @@ -873,6 +873,23 @@ reg = <0x94c 200>; }; }; + + qcom,ghd { + compatible = "qcom,gladiator-hang-detect"; + qcom,threshold-arr = <0x179d141c 0x179d1420 + 0x179d1424 0x179d1428 + 0x179d142c 0x179d1430>; + qcom,config-reg = <0x179d1434>; + }; + + qcom,msm-gladiator-v2@17900000 { + compatible = "qcom,msm-gladiator-v2"; + reg = <0x17900000 0xe000>; + reg-names = "gladiator_base"; + interrupts = <0 22 0>; + clock-names = "atb_clk"; + clocks = <&clock_rpmcc RPM_QDSS_CLK>; + }; }; #include "msmfalcon-ion.dtsi" diff --git a/arch/arm/boot/dts/qcom/msmtriton.dtsi b/arch/arm/boot/dts/qcom/msmtriton.dtsi index 06f296a49113..1bc97e9a9615 100644 --- a/arch/arm/boot/dts/qcom/msmtriton.dtsi +++ b/arch/arm/boot/dts/qcom/msmtriton.dtsi @@ -710,6 +710,23 @@ reg = <0x94c 200>; }; }; + + qcom,ghd { + compatible = "qcom,gladiator-hang-detect"; + qcom,threshold-arr = <0x179d141c 0x179d1420 + 0x179d1424 0x179d1428 + 0x179d142c 0x179d1430>; + qcom,config-reg = <0x179d1434>; + }; + + qcom,msm-gladiator-v2@17900000 { + compatible = "qcom,msm-gladiator-v2"; + reg = <0x17900000 0xe000>; + reg-names = "gladiator_base"; + interrupts = <0 22 0>; + clock-names = "atb_clk"; + clocks = <&clock_rpmcc RPM_QDSS_CLK>; + }; }; #include "msmtriton-ion.dtsi" -- cgit v1.2.3 From 640d5e9d1d6185e1a15525b9951151cd8201cbb2 Mon Sep 17 00:00:00 2001 From: Venkatesh Yadav Abbarapu Date: Tue, 15 Nov 2016 11:28:43 +0530 Subject: pinctrl: qcom: msmfalcon: Update gpios as per latest gpio map UART and SPI gpios are changed as per latest hardware definitions, so updating them. Change-Id: I0e06be169edc2eb1d35ef7fc6c41ff1809aebd03 Signed-off-by: Venkatesh Yadav Abbarapu --- drivers/pinctrl/qcom/pinctrl-msmfalcon.c | 31 ++++++++++++++++--------------- 1 file changed, 16 insertions(+), 15 deletions(-) diff --git a/drivers/pinctrl/qcom/pinctrl-msmfalcon.c b/drivers/pinctrl/qcom/pinctrl-msmfalcon.c index 3678f952fe0f..91bbce2ce1d1 100644 --- a/drivers/pinctrl/qcom/pinctrl-msmfalcon.c +++ b/drivers/pinctrl/qcom/pinctrl-msmfalcon.c @@ -748,10 +748,10 @@ static const char * const blsp_i2c5_groups[] = { "gpio18", "gpio19", }; static const char * const blsp_spi6_groups[] = { - "gpio20", "gpio21", "gpio22", "gpio23", + "gpio49", "gpio52", "gpio22", "gpio23", }; static const char * const blsp_uart2_groups[] = { - "gpio20", "gpio21", "gpio22", "gpio23", + "gpio4", "gpio5", "gpio6", "gpio7", }; static const char * const blsp_uim6_groups[] = { "gpio20", "gpio21", @@ -1495,13 +1495,14 @@ static const struct msm_pingroup msmfalcon_groups[] = { NA, NA), PINGROUP(3, SOUTH, blsp_spi1, blsp_uart1, blsp_i2c1, ddr_bist, NA, NA, atest_tsens2, atest_usb1, NA), - PINGROUP(4, NORTH, blsp_spi2, blsp_uim2, NA, phase_flag3, NA, NA, NA, - NA, NA), - PINGROUP(5, SOUTH, blsp_spi2, blsp_uim2, NA, phase_flag14, NA, NA, NA, - NA, NA), - PINGROUP(6, SOUTH, blsp_spi2, blsp_i2c2, NA, phase_flag31, NA, NA, NA, + PINGROUP(4, NORTH, blsp_spi2, blsp_uim2, blsp_uart2, phase_flag3, NA, + NA, NA, NA, NA), + PINGROUP(5, SOUTH, blsp_spi2, blsp_uim2, blsp_uart2, phase_flag14, NA, + NA, NA, NA, NA), + PINGROUP(6, SOUTH, blsp_spi2, blsp_i2c2, blsp_uart2, phase_flag31, NA, + NA, NA, NA, NA), + PINGROUP(7, SOUTH, blsp_spi2, blsp_i2c2, blsp_uart2, NA, NA, NA, NA, NA, NA), - PINGROUP(7, SOUTH, blsp_spi2, blsp_i2c2, NA, NA, NA, NA, NA, NA, NA), PINGROUP(8, NORTH, blsp_spi3, ddr_bist, NA, NA, NA, wlan1_adc1, atest_usb13, bimc_dte1, NA), PINGROUP(9, NORTH, blsp_spi3, ddr_bist, NA, NA, NA, wlan1_adc0, @@ -1526,13 +1527,13 @@ static const struct msm_pingroup msmfalcon_groups[] = { NA, NA), PINGROUP(19, CENTER, blsp_uart5, blsp_spi5, blsp_i2c5, NA, NA, NA, NA, NA, NA), - PINGROUP(20, SOUTH, blsp_spi6, blsp_uart2, blsp_uim6, NA, NA, NA, NA, + PINGROUP(20, SOUTH, NA, NA, blsp_uim6, NA, NA, NA, NA, NA, NA), - PINGROUP(21, SOUTH, blsp_spi6, blsp_uart2, blsp_uim6, NA, phase_flag11, + PINGROUP(21, SOUTH, NA, NA, blsp_uim6, NA, phase_flag11, qdss_cti0_b, vsense_data0, NA, NA), - PINGROUP(22, CENTER, blsp_spi6, blsp_uart2, blsp_i2c6, NA, + PINGROUP(22, CENTER, blsp_spi6, NA, blsp_i2c6, NA, phase_flag12, vsense_data1, NA, NA, NA), - PINGROUP(23, CENTER, blsp_spi6, blsp_uart2, blsp_i2c6, NA, + PINGROUP(23, CENTER, blsp_spi6, NA, blsp_i2c6, NA, phase_flag13, vsense_mode, NA, NA, NA), PINGROUP(24, NORTH, blsp_spi7, blsp_uart6_a, sec_mi2s, sndwire_clk, NA, NA, phase_flag17, vsense_clkout, NA), @@ -1580,13 +1581,13 @@ static const struct msm_pingroup msmfalcon_groups[] = { NA, NA, NA), PINGROUP(48, SOUTH, NA, phase_flag1, qdss_gpio15, NA, NA, NA, NA, NA, NA), - PINGROUP(49, SOUTH, NA, phase_flag2, qdss_cti0_a, NA, NA, NA, NA, NA, - NA), + PINGROUP(49, SOUTH, blsp_spi6, phase_flag2, qdss_cti0_a, NA, NA, NA, + NA, NA, NA), PINGROUP(50, SOUTH, qspi_cs, NA, phase_flag9, qdss_cti0_a, NA, NA, NA, NA, NA), PINGROUP(51, SOUTH, qspi_data3, NA, phase_flag15, qdss_gpio8, NA, NA, NA, NA, NA), - PINGROUP(52, SOUTH, CCI_TIMER2, blsp_spi8_b, blsp_i2c8_b, NA, + PINGROUP(52, SOUTH, CCI_TIMER2, blsp_spi8_b, blsp_i2c8_b, blsp_spi6, phase_flag16, qdss_gpio, NA, NA, NA), PINGROUP(53, NORTH, NA, phase_flag6, qdss_cti1_a, NA, NA, NA, NA, NA, NA), -- cgit v1.2.3 From bc98f9fc6da8bc97b2bbfcbe91317dd8a3f79b74 Mon Sep 17 00:00:00 2001 From: Venkatesh Yadav Abbarapu Date: Mon, 14 Nov 2016 11:34:02 +0530 Subject: ARM: dts: msm: Update the console uart gpios for msmfalcon Updating the debug uart BLSP1UART2 gpios as per the latest hardware definitions. Change-Id: I9cda84d1c199b72ce8b9e2997601bcc7430ddbf3 Signed-off-by: Venkatesh Yadav Abbarapu --- arch/arm/boot/dts/qcom/msmfalcon-pinctrl.dtsi | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/arch/arm/boot/dts/qcom/msmfalcon-pinctrl.dtsi b/arch/arm/boot/dts/qcom/msmfalcon-pinctrl.dtsi index f13e34f8296b..2eb3f67cb6f2 100644 --- a/arch/arm/boot/dts/qcom/msmfalcon-pinctrl.dtsi +++ b/arch/arm/boot/dts/qcom/msmfalcon-pinctrl.dtsi @@ -22,12 +22,12 @@ uart_console_active: uart_console_active { mux { - pins = "gpio0", "gpio1"; - function = "blsp_uart1"; + pins = "gpio4", "gpio5"; + function = "blsp_uart2"; }; config { - pins = "gpio0", "gpio1"; + pins = "gpio4", "gpio5"; drive-strength = <2>; bias-disable; }; -- cgit v1.2.3 From ce5504db5e715033ac6bcdca9c2601e7ec6bcf3a Mon Sep 17 00:00:00 2001 From: Vijayavardhan Vennapusa Date: Wed, 16 Nov 2016 17:27:59 +0530 Subject: ARM: dts: msm: Set USB core clock rate for USB2/USB3 for msm8996 Set required USB core clock rate for USB3 working across connect/ disconnect for msm8996. Else USB enumeration fails after reconnection due to this invalid clock rate setting for USB core clock. Also set USB core clock rate for USB2 controller as well. Change-Id: I6ce48512df5973bf8a2a3081a3a6f8759aeb499f Signed-off-by: Vijayavardhan Vennapusa --- arch/arm/boot/dts/qcom/msm8996.dtsi | 3 +++ 1 file changed, 3 insertions(+) diff --git a/arch/arm/boot/dts/qcom/msm8996.dtsi b/arch/arm/boot/dts/qcom/msm8996.dtsi index 7e88f524367f..2735cfb93be0 100644 --- a/arch/arm/boot/dts/qcom/msm8996.dtsi +++ b/arch/arm/boot/dts/qcom/msm8996.dtsi @@ -1948,6 +1948,8 @@ clock-names = "core_clk", "iface_clk", "bus_aggr_clk", "utmi_clk", "sleep_clk", "xo", "cfg_ahb_clk"; + qcom,core-clk-rate = <120000000>; + resets = <&clock_gcc USB_30_BCR>; reset-names = "core_reset"; @@ -2056,6 +2058,7 @@ <&clock_gcc clk_gcc_usb_phy_cfg_ahb2phy_clk>; clock-names = "core_clk", "iface_clk", "utmi_clk", "sleep_clk", "xo", "cfg_ahb_clk"; + qcom,core-clk-rate = <60000000>; resets = <&clock_gcc USB_20_BCR>; reset-names = "core_reset"; -- cgit v1.2.3 From 1b29a217c2dde266036d5e942abbe342cf6d5677 Mon Sep 17 00:00:00 2001 From: Laxminath Kasam Date: Mon, 14 Nov 2016 17:22:55 +0530 Subject: ASoC: msm: Add support for USB/WCN/TDM Audio Add required machine driver support for USB Audio, BT, FM, TDM interfaces both for internal and external codecs. CRs-Fixed: 1083537 Change-Id: I3d2765535793d6ef9153cfcab4b44a9adad67e15 Signed-off-by: Laxminath Kasam --- sound/soc/msm/msmfalcon-common.c | 1143 +++++++++++++++++++++++++++++-- sound/soc/msm/msmfalcon-common.h | 28 + sound/soc/msm/msmfalcon-ext-dai-links.c | 433 +++++++++++- sound/soc/msm/msmfalcon-external.c | 58 ++ sound/soc/msm/msmfalcon-internal.c | 521 +++++++++++++- 5 files changed, 2122 insertions(+), 61 deletions(-) diff --git a/sound/soc/msm/msmfalcon-common.c b/sound/soc/msm/msmfalcon-common.c index 6c96a0778b52..cdd3af21eaef 100644 --- a/sound/soc/msm/msmfalcon-common.c +++ b/sound/soc/msm/msmfalcon-common.c @@ -28,6 +28,112 @@ #define DEV_NAME_STR_LEN 32 #define DEFAULT_MCLK_RATE 9600000 +struct dev_config { + u32 sample_rate; + u32 bit_format; + u32 channels; +}; + +/* TDM default config */ +static struct dev_config tdm_rx_cfg[TDM_INTERFACE_MAX][TDM_PORT_MAX] = { + { /* PRI TDM */ + {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* RX_0 */ + {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* RX_1 */ + {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* RX_2 */ + {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* RX_3 */ + {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* RX_4 */ + {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* RX_5 */ + {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* RX_6 */ + {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* RX_7 */ + }, + { /* SEC TDM */ + {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* RX_0 */ + {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* RX_1 */ + {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* RX_2 */ + {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* RX_3 */ + {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* RX_4 */ + {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* RX_5 */ + {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* RX_6 */ + {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* RX_7 */ + }, + { /* TERT TDM */ + {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* RX_0 */ + {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* RX_1 */ + {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* RX_2 */ + {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* RX_3 */ + {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* RX_4 */ + {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* RX_5 */ + {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* RX_6 */ + {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* RX_7 */ + }, + { /* QUAT TDM */ + {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* RX_0 */ + {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* RX_1 */ + {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* RX_2 */ + {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* RX_3 */ + {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* RX_4 */ + {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* RX_5 */ + {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* RX_6 */ + {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* RX_7 */ + } +}; + +/* TDM default config */ +static struct dev_config tdm_tx_cfg[TDM_INTERFACE_MAX][TDM_PORT_MAX] = { + { /* PRI TDM */ + {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* TX_0 */ + {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* TX_1 */ + {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* TX_2 */ + {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* TX_3 */ + {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* TX_4 */ + {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* TX_5 */ + {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* TX_6 */ + {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* TX_7 */ + }, + { /* SEC TDM */ + {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* TX_0 */ + {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* TX_1 */ + {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* TX_2 */ + {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* TX_3 */ + {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* TX_4 */ + {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* TX_5 */ + {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* TX_6 */ + {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* TX_7 */ + }, + { /* TERT TDM */ + {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* TX_0 */ + {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* TX_1 */ + {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* TX_2 */ + {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* TX_3 */ + {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* TX_4 */ + {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* TX_5 */ + {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* TX_6 */ + {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* TX_7 */ + }, + { /* QUAT TDM */ + {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* TX_0 */ + {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* TX_1 */ + {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* TX_2 */ + {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* TX_3 */ + {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* TX_4 */ + {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* TX_5 */ + {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* TX_6 */ + {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* TX_7 */ + } +}; + +static struct dev_config usb_rx_cfg = { + .sample_rate = SAMPLING_RATE_48KHZ, + .bit_format = SNDRV_PCM_FORMAT_S16_LE, + .channels = 2, +}; + +static struct dev_config usb_tx_cfg = { + .sample_rate = SAMPLING_RATE_48KHZ, + .bit_format = SNDRV_PCM_FORMAT_S16_LE, + .channels = 1, +}; + enum { PRIM_MI2S = 0, SEC_MI2S, @@ -68,12 +174,6 @@ struct auxpcm_conf { u32 ref_cnt; }; -struct dev_config { - u32 sample_rate; - u32 bit_format; - u32 channels; -}; - struct msm_wsa881x_dev_info { struct device_node *of_node; u32 index; @@ -111,12 +211,6 @@ static struct dev_config proxy_rx_cfg = { .channels = 2, }; -static struct dev_config btsco_cfg = { - .sample_rate = SAMPLING_RATE_8KHZ, - .bit_format = SNDRV_PCM_FORMAT_S16_LE, - .channels = 1, -}; - /* Default configuration of MI2S channels */ static struct dev_config mi2s_rx_cfg[] = { [PRIM_MI2S] = {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 2}, @@ -155,8 +249,22 @@ static char const *mi2s_rate_text[] = {"KHZ_8", "KHZ_16", static const char *const mi2s_ch_text[] = {"One", "Two", "Three", "Four", "Five", "Six", "Seven", "Eight"}; +static char const *bit_format_text[] = {"S16_LE", "S24_LE", "S24_3LE", + "S32_LE"}; +static char const *tdm_ch_text[] = {"One", "Two", "Three", "Four", + "Five", "Six", "Seven", "Eight"}; +static char const *tdm_bit_format_text[] = {"S16_LE", "S24_LE", "S32_LE"}; +static char const *tdm_sample_rate_text[] = {"KHZ_8", "KHZ_16", "KHZ_32", + "KHZ_44P1", "KHZ_48", "KHZ_96", + "KHZ_192", "KHZ_352P8", "KHZ_384"}; +static const char *const usb_ch_text[] = {"One", "Two", "Three", "Four", + "Five", "Six", "Seven", + "Eight"}; +static char const *usb_sample_rate_text[] = {"KHZ_8", "KHZ_11P025", + "KHZ_16", "KHZ_22P05", + "KHZ_32", "KHZ_44P1", "KHZ_48", + "KHZ_96", "KHZ_192", "KHZ_384"}; -static SOC_ENUM_SINGLE_EXT_DECL(btsco_sample_rate, auxpcm_rate_text); static SOC_ENUM_SINGLE_EXT_DECL(proxy_rx_chs, ch_text); static SOC_ENUM_SINGLE_EXT_DECL(prim_aux_pcm_rx_sample_rate, auxpcm_rate_text); static SOC_ENUM_SINGLE_EXT_DECL(sec_aux_pcm_rx_sample_rate, auxpcm_rate_text); @@ -182,6 +290,18 @@ static SOC_ENUM_SINGLE_EXT_DECL(tert_mi2s_rx_chs, mi2s_ch_text); static SOC_ENUM_SINGLE_EXT_DECL(tert_mi2s_tx_chs, mi2s_ch_text); static SOC_ENUM_SINGLE_EXT_DECL(quat_mi2s_rx_chs, mi2s_ch_text); static SOC_ENUM_SINGLE_EXT_DECL(quat_mi2s_tx_chs, mi2s_ch_text); +static SOC_ENUM_SINGLE_EXT_DECL(usb_rx_chs, usb_ch_text); +static SOC_ENUM_SINGLE_EXT_DECL(usb_tx_chs, usb_ch_text); +static SOC_ENUM_SINGLE_EXT_DECL(usb_rx_format, bit_format_text); +static SOC_ENUM_SINGLE_EXT_DECL(usb_tx_format, bit_format_text); +static SOC_ENUM_SINGLE_EXT_DECL(usb_rx_sample_rate, usb_sample_rate_text); +static SOC_ENUM_SINGLE_EXT_DECL(usb_tx_sample_rate, usb_sample_rate_text); +static SOC_ENUM_SINGLE_EXT_DECL(tdm_tx_chs, tdm_ch_text); +static SOC_ENUM_SINGLE_EXT_DECL(tdm_tx_format, tdm_bit_format_text); +static SOC_ENUM_SINGLE_EXT_DECL(tdm_tx_sample_rate, tdm_sample_rate_text); +static SOC_ENUM_SINGLE_EXT_DECL(tdm_rx_chs, tdm_ch_text); +static SOC_ENUM_SINGLE_EXT_DECL(tdm_rx_format, tdm_bit_format_text); +static SOC_ENUM_SINGLE_EXT_DECL(tdm_rx_sample_rate, tdm_sample_rate_text); static struct afe_clk_set mi2s_clk[MI2S_MAX] = { { @@ -242,6 +362,439 @@ static int proxy_rx_ch_put(struct snd_kcontrol *kcontrol, return 1; } +static int tdm_get_sample_rate(int value) +{ + int sample_rate = 0; + + switch (value) { + case 0: + sample_rate = SAMPLING_RATE_8KHZ; + break; + case 1: + sample_rate = SAMPLING_RATE_16KHZ; + break; + case 2: + sample_rate = SAMPLING_RATE_32KHZ; + break; + case 3: + sample_rate = SAMPLING_RATE_44P1KHZ; + break; + case 4: + sample_rate = SAMPLING_RATE_48KHZ; + break; + case 5: + sample_rate = SAMPLING_RATE_96KHZ; + break; + case 6: + sample_rate = SAMPLING_RATE_192KHZ; + break; + case 7: + sample_rate = SAMPLING_RATE_352P8KHZ; + break; + case 8: + sample_rate = SAMPLING_RATE_384KHZ; + break; + default: + sample_rate = SAMPLING_RATE_48KHZ; + break; + } + return sample_rate; +} + +static int tdm_get_sample_rate_val(int sample_rate) +{ + int sample_rate_val = 0; + + switch (sample_rate) { + case SAMPLING_RATE_8KHZ: + sample_rate_val = 0; + break; + case SAMPLING_RATE_16KHZ: + sample_rate_val = 1; + break; + case SAMPLING_RATE_32KHZ: + sample_rate_val = 2; + break; + case SAMPLING_RATE_44P1KHZ: + sample_rate_val = 3; + break; + case SAMPLING_RATE_48KHZ: + sample_rate_val = 4; + break; + case SAMPLING_RATE_96KHZ: + sample_rate_val = 5; + break; + case SAMPLING_RATE_192KHZ: + sample_rate_val = 6; + break; + case SAMPLING_RATE_352P8KHZ: + sample_rate_val = 7; + break; + case SAMPLING_RATE_384KHZ: + sample_rate_val = 8; + break; + default: + sample_rate_val = 4; + break; + } + return sample_rate_val; +} + +static int tdm_get_port_idx(struct snd_kcontrol *kcontrol, + struct tdm_port *port) +{ + if (port) { + if (strnstr(kcontrol->id.name, "PRI", + sizeof(kcontrol->id.name))) { + port->mode = TDM_PRI; + } else if (strnstr(kcontrol->id.name, "SEC", + sizeof(kcontrol->id.name))) { + port->mode = TDM_SEC; + } else if (strnstr(kcontrol->id.name, "TERT", + sizeof(kcontrol->id.name))) { + port->mode = TDM_TERT; + } else if (strnstr(kcontrol->id.name, "QUAT", + sizeof(kcontrol->id.name))) { + port->mode = TDM_QUAT; + } else { + pr_err("%s: unsupported mode in: %s", + __func__, kcontrol->id.name); + return -EINVAL; + } + + if (strnstr(kcontrol->id.name, "RX_0", + sizeof(kcontrol->id.name)) || + strnstr(kcontrol->id.name, "TX_0", + sizeof(kcontrol->id.name))) { + port->channel = TDM_0; + } else if (strnstr(kcontrol->id.name, "RX_1", + sizeof(kcontrol->id.name)) || + strnstr(kcontrol->id.name, "TX_1", + sizeof(kcontrol->id.name))) { + port->channel = TDM_1; + } else if (strnstr(kcontrol->id.name, "RX_2", + sizeof(kcontrol->id.name)) || + strnstr(kcontrol->id.name, "TX_2", + sizeof(kcontrol->id.name))) { + port->channel = TDM_2; + } else if (strnstr(kcontrol->id.name, "RX_3", + sizeof(kcontrol->id.name)) || + strnstr(kcontrol->id.name, "TX_3", + sizeof(kcontrol->id.name))) { + port->channel = TDM_3; + } else if (strnstr(kcontrol->id.name, "RX_4", + sizeof(kcontrol->id.name)) || + strnstr(kcontrol->id.name, "TX_4", + sizeof(kcontrol->id.name))) { + port->channel = TDM_4; + } else if (strnstr(kcontrol->id.name, "RX_5", + sizeof(kcontrol->id.name)) || + strnstr(kcontrol->id.name, "TX_5", + sizeof(kcontrol->id.name))) { + port->channel = TDM_5; + } else if (strnstr(kcontrol->id.name, "RX_6", + sizeof(kcontrol->id.name)) || + strnstr(kcontrol->id.name, "TX_6", + sizeof(kcontrol->id.name))) { + port->channel = TDM_6; + } else if (strnstr(kcontrol->id.name, "RX_7", + sizeof(kcontrol->id.name)) || + strnstr(kcontrol->id.name, "TX_7", + sizeof(kcontrol->id.name))) { + port->channel = TDM_7; + } else { + pr_err("%s: unsupported channel in: %s", + __func__, kcontrol->id.name); + return -EINVAL; + } + } else + return -EINVAL; + return 0; +} + +static int tdm_rx_sample_rate_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct tdm_port port; + int ret = tdm_get_port_idx(kcontrol, &port); + + if (ret) { + pr_err("%s: unsupported control: %s", + __func__, kcontrol->id.name); + } else { + ucontrol->value.enumerated.item[0] = tdm_get_sample_rate_val( + tdm_rx_cfg[port.mode][port.channel].sample_rate); + + pr_debug("%s: tdm_rx_sample_rate = %d, item = %d\n", __func__, + tdm_rx_cfg[port.mode][port.channel].sample_rate, + ucontrol->value.enumerated.item[0]); + } + return ret; +} + +static int tdm_rx_sample_rate_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct tdm_port port; + int ret = tdm_get_port_idx(kcontrol, &port); + + if (ret) { + pr_err("%s: unsupported control: %s", + __func__, kcontrol->id.name); + } else { + tdm_rx_cfg[port.mode][port.channel].sample_rate = + tdm_get_sample_rate(ucontrol->value.enumerated.item[0]); + + pr_debug("%s: tdm_rx_sample_rate = %d, item = %d\n", __func__, + tdm_rx_cfg[port.mode][port.channel].sample_rate, + ucontrol->value.enumerated.item[0]); + } + return ret; +} + +static int tdm_tx_sample_rate_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct tdm_port port; + int ret = tdm_get_port_idx(kcontrol, &port); + + if (ret) { + pr_err("%s: unsupported control: %s", + __func__, kcontrol->id.name); + } else { + ucontrol->value.enumerated.item[0] = tdm_get_sample_rate_val( + tdm_tx_cfg[port.mode][port.channel].sample_rate); + + pr_debug("%s: tdm_tx_sample_rate = %d, item = %d\n", __func__, + tdm_tx_cfg[port.mode][port.channel].sample_rate, + ucontrol->value.enumerated.item[0]); + } + return ret; +} + +static int tdm_tx_sample_rate_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct tdm_port port; + int ret = tdm_get_port_idx(kcontrol, &port); + + if (ret) { + pr_err("%s: unsupported control: %s", + __func__, kcontrol->id.name); + } else { + tdm_tx_cfg[port.mode][port.channel].sample_rate = + tdm_get_sample_rate(ucontrol->value.enumerated.item[0]); + + pr_debug("%s: tdm_tx_sample_rate = %d, item = %d\n", __func__, + tdm_tx_cfg[port.mode][port.channel].sample_rate, + ucontrol->value.enumerated.item[0]); + } + return ret; +} + +static int tdm_get_format(int value) +{ + int format = 0; + + switch (value) { + case 0: + format = SNDRV_PCM_FORMAT_S16_LE; + break; + case 1: + format = SNDRV_PCM_FORMAT_S24_LE; + break; + case 2: + format = SNDRV_PCM_FORMAT_S32_LE; + break; + default: + format = SNDRV_PCM_FORMAT_S16_LE; + break; + } + return format; +} + +static int tdm_get_format_val(int format) +{ + int value = 0; + + switch (format) { + case SNDRV_PCM_FORMAT_S16_LE: + value = 0; + break; + case SNDRV_PCM_FORMAT_S24_LE: + value = 1; + break; + case SNDRV_PCM_FORMAT_S32_LE: + value = 2; + break; + default: + value = 0; + break; + } + return value; +} + +static int tdm_rx_format_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct tdm_port port; + int ret = tdm_get_port_idx(kcontrol, &port); + + if (ret) { + pr_err("%s: unsupported control: %s", + __func__, kcontrol->id.name); + } else { + ucontrol->value.enumerated.item[0] = tdm_get_format_val( + tdm_rx_cfg[port.mode][port.channel].bit_format); + + pr_debug("%s: tdm_rx_bit_format = %d, item = %d\n", __func__, + tdm_rx_cfg[port.mode][port.channel].bit_format, + ucontrol->value.enumerated.item[0]); + } + return ret; +} + +static int tdm_rx_format_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct tdm_port port; + int ret = tdm_get_port_idx(kcontrol, &port); + + if (ret) { + pr_err("%s: unsupported control: %s", + __func__, kcontrol->id.name); + } else { + tdm_rx_cfg[port.mode][port.channel].bit_format = + tdm_get_format(ucontrol->value.enumerated.item[0]); + + pr_debug("%s: tdm_rx_bit_format = %d, item = %d\n", __func__, + tdm_rx_cfg[port.mode][port.channel].bit_format, + ucontrol->value.enumerated.item[0]); + } + return ret; +} + +static int tdm_tx_format_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct tdm_port port; + int ret = tdm_get_port_idx(kcontrol, &port); + + if (ret) { + pr_err("%s: unsupported control: %s", + __func__, kcontrol->id.name); + } else { + ucontrol->value.enumerated.item[0] = tdm_get_format_val( + tdm_tx_cfg[port.mode][port.channel].bit_format); + + pr_debug("%s: tdm_tx_bit_format = %d, item = %d\n", __func__, + tdm_tx_cfg[port.mode][port.channel].bit_format, + ucontrol->value.enumerated.item[0]); + } + return ret; +} + +static int tdm_tx_format_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct tdm_port port; + int ret = tdm_get_port_idx(kcontrol, &port); + + if (ret) { + pr_err("%s: unsupported control: %s", + __func__, kcontrol->id.name); + } else { + tdm_tx_cfg[port.mode][port.channel].bit_format = + tdm_get_format(ucontrol->value.enumerated.item[0]); + + pr_debug("%s: tdm_tx_bit_format = %d, item = %d\n", __func__, + tdm_tx_cfg[port.mode][port.channel].bit_format, + ucontrol->value.enumerated.item[0]); + } + return ret; +} + +static int tdm_rx_ch_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct tdm_port port; + int ret = tdm_get_port_idx(kcontrol, &port); + + if (ret) { + pr_err("%s: unsupported control: %s", + __func__, kcontrol->id.name); + } else { + + ucontrol->value.enumerated.item[0] = + tdm_rx_cfg[port.mode][port.channel].channels - 1; + + pr_debug("%s: tdm_rx_ch = %d, item = %d\n", __func__, + tdm_rx_cfg[port.mode][port.channel].channels - 1, + ucontrol->value.enumerated.item[0]); + } + return ret; +} + +static int tdm_rx_ch_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct tdm_port port; + int ret = tdm_get_port_idx(kcontrol, &port); + + if (ret) { + pr_err("%s: unsupported control: %s", + __func__, kcontrol->id.name); + } else { + tdm_rx_cfg[port.mode][port.channel].channels = + ucontrol->value.enumerated.item[0] + 1; + + pr_debug("%s: tdm_rx_ch = %d, item = %d\n", __func__, + tdm_rx_cfg[port.mode][port.channel].channels, + ucontrol->value.enumerated.item[0] + 1); + } + return ret; +} + +static int tdm_tx_ch_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct tdm_port port; + int ret = tdm_get_port_idx(kcontrol, &port); + + if (ret) { + pr_err("%s: unsupported control: %s", + __func__, kcontrol->id.name); + } else { + ucontrol->value.enumerated.item[0] = + tdm_tx_cfg[port.mode][port.channel].channels - 1; + + pr_debug("%s: tdm_tx_ch = %d, item = %d\n", __func__, + tdm_tx_cfg[port.mode][port.channel].channels - 1, + ucontrol->value.enumerated.item[0]); + } + return ret; +} + +static int tdm_tx_ch_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct tdm_port port; + int ret = tdm_get_port_idx(kcontrol, &port); + + if (ret) { + pr_err("%s: unsupported control: %s", + __func__, kcontrol->id.name); + } else { + tdm_tx_cfg[port.mode][port.channel].channels = + ucontrol->value.enumerated.item[0] + 1; + + pr_debug("%s: tdm_tx_ch = %d, item = %d\n", __func__, + tdm_tx_cfg[port.mode][port.channel].channels, + ucontrol->value.enumerated.item[0] + 1); + } + return ret; +} + static int aux_pcm_get_sample_rate(int value) { int sample_rate; @@ -285,44 +838,18 @@ static int aux_pcm_get_port_idx(struct snd_kcontrol *kcontrol) sizeof("SEC_AUX_PCM"))) idx = SEC_AUX_PCM; else if (strnstr(kcontrol->id.name, "TERT_AUX_PCM", - sizeof("TERT_AUX_PCM"))) - idx = TERT_AUX_PCM; - else if (strnstr(kcontrol->id.name, "QUAT_AUX_PCM", - sizeof("QUAT_AUX_PCM"))) - idx = QUAT_AUX_PCM; - else { - pr_err("%s: unsupported port: %s", - __func__, kcontrol->id.name); - idx = -EINVAL; - } - - return idx; -} - -static int btsco_sample_rate_put(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - btsco_cfg.sample_rate = - aux_pcm_get_sample_rate(ucontrol->value.enumerated.item[0]); - - pr_debug("%s: btsco_sample_rate = %d, item = %d\n", __func__, - btsco_cfg.sample_rate, - ucontrol->value.enumerated.item[0]); - - return 0; -} - -static int btsco_sample_rate_get(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - ucontrol->value.enumerated.item[0] = - aux_pcm_get_sample_rate_val(btsco_cfg.sample_rate); - - pr_debug("%s: btsco_sample_rate = %d, item = %d\n", __func__, - btsco_cfg.sample_rate, - ucontrol->value.enumerated.item[0]); + sizeof("TERT_AUX_PCM"))) + idx = TERT_AUX_PCM; + else if (strnstr(kcontrol->id.name, "QUAT_AUX_PCM", + sizeof("QUAT_AUX_PCM"))) + idx = QUAT_AUX_PCM; + else { + pr_err("%s: unsupported port: %s", + __func__, kcontrol->id.name); + idx = -EINVAL; + } - return 0; + return idx; } static int aux_pcm_rx_sample_rate_put(struct snd_kcontrol *kcontrol, @@ -632,12 +1159,331 @@ static int msm_mi2s_tx_ch_put(struct snd_kcontrol *kcontrol, return 1; } +static int usb_audio_rx_ch_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + pr_debug("%s: usb_audio_rx_ch = %d\n", __func__, + usb_rx_cfg.channels); + ucontrol->value.integer.value[0] = usb_rx_cfg.channels - 1; + return 0; +} + +static int usb_audio_rx_ch_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + usb_rx_cfg.channels = ucontrol->value.integer.value[0] + 1; + + pr_debug("%s: usb_audio_rx_ch = %d\n", __func__, usb_rx_cfg.channels); + return 1; +} + +static int usb_audio_rx_sample_rate_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + int sample_rate_val; + + switch (usb_rx_cfg.sample_rate) { + case SAMPLING_RATE_384KHZ: + sample_rate_val = 9; + break; + case SAMPLING_RATE_192KHZ: + sample_rate_val = 8; + break; + case SAMPLING_RATE_96KHZ: + sample_rate_val = 7; + break; + case SAMPLING_RATE_48KHZ: + sample_rate_val = 6; + break; + case SAMPLING_RATE_44P1KHZ: + sample_rate_val = 5; + break; + case SAMPLING_RATE_32KHZ: + sample_rate_val = 4; + break; + case SAMPLING_RATE_22P05KHZ: + sample_rate_val = 3; + break; + case SAMPLING_RATE_16KHZ: + sample_rate_val = 2; + break; + case SAMPLING_RATE_11P025KHZ: + sample_rate_val = 1; + break; + case SAMPLING_RATE_8KHZ: + default: + sample_rate_val = 0; + break; + } + + ucontrol->value.integer.value[0] = sample_rate_val; + pr_debug("%s: usb_audio_rx_sample_rate = %d\n", __func__, + usb_rx_cfg.sample_rate); + return 0; +} + +static int usb_audio_rx_sample_rate_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + switch (ucontrol->value.integer.value[0]) { + case 9: + usb_rx_cfg.sample_rate = SAMPLING_RATE_384KHZ; + break; + case 8: + usb_rx_cfg.sample_rate = SAMPLING_RATE_192KHZ; + break; + case 7: + usb_rx_cfg.sample_rate = SAMPLING_RATE_96KHZ; + break; + case 6: + usb_rx_cfg.sample_rate = SAMPLING_RATE_48KHZ; + break; + case 5: + usb_rx_cfg.sample_rate = SAMPLING_RATE_44P1KHZ; + break; + case 4: + usb_rx_cfg.sample_rate = SAMPLING_RATE_32KHZ; + break; + case 3: + usb_rx_cfg.sample_rate = SAMPLING_RATE_22P05KHZ; + break; + case 2: + usb_rx_cfg.sample_rate = SAMPLING_RATE_16KHZ; + break; + case 1: + usb_rx_cfg.sample_rate = SAMPLING_RATE_11P025KHZ; + break; + case 0: + usb_rx_cfg.sample_rate = SAMPLING_RATE_8KHZ; + break; + default: + usb_rx_cfg.sample_rate = SAMPLING_RATE_48KHZ; + break; + } + + pr_debug("%s: control value = %ld, usb_audio_rx_sample_rate = %d\n", + __func__, ucontrol->value.integer.value[0], + usb_rx_cfg.sample_rate); + return 0; +} + +static int usb_audio_rx_format_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + switch (usb_rx_cfg.bit_format) { + case SNDRV_PCM_FORMAT_S32_LE: + ucontrol->value.integer.value[0] = 3; + break; + case SNDRV_PCM_FORMAT_S24_3LE: + ucontrol->value.integer.value[0] = 2; + break; + case SNDRV_PCM_FORMAT_S24_LE: + ucontrol->value.integer.value[0] = 1; + break; + case SNDRV_PCM_FORMAT_S16_LE: + default: + ucontrol->value.integer.value[0] = 0; + break; + } + + pr_debug("%s: usb_audio_rx_format = %d, ucontrol value = %ld\n", + __func__, usb_rx_cfg.bit_format, + ucontrol->value.integer.value[0]); + return 0; +} + +static int usb_audio_rx_format_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + int rc = 0; + + switch (ucontrol->value.integer.value[0]) { + case 3: + usb_rx_cfg.bit_format = SNDRV_PCM_FORMAT_S32_LE; + break; + case 2: + usb_rx_cfg.bit_format = SNDRV_PCM_FORMAT_S24_3LE; + break; + case 1: + usb_rx_cfg.bit_format = SNDRV_PCM_FORMAT_S24_LE; + break; + case 0: + default: + usb_rx_cfg.bit_format = SNDRV_PCM_FORMAT_S16_LE; + break; + } + pr_debug("%s: usb_audio_rx_format = %d, ucontrol value = %ld\n", + __func__, usb_rx_cfg.bit_format, + ucontrol->value.integer.value[0]); + + return rc; +} + +static int usb_audio_tx_ch_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + pr_debug("%s: usb_audio_tx_ch = %d\n", __func__, + usb_tx_cfg.channels); + ucontrol->value.integer.value[0] = usb_tx_cfg.channels - 1; + return 0; +} + +static int usb_audio_tx_ch_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + usb_tx_cfg.channels = ucontrol->value.integer.value[0] + 1; + + pr_debug("%s: usb_audio_tx_ch = %d\n", __func__, usb_tx_cfg.channels); + return 1; +} + +static int usb_audio_tx_sample_rate_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + int sample_rate_val; + + switch (usb_tx_cfg.sample_rate) { + case SAMPLING_RATE_384KHZ: + sample_rate_val = 9; + break; + case SAMPLING_RATE_192KHZ: + sample_rate_val = 8; + break; + case SAMPLING_RATE_96KHZ: + sample_rate_val = 7; + break; + case SAMPLING_RATE_48KHZ: + sample_rate_val = 6; + break; + case SAMPLING_RATE_44P1KHZ: + sample_rate_val = 5; + break; + case SAMPLING_RATE_32KHZ: + sample_rate_val = 4; + break; + case SAMPLING_RATE_22P05KHZ: + sample_rate_val = 3; + break; + case SAMPLING_RATE_16KHZ: + sample_rate_val = 2; + break; + case SAMPLING_RATE_11P025KHZ: + sample_rate_val = 1; + break; + case SAMPLING_RATE_8KHZ: + sample_rate_val = 0; + break; + default: + sample_rate_val = 6; + break; + } + + ucontrol->value.integer.value[0] = sample_rate_val; + pr_debug("%s: usb_audio_tx_sample_rate = %d\n", __func__, + usb_tx_cfg.sample_rate); + return 0; +} + +static int usb_audio_tx_sample_rate_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + switch (ucontrol->value.integer.value[0]) { + case 9: + usb_tx_cfg.sample_rate = SAMPLING_RATE_384KHZ; + break; + case 8: + usb_tx_cfg.sample_rate = SAMPLING_RATE_192KHZ; + break; + case 7: + usb_tx_cfg.sample_rate = SAMPLING_RATE_96KHZ; + break; + case 6: + usb_tx_cfg.sample_rate = SAMPLING_RATE_48KHZ; + break; + case 5: + usb_tx_cfg.sample_rate = SAMPLING_RATE_44P1KHZ; + break; + case 4: + usb_tx_cfg.sample_rate = SAMPLING_RATE_32KHZ; + break; + case 3: + usb_tx_cfg.sample_rate = SAMPLING_RATE_22P05KHZ; + break; + case 2: + usb_tx_cfg.sample_rate = SAMPLING_RATE_16KHZ; + break; + case 1: + usb_tx_cfg.sample_rate = SAMPLING_RATE_11P025KHZ; + break; + case 0: + usb_tx_cfg.sample_rate = SAMPLING_RATE_8KHZ; + break; + default: + usb_tx_cfg.sample_rate = SAMPLING_RATE_48KHZ; + break; + } + + pr_debug("%s: control value = %ld, usb_audio_tx_sample_rate = %d\n", + __func__, ucontrol->value.integer.value[0], + usb_tx_cfg.sample_rate); + return 0; +} + +static int usb_audio_tx_format_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + switch (usb_tx_cfg.bit_format) { + case SNDRV_PCM_FORMAT_S32_LE: + ucontrol->value.integer.value[0] = 3; + break; + case SNDRV_PCM_FORMAT_S24_3LE: + ucontrol->value.integer.value[0] = 2; + break; + case SNDRV_PCM_FORMAT_S24_LE: + ucontrol->value.integer.value[0] = 1; + break; + case SNDRV_PCM_FORMAT_S16_LE: + default: + ucontrol->value.integer.value[0] = 0; + break; + } + + pr_debug("%s: usb_audio_tx_format = %d, ucontrol value = %ld\n", + __func__, usb_tx_cfg.bit_format, + ucontrol->value.integer.value[0]); + return 0; +} + +static int usb_audio_tx_format_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + int rc = 0; + + switch (ucontrol->value.integer.value[0]) { + case 3: + usb_tx_cfg.bit_format = SNDRV_PCM_FORMAT_S32_LE; + break; + case 2: + usb_tx_cfg.bit_format = SNDRV_PCM_FORMAT_S24_3LE; + break; + case 1: + usb_tx_cfg.bit_format = SNDRV_PCM_FORMAT_S24_LE; + break; + case 0: + default: + usb_tx_cfg.bit_format = SNDRV_PCM_FORMAT_S16_LE; + break; + } + pr_debug("%s: usb_audio_tx_format = %d, ucontrol value = %ld\n", + __func__, usb_tx_cfg.bit_format, + ucontrol->value.integer.value[0]); + + return rc; +} + const struct snd_kcontrol_new msm_common_snd_controls[] = { SOC_ENUM_EXT("PROXY_RX Channels", proxy_rx_chs, proxy_rx_ch_get, proxy_rx_ch_put), - SOC_ENUM_EXT("BTSCO SampleRate", btsco_sample_rate, - btsco_sample_rate_get, - btsco_sample_rate_put), SOC_ENUM_EXT("PRIM_AUX_PCM_RX SampleRate", prim_aux_pcm_rx_sample_rate, aux_pcm_rx_sample_rate_get, aux_pcm_rx_sample_rate_put), @@ -702,8 +1548,119 @@ const struct snd_kcontrol_new msm_common_snd_controls[] = { msm_mi2s_rx_ch_get, msm_mi2s_rx_ch_put), SOC_ENUM_EXT("QUAT_MI2S_TX Channels", quat_mi2s_tx_chs, msm_mi2s_tx_ch_get, msm_mi2s_tx_ch_put), + SOC_ENUM_EXT("USB_AUDIO_RX Channels", usb_rx_chs, + usb_audio_rx_ch_get, usb_audio_rx_ch_put), + SOC_ENUM_EXT("USB_AUDIO_TX Channels", usb_tx_chs, + usb_audio_tx_ch_get, usb_audio_tx_ch_put), + SOC_ENUM_EXT("USB_AUDIO_RX Format", usb_rx_format, + usb_audio_rx_format_get, usb_audio_rx_format_put), + SOC_ENUM_EXT("USB_AUDIO_TX Format", usb_tx_format, + usb_audio_tx_format_get, usb_audio_tx_format_put), + SOC_ENUM_EXT("USB_AUDIO_RX SampleRate", usb_rx_sample_rate, + usb_audio_rx_sample_rate_get, + usb_audio_rx_sample_rate_put), + SOC_ENUM_EXT("USB_AUDIO_TX SampleRate", usb_tx_sample_rate, + usb_audio_tx_sample_rate_get, + usb_audio_tx_sample_rate_put), + SOC_ENUM_EXT("PRI_TDM_RX_0 SampleRate", tdm_rx_sample_rate, + tdm_rx_sample_rate_get, + tdm_rx_sample_rate_put), + SOC_ENUM_EXT("PRI_TDM_TX_0 SampleRate", tdm_tx_sample_rate, + tdm_tx_sample_rate_get, + tdm_tx_sample_rate_put), + SOC_ENUM_EXT("PRI_TDM_RX_0 Format", tdm_rx_format, + tdm_rx_format_get, + tdm_rx_format_put), + SOC_ENUM_EXT("PRI_TDM_TX_0 Format", tdm_tx_format, + tdm_tx_format_get, + tdm_tx_format_put), + SOC_ENUM_EXT("PRI_TDM_RX_0 Channels", tdm_rx_chs, + tdm_rx_ch_get, + tdm_rx_ch_put), + SOC_ENUM_EXT("PRI_TDM_TX_0 Channels", tdm_tx_chs, + tdm_tx_ch_get, + tdm_tx_ch_put), + SOC_ENUM_EXT("SEC_TDM_RX_0 SampleRate", tdm_rx_sample_rate, + tdm_rx_sample_rate_get, + tdm_rx_sample_rate_put), + SOC_ENUM_EXT("SEC_TDM_TX_0 SampleRate", tdm_tx_sample_rate, + tdm_tx_sample_rate_get, + tdm_tx_sample_rate_put), + SOC_ENUM_EXT("SEC_TDM_RX_0 Format", tdm_rx_format, + tdm_rx_format_get, + tdm_rx_format_put), + SOC_ENUM_EXT("SEC_TDM_TX_0 Format", tdm_tx_format, + tdm_tx_format_get, + tdm_tx_format_put), + SOC_ENUM_EXT("SEC_TDM_RX_0 Channels", tdm_rx_chs, + tdm_rx_ch_get, + tdm_rx_ch_put), + SOC_ENUM_EXT("SEC_TDM_TX_0 Channels", tdm_tx_chs, + tdm_tx_ch_get, + tdm_tx_ch_put), + SOC_ENUM_EXT("TERT_TDM_RX_0 SampleRate", tdm_rx_sample_rate, + tdm_rx_sample_rate_get, + tdm_rx_sample_rate_put), + SOC_ENUM_EXT("TERT_TDM_TX_0 SampleRate", tdm_tx_sample_rate, + tdm_tx_sample_rate_get, + tdm_tx_sample_rate_put), + SOC_ENUM_EXT("TERT_TDM_RX_0 Format", tdm_rx_format, + tdm_rx_format_get, + tdm_rx_format_put), + SOC_ENUM_EXT("TERT_TDM_TX_0 Format", tdm_tx_format, + tdm_tx_format_get, + tdm_tx_format_put), + SOC_ENUM_EXT("TERT_TDM_RX_0 Channels", tdm_rx_chs, + tdm_rx_ch_get, + tdm_rx_ch_put), + SOC_ENUM_EXT("TERT_TDM_TX_0 Channels", tdm_tx_chs, + tdm_tx_ch_get, + tdm_tx_ch_put), + SOC_ENUM_EXT("QUAT_TDM_RX_0 SampleRate", tdm_rx_sample_rate, + tdm_rx_sample_rate_get, + tdm_rx_sample_rate_put), + SOC_ENUM_EXT("QUAT_TDM_TX_0 SampleRate", tdm_tx_sample_rate, + tdm_tx_sample_rate_get, + tdm_tx_sample_rate_put), + SOC_ENUM_EXT("QUAT_TDM_RX_0 Format", tdm_rx_format, + tdm_rx_format_get, + tdm_rx_format_put), + SOC_ENUM_EXT("QUAT_TDM_TX_0 Format", tdm_tx_format, + tdm_tx_format_get, + tdm_tx_format_put), + SOC_ENUM_EXT("QUAT_TDM_RX_0 Channels", tdm_rx_chs, + tdm_rx_ch_get, + tdm_rx_ch_put), + SOC_ENUM_EXT("QUAT_TDM_TX_0 Channels", tdm_tx_chs, + tdm_tx_ch_get, + tdm_tx_ch_put), }; +static inline int param_is_mask(int p) +{ + return (p >= SNDRV_PCM_HW_PARAM_FIRST_MASK) && + (p <= SNDRV_PCM_HW_PARAM_LAST_MASK); +} + +static inline struct snd_mask *param_to_mask(struct snd_pcm_hw_params *p, + int n) +{ + return &(p->masks[n - SNDRV_PCM_HW_PARAM_FIRST_MASK]); +} + +static void param_set_mask(struct snd_pcm_hw_params *p, int n, unsigned bit) +{ + if (bit >= SNDRV_MASK_MAX) + return; + if (param_is_mask(n)) { + struct snd_mask *m = param_to_mask(p, n); + + m->bits[0] = 0; + m->bits[1] = 0; + m->bits[bit >> 5] |= (1 << (bit & 31)); + } +} + /** * msm_common_be_hw_params_fixup - updates settings of ALSA BE hw params. * @@ -726,10 +1683,18 @@ int msm_common_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd, __func__, params_format(params), params_rate(params)); switch (dai_link->be_id) { - case MSM_BACKEND_DAI_INT_BT_SCO_RX: - case MSM_BACKEND_DAI_INT_BT_SCO_TX: - channels->min = channels->max = btsco_cfg.channels; - rate->min = rate->max = 1; + case MSM_BACKEND_DAI_USB_RX: + param_set_mask(params, SNDRV_PCM_HW_PARAM_FORMAT, + usb_rx_cfg.bit_format); + rate->min = rate->max = usb_rx_cfg.sample_rate; + channels->min = channels->max = usb_rx_cfg.channels; + break; + + case MSM_BACKEND_DAI_USB_TX: + param_set_mask(params, SNDRV_PCM_HW_PARAM_FORMAT, + usb_tx_cfg.bit_format); + rate->min = rate->max = usb_tx_cfg.sample_rate; + channels->min = channels->max = usb_tx_cfg.channels; break; case MSM_BACKEND_DAI_AFE_PCM_RX: @@ -737,6 +1702,70 @@ int msm_common_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd, rate->min = rate->max = SAMPLING_RATE_48KHZ; break; + case MSM_BACKEND_DAI_PRI_TDM_RX_0: + channels->min = channels->max = + tdm_rx_cfg[TDM_PRI][TDM_0].channels; + param_set_mask(params, SNDRV_PCM_HW_PARAM_FORMAT, + tdm_rx_cfg[TDM_PRI][TDM_0].bit_format); + rate->min = rate->max = tdm_rx_cfg[TDM_PRI][TDM_0].sample_rate; + break; + + case MSM_BACKEND_DAI_PRI_TDM_TX_0: + channels->min = channels->max = + tdm_tx_cfg[TDM_PRI][TDM_0].channels; + param_set_mask(params, SNDRV_PCM_HW_PARAM_FORMAT, + tdm_tx_cfg[TDM_PRI][TDM_0].bit_format); + rate->min = rate->max = tdm_tx_cfg[TDM_PRI][TDM_0].sample_rate; + break; + + case MSM_BACKEND_DAI_SEC_TDM_RX_0: + channels->min = channels->max = + tdm_rx_cfg[TDM_SEC][TDM_0].channels; + param_set_mask(params, SNDRV_PCM_HW_PARAM_FORMAT, + tdm_rx_cfg[TDM_SEC][TDM_0].bit_format); + rate->min = rate->max = tdm_rx_cfg[TDM_SEC][TDM_0].sample_rate; + break; + + case MSM_BACKEND_DAI_SEC_TDM_TX_0: + channels->min = channels->max = + tdm_tx_cfg[TDM_SEC][TDM_0].channels; + param_set_mask(params, SNDRV_PCM_HW_PARAM_FORMAT, + tdm_tx_cfg[TDM_SEC][TDM_0].bit_format); + rate->min = rate->max = tdm_tx_cfg[TDM_SEC][TDM_0].sample_rate; + break; + + case MSM_BACKEND_DAI_TERT_TDM_RX_0: + channels->min = channels->max = + tdm_rx_cfg[TDM_TERT][TDM_0].channels; + param_set_mask(params, SNDRV_PCM_HW_PARAM_FORMAT, + tdm_rx_cfg[TDM_TERT][TDM_0].bit_format); + rate->min = rate->max = tdm_rx_cfg[TDM_TERT][TDM_0].sample_rate; + break; + + case MSM_BACKEND_DAI_TERT_TDM_TX_0: + channels->min = channels->max = + tdm_tx_cfg[TDM_TERT][TDM_0].channels; + param_set_mask(params, SNDRV_PCM_HW_PARAM_FORMAT, + tdm_tx_cfg[TDM_TERT][TDM_0].bit_format); + rate->min = rate->max = tdm_tx_cfg[TDM_TERT][TDM_0].sample_rate; + break; + + case MSM_BACKEND_DAI_QUAT_TDM_RX_0: + channels->min = channels->max = + tdm_rx_cfg[TDM_QUAT][TDM_0].channels; + param_set_mask(params, SNDRV_PCM_HW_PARAM_FORMAT, + tdm_rx_cfg[TDM_QUAT][TDM_0].bit_format); + rate->min = rate->max = tdm_rx_cfg[TDM_QUAT][TDM_0].sample_rate; + break; + + case MSM_BACKEND_DAI_QUAT_TDM_TX_0: + channels->min = channels->max = + tdm_tx_cfg[TDM_QUAT][TDM_0].channels; + param_set_mask(params, SNDRV_PCM_HW_PARAM_FORMAT, + tdm_tx_cfg[TDM_QUAT][TDM_0].bit_format); + rate->min = rate->max = tdm_tx_cfg[TDM_QUAT][TDM_0].sample_rate; + break; + case MSM_BACKEND_DAI_AUXPCM_RX: rate->min = rate->max = aux_pcm_rx_cfg[PRIM_AUX_PCM].sample_rate; diff --git a/sound/soc/msm/msmfalcon-common.h b/sound/soc/msm/msmfalcon-common.h index ff8232d6fcbb..50495c161347 100644 --- a/sound/soc/msm/msmfalcon-common.h +++ b/sound/soc/msm/msmfalcon-common.h @@ -31,6 +31,34 @@ #define SAMPLING_RATE_352P8KHZ 352800 #define SAMPLING_RATE_384KHZ 384000 +#define TDM_CHANNEL_MAX 8 +#define TDM_SLOT_OFFSET_MAX 8 + +enum { + TDM_0 = 0, + TDM_1, + TDM_2, + TDM_3, + TDM_4, + TDM_5, + TDM_6, + TDM_7, + TDM_PORT_MAX, +}; + +enum { + TDM_PRI = 0, + TDM_SEC, + TDM_TERT, + TDM_QUAT, + TDM_INTERFACE_MAX, +}; + +struct tdm_port { + u32 mode; + u32 channel; +}; + extern const struct snd_kcontrol_new msm_common_snd_controls[]; struct msmfalcon_codec { void* (*get_afe_config_fn)(struct snd_soc_codec *codec, diff --git a/sound/soc/msm/msmfalcon-ext-dai-links.c b/sound/soc/msm/msmfalcon-ext-dai-links.c index 4dca7908c108..ce9e41cc11cc 100644 --- a/sound/soc/msm/msmfalcon-ext-dai-links.c +++ b/sound/soc/msm/msmfalcon-ext-dai-links.c @@ -16,6 +16,7 @@ #include #include #include +#include #include "qdsp6v2/msm-pcm-routing-v2.h" #include "../codecs/wcd9335.h" #include "msmfalcon-common.h" @@ -25,6 +26,9 @@ #define __CHIPSET__ "MSMFALCON " #define MSM_DAILINK_NAME(name) (__CHIPSET__#name) +#define WCN_CDC_SLIM_RX_CH_MAX 2 +#define WCN_CDC_SLIM_TX_CH_MAX 3 + static struct snd_soc_card snd_soc_card_msm_card; static struct snd_soc_ops msm_ext_slimbus_be_ops = { @@ -49,6 +53,222 @@ static struct snd_soc_ops msm_aux_pcm_be_ops = { .shutdown = msm_aux_pcm_snd_shutdown, }; +static int msm_wcn_init(struct snd_soc_pcm_runtime *rtd) +{ + unsigned int rx_ch[WCN_CDC_SLIM_RX_CH_MAX] = {157, 158}; + unsigned int tx_ch[WCN_CDC_SLIM_TX_CH_MAX] = {159, 160, 161}; + struct snd_soc_dai *codec_dai = rtd->codec_dai; + + return snd_soc_dai_set_channel_map(codec_dai, ARRAY_SIZE(tx_ch), + tx_ch, ARRAY_SIZE(rx_ch), rx_ch); +} + +static int msm_wcn_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_dai *codec_dai = rtd->codec_dai; + struct snd_soc_dai *cpu_dai = rtd->cpu_dai; + struct snd_soc_dai_link *dai_link = rtd->dai_link; + u32 rx_ch[WCN_CDC_SLIM_RX_CH_MAX], tx_ch[WCN_CDC_SLIM_TX_CH_MAX]; + u32 rx_ch_cnt = 0, tx_ch_cnt = 0; + int ret; + + dev_dbg(rtd->dev, "%s: %s_tx_dai_id_%d\n", __func__, + codec_dai->name, codec_dai->id); + ret = snd_soc_dai_get_channel_map(codec_dai, + &tx_ch_cnt, tx_ch, &rx_ch_cnt, rx_ch); + if (ret) { + dev_err(rtd->dev, + "%s: failed to get BTFM codec chan map\n, err:%d\n", + __func__, ret); + goto exit; + } + + dev_dbg(rtd->dev, "%s: tx_ch_cnt(%d) be_id %d\n", + __func__, tx_ch_cnt, dai_link->be_id); + + ret = snd_soc_dai_set_channel_map(cpu_dai, + tx_ch_cnt, tx_ch, rx_ch_cnt, rx_ch); + if (ret) + dev_err(rtd->dev, "%s: failed to set cpu chan map, err:%d\n", + __func__, ret); + +exit: + return ret; +} + +static struct snd_soc_ops msm_wcn_ops = { + .hw_params = msm_wcn_hw_params, +}; + +/*TDM default offset currently only supporting TDM_RX_0 and TDM_TX_0 */ +static unsigned int tdm_slot_offset[TDM_PORT_MAX][TDM_SLOT_OFFSET_MAX] = { + {0, 4, 8, 12, 16, 20, 24, 28},/* TX_0 | RX_0 */ + {AFE_SLOT_MAPPING_OFFSET_INVALID},/* TX_1 | RX_1 */ + {AFE_SLOT_MAPPING_OFFSET_INVALID},/* TX_2 | RX_2 */ + {AFE_SLOT_MAPPING_OFFSET_INVALID},/* TX_3 | RX_3 */ + {AFE_SLOT_MAPPING_OFFSET_INVALID},/* TX_4 | RX_4 */ + {AFE_SLOT_MAPPING_OFFSET_INVALID},/* TX_5 | RX_5 */ + {AFE_SLOT_MAPPING_OFFSET_INVALID},/* TX_6 | RX_6 */ + {AFE_SLOT_MAPPING_OFFSET_INVALID},/* TX_7 | RX_7 */ +}; + +static unsigned int tdm_param_set_slot_mask(u16 port_id, int slot_width, + int slots) +{ + unsigned int slot_mask = 0; + int i, j; + unsigned int *slot_offset; + + for (i = TDM_0; i < TDM_PORT_MAX; i++) { + slot_offset = tdm_slot_offset[i]; + + for (j = 0; j < TDM_SLOT_OFFSET_MAX; j++) { + if (slot_offset[j] != AFE_SLOT_MAPPING_OFFSET_INVALID) + slot_mask |= + (1 << ((slot_offset[j] * 8) / slot_width)); + else + break; + } + } + + return slot_mask; +} + +static int msm_tdm_snd_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_dai *cpu_dai = rtd->cpu_dai; + int ret = 0; + int channels, slot_width, slots; + unsigned int slot_mask; + unsigned int *slot_offset; + int offset_channels = 0; + int i; + + pr_debug("%s: dai id = 0x%x\n", __func__, cpu_dai->id); + + channels = params_channels(params); + switch (channels) { + case 1: + case 2: + case 3: + case 4: + case 5: + case 6: + case 7: + case 8: + switch (params_format(params)) { + case SNDRV_PCM_FORMAT_S32_LE: + case SNDRV_PCM_FORMAT_S24_LE: + case SNDRV_PCM_FORMAT_S16_LE: + /* + * up to 8 channels HW config should + * use 32 bit slot width for max support of + * stream bit width. (slot_width > bit_width) + */ + slot_width = 32; + break; + default: + pr_err("%s: invalid param format 0x%x\n", + __func__, params_format(params)); + return -EINVAL; + } + slots = 8; + slot_mask = tdm_param_set_slot_mask(cpu_dai->id, + slot_width, + slots); + if (!slot_mask) { + pr_err("%s: invalid slot_mask 0x%x\n", + __func__, slot_mask); + return -EINVAL; + } + break; + default: + pr_err("%s: invalid param channels %d\n", + __func__, channels); + return -EINVAL; + } + /* currently only supporting TDM_RX_0 and TDM_TX_0 */ + switch (cpu_dai->id) { + case AFE_PORT_ID_PRIMARY_TDM_RX: + case AFE_PORT_ID_SECONDARY_TDM_RX: + case AFE_PORT_ID_TERTIARY_TDM_RX: + case AFE_PORT_ID_QUATERNARY_TDM_RX: + case AFE_PORT_ID_PRIMARY_TDM_TX: + case AFE_PORT_ID_SECONDARY_TDM_TX: + case AFE_PORT_ID_TERTIARY_TDM_TX: + case AFE_PORT_ID_QUATERNARY_TDM_TX: + slot_offset = tdm_slot_offset[TDM_0]; + break; + default: + pr_err("%s: dai id 0x%x not supported\n", + __func__, cpu_dai->id); + return -EINVAL; + } + + for (i = 0; i < TDM_SLOT_OFFSET_MAX; i++) { + if (slot_offset[i] != AFE_SLOT_MAPPING_OFFSET_INVALID) + offset_channels++; + else + break; + } + + if (offset_channels == 0) { + pr_err("%s: slot offset not supported, offset_channels %d\n", + __func__, offset_channels); + return -EINVAL; + } + + if (channels > offset_channels) { + pr_err("%s: channels %d exceed offset_channels %d\n", + __func__, channels, offset_channels); + return -EINVAL; + } + + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { + ret = snd_soc_dai_set_tdm_slot(cpu_dai, 0, slot_mask, + slots, slot_width); + if (ret < 0) { + pr_err("%s: failed to set tdm slot, err:%d\n", + __func__, ret); + goto end; + } + + ret = snd_soc_dai_set_channel_map(cpu_dai, 0, NULL, + channels, slot_offset); + if (ret < 0) { + pr_err("%s: failed to set channel map, err:%d\n", + __func__, ret); + goto end; + } + } else { + ret = snd_soc_dai_set_tdm_slot(cpu_dai, slot_mask, 0, + slots, slot_width); + if (ret < 0) { + pr_err("%s: failed to set tdm slot, err:%d\n", + __func__, ret); + goto end; + } + + ret = snd_soc_dai_set_channel_map(cpu_dai, channels, + slot_offset, 0, NULL); + if (ret < 0) { + pr_err("%s: failed to set channel map, err:%d\n", + __func__, ret); + goto end; + } + } +end: + return ret; +} + +static struct snd_soc_ops msm_tdm_be_ops = { + .hw_params = msm_tdm_snd_hw_params +}; + static struct snd_soc_dai_link msm_ext_tasha_fe_dai[] = { /* tasha_vifeedback for speaker protection */ { @@ -1167,6 +1387,145 @@ static struct snd_soc_dai_link msm_ext_common_be_dai[] = { .be_hw_params_fixup = msm_ext_be_hw_params_fixup, .ignore_suspend = 1, }, + { + .name = LPASS_BE_USB_AUDIO_RX, + .stream_name = "USB Audio Playback", + .cpu_dai_name = "msm-dai-q6-dev.28672", + .platform_name = "msm-pcm-routing", + .codec_name = "msm-stub-codec.1", + .codec_dai_name = "msm-stub-rx", + .no_pcm = 1, + .dpcm_playback = 1, + .be_id = MSM_BACKEND_DAI_USB_RX, + .be_hw_params_fixup = msm_common_be_hw_params_fixup, + .ignore_pmdown_time = 1, + .ignore_suspend = 1, + }, + { + .name = LPASS_BE_USB_AUDIO_TX, + .stream_name = "USB Audio Capture", + .cpu_dai_name = "msm-dai-q6-dev.28673", + .platform_name = "msm-pcm-routing", + .codec_name = "msm-stub-codec.1", + .codec_dai_name = "msm-stub-tx", + .no_pcm = 1, + .dpcm_capture = 1, + .be_id = MSM_BACKEND_DAI_USB_TX, + .be_hw_params_fixup = msm_common_be_hw_params_fixup, + .ignore_suspend = 1, + }, + { + .name = LPASS_BE_PRI_TDM_RX_0, + .stream_name = "Primary TDM0 Playback", + .cpu_dai_name = "msm-dai-q6-tdm.36864", + .platform_name = "msm-pcm-routing", + .codec_name = "msm-stub-codec.1", + .codec_dai_name = "msm-stub-rx", + .no_pcm = 1, + .dpcm_playback = 1, + .be_id = MSM_BACKEND_DAI_PRI_TDM_RX_0, + .be_hw_params_fixup = msm_common_be_hw_params_fixup, + .ops = &msm_tdm_be_ops, + .ignore_suspend = 1, + }, + { + .name = LPASS_BE_PRI_TDM_TX_0, + .stream_name = "Primary TDM0 Capture", + .cpu_dai_name = "msm-dai-q6-tdm.36865", + .platform_name = "msm-pcm-routing", + .codec_name = "msm-stub-codec.1", + .codec_dai_name = "msm-stub-tx", + .no_pcm = 1, + .dpcm_capture = 1, + .be_id = MSM_BACKEND_DAI_PRI_TDM_TX_0, + .be_hw_params_fixup = msm_common_be_hw_params_fixup, + .ops = &msm_tdm_be_ops, + .ignore_suspend = 1, + }, + { + .name = LPASS_BE_SEC_TDM_RX_0, + .stream_name = "Secondary TDM0 Playback", + .cpu_dai_name = "msm-dai-q6-tdm.36880", + .platform_name = "msm-pcm-routing", + .codec_name = "msm-stub-codec.1", + .codec_dai_name = "msm-stub-rx", + .no_pcm = 1, + .dpcm_playback = 1, + .be_id = MSM_BACKEND_DAI_SEC_TDM_RX_0, + .be_hw_params_fixup = msm_common_be_hw_params_fixup, + .ops = &msm_tdm_be_ops, + .ignore_suspend = 1, + }, + { + .name = LPASS_BE_SEC_TDM_TX_0, + .stream_name = "Secondary TDM0 Capture", + .cpu_dai_name = "msm-dai-q6-tdm.36881", + .platform_name = "msm-pcm-routing", + .codec_name = "msm-stub-codec.1", + .codec_dai_name = "msm-stub-tx", + .no_pcm = 1, + .dpcm_capture = 1, + .be_id = MSM_BACKEND_DAI_SEC_TDM_TX_0, + .be_hw_params_fixup = msm_common_be_hw_params_fixup, + .ops = &msm_tdm_be_ops, + .ignore_suspend = 1, + }, + { + .name = LPASS_BE_TERT_TDM_RX_0, + .stream_name = "Tertiary TDM0 Playback", + .cpu_dai_name = "msm-dai-q6-tdm.36896", + .platform_name = "msm-pcm-routing", + .codec_name = "msm-stub-codec.1", + .codec_dai_name = "msm-stub-rx", + .no_pcm = 1, + .dpcm_playback = 1, + .be_id = MSM_BACKEND_DAI_TERT_TDM_RX_0, + .be_hw_params_fixup = msm_common_be_hw_params_fixup, + .ops = &msm_tdm_be_ops, + .ignore_suspend = 1, + }, + { + .name = LPASS_BE_TERT_TDM_TX_0, + .stream_name = "Tertiary TDM0 Capture", + .cpu_dai_name = "msm-dai-q6-tdm.36897", + .platform_name = "msm-pcm-routing", + .codec_name = "msm-stub-codec.1", + .codec_dai_name = "msm-stub-tx", + .no_pcm = 1, + .dpcm_capture = 1, + .be_id = MSM_BACKEND_DAI_TERT_TDM_TX_0, + .be_hw_params_fixup = msm_common_be_hw_params_fixup, + .ops = &msm_tdm_be_ops, + .ignore_suspend = 1, + }, + { + .name = LPASS_BE_QUAT_TDM_RX_0, + .stream_name = "Quaternary TDM0 Playback", + .cpu_dai_name = "msm-dai-q6-tdm.36912", + .platform_name = "msm-pcm-routing", + .codec_name = "msm-stub-codec.1", + .codec_dai_name = "msm-stub-rx", + .no_pcm = 1, + .dpcm_playback = 1, + .be_id = MSM_BACKEND_DAI_QUAT_TDM_RX_0, + .be_hw_params_fixup = msm_common_be_hw_params_fixup, + .ops = &msm_tdm_be_ops, + .ignore_suspend = 1, + }, + { + .name = LPASS_BE_QUAT_TDM_TX_0, + .stream_name = "Quaternary TDM0 Capture", + .cpu_dai_name = "msm-dai-q6-tdm.36913", + .platform_name = "msm-pcm-routing", + .codec_name = "msm-stub-codec.1", + .codec_dai_name = "msm-stub-tx", + .no_pcm = 1, + .dpcm_capture = 1, + .be_id = MSM_BACKEND_DAI_QUAT_TDM_TX_0, + .be_hw_params_fixup = msm_common_be_hw_params_fixup, + .ops = &msm_tdm_be_ops, + .ignore_suspend = 1, + }, }; static struct snd_soc_dai_link msm_mi2s_be_dai_links[] = { @@ -1415,13 +1774,66 @@ static struct snd_soc_dai_link msm_auxpcm_be_dai_links[] = { }, }; +static struct snd_soc_dai_link msm_wcn_be_dai_links[] = { + { + .name = LPASS_BE_SLIMBUS_7_RX, + .stream_name = "Slimbus7 Playback", + .cpu_dai_name = "msm-dai-q6-dev.16398", + .platform_name = "msm-pcm-routing", + .codec_name = "btfmslim_slave", + /* BT codec driver determines capabilities based on + * dai name, bt codecdai name should always contains + * supported usecase information + */ + .codec_dai_name = "btfm_bt_sco_a2dp_slim_rx", + .no_pcm = 1, + .dpcm_playback = 1, + .be_id = MSM_BACKEND_DAI_SLIMBUS_7_RX, + .be_hw_params_fixup = msm_ext_be_hw_params_fixup, + .ops = &msm_wcn_ops, + /* dai link has playback support */ + .ignore_pmdown_time = 1, + .ignore_suspend = 1, + }, + { + .name = LPASS_BE_SLIMBUS_7_TX, + .stream_name = "Slimbus7 Capture", + .cpu_dai_name = "msm-dai-q6-dev.16399", + .platform_name = "msm-pcm-routing", + .codec_name = "btfmslim_slave", + .codec_dai_name = "btfm_bt_sco_slim_tx", + .no_pcm = 1, + .dpcm_capture = 1, + .be_id = MSM_BACKEND_DAI_SLIMBUS_7_TX, + .be_hw_params_fixup = msm_ext_be_hw_params_fixup, + .ops = &msm_wcn_ops, + .ignore_suspend = 1, + }, + { + .name = LPASS_BE_SLIMBUS_8_TX, + .stream_name = "Slimbus8 Capture", + .cpu_dai_name = "msm-dai-q6-dev.16401", + .platform_name = "msm-pcm-routing", + .codec_name = "btfmslim_slave", + .codec_dai_name = "btfm_fm_slim_tx", + .no_pcm = 1, + .dpcm_capture = 1, + .be_id = MSM_BACKEND_DAI_SLIMBUS_8_TX, + .be_hw_params_fixup = msm_ext_be_hw_params_fixup, + .init = &msm_wcn_init, + .ops = &msm_wcn_ops, + .ignore_suspend = 1, + }, +}; + static struct snd_soc_dai_link msm_ext_tasha_dai_links[ ARRAY_SIZE(msm_ext_common_fe_dai) + ARRAY_SIZE(msm_ext_tasha_fe_dai) + ARRAY_SIZE(msm_ext_common_be_dai) + ARRAY_SIZE(msm_ext_tasha_be_dai) + ARRAY_SIZE(msm_mi2s_be_dai_links) + -ARRAY_SIZE(msm_auxpcm_be_dai_links)]; +ARRAY_SIZE(msm_auxpcm_be_dai_links) + +ARRAY_SIZE(msm_wcn_be_dai_links)]; static struct snd_soc_dai_link msm_ext_tavil_dai_links[ ARRAY_SIZE(msm_ext_common_fe_dai) + @@ -1429,7 +1841,8 @@ ARRAY_SIZE(msm_ext_tavil_fe_dai) + ARRAY_SIZE(msm_ext_common_be_dai) + ARRAY_SIZE(msm_ext_tavil_be_dai) + ARRAY_SIZE(msm_mi2s_be_dai_links) + -ARRAY_SIZE(msm_auxpcm_be_dai_links)]; +ARRAY_SIZE(msm_auxpcm_be_dai_links) + +ARRAY_SIZE(msm_wcn_be_dai_links)]; /** * populate_snd_card_dailinks - prepares dailink array and initializes card. @@ -1484,6 +1897,14 @@ struct snd_soc_card *populate_snd_card_dailinks(struct device *dev) sizeof(msm_auxpcm_be_dai_links)); len4 += ARRAY_SIZE(msm_auxpcm_be_dai_links); } + if (of_property_read_bool(dev->of_node, "qcom,wcn-btfm")) { + dev_dbg(dev, "%s(): WCN BTFM support present\n", + __func__); + memcpy(msm_ext_tasha_dai_links + len4, + msm_wcn_be_dai_links, + sizeof(msm_wcn_be_dai_links)); + len4 += ARRAY_SIZE(msm_wcn_be_dai_links); + } msm_ext_dai_links = msm_ext_tasha_dai_links; } else if (strnstr(card->name, "tavil", strlen(card->name))) { len1 = ARRAY_SIZE(msm_ext_common_fe_dai); @@ -1512,6 +1933,14 @@ struct snd_soc_card *populate_snd_card_dailinks(struct device *dev) sizeof(msm_auxpcm_be_dai_links)); len4 += ARRAY_SIZE(msm_auxpcm_be_dai_links); } + if (of_property_read_bool(dev->of_node, "qcom,wcn-btfm")) { + dev_dbg(dev, "%s(): WCN BTFM support present\n", + __func__); + memcpy(msm_ext_tavil_dai_links + len4, + msm_wcn_be_dai_links, + sizeof(msm_wcn_be_dai_links)); + len4 += ARRAY_SIZE(msm_wcn_be_dai_links); + } msm_ext_dai_links = msm_ext_tavil_dai_links; } else { dev_err(dev, "%s: failing as no matching card name\n", diff --git a/sound/soc/msm/msmfalcon-external.c b/sound/soc/msm/msmfalcon-external.c index 046c63bb73cf..0a82eb87d267 100644 --- a/sound/soc/msm/msmfalcon-external.c +++ b/sound/soc/msm/msmfalcon-external.c @@ -122,6 +122,7 @@ static char const *slim_sample_rate_text[] = {"KHZ_8", "KHZ_16", "KHZ_88P2", "KHZ_96", "KHZ_176P4", "KHZ_192", "KHZ_352P8", "KHZ_384"}; static const char *const spk_function_text[] = {"Off", "On"}; +static char const *bt_sample_rate_text[] = {"KHZ_8", "KHZ_16", "KHZ_48"}; static SOC_ENUM_SINGLE_EXT_DECL(spk_func_en, spk_function_text); static SOC_ENUM_SINGLE_EXT_DECL(slim_0_rx_chs, slim_rx_ch_text); @@ -140,6 +141,7 @@ static SOC_ENUM_SINGLE_EXT_DECL(slim_2_rx_sample_rate, slim_sample_rate_text); static SOC_ENUM_SINGLE_EXT_DECL(slim_0_tx_sample_rate, slim_sample_rate_text); static SOC_ENUM_SINGLE_EXT_DECL(slim_5_rx_sample_rate, slim_sample_rate_text); static SOC_ENUM_SINGLE_EXT_DECL(slim_6_rx_sample_rate, slim_sample_rate_text); +static SOC_ENUM_SINGLE_EXT_DECL(bt_sample_rate, bt_sample_rate_text); static int slim_get_sample_rate_val(int sample_rate) { @@ -302,6 +304,59 @@ static int slim_get_port_idx(struct snd_kcontrol *kcontrol) return port_id; } +static int msm_bt_sample_rate_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + /* + * Slimbus_7_Rx/Tx sample rate values should always be in sync (same) + * when used for BT_SCO use case. Return either Rx or Tx sample rate + * value. + */ + switch (slim_rx_cfg[SLIM_RX_7].sample_rate) { + case SAMPLING_RATE_48KHZ: + ucontrol->value.integer.value[0] = 2; + break; + case SAMPLING_RATE_16KHZ: + ucontrol->value.integer.value[0] = 1; + break; + case SAMPLING_RATE_8KHZ: + default: + ucontrol->value.integer.value[0] = 0; + break; + } + pr_debug("%s: sample rate = %d", __func__, + slim_rx_cfg[SLIM_RX_7].sample_rate); + + return 0; +} + +static int msm_bt_sample_rate_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + switch (ucontrol->value.integer.value[0]) { + case 1: + slim_rx_cfg[SLIM_RX_7].sample_rate = SAMPLING_RATE_16KHZ; + slim_tx_cfg[SLIM_TX_7].sample_rate = SAMPLING_RATE_16KHZ; + break; + case 2: + slim_rx_cfg[SLIM_RX_7].sample_rate = SAMPLING_RATE_48KHZ; + slim_tx_cfg[SLIM_TX_7].sample_rate = SAMPLING_RATE_48KHZ; + break; + case 0: + default: + slim_rx_cfg[SLIM_RX_7].sample_rate = SAMPLING_RATE_8KHZ; + slim_tx_cfg[SLIM_TX_7].sample_rate = SAMPLING_RATE_8KHZ; + break; + } + pr_debug("%s: sample rates: slim7_rx = %d, slim7_tx = %d, value = %d\n", + __func__, + slim_rx_cfg[SLIM_RX_7].sample_rate, + slim_tx_cfg[SLIM_TX_7].sample_rate, + ucontrol->value.enumerated.item[0]); + + return 0; +} + static int slim_rx_sample_rate_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { @@ -670,6 +725,9 @@ static const struct snd_kcontrol_new msm_snd_controls[] = { slim_rx_sample_rate_get, slim_rx_sample_rate_put), SOC_ENUM_EXT("SLIM_6_RX SampleRate", slim_6_rx_sample_rate, slim_rx_sample_rate_get, slim_rx_sample_rate_put), + SOC_ENUM_EXT("BT SampleRate", bt_sample_rate, + msm_bt_sample_rate_get, + msm_bt_sample_rate_put), }; static int msm_slim_get_ch_from_beid(int32_t be_id) diff --git a/sound/soc/msm/msmfalcon-internal.c b/sound/soc/msm/msmfalcon-internal.c index 3a8b88cdfb64..180ff492e9e9 100644 --- a/sound/soc/msm/msmfalcon-internal.c +++ b/sound/soc/msm/msmfalcon-internal.c @@ -27,6 +27,9 @@ #define WCD_MBHC_DEF_RLOADS 5 +#define WCN_CDC_SLIM_RX_CH_MAX 2 +#define WCN_CDC_SLIM_TX_CH_MAX 3 + enum { INT0_MI2S = 0, INT1_MI2S, @@ -38,6 +41,24 @@ enum { INT_MI2S_MAX, }; +enum { + BT_SLIM7, + FM_SLIM8, + SLIM_MAX, +}; + +/*TDM default offset currently only supporting TDM_RX_0 and TDM_TX_0 */ +static unsigned int tdm_slot_offset[TDM_PORT_MAX][TDM_SLOT_OFFSET_MAX] = { + {0, 4, 8, 12, 16, 20, 24, 28},/* TX_0 | RX_0 */ + {AFE_SLOT_MAPPING_OFFSET_INVALID},/* TX_1 | RX_1 */ + {AFE_SLOT_MAPPING_OFFSET_INVALID},/* TX_2 | RX_2 */ + {AFE_SLOT_MAPPING_OFFSET_INVALID},/* TX_3 | RX_3 */ + {AFE_SLOT_MAPPING_OFFSET_INVALID},/* TX_4 | RX_4 */ + {AFE_SLOT_MAPPING_OFFSET_INVALID},/* TX_5 | RX_5 */ + {AFE_SLOT_MAPPING_OFFSET_INVALID},/* TX_6 | RX_6 */ + {AFE_SLOT_MAPPING_OFFSET_INVALID},/* TX_7 | RX_7 */ +}; + static struct afe_clk_set int_mi2s_clk[INT_MI2S_MAX] = { { AFE_API_VERSION_I2S_CONFIG, @@ -114,6 +135,11 @@ static struct dev_config int_mi2s_cfg[] = { [INT6_MI2S] = {SAMPLING_RATE_8KHZ, SNDRV_PCM_FORMAT_S16_LE, 2}, }; +static struct dev_config bt_fm_cfg[] = { + [BT_SLIM7] = {SAMPLING_RATE_8KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, + [FM_SLIM8] = {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 2}, +}; + static char const *int_mi2s_rate_text[] = {"KHZ_8", "KHZ_16", "KHZ_32", "KHZ_44P1", "KHZ_48", "KHZ_96", "KHZ_192"}; @@ -122,6 +148,7 @@ static const char *const int_mi2s_tx_ch_text[] = {"One", "Two", "Three", "Four"}; static char const *bit_format_text[] = {"S16_LE", "S24_LE", "S24_3LE"}; static const char *const loopback_mclk_text[] = {"DISABLE", "ENABLE"}; +static char const *bt_sample_rate_text[] = {"KHZ_8", "KHZ_16", "KHZ_48"}; static SOC_ENUM_SINGLE_EXT_DECL(int0_mi2s_rx_sample_rate, int_mi2s_rate_text); static SOC_ENUM_SINGLE_EXT_DECL(int0_mi2s_rx_chs, int_mi2s_ch_text); @@ -137,6 +164,7 @@ static SOC_ENUM_SINGLE_EXT_DECL(int4_mi2s_rx_chs, int_mi2s_ch_text); static SOC_ENUM_SINGLE_EXT_DECL(int4_mi2s_rx_format, bit_format_text); static SOC_ENUM_SINGLE_EXT_DECL(int5_mi2s_tx_chs, int_mi2s_ch_text); static SOC_ENUM_SINGLE_EXT_DECL(loopback_mclk_en, loopback_mclk_text); +static SOC_ENUM_SINGLE_EXT_DECL(bt_sample_rate, bt_sample_rate_text); static int msm_dmic_event(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol, int event); @@ -544,7 +572,7 @@ static int msm_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd, return 0; } -int int_mi2s_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd, +static int int_mi2s_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd, struct snd_pcm_hw_params *params) { struct snd_soc_dai_link *dai_link = rtd->dai_link; @@ -577,6 +605,38 @@ int int_mi2s_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd, return 0; } +static int msm_btfm_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd, + struct snd_pcm_hw_params *params) +{ + struct snd_soc_dai_link *dai_link = rtd->dai_link; + struct snd_interval *rate = hw_param_interval(params, + SNDRV_PCM_HW_PARAM_RATE); + struct snd_interval *channels = hw_param_interval(params, + SNDRV_PCM_HW_PARAM_CHANNELS); + + switch (dai_link->be_id) { + case MSM_BACKEND_DAI_SLIMBUS_7_RX: + case MSM_BACKEND_DAI_SLIMBUS_7_TX: + param_set_mask(params, SNDRV_PCM_HW_PARAM_FORMAT, + bt_fm_cfg[BT_SLIM7].bit_format); + rate->min = rate->max = bt_fm_cfg[BT_SLIM7].sample_rate; + channels->min = channels->max = + bt_fm_cfg[BT_SLIM7].channels; + break; + + case MSM_BACKEND_DAI_SLIMBUS_8_TX: + rate->min = rate->max = bt_fm_cfg[FM_SLIM8].sample_rate; + channels->min = channels->max = + bt_fm_cfg[FM_SLIM8].channels; + break; + + default: + rate->min = rate->max = SAMPLING_RATE_48KHZ; + break; + } + return 0; +} + static int msm_vi_feed_tx_ch_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { @@ -746,6 +806,55 @@ static int loopback_mclk_put(struct snd_kcontrol *kcontrol, return ret; } +static int msm_bt_sample_rate_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + /* + * Slimbus_7_Rx/Tx sample rate values should always be in sync (same) + * when used for BT_SCO use case. Return either Rx or Tx sample rate + * value. + */ + switch (bt_fm_cfg[BT_SLIM7].sample_rate) { + case SAMPLING_RATE_48KHZ: + ucontrol->value.integer.value[0] = 2; + break; + case SAMPLING_RATE_16KHZ: + ucontrol->value.integer.value[0] = 1; + break; + case SAMPLING_RATE_8KHZ: + default: + ucontrol->value.integer.value[0] = 0; + break; + } + pr_debug("%s: sample rate = %d", __func__, + bt_fm_cfg[BT_SLIM7].sample_rate); + + return 0; +} + +static int msm_bt_sample_rate_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + switch (ucontrol->value.integer.value[0]) { + case 1: + bt_fm_cfg[BT_SLIM7].sample_rate = SAMPLING_RATE_16KHZ; + break; + case 2: + bt_fm_cfg[BT_SLIM7].sample_rate = SAMPLING_RATE_48KHZ; + break; + case 0: + default: + bt_fm_cfg[BT_SLIM7].sample_rate = SAMPLING_RATE_8KHZ; + break; + } + pr_debug("%s: sample rates: slim7_rx = %d, value = %d\n", + __func__, + bt_fm_cfg[BT_SLIM7].sample_rate, + ucontrol->value.enumerated.item[0]); + + return 0; +} + static const struct snd_kcontrol_new msm_snd_controls[] = { SOC_ENUM_EXT("INT0_MI2S_RX Format", int0_mi2s_rx_format, int_mi2s_bit_format_get, int_mi2s_bit_format_put), @@ -779,6 +888,9 @@ static const struct snd_kcontrol_new msm_snd_controls[] = { int_mi2s_ch_get, int_mi2s_ch_put), SOC_ENUM_EXT("Loopback MCLK", loopback_mclk_en, loopback_mclk_get, loopback_mclk_put), + SOC_ENUM_EXT("BT SampleRate", bt_sample_rate, + msm_bt_sample_rate_get, + msm_bt_sample_rate_put), }; static const struct snd_kcontrol_new msm_swr_controls[] = { @@ -1209,6 +1321,210 @@ static int msm_swr_audrx_init(struct snd_soc_pcm_runtime *rtd) return 0; } +static int msm_wcn_init(struct snd_soc_pcm_runtime *rtd) +{ + unsigned int rx_ch[WCN_CDC_SLIM_RX_CH_MAX] = {157, 158}; + unsigned int tx_ch[WCN_CDC_SLIM_TX_CH_MAX] = {159, 160, 161}; + struct snd_soc_dai *codec_dai = rtd->codec_dai; + + return snd_soc_dai_set_channel_map(codec_dai, ARRAY_SIZE(tx_ch), + tx_ch, ARRAY_SIZE(rx_ch), rx_ch); +} + +static int msm_wcn_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_dai *codec_dai = rtd->codec_dai; + struct snd_soc_dai *cpu_dai = rtd->cpu_dai; + struct snd_soc_dai_link *dai_link = rtd->dai_link; + u32 rx_ch[WCN_CDC_SLIM_RX_CH_MAX], tx_ch[WCN_CDC_SLIM_TX_CH_MAX]; + u32 rx_ch_cnt = 0, tx_ch_cnt = 0; + int ret; + + dev_dbg(rtd->dev, "%s: %s_tx_dai_id_%d\n", __func__, + codec_dai->name, codec_dai->id); + ret = snd_soc_dai_get_channel_map(codec_dai, + &tx_ch_cnt, tx_ch, &rx_ch_cnt, rx_ch); + if (ret) { + dev_err(rtd->dev, + "%s: failed to get BTFM codec chan map\n, err:%d\n", + __func__, ret); + goto exit; + } + + dev_dbg(rtd->dev, "%s: tx_ch_cnt(%d) be_id %d\n", + __func__, tx_ch_cnt, dai_link->be_id); + + ret = snd_soc_dai_set_channel_map(cpu_dai, + tx_ch_cnt, tx_ch, rx_ch_cnt, rx_ch); + if (ret) + dev_err(rtd->dev, "%s: failed to set cpu chan map, err:%d\n", + __func__, ret); + +exit: + return ret; +} + +static unsigned int tdm_param_set_slot_mask(u16 port_id, int slot_width, + int slots) +{ + unsigned int slot_mask = 0; + int i, j; + unsigned int *slot_offset; + + for (i = TDM_0; i < TDM_PORT_MAX; i++) { + slot_offset = tdm_slot_offset[i]; + + for (j = 0; j < TDM_SLOT_OFFSET_MAX; j++) { + if (slot_offset[j] != AFE_SLOT_MAPPING_OFFSET_INVALID) + slot_mask |= + (1 << ((slot_offset[j] * 8) / slot_width)); + else + break; + } + } + + return slot_mask; +} + +static int msm_tdm_snd_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_dai *cpu_dai = rtd->cpu_dai; + int ret = 0; + int channels, slot_width, slots; + unsigned int slot_mask; + unsigned int *slot_offset; + int offset_channels = 0; + int i; + + pr_debug("%s: dai id = 0x%x\n", __func__, cpu_dai->id); + + channels = params_channels(params); + switch (channels) { + case 1: + case 2: + case 3: + case 4: + case 5: + case 6: + case 7: + case 8: + switch (params_format(params)) { + case SNDRV_PCM_FORMAT_S32_LE: + case SNDRV_PCM_FORMAT_S24_LE: + case SNDRV_PCM_FORMAT_S16_LE: + /* + * up to 8 channels HW config should + * use 32 bit slot width for max support of + * stream bit width. (slot_width > bit_width) + */ + slot_width = 32; + break; + default: + pr_err("%s: invalid param format 0x%x\n", + __func__, params_format(params)); + return -EINVAL; + } + slots = 8; + slot_mask = tdm_param_set_slot_mask(cpu_dai->id, + slot_width, + slots); + if (!slot_mask) { + pr_err("%s: invalid slot_mask 0x%x\n", + __func__, slot_mask); + return -EINVAL; + } + break; + default: + pr_err("%s: invalid param channels %d\n", + __func__, channels); + return -EINVAL; + } + /* currently only supporting TDM_RX_0 and TDM_TX_0 */ + switch (cpu_dai->id) { + case AFE_PORT_ID_PRIMARY_TDM_RX: + case AFE_PORT_ID_SECONDARY_TDM_RX: + case AFE_PORT_ID_TERTIARY_TDM_RX: + case AFE_PORT_ID_QUATERNARY_TDM_RX: + case AFE_PORT_ID_PRIMARY_TDM_TX: + case AFE_PORT_ID_SECONDARY_TDM_TX: + case AFE_PORT_ID_TERTIARY_TDM_TX: + case AFE_PORT_ID_QUATERNARY_TDM_TX: + slot_offset = tdm_slot_offset[TDM_0]; + break; + default: + pr_err("%s: dai id 0x%x not supported\n", + __func__, cpu_dai->id); + return -EINVAL; + } + + for (i = 0; i < TDM_SLOT_OFFSET_MAX; i++) { + if (slot_offset[i] != AFE_SLOT_MAPPING_OFFSET_INVALID) + offset_channels++; + else + break; + } + + if (offset_channels == 0) { + pr_err("%s: slot offset not supported, offset_channels %d\n", + __func__, offset_channels); + return -EINVAL; + } + + if (channels > offset_channels) { + pr_err("%s: channels %d exceed offset_channels %d\n", + __func__, channels, offset_channels); + return -EINVAL; + } + + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { + ret = snd_soc_dai_set_tdm_slot(cpu_dai, 0, slot_mask, + slots, slot_width); + if (ret < 0) { + pr_err("%s: failed to set tdm slot, err:%d\n", + __func__, ret); + goto end; + } + + ret = snd_soc_dai_set_channel_map(cpu_dai, 0, NULL, + channels, slot_offset); + if (ret < 0) { + pr_err("%s: failed to set channel map, err:%d\n", + __func__, ret); + goto end; + } + } else { + ret = snd_soc_dai_set_tdm_slot(cpu_dai, slot_mask, 0, + slots, slot_width); + if (ret < 0) { + pr_err("%s: failed to set tdm slot, err:%d\n", + __func__, ret); + goto end; + } + + ret = snd_soc_dai_set_channel_map(cpu_dai, channels, + slot_offset, 0, NULL); + if (ret < 0) { + pr_err("%s: failed to set channel map, err:%d\n", + __func__, ret); + goto end; + } + } +end: + return ret; +} + +static struct snd_soc_ops msm_tdm_be_ops = { + .hw_params = msm_tdm_snd_hw_params +}; + +static struct snd_soc_ops msm_wcn_ops = { + .hw_params = msm_wcn_hw_params, +}; + static struct snd_soc_ops msm_mi2s_be_ops = { .startup = msm_mi2s_snd_startup, .shutdown = msm_mi2s_snd_shutdown, @@ -2029,6 +2345,145 @@ static struct snd_soc_dai_link msm_int_dai[] = { .be_hw_params_fixup = msm_be_hw_params_fixup, .ignore_suspend = 1, }, + { + .name = LPASS_BE_USB_AUDIO_RX, + .stream_name = "USB Audio Playback", + .cpu_dai_name = "msm-dai-q6-dev.28672", + .platform_name = "msm-pcm-routing", + .codec_name = "msm-stub-codec.1", + .codec_dai_name = "msm-stub-rx", + .no_pcm = 1, + .dpcm_playback = 1, + .be_id = MSM_BACKEND_DAI_USB_RX, + .be_hw_params_fixup = msm_common_be_hw_params_fixup, + .ignore_pmdown_time = 1, + .ignore_suspend = 1, + }, + { + .name = LPASS_BE_USB_AUDIO_TX, + .stream_name = "USB Audio Capture", + .cpu_dai_name = "msm-dai-q6-dev.28673", + .platform_name = "msm-pcm-routing", + .codec_name = "msm-stub-codec.1", + .codec_dai_name = "msm-stub-tx", + .no_pcm = 1, + .dpcm_capture = 1, + .be_id = MSM_BACKEND_DAI_USB_TX, + .be_hw_params_fixup = msm_common_be_hw_params_fixup, + .ignore_suspend = 1, + }, + { + .name = LPASS_BE_PRI_TDM_RX_0, + .stream_name = "Primary TDM0 Playback", + .cpu_dai_name = "msm-dai-q6-tdm.36864", + .platform_name = "msm-pcm-routing", + .codec_name = "msm-stub-codec.1", + .codec_dai_name = "msm-stub-rx", + .no_pcm = 1, + .dpcm_playback = 1, + .be_id = MSM_BACKEND_DAI_PRI_TDM_RX_0, + .be_hw_params_fixup = msm_common_be_hw_params_fixup, + .ops = &msm_tdm_be_ops, + .ignore_suspend = 1, + }, + { + .name = LPASS_BE_PRI_TDM_TX_0, + .stream_name = "Primary TDM0 Capture", + .cpu_dai_name = "msm-dai-q6-tdm.36865", + .platform_name = "msm-pcm-routing", + .codec_name = "msm-stub-codec.1", + .codec_dai_name = "msm-stub-tx", + .no_pcm = 1, + .dpcm_capture = 1, + .be_id = MSM_BACKEND_DAI_PRI_TDM_TX_0, + .be_hw_params_fixup = msm_common_be_hw_params_fixup, + .ops = &msm_tdm_be_ops, + .ignore_suspend = 1, + }, + { + .name = LPASS_BE_SEC_TDM_RX_0, + .stream_name = "Secondary TDM0 Playback", + .cpu_dai_name = "msm-dai-q6-tdm.36880", + .platform_name = "msm-pcm-routing", + .codec_name = "msm-stub-codec.1", + .codec_dai_name = "msm-stub-rx", + .no_pcm = 1, + .dpcm_playback = 1, + .be_id = MSM_BACKEND_DAI_SEC_TDM_RX_0, + .be_hw_params_fixup = msm_common_be_hw_params_fixup, + .ops = &msm_tdm_be_ops, + .ignore_suspend = 1, + }, + { + .name = LPASS_BE_SEC_TDM_TX_0, + .stream_name = "Secondary TDM0 Capture", + .cpu_dai_name = "msm-dai-q6-tdm.36881", + .platform_name = "msm-pcm-routing", + .codec_name = "msm-stub-codec.1", + .codec_dai_name = "msm-stub-tx", + .no_pcm = 1, + .dpcm_capture = 1, + .be_id = MSM_BACKEND_DAI_SEC_TDM_TX_0, + .be_hw_params_fixup = msm_common_be_hw_params_fixup, + .ops = &msm_tdm_be_ops, + .ignore_suspend = 1, + }, + { + .name = LPASS_BE_TERT_TDM_RX_0, + .stream_name = "Tertiary TDM0 Playback", + .cpu_dai_name = "msm-dai-q6-tdm.36896", + .platform_name = "msm-pcm-routing", + .codec_name = "msm-stub-codec.1", + .codec_dai_name = "msm-stub-rx", + .no_pcm = 1, + .dpcm_playback = 1, + .be_id = MSM_BACKEND_DAI_TERT_TDM_RX_0, + .be_hw_params_fixup = msm_common_be_hw_params_fixup, + .ops = &msm_tdm_be_ops, + .ignore_suspend = 1, + }, + { + .name = LPASS_BE_TERT_TDM_TX_0, + .stream_name = "Tertiary TDM0 Capture", + .cpu_dai_name = "msm-dai-q6-tdm.36897", + .platform_name = "msm-pcm-routing", + .codec_name = "msm-stub-codec.1", + .codec_dai_name = "msm-stub-tx", + .no_pcm = 1, + .dpcm_capture = 1, + .be_id = MSM_BACKEND_DAI_TERT_TDM_TX_0, + .be_hw_params_fixup = msm_common_be_hw_params_fixup, + .ops = &msm_tdm_be_ops, + .ignore_suspend = 1, + }, + { + .name = LPASS_BE_QUAT_TDM_RX_0, + .stream_name = "Quaternary TDM0 Playback", + .cpu_dai_name = "msm-dai-q6-tdm.36912", + .platform_name = "msm-pcm-routing", + .codec_name = "msm-stub-codec.1", + .codec_dai_name = "msm-stub-rx", + .no_pcm = 1, + .dpcm_playback = 1, + .be_id = MSM_BACKEND_DAI_QUAT_TDM_RX_0, + .be_hw_params_fixup = msm_common_be_hw_params_fixup, + .ops = &msm_tdm_be_ops, + .ignore_suspend = 1, + }, + { + .name = LPASS_BE_QUAT_TDM_TX_0, + .stream_name = "Quaternary TDM0 Capture", + .cpu_dai_name = "msm-dai-q6-tdm.36913", + .platform_name = "msm-pcm-routing", + .codec_name = "msm-stub-codec.1", + .codec_dai_name = "msm-stub-tx", + .no_pcm = 1, + .dpcm_capture = 1, + .be_id = MSM_BACKEND_DAI_QUAT_TDM_TX_0, + .be_hw_params_fixup = msm_common_be_hw_params_fixup, + .ops = &msm_tdm_be_ops, + .ignore_suspend = 1, + }, }; static struct snd_soc_dai_link msm_mi2s_be_dai_links[] = { @@ -2277,10 +2732,64 @@ static struct snd_soc_dai_link msm_auxpcm_be_dai_links[] = { }, }; + +static struct snd_soc_dai_link msm_wcn_be_dai_links[] = { + { + .name = LPASS_BE_SLIMBUS_7_RX, + .stream_name = "Slimbus7 Playback", + .cpu_dai_name = "msm-dai-q6-dev.16398", + .platform_name = "msm-pcm-routing", + .codec_name = "btfmslim_slave", + /* BT codec driver determines capabilities based on + * dai name, bt codecdai name should always contains + * supported usecase information + */ + .codec_dai_name = "btfm_bt_sco_a2dp_slim_rx", + .no_pcm = 1, + .dpcm_playback = 1, + .be_id = MSM_BACKEND_DAI_SLIMBUS_7_RX, + .be_hw_params_fixup = msm_btfm_be_hw_params_fixup, + .ops = &msm_wcn_ops, + /* dai link has playback support */ + .ignore_pmdown_time = 1, + .ignore_suspend = 1, + }, + { + .name = LPASS_BE_SLIMBUS_7_TX, + .stream_name = "Slimbus7 Capture", + .cpu_dai_name = "msm-dai-q6-dev.16399", + .platform_name = "msm-pcm-routing", + .codec_name = "btfmslim_slave", + .codec_dai_name = "btfm_bt_sco_slim_tx", + .no_pcm = 1, + .dpcm_capture = 1, + .be_id = MSM_BACKEND_DAI_SLIMBUS_7_TX, + .be_hw_params_fixup = msm_btfm_be_hw_params_fixup, + .ops = &msm_wcn_ops, + .ignore_suspend = 1, + }, + { + .name = LPASS_BE_SLIMBUS_8_TX, + .stream_name = "Slimbus8 Capture", + .cpu_dai_name = "msm-dai-q6-dev.16401", + .platform_name = "msm-pcm-routing", + .codec_name = "btfmslim_slave", + .codec_dai_name = "btfm_fm_slim_tx", + .no_pcm = 1, + .dpcm_capture = 1, + .be_id = MSM_BACKEND_DAI_SLIMBUS_8_TX, + .be_hw_params_fixup = msm_btfm_be_hw_params_fixup, + .init = &msm_wcn_init, + .ops = &msm_wcn_ops, + .ignore_suspend = 1, + }, +}; + static struct snd_soc_dai_link msm_int_dai_links[ ARRAY_SIZE(msm_int_dai) + ARRAY_SIZE(msm_mi2s_be_dai_links) + -ARRAY_SIZE(msm_auxpcm_be_dai_links)]; +ARRAY_SIZE(msm_auxpcm_be_dai_links)+ +ARRAY_SIZE(msm_wcn_be_dai_links)]; static struct snd_soc_card msmfalcon_card = { /* snd_soc_card_msmfalcon */ @@ -2357,6 +2866,14 @@ static struct snd_soc_card *msm_int_populate_sndcard_dailinks( sizeof(msm_auxpcm_be_dai_links)); len1 += ARRAY_SIZE(msm_auxpcm_be_dai_links); } + if (of_property_read_bool(dev->of_node, "qcom,wcn-btfm")) { + dev_dbg(dev, "%s(): WCN BTFM support present\n", + __func__); + memcpy(dailink + len1, + msm_wcn_be_dai_links, + sizeof(msm_wcn_be_dai_links)); + len1 += ARRAY_SIZE(msm_wcn_be_dai_links); + } card->dai_link = dailink; card->num_links = len1; return card; -- cgit v1.2.3 From f88f90a5478a2cdf2691dcd9457c6fbf54a5f174 Mon Sep 17 00:00:00 2001 From: Laxminath Kasam Date: Wed, 16 Nov 2016 19:27:44 +0530 Subject: ASoC: msm: Fix sound card registration failure In external codec machine driver, register SSR notifier after sound card register. Also, add separate snd_soc_card variables for tavil and tasha since same machine driver is used for both codecs. CRs-Fixed: 1083537 Change-Id: I73fc02b812f2e6694e2a6aa8bdad2381a5f19406 Signed-off-by: Laxminath Kasam --- sound/soc/msm/msmfalcon-common.c | 25 +++++++++++++++++-------- sound/soc/msm/msmfalcon-common.h | 8 +++++++- sound/soc/msm/msmfalcon-ext-dai-links.c | 19 +++++++++++++++---- sound/soc/msm/msmfalcon-external.c | 25 ++++++++++++++++--------- sound/soc/msm/msmfalcon-external.h | 8 +++++++- 5 files changed, 62 insertions(+), 23 deletions(-) diff --git a/sound/soc/msm/msmfalcon-common.c b/sound/soc/msm/msmfalcon-common.c index cdd3af21eaef..c82319539f39 100644 --- a/sound/soc/msm/msmfalcon-common.c +++ b/sound/soc/msm/msmfalcon-common.c @@ -2669,11 +2669,15 @@ static int msm_asoc_machine_probe(struct platform_device *pdev) if (!strcmp(match->data, "tasha_codec") || !strcmp(match->data, "tavil_codec")) { + if (!strcmp(match->data, "tasha_codec")) + pdata->snd_card_val = EXT_SND_CARD_TASHA; + else + pdata->snd_card_val = EXT_SND_CARD_TAVIL; ret = msm_ext_cdc_init(pdev, pdata, &card, &mbhc_cfg); if (ret) goto err; } else if (!strcmp(match->data, "internal_codec")) { - pdata->int_codec = 1; + pdata->snd_card_val = INT_SND_CARD; ret = msm_int_cdc_init(pdev, pdata, &card, &mbhc_cfg); if (ret) goto err; @@ -2685,12 +2689,15 @@ static int msm_asoc_machine_probe(struct platform_device *pdev) if (!card) goto err; - /*reading the gpio configurations from dtsi file*/ - ret = msm_gpioset_initialize(CLIENT_WCD, &pdev->dev); - if (ret < 0) { - dev_err(&pdev->dev, - "%s: error reading dtsi files%d\n", __func__, ret); - goto err; + if (pdata->snd_card_val == INT_SND_CARD) { + /*reading the gpio configurations from dtsi file*/ + ret = msm_gpioset_initialize(CLIENT_WCD, &pdev->dev); + if (ret < 0) { + dev_err(&pdev->dev, + "%s: error reading dtsi files%d\n", + __func__, ret); + goto err; + } } /* @@ -2739,6 +2746,8 @@ static int msm_asoc_machine_probe(struct platform_device *pdev) ret); goto err; } + if (pdata->snd_card_val != INT_SND_CARD) + msm_ext_register_audio_notifier(); return 0; err: if (pdata->us_euro_gpio > 0) { @@ -2767,7 +2776,7 @@ static int msm_asoc_machine_remove(struct platform_device *pdev) struct snd_soc_card *card = platform_get_drvdata(pdev); struct msm_asoc_mach_data *pdata = snd_soc_card_get_drvdata(card); - if (pdata->int_codec) + if (pdata->snd_card_val == INT_SND_CARD) mutex_destroy(&pdata->cdc_int_mclk0_mutex); msm_free_auxdev_mem(pdev); diff --git a/sound/soc/msm/msmfalcon-common.h b/sound/soc/msm/msmfalcon-common.h index 50495c161347..5f6b8592acec 100644 --- a/sound/soc/msm/msmfalcon-common.h +++ b/sound/soc/msm/msmfalcon-common.h @@ -65,6 +65,12 @@ struct msmfalcon_codec { enum afe_config_type config_type); }; +enum { + INT_SND_CARD, + EXT_SND_CARD_TASHA, + EXT_SND_CARD_TAVIL, +}; + struct msm_asoc_mach_data { int us_euro_gpio; /* used by gpio driver API */ int hph_en1_gpio; @@ -78,6 +84,7 @@ struct msm_asoc_mach_data { int spk_ext_pa_gpio; int mclk_freq; int lb_mode; + int snd_card_val; u8 micbias1_cap_mode; u8 micbias2_cap_mode; atomic_t int_mclk0_rsc_ref; @@ -85,7 +92,6 @@ struct msm_asoc_mach_data { struct mutex cdc_int_mclk0_mutex; struct delayed_work disable_int_mclk0_work; struct afe_clk_set digital_cdc_core_clk; - bool int_codec; }; int msm_common_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd, diff --git a/sound/soc/msm/msmfalcon-ext-dai-links.c b/sound/soc/msm/msmfalcon-ext-dai-links.c index ce9e41cc11cc..6f066c5945a9 100644 --- a/sound/soc/msm/msmfalcon-ext-dai-links.c +++ b/sound/soc/msm/msmfalcon-ext-dai-links.c @@ -29,7 +29,8 @@ #define WCN_CDC_SLIM_RX_CH_MAX 2 #define WCN_CDC_SLIM_TX_CH_MAX 3 -static struct snd_soc_card snd_soc_card_msm_card; +static struct snd_soc_card snd_soc_card_msm_card_tavil; +static struct snd_soc_card snd_soc_card_msm_card_tasha; static struct snd_soc_ops msm_ext_slimbus_be_ops = { .hw_params = msm_snd_hw_params, @@ -1851,13 +1852,24 @@ ARRAY_SIZE(msm_wcn_be_dai_links)]; * * Returns card on success or NULL on failure. */ -struct snd_soc_card *populate_snd_card_dailinks(struct device *dev) +struct snd_soc_card *populate_snd_card_dailinks(struct device *dev, + int snd_card_val) { - struct snd_soc_card *card = &snd_soc_card_msm_card; + struct snd_soc_card *card; struct snd_soc_dai_link *msm_ext_dai_links = NULL; int ret, len1, len2, len3, len4; enum codec_variant codec_ver = 0; + if (snd_card_val == EXT_SND_CARD_TASHA) { + card = &snd_soc_card_msm_card_tasha; + } else if (snd_card_val == EXT_SND_CARD_TAVIL) { + card = &snd_soc_card_msm_card_tavil; + } else { + dev_err(dev, "%s: failing as no matching card name\n", + __func__); + return NULL; + } + card->dev = dev; ret = snd_soc_of_parse_card_name(card, "qcom,model"); if (ret) { @@ -1949,7 +1961,6 @@ struct snd_soc_card *populate_snd_card_dailinks(struct device *dev) } card->dai_link = msm_ext_dai_links; card->num_links = len4; - card->dev = dev; return card; } diff --git a/sound/soc/msm/msmfalcon-external.c b/sound/soc/msm/msmfalcon-external.c index 0a82eb87d267..3934c50c48a9 100644 --- a/sound/soc/msm/msmfalcon-external.c +++ b/sound/soc/msm/msmfalcon-external.c @@ -1684,6 +1684,21 @@ err_mbhc_cal: } EXPORT_SYMBOL(msm_audrx_init); +/** + * msm_ext_register_audio_notifier - register SSR notifier. + */ +void msm_ext_register_audio_notifier(void) +{ + int ret; + + ret = audio_notifier_register("msmfalcon", AUDIO_NOTIFIER_ADSP_DOMAIN, + &service_nb); + if (ret < 0) + pr_err("%s: Audio notifier register failed ret = %d\n", + __func__, ret); +} +EXPORT_SYMBOL(msm_ext_register_audio_notifier); + /** * msm_ext_cdc_init - external codec machine specific init. * @@ -1708,24 +1723,16 @@ int msm_ext_cdc_init(struct platform_device *pdev, wcd_mbhc_cfg_ptr->anc_micbias = MIC_BIAS_2; wcd_mbhc_cfg_ptr->enable_anc_mic_detect = false; - *card = populate_snd_card_dailinks(&pdev->dev); + *card = populate_snd_card_dailinks(&pdev->dev, pdata->snd_card_val); if (!(*card)) { dev_err(&pdev->dev, "%s: Card uninitialized\n", __func__); ret = -EPROBE_DEFER; goto err; } - (*card)->dev = &pdev->dev; spdev = pdev; platform_set_drvdata(pdev, *card); snd_soc_card_set_drvdata(*card, pdata); is_initial_boot = true; - ret = audio_notifier_register("msmfalcon", AUDIO_NOTIFIER_ADSP_DOMAIN, - &service_nb); - if (ret < 0) { - pr_err("%s: Audio notifier register failed ret = %d\n", - __func__, ret); - goto err; - } pdata->hph_en1_gpio = of_get_named_gpio(pdev->dev.of_node, "qcom,hph-en1-gpio", 0); if (!gpio_is_valid(pdata->hph_en1_gpio)) diff --git a/sound/soc/msm/msmfalcon-external.h b/sound/soc/msm/msmfalcon-external.h index 24aa7ea53a09..654cb70b9c84 100644 --- a/sound/soc/msm/msmfalcon-external.h +++ b/sound/soc/msm/msmfalcon-external.h @@ -26,12 +26,14 @@ int msm_proxy_tx_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd, int msm_audrx_init(struct snd_soc_pcm_runtime *rtd); int msm_snd_cpe_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params); -struct snd_soc_card *populate_snd_card_dailinks(struct device *dev); +struct snd_soc_card *populate_snd_card_dailinks(struct device *dev, + int snd_card_val); int msm_ext_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd, struct snd_pcm_hw_params *params); #ifdef CONFIG_SND_SOC_EXT_CODEC int msm_ext_cdc_init(struct platform_device *, struct msm_asoc_mach_data *, struct snd_soc_card **, struct wcd_mbhc_config *); +void msm_ext_register_audio_notifier(void); #else inline int msm_ext_cdc_init(struct platform_device *pdev, struct msm_asoc_mach_data *pdata, @@ -40,5 +42,9 @@ inline int msm_ext_cdc_init(struct platform_device *pdev, { return 0; } + +inline void msm_ext_register_audio_notifier(void) +{ +} #endif #endif -- cgit v1.2.3 From 316ea48ad654703ca8bdb25044b0282a2621d1bf Mon Sep 17 00:00:00 2001 From: Padmanabhan Komanduru Date: Thu, 17 Nov 2016 13:45:50 +0530 Subject: Revert "defconfig: msm: avoid compilation of MDSS DP driver for 32-bit msmfalcon" This reverts 'commit d3c76b29e6d6 ("defconfig: msm: avoid compilation of MDSS DP driver for 32-bit msmfalcon")'. The compilation of MDSS DP driver was disabled for 32-bit msmfalcon earlier to avoid compilation issues. The related issues are now resolved. Hence, enable back the compilation of DP driver. Change-Id: I9f928f0aad6af346de43965755beb039e422047a Signed-off-by: Padmanabhan Komanduru --- arch/arm/configs/msmfalcon_defconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/arm/configs/msmfalcon_defconfig b/arch/arm/configs/msmfalcon_defconfig index 511b9fe32b9b..d10fba1dc4b5 100644 --- a/arch/arm/configs/msmfalcon_defconfig +++ b/arch/arm/configs/msmfalcon_defconfig @@ -337,6 +337,7 @@ CONFIG_FB_MSM=y CONFIG_FB_MSM_MDSS=y CONFIG_FB_MSM_MDSS_WRITEBACK=y CONFIG_FB_MSM_MDSS_HDMI_PANEL=y +CONFIG_FB_MSM_MDSS_DP_PANEL=y CONFIG_FB_MSM_MDSS_XLOG_DEBUG=y CONFIG_LOGO=y # CONFIG_LOGO_LINUX_MONO is not set -- cgit v1.2.3 From 596b431a5f11981a5d002ae941930f91612f7bd8 Mon Sep 17 00:00:00 2001 From: Fenglin Wu Date: Wed, 9 Nov 2016 13:37:08 +0800 Subject: leds: qpnp-wled: Add support to configure auto PFM for pmicobalt The WLED boost controller in pmicobalt supports auto PFM mode when LCD mode is selected. Auto PFM mode is enabled by default except on some specific hardware versions. Add a property to specify AUTO_PFM_THRESHOLD for the boost controller so that it can enter PFM mode when the adaptive headroom voltage falls below the threshold. CRs-Fixed: 1081738 Change-Id: I964b3452d0cdb3618b4ab446655ae75fa3a1049d Signed-off-by: Fenglin Wu --- .../devicetree/bindings/leds/leds-qpnp-wled.txt | 3 ++ drivers/leds/leds-qpnp-wled.c | 52 ++++++++++++++++++++++ 2 files changed, 55 insertions(+) diff --git a/Documentation/devicetree/bindings/leds/leds-qpnp-wled.txt b/Documentation/devicetree/bindings/leds/leds-qpnp-wled.txt index 15924f659e61..4b23cb1e9a9c 100644 --- a/Documentation/devicetree/bindings/leds/leds-qpnp-wled.txt +++ b/Documentation/devicetree/bindings/leds/leds-qpnp-wled.txt @@ -72,6 +72,9 @@ Optional properties for WLED: - qcom,loop-auto-gm-en : A boolean property to specify if auto gm is enabled. - qcom,loop-auto-gm-thresh : Specify auto gm threshold if "loop-auto-gm-en" is defined. Supported values are: 0 - 3. +- qcom,lcd-auto-pfm-thresh : Specify the auto-pfm threshold, if the headroom voltage level + falls below this threshold and auto PFM is enabled, boost + controller will enter into PFM mode automatically. Optional properties if 'qcom,disp-type-amoled' is mentioned in DT: - qcom,loop-comp-res-kohm : control to select the compensation resistor in kohm. default is 320. diff --git a/drivers/leds/leds-qpnp-wled.c b/drivers/leds/leds-qpnp-wled.c index 0e359962ca37..79c54edefdc5 100644 --- a/drivers/leds/leds-qpnp-wled.c +++ b/drivers/leds/leds-qpnp-wled.c @@ -50,6 +50,7 @@ #define QPNP_WLED_VLOOP_COMP_RES_REG(b) (b + 0x55) #define QPNP_WLED_VLOOP_COMP_GM_REG(b) (b + 0x56) #define QPNP_WLED_PSM_CTRL_REG(b) (b + 0x5B) +#define QPNP_WLED_LCD_AUTO_PFM_REG(b) (b + 0x5C) #define QPNP_WLED_SC_PRO_REG(b) (b + 0x5E) #define QPNP_WLED_SWIRE_AVDD_REG(b) (b + 0x5F) #define QPNP_WLED_CTRL_SPARE_REG(b) (b + 0xDF) @@ -87,6 +88,11 @@ #define QPNP_WLED_VREF_PSM_MAX_MV 750 #define QPNP_WLED_VREF_PSM_DFLT_AMOLED_MV 450 #define QPNP_WLED_PSM_CTRL_OVERWRITE 0x80 +#define QPNP_WLED_LCD_AUTO_PFM_DFLT_THRESH 1 +#define QPNP_WLED_LCD_AUTO_PFM_THRESH_MAX 0xF +#define QPNP_WLED_LCD_AUTO_PFM_EN_SHIFT 7 +#define QPNP_WLED_LCD_AUTO_PFM_EN_BIT BIT(7) +#define QPNP_WLED_LCD_AUTO_PFM_THRESH_MASK GENMASK(3, 0) #define QPNP_WLED_ILIM_MASK GENMASK(2, 0) #define QPNP_WLED_ILIM_OVERWRITE BIT(7) @@ -327,7 +333,9 @@ static struct wled_vref_setting vref_setting_pmicobalt = { * @ strings - supported list of strings * @ num_strings - number of strings * @ loop_auto_gm_thresh - the clamping level for auto gm + * @ lcd_auto_pfm_thresh - the threshold for lcd auto pfm mode * @ loop_auto_gm_en - select if auto gm is enabled + * @ lcd_auto_pfm_en - select if auto pfm is enabled in lcd mode * @ avdd_mode_spmi - enable avdd programming via spmi * @ en_9b_dim_res - enable or disable 9bit dimming * @ en_phase_stag - enable or disable phase staggering @@ -372,7 +380,9 @@ struct qpnp_wled { u8 strings[QPNP_WLED_MAX_STRINGS]; u8 num_strings; u8 loop_auto_gm_thresh; + u8 lcd_auto_pfm_thresh; bool loop_auto_gm_en; + bool lcd_auto_pfm_en; bool avdd_mode_spmi; bool en_9b_dim_res; bool en_phase_stag; @@ -1363,6 +1373,24 @@ static int qpnp_wled_config(struct qpnp_wled *wled) return rc; } + /* Configure auto PFM mode for LCD mode only */ + if ((wled->pmic_rev_id->pmic_subtype == PMICOBALT_SUBTYPE || + wled->pmic_rev_id->pmic_subtype == PM2FALCON_SUBTYPE) + && !wled->disp_type_amoled) { + reg = 0; + reg |= wled->lcd_auto_pfm_thresh; + reg |= wled->lcd_auto_pfm_en << + QPNP_WLED_LCD_AUTO_PFM_EN_SHIFT; + rc = qpnp_wled_masked_write_reg(wled, + QPNP_WLED_LCD_AUTO_PFM_EN_BIT | + QPNP_WLED_LCD_AUTO_PFM_THRESH_MASK, ®, + QPNP_WLED_LCD_AUTO_PFM_REG(wled->ctrl_base)); + if (rc < 0) { + pr_err("Write LCD_AUTO_PFM failed, rc=%d\n", rc); + return rc; + } + } + /* Configure the Soft start Ramp delay: for AMOLED - 0,for LCD - 2 */ reg = (wled->disp_type_amoled) ? 0 : 2; rc = qpnp_wled_write_reg(wled, reg, @@ -1779,6 +1807,30 @@ static int qpnp_wled_parse_dt(struct qpnp_wled *wled) } } + if (wled->pmic_rev_id->pmic_subtype == PMICOBALT_SUBTYPE || + wled->pmic_rev_id->pmic_subtype == PM2FALCON_SUBTYPE) { + + if (wled->pmic_rev_id->rev4 == PMICOBALT_V2P0_REV4) + wled->lcd_auto_pfm_en = false; + else + wled->lcd_auto_pfm_en = true; + + wled->lcd_auto_pfm_thresh = QPNP_WLED_LCD_AUTO_PFM_DFLT_THRESH; + rc = of_property_read_u8(pdev->dev.of_node, + "qcom,lcd-auto-pfm-thresh", + &wled->lcd_auto_pfm_thresh); + if (rc && rc != -EINVAL) { + dev_err(&pdev->dev, + "Unable to read lcd-auto-pfm-thresh\n"); + return rc; + } + + if (wled->lcd_auto_pfm_thresh > + QPNP_WLED_LCD_AUTO_PFM_THRESH_MAX) + wled->lcd_auto_pfm_thresh = + QPNP_WLED_LCD_AUTO_PFM_THRESH_MAX; + } + wled->sc_deb_cycles = QPNP_WLED_SC_DEB_CYCLES_DFLT; rc = of_property_read_u32(pdev->dev.of_node, "qcom,sc-deb-cycles", &temp_val); -- cgit v1.2.3 From 877c99e11d513f9dd8b3159627d0fe02e6f7617c Mon Sep 17 00:00:00 2001 From: Fenglin Wu Date: Thu, 10 Nov 2016 10:17:02 +0800 Subject: ARM: dts: msm: Enable auto GM for WLED in pmicobalt Enable auto GM for WLED module in pmicobalt to make LOOP_GM adaptively changes with brightness change. CRs-Fixed: 1081738 Change-Id: I10a788726358c56df9bfe11f2332e3823d7cd332 Signed-off-by: Fenglin Wu --- arch/arm/boot/dts/qcom/msm-pmicobalt.dtsi | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/arm/boot/dts/qcom/msm-pmicobalt.dtsi b/arch/arm/boot/dts/qcom/msm-pmicobalt.dtsi index 8c0c65361f2c..d6bd6b3054dc 100644 --- a/arch/arm/boot/dts/qcom/msm-pmicobalt.dtsi +++ b/arch/arm/boot/dts/qcom/msm-pmicobalt.dtsi @@ -609,6 +609,7 @@ qcom,led-strings-list = [00 01 02 03]; qcom,en-ext-pfet-sc-pro; qcom,pmic-revid = <&pmicobalt_revid>; + qcom,loop-auto-gm-en; }; pmicobalt_haptics: qcom,haptic@c000 { -- cgit v1.2.3 From 3c251aca9011acfb62d116d0cb22124ff3575c2b Mon Sep 17 00:00:00 2001 From: Dhoat Harpal Date: Mon, 14 Nov 2016 16:41:04 +0530 Subject: soc: qcom: smem: Redesign smem memory architecture Smem uses static array to store legacy partition information. New comm partition is used to replace existing legacy partition. CRs-Fixed: 1074985 Change-Id: Ib2268181a617c23d62b5b6f857be5327113b2a67 Signed-off-by: Dhoat Harpal --- drivers/soc/qcom/msm_smem.c | 137 ++++++++++++++++++++++++++++------------ drivers/soc/qcom/smem_debug.c | 9 ++- drivers/soc/qcom/smem_private.h | 3 +- 3 files changed, 102 insertions(+), 47 deletions(-) diff --git a/drivers/soc/qcom/msm_smem.c b/drivers/soc/qcom/msm_smem.c index cd3d387645fd..8f5ad7af8d0d 100644 --- a/drivers/soc/qcom/msm_smem.c +++ b/drivers/soc/qcom/msm_smem.c @@ -84,6 +84,7 @@ static int smem_module_inited; static RAW_NOTIFIER_HEAD(smem_module_init_notifier_list); static DEFINE_MUTEX(smem_module_init_notifier_lock); static bool probe_done; +uint32_t smem_max_items; /* smem security feature components */ #define SMEM_TOC_IDENTIFIER 0x434f5424 /* "$TOC" */ @@ -139,6 +140,11 @@ struct smem_partition_info { }; static struct smem_partition_info partitions[NUM_SMEM_SUBSYSTEMS]; + +#define SMEM_COMM_PART_VERSION 0x000C +#define SMEM_COMM_HOST 0xFFFE +static bool use_comm_partition; +static struct smem_partition_info comm_partition; /* end smem security feature components */ /* Identifier for the SMEM target info struct. */ @@ -149,6 +155,7 @@ struct smem_targ_info_type { uint32_t identifier; uint32_t size; phys_addr_t phys_base_addr; + uint32_t max_items; }; struct restart_notifier_block { @@ -312,7 +319,7 @@ static void *__smem_get_entry_nonsecure(unsigned id, unsigned *size, if (!skip_init_check && !smem_initialized_check()) return ret; - if (id >= SMEM_NUM_ITEMS) + if (id >= smem_max_items) return ret; if (use_spinlocks) { @@ -374,7 +381,7 @@ static void *__smem_get_entry_secure(unsigned id, if (!skip_init_check && !smem_initialized_check()) return NULL; - if (id >= SMEM_NUM_ITEMS) { + if (id >= smem_max_items) { SMEM_INFO("%s: invalid id %d\n", __func__, id); return NULL; } @@ -385,12 +392,18 @@ static void *__smem_get_entry_secure(unsigned id, return NULL; } - if (flags & SMEM_ANY_HOST_FLAG || !partitions[to_proc].offset) - return __smem_get_entry_nonsecure(id, size, skip_init_check, - use_rspinlock); - - partition_num = partitions[to_proc].partition_num; - hdr = smem_areas[0].virt_addr + partitions[to_proc].offset; + if (flags & SMEM_ANY_HOST_FLAG || !partitions[to_proc].offset) { + if (use_comm_partition) { + partition_num = comm_partition.partition_num; + hdr = smem_areas[0].virt_addr + comm_partition.offset; + } else { + return __smem_get_entry_nonsecure(id, size, + skip_init_check, use_rspinlock); + } + } else { + partition_num = partitions[to_proc].partition_num; + hdr = smem_areas[0].virt_addr + partitions[to_proc].offset; + } if (unlikely(!spinlocks_initialized)) { rc = init_smem_remote_spinlock(); if (unlikely(rc)) { @@ -613,8 +626,19 @@ static void *alloc_item_secure(unsigned id, unsigned size_in, unsigned to_proc, uint32_t partition_num; void *ret = NULL; - hdr = smem_base + partitions[to_proc].offset; - partition_num = partitions[to_proc].partition_num; + if (to_proc == SMEM_COMM_HOST) { + hdr = smem_base + comm_partition.offset; + partition_num = comm_partition.partition_num; + size_cacheline = comm_partition.size_cacheline; + } else if (to_proc < NUM_SMEM_SUBSYSTEMS) { + hdr = smem_base + partitions[to_proc].offset; + partition_num = partitions[to_proc].partition_num; + size_cacheline = partitions[to_proc].size_cacheline; + } else { + SMEM_INFO("%s: invalid to_proc %u for id %u\n", __func__, + to_proc, id); + return NULL; + } if (hdr->identifier != SMEM_PART_HDR_IDENTIFIER) { LOG_ERR( @@ -626,7 +650,6 @@ static void *alloc_item_secure(unsigned id, unsigned size_in, unsigned to_proc, BUG(); } - size_cacheline = partitions[to_proc].size_cacheline; free_space = hdr->offset_free_cached - hdr->offset_free_uncached; @@ -718,7 +741,7 @@ void *smem_alloc(unsigned id, unsigned size_in, unsigned to_proc, if (!smem_initialized_check()) return NULL; - if (id >= SMEM_NUM_ITEMS) { + if (id >= smem_max_items) { SMEM_INFO("%s: invalid id %u\n", __func__, id); return NULL; } @@ -761,11 +784,16 @@ void *smem_alloc(unsigned id, unsigned size_in, unsigned to_proc, if (id > SMEM_FIXED_ITEM_LAST) { SMEM_INFO("%s: allocating %u size %u to_proc %u flags %u\n", __func__, id, size_in, to_proc, flags); - if (flags & SMEM_ANY_HOST_FLAG || !partitions[to_proc].offset) - ret = alloc_item_nonsecure(id, a_size_in); - else + if (flags & SMEM_ANY_HOST_FLAG + || !partitions[to_proc].offset) { + if (use_comm_partition) + ret = alloc_item_secure(id, size_in, + SMEM_COMM_HOST, flags); + else + ret = alloc_item_nonsecure(id, a_size_in); + } else { ret = alloc_item_secure(id, size_in, to_proc, flags); - + } } else { SMEM_INFO("%s: attempted to allocate non-dynamic item %u\n", __func__, id); @@ -893,14 +921,18 @@ EXPORT_SYMBOL(smem_get_free_space); unsigned smem_get_version(unsigned idx) { int *version_array; + struct smem_shared *smem = smem_ram_base; if (idx > 32) { pr_err("%s: invalid idx:%d\n", __func__, idx); return 0; } - version_array = __smem_find(SMEM_VERSION_INFO, SMEM_VERSION_INFO_SIZE, - true); + if (use_comm_partition) + version_array = smem->version; + else + version_array = __smem_find(SMEM_VERSION_INFO, + SMEM_VERSION_INFO_SIZE, true); if (version_array == NULL) return 0; @@ -948,6 +980,7 @@ bool smem_initialized_check(void) static int is_inited; unsigned long flags; struct smem_shared *smem; + unsigned ver; if (likely(checked)) { if (unlikely(!is_inited)) @@ -976,8 +1009,12 @@ bool smem_initialized_check(void) * structures. Without the extra configuration data, the SMEM driver * cannot be properly initialized. */ - if (smem_get_version(MODEM_SBL_VERSION_INDEX) != SMEM_VERSION << 16) { - pr_err("%s: SBL version not correct\n", __func__); + ver = smem->version[MODEM_SBL_VERSION_INDEX]; + if (ver == SMEM_COMM_PART_VERSION << 16) { + use_comm_partition = true; + } else if (ver != SMEM_VERSION << 16) { + pr_err("%s: SBL version not correct 0x%x\n", + __func__, smem->version[7]); goto failed; } @@ -1122,6 +1159,7 @@ static void smem_init_security_partition(struct smem_toc_entry *entry, { uint16_t remote_host; struct smem_partition_header *hdr; + bool is_comm_partition = false; if (!entry->offset) { SMEM_INFO("Skipping smem partition %d - bad offset\n", num); @@ -1136,31 +1174,38 @@ static void smem_init_security_partition(struct smem_toc_entry *entry, return; } - if (entry->host0 == SMEM_APPS) - remote_host = entry->host1; - else - remote_host = entry->host0; + if (entry->host0 == SMEM_COMM_HOST && entry->host1 == SMEM_COMM_HOST) + is_comm_partition = true; - if (remote_host >= NUM_SMEM_SUBSYSTEMS) { - SMEM_INFO("Skipping smem partition %d - bad remote:%d\n", num, - remote_host); - return; - } - if (partitions[remote_host].offset) { - SMEM_INFO("Skipping smem partition %d - duplicate of %d\n", num, - partitions[remote_host].partition_num); - return; - } + if (!is_comm_partition) { + if (entry->host0 == SMEM_APPS) + remote_host = entry->host1; + else + remote_host = entry->host0; - hdr = smem_areas[0].virt_addr + entry->offset; + if (remote_host >= NUM_SMEM_SUBSYSTEMS) { + SMEM_INFO( + "Skipping smem partition %d - bad remote:%d\n", + num, remote_host); + return; + } + if (partitions[remote_host].offset) { + SMEM_INFO( + "Skipping smem partition %d - duplicate of %d\n", + num, partitions[remote_host].partition_num); + return; + } - if (entry->host0 != SMEM_APPS && entry->host1 != SMEM_APPS) { - SMEM_INFO( - "Non-APSS Partition %d offset:%x host0:%d host1:%d\n", - num, entry->offset, entry->host0, entry->host1); - return; + if (entry->host0 != SMEM_APPS && entry->host1 != SMEM_APPS) { + SMEM_INFO( + "Non-APSS Partition %d offset:%x host0:%d host1:%d\n", + num, entry->offset, entry->host0, entry->host1); + return; + } } + hdr = smem_areas[0].virt_addr + entry->offset; + if (hdr->identifier != SMEM_PART_HDR_IDENTIFIER) { LOG_ERR("Smem partition %d hdr magic is bad\n", num); BUG(); @@ -1177,6 +1222,14 @@ static void smem_init_security_partition(struct smem_toc_entry *entry, LOG_ERR("Smem partition %d cached heap exceeds size\n", num); BUG(); } + if (hdr->host0 == SMEM_COMM_HOST && hdr->host1 == SMEM_COMM_HOST) { + comm_partition.partition_num = num; + comm_partition.offset = entry->offset; + comm_partition.size_cacheline = entry->size_cacheline; + SMEM_INFO("Common Partition %d offset:%x\n", num, + entry->offset); + return; + } if (hdr->host0 != SMEM_APPS && hdr->host1 != SMEM_APPS) { LOG_ERR("Smem partition %d hosts don't match TOC\n", num); BUG(); @@ -1253,6 +1306,8 @@ static int smem_init_target_info(phys_addr_t info_addr, resource_size_t size) } smem_ram_phys = smem_targ_info->phys_base_addr; smem_ram_size = smem_targ_info->size; + if (smem_targ_info->max_items) + smem_max_items = smem_targ_info->max_items; iounmap(smem_targ_info_addr); return 0; } @@ -1488,7 +1543,7 @@ int __init msm_smem_init(void) return 0; registered = true; - + smem_max_items = SMEM_NUM_ITEMS; smem_ipc_log_ctx = ipc_log_context_create(NUM_LOG_PAGES, "smem", 0); if (!smem_ipc_log_ctx) { pr_err("%s: unable to create logging context\n", __func__); diff --git a/drivers/soc/qcom/smem_debug.c b/drivers/soc/qcom/smem_debug.c index ace89afb614c..766a1781e6b9 100644 --- a/drivers/soc/qcom/smem_debug.c +++ b/drivers/soc/qcom/smem_debug.c @@ -1,7 +1,7 @@ /* arch/arm/mach-msm/smem_debug.c * * Copyright (C) 2007 Google, Inc. - * Copyright (c) 2009-2013, The Linux Foundation. All rights reserved. + * Copyright (c) 2009-2013,2016 The Linux Foundation. All rights reserved. * Author: Brian Swetland * * This software is licensed under the terms of the GNU General Public @@ -53,7 +53,7 @@ static void debug_read_mem(struct seq_file *s) heap_info->free_offset, heap_info->heap_remaining); - for (n = 0; n < SMEM_NUM_ITEMS; n++) { + for (n = 0; n < smem_max_items; n++) { if (toc[n].allocated == 0) continue; seq_printf(s, "%04d: offset %08x size %08x\n", @@ -67,9 +67,8 @@ static void debug_read_smem_version(struct seq_file *s) for (n = 0; n < 32; n++) { version = smem_get_version(n); - seq_printf(s, "entry %d: smem = %d proc_comm = %d\n", n, - version >> 16, - version & 0xffff); + seq_printf(s, "entry %d:%x smem = %d proc_comm = %d\n", + n, version, version >> 16, version & 0xffff); } } diff --git a/drivers/soc/qcom/smem_private.h b/drivers/soc/qcom/smem_private.h index 7aeca5eed8d2..ddbc29e30dfb 100644 --- a/drivers/soc/qcom/smem_private.h +++ b/drivers/soc/qcom/smem_private.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2013, The Linux Foundation. All rights reserved. +/* Copyright (c) 2013,2016 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 @@ -18,6 +18,7 @@ #define SMD_HEAP_SIZE 512 +extern uint32_t smem_max_items; struct smem_heap_info { unsigned initialized; -- cgit v1.2.3 From 1a8e292bce506109fc61e567549cf1fcc9bbc607 Mon Sep 17 00:00:00 2001 From: Amar Singhal Date: Wed, 16 Nov 2016 11:20:33 -0800 Subject: msm: wlan: update regulatory database Incorporate the 2016-10-31 updates to the internal regulatory database. Update countries Bahrain, Belize, Chile, Egypt, Honduras, India, S Korea, Nepal, Panama, Russia, Senegal, TT and UAE. Also update St. Kitts&Navis and St. Lucia dfs region. Change-Id: Ia151b2dd5229f07790ac961af298305b24e098fb CRs-Fixed: 1091511 Signed-off-by: Amar Singhal --- net/wireless/db.txt | 95 +++++++++++++++++++++++++---------------------------- 1 file changed, 44 insertions(+), 51 deletions(-) diff --git a/net/wireless/db.txt b/net/wireless/db.txt index 23b7c76ff2d8..89130cf4db04 100644 --- a/net/wireless/db.txt +++ b/net/wireless/db.txt @@ -16,7 +16,7 @@ country 00: (57240 - 63720 @ 2160), (0) -country AE: DFS-FCC +country AE: DFS-ETSI (2402 - 2482 @ 40), (20) (5170 - 5250 @ 80), (24), AUTO-BW (5250 - 5330 @ 80), (24), DFS, AUTO-BW @@ -52,13 +52,12 @@ country AN: DFS-ETSI (5250 - 5330 @ 80), (23), DFS, AUTO-BW (5490 - 5710 @ 160), (30), DFS -country AR: DFS-FCC - (2402 - 2482 @ 40), (20) - (5170 - 5250 @ 80), (24), AUTO-BW - (5250 - 5330 @ 80), (24), DFS, AUTO-BW - (5490 - 5590 @ 80), (24), DFS - (5650 - 5730 @ 80), (24), DFS - (5735 - 5835 @ 80), (30) +country AR: + (2402 - 2482 @ 40), (36) + (5170 - 5330 @ 160), (23) + (5490 - 5590 @ 80), (36) + (5650 - 5730 @ 80), (36) + (5735 - 5835 @ 80), (36) country AS: DFS-FCC (2402 - 2472 @ 40), (30) @@ -162,11 +161,10 @@ country BG: DFS-ETSI # 60 gHz band channels 1-4, ref: Etsi En 302 567 (57240 - 65880 @ 2160), (40), NO-OUTDOOR -country BH: DFS-ETSI +country BH: (2402 - 2482 @ 40), (20) - (5170 - 5250 @ 20), (20) - (5250 - 5330 @ 20), (20), DFS - (5735 - 5835 @ 20), (20) + (5170 - 5330 @ 20), (23) + (5735 - 5835 @ 20), (33) country BL: DFS-ETSI (2402 - 2482 @ 40), (20) @@ -219,8 +217,10 @@ country BY: DFS-ETSI (5490 - 5710 @ 160), (30), DFS country BZ: - (2402 - 2482 @ 40), (30) - (5735 - 5835 @ 80), (30) + (2402 - 2482 @ 40), (36) + (5170 - 5330 @ 160), (27) + (5490 - 5730 @ 160), (36) + (5735 - 5835 @ 80), (36) country CA: DFS-FCC (2402 - 2472 @ 40), (30) @@ -259,10 +259,9 @@ country CI: DFS-FCC (5490 - 5730 @ 160), (24), DFS (5735 - 5835 @ 80), (30) -country CL: DFS-ETSI +country CL: (2402 - 2482 @ 40), (20) - (5170 - 5250 @ 80), (20), AUTO-BW - (5250 - 5330 @ 80), (20), DFS, AUTO-BW + (5170 - 5330 @ 160), (20) (5735 - 5835 @ 80), (20) country CN: DFS-FCC @@ -416,9 +415,9 @@ country EE: DFS-ETSI (57240 - 65880 @ 2160), (40), NO-OUTDOOR country EG: DFS-ETSI - (2402 - 2482 @ 20), (20) - (5170 - 5250 @ 20), (23) - (5250 - 5330 @ 20), (23), DFS + (2402 - 2482 @ 40), (20) + (5170 - 5250 @ 40), (23) + (5250 - 5330 @ 40), (23), DFS country ES: DFS-ETSI (2402 - 2482 @ 40), (20) @@ -581,11 +580,10 @@ country HK: DFS-FCC (5490 - 5730 @ 160), (24), DFS (5735 - 5835 @ 80), (30) -country HN: DFS-FCC +country HN: (2402 - 2482 @ 40), (20) - (5170 - 5250 @ 80), (24), AUTO-BW - (5250 - 5330 @ 80), (24), DFS, AUTO-BW - (5490 - 5730 @ 160), (24), DFS + (5170 - 5330 @ 160), (24) + (5490 - 5730 @ 160), (24) (5735 - 5835 @ 80), (30) country HR: DFS-ETSI @@ -657,10 +655,9 @@ country IL: DFS-ETSI (5170 - 5250 @ 80), (23), AUTO-BW (5250 - 5330 @ 80), (23), DFS, AUTO-BW -country IN: DFS-ETSI +country IN: (2402 - 2482 @ 40), (20) - (5170 - 5250 @ 80), (23), AUTO-BW - (5250 - 5330 @ 80), (23), DFS, AUTO-BW + (5170 - 5330 @ 160), (23) (5735 - 5835 @ 80), (30) country IR: @@ -735,7 +732,7 @@ country KH: DFS-ETSI (5250 - 5330 @ 80), (23), DFS, AUTO-BW (5490 - 5710 @ 160), (30), DFS -country KN: DFS-ETSI +country KN: DFS-FCC (2402 - 2482 @ 40), (20) (5170 - 5250 @ 80), (23), AUTO-BW (5250 - 5330 @ 80), (23), DFS, AUTO-BW @@ -746,8 +743,8 @@ country KR: DFS-ETSI (2402 - 2482 @ 40), (20) (5170 - 5250 @ 80), (20), AUTO-BW (5250 - 5330 @ 80), (20), DFS, AUTO-BW - (5490 - 5630 @ 80), (30), DFS - (5735 - 5815 @ 80), (30) + (5490 - 5710 @ 80), (30), DFS + (5735 - 5835 @ 80), (30) # 60 GHz band channels 1-4, # ref: http://www.law.go.kr/%ED%96%89%EC%A0%95%EA%B7%9C%EC%B9%99/%EB%AC%B4%EC%84%A0%EC%84%A4%EB%B9%84%EA%B7%9C%EC%B9%99 (57000 - 66000 @ 2160), (43) @@ -781,7 +778,7 @@ country LB: DFS-FCC (5490 - 5730 @ 160), (24), DFS (5735 - 5835 @ 80), (30) -country LC: DFS-ETSI +country LC: DFS-FCC (2402 - 2482 @ 40), (20) (5170 - 5250 @ 80), (20), AUTO-BW (5250 - 5330 @ 80), (30), DFS, AUTO-BW @@ -1047,10 +1044,9 @@ country NO: DFS-ETSI # 60 gHz band channels 1-4, ref: Etsi En 302 567 (57240 - 65880 @ 2160), (40), NO-OUTDOOR -country NP: DFS-ETSI +country NP: (2402 - 2482 @ 40), (20) - (5170 - 5250 @ 80), (20), AUTO-BW - (5250 - 5330 @ 80), (20), DFS, AUTO-BW + (5170 - 5330 @ 160), (20) (5735 - 5835 @ 80), (20) country NZ: DFS-FCC @@ -1066,11 +1062,11 @@ country OM: DFS-ETSI (5250 - 5330 @ 80), (23), DFS, AUTO-BW (5490 - 5710 @ 160), (30), DFS -country PA: DFS-FCC +country PA: (2402 - 2472 @ 40), (30) - (5170 - 5250 @ 80), (23), AUTO-BW - (5250 - 5330 @ 80), (23), DFS, AUTO-BW - (5735 - 5835 @ 80), (30) + (5170 - 5250 @ 80), (23), AUT0-BW + (5250 - 5330 @ 80), (30), AUTO-BW + (5735 - 5835 @ 80), (36) country PE: DFS-FCC (2402 - 2482 @ 40), (20) @@ -1208,11 +1204,10 @@ country RS: DFS-ETSI # 60 gHz band channels 1-4, ref: Etsi En 302 567 (57240 - 65880 @ 2160), (40), NO-OUTDOOR -country RU: DFS-ETSI +country RU: (2402 - 2482 @ 40), (20) - (5170 - 5250 @ 80), (23), AUTO-BW - (5250 - 5330 @ 80), (23), DFS, AUTO-BW - (5490 - 5730 @ 160), (30), DFS + (5170 - 5330 @ 160), (23) + (5490 - 5730 @ 160), (30) (5735 - 5835 @ 80), (30) country RW: DFS-FCC @@ -1286,11 +1281,10 @@ country SK: DFS-ETSI # 60 gHz band channels 1-4, ref: Etsi En 302 567 (57240 - 65880 @ 2160), (40), NO-OUTDOOR -country SN: DFS-FCC +country SN: (2402 - 2482 @ 40), (20) - (5170 - 5250 @ 80), (24), AUTO-BW - (5250 - 5330 @ 80), (24), DFS, AUTO-BW - (5490 - 5730 @ 160), (24), DFS + (5170 - 5330 @ 160), (24) + (5490 - 5730 @ 160), (24) (5735 - 5835 @ 80), (30) country SR: DFS-ETSI @@ -1347,12 +1341,11 @@ country TR: DFS-ETSI # 60 gHz band channels 1-4, ref: Etsi En 302 567 (57240 - 65880 @ 2160), (40), NO-OUTDOOR -country TT: DFS-FCC +country TT: (2402 - 2482 @ 40), (20) - (5170 - 5250 @ 80), (24), AUTO-BW - (5250 - 5330 @ 80), (24), DFS, AUTO-BW - (5490 - 5730 @ 160), (24), DFS - (5735 - 5835 @ 80), (30) + (5170 - 5330 @ 160), (27) + (5490 - 5730 @ 160), (36) + (5735 - 5835 @ 80), (36) country TW: DFS-FCC (2402 - 2472 @ 40), (30) -- cgit v1.2.3 From 73337d532d7bffc64988c8d377ed9e1461c9813b Mon Sep 17 00:00:00 2001 From: Harry Yang Date: Thu, 17 Nov 2016 11:24:25 -0800 Subject: qcom-charger: Change usb_icl votable for PD vote Currently there is an issue introduced by forcing the results of the icl_votable while pd is active. icl_votable is a min voter and since the DEFAULT_VOTER votes 1.5Amps that becomes the max one could draw when pd is active. This is incorrect and hence the issue. Note that DEFAULT_VOTER is only needed while DCP is present. So, to fix it, rename DEFAULT_VOTER to DCP_VOTER and make DCP_VOTER unvote and vote when pd_active is set and unset respectively. CRs-Fixed: 1091477 Change-Id: I7435f05f20e12a7704ae5d9597b5cdc9b5a61d00 Signed-off-by: Harry Yang --- drivers/power/qcom-charger/qpnp-smb2.c | 3 ++- drivers/power/qcom-charger/smb-lib.c | 15 +++++++++++++++ drivers/power/qcom-charger/smb-lib.h | 2 ++ drivers/power/qcom-charger/smb138x-charger.c | 4 +++- 4 files changed, 22 insertions(+), 2 deletions(-) diff --git a/drivers/power/qcom-charger/qpnp-smb2.c b/drivers/power/qcom-charger/qpnp-smb2.c index 6968ab2ab11c..ee18ac271573 100644 --- a/drivers/power/qcom-charger/qpnp-smb2.c +++ b/drivers/power/qcom-charger/qpnp-smb2.c @@ -1069,6 +1069,7 @@ static int smb2_init_hw(struct smb2 *chip) &chip->dt.dc_icl_ua); chg->otg_cl_ua = chip->dt.otg_cl_ua; + chg->dcp_icl_ua = chip->dt.usb_icl_ua; rc = smblib_read(chg, APSD_RESULT_STATUS_REG, &stat); if (rc < 0) { @@ -1101,7 +1102,7 @@ static int smb2_init_hw(struct smb2 *chip) vote(chg->fv_votable, DEFAULT_VOTER, true, chip->dt.fv_uv); vote(chg->usb_icl_votable, - DEFAULT_VOTER, true, chip->dt.usb_icl_ua); + DCP_VOTER, true, chip->dt.usb_icl_ua); vote(chg->dc_icl_votable, DEFAULT_VOTER, true, chip->dt.dc_icl_ua); vote(chg->hvdcp_disable_votable, DEFAULT_VOTER, diff --git a/drivers/power/qcom-charger/smb-lib.c b/drivers/power/qcom-charger/smb-lib.c index 6aae7d49271f..41260fc56077 100644 --- a/drivers/power/qcom-charger/smb-lib.c +++ b/drivers/power/qcom-charger/smb-lib.c @@ -2015,6 +2015,13 @@ int smblib_set_prop_pd_active(struct smb_charger *chg, return rc; } + rc = vote(chg->usb_icl_votable, DCP_VOTER, false, 0); + if (rc < 0) { + smblib_err(chg, "Couldn't vote for USB ICL rc=%d\n", + rc); + return rc; + } + rc = smblib_masked_write(chg, USBIN_ICL_OPTIONS_REG, USBIN_MODE_CHG_BIT, USBIN_MODE_CHG_BIT); if (rc < 0) { @@ -2031,6 +2038,14 @@ int smblib_set_prop_pd_active(struct smb_charger *chg, return rc; } } else { + rc = vote(chg->usb_icl_votable, DCP_VOTER, true, + chg->dcp_icl_ua); + if (rc < 0) { + smblib_err(chg, "Couldn't vote for USB ICL rc=%d\n", + rc); + return rc; + } + rc = smblib_masked_write(chg, CMD_APSD_REG, ICL_OVERRIDE_BIT, 0); if (rc < 0) { diff --git a/drivers/power/qcom-charger/smb-lib.h b/drivers/power/qcom-charger/smb-lib.h index a0237412ee8b..fa2e32b115d0 100644 --- a/drivers/power/qcom-charger/smb-lib.h +++ b/drivers/power/qcom-charger/smb-lib.h @@ -28,6 +28,7 @@ enum print_reason { #define DEFAULT_VOTER "DEFAULT_VOTER" #define USER_VOTER "USER_VOTER" #define PD_VOTER "PD_VOTER" +#define DCP_VOTER "DCP_VOTER" #define USB_PSY_VOTER "USB_PSY_VOTER" #define PL_TAPER_WORK_RUNNING_VOTER "PL_TAPER_WORK_RUNNING_VOTER" #define PARALLEL_PSY_VOTER "PARALLEL_PSY_VOTER" @@ -203,6 +204,7 @@ struct smb_charger { int *thermal_mitigation; int otg_cl_ua; + int dcp_icl_ua; int fake_capacity; diff --git a/drivers/power/qcom-charger/smb138x-charger.c b/drivers/power/qcom-charger/smb138x-charger.c index 9dc528a6bb45..4255958de300 100644 --- a/drivers/power/qcom-charger/smb138x-charger.c +++ b/drivers/power/qcom-charger/smb138x-charger.c @@ -630,10 +630,12 @@ static int smb138x_init_hw(struct smb138x *chip) vote(chg->fcc_votable, DEFAULT_VOTER, true, chip->dt.fcc_ua); vote(chg->usb_icl_votable, - DEFAULT_VOTER, true, chip->dt.usb_icl_ua); + DCP_VOTER, true, chip->dt.usb_icl_ua); vote(chg->dc_icl_votable, DEFAULT_VOTER, true, chip->dt.dc_icl_ua); + chg->dcp_icl_ua = chip->dt.usb_icl_ua; + /* configure charge enable for software control; active high */ rc = smblib_masked_write(chg, CHGR_CFG2_REG, CHG_EN_POLARITY_BIT | CHG_EN_SRC_BIT, 0); -- cgit v1.2.3 From fbff4fcc80b04e632c07592d7dc76bcbd6523061 Mon Sep 17 00:00:00 2001 From: Harry Yang Date: Thu, 17 Nov 2016 12:50:04 -0800 Subject: qcom-charger: smb2: Disable try.SINK mode in the probe Currently we disable try.SINK right before pd becomes active and re-enable it right after inactive. This breaks typec compliance. To fix it, disable try.SINK mode in the probe and never enable it. Change-Id: I61523188f45daca026b90943c845b43a8327f51e Signed-off-by: Harry Yang --- drivers/power/qcom-charger/qpnp-smb2.c | 7 +++++++ drivers/power/qcom-charger/smb-lib.c | 7 ------- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/drivers/power/qcom-charger/qpnp-smb2.c b/drivers/power/qcom-charger/qpnp-smb2.c index ee18ac271573..a6c08e8d62ec 100644 --- a/drivers/power/qcom-charger/qpnp-smb2.c +++ b/drivers/power/qcom-charger/qpnp-smb2.c @@ -1187,6 +1187,13 @@ static int smb2_init_hw(struct smb2 *chip) return rc; } + /* disable try.SINK mode */ + rc = smblib_masked_write(chg, TYPE_C_CFG_3_REG, EN_TRYSINK_MODE_BIT, 0); + if (rc < 0) { + dev_err(chg->dev, "Couldn't set TRYSINK_MODE rc=%d\n", rc); + return rc; + } + rc = smblib_masked_write(chg, QNOVO_PT_ENABLE_CMD_REG, QNOVO_PT_ENABLE_CMD_BIT, QNOVO_PT_ENABLE_CMD_BIT); if (rc < 0) { diff --git a/drivers/power/qcom-charger/smb-lib.c b/drivers/power/qcom-charger/smb-lib.c index 41260fc56077..781f5554f1bb 100644 --- a/drivers/power/qcom-charger/smb-lib.c +++ b/drivers/power/qcom-charger/smb-lib.c @@ -2081,13 +2081,6 @@ int smblib_set_prop_pd_active(struct smb_charger *chg, smblib_update_usb_type(chg); power_supply_changed(chg->usb_psy); - rc = smblib_masked_write(chg, TYPE_C_CFG_3_REG, EN_TRYSINK_MODE_BIT, - chg->pd_active ? 0 : EN_TRYSINK_MODE_BIT); - if (rc < 0) { - dev_err(chg->dev, "Couldn't set TRYSINK_MODE rc=%d\n", rc); - return rc; - } - return rc; } -- cgit v1.2.3 From c576ff4ddf647f59700471e11f79039b54b8786b Mon Sep 17 00:00:00 2001 From: Yuanyuan Liu Date: Mon, 14 Nov 2016 17:05:25 -0800 Subject: icnss: Reset mpm_wcssaon_config bits before top level reset Clear mpm_wcssaon_config bits before top level reset. If those bits are non-zero during WLAN is enabled, there could be random failures. CRs-Fixed: 1086372 Change-Id: Ia03380dfa4852c80fedb38f3c79f55d8d1a9a7f6 Signed-off-by: Yuanyuan Liu --- drivers/soc/qcom/icnss.c | 24 ++++++++++++++++++++++-- 1 file changed, 22 insertions(+), 2 deletions(-) diff --git a/drivers/soc/qcom/icnss.c b/drivers/soc/qcom/icnss.c index 6215636b0f46..59d7f6423932 100644 --- a/drivers/soc/qcom/icnss.c +++ b/drivers/soc/qcom/icnss.c @@ -1485,8 +1485,18 @@ static int icnss_hw_reset(struct icnss_priv *priv) icnss_hw_reset_wlan_rfactrl_power_down(priv); ret = icnss_hw_reset_rf_reset_cmd(priv); - if (ret) + if (ret) { + icnss_hw_write_reg_field(priv->mpm_config_va, + MPM_WCSSAON_CONFIG_OFFSET, + MPM_WCSSAON_CONFIG_FORCE_ACTIVE, 0); + icnss_hw_write_reg_field(priv->mpm_config_va, + MPM_WCSSAON_CONFIG_OFFSET, + MPM_WCSSAON_CONFIG_DISCONNECT_CLR, 0); + icnss_hw_write_reg_field(priv->mpm_config_va, + MPM_WCSSAON_CONFIG_OFFSET, + MPM_WCSSAON_CONFIG_WLAN_DISABLE, 1); goto top_level_reset; + } icnss_hw_reset_switch_to_cxo(priv); @@ -1511,8 +1521,18 @@ static int icnss_hw_reset(struct icnss_priv *priv) } ret = icnss_hw_reset_xo_disable_cmd(priv); - if (ret) + if (ret) { + icnss_hw_write_reg_field(priv->mpm_config_va, + MPM_WCSSAON_CONFIG_OFFSET, + MPM_WCSSAON_CONFIG_FORCE_ACTIVE, 0); + icnss_hw_write_reg_field(priv->mpm_config_va, + MPM_WCSSAON_CONFIG_OFFSET, + MPM_WCSSAON_CONFIG_DISCONNECT_CLR, 0); + icnss_hw_write_reg_field(priv->mpm_config_va, + MPM_WCSSAON_CONFIG_OFFSET, + MPM_WCSSAON_CONFIG_WLAN_DISABLE, 1); goto top_level_reset; + } icnss_hw_write_reg_field(priv->mpm_config_va, MPM_WCSSAON_CONFIG_OFFSET, MPM_WCSSAON_CONFIG_FORCE_ACTIVE, 0); -- cgit v1.2.3 From 1f2e772d9c322b69cd9193c1e4a8721944c47fab Mon Sep 17 00:00:00 2001 From: Siddartha Mohanadoss Date: Wed, 16 Nov 2016 14:04:47 -0800 Subject: iio: rradc: Update reading USBIN_V channel Increase the refresh rate for the RRADC to support reading refreshed USBIN voltage at a higher frequency. To support the higher frequency at which the data is refreshed enable continuous mode and force update on reading every cycle on the USBIN_V trigger. After reading the USBIN_V result set the RRADC to non continuous mode with default trigger setting. Change-Id: I7e9ada5de1f619c6a34a4b2e1764f5e908564ce5 Signed-off-by: Siddartha Mohanadoss --- drivers/iio/adc/qcom-rradc.c | 110 ++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 108 insertions(+), 2 deletions(-) diff --git a/drivers/iio/adc/qcom-rradc.c b/drivers/iio/adc/qcom-rradc.c index e08de7a808eb..0e8fda8b9080 100644 --- a/drivers/iio/adc/qcom-rradc.c +++ b/drivers/iio/adc/qcom-rradc.c @@ -20,12 +20,18 @@ #include #include #include +#include #include #define FG_ADC_RR_EN_CTL 0x46 #define FG_ADC_RR_SKIN_TEMP_LSB 0x50 #define FG_ADC_RR_SKIN_TEMP_MSB 0x51 #define FG_ADC_RR_RR_ADC_CTL 0x52 +#define FG_ADC_RR_ADC_CTL_CONTINUOUS_SEL_MASK 0x8 +#define FG_ADC_RR_ADC_CTL_CONTINUOUS_SEL BIT(3) +#define FG_ADC_RR_ADC_LOG 0x53 +#define FG_ADC_RR_ADC_LOG_CLR_CTRL_MASK 0xFE +#define FG_ADC_RR_ADC_LOG_CLR_CTRL BIT(0) #define FG_ADC_RR_FAKE_BATT_LOW_LSB 0x58 #define FG_ADC_RR_FAKE_BATT_LOW_MSB 0x59 @@ -68,6 +74,8 @@ #define FG_ADC_RR_USB_IN_V_CTRL 0x90 #define FG_ADC_RR_USB_IN_V_TRIGGER 0x91 +#define FG_ADC_RR_USB_IN_V_EVERY_CYCLE_MASK 0x80 +#define FG_ADC_RR_USB_IN_V_EVERY_CYCLE BIT(7) #define FG_ADC_RR_USB_IN_V_STS 0x92 #define FG_ADC_RR_USB_IN_V_LSB 0x94 #define FG_ADC_RR_USB_IN_V_MSB 0x95 @@ -175,6 +183,9 @@ #define FG_RR_ADC_MAX_CONTINUOUS_BUFFER_LEN 16 #define FG_RR_ADC_STS_CHANNEL_READING_MASK 0x3 +#define FG_RR_CONV_CONTINUOUS_TIME_MIN 80000 +#define FG_RR_CONV_CONTINUOUS_TIME_MAX 81000 + /* * The channel number is not a physical index in hardware, * rather it's a list of supported channels and an index to @@ -230,6 +241,21 @@ struct rradc_chan_prop { u16 adc_code, int *result); }; +static int rradc_masked_write(struct rradc_chip *rr_adc, u16 offset, u8 mask, + u8 val) +{ + int rc; + + rc = regmap_update_bits(rr_adc->regmap, rr_adc->base + offset, + mask, val); + if (rc) { + pr_err("spmi write failed: addr=%03X, rc=%d\n", offset, rc); + return rc; + } + + return rc; +} + static int rradc_read(struct rradc_chip *rr_adc, u16 offset, u8 *data, int len) { int rc = 0, retry_cnt = 0, i = 0; @@ -547,7 +573,7 @@ static const struct rradc_channels rradc_chans[] = { static int rradc_do_conversion(struct rradc_chip *chip, struct rradc_chan_prop *prop, u16 *data) { - int rc = 0, bytes_to_read = 0; + int rc = 0, bytes_to_read = 0, retry = 0; u8 buf[6]; u16 offset = 0, batt_id_5 = 0, batt_id_15 = 0, batt_id_150 = 0; u16 status = 0; @@ -558,7 +584,8 @@ static int rradc_do_conversion(struct rradc_chip *chip, (prop->channel != RR_ADC_CHG_HOT_TEMP) && (prop->channel != RR_ADC_CHG_TOO_HOT_TEMP) && (prop->channel != RR_ADC_SKIN_HOT_TEMP) && - (prop->channel != RR_ADC_SKIN_TOO_HOT_TEMP)) { + (prop->channel != RR_ADC_SKIN_TOO_HOT_TEMP) && + (prop->channel != RR_ADC_USBIN_V)) { /* BATT_ID STS bit does not get set initially */ status = rradc_chans[prop->channel].sts; rc = rradc_read(chip, status, buf, 1); @@ -576,6 +603,85 @@ static int rradc_do_conversion(struct rradc_chip *chip, } } + if (prop->channel == RR_ADC_USBIN_V) { + /* Force conversion every cycle */ + rc = rradc_masked_write(chip, FG_ADC_RR_USB_IN_V_TRIGGER, + FG_ADC_RR_USB_IN_V_EVERY_CYCLE_MASK, + FG_ADC_RR_USB_IN_V_EVERY_CYCLE); + if (rc < 0) { + pr_err("Force every cycle update failed:%d\n", rc); + goto fail; + } + + /* Clear channel log */ + rc = rradc_masked_write(chip, FG_ADC_RR_ADC_LOG, + FG_ADC_RR_ADC_LOG_CLR_CTRL_MASK, + FG_ADC_RR_ADC_LOG_CLR_CTRL); + if (rc < 0) { + pr_err("log ctrl update to clear failed:%d\n", rc); + goto fail; + } + + rc = rradc_masked_write(chip, FG_ADC_RR_ADC_LOG, + FG_ADC_RR_ADC_LOG_CLR_CTRL_MASK, 0); + if (rc < 0) { + pr_err("log ctrl update to not clear failed:%d\n", rc); + goto fail; + } + + /* Switch to continuous mode */ + rc = rradc_masked_write(chip, FG_ADC_RR_RR_ADC_CTL, + FG_ADC_RR_ADC_CTL_CONTINUOUS_SEL_MASK, + FG_ADC_RR_ADC_CTL_CONTINUOUS_SEL); + if (rc < 0) { + pr_err("Update to continuous mode failed:%d\n", rc); + goto fail; + } + + status = rradc_chans[prop->channel].sts; + rc = rradc_read(chip, status, buf, 1); + if (rc < 0) { + pr_err("status read failed:%d\n", rc); + goto fail; + } + + buf[0] &= FG_RR_ADC_STS_CHANNEL_READING_MASK; + while ((buf[0] != FG_RR_ADC_STS_CHANNEL_READING_MASK) && + (retry < 2)) { + pr_debug("%s is not ready; nothing to read\n", + rradc_chans[prop->channel].datasheet_name); + usleep_range(FG_RR_CONV_CONTINUOUS_TIME_MIN, + FG_RR_CONV_CONTINUOUS_TIME_MAX); + retry++; + rc = rradc_read(chip, status, buf, 1); + if (rc < 0) { + pr_err("status read failed:%d\n", rc); + goto fail; + } + } + + /* Switch to non continuous mode */ + rc = rradc_masked_write(chip, FG_ADC_RR_RR_ADC_CTL, + FG_ADC_RR_ADC_CTL_CONTINUOUS_SEL_MASK, 0); + if (rc < 0) { + pr_err("Update to continuous mode failed:%d\n", rc); + goto fail; + } + + /* Restore usb_in trigger */ + rc = rradc_masked_write(chip, FG_ADC_RR_USB_IN_V_TRIGGER, + FG_ADC_RR_USB_IN_V_EVERY_CYCLE_MASK, 0); + if (rc < 0) { + pr_err("Restore every cycle update failed:%d\n", rc); + goto fail; + } + + if (retry >= 2) { + rc = -ENODATA; + goto fail; + } + } + offset = rradc_chans[prop->channel].lsb; if (prop->channel == RR_ADC_BATT_ID) bytes_to_read = 6; -- cgit v1.2.3 From d96857fbff930a2b2c339ef22b0c6329609d9639 Mon Sep 17 00:00:00 2001 From: Jack Pham Date: Thu, 17 Nov 2016 13:19:49 -0800 Subject: usb: pd: Don't suspend charging unless changing voltages To optimize charging during power negotiation and the voltage is not changing, for example when transitioning from implicit contract to the default 5V PDO, there is no requirement to suspend the charging and hence setting the charger's PROP_PD_CURRENT_MAX can be avoided. It is only needed when changing voltages, in which case current limit should be calculated based on pSnkStdby (2.5W), or when staying at the same voltage and decreasing current. Also fix the incorrect setting of PROP_CURRENT_MAX to PROP_PD_CURRENT_MAX when doing a sink->source swap. Change-Id: Ib53902459646e590df4dc7fcb00f833d5e8f41ed Signed-off-by: Jack Pham --- drivers/usb/pd/policy_engine.c | 31 ++++++++++++++++++++++++------- 1 file changed, 24 insertions(+), 7 deletions(-) diff --git a/drivers/usb/pd/policy_engine.c b/drivers/usb/pd/policy_engine.c index b4d7c7d8bddf..27a963aac984 100644 --- a/drivers/usb/pd/policy_engine.c +++ b/drivers/usb/pd/policy_engine.c @@ -913,7 +913,7 @@ static void usbpd_set_state(struct usbpd *pd, enum usbpd_state next_state) case PE_PRS_SNK_SRC_TRANSITION_TO_OFF: val.intval = pd->requested_current = 0; /* suspend charging */ power_supply_set_property(pd->usb_psy, - POWER_SUPPLY_PROP_CURRENT_MAX, &val); + POWER_SUPPLY_PROP_PD_CURRENT_MAX, &val); pd->in_explicit_contract = false; @@ -1731,6 +1731,8 @@ static void usbpd_sm(struct work_struct *w) case PE_SNK_SELECT_CAPABILITY: if (IS_CTRL(rx_msg, MSG_ACCEPT)) { + usbpd_set_state(pd, PE_SNK_TRANSITION_SINK); + /* prepare for voltage increase/decrease */ val.intval = pd->requested_voltage; power_supply_set_property(pd->usb_psy, @@ -1740,16 +1742,31 @@ static void usbpd_sm(struct work_struct *w) &val); /* - * disable charging; technically we are allowed to - * charge up to pSnkStdby (2.5 W) during this - * transition, but disable it just for simplicity. + * if we are changing voltages, we must lower input + * current to pSnkStdby (2.5W). Calculate it and set + * PD_CURRENT_MAX accordingly. */ - val.intval = 0; - power_supply_set_property(pd->usb_psy, + if (pd->requested_voltage != pd->current_voltage) { + int mv = max(pd->requested_voltage, + pd->current_voltage) / 1000; + val.intval = (2500000 / mv) * 1000; + power_supply_set_property(pd->usb_psy, POWER_SUPPLY_PROP_PD_CURRENT_MAX, &val); + } else { + /* decreasing current? */ + ret = power_supply_get_property(pd->usb_psy, + POWER_SUPPLY_PROP_PD_CURRENT_MAX, &val); + if (!ret && + pd->requested_current < val.intval) { + val.intval = + pd->requested_current * 1000; + power_supply_set_property(pd->usb_psy, + POWER_SUPPLY_PROP_PD_CURRENT_MAX, + &val); + } + } pd->selected_pdo = pd->requested_pdo; - usbpd_set_state(pd, PE_SNK_TRANSITION_SINK); } else if (IS_CTRL(rx_msg, MSG_REJECT) || IS_CTRL(rx_msg, MSG_WAIT)) { if (pd->in_explicit_contract) -- cgit v1.2.3 From 291a7d133e2174c669970cd89dc4af450b165bcc Mon Sep 17 00:00:00 2001 From: Chandana Kishori Chiluveru Date: Fri, 21 Oct 2016 09:59:35 +0530 Subject: ARM: dts: msm: Add support for USB device for msmfalcon and msmtriton Add common dtsi file for msmfalcon and msmtriton. Also Add device tree entry for super speed USB3 controller, super speed phy and high speed phy. Change-Id: I326eceeddff8e77d346c3365fa46cd539324451f Signed-off-by: Chandana Kishori Chiluveru --- arch/arm/boot/dts/qcom/msmfalcon-common.dtsi | 196 +++++++++++++++++++++++++++ arch/arm/boot/dts/qcom/msmfalcon-rumi.dts | 32 +++++ arch/arm/boot/dts/qcom/msmfalcon-sim.dts | 16 +++ arch/arm/boot/dts/qcom/msmfalcon.dtsi | 1 + arch/arm/boot/dts/qcom/msmtriton-rumi.dts | 31 +++++ arch/arm/boot/dts/qcom/msmtriton.dtsi | 1 + 6 files changed, 277 insertions(+) create mode 100644 arch/arm/boot/dts/qcom/msmfalcon-common.dtsi diff --git a/arch/arm/boot/dts/qcom/msmfalcon-common.dtsi b/arch/arm/boot/dts/qcom/msmfalcon-common.dtsi new file mode 100644 index 000000000000..b3be67bd8c32 --- /dev/null +++ b/arch/arm/boot/dts/qcom/msmfalcon-common.dtsi @@ -0,0 +1,196 @@ +/* Copyright (c) 2016, 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 + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +&soc { + usb3: ssusb@a800000 { + compatible = "qcom,dwc-usb3-msm"; + reg = <0x0a800000 0xfc100>, + <0x0c016000 0x400>; + reg-names = "core_base", + "ahb2phy_base"; + #address-cells = <1>; + #size-cells = <1>; + ranges; + + interrupts = <0 347 0>, <0 243 0>, <0 180 0>; + interrupt-names = "hs_phy_irq", "ss_phy_irq", "pwr_event_irq"; + + USB3_GDSC-supply = <&gdsc_usb30>; + + qcom,usb-dbm = <&dbm_1p5>; + qcom,msm-bus,name = "usb3"; + qcom,msm-bus,num-cases = <2>; + qcom,msm-bus,num-paths = <1>; + qcom,msm-bus,vectors-KBps = + <61 512 0 0>, + <61 512 240000 800000>; + + qcom,dwc-usb3-msm-tx-fifo-size = <21288>; + + clocks = <&clock_gcc GCC_USB30_MASTER_CLK>, + <&clock_gcc GCC_CFG_NOC_USB3_AXI_CLK>, + <&clock_gcc GCC_AGGRE2_USB3_AXI_CLK>, + <&clock_gcc GCC_USB30_MOCK_UTMI_CLK>, + <&clock_gcc GCC_USB30_SLEEP_CLK>, + <&clock_gcc GCC_USB_PHY_CFG_AHB2PHY_CLK>, + <&clock_rpmcc CXO_DWC3_CLK>; + + clock-names = "core_clk", "iface_clk", "bus_aggr_clk", + "utmi_clk", "sleep_clk", "cfg_ahb_clk", "xo"; + + resets = <&clock_gcc GCC_USB_30_BCR>; + reset-names = "core_reset"; + + dwc3@a800000 { + compatible = "snps,dwc3"; + reg = <0x0a800000 0xc8d0>; + interrupt-parent = <&intc>; + interrupts = <0 131 0>; + usb-phy = <&qusb_phy0>, <&ssphy>; + tx-fifo-resize; + snps,usb3-u1u2-disable; + snps,nominal-elastic-buffer; + snps,is-utmi-l1-suspend; + snps,hird-threshold = /bits/ 8 <0x0>; + }; + + qcom,usbbam@a904000 { + compatible = "qcom,usb-bam-msm"; + reg = <0x0a904000 0x17000>; + interrupt-parent = <&intc>; + interrupts = <0 132 0>; + + qcom,bam-type = <0>; + qcom,usb-bam-fifo-baseaddr = <0x066bb000>; + qcom,usb-bam-num-pipes = <8>; + qcom,ignore-core-reset-ack; + qcom,disable-clk-gating; + qcom,usb-bam-override-threshold = <0x4001>; + qcom,usb-bam-max-mbps-highspeed = <400>; + qcom,usb-bam-max-mbps-superspeed = <3600>; + qcom,reset-bam-on-connect; + + qcom,pipe0 { + label = "ssusb-ipa-out-0"; + qcom,usb-bam-mem-type = <1>; + qcom,dir = <0>; + qcom,pipe-num = <0>; + qcom,peer-bam = <1>; + qcom,src-bam-pipe-index = <1>; + qcom,data-fifo-size = <0x8000>; + qcom,descriptor-fifo-size = <0x2000>; + }; + qcom,pipe1 { + label = "ssusb-ipa-in-0"; + qcom,usb-bam-mem-type = <1>; + qcom,dir = <1>; + qcom,pipe-num = <0>; + qcom,peer-bam = <1>; + qcom,dst-bam-pipe-index = <0>; + qcom,data-fifo-size = <0x8000>; + qcom,descriptor-fifo-size = <0x2000>; + }; + qcom,pipe2 { + label = "ssusb-qdss-in-0"; + qcom,usb-bam-mem-type = <2>; + qcom,dir = <1>; + qcom,pipe-num = <0>; + qcom,peer-bam = <0>; + qcom,peer-bam-physical-address = <0x06064000>; + qcom,src-bam-pipe-index = <0>; + qcom,dst-bam-pipe-index = <2>; + qcom,data-fifo-offset = <0x0>; + qcom,data-fifo-size = <0x1800>; + qcom,descriptor-fifo-offset = <0x1800>; + qcom,descriptor-fifo-size = <0x800>; + }; + qcom,pipe3 { + label = "ssusb-dpl-ipa-in-1"; + qcom,usb-bam-mem-type = <1>; + qcom,dir = <1>; + qcom,pipe-num = <1>; + qcom,peer-bam = <1>; + qcom,dst-bam-pipe-index = <2>; + qcom,data-fifo-size = <0x8000>; + qcom,descriptor-fifo-size = <0x2000>; + }; + }; + }; + + qusb_phy0: qusb@c012000 { + compatible = "qcom,qusb2phy"; + reg = <0x0c012000 0x180>, + <0x00188018 0x4>; + reg-names = "qusb_phy_base", + "ref_clk_addr"; + vdd-supply = <&pm2falcon_l1>; + vdda18-supply = <&pmfalcon_l10>; + vdda33-supply = <&pm2falcon_l7>; + qcom,vdd-voltage-level = <0 925000 925000>; + qcom,tune2-efuse-bit-pos = <21>; + qcom,tune2-efuse-num-bits = <4>; + qcom,enable-dpdm-pulsing; + qcom,qusb-phy-init-seq = <0xf8 0x80 + 0xb3 0x84 + 0x83 0x88 + 0xc0 0x8c + 0x30 0x08 + 0x79 0x0c + 0x21 0x10 + 0x14 0x9c + 0x9f 0x1c + 0x00 0x18>; + phy_type= "utmi"; + + clocks = <&clock_rpmcc RPM_LN_BB_CLK1>, + <&clock_gcc GCC_RX0_USB2_CLKREF_CLK>, + <&clock_gcc GCC_USB_PHY_CFG_AHB2PHY_CLK>; + + clock-names = "ref_clk_src", "ref_clk", "cfg_ahb_clk"; + + resets = <&clock_gcc GCC_QUSB2PHY_PRIM_BCR>; + reset-names = "phy_reset"; + }; + + ssphy: ssphy@c010000 { + compatible = "qcom,usb-ssphy-qmp-v2"; + reg = <0xc010000 0x7a8>, + <0x01fcb244 0x4>, + <0x01fcb248 0x4>; + reg-names = "qmp_phy_base", + "vls_clamp_reg", + "tcsr_usb3_dp_phymode"; + vdd-supply = <&pm2falcon_l1>; + core-supply = <&pmfalcon_l10>; + qcom,vdd-voltage-level = <0 925000 925000>; + qcom,vbus-valid-override; + + clocks = <&clock_gcc GCC_USB3_PHY_AUX_CLK>, + <&clock_gcc GCC_USB3_PHY_PIPE_CLK>, + <&clock_gcc GCC_USB_PHY_CFG_AHB2PHY_CLK>, + <&clock_rpmcc RPM_LN_BB_CLK1>, + <&clock_gcc GCC_USB3_CLKREF_CLK>; + + clock-names = "aux_clk", "pipe_clk", "cfg_ahb_clk", + "ref_clk_src", "ref_clk"; + + resets = <&clock_gcc GCC_USB3_PHY_BCR>, + <&clock_gcc GCC_USB3PHY_PHY_BCR>; + reset-names = "phy_reset", "phy_phy_reset"; + }; + + dbm_1p5: dbm@a8f8000 { + compatible = "qcom,usb-dbm-1p5"; + reg = <0xa8f8000 0x300>; + qcom,reset-ep-after-lpm-resume; + }; +}; diff --git a/arch/arm/boot/dts/qcom/msmfalcon-rumi.dts b/arch/arm/boot/dts/qcom/msmfalcon-rumi.dts index c94ba0df3e6e..1840221359e3 100644 --- a/arch/arm/boot/dts/qcom/msmfalcon-rumi.dts +++ b/arch/arm/boot/dts/qcom/msmfalcon-rumi.dts @@ -26,6 +26,38 @@ }; }; +&usb3 { + /delete-property/ USB3_GDSC-supply; + dwc3@a800000 { + maximum-speed = "high-speed"; + }; +}; + +&ssphy { + compatible = "usb-nop-xceiv"; +}; + +&qusb_phy0 { + reg = <0x0a928000 0x8000>, + <0x0a8f8800 0x400>, + <0x0a920000 0x100>; + reg-names = "qusb_phy_base", + "qscratch_base", + "emu_phy_base"; + qcom,emulation; + qcom,qusb-phy-init-seq = <0x19 0x1404 + 0x20 0x1414 + 0x79 0x1410 + 0x00 0x1418 + 0x99 0x1404 + 0x04 0x1408 + 0xd9 0x1404>; + qcom,emu-dcm-reset-seq = <0x100000 0x20 + 0x0 0x20 + 0x1a0 0x20 + 0x5 0x14>; +}; + &uartblsp1dm1 { status = "ok"; pinctrl-names = "default"; diff --git a/arch/arm/boot/dts/qcom/msmfalcon-sim.dts b/arch/arm/boot/dts/qcom/msmfalcon-sim.dts index 00d97c8fdd32..47759c9ce3ff 100644 --- a/arch/arm/boot/dts/qcom/msmfalcon-sim.dts +++ b/arch/arm/boot/dts/qcom/msmfalcon-sim.dts @@ -26,6 +26,22 @@ }; }; +&usb3 { + reg = <0xa800000 0xfc000>; + reg-names = "core_base"; + dwc3@a800000 { + maximum-speed = "high-speed"; + }; +}; + +&ssphy { + compatible = "usb-nop-xceiv"; +}; + +&qusb_phy0 { + compatible = "usb-nop-xceiv"; +}; + &uartblsp1dm1 { status = "ok"; pinctrl-names = "default"; diff --git a/arch/arm/boot/dts/qcom/msmfalcon.dtsi b/arch/arm/boot/dts/qcom/msmfalcon.dtsi index 473270d6e87d..5b57ccfca435 100644 --- a/arch/arm/boot/dts/qcom/msmfalcon.dtsi +++ b/arch/arm/boot/dts/qcom/msmfalcon.dtsi @@ -967,4 +967,5 @@ #include "msm-pm2falcon.dtsi" #include "msm-arm-smmu-falcon.dtsi" #include "msm-arm-smmu-impl-defs-falcon.dtsi" +#include "msmfalcon-common.dtsi" #include "msmfalcon-blsp.dtsi" diff --git a/arch/arm/boot/dts/qcom/msmtriton-rumi.dts b/arch/arm/boot/dts/qcom/msmtriton-rumi.dts index 0317c35d1f44..08809fb38cae 100644 --- a/arch/arm/boot/dts/qcom/msmtriton-rumi.dts +++ b/arch/arm/boot/dts/qcom/msmtriton-rumi.dts @@ -22,6 +22,37 @@ qcom,board-id = <15 0>; }; +&usb3 { + dwc3@a800000 { + maximum-speed = "high-speed"; + }; +}; + +&ssphy { + compatible = "usb-nop-xceiv"; +}; + +&qusb_phy0 { + reg = <0x0a928000 0x8000>, + <0x0a8f8800 0x400>, + <0x0a920000 0x100>; + reg-names = "qusb_phy_base", + "qscratch_base", + "emu_phy_base"; + qcom,emulation; + qcom,qusb-phy-init-seq = <0x19 0x1404 + 0x20 0x1414 + 0x79 0x1410 + 0x00 0x1418 + 0x99 0x1404 + 0x04 0x1408 + 0xd9 0x1404>; + qcom,emu-dcm-reset-seq = <0x100000 0x20 + 0x0 0x20 + 0x1a0 0x20 + 0x5 0x14>; +}; + &uartblsp1dm1 { status = "ok"; pinctrl-names = "default"; diff --git a/arch/arm/boot/dts/qcom/msmtriton.dtsi b/arch/arm/boot/dts/qcom/msmtriton.dtsi index 06f296a49113..ff810acf5b7b 100644 --- a/arch/arm/boot/dts/qcom/msmtriton.dtsi +++ b/arch/arm/boot/dts/qcom/msmtriton.dtsi @@ -715,6 +715,7 @@ #include "msmtriton-ion.dtsi" #include "msmtriton-regulator.dtsi" #include "msm-gdsc-falcon.dtsi" +#include "msmfalcon-common.dtsi" &gdsc_usb30 { clock-names = "core_clk"; -- cgit v1.2.3 From 323102d37843df7710cea797f7857eb691109c8b Mon Sep 17 00:00:00 2001 From: Anirudh Ghayal Date: Tue, 15 Nov 2016 19:40:48 +0530 Subject: ARM: dts: msm: Add dummy regulator for LCDB bias Add the LDO and NCP display +ve and -ve bias for LCD display. Change-Id: Ia85688854f26fe871d5c1253c2d51d75d84deb8f Signed-off-by: Anirudh Ghayal --- .../arm/boot/dts/qcom/msmcobalt-interposer-pmfalcon.dtsi | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/arch/arm/boot/dts/qcom/msmcobalt-interposer-pmfalcon.dtsi b/arch/arm/boot/dts/qcom/msmcobalt-interposer-pmfalcon.dtsi index 274281f7c982..d42ea76a23b7 100644 --- a/arch/arm/boot/dts/qcom/msmcobalt-interposer-pmfalcon.dtsi +++ b/arch/arm/boot/dts/qcom/msmcobalt-interposer-pmfalcon.dtsi @@ -277,3 +277,19 @@ #include "msm-pm2falcon.dtsi" #include "msmfalcon-regulator.dtsi" +/* dummy LCDB regulator nodes */ +&soc { + lcdb_ldo_vreg: regulator-vdisp-vreg { + compatible = "qcom,stub-regulator"; + regulator-name = "lcdb_ldo"; + regulator-min-microvolt = <4000000>; + regulator-max-microvolt = <6000000>; + }; + + lcdb_ncp_vreg: regulator-vdisn-vreg { + compatible = "qcom,stub-regulator"; + regulator-name = "lcdb_ncp"; + regulator-min-microvolt = <4000000>; + regulator-max-microvolt = <6000000>; + }; +}; -- cgit v1.2.3 From 4f161b67ae9c1fe1bd202809c1c2531099d3c4f0 Mon Sep 17 00:00:00 2001 From: Ashish Garg Date: Tue, 15 Nov 2016 11:33:01 +0530 Subject: ARM: dts: msm: enable mdss power supplies for falcon track3 Specify the regulators for mdss on falcon track3. Change-Id: Ie828c8568ef09c89cff157d16d3cb322647b6f6e Signed-off-by: Ashish Garg --- .../boot/dts/qcom/msmcobalt-interposer-msmfalcon-cdp.dtsi | 14 ++++++++++++-- .../boot/dts/qcom/msmcobalt-interposer-msmfalcon-mtp.dtsi | 14 ++++++++++++-- 2 files changed, 24 insertions(+), 4 deletions(-) diff --git a/arch/arm/boot/dts/qcom/msmcobalt-interposer-msmfalcon-cdp.dtsi b/arch/arm/boot/dts/qcom/msmcobalt-interposer-msmfalcon-cdp.dtsi index 4822823aa63f..dd8e6641c1bf 100644 --- a/arch/arm/boot/dts/qcom/msmcobalt-interposer-msmfalcon-cdp.dtsi +++ b/arch/arm/boot/dts/qcom/msmcobalt-interposer-msmfalcon-cdp.dtsi @@ -275,10 +275,15 @@ &mdss_dsi { hw-config = "split_dsi"; + vdda-1p2-supply = <&pmfalcon_l1>; + vdda-0p9-supply = <&pm2falcon_l1>; }; &mdss_dsi0 { - qcom,dsi-pref-prim-pan = <&dsi_dual_nt35597_video>; + qcom,dsi-pref-prim-pan = <&dsi_dual_nt35597_truly_video>; + wqhd-vddio-supply = <&pmfalcon_l11>; + lab-supply = <&lcdb_ldo_vreg>; + ibb-supply = <&lcdb_ncp_vreg>; pinctrl-names = "mdss_default", "mdss_sleep"; pinctrl-0 = <&mdss_dsi_active &mdss_te_active>; pinctrl-1 = <&mdss_dsi_suspend &mdss_te_suspend>; @@ -288,7 +293,10 @@ }; &mdss_dsi1 { - qcom,dsi-pref-prim-pan = <&dsi_dual_nt35597_video>; + qcom,dsi-pref-prim-pan = <&dsi_dual_nt35597_truly_video>; + wqhd-vddio-supply = <&pmfalcon_l11>; + lab-supply = <&lcdb_ldo_vreg>; + ibb-supply = <&lcdb_ncp_vreg>; pinctrl-names = "mdss_default", "mdss_sleep"; pinctrl-0 = <&mdss_dsi_active &mdss_te_active>; pinctrl-1 = <&mdss_dsi_suspend &mdss_te_suspend>; @@ -424,6 +432,8 @@ }; &mdss_dp_ctrl { + vdda-1p2-supply = <&pmfalcon_l1>; + vdda-0p9-supply = <&pm2falcon_l1>; pinctrl-names = "mdss_dp_active", "mdss_dp_sleep"; pinctrl-0 = <&mdss_dp_aux_active &mdss_dp_usbplug_cc_active>; pinctrl-1 = <&mdss_dp_aux_suspend &mdss_dp_usbplug_cc_suspend>; diff --git a/arch/arm/boot/dts/qcom/msmcobalt-interposer-msmfalcon-mtp.dtsi b/arch/arm/boot/dts/qcom/msmcobalt-interposer-msmfalcon-mtp.dtsi index b77bab712ecf..5ea3d3d73653 100644 --- a/arch/arm/boot/dts/qcom/msmcobalt-interposer-msmfalcon-mtp.dtsi +++ b/arch/arm/boot/dts/qcom/msmcobalt-interposer-msmfalcon-mtp.dtsi @@ -314,6 +314,8 @@ }; &mdss_dp_ctrl { + vdda-1p2-supply = <&pmfalcon_l1>; + vdda-0p9-supply = <&pm2falcon_l1>; pinctrl-names = "mdss_dp_active", "mdss_dp_sleep"; pinctrl-0 = <&mdss_dp_aux_active &mdss_dp_usbplug_cc_active>; pinctrl-1 = <&mdss_dp_aux_suspend &mdss_dp_usbplug_cc_suspend>; @@ -328,10 +330,15 @@ &mdss_dsi { hw-config = "split_dsi"; + vdda-1p2-supply = <&pmfalcon_l1>; + vdda-0p9-supply = <&pm2falcon_l1>; }; &mdss_dsi0 { - qcom,dsi-pref-prim-pan = <&dsi_dual_nt35597_video>; + qcom,dsi-pref-prim-pan = <&dsi_dual_nt35597_truly_video>; + wqhd-vddio-supply = <&pmfalcon_l11>; + lab-supply = <&lcdb_ldo_vreg>; + ibb-supply = <&lcdb_ncp_vreg>; pinctrl-names = "mdss_default", "mdss_sleep"; pinctrl-0 = <&mdss_dsi_active &mdss_te_active>; pinctrl-1 = <&mdss_dsi_suspend &mdss_te_suspend>; @@ -341,7 +348,10 @@ }; &mdss_dsi1 { - qcom,dsi-pref-prim-pan = <&dsi_dual_nt35597_video>; + qcom,dsi-pref-prim-pan = <&dsi_dual_nt35597_truly_video>; + wqhd-vddio-supply = <&pmfalcon_l11>; + lab-supply = <&lcdb_ldo_vreg>; + ibb-supply = <&lcdb_ncp_vreg>; pinctrl-names = "mdss_default", "mdss_sleep"; pinctrl-0 = <&mdss_dsi_active &mdss_te_active>; pinctrl-1 = <&mdss_dsi_suspend &mdss_te_suspend>; -- cgit v1.2.3