diff options
31 files changed, 510 insertions, 96 deletions
diff --git a/Documentation/devicetree/bindings/media/video/msm-cpp.txt b/Documentation/devicetree/bindings/media/video/msm-cpp.txt index 2bd9fb840830..450e4d6ee8f0 100644 --- a/Documentation/devicetree/bindings/media/video/msm-cpp.txt +++ b/Documentation/devicetree/bindings/media/video/msm-cpp.txt @@ -70,6 +70,13 @@ Optional properties: The first entry is register offset and second entry is register value. - qcom,micro-reset: Boolean flag indicating if micro reset need to be enabled. This needs to present on platforms that support this feature. +- qcom,cpp-cx-ipeak: To handle Cx peak current limit. + <phandle bit> + phandle - phandle of cx ipeak device node + bit - bit number of client in relevant register + This is used to access Cx ipeak HW module to limit the current drawn by + various subsystem blocks on Cx power rail. CPP set their bit in tcsr register + if it is going to cross its own threshold. Example: @@ -105,6 +112,7 @@ Example: "micro_iface_clk", "camss_ahb_clk"; "smmu_cpp_axi_clk", "cpp_vbif_ahb_clk"; qcom,clock-rates = <0 0 0 0 465000000 0 0 465000000 0 0 0 0>; + qcom,cpp-cx-ipeak = <&cx_ipeak_lm 2>; qcom,min-clock-rate = <320000000>; qcom,bus-master = <1>; qcom,vbif-qos-setting = <0x20 0x10000000>, diff --git a/Documentation/devicetree/bindings/media/video/msm-vfe.txt b/Documentation/devicetree/bindings/media/video/msm-vfe.txt index dac22f30bf1d..aaf13442fcf1 100644 --- a/Documentation/devicetree/bindings/media/video/msm-vfe.txt +++ b/Documentation/devicetree/bindings/media/video/msm-vfe.txt @@ -23,6 +23,7 @@ Required properties for child node: Only needed for child node. - "vfe" - Required. - "vfe_vbif" - Optional for "vfe32". Required for "vfe40". + - "vfe_fuse" - Optional. - interrupts : should contain the vfe interrupt. - interrupt-names : should specify relevant names to each interrupts property defined. @@ -52,9 +53,10 @@ Example: vfe0: qcom,vfe0@fda10000 { cell-index = <0>; compatible = "qcom,vfe44"; - reg = <0xfda10000 0x1000>; - <0xfda40000 0x200>; - reg-names = "vfe", "vfe_vbif"; + reg = <0xfda10000 0x1000>, + <0xfda40000 0x200>, + <0x7801a4 0x8>; + reg-names = "vfe", "vfe_vbif", "vfe_fuse"; interrupts = <0 57 0>; interrupt-names = "vfe"; vdd-supply = <&gdsc_vfe>; @@ -105,9 +107,10 @@ vfe0: qcom,vfe0@fda10000 { vfe1: qcom,vfe1@fda14000 { cell-index = <1>; compatible = "qcom,vfe44"; - reg = <0xfda14000 0x1000>; - <0xfda40000 0x200>; - reg-names = "vfe", "vfe_vbif"; + reg = <0xfda14000 0x1000>, + <0xfda40000 0x200>, + <0x7801a4 0x8>; + reg-names = "vfe", "vfe_vbif", "vfe_fuse"; interrupts = <0 58 0>; interrupt-names = "vfe"; vdd-supply = <&gdsc_vfe>; diff --git a/arch/arm/boot/dts/qcom/sdm630-pm660a-qrd.dts b/arch/arm/boot/dts/qcom/sdm630-pm660a-qrd.dts index d535d62e521c..c2408ba7bf76 100644 --- a/arch/arm/boot/dts/qcom/sdm630-pm660a-qrd.dts +++ b/arch/arm/boot/dts/qcom/sdm630-pm660a-qrd.dts @@ -16,6 +16,7 @@ #include "sdm630.dtsi" #include "sdm630-qrd.dtsi" #include "msm-pm660a.dtsi" +#include "sdm660-internal-codec.dtsi" / { model = "Qualcomm Technologies, Inc. SDM 630 PM660 + PM660A QRD"; @@ -23,3 +24,30 @@ qcom,board-id = <0x0002000b 0x00>; qcom,pmic-id = <0x0001001b 0x0001011a 0x0 0x0>; }; + +&int_codec { + qcom,model = "sdm660-snd-card-skush"; + /delete-property/ qcom,us-euro-gpios; + qcom,audio-routing = + "RX_BIAS", "INT_MCLK0", + "SPK_RX_BIAS", "INT_MCLK0", + "INT_LDO_H", "INT_MCLK0", + "MIC BIAS External2", "Headset Mic", + "AMIC2", "MIC BIAS External2", + "MIC BIAS External", "Digital Mic1", + "DMIC1", "MIC BIAS External", + "MIC BIAS External", "Digital Mic3", + "DMIC3", "MIC BIAS External", + "MIC BIAS External", "Digital Mic4", + "DMIC4", "MIC BIAS External", + "SpkrLeft IN", "SPK1 OUT", + "PDM_IN_RX1", "PDM_OUT_RX1", + "PDM_IN_RX2", "PDM_OUT_RX2", + "PDM_IN_RX3", "PDM_OUT_RX3", + "ADC1_IN", "ADC1_OUT", + "ADC2_IN", "ADC2_OUT", + "ADC3_IN", "ADC3_OUT"; + qcom,wsa-max-devs = <1>; + qcom,wsa-devs = <&wsa881x_211_en>, <&wsa881x_213_en>; + qcom,wsa-aux-dev-prefix = "SpkrLeft", "SpkrLeft"; +}; diff --git a/arch/arm/boot/dts/qcom/sdm660-audio.dtsi b/arch/arm/boot/dts/qcom/sdm660-audio.dtsi index 0b216a16c7e8..c1cb6441cd43 100644 --- a/arch/arm/boot/dts/qcom/sdm660-audio.dtsi +++ b/arch/arm/boot/dts/qcom/sdm660-audio.dtsi @@ -271,7 +271,7 @@ gpio@c200 { status = "ok"; qcom,mode = <1>; - qcom,pull = <5>; + qcom,pull = <4>; qcom,vin-sel = <0>; qcom,src-sel = <2>; qcom,master-en = <1>; diff --git a/arch/arm/boot/dts/qcom/sdm660-mdss-panels.dtsi b/arch/arm/boot/dts/qcom/sdm660-mdss-panels.dtsi index 0fc24dc6e72b..ff51db728d85 100644 --- a/arch/arm/boot/dts/qcom/sdm660-mdss-panels.dtsi +++ b/arch/arm/boot/dts/qcom/sdm660-mdss-panels.dtsi @@ -24,6 +24,7 @@ #include "dsi-panel-nt35695b-truly-fhd-cmd.dtsi" #include "dsi-panel-truly-1080p-cmd.dtsi" #include "dsi-panel-truly-1080p-video.dtsi" +#include "dsi-panel-rm67195-amoled-fhd-cmd.dtsi" &soc { dsi_panel_pwr_supply: dsi_panel_pwr_supply { @@ -67,7 +68,7 @@ qcom,panel-supply-entry@0 { reg = <0>; qcom,supply-name = "wqhd-vddio"; - qcom,supply-min-voltage = <1880000>; + qcom,supply-min-voltage = <1800000>; qcom,supply-max-voltage = <1950000>; qcom,supply-enable-load = <32000>; qcom,supply-disable-load = <80>; @@ -117,7 +118,7 @@ qcom,panel-supply-entry@0 { reg = <0>; qcom,supply-name = "wqhd-vddio"; - qcom,supply-min-voltage = <1880000>; + qcom,supply-min-voltage = <1800000>; qcom,supply-max-voltage = <1950000>; qcom,supply-enable-load = <32000>; qcom,supply-disable-load = <80>; @@ -260,3 +261,13 @@ qcom,esd-check-enabled; qcom,mdss-dsi-panel-status-check-mode = "bta_check"; }; + +&dsi_rm67195_amoled_fhd_cmd { + qcom,mdss-dsi-panel-timings-phy-v2 = [23 1e 07 08 05 03 04 a0 + 23 1e 07 08 05 03 04 a0 + 23 1e 07 08 05 03 04 a0 + 23 1e 07 08 05 03 04 a0 + 23 19 07 08 05 03 04 a0]; + qcom,mdss-dsi-t-clk-post = <0x0d>; + qcom,mdss-dsi-t-clk-pre = <0x2d>; +}; diff --git a/arch/arm/boot/dts/qcom/sdm660-pm660a-qrd.dts b/arch/arm/boot/dts/qcom/sdm660-pm660a-qrd.dts index 48e02bbdfbfe..d9d74ea31d3d 100644 --- a/arch/arm/boot/dts/qcom/sdm660-pm660a-qrd.dts +++ b/arch/arm/boot/dts/qcom/sdm660-pm660a-qrd.dts @@ -23,3 +23,34 @@ qcom,board-id = <0x0012000b 0>; qcom,pmic-id = <0x0001001b 0x0001011a 0x0 0x0>; }; + +&pm660a_oledb { + status = "okay"; + qcom,oledb-default-voltage-mv = <6400>; +}; + +&mdss_mdp { + qcom,mdss-pref-prim-intf = "dsi"; +}; + +&mdss_dsi { + hw-config = "single_dsi"; +}; + +&mdss_dsi0 { + qcom,dsi-pref-prim-pan = <&dsi_rm67195_amoled_fhd_cmd>; + pinctrl-names = "mdss_default", "mdss_sleep"; + pinctrl-0 = <&mdss_dsi_active &mdss_te_active>; + pinctrl-1 = <&mdss_dsi_suspend &mdss_te_suspend>; + lab-supply = <&lab_regulator>; + ibb-supply = <&ibb_regulator>; + qcom,platform-reset-gpio = <&tlmm 53 0>; + qcom,platform-te-gpio = <&tlmm 59 0>; +}; + +&dsi_rm67195_amoled_fhd_cmd { + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_dcs"; + qcom,mdss-dsi-bl-min-level = <1>; + qcom,mdss-dsi-bl-max-level = <255>; + qcom,panel-supply-entries = <&dsi_panel_pwr_supply_labibb_amoled>; +}; diff --git a/drivers/clk/qcom/clk-rcg.h b/drivers/clk/qcom/clk-rcg.h index 58fbd07e6f15..0bcada9aac5d 100644 --- a/drivers/clk/qcom/clk-rcg.h +++ b/drivers/clk/qcom/clk-rcg.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 2016, The Linux Foundation. All rights reserved. + * Copyright (c) 2013, 2016-2017, 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 @@ -192,5 +192,6 @@ extern const struct clk_ops clk_pixel_ops; extern const struct clk_ops clk_gfx3d_ops; extern const struct clk_ops clk_gfx3d_src_ops; extern const struct clk_ops clk_dp_ops; +extern const struct clk_ops clk_esc_ops; #endif diff --git a/drivers/clk/qcom/clk-rcg2.c b/drivers/clk/qcom/clk-rcg2.c index 632d0f4ac9c1..ff0c8327fabe 100644 --- a/drivers/clk/qcom/clk-rcg2.c +++ b/drivers/clk/qcom/clk-rcg2.c @@ -1349,3 +1349,73 @@ const struct clk_ops clk_gfx3d_src_ops = { .list_registers = clk_rcg2_list_registers, }; EXPORT_SYMBOL_GPL(clk_gfx3d_src_ops); + +static int clk_esc_determine_rate(struct clk_hw *hw, + struct clk_rate_request *req) +{ + struct clk_rcg2 *rcg = to_clk_rcg2(hw); + unsigned long parent_rate, div; + u32 mask = BIT(rcg->hid_width) - 1; + struct clk_hw *p; + unsigned long rate = req->rate; + + if (rate == 0) + return -EINVAL; + + p = req->best_parent_hw; + req->best_parent_rate = parent_rate = clk_hw_round_rate(p, rate); + + div = ((2 * parent_rate) / rate) - 1; + div = min_t(u32, div, mask); + + req->rate = calc_rate(parent_rate, 0, 0, 0, div); + + return 0; +} + +static int clk_esc_set_rate(struct clk_hw *hw, unsigned long rate, + unsigned long parent_rate) +{ + struct clk_rcg2 *rcg = to_clk_rcg2(hw); + struct freq_tbl f = { 0 }; + unsigned long div; + int i, num_parents = clk_hw_get_num_parents(hw); + u32 mask = BIT(rcg->hid_width) - 1; + u32 cfg; + + div = ((2 * parent_rate) / rate) - 1; + div = min_t(u32, div, mask); + + f.pre_div = div; + + regmap_read(rcg->clkr.regmap, rcg->cmd_rcgr + CFG_REG, &cfg); + cfg &= CFG_SRC_SEL_MASK; + cfg >>= CFG_SRC_SEL_SHIFT; + + for (i = 0; i < num_parents; i++) { + if (cfg == rcg->parent_map[i].cfg) { + f.src = rcg->parent_map[i].src; + return clk_rcg2_configure(rcg, &f); + } + } + + return -EINVAL; +} + +static int clk_esc_set_rate_and_parent(struct clk_hw *hw, + unsigned long rate, unsigned long parent_rate, u8 index) +{ + return clk_esc_set_rate(hw, rate, parent_rate); +} + +const struct clk_ops clk_esc_ops = { + .is_enabled = clk_rcg2_is_enabled, + .get_parent = clk_rcg2_get_parent, + .set_parent = clk_rcg2_set_parent, + .recalc_rate = clk_rcg2_recalc_rate, + .determine_rate = clk_esc_determine_rate, + .set_rate = clk_esc_set_rate, + .set_rate_and_parent = clk_esc_set_rate_and_parent, + .list_registers = clk_rcg2_list_registers, +}; +EXPORT_SYMBOL(clk_esc_ops); diff --git a/drivers/clk/qcom/mmcc-sdm660.c b/drivers/clk/qcom/mmcc-sdm660.c index 0bf7ef05ed06..910c36c65b6a 100644 --- a/drivers/clk/qcom/mmcc-sdm660.c +++ b/drivers/clk/qcom/mmcc-sdm660.c @@ -978,12 +978,11 @@ static struct clk_rcg2 esc0_clk_src = { .mnd_width = 0, .hid_width = 5, .parent_map = mmcc_parent_map_1, - .freq_tbl = ftbl_dp_aux_clk_src, .clkr.hw.init = &(struct clk_init_data){ .name = "esc0_clk_src", .parent_names = mmcc_parent_names_1, .num_parents = 4, - .ops = &clk_rcg2_ops, + .ops = &clk_esc_ops, VDD_DIG_FMAX_MAP1( LOWER, 19200000), }, @@ -994,12 +993,11 @@ static struct clk_rcg2 esc1_clk_src = { .mnd_width = 0, .hid_width = 5, .parent_map = mmcc_parent_map_1, - .freq_tbl = ftbl_dp_aux_clk_src, .clkr.hw.init = &(struct clk_init_data){ .name = "esc1_clk_src", .parent_names = mmcc_parent_names_1, .num_parents = 4, - .ops = &clk_rcg2_ops, + .ops = &clk_esc_ops, VDD_DIG_FMAX_MAP1( LOWER, 19200000), }, diff --git a/drivers/firmware/qcom/tz_log.c b/drivers/firmware/qcom/tz_log.c index bf3a24b3eb01..11bd3aae340b 100644 --- a/drivers/firmware/qcom/tz_log.c +++ b/drivers/firmware/qcom/tz_log.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2011-2015, The Linux Foundation. All rights reserved. +/* Copyright (c) 2011-2015,2017 The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -57,6 +57,11 @@ * TZ 3.X version info */ #define QSEE_VERSION_TZ_3_X 0x800000 + +#define TZBSP_AES_256_ENCRYPTED_KEY_SIZE 256 +#define TZBSP_NONCE_LEN 12 +#define TZBSP_TAG_LEN 16 + /* * VMID Table */ @@ -125,6 +130,14 @@ struct tzdbg_int_t { uint64_t int_count[TZBSP_MAX_CPU_COUNT]; /* # of times seen per CPU */ }; +/* warm boot reason for cores */ +struct tzbsp_diag_wakeup_info_t { + /* Wake source info : APCS_GICC_HPPIR */ + uint32_t HPPIR; + /* Wake source info : APCS_GICC_AHPPIR */ + uint32_t AHPPIR; +}; + /* * Log ring buffer position */ @@ -179,6 +192,10 @@ struct tzdbg_t { * Ring Buffer Length */ uint32_t ring_len; + + /* Offset for Wakeup info */ + uint32_t wakeup_info_off; + /* * VMID to EE Mapping */ @@ -193,6 +210,16 @@ struct tzdbg_t { struct tzdbg_reset_info_t reset_info[TZBSP_MAX_CPU_COUNT]; uint32_t num_interrupts; struct tzdbg_int_t int_info[TZBSP_DIAG_INT_NUM]; + + /* Wake up info */ + struct tzbsp_diag_wakeup_info_t wakeup_info[TZBSP_MAX_CPU_COUNT]; + + uint8_t key[TZBSP_AES_256_ENCRYPTED_KEY_SIZE]; + + uint8_t nonce[TZBSP_NONCE_LEN]; + + uint8_t tag[TZBSP_TAG_LEN]; + /* * We need at least 2K for the ring buffer */ @@ -731,10 +758,16 @@ static ssize_t tzdbgfs_read(struct file *file, char __user *buf, int len = 0; int *tz_id = file->private_data; - memcpy_fromio((void *)tzdbg.diag_buf, tzdbg.virt_iobase, + if (*tz_id == TZDBG_BOOT || *tz_id == TZDBG_RESET || + *tz_id == TZDBG_INTERRUPT || *tz_id == TZDBG_GENERAL || + *tz_id == TZDBG_VMID || *tz_id == TZDBG_LOG) + memcpy_fromio((void *)tzdbg.diag_buf, tzdbg.virt_iobase, debug_rw_buf_size); - memcpy_fromio((void *)tzdbg.hyp_diag_buf, tzdbg.hyp_virt_iobase, + + if (*tz_id == TZDBG_HYP_GENERAL || *tz_id == TZDBG_HYP_LOG) + memcpy_fromio((void *)tzdbg.hyp_diag_buf, tzdbg.hyp_virt_iobase, tzdbg.hyp_debug_rw_buf_size); + switch (*tz_id) { case TZDBG_BOOT: len = _disp_tz_boot_stats(); diff --git a/drivers/gpu/drm/msm/msm_drv.c b/drivers/gpu/drm/msm/msm_drv.c index f821a81c53a6..532ff8677259 100644 --- a/drivers/gpu/drm/msm/msm_drv.c +++ b/drivers/gpu/drm/msm/msm_drv.c @@ -1683,7 +1683,7 @@ static struct drm_driver msm_driver = { .debugfs_cleanup = msm_debugfs_cleanup, #endif .ioctls = msm_ioctls, - .num_ioctls = DRM_MSM_NUM_IOCTLS, + .num_ioctls = ARRAY_SIZE(msm_ioctls), .fops = &fops, .name = "msm_drm", .desc = "MSM Snapdragon DRM", diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp.c b/drivers/media/platform/msm/camera_v2/isp/msm_isp.c index bb3f0dca9d92..f2f3388b41c1 100644 --- a/drivers/media/platform/msm/camera_v2/isp/msm_isp.c +++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp.c @@ -590,9 +590,9 @@ int vfe_hw_probe(struct platform_device *pdev) (struct msm_vfe_hardware_info *) match_dev->data; /* Cx ipeak support */ if (of_find_property(pdev->dev.of_node, - "qcom,vfe_cx_ipeak", NULL)) { + "qcom,vfe-cx-ipeak", NULL)) { vfe_dev->vfe_cx_ipeak = cx_ipeak_register( - pdev->dev.of_node, "qcom,vfe_cx_ipeak"); + pdev->dev.of_node, "qcom,vfe-cx-ipeak"); } } else { vfe_dev->hw_info = (struct msm_vfe_hardware_info *) diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp.h b/drivers/media/platform/msm/camera_v2/isp/msm_isp.h index c8cc66a564ce..0325c5ded3cf 100644 --- a/drivers/media/platform/msm/camera_v2/isp/msm_isp.h +++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp.h @@ -768,7 +768,6 @@ struct vfe_device { size_t num_hvx_clk; size_t num_norm_clk; enum cam_ahb_clk_vote ahb_vote; - bool turbo_vote; struct cx_ipeak_client *vfe_cx_ipeak; /* Sync variables*/ @@ -809,6 +808,7 @@ struct vfe_device { uint32_t is_split; uint32_t dual_vfe_enable; unsigned long page_fault_addr; + uint32_t vfe_hw_limit; /* Debug variables */ int dump_reg; diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp47.c b/drivers/media/platform/msm/camera_v2/isp/msm_isp47.c index d829aefe6c98..b704e84cc140 100644 --- a/drivers/media/platform/msm/camera_v2/isp/msm_isp47.c +++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp47.c @@ -331,7 +331,6 @@ int msm_vfe47_init_hardware(struct vfe_device *vfe_dev) goto ahb_vote_fail; } vfe_dev->ahb_vote = CAM_AHB_SVS_VOTE; - vfe_dev->turbo_vote = 0; vfe_dev->common_data->dual_vfe_res->vfe_base[vfe_dev->pdev->id] = vfe_dev->vfe_base; @@ -2563,31 +2562,53 @@ int msm_vfe47_set_clk_rate(struct vfe_device *vfe_dev, long *rate) int rc = 0; int clk_idx = vfe_dev->hw_info->vfe_clk_idx; int ret; + long clk_rate, prev_clk_rate; + clk_rate = clk_round_rate(vfe_dev->vfe_clk[clk_idx], *rate); + if (vfe_dev->msm_isp_vfe_clk_rate == clk_rate) + return rc; + + prev_clk_rate = vfe_dev->msm_isp_vfe_clk_rate; + vfe_dev->msm_isp_vfe_clk_rate = clk_rate; + /* + * if cx_ipeak is supported vote first so that dsp throttling is + * reduced before we go to turbo + */ + if ((vfe_dev->vfe_cx_ipeak) && + (vfe_dev->msm_isp_vfe_clk_rate >= + vfe_dev->vfe_clk_rates[MSM_VFE_CLK_RATE_TURBO] + [vfe_dev->hw_info->vfe_clk_idx]) && + prev_clk_rate < + vfe_dev->vfe_clk_rates[MSM_VFE_CLK_RATE_TURBO] + [vfe_dev->hw_info->vfe_clk_idx]) { + ret = cx_ipeak_update(vfe_dev->vfe_cx_ipeak, true); + if (ret) { + pr_err("%s: cx_ipeak_update failed %d\n", + __func__, ret); + return ret; + } + } + /*set vfe clock*/ rc = msm_camera_clk_set_rate(&vfe_dev->pdev->dev, vfe_dev->vfe_clk[clk_idx], *rate); if (rc < 0) return rc; - *rate = clk_round_rate(vfe_dev->vfe_clk[clk_idx], *rate); - vfe_dev->msm_isp_vfe_clk_rate = *rate; - if (vfe_dev->vfe_cx_ipeak) { - if (vfe_dev->msm_isp_vfe_clk_rate >= - vfe_dev->vfe_clk_rates[MSM_VFE_CLK_RATE_TURBO] - [vfe_dev->hw_info->vfe_clk_idx] && - vfe_dev->turbo_vote == 0) { - ret = cx_ipeak_update(vfe_dev->vfe_cx_ipeak, true); - if (ret) - pr_debug("%s: cx_ipeak_update failed %d\n", - __func__, ret); - else - vfe_dev->turbo_vote = 1; - } else if (vfe_dev->turbo_vote == 1) { - ret = cx_ipeak_update(vfe_dev->vfe_cx_ipeak, false); - if (ret) - pr_debug("%s: cx_ipeak_update failed %d\n", - __func__, ret); - else - vfe_dev->turbo_vote = 0; + /* + * if cx_ipeak is supported remove the vote for non-turbo clock and + * if voting done earlier + */ + if ((vfe_dev->vfe_cx_ipeak) && + (vfe_dev->msm_isp_vfe_clk_rate < + vfe_dev->vfe_clk_rates[MSM_VFE_CLK_RATE_TURBO] + [vfe_dev->hw_info->vfe_clk_idx]) && + prev_clk_rate >= + vfe_dev->vfe_clk_rates[MSM_VFE_CLK_RATE_TURBO] + [vfe_dev->hw_info->vfe_clk_idx]) { + ret = cx_ipeak_update(vfe_dev->vfe_cx_ipeak, false); + if (ret) { + pr_err("%s: cx_ipeak_update failed %d\n", + __func__, ret); + return ret; } } if (vfe_dev->hw_info->vfe_ops.core_ops.ahb_clk_cfg) @@ -2742,6 +2763,8 @@ int msm_vfe47_enable_regulators(struct vfe_device *vfe_dev, int enable) int msm_vfe47_get_platform_data(struct vfe_device *vfe_dev) { int rc = 0; + void __iomem *vfe_fuse_base; + uint32_t vfe_fuse_base_size; vfe_dev->vfe_base = msm_camera_get_reg_base(vfe_dev->pdev, "vfe", 0); if (!vfe_dev->vfe_base) @@ -2766,7 +2789,18 @@ int msm_vfe47_get_platform_data(struct vfe_device *vfe_dev) rc = -ENOMEM; goto get_res_fail; } - + vfe_dev->vfe_hw_limit = 0; + vfe_fuse_base = msm_camera_get_reg_base(vfe_dev->pdev, + "vfe_fuse", 0); + vfe_fuse_base_size = msm_camera_get_res_size(vfe_dev->pdev, + "vfe_fuse"); + if (vfe_fuse_base) { + if (vfe_fuse_base_size) + vfe_dev->vfe_hw_limit = + (msm_camera_io_r(vfe_fuse_base) >> 5) & 0x1; + msm_camera_put_reg_base(vfe_dev->pdev, vfe_fuse_base, + "vfe_fuse", 0); + } rc = vfe_dev->hw_info->vfe_ops.platform_ops.get_regulators(vfe_dev); if (rc) goto get_regulator_fail; diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp_util.c b/drivers/media/platform/msm/camera_v2/isp/msm_isp_util.c index 22246f613462..507198721ccc 100644 --- a/drivers/media/platform/msm/camera_v2/isp/msm_isp_util.c +++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp_util.c @@ -1428,6 +1428,20 @@ static int msm_isp_send_hw_cmd(struct vfe_device *vfe_dev, vfe_dev->vfe_ub_policy = *cfg_data; break; } + case GET_VFE_HW_LIMIT: { + uint32_t *hw_limit = NULL; + + if (cmd_len < sizeof(uint32_t)) { + pr_err("%s:%d failed: invalid cmd len %u exp %zu\n", + __func__, __LINE__, cmd_len, + sizeof(uint32_t)); + return -EINVAL; + } + + hw_limit = (uint32_t *)cfg_data; + *hw_limit = vfe_dev->vfe_hw_limit; + break; + } } return 0; } diff --git a/drivers/media/platform/msm/camera_v2/pproc/cpp/msm_cpp.c b/drivers/media/platform/msm/camera_v2/pproc/cpp/msm_cpp.c index 08aab077eec7..8402e31364b9 100644 --- a/drivers/media/platform/msm/camera_v2/pproc/cpp/msm_cpp.c +++ b/drivers/media/platform/msm/camera_v2/pproc/cpp/msm_cpp.c @@ -980,6 +980,7 @@ static int cpp_init_hardware(struct cpp_device *cpp_dev) { int rc = 0; uint32_t vbif_version; + cpp_dev->turbo_vote = 0; rc = msm_camera_regulator_enable(cpp_dev->cpp_vdd, cpp_dev->num_reg, true); @@ -1432,6 +1433,14 @@ static int cpp_close_node(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) return -ENODEV; } + if (cpp_dev->turbo_vote == 1) { + rc = cx_ipeak_update(cpp_dev->cpp_cx_ipeak, false); + if (rc) + pr_err("cx_ipeak_update failed"); + else + cpp_dev->turbo_vote = 0; + } + cpp_dev->cpp_open_cnt--; if (cpp_dev->cpp_open_cnt == 0) { pr_debug("irq_status: 0x%x\n", @@ -2955,6 +2964,38 @@ static int msm_cpp_validate_input(unsigned int cmd, void *arg, return 0; } +unsigned long cpp_cx_ipeak_update(struct cpp_device *cpp_dev, + unsigned long clock, int idx) +{ + unsigned long clock_rate = 0; + int ret = 0; + + if ((clock >= cpp_dev->hw_info.freq_tbl + [(cpp_dev->hw_info.freq_tbl_count) - 1]) && + (cpp_dev->turbo_vote == 0)) { + ret = cx_ipeak_update(cpp_dev->cpp_cx_ipeak, true); + if (ret) { + pr_err("cx_ipeak voting failed setting clock below turbo"); + clock = cpp_dev->hw_info.freq_tbl + [(cpp_dev->hw_info.freq_tbl_count) - 2]; + } else { + cpp_dev->turbo_vote = 1; + } + clock_rate = msm_cpp_set_core_clk(cpp_dev, clock, idx); + } else if (clock < cpp_dev->hw_info.freq_tbl + [(cpp_dev->hw_info.freq_tbl_count) - 1]) { + clock_rate = msm_cpp_set_core_clk(cpp_dev, clock, idx); + if (cpp_dev->turbo_vote == 1) { + ret = cx_ipeak_update(cpp_dev->cpp_cx_ipeak, false); + if (ret) + pr_err("cx_ipeak unvoting failed"); + else + cpp_dev->turbo_vote = 0; + } + } + return clock_rate; +} + long msm_cpp_subdev_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg) { @@ -3337,9 +3378,15 @@ STREAM_BUFF_END: mutex_unlock(&cpp_dev->mutex); return -EINVAL; } - clock_rate = msm_cpp_set_core_clk(cpp_dev, - clock_settings.clock_rate, - msm_cpp_core_clk_idx); + if (cpp_dev->cpp_cx_ipeak) { + clock_rate = cpp_cx_ipeak_update(cpp_dev, + clock_settings.clock_rate, + msm_cpp_core_clk_idx); + } else { + clock_rate = msm_cpp_set_core_clk(cpp_dev, + clock_settings.clock_rate, + msm_cpp_core_clk_idx); + } if (rc < 0) { pr_err("Fail to set core clk\n"); mutex_unlock(&cpp_dev->mutex); @@ -4391,6 +4438,15 @@ static int cpp_probe(struct platform_device *pdev) } } + if (of_find_property(pdev->dev.of_node, "qcom,cpp-cx-ipeak", NULL)) { + cpp_dev->cpp_cx_ipeak = cx_ipeak_register( + pdev->dev.of_node, "qcom,cpp-cx-ipeak"); + if (cpp_dev->cpp_cx_ipeak) + CPP_DBG("Cx ipeak Registration Successful "); + else + pr_err("Cx ipeak Registration Unsuccessful"); + } + rc = msm_camera_get_reset_info(pdev, &cpp_dev->micro_iface_reset); if (rc < 0) { diff --git a/drivers/media/platform/msm/camera_v2/pproc/cpp/msm_cpp.h b/drivers/media/platform/msm/camera_v2/pproc/cpp/msm_cpp.h index e69b9d633a1f..a05448091e42 100644 --- a/drivers/media/platform/msm/camera_v2/pproc/cpp/msm_cpp.h +++ b/drivers/media/platform/msm/camera_v2/pproc/cpp/msm_cpp.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2013-2016, The Linux Foundation. All rights reserved. +/* Copyright (c) 2013-2017, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -24,6 +24,7 @@ #include "cam_soc_api.h" #include "cam_hw_ops.h" #include <media/msmb_pproc.h> +#include <soc/qcom/cx_ipeak.h> /* hw version info: 31:28 Major version @@ -284,6 +285,8 @@ struct cpp_device { uint32_t micro_reset; struct msm_cpp_payload_params payload_params; struct msm_cpp_vbif_data *vbif_data; + bool turbo_vote; + struct cx_ipeak_client *cpp_cx_ipeak; }; int msm_cpp_set_micro_clk(struct cpp_device *cpp_dev); diff --git a/drivers/net/wireless/ath/wil6210/pm.c b/drivers/net/wireless/ath/wil6210/pm.c index a0acb2d0cb79..7260bef314a4 100644 --- a/drivers/net/wireless/ath/wil6210/pm.c +++ b/drivers/net/wireless/ath/wil6210/pm.c @@ -80,12 +80,20 @@ int wil_suspend(struct wil6210_priv *wil, bool is_runtime) } } - if (wil->platform_ops.suspend) + /* Disable PCIe IRQ to prevent sporadic IRQs when PCIe is suspending */ + wil_dbg_pm(wil, "Disabling PCIe IRQ before suspending\n"); + wil_disable_irq(wil); + + if (wil->platform_ops.suspend) { rc = wil->platform_ops.suspend(wil->platform_handle); + if (rc) + wil_enable_irq(wil); + } out: wil_dbg_pm(wil, "suspend: %s => %d\n", is_runtime ? "runtime" : "system", rc); + return rc; } @@ -104,6 +112,9 @@ int wil_resume(struct wil6210_priv *wil, bool is_runtime) } } + wil_dbg_pm(wil, "Enabling PCIe IRQ\n"); + wil_enable_irq(wil); + /* if netif up, bring hardware up * During open(), IFF_UP set after actual device method * invocation. This prevent recursive call to wil_up() diff --git a/drivers/platform/msm/ipa/ipa_v2/ipa_dp.c b/drivers/platform/msm/ipa/ipa_v2/ipa_dp.c index a2665c9e9688..25364e8efa38 100644 --- a/drivers/platform/msm/ipa/ipa_v2/ipa_dp.c +++ b/drivers/platform/msm/ipa/ipa_v2/ipa_dp.c @@ -1974,6 +1974,8 @@ static void ipa_cleanup_wlan_rx_common_cache(void) struct ipa_rx_pkt_wrapper *rx_pkt; struct ipa_rx_pkt_wrapper *tmp; + spin_lock_bh(&ipa_ctx->wc_memb.wlan_spinlock); + list_for_each_entry_safe(rx_pkt, tmp, &ipa_ctx->wc_memb.wlan_comm_desc_list, link) { list_del(&rx_pkt->link); @@ -1994,6 +1996,8 @@ static void ipa_cleanup_wlan_rx_common_cache(void) IPAERR("wlan comm buff total cnt: %d\n", ipa_ctx->wc_memb.wlan_comm_total_cnt); + spin_unlock_bh(&ipa_ctx->wc_memb.wlan_spinlock); + } static void ipa_alloc_wlan_rx_common_cache(u32 size) diff --git a/drivers/platform/msm/ipa/ipa_v2/ipa_uc_ntn.c b/drivers/platform/msm/ipa/ipa_v2/ipa_uc_ntn.c index d14f8da15595..00d52d0d9115 100644 --- a/drivers/platform/msm/ipa/ipa_v2/ipa_uc_ntn.c +++ b/drivers/platform/msm/ipa/ipa_v2/ipa_uc_ntn.c @@ -361,6 +361,7 @@ int ipa2_setup_uc_ntn_pipes(struct ipa_ntn_conn_in_params *in, ep_dl->uc_offload_state |= IPA_UC_OFFLOAD_CONNECTED; IPAERR("client %d (ep: %d) connected\n", in->dl.client, ipa_ep_idx_dl); + ipa_inc_acquire_wakelock(IPA_WAKELOCK_REF_CLIENT_ODU_RX); fail: IPA_ACTIVE_CLIENTS_DEC_SIMPLE(); @@ -436,6 +437,7 @@ int ipa2_tear_down_uc_offload_pipes(int ipa_ep_idx_ul, ipa_disable_data_path(ipa_ep_idx_dl); memset(&ipa_ctx->ep[ipa_ep_idx_dl], 0, sizeof(struct ipa_ep_context)); IPADBG("dl client (ep: %d) disconnected\n", ipa_ep_idx_dl); + ipa_dec_release_wakelock(IPA_WAKELOCK_REF_CLIENT_ODU_RX); fail: dma_free_coherent(ipa_ctx->uc_pdev, cmd.size, cmd.base, cmd.phys_base); diff --git a/drivers/soc/qcom/service-locator.c b/drivers/soc/qcom/service-locator.c index 8581ed587ead..0d6c1d62c732 100644 --- a/drivers/soc/qcom/service-locator.c +++ b/drivers/soc/qcom/service-locator.c @@ -266,10 +266,9 @@ static int service_locator_send_msg(struct pd_qmi_client_data *pd) if (!domains_read) { db_rev_count = pd->db_rev_count = resp->db_rev_count; pd->total_domains = resp->total_domains; - if (!pd->total_domains && resp->domain_list_len) { - pr_err("total domains not set\n"); - pd->total_domains = resp->domain_list_len; - } + if (!resp->total_domains) + pr_info("No matching domains found\n"); + pd->domain_list = kmalloc( sizeof(struct servreg_loc_entry_v01) * resp->total_domains, GFP_KERNEL); @@ -286,6 +285,10 @@ static int service_locator_send_msg(struct pd_qmi_client_data *pd) rc = -EAGAIN; goto out; } + if (resp->domain_list_len > resp->total_domains) { + /* Always read total_domains from the response msg */ + resp->domain_list_len = resp->total_domains; + } /* Copy the response*/ store_get_domain_list_response(pd, resp, domains_read); domains_read += resp->domain_list_len; diff --git a/drivers/usb/host/xhci-plat.c b/drivers/usb/host/xhci-plat.c index 05d96fd8c07c..3f106b428dba 100644 --- a/drivers/usb/host/xhci-plat.c +++ b/drivers/usb/host/xhci-plat.c @@ -38,12 +38,19 @@ static const struct xhci_driver_overrides xhci_plat_overrides __initconst = { static void xhci_plat_quirks(struct device *dev, struct xhci_hcd *xhci) { + struct device_node *node = dev->of_node; + struct usb_xhci_pdata *pdata = dev_get_platdata(dev); + /* * As of now platform drivers don't provide MSI support so we ensure * here that the generic code does not try to make a pci_dev from our * dev struct in order to setup MSI */ xhci->quirks |= XHCI_PLAT; + + if ((node && of_property_read_bool(node, "usb3-lpm-capable")) || + (pdata && pdata->usb3_lpm_capable)) + xhci->quirks |= XHCI_LPM_SUPPORT; } /* called during probe() after chip reset completes */ @@ -129,7 +136,6 @@ static DEVICE_ATTR(config_imod, S_IRUGO | S_IWUSR, static int xhci_plat_probe(struct platform_device *pdev) { - struct device_node *node = pdev->dev.of_node; struct usb_xhci_pdata *pdata = dev_get_platdata(&pdev->dev); const struct hc_driver *driver; struct xhci_hcd *xhci; @@ -227,10 +233,6 @@ static int xhci_plat_probe(struct platform_device *pdev) 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; - if (HCC_MAX_PSA(xhci->hcc_params) >= 4) xhci->shared_hcd->can_do_streams = 1; diff --git a/drivers/video/fbdev/msm/mdss_mdp_intf_cmd.c b/drivers/video/fbdev/msm/mdss_mdp_intf_cmd.c index c5e1c966ee2f..583cfed598cd 100644 --- a/drivers/video/fbdev/msm/mdss_mdp_intf_cmd.c +++ b/drivers/video/fbdev/msm/mdss_mdp_intf_cmd.c @@ -3207,6 +3207,8 @@ int mdss_mdp_cmd_ctx_stop(struct mdss_mdp_ctl *ctl, ctx->default_pp_num, NULL, NULL); memset(ctx, 0, sizeof(*ctx)); + /* intf stopped, no more kickoff */ + ctx->intf_stopped = 1; return 0; } diff --git a/drivers/video/fbdev/msm/mdss_mdp_layer.c b/drivers/video/fbdev/msm/mdss_mdp_layer.c index c9e32d69d444..f78600072ed0 100644 --- a/drivers/video/fbdev/msm/mdss_mdp_layer.c +++ b/drivers/video/fbdev/msm/mdss_mdp_layer.c @@ -1123,6 +1123,7 @@ static int __configure_pipe_params(struct msm_fb_data_type *mfd, int ret = 0; u32 left_lm_w = left_lm_w_from_mfd(mfd); u64 flags; + bool is_right_blend = false; struct mdss_mdp_mixer *mixer = NULL; struct mdss_overlay_private *mdp5_data = mfd_to_mdp5_data(mfd); @@ -1234,6 +1235,7 @@ static int __configure_pipe_params(struct msm_fb_data_type *mfd, * staging, same pipe will be stagged on both layer mixers. */ if (mdata->has_src_split) { + is_right_blend = pipe->is_right_blend; if (left_blend_pipe) { if (__validate_pipe_priorities(left_blend_pipe, pipe)) { pr_err("priority limitation. left:%d rect:%d, right:%d rect:%d\n", @@ -1245,7 +1247,7 @@ static int __configure_pipe_params(struct msm_fb_data_type *mfd, goto end; } else { pr_debug("pipe%d is a right_pipe\n", pipe->num); - pipe->is_right_blend = true; + is_right_blend = true; } } else if (pipe->is_right_blend) { /* @@ -1254,7 +1256,7 @@ static int __configure_pipe_params(struct msm_fb_data_type *mfd, */ mdss_mdp_mixer_pipe_unstage(pipe, pipe->mixer_left); mdss_mdp_mixer_pipe_unstage(pipe, pipe->mixer_right); - pipe->is_right_blend = false; + is_right_blend = false; } if (is_split_lm(mfd) && __layer_needs_src_split(layer)) { @@ -1280,6 +1282,7 @@ static int __configure_pipe_params(struct msm_fb_data_type *mfd, } pipe->src_split_req = false; } + pipe->is_right_blend = is_right_blend; } pipe->multirect.mode = vinfo->multirect.mode; diff --git a/include/uapi/drm/msm_drm.h b/include/uapi/drm/msm_drm.h index d2f19ac6f536..99fe34d25fc5 100644 --- a/include/uapi/drm/msm_drm.h +++ b/include/uapi/drm/msm_drm.h @@ -263,10 +263,10 @@ struct drm_msm_event_resp { #define DRM_MSM_GEM_CPU_FINI 0x05 #define DRM_MSM_GEM_SUBMIT 0x06 #define DRM_MSM_WAIT_FENCE 0x07 -#define DRM_SDE_WB_CONFIG 0x08 -#define DRM_MSM_REGISTER_EVENT 0x09 -#define DRM_MSM_DEREGISTER_EVENT 0x0A -#define DRM_MSM_NUM_IOCTLS 0x0B + +#define DRM_SDE_WB_CONFIG 0x40 +#define DRM_MSM_REGISTER_EVENT 0x41 +#define DRM_MSM_DEREGISTER_EVENT 0x42 /** * Currently DRM framework supports only VSYNC event. diff --git a/include/uapi/media/msmb_isp.h b/include/uapi/media/msmb_isp.h index 21fcb3401298..d84bb30d56fa 100644 --- a/include/uapi/media/msmb_isp.h +++ b/include/uapi/media/msmb_isp.h @@ -24,6 +24,8 @@ #define ISP_STATS_STREAM_BIT 0x80000000 +#define VFE_HW_LIMIT 1 + struct msm_vfe_cfg_cmd_list; enum ISP_START_PIXEL_PATTERN { @@ -456,6 +458,7 @@ enum msm_vfe_reg_cfg_type { VFE_HW_UPDATE_UNLOCK, SET_WM_UB_SIZE, SET_UB_POLICY, + GET_VFE_HW_LIMIT, }; struct msm_vfe_cfg_cmd2 { diff --git a/sound/soc/codecs/sdm660_cdc/msm-analog-cdc.c b/sound/soc/codecs/sdm660_cdc/msm-analog-cdc.c index e18a756b0eda..e5e71939f529 100644 --- a/sound/soc/codecs/sdm660_cdc/msm-analog-cdc.c +++ b/sound/soc/codecs/sdm660_cdc/msm-analog-cdc.c @@ -4046,6 +4046,7 @@ EXPORT_SYMBOL(msm_anlg_codec_info_create_codec_entry); static int msm_anlg_cdc_soc_probe(struct snd_soc_codec *codec) { struct sdm660_cdc_priv *sdm660_cdc; + struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec); int ret; sdm660_cdc = dev_get_drvdata(codec->dev); @@ -4154,6 +4155,9 @@ static int msm_anlg_cdc_soc_probe(struct snd_soc_codec *codec) /* Set initial cap mode */ msm_anlg_cdc_configure_cap(codec, false, false); + snd_soc_dapm_ignore_suspend(dapm, "PDM Playback"); + snd_soc_dapm_ignore_suspend(dapm, "PDM Capture"); + return 0; } @@ -4229,24 +4233,10 @@ static int msm_anlg_cdc_disable_static_supplies_to_optimum( static int msm_anlg_cdc_suspend(struct snd_soc_codec *codec) { - struct msm_asoc_mach_data *pdata = NULL; struct sdm660_cdc_priv *sdm660_cdc = snd_soc_codec_get_drvdata(codec); struct sdm660_cdc_pdata *sdm660_cdc_pdata = sdm660_cdc->dev->platform_data; - pdata = snd_soc_card_get_drvdata(codec->component.card); - pr_debug("%s: mclk cnt = %d, mclk_enabled = %d\n", - __func__, atomic_read(&pdata->int_mclk0_rsc_ref), - atomic_read(&pdata->int_mclk0_enabled)); - if (atomic_read(&pdata->int_mclk0_enabled) == true) { - cancel_delayed_work_sync(&pdata->disable_int_mclk0_work); - mutex_lock(&pdata->cdc_int_mclk0_mutex); - pdata->digital_cdc_core_clk.enable = 0; - afe_set_lpass_clock_v2(AFE_PORT_ID_INT0_MI2S_RX, - &pdata->digital_cdc_core_clk); - atomic_set(&pdata->int_mclk0_enabled, false); - mutex_unlock(&pdata->cdc_int_mclk0_mutex); - } msm_anlg_cdc_disable_static_supplies_to_optimum(sdm660_cdc, sdm660_cdc_pdata); return 0; diff --git a/sound/soc/codecs/sdm660_cdc/msm-digital-cdc.c b/sound/soc/codecs/sdm660_cdc/msm-digital-cdc.c index d8828a1e36b7..91faee1ffd32 100644 --- a/sound/soc/codecs/sdm660_cdc/msm-digital-cdc.c +++ b/sound/soc/codecs/sdm660_cdc/msm-digital-cdc.c @@ -79,7 +79,7 @@ static int msm_digcdc_clock_control(bool flag) if (atomic_read(&pdata->int_mclk0_enabled) == false) { pdata->digital_cdc_core_clk.enable = 1; ret = afe_set_lpass_clock_v2( - AFE_PORT_ID_PRIMARY_MI2S_RX, + AFE_PORT_ID_INT0_MI2S_RX, &pdata->digital_cdc_core_clk); if (ret < 0) { pr_err("%s:failed to enable the MCLK\n", @@ -1166,6 +1166,7 @@ EXPORT_SYMBOL(msm_dig_codec_info_create_codec_entry); static int msm_dig_cdc_soc_probe(struct snd_soc_codec *codec) { struct msm_dig_priv *msm_dig_cdc = dev_get_drvdata(codec->dev); + struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec); int i, ret; msm_dig_cdc->codec = codec; @@ -1197,6 +1198,15 @@ static int msm_dig_cdc_soc_probe(struct snd_soc_codec *codec) } registered_digcodec = codec; + snd_soc_dapm_ignore_suspend(dapm, "AIF1 Playback"); + snd_soc_dapm_ignore_suspend(dapm, "AIF1 Capture"); + snd_soc_dapm_ignore_suspend(dapm, "ADC1_IN"); + snd_soc_dapm_ignore_suspend(dapm, "ADC2_IN"); + snd_soc_dapm_ignore_suspend(dapm, "ADC3_IN"); + snd_soc_dapm_ignore_suspend(dapm, "PDM_OUT_RX1"); + snd_soc_dapm_ignore_suspend(dapm, "PDM_OUT_RX2"); + snd_soc_dapm_ignore_suspend(dapm, "PDM_OUT_RX3"); + return 0; } @@ -1969,9 +1979,27 @@ static struct regmap *msm_digital_get_regmap(struct device *dev) return msm_dig_cdc->regmap; } +static int msm_dig_cdc_suspend(struct snd_soc_codec *codec) +{ + struct msm_dig_priv *msm_dig_cdc = dev_get_drvdata(codec->dev); + + msm_dig_cdc->dapm_bias_off = 1; + return 0; +} + +static int msm_dig_cdc_resume(struct snd_soc_codec *codec) +{ + struct msm_dig_priv *msm_dig_cdc = dev_get_drvdata(codec->dev); + + msm_dig_cdc->dapm_bias_off = 0; + return 0; +} + static struct snd_soc_codec_driver soc_msm_dig_codec = { .probe = msm_dig_cdc_soc_probe, .remove = msm_dig_cdc_soc_remove, + .suspend = msm_dig_cdc_suspend, + .resume = msm_dig_cdc_resume, .controls = msm_dig_snd_controls, .num_controls = ARRAY_SIZE(msm_dig_snd_controls), .dapm_widgets = msm_dig_dapm_widgets, @@ -2054,6 +2082,44 @@ static int msm_dig_cdc_remove(struct platform_device *pdev) return 0; } +#ifdef CONFIG_PM +static int msm_dig_suspend(struct device *dev) +{ + struct msm_asoc_mach_data *pdata = + snd_soc_card_get_drvdata(registered_digcodec->component.card); + struct msm_dig_priv *msm_dig_cdc = dev_get_drvdata(dev); + + if (msm_dig_cdc->dapm_bias_off) { + pr_debug("%s: mclk cnt = %d, mclk_enabled = %d\n", + __func__, atomic_read(&pdata->int_mclk0_rsc_ref), + atomic_read(&pdata->int_mclk0_enabled)); + + if (atomic_read(&pdata->int_mclk0_enabled) == true) { + cancel_delayed_work_sync( + &pdata->disable_int_mclk0_work); + mutex_lock(&pdata->cdc_int_mclk0_mutex); + pdata->digital_cdc_core_clk.enable = 0; + afe_set_lpass_clock_v2(AFE_PORT_ID_INT0_MI2S_RX, + &pdata->digital_cdc_core_clk); + atomic_set(&pdata->int_mclk0_enabled, false); + mutex_unlock(&pdata->cdc_int_mclk0_mutex); + } + } + + return 0; +} + +static int msm_dig_resume(struct device *dev) +{ + return 0; +} + +static const struct dev_pm_ops msm_dig_pm_ops = { + .suspend = msm_dig_suspend, + .resume = msm_dig_resume, +}; +#endif + static const struct of_device_id msm_dig_cdc_of_match[] = { {.compatible = "qcom,msm-digital-codec"}, {}, @@ -2064,6 +2130,9 @@ static struct platform_driver msm_digcodec_driver = { .owner = THIS_MODULE, .name = DRV_NAME, .of_match_table = msm_dig_cdc_of_match, +#ifdef CONFIG_PM + .pm = &msm_dig_pm_ops, +#endif }, .probe = msm_dig_cdc_probe, .remove = msm_dig_cdc_remove, diff --git a/sound/soc/codecs/sdm660_cdc/msm-digital-cdc.h b/sound/soc/codecs/sdm660_cdc/msm-digital-cdc.h index b401a4082cbb..f0e7a9cf9228 100644 --- a/sound/soc/codecs/sdm660_cdc/msm-digital-cdc.h +++ b/sound/soc/codecs/sdm660_cdc/msm-digital-cdc.h @@ -47,6 +47,7 @@ struct msm_dig_priv { struct regmap *regmap; struct notifier_block nblock; u32 mute_mask; + int dapm_bias_off; void *handle; void (*update_clkdiv)(void *handle, int val); int (*get_cdc_version)(void *handle); diff --git a/sound/soc/msm/qdsp6v2/msm-compress-q6-v2.c b/sound/soc/msm/qdsp6v2/msm-compress-q6-v2.c index 4fa80c679b46..8e986a74ffff 100644 --- a/sound/soc/msm/qdsp6v2/msm-compress-q6-v2.c +++ b/sound/soc/msm/qdsp6v2/msm-compress-q6-v2.c @@ -56,8 +56,8 @@ #define FLAC_BLK_SIZE_LIMIT 65535 /* Timestamp mode payload offsets */ -#define TS_LSW_OFFSET 6 -#define TS_MSW_OFFSET 7 +#define CAPTURE_META_DATA_TS_OFFSET_LSW 6 +#define CAPTURE_META_DATA_TS_OFFSET_MSW 7 /* decoder parameter length */ #define DDP_DEC_MAX_NUM_PARAM 18 @@ -410,6 +410,7 @@ static int msm_compr_send_buffer(struct msm_compr_audio *prtd) int buffer_length; uint64_t bytes_available; struct audio_aio_write_param param; + struct snd_codec_metadata *buff_addr; if (!atomic_read(&prtd->start)) { pr_err("%s: stream is not in started state\n", __func__); @@ -442,23 +443,34 @@ static int msm_compr_send_buffer(struct msm_compr_audio *prtd) } if (buffer_length) { - param.paddr = prtd->buffer_paddr + prtd->byte_offset; + param.paddr = prtd->buffer_paddr + prtd->byte_offset; WARN(prtd->byte_offset % 32 != 0, "offset %x not multiple of 32", prtd->byte_offset); } else - param.paddr = prtd->buffer_paddr; - + param.paddr = prtd->buffer_paddr; param.len = buffer_length; - param.msw_ts = 0; - param.lsw_ts = 0; - param.flags = NO_TIMESTAMP; + if (prtd->ts_header_offset) { + buff_addr = (struct snd_codec_metadata *) + (prtd->buffer + prtd->byte_offset); + param.len = buff_addr->length; + param.msw_ts = (uint32_t) + ((buff_addr->timestamp & 0xFFFFFFFF00000000LL) >> 32); + param.lsw_ts = (uint32_t) (buff_addr->timestamp & 0xFFFFFFFFLL); + param.paddr += prtd->ts_header_offset; + param.flags = SET_TIMESTAMP; + param.metadata_len = prtd->ts_header_offset; + } else { + param.msw_ts = 0; + param.lsw_ts = 0; + param.flags = NO_TIMESTAMP; + param.metadata_len = 0; + } param.uid = buffer_length; - param.metadata_len = 0; param.last_buffer = prtd->last_buffer; pr_debug("%s: sending %d bytes to DSP byte_offset = %d\n", - __func__, buffer_length, prtd->byte_offset); + __func__, param.len, prtd->byte_offset); if (q6asm_async_write(prtd->audio_client, ¶m) < 0) { pr_err("%s:q6asm_async_write failed\n", __func__); } else { @@ -577,9 +589,21 @@ static void compr_event_handler(uint32_t opcode, * written to ADSP in the last write, update offset and * total copied data accordingly. */ - - prtd->byte_offset += token; - prtd->copied_total += token; + if (prtd->ts_header_offset) { + /* Always assume that the data will be sent to DSP on + * frame boundary. + * i.e, one frame of userspace write will result in + * one kernel write to DSP. This is needed as + * timestamp will be sent per frame. + */ + prtd->byte_offset += + prtd->codec_param.buffer.fragment_size; + prtd->copied_total += + prtd->codec_param.buffer.fragment_size; + } else { + prtd->byte_offset += token; + prtd->copied_total += token; + } if (prtd->byte_offset >= prtd->buffer_size) prtd->byte_offset -= prtd->buffer_size; @@ -634,10 +658,10 @@ static void compr_event_handler(uint32_t opcode, *buff_addr = prtd->ts_header_offset; buff_addr++; /* Write the TS LSW */ - *buff_addr = payload[TS_LSW_OFFSET]; + *buff_addr = payload[CAPTURE_META_DATA_TS_OFFSET_LSW]; buff_addr++; /* Write the TS MSW */ - *buff_addr = payload[TS_MSW_OFFSET]; + *buff_addr = payload[CAPTURE_META_DATA_TS_OFFSET_MSW]; } /* Always assume read_size is same as fragment_size */ read_size = prtd->codec_param.buffer.fragment_size; @@ -1320,6 +1344,12 @@ static int msm_compr_configure_dsp_for_playback prtd->buffer_paddr = ac->port[dir].buf[0].phys; prtd->buffer_size = runtime->fragments * runtime->fragment_size; + /* Bit-0 of flags represent timestamp mode */ + if (prtd->codec_param.codec.flags & COMPRESSED_TIMESTAMP_FLAG) + prtd->ts_header_offset = sizeof(struct snd_codec_metadata); + else + prtd->ts_header_offset = 0; + ret = msm_compr_send_media_format_block(cstream, ac->stream_id, false); if (ret < 0) { pr_err("%s, failed to send media format block\n", __func__); diff --git a/sound/soc/msm/qdsp6v2/q6asm.c b/sound/soc/msm/qdsp6v2/q6asm.c index c3a4719542ef..f38108258306 100644 --- a/sound/soc/msm/qdsp6v2/q6asm.c +++ b/sound/soc/msm/qdsp6v2/q6asm.c @@ -7466,9 +7466,13 @@ int q6asm_async_write(struct audio_client *ac, else if (ac->io_mode == io_compressed || ac->io_mode == io_compressed_stream) lbuf_phys_addr = (param->paddr - param->metadata_len); - else - lbuf_phys_addr = param->paddr; - + else { + if (param->flags & SET_TIMESTAMP) + lbuf_phys_addr = param->paddr - + sizeof(struct snd_codec_metadata); + else + lbuf_phys_addr = param->paddr; + } dev_vdbg(ac->dev, "%s: token[0x%x], buf_addr[%pK], buf_size[0x%x], ts_msw[0x%x], ts_lsw[0x%x], lbuf_phys_addr: 0x[%pK]\n", __func__, write.hdr.token, ¶m->paddr, |
