diff options
46 files changed, 1435 insertions, 638 deletions
diff --git a/Documentation/devicetree/bindings/fb/mdss-dsi-panel.txt b/Documentation/devicetree/bindings/fb/mdss-dsi-panel.txt index cc55f6e2bfa0..4d0e1d5e12a2 100644 --- a/Documentation/devicetree/bindings/fb/mdss-dsi-panel.txt +++ b/Documentation/devicetree/bindings/fb/mdss-dsi-panel.txt @@ -165,6 +165,9 @@ Optional properties: - qcom,mdss-dsi-border-color: Defines the border color value if border is present. 0 = default value. - qcom,mdss-dsi-pan-enable-dynamic-fps: Boolean used to enable change in frame rate dynamically. +- qcom,mdss-dsi-pan-enable-dynamic-bitclk: Boolean used to enable change in DSI clock dynamically. +- qcom,mdss-dsi-dynamic-bitclk_freq: An array of integers that specifies the DSI bit clock + frequencies supported as part of dynamic bit clock feature. - qcom,mdss-dsi-pan-fps-update: A string that specifies when to change the frame rate. "dfps_suspend_resume_mode"= FPS change request is implemented during suspend/resume. @@ -696,6 +699,9 @@ Example: qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_wled"; qcom,mdss-dsi-pan-enable-dynamic-fps; qcom,mdss-dsi-pan-fps-update = "dfps_suspend_resume_mode"; + qcom,mdss-dsi-pan-enable-dynamic-bitclk; + qcom,mdss-dsi-dynamic-bitclk_freq = <711037824 724453632 737869440 + 751285248 764701056 778116864 791532672 804948480>; qcom,min-refresh-rate = <30>; qcom,max-refresh-rate = <60>; qcom,mdss-dsi-bl-pmic-bank-select = <0>; diff --git a/arch/arm/boot/dts/qcom/sdm630-mdss-pll.dtsi b/arch/arm/boot/dts/qcom/sdm630-mdss-pll.dtsi index 42eac0ab223a..3adf92a76347 100644 --- a/arch/arm/boot/dts/qcom/sdm630-mdss-pll.dtsi +++ b/arch/arm/boot/dts/qcom/sdm630-mdss-pll.dtsi @@ -1,4 +1,4 @@ -/* Copyright (c) 2017, The Linux Foundation. All rights reserved. +/* Copyright (c) 2017-2018, 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 @@ -19,8 +19,9 @@ #clock-cells = <1>; reg = <0xc994400 0x588>, - <0xc8c2300 0x8>; - reg-names = "pll_base", "gdsc_base"; + <0xc8c2300 0x8>, + <0xc994200 0x98>; + reg-names = "pll_base", "gdsc_base", "dynamic_pll_base"; gdsc-supply = <&gdsc_mdss>; diff --git a/arch/arm/boot/dts/qcom/sdm630-mdss.dtsi b/arch/arm/boot/dts/qcom/sdm630-mdss.dtsi index d7fef426d4b6..de06a67db1b9 100644 --- a/arch/arm/boot/dts/qcom/sdm630-mdss.dtsi +++ b/arch/arm/boot/dts/qcom/sdm630-mdss.dtsi @@ -1,4 +1,4 @@ -/* Copyright (c) 2017, The Linux Foundation. All rights reserved. +/* Copyright (c) 2017-2018, 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 @@ -359,10 +359,19 @@ <&clock_mmss MMSS_MDSS_ESC0_CLK>, <&clock_mmss BYTE0_CLK_SRC>, <&clock_mmss PCLK0_CLK_SRC>, - <&clock_mmss MMSS_MDSS_BYTE0_INTF_CLK>; + <&clock_mmss MMSS_MDSS_BYTE0_INTF_CLK>, + <&mdss_dsi0_pll BYTE0_MUX_CLK>, + <&mdss_dsi0_pll PIX0_MUX_CLK>, + <&mdss_dsi0_pll BYTE0_SRC_CLK>, + <&mdss_dsi0_pll PIX0_SRC_CLK>, + <&mdss_dsi0_pll SHADOW_BYTE0_SRC_CLK>, + <&mdss_dsi0_pll SHADOW_PIX0_SRC_CLK>; clock-names = "byte_clk", "pixel_clk", "core_clk", "byte_clk_rcg", "pixel_clk_rcg", - "byte_intf_clk"; + "byte_intf_clk", "pll_byte_clk_mux", + "pll_pixel_clk_mux", "pll_byte_clk_src", + "pll_pixel_clk_src", "pll_shadow_byte_clk_src", + "pll_shadow_pixel_clk_src"; qcom,platform-strength-ctrl = [ff 06 ff 06 diff --git a/arch/arm/boot/dts/qcom/sdm630-qrd.dtsi b/arch/arm/boot/dts/qcom/sdm630-qrd.dtsi index 384e24d221c4..82e80891e05d 100644 --- a/arch/arm/boot/dts/qcom/sdm630-qrd.dtsi +++ b/arch/arm/boot/dts/qcom/sdm630-qrd.dtsi @@ -1,4 +1,4 @@ -/* Copyright (c) 2017, The Linux Foundation. All rights reserved. +/* Copyright (c) 2017-2018, 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 @@ -366,16 +366,6 @@ gpio-key,wakeup; debounce-interval = <15>; }; - - home { - label = "home"; - gpios = <&pm660_gpios 11 0x1>; - linux,input-type = <1>; - linux,code = <102>; - gpio-key,wakeup; - debounce-interval = <15>; - }; - }; hbtp { diff --git a/arch/arm/boot/dts/qcom/sdm630.dtsi b/arch/arm/boot/dts/qcom/sdm630.dtsi index 1e767b4648b1..808421c763ea 100644 --- a/arch/arm/boot/dts/qcom/sdm630.dtsi +++ b/arch/arm/boot/dts/qcom/sdm630.dtsi @@ -406,9 +406,14 @@ }; cont_splash_mem: splash_region@9d400000 { - reg = <0x0 0x9d400000 0x0 0x02400000>; + reg = <0x0 0x9d400000 0x0 0x23ff000>; label = "cont_splash_mem"; }; + + dfps_data_mem: dfps_data_mem@0x9f7ff000 { + reg = <0 0x9f7ff000 0 0x00001000>; + label = "dfps_data_mem"; + }; }; bluetooth: bt_wcn3990 { diff --git a/arch/arm/boot/dts/qcom/sdm660-mdss-panels.dtsi b/arch/arm/boot/dts/qcom/sdm660-mdss-panels.dtsi index b2f4a8ce47d3..6abd62c01fb5 100644 --- a/arch/arm/boot/dts/qcom/sdm660-mdss-panels.dtsi +++ b/arch/arm/boot/dts/qcom/sdm660-mdss-panels.dtsi @@ -144,6 +144,9 @@ qcom,mdss-dsi-panel-max-error-count = <3>; qcom,mdss-dsi-min-refresh-rate = <53>; qcom,mdss-dsi-max-refresh-rate = <60>; + qcom,mdss-dsi-pan-enable-dynamic-bitclk; + qcom,mdss-dsi-dynamic-bitclk_freq = <798240576 801594528 804948480 + 808302432 811656384>; qcom,mdss-dsi-pan-enable-dynamic-fps; qcom,mdss-dsi-pan-fps-update = "dfps_immediate_porch_mode_vfp"; }; diff --git a/arch/arm/boot/dts/qcom/sdm660-mdss-pll.dtsi b/arch/arm/boot/dts/qcom/sdm660-mdss-pll.dtsi index 69d3736d4ba8..a3b6aadd893e 100644 --- a/arch/arm/boot/dts/qcom/sdm660-mdss-pll.dtsi +++ b/arch/arm/boot/dts/qcom/sdm660-mdss-pll.dtsi @@ -1,4 +1,4 @@ -/* Copyright (c) 2016-2017, The Linux Foundation. All rights reserved. +/* Copyright (c) 2016-2018, 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 @@ -19,8 +19,9 @@ #clock-cells = <1>; reg = <0xc994400 0x588>, - <0xc8c2300 0x8>; - reg-names = "pll_base", "gdsc_base"; + <0xc8c2300 0x8>, + <0xc994200 0x98>; + reg-names = "pll_base", "gdsc_base", "dynamic_pll_base"; gdsc-supply = <&gdsc_mdss>; @@ -29,6 +30,7 @@ clock-rate = <0>; qcom,dsi-pll-ssc-en; qcom,dsi-pll-ssc-mode = "down-spread"; + memory-region = <&dfps_data_mem>; qcom,platform-supply-entries { #address-cells = <1>; @@ -54,8 +56,9 @@ #clock-cells = <1>; reg = <0xc996400 0x588>, - <0xc8c2300 0x8>; - reg-names = "pll_base", "gdsc_base"; + <0xc8c2300 0x8>, + <0xc996200 0x98>; + reg-names = "pll_base", "gdsc_base", "dynamic_pll_base"; gdsc-supply = <&gdsc_mdss>; diff --git a/arch/arm/boot/dts/qcom/sdm660-mdss.dtsi b/arch/arm/boot/dts/qcom/sdm660-mdss.dtsi index ab4e71e3cd65..b4fbb23c51e4 100644 --- a/arch/arm/boot/dts/qcom/sdm660-mdss.dtsi +++ b/arch/arm/boot/dts/qcom/sdm660-mdss.dtsi @@ -1,4 +1,4 @@ -/* Copyright (c) 2016-2017, The Linux Foundation. All rights reserved. +/* Copyright (c) 2016-2018, 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 @@ -382,10 +382,19 @@ <&clock_mmss MMSS_MDSS_ESC0_CLK>, <&clock_mmss BYTE0_CLK_SRC>, <&clock_mmss PCLK0_CLK_SRC>, - <&clock_mmss MMSS_MDSS_BYTE0_INTF_CLK>; + <&clock_mmss MMSS_MDSS_BYTE0_INTF_CLK>, + <&mdss_dsi0_pll BYTE0_MUX_CLK>, + <&mdss_dsi0_pll PIX0_MUX_CLK>, + <&mdss_dsi0_pll BYTE0_SRC_CLK>, + <&mdss_dsi0_pll PIX0_SRC_CLK>, + <&mdss_dsi0_pll SHADOW_BYTE0_SRC_CLK>, + <&mdss_dsi0_pll SHADOW_PIX0_SRC_CLK>; clock-names = "byte_clk", "pixel_clk", "core_clk", "byte_clk_rcg", "pixel_clk_rcg", - "byte_intf_clk"; + "byte_intf_clk", "pll_byte_clk_mux", + "pll_pixel_clk_mux", "pll_byte_clk_src", + "pll_pixel_clk_src", "pll_shadow_byte_clk_src", + "pll_shadow_pixel_clk_src"; qcom,null-insertion-enabled; qcom,platform-strength-ctrl = [ff 06 @@ -423,10 +432,19 @@ <&clock_mmss MMSS_MDSS_ESC1_CLK>, <&clock_mmss BYTE1_CLK_SRC>, <&clock_mmss PCLK1_CLK_SRC>, - <&clock_mmss MMSS_MDSS_BYTE1_INTF_CLK>; + <&clock_mmss MMSS_MDSS_BYTE1_INTF_CLK>, + <&mdss_dsi1_pll BYTE1_MUX_CLK>, + <&mdss_dsi1_pll PIX1_MUX_CLK>, + <&mdss_dsi1_pll BYTE1_SRC_CLK>, + <&mdss_dsi1_pll PIX1_SRC_CLK>, + <&mdss_dsi1_pll SHADOW_BYTE1_SRC_CLK>, + <&mdss_dsi1_pll SHADOW_PIX1_SRC_CLK>; clock-names = "byte_clk", "pixel_clk", "core_clk", "byte_clk_rcg", "pixel_clk_rcg", - "byte_intf_clk"; + "byte_intf_clk", "pll_byte_clk_mux", + "pll_pixel_clk_mux", "pll_byte_clk_src", + "pll_pixel_clk_src", "pll_shadow_byte_clk_src", + "pll_shadow_pixel_clk_src"; qcom,null-insertion-enabled; qcom,platform-strength-ctrl = [ff 06 diff --git a/arch/arm/boot/dts/qcom/sdm660.dtsi b/arch/arm/boot/dts/qcom/sdm660.dtsi index ef72d6bed86f..27bc0cebfc2a 100644 --- a/arch/arm/boot/dts/qcom/sdm660.dtsi +++ b/arch/arm/boot/dts/qcom/sdm660.dtsi @@ -404,9 +404,14 @@ }; cont_splash_mem: splash_region@9d400000 { - reg = <0x0 0x9d400000 0x0 0x02400000>; + reg = <0x0 0x9d400000 0x0 0x23ff000>; label = "cont_splash_mem"; }; + + dfps_data_mem: dfps_data_mem@0x9f7ff000 { + reg = <0 0x9f7ff000 0 0x00001000>; + label = "dfps_data_mem"; + }; }; bluetooth: bt_wcn3990 { diff --git a/arch/arm/boot/dts/qcom/vplatform-lfv-msm8996-ivi-la.dts b/arch/arm/boot/dts/qcom/vplatform-lfv-msm8996-ivi-la.dts index 3434514df69c..5856aa1f6447 100644 --- a/arch/arm/boot/dts/qcom/vplatform-lfv-msm8996-ivi-la.dts +++ b/arch/arm/boot/dts/qcom/vplatform-lfv-msm8996-ivi-la.dts @@ -140,6 +140,7 @@ pinctrl-names = "bootstrap_active", "bootstrap_sleep"; pinctrl-0 = <&cnss_bootstrap_active>; pinctrl-1 = <&cnss_bootstrap_sleep>; + qcom,wlan-ramdump-dynamic = <0x200000>; qcom,msm-bus,name = "msm-cnss"; qcom,msm-bus,num-cases = <4>; diff --git a/drivers/gpu/msm/kgsl.c b/drivers/gpu/msm/kgsl.c index 02f0cb7eb16c..55ebc0a8e26c 100644 --- a/drivers/gpu/msm/kgsl.c +++ b/drivers/gpu/msm/kgsl.c @@ -1403,6 +1403,45 @@ long kgsl_ioctl_device_getproperty(struct kgsl_device_private *dev_priv, kgsl_context_put(context); break; } + case KGSL_PROP_SECURE_BUFFER_ALIGNMENT: + { + unsigned int align; + + if (param->sizebytes != sizeof(unsigned int)) { + result = -EINVAL; + break; + } + /* + * XPUv2 impose the constraint of 1MB memory alignment, + * on the other hand Hypervisor does not have such + * constraints. So driver should fulfill such + * requirements when allocating secure memory. + */ + align = MMU_FEATURE(&dev_priv->device->mmu, + KGSL_MMU_HYP_SECURE_ALLOC) ? PAGE_SIZE : SZ_1M; + + if (copy_to_user(param->value, &align, sizeof(align))) + result = -EFAULT; + + break; + } + case KGSL_PROP_SECURE_CTXT_SUPPORT: + { + unsigned int secure_ctxt; + + if (param->sizebytes != sizeof(unsigned int)) { + result = -EINVAL; + break; + } + + secure_ctxt = dev_priv->device->mmu.secured ? 1 : 0; + + if (copy_to_user(param->value, &secure_ctxt, + sizeof(secure_ctxt))) + result = -EFAULT; + + break; + } default: if (is_compat_task()) result = dev_priv->device->ftbl->getproperty_compat( diff --git a/drivers/i2c/busses/i2c-msm-v2.c b/drivers/i2c/busses/i2c-msm-v2.c index d72953f2df23..198e55829226 100644 --- a/drivers/i2c/busses/i2c-msm-v2.c +++ b/drivers/i2c/busses/i2c-msm-v2.c @@ -2330,6 +2330,12 @@ i2c_msm_frmwrk_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num) struct i2c_msm_ctrl *ctrl = i2c_get_adapdata(adap); struct i2c_msm_xfer *xfer = &ctrl->xfer; + if (num < 1) { + dev_err(ctrl->dev, + "error on number of msgs(%d) received\n", num); + return -EINVAL; + } + if (IS_ERR_OR_NULL(msgs)) { dev_err(ctrl->dev, " error on msgs Accessing invalid pointer location\n"); return PTR_ERR(msgs); diff --git a/drivers/net/wireless/cnss2/main.c b/drivers/net/wireless/cnss2/main.c index 8aa9eabdc73f..ac9d8e7d08ad 100644 --- a/drivers/net/wireless/cnss2/main.c +++ b/drivers/net/wireless/cnss2/main.c @@ -37,6 +37,7 @@ #define FW_READY_TIMEOUT 20000 #define FW_ASSERT_TIMEOUT 5000 #define CNSS_EVENT_PENDING 2989 +#define CE_MSI_NAME "CE" static struct cnss_plat_data *plat_env; @@ -249,7 +250,7 @@ int cnss_wlan_enable(struct device *dev, { struct cnss_plat_data *plat_priv = cnss_bus_dev_to_plat_priv(dev); struct wlfw_wlan_cfg_req_msg_v01 req; - u32 i; + u32 i, ce_id, num_vectors, user_base_data, base_vector; int ret = 0; if (plat_priv->device_id == QCA6174_DEVICE_ID) @@ -299,6 +300,19 @@ int cnss_wlan_enable(struct device *dev, req.svc_cfg[i].pipe_num = config->ce_svc_cfg[i].pipe_num; } + if (config->num_shadow_reg_cfg) { + req.shadow_reg_valid = 1; + + if (config->num_shadow_reg_cfg > + QMI_WLFW_MAX_NUM_SHADOW_REG_V01) + req.shadow_reg_len = QMI_WLFW_MAX_NUM_SHADOW_REG_V01; + else + req.shadow_reg_len = config->num_shadow_reg_cfg; + memcpy(req.shadow_reg, config->shadow_reg_cfg, + sizeof(struct wlfw_shadow_reg_cfg_s_v01) + * req.shadow_reg_len); + } + req.shadow_reg_v2_valid = 1; if (config->num_shadow_reg_v2_cfg > QMI_WLFW_MAX_NUM_SHADOW_REG_V2_V01) @@ -310,6 +324,30 @@ int cnss_wlan_enable(struct device *dev, sizeof(struct wlfw_shadow_reg_v2_cfg_s_v01) * req.shadow_reg_v2_len); + if (config->rri_over_ddr_cfg_valid) { + req.rri_over_ddr_cfg_valid = 1; + req.rri_over_ddr_cfg.base_addr_low = + config->rri_over_ddr_cfg.base_addr_low; + req.rri_over_ddr_cfg.base_addr_high = + config->rri_over_ddr_cfg.base_addr_high; + } + + if (plat_priv->device_id == QCN7605_DEVICE_ID) { + ret = cnss_get_user_msi_assignment(dev, CE_MSI_NAME, + &num_vectors, + &user_base_data, + &base_vector); + if (!ret) { + req.msi_cfg_valid = 1; + req.msi_cfg_len = QMI_WLFW_MAX_NUM_CE_V01; + for (ce_id = 0; ce_id < QMI_WLFW_MAX_NUM_CE_V01; + ce_id++) { + req.msi_cfg[ce_id].ce_id = ce_id; + req.msi_cfg[ce_id].msi_vector = + (ce_id % num_vectors) + base_vector; + } + } + } ret = cnss_wlfw_wlan_cfg_send_sync(plat_priv, &req); if (ret) goto out; diff --git a/drivers/net/wireless/cnss2/pci.c b/drivers/net/wireless/cnss2/pci.c index 1d4b5b9ea9c9..427b42c871f3 100644 --- a/drivers/net/wireless/cnss2/pci.c +++ b/drivers/net/wireless/cnss2/pci.c @@ -1297,6 +1297,94 @@ int cnss_pm_request_resume(struct cnss_pci_data *pci_priv) return pm_request_resume(&pci_dev->dev); } +#ifdef CONFIG_CNSS_QCA6390 +int cnss_pci_force_wake_request(struct device *dev) +{ + struct pci_dev *pci_dev = to_pci_dev(dev); + struct cnss_pci_data *pci_priv = cnss_get_pci_priv(pci_dev); + struct mhi_controller *mhi_ctrl; + + if (!pci_priv) + return -ENODEV; + + if (pci_priv->device_id != QCA6390_DEVICE_ID) + return 0; + + mhi_ctrl = pci_priv->mhi_ctrl; + if (!mhi_ctrl) + return -EINVAL; + + read_lock_bh(&mhi_ctrl->pm_lock); + mhi_ctrl->wake_get(mhi_ctrl, true); + read_unlock_bh(&mhi_ctrl->pm_lock); + + return 0; +} +EXPORT_SYMBOL(cnss_pci_force_wake_request); + +int cnss_pci_is_device_awake(struct device *dev) +{ + struct pci_dev *pci_dev = to_pci_dev(dev); + struct cnss_pci_data *pci_priv = cnss_get_pci_priv(pci_dev); + struct mhi_controller *mhi_ctrl; + + if (!pci_priv) + return -ENODEV; + + if (pci_priv->device_id != QCA6390_DEVICE_ID) + return true; + + mhi_ctrl = pci_priv->mhi_ctrl; + if (!mhi_ctrl) + return -EINVAL; + + return mhi_ctrl->dev_state == MHI_STATE_M0 ? true : false; +} +EXPORT_SYMBOL(cnss_pci_is_device_awake); + +int cnss_pci_force_wake_release(struct device *dev) +{ + struct pci_dev *pci_dev = to_pci_dev(dev); + struct cnss_pci_data *pci_priv = cnss_get_pci_priv(pci_dev); + struct mhi_controller *mhi_ctrl; + + if (!pci_priv) + return -ENODEV; + + if (pci_priv->device_id != QCA6390_DEVICE_ID) + return 0; + + mhi_ctrl = pci_priv->mhi_ctrl; + if (!mhi_ctrl) + return -EINVAL; + + read_lock_bh(&mhi_ctrl->pm_lock); + mhi_ctrl->wake_put(mhi_ctrl, false); + read_unlock_bh(&mhi_ctrl->pm_lock); + + return 0; +} +EXPORT_SYMBOL(cnss_pci_force_wake_release); +#else +int cnss_pci_force_wake_request(struct device *dev) +{ + return 0; +} +EXPORT_SYMBOL(cnss_pci_force_wake_request); + +int cnss_pci_is_device_awake(struct device *dev) +{ + return true; +} +EXPORT_SYMBOL(cnss_pci_is_device_awake); + +int cnss_pci_force_wake_release(struct device *dev) +{ + return 0; +} +EXPORT_SYMBOL(cnss_pci_force_wake_release); +#endif + int cnss_pci_alloc_fw_mem(struct cnss_pci_data *pci_priv) { struct cnss_plat_data *plat_priv = pci_priv->plat_priv; diff --git a/drivers/net/wireless/cnss2/wlan_firmware_service_v01.c b/drivers/net/wireless/cnss2/wlan_firmware_service_v01.c index bbf707b869bd..8f2637c3eaf9 100644 --- a/drivers/net/wireless/cnss2/wlan_firmware_service_v01.c +++ b/drivers/net/wireless/cnss2/wlan_firmware_service_v01.c @@ -144,6 +144,60 @@ static struct elem_info wlfw_shadow_reg_v2_cfg_s_v01_ei[] = { }, }; +static struct elem_info wlfw_rri_over_ddr_cfg_s_v01_ei[] = { + { + .data_type = QMI_UNSIGNED_4_BYTE, + .elem_len = 1, + .elem_size = sizeof(u32), + .is_array = NO_ARRAY, + .tlv_type = 0, + .offset = offsetof(struct + wlfw_rri_over_ddr_cfg_s_v01, + base_addr_low), + }, + { + .data_type = QMI_UNSIGNED_4_BYTE, + .elem_len = 1, + .elem_size = sizeof(u32), + .is_array = NO_ARRAY, + .tlv_type = 0, + .offset = offsetof(struct + wlfw_rri_over_ddr_cfg_s_v01, + base_addr_high), + }, + { + .data_type = QMI_EOTI, + .is_array = NO_ARRAY, + .tlv_type = QMI_COMMON_TLV_TYPE, + }, +}; + +static struct elem_info wlfw_msi_cfg_s_v01_ei[] = { + { + .data_type = QMI_UNSIGNED_2_BYTE, + .elem_len = 1, + .elem_size = sizeof(u16), + .is_array = NO_ARRAY, + .tlv_type = 0, + .offset = offsetof(struct wlfw_msi_cfg_s_v01, + ce_id), + }, + { + .data_type = QMI_UNSIGNED_2_BYTE, + .elem_len = 1, + .elem_size = sizeof(u16), + .is_array = NO_ARRAY, + .tlv_type = 0, + .offset = offsetof(struct wlfw_msi_cfg_s_v01, + msi_vector), + }, + { + .data_type = QMI_EOTI, + .is_array = NO_ARRAY, + .tlv_type = QMI_COMMON_TLV_TYPE, + }, +}; + static struct elem_info wlfw_memory_region_info_s_v01_ei[] = { { .data_type = QMI_UNSIGNED_8_BYTE, @@ -922,6 +976,53 @@ struct elem_info wlfw_wlan_cfg_req_msg_v01_ei[] = { .ei_array = wlfw_shadow_reg_v2_cfg_s_v01_ei, }, { + .data_type = QMI_OPT_FLAG, + .elem_len = 1, + .elem_size = sizeof(u8), + .is_array = NO_ARRAY, + .tlv_type = 0x15, + .offset = offsetof(struct wlfw_wlan_cfg_req_msg_v01, + rri_over_ddr_cfg_valid), + }, + { + .data_type = QMI_STRUCT, + .elem_len = 1, + .elem_size = sizeof(struct wlfw_rri_over_ddr_cfg_s_v01), + .is_array = NO_ARRAY, + .tlv_type = 0x15, + .offset = offsetof(struct wlfw_wlan_cfg_req_msg_v01, + rri_over_ddr_cfg), + .ei_array = wlfw_rri_over_ddr_cfg_s_v01_ei, + }, + { + .data_type = QMI_OPT_FLAG, + .elem_len = 1, + .elem_size = sizeof(u8), + .is_array = NO_ARRAY, + .tlv_type = 0x16, + .offset = offsetof(struct wlfw_wlan_cfg_req_msg_v01, + msi_cfg_valid), + }, + { + .data_type = QMI_DATA_LEN, + .elem_len = 1, + .elem_size = sizeof(u8), + .is_array = NO_ARRAY, + .tlv_type = 0x16, + .offset = offsetof(struct wlfw_wlan_cfg_req_msg_v01, + msi_cfg_len), + }, + { + .data_type = QMI_STRUCT, + .elem_len = QMI_WLFW_MAX_NUM_CE_V01, + .elem_size = sizeof(struct wlfw_msi_cfg_s_v01), + .is_array = VAR_LEN_ARRAY, + .tlv_type = 0x16, + .offset = offsetof(struct wlfw_wlan_cfg_req_msg_v01, + msi_cfg), + .ei_array = wlfw_msi_cfg_s_v01_ei, + }, + { .data_type = QMI_EOTI, .is_array = NO_ARRAY, .tlv_type = QMI_COMMON_TLV_TYPE, diff --git a/drivers/net/wireless/cnss2/wlan_firmware_service_v01.h b/drivers/net/wireless/cnss2/wlan_firmware_service_v01.h index 00a873d11d14..964c1e56dbdd 100644 --- a/drivers/net/wireless/cnss2/wlan_firmware_service_v01.h +++ b/drivers/net/wireless/cnss2/wlan_firmware_service_v01.h @@ -170,6 +170,16 @@ struct wlfw_shadow_reg_v2_cfg_s_v01 { u32 addr; }; +struct wlfw_rri_over_ddr_cfg_s_v01 { + u32 base_addr_low; + u32 base_addr_high; +}; + +struct wlfw_msi_cfg_s_v01 { + u16 ce_id; + u16 msi_vector; +}; + struct wlfw_memory_region_info_s_v01 { u64 region_addr; u32 size; @@ -312,6 +322,11 @@ struct wlfw_wlan_cfg_req_msg_v01 { u32 shadow_reg_v2_len; struct wlfw_shadow_reg_v2_cfg_s_v01 shadow_reg_v2[QMI_WLFW_MAX_NUM_SHADOW_REG_V2_V01]; + u8 rri_over_ddr_cfg_valid; + struct wlfw_rri_over_ddr_cfg_s_v01 rri_over_ddr_cfg; + u8 msi_cfg_valid; + u32 msi_cfg_len; + struct wlfw_msi_cfg_s_v01 msi_cfg[QMI_WLFW_MAX_NUM_CE_V01]; }; #define WLFW_WLAN_CFG_REQ_MSG_V01_MAX_MSG_LEN 803 diff --git a/drivers/net/wireless/wcnss/wcnss_wlan.c b/drivers/net/wireless/wcnss/wcnss_wlan.c index 13ae5c3c2471..b97e550cba5d 100644 --- a/drivers/net/wireless/wcnss/wcnss_wlan.c +++ b/drivers/net/wireless/wcnss/wcnss_wlan.c @@ -2368,6 +2368,12 @@ static void wcnss_nvbin_dnld(void) goto out; } + if (nv->size <= 4) { + pr_err("wcnss: %s: request_firmware failed for %s (file size = %zu)\n", + __func__, NVBIN_FILE, nv->size); + goto out; + } + /* First 4 bytes in nv blob is validity bitmap. * We cannot validate nv, so skip those 4 bytes. */ diff --git a/drivers/soc/qcom/hab/hab.c b/drivers/soc/qcom/hab/hab.c index db4961f5f15f..ebe7dfc4a5b6 100644 --- a/drivers/soc/qcom/hab/hab.c +++ b/drivers/soc/qcom/hab/hab.c @@ -21,7 +21,7 @@ .openlock = __SPIN_LOCK_UNLOCKED(&hab_devices[__num__].openlock)\ } -static const char hab_info_str[] = "Change: 16764735 Revision: #76"; +static const char hab_info_str[] = "Change: 17280941 Revision: #81"; /* * The following has to match habmm definitions, order does not matter if @@ -42,15 +42,13 @@ static struct hab_device hab_devices[] = { HAB_DEVICE_CNSTR(DEVICE_DISP5_NAME, MM_DISP_5, 10), HAB_DEVICE_CNSTR(DEVICE_GFX_NAME, MM_GFX, 11), HAB_DEVICE_CNSTR(DEVICE_VID_NAME, MM_VID, 12), - HAB_DEVICE_CNSTR(DEVICE_MISC_NAME, MM_MISC, 13), - HAB_DEVICE_CNSTR(DEVICE_QCPE1_NAME, MM_QCPE_VM1, 14), - HAB_DEVICE_CNSTR(DEVICE_QCPE2_NAME, MM_QCPE_VM2, 15), - HAB_DEVICE_CNSTR(DEVICE_QCPE3_NAME, MM_QCPE_VM3, 16), - HAB_DEVICE_CNSTR(DEVICE_QCPE4_NAME, MM_QCPE_VM4, 17), - HAB_DEVICE_CNSTR(DEVICE_CLK1_NAME, MM_CLK_VM1, 18), - HAB_DEVICE_CNSTR(DEVICE_CLK2_NAME, MM_CLK_VM2, 19), - HAB_DEVICE_CNSTR(DEVICE_FDE1_NAME, MM_FDE_1, 20), - HAB_DEVICE_CNSTR(DEVICE_BUFFERQ1_NAME, MM_BUFFERQ_1, 21), + HAB_DEVICE_CNSTR(DEVICE_VID2_NAME, MM_VID_2, 13), + HAB_DEVICE_CNSTR(DEVICE_MISC_NAME, MM_MISC, 14), + HAB_DEVICE_CNSTR(DEVICE_QCPE1_NAME, MM_QCPE_VM1, 15), + HAB_DEVICE_CNSTR(DEVICE_CLK1_NAME, MM_CLK_VM1, 16), + HAB_DEVICE_CNSTR(DEVICE_CLK2_NAME, MM_CLK_VM2, 17), + HAB_DEVICE_CNSTR(DEVICE_FDE1_NAME, MM_FDE_1, 18), + HAB_DEVICE_CNSTR(DEVICE_BUFFERQ1_NAME, MM_BUFFERQ_1, 19), }; struct hab_driver hab_driver = { @@ -218,7 +216,15 @@ struct virtual_channel *hab_get_vchan_fromvcid(int32_t vcid, read_lock(&ctx->ctx_lock); list_for_each_entry(vchan, &ctx->vchannels, node) { if (vcid == vchan->id) { - kref_get(&vchan->refcount); + if (vchan->otherend_closed || vchan->closed || + !kref_get_unless_zero(&vchan->refcount)) { + pr_debug("failed to inc vcid %x remote %x session %d refcnt %d close_flg remote %d local %d\n", + vchan->id, vchan->otherend_id, + vchan->session_id, + get_refcnt(vchan->refcount), + vchan->otherend_closed, vchan->closed); + vchan = NULL; + } read_unlock(&ctx->ctx_lock); return vchan; } @@ -1074,15 +1080,25 @@ static int hab_release(struct inode *inodep, struct file *filep) /* notify remote side on vchan closing */ list_for_each_entry_safe(vchan, tmp, &ctx->vchannels, node) { list_del(&vchan->node); /* vchan is not in this ctx anymore */ - hab_vchan_stop_notify(vchan); + + if (!vchan->closed) { /* locally hasn't closed yet */ + if (!kref_get_unless_zero(&vchan->refcount)) { + pr_err("vchan %x %x refcnt %d mismanaged closed %d remote closed %d\n", + vchan->id, + vchan->otherend_id, + get_refcnt(vchan->refcount), + vchan->closed, vchan->otherend_closed); + continue; /* vchan is already being freed */ + } else { + hab_vchan_stop_notify(vchan); + /* put for notify. shouldn't cause free */ + hab_vchan_put(vchan); + } + } else + continue; + write_unlock(&ctx->ctx_lock); - if (!vchan->closed) { - pr_warn("potential leak vc %pK %x remote %x session %d refcnt %d\n", - vchan, vchan->id, vchan->otherend_id, - vchan->session_id, - get_refcnt(vchan->refcount)); - hab_vchan_put(vchan); /* there is a lock inside */ - } + hab_vchan_put(vchan); /* there is a lock inside */ write_lock(&ctx->ctx_lock); } @@ -1316,7 +1332,6 @@ static int __init hab_init(void) dev_t dev; place_marker("M - HAB INIT Start"); - result = alloc_chrdev_region(&hab_driver.major, 0, 1, "hab"); if (result < 0) { @@ -1371,11 +1386,8 @@ static int __init hab_init(void) } else set_dma_ops(hab_driver.dev, &hab_dma_ops); } - hab_stat_init(&hab_driver); - place_marker("M - HAB INIT End"); - return result; err: diff --git a/drivers/soc/qcom/hab/hab.h b/drivers/soc/qcom/hab/hab.h index c4e8eaa368e3..cbc049e89d63 100644 --- a/drivers/soc/qcom/hab/hab.h +++ b/drivers/soc/qcom/hab/hab.h @@ -45,6 +45,7 @@ #include <linux/reboot.h> #include <linux/kobject.h> #include <linux/sysfs.h> +#include <linux/delay.h> #include <soc/qcom/boot_stats.h> enum hab_payload_type { @@ -81,11 +82,9 @@ enum hab_payload_type { #define DEVICE_DISP5_NAME "hab_disp5" #define DEVICE_GFX_NAME "hab_ogles" #define DEVICE_VID_NAME "hab_vid" +#define DEVICE_VID2_NAME "hab_vid2" #define DEVICE_MISC_NAME "hab_misc" #define DEVICE_QCPE1_NAME "hab_qcpe_vm1" -#define DEVICE_QCPE2_NAME "hab_qcpe_vm2" -#define DEVICE_QCPE3_NAME "hab_qcpe_vm3" -#define DEVICE_QCPE4_NAME "hab_qcpe_vm4" #define DEVICE_CLK1_NAME "hab_clock_vm1" #define DEVICE_CLK2_NAME "hab_clock_vm2" #define DEVICE_FDE1_NAME "hab_fde1" @@ -346,6 +345,8 @@ struct hab_driver { }; struct virtual_channel { + struct list_head node; /* for ctx */ + struct list_head pnode; /* for pchan */ /* * refcount is used to track the references from hab core to the virtual * channel such as references from physical channels, @@ -354,8 +355,6 @@ struct virtual_channel { struct kref refcount; struct physical_channel *pchan; struct uhab_context *ctx; - struct list_head node; /* for ctx */ - struct list_head pnode; /* for pchan */ struct list_head rx_list; wait_queue_head_t rx_queue; spinlock_t rx_lock; diff --git a/drivers/soc/qcom/hab/hab_ghs.c b/drivers/soc/qcom/hab/hab_ghs.c index e743d9b00a66..a445aa1a6707 100644 --- a/drivers/soc/qcom/hab/hab_ghs.c +++ b/drivers/soc/qcom/hab/hab_ghs.c @@ -14,6 +14,7 @@ #include "hab.h" #include "hab_ghs.h" +#define GIPC_VM_SET_CNT 22 static const char * const dt_gipc_path_name[] = { "testgipc1", "testgipc2", @@ -39,12 +40,41 @@ static const char * const dt_gipc_path_name[] = { "testgipc22", }; + +/* same vmid assignment for all the vms. it should matches dt_gipc_path_name */ +int mmid_order[GIPC_VM_SET_CNT] = { + MM_AUD_1, + MM_AUD_2, + MM_AUD_3, + MM_AUD_4, + MM_CAM_1, + MM_CAM_2, + MM_DISP_1, + MM_DISP_2, + MM_DISP_3, + MM_DISP_4, + MM_DISP_5, + MM_GFX, + MM_VID, + MM_MISC, + MM_QCPE_VM1, + MM_VID_2, /* newly recycled */ + 0, + 0, + MM_CLK_VM1, + MM_CLK_VM2, + MM_FDE_1, + MM_BUFFERQ_1, +}; + static struct ghs_vmm_plugin_info_s { const char * const *dt_name; + int *mmid_dt_mapping; int curr; int probe_cnt; } ghs_vmm_plugin_info = { dt_gipc_path_name, + mmid_order, 0, ARRAY_SIZE(dt_gipc_path_name), }; @@ -59,6 +89,33 @@ static void ghs_irq_handler(void *cookie) tasklet_schedule(&dev->task); } +static int get_dt_name_idx(int vmid_base, int mmid, + struct ghs_vmm_plugin_info_s *plugin_info) +{ + int idx = -1; + int i; + + if (vmid_base < 0 || vmid_base > plugin_info->probe_cnt / + GIPC_VM_SET_CNT) { + pr_err("vmid %d overflow expected max %d\n", vmid_base, + plugin_info->probe_cnt / GIPC_VM_SET_CNT); + return idx; + } + + for (i = 0; i < GIPC_VM_SET_CNT; i++) { + if (mmid == plugin_info->mmid_dt_mapping[i]) { + idx = vmid_base * GIPC_VM_SET_CNT + i; + if (idx > plugin_info->probe_cnt) { + pr_err("dt name idx %d overflow max %d\n", + idx, plugin_info->probe_cnt); + idx = -1; + } + break; + } + } + return idx; +} + /* static struct physical_channel *habhyp_commdev_alloc(int id) */ int habhyp_commdev_alloc(void **commdev, int is_be, char *name, int vmid_remote, struct hab_device *mmid_device) @@ -67,6 +124,7 @@ int habhyp_commdev_alloc(void **commdev, int is_be, char *name, int vmid_remote, struct physical_channel *pchan = NULL; struct physical_channel **ppchan = (struct physical_channel **)commdev; int ret = 0; + int dt_name_idx = 0; if (ghs_vmm_plugin_info.curr > ghs_vmm_plugin_info.probe_cnt) { pr_err("too many commdev alloc %d, supported is %d\n", @@ -101,13 +159,25 @@ int habhyp_commdev_alloc(void **commdev, int is_be, char *name, int vmid_remote, gvh_dn = of_find_node_by_path("/aliases"); if (gvh_dn) { const char *ep_path = NULL; - struct device_node *ep_dn; + struct device_node *ep_dn = NULL; + + dt_name_idx = get_dt_name_idx(vmid_remote, + mmid_device->id, + &ghs_vmm_plugin_info); + if (dt_name_idx < 0) { + pr_err("failed to find %s for vmid %d ret %d\n", + mmid_device->name, + mmid_device->id, + dt_name_idx); + ret = -ENOENT; + goto err; + } ret = of_property_read_string(gvh_dn, - ghs_vmm_plugin_info.dt_name[ghs_vmm_plugin_info.curr], - &ep_path); + ghs_vmm_plugin_info.dt_name[dt_name_idx], + &ep_path); if (ret) - pr_err("failed to read endpoint string ret %d\n", + pr_err("failed to read endpoint str ret %d\n", ret); of_node_put(gvh_dn); @@ -117,22 +187,23 @@ int habhyp_commdev_alloc(void **commdev, int is_be, char *name, int vmid_remote, of_node_put(ep_dn); if (IS_ERR(dev->endpoint)) { ret = PTR_ERR(dev->endpoint); - pr_err("KGIPC alloc failed id: %d, ret: %d\n", - ghs_vmm_plugin_info.curr, ret); + pr_err("alloc failed %d %s ret %d\n", + dt_name_idx, mmid_device->name, + ret); goto err; } else { - pr_debug("gipc ep found for %d\n", - ghs_vmm_plugin_info.curr); + pr_debug("gipc ep found for %d %s\n", + dt_name_idx, mmid_device->name); } } else { - pr_err("of_parse_phandle failed id: %d\n", - ghs_vmm_plugin_info.curr); + pr_err("of_parse_phandle failed id %d %s\n", + dt_name_idx, mmid_device->name); ret = -ENOENT; goto err; } } else { - pr_err("of_find_compatible_node failed id: %d\n", - ghs_vmm_plugin_info.curr); + pr_err("of_find_compatible_node failed id %d %s\n", + dt_name_idx, mmid_device->name); ret = -ENOENT; goto err; } @@ -149,6 +220,7 @@ int habhyp_commdev_alloc(void **commdev, int is_be, char *name, int vmid_remote, pchan->hyp_data = (void *)dev; pchan->is_be = is_be; strlcpy(dev->name, name, sizeof(dev->name)); + strlcpy(pchan->name, name, sizeof(pchan->name)); *ppchan = pchan; dev->read_data = kmalloc(GIPC_RECV_BUFF_SIZE_BYTES, GFP_KERNEL); if (!dev->read_data) { diff --git a/drivers/soc/qcom/hab/hab_mem_linux.c b/drivers/soc/qcom/hab/hab_mem_linux.c index b5afd983d64c..60156c6b00f0 100644 --- a/drivers/soc/qcom/hab/hab_mem_linux.c +++ b/drivers/soc/qcom/hab/hab_mem_linux.c @@ -21,18 +21,14 @@ struct pages_list { struct page **pages; long npages; uint64_t index; /* for mmap first call */ - int kernel; void *kva; - void *uva; - int refcntk; - int refcntu; uint32_t userflags; struct file *filp_owner; struct file *filp_mapper; - struct dma_buf *dmabuf; int32_t export_id; int32_t vcid; struct physical_channel *pchan; + struct kref refcount; }; struct importer_context { @@ -42,6 +38,118 @@ struct importer_context { rwlock_t implist_lock; }; +static struct pages_list *pages_list_create( + void *imp_ctx, + struct export_desc *exp, + uint32_t userflags) +{ + struct page **pages; + struct compressed_pfns *pfn_table = + (struct compressed_pfns *)exp->payload; + struct pages_list *pglist; + unsigned long pfn; + int i, j, k = 0, size; + + if (!pfn_table) + return ERR_PTR(-EINVAL); + + size = exp->payload_count * sizeof(struct page *); + pages = kmalloc(size, GFP_KERNEL); + if (!pages) + return ERR_PTR(-ENOMEM); + + pglist = kzalloc(sizeof(*pglist), GFP_KERNEL); + if (!pglist) { + kfree(pages); + return ERR_PTR(-ENOMEM); + } + + pfn = pfn_table->first_pfn; + for (i = 0; i < pfn_table->nregions; i++) { + for (j = 0; j < pfn_table->region[i].size; j++) { + pages[k] = pfn_to_page(pfn+j); + k++; + } + pfn += pfn_table->region[i].size + pfn_table->region[i].space; + } + + pglist->pages = pages; + pglist->npages = exp->payload_count; + pglist->userflags = userflags; + pglist->export_id = exp->export_id; + pglist->vcid = exp->vcid_remote; + pglist->pchan = exp->pchan; + + kref_init(&pglist->refcount); + + return pglist; +} + +static void pages_list_destroy(struct kref *refcount) +{ + struct pages_list *pglist = container_of(refcount, + struct pages_list, refcount); + + if (pglist->kva) + vunmap(pglist->kva); + + kfree(pglist->pages); + + kfree(pglist); +} + +static void pages_list_get(struct pages_list *pglist) +{ + kref_get(&pglist->refcount); +} + +static int pages_list_put(struct pages_list *pglist) +{ + return kref_put(&pglist->refcount, pages_list_destroy); +} + +static struct pages_list *pages_list_lookup( + struct importer_context *imp_ctx, + uint32_t export_id, struct physical_channel *pchan) +{ + struct pages_list *pglist, *tmp; + + read_lock(&imp_ctx->implist_lock); + list_for_each_entry_safe(pglist, tmp, &imp_ctx->imp_list, list) { + if (pglist->export_id == export_id && + pglist->pchan == pchan) { + pages_list_get(pglist); + read_unlock(&imp_ctx->implist_lock); + return pglist; + } + } + read_unlock(&imp_ctx->implist_lock); + + return NULL; +} + +static void pages_list_add(struct importer_context *imp_ctx, + struct pages_list *pglist) +{ + pages_list_get(pglist); + + write_lock(&imp_ctx->implist_lock); + list_add_tail(&pglist->list, &imp_ctx->imp_list); + imp_ctx->cnt++; + write_unlock(&imp_ctx->implist_lock); +} + +static void pages_list_remove(struct importer_context *imp_ctx, + struct pages_list *pglist) +{ + write_lock(&imp_ctx->implist_lock); + list_del(&pglist->list); + imp_ctx->cnt--; + write_unlock(&imp_ctx->implist_lock); + + pages_list_put(pglist); +} + void *habmm_hyp_allocate_grantable(int page_count, uint32_t *sizebytes) { @@ -192,9 +300,12 @@ static int habmem_get_dma_pages_from_fd(int32_t fd, for (j = 0; j < (s->length >> PAGE_SHIFT); j++) { pages[rc] = nth_page(page, j); rc++; - if (WARN_ON(rc >= page_count)) + if (rc >= page_count) break; } + + if (rc >= page_count) + break; } err: @@ -320,16 +431,8 @@ void habmem_imp_hyp_close(void *imp_ctx, int kernel) if (!priv) return; - list_for_each_entry_safe(pglist, pglist_tmp, &priv->imp_list, list) { - if (kernel && pglist->kva) - vunmap(pglist->kva); - - list_del(&pglist->list); - priv->cnt--; - - kfree(pglist->pages); - kfree(pglist); - } + list_for_each_entry_safe(pglist, pglist_tmp, &priv->imp_list, list) + pages_list_remove(priv, pglist); kfree(priv); } @@ -406,10 +509,19 @@ static int hab_map_fault(struct vm_area_struct *vma, struct vm_fault *vmf) static void hab_map_open(struct vm_area_struct *vma) { + struct pages_list *pglist = + (struct pages_list *)vma->vm_private_data; + + pages_list_get(pglist); } static void hab_map_close(struct vm_area_struct *vma) { + struct pages_list *pglist = + (struct pages_list *)vma->vm_private_data; + + pages_list_put(pglist); + vma->vm_private_data = NULL; } static const struct vm_operations_struct habmem_vm_ops = { @@ -418,6 +530,51 @@ static const struct vm_operations_struct habmem_vm_ops = { .close = hab_map_close, }; +static int hab_buffer_fault(struct vm_area_struct *vma, struct vm_fault *vmf) +{ + struct pages_list *pglist = vma->vm_private_data; + pgoff_t page_offset; + int ret; + + page_offset = ((unsigned long)vmf->virtual_address - vma->vm_start) >> + PAGE_SHIFT; + + if (page_offset > pglist->npages) + return VM_FAULT_SIGBUS; + + ret = vm_insert_page(vma, (unsigned long)vmf->virtual_address, + pglist->pages[page_offset]); + + switch (ret) { + case 0: + return VM_FAULT_NOPAGE; + case -ENOMEM: + return VM_FAULT_OOM; + case -EBUSY: + return VM_FAULT_RETRY; + case -EFAULT: + case -EINVAL: + return VM_FAULT_SIGBUS; + default: + WARN_ON(1); + return VM_FAULT_SIGBUS; + } +} + +static void hab_buffer_open(struct vm_area_struct *vma) +{ +} + +static void hab_buffer_close(struct vm_area_struct *vma) +{ +} + +static const struct vm_operations_struct hab_buffer_vm_ops = { + .fault = hab_buffer_fault, + .open = hab_buffer_open, + .close = hab_buffer_close, +}; + static int hab_mem_mmap(struct dma_buf *dmabuf, struct vm_area_struct *vma) { struct pages_list *pglist = dmabuf->priv; @@ -431,7 +588,7 @@ static int hab_mem_mmap(struct dma_buf *dmabuf, struct vm_area_struct *vma) return -EINVAL; vma->vm_flags |= VM_IO | VM_PFNMAP | VM_DONTEXPAND | VM_DONTDUMP; - vma->vm_ops = &habmem_vm_ops; + vma->vm_ops = &hab_buffer_vm_ops; vma->vm_private_data = pglist; vma->vm_flags |= VM_MIXEDMAP; @@ -440,6 +597,9 @@ static int hab_mem_mmap(struct dma_buf *dmabuf, struct vm_area_struct *vma) static void hab_mem_dma_buf_release(struct dma_buf *dmabuf) { + struct pages_list *pglist = dmabuf->priv; + + pages_list_put(pglist); } static void *hab_mem_dma_buf_kmap(struct dma_buf *dmabuf, @@ -470,82 +630,50 @@ static int habmem_imp_hyp_map_fd(void *imp_ctx, uint32_t userflags, int32_t *pfd) { - struct page **pages; - struct compressed_pfns *pfn_table = - (struct compressed_pfns *)exp->payload; struct pages_list *pglist; struct importer_context *priv = imp_ctx; - unsigned long pfn; - int i, j, k = 0; - pgprot_t prot = PAGE_KERNEL; - int32_t fd, size; + int32_t fd = -1; int ret; + struct dma_buf *dmabuf; DEFINE_DMA_BUF_EXPORT_INFO(exp_info); - if (!pfn_table || !priv) + if (!priv) return -EINVAL; - size = exp->payload_count * sizeof(struct page *); - pages = kmalloc(size, GFP_KERNEL); - if (!pages) - return -ENOMEM; - - pglist = kzalloc(sizeof(*pglist), GFP_KERNEL); - if (!pglist) { - kfree(pages); - return -ENOMEM; - } - pfn = pfn_table->first_pfn; - for (i = 0; i < pfn_table->nregions; i++) { - for (j = 0; j < pfn_table->region[i].size; j++) { - pages[k] = pfn_to_page(pfn+j); - k++; - } - pfn += pfn_table->region[i].size + pfn_table->region[i].space; - } + pglist = pages_list_lookup(priv, exp->export_id, exp->pchan); + if (pglist) + goto buffer_ready; - pglist->pages = pages; - pglist->npages = exp->payload_count; - pglist->kernel = 0; - pglist->index = 0; - pglist->refcntk = pglist->refcntu = 0; - pglist->userflags = userflags; - pglist->export_id = exp->export_id; - pglist->vcid = exp->vcid_remote; - pglist->pchan = exp->pchan; + pglist = pages_list_create(imp_ctx, exp, userflags); + if (IS_ERR(pglist)) + return PTR_ERR(pglist); - if (!(userflags & HABMM_IMPORT_FLAGS_CACHED)) - prot = pgprot_writecombine(prot); + pages_list_add(priv, pglist); +buffer_ready: exp_info.ops = &dma_buf_ops; - exp_info.size = exp->payload_count << PAGE_SHIFT; + exp_info.size = pglist->npages << PAGE_SHIFT; exp_info.flags = O_RDWR; exp_info.priv = pglist; - pglist->dmabuf = dma_buf_export(&exp_info); - if (IS_ERR(pglist->dmabuf)) { - ret = PTR_ERR(pglist->dmabuf); - kfree(pages); - kfree(pglist); - return ret; + dmabuf = dma_buf_export(&exp_info); + if (IS_ERR(dmabuf)) { + pr_err("export to dmabuf failed\n"); + ret = PTR_ERR(dmabuf); + goto proc_end; } + pages_list_get(pglist); - fd = dma_buf_fd(pglist->dmabuf, O_CLOEXEC); + fd = dma_buf_fd(dmabuf, O_CLOEXEC); if (fd < 0) { - dma_buf_put(pglist->dmabuf); - kfree(pages); - kfree(pglist); - return -EINVAL; + pr_err("dma buf to fd failed\n"); + dma_buf_put(dmabuf); + ret = -EINVAL; + goto proc_end; } - pglist->refcntk++; - - write_lock(&priv->implist_lock); - list_add_tail(&pglist->list, &priv->imp_list); - priv->cnt++; - write_unlock(&priv->implist_lock); - +proc_end: *pfd = fd; - + pages_list_put(pglist); return 0; } @@ -554,68 +682,45 @@ static int habmem_imp_hyp_map_kva(void *imp_ctx, uint32_t userflags, void **pkva) { - struct page **pages; - struct compressed_pfns *pfn_table = - (struct compressed_pfns *)exp->payload; struct pages_list *pglist; struct importer_context *priv = imp_ctx; - unsigned long pfn; - int i, j, k = 0, size; pgprot_t prot = PAGE_KERNEL; - if (!pfn_table || !priv) + if (!priv) return -EINVAL; - size = exp->payload_count * sizeof(struct page *); - pages = kmalloc(size, GFP_KERNEL); - if (!pages) - return -ENOMEM; - pglist = kzalloc(sizeof(*pglist), GFP_KERNEL); - if (!pglist) { - kfree(pages); - return -ENOMEM; - } - pfn = pfn_table->first_pfn; - for (i = 0; i < pfn_table->nregions; i++) { - for (j = 0; j < pfn_table->region[i].size; j++) { - pages[k] = pfn_to_page(pfn+j); - k++; - } - pfn += pfn_table->region[i].size + pfn_table->region[i].space; - } + pglist = pages_list_lookup(priv, exp->export_id, exp->pchan); + if (pglist) + goto buffer_ready; - pglist->pages = pages; - pglist->npages = exp->payload_count; - pglist->kernel = 1; - pglist->refcntk = pglist->refcntu = 0; - pglist->userflags = userflags; - pglist->export_id = exp->export_id; - pglist->vcid = exp->vcid_remote; - pglist->pchan = exp->pchan; + pglist = pages_list_create(imp_ctx, exp, userflags); + if (IS_ERR(pglist)) + return PTR_ERR(pglist); + + pages_list_add(priv, pglist); + +buffer_ready: + if (pglist->kva) + goto pro_end; + + if (pglist->userflags != userflags) { + pr_info("exp %d: userflags: 0x%x -> 0x%x\n", + exp->export_id, pglist->userflags, userflags); + pglist->userflags = userflags; + } if (!(userflags & HABMM_IMPORT_FLAGS_CACHED)) prot = pgprot_writecombine(prot); pglist->kva = vmap(pglist->pages, pglist->npages, VM_MAP, prot); if (pglist->kva == NULL) { - kfree(pages); pr_err("%ld pages vmap failed\n", pglist->npages); - kfree(pglist); return -ENOMEM; } - pr_debug("%ld pages vmap pass, return %p\n", - pglist->npages, pglist->kva); - - pglist->refcntk++; - - write_lock(&priv->implist_lock); - list_add_tail(&pglist->list, &priv->imp_list); - priv->cnt++; - write_unlock(&priv->implist_lock); - +pro_end: *pkva = pglist->kva; - + pages_list_put(pglist); return 0; } @@ -624,52 +729,31 @@ static int habmem_imp_hyp_map_uva(void *imp_ctx, uint32_t userflags, uint64_t *index) { - struct page **pages; - struct compressed_pfns *pfn_table = - (struct compressed_pfns *)exp->payload; struct pages_list *pglist; struct importer_context *priv = imp_ctx; - unsigned long pfn; - int i, j, k = 0, size; - if (!pfn_table || !priv) + if (!priv) return -EINVAL; - size = exp->payload_count * sizeof(struct page *); - pages = kmalloc(size, GFP_KERNEL); - if (!pages) - return -ENOMEM; - pglist = kzalloc(sizeof(*pglist), GFP_KERNEL); - if (!pglist) { - kfree(pages); - return -ENOMEM; - } + pglist = pages_list_lookup(priv, exp->export_id, exp->pchan); + if (pglist) + goto buffer_ready; - pfn = pfn_table->first_pfn; - for (i = 0; i < pfn_table->nregions; i++) { - for (j = 0; j < pfn_table->region[i].size; j++) { - pages[k] = pfn_to_page(pfn+j); - k++; - } - pfn += pfn_table->region[i].size + pfn_table->region[i].space; - } + pglist = pages_list_create(imp_ctx, exp, userflags); + if (IS_ERR(pglist)) + return PTR_ERR(pglist); - pglist->pages = pages; - pglist->npages = exp->payload_count; - pglist->index = page_to_phys(pages[0]) >> PAGE_SHIFT; - pglist->refcntk = pglist->refcntu = 0; - pglist->userflags = userflags; - pglist->export_id = exp->export_id; - pglist->vcid = exp->vcid_remote; - pglist->pchan = exp->pchan; + pages_list_add(priv, pglist); - write_lock(&priv->implist_lock); - list_add_tail(&pglist->list, &priv->imp_list); - priv->cnt++; - write_unlock(&priv->implist_lock); +buffer_ready: + if (pglist->index) + goto proc_end; - *index = pglist->index << PAGE_SHIFT; + pglist->index = page_to_phys(pglist->pages[0]) >> PAGE_SHIFT; +proc_end: + *index = pglist->index << PAGE_SHIFT; + pages_list_put(pglist); return 0; } @@ -697,37 +781,17 @@ int habmem_imp_hyp_map(void *imp_ctx, struct hab_import *param, int habmm_imp_hyp_unmap(void *imp_ctx, struct export_desc *exp, int kernel) { struct importer_context *priv = imp_ctx; - struct pages_list *pglist, *tmp; - int found = 0; - - write_lock(&priv->implist_lock); - list_for_each_entry_safe(pglist, tmp, &priv->imp_list, list) { - if (pglist->export_id == exp->export_id && - pglist->pchan == exp->pchan) { - found = 1; - list_del(&pglist->list); - priv->cnt--; - break; - } - } - write_unlock(&priv->implist_lock); + struct pages_list *pglist; - if (!found) { + pglist = pages_list_lookup(priv, exp->export_id, exp->pchan); + if (!pglist) { pr_err("failed to find export id %u\n", exp->export_id); return -EINVAL; } - pr_debug("detach pglist %p, kernel %d, list cnt %d\n", - pglist, pglist->kernel, priv->cnt); + pages_list_remove(priv, pglist); - if (pglist->kva) - vunmap(pglist->kva); - - if (pglist->dmabuf) - dma_buf_put(pglist->dmabuf); - - kfree(pglist->pages); - kfree(pglist); + pages_list_put(pglist); return 0; } @@ -739,12 +803,14 @@ int habmem_imp_hyp_mmap(struct file *filp, struct vm_area_struct *vma) long length = vma->vm_end - vma->vm_start; struct pages_list *pglist; int bfound = 0; + int ret = 0; read_lock(&imp_ctx->implist_lock); list_for_each_entry(pglist, &imp_ctx->imp_list, list) { if ((pglist->index == vma->vm_pgoff) && ((length <= pglist->npages * PAGE_SIZE))) { bfound = 1; + pages_list_get(pglist); break; } } @@ -758,7 +824,8 @@ int habmem_imp_hyp_mmap(struct file *filp, struct vm_area_struct *vma) if (length > pglist->npages * PAGE_SIZE) { pr_err("Error vma length %ld not matching page list %ld\n", length, pglist->npages * PAGE_SIZE); - return -EINVAL; + ret = -EINVAL; + goto proc_end; } vma->vm_ops = &habmem_vm_ops; @@ -769,6 +836,10 @@ int habmem_imp_hyp_mmap(struct file *filp, struct vm_area_struct *vma) vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot); return 0; + +proc_end: + pages_list_put(pglist); + return ret; } int habmm_imp_hyp_map_check(void *imp_ctx, struct export_desc *exp) @@ -777,15 +848,11 @@ int habmm_imp_hyp_map_check(void *imp_ctx, struct export_desc *exp) struct pages_list *pglist; int found = 0; - read_lock(&priv->implist_lock); - list_for_each_entry(pglist, &priv->imp_list, list) { - if (pglist->export_id == exp->export_id && - pglist->pchan == exp->pchan) { - found = 1; - break; - } + pglist = pages_list_lookup(priv, exp->export_id, exp->pchan); + if (pglist) { + found = 1; + pages_list_put(pglist); } - read_unlock(&priv->implist_lock); return found; } diff --git a/drivers/soc/qcom/hab/hab_mimex.c b/drivers/soc/qcom/hab/hab_mimex.c index d5786170f0f3..00c6c475fa92 100644 --- a/drivers/soc/qcom/hab/hab_mimex.c +++ b/drivers/soc/qcom/hab/hab_mimex.c @@ -124,8 +124,11 @@ void habmem_remove_export(struct export_desc *exp) struct uhab_context *ctx; if (!exp || !exp->ctx || !exp->pchan) { - pr_err("failed to find valid info in exp %pK ctx %pK pchan %pK\n", + if (exp) + pr_err("invalid info in exp %pK ctx %pK pchan %pK\n", exp, exp->ctx, exp->pchan); + else + pr_err("invalid exp\n"); return; } diff --git a/drivers/soc/qcom/hab/hab_msg.c b/drivers/soc/qcom/hab/hab_msg.c index 3765623d3190..61e658954312 100644 --- a/drivers/soc/qcom/hab/hab_msg.c +++ b/drivers/soc/qcom/hab/hab_msg.c @@ -76,8 +76,9 @@ hab_msg_dequeue(struct virtual_channel *vchan, struct hab_message **msg, ret = 0; *rsize = message->sizebytes; } else { - pr_err("rcv buffer too small %d < %zd\n", - *rsize, message->sizebytes); + pr_err("vcid %x rcv buf too small %d < %zd\n", + vchan->id, *rsize, + message->sizebytes); *rsize = message->sizebytes; message = NULL; ret = -EOVERFLOW; /* come back again */ @@ -281,7 +282,13 @@ int hab_msg_recv(struct physical_channel *pchan, break; } - exp_desc->domid_local = pchan->dom_id; + if (pchan->vmid_local != exp_desc->domid_remote || + pchan->vmid_remote != exp_desc->domid_local) + pr_err("corrupted vmid %d != %d %d != %d\n", + pchan->vmid_local, exp_desc->domid_remote, + pchan->vmid_remote, exp_desc->domid_local); + exp_desc->domid_remote = pchan->vmid_remote; + exp_desc->domid_local = pchan->vmid_local; exp_desc->pchan = pchan; hab_export_enqueue(vchan, exp_desc); diff --git a/drivers/soc/qcom/hab/hab_open.c b/drivers/soc/qcom/hab/hab_open.c index f740a43c1973..f09a1df8aa57 100644 --- a/drivers/soc/qcom/hab/hab_open.c +++ b/drivers/soc/qcom/hab/hab_open.c @@ -152,10 +152,13 @@ int hab_open_listen(struct uhab_context *ctx, ret = wait_event_interruptible_timeout(dev->openq, hab_open_request_find(ctx, dev, listen, recv_request), ms_timeout); - if (!ret || (-ERESTARTSYS == ret)) { + if (!ret) { + pr_debug("%s timeout in open listen\n", dev->name); + ret = -EAGAIN; /* condition not met */ + } else if (-ERESTARTSYS == ret) { pr_warn("something failed in open listen ret %d\n", ret); - ret = -EAGAIN; /* condition not met */ + ret = -EINTR; /* condition not met */ } else if (ret > 0) ret = 0; /* condition met */ } else { /* fe case */ diff --git a/drivers/soc/qcom/hab/hab_vchan.c b/drivers/soc/qcom/hab/hab_vchan.c index e42b27f5048d..8d818b8fafb1 100644 --- a/drivers/soc/qcom/hab/hab_vchan.c +++ b/drivers/soc/qcom/hab/hab_vchan.c @@ -87,7 +87,6 @@ hab_vchan_free(struct kref *ref) /* the release vchan from ctx was done earlier in vchan close() */ hab_ctx_put(ctx); /* now ctx is not needed from this vchan's view */ - vchan->ctx = NULL; /* release vchan from pchan. no more msg for this vchan */ write_lock_bh(&pchan->vchans_lock); @@ -144,6 +143,13 @@ hab_vchan_get(struct physical_channel *pchan, struct hab_header *header) get_refcnt(vchan->refcount), payload_type, sizebytes); vchan = NULL; + } else if (vchan->otherend_closed || vchan->closed) { + pr_err("closed already remote %d local %d vcid %x remote %x session %d refcnt %d header %x session %d type %d sz %zd\n", + vchan->otherend_closed, vchan->closed, + vchan->id, vchan->otherend_id, + vchan->session_id, get_refcnt(vchan->refcount), + vchan_id, session_id, payload_type, sizebytes); + vchan = NULL; } else if (!kref_get_unless_zero(&vchan->refcount)) { /* * this happens when refcnt is already zero @@ -154,13 +160,6 @@ hab_vchan_get(struct physical_channel *pchan, struct hab_header *header) vchan->session_id, get_refcnt(vchan->refcount), vchan_id, session_id, payload_type, sizebytes); vchan = NULL; - } else if (vchan->otherend_closed || vchan->closed) { - pr_err("closed already remote %d local %d vcid %x remote %x session %d refcnt %d header %x session %d type %d sz %zd\n", - vchan->otherend_closed, vchan->closed, - vchan->id, vchan->otherend_id, - vchan->session_id, get_refcnt(vchan->refcount), - vchan_id, session_id, payload_type, sizebytes); - vchan = NULL; } } spin_unlock_bh(&pchan->vid_lock); @@ -173,7 +172,10 @@ void hab_vchan_stop(struct virtual_channel *vchan) if (vchan) { vchan->otherend_closed = 1; wake_up(&vchan->rx_queue); - wake_up_interruptible(&vchan->ctx->exp_wq); + if (vchan->ctx) + wake_up_interruptible(&vchan->ctx->exp_wq); + else + pr_err("NULL ctx for vchan %x\n", vchan->id); } } @@ -200,6 +202,18 @@ static int hab_vchans_per_pchan_empty(struct physical_channel *pchan) read_lock(&pchan->vchans_lock); empty = list_empty(&pchan->vchannels); + if (!empty) { + struct virtual_channel *vchan; + + list_for_each_entry(vchan, &pchan->vchannels, pnode) { + pr_err("vchan %pK id %x remote id %x session %d ref %d closed %d remote close %d\n", + vchan, vchan->id, vchan->otherend_id, + vchan->session_id, + get_refcnt(vchan->refcount), vchan->closed, + vchan->otherend_closed); + } + + } read_unlock(&pchan->vchans_lock); return empty; @@ -220,6 +234,8 @@ static int hab_vchans_empty(int vmid) if (!hab_vchans_per_pchan_empty(pchan)) { empty = 0; spin_unlock_bh(&hab_dev->pchan_lock); + pr_info("vmid %d %s's vchans are not closed\n", + vmid, pchan->name); break; } } @@ -239,7 +255,7 @@ void hab_vchans_empty_wait(int vmid) pr_info("waiting for GVM%d's sockets closure\n", vmid); while (!hab_vchans_empty(vmid)) - schedule(); + usleep_range(10000, 12000); pr_info("all of GVM%d's sockets are closed\n", vmid); } diff --git a/drivers/soc/qcom/qdsp6v2/audio-anc-dev-mgr.c b/drivers/soc/qcom/qdsp6v2/audio-anc-dev-mgr.c index 75b114e6905c..95562d2cbfad 100644 --- a/drivers/soc/qcom/qdsp6v2/audio-anc-dev-mgr.c +++ b/drivers/soc/qcom/qdsp6v2/audio-anc-dev-mgr.c @@ -53,8 +53,6 @@ struct anc_tdm_group_set_info { struct anc_dev_drv_info { uint32_t state; - uint32_t rpm; - uint32_t bypass_mode; uint32_t algo_module_id; }; @@ -311,52 +309,68 @@ static int anc_dev_port_stop(int32_t which_port) int msm_anc_dev_set_info(void *info_p, int32_t anc_cmd) { - int rc = 0; + int rc = -EINVAL; switch (anc_cmd) { - case ANC_CMD_RPM: { - struct audio_anc_rpm_info *rpm_info_p = - (struct audio_anc_rpm_info *)info_p; + case ANC_CMD_ALGO_MODULE: { + struct audio_anc_algo_module_info *module_info_p = + (struct audio_anc_algo_module_info *)info_p; + + rc = 0; if (this_anc_dev_info.state) - rc = anc_if_set_rpm( + rc = anc_if_set_algo_module_id( anc_port_cfg[ANC_DEV_PORT_ANC_SPKR].port_id, - rpm_info_p->rpm); + module_info_p->module_id); else - this_anc_dev_info.rpm = 0; + this_anc_dev_info.algo_module_id = + module_info_p->module_id; break; } - case ANC_CMD_BYPASS_MODE: { - struct audio_anc_bypass_mode *bypass_mode_p = - (struct audio_anc_bypass_mode *)info_p; - + case ANC_CMD_ALGO_CALIBRATION: { + rc = -EINVAL; if (this_anc_dev_info.state) - rc = anc_if_set_bypass_mode( + rc = anc_if_set_algo_module_cali_data( anc_port_cfg[ANC_DEV_PORT_ANC_SPKR].port_id, - bypass_mode_p->mode); + info_p); else - this_anc_dev_info.bypass_mode = bypass_mode_p->mode; + pr_err("%s: ANC is not running yet\n", + __func__); + break; + } + default: + pr_err("%s: ANC cmd wrong\n", + __func__); break; } - case ANC_CMD_ALGO_MODULE: { - struct audio_anc_algo_module_info *module_info_p = - (struct audio_anc_algo_module_info *)info_p; + return rc; +} + +int msm_anc_dev_get_info(void *info_p, int32_t anc_cmd) +{ + int rc = -EINVAL; + + switch (anc_cmd) { + case ANC_CMD_ALGO_CALIBRATION: { if (this_anc_dev_info.state) - rc = anc_if_set_algo_module_id( + rc = anc_if_get_algo_module_cali_data( anc_port_cfg[ANC_DEV_PORT_ANC_SPKR].port_id, - module_info_p->module_id); + info_p); else - this_anc_dev_info.algo_module_id = - module_info_p->module_id; + pr_err("%s: ANC is not running yet\n", + __func__); break; } + default: + pr_err("%s: ANC cmd wrong\n", + __func__); + break; } return rc; } - int msm_anc_dev_start(void) { int rc = 0; @@ -514,11 +528,6 @@ int msm_anc_dev_start(void) anc_port_cfg[ANC_DEV_PORT_ANC_SPKR].port_id, this_anc_dev_info.algo_module_id); - if (this_anc_dev_info.bypass_mode != 0) - rc = anc_if_set_bypass_mode( - anc_port_cfg[ANC_DEV_PORT_ANC_SPKR].port_id, - this_anc_dev_info.bypass_mode); - group_id = get_group_id_from_port_id( anc_port_cfg[ANC_DEV_PORT_ANC_SPKR].port_id); @@ -612,8 +621,6 @@ int msm_anc_dev_stop(void) this_anc_dev_info.state = 0; this_anc_dev_info.algo_module_id = 0; - this_anc_dev_info.rpm = 0; - this_anc_dev_info.bypass_mode = 0; pr_debug("%s: ANC devices stop successfully!\n", __func__); diff --git a/drivers/soc/qcom/qdsp6v2/audio_anc.c b/drivers/soc/qcom/qdsp6v2/audio_anc.c index 65c585886453..50cc255043df 100644 --- a/drivers/soc/qcom/qdsp6v2/audio_anc.c +++ b/drivers/soc/qcom/qdsp6v2/audio_anc.c @@ -44,17 +44,11 @@ static size_t get_user_anc_cmd_size(int32_t anc_cmd) case ANC_CMD_STOP: size = 0; break; - case ANC_CMD_RPM: - size = sizeof(struct audio_anc_rpm_info); - break; - case ANC_CMD_BYPASS_MODE: - size = sizeof(struct audio_anc_bypass_mode); - break; case ANC_CMD_ALGO_MODULE: size = sizeof(struct audio_anc_algo_module_info); break; case ANC_CMD_ALGO_CALIBRATION: - size = sizeof(struct audio_anc_algo_calibration_info); + size = sizeof(struct audio_anc_algo_calibration_header); break; default: pr_err("%s:Invalid anc cmd %d!", @@ -77,8 +71,6 @@ static int call_set_anc(int32_t anc_cmd, case ANC_CMD_STOP: ret = msm_anc_dev_stop(); break; - case ANC_CMD_RPM: - case ANC_CMD_BYPASS_MODE: case ANC_CMD_ALGO_MODULE: case ANC_CMD_ALGO_CALIBRATION: ret = msm_anc_dev_set_info(data, anc_cmd); @@ -98,7 +90,8 @@ static int call_get_anc(int32_t anc_cmd, int ret = 0; switch (anc_cmd) { - case ANC_CMD_RPM: + case ANC_CMD_ALGO_CALIBRATION: + ret = msm_anc_dev_get_info(data, anc_cmd); break; default: break; @@ -146,9 +139,9 @@ static long audio_anc_shared_ioctl(struct file *file, unsigned int cmd, pr_err("%s: Could not copy size value from user\n", __func__); ret = -EFAULT; goto done; - } else if (size < sizeof(struct audio_anc_packet)) { + } else if (size < sizeof(struct audio_anc_header)) { pr_err("%s: Invalid size sent to driver: %d, min size is %zd\n", - __func__, size, sizeof(struct audio_anc_packet)); + __func__, size, sizeof(struct audio_anc_header)); ret = -EINVAL; goto done; } diff --git a/drivers/soc/qcom/qdsp6v2/sdsp-anc.c b/drivers/soc/qcom/qdsp6v2/sdsp-anc.c index 9294485f7ff2..4e75bc89aa8f 100644 --- a/drivers/soc/qcom/qdsp6v2/sdsp-anc.c +++ b/drivers/soc/qcom/qdsp6v2/sdsp-anc.c @@ -38,7 +38,7 @@ struct anc_if_ctl { atomic_t status; wait_queue_head_t wait[AFE_MAX_PORTS]; struct task_struct *task; - struct anc_get_rpm_resp rpm_calib_data; + struct anc_get_algo_module_cali_data_resp cali_data_resp; uint32_t mmap_handle; struct mutex afe_cmd_lock; }; @@ -48,33 +48,23 @@ static struct anc_if_ctl this_anc_if; static int32_t anc_get_param_callback(uint32_t *payload, uint32_t payload_size) { - u32 param_id; - struct anc_get_rpm_resp *resp = - (struct anc_get_rpm_resp *) payload; - - if (!(&(resp->pdata))) { - pr_err("%s: Error: resp pdata is NULL\n", __func__); + if ((payload_size < (sizeof(uint32_t) + + sizeof(this_anc_if.cali_data_resp.pdata))) || + (payload_size > sizeof(this_anc_if.cali_data_resp))) { + pr_err("%s: Error: received size %d, calib_data size %zu\n", + __func__, payload_size, + sizeof(this_anc_if.cali_data_resp)); return -EINVAL; } - param_id = resp->pdata.param_id; - if (param_id == AUD_MSVC_PARAM_ID_PORT_ANC_ALGO_RPM) { - if (payload_size < sizeof(this_anc_if.rpm_calib_data)) { - pr_err("%s: Error: received size %d, calib_data size %zu\n", - __func__, payload_size, - sizeof(this_anc_if.rpm_calib_data)); - return -EINVAL; - } - - memcpy(&this_anc_if.rpm_calib_data, payload, - sizeof(this_anc_if.rpm_calib_data)); - if (!this_anc_if.rpm_calib_data.status) { - atomic_set(&this_anc_if.state, 0); - } else { - pr_debug("%s: calib resp status: %d", __func__, - this_anc_if.rpm_calib_data.status); - atomic_set(&this_anc_if.state, -1); - } + memcpy(&this_anc_if.cali_data_resp, payload, + payload_size); + if (!this_anc_if.cali_data_resp.status) { + atomic_set(&this_anc_if.state, 0); + } else { + pr_debug("%s: calib resp status: %d", __func__, + this_anc_if.cali_data_resp.status); + atomic_set(&this_anc_if.state, -1); } return 0; @@ -465,7 +455,7 @@ int anc_if_tdm_port_stop(u16 port_id) return anc_if_send_cmd_port_stop(port_id); } -int anc_if_set_rpm(u16 port_id, u32 rpm) +int anc_if_set_algo_module_id(u16 port_id, u32 module_id) { int ret = 0; int index; @@ -479,7 +469,7 @@ int anc_if_set_rpm(u16 port_id, u32 rpm) index = q6audio_get_port_index(port_id); { - struct anc_set_rpm_command config; + struct anc_set_algo_module_id_command config; memset(&config, 0, sizeof(config)); config.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD, @@ -496,16 +486,16 @@ int anc_if_set_rpm(u16 port_id, u32 rpm) config.param.payload_address_lsw = 0x00; config.param.payload_address_msw = 0x00; config.param.mem_map_handle = 0x00; - config.pdata.module_id = AUD_MSVC_MODULE_AUDIO_DEV_ANC_ALGO; - config.pdata.param_id = AUD_MSVC_PARAM_ID_PORT_ANC_ALGO_RPM; - config.pdata.param_size = sizeof(config.set_rpm); - config.set_rpm.minor_version = - AUD_MSVC_API_VERSION_DEV_ANC_ALGO_RPM; - config.set_rpm.rpm = rpm; + config.pdata.module_id = AFE_MODULE_AUDIO_DEV_INTERFACE; + config.pdata.param_id = + AUD_MSVC_PARAM_ID_PORT_ANC_ALGO_MODULE_ID; + config.pdata.param_size = sizeof(config.set_algo_module_id); + config.set_algo_module_id.minor_version = 1; + config.set_algo_module_id.module_id = module_id; ret = anc_if_apr_send_pkt(&config, &this_anc_if.wait[index]); if (ret) { - pr_err("%s: share resource for port 0x%x failed ret = %d\n", + pr_err("%s: anc algo module ID for port 0x%x failed ret = %d\n", __func__, port_id, ret); } } @@ -513,10 +503,10 @@ int anc_if_set_rpm(u16 port_id, u32 rpm) return ret; } -int anc_if_set_bypass_mode(u16 port_id, u32 bypass_mode) +int anc_if_set_anc_mic_spkr_layout(u16 port_id, +struct aud_msvc_param_id_dev_anc_mic_spkr_layout_info *set_mic_spkr_layout_p) { int ret = 0; - int index; ret = anc_sdsp_interface_prepare(); @@ -528,7 +518,7 @@ int anc_if_set_bypass_mode(u16 port_id, u32 bypass_mode) index = q6audio_get_port_index(port_id); { - struct anc_set_bypass_mode_command config; + struct anc_set_mic_spkr_layout_info_command config; memset(&config, 0, sizeof(config)); config.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD, @@ -545,17 +535,16 @@ int anc_if_set_bypass_mode(u16 port_id, u32 bypass_mode) config.param.payload_address_lsw = 0x00; config.param.payload_address_msw = 0x00; config.param.mem_map_handle = 0x00; - config.pdata.module_id = AUD_MSVC_MODULE_AUDIO_DEV_ANC_ALGO; + config.pdata.module_id = AFE_MODULE_AUDIO_DEV_INTERFACE; config.pdata.param_id = - AUD_MSVC_PARAM_ID_PORT_ANC_ALGO_BYPASS_MODE; - config.pdata.param_size = sizeof(config.set_bypass_mode); - config.set_bypass_mode.minor_version = - AUD_MSVC_API_VERSION_DEV_ANC_ALGO_BYPASS_MODE; - config.set_bypass_mode.bypass_mode = bypass_mode; + AUD_MSVC_PARAM_ID_PORT_ANC_MIC_SPKR_LAYOUT_INFO; + config.pdata.param_size = sizeof(config.set_mic_spkr_layout); + memcpy(&config.set_mic_spkr_layout, set_mic_spkr_layout_p, + sizeof(config.set_mic_spkr_layout)); ret = anc_if_apr_send_pkt(&config, &this_anc_if.wait[index]); if (ret) { - pr_err("%s: share resource for port 0x%x failed ret = %d\n", + pr_err("%s: anc algo module ID for port 0x%x failed ret = %d\n", __func__, port_id, ret); } } @@ -563,10 +552,10 @@ int anc_if_set_bypass_mode(u16 port_id, u32 bypass_mode) return ret; } -int anc_if_set_algo_module_id(u16 port_id, u32 module_id) + +int anc_if_set_algo_module_cali_data(u16 port_id, void *data_p) { int ret = 0; - int index; ret = anc_sdsp_interface_prepare(); @@ -578,45 +567,67 @@ int anc_if_set_algo_module_id(u16 port_id, u32 module_id) index = q6audio_get_port_index(port_id); { - struct anc_set_algo_module_id_command config; + struct anc_set_algo_module_cali_data_command *cali_data_cfg_p; + void *config_p = NULL; + int cmd_size = 0; + void *out_payload_p = NULL; + uint32_t *in_payload_p = (uint32_t *)data_p; + + uint32_t module_id = *in_payload_p; + uint32_t param_id = *(in_payload_p + 1); + uint32_t payload_size = *(in_payload_p + 2); + + cmd_size = sizeof(struct anc_set_algo_module_cali_data_command) + + payload_size; + config_p = kzalloc(cmd_size, GFP_KERNEL); + if (!config_p) { + ret = -ENOMEM; + return ret; + } - memset(&config, 0, sizeof(config)); - config.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD, + memset(config_p, 0, cmd_size); + out_payload_p = config_p + + sizeof(struct anc_set_algo_module_cali_data_command); + + cali_data_cfg_p = + (struct anc_set_algo_module_cali_data_command *)config_p; + + cali_data_cfg_p->hdr.hdr_field = + APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD, APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER); - config.hdr.pkt_size = sizeof(config); - config.hdr.src_port = 0; - config.hdr.dest_port = 0; - config.hdr.token = index; - config.hdr.opcode = AFE_PORT_CMD_SET_PARAM_V2; - config.param.port_id = q6audio_get_port_id(port_id); - config.param.payload_size = sizeof(config) - + cali_data_cfg_p->hdr.pkt_size = cmd_size; + cali_data_cfg_p->hdr.src_port = 0; + cali_data_cfg_p->hdr.dest_port = 0; + cali_data_cfg_p->hdr.token = index; + cali_data_cfg_p->hdr.opcode = AFE_PORT_CMD_SET_PARAM_V2; + cali_data_cfg_p->param.port_id = q6audio_get_port_id(port_id); + cali_data_cfg_p->param.payload_size = cmd_size - sizeof(struct apr_hdr) - - sizeof(config.param); - config.param.payload_address_lsw = 0x00; - config.param.payload_address_msw = 0x00; - config.param.mem_map_handle = 0x00; - config.pdata.module_id = AUD_MSVC_MODULE_AUDIO_DEV_ANC_ALGO; - config.pdata.param_id = - AUD_MSVC_PARAM_ID_PORT_ANC_ALGO_MODULE_ID; - config.pdata.param_size = sizeof(config.set_algo_module_id); - config.set_algo_module_id.minor_version = 1; - config.set_algo_module_id.module_id = module_id; + sizeof(struct aud_msvc_port_cmd_set_param_v2); + cali_data_cfg_p->param.payload_address_lsw = 0x00; + cali_data_cfg_p->param.payload_address_msw = 0x00; + cali_data_cfg_p->param.mem_map_handle = 0x00; + cali_data_cfg_p->pdata.module_id = module_id; + cali_data_cfg_p->pdata.param_id = param_id; + cali_data_cfg_p->pdata.param_size = payload_size; + + memcpy(out_payload_p, (in_payload_p + 3), payload_size); + + ret = anc_if_apr_send_pkt(cali_data_cfg_p, + &this_anc_if.wait[index]); + if (ret) + pr_err("%s: anc algo module calibration data for port 0x%x failed ret = %d\n", + __func__, port_id, ret); - ret = anc_if_apr_send_pkt(&config, &this_anc_if.wait[index]); - if (ret) { - pr_err("%s: anc algo module ID for port 0x%x failed ret = %d\n", - __func__, port_id, ret); - } + kfree(config_p); } return ret; } -int anc_if_set_anc_mic_spkr_layout(u16 port_id, -struct aud_msvc_param_id_dev_anc_mic_spkr_layout_info *set_mic_spkr_layout_p) +int anc_if_get_algo_module_cali_data(u16 port_id, void *data_p) { int ret = 0; - int index; ret = anc_sdsp_interface_prepare(); @@ -628,35 +639,68 @@ struct aud_msvc_param_id_dev_anc_mic_spkr_layout_info *set_mic_spkr_layout_p) index = q6audio_get_port_index(port_id); { - struct anc_set_mic_spkr_layout_info_command config; + struct anc_get_algo_module_cali_data_command *cali_data_cfg_p; + void *config_p = NULL; + int cmd_size = 0; + void *out_payload_p = NULL; + uint32_t *in_payload_p = (uint32_t *)data_p; + + uint32_t module_id = *in_payload_p; + uint32_t param_id = *(in_payload_p + 1); + uint32_t payload_size = *(in_payload_p + 2); + + cmd_size = sizeof(struct anc_get_algo_module_cali_data_command) + + payload_size; + config_p = kzalloc(cmd_size, GFP_KERNEL); + if (!config_p) { + ret = -ENOMEM; + return ret; + } - memset(&config, 0, sizeof(config)); - config.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD, + memset(config_p, 0, cmd_size); + out_payload_p = config_p + + sizeof(struct anc_set_algo_module_cali_data_command); + + cali_data_cfg_p = + (struct anc_get_algo_module_cali_data_command *)config_p; + + cali_data_cfg_p->hdr.hdr_field = + APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD, APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER); - config.hdr.pkt_size = sizeof(config); - config.hdr.src_port = 0; - config.hdr.dest_port = 0; - config.hdr.token = index; - config.hdr.opcode = AFE_PORT_CMD_SET_PARAM_V2; - config.param.port_id = q6audio_get_port_id(port_id); - config.param.payload_size = sizeof(config) - + cali_data_cfg_p->hdr.pkt_size = cmd_size; + cali_data_cfg_p->hdr.src_port = 0; + cali_data_cfg_p->hdr.dest_port = 0; + cali_data_cfg_p->hdr.token = index; + cali_data_cfg_p->hdr.opcode = AFE_PORT_CMD_GET_PARAM_V2; + cali_data_cfg_p->param.port_id = q6audio_get_port_id(port_id); + cali_data_cfg_p->param.payload_size = cmd_size - sizeof(struct apr_hdr) - - sizeof(config.param); - config.param.payload_address_lsw = 0x00; - config.param.payload_address_msw = 0x00; - config.param.mem_map_handle = 0x00; - config.pdata.module_id = AUD_MSVC_MODULE_AUDIO_DEV_ANC_ALGO; - config.pdata.param_id = - AUD_MSVC_PARAM_ID_PORT_ANC_MIC_SPKR_LAYOUT_INFO; - config.pdata.param_size = sizeof(config.set_mic_spkr_layout); - - memcpy(&config.set_mic_spkr_layout, set_mic_spkr_layout_p, - sizeof(config.set_mic_spkr_layout)); - ret = anc_if_apr_send_pkt(&config, &this_anc_if.wait[index]); - if (ret) { - pr_err("%s: anc algo module ID for port 0x%x failed ret = %d\n", + sizeof(struct aud_msvc_port_cmd_get_param_v2); + cali_data_cfg_p->param.payload_address_lsw = 0x00; + cali_data_cfg_p->param.payload_address_msw = 0x00; + cali_data_cfg_p->param.mem_map_handle = 0x00; + cali_data_cfg_p->param.module_id = module_id; + cali_data_cfg_p->param.param_id = param_id; + cali_data_cfg_p->pdata.param_size = 0; + cali_data_cfg_p->pdata.module_id = 0; + cali_data_cfg_p->pdata.param_id = 0; + + ret = anc_if_apr_send_pkt(cali_data_cfg_p, + &this_anc_if.wait[index]); + if (ret) + pr_err("%s: anc algo module calibration data for port 0x%x failed ret = %d\n", __func__, port_id, ret); - } + + memcpy((in_payload_p + 3), + &this_anc_if.cali_data_resp.payload[0], payload_size); + + *in_payload_p = this_anc_if.cali_data_resp.pdata.module_id; + *(in_payload_p + 1) = + this_anc_if.cali_data_resp.pdata.param_id; + *(in_payload_p + 2) = + this_anc_if.cali_data_resp.pdata.param_size; + + kfree(config_p); } return ret; @@ -700,7 +744,6 @@ int anc_if_cmd_memory_map(int port_id, phys_addr_t dma_addr_p, mmap_region_cmd = kzalloc(cmd_size, GFP_KERNEL); if (!mmap_region_cmd) { ret = -ENOMEM; - pr_err("%s: allocate mmap_region_cmd failed\n", __func__); return ret; } diff --git a/drivers/soc/qcom/subsystem_notif_virt.c b/drivers/soc/qcom/subsystem_notif_virt.c index f8ce53cfa9f7..5c9acf7e4563 100644 --- a/drivers/soc/qcom/subsystem_notif_virt.c +++ b/drivers/soc/qcom/subsystem_notif_virt.c @@ -43,7 +43,7 @@ struct subsystem_descriptor { enum subsystem_type type; struct notifier_block nb; void *handle; - unsigned int ssr_irq; + int ssr_irq; struct list_head subsystem_list; struct work_struct work; }; @@ -91,7 +91,7 @@ static int subsys_notif_virt_probe(struct platform_device *pdev) struct device_node *child = NULL; const char *ss_type; struct resource *res; - struct subsystem_descriptor *subsystem; + struct subsystem_descriptor *subsystem = NULL; int ret = 0; if (!pdev) { @@ -193,7 +193,8 @@ static int subsys_notif_virt_probe(struct platform_device *pdev) } } - INIT_WORK(&subsystem->work, subsystem_notif_wq_func); + if (subsystem) + INIT_WORK(&subsystem->work, subsystem_notif_wq_func); return 0; err: destroy_workqueue(ssr_wq); diff --git a/drivers/usb/misc/Kconfig b/drivers/usb/misc/Kconfig index 4670e2f4c2de..278df845f066 100644 --- a/drivers/usb/misc/Kconfig +++ b/drivers/usb/misc/Kconfig @@ -279,13 +279,24 @@ config USB_QTI_KS_BRIDGE To compile this driver as a module, choose M here: the module will be called ks_bridge. If unsure, choose N. +config USB_QCOM_IPC_BRIDGE + tristate "USB QTI IPC bridge driver" + depends on USB + depends on USB_QCOM_DIAG_BRIDGE + help + Say Y here if you have a QTI modem device connected via USB that + will be bridged in kernel space. This driver works as a transport + layer for IPC router module that enables communication between + APPS processor and MODEM processor. + config USB_QCOM_DIAG_BRIDGE tristate "USB QTI diagnostic bridge driver" depends on USB + select USB_QCOM_IPC_BRIDGE help Say Y here if you have a QTI modem device connected via USB that will be bridged in kernel space. This driver communicates with the - diagnostic and QMI interfaces and allows for bridging with the diag - forwarding driver for diag interface and IPC router for QMI interface. + diagnostic interface and allows for bridging with the diag forwarding + driver. To compile this driver as a module, choose M here: the module will be called diag_bridge. If unsure, choose N. diff --git a/drivers/video/fbdev/msm/mdss_dsi.c b/drivers/video/fbdev/msm/mdss_dsi.c index 0d41f41371dd..69b9149cd750 100644 --- a/drivers/video/fbdev/msm/mdss_dsi.c +++ b/drivers/video/fbdev/msm/mdss_dsi.c @@ -2043,10 +2043,9 @@ static void __mdss_dsi_calc_dfps_delay(struct mdss_panel_data *pdata) } static int __mdss_dsi_dfps_calc_clks(struct mdss_panel_data *pdata, - int new_fps) + u64 new_clk_rate) { int rc = 0; - u64 clk_rate; struct mdss_dsi_ctrl_pdata *ctrl_pdata = NULL; struct mdss_panel_info *pinfo; u32 phy_rev; @@ -2066,14 +2065,9 @@ static int __mdss_dsi_dfps_calc_clks(struct mdss_panel_data *pdata, pinfo = &pdata->panel_info; phy_rev = ctrl_pdata->shared_data->phy_rev; - rc = mdss_dsi_clk_div_config - (&ctrl_pdata->panel_data.panel_info, new_fps); - if (rc) { - pr_err("%s: unable to initialize the clk dividers\n", - __func__); - return rc; - } - + pinfo->clk_rate = new_clk_rate; + pinfo->mipi.dsi_pclk_rate = mdss_dsi_get_pclk_rate(pinfo, + new_clk_rate); __mdss_dsi_dyn_refresh_config(ctrl_pdata); if (phy_rev == DSI_PHY_REV_20) @@ -2086,9 +2080,8 @@ static int __mdss_dsi_dfps_calc_clks(struct mdss_panel_data *pdata, ctrl_pdata->byte_clk_rate_bkp = ctrl_pdata->byte_clk_rate; ctrl_pdata->pclk_rate = pinfo->mipi.dsi_pclk_rate; - clk_rate = pinfo->clk_rate; - do_div(clk_rate, 8U); - ctrl_pdata->byte_clk_rate = (u32) clk_rate; + do_div(new_clk_rate, 8U); + ctrl_pdata->byte_clk_rate = (u32) new_clk_rate; pr_debug("byte_rate=%i\n", ctrl_pdata->byte_clk_rate); pr_debug("pclk_rate=%i\n", ctrl_pdata->pclk_rate); @@ -2096,8 +2089,7 @@ static int __mdss_dsi_dfps_calc_clks(struct mdss_panel_data *pdata, return rc; } -static int __mdss_dsi_dfps_update_clks(struct mdss_panel_data *pdata, - int new_fps) +static int __mdss_dsi_dfps_update_clks(struct mdss_panel_data *pdata) { struct mdss_dsi_ctrl_pdata *ctrl_pdata = NULL; struct mdss_dsi_ctrl_pdata *sctrl_pdata = NULL; @@ -2248,12 +2240,6 @@ static int __mdss_dsi_dfps_update_clks(struct mdss_panel_data *pdata, clk_disable_unprepare(ctrl_pdata->pll_byte_clk); clk_disable_unprepare(ctrl_pdata->pll_pixel_clk); - /* update new fps that at this point is already updated in hw */ - pinfo->current_fps = new_fps; - if (sctrl_pdata) { - spinfo->current_fps = new_fps; - } - return rc; dfps_timeout: @@ -2330,13 +2316,65 @@ static void mdss_dsi_avr_config(struct mdss_dsi_ctrl_pdata *ctrl_pdata, MDSS_XLOG(ctrl_pdata->ndx, enabled, data); } -static int mdss_dsi_dfps_config(struct mdss_panel_data *pdata, int new_fps) +static int __mdss_dsi_dynamic_clock_switch(struct mdss_panel_data *pdata, + u64 new_clk_rate) { int rc = 0; struct mdss_dsi_ctrl_pdata *ctrl_pdata = NULL; struct mdss_panel_info *pinfo; u32 phy_rev; - u32 frame_rate_bkp; + u64 clk_rate_bkp; + + pr_debug("%s+:\n", __func__); + + ctrl_pdata = container_of(pdata, struct mdss_dsi_ctrl_pdata, + panel_data); + + phy_rev = ctrl_pdata->shared_data->phy_rev; + pinfo = &pdata->panel_info; + + /* get the fps configured in HW */ + clk_rate_bkp = pinfo->clk_rate; + + __mdss_dsi_mask_dfps_errors(ctrl_pdata, true); + + if (phy_rev == DSI_PHY_REV_20) { + rc = mdss_dsi_phy_calc_timing_param(pinfo, phy_rev, + new_clk_rate); + if (rc) { + pr_err("PHY calculations failed-%lld\n", new_clk_rate); + goto end_update; + } + } + + rc = __mdss_dsi_dfps_calc_clks(pdata, new_clk_rate); + if (rc) { + pr_err("error calculating clocks for %lld\n", new_clk_rate); + goto error_clks; + } + + rc = __mdss_dsi_dfps_update_clks(pdata); + if (rc) { + pr_err("Dynamic refresh failed-%lld\n", new_clk_rate); + goto error_dfps; + } + return rc; +error_dfps: + if (__mdss_dsi_dfps_calc_clks(pdata, clk_rate_bkp)) + pr_err("error reverting clock calculations for %lld\n", + clk_rate_bkp); +error_clks: + if (mdss_dsi_phy_calc_timing_param(pinfo, phy_rev, clk_rate_bkp)) + pr_err("Unable to revert phy timing-%lld\n", clk_rate_bkp); +end_update: + return rc; +} + +static int mdss_dsi_dfps_config(struct mdss_panel_data *pdata, int new_fps) +{ + int rc = 0; + struct mdss_dsi_ctrl_pdata *ctrl_pdata = NULL; + struct mdss_panel_info *pinfo; pr_debug("%s+:\n", __func__); @@ -2353,12 +2391,8 @@ static int mdss_dsi_dfps_config(struct mdss_panel_data *pdata, int new_fps) return -EINVAL; } - phy_rev = ctrl_pdata->shared_data->phy_rev; pinfo = &pdata->panel_info; - /* get the fps configured in HW */ - frame_rate_bkp = pinfo->current_fps; - if (new_fps == pinfo->current_fps) { /* * This is unlikely as mdss driver checks for previously @@ -2374,39 +2408,45 @@ static int mdss_dsi_dfps_config(struct mdss_panel_data *pdata, int new_fps) __mdss_dsi_update_video_mode_total(pdata, new_fps); } else if (pinfo->dfps_update == DFPS_IMMEDIATE_CLK_UPDATE_MODE) { /* Clock update method */ + u64 new_clk_rate = mdss_dsi_calc_bitclk + (&ctrl_pdata->panel_data.panel_info, new_fps); + if (!new_clk_rate) { + pr_err("%s: unable to get the new bit clock rate\n", + __func__); + rc = -EINVAL; + goto end_update; + } - __mdss_dsi_mask_dfps_errors(ctrl_pdata, true); + rc = __mdss_dsi_dynamic_clock_switch(pdata, new_clk_rate); + if (!rc) { + struct mdss_dsi_ctrl_pdata *mctrl_pdata = NULL; + struct mdss_panel_info *mpinfo = NULL; - if (phy_rev == DSI_PHY_REV_20) { - rc = mdss_dsi_phy_calc_timing_param(pinfo, phy_rev, - new_fps); - if (rc) { - pr_err("PHY calculations failed-%d\n", new_fps); + if (mdss_dsi_is_hw_config_split + (ctrl_pdata->shared_data) && + mdss_dsi_is_ctrl_clk_master(ctrl_pdata)) goto end_update; - } - } - rc = __mdss_dsi_dfps_calc_clks(pdata, new_fps); - if (rc) { - pr_err("error calculating clocks for %d\n", new_fps); - goto error_clks; - } + if (mdss_dsi_is_hw_config_split + (ctrl_pdata->shared_data) && + mdss_dsi_is_ctrl_clk_slave(ctrl_pdata)) { + mctrl_pdata = mdss_dsi_get_ctrl_clk_master(); + if (IS_ERR_OR_NULL(mctrl_pdata)) { + pr_err("Invalid mctrl_pdata\n"); + goto end_update; + } - rc = __mdss_dsi_dfps_update_clks(pdata, new_fps); - if (rc) { - pr_err("Dynamic refresh failed-%d\n", new_fps); - goto error_dfps; + mpinfo = &mctrl_pdata->panel_data.panel_info; + } + /* + * update new fps that at this point is already + * updated in hw + */ + pinfo->current_fps = new_fps; + if (mctrl_pdata && mpinfo) + mpinfo->current_fps = new_fps; } } - - return rc; -error_dfps: - if (__mdss_dsi_dfps_calc_clks(pdata, frame_rate_bkp)) - pr_err("error reverting clock calculations for %d\n", - frame_rate_bkp); -error_clks: - if (mdss_dsi_phy_calc_timing_param(pinfo, phy_rev, frame_rate_bkp)) - pr_err("Unable to revert phy timing-%d\n", frame_rate_bkp); end_update: return rc; } @@ -2678,6 +2718,163 @@ static void mdss_dsi_timing_db_ctrl(struct mdss_dsi_ctrl_pdata *ctrl, MDSS_DSI_CORE_CLK, MDSS_DSI_CLK_OFF); } +static struct mdss_dsi_ctrl_pdata *mdss_dsi_get_drvdata(struct device *dev) +{ + struct msm_fb_data_type *mfd; + struct mdss_panel_data *pdata; + struct mdss_dsi_ctrl_pdata *ctrl_pdata = NULL; + struct fb_info *fbi = dev_get_drvdata(dev); + + if (fbi) { + mfd = (struct msm_fb_data_type *)fbi->par; + pdata = dev_get_platdata(&mfd->pdev->dev); + + ctrl_pdata = container_of(pdata, + struct mdss_dsi_ctrl_pdata, panel_data); + } + + return ctrl_pdata; +} + +static ssize_t supp_bitclk_list_sysfs_rda(struct device *dev, + struct device_attribute *attr, char *buf) +{ + ssize_t ret = 0; + int i = 0; + struct mdss_dsi_ctrl_pdata *ctrl_pdata = mdss_dsi_get_drvdata(dev); + struct mdss_panel_info *pinfo = NULL; + + if (!ctrl_pdata) { + pr_err("%s: invalid input\n", __func__); + return -EINVAL; + } + + pinfo = &ctrl_pdata->panel_data.panel_info; + if (!pinfo) { + pr_err("no panel connected\n"); + return -ENODEV; + } + + if (!pinfo->dynamic_bitclk) { + pr_err_once("%s: Dynamic bitclk not enabled for this panel\n", + __func__); + return -EINVAL; + } + + buf[0] = 0; + for (i = 0; i < pinfo->supp_bitclk_len; i++) { + if (ret > 0) + ret += scnprintf(buf + ret, PAGE_SIZE - ret, + ",%d", pinfo->supp_bitclks[i]); + else + ret += scnprintf(buf + ret, PAGE_SIZE - ret, + "%d", pinfo->supp_bitclks[i]); + } + + ret += scnprintf(buf + ret, PAGE_SIZE - ret, "\n"); + + return ret; +} + +static ssize_t dynamic_bitclk_sysfs_wta(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + int rc = 0, i = 0; + struct mdss_dsi_ctrl_pdata *ctrl_pdata = mdss_dsi_get_drvdata(dev); + struct mdss_panel_info *pinfo = NULL; + int clk_rate = 0; + + if (!ctrl_pdata) { + pr_err("%s: invalid input\n", __func__); + return -EINVAL; + } + + pinfo = &ctrl_pdata->panel_data.panel_info; + if (!pinfo) { + pr_err("no panel connected\n"); + return -ENODEV; + } + + if (!pinfo->dynamic_bitclk) { + pr_err_once("%s: Dynamic bitclk not enabled for this panel\n", + __func__); + return -EINVAL; + } + + if (mdss_panel_is_power_off(pinfo->panel_power_state)) { + pr_err_once("%s: Panel powered off!\n", __func__); + return -EINVAL; + } + + rc = kstrtoint(buf, 10, &clk_rate); + if (rc) { + pr_err("%s: kstrtoint failed. rc=%d\n", __func__, rc); + return rc; + } + + for (i = 0; i < pinfo->supp_bitclk_len; i++) { + if (pinfo->supp_bitclks[i] == clk_rate) + break; + } + if (i == pinfo->supp_bitclk_len) { + pr_err("Requested bitclk: %d not supported\n", clk_rate); + return -EINVAL; + } + + rc = __mdss_dsi_dynamic_clock_switch(&ctrl_pdata->panel_data, + clk_rate); + if (!rc && mdss_dsi_is_hw_config_split(ctrl_pdata->shared_data)) { + struct mdss_dsi_ctrl_pdata *octrl = + mdss_dsi_get_other_ctrl(ctrl_pdata); + rc = __mdss_dsi_dynamic_clock_switch(&octrl->panel_data, + clk_rate); + if (rc) + pr_err("failed to switch DSI bitclk for sctrl\n"); + } else if (rc) { + pr_err("failed to switch DSI bitclk\n"); + } + + return count; +} /* dynamic_bitclk_sysfs_wta */ + +static ssize_t dynamic_bitclk_sysfs_rda(struct device *dev, + struct device_attribute *attr, char *buf) +{ + ssize_t ret; + struct mdss_dsi_ctrl_pdata *ctrl_pdata = mdss_dsi_get_drvdata(dev); + struct mdss_panel_info *pinfo = NULL; + + if (!ctrl_pdata) { + pr_err("%s: invalid input\n", __func__); + return -EINVAL; + } + + pinfo = &ctrl_pdata->panel_data.panel_info; + if (!pinfo) { + pr_err("no panel connected\n"); + return -ENODEV; + } + + ret = snprintf(buf, PAGE_SIZE, "%llu\n", pinfo->clk_rate); + pr_debug("%s: '%llu'\n", __func__, pinfo->clk_rate); + + return ret; +} /* dynamic_bitclk_sysfs_rda */ + +static DEVICE_ATTR(dynamic_bitclk, S_IRUGO | S_IWUSR | S_IWGRP, + dynamic_bitclk_sysfs_rda, dynamic_bitclk_sysfs_wta); +static DEVICE_ATTR(supported_bitclk, S_IRUGO, supp_bitclk_list_sysfs_rda, NULL); + +static struct attribute *dynamic_bitclk_fs_attrs[] = { + &dev_attr_dynamic_bitclk.attr, + &dev_attr_supported_bitclk.attr, + NULL, +}; + +static struct attribute_group mdss_dsi_fs_attrs_group = { + .attrs = dynamic_bitclk_fs_attrs, +}; + static int mdss_dsi_event_handler(struct mdss_panel_data *pdata, int event, void *arg) { @@ -2844,6 +3041,14 @@ static int mdss_dsi_event_handler(struct mdss_panel_data *pdata, ctrl_pdata->kobj = &fbi->dev->kobj; ctrl_pdata->fb_node = fbi->node; + if (!mdss_dsi_is_hw_config_split(ctrl_pdata->shared_data) || + (mdss_dsi_is_hw_config_split(ctrl_pdata->shared_data) && + mdss_dsi_is_ctrl_clk_master(ctrl_pdata))) { + if (sysfs_create_group(&fbi->dev->kobj, + &mdss_dsi_fs_attrs_group)) + pr_err("failed to create DSI sysfs group\n"); + } + if (IS_ENABLED(CONFIG_MSM_DBA) && pdata->panel_info.is_dba_panel) { queue_delayed_work(ctrl_pdata->workq, @@ -3392,7 +3597,7 @@ static int mdss_dsi_ctrl_probe(struct platform_device *pdev) pinfo = &(ctrl_pdata->panel_data.panel_info); if (!(mdss_dsi_is_hw_config_split(ctrl_pdata->shared_data) && mdss_dsi_is_ctrl_clk_slave(ctrl_pdata)) && - pinfo->dynamic_fps) { + (pinfo->dynamic_fps || pinfo->dynamic_bitclk)) { rc = mdss_dsi_shadow_clk_init(pdev, ctrl_pdata); if (rc) { @@ -4359,11 +4564,19 @@ int dsi_panel_device_register(struct platform_device *ctrl_pdev, ((mipi->mode == DSI_VIDEO_MODE) ? MIPI_VIDEO_PANEL : MIPI_CMD_PANEL); - rc = mdss_dsi_clk_div_config(pinfo, mipi->frame_rate); - if (rc) { - pr_err("%s: unable to initialize the clk dividers\n", __func__); - return rc; + pinfo->clk_rate = mdss_dsi_calc_bitclk(pinfo, mipi->frame_rate); + if (!pinfo->clk_rate) { + pr_err("%s: unable to calculate the DSI bit clock\n", __func__); + return -EINVAL; } + + pinfo->mipi.dsi_pclk_rate = mdss_dsi_get_pclk_rate(pinfo, + pinfo->clk_rate); + if (!pinfo->mipi.dsi_pclk_rate) { + pr_err("%s: unable to calculate the DSI pclk\n", __func__); + return -EINVAL; + } + ctrl_pdata->pclk_rate = mipi->dsi_pclk_rate; clk_rate = pinfo->clk_rate; do_div(clk_rate, 8U); diff --git a/drivers/video/fbdev/msm/mdss_dsi.h b/drivers/video/fbdev/msm/mdss_dsi.h index 9847016fed29..900513931547 100644 --- a/drivers/video/fbdev/msm/mdss_dsi.h +++ b/drivers/video/fbdev/msm/mdss_dsi.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2012-2017, The Linux Foundation. All rights reserved. +/* Copyright (c) 2012-2018, 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 @@ -633,8 +633,8 @@ void disable_esd_thread(void); void mdss_dsi_irq_handler_config(struct mdss_dsi_ctrl_pdata *ctrl_pdata); void mdss_dsi_set_tx_power_mode(int mode, struct mdss_panel_data *pdata); -int mdss_dsi_clk_div_config(struct mdss_panel_info *panel_info, - int frame_rate); +u64 mdss_dsi_calc_bitclk(struct mdss_panel_info *panel_info, int frame_rate); +u32 mdss_dsi_get_pclk_rate(struct mdss_panel_info *panel_info, u64 clk_rate); int mdss_dsi_clk_refresh(struct mdss_panel_data *pdata, bool update_phy); int mdss_dsi_link_clk_init(struct platform_device *pdev, struct mdss_dsi_ctrl_pdata *ctrl_pdata); diff --git a/drivers/video/fbdev/msm/mdss_dsi_panel.c b/drivers/video/fbdev/msm/mdss_dsi_panel.c index dbd58f93e907..bf695ae0beaf 100644 --- a/drivers/video/fbdev/msm/mdss_dsi_panel.c +++ b/drivers/video/fbdev/msm/mdss_dsi_panel.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2012-2017, The Linux Foundation. All rights reserved. +/* Copyright (c) 2012-2018, 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 @@ -1803,17 +1803,13 @@ static bool mdss_dsi_cmp_panel_reg_v2(struct mdss_dsi_ctrl_pdata *ctrl) for (i = 0; i < ctrl->status_cmds.cmd_cnt; i++) len += lenp[i]; - for (i = 0; i < len; i++) { - pr_debug("[%i] return:0x%x status:0x%x\n", - i, (unsigned int)ctrl->return_buf[i], - (unsigned int)ctrl->status_value[j + i]); - MDSS_XLOG(ctrl->ndx, ctrl->return_buf[i], - ctrl->status_value[j + i]); - j += len; - } - for (j = 0; j < ctrl->groups; ++j) { for (i = 0; i < len; ++i) { + pr_debug("[%i] return:0x%x status:0x%x\n", + i, ctrl->return_buf[i], + (unsigned int)ctrl->status_value[group + i]); + MDSS_XLOG(ctrl->ndx, ctrl->return_buf[i], + ctrl->status_value[group + i]); if (ctrl->return_buf[i] != ctrl->status_value[group + i]) break; @@ -2324,14 +2320,15 @@ static void mdss_dsi_parse_dfps_config(struct device_node *pan_node, struct mdss_dsi_ctrl_pdata *ctrl_pdata) { const char *data; - bool dynamic_fps; + bool dynamic_fps, dynamic_bitclk; struct mdss_panel_info *pinfo = &(ctrl_pdata->panel_data.panel_info); + int rc = 0; dynamic_fps = of_property_read_bool(pan_node, "qcom,mdss-dsi-pan-enable-dynamic-fps"); if (!dynamic_fps) - return; + goto dynamic_bitclk; pinfo->dynamic_fps = true; data = of_get_property(pan_node, "qcom,mdss-dsi-pan-fps-update", NULL); @@ -2361,6 +2358,31 @@ static void mdss_dsi_parse_dfps_config(struct device_node *pan_node, pinfo->new_fps = pinfo->mipi.frame_rate; pinfo->current_fps = pinfo->mipi.frame_rate; +dynamic_bitclk: + dynamic_bitclk = of_property_read_bool(pan_node, + "qcom,mdss-dsi-pan-enable-dynamic-bitclk"); + if (!dynamic_bitclk) + return; + + of_find_property(pan_node, "qcom,mdss-dsi-dynamic-bitclk_freq", + &pinfo->supp_bitclk_len); + pinfo->supp_bitclk_len = pinfo->supp_bitclk_len/sizeof(u32); + if (pinfo->supp_bitclk_len < 1) + return; + + pinfo->supp_bitclks = kzalloc((sizeof(u32) * pinfo->supp_bitclk_len), + GFP_KERNEL); + if (!pinfo->supp_bitclks) + return; + + rc = of_property_read_u32_array(pan_node, + "qcom,mdss-dsi-dynamic-bitclk_freq", pinfo->supp_bitclks, + pinfo->supp_bitclk_len); + if (rc) { + pr_err("Error from dynamic bitclk freq u64 array read\n"); + return; + } + pinfo->dynamic_bitclk = true; return; } diff --git a/drivers/video/fbdev/msm/mdss_dsi_phy.c b/drivers/video/fbdev/msm/mdss_dsi_phy.c index 2d2498643c3f..e8e903e6ce88 100644 --- a/drivers/video/fbdev/msm/mdss_dsi_phy.c +++ b/drivers/video/fbdev/msm/mdss_dsi_phy.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2015-2016, The Linux Foundation. All rights reserved. +/* Copyright (c) 2015-2016, 2018 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 @@ -1034,15 +1034,10 @@ static void mdss_dsi_phy_update_timing_param_v3(struct mdss_panel_info *pinfo, } int mdss_dsi_phy_calc_timing_param(struct mdss_panel_info *pinfo, u32 phy_rev, - u32 frate_hz) + u64 clk_rate) { struct dsi_phy_t_clk_param t_clk; struct dsi_phy_timing t_param; - int hsync_period; - int vsync_period; - unsigned long inter_num; - uint32_t lane_config = 0; - unsigned long x, y; int rc = 0; if (!pinfo) { @@ -1050,30 +1045,12 @@ int mdss_dsi_phy_calc_timing_param(struct mdss_panel_info *pinfo, u32 phy_rev, return -EINVAL; } - hsync_period = mdss_panel_get_htotal(pinfo, true); - vsync_period = mdss_panel_get_vtotal(pinfo); - - inter_num = pinfo->bpp * frate_hz; - - if (pinfo->mipi.data_lane0) - lane_config++; - if (pinfo->mipi.data_lane1) - lane_config++; - if (pinfo->mipi.data_lane2) - lane_config++; - if (pinfo->mipi.data_lane3) - lane_config++; - - x = mult_frac(vsync_period * hsync_period, inter_num, lane_config); - y = rounddown(x, 1); - t_clk.bitclk_mbps = rounddown(mult_frac(y, 1, 1000000), 1); + t_clk.bitclk_mbps = rounddown((uint32_t) div_u64(clk_rate, 1000000), 1); t_clk.escclk_numer = ESC_CLK_MHZ; t_clk.escclk_denom = ESCCLK_MMSS_CC_PREDIV; t_clk.tlpx_numer_ns = TLPX_NUMER; t_clk.treot_ns = TR_EOT; - pr_debug("hperiod=%d, vperiod=%d, inter_num=%lu, lane_cfg=%d\n", - hsync_period, vsync_period, inter_num, lane_config); - pr_debug("x=%lu, y=%lu, bitrate=%d\n", x, y, t_clk.bitclk_mbps); + pr_debug("bitrate=%d\n", t_clk.bitclk_mbps); rc = mdss_dsi_phy_initialize_defaults(&t_clk, &t_param, phy_rev); if (rc) { diff --git a/drivers/video/fbdev/msm/mdss_dsi_phy.h b/drivers/video/fbdev/msm/mdss_dsi_phy.h index 03df17d81f69..b0f7d68556d5 100644 --- a/drivers/video/fbdev/msm/mdss_dsi_phy.h +++ b/drivers/video/fbdev/msm/mdss_dsi_phy.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2015-2017, The Linux Foundation. All rights reserved. +/* Copyright (c) 2015-2018, 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 @@ -42,7 +42,7 @@ enum phy_mode { * @frate_hz - Frame rate for which phy timing parameters are to be calculated. */ int mdss_dsi_phy_calc_timing_param(struct mdss_panel_info *pinfo, u32 phy_rev, - u32 frate_hz); + u64 clk_rate); /* * mdss_dsi_phy_v3_init() - initialization sequence for DSI PHY rev v3 diff --git a/drivers/video/fbdev/msm/mdss_fb.c b/drivers/video/fbdev/msm/mdss_fb.c index 6c4db0f1f5bd..1b408e2838d6 100644 --- a/drivers/video/fbdev/msm/mdss_fb.c +++ b/drivers/video/fbdev/msm/mdss_fb.c @@ -1,7 +1,7 @@ /* * Core MDSS framebuffer driver. * - * Copyright (c) 2008-2017, The Linux Foundation. All rights reserved. + * Copyright (c) 2008-2018, The Linux Foundation. All rights reserved. * Copyright (C) 2007 Google Incorporated * * This software is licensed under the terms of the GNU General Public @@ -610,7 +610,7 @@ static ssize_t mdss_fb_get_panel_info(struct device *dev, "red_chromaticity_x=%d\nred_chromaticity_y=%d\n" "green_chromaticity_x=%d\ngreen_chromaticity_y=%d\n" "blue_chromaticity_x=%d\nblue_chromaticity_y=%d\n" - "panel_orientation=%d\n", + "panel_orientation=%d\ndyn_bitclk_en=%d\n", pinfo->partial_update_enabled, pinfo->roi_alignment.xstart_pix_align, pinfo->roi_alignment.width_pix_align, @@ -636,7 +636,7 @@ static ssize_t mdss_fb_get_panel_info(struct device *dev, pinfo->hdr_properties.display_primaries[5], pinfo->hdr_properties.display_primaries[6], pinfo->hdr_properties.display_primaries[7], - pinfo->panel_orientation); + pinfo->panel_orientation, pinfo->dynamic_bitclk); return ret; } diff --git a/drivers/video/fbdev/msm/mdss_panel.h b/drivers/video/fbdev/msm/mdss_panel.h index acac672662c1..de3ff0c77625 100644 --- a/drivers/video/fbdev/msm/mdss_panel.h +++ b/drivers/video/fbdev/msm/mdss_panel.h @@ -805,6 +805,9 @@ struct mdss_panel_info { int pwm_lpg_chan; int pwm_period; bool dynamic_fps; + bool dynamic_bitclk; + u32 *supp_bitclks; + u32 supp_bitclk_len; bool ulps_feature_enabled; bool ulps_suspend_enabled; bool panel_ack_disabled; diff --git a/drivers/video/fbdev/msm/msm_mdss_io_8974.c b/drivers/video/fbdev/msm/msm_mdss_io_8974.c index bb3b4b3fa929..922c4440ba82 100644 --- a/drivers/video/fbdev/msm/msm_mdss_io_8974.c +++ b/drivers/video/fbdev/msm/msm_mdss_io_8974.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2012-2017, The Linux Foundation. All rights reserved. +/* Copyright (c) 2012-2018, 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 @@ -1489,13 +1489,19 @@ int mdss_dsi_clk_refresh(struct mdss_panel_data *pdata, bool update_phy) __func__, pinfo->mipi.frame_rate); } - rc = mdss_dsi_clk_div_config(&pdata->panel_info, - pdata->panel_info.mipi.frame_rate); - if (rc) { - pr_err("%s: unable to initialize the clk dividers\n", - __func__); - return rc; + pinfo->clk_rate = mdss_dsi_calc_bitclk(pinfo, pinfo->mipi.frame_rate); + if (!pinfo->clk_rate) { + pr_err("%s: unable to calculate the DSI bit clock\n", __func__); + return -EINVAL; } + + pinfo->mipi.dsi_pclk_rate = mdss_dsi_get_pclk_rate(pinfo, + pinfo->clk_rate); + if (!pinfo->mipi.dsi_pclk_rate) { + pr_err("%s: unable to calculate the DSI pclk\n", __func__); + return -EINVAL; + } + ctrl_pdata->refresh_clk_rate = false; ctrl_pdata->pclk_rate = pdata->panel_info.mipi.dsi_pclk_rate; ctrl_pdata->byte_clk_rate = pdata->panel_info.clk_rate / 8; @@ -1524,7 +1530,7 @@ int mdss_dsi_clk_refresh(struct mdss_panel_data *pdata, bool update_phy) /* phy panel timing calaculation */ rc = mdss_dsi_phy_calc_timing_param(pinfo, ctrl_pdata->shared_data->phy_rev, - pinfo->mipi.frame_rate); + pdata->panel_info.clk_rate); if (rc) { pr_err("Error in calculating phy timings\n"); return rc; @@ -1811,16 +1817,9 @@ bool is_diff_frame_rate(struct mdss_panel_info *panel_info, return (frame_rate != panel_info->mipi.frame_rate); } -int mdss_dsi_clk_div_config(struct mdss_panel_info *panel_info, - int frame_rate) +static u8 mdss_dsi_get_lane_cnt(struct mdss_panel_info *panel_info) { - struct mdss_panel_data *pdata = container_of(panel_info, - struct mdss_panel_data, panel_info); - struct mdss_dsi_ctrl_pdata *ctrl_pdata = container_of(pdata, - struct mdss_dsi_ctrl_pdata, panel_data); - u64 h_period, v_period, clk_rate; - u32 dsi_pclk_rate; - u8 lanes = 0, bpp; + u8 lanes = 0; if (!panel_info) return -EINVAL; @@ -1834,7 +1833,17 @@ int mdss_dsi_clk_div_config(struct mdss_panel_info *panel_info, if (panel_info->mipi.data_lane0) lanes += 1; - switch (panel_info->mipi.dst_format) { + if (!lanes) + lanes = 1; + + return lanes; +} + +static u8 mdss_dsi_get_bpp(char dst_format) +{ + u8 bpp = 0; + + switch (dst_format) { case DSI_CMD_DST_FORMAT_RGB888: case DSI_VIDEO_DST_FORMAT_RGB888: case DSI_VIDEO_DST_FORMAT_RGB666_LOOSE: @@ -1848,6 +1857,21 @@ int mdss_dsi_clk_div_config(struct mdss_panel_info *panel_info, bpp = 3; /* Default format set to RGB888 */ break; } + return bpp; +} + +u64 mdss_dsi_calc_bitclk(struct mdss_panel_info *panel_info, int frame_rate) +{ + struct mdss_panel_data *pdata = container_of(panel_info, + struct mdss_panel_data, panel_info); + struct mdss_dsi_ctrl_pdata *ctrl_pdata = container_of(pdata, + struct mdss_dsi_ctrl_pdata, panel_data); + u64 h_period, v_period, clk_rate = 0; + u8 lanes = 0, bpp; + + lanes = mdss_dsi_get_lane_cnt(panel_info); + + bpp = mdss_dsi_get_bpp(panel_info->mipi.dst_format); h_period = mdss_panel_get_htotal(panel_info, true); if (panel_info->split_link_enabled) @@ -1855,35 +1879,40 @@ int mdss_dsi_clk_div_config(struct mdss_panel_info *panel_info, v_period = mdss_panel_get_vtotal(panel_info); if (ctrl_pdata->refresh_clk_rate || is_diff_frame_rate(panel_info, - frame_rate) || (!panel_info->clk_rate)) { - if (lanes > 0) { - panel_info->clk_rate = h_period * v_period * frame_rate - * bpp * 8; - do_div(panel_info->clk_rate, lanes); - } else { - pr_err("%s: forcing mdss_dsi lanes to 1\n", __func__); - panel_info->clk_rate = - h_period * v_period * frame_rate * bpp * 8; - } + frame_rate) || (!panel_info->clk_rate)) { + clk_rate = h_period * v_period * frame_rate * bpp * 8; + do_div(clk_rate, lanes); + } else if (panel_info->clk_rate) { + clk_rate = panel_info->clk_rate; } - if (panel_info->clk_rate == 0) - panel_info->clk_rate = 454000000; + if (clk_rate == 0) + clk_rate = 454000000; + + return clk_rate; +} + +u32 mdss_dsi_get_pclk_rate(struct mdss_panel_info *panel_info, u64 clk_rate) +{ + u8 lanes = 0, bpp; + u32 pclk_rate = 0; + + lanes = mdss_dsi_get_lane_cnt(panel_info); + + bpp = mdss_dsi_get_bpp(panel_info->mipi.dst_format); - clk_rate = panel_info->clk_rate; do_div(clk_rate, 8 * bpp); if (panel_info->split_link_enabled) - dsi_pclk_rate = (u32) clk_rate * + pclk_rate = (u32) clk_rate * panel_info->mipi.lanes_per_sublink; else - dsi_pclk_rate = (u32) clk_rate * lanes; + pclk_rate = (u32) clk_rate * lanes; - if ((dsi_pclk_rate < 3300000) || (dsi_pclk_rate > 250000000)) - dsi_pclk_rate = 35000000; - panel_info->mipi.dsi_pclk_rate = dsi_pclk_rate; + if ((pclk_rate < 3300000) || (pclk_rate > 250000000)) + pclk_rate = 35000000; - return 0; + return pclk_rate; } static bool mdss_dsi_is_ulps_req_valid(struct mdss_dsi_ctrl_pdata *ctrl, diff --git a/fs/sdcardfs/main.c b/fs/sdcardfs/main.c index 27ec726e7a46..1ad7718c05d9 100644 --- a/fs/sdcardfs/main.c +++ b/fs/sdcardfs/main.c @@ -264,7 +264,7 @@ static int sdcardfs_read_super(struct vfsmount *mnt, struct super_block *sb, pr_info("sdcardfs: dev_name -> %s\n", dev_name); pr_info("sdcardfs: options -> %s\n", (char *)raw_data); - pr_info("sdcardfs: mnt -> %p\n", mnt); + pr_info("sdcardfs: mnt -> %pK\n", mnt); /* parse lower path */ err = kern_path(dev_name, LOOKUP_FOLLOW | LOOKUP_DIRECTORY, diff --git a/fs/sdcardfs/super.c b/fs/sdcardfs/super.c index cffcdb11cb8a..fa7d9d2c5c2b 100644 --- a/fs/sdcardfs/super.c +++ b/fs/sdcardfs/super.c @@ -144,7 +144,7 @@ static int sdcardfs_remount_fs2(struct vfsmount *mnt, struct super_block *sb, pr_err("sdcardfs: remount flags 0x%x unsupported\n", *flags); err = -EINVAL; } - pr_info("Remount options were %s for vfsmnt %p.\n", options, mnt); + pr_info("Remount options were %s for vfsmnt %pK.\n", options, mnt); err = parse_options_remount(sb, options, *flags & ~MS_SILENT, mnt->data); diff --git a/include/linux/qdsp6v2/audio-anc-dev-mgr.h b/include/linux/qdsp6v2/audio-anc-dev-mgr.h index dfa6752bc31b..b0ece2dbb239 100644 --- a/include/linux/qdsp6v2/audio-anc-dev-mgr.h +++ b/include/linux/qdsp6v2/audio-anc-dev-mgr.h @@ -39,6 +39,8 @@ int msm_anc_dev_stop(void); int msm_anc_dev_set_info(void *info_p, int32_t anc_cmd); +int msm_anc_dev_get_info(void *info_p, int32_t anc_cmd); + int msm_anc_dev_create(struct platform_device *pdev); int msm_anc_dev_destroy(struct platform_device *pdev); diff --git a/include/linux/qdsp6v2/sdsp_anc.h b/include/linux/qdsp6v2/sdsp_anc.h index 3b236e827e3d..5c1b7055c1d5 100644 --- a/include/linux/qdsp6v2/sdsp_anc.h +++ b/include/linux/qdsp6v2/sdsp_anc.h @@ -15,7 +15,6 @@ #include <sound/q6afe-v2.h> #include <sound/apr_audio-v2.h> - #define AUD_MSVC_MODULE_AUDIO_DEV_RESOURCE_SHARE 0x0001028A #define AUD_MSVC_PARAM_ID_PORT_SHARE_RESOURCE_CONFIG 0x00010297 #define AUD_MSVC_API_VERSION_SHARE_RESOURCE_CONFIG 0x1 @@ -23,8 +22,6 @@ #define AUD_MSVC_PARAM_ID_DEV_ANC_REFS_CONFIG 0x00010286 #define AUD_MSVC_API_VERSION_DEV_ANC_REFS_CONFIG 0x1 #define AUD_MSVC_MODULE_AUDIO_DEV_ANC_ALGO 0x00010234 -#define AUD_MSVC_PARAM_ID_PORT_ANC_ALGO_RPM 0x00010235 -#define AUD_MSVC_API_VERSION_DEV_ANC_ALGO_RPM 0x1 struct aud_msvc_port_param_data_v2 { /* ID of the module to be configured. @@ -148,7 +145,7 @@ struct aud_msvc_port_cmd_get_param_v2 { } __packed; struct aud_audioif_config_command { - struct apr_hdr hdr; + struct apr_hdr hdr; struct aud_msvc_port_cmd_set_param_v2 param; struct aud_msvc_port_param_data_v2 pdata; union afe_port_config port; @@ -162,13 +159,6 @@ struct aud_msvc_param_id_dev_share_resource_cfg { u32 lpm_length; } __packed; - -struct aud_msvc_param_id_dev_anc_algo_rpm { - u32 minor_version; - u32 rpm; -} __packed; - - struct aud_msvc_param_id_dev_anc_refs_cfg { u32 minor_version; u16 port_id; @@ -177,65 +167,20 @@ struct aud_msvc_param_id_dev_anc_refs_cfg { u32 bit_width; } __packed; - struct anc_share_resource_command { - struct apr_hdr hdr; + struct apr_hdr hdr; struct aud_msvc_port_cmd_set_param_v2 param; struct aud_msvc_port_param_data_v2 pdata; struct aud_msvc_param_id_dev_share_resource_cfg resource; } __packed; - struct anc_config_ref_command { - struct apr_hdr hdr; + struct apr_hdr hdr; struct aud_msvc_port_cmd_set_param_v2 param; struct aud_msvc_port_param_data_v2 pdata; struct aud_msvc_param_id_dev_anc_refs_cfg refs; } __packed; - - -struct anc_set_rpm_command { - struct apr_hdr hdr; - struct aud_msvc_port_cmd_set_param_v2 param; - struct aud_msvc_port_param_data_v2 pdata; - struct aud_msvc_param_id_dev_anc_algo_rpm set_rpm; -} __packed; - -struct anc_get_rpm_command { - struct apr_hdr hdr; - struct aud_msvc_port_cmd_get_param_v2 param; - struct aud_msvc_port_param_data_v2 pdata; - struct aud_msvc_param_id_dev_anc_algo_rpm get_rpm; -} __packed; - -struct anc_get_rpm_resp { - uint32_t status; - struct aud_msvc_port_param_data_v2 pdata; - struct aud_msvc_param_id_dev_anc_algo_rpm res_rpm; -} __packed; - -#define AUD_MSVC_PARAM_ID_PORT_ANC_ALGO_BYPASS_MODE 0x0001029B - -#define AUD_MSVC_API_VERSION_DEV_ANC_ALGO_BYPASS_MODE 0x1 - -#define AUD_MSVC_ANC_ALGO_BYPASS_MODE_NO 0x0 -#define AUD_MSVC_ANC_ALGO_BYPASS_MODE_REFS_TO_ANC_SPKR 0x1 -#define AUD_MSVC_ANC_ALGO_BYPASS_MODE_ANC_MIC_TO_ANC_SPKR 0x2 -#define AUD_MSVC_ANC_ALGO_BYPASS_MODE_REFS_MIXED_ANC_MIC_TO_ANC_SPKR 0x3 - -struct aud_msvc_param_id_dev_anc_algo_bypass_mode { - uint32_t minor_version; - uint32_t bypass_mode; -} __packed; - -struct anc_set_bypass_mode_command { - struct apr_hdr hdr; - struct aud_msvc_port_cmd_set_param_v2 param; - struct aud_msvc_port_param_data_v2 pdata; - struct aud_msvc_param_id_dev_anc_algo_bypass_mode set_bypass_mode; -} __packed; - #define AUD_MSVC_PARAM_ID_PORT_ANC_ALGO_MODULE_ID 0x0001023A struct aud_msvc_param_id_dev_anc_algo_module_id { @@ -244,7 +189,7 @@ struct aud_msvc_param_id_dev_anc_algo_module_id { } __packed; struct anc_set_algo_module_id_command { - struct apr_hdr hdr; + struct apr_hdr hdr; struct aud_msvc_port_cmd_set_param_v2 param; struct aud_msvc_port_param_data_v2 pdata; struct aud_msvc_param_id_dev_anc_algo_module_id set_algo_module_id; @@ -269,13 +214,37 @@ struct aud_msvc_param_id_dev_anc_mic_spkr_layout_info { } __packed; struct anc_set_mic_spkr_layout_info_command { - struct apr_hdr hdr; + struct apr_hdr hdr; struct aud_msvc_port_cmd_set_param_v2 param; struct aud_msvc_port_param_data_v2 pdata; struct aud_msvc_param_id_dev_anc_mic_spkr_layout_info set_mic_spkr_layout; } __packed; +struct anc_set_algo_module_cali_data_command { + struct apr_hdr hdr; + struct aud_msvc_port_cmd_set_param_v2 param; + struct aud_msvc_port_param_data_v2 pdata; + /* + * calibration data payload followed + */ +} __packed; + +struct anc_get_algo_module_cali_data_command { + struct apr_hdr hdr; + struct aud_msvc_port_cmd_get_param_v2 param; + struct aud_msvc_port_param_data_v2 pdata; + /* + * calibration data payload followed + */ +} __packed; + +struct anc_get_algo_module_cali_data_resp { + uint32_t status; + struct aud_msvc_port_param_data_v2 pdata; + uint32_t payload[128]; +} __packed; + int anc_if_tdm_port_start(u16 port_id, struct afe_tdm_port_config *tdm_port); int anc_if_tdm_port_stop(u16 port_id); @@ -286,15 +255,15 @@ int anc_if_share_resource(u16 port_id, u16 rddma_idx, u16 wrdma_idx, int anc_if_config_ref(u16 port_id, u32 sample_rate, u32 bit_width, u16 num_channel); -int anc_if_set_rpm(u16 port_id, u32 rpm); - -int anc_if_set_bypass_mode(u16 port_id, u32 bypass_mode); - int anc_if_set_algo_module_id(u16 port_id, u32 module_id); int anc_if_set_anc_mic_spkr_layout(u16 port_id, struct aud_msvc_param_id_dev_anc_mic_spkr_layout_info *set_mic_spkr_layout_p); +int anc_if_set_algo_module_cali_data(u16 port_id, void *data_p); + +int anc_if_get_algo_module_cali_data(u16 port_id, void *data_p); + int anc_if_shared_mem_map(void); int anc_if_shared_mem_unmap(void); diff --git a/include/net/cnss2.h b/include/net/cnss2.h index e06f0b670d90..7ca407f6b606 100644 --- a/include/net/cnss2.h +++ b/include/net/cnss2.h @@ -192,6 +192,9 @@ extern void cnss_lock_pm_sem(struct device *dev); extern void cnss_release_pm_sem(struct device *dev); extern int cnss_auto_suspend(struct device *dev); extern int cnss_auto_resume(struct device *dev); +extern int cnss_pci_force_wake_request(struct device *dev); +extern int cnss_pci_is_device_awake(struct device *dev); +extern int cnss_pci_force_wake_release(struct device *dev); extern int cnss_get_user_msi_assignment(struct device *dev, char *user_name, int *num_vectors, uint32_t *user_base_data, diff --git a/include/uapi/linux/habmmid.h b/include/uapi/linux/habmmid.h index 4f79506dd971..1845c72c9e60 100644 --- a/include/uapi/linux/habmmid.h +++ b/include/uapi/linux/habmmid.h @@ -29,7 +29,8 @@ #define MM_VID_START 500 #define MM_VID 501 -#define MM_VID_END 502 +#define MM_VID_2 502 +#define MM_VID_END 503 #define MM_MISC_START 600 #define MM_MISC 601 @@ -37,10 +38,7 @@ #define MM_QCPE_START 700 #define MM_QCPE_VM1 701 -#define MM_QCPE_VM2 702 -#define MM_QCPE_VM3 703 -#define MM_QCPE_VM4 704 -#define MM_QCPE_END 705 +#define MM_QCPE_END 702 #define MM_CLK_START 800 #define MM_CLK_VM1 801 diff --git a/include/uapi/linux/msm_audio_anc.h b/include/uapi/linux/msm_audio_anc.h index d628f7ce9267..87701fd8ee3a 100644 --- a/include/uapi/linux/msm_audio_anc.h +++ b/include/uapi/linux/msm_audio_anc.h @@ -21,6 +21,8 @@ /* room for ANC_CMD define extend */ #define ANC_CMD_MAX 0xFF +#define ANC_CALIBRATION_PAYLOAD_SIZE_MAX 100 + struct audio_anc_header { int32_t data_size; int32_t version; @@ -35,14 +37,23 @@ struct audio_anc_rpm_info { struct audio_anc_bypass_mode { int32_t mode; }; - struct audio_anc_algo_module_info { int32_t module_id; }; +struct audio_anc_algo_calibration_header { + uint32_t module_id; + uint32_t param_id; + uint32_t payload_size; +}; + +struct audio_anc_algo_calibration_body { + int32_t payload[ANC_CALIBRATION_PAYLOAD_SIZE_MAX]; +}; + struct audio_anc_algo_calibration_info { - int32_t payload_size; - /* num bytes of payload specificed in payload_size followed */ + struct audio_anc_algo_calibration_header cali_header; + struct audio_anc_algo_calibration_body cali_body; }; union audio_anc_data { diff --git a/include/uapi/linux/msm_kgsl.h b/include/uapi/linux/msm_kgsl.h index 13bb8b79359a..005fb8284524 100644 --- a/include/uapi/linux/msm_kgsl.h +++ b/include/uapi/linux/msm_kgsl.h @@ -322,6 +322,8 @@ enum kgsl_timestamp_type { #define KGSL_PROP_DEVICE_QDSS_STM 0x19 #define KGSL_PROP_DEVICE_QTIMER 0x20 #define KGSL_PROP_IB_TIMEOUT 0x21 +#define KGSL_PROP_SECURE_BUFFER_ALIGNMENT 0x23 +#define KGSL_PROP_SECURE_CTXT_SUPPORT 0x24 struct kgsl_shadowprop { unsigned long gpuaddr; |
