diff options
37 files changed, 885 insertions, 140 deletions
diff --git a/Documentation/devicetree/bindings/iio/imu/invn-iam20680.txt b/Documentation/devicetree/bindings/iio/imu/invn-iam20680.txt new file mode 100644 index 000000000000..f5227841b5d9 --- /dev/null +++ b/Documentation/devicetree/bindings/iio/imu/invn-iam20680.txt @@ -0,0 +1,83 @@ +The IAM20680 sensor is 6-axis gyroscope+accelerometer combo +device which is made by InvenSense Inc. + +Required properties: + + - compatible : Should be "invn,iam20680". + - reg : the I2C address which depends on the AD0 pin. + - gpios : INVENSENSE GPIO in the format described by ../gpio/gpio.txt + +Optional properties: + - inven,vdd_ana-supply : + - inven,vcc_i2c-supply : + - inven,gpio_int1 : + - axis_map_x : + - axis_map_y : + - axis_map_z : + - negate_x : + - negate_y : + - negate_z : + - fs_range : + - poll_interval : + - min_interval : + - inven,secondary_reg : + - inven,secondary_type : + - inven,secondary_name : + - inven,secondary_axis_map_x : + - inven,secondary_axis_map_y : + - inven,secondary_axis_map_z : + - inven,secondary_negate_x : + - inven,secondary_negate_y : + - inven,secondary_negate_z : + - inven,aux_type : + - inven,aux_name : + - inven,aux_reg : + - inven,read_only_slave_type : + - inven,read_only_slave_name : + - inven,read_only_slave_reg : + +Example: + iam20680@69 { + compatible = "inven,iam20680"; + reg = <0x69>; + pinctrl-names = "default"; + pinctrl-0 = <&int1_default>; + interrupt-parent = <&tlmm_pinmux>; + interrupts = <78 IRQ_TYPE_EDGE_RISING>; + inven,vdd_ana-supply = <&pm8941_l17>; + inven,vcc_i2c-supply = <&pm8941_lvs1>; + inven,gpio_int1 = <&msmgpio 73 0x00>; + axis_map_x = <1>; + axis_map_y = <0>; + axis_map_z = <2>; + negate_x = <1>; + negate_y = <0>; + negate_z = <0>; + fs_range = <0x00>; + poll_interval = <200>; + min_interval = <5>; + inven,secondary_reg = <0x0c>; + /* If no compass sensor, + * replace "compass" with "none" + */ + inven,secondary_type = "compass"; + inven,secondary_name = "ak09911"; + inven,secondary_axis_map_x = <1>; + inven,secondary_axis_map_y = <0>; + inven,secondary_axis_map_z = <2>; + inven,secondary_negate_x = <1>; + inven,secondary_negate_y = <1>; + inven,secondary_negate_z = <1>; + /* If no pressure sensor, + * replace "pressure" with "none" + */ + inven,aux_type = "pressure"; + inven,aux_name = "bmp280"; + inven,aux_reg = <0x76>; + /* If no ALS sensor + * replace "als" with "none" + */ + inven,read_only_slave_type = "als"; + inven,read_only_slave_name = "apds9930"; + inven,read_only_slave_reg = <0x39>; + }; diff --git a/Documentation/devicetree/bindings/input/sensors/bmi160.txt b/Documentation/devicetree/bindings/input/sensors/bmi160.txt new file mode 100644 index 000000000000..8fd43cd6e52b --- /dev/null +++ b/Documentation/devicetree/bindings/input/sensors/bmi160.txt @@ -0,0 +1,27 @@ + +The BMI160 is a highly integrated, low power inertial measurement unit (IMU) +that provides precise acceleration and angular rate (gyroscopic) measurement. + +Required properties: + + - compatible : Should be "bosch-sensortec,bmi160". + - reg : the Chip select ID. + - gpios : BMI GPIO in the format described by ../gpio/gpio.txt + +Optional properties: + - bmi,init-interval: + - bmi,place : + + +Example: + bmi160@68{ + compatible = "bosch-sensortec,bmi160"; + reg = <0x68>; + pinctrl-names = "default"; + pinctrl-0 = <&bmi160_int1_default &bmi160_int2_default>; + interrupt-parent = <&tlmm_pinmux>; + interrupts = <78 0x2002>; + bmi,init-interval = <200>; + bmi,place = <1>; + bmi,gpio_irq = <&tlmm_pinmux 78 0x2002>; + }; diff --git a/Documentation/devicetree/bindings/vendor-prefixes.txt b/Documentation/devicetree/bindings/vendor-prefixes.txt index f9097941c192..7354ff18e919 100644 --- a/Documentation/devicetree/bindings/vendor-prefixes.txt +++ b/Documentation/devicetree/bindings/vendor-prefixes.txt @@ -259,6 +259,8 @@ xes Extreme Engineering Solutions (X-ES) xillybus Xillybus Ltd. xlnx Xilinx zyxel ZyXEL Communications Corp. +bosch-sensortec» Bosch Sensortec GmbH +inven InvenSense, Inc. zarlink Zarlink Semiconductor zii Zodiac Inflight Innovations zte ZTE Corp. diff --git a/arch/arm/boot/dts/qcom/apq8096pro-auto-cdp.dts b/arch/arm/boot/dts/qcom/apq8096pro-auto-cdp.dts index 1bca588f448e..7fa5b2850635 100644 --- a/arch/arm/boot/dts/qcom/apq8096pro-auto-cdp.dts +++ b/arch/arm/boot/dts/qcom/apq8096pro-auto-cdp.dts @@ -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 @@ -20,7 +20,7 @@ / { model = "Qualcomm Technologies, Inc. APQ 8096 pro AUTO CDP"; compatible = "qcom,apq8096-cdp", "qcom,apq8096", "qcom,cdp"; - qcom,msm-id = <316 0x10000>; + qcom,msm-id = <316 0x10000>, <387 0x10000>; qcom,board-id = <0x03010001 0>; }; diff --git a/arch/arm/boot/dts/qcom/apq8096pro-v1.1-auto-adp-lite.dts b/arch/arm/boot/dts/qcom/apq8096pro-v1.1-auto-adp-lite.dts index 0bb04361eabe..c2d9f6696307 100644 --- a/arch/arm/boot/dts/qcom/apq8096pro-v1.1-auto-adp-lite.dts +++ b/arch/arm/boot/dts/qcom/apq8096pro-v1.1-auto-adp-lite.dts @@ -21,7 +21,7 @@ / { model = "Qualcomm Technologies, Inc. APQ 8096pro V1.1 AUTO ADP LITE"; compatible = "qcom,apq8096-adp", "qcom,msm8996", "qcom,adp"; - qcom,msm-id = <316 0x10001>; + qcom,msm-id = <316 0x10001>, <387 0x10001>; qcom,board-id = <0x03010019 0>; }; diff --git a/arch/arm/boot/dts/qcom/apq8096pro-v1.1-auto-adp.dts b/arch/arm/boot/dts/qcom/apq8096pro-v1.1-auto-adp.dts index 908dc4a20372..9ca38fcac0bb 100644 --- a/arch/arm/boot/dts/qcom/apq8096pro-v1.1-auto-adp.dts +++ b/arch/arm/boot/dts/qcom/apq8096pro-v1.1-auto-adp.dts @@ -21,7 +21,7 @@ / { model = "Qualcomm Technologies, Inc. MSM 8996pro AUTO ADP"; compatible = "qcom,apq8096-adp", "qcom,msm8996", "qcom,adp"; - qcom,msm-id = <316 0x10001>; + qcom,msm-id = <316 0x10001>, <387 0x10001> ; qcom,board-id = <0x02010019 0>, <0x00010001 0>; }; diff --git a/arch/arm/boot/dts/qcom/apq8096pro-v1.1-auto-cdp.dts b/arch/arm/boot/dts/qcom/apq8096pro-v1.1-auto-cdp.dts index e69640ddd363..422db71b26d4 100644 --- a/arch/arm/boot/dts/qcom/apq8096pro-v1.1-auto-cdp.dts +++ b/arch/arm/boot/dts/qcom/apq8096pro-v1.1-auto-cdp.dts @@ -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 @@ -20,7 +20,7 @@ / { model = "Qualcomm Technologies, Inc. APQ 8096 pro v1.1 AUTO CDP"; compatible = "qcom,msm8996-cdp", "qcom,msm8996", "qcom,cdp"; - qcom,msm-id = <316 0x10001>; + qcom,msm-id = <316 0x10001>, <387 0x10001>; qcom,board-id = <0x03010001 0>, <0x00010001 0>; }; diff --git a/arch/arm/boot/dts/qcom/msm8996-agave-adp.dtsi b/arch/arm/boot/dts/qcom/msm8996-agave-adp.dtsi index e6598fa2d0c5..ee42fe68f430 100644 --- a/arch/arm/boot/dts/qcom/msm8996-agave-adp.dtsi +++ b/arch/arm/boot/dts/qcom/msm8996-agave-adp.dtsi @@ -1488,6 +1488,41 @@ }; }; +&i2c_10 { + bmi160@68 { + compatible = "bosch-sensortec,bmi160"; + reg = <0x68>; + vdd-supply = <&pm8994_lvs2>; + vio-supply = <&pm8994_lvs2>; + pinctrl-names = "default"; + pinctrl-0 = <&sensor_int1_default &sensor_int2_default>; + interrupt-parent = <&tlmm>; + interrupts = <117 0x2002>; + bmi,init-interval = <200>; + bmi,place = <1>; + bmi,gpio_irq = <&tlmm 117 0x2002>; + }; + iam20680@69 { + compatible = "inven,iam20680"; + reg = <0x69>; + vdd-supply = <&pm8994_lvs2>; + vio-supply = <&pm8994_lvs2>; + pinctrl-names = "default"; + pinctrl-0 = <&sensor_int1_default &sensor_int2_default>; + interrupt-parent = <&tlmm>; + interrupts = <118 IRQ_TYPE_EDGE_RISING>; + axis_map_x = <1>; + axis_map_y = <0>; + axis_map_z = <2>; + negate_x = <1>; + negate_y = <0>; + negate_z = <0>; + inven,secondary_type = "none"; + inven,aux_type = "none"; + inven,read_only_slave_type = "none"; + }; +}; + &dsi_dual_jdi_video { /delete-property/ pwms; /delete-property/ qcom,5v-boost-gpio; diff --git a/arch/arm/boot/dts/qcom/msm8996-pinctrl.dtsi b/arch/arm/boot/dts/qcom/msm8996-pinctrl.dtsi index 0982ead00f8c..50b435547982 100644 --- a/arch/arm/boot/dts/qcom/msm8996-pinctrl.dtsi +++ b/arch/arm/boot/dts/qcom/msm8996-pinctrl.dtsi @@ -850,6 +850,58 @@ }; }; }; + i2c_10 { + i2c_10_active: i2c_10_active { + mux { + pins = "gpio10", "gpio11"; + function = "blsp_i2c10"; + }; + + config { + pins = "gpio10", "gpio11"; + drive-strength = <16>; + bias-pull-up; + }; + }; + + i2c_10_sleep: i2c_10_sleep { + mux { + pins = "gpio10", "gpio11"; + function = "blsp_i2c10"; + }; + + config { + pins = "gpio10", "gpio11"; + drive-strength = <16>; + bias-pull-up; + }; + }; + }; + + sensor_int1_default: sensor_int1_default { + mux { + pins = "gpio117"; + function = "gpio"; + }; + + config { + pins = "gpio117"; + drive-strength = <16>; /* 16 mA */ + bias-pull-down; /* pull down */ + }; + }; + sensor_int2_default: sensor_int2_default { + mux { + pins = "gpio118"; + function = "gpio"; + }; + + config { + pins = "gpio118"; + drive-strength = <16>; /* 16 mA */ + bias-pull-down; /* pull down */ + }; + }; pmx_fm_int { fm_int_active: fm_int_active { @@ -2839,5 +2891,19 @@ bias-pull-down; /* PULL down */ }; }; + + pinctrl_pps: ppsgrp { + mux { + pins = "gpio128"; + function = "nav_dr"; + }; + + config { + pins = "gpio128"; + drive-strength = <16>; + bias-pull-down; + }; + }; + }; }; diff --git a/arch/arm/boot/dts/qcom/msm8996.dtsi b/arch/arm/boot/dts/qcom/msm8996.dtsi index 95b100e10e5b..ed88cfeac053 100644 --- a/arch/arm/boot/dts/qcom/msm8996.dtsi +++ b/arch/arm/boot/dts/qcom/msm8996.dtsi @@ -39,6 +39,7 @@ i2c6 = &i2c_6; i2c7 = &i2c_7; i2c8 = &i2c_8; + i2c10 = &i2c_10; i2c12 = &i2c_12; spi0 = &spi_0; serial0 = &uartblsp2dm1; @@ -387,6 +388,28 @@ clock-names = "core_clk", "iface_clk"; }; + i2c_10: i2c@75b8000 { /* BLSP2 QUP4 */ + compatible = "qcom,i2c-msm-v2"; + #address-cells = <1>; + #size-cells = <0>; + reg-names = "qup_phys_addr"; + reg = <0x75b8000 0x600>; + interrupt-names = "qup_irq"; + interrupts = <0 104 0>; + dmas = <&dma_blsp2 18 32 0x20000020 0x20>, + <&dma_blsp2 19 32 0x20000020 0x20>; + dma-names = "tx", "rx"; + qcom,master-id = <84>; + qcom,clk-freq-out = <400000>; + qcom,clk-freq-in = <19200000>; + clock-names = "iface_clk", "core_clk"; + clocks = <&clock_gcc clk_gcc_blsp2_ahb_clk>, + <&clock_gcc clk_gcc_blsp2_qup4_i2c_apps_clk>; + pinctrl-names = "i2c_active", "i2c_sleep"; + pinctrl-0 = <&i2c_10_active>; + pinctrl-1 = <&i2c_10_sleep>; + }; + i2c_12: i2c@75ba000 { compatible = "qcom,i2c-msm-v2"; #address-cells = <1>; @@ -2560,6 +2583,132 @@ qcom,ipa-advertise-sg-support; }; + pcie_ep: qcom,pcie-ep@00600000 { + compatible = "qcom,pcie-ep"; + + reg = <0x0c001000 0x1000>, + <0x0c000000 0xf1d>, + <0x0c000f20 0xa8>, + <0x00600000 0x2000>, + <0x00034000 0x4000>, + <0x00607000 0x1000>; + reg-names = "msi", "dm_core", "elbi", "parf", "phy", "mmio"; + + #address-cells = <0>; + interrupt-parent = <&pcie_ep>; + interrupts = <0 1 2 3 4>; + #interrupt-cells = <1>; + interrupt-map-mask = <0xffffffff>; + interrupt-map = <0 &intc 0 0 247 0 + 1 &intc 0 0 249 0 + 2 &intc 0 0 253 0 + 3 &intc 0 0 254 0 + 4 &intc 0 0 49 0>; + + interrupt-names ="int_pm_turnoff", "int_dstate_change", + "int_link_up", "int_link_down", "int_global"; + + pinctrl-names = "default"; + pinctrl-0 = <&pcie0_clkreq_default &pcie0_perst_default + &pcie0_wake_default>; + + clkreq-gpio = <&tlmm 36 0>; + perst-gpio = <&tlmm 35 0>; + wake-gpio = <&tlmm 37 0>; + + gdsc-vdd-supply = <&gdsc_pcie_0>; + vreg-1.8-supply = <&pm8994_l12>; + vreg-0.9-supply = <&pm8994_l28>; + + qcom,vreg-0.9-voltage-level = <925000 925000 24000>; + + clocks = <&clock_gcc clk_gcc_pcie_0_pipe_clk>, + <&clock_gcc clk_gcc_pcie_0_cfg_ahb_clk>, + <&clock_gcc clk_gcc_pcie_0_mstr_axi_clk>, + <&clock_gcc clk_gcc_pcie_0_slv_axi_clk>, + <&clock_gcc clk_gcc_pcie_0_aux_clk>, + <&clock_gcc clk_gcc_pcie_clkref_clk>, + <&clock_gcc clk_gcc_pcie_phy_reset>, + <&clock_gcc clk_gcc_pcie_phy_cfg_ahb_clk>, + <&clock_gcc clk_gcc_pcie_phy_aux_clk>; + + clock-names = "pcie_0_pipe_clk", "pcie_0_cfg_ahb_clk", + "pcie_0_mstr_axi_clk", "pcie_0_slv_axi_clk", + "pcie_0_aux_clk", "pcie_0_ldo", "pcie_0_phy_reset", + "pcie_0_phy_cfg_ahb_clk", "pcie_0_phy_aux_clk"; + + resets = <&clock_gcc PCIE_PHY_BCR>, + <&clock_gcc PCIE_PHY_COM_BCR>, + <&clock_gcc PCIE_PHY_NOCSR_COM_PHY_BCR>, + <&clock_gcc PCIE_0_PHY_BCR>; + + reset-names = "pcie_phy_reset", "pcie_phy_com_reset", + "pcie_phy_nocsr_com_phy_reset","pcie_0_phy_reset"; + + max-clock-frequency-hz = <0>, <0>, <0>, <0>, <1010526>, + <0>, <0>, <0>, <0>; + + qcom,msm-bus,name = "pcie-ep"; + qcom,msm-bus,num-cases = <2>; + qcom,msm-bus,num-paths = <1>; + qcom,msm-bus,vectors-KBps = + <45 512 0 0>, + <45 512 500 800>; + + qcom,pcie-link-speed = <0>; + qcom,pcie-phy-ver = <4>; + qcom,pcie-perst-enum; + + qcom,phy-status-reg = <0x448>; + qcom,phy-sequence = <0x400 0x01 0x00 + 0x404 0x01 0x00 + 0x00AC 0x00 0x00 + 0x0034 0x18 0x00 + 0x0174 0x30 0x00 + 0x00B4 0x20 0x00 + 0x1094 0x06 0x00 + 0x00D0 0x19 0x00 + 0x0078 0x3F 0x00 + 0x0084 0x1A 0x00 + 0x0090 0x00 0x00 + 0x010C 0x00 0x00 + 0x0108 0xFF 0x00 + 0x019C 0x01 0x00 + 0x018C 0x00 0x00 + 0x0050 0x04 0x00 + 0x004C 0xff 0x00 + 0x00C8 0x42 0x00 + 0x0128 0x00 0x00 + 0x0148 0x3f 0x00 + 0x0144 0xff 0x00 + 0x000C 0x01 0x00 + 0x0070 0x0f 0x00 + 0x0048 0x0f 0x00 + 0x1248 0x4B 0x00 + 0x120C 0x0A 0x00 + 0x1200 0x0A 0x00 + 0x121C 0x04 0x00 + 0x1210 0x04 0x00 + 0x12D8 0x01 0x00 + 0x12DC 0x00 0x00 + 0x12E0 0xDB 0x00 + 0x12D4 0x77 0x00 + 0x130C 0x80 0x00 + 0x1310 0x1C 0x00 + 0x1314 0x03 0x00 + 0x131C 0x14 0x00 + 0x1054 0x02 0x00 + 0x1068 0x45 0x00 + 0x10AC 0x12 0x00 + 0x0194 0x06 0x00 + 0x1454 0x00 0x00 + 0x1404 0x00 0x00 + 0x400 0x00 0x00 + 0x408 0x03 0x00>; + + status = "disabled"; + }; + qcom_rng: qrng@83000 { compatible = "qcom,msm-rng"; reg = <0x83000 0x1000>; @@ -4018,6 +4167,14 @@ qcom,save-reg; }; + + pps { + compatible = "pps-gpio"; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_pps>; + gpios = <&tlmm 128 0>; + status = "okay"; + }; }; &gdsc_venus { diff --git a/arch/arm64/configs/msm-auto-perf_defconfig b/arch/arm64/configs/msm-auto-perf_defconfig index 6f631287652a..54f46ac4dbf4 100644 --- a/arch/arm64/configs/msm-auto-perf_defconfig +++ b/arch/arm64/configs/msm-auto-perf_defconfig @@ -317,6 +317,11 @@ CONFIG_INPUT_HBTP_INPUT=y CONFIG_INPUT_QPNP_POWER_ON=y CONFIG_INPUT_UINPUT=y CONFIG_INPUT_GPIO=y +CONFIG_BOSCH_DRIVER_LOG_FUNC=y +CONFIG_SENSORS_BMA2X2=y +CONFIG_SENSORS_BMA2X2_ENABLE_INT1=y +CONFIG_SENSORS_BMG=y +CONFIG_SENSORS_BMG_FIFO=y # CONFIG_SERIO_SERPORT is not set # CONFIG_VT is not set # CONFIG_LEGACY_PTYS is not set @@ -514,6 +519,7 @@ CONFIG_SEEMP_CORE=y CONFIG_USB_BAM=y CONFIG_MSM_MDSS_PLL=y CONFIG_REMOTE_SPINLOCK_MSM=y +CONFIG_MSM_TIMER_LEAP=y CONFIG_IOMMU_IO_PGTABLE_FAST=y CONFIG_ARM_SMMU=y CONFIG_IOMMU_DEBUG=y @@ -576,6 +582,11 @@ CONFIG_DEVFREQ_GOV_MEMLAT=y CONFIG_DEVFREQ_SIMPLE_DEV=y CONFIG_QCOM_DEVFREQ_DEVBW=y CONFIG_EXTCON=y +CONFIG_IIO=y +CONFIG_INV_MPU_IIO_IAM20680=y +CONFIG_INV_MPU_IIO_I2C=y +CONFIG_INV_MPU_IIO_SPI=y +CONFIG_INV_TESTING=y CONFIG_PWM=y CONFIG_PWM_QPNP=y CONFIG_ARM_GIC_V3_ACL=y diff --git a/arch/arm64/configs/msm-auto_defconfig b/arch/arm64/configs/msm-auto_defconfig index a45fc1ce832a..eb8a244aef6d 100644 --- a/arch/arm64/configs/msm-auto_defconfig +++ b/arch/arm64/configs/msm-auto_defconfig @@ -318,6 +318,11 @@ CONFIG_INPUT_HBTP_INPUT=y CONFIG_INPUT_QPNP_POWER_ON=y CONFIG_INPUT_UINPUT=y CONFIG_INPUT_GPIO=y +CONFIG_BOSCH_DRIVER_LOG_FUNC=y +CONFIG_SENSORS_BMA2X2=y +CONFIG_SENSORS_BMA2X2_ENABLE_INT1=y +CONFIG_SENSORS_BMG=y +CONFIG_SENSORS_BMG_FIFO=y # CONFIG_SERIO_SERPORT is not set # CONFIG_VT is not set # CONFIG_LEGACY_PTYS is not set @@ -520,6 +525,7 @@ CONFIG_SEEMP_CORE=y CONFIG_USB_BAM=y CONFIG_MSM_MDSS_PLL=y CONFIG_REMOTE_SPINLOCK_MSM=y +CONFIG_MSM_TIMER_LEAP=y CONFIG_IOMMU_IO_PGTABLE_FAST=y CONFIG_IOMMU_IO_PGTABLE_FAST_SELFTEST=y CONFIG_ARM_SMMU=y @@ -585,6 +591,11 @@ CONFIG_DEVFREQ_GOV_MEMLAT=y CONFIG_DEVFREQ_SIMPLE_DEV=y CONFIG_QCOM_DEVFREQ_DEVBW=y CONFIG_EXTCON=y +CONFIG_IIO=y +CONFIG_INV_MPU_IIO_IAM20680=y +CONFIG_INV_MPU_IIO_I2C=y +CONFIG_INV_MPU_IIO_SPI=y +CONFIG_INV_TESTING=y CONFIG_PWM=y CONFIG_PWM_QPNP=y CONFIG_ARM_GIC_V3_ACL=y diff --git a/drivers/gpu/msm/adreno.c b/drivers/gpu/msm/adreno.c index 9cb65033ed13..d2aa0a0f9507 100644 --- a/drivers/gpu/msm/adreno.c +++ b/drivers/gpu/msm/adreno.c @@ -2807,7 +2807,8 @@ static void adreno_suspend_device(struct kgsl_device *device, struct adreno_gpudev *gpudev = ADRENO_GPU_DEVICE(adreno_dev); int pm_event = pm_state.event; - adreno_dispatcher_halt(device); + if (device->state == KGSL_STATE_SUSPEND) + adreno_dispatcher_halt(device); if ((pm_event == PM_EVENT_FREEZE) || (pm_event == PM_EVENT_QUIESCE) || diff --git a/drivers/iio/imu/Kconfig b/drivers/iio/imu/Kconfig index 5e610f7de5aa..903beab85e7e 100644 --- a/drivers/iio/imu/Kconfig +++ b/drivers/iio/imu/Kconfig @@ -37,6 +37,7 @@ config KMX61 be called kmx61. source "drivers/iio/imu/inv_mpu6050/Kconfig" +source "drivers/iio/imu/inv_mpu/Kconfig" endmenu diff --git a/drivers/iio/imu/Makefile b/drivers/iio/imu/Makefile index e1e6e3d70e26..54c282cca986 100644 --- a/drivers/iio/imu/Makefile +++ b/drivers/iio/imu/Makefile @@ -14,5 +14,6 @@ adis_lib-$(CONFIG_IIO_ADIS_LIB_BUFFER) += adis_buffer.o obj-$(CONFIG_IIO_ADIS_LIB) += adis_lib.o obj-y += inv_mpu6050/ +obj-y += inv_mpu/ obj-$(CONFIG_KMX61) += kmx61.o diff --git a/drivers/input/Kconfig b/drivers/input/Kconfig index 2557dcda7621..5987a6c2261b 100644 --- a/drivers/input/Kconfig +++ b/drivers/input/Kconfig @@ -214,6 +214,8 @@ source "drivers/input/touchscreen/Kconfig" source "drivers/input/misc/Kconfig" +source "drivers/input/sensors/bmi160/Kconfig" + endif menu "Hardware I/O ports" diff --git a/drivers/input/Makefile b/drivers/input/Makefile index 2a6d05ab9170..45286b8e4769 100644 --- a/drivers/input/Makefile +++ b/drivers/input/Makefile @@ -28,4 +28,4 @@ obj-$(CONFIG_INPUT_MISC) += misc/ obj-$(CONFIG_INPUT_APMPOWER) += apm-power.o obj-$(CONFIG_INPUT_KEYRESET) += keyreset.o obj-$(CONFIG_INPUT_KEYCOMBO) += keycombo.o - +obj-y += sensors/bmi160/ diff --git a/drivers/media/platform/msm/ais/msm_buf_mgr/msm_generic_buf_mgr.c b/drivers/media/platform/msm/ais/msm_buf_mgr/msm_generic_buf_mgr.c index 66751b1f0657..db41cada4328 100644 --- a/drivers/media/platform/msm/ais/msm_buf_mgr/msm_generic_buf_mgr.c +++ b/drivers/media/platform/msm/ais/msm_buf_mgr/msm_generic_buf_mgr.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2013-2017, The Linux Foundation. All rights reserved. +/* Copyright (c) 2013-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 @@ -554,15 +554,16 @@ static long msm_buf_mngr_subdev_ioctl(struct v4l2_subdev *sd, return -EINVAL; if (!k_ioctl.ioctl_ptr) return -EINVAL; - - MSM_CAM_GET_IOCTL_ARG_PTR(&tmp, &k_ioctl.ioctl_ptr, - sizeof(tmp)); - if (copy_from_user(&buf_info, (void __user *)tmp, - sizeof(struct msm_buf_mngr_info))) { - return -EFAULT; + if (!is_compat_task()) { + MSM_CAM_GET_IOCTL_ARG_PTR(&tmp, + &k_ioctl.ioctl_ptr, sizeof(tmp)); + if (copy_from_user(&buf_info, + (void __user *)tmp, + sizeof(struct msm_buf_mngr_info))) { + return -EFAULT; + } + k_ioctl.ioctl_ptr = (uintptr_t)&buf_info; } - k_ioctl.ioctl_ptr = (uintptr_t)&buf_info; - argp = (void *)&k_ioctl; rc = msm_cam_buf_mgr_ops(cmd, argp); } diff --git a/drivers/net/wireless/cnss2/usb.c b/drivers/net/wireless/cnss2/usb.c index 60d81b10cc84..4310109987b0 100644 --- a/drivers/net/wireless/cnss2/usb.c +++ b/drivers/net/wireless/cnss2/usb.c @@ -108,6 +108,7 @@ int cnss_usb_dev_shutdown(struct cnss_usb_data *usb_priv) switch (usb_priv->device_id) { case QCN7605_COMPOSITE_DEVICE_ID: case QCN7605_STANDALONE_DEVICE_ID: + cnss_usb_call_driver_remove(usb_priv); break; default: cnss_pr_err("Unknown device_id found: 0x%x\n", @@ -175,12 +176,13 @@ int cnss_usb_call_driver_remove(struct cnss_usb_data *usb_priv) if (test_bit(CNSS_DRIVER_RECOVERY, &plat_priv->driver_state) && test_bit(CNSS_DRIVER_PROBED, &plat_priv->driver_state)) { + cnss_pr_dbg("Recovery set after driver probed.Call shutdown\n"); usb_priv->driver_ops->shutdown(usb_priv->usb_intf); } else if (test_bit(CNSS_DRIVER_UNLOADING, &plat_priv->driver_state)) { + cnss_pr_dbg("driver_ops->remove\n"); usb_priv->driver_ops->remove(usb_priv->usb_intf); clear_bit(CNSS_DRIVER_PROBED, &plat_priv->driver_state); } - return 0; } diff --git a/drivers/platform/msm/ep_pcie/ep_pcie_com.h b/drivers/platform/msm/ep_pcie/ep_pcie_com.h index 4b89c8636141..0c3fb1676eea 100644 --- a/drivers/platform/msm/ep_pcie/ep_pcie_com.h +++ b/drivers/platform/msm/ep_pcie/ep_pcie_com.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2015, 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 @@ -101,6 +101,14 @@ #define PCIE20_AUX_CLK_FREQ_REG 0xB40 +#define PCIE20_MHISTATUS 0x148 +#define PCIE20_PARF_MHI_CLOCK_RESET_CTRL 0x174 +#define PCIE20_PARF_CFG_BITS 0x210 + +#define PCIE20_BRIDGE_CTRL_INT_PIN_INT_LINE_REG 0x3C +#define PCIE20_DEVICE_ID_VENDOR_ID_REG 0x0 +#define PCIE20_L1_SUBSTATES_REG 0xB44 + #define PERST_TIMEOUT_US_MIN 1000 #define PERST_TIMEOUT_US_MAX 1000 #define PERST_CHECK_MAX_COUNT 30000 @@ -126,7 +134,7 @@ #define EP_PCIE_LOG_PAGES 50 #define EP_PCIE_MAX_VREG 2 -#define EP_PCIE_MAX_CLK 6 +#define EP_PCIE_MAX_CLK 8 #define EP_PCIE_MAX_PIPE_CLK 1 #define EP_PCIE_ERROR -30655 @@ -255,6 +263,12 @@ struct ep_pcie_irq_info_t { u32 num; }; +struct ep_pcie_phy_info_t { + u32 offset; + u32 val; + u32 delay; +}; + /* pcie endpoint device structure */ struct ep_pcie_dev_t { struct platform_device *pdev; @@ -278,6 +292,9 @@ struct ep_pcie_dev_t { u32 link_speed; bool active_config; bool aggregated_irq; + u32 phy_status_reg; + u32 phy_len; + struct ep_pcie_phy_info_t *phy_sequence; u32 rev; u32 phy_rev; @@ -356,5 +373,7 @@ extern bool ep_pcie_phy_is_ready(struct ep_pcie_dev_t *dev); extern void ep_pcie_reg_dump(struct ep_pcie_dev_t *dev, u32 sel, bool linkdown); extern void ep_pcie_debugfs_init(struct ep_pcie_dev_t *ep_dev); extern void ep_pcie_debugfs_exit(void); - +#ifdef CONFIG_ARCH_MSM8996 +extern void ep_pcie_phy_bringup_port(struct ep_pcie_dev_t *dev); +#endif #endif diff --git a/drivers/platform/msm/ep_pcie/ep_pcie_core.c b/drivers/platform/msm/ep_pcie/ep_pcie_core.c index f3cc96c271a7..f6d39031c5d5 100644 --- a/drivers/platform/msm/ep_pcie/ep_pcie_core.c +++ b/drivers/platform/msm/ep_pcie/ep_pcie_core.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2015, 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 @@ -64,7 +64,9 @@ static struct ep_pcie_clk_info_t {NULL, "pcie_0_slv_axi_clk", 0, true}, {NULL, "pcie_0_aux_clk", 1000000, true}, {NULL, "pcie_0_ldo", 0, true}, - {NULL, "pcie_0_phy_reset", 0, false} + {NULL, "pcie_0_phy_reset", 0, false}, + {NULL, "pcie_0_phy_cfg_ahb_clk", 0, false}, + {NULL, "pcie_0_phy_aux_clk", 0, false} }; static struct ep_pcie_clk_info_t @@ -131,11 +133,18 @@ static int ep_pcie_gpio_init(struct ep_pcie_dev_t *dev) info = &dev->gpio[i]; if (!info->num) { - EP_PCIE_ERR(dev, - "PCIe V%d: the number of gpio %s is invalid\n", - dev->rev, info->name); - rc = -EINVAL; - break; + if (i == EP_PCIE_GPIO_MDM2AP) { + EP_PCIE_DBG(dev, + "PCIe V%d: gpio %s does not exist.\n", + dev->rev, info->name); + continue; + } else { + EP_PCIE_ERR(dev, + "PCIe V%d: the number of gpio %s is invalid\n", + dev->rev, info->name); + rc = -EINVAL; + break; + } } rc = gpio_request(info->num, info->name); @@ -451,6 +460,109 @@ static void ep_pcie_bar_init(struct ep_pcie_dev_t *dev) ep_pcie_write_mask(dev->dm_core + PCIE20_MISC_CONTROL_1, BIT(0), 0); } +#ifdef CONFIG_ARCH_MSM8996 +static void ep_pcie_core_init(struct ep_pcie_dev_t *dev) +{ + u32 regval; + + EP_PCIE_DBG(dev, "PCIe V%d\n", dev->rev); + + /* Configure PCIe to endpoint mode */ + ep_pcie_write_reg(dev->parf, PCIE20_PARF_DEVICE_TYPE, 0x0); + + /* adjust DBI base address */ + writel_relaxed(0x0C000000, dev->parf + PCIE20_PARF_DBI_BASE_ADDR); + + /* Configure PCIe core to support 1GB aperture */ + ep_pcie_write_reg(dev->parf, PCIE20_PARF_SLV_ADDR_SPACE_SIZE, + 0x40000000); + + /* Disable the debouncers */ + ep_pcie_write_reg(dev->parf, PCIE20_PARF_DB_CTRL, 0x73); + + /* Enable Auxiliary Power Detect */ + ep_pcie_write_mask(dev->parf + PCIE20_PARF_SYS_CTRL, 0x10, BIT(4)); + + /* Enable the bit to exit l1ss when sending LTR and MSI */ + ep_pcie_write_mask(dev->parf + PCIE20_PARF_CFG_BITS, 0x2, BIT(1)); + + /* Enable CS for RO(CS) register writes */ + ep_pcie_write_mask(dev->dm_core + PCIE20_MISC_CONTROL_1, 0, BIT(0)); + + /* Set the INT_LINE Register field to 0 */ + ep_pcie_write_mask(dev->dm_core + + PCIE20_BRIDGE_CTRL_INT_PIN_INT_LINE_REG, 0xff, 0); + + /* Set the PMC Register - to support PME in D0, D3hot and D3cold */ + ep_pcie_write_mask(dev->dm_core + PCIE20_CAP_ID_NXT_PTR, + 0xF8000000, BIT(31) | BIT(30) | BIT(27)); + + /* Set the frequency for the AUX clock to 19.2MHz */ + ep_pcie_write_mask(dev->dm_core + PCIE20_AUX_CLK_FREQ_REG, + 0x3FF, BIT(4) | BIT(2)); + + /* Set the Endpoint L0s Acceptable Latency to 1us (max) */ + ep_pcie_write_mask(dev->dm_core + PCIE20_DEVICE_CAPABILITIES, + 0x1C0, BIT(8) | BIT(7) | BIT(6)); + + /* Set the Endpoint L1 Acceptable Latency to 2 us (max) */ + ep_pcie_write_mask(dev->dm_core + PCIE20_DEVICE_CAPABILITIES, + 0xE00, BIT(11) | BIT(10) | BIT(9)); + + /* Set the L0s Exit Latency to 2us-4us = 0x6 */ + ep_pcie_write_mask(dev->dm_core + PCIE20_LINK_CAPABILITIES, + 0x38000, BIT(17) | BIT(16)); + + /* Set the L1 Exit Latency to be 32us-64 us = 0x6 */ + ep_pcie_write_mask(dev->dm_core + PCIE20_LINK_CAPABILITIES, + 0x7000, BIT(14) | BIT(13)); + + /* Enable Clock Power Management */ + ep_pcie_write_mask(dev->dm_core + PCIE20_LINK_CAPABILITIES, + 0x40000, BIT(18)); + + /* Disable CS for RO(CS) register writes */ + ep_pcie_write_mask(dev->dm_core + PCIE20_MISC_CONTROL_1, BIT(0), 0); + + /* Enable writes for RO(CS2) */ + ep_pcie_write_mask(dev->elbi + PCIE20_ELBI_CS2_ENABLE, 0, BIT(0)); + + /* Set the Common Clock L0s Exit Latency to 2us-4us = 0x6 */ + ep_pcie_write_mask(dev->dm_core + PCIE20_LINK_CAPABILITIES, + 0x38000, BIT(17) | BIT(16)); + + /* Set the Common Clock L1 Exit Latency to be 32us-64 us = 0x6 */ + ep_pcie_write_mask(dev->dm_core + PCIE20_LINK_CAPABILITIES, + 0x7000, BIT(14) | BIT(13)); + + /* Disable writes for RO(CS2) */ + ep_pcie_write_mask(dev->elbi + PCIE20_ELBI_CS2_ENABLE, BIT(0), 0); + + /* T_Power_Off */ + ep_pcie_write_mask(dev->dm_core + PCIE20_L1_SUBSTATES_REG, + BIT(1) | BIT(0), 0); + + /* Set Device ID and Vendor ID */ + ep_pcie_write_mask(dev->dm_core + PCIE20_MISC_CONTROL_1, 0, BIT(0)); + ep_pcie_write_reg(dev->dm_core, PCIE20_DEVICE_ID_VENDOR_ID_REG, + 0x030217cb); + ep_pcie_write_mask(dev->dm_core + PCIE20_MISC_CONTROL_1, BIT(0), 0); + + /* Configure link speed */ + ep_pcie_write_mask(dev->dm_core + PCIE20_LINK_CONTROL2_LINK_STATUS2, + 0xf, dev->link_speed); + + /* Configure BARs */ + ep_pcie_bar_init(dev); + + /* Enable MHI clocks */ + ep_pcie_write_reg(dev->parf, PCIE20_PARF_MHI_CLOCK_RESET_CTRL, + BIT(1) | BIT(0)); + + ep_pcie_write_reg(dev->mmio, PCIE20_MHISTATUS, 0x0); + ep_pcie_write_reg(dev->mmio, PCIE20_BHI_EXECENV, 0x2); +} +#else static void ep_pcie_core_init(struct ep_pcie_dev_t *dev) { EP_PCIE_DBG(dev, "PCIe V%d\n", dev->rev); @@ -578,6 +690,7 @@ static void ep_pcie_core_init(struct ep_pcie_dev_t *dev) ep_pcie_write_reg(dev->dm_core, PCIE20_AUX_CLK_FREQ_REG, 0x14); } +#endif static void ep_pcie_config_inbound_iatu(struct ep_pcie_dev_t *dev) { @@ -694,6 +807,32 @@ static int ep_pcie_get_resources(struct ep_pcie_dev_t *dev, EP_PCIE_DBG(dev, "PCIe V%d\n", dev->rev); + of_get_property(pdev->dev.of_node, "qcom,phy-sequence", &cnt); + if (cnt) { + dev->phy_sequence = (struct ep_pcie_phy_info_t *) + devm_kzalloc(&pdev->dev, cnt, GFP_KERNEL); + + if (dev->phy_sequence) { + dev->phy_len = + cnt / sizeof(*dev->phy_sequence); + + of_property_read_u32_array(pdev->dev.of_node, + "qcom,phy-sequence", + (unsigned int *)dev->phy_sequence, + cnt / sizeof(dev->phy_sequence->offset)); + } else { + EP_PCIE_ERR(dev, + "PCIe V%d: Failed to alloc mem for phy seq.\n", + dev->rev); + ret = -ENOMEM; + goto out; + } + } else { + EP_PCIE_DBG(dev, + "PCIe V%d: phy sequence is not present in DT.\n", + dev->rev); + } + cnt = of_property_count_strings((&pdev->dev)->of_node, "clock-names"); if (cnt > 0) { @@ -782,6 +921,7 @@ static int ep_pcie_get_resources(struct ep_pcie_dev_t *dev, EP_PCIE_DBG(dev, "GPIO %s is not supported in this configuration.\n", gpio_info->name); + ret = 0; } } @@ -1070,6 +1210,9 @@ int ep_pcie_core_enable_endpoint(enum ep_pcie_options opt) EP_PCIE_INFO(dev, "PCIe V%d: PCIe PHY is ready!\n", dev->rev); } +#ifdef CONFIG_ARCH_MSM8996 + ep_pcie_phy_bringup_port(dev); +#endif ep_pcie_core_init(dev); ep_pcie_config_inbound_iatu(dev); @@ -1977,6 +2120,17 @@ static int ep_pcie_probe(struct platform_device *pdev) EP_PCIE_DBG(&ep_pcie_dev, "PCIe V%d: pcie-link-speed:%d.\n", ep_pcie_dev.rev, ep_pcie_dev.link_speed); + ret = of_property_read_u32((&pdev->dev)->of_node, + "qcom,phy-status-reg", + &ep_pcie_dev.phy_status_reg); + if (ret) + EP_PCIE_DBG(&ep_pcie_dev, + "PCIe V%d: phy-status-reg does not exist.\n", + ep_pcie_dev.rev); + else + EP_PCIE_DBG(&ep_pcie_dev, "PCIe V%d: phy-status-reg:0x%x.\n", + ep_pcie_dev.rev, ep_pcie_dev.phy_status_reg); + ep_pcie_dev.phy_rev = 1; ret = of_property_read_u32((&pdev->dev)->of_node, "qcom,pcie-phy-ver", diff --git a/drivers/platform/msm/ep_pcie/ep_pcie_phy.c b/drivers/platform/msm/ep_pcie/ep_pcie_phy.c index 83e74f2c7ba7..3dfabd3ed81f 100644 --- a/drivers/platform/msm/ep_pcie/ep_pcie_phy.c +++ b/drivers/platform/msm/ep_pcie/ep_pcie_phy.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2015, 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 @@ -13,6 +13,7 @@ /* * MSM PCIe PHY endpoint mode */ +#include <linux/delay.h> #include "ep_pcie_com.h" #include "ep_pcie_phy.h" @@ -23,6 +24,28 @@ void ep_pcie_phy_init(struct ep_pcie_dev_t *dev) "PCIe V%d: PHY V%d: Initializing 14nm QMP phy - 100MHz\n", dev->rev, dev->phy_rev); + if (dev->phy_sequence) { + int i; + struct ep_pcie_phy_info_t *phy_seq; + + EP_PCIE_DBG(dev, + "PCIe V%d: PHY V%d: process the sequence specified by DT.!\n", + dev->rev, dev->phy_rev); + + i = dev->phy_len; + phy_seq = dev->phy_sequence; + while (i--) { + ep_pcie_write_reg(dev->phy, + phy_seq->offset, + phy_seq->val); + if (phy_seq->delay) + usleep_range(phy_seq->delay, + phy_seq->delay + 1); + phy_seq++; + } + return; + } + ep_pcie_write_reg(dev->phy, PCIE_PHY_SW_RESET, 0x01); ep_pcie_write_reg(dev->phy, PCIE_PHY_POWER_DOWN_CONTROL, 0x01); @@ -104,10 +127,26 @@ void ep_pcie_phy_init(struct ep_pcie_dev_t *dev) ep_pcie_write_reg(dev->phy, PCIE_PHY_START_CONTROL, 0x03); } +#ifdef CONFIG_ARCH_MSM8996 +void ep_pcie_phy_bringup_port(struct ep_pcie_dev_t *dev) +{ + ep_pcie_write_reg(dev->phy, PCIE_PORT_POWER_DOWN_CONTROL, 0x03); + ep_pcie_write_reg(dev->phy, PCIE_PORT_SW_RESET, 0x0); + ep_pcie_write_reg(dev->phy, PCIE_PORT_START_CONTROL, 0x0a); +} +#endif + bool ep_pcie_phy_is_ready(struct ep_pcie_dev_t *dev) { - if (readl_relaxed(dev->phy + PCIE_PHY_PCS_STATUS) & BIT(6)) - return false; + u32 offset; + + if (dev->phy_status_reg) + offset = dev->phy_status_reg; else + offset = PCIE_PHY_PCS_STATUS; + + if (readl_relaxed(dev->phy + offset) & BIT(0)) return true; + else + return false; } diff --git a/drivers/platform/msm/ep_pcie/ep_pcie_phy.h b/drivers/platform/msm/ep_pcie/ep_pcie_phy.h index 199e0760956a..884f9fdf7dba 100644 --- a/drivers/platform/msm/ep_pcie/ep_pcie_phy.h +++ b/drivers/platform/msm/ep_pcie/ep_pcie_phy.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2015, 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 @@ -460,4 +460,34 @@ #define PCIE_PHY_LFPS_PER_TIMER_VAL 0x9EC #define PCIE_PHY_SIGDET_STARTUP_TIMER_VAL 0x9F0 #define PCIE_PHY_LOCK_DETECT_CONFIG4 0x9F4 +#ifdef CONFIG_ARCH_MSM8996 +#define QSERDES_TX_RES_CODE_LANE_OFFSET 0x1054 +#define QSERDES_TX_HIGHZ_TRANSCEIVEREN_BIAS_DRVR_EN 0x1068 +#define QSERDES_TX_LANE_MODE 0x1094 +#define QSERDES_TX_RCV_DETECT_LVL_2 0x10AC +#define QSERDES_RX_UCDR_FO_GAIN_HALF 0x1200 +#define QSERDES_RX_UCDR_FO_GAIN 0x120C +#define QSERDES_RX_UCDR_SO_GAIN_HALF 0x1210 +#define QSERDES_RX_UCDR_SO_GAIN 0x121C +#define QSERDES_RX_UCDR_SO_SATURATION_AND_ENABLE 0x1248 +#define QSERDES_RX_RX_EQU_ADAPTOR_CNTRL1 0x12D4 +#define QSERDES_RX_RX_EQU_ADAPTOR_CNTRL2 0x12D8 +#define QSERDES_RX_RX_EQU_ADAPTOR_CNTRL3 0x12DC +#define QSERDES_RX_RX_EQU_ADAPTOR_CNTRL4 0x12E0 +#define QSERDES_RX_RX_OFFSET_ADAPTOR_CNTRL2 0x130C +#define QSERDES_RX_SIGDET_ENABLES 0x1310 +#define QSERDES_RX_SIGDET_CNTRL 0x1314 +#define QSERDES_RX_SIGDET_LVL 0x1318 +#define QSERDES_RX_SIGDET_DEGLITCH_CNTRL 0x131C +#define PCIE_PHY_SW_RESET 0x400 +#define PCIE_PHY_POWER_DOWN_CONTROL 0x404 +#define PCIE_PHY_START_CONTROL 0x408 +#define PCIE_PHY_ENDPOINT_REFCLK_DRIVE 0x1454 +#define PCIE_PHY_PWRUP_RESET_DLY_TIME_AUXCLK 0x14A0 +#define PCIE_PORT_ENDPOINT_REFCLK_DRIVE 0x1454 +#define PCIE_PORT_POWER_DOWN_CONTROL 0x1404 +#define PCIE_PORT_SW_RESET 0x1400 +#define PCIE_PORT_START_CONTROL 0x1408 +#define PCIE_COM_PCS_READY_STATUS 0x448 +#endif #endif diff --git a/drivers/soc/qcom/glink_smem_native_xprt.c b/drivers/soc/qcom/glink_smem_native_xprt.c index c78c8a00aa21..e532f071c9ee 100644 --- a/drivers/soc/qcom/glink_smem_native_xprt.c +++ b/drivers/soc/qcom/glink_smem_native_xprt.c @@ -2442,6 +2442,7 @@ static int glink_smem_native_probe(struct platform_device *pdev) } einfo->irq_line = irq_line; + einfo->in_ssr = true; rc = request_irq(irq_line, irq_handler, IRQF_TRIGGER_RISING | IRQF_NO_SUSPEND | IRQF_SHARED, node->name, einfo); @@ -2450,7 +2451,6 @@ static int glink_smem_native_probe(struct platform_device *pdev) rc); goto request_irq_fail; } - einfo->in_ssr = true; rc = enable_irq_wake(irq_line); if (rc < 0) pr_err("%s: enable_irq_wake() failed on %d\n", __func__, diff --git a/drivers/soc/qcom/hab/hab.c b/drivers/soc/qcom/hab/hab.c index ebe7dfc4a5b6..b6dfe2d9ae22 100644 --- a/drivers/soc/qcom/hab/hab.c +++ b/drivers/soc/qcom/hab/hab.c @@ -209,14 +209,15 @@ void hab_ctx_free(struct kref *ref) * the local ioctl access based on ctx */ struct virtual_channel *hab_get_vchan_fromvcid(int32_t vcid, - struct uhab_context *ctx) + struct uhab_context *ctx, int ignore_remote) { struct virtual_channel *vchan; read_lock(&ctx->ctx_lock); list_for_each_entry(vchan, &ctx->vchannels, node) { if (vcid == vchan->id) { - if (vchan->otherend_closed || vchan->closed || + if ((ignore_remote ? 0 : 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, @@ -550,7 +551,7 @@ long hab_vchan_send(struct uhab_context *ctx, return -EINVAL; } - vchan = hab_get_vchan_fromvcid(vcid, ctx); + vchan = hab_get_vchan_fromvcid(vcid, ctx, 0); if (!vchan || vchan->otherend_closed) { ret = -ENODEV; goto err; @@ -565,6 +566,14 @@ long hab_vchan_send(struct uhab_context *ctx, sizeof(struct habmm_xing_vm_stat)); return -EINVAL; } + } else if (flags & HABMM_SOCKET_XVM_SCHE_TEST) { + HAB_HEADER_SET_TYPE(header, HAB_PAYLOAD_TYPE_SCHE_MSG); + } else if (flags & HABMM_SOCKET_XVM_SCHE_TEST_ACK) { + HAB_HEADER_SET_TYPE(header, HAB_PAYLOAD_TYPE_SCHE_MSG_ACK); + } else if (flags & HABMM_SOCKET_XVM_SCHE_RESULT_REQ) { + HAB_HEADER_SET_TYPE(header, HAB_PAYLOAD_TYPE_SCHE_RESULT_REQ); + } else if (flags & HABMM_SOCKET_XVM_SCHE_RESULT_RSP) { + HAB_HEADER_SET_TYPE(header, HAB_PAYLOAD_TYPE_SCHE_RESULT_RSP); } else { HAB_HEADER_SET_TYPE(header, HAB_PAYLOAD_TYPE_MSG); } @@ -597,9 +606,9 @@ int hab_vchan_recv(struct uhab_context *ctx, int ret = 0; int nonblocking_flag = flags & HABMM_SOCKET_RECV_FLAGS_NON_BLOCKING; - vchan = hab_get_vchan_fromvcid(vcid, ctx); + vchan = hab_get_vchan_fromvcid(vcid, ctx, 1); if (!vchan) { - pr_err("vcid %X, vchan %p ctx %p\n", vcid, vchan, ctx); + pr_err("vcid %X vchan 0x%pK ctx %pK\n", vcid, vchan, ctx); return -ENODEV; } @@ -719,24 +728,20 @@ void hab_vchan_close(struct uhab_context *ctx, int32_t vcid) write_lock(&ctx->ctx_lock); list_for_each_entry_safe(vchan, tmp, &ctx->vchannels, node) { if (vchan->id == vcid) { - write_unlock(&ctx->ctx_lock); + /* local close starts */ + vchan->closed = 1; + + /* vchan is not in this ctx anymore */ + list_del(&vchan->node); + ctx->vcnt--; + pr_debug("vcid %x remote %x session %d refcnt %d\n", vchan->id, vchan->otherend_id, vchan->session_id, get_refcnt(vchan->refcount)); - /* - * only set when vc close is called locally by user - * explicity. Used to block remote msg. if forked once - * before, this local close is skipped due to child - * usage. if forked but not closed locally, the local - * context could NOT be closed, vchan can be prolonged - * by arrived remote msgs - */ - if (vchan->forked) - vchan->forked = 0; - else { - vchan->closed = 1; - hab_vchan_stop_notify(vchan); - } + + write_unlock(&ctx->ctx_lock); + /* unblocking blocked in-calls */ + hab_vchan_stop_notify(vchan); hab_vchan_put(vchan); /* there is a lock inside */ write_lock(&ctx->ctx_lock); break; @@ -1079,25 +1084,14 @@ static int hab_release(struct inode *inodep, struct file *filep) write_lock(&ctx->ctx_lock); /* 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 */ + /* local close starts */ + vchan->closed = 1; - 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; + list_del(&vchan->node); /* vchan is not in this ctx anymore */ + ctx->vcnt--; write_unlock(&ctx->ctx_lock); + hab_vchan_stop_notify(vchan); hab_vchan_put(vchan); /* there is a lock inside */ write_lock(&ctx->ctx_lock); } @@ -1117,12 +1111,6 @@ static int hab_release(struct inode *inodep, struct file *filep) hab_ctx_put(ctx); filep->private_data = NULL; - /* ctx leak check */ - if (get_refcnt(ctx->refcount)) - pr_warn("pending ctx release owner %d refcnt %d total %d\n", - ctx->owner, get_refcnt(ctx->refcount), - hab_driver.ctx_cnt); - return 0; } @@ -1134,7 +1122,7 @@ static long hab_ioctl(struct file *filep, unsigned int cmd, unsigned long arg) struct hab_recv *recv_param; struct hab_send *send_param; struct hab_info *info_param; - struct hab_message *msg; + struct hab_message *msg = NULL; void *send_data; unsigned char data[256] = { 0 }; long ret = 0; diff --git a/drivers/soc/qcom/hab/hab.h b/drivers/soc/qcom/hab/hab.h index cbc049e89d63..7d0c5f2673a2 100644 --- a/drivers/soc/qcom/hab/hab.h +++ b/drivers/soc/qcom/hab/hab.h @@ -58,6 +58,10 @@ enum hab_payload_type { HAB_PAYLOAD_TYPE_PROFILE, HAB_PAYLOAD_TYPE_CLOSE, HAB_PAYLOAD_TYPE_INIT_CANCEL, + HAB_PAYLOAD_TYPE_SCHE_MSG, + HAB_PAYLOAD_TYPE_SCHE_MSG_ACK, + HAB_PAYLOAD_TYPE_SCHE_RESULT_REQ, + HAB_PAYLOAD_TYPE_SCHE_RESULT_RSP, HAB_PAYLOAD_TYPE_MAX, }; #define LOOPBACK_DOM 0xFF @@ -214,6 +218,7 @@ struct physical_channel { /* debug only */ uint32_t sequence_tx; uint32_t sequence_rx; + uint32_t status; /* vchans on this pchan */ struct list_head vchannels; @@ -255,8 +260,8 @@ struct hab_export_ack_recvd { }; struct hab_message { - size_t sizebytes; struct list_head node; + size_t sizebytes; uint32_t data[]; }; @@ -493,7 +498,7 @@ struct virtual_channel *hab_vchan_get(struct physical_channel *pchan, void hab_vchan_put(struct virtual_channel *vchan); struct virtual_channel *hab_get_vchan_fromvcid(int32_t vcid, - struct uhab_context *ctx); + struct uhab_context *ctx, int ignore_remote); struct physical_channel *hab_pchan_alloc(struct hab_device *habdev, int otherend_id); struct physical_channel *hab_pchan_find_domid(struct hab_device *dev, diff --git a/drivers/soc/qcom/hab/hab_mem_linux.c b/drivers/soc/qcom/hab/hab_mem_linux.c index 60156c6b00f0..670efdea212f 100644 --- a/drivers/soc/qcom/hab/hab_mem_linux.c +++ b/drivers/soc/qcom/hab/hab_mem_linux.c @@ -53,6 +53,14 @@ static struct pages_list *pages_list_create( if (!pfn_table) return ERR_PTR(-EINVAL); + pfn = pfn_table->first_pfn; + if (pfn_valid(pfn) == 0 || page_is_ram(pfn) == 0) { + pr_err("imp sanity failed pfn %lx valid %d ram %d pchan %s\n", + pfn, pfn_valid(pfn), + page_is_ram(pfn), exp->pchan->name); + return ERR_PTR(-EINVAL); + } + size = exp->payload_count * sizeof(struct page *); pages = kmalloc(size, GFP_KERNEL); if (!pages) @@ -64,7 +72,6 @@ static struct pages_list *pages_list_create( 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); diff --git a/drivers/soc/qcom/hab/hab_mimex.c b/drivers/soc/qcom/hab/hab_mimex.c index efa4bb383ec6..b03739974390 100644 --- a/drivers/soc/qcom/hab/hab_mimex.c +++ b/drivers/soc/qcom/hab/hab_mimex.c @@ -246,7 +246,7 @@ int hab_mem_export(struct uhab_context *ctx, if (!ctx || !param || !param->buffer) return -EINVAL; - vchan = hab_get_vchan_fromvcid(param->vcid, ctx); + vchan = hab_get_vchan_fromvcid(param->vcid, ctx, 0); if (!vchan || !vchan->pchan) { ret = -ENODEV; goto err; @@ -277,8 +277,8 @@ int hab_mem_export(struct uhab_context *ctx, &pdata_size); } if (ret < 0) { - pr_err("habmem_hyp_grant failed size=%d ret=%d\n", - pdata_size, ret); + pr_err("habmem_hyp_grant vc %x failed size=%d ret=%d\n", + param->vcid, pdata_size, ret); goto err; } @@ -313,7 +313,7 @@ int hab_mem_unexport(struct uhab_context *ctx, return -EINVAL; /* refcnt on the access */ - vchan = hab_get_vchan_fromvcid(param->vcid, ctx); + vchan = hab_get_vchan_fromvcid(param->vcid, ctx, 1); if (!vchan || !vchan->pchan) { ret = -ENODEV; goto err_novchan; @@ -360,7 +360,7 @@ int hab_mem_import(struct uhab_context *ctx, if (!ctx || !param) return -EINVAL; - vchan = hab_get_vchan_fromvcid(param->vcid, ctx); + vchan = hab_get_vchan_fromvcid(param->vcid, ctx, 0); if (!vchan || !vchan->pchan) { ret = -ENODEV; goto err_imp; @@ -420,7 +420,7 @@ int hab_mem_unimport(struct uhab_context *ctx, if (!ctx || !param) return -EINVAL; - vchan = hab_get_vchan_fromvcid(param->vcid, ctx); + vchan = hab_get_vchan_fromvcid(param->vcid, ctx, 1); if (!vchan || !vchan->pchan) { if (vchan) hab_vchan_put(vchan); diff --git a/drivers/soc/qcom/hab/hab_msg.c b/drivers/soc/qcom/hab/hab_msg.c index 71010be414d5..e0f4970ce14e 100644 --- a/drivers/soc/qcom/hab/hab_msg.c +++ b/drivers/soc/qcom/hab/hab_msg.c @@ -27,6 +27,12 @@ hab_msg_alloc(struct physical_channel *pchan, size_t sizebytes) { struct hab_message *message; + if (sizebytes > HAB_HEADER_SIZE_MASK) { + pr_err("pchan %s send size too large %zd\n", + pchan->name, sizebytes); + return NULL; + } + message = kzalloc(sizeof(*message) + sizebytes, GFP_ATOMIC); if (!message) return NULL; @@ -153,6 +159,12 @@ static int hab_receive_create_export_ack(struct physical_channel *pchan, pr_err("exp ack size %zu is not as arrived %zu\n", sizeof(ack_recvd->ack), sizebytes); + if (sizebytes > HAB_HEADER_SIZE_MASK) { + pr_err("pchan %s read size too large %zd\n", + pchan->name, sizebytes); + return -EINVAL; + } + if (physical_channel_read(pchan, &ack_recvd->ack, sizebytes) != sizebytes) @@ -169,6 +181,11 @@ static void hab_msg_drop(struct physical_channel *pchan, size_t sizebytes) { uint8_t *data = NULL; + if (sizebytes > HAB_HEADER_SIZE_MASK) { + pr_err("%s read size too large %zd\n", pchan->name, sizebytes); + return; + } + data = kmalloc(sizebytes, GFP_ATOMIC); if (data == NULL) return; @@ -189,6 +206,7 @@ int hab_msg_recv(struct physical_channel *pchan, struct virtual_channel *vchan = NULL; struct export_desc *exp_desc; struct timeval tv; + unsigned long long rx_mpm_tv; /* get the local virtual channel if it isn't an open message */ if (payload_type != HAB_PAYLOAD_TYPE_INIT && @@ -210,7 +228,7 @@ int hab_msg_recv(struct physical_channel *pchan, */ vchan = hab_vchan_get(pchan, header); if (!vchan) { - pr_info("vchan is not found, payload type %d, vchan id %x, sizebytes %zx, session %d\n", + pr_debug("vchan not found type %d vcid %x sz %zx sesn %d\n", payload_type, vchan_id, sizebytes, session_id); if (sizebytes) { @@ -245,6 +263,8 @@ int hab_msg_recv(struct physical_channel *pchan, switch (payload_type) { case HAB_PAYLOAD_TYPE_MSG: + case HAB_PAYLOAD_TYPE_SCHE_RESULT_REQ: + case HAB_PAYLOAD_TYPE_SCHE_RESULT_RSP: message = hab_msg_alloc(pchan, sizebytes); if (!message) break; @@ -275,6 +295,12 @@ int hab_msg_recv(struct physical_channel *pchan, break; case HAB_PAYLOAD_TYPE_EXPORT: + if (sizebytes > HAB_HEADER_SIZE_MASK) { + pr_err("%s exp size too large %zd\n", + pchan->name, sizebytes); + break; + } + exp_desc = kzalloc(sizebytes, GFP_ATOMIC); if (!exp_desc) break; @@ -313,7 +339,7 @@ int hab_msg_recv(struct physical_channel *pchan, case HAB_PAYLOAD_TYPE_CLOSE: /* remote request close */ - pr_info("remote request close vcid %pK %X other id %X session %d refcnt %d\n", + pr_debug("remote close vcid %pK %X other id %X session %d refcnt %d\n", vchan, vchan->id, vchan->otherend_id, session_id, get_refcnt(vchan->refcount)); hab_vchan_stop(vchan); @@ -334,6 +360,19 @@ int hab_msg_recv(struct physical_channel *pchan, } break; + case HAB_PAYLOAD_TYPE_SCHE_MSG: + case HAB_PAYLOAD_TYPE_SCHE_MSG_ACK: + rx_mpm_tv = msm_timer_get_sclk_ticks(); + /* pull down the incoming data */ + message = hab_msg_alloc(pchan, sizebytes); + if (!message) + pr_err("failed to allocate msg Arrived msg will be lost\n"); + else { + ((unsigned long long *)message->data)[0] = rx_mpm_tv; + hab_msg_queue(vchan, message); + } + break; + default: pr_err("unknown msg received, payload type %d, vchan id %x, sizebytes %zx, session %d\n", payload_type, vchan_id, sizebytes, session_id); diff --git a/drivers/soc/qcom/hab/hab_open.c b/drivers/soc/qcom/hab/hab_open.c index f09a1df8aa57..bc2b774883f4 100644 --- a/drivers/soc/qcom/hab/hab_open.c +++ b/drivers/soc/qcom/hab/hab_open.c @@ -47,6 +47,12 @@ int hab_open_request_add(struct physical_channel *pchan, struct hab_open_request *request; struct timeval tv; + if (sizebytes > HAB_HEADER_SIZE_MASK) { + pr_err("pchan %s request size too large %zd\n", + pchan->name, sizebytes); + return -EINVAL; + } + node = kzalloc(sizeof(*node), GFP_ATOMIC); if (!node) return -ENOMEM; @@ -187,6 +193,12 @@ int hab_open_receive_cancel(struct physical_channel *pchan, int bfound = 0; struct timeval tv; + if (sizebytes > HAB_HEADER_SIZE_MASK) { + pr_err("pchan %s cancel size too large %zd\n", + pchan->name, sizebytes); + return -EINVAL; + } + if (physical_channel_read(pchan, &data, sizebytes) != sizebytes) return -EIO; diff --git a/drivers/soc/qcom/hab/hab_stat.c b/drivers/soc/qcom/hab/hab_stat.c index f0a4207bc871..b78e5e7e9867 100644 --- a/drivers/soc/qcom/hab/hab_stat.c +++ b/drivers/soc/qcom/hab/hab_stat.c @@ -61,14 +61,17 @@ int hab_stat_show_vchan(struct hab_driver *driver, continue; ret = hab_stat_buffer_print(buf, size, - "mmid %s role %d local %d remote %d vcnt %d:\n", + "nm %s r %d lc %d rm %d sq_t %d sq_r %d st 0x%x vn %d:\n", pchan->name, pchan->is_be, pchan->vmid_local, - pchan->vmid_remote, pchan->vcnt); + pchan->vmid_remote, pchan->sequence_tx, + pchan->sequence_rx, pchan->status, pchan->vcnt); read_lock(&pchan->vchans_lock); list_for_each_entry(vc, &pchan->vchannels, pnode) { ret = hab_stat_buffer_print(buf, size, - "%08X ", vc->id); + "%08X(%d:%d) ", vc->id, + get_refcnt(vc->refcount), + vc->otherend_closed); } ret = hab_stat_buffer_print(buf, size, "\n"); read_unlock(&pchan->vchans_lock); diff --git a/drivers/soc/qcom/hab/hab_vchan.c b/drivers/soc/qcom/hab/hab_vchan.c index 8d818b8fafb1..a95d6c7451c9 100644 --- a/drivers/soc/qcom/hab/hab_vchan.c +++ b/drivers/soc/qcom/hab/hab_vchan.c @@ -85,9 +85,6 @@ hab_vchan_free(struct kref *ref) } spin_unlock_bh(&vchan->rx_lock); - /* 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 */ - /* release vchan from pchan. no more msg for this vchan */ write_lock_bh(&pchan->vchans_lock); list_for_each_entry_safe(vc, vc_tmp, &pchan->vchannels, pnode) { @@ -100,6 +97,9 @@ hab_vchan_free(struct kref *ref) } write_unlock_bh(&pchan->vchans_lock); + /* 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 */ + /* release idr at the last so same idr will not be used early */ spin_lock_bh(&pchan->vid_lock); idr_remove(&pchan->vchan_idr, HAB_VCID_GET_ID(vchan->id)); @@ -167,6 +167,7 @@ hab_vchan_get(struct physical_channel *pchan, struct hab_header *header) return vchan; } +/* wake up local waiting Q, so stop-vchan can be processed */ void hab_vchan_stop(struct virtual_channel *vchan) { if (vchan) { @@ -190,6 +191,7 @@ void hab_vchans_stop(struct physical_channel *pchan) read_unlock(&pchan->vchans_lock); } +/* send vchan close to remote and stop receiving anything locally */ void hab_vchan_stop_notify(struct virtual_channel *vchan) { hab_send_close_msg(vchan); @@ -204,15 +206,22 @@ static int hab_vchans_per_pchan_empty(struct physical_channel *pchan) empty = list_empty(&pchan->vchannels); if (!empty) { struct virtual_channel *vchan; + int vcnt = pchan->vcnt; 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); + /* discount open-pending unpaired vchan */ + if (!vchan->session_id) + vcnt--; + else + pr_err("vchan %pK %x rm %x sn %d rf %d clsd %d rm clsd %d\n", + vchan, vchan->id, + vchan->otherend_id, + vchan->session_id, + get_refcnt(vchan->refcount), + vchan->closed, vchan->otherend_closed); } - + if (!vcnt) + empty = 1;/* unpaired vchan can exist at init time */ } read_unlock(&pchan->vchans_lock); @@ -265,48 +274,18 @@ int hab_vchan_find_domid(struct virtual_channel *vchan) return vchan ? vchan->pchan->dom_id : -1; } -/* this sould be only called once after refcnt is zero */ -static void hab_vchan_schedule_free(struct kref *ref) -{ - struct virtual_channel *vchanin = - container_of(ref, struct virtual_channel, refcount); - struct uhab_context *ctx = vchanin->ctx; - struct virtual_channel *vchan, *tmp; - int bnotify = 0; - - /* - * similar logic is in ctx free. if ctx free runs first, - * this is skipped - */ - write_lock_bh(&ctx->ctx_lock); - list_for_each_entry_safe(vchan, tmp, &ctx->vchannels, node) { - if (vchan == vchanin) { - pr_debug("vchan free refcnt = %d\n", - get_refcnt(vchan->refcount)); - ctx->vcnt--; - list_del(&vchan->node); - bnotify = 1; - break; - } - } - write_unlock_bh(&ctx->ctx_lock); - - if (bnotify) - hab_vchan_stop_notify(vchan); - - hab_vchan_free(ref); -} - void hab_vchan_put(struct virtual_channel *vchan) { if (vchan) - kref_put(&vchan->refcount, hab_vchan_schedule_free); + kref_put(&vchan->refcount, hab_vchan_free); } int hab_vchan_query(struct uhab_context *ctx, int32_t vcid, uint64_t *ids, char *names, size_t name_size, uint32_t flags) { - struct virtual_channel *vchan = hab_get_vchan_fromvcid(vcid, ctx); + struct virtual_channel *vchan; + + vchan = hab_get_vchan_fromvcid(vcid, ctx, 1); if (!vchan) return -EINVAL; diff --git a/drivers/soc/qcom/hab/qvm_comm.c b/drivers/soc/qcom/hab/qvm_comm.c index cce24d72c28e..25d0208dea4c 100644 --- a/drivers/soc/qcom/hab/qvm_comm.c +++ b/drivers/soc/qcom/hab/qvm_comm.c @@ -13,6 +13,8 @@ #include "hab.h" #include "hab_qvm.h" +static unsigned long long xvm_sche_tx_tv_buffer[2]; + inline void habhyp_notify(void *commdev) { struct qvm_channel *dev = (struct qvm_channel *)commdev; @@ -56,6 +58,7 @@ int physical_channel_send(struct physical_channel *pchan, return -EAGAIN; /* not enough free space */ } + header->sequence = pchan->sequence_tx + 1; header->signature = HAB_HEAD_SIGNATURE; if (hab_pipe_write(dev->pipe_ep, @@ -78,6 +81,12 @@ int physical_channel_send(struct physical_channel *pchan, spin_unlock_bh(&dev->io_lock); return -EINVAL; } + } else if (HAB_HEADER_GET_TYPE(*header) + == HAB_PAYLOAD_TYPE_SCHE_RESULT_REQ) { + ((unsigned long long *)payload)[0] = xvm_sche_tx_tv_buffer[0]; + } else if (HAB_HEADER_GET_TYPE(*header) + == HAB_PAYLOAD_TYPE_SCHE_RESULT_RSP) { + ((unsigned long long *)payload)[2] = xvm_sche_tx_tv_buffer[1]; } if (sizebytes) { @@ -91,8 +100,12 @@ int physical_channel_send(struct physical_channel *pchan, hab_pipe_write_commit(dev->pipe_ep); spin_unlock_bh(&dev->io_lock); + if (HAB_HEADER_GET_TYPE(*header) == HAB_PAYLOAD_TYPE_SCHE_MSG) + xvm_sche_tx_tv_buffer[0] = msm_timer_get_sclk_ticks(); + else if (HAB_HEADER_GET_TYPE(*header) == HAB_PAYLOAD_TYPE_SCHE_MSG_ACK) + xvm_sche_tx_tv_buffer[1] = msm_timer_get_sclk_ticks(); habhyp_notify(dev); - + ++pchan->sequence_tx; return 0; } @@ -117,6 +130,8 @@ void physical_channel_rx_dispatch(unsigned long data) header.sequence); } + pchan->sequence_rx = header.sequence; + hab_msg_recv(pchan, &header); } spin_unlock_bh(&pchan->rxbuf_lock); diff --git a/drivers/soc/qcom/socinfo.c b/drivers/soc/qcom/socinfo.c index 7604affe63a8..b20cf2d65a6a 100644 --- a/drivers/soc/qcom/socinfo.c +++ b/drivers/soc/qcom/socinfo.c @@ -539,6 +539,7 @@ static struct msm_soc_info cpu_of_id[] = { [312] = {MSM_CPU_8996, "APQ8096pro"}, [315] = {MSM_CPU_8996, "MSM8996pro"}, [316] = {MSM_CPU_8996, "APQ8096pro"}, + [387] = {MSM_CPU_8996, "APQ8096A"}, /* 8976 ID */ [266] = {MSM_CPU_8976, "MSM8976"}, diff --git a/include/linux/habmm.h b/include/linux/habmm.h index cd4e2506f9ee..34ba1083a554 100644 --- a/include/linux/habmm.h +++ b/include/linux/habmm.h @@ -105,6 +105,37 @@ int32_t habmm_socket_close(int32_t handle); */ #define HABMM_SOCKET_SEND_FLAGS_XING_VM_STAT 0x00000002 +/* start to measure cross-vm schedule latency: VM1 send msg with this flag + * to VM2 to kick off the measurement. In the hab driver level, the VM1 hab + * driver shall record the time of schdule out with mpm_timer, and buffer + * it for later usage. The VM2 hab driver shall record the time of schedule + * in with mpm_timer and pass it to "habtest" application. + */ +#define HABMM_SOCKET_XVM_SCHE_TEST 0x00000004 + +/* VM2 responds this message to VM1 for HABMM_SOCKET_XVM_SCHE_TEST. + * In the hab driver level, the VM2 hab driver shall record the time of schedule + * out with mpm_timer, and buffer it for later usage; the VM1 hab driver + * shall record the time of schedule in with mpm_timer and pass it to "habtest" + * application. + */ +#define HABMM_SOCKET_XVM_SCHE_TEST_ACK 0x00000008 + +/* VM1 sends this message to VM2 asking for collect all the mpm_timer values + * to calculate the latency of schduling between VM1 and VM2. In the hab driver + * level, the VM1 hab driver shall save the previous restored schduling out + * time to the message buffer + */ +#define HABMM_SOCKET_XVM_SCHE_RESULT_REQ 0x00000010 + +/* VM2 responds this message to VM2 for HABMM_SOCKET_XVM_SCHE_RESULT_REQ. + * In the habtest application level, VM2 shall save the previous restored + * scheduling in time into message buffer, in the hab driver level, VM2 + * shall save the previous restored scheduling out time to the message + * buffer. + */ +#define HABMM_SOCKET_XVM_SCHE_RESULT_RSP 0x00000020 + struct habmm_xing_vm_stat { uint64_t tx_sec; uint64_t tx_usec; diff --git a/kernel/time/timekeeping.c b/kernel/time/timekeeping.c index 7902ecbce8ec..0651c7f47932 100644 --- a/kernel/time/timekeeping.c +++ b/kernel/time/timekeeping.c @@ -1669,9 +1669,12 @@ static __always_inline void timekeeping_freqadjust(struct timekeeper *tk, { s64 interval = tk->cycle_interval; s64 xinterval = tk->xtime_interval; + u32 base = tk->tkr_mono.clock->mult; + u32 max = tk->tkr_mono.clock->maxadj; + u32 cur_adj = tk->tkr_mono.mult; s64 tick_error; bool negative; - u32 adj; + u32 adj_scale; /* Remove any current error adj from freq calculation */ if (tk->ntp_err_mult) @@ -1690,13 +1693,33 @@ static __always_inline void timekeeping_freqadjust(struct timekeeper *tk, /* preserve the direction of correction */ negative = (tick_error < 0); - /* Sort out the magnitude of the correction */ + /* If any adjustment would pass the max, just return */ + if (negative && (cur_adj - 1) <= (base - max)) + return; + if (!negative && (cur_adj + 1) >= (base + max)) + return; + /* + * Sort out the magnitude of the correction, but + * avoid making so large a correction that we go + * over the max adjustment. + */ + adj_scale = 0; tick_error = abs(tick_error); - for (adj = 0; tick_error > interval; adj++) + while (tick_error > interval) { + u32 adj = 1 << (adj_scale + 1); + + /* Check if adjustment gets us within 1 unit from the max */ + if (negative && (cur_adj - adj) <= (base - max)) + break; + if (!negative && (cur_adj + adj) >= (base + max)) + break; + + adj_scale++; tick_error >>= 1; + } /* scale the corrections */ - timekeeping_apply_adjustment(tk, offset, negative, adj); + timekeeping_apply_adjustment(tk, offset, negative, adj_scale); } /* diff --git a/sound/soc/soc-ops.c b/sound/soc/soc-ops.c index c48d8c8d9766..92ccddea1fc5 100644 --- a/sound/soc/soc-ops.c +++ b/sound/soc/soc-ops.c @@ -379,7 +379,7 @@ int snd_soc_get_volsw_sx(struct snd_kcontrol *kcontrol, unsigned int rshift = mc->rshift; int max = mc->max; int min = mc->min; - int mask = (1 << (fls(min + max) - 1)) - 1; + unsigned int mask = (1 << (fls(min + max) - 1)) - 1; unsigned int val; int ret; @@ -424,7 +424,7 @@ int snd_soc_put_volsw_sx(struct snd_kcontrol *kcontrol, unsigned int rshift = mc->rshift; int max = mc->max; int min = mc->min; - int mask = (1 << (fls(min + max) - 1)) - 1; + unsigned int mask = (1 << (fls(min + max) - 1)) - 1; int err = 0; unsigned int val, val_mask, val2 = 0; |
