summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Documentation/devicetree/bindings/arm/msm/android.txt34
-rw-r--r--Documentation/devicetree/bindings/arm/msm/imem.txt10
-rw-r--r--Documentation/devicetree/bindings/arm/msm/msm.txt12
-rw-r--r--Documentation/devicetree/bindings/display/msm/sde.txt4
-rw-r--r--Documentation/devicetree/bindings/mmc/sdhci-msm.txt1
-rw-r--r--Documentation/devicetree/bindings/net/can/k61-can.txt27
-rw-r--r--Documentation/devicetree/bindings/pil/pil-q6v5-mss.txt1
-rw-r--r--Documentation/devicetree/bindings/power/supply/qcom/qpnp-fg-gen3.txt8
-rw-r--r--Documentation/devicetree/bindings/power/supply/qcom/qpnp-qnovo.txt1
-rw-r--r--Documentation/devicetree/bindings/soc/qcom/guest_shm.txt19
-rw-r--r--Documentation/devicetree/bindings/spi/spidev.txt30
-rw-r--r--Documentation/devicetree/bindings/usb/msm-phy.txt2
-rw-r--r--Documentation/devicetree/bindings/vendor-prefixes.txt3
-rw-r--r--arch/arm/boot/dts/qcom/Makefile30
-rw-r--r--arch/arm/boot/dts/qcom/fg-gen3-batterydata-ascent-3450mah.dtsi120
-rw-r--r--arch/arm/boot/dts/qcom/msm-smb138x.dtsi2
-rw-r--r--arch/arm/boot/dts/qcom/msm8996-cv2x.dtsi641
-rw-r--r--arch/arm/boot/dts/qcom/msm8996-pinctrl.dtsi29
-rw-r--r--arch/arm/boot/dts/qcom/msm8996-regulator.dtsi1
-rw-r--r--arch/arm/boot/dts/qcom/msm8996.dtsi25
-rw-r--r--arch/arm/boot/dts/qcom/msm8996pro-auto-cv2x.dts26
-rw-r--r--arch/arm/boot/dts/qcom/msm8998-sde.dtsi31
-rw-r--r--arch/arm/boot/dts/qcom/msm8998-v2.dtsi3
-rw-r--r--arch/arm/boot/dts/qcom/sda636-cdp.dts36
-rw-r--r--arch/arm/boot/dts/qcom/sda636-mtp.dts30
-rw-r--r--arch/arm/boot/dts/qcom/sda636-pm660a-cdp.dts36
-rw-r--r--arch/arm/boot/dts/qcom/sda636-pm660a-mtp.dts30
-rw-r--r--arch/arm/boot/dts/qcom/sda636-pm660a-qrd-hdk.dts240
-rw-r--r--arch/arm/boot/dts/qcom/sda636-pm660a-rcm.dts36
-rw-r--r--arch/arm/boot/dts/qcom/sda636-rcm.dts36
-rw-r--r--arch/arm/boot/dts/qcom/sda636.dtsi29
-rw-r--r--arch/arm/boot/dts/qcom/sdm630-qrd.dtsi4
-rw-r--r--arch/arm/boot/dts/qcom/sdm630.dtsi1
-rw-r--r--arch/arm/boot/dts/qcom/sdm636-cdp.dts36
-rw-r--r--arch/arm/boot/dts/qcom/sdm636-cdp.dtsi27
-rw-r--r--arch/arm/boot/dts/qcom/sdm636-headset-jacktype-no-cdp.dts26
-rw-r--r--arch/arm/boot/dts/qcom/sdm636-headset-jacktype-no-rcm.dts26
-rw-r--r--arch/arm/boot/dts/qcom/sdm636-internal-codec-cdp.dts26
-rw-r--r--arch/arm/boot/dts/qcom/sdm636-internal-codec-mtp.dts30
-rw-r--r--arch/arm/boot/dts/qcom/sdm636-internal-codec-pm660a-cdp.dts26
-rw-r--r--arch/arm/boot/dts/qcom/sdm636-internal-codec-pm660a-mtp.dts31
-rw-r--r--arch/arm/boot/dts/qcom/sdm636-internal-codec-pm660a-rcm.dts26
-rw-r--r--arch/arm/boot/dts/qcom/sdm636-internal-codec-rcm.dts26
-rw-r--r--arch/arm/boot/dts/qcom/sdm636-mtp.dts30
-rw-r--r--arch/arm/boot/dts/qcom/sdm636-mtp.dtsi27
-rw-r--r--arch/arm/boot/dts/qcom/sdm636-pm660a-cdp.dts54
-rw-r--r--arch/arm/boot/dts/qcom/sdm636-pm660a-headset-jacktype-no-cdp.dts38
-rw-r--r--arch/arm/boot/dts/qcom/sdm636-pm660a-headset-jacktype-no-rcm.dts26
-rw-r--r--arch/arm/boot/dts/qcom/sdm636-pm660a-mtp.dts48
-rw-r--r--arch/arm/boot/dts/qcom/sdm636-pm660a-qrd.dts56
-rw-r--r--arch/arm/boot/dts/qcom/sdm636-pm660a-rcm.dts36
-rw-r--r--arch/arm/boot/dts/qcom/sdm636-qrd.dts87
-rw-r--r--arch/arm/boot/dts/qcom/sdm636-qrd.dtsi16
-rw-r--r--arch/arm/boot/dts/qcom/sdm636-rcm.dts36
-rw-r--r--arch/arm/boot/dts/qcom/sdm636-usbc-audio-mtp.dts31
-rw-r--r--arch/arm/boot/dts/qcom/sdm636-usbc-audio-rcm.dts30
-rw-r--r--arch/arm/boot/dts/qcom/sdm636.dtsi73
-rw-r--r--arch/arm/boot/dts/qcom/sdm660-gpu.dtsi45
-rw-r--r--arch/arm/boot/dts/qcom/sdm660-qrd.dtsi4
-rw-r--r--arch/arm/boot/dts/qcom/sdm660-regulator.dtsi83
-rw-r--r--arch/arm/boot/dts/qcom/sdm660.dtsi42
-rw-r--r--arch/arm/boot/dts/qcom/vplatform-lfv-agave.dtsi50
-rw-r--r--arch/arm/boot/dts/qcom/vplatform-lfv-msm8996-pinctrl.dtsi538
-rw-r--r--arch/arm/boot/dts/qcom/vplatform-lfv-msm8996.dts611
-rw-r--r--arch/arm/boot/dts/qcom/vplatform-lfv-smmu.dtsi75
-rw-r--r--arch/arm/configs/sdm660-perf_defconfig5
-rw-r--r--arch/arm/configs/sdm660_defconfig6
-rw-r--r--arch/arm64/Kconfig9
-rw-r--r--arch/arm64/configs/msm-auto-gvm-perf_defconfig286
-rw-r--r--arch/arm64/configs/msm-auto-gvm_defconfig316
-rw-r--r--arch/arm64/configs/msm-auto-perf_defconfig4
-rw-r--r--arch/arm64/configs/msm-auto_defconfig4
-rw-r--r--arch/arm64/configs/msmcortex_defconfig1
-rw-r--r--arch/arm64/configs/sdm660-perf_defconfig11
-rw-r--r--arch/arm64/configs/sdm660_defconfig8
-rw-r--r--arch/arm64/kernel/smp.c2
-rw-r--r--arch/arm64/mm/dma-mapping.c24
-rw-r--r--drivers/base/core.c8
-rw-r--r--drivers/base/power/main.c12
-rw-r--r--drivers/bluetooth/btfm_slim_wcn3990.c18
-rw-r--r--drivers/char/adsprpc.c67
-rw-r--r--drivers/char/diag/diagchar_core.c21
-rw-r--r--drivers/char/diag/diagfwd_cntl.c12
-rw-r--r--drivers/char/diag/diagfwd_peripheral.c83
-rw-r--r--drivers/clk/msm/clock-dummy.c7
-rw-r--r--drivers/clk/qcom/clk-cpu-osm.c30
-rw-r--r--drivers/gpu/drm/msm/Kconfig10
-rw-r--r--drivers/gpu/drm/msm/Makefile1
-rw-r--r--drivers/gpu/drm/msm/msm_drv.c16
-rw-r--r--drivers/gpu/drm/msm/msm_drv.h1
-rw-r--r--drivers/gpu/drm/msm/sde/sde_connector.c170
-rw-r--r--drivers/gpu/drm/msm/sde/sde_connector.h29
-rw-r--r--drivers/gpu/drm/msm/sde/sde_core_irq.c2
-rw-r--r--drivers/gpu/drm/msm/sde/sde_crtc.c216
-rw-r--r--drivers/gpu/drm/msm/sde/sde_crtc.h8
-rw-r--r--drivers/gpu/drm/msm/sde/sde_encoder.c11
-rw-r--r--drivers/gpu/drm/msm/sde/sde_encoder_phys_vid.c55
-rw-r--r--drivers/gpu/drm/msm/sde/sde_hw_catalog.c74
-rw-r--r--drivers/gpu/drm/msm/sde/sde_hw_catalog.h12
-rw-r--r--drivers/gpu/drm/msm/sde/sde_hw_cdm.c4
-rw-r--r--drivers/gpu/drm/msm/sde/sde_hw_ctl.c66
-rw-r--r--drivers/gpu/drm/msm/sde/sde_hw_ctl.h20
-rw-r--r--drivers/gpu/drm/msm/sde/sde_hw_dspp.c7
-rw-r--r--drivers/gpu/drm/msm/sde/sde_hw_intf.c10
-rw-r--r--drivers/gpu/drm/msm/sde/sde_hw_lm.c10
-rw-r--r--drivers/gpu/drm/msm/sde/sde_hw_mdss.h2
-rw-r--r--drivers/gpu/drm/msm/sde/sde_hw_pingpong.c7
-rw-r--r--drivers/gpu/drm/msm/sde/sde_hw_sspp.c37
-rw-r--r--drivers/gpu/drm/msm/sde/sde_hw_top.c11
-rw-r--r--drivers/gpu/drm/msm/sde/sde_hw_util.h2
-rw-r--r--drivers/gpu/drm/msm/sde/sde_hw_vbif.c6
-rw-r--r--drivers/gpu/drm/msm/sde/sde_hw_wb.c7
-rw-r--r--drivers/gpu/drm/msm/sde/sde_kms.c85
-rw-r--r--drivers/gpu/drm/msm/sde/sde_kms.h48
-rw-r--r--drivers/gpu/drm/msm/sde/sde_kms_utils.c26
-rw-r--r--drivers/gpu/drm/msm/sde_dbg.c2070
-rw-r--r--drivers/gpu/drm/msm/sde_dbg.h292
-rw-r--r--drivers/gpu/drm/msm/sde_dbg_evtlog.c257
-rw-r--r--drivers/gpu/msm/kgsl_pool.c18
-rw-r--r--drivers/gpu/msm/kgsl_pool.h3
-rw-r--r--drivers/gpu/msm/kgsl_sharedmem.c1
-rw-r--r--drivers/gpu/msm/kgsl_sharedmem.h13
-rw-r--r--drivers/input/misc/hbtp_input.c160
-rw-r--r--drivers/iommu/arm-smmu.c2
-rw-r--r--drivers/iommu/dma-iommu.c10
-rw-r--r--drivers/leds/leds-qpnp-wled.c5
-rw-r--r--drivers/media/platform/msm/ais/msm.c3
-rw-r--r--drivers/media/platform/msm/ais/sensor/msm_sensor.c125
-rw-r--r--drivers/media/platform/msm/ais/sensor/msm_sensor.h10
-rw-r--r--drivers/media/platform/msm/ais/sensor/msm_sensor_driver.c130
-rw-r--r--drivers/media/platform/msm/ais/sensor/ois/msm_ois.c4
-rw-r--r--drivers/media/platform/msm/camera_v2/camera/camera.c6
-rw-r--r--drivers/media/platform/msm/camera_v2/common/msm_camera_io_util.c18
-rw-r--r--drivers/media/platform/msm/camera_v2/isp/msm_isp_util.c2
-rw-r--r--drivers/media/platform/msm/camera_v2/msm.c18
-rw-r--r--drivers/media/platform/msm/camera_v2/msm.h1
-rw-r--r--drivers/media/platform/msm/sde/rotator/sde_rotator_core.c6
-rw-r--r--drivers/media/platform/msm/vidc/msm_vdec.c2
-rw-r--r--drivers/media/platform/msm/vidc/msm_vidc_debug.c2
-rw-r--r--drivers/misc/qcom/qdsp6v2/audio_utils_aio.c2
-rw-r--r--drivers/mmc/core/sd.c1
-rw-r--r--drivers/mmc/host/sdhci-msm.c8
-rw-r--r--drivers/mmc/host/sdhci.c10
-rw-r--r--drivers/net/can/spi/Kconfig6
-rw-r--r--drivers/net/can/spi/Makefile1
-rw-r--r--drivers/net/can/spi/k61.c927
-rw-r--r--drivers/net/wireless/ath/ath10k/ce.c8
-rw-r--r--drivers/net/wireless/ath/ath10k/mac.c7
-rw-r--r--drivers/net/wireless/ath/wil6210/cfg80211.c22
-rw-r--r--drivers/net/wireless/ath/wil6210/debugfs.c24
-rw-r--r--drivers/net/wireless/ath/wil6210/main.c12
-rw-r--r--drivers/net/wireless/ath/wil6210/pcie_bus.c3
-rw-r--r--drivers/net/wireless/ath/wil6210/pm.c27
-rw-r--r--drivers/net/wireless/ath/wil6210/txrx.c6
-rw-r--r--drivers/net/wireless/ath/wil6210/wil6210.h13
-rw-r--r--drivers/net/wireless/ath/wil6210/wmi.c14
-rw-r--r--drivers/net/wireless/ath/wil6210/wmi.h8
-rw-r--r--drivers/net/wireless/cnss/Kconfig1
-rw-r--r--drivers/net/wireless/cnss/cnss_sdio.c7
-rw-r--r--drivers/net/wireless/cnss2/wlan_firmware_service_v01.h6
-rw-r--r--drivers/platform/msm/ipa/ipa_v2/ipa_debugfs.c4
-rw-r--r--drivers/platform/msm/ipa/ipa_v2/ipa_rt.c13
-rw-r--r--drivers/platform/msm/ipa/ipa_v3/ipa.c245
-rw-r--r--drivers/platform/msm/ipa/ipa_v3/ipa_debugfs.c4
-rw-r--r--drivers/platform/msm/ipa/ipa_v3/ipa_i.h5
-rw-r--r--drivers/platform/msm/ipa/ipa_v3/ipa_mhi.c4
-rw-r--r--drivers/platform/msm/ipa/ipa_v3/ipa_nat.c59
-rw-r--r--drivers/platform/msm/ipa/ipa_v3/ipa_rt.c17
-rw-r--r--drivers/platform/msm/ipa/ipa_v3/ipa_utils.c14
-rw-r--r--drivers/platform/msm/sps/sps.c3
-rw-r--r--drivers/power/power_supply_sysfs.c2
-rw-r--r--drivers/power/supply/qcom/fg-core.h3
-rw-r--r--drivers/power/supply/qcom/qpnp-fg-gen3.c304
-rw-r--r--drivers/power/supply/qcom/qpnp-qnovo.c55
-rw-r--r--drivers/power/supply/qcom/qpnp-smb2.c12
-rw-r--r--drivers/power/supply/qcom/smb-lib.h1
-rw-r--r--drivers/power/supply/qcom/smb138x-charger.c6
-rw-r--r--drivers/power/supply/qcom/step-chg-jeita.c9
-rw-r--r--drivers/regulator/cprh-kbss-regulator.c13
-rw-r--r--drivers/soc/qcom/Kconfig2
-rw-r--r--drivers/soc/qcom/Makefile1
-rw-r--r--drivers/soc/qcom/common_log.c27
-rw-r--r--drivers/soc/qcom/glink.c35
-rw-r--r--drivers/soc/qcom/glink_spi_xprt.c78
-rw-r--r--drivers/soc/qcom/hab/Kconfig7
-rw-r--r--drivers/soc/qcom/hab/Makefile14
-rw-r--r--drivers/soc/qcom/hab/hab.c726
-rw-r--r--drivers/soc/qcom/hab/hab.h415
-rw-r--r--drivers/soc/qcom/hab/hab_grantable.h29
-rw-r--r--drivers/soc/qcom/hab/hab_mem_linux.c451
-rw-r--r--drivers/soc/qcom/hab/hab_mimex.c394
-rw-r--r--drivers/soc/qcom/hab/hab_msg.c208
-rw-r--r--drivers/soc/qcom/hab/hab_open.c154
-rw-r--r--drivers/soc/qcom/hab/hab_pchan.c86
-rw-r--r--drivers/soc/qcom/hab/hab_pipe.c131
-rw-r--r--drivers/soc/qcom/hab/hab_pipe.h60
-rw-r--r--drivers/soc/qcom/hab/hab_qvm.c251
-rw-r--r--drivers/soc/qcom/hab/hab_qvm.h47
-rw-r--r--drivers/soc/qcom/hab/hab_vchan.c184
-rw-r--r--drivers/soc/qcom/hab/khab.c140
-rw-r--r--drivers/soc/qcom/hab/qvm_comm.c95
-rw-r--r--drivers/soc/qcom/icnss.c22
-rw-r--r--drivers/soc/qcom/ipc_router_glink_xprt.c5
-rw-r--r--drivers/soc/qcom/peripheral-loader.c108
-rw-r--r--drivers/soc/qcom/peripheral-loader.h28
-rw-r--r--drivers/soc/qcom/pil-msa.c10
-rw-r--r--drivers/soc/qcom/qdsp6v2/apr.c1
-rw-r--r--drivers/soc/qcom/qdsp6v2/msm_audio_ion.c60
-rw-r--r--drivers/soc/qcom/ramdump.c133
-rw-r--r--drivers/soc/qcom/scm_qcpe.c35
-rw-r--r--drivers/soc/qcom/smp2p_spinlock_test.c4
-rw-r--r--drivers/soc/qcom/socinfo.c12
-rw-r--r--drivers/soc/qcom/spcom.c42
-rw-r--r--drivers/soc/qcom/wcd-dsp-glink.c38
-rw-r--r--drivers/spi/spi_qsd.c12
-rw-r--r--drivers/spi/spidev.c2
-rw-r--r--drivers/thermal/msm_thermal.c6
-rw-r--r--drivers/usb/dwc3/core.c2
-rw-r--r--drivers/usb/dwc3/dwc3-msm.c4
-rw-r--r--drivers/usb/phy/phy-msm-qusb.c38
-rw-r--r--drivers/video/fbdev/msm/mdss_dp.c1
-rw-r--r--drivers/video/fbdev/msm/mdss_dp_aux.c5
-rw-r--r--drivers/video/fbdev/msm/mdss_hdmi_edid.c7
-rw-r--r--drivers/video/fbdev/msm/mdss_mdp_layer.c3
-rw-r--r--include/linux/dma-iommu.h1
-rw-r--r--include/linux/habmm.h38
-rw-r--r--include/linux/msm_audio_ion.h10
-rw-r--r--include/linux/power_supply.h2
-rw-r--r--include/linux/sched.h5
-rw-r--r--include/soc/qcom/minidump.h5
-rw-r--r--include/soc/qcom/ramdump.h5
-rw-r--r--include/soc/qcom/socinfo.h7
-rw-r--r--include/sound/q6asm-v2.h3
-rw-r--r--include/uapi/drm/sde_drm.h10
-rw-r--r--include/uapi/linux/Kbuild1
-rw-r--r--include/uapi/linux/habmm.h143
-rw-r--r--include/uapi/linux/msm_ipa.h56
-rw-r--r--include/uapi/media/ais/msm_ais_sensor.h21
-rw-r--r--include/uapi/media/ais/msm_ais_sensor_sdk.h8
-rw-r--r--kernel/panic.c2
-rw-r--r--kernel/sched/cpupri.c11
-rw-r--r--kernel/softirq.c5
-rw-r--r--lib/stackdepot.c1
-rw-r--r--sound/soc/codecs/sdm660_cdc/msm-analog-cdc.c15
-rw-r--r--sound/soc/codecs/sdm660_cdc/msm-digital-cdc.c6
-rw-r--r--sound/soc/codecs/wsa881x.c2
-rw-r--r--sound/soc/msm/Kconfig4
-rw-r--r--sound/soc/msm/qdsp6v2/msm-compress-q6-v2.c247
-rw-r--r--sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c15
-rw-r--r--sound/soc/msm/qdsp6v2/msm-transcode-loopback-q6-v2.c77
-rw-r--r--sound/soc/msm/qdsp6v2/q6asm.c6
-rw-r--r--sound/soc/msm/sdm660-internal.c3
252 files changed, 14581 insertions, 1026 deletions
diff --git a/Documentation/devicetree/bindings/arm/msm/android.txt b/Documentation/devicetree/bindings/arm/msm/android.txt
index db52284892af..7b8b7909bae3 100644
--- a/Documentation/devicetree/bindings/arm/msm/android.txt
+++ b/Documentation/devicetree/bindings/arm/msm/android.txt
@@ -1,6 +1,6 @@
Android firmware
-Node to specify early mount of vendor partition.
+Node to specify early mount of vendor and system partition.
Required properties
@@ -52,3 +52,35 @@ Example:
};
};
};
+
+system:
+-----------------
+
+system partition specification.
+
+Required properties:
+
+-compatible: "android,system"
+-dev: block device corresponding to system partition
+-type: file system type of system partition
+-mnt_flags: mount flags
+-fsmgr_flags: fsmgr flags
+
+Example:
+
+ firmware: firmware {
+ android {
+ compatible = "android,firmware";
+ fstab {
+ compatible = "android,fstab";
+ system {
+ compatible = "android,system";
+ dev = "/dev/block/platform/soc/1da4000.ufshc/by-name/system";
+ type = "ext4";
+ mnt_flags = "ro,barrier=1,discard";
+ fsmgr_flags = "wait,slotselect";
+ status = "ok";
+ };
+ };
+ };
+ };
diff --git a/Documentation/devicetree/bindings/arm/msm/imem.txt b/Documentation/devicetree/bindings/arm/msm/imem.txt
index 2989fbfe7972..440628d02630 100644
--- a/Documentation/devicetree/bindings/arm/msm/imem.txt
+++ b/Documentation/devicetree/bindings/arm/msm/imem.txt
@@ -73,6 +73,11 @@ USB Diag Cookies:
Memory region used to store USB PID and serial numbers to be used by
bootloader in download mode.
+SSR Minidump Offset
+-------------------
+-Compatible: "qcom,msm-imem-minidump"
+-reg: start address and size of ssr imem region
+
Required properties:
-compatible: "qcom,msm-imem-diag-dload"
-reg: start address and size of USB Diag download mode region in imem
@@ -121,4 +126,9 @@ Example:
compatible = "qcom,msm-imem-emergency_download_mode";
reg = <0xfe0 12>;
};
+
+ ss_mdump@b88 {
+ compatible = "qcom,msm-imem-minidump";
+ reg = <0xb88 28>;
+ };
};
diff --git a/Documentation/devicetree/bindings/arm/msm/msm.txt b/Documentation/devicetree/bindings/arm/msm/msm.txt
index d58b98f9a702..c264f9f65265 100644
--- a/Documentation/devicetree/bindings/arm/msm/msm.txt
+++ b/Documentation/devicetree/bindings/arm/msm/msm.txt
@@ -110,6 +110,12 @@ SoCs:
- SDA630
compatible = "qcom,sda630"
+- SDM636
+ compatible = "qcom,sdm636"
+
+- SDA636
+ compatible = "qcom,sda636"
+
- MSM8952
compatible = "qcom,msm8952"
@@ -295,6 +301,12 @@ compatible = "qcom,sda658-mtp"
compatible = "qcom,sda658-cdp"
compatible = "qcom,sda660-mtp"
compatible = "qcom,sda660-cdp"
+compatible = "qcom,sdm636-cdp"
+compatible = "qcom,sdm636-mtp"
+compatible = "qcom,sdm636-qrd"
+compatible = "qcom,sda636-qrd"
+compatible = "qcom,sda636-mtp"
+compatible = "qcom,sda636-cdp"
compatible = "qcom,sdm630-rumi"
compatible = "qcom,sdm630-mtp"
compatible = "qcom,sdm630-cdp"
diff --git a/Documentation/devicetree/bindings/display/msm/sde.txt b/Documentation/devicetree/bindings/display/msm/sde.txt
index e14acdc6303e..1583da81c090 100644
--- a/Documentation/devicetree/bindings/display/msm/sde.txt
+++ b/Documentation/devicetree/bindings/display/msm/sde.txt
@@ -169,6 +169,7 @@ Optional properties:
e.g. qcom,sde-sspp-vig-blocks
-- qcom,sde-vig-csc-off: offset of CSC hardware
-- qcom,sde-vig-qseed-off: offset of QSEED hardware
+ -- qcom,sde-vig-qseed-size: A u32 address range for qseed scaler.
-- qcom,sde-vig-pcc: offset and version of PCC hardware
-- qcom,sde-vig-hsic: offset and version of global PA adjustment
-- qcom,sde-vig-memcolor: offset and version of PA memcolor hardware
@@ -178,6 +179,7 @@ Optional properties:
indicates that the SSPP RGB contains that feature hardware.
e.g. qcom,sde-sspp-vig-blocks
-- qcom,sde-rgb-scaler-off: offset of RGB scaler hardware
+ -- qcom,sde-rgb-scaler-size: A u32 address range for scaler.
-- qcom,sde-rgb-pcc: offset and version of PCC hardware
- qcom,sde-dspp-blocks: A node that lists the blocks inside the DSPP hardware. The
block entries will contain the offset and version of each
@@ -417,6 +419,7 @@ Example:
qcom,sde-sspp-vig-blocks {
qcom,sde-vig-csc-off = <0x320>;
qcom,sde-vig-qseed-off = <0x200>;
+ qcom,sde-vig-qseed-size = <0x74>;
/* Offset from vig top, version of HSIC */
qcom,sde-vig-hsic = <0x200 0x00010000>;
qcom,sde-vig-memcolor = <0x200 0x00010000>;
@@ -425,6 +428,7 @@ Example:
qcom,sde-sspp-rgb-blocks {
qcom,sde-rgb-scaler-off = <0x200>;
+ qcom,sde-rgb-scaler-size = <0x74>;
qcom,sde-rgb-pcc = <0x380 0x00010000>;
};
diff --git a/Documentation/devicetree/bindings/mmc/sdhci-msm.txt b/Documentation/devicetree/bindings/mmc/sdhci-msm.txt
index d00e26b4d5ed..9916c34e62b8 100644
--- a/Documentation/devicetree/bindings/mmc/sdhci-msm.txt
+++ b/Documentation/devicetree/bindings/mmc/sdhci-msm.txt
@@ -80,6 +80,7 @@ Optional Properties:
register dumps on CRC errors and also downgrade bus speed mode to
SDR50/DDR50 in case of continuous CRC errors. Set this flag to enable
this workaround.
+ - qcom,force-sdhc1-probe: Force probing sdhc1 even if it is not the boot device.
In the following, <supply> can be vdd (flash core voltage) or vdd-io (I/O voltage).
- qcom,<supply>-always-on - specifies whether supply should be kept "on" always.
diff --git a/Documentation/devicetree/bindings/net/can/k61-can.txt b/Documentation/devicetree/bindings/net/can/k61-can.txt
new file mode 100644
index 000000000000..57e85817a0a5
--- /dev/null
+++ b/Documentation/devicetree/bindings/net/can/k61-can.txt
@@ -0,0 +1,27 @@
+* Kinetis K61 CAN *
+
+This driver implements SPI slave protocol for Freescale K61 CAN controller.
+
+Required properties:
+ - compatible: Should be "fsl,k61".
+ - reg: Should contain SPI chip select.
+ - interrupt-parent: Should specify interrupt controller for the interrupt.
+ - interrupts: Should contain IRQ line for the CAN controller.
+ - reset-gpio: Reference to the GPIO connected to the reset input.
+ - pinctrl-names : Names corresponding to the numbered pinctrl states.
+ - pinctrl-0 : This explains the active state of the GPIO line.
+ - pinctrl-1 : This explains the suspend state of the GPIO line.
+
+
+Example:
+
+ can-controller@0 {
+ compatible = "fsl,k61";
+ reg = <0>;
+ interrupt-parent = <&tlmm_pinmux>;
+ interrupts = <25 0>;
+ reset-gpio = <&tlmm_pinmux 11 0x1>;
+ pinctrl-names = "active", "sleep";
+ pinctrl-0 = <&can_rst_on>;
+ pinctrl-1 = <&can_rst_off>;
+ };
diff --git a/Documentation/devicetree/bindings/pil/pil-q6v5-mss.txt b/Documentation/devicetree/bindings/pil/pil-q6v5-mss.txt
index 47a6fdd300ca..406920b7246e 100644
--- a/Documentation/devicetree/bindings/pil/pil-q6v5-mss.txt
+++ b/Documentation/devicetree/bindings/pil/pil-q6v5-mss.txt
@@ -88,6 +88,7 @@ Optional properties:
- qcom,override-acc-1: Override the default ACC settings with this value if present.
- qcom,cx-ipeak-vote: Boolean- Present if we need to set bit 5 of cxip_lm_vote_clear
during modem shutdown
+- qcom,minidump-id: Unique id for each subsystem
One child node to represent the MBA image may be specified, when the MBA image
needs to be loaded in a specifically carved out memory region.
diff --git a/Documentation/devicetree/bindings/power/supply/qcom/qpnp-fg-gen3.txt b/Documentation/devicetree/bindings/power/supply/qcom/qpnp-fg-gen3.txt
index 012368275db3..dc04942d6792 100644
--- a/Documentation/devicetree/bindings/power/supply/qcom/qpnp-fg-gen3.txt
+++ b/Documentation/devicetree/bindings/power/supply/qcom/qpnp-fg-gen3.txt
@@ -271,6 +271,14 @@ First Level Node - FG Gen3 device
Definition: A boolean property that when defined holds SOC at 100% when
the battery is full.
+- qcom,linearize-soc
+ Usage: optional
+ Value type: <empty>
+ Definition: A boolean property that when defined linearizes SOC when
+ the SOC drops after charge termination monotonically to
+ improve the user experience. This is applicable only if
+ "qcom,hold-soc-while-full" is specified.
+
- qcom,ki-coeff-soc-dischg
Usage: optional
Value type: <prop-encoded-array>
diff --git a/Documentation/devicetree/bindings/power/supply/qcom/qpnp-qnovo.txt b/Documentation/devicetree/bindings/power/supply/qcom/qpnp-qnovo.txt
index 96b7dd517231..8f35e56816ce 100644
--- a/Documentation/devicetree/bindings/power/supply/qcom/qpnp-qnovo.txt
+++ b/Documentation/devicetree/bindings/power/supply/qcom/qpnp-qnovo.txt
@@ -20,6 +20,7 @@ Required properties:
Optional Properties:
- qcom,external-rsense: To indicate whether the platform uses external or
internal rsense for measuring battery current.
+- qcom,enable-for-dc: To enable qnovo for dc charging path.
Example:
diff --git a/Documentation/devicetree/bindings/soc/qcom/guest_shm.txt b/Documentation/devicetree/bindings/soc/qcom/guest_shm.txt
new file mode 100644
index 000000000000..9491344c7b9f
--- /dev/null
+++ b/Documentation/devicetree/bindings/soc/qcom/guest_shm.txt
@@ -0,0 +1,19 @@
+QVM Guest Shared Memory
+
+guest_shm is a device that enables linux as a guest operating system
+to allocate shared memory between virtual machines and send notifications
+of updates to other virtual machines.
+
+Required properties:
+- compatible: Must be "qvm,guest_shm".
+- interrupt-parent: Parent interrupt controller.
+- interrupts: Should contain QVM interrupt.
+- reg: Physical address of the guest factory and length.
+
+Example:
+ qvm,guest_shm {
+ compatible = "qvm,guest_shm";
+ interrupt-parent = <&gic>;
+ interrupts = <6 4>;
+ reg = <0x1c050000 0x1000>;
+ };
diff --git a/Documentation/devicetree/bindings/spi/spidev.txt b/Documentation/devicetree/bindings/spi/spidev.txt
new file mode 100644
index 000000000000..886eb4bfadf5
--- /dev/null
+++ b/Documentation/devicetree/bindings/spi/spidev.txt
@@ -0,0 +1,30 @@
+SPIDEV
+
+SPI slave devices using the spidev driver allowing for userspace
+control of the SPI devices. Must be children of a SPI master node
+and contain the following properties.
+
+Required properties:
+- compatible: Should contain:
+ "nxp,mpc57xx" for external CAN controller
+ "infineon,sli97" for external HSM module
+
+- reg: Chip select address of device.
+- spi-max-frequency: Maximum SPI clocking speed of device in Hz.
+
+Optional properties:
+- spi-cpol: Empty property indicating device requires
+ inverse clock polarity (CPOL) mode.
+- spi-cpha: Empty property indicating device requires
+ shifted clock phase (CPHA) mode.
+
+Other optional properties described in
+Documentation/devicetree/bindings/spi/spi-bus.txt
+
+Example:
+
+ spi@0 {
+ compatible = "nxp,mpc57xx";
+ reg = <0>;
+ spi-max-frequency = <19200000>;
+ };
diff --git a/Documentation/devicetree/bindings/usb/msm-phy.txt b/Documentation/devicetree/bindings/usb/msm-phy.txt
index 88ad24900f28..9b40d44d363b 100644
--- a/Documentation/devicetree/bindings/usb/msm-phy.txt
+++ b/Documentation/devicetree/bindings/usb/msm-phy.txt
@@ -214,6 +214,8 @@ Optional properties:
- qcom,major-rev: provide major revision number to differentiate power up sequence. default is 2.0
- qcom,vdda33-voltage-level: A list of three integer values (min, op, max) representing
specific voltages (in microvolts) used for the vdda33 supply.
+ - qcom,tune2-efuse-correction: The value to be adjusted from fused value for
+ improved rise/fall times.
Example:
qusb_phy: qusb@f9b39000 {
diff --git a/Documentation/devicetree/bindings/vendor-prefixes.txt b/Documentation/devicetree/bindings/vendor-prefixes.txt
index 91412a10bf65..bfaca0cf9adf 100644
--- a/Documentation/devicetree/bindings/vendor-prefixes.txt
+++ b/Documentation/devicetree/bindings/vendor-prefixes.txt
@@ -21,6 +21,7 @@ amlogic Amlogic, Inc.
ampire Ampire Co., Ltd.
ams AMS AG
amstaos AMS-Taos Inc.
+android Google Inc.
apm Applied Micro Circuits Corporation (APM)
aptina Aptina Imaging
arasan Arasan Chip Systems
@@ -114,6 +115,7 @@ ibm International Business Machines (IBM)
idt Integrated Device Technologies, Inc.
iom Iomega Corporation
img Imagination Technologies Ltd.
+infineon Infineon Technologies AG
ingenic Ingenic Semiconductor
innolux Innolux Corporation
intel Intel Corporation
@@ -186,6 +188,7 @@ qcom Qualcomm Technologies, Inc
qemu QEMU, a generic and open source machine emulator and virtualizer
qi Qi Hardware
qnap QNAP Systems, Inc.
+qvm BlackBerry Ltd
radxa Radxa
raidsonic RaidSonic Technology GmbH
ralink Mediatek/Ralink Technology Corp.
diff --git a/arch/arm/boot/dts/qcom/Makefile b/arch/arm/boot/dts/qcom/Makefile
index 1c3de8ccb400..faff7ea618d0 100644
--- a/arch/arm/boot/dts/qcom/Makefile
+++ b/arch/arm/boot/dts/qcom/Makefile
@@ -32,6 +32,7 @@ dtb-$(CONFIG_ARCH_MSM8996) += msm8996-v2-pmi8994-cdp.dtb \
msm8996pro-auto-adp.dtb \
msm8996pro-auto-adp-lite.dtb \
msm8996pro-auto-cdp.dtb \
+ msm8996pro-auto-cv2x.dtb \
msm8996pro-pmi8994-cdp.dtb \
msm8996pro-pmi8994-mtp.dtb \
msm8996pro-pmi8994-pmk8001-cdp.dtb \
@@ -229,7 +230,34 @@ dtb-$(CONFIG_ARCH_SDM660) += sdm660-sim.dtb \
sda658-rcm.dtb \
sda658-pm660a-mtp.dtb \
sda658-pm660a-cdp.dtb \
- sda658-pm660a-rcm.dtb
+ sda658-pm660a-rcm.dtb \
+ sdm636-cdp.dtb \
+ sdm636-mtp.dtb \
+ sdm636-qrd.dtb \
+ sdm636-rcm.dtb \
+ sdm636-headset-jacktype-no-cdp.dtb \
+ sdm636-headset-jacktype-no-rcm.dtb \
+ sdm636-internal-codec-cdp.dtb \
+ sdm636-internal-codec-mtp.dtb \
+ sdm636-internal-codec-pm660a-cdp.dtb \
+ sdm636-internal-codec-pm660a-mtp.dtb \
+ sdm636-internal-codec-pm660a-rcm.dtb \
+ sdm636-internal-codec-rcm.dtb \
+ sdm636-pm660a-headset-jacktype-no-cdp.dtb \
+ sdm636-pm660a-headset-jacktype-no-rcm.dtb \
+ sdm636-pm660a-cdp.dtb \
+ sdm636-pm660a-mtp.dtb \
+ sdm636-pm660a-qrd.dtb \
+ sdm636-pm660a-rcm.dtb \
+ sdm636-usbc-audio-mtp.dtb \
+ sdm636-usbc-audio-rcm.dtb \
+ sda636-cdp.dtb \
+ sda636-mtp.dtb \
+ sda636-rcm.dtb \
+ sda636-pm660a-cdp.dtb \
+ sda636-pm660a-mtp.dtb \
+ sda636-pm660a-qrd-hdk.dtb \
+ sda636-pm660a-rcm.dtb
dtb-$(CONFIG_ARCH_SDM630) += sdm630-rumi.dtb \
sdm630-pm660a-rumi.dtb \
diff --git a/arch/arm/boot/dts/qcom/fg-gen3-batterydata-ascent-3450mah.dtsi b/arch/arm/boot/dts/qcom/fg-gen3-batterydata-ascent-3450mah.dtsi
index c7cecbca3929..7705d01570ac 100644
--- a/arch/arm/boot/dts/qcom/fg-gen3-batterydata-ascent-3450mah.dtsi
+++ b/arch/arm/boot/dts/qcom/fg-gen3-batterydata-ascent-3450mah.dtsi
@@ -11,71 +11,71 @@
*/
qcom,ascent_3450mah {
- /* Ascent_with_connector_3450mAh_averaged_MasterSlave_Jan6th2017 */
+ /* Ascent_wConn_Aging_3450mAh_averaged_MasterSlave_Jul11th2017 */
qcom,max-voltage-uv = <4350000>;
qcom,fg-cc-cv-threshold-mv = <4340>;
qcom,fastchg-current-ma = <3450>;
qcom,batt-id-kohm = <60>;
qcom,battery-beta = <3435>;
- qcom,battery-type = "ascent_3450mah_averaged_masterslave_jan6th2017";
- qcom,checksum = <0x96AC>;
- qcom,gui-version = "PMI8998GUI - 2.0.0.54";
+ qcom,battery-type = "ascent_3450mah_averaged_masterslave_jul11th2017";
+ qcom,checksum = <0x7C33>;
+ qcom,gui-version = "PMI8998GUI - 2.0.0.58";
qcom,fg-profile-data = [
- 9C 1F 85 05
- 82 0A 73 FC
- 2B 1D 72 EA
- EE 03 66 0C
- C8 17 F4 22
- E0 45 1F 52
- 5C 00 00 00
- 10 00 00 00
- 00 00 4A C4
- C7 BC 48 C2
- 0F 00 08 00
- E1 DA 5D ED
- 8D FD B2 F3
- 96 E2 A7 12
- 7E F4 0E 3B
- 24 06 09 20
- 27 00 14 00
- 83 1F EE 05
- 1F 0A 45 FD
- 6B 1D 53 E5
- EC 0B 31 14
- 44 18 49 23
- 18 45 A6 53
- 55 00 00 00
- 0E 00 00 00
- 00 00 61 CC
- B7 C3 0F BC
- 0F 00 00 00
- 92 00 5D ED
- E3 06 E0 00
- 75 FD 9C 03
- 47 DB B3 22
- CB 33 CC FF
- 07 10 00 00
- 99 0D 99 45
- 0F 00 40 00
- AB 01 0A FA
- FF 00 00 00
- 00 00 00 00
- 00 00 00 00
- 00 00 00 00
- 00 00 00 00
- 00 00 00 00
- 00 00 00 00
- 00 00 00 00
- 00 00 00 00
- 00 00 00 00
- 00 00 00 00
- 00 00 00 00
- 00 00 00 00
- 00 00 00 00
- 00 00 00 00
- 00 00 00 00
- 00 00 00 00
- 00 00 00 00
- 00 00 00 00
+ 8F 1F 94 05
+ 73 0A 4A 06
+ 27 1D 21 EA
+ 16 0A 3B 0C
+ 07 18 97 22
+ A5 3C EC 4A
+ 5C 00 00 00
+ 10 00 00 00
+ 00 00 92 BC
+ CD BD 02 B4
+ 11 00 08 00
+ 69 DA AD 07
+ 4B FD 19 FA
+ 1D 0C B0 0C
+ EB F3 78 3B
+ 24 06 09 20
+ 27 00 14 00
+ 7E 1F F2 05
+ 19 0A 55 FD
+ 6C 1D C6 ED
+ 1A 12 FF 1D
+ 6F 18 EB 22
+ B9 45 6F 52
+ 55 00 00 00
+ 0E 00 00 00
+ 00 00 A1 D5
+ 34 BA A0 CA
+ 0F 00 00 00
+ 93 00 AD 07
+ 8D FD F6 00
+ BA 0D 5C 04
+ B3 FC F4 1B
+ C3 33 CC FF
+ 07 10 00 00
+ A4 0D 99 45
+ 0F 00 40 00
+ A4 01 0A FA
+ FF 00 00 00
+ 00 00 00 00
+ 00 00 00 00
+ 00 00 00 00
+ 00 00 00 00
+ 00 00 00 00
+ 00 00 00 00
+ 00 00 00 00
+ 00 00 00 00
+ 00 00 00 00
+ 00 00 00 00
+ 00 00 00 00
+ 00 00 00 00
+ 00 00 00 00
+ 00 00 00 00
+ 00 00 00 00
+ 00 00 00 00
+ 00 00 00 00
+ 00 00 00 00
];
};
diff --git a/arch/arm/boot/dts/qcom/msm-smb138x.dtsi b/arch/arm/boot/dts/qcom/msm-smb138x.dtsi
index df7d30210c19..c156e91dfcf9 100644
--- a/arch/arm/boot/dts/qcom/msm-smb138x.dtsi
+++ b/arch/arm/boot/dts/qcom/msm-smb138x.dtsi
@@ -18,7 +18,7 @@
compatible = "qcom,i2c-pmic";
reg = <0x8>;
#address-cells = <1>;
- #size-cells = <1>;
+ #size-cells = <0>;
interrupt-parent = <&spmi_bus>;
interrupts = <0x0 0xd1 0x0 IRQ_TYPE_LEVEL_LOW>;
interrupt_names = "smb138x";
diff --git a/arch/arm/boot/dts/qcom/msm8996-cv2x.dtsi b/arch/arm/boot/dts/qcom/msm8996-cv2x.dtsi
new file mode 100644
index 000000000000..d18344eb3daf
--- /dev/null
+++ b/arch/arm/boot/dts/qcom/msm8996-cv2x.dtsi
@@ -0,0 +1,641 @@
+/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include "msm8996-pinctrl.dtsi"
+#include "external-soc.dtsi"
+
+/ {
+ reserved-memory {
+ lk_mem: lk_pool@91600000 {
+ reg = <0x0 0x91600000 0x0 0x600000>;
+ label = "lk_pool";
+ };
+ };
+
+ aliases {
+ mhi_rmnet0 = &mhi_rmnet_0;
+ mhi_rmnet1 = &mhi_rmnet_1;
+ mhi_uci0 = &mhi_uci;
+ mhi0 = &mhi;
+ };
+
+ gpio-leds {
+ compatible = "gpio-leds";
+
+ status {
+ gpios = <&tlmm 21 0>;
+ default-state = "on";
+ };
+ };
+
+ pps {
+ compatible = "pps-gpio";
+ pinctrl-names = "default";
+ pinctrl-0 = <&pmx_pps>;
+ gpios = <&tlmm 22 0>;
+ status = "okay";
+ };
+};
+
+&soc {
+ /delete-node/ sound-9335;
+
+ qcom,ntn_avb {
+ compatible = "qcom,ntn_avb";
+ vdd-ntn-pci-supply = <&ntn_vreg>;
+ vdd-ntn-io-supply = <&ntn_vreg>;
+ qcom,ntn-rst-delay-msec = <100>;
+ qcom,ntn-rc-num = <1>;
+ qcom,ntn-bus-num = <1>;
+ qcom,ntn-mdio-bus-id = <1>;
+ qcom,ntn-phy-addr = <7>;
+ qcom,msm-bus,name = "ntn";
+ qcom,msm-bus,num-cases = <2>;
+ qcom,msm-bus,num-paths = <1>;
+ qcom,msm-bus,vectors-KBps =
+ <100 512 0 0>,
+ <100 512 207108 14432000>;
+ };
+
+ usb_detect: usb_detect {
+ compatible = "qcom,gpio-usbdetect";
+ qcom,vbus-det-gpio = <&pm8994_gpios 17 0>;
+ interrupt-parent = <&spmi_bus>;
+ interrupts = <0x0 0x9 0x0 IRQ_TYPE_NONE>;
+ interrupt-names ="pmic_id_irq";
+ };
+
+ qcom,cnss {
+ vdd-wlan-en-supply = <&wlan_en_vreg>;
+ qcom,wlan-en-vreg-support;
+ /delete-property/ wlan-en-gpio;
+ /delete-property/ wlan-bootstrap-gpio;
+ /delete-property/ vdd-wlan-core-supply;
+ };
+
+ qcom,cnss_sdio {
+ compatible = "qcom,cnss_sdio";
+ subsys-name = "AR6320_SDIO";
+ vdd-wlan-supply = <&rome_vreg>;
+ vdd-wlan-xtal-supply = <&pm8994_l30>;
+ vdd-wlan-io-supply = <&pm8994_s4>;
+ vdd-wlan-dsrc-supply = <&dsrc_vreg>;
+ qcom,wlan-ramdump-dynamic = <0x200000>;
+ qcom,skip-wlan-en-toggle;
+ };
+
+ ntn_vreg: regulator-ntn-tps65051 {
+ compatible = "regulator-fixed";
+ regulator-name = "ntn_vreg";
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ startup-delay-us = <920>;
+ gpio = <&tlmm 138 0>;
+ enable-active-high;
+ };
+
+ eth_phy_vreg: regulator-eth-phy-tps65051 {
+ compatible = "regulator-fixed";
+ regulator-name = "eth_phy_vreg";
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ startup-delay-us = <920>;
+ gpio = <&tlmm 136 0>;
+ enable-active-high;
+ regulator-always-on;
+ };
+
+ hsm_vreg: regulator-hsm-tps22966 {
+ compatible = "regulator-fixed";
+ regulator-name = "hsm_vreg";
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ startup-delay-us = <2410>;
+ gpio = <&tlmm 81 0>;
+ enable-active-high;
+ regulator-always-on;
+ };
+
+ dsrc_vreg: dsrc_vreg {
+ compatible = "regulator-fixed";
+ regulator-name = "dsrc_vreg";
+ startup-delay-us = <2410>;
+ enable-active-high;
+ gpio = <&tlmm 125 0>;
+ };
+
+ mhi_rmnet_0: qcom,mhi-rmnet@0 {
+ compatible = "qcom,mhi-rmnet";
+ cell-index = <0>;
+ qcom,mhi = <&mhi>;
+ qcom,mhi-rx-channel = <101>;
+ qcom,mhi-tx-channel = <100>;
+ qcom,mhi-mru = <0x4000>;
+ status = "okay";
+ };
+
+ mhi_rmnet_1: qcom,mhi-rmnet@1 {
+ compatible = "qcom,mhi-rmnet";
+ cell-index = <1>;
+ qcom,mhi = <&mhi>;
+ qcom,mhi-rx-channel = <47>;
+ qcom,mhi-tx-channel = <46>;
+ qcom,mhi-mru = <0x4000>;
+ qcom,interface-name = "mhi_swip";
+ status = "okay";
+ };
+
+ mhi_uci: qcom,mhi-uci {
+ compatible = "qcom,mhi-uci";
+ qcom,mhi-uci-channels = <0 0xffff>,
+ <1 0x1000>,
+ <2 0xffff>,
+ <3 0xffff>,
+ <10 0xffff>,
+ <11 0x1000>,
+ <14 0xffff>,
+ <15 0x1000>,
+ <16 0xffff>,
+ <17 0x1000>,
+ <18 0xffff>,
+ <19 0x1000>,
+ <22 0xffff>,
+ <23 0x1000>,
+ <24 0xffff>,
+ <25 0x1000>,
+ <32 0xffff>,
+ <33 0x1000>;
+ qcom,mhi-uci-ctrlchan = <18>;
+ qcom,mhi = <&mhi>;
+ status = "okay";
+ };
+};
+
+/delete-node/ &sde_kms;
+/delete-node/ &sde_dsi0;
+/delete-node/ &sde_dsi1;
+/delete-node/ &sde_dsi_phy0;
+/delete-node/ &sde_dsi_phy1;
+/delete-node/ &sde_hdmi_tx;
+/delete-node/ &mdss_mdp;
+/delete-node/ &mdss_dsi;
+/delete-node/ &msm_ext_disp;
+/delete-node/ &mdss_hdmi_tx;
+/delete-node/ &mdss_rotator;
+/delete-node/ &routing;
+
+&pil_modem {
+ status = "disabled";
+};
+
+&pm8994_l9 {
+ regulator-always-on;
+};
+
+&pm8994_l10 {
+ regulator-always-on;
+};
+
+&wlan_en_vreg {
+ status = "okay";
+};
+
+&i2c_12 {
+ status = "disabled";
+};
+
+&spi_9 {
+ status = "okay";
+
+ /* CAN controller */
+ spi@0 {
+ compatible = "nxp,mpc57xx";
+ reg = <0>;
+ spi-max-frequency = <19200000>;
+ };
+};
+
+&spi_12 {
+ status = "okay";
+
+ /* HSM module */
+ spi@0 {
+ compatible = "infineon,sli97";
+ reg = <0>;
+ spi-max-frequency = <4800000>;
+ };
+};
+
+&ufs_ice {
+ status = "okay";
+};
+
+&ufsphy1 {
+ status = "okay";
+};
+
+&ufs1 {
+ status = "okay";
+};
+
+&uartblsp2dm1 {
+ status = "okay";
+ pinctrl-names = "default";
+ pinctrl-0 = <&uart_console_active>;
+};
+
+/* Rome SDIO */
+&sdhc_1 {
+ reg = <0x7464900 0x500>, <0x7464000 0x800>;
+ reg-names = "hc_mem", "core_mem";
+
+ vdd-supply = <&wlan_en_vreg>;
+
+ pinctrl-names = "active", "sleep";
+ pinctrl-0 = <&sdc1_clk_on &sdc1_cmd_on &sdc1_data_on>;
+ pinctrl-1 = <&sdc1_clk_off &sdc1_cmd_off &sdc1_data_off>;
+
+ qcom,clk-rates = <400000 20000000 25000000 50000000
+ 96000000 192000000>;
+ qcom,bus-speed-mode = "SDR12", "SDR25", "SDR50", "DDR50", "SDR104";
+
+ qcom,bus-width = <4>;
+ qcom,core_3_0v_support;
+ qcom,nonremovable;
+ qcom,force-sdhc1-probe;
+
+ status = "okay";
+};
+
+/* SDCARD slot */
+&sdhc_2 {
+ vdd-supply = <&pm8994_l21>;
+ qcom,vdd-voltage-level = <2950000 2950000>;
+ qcom,vdd-current-level = <200 800000>;
+
+ vdd-io-supply = <&pm8994_l13>;
+ qcom,vdd-io-voltage-level = <1800000 2950000>;
+ qcom,vdd-io-current-level = <200 22000>;
+
+ pinctrl-names = "active", "sleep";
+ pinctrl-0 = <&sdc2_clk_on &sdc2_cmd_on &sdc2_data_on
+ &sdc2_cd_on_sbc>;
+ pinctrl-1 = <&sdc2_clk_off &sdc2_cmd_off &sdc2_data_off
+ &sdc2_cd_off_sbc>;
+
+ qcom,clk-rates = <400000 20000000 25000000
+ 50000000 100000000 200000000>;
+ qcom,bus-speed-mode = "SDR12", "SDR25", "SDR50", "DDR50", "SDR104";
+
+ cd-gpios = <&tlmm 38 GPIO_ACTIVE_LOW>;
+
+ status = "okay";
+};
+
+&usb2s {
+ status = "okay";
+};
+
+&usb3 {
+ extcon = <&usb_detect>;
+ vbus_dwc3-supply = <&usb_otg_switch>;
+ vdda33-supply = <&pm8994_l24>;
+ vdda18-supply = <&pm8994_l12>;
+};
+
+&usb_otg_switch {
+ gpio = <&pm8994_gpios 11 0>;
+ enable-active-high;
+ status = "ok";
+ /delete-property/ vin-supply;
+};
+
+&pcie1 {
+ qcom,msi-gicm-addr = <0x09bd0040>;
+ qcom,msi-gicm-base = <0x240>;
+};
+
+&pcie2 {
+ /* Enumerate MDM on wake interrupt */
+ qcom,boot-option = <0x0>;
+};
+
+&mdm3 {
+ pinctrl-names = "mdm_active", "mdm_suspend";
+ pinctrl-0 = <&ap2mdm_active &mdm2ap_active>;
+ pinctrl-1 = <&ap2mdm_sleep &mdm2ap_sleep>;
+ interrupt-map = <0 &tlmm 108 0x3
+ 1 &tlmm 107 0x3
+ 2 &tlmm 112 0x3>;
+ qcom,mdm2ap-errfatal-gpio = <&tlmm 108 0x00>;
+ qcom,ap2mdm-errfatal-gpio = <&tlmm 109 0x00>;
+ qcom,mdm2ap-status-gpio = <&tlmm 106 0x00>;
+ qcom,ap2mdm-status-gpio = <&tlmm 107 0x00>;
+ qcom,ap2mdm-soft-reset-gpio = <&pm8994_mpps 2 GPIO_ACTIVE_LOW>;
+ qcom,ap2mdm-vddmin-gpio = <&tlmm 111 0x00>;
+ qcom,mdm2ap-vddmin-gpio = <&tlmm 112 0x00>;
+ status = "okay";
+};
+
+&mhi {
+ qcom,mhi-address-window = <0x0 0x80000000 0x1 0xffffffff>;
+ qcom,pci-dev_id = <0x0302>;
+ qcom,pci-domain = <2>;
+ qcom,pci-bus = <1>;
+ qcom,pci-slot = <0>;
+ esoc-names = "mdm";
+ esoc-0 = <&mdm3>;
+ qcom,msm-bus,name = "mhi";
+ qcom,msm-bus,num-cases = <2>;
+ qcom,msm-bus,num-paths = <1>;
+ qcom,msm-bus,vectors-KBps =
+ <100 512 0 0>,
+ <100 512 1200000000 650000000>;
+ mhi-chan-cfg-0 = <0x0 0x80 0x2 0x92>;
+ mhi-chan-cfg-1 = <0x1 0x80 0x2 0xa2>;
+ mhi-chan-cfg-2 = <0x2 0x80 0x1 0x91>;
+ mhi-chan-cfg-3 = <0x3 0x80 0x1 0xa1>;
+ mhi-chan-cfg-4 = <0x4 0x80 0x2 0x92>;
+ mhi-chan-cfg-5 = <0x5 0x80 0x2 0xa2>;
+ mhi-chan-cfg-6 = <0x6 0xa 0x2 0x92>;
+ mhi-chan-cfg-7 = <0x7 0xa 0x2 0xa2>;
+ mhi-chan-cfg-10 = <0xa 0x80 0x1 0x92>;
+ mhi-chan-cfg-11 = <0xb 0x80 0x1 0xa2>;
+ mhi-chan-cfg-14 = <0xe 0x40 0x1 0x92>;
+ mhi-chan-cfg-15 = <0xf 0x40 0x1 0xa2>;
+ mhi-chan-cfg-16 = <0x10 0x40 0x1 0x92>;
+ mhi-chan-cfg-17 = <0x11 0x40 0x1 0xa2>;
+ mhi-chan-cfg-18 = <0x12 0x40 0x1 0x92>;
+ mhi-chan-cfg-19 = <0x13 0x40 0x1 0xa2>;
+ mhi-chan-cfg-20 = <0x14 0xa 0x2 0x92>;
+ mhi-chan-cfg-21 = <0x15 0xa 0x2 0xa2>;
+ mhi-chan-cfg-22 = <0x16 0x40 0x2 0x92>;
+ mhi-chan-cfg-23 = <0x17 0x40 0x2 0xa2>;
+ mhi-chan-cfg-24 = <0x18 0xa 0x1 0x91>;
+ mhi-chan-cfg-25 = <0x19 0xa 0x1 0xa1>;
+ mhi-chan-cfg-32 = <0x20 0x80 0x2 0x92>;
+ mhi-chan-cfg-33 = <0x21 0x80 0x2 0xa2>;
+ mhi-chan-cfg-34 = <0x22 0x80 0x2 0x92>;
+ mhi-chan-cfg-35 = <0x23 0x80 0x2 0xa2>;
+ mhi-chan-cfg-46 = <0x2e 0x80 0x2 0x412>;
+ mhi-chan-cfg-47 = <0x2f 0x80 0x3 0x422>;
+ mhi-chan-cfg-100 = <0x64 0x80 0x4 0x652>;
+ mhi-chan-cfg-101 = <0x65 0x80 0x5 0x762>;
+ mhi-event-rings = <6>;
+ mhi-event-cfg-0 = <0x80 0x0 0x1 0 1 0x11>;
+ mhi-event-cfg-1 = <0x80 0x1 0x1 0 1 0x11>;
+ mhi-event-cfg-2 = <0x80 0x2 0x5 0 2 0x11>;
+ mhi-event-cfg-3 = <0x100 0x3 0x1 47 1 0x48>;
+ mhi-event-cfg-4 = <0x100 0x4 0x1 100 1 0x69>;
+ mhi-event-cfg-5 = <0x100 0x5 0x1 101 1 0x68>;
+ status = "okay";
+};
+
+&tlmm {
+ /* Set these up as hogs */
+ pinctrl-names = "default";
+ pinctrl-0 = <&can_reset_gpio>;
+};
+
+&pm8994_gpios {
+ gpio@c700 { /* GPIO 8 - WLAN_EN */
+ qcom,mode = <1>; /* Digital output*/
+ qcom,pull = <4>; /* Pulldown 10uA */
+ qcom,vin-sel = <2>; /* VIN2 */
+ qcom,src-sel = <0>; /* GPIO */
+ qcom,invert = <0>; /* Invert */
+ qcom,master-en = <1>; /* Enable GPIO */
+ status = "okay";
+ };
+
+ gpio@c800 { /* GPIO 9 - Rome 3.3V control */
+ qcom,mode = <1>; /* Digital output */
+ qcom,output-type = <0>; /* MOS logic */
+ qcom,invert = <1>; /* Output high */
+ qcom,vin-sel = <0>; /* VPH_PWR */
+ qcom,src-sel = <0>; /* Constant */
+ qcom,out-strength = <1>; /* High drive strength */
+ qcom,master-en = <1>; /* Enable GPIO */
+ status = "okay";
+ };
+
+ gpio@ca00 { /* GPIO 11 - USB ENB1 (otg switch) */
+ qcom,mode = <1>; /* DIGITAL OUT */
+ qcom,vin-sel = <2>; /* 1.8 */
+ qcom,src-sel = <0>; /* GPIO */
+ qcom,master-en = <1>; /* Enable GPIO */
+ status = "okay";
+ };
+
+ gpio@d000 { /* GPIO 17 - USB1 VBUS detect */
+ qcom,mode = <0>; /* Digital Input*/
+ qcom,pull = <5>; /* No pull */
+ qcom,vin-sel = <2>; /* 1.8 V */
+ qcom,src-sel = <0>; /* GPIO */
+ qcom,master-en = <1>; /* Enable GPIO */
+ status = "okay";
+ };
+
+ gpio@d100 { /* GPIO 18 - Rome Sleep Clock */
+ qcom,mode = <1>; /* Digital output */
+ qcom,output-type = <0>; /* CMOS logic */
+ qcom,invert = <0>; /* Output low initially */
+ qcom,vin-sel = <2>; /* VIN 2 */
+ qcom,src-sel = <3>; /* Function 2 */
+ qcom,out-strength = <2>; /* Medium */
+ qcom,master-en = <1>; /* Enable GPIO */
+ status = "okay";
+ };
+};
+
+&pm8994_mpps {
+ mpp@a100 { /* MPP 2 */
+ /* MDM PON conrol*/
+ qcom,mode = <1>; /* Digital output */
+ qcom,output-type = <0>; /* CMOS logic */
+ qcom,vin-sel = <2>; /* S4 1.8V */
+ qcom,src-sel = <0>; /* Constant */
+ qcom,master-en = <1>; /* Enable GPIO */
+ qcom,invert = <1>; /* Output high */
+ status = "okay";
+ };
+};
+
+&pm8994_vadc {
+ chan@5 {
+ label = "vcoin";
+ reg = <5>;
+ qcom,decimation = <0>;
+ qcom,pre-div-channel-scaling = <1>;
+ qcom,calibration-type = "absolute";
+ qcom,scale-function = <0>;
+ qcom,hw-settle-time = <0>;
+ qcom,fast-avg-setup = <0>;
+ };
+
+ chan@7 {
+ label = "vph_pwr";
+ reg = <7>;
+ qcom,decimation = <0>;
+ qcom,pre-div-channel-scaling = <1>;
+ qcom,calibration-type = "absolute";
+ qcom,scale-function = <0>;
+ qcom,hw-settle-time = <0>;
+ qcom,fast-avg-setup = <0>;
+ };
+
+ chan@73 {
+ label = "msm_therm";
+ reg = <0x73>;
+ qcom,decimation = <0>;
+ qcom,pre-div-channel-scaling = <0>;
+ qcom,calibration-type = "ratiometric";
+ qcom,scale-function = <2>;
+ qcom,hw-settle-time = <2>;
+ qcom,fast-avg-setup = <0>;
+ };
+
+ chan@74 {
+ label = "emmc_therm";
+ reg = <0x74>;
+ qcom,decimation = <0>;
+ qcom,pre-div-channel-scaling = <0>;
+ qcom,calibration-type = "ratiometric";
+ qcom,scale-function = <2>;
+ qcom,hw-settle-time = <2>;
+ qcom,fast-avg-setup = <0>;
+ };
+
+ chan@75 {
+ label = "pa_therm0";
+ reg = <0x75>;
+ qcom,decimation = <0>;
+ qcom,pre-div-channel-scaling = <0>;
+ qcom,calibration-type = "ratiometric";
+ qcom,scale-function = <2>;
+ qcom,hw-settle-time = <2>;
+ qcom,fast-avg-setup = <0>;
+ };
+
+ chan@77 {
+ label = "pa_therm1";
+ reg = <0x77>;
+ qcom,decimation = <0>;
+ qcom,pre-div-channel-scaling = <0>;
+ qcom,calibration-type = "ratiometric";
+ qcom,scale-function = <2>;
+ qcom,hw-settle-time = <2>;
+ qcom,fast-avg-setup = <0>;
+ };
+
+ chan@78 {
+ label = "quiet_therm";
+ reg = <0x78>;
+ qcom,decimation = <0>;
+ qcom,pre-div-channel-scaling = <0>;
+ qcom,calibration-type = "ratiometric";
+ qcom,scale-function = <2>;
+ qcom,hw-settle-time = <2>;
+ qcom,fast-avg-setup = <0>;
+ };
+
+ chan@7c {
+ label = "xo_therm_buf";
+ reg = <0x7c>;
+ qcom,decimation = <0>;
+ qcom,pre-div-channel-scaling = <0>;
+ qcom,calibration-type = "ratiometric";
+ qcom,scale-function = <4>;
+ qcom,hw-settle-time = <2>;
+ qcom,fast-avg-setup = <0>;
+ };
+};
+
+&pm8994_adc_tm {
+ chan@73 {
+ label = "msm_therm";
+ reg = <0x73>;
+ qcom,decimation = <0>;
+ qcom,pre-div-channel-scaling = <0>;
+ qcom,calibration-type = "ratiometric";
+ qcom,scale-function = <2>;
+ qcom,hw-settle-time = <2>;
+ qcom,fast-avg-setup = <0>;
+ qcom,btm-channel-number = <0x48>;
+ qcom,thermal-node;
+ };
+
+ chan@74 {
+ label = "emmc_therm";
+ reg = <0x74>;
+ qcom,decimation = <0>;
+ qcom,pre-div-channel-scaling = <0>;
+ qcom,calibration-type = "ratiometric";
+ qcom,scale-function = <2>;
+ qcom,hw-settle-time = <2>;
+ qcom,fast-avg-setup = <0>;
+ qcom,btm-channel-number = <0x68>;
+ qcom,thermal-node;
+ };
+
+ chan@75 {
+ label = "pa_therm0";
+ reg = <0x75>;
+ qcom,decimation = <0>;
+ qcom,pre-div-channel-scaling = <0>;
+ qcom,calibration-type = "ratiometric";
+ qcom,scale-function = <2>;
+ qcom,hw-settle-time = <2>;
+ qcom,fast-avg-setup = <0>;
+ qcom,btm-channel-number = <0x70>;
+ qcom,thermal-node;
+ };
+
+ chan@77 {
+ label = "pa_therm1";
+ reg = <0x77>;
+ qcom,decimation = <0>;
+ qcom,pre-div-channel-scaling = <0>;
+ qcom,calibration-type = "ratiometric";
+ qcom,scale-function = <2>;
+ qcom,hw-settle-time = <2>;
+ qcom,fast-avg-setup = <0>;
+ qcom,btm-channel-number = <0x78>;
+ qcom,thermal-node;
+ };
+
+ chan@78 {
+ label = "quiet_therm";
+ reg = <0x78>;
+ qcom,decimation = <0>;
+ qcom,pre-div-channel-scaling = <0>;
+ qcom,calibration-type = "ratiometric";
+ qcom,scale-function = <2>;
+ qcom,hw-settle-time = <2>;
+ qcom,fast-avg-setup = <0>;
+ qcom,btm-channel-number = <0x80>;
+ qcom,thermal-node;
+ };
+
+ chan@7c {
+ label = "xo_therm_buf";
+ reg = <0x7c>;
+ qcom,decimation = <0>;
+ qcom,pre-div-channel-scaling = <0>;
+ qcom,calibration-type = "ratiometric";
+ qcom,scale-function = <4>;
+ qcom,hw-settle-time = <2>;
+ qcom,fast-avg-setup = <0>;
+ qcom,btm-channel-number = <0x88>;
+ qcom,thermal-node;
+ };
+};
diff --git a/arch/arm/boot/dts/qcom/msm8996-pinctrl.dtsi b/arch/arm/boot/dts/qcom/msm8996-pinctrl.dtsi
index 316859a65801..d800fdaae3de 100644
--- a/arch/arm/boot/dts/qcom/msm8996-pinctrl.dtsi
+++ b/arch/arm/boot/dts/qcom/msm8996-pinctrl.dtsi
@@ -1,4 +1,4 @@
-/* Copyright (c) 2014-2016, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2014-2017, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -2731,5 +2731,32 @@
};
};
};
+
+ pmx_pps: pmx_pps {
+ mux {
+ pins = "gpio22";
+ function = "gpio";
+ };
+
+ config {
+ pins = "gpio22";
+ drive-strength = <16>; /* 16 mA */
+ bias-pull-down; /* pull down */
+ };
+ };
+
+ can_reset_gpio: can_reset_gpio {
+ mux {
+ pins = "gpio71";
+ function = "gpio";
+ };
+
+ config {
+ pins = "gpio71";
+ drive-strength = <2>;
+ output-high;
+ bias-pull-up;
+ };
+ };
};
};
diff --git a/arch/arm/boot/dts/qcom/msm8996-regulator.dtsi b/arch/arm/boot/dts/qcom/msm8996-regulator.dtsi
index 936dfd4d1cb2..1800a31dda9a 100644
--- a/arch/arm/boot/dts/qcom/msm8996-regulator.dtsi
+++ b/arch/arm/boot/dts/qcom/msm8996-regulator.dtsi
@@ -1986,5 +1986,6 @@
maxim,vrange-sel = <0>;
maxim,soft-start-slew-rate = <5500>;
maxim,dvs-slew-rate = <5500>;
+ status = "disabled";
};
};
diff --git a/arch/arm/boot/dts/qcom/msm8996.dtsi b/arch/arm/boot/dts/qcom/msm8996.dtsi
index f5e059484c95..505e325db1f5 100644
--- a/arch/arm/boot/dts/qcom/msm8996.dtsi
+++ b/arch/arm/boot/dts/qcom/msm8996.dtsi
@@ -176,6 +176,31 @@
soc: soc { };
+ firmware: firmware {
+ android {
+ compatible = "android,firmware";
+ fstab {
+ compatible = "android,fstab";
+ vendor {
+ compatible = "android,vendor";
+ dev = "/dev/block/platform/soc/7464900.sdhci/by-name/vendor";
+ type = "ext4";
+ mnt_flags = "ro,barrier=1,discard";
+ fsmgr_flags = "wait,verify";
+ status = "ok";
+ };
+ system {
+ compatible = "android,system";
+ dev = "/dev/block/platform/soc/7464900.sdhci/by-name/system";
+ type = "ext4";
+ mnt_flags = "ro,barrier=1,discard";
+ fsmgr_flags = "wait,verify";
+ status = "ok";
+ };
+ };
+ };
+ };
+
reserved-memory {
#address-cells = <2>;
#size-cells = <2>;
diff --git a/arch/arm/boot/dts/qcom/msm8996pro-auto-cv2x.dts b/arch/arm/boot/dts/qcom/msm8996pro-auto-cv2x.dts
new file mode 100644
index 000000000000..a89aa879436b
--- /dev/null
+++ b/arch/arm/boot/dts/qcom/msm8996pro-auto-cv2x.dts
@@ -0,0 +1,26 @@
+/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+/dts-v1/;
+
+#include <dt-bindings/gpio/gpio.h>
+#include "msm8996pro.dtsi"
+#include "msm8996-pm8994.dtsi"
+#include "msm8996pro-auto.dtsi"
+#include "msm8996-cv2x.dtsi"
+
+/ {
+ model = "Qualcomm Technologies, Inc. MSM 8996pro AUTO CV2X";
+ compatible = "qcom,msm8996-adp", "qcom,msm8996", "qcom,adp";
+ qcom,msm-id = <315 0x10001>;
+ qcom,board-id = <0x1e 0>;
+};
diff --git a/arch/arm/boot/dts/qcom/msm8998-sde.dtsi b/arch/arm/boot/dts/qcom/msm8998-sde.dtsi
index 354ac830e0fa..f95ef2b84e2c 100644
--- a/arch/arm/boot/dts/qcom/msm8998-sde.dtsi
+++ b/arch/arm/boot/dts/qcom/msm8998-sde.dtsi
@@ -14,7 +14,7 @@
sde_kms: qcom,sde_kms@c900000 {
compatible = "qcom,sde-kms";
reg = <0x0c900000 0x90000>,
- <0x0c9b0000 0x1040>;
+ <0x0c9b0000 0x2008>;
reg-names = "mdp_phys", "vbif_phys";
/* clock and supply entries */
@@ -52,23 +52,44 @@
/* hw blocks */
qcom,sde-off = <0x1000>;
+ qcom,sde-len = <0x458>;
+
qcom,sde-ctl-off = <0x2000 0x2200 0x2400
0x2600 0x2800>;
+ qcom,sde-ctl-size = <0x94>;
+
qcom,sde-mixer-off = <0x45000 0x46000 0x47000
0x48000 0x49000 0x4a000>;
+ qcom,sde-mixer-size = <0x31c>;
+
qcom,sde-dspp-off = <0x55000 0x57000>;
+ qcom,sde-dspp-size = <0x17e0>;
+
qcom,sde-wb-off = <0x66000>;
+ qcom,sde-wb-size = <0x2dc>;
+
qcom,sde-wb-id = <2>;
qcom,sde-wb-xin-id = <6>;
qcom,sde-wb-clk-ctrl = <0x2bc 0x10>;
qcom,sde-intf-off = <0x6b000 0x6b800
0x6c000 0x6c800>;
+ qcom,sde-intf-size = <0x280>;
+
qcom,sde-intf-type = "dp", "dsi", "dsi", "hdmi";
+
qcom,sde-pp-off = <0x71000 0x71800
- 0x72000 0x72800>;
- qcom,sde-te2-off = <0x2000 0x2000 0x0 0x0>;
+ 0x72000 0x72800 0x73000>;
+ qcom,sde-pp-slave = <0x0 0x0 0x0 0x0 0x1>;
+
+ qcom,sde-pp-size = <0xd4>;
+
+ qcom,sde-te2-off = <0x2000 0x2000 0x0 0x0 0x0>;
qcom,sde-cdm-off = <0x7a200>;
- qcom,sde-dsc-off = <0x10000 0x10000 0x0 0x0>;
+ qcom,sde-cdm-size = <0x224>;
+
+ qcom,sde-dsc-off = <0x81000 0x81400>;
+ qcom,sde-dsc-size = <0x140>;
+
qcom,sde-intf-max-prefetch-lines = <0x15 0x15 0x15 0x15>;
qcom,sde-sspp-type = "vig", "vig", "vig", "vig",
@@ -78,6 +99,7 @@
qcom,sde-sspp-off = <0x5000 0x7000 0x9000 0xb000
0x25000 0x27000 0x29000 0x2b000
0x35000 0x37000>;
+ qcom,sde-sspp-src-size = <0x1ac>;
qcom,sde-sspp-xin-id = <0 4 8 12 1 5 9 13 2 10>;
@@ -113,6 +135,7 @@
qcom,sde-sspp-vig-blocks {
qcom,sde-vig-csc-off = <0x1a00>;
qcom,sde-vig-qseed-off = <0xa00>;
+ qcom,sde-vig-qseed-size = <0xa0>;
};
qcom,platform-supply-entries {
diff --git a/arch/arm/boot/dts/qcom/msm8998-v2.dtsi b/arch/arm/boot/dts/qcom/msm8998-v2.dtsi
index acdd4bdcd95b..abc0247b4475 100644
--- a/arch/arm/boot/dts/qcom/msm8998-v2.dtsi
+++ b/arch/arm/boot/dts/qcom/msm8998-v2.dtsi
@@ -293,7 +293,8 @@
< 1900800 1525 >;
cpu-to-dev-map-4 =
< 2112000 1525 >,
- < 2496000 5195 >;
+ < 2342400 5195 >,
+ < 2496000 13763 >;
};
};
diff --git a/arch/arm/boot/dts/qcom/sda636-cdp.dts b/arch/arm/boot/dts/qcom/sda636-cdp.dts
new file mode 100644
index 000000000000..a4cc4b3f4662
--- /dev/null
+++ b/arch/arm/boot/dts/qcom/sda636-cdp.dts
@@ -0,0 +1,36 @@
+/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+
+/dts-v1/;
+
+#include "sda636.dtsi"
+#include "sdm636-cdp.dtsi"
+#include "sdm660-external-codec.dtsi"
+
+/ {
+ model = "Qualcomm Technologies, Inc. SDA 636 PM660 + PM660L CDP";
+ compatible = "qcom,sda636-cdp", "qcom,sda636", "qcom,cdp";
+ qcom,board-id = <1 0>;
+ qcom,pmic-id = <0x0001001b 0x0101011a 0x0 0x0>,
+ <0x0001001b 0x0201011a 0x0 0x0>;
+};
+
+&tavil_snd {
+ qcom,msm-mbhc-hphl-swh = <0>;
+ qcom,msm-mbhc-gnd-swh = <0>;
+};
+
+&tasha_snd {
+ qcom,msm-mbhc-hphl-swh = <0>;
+ qcom,msm-mbhc-gnd-swh = <0>;
+};
diff --git a/arch/arm/boot/dts/qcom/sda636-mtp.dts b/arch/arm/boot/dts/qcom/sda636-mtp.dts
new file mode 100644
index 000000000000..3fd19437b3eb
--- /dev/null
+++ b/arch/arm/boot/dts/qcom/sda636-mtp.dts
@@ -0,0 +1,30 @@
+/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+
+/dts-v1/;
+
+#include "sda636.dtsi"
+#include "sdm636-mtp.dtsi"
+#include "sdm660-external-codec.dtsi"
+
+/ {
+ model = "Qualcomm Technologies, Inc. SDA 636 PM660 + PM660L MTP";
+ compatible = "qcom,sda636-mtp", "qcom,sda636", "qcom,mtp";
+ qcom,board-id = <8 0>;
+ qcom,pmic-id = <0x0001001b 0x0101011a 0x0 0x0>,
+ <0x0001001b 0x0201011a 0x0 0x0>;
+};
+
+&tavil_snd {
+ qcom,msm-mbhc-moist-cfg = <0>, <0>, <3>;
+};
diff --git a/arch/arm/boot/dts/qcom/sda636-pm660a-cdp.dts b/arch/arm/boot/dts/qcom/sda636-pm660a-cdp.dts
new file mode 100644
index 000000000000..72db1be68c83
--- /dev/null
+++ b/arch/arm/boot/dts/qcom/sda636-pm660a-cdp.dts
@@ -0,0 +1,36 @@
+/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+
+/dts-v1/;
+
+#include "sda636.dtsi"
+#include "sdm636-cdp.dtsi"
+#include "msm-pm660a.dtsi"
+#include "sdm660-external-codec.dtsi"
+
+/ {
+ model = "Qualcomm Technologies, Inc. SDA 636 PM660 + PM660A CDP";
+ compatible = "qcom,sda636-cdp", "qcom,sda636", "qcom,cdp";
+ qcom,board-id = <1 0>;
+ qcom,pmic-id = <0x0001001b 0x0001011a 0x0 0x0>;
+};
+
+&tavil_snd {
+ qcom,msm-mbhc-hphl-swh = <0>;
+ qcom,msm-mbhc-gnd-swh = <0>;
+};
+
+&tasha_snd {
+ qcom,msm-mbhc-hphl-swh = <0>;
+ qcom,msm-mbhc-gnd-swh = <0>;
+};
diff --git a/arch/arm/boot/dts/qcom/sda636-pm660a-mtp.dts b/arch/arm/boot/dts/qcom/sda636-pm660a-mtp.dts
new file mode 100644
index 000000000000..fd5b94420102
--- /dev/null
+++ b/arch/arm/boot/dts/qcom/sda636-pm660a-mtp.dts
@@ -0,0 +1,30 @@
+/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+
+/dts-v1/;
+
+#include "sda636.dtsi"
+#include "sdm636-mtp.dtsi"
+#include "msm-pm660a.dtsi"
+#include "sdm660-external-codec.dtsi"
+
+/ {
+ model = "Qualcomm Technologies, Inc. SDA 636 PM660 + PM660A MTP";
+ compatible = "qcom,sda636-mtp", "qcom,sda636", "qcom,mtp";
+ qcom,board-id = <8 0>;
+ qcom,pmic-id = <0x0001001b 0x0001011a 0x0 0x0>;
+};
+
+&tavil_snd {
+ qcom,msm-mbhc-moist-cfg = <0>, <0>, <3>;
+};
diff --git a/arch/arm/boot/dts/qcom/sda636-pm660a-qrd-hdk.dts b/arch/arm/boot/dts/qcom/sda636-pm660a-qrd-hdk.dts
new file mode 100644
index 000000000000..3535c54f5dd0
--- /dev/null
+++ b/arch/arm/boot/dts/qcom/sda636-pm660a-qrd-hdk.dts
@@ -0,0 +1,240 @@
+/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+
+/dts-v1/;
+
+#include "sda636.dtsi"
+#include "sdm636-qrd.dtsi"
+#include "msm-pm660a.dtsi"
+
+&smb1351_charger {
+ status = "disabled";
+};
+
+&i2c_2 {
+ smb138x: qcom,smb138x@8 {
+ compatible = "qcom,i2c-pmic";
+ reg = <0x8>;
+ #address-cells = <1>;
+ #size-cells = <1>;
+ interrupt-parent = <&tlmm>;
+ interrupts = <21 IRQ_TYPE_LEVEL_LOW>;
+ interrupt_names = "smb138x";
+ interrupt-controller;
+ #interrupt-cells = <3>;
+ qcom,periph-map = <0x10 0x11 0x12 0x13 0x14 0x16 0x36>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&smb_int_default>;
+
+ smb138x_revid: qcom,revid@100 {
+ compatible = "qcom,qpnp-revid";
+ reg = <0x100 0x100>;
+ };
+
+ smb138x_tadc: qcom,tadc@3600 {
+ compatible = "qcom,tadc";
+ reg = <0x3600 0x100>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ #io-channel-cells = <1>;
+ interrupt-parent = <&smb138x>;
+ interrupts = <0x36 0x0 IRQ_TYPE_EDGE_BOTH>;
+ interrupt-names = "eoc";
+
+ batt_temp@0 {
+ reg = <0>;
+ qcom,rbias = <68100>;
+ qcom,rtherm-at-25degc = <68000>;
+ qcom,beta-coefficient = <3450>;
+ };
+
+ skin_temp@1 {
+ reg = <1>;
+ qcom,rbias = <33000>;
+ qcom,rtherm-at-25degc = <68000>;
+ qcom,beta-coefficient = <3450>;
+ };
+
+ die_temp@2 {
+ reg = <2>;
+ qcom,scale = <(-1306)>;
+ qcom,offset = <397904>;
+ };
+
+ batt_i@3 {
+ reg = <3>;
+ qcom,channel = <3>;
+ qcom,scale = <(-20000000)>;
+ };
+
+ batt_v@4 {
+ reg = <4>;
+ qcom,scale = <5000000>;
+ };
+
+ input_i@5 {
+ reg = <5>;
+ qcom,scale = <14285714>;
+ };
+
+ input_v@6 {
+ reg = <6>;
+ qcom,scale = <25000000>;
+ };
+
+ otg_i@7 {
+ reg = <7>;
+ qcom,scale = <5714286>;
+ };
+ };
+
+ smb138x_parallel_slave: qcom,smb138x-parallel-slave@1000 {
+ compatible = "qcom,smb138x-parallel-slave";
+ qcom,pmic-revid = <&smb138x_revid>;
+ reg = <0x1000 0x700>;
+ #address-cells = <1>;
+ #size-cells = <1>;
+ interrupt-parent = <&smb138x>;
+ io-channels =
+ <&smb138x_tadc 1>,
+ <&smb138x_tadc 2>,
+ <&smb138x_tadc 3>,
+ <&smb138x_tadc 14>,
+ <&smb138x_tadc 15>,
+ <&smb138x_tadc 16>,
+ <&smb138x_tadc 17>;
+ io-channel-names =
+ "connector_temp",
+ "charger_temp",
+ "batt_i",
+ "connector_temp_thr1",
+ "connector_temp_thr2",
+ "connector_temp_thr3",
+ "charger_temp_max";
+
+ qcom,chgr@1000 {
+ reg = <0x1000 0x100>;
+ interrupts = <0x10 0x1 IRQ_TYPE_EDGE_RISING>;
+ interrupt-names = "chg-state-change";
+ };
+
+ qcom,chgr-misc@1600 {
+ reg = <0x1600 0x100>;
+ interrupts = <0x16 0x1 IRQ_TYPE_EDGE_RISING>,
+ <0x16 0x6 IRQ_TYPE_EDGE_RISING>;
+ interrupt-names = "wdog-bark",
+ "temperature-change";
+ };
+ };
+ };
+};
+
+&tlmm {
+ smb_int_default: smb_int_default {
+ mux {
+ pins = "gpio21";
+ function = "gpio";
+ };
+
+ config {
+ pins = "gpio21";
+ drive-strength = <2>;
+ bias-pull-up;
+ };
+ };
+};
+
+/ {
+ model = "Qualcomm Technologies, Inc. SDA 636 PM660 + PM660A QRD HDK636";
+ compatible = "qcom,sda636-qrd", "qcom,sda636", "qcom,qrd";
+ qcom,board-id = <0x0016000b 0>;
+ qcom,pmic-id = <0x0001001b 0x0001011a 0x0 0x0>;
+};
+
+&pm660a_oledb {
+ status = "okay";
+ qcom,oledb-default-voltage-mv = <6400>;
+};
+
+&mdss_mdp {
+ qcom,mdss-pref-prim-intf = "dsi";
+};
+
+&mdss_dp_ctrl {
+ pinctrl-names = "mdss_dp_active", "mdss_dp_sleep";
+ pinctrl-0 = <&mdss_dp_aux_active &mdss_dp_usbplug_cc_active>;
+ pinctrl-1 = <&mdss_dp_aux_suspend &mdss_dp_usbplug_cc_suspend>;
+ qcom,aux-en-gpio = <&tlmm 55 0>;
+ qcom,aux-sel-gpio = <&tlmm 56 0>;
+ qcom,usbplug-cc-gpio = <&tlmm 58 0>;
+};
+
+&mdss_dsi {
+ hw-config = "single_dsi";
+};
+
+&mdss_dsi0 {
+ qcom,dsi-pref-prim-pan = <&dsi_rm67195_amoled_fhd_cmd>;
+ pinctrl-names = "mdss_default", "mdss_sleep";
+ pinctrl-0 = <&mdss_dsi_active &mdss_te_active>;
+ pinctrl-1 = <&mdss_dsi_suspend &mdss_te_suspend>;
+ lab-supply = <&lab_regulator>;
+ ibb-supply = <&ibb_regulator>;
+ qcom,platform-reset-gpio = <&tlmm 53 0>;
+ qcom,platform-te-gpio = <&tlmm 59 0>;
+};
+
+&dsi_rm67195_amoled_fhd_cmd {
+ qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_dcs";
+ qcom,mdss-dsi-bl-min-level = <1>;
+ qcom,mdss-dsi-bl-max-level = <255>;
+ qcom,panel-supply-entries = <&dsi_panel_pwr_supply_labibb_amoled>;
+};
+
+&tasha_snd {
+ qcom,audio-routing =
+ "AIF4 VI", "MCLK",
+ "RX_BIAS", "MCLK",
+ "MADINPUT", "MCLK",
+ "AMIC2", "MIC BIAS2",
+ "MIC BIAS2", "Headset Mic",
+ "DMIC0", "MIC BIAS1",
+ "MIC BIAS1", "Digital Mic0",
+ "DMIC3", "MIC BIAS3",
+ "MIC BIAS3", "Digital Mic3",
+ "DMIC5", "MIC BIAS4",
+ "MIC BIAS4", "Digital Mic5",
+ "SpkrLeft IN", "SPK1 OUT";
+ qcom,msm-mbhc-hphl-swh = <0>;
+};
+
+&usb2s {
+ status = "okay";
+};
+
+&qusb_phy0 {
+ reg = <0x0c012000 0x180>,
+ <0x00188018 0x4>;
+ reg-names = "qusb_phy_base",
+ "ref_clk_addr";
+ qcom,qusb-phy-init-seq = <0xf8 0x80
+ 0xb3 0x84
+ 0x83 0x88
+ 0xc7 0x8c
+ 0x30 0x08
+ 0x79 0x0c
+ 0x21 0x10
+ 0x14 0x9c
+ 0x9f 0x1c
+ 0x00 0x18>;
+};
diff --git a/arch/arm/boot/dts/qcom/sda636-pm660a-rcm.dts b/arch/arm/boot/dts/qcom/sda636-pm660a-rcm.dts
new file mode 100644
index 000000000000..321de0526c77
--- /dev/null
+++ b/arch/arm/boot/dts/qcom/sda636-pm660a-rcm.dts
@@ -0,0 +1,36 @@
+/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+
+/dts-v1/;
+
+#include "sda636.dtsi"
+#include "sdm636-cdp.dtsi"
+#include "msm-pm660a.dtsi"
+#include "sdm660-external-codec.dtsi"
+
+/ {
+ model = "Qualcomm Technologies, Inc. SDA 636 PM660 + PM660A RCM";
+ compatible = "qcom,sda636-cdp", "qcom,sda636", "qcom,cdp";
+ qcom,board-id = <21 0>;
+ qcom,pmic-id = <0x0001001b 0x0001011a 0x0 0x0>;
+};
+
+&tavil_snd {
+ qcom,msm-mbhc-hphl-swh = <0>;
+ qcom,msm-mbhc-gnd-swh = <0>;
+};
+
+&tasha_snd {
+ qcom,msm-mbhc-hphl-swh = <0>;
+ qcom,msm-mbhc-gnd-swh = <0>;
+};
diff --git a/arch/arm/boot/dts/qcom/sda636-rcm.dts b/arch/arm/boot/dts/qcom/sda636-rcm.dts
new file mode 100644
index 000000000000..50cf84bef0e5
--- /dev/null
+++ b/arch/arm/boot/dts/qcom/sda636-rcm.dts
@@ -0,0 +1,36 @@
+/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+
+/dts-v1/;
+
+#include "sda636.dtsi"
+#include "sdm636-cdp.dtsi"
+#include "sdm660-external-codec.dtsi"
+
+/ {
+ model = "Qualcomm Technologies, Inc. SDA 636 PM660 + PM660L RCM";
+ compatible = "qcom,sda636-cdp", "qcom,sda636", "qcom,cdp";
+ qcom,board-id = <21 0>;
+ qcom,pmic-id = <0x0001001b 0x0101011a 0x0 0x0>,
+ <0x0001001b 0x0201011a 0x0 0x0>;
+};
+
+&tavil_snd {
+ qcom,msm-mbhc-hphl-swh = <0>;
+ qcom,msm-mbhc-gnd-swh = <0>;
+};
+
+&tasha_snd {
+ qcom,msm-mbhc-hphl-swh = <0>;
+ qcom,msm-mbhc-gnd-swh = <0>;
+};
diff --git a/arch/arm/boot/dts/qcom/sda636.dtsi b/arch/arm/boot/dts/qcom/sda636.dtsi
new file mode 100644
index 000000000000..a219ca92767a
--- /dev/null
+++ b/arch/arm/boot/dts/qcom/sda636.dtsi
@@ -0,0 +1,29 @@
+/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include "sdm636.dtsi"
+
+/ {
+ model = "Qualcomm Technologies, Inc. SDA 636";
+ compatible = "qcom,sda636";
+ qcom,msm-id = <346 0x0>;
+};
+
+&soc {
+ qcom,rmnet-ipa {
+ status = "disabled";
+ };
+};
+
+&ipa_hw {
+ status = "disabled";
+};
diff --git a/arch/arm/boot/dts/qcom/sdm630-qrd.dtsi b/arch/arm/boot/dts/qcom/sdm630-qrd.dtsi
index c24a41656f3a..af3c5d1b51da 100644
--- a/arch/arm/boot/dts/qcom/sdm630-qrd.dtsi
+++ b/arch/arm/boot/dts/qcom/sdm630-qrd.dtsi
@@ -399,9 +399,9 @@
&qusb_phy0 {
qcom,qusb-phy-init-seq = <0xf8 0x80
- 0x80 0x84
+ 0x83 0x84
0x83 0x88
- 0xc7 0x8c
+ 0xc3 0x8c
0x30 0x08
0x79 0x0c
0x21 0x10
diff --git a/arch/arm/boot/dts/qcom/sdm630.dtsi b/arch/arm/boot/dts/qcom/sdm630.dtsi
index 5618f02e34f2..e918864a3df7 100644
--- a/arch/arm/boot/dts/qcom/sdm630.dtsi
+++ b/arch/arm/boot/dts/qcom/sdm630.dtsi
@@ -1366,7 +1366,6 @@
qcom,up-timer = <1000 1000>;
qcom,down-timer = <1000 1000>;
- qcom,pc-override-index = <0 0>;
qcom,set-ret-inactive;
qcom,enable-llm-freq-vote;
qcom,llm-freq-up-timer = <327675 327675>;
diff --git a/arch/arm/boot/dts/qcom/sdm636-cdp.dts b/arch/arm/boot/dts/qcom/sdm636-cdp.dts
new file mode 100644
index 000000000000..47f5eba8f491
--- /dev/null
+++ b/arch/arm/boot/dts/qcom/sdm636-cdp.dts
@@ -0,0 +1,36 @@
+/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+
+/dts-v1/;
+
+#include "sdm636.dtsi"
+#include "sdm636-cdp.dtsi"
+#include "sdm660-external-codec.dtsi"
+
+/ {
+ model = "Qualcomm Technologies, Inc. SDM 636 PM660 + PM660L CDP";
+ compatible = "qcom,sdm636-cdp", "qcom,sdm636", "qcom,cdp";
+ qcom,board-id = <1 0>;
+ qcom,pmic-id = <0x0001001b 0x0101011a 0x0 0x0>,
+ <0x0001001b 0x0201011a 0x0 0x0>;
+};
+
+&tavil_snd {
+ qcom,msm-mbhc-hphl-swh = <0>;
+ qcom,msm-mbhc-gnd-swh = <0>;
+};
+
+&tasha_snd {
+ qcom,msm-mbhc-hphl-swh = <0>;
+ qcom,msm-mbhc-gnd-swh = <0>;
+};
diff --git a/arch/arm/boot/dts/qcom/sdm636-cdp.dtsi b/arch/arm/boot/dts/qcom/sdm636-cdp.dtsi
new file mode 100644
index 000000000000..279a542be7e4
--- /dev/null
+++ b/arch/arm/boot/dts/qcom/sdm636-cdp.dtsi
@@ -0,0 +1,27 @@
+/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include "sdm660-cdp.dtsi"
+/ {
+};
+
+&mdss_dsi {
+ hw-config = "single_dsi";
+};
+
+&mdss_dsi0 {
+ qcom,dsi-pref-prim-pan = <&dsi_nt35695b_truly_fhd_video>;
+};
+
+&mdss_dsi1 {
+ status = "disabled";
+};
diff --git a/arch/arm/boot/dts/qcom/sdm636-headset-jacktype-no-cdp.dts b/arch/arm/boot/dts/qcom/sdm636-headset-jacktype-no-cdp.dts
new file mode 100644
index 000000000000..4d47ac1ef517
--- /dev/null
+++ b/arch/arm/boot/dts/qcom/sdm636-headset-jacktype-no-cdp.dts
@@ -0,0 +1,26 @@
+/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+
+/dts-v1/;
+
+#include "sdm636.dtsi"
+#include "sdm636-cdp.dtsi"
+#include "sdm660-external-codec.dtsi"
+
+/ {
+ model = "Qualcomm Technologies, Inc. SDM 636 PM660 + PM660L, Headset Jacktype NO, CDP";
+ compatible = "qcom,sdm636-cdp", "qcom,sdm636", "qcom,cdp";
+ qcom,board-id = <1 2>;
+ qcom,pmic-id = <0x0001001b 0x0101011a 0x0 0x0>,
+ <0x0001001b 0x0201011a 0x0 0x0>;
+};
diff --git a/arch/arm/boot/dts/qcom/sdm636-headset-jacktype-no-rcm.dts b/arch/arm/boot/dts/qcom/sdm636-headset-jacktype-no-rcm.dts
new file mode 100644
index 000000000000..dfe066d1902c
--- /dev/null
+++ b/arch/arm/boot/dts/qcom/sdm636-headset-jacktype-no-rcm.dts
@@ -0,0 +1,26 @@
+/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+
+/dts-v1/;
+
+#include "sdm636.dtsi"
+#include "sdm636-cdp.dtsi"
+#include "sdm660-external-codec.dtsi"
+
+/ {
+ model = "Qualcomm Technologies, Inc. SDM 636 PM660 + PM660L, Headset Jacktype NO, RCM";
+ compatible = "qcom,sdm636-cdp", "qcom,sdm636", "qcom,cdp";
+ qcom,board-id = <21 2>;
+ qcom,pmic-id = <0x0001001b 0x0101011a 0x0 0x0>,
+ <0x0001001b 0x0201011a 0x0 0x0>;
+};
diff --git a/arch/arm/boot/dts/qcom/sdm636-internal-codec-cdp.dts b/arch/arm/boot/dts/qcom/sdm636-internal-codec-cdp.dts
new file mode 100644
index 000000000000..725e9739a487
--- /dev/null
+++ b/arch/arm/boot/dts/qcom/sdm636-internal-codec-cdp.dts
@@ -0,0 +1,26 @@
+/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+
+/dts-v1/;
+
+#include "sdm636.dtsi"
+#include "sdm636-cdp.dtsi"
+#include "sdm660-internal-codec.dtsi"
+
+/ {
+ model = "Qualcomm Technologies, Inc. SDM 636 PM660 + PM660L Int. Audio Codec CDP";
+ compatible = "qcom,sdm636-cdp", "qcom,sdm636", "qcom,cdp";
+ qcom,board-id = <1 1>;
+ qcom,pmic-id = <0x0001001b 0x0101011a 0x0 0x0>,
+ <0x0001001b 0x0201011a 0x0 0x0>;
+};
diff --git a/arch/arm/boot/dts/qcom/sdm636-internal-codec-mtp.dts b/arch/arm/boot/dts/qcom/sdm636-internal-codec-mtp.dts
new file mode 100644
index 000000000000..3630e329b13d
--- /dev/null
+++ b/arch/arm/boot/dts/qcom/sdm636-internal-codec-mtp.dts
@@ -0,0 +1,30 @@
+/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+
+/dts-v1/;
+
+#include "sdm636.dtsi"
+#include "sdm636-mtp.dtsi"
+#include "sdm660-internal-codec.dtsi"
+
+/ {
+ model = "Qualcomm Technologies, Inc. SDM 636 PM660 + PM660L Int. Audio Codec MTP";
+ compatible = "qcom,sdm636-mtp", "qcom,sdm636", "qcom,mtp";
+ qcom,board-id = <8 1>;
+ qcom,pmic-id = <0x0001001b 0x0101011a 0x0 0x0>,
+ <0x0001001b 0x0201011a 0x0 0x0>;
+};
+
+&int_codec {
+ qcom,model = "sdm660-snd-card-mtp";
+};
diff --git a/arch/arm/boot/dts/qcom/sdm636-internal-codec-pm660a-cdp.dts b/arch/arm/boot/dts/qcom/sdm636-internal-codec-pm660a-cdp.dts
new file mode 100644
index 000000000000..416cd3754a10
--- /dev/null
+++ b/arch/arm/boot/dts/qcom/sdm636-internal-codec-pm660a-cdp.dts
@@ -0,0 +1,26 @@
+/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+
+/dts-v1/;
+
+#include "sdm636.dtsi"
+#include "sdm636-cdp.dtsi"
+#include "msm-pm660a.dtsi"
+#include "sdm660-internal-codec.dtsi"
+
+/ {
+ model = "Qualcomm Technologies, Inc. SDM 636 PM660 + PM660A Int. Audio Codec CDP";
+ compatible = "qcom,sdm636-cdp", "qcom,sdm636", "qcom,cdp";
+ qcom,board-id = <1 1>;
+ qcom,pmic-id = <0x0001001b 0x0001011a 0x0 0x0>;
+};
diff --git a/arch/arm/boot/dts/qcom/sdm636-internal-codec-pm660a-mtp.dts b/arch/arm/boot/dts/qcom/sdm636-internal-codec-pm660a-mtp.dts
new file mode 100644
index 000000000000..e9ad9048c6e9
--- /dev/null
+++ b/arch/arm/boot/dts/qcom/sdm636-internal-codec-pm660a-mtp.dts
@@ -0,0 +1,31 @@
+/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+
+/dts-v1/;
+
+#include "sdm636.dtsi"
+#include "sdm636-mtp.dtsi"
+#include "msm-pm660a.dtsi"
+#include "sdm660-internal-codec.dtsi"
+
+/ {
+ model = "Qualcomm Technologies, Inc. SDM 636 PM660 + PM660A Int. Audio Codec MTP";
+ compatible = "qcom,sdm636-mtp", "qcom,sdm636", "qcom,mtp";
+ qcom,board-id = <8 1>;
+ qcom,pmic-id = <0x0001001b 0x0001011a 0x0 0x0>;
+};
+
+&int_codec {
+ qcom,model = "sdm660-snd-card-mtp";
+ status = "okay";
+};
diff --git a/arch/arm/boot/dts/qcom/sdm636-internal-codec-pm660a-rcm.dts b/arch/arm/boot/dts/qcom/sdm636-internal-codec-pm660a-rcm.dts
new file mode 100644
index 000000000000..1812423ed948
--- /dev/null
+++ b/arch/arm/boot/dts/qcom/sdm636-internal-codec-pm660a-rcm.dts
@@ -0,0 +1,26 @@
+/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+
+/dts-v1/;
+
+#include "sdm636.dtsi"
+#include "sdm636-cdp.dtsi"
+#include "msm-pm660a.dtsi"
+#include "sdm660-internal-codec.dtsi"
+
+/ {
+ model = "Qualcomm Technologies, Inc. SDM 636 PM660 + PM660A Int. Audio Codec RCM";
+ compatible = "qcom,sdm636-cdp", "qcom,sdm636", "qcom,cdp";
+ qcom,board-id = <21 1>;
+ qcom,pmic-id = <0x0001001b 0x0001011a 0x0 0x0>;
+};
diff --git a/arch/arm/boot/dts/qcom/sdm636-internal-codec-rcm.dts b/arch/arm/boot/dts/qcom/sdm636-internal-codec-rcm.dts
new file mode 100644
index 000000000000..4bb67fa5bb71
--- /dev/null
+++ b/arch/arm/boot/dts/qcom/sdm636-internal-codec-rcm.dts
@@ -0,0 +1,26 @@
+/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+
+/dts-v1/;
+
+#include "sdm636.dtsi"
+#include "sdm636-cdp.dtsi"
+#include "sdm660-internal-codec.dtsi"
+
+/ {
+ model = "Qualcomm Technologies, Inc. SDM 636 PM660 + PM660L Int. Audio Codec RCM";
+ compatible = "qcom,sdm636-cdp", "qcom,sdm636", "qcom,cdp";
+ qcom,board-id = <21 1>;
+ qcom,pmic-id = <0x0001001b 0x0101011a 0x0 0x0>,
+ <0x0001001b 0x0201011a 0x0 0x0>;
+};
diff --git a/arch/arm/boot/dts/qcom/sdm636-mtp.dts b/arch/arm/boot/dts/qcom/sdm636-mtp.dts
new file mode 100644
index 000000000000..7f08e44148b5
--- /dev/null
+++ b/arch/arm/boot/dts/qcom/sdm636-mtp.dts
@@ -0,0 +1,30 @@
+/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+
+/dts-v1/;
+
+#include "sdm636.dtsi"
+#include "sdm636-mtp.dtsi"
+#include "sdm660-external-codec.dtsi"
+
+/ {
+ model = "Qualcomm Technologies, Inc. SDM 636 PM660 + PM660L MTP";
+ compatible = "qcom,sdm636-mtp", "qcom,sdm636", "qcom,mtp";
+ qcom,board-id = <8 0>;
+ qcom,pmic-id = <0x0001001b 0x0101011a 0x0 0x0>,
+ <0x0001001b 0x0201011a 0x0 0x0>;
+};
+
+&tavil_snd {
+ qcom,msm-mbhc-moist-cfg = <0>, <0>, <3>;
+};
diff --git a/arch/arm/boot/dts/qcom/sdm636-mtp.dtsi b/arch/arm/boot/dts/qcom/sdm636-mtp.dtsi
new file mode 100644
index 000000000000..f1d96459ec17
--- /dev/null
+++ b/arch/arm/boot/dts/qcom/sdm636-mtp.dtsi
@@ -0,0 +1,27 @@
+/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include "sdm660-mtp.dtsi"
+/ {
+};
+
+&mdss_dsi {
+ hw-config = "single_dsi";
+};
+
+&mdss_dsi0 {
+ qcom,dsi-pref-prim-pan = <&dsi_nt35695b_truly_fhd_video>;
+};
+
+&mdss_dsi1 {
+ status = "disabled";
+};
diff --git a/arch/arm/boot/dts/qcom/sdm636-pm660a-cdp.dts b/arch/arm/boot/dts/qcom/sdm636-pm660a-cdp.dts
new file mode 100644
index 000000000000..84a28770d5a8
--- /dev/null
+++ b/arch/arm/boot/dts/qcom/sdm636-pm660a-cdp.dts
@@ -0,0 +1,54 @@
+/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+
+/dts-v1/;
+
+#include "sdm636.dtsi"
+#include "sdm636-cdp.dtsi"
+#include "msm-pm660a.dtsi"
+#include "sdm660-external-codec.dtsi"
+
+/ {
+ model = "Qualcomm Technologies, Inc. SDM 636 PM660 + PM660A CDP";
+ compatible = "qcom,sdm636-cdp", "qcom,sdm636", "qcom,cdp";
+ qcom,board-id = <1 0>;
+ qcom,pmic-id = <0x0001001b 0x0001011a 0x0 0x0>;
+};
+
+&mdss_dsi {
+ hw-config = "single_dsi";
+};
+
+&mdss_dsi0 {
+ qcom,dsi-pref-prim-pan = <&dsi_rm67195_amoled_fhd_cmd>;
+ oledb-supply = <&pm660a_oledb>;
+ lab-supply = <&lab_regulator>;
+ ibb-supply = <&ibb_regulator>;
+};
+
+&mdss_dsi1 {
+ status = "disabled";
+ oledb-supply = <&pm660a_oledb>;
+ lab-supply = <&lab_regulator>;
+ ibb-supply = <&ibb_regulator>;
+};
+
+&tavil_snd {
+ qcom,msm-mbhc-hphl-swh = <0>;
+ qcom,msm-mbhc-gnd-swh = <0>;
+};
+
+&tasha_snd {
+ qcom,msm-mbhc-hphl-swh = <0>;
+ qcom,msm-mbhc-gnd-swh = <0>;
+};
diff --git a/arch/arm/boot/dts/qcom/sdm636-pm660a-headset-jacktype-no-cdp.dts b/arch/arm/boot/dts/qcom/sdm636-pm660a-headset-jacktype-no-cdp.dts
new file mode 100644
index 000000000000..b2517e32ae26
--- /dev/null
+++ b/arch/arm/boot/dts/qcom/sdm636-pm660a-headset-jacktype-no-cdp.dts
@@ -0,0 +1,38 @@
+/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+
+/dts-v1/;
+
+#include "sdm636.dtsi"
+#include "sdm636-cdp.dtsi"
+#include "msm-pm660a.dtsi"
+#include "sdm660-external-codec.dtsi"
+
+/ {
+ model = "Qualcomm Technologies, Inc. SDM 636 PM660 + PM660A, Headset Jacktype NO, CDP";
+ compatible = "qcom,sdm636-cdp", "qcom,sdm636", "qcom,cdp";
+ qcom,board-id = <1 2>;
+ qcom,pmic-id = <0x0001001b 0x0001011a 0x0 0x0>;
+};
+
+&mdss_dsi0 {
+ oledb-supply = <&pm660a_oledb>;
+ lab-supply = <&lab_regulator>;
+ ibb-supply = <&ibb_regulator>;
+};
+
+&mdss_dsi1 {
+ oledb-supply = <&pm660a_oledb>;
+ lab-supply = <&lab_regulator>;
+ ibb-supply = <&ibb_regulator>;
+};
diff --git a/arch/arm/boot/dts/qcom/sdm636-pm660a-headset-jacktype-no-rcm.dts b/arch/arm/boot/dts/qcom/sdm636-pm660a-headset-jacktype-no-rcm.dts
new file mode 100644
index 000000000000..20b4365380bb
--- /dev/null
+++ b/arch/arm/boot/dts/qcom/sdm636-pm660a-headset-jacktype-no-rcm.dts
@@ -0,0 +1,26 @@
+/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+
+/dts-v1/;
+
+#include "sdm636.dtsi"
+#include "sdm636-cdp.dtsi"
+#include "msm-pm660a.dtsi"
+#include "sdm660-external-codec.dtsi"
+
+/ {
+ model = "Qualcomm Technologies, Inc. SDM 636 PM660 + PM660A, Headset Jacktype NO, RCM";
+ compatible = "qcom,sdm636-cdp", "qcom,sdm636", "qcom,cdp";
+ qcom,board-id = <21 2>;
+ qcom,pmic-id = <0x0001001b 0x0001011a 0x0 0x0>;
+};
diff --git a/arch/arm/boot/dts/qcom/sdm636-pm660a-mtp.dts b/arch/arm/boot/dts/qcom/sdm636-pm660a-mtp.dts
new file mode 100644
index 000000000000..966a00af7216
--- /dev/null
+++ b/arch/arm/boot/dts/qcom/sdm636-pm660a-mtp.dts
@@ -0,0 +1,48 @@
+/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+
+/dts-v1/;
+
+#include "sdm636.dtsi"
+#include "sdm636-mtp.dtsi"
+#include "msm-pm660a.dtsi"
+#include "sdm660-external-codec.dtsi"
+
+/ {
+ model = "Qualcomm Technologies, Inc. SDM 636 PM660 + PM660A MTP";
+ compatible = "qcom,sdm636-mtp", "qcom,sdm636", "qcom,mtp";
+ qcom,board-id = <8 0>;
+ qcom,pmic-id = <0x0001001b 0x0001011a 0x0 0x0>;
+};
+
+&mdss_dsi {
+ hw-config = "single_dsi";
+};
+
+&mdss_dsi0 {
+ qcom,dsi-pref-prim-pan = <&dsi_rm67195_amoled_fhd_cmd>;
+ oledb-supply = <&pm660a_oledb>;
+ lab-supply = <&lab_regulator>;
+ ibb-supply = <&ibb_regulator>;
+};
+
+&mdss_dsi1 {
+ status = "disabled";
+ oledb-supply = <&pm660a_oledb>;
+ lab-supply = <&lab_regulator>;
+ ibb-supply = <&ibb_regulator>;
+};
+
+&tavil_snd {
+ qcom,msm-mbhc-moist-cfg = <0>, <0>, <3>;
+};
diff --git a/arch/arm/boot/dts/qcom/sdm636-pm660a-qrd.dts b/arch/arm/boot/dts/qcom/sdm636-pm660a-qrd.dts
new file mode 100644
index 000000000000..d8b6c744a204
--- /dev/null
+++ b/arch/arm/boot/dts/qcom/sdm636-pm660a-qrd.dts
@@ -0,0 +1,56 @@
+/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+
+/dts-v1/;
+
+#include "sdm636.dtsi"
+#include "sdm636-qrd.dtsi"
+#include "msm-pm660a.dtsi"
+
+/ {
+ model = "Qualcomm Technologies, Inc. SDM 636 PM660 + PM660A QRD";
+ compatible = "qcom,sdm636-qrd", "qcom,sdm636", "qcom,qrd";
+ qcom,board-id = <0x0012000b 0>;
+ qcom,pmic-id = <0x0001001b 0x0001011a 0x0 0x0>;
+};
+
+&pm660a_oledb {
+ status = "okay";
+ qcom,oledb-default-voltage-mv = <6400>;
+};
+
+&mdss_mdp {
+ qcom,mdss-pref-prim-intf = "dsi";
+};
+
+&mdss_dsi {
+ hw-config = "single_dsi";
+};
+
+&mdss_dsi0 {
+ qcom,dsi-pref-prim-pan = <&dsi_rm67195_amoled_fhd_cmd>;
+ pinctrl-names = "mdss_default", "mdss_sleep";
+ pinctrl-0 = <&mdss_dsi_active &mdss_te_active>;
+ pinctrl-1 = <&mdss_dsi_suspend &mdss_te_suspend>;
+ lab-supply = <&lab_regulator>;
+ ibb-supply = <&ibb_regulator>;
+ qcom,platform-reset-gpio = <&tlmm 53 0>;
+ qcom,platform-te-gpio = <&tlmm 59 0>;
+};
+
+&dsi_rm67195_amoled_fhd_cmd {
+ qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_dcs";
+ qcom,mdss-dsi-bl-min-level = <1>;
+ qcom,mdss-dsi-bl-max-level = <255>;
+ qcom,panel-supply-entries = <&dsi_panel_pwr_supply_labibb_amoled>;
+};
diff --git a/arch/arm/boot/dts/qcom/sdm636-pm660a-rcm.dts b/arch/arm/boot/dts/qcom/sdm636-pm660a-rcm.dts
new file mode 100644
index 000000000000..a23b074b4392
--- /dev/null
+++ b/arch/arm/boot/dts/qcom/sdm636-pm660a-rcm.dts
@@ -0,0 +1,36 @@
+/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+
+/dts-v1/;
+
+#include "sdm636.dtsi"
+#include "sdm636-cdp.dtsi"
+#include "msm-pm660a.dtsi"
+#include "sdm660-external-codec.dtsi"
+
+/ {
+ model = "Qualcomm Technologies, Inc. SDM 636 PM660 + PM660A RCM";
+ compatible = "qcom,sdm636-cdp", "qcom,sdm636", "qcom,cdp";
+ qcom,board-id = <21 0>;
+ qcom,pmic-id = <0x0001001b 0x0001011a 0x0 0x0>;
+};
+
+&tavil_snd {
+ qcom,msm-mbhc-hphl-swh = <0>;
+ qcom,msm-mbhc-gnd-swh = <0>;
+};
+
+&tasha_snd {
+ qcom,msm-mbhc-hphl-swh = <0>;
+ qcom,msm-mbhc-gnd-swh = <0>;
+};
diff --git a/arch/arm/boot/dts/qcom/sdm636-qrd.dts b/arch/arm/boot/dts/qcom/sdm636-qrd.dts
new file mode 100644
index 000000000000..a2d22f281a5d
--- /dev/null
+++ b/arch/arm/boot/dts/qcom/sdm636-qrd.dts
@@ -0,0 +1,87 @@
+/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+
+/dts-v1/;
+
+#include "sdm636.dtsi"
+#include "sdm636-qrd.dtsi"
+
+/ {
+ model = "Qualcomm Technologies, Inc. SDM 636 PM660 + PM660L QRD";
+ compatible = "qcom,sdm636-qrd", "qcom,sdm636", "qcom,qrd";
+ qcom,board-id = <0x1000b 0>;
+ qcom,pmic-id = <0x0001001b 0x0101011a 0x0 0x0>,
+ <0x0001001b 0x0201011a 0x0 0x0>;
+};
+
+&mdss_mdp {
+ qcom,mdss-pref-prim-intf = "dsi";
+};
+
+&mdss_fb0 {
+ qcom,mdss-mixer-swap;
+};
+
+&mdss_dsi {
+ hw-config = "split_dsi";
+};
+
+&mdss_dsi0 {
+ qcom,dsi-pref-prim-pan = <&dsi_dual_nt36850_truly_cmd>;
+ pinctrl-names = "mdss_default", "mdss_sleep";
+ pinctrl-0 = <&mdss_dsi_active &mdss_te_active>;
+ pinctrl-1 = <&mdss_dsi_suspend &mdss_te_suspend>;
+ qcom,platform-reset-gpio = <&tlmm 53 0>;
+ qcom,platform-te-gpio = <&tlmm 59 0>;
+};
+
+&mdss_dsi1 {
+ qcom,dsi-pref-prim-pan = <&dsi_dual_nt36850_truly_cmd>;
+ pinctrl-names = "mdss_default", "mdss_sleep";
+ pinctrl-0 = <&mdss_dsi_active &mdss_te_active>;
+ pinctrl-1 = <&mdss_dsi_suspend &mdss_te_suspend>;
+ qcom,platform-reset-gpio = <&tlmm 53 0>;
+ qcom,platform-te-gpio = <&tlmm 59 0>;
+};
+
+&dsi_dual_nt36850_truly_cmd {
+ qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_wled";
+ qcom,mdss-dsi-bl-min-level = <1>;
+ qcom,mdss-dsi-bl-max-level = <4095>;
+ qcom,panel-supply-entries = <&dsi_panel_pwr_supply>;
+};
+
+&pm660l_wled {
+ qcom,led-strings-list = [00 01];
+};
+
+&soc {
+ hbtp {
+ compatible = "qcom,hbtp-input";
+ pinctrl-names = "pmx_ts_active", "pmx_ts_suspend";
+ pinctrl-0 = <&ts_rst_active>;
+ pinctrl-1 = <&ts_rst_suspend>;
+ vcc_ana-supply = <&pm660l_l3>;
+ vcc_dig-supply = <&pm660_l13>;
+ qcom,afe-load = <20000>;
+ qcom,afe-vtg-min = <3008000>;
+ qcom,afe-vtg-max = <3008000>;
+ qcom,dig-load = <40000>;
+ qcom,dig-vtg-min = <1808000>;
+ qcom,dig-vtg-max = <1808000>;
+ qcom,fb-resume-delay-us = <10000>;
+ qcom,afe-force-power-on;
+ qcom,afe-power-on-delay-us = <1000>;
+ qcom,afe-power-off-delay-us = <6>;
+ };
+};
diff --git a/arch/arm/boot/dts/qcom/sdm636-qrd.dtsi b/arch/arm/boot/dts/qcom/sdm636-qrd.dtsi
new file mode 100644
index 000000000000..8791e7420148
--- /dev/null
+++ b/arch/arm/boot/dts/qcom/sdm636-qrd.dtsi
@@ -0,0 +1,16 @@
+/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include "sdm660-qrd.dtsi"
+/ {
+};
+
diff --git a/arch/arm/boot/dts/qcom/sdm636-rcm.dts b/arch/arm/boot/dts/qcom/sdm636-rcm.dts
new file mode 100644
index 000000000000..5566610566f8
--- /dev/null
+++ b/arch/arm/boot/dts/qcom/sdm636-rcm.dts
@@ -0,0 +1,36 @@
+/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+
+/dts-v1/;
+
+#include "sdm636.dtsi"
+#include "sdm636-cdp.dtsi"
+#include "sdm660-external-codec.dtsi"
+
+/ {
+ model = "Qualcomm Technologies, Inc. SDM 636 PM660 + PM660L RCM";
+ compatible = "qcom,sdm636-cdp", "qcom,sdm636", "qcom,cdp";
+ qcom,board-id = <21 0>;
+ qcom,pmic-id = <0x0001001b 0x0101011a 0x0 0x0>,
+ <0x0001001b 0x0201011a 0x0 0x0>;
+};
+
+&tavil_snd {
+ qcom,msm-mbhc-hphl-swh = <0>;
+ qcom,msm-mbhc-gnd-swh = <0>;
+};
+
+&tasha_snd {
+ qcom,msm-mbhc-hphl-swh = <0>;
+ qcom,msm-mbhc-gnd-swh = <0>;
+};
diff --git a/arch/arm/boot/dts/qcom/sdm636-usbc-audio-mtp.dts b/arch/arm/boot/dts/qcom/sdm636-usbc-audio-mtp.dts
new file mode 100644
index 000000000000..90879cdf35cc
--- /dev/null
+++ b/arch/arm/boot/dts/qcom/sdm636-usbc-audio-mtp.dts
@@ -0,0 +1,31 @@
+/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+
+/dts-v1/;
+
+#include "sdm636.dtsi"
+#include "sdm636-mtp.dtsi"
+#include "sdm660-external-codec.dtsi"
+
+/ {
+ model = "Qualcomm Technologies, Inc. SDM 636 PM660 + PM660L, USBC Audio MTP";
+ compatible = "qcom,sdm636-mtp", "qcom,sdm636", "qcom,mtp";
+ qcom,board-id = <8 2>;
+ qcom,pmic-id = <0x0001001b 0x0101011a 0x0 0x0>,
+ <0x0001001b 0x0201011a 0x0 0x0>;
+};
+
+&tavil_snd {
+ qcom,msm-mbhc-moist-cfg = <0>, <0>, <3>;
+ qcom,msm-mbhc-usbc-audio-supported = <1>;
+};
diff --git a/arch/arm/boot/dts/qcom/sdm636-usbc-audio-rcm.dts b/arch/arm/boot/dts/qcom/sdm636-usbc-audio-rcm.dts
new file mode 100644
index 000000000000..6fff927913fa
--- /dev/null
+++ b/arch/arm/boot/dts/qcom/sdm636-usbc-audio-rcm.dts
@@ -0,0 +1,30 @@
+/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+
+/dts-v1/;
+
+#include "sdm636.dtsi"
+#include "sdm636-cdp.dtsi"
+#include "sdm660-external-codec.dtsi"
+
+/ {
+ model = "Qualcomm Technologies, Inc. SDM 636 PM660 + PM660L, USBC Audio, RCM";
+ compatible = "qcom,sdm636-cdp", "qcom,sdm636", "qcom,cdp";
+ qcom,board-id = <21 3>;
+ qcom,pmic-id = <0x0001001b 0x0101011a 0x0 0x0>,
+ <0x0001001b 0x0201011a 0x0 0x0>;
+};
+
+&tavil_snd {
+ qcom,msm-mbhc-usbc-audio-supported = <1>;
+};
diff --git a/arch/arm/boot/dts/qcom/sdm636.dtsi b/arch/arm/boot/dts/qcom/sdm636.dtsi
new file mode 100644
index 000000000000..8024eee279cb
--- /dev/null
+++ b/arch/arm/boot/dts/qcom/sdm636.dtsi
@@ -0,0 +1,73 @@
+/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include "sdm660.dtsi"
+
+/ {
+ model = "Qualcomm Technologies, Inc. SDM 636";
+ compatible = "qcom,sdm636";
+ qcom,msm-id = <345 0x0>;
+
+ reserved-memory {
+ /delete-node/ cdsp_fw_region@94a00000;
+
+ buffer_mem: buffer_region@94a00000 {
+ compatible = "removed-dma-pool";
+ no-map;
+ reg = <0x0 0x94a00000 0x0 0x100000>;
+ };
+ };
+};
+
+&soc {
+ /delete-node/ qcom,turing@1a300000;
+
+ /delete-node/ cti@7068000;
+ /delete-node/ turing_etm0;
+ funnel@6042000 {
+ ports {
+ /delete-node/ port@4;
+ };
+ };
+
+ devfreq_memlat_4: qcom,arm-memlat-mon-4 {
+ qcom,core-dev-table =
+ < 1113600 762 >,
+ < 1401600 3879 >,
+ < 1804800 5163 >;
+ };
+
+ devfreq_cpufreq: devfreq-cpufreq {
+ mincpubw-cpufreq {
+ cpu-to-dev-map-4 =
+ < 1113600 762 >,
+ < 1401600 2086 >,
+ < 1747200 2929 >,
+ < 1804800 5163 >;
+ };
+ };
+};
+
+&soc {
+ /delete-node/ arm,smmu-turing_q6@5180000;
+ qcom,msm_fastrpc {
+ /delete-node/ qcom,msm_fastrpc_compute_cb5;
+ /delete-node/ qcom,msm_fastrpc_compute_cb6;
+ /delete-node/ qcom,msm_fastrpc_compute_cb7;
+ /delete-node/ qcom,msm_fastrpc_compute_cb8;
+ /delete-node/ qcom,msm_fastrpc_compute_cb9;
+ /delete-node/ qcom,msm_fastrpc_compute_cb10;
+ /delete-node/ qcom,msm_fastrpc_compute_cb11;
+ /delete-node/ qcom,msm_fastrpc_compute_cb12;
+ /delete-node/ qcom,msm_fastrpc_compute_cb13;
+ };
+};
diff --git a/arch/arm/boot/dts/qcom/sdm660-gpu.dtsi b/arch/arm/boot/dts/qcom/sdm660-gpu.dtsi
index fecb86dcfdeb..2194cf606d29 100644
--- a/arch/arm/boot/dts/qcom/sdm660-gpu.dtsi
+++ b/arch/arm/boot/dts/qcom/sdm660-gpu.dtsi
@@ -506,6 +506,51 @@
qcom,bus-max = <0>;
};
};
+
+ qcom,gpu-pwrlevels-4 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ qcom,speed-bin = <78>;
+
+ qcom,initial-pwrlevel = <1>;
+
+ /* SVS */
+ qcom,gpu-pwrlevel@0 {
+ reg = <0>;
+ qcom,gpu-freq = <370000000>;
+ qcom,bus-freq = <8>;
+ qcom,bus-min = <6>;
+ qcom,bus-max = <11>;
+ };
+
+ /* Low SVS */
+ qcom,gpu-pwrlevel@1 {
+ reg = <1>;
+ qcom,gpu-freq = <266000000>;
+ qcom,bus-freq = <3>;
+ qcom,bus-min = <3>;
+ qcom,bus-max = <6>;
+ };
+
+ /* Min SVS */
+ qcom,gpu-pwrlevel@2 {
+ reg = <2>;
+ qcom,gpu-freq = <160000000>;
+ qcom,bus-freq = <3>;
+ qcom,bus-min = <3>;
+ qcom,bus-max = <5>;
+ };
+
+ /* XO */
+ qcom,gpu-pwrlevel@3 {
+ reg = <3>;
+ qcom,gpu-freq = <19200000>;
+ qcom,bus-freq = <0>;
+ qcom,bus-min = <0>;
+ qcom,bus-max = <0>;
+ };
+ };
};
};
diff --git a/arch/arm/boot/dts/qcom/sdm660-qrd.dtsi b/arch/arm/boot/dts/qcom/sdm660-qrd.dtsi
index e78c2474df4d..b1408cc295e8 100644
--- a/arch/arm/boot/dts/qcom/sdm660-qrd.dtsi
+++ b/arch/arm/boot/dts/qcom/sdm660-qrd.dtsi
@@ -121,9 +121,9 @@
&qusb_phy0 {
qcom,qusb-phy-init-seq = <0xf8 0x80
- 0x80 0x84
+ 0x83 0x84
0x83 0x88
- 0xc7 0x8c
+ 0xc3 0x8c
0x30 0x08
0x79 0x0c
0x21 0x10
diff --git a/arch/arm/boot/dts/qcom/sdm660-regulator.dtsi b/arch/arm/boot/dts/qcom/sdm660-regulator.dtsi
index a4111f6d1b94..6556c986ae75 100644
--- a/arch/arm/boot/dts/qcom/sdm660-regulator.dtsi
+++ b/arch/arm/boot/dts/qcom/sdm660-regulator.dtsi
@@ -700,11 +700,33 @@
regulator-max-microvolt = <8>;
qcom,cpr-fuse-corners = <5>;
- qcom,cpr-fuse-combos = <16>;
- qcom,cpr-speed-bins = <2>;
- qcom,cpr-speed-bin-corners = <8 8>;
- qcom,cpr-corners = <8>;
- qcom,cpr-corner-fmax-map = <2 3 4 5 8>;
+ qcom,cpr-fuse-combos = <32>;
+ qcom,cpr-speed-bins = <4>;
+ qcom,cpr-speed-bin-corners = <8 8 0 8>;
+ qcom,cpr-corners =
+ /* Speed bin 0 */
+ <8 8 8 8 8 8 8 8>,
+
+ /* Speed bin 1 */
+ <8 8 8 8 8 8 8 8>,
+
+ /* Speed bin 2 */
+ <0 0 0 0 0 0 0 0>,
+
+ /* Speed bin 3 */
+ <8 8 8 8 8 8 8 8>;
+ qcom,cpr-corner-fmax-map =
+ /* Speed bin 0 */
+ <2 3 4 5 8>,
+
+ /* Speed bin 1 */
+ <2 3 4 5 8>,
+
+ /* Speed bin 2 */
+ <0 0 0 0 0>,
+
+ /* Speed bin 3 */
+ <2 3 4 5 8>;
qcom,cpr-voltage-ceiling =
< 724000 724000 724000 788000 868000
@@ -715,9 +737,20 @@
744000 784000 844000>;
qcom,corner-frequencies =
+ /* Speed bin 0 */
+ <300000000 633600000 902400000
+ 1113600000 1401600000 1536000000
+ 1747200000 1843200000>,
+
+ /* Speed bin 1 */
+ <300000000 633600000 902400000
+ 1113600000 1401600000 1536000000
+ 1747200000 1843200000>,
+
+ /* Speed bin 3 */
<300000000 633600000 902400000
1113600000 1401600000 1536000000
- 1747200000 1843200000>;
+ 1612800000 1843200000>;
qcom,allow-voltage-interpolation;
qcom,allow-quotient-interpolation;
@@ -806,11 +839,34 @@
regulator-max-microvolt = <7>;
qcom,cpr-fuse-corners = <5>;
- qcom,cpr-fuse-combos = <16>;
- qcom,cpr-speed-bins = <2>;
- qcom,cpr-speed-bin-corners = <7 7>;
- qcom,cpr-corners = <7>;
- qcom,cpr-corner-fmax-map = <2 3 4 6 7>;
+ qcom,cpr-fuse-combos = <32>;
+ qcom,cpr-speed-bins = <4>;
+ qcom,cpr-speed-bin-corners = <7 7 0 7>;
+ qcom,cpr-corners =
+ /* Speed-bin 0 */
+ <7 7 7 7 7 7 7 7>,
+
+ /* Speed-bin 1 */
+ <7 7 7 7 7 7 7 7>,
+
+ /* Speed-bin 1 */
+ <0 0 0 0 0 0 0 0>,
+
+ /* Speed-bin 3 */
+ <7 7 7 7 7 7 7 7>;
+
+ qcom,cpr-corner-fmax-map =
+ /* Speed-bin 0 */
+ <2 3 4 6 7>,
+
+ /* Speed-bin 1 */
+ <2 3 4 6 7>,
+
+ /* Speed-bin 2 */
+ <0 0 0 0 0>,
+
+ /* Speed-bin 3 */
+ <2 3 4 6 7>;
qcom,cpr-voltage-ceiling =
<724000 724000 788000 868000
@@ -829,6 +885,11 @@
/* Speed bin 1 */
<300000000 1113600000 1401600000
1747200000 1958400000 2150400000
+ 2208000000>,
+
+ /* Speed bin 3 */
+ <300000000 1113600000 1401600000
+ 1747200000 1804800000 2150400000
2208000000>;
qcom,allow-voltage-interpolation;
diff --git a/arch/arm/boot/dts/qcom/sdm660.dtsi b/arch/arm/boot/dts/qcom/sdm660.dtsi
index e00753f8b3e7..c436ce643091 100644
--- a/arch/arm/boot/dts/qcom/sdm660.dtsi
+++ b/arch/arm/boot/dts/qcom/sdm660.dtsi
@@ -1254,10 +1254,11 @@
compatible = "qcom,clk-cpu-osm";
reg = <0x179c0000 0x4000>, <0x17916000 0x1000>,
<0x17816000 0x1000>, <0x179d1000 0x1000>,
- <0x00784130 0x8>, <0x17914800 0x800>;
+ <0x00784130 0x8>, <0x00784130 0x8>,
+ <0x17914800 0x800>;
reg-names = "osm", "pwrcl_pll", "perfcl_pll",
- "apcs_common", "perfcl_efuse",
- "pwrcl_acd";
+ "apcs_common", "pwrcl_efuse",
+ "perfcl_efuse", "pwrcl_acd";
qcom,acdtd-val = <0x0000a111 0x0000a111>;
qcom,acdcr-val = <0x002c5ffd 0x002c5ffd>;
@@ -1283,6 +1284,25 @@
< 1747200000 0x0404005b 0x09480048 0x2 7 >,
< 1843200000 0x04040060 0x094c004c 0x3 8 >;
+ qcom,pwrcl-speedbin1-v0 =
+ < 300000000 0x0004000f 0x01200020 0x1 1 >,
+ < 633600000 0x05040021 0x03200020 0x1 2 >,
+ < 902400000 0x0404002f 0x04260026 0x1 3 >,
+ < 1113600000 0x0404003a 0x052e002e 0x2 4 >,
+ < 1401600000 0x04040049 0x073a003a 0x2 5 >,
+ < 1536000000 0x04040050 0x08400040 0x2 6 >,
+ < 1747200000 0x0404005b 0x09480048 0x2 7 >,
+ < 1843200000 0x04040060 0x094c004c 0x3 8 >;
+
+ qcom,pwrcl-speedbin3-v0 =
+ < 300000000 0x0004000f 0x01200020 0x1 1 >,
+ < 633600000 0x05040021 0x03200020 0x1 2 >,
+ < 902400000 0x0404002f 0x04260026 0x1 3 >,
+ < 1113600000 0x0404003a 0x052e002e 0x2 4 >,
+ < 1401600000 0x04040049 0x073a003a 0x2 5 >,
+ < 1536000000 0x04040050 0x08400040 0x2 6 >,
+ < 1612800000 0x04040054 0x09430043 0x2 7 >;
+
qcom,perfcl-speedbin0-v0 =
< 300000000 0x0004000f 0x01200020 0x1 1 >,
< 1113600000 0x0404003a 0x052e002e 0x1 2 >,
@@ -1301,6 +1321,13 @@
< 2150400000 0x04040070 0x0b590059 0x2 6 >,
< 2208000000 0x04040073 0x0b5c005c 0x3 7 >;
+ qcom,perfcl-speedbin3-v0 =
+ < 300000000 0x0004000f 0x01200020 0x1 1 >,
+ < 1113600000 0x0404003a 0x052e002e 0x1 2 >,
+ < 1401600000 0x04040049 0x073a003a 0x2 3 >,
+ < 1747200000 0x0404005b 0x09480048 0x2 4 >,
+ < 1804800000 0x0404005e 0x094b004b 0x2 5 >;
+
qcom,up-timer = <1000 1000>;
qcom,down-timer = <1000 1000>;
qcom,pc-override-index = <0 0>;
@@ -1354,6 +1381,7 @@
< 1113600 >,
< 1401600 >,
< 1536000 >,
+ < 1612800 >,
< 1747200 >,
< 1843200 >;
@@ -1361,6 +1389,7 @@
< 1113600 >,
< 1401600 >,
< 1747200 >,
+ < 1804800 >,
< 1958400 >,
< 2150400 >,
< 2208000 >,
@@ -1577,7 +1606,6 @@
qcom,msm_fastrpc {
compatible = "qcom,msm-fastrpc-adsp";
qcom,fastrpc-glink;
- qcom,fastrpc-vmid-heap-shared;
qcom,msm_fastrpc_compute_cb1 {
compatible = "qcom,msm-fastrpc-compute-cb";
@@ -2056,6 +2084,7 @@
qcom,firmware-name = "modem";
qcom,pil-self-auth;
qcom,sysmon-id = <0>;
+ qcom,minidump-id = <0>;
qcom,ssctl-instance-id = <0x12>;
qcom,qdsp6v62-1-5;
memory-region = <&modem_fw_mem>;
@@ -2130,6 +2159,11 @@
compatible = "qcom,msm-imem-diag-dload";
reg = <0xc8 200>;
};
+
+ ss_mdump@b88 {
+ compatible = "qcom,msm-imem-minidump";
+ reg = <0xb88 28>;
+ };
};
qcom,ghd {
diff --git a/arch/arm/boot/dts/qcom/vplatform-lfv-agave.dtsi b/arch/arm/boot/dts/qcom/vplatform-lfv-agave.dtsi
new file mode 100644
index 000000000000..fddffee703d1
--- /dev/null
+++ b/arch/arm/boot/dts/qcom/vplatform-lfv-agave.dtsi
@@ -0,0 +1,50 @@
+/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+&soc {
+ qcom,msm-dai-mi2s {
+ dai_mi2s_sec: qcom,msm-dai-q6-mi2s-sec {
+ qcom,msm-mi2s-rx-lines = <2>;
+ qcom,msm-mi2s-tx-lines = <1>;
+ pinctrl-names = "default", "sleep";
+ pinctrl-0 = <&sec_mi2s_active &sec_mi2s_sd0_active
+ &sec_mi2s_sd1_active>;
+ pinctrl-1 = <&sec_mi2s_sleep &sec_mi2s_sd0_sleep
+ &sec_mi2s_sd1_sleep>;
+ };
+
+ dai_mi2s: qcom,msm-dai-q6-mi2s-tert {
+ pinctrl-names = "default", "sleep";
+ pinctrl-0 = <&tert_mi2s_active &tert_mi2s_sd0_active>;
+ pinctrl-1 = <&tert_mi2s_sleep &tert_mi2s_sd0_sleep>;
+ };
+
+ dai_mi2s_quat: qcom,msm-dai-q6-mi2s-quat {
+ pinctrl-names = "default", "sleep";
+ pinctrl-0 = <&quat_mi2s_active &quat_mi2s_sd0_active>;
+ pinctrl-1 = <&quat_mi2s_sleep &quat_mi2s_sd0_sleep>;
+ };
+ };
+
+ qcom,msm-dai-tdm-tert-rx {
+ pinctrl-names = "default", "sleep";
+ pinctrl-0 = <&tert_tdm_dout_active>;
+ pinctrl-1 = <&tert_tdm_dout_sleep>;
+ };
+
+ qcom,msm-dai-tdm-quat-rx {
+ pinctrl-names = "default", "sleep";
+ pinctrl-0 = <&quat_tdm_dout_active>;
+ pinctrl-1 = <&quat_tdm_dout_sleep>;
+ };
+};
+
diff --git a/arch/arm/boot/dts/qcom/vplatform-lfv-msm8996-pinctrl.dtsi b/arch/arm/boot/dts/qcom/vplatform-lfv-msm8996-pinctrl.dtsi
new file mode 100644
index 000000000000..ce7741f75b24
--- /dev/null
+++ b/arch/arm/boot/dts/qcom/vplatform-lfv-msm8996-pinctrl.dtsi
@@ -0,0 +1,538 @@
+/* Copyright (c) 2014-2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+&soc {
+ tlmm: pinctrl@01010000 {
+ compatible = "qcom,msm8996-pinctrl";
+ reg = <0x01010000 0x300000>;
+ interrupts = <0 208 0>;
+ gpio-controller;
+ #gpio-cells = <2>;
+ interrupt-controller;
+ #interrupt-cells = <2>;
+
+ blsp1_uart2_active: blsp1_uart2_active {
+ mux {
+ pins = "gpio41", "gpio42", "gpio43", "gpio44";
+ function = "blsp_uart2";
+ };
+
+ config {
+ pins = "gpio41", "gpio42", "gpio43", "gpio44";
+ drive-strength = <2>;
+ bias-disable;
+ };
+ };
+
+ blsp1_uart2_sleep: blsp1_uart2_sleep {
+ mux {
+ pins = "gpio41", "gpio42", "gpio43", "gpio44";
+ function = "gpio";
+ };
+
+ config {
+ pins = "gpio41", "gpio42", "gpio43", "gpio44";
+ drive-strength = <2>;
+ bias-disable;
+ };
+ };
+
+ usb_hub_reset_active: usb_hub_reset_active {
+ usb_hub_reset_active {
+ pins = "gpio103";
+ drive-strength = <8>; /* 8 mA */
+ bias-pull-up; /* pull up */
+ output-high;
+ };
+ };
+
+ usb_hub_reset_suspend: usb_hub_reset_suspend {
+ usb_hub_reset_suspend {
+ pins = "gpio103";
+ drive-strength = <2>; /* 2 mA */
+ bias-disable= <0>; /* no pull */
+ };
+ };
+
+ i2c_6 {
+ i2c_6_active: i2c_6_active {
+ mux {
+ pins = "gpio27", "gpio28";
+ function = "blsp_i2c6";
+ };
+
+ config {
+ pins = "gpio27", "gpio28";
+ drive-strength = <2>;
+ bias-disable;
+ };
+ };
+
+ i2c_6_sleep: i2c_6_sleep {
+ mux {
+ pins = "gpio27", "gpio28";
+ function = "blsp_i2c6";
+ };
+
+ config {
+ pins = "gpio27", "gpio28";
+ drive-strength = <2>;
+ bias-pull-up;
+ };
+ };
+ };
+
+ i2c_8 {
+ i2c_8_active: i2c_8_active {
+ mux {
+ pins = "gpio6", "gpio7";
+ function = "blsp_i2c8";
+ };
+
+ config {
+ pins = "gpio6", "gpio7";
+ drive-strength = <4>;
+ bias-disable;
+ };
+ };
+
+ i2c_8_sleep: i2c_8_sleep {
+ mux {
+ pins = "gpio6", "gpio7";
+ function = "blsp_i2c8";
+ };
+
+ config {
+ pins = "gpio6", "gpio7";
+ drive-strength = <4>;
+ bias-pull-up;
+ };
+ };
+ };
+
+ spi_9 {
+ spi_9_active: spi_9_active {
+ mux {
+ pins = "gpio49", "gpio50", "gpio51",
+ "gpio52";
+ function = "blsp_spi9";
+ };
+
+ config {
+ pins = "gpio49", "gpio50", "gpio51",
+ "gpio52";
+ drive-strength = <6>;
+ bias-disable;
+ };
+ };
+
+ spi_9_sleep: spi_9_sleep {
+ mux {
+ pins = "gpio49", "gpio50", "gpio51",
+ "gpio52";
+ function = "blsp_spi9";
+ };
+
+ config {
+ pins = "gpio49", "gpio50", "gpio51",
+ "gpio52";
+ drive-strength = <6>;
+ bias-disable;
+ };
+ };
+ };
+
+ cnss_pins {
+ cnss_bootstrap_active: cnss_bootstrap_active {
+ mux {
+ pins = "gpio46";
+ function = "gpio";
+ };
+
+ config {
+ pins = "gpio46";
+ drive-strength = <16>;
+ output-high;
+ bias-pull-up;
+ };
+ };
+ cnss_bootstrap_sleep: cnss_bootstrap_sleep {
+ mux {
+ pins = "gpio46";
+ function = "gpio";
+ };
+
+ config {
+ pins = "gpio46";
+ drive-strength = <2>;
+ output-low;
+ bias-pull-down;
+ };
+ };
+ };
+
+ sec_mi2s {
+ sec_mi2s_sleep: sec_mi2s_sleep {
+ mux {
+ pins = "gpio80", "gpio81";
+ function = "sec_mi2s";
+ };
+
+ config {
+ pins = "gpio80", "gpio81";
+ drive-strength = <2>; /* 2 mA */
+ bias-disable; /* NO PULL */
+ };
+ };
+ sec_mi2s_active: sec_mi2s_active {
+ mux {
+ pins = "gpio80", "gpio81";
+ function = "sec_mi2s";
+ };
+
+ config {
+ pins = "gpio80", "gpio81";
+ drive-strength = <8>; /* 8 mA */
+ bias-disable; /* NO PULL */
+ };
+ };
+ };
+
+ sec_mi2s_sd0 {
+ sec_mi2s_sd0_sleep: sec_mi2s_sd0_sleep {
+ mux {
+ pins = "gpio82";
+ function = "sec_mi2s";
+ };
+
+ config {
+ pins = "gpio82";
+ drive-strength = <2>; /* 2 mA */
+ bias-pull-down; /* PULL DOWN */
+ };
+ };
+ sec_mi2s_sd0_active: sec_mi2s_sd0_active {
+ mux {
+ pins = "gpio82";
+ function = "sec_mi2s";
+ };
+
+ config {
+ pins = "gpio82";
+ drive-strength = <8>; /* 8 mA */
+ bias-disable; /* NO PULL */
+ };
+ };
+ };
+
+ sec_mi2s_sd1 {
+ sec_mi2s_sd1_sleep: sec_mi2s_sd1_sleep {
+ mux {
+ pins = "gpio83";
+ function = "sec_mi2s";
+ };
+
+ config {
+ pins = "gpio83";
+ drive-strength = <2>; /* 2 mA */
+ bias-pull-down; /* PULL DOWN */
+ };
+ };
+ sec_mi2s_sd1_active: sec_mi2s_sd1_active {
+ mux {
+ pins = "gpio83";
+ function = "sec_mi2s";
+ };
+
+ config {
+ pins = "gpio83";
+ drive-strength = <8>; /* 8 mA */
+ bias-disable; /* NO PULL */
+ };
+ };
+ };
+
+ tert_mi2s {
+ tert_mi2s_sleep: tert_mi2s_sleep {
+ mux {
+ pins = "gpio75", "gpio76";
+ function = "ter_mi2s";
+ };
+
+ config {
+ pins = "gpio75", "gpio76";
+ drive-strength = <2>; /* 2 mA */
+ bias-pull-down; /* PULL DOWN */
+ };
+ };
+ tert_mi2s_active: tert_mi2s_active {
+ mux {
+ pins = "gpio75", "gpio76";
+ function = "ter_mi2s";
+ };
+
+ config {
+ pins = "gpio75", "gpio76";
+ drive-strength = <8>; /* 8 mA */
+ bias-disable; /* NO PULL */
+ output-high;
+ };
+ };
+ };
+
+ tert_mi2s_sd0 {
+ tert_mi2s_sd0_sleep: tert_mi2s_sd0_sleep {
+ mux {
+ pins = "gpio77";
+ function = "ter_mi2s";
+ };
+
+ config {
+ pins = "gpio77";
+ drive-strength = <2>; /* 2 mA */
+ bias-pull-down; /* PULL DOWN */
+ };
+ };
+ tert_mi2s_sd0_active: tert_mi2s_sd0_active {
+ mux {
+ pins = "gpio77";
+ function = "ter_mi2s";
+ };
+
+ config {
+ pins = "gpio77";
+ drive-strength = <8>; /* 8 mA */
+ bias-disable; /* NO PULL */
+ };
+ };
+ };
+
+ quat_mi2s {
+ quat_mi2s_sleep: quat_mi2s_sleep {
+ mux {
+ pins = "gpio58", "gpio59";
+ function = "qua_mi2s";
+ };
+
+ config {
+ pins = "gpio58", "gpio59";
+ drive-strength = <2>; /* 2 mA */
+ bias-pull-down; /* PULL DOWN */
+ };
+ };
+ quat_mi2s_active: quat_mi2s_active {
+ mux {
+ pins = "gpio58", "gpio59";
+ function = "qua_mi2s";
+ };
+
+ config {
+ pins = "gpio58", "gpio59";
+ drive-strength = <8>; /* 8 mA */
+ bias-disable; /* NO PULL */
+ output-high;
+ };
+ };
+ };
+
+ quat_mi2s_sd0 {
+ quat_mi2s_sd0_sleep: quat_mi2s_sd0_sleep {
+ mux {
+ pins = "gpio60";
+ function = "qua_mi2s";
+ };
+
+ config {
+ pins = "gpio60";
+ drive-strength = <2>; /* 2 mA */
+ bias-pull-down; /* PULL DOWN */
+ };
+ };
+ quat_mi2s_sd0_active: quat_mi2s_sd0_active {
+ mux {
+ pins = "gpio60";
+ function = "qua_mi2s";
+ };
+
+ config {
+ pins = "gpio60";
+ drive-strength = <8>; /* 8 mA */
+ bias-disable; /* NO PULL */
+ };
+ };
+ };
+
+ tert_tdm {
+ tert_tdm_sleep: tert_tdm_sleep {
+ mux {
+ pins = "gpio75", "gpio76";
+ function = "ter_mi2s";
+ };
+
+ config {
+ pins = "gpio75", "gpio76";
+ drive-strength = <2>; /* 2 mA */
+ bias-pull-down; /* PULL DOWN */
+ };
+ };
+ tert_tdm_active: tert_tdm_active {
+ mux {
+ pins = "gpio75", "gpio76";
+ function = "ter_mi2s";
+ };
+
+ config {
+ pins = "gpio75", "gpio76";
+ drive-strength = <8>; /* 8 mA */
+ bias-disable; /* NO PULL */
+ output-high;
+ };
+ };
+ };
+
+ tert_tdm_din {
+ tert_tdm_din_sleep: tert_tdm_din_sleep {
+ mux {
+ pins = "gpio77";
+ function = "ter_mi2s";
+ };
+
+ config {
+ pins = "gpio77";
+ drive-strength = <2>; /* 2 mA */
+ bias-pull-down; /* PULL DOWN */
+ };
+ };
+ tert_tdm_din_active: tert_tdm_din_active {
+ mux {
+ pins = "gpio77";
+ function = "ter_mi2s";
+ };
+
+ config {
+ pins = "gpio77";
+ drive-strength = <8>; /* 8 mA */
+ bias-disable; /* NO PULL */
+ };
+ };
+ };
+
+ tert_tdm_dout {
+ tert_tdm_dout_sleep: tert_tdm_dout_sleep {
+ mux {
+ pins = "gpio78";
+ function = "ter_mi2s";
+ };
+
+ config {
+ pins = "gpio78";
+ drive-strength = <2>; /* 2 mA */
+ bias-pull-down; /* PULL DOWN */
+ };
+ };
+ tert_tdm_dout_active: tert_tdm_dout_active {
+ mux {
+ pins = "gpio78";
+ function = "ter_mi2s";
+ };
+
+ config {
+ pins = "gpio78";
+ drive-strength = <8>; /* 8 mA */
+ bias-disable; /* NO PULL */
+ };
+ };
+ };
+
+ quat_tdm {
+ quat_tdm_sleep: quat_tdm_sleep {
+ mux {
+ pins = "gpio58", "gpio59";
+ function = "qua_mi2s";
+ };
+
+ config {
+ pins = "gpio58", "gpio59";
+ drive-strength = <2>; /* 2 mA */
+ bias-pull-down; /* PULL DOWN */
+ };
+ };
+ quat_tdm_active: quat_tdm_active {
+ mux {
+ pins = "gpio58", "gpio59";
+ function = "qua_mi2s";
+ };
+
+ config {
+ pins = "gpio58", "gpio59";
+ drive-strength = <8>; /* 8 mA */
+ bias-disable; /* NO PULL */
+ output-high;
+ };
+ };
+ };
+
+ quat_tdm_din {
+ quat_tdm_din_sleep: quat_tdm_din_sleep {
+ mux {
+ pins = "gpio60";
+ function = "qua_mi2s";
+ };
+
+ config {
+ pins = "gpio60";
+ drive-strength = <2>; /* 2 mA */
+ bias-pull-down; /* PULL DOWN */
+ };
+ };
+ quat_tdm_din_active: quat_tdm_din_active {
+ mux {
+ pins = "gpio60";
+ function = "qua_mi2s";
+ };
+
+ config {
+ pins = "gpio60";
+ drive-strength = <8>; /* 8 mA */
+ bias-disable; /* NO PULL */
+ };
+ };
+ };
+
+ quat_tdm_dout {
+ quat_tdm_dout_sleep: quat_tdm_dout_sleep {
+ mux {
+ pins = "gpio61";
+ function = "qua_mi2s";
+ };
+
+ config {
+ pins = "gpio61";
+ drive-strength = <2>; /* 2 mA */
+ bias-pull-down; /* PULL DOWN */
+ };
+ };
+ quat_tdm_dout_active: quat_tdm_dout_active {
+ mux {
+ pins = "gpio61";
+ function = "qua_mi2s";
+ };
+
+ config {
+ pins = "gpio61";
+ drive-strength = <8>; /* 8 mA */
+ bias-disable; /* NO PULL */
+ };
+ };
+ };
+ };
+};
diff --git a/arch/arm/boot/dts/qcom/vplatform-lfv-msm8996.dts b/arch/arm/boot/dts/qcom/vplatform-lfv-msm8996.dts
index 5c0bbbccafea..e6d9f7b7d2f2 100644
--- a/arch/arm/boot/dts/qcom/vplatform-lfv-msm8996.dts
+++ b/arch/arm/boot/dts/qcom/vplatform-lfv-msm8996.dts
@@ -13,12 +13,20 @@
/dts-v1/;
#include "skeleton64.dtsi"
+#include <dt-bindings/clock/msm-clocks-8996.h>
+#include <dt-bindings/interrupt-controller/arm-gic.h>
/ {
model = "Qualcomm Technologies, Inc. MSM 8996";
compatible = "qcom,msm8996";
qcom,msm-id = <246 0x0>;
+ aliases {
+ spi9 = &spi_9;
+ i2c6 = &i2c_6;
+ i2c8 = &i2c_8;
+ };
+
soc: soc { };
psci {
@@ -53,14 +61,33 @@
reg = <0 0xc8000000 0 0x00400000>;
label = "ion_audio_mem";
};
+ modem_mem: modem_region@88800000 {
+ compatible = "removed-dma-pool";
+ no-map;
+ reg = <0 0x88800000 0 0x6200000>;
+ };
+ peripheral_mem: peripheral_region@8ea00000 {
+ compatible = "removed-dma-pool";
+ no-map;
+ reg = <0 0x8ea00000 0 0x2b00000>;
+ };
+ adsp_mem: adsp_region {
+ compatible = "shared-dma-pool";
+ alloc-ranges = <0 0x00000000 0 0xffffffff>;
+ reusable;
+ alignment = <0 0x100000>;
+ size = <0 0x400000>;
+ };
};
};
#include "vplatform-lfv-ion.dtsi"
+#include "vplatform-lfv-smmu.dtsi"
&soc {
#address-cells = <1>;
#size-cells = <1>;
+ virtual-interrupt-parent = "gic";
ranges = <0 0 0 0xffffffff>;
compatible = "simple-bus";
@@ -125,11 +152,17 @@
asoc-codec = <&stub_codec>;
asoc-codec-names = "msm-stub-codec.1";
};
+ qcom,msm-adsp-loader {
+ status = "ok";
+ compatible = "qcom,adsp-loader";
+ qcom,adsp-state = <0>;
+ };
qcom,msm-audio-ion {
compatible = "qcom,msm-audio-ion";
+ qcom,smmu-version = <2>;
qcom,smmu-enabled;
- qcom,smmu-sid = <1>;
+ iommus = <&lpass_q6_smmu 1>;
};
pcm0: qcom,msm-pcm {
@@ -587,4 +620,580 @@
hostless: qcom,msm-pcm-hostless {
compatible = "qcom,msm-pcm-hostless";
};
+
+ qcom,msm-adsprpc-mem {
+ compatible = "qcom,msm-adsprpc-mem-region";
+ memory-region = <&adsp_mem>;
+ };
+
+ qcom,msm_fastrpc {
+ compatible = "qcom,msm-fastrpc-adsp";
+
+ qcom,msm_fastrpc_compute_cb1 {
+ compatible = "qcom,msm-fastrpc-compute-cb";
+ label = "adsprpc-smd";
+ iommus = <&lpass_q6_smmu 8>;
+ };
+ qcom,msm_fastrpc_compute_cb2 {
+ compatible = "qcom,msm-fastrpc-compute-cb";
+ label = "adsprpc-smd";
+ iommus = <&lpass_q6_smmu 9>;
+ };
+ qcom,msm_fastrpc_compute_cb3 {
+ compatible = "qcom,msm-fastrpc-compute-cb";
+ label = "adsprpc-smd";
+ iommus = <&lpass_q6_smmu 10>;
+ };
+ qcom,msm_fastrpc_compute_cb4 {
+ compatible = "qcom,msm-fastrpc-compute-cb";
+ label = "adsprpc-smd";
+ iommus = <&lpass_q6_smmu 11>;
+ };
+ qcom,msm_fastrpc_compute_cb5 {
+ compatible = "qcom,msm-fastrpc-compute-cb";
+ label = "adsprpc-smd";
+ iommus = <&lpass_q6_smmu 12>;
+ };
+ qcom,msm_fastrpc_compute_cb6 {
+ compatible = "qcom,msm-fastrpc-compute-cb";
+ label = "adsprpc-smd";
+ iommus = <&lpass_q6_smmu 5>;
+ };
+ qcom,msm_fastrpc_compute_cb7 {
+ compatible = "qcom,msm-fastrpc-compute-cb";
+ label = "adsprpc-smd";
+ iommus = <&lpass_q6_smmu 6>;
+ };
+ qcom,msm_fastrpc_compute_cb8 {
+ compatible = "qcom,msm-fastrpc-compute-cb";
+ label = "adsprpc-smd";
+ iommus = <&lpass_q6_smmu 7>;
+ };
+ };
+};
+
+#include "vplatform-lfv-msm8996-pinctrl.dtsi"
+#include "msm8996-smp2p.dtsi"
+
+&soc {
+ qcom,ipc-spinlock@740000 {
+ compatible = "qcom,ipc-spinlock-sfpb";
+ reg = <0x740000 0x8000>;
+ qcom,num-locks = <8>;
+ };
+
+ qcom,smem@86000000 {
+ compatible = "qcom,smem";
+ reg = <0x86000000 0x200000>,
+ <0x9820010 0x4>,
+ <0x7b4000 0x8>;
+ reg-names = "smem", "irq-reg-base",
+ "smem_targ_info_reg";
+ qcom,mpu-enabled;
+
+ qcom,smd-modem {
+ compatible = "qcom,smd";
+ qcom,smd-edge = <0>;
+ qcom,smd-irq-offset = <0x0>;
+ qcom,smd-irq-bitmask = <0x1000>;
+ interrupts = <0 449 1>;
+ label = "modem";
+ qcom,not-loadable;
+ };
+
+ qcom,smd-adsp {
+ compatible = "qcom,smd";
+ qcom,smd-edge = <0x1>;
+ qcom,smd-irq-offset = <0x0>;
+ qcom,smd-irq-bitmask = <0x100>;
+ interrupts = <0x0 0x9c 0x1>;
+ label = "adsp";
+ };
+ };
+
+ qcom,rmtfs_sharedmem@0 {
+ compatible = "qcom,sharedmem-uio";
+ reg = <0x85e00000 0x00200000>;
+ reg-names = "rmtfs";
+ qcom,client-id = <0x00000001>;
+ };
+
+ qcom,glink-smem-native-xprt-modem@86000000 {
+ compatible = "qcom,glink-smem-native-xprt";
+ reg = <0x86000000 0x200000>,
+ <0x9820010 0x4>;
+ reg-names = "smem", "irq-reg-base";
+ qcom,irq-mask = <0x8000>;
+ interrupts = <0 452 1>;
+ label = "mpss";
+ };
+
+ qcom,glink-smem-native-xprt-adsp@86000000 {
+ compatible = "qcom,glink-smem-native-xprt";
+ reg = <0x86000000 0x200000>,
+ <0x9820010 0x4>;
+ reg-names = "smem", "irq-reg-base";
+ qcom,irq-mask = <0x200>;
+ interrupts = <0 157 1>;
+ label = "lpass";
+ qcom,qos-config = <0x1b8>;
+ qcom,ramp-time = <0xaf>;
+ };
+
+ qcom,glink-qos-config-adsp {
+ compatible = "qcom,glink-qos-config";
+ qcom,flow-info = <0x3c 0x0 0x3c 0x0 0x3c 0x0 0x3c 0x0>;
+ qcom,mtu-size = <0x800>;
+ qcom,tput-stats-cycle = <0xa>;
+ linux,phandle = <0x1b8>;
+ phandle = <0x1b8>;
+ };
+
+ /* IPC router */
+ qcom,ipc_router {
+ compatible = "qcom,ipc_router";
+ qcom,node-id = <1>;
+ };
+
+ qcom,ipc_router_modem_xprt {
+ compatible = "qcom,ipc_router_glink_xprt";
+ qcom,ch-name = "IPCRTR";
+ qcom,xprt-remote = "mpss";
+ qcom,glink-xprt = "smd_trans";
+ qcom,xprt-linkid = <1>;
+ qcom,xprt-version = <1>;
+ qcom,fragmented-data;
+ };
+
+ qcom,ipc_router_q6_xprt {
+ compatible = "qcom,ipc_router_glink_xprt";
+ qcom,ch-name = "IPCRTR";
+ qcom,xprt-remote = "lpass";
+ qcom,glink-xprt = "smd_trans";
+ qcom,xprt-linkid = <1>;
+ qcom,xprt-version = <1>;
+ qcom,fragmented-data;
+ };
+
+ /* IPA including NDP-BAM */
+ ipa_hw: qcom,ipa@680000 {
+ compatible = "qcom,ipa";
+ reg = <0x680000 0x4effc>,
+ <0x684000 0x26934>;
+ reg-names = "ipa-base", "bam-base";
+ interrupts = <0 333 0>,
+ <0 432 0>;
+ interrupt-names = "ipa-irq", "bam-irq";
+ qcom,ipa-hw-ver = <5>; /* IPA core version = IPAv2.5 */
+ qcom,ipa-hw-mode = <0>;
+ qcom,ee = <0>;
+ qcom,use-ipa-tethering-bridge;
+ qcom,ipa-bam-remote-mode;
+ qcom,modem-cfg-emb-pipe-flt;
+ clocks = <&clock_gcc clk_ipa_clk>;
+ clock-names = "core_clk";
+ qcom,use-dma-zone;
+ qcom,msm-bus,name = "ipa";
+ qcom,msm-bus,num-cases = <3>;
+ qcom,msm-bus,num-paths = <2>;
+ qcom,msm-bus,vectors-KBps =
+ <90 512 0 0>, <90 585 0 0>, /* No vote */
+ <90 512 80000 640000>, <90 585 80000 640000>, /* SVS */
+ <90 512 206000 960000>, <90 585 206000 960000>; /* PERF */
+ qcom,bus-vector-names = "MIN", "SVS", "PERF";
+ };
+
+ /* rmnet over IPA */
+ qcom,rmnet-ipa {
+ compatible = "qcom,rmnet-ipa";
+ qcom,rmnet-ipa-ssr;
+ qcom,ipa-loaduC;
+ qcom,ipa-advertise-sg-support;
+ };
+
+ /* SPS */
+ qcom,sps {
+ compatible = "qcom,msm_sps_4k";
+ qcom,device-type = <3>;
+ qcom,pipe-attr-ee;
+ };
+
+ clock_gcc: qcom,gcc@300000 {
+ compatible = "qcom,dummycc";
+ #clock-cells = <1>;
+ #reset-cells = <1>;
+ };
+
+ clock_mmss: qcom,mmsscc@8c0000 {
+ compatible = "qcom,dummycc";
+ #clock-cells = <1>;
+ #reset-cells = <1>;
+ };
+
+ clock_gpu: qcom,gpucc@8c0000 {
+ compatible = "qcom,dummycc";
+ #clock-cells = <1>;
+ #reset-cells = <1>;
+ };
+
+ clock_debug: qcom,cc-debug@362000 {
+ compatible = "qcom,dummycc";
+ #clock-cells = <1>;
+ #reset-cells = <1>;
+ };
+
+ clock_cpu: qcom,cpu-clock-8996@ {
+ compatible = "qcom,dummycc";
+ #clock-cells = <1>;
+ #reset-cells = <1>;
+ };
+
+ pil_modem: qcom,mss@2080000 {
+ compatible = "qcom,pil-q6v55-mss";
+ reg = <0x2080000 0x100>,
+ <0x0763000 0x008>,
+ <0x0765000 0x008>,
+ <0x0764000 0x008>,
+ <0x2180000 0x020>,
+ <0x038f008 0x004>;
+ reg-names = "qdsp6_base", "halt_q6", "halt_modem",
+ "halt_nc", "rmb_base", "restart_reg";
+
+ clocks = <&clock_gcc clk_cxo_clk_src>,
+ <&clock_gcc clk_gcc_mss_cfg_ahb_clk>,
+ <&clock_gcc clk_pnoc_clk>,
+ <&clock_gcc clk_gcc_mss_q6_bimc_axi_clk>,
+ <&clock_gcc clk_gcc_boot_rom_ahb_clk>,
+ <&clock_gcc clk_gpll0_out_msscc>,
+ <&clock_gcc clk_gcc_mss_snoc_axi_clk>,
+ <&clock_gcc clk_gcc_mss_mnoc_bimc_axi_clk>,
+ <&clock_gcc clk_qdss_clk>;
+ clock-names = "xo", "iface_clk", "pnoc_clk", "bus_clk",
+ "mem_clk", "gpll0_mss_clk", "snoc_axi_clk",
+ "mnoc_axi_clk", "qdss_clk";
+ qcom,proxy-clock-names = "xo", "pnoc_clk", "qdss_clk";
+ qcom,active-clock-names = "iface_clk", "bus_clk", "mem_clk",
+ "gpll0_mss_clk", "snoc_axi_clk",
+ "mnoc_axi_clk";
+
+ interrupts = <0 448 1>;
+ vdd_cx-supply = <&pm8994_s1_corner>;
+ vdd_cx-voltage = <7>;
+ vdd_mx-supply = <&pm8994_s2_corner>;
+ vdd_mx-uV = <6>;
+ vdd_pll-supply = <&pm8994_l12>;
+ qcom,vdd_pll = <1800000>;
+ qcom,firmware-name = "modem";
+ qcom,pil-self-auth;
+ qcom,sysmon-id = <0>;
+ qcom,ssctl-instance-id = <0x12>;
+ qcom,override-acc;
+ qcom,ahb-clk-vote;
+ qcom,pnoc-clk-vote;
+ qcom,qdsp6v56-1-5;
+ qcom,mx-spike-wa;
+ memory-region = <&modem_mem>;
+ qcom,mem-protect-id = <0xF>;
+
+ /* GPIO inputs from mss */
+ qcom,gpio-err-fatal = <&smp2pgpio_ssr_smp2p_1_in 0 0>;
+ qcom,gpio-err-ready = <&smp2pgpio_ssr_smp2p_1_in 1 0>;
+ qcom,gpio-proxy-unvote = <&smp2pgpio_ssr_smp2p_1_in 2 0>;
+ qcom,gpio-stop-ack = <&smp2pgpio_ssr_smp2p_1_in 3 0>;
+ qcom,gpio-shutdown-ack = <&smp2pgpio_ssr_smp2p_1_in 7 0>;
+
+ /* GPIO output to mss */
+ qcom,gpio-force-stop = <&smp2pgpio_ssr_smp2p_1_out 0 0>;
+ status = "ok";
+ };
+
+ pm8994_s1_corner: regulator-s1-corner {
+ compatible = "qcom,stub-regulator";
+ regulator-name = "pm8994_s1_corner";
+ regulator-min-microvolt = <1>;
+ regulator-max-microvolt = <7>;
+ };
+
+ pm8994_s1_floor_corner: regulator-s1-floor-corner {
+ compatible = "qcom,stub-regulator";
+ regulator-name = "pm8994_s1_floor_corner";
+ };
+
+ pm8994_s1_corner_ao: regulator-s1-corner-ao {
+ compatible = "qcom,stub-regulator";
+ regulator-name = "pm8994_s1_corner_ao";
+ };
+
+ pm8994_s2_corner: regulator-s2-corner {
+ compatible = "qcom,stub-regulator";
+ regulator-name = "pm8994_s2_corner";
+ regulator-min-microvolt = <1>;
+ regulator-max-microvolt = <7>;
+ };
+
+ pm8994_s2_corner_ao: regulator-s2-corner-ao {
+ compatible = "qcom,stub-regulator";
+ regulator-name = "pm8994_s2_corner_ao";
+ };
+
+ pm8994_l12: regulator-l12 {
+ compatible = "qcom,stub-regulator";
+ regulator-name = "pm8994_l12";
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ };
+
+ pm8994_l30: regulator-l30 {
+ compatible = "qcom,stub-regulator";
+ regulator-name = "pm8994_l30";
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ qcom,init-voltage = <1800000>;
+ };
+
+ pm8994_l18_pin_ctrl: regulator-l18-pin-ctrl {
+ compatible = "qcom,stub-regulator";
+ regulator-name = "pm8994_l18_pin_ctrl";
+ regulator-min-microvolt = <2700000>;
+ regulator-max-microvolt = <2900000>;
+ qcom,init-voltage = <2700000>;
+ };
+
+ pm8994_l26_corner: regulator-l26-corner {
+ compatible = "qcom,stub-regulator";
+ regulator-name = "pm8994_l26_corner";
+ };
+
+ pm8994_l26_floor_corner: regulator-l26-floor-corner {
+ compatible = "qcom,stub-regulator";
+ regulator-name = "pm8994_l26_floor_corner";
+ };
+
+ pmi8994_boost_pin_ctrl: regulator-bst-pin-ctrl {
+ compatible = "qcom,stub-regulator";
+ regulator-name = "pmi8994_boost_pin_ctrl";
+ };
+
+ pm8994_s11: spm-regulator@3200 {
+ compatible = "qcom,stub-regulator";
+ regulator-name = "pm8994_s11";
+ };
+
+ pmi8994_s2: regulator@1700 {
+ compatible = "qcom,stub-regulator";
+ regulator-name = "pmi8994_s2";
+ };
+
+ pm8994_s3: regulator-s3 {
+ compatible = "qcom,stub-regulator";
+ regulator-name = "pm8994_s3";
+ regulator-min-microvolt = <1300000>;
+ regulator-max-microvolt = <1300000>;
+ qcom,init-voltage = <1300000>;
+ };
+
+ pm8994_s4: regulator-s4 {
+ compatible = "qcom,stub-regulator";
+ regulator-name = "pm8994_s4";
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ qcom,init-voltage = <1800000>;
+ };
+
+ pm8004_s2: regulator@1700 {
+ compatible = "qcom,stub-regulator";
+ regulator-name = "pm8004_s2";
+ };
+
+ spi_eth_vreg: spi_eth_phy_vreg {
+ compatible = "qcom,stub-regulator";
+ regulator-name = "ethernet_phy";
+ };
+
+ usb_otg_switch: usb-otg-switch {
+ compatible = "qcom,stub-regulator";
+ regulator-name = "usb_otg_vreg";
+ };
+
+ rome_vreg: rome_vreg {
+ compatible = "qcom,stub-regulator";
+ regulator-name = "rome_vreg";
+ };
+
+ wlan_en_vreg: wlan_en_vreg {
+ compatible = "qcom,stub-regulator";
+ regulator-name = "wlan_en_vreg";
+ };
+
+ hl7509_en_vreg: hl7509_en_vreg {
+ compatible = "qcom,stub-regulator";
+ regulator-name = "hl7509_en_vreg";
+ };
+
+ gdsc_mmagic_camss: qcom,gdsc@8c3c4c {
+ compatible = "qcom,stub-regulator";
+ regulator-name = "gdsc_mmagic_camss";
+ regulator-min-microvolt = <1>;
+ regulator-max-microvolt = <7>;
+ };
+
+ gdsc_hlos1_vote_lpass_adsp: qcom,gdsc@37d034 {
+ compatible = "qcom,stub-regulator";
+ regulator-name = "gdsc_hlos1_vote_lpass_adsp";
+ regulator-min-microvolt = <1>;
+ regulator-max-microvolt = <7>;
+ };
+
+ spi_9: spi@75B7000 { /* BLSP2 QUP3 */
+ compatible = "qcom,spi-qup-v2";
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg-names = "spi_physical";
+ reg = <0x075B7000 0x600>;
+ interrupt-names = "spi_irq";
+ interrupts = <0 103 0>;
+ spi-max-frequency = <19200000>;
+ qcom,infinite-mode = <0>;
+ qcom,ver-reg-exists;
+ qcom,master-id = <84>;
+ qcom,use-pinctrl;
+ pinctrl-names = "spi_default", "spi_sleep";
+ pinctrl-0 = <&spi_9_active>;
+ pinctrl-1 = <&spi_9_sleep>;
+ clock-names = "iface_clk", "core_clk";
+ clocks = <&clock_gcc clk_gcc_blsp2_ahb_clk>,
+ <&clock_gcc clk_gcc_blsp2_qup3_spi_apps_clk>;
+ };
+
+ i2c_6: i2c@757a000 { /* BLSP1 QUP6 */
+ compatible = "qcom,i2c-msm-v2";
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg = <0x757a000 0x1000>;
+ reg-names = "qup_phys_addr";
+ interrupt-names = "qup_irq";
+ interrupts = <0 100 0>;
+ qcom,disable-dma;
+ qcom,master-id = <86>;
+ qcom,clk-freq-out = <400000>;
+ qcom,clk-freq-in = <19200000>;
+ clock-names = "iface_clk", "core_clk";
+ clocks = <&clock_gcc clk_gcc_blsp1_ahb_clk>,
+ <&clock_gcc clk_gcc_blsp1_qup6_i2c_apps_clk>;
+ pinctrl-names = "i2c_active", "i2c_sleep";
+ pinctrl-0 = <&i2c_6_active>;
+ pinctrl-1 = <&i2c_6_sleep>;
+ };
+
+ i2c_8: i2c@75b6000 { /* BLSP2 QUP2 */
+ compatible = "qcom,i2c-msm-v2";
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg-names = "qup_phys_addr";
+ reg = <0x75b6000 0x1000>;
+ interrupt-names = "qup_irq";
+ interrupts = <0 102 0>;
+ qcom,disable-dma;
+ 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_qup2_i2c_apps_clk>;
+ pinctrl-names = "i2c_active", "i2c_sleep";
+ pinctrl-0 = <&i2c_8_active>;
+ pinctrl-1 = <&i2c_8_sleep>;
+ };
+
+ blsp1_uart2: uart@07570000 { /* BLSP1 UART2 */
+ compatible = "qcom,msm-hsuart-v14";
+ reg = <0x07570000 0x1000>,
+ <0x7544000 0x2b000>;
+ reg-names = "core_mem", "bam_mem";
+ interrupt-names = "core_irq", "bam_irq", "wakeup_irq";
+ interrupts = <0 108 0>, <0 238 0>, <0 810 0>;
+ #address-cells = <0>;
+
+ qcom,inject-rx-on-wakeup;
+ qcom,rx-char-to-inject = <0xFD>;
+
+ qcom,bam-tx-ep-pipe-index = <2>;
+ qcom,bam-rx-ep-pipe-index = <3>;
+ qcom,master-id = <86>;
+ clock-names = "core_clk", "iface_clk";
+ clocks = <&clock_gcc clk_gcc_blsp1_uart2_apps_clk>,
+ <&clock_gcc clk_gcc_blsp1_ahb_clk>;
+ pinctrl-names = "sleep", "default";
+ pinctrl-0 = <&blsp1_uart2_sleep>;
+ pinctrl-1 = <&blsp1_uart2_active>;
+
+ qcom,msm-bus,name = "buart2";
+ qcom,msm-bus,num-cases = <2>;
+ qcom,msm-bus,num-paths = <1>;
+ qcom,msm-bus,vectors-KBps =
+ <86 512 0 0>,
+ <86 512 500 800>;
+ };
+
+ qcom,lpass@9300000 {
+ compatible = "qcom,pil-tz-generic";
+ reg = <0x9300000 0x00100>;
+ interrupts = <0 162 1>;
+
+ vdd_cx-supply = <&pm8994_s1_corner>;
+ qcom,proxy-reg-names = "vdd_cx";
+ qcom,vdd_cx-uV-uA = <7 100000>;
+
+ clocks = <&clock_gcc clk_cxo_pil_lpass_clk>;
+ clock-names = "xo";
+ qcom,proxy-clock-names = "xo";
+
+ qcom,pas-id = <1>;
+ qcom,proxy-timeout-ms = <10000>;
+ qcom,smem-id = <423>;
+ qcom,sysmon-id = <1>;
+ qcom,ssctl-instance-id = <0x14>;
+ qcom,firmware-name = "adsp";
+ qcom,edge = "lpass";
+ memory-region = <&peripheral_mem>;
+
+ /* GPIO inputs from lpass */
+ qcom,gpio-err-fatal = <&smp2pgpio_ssr_smp2p_2_in 0 0>;
+ qcom,gpio-proxy-unvote = <&smp2pgpio_ssr_smp2p_2_in 2 0>;
+ qcom,gpio-err-ready = <&smp2pgpio_ssr_smp2p_2_in 1 0>;
+ qcom,gpio-stop-ack = <&smp2pgpio_ssr_smp2p_2_in 3 0>;
+
+ /* GPIO output to lpass */
+ qcom,gpio-force-stop = <&smp2pgpio_ssr_smp2p_2_out 0 0>;
+ };
+
+ qcom,cnss {
+ compatible = "qcom,cnss";
+ wlan-bootstrap-gpio = <&tlmm 46 0>;
+ vdd-wlan-en-supply = <&wlan_en_vreg>;
+ vdd-wlan-supply = <&rome_vreg>;
+ vdd-wlan-io-supply = <&pm8994_s4>;
+ vdd-wlan-xtal-supply = <&pm8994_l30>;
+ vdd-wlan-core-supply = <&pm8994_s3>;
+ wlan-ant-switch-supply = <&pm8994_l18_pin_ctrl>;
+ qcom,wlan-en-vreg-support;
+ qcom,notify-modem-status;
+ pinctrl-names = "bootstrap_active", "bootstrap_sleep";
+ pinctrl-0 = <&cnss_bootstrap_active>;
+ pinctrl-1 = <&cnss_bootstrap_sleep>;
+
+ qcom,msm-bus,name = "msm-cnss";
+ qcom,msm-bus,num-cases = <4>;
+ qcom,msm-bus,num-paths = <1>;
+ qcom,msm-bus,vectors-KBps =
+ /* No vote */
+ <45 512 0 0>,
+ /* Up to 200 Mbps */
+ <45 512 41421 1520000>,
+ /* Up to 400 Mbps */
+ <45 512 96650 1520000>,
+ /* Up to 800 Mbps */
+ <45 512 207108 14432000>;
+ };
};
+#include "vplatform-lfv-agave.dtsi"
diff --git a/arch/arm/boot/dts/qcom/vplatform-lfv-smmu.dtsi b/arch/arm/boot/dts/qcom/vplatform-lfv-smmu.dtsi
new file mode 100644
index 000000000000..65eaa0c5aef9
--- /dev/null
+++ b/arch/arm/boot/dts/qcom/vplatform-lfv-smmu.dtsi
@@ -0,0 +1,75 @@
+/* Copyright (c) 2015-2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include "msm-arm-smmu.dtsi"
+#include <dt-bindings/msm/msm-bus-ids.h>
+#include <dt-bindings/interrupt-controller/arm-gic.h>
+
+&lpass_q6_smmu {
+ status = "ok";
+ qcom,register-save;
+ qcom,skip-init;
+ #global-interrupts = <1>;
+ interrupts = <GIC_SPI 404 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 226 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 393 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 394 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 395 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 396 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 397 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 398 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 399 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 400 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 401 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 402 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 403 IRQ_TYPE_LEVEL_HIGH>;
+ vdd-supply = <&gdsc_hlos1_vote_lpass_adsp>;
+ clocks = <&clock_gcc clk_hlos1_vote_lpass_adsp_smmu_clk>;
+ clock-names = "lpass_q6_smmu_clocks";
+ #clock-cells = <1>;
+};
+
+&cpp_fd_smmu {
+ status = "ok";
+ qcom,register-save;
+ qcom,skip-init;
+ qcom,fatal-asf;
+ #global-interrupts = <1>;
+ interrupts = <GIC_SPI 264 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 263 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 266 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 267 IRQ_TYPE_LEVEL_HIGH>;
+ vdd-supply = <&gdsc_mmagic_camss>;
+ clocks = <&clock_mmss clk_mmss_mmagic_ahb_clk>,
+ <&clock_mmss clk_mmss_mmagic_cfg_ahb_clk>,
+ <&clock_mmss clk_smmu_cpp_ahb_clk>,
+ <&clock_mmss clk_smmu_cpp_axi_clk>,
+ <&clock_mmss clk_mmagic_camss_axi_clk>;
+ clock-names = "mmagic_ahb_clk", "mmagic_cfg_ahb_clk",
+ "cpp_ahb_clk", "cpp_axi_clk",
+ "mmagic_camss_axi_clk";
+ #clock-cells = <1>;
+ qcom,bus-master-id = <MSM_BUS_MASTER_CPP>;
+};
+
+&soc {
+ iommu_test_device {
+ compatible = "iommu-debug-test";
+ /*
+ * 42 shouldn't be used by anyone on the cpp_fd_smmu. We just
+ * need _something_ here to get this node recognized by the
+ * SMMU driver. Our test uses ATOS, which doesn't use SIDs
+ * anyways, so using a dummy value is ok.
+ */
+ iommus = <&cpp_fd_smmu 42>;
+ };
+};
diff --git a/arch/arm/configs/sdm660-perf_defconfig b/arch/arm/configs/sdm660-perf_defconfig
index 878e720a927b..fbd36cd00ea0 100644
--- a/arch/arm/configs/sdm660-perf_defconfig
+++ b/arch/arm/configs/sdm660-perf_defconfig
@@ -93,6 +93,7 @@ CONFIG_XFRM_USER=y
CONFIG_XFRM_STATISTICS=y
CONFIG_NET_KEY=y
CONFIG_INET=y
+CONFIG_IP_MULTICAST=y
CONFIG_IP_ADVANCED_ROUTER=y
CONFIG_IP_MULTIPLE_TABLES=y
CONFIG_IP_ROUTE_VERBOSE=y
@@ -615,6 +616,9 @@ CONFIG_EXT4_ENCRYPTION=y
CONFIG_EXT4_FS_ENCRYPTION=y
CONFIG_EXT4_FS_ICE_ENCRYPTION=y
CONFIG_EXT4_DEBUG=y
+CONFIG_QUOTA=y
+CONFIG_QUOTA_NETLINK_INTERFACE=y
+CONFIG_QFMT_V2=y
CONFIG_FUSE_FS=y
CONFIG_MSDOS_FS=y
CONFIG_VFAT_FS=y
@@ -655,6 +659,7 @@ CONFIG_CORESIGHT_TPDM=y
CONFIG_CORESIGHT_QPDI=y
CONFIG_CORESIGHT_SOURCE_DUMMY=y
CONFIG_PFK=y
+CONFIG_SECURITY_PERF_EVENTS_RESTRICT=y
CONFIG_SECURITY=y
CONFIG_HARDENED_USERCOPY=y
CONFIG_SECURITY_SELINUX=y
diff --git a/arch/arm/configs/sdm660_defconfig b/arch/arm/configs/sdm660_defconfig
index 524abcf83e77..af5adfeb1a41 100644
--- a/arch/arm/configs/sdm660_defconfig
+++ b/arch/arm/configs/sdm660_defconfig
@@ -91,6 +91,7 @@ CONFIG_XFRM_USER=y
CONFIG_XFRM_STATISTICS=y
CONFIG_NET_KEY=y
CONFIG_INET=y
+CONFIG_IP_MULTICAST=y
CONFIG_IP_ADVANCED_ROUTER=y
CONFIG_IP_MULTIPLE_TABLES=y
CONFIG_IP_ROUTE_VERBOSE=y
@@ -617,6 +618,9 @@ CONFIG_EXT4_FS_SECURITY=y
CONFIG_EXT4_ENCRYPTION=y
CONFIG_EXT4_FS_ENCRYPTION=y
CONFIG_EXT4_FS_ICE_ENCRYPTION=y
+CONFIG_QUOTA=y
+CONFIG_QUOTA_NETLINK_INTERFACE=y
+CONFIG_QFMT_V2=y
CONFIG_FUSE_FS=y
CONFIG_MSDOS_FS=y
CONFIG_VFAT_FS=y
@@ -673,6 +677,7 @@ CONFIG_IRQSOFF_TRACER=y
CONFIG_PREEMPT_TRACER=y
CONFIG_BLK_DEV_IO_TRACE=y
CONFIG_CPU_FREQ_SWITCH_PROFILER=y
+CONFIG_LKDTM=y
CONFIG_MEMTEST=y
CONFIG_PANIC_ON_DATA_CORRUPTION=y
CONFIG_FREE_PAGES_RDONLY=y
@@ -693,6 +698,7 @@ CONFIG_CORESIGHT_TPDM=y
CONFIG_CORESIGHT_QPDI=y
CONFIG_CORESIGHT_SOURCE_DUMMY=y
CONFIG_PFK=y
+CONFIG_SECURITY_PERF_EVENTS_RESTRICT=y
CONFIG_SECURITY=y
CONFIG_HARDENED_USERCOPY=y
CONFIG_SECURITY_SELINUX=y
diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig
index 165c9a745d58..d61f3ae80e15 100644
--- a/arch/arm64/Kconfig
+++ b/arch/arm64/Kconfig
@@ -248,6 +248,15 @@ config PGTABLE_LEVELS
default 3 if ARM64_16K_PAGES && ARM64_VA_BITS_47
default 4 if !ARM64_64K_PAGES && ARM64_VA_BITS_48
+config MSM_GVM_QUIN
+ bool "Enable virtualization Support for MSM kernel required for QUIN platform"
+ help
+ This enables support for MSM Kernel based virtual
+ machine for QUIN platform.
+ This helps to enable virtual driver support.
+ This should work on 64bit machine.
+ If you don't know what to do here, say N.
+
source "init/Kconfig"
source "kernel/Kconfig.freezer"
diff --git a/arch/arm64/configs/msm-auto-gvm-perf_defconfig b/arch/arm64/configs/msm-auto-gvm-perf_defconfig
new file mode 100644
index 000000000000..2e551218af2d
--- /dev/null
+++ b/arch/arm64/configs/msm-auto-gvm-perf_defconfig
@@ -0,0 +1,286 @@
+CONFIG_LOCALVERSION="-perf"
+# CONFIG_LOCALVERSION_AUTO is not set
+CONFIG_SYSVIPC=y
+CONFIG_AUDIT=y
+CONFIG_NO_HZ=y
+CONFIG_HIGH_RES_TIMERS=y
+CONFIG_IRQ_TIME_ACCOUNTING=y
+CONFIG_IKCONFIG=y
+CONFIG_IKCONFIG_PROC=y
+CONFIG_LOG_CPU_MAX_BUF_SHIFT=15
+CONFIG_CGROUPS=y
+CONFIG_CGROUP_FREEZER=y
+CONFIG_CGROUP_CPUACCT=y
+CONFIG_CGROUP_SCHED=y
+CONFIG_RT_GROUP_SCHED=y
+CONFIG_SCHED_HMP=y
+CONFIG_NAMESPACES=y
+CONFIG_BLK_DEV_INITRD=y
+CONFIG_CC_OPTIMIZE_FOR_SIZE=y
+CONFIG_KALLSYMS_ALL=y
+CONFIG_EMBEDDED=y
+CONFIG_PROFILING=y
+CONFIG_CC_STACKPROTECTOR_REGULAR=y
+CONFIG_MODULES=y
+CONFIG_MODULE_UNLOAD=y
+CONFIG_MODULE_FORCE_UNLOAD=y
+CONFIG_MODVERSIONS=y
+CONFIG_MODULE_SIG=y
+CONFIG_MODULE_SIG_FORCE=y
+CONFIG_MODULE_SIG_SHA512=y
+CONFIG_PARTITION_ADVANCED=y
+CONFIG_ARCH_QCOM=y
+CONFIG_PCI=y
+CONFIG_PCI_HOST_GENERIC=y
+CONFIG_SCHED_MC=y
+CONFIG_NR_CPUS=8
+CONFIG_PREEMPT=y
+CONFIG_ARM64_REG_REBALANCE_ON_CTX_SW=y
+CONFIG_ZSMALLOC=y
+CONFIG_BALANCE_ANON_FILE_RECLAIM=y
+CONFIG_FORCE_ALLOC_FROM_DMA_ZONE=y
+CONFIG_SECCOMP=y
+CONFIG_ARMV8_DEPRECATED=y
+CONFIG_SWP_EMULATION=y
+CONFIG_BUILD_ARM64_APPENDED_DTB_IMAGE=y
+CONFIG_COMPAT=y
+CONFIG_NET=y
+CONFIG_PACKET=y
+CONFIG_UNIX=y
+CONFIG_XFRM_USER=y
+CONFIG_XFRM_STATISTICS=y
+CONFIG_NET_KEY=y
+CONFIG_INET=y
+CONFIG_IP_ADVANCED_ROUTER=y
+CONFIG_IP_MULTIPLE_TABLES=y
+CONFIG_IP_ROUTE_VERBOSE=y
+CONFIG_IP_PNP=y
+CONFIG_IP_PNP_DHCP=y
+CONFIG_INET_AH=y
+CONFIG_INET_ESP=y
+CONFIG_INET_IPCOMP=y
+CONFIG_IPV6_ROUTER_PREF=y
+CONFIG_IPV6_ROUTE_INFO=y
+CONFIG_IPV6_OPTIMISTIC_DAD=y
+CONFIG_INET6_AH=y
+CONFIG_INET6_ESP=y
+CONFIG_INET6_IPCOMP=y
+CONFIG_IPV6_MIP6=y
+CONFIG_IPV6_MULTIPLE_TABLES=y
+CONFIG_IPV6_SUBTREES=y
+CONFIG_NETFILTER=y
+CONFIG_NF_CONNTRACK=y
+CONFIG_NF_CONNTRACK_EVENTS=y
+CONFIG_NF_CT_PROTO_DCCP=y
+CONFIG_NF_CT_PROTO_SCTP=y
+CONFIG_NF_CT_PROTO_UDPLITE=y
+CONFIG_NF_CONNTRACK_AMANDA=y
+CONFIG_NF_CONNTRACK_FTP=y
+CONFIG_NF_CONNTRACK_H323=y
+CONFIG_NF_CONNTRACK_IRC=y
+CONFIG_NF_CONNTRACK_NETBIOS_NS=y
+CONFIG_NF_CONNTRACK_PPTP=y
+CONFIG_NF_CONNTRACK_SANE=y
+CONFIG_NF_CONNTRACK_TFTP=y
+CONFIG_NF_CT_NETLINK=y
+CONFIG_NETFILTER_XT_TARGET_CLASSIFY=y
+CONFIG_NETFILTER_XT_TARGET_CONNMARK=y
+CONFIG_NETFILTER_XT_TARGET_LOG=y
+CONFIG_NETFILTER_XT_TARGET_MARK=y
+CONFIG_NETFILTER_XT_TARGET_NFLOG=y
+CONFIG_NETFILTER_XT_TARGET_NFQUEUE=y
+CONFIG_NETFILTER_XT_TARGET_NOTRACK=y
+CONFIG_NETFILTER_XT_TARGET_TPROXY=y
+CONFIG_NETFILTER_XT_TARGET_TRACE=y
+CONFIG_NETFILTER_XT_MATCH_COMMENT=y
+CONFIG_NETFILTER_XT_MATCH_CONNLIMIT=y
+CONFIG_NETFILTER_XT_MATCH_CONNMARK=y
+CONFIG_NETFILTER_XT_MATCH_CONNTRACK=y
+CONFIG_NETFILTER_XT_MATCH_DSCP=y
+CONFIG_NETFILTER_XT_MATCH_HASHLIMIT=y
+CONFIG_NETFILTER_XT_MATCH_HELPER=y
+CONFIG_NETFILTER_XT_MATCH_IPRANGE=y
+CONFIG_NETFILTER_XT_MATCH_LENGTH=y
+CONFIG_NETFILTER_XT_MATCH_LIMIT=y
+CONFIG_NETFILTER_XT_MATCH_MAC=y
+CONFIG_NETFILTER_XT_MATCH_MARK=y
+CONFIG_NETFILTER_XT_MATCH_MULTIPORT=y
+CONFIG_NETFILTER_XT_MATCH_POLICY=y
+CONFIG_NETFILTER_XT_MATCH_PKTTYPE=y
+CONFIG_NETFILTER_XT_MATCH_QTAGUID=y
+CONFIG_NETFILTER_XT_MATCH_QUOTA=y
+CONFIG_NETFILTER_XT_MATCH_QUOTA2=y
+CONFIG_NETFILTER_XT_MATCH_SOCKET=y
+CONFIG_NETFILTER_XT_MATCH_STATE=y
+CONFIG_NETFILTER_XT_MATCH_STATISTIC=y
+CONFIG_NETFILTER_XT_MATCH_STRING=y
+CONFIG_NETFILTER_XT_MATCH_TIME=y
+CONFIG_NETFILTER_XT_MATCH_U32=y
+CONFIG_NF_CONNTRACK_IPV4=y
+CONFIG_IP_NF_IPTABLES=y
+CONFIG_IP_NF_MATCH_AH=y
+CONFIG_IP_NF_MATCH_ECN=y
+CONFIG_IP_NF_MATCH_TTL=y
+CONFIG_IP_NF_FILTER=y
+CONFIG_IP_NF_TARGET_REJECT=y
+CONFIG_IP_NF_NAT=y
+CONFIG_IP_NF_TARGET_MASQUERADE=y
+CONFIG_IP_NF_TARGET_NETMAP=y
+CONFIG_IP_NF_TARGET_REDIRECT=y
+CONFIG_IP_NF_MANGLE=y
+CONFIG_IP_NF_RAW=y
+CONFIG_IP_NF_SECURITY=y
+CONFIG_IP_NF_ARPTABLES=y
+CONFIG_IP_NF_ARPFILTER=y
+CONFIG_IP_NF_ARP_MANGLE=y
+CONFIG_NF_CONNTRACK_IPV6=y
+CONFIG_IP6_NF_IPTABLES=y
+CONFIG_IP6_NF_FILTER=y
+CONFIG_IP6_NF_TARGET_REJECT=y
+CONFIG_IP6_NF_MANGLE=y
+CONFIG_IP6_NF_RAW=y
+CONFIG_BRIDGE_NF_EBTABLES=y
+CONFIG_BRIDGE_EBT_BROUTE=y
+CONFIG_BRIDGE=y
+CONFIG_NET_SCHED=y
+CONFIG_NET_SCH_HTB=y
+CONFIG_NET_SCH_PRIO=y
+CONFIG_NET_CLS_FW=y
+CONFIG_NET_CLS_U32=y
+CONFIG_CLS_U32_MARK=y
+CONFIG_NET_CLS_FLOW=y
+CONFIG_NET_EMATCH=y
+CONFIG_NET_EMATCH_CMP=y
+CONFIG_NET_EMATCH_NBYTE=y
+CONFIG_NET_EMATCH_U32=y
+CONFIG_NET_EMATCH_META=y
+CONFIG_NET_EMATCH_TEXT=y
+CONFIG_NET_CLS_ACT=y
+CONFIG_RMNET_DATA=y
+CONFIG_RMNET_DATA_FC=y
+CONFIG_RMNET_DATA_DEBUG_PKT=y
+CONFIG_CAN=y
+CONFIG_CAN_RH850=y
+CONFIG_IPC_ROUTER=y
+CONFIG_IPC_ROUTER_SECURITY=y
+CONFIG_DEVTMPFS=y
+CONFIG_DEVTMPFS_MOUNT=y
+CONFIG_ZRAM=y
+CONFIG_BLK_DEV_LOOP=y
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_SIZE=8192
+CONFIG_VIRTIO_BLK=y
+CONFIG_SRAM=y
+CONFIG_MD=y
+CONFIG_BLK_DEV_DM=y
+CONFIG_DM_UEVENT=y
+CONFIG_DM_VERITY=y
+CONFIG_DM_VERITY_FEC=y
+CONFIG_NETDEVICES=y
+CONFIG_DUMMY=y
+CONFIG_TUN=y
+CONFIG_VIRTIO_NET=y
+CONFIG_PPP=y
+CONFIG_PPP_BSDCOMP=y
+CONFIG_PPP_DEFLATE=y
+CONFIG_PPPOE=y
+CONFIG_PPP_ASYNC=y
+CONFIG_PPP_SYNC_TTY=y
+CONFIG_INPUT_EVDEV=y
+CONFIG_INPUT_EVBUG=m
+CONFIG_INPUT_JOYSTICK=y
+CONFIG_INPUT_TOUCHSCREEN=y
+CONFIG_INPUT_MISC=y
+CONFIG_INPUT_UINPUT=y
+CONFIG_INPUT_GPIO=m
+CONFIG_SERIO_AMBAKMI=y
+CONFIG_SERIAL_MSM_HS=y
+CONFIG_I2C_CHARDEV=y
+CONFIG_I2C_MSM_V2=y
+CONFIG_SPI=y
+CONFIG_SPI_QUP=y
+CONFIG_SPI_SPIDEV=y
+CONFIG_PINCTRL_MSM8996=y
+CONFIG_GPIOLIB=y
+CONFIG_GPIO_SYSFS=y
+CONFIG_POWER_RESET_QCOM=y
+CONFIG_WATCHDOG=y
+CONFIG_REGULATOR=y
+CONFIG_REGULATOR_STUB=y
+CONFIG_MEDIA_SUPPORT=y
+CONFIG_MEDIA_CAMERA_SUPPORT=y
+CONFIG_MEDIA_CONTROLLER=y
+CONFIG_VIDEO_V4L2_SUBDEV_API=y
+CONFIG_V4L_PLATFORM_DRIVERS=y
+CONFIG_DRM=y
+# CONFIG_DRM_MSM is not set
+CONFIG_SOUND=y
+CONFIG_SND=y
+CONFIG_SND_SOC=y
+CONFIG_HIDRAW=y
+CONFIG_UHID=y
+CONFIG_HID_APPLE=y
+CONFIG_HID_ELECOM=y
+CONFIG_HID_MAGICMOUSE=y
+CONFIG_HID_MICROSOFT=y
+CONFIG_UIO=y
+CONFIG_UIO_MSM_SHAREDMEM=y
+CONFIG_VIRTIO_INPUT=y
+CONFIG_VIRTIO_MMIO=y
+CONFIG_STAGING=y
+CONFIG_ASHMEM=y
+CONFIG_ANDROID_LOW_MEMORY_KILLER=y
+CONFIG_SYNC=y
+CONFIG_SW_SYNC=y
+CONFIG_SW_SYNC_USER=y
+CONFIG_SPS=y
+CONFIG_SPS_SUPPORT_NDP_BAM=y
+CONFIG_IPA=y
+CONFIG_RMNET_IPA=y
+CONFIG_COMMON_CLK_MSM=y
+CONFIG_MSM_CLK_CONTROLLER_V2=y
+CONFIG_REMOTE_SPINLOCK_MSM=y
+CONFIG_IOMMU_IO_PGTABLE_FAST=y
+CONFIG_ARM_SMMU=y
+CONFIG_IOMMU_DEBUG=y
+CONFIG_IOMMU_TESTS=y
+CONFIG_MSM_SMEM=y
+CONFIG_MSM_SMD=y
+CONFIG_MSM_GLINK=y
+CONFIG_MSM_GLINK_LOOPBACK_SERVER=y
+CONFIG_MSM_GLINK_SMD_XPRT=y
+CONFIG_MSM_GLINK_SMEM_NATIVE_XPRT=y
+CONFIG_MSM_SMEM_LOGGING=y
+CONFIG_MSM_SMP2P=y
+CONFIG_MSM_SMP2P_TEST=y
+CONFIG_MSM_QMI_INTERFACE=y
+CONFIG_MSM_IPC_ROUTER_SMD_XPRT=y
+CONFIG_MSM_IPC_ROUTER_GLINK_XPRT=y
+CONFIG_MSM_SUBSYSTEM_RESTART=y
+CONFIG_MSM_PIL=y
+CONFIG_MSM_PIL_MSS_QDSP6V5=y
+CONFIG_ANDROID=y
+CONFIG_ANDROID_BINDER_IPC=y
+CONFIG_EXT2_FS=y
+CONFIG_EXT2_FS_XATTR=y
+CONFIG_EXT3_FS=y
+CONFIG_EXT4_FS_SECURITY=y
+CONFIG_FUSE_FS=y
+CONFIG_VFAT_FS=y
+CONFIG_TMPFS=y
+CONFIG_NLS_CODEPAGE_437=y
+CONFIG_NLS_ASCII=y
+CONFIG_NLS_ISO8859_1=y
+CONFIG_PRINTK_TIME=y
+CONFIG_DEBUG_INFO=y
+CONFIG_MAGIC_SYSRQ=y
+CONFIG_PANIC_TIMEOUT=5
+CONFIG_SCHEDSTATS=y
+CONFIG_IPC_LOGGING=y
+CONFIG_SECURITY=y
+CONFIG_SECURITY_NETWORK=y
+CONFIG_CRYPTO_XCBC=y
+CONFIG_CRYPTO_MD4=y
+CONFIG_CRYPTO_ARC4=y
+CONFIG_CRYPTO_TWOFISH=y
+CONFIG_QMI_ENCDEC=y
diff --git a/arch/arm64/configs/msm-auto-gvm_defconfig b/arch/arm64/configs/msm-auto-gvm_defconfig
new file mode 100644
index 000000000000..a6d36c314a4a
--- /dev/null
+++ b/arch/arm64/configs/msm-auto-gvm_defconfig
@@ -0,0 +1,316 @@
+CONFIG_SYSVIPC=y
+CONFIG_AUDIT=y
+CONFIG_NO_HZ=y
+CONFIG_HIGH_RES_TIMERS=y
+CONFIG_IRQ_TIME_ACCOUNTING=y
+CONFIG_IKCONFIG=y
+CONFIG_IKCONFIG_PROC=y
+CONFIG_LOG_CPU_MAX_BUF_SHIFT=15
+CONFIG_CGROUPS=y
+CONFIG_CGROUP_FREEZER=y
+CONFIG_CGROUP_CPUACCT=y
+CONFIG_CGROUP_SCHED=y
+CONFIG_RT_GROUP_SCHED=y
+CONFIG_SCHED_HMP=y
+CONFIG_NAMESPACES=y
+CONFIG_BLK_DEV_INITRD=y
+CONFIG_CC_OPTIMIZE_FOR_SIZE=y
+CONFIG_KALLSYMS_ALL=y
+CONFIG_EMBEDDED=y
+CONFIG_PROFILING=y
+CONFIG_CC_STACKPROTECTOR_REGULAR=y
+CONFIG_MODULES=y
+CONFIG_MODULE_UNLOAD=y
+CONFIG_MODULE_FORCE_UNLOAD=y
+CONFIG_MODVERSIONS=y
+CONFIG_MODULE_SIG=y
+CONFIG_MODULE_SIG_FORCE=y
+CONFIG_MODULE_SIG_SHA512=y
+CONFIG_PARTITION_ADVANCED=y
+CONFIG_ARCH_QCOM=y
+CONFIG_PCI=y
+CONFIG_PCI_HOST_GENERIC=y
+CONFIG_SCHED_MC=y
+CONFIG_NR_CPUS=8
+CONFIG_PREEMPT=y
+CONFIG_ARM64_REG_REBALANCE_ON_CTX_SW=y
+CONFIG_ZSMALLOC=y
+CONFIG_BALANCE_ANON_FILE_RECLAIM=y
+CONFIG_FORCE_ALLOC_FROM_DMA_ZONE=y
+CONFIG_SECCOMP=y
+CONFIG_ARMV8_DEPRECATED=y
+CONFIG_SWP_EMULATION=y
+CONFIG_BUILD_ARM64_APPENDED_DTB_IMAGE=y
+CONFIG_COMPAT=y
+CONFIG_NET=y
+CONFIG_PACKET=y
+CONFIG_UNIX=y
+CONFIG_XFRM_USER=y
+CONFIG_XFRM_STATISTICS=y
+CONFIG_NET_KEY=y
+CONFIG_INET=y
+CONFIG_IP_ADVANCED_ROUTER=y
+CONFIG_IP_MULTIPLE_TABLES=y
+CONFIG_IP_ROUTE_VERBOSE=y
+CONFIG_IP_PNP=y
+CONFIG_IP_PNP_DHCP=y
+CONFIG_INET_AH=y
+CONFIG_INET_ESP=y
+CONFIG_INET_IPCOMP=y
+CONFIG_IPV6_ROUTER_PREF=y
+CONFIG_IPV6_ROUTE_INFO=y
+CONFIG_IPV6_OPTIMISTIC_DAD=y
+CONFIG_INET6_AH=y
+CONFIG_INET6_ESP=y
+CONFIG_INET6_IPCOMP=y
+CONFIG_IPV6_MIP6=y
+CONFIG_IPV6_MULTIPLE_TABLES=y
+CONFIG_IPV6_SUBTREES=y
+CONFIG_NETFILTER=y
+CONFIG_NF_CONNTRACK=y
+CONFIG_NF_CONNTRACK_EVENTS=y
+CONFIG_NF_CT_PROTO_DCCP=y
+CONFIG_NF_CT_PROTO_SCTP=y
+CONFIG_NF_CT_PROTO_UDPLITE=y
+CONFIG_NF_CONNTRACK_AMANDA=y
+CONFIG_NF_CONNTRACK_FTP=y
+CONFIG_NF_CONNTRACK_H323=y
+CONFIG_NF_CONNTRACK_IRC=y
+CONFIG_NF_CONNTRACK_NETBIOS_NS=y
+CONFIG_NF_CONNTRACK_PPTP=y
+CONFIG_NF_CONNTRACK_SANE=y
+CONFIG_NF_CONNTRACK_TFTP=y
+CONFIG_NF_CT_NETLINK=y
+CONFIG_NETFILTER_XT_TARGET_CLASSIFY=y
+CONFIG_NETFILTER_XT_TARGET_CONNMARK=y
+CONFIG_NETFILTER_XT_TARGET_LOG=y
+CONFIG_NETFILTER_XT_TARGET_MARK=y
+CONFIG_NETFILTER_XT_TARGET_NFLOG=y
+CONFIG_NETFILTER_XT_TARGET_NFQUEUE=y
+CONFIG_NETFILTER_XT_TARGET_NOTRACK=y
+CONFIG_NETFILTER_XT_TARGET_TPROXY=y
+CONFIG_NETFILTER_XT_TARGET_TRACE=y
+CONFIG_NETFILTER_XT_MATCH_COMMENT=y
+CONFIG_NETFILTER_XT_MATCH_CONNLIMIT=y
+CONFIG_NETFILTER_XT_MATCH_CONNMARK=y
+CONFIG_NETFILTER_XT_MATCH_CONNTRACK=y
+CONFIG_NETFILTER_XT_MATCH_DSCP=y
+CONFIG_NETFILTER_XT_MATCH_HASHLIMIT=y
+CONFIG_NETFILTER_XT_MATCH_HELPER=y
+CONFIG_NETFILTER_XT_MATCH_IPRANGE=y
+CONFIG_NETFILTER_XT_MATCH_LENGTH=y
+CONFIG_NETFILTER_XT_MATCH_LIMIT=y
+CONFIG_NETFILTER_XT_MATCH_MAC=y
+CONFIG_NETFILTER_XT_MATCH_MARK=y
+CONFIG_NETFILTER_XT_MATCH_MULTIPORT=y
+CONFIG_NETFILTER_XT_MATCH_POLICY=y
+CONFIG_NETFILTER_XT_MATCH_PKTTYPE=y
+CONFIG_NETFILTER_XT_MATCH_QTAGUID=y
+CONFIG_NETFILTER_XT_MATCH_QUOTA=y
+CONFIG_NETFILTER_XT_MATCH_QUOTA2=y
+CONFIG_NETFILTER_XT_MATCH_SOCKET=y
+CONFIG_NETFILTER_XT_MATCH_STATE=y
+CONFIG_NETFILTER_XT_MATCH_STATISTIC=y
+CONFIG_NETFILTER_XT_MATCH_STRING=y
+CONFIG_NETFILTER_XT_MATCH_TIME=y
+CONFIG_NETFILTER_XT_MATCH_U32=y
+CONFIG_NF_CONNTRACK_IPV4=y
+CONFIG_IP_NF_IPTABLES=y
+CONFIG_IP_NF_MATCH_AH=y
+CONFIG_IP_NF_MATCH_ECN=y
+CONFIG_IP_NF_MATCH_TTL=y
+CONFIG_IP_NF_FILTER=y
+CONFIG_IP_NF_TARGET_REJECT=y
+CONFIG_IP_NF_NAT=y
+CONFIG_IP_NF_TARGET_MASQUERADE=y
+CONFIG_IP_NF_TARGET_NETMAP=y
+CONFIG_IP_NF_TARGET_REDIRECT=y
+CONFIG_IP_NF_MANGLE=y
+CONFIG_IP_NF_RAW=y
+CONFIG_IP_NF_SECURITY=y
+CONFIG_IP_NF_ARPTABLES=y
+CONFIG_IP_NF_ARPFILTER=y
+CONFIG_IP_NF_ARP_MANGLE=y
+CONFIG_NF_CONNTRACK_IPV6=y
+CONFIG_IP6_NF_IPTABLES=y
+CONFIG_IP6_NF_FILTER=y
+CONFIG_IP6_NF_TARGET_REJECT=y
+CONFIG_IP6_NF_MANGLE=y
+CONFIG_IP6_NF_RAW=y
+CONFIG_BRIDGE_NF_EBTABLES=y
+CONFIG_BRIDGE_EBT_BROUTE=y
+CONFIG_BRIDGE=y
+CONFIG_NET_SCHED=y
+CONFIG_NET_SCH_HTB=y
+CONFIG_NET_SCH_PRIO=y
+CONFIG_NET_CLS_FW=y
+CONFIG_NET_CLS_U32=y
+CONFIG_CLS_U32_MARK=y
+CONFIG_NET_CLS_FLOW=y
+CONFIG_NET_EMATCH=y
+CONFIG_NET_EMATCH_CMP=y
+CONFIG_NET_EMATCH_NBYTE=y
+CONFIG_NET_EMATCH_U32=y
+CONFIG_NET_EMATCH_META=y
+CONFIG_NET_EMATCH_TEXT=y
+CONFIG_NET_CLS_ACT=y
+CONFIG_RMNET_DATA=y
+CONFIG_RMNET_DATA_FC=y
+CONFIG_RMNET_DATA_DEBUG_PKT=y
+CONFIG_CAN=y
+CONFIG_CAN_RH850=y
+CONFIG_IPC_ROUTER=y
+CONFIG_IPC_ROUTER_SECURITY=y
+CONFIG_DEVTMPFS=y
+CONFIG_DEVTMPFS_MOUNT=y
+CONFIG_ZRAM=y
+CONFIG_BLK_DEV_LOOP=y
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_SIZE=8192
+CONFIG_VIRTIO_BLK=y
+CONFIG_SRAM=y
+CONFIG_MD=y
+CONFIG_BLK_DEV_DM=y
+CONFIG_DM_UEVENT=y
+CONFIG_DM_VERITY=y
+CONFIG_DM_VERITY_FEC=y
+CONFIG_NETDEVICES=y
+CONFIG_DUMMY=y
+CONFIG_TUN=y
+CONFIG_VIRTIO_NET=y
+CONFIG_PPP=y
+CONFIG_PPP_BSDCOMP=y
+CONFIG_PPP_DEFLATE=y
+CONFIG_PPPOE=y
+CONFIG_PPP_ASYNC=y
+CONFIG_PPP_SYNC_TTY=y
+CONFIG_INPUT_EVDEV=y
+CONFIG_INPUT_EVBUG=m
+CONFIG_INPUT_JOYSTICK=y
+CONFIG_INPUT_TOUCHSCREEN=y
+CONFIG_INPUT_MISC=y
+CONFIG_INPUT_UINPUT=y
+CONFIG_INPUT_GPIO=m
+CONFIG_SERIO_AMBAKMI=y
+CONFIG_VT_HW_CONSOLE_BINDING=y
+CONFIG_SERIAL_AMBA_PL011=y
+CONFIG_SERIAL_AMBA_PL011_CONSOLE=y
+CONFIG_SERIAL_MSM_HS=y
+CONFIG_I2C_CHARDEV=y
+CONFIG_I2C_MSM_V2=y
+CONFIG_SPI=y
+CONFIG_SPI_DEBUG=y
+CONFIG_SPI_QUP=y
+CONFIG_SPI_SPIDEV=y
+CONFIG_PINCTRL_MSM8996=y
+CONFIG_GPIOLIB=y
+CONFIG_GPIO_SYSFS=y
+CONFIG_POWER_RESET_QCOM=y
+CONFIG_WATCHDOG=y
+CONFIG_REGULATOR=y
+CONFIG_REGULATOR_STUB=y
+CONFIG_MEDIA_SUPPORT=y
+CONFIG_MEDIA_CAMERA_SUPPORT=y
+CONFIG_MEDIA_CONTROLLER=y
+CONFIG_VIDEO_V4L2_SUBDEV_API=y
+CONFIG_V4L_PLATFORM_DRIVERS=y
+CONFIG_DRM=y
+# CONFIG_DRM_MSM is not set
+CONFIG_SOUND=y
+CONFIG_SND=y
+CONFIG_SND_SOC=y
+CONFIG_HIDRAW=y
+CONFIG_UHID=y
+CONFIG_HID_APPLE=y
+CONFIG_HID_ELECOM=y
+CONFIG_HID_MAGICMOUSE=y
+CONFIG_HID_MICROSOFT=y
+CONFIG_UIO=y
+CONFIG_UIO_MSM_SHAREDMEM=y
+CONFIG_VIRTIO_INPUT=y
+CONFIG_VIRTIO_MMIO=y
+CONFIG_STAGING=y
+CONFIG_ASHMEM=y
+CONFIG_ANDROID_LOW_MEMORY_KILLER=y
+CONFIG_SYNC=y
+CONFIG_SW_SYNC=y
+CONFIG_SW_SYNC_USER=y
+CONFIG_SPS=y
+CONFIG_SPS_SUPPORT_NDP_BAM=y
+CONFIG_IPA=y
+CONFIG_RMNET_IPA=y
+CONFIG_COMMON_CLK_MSM=y
+CONFIG_MSM_CLK_CONTROLLER_V2=y
+CONFIG_REMOTE_SPINLOCK_MSM=y
+CONFIG_IOMMU_IO_PGTABLE_FAST=y
+CONFIG_IOMMU_IO_PGTABLE_FAST_SELFTEST=y
+CONFIG_ARM_SMMU=y
+CONFIG_IOMMU_DEBUG=y
+CONFIG_IOMMU_DEBUG_TRACKING=y
+CONFIG_IOMMU_TESTS=y
+CONFIG_MSM_SMEM=y
+CONFIG_MSM_SMD=y
+CONFIG_MSM_SMD_DEBUG=y
+CONFIG_MSM_GLINK=y
+CONFIG_MSM_GLINK_LOOPBACK_SERVER=y
+CONFIG_MSM_GLINK_SMD_XPRT=y
+CONFIG_MSM_GLINK_SMEM_NATIVE_XPRT=y
+CONFIG_MSM_SMEM_LOGGING=y
+CONFIG_MSM_SMP2P=y
+CONFIG_MSM_SMP2P_TEST=y
+CONFIG_MSM_QMI_INTERFACE=y
+CONFIG_MSM_IPC_ROUTER_SMD_XPRT=y
+CONFIG_MSM_IPC_ROUTER_GLINK_XPRT=y
+CONFIG_MSM_SUBSYSTEM_RESTART=y
+CONFIG_MSM_PIL=y
+CONFIG_MSM_PIL_MSS_QDSP6V5=y
+CONFIG_ANDROID=y
+CONFIG_ANDROID_BINDER_IPC=y
+CONFIG_EXT2_FS=y
+CONFIG_EXT2_FS_XATTR=y
+CONFIG_EXT3_FS=y
+CONFIG_EXT4_FS_SECURITY=y
+CONFIG_FUSE_FS=y
+CONFIG_VFAT_FS=y
+CONFIG_TMPFS=y
+CONFIG_NLS_CODEPAGE_437=y
+CONFIG_NLS_ASCII=y
+CONFIG_NLS_ISO8859_1=y
+CONFIG_PRINTK_TIME=y
+CONFIG_DYNAMIC_DEBUG=y
+CONFIG_DEBUG_INFO=y
+CONFIG_PAGE_OWNER=y
+CONFIG_MAGIC_SYSRQ=y
+CONFIG_DEBUG_OBJECTS=y
+CONFIG_DEBUG_OBJECTS_FREE=y
+CONFIG_DEBUG_OBJECTS_TIMERS=y
+CONFIG_DEBUG_OBJECTS_WORK=y
+CONFIG_DEBUG_OBJECTS_RCU_HEAD=y
+CONFIG_DEBUG_OBJECTS_PERCPU_COUNTER=y
+CONFIG_DEBUG_KMEMLEAK=y
+CONFIG_DEBUG_KMEMLEAK_DEFAULT_OFF=y
+CONFIG_DEBUG_STACK_USAGE=y
+CONFIG_DEBUG_MEMORY_INIT=y
+CONFIG_LOCKUP_DETECTOR=y
+CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC=y
+CONFIG_PANIC_TIMEOUT=5
+CONFIG_PANIC_ON_SCHED_BUG=y
+CONFIG_SCHEDSTATS=y
+CONFIG_DEBUG_ATOMIC_SLEEP=y
+CONFIG_DEBUG_LIST=y
+CONFIG_FAULT_INJECTION=y
+CONFIG_FAIL_PAGE_ALLOC=y
+CONFIG_FAULT_INJECTION_DEBUG_FS=y
+CONFIG_FAULT_INJECTION_STACKTRACE_FILTER=y
+CONFIG_IPC_LOGGING=y
+CONFIG_BLK_DEV_IO_TRACE=y
+CONFIG_PANIC_ON_DATA_CORRUPTION=y
+CONFIG_ARM64_PTDUMP=y
+CONFIG_FREE_PAGES_RDONLY=y
+CONFIG_SECURITY=y
+CONFIG_SECURITY_NETWORK=y
+CONFIG_CRYPTO_XCBC=y
+CONFIG_CRYPTO_MD4=y
+CONFIG_CRYPTO_ARC4=y
+CONFIG_CRYPTO_TWOFISH=y
+CONFIG_QMI_ENCDEC=y
diff --git a/arch/arm64/configs/msm-auto-perf_defconfig b/arch/arm64/configs/msm-auto-perf_defconfig
index efdfb4da2de2..28d10091da43 100644
--- a/arch/arm64/configs/msm-auto-perf_defconfig
+++ b/arch/arm64/configs/msm-auto-perf_defconfig
@@ -261,6 +261,7 @@ CONFIG_NETDEVICES=y
CONFIG_BONDING=y
CONFIG_DUMMY=y
CONFIG_TUN=y
+CONFIG_ATL1C=y
CONFIG_E1000E=y
CONFIG_MSM_RMNET_MHI=y
CONFIG_RNDIS_IPA=y
@@ -299,8 +300,6 @@ CONFIG_INPUT_GPIO=y
# CONFIG_SERIO_SERPORT is not set
# CONFIG_VT is not set
# CONFIG_LEGACY_PTYS is not set
-# CONFIG_DEVMEM is not set
-# CONFIG_DEVKMEM is not set
CONFIG_SERIAL_MSM_HS=y
CONFIG_SERIAL_MSM_SMD=y
CONFIG_DIAG_CHAR=y
@@ -319,6 +318,7 @@ CONFIG_SPI=y
CONFIG_SPI_QUP=y
CONFIG_SPI_SPIDEV=y
CONFIG_SPMI=y
+CONFIG_PPS_CLIENT_GPIO=y
CONFIG_PINCTRL_MSM8996=y
CONFIG_GPIOLIB=y
CONFIG_GPIO_SYSFS=y
diff --git a/arch/arm64/configs/msm-auto_defconfig b/arch/arm64/configs/msm-auto_defconfig
index e9ef95772ebd..1783707399ca 100644
--- a/arch/arm64/configs/msm-auto_defconfig
+++ b/arch/arm64/configs/msm-auto_defconfig
@@ -262,6 +262,7 @@ CONFIG_NETDEVICES=y
CONFIG_BONDING=y
CONFIG_DUMMY=y
CONFIG_TUN=y
+CONFIG_ATL1C=y
CONFIG_E1000E=y
CONFIG_MSM_RMNET_MHI=y
CONFIG_RNDIS_IPA=y
@@ -300,8 +301,6 @@ CONFIG_INPUT_GPIO=y
# CONFIG_SERIO_SERPORT is not set
# CONFIG_VT is not set
# CONFIG_LEGACY_PTYS is not set
-# CONFIG_DEVMEM is not set
-# CONFIG_DEVKMEM is not set
CONFIG_SERIAL_MSM=y
CONFIG_SERIAL_MSM_CONSOLE=y
CONFIG_SERIAL_MSM_HS=y
@@ -322,6 +321,7 @@ CONFIG_SPI=y
CONFIG_SPI_QUP=y
CONFIG_SPI_SPIDEV=y
CONFIG_SPMI=y
+CONFIG_PPS_CLIENT_GPIO=y
CONFIG_PINCTRL_MSM8996=y
CONFIG_GPIOLIB=y
CONFIG_GPIO_SYSFS=y
diff --git a/arch/arm64/configs/msmcortex_defconfig b/arch/arm64/configs/msmcortex_defconfig
index 77157bb85ee1..3cbcc10ceb1d 100644
--- a/arch/arm64/configs/msmcortex_defconfig
+++ b/arch/arm64/configs/msmcortex_defconfig
@@ -698,6 +698,7 @@ CONFIG_IRQSOFF_TRACER=y
CONFIG_PREEMPT_TRACER=y
CONFIG_BLK_DEV_IO_TRACE=y
CONFIG_CPU_FREQ_SWITCH_PROFILER=y
+CONFIG_LKDTM=y
CONFIG_MEMTEST=y
CONFIG_PANIC_ON_DATA_CORRUPTION=y
CONFIG_ARM64_PTDUMP=y
diff --git a/arch/arm64/configs/sdm660-perf_defconfig b/arch/arm64/configs/sdm660-perf_defconfig
index c92551c69bf8..0a5f7f1f0f2d 100644
--- a/arch/arm64/configs/sdm660-perf_defconfig
+++ b/arch/arm64/configs/sdm660-perf_defconfig
@@ -5,6 +5,9 @@ CONFIG_AUDIT=y
CONFIG_NO_HZ=y
CONFIG_HIGH_RES_TIMERS=y
CONFIG_IRQ_TIME_ACCOUNTING=y
+CONFIG_TASKSTATS=y
+CONFIG_TASK_XACCT=y
+CONFIG_TASK_IO_ACCOUNTING=y
CONFIG_RCU_EXPERT=y
CONFIG_RCU_FAST_NO_HZ=y
CONFIG_RCU_NOCB_CPU=y
@@ -93,6 +96,7 @@ CONFIG_XFRM_USER=y
CONFIG_XFRM_STATISTICS=y
CONFIG_NET_KEY=y
CONFIG_INET=y
+CONFIG_IP_MULTICAST=y
CONFIG_IP_ADVANCED_ROUTER=y
CONFIG_IP_MULTIPLE_TABLES=y
CONFIG_IP_ROUTE_VERBOSE=y
@@ -242,6 +246,7 @@ CONFIG_BLK_DEV_RAM=y
CONFIG_BLK_DEV_RAM_SIZE=8192
CONFIG_QSEECOM=y
CONFIG_HDCP_QSEECOM=y
+CONFIG_UID_SYS_STATS=y
CONFIG_QPNP_MISC=y
CONFIG_SCSI=y
CONFIG_BLK_DEV_SD=y
@@ -311,6 +316,7 @@ CONFIG_SERIAL_MSM_SMD=y
CONFIG_DIAG_CHAR=y
CONFIG_HW_RANDOM=y
CONFIG_HW_RANDOM_MSM_LEGACY=y
+# CONFIG_DEVPORT is not set
CONFIG_MSM_ADSPRPC=y
CONFIG_MSM_RDBG=m
CONFIG_I2C_CHARDEV=y
@@ -559,6 +565,7 @@ CONFIG_QCOM_SCM=y
CONFIG_QCOM_WATCHDOG_V2=y
CONFIG_QCOM_IRQ_HELPER=y
CONFIG_QCOM_MEMORY_DUMP_V2=y
+CONFIG_QCOM_MINIDUMP=y
CONFIG_ICNSS=y
CONFIG_MSM_RUN_QUEUE_STATS=y
CONFIG_MSM_BOOT_STATS=y
@@ -610,6 +617,9 @@ CONFIG_EXT4_FS_SECURITY=y
CONFIG_EXT4_ENCRYPTION=y
CONFIG_EXT4_FS_ENCRYPTION=y
CONFIG_EXT4_FS_ICE_ENCRYPTION=y
+CONFIG_QUOTA=y
+CONFIG_QUOTA_NETLINK_INTERFACE=y
+CONFIG_QFMT_V2=y
CONFIG_FUSE_FS=y
CONFIG_MSDOS_FS=y
CONFIG_VFAT_FS=y
@@ -642,6 +652,7 @@ CONFIG_CORESIGHT_TPDM=y
CONFIG_CORESIGHT_QPDI=y
CONFIG_CORESIGHT_SOURCE_DUMMY=y
CONFIG_PFK=y
+CONFIG_SECURITY_PERF_EVENTS_RESTRICT=y
CONFIG_SECURITY=y
CONFIG_HARDENED_USERCOPY=y
CONFIG_SECURITY_SELINUX=y
diff --git a/arch/arm64/configs/sdm660_defconfig b/arch/arm64/configs/sdm660_defconfig
index 6b45087e2603..7819916fb841 100644
--- a/arch/arm64/configs/sdm660_defconfig
+++ b/arch/arm64/configs/sdm660_defconfig
@@ -97,6 +97,7 @@ CONFIG_XFRM_USER=y
CONFIG_XFRM_STATISTICS=y
CONFIG_NET_KEY=y
CONFIG_INET=y
+CONFIG_IP_MULTICAST=y
CONFIG_IP_ADVANCED_ROUTER=y
CONFIG_IP_MULTIPLE_TABLES=y
CONFIG_IP_ROUTE_VERBOSE=y
@@ -320,6 +321,7 @@ CONFIG_SERIAL_MSM_SMD=y
CONFIG_DIAG_CHAR=y
CONFIG_HW_RANDOM=y
CONFIG_HW_RANDOM_MSM_LEGACY=y
+# CONFIG_DEVPORT is not set
CONFIG_MSM_ADSPRPC=y
CONFIG_MSM_RDBG=m
CONFIG_I2C_CHARDEV=y
@@ -579,6 +581,7 @@ CONFIG_QCOM_SCM=y
CONFIG_QCOM_WATCHDOG_V2=y
CONFIG_QCOM_IRQ_HELPER=y
CONFIG_QCOM_MEMORY_DUMP_V2=y
+CONFIG_QCOM_MINIDUMP=y
CONFIG_ICNSS=y
CONFIG_MSM_GLADIATOR_ERP_V2=y
CONFIG_PANIC_ON_GLADIATOR_ERROR_V2=y
@@ -636,6 +639,9 @@ CONFIG_EXT4_FS_SECURITY=y
CONFIG_EXT4_ENCRYPTION=y
CONFIG_EXT4_FS_ENCRYPTION=y
CONFIG_EXT4_FS_ICE_ENCRYPTION=y
+CONFIG_QUOTA=y
+CONFIG_QUOTA_NETLINK_INTERFACE=y
+CONFIG_QFMT_V2=y
CONFIG_FUSE_FS=y
CONFIG_MSDOS_FS=y
CONFIG_VFAT_FS=y
@@ -693,6 +699,7 @@ CONFIG_IRQSOFF_TRACER=y
CONFIG_PREEMPT_TRACER=y
CONFIG_BLK_DEV_IO_TRACE=y
CONFIG_CPU_FREQ_SWITCH_PROFILER=y
+CONFIG_LKDTM=y
CONFIG_MEMTEST=y
CONFIG_PANIC_ON_DATA_CORRUPTION=y
CONFIG_ARM64_PTDUMP=y
@@ -715,6 +722,7 @@ CONFIG_CORESIGHT_TPDM=y
CONFIG_CORESIGHT_QPDI=y
CONFIG_CORESIGHT_SOURCE_DUMMY=y
CONFIG_PFK=y
+CONFIG_SECURITY_PERF_EVENTS_RESTRICT=y
CONFIG_SECURITY=y
CONFIG_HARDENED_USERCOPY=y
CONFIG_SECURITY_SELINUX=y
diff --git a/arch/arm64/kernel/smp.c b/arch/arm64/kernel/smp.c
index ca522c822eff..961fd5d2e7ce 100644
--- a/arch/arm64/kernel/smp.c
+++ b/arch/arm64/kernel/smp.c
@@ -54,6 +54,7 @@
#include <asm/ptrace.h>
#include <asm/virt.h>
#include <asm/edac.h>
+#include <soc/qcom/minidump.h>
#define CREATE_TRACE_POINTS
#include <trace/events/ipi.h>
@@ -752,6 +753,7 @@ static void ipi_cpu_stop(unsigned int cpu, struct pt_regs *regs)
pr_crit("CPU%u: stopping\n", cpu);
show_regs(regs);
dump_stack();
+ dump_stack_minidump(regs->sp);
arm64_check_cache_ecc(NULL);
raw_spin_unlock(&stop_lock);
}
diff --git a/arch/arm64/mm/dma-mapping.c b/arch/arm64/mm/dma-mapping.c
index a41178f8eeea..159c79612e63 100644
--- a/arch/arm64/mm/dma-mapping.c
+++ b/arch/arm64/mm/dma-mapping.c
@@ -3,6 +3,7 @@
*
* Copyright (C) 2012 ARM Ltd.
* Author: Catalin Marinas <catalin.marinas@arm.com>
+ * Copyright (c) 2017, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -49,17 +50,6 @@ static pgprot_t __get_dma_pgprot(struct dma_attrs *attrs, pgprot_t prot,
return prot;
}
-static int __get_iommu_pgprot(struct dma_attrs *attrs, int prot,
- bool coherent)
-{
- if (!dma_get_attr(DMA_ATTR_EXEC_MAPPING, attrs))
- prot |= IOMMU_NOEXEC;
- if (coherent)
- prot |= IOMMU_CACHE;
-
- return prot;
-}
-
static bool is_dma_coherent(struct device *dev, struct dma_attrs *attrs)
{
bool is_coherent;
@@ -930,7 +920,6 @@ static struct dma_map_ops iommu_dma_ops = {
.sync_single_for_device = __iommu_sync_single_for_device,
.sync_sg_for_cpu = __iommu_sync_sg_for_cpu,
.sync_sg_for_device = __iommu_sync_sg_for_device,
- .dma_supported = iommu_dma_supported,
.mapping_error = iommu_dma_mapping_error,
};
@@ -1145,6 +1134,17 @@ EXPORT_SYMBOL(arch_setup_dma_ops);
#ifdef CONFIG_ARM64_DMA_USE_IOMMU
+static int __get_iommu_pgprot(struct dma_attrs *attrs, int prot,
+ bool coherent)
+{
+ if (!dma_get_attr(DMA_ATTR_EXEC_MAPPING, attrs))
+ prot |= IOMMU_NOEXEC;
+ if (coherent)
+ prot |= IOMMU_CACHE;
+
+ return prot;
+}
+
/*
* Make an area consistent for devices.
* Note: Drivers should NOT use this function directly, as it will break
diff --git a/drivers/base/core.c b/drivers/base/core.c
index 5a56a8e9f006..f3d395bfe8f6 100644
--- a/drivers/base/core.c
+++ b/drivers/base/core.c
@@ -1116,13 +1116,7 @@ int device_add(struct device *dev)
error = dpm_sysfs_add(dev);
if (error)
goto DPMError;
- if ((dev->pm_domain) || (dev->type && dev->type->pm)
- || (dev->class && (dev->class->pm || dev->class->resume))
- || (dev->bus && (dev->bus->pm || dev->bus->resume)) ||
- (dev->driver && dev->driver->pm)) {
- device_pm_add(dev);
- }
-
+ device_pm_add(dev);
if (MAJOR(dev->devt)) {
error = device_create_file(dev, &dev_attr_dev);
diff --git a/drivers/base/power/main.c b/drivers/base/power/main.c
index a88590bb0b10..6c5bc3fadfcf 100644
--- a/drivers/base/power/main.c
+++ b/drivers/base/power/main.c
@@ -162,12 +162,6 @@ void device_pm_move_before(struct device *deva, struct device *devb)
pr_debug("PM: Moving %s:%s before %s:%s\n",
deva->bus ? deva->bus->name : "No Bus", dev_name(deva),
devb->bus ? devb->bus->name : "No Bus", dev_name(devb));
- if (!((devb->pm_domain) || (devb->type && devb->type->pm)
- || (devb->class && (devb->class->pm || devb->class->resume))
- || (devb->bus && (devb->bus->pm || devb->bus->resume)) ||
- (devb->driver && devb->driver->pm))) {
- device_pm_add(devb);
- }
/* Delete deva from dpm_list and reinsert before devb. */
list_move_tail(&deva->power.entry, &devb->power.entry);
}
@@ -182,12 +176,6 @@ void device_pm_move_after(struct device *deva, struct device *devb)
pr_debug("PM: Moving %s:%s after %s:%s\n",
deva->bus ? deva->bus->name : "No Bus", dev_name(deva),
devb->bus ? devb->bus->name : "No Bus", dev_name(devb));
- if (!((devb->pm_domain) || (devb->type && devb->type->pm)
- || (devb->class && (devb->class->pm || devb->class->resume))
- || (devb->bus && (devb->bus->pm || devb->bus->resume)) ||
- (devb->driver && devb->driver->pm))) {
- device_pm_add(devb);
- }
/* Delete deva from dpm_list and reinsert after devb. */
list_move(&deva->power.entry, &devb->power.entry);
}
diff --git a/drivers/bluetooth/btfm_slim_wcn3990.c b/drivers/bluetooth/btfm_slim_wcn3990.c
index 363b4692d228..7abd5598c47b 100644
--- a/drivers/bluetooth/btfm_slim_wcn3990.c
+++ b/drivers/bluetooth/btfm_slim_wcn3990.c
@@ -122,6 +122,18 @@ int btfm_slim_chrk_enable_port(struct btfmslim *btfmslim, uint8_t port_num,
ret, reg);
goto error;
}
+ } else if (port_num == CHRK_SB_PGD_PORT_TX_SCO) {
+ /* SCO Tx */
+ reg_val = 0x1 << CHRK_SB_PGD_PORT_TX_SCO;
+ reg = CHRK_SB_PGD_TX_PORTn_MULTI_CHNL_0(port_num);
+ BTFMSLIM_DBG("writing reg_val (%d) to reg(%x)",
+ reg_val, reg);
+ ret = btfm_slim_write(btfmslim, reg, 1, &reg_val, IFD);
+ if (ret) {
+ BTFMSLIM_ERR("failed to write (%d) reg 0x%x",
+ ret, reg);
+ goto error;
+ }
}
/* Enable Tx port hw auto recovery for underrun or overrun error */
@@ -146,9 +158,15 @@ enable_disable_rxport:
if (is_fm_port(port_num))
reg_val = en | CHRK_SB_PGD_PORT_WM_L8;
+ else if (port_num == CHRK_SB_PGD_PORT_TX_SCO)
+ reg_val = enable ? en | CHRK_SB_PGD_PORT_WM_L1 : en;
else
reg_val = enable ? en | CHRK_SB_PGD_PORT_WM_LB : en;
+ if (enable && port_num == CHRK_SB_PGD_PORT_TX_SCO)
+ BTFMSLIM_INFO("programming SCO Tx with reg_val %d to reg 0x%x",
+ reg_val, reg);
+
ret = btfm_slim_write(btfmslim, reg, 1, &reg_val, IFD);
if (ret)
BTFMSLIM_ERR("failed to write (%d) reg 0x%x", ret, reg);
diff --git a/drivers/char/adsprpc.c b/drivers/char/adsprpc.c
index aba9010c5aa2..77c8f279b4f5 100644
--- a/drivers/char/adsprpc.c
+++ b/drivers/char/adsprpc.c
@@ -1256,9 +1256,18 @@ static int get_args(uint32_t kernel, struct smq_invoke_ctx *ctx)
if (map && (map->attr & FASTRPC_ATTR_COHERENT))
continue;
- if (rpra[i].buf.len && ctx->overps[oix]->mstart)
- dmac_flush_range(uint64_to_ptr(rpra[i].buf.pv),
- uint64_to_ptr(rpra[i].buf.pv + rpra[i].buf.len));
+ if (rpra[i].buf.len && ctx->overps[oix]->mstart) {
+ if (map && map->handle)
+ msm_ion_do_cache_op(ctx->fl->apps->client,
+ map->handle,
+ uint64_to_ptr(rpra[i].buf.pv),
+ rpra[i].buf.len,
+ ION_IOC_CLEAN_INV_CACHES);
+ else
+ dmac_flush_range(uint64_to_ptr(rpra[i].buf.pv),
+ uint64_to_ptr(rpra[i].buf.pv
+ + rpra[i].buf.len));
+ }
}
PERF_END);
@@ -1269,11 +1278,6 @@ static int get_args(uint32_t kernel, struct smq_invoke_ctx *ctx)
rpra[inh + i].h = ctx->lpra[inh + i].h;
}
- if (!ctx->fl->sctx->smmu.coherent) {
- PERF(ctx->fl->profile, ctx->fl->perf.flush,
- dmac_flush_range((char *)rpra, (char *)rpra + ctx->used);
- PERF_END);
- }
bail:
return err;
}
@@ -1337,14 +1341,33 @@ static void inv_args_pre(struct smq_invoke_ctx *ctx)
if (buf_page_start(ptr_to_uint64((void *)rpra)) ==
buf_page_start(rpra[i].buf.pv))
continue;
- if (!IS_CACHE_ALIGNED((uintptr_t)uint64_to_ptr(rpra[i].buf.pv)))
- dmac_flush_range(uint64_to_ptr(rpra[i].buf.pv),
- (char *)(uint64_to_ptr(rpra[i].buf.pv + 1)));
+ if (!IS_CACHE_ALIGNED((uintptr_t)
+ uint64_to_ptr(rpra[i].buf.pv))) {
+ if (map && map->handle)
+ msm_ion_do_cache_op(ctx->fl->apps->client,
+ map->handle,
+ uint64_to_ptr(rpra[i].buf.pv),
+ sizeof(uintptr_t),
+ ION_IOC_CLEAN_INV_CACHES);
+ else
+ dmac_flush_range(
+ uint64_to_ptr(rpra[i].buf.pv), (char *)
+ uint64_to_ptr(rpra[i].buf.pv + 1));
+ }
+
end = (uintptr_t)uint64_to_ptr(rpra[i].buf.pv +
rpra[i].buf.len);
- if (!IS_CACHE_ALIGNED(end))
- dmac_flush_range((char *)end,
- (char *)end + 1);
+ if (!IS_CACHE_ALIGNED(end)) {
+ if (map && map->handle)
+ msm_ion_do_cache_op(ctx->fl->apps->client,
+ map->handle,
+ uint64_to_ptr(end),
+ sizeof(uintptr_t),
+ ION_IOC_CLEAN_INV_CACHES);
+ else
+ dmac_flush_range((char *)end,
+ (char *)end + 1);
+ }
}
}
@@ -1353,7 +1376,6 @@ static void inv_args(struct smq_invoke_ctx *ctx)
int i, inbufs, outbufs;
uint32_t sc = ctx->sc;
remote_arg64_t *rpra = ctx->rpra;
- int used = ctx->used;
int inv = 0;
inbufs = REMOTE_SCALARS_INBUFS(sc);
@@ -1386,8 +1408,6 @@ static void inv_args(struct smq_invoke_ctx *ctx)
+ rpra[i].buf.len));
}
- if (inv || REMOTE_SCALARS_OUTHANDLES(sc))
- dmac_inv_range(rpra, (char *)rpra + used);
}
static int fastrpc_invoke_send(struct smq_invoke_ctx *ctx,
@@ -2502,9 +2522,16 @@ static int fastrpc_channel_open(struct fastrpc_file *fl)
kref_init(&me->channel[cid].kref);
pr_info("'opened /dev/%s c %d %d'\n", gcinfo[cid].name,
MAJOR(me->dev_no), cid);
- err = glink_queue_rx_intent(me->channel[cid].chan, NULL, 64);
- if (err)
- pr_info("adsprpc: initial intent failed for %d\n", cid);
+
+ if (me->glink) {
+ err = glink_queue_rx_intent(me->channel[cid].chan,
+ NULL, 16);
+ err |= glink_queue_rx_intent(me->channel[cid].chan,
+ NULL, 64);
+ if (err)
+ pr_warn("adsprpc: intent fail for %d err %d\n",
+ cid, err);
+ }
if (cid == 0 && me->channel[cid].ssrcount !=
me->channel[cid].prevssrcount) {
if (fastrpc_mmap_remove_ssr(fl))
diff --git a/drivers/char/diag/diagchar_core.c b/drivers/char/diag/diagchar_core.c
index eaed3b101095..4111e599877a 100644
--- a/drivers/char/diag/diagchar_core.c
+++ b/drivers/char/diag/diagchar_core.c
@@ -3029,6 +3029,16 @@ static int diag_user_process_apps_data(const char __user *buf, int len,
return 0;
}
+static int check_data_ready(int index)
+{
+ int data_type = 0;
+
+ mutex_lock(&driver->diagchar_mutex);
+ data_type = driver->data_ready[index];
+ mutex_unlock(&driver->diagchar_mutex);
+ return data_type;
+}
+
static ssize_t diagchar_read(struct file *file, char __user *buf, size_t count,
loff_t *ppos)
{
@@ -3041,9 +3051,11 @@ static ssize_t diagchar_read(struct file *file, char __user *buf, size_t count,
int write_len = 0;
struct diag_md_session_t *session_info = NULL;
+ mutex_lock(&driver->diagchar_mutex);
for (i = 0; i < driver->num_clients; i++)
if (driver->client_map[i].pid == current->tgid)
index = i;
+ mutex_unlock(&driver->diagchar_mutex);
if (index == -1) {
pr_err("diag: Client PID not found in table");
@@ -3053,7 +3065,7 @@ static ssize_t diagchar_read(struct file *file, char __user *buf, size_t count,
pr_err("diag: bad address from user side\n");
return -EFAULT;
}
- wait_event_interruptible(driver->wait_q, driver->data_ready[index]);
+ wait_event_interruptible(driver->wait_q, (check_data_ready(index)) > 0);
mutex_lock(&driver->diagchar_mutex);
@@ -3194,11 +3206,11 @@ static ssize_t diagchar_read(struct file *file, char __user *buf, size_t count,
}
exit:
- mutex_unlock(&driver->diagchar_mutex);
if (driver->data_ready[index] & DCI_DATA_TYPE) {
- mutex_lock(&driver->dci_mutex);
- /* Copy the type of data being passed */
data_type = driver->data_ready[index] & DCI_DATA_TYPE;
+ mutex_unlock(&driver->diagchar_mutex);
+ /* Copy the type of data being passed */
+ mutex_lock(&driver->dci_mutex);
list_for_each_safe(start, temp, &driver->dci_client_list) {
entry = list_entry(start, struct diag_dci_client_tbl,
track);
@@ -3230,6 +3242,7 @@ exit:
mutex_unlock(&driver->dci_mutex);
goto end;
}
+ mutex_unlock(&driver->diagchar_mutex);
end:
/*
* Flush any read that is currently pending on DCI data and
diff --git a/drivers/char/diag/diagfwd_cntl.c b/drivers/char/diag/diagfwd_cntl.c
index 74777212e4cf..10038e629e6c 100644
--- a/drivers/char/diag/diagfwd_cntl.c
+++ b/drivers/char/diag/diagfwd_cntl.c
@@ -1119,6 +1119,18 @@ void diag_map_pd_to_diagid(uint8_t pd, uint8_t *diag_id, int *peripheral)
*diag_id = DIAG_ID_LPASS;
*peripheral = PERIPHERAL_LPASS;
break;
+ case PERIPHERAL_WCNSS:
+ *diag_id = 0;
+ *peripheral = PERIPHERAL_WCNSS;
+ break;
+ case PERIPHERAL_SENSORS:
+ *diag_id = 0;
+ *peripheral = PERIPHERAL_SENSORS;
+ break;
+ case PERIPHERAL_WDSP:
+ *diag_id = 0;
+ *peripheral = PERIPHERAL_WDSP;
+ break;
case PERIPHERAL_CDSP:
*diag_id = DIAG_ID_CDSP;
*peripheral = PERIPHERAL_CDSP;
diff --git a/drivers/char/diag/diagfwd_peripheral.c b/drivers/char/diag/diagfwd_peripheral.c
index 78b8452b19b3..0f94bab3bf84 100644
--- a/drivers/char/diag/diagfwd_peripheral.c
+++ b/drivers/char/diag/diagfwd_peripheral.c
@@ -500,15 +500,29 @@ static void diagfwd_data_read_untag_done(struct diagfwd_info *fwd_info,
temp_buf_main += (buf_len + 4);
processed += buf_len;
}
+
+ if (flag_buf_1) {
+ fwd_info->cpd_len_1 = len_cpd;
+ if (fwd_info->type == TYPE_DATA)
+ fwd_info->upd_len_1_a = len_upd_1;
+ if (peripheral == PERIPHERAL_LPASS &&
+ fwd_info->type == TYPE_DATA)
+ fwd_info->upd_len_2_a = len_upd_2;
+ } else if (flag_buf_2) {
+ fwd_info->cpd_len_2 = len_cpd;
+ if (fwd_info->type == TYPE_DATA)
+ fwd_info->upd_len_1_b = len_upd_1;
+ if (peripheral == PERIPHERAL_LPASS &&
+ fwd_info->type == TYPE_DATA)
+ fwd_info->upd_len_2_b = len_upd_2;
+ }
+
if (peripheral == PERIPHERAL_LPASS &&
fwd_info->type == TYPE_DATA && len_upd_2) {
- if (flag_buf_1) {
- fwd_info->upd_len_2_a = len_upd_2;
+ if (flag_buf_1)
temp_ptr_upd = fwd_info->buf_upd_2_a;
- } else {
- fwd_info->upd_len_2_b = len_upd_2;
+ else
temp_ptr_upd = fwd_info->buf_upd_2_b;
- }
temp_ptr_upd->ctxt &= 0x00FFFFFF;
temp_ptr_upd->ctxt |=
(SET_PD_CTXT(ctxt_upd_2));
@@ -522,15 +536,10 @@ static void diagfwd_data_read_untag_done(struct diagfwd_info *fwd_info,
fwd_info->upd_len_2_b = 0;
}
if (fwd_info->type == TYPE_DATA && len_upd_1) {
- if (flag_buf_1) {
- fwd_info->upd_len_1_a =
- len_upd_1;
+ if (flag_buf_1)
temp_ptr_upd = fwd_info->buf_upd_1_a;
- } else {
- fwd_info->upd_len_1_b =
- len_upd_1;
+ else
temp_ptr_upd = fwd_info->buf_upd_1_b;
- }
temp_ptr_upd->ctxt &= 0x00FFFFFF;
temp_ptr_upd->ctxt |=
(SET_PD_CTXT(ctxt_upd_1));
@@ -544,10 +553,6 @@ static void diagfwd_data_read_untag_done(struct diagfwd_info *fwd_info,
fwd_info->upd_len_1_b = 0;
}
if (len_cpd) {
- if (flag_buf_1)
- fwd_info->cpd_len_1 = len_cpd;
- else
- fwd_info->cpd_len_2 = len_cpd;
temp_ptr_cpd->ctxt &= 0x00FFFFFF;
temp_ptr_cpd->ctxt |=
(SET_PD_CTXT(ctxt_cpd));
@@ -1049,16 +1054,7 @@ void diagfwd_close_transport(uint8_t transport, uint8_t peripheral)
dest_info->buf_ptr[i] = fwd_info->buf_ptr[i];
if (!check_channel_state(dest_info->ctxt))
diagfwd_late_open(dest_info);
-
- /*
- * Open control channel to update masks after buffers are
- * initialized for peripherals that have transport other than
- * GLINK. GLINK supported peripheral mask update will
- * happen after glink buffers are initialized.
- */
-
- if (dest_info->transport != TRANSPORT_GLINK)
- diagfwd_cntl_open(dest_info);
+ diagfwd_cntl_open(dest_info);
init_fn(peripheral);
mutex_unlock(&driver->diagfwd_channel_mutex[peripheral]);
diagfwd_queue_read(&peripheral_info[TYPE_DATA][peripheral]);
@@ -1251,15 +1247,11 @@ int diagfwd_channel_open(struct diagfwd_info *fwd_info)
diagfwd_buffers_init(fwd_info);
/*
- * Initialize buffers for glink supported
- * peripherals only. Open control channel to update
- * masks after buffers are initialized.
+ * Initialize buffers for glink supported
+ * peripherals only.
*/
- if (fwd_info->transport == TRANSPORT_GLINK) {
+ if (fwd_info->transport == TRANSPORT_GLINK)
diagfwd_write_buffers_init(fwd_info);
- if (fwd_info->type == TYPE_CNTL)
- diagfwd_cntl_open(fwd_info);
- }
if (fwd_info && fwd_info->c_ops && fwd_info->c_ops->open)
fwd_info->c_ops->open(fwd_info);
@@ -1345,12 +1337,33 @@ void diagfwd_write_done(uint8_t peripheral, uint8_t type, int ctxt)
if (ctxt == 1 && fwd_info->buf_1) {
/* Buffer 1 for core PD is freed */
- atomic_set(&fwd_info->buf_1->in_busy, 0);
fwd_info->cpd_len_1 = 0;
+
+ if (peripheral == PERIPHERAL_LPASS) {
+ if (!fwd_info->upd_len_1_a &&
+ !fwd_info->upd_len_2_a)
+ atomic_set(&fwd_info->buf_1->in_busy, 0);
+ } else if (peripheral == PERIPHERAL_MODEM) {
+ if (!fwd_info->upd_len_1_a)
+ atomic_set(&fwd_info->buf_1->in_busy, 0);
+ } else {
+ atomic_set(&fwd_info->buf_1->in_busy, 0);
+ }
} else if (ctxt == 2 && fwd_info->buf_2) {
/* Buffer 2 for core PD is freed */
- atomic_set(&fwd_info->buf_2->in_busy, 0);
fwd_info->cpd_len_2 = 0;
+
+ if (peripheral == PERIPHERAL_LPASS) {
+ if (!fwd_info->upd_len_1_b &&
+ !fwd_info->upd_len_2_b)
+ atomic_set(&fwd_info->buf_2->in_busy, 0);
+ } else if (peripheral == PERIPHERAL_MODEM) {
+ if (!fwd_info->upd_len_1_b)
+ atomic_set(&fwd_info->buf_2->in_busy, 0);
+ } else {
+ atomic_set(&fwd_info->buf_2->in_busy, 0);
+ }
+
} else if (ctxt == 3 && fwd_info->buf_upd_1_a) {
/* Buffer 1 for user pd 1 is freed */
atomic_set(&fwd_info->buf_upd_1_a->in_busy, 0);
diff --git a/drivers/clk/msm/clock-dummy.c b/drivers/clk/msm/clock-dummy.c
index e5339b110cd6..caa6a6ab7565 100644
--- a/drivers/clk/msm/clock-dummy.c
+++ b/drivers/clk/msm/clock-dummy.c
@@ -64,12 +64,18 @@ struct clk dummy_clk = {
static void *dummy_clk_dt_parser(struct device *dev, struct device_node *np)
{
struct clk *c;
+ u32 rate;
+
c = devm_kzalloc(dev, sizeof(*c), GFP_KERNEL);
if (!c) {
dev_err(dev, "failed to map memory for %s\n", np->name);
return ERR_PTR(-ENOMEM);
}
c->ops = &clk_ops_dummy;
+
+ if (!of_property_read_u32(np, "clock-frequency", &rate))
+ c->rate = rate;
+
return msmclk_generic_clk_init(dev, np, c);
}
MSMCLK_PARSER(dummy_clk_dt_parser, "qcom,dummy-clk", 0);
@@ -82,6 +88,7 @@ static struct clk *of_dummy_get(struct of_phandle_args *clkspec,
static struct of_device_id msm_clock_dummy_match_table[] = {
{ .compatible = "qcom,dummycc" },
+ { .compatible = "fixed-clock" },
{}
};
diff --git a/drivers/clk/qcom/clk-cpu-osm.c b/drivers/clk/qcom/clk-cpu-osm.c
index ddaeca1b29e4..510a9803bd82 100644
--- a/drivers/clk/qcom/clk-cpu-osm.c
+++ b/drivers/clk/qcom/clk-cpu-osm.c
@@ -226,8 +226,8 @@ enum clk_osm_trace_packet_id {
#define PLL_DD_D0_USER_CTL_LO 0x17916208
#define PLL_DD_D1_USER_CTL_LO 0x17816208
-#define PWRCL_EFUSE_SHIFT 0
-#define PWRCL_EFUSE_MASK 0
+#define PWRCL_EFUSE_SHIFT 29
+#define PWRCL_EFUSE_MASK 0x7
#define PERFCL_EFUSE_SHIFT 29
#define PERFCL_EFUSE_MASK 0x7
@@ -623,18 +623,21 @@ static inline bool is_better_rate(unsigned long req, unsigned long best,
return (req <= new && new < best) || (best < req && best < new);
}
-static long clk_osm_round_rate(struct clk_hw *hw, unsigned long rate,
- unsigned long *parent_rate)
+static int clk_osm_determine_rate(struct clk_hw *hw,
+ struct clk_rate_request *req)
{
int i;
unsigned long rrate = 0;
+ unsigned long rate = req->rate;
/*
* If the rate passed in is 0, return the first frequency in the
* FMAX table.
*/
- if (!rate)
- return hw->init->rate_max[0];
+ if (!rate) {
+ req->rate = hw->init->rate_max[0];
+ return 0;
+ }
for (i = 0; i < hw->init->num_rate_max; i++) {
if (is_better_rate(rate, rrate, hw->init->rate_max[i])) {
@@ -644,10 +647,12 @@ static long clk_osm_round_rate(struct clk_hw *hw, unsigned long rate,
}
}
+ req->rate = rrate;
+
pr_debug("%s: rate %lu, rrate %ld, Rate max %ld\n", __func__, rate,
rrate, hw->init->rate_max[i]);
- return rrate;
+ return 0;
}
static int clk_osm_search_table(struct osm_entry *table, int entries, long rate)
@@ -678,18 +683,19 @@ static int clk_osm_set_rate(struct clk_hw *hw, unsigned long rate,
{
struct clk_osm *cpuclk = to_clk_osm(hw);
int index = 0;
- unsigned long r_rate;
+ struct clk_rate_request req;
- r_rate = clk_osm_round_rate(hw, rate, NULL);
+ req.rate = rate;
+ clk_osm_determine_rate(hw, &req);
- if (rate != r_rate) {
+ if (rate != req.rate) {
pr_err("invalid rate requested rate=%ld\n", rate);
return -EINVAL;
}
/* Convert rate to table index */
index = clk_osm_search_table(cpuclk->osm_table,
- cpuclk->num_entries, r_rate);
+ cpuclk->num_entries, req.rate);
if (index < 0) {
pr_err("cannot set cluster %u to %lu\n",
cpuclk->cluster_num, rate);
@@ -773,7 +779,7 @@ static unsigned long clk_osm_recalc_rate(struct clk_hw *hw,
static struct clk_ops clk_ops_cpu_osm = {
.enable = clk_osm_enable,
.set_rate = clk_osm_set_rate,
- .round_rate = clk_osm_round_rate,
+ .determine_rate = clk_osm_determine_rate,
.list_rate = clk_osm_list_rate,
.recalc_rate = clk_osm_recalc_rate,
.debug_init = clk_debug_measure_add,
diff --git a/drivers/gpu/drm/msm/Kconfig b/drivers/gpu/drm/msm/Kconfig
index dbc198b00792..cb3b25ddd0da 100644
--- a/drivers/gpu/drm/msm/Kconfig
+++ b/drivers/gpu/drm/msm/Kconfig
@@ -98,3 +98,13 @@ config DRM_SDE_HDMI
default y
help
Choose this option if HDMI connector support is needed in SDE driver.
+
+config DRM_SDE_EVTLOG_DEBUG
+ bool "Enable event logging in MSM DRM"
+ depends on DRM_MSM
+ help
+ The SDE DRM debugging provides support to enable display debugging
+ features to: dump SDE registers during driver errors, panic
+ driver during fatal errors and enable some display-driver logging
+ into an internal buffer (this avoids logging overhead).
+
diff --git a/drivers/gpu/drm/msm/Makefile b/drivers/gpu/drm/msm/Makefile
index 4c082fff2fc5..678b2178cb69 100644
--- a/drivers/gpu/drm/msm/Makefile
+++ b/drivers/gpu/drm/msm/Makefile
@@ -49,6 +49,7 @@ msm_drm-y := \
sde/sde_color_processing.o \
sde/sde_vbif.o \
sde/sde_splash.o \
+ sde_dbg.o \
sde_dbg_evtlog.o \
sde_io_util.o \
dba_bridge.o \
diff --git a/drivers/gpu/drm/msm/msm_drv.c b/drivers/gpu/drm/msm/msm_drv.c
index c8b11425a817..969af4c6f0c0 100644
--- a/drivers/gpu/drm/msm/msm_drv.c
+++ b/drivers/gpu/drm/msm/msm_drv.c
@@ -293,7 +293,7 @@ static int msm_unload(struct drm_device *dev)
priv->vram.paddr, &attrs);
}
- sde_evtlog_destroy();
+ sde_dbg_destroy();
sde_power_client_destroy(&priv->phandle, priv->pclient);
sde_power_resource_deinit(pdev, &priv->phandle);
@@ -423,11 +423,17 @@ static int msm_component_bind_all(struct device *dev,
}
#endif
+static int msm_power_enable_wrapper(void *handle, void *client, bool enable)
+{
+ return sde_power_resource_enable(handle, client, enable);
+}
+
static int msm_load(struct drm_device *dev, unsigned long flags)
{
struct platform_device *pdev = dev->platformdev;
struct msm_drm_private *priv;
struct msm_kms *kms;
+ struct sde_dbg_power_ctrl dbg_power_ctrl = { NULL };
int ret, i;
priv = kzalloc(sizeof(*priv), GFP_KERNEL);
@@ -477,9 +483,13 @@ static int msm_load(struct drm_device *dev, unsigned long flags)
if (ret)
goto fail;
- ret = sde_evtlog_init(dev->primary->debugfs_root);
+ dbg_power_ctrl.handle = &priv->phandle;
+ dbg_power_ctrl.client = priv->pclient;
+ dbg_power_ctrl.enable_fn = msm_power_enable_wrapper;
+ ret = sde_dbg_init(dev->primary->debugfs_root, &pdev->dev,
+ &dbg_power_ctrl);
if (ret) {
- dev_err(dev->dev, "failed to init evtlog: %d\n", ret);
+ dev_err(dev->dev, "failed to init sde dbg: %d\n", ret);
goto fail;
}
diff --git a/drivers/gpu/drm/msm/msm_drv.h b/drivers/gpu/drm/msm/msm_drv.h
index 49b6029c3342..ae3a930005b6 100644
--- a/drivers/gpu/drm/msm/msm_drv.h
+++ b/drivers/gpu/drm/msm/msm_drv.h
@@ -162,6 +162,7 @@ enum msm_mdp_conn_property {
/* enum/bitmask properties */
CONNECTOR_PROP_TOPOLOGY_NAME,
CONNECTOR_PROP_TOPOLOGY_CONTROL,
+ CONNECTOR_PROP_LP,
/* total # of properties */
CONNECTOR_PROP_COUNT
diff --git a/drivers/gpu/drm/msm/sde/sde_connector.c b/drivers/gpu/drm/msm/sde/sde_connector.c
index 5fa4c21060f9..2ca91674a15a 100644
--- a/drivers/gpu/drm/msm/sde/sde_connector.c
+++ b/drivers/gpu/drm/msm/sde/sde_connector.c
@@ -10,12 +10,13 @@
* GNU General Public License for more details.
*/
-#define pr_fmt(fmt) "sde-drm:[%s] " fmt, __func__
+#define pr_fmt(fmt) "[drm:%s:%d] " fmt, __func__, __LINE__
#include "msm_drv.h"
#include "sde_kms.h"
#include "sde_connector.h"
#include "sde_backlight.h"
+#include "sde_splash.h"
#define SDE_DEBUG_CONN(c, fmt, ...) SDE_DEBUG("conn%d " fmt,\
(c) ? (c)->base.base.id : -1, ##__VA_ARGS__)
@@ -38,6 +39,13 @@ static const struct drm_prop_enum_list e_topology_control[] = {
{SDE_RM_TOPCTL_PPSPLIT, "ppsplit"}
};
+static const struct drm_prop_enum_list e_power_mode[] = {
+ {SDE_MODE_DPMS_ON, "ON"},
+ {SDE_MODE_DPMS_LP1, "LP1"},
+ {SDE_MODE_DPMS_LP2, "LP2"},
+ {SDE_MODE_DPMS_OFF, "OFF"},
+};
+
int sde_connector_get_info(struct drm_connector *connector,
struct msm_display_info *info)
{
@@ -155,6 +163,7 @@ static void sde_connector_destroy(struct drm_connector *connector)
msm_property_destroy(&c_conn->property_info);
drm_connector_unregister(connector);
+ mutex_destroy(&c_conn->lock);
sde_fence_deinit(&c_conn->retire_fence);
drm_connector_cleanup(connector);
kfree(c_conn);
@@ -353,6 +362,56 @@ static int _sde_connector_set_hdr_info(
return 0;
}
+static int _sde_connector_update_power_locked(struct sde_connector *c_conn)
+{
+ struct drm_connector *connector;
+ void *display;
+ int (*set_power)(struct drm_connector *, int, void *);
+ int mode, rc = 0;
+
+ if (!c_conn)
+ return -EINVAL;
+ connector = &c_conn->base;
+
+ mode = c_conn->lp_mode;
+ if (c_conn->dpms_mode != DRM_MODE_DPMS_ON)
+ mode = SDE_MODE_DPMS_OFF;
+ switch (c_conn->dpms_mode) {
+ case DRM_MODE_DPMS_ON:
+ mode = c_conn->lp_mode;
+ break;
+ case DRM_MODE_DPMS_STANDBY:
+ mode = SDE_MODE_DPMS_STANDBY;
+ break;
+ case DRM_MODE_DPMS_SUSPEND:
+ mode = SDE_MODE_DPMS_SUSPEND;
+ break;
+ case DRM_MODE_DPMS_OFF:
+ mode = SDE_MODE_DPMS_OFF;
+ break;
+ default:
+ mode = c_conn->lp_mode;
+ SDE_ERROR("conn %d dpms set to unrecognized mode %d\n",
+ connector->base.id, mode);
+ break;
+ }
+
+ SDE_DEBUG("conn %d - dpms %d, lp %d, panel %d\n", connector->base.id,
+ c_conn->dpms_mode, c_conn->lp_mode, mode);
+
+ if (mode != c_conn->last_panel_power_mode && c_conn->ops.set_power) {
+ display = c_conn->display;
+ set_power = c_conn->ops.set_power;
+
+ mutex_unlock(&c_conn->lock);
+ rc = set_power(connector, mode, display);
+ mutex_lock(&c_conn->lock);
+ }
+ c_conn->last_panel_power_mode = mode;
+
+ return rc;
+}
+
static int sde_connector_atomic_set_property(struct drm_connector *connector,
struct drm_connector_state *state,
struct drm_property *property,
@@ -379,8 +438,8 @@ static int sde_connector_atomic_set_property(struct drm_connector *connector,
/* connector-specific property handling */
idx = msm_property_index(&c_conn->property_info, property);
-
- if (idx == CONNECTOR_PROP_OUT_FB) {
+ switch (idx) {
+ case CONNECTOR_PROP_OUT_FB:
/* clear old fb, if present */
if (c_state->out_fb)
_sde_connector_destroy_fb(c_conn, c_state);
@@ -404,12 +463,20 @@ static int sde_connector_atomic_set_property(struct drm_connector *connector,
if (rc)
SDE_ERROR("prep fb failed, %d\n", rc);
}
- }
-
- if (idx == CONNECTOR_PROP_TOPOLOGY_CONTROL) {
+ break;
+ case CONNECTOR_PROP_TOPOLOGY_CONTROL:
rc = sde_rm_check_property_topctl(val);
if (rc)
SDE_ERROR("invalid topology_control: 0x%llX\n", val);
+ break;
+ case CONNECTOR_PROP_LP:
+ mutex_lock(&c_conn->lock);
+ c_conn->lp_mode = val;
+ _sde_connector_update_power_locked(c_conn);
+ mutex_unlock(&c_conn->lock);
+ break;
+ default:
+ break;
}
if (idx == CONNECTOR_PROP_HDR_CONTROL) {
@@ -501,13 +568,89 @@ void sde_connector_prepare_fence(struct drm_connector *connector)
void sde_connector_complete_commit(struct drm_connector *connector)
{
+ struct drm_device *dev;
+ struct msm_drm_private *priv;
+ struct sde_connector *c_conn;
+ struct sde_kms *sde_kms;
+
if (!connector) {
SDE_ERROR("invalid connector\n");
return;
}
+ dev = connector->dev;
+ priv = dev->dev_private;
+ sde_kms = to_sde_kms(priv->kms);
+
/* signal connector's retire fence */
sde_fence_signal(&to_sde_connector(connector)->retire_fence, 0);
+
+ /* after first vsync comes,
+ * early splash resource should start to be released.
+ */
+ if (sde_splash_get_lk_complete_status(&sde_kms->splash_info)) {
+ c_conn = to_sde_connector(connector);
+
+ sde_splash_clean_up_free_resource(priv->kms,
+ &priv->phandle,
+ c_conn->connector_type,
+ c_conn->display);
+ }
+
+}
+
+static int sde_connector_dpms(struct drm_connector *connector,
+ int mode)
+{
+ struct sde_connector *c_conn;
+
+ if (!connector) {
+ SDE_ERROR("invalid connector\n");
+ return -EINVAL;
+ }
+ c_conn = to_sde_connector(connector);
+
+ /* validate incoming dpms request */
+ switch (mode) {
+ case DRM_MODE_DPMS_ON:
+ case DRM_MODE_DPMS_STANDBY:
+ case DRM_MODE_DPMS_SUSPEND:
+ case DRM_MODE_DPMS_OFF:
+ SDE_DEBUG("conn %d dpms set to %d\n",
+ connector->base.id, mode);
+ break;
+ default:
+ SDE_ERROR("conn %d dpms set to unrecognized mode %d\n",
+ connector->base.id, mode);
+ break;
+ }
+
+ mutex_lock(&c_conn->lock);
+ c_conn->dpms_mode = mode;
+ _sde_connector_update_power_locked(c_conn);
+ mutex_unlock(&c_conn->lock);
+
+ /* use helper for boilerplate handling */
+ return drm_atomic_helper_connector_dpms(connector, mode);
+}
+
+int sde_connector_get_dpms(struct drm_connector *connector)
+{
+ struct sde_connector *c_conn;
+ int rc;
+
+ if (!connector) {
+ SDE_DEBUG("invalid connector\n");
+ return DRM_MODE_DPMS_OFF;
+ }
+
+ c_conn = to_sde_connector(connector);
+
+ mutex_lock(&c_conn->lock);
+ rc = c_conn->dpms_mode;
+ mutex_unlock(&c_conn->lock);
+
+ return rc;
}
static void sde_connector_update_hdr_props(struct drm_connector *connector)
@@ -558,7 +701,7 @@ sde_connector_detect(struct drm_connector *connector, bool force)
}
static const struct drm_connector_funcs sde_connector_ops = {
- .dpms = drm_atomic_helper_connector_dpms,
+ .dpms = sde_connector_dpms,
.reset = sde_connector_atomic_reset,
.detect = sde_connector_detect,
.destroy = sde_connector_destroy,
@@ -681,6 +824,11 @@ struct drm_connector *sde_connector_init(struct drm_device *dev,
c_conn->panel = panel;
c_conn->display = display;
+ c_conn->dpms_mode = DRM_MODE_DPMS_ON;
+ c_conn->lp_mode = 0;
+ c_conn->last_panel_power_mode = SDE_MODE_DPMS_ON;
+
+
sde_kms = to_sde_kms(priv->kms);
if (sde_kms->vbif[VBIF_NRT]) {
c_conn->aspace[SDE_IOMMU_DOMAIN_UNSECURE] =
@@ -714,6 +862,8 @@ struct drm_connector *sde_connector_init(struct drm_device *dev,
goto error_cleanup_conn;
}
+ mutex_init(&c_conn->lock);
+
rc = drm_connector_register(&c_conn->base);
if (rc) {
SDE_ERROR("failed to register drm connector, %d\n", rc);
@@ -793,6 +943,11 @@ struct drm_connector *sde_connector_init(struct drm_device *dev,
ARRAY_SIZE(e_topology_control),
CONNECTOR_PROP_TOPOLOGY_CONTROL, 0);
+ msm_property_install_enum(&c_conn->property_info, "LP",
+ 0, 0, e_power_mode,
+ ARRAY_SIZE(e_power_mode),
+ CONNECTOR_PROP_LP, 0);
+
rc = msm_property_install_get_status(&c_conn->property_info);
if (rc) {
SDE_ERROR("failed to create one or more properties\n");
@@ -819,6 +974,7 @@ error_destroy_property:
error_unregister_conn:
drm_connector_unregister(&c_conn->base);
error_cleanup_fence:
+ mutex_destroy(&c_conn->lock);
sde_fence_deinit(&c_conn->retire_fence);
error_cleanup_conn:
drm_connector_cleanup(&c_conn->base);
diff --git a/drivers/gpu/drm/msm/sde/sde_connector.h b/drivers/gpu/drm/msm/sde/sde_connector.h
index b76ce0aaf577..f9b8c3966d74 100644
--- a/drivers/gpu/drm/msm/sde/sde_connector.h
+++ b/drivers/gpu/drm/msm/sde/sde_connector.h
@@ -153,6 +153,20 @@ struct sde_connector_ops {
*/
enum sde_csc_type (*get_csc_type)(struct drm_connector *connector,
void *display);
+
+ /**
+ * set_power - update dpms setting
+ * @connector: Pointer to drm connector structure
+ * @power_mode: One of the following,
+ * SDE_MODE_DPMS_ON
+ * SDE_MODE_DPMS_LP1
+ * SDE_MODE_DPMS_LP2
+ * SDE_MODE_DPMS_OFF
+ * @display: Pointer to private display structure
+ * Returns: Zero on success
+ */
+ int (*set_power)(struct drm_connector *connector,
+ int power_mode, void *display);
};
/**
@@ -165,8 +179,12 @@ struct sde_connector_ops {
* @mmu_secure: MMU id for secure buffers
* @mmu_unsecure: MMU id for unsecure buffers
* @name: ASCII name of connector
+ * @lock: Mutex lock object for this structure
* @retire_fence: Retire fence reference
* @ops: Local callback function pointer table
+ * @dpms_mode: DPMS property setting from user space
+ * @lp_mode: LP property setting from user space
+ * @last_panel_power_mode: Last consolidated dpms/lp mode setting
* @property_info: Private structure for generic property handling
* @property_data: Array of private data for generic property handling
* @blob_caps: Pointer to blob structure for 'capabilities' property
@@ -185,8 +203,12 @@ struct sde_connector {
char name[SDE_CONNECTOR_NAME_SIZE];
+ struct mutex lock;
struct sde_fence retire_fence;
struct sde_connector_ops ops;
+ int dpms_mode;
+ int lp_mode;
+ int last_panel_power_mode;
struct msm_property_info property_info;
struct msm_property_data property_data[CONNECTOR_PROP_COUNT];
@@ -361,5 +383,12 @@ bool sde_connector_mode_needs_full_range(struct drm_connector *connector);
*/
enum sde_csc_type sde_connector_get_csc_type(struct drm_connector *conn);
+/**
+ * sde_connector_get_dpms - query dpms setting
+ * @connector: Pointer to drm connector structure
+ * Returns: Current DPMS setting for connector
+ */
+int sde_connector_get_dpms(struct drm_connector *connector);
+
#endif /* _SDE_CONNECTOR_H_ */
diff --git a/drivers/gpu/drm/msm/sde/sde_core_irq.c b/drivers/gpu/drm/msm/sde/sde_core_irq.c
index dbfc2dd11a17..83c8982b2e00 100644
--- a/drivers/gpu/drm/msm/sde/sde_core_irq.c
+++ b/drivers/gpu/drm/msm/sde/sde_core_irq.c
@@ -32,7 +32,7 @@ static void sde_core_irq_callback_handler(void *arg, int irq_idx)
struct sde_irq_callback *cb;
unsigned long irq_flags;
- SDE_DEBUG("irq_idx=%d\n", irq_idx);
+ pr_debug("irq_idx=%d\n", irq_idx);
if (list_empty(&irq_obj->irq_cb_tbl[irq_idx]))
SDE_ERROR("irq_idx=%d has no registered callback\n", irq_idx);
diff --git a/drivers/gpu/drm/msm/sde/sde_crtc.c b/drivers/gpu/drm/msm/sde/sde_crtc.c
index 2e9e2192670d..a0417a0dd12e 100644
--- a/drivers/gpu/drm/msm/sde/sde_crtc.c
+++ b/drivers/gpu/drm/msm/sde/sde_crtc.c
@@ -600,23 +600,14 @@ void sde_crtc_complete_commit(struct drm_crtc *crtc,
{
struct sde_crtc *sde_crtc;
struct sde_crtc_state *cstate;
- struct drm_connector *conn;
- struct sde_connector *c_conn;
- struct drm_device *dev;
- struct msm_drm_private *priv;
- struct sde_kms *sde_kms;
int i;
- if (!crtc || !crtc->state || !crtc->dev) {
+ if (!crtc || !crtc->state) {
SDE_ERROR("invalid crtc\n");
return;
}
- dev = crtc->dev;
- priv = dev->dev_private;
-
sde_crtc = to_sde_crtc(crtc);
- sde_kms = _sde_crtc_get_kms(crtc);
cstate = to_sde_crtc_state(crtc->state);
SDE_EVT32(DRMID(crtc));
@@ -625,22 +616,6 @@ void sde_crtc_complete_commit(struct drm_crtc *crtc,
for (i = 0; i < cstate->num_connectors; ++i)
sde_connector_complete_commit(cstate->connectors[i]);
-
- if (sde_splash_get_lk_complete_status(&sde_kms->splash_info)) {
- mutex_lock(&dev->mode_config.mutex);
- drm_for_each_connector(conn, crtc->dev) {
- if (conn->state->crtc != crtc)
- continue;
-
- c_conn = to_sde_connector(conn);
-
- sde_splash_clean_up_free_resource(priv->kms,
- &priv->phandle,
- c_conn->connector_type,
- c_conn->display);
- }
- mutex_unlock(&dev->mode_config.mutex);
- }
}
/**
@@ -935,6 +910,15 @@ void sde_crtc_commit_kickoff(struct drm_crtc *crtc)
sde_kms = _sde_crtc_get_kms(crtc);
priv = sde_kms->dev->dev_private;
+ /*
+ * If no mixers has been allocated in sde_crtc_atomic_check(),
+ * it means we are trying to start a CRTC whose state is disabled:
+ * nothing else needs to be done.
+ */
+ if (unlikely(!sde_crtc->num_mixers))
+ return;
+
+
SDE_ATRACE_BEGIN("crtc_commit");
list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) {
if (encoder->crtc != crtc)
@@ -979,8 +963,10 @@ end:
* _sde_crtc_vblank_enable_nolock - update power resource and vblank request
* @sde_crtc: Pointer to sde crtc structure
* @enable: Whether to enable/disable vblanks
+ *
+ * @Return: error code
*/
-static void _sde_crtc_vblank_enable_nolock(
+static int _sde_crtc_vblank_enable_no_lock(
struct sde_crtc *sde_crtc, bool enable)
{
struct drm_device *dev;
@@ -988,10 +974,11 @@ static void _sde_crtc_vblank_enable_nolock(
struct drm_encoder *enc;
struct msm_drm_private *priv;
struct sde_kms *sde_kms;
+ int ret = 0;
if (!sde_crtc) {
SDE_ERROR("invalid crtc\n");
- return;
+ return -EINVAL;
}
crtc = &sde_crtc->base;
@@ -1000,13 +987,16 @@ static void _sde_crtc_vblank_enable_nolock(
if (!priv->kms) {
SDE_ERROR("invalid kms\n");
- return;
+ return -EINVAL;
}
sde_kms = to_sde_kms(priv->kms);
if (enable) {
- sde_power_resource_enable(&priv->phandle,
+ ret = sde_power_resource_enable(&priv->phandle,
sde_kms->core_client, true);
+ if (ret)
+ return ret;
+
list_for_each_entry(enc, &dev->mode_config.encoder_list, head) {
if (enc->crtc != crtc)
continue;
@@ -1025,9 +1015,11 @@ static void _sde_crtc_vblank_enable_nolock(
sde_encoder_register_vblank_callback(enc, NULL, NULL);
}
- sde_power_resource_enable(&priv->phandle,
+ ret = sde_power_resource_enable(&priv->phandle,
sde_kms->core_client, false);
}
+
+ return ret;
}
/**
@@ -1073,8 +1065,8 @@ static void _sde_crtc_set_suspend(struct drm_crtc *crtc, bool enable)
if (sde_crtc->suspend == enable)
SDE_DEBUG("crtc%d suspend already set to %d, ignoring update\n",
crtc->base.id, enable);
- else if (atomic_read(&sde_crtc->vblank_refcount) != 0)
- _sde_crtc_vblank_enable_nolock(sde_crtc, !enable);
+ else if (sde_crtc->enabled && sde_crtc->vblank_requested)
+ _sde_crtc_vblank_enable_no_lock(sde_crtc, !enable);
sde_crtc->suspend = enable;
@@ -1158,39 +1150,13 @@ static void sde_crtc_reset(struct drm_crtc *crtc)
crtc->state = &cstate->base;
}
-static int _sde_crtc_vblank_no_lock(struct sde_crtc *sde_crtc, bool en)
-{
- if (!sde_crtc) {
- SDE_ERROR("invalid crtc\n");
- return -EINVAL;
- } else if (en && atomic_inc_return(&sde_crtc->vblank_refcount) == 1) {
- SDE_DEBUG("crtc%d vblank enable\n", sde_crtc->base.base.id);
- if (!sde_crtc->suspend)
- _sde_crtc_vblank_enable_nolock(sde_crtc, true);
- } else if (!en && atomic_read(&sde_crtc->vblank_refcount) < 1) {
- SDE_ERROR("crtc%d invalid vblank disable\n",
- sde_crtc->base.base.id);
- return -EINVAL;
- } else if (!en && atomic_dec_return(&sde_crtc->vblank_refcount) == 0) {
- SDE_DEBUG("crtc%d vblank disable\n", sde_crtc->base.base.id);
- if (!sde_crtc->suspend)
- _sde_crtc_vblank_enable_nolock(sde_crtc, false);
- } else {
- SDE_DEBUG("crtc%d vblank %s refcount:%d\n",
- sde_crtc->base.base.id,
- en ? "enable" : "disable",
- atomic_read(&sde_crtc->vblank_refcount));
- }
-
- return 0;
-}
-
static void sde_crtc_disable(struct drm_crtc *crtc)
{
struct drm_encoder *encoder;
struct sde_crtc *sde_crtc;
struct sde_kms *sde_kms;
struct msm_drm_private *priv;
+ int ret = 0;
if (!crtc || !crtc->dev || !crtc->state) {
SDE_ERROR("invalid crtc\n");
@@ -1210,17 +1176,19 @@ static void sde_crtc_disable(struct drm_crtc *crtc)
_sde_crtc_set_suspend(crtc, true);
mutex_lock(&sde_crtc->crtc_lock);
- SDE_EVT32(DRMID(crtc));
+ SDE_EVT32(DRMID(crtc), sde_crtc->enabled, sde_crtc->suspend,
+ sde_crtc->vblank_requested);
- if (atomic_read(&sde_crtc->vblank_refcount) && !sde_crtc->suspend) {
- SDE_ERROR("crtc%d invalid vblank refcount\n",
- crtc->base.id);
- SDE_EVT32(DRMID(crtc), atomic_read(&sde_crtc->vblank_refcount));
- while (atomic_read(&sde_crtc->vblank_refcount))
- if (_sde_crtc_vblank_no_lock(sde_crtc, false))
- break;
+ if (sde_crtc->enabled && !sde_crtc->suspend &&
+ sde_crtc->vblank_requested) {
+ ret = _sde_crtc_vblank_enable_no_lock(sde_crtc, false);
+ if (ret)
+ SDE_ERROR("%s vblank enable failed: %d\n",
+ sde_crtc->name, ret);
}
+ sde_crtc->enabled = false;
+
if (atomic_read(&sde_crtc->frame_pending)) {
/* release bandwidth and other resources */
SDE_ERROR("crtc%d invalid frame pending\n",
@@ -1255,6 +1223,7 @@ static void sde_crtc_enable(struct drm_crtc *crtc)
struct sde_hw_mixer_cfg cfg;
struct drm_encoder *encoder;
int i;
+ int ret = 0;
if (!crtc) {
SDE_ERROR("invalid crtc\n");
@@ -1283,6 +1252,19 @@ static void sde_crtc_enable(struct drm_crtc *crtc)
sde_crtc_request_flip_cb, (void *)crtc);
}
+ mutex_lock(&sde_crtc->crtc_lock);
+ SDE_EVT32(DRMID(crtc), sde_crtc->enabled, sde_crtc->suspend,
+ sde_crtc->vblank_requested);
+ if (!sde_crtc->enabled && !sde_crtc->suspend &&
+ sde_crtc->vblank_requested) {
+ ret = _sde_crtc_vblank_enable_no_lock(sde_crtc, true);
+ if (ret)
+ SDE_ERROR("%s vblank enable failed: %d\n",
+ sde_crtc->name, ret);
+ }
+ sde_crtc->enabled = true;
+ mutex_unlock(&sde_crtc->crtc_lock);
+
for (i = 0; i < sde_crtc->num_mixers; i++) {
lm = mixer[i].hw_lm;
cfg.out_width = sde_crtc_mixer_width(sde_crtc, mode);
@@ -1329,8 +1311,7 @@ static int sde_crtc_atomic_check(struct drm_crtc *crtc,
struct drm_display_mode *mode;
int cnt = 0, rc = 0, mixer_width, i, z_pos;
- int left_crtc_zpos_cnt[SDE_STAGE_MAX] = {0};
- int right_crtc_zpos_cnt[SDE_STAGE_MAX] = {0};
+ int left_zpos_cnt = 0, right_zpos_cnt = 0;
if (!crtc) {
SDE_ERROR("invalid crtc\n");
@@ -1347,6 +1328,10 @@ static int sde_crtc_atomic_check(struct drm_crtc *crtc,
mode = &state->adjusted_mode;
SDE_DEBUG("%s: check", sde_crtc->name);
+ /* force a full mode set if active state changed */
+ if (state->active_changed)
+ state->mode_changed = true;
+
mixer_width = sde_crtc_mixer_width(sde_crtc, mode);
/* get plane state for all drm planes associated with crtc state */
@@ -1380,11 +1365,12 @@ static int sde_crtc_atomic_check(struct drm_crtc *crtc,
}
}
+ /* assign mixer stages based on sorted zpos property */
+ sort(pstates, cnt, sizeof(pstates[0]), pstate_cmp, NULL);
+
if (!sde_is_custom_client()) {
int stage_old = pstates[0].stage;
- /* assign mixer stages based on sorted zpos property */
- sort(pstates, cnt, sizeof(pstates[0]), pstate_cmp, NULL);
z_pos = 0;
for (i = 0; i < cnt; i++) {
if (stage_old != pstates[i].stage)
@@ -1394,8 +1380,14 @@ static int sde_crtc_atomic_check(struct drm_crtc *crtc,
}
}
+ z_pos = -1;
for (i = 0; i < cnt; i++) {
- z_pos = pstates[i].stage;
+ /* reset counts at every new blend stage */
+ if (pstates[i].stage != z_pos) {
+ left_zpos_cnt = 0;
+ right_zpos_cnt = 0;
+ z_pos = pstates[i].stage;
+ }
/* verify z_pos setting before using it */
if (z_pos >= SDE_STAGE_MAX - SDE_STAGE_0) {
@@ -1404,22 +1396,24 @@ static int sde_crtc_atomic_check(struct drm_crtc *crtc,
rc = -EINVAL;
goto end;
} else if (pstates[i].drm_pstate->crtc_x < mixer_width) {
- if (left_crtc_zpos_cnt[z_pos] == 2) {
- SDE_ERROR("> 2 plane @ stage%d on left\n",
+ if (left_zpos_cnt == 2) {
+ SDE_ERROR("> 2 planes @ stage %d on left\n",
z_pos);
rc = -EINVAL;
goto end;
}
- left_crtc_zpos_cnt[z_pos]++;
+ left_zpos_cnt++;
+
} else {
- if (right_crtc_zpos_cnt[z_pos] == 2) {
- SDE_ERROR("> 2 plane @ stage%d on right\n",
+ if (right_zpos_cnt == 2) {
+ SDE_ERROR("> 2 planes @ stage %d on right\n",
z_pos);
rc = -EINVAL;
goto end;
}
- right_crtc_zpos_cnt[z_pos]++;
+ right_zpos_cnt++;
}
+
pstates[i].sde_pstate->stage = z_pos + SDE_STAGE_0;
SDE_DEBUG("%s: zpos %d", sde_crtc->name, z_pos);
}
@@ -1431,6 +1425,49 @@ static int sde_crtc_atomic_check(struct drm_crtc *crtc,
goto end;
}
+ /*
+ * enforce pipe priority restrictions
+ * use pstates sorted by stage to check planes on same stage
+ * we assume that all pipes are in source split so its valid to compare
+ * without taking into account left/right mixer placement
+ */
+ for (i = 1; i < cnt; i++) {
+ struct plane_state *prv_pstate, *cur_pstate;
+ int32_t prv_x, cur_x, prv_id, cur_id;
+
+ prv_pstate = &pstates[i - 1];
+ cur_pstate = &pstates[i];
+ if (prv_pstate->stage != cur_pstate->stage)
+ continue;
+
+ prv_x = prv_pstate->drm_pstate->crtc_x;
+ cur_x = cur_pstate->drm_pstate->crtc_x;
+ prv_id = prv_pstate->sde_pstate->base.plane->base.id;
+ cur_id = cur_pstate->sde_pstate->base.plane->base.id;
+
+ /*
+ * Planes are enumerated in pipe-priority order such that planes
+ * with lower drm_id must be left-most in a shared blend-stage
+ * when using source split.
+ */
+ if (cur_x > prv_x && cur_id < prv_id) {
+ SDE_ERROR(
+ "shared z_pos %d lower id plane%d @ x%d should be left of plane%d @ x %d\n",
+ cur_pstate->stage, cur_id, cur_x,
+ prv_id, prv_x);
+ rc = -EINVAL;
+ goto end;
+ } else if (cur_x < prv_x && cur_id > prv_id) {
+ SDE_ERROR(
+ "shared z_pos %d lower id plane%d @ x%d should be left of plane%d @ x %d\n",
+ cur_pstate->stage, prv_id, prv_x,
+ cur_id, cur_x);
+ rc = -EINVAL;
+ goto end;
+ }
+ }
+
+
end:
return rc;
}
@@ -1438,7 +1475,7 @@ end:
int sde_crtc_vblank(struct drm_crtc *crtc, bool en)
{
struct sde_crtc *sde_crtc;
- int rc;
+ int ret;
if (!crtc) {
SDE_ERROR("invalid crtc\n");
@@ -1447,10 +1484,19 @@ int sde_crtc_vblank(struct drm_crtc *crtc, bool en)
sde_crtc = to_sde_crtc(crtc);
mutex_lock(&sde_crtc->crtc_lock);
- rc = _sde_crtc_vblank_no_lock(sde_crtc, en);
+ SDE_EVT32(DRMID(&sde_crtc->base), en, sde_crtc->enabled,
+ sde_crtc->suspend, sde_crtc->vblank_requested);
+ if (sde_crtc->enabled && !sde_crtc->suspend) {
+ ret = _sde_crtc_vblank_enable_no_lock(sde_crtc, en);
+ if (ret)
+ SDE_ERROR("%s vblank enable failed: %d\n",
+ sde_crtc->name, ret);
+ }
+
+ sde_crtc->vblank_requested = en;
mutex_unlock(&sde_crtc->crtc_lock);
- return rc;
+ return 0;
}
void sde_crtc_cancel_pending_flip(struct drm_crtc *crtc,
@@ -1551,7 +1597,7 @@ static void sde_crtc_install_properties(struct drm_crtc *crtc,
sde_kms_info_add_keyint(info, "max_mdp_clk",
sde_kms->perf.max_core_clk_rate);
msm_property_set_blob(&sde_crtc->property_info, &sde_crtc->blob_info,
- info->data, info->len, CRTC_PROP_INFO);
+ info->data, SDE_KMS_INFO_DATALEN(info), CRTC_PROP_INFO);
kfree(info);
}
@@ -1763,8 +1809,7 @@ static int _sde_debugfs_status_show(struct seq_file *s, void *data)
sde_crtc->vblank_cb_time = ktime_set(0, 0);
}
- seq_printf(s, "vblank_refcount:%d\n",
- atomic_read(&sde_crtc->vblank_refcount));
+ seq_printf(s, "vblank_enable:%d\n", sde_crtc->vblank_requested);
mutex_unlock(&sde_crtc->crtc_lock);
@@ -1892,7 +1937,6 @@ struct drm_crtc *sde_crtc_init(struct drm_device *dev,
crtc = &sde_crtc->base;
crtc->dev = dev;
- atomic_set(&sde_crtc->vblank_refcount, 0);
mutex_init(&sde_crtc->crtc_lock);
spin_lock_init(&sde_crtc->spin_lock);
diff --git a/drivers/gpu/drm/msm/sde/sde_crtc.h b/drivers/gpu/drm/msm/sde/sde_crtc.h
index 6b8483d574b1..0eed61580cd8 100644
--- a/drivers/gpu/drm/msm/sde/sde_crtc.h
+++ b/drivers/gpu/drm/msm/sde/sde_crtc.h
@@ -81,8 +81,11 @@ struct sde_crtc_frame_event {
* @debugfs_root : Parent of debugfs node
* @vblank_cb_count : count of vblank callback since last reset
* @vblank_cb_time : ktime at vblank count reset
- * @vblank_refcount : reference count for vblank enable request
+ * @vblank_requested : whether the user has requested vblank events
* @suspend : whether or not a suspend operation is in progress
+ * @enabled : whether the SDE CRTC is currently enabled. updated in the
+ * commit-thread, not state-swap time which is earlier, so
+ * safe to make decisions on during VBLANK on/off work
* @feature_list : list of color processing features supported on a crtc
* @active_list : list of color processing features are active
* @dirty_list : list of color processing features are dirty
@@ -117,8 +120,9 @@ struct sde_crtc {
u32 vblank_cb_count;
ktime_t vblank_cb_time;
- atomic_t vblank_refcount;
+ bool vblank_requested;
bool suspend;
+ bool enabled;
struct list_head feature_list;
struct list_head active_list;
diff --git a/drivers/gpu/drm/msm/sde/sde_encoder.c b/drivers/gpu/drm/msm/sde/sde_encoder.c
index 23fb79241d84..cb8b349e72c7 100644
--- a/drivers/gpu/drm/msm/sde/sde_encoder.c
+++ b/drivers/gpu/drm/msm/sde/sde_encoder.c
@@ -506,11 +506,6 @@ static void sde_encoder_virt_disable(struct drm_encoder *drm_enc)
SDE_EVT32(DRMID(drm_enc));
- if (atomic_xchg(&sde_enc->frame_done_timeout, 0)) {
- SDE_ERROR("enc%d timeout pending\n", drm_enc->base.id);
- del_timer_sync(&sde_enc->frame_done_timer);
- }
-
for (i = 0; i < sde_enc->num_phys_encs; i++) {
struct sde_encoder_phys *phys = sde_enc->phys_encs[i];
@@ -523,6 +518,12 @@ static void sde_encoder_virt_disable(struct drm_encoder *drm_enc)
}
}
+ /* after phys waits for frame-done, should be no more frames pending */
+ if (atomic_xchg(&sde_enc->frame_done_timeout, 0)) {
+ SDE_ERROR("enc%d timeout pending\n", drm_enc->base.id);
+ del_timer_sync(&sde_enc->frame_done_timer);
+ }
+
if (sde_enc->cur_master && sde_enc->cur_master->ops.disable)
sde_enc->cur_master->ops.disable(sde_enc->cur_master);
diff --git a/drivers/gpu/drm/msm/sde/sde_encoder_phys_vid.c b/drivers/gpu/drm/msm/sde/sde_encoder_phys_vid.c
index 69a4237f7b67..d58c06de1684 100644
--- a/drivers/gpu/drm/msm/sde/sde_encoder_phys_vid.c
+++ b/drivers/gpu/drm/msm/sde/sde_encoder_phys_vid.c
@@ -281,23 +281,40 @@ static void sde_encoder_phys_vid_vblank_irq(void *arg, int irq_idx)
{
struct sde_encoder_phys_vid *vid_enc = arg;
struct sde_encoder_phys *phys_enc;
+ struct sde_hw_ctl *hw_ctl;
unsigned long lock_flags;
- int new_cnt;
+ u32 flush_register = 0;
+ int new_cnt = -1, old_cnt = -1;
if (!vid_enc)
return;
phys_enc = &vid_enc->base;
+ hw_ctl = phys_enc->hw_ctl;
+
if (phys_enc->parent_ops.handle_vblank_virt)
phys_enc->parent_ops.handle_vblank_virt(phys_enc->parent,
phys_enc);
+ old_cnt = atomic_read(&phys_enc->pending_kickoff_cnt);
+
+ /*
+ * only decrement the pending flush count if we've actually flushed
+ * hardware. due to sw irq latency, vblank may have already happened
+ * so we need to double-check with hw that it accepted the flush bits
+ */
spin_lock_irqsave(phys_enc->enc_spinlock, lock_flags);
- new_cnt = atomic_add_unless(&phys_enc->pending_kickoff_cnt, -1, 0);
- SDE_EVT32_IRQ(DRMID(phys_enc->parent), vid_enc->hw_intf->idx - INTF_0,
- new_cnt);
+ if (hw_ctl && hw_ctl->ops.get_flush_register)
+ flush_register = hw_ctl->ops.get_flush_register(hw_ctl);
+
+ if (flush_register == 0)
+ new_cnt = atomic_add_unless(&phys_enc->pending_kickoff_cnt,
+ -1, 0);
spin_unlock_irqrestore(phys_enc->enc_spinlock, lock_flags);
+ SDE_EVT32_IRQ(DRMID(phys_enc->parent), vid_enc->hw_intf->idx - INTF_0,
+ old_cnt, new_cnt, flush_register);
+
/* Signal any waiting atomic commit thread */
wake_up_all(&phys_enc->pending_kickoff_wq);
}
@@ -700,6 +717,35 @@ static int sde_encoder_phys_vid_wait_for_commit_done(
return ret;
}
+static void sde_encoder_phys_vid_prepare_for_kickoff(
+ struct sde_encoder_phys *phys_enc)
+{
+ struct sde_encoder_phys_vid *vid_enc;
+ struct sde_hw_ctl *ctl;
+ int rc;
+
+ if (!phys_enc) {
+ SDE_ERROR("invalid encoder\n");
+ return;
+ }
+ vid_enc = to_sde_encoder_phys_vid(phys_enc);
+
+ ctl = phys_enc->hw_ctl;
+ if (!ctl || !ctl->ops.wait_reset_status)
+ return;
+
+ /*
+ * hw supports hardware initiated ctl reset, so before we kickoff a new
+ * frame, need to check and wait for hw initiated ctl reset completion
+ */
+ rc = ctl->ops.wait_reset_status(ctl);
+ if (rc) {
+ SDE_ERROR_VIDENC(vid_enc, "ctl %d reset failure: %d\n",
+ ctl->idx, rc);
+ SDE_DBG_DUMP("panic");
+ }
+}
+
static void sde_encoder_phys_vid_disable(struct sde_encoder_phys *phys_enc)
{
struct msm_drm_private *priv;
@@ -832,6 +878,7 @@ static void sde_encoder_phys_vid_init_ops(struct sde_encoder_phys_ops *ops)
ops->get_hw_resources = sde_encoder_phys_vid_get_hw_resources;
ops->control_vblank_irq = sde_encoder_phys_vid_control_vblank_irq;
ops->wait_for_commit_done = sde_encoder_phys_vid_wait_for_commit_done;
+ ops->prepare_for_kickoff = sde_encoder_phys_vid_prepare_for_kickoff;
ops->handle_post_kickoff = sde_encoder_phys_vid_handle_post_kickoff;
ops->needs_single_flush = sde_encoder_phys_vid_needs_single_flush;
ops->setup_misr = sde_encoder_phys_vid_setup_misr;
diff --git a/drivers/gpu/drm/msm/sde/sde_hw_catalog.c b/drivers/gpu/drm/msm/sde/sde_hw_catalog.c
index a185eb338134..1a563ea5f50c 100644
--- a/drivers/gpu/drm/msm/sde/sde_hw_catalog.c
+++ b/drivers/gpu/drm/msm/sde/sde_hw_catalog.c
@@ -134,6 +134,7 @@ enum {
enum {
VIG_QSEED_OFF,
+ VIG_QSEED_LEN,
VIG_CSC_OFF,
VIG_HSIC_PROP,
VIG_MEMCOLOR_PROP,
@@ -143,6 +144,7 @@ enum {
enum {
RGB_SCALER_OFF,
+ RGB_SCALER_LEN,
RGB_PCC_PROP,
RGB_PROP_MAX,
};
@@ -301,6 +303,7 @@ static struct sde_prop_type sspp_prop[] = {
static struct sde_prop_type vig_prop[] = {
{VIG_QSEED_OFF, "qcom,sde-vig-qseed-off", false, PROP_TYPE_U32},
+ {VIG_QSEED_LEN, "qcom,sde-vig-qseed-size", false, PROP_TYPE_U32},
{VIG_CSC_OFF, "qcom,sde-vig-csc-off", false, PROP_TYPE_U32},
{VIG_HSIC_PROP, "qcom,sde-vig-hsic", false, PROP_TYPE_U32_ARRAY},
{VIG_MEMCOLOR_PROP, "qcom,sde-vig-memcolor", false,
@@ -310,6 +313,7 @@ static struct sde_prop_type vig_prop[] = {
static struct sde_prop_type rgb_prop[] = {
{RGB_SCALER_OFF, "qcom,sde-rgb-scaler-off", false, PROP_TYPE_U32},
+ {RGB_SCALER_LEN, "qcom,sde-rgb-scaler-size", false, PROP_TYPE_U32},
{RGB_PCC_PROP, "qcom,sde-rgb-pcc", false, PROP_TYPE_U32_ARRAY},
};
@@ -691,6 +695,8 @@ static void _sde_sspp_setup_vig(struct sde_mdss_cfg *sde_cfg,
sblk->maxdwnscale = MAX_SSPP_DOWNSCALE;
sblk->format_list = plane_formats_yuv;
sspp->id = SSPP_VIG0 + *vig_count;
+ snprintf(sspp->name, SDE_HW_BLK_NAME_LEN, "sspp_%u",
+ sspp->id - SSPP_VIG0);
sspp->clk_ctrl = SDE_CLK_CTRL_VIG0 + *vig_count;
sspp->type = SSPP_TYPE_VIG;
set_bit(SDE_SSPP_QOS, &sspp->features);
@@ -704,14 +710,24 @@ static void _sde_sspp_setup_vig(struct sde_mdss_cfg *sde_cfg,
sblk->scaler_blk.id = SDE_SSPP_SCALER_QSEED2;
sblk->scaler_blk.base = PROP_VALUE_ACCESS(prop_value,
VIG_QSEED_OFF, 0);
- } else if (sde_cfg->qseed_type == SDE_SSPP_SCALER_QSEED3) {
+ sblk->scaler_blk.len = PROP_VALUE_ACCESS(prop_value,
+ VIG_QSEED_LEN, 0);
+ snprintf(sblk->scaler_blk.name, SDE_HW_BLK_NAME_LEN,
+ "sspp_scaler%u", sspp->id - SSPP_VIG0);
+ } else if (sde_cfg->qseed_type == SDE_SSPP_SCALER_QSEED3) {
set_bit(SDE_SSPP_SCALER_QSEED3, &sspp->features);
sblk->scaler_blk.id = SDE_SSPP_SCALER_QSEED3;
sblk->scaler_blk.base = PROP_VALUE_ACCESS(prop_value,
VIG_QSEED_OFF, 0);
+ sblk->scaler_blk.len = PROP_VALUE_ACCESS(prop_value,
+ VIG_QSEED_LEN, 0);
+ snprintf(sblk->scaler_blk.name, SDE_HW_BLK_NAME_LEN,
+ "sspp_scaler%u", sspp->id - SSPP_VIG0);
}
sblk->csc_blk.id = SDE_SSPP_CSC;
+ snprintf(sblk->csc_blk.name, SDE_HW_BLK_NAME_LEN,
+ "sspp_csc%u", sspp->id - SSPP_VIG0);
if (sde_cfg->csc_type == SDE_SSPP_CSC) {
set_bit(SDE_SSPP_CSC, &sspp->features);
sblk->csc_blk.base = PROP_VALUE_ACCESS(prop_value,
@@ -723,6 +739,8 @@ static void _sde_sspp_setup_vig(struct sde_mdss_cfg *sde_cfg,
}
sblk->hsic_blk.id = SDE_SSPP_HSIC;
+ snprintf(sblk->hsic_blk.name, SDE_HW_BLK_NAME_LEN,
+ "sspp_hsic%u", sspp->id - SSPP_VIG0);
if (prop_exists[VIG_HSIC_PROP]) {
sblk->hsic_blk.base = PROP_VALUE_ACCESS(prop_value,
VIG_HSIC_PROP, 0);
@@ -733,6 +751,8 @@ static void _sde_sspp_setup_vig(struct sde_mdss_cfg *sde_cfg,
}
sblk->memcolor_blk.id = SDE_SSPP_MEMCOLOR;
+ snprintf(sblk->memcolor_blk.name, SDE_HW_BLK_NAME_LEN,
+ "sspp_memcolor%u", sspp->id - SSPP_VIG0);
if (prop_exists[VIG_MEMCOLOR_PROP]) {
sblk->memcolor_blk.base = PROP_VALUE_ACCESS(prop_value,
VIG_MEMCOLOR_PROP, 0);
@@ -743,6 +763,8 @@ static void _sde_sspp_setup_vig(struct sde_mdss_cfg *sde_cfg,
}
sblk->pcc_blk.id = SDE_SSPP_PCC;
+ snprintf(sblk->pcc_blk.name, SDE_HW_BLK_NAME_LEN,
+ "sspp_pcc%u", sspp->id - SSPP_VIG0);
if (prop_exists[VIG_PCC_PROP]) {
sblk->pcc_blk.base = PROP_VALUE_ACCESS(prop_value,
VIG_PCC_PROP, 0);
@@ -762,6 +784,8 @@ static void _sde_sspp_setup_rgb(struct sde_mdss_cfg *sde_cfg,
sblk->maxdwnscale = MAX_SSPP_DOWNSCALE;
sblk->format_list = plane_formats;
sspp->id = SSPP_RGB0 + *rgb_count;
+ snprintf(sspp->name, SDE_HW_BLK_NAME_LEN, "sspp_%u",
+ sspp->id - SSPP_VIG0);
sspp->clk_ctrl = SDE_CLK_CTRL_RGB0 + *rgb_count;
sspp->type = SSPP_TYPE_RGB;
set_bit(SDE_SSPP_QOS, &sspp->features);
@@ -775,11 +799,19 @@ static void _sde_sspp_setup_rgb(struct sde_mdss_cfg *sde_cfg,
sblk->scaler_blk.id = SDE_SSPP_SCALER_QSEED2;
sblk->scaler_blk.base = PROP_VALUE_ACCESS(prop_value,
RGB_SCALER_OFF, 0);
+ sblk->scaler_blk.len = PROP_VALUE_ACCESS(prop_value,
+ RGB_SCALER_LEN, 0);
+ snprintf(sblk->scaler_blk.name, SDE_HW_BLK_NAME_LEN,
+ "sspp_scaler%u", sspp->id - SSPP_VIG0);
} else if (sde_cfg->qseed_type == SDE_SSPP_SCALER_QSEED3) {
set_bit(SDE_SSPP_SCALER_RGB, &sspp->features);
sblk->scaler_blk.id = SDE_SSPP_SCALER_QSEED3;
sblk->scaler_blk.base = PROP_VALUE_ACCESS(prop_value,
- RGB_SCALER_OFF, 0);
+ RGB_SCALER_LEN, 0);
+ sblk->scaler_blk.len = PROP_VALUE_ACCESS(prop_value,
+ SSPP_SCALE_SIZE, 0);
+ snprintf(sblk->scaler_blk.name, SDE_HW_BLK_NAME_LEN,
+ "sspp_scaler%u", sspp->id - SSPP_VIG0);
}
sblk->pcc_blk.id = SDE_SSPP_PCC;
@@ -803,6 +835,8 @@ static void _sde_sspp_setup_cursor(struct sde_mdss_cfg *sde_cfg,
sblk->maxdwnscale = SSPP_UNITY_SCALE;
sblk->format_list = cursor_formats;
sspp->id = SSPP_CURSOR0 + *cursor_count;
+ snprintf(sspp->name, SDE_HW_BLK_NAME_LEN, "sspp_%u",
+ sspp->id - SSPP_VIG0);
sspp->clk_ctrl = SDE_CLK_CTRL_CURSOR0 + *cursor_count;
sspp->type = SSPP_TYPE_CURSOR;
(*cursor_count)++;
@@ -819,6 +853,8 @@ static void _sde_sspp_setup_dma(struct sde_mdss_cfg *sde_cfg,
sspp->id = SSPP_DMA0 + *dma_count;
sspp->clk_ctrl = SDE_CLK_CTRL_DMA0 + *dma_count;
sspp->type = SSPP_TYPE_DMA;
+ snprintf(sspp->name, SDE_HW_BLK_NAME_LEN, "sspp_%u",
+ sspp->id - SSPP_VIG0);
set_bit(SDE_SSPP_QOS, &sspp->features);
(*dma_count)++;
snprintf(sspp->name, sizeof(sspp->name), "dma%d", *dma_count-1);
@@ -917,6 +953,7 @@ static int sde_sspp_parse_dt(struct device_node *np,
sspp->sblk = sblk;
sspp->base = PROP_VALUE_ACCESS(prop_value, SSPP_OFF, i);
+ sspp->len = PROP_VALUE_ACCESS(prop_value, SSPP_SIZE, 0);
sblk->maxlinewidth = sde_cfg->max_sspp_linewidth;
set_bit(SDE_SSPP_SRC, &sspp->features);
@@ -944,6 +981,9 @@ static int sde_sspp_parse_dt(struct device_node *np,
goto end;
}
+ snprintf(sblk->src_blk.name, SDE_HW_BLK_NAME_LEN, "sspp_src_%u",
+ sspp->id - SSPP_VIG0);
+
sblk->maxhdeciexp = MAX_HORZ_DECIMATION;
sblk->maxvdeciexp = MAX_VERT_DECIMATION;
@@ -1033,7 +1073,10 @@ static int sde_ctl_parse_dt(struct device_node *np,
for (i = 0; i < off_count; i++) {
ctl = sde_cfg->ctl + i;
ctl->base = PROP_VALUE_ACCESS(prop_value, HW_OFF, i);
+ ctl->len = PROP_VALUE_ACCESS(prop_value, HW_LEN, 0);
ctl->id = CTL_0 + i;
+ snprintf(ctl->name, SDE_HW_BLK_NAME_LEN, "ctl_%u",
+ ctl->id - CTL_0);
if (i < MAX_SPLIT_DISPLAY_CTL)
set_bit(SDE_CTL_SPLIT_DISPLAY, &ctl->features);
@@ -1125,6 +1168,9 @@ static int sde_mixer_parse_dt(struct device_node *np,
mixer->base = PROP_VALUE_ACCESS(prop_value, MIXER_OFF, i);
mixer->len = PROP_VALUE_ACCESS(prop_value, MIXER_LEN, 0);
mixer->id = LM_0 + i;
+ snprintf(mixer->name, SDE_HW_BLK_NAME_LEN, "lm_%u",
+ mixer->id - LM_0);
+
if (!prop_exists[MIXER_LEN])
mixer->len = DEFAULT_SDE_HW_BLOCK_LEN;
@@ -1211,6 +1257,9 @@ static int sde_intf_parse_dt(struct device_node *np,
intf->base = PROP_VALUE_ACCESS(prop_value, INTF_OFF, i);
intf->len = PROP_VALUE_ACCESS(prop_value, INTF_LEN, 0);
intf->id = INTF_0 + i;
+ snprintf(intf->name, SDE_HW_BLK_NAME_LEN, "intf_%u",
+ intf->id - INTF_0);
+
if (!prop_exists[INTF_LEN])
intf->len = DEFAULT_SDE_HW_BLOCK_LEN;
@@ -1290,6 +1339,8 @@ static int sde_wb_parse_dt(struct device_node *np,
wb->base = PROP_VALUE_ACCESS(prop_value, WB_OFF, i);
wb->id = WB_0 + PROP_VALUE_ACCESS(prop_value, WB_ID, i);
+ snprintf(wb->name, SDE_HW_BLK_NAME_LEN, "wb_%u",
+ wb->id - WB_0);
wb->clk_ctrl = SDE_CLK_CTRL_WB0 +
PROP_VALUE_ACCESS(prop_value, WB_ID, i);
wb->xin_id = PROP_VALUE_ACCESS(prop_value, WB_XIN_ID, i);
@@ -1515,7 +1566,10 @@ static int sde_dspp_parse_dt(struct device_node *np,
for (i = 0; i < off_count; i++) {
dspp = sde_cfg->dspp + i;
dspp->base = PROP_VALUE_ACCESS(prop_value, DSPP_OFF, i);
+ dspp->len = PROP_VALUE_ACCESS(prop_value, DSPP_SIZE, 0);
dspp->id = DSPP_0 + i;
+ snprintf(dspp->name, SDE_HW_BLK_NAME_LEN, "dspp_%u",
+ dspp->id - DSPP_0);
sblk = kzalloc(sizeof(*sblk), GFP_KERNEL);
if (!sblk) {
@@ -1585,6 +1639,8 @@ static int sde_cdm_parse_dt(struct device_node *np,
cdm = sde_cfg->cdm + i;
cdm->base = PROP_VALUE_ACCESS(prop_value, HW_OFF, i);
cdm->id = CDM_0 + i;
+ snprintf(cdm->name, SDE_HW_BLK_NAME_LEN, "cdm_%u",
+ cdm->id - CDM_0);
cdm->len = PROP_VALUE_ACCESS(prop_value, HW_LEN, 0);
/* intf3 and wb2 for cdm block */
@@ -1650,6 +1706,8 @@ static int sde_vbif_parse_dt(struct device_node *np,
vbif->base = PROP_VALUE_ACCESS(prop_value, VBIF_OFF, i);
vbif->len = vbif_len;
vbif->id = VBIF_0 + PROP_VALUE_ACCESS(prop_value, VBIF_ID, i);
+ snprintf(vbif->name, SDE_HW_BLK_NAME_LEN, "vbif_%u",
+ vbif->id - VBIF_0);
SDE_DEBUG("vbif:%d\n", vbif->id - VBIF_0);
@@ -1777,15 +1835,21 @@ static int sde_pp_parse_dt(struct device_node *np,
pp->base = PROP_VALUE_ACCESS(prop_value, PP_OFF, i);
pp->id = PINGPONG_0 + i;
+ snprintf(pp->name, SDE_HW_BLK_NAME_LEN, "pingpong_%u",
+ pp->id - PINGPONG_0);
pp->len = PROP_VALUE_ACCESS(prop_value, PP_LEN, 0);
sblk->te.base = PROP_VALUE_ACCESS(prop_value, TE_OFF, i);
sblk->te.id = SDE_PINGPONG_TE;
+ snprintf(sblk->te.name, SDE_HW_BLK_NAME_LEN, "te_%u",
+ pp->id - PINGPONG_0);
set_bit(SDE_PINGPONG_TE, &pp->features);
sblk->te2.base = PROP_VALUE_ACCESS(prop_value, TE2_OFF, i);
if (sblk->te2.base) {
sblk->te2.id = SDE_PINGPONG_TE2;
+ snprintf(sblk->te2.name, SDE_HW_BLK_NAME_LEN, "te2_%u",
+ pp->id - PINGPONG_0);
set_bit(SDE_PINGPONG_TE2, &pp->features);
set_bit(SDE_PINGPONG_SPLIT, &pp->features);
}
@@ -1796,6 +1860,8 @@ static int sde_pp_parse_dt(struct device_node *np,
sblk->dsc.base = PROP_VALUE_ACCESS(prop_value, DSC_OFF, i);
if (sblk->dsc.base) {
sblk->dsc.id = SDE_PINGPONG_DSC;
+ snprintf(sblk->dsc.name, SDE_HW_BLK_NAME_LEN, "dsc_%u",
+ sblk->dsc.id - PINGPONG_0);
set_bit(SDE_PINGPONG_DSC, &pp->features);
}
}
@@ -1926,9 +1992,13 @@ static int sde_parse_dt(struct device_node *np, struct sde_mdss_cfg *cfg)
cfg->mdss_count = 1;
cfg->mdss[0].base = MDSS_BASE_OFFSET;
cfg->mdss[0].id = MDP_TOP;
+ snprintf(cfg->mdss[0].name, SDE_HW_BLK_NAME_LEN, "mdss_%u",
+ cfg->mdss[0].id - MDP_TOP);
cfg->mdp_count = 1;
cfg->mdp[0].id = MDP_TOP;
+ snprintf(cfg->mdp[0].name, SDE_HW_BLK_NAME_LEN, "top_%u",
+ cfg->mdp[0].id - MDP_TOP);
cfg->mdp[0].base = PROP_VALUE_ACCESS(prop_value, SDE_OFF, 0);
cfg->mdp[0].len = PROP_VALUE_ACCESS(prop_value, SDE_LEN, 0);
if (!prop_exists[SDE_LEN])
diff --git a/drivers/gpu/drm/msm/sde/sde_hw_catalog.h b/drivers/gpu/drm/msm/sde/sde_hw_catalog.h
index 73bb77b7afa6..81e6bfe6defe 100644
--- a/drivers/gpu/drm/msm/sde/sde_hw_catalog.h
+++ b/drivers/gpu/drm/msm/sde/sde_hw_catalog.h
@@ -44,10 +44,12 @@
#define SDE_HW_VER_172 SDE_HW_VER(1, 7, 2) /* 8996 v3.0 */
#define SDE_HW_VER_300 SDE_HW_VER(3, 0, 0) /* 8998 v1.0 */
#define SDE_HW_VER_301 SDE_HW_VER(3, 0, 1) /* 8998 v1.1 */
-#define SDE_HW_VER_400 SDE_HW_VER(4, 0, 0) /* msmskunk v1.0 */
+#define SDE_HW_VER_400 SDE_HW_VER(4, 0, 0) /* sdm845 v1.0 */
#define IS_MSMSKUNK_TARGET(rev) IS_SDE_MAJOR_MINOR_SAME((rev), SDE_HW_VER_400)
+#define SDE_HW_BLK_NAME_LEN 16
+
#define MAX_IMG_WIDTH 0x3fff
#define MAX_IMG_HEIGHT 0x3fff
@@ -58,8 +60,6 @@
#define SDE_COLOR_PROCESS_MAJOR(version) (((version) & 0xFFFF0000) >> 16)
#define SDE_COLOR_PROCESS_MINOR(version) ((version) & 0xFFFF)
-#define SSPP_NAME_SIZE 12
-
/**
* MDP TOP BLOCK features
* @SDE_MDP_PANIC_PER_PIPE Panic configuration needs to be be done per pipe
@@ -236,12 +236,14 @@ enum {
/**
* MACRO SDE_HW_BLK_INFO - information of HW blocks inside SDE
+ * @name: string name for debug purposes
* @id: enum identifying this block
* @base: register base offset to mdss
* @len: length of hardware block
* @features bit mask identifying sub-blocks/features
*/
#define SDE_HW_BLK_INFO \
+ char name[SDE_HW_BLK_NAME_LEN]; \
u32 id; \
u32 base; \
u32 len; \
@@ -249,12 +251,14 @@ enum {
/**
* MACRO SDE_HW_SUBBLK_INFO - information of HW sub-block inside SDE
+ * @name: string name for debug purposes
* @id: enum identifying this sub-block
* @base: offset of this sub-block relative to the block
* offset
* @len register block length of this sub-block
*/
#define SDE_HW_SUBBLK_INFO \
+ char name[SDE_HW_BLK_NAME_LEN]; \
u32 id; \
u32 base; \
u32 len
@@ -458,7 +462,6 @@ struct sde_ctl_cfg {
* @sblk: SSPP sub-blocks information
* @xin_id: bus client identifier
* @clk_ctrl clock control identifier
- * @name source pipe name
* @type sspp type identifier
*/
struct sde_sspp_cfg {
@@ -466,7 +469,6 @@ struct sde_sspp_cfg {
const struct sde_sspp_sub_blks *sblk;
u32 xin_id;
enum sde_clk_ctrl_type clk_ctrl;
- char name[SSPP_NAME_SIZE];
u32 type;
};
diff --git a/drivers/gpu/drm/msm/sde/sde_hw_cdm.c b/drivers/gpu/drm/msm/sde/sde_hw_cdm.c
index 9ec81c227e60..da04be4e9719 100644
--- a/drivers/gpu/drm/msm/sde/sde_hw_cdm.c
+++ b/drivers/gpu/drm/msm/sde/sde_hw_cdm.c
@@ -14,6 +14,7 @@
#include "sde_hwio.h"
#include "sde_hw_catalog.h"
#include "sde_hw_cdm.h"
+#include "sde_dbg.h"
#define CDM_CSC_10_OPMODE 0x000
#define CDM_CSC_10_BASE 0x004
@@ -295,6 +296,9 @@ struct sde_hw_cdm *sde_hw_cdm_init(enum sde_cdm idx,
*/
sde_hw_cdm_setup_csc_10bit(c, &rgb2yuv_cfg);
+ sde_dbg_reg_register_dump_range(SDE_DBG_NAME, cfg->name, c->hw.blk_off,
+ c->hw.blk_off + c->hw.length, c->hw.xin_id);
+
return c;
}
diff --git a/drivers/gpu/drm/msm/sde/sde_hw_ctl.c b/drivers/gpu/drm/msm/sde/sde_hw_ctl.c
index 56d9f2a4a9b8..270e79a774b2 100644
--- a/drivers/gpu/drm/msm/sde/sde_hw_ctl.c
+++ b/drivers/gpu/drm/msm/sde/sde_hw_ctl.c
@@ -13,6 +13,7 @@
#include <linux/delay.h>
#include "sde_hwio.h"
#include "sde_hw_ctl.h"
+#include "sde_dbg.h"
#define CTL_LAYER(lm) \
(((lm) == LM_5) ? (0x024) : (((lm) - LM_0) * 0x004))
@@ -39,6 +40,7 @@ static struct sde_ctl_cfg *_ctl_offset(enum sde_ctl ctl,
if (ctl == m->ctl[i].id) {
b->base_off = addr;
b->blk_off = m->ctl[i].base;
+ b->length = m->ctl[i].len;
b->hwversion = m->hwversion;
b->log_mask = SDE_DBG_MASK_CTL;
return &m->ctl[i];
@@ -92,6 +94,12 @@ static inline void sde_hw_ctl_trigger_flush(struct sde_hw_ctl *ctx)
SDE_REG_WRITE(&ctx->hw, CTL_FLUSH, ctx->pending_flush_mask);
}
+static inline u32 sde_hw_ctl_get_flush_register(struct sde_hw_ctl *ctx)
+{
+ struct sde_hw_blk_reg_map *c = &ctx->hw;
+
+ return SDE_REG_READ(c, CTL_FLUSH);
+}
static inline uint32_t sde_hw_ctl_get_bitmask_sspp(struct sde_hw_ctl *ctx,
enum sde_sspp sspp)
@@ -247,23 +255,58 @@ static inline int sde_hw_ctl_get_bitmask_cdm(struct sde_hw_ctl *ctx,
return 0;
}
+static u32 sde_hw_ctl_poll_reset_status(struct sde_hw_ctl *ctx, u32 count)
+{
+ struct sde_hw_blk_reg_map *c = &ctx->hw;
+ u32 status;
+
+ /* protect to do at least one iteration */
+ if (!count)
+ count = 1;
+
+ /*
+ * it takes around 30us to have mdp finish resetting its ctl path
+ * poll every 50us so that reset should be completed at 1st poll
+ */
+ do {
+ status = SDE_REG_READ(c, CTL_SW_RESET);
+ status &= 0x01;
+ if (status)
+ usleep_range(20, 50);
+ } while (status && --count > 0);
+
+ return status;
+}
+
static int sde_hw_ctl_reset_control(struct sde_hw_ctl *ctx)
{
struct sde_hw_blk_reg_map *c = &ctx->hw;
- int count = SDE_REG_RESET_TIMEOUT_COUNT;
- int reset;
+ pr_debug("issuing hw ctl reset for ctl:%d\n", ctx->idx);
SDE_REG_WRITE(c, CTL_SW_RESET, 0x1);
+ if (sde_hw_ctl_poll_reset_status(ctx, SDE_REG_RESET_TIMEOUT_COUNT))
+ return -EINVAL;
- for (; count > 0; count--) {
- /* insert small delay to avoid spinning the cpu while waiting */
- usleep_range(20, 50);
- reset = SDE_REG_READ(c, CTL_SW_RESET);
- if (reset == 0)
- return 0;
+ return 0;
+}
+
+static int sde_hw_ctl_wait_reset_status(struct sde_hw_ctl *ctx)
+{
+ struct sde_hw_blk_reg_map *c = &ctx->hw;
+ u32 status;
+
+ status = SDE_REG_READ(c, CTL_SW_RESET);
+ status &= 0x01;
+ if (!status)
+ return 0;
+
+ pr_debug("hw ctl reset is set for ctl:%d\n", ctx->idx);
+ if (sde_hw_ctl_poll_reset_status(ctx, SDE_REG_RESET_TIMEOUT_COUNT)) {
+ pr_err("hw recovery is not complete for ctl:%d\n", ctx->idx);
+ return -EINVAL;
}
- return -EINVAL;
+ return 0;
}
static void sde_hw_ctl_clear_all_blendstages(struct sde_hw_ctl *ctx)
@@ -415,9 +458,11 @@ static void _setup_ctl_ops(struct sde_hw_ctl_ops *ops,
ops->update_pending_flush = sde_hw_ctl_update_pending_flush;
ops->get_pending_flush = sde_hw_ctl_get_pending_flush;
ops->trigger_flush = sde_hw_ctl_trigger_flush;
+ ops->get_flush_register = sde_hw_ctl_get_flush_register;
ops->trigger_start = sde_hw_ctl_trigger_start;
ops->setup_intf_cfg = sde_hw_ctl_intf_cfg;
ops->reset = sde_hw_ctl_reset_control;
+ ops->wait_reset_status = sde_hw_ctl_wait_reset_status;
ops->clear_all_blendstages = sde_hw_ctl_clear_all_blendstages;
ops->setup_blendstage = sde_hw_ctl_setup_blendstage;
ops->get_bitmask_sspp = sde_hw_ctl_get_bitmask_sspp;
@@ -452,6 +497,9 @@ struct sde_hw_ctl *sde_hw_ctl_init(enum sde_ctl idx,
c->mixer_count = m->mixer_count;
c->mixer_hw_caps = m->mixer;
+ sde_dbg_reg_register_dump_range(SDE_DBG_NAME, cfg->name, c->hw.blk_off,
+ c->hw.blk_off + c->hw.length, c->hw.xin_id);
+
return c;
}
diff --git a/drivers/gpu/drm/msm/sde/sde_hw_ctl.h b/drivers/gpu/drm/msm/sde/sde_hw_ctl.h
index 2fb7b377e51d..74dbde92639a 100644
--- a/drivers/gpu/drm/msm/sde/sde_hw_ctl.h
+++ b/drivers/gpu/drm/msm/sde/sde_hw_ctl.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2015-2016, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2015-2017, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -94,6 +94,13 @@ struct sde_hw_ctl_ops {
void (*trigger_flush)(struct sde_hw_ctl *ctx);
/**
+ * Read the value of the flush register
+ * @ctx : ctl path ctx pointer
+ * @Return: value of the ctl flush register.
+ */
+ u32 (*get_flush_register)(struct sde_hw_ctl *ctx);
+
+ /**
* Setup ctl_path interface config
* @ctx
* @cfg : interface config structure pointer
@@ -103,6 +110,17 @@ struct sde_hw_ctl_ops {
int (*reset)(struct sde_hw_ctl *c);
+ /*
+ * wait_reset_status - checks ctl reset status
+ * @ctx : ctl path ctx pointer
+ *
+ * This function checks the ctl reset status bit.
+ * If the reset bit is set, it keeps polling the status till the hw
+ * reset is complete.
+ * Returns: 0 on success or -error if reset incomplete within interval
+ */
+ int (*wait_reset_status)(struct sde_hw_ctl *ctx);
+
uint32_t (*get_bitmask_sspp)(struct sde_hw_ctl *ctx,
enum sde_sspp blk);
diff --git a/drivers/gpu/drm/msm/sde/sde_hw_dspp.c b/drivers/gpu/drm/msm/sde/sde_hw_dspp.c
index d6250b07b4f0..2fd879a0030d 100644
--- a/drivers/gpu/drm/msm/sde/sde_hw_dspp.c
+++ b/drivers/gpu/drm/msm/sde/sde_hw_dspp.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2015-2016, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2015-2017, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -15,6 +15,7 @@
#include "sde_hw_catalog.h"
#include "sde_hw_dspp.h"
#include "sde_hw_color_processing.h"
+#include "sde_dbg.h"
static struct sde_dspp_cfg *_dspp_offset(enum sde_dspp dspp,
struct sde_mdss_cfg *m,
@@ -27,6 +28,7 @@ static struct sde_dspp_cfg *_dspp_offset(enum sde_dspp dspp,
if (dspp == m->dspp[i].id) {
b->base_off = addr;
b->blk_off = m->dspp[i].base;
+ b->length = m->dspp[i].len;
b->hwversion = m->hwversion;
b->log_mask = SDE_DBG_MASK_DSPP;
return &m->dspp[i];
@@ -111,6 +113,9 @@ struct sde_hw_dspp *sde_hw_dspp_init(enum sde_dspp idx,
c->cap = cfg;
_setup_dspp_ops(c, c->cap->features);
+ sde_dbg_reg_register_dump_range(SDE_DBG_NAME, cfg->name, c->hw.blk_off,
+ c->hw.blk_off + c->hw.length, c->hw.xin_id);
+
return c;
}
diff --git a/drivers/gpu/drm/msm/sde/sde_hw_intf.c b/drivers/gpu/drm/msm/sde/sde_hw_intf.c
index 042b0ee7909a..9e1b97800cb9 100644
--- a/drivers/gpu/drm/msm/sde/sde_hw_intf.c
+++ b/drivers/gpu/drm/msm/sde/sde_hw_intf.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2015-2016, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2015-2017, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -13,6 +13,7 @@
#include "sde_hwio.h"
#include "sde_hw_catalog.h"
#include "sde_hw_intf.h"
+#include "sde_dbg.h"
#define INTF_TIMING_ENGINE_EN 0x000
#define INTF_CONFIG 0x004
@@ -83,6 +84,7 @@ static struct sde_intf_cfg *_intf_offset(enum sde_intf intf,
(m->intf[i].type != INTF_NONE)) {
b->base_off = addr;
b->blk_off = m->intf[i].base;
+ b->length = m->intf[i].len;
b->hwversion = m->hwversion;
b->log_mask = SDE_DBG_MASK_INTF;
return &m->intf[i];
@@ -324,9 +326,9 @@ struct sde_hw_intf *sde_hw_intf_init(enum sde_intf idx,
c->mdss = m;
_setup_intf_ops(&c->ops, c->cap->features);
- /*
- * Perform any default initialization for the intf
- */
+ sde_dbg_reg_register_dump_range(SDE_DBG_NAME, cfg->name, c->hw.blk_off,
+ c->hw.blk_off + c->hw.length, c->hw.xin_id);
+
return c;
}
diff --git a/drivers/gpu/drm/msm/sde/sde_hw_lm.c b/drivers/gpu/drm/msm/sde/sde_hw_lm.c
index 365b9b17715d..8b4e0901458f 100644
--- a/drivers/gpu/drm/msm/sde/sde_hw_lm.c
+++ b/drivers/gpu/drm/msm/sde/sde_hw_lm.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2015-2016, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2015-2017, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -14,6 +14,7 @@
#include "sde_hwio.h"
#include "sde_hw_lm.h"
#include "sde_hw_mdss.h"
+#include "sde_dbg.h"
#define LM_OP_MODE 0x00
#define LM_OUT_SIZE 0x04
@@ -37,6 +38,7 @@ static struct sde_lm_cfg *_lm_offset(enum sde_lm mixer,
if (mixer == m->mixer[i].id) {
b->base_off = addr;
b->blk_off = m->mixer[i].base;
+ b->length = m->mixer[i].len;
b->hwversion = m->hwversion;
b->log_mask = SDE_DBG_MASK_LM;
return &m->mixer[i];
@@ -195,9 +197,9 @@ struct sde_hw_mixer *sde_hw_lm_init(enum sde_lm idx,
c->cap = cfg;
_setup_mixer_ops(m, &c->ops, c->cap->features);
- /*
- * Perform any default initialization for the sspp blocks
- */
+ sde_dbg_reg_register_dump_range(SDE_DBG_NAME, cfg->name, c->hw.blk_off,
+ c->hw.blk_off + c->hw.length, c->hw.xin_id);
+
return c;
}
diff --git a/drivers/gpu/drm/msm/sde/sde_hw_mdss.h b/drivers/gpu/drm/msm/sde/sde_hw_mdss.h
index 92dd829eee3e..3d63d01a6d4e 100644
--- a/drivers/gpu/drm/msm/sde/sde_hw_mdss.h
+++ b/drivers/gpu/drm/msm/sde/sde_hw_mdss.h
@@ -18,6 +18,8 @@
#include "msm_drv.h"
+#define SDE_DBG_NAME "sde"
+
#define SDE_NONE 0
#ifndef SDE_CSC_MATRIX_COEFF_SIZE
diff --git a/drivers/gpu/drm/msm/sde/sde_hw_pingpong.c b/drivers/gpu/drm/msm/sde/sde_hw_pingpong.c
index 837edeeba4c6..8488d03af79a 100644
--- a/drivers/gpu/drm/msm/sde/sde_hw_pingpong.c
+++ b/drivers/gpu/drm/msm/sde/sde_hw_pingpong.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2015-2016, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2015-2017, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -14,6 +14,7 @@
#include "sde_hwio.h"
#include "sde_hw_catalog.h"
#include "sde_hw_pingpong.h"
+#include "sde_dbg.h"
#define PP_TEAR_CHECK_EN 0x000
#define PP_SYNC_CONFIG_VSYNC 0x004
@@ -47,6 +48,7 @@ static struct sde_pingpong_cfg *_pingpong_offset(enum sde_pingpong pp,
if (pp == m->pingpong[i].id) {
b->base_off = addr;
b->blk_off = m->pingpong[i].base;
+ b->length = m->pingpong[i].len;
b->hwversion = m->hwversion;
b->log_mask = SDE_DBG_MASK_PINGPONG;
return &m->pingpong[i];
@@ -159,6 +161,9 @@ struct sde_hw_pingpong *sde_hw_pingpong_init(enum sde_pingpong idx,
c->pingpong_hw_cap = cfg;
_setup_pingpong_ops(&c->ops, c->pingpong_hw_cap->features);
+ sde_dbg_reg_register_dump_range(SDE_DBG_NAME, cfg->name, c->hw.blk_off,
+ c->hw.blk_off + c->hw.length, c->hw.xin_id);
+
return c;
}
diff --git a/drivers/gpu/drm/msm/sde/sde_hw_sspp.c b/drivers/gpu/drm/msm/sde/sde_hw_sspp.c
index ea2890d776ae..be620aebf850 100644
--- a/drivers/gpu/drm/msm/sde/sde_hw_sspp.c
+++ b/drivers/gpu/drm/msm/sde/sde_hw_sspp.c
@@ -15,6 +15,7 @@
#include "sde_hw_lm.h"
#include "sde_hw_sspp.h"
#include "sde_hw_color_processing.h"
+#include "sde_dbg.h"
#define SDE_FETCH_CONFIG_RESET_VALUE 0x00000087
@@ -903,6 +904,7 @@ static struct sde_sspp_cfg *_sspp_offset(enum sde_sspp sspp,
if (sspp == catalog->sspp[i].id) {
b->base_off = addr;
b->blk_off = catalog->sspp[i].base;
+ b->length = catalog->sspp[i].len;
b->hwversion = catalog->hwversion;
b->log_mask = SDE_DBG_MASK_SSPP;
return &catalog->sspp[i];
@@ -917,26 +919,39 @@ struct sde_hw_pipe *sde_hw_sspp_init(enum sde_sspp idx,
void __iomem *addr,
struct sde_mdss_cfg *catalog)
{
- struct sde_hw_pipe *ctx;
+ struct sde_hw_pipe *hw_pipe;
struct sde_sspp_cfg *cfg;
- ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
- if (!ctx)
+ hw_pipe = kzalloc(sizeof(*hw_pipe), GFP_KERNEL);
+ if (!hw_pipe)
return ERR_PTR(-ENOMEM);
- cfg = _sspp_offset(idx, addr, catalog, &ctx->hw);
+ cfg = _sspp_offset(idx, addr, catalog, &hw_pipe->hw);
if (IS_ERR_OR_NULL(cfg)) {
- kfree(ctx);
+ kfree(hw_pipe);
return ERR_PTR(-EINVAL);
}
/* Assign ops */
- ctx->idx = idx;
- ctx->cap = cfg;
- _setup_layer_ops(ctx, ctx->cap->features);
- ctx->highest_bank_bit = catalog->mdp[0].highest_bank_bit;
-
- return ctx;
+ hw_pipe->idx = idx;
+ hw_pipe->cap = cfg;
+ _setup_layer_ops(hw_pipe, hw_pipe->cap->features);
+ hw_pipe->highest_bank_bit = catalog->mdp[0].highest_bank_bit;
+
+ sde_dbg_reg_register_dump_range(SDE_DBG_NAME, cfg->name,
+ hw_pipe->hw.blk_off,
+ hw_pipe->hw.blk_off + hw_pipe->hw.length,
+ hw_pipe->hw.xin_id);
+
+ if (cfg->sblk->scaler_blk.len)
+ sde_dbg_reg_register_dump_range(SDE_DBG_NAME,
+ cfg->sblk->scaler_blk.name,
+ hw_pipe->hw.blk_off + cfg->sblk->scaler_blk.base,
+ hw_pipe->hw.blk_off + cfg->sblk->scaler_blk.base +
+ cfg->sblk->scaler_blk.len,
+ hw_pipe->hw.xin_id);
+
+ return hw_pipe;
}
void sde_hw_sspp_destroy(struct sde_hw_pipe *ctx)
diff --git a/drivers/gpu/drm/msm/sde/sde_hw_top.c b/drivers/gpu/drm/msm/sde/sde_hw_top.c
index d6d2e41ff5aa..218797e623a2 100644
--- a/drivers/gpu/drm/msm/sde/sde_hw_top.c
+++ b/drivers/gpu/drm/msm/sde/sde_hw_top.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2015-2016, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2015-2017, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -13,6 +13,7 @@
#include "sde_hwio.h"
#include "sde_hw_catalog.h"
#include "sde_hw_top.h"
+#include "sde_dbg.h"
#define SSPP_SPARE 0x28
@@ -225,6 +226,7 @@ static const struct sde_mdp_cfg *_top_offset(enum sde_mdp mdp,
if (mdp == m->mdp[i].id) {
b->base_off = addr;
b->blk_off = m->mdp[i].base;
+ b->length = m->mdp[i].len;
b->hwversion = m->hwversion;
b->log_mask = SDE_DBG_MASK_TOP;
return &m->mdp[i];
@@ -258,9 +260,10 @@ struct sde_hw_mdp *sde_hw_mdptop_init(enum sde_mdp idx,
mdp->cap = cfg;
_setup_mdp_ops(&mdp->ops, mdp->cap->features);
- /*
- * Perform any default initialization for the intf
- */
+ sde_dbg_reg_register_dump_range(SDE_DBG_NAME, cfg->name,
+ mdp->hw.blk_off, mdp->hw.blk_off + mdp->hw.length,
+ mdp->hw.xin_id);
+ sde_dbg_set_sde_top_offset(mdp->hw.blk_off);
return mdp;
}
diff --git a/drivers/gpu/drm/msm/sde/sde_hw_util.h b/drivers/gpu/drm/msm/sde/sde_hw_util.h
index c38c22237a57..008b657966b6 100644
--- a/drivers/gpu/drm/msm/sde/sde_hw_util.h
+++ b/drivers/gpu/drm/msm/sde/sde_hw_util.h
@@ -24,12 +24,14 @@
* @base_off: mdp register mapped offset
* @blk_off: pipe offset relative to mdss offset
* @length length of register block offset
+ * @xin_id xin id
* @hwversion mdss hw version number
*/
struct sde_hw_blk_reg_map {
void __iomem *base_off;
u32 blk_off;
u32 length;
+ u32 xin_id;
u32 hwversion;
u32 log_mask;
};
diff --git a/drivers/gpu/drm/msm/sde/sde_hw_vbif.c b/drivers/gpu/drm/msm/sde/sde_hw_vbif.c
index 76473fa879c5..048ec47d7c72 100644
--- a/drivers/gpu/drm/msm/sde/sde_hw_vbif.c
+++ b/drivers/gpu/drm/msm/sde/sde_hw_vbif.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2015-2016, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2015-2017, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -13,6 +13,7 @@
#include "sde_hwio.h"
#include "sde_hw_catalog.h"
#include "sde_hw_vbif.h"
+#include "sde_dbg.h"
#define VBIF_VERSION 0x0000
#define VBIF_CLK_FORCE_CTRL0 0x0008
@@ -123,6 +124,7 @@ static const struct sde_vbif_cfg *_top_offset(enum sde_vbif vbif,
if (vbif == m->vbif[i].id) {
b->base_off = addr;
b->blk_off = m->vbif[i].base;
+ b->length = m->vbif[i].len;
b->hwversion = m->hwversion;
b->log_mask = SDE_DBG_MASK_VBIF;
return &m->vbif[i];
@@ -156,6 +158,8 @@ struct sde_hw_vbif *sde_hw_vbif_init(enum sde_vbif idx,
c->cap = cfg;
_setup_vbif_ops(&c->ops, c->cap->features);
+ /* no need to register sub-range in sde dbg, dump entire vbif io base */
+
return c;
}
diff --git a/drivers/gpu/drm/msm/sde/sde_hw_wb.c b/drivers/gpu/drm/msm/sde/sde_hw_wb.c
index 426e9991a6b5..320b05f67669 100644
--- a/drivers/gpu/drm/msm/sde/sde_hw_wb.c
+++ b/drivers/gpu/drm/msm/sde/sde_hw_wb.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2015-2016, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2015-2017, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -15,6 +15,7 @@
#include "sde_hw_catalog.h"
#include "sde_hw_wb.h"
#include "sde_formats.h"
+#include "sde_dbg.h"
#define WB_DST_FORMAT 0x000
#define WB_DST_OP_MODE 0x004
@@ -57,6 +58,7 @@ static struct sde_wb_cfg *_wb_offset(enum sde_wb wb,
if (wb == m->wb[i].id) {
b->base_off = addr;
b->blk_off = m->wb[i].base;
+ b->length = m->wb[i].len;
b->hwversion = m->hwversion;
b->log_mask = SDE_DBG_MASK_WB;
return &m->wb[i];
@@ -215,6 +217,9 @@ struct sde_hw_wb *sde_hw_wb_init(enum sde_wb idx,
c->highest_bank_bit = m->mdp[0].highest_bank_bit;
c->hw_mdp = hw_mdp;
+ sde_dbg_reg_register_dump_range(SDE_DBG_NAME, cfg->name, c->hw.blk_off,
+ c->hw.blk_off + c->hw.length, c->hw.xin_id);
+
return c;
}
diff --git a/drivers/gpu/drm/msm/sde/sde_kms.c b/drivers/gpu/drm/msm/sde/sde_kms.c
index cdf67c0aa864..8d821e43afa5 100644
--- a/drivers/gpu/drm/msm/sde/sde_kms.c
+++ b/drivers/gpu/drm/msm/sde/sde_kms.c
@@ -69,7 +69,7 @@
*
* This is disabled by default.
*/
-static bool sdecustom = true;
+static bool sdecustom;
module_param(sdecustom, bool, 0400);
MODULE_PARM_DESC(sdecustom, "Enable customizations for sde clients");
@@ -1167,6 +1167,44 @@ fail:
return ret;
}
+static void __iomem *_sde_kms_ioremap(struct platform_device *pdev,
+ const char *name, unsigned long *out_size)
+{
+ struct resource *res;
+ unsigned long size;
+ void __iomem *ptr;
+
+ if (out_size)
+ *out_size = 0;
+
+ if (name)
+ res = platform_get_resource_byname(pdev, IORESOURCE_MEM, name);
+ else
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+
+ if (!res) {
+ /* availability depends on platform */
+ SDE_DEBUG("failed to get memory resource: %s\n", name);
+ return NULL;
+ }
+
+ size = resource_size(res);
+
+ ptr = devm_ioremap_nocache(&pdev->dev, res->start, size);
+ if (!ptr) {
+ SDE_ERROR("failed to ioremap: %s\n", name);
+ return NULL;
+ }
+
+ SDE_DEBUG("IO:region %s %pK %08lx\n", name, ptr, size);
+
+ if (out_size)
+ *out_size = size;
+
+ return ptr;
+}
+
+
static int sde_kms_hw_init(struct msm_kms *kms)
{
struct sde_kms *sde_kms;
@@ -1193,29 +1231,42 @@ static int sde_kms_hw_init(struct msm_kms *kms)
goto end;
}
- sde_kms->mmio = msm_ioremap(dev->platformdev, "mdp_phys", "SDE");
- if (IS_ERR(sde_kms->mmio)) {
- rc = PTR_ERR(sde_kms->mmio);
- SDE_ERROR("mdp register memory map failed: %d\n", rc);
- sde_kms->mmio = NULL;
+ sde_kms->mmio = _sde_kms_ioremap(dev->platformdev, "mdp_phys",
+ &sde_kms->mmio_len);
+ if (!sde_kms->mmio) {
+ SDE_ERROR("mdp register memory map failed\n");
goto error;
}
DRM_INFO("mapped mdp address space @%p\n", sde_kms->mmio);
- sde_kms->vbif[VBIF_RT] = msm_ioremap(dev->platformdev,
- "vbif_phys", "VBIF");
- if (IS_ERR(sde_kms->vbif[VBIF_RT])) {
- rc = PTR_ERR(sde_kms->vbif[VBIF_RT]);
- SDE_ERROR("vbif register memory map failed: %d\n", rc);
- sde_kms->vbif[VBIF_RT] = NULL;
+ rc = sde_dbg_reg_register_base(SDE_DBG_NAME, sde_kms->mmio,
+ sde_kms->mmio_len);
+ if (rc)
+ SDE_ERROR("dbg base register kms failed: %d\n", rc);
+
+ sde_kms->vbif[VBIF_RT] = _sde_kms_ioremap(dev->platformdev, "vbif_phys",
+ &sde_kms->vbif_len[VBIF_RT]);
+ if (!sde_kms->vbif[VBIF_RT]) {
+ SDE_ERROR("vbif register memory map failed\n");
goto error;
}
- sde_kms->vbif[VBIF_NRT] = msm_ioremap(dev->platformdev,
- "vbif_nrt_phys", "VBIF_NRT");
- if (IS_ERR(sde_kms->vbif[VBIF_NRT])) {
- sde_kms->vbif[VBIF_NRT] = NULL;
+ rc = sde_dbg_reg_register_base("vbif_rt", sde_kms->vbif[VBIF_RT],
+ sde_kms->vbif_len[VBIF_RT]);
+ if (rc)
+ SDE_ERROR("dbg base register vbif_rt failed: %d\n", rc);
+
+ sde_kms->vbif[VBIF_NRT] = _sde_kms_ioremap(dev->platformdev,
+ "vbif_nrt_phys", &sde_kms->vbif_len[VBIF_NRT]);
+ if (!sde_kms->vbif[VBIF_NRT]) {
SDE_DEBUG("VBIF NRT is not defined");
+ } else {
+ rc = sde_dbg_reg_register_base("vbif_nrt",
+ sde_kms->vbif[VBIF_NRT],
+ sde_kms->vbif_len[VBIF_NRT]);
+ if (rc)
+ SDE_ERROR("dbg base register vbif_nrt failed: %d\n",
+ rc);
}
sde_kms->core_client = sde_power_client_create(&priv->phandle, "core");
@@ -1245,6 +1296,8 @@ static int sde_kms_hw_init(struct msm_kms *kms)
goto power_error;
}
+ sde_dbg_init_dbg_buses(sde_kms->core_rev);
+
rc = sde_rm_init(&sde_kms->rm, sde_kms->catalog, sde_kms->mmio,
sde_kms->dev);
if (rc) {
diff --git a/drivers/gpu/drm/msm/sde/sde_kms.h b/drivers/gpu/drm/msm/sde/sde_kms.h
index d929e48a3fe8..dee16d119d47 100644
--- a/drivers/gpu/drm/msm/sde/sde_kms.h
+++ b/drivers/gpu/drm/msm/sde/sde_kms.h
@@ -134,6 +134,7 @@ struct sde_kms {
/* io/register spaces: */
void __iomem *mmio, *vbif[VBIF_MAX];
+ unsigned long mmio_len, vbif_len[VBIF_MAX];
struct regulator *vdd;
struct regulator *mmagic;
@@ -281,10 +282,12 @@ struct sde_kms_info {
/**
* SDE_KMS_INFO_DATALEN - Macro for accessing sde_kms_info data length
+ * it adds an extra character length to count null.
* @S: Pointer to sde_kms_info structure
* Returns: Size of available byte data
*/
-#define SDE_KMS_INFO_DATALEN(S) ((S) ? ((struct sde_kms_info *)(S))->len : 0)
+#define SDE_KMS_INFO_DATALEN(S) ((S) ? ((struct sde_kms_info *)(S))->len + 1 \
+ : 0)
/**
* sde_kms_info_reset - reset sde_kms_info structure
@@ -368,6 +371,49 @@ void sde_kms_info_append_format(struct sde_kms_info *info,
void sde_kms_info_stop(struct sde_kms_info *info);
/**
+ * sde_kms_rect_intersect - intersect two rectangles
+ * @r1: first rectangle
+ * @r2: scissor rectangle
+ * @result: result rectangle, all 0's on no intersection found
+ */
+void sde_kms_rect_intersect(const struct sde_rect *r1,
+ const struct sde_rect *r2,
+ struct sde_rect *result);
+
+/**
+ * sde_kms_rect_is_equal - compares two rects
+ * @r1: rect value to compare
+ * @r2: rect value to compare
+ *
+ * Returns 1 if the rects are same, 0 otherwise.
+ */
+static inline bool sde_kms_rect_is_equal(struct sde_rect *r1,
+ struct sde_rect *r2)
+{
+ if ((!r1 && r2) || (r1 && !r2))
+ return false;
+
+ if (!r1 && !r2)
+ return true;
+
+ return r1->x == r2->x && r1->y == r2->y && r1->w == r2->w &&
+ r1->h == r2->h;
+}
+
+/**
+ * sde_kms_rect_is_null - returns true if the width or height of a rect is 0
+ * @rect: rectangle to check for zero size
+ * @Return: True if width or height of rectangle is 0
+ */
+static inline bool sde_kms_rect_is_null(const struct sde_rect *r)
+{
+ if (!r)
+ return true;
+
+ return (!r->w || !r->h);
+}
+
+/**
* Vblank enable/disable functions
*/
int sde_enable_vblank(struct msm_kms *kms, struct drm_crtc *crtc);
diff --git a/drivers/gpu/drm/msm/sde/sde_kms_utils.c b/drivers/gpu/drm/msm/sde/sde_kms_utils.c
index 6e29c09deb40..30e12c969538 100644
--- a/drivers/gpu/drm/msm/sde/sde_kms_utils.c
+++ b/drivers/gpu/drm/msm/sde/sde_kms_utils.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2015-2016, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2015-2017, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -151,3 +151,27 @@ void sde_kms_info_stop(struct sde_kms_info *info)
info->len = info->staged_len + len;
}
}
+
+void sde_kms_rect_intersect(const struct sde_rect *r1,
+ const struct sde_rect *r2,
+ struct sde_rect *result)
+{
+ int l, t, r, b;
+
+ if (!r1 || !r2 || !result)
+ return;
+
+ l = max(r1->x, r2->x);
+ t = max(r1->y, r2->y);
+ r = min((r1->x + r1->w), (r2->x + r2->w));
+ b = min((r1->y + r1->h), (r2->y + r2->h));
+
+ if (r < l || b < t) {
+ memset(result, 0, sizeof(*result));
+ } else {
+ result->x = l;
+ result->y = t;
+ result->w = r - l;
+ result->h = b - t;
+ }
+}
diff --git a/drivers/gpu/drm/msm/sde_dbg.c b/drivers/gpu/drm/msm/sde_dbg.c
new file mode 100644
index 000000000000..b87bc75f17ea
--- /dev/null
+++ b/drivers/gpu/drm/msm/sde_dbg.c
@@ -0,0 +1,2070 @@
+/* Copyright (c) 2009-2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#define pr_fmt(fmt) "[drm:%s:%d] " fmt, __func__, __LINE__
+
+#include <linux/delay.h>
+#include <linux/spinlock.h>
+#include <linux/ktime.h>
+#include <linux/debugfs.h>
+#include <linux/uaccess.h>
+#include <linux/dma-buf.h>
+#include <linux/slab.h>
+#include <linux/list_sort.h>
+
+#include "sde_dbg.h"
+#include "sde/sde_hw_catalog.h"
+
+#define SDE_DBG_BASE_MAX 10
+
+#define DEFAULT_PANIC 1
+#define DEFAULT_REGDUMP SDE_DBG_DUMP_IN_MEM
+#define DEFAULT_DBGBUS_SDE SDE_DBG_DUMP_IN_MEM
+#define DEFAULT_DBGBUS_VBIFRT SDE_DBG_DUMP_IN_MEM
+#define DEFAULT_BASE_REG_CNT 0x100
+#define GROUP_BYTES 4
+#define ROW_BYTES 16
+#define RANGE_NAME_LEN 40
+#define REG_BASE_NAME_LEN 80
+
+#define DBGBUS_FLAGS_DSPP BIT(0)
+#define DBGBUS_DSPP_STATUS 0x34C
+
+#define DBGBUS_NAME_SDE "sde"
+#define DBGBUS_NAME_VBIF_RT "vbif_rt"
+
+/* offsets from sde top address for the debug buses */
+#define DBGBUS_SSPP0 0x188
+#define DBGBUS_SSPP1 0x298
+#define DBGBUS_DSPP 0x348
+#define DBGBUS_PERIPH 0x418
+
+#define TEST_MASK(id, tp) ((id << 4) | (tp << 1) | BIT(0))
+
+/* following offsets are with respect to MDP VBIF base for DBG BUS access */
+#define MMSS_VBIF_CLKON 0x4
+#define MMSS_VBIF_TEST_BUS_OUT_CTRL 0x210
+#define MMSS_VBIF_TEST_BUS_OUT 0x230
+
+/* print debug ranges in groups of 4 u32s */
+#define REG_DUMP_ALIGN 16
+
+/**
+ * struct sde_dbg_reg_offset - tracking for start and end of region
+ * @start: start offset
+ * @start: end offset
+ */
+struct sde_dbg_reg_offset {
+ u32 start;
+ u32 end;
+};
+
+/**
+ * struct sde_dbg_reg_range - register dumping named sub-range
+ * @head: head of this node
+ * @reg_dump: address for the mem dump
+ * @range_name: name of this range
+ * @offset: offsets for range to dump
+ * @xin_id: client xin id
+ */
+struct sde_dbg_reg_range {
+ struct list_head head;
+ u32 *reg_dump;
+ char range_name[RANGE_NAME_LEN];
+ struct sde_dbg_reg_offset offset;
+ uint32_t xin_id;
+};
+
+/**
+ * struct sde_dbg_reg_base - register region base.
+ * may sub-ranges: sub-ranges are used for dumping
+ * or may not have sub-ranges: dumping is base -> max_offset
+ * @reg_base_head: head of this node
+ * @sub_range_list: head to the list with dump ranges
+ * @name: register base name
+ * @base: base pointer
+ * @off: cached offset of region for manual register dumping
+ * @cnt: cached range of region for manual register dumping
+ * @max_offset: length of region
+ * @buf: buffer used for manual register dumping
+ * @buf_len: buffer length used for manual register dumping
+ * @reg_dump: address for the mem dump if no ranges used
+ */
+struct sde_dbg_reg_base {
+ struct list_head reg_base_head;
+ struct list_head sub_range_list;
+ char name[REG_BASE_NAME_LEN];
+ void __iomem *base;
+ size_t off;
+ size_t cnt;
+ size_t max_offset;
+ char *buf;
+ size_t buf_len;
+ u32 *reg_dump;
+};
+
+struct sde_debug_bus_entry {
+ u32 wr_addr;
+ u32 block_id;
+ u32 test_id;
+};
+
+struct vbif_debug_bus_entry {
+ u32 disable_bus_addr;
+ u32 block_bus_addr;
+ u32 bit_offset;
+ u32 block_cnt;
+ u32 test_pnt_start;
+ u32 test_pnt_cnt;
+};
+
+struct sde_dbg_debug_bus_common {
+ char *name;
+ u32 enable_mask;
+ bool include_in_deferred_work;
+ u32 flags;
+ u32 entries_size;
+ u32 *dumped_content;
+};
+
+struct sde_dbg_sde_debug_bus {
+ struct sde_dbg_debug_bus_common cmn;
+ struct sde_debug_bus_entry *entries;
+ u32 top_blk_off;
+};
+
+struct sde_dbg_vbif_debug_bus {
+ struct sde_dbg_debug_bus_common cmn;
+ struct vbif_debug_bus_entry *entries;
+};
+
+/**
+ * struct sde_dbg_base - global sde debug base structure
+ * @evtlog: event log instance
+ * @reg_base_list: list of register dumping regions
+ * @root: base debugfs root
+ * @dev: device pointer
+ * @power_ctrl: callback structure for enabling power for reading hw registers
+ * @req_dump_blks: list of blocks requested for dumping
+ * @panic_on_err: whether to kernel panic after triggering dump via debugfs
+ * @dump_work: work struct for deferring register dump work to separate thread
+ * @work_panic: panic after dump if internal user passed "panic" special region
+ * @enable_reg_dump: whether to dump registers into memory, kernel log, or both
+ * @dbgbus_sde: debug bus structure for the sde
+ * @dbgbus_vbif_rt: debug bus structure for the realtime vbif
+ */
+static struct sde_dbg_base {
+ struct sde_dbg_evtlog *evtlog;
+ struct list_head reg_base_list;
+ struct dentry *root;
+ struct device *dev;
+ struct sde_dbg_power_ctrl power_ctrl;
+
+ struct sde_dbg_reg_base *req_dump_blks[SDE_DBG_BASE_MAX];
+
+ u32 panic_on_err;
+ struct work_struct dump_work;
+ bool work_panic;
+ u32 enable_reg_dump;
+
+ struct sde_dbg_sde_debug_bus dbgbus_sde;
+ struct sde_dbg_vbif_debug_bus dbgbus_vbif_rt;
+} sde_dbg_base;
+
+/* sde_dbg_base_evtlog - global pointer to main sde event log for macro use */
+struct sde_dbg_evtlog *sde_dbg_base_evtlog;
+
+static struct sde_debug_bus_entry dbg_bus_sde_8998[] = {
+
+ /* Unpack 0 sspp 0*/
+ { DBGBUS_SSPP0, 50, 2 },
+ { DBGBUS_SSPP0, 60, 2 },
+ { DBGBUS_SSPP0, 70, 2 },
+ { DBGBUS_SSPP0, 85, 2 },
+
+ /* Upack 0 sspp 1*/
+ { DBGBUS_SSPP1, 50, 2 },
+ { DBGBUS_SSPP1, 60, 2 },
+ { DBGBUS_SSPP1, 70, 2 },
+ { DBGBUS_SSPP1, 85, 2 },
+
+ /* scheduler */
+ { DBGBUS_DSPP, 130, 0 },
+ { DBGBUS_DSPP, 130, 1 },
+ { DBGBUS_DSPP, 130, 2 },
+ { DBGBUS_DSPP, 130, 3 },
+ { DBGBUS_DSPP, 130, 4 },
+ { DBGBUS_DSPP, 130, 5 },
+
+ /* qseed */
+ { DBGBUS_SSPP0, 6, 0},
+ { DBGBUS_SSPP0, 6, 1},
+ { DBGBUS_SSPP0, 26, 0},
+ { DBGBUS_SSPP0, 26, 1},
+ { DBGBUS_SSPP1, 6, 0},
+ { DBGBUS_SSPP1, 6, 1},
+ { DBGBUS_SSPP1, 26, 0},
+ { DBGBUS_SSPP1, 26, 1},
+
+ /* scale */
+ { DBGBUS_SSPP0, 16, 0},
+ { DBGBUS_SSPP0, 16, 1},
+ { DBGBUS_SSPP0, 36, 0},
+ { DBGBUS_SSPP0, 36, 1},
+ { DBGBUS_SSPP1, 16, 0},
+ { DBGBUS_SSPP1, 16, 1},
+ { DBGBUS_SSPP1, 36, 0},
+ { DBGBUS_SSPP1, 36, 1},
+
+ /* fetch sspp0 */
+
+ /* vig 0 */
+ { DBGBUS_SSPP0, 0, 0 },
+ { DBGBUS_SSPP0, 0, 1 },
+ { DBGBUS_SSPP0, 0, 2 },
+ { DBGBUS_SSPP0, 0, 3 },
+ { DBGBUS_SSPP0, 0, 4 },
+ { DBGBUS_SSPP0, 0, 5 },
+ { DBGBUS_SSPP0, 0, 6 },
+ { DBGBUS_SSPP0, 0, 7 },
+
+ { DBGBUS_SSPP0, 1, 0 },
+ { DBGBUS_SSPP0, 1, 1 },
+ { DBGBUS_SSPP0, 1, 2 },
+ { DBGBUS_SSPP0, 1, 3 },
+ { DBGBUS_SSPP0, 1, 4 },
+ { DBGBUS_SSPP0, 1, 5 },
+ { DBGBUS_SSPP0, 1, 6 },
+ { DBGBUS_SSPP0, 1, 7 },
+
+ { DBGBUS_SSPP0, 2, 0 },
+ { DBGBUS_SSPP0, 2, 1 },
+ { DBGBUS_SSPP0, 2, 2 },
+ { DBGBUS_SSPP0, 2, 3 },
+ { DBGBUS_SSPP0, 2, 4 },
+ { DBGBUS_SSPP0, 2, 5 },
+ { DBGBUS_SSPP0, 2, 6 },
+ { DBGBUS_SSPP0, 2, 7 },
+
+ { DBGBUS_SSPP0, 4, 0 },
+ { DBGBUS_SSPP0, 4, 1 },
+ { DBGBUS_SSPP0, 4, 2 },
+ { DBGBUS_SSPP0, 4, 3 },
+ { DBGBUS_SSPP0, 4, 4 },
+ { DBGBUS_SSPP0, 4, 5 },
+ { DBGBUS_SSPP0, 4, 6 },
+ { DBGBUS_SSPP0, 4, 7 },
+
+ { DBGBUS_SSPP0, 5, 0 },
+ { DBGBUS_SSPP0, 5, 1 },
+ { DBGBUS_SSPP0, 5, 2 },
+ { DBGBUS_SSPP0, 5, 3 },
+ { DBGBUS_SSPP0, 5, 4 },
+ { DBGBUS_SSPP0, 5, 5 },
+ { DBGBUS_SSPP0, 5, 6 },
+ { DBGBUS_SSPP0, 5, 7 },
+
+ /* vig 2 */
+ { DBGBUS_SSPP0, 20, 0 },
+ { DBGBUS_SSPP0, 20, 1 },
+ { DBGBUS_SSPP0, 20, 2 },
+ { DBGBUS_SSPP0, 20, 3 },
+ { DBGBUS_SSPP0, 20, 4 },
+ { DBGBUS_SSPP0, 20, 5 },
+ { DBGBUS_SSPP0, 20, 6 },
+ { DBGBUS_SSPP0, 20, 7 },
+
+ { DBGBUS_SSPP0, 21, 0 },
+ { DBGBUS_SSPP0, 21, 1 },
+ { DBGBUS_SSPP0, 21, 2 },
+ { DBGBUS_SSPP0, 21, 3 },
+ { DBGBUS_SSPP0, 21, 4 },
+ { DBGBUS_SSPP0, 21, 5 },
+ { DBGBUS_SSPP0, 21, 6 },
+ { DBGBUS_SSPP0, 21, 7 },
+
+ { DBGBUS_SSPP0, 22, 0 },
+ { DBGBUS_SSPP0, 22, 1 },
+ { DBGBUS_SSPP0, 22, 2 },
+ { DBGBUS_SSPP0, 22, 3 },
+ { DBGBUS_SSPP0, 22, 4 },
+ { DBGBUS_SSPP0, 22, 5 },
+ { DBGBUS_SSPP0, 22, 6 },
+ { DBGBUS_SSPP0, 22, 7 },
+
+ { DBGBUS_SSPP0, 24, 0 },
+ { DBGBUS_SSPP0, 24, 1 },
+ { DBGBUS_SSPP0, 24, 2 },
+ { DBGBUS_SSPP0, 24, 3 },
+ { DBGBUS_SSPP0, 24, 4 },
+ { DBGBUS_SSPP0, 24, 5 },
+ { DBGBUS_SSPP0, 24, 6 },
+ { DBGBUS_SSPP0, 24, 7 },
+
+ { DBGBUS_SSPP0, 25, 0 },
+ { DBGBUS_SSPP0, 25, 1 },
+ { DBGBUS_SSPP0, 25, 2 },
+ { DBGBUS_SSPP0, 25, 3 },
+ { DBGBUS_SSPP0, 25, 4 },
+ { DBGBUS_SSPP0, 25, 5 },
+ { DBGBUS_SSPP0, 25, 6 },
+ { DBGBUS_SSPP0, 25, 7 },
+
+ /* dma 2 */
+ { DBGBUS_SSPP0, 30, 0 },
+ { DBGBUS_SSPP0, 30, 1 },
+ { DBGBUS_SSPP0, 30, 2 },
+ { DBGBUS_SSPP0, 30, 3 },
+ { DBGBUS_SSPP0, 30, 4 },
+ { DBGBUS_SSPP0, 30, 5 },
+ { DBGBUS_SSPP0, 30, 6 },
+ { DBGBUS_SSPP0, 30, 7 },
+
+ { DBGBUS_SSPP0, 31, 0 },
+ { DBGBUS_SSPP0, 31, 1 },
+ { DBGBUS_SSPP0, 31, 2 },
+ { DBGBUS_SSPP0, 31, 3 },
+ { DBGBUS_SSPP0, 31, 4 },
+ { DBGBUS_SSPP0, 31, 5 },
+ { DBGBUS_SSPP0, 31, 6 },
+ { DBGBUS_SSPP0, 31, 7 },
+
+ { DBGBUS_SSPP0, 32, 0 },
+ { DBGBUS_SSPP0, 32, 1 },
+ { DBGBUS_SSPP0, 32, 2 },
+ { DBGBUS_SSPP0, 32, 3 },
+ { DBGBUS_SSPP0, 32, 4 },
+ { DBGBUS_SSPP0, 32, 5 },
+ { DBGBUS_SSPP0, 32, 6 },
+ { DBGBUS_SSPP0, 32, 7 },
+
+ { DBGBUS_SSPP0, 33, 0 },
+ { DBGBUS_SSPP0, 33, 1 },
+ { DBGBUS_SSPP0, 33, 2 },
+ { DBGBUS_SSPP0, 33, 3 },
+ { DBGBUS_SSPP0, 33, 4 },
+ { DBGBUS_SSPP0, 33, 5 },
+ { DBGBUS_SSPP0, 33, 6 },
+ { DBGBUS_SSPP0, 33, 7 },
+
+ { DBGBUS_SSPP0, 34, 0 },
+ { DBGBUS_SSPP0, 34, 1 },
+ { DBGBUS_SSPP0, 34, 2 },
+ { DBGBUS_SSPP0, 34, 3 },
+ { DBGBUS_SSPP0, 34, 4 },
+ { DBGBUS_SSPP0, 34, 5 },
+ { DBGBUS_SSPP0, 34, 6 },
+ { DBGBUS_SSPP0, 34, 7 },
+
+ { DBGBUS_SSPP0, 35, 0 },
+ { DBGBUS_SSPP0, 35, 1 },
+ { DBGBUS_SSPP0, 35, 2 },
+ { DBGBUS_SSPP0, 35, 3 },
+
+ /* dma 0 */
+ { DBGBUS_SSPP0, 40, 0 },
+ { DBGBUS_SSPP0, 40, 1 },
+ { DBGBUS_SSPP0, 40, 2 },
+ { DBGBUS_SSPP0, 40, 3 },
+ { DBGBUS_SSPP0, 40, 4 },
+ { DBGBUS_SSPP0, 40, 5 },
+ { DBGBUS_SSPP0, 40, 6 },
+ { DBGBUS_SSPP0, 40, 7 },
+
+ { DBGBUS_SSPP0, 41, 0 },
+ { DBGBUS_SSPP0, 41, 1 },
+ { DBGBUS_SSPP0, 41, 2 },
+ { DBGBUS_SSPP0, 41, 3 },
+ { DBGBUS_SSPP0, 41, 4 },
+ { DBGBUS_SSPP0, 41, 5 },
+ { DBGBUS_SSPP0, 41, 6 },
+ { DBGBUS_SSPP0, 41, 7 },
+
+ { DBGBUS_SSPP0, 42, 0 },
+ { DBGBUS_SSPP0, 42, 1 },
+ { DBGBUS_SSPP0, 42, 2 },
+ { DBGBUS_SSPP0, 42, 3 },
+ { DBGBUS_SSPP0, 42, 4 },
+ { DBGBUS_SSPP0, 42, 5 },
+ { DBGBUS_SSPP0, 42, 6 },
+ { DBGBUS_SSPP0, 42, 7 },
+
+ { DBGBUS_SSPP0, 44, 0 },
+ { DBGBUS_SSPP0, 44, 1 },
+ { DBGBUS_SSPP0, 44, 2 },
+ { DBGBUS_SSPP0, 44, 3 },
+ { DBGBUS_SSPP0, 44, 4 },
+ { DBGBUS_SSPP0, 44, 5 },
+ { DBGBUS_SSPP0, 44, 6 },
+ { DBGBUS_SSPP0, 44, 7 },
+
+ { DBGBUS_SSPP0, 45, 0 },
+ { DBGBUS_SSPP0, 45, 1 },
+ { DBGBUS_SSPP0, 45, 2 },
+ { DBGBUS_SSPP0, 45, 3 },
+ { DBGBUS_SSPP0, 45, 4 },
+ { DBGBUS_SSPP0, 45, 5 },
+ { DBGBUS_SSPP0, 45, 6 },
+ { DBGBUS_SSPP0, 45, 7 },
+
+ /* fetch sspp1 */
+ /* vig 1 */
+ { DBGBUS_SSPP1, 0, 0 },
+ { DBGBUS_SSPP1, 0, 1 },
+ { DBGBUS_SSPP1, 0, 2 },
+ { DBGBUS_SSPP1, 0, 3 },
+ { DBGBUS_SSPP1, 0, 4 },
+ { DBGBUS_SSPP1, 0, 5 },
+ { DBGBUS_SSPP1, 0, 6 },
+ { DBGBUS_SSPP1, 0, 7 },
+
+ { DBGBUS_SSPP1, 1, 0 },
+ { DBGBUS_SSPP1, 1, 1 },
+ { DBGBUS_SSPP1, 1, 2 },
+ { DBGBUS_SSPP1, 1, 3 },
+ { DBGBUS_SSPP1, 1, 4 },
+ { DBGBUS_SSPP1, 1, 5 },
+ { DBGBUS_SSPP1, 1, 6 },
+ { DBGBUS_SSPP1, 1, 7 },
+
+ { DBGBUS_SSPP1, 2, 0 },
+ { DBGBUS_SSPP1, 2, 1 },
+ { DBGBUS_SSPP1, 2, 2 },
+ { DBGBUS_SSPP1, 2, 3 },
+ { DBGBUS_SSPP1, 2, 4 },
+ { DBGBUS_SSPP1, 2, 5 },
+ { DBGBUS_SSPP1, 2, 6 },
+ { DBGBUS_SSPP1, 2, 7 },
+
+ { DBGBUS_SSPP1, 4, 0 },
+ { DBGBUS_SSPP1, 4, 1 },
+ { DBGBUS_SSPP1, 4, 2 },
+ { DBGBUS_SSPP1, 4, 3 },
+ { DBGBUS_SSPP1, 4, 4 },
+ { DBGBUS_SSPP1, 4, 5 },
+ { DBGBUS_SSPP1, 4, 6 },
+ { DBGBUS_SSPP1, 4, 7 },
+
+ { DBGBUS_SSPP1, 5, 0 },
+ { DBGBUS_SSPP1, 5, 1 },
+ { DBGBUS_SSPP1, 5, 2 },
+ { DBGBUS_SSPP1, 5, 3 },
+ { DBGBUS_SSPP1, 5, 4 },
+ { DBGBUS_SSPP1, 5, 5 },
+ { DBGBUS_SSPP1, 5, 6 },
+ { DBGBUS_SSPP1, 5, 7 },
+
+ /* vig 3 */
+ { DBGBUS_SSPP1, 20, 0 },
+ { DBGBUS_SSPP1, 20, 1 },
+ { DBGBUS_SSPP1, 20, 2 },
+ { DBGBUS_SSPP1, 20, 3 },
+ { DBGBUS_SSPP1, 20, 4 },
+ { DBGBUS_SSPP1, 20, 5 },
+ { DBGBUS_SSPP1, 20, 6 },
+ { DBGBUS_SSPP1, 20, 7 },
+
+ { DBGBUS_SSPP1, 21, 0 },
+ { DBGBUS_SSPP1, 21, 1 },
+ { DBGBUS_SSPP1, 21, 2 },
+ { DBGBUS_SSPP1, 21, 3 },
+ { DBGBUS_SSPP1, 21, 4 },
+ { DBGBUS_SSPP1, 21, 5 },
+ { DBGBUS_SSPP1, 21, 6 },
+ { DBGBUS_SSPP1, 21, 7 },
+
+ { DBGBUS_SSPP1, 22, 0 },
+ { DBGBUS_SSPP1, 22, 1 },
+ { DBGBUS_SSPP1, 22, 2 },
+ { DBGBUS_SSPP1, 22, 3 },
+ { DBGBUS_SSPP1, 22, 4 },
+ { DBGBUS_SSPP1, 22, 5 },
+ { DBGBUS_SSPP1, 22, 6 },
+ { DBGBUS_SSPP1, 22, 7 },
+
+ { DBGBUS_SSPP1, 24, 0 },
+ { DBGBUS_SSPP1, 24, 1 },
+ { DBGBUS_SSPP1, 24, 2 },
+ { DBGBUS_SSPP1, 24, 3 },
+ { DBGBUS_SSPP1, 24, 4 },
+ { DBGBUS_SSPP1, 24, 5 },
+ { DBGBUS_SSPP1, 24, 6 },
+ { DBGBUS_SSPP1, 24, 7 },
+
+ { DBGBUS_SSPP1, 25, 0 },
+ { DBGBUS_SSPP1, 25, 1 },
+ { DBGBUS_SSPP1, 25, 2 },
+ { DBGBUS_SSPP1, 25, 3 },
+ { DBGBUS_SSPP1, 25, 4 },
+ { DBGBUS_SSPP1, 25, 5 },
+ { DBGBUS_SSPP1, 25, 6 },
+ { DBGBUS_SSPP1, 25, 7 },
+
+ /* dma 3 */
+ { DBGBUS_SSPP1, 30, 0 },
+ { DBGBUS_SSPP1, 30, 1 },
+ { DBGBUS_SSPP1, 30, 2 },
+ { DBGBUS_SSPP1, 30, 3 },
+ { DBGBUS_SSPP1, 30, 4 },
+ { DBGBUS_SSPP1, 30, 5 },
+ { DBGBUS_SSPP1, 30, 6 },
+ { DBGBUS_SSPP1, 30, 7 },
+
+ { DBGBUS_SSPP1, 31, 0 },
+ { DBGBUS_SSPP1, 31, 1 },
+ { DBGBUS_SSPP1, 31, 2 },
+ { DBGBUS_SSPP1, 31, 3 },
+ { DBGBUS_SSPP1, 31, 4 },
+ { DBGBUS_SSPP1, 31, 5 },
+ { DBGBUS_SSPP1, 31, 6 },
+ { DBGBUS_SSPP1, 31, 7 },
+
+ { DBGBUS_SSPP1, 32, 0 },
+ { DBGBUS_SSPP1, 32, 1 },
+ { DBGBUS_SSPP1, 32, 2 },
+ { DBGBUS_SSPP1, 32, 3 },
+ { DBGBUS_SSPP1, 32, 4 },
+ { DBGBUS_SSPP1, 32, 5 },
+ { DBGBUS_SSPP1, 32, 6 },
+ { DBGBUS_SSPP1, 32, 7 },
+
+ { DBGBUS_SSPP1, 33, 0 },
+ { DBGBUS_SSPP1, 33, 1 },
+ { DBGBUS_SSPP1, 33, 2 },
+ { DBGBUS_SSPP1, 33, 3 },
+ { DBGBUS_SSPP1, 33, 4 },
+ { DBGBUS_SSPP1, 33, 5 },
+ { DBGBUS_SSPP1, 33, 6 },
+ { DBGBUS_SSPP1, 33, 7 },
+
+ { DBGBUS_SSPP1, 34, 0 },
+ { DBGBUS_SSPP1, 34, 1 },
+ { DBGBUS_SSPP1, 34, 2 },
+ { DBGBUS_SSPP1, 34, 3 },
+ { DBGBUS_SSPP1, 34, 4 },
+ { DBGBUS_SSPP1, 34, 5 },
+ { DBGBUS_SSPP1, 34, 6 },
+ { DBGBUS_SSPP1, 34, 7 },
+
+ { DBGBUS_SSPP1, 35, 0 },
+ { DBGBUS_SSPP1, 35, 1 },
+ { DBGBUS_SSPP1, 35, 2 },
+
+ /* dma 1 */
+ { DBGBUS_SSPP1, 40, 0 },
+ { DBGBUS_SSPP1, 40, 1 },
+ { DBGBUS_SSPP1, 40, 2 },
+ { DBGBUS_SSPP1, 40, 3 },
+ { DBGBUS_SSPP1, 40, 4 },
+ { DBGBUS_SSPP1, 40, 5 },
+ { DBGBUS_SSPP1, 40, 6 },
+ { DBGBUS_SSPP1, 40, 7 },
+
+ { DBGBUS_SSPP1, 41, 0 },
+ { DBGBUS_SSPP1, 41, 1 },
+ { DBGBUS_SSPP1, 41, 2 },
+ { DBGBUS_SSPP1, 41, 3 },
+ { DBGBUS_SSPP1, 41, 4 },
+ { DBGBUS_SSPP1, 41, 5 },
+ { DBGBUS_SSPP1, 41, 6 },
+ { DBGBUS_SSPP1, 41, 7 },
+
+ { DBGBUS_SSPP1, 42, 0 },
+ { DBGBUS_SSPP1, 42, 1 },
+ { DBGBUS_SSPP1, 42, 2 },
+ { DBGBUS_SSPP1, 42, 3 },
+ { DBGBUS_SSPP1, 42, 4 },
+ { DBGBUS_SSPP1, 42, 5 },
+ { DBGBUS_SSPP1, 42, 6 },
+ { DBGBUS_SSPP1, 42, 7 },
+
+ { DBGBUS_SSPP1, 44, 0 },
+ { DBGBUS_SSPP1, 44, 1 },
+ { DBGBUS_SSPP1, 44, 2 },
+ { DBGBUS_SSPP1, 44, 3 },
+ { DBGBUS_SSPP1, 44, 4 },
+ { DBGBUS_SSPP1, 44, 5 },
+ { DBGBUS_SSPP1, 44, 6 },
+ { DBGBUS_SSPP1, 44, 7 },
+
+ { DBGBUS_SSPP1, 45, 0 },
+ { DBGBUS_SSPP1, 45, 1 },
+ { DBGBUS_SSPP1, 45, 2 },
+ { DBGBUS_SSPP1, 45, 3 },
+ { DBGBUS_SSPP1, 45, 4 },
+ { DBGBUS_SSPP1, 45, 5 },
+ { DBGBUS_SSPP1, 45, 6 },
+ { DBGBUS_SSPP1, 45, 7 },
+
+ /* cursor 1 */
+ { DBGBUS_SSPP1, 80, 0 },
+ { DBGBUS_SSPP1, 80, 1 },
+ { DBGBUS_SSPP1, 80, 2 },
+ { DBGBUS_SSPP1, 80, 3 },
+ { DBGBUS_SSPP1, 80, 4 },
+ { DBGBUS_SSPP1, 80, 5 },
+ { DBGBUS_SSPP1, 80, 6 },
+ { DBGBUS_SSPP1, 80, 7 },
+
+ { DBGBUS_SSPP1, 81, 0 },
+ { DBGBUS_SSPP1, 81, 1 },
+ { DBGBUS_SSPP1, 81, 2 },
+ { DBGBUS_SSPP1, 81, 3 },
+ { DBGBUS_SSPP1, 81, 4 },
+ { DBGBUS_SSPP1, 81, 5 },
+ { DBGBUS_SSPP1, 81, 6 },
+ { DBGBUS_SSPP1, 81, 7 },
+
+ { DBGBUS_SSPP1, 82, 0 },
+ { DBGBUS_SSPP1, 82, 1 },
+ { DBGBUS_SSPP1, 82, 2 },
+ { DBGBUS_SSPP1, 82, 3 },
+ { DBGBUS_SSPP1, 82, 4 },
+ { DBGBUS_SSPP1, 82, 5 },
+ { DBGBUS_SSPP1, 82, 6 },
+ { DBGBUS_SSPP1, 82, 7 },
+
+ { DBGBUS_SSPP1, 83, 0 },
+ { DBGBUS_SSPP1, 83, 1 },
+ { DBGBUS_SSPP1, 83, 2 },
+ { DBGBUS_SSPP1, 83, 3 },
+ { DBGBUS_SSPP1, 83, 4 },
+ { DBGBUS_SSPP1, 83, 5 },
+ { DBGBUS_SSPP1, 83, 6 },
+ { DBGBUS_SSPP1, 83, 7 },
+
+ { DBGBUS_SSPP1, 84, 0 },
+ { DBGBUS_SSPP1, 84, 1 },
+ { DBGBUS_SSPP1, 84, 2 },
+ { DBGBUS_SSPP1, 84, 3 },
+ { DBGBUS_SSPP1, 84, 4 },
+ { DBGBUS_SSPP1, 84, 5 },
+ { DBGBUS_SSPP1, 84, 6 },
+ { DBGBUS_SSPP1, 84, 7 },
+
+ /* dspp */
+ { DBGBUS_DSPP, 13, 0 },
+ { DBGBUS_DSPP, 19, 0 },
+ { DBGBUS_DSPP, 14, 0 },
+ { DBGBUS_DSPP, 14, 1 },
+ { DBGBUS_DSPP, 14, 3 },
+ { DBGBUS_DSPP, 20, 0 },
+ { DBGBUS_DSPP, 20, 1 },
+ { DBGBUS_DSPP, 20, 3 },
+
+ /* ppb_0 */
+ { DBGBUS_DSPP, 31, 0 },
+ { DBGBUS_DSPP, 33, 0 },
+ { DBGBUS_DSPP, 35, 0 },
+ { DBGBUS_DSPP, 42, 0 },
+
+ /* ppb_1 */
+ { DBGBUS_DSPP, 32, 0 },
+ { DBGBUS_DSPP, 34, 0 },
+ { DBGBUS_DSPP, 36, 0 },
+ { DBGBUS_DSPP, 43, 0 },
+
+ /* lm_lut */
+ { DBGBUS_DSPP, 109, 0 },
+ { DBGBUS_DSPP, 105, 0 },
+ { DBGBUS_DSPP, 103, 0 },
+
+ /* tear-check */
+ { DBGBUS_PERIPH, 63, 0 },
+ { DBGBUS_PERIPH, 64, 0 },
+ { DBGBUS_PERIPH, 65, 0 },
+ { DBGBUS_PERIPH, 73, 0 },
+ { DBGBUS_PERIPH, 74, 0 },
+
+ /* crossbar */
+ { DBGBUS_DSPP, 0, 0},
+
+ /* rotator */
+ { DBGBUS_DSPP, 9, 0},
+
+ /* blend */
+ /* LM0 */
+ { DBGBUS_DSPP, 63, 0},
+ { DBGBUS_DSPP, 63, 1},
+ { DBGBUS_DSPP, 63, 2},
+ { DBGBUS_DSPP, 63, 3},
+ { DBGBUS_DSPP, 63, 4},
+ { DBGBUS_DSPP, 63, 5},
+ { DBGBUS_DSPP, 63, 6},
+ { DBGBUS_DSPP, 63, 7},
+
+ { DBGBUS_DSPP, 64, 0},
+ { DBGBUS_DSPP, 64, 1},
+ { DBGBUS_DSPP, 64, 2},
+ { DBGBUS_DSPP, 64, 3},
+ { DBGBUS_DSPP, 64, 4},
+ { DBGBUS_DSPP, 64, 5},
+ { DBGBUS_DSPP, 64, 6},
+ { DBGBUS_DSPP, 64, 7},
+
+ { DBGBUS_DSPP, 65, 0},
+ { DBGBUS_DSPP, 65, 1},
+ { DBGBUS_DSPP, 65, 2},
+ { DBGBUS_DSPP, 65, 3},
+ { DBGBUS_DSPP, 65, 4},
+ { DBGBUS_DSPP, 65, 5},
+ { DBGBUS_DSPP, 65, 6},
+ { DBGBUS_DSPP, 65, 7},
+
+ { DBGBUS_DSPP, 66, 0},
+ { DBGBUS_DSPP, 66, 1},
+ { DBGBUS_DSPP, 66, 2},
+ { DBGBUS_DSPP, 66, 3},
+ { DBGBUS_DSPP, 66, 4},
+ { DBGBUS_DSPP, 66, 5},
+ { DBGBUS_DSPP, 66, 6},
+ { DBGBUS_DSPP, 66, 7},
+
+ { DBGBUS_DSPP, 67, 0},
+ { DBGBUS_DSPP, 67, 1},
+ { DBGBUS_DSPP, 67, 2},
+ { DBGBUS_DSPP, 67, 3},
+ { DBGBUS_DSPP, 67, 4},
+ { DBGBUS_DSPP, 67, 5},
+ { DBGBUS_DSPP, 67, 6},
+ { DBGBUS_DSPP, 67, 7},
+
+ { DBGBUS_DSPP, 68, 0},
+ { DBGBUS_DSPP, 68, 1},
+ { DBGBUS_DSPP, 68, 2},
+ { DBGBUS_DSPP, 68, 3},
+ { DBGBUS_DSPP, 68, 4},
+ { DBGBUS_DSPP, 68, 5},
+ { DBGBUS_DSPP, 68, 6},
+ { DBGBUS_DSPP, 68, 7},
+
+ { DBGBUS_DSPP, 69, 0},
+ { DBGBUS_DSPP, 69, 1},
+ { DBGBUS_DSPP, 69, 2},
+ { DBGBUS_DSPP, 69, 3},
+ { DBGBUS_DSPP, 69, 4},
+ { DBGBUS_DSPP, 69, 5},
+ { DBGBUS_DSPP, 69, 6},
+ { DBGBUS_DSPP, 69, 7},
+
+ /* LM1 */
+ { DBGBUS_DSPP, 70, 0},
+ { DBGBUS_DSPP, 70, 1},
+ { DBGBUS_DSPP, 70, 2},
+ { DBGBUS_DSPP, 70, 3},
+ { DBGBUS_DSPP, 70, 4},
+ { DBGBUS_DSPP, 70, 5},
+ { DBGBUS_DSPP, 70, 6},
+ { DBGBUS_DSPP, 70, 7},
+
+ { DBGBUS_DSPP, 71, 0},
+ { DBGBUS_DSPP, 71, 1},
+ { DBGBUS_DSPP, 71, 2},
+ { DBGBUS_DSPP, 71, 3},
+ { DBGBUS_DSPP, 71, 4},
+ { DBGBUS_DSPP, 71, 5},
+ { DBGBUS_DSPP, 71, 6},
+ { DBGBUS_DSPP, 71, 7},
+
+ { DBGBUS_DSPP, 72, 0},
+ { DBGBUS_DSPP, 72, 1},
+ { DBGBUS_DSPP, 72, 2},
+ { DBGBUS_DSPP, 72, 3},
+ { DBGBUS_DSPP, 72, 4},
+ { DBGBUS_DSPP, 72, 5},
+ { DBGBUS_DSPP, 72, 6},
+ { DBGBUS_DSPP, 72, 7},
+
+ { DBGBUS_DSPP, 73, 0},
+ { DBGBUS_DSPP, 73, 1},
+ { DBGBUS_DSPP, 73, 2},
+ { DBGBUS_DSPP, 73, 3},
+ { DBGBUS_DSPP, 73, 4},
+ { DBGBUS_DSPP, 73, 5},
+ { DBGBUS_DSPP, 73, 6},
+ { DBGBUS_DSPP, 73, 7},
+
+ { DBGBUS_DSPP, 74, 0},
+ { DBGBUS_DSPP, 74, 1},
+ { DBGBUS_DSPP, 74, 2},
+ { DBGBUS_DSPP, 74, 3},
+ { DBGBUS_DSPP, 74, 4},
+ { DBGBUS_DSPP, 74, 5},
+ { DBGBUS_DSPP, 74, 6},
+ { DBGBUS_DSPP, 74, 7},
+
+ { DBGBUS_DSPP, 75, 0},
+ { DBGBUS_DSPP, 75, 1},
+ { DBGBUS_DSPP, 75, 2},
+ { DBGBUS_DSPP, 75, 3},
+ { DBGBUS_DSPP, 75, 4},
+ { DBGBUS_DSPP, 75, 5},
+ { DBGBUS_DSPP, 75, 6},
+ { DBGBUS_DSPP, 75, 7},
+
+ { DBGBUS_DSPP, 76, 0},
+ { DBGBUS_DSPP, 76, 1},
+ { DBGBUS_DSPP, 76, 2},
+ { DBGBUS_DSPP, 76, 3},
+ { DBGBUS_DSPP, 76, 4},
+ { DBGBUS_DSPP, 76, 5},
+ { DBGBUS_DSPP, 76, 6},
+ { DBGBUS_DSPP, 76, 7},
+
+ /* LM2 */
+ { DBGBUS_DSPP, 77, 0},
+ { DBGBUS_DSPP, 77, 1},
+ { DBGBUS_DSPP, 77, 2},
+ { DBGBUS_DSPP, 77, 3},
+ { DBGBUS_DSPP, 77, 4},
+ { DBGBUS_DSPP, 77, 5},
+ { DBGBUS_DSPP, 77, 6},
+ { DBGBUS_DSPP, 77, 7},
+
+ { DBGBUS_DSPP, 78, 0},
+ { DBGBUS_DSPP, 78, 1},
+ { DBGBUS_DSPP, 78, 2},
+ { DBGBUS_DSPP, 78, 3},
+ { DBGBUS_DSPP, 78, 4},
+ { DBGBUS_DSPP, 78, 5},
+ { DBGBUS_DSPP, 78, 6},
+ { DBGBUS_DSPP, 78, 7},
+
+ { DBGBUS_DSPP, 79, 0},
+ { DBGBUS_DSPP, 79, 1},
+ { DBGBUS_DSPP, 79, 2},
+ { DBGBUS_DSPP, 79, 3},
+ { DBGBUS_DSPP, 79, 4},
+ { DBGBUS_DSPP, 79, 5},
+ { DBGBUS_DSPP, 79, 6},
+ { DBGBUS_DSPP, 79, 7},
+
+ { DBGBUS_DSPP, 80, 0},
+ { DBGBUS_DSPP, 80, 1},
+ { DBGBUS_DSPP, 80, 2},
+ { DBGBUS_DSPP, 80, 3},
+ { DBGBUS_DSPP, 80, 4},
+ { DBGBUS_DSPP, 80, 5},
+ { DBGBUS_DSPP, 80, 6},
+ { DBGBUS_DSPP, 80, 7},
+
+ { DBGBUS_DSPP, 81, 0},
+ { DBGBUS_DSPP, 81, 1},
+ { DBGBUS_DSPP, 81, 2},
+ { DBGBUS_DSPP, 81, 3},
+ { DBGBUS_DSPP, 81, 4},
+ { DBGBUS_DSPP, 81, 5},
+ { DBGBUS_DSPP, 81, 6},
+ { DBGBUS_DSPP, 81, 7},
+
+ { DBGBUS_DSPP, 82, 0},
+ { DBGBUS_DSPP, 82, 1},
+ { DBGBUS_DSPP, 82, 2},
+ { DBGBUS_DSPP, 82, 3},
+ { DBGBUS_DSPP, 82, 4},
+ { DBGBUS_DSPP, 82, 5},
+ { DBGBUS_DSPP, 82, 6},
+ { DBGBUS_DSPP, 82, 7},
+
+ { DBGBUS_DSPP, 83, 0},
+ { DBGBUS_DSPP, 83, 1},
+ { DBGBUS_DSPP, 83, 2},
+ { DBGBUS_DSPP, 83, 3},
+ { DBGBUS_DSPP, 83, 4},
+ { DBGBUS_DSPP, 83, 5},
+ { DBGBUS_DSPP, 83, 6},
+ { DBGBUS_DSPP, 83, 7},
+
+ /* csc */
+ { DBGBUS_SSPP0, 7, 0},
+ { DBGBUS_SSPP0, 7, 1},
+ { DBGBUS_SSPP0, 27, 0},
+ { DBGBUS_SSPP0, 27, 1},
+ { DBGBUS_SSPP1, 7, 0},
+ { DBGBUS_SSPP1, 7, 1},
+ { DBGBUS_SSPP1, 27, 0},
+ { DBGBUS_SSPP1, 27, 1},
+
+ /* pcc */
+ { DBGBUS_SSPP0, 3, 3},
+ { DBGBUS_SSPP0, 23, 3},
+ { DBGBUS_SSPP0, 33, 3},
+ { DBGBUS_SSPP0, 43, 3},
+ { DBGBUS_SSPP1, 3, 3},
+ { DBGBUS_SSPP1, 23, 3},
+ { DBGBUS_SSPP1, 33, 3},
+ { DBGBUS_SSPP1, 43, 3},
+
+ /* spa */
+ { DBGBUS_SSPP0, 8, 0},
+ { DBGBUS_SSPP0, 28, 0},
+ { DBGBUS_SSPP1, 8, 0},
+ { DBGBUS_SSPP1, 28, 0},
+ { DBGBUS_DSPP, 13, 0},
+ { DBGBUS_DSPP, 19, 0},
+
+ /* igc */
+ { DBGBUS_SSPP0, 9, 0},
+ { DBGBUS_SSPP0, 9, 1},
+ { DBGBUS_SSPP0, 9, 3},
+ { DBGBUS_SSPP0, 29, 0},
+ { DBGBUS_SSPP0, 29, 1},
+ { DBGBUS_SSPP0, 29, 3},
+ { DBGBUS_SSPP0, 17, 0},
+ { DBGBUS_SSPP0, 17, 1},
+ { DBGBUS_SSPP0, 17, 3},
+ { DBGBUS_SSPP0, 37, 0},
+ { DBGBUS_SSPP0, 37, 1},
+ { DBGBUS_SSPP0, 37, 3},
+ { DBGBUS_SSPP0, 46, 0},
+ { DBGBUS_SSPP0, 46, 1},
+ { DBGBUS_SSPP0, 46, 3},
+
+ { DBGBUS_SSPP1, 9, 0},
+ { DBGBUS_SSPP1, 9, 1},
+ { DBGBUS_SSPP1, 9, 3},
+ { DBGBUS_SSPP1, 29, 0},
+ { DBGBUS_SSPP1, 29, 1},
+ { DBGBUS_SSPP1, 29, 3},
+ { DBGBUS_SSPP1, 17, 0},
+ { DBGBUS_SSPP1, 17, 1},
+ { DBGBUS_SSPP1, 17, 3},
+ { DBGBUS_SSPP1, 37, 0},
+ { DBGBUS_SSPP1, 37, 1},
+ { DBGBUS_SSPP1, 37, 3},
+ { DBGBUS_SSPP1, 46, 0},
+ { DBGBUS_SSPP1, 46, 1},
+ { DBGBUS_SSPP1, 46, 3},
+
+ { DBGBUS_DSPP, 14, 0},
+ { DBGBUS_DSPP, 14, 1},
+ { DBGBUS_DSPP, 14, 3},
+ { DBGBUS_DSPP, 20, 0},
+ { DBGBUS_DSPP, 20, 1},
+ { DBGBUS_DSPP, 20, 3},
+
+ { DBGBUS_PERIPH, 60, 0},
+};
+
+static struct vbif_debug_bus_entry vbif_dbg_bus_msm8998[] = {
+ {0x214, 0x21c, 16, 2, 0x0, 0xd}, /* arb clients */
+ {0x214, 0x21c, 16, 2, 0x80, 0xc0}, /* arb clients */
+ {0x214, 0x21c, 16, 2, 0x100, 0x140}, /* arb clients */
+ {0x214, 0x21c, 0, 16, 0x0, 0xf}, /* xin blocks - axi side */
+ {0x214, 0x21c, 0, 16, 0x80, 0xa4}, /* xin blocks - axi side */
+ {0x214, 0x21c, 0, 15, 0x100, 0x124}, /* xin blocks - axi side */
+ {0x21c, 0x214, 0, 14, 0, 0xc}, /* xin blocks - clock side */
+};
+
+/**
+ * _sde_dbg_enable_power - use callback to turn power on for hw register access
+ * @enable: whether to turn power on or off
+ */
+static inline void _sde_dbg_enable_power(int enable)
+{
+ if (!sde_dbg_base.power_ctrl.enable_fn)
+ return;
+ sde_dbg_base.power_ctrl.enable_fn(
+ sde_dbg_base.power_ctrl.handle,
+ sde_dbg_base.power_ctrl.client,
+ enable);
+}
+
+/**
+ * _sde_dump_reg - helper function for dumping rotator register set content
+ * @dump_name: register set name
+ * @reg_dump_flag: dumping flag controlling in-log/memory dump location
+ * @base_addr: starting address of io region for calculating offsets to print
+ * @addr: starting address offset for dumping
+ * @len_bytes: range of the register set
+ * @dump_mem: output buffer for memory dump location option
+ * @from_isr: whether being called from isr context
+ */
+static void _sde_dump_reg(const char *dump_name, u32 reg_dump_flag,
+ char __iomem *base_addr, char __iomem *addr, size_t len_bytes,
+ u32 **dump_mem, bool from_isr)
+{
+ u32 in_log, in_mem, len_align, len_padded;
+ u32 *dump_addr = NULL;
+ char __iomem *end_addr;
+ int i;
+
+ if (!len_bytes)
+ return;
+
+ in_log = (reg_dump_flag & SDE_DBG_DUMP_IN_LOG);
+ in_mem = (reg_dump_flag & SDE_DBG_DUMP_IN_MEM);
+
+ pr_debug("%s: reg_dump_flag=%d in_log=%d in_mem=%d\n",
+ dump_name, reg_dump_flag, in_log, in_mem);
+
+ if (!in_log && !in_mem)
+ return;
+
+ if (in_log)
+ dev_info(sde_dbg_base.dev, "%s: start_offset 0x%lx len 0x%zx\n",
+ dump_name, addr - base_addr, len_bytes);
+
+ len_align = (len_bytes + REG_DUMP_ALIGN - 1) / REG_DUMP_ALIGN;
+ len_padded = len_align * REG_DUMP_ALIGN;
+ end_addr = addr + len_bytes;
+
+ if (in_mem) {
+ if (dump_mem && !(*dump_mem)) {
+ phys_addr_t phys = 0;
+ *dump_mem = dma_alloc_coherent(sde_dbg_base.dev,
+ len_padded, &phys, GFP_KERNEL);
+ }
+
+ if (dump_mem && *dump_mem) {
+ dump_addr = *dump_mem;
+ dev_info(sde_dbg_base.dev,
+ "%s: start_addr:0x%pK len:0x%x reg_offset=0x%lx\n",
+ dump_name, dump_addr, len_padded,
+ addr - base_addr);
+ } else {
+ in_mem = 0;
+ pr_err("dump_mem: kzalloc fails!\n");
+ }
+ }
+
+ if (!from_isr)
+ _sde_dbg_enable_power(true);
+
+ for (i = 0; i < len_align; i++) {
+ u32 x0, x4, x8, xc;
+
+ x0 = (addr < end_addr) ? readl_relaxed(addr + 0x0) : 0;
+ x4 = (addr + 0x4 < end_addr) ? readl_relaxed(addr + 0x4) : 0;
+ x8 = (addr + 0x8 < end_addr) ? readl_relaxed(addr + 0x8) : 0;
+ xc = (addr + 0xc < end_addr) ? readl_relaxed(addr + 0xc) : 0;
+
+ if (in_log)
+ dev_info(sde_dbg_base.dev,
+ "0x%lx : %08x %08x %08x %08x\n",
+ addr - base_addr, x0, x4, x8, xc);
+
+ if (dump_addr) {
+ dump_addr[i * 4] = x0;
+ dump_addr[i * 4 + 1] = x4;
+ dump_addr[i * 4 + 2] = x8;
+ dump_addr[i * 4 + 3] = xc;
+ }
+
+ addr += REG_DUMP_ALIGN;
+ }
+
+ if (!from_isr)
+ _sde_dbg_enable_power(false);
+}
+
+/**
+ * _sde_dbg_get_dump_range - helper to retrieve dump length for a range node
+ * @range_node: range node to dump
+ * @max_offset: max offset of the register base
+ * @Return: length
+ */
+static u32 _sde_dbg_get_dump_range(struct sde_dbg_reg_offset *range_node,
+ size_t max_offset)
+{
+ u32 length = 0;
+
+ if ((range_node->start > range_node->end) ||
+ (range_node->end > max_offset) || (range_node->start == 0
+ && range_node->end == 0)) {
+ length = max_offset;
+ } else {
+ length = range_node->end - range_node->start;
+ }
+
+ return length;
+}
+
+static int _sde_dump_reg_range_cmp(void *priv, struct list_head *a,
+ struct list_head *b)
+{
+ struct sde_dbg_reg_range *ar, *br;
+
+ if (!a || !b)
+ return 0;
+
+ ar = container_of(a, struct sde_dbg_reg_range, head);
+ br = container_of(b, struct sde_dbg_reg_range, head);
+
+ return ar->offset.start - br->offset.start;
+}
+
+/**
+ * _sde_dump_reg_by_ranges - dump ranges or full range of the register blk base
+ * @dbg: register blk base structure
+ * @reg_dump_flag: dump target, memory, kernel log, or both
+ */
+static void _sde_dump_reg_by_ranges(struct sde_dbg_reg_base *dbg,
+ u32 reg_dump_flag)
+{
+ char __iomem *addr;
+ size_t len;
+ struct sde_dbg_reg_range *range_node;
+
+ if (!dbg || !dbg->base) {
+ pr_err("dbg base is null!\n");
+ return;
+ }
+
+ dev_info(sde_dbg_base.dev, "%s:=========%s DUMP=========\n", __func__,
+ dbg->name);
+
+ /* If there is a list to dump the registers by ranges, use the ranges */
+ if (!list_empty(&dbg->sub_range_list)) {
+ /* sort the list by start address first */
+ list_sort(NULL, &dbg->sub_range_list, _sde_dump_reg_range_cmp);
+ list_for_each_entry(range_node, &dbg->sub_range_list, head) {
+ len = _sde_dbg_get_dump_range(&range_node->offset,
+ dbg->max_offset);
+ addr = dbg->base + range_node->offset.start;
+ pr_debug("%s: range_base=0x%pK start=0x%x end=0x%x\n",
+ range_node->range_name,
+ addr, range_node->offset.start,
+ range_node->offset.end);
+
+ _sde_dump_reg(range_node->range_name, reg_dump_flag,
+ dbg->base, addr, len,
+ &range_node->reg_dump, false);
+ }
+ } else {
+ /* If there is no list to dump ranges, dump all registers */
+ dev_info(sde_dbg_base.dev,
+ "Ranges not found, will dump full registers\n");
+ dev_info(sde_dbg_base.dev, "base:0x%pK len:0x%zx\n", dbg->base,
+ dbg->max_offset);
+ addr = dbg->base;
+ len = dbg->max_offset;
+ _sde_dump_reg(dbg->name, reg_dump_flag, dbg->base, addr, len,
+ &dbg->reg_dump, false);
+ }
+}
+
+/**
+ * _sde_dump_reg_by_blk - dump a named register base region
+ * @blk_name: register blk name
+ */
+static void _sde_dump_reg_by_blk(const char *blk_name)
+{
+ struct sde_dbg_base *dbg_base = &sde_dbg_base;
+ struct sde_dbg_reg_base *blk_base;
+
+ if (!dbg_base)
+ return;
+
+ list_for_each_entry(blk_base, &dbg_base->reg_base_list, reg_base_head) {
+ if (strlen(blk_base->name) &&
+ !strcmp(blk_base->name, blk_name)) {
+ _sde_dump_reg_by_ranges(blk_base,
+ dbg_base->enable_reg_dump);
+ break;
+ }
+ }
+}
+
+/**
+ * _sde_dump_reg_all - dump all register regions
+ */
+static void _sde_dump_reg_all(void)
+{
+ struct sde_dbg_base *dbg_base = &sde_dbg_base;
+ struct sde_dbg_reg_base *blk_base;
+
+ if (!dbg_base)
+ return;
+
+ list_for_each_entry(blk_base, &dbg_base->reg_base_list, reg_base_head)
+ if (strlen(blk_base->name))
+ _sde_dump_reg_by_blk(blk_base->name);
+}
+
+/**
+ * _sde_dump_get_blk_addr - retrieve register block address by name
+ * @blk_name: register blk name
+ * @Return: register blk base, or NULL
+ */
+static struct sde_dbg_reg_base *_sde_dump_get_blk_addr(const char *blk_name)
+{
+ struct sde_dbg_base *dbg_base = &sde_dbg_base;
+ struct sde_dbg_reg_base *blk_base;
+
+ list_for_each_entry(blk_base, &dbg_base->reg_base_list, reg_base_head)
+ if (strlen(blk_base->name) && !strcmp(blk_base->name, blk_name))
+ return blk_base;
+
+ return NULL;
+}
+
+static void _sde_dbg_dump_sde_dbg_bus(struct sde_dbg_sde_debug_bus *bus)
+{
+ bool in_log, in_mem;
+ u32 **dump_mem = NULL;
+ u32 *dump_addr = NULL;
+ u32 status = 0;
+ struct sde_debug_bus_entry *head;
+ phys_addr_t phys = 0;
+ int list_size;
+ int i;
+ u32 offset;
+ void __iomem *mem_base = NULL;
+ struct sde_dbg_reg_base *reg_base;
+
+ if (!bus || !bus->cmn.entries_size)
+ return;
+
+ list_for_each_entry(reg_base, &sde_dbg_base.reg_base_list,
+ reg_base_head)
+ if (strlen(reg_base->name) &&
+ !strcmp(reg_base->name, bus->cmn.name))
+ mem_base = reg_base->base + bus->top_blk_off;
+
+ if (!mem_base) {
+ pr_err("unable to find mem_base for %s\n", bus->cmn.name);
+ return;
+ }
+
+ dump_mem = &bus->cmn.dumped_content;
+
+ /* will keep in memory 4 entries of 4 bytes each */
+ list_size = (bus->cmn.entries_size * 4 * 4);
+
+ in_log = (bus->cmn.enable_mask & SDE_DBG_DUMP_IN_LOG);
+ in_mem = (bus->cmn.enable_mask & SDE_DBG_DUMP_IN_MEM);
+
+ if (!in_log && !in_mem)
+ return;
+
+ dev_info(sde_dbg_base.dev, "======== start %s dump =========\n",
+ bus->cmn.name);
+
+ if (in_mem) {
+ if (!(*dump_mem))
+ *dump_mem = dma_alloc_coherent(sde_dbg_base.dev,
+ list_size, &phys, GFP_KERNEL);
+
+ if (*dump_mem) {
+ dump_addr = *dump_mem;
+ dev_info(sde_dbg_base.dev,
+ "%s: start_addr:0x%pK len:0x%x\n",
+ __func__, dump_addr, list_size);
+ } else {
+ in_mem = false;
+ pr_err("dump_mem: allocation fails\n");
+ }
+ }
+
+ _sde_dbg_enable_power(true);
+ for (i = 0; i < bus->cmn.entries_size; i++) {
+ head = bus->entries + i;
+ writel_relaxed(TEST_MASK(head->block_id, head->test_id),
+ mem_base + head->wr_addr);
+ wmb(); /* make sure test bits were written */
+
+ if (bus->cmn.flags & DBGBUS_FLAGS_DSPP)
+ offset = DBGBUS_DSPP_STATUS;
+ else
+ offset = head->wr_addr + 0x4;
+
+ status = readl_relaxed(mem_base + offset);
+
+ if (in_log)
+ dev_info(sde_dbg_base.dev,
+ "waddr=0x%x blk=%d tst=%d val=0x%x\n",
+ head->wr_addr, head->block_id,
+ head->test_id, status);
+
+ if (dump_addr && in_mem) {
+ dump_addr[i*4] = head->wr_addr;
+ dump_addr[i*4 + 1] = head->block_id;
+ dump_addr[i*4 + 2] = head->test_id;
+ dump_addr[i*4 + 3] = status;
+ }
+
+ /* Disable debug bus once we are done */
+ writel_relaxed(0, mem_base + head->wr_addr);
+
+ }
+ _sde_dbg_enable_power(false);
+
+ dev_info(sde_dbg_base.dev, "======== end %s dump =========\n",
+ bus->cmn.name);
+}
+
+static void _sde_dbg_dump_vbif_debug_bus_entry(
+ struct vbif_debug_bus_entry *head, void __iomem *mem_base,
+ u32 *dump_addr, bool in_log)
+{
+ int i, j;
+ u32 val;
+
+ if (!dump_addr && !in_log)
+ return;
+
+ for (i = 0; i < head->block_cnt; i++) {
+ writel_relaxed(1 << (i + head->bit_offset),
+ mem_base + head->block_bus_addr);
+ /* make sure that current bus blcok enable */
+ wmb();
+ for (j = head->test_pnt_start; j < head->test_pnt_cnt; j++) {
+ writel_relaxed(j, mem_base + head->block_bus_addr + 4);
+ /* make sure that test point is enabled */
+ wmb();
+ val = readl_relaxed(mem_base + MMSS_VBIF_TEST_BUS_OUT);
+ if (dump_addr) {
+ *dump_addr++ = head->block_bus_addr;
+ *dump_addr++ = i;
+ *dump_addr++ = j;
+ *dump_addr++ = val;
+ }
+ if (in_log)
+ dev_info(sde_dbg_base.dev,
+ "testpoint:%x arb/xin id=%d index=%d val=0x%x\n",
+ head->block_bus_addr, i, j, val);
+ }
+ }
+}
+
+static void _sde_dbg_dump_vbif_dbg_bus(struct sde_dbg_vbif_debug_bus *bus)
+{
+ bool in_log, in_mem;
+ u32 **dump_mem = NULL;
+ u32 *dump_addr = NULL;
+ u32 value;
+ struct vbif_debug_bus_entry *head;
+ phys_addr_t phys = 0;
+ int i, list_size = 0;
+ void __iomem *mem_base = NULL;
+ struct vbif_debug_bus_entry *dbg_bus;
+ u32 bus_size;
+ struct sde_dbg_reg_base *reg_base;
+
+ if (!bus || !bus->cmn.entries_size)
+ return;
+
+ list_for_each_entry(reg_base, &sde_dbg_base.reg_base_list,
+ reg_base_head)
+ if (strlen(reg_base->name) &&
+ !strcmp(reg_base->name, bus->cmn.name))
+ mem_base = reg_base->base;
+
+ if (!mem_base) {
+ pr_err("unable to find mem_base for %s\n", bus->cmn.name);
+ return;
+ }
+
+ dbg_bus = bus->entries;
+ bus_size = bus->cmn.entries_size;
+ list_size = bus->cmn.entries_size;
+ dump_mem = &bus->cmn.dumped_content;
+
+ dev_info(sde_dbg_base.dev, "======== start %s dump =========\n",
+ bus->cmn.name);
+
+ if (!dump_mem || !dbg_bus || !bus_size || !list_size)
+ return;
+
+ /* allocate memory for each test point */
+ for (i = 0; i < bus_size; i++) {
+ head = dbg_bus + i;
+ list_size += (head->block_cnt * head->test_pnt_cnt);
+ }
+
+ /* 4 bytes * 4 entries for each test point*/
+ list_size *= 16;
+
+ in_log = (bus->cmn.enable_mask & SDE_DBG_DUMP_IN_LOG);
+ in_mem = (bus->cmn.enable_mask & SDE_DBG_DUMP_IN_MEM);
+
+ if (!in_log && !in_mem)
+ return;
+
+ if (in_mem) {
+ if (!(*dump_mem))
+ *dump_mem = dma_alloc_coherent(sde_dbg_base.dev,
+ list_size, &phys, GFP_KERNEL);
+
+ if (*dump_mem) {
+ dump_addr = *dump_mem;
+ dev_info(sde_dbg_base.dev,
+ "%s: start_addr:0x%pK len:0x%x\n",
+ __func__, dump_addr, list_size);
+ } else {
+ in_mem = false;
+ pr_err("dump_mem: allocation fails\n");
+ }
+ }
+
+ _sde_dbg_enable_power(true);
+
+ value = readl_relaxed(mem_base + MMSS_VBIF_CLKON);
+ writel_relaxed(value | BIT(1), mem_base + MMSS_VBIF_CLKON);
+
+ /* make sure that vbif core is on */
+ wmb();
+
+ for (i = 0; i < bus_size; i++) {
+ head = dbg_bus + i;
+
+ writel_relaxed(0, mem_base + head->disable_bus_addr);
+ writel_relaxed(BIT(0), mem_base + MMSS_VBIF_TEST_BUS_OUT_CTRL);
+ /* make sure that other bus is off */
+ wmb();
+
+ _sde_dbg_dump_vbif_debug_bus_entry(head, mem_base, dump_addr,
+ in_log);
+ if (dump_addr)
+ dump_addr += (head->block_cnt * head->test_pnt_cnt * 4);
+ }
+
+ _sde_dbg_enable_power(false);
+
+ dev_info(sde_dbg_base.dev, "======== end %s dump =========\n",
+ bus->cmn.name);
+}
+
+/**
+ * _sde_dump_array - dump array of register bases
+ * @blk_arr: array of register base pointers
+ * @len: length of blk_arr
+ * @do_panic: whether to trigger a panic after dumping
+ * @name: string indicating origin of dump
+ * @dump_dbgbus_sde: whether to dump the sde debug bus
+ * @dump_dbgbus_vbif_rt: whether to dump the vbif rt debug bus
+ */
+static void _sde_dump_array(struct sde_dbg_reg_base *blk_arr[],
+ u32 len, bool do_panic, const char *name, bool dump_dbgbus_sde,
+ bool dump_dbgbus_vbif_rt)
+{
+ int i;
+
+ for (i = 0; i < len; i++) {
+ if (blk_arr[i] != NULL)
+ _sde_dump_reg_by_ranges(blk_arr[i],
+ sde_dbg_base.enable_reg_dump);
+ }
+
+ sde_evtlog_dump_all(sde_dbg_base.evtlog);
+
+ if (dump_dbgbus_sde)
+ _sde_dbg_dump_sde_dbg_bus(&sde_dbg_base.dbgbus_sde);
+
+ if (dump_dbgbus_vbif_rt)
+ _sde_dbg_dump_vbif_dbg_bus(&sde_dbg_base.dbgbus_vbif_rt);
+
+ if (do_panic && sde_dbg_base.panic_on_err)
+ panic(name);
+}
+
+/**
+ * _sde_dump_work - deferred dump work function
+ * @work: work structure
+ */
+static void _sde_dump_work(struct work_struct *work)
+{
+ _sde_dump_array(sde_dbg_base.req_dump_blks,
+ ARRAY_SIZE(sde_dbg_base.req_dump_blks),
+ sde_dbg_base.work_panic, "evtlog_workitem",
+ sde_dbg_base.dbgbus_sde.cmn.include_in_deferred_work,
+ sde_dbg_base.dbgbus_vbif_rt.cmn.include_in_deferred_work);
+}
+
+void sde_dbg_dump(bool queue_work, const char *name, ...)
+{
+ int i, index = 0;
+ bool do_panic = false;
+ bool dump_dbgbus_sde = false;
+ bool dump_dbgbus_vbif_rt = false;
+ va_list args;
+ char *blk_name = NULL;
+ struct sde_dbg_reg_base *blk_base = NULL;
+ struct sde_dbg_reg_base **blk_arr;
+ u32 blk_len;
+
+ if (!sde_evtlog_is_enabled(sde_dbg_base.evtlog, SDE_EVTLOG_DEFAULT))
+ return;
+
+ if (queue_work && work_pending(&sde_dbg_base.dump_work))
+ return;
+
+ blk_arr = &sde_dbg_base.req_dump_blks[0];
+ blk_len = ARRAY_SIZE(sde_dbg_base.req_dump_blks);
+
+ memset(sde_dbg_base.req_dump_blks, 0,
+ sizeof(sde_dbg_base.req_dump_blks));
+
+ va_start(args, name);
+ i = 0;
+ while ((blk_name = va_arg(args, char*))) {
+ if (i++ >= SDE_EVTLOG_MAX_DATA) {
+ pr_err("could not parse all dump arguments\n");
+ break;
+ }
+ if (IS_ERR_OR_NULL(blk_name))
+ break;
+
+ blk_base = _sde_dump_get_blk_addr(blk_name);
+ if (blk_base) {
+ if (index < blk_len) {
+ blk_arr[index] = blk_base;
+ index++;
+ } else {
+ pr_err("insufficient space to to dump %s\n",
+ blk_name);
+ }
+ }
+
+ if (!strcmp(blk_name, "dbg_bus"))
+ dump_dbgbus_sde = true;
+
+ if (!strcmp(blk_name, "vbif_dbg_bus"))
+ dump_dbgbus_vbif_rt = true;
+
+ if (!strcmp(blk_name, "panic"))
+ do_panic = true;
+ }
+ va_end(args);
+
+ if (queue_work) {
+ /* schedule work to dump later */
+ sde_dbg_base.work_panic = do_panic;
+ sde_dbg_base.dbgbus_sde.cmn.include_in_deferred_work =
+ dump_dbgbus_sde;
+ sde_dbg_base.dbgbus_vbif_rt.cmn.include_in_deferred_work =
+ dump_dbgbus_vbif_rt;
+ schedule_work(&sde_dbg_base.dump_work);
+ } else {
+ _sde_dump_array(blk_arr, blk_len, do_panic, name,
+ dump_dbgbus_sde, dump_dbgbus_vbif_rt);
+ }
+}
+
+/*
+ * sde_dbg_debugfs_open - debugfs open handler for evtlog dump
+ * @inode: debugfs inode
+ * @file: file handle
+ */
+static int sde_dbg_debugfs_open(struct inode *inode, struct file *file)
+{
+ /* non-seekable */
+ file->f_mode &= ~(FMODE_LSEEK | FMODE_PREAD | FMODE_PWRITE);
+ file->private_data = inode->i_private;
+ return 0;
+}
+
+/**
+ * sde_evtlog_dump_read - debugfs read handler for evtlog dump
+ * @file: file handler
+ * @buff: user buffer content for debugfs
+ * @count: size of user buffer
+ * @ppos: position offset of user buffer
+ */
+static ssize_t sde_evtlog_dump_read(struct file *file, char __user *buff,
+ size_t count, loff_t *ppos)
+{
+ ssize_t len = 0;
+ char evtlog_buf[SDE_EVTLOG_BUF_MAX];
+
+ len = sde_evtlog_dump_to_buffer(sde_dbg_base.evtlog, evtlog_buf,
+ SDE_EVTLOG_BUF_MAX);
+ if (copy_to_user(buff, evtlog_buf, len))
+ return -EFAULT;
+ *ppos += len;
+
+ return len;
+}
+
+/**
+ * sde_evtlog_dump_write - debugfs write handler for evtlog dump
+ * @file: file handler
+ * @user_buf: user buffer content from debugfs
+ * @count: size of user buffer
+ * @ppos: position offset of user buffer
+ */
+static ssize_t sde_evtlog_dump_write(struct file *file,
+ const char __user *user_buf, size_t count, loff_t *ppos)
+{
+ _sde_dump_reg_all();
+
+ sde_evtlog_dump_all(sde_dbg_base.evtlog);
+
+ _sde_dbg_dump_sde_dbg_bus(&sde_dbg_base.dbgbus_sde);
+ _sde_dbg_dump_vbif_dbg_bus(&sde_dbg_base.dbgbus_vbif_rt);
+
+ if (sde_dbg_base.panic_on_err)
+ panic("sde");
+
+ return count;
+}
+
+static const struct file_operations sde_evtlog_fops = {
+ .open = sde_dbg_debugfs_open,
+ .read = sde_evtlog_dump_read,
+ .write = sde_evtlog_dump_write,
+};
+
+void sde_dbg_init_dbg_buses(u32 hwversion)
+{
+ static struct sde_dbg_base *dbg = &sde_dbg_base;
+ char debug_name[80] = "";
+
+ memset(&dbg->dbgbus_sde, 0, sizeof(dbg->dbgbus_sde));
+ memset(&dbg->dbgbus_vbif_rt, 0, sizeof(dbg->dbgbus_vbif_rt));
+
+ switch (hwversion) {
+ case SDE_HW_VER_300:
+ case SDE_HW_VER_301:
+ dbg->dbgbus_sde.entries = dbg_bus_sde_8998;
+ dbg->dbgbus_sde.cmn.entries_size = ARRAY_SIZE(dbg_bus_sde_8998);
+ dbg->dbgbus_sde.cmn.flags = DBGBUS_FLAGS_DSPP;
+
+ dbg->dbgbus_vbif_rt.entries = vbif_dbg_bus_msm8998;
+ dbg->dbgbus_vbif_rt.cmn.entries_size =
+ ARRAY_SIZE(vbif_dbg_bus_msm8998);
+ break;
+ default:
+ pr_err("unsupported chipset id %u\n", hwversion);
+ break;
+ }
+
+ if (dbg->dbgbus_sde.entries) {
+ dbg->dbgbus_sde.cmn.name = DBGBUS_NAME_SDE;
+ snprintf(debug_name, sizeof(debug_name), "%s_dbgbus",
+ dbg->dbgbus_sde.cmn.name);
+ dbg->dbgbus_sde.cmn.enable_mask = DEFAULT_DBGBUS_SDE;
+ debugfs_create_u32(debug_name, 0600, dbg->root,
+ &dbg->dbgbus_sde.cmn.enable_mask);
+ }
+
+ if (dbg->dbgbus_vbif_rt.entries) {
+ dbg->dbgbus_vbif_rt.cmn.name = DBGBUS_NAME_VBIF_RT;
+ snprintf(debug_name, sizeof(debug_name), "%s_dbgbus",
+ dbg->dbgbus_vbif_rt.cmn.name);
+ dbg->dbgbus_vbif_rt.cmn.enable_mask = DEFAULT_DBGBUS_VBIFRT;
+ debugfs_create_u32(debug_name, 0600, dbg->root,
+ &dbg->dbgbus_vbif_rt.cmn.enable_mask);
+ }
+}
+
+int sde_dbg_init(struct dentry *debugfs_root, struct device *dev,
+ struct sde_dbg_power_ctrl *power_ctrl)
+{
+ int i;
+
+ INIT_LIST_HEAD(&sde_dbg_base.reg_base_list);
+ sde_dbg_base.dev = dev;
+ sde_dbg_base.power_ctrl = *power_ctrl;
+
+
+ sde_dbg_base.evtlog = sde_evtlog_init();
+ if (IS_ERR_OR_NULL(sde_dbg_base.evtlog))
+ return PTR_ERR(sde_dbg_base.evtlog);
+
+ sde_dbg_base_evtlog = sde_dbg_base.evtlog;
+
+ sde_dbg_base.root = debugfs_create_dir("evt_dbg", debugfs_root);
+ if (IS_ERR_OR_NULL(sde_dbg_base.root)) {
+ pr_err("debugfs_create_dir fail, error %ld\n",
+ PTR_ERR(sde_dbg_base.root));
+ sde_dbg_base.root = NULL;
+ return -ENODEV;
+ }
+
+ INIT_WORK(&sde_dbg_base.dump_work, _sde_dump_work);
+ sde_dbg_base.work_panic = false;
+
+ for (i = 0; i < SDE_EVTLOG_ENTRY; i++)
+ sde_dbg_base.evtlog->logs[i].counter = i;
+
+ debugfs_create_file("dump", 0600, sde_dbg_base.root, NULL,
+ &sde_evtlog_fops);
+ debugfs_create_u32("enable", 0600, sde_dbg_base.root,
+ &(sde_dbg_base.evtlog->enable));
+ debugfs_create_u32("panic", 0600, sde_dbg_base.root,
+ &sde_dbg_base.panic_on_err);
+ debugfs_create_u32("reg_dump", 0600, sde_dbg_base.root,
+ &sde_dbg_base.enable_reg_dump);
+
+ sde_dbg_base.panic_on_err = DEFAULT_PANIC;
+ sde_dbg_base.enable_reg_dump = DEFAULT_REGDUMP;
+
+ pr_info("evtlog_status: enable:%d, panic:%d, dump:%d\n",
+ sde_dbg_base.evtlog->enable, sde_dbg_base.panic_on_err,
+ sde_dbg_base.enable_reg_dump);
+
+ return 0;
+}
+
+/**
+ * sde_dbg_destroy - destroy sde debug facilities
+ */
+void sde_dbg_destroy(void)
+{
+ debugfs_remove_recursive(sde_dbg_base.root);
+ sde_dbg_base.root = NULL;
+
+ sde_dbg_base_evtlog = NULL;
+ sde_evtlog_destroy(sde_dbg_base.evtlog);
+ sde_dbg_base.evtlog = NULL;
+}
+
+/**
+ * sde_dbg_reg_base_release - release allocated reg dump file private data
+ * @inode: debugfs inode
+ * @file: file handle
+ * @Return: 0 on success
+ */
+static int sde_dbg_reg_base_release(struct inode *inode, struct file *file)
+{
+ struct sde_dbg_reg_base *dbg = file->private_data;
+
+ if (dbg && dbg->buf) {
+ kfree(dbg->buf);
+ dbg->buf_len = 0;
+ dbg->buf = NULL;
+ }
+ return 0;
+}
+
+
+/**
+ * sde_dbg_reg_base_offset_write - set new offset and len to debugfs reg base
+ * @file: file handler
+ * @user_buf: user buffer content from debugfs
+ * @count: size of user buffer
+ * @ppos: position offset of user buffer
+ */
+static ssize_t sde_dbg_reg_base_offset_write(struct file *file,
+ const char __user *user_buf, size_t count, loff_t *ppos)
+{
+ struct sde_dbg_reg_base *dbg = file->private_data;
+ u32 off = 0;
+ u32 cnt = DEFAULT_BASE_REG_CNT;
+ char buf[24];
+
+ if (!dbg)
+ return -ENODEV;
+
+ if (count >= sizeof(buf))
+ return -EFAULT;
+
+ if (copy_from_user(buf, user_buf, count))
+ return -EFAULT;
+
+ buf[count] = 0; /* end of string */
+
+ if (sscanf(buf, "%5x %x", &off, &cnt) != 2)
+ return -EFAULT;
+
+ if (off > dbg->max_offset)
+ return -EINVAL;
+
+ if (off % sizeof(u32))
+ return -EINVAL;
+
+ if (cnt > (dbg->max_offset - off))
+ cnt = dbg->max_offset - off;
+
+ if (cnt % sizeof(u32))
+ return -EINVAL;
+
+ dbg->off = off;
+ dbg->cnt = cnt;
+
+ pr_debug("offset=%x cnt=%x\n", off, cnt);
+
+ return count;
+}
+
+/**
+ * sde_dbg_reg_base_offset_read - read current offset and len of register base
+ * @file: file handler
+ * @user_buf: user buffer content from debugfs
+ * @count: size of user buffer
+ * @ppos: position offset of user buffer
+ */
+static ssize_t sde_dbg_reg_base_offset_read(struct file *file,
+ char __user *buff, size_t count, loff_t *ppos)
+{
+ struct sde_dbg_reg_base *dbg = file->private_data;
+ int len = 0;
+ char buf[24] = {'\0'};
+
+ if (!dbg)
+ return -ENODEV;
+
+ if (*ppos)
+ return 0; /* the end */
+
+ len = snprintf(buf, sizeof(buf), "0x%08zx %zx\n", dbg->off, dbg->cnt);
+ if (len < 0 || len >= sizeof(buf))
+ return 0;
+
+ if ((count < sizeof(buf)) || copy_to_user(buff, buf, len))
+ return -EFAULT;
+
+ *ppos += len; /* increase offset */
+
+ return len;
+}
+
+/**
+ * sde_dbg_reg_base_reg_write - write to reg base hw at offset a given value
+ * @file: file handler
+ * @user_buf: user buffer content from debugfs
+ * @count: size of user buffer
+ * @ppos: position offset of user buffer
+ */
+static ssize_t sde_dbg_reg_base_reg_write(struct file *file,
+ const char __user *user_buf, size_t count, loff_t *ppos)
+{
+ struct sde_dbg_reg_base *dbg = file->private_data;
+ size_t off;
+ u32 data, cnt;
+ char buf[24];
+
+ if (!dbg)
+ return -ENODEV;
+
+ if (count >= sizeof(buf))
+ return -EFAULT;
+
+ if (copy_from_user(buf, user_buf, count))
+ return -EFAULT;
+
+ buf[count] = 0; /* end of string */
+
+ cnt = sscanf(buf, "%zx %x", &off, &data);
+
+ if (cnt < 2)
+ return -EFAULT;
+
+ if (off >= dbg->max_offset)
+ return -EFAULT;
+
+ _sde_dbg_enable_power(true);
+
+ writel_relaxed(data, dbg->base + off);
+
+ _sde_dbg_enable_power(false);
+
+ pr_debug("addr=%zx data=%x\n", off, data);
+
+ return count;
+}
+
+/**
+ * sde_dbg_reg_base_reg_read - read len from reg base hw at current offset
+ * @file: file handler
+ * @user_buf: user buffer content from debugfs
+ * @count: size of user buffer
+ * @ppos: position offset of user buffer
+ */
+static ssize_t sde_dbg_reg_base_reg_read(struct file *file,
+ char __user *user_buf, size_t count, loff_t *ppos)
+{
+ struct sde_dbg_reg_base *dbg = file->private_data;
+ size_t len;
+
+ if (!dbg) {
+ pr_err("invalid handle\n");
+ return -ENODEV;
+ }
+
+ if (!dbg->buf) {
+ char *hwbuf, *hwbuf_cur;
+ char dump_buf[64];
+ char __iomem *ioptr;
+ int cnt, tot;
+
+ dbg->buf_len = sizeof(dump_buf) *
+ DIV_ROUND_UP(dbg->cnt, ROW_BYTES);
+
+ if (dbg->buf_len % sizeof(u32))
+ return -EINVAL;
+
+ dbg->buf = kzalloc(dbg->buf_len, GFP_KERNEL);
+
+ if (!dbg->buf)
+ return -ENOMEM;
+
+ hwbuf = kzalloc(dbg->buf_len, GFP_KERNEL);
+ if (!hwbuf) {
+ kfree(dbg->buf);
+ return -ENOMEM;
+ }
+ hwbuf_cur = hwbuf;
+
+ ioptr = dbg->base + dbg->off;
+ tot = 0;
+
+ _sde_dbg_enable_power(true);
+
+ memcpy_fromio(hwbuf, ioptr, dbg->buf_len);
+
+ _sde_dbg_enable_power(false);
+
+ for (cnt = dbg->cnt; cnt > 0; cnt -= ROW_BYTES) {
+ hex_dump_to_buffer(hwbuf_cur,
+ min(cnt, ROW_BYTES),
+ ROW_BYTES, GROUP_BYTES, dump_buf,
+ sizeof(dump_buf), false);
+ len = scnprintf(dbg->buf + tot, dbg->buf_len - tot,
+ "0x%08x: %s\n",
+ ((int) (unsigned long) hwbuf_cur) -
+ ((int) (unsigned long) dbg->base),
+ dump_buf);
+
+ hwbuf_cur += ROW_BYTES;
+ tot += len;
+ if (tot >= dbg->buf_len)
+ break;
+ }
+
+ dbg->buf_len = tot;
+ kfree(hwbuf);
+ }
+
+ if (*ppos >= dbg->buf_len)
+ return 0; /* done reading */
+
+ len = min(count, dbg->buf_len - (size_t) *ppos);
+ if (copy_to_user(user_buf, dbg->buf + *ppos, len)) {
+ pr_err("failed to copy to user\n");
+ return -EFAULT;
+ }
+
+ *ppos += len; /* increase offset */
+
+ return len;
+}
+
+static const struct file_operations sde_off_fops = {
+ .open = sde_dbg_debugfs_open,
+ .release = sde_dbg_reg_base_release,
+ .read = sde_dbg_reg_base_offset_read,
+ .write = sde_dbg_reg_base_offset_write,
+};
+
+static const struct file_operations sde_reg_fops = {
+ .open = sde_dbg_debugfs_open,
+ .release = sde_dbg_reg_base_release,
+ .read = sde_dbg_reg_base_reg_read,
+ .write = sde_dbg_reg_base_reg_write,
+};
+
+int sde_dbg_reg_register_base(const char *name, void __iomem *base,
+ size_t max_offset)
+{
+ struct sde_dbg_base *dbg_base = &sde_dbg_base;
+ struct sde_dbg_reg_base *reg_base;
+ struct dentry *ent_off, *ent_reg;
+ char dn[80] = "";
+ int prefix_len = 0;
+
+ reg_base = kzalloc(sizeof(*reg_base), GFP_KERNEL);
+ if (!reg_base)
+ return -ENOMEM;
+
+ if (name)
+ strlcpy(reg_base->name, name, sizeof(reg_base->name));
+ reg_base->base = base;
+ reg_base->max_offset = max_offset;
+ reg_base->off = 0;
+ reg_base->cnt = DEFAULT_BASE_REG_CNT;
+ reg_base->reg_dump = NULL;
+
+ if (name)
+ prefix_len = snprintf(dn, sizeof(dn), "%s_", name);
+ strlcpy(dn + prefix_len, "off", sizeof(dn) - prefix_len);
+ ent_off = debugfs_create_file(dn, 0600, dbg_base->root, reg_base,
+ &sde_off_fops);
+ if (IS_ERR_OR_NULL(ent_off)) {
+ pr_err("debugfs_create_file: offset fail\n");
+ goto off_fail;
+ }
+
+ strlcpy(dn + prefix_len, "reg", sizeof(dn) - prefix_len);
+ ent_reg = debugfs_create_file(dn, 0600, dbg_base->root, reg_base,
+ &sde_reg_fops);
+ if (IS_ERR_OR_NULL(ent_reg)) {
+ pr_err("debugfs_create_file: reg fail\n");
+ goto reg_fail;
+ }
+
+ /* Initialize list to make sure check for null list will be valid */
+ INIT_LIST_HEAD(&reg_base->sub_range_list);
+
+ pr_debug("%s base: %pK max_offset 0x%zX\n", reg_base->name,
+ reg_base->base, reg_base->max_offset);
+
+ list_add(&reg_base->reg_base_head, &dbg_base->reg_base_list);
+
+ return 0;
+reg_fail:
+ debugfs_remove(ent_off);
+off_fail:
+ kfree(reg_base);
+ return -ENODEV;
+}
+
+void sde_dbg_reg_register_dump_range(const char *base_name,
+ const char *range_name, u32 offset_start, u32 offset_end,
+ uint32_t xin_id)
+{
+ struct sde_dbg_reg_base *reg_base;
+ struct sde_dbg_reg_range *range;
+
+ reg_base = _sde_dump_get_blk_addr(base_name);
+ if (!reg_base) {
+ pr_err("error: for range %s unable to locate base %s\n",
+ range_name, base_name);
+ return;
+ }
+
+ if (!range_name || strlen(range_name) == 0) {
+ pr_err("%pS: bad range name, base_name %s, offset_start 0x%X, end 0x%X\n",
+ __builtin_return_address(0), base_name,
+ offset_start, offset_end);
+ return;
+ }
+
+ if (offset_end - offset_start < REG_DUMP_ALIGN ||
+ offset_start > offset_end) {
+ pr_err("%pS: bad range, base_name %s, range_name %s, offset_start 0x%X, end 0x%X\n",
+ __builtin_return_address(0), base_name,
+ range_name, offset_start, offset_end);
+ return;
+ }
+
+ range = kzalloc(sizeof(*range), GFP_KERNEL);
+ if (!range)
+ return;
+
+ strlcpy(range->range_name, range_name, sizeof(range->range_name));
+ range->offset.start = offset_start;
+ range->offset.end = offset_end;
+ range->xin_id = xin_id;
+ list_add_tail(&range->head, &reg_base->sub_range_list);
+
+ pr_debug("base %s, range %s, start 0x%X, end 0x%X\n",
+ base_name, range->range_name,
+ range->offset.start, range->offset.end);
+}
+
+void sde_dbg_set_sde_top_offset(u32 blk_off)
+{
+ sde_dbg_base.dbgbus_sde.top_blk_off = blk_off;
+}
diff --git a/drivers/gpu/drm/msm/sde_dbg.h b/drivers/gpu/drm/msm/sde_dbg.h
index 271c41f05ce5..74fd4c94b490 100644
--- a/drivers/gpu/drm/msm/sde_dbg.h
+++ b/drivers/gpu/drm/msm/sde_dbg.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2016, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2016-2017, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -29,34 +29,288 @@ enum sde_dbg_evtlog_flag {
SDE_EVTLOG_ALL = BIT(7)
};
+enum sde_dbg_dump_flag {
+ SDE_DBG_DUMP_IN_LOG = BIT(0),
+ SDE_DBG_DUMP_IN_MEM = BIT(1),
+};
+
+#ifdef CONFIG_DRM_SDE_EVTLOG_DEBUG
+#define SDE_EVTLOG_DEFAULT_ENABLE 1
+#else
+#define SDE_EVTLOG_DEFAULT_ENABLE 0
+#endif
+
+/*
+ * evtlog will print this number of entries when it is called through
+ * sysfs node or panic. This prevents kernel log from evtlog message
+ * flood.
+ */
+#define SDE_EVTLOG_PRINT_ENTRY 256
+
+/*
+ * evtlog keeps this number of entries in memory for debug purpose. This
+ * number must be greater than print entry to prevent out of bound evtlog
+ * entry array access.
+ */
+#define SDE_EVTLOG_ENTRY (SDE_EVTLOG_PRINT_ENTRY * 4)
+#define SDE_EVTLOG_MAX_DATA 15
+#define SDE_EVTLOG_BUF_MAX 512
+#define SDE_EVTLOG_BUF_ALIGN 32
+
+struct sde_dbg_power_ctrl {
+ void *handle;
+ void *client;
+ int (*enable_fn)(void *handle, void *client, bool enable);
+};
+
+struct sde_dbg_evtlog_log {
+ u32 counter;
+ s64 time;
+ const char *name;
+ int line;
+ u32 data[SDE_EVTLOG_MAX_DATA];
+ u32 data_cnt;
+ int pid;
+};
+
+struct sde_dbg_evtlog {
+ struct sde_dbg_evtlog_log logs[SDE_EVTLOG_ENTRY];
+ u32 first;
+ u32 last;
+ u32 curr;
+ u32 next;
+ u32 enable;
+ spinlock_t spin_lock;
+};
+
+extern struct sde_dbg_evtlog *sde_dbg_base_evtlog;
+
+/**
+ * SDE_EVT32 - Write a list of 32bit values to the event log, default area
+ * ... - variable arguments
+ */
+#define SDE_EVT32(...) sde_evtlog_log(sde_dbg_base_evtlog, __func__, \
+ __LINE__, SDE_EVTLOG_DEFAULT, ##__VA_ARGS__, \
+ SDE_EVTLOG_DATA_LIMITER)
+
/**
- * SDE_EVT32 - Write an list of 32bit values as an event into the event log
+ * SDE_EVT32_IRQ - Write a list of 32bit values to the event log, IRQ area
* ... - variable arguments
*/
-#define SDE_EVT32(...) sde_evtlog(__func__, __LINE__, SDE_EVTLOG_DEFAULT, \
- ##__VA_ARGS__, SDE_EVTLOG_DATA_LIMITER)
-#define SDE_EVT32_IRQ(...) sde_evtlog(__func__, __LINE__, SDE_EVTLOG_IRQ, \
- ##__VA_ARGS__, SDE_EVTLOG_DATA_LIMITER)
+#define SDE_EVT32_IRQ(...) sde_evtlog_log(sde_dbg_base_evtlog, __func__, \
+ __LINE__, SDE_EVTLOG_IRQ, ##__VA_ARGS__, \
+ SDE_EVTLOG_DATA_LIMITER)
-#define SDE_DBG_DUMP(...) \
- sde_dbg_dump(false, __func__, ##__VA_ARGS__, \
+/**
+ * SDE_DBG_DUMP - trigger dumping of all sde_dbg facilities
+ * @va_args: list of named register dump ranges and regions to dump, as
+ * registered previously through sde_dbg_reg_register_base and
+ * sde_dbg_reg_register_dump_range.
+ * Including the special name "panic" will trigger a panic after
+ * the dumping work has completed.
+ */
+#define SDE_DBG_DUMP(...) sde_dbg_dump(false, __func__, ##__VA_ARGS__, \
SDE_DBG_DUMP_DATA_LIMITER)
-#define SDE_DBG_DUMP_WQ(...) \
- sde_dbg_dump(true, __func__, ##__VA_ARGS__, \
+/**
+ * SDE_DBG_DUMP_WQ - trigger dumping of all sde_dbg facilities, queuing the work
+ * @va_args: list of named register dump ranges and regions to dump, as
+ * registered previously through sde_dbg_reg_register_base and
+ * sde_dbg_reg_register_dump_range.
+ * Including the special name "panic" will trigger a panic after
+ * the dumping work has completed.
+ */
+#define SDE_DBG_DUMP_WQ(...) sde_dbg_dump(true, __func__, ##__VA_ARGS__, \
SDE_DBG_DUMP_DATA_LIMITER)
#if defined(CONFIG_DEBUG_FS)
-int sde_evtlog_init(struct dentry *debugfs_root);
-void sde_evtlog_destroy(void);
-void sde_evtlog(const char *name, int line, int flag, ...);
-void sde_dbg_dump(bool queue, const char *name, ...);
+/**
+ * sde_evtlog_init - allocate a new event log object
+ * Returns: evtlog or -ERROR
+ */
+struct sde_dbg_evtlog *sde_evtlog_init(void);
+
+/**
+ * sde_evtlog_destroy - destroy previously allocated event log
+ * @evtlog: pointer to evtlog
+ * Returns: none
+ */
+void sde_evtlog_destroy(struct sde_dbg_evtlog *evtlog);
+
+/**
+ * sde_evtlog_log - log an entry into the event log.
+ * log collection may be enabled/disabled entirely via debugfs
+ * log area collection may be filtered by user provided flags via debugfs.
+ * @evtlog: pointer to evtlog
+ * @name: function name of call site
+ * @line: line number of call site
+ * @flag: log area filter flag checked against user's debugfs request
+ * Returns: none
+ */
+void sde_evtlog_log(struct sde_dbg_evtlog *evtlog, const char *name, int line,
+ int flag, ...);
+
+/**
+ * sde_evtlog_dump_all - print all entries in event log to kernel log
+ * @evtlog: pointer to evtlog
+ * Returns: none
+ */
+void sde_evtlog_dump_all(struct sde_dbg_evtlog *evtlog);
+
+/**
+ * sde_evtlog_is_enabled - check whether log collection is enabled for given
+ * event log and log area flag
+ * @evtlog: pointer to evtlog
+ * @flag: log area filter flag
+ * Returns: none
+ */
+bool sde_evtlog_is_enabled(struct sde_dbg_evtlog *evtlog, u32 flag);
+
+/**
+ * sde_evtlog_dump_to_buffer - print content of event log to the given buffer
+ * @evtlog: pointer to evtlog
+ * @evtlog_buf: target buffer to print into
+ * @evtlog_buf_size: size of target buffer
+ * Returns: number of bytes written to buffer
+ */
+ssize_t sde_evtlog_dump_to_buffer(struct sde_dbg_evtlog *evtlog,
+ char *evtlog_buf, ssize_t evtlog_buf_size);
+
+/**
+ * sde_dbg_init_dbg_buses - initialize debug bus dumping support for the chipset
+ * @hwversion: Chipset revision
+ */
+void sde_dbg_init_dbg_buses(u32 hwversion);
+
+/**
+ * sde_dbg_init - initialize global sde debug facilities: evtlog, regdump
+ * @debugfs_root: debugfs root in which to create sde debug entries
+ * @dev: device handle
+ * @power_ctrl: power control callback structure for enabling clocks
+ * during register dumping
+ * Returns: 0 or -ERROR
+ */
+int sde_dbg_init(struct dentry *debugfs_root, struct device *dev,
+ struct sde_dbg_power_ctrl *power_ctrl);
+
+/**
+ * sde_dbg_destroy - destroy the global sde debug facilities
+ * Returns: none
+ */
+void sde_dbg_destroy(void);
+
+/**
+ * sde_dbg_dump - trigger dumping of all sde_dbg facilities
+ * @queue_work: whether to queue the dumping work to the work_struct
+ * @name: string indicating origin of dump
+ * @va_args: list of named register dump ranges and regions to dump, as
+ * registered previously through sde_dbg_reg_register_base and
+ * sde_dbg_reg_register_dump_range.
+ * Including the special name "panic" will trigger a panic after
+ * the dumping work has completed.
+ * Returns: none
+ */
+void sde_dbg_dump(bool queue_work, const char *name, ...);
+
+/**
+ * sde_dbg_reg_register_base - register a hw register address section for later
+ * dumping. call this before calling sde_dbg_reg_register_dump_range
+ * to be able to specify sub-ranges within the base hw range.
+ * @name: name of base region
+ * @base: base pointer of region
+ * @max_offset: length of region
+ * Returns: 0 or -ERROR
+ */
+int sde_dbg_reg_register_base(const char *name, void __iomem *base,
+ size_t max_offset);
+
+/**
+ * sde_dbg_reg_register_dump_range - register a hw register sub-region for
+ * later register dumping associated with base specified by
+ * sde_dbg_reg_register_base
+ * @base_name: name of base region
+ * @range_name: name of sub-range within base region
+ * @offset_start: sub-range's start offset from base's base pointer
+ * @offset_end: sub-range's end offset from base's base pointer
+ * @xin_id: xin id
+ * Returns: none
+ */
+void sde_dbg_reg_register_dump_range(const char *base_name,
+ const char *range_name, u32 offset_start, u32 offset_end,
+ uint32_t xin_id);
+
+/**
+ * sde_dbg_set_sde_top_offset - set the target specific offset from mdss base
+ * address of the top registers. Used for accessing debug bus controls.
+ * @blk_off: offset from mdss base of the top block
+ */
+void sde_dbg_set_sde_top_offset(u32 blk_off);
#else
-static inline int sde_evtlog_init(struct dentry *debugfs_root) { return 0; }
-static inline void sde_evtlog(const char *name, int line, flag, ...) {}
-static inline void sde_evtlog_destroy(void) { }
-static inline void sde_dbg_dump(bool queue, const char *name, ...) {}
-#endif
+static inline struct sde_dbg_evtlog *sde_evtlog_init(void)
+{
+ return NULL;
+}
+
+static inline void sde_evtlog_destroy(struct sde_dbg_evtlog *evtlog)
+{
+}
+
+static inline void sde_evtlog_log(struct sde_dbg_evtlog *evtlog,
+ const char *name, int line, int flag, ...)
+{
+}
+
+static inline void sde_evtlog_dump_all(struct sde_dbg_evtlog *evtlog)
+{
+}
+
+static inline bool sde_evtlog_is_enabled(struct sde_dbg_evtlog *evtlog,
+ u32 flag)
+{
+ return false;
+}
+
+static inline ssize_t sde_evtlog_dump_to_buffer(struct sde_dbg_evtlog *evtlog,
+ char *evtlog_buf, ssize_t evtlog_buf_size)
+{
+ return 0;
+}
+
+void sde_dbg_init_dbg_buses(u32 hwversion)
+{
+}
+
+static inline int sde_dbg_init(struct dentry *debugfs_root, struct device *dev,
+ struct sde_dbg_power_ctrl *power_ctrl)
+{
+ return 0;
+}
+
+static inline void sde_dbg_destroy(void)
+{
+}
+
+static inline void sde_dbg_dump(bool queue_work, const char *name, ...)
+{
+}
+
+static inline int sde_dbg_reg_register_base(const char *name,
+ void __iomem *base, size_t max_offset)
+{
+ return 0;
+}
+
+static inline void sde_dbg_reg_register_dump_range(const char *base_name,
+ const char *range_name, u32 offset_start, u32 offset_end,
+ uint32_t xin_id)
+{
+}
+
+void sde_dbg_set_sde_top_offset(u32 blk_off)
+{
+}
+#endif /* defined(CONFIG_DEBUG_FS) */
+
#endif /* SDE_DBG_H_ */
diff --git a/drivers/gpu/drm/msm/sde_dbg_evtlog.c b/drivers/gpu/drm/msm/sde_dbg_evtlog.c
index 72832776659d..759bdab48840 100644
--- a/drivers/gpu/drm/msm/sde_dbg_evtlog.c
+++ b/drivers/gpu/drm/msm/sde_dbg_evtlog.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2016, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2016-2017, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -10,7 +10,7 @@
* GNU General Public License for more details.
*/
-#define pr_fmt(fmt) "sde_evtlog:[%s] " fmt, __func__
+#define pr_fmt(fmt) "sde_dbg:[%s] " fmt, __func__
#include <linux/delay.h>
#include <linux/spinlock.h>
@@ -18,77 +18,36 @@
#include <linux/debugfs.h>
#include <linux/uaccess.h>
#include <linux/dma-buf.h>
+#include <linux/slab.h>
#include "sde_dbg.h"
#include "sde_trace.h"
-#ifdef CONFIG_DRM_SDE_EVTLOG_DEBUG
-#define SDE_EVTLOG_DEFAULT_ENABLE 1
-#else
-#define SDE_EVTLOG_DEFAULT_ENABLE 0
-#endif
-
-#define SDE_DBG_DEFAULT_PANIC 1
-
-/*
- * evtlog will print this number of entries when it is called through
- * sysfs node or panic. This prevents kernel log from evtlog message
- * flood.
- */
-#define SDE_EVTLOG_PRINT_ENTRY 256
-
-/*
- * evtlog keeps this number of entries in memory for debug purpose. This
- * number must be greater than print entry to prevent out of bound evtlog
- * entry array access.
- */
-#define SDE_EVTLOG_ENTRY (SDE_EVTLOG_PRINT_ENTRY * 4)
-#define SDE_EVTLOG_MAX_DATA 15
-#define SDE_EVTLOG_BUF_MAX 512
-#define SDE_EVTLOG_BUF_ALIGN 32
-
-DEFINE_SPINLOCK(sde_evtloglock);
-
-struct tlog {
- u32 counter;
- s64 time;
- const char *name;
- int line;
- u32 data[SDE_EVTLOG_MAX_DATA];
- u32 data_cnt;
- int pid;
-};
-
-static struct sde_dbg_evtlog {
- struct tlog logs[SDE_EVTLOG_ENTRY];
- u32 first;
- u32 last;
- u32 curr;
- struct dentry *evtlog;
- u32 evtlog_enable;
- u32 panic_on_err;
- struct work_struct evtlog_dump_work;
- bool work_panic;
-} sde_dbg_evtlog;
-
-static inline bool sde_evtlog_is_enabled(u32 flag)
+bool sde_evtlog_is_enabled(struct sde_dbg_evtlog *evtlog, u32 flag)
{
- return (flag & sde_dbg_evtlog.evtlog_enable) ||
- (flag == SDE_EVTLOG_ALL && sde_dbg_evtlog.evtlog_enable);
+ if (!evtlog)
+ return false;
+
+ return (flag & evtlog->enable) ||
+ (flag == SDE_EVTLOG_ALL && evtlog->enable);
}
-void sde_evtlog(const char *name, int line, int flag, ...)
+void sde_evtlog_log(struct sde_dbg_evtlog *evtlog, const char *name, int line,
+ int flag, ...)
{
unsigned long flags;
int i, val = 0;
va_list args;
- struct tlog *log;
+ struct sde_dbg_evtlog_log *log;
+
+ if (!evtlog)
+ return;
- if (!sde_evtlog_is_enabled(flag))
+ if (!sde_evtlog_is_enabled(evtlog, flag))
return;
- spin_lock_irqsave(&sde_evtloglock, flags);
- log = &sde_dbg_evtlog.logs[sde_dbg_evtlog.curr];
+ spin_lock_irqsave(&evtlog->spin_lock, flags);
+ log = &evtlog->logs[evtlog->curr];
log->time = ktime_to_us(ktime_get());
log->name = name;
log->line = line;
@@ -106,26 +65,27 @@ void sde_evtlog(const char *name, int line, int flag, ...)
}
va_end(args);
log->data_cnt = i;
- sde_dbg_evtlog.curr = (sde_dbg_evtlog.curr + 1) % SDE_EVTLOG_ENTRY;
- sde_dbg_evtlog.last++;
+ evtlog->curr = (evtlog->curr + 1) % SDE_EVTLOG_ENTRY;
+ evtlog->last++;
trace_sde_evtlog(name, line, i > 0 ? log->data[0] : 0,
i > 1 ? log->data[1] : 0);
- spin_unlock_irqrestore(&sde_evtloglock, flags);
+ spin_unlock_irqrestore(&evtlog->spin_lock, flags);
}
/* always dump the last entries which are not dumped yet */
-static bool _sde_evtlog_dump_calc_range(void)
+static bool _sde_evtlog_dump_calc_range(struct sde_dbg_evtlog *evtlog)
{
- static u32 next;
bool need_dump = true;
unsigned long flags;
- struct sde_dbg_evtlog *evtlog = &sde_dbg_evtlog;
- spin_lock_irqsave(&sde_evtloglock, flags);
+ if (!evtlog)
+ return false;
+
+ spin_lock_irqsave(&evtlog->spin_lock, flags);
- evtlog->first = next;
+ evtlog->first = evtlog->next;
if (evtlog->last == evtlog->first) {
need_dump = false;
@@ -143,27 +103,34 @@ static bool _sde_evtlog_dump_calc_range(void)
evtlog->last - evtlog->first);
evtlog->first = evtlog->last - SDE_EVTLOG_PRINT_ENTRY;
}
- next = evtlog->first + 1;
+ evtlog->next = evtlog->first + 1;
dump_exit:
- spin_unlock_irqrestore(&sde_evtloglock, flags);
+ spin_unlock_irqrestore(&evtlog->spin_lock, flags);
return need_dump;
}
-static ssize_t sde_evtlog_dump_entry(char *evtlog_buf, ssize_t evtlog_buf_size)
+ssize_t sde_evtlog_dump_to_buffer(struct sde_dbg_evtlog *evtlog,
+ char *evtlog_buf, ssize_t evtlog_buf_size)
{
int i;
ssize_t off = 0;
- struct tlog *log, *prev_log;
+ struct sde_dbg_evtlog_log *log, *prev_log;
unsigned long flags;
- spin_lock_irqsave(&sde_evtloglock, flags);
+ if (!evtlog || !evtlog_buf)
+ return 0;
- log = &sde_dbg_evtlog.logs[sde_dbg_evtlog.first %
- SDE_EVTLOG_ENTRY];
+ /* update markers, exit if nothing to print */
+ if (!_sde_evtlog_dump_calc_range(evtlog))
+ return 0;
+
+ spin_lock_irqsave(&evtlog->spin_lock, flags);
- prev_log = &sde_dbg_evtlog.logs[(sde_dbg_evtlog.first - 1) %
+ log = &evtlog->logs[evtlog->first % SDE_EVTLOG_ENTRY];
+
+ prev_log = &evtlog->logs[(evtlog->first - 1) %
SDE_EVTLOG_ENTRY];
off = snprintf((evtlog_buf + off), (evtlog_buf_size - off), "%s:%-4d",
@@ -175,7 +142,7 @@ static ssize_t sde_evtlog_dump_entry(char *evtlog_buf, ssize_t evtlog_buf_size)
}
off += snprintf((evtlog_buf + off), (evtlog_buf_size - off),
- "=>[%-8d:%-11llu:%9llu][%-4d]:", sde_dbg_evtlog.first,
+ "=>[%-8d:%-11llu:%9llu][%-4d]:", evtlog->first,
log->time, (log->time - prev_log->time), log->pid);
for (i = 0; i < log->data_cnt; i++)
@@ -184,143 +151,37 @@ static ssize_t sde_evtlog_dump_entry(char *evtlog_buf, ssize_t evtlog_buf_size)
off += snprintf((evtlog_buf + off), (evtlog_buf_size - off), "\n");
- spin_unlock_irqrestore(&sde_evtloglock, flags);
+ spin_unlock_irqrestore(&evtlog->spin_lock, flags);
return off;
}
-static void _sde_evtlog_dump_all(void)
-{
- char evtlog_buf[SDE_EVTLOG_BUF_MAX];
-
- while (_sde_evtlog_dump_calc_range()) {
- sde_evtlog_dump_entry(evtlog_buf, SDE_EVTLOG_BUF_MAX);
- pr_info("%s", evtlog_buf);
- }
-}
-
-static void _sde_dump_array(bool dead, const char *name)
-{
- _sde_evtlog_dump_all();
-
- if (dead && sde_dbg_evtlog.panic_on_err)
- panic(name);
-}
-
-static void _sde_dump_work(struct work_struct *work)
+void sde_evtlog_dump_all(struct sde_dbg_evtlog *evtlog)
{
- _sde_dump_array(sde_dbg_evtlog.work_panic, "evtlog_workitem");
-}
-
-void sde_dbg_dump(bool queue, const char *name, ...)
-{
- int i;
- bool dead = false;
- va_list args;
- char *blk_name = NULL;
-
- if (!sde_evtlog_is_enabled(SDE_EVTLOG_DEFAULT))
- return;
+ char buf[SDE_EVTLOG_BUF_MAX];
- if (queue && work_pending(&sde_dbg_evtlog.evtlog_dump_work))
+ if (!evtlog)
return;
- va_start(args, name);
- for (i = 0; i < SDE_EVTLOG_MAX_DATA; i++) {
- blk_name = va_arg(args, char*);
- if (IS_ERR_OR_NULL(blk_name))
- break;
-
- if (!strcmp(blk_name, "panic"))
- dead = true;
- }
- va_end(args);
-
- if (queue) {
- /* schedule work to dump later */
- sde_dbg_evtlog.work_panic = dead;
- schedule_work(&sde_dbg_evtlog.evtlog_dump_work);
- } else {
- _sde_dump_array(dead, name);
- }
+ while (sde_evtlog_dump_to_buffer(evtlog, buf, sizeof(buf)))
+ pr_info("%s", buf);
}
-static int sde_evtlog_dump_open(struct inode *inode, struct file *file)
+struct sde_dbg_evtlog *sde_evtlog_init(void)
{
- /* non-seekable */
- file->f_mode &= ~(FMODE_LSEEK | FMODE_PREAD | FMODE_PWRITE);
- file->private_data = inode->i_private;
- return 0;
-}
-
-static ssize_t sde_evtlog_dump_read(struct file *file, char __user *buff,
- size_t count, loff_t *ppos)
-{
- ssize_t len = 0;
- char evtlog_buf[SDE_EVTLOG_BUF_MAX];
-
- if (_sde_evtlog_dump_calc_range()) {
- len = sde_evtlog_dump_entry(evtlog_buf, SDE_EVTLOG_BUF_MAX);
- if (copy_to_user(buff, evtlog_buf, len))
- return -EFAULT;
- *ppos += len;
- }
-
- return len;
-}
-
-static ssize_t sde_evtlog_dump_write(struct file *file,
- const char __user *user_buf, size_t count, loff_t *ppos)
-{
- _sde_evtlog_dump_all();
-
- if (sde_dbg_evtlog.panic_on_err)
- panic("sde");
-
- return count;
-}
-
-static const struct file_operations sde_evtlog_fops = {
- .open = sde_evtlog_dump_open,
- .read = sde_evtlog_dump_read,
- .write = sde_evtlog_dump_write,
-};
-
-int sde_evtlog_init(struct dentry *debugfs_root)
-{
- int i;
-
- sde_dbg_evtlog.evtlog = debugfs_create_dir("evt_dbg", debugfs_root);
- if (IS_ERR_OR_NULL(sde_dbg_evtlog.evtlog)) {
- pr_err("debugfs_create_dir fail, error %ld\n",
- PTR_ERR(sde_dbg_evtlog.evtlog));
- sde_dbg_evtlog.evtlog = NULL;
- return -ENODEV;
- }
-
- INIT_WORK(&sde_dbg_evtlog.evtlog_dump_work, _sde_dump_work);
- sde_dbg_evtlog.work_panic = false;
-
- for (i = 0; i < SDE_EVTLOG_ENTRY; i++)
- sde_dbg_evtlog.logs[i].counter = i;
-
- debugfs_create_file("dump", 0644, sde_dbg_evtlog.evtlog, NULL,
- &sde_evtlog_fops);
- debugfs_create_u32("enable", 0644, sde_dbg_evtlog.evtlog,
- &sde_dbg_evtlog.evtlog_enable);
- debugfs_create_u32("panic", 0644, sde_dbg_evtlog.evtlog,
- &sde_dbg_evtlog.panic_on_err);
+ struct sde_dbg_evtlog *evtlog;
- sde_dbg_evtlog.evtlog_enable = SDE_EVTLOG_DEFAULT_ENABLE;
- sde_dbg_evtlog.panic_on_err = SDE_DBG_DEFAULT_PANIC;
+ evtlog = kzalloc(sizeof(*evtlog), GFP_KERNEL);
+ if (!evtlog)
+ return ERR_PTR(-ENOMEM);
- pr_info("evtlog_status: enable:%d, panic:%d\n",
- sde_dbg_evtlog.evtlog_enable, sde_dbg_evtlog.panic_on_err);
+ spin_lock_init(&evtlog->spin_lock);
+ evtlog->enable = SDE_EVTLOG_DEFAULT_ENABLE;
- return 0;
+ return evtlog;
}
-void sde_evtlog_destroy(void)
+void sde_evtlog_destroy(struct sde_dbg_evtlog *evtlog)
{
- debugfs_remove(sde_dbg_evtlog.evtlog);
+ kfree(evtlog);
}
diff --git a/drivers/gpu/msm/kgsl_pool.c b/drivers/gpu/msm/kgsl_pool.c
index 685ce3ea968b..4a9997b02155 100644
--- a/drivers/gpu/msm/kgsl_pool.c
+++ b/drivers/gpu/msm/kgsl_pool.c
@@ -412,6 +412,24 @@ void kgsl_pool_free_page(struct page *page)
__free_pages(page, page_order);
}
+/*
+ * Return true if the pool of specified page size is supported
+ * or no pools are supported otherwise return false.
+ */
+bool kgsl_pool_avaialable(int page_size)
+{
+ int i;
+
+ if (!kgsl_num_pools)
+ return true;
+
+ for (i = 0; i < kgsl_num_pools; i++)
+ if (ilog2(page_size >> PAGE_SHIFT) == kgsl_pools[i].pool_order)
+ return true;
+
+ return false;
+}
+
static void kgsl_pool_reserve_pages(void)
{
int i, j;
diff --git a/drivers/gpu/msm/kgsl_pool.h b/drivers/gpu/msm/kgsl_pool.h
index d55e1ada123b..8091afb1ff11 100644
--- a/drivers/gpu/msm/kgsl_pool.h
+++ b/drivers/gpu/msm/kgsl_pool.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2016, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2016-2017, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -40,5 +40,6 @@ void kgsl_exit_page_pools(void);
int kgsl_pool_alloc_page(int *page_size, struct page **pages,
unsigned int pages_len, unsigned int *align);
void kgsl_pool_free_page(struct page *p);
+bool kgsl_pool_avaialable(int size);
#endif /* __KGSL_POOL_H */
diff --git a/drivers/gpu/msm/kgsl_sharedmem.c b/drivers/gpu/msm/kgsl_sharedmem.c
index 27733b068434..d3ba8ca0dc00 100644
--- a/drivers/gpu/msm/kgsl_sharedmem.c
+++ b/drivers/gpu/msm/kgsl_sharedmem.c
@@ -28,7 +28,6 @@
#include "kgsl_device.h"
#include "kgsl_log.h"
#include "kgsl_mmu.h"
-#include "kgsl_pool.h"
/*
* The user can set this from debugfs to force failed memory allocations to
diff --git a/drivers/gpu/msm/kgsl_sharedmem.h b/drivers/gpu/msm/kgsl_sharedmem.h
index 7db8ce0413c2..e5da594b77b8 100644
--- a/drivers/gpu/msm/kgsl_sharedmem.h
+++ b/drivers/gpu/msm/kgsl_sharedmem.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2002,2007-2016, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2002,2007-2017, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -363,6 +363,8 @@ static inline void kgsl_free_sgt(struct sg_table *sgt)
}
}
+#include "kgsl_pool.h"
+
/**
* kgsl_get_page_size() - Get supported pagesize
* @size: Size of the page
@@ -373,11 +375,14 @@ static inline void kgsl_free_sgt(struct sg_table *sgt)
#ifndef CONFIG_ALLOC_BUFFERS_IN_4K_CHUNKS
static inline int kgsl_get_page_size(size_t size, unsigned int align)
{
- if (align >= ilog2(SZ_1M) && size >= SZ_1M)
+ if (align >= ilog2(SZ_1M) && size >= SZ_1M &&
+ kgsl_pool_avaialable(SZ_1M))
return SZ_1M;
- else if (align >= ilog2(SZ_64K) && size >= SZ_64K)
+ else if (align >= ilog2(SZ_64K) && size >= SZ_64K &&
+ kgsl_pool_avaialable(SZ_64K))
return SZ_64K;
- else if (align >= ilog2(SZ_8K) && size >= SZ_8K)
+ else if (align >= ilog2(SZ_8K) && size >= SZ_8K &&
+ kgsl_pool_avaialable(SZ_8K))
return SZ_8K;
else
return PAGE_SIZE;
diff --git a/drivers/input/misc/hbtp_input.c b/drivers/input/misc/hbtp_input.c
index 56f2732334db..f85556079d12 100644
--- a/drivers/input/misc/hbtp_input.c
+++ b/drivers/input/misc/hbtp_input.c
@@ -98,9 +98,10 @@ static struct hbtp_data *hbtp;
static struct kobject *sensor_kobject;
#if defined(CONFIG_FB)
+static int hbtp_fb_early_suspend(struct hbtp_data *ts);
static int hbtp_fb_suspend(struct hbtp_data *ts);
static int hbtp_fb_early_resume(struct hbtp_data *ts);
-static int hbtp_fb_resume(struct hbtp_data *ts);
+static int hbtp_fb_revert_resume(struct hbtp_data *ts);
#endif
#if defined(CONFIG_FB)
@@ -145,6 +146,7 @@ static int fb_notifier_callback(struct notifier_block *self,
lcd_state <= FB_BLANK_NORMAL) {
pr_debug("%s: receives EARLY_BLANK:POWERDOWN\n",
__func__);
+ hbtp_fb_early_suspend(hbtp_data);
} else {
pr_debug("%s: receives EARLY_BLANK:%d in %d state\n",
__func__, blank, lcd_state);
@@ -153,10 +155,12 @@ static int fb_notifier_callback(struct notifier_block *self,
if (blank <= FB_BLANK_NORMAL) {
pr_debug("%s: receives R_EARLY_BALNK:UNBLANK\n",
__func__);
+ hbtp_fb_early_suspend(hbtp_data);
hbtp_fb_suspend(hbtp_data);
} else if (blank == FB_BLANK_POWERDOWN) {
pr_debug("%s: receives R_EARLY_BALNK:POWERDOWN\n",
__func__);
+ hbtp_fb_revert_resume(hbtp_data);
} else {
pr_debug("%s: receives R_EARLY_BALNK:%d in %d state\n",
__func__, blank, lcd_state);
@@ -175,7 +179,6 @@ static int fb_notifier_callback(struct notifier_block *self,
} else if (blank <= FB_BLANK_NORMAL &&
lcd_state == FB_BLANK_POWERDOWN) {
pr_debug("%s: receives BLANK:UNBLANK\n", __func__);
- hbtp_fb_resume(hbtp_data);
} else {
pr_debug("%s: receives BLANK:%d in %d state\n",
__func__, blank, lcd_state);
@@ -1192,6 +1195,43 @@ error:
return rc;
}
+static int hbtp_fb_early_suspend(struct hbtp_data *ts)
+{
+ int rc = 0;
+ char *envp[2] = {HBTP_EVENT_TYPE_DISPLAY, NULL};
+
+ mutex_lock(&hbtp->mutex);
+ if (ts->pdev && (!ts->power_sync_enabled)) {
+ pr_debug("%s: power_sync is not enabled\n", __func__);
+
+ if (ts->input_dev) {
+ kobject_uevent_env(&ts->input_dev->dev.kobj,
+ KOBJ_OFFLINE, envp);
+
+ if (ts->power_sig_enabled) {
+ pr_debug("%s: power_sig is enabled, wait for signal\n",
+ __func__);
+ mutex_unlock(&hbtp->mutex);
+ rc = wait_for_completion_interruptible(
+ &hbtp->power_suspend_sig);
+ if (rc != 0) {
+ pr_err("%s: wait for early suspend is interrupted\n",
+ __func__);
+ }
+ mutex_lock(&hbtp->mutex);
+ pr_debug("%s: Wait is done for early suspend\n",
+ __func__);
+ } else {
+ pr_debug("%s: power_sig is NOT enabled",
+ __func__);
+ }
+ }
+ }
+
+ mutex_unlock(&hbtp->mutex);
+ return rc;
+}
+
static int hbtp_fb_suspend(struct hbtp_data *ts)
{
int rc;
@@ -1217,26 +1257,28 @@ static int hbtp_fb_suspend(struct hbtp_data *ts)
goto err_power_disable;
}
ts->power_suspended = true;
- }
- if (ts->input_dev) {
- kobject_uevent_env(&ts->input_dev->dev.kobj,
- KOBJ_OFFLINE, envp);
+ if (ts->input_dev) {
+ kobject_uevent_env(&ts->input_dev->dev.kobj,
+ KOBJ_OFFLINE, envp);
- if (ts->power_sig_enabled) {
- pr_debug("%s: power_sig is enabled, wait for signal\n",
- __func__);
- mutex_unlock(&hbtp->mutex);
- rc = wait_for_completion_interruptible(
- &hbtp->power_suspend_sig);
- if (rc != 0) {
- pr_err("%s: wait for suspend is interrupted\n",
- __func__);
+ if (ts->power_sig_enabled) {
+ pr_debug("%s: power_sig is enabled, wait for signal\n",
+ __func__);
+ mutex_unlock(&hbtp->mutex);
+ rc = wait_for_completion_interruptible(
+ &hbtp->power_suspend_sig);
+ if (rc != 0) {
+ pr_err("%s: wait for suspend is interrupted\n",
+ __func__);
+ }
+ mutex_lock(&hbtp->mutex);
+ pr_debug("%s: Wait is done for suspend\n",
+ __func__);
+ } else {
+ pr_debug("%s: power_sig is NOT enabled",
+ __func__);
}
- mutex_lock(&hbtp->mutex);
- pr_debug("%s: Wait is done for suspend\n", __func__);
- } else {
- pr_debug("%s: power_sig is NOT enabled", __func__);
}
}
@@ -1278,39 +1320,40 @@ static int hbtp_fb_early_resume(struct hbtp_data *ts)
goto err_pin_enable;
}
+ if (ts->fb_resume_seq_delay) {
+ usleep_range(ts->fb_resume_seq_delay,
+ ts->fb_resume_seq_delay +
+ HBTP_HOLD_DURATION_US);
+ pr_debug("%s: fb_resume_seq_delay = %u\n",
+ __func__, ts->fb_resume_seq_delay);
+ }
+
ts->power_suspended = false;
+ }
- if (ts->input_dev) {
+ if (ts->input_dev) {
- kobject_uevent_env(&ts->input_dev->dev.kobj,
- KOBJ_ONLINE, envp);
+ kobject_uevent_env(&ts->input_dev->dev.kobj,
+ KOBJ_ONLINE, envp);
- if (ts->power_sig_enabled) {
- pr_err("%s: power_sig is enabled, wait for signal\n",
+ if (ts->power_sig_enabled) {
+ pr_err("%s: power_sig is enabled, wait for signal\n",
__func__);
- mutex_unlock(&hbtp->mutex);
- rc = wait_for_completion_interruptible(
+ mutex_unlock(&hbtp->mutex);
+ rc = wait_for_completion_interruptible(
&hbtp->power_resume_sig);
- if (rc != 0) {
- pr_err("%s: wait for resume is interrupted\n",
+ if (rc != 0) {
+ pr_err("%s: wait for resume is interrupted\n",
__func__);
- }
- mutex_lock(&hbtp->mutex);
- pr_debug("%s: wait is done\n", __func__);
- } else {
- pr_debug("%s: power_sig is NOT enabled\n",
- __func__);
- }
-
- if (ts->fb_resume_seq_delay) {
- usleep_range(ts->fb_resume_seq_delay,
- ts->fb_resume_seq_delay +
- HBTP_HOLD_DURATION_US);
- pr_err("%s: fb_resume_seq_delay = %u\n",
- __func__, ts->fb_resume_seq_delay);
}
+ mutex_lock(&hbtp->mutex);
+ pr_debug("%s: wait is done\n", __func__);
+ } else {
+ pr_debug("%s: power_sig is NOT enabled\n",
+ __func__);
}
}
+
mutex_unlock(&hbtp->mutex);
return 0;
@@ -1321,20 +1364,41 @@ err_power_on:
return rc;
}
-static int hbtp_fb_resume(struct hbtp_data *ts)
+static int hbtp_fb_revert_resume(struct hbtp_data *ts)
{
char *envp[2] = {HBTP_EVENT_TYPE_DISPLAY, NULL};
+ int rc = 0;
mutex_lock(&hbtp->mutex);
- if (!ts->power_sync_enabled) {
- pr_debug("%s: power_sync is disabled, send uevent\n", __func__);
+
+ pr_debug("%s: hbtp_fb_revert_resume\n", __func__);
+
+ if (ts->pdev && (!ts->power_sync_enabled)) {
+ pr_debug("%s: power_sync is not enabled\n", __func__);
+
if (ts->input_dev) {
kobject_uevent_env(&ts->input_dev->dev.kobj,
- KOBJ_ONLINE, envp);
+ KOBJ_ONLINE, envp);
+
+ if (ts->power_sig_enabled) {
+ pr_debug("%s: power_sig is enabled, wait for signal\n",
+ __func__);
+ mutex_unlock(&hbtp->mutex);
+ rc = wait_for_completion_interruptible(
+ &hbtp->power_resume_sig);
+ if (rc != 0) {
+ pr_warn("%s: wait for revert resume is interrupted\n",
+ __func__);
+ }
+ pr_debug("%s: wait is done\n", __func__);
+ } else {
+ pr_debug("%s: power_sig is NOT enabled\n",
+ __func__);
+ }
}
}
- mutex_unlock(&hbtp->mutex);
- return 0;
+
+ return rc;
}
static int hbtp_pdev_probe(struct platform_device *pdev)
diff --git a/drivers/iommu/arm-smmu.c b/drivers/iommu/arm-smmu.c
index ce18a512b76a..b30739de79e7 100644
--- a/drivers/iommu/arm-smmu.c
+++ b/drivers/iommu/arm-smmu.c
@@ -1728,7 +1728,7 @@ static void arm_smmu_pgtbl_unlock(struct arm_smmu_domain *smmu_domain,
static int arm_smmu_restore_sec_cfg(struct arm_smmu_device *smmu)
{
int ret;
- u64 scm_ret;
+ u64 scm_ret = 0;
if (!arm_smmu_is_static_cb(smmu))
return 0;
diff --git a/drivers/iommu/dma-iommu.c b/drivers/iommu/dma-iommu.c
index 347a3c17f73a..041c42fb511f 100644
--- a/drivers/iommu/dma-iommu.c
+++ b/drivers/iommu/dma-iommu.c
@@ -514,16 +514,6 @@ void iommu_dma_unmap_sg(struct device *dev, struct scatterlist *sg, int nents,
__iommu_dma_unmap(iommu_get_domain_for_dev(dev), sg_dma_address(sg));
}
-int iommu_dma_supported(struct device *dev, u64 mask)
-{
- /*
- * 'Special' IOMMUs which don't have the same addressing capability
- * as the CPU will have to wait until we have some way to query that
- * before they'll be able to use this framework.
- */
- return 1;
-}
-
int iommu_dma_mapping_error(struct device *dev, dma_addr_t dma_addr)
{
return dma_addr == DMA_ERROR_CODE;
diff --git a/drivers/leds/leds-qpnp-wled.c b/drivers/leds/leds-qpnp-wled.c
index bfa7d29701da..c85b3e42c8c8 100644
--- a/drivers/leds/leds-qpnp-wled.c
+++ b/drivers/leds/leds-qpnp-wled.c
@@ -537,6 +537,11 @@ static int qpnp_wled_set_level(struct qpnp_wled *wled, int level)
{
int i, rc;
u8 reg;
+ u16 low_limit = WLED_MAX_LEVEL_4095 * 4 / 1000;
+
+ /* WLED's lower limit of operation is 0.4% */
+ if (level > 0 && level < low_limit)
+ level = low_limit;
/* set brightness registers */
for (i = 0; i < wled->max_strings; i++) {
diff --git a/drivers/media/platform/msm/ais/msm.c b/drivers/media/platform/msm/ais/msm.c
index 2a1ec86118c5..a3a742182e76 100644
--- a/drivers/media/platform/msm/ais/msm.c
+++ b/drivers/media/platform/msm/ais/msm.c
@@ -391,6 +391,9 @@ static void msm_add_sd_in_position(struct msm_sd_subdev *msm_subdev,
struct msm_sd_subdev *temp_sd;
list_for_each_entry(temp_sd, sd_list, list) {
+ if (temp_sd == msm_subdev) {
+ return;
+ }
if (msm_subdev->close_seq < temp_sd->close_seq) {
list_add_tail(&msm_subdev->list, &temp_sd->list);
return;
diff --git a/drivers/media/platform/msm/ais/sensor/msm_sensor.c b/drivers/media/platform/msm/ais/sensor/msm_sensor.c
index a276b03e5294..9655fad5b62b 100644
--- a/drivers/media/platform/msm/ais/sensor/msm_sensor.c
+++ b/drivers/media/platform/msm/ais/sensor/msm_sensor.c
@@ -10,6 +10,12 @@
* GNU General Public License for more details.
*/
+#include <media/v4l2-subdev.h>
+#include <media/v4l2-dev.h>
+#include <media/v4l2-ioctl.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-fh.h>
+#include <media/v4l2-event.h>
#include "msm_sensor.h"
#include "msm_sd.h"
#include "msm_cci.h"
@@ -21,6 +27,7 @@
#undef CDBG
#define CDBG(fmt, args...) pr_debug(fmt, ##args)
+#define MAX_SENSOR_V4l2_EVENTS 100
static struct msm_camera_i2c_fn_t msm_sensor_cci_func_tbl;
static struct msm_camera_i2c_fn_t msm_sensor_secure_func_tbl;
@@ -405,12 +412,26 @@ static long msm_sensor_subdev_do_ioctl(
{
struct video_device *vdev = video_devdata(file);
struct v4l2_subdev *sd = vdev_to_v4l2_subdev(vdev);
-
+ struct v4l2_fh *vfh = file->private_data;
switch (cmd) {
case VIDIOC_MSM_SENSOR_CFG32:
cmd = VIDIOC_MSM_SENSOR_CFG;
+ case VIDIOC_DQEVENT: {
+ if (!(sd->flags & V4L2_SUBDEV_FL_HAS_EVENTS))
+ return -ENOIOCTLCMD;
+ return v4l2_event_dequeue(vfh, arg,
+ file->f_flags & O_NONBLOCK);
+ }
+ break;
+ case VIDIOC_SUBSCRIBE_EVENT:
+ pr_debug("msm_sensor_subdev_do_ioctl:VIDIOC_SUBSCRIBE_EVENT");
+ return v4l2_subdev_call(sd, core, subscribe_event, vfh, arg);
+
+ case VIDIOC_UNSUBSCRIBE_EVENT:
+ return v4l2_subdev_call(sd, core, unsubscribe_event, vfh, arg);
default:
- return msm_sensor_subdev_ioctl(sd, cmd, arg);
+ pr_debug("msm_sensor.c msm_sensor_subdev_do_ioctl");
+ return v4l2_subdev_call(sd, core, ioctl, cmd, arg);
}
}
@@ -1459,8 +1480,108 @@ static int msm_sensor_power(struct v4l2_subdev *sd, int on)
return rc;
}
+
+static u32 msm_sensor_evt_mask_to_sensor_event(u32 evt_mask)
+{
+ u32 evt_id = SENSOR_EVENT_SUBS_MASK_NONE;
+
+ switch (evt_mask) {
+ case SENSOR_EVENT_MASK_INDEX_SIGNAL_STATUS:
+ evt_id = SENSOR_EVENT_SIGNAL_STATUS;
+ break;
+ default:
+ evt_id = SENSOR_EVENT_SUBS_MASK_NONE;
+ break;
+ }
+
+ return evt_id;
+}
+
+static int msm_sensor_subscribe_event_mask(struct v4l2_fh *fh,
+ struct v4l2_event_subscription *sub, int evt_mask_index,
+ u32 evt_id, bool subscribe_flag)
+{
+ int rc = 0;
+
+ sub->type = evt_id;
+
+ if (subscribe_flag)
+ rc = v4l2_event_subscribe(fh, sub,
+ MAX_SENSOR_V4l2_EVENTS, NULL);
+ else
+ rc = v4l2_event_unsubscribe(fh, sub);
+ if (rc != 0) {
+ pr_err("%s: Subs event_type =0x%x failed\n",
+ __func__, sub->type);
+ return rc;
+ }
+ return rc;
+}
+
+static int msm_sensor_process_event_subscription(struct v4l2_fh *fh,
+ struct v4l2_event_subscription *sub, bool subscribe_flag)
+{
+ int rc = 0, evt_mask_index = 0;
+ u32 evt_mask = sub->type;
+ u32 evt_id = 0;
+
+ if (SENSOR_EVENT_SUBS_MASK_NONE == evt_mask) {
+ pr_err("%s: Subs event_type is None=0x%x\n",
+ __func__, evt_mask);
+ return 0;
+ }
+
+ evt_mask_index = SENSOR_EVENT_MASK_INDEX_SIGNAL_STATUS;
+ if (evt_mask & (1<<evt_mask_index)) {
+ evt_id =
+ msm_sensor_evt_mask_to_sensor_event(
+ evt_mask_index);
+ rc = msm_sensor_subscribe_event_mask(fh, sub,
+ evt_mask_index, evt_id, subscribe_flag);
+ if (rc != 0) {
+ pr_err("%s: Subs event index:%d failed\n",
+ __func__, evt_mask_index);
+ return rc;
+ }
+ }
+
+ return rc;
+}
+
+int msm_sensor_send_event(struct msm_sensor_ctrl_t *s_ctrl,
+ uint32_t event_type,
+ struct msm_sensor_event_data *event_data)
+{
+ struct v4l2_event sensor_event;
+
+ memset(&sensor_event, 0, sizeof(struct v4l2_event));
+ sensor_event.id = 0;
+ sensor_event.type = event_type;
+
+ memcpy(&sensor_event.u.data[0], event_data,
+ sizeof(struct msm_sensor_event_data));
+ v4l2_event_queue(s_ctrl->msm_sd.sd.devnode, &sensor_event);
+ return 0;
+}
+
+static int msm_sensor_subscribe_event(struct v4l2_subdev *sd,
+ struct v4l2_fh *fh,
+ struct v4l2_event_subscription *sub)
+{
+ return msm_sensor_process_event_subscription(fh, sub, true);
+}
+
+static int msm_sensor_unsubscribe_event(struct v4l2_subdev *sd,
+ struct v4l2_fh *fh,
+ struct v4l2_event_subscription *sub)
+{
+ return msm_sensor_process_event_subscription(fh, sub, false);
+}
+
static struct v4l2_subdev_core_ops msm_sensor_subdev_core_ops = {
.ioctl = msm_sensor_subdev_ioctl,
+ .subscribe_event = msm_sensor_subscribe_event,
+ .unsubscribe_event = msm_sensor_unsubscribe_event,
.s_power = msm_sensor_power,
};
diff --git a/drivers/media/platform/msm/ais/sensor/msm_sensor.h b/drivers/media/platform/msm/ais/sensor/msm_sensor.h
index eacd3b05420c..b742d06d3baa 100644
--- a/drivers/media/platform/msm/ais/sensor/msm_sensor.h
+++ b/drivers/media/platform/msm/ais/sensor/msm_sensor.h
@@ -90,10 +90,18 @@ struct msm_sensor_ctrl_t {
uint32_t set_mclk_23880000;
uint8_t is_csid_tg_mode;
uint32_t is_secure;
-
+ /* Interrupt GPIOs */
+ struct gpio gpio_array[1];
+ /* device status and Flags */
+ int irq;
struct msm_sensor_init_t s_init;
+ /* worker to handle interrupts */
+ struct delayed_work irq_delayed_work;
};
+int msm_sensor_send_event(struct msm_sensor_ctrl_t *s_ctrl,
+ uint32_t event_type, struct msm_sensor_event_data *event_data);
+
int msm_sensor_config(struct msm_sensor_ctrl_t *s_ctrl, void *argp);
int msm_sensor_power_up(struct msm_sensor_ctrl_t *s_ctrl);
diff --git a/drivers/media/platform/msm/ais/sensor/msm_sensor_driver.c b/drivers/media/platform/msm/ais/sensor/msm_sensor_driver.c
index c02972e5e993..5e34016d199c 100644
--- a/drivers/media/platform/msm/ais/sensor/msm_sensor_driver.c
+++ b/drivers/media/platform/msm/ais/sensor/msm_sensor_driver.c
@@ -105,7 +105,11 @@ static int32_t msm_sensor_driver_create_i2c_v4l_subdev
s_ctrl->msm_sd.sd.entity.name = s_ctrl->msm_sd.sd.name;
s_ctrl->sensordata->sensor_info->session_id = session_id;
s_ctrl->msm_sd.close_seq = MSM_SD_CLOSE_2ND_CATEGORY | 0x3;
- msm_sd_register(&s_ctrl->msm_sd);
+ rc = msm_sd_register(&s_ctrl->msm_sd);
+ if (rc < 0) {
+ pr_err("failed: msm_sd_register rc %d", rc);
+ return rc;
+ }
msm_sensor_v4l2_subdev_fops = v4l2_subdev_fops;
#ifdef CONFIG_COMPAT
msm_sensor_v4l2_subdev_fops.compat_ioctl32 =
@@ -128,13 +132,20 @@ static int32_t msm_sensor_driver_create_v4l_subdev
s_ctrl->sensordata->sensor_name);
v4l2_set_subdevdata(&s_ctrl->msm_sd.sd, s_ctrl->pdev);
s_ctrl->msm_sd.sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
+ s_ctrl->msm_sd.sd.flags |= V4L2_SUBDEV_FL_HAS_EVENTS;
media_entity_init(&s_ctrl->msm_sd.sd.entity, 0, NULL, 0);
s_ctrl->msm_sd.sd.entity.type = MEDIA_ENT_T_V4L2_SUBDEV;
s_ctrl->msm_sd.sd.entity.group_id = MSM_CAMERA_SUBDEV_SENSOR;
s_ctrl->msm_sd.sd.entity.name = s_ctrl->msm_sd.sd.name;
s_ctrl->msm_sd.close_seq = MSM_SD_CLOSE_2ND_CATEGORY | 0x3;
- msm_sd_register(&s_ctrl->msm_sd);
+ rc = msm_sd_register(&s_ctrl->msm_sd);
+ if (rc < 0) {
+ pr_err("failed: msm_sd_register rc %d", rc);
+ return rc;
+ }
msm_cam_copy_v4l2_subdev_fops(&msm_sensor_v4l2_subdev_fops);
+ msm_sensor_v4l2_subdev_fops.unlocked_ioctl =
+ msm_sensor_subdev_fops_ioctl;
#ifdef CONFIG_COMPAT
msm_sensor_v4l2_subdev_fops.compat_ioctl32 =
msm_sensor_subdev_fops_ioctl;
@@ -624,6 +635,56 @@ static void msm_sensor_fill_sensor_info(struct msm_sensor_ctrl_t *s_ctrl,
strlcpy(entity_name, s_ctrl->msm_sd.sd.entity.name, MAX_SENSOR_NAME);
}
+static irqreturn_t bridge_irq(int irq, void *dev)
+{
+ struct msm_sensor_ctrl_t *s_ctrl = dev;
+
+ pr_err("msm_sensor_driver: received bridge interrupt:0x%x",
+ s_ctrl->sensordata->slave_info->sensor_slave_addr);
+ schedule_delayed_work(&s_ctrl->irq_delayed_work,
+ msecs_to_jiffies(0));
+ return IRQ_HANDLED;
+}
+
+static void bridge_irq_delay_work(struct work_struct *work)
+{
+ struct msm_sensor_ctrl_t *s_ctrl;
+ struct msm_camera_i2c_client *sensor_i2c_client;
+ struct msm_camera_slave_info *slave_info;
+ const char *sensor_name;
+
+ struct msm_sensor_event_data sensor_event;
+
+ s_ctrl = container_of(work, struct msm_sensor_ctrl_t,
+ irq_delayed_work.work);
+ if (!s_ctrl) {
+ pr_err("%s:%d failed: %pK\n",
+ __func__, __LINE__, s_ctrl);
+ goto exit_queue;
+ }
+ sensor_i2c_client = s_ctrl->sensor_i2c_client;
+ slave_info = s_ctrl->sensordata->slave_info;
+ sensor_name = s_ctrl->sensordata->sensor_name;
+
+ if (!sensor_i2c_client || !slave_info || !sensor_name) {
+ pr_err("%s:%d failed: %pK %pK %pK\n",
+ __func__, __LINE__, sensor_i2c_client, slave_info,
+ sensor_name);
+ goto exit_queue;
+ }
+
+ mutex_lock(s_ctrl->msm_sensor_mutex);
+ /* Fill the sensor event */
+ sensor_event.sensor_slave_addr =
+ slave_info->sensor_slave_addr;
+ /* Queue the event */
+ msm_sensor_send_event(s_ctrl, SENSOR_EVENT_SIGNAL_STATUS,
+ &sensor_event);
+ mutex_unlock(s_ctrl->msm_sensor_mutex);
+exit_queue:
+ pr_err("Work IRQ exit");
+}
+
/* static function definition */
int32_t msm_sensor_driver_probe(void *setting,
struct msm_sensor_info_t *probed_info, char *entity_name)
@@ -888,11 +949,6 @@ CSID_TG:
pr_err("%s probe succeeded", slave_info->sensor_name);
- /* Set probe succeeded flag to 1 so that no other camera shall
- * probed on this slot
- */
- s_ctrl->is_probe_succeed = 1;
-
/*
* Update the subdevice id of flash-src based on availability in kernel.
*/
@@ -931,8 +987,66 @@ CSID_TG:
msm_sensor_fill_sensor_info(s_ctrl, probed_info, entity_name);
+ if (slave_info->gpio_intr_config.gpio_num != -1) {
+ /* Configure INTB interrupt */
+ s_ctrl->gpio_array[0].gpio =
+ slave_info->gpio_intr_config.gpio_num;
+ s_ctrl->gpio_array[0].flags = 0;
+ /* Only setup IRQ1 for now... */
+ INIT_DELAYED_WORK(&s_ctrl->irq_delayed_work,
+ bridge_irq_delay_work);
+ rc = gpio_request_array(&s_ctrl->gpio_array[0], 1);
+ if (rc < 0) {
+ pr_err("%s: Failed to request irq_gpio %d",
+ __func__, rc);
+ goto cancel_work;
+ }
+
+ if (gpio_is_valid(s_ctrl->gpio_array[0].gpio)) {
+ rc |= gpio_direction_input(
+ s_ctrl->gpio_array[0].gpio);
+ if (rc) {
+ pr_err("%s: Failed gpio_direction irq %d",
+ __func__, rc);
+ goto cancel_work;
+ } else {
+ pr_err("sensor probe IRQ direction succeeded");
+ }
+ }
+
+ s_ctrl->irq = gpio_to_irq(s_ctrl->gpio_array[0].gpio);
+ if (s_ctrl->irq) {
+ rc = request_irq(s_ctrl->irq, bridge_irq,
+ IRQF_ONESHOT |
+ (slave_info->
+ gpio_intr_config.gpio_trigger),
+ "qcom,camera", s_ctrl);
+ if (rc) {
+ pr_err("%s: Failed request_irq %d",
+ __func__, rc);
+ goto cancel_work;
+ }
+
+ } else {
+ pr_err("%s: Failed gpio_to_irq %d",
+ __func__, rc);
+ rc = -EINVAL;
+ goto cancel_work;
+ }
+
+ /* Keep irq enabled */
+ pr_err("msm_sensor_driver.c irq number = %d", s_ctrl->irq);
+ }
+
+ /*
+ Set probe succeeded flag to 1 so that no other camera shall
+ * probed on this slot
+ */
+ s_ctrl->is_probe_succeed = 1;
return rc;
+cancel_work:
+ cancel_delayed_work(&s_ctrl->irq_delayed_work);
free_camera_info:
kfree(camera_info);
free_slave_info:
@@ -1118,7 +1232,6 @@ static int32_t msm_sensor_driver_parse(struct msm_sensor_ctrl_t *s_ctrl)
/* Store sensor control structure in static database */
g_sctrl[s_ctrl->id] = s_ctrl;
CDBG("g_sctrl[%d] %pK", s_ctrl->id, g_sctrl[s_ctrl->id]);
-
return rc;
FREE_DT_DATA:
@@ -1171,7 +1284,6 @@ static int32_t msm_sensor_driver_platform_probe(struct platform_device *pdev)
/* Fill platform device id*/
pdev->id = s_ctrl->id;
-
/* Fill device in power info */
s_ctrl->sensordata->power_info.dev = &pdev->dev;
diff --git a/drivers/media/platform/msm/ais/sensor/ois/msm_ois.c b/drivers/media/platform/msm/ais/sensor/ois/msm_ois.c
index 4a74e808d86f..3dccb73d9de4 100644
--- a/drivers/media/platform/msm/ais/sensor/ois/msm_ois.c
+++ b/drivers/media/platform/msm/ais/sensor/ois/msm_ois.c
@@ -828,6 +828,10 @@ static long msm_ois_subdev_do_ioctl(
parg = &ois_data;
break;
}
+ break;
+ case VIDIOC_MSM_OIS_CFG:
+ pr_err("%s: invalid cmd 0x%x received\n", __func__, cmd);
+ return -EINVAL;
}
rc = msm_ois_subdev_ioctl(sd, cmd, parg);
diff --git a/drivers/media/platform/msm/camera_v2/camera/camera.c b/drivers/media/platform/msm/camera_v2/camera/camera.c
index df0664b496ba..aeeb5cae3096 100644
--- a/drivers/media/platform/msm/camera_v2/camera/camera.c
+++ b/drivers/media/platform/msm/camera_v2/camera/camera.c
@@ -623,6 +623,7 @@ static int camera_v4l2_open(struct file *filep)
unsigned long opn_idx, idx;
BUG_ON(!pvdev);
+ mutex_lock(&pvdev->video_drvdata_mutex);
rc = camera_v4l2_fh_open(filep);
if (rc < 0) {
pr_err("%s : camera_v4l2_fh_open failed Line %d rc %d\n",
@@ -693,6 +694,7 @@ static int camera_v4l2_open(struct file *filep)
idx |= (1 << find_first_zero_bit((const unsigned long *)&opn_idx,
MSM_CAMERA_STREAM_CNT_BITS));
atomic_cmpxchg(&pvdev->opened, opn_idx, idx);
+ mutex_unlock(&pvdev->video_drvdata_mutex);
return rc;
@@ -707,6 +709,7 @@ stream_fail:
vb2_q_fail:
camera_v4l2_fh_release(filep);
fh_open_fail:
+ mutex_unlock(&pvdev->video_drvdata_mutex);
return rc;
}
@@ -737,6 +740,7 @@ static int camera_v4l2_close(struct file *filep)
if (WARN_ON(!session))
return -EIO;
+ mutex_lock(&pvdev->video_drvdata_mutex);
mutex_lock(&session->close_lock);
opn_idx = atomic_read(&pvdev->opened);
mask = (1 << sp->stream_id);
@@ -778,6 +782,7 @@ static int camera_v4l2_close(struct file *filep)
}
camera_v4l2_fh_release(filep);
+ mutex_unlock(&pvdev->video_drvdata_mutex);
return 0;
}
@@ -924,6 +929,7 @@ int camera_init_v4l2(struct device *dev, unsigned int *session)
*session = pvdev->vdev->num;
atomic_set(&pvdev->opened, 0);
+ mutex_init(&pvdev->video_drvdata_mutex);
video_set_drvdata(pvdev->vdev, pvdev);
device_init_wakeup(&pvdev->vdev->dev, 1);
goto init_end;
diff --git a/drivers/media/platform/msm/camera_v2/common/msm_camera_io_util.c b/drivers/media/platform/msm/camera_v2/common/msm_camera_io_util.c
index 90edadaed1ef..f6d7f5fb8d32 100644
--- a/drivers/media/platform/msm/camera_v2/common/msm_camera_io_util.c
+++ b/drivers/media/platform/msm/camera_v2/common/msm_camera_io_util.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011-2014, The Linux Foundataion. All rights reserved.
+/* Copyright (c) 2011-2014, 2017, The Linux Foundataion. 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
@@ -556,12 +556,16 @@ int msm_camera_enable_vreg(struct device *dev, struct camera_vreg_t *cam_vreg,
continue;
} else
j = i;
- regulator_disable(reg_ptr[j]);
- if (cam_vreg[j].delay > 20)
- msleep(cam_vreg[j].delay);
- else if (cam_vreg[j].delay)
- usleep_range(cam_vreg[j].delay * 1000,
- (cam_vreg[j].delay * 1000) + 1000);
+ if (reg_ptr[j]) {
+ regulator_disable(reg_ptr[j]);
+ if (cam_vreg[j].delay > 20)
+ msleep(cam_vreg[j].delay);
+ else if (cam_vreg[j].delay)
+ usleep_range(
+ cam_vreg[j].delay * 1000,
+ (cam_vreg[j].delay * 1000)
+ + 1000);
+ }
}
}
return rc;
diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp_util.c b/drivers/media/platform/msm/camera_v2/isp/msm_isp_util.c
index e87f2414a879..92b1f2ea871b 100644
--- a/drivers/media/platform/msm/camera_v2/isp/msm_isp_util.c
+++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp_util.c
@@ -196,7 +196,7 @@ uint32_t msm_isp_get_framedrop_period(
return 32;
break;
case SKIP_ALL:
- return 1;
+ return SKIP_ALL;
default:
return 1;
}
diff --git a/drivers/media/platform/msm/camera_v2/msm.c b/drivers/media/platform/msm/camera_v2/msm.c
index 04ca0fba71e5..194a6583103e 100644
--- a/drivers/media/platform/msm/camera_v2/msm.c
+++ b/drivers/media/platform/msm/camera_v2/msm.c
@@ -34,6 +34,7 @@
static struct v4l2_device *msm_v4l2_dev;
static struct list_head ordered_sd_list;
+static struct mutex ordered_sd_mtx;
static struct pm_qos_request msm_v4l2_pm_qos_request;
@@ -409,7 +410,9 @@ int msm_sd_register(struct msm_sd_subdev *msm_subdev)
if (WARN_ON(!msm_v4l2_dev) || WARN_ON(!msm_v4l2_dev->dev))
return -EIO;
+ mutex_lock(&ordered_sd_mtx);
msm_add_sd_in_position(msm_subdev, &ordered_sd_list);
+ mutex_unlock(&ordered_sd_mtx);
return __msm_sd_register_subdev(&msm_subdev->sd);
}
EXPORT_SYMBOL(msm_sd_register);
@@ -743,6 +746,16 @@ static long msm_private_ioctl(struct file *file, void *fh,
if (!event_data)
return -EINVAL;
+ switch (cmd) {
+ case MSM_CAM_V4L2_IOCTL_NOTIFY:
+ case MSM_CAM_V4L2_IOCTL_CMD_ACK:
+ case MSM_CAM_V4L2_IOCTL_NOTIFY_DEBUG:
+ case MSM_CAM_V4L2_IOCTL_NOTIFY_ERROR:
+ break;
+ default:
+ return -ENOTTY;
+ }
+
memset(&event, 0, sizeof(struct v4l2_event));
session_id = event_data->session_id;
stream_id = event_data->stream_id;
@@ -811,11 +824,13 @@ static long msm_private_ioctl(struct file *file, void *fh,
__func__);
}
+ mutex_lock(&ordered_sd_mtx);
if (!list_empty(&msm_v4l2_dev->subdevs)) {
list_for_each_entry(msm_sd, &ordered_sd_list, list)
__msm_sd_notify_freeze_subdevs(msm_sd,
event_data->status);
}
+ mutex_unlock(&ordered_sd_mtx);
}
break;
@@ -1000,9 +1015,11 @@ static int msm_close(struct file *filep)
struct msm_sd_subdev *msm_sd;
/*stop all hardware blocks immediately*/
+ mutex_lock(&ordered_sd_mtx);
if (!list_empty(&msm_v4l2_dev->subdevs))
list_for_each_entry(msm_sd, &ordered_sd_list, list)
__msm_sd_close_subdevs(msm_sd, &sd_close);
+ mutex_unlock(&ordered_sd_mtx);
/* remove msm_v4l2_pm_qos_request */
msm_pm_qos_remove_request();
@@ -1358,6 +1375,7 @@ static int msm_probe(struct platform_device *pdev)
msm_init_queue(msm_session_q);
spin_lock_init(&msm_eventq_lock);
spin_lock_init(&msm_pid_lock);
+ mutex_init(&ordered_sd_mtx);
INIT_LIST_HEAD(&ordered_sd_list);
cam_debugfs_root = debugfs_create_dir(MSM_CAM_LOGSYNC_FILE_BASEDIR,
diff --git a/drivers/media/platform/msm/camera_v2/msm.h b/drivers/media/platform/msm/camera_v2/msm.h
index dce47bc7249c..8bdb14f5c16e 100644
--- a/drivers/media/platform/msm/camera_v2/msm.h
+++ b/drivers/media/platform/msm/camera_v2/msm.h
@@ -46,6 +46,7 @@ extern bool is_daemon_status;
struct msm_video_device {
struct video_device *vdev;
atomic_t opened;
+ struct mutex video_drvdata_mutex;
};
struct msm_queue_head {
diff --git a/drivers/media/platform/msm/sde/rotator/sde_rotator_core.c b/drivers/media/platform/msm/sde/rotator/sde_rotator_core.c
index abf20aef1256..422c7a590a45 100644
--- a/drivers/media/platform/msm/sde/rotator/sde_rotator_core.c
+++ b/drivers/media/platform/msm/sde/rotator/sde_rotator_core.c
@@ -2003,8 +2003,10 @@ static void sde_rotator_cancel_request(struct sde_rot_mgr *mgr,
sde_rot_mgr_unlock(mgr);
for (i = req->count - 1; i >= 0; i--) {
entry = req->entries + i;
- flush_kthread_worker(&entry->commitq->rot_kw);
- flush_kthread_worker(&entry->doneq->rot_kw);
+ if (entry->commitq)
+ flush_kthread_worker(&entry->commitq->rot_kw);
+ if (entry->doneq)
+ flush_kthread_worker(&entry->doneq->rot_kw);
}
sde_rot_mgr_lock(mgr);
SDEROT_DBG("cancel work done\n");
diff --git a/drivers/media/platform/msm/vidc/msm_vdec.c b/drivers/media/platform/msm/vidc/msm_vdec.c
index 0f6389370643..78cced2abd47 100644
--- a/drivers/media/platform/msm/vidc/msm_vdec.c
+++ b/drivers/media/platform/msm/vidc/msm_vdec.c
@@ -1618,6 +1618,8 @@ static int set_max_internal_buffers_size(struct msm_vidc_inst *inst)
get_buff_req_buffer(inst, internal_buffers[i].type);
internal_buffers[i].size = internal_buffers[i].req ?
internal_buffers[i].req->buffer_size : 0;
+ if (internal_buffers[i].req == NULL)
+ continue;
rc = allocate_and_set_internal_bufs(inst,
internal_buffers[i].req,
diff --git a/drivers/media/platform/msm/vidc/msm_vidc_debug.c b/drivers/media/platform/msm/vidc/msm_vidc_debug.c
index 5c13b6fef3ec..2be52b10c84b 100644
--- a/drivers/media/platform/msm/vidc/msm_vidc_debug.c
+++ b/drivers/media/platform/msm/vidc/msm_vidc_debug.c
@@ -445,7 +445,7 @@ struct dentry *msm_vidc_debugfs_init_inst(struct msm_vidc_inst *inst,
dprintk(VIDC_ERR, "Invalid params, inst: %pK\n", inst);
goto exit;
}
- snprintf(debugfs_name, MAX_DEBUGFS_NAME, "inst_%p", inst);
+ snprintf(debugfs_name, MAX_DEBUGFS_NAME, "inst_%pK", inst);
idata = kzalloc(sizeof(struct core_inst_pair), GFP_KERNEL);
if (!idata) {
diff --git a/drivers/misc/qcom/qdsp6v2/audio_utils_aio.c b/drivers/misc/qcom/qdsp6v2/audio_utils_aio.c
index b292ea70fb40..7fa5e326fa0b 100644
--- a/drivers/misc/qcom/qdsp6v2/audio_utils_aio.c
+++ b/drivers/misc/qcom/qdsp6v2/audio_utils_aio.c
@@ -1062,6 +1062,8 @@ static int audio_aio_async_write(struct q6audio_aio *audio,
struct audio_client *ac;
struct audio_aio_write_param param;
+ memset(&param, 0, sizeof(param));
+
if (!audio || !buf_node) {
pr_err("%s NULL pointer audio=[0x%pK], buf_node=[0x%pK]\n",
__func__, audio, buf_node);
diff --git a/drivers/mmc/core/sd.c b/drivers/mmc/core/sd.c
index 5033107f6e26..9bef77ba29fd 100644
--- a/drivers/mmc/core/sd.c
+++ b/drivers/mmc/core/sd.c
@@ -1286,6 +1286,7 @@ static int _mmc_sd_resume(struct mmc_host *host)
if (err) {
pr_err("%s: %s: mmc_sd_init_card_failed (%d)\n",
mmc_hostname(host), __func__, err);
+ mmc_power_off(host);
goto out;
}
mmc_card_clr_suspended(host->card);
diff --git a/drivers/mmc/host/sdhci-msm.c b/drivers/mmc/host/sdhci-msm.c
index 907763ddf234..ab4837128cb2 100644
--- a/drivers/mmc/host/sdhci-msm.c
+++ b/drivers/mmc/host/sdhci-msm.c
@@ -4249,6 +4249,7 @@ static int sdhci_msm_probe(struct platform_device *pdev)
struct resource *tlmm_memres = NULL;
void __iomem *tlmm_mem;
unsigned long flags;
+ bool force_probe;
pr_debug("%s: Enter %s\n", dev_name(&pdev->dev), __func__);
msm_host = devm_kzalloc(&pdev->dev, sizeof(struct sdhci_msm_host),
@@ -4312,8 +4313,13 @@ static int sdhci_msm_probe(struct platform_device *pdev)
goto pltfm_free;
}
+ /* Read property to determine if the probe is forced */
+ force_probe = of_find_property(pdev->dev.of_node,
+ "qcom,force-sdhc1-probe", NULL);
+
/* skip the probe if eMMC isn't a boot device */
- if ((ret == 1) && !sdhci_msm_is_bootdevice(&pdev->dev)) {
+ if ((ret == 1) && !sdhci_msm_is_bootdevice(&pdev->dev)
+ && !force_probe) {
ret = -ENODEV;
goto pltfm_free;
}
diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c
index 0033fea0a800..f9d80b3bbcf9 100644
--- a/drivers/mmc/host/sdhci.c
+++ b/drivers/mmc/host/sdhci.c
@@ -3041,11 +3041,6 @@ static void sdhci_data_irq(struct sdhci_host *host, u32 intmask)
* above in sdhci_cmd_irq().
*/
if (host->cmd && (host->cmd->flags & MMC_RSP_BUSY)) {
- if (intmask & SDHCI_INT_DATA_TIMEOUT) {
- host->cmd->error = -ETIMEDOUT;
- tasklet_schedule(&host->finish_tasklet);
- return;
- }
if (intmask & SDHCI_INT_DATA_END) {
/*
* Some cards handle busy-end interrupt
@@ -3061,6 +3056,11 @@ static void sdhci_data_irq(struct sdhci_host *host, u32 intmask)
if (host->quirks2 &
SDHCI_QUIRK2_IGNORE_DATATOUT_FOR_R1BCMD)
return;
+ if (intmask & SDHCI_INT_DATA_TIMEOUT) {
+ host->cmd->error = -ETIMEDOUT;
+ tasklet_schedule(&host->finish_tasklet);
+ return;
+ }
}
pr_err("%s: Got data interrupt 0x%08x even "
diff --git a/drivers/net/can/spi/Kconfig b/drivers/net/can/spi/Kconfig
index a8001b41c81c..5b315573387e 100644
--- a/drivers/net/can/spi/Kconfig
+++ b/drivers/net/can/spi/Kconfig
@@ -12,4 +12,10 @@ config CAN_RH850
depends on HAS_DMA
---help---
Driver for the Renesas RH850 SPI CAN controller.
+
+config CAN_K61
+ tristate "Freescale K61 SPI CAN controllers"
+ depends on SPI
+ ---help---
+ Driver for the Freescale K61 SPI CAN controllers.
endmenu
diff --git a/drivers/net/can/spi/Makefile b/drivers/net/can/spi/Makefile
index e84da9b8d5ab..375a6cbfbb67 100644
--- a/drivers/net/can/spi/Makefile
+++ b/drivers/net/can/spi/Makefile
@@ -5,3 +5,4 @@
obj-$(CONFIG_CAN_MCP251X) += mcp251x.o
obj-$(CONFIG_CAN_RH850) += rh850.o
+obj-${CONFIG_CAN_K61} += k61.o
diff --git a/drivers/net/can/spi/k61.c b/drivers/net/can/spi/k61.c
new file mode 100644
index 000000000000..a567cc653e46
--- /dev/null
+++ b/drivers/net/can/spi/k61.c
@@ -0,0 +1,927 @@
+/* Copyright (c) 2016-2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/interrupt.h>
+#include <linux/module.h>
+#include <linux/errno.h>
+#include <linux/netdevice.h>
+#include <linux/workqueue.h>
+#include <linux/spi/spi.h>
+#include <linux/can.h>
+#include <linux/can/dev.h>
+#include <linux/can/error.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/of_gpio.h>
+#include <linux/uaccess.h>
+
+#define DEBUG_K61 0
+#if DEBUG_K61 == 1
+#define LOGDI(...) dev_info(&priv_data->spidev->dev, __VA_ARGS__)
+#define LOGNI(...) netdev_info(netdev, __VA_ARGS__)
+#else
+#define LOGDI(...)
+#define LOGNI(...)
+#endif
+#define LOGDE(...) dev_err(&priv_data->spidev->dev, __VA_ARGS__)
+#define LOGNE(...) netdev_err(netdev, __VA_ARGS__)
+
+#define MAX_TX_BUFFERS 1
+#define XFER_BUFFER_SIZE 64
+#define K61_CLOCK 120000000
+#define K61_MAX_CHANNELS 1
+#define K61_FW_QUERY_RETRY_COUNT 3
+
+struct k61_can {
+ struct net_device *netdev;
+ struct spi_device *spidev;
+
+ struct mutex spi_lock; /* SPI device lock */
+
+ struct workqueue_struct *tx_wq;
+ char *tx_buf, *rx_buf;
+ int xfer_length;
+ atomic_t msg_seq;
+
+ atomic_t netif_queue_stop;
+ struct completion response_completion;
+ int reset;
+ int wait_cmd;
+ int cmd_result;
+};
+
+struct k61_netdev_privdata {
+ struct can_priv can;
+ struct k61_can *k61_can;
+};
+
+struct k61_tx_work {
+ struct work_struct work;
+ struct sk_buff *skb;
+ struct net_device *netdev;
+};
+
+/* Message definitions */
+struct spi_mosi { /* TLV for MOSI line */
+ u8 cmd;
+ u8 len;
+ u16 seq;
+ u8 data[];
+} __packed;
+
+struct spi_miso { /* TLV for MISO line */
+ u8 cmd;
+ u8 len;
+ u16 seq; /* should match seq field from request, or 0 for unsols */
+ u8 data[];
+} __packed;
+
+#define CMD_GET_FW_VERSION 0x81
+#define CMD_CAN_SEND_FRAME 0x82
+#define CMD_CAN_ADD_FILTER 0x83
+#define CMD_CAN_REMOVE_FILTER 0x84
+#define CMD_CAN_RECEIVE_FRAME 0x85
+#define CMD_CAN_DATA_BUFF_ADD 0x87
+#define CMD_CAN_DATA_BUFF_REMOVE 0x88
+#define CMD_CAN_RELEASE_BUFFER 0x89
+#define CMD_CAN_DATA_BUFF_REMOVE_ALL 0x8A
+
+#define IOCTL_RELEASE_CAN_BUFFER (SIOCDEVPRIVATE + 0)
+#define IOCTL_ENABLE_BUFFERING (SIOCDEVPRIVATE + 1)
+#define IOCTL_ADD_FRAME_FILTER (SIOCDEVPRIVATE + 2)
+#define IOCTL_REMOVE_FRAME_FILTER (SIOCDEVPRIVATE + 3)
+#define IOCTL_DISABLE_BUFFERING (SIOCDEVPRIVATE + 5)
+#define IOCTL_DISABLE_ALL_BUFFERING (SIOCDEVPRIVATE + 6)
+
+struct can_fw_resp {
+ u8 maj;
+ u8 min;
+ u8 ver;
+} __packed;
+
+struct can_write_req {
+ u32 ts;
+ u32 mid;
+ u8 dlc;
+ u8 data[];
+} __packed;
+
+struct can_write_resp {
+ u8 err;
+} __packed;
+
+struct can_receive_frame {
+ u32 ts;
+ u32 mid;
+ u8 dlc;
+ u8 data[];
+} __packed;
+
+struct can_add_filter_req {
+ u8 can_if;
+ u32 mid;
+ u32 mask;
+ u8 type;
+} __packed;
+
+static struct can_bittiming_const k61_bittiming_const = {
+ .name = "k61",
+ .tseg1_min = 4,
+ .tseg1_max = 16,
+ .tseg2_min = 2,
+ .tseg2_max = 8,
+ .sjw_max = 4,
+ .brp_min = 4,
+ .brp_max = 1023,
+ .brp_inc = 1,
+};
+
+struct k61_add_can_buffer {
+ u8 can_if;
+ u32 mid;
+ u32 mask;
+} __packed;
+
+struct k61_delete_can_buffer {
+ u8 can_if;
+ u32 mid;
+ u32 mask;
+} __packed;
+
+static int k61_rx_message(struct k61_can *priv_data);
+
+static irqreturn_t k61_irq(int irq, void *priv)
+{
+ struct k61_can *priv_data = priv;
+
+ LOGDI("k61_irq\n");
+ k61_rx_message(priv_data);
+ return IRQ_HANDLED;
+}
+
+static void k61_frame_error(struct k61_can *priv_data,
+ struct can_receive_frame *frame)
+{
+ struct can_frame *cf;
+ struct sk_buff *skb;
+ struct net_device *netdev;
+
+ netdev = priv_data->netdev;
+ skb = alloc_can_err_skb(netdev, &cf);
+ if (!skb) {
+ LOGDE("skb alloc failed\n");
+ return;
+ }
+
+ cf->can_id |= CAN_ERR_BUSERROR;
+ cf->data[2] |= CAN_ERR_PROT_FORM;
+ netdev->stats.rx_errors++;
+ netif_rx(skb);
+ netdev->stats.rx_packets++;
+ netdev->stats.rx_bytes += cf->can_dlc;
+}
+
+static void k61_receive_frame(struct k61_can *priv_data,
+ struct can_receive_frame *frame)
+{
+ struct can_frame *cf;
+ struct sk_buff *skb;
+ struct skb_shared_hwtstamps *skt;
+ struct timeval tv;
+ static int msec;
+ struct net_device *netdev;
+ int i;
+
+ if (frame->dlc > 8) {
+ LOGDE("can rx frame error\n");
+ k61_frame_error(priv_data, frame);
+ return;
+ }
+
+ netdev = priv_data->netdev;
+ skb = alloc_can_skb(netdev, &cf);
+ if (!skb) {
+ LOGDE("skb alloc failed\n");
+ return;
+ }
+
+ LOGDI("rcv frame %d %x %d %x %x %x %x %x %x %x %x\n",
+ frame->ts, frame->mid, frame->dlc, frame->data[0],
+ frame->data[1], frame->data[2], frame->data[3], frame->data[4],
+ frame->data[5], frame->data[6], frame->data[7]);
+ cf->can_id = le32_to_cpu(frame->mid);
+ cf->can_dlc = get_can_dlc(frame->dlc);
+
+ for (i = 0; i < cf->can_dlc; i++)
+ cf->data[i] = frame->data[i];
+
+ msec = le32_to_cpu(frame->ts);
+ tv.tv_sec = msec / 1000;
+ tv.tv_usec = (msec - tv.tv_sec * 1000) * 1000;
+ skt = skb_hwtstamps(skb);
+ skt->hwtstamp = timeval_to_ktime(tv);
+ LOGDI(" hwtstamp %lld\n", ktime_to_ms(skt->hwtstamp));
+ skb->tstamp = timeval_to_ktime(tv);
+ netif_rx(skb);
+ netdev->stats.rx_packets++;
+ netdev->stats.rx_bytes += cf->can_dlc;
+}
+
+static void k61_process_response(struct k61_can *priv_data,
+ struct spi_miso *resp)
+{
+ int ret = 0;
+
+ LOGDI("<%x %2d [%d]\n", resp->cmd, resp->len, resp->seq);
+ if (resp->cmd == CMD_CAN_RECEIVE_FRAME) {
+ struct can_receive_frame *frame =
+ (struct can_receive_frame *)&resp->data;
+ k61_receive_frame(priv_data, frame);
+ } else if (resp->cmd == CMD_GET_FW_VERSION) {
+ struct can_fw_resp *fw_resp = (struct can_fw_resp *)resp->data;
+
+ dev_info(&priv_data->spidev->dev, "fw %d.%d.%d",
+ fw_resp->maj, fw_resp->min, fw_resp->ver);
+ }
+
+ if (resp->cmd == priv_data->wait_cmd) {
+ priv_data->cmd_result = ret;
+ complete(&priv_data->response_completion);
+ }
+}
+
+static void k61_process_rx(struct k61_can *priv_data, char *rx_buf)
+{
+ struct spi_miso *resp;
+ int length_processed = 0, actual_length = priv_data->xfer_length;
+
+ while (length_processed < actual_length) {
+ int length_left = actual_length - length_processed;
+ int length = 0; /* length of consumed chunk */
+ void *data;
+
+ data = rx_buf + length_processed;
+ resp = (struct spi_miso *)data;
+
+ if (resp->cmd == 0) {
+ /* special case. ignore cmd==0 */
+ length_processed += 1;
+ continue;
+ }
+
+ LOGDI("processing. p %d -> l %d (t %d)\n",
+ length_processed, length_left, priv_data->xfer_length);
+ length = resp->len + sizeof(*resp);
+
+ if (length <= length_left) {
+ k61_process_response(priv_data, resp);
+ length_processed += length;
+ } else {
+ /* Incomplete command */
+ break;
+ }
+ }
+}
+
+static int k61_do_spi_transaction(struct k61_can *priv_data)
+{
+ struct spi_device *spi;
+ struct spi_transfer *xfer;
+ struct spi_message *msg;
+ int ret;
+
+ spi = priv_data->spidev;
+ msg = devm_kzalloc(&spi->dev, sizeof(*msg), GFP_KERNEL);
+ xfer = devm_kzalloc(&spi->dev, sizeof(*xfer), GFP_KERNEL);
+ if (xfer == 0 || msg == 0)
+ return -ENOMEM;
+ spi_message_init(msg);
+
+ spi_message_add_tail(xfer, msg);
+ xfer->tx_buf = priv_data->tx_buf;
+ xfer->rx_buf = priv_data->rx_buf;
+ xfer->len = XFER_BUFFER_SIZE;
+ xfer->bits_per_word = 16;
+
+ ret = spi_sync(spi, msg);
+ LOGDI("spi_sync ret %d\n", ret);
+
+ if (ret == 0) {
+ devm_kfree(&spi->dev, msg);
+ devm_kfree(&spi->dev, xfer);
+ k61_process_rx(priv_data, priv_data->rx_buf);
+ }
+ return ret;
+}
+
+static int k61_rx_message(struct k61_can *priv_data)
+{
+ char *tx_buf, *rx_buf;
+ int ret;
+
+ mutex_lock(&priv_data->spi_lock);
+ tx_buf = priv_data->tx_buf;
+ rx_buf = priv_data->rx_buf;
+ memset(tx_buf, 0, XFER_BUFFER_SIZE);
+ memset(rx_buf, 0, XFER_BUFFER_SIZE);
+ priv_data->xfer_length = XFER_BUFFER_SIZE;
+
+ ret = k61_do_spi_transaction(priv_data);
+ mutex_unlock(&priv_data->spi_lock);
+
+ return ret;
+}
+
+static int k61_query_firmware_version(struct k61_can *priv_data)
+{
+ char *tx_buf, *rx_buf;
+ int ret;
+ struct spi_mosi *req;
+
+ mutex_lock(&priv_data->spi_lock);
+ tx_buf = priv_data->tx_buf;
+ rx_buf = priv_data->rx_buf;
+ memset(tx_buf, 0, XFER_BUFFER_SIZE);
+ memset(rx_buf, 0, XFER_BUFFER_SIZE);
+ priv_data->xfer_length = XFER_BUFFER_SIZE;
+
+ req = (struct spi_mosi *)tx_buf;
+ req->cmd = CMD_GET_FW_VERSION;
+ req->len = 0;
+ req->seq = atomic_inc_return(&priv_data->msg_seq);
+
+ priv_data->wait_cmd = CMD_GET_FW_VERSION;
+ priv_data->cmd_result = -1;
+ reinit_completion(&priv_data->response_completion);
+
+ ret = k61_do_spi_transaction(priv_data);
+ mutex_unlock(&priv_data->spi_lock);
+
+ if (ret == 0) {
+ wait_for_completion_interruptible_timeout(
+ &priv_data->response_completion, 0.001 * HZ);
+ ret = priv_data->cmd_result;
+ }
+
+ return ret;
+}
+
+static int k61_can_write(struct k61_can *priv_data, struct can_frame *cf)
+{
+ char *tx_buf, *rx_buf;
+ int ret, i;
+ struct spi_mosi *req;
+ struct can_write_req *req_d;
+ struct net_device *netdev;
+
+ mutex_lock(&priv_data->spi_lock);
+ tx_buf = priv_data->tx_buf;
+ rx_buf = priv_data->rx_buf;
+ memset(tx_buf, 0, XFER_BUFFER_SIZE);
+ memset(rx_buf, 0, XFER_BUFFER_SIZE);
+ priv_data->xfer_length = XFER_BUFFER_SIZE;
+
+ req = (struct spi_mosi *)tx_buf;
+ req->cmd = CMD_CAN_SEND_FRAME;
+ req->len = sizeof(struct can_write_req) + 8;
+ req->seq = atomic_inc_return(&priv_data->msg_seq);
+
+ req_d = (struct can_write_req *)req->data;
+ req_d->mid = cf->can_id;
+ req_d->dlc = cf->can_dlc;
+ for (i = 0; i < cf->can_dlc; i++)
+ req_d->data[i] = cf->data[i];
+
+ ret = k61_do_spi_transaction(priv_data);
+ netdev = priv_data->netdev;
+ netdev->stats.tx_packets++;
+ netdev->stats.tx_bytes += cf->can_dlc;
+ mutex_unlock(&priv_data->spi_lock);
+
+ return ret;
+}
+
+static int k61_netdev_open(struct net_device *netdev)
+{
+ int err;
+
+ LOGNI("Open");
+ err = open_candev(netdev);
+ if (err)
+ return err;
+
+ netif_start_queue(netdev);
+
+ return 0;
+}
+
+static int k61_netdev_close(struct net_device *netdev)
+{
+ LOGNI("Close");
+
+ netif_stop_queue(netdev);
+ close_candev(netdev);
+ return 0;
+}
+
+static void k61_send_can_frame(struct work_struct *ws)
+{
+ struct k61_tx_work *tx_work;
+ struct can_frame *cf;
+ struct k61_can *priv_data;
+ struct net_device *netdev;
+ struct k61_netdev_privdata *netdev_priv_data;
+
+ tx_work = container_of(ws, struct k61_tx_work, work);
+ netdev = tx_work->netdev;
+ netdev_priv_data = netdev_priv(netdev);
+ priv_data = netdev_priv_data->k61_can;
+ LOGDI("send_can_frame ws %p\n", ws);
+ LOGDI("send_can_frame tx %p\n", tx_work);
+
+ cf = (struct can_frame *)tx_work->skb->data;
+ k61_can_write(priv_data, cf);
+
+ dev_kfree_skb(tx_work->skb);
+ kfree(tx_work);
+}
+
+static int k61_frame_filter(struct net_device *netdev,
+ struct ifreq *ifr, int cmd)
+{
+ char *tx_buf, *rx_buf;
+ int ret;
+ struct spi_mosi *req;
+ struct can_add_filter_req *add_filter;
+ struct can_add_filter_req *filter_request;
+ struct k61_can *priv_data;
+ struct k61_netdev_privdata *netdev_priv_data;
+ struct spi_device *spi;
+
+ netdev_priv_data = netdev_priv(netdev);
+ priv_data = netdev_priv_data->k61_can;
+ spi = priv_data->spidev;
+
+ mutex_lock(&priv_data->spi_lock);
+ tx_buf = priv_data->tx_buf;
+ rx_buf = priv_data->rx_buf;
+ memset(tx_buf, 0, XFER_BUFFER_SIZE);
+ memset(rx_buf, 0, XFER_BUFFER_SIZE);
+ priv_data->xfer_length = XFER_BUFFER_SIZE;
+
+ if (!ifr)
+ return -EINVAL;
+
+ filter_request =
+ devm_kzalloc(&spi->dev, sizeof(struct can_add_filter_req),
+ GFP_KERNEL);
+ if (!filter_request)
+ return -ENOMEM;
+
+ if (copy_from_user(filter_request, ifr->ifr_data,
+ sizeof(struct can_add_filter_req))) {
+ devm_kfree(&spi->dev, filter_request);
+ return -EFAULT;
+ }
+
+ req = (struct spi_mosi *)tx_buf;
+ if (cmd == IOCTL_ADD_FRAME_FILTER)
+ req->cmd = CMD_CAN_ADD_FILTER;
+ else
+ req->cmd = CMD_CAN_REMOVE_FILTER;
+
+ req->len = sizeof(struct can_add_filter_req);
+ req->seq = atomic_inc_return(&priv_data->msg_seq);
+
+ add_filter = (struct can_add_filter_req *)req->data;
+ add_filter->can_if = filter_request->can_if;
+ add_filter->mid = filter_request->mid;
+ add_filter->mask = filter_request->mask;
+
+ ret = k61_do_spi_transaction(priv_data);
+ devm_kfree(&spi->dev, filter_request);
+ mutex_unlock(&priv_data->spi_lock);
+ return ret;
+}
+
+static netdev_tx_t k61_netdev_start_xmit(
+ struct sk_buff *skb, struct net_device *netdev)
+{
+ struct k61_netdev_privdata *netdev_priv_data = netdev_priv(netdev);
+ struct k61_can *priv_data = netdev_priv_data->k61_can;
+ struct k61_tx_work *tx_work;
+
+ LOGNI("netdev_start_xmit");
+ if (can_dropped_invalid_skb(netdev, skb)) {
+ LOGNE("Dropping invalid can frame\n");
+ return NETDEV_TX_OK;
+ }
+ tx_work = kzalloc(sizeof(*tx_work), GFP_ATOMIC);
+ if (tx_work == 0)
+ return NETDEV_TX_OK;
+ INIT_WORK(&tx_work->work, k61_send_can_frame);
+ tx_work->netdev = netdev;
+ tx_work->skb = skb;
+ queue_work(priv_data->tx_wq, &tx_work->work);
+
+ return NETDEV_TX_OK;
+}
+
+static int k61_send_release_can_buffer_cmd(struct net_device *netdev)
+{
+ struct k61_can *priv_data;
+ struct k61_netdev_privdata *netdev_priv_data;
+ struct spi_device *spi;
+ char *tx_buf, *rx_buf;
+ int ret;
+ struct spi_mosi *req;
+
+ netdev_priv_data = netdev_priv(netdev);
+ priv_data = netdev_priv_data->k61_can;
+ spi = priv_data->spidev;
+
+ mutex_lock(&priv_data->spi_lock);
+ tx_buf = priv_data->tx_buf;
+ rx_buf = priv_data->rx_buf;
+ memset(tx_buf, 0, XFER_BUFFER_SIZE);
+ memset(rx_buf, 0, XFER_BUFFER_SIZE);
+ priv_data->xfer_length = XFER_BUFFER_SIZE;
+
+ req = (struct spi_mosi *)tx_buf;
+ req->cmd = CMD_CAN_RELEASE_BUFFER;
+ req->len = 0;
+ req->seq = atomic_inc_return(&priv_data->msg_seq);
+
+ ret = k61_do_spi_transaction(priv_data);
+ mutex_unlock(&priv_data->spi_lock);
+ return ret;
+}
+
+static int k61_remove_all_buffering(struct net_device *netdev)
+{
+ char *tx_buf, *rx_buf;
+ int ret;
+ struct spi_mosi *req;
+ struct k61_can *priv_data;
+ struct k61_netdev_privdata *netdev_priv_data;
+
+ netdev_priv_data = netdev_priv(netdev);
+ priv_data = netdev_priv_data->k61_can;
+
+ mutex_lock(&priv_data->spi_lock);
+ tx_buf = priv_data->tx_buf;
+ rx_buf = priv_data->rx_buf;
+ memset(tx_buf, 0, XFER_BUFFER_SIZE);
+ memset(rx_buf, 0, XFER_BUFFER_SIZE);
+ priv_data->xfer_length = XFER_BUFFER_SIZE;
+
+ req = (struct spi_mosi *)tx_buf;
+ req->cmd = CMD_CAN_DATA_BUFF_REMOVE_ALL;
+ req->len = 0;
+ req->seq = atomic_inc_return(&priv_data->msg_seq);
+
+ priv_data->wait_cmd = req->cmd;
+ priv_data->cmd_result = -1;
+ reinit_completion(&priv_data->response_completion);
+
+ ret = k61_do_spi_transaction(priv_data);
+ mutex_unlock(&priv_data->spi_lock);
+
+ if (ret == 0) {
+ LOGDI("k61_do_blocking_ioctl ready to wait for response\n");
+ /* Flash write may take some time. Hence give 2s as
+ * wait duration in the worst case. This wait time should
+ * increase if more number of frame IDs are stored in flash.
+ */
+ ret = wait_for_completion_interruptible_timeout(
+ &priv_data->response_completion, 2 * HZ);
+ ret = priv_data->cmd_result;
+ }
+
+ return ret;
+}
+
+static int k61_convert_ioctl_cmd_to_spi_cmd(int ioctl_cmd)
+{
+ switch (ioctl_cmd) {
+ case IOCTL_ENABLE_BUFFERING:
+ return CMD_CAN_DATA_BUFF_ADD;
+ case IOCTL_DISABLE_BUFFERING:
+ return CMD_CAN_DATA_BUFF_REMOVE;
+ }
+ return -EINVAL;
+}
+
+static int k61_data_buffering(struct net_device *netdev,
+ struct ifreq *ifr, int cmd)
+{
+ int spi_cmd, ret;
+ char *tx_buf, *rx_buf;
+ struct k61_can *priv_data;
+ struct spi_mosi *req;
+ struct k61_netdev_privdata *netdev_priv_data;
+ struct k61_add_can_buffer *enable_buffering;
+ struct k61_add_can_buffer *add_request;
+ struct spi_device *spi;
+
+ netdev_priv_data = netdev_priv(netdev);
+ priv_data = netdev_priv_data->k61_can;
+ spi = priv_data->spidev;
+
+ mutex_lock(&priv_data->spi_lock);
+ spi_cmd = k61_convert_ioctl_cmd_to_spi_cmd(cmd);
+ if (spi_cmd < 0) {
+ LOGDE("k61_do_blocking_ioctl wrong command %d\n", cmd);
+ return spi_cmd;
+ }
+
+ if (!ifr)
+ return -EINVAL;
+
+ add_request = devm_kzalloc(&spi->dev, sizeof(struct k61_add_can_buffer),
+ GFP_KERNEL);
+ if (!add_request)
+ return -ENOMEM;
+
+ if (copy_from_user(add_request, ifr->ifr_data,
+ sizeof(struct k61_add_can_buffer))) {
+ devm_kfree(&spi->dev, add_request);
+ return -EFAULT;
+ }
+
+ tx_buf = priv_data->tx_buf;
+ rx_buf = priv_data->rx_buf;
+ memset(tx_buf, 0, XFER_BUFFER_SIZE);
+ memset(rx_buf, 0, XFER_BUFFER_SIZE);
+ priv_data->xfer_length = XFER_BUFFER_SIZE;
+
+ req = (struct spi_mosi *)tx_buf;
+ req->cmd = spi_cmd;
+ req->len = sizeof(struct k61_add_can_buffer);
+ req->seq = atomic_inc_return(&priv_data->msg_seq);
+
+ enable_buffering = (struct k61_add_can_buffer *)req->data;
+ enable_buffering->can_if = add_request->can_if;
+ enable_buffering->mid = add_request->mid;
+ enable_buffering->mask = add_request->mask;
+
+ priv_data->wait_cmd = spi_cmd;
+ priv_data->cmd_result = -1;
+ reinit_completion(&priv_data->response_completion);
+
+ ret = k61_do_spi_transaction(priv_data);
+ devm_kfree(&spi->dev, add_request);
+ mutex_unlock(&priv_data->spi_lock);
+
+ if (ret == 0) {
+ LOGDI("k61_do_blocking_ioctl ready to wait for response\n");
+ /* Flash write may take some time. Hence give 400ms as
+ * wait duration in the worst case.
+ */
+ ret = wait_for_completion_interruptible_timeout(
+ &priv_data->response_completion, 0.4 * HZ);
+ ret = priv_data->cmd_result;
+ }
+ return ret;
+}
+
+static int k61_netdev_do_ioctl(struct net_device *netdev,
+ struct ifreq *ifr, int cmd)
+{
+ struct k61_can *priv_data;
+ struct k61_netdev_privdata *netdev_priv_data;
+ int ret = -EINVAL;
+
+ netdev_priv_data = netdev_priv(netdev);
+ priv_data = netdev_priv_data->k61_can;
+ LOGDI("k61_netdev_do_ioctl %x\n", cmd);
+
+ switch (cmd) {
+ case IOCTL_ADD_FRAME_FILTER:
+ case IOCTL_REMOVE_FRAME_FILTER:
+ ret = k61_frame_filter(netdev, ifr, cmd);
+ break;
+ case IOCTL_ENABLE_BUFFERING:
+ case IOCTL_DISABLE_BUFFERING:
+ ret = k61_data_buffering(netdev, ifr, cmd);
+ break;
+ case IOCTL_DISABLE_ALL_BUFFERING:
+ ret = k61_remove_all_buffering(netdev);
+ break;
+ case IOCTL_RELEASE_CAN_BUFFER:
+ ret = k61_send_release_can_buffer_cmd(netdev);
+ break;
+ }
+ return ret;
+}
+
+static const struct net_device_ops k61_netdev_ops = {
+ .ndo_open = k61_netdev_open,
+ .ndo_stop = k61_netdev_close,
+ .ndo_start_xmit = k61_netdev_start_xmit,
+ .ndo_do_ioctl = k61_netdev_do_ioctl,
+};
+
+static int k61_create_netdev(struct spi_device *spi,
+ struct k61_can *priv_data)
+{
+ struct net_device *netdev;
+ struct k61_netdev_privdata *netdev_priv_data;
+
+ LOGDI("k61_create_netdev\n");
+ netdev = alloc_candev(sizeof(*netdev_priv_data), MAX_TX_BUFFERS);
+ if (!netdev) {
+ LOGDE("Couldn't alloc candev\n");
+ return -ENOMEM;
+ }
+
+ netdev_priv_data = netdev_priv(netdev);
+ netdev_priv_data->k61_can = priv_data;
+
+ priv_data->netdev = netdev;
+
+ netdev->netdev_ops = &k61_netdev_ops;
+ SET_NETDEV_DEV(netdev, &spi->dev);
+ netdev_priv_data->can.ctrlmode_supported = CAN_CTRLMODE_3_SAMPLES |
+ CAN_CTRLMODE_LISTENONLY;
+ netdev_priv_data->can.bittiming_const = &k61_bittiming_const;
+ netdev_priv_data->can.clock.freq = K61_CLOCK;
+
+ return 0;
+}
+
+static struct k61_can *k61_create_priv_data(struct spi_device *spi)
+{
+ struct k61_can *priv_data;
+ int err;
+ struct device *dev;
+
+ dev = &spi->dev;
+ priv_data = devm_kzalloc(dev, sizeof(*priv_data), GFP_KERNEL);
+ if (!priv_data) {
+ dev_err(dev, "Couldn't alloc k61_can\n");
+ return 0;
+ }
+ spi_set_drvdata(spi, priv_data);
+ atomic_set(&priv_data->netif_queue_stop, 0);
+ priv_data->spidev = spi;
+
+ priv_data->tx_wq = alloc_workqueue("k61_tx_wq", 0, 0);
+ if (!priv_data->tx_wq) {
+ dev_err(dev, "Couldn't alloc workqueue\n");
+ err = -ENOMEM;
+ goto cleanup_privdata;
+ }
+
+ priv_data->tx_buf = devm_kzalloc(dev, XFER_BUFFER_SIZE,
+ GFP_KERNEL);
+ priv_data->rx_buf = devm_kzalloc(dev, XFER_BUFFER_SIZE,
+ GFP_KERNEL);
+ if (!priv_data->tx_buf || !priv_data->rx_buf) {
+ dev_err(dev, "Couldn't alloc tx or rx buffers\n");
+ err = -ENOMEM;
+ goto cleanup_privdata;
+ }
+ priv_data->xfer_length = 0;
+
+ mutex_init(&priv_data->spi_lock);
+ atomic_set(&priv_data->msg_seq, 0);
+ init_completion(&priv_data->response_completion);
+ return priv_data;
+
+cleanup_privdata:
+ if (priv_data) {
+ if (priv_data->tx_wq)
+ destroy_workqueue(priv_data->tx_wq);
+ }
+ return 0;
+}
+
+static int k61_probe(struct spi_device *spi)
+{
+ int err, retry = 0, query_err = -1;
+ struct k61_can *priv_data;
+ struct device *dev;
+
+ dev = &spi->dev;
+ dev_dbg(dev, "k61_probe");
+
+ err = spi_setup(spi);
+ if (err) {
+ dev_err(dev, "spi_setup failed: %d", err);
+ return err;
+ }
+
+ priv_data = k61_create_priv_data(spi);
+ if (!priv_data) {
+ dev_err(dev, "Failed to create k61_can priv_data\n");
+ err = -ENOMEM;
+ return err;
+ }
+ dev_dbg(dev, "k61_probe created priv_data");
+
+ priv_data->reset = of_get_named_gpio(spi->dev.of_node, "reset-gpio", 0);
+ if (!gpio_is_valid(priv_data->reset)) {
+ dev_err(&spi->dev, "Missing dt property: reset-gpio\n");
+ return -EINVAL;
+ }
+ err = gpio_request(priv_data->reset, "k61-reset");
+ if (err < 0) {
+ dev_err(&spi->dev,
+ "failed to request gpio %d: %d\n",
+ priv_data->reset, err);
+ }
+
+ gpio_direction_output(priv_data->reset, 0);
+ udelay(1);
+ gpio_direction_output(priv_data->reset, 1);
+ /* Provide a delay of 300us for the chip to reset. This is part of
+ * the reset sequence.
+ */
+ usleep_range(300, 301);
+
+ err = k61_create_netdev(spi, priv_data);
+ if (err) {
+ dev_err(dev, "Failed to create CAN device: %d", err);
+ goto cleanup_candev;
+ }
+
+ err = register_candev(priv_data->netdev);
+ if (err) {
+ dev_err(dev, "Failed to register CAN device: %d", err);
+ goto unregister_candev;
+ }
+
+ err = request_threaded_irq(spi->irq, NULL, k61_irq,
+ IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
+ "k61", priv_data);
+ if (err) {
+ dev_err(dev, "Failed to request irq: %d", err);
+ goto unregister_candev;
+ }
+ dev_dbg(dev, "Request irq %d ret %d\n", spi->irq, err);
+
+ while ((query_err != 0) && (retry < K61_FW_QUERY_RETRY_COUNT)) {
+ query_err = k61_query_firmware_version(priv_data);
+ retry++;
+ }
+
+ if (query_err) {
+ dev_info(dev, "K61 probe failed\n");
+ err = -ENODEV;
+ goto free_irq;
+ }
+ return 0;
+
+free_irq:
+ free_irq(spi->irq, priv_data);
+unregister_candev:
+ unregister_candev(priv_data->netdev);
+cleanup_candev:
+ if (priv_data) {
+ if (priv_data->netdev)
+ free_candev(priv_data->netdev);
+ if (priv_data->tx_wq)
+ destroy_workqueue(priv_data->tx_wq);
+ }
+ return err;
+}
+
+static int k61_remove(struct spi_device *spi)
+{
+ struct k61_can *priv_data = spi_get_drvdata(spi);
+
+ LOGDI("k61_remove\n");
+ unregister_candev(priv_data->netdev);
+ free_candev(priv_data->netdev);
+ destroy_workqueue(priv_data->tx_wq);
+ return 0;
+}
+
+static const struct of_device_id k61_match_table[] = {
+ { .compatible = "fsl,k61" },
+ { }
+};
+
+static struct spi_driver k61_driver = {
+ .driver = {
+ .name = "k61",
+ .of_match_table = k61_match_table,
+ .owner = THIS_MODULE,
+ },
+ .probe = k61_probe,
+ .remove = k61_remove,
+};
+module_spi_driver(k61_driver);
+
+MODULE_DESCRIPTION("Freescale K61 SPI-CAN module");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/net/wireless/ath/ath10k/ce.c b/drivers/net/wireless/ath/ath10k/ce.c
index 9cda1303c9e1..769f89e8d14c 100644
--- a/drivers/net/wireless/ath/ath10k/ce.c
+++ b/drivers/net/wireless/ath/ath10k/ce.c
@@ -1009,11 +1009,17 @@ void ath10k_ce_enable_interrupts(struct ath10k *ar)
struct bus_opaque *ar_opaque = ath10k_bus_priv(ar);
int ce_id;
struct ath10k_ce_pipe *ce_state;
+ u8 ce_count;
+ if (QCA_REV_WCN3990(ar))
+ ce_count = CE_COUNT;
+ else
/* Skip the last copy engine, CE7 the diagnostic window, as that
* uses polling and isn't initialized for interrupts.
*/
- for (ce_id = 0; ce_id < CE_COUNT - 1; ce_id++) {
+ ce_count = CE_COUNT - 1;
+
+ for (ce_id = 0; ce_id < ce_count; ce_id++) {
ce_state = &ar_opaque->ce_states[ce_id];
ath10k_ce_per_engine_handler_adjust(ce_state);
}
diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c
index ec86c837e60a..4bb14d43e136 100644
--- a/drivers/net/wireless/ath/ath10k/mac.c
+++ b/drivers/net/wireless/ath/ath10k/mac.c
@@ -4507,6 +4507,13 @@ static int ath10k_start(struct ieee80211_hw *hw)
goto err_core_stop;
}
+ param = ar->wmi.pdev_param->idle_ps_config;
+ ret = ath10k_wmi_pdev_set_param(ar, param, 1);
+ if (ret) {
+ ath10k_warn(ar, "failed to enable idle_ps_config: %d\n", ret);
+ goto err_core_stop;
+ }
+
if (test_bit(WMI_SERVICE_ADAPTIVE_OCS, ar->wmi.svc_map)) {
ret = ath10k_wmi_adaptive_qcs(ar, true);
if (ret) {
diff --git a/drivers/net/wireless/ath/wil6210/cfg80211.c b/drivers/net/wireless/ath/wil6210/cfg80211.c
index 94861020af12..93868095dc3c 100644
--- a/drivers/net/wireless/ath/wil6210/cfg80211.c
+++ b/drivers/net/wireless/ath/wil6210/cfg80211.c
@@ -31,6 +31,12 @@ static bool ignore_reg_hints = true;
module_param(ignore_reg_hints, bool, 0444);
MODULE_PARM_DESC(ignore_reg_hints, " Ignore OTA regulatory hints (Default: true)");
+#ifdef CONFIG_PM
+static struct wiphy_wowlan_support wil_wowlan_support = {
+ .flags = WIPHY_WOWLAN_ANY | WIPHY_WOWLAN_DISCONNECT,
+};
+#endif
+
#define CHAN60G(_channel, _flags) { \
.band = IEEE80211_BAND_60GHZ, \
.center_freq = 56160 + (2160 * (_channel)), \
@@ -345,12 +351,12 @@ int wil_cid_fill_sinfo(struct wil6210_priv *wil, int cid,
wil_dbg_wmi(wil, "Link status for CID %d: {\n"
" MCS %d TSF 0x%016llx\n"
- " BF status 0x%08x SNR 0x%08x SQI %d%%\n"
+ " BF status 0x%08x RSSI %d SQI %d%%\n"
" Tx Tpt %d goodput %d Rx goodput %d\n"
" Sectors(rx:tx) my %d:%d peer %d:%d\n""}\n",
cid, le16_to_cpu(reply.evt.bf_mcs),
le64_to_cpu(reply.evt.tsf), reply.evt.status,
- le32_to_cpu(reply.evt.snr_val),
+ reply.evt.rssi,
reply.evt.sqi,
le32_to_cpu(reply.evt.tx_tpt),
le32_to_cpu(reply.evt.tx_goodput),
@@ -384,7 +390,11 @@ int wil_cid_fill_sinfo(struct wil6210_priv *wil, int cid,
if (test_bit(wil_status_fwconnected, wil->status)) {
sinfo->filled |= BIT(NL80211_STA_INFO_SIGNAL);
- sinfo->signal = reply.evt.sqi;
+ if (test_bit(WMI_FW_CAPABILITY_RSSI_REPORTING,
+ wil->fw_capabilities))
+ sinfo->signal = reply.evt.rssi;
+ else
+ sinfo->signal = reply.evt.sqi;
}
return rc;
@@ -1870,7 +1880,7 @@ static void wil_wiphy_init(struct wiphy *wiphy)
wiphy->bands[IEEE80211_BAND_60GHZ] = &wil_band_60ghz;
- /* TODO: figure this out */
+ /* may change after reading FW capabilities */
wiphy->signal_type = CFG80211_SIGNAL_TYPE_UNSPEC;
wiphy->cipher_suites = wil_cipher_suites;
@@ -1887,6 +1897,10 @@ static void wil_wiphy_init(struct wiphy *wiphy)
wiphy->regulatory_flags |= REGULATORY_DISABLE_BEACON_HINTS;
wiphy->regulatory_flags |= REGULATORY_COUNTRY_IE_IGNORE;
}
+
+#ifdef CONFIG_PM
+ wiphy->wowlan = &wil_wowlan_support;
+#endif
}
struct wireless_dev *wil_cfg80211_init(struct device *dev)
diff --git a/drivers/net/wireless/ath/wil6210/debugfs.c b/drivers/net/wireless/ath/wil6210/debugfs.c
index 6eefb9e61ec4..65f39a4343ff 100644
--- a/drivers/net/wireless/ath/wil6210/debugfs.c
+++ b/drivers/net/wireless/ath/wil6210/debugfs.c
@@ -20,7 +20,6 @@
#include <linux/pci.h>
#include <linux/rtnetlink.h>
#include <linux/power_supply.h>
-
#include "wil6210.h"
#include "wmi.h"
#include "txrx.h"
@@ -30,7 +29,6 @@
static u32 mem_addr;
static u32 dbg_txdesc_index;
static u32 dbg_vring_index; /* 24+ for Rx, 0..23 for Tx */
-u32 vring_idle_trsh = 16; /* HW fetches up to 16 descriptors at once */
enum dbg_off_type {
doff_u32 = 0,
@@ -1027,6 +1025,7 @@ static int wil_bf_debugfs_show(struct seq_file *s, void *data)
" TSF = 0x%016llx\n"
" TxMCS = %2d TxTpt = %4d\n"
" SQI = %4d\n"
+ " RSSI = %4d\n"
" Status = 0x%08x %s\n"
" Sectors(rx:tx) my %2d:%2d peer %2d:%2d\n"
" Goodput(rx:tx) %4d:%4d\n"
@@ -1036,6 +1035,7 @@ static int wil_bf_debugfs_show(struct seq_file *s, void *data)
le16_to_cpu(reply.evt.bf_mcs),
le32_to_cpu(reply.evt.tx_tpt),
reply.evt.sqi,
+ reply.evt.rssi,
status, wil_bfstatus_str(status),
le16_to_cpu(reply.evt.my_rx_sector),
le16_to_cpu(reply.evt.my_tx_sector),
@@ -1626,6 +1626,8 @@ static ssize_t wil_write_suspend_stats(struct file *file,
struct wil6210_priv *wil = file->private_data;
memset(&wil->suspend_stats, 0, sizeof(wil->suspend_stats));
+ wil->suspend_stats.min_suspend_time = ULONG_MAX;
+ wil->suspend_stats.collection_start = ktime_get();
return len;
}
@@ -1637,18 +1639,27 @@ static ssize_t wil_read_suspend_stats(struct file *file,
struct wil6210_priv *wil = file->private_data;
static char text[400];
int n;
+ unsigned long long stats_collection_time =
+ ktime_to_us(ktime_sub(ktime_get(),
+ wil->suspend_stats.collection_start));
n = snprintf(text, sizeof(text),
"Suspend statistics:\n"
"successful suspends:%ld failed suspends:%ld\n"
"successful resumes:%ld failed resumes:%ld\n"
- "rejected by host:%ld rejected by device:%ld\n",
+ "rejected by host:%ld rejected by device:%ld\n"
+ "total suspend time:%lld min suspend time:%lld\n"
+ "max suspend time:%lld stats collection time: %lld\n",
wil->suspend_stats.successful_suspends,
wil->suspend_stats.failed_suspends,
wil->suspend_stats.successful_resumes,
wil->suspend_stats.failed_resumes,
wil->suspend_stats.rejected_by_host,
- wil->suspend_stats.rejected_by_device);
+ wil->suspend_stats.rejected_by_device,
+ wil->suspend_stats.total_suspend_time,
+ wil->suspend_stats.min_suspend_time,
+ wil->suspend_stats.max_suspend_time,
+ stats_collection_time);
n = min_t(int, n, sizeof(text));
@@ -1761,6 +1772,7 @@ static const struct dbg_off dbg_wil_off[] = {
WIL_FIELD(chip_revision, 0444, doff_u8),
WIL_FIELD(abft_len, 0644, doff_u8),
WIL_FIELD(wakeup_trigger, 0644, doff_u8),
+ WIL_FIELD(vring_idle_trsh, 0644, doff_u32),
{},
};
@@ -1776,8 +1788,6 @@ static const struct dbg_off dbg_statics[] = {
{"desc_index", 0644, (ulong)&dbg_txdesc_index, doff_u32},
{"vring_index", 0644, (ulong)&dbg_vring_index, doff_u32},
{"mem_addr", 0644, (ulong)&mem_addr, doff_u32},
- {"vring_idle_trsh", 0644, (ulong)&vring_idle_trsh,
- doff_u32},
{"led_polarity", 0644, (ulong)&led_polarity, doff_u8},
{},
};
@@ -1804,6 +1814,8 @@ int wil6210_debugfs_init(struct wil6210_priv *wil)
wil6210_debugfs_create_ITR_CNT(wil, dbg);
+ wil->suspend_stats.collection_start = ktime_get();
+
return 0;
}
diff --git a/drivers/net/wireless/ath/wil6210/main.c b/drivers/net/wireless/ath/wil6210/main.c
index 78091b7910c7..09da8e769394 100644
--- a/drivers/net/wireless/ath/wil6210/main.c
+++ b/drivers/net/wireless/ath/wil6210/main.c
@@ -395,10 +395,11 @@ static void wil_fw_error_worker(struct work_struct *work)
struct wil6210_priv *wil = container_of(work, struct wil6210_priv,
fw_error_worker);
struct wireless_dev *wdev = wil->wdev;
+ struct net_device *ndev = wil_to_ndev(wil);
wil_dbg_misc(wil, "fw error worker\n");
- if (!netif_running(wil_to_ndev(wil))) {
+ if (!(ndev->flags & IFF_UP)) {
wil_info(wil, "No recovery - interface is down\n");
return;
}
@@ -581,6 +582,9 @@ int wil_priv_init(struct wil6210_priv *wil)
wil->wakeup_trigger = WMI_WAKEUP_TRIGGER_UCAST |
WMI_WAKEUP_TRIGGER_BCAST;
+ memset(&wil->suspend_stats, 0, sizeof(wil->suspend_stats));
+ wil->suspend_stats.min_suspend_time = ULONG_MAX;
+ wil->vring_idle_trsh = 16;
return 0;
@@ -1036,6 +1040,12 @@ int wil_reset(struct wil6210_priv *wil, bool load_fw)
wil_s(wil, RGF_CAF_ICR + offsetof(struct RGF_ICR, ICR), 0);
wil_w(wil, RGF_CAF_ICR + offsetof(struct RGF_ICR, IMV), ~0);
+ if (wil->fw_calib_result > 0) {
+ __le32 val = cpu_to_le32(wil->fw_calib_result |
+ (CALIB_RESULT_SIGNATURE << 8));
+ wil_w(wil, RGF_USER_FW_CALIB_RESULT, (u32 __force)val);
+ }
+
wil_release_cpu(wil);
}
diff --git a/drivers/net/wireless/ath/wil6210/pcie_bus.c b/drivers/net/wireless/ath/wil6210/pcie_bus.c
index e91cddbacf24..54aef15a9206 100644
--- a/drivers/net/wireless/ath/wil6210/pcie_bus.c
+++ b/drivers/net/wireless/ath/wil6210/pcie_bus.c
@@ -84,6 +84,9 @@ void wil_set_capabilities(struct wil6210_priv *wil)
/* extract FW capabilities from file without loading the FW */
wil_request_firmware(wil, wil->wil_fw_name, false);
+
+ if (test_bit(WMI_FW_CAPABILITY_RSSI_REPORTING, wil->fw_capabilities))
+ wil_to_wiphy(wil)->signal_type = CFG80211_SIGNAL_TYPE_MBM;
}
void wil_disable_irq(struct wil6210_priv *wil)
diff --git a/drivers/net/wireless/ath/wil6210/pm.c b/drivers/net/wireless/ath/wil6210/pm.c
index ce1f384e7f8e..8f5d1b447aaa 100644
--- a/drivers/net/wireless/ath/wil6210/pm.c
+++ b/drivers/net/wireless/ath/wil6210/pm.c
@@ -21,10 +21,11 @@ int wil_can_suspend(struct wil6210_priv *wil, bool is_runtime)
{
int rc = 0;
struct wireless_dev *wdev = wil->wdev;
+ struct net_device *ndev = wil_to_ndev(wil);
wil_dbg_pm(wil, "can_suspend: %s\n", is_runtime ? "runtime" : "system");
- if (!netif_running(wil_to_ndev(wil))) {
+ if (!(ndev->flags & IFF_UP)) {
/* can always sleep when down */
wil_dbg_pm(wil, "Interface is down\n");
goto out;
@@ -85,7 +86,9 @@ static int wil_resume_keep_radio_on(struct wil6210_priv *wil)
/* Send WMI resume request to the device */
rc = wmi_resume(wil);
if (rc) {
- wil_err(wil, "device failed to resume (%d), resetting\n", rc);
+ wil_err(wil, "device failed to resume (%d)\n", rc);
+ if (no_fw_recovery)
+ goto out;
rc = wil_down(wil);
if (rc) {
wil_err(wil, "wil_down failed (%d)\n", rc);
@@ -298,6 +301,9 @@ int wil_suspend(struct wil6210_priv *wil, bool is_runtime)
wil_dbg_pm(wil, "suspend: %s => %d\n",
is_runtime ? "runtime" : "system", rc);
+ if (!rc)
+ wil->suspend_stats.suspend_start_time = ktime_get();
+
return rc;
}
@@ -307,6 +313,7 @@ int wil_resume(struct wil6210_priv *wil, bool is_runtime)
struct net_device *ndev = wil_to_ndev(wil);
bool keep_radio_on = ndev->flags & IFF_UP &&
wil->keep_radio_on_during_sleep;
+ unsigned long long suspend_time_usec = 0;
wil_dbg_pm(wil, "resume: %s\n", is_runtime ? "runtime" : "system");
@@ -324,8 +331,20 @@ int wil_resume(struct wil6210_priv *wil, bool is_runtime)
else
rc = wil_resume_radio_off(wil);
+ if (rc)
+ goto out;
+
+ suspend_time_usec =
+ ktime_to_us(ktime_sub(ktime_get(),
+ wil->suspend_stats.suspend_start_time));
+ wil->suspend_stats.total_suspend_time += suspend_time_usec;
+ if (suspend_time_usec < wil->suspend_stats.min_suspend_time)
+ wil->suspend_stats.min_suspend_time = suspend_time_usec;
+ if (suspend_time_usec > wil->suspend_stats.max_suspend_time)
+ wil->suspend_stats.max_suspend_time = suspend_time_usec;
+
out:
- wil_dbg_pm(wil, "resume: %s => %d\n",
- is_runtime ? "runtime" : "system", rc);
+ wil_dbg_pm(wil, "resume: %s => %d, suspend time %lld usec\n",
+ is_runtime ? "runtime" : "system", rc, suspend_time_usec);
return rc;
}
diff --git a/drivers/net/wireless/ath/wil6210/txrx.c b/drivers/net/wireless/ath/wil6210/txrx.c
index 8f1e79b425cf..8fe2239603d1 100644
--- a/drivers/net/wireless/ath/wil6210/txrx.c
+++ b/drivers/net/wireless/ath/wil6210/txrx.c
@@ -1666,7 +1666,7 @@ static int __wil_tx_vring_tso(struct wil6210_priv *wil, struct vring *vring,
/* performance monitoring */
used = wil_vring_used_tx(vring);
- if (wil_val_in_range(vring_idle_trsh,
+ if (wil_val_in_range(wil->vring_idle_trsh,
used, used + descs_used)) {
txdata->idle += get_cycles() - txdata->last_idle;
wil_dbg_txrx(wil, "Ring[%2d] not idle %d -> %d\n",
@@ -1813,7 +1813,7 @@ static int __wil_tx_vring(struct wil6210_priv *wil, struct vring *vring,
/* performance monitoring */
used = wil_vring_used_tx(vring);
- if (wil_val_in_range(vring_idle_trsh,
+ if (wil_val_in_range(wil->vring_idle_trsh,
used, used + nr_frags + 1)) {
txdata->idle += get_cycles() - txdata->last_idle;
wil_dbg_txrx(wil, "Ring[%2d] not idle %d -> %d\n",
@@ -2175,7 +2175,7 @@ int wil_tx_complete(struct wil6210_priv *wil, int ringid)
/* performance monitoring */
used_new = wil_vring_used_tx(vring);
- if (wil_val_in_range(vring_idle_trsh,
+ if (wil_val_in_range(wil->vring_idle_trsh,
used_new, used_before_complete)) {
wil_dbg_txrx(wil, "Ring[%2d] idle %d -> %d\n",
ringid, used_before_complete, used_new);
diff --git a/drivers/net/wireless/ath/wil6210/wil6210.h b/drivers/net/wireless/ath/wil6210/wil6210.h
index 9525f521d215..c9ab282c161a 100644
--- a/drivers/net/wireless/ath/wil6210/wil6210.h
+++ b/drivers/net/wireless/ath/wil6210/wil6210.h
@@ -31,7 +31,6 @@ extern bool no_fw_recovery;
extern unsigned int mtu_max;
extern unsigned short rx_ring_overflow_thrsh;
extern int agg_wsize;
-extern u32 vring_idle_trsh;
extern bool rx_align_2;
extern bool rx_large_buf;
extern bool debug_fw;
@@ -91,6 +90,11 @@ struct wil_suspend_stats {
unsigned long failed_resumes;
unsigned long rejected_by_device;
unsigned long rejected_by_host;
+ unsigned long long total_suspend_time;
+ unsigned long long min_suspend_time;
+ unsigned long long max_suspend_time;
+ ktime_t collection_start;
+ ktime_t suspend_start_time;
};
/* Calculate MAC buffer size for the firmware. It includes all overhead,
@@ -170,6 +174,10 @@ struct RGF_ICR {
#define RGF_USER_USER_SCRATCH_PAD (0x8802bc)
#define RGF_USER_BL (0x880A3C) /* Boot Loader */
#define RGF_USER_FW_REV_ID (0x880a8c) /* chip revision */
+#define RGF_USER_FW_CALIB_RESULT (0x880a90) /* b0-7:result
+ * b8-15:signature
+ */
+ #define CALIB_RESULT_SIGNATURE (0x11)
#define RGF_USER_CLKS_CTL_0 (0x880abc)
#define BIT_USER_CLKS_CAR_AHB_SW_SEL BIT(1) /* ref clk/PLL */
#define BIT_USER_CLKS_RST_PWGD BIT(11) /* reset on "power good" */
@@ -692,6 +700,7 @@ struct wil6210_priv {
u8 vring2cid_tid[WIL6210_MAX_TX_RINGS][2]; /* [0] - CID, [1] - TID */
struct wil_sta_info sta[WIL6210_MAX_CID];
int bcast_vring;
+ u32 vring_idle_trsh; /* HW fetches up to 16 descriptors at once */
bool use_extended_dma_addr; /* indicates whether we are using 48 bits */
/* scan */
struct cfg80211_scan_request *scan_request;
@@ -731,6 +740,8 @@ struct wil6210_priv {
bool tt_data_set;
struct wmi_tt_data tt_data;
+ int fw_calib_result;
+
#ifdef CONFIG_PM
#ifdef CONFIG_PM_SLEEP
struct notifier_block pm_notify;
diff --git a/drivers/net/wireless/ath/wil6210/wmi.c b/drivers/net/wireless/ath/wil6210/wmi.c
index fba0d6a79ae2..e421fdad81e2 100644
--- a/drivers/net/wireless/ath/wil6210/wmi.c
+++ b/drivers/net/wireless/ath/wil6210/wmi.c
@@ -345,6 +345,11 @@ static void wmi_evt_ready(struct wil6210_priv *wil, int id, void *d, int len)
strlcpy(wdev->wiphy->fw_version, wil->fw_version,
sizeof(wdev->wiphy->fw_version));
+ if (len > offsetof(struct wmi_ready_event, rfc_read_calib_result)) {
+ wil_dbg_wmi(wil, "rfc calibration result %d\n",
+ evt->rfc_read_calib_result);
+ wil->fw_calib_result = evt->rfc_read_calib_result;
+ }
wil_set_recovery_state(wil, fw_recovery_idle);
set_bit(wil_status_fwready, wil->status);
/* let the reset sequence continue */
@@ -382,12 +387,15 @@ static void wmi_evt_rx_mgmt(struct wil6210_priv *wil, int id, void *d, int len)
ch_no = data->info.channel + 1;
freq = ieee80211_channel_to_frequency(ch_no, IEEE80211_BAND_60GHZ);
channel = ieee80211_get_channel(wiphy, freq);
- signal = data->info.sqi;
+ if (test_bit(WMI_FW_CAPABILITY_RSSI_REPORTING, wil->fw_capabilities))
+ signal = 100 * data->info.rssi;
+ else
+ signal = data->info.sqi;
d_status = le16_to_cpu(data->info.status);
fc = rx_mgmt_frame->frame_control;
- wil_dbg_wmi(wil, "MGMT Rx: channel %d MCS %d SNR %d SQI %d%%\n",
- data->info.channel, data->info.mcs, data->info.snr,
+ wil_dbg_wmi(wil, "MGMT Rx: channel %d MCS %d RSSI %d SQI %d%%\n",
+ data->info.channel, data->info.mcs, data->info.rssi,
data->info.sqi);
wil_dbg_wmi(wil, "status 0x%04x len %d fc 0x%04x\n", d_status, d_len,
le16_to_cpu(fc));
diff --git a/drivers/net/wireless/ath/wil6210/wmi.h b/drivers/net/wireless/ath/wil6210/wmi.h
index 256f63c57da0..1b426d7ef81f 100644
--- a/drivers/net/wireless/ath/wil6210/wmi.h
+++ b/drivers/net/wireless/ath/wil6210/wmi.h
@@ -60,6 +60,7 @@ enum wmi_fw_capability {
WMI_FW_CAPABILITY_WMI_ONLY = 5,
WMI_FW_CAPABILITY_THERMAL_THROTTLING = 7,
WMI_FW_CAPABILITY_D3_SUSPEND = 8,
+ WMI_FW_CAPABILITY_RSSI_REPORTING = 12,
WMI_FW_CAPABILITY_MAX,
};
@@ -1299,6 +1300,8 @@ struct wmi_ready_event {
/* enum wmi_phy_capability */
u8 phy_capability;
u8 numof_additional_mids;
+ u8 rfc_read_calib_result;
+ u8 reserved[3];
} __packed;
/* WMI_NOTIFY_REQ_DONE_EVENTID */
@@ -1306,7 +1309,8 @@ struct wmi_notify_req_done_event {
/* beamforming status, 0: fail; 1: OK; 2: retrying */
__le32 status;
__le64 tsf;
- __le32 snr_val;
+ s8 rssi;
+ u8 reserved0[3];
__le32 tx_tpt;
__le32 tx_goodput;
__le32 rx_goodput;
@@ -1602,7 +1606,7 @@ struct wmi_get_ssid_event {
/* wmi_rx_mgmt_info */
struct wmi_rx_mgmt_info {
u8 mcs;
- s8 snr;
+ s8 rssi;
u8 range;
u8 sqi;
__le16 stype;
diff --git a/drivers/net/wireless/cnss/Kconfig b/drivers/net/wireless/cnss/Kconfig
index 6faf9f1ef5d0..863f766bccdb 100644
--- a/drivers/net/wireless/cnss/Kconfig
+++ b/drivers/net/wireless/cnss/Kconfig
@@ -46,7 +46,6 @@ config CLD_HL_SDIO_CORE
select WEXT_CORE
select WEXT_SPY
select NL80211_TESTMODE
- depends on ARCH_MSM
depends on MMC
config CLD_LL_CORE
diff --git a/drivers/net/wireless/cnss/cnss_sdio.c b/drivers/net/wireless/cnss/cnss_sdio.c
index ce7dbc64c4c3..8586bb16cfd3 100644
--- a/drivers/net/wireless/cnss/cnss_sdio.c
+++ b/drivers/net/wireless/cnss/cnss_sdio.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2015-2016, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2015-2017, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -276,6 +276,11 @@ static int cnss_get_hw_resources(struct device *dev)
host = info->host;
+ if (!host) {
+ pr_err("%s: MMC host is invalid\n", __func__);
+ return -ENODEV;
+ }
+
ret = regulator_enable(cnss_pdata->regulator.wlan_vreg);
if (ret) {
pr_err("%s: Failed to enable wlan vreg\n", __func__);
diff --git a/drivers/net/wireless/cnss2/wlan_firmware_service_v01.h b/drivers/net/wireless/cnss2/wlan_firmware_service_v01.h
index a3081433cc2b..9b56eb0c02fb 100644
--- a/drivers/net/wireless/cnss2/wlan_firmware_service_v01.h
+++ b/drivers/net/wireless/cnss2/wlan_firmware_service_v01.h
@@ -77,7 +77,7 @@
#define QMI_WLFW_FUNCTION_NAME_LEN_V01 128
#define QMI_WLFW_MAX_NUM_CE_V01 12
#define QMI_WLFW_MAX_TIMESTAMP_LEN_V01 32
-#define QMI_WLFW_MAX_ATHDIAG_DATA_SIZE_V01 512
+#define QMI_WLFW_MAX_ATHDIAG_DATA_SIZE_V01 6144
#define QMI_WLFW_MAX_BUILD_ID_LEN_V01 128
#define QMI_WLFW_MAX_STR_LEN_V01 16
#define QMI_WLFW_MAX_NUM_SHADOW_REG_V01 24
@@ -483,7 +483,7 @@ struct wlfw_athdiag_read_resp_msg_v01 {
u8 data[QMI_WLFW_MAX_ATHDIAG_DATA_SIZE_V01];
};
-#define WLFW_ATHDIAG_READ_RESP_MSG_V01_MAX_MSG_LEN 524
+#define WLFW_ATHDIAG_READ_RESP_MSG_V01_MAX_MSG_LEN 6156
extern struct elem_info wlfw_athdiag_read_resp_msg_v01_ei[];
struct wlfw_athdiag_write_req_msg_v01 {
@@ -493,7 +493,7 @@ struct wlfw_athdiag_write_req_msg_v01 {
u8 data[QMI_WLFW_MAX_ATHDIAG_DATA_SIZE_V01];
};
-#define WLFW_ATHDIAG_WRITE_REQ_MSG_V01_MAX_MSG_LEN 531
+#define WLFW_ATHDIAG_WRITE_REQ_MSG_V01_MAX_MSG_LEN 6163
extern struct elem_info wlfw_athdiag_write_req_msg_v01_ei[];
struct wlfw_athdiag_write_resp_msg_v01 {
diff --git a/drivers/platform/msm/ipa/ipa_v2/ipa_debugfs.c b/drivers/platform/msm/ipa/ipa_v2/ipa_debugfs.c
index cb95f6e98956..4275e3d26157 100644
--- a/drivers/platform/msm/ipa/ipa_v2/ipa_debugfs.c
+++ b/drivers/platform/msm/ipa/ipa_v2/ipa_debugfs.c
@@ -83,6 +83,10 @@ const char *ipa_event_name[] = {
__stringify(IPA_QUOTA_REACH),
__stringify(IPA_SSR_BEFORE_SHUTDOWN),
__stringify(IPA_SSR_AFTER_POWERUP),
+ __stringify(ADD_VLAN_IFACE),
+ __stringify(DEL_VLAN_IFACE),
+ __stringify(ADD_L2TP_VLAN_MAPPING),
+ __stringify(DEL_L2TP_VLAN_MAPPING)
};
const char *ipa_hdr_l2_type_name[] = {
diff --git a/drivers/platform/msm/ipa/ipa_v2/ipa_rt.c b/drivers/platform/msm/ipa/ipa_v2/ipa_rt.c
index 0531919487d7..293a60a60881 100644
--- a/drivers/platform/msm/ipa/ipa_v2/ipa_rt.c
+++ b/drivers/platform/msm/ipa/ipa_v2/ipa_rt.c
@@ -53,7 +53,7 @@ int __ipa_generate_rt_hw_rule_v2(enum ipa_ip_type ip,
int pipe_idx;
if (buf == NULL) {
- memset(tmp, 0, IPA_RT_FLT_HW_RULE_BUF_SIZE);
+ memset(tmp, 0, (IPA_RT_FLT_HW_RULE_BUF_SIZE/4));
buf = (u8 *)tmp;
}
@@ -75,8 +75,15 @@ int __ipa_generate_rt_hw_rule_v2(enum ipa_ip_type ip,
rule_hdr->u.hdr.pipe_dest_idx = pipe_idx;
rule_hdr->u.hdr.system = !ipa_ctx->hdr_tbl_lcl;
if (entry->hdr) {
- rule_hdr->u.hdr.hdr_offset =
- entry->hdr->offset_entry->offset >> 2;
+ if (entry->hdr->cookie == IPA_HDR_COOKIE) {
+ rule_hdr->u.hdr.hdr_offset =
+ entry->hdr->offset_entry->offset >> 2;
+ } else {
+ IPAERR("Entry hdr deleted by user = %d cookie = %u\n",
+ entry->hdr->user_deleted, entry->hdr->cookie);
+ WARN_ON(1);
+ rule_hdr->u.hdr.hdr_offset = 0;
+ }
} else {
rule_hdr->u.hdr.hdr_offset = 0;
}
diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa.c b/drivers/platform/msm/ipa/ipa_v3/ipa.c
index 52f99c830b47..4cba8a7573bb 100644
--- a/drivers/platform/msm/ipa/ipa_v3/ipa.c
+++ b/drivers/platform/msm/ipa/ipa_v3/ipa.c
@@ -143,6 +143,9 @@
#define IPA_IOC_ALLOC_NAT_MEM32 _IOWR(IPA_IOC_MAGIC, \
IPA_IOCTL_ALLOC_NAT_MEM, \
compat_uptr_t)
+#define IPA_IOC_ALLOC_NAT_TABLE32 _IOWR(IPA_IOC_MAGIC, \
+ IPA_IOCTL_ALLOC_NAT_TABLE, \
+ compat_uptr_t)
#define IPA_IOC_V4_INIT_NAT32 _IOWR(IPA_IOC_MAGIC, \
IPA_IOCTL_V4_INIT_NAT, \
compat_uptr_t)
@@ -152,6 +155,9 @@
#define IPA_IOC_V4_DEL_NAT32 _IOWR(IPA_IOC_MAGIC, \
IPA_IOCTL_V4_DEL_NAT, \
compat_uptr_t)
+#define IPA_IOC_DEL_NAT_TABLE32 _IOWR(IPA_IOC_MAGIC, \
+ IPA_IOCTL_DEL_NAT_TABLE, \
+ compat_uptr_t)
#define IPA_IOC_GET_NAT_OFFSET32 _IOWR(IPA_IOC_MAGIC, \
IPA_IOCTL_GET_NAT_OFFSET, \
compat_uptr_t)
@@ -207,6 +213,18 @@ struct ipa3_ioc_nat_alloc_mem32 {
compat_size_t size;
compat_off_t offset;
};
+
+/**
+* struct ipa_ioc_nat_ipv6ct_table_alloc32 - table memory allocation
+* properties
+* @size: input parameter, size of table in bytes
+* @offset: output parameter, offset into page in case of system memory
+*/
+struct ipa_ioc_nat_ipv6ct_table_alloc32 {
+ compat_size_t size;
+ compat_off_t offset;
+};
+
#endif
#define IPA_TZ_UNLOCK_ATTRIBUTE 0x0C0311
@@ -611,6 +629,90 @@ static int ipa3_send_wan_msg(unsigned long usr_param, uint8_t msg_type)
return 0;
}
+static void ipa3_vlan_l2tp_msg_free_cb(void *buff, u32 len, u32 type)
+{
+ if (!buff) {
+ IPAERR("Null buffer\n");
+ return;
+ }
+
+ if (type != ADD_VLAN_IFACE &&
+ type != DEL_VLAN_IFACE &&
+ type != ADD_L2TP_VLAN_MAPPING &&
+ type != DEL_L2TP_VLAN_MAPPING) {
+ IPAERR("Wrong type given. buff %pK type %d\n", buff, type);
+ return;
+ }
+
+ kfree(buff);
+}
+
+static int ipa3_send_vlan_l2tp_msg(unsigned long usr_param, uint8_t msg_type)
+{
+ int retval;
+ struct ipa_ioc_vlan_iface_info *vlan_info;
+ struct ipa_ioc_l2tp_vlan_mapping_info *mapping_info;
+ struct ipa_msg_meta msg_meta;
+
+ if (msg_type == ADD_VLAN_IFACE ||
+ msg_type == DEL_VLAN_IFACE) {
+ vlan_info = kzalloc(sizeof(struct ipa_ioc_vlan_iface_info),
+ GFP_KERNEL);
+ if (!vlan_info) {
+ IPAERR("no memory\n");
+ return -ENOMEM;
+ }
+
+ if (copy_from_user((u8 *)vlan_info, (void __user *)usr_param,
+ sizeof(struct ipa_ioc_vlan_iface_info))) {
+ kfree(vlan_info);
+ return -EFAULT;
+ }
+
+ memset(&msg_meta, 0, sizeof(msg_meta));
+ msg_meta.msg_type = msg_type;
+ msg_meta.msg_len = sizeof(struct ipa_ioc_vlan_iface_info);
+ retval = ipa3_send_msg(&msg_meta, vlan_info,
+ ipa3_vlan_l2tp_msg_free_cb);
+ if (retval) {
+ IPAERR("ipa3_send_msg failed: %d\n", retval);
+ kfree(vlan_info);
+ return retval;
+ }
+ } else if (msg_type == ADD_L2TP_VLAN_MAPPING ||
+ msg_type == DEL_L2TP_VLAN_MAPPING) {
+ mapping_info = kzalloc(sizeof(struct
+ ipa_ioc_l2tp_vlan_mapping_info), GFP_KERNEL);
+ if (!mapping_info) {
+ IPAERR("no memory\n");
+ return -ENOMEM;
+ }
+
+ if (copy_from_user((u8 *)mapping_info,
+ (void __user *)usr_param,
+ sizeof(struct ipa_ioc_l2tp_vlan_mapping_info))) {
+ kfree(mapping_info);
+ return -EFAULT;
+ }
+
+ memset(&msg_meta, 0, sizeof(msg_meta));
+ msg_meta.msg_type = msg_type;
+ msg_meta.msg_len = sizeof(struct
+ ipa_ioc_l2tp_vlan_mapping_info);
+ retval = ipa3_send_msg(&msg_meta, mapping_info,
+ ipa3_vlan_l2tp_msg_free_cb);
+ if (retval) {
+ IPAERR("ipa3_send_msg failed: %d\n", retval);
+ kfree(mapping_info);
+ return retval;
+ }
+ } else {
+ IPAERR("Unexpected event\n");
+ return -EFAULT;
+ }
+
+ return 0;
+}
static long ipa3_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
{
@@ -619,8 +721,10 @@ static long ipa3_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
u8 header[128] = { 0 };
u8 *param = NULL;
struct ipa_ioc_nat_alloc_mem nat_mem;
+ struct ipa_ioc_nat_ipv6ct_table_alloc table_alloc;
struct ipa_ioc_v4_nat_init nat_init;
struct ipa_ioc_v4_nat_del nat_del;
+ struct ipa_ioc_nat_ipv6ct_table_del table_del;
struct ipa_ioc_rm_dependency rm_depend;
size_t sz;
int pre_entry;
@@ -659,6 +763,26 @@ static long ipa3_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
break;
}
break;
+
+ case IPA_IOC_ALLOC_NAT_TABLE:
+ if (copy_from_user(&table_alloc, (const void __user *)arg,
+ sizeof(struct ipa_ioc_nat_ipv6ct_table_alloc))) {
+ retval = -EFAULT;
+ break;
+ }
+
+ if (ipa3_allocate_nat_table(&table_alloc)) {
+ retval = -EFAULT;
+ break;
+ }
+ if (table_alloc.offset &&
+ copy_to_user((void __user *)arg, &table_alloc, sizeof(
+ struct ipa_ioc_nat_ipv6ct_table_alloc))) {
+ retval = -EFAULT;
+ break;
+ }
+ break;
+
case IPA_IOC_V4_INIT_NAT:
if (copy_from_user((u8 *)&nat_init, (u8 *)arg,
sizeof(struct ipa_ioc_v4_nat_init))) {
@@ -719,6 +843,18 @@ static long ipa3_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
}
break;
+ case IPA_IOC_DEL_NAT_TABLE:
+ if (copy_from_user(&table_del, (const void __user *)arg,
+ sizeof(struct ipa_ioc_nat_ipv6ct_table_del))) {
+ retval = -EFAULT;
+ break;
+ }
+ if (ipa3_del_nat_table(&table_del)) {
+ retval = -EFAULT;
+ break;
+ }
+ break;
+
case IPA_IOC_ADD_HDR:
if (copy_from_user(header, (u8 *)arg,
sizeof(struct ipa_ioc_add_hdr))) {
@@ -1582,6 +1718,34 @@ static long ipa3_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
}
break;
+ case IPA_IOC_ADD_VLAN_IFACE:
+ if (ipa3_send_vlan_l2tp_msg(arg, ADD_VLAN_IFACE)) {
+ retval = -EFAULT;
+ break;
+ }
+ break;
+
+ case IPA_IOC_DEL_VLAN_IFACE:
+ if (ipa3_send_vlan_l2tp_msg(arg, DEL_VLAN_IFACE)) {
+ retval = -EFAULT;
+ break;
+ }
+ break;
+
+ case IPA_IOC_ADD_L2TP_VLAN_MAPPING:
+ if (ipa3_send_vlan_l2tp_msg(arg, ADD_L2TP_VLAN_MAPPING)) {
+ retval = -EFAULT;
+ break;
+ }
+ break;
+
+ case IPA_IOC_DEL_L2TP_VLAN_MAPPING:
+ if (ipa3_send_vlan_l2tp_msg(arg, DEL_L2TP_VLAN_MAPPING)) {
+ retval = -EFAULT;
+ break;
+ }
+ break;
+
default: /* redundant, as cmd was checked against MAXNR */
IPA_ACTIVE_CLIENTS_DEC_SIMPLE();
return -ENOTTY;
@@ -2997,6 +3161,34 @@ static void ipa3_teardown_apps_pipes(void)
}
#ifdef CONFIG_COMPAT
+static long compat_ipa3_nat_ipv6ct_alloc_table(unsigned long arg,
+ int (alloc_func)(struct ipa_ioc_nat_ipv6ct_table_alloc *))
+{
+ long retval;
+ struct ipa_ioc_nat_ipv6ct_table_alloc32 table_alloc32;
+ struct ipa_ioc_nat_ipv6ct_table_alloc table_alloc;
+
+ retval = copy_from_user(&table_alloc32, (const void __user *)arg,
+ sizeof(struct ipa_ioc_nat_ipv6ct_table_alloc32));
+ if (retval)
+ return retval;
+
+ table_alloc.size = (size_t)table_alloc32.size;
+ table_alloc.offset = (off_t)table_alloc32.offset;
+
+ retval = alloc_func(&table_alloc);
+ if (retval)
+ return retval;
+
+ if (table_alloc.offset) {
+ table_alloc32.offset = (compat_off_t)table_alloc.offset;
+ retval = copy_to_user((void __user *)arg, &table_alloc32,
+ sizeof(struct ipa_ioc_nat_ipv6ct_table_alloc32));
+ }
+
+ return retval;
+}
+
long compat_ipa3_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{
int retval = 0;
@@ -3068,6 +3260,9 @@ long compat_ipa3_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
}
ret:
return retval;
+ case IPA_IOC_ALLOC_NAT_TABLE32:
+ return compat_ipa3_nat_ipv6ct_alloc_table(arg,
+ ipa3_allocate_nat_table);
case IPA_IOC_V4_INIT_NAT32:
cmd = IPA_IOC_V4_INIT_NAT;
break;
@@ -3077,6 +3272,9 @@ ret:
case IPA_IOC_V4_DEL_NAT32:
cmd = IPA_IOC_V4_DEL_NAT;
break;
+ case IPA_IOC_DEL_NAT_TABLE32:
+ cmd = IPA_IOC_DEL_NAT_TABLE;
+ break;
case IPA_IOC_GET_NAT_OFFSET32:
cmd = IPA_IOC_GET_NAT_OFFSET;
break;
@@ -4075,12 +4273,12 @@ static void ipa3_post_init_wq(struct work_struct *work)
ipa3_post_init(&ipa3_res, ipa3_ctx->dev);
}
-static int ipa3_trigger_fw_loading_mdms(void)
+static int ipa3_manual_load_ipa_fws(void)
{
int result;
const struct firmware *fw;
- IPADBG("FW loading process initiated\n");
+ IPADBG("Manual FW loading process initiated\n");
result = request_firmware(&fw, IPA_FWS_PATH, ipa3_ctx->dev);
if (result < 0) {
@@ -4096,7 +4294,7 @@ static int ipa3_trigger_fw_loading_mdms(void)
result = ipa3_load_fws(fw, ipa3_res.transport_mem_base);
if (result) {
- IPAERR("IPA FWs loading has failed\n");
+ IPAERR("Manual IPA FWs loading has failed\n");
release_firmware(fw);
return result;
}
@@ -4111,15 +4309,15 @@ static int ipa3_trigger_fw_loading_mdms(void)
release_firmware(fw);
- IPADBG("FW loading process is complete\n");
+ IPADBG("Manual FW loading process is complete\n");
return 0;
}
-static int ipa3_trigger_fw_loading_msms(void)
+static int ipa3_pil_load_ipa_fws(void)
{
void *subsystem_get_retval = NULL;
- IPADBG("FW loading process initiated\n");
+ IPADBG("PIL FW loading process initiated\n");
subsystem_get_retval = subsystem_get(IPA_SUBSYSTEM_NAME);
if (IS_ERR_OR_NULL(subsystem_get_retval)) {
@@ -4127,7 +4325,7 @@ static int ipa3_trigger_fw_loading_msms(void)
return -EINVAL;
}
- IPADBG("FW loading process is complete\n");
+ IPADBG("PIL FW loading process is complete\n");
return 0;
}
@@ -4157,25 +4355,27 @@ static ssize_t ipa3_write(struct file *file, const char __user *buf,
* We will trigger the process only if we're in GSI mode, otherwise,
* we just ignore the write.
*/
- if (ipa3_ctx->transport_prototype == IPA_TRANSPORT_TYPE_GSI) {
- IPA_ACTIVE_CLIENTS_INC_SIMPLE();
+ if (ipa3_ctx->transport_prototype != IPA_TRANSPORT_TYPE_GSI)
+ return count;
- if (ipa3_is_msm_device())
- result = ipa3_trigger_fw_loading_msms();
- else
- result = ipa3_trigger_fw_loading_mdms();
- /* No IPAv3.x chipsets that don't support FW loading */
+ IPA_ACTIVE_CLIENTS_INC_SIMPLE();
- IPA_ACTIVE_CLIENTS_DEC_SIMPLE();
+ if (ipa3_is_msm_device() || (ipa3_ctx->ipa_hw_type >= IPA_HW_v3_5))
+ result = ipa3_pil_load_ipa_fws();
+ else
+ result = ipa3_manual_load_ipa_fws();
- if (result) {
- IPAERR("FW loading process has failed\n");
- return result;
- } else {
- queue_work(ipa3_ctx->transport_power_mgmt_wq,
- &ipa3_post_init_work);
- }
+ IPA_ACTIVE_CLIENTS_DEC_SIMPLE();
+
+ if (result) {
+ IPAERR("IPA FW loading process has failed\n");
+ return result;
}
+
+ queue_work(ipa3_ctx->transport_power_mgmt_wq,
+ &ipa3_post_init_work);
+ IPADBG("IPA FW loaded successfully\n");
+
return count;
}
@@ -4619,6 +4819,7 @@ static int ipa3_pre_init(const struct ipa3_plat_drv_res *resource_p,
mutex_init(&ipa3_ctx->lock);
mutex_init(&ipa3_ctx->nat_mem.lock);
+ mutex_init(&ipa3_ctx->q6_proxy_clk_vote_mutex);
idr_init(&ipa3_ctx->ipa_idr);
spin_lock_init(&ipa3_ctx->idr_lock);
diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_debugfs.c b/drivers/platform/msm/ipa/ipa_v3/ipa_debugfs.c
index fbf84ab7d2d4..c7ab616cb5b8 100644
--- a/drivers/platform/msm/ipa/ipa_v3/ipa_debugfs.c
+++ b/drivers/platform/msm/ipa/ipa_v3/ipa_debugfs.c
@@ -64,6 +64,10 @@ const char *ipa3_event_name[] = {
__stringify(IPA_QUOTA_REACH),
__stringify(IPA_SSR_BEFORE_SHUTDOWN),
__stringify(IPA_SSR_AFTER_POWERUP),
+ __stringify(ADD_VLAN_IFACE),
+ __stringify(DEL_VLAN_IFACE),
+ __stringify(ADD_L2TP_VLAN_MAPPING),
+ __stringify(DEL_L2TP_VLAN_MAPPING)
};
const char *ipa3_hdr_l2_type_name[] = {
diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_i.h b/drivers/platform/msm/ipa/ipa_v3/ipa_i.h
index 4278dc45aad2..7da78457f1b1 100644
--- a/drivers/platform/msm/ipa/ipa_v3/ipa_i.h
+++ b/drivers/platform/msm/ipa/ipa_v3/ipa_i.h
@@ -38,7 +38,6 @@
#include "ipa_uc_offload_i.h"
#define DRV_NAME "ipa"
-#define NAT_DEV_NAME "ipaNatTable"
#define IPA_COOKIE 0x57831603
#define IPA_RT_RULE_COOKIE 0x57831604
#define IPA_RT_TBL_COOKIE 0x57831605
@@ -1231,6 +1230,7 @@ struct ipa3_context {
u32 enable_clock_scaling;
u32 curr_ipa_clk_rate;
bool q6_proxy_clk_vote_valid;
+ struct mutex q6_proxy_clk_vote_mutex;
u32 ipa_num_pipes;
struct ipa3_wlan_comm_memb wc_memb;
@@ -1640,12 +1640,15 @@ int ipa3_reset_flt(enum ipa_ip_type ip);
* NAT
*/
int ipa3_allocate_nat_device(struct ipa_ioc_nat_alloc_mem *mem);
+int ipa3_allocate_nat_table(
+ struct ipa_ioc_nat_ipv6ct_table_alloc *table_alloc);
int ipa3_nat_init_cmd(struct ipa_ioc_v4_nat_init *init);
int ipa3_nat_dma_cmd(struct ipa_ioc_nat_dma_cmd *dma);
int ipa3_nat_del_cmd(struct ipa_ioc_v4_nat_del *del);
+int ipa3_del_nat_table(struct ipa_ioc_nat_ipv6ct_table_del *del);
/*
* Messaging
diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_mhi.c b/drivers/platform/msm/ipa/ipa_v3/ipa_mhi.c
index 3267e0e83a82..0bf2be7f8463 100644
--- a/drivers/platform/msm/ipa/ipa_v3/ipa_mhi.c
+++ b/drivers/platform/msm/ipa/ipa_v3/ipa_mhi.c
@@ -630,6 +630,8 @@ int ipa3_mhi_destroy_channel(enum ipa_client_type client)
}
ep = &ipa3_ctx->ep[ipa_ep_idx];
+ IPA_ACTIVE_CLIENTS_INC_EP(client);
+
IPA_MHI_DBG("reset event ring (hdl: %lu, ep: %d)\n",
ep->gsi_evt_ring_hdl, ipa_ep_idx);
@@ -651,8 +653,10 @@ int ipa3_mhi_destroy_channel(enum ipa_client_type client)
goto fail;
}
+ IPA_ACTIVE_CLIENTS_DEC_EP(client);
return 0;
fail:
+ IPA_ACTIVE_CLIENTS_DEC_EP(client);
return res;
}
diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_nat.c b/drivers/platform/msm/ipa/ipa_v3/ipa_nat.c
index 0256ff89ae24..a78a0a608cb4 100644
--- a/drivers/platform/msm/ipa/ipa_v3/ipa_nat.c
+++ b/drivers/platform/msm/ipa/ipa_v3/ipa_nat.c
@@ -34,7 +34,6 @@ enum nat_table_type {
#define NAT_TABLE_ENTRY_SIZE_BYTE 32
#define NAT_INTEX_TABLE_ENTRY_SIZE_BYTE 4
-
static int ipa3_nat_vma_fault_remap(
struct vm_area_struct *vma, struct vm_fault *vmf)
{
@@ -167,7 +166,7 @@ int ipa3_create_nat_device(void)
IPADBG("\n");
mutex_lock(&nat_ctx->lock);
- nat_ctx->class = class_create(THIS_MODULE, NAT_DEV_NAME);
+ nat_ctx->class = class_create(THIS_MODULE, IPA_NAT_DEV_NAME);
if (IS_ERR(nat_ctx->class)) {
IPAERR("unable to create the class\n");
result = -ENODEV;
@@ -176,7 +175,7 @@ int ipa3_create_nat_device(void)
result = alloc_chrdev_region(&nat_ctx->dev_num,
0,
1,
- NAT_DEV_NAME);
+ IPA_NAT_DEV_NAME);
if (result) {
IPAERR("alloc_chrdev_region err.\n");
result = -ENODEV;
@@ -185,7 +184,7 @@ int ipa3_create_nat_device(void)
nat_ctx->dev =
device_create(nat_ctx->class, NULL, nat_ctx->dev_num, nat_ctx,
- "%s", NAT_DEV_NAME);
+ "%s", IPA_NAT_DEV_NAME);
if (IS_ERR(nat_ctx->dev)) {
IPAERR("device_create err:%ld\n", PTR_ERR(nat_ctx->dev));
@@ -253,9 +252,10 @@ int ipa3_allocate_nat_device(struct ipa_ioc_nat_alloc_mem *mem)
IPADBG("passed memory size %zu\n", mem->size);
mutex_lock(&nat_ctx->lock);
- if (strcmp(mem->dev_name, NAT_DEV_NAME)) {
+ if (strcmp(IPA_NAT_DEV_NAME, mem->dev_name)) {
IPAERR_RL("Nat device name mismatch\n");
- IPAERR_RL("Expect: %s Recv: %s\n", NAT_DEV_NAME, mem->dev_name);
+ IPAERR_RL("Expect: %s Recv: %s\n",
+ IPA_NAT_DEV_NAME, mem->dev_name);
result = -EPERM;
goto bail;
}
@@ -306,6 +306,34 @@ bail:
return result;
}
+/**
+* ipa3_allocate_nat_table() - Allocates memory for the NAT table
+* @table_alloc: [in/out] memory parameters
+*
+* Called by NAT client to allocate memory for the table entries.
+* Based on the request size either shared or system memory will be used.
+*
+* Returns: 0 on success, negative on failure
+*/
+int ipa3_allocate_nat_table(struct ipa_ioc_nat_ipv6ct_table_alloc *table_alloc)
+{
+ int result;
+ struct ipa_ioc_nat_alloc_mem tmp;
+
+ strlcpy(tmp.dev_name, IPA_NAT_DEV_NAME, IPA_RESOURCE_NAME_MAX);
+ tmp.size = table_alloc->size;
+ tmp.offset = 0;
+
+ result = ipa3_allocate_nat_device(&tmp);
+ if (result)
+ goto bail;
+
+ table_alloc->offset = tmp.offset;
+
+bail:
+ return result;
+}
+
/* IOCTL function handlers */
/**
* ipa3_nat_init_cmd() - Post IP_V4_NAT_INIT command to IPA HW
@@ -833,3 +861,22 @@ destroy_regwrt_imm_cmd:
bail:
return result;
}
+
+/**
+* ipa3_del_nat_table() - Delete the NAT table
+* @del: [in] delete table parameters
+*
+* Called by NAT client to delete the table
+*
+* Returns: 0 on success, negative on failure
+*/
+int ipa3_del_nat_table(struct ipa_ioc_nat_ipv6ct_table_del *del)
+{
+ struct ipa_ioc_v4_nat_del tmp;
+
+ tmp.table_index = del->table_index;
+ tmp.public_ip_addr = ipa3_ctx->nat_mem.public_ip_addr;
+
+ return ipa3_nat_del_cmd(&tmp);
+}
+
diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_rt.c b/drivers/platform/msm/ipa/ipa_v3/ipa_rt.c
index 8e790c89ed13..ff57e3bd48f0 100644
--- a/drivers/platform/msm/ipa/ipa_v3/ipa_rt.c
+++ b/drivers/platform/msm/ipa/ipa_v3/ipa_rt.c
@@ -72,11 +72,18 @@ static int ipa_generate_rt_hw_rule(enum ipa_ip_type ip,
if (entry->proc_ctx || (entry->hdr && entry->hdr->is_hdr_proc_ctx)) {
struct ipa3_hdr_proc_ctx_entry *proc_ctx;
proc_ctx = (entry->proc_ctx) ? : entry->hdr->proc_ctx;
- gen_params.hdr_lcl = ipa3_ctx->hdr_proc_ctx_tbl_lcl;
- gen_params.hdr_type = IPAHAL_RT_RULE_HDR_PROC_CTX;
- gen_params.hdr_ofst = proc_ctx->offset_entry->offset +
- ipa3_ctx->hdr_proc_ctx_tbl.start_offset;
- } else if (entry->hdr) {
+ if ((proc_ctx == NULL) ||
+ (proc_ctx->cookie != IPA_PROC_HDR_COOKIE)) {
+ gen_params.hdr_type = IPAHAL_RT_RULE_HDR_NONE;
+ gen_params.hdr_ofst = 0;
+ } else {
+ gen_params.hdr_lcl = ipa3_ctx->hdr_proc_ctx_tbl_lcl;
+ gen_params.hdr_type = IPAHAL_RT_RULE_HDR_PROC_CTX;
+ gen_params.hdr_ofst = proc_ctx->offset_entry->offset +
+ ipa3_ctx->hdr_proc_ctx_tbl.start_offset;
+ }
+ } else if ((entry->hdr != NULL) &&
+ (entry->hdr->cookie == IPA_HDR_COOKIE)) {
gen_params.hdr_lcl = ipa3_ctx->hdr_tbl_lcl;
gen_params.hdr_type = IPAHAL_RT_RULE_HDR_RAW;
gen_params.hdr_ofst = entry->hdr->offset_entry->offset;
diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_utils.c b/drivers/platform/msm/ipa/ipa_v3/ipa_utils.c
index 545c2b599a6f..4979f62b928f 100644
--- a/drivers/platform/msm/ipa/ipa_v3/ipa_utils.c
+++ b/drivers/platform/msm/ipa/ipa_v3/ipa_utils.c
@@ -2983,10 +2983,15 @@ bool ipa3_is_client_handle_valid(u32 clnt_hdl)
*/
void ipa3_proxy_clk_unvote(void)
{
- if (ipa3_is_ready() && ipa3_ctx->q6_proxy_clk_vote_valid) {
+ if (!ipa3_is_ready())
+ return;
+
+ mutex_lock(&ipa3_ctx->q6_proxy_clk_vote_mutex);
+ if (ipa3_ctx->q6_proxy_clk_vote_valid) {
IPA_ACTIVE_CLIENTS_DEC_SPECIAL("PROXY_CLK_VOTE");
ipa3_ctx->q6_proxy_clk_vote_valid = false;
}
+ mutex_unlock(&ipa3_ctx->q6_proxy_clk_vote_mutex);
}
/**
@@ -2996,10 +3001,15 @@ void ipa3_proxy_clk_unvote(void)
*/
void ipa3_proxy_clk_vote(void)
{
- if (ipa3_is_ready() && !ipa3_ctx->q6_proxy_clk_vote_valid) {
+ if (!ipa3_is_ready())
+ return;
+
+ mutex_lock(&ipa3_ctx->q6_proxy_clk_vote_mutex);
+ if (!ipa3_ctx->q6_proxy_clk_vote_valid) {
IPA_ACTIVE_CLIENTS_INC_SPECIAL("PROXY_CLK_VOTE");
ipa3_ctx->q6_proxy_clk_vote_valid = true;
}
+ mutex_unlock(&ipa3_ctx->q6_proxy_clk_vote_mutex);
}
/**
diff --git a/drivers/platform/msm/sps/sps.c b/drivers/platform/msm/sps/sps.c
index ddb2388c5006..e7710f929e71 100644
--- a/drivers/platform/msm/sps/sps.c
+++ b/drivers/platform/msm/sps/sps.c
@@ -2322,8 +2322,11 @@ int sps_deregister_bam_device(unsigned long dev_handle)
mutex_lock(&bam->lock);
sps_bam_device_de_init(bam);
mutex_unlock(&bam->lock);
+ ipc_log_context_destroy(bam->ipc_log0);
ipc_log_context_destroy(bam->ipc_log1);
ipc_log_context_destroy(bam->ipc_log2);
+ ipc_log_context_destroy(bam->ipc_log3);
+ ipc_log_context_destroy(bam->ipc_log4);
if (bam->props.virt_size)
(void)iounmap(bam->props.virt_addr);
diff --git a/drivers/power/power_supply_sysfs.c b/drivers/power/power_supply_sysfs.c
index a45a51490817..2e9ff2afcba2 100644
--- a/drivers/power/power_supply_sysfs.c
+++ b/drivers/power/power_supply_sysfs.c
@@ -247,6 +247,8 @@ static struct device_attribute power_supply_attrs[] = {
POWER_SUPPLY_ATTR(low_power),
POWER_SUPPLY_ATTR(temp_cool),
POWER_SUPPLY_ATTR(temp_warm),
+ POWER_SUPPLY_ATTR(temp_cold),
+ POWER_SUPPLY_ATTR(temp_hot),
POWER_SUPPLY_ATTR(system_temp_level),
POWER_SUPPLY_ATTR(resistance),
POWER_SUPPLY_ATTR(resistance_capacitive),
diff --git a/drivers/power/supply/qcom/fg-core.h b/drivers/power/supply/qcom/fg-core.h
index 88dcdd8fd7be..16441d6e09e4 100644
--- a/drivers/power/supply/qcom/fg-core.h
+++ b/drivers/power/supply/qcom/fg-core.h
@@ -104,7 +104,7 @@ enum sram_access_flags {
};
/* JEITA */
-enum {
+enum jeita_levels {
JEITA_COLD = 0,
JEITA_COOL,
JEITA_WARM,
@@ -239,6 +239,7 @@ enum ttf_mode {
struct fg_dt_props {
bool force_load_profile;
bool hold_soc_while_full;
+ bool linearize_soc;
bool auto_recharge_soc;
int cutoff_volt_mv;
int empty_volt_mv;
diff --git a/drivers/power/supply/qcom/qpnp-fg-gen3.c b/drivers/power/supply/qcom/qpnp-fg-gen3.c
index 361efd4fbbbd..4788053115e1 100644
--- a/drivers/power/supply/qcom/qpnp-fg-gen3.c
+++ b/drivers/power/supply/qcom/qpnp-fg-gen3.c
@@ -576,6 +576,41 @@ static int fg_get_charge_counter(struct fg_chip *chip, int *val)
return 0;
}
+static int fg_get_jeita_threshold(struct fg_chip *chip,
+ enum jeita_levels level, int *temp_decidegC)
+{
+ int rc;
+ u8 val;
+ u16 reg;
+
+ switch (level) {
+ case JEITA_COLD:
+ reg = BATT_INFO_JEITA_TOO_COLD(chip);
+ break;
+ case JEITA_COOL:
+ reg = BATT_INFO_JEITA_COLD(chip);
+ break;
+ case JEITA_WARM:
+ reg = BATT_INFO_JEITA_HOT(chip);
+ break;
+ case JEITA_HOT:
+ reg = BATT_INFO_JEITA_TOO_HOT(chip);
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ rc = fg_read(chip, reg, &val, 1);
+ if (rc < 0) {
+ pr_err("Error in reading jeita level %d, rc=%d\n", level, rc);
+ return rc;
+ }
+
+ /* Resolution is 0.5C. Base is -30C. */
+ *temp_decidegC = (((5 * val) / 10) - 30) * 10;
+ return 0;
+}
+
#define BATT_TEMP_NUMR 1
#define BATT_TEMP_DENR 1
static int fg_get_battery_temp(struct fg_chip *chip, int *val)
@@ -838,7 +873,7 @@ static int fg_get_prop_capacity(struct fg_chip *chip, int *val)
if (rc < 0)
return rc;
- if (chip->delta_soc > 0)
+ if (chip->dt.linearize_soc && chip->delta_soc > 0)
*val = chip->maint_soc;
else
*val = msoc;
@@ -978,12 +1013,6 @@ static int fg_get_batt_profile(struct fg_chip *chip)
return 0;
}
-static inline void get_temp_setpoint(int threshold, u8 *val)
-{
- /* Resolution is 0.5C. Base is -30C. */
- *val = DIV_ROUND_CLOSEST((threshold + 30) * 10, 5);
-}
-
static inline void get_batt_temp_delta(int delta, u8 *val)
{
switch (delta) {
@@ -1658,12 +1687,38 @@ static int fg_set_recharge_voltage(struct fg_chip *chip, int voltage_mv)
return 0;
}
+static int fg_configure_full_soc(struct fg_chip *chip, int bsoc)
+{
+ int rc;
+ u8 full_soc[2] = {0xFF, 0xFF};
+
+ /*
+ * Once SOC masking condition is cleared, FULL_SOC and MONOTONIC_SOC
+ * needs to be updated to reflect the same. Write battery SOC to
+ * FULL_SOC and write a full value to MONOTONIC_SOC.
+ */
+ rc = fg_sram_write(chip, FULL_SOC_WORD, FULL_SOC_OFFSET,
+ (u8 *)&bsoc, 2, FG_IMA_ATOMIC);
+ if (rc < 0) {
+ pr_err("failed to write full_soc rc=%d\n", rc);
+ return rc;
+ }
+
+ rc = fg_sram_write(chip, MONOTONIC_SOC_WORD, MONOTONIC_SOC_OFFSET,
+ full_soc, 2, FG_IMA_ATOMIC);
+ if (rc < 0) {
+ pr_err("failed to write monotonic_soc rc=%d\n", rc);
+ return rc;
+ }
+
+ return 0;
+}
+
#define AUTO_RECHG_VOLT_LOW_LIMIT_MV 3700
static int fg_charge_full_update(struct fg_chip *chip)
{
union power_supply_propval prop = {0, };
int rc, msoc, bsoc, recharge_soc, msoc_raw;
- u8 full_soc[2] = {0xFF, 0xFF};
if (!chip->dt.hold_soc_while_full)
return 0;
@@ -1722,24 +1777,24 @@ static int fg_charge_full_update(struct fg_chip *chip)
fg_dbg(chip, FG_STATUS, "Terminated charging @ SOC%d\n",
msoc);
}
- } else if (msoc_raw < recharge_soc && chip->charge_full) {
- chip->delta_soc = FULL_CAPACITY - msoc;
+ } else if (msoc_raw <= recharge_soc && chip->charge_full) {
+ if (chip->dt.linearize_soc) {
+ chip->delta_soc = FULL_CAPACITY - msoc;
- /*
- * We're spreading out the delta SOC over every 10% change
- * in monotonic SOC. We cannot spread more than 9% in the
- * range of 0-100 skipping the first 10%.
- */
- if (chip->delta_soc > 9) {
- chip->delta_soc = 0;
- chip->maint_soc = 0;
- } else {
- chip->maint_soc = FULL_CAPACITY;
- chip->last_msoc = msoc;
+ /*
+ * We're spreading out the delta SOC over every 10%
+ * change in monotonic SOC. We cannot spread more than
+ * 9% in the range of 0-100 skipping the first 10%.
+ */
+ if (chip->delta_soc > 9) {
+ chip->delta_soc = 0;
+ chip->maint_soc = 0;
+ } else {
+ chip->maint_soc = FULL_CAPACITY;
+ chip->last_msoc = msoc;
+ }
}
- chip->charge_full = false;
-
/*
* Raise the recharge voltage so that VBAT_LT_RECHG signal
* will be asserted soon as battery SOC had dropped below
@@ -1752,35 +1807,23 @@ static int fg_charge_full_update(struct fg_chip *chip)
rc);
goto out;
}
- fg_dbg(chip, FG_STATUS, "msoc_raw = %d bsoc: %d recharge_soc: %d delta_soc: %d\n",
- msoc_raw, bsoc >> 8, recharge_soc, chip->delta_soc);
- } else {
- goto out;
- }
- if (!chip->charge_full)
- goto out;
+ /*
+ * If charge_done is still set, wait for recharging or
+ * discharging to happen.
+ */
+ if (chip->charge_done)
+ goto out;
- /*
- * During JEITA conditions, charge_full can happen early. FULL_SOC
- * and MONOTONIC_SOC needs to be updated to reflect the same. Write
- * battery SOC to FULL_SOC and write a full value to MONOTONIC_SOC.
- */
- rc = fg_sram_write(chip, FULL_SOC_WORD, FULL_SOC_OFFSET, (u8 *)&bsoc, 2,
- FG_IMA_ATOMIC);
- if (rc < 0) {
- pr_err("failed to write full_soc rc=%d\n", rc);
- goto out;
- }
+ rc = fg_configure_full_soc(chip, bsoc);
+ if (rc < 0)
+ goto out;
- rc = fg_sram_write(chip, MONOTONIC_SOC_WORD, MONOTONIC_SOC_OFFSET,
- full_soc, 2, FG_IMA_ATOMIC);
- if (rc < 0) {
- pr_err("failed to write monotonic_soc rc=%d\n", rc);
- goto out;
+ chip->charge_full = false;
+ fg_dbg(chip, FG_STATUS, "msoc_raw = %d bsoc: %d recharge_soc: %d delta_soc: %d\n",
+ msoc_raw, bsoc >> 8, recharge_soc, chip->delta_soc);
}
- fg_dbg(chip, FG_STATUS, "Set charge_full to true @ soc %d\n", msoc);
out:
mutex_unlock(&chip->charge_full_lock);
return rc;
@@ -1863,6 +1906,44 @@ static int fg_rconn_config(struct fg_chip *chip)
return 0;
}
+static int fg_set_jeita_threshold(struct fg_chip *chip,
+ enum jeita_levels level, int temp_decidegC)
+{
+ int rc;
+ u8 val;
+ u16 reg;
+
+ if (temp_decidegC < -300 || temp_decidegC > 970)
+ return -EINVAL;
+
+ /* Resolution is 0.5C. Base is -30C. */
+ val = DIV_ROUND_CLOSEST(((temp_decidegC / 10) + 30) * 10, 5);
+ switch (level) {
+ case JEITA_COLD:
+ reg = BATT_INFO_JEITA_TOO_COLD(chip);
+ break;
+ case JEITA_COOL:
+ reg = BATT_INFO_JEITA_COLD(chip);
+ break;
+ case JEITA_WARM:
+ reg = BATT_INFO_JEITA_HOT(chip);
+ break;
+ case JEITA_HOT:
+ reg = BATT_INFO_JEITA_TOO_HOT(chip);
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ rc = fg_write(chip, reg, &val, 1);
+ if (rc < 0) {
+ pr_err("Error in setting jeita level %d, rc=%d\n", level, rc);
+ return rc;
+ }
+
+ return 0;
+}
+
static int fg_set_constant_chg_voltage(struct fg_chip *chip, int volt_uv)
{
u8 buf[2];
@@ -3137,6 +3218,9 @@ static int fg_update_maint_soc(struct fg_chip *chip)
{
int rc = 0, msoc;
+ if (!chip->dt.linearize_soc)
+ return 0;
+
mutex_lock(&chip->charge_full_lock);
if (chip->delta_soc <= 0)
goto out;
@@ -3365,6 +3449,9 @@ static int fg_psy_get_property(struct power_supply *psy,
case POWER_SUPPLY_PROP_CAPACITY:
rc = fg_get_prop_capacity(chip, &pval->intval);
break;
+ case POWER_SUPPLY_PROP_CAPACITY_RAW:
+ rc = fg_get_msoc_raw(chip, &pval->intval);
+ break;
case POWER_SUPPLY_PROP_VOLTAGE_NOW:
if (chip->battery_missing)
pval->intval = 3700000;
@@ -3377,6 +3464,34 @@ static int fg_psy_get_property(struct power_supply *psy,
case POWER_SUPPLY_PROP_TEMP:
rc = fg_get_battery_temp(chip, &pval->intval);
break;
+ case POWER_SUPPLY_PROP_COLD_TEMP:
+ rc = fg_get_jeita_threshold(chip, JEITA_COLD, &pval->intval);
+ if (rc < 0) {
+ pr_err("Error in reading jeita_cold, rc=%d\n", rc);
+ return rc;
+ }
+ break;
+ case POWER_SUPPLY_PROP_COOL_TEMP:
+ rc = fg_get_jeita_threshold(chip, JEITA_COOL, &pval->intval);
+ if (rc < 0) {
+ pr_err("Error in reading jeita_cool, rc=%d\n", rc);
+ return rc;
+ }
+ break;
+ case POWER_SUPPLY_PROP_WARM_TEMP:
+ rc = fg_get_jeita_threshold(chip, JEITA_WARM, &pval->intval);
+ if (rc < 0) {
+ pr_err("Error in reading jeita_warm, rc=%d\n", rc);
+ return rc;
+ }
+ break;
+ case POWER_SUPPLY_PROP_HOT_TEMP:
+ rc = fg_get_jeita_threshold(chip, JEITA_HOT, &pval->intval);
+ if (rc < 0) {
+ pr_err("Error in reading jeita_hot, rc=%d\n", rc);
+ return rc;
+ }
+ break;
case POWER_SUPPLY_PROP_RESISTANCE:
rc = fg_get_battery_resistance(chip, &pval->intval);
break;
@@ -3500,6 +3615,48 @@ static int fg_psy_set_property(struct power_supply *psy,
return -EINVAL;
}
break;
+ case POWER_SUPPLY_PROP_CHARGE_FULL:
+ if (chip->cl.active) {
+ pr_warn("Capacity learning active!\n");
+ return 0;
+ }
+ if (pval->intval <= 0 || pval->intval > chip->cl.nom_cap_uah) {
+ pr_err("charge_full is out of bounds\n");
+ return -EINVAL;
+ }
+ chip->cl.learned_cc_uah = pval->intval;
+ rc = fg_save_learned_cap_to_sram(chip);
+ if (rc < 0)
+ pr_err("Error in saving learned_cc_uah, rc=%d\n", rc);
+ break;
+ case POWER_SUPPLY_PROP_COLD_TEMP:
+ rc = fg_set_jeita_threshold(chip, JEITA_COLD, pval->intval);
+ if (rc < 0) {
+ pr_err("Error in writing jeita_cold, rc=%d\n", rc);
+ return rc;
+ }
+ break;
+ case POWER_SUPPLY_PROP_COOL_TEMP:
+ rc = fg_set_jeita_threshold(chip, JEITA_COOL, pval->intval);
+ if (rc < 0) {
+ pr_err("Error in writing jeita_cool, rc=%d\n", rc);
+ return rc;
+ }
+ break;
+ case POWER_SUPPLY_PROP_WARM_TEMP:
+ rc = fg_set_jeita_threshold(chip, JEITA_WARM, pval->intval);
+ if (rc < 0) {
+ pr_err("Error in writing jeita_warm, rc=%d\n", rc);
+ return rc;
+ }
+ break;
+ case POWER_SUPPLY_PROP_HOT_TEMP:
+ rc = fg_set_jeita_threshold(chip, JEITA_HOT, pval->intval);
+ if (rc < 0) {
+ pr_err("Error in writing jeita_hot, rc=%d\n", rc);
+ return rc;
+ }
+ break;
default:
break;
}
@@ -3515,6 +3672,11 @@ static int fg_property_is_writeable(struct power_supply *psy,
case POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE:
case POWER_SUPPLY_PROP_CC_STEP:
case POWER_SUPPLY_PROP_CC_STEP_SEL:
+ case POWER_SUPPLY_PROP_CHARGE_FULL:
+ case POWER_SUPPLY_PROP_COLD_TEMP:
+ case POWER_SUPPLY_PROP_COOL_TEMP:
+ case POWER_SUPPLY_PROP_WARM_TEMP:
+ case POWER_SUPPLY_PROP_HOT_TEMP:
return 1;
default:
break;
@@ -3555,7 +3717,12 @@ static int fg_notifier_cb(struct notifier_block *nb,
static enum power_supply_property fg_psy_props[] = {
POWER_SUPPLY_PROP_CAPACITY,
+ POWER_SUPPLY_PROP_CAPACITY_RAW,
POWER_SUPPLY_PROP_TEMP,
+ POWER_SUPPLY_PROP_COLD_TEMP,
+ POWER_SUPPLY_PROP_COOL_TEMP,
+ POWER_SUPPLY_PROP_WARM_TEMP,
+ POWER_SUPPLY_PROP_HOT_TEMP,
POWER_SUPPLY_PROP_VOLTAGE_NOW,
POWER_SUPPLY_PROP_VOLTAGE_OCV,
POWER_SUPPLY_PROP_CURRENT_NOW,
@@ -3734,29 +3901,29 @@ static int fg_hw_init(struct fg_chip *chip)
}
}
- get_temp_setpoint(chip->dt.jeita_thresholds[JEITA_COLD], &val);
- rc = fg_write(chip, BATT_INFO_JEITA_TOO_COLD(chip), &val, 1);
+ rc = fg_set_jeita_threshold(chip, JEITA_COLD,
+ chip->dt.jeita_thresholds[JEITA_COLD] * 10);
if (rc < 0) {
pr_err("Error in writing jeita_cold, rc=%d\n", rc);
return rc;
}
- get_temp_setpoint(chip->dt.jeita_thresholds[JEITA_COOL], &val);
- rc = fg_write(chip, BATT_INFO_JEITA_COLD(chip), &val, 1);
+ rc = fg_set_jeita_threshold(chip, JEITA_COOL,
+ chip->dt.jeita_thresholds[JEITA_COOL] * 10);
if (rc < 0) {
pr_err("Error in writing jeita_cool, rc=%d\n", rc);
return rc;
}
- get_temp_setpoint(chip->dt.jeita_thresholds[JEITA_WARM], &val);
- rc = fg_write(chip, BATT_INFO_JEITA_HOT(chip), &val, 1);
+ rc = fg_set_jeita_threshold(chip, JEITA_WARM,
+ chip->dt.jeita_thresholds[JEITA_WARM] * 10);
if (rc < 0) {
pr_err("Error in writing jeita_warm, rc=%d\n", rc);
return rc;
}
- get_temp_setpoint(chip->dt.jeita_thresholds[JEITA_HOT], &val);
- rc = fg_write(chip, BATT_INFO_JEITA_TOO_HOT(chip), &val, 1);
+ rc = fg_set_jeita_threshold(chip, JEITA_HOT,
+ chip->dt.jeita_thresholds[JEITA_HOT] * 10);
if (rc < 0) {
pr_err("Error in writing jeita_hot, rc=%d\n", rc);
return rc;
@@ -4654,6 +4821,9 @@ static int fg_parse_dt(struct fg_chip *chip)
chip->dt.hold_soc_while_full = of_property_read_bool(node,
"qcom,hold-soc-while-full");
+ chip->dt.linearize_soc = of_property_read_bool(node,
+ "qcom,linearize-soc");
+
rc = fg_parse_ki_coefficients(chip);
if (rc < 0)
pr_err("Error in parsing Ki coefficients, rc=%d\n", rc);
@@ -4968,6 +5138,29 @@ static int fg_gen3_remove(struct platform_device *pdev)
return 0;
}
+static void fg_gen3_shutdown(struct platform_device *pdev)
+{
+ struct fg_chip *chip = dev_get_drvdata(&pdev->dev);
+ int rc, bsoc;
+
+ if (chip->charge_full) {
+ rc = fg_get_sram_prop(chip, FG_SRAM_BATT_SOC, &bsoc);
+ if (rc < 0) {
+ pr_err("Error in getting BATT_SOC, rc=%d\n", rc);
+ return;
+ }
+
+ /* We need 2 most significant bytes here */
+ bsoc = (u32)bsoc >> 16;
+
+ rc = fg_configure_full_soc(chip, bsoc);
+ if (rc < 0) {
+ pr_err("Error in configuring full_soc, rc=%d\n", rc);
+ return;
+ }
+ }
+}
+
static const struct of_device_id fg_gen3_match_table[] = {
{.compatible = FG_GEN3_DEV_NAME},
{},
@@ -4982,6 +5175,7 @@ static struct platform_driver fg_gen3_driver = {
},
.probe = fg_gen3_probe,
.remove = fg_gen3_remove,
+ .shutdown = fg_gen3_shutdown,
};
static int __init fg_gen3_init(void)
diff --git a/drivers/power/supply/qcom/qpnp-qnovo.c b/drivers/power/supply/qcom/qpnp-qnovo.c
index b20807990efc..53af3415ec6a 100644
--- a/drivers/power/supply/qcom/qpnp-qnovo.c
+++ b/drivers/power/supply/qcom/qpnp-qnovo.c
@@ -112,6 +112,7 @@
#define GAIN_LSB_FACTOR 976560
#define USER_VOTER "user_voter"
+#define SHUTDOWN_VOTER "user_voter"
#define OK_TO_QNOVO_VOTER "ok_to_qnovo_voter"
#define QNOVO_VOTER "qnovo_voter"
@@ -130,6 +131,7 @@
struct qnovo_dt_props {
bool external_rsense;
struct device_node *revid_dev_node;
+ bool enable_for_dc;
};
struct qnovo {
@@ -442,6 +444,8 @@ static int qnovo_parse_dt(struct qnovo *chip)
pr_err("Missing qcom,pmic-revid property - driver failed\n");
return -EINVAL;
}
+ chip->dt.enable_for_dc = of_property_read_bool(node,
+ "qcom,enable-for-dc");
return 0;
}
@@ -1310,6 +1314,10 @@ static void status_change_work(struct work_struct *work)
if (usb_present)
dc_present = 0;
+ /* disable qnovo for dc path by forcing dc_present = 0 always */
+ if (!chip->dt.enable_for_dc)
+ dc_present = 0;
+
if (chip->dc_present && !dc_present) {
/* removal */
chip->dc_present = 0;
@@ -1333,6 +1341,26 @@ static void ptrain_restart_work(struct work_struct *work)
struct qnovo, ptrain_restart_work.work);
u8 pt_t1, pt_t2;
int rc;
+ u8 pt_en;
+
+ rc = qnovo_read(chip, QNOVO_PTRAIN_EN, &pt_en, 1);
+ if (rc < 0) {
+ dev_err(chip->dev, "Couldn't read QNOVO_PTRAIN_EN rc = %d\n",
+ rc);
+ goto clean_up;
+ }
+
+ if (!pt_en) {
+ rc = qnovo_masked_write(chip, QNOVO_PTRAIN_EN,
+ QNOVO_PTRAIN_EN_BIT, QNOVO_PTRAIN_EN_BIT);
+ if (rc < 0) {
+ dev_err(chip->dev, "Couldn't enable pulse train rc=%d\n",
+ rc);
+ goto clean_up;
+ }
+ /* sleep 20ms for the pulse trains to restart and settle */
+ msleep(20);
+ }
rc = qnovo_read(chip, QNOVO_PTTIME_STS, &pt_t1, 1);
if (rc < 0) {
@@ -1395,16 +1423,7 @@ static irqreturn_t handle_ptrain_done(int irq, void *data)
struct qnovo *chip = data;
union power_supply_propval pval = {0};
- /*
- * In some cases (esp shutting down) the userspace would disable by
- * setting qnovo_enable=0. Also charger could be removed or there is
- * an error (i.e. its not okay to run qnovo)-
- * skip taking ESR measurement in such situations
- */
-
- if (get_client_vote(chip->disable_votable, USER_VOTER)
- || get_effective_result(chip->not_ok_to_qnovo_votable) > 0)
- return IRQ_HANDLED;
+ qnovo_update_status(chip);
/*
* hw resets pt_en bit once ptrain_done triggers.
@@ -1415,13 +1434,14 @@ static irqreturn_t handle_ptrain_done(int irq, void *data)
vote(chip->pt_dis_votable, QNI_PT_VOTER, true, 0);
vote(chip->pt_dis_votable, ESR_VOTER, true, 0);
- if (is_fg_available(chip))
+ if (is_fg_available(chip)
+ && !get_client_vote(chip->disable_votable, USER_VOTER)
+ && !get_effective_result(chip->not_ok_to_qnovo_votable))
power_supply_set_property(chip->bms_psy,
POWER_SUPPLY_PROP_RESISTANCE,
&pval);
vote(chip->pt_dis_votable, ESR_VOTER, false, 0);
- qnovo_update_status(chip);
kobject_uevent(&chip->dev->kobj, KOBJ_CHANGE);
return IRQ_HANDLED;
}
@@ -1434,6 +1454,9 @@ static int qnovo_hw_init(struct qnovo *chip)
u8 vadc_offset, vadc_gain;
u8 val;
+ vote(chip->chg_ready_votable, USB_READY_VOTER, false, 0);
+ vote(chip->chg_ready_votable, DC_READY_VOTER, false, 0);
+
vote(chip->disable_votable, USER_VOTER, true, 0);
vote(chip->disable_votable, FG_AVAILABLE_VOTER, true, 0);
@@ -1706,6 +1729,13 @@ static int qnovo_remove(struct platform_device *pdev)
return 0;
}
+static void qnovo_shutdown(struct platform_device *pdev)
+{
+ struct qnovo *chip = platform_get_drvdata(pdev);
+
+ vote(chip->not_ok_to_qnovo_votable, SHUTDOWN_VOTER, true, 0);
+}
+
static const struct of_device_id match_table[] = {
{ .compatible = "qcom,qpnp-qnovo", },
{ },
@@ -1719,6 +1749,7 @@ static struct platform_driver qnovo_driver = {
},
.probe = qnovo_probe,
.remove = qnovo_remove,
+ .shutdown = qnovo_shutdown,
};
module_platform_driver(qnovo_driver);
diff --git a/drivers/power/supply/qcom/qpnp-smb2.c b/drivers/power/supply/qcom/qpnp-smb2.c
index c085256a794a..ea205100644d 100644
--- a/drivers/power/supply/qcom/qpnp-smb2.c
+++ b/drivers/power/supply/qcom/qpnp-smb2.c
@@ -795,6 +795,7 @@ static int smb2_init_usb_main_psy(struct smb2 *chip)
*************************/
static enum power_supply_property smb2_dc_props[] = {
+ POWER_SUPPLY_PROP_INPUT_SUSPEND,
POWER_SUPPLY_PROP_PRESENT,
POWER_SUPPLY_PROP_ONLINE,
POWER_SUPPLY_PROP_CURRENT_MAX,
@@ -810,6 +811,9 @@ static int smb2_dc_get_prop(struct power_supply *psy,
int rc = 0;
switch (psp) {
+ case POWER_SUPPLY_PROP_INPUT_SUSPEND:
+ val->intval = get_effective_result(chg->dc_suspend_votable);
+ break;
case POWER_SUPPLY_PROP_PRESENT:
rc = smblib_get_prop_dc_present(chg, val);
break;
@@ -841,6 +845,10 @@ static int smb2_dc_set_prop(struct power_supply *psy,
int rc = 0;
switch (psp) {
+ case POWER_SUPPLY_PROP_INPUT_SUSPEND:
+ rc = vote(chg->dc_suspend_votable, WBC_VOTER,
+ (bool)val->intval, 0);
+ break;
case POWER_SUPPLY_PROP_CURRENT_MAX:
rc = smblib_set_prop_dc_current_max(chg, val);
break;
@@ -1191,7 +1199,7 @@ static int smb2_init_batt_psy(struct smb2 *chip)
* VBUS REGULATOR REGISTRATION *
******************************/
-struct regulator_ops smb2_vbus_reg_ops = {
+static struct regulator_ops smb2_vbus_reg_ops = {
.enable = smblib_vbus_regulator_enable,
.disable = smblib_vbus_regulator_disable,
.is_enabled = smblib_vbus_regulator_is_enabled,
@@ -1233,7 +1241,7 @@ static int smb2_init_vbus_regulator(struct smb2 *chip)
* VCONN REGULATOR REGISTRATION *
******************************/
-struct regulator_ops smb2_vconn_reg_ops = {
+static struct regulator_ops smb2_vconn_reg_ops = {
.enable = smblib_vconn_regulator_enable,
.disable = smblib_vconn_regulator_disable,
.is_enabled = smblib_vconn_regulator_is_enabled,
diff --git a/drivers/power/supply/qcom/smb-lib.h b/drivers/power/supply/qcom/smb-lib.h
index a89d09711ec8..19c0d19106d6 100644
--- a/drivers/power/supply/qcom/smb-lib.h
+++ b/drivers/power/supply/qcom/smb-lib.h
@@ -65,6 +65,7 @@ enum print_reason {
#define OTG_DELAY_VOTER "OTG_DELAY_VOTER"
#define USBIN_I_VOTER "USBIN_I_VOTER"
#define WEAK_CHARGER_VOTER "WEAK_CHARGER_VOTER"
+#define WBC_VOTER "WBC_VOTER"
#define VCONN_MAX_ATTEMPTS 3
#define OTG_MAX_ATTEMPTS 3
diff --git a/drivers/power/supply/qcom/smb138x-charger.c b/drivers/power/supply/qcom/smb138x-charger.c
index e7ca1e3fb108..a7e7f0be9afc 100644
--- a/drivers/power/supply/qcom/smb138x-charger.c
+++ b/drivers/power/supply/qcom/smb138x-charger.c
@@ -111,7 +111,7 @@ module_param_named(
debug_mask, __debug_mask, int, S_IRUSR | S_IWUSR
);
-irqreturn_t smb138x_handle_slave_chg_state_change(int irq, void *data)
+static irqreturn_t smb138x_handle_slave_chg_state_change(int irq, void *data)
{
struct smb_irq_data *irq_data = data;
struct smb138x *chip = irq_data->parent_data;
@@ -727,7 +727,7 @@ static int smb138x_init_parallel_psy(struct smb138x *chip)
* VBUS REGULATOR REGISTRATION *
******************************/
-struct regulator_ops smb138x_vbus_reg_ops = {
+static struct regulator_ops smb138x_vbus_reg_ops = {
.enable = smblib_vbus_regulator_enable,
.disable = smblib_vbus_regulator_disable,
.is_enabled = smblib_vbus_regulator_is_enabled,
@@ -769,7 +769,7 @@ static int smb138x_init_vbus_regulator(struct smb138x *chip)
* VCONN REGULATOR REGISTRATION *
******************************/
-struct regulator_ops smb138x_vconn_reg_ops = {
+static struct regulator_ops smb138x_vconn_reg_ops = {
.enable = smblib_vconn_regulator_enable,
.disable = smblib_vconn_regulator_disable,
.is_enabled = smblib_vconn_regulator_is_enabled,
diff --git a/drivers/power/supply/qcom/step-chg-jeita.c b/drivers/power/supply/qcom/step-chg-jeita.c
index 5b41a456c6db..06ecc7ea6e8a 100644
--- a/drivers/power/supply/qcom/step-chg-jeita.c
+++ b/drivers/power/supply/qcom/step-chg-jeita.c
@@ -443,21 +443,24 @@ int qcom_step_chg_init(bool step_chg_enable, bool sw_jeita_enable)
!step_chg_config.prop_name)) {
/* fail if step-chg configuration is invalid */
pr_err("Step-chg configuration not defined - fail\n");
- return -ENODATA;
+ rc = -ENODATA;
+ goto release_wakeup_source;
}
if (sw_jeita_enable && (!jeita_fcc_config.psy_prop ||
!jeita_fcc_config.prop_name)) {
/* fail if step-chg configuration is invalid */
pr_err("Jeita TEMP configuration not defined - fail\n");
- return -ENODATA;
+ rc = -ENODATA;
+ goto release_wakeup_source;
}
if (sw_jeita_enable && (!jeita_fv_config.psy_prop ||
!jeita_fv_config.prop_name)) {
/* fail if step-chg configuration is invalid */
pr_err("Jeita TEMP configuration not defined - fail\n");
- return -ENODATA;
+ rc = -ENODATA;
+ goto release_wakeup_source;
}
INIT_DELAYED_WORK(&chip->status_change_work, status_change_work);
diff --git a/drivers/regulator/cprh-kbss-regulator.c b/drivers/regulator/cprh-kbss-regulator.c
index ecf7885a4bff..4d6d63e6d887 100644
--- a/drivers/regulator/cprh-kbss-regulator.c
+++ b/drivers/regulator/cprh-kbss-regulator.c
@@ -80,7 +80,7 @@ struct cprh_kbss_fuses {
* Fuse combos 24 - 31 map to CPR fusing revision 0 - 7 with speed bin fuse = 3.
*/
#define CPRH_MSM8998_KBSS_FUSE_COMBO_COUNT 32
-#define CPRH_SDM660_KBSS_FUSE_COMBO_COUNT 16
+#define CPRH_SDM660_KBSS_FUSE_COMBO_COUNT 32
#define CPRH_SDM630_KBSS_FUSE_COMBO_COUNT 24
/*
@@ -1069,6 +1069,12 @@ static int cprh_kbss_calculate_open_loop_voltages(struct cpr3_regulator *vreg)
CPRH_KBSS_FUSE_STEP_VOLT, fuse->init_voltage[i],
CPRH_KBSS_VOLTAGE_FUSE_SIZE);
+ /* SDM660 speed bin #3 does not support TURBO_L1/L2 */
+ if (soc_revision == SDM660_SOC_ID && vreg->speed_bin_fuse == 3
+ && (id == CPRH_KBSS_PERFORMANCE_CLUSTER_ID)
+ && (i == CPRH_SDM660_PERF_KBSS_FUSE_CORNER_TURBO_L2))
+ continue;
+
/* Log fused open-loop voltage values for debugging purposes. */
cpr3_info(vreg, "fused %8s: open-loop=%7d uV\n", corner_name[i],
fuse_volt[i]);
@@ -1615,6 +1621,11 @@ static int cprh_kbss_calculate_target_quotients(struct cpr3_regulator *vreg)
CPRH_SDM660_PERF_KBSS_FUSE_CORNER_SVS;
highest_fuse_corner =
CPRH_SDM660_PERF_KBSS_FUSE_CORNER_TURBO_L2;
+
+ /* speed-bin 3 does not have Turbo_L2 fuse */
+ if (vreg->speed_bin_fuse == 3)
+ highest_fuse_corner =
+ CPRH_SDM660_PERF_KBSS_FUSE_CORNER_TURBO;
}
break;
case SDM630_SOC_ID:
diff --git a/drivers/soc/qcom/Kconfig b/drivers/soc/qcom/Kconfig
index 907960cfa9d5..829876226689 100644
--- a/drivers/soc/qcom/Kconfig
+++ b/drivers/soc/qcom/Kconfig
@@ -1,6 +1,8 @@
#
# QCOM Soc drivers
#
+source "drivers/soc/qcom/hab/Kconfig"
+
config MSM_INRUSH_CURRENT_MITIGATION
bool "Inrush-current mitigation Driver"
help
diff --git a/drivers/soc/qcom/Makefile b/drivers/soc/qcom/Makefile
index 0bf54bedd6ea..229b13a04819 100644
--- a/drivers/soc/qcom/Makefile
+++ b/drivers/soc/qcom/Makefile
@@ -107,3 +107,4 @@ obj-$(CONFIG_QCOM_SMCINVOKE) += smcinvoke.o
obj-$(CONFIG_QCOM_EARLY_RANDOM) += early_random.o
obj-$(CONFIG_QCOM_CX_IPEAK) += cx_ipeak.o
obj-$(CONFIG_MSM_CACHE_M4M_ERP64) += cache_m4m_erp64.o
+obj-$(CONFIG_MSM_HAB) += hab/
diff --git a/drivers/soc/qcom/common_log.c b/drivers/soc/qcom/common_log.c
index 1e8744b41e4c..11ca86a4ba41 100644
--- a/drivers/soc/qcom/common_log.c
+++ b/drivers/soc/qcom/common_log.c
@@ -18,6 +18,7 @@
#include <linux/slab.h>
#include <linux/kmemleak.h>
#include <linux/async.h>
+#include <linux/thread_info.h>
#include <soc/qcom/memory_dump.h>
#include <soc/qcom/minidump.h>
#include <asm/sections.h>
@@ -256,6 +257,32 @@ static void __init register_kernel_sections(void)
}
}
+#ifdef CONFIG_QCOM_MINIDUMP
+void dump_stack_minidump(u64 sp)
+{
+ struct md_region ksp_entry, ktsk_entry;
+ u32 cpu = smp_processor_id();
+
+ if (sp < KIMAGE_VADDR || sp > -256UL)
+ sp = current_stack_pointer;
+
+ sp &= ~(THREAD_SIZE - 1);
+ scnprintf(ksp_entry.name, sizeof(ksp_entry.name), "KSTACK%d", cpu);
+ ksp_entry.virt_addr = sp;
+ ksp_entry.phys_addr = virt_to_phys((uintptr_t *)sp);
+ ksp_entry.size = THREAD_SIZE;
+ if (msm_minidump_add_region(&ksp_entry))
+ pr_err("Failed to add stack of cpu %d in Minidump\n", cpu);
+
+ scnprintf(ktsk_entry.name, sizeof(ktsk_entry.name), "KTASK%d", cpu);
+ ktsk_entry.virt_addr = (u64)current;
+ ktsk_entry.phys_addr = virt_to_phys((uintptr_t *)current);
+ ktsk_entry.size = sizeof(struct task_struct);
+ if (msm_minidump_add_region(&ktsk_entry))
+ pr_err("Failed to add current task %d in Minidump\n", cpu);
+}
+#endif
+
static void __init async_common_log_init(void *data, async_cookie_t cookie)
{
register_kernel_sections();
diff --git a/drivers/soc/qcom/glink.c b/drivers/soc/qcom/glink.c
index e0d9f68ceef9..f3debd14c27b 100644
--- a/drivers/soc/qcom/glink.c
+++ b/drivers/soc/qcom/glink.c
@@ -2372,6 +2372,35 @@ static void dummy_tx_cmd_ch_remote_close_ack(struct glink_transport_if *if_ptr,
}
/**
+ * dummy_tx_cmd_ch_open() - dummy channel open cmd sending function
+ * @if_ptr: The transport to transmit on.
+ * @lcid: The local channel id to encode.
+ * @name: The channel name to encode.
+ * @req_xprt: The transport the core would like to migrate this channel to.
+ *
+ * Return: 0 on success or standard Linux error code.
+ */
+static int dummy_tx_cmd_ch_open(struct glink_transport_if *if_ptr,
+ uint32_t lcid, const char *name,
+ uint16_t req_xprt)
+{
+ return -EOPNOTSUPP;
+}
+
+/**
+ * dummy_tx_cmd_ch_remote_open_ack() - convert a channel open ack cmd to wire
+ * format and transmit
+ * @if_ptr: The transport to transmit on.
+ * @rcid: The remote channel id to encode.
+ * @xprt_resp: The response to a transport migration request.
+ */
+static void dummy_tx_cmd_ch_remote_open_ack(struct glink_transport_if *if_ptr,
+ uint32_t rcid, uint16_t xprt_resp)
+{
+ /* intentionally left blank */
+}
+
+/**
* dummy_get_power_vote_ramp_time() - Dummy Power vote ramp time
* @if_ptr: The transport to transmit on.
* @state: The power state being requested from the transport.
@@ -4184,8 +4213,14 @@ static struct glink_core_xprt_ctx *glink_create_dummy_xprt_ctx(
if_ptr->tx_cmd_remote_rx_intent_req_ack =
dummy_tx_cmd_remote_rx_intent_req_ack;
if_ptr->tx_cmd_set_sigs = dummy_tx_cmd_set_sigs;
+ if_ptr->tx_cmd_ch_open = dummy_tx_cmd_ch_open;
+ if_ptr->tx_cmd_ch_remote_open_ack = dummy_tx_cmd_ch_remote_open_ack;
if_ptr->tx_cmd_ch_close = dummy_tx_cmd_ch_close;
if_ptr->tx_cmd_ch_remote_close_ack = dummy_tx_cmd_ch_remote_close_ack;
+ if_ptr->tx_cmd_tracer_pkt = dummy_tx_cmd_tracer_pkt;
+ if_ptr->get_power_vote_ramp_time = dummy_get_power_vote_ramp_time;
+ if_ptr->power_vote = dummy_power_vote;
+ if_ptr->power_unvote = dummy_power_unvote;
xprt_ptr->ops = if_ptr;
xprt_ptr->log_ctx = log_ctx;
diff --git a/drivers/soc/qcom/glink_spi_xprt.c b/drivers/soc/qcom/glink_spi_xprt.c
index 6794c30605d7..a94c4c909a40 100644
--- a/drivers/soc/qcom/glink_spi_xprt.c
+++ b/drivers/soc/qcom/glink_spi_xprt.c
@@ -121,6 +121,8 @@ struct glink_cmpnt {
* @tx_fifo_write_reg_addr: Address of the TX FIFO Write Index Register.
* @rx_fifo_read_reg_addr: Address of the RX FIFO Read Index Register.
* @rx_fifo_write_reg_addr: Address of the RX FIFO Write Index Register.
+ * @tx_fifo_write: Internal write index for TX FIFO.
+ * @rx_fifo_read: Internal read index for RX FIFO.
* @kwork: Work to be executed when receiving data.
* @kworker: Handle to the entity processing @kwork.
* @task: Handle to the task context that runs @kworker.
@@ -158,6 +160,8 @@ struct edge_info {
unsigned int tx_fifo_write_reg_addr;
unsigned int rx_fifo_read_reg_addr;
unsigned int rx_fifo_write_reg_addr;
+ uint32_t tx_fifo_write;
+ uint32_t rx_fifo_read;
struct kthread_work kwork;
struct kthread_worker kworker;
@@ -368,6 +372,19 @@ static int glink_spi_xprt_write_avail(struct edge_info *einfo)
int write_avail;
int ret;
+ if (unlikely(!einfo->tx_fifo_start)) {
+ ret = glink_spi_xprt_reg_read(einfo,
+ einfo->tx_fifo_write_reg_addr, &einfo->tx_fifo_write);
+ if (ret < 0) {
+ pr_err("%s: Error %d reading %s tx_fifo_write_reg_addr %d\n",
+ __func__, ret, einfo->xprt_cfg.edge,
+ einfo->tx_fifo_write_reg_addr);
+ return 0;
+ }
+ einfo->tx_fifo_start = einfo->tx_fifo_write;
+ }
+ write_id = einfo->tx_fifo_write;
+
ret = glink_spi_xprt_reg_read(einfo, einfo->tx_fifo_read_reg_addr,
&read_id);
if (ret < 0) {
@@ -377,21 +394,9 @@ static int glink_spi_xprt_write_avail(struct edge_info *einfo)
return 0;
}
- ret = glink_spi_xprt_reg_read(einfo, einfo->tx_fifo_write_reg_addr,
- &write_id);
- if (ret < 0) {
- pr_err("%s: Error %d reading %s tx_fifo_write_reg_addr %d\n",
- __func__, ret, einfo->xprt_cfg.edge,
- einfo->tx_fifo_write_reg_addr);
- return 0;
- }
-
if (!read_id || !write_id)
return 0;
- if (unlikely(!einfo->tx_fifo_start))
- einfo->tx_fifo_start = write_id;
-
if (read_id > write_id)
write_avail = read_id - write_id;
else
@@ -421,14 +426,18 @@ static int glink_spi_xprt_read_avail(struct edge_info *einfo)
int read_avail;
int ret;
- ret = glink_spi_xprt_reg_read(einfo, einfo->rx_fifo_read_reg_addr,
- &read_id);
- if (ret < 0) {
- pr_err("%s: Error %d reading %s rx_fifo_read_reg_addr %d\n",
- __func__, ret, einfo->xprt_cfg.edge,
- einfo->rx_fifo_read_reg_addr);
- return 0;
+ if (unlikely(!einfo->rx_fifo_start)) {
+ ret = glink_spi_xprt_reg_read(einfo,
+ einfo->rx_fifo_read_reg_addr, &einfo->rx_fifo_read);
+ if (ret < 0) {
+ pr_err("%s: Error %d reading %s rx_fifo_read_reg_addr %d\n",
+ __func__, ret, einfo->xprt_cfg.edge,
+ einfo->rx_fifo_read_reg_addr);
+ return 0;
+ }
+ einfo->rx_fifo_start = einfo->rx_fifo_read;
}
+ read_id = einfo->rx_fifo_read;
ret = glink_spi_xprt_reg_read(einfo, einfo->rx_fifo_write_reg_addr,
&write_id);
@@ -442,9 +451,6 @@ static int glink_spi_xprt_read_avail(struct edge_info *einfo)
if (!read_id || !write_id)
return 0;
- if (unlikely(!einfo->rx_fifo_start))
- einfo->rx_fifo_start = read_id;
-
if (read_id <= write_id)
read_avail = write_id - read_id;
else
@@ -471,15 +477,7 @@ static int glink_spi_xprt_rx_cmd(struct edge_info *einfo, void *dst,
uint32_t offset = 0;
int ret;
- ret = glink_spi_xprt_reg_read(einfo, einfo->rx_fifo_read_reg_addr,
- &read_id);
- if (ret < 0) {
- pr_err("%s: Error %d reading %s rx_fifo_read_reg_addr %d\n",
- __func__, ret, einfo->xprt_cfg.edge,
- einfo->rx_fifo_read_reg_addr);
- return ret;
- }
-
+ read_id = einfo->rx_fifo_read;
do {
if ((read_id + size_to_read) >=
(einfo->rx_fifo_start + einfo->fifo_size))
@@ -504,6 +502,9 @@ static int glink_spi_xprt_rx_cmd(struct edge_info *einfo, void *dst,
pr_err("%s: Error %d writing %s rx_fifo_read_reg_addr %d\n",
__func__, ret, einfo->xprt_cfg.edge,
einfo->rx_fifo_read_reg_addr);
+ else
+ einfo->rx_fifo_read = read_id;
+
return ret;
}
@@ -526,15 +527,7 @@ static int glink_spi_xprt_tx_cmd_safe(struct edge_info *einfo, void *src,
uint32_t offset = 0;
int ret;
- ret = glink_spi_xprt_reg_read(einfo, einfo->tx_fifo_write_reg_addr,
- &write_id);
- if (ret < 0) {
- pr_err("%s: Error %d reading %s tx_fifo_write_reg_addr %d\n",
- __func__, ret, einfo->xprt_cfg.edge,
- einfo->tx_fifo_write_reg_addr);
- return ret;
- }
-
+ write_id = einfo->tx_fifo_write;
do {
if ((write_id + size_to_write) >=
(einfo->tx_fifo_start + einfo->fifo_size))
@@ -559,6 +552,9 @@ static int glink_spi_xprt_tx_cmd_safe(struct edge_info *einfo, void *src,
pr_err("%s: Error %d writing %s tx_fifo_write_reg_addr %d\n",
__func__, ret, einfo->xprt_cfg.edge,
einfo->tx_fifo_write_reg_addr);
+ else
+ einfo->tx_fifo_write = write_id;
+
return ret;
}
@@ -1236,6 +1232,8 @@ static int ssr(struct glink_transport_if *if_ptr)
einfo->tx_blocked_signal_sent = false;
einfo->tx_fifo_start = 0;
einfo->rx_fifo_start = 0;
+ einfo->tx_fifo_write = 0;
+ einfo->rx_fifo_read = 0;
einfo->fifo_size = DEFAULT_FIFO_SIZE;
einfo->xprt_if.glink_core_if_ptr->link_down(&einfo->xprt_if);
diff --git a/drivers/soc/qcom/hab/Kconfig b/drivers/soc/qcom/hab/Kconfig
new file mode 100644
index 000000000000..2e4f5114e29f
--- /dev/null
+++ b/drivers/soc/qcom/hab/Kconfig
@@ -0,0 +1,7 @@
+config MSM_HAB
+ bool "Enable Multimedia driver Hypervisor Abstraction Layer"
+ help
+ Multimedia driver hypervisor abstraction layer.
+ Required for drivers to use the HAB API to communicate with the host
+ OS.
+
diff --git a/drivers/soc/qcom/hab/Makefile b/drivers/soc/qcom/hab/Makefile
new file mode 100644
index 000000000000..83fc54d42202
--- /dev/null
+++ b/drivers/soc/qcom/hab/Makefile
@@ -0,0 +1,14 @@
+msm_hab-objs = \
+ khab.o \
+ hab.o \
+ hab_msg.o \
+ hab_vchan.o \
+ hab_pchan.o \
+ hab_open.o \
+ hab_mimex.o \
+ hab_mem_linux.o \
+ hab_pipe.o \
+ qvm_comm.o \
+ hab_qvm.o
+
+obj-$(CONFIG_MSM_HAB) += msm_hab.o
diff --git a/drivers/soc/qcom/hab/hab.c b/drivers/soc/qcom/hab/hab.c
new file mode 100644
index 000000000000..c6df36f5c0a2
--- /dev/null
+++ b/drivers/soc/qcom/hab/hab.c
@@ -0,0 +1,726 @@
+/* Copyright (c) 2016-2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+#include "hab.h"
+
+#define HAB_DEVICE_CNSTR(__name__, __id__, __num__) { \
+ .name = __name__,\
+ .id = __id__,\
+ .pchannels = LIST_HEAD_INIT(hab_devices[__num__].pchannels),\
+ .pchan_lock = __MUTEX_INITIALIZER(hab_devices[__num__].pchan_lock),\
+ .openq_list = LIST_HEAD_INIT(hab_devices[__num__].openq_list),\
+ .openlock = __SPIN_LOCK_UNLOCKED(&hab_devices[__num__].openlock)\
+ }
+
+/* the following has to match habmm definitions, order does not matter */
+static struct hab_device hab_devices[] = {
+ HAB_DEVICE_CNSTR(DEVICE_AUD1_NAME, MM_AUD_1, 0),
+ HAB_DEVICE_CNSTR(DEVICE_AUD2_NAME, MM_AUD_2, 1),
+ HAB_DEVICE_CNSTR(DEVICE_AUD3_NAME, MM_AUD_3, 2),
+ HAB_DEVICE_CNSTR(DEVICE_AUD4_NAME, MM_AUD_4, 3),
+ HAB_DEVICE_CNSTR(DEVICE_CAM_NAME, MM_CAM, 4),
+ HAB_DEVICE_CNSTR(DEVICE_DISP1_NAME, MM_DISP_1, 5),
+ HAB_DEVICE_CNSTR(DEVICE_DISP2_NAME, MM_DISP_2, 6),
+ HAB_DEVICE_CNSTR(DEVICE_DISP3_NAME, MM_DISP_3, 7),
+ HAB_DEVICE_CNSTR(DEVICE_DISP4_NAME, MM_DISP_4, 8),
+ HAB_DEVICE_CNSTR(DEVICE_DISP5_NAME, MM_DISP_5, 9),
+ HAB_DEVICE_CNSTR(DEVICE_GFX_NAME, MM_GFX, 10),
+ HAB_DEVICE_CNSTR(DEVICE_VID_NAME, MM_VID, 11),
+ HAB_DEVICE_CNSTR(DEVICE_MISC_NAME, MM_MISC, 12),
+ HAB_DEVICE_CNSTR(DEVICE_QCPE1_NAME, MM_QCPE_VM1, 13),
+ HAB_DEVICE_CNSTR(DEVICE_QCPE2_NAME, MM_QCPE_VM2, 14),
+ HAB_DEVICE_CNSTR(DEVICE_QCPE3_NAME, MM_QCPE_VM3, 15),
+ HAB_DEVICE_CNSTR(DEVICE_QCPE4_NAME, MM_QCPE_VM4, 16)
+};
+
+struct hab_driver hab_driver = {
+ .ndevices = ARRAY_SIZE(hab_devices),
+ .devp = hab_devices,
+};
+
+struct uhab_context *hab_ctx_alloc(int kernel)
+{
+ struct uhab_context *ctx;
+
+ ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
+ if (!ctx)
+ return NULL;
+
+ ctx->closing = 0;
+ INIT_LIST_HEAD(&ctx->vchannels);
+ INIT_LIST_HEAD(&ctx->exp_whse);
+ INIT_LIST_HEAD(&ctx->imp_whse);
+
+ INIT_LIST_HEAD(&ctx->exp_rxq);
+ init_waitqueue_head(&ctx->exp_wq);
+ spin_lock_init(&ctx->expq_lock);
+
+ spin_lock_init(&ctx->imp_lock);
+ rwlock_init(&ctx->exp_lock);
+ rwlock_init(&ctx->ctx_lock);
+
+ kref_init(&ctx->refcount);
+ ctx->import_ctx = habmem_imp_hyp_open();
+ if (!ctx->import_ctx) {
+ kfree(ctx);
+ return NULL;
+ }
+ ctx->kernel = kernel;
+
+ return ctx;
+}
+
+void hab_ctx_free(struct kref *ref)
+{
+ struct uhab_context *ctx =
+ container_of(ref, struct uhab_context, refcount);
+ struct hab_export_ack_recvd *ack_recvd, *tmp;
+
+ habmem_imp_hyp_close(ctx->import_ctx, ctx->kernel);
+
+ list_for_each_entry_safe(ack_recvd, tmp, &ctx->exp_rxq, node) {
+ list_del(&ack_recvd->node);
+ kfree(ack_recvd);
+ }
+
+ kfree(ctx);
+}
+
+struct virtual_channel *hab_get_vchan_fromvcid(int32_t vcid,
+ struct uhab_context *ctx)
+{
+ struct virtual_channel *vchan;
+
+ read_lock(&ctx->ctx_lock);
+ list_for_each_entry(vchan, &ctx->vchannels, node) {
+ if (vcid == vchan->id) {
+ kref_get(&vchan->refcount);
+ read_unlock(&ctx->ctx_lock);
+ return vchan;
+ }
+ }
+ read_unlock(&ctx->ctx_lock);
+ return NULL;
+}
+
+static struct hab_device *find_hab_device(unsigned int mm_id)
+{
+ int i;
+
+ for (i = 0; i < hab_driver.ndevices; i++) {
+ if (hab_driver.devp[i].id == HAB_MMID_GET_MAJOR(mm_id))
+ return &hab_driver.devp[i];
+ }
+
+ pr_err("find_hab_device failed: id=%d\n", mm_id);
+ return NULL;
+}
+/*
+ * open handshake in FE and BE
+
+ * frontend backend
+ * send(INIT) wait(INIT)
+ * wait(INIT_ACK) send(INIT_ACK)
+ * send(ACK) wait(ACK)
+
+ */
+struct virtual_channel *frontend_open(struct uhab_context *ctx,
+ unsigned int mm_id,
+ int dom_id)
+{
+ int ret, open_id = 0;
+ struct physical_channel *pchan = NULL;
+ struct hab_device *dev;
+ struct virtual_channel *vchan = NULL;
+ static atomic_t open_id_counter = ATOMIC_INIT(0);
+ struct hab_open_request request;
+ struct hab_open_request *recv_request;
+ int sub_id = HAB_MMID_GET_MINOR(mm_id);
+
+ dev = find_hab_device(mm_id);
+ if (dev == NULL) {
+ ret = -EINVAL;
+ goto err;
+ }
+
+ pchan = hab_pchan_find_domid(dev, dom_id);
+ if (!pchan) {
+ pr_err("hab_pchan_find_domid failed: dom_id=%d\n", dom_id);
+ ret = -EINVAL;
+ goto err;
+ }
+
+ vchan = hab_vchan_alloc(ctx, pchan);
+ if (!vchan) {
+ ret = -ENOMEM;
+ goto err;
+ }
+
+ /* Send Init sequence */
+ open_id = atomic_inc_return(&open_id_counter);
+ hab_open_request_init(&request, HAB_PAYLOAD_TYPE_INIT, pchan,
+ vchan->id, sub_id, open_id);
+ ret = hab_open_request_send(&request);
+ if (ret) {
+ pr_err("hab_open_request_send failed: %d\n", ret);
+ goto err;
+ }
+
+ /* Wait for Init-Ack sequence */
+ hab_open_request_init(&request, HAB_PAYLOAD_TYPE_INIT_ACK, pchan,
+ 0, sub_id, open_id);
+ ret = hab_open_listen(ctx, dev, &request, &recv_request, 0);
+ if (ret || !recv_request) {
+ pr_err("hab_open_listen failed: %d\n", ret);
+ goto err;
+ }
+
+ vchan->otherend_id = recv_request->vchan_id;
+ hab_open_request_free(recv_request);
+
+ /* Send Ack sequence */
+ hab_open_request_init(&request, HAB_PAYLOAD_TYPE_ACK, pchan,
+ 0, sub_id, open_id);
+ ret = hab_open_request_send(&request);
+ if (ret)
+ goto err;
+
+ hab_pchan_put(pchan);
+
+ return vchan;
+err:
+ if (vchan)
+ hab_vchan_put(vchan);
+ if (pchan)
+ hab_pchan_put(pchan);
+
+ return ERR_PTR(ret);
+}
+
+struct virtual_channel *backend_listen(struct uhab_context *ctx,
+ unsigned int mm_id)
+{
+ int ret;
+ int open_id;
+ int sub_id = HAB_MMID_GET_MINOR(mm_id);
+ struct physical_channel *pchan = NULL;
+ struct hab_device *dev;
+ struct virtual_channel *vchan = NULL;
+ struct hab_open_request request;
+ struct hab_open_request *recv_request;
+ uint32_t otherend_vchan_id;
+
+ dev = find_hab_device(mm_id);
+ if (dev == NULL) {
+ ret = -EINVAL;
+ goto err;
+ }
+
+ while (1) {
+ /* Wait for Init sequence */
+ hab_open_request_init(&request, HAB_PAYLOAD_TYPE_INIT,
+ NULL, 0, sub_id, 0);
+ ret = hab_open_listen(ctx, dev, &request, &recv_request, 0);
+ if (ret || !recv_request) {
+ pr_err("hab_open_listen failed: %d\n", ret);
+ goto err;
+ }
+
+ otherend_vchan_id = recv_request->vchan_id;
+ open_id = recv_request->open_id;
+ pchan = recv_request->pchan;
+ hab_pchan_get(pchan);
+ hab_open_request_free(recv_request);
+
+ vchan = hab_vchan_alloc(ctx, pchan);
+ if (!vchan) {
+ ret = -ENOMEM;
+ goto err;
+ }
+
+ vchan->otherend_id = otherend_vchan_id;
+
+ /* Send Init-Ack sequence */
+ hab_open_request_init(&request, HAB_PAYLOAD_TYPE_INIT_ACK,
+ pchan, vchan->id, sub_id, open_id);
+ ret = hab_open_request_send(&request);
+ if (ret)
+ goto err;
+
+ /* Wait for Ack sequence */
+ hab_open_request_init(&request, HAB_PAYLOAD_TYPE_ACK,
+ pchan, 0, sub_id, open_id);
+ ret = hab_open_listen(ctx, dev, &request, &recv_request, HZ);
+
+ if (ret != -EAGAIN)
+ break;
+
+ hab_vchan_put(vchan);
+ vchan = NULL;
+ hab_pchan_put(pchan);
+ pchan = NULL;
+ }
+
+ if (ret || !recv_request) {
+ pr_err("backend_listen failed: %d\n", ret);
+ ret = -EINVAL;
+ goto err;
+ }
+
+ hab_open_request_free(recv_request);
+ hab_pchan_put(pchan);
+ return vchan;
+err:
+ if (vchan)
+ hab_vchan_put(vchan);
+ if (pchan)
+ hab_pchan_put(pchan);
+ return ERR_PTR(ret);
+}
+
+long hab_vchan_send(struct uhab_context *ctx,
+ int vcid,
+ size_t sizebytes,
+ void *data,
+ unsigned int flags)
+{
+ struct virtual_channel *vchan;
+ int ret;
+ struct hab_header header = HAB_HEADER_INITIALIZER;
+ int nonblocking_flag = flags & HABMM_SOCKET_SEND_FLAGS_NON_BLOCKING;
+
+ if (sizebytes > HAB_MAX_MSG_SIZEBYTES) {
+ pr_err("Message too large, %lu bytes\n", sizebytes);
+ return -EINVAL;
+ }
+
+ vchan = hab_get_vchan_fromvcid(vcid, ctx);
+ if (!vchan || vchan->otherend_closed)
+ return -ENODEV;
+
+ HAB_HEADER_SET_SIZE(header, sizebytes);
+ HAB_HEADER_SET_TYPE(header, HAB_PAYLOAD_TYPE_MSG);
+ HAB_HEADER_SET_ID(header, vchan->otherend_id);
+
+ while (1) {
+ ret = physical_channel_send(vchan->pchan, &header, data);
+
+ if (vchan->otherend_closed || nonblocking_flag ||
+ ret != -EAGAIN)
+ break;
+
+ schedule();
+ }
+
+ hab_vchan_put(vchan);
+ return ret;
+}
+
+struct hab_message *hab_vchan_recv(struct uhab_context *ctx,
+ int vcid,
+ unsigned int flags)
+{
+ struct virtual_channel *vchan;
+ struct hab_message *message;
+ int ret = 0;
+ int nonblocking_flag = flags & HABMM_SOCKET_RECV_FLAGS_NON_BLOCKING;
+
+ vchan = hab_get_vchan_fromvcid(vcid, ctx);
+ if (!vchan || vchan->otherend_closed)
+ return ERR_PTR(-ENODEV);
+
+ if (nonblocking_flag) {
+ /*
+ * Try to pull data from the ring in this context instead of
+ * IRQ handler. Any available messages will be copied and queued
+ * internally, then fetched by hab_msg_dequeue()
+ */
+ physical_channel_rx_dispatch((unsigned long) vchan->pchan);
+ }
+
+ message = hab_msg_dequeue(vchan, !nonblocking_flag);
+ if (!message) {
+ if (nonblocking_flag)
+ ret = -EAGAIN;
+ else
+ ret = -EPIPE;
+ }
+
+ hab_vchan_put(vchan);
+ return ret ? ERR_PTR(ret) : message;
+}
+
+bool hab_is_loopback(void)
+{
+ return hab_driver.b_loopback;
+}
+
+int hab_vchan_open(struct uhab_context *ctx,
+ unsigned int mmid,
+ int32_t *vcid,
+ uint32_t flags)
+{
+ struct virtual_channel *vchan;
+
+ if (!vcid)
+ return -EINVAL;
+
+ if (hab_is_loopback()) {
+ if (!hab_driver.loopback_num) {
+ hab_driver.loopback_num = 1;
+ vchan = backend_listen(ctx, mmid);
+ } else {
+ hab_driver.loopback_num = 0;
+ vchan = frontend_open(ctx, mmid, LOOPBACK_DOM);
+ }
+ } else {
+ if (hab_driver.b_server_dom)
+ vchan = backend_listen(ctx, mmid);
+ else
+ vchan = frontend_open(ctx, mmid, 0);
+ }
+
+ if (IS_ERR(vchan))
+ return PTR_ERR(vchan);
+
+ write_lock(&ctx->ctx_lock);
+ list_add_tail(&vchan->node, &ctx->vchannels);
+ write_unlock(&ctx->ctx_lock);
+
+ *vcid = vchan->id;
+
+ return 0;
+}
+
+void hab_send_close_msg(struct virtual_channel *vchan)
+{
+ struct hab_header header;
+
+ if (vchan && !vchan->otherend_closed) {
+ HAB_HEADER_SET_SIZE(header, 0);
+ HAB_HEADER_SET_TYPE(header, HAB_PAYLOAD_TYPE_CLOSE);
+ HAB_HEADER_SET_ID(header, vchan->otherend_id);
+ physical_channel_send(vchan->pchan, &header, NULL);
+ }
+}
+
+static void hab_vchan_close_impl(struct kref *ref)
+{
+ struct virtual_channel *vchan =
+ container_of(ref, struct virtual_channel, usagecnt);
+
+ list_del(&vchan->node);
+ hab_vchan_stop_notify(vchan);
+ hab_vchan_put(vchan);
+}
+
+
+void hab_vchan_close(struct uhab_context *ctx, int32_t vcid)
+{
+ struct virtual_channel *vchan, *tmp;
+
+ if (!ctx)
+ return;
+
+ write_lock(&ctx->ctx_lock);
+ list_for_each_entry_safe(vchan, tmp, &ctx->vchannels, node) {
+ if (vchan->id == vcid) {
+ kref_put(&vchan->usagecnt, hab_vchan_close_impl);
+ break;
+ }
+ }
+
+ write_unlock(&ctx->ctx_lock);
+}
+
+static int hab_open(struct inode *inodep, struct file *filep)
+{
+ int result = 0;
+ struct uhab_context *ctx;
+
+ ctx = hab_ctx_alloc(0);
+
+ if (!ctx) {
+ pr_err("hab_ctx_alloc failed\n");
+ filep->private_data = NULL;
+ return -ENOMEM;
+ }
+
+ filep->private_data = ctx;
+
+ return result;
+}
+
+static int hab_release(struct inode *inodep, struct file *filep)
+{
+ struct uhab_context *ctx = filep->private_data;
+ struct virtual_channel *vchan, *tmp;
+
+ if (!ctx)
+ return 0;
+
+ write_lock(&ctx->ctx_lock);
+
+ list_for_each_entry_safe(vchan, tmp, &ctx->vchannels, node) {
+ list_del(&vchan->node);
+ hab_vchan_stop_notify(vchan);
+ hab_vchan_put(vchan);
+ }
+
+ write_unlock(&ctx->ctx_lock);
+
+ hab_ctx_put(ctx);
+ filep->private_data = NULL;
+
+ return 0;
+}
+
+static long hab_ioctl(struct file *filep, unsigned int cmd, unsigned long arg)
+{
+ struct uhab_context *ctx = (struct uhab_context *)filep->private_data;
+ struct hab_open *open_param;
+ struct hab_close *close_param;
+ struct hab_recv *recv_param;
+ struct hab_send *send_param;
+ struct hab_message *msg;
+ void *send_data;
+ unsigned char data[256] = { 0 };
+ long ret = 0;
+
+ if (_IOC_SIZE(cmd) && (cmd & IOC_IN)) {
+ if (_IOC_SIZE(cmd) > sizeof(data))
+ return -EINVAL;
+
+ if (copy_from_user(data, (void __user *)arg, _IOC_SIZE(cmd))) {
+ pr_err("copy_from_user failed cmd=%x size=%d\n",
+ cmd, _IOC_SIZE(cmd));
+ return -EFAULT;
+ }
+ }
+
+ switch (cmd) {
+ case IOCTL_HAB_VC_OPEN:
+ open_param = (struct hab_open *)data;
+ ret = hab_vchan_open(ctx, open_param->mmid,
+ &open_param->vcid, open_param->flags);
+ break;
+ case IOCTL_HAB_VC_CLOSE:
+ close_param = (struct hab_close *)data;
+ hab_vchan_close(ctx, close_param->vcid);
+ break;
+ case IOCTL_HAB_SEND:
+ send_param = (struct hab_send *)data;
+ if (send_param->sizebytes > HAB_MAX_MSG_SIZEBYTES) {
+ ret = -EINVAL;
+ break;
+ }
+
+ send_data = kzalloc(send_param->sizebytes, GFP_TEMPORARY);
+ if (!send_data) {
+ ret = -ENOMEM;
+ break;
+ }
+
+ if (copy_from_user(send_data, (void __user *)send_param->data,
+ send_param->sizebytes)) {
+ ret = -EFAULT;
+ } else {
+ ret = hab_vchan_send(ctx, send_param->vcid,
+ send_param->sizebytes,
+ send_data,
+ send_param->flags);
+ }
+ kfree(send_data);
+ break;
+ case IOCTL_HAB_RECV:
+ recv_param = (struct hab_recv *)data;
+ if (!recv_param->data) {
+ ret = -EINVAL;
+ break;
+ }
+
+ msg = hab_vchan_recv(ctx, recv_param->vcid, recv_param->flags);
+
+ if (IS_ERR(msg)) {
+ recv_param->sizebytes = 0;
+ ret = PTR_ERR(msg);
+ break;
+ }
+
+ if (recv_param->sizebytes < msg->sizebytes) {
+ recv_param->sizebytes = 0;
+ ret = -EINVAL;
+ } else if (copy_to_user((void __user *)recv_param->data,
+ msg->data,
+ msg->sizebytes)) {
+ pr_err("copy_to_user failed: vc=%x size=%d\n",
+ recv_param->vcid, (int)msg->sizebytes);
+ recv_param->sizebytes = 0;
+ ret = -EFAULT;
+ } else {
+ recv_param->sizebytes = msg->sizebytes;
+ }
+
+ hab_msg_free(msg);
+ break;
+ case IOCTL_HAB_VC_EXPORT:
+ ret = hab_mem_export(ctx, (struct hab_export *)data, 0);
+ break;
+ case IOCTL_HAB_VC_IMPORT:
+ ret = hab_mem_import(ctx, (struct hab_import *)data, 0);
+ break;
+ case IOCTL_HAB_VC_UNEXPORT:
+ ret = hab_mem_unexport(ctx, (struct hab_unexport *)data, 0);
+ break;
+ case IOCTL_HAB_VC_UNIMPORT:
+ ret = hab_mem_unimport(ctx, (struct hab_unimport *)data, 0);
+ break;
+ default:
+ ret = -ENOIOCTLCMD;
+ }
+
+ if (ret == 0 && _IOC_SIZE(cmd) && (cmd & IOC_OUT))
+ if (copy_to_user((void __user *) arg, data, _IOC_SIZE(cmd))) {
+ pr_err("copy_to_user failed: cmd=%x\n", cmd);
+ ret = -EFAULT;
+ }
+
+ return ret;
+}
+
+static const struct file_operations hab_fops = {
+ .owner = THIS_MODULE,
+ .open = hab_open,
+ .release = hab_release,
+ .mmap = habmem_imp_hyp_mmap,
+ .unlocked_ioctl = hab_ioctl
+};
+
+/*
+ * These map sg functions are pass through because the memory backing the
+ * sg list is already accessible to the kernel as they come from a the
+ * dedicated shared vm pool
+ */
+
+static int hab_map_sg(struct device *dev, struct scatterlist *sgl,
+ int nelems, enum dma_data_direction dir,
+ struct dma_attrs *attrs)
+{
+ /* return nelems directly */
+ return nelems;
+}
+
+static void hab_unmap_sg(struct device *dev,
+ struct scatterlist *sgl, int nelems,
+ enum dma_data_direction dir,
+ struct dma_attrs *attrs)
+{
+ /*Do nothing */
+}
+
+static const struct dma_map_ops hab_dma_ops = {
+ .map_sg = hab_map_sg,
+ .unmap_sg = hab_unmap_sg,
+};
+
+static int __init hab_init(void)
+{
+ int result;
+ int i;
+ dev_t dev;
+ struct hab_device *device;
+
+ result = alloc_chrdev_region(&hab_driver.major, 0, 1, "hab");
+
+ if (result < 0) {
+ pr_err("alloc_chrdev_region failed: %d\n", result);
+ return result;
+ }
+
+ cdev_init(&hab_driver.cdev, &hab_fops);
+ hab_driver.cdev.owner = THIS_MODULE;
+ hab_driver.cdev.ops = &hab_fops;
+ dev = MKDEV(MAJOR(hab_driver.major), 0);
+
+ result = cdev_add(&hab_driver.cdev, dev, 1);
+
+ if (result < 0) {
+ unregister_chrdev_region(dev, 1);
+ pr_err("cdev_add failed: %d\n", result);
+ return result;
+ }
+
+ hab_driver.class = class_create(THIS_MODULE, "hab");
+
+ if (IS_ERR(hab_driver.class)) {
+ result = PTR_ERR(hab_driver.class);
+ pr_err("class_create failed: %d\n", result);
+ goto err;
+ }
+
+ hab_driver.dev = device_create(hab_driver.class, NULL,
+ dev, &hab_driver, "hab");
+
+ if (IS_ERR(hab_driver.dev)) {
+ result = PTR_ERR(hab_driver.dev);
+ pr_err("device_create failed: %d\n", result);
+ goto err;
+ }
+
+ for (i = 0; i < hab_driver.ndevices; i++) {
+ device = &hab_driver.devp[i];
+ init_waitqueue_head(&device->openq);
+ }
+
+ hab_hypervisor_register();
+
+ hab_driver.kctx = hab_ctx_alloc(1);
+ if (!hab_driver.kctx) {
+ pr_err("hab_ctx_alloc failed");
+ result = -ENOMEM;
+ hab_hypervisor_unregister();
+ goto err;
+ }
+
+ set_dma_ops(hab_driver.dev, &hab_dma_ops);
+
+ return result;
+
+err:
+ if (!IS_ERR_OR_NULL(hab_driver.dev))
+ device_destroy(hab_driver.class, dev);
+ if (!IS_ERR_OR_NULL(hab_driver.class))
+ class_destroy(hab_driver.class);
+ cdev_del(&hab_driver.cdev);
+ unregister_chrdev_region(dev, 1);
+
+ return result;
+}
+
+static void __exit hab_exit(void)
+{
+ dev_t dev;
+
+ hab_hypervisor_unregister();
+ hab_ctx_put(hab_driver.kctx);
+ dev = MKDEV(MAJOR(hab_driver.major), 0);
+ device_destroy(hab_driver.class, dev);
+ class_destroy(hab_driver.class);
+ cdev_del(&hab_driver.cdev);
+ unregister_chrdev_region(dev, 1);
+}
+
+subsys_initcall(hab_init);
+module_exit(hab_exit);
+
+MODULE_DESCRIPTION("Hypervisor abstraction layer");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/soc/qcom/hab/hab.h b/drivers/soc/qcom/hab/hab.h
new file mode 100644
index 000000000000..805e5b4a7008
--- /dev/null
+++ b/drivers/soc/qcom/hab/hab.h
@@ -0,0 +1,415 @@
+/* Copyright (c) 2016-2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+#ifndef __HAB_H
+#define __HAB_H
+
+#define pr_fmt(fmt) "hab: " fmt
+
+#include <linux/types.h>
+
+#include <linux/habmm.h>
+
+#include <linux/kernel.h>
+#include <linux/interrupt.h>
+#include <linux/device.h>
+#include <linux/fs.h>
+#include <linux/mm.h>
+#include <linux/vmalloc.h>
+#include <linux/slab.h>
+#include <linux/kthread.h>
+#include <linux/sched.h>
+#include <linux/cdev.h>
+#include <linux/list.h>
+#include <linux/spinlock.h>
+#include <linux/rbtree.h>
+#include <linux/idr.h>
+#include <linux/module.h>
+#include <linux/uaccess.h>
+#include <linux/dma-direction.h>
+#include <linux/dma-mapping.h>
+
+enum hab_payload_type {
+ HAB_PAYLOAD_TYPE_MSG = 0x0,
+ HAB_PAYLOAD_TYPE_INIT,
+ HAB_PAYLOAD_TYPE_INIT_ACK,
+ HAB_PAYLOAD_TYPE_ACK,
+ HAB_PAYLOAD_TYPE_EXPORT,
+ HAB_PAYLOAD_TYPE_EXPORT_ACK,
+ HAB_PAYLOAD_TYPE_PROFILE,
+ HAB_PAYLOAD_TYPE_CLOSE,
+};
+#define LOOPBACK_DOM 0xFF
+
+/*
+ * Tuning required. If there are multiple clients, the aging of previous
+ * "request" might be discarded
+ */
+#define Q_AGE_THRESHOLD 1000000
+
+/* match the name to dtsi if for real HYP framework */
+#define DEVICE_AUD1_NAME "hab_aud1"
+#define DEVICE_AUD2_NAME "hab_aud2"
+#define DEVICE_AUD3_NAME "hab_aud3"
+#define DEVICE_AUD4_NAME "hab_aud4"
+#define DEVICE_CAM_NAME "hab_cam"
+#define DEVICE_DISP1_NAME "hab_disp1"
+#define DEVICE_DISP2_NAME "hab_disp2"
+#define DEVICE_DISP3_NAME "hab_disp3"
+#define DEVICE_DISP4_NAME "hab_disp4"
+#define DEVICE_DISP5_NAME "hab_disp5"
+#define DEVICE_GFX_NAME "hab_ogles"
+#define DEVICE_VID_NAME "hab_vid"
+#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"
+
+/* "Size" of the HAB_HEADER_ID and HAB_VCID_ID must match */
+#define HAB_HEADER_SIZE_SHIFT 0
+#define HAB_HEADER_TYPE_SHIFT 16
+#define HAB_HEADER_ID_SHIFT 24
+#define HAB_HEADER_SIZE_MASK 0x0000FFFF
+#define HAB_HEADER_TYPE_MASK 0x00FF0000
+#define HAB_HEADER_ID_MASK 0xFF000000
+#define HAB_HEADER_INITIALIZER {0}
+
+#define HAB_MMID_GET_MAJOR(mmid) (mmid & 0xFFFF)
+#define HAB_MMID_GET_MINOR(mmid) ((mmid>>16) & 0xFF)
+
+#define HAB_VCID_ID_SHIFT 0
+#define HAB_VCID_DOMID_SHIFT 8
+#define HAB_VCID_MMID_SHIFT 16
+#define HAB_VCID_ID_MASK 0x000000FF
+#define HAB_VCID_DOMID_MASK 0x0000FF00
+#define HAB_VCID_MMID_MASK 0xFFFF0000
+#define HAB_VCID_GET_ID(vcid) \
+ (((vcid) & HAB_VCID_ID_MASK) >> HAB_VCID_ID_SHIFT)
+
+#define HAB_HEADER_SET_SIZE(header, size) \
+ ((header).info = (((header).info) & (~HAB_HEADER_SIZE_MASK)) | \
+ (((size) << HAB_HEADER_SIZE_SHIFT) & HAB_HEADER_SIZE_MASK))
+
+#define HAB_HEADER_SET_TYPE(header, type) \
+ ((header).info = (((header).info) & (~HAB_HEADER_TYPE_MASK)) | \
+ (((type) << HAB_HEADER_TYPE_SHIFT) & HAB_HEADER_TYPE_MASK))
+
+#define HAB_HEADER_SET_ID(header, id) \
+ ((header).info = (((header).info) & (~HAB_HEADER_ID_MASK)) | \
+ ((HAB_VCID_GET_ID(id) << HAB_HEADER_ID_SHIFT) \
+ & HAB_HEADER_ID_MASK))
+
+#define HAB_HEADER_GET_SIZE(header) \
+ ((((header).info) & HAB_HEADER_SIZE_MASK) >> HAB_HEADER_SIZE_SHIFT)
+
+#define HAB_HEADER_GET_TYPE(header) \
+ ((((header).info) & HAB_HEADER_TYPE_MASK) >> HAB_HEADER_TYPE_SHIFT)
+
+#define HAB_HEADER_GET_ID(header) \
+ (((((header).info) & HAB_HEADER_ID_MASK) >> \
+ (HAB_HEADER_ID_SHIFT - HAB_VCID_ID_SHIFT)) & HAB_VCID_ID_MASK)
+
+struct hab_header {
+ uint32_t info;
+};
+
+struct physical_channel {
+ struct kref refcount;
+ struct hab_device *habdev;
+ struct list_head node;
+ struct idr vchan_idr;
+ spinlock_t vid_lock;
+
+ struct idr expid_idr;
+ spinlock_t expid_lock;
+
+ void *hyp_data;
+ int dom_id;
+ int closed;
+
+ spinlock_t rxbuf_lock;
+};
+
+struct hab_open_send_data {
+ int vchan_id;
+ int sub_id;
+ int open_id;
+};
+
+struct hab_open_request {
+ int type;
+ struct physical_channel *pchan;
+ int vchan_id;
+ int sub_id;
+ int open_id;
+};
+
+struct hab_open_node {
+ struct hab_open_request request;
+ struct list_head node;
+ int age;
+};
+
+struct hab_export_ack {
+ uint32_t export_id;
+ int32_t vcid_local;
+ int32_t vcid_remote;
+};
+
+struct hab_export_ack_recvd {
+ struct hab_export_ack ack;
+ struct list_head node;
+ int age;
+};
+
+struct hab_message {
+ size_t sizebytes;
+ struct list_head node;
+ uint32_t data[];
+};
+
+struct hab_device {
+ const char *name;
+ unsigned int id;
+ struct list_head pchannels;
+ struct mutex pchan_lock;
+ struct list_head openq_list;
+ spinlock_t openlock;
+ wait_queue_head_t openq;
+};
+
+struct uhab_context {
+ struct kref refcount;
+ struct list_head vchannels;
+
+ struct list_head exp_whse;
+ uint32_t export_total;
+
+ wait_queue_head_t exp_wq;
+ struct list_head exp_rxq;
+ rwlock_t exp_lock;
+ spinlock_t expq_lock;
+
+ struct list_head imp_whse;
+ spinlock_t imp_lock;
+ uint32_t import_total;
+
+ void *import_ctx;
+
+ rwlock_t ctx_lock;
+ int closing;
+ int kernel;
+};
+
+struct hab_driver {
+ struct device *dev;
+ struct cdev cdev;
+ dev_t major;
+ struct class *class;
+ int irq;
+
+ int ndevices;
+ struct hab_device *devp;
+ struct uhab_context *kctx;
+ int b_server_dom;
+ int loopback_num;
+ int b_loopback;
+};
+
+struct virtual_channel {
+ struct work_struct work;
+ /*
+ * refcount is used to track the references from hab core to the virtual
+ * channel such as references from physical channels,
+ * i.e. references from the "other" side
+ */
+ struct kref refcount;
+ /*
+ * usagecnt is used to track the clients who are using this virtual
+ * channel such as local clients, client sowftware etc,
+ * i.e. references from "this" side
+ */
+ struct kref usagecnt;
+ struct physical_channel *pchan;
+ struct uhab_context *ctx;
+ struct list_head node;
+ struct list_head rx_list;
+ wait_queue_head_t rx_queue;
+ spinlock_t rx_lock;
+ int id;
+ int otherend_id;
+ int otherend_closed;
+};
+
+/*
+ * Struct shared between local and remote, contents are composed by exporter,
+ * the importer only writes to pdata and local (exporter) domID
+ */
+struct export_desc {
+ uint32_t export_id;
+ int readonly;
+ uint64_t import_index;
+
+ struct virtual_channel *vchan;
+
+ int32_t vcid_local;
+ int32_t vcid_remote;
+ int domid_local;
+ int domid_remote;
+
+ struct list_head node;
+ void *kva;
+ int payload_count;
+ unsigned char payload[1];
+};
+
+int hab_vchan_open(struct uhab_context *ctx,
+ unsigned int mmid, int32_t *vcid, uint32_t flags);
+void hab_vchan_close(struct uhab_context *ctx,
+ int32_t vcid);
+long hab_vchan_send(struct uhab_context *ctx,
+ int vcid,
+ size_t sizebytes,
+ void *data,
+ unsigned int flags);
+struct hab_message *hab_vchan_recv(struct uhab_context *ctx,
+ int vcid,
+ unsigned int flags);
+void hab_vchan_stop(struct virtual_channel *vchan);
+void hab_vchan_stop_notify(struct virtual_channel *vchan);
+
+int hab_mem_export(struct uhab_context *ctx,
+ struct hab_export *param, int kernel);
+int hab_mem_import(struct uhab_context *ctx,
+ struct hab_import *param, int kernel);
+int hab_mem_unexport(struct uhab_context *ctx,
+ struct hab_unexport *param, int kernel);
+int hab_mem_unimport(struct uhab_context *ctx,
+ struct hab_unimport *param, int kernel);
+
+void habmem_remove_export(struct export_desc *exp);
+
+/* memory hypervisor framework plugin I/F */
+void *habmm_hyp_allocate_grantable(int page_count,
+ uint32_t *sizebytes);
+
+int habmem_hyp_grant_user(unsigned long address,
+ int page_count,
+ int flags,
+ int remotedom,
+ void *ppdata);
+
+int habmem_hyp_grant(unsigned long address,
+ int page_count,
+ int flags,
+ int remotedom,
+ void *ppdata);
+
+int habmem_hyp_revoke(void *expdata, uint32_t count);
+
+void *habmem_imp_hyp_open(void);
+void habmem_imp_hyp_close(void *priv, int kernel);
+
+long habmem_imp_hyp_map(void *priv, void *impdata, uint32_t count,
+ uint32_t remotedom,
+ uint64_t *index,
+ void **pkva,
+ int kernel,
+ uint32_t userflags);
+
+long habmm_imp_hyp_unmap(void *priv, uint64_t index,
+ uint32_t count,
+ int kernel);
+
+int habmem_imp_hyp_mmap(struct file *flip, struct vm_area_struct *vma);
+
+
+
+void hab_msg_free(struct hab_message *message);
+struct hab_message *hab_msg_dequeue(struct virtual_channel *vchan,
+ int wait_flag);
+
+void hab_msg_recv(struct physical_channel *pchan,
+ struct hab_header *header);
+
+void hab_open_request_init(struct hab_open_request *request,
+ int type,
+ struct physical_channel *pchan,
+ int vchan_id,
+ int sub_id,
+ int open_id);
+int hab_open_request_send(struct hab_open_request *request);
+int hab_open_request_add(struct physical_channel *pchan,
+ struct hab_header *header);
+void hab_open_request_free(struct hab_open_request *request);
+int hab_open_listen(struct uhab_context *ctx,
+ struct hab_device *dev,
+ struct hab_open_request *listen,
+ struct hab_open_request **recv_request,
+ int ms_timeout);
+
+struct virtual_channel *hab_vchan_alloc(struct uhab_context *ctx,
+ struct physical_channel *pchan);
+struct virtual_channel *hab_vchan_get(struct physical_channel *pchan,
+ uint32_t vchan_id);
+void hab_vchan_put(struct virtual_channel *vchan);
+
+struct virtual_channel *hab_get_vchan_fromvcid(int32_t vcid,
+ struct uhab_context *ctx);
+struct physical_channel *hab_pchan_alloc(struct hab_device *habdev,
+ int otherend_id);
+struct physical_channel *hab_pchan_find_domid(struct hab_device *dev,
+ int dom_id);
+int hab_vchan_find_domid(struct virtual_channel *vchan);
+
+void hab_pchan_get(struct physical_channel *pchan);
+void hab_pchan_put(struct physical_channel *pchan);
+
+struct uhab_context *hab_ctx_alloc(int kernel);
+
+void hab_ctx_free(struct kref *ref);
+
+static inline void hab_ctx_get(struct uhab_context *ctx)
+{
+ if (ctx)
+ kref_get(&ctx->refcount);
+}
+
+static inline void hab_ctx_put(struct uhab_context *ctx)
+{
+ if (ctx)
+ kref_put(&ctx->refcount, hab_ctx_free);
+}
+
+void hab_send_close_msg(struct virtual_channel *vchan);
+int hab_hypervisor_register(void);
+void hab_hypervisor_unregister(void);
+
+int physical_channel_read(struct physical_channel *pchan,
+ void *payload,
+ size_t read_size);
+
+int physical_channel_send(struct physical_channel *pchan,
+ struct hab_header *header,
+ void *payload);
+
+void physical_channel_rx_dispatch(unsigned long physical_channel);
+
+int loopback_pchan_create(char *dev_name);
+
+bool hab_is_loopback(void);
+
+/* Global singleton HAB instance */
+extern struct hab_driver hab_driver;
+
+#endif /* __HAB_H */
diff --git a/drivers/soc/qcom/hab/hab_grantable.h b/drivers/soc/qcom/hab/hab_grantable.h
new file mode 100644
index 000000000000..8a3f9721a89a
--- /dev/null
+++ b/drivers/soc/qcom/hab/hab_grantable.h
@@ -0,0 +1,29 @@
+/* Copyright (c) 2016-2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+#ifndef __HAB_GRANTABLE_H
+#define __HAB_GRANTABLE_H
+
+/* Grantable should be common between exporter and importer */
+struct grantable {
+ unsigned long pfn;
+};
+
+struct compressed_pfns {
+ unsigned long first_pfn;
+ int nregions;
+ struct region {
+ int size;
+ int space;
+ } region[];
+};
+#endif /* __HAB_GRANTABLE_H */
diff --git a/drivers/soc/qcom/hab/hab_mem_linux.c b/drivers/soc/qcom/hab/hab_mem_linux.c
new file mode 100644
index 000000000000..ab4b9d0885cb
--- /dev/null
+++ b/drivers/soc/qcom/hab/hab_mem_linux.c
@@ -0,0 +1,451 @@
+/* Copyright (c) 2016-2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+#include "hab.h"
+#include <linux/fdtable.h>
+#include <linux/dma-buf.h>
+#include "hab_grantable.h"
+
+
+struct pages_list {
+ struct list_head 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 importer_context {
+ int cnt; /* pages allocated for local file */
+ struct list_head imp_list;
+ struct file *filp;
+};
+
+void *habmm_hyp_allocate_grantable(int page_count,
+ uint32_t *sizebytes)
+{
+ if (!sizebytes || !page_count)
+ return NULL;
+
+ *sizebytes = page_count * sizeof(struct grantable);
+ return vmalloc(*sizebytes);
+}
+
+static int match_file(const void *p, struct file *file, unsigned int fd)
+{
+ /*
+ * We must return fd + 1 because iterate_fd stops searching on
+ * non-zero return, but 0 is a valid fd.
+ */
+ return (p == file) ? (fd + 1) : 0;
+}
+
+
+static int habmem_get_dma_pages(unsigned long address,
+ int page_count,
+ struct page **pages)
+{
+ struct vm_area_struct *vma;
+ struct dma_buf *dmabuf = NULL;
+ unsigned long offset;
+ unsigned long page_offset;
+ struct scatterlist *s;
+ struct sg_table *sg_table = NULL;
+ struct dma_buf_attachment *attach = NULL;
+ struct page *page;
+ int i, j, rc = 0;
+ int fd;
+
+ vma = find_vma(current->mm, address);
+ if (!vma || !vma->vm_file)
+ goto err;
+
+ /* Look for the fd that matches this the vma file */
+ fd = iterate_fd(current->files, 0, match_file, vma->vm_file);
+ if (fd == 0) {
+ pr_err("iterate_fd failed\n");
+ goto err;
+ }
+
+ offset = address - vma->vm_start;
+ page_offset = offset/PAGE_SIZE;
+
+ dmabuf = dma_buf_get(fd - 1);
+
+ attach = dma_buf_attach(dmabuf, hab_driver.dev);
+ if (IS_ERR_OR_NULL(attach)) {
+ pr_err("dma_buf_attach failed\n");
+ goto err;
+ }
+
+ sg_table = dma_buf_map_attachment(attach, DMA_TO_DEVICE);
+
+ if (IS_ERR_OR_NULL(sg_table)) {
+ pr_err("dma_buf_map_attachment failed\n");
+ goto err;
+ }
+
+ for_each_sg(sg_table->sgl, s, sg_table->nents, i) {
+ page = sg_page(s);
+
+ for (j = page_offset; j < (s->length >> PAGE_SHIFT); j++) {
+ pages[rc] = nth_page(page, j);
+ rc++;
+ if (rc >= page_count)
+ break;
+ }
+ if (rc >= page_count)
+ break;
+
+ if (page_offset > (s->length >> PAGE_SHIFT)) {
+ /* carry-over the remaining offset to next s list */
+ page_offset = page_offset-(s->length >> PAGE_SHIFT);
+ } else {
+ /*
+ * the page_offset is within this s list
+ * there is no more offset for the next s list
+ */
+ page_offset = 0;
+ }
+
+ }
+
+err:
+ if (!IS_ERR_OR_NULL(sg_table))
+ dma_buf_unmap_attachment(attach, sg_table, DMA_TO_DEVICE);
+ if (!IS_ERR_OR_NULL(attach))
+ dma_buf_detach(dmabuf, attach);
+ if (!IS_ERR_OR_NULL(dmabuf))
+ dma_buf_put(dmabuf);
+ return rc;
+}
+
+int habmem_hyp_grant_user(unsigned long address,
+ int page_count,
+ int flags,
+ int remotedom,
+ void *ppdata)
+{
+ int i, ret = 0;
+ struct grantable *item = (struct grantable *)ppdata;
+ struct page **pages;
+
+ pages = vmalloc(page_count * sizeof(struct page *));
+ if (!pages)
+ return -ENOMEM;
+
+ down_read(&current->mm->mmap_sem);
+
+ if (HABMM_EXP_MEM_TYPE_DMA & flags) {
+ ret = habmem_get_dma_pages(address,
+ page_count,
+ pages);
+ } else {
+ ret = get_user_pages(current, current->mm,
+ address,
+ page_count,
+ 1,
+ 1,
+ pages,
+ NULL);
+ }
+
+ if (ret > 0) {
+ for (i = 0; i < page_count; i++)
+ item[i].pfn = page_to_pfn(pages[i]);
+ } else {
+ pr_err("get %d user pages failed: %d\n", page_count, ret);
+ }
+
+ vfree(pages);
+ up_read(&current->mm->mmap_sem);
+ return ret;
+}
+/*
+ * exporter - grant & revoke
+ * generate shareable page list based on CPU friendly virtual "address".
+ * The result as an array is stored in ppdata to return to caller
+ * page size 4KB is assumed
+ */
+int habmem_hyp_grant(unsigned long address,
+ int page_count,
+ int flags,
+ int remotedom,
+ void *ppdata)
+{
+ int i;
+ struct grantable *item;
+ void *kva = (void *)(uintptr_t)address;
+ int is_vmalloc = is_vmalloc_addr(kva);
+
+ item = (struct grantable *)ppdata;
+
+ for (i = 0; i < page_count; i++) {
+ kva = (void *)(uintptr_t)(address + i*PAGE_SIZE);
+ if (is_vmalloc)
+ item[i].pfn = page_to_pfn(vmalloc_to_page(kva));
+ else
+ item[i].pfn = page_to_pfn(virt_to_page(kva));
+ }
+
+ return 0;
+}
+
+int habmem_hyp_revoke(void *expdata, uint32_t count)
+{
+ return 0;
+}
+
+void *habmem_imp_hyp_open(void)
+{
+ struct importer_context *priv;
+
+ priv = kzalloc(sizeof(*priv), GFP_KERNEL);
+ if (!priv)
+ return NULL;
+
+ INIT_LIST_HEAD(&priv->imp_list);
+
+ return priv;
+}
+
+void habmem_imp_hyp_close(void *imp_ctx, int kernel)
+{
+ struct importer_context *priv = imp_ctx;
+ struct pages_list *pglist, *pglist_tmp;
+
+ 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--;
+
+ vfree(pglist->pages);
+ kfree(pglist);
+ }
+
+ kfree(priv);
+}
+
+/*
+ * setup pages, be ready for the following mmap call
+ * index is output to refer to this imported buffer described by the import data
+ */
+long habmem_imp_hyp_map(void *imp_ctx,
+ void *impdata,
+ uint32_t count,
+ uint32_t remotedom,
+ uint64_t *index,
+ void **pkva,
+ int kernel,
+ uint32_t userflags)
+{
+ struct page **pages;
+ struct compressed_pfns *pfn_table = impdata;
+ struct pages_list *pglist;
+ struct importer_context *priv = imp_ctx;
+ unsigned long pfn;
+ int i, j, k = 0;
+
+ if (!pfn_table || !priv)
+ return -EINVAL;
+
+ pages = vmalloc(count * sizeof(struct page *));
+ if (!pages)
+ return -ENOMEM;
+
+ pglist = kzalloc(sizeof(*pglist), GFP_KERNEL);
+ if (!pglist) {
+ vfree(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 = pages;
+ pglist->npages = count;
+ pglist->kernel = kernel;
+ pglist->index = page_to_phys(pages[0]) >> PAGE_SHIFT;
+ pglist->refcntk = pglist->refcntu = 0;
+ pglist->userflags = userflags;
+
+ *index = pglist->index << PAGE_SHIFT;
+
+ if (kernel) {
+ pgprot_t prot = PAGE_KERNEL;
+
+ if (!(userflags & HABMM_IMPORT_FLAGS_CACHED))
+ prot = pgprot_writecombine(prot);
+
+ pglist->kva = vmap(pglist->pages, pglist->npages, VM_MAP, prot);
+ if (pglist->kva == NULL) {
+ vfree(pages);
+ kfree(pglist);
+ pr_err("%ld pages vmap failed\n", pglist->npages);
+ return -ENOMEM;
+ }
+
+ pglist->uva = NULL;
+ pglist->refcntk++;
+ *pkva = pglist->kva;
+ *index = (uint64_t)((uintptr_t)pglist->kva);
+ } else {
+ pglist->kva = NULL;
+ }
+
+ list_add_tail(&pglist->list, &priv->imp_list);
+ priv->cnt++;
+
+ return 0;
+}
+
+/* the input index is PHY address shifted for uhab, and kva for khab */
+long habmm_imp_hyp_unmap(void *imp_ctx,
+ uint64_t index,
+ uint32_t count,
+ int kernel)
+{
+ struct importer_context *priv = imp_ctx;
+ struct pages_list *pglist;
+ int found = 0;
+ uint64_t pg_index = index >> PAGE_SHIFT;
+
+ list_for_each_entry(pglist, &priv->imp_list, list) {
+ if (kernel) {
+ if (pglist->kva == (void *)((uintptr_t)index))
+ found = 1;
+ } else {
+ if (pglist->index == pg_index)
+ found = 1;
+ }
+
+ if (found) {
+ list_del(&pglist->list);
+ priv->cnt--;
+ break;
+ }
+ }
+
+ if (!found) {
+ pr_err("failed to find export id on index %llx\n", index);
+ return -EINVAL;
+ }
+
+ if (kernel)
+ if (pglist->kva)
+ vunmap(pglist->kva);
+
+ vfree(pglist->pages);
+ kfree(pglist);
+
+ return 0;
+}
+
+static int hab_map_fault(struct vm_area_struct *vma, struct vm_fault *vmf)
+{
+ struct page *page;
+ struct pages_list *pglist;
+
+ unsigned long offset = vma->vm_pgoff << PAGE_SHIFT;
+
+ /* PHY address */
+ unsigned long fault_offset =
+ (unsigned long)vmf->virtual_address - vma->vm_start + offset;
+ unsigned long fault_index = fault_offset>>PAGE_SHIFT;
+ int page_idx;
+
+ if (vma == NULL)
+ return VM_FAULT_SIGBUS;
+
+ pglist = vma->vm_private_data;
+
+ page_idx = fault_index - pglist->index;
+ if (page_idx < 0 || page_idx >= pglist->npages) {
+ pr_err("Out of page array. page_idx %d, pg cnt %ld",
+ page_idx, pglist->npages);
+ return VM_FAULT_SIGBUS;
+ }
+
+ page = pglist->pages[page_idx];
+ get_page(page);
+ vmf->page = page;
+ return 0;
+}
+
+static void hab_map_open(struct vm_area_struct *vma)
+{
+}
+
+static void hab_map_close(struct vm_area_struct *vma)
+{
+}
+
+static const struct vm_operations_struct habmem_vm_ops = {
+
+ .fault = hab_map_fault,
+ .open = hab_map_open,
+ .close = hab_map_close,
+};
+
+int habmem_imp_hyp_mmap(struct file *filp, struct vm_area_struct *vma)
+{
+ struct uhab_context *ctx = (struct uhab_context *) filp->private_data;
+ struct importer_context *imp_ctx = ctx->import_ctx;
+ long length = vma->vm_end - vma->vm_start;
+ struct pages_list *pglist;
+ int bfound = 0;
+
+ list_for_each_entry(pglist, &imp_ctx->imp_list, list) {
+ if (pglist->index == vma->vm_pgoff) {
+ bfound = 1;
+ break;
+ }
+ }
+
+ if (!bfound) {
+ pr_err("Failed to find pglist vm_pgoff: %d\n", vma->vm_pgoff);
+ return -EINVAL;
+ }
+
+ 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;
+ }
+
+ vma->vm_ops = &habmem_vm_ops;
+
+ vma->vm_private_data = pglist;
+
+ if (!(pglist->userflags & HABMM_IMPORT_FLAGS_CACHED))
+ vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot);
+
+ return 0;
+}
diff --git a/drivers/soc/qcom/hab/hab_mimex.c b/drivers/soc/qcom/hab/hab_mimex.c
new file mode 100644
index 000000000000..aaef9aa9f414
--- /dev/null
+++ b/drivers/soc/qcom/hab/hab_mimex.c
@@ -0,0 +1,394 @@
+/* Copyright (c) 2016-2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+#include "hab.h"
+#include "hab_grantable.h"
+
+/*
+ * use physical channel to send export parcel
+
+ * local remote
+ * send(export) --> IRQ store to export warehouse
+ * wait(export ack) <-- send(export ack)
+
+ * the actual data consists the following 3 parts listed in order
+ * 1. header (uint32_t) vcid|type|size
+ * 2. export parcel (full struct)
+ * 3. full contents in export->pdata
+ */
+
+
+static int hab_export_ack_find(struct uhab_context *ctx,
+ struct hab_export_ack *expect_ack)
+{
+ int ret = 0;
+ struct hab_export_ack_recvd *ack_recvd;
+
+ spin_lock_bh(&ctx->expq_lock);
+
+ list_for_each_entry(ack_recvd, &ctx->exp_rxq, node) {
+ if (ack_recvd->ack.export_id == expect_ack->export_id &&
+ ack_recvd->ack.vcid_local == expect_ack->vcid_local &&
+ ack_recvd->ack.vcid_remote == expect_ack->vcid_remote) {
+ list_del(&ack_recvd->node);
+ kfree(ack_recvd);
+ ret = 1;
+ break;
+ }
+ ack_recvd->age++;
+ if (ack_recvd->age > Q_AGE_THRESHOLD) {
+ list_del(&ack_recvd->node);
+ kfree(ack_recvd);
+ }
+ }
+
+ spin_unlock_bh(&ctx->expq_lock);
+
+ return ret;
+}
+
+static int hab_export_ack_wait(struct uhab_context *ctx,
+ struct hab_export_ack *expect_ack)
+{
+ int ret;
+
+ ret = wait_event_interruptible_timeout(ctx->exp_wq,
+ hab_export_ack_find(ctx, expect_ack),
+ HZ);
+ if (!ret || (ret == -ERESTARTSYS))
+ ret = -EAGAIN;
+ else if (ret > 0)
+ ret = 0;
+ return ret;
+}
+
+/*
+ * Get id from free list first. if not available, new id is generated.
+ * Once generated it will not be erased
+ * assumptions: no handshake or memory map/unmap in this helper function
+ */
+static struct export_desc *habmem_add_export(struct virtual_channel *vchan,
+ int sizebytes,
+ uint32_t flags)
+{
+ struct uhab_context *ctx;
+ struct export_desc *exp;
+
+ if (!vchan || !sizebytes)
+ return NULL;
+
+ exp = vmalloc(sizebytes);
+ if (!exp)
+ return NULL;
+
+ idr_preload(GFP_KERNEL);
+ spin_lock(&vchan->pchan->expid_lock);
+ exp->export_id =
+ idr_alloc(&vchan->pchan->expid_idr, exp, 1, 0, GFP_NOWAIT);
+ spin_unlock(&vchan->pchan->expid_lock);
+ idr_preload_end();
+
+ exp->readonly = flags;
+ exp->vchan = vchan;
+ exp->vcid_local = vchan->id;
+ exp->vcid_remote = vchan->otherend_id;
+ exp->domid_local = -1; /* dom id, provided on the importer */
+ exp->domid_remote = vchan->pchan->dom_id;
+
+ ctx = vchan->ctx;
+ write_lock(&ctx->exp_lock);
+ ctx->export_total++;
+ list_add_tail(&exp->node, &ctx->exp_whse);
+ write_unlock(&ctx->exp_lock);
+
+ return exp;
+}
+
+void habmem_remove_export(struct export_desc *exp)
+{
+ struct physical_channel *pchan;
+ struct uhab_context *ctx;
+
+ if (!exp || !exp->vchan || !exp->vchan->ctx || !exp->vchan->pchan)
+ return;
+
+ ctx = exp->vchan->ctx;
+ ctx->export_total--;
+
+ pchan = exp->vchan->pchan;
+
+ spin_lock(&pchan->expid_lock);
+ idr_remove(&pchan->expid_idr, exp->export_id);
+ spin_unlock(&pchan->expid_lock);
+
+ vfree(exp);
+}
+
+static int compress_pfns(void **pfns, int npages, unsigned int *data_size)
+{
+ int i, j = 0;
+ struct grantable *item = (struct grantable *)*pfns;
+ int region_size = 1;
+ struct compressed_pfns *new_table =
+ vmalloc(sizeof(struct compressed_pfns) +
+ npages * sizeof(struct region));
+
+ if (!new_table)
+ return -ENOMEM;
+
+ new_table->first_pfn = item[0].pfn;
+ for (i = 1; i < npages; i++) {
+ if (item[i].pfn-1 == item[i-1].pfn) {
+ region_size++;
+ } else {
+ new_table->region[j].size = region_size;
+ new_table->region[j].space = item[i].pfn -
+ item[i-1].pfn - 1;
+ j++;
+ region_size = 1;
+ }
+ }
+ new_table->region[j].size = region_size;
+ new_table->region[j].space = 0;
+ new_table->nregions = j+1;
+ vfree(*pfns);
+
+ *data_size = sizeof(struct compressed_pfns) +
+ sizeof(struct region)*new_table->nregions;
+ *pfns = new_table;
+ return 0;
+}
+
+/*
+ * store the parcel to the warehouse, then send the parcel to remote side
+ * both exporter composed export descriptor and the grantrefids are sent
+ * as one msg to the importer side
+ */
+static int habmem_export_vchan(struct uhab_context *ctx,
+ struct virtual_channel *vchan,
+ void *pdata,
+ int payload_size,
+ int nunits,
+ uint32_t flags,
+ uint32_t *export_id) {
+ int ret;
+ struct export_desc *exp;
+ uint32_t sizebytes = sizeof(*exp) + payload_size;
+ struct hab_export_ack expected_ack = {0};
+ struct hab_header header = HAB_HEADER_INITIALIZER;
+
+ exp = habmem_add_export(vchan, sizebytes, flags);
+ if (!exp)
+ return -ENOMEM;
+
+ /* append the pdata to the export descriptor */
+ exp->payload_count = nunits;
+ memcpy(exp->payload, pdata, payload_size);
+
+ HAB_HEADER_SET_SIZE(header, sizebytes);
+ HAB_HEADER_SET_TYPE(header, HAB_PAYLOAD_TYPE_EXPORT);
+ HAB_HEADER_SET_ID(header, vchan->otherend_id);
+ ret = physical_channel_send(vchan->pchan, &header, exp);
+
+ if (ret != 0) {
+ pr_err("failed to export payload to the remote %d\n", ret);
+ return ret;
+ }
+
+ expected_ack.export_id = exp->export_id;
+ expected_ack.vcid_local = exp->vcid_local;
+ expected_ack.vcid_remote = exp->vcid_remote;
+ ret = hab_export_ack_wait(ctx, &expected_ack);
+
+ *export_id = exp->export_id;
+
+ return ret;
+}
+
+int hab_mem_export(struct uhab_context *ctx,
+ struct hab_export *param,
+ int kernel)
+{
+ int ret = 0;
+ void *pdata_exp = NULL;
+ unsigned int pdata_size = 0;
+ uint32_t export_id = 0;
+ struct virtual_channel *vchan;
+ int page_count;
+
+ if (!ctx || !param || param->sizebytes > HAB_MAX_EXPORT_SIZE)
+ return -EINVAL;
+
+ vchan = hab_get_vchan_fromvcid(param->vcid, ctx);
+ if (!vchan || !vchan->pchan) {
+ ret = -ENODEV;
+ goto err;
+ }
+
+ page_count = param->sizebytes/PAGE_SIZE;
+ pdata_exp = habmm_hyp_allocate_grantable(page_count, &pdata_size);
+ if (!pdata_exp) {
+ ret = -ENOMEM;
+ goto err;
+ }
+
+ if (kernel) {
+ ret = habmem_hyp_grant((unsigned long)param->buffer,
+ page_count,
+ param->flags,
+ vchan->pchan->dom_id,
+ pdata_exp);
+ } else {
+ ret = habmem_hyp_grant_user((unsigned long)param->buffer,
+ page_count,
+ param->flags,
+ vchan->pchan->dom_id,
+ pdata_exp);
+ }
+ if (ret < 0) {
+ pr_err("habmem_hyp_grant failed size=%d ret=%d\n",
+ pdata_size, ret);
+ goto err;
+ }
+
+ compress_pfns(&pdata_exp, page_count, &pdata_size);
+
+ ret = habmem_export_vchan(ctx,
+ vchan,
+ pdata_exp,
+ pdata_size,
+ page_count,
+ param->flags,
+ &export_id);
+
+ param->exportid = export_id;
+err:
+ vfree(pdata_exp);
+ if (vchan)
+ hab_vchan_put(vchan);
+ return ret;
+}
+
+int hab_mem_unexport(struct uhab_context *ctx,
+ struct hab_unexport *param,
+ int kernel)
+{
+ int ret = 0, found = 0;
+ struct export_desc *exp, *tmp;
+
+ if (!ctx || !param)
+ return -EINVAL;
+
+ write_lock(&ctx->exp_lock);
+ list_for_each_entry_safe(exp, tmp, &ctx->exp_whse, node) {
+ if ((param->exportid == exp->export_id) &&
+ (param->vcid == exp->vcid_local)) {
+ list_del(&exp->node);
+ found = 1;
+ break;
+ }
+ }
+ write_unlock(&ctx->exp_lock);
+
+ if (!found)
+ return -EINVAL;
+
+ ret = habmem_hyp_revoke(exp->payload, exp->payload_count);
+
+ habmem_remove_export(exp);
+ return ret;
+}
+
+int hab_mem_import(struct uhab_context *ctx,
+ struct hab_import *param,
+ int kernel)
+{
+ int ret = 0, found = 0;
+ struct export_desc *exp = NULL;
+
+ if (!ctx || !param)
+ return -EINVAL;
+
+ spin_lock_bh(&ctx->imp_lock);
+ list_for_each_entry(exp, &ctx->imp_whse, node) {
+ if ((exp->export_id == param->exportid) &&
+ (param->vcid == exp->vcid_remote)) {
+ found = 1;
+ break;
+ }
+ }
+ spin_unlock_bh(&ctx->imp_lock);
+
+ if (!found) {
+ pr_err("Fail to get export descriptor from export id %d\n",
+ param->exportid);
+ ret = -ENODEV;
+ return ret;
+ }
+
+ ret = habmem_imp_hyp_map(ctx->import_ctx,
+ exp->payload,
+ exp->payload_count,
+ exp->domid_local,
+ &exp->import_index,
+ &exp->kva,
+ kernel,
+ param->flags);
+ if (ret) {
+ pr_err("Import fail ret:%d pcnt:%d rem:%d 1st_ref:0x%X\n",
+ ret, exp->payload_count,
+ exp->domid_local, *((uint32_t *)exp->payload));
+ return ret;
+ }
+
+ param->index = exp->import_index;
+ param->kva = (uint64_t)exp->kva;
+
+ return ret;
+}
+
+int hab_mem_unimport(struct uhab_context *ctx,
+ struct hab_unimport *param,
+ int kernel)
+{
+ int ret = 0, found = 0;
+ struct export_desc *exp = NULL, *exp_tmp;
+
+ if (!ctx || !param)
+ return -EINVAL;
+
+ spin_lock_bh(&ctx->imp_lock);
+ list_for_each_entry_safe(exp, exp_tmp, &ctx->imp_whse, node) {
+ if ((exp->export_id == param->exportid) &&
+ (param->vcid == exp->vcid_remote)) {
+ list_del(&exp->node);
+ ctx->import_total--;
+ found = 1;
+ break;
+ }
+ }
+ spin_unlock_bh(&ctx->imp_lock);
+
+ if (!found)
+ ret = -EINVAL;
+ else {
+ ret = habmm_imp_hyp_unmap(ctx->import_ctx,
+ exp->import_index,
+ exp->payload_count,
+ kernel);
+
+ param->kva = (uint64_t)exp->kva;
+ kfree(exp);
+ }
+
+ return ret;
+}
diff --git a/drivers/soc/qcom/hab/hab_msg.c b/drivers/soc/qcom/hab/hab_msg.c
new file mode 100644
index 000000000000..f08cc83fe9fc
--- /dev/null
+++ b/drivers/soc/qcom/hab/hab_msg.c
@@ -0,0 +1,208 @@
+/* Copyright (c) 2016-2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+#include "hab.h"
+
+static int hab_rx_queue_empty(struct virtual_channel *vchan)
+{
+ int ret;
+
+ spin_lock_bh(&vchan->rx_lock);
+ ret = list_empty(&vchan->rx_list);
+ spin_unlock_bh(&vchan->rx_lock);
+ return ret;
+}
+
+static struct hab_message*
+hab_msg_alloc(struct physical_channel *pchan, size_t sizebytes)
+{
+ struct hab_message *message;
+
+ message = kzalloc(sizeof(*message) + sizebytes, GFP_ATOMIC);
+ if (!message)
+ return NULL;
+
+ message->sizebytes =
+ physical_channel_read(pchan, message->data, sizebytes);
+
+ return message;
+}
+
+void hab_msg_free(struct hab_message *message)
+{
+ kfree(message);
+}
+
+struct hab_message *
+hab_msg_dequeue(struct virtual_channel *vchan, int wait_flag)
+{
+ struct hab_message *message = NULL;
+ int ret = 0;
+
+ if (wait_flag) {
+ if (hab_rx_queue_empty(vchan))
+ ret = wait_event_interruptible(vchan->rx_queue,
+ !hab_rx_queue_empty(vchan) ||
+ vchan->otherend_closed);
+ }
+
+ if (!ret && !vchan->otherend_closed) {
+ spin_lock_bh(&vchan->rx_lock);
+ if (!list_empty(&vchan->rx_list)) {
+ message = list_first_entry(&vchan->rx_list,
+ struct hab_message, node);
+ list_del(&message->node);
+ }
+ spin_unlock_bh(&vchan->rx_lock);
+ }
+
+ return message;
+}
+
+static void hab_msg_queue(struct virtual_channel *vchan,
+ struct hab_message *message)
+{
+ spin_lock_bh(&vchan->rx_lock);
+ list_add_tail(&message->node, &vchan->rx_list);
+ spin_unlock_bh(&vchan->rx_lock);
+
+ wake_up_interruptible(&vchan->rx_queue);
+}
+
+static int hab_export_enqueue(struct virtual_channel *vchan,
+ struct export_desc *exp)
+{
+ struct uhab_context *ctx = vchan->ctx;
+
+ spin_lock_bh(&ctx->imp_lock);
+ list_add_tail(&exp->node, &ctx->imp_whse);
+ ctx->import_total++;
+ spin_unlock_bh(&ctx->imp_lock);
+
+ return 0;
+}
+
+static int hab_send_export_ack(struct physical_channel *pchan,
+ struct export_desc *exp)
+{
+ struct hab_export_ack exp_ack = {
+ .export_id = exp->export_id,
+ .vcid_local = exp->vcid_local,
+ .vcid_remote = exp->vcid_remote
+ };
+ struct hab_header header = HAB_HEADER_INITIALIZER;
+
+ HAB_HEADER_SET_SIZE(header, sizeof(exp_ack));
+ HAB_HEADER_SET_TYPE(header, HAB_PAYLOAD_TYPE_EXPORT_ACK);
+ HAB_HEADER_SET_ID(header, exp->vcid_local);
+ return physical_channel_send(pchan, &header, &exp_ack);
+}
+
+static int hab_receive_create_export_ack(struct physical_channel *pchan,
+ struct uhab_context *ctx)
+{
+ struct hab_export_ack_recvd *ack_recvd =
+ kzalloc(sizeof(*ack_recvd), GFP_ATOMIC);
+
+ if (!ack_recvd)
+ return -ENOMEM;
+
+ if (physical_channel_read(pchan,
+ &ack_recvd->ack,
+ sizeof(ack_recvd->ack)) != sizeof(ack_recvd->ack))
+ return -EIO;
+
+ spin_lock_bh(&ctx->expq_lock);
+ list_add_tail(&ack_recvd->node, &ctx->exp_rxq);
+ spin_unlock_bh(&ctx->expq_lock);
+
+ return 0;
+}
+
+void hab_msg_recv(struct physical_channel *pchan,
+ struct hab_header *header)
+{
+ int ret;
+ struct hab_message *message;
+ struct hab_device *dev = pchan->habdev;
+ size_t sizebytes = HAB_HEADER_GET_SIZE(*header);
+ uint32_t payload_type = HAB_HEADER_GET_TYPE(*header);
+ uint32_t vchan_id = HAB_HEADER_GET_ID(*header);
+ struct virtual_channel *vchan = NULL;
+ struct export_desc *exp_desc;
+
+ /* get the local virtual channel if it isn't an open message */
+ if (payload_type != HAB_PAYLOAD_TYPE_INIT &&
+ payload_type != HAB_PAYLOAD_TYPE_INIT_ACK &&
+ payload_type != HAB_PAYLOAD_TYPE_ACK) {
+ vchan = hab_vchan_get(pchan, vchan_id);
+ if (!vchan) {
+ return;
+ } else if (vchan->otherend_closed) {
+ hab_vchan_put(vchan);
+ return;
+ }
+ }
+
+ switch (payload_type) {
+ case HAB_PAYLOAD_TYPE_MSG:
+ message = hab_msg_alloc(pchan, sizebytes);
+ if (!message)
+ break;
+
+ hab_msg_queue(vchan, message);
+ break;
+
+ case HAB_PAYLOAD_TYPE_INIT:
+ case HAB_PAYLOAD_TYPE_INIT_ACK:
+ case HAB_PAYLOAD_TYPE_ACK:
+ ret = hab_open_request_add(pchan, header);
+ if (ret)
+ break;
+ wake_up_interruptible(&dev->openq);
+ break;
+
+ case HAB_PAYLOAD_TYPE_EXPORT:
+ exp_desc = kzalloc(sizebytes, GFP_ATOMIC);
+ if (!exp_desc)
+ break;
+
+ if (physical_channel_read(pchan, exp_desc, sizebytes) !=
+ sizebytes) {
+ vfree(exp_desc);
+ break;
+ }
+
+ exp_desc->domid_local = pchan->dom_id;
+
+ hab_export_enqueue(vchan, exp_desc);
+ hab_send_export_ack(pchan, exp_desc);
+ break;
+
+ case HAB_PAYLOAD_TYPE_EXPORT_ACK:
+ ret = hab_receive_create_export_ack(pchan, vchan->ctx);
+ if (ret)
+ break;
+
+ wake_up_interruptible(&vchan->ctx->exp_wq);
+ break;
+
+ case HAB_PAYLOAD_TYPE_CLOSE:
+ hab_vchan_stop(vchan);
+ break;
+
+ default:
+ break;
+ }
+ if (vchan)
+ hab_vchan_put(vchan);
+}
diff --git a/drivers/soc/qcom/hab/hab_open.c b/drivers/soc/qcom/hab/hab_open.c
new file mode 100644
index 000000000000..66468aa43afd
--- /dev/null
+++ b/drivers/soc/qcom/hab/hab_open.c
@@ -0,0 +1,154 @@
+/* Copyright (c) 2016-2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+#include "hab.h"
+
+void hab_open_request_init(struct hab_open_request *request,
+ int type,
+ struct physical_channel *pchan,
+ int vchan_id,
+ int sub_id,
+ int open_id)
+{
+ request->type = type;
+ request->pchan = pchan;
+ request->vchan_id = vchan_id;
+ request->sub_id = sub_id;
+ request->open_id = open_id;
+}
+
+int hab_open_request_send(struct hab_open_request *request)
+{
+ struct hab_header header = HAB_HEADER_INITIALIZER;
+ struct hab_open_send_data data;
+
+ HAB_HEADER_SET_SIZE(header, sizeof(struct hab_open_send_data));
+ HAB_HEADER_SET_TYPE(header, request->type);
+
+ data.vchan_id = request->vchan_id;
+ data.open_id = request->open_id;
+ data.sub_id = request->sub_id;
+
+ return physical_channel_send(request->pchan, &header, &data);
+}
+
+int hab_open_request_add(struct physical_channel *pchan,
+ struct hab_header *header)
+{
+ struct hab_open_node *node;
+ struct hab_device *dev = pchan->habdev;
+ struct hab_open_send_data data;
+ struct hab_open_request *request;
+
+ node = kzalloc(sizeof(*node), GFP_ATOMIC);
+ if (!node)
+ return -ENOMEM;
+
+ if (physical_channel_read(pchan, &data, HAB_HEADER_GET_SIZE(*header)) !=
+ HAB_HEADER_GET_SIZE(*header))
+ return -EIO;
+
+ request = &node->request;
+ request->type = HAB_HEADER_GET_TYPE(*header);
+ request->pchan = pchan;
+ request->vchan_id = data.vchan_id;
+ request->sub_id = data.sub_id;
+ request->open_id = data.open_id;
+ node->age = 0;
+ hab_pchan_get(pchan);
+
+ spin_lock_bh(&dev->openlock);
+ list_add_tail(&node->node, &dev->openq_list);
+ spin_unlock_bh(&dev->openlock);
+
+ return 0;
+}
+
+static int hab_open_request_find(struct uhab_context *ctx,
+ struct hab_device *dev,
+ struct hab_open_request *listen,
+ struct hab_open_request **recv_request)
+{
+ struct hab_open_node *node, *tmp;
+ struct hab_open_request *request;
+ int ret = 0;
+
+ if (ctx->closing ||
+ (listen->pchan && listen->pchan->closed)) {
+ *recv_request = NULL;
+ return 1;
+ }
+
+ spin_lock_bh(&dev->openlock);
+ if (list_empty(&dev->openq_list))
+ goto done;
+
+ list_for_each_entry_safe(node, tmp, &dev->openq_list, node) {
+ request = (struct hab_open_request *)node;
+ if (request->type == listen->type &&
+ (request->sub_id == listen->sub_id) &&
+ (!listen->open_id ||
+ request->open_id == listen->open_id) &&
+ (!listen->pchan ||
+ request->pchan == listen->pchan)) {
+ list_del(&node->node);
+ *recv_request = request;
+ ret = 1;
+ break;
+ }
+ node->age++;
+ if (node->age > Q_AGE_THRESHOLD) {
+ list_del(&node->node);
+ hab_open_request_free(request);
+ }
+ }
+
+done:
+ spin_unlock_bh(&dev->openlock);
+ return ret;
+}
+
+void hab_open_request_free(struct hab_open_request *request)
+{
+ if (request) {
+ hab_pchan_put(request->pchan);
+ kfree(request);
+ }
+}
+
+int hab_open_listen(struct uhab_context *ctx,
+ struct hab_device *dev,
+ struct hab_open_request *listen,
+ struct hab_open_request **recv_request,
+ int ms_timeout)
+{
+ int ret = 0;
+
+ if (!ctx || !listen || !recv_request)
+ return -EINVAL;
+
+ *recv_request = NULL;
+ if (ms_timeout > 0) {
+ ret = wait_event_interruptible_timeout(dev->openq,
+ hab_open_request_find(ctx, dev, listen, recv_request),
+ ms_timeout);
+ if (!ret || (-ERESTARTSYS == ret))
+ ret = -EAGAIN;
+ else if (ret > 0)
+ ret = 0;
+ } else {
+ ret = wait_event_interruptible(dev->openq,
+ hab_open_request_find(ctx, dev, listen, recv_request));
+ }
+
+ return ret;
+}
diff --git a/drivers/soc/qcom/hab/hab_pchan.c b/drivers/soc/qcom/hab/hab_pchan.c
new file mode 100644
index 000000000000..1ad727f7d90f
--- /dev/null
+++ b/drivers/soc/qcom/hab/hab_pchan.c
@@ -0,0 +1,86 @@
+/* Copyright (c) 2016-2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+#include "hab.h"
+
+struct physical_channel *
+hab_pchan_alloc(struct hab_device *habdev, int otherend_id)
+{
+ struct physical_channel *pchan = kzalloc(sizeof(*pchan), GFP_KERNEL);
+
+ if (!pchan)
+ return NULL;
+
+ idr_init(&pchan->vchan_idr);
+ spin_lock_init(&pchan->vid_lock);
+ idr_init(&pchan->expid_idr);
+ spin_lock_init(&pchan->expid_lock);
+ kref_init(&pchan->refcount);
+
+ pchan->habdev = habdev;
+ pchan->dom_id = otherend_id;
+ pchan->closed = 1;
+ pchan->hyp_data = NULL;
+
+ spin_lock_init(&pchan->rxbuf_lock);
+
+ mutex_lock(&habdev->pchan_lock);
+ list_add_tail(&pchan->node, &habdev->pchannels);
+ mutex_unlock(&habdev->pchan_lock);
+
+ return pchan;
+}
+
+static void hab_pchan_free(struct kref *ref)
+{
+ struct physical_channel *pchan =
+ container_of(ref, struct physical_channel, refcount);
+
+ mutex_lock(&pchan->habdev->pchan_lock);
+ list_del(&pchan->node);
+ mutex_unlock(&pchan->habdev->pchan_lock);
+ kfree(pchan->hyp_data);
+ kfree(pchan);
+}
+
+struct physical_channel *
+hab_pchan_find_domid(struct hab_device *dev, int dom_id)
+{
+ struct physical_channel *pchan;
+
+ mutex_lock(&dev->pchan_lock);
+ list_for_each_entry(pchan, &dev->pchannels, node)
+ if (pchan->dom_id == dom_id)
+ break;
+
+ if (pchan->dom_id != dom_id)
+ pchan = NULL;
+
+ if (pchan && !kref_get_unless_zero(&pchan->refcount))
+ pchan = NULL;
+
+ mutex_unlock(&dev->pchan_lock);
+
+ return pchan;
+}
+
+void hab_pchan_get(struct physical_channel *pchan)
+{
+ if (pchan)
+ kref_get(&pchan->refcount);
+}
+
+void hab_pchan_put(struct physical_channel *pchan)
+{
+ if (pchan)
+ kref_put(&pchan->refcount, hab_pchan_free);
+}
diff --git a/drivers/soc/qcom/hab/hab_pipe.c b/drivers/soc/qcom/hab/hab_pipe.c
new file mode 100644
index 000000000000..e757b6cb1f01
--- /dev/null
+++ b/drivers/soc/qcom/hab/hab_pipe.c
@@ -0,0 +1,131 @@
+/* Copyright (c) 2016-2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+#include "hab.h"
+#include "hab_pipe.h"
+
+size_t hab_pipe_calc_required_bytes(uint32_t shared_buf_size)
+{
+ return sizeof(struct hab_pipe)
+ + (2 * (sizeof(struct hab_shared_buf) + shared_buf_size));
+}
+
+struct hab_pipe_endpoint *hab_pipe_init(struct hab_pipe *pipe,
+ uint32_t shared_buf_size, int top)
+{
+ struct hab_pipe_endpoint *ep = NULL;
+ struct hab_shared_buf *buf_a;
+ struct hab_shared_buf *buf_b;
+
+ if (!pipe)
+ return NULL;
+
+ buf_a = (struct hab_shared_buf *) pipe->buf_base;
+ buf_b = (struct hab_shared_buf *) (pipe->buf_base
+ + sizeof(struct hab_shared_buf) + shared_buf_size);
+
+ if (top) {
+ ep = &pipe->top;
+ memset(ep, 0, sizeof(*ep));
+ ep->tx_info.sh_buf = buf_a;
+ ep->rx_info.sh_buf = buf_b;
+ } else {
+ ep = &pipe->bottom;
+ memset(ep, 0, sizeof(*ep));
+ ep->tx_info.sh_buf = buf_b;
+ ep->rx_info.sh_buf = buf_a;
+ memset(ep->tx_info.sh_buf, 0, sizeof(struct hab_shared_buf));
+ memset(ep->rx_info.sh_buf, 0, sizeof(struct hab_shared_buf));
+ ep->tx_info.sh_buf->size = shared_buf_size;
+ ep->rx_info.sh_buf->size = shared_buf_size;
+
+ pipe->buf_a = buf_a;
+ pipe->buf_b = buf_b;
+ pipe->total_size =
+ hab_pipe_calc_required_bytes(shared_buf_size);
+ }
+ return ep;
+}
+
+uint32_t hab_pipe_write(struct hab_pipe_endpoint *ep,
+ unsigned char *p, uint32_t num_bytes)
+{
+ struct hab_shared_buf *sh_buf = ep->tx_info.sh_buf;
+ uint32_t space =
+ (sh_buf->size - (ep->tx_info.wr_count - sh_buf->rd_count));
+ uint32_t count1, count2;
+
+ if (!p || num_bytes > space || num_bytes == 0)
+ return 0;
+
+ count1 = (num_bytes <= (sh_buf->size - ep->tx_info.index)) ? num_bytes :
+ (sh_buf->size - ep->tx_info.index);
+ count2 = num_bytes - count1;
+
+ if (count1 > 0) {
+ memcpy(&sh_buf->data[ep->tx_info.index], p, count1);
+ ep->tx_info.wr_count += count1;
+ ep->tx_info.index += count1;
+ if (ep->tx_info.index >= sh_buf->size)
+ ep->tx_info.index = 0;
+ }
+ if (count2 > 0) {/* handle buffer wrapping */
+ memcpy(&sh_buf->data[ep->tx_info.index], p + count1, count2);
+ ep->tx_info.wr_count += count2;
+ ep->tx_info.index += count2;
+ if (ep->tx_info.index >= sh_buf->size)
+ ep->tx_info.index = 0;
+ }
+ return num_bytes;
+}
+
+/* Updates the write index which is shared with the other VM */
+void hab_pipe_write_commit(struct hab_pipe_endpoint *ep)
+{
+ struct hab_shared_buf *sh_buf = ep->tx_info.sh_buf;
+
+ mb(); /* Must commit data before incrementing count */
+ sh_buf->wr_count = ep->tx_info.wr_count;
+}
+
+uint32_t hab_pipe_read(struct hab_pipe_endpoint *ep,
+ unsigned char *p, uint32_t size)
+{
+ struct hab_shared_buf *sh_buf = ep->rx_info.sh_buf;
+ uint32_t avail = sh_buf->wr_count - sh_buf->rd_count;
+ uint32_t count1, count2, to_read;
+
+ if (!p || avail == 0 || size == 0)
+ return 0;
+
+ to_read = (avail < size) ? avail : size;
+ count1 = (to_read <= (sh_buf->size - ep->rx_info.index)) ? to_read :
+ (sh_buf->size - ep->rx_info.index);
+ count2 = to_read - count1;
+
+ if (count1 > 0) {
+ memcpy(p, &sh_buf->data[ep->rx_info.index], count1);
+ ep->rx_info.index += count1;
+ if (ep->rx_info.index >= sh_buf->size)
+ ep->rx_info.index = 0;
+ mb(); /*Must commit data before incremeting count*/
+ sh_buf->rd_count += count1;
+ }
+ if (count2 > 0) { /* handle buffer wrapping */
+ memcpy(p + count1, &sh_buf->data[ep->rx_info.index], count2);
+ ep->rx_info.index += count2;
+ mb(); /*Must commit data before incremeting count*/
+ sh_buf->rd_count += count2;
+ }
+
+ return to_read;
+}
diff --git a/drivers/soc/qcom/hab/hab_pipe.h b/drivers/soc/qcom/hab/hab_pipe.h
new file mode 100644
index 000000000000..6ffdbd133868
--- /dev/null
+++ b/drivers/soc/qcom/hab/hab_pipe.h
@@ -0,0 +1,60 @@
+/* Copyright (c) 2016-2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+#ifndef HAB_PIPE_H
+#define HAB_PIPE_H
+
+struct hab_shared_buf {
+ uint32_t rd_count;
+ uint32_t wr_count;
+ uint32_t size;
+ unsigned char data[];
+};
+
+struct hab_pipe_endpoint {
+ struct {
+ uint32_t wr_count;
+ uint32_t index;
+ struct hab_shared_buf *sh_buf;
+ } tx_info;
+ struct {
+ uint32_t index;
+ struct hab_shared_buf *sh_buf;
+ } rx_info;
+};
+
+struct hab_pipe {
+ struct hab_pipe_endpoint top;
+ struct hab_pipe_endpoint bottom;
+
+ /* For debugging only */
+ struct hab_shared_buf *buf_a; /* top TX, bottom RX */
+ struct hab_shared_buf *buf_b; /* top RX, bottom TX */
+ size_t total_size;
+
+ unsigned char buf_base[];
+};
+
+size_t hab_pipe_calc_required_bytes(uint32_t shared_buf_size);
+
+struct hab_pipe_endpoint *hab_pipe_init(struct hab_pipe *pipe,
+ uint32_t shared_buf_size, int top);
+
+uint32_t hab_pipe_write(struct hab_pipe_endpoint *ep,
+ unsigned char *p, uint32_t num_bytes);
+
+void hab_pipe_write_commit(struct hab_pipe_endpoint *ep);
+
+uint32_t hab_pipe_read(struct hab_pipe_endpoint *ep,
+ unsigned char *p, uint32_t size);
+
+#endif /* HAB_PIPE_H */
diff --git a/drivers/soc/qcom/hab/hab_qvm.c b/drivers/soc/qcom/hab/hab_qvm.c
new file mode 100644
index 000000000000..a37590f23c61
--- /dev/null
+++ b/drivers/soc/qcom/hab/hab_qvm.c
@@ -0,0 +1,251 @@
+/* Copyright (c) 2016-2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+#include "hab.h"
+#include "hab_qvm.h"
+
+#include <linux/highmem.h>
+#include <linux/string.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+
+#include <linux/of.h>
+#include <linux/of_platform.h>
+
+#define DEFAULT_HAB_SHMEM_IRQ 7
+
+#define SHMEM_PHYSICAL_ADDR 0x1c050000
+
+static irqreturn_t shm_irq_handler(int irq, void *_pchan)
+{
+ irqreturn_t rc = IRQ_NONE;
+ struct physical_channel *pchan = _pchan;
+ struct qvm_channel *dev =
+ (struct qvm_channel *) (pchan ? pchan->hyp_data : NULL);
+
+ if (dev && dev->guest_ctrl) {
+ int status = dev->guest_ctrl->status;
+
+ if (status & dev->idx) {
+ rc = IRQ_HANDLED;
+ tasklet_schedule(&dev->task);
+ }
+ }
+ return rc;
+}
+
+static uint64_t get_guest_factory_paddr(struct qvm_channel *dev,
+ const char *name, uint32_t pages)
+{
+ int i;
+
+ dev->guest_factory = ioremap(SHMEM_PHYSICAL_ADDR, PAGE_SIZE);
+
+ if (!dev->guest_factory) {
+ pr_err("Couldn't map guest_factory\n");
+ return 0;
+ }
+
+ if (dev->guest_factory->signature != GUEST_SHM_SIGNATURE) {
+ pr_err("shmem factory signature incorrect: %ld != %lu\n",
+ GUEST_SHM_SIGNATURE, dev->guest_factory->signature);
+ iounmap(dev->guest_factory);
+ return 0;
+ }
+
+ dev->guest_intr = dev->guest_factory->vector;
+
+ /*
+ * Set the name field on the factory page to identify the shared memory
+ * region
+ */
+ for (i = 0; i < strlen(name) && i < GUEST_SHM_MAX_NAME - 1; i++)
+ dev->guest_factory->name[i] = name[i];
+ dev->guest_factory->name[i] = (char) 0;
+
+ guest_shm_create(dev->guest_factory, pages);
+
+ /* See if we successfully created/attached to the region. */
+ if (dev->guest_factory->status != GSS_OK) {
+ pr_err("create failed: %d\n", dev->guest_factory->status);
+ iounmap(dev->guest_factory);
+ return 0;
+ }
+
+ pr_debug("shm creation size %x\n", dev->guest_factory->size);
+
+ return dev->guest_factory->shmem;
+}
+
+static int create_dispatcher(struct physical_channel *pchan, int id)
+{
+ struct qvm_channel *dev = (struct qvm_channel *)pchan->hyp_data;
+ int ret;
+
+ tasklet_init(&dev->task, physical_channel_rx_dispatch,
+ (unsigned long) pchan);
+
+ ret = request_irq(hab_driver.irq, shm_irq_handler, IRQF_SHARED,
+ hab_driver.devp[id].name, pchan);
+
+ if (ret)
+ pr_err("request_irq for %s failed: %d\n",
+ hab_driver.devp[id].name, ret);
+
+ return ret;
+}
+
+static struct physical_channel *habhyp_commdev_alloc(int id)
+{
+ struct qvm_channel *dev;
+ struct physical_channel *pchan = NULL;
+ int ret = 0, channel = 0;
+ char *shmdata;
+ uint32_t pipe_alloc_size =
+ hab_pipe_calc_required_bytes(PIPE_SHMEM_SIZE);
+ uint32_t pipe_alloc_pages =
+ (pipe_alloc_size + PAGE_SIZE - 1) / PAGE_SIZE;
+ uint64_t paddr;
+ int temp;
+ int total_pages;
+ struct page **pages;
+
+ dev = kzalloc(sizeof(*dev), GFP_KERNEL);
+ if (!dev)
+ return ERR_PTR(-ENOMEM);
+
+ spin_lock_init(&dev->io_lock);
+
+ paddr = get_guest_factory_paddr(dev,
+ hab_driver.devp[id].name,
+ pipe_alloc_pages);
+
+ total_pages = dev->guest_factory->size + 1;
+ pages = kmalloc_array(total_pages, sizeof(struct page *), GFP_KERNEL);
+ if (!pages) {
+ ret = -ENOMEM;
+ goto err;
+ }
+
+ for (temp = 0; temp < total_pages; temp++)
+ pages[temp] = pfn_to_page((paddr / PAGE_SIZE) + temp);
+
+ dev->guest_ctrl = vmap(pages, total_pages, VM_MAP, PAGE_KERNEL);
+ if (!dev->guest_ctrl) {
+ ret = -ENOMEM;
+ kfree(pages);
+ goto err;
+ }
+
+ shmdata = (char *)dev->guest_ctrl + PAGE_SIZE;
+ dev->idx = dev->guest_ctrl->idx;
+
+ kfree(pages);
+
+ dev->pipe = (struct hab_pipe *) shmdata;
+ dev->pipe_ep = hab_pipe_init(dev->pipe, PIPE_SHMEM_SIZE,
+ dev->be ? 0 : 1);
+
+ pchan = hab_pchan_alloc(&hab_driver.devp[id], dev->be);
+ if (!pchan) {
+ ret = -ENOMEM;
+ goto err;
+ }
+
+ pchan->closed = 0;
+ pchan->hyp_data = (void *)dev;
+
+ dev->channel = channel;
+
+ ret = create_dispatcher(pchan, id);
+ if (ret < 0)
+ goto err;
+
+ return pchan;
+
+err:
+ kfree(dev);
+
+ if (pchan)
+ hab_pchan_put(pchan);
+ pr_err("habhyp_commdev_alloc failed: %d\n", ret);
+ return ERR_PTR(ret);
+}
+
+int hab_hypervisor_register(void)
+{
+ int ret = 0, i;
+
+ hab_driver.b_server_dom = 0;
+
+ /*
+ * Can still attempt to instantiate more channels if one fails.
+ * Others can be retried later.
+ */
+ for (i = 0; i < hab_driver.ndevices; i++) {
+ if (IS_ERR(habhyp_commdev_alloc(i)))
+ ret = -EAGAIN;
+ }
+
+ return ret;
+}
+
+void hab_hypervisor_unregister(void)
+{
+}
+
+static int hab_shmem_probe(struct platform_device *pdev)
+{
+ int irq = platform_get_irq(pdev, 0);
+
+ if (irq > 0)
+ hab_driver.irq = irq;
+ else
+ hab_driver.irq = DEFAULT_HAB_SHMEM_IRQ;
+
+ return 0;
+}
+
+static int hab_shmem_remove(struct platform_device *pdev)
+{
+ return 0;
+}
+
+static const struct of_device_id hab_shmem_match_table[] = {
+ {.compatible = "qvm,guest_shm"},
+ {},
+};
+
+static struct platform_driver hab_shmem_driver = {
+ .probe = hab_shmem_probe,
+ .remove = hab_shmem_remove,
+ .driver = {
+ .name = "hab_shmem",
+ .of_match_table = of_match_ptr(hab_shmem_match_table),
+ },
+};
+
+static int __init hab_shmem_init(void)
+{
+ return platform_driver_register(&hab_shmem_driver);
+}
+
+static void __exit hab_shmem_exit(void)
+{
+ platform_driver_unregister(&hab_shmem_driver);
+}
+
+core_initcall(hab_shmem_init);
+module_exit(hab_shmem_exit);
+
+MODULE_DESCRIPTION("Hypervisor shared memory driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/soc/qcom/hab/hab_qvm.h b/drivers/soc/qcom/hab/hab_qvm.h
new file mode 100644
index 000000000000..e94b82f87942
--- /dev/null
+++ b/drivers/soc/qcom/hab/hab_qvm.h
@@ -0,0 +1,47 @@
+/* Copyright (c) 2016-2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+#ifndef __HAB_QNX_H
+#define __HAB_QNX_H
+#include "hab.h"
+#include "hab_pipe.h"
+
+#include <guest_shm.h>
+#include <linux/stddef.h>
+
+#define PULSE_CODE_NOTIFY 0
+#define PULSE_CODE_INPUT 1
+
+struct qvm_channel {
+ int be;
+
+ struct hab_pipe *pipe;
+ struct hab_pipe_endpoint *pipe_ep;
+ spinlock_t io_lock;
+ struct tasklet_struct task;
+ struct guest_shm_factory *guest_factory;
+ struct guest_shm_control *guest_ctrl;
+ uint32_t idx;
+
+ int channel;
+ int coid;
+
+ unsigned int guest_intr;
+ unsigned int guest_iid;
+};
+
+/* Shared mem size in each direction for communication pipe */
+#define PIPE_SHMEM_SIZE (128 * 1024)
+
+void *qnx_hyp_rx_dispatch(void *data);
+
+#endif /* __HAB_QNX_H */
diff --git a/drivers/soc/qcom/hab/hab_vchan.c b/drivers/soc/qcom/hab/hab_vchan.c
new file mode 100644
index 000000000000..75a3fad68ab5
--- /dev/null
+++ b/drivers/soc/qcom/hab/hab_vchan.c
@@ -0,0 +1,184 @@
+/* Copyright (c) 2016-2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+#include "hab.h"
+
+struct virtual_channel *
+hab_vchan_alloc(struct uhab_context *ctx, struct physical_channel *pchan)
+{
+ int id;
+ struct virtual_channel *vchan;
+
+ if (!pchan || !ctx)
+ return NULL;
+
+ vchan = kzalloc(sizeof(*vchan), GFP_KERNEL);
+ if (!vchan)
+ return NULL;
+
+ /* This should be the first thing we do in this function */
+ idr_preload(GFP_KERNEL);
+ spin_lock_bh(&pchan->vid_lock);
+ id = idr_alloc(&pchan->vchan_idr, vchan, 1, 256, GFP_NOWAIT);
+ spin_unlock_bh(&pchan->vid_lock);
+ idr_preload_end();
+
+ if (id < 0) {
+ kfree(vchan);
+ return NULL;
+ }
+ mb(); /* id must be generated done before pchan_get */
+
+ hab_pchan_get(pchan);
+ vchan->pchan = pchan;
+ vchan->id = ((id << HAB_VCID_ID_SHIFT) & HAB_VCID_ID_MASK) |
+ ((pchan->habdev->id << HAB_VCID_MMID_SHIFT) &
+ HAB_VCID_MMID_MASK) |
+ ((pchan->dom_id << HAB_VCID_DOMID_SHIFT) &
+ HAB_VCID_DOMID_MASK);
+ spin_lock_init(&vchan->rx_lock);
+ INIT_LIST_HEAD(&vchan->rx_list);
+ init_waitqueue_head(&vchan->rx_queue);
+
+ kref_init(&vchan->refcount);
+ kref_init(&vchan->usagecnt);
+ vchan->otherend_closed = pchan->closed;
+
+ hab_ctx_get(ctx);
+ vchan->ctx = ctx;
+
+ return vchan;
+}
+
+static void
+hab_vchan_free(struct kref *ref)
+{
+ int found;
+ struct virtual_channel *vchan =
+ container_of(ref, struct virtual_channel, refcount);
+ struct hab_message *message, *msg_tmp;
+ struct export_desc *exp;
+ struct physical_channel *pchan = vchan->pchan;
+ struct uhab_context *ctx = vchan->ctx;
+
+ list_for_each_entry_safe(message, msg_tmp, &vchan->rx_list, node) {
+ list_del(&message->node);
+ hab_msg_free(message);
+ }
+
+ do {
+ found = 0;
+ write_lock(&ctx->exp_lock);
+ list_for_each_entry(exp, &ctx->exp_whse, node) {
+ if (exp->vcid_local == vchan->id) {
+ list_del(&exp->node);
+ found = 1;
+ break;
+ }
+ }
+ write_unlock(&ctx->exp_lock);
+ if (found) {
+ habmem_hyp_revoke(exp->payload, exp->payload_count);
+ habmem_remove_export(exp);
+ }
+ } while (found);
+
+ do {
+ found = 0;
+ spin_lock_bh(&ctx->imp_lock);
+ list_for_each_entry(exp, &ctx->imp_whse, node) {
+ if (exp->vcid_remote == vchan->id) {
+ list_del(&exp->node);
+ found = 1;
+ break;
+ }
+ }
+ spin_unlock_bh(&ctx->imp_lock);
+ if (found) {
+ habmm_imp_hyp_unmap(ctx->import_ctx,
+ exp->import_index,
+ exp->payload_count,
+ ctx->kernel);
+ ctx->import_total--;
+ kfree(exp);
+ }
+ } while (found);
+
+ spin_lock_bh(&pchan->vid_lock);
+ idr_remove(&pchan->vchan_idr, HAB_VCID_GET_ID(vchan->id));
+ spin_unlock_bh(&pchan->vid_lock);
+
+ hab_pchan_put(pchan);
+ hab_ctx_put(ctx);
+
+ kfree(vchan);
+}
+
+struct virtual_channel*
+hab_vchan_get(struct physical_channel *pchan, uint32_t vchan_id)
+{
+ struct virtual_channel *vchan;
+
+ spin_lock_bh(&pchan->vid_lock);
+ vchan = idr_find(&pchan->vchan_idr, HAB_VCID_GET_ID(vchan_id));
+ if (vchan)
+ if (!kref_get_unless_zero(&vchan->refcount))
+ vchan = NULL;
+ spin_unlock_bh(&pchan->vid_lock);
+
+ return vchan;
+}
+
+void hab_vchan_stop(struct virtual_channel *vchan)
+{
+ if (vchan) {
+ vchan->otherend_closed = 1;
+ wake_up_interruptible(&vchan->rx_queue);
+ }
+}
+
+void hab_vchan_stop_notify(struct virtual_channel *vchan)
+{
+ hab_send_close_msg(vchan);
+ hab_vchan_stop(vchan);
+}
+
+
+int hab_vchan_find_domid(struct virtual_channel *vchan)
+{
+ return vchan ? vchan->pchan->dom_id : -1;
+}
+
+static void
+hab_vchan_free_deferred(struct work_struct *work)
+{
+ struct virtual_channel *vchan =
+ container_of(work, struct virtual_channel, work);
+
+ hab_vchan_free(&vchan->refcount);
+}
+
+static void
+hab_vchan_schedule_free(struct kref *ref)
+{
+ struct virtual_channel *vchan =
+ container_of(ref, struct virtual_channel, refcount);
+
+ INIT_WORK(&vchan->work, hab_vchan_free_deferred);
+ schedule_work(&vchan->work);
+}
+
+void hab_vchan_put(struct virtual_channel *vchan)
+{
+ if (vchan)
+ kref_put(&vchan->refcount, hab_vchan_schedule_free);
+}
diff --git a/drivers/soc/qcom/hab/khab.c b/drivers/soc/qcom/hab/khab.c
new file mode 100644
index 000000000000..f7499773ae42
--- /dev/null
+++ b/drivers/soc/qcom/hab/khab.c
@@ -0,0 +1,140 @@
+/* Copyright (c) 2016-2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+#include <linux/module.h>
+#include "hab.h"
+
+int32_t habmm_socket_open(int32_t *handle, uint32_t mm_ip_id,
+ uint32_t timeout, uint32_t flags)
+{
+ return hab_vchan_open(hab_driver.kctx, mm_ip_id, handle, flags);
+}
+EXPORT_SYMBOL(habmm_socket_open);
+
+int32_t habmm_socket_close(int32_t handle)
+{
+ hab_vchan_close(hab_driver.kctx, handle);
+ return 0;
+}
+EXPORT_SYMBOL(habmm_socket_close);
+
+int32_t habmm_socket_send(int32_t handle, void *src_buff,
+ uint32_t size_bytes, uint32_t flags)
+{
+ struct hab_send param = {0};
+
+ param.vcid = handle;
+ param.data = (uint64_t)(uintptr_t)src_buff;
+ param.sizebytes = size_bytes;
+ param.flags = flags;
+
+ return hab_vchan_send(hab_driver.kctx, handle,
+ size_bytes, src_buff, flags);
+}
+EXPORT_SYMBOL(habmm_socket_send);
+
+int32_t habmm_socket_recv(int32_t handle, void *dst_buff, uint32_t *size_bytes,
+ uint32_t timeout, uint32_t flags)
+{
+ int ret = 0;
+ struct hab_message *msg;
+
+ if (!size_bytes || !dst_buff)
+ return -EINVAL;
+
+ msg = hab_vchan_recv(hab_driver.kctx, handle, flags);
+
+ if (IS_ERR(msg)) {
+ *size_bytes = 0;
+ return PTR_ERR(msg);
+ }
+
+ if (*size_bytes < msg->sizebytes) {
+ *size_bytes = 0;
+ ret = -EINVAL;
+ } else {
+ memcpy(dst_buff, msg->data, msg->sizebytes);
+ *size_bytes = msg->sizebytes;
+ }
+
+ hab_msg_free(msg);
+ return ret;
+}
+EXPORT_SYMBOL(habmm_socket_recv);
+
+int32_t habmm_export(int32_t handle, void *buff_to_share, uint32_t size_bytes,
+ uint32_t *export_id, uint32_t flags)
+{
+ int ret;
+ struct hab_export param = {0};
+
+ if (!export_id)
+ return -EINVAL;
+
+ param.vcid = handle;
+ param.buffer = (uint64_t)(uintptr_t)buff_to_share;
+ param.sizebytes = size_bytes;
+
+ ret = hab_mem_export(hab_driver.kctx, &param, 1);
+
+ *export_id = param.exportid;
+ return ret;
+}
+EXPORT_SYMBOL(habmm_export);
+
+int32_t habmm_unexport(int32_t handle, uint32_t export_id, uint32_t flags)
+{
+ struct hab_unexport param = {0};
+
+ param.vcid = handle;
+ param.exportid = export_id;
+
+ return hab_mem_unexport(hab_driver.kctx, &param, 1);
+}
+EXPORT_SYMBOL(habmm_unexport);
+
+int32_t habmm_import(int32_t handle, void **buff_shared, uint32_t size_bytes,
+ uint32_t export_id, uint32_t flags)
+{
+ int ret;
+ struct hab_import param = {0};
+
+ if (!buff_shared)
+ return -EINVAL;
+
+ param.vcid = handle;
+ param.sizebytes = size_bytes;
+ param.exportid = export_id;
+ param.flags = flags;
+
+ ret = hab_mem_import(hab_driver.kctx, &param, 1);
+ if (!IS_ERR(ret))
+ *buff_shared = (void *)(uintptr_t)param.kva;
+
+ return ret;
+}
+EXPORT_SYMBOL(habmm_import);
+
+int32_t habmm_unimport(int32_t handle,
+ uint32_t export_id,
+ void *buff_shared,
+ uint32_t flags)
+{
+ struct hab_unimport param = {0};
+
+ param.vcid = handle;
+ param.exportid = export_id;
+ param.kva = (uint64_t)(uintptr_t)buff_shared;
+
+ return hab_mem_unimport(hab_driver.kctx, &param, 1);
+}
+EXPORT_SYMBOL(habmm_unimport);
diff --git a/drivers/soc/qcom/hab/qvm_comm.c b/drivers/soc/qcom/hab/qvm_comm.c
new file mode 100644
index 000000000000..20a631e13794
--- /dev/null
+++ b/drivers/soc/qcom/hab/qvm_comm.c
@@ -0,0 +1,95 @@
+/* Copyright (c) 2016-2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+#include "hab.h"
+#include "hab_qvm.h"
+
+static inline void habhyp_notify(void *commdev)
+{
+ struct qvm_channel *dev = (struct qvm_channel *)commdev;
+
+ if (dev && dev->guest_ctrl)
+ dev->guest_ctrl->notify = ~0;
+}
+
+int physical_channel_read(struct physical_channel *pchan,
+ void *payload,
+ size_t read_size)
+{
+ struct qvm_channel *dev = (struct qvm_channel *)pchan->hyp_data;
+
+ if (dev)
+ return hab_pipe_read(dev->pipe_ep, payload, read_size);
+ else
+ return 0;
+}
+
+int physical_channel_send(struct physical_channel *pchan,
+ struct hab_header *header,
+ void *payload)
+{
+ int sizebytes = HAB_HEADER_GET_SIZE(*header);
+ struct qvm_channel *dev = (struct qvm_channel *)pchan->hyp_data;
+ int total_size = sizeof(*header) + sizebytes;
+
+ if (total_size > dev->pipe_ep->tx_info.sh_buf->size)
+ return -EINVAL; /* too much data for ring */
+
+ spin_lock_bh(&dev->io_lock);
+
+ if ((dev->pipe_ep->tx_info.sh_buf->size -
+ (dev->pipe_ep->tx_info.wr_count -
+ dev->pipe_ep->tx_info.sh_buf->rd_count)) < total_size) {
+ spin_unlock_bh(&dev->io_lock);
+ return -EAGAIN; /* not enough free space */
+ }
+
+ if (hab_pipe_write(dev->pipe_ep,
+ (unsigned char *)header,
+ sizeof(*header)) != sizeof(*header)) {
+ spin_unlock_bh(&dev->io_lock);
+ return -EIO;
+ }
+
+ if (sizebytes) {
+ if (hab_pipe_write(dev->pipe_ep,
+ (unsigned char *)payload,
+ sizebytes) != sizebytes) {
+ spin_unlock_bh(&dev->io_lock);
+ return -EIO;
+ }
+ }
+
+ hab_pipe_write_commit(dev->pipe_ep);
+ spin_unlock_bh(&dev->io_lock);
+ habhyp_notify(dev);
+
+ return 0;
+}
+
+void physical_channel_rx_dispatch(unsigned long data)
+{
+ struct hab_header header;
+ struct physical_channel *pchan = (struct physical_channel *)data;
+ struct qvm_channel *dev = (struct qvm_channel *)pchan->hyp_data;
+
+ spin_lock_bh(&pchan->rxbuf_lock);
+ while (1) {
+ if (hab_pipe_read(dev->pipe_ep,
+ (unsigned char *)&header,
+ sizeof(header)) != sizeof(header))
+ break; /* no data available */
+
+ hab_msg_recv(pchan, &header);
+ }
+ spin_unlock_bh(&pchan->rxbuf_lock);
+}
diff --git a/drivers/soc/qcom/icnss.c b/drivers/soc/qcom/icnss.c
index 7f2e4cc42e51..2326487302fd 100644
--- a/drivers/soc/qcom/icnss.c
+++ b/drivers/soc/qcom/icnss.c
@@ -294,6 +294,7 @@ enum icnss_driver_state {
ICNSS_WLFW_EXISTS,
ICNSS_SHUTDOWN_DONE,
ICNSS_HOST_TRIGGERED_PDR,
+ ICNSS_FW_DOWN,
};
struct ce_irq_list {
@@ -504,10 +505,10 @@ static int icnss_assign_msa_perm(struct icnss_mem_region_info
phys_addr_t addr;
u32 size;
u32 i = 0;
- u32 source_vmids[ICNSS_MAX_VMIDS];
+ u32 source_vmids[ICNSS_MAX_VMIDS] = {0};
u32 source_nelems;
- u32 dest_vmids[ICNSS_MAX_VMIDS];
- u32 dest_perms[ICNSS_MAX_VMIDS];
+ u32 dest_vmids[ICNSS_MAX_VMIDS] = {0};
+ u32 dest_perms[ICNSS_MAX_VMIDS] = {0};
u32 dest_nelems;
enum icnss_msa_perm cur_perm = mem_region->perm;
struct icnss_msa_perm_list_t *new_perm_list, *old_perm_list;
@@ -1950,6 +1951,12 @@ static void icnss_qmi_wlfw_clnt_ind(struct qmi_handle *handle,
icnss_pr_dbg("Received Ind 0x%x, msg_len: %d\n", msg_id, msg_len);
+ if (test_bit(ICNSS_FW_DOWN, &penv->state)) {
+ icnss_pr_dbg("FW down, ignoring 0x%x, state: 0x%lx\n",
+ msg_id, penv->state);
+ return;
+ }
+
switch (msg_id) {
case QMI_WLFW_FW_READY_IND_V01:
icnss_driver_event_post(ICNSS_DRIVER_EVENT_FW_READY_IND,
@@ -1996,6 +2003,7 @@ static int icnss_driver_event_server_arrive(void *data)
return -ENODEV;
set_bit(ICNSS_WLFW_EXISTS, &penv->state);
+ clear_bit(ICNSS_FW_DOWN, &penv->state);
penv->wlfw_clnt = qmi_handle_create(icnss_qmi_wlfw_clnt_notify, penv);
if (!penv->wlfw_clnt) {
@@ -2496,6 +2504,8 @@ static int icnss_modem_notifier_nb(struct notifier_block *nb,
icnss_pr_info("Modem went down, state: 0x%lx, crashed: %d\n",
priv->state, notif->crashed);
+ set_bit(ICNSS_FW_DOWN, &priv->state);
+
if (notif->crashed)
priv->stats.recovery.root_pd_crash++;
else
@@ -2623,6 +2633,7 @@ static int icnss_service_notifier_notify(struct notifier_block *nb,
icnss_pr_info("PD service down, pd_state: %d, state: 0x%lx: cause: %s\n",
*state, priv->state, icnss_pdr_cause[cause]);
event_post:
+ set_bit(ICNSS_FW_DOWN, &priv->state);
icnss_ignore_qmi_timeout(true);
clear_bit(ICNSS_HOST_TRIGGERED_PDR, &priv->state);
@@ -2631,6 +2642,8 @@ event_post:
icnss_driver_event_post(ICNSS_DRIVER_EVENT_PD_SERVICE_DOWN,
ICNSS_EVENT_SYNC, event_data);
done:
+ if (notification == SERVREG_NOTIF_SERVICE_STATE_UP_V01)
+ clear_bit(ICNSS_FW_DOWN, &priv->state);
return NOTIFY_OK;
}
@@ -3824,6 +3837,9 @@ static int icnss_stats_show_state(struct seq_file *s, struct icnss_priv *priv)
case ICNSS_HOST_TRIGGERED_PDR:
seq_puts(s, "HOST TRIGGERED PDR");
continue;
+ case ICNSS_FW_DOWN:
+ seq_puts(s, "FW DOWN");
+ continue;
}
seq_printf(s, "UNKNOWN-%d", i);
diff --git a/drivers/soc/qcom/ipc_router_glink_xprt.c b/drivers/soc/qcom/ipc_router_glink_xprt.c
index 7dd1683881fb..0c588c586306 100644
--- a/drivers/soc/qcom/ipc_router_glink_xprt.c
+++ b/drivers/soc/qcom/ipc_router_glink_xprt.c
@@ -82,6 +82,7 @@ struct ipc_router_glink_xprt {
struct msm_ipc_router_xprt xprt;
void *ch_hndl;
struct workqueue_struct *xprt_wq;
+ struct wakeup_source notify_rxv_ws;
struct rw_semaphore ss_reset_rwlock;
int ss_reset;
void *pil;
@@ -377,6 +378,7 @@ out_read_data:
glink_rx_done(glink_xprtp->ch_hndl, rx_work->iovec, reuse_intent);
kfree(rx_work);
up_read(&glink_xprtp->ss_reset_rwlock);
+ __pm_relax(&glink_xprtp->notify_rxv_ws);
}
static void glink_xprt_open_event(struct work_struct *work)
@@ -491,6 +493,8 @@ static void glink_xprt_notify_rxv(void *handle, const void *priv,
rx_work->iovec_size = size;
rx_work->vbuf_provider = vbuf_provider;
rx_work->pbuf_provider = pbuf_provider;
+ if (!glink_xprtp->dynamic_wakeup_source)
+ __pm_stay_awake(&glink_xprtp->notify_rxv_ws);
INIT_WORK(&rx_work->work, glink_xprt_read_data);
queue_work(glink_xprtp->xprt_wq, &rx_work->work);
}
@@ -760,6 +764,7 @@ static int ipc_router_glink_config_init(
return -EFAULT;
}
+ wakeup_source_init(&glink_xprtp->notify_rxv_ws, xprt_wq_name);
mutex_lock(&glink_xprt_list_lock_lha1);
list_add(&glink_xprtp->list, &glink_xprt_list);
mutex_unlock(&glink_xprt_list_lock_lha1);
diff --git a/drivers/soc/qcom/peripheral-loader.c b/drivers/soc/qcom/peripheral-loader.c
index ace2bc4f30b6..d77a12626330 100644
--- a/drivers/soc/qcom/peripheral-loader.c
+++ b/drivers/soc/qcom/peripheral-loader.c
@@ -56,7 +56,9 @@
#endif
#define PIL_NUM_DESC 10
+#define NUM_OF_ENCRYPTED_KEY 3
static void __iomem *pil_info_base;
+static void __iomem *pil_minidump_base;
/**
* proxy_timeout - Override for proxy vote timeouts
@@ -80,6 +82,18 @@ struct pil_mdt {
};
/**
+ * struct boot_minidump_smem_region - Representation of SMEM TOC
+ * @region_name: Name of modem segment to be dumped
+ * @region_base_address: Where segment start from
+ * @region_size: Size of segment to be dumped
+ */
+struct boot_minidump_smem_region {
+ char region_name[16];
+ u64 region_base_address;
+ u64 region_size;
+};
+
+/**
* struct pil_seg - memory map representing one segment
* @next: points to next seg mentor NULL if last segment
* @paddr: physical start address of segment
@@ -133,11 +147,67 @@ struct pil_priv {
phys_addr_t region_end;
void *region;
struct pil_image_info __iomem *info;
+ struct md_ssr_ss_info __iomem *minidump;
+ int minidump_id;
int id;
int unvoted_flag;
size_t region_size;
};
+static int pil_do_minidump(struct pil_desc *desc, void *ramdump_dev)
+{
+ struct boot_minidump_smem_region __iomem *region_info;
+ struct ramdump_segment *ramdump_segs, *s;
+ struct pil_priv *priv = desc->priv;
+ void __iomem *subsys_smem_base;
+ void __iomem *offset;
+ int ss_mdump_seg_cnt;
+ int ret, i;
+
+ memcpy(&offset, &priv->minidump, sizeof(priv->minidump));
+ offset = offset + sizeof(priv->minidump->md_ss_smem_regions_baseptr);
+ /* There are 3 encryption keys which also need to be dumped */
+ ss_mdump_seg_cnt = readb_relaxed(offset) +
+ NUM_OF_ENCRYPTED_KEY;
+
+ subsys_smem_base = ioremap(__raw_readl(priv->minidump),
+ ss_mdump_seg_cnt * sizeof(*region_info));
+ region_info =
+ (struct boot_minidump_smem_region __iomem *)subsys_smem_base;
+ ramdump_segs = kcalloc(ss_mdump_seg_cnt,
+ sizeof(*ramdump_segs), GFP_KERNEL);
+ if (!ramdump_segs)
+ return -ENOMEM;
+
+ if (desc->subsys_vmid > 0)
+ ret = pil_assign_mem_to_linux(desc, priv->region_start,
+ (priv->region_end - priv->region_start));
+
+ s = ramdump_segs;
+ for (i = 0; i < ss_mdump_seg_cnt; i++) {
+ memcpy(&offset, &region_info, sizeof(region_info));
+ memcpy(&s->name, &region_info, sizeof(region_info));
+ offset = offset + sizeof(region_info->region_name);
+ s->address = __raw_readl(offset);
+ offset = offset + sizeof(region_info->region_base_address);
+ s->size = __raw_readl(offset);
+ s++;
+ region_info++;
+ }
+ ret = do_minidump(ramdump_dev, ramdump_segs, ss_mdump_seg_cnt);
+ kfree(ramdump_segs);
+ if (ret)
+ pil_err(desc, "%s: Ramdump collection failed for subsys %s rc:%d\n",
+ __func__, desc->name, ret);
+ writel_relaxed(0, &priv->minidump->md_ss_smem_regions_baseptr);
+ writeb_relaxed(1, &priv->minidump->md_ss_ssr_cause);
+
+ if (desc->subsys_vmid > 0)
+ ret = pil_assign_mem_to_subsys(desc, priv->region_start,
+ (priv->region_end - priv->region_start));
+ return ret;
+}
+
/**
* pil_do_ramdump() - Ramdump an image
* @desc: descriptor from pil_desc_init()
@@ -153,6 +223,9 @@ int pil_do_ramdump(struct pil_desc *desc, void *ramdump_dev)
int count = 0, ret;
struct ramdump_segment *ramdump_segs, *s;
+ if (priv->minidump && (__raw_readl(priv->minidump) > 0))
+ return pil_do_minidump(desc, ramdump_dev);
+
list_for_each_entry(seg, &priv->segs, list)
count++;
@@ -1014,9 +1087,10 @@ bool is_timeout_disabled(void)
int pil_desc_init(struct pil_desc *desc)
{
struct pil_priv *priv;
- int ret;
void __iomem *addr;
+ int ret, ss_imem_offset_mdump;
char buf[sizeof(priv->info->name)];
+ struct device_node *ofnode = desc->dev->of_node;
if (WARN(desc->ops->proxy_unvote && !desc->ops->proxy_vote,
"Invalid proxy voting. Ignoring\n"))
@@ -1039,6 +1113,22 @@ int pil_desc_init(struct pil_desc *desc)
strncpy(buf, desc->name, sizeof(buf));
__iowrite32_copy(priv->info->name, buf, sizeof(buf) / 4);
}
+ if (of_property_read_u32(ofnode, "qcom,minidump-id",
+ &priv->minidump_id))
+ pr_debug("minidump-id not found for %s\n", desc->name);
+ else {
+ ss_imem_offset_mdump =
+ sizeof(struct md_ssr_ss_info) * priv->minidump_id;
+ if (pil_minidump_base) {
+ /* Add 0x4 to get start of struct md_ssr_ss_info base
+ * from struct md_ssr_toc for any subsystem,
+ * struct md_ssr_ss_info is actually the pointer
+ * of ToC in smem for any subsystem.
+ */
+ addr = pil_minidump_base + ss_imem_offset_mdump + 0x4;
+ priv->minidump = (struct md_ssr_ss_info __iomem *)addr;
+ }
+ }
ret = pil_parse_devicetree(desc);
if (ret)
@@ -1148,6 +1238,20 @@ static int __init msm_pil_init(void)
for (i = 0; i < resource_size(&res)/sizeof(u32); i++)
writel_relaxed(0, pil_info_base + (i * sizeof(u32)));
+ np = of_find_compatible_node(NULL, NULL, "qcom,msm-imem-minidump");
+ if (!np) {
+ pr_warn("pil: failed to find qcom,msm-imem-minidump node\n");
+ goto out;
+ } else {
+ pil_minidump_base = of_iomap(np, 0);
+ if (!pil_minidump_base) {
+ pr_err("unable to map pil minidump imem offset\n");
+ goto out;
+ }
+ }
+ for (i = 0; i < sizeof(struct md_ssr_toc)/sizeof(u32); i++)
+ writel_relaxed(0, pil_minidump_base + (i * sizeof(u32)));
+ writel_relaxed(1, pil_minidump_base);
out:
return register_pm_notifier(&pil_pm_notifier);
}
@@ -1158,6 +1262,8 @@ static void __exit msm_pil_exit(void)
unregister_pm_notifier(&pil_pm_notifier);
if (pil_info_base)
iounmap(pil_info_base);
+ if (pil_minidump_base)
+ iounmap(pil_minidump_base);
}
module_exit(msm_pil_exit);
diff --git a/drivers/soc/qcom/peripheral-loader.h b/drivers/soc/qcom/peripheral-loader.h
index 0cd2aeae1edd..908ab78124f7 100644
--- a/drivers/soc/qcom/peripheral-loader.h
+++ b/drivers/soc/qcom/peripheral-loader.h
@@ -74,6 +74,34 @@ struct pil_image_info {
__le32 size;
} __attribute__((__packed__));
+#define MAX_NUM_OF_SS 3
+
+/**
+ * struct md_ssr_ss_info - Info in imem about smem ToC
+ * @md_ss_smem_regions_baseptr: Start physical address of SMEM TOC
+ * @md_ss_num_of_regions: number of segments that need to be dumped
+ * @md_ss_encryption_status: status of encryption of segments
+ * @md_ss_ssr_cause: ssr cause enum
+ */
+struct md_ssr_ss_info {
+ u32 md_ss_smem_regions_baseptr;
+ u8 md_ss_num_of_regions;
+ u8 md_ss_encryption_status;
+ u8 md_ss_ssr_cause;
+ u8 reserved;
+};
+
+/**
+ * struct md_ssr_toc - Wrapper of struct md_ssr_ss_info
+ * @md_ssr_toc_init: flag to indicate to MSS SW about imem init done
+ * @md_ssr_ss: Instance of struct md_ssr_ss_info for a subsystem
+ */
+struct md_ssr_toc /* Shared IMEM ToC struct */
+{
+ u32 md_ssr_toc_init;
+ struct md_ssr_ss_info md_ssr_ss[MAX_NUM_OF_SS];
+};
+
/**
* struct pil_reset_ops - PIL operations
* @init_image: prepare an image for authentication
diff --git a/drivers/soc/qcom/pil-msa.c b/drivers/soc/qcom/pil-msa.c
index 5fcb0f95733c..4bea034f0bdd 100644
--- a/drivers/soc/qcom/pil-msa.c
+++ b/drivers/soc/qcom/pil-msa.c
@@ -78,7 +78,8 @@
#define MSS_MAGIC 0XAABADEAD
/* CX_IPEAK Parameters */
#define CX_IPEAK_MSS BIT(5)
-
+/* Timeout value for MBA boot when minidump is enabled */
+#define MBA_ENCRYPTION_TIMEOUT 3000
enum scm_cmd {
PAS_MEM_SETUP_CMD = 2,
};
@@ -244,7 +245,12 @@ static int pil_msa_wait_for_mba_ready(struct q6v5_data *drv)
struct device *dev = drv->desc.dev;
int ret;
u32 status;
- u64 val = is_timeout_disabled() ? 0 : pbl_mba_boot_timeout_ms * 1000;
+ u64 val;
+
+ if (of_property_read_bool(dev->of_node, "qcom,minidump-id"))
+ pbl_mba_boot_timeout_ms = MBA_ENCRYPTION_TIMEOUT;
+
+ val = is_timeout_disabled() ? 0 : pbl_mba_boot_timeout_ms * 1000;
/* Wait for PBL completion. */
ret = readl_poll_timeout(drv->rmb_base + RMB_PBL_STATUS, status,
diff --git a/drivers/soc/qcom/qdsp6v2/apr.c b/drivers/soc/qcom/qdsp6v2/apr.c
index eca992ec17e4..3791169ec0ac 100644
--- a/drivers/soc/qcom/qdsp6v2/apr.c
+++ b/drivers/soc/qcom/qdsp6v2/apr.c
@@ -820,6 +820,7 @@ static void dispatch_event(unsigned long code, uint16_t proc)
uint16_t clnt;
int i, j;
+ memset(&data, 0, sizeof(data));
data.opcode = RESET_EVENTS;
data.reset_event = code;
diff --git a/drivers/soc/qcom/qdsp6v2/msm_audio_ion.c b/drivers/soc/qcom/qdsp6v2/msm_audio_ion.c
index b119c7a8441d..9e61ff1ebfcc 100644
--- a/drivers/soc/qcom/qdsp6v2/msm_audio_ion.c
+++ b/drivers/soc/qcom/qdsp6v2/msm_audio_ion.c
@@ -210,11 +210,44 @@ done:
return ret;
}
-int msm_audio_ion_phys_assign(const char *name, int fd, ion_phys_addr_t *paddr,
+int msm_audio_ion_phys_free(struct ion_client *client,
+ struct ion_handle *handle,
+ ion_phys_addr_t *paddr,
+ size_t *pa_len, u8 assign_type)
+{
+ int ret;
+
+ if (!(msm_audio_ion_data.device_status & MSM_AUDIO_ION_PROBED)) {
+ pr_debug("%s:probe is not done, deferred\n", __func__);
+ return -EPROBE_DEFER;
+ }
+
+ if (!client || !handle || !paddr || !pa_len) {
+ pr_err("%s: Invalid params\n", __func__);
+ return -EINVAL;
+ }
+
+ ret = ion_phys(client, handle, paddr, pa_len);
+ if (ret) {
+ pr_err("%s: could not get physical address for handle, ret = %d\n",
+ __func__, ret);
+ goto err_ion_handle;
+ }
+
+ ret = msm_audio_hyp_assign(paddr, pa_len, assign_type);
+
+err_ion_handle:
+ ion_free(client, handle);
+ ion_client_destroy(client);
+
+ return ret;
+}
+
+int msm_audio_ion_phys_assign(const char *name, struct ion_client **client,
+ struct ion_handle **handle, int fd,
+ ion_phys_addr_t *paddr,
size_t *pa_len, u8 assign_type)
{
- struct ion_client *client;
- struct ion_handle *handle;
int ret;
if (!(msm_audio_ion_data.device_status & MSM_AUDIO_ION_PROBED)) {
@@ -222,40 +255,43 @@ int msm_audio_ion_phys_assign(const char *name, int fd, ion_phys_addr_t *paddr,
return -EPROBE_DEFER;
}
- if (!name || !paddr || !pa_len) {
+ if (!name || !client || !handle || !paddr || !pa_len) {
pr_err("%s: Invalid params\n", __func__);
return -EINVAL;
}
- client = msm_audio_ion_client_create(name);
- if (IS_ERR_OR_NULL((void *)(client))) {
+ *client = msm_audio_ion_client_create(name);
+ if (IS_ERR_OR_NULL((void *)(*client))) {
pr_err("%s: ION create client failed\n", __func__);
return -EINVAL;
}
- handle = ion_import_dma_buf(client, fd);
- if (IS_ERR_OR_NULL((void *) (handle))) {
+ *handle = ion_import_dma_buf(*client, fd);
+ if (IS_ERR_OR_NULL((void *) (*handle))) {
pr_err("%s: ion import dma buffer failed\n",
__func__);
ret = -EINVAL;
goto err_destroy_client;
}
- ret = ion_phys(client, handle, paddr, pa_len);
+ ret = ion_phys(*client, *handle, paddr, pa_len);
if (ret) {
pr_err("%s: could not get physical address for handle, ret = %d\n",
__func__, ret);
goto err_ion_handle;
}
- pr_debug("%s: ION Physical address is %x\n", __func__, (u32)*paddr);
ret = msm_audio_hyp_assign(paddr, pa_len, assign_type);
+ return ret;
+
err_ion_handle:
- ion_free(client, handle);
+ ion_free(*client, *handle);
err_destroy_client:
- ion_client_destroy(client);
+ ion_client_destroy(*client);
+ *client = NULL;
+ *handle = NULL;
return ret;
}
diff --git a/drivers/soc/qcom/ramdump.c b/drivers/soc/qcom/ramdump.c
index c712ed392b0b..c8353dc8a43a 100644
--- a/drivers/soc/qcom/ramdump.c
+++ b/drivers/soc/qcom/ramdump.c
@@ -29,6 +29,8 @@
#include <linux/of.h>
#define RAMDUMP_WAIT_MSECS 120000
+#define MAX_STRTBL_SIZE 512
+#define MAX_NAME_LENGTH 16
struct ramdump_device {
char name[256];
@@ -391,12 +393,143 @@ static int _do_ramdump(void *handle, struct ramdump_segment *segments,
}
+static inline struct elf_shdr *elf_sheader(struct elfhdr *hdr)
+{
+ return (struct elf_shdr *)((size_t)hdr + (size_t)hdr->e_shoff);
+}
+
+static inline struct elf_shdr *elf_section(struct elfhdr *hdr, int idx)
+{
+ return &elf_sheader(hdr)[idx];
+}
+
+static inline char *elf_str_table(struct elfhdr *hdr)
+{
+ if (hdr->e_shstrndx == SHN_UNDEF)
+ return NULL;
+ return (char *)hdr + elf_section(hdr, hdr->e_shstrndx)->sh_offset;
+}
+
+static inline unsigned int set_section_name(const char *name,
+ struct elfhdr *ehdr)
+{
+ char *strtab = elf_str_table(ehdr);
+ static int strtable_idx = 1;
+ int idx, ret = 0;
+
+ idx = strtable_idx;
+ if ((strtab == NULL) || (name == NULL))
+ return 0;
+
+ ret = idx;
+ idx += strlcpy((strtab + idx), name, MAX_NAME_LENGTH);
+ strtable_idx = idx + 1;
+
+ return ret;
+}
+
+static int _do_minidump(void *handle, struct ramdump_segment *segments,
+ int nsegments)
+{
+ int ret, i;
+ struct ramdump_device *rd_dev = (struct ramdump_device *)handle;
+ struct elfhdr *ehdr;
+ struct elf_shdr *shdr;
+ unsigned long offset, strtbl_off;
+
+ if (!rd_dev->consumer_present) {
+ pr_err("Ramdump(%s): No consumers. Aborting..\n", rd_dev->name);
+ return -EPIPE;
+ }
+
+ rd_dev->segments = segments;
+ rd_dev->nsegments = nsegments;
+
+ rd_dev->elfcore_size = sizeof(*ehdr) +
+ (sizeof(*shdr) * (nsegments + 2)) + MAX_STRTBL_SIZE;
+ ehdr = kzalloc(rd_dev->elfcore_size, GFP_KERNEL);
+ rd_dev->elfcore_buf = (char *)ehdr;
+ if (!rd_dev->elfcore_buf)
+ return -ENOMEM;
+
+ memcpy(ehdr->e_ident, ELFMAG, SELFMAG);
+ ehdr->e_ident[EI_CLASS] = ELF_CLASS;
+ ehdr->e_ident[EI_DATA] = ELF_DATA;
+ ehdr->e_ident[EI_VERSION] = EV_CURRENT;
+ ehdr->e_ident[EI_OSABI] = ELF_OSABI;
+ ehdr->e_type = ET_CORE;
+ ehdr->e_machine = ELF_ARCH;
+ ehdr->e_version = EV_CURRENT;
+ ehdr->e_ehsize = sizeof(*ehdr);
+ ehdr->e_shoff = sizeof(*ehdr);
+ ehdr->e_shentsize = sizeof(*shdr);
+ ehdr->e_shstrndx = 1;
+
+
+ offset = rd_dev->elfcore_size;
+ shdr = (struct elf_shdr *)(ehdr + 1);
+ strtbl_off = sizeof(*ehdr) + sizeof(*shdr) * (nsegments + 2);
+ shdr++;
+ shdr->sh_type = SHT_STRTAB;
+ shdr->sh_offset = (elf_addr_t)strtbl_off;
+ shdr->sh_size = MAX_STRTBL_SIZE;
+ shdr->sh_entsize = 0;
+ shdr->sh_flags = 0;
+ shdr->sh_name = set_section_name("STR_TBL", ehdr);
+ shdr++;
+
+ for (i = 0; i < nsegments; i++, shdr++) {
+ /* Update elf header */
+ shdr->sh_type = SHT_PROGBITS;
+ shdr->sh_name = set_section_name(segments[i].name, ehdr);
+ shdr->sh_addr = (elf_addr_t)segments[i].address;
+ shdr->sh_size = segments[i].size;
+ shdr->sh_flags = SHF_WRITE;
+ shdr->sh_offset = offset;
+ shdr->sh_entsize = 0;
+ offset += shdr->sh_size;
+ }
+ ehdr->e_shnum = nsegments + 2;
+
+ rd_dev->data_ready = 1;
+ rd_dev->ramdump_status = -1;
+
+ reinit_completion(&rd_dev->ramdump_complete);
+
+ /* Tell userspace that the data is ready */
+ wake_up(&rd_dev->dump_wait_q);
+
+ /* Wait (with a timeout) to let the ramdump complete */
+ ret = wait_for_completion_timeout(&rd_dev->ramdump_complete,
+ msecs_to_jiffies(RAMDUMP_WAIT_MSECS));
+
+ if (!ret) {
+ pr_err("Ramdump(%s): Timed out waiting for userspace.\n",
+ rd_dev->name);
+ ret = -EPIPE;
+ } else {
+ ret = (rd_dev->ramdump_status == 0) ? 0 : -EPIPE;
+ }
+
+ rd_dev->data_ready = 0;
+ rd_dev->elfcore_size = 0;
+ kfree(rd_dev->elfcore_buf);
+ rd_dev->elfcore_buf = NULL;
+ return ret;
+}
+
int do_ramdump(void *handle, struct ramdump_segment *segments, int nsegments)
{
return _do_ramdump(handle, segments, nsegments, false);
}
EXPORT_SYMBOL(do_ramdump);
+int do_minidump(void *handle, struct ramdump_segment *segments, int nsegments)
+{
+ return _do_minidump(handle, segments, nsegments);
+}
+EXPORT_SYMBOL(do_minidump);
+
int
do_elf_ramdump(void *handle, struct ramdump_segment *segments, int nsegments)
{
diff --git a/drivers/soc/qcom/scm_qcpe.c b/drivers/soc/qcom/scm_qcpe.c
index 1e369c73e34b..3f2b05a0ec9e 100644
--- a/drivers/soc/qcom/scm_qcpe.c
+++ b/drivers/soc/qcom/scm_qcpe.c
@@ -1027,55 +1027,56 @@ int scm_is_call_available(u32 svc_id, u32 cmd_id)
ret = scm_call(SCM_SVC_INFO, IS_CALL_AVAIL_CMD, &svc_cmd,
sizeof(svc_cmd), &ret_val, sizeof(ret_val));
- if (ret)
- return ret;
+ if (!ret && ret_val)
+ return 1;
+ else
+ return 0;
return ret_val;
}
desc.arginfo = SCM_ARGS(1);
desc.args[0] = SCM_SIP_FNID(svc_id, cmd_id);
+ desc.ret[0] = 0;
ret = scm_call2(SCM_SIP_FNID(SCM_SVC_INFO, IS_CALL_AVAIL_CMD), &desc);
- if (ret)
- return ret;
-
- return desc.ret[0];
+ if (!ret && desc.ret[0])
+ return 1;
+ else
+ return 0;
}
EXPORT_SYMBOL(scm_is_call_available);
#define GET_FEAT_VERSION_CMD 3
-int scm_get_feat_version(u32 feat)
+int scm_get_feat_version(u32 feat, u64 *scm_ret)
{
struct scm_desc desc = {0};
int ret;
if (!is_scm_armv8()) {
if (scm_is_call_available(SCM_SVC_INFO, GET_FEAT_VERSION_CMD)) {
- u32 version;
-
- if (!scm_call(SCM_SVC_INFO, GET_FEAT_VERSION_CMD, &feat,
- sizeof(feat), &version, sizeof(version)))
- return version;
+ ret = scm_call(SCM_SVC_INFO, GET_FEAT_VERSION_CMD,
+ &feat, sizeof(feat), scm_ret, sizeof(*scm_ret));
+ return ret;
}
return 0;
}
ret = scm_is_call_available(SCM_SVC_INFO, GET_FEAT_VERSION_CMD);
if (ret <= 0)
- return 0;
+ return -EAGAIN;
desc.args[0] = feat;
desc.arginfo = SCM_ARGS(1);
ret = scm_call2(SCM_SIP_FNID(SCM_SVC_INFO, GET_FEAT_VERSION_CMD),
&desc);
- if (!ret)
- return desc.ret[0];
- return 0;
+ *scm_ret = desc.ret[0];
+
+ return ret;
}
EXPORT_SYMBOL(scm_get_feat_version);
#define RESTORE_SEC_CFG 2
-int scm_restore_sec_cfg(u32 device_id, u32 spare, int *scm_ret)
+int scm_restore_sec_cfg(u32 device_id, u32 spare, u64 *scm_ret)
{
struct scm_desc desc = {0};
int ret;
diff --git a/drivers/soc/qcom/smp2p_spinlock_test.c b/drivers/soc/qcom/smp2p_spinlock_test.c
index 74aac52b5285..1fe4411eebde 100644
--- a/drivers/soc/qcom/smp2p_spinlock_test.c
+++ b/drivers/soc/qcom/smp2p_spinlock_test.c
@@ -1,6 +1,6 @@
/* drivers/soc/qcom/smp2p_spinlock_test.c
*
- * Copyright (c) 2013-2016, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2013-2017, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -522,7 +522,7 @@ static void smp2p_ut_remote_spinlock_ssr(struct seq_file *s)
int spinlock_owner = 0;
struct workqueue_struct *ws = NULL;
- struct rmt_spinlock_work_item work_item;
+ struct rmt_spinlock_work_item work_item = { .has_locked = false };
seq_printf(s, " Running %s Test\n",
__func__);
diff --git a/drivers/soc/qcom/socinfo.c b/drivers/soc/qcom/socinfo.c
index b9903fe86f60..74dbd4d42272 100644
--- a/drivers/soc/qcom/socinfo.c
+++ b/drivers/soc/qcom/socinfo.c
@@ -566,6 +566,10 @@ static struct msm_soc_info cpu_of_id[] = {
[318] = {MSM_CPU_630, "SDM630"},
[327] = {MSM_CPU_630, "SDA630"},
+ /* 636 ID */
+ [345] = {MSM_CPU_636, "SDM636"},
+ [346] = {MSM_CPU_636, "SDA636"},
+
/* Uninitialized IDs are not known to run Linux.
MSM_CPU_UNKNOWN is set to 0 to ensure these IDs are
considered as unknown CPU. */
@@ -1289,6 +1293,14 @@ static void * __init setup_dummy_socinfo(void)
dummy_socinfo.id = 327;
strlcpy(dummy_socinfo.build_id, "sda630 - ",
sizeof(dummy_socinfo.build_id));
+ } else if (early_machine_is_sdm636()) {
+ dummy_socinfo.id = 345;
+ strlcpy(dummy_socinfo.build_id, "sdm636 - ",
+ sizeof(dummy_socinfo.build_id));
+ } else if (early_machine_is_sda636()) {
+ dummy_socinfo.id = 346;
+ strlcpy(dummy_socinfo.build_id, "sda636 - ",
+ sizeof(dummy_socinfo.build_id));
} else if (early_machine_is_apq8098()) {
dummy_socinfo.id = 319;
strlcpy(dummy_socinfo.build_id, "apq8098 - ",
diff --git a/drivers/soc/qcom/spcom.c b/drivers/soc/qcom/spcom.c
index 24de162e5401..a49848808078 100644
--- a/drivers/soc/qcom/spcom.c
+++ b/drivers/soc/qcom/spcom.c
@@ -209,10 +209,8 @@ struct spcom_channel {
* Only one rx/tx transaction at a time (request + response).
*/
int ref_count;
- u32 pid;
- /* link UP/DOWN callback */
- void (*notify_link_state_cb)(bool up);
+ u32 pid; /* debug only to find user space application */
/* abort flags */
bool rx_abort;
@@ -739,6 +737,7 @@ static int spcom_open(struct spcom_channel *ch, unsigned int timeout_msec)
long timeleft;
const char *name;
void *handle;
+ u32 pid = current_pid();
mutex_lock(&ch->lock);
name = ch->name;
@@ -752,7 +751,7 @@ static int spcom_open(struct spcom_channel *ch, unsigned int timeout_msec)
}
pr_debug("ch [%s] opened by PID [%d], count [%d]\n",
- name, ch->pid, ch->ref_count);
+ name, pid, ch->ref_count);
pr_debug("Open channel [%s] timeout_msec [%d].\n", name, timeout_msec);
@@ -780,7 +779,7 @@ static int spcom_open(struct spcom_channel *ch, unsigned int timeout_msec)
/* init channel context after successful open */
ch->glink_handle = handle;
ch->ref_count++;
- ch->pid = current_pid();
+ ch->pid = pid;
ch->txn_id = INITIAL_TXN_ID;
mutex_unlock(&ch->lock);
@@ -1139,6 +1138,7 @@ struct spcom_client *spcom_register_client(struct spcom_client_info *info)
ch = spcom_find_channel_by_name(name);
if (!ch) {
pr_err("channel %s doesn't exist, load App first.\n", name);
+ kfree(client);
return NULL;
}
@@ -1326,6 +1326,7 @@ struct spcom_server *spcom_register_service(struct spcom_service_info *info)
ch = spcom_find_channel_by_name(name);
if (!ch) {
pr_err("channel %s doesn't exist, load App first.\n", name);
+ kfree(server);
return NULL;
}
@@ -2029,6 +2030,7 @@ static int spcom_handle_get_req_size(struct spcom_channel *ch,
void *buf,
uint32_t size)
{
+ int ret = -1;
uint32_t next_req_size = 0;
if (size < sizeof(next_req_size)) {
@@ -2036,7 +2038,10 @@ static int spcom_handle_get_req_size(struct spcom_channel *ch,
return -EINVAL;
}
- next_req_size = spcom_get_next_request_size(ch);
+ ret = spcom_get_next_request_size(ch);
+ if (ret < 0)
+ return ret;
+ next_req_size = (uint32_t) ret;
memcpy(buf, &next_req_size, sizeof(next_req_size));
pr_debug("next_req_size [%d].\n", next_req_size);
@@ -2141,18 +2146,20 @@ static int spcom_handle_read(struct spcom_channel *ch,
void *buf,
uint32_t size)
{
+ int ret = -1;
+
if (size == SPCOM_GET_NEXT_REQUEST_SIZE) {
pr_debug("get next request size, ch [%s].\n", ch->name);
ch->is_server = true;
- size = spcom_handle_get_req_size(ch, buf, size);
+ ret = spcom_handle_get_req_size(ch, buf, size);
} else {
pr_debug("get request/response, ch [%s].\n", ch->name);
- size = spcom_handle_read_req_resp(ch, buf, size);
+ ret = spcom_handle_read_req_resp(ch, buf, size);
}
pr_debug("ch [%s] , size = %d.\n", ch->name, size);
- return size;
+ return ret;
}
/*======================================================================*/
@@ -2304,6 +2311,7 @@ static ssize_t spcom_device_write(struct file *filp,
char *buf;
struct spcom_channel *ch;
const char *name = file_to_filename(filp);
+ int buf_size = 0;
pr_debug("Write file [%s] size [%d] pos [%d].\n",
name, (int) size, (int) *f_pos);
@@ -2330,6 +2338,7 @@ static ssize_t spcom_device_write(struct file *filp,
(int) size , (int) SPCOM_MAX_COMMAND_SIZE);
return -EINVAL;
}
+ buf_size = size; /* explicit casting size_t to int */
if (*f_pos != 0) {
pr_err("offset should be zero, no sparse buffer.\n");
@@ -2347,7 +2356,7 @@ static ssize_t spcom_device_write(struct file *filp,
return -EFAULT;
}
- ret = spcom_handle_write(ch, buf, size);
+ ret = spcom_handle_write(ch, buf, buf_size);
if (ret) {
pr_err("handle command error [%d].\n", ret);
kfree(buf);
@@ -2375,6 +2384,7 @@ static ssize_t spcom_device_read(struct file *filp, char __user *user_buff,
char *buf;
struct spcom_channel *ch;
const char *name = file_to_filename(filp);
+ uint32_t buf_size = 0;
pr_debug("Read file [%s], size = %d bytes.\n", name, (int) size);
@@ -2383,6 +2393,7 @@ static ssize_t spcom_device_read(struct file *filp, char __user *user_buff,
pr_err("invalid parameters.\n");
return -EINVAL;
}
+ buf_size = size; /* explicit casting size_t to uint32_t */
ch = filp->private_data;
@@ -2400,7 +2411,7 @@ static ssize_t spcom_device_read(struct file *filp, char __user *user_buff,
if (buf == NULL)
return -ENOMEM;
- ret = spcom_handle_read(ch, buf, size);
+ ret = spcom_handle_read(ch, buf, buf_size);
if (ret < 0) {
pr_err("read error [%d].\n", ret);
kfree(buf);
@@ -2483,9 +2494,14 @@ static unsigned int spcom_device_poll(struct file *filp,
done = (spcom_dev->link_state == GLINK_LINK_STATE_UP);
break;
case SPCOM_POLL_CH_CONNECT:
+ /*
+ * ch is not expected to be NULL since user must call open()
+ * to get FD before it can call poll().
+ * open() will fail if no ch related to the char-device.
+ */
if (ch == NULL) {
pr_err("invalid ch pointer, file [%s].\n", name);
- return -EINVAL;
+ return POLLERR;
}
pr_debug("ch [%s] SPCOM_POLL_CH_CONNECT.\n", name);
if (wait) {
@@ -2786,7 +2802,7 @@ static int __init spcom_init(void)
{
int ret;
- pr_info("spcom driver version 1.1 17-July-2017.\n");
+ pr_info("spcom driver version 1.2 23-Aug-2017.\n");
ret = platform_driver_register(&spcom_driver);
if (ret)
diff --git a/drivers/soc/qcom/wcd-dsp-glink.c b/drivers/soc/qcom/wcd-dsp-glink.c
index 5fe3c572628b..85c2b92f5474 100644
--- a/drivers/soc/qcom/wcd-dsp-glink.c
+++ b/drivers/soc/qcom/wcd-dsp-glink.c
@@ -570,7 +570,7 @@ static int wdsp_glink_ch_info_init(struct wdsp_glink_priv *wpriv,
mutex_lock(&wpriv->glink_mutex);
if (wpriv->ch) {
- dev_err(wpriv->dev, "%s: glink ch memory is already allocated\n",
+ dev_err_ratelimited(wpriv->dev, "%s: glink ch memory is already allocated\n",
__func__);
ret = -EINVAL;
goto done;
@@ -579,7 +579,7 @@ static int wdsp_glink_ch_info_init(struct wdsp_glink_priv *wpriv,
no_of_channels = pkt->no_of_channels;
if (no_of_channels > WDSP_MAX_NO_OF_CHANNELS) {
- dev_err(wpriv->dev, "%s: no_of_channels: %d but max allowed are %d\n",
+ dev_err_ratelimited(wpriv->dev, "%s: no_of_channels: %d but max allowed are %d\n",
__func__, no_of_channels, WDSP_MAX_NO_OF_CHANNELS);
ret = -EINVAL;
goto done;
@@ -598,20 +598,20 @@ static int wdsp_glink_ch_info_init(struct wdsp_glink_priv *wpriv,
size += WDSP_CH_CFG_SIZE;
if (size > pkt_size) {
- dev_err(wpriv->dev, "%s: Invalid size = %zd, pkt_size = %zd\n",
+ dev_err_ratelimited(wpriv->dev, "%s: Invalid size = %zd, pkt_size = %zd\n",
__func__, size, pkt_size);
ret = -EINVAL;
goto err_ch_mem;
}
if (ch_cfg->no_of_intents > WDSP_MAX_NO_OF_INTENTS) {
- dev_err(wpriv->dev, "%s: Invalid no_of_intents = %d\n",
+ dev_err_ratelimited(wpriv->dev, "%s: Invalid no_of_intents = %d\n",
__func__, ch_cfg->no_of_intents);
ret = -EINVAL;
goto err_ch_mem;
}
size += (sizeof(u32) * ch_cfg->no_of_intents);
if (size > pkt_size) {
- dev_err(wpriv->dev, "%s: Invalid size = %zd, pkt_size = %zd\n",
+ dev_err_ratelimited(wpriv->dev, "%s: Invalid size = %zd, pkt_size = %zd\n",
__func__, size, pkt_size);
ret = -EINVAL;
goto err_ch_mem;
@@ -746,7 +746,7 @@ static ssize_t wdsp_glink_read(struct file *file, char __user *buf,
}
if (count > WDSP_MAX_READ_SIZE) {
- dev_info(wpriv->dev, "%s: count = %zd is more than WDSP_MAX_READ_SIZE\n",
+ dev_info_ratelimited(wpriv->dev, "%s: count = %zd is more than WDSP_MAX_READ_SIZE\n",
__func__, count);
count = WDSP_MAX_READ_SIZE;
}
@@ -778,7 +778,7 @@ static ssize_t wdsp_glink_read(struct file *file, char __user *buf,
if (ret1) {
mutex_unlock(&wpriv->rsp_mutex);
- dev_err(wpriv->dev, "%s: copy_to_user failed %d\n",
+ dev_err_ratelimited(wpriv->dev, "%s: copy_to_user failed %d\n",
__func__, ret);
ret = -EFAULT;
goto done;
@@ -824,7 +824,7 @@ static ssize_t wdsp_glink_write(struct file *file, const char __user *buf,
if ((count < WDSP_WRITE_PKT_SIZE) ||
(count > WDSP_MAX_WRITE_SIZE)) {
- dev_err(wpriv->dev, "%s: Invalid count = %zd\n",
+ dev_err_ratelimited(wpriv->dev, "%s: Invalid count = %zd\n",
__func__, count);
ret = -EINVAL;
goto done;
@@ -841,7 +841,7 @@ static ssize_t wdsp_glink_write(struct file *file, const char __user *buf,
ret = copy_from_user(tx_buf->buf, buf, count);
if (ret) {
- dev_err(wpriv->dev, "%s: copy_from_user failed %d\n",
+ dev_err_ratelimited(wpriv->dev, "%s: copy_from_user failed %d\n",
__func__, ret);
ret = -EFAULT;
goto free_buf;
@@ -852,7 +852,7 @@ static ssize_t wdsp_glink_write(struct file *file, const char __user *buf,
case WDSP_REG_PKT:
if (count < (WDSP_WRITE_PKT_SIZE + WDSP_REG_PKT_SIZE +
WDSP_CH_CFG_SIZE)) {
- dev_err(wpriv->dev, "%s: Invalid reg pkt size = %zd\n",
+ dev_err_ratelimited(wpriv->dev, "%s: Invalid reg pkt size = %zd\n",
__func__, count);
ret = -EINVAL;
goto free_buf;
@@ -861,7 +861,7 @@ static ssize_t wdsp_glink_write(struct file *file, const char __user *buf,
(struct wdsp_reg_pkt *)wpkt->payload,
count);
if (IS_ERR_VALUE(ret))
- dev_err(wpriv->dev, "%s: glink register failed, ret = %d\n",
+ dev_err_ratelimited(wpriv->dev, "%s: glink register failed, ret = %d\n",
__func__, ret);
vfree(tx_buf);
break;
@@ -871,7 +871,7 @@ static ssize_t wdsp_glink_write(struct file *file, const char __user *buf,
GLINK_LINK_STATE_UP),
msecs_to_jiffies(TIMEOUT_MS));
if (!ret) {
- dev_err(wpriv->dev, "%s: Link state wait timeout\n",
+ dev_err_ratelimited(wpriv->dev, "%s: Link state wait timeout\n",
__func__);
ret = -ETIMEDOUT;
goto free_buf;
@@ -881,7 +881,7 @@ static ssize_t wdsp_glink_write(struct file *file, const char __user *buf,
break;
case WDSP_CMD_PKT:
if (count <= (WDSP_WRITE_PKT_SIZE + WDSP_CMD_PKT_SIZE)) {
- dev_err(wpriv->dev, "%s: Invalid cmd pkt size = %zd\n",
+ dev_err_ratelimited(wpriv->dev, "%s: Invalid cmd pkt size = %zd\n",
__func__, count);
ret = -EINVAL;
goto free_buf;
@@ -889,7 +889,7 @@ static ssize_t wdsp_glink_write(struct file *file, const char __user *buf,
mutex_lock(&wpriv->glink_mutex);
if (wpriv->glink_state.link_state == GLINK_LINK_STATE_DOWN) {
mutex_unlock(&wpriv->glink_mutex);
- dev_err(wpriv->dev, "%s: Link state is Down\n",
+ dev_err_ratelimited(wpriv->dev, "%s: Link state is Down\n",
__func__);
ret = -ENETRESET;
@@ -901,7 +901,7 @@ static ssize_t wdsp_glink_write(struct file *file, const char __user *buf,
sizeof(struct wdsp_cmd_pkt) +
cpkt->payload_size;
if (count < pkt_max_size) {
- dev_err(wpriv->dev, "%s: Invalid cmd pkt count = %zd, pkt_size = %zd\n",
+ dev_err_ratelimited(wpriv->dev, "%s: Invalid cmd pkt count = %zd, pkt_size = %zd\n",
__func__, count, pkt_max_size);
ret = -EINVAL;
goto free_buf;
@@ -917,7 +917,7 @@ static ssize_t wdsp_glink_write(struct file *file, const char __user *buf,
}
}
if (!tx_buf->ch) {
- dev_err(wpriv->dev, "%s: Failed to get glink channel\n",
+ dev_err_ratelimited(wpriv->dev, "%s: Failed to get glink channel\n",
__func__);
ret = -EINVAL;
goto free_buf;
@@ -928,7 +928,7 @@ static ssize_t wdsp_glink_write(struct file *file, const char __user *buf,
GLINK_CONNECTED),
msecs_to_jiffies(TIMEOUT_MS));
if (!ret) {
- dev_err(wpriv->dev, "%s: glink channel %s is not in connected state %d\n",
+ dev_err_ratelimited(wpriv->dev, "%s: glink channel %s is not in connected state %d\n",
__func__, tx_buf->ch->ch_cfg.name,
tx_buf->ch->channel_state);
ret = -ETIMEDOUT;
@@ -940,7 +940,8 @@ static ssize_t wdsp_glink_write(struct file *file, const char __user *buf,
queue_work(wpriv->work_queue, &tx_buf->tx_work);
break;
default:
- dev_err(wpriv->dev, "%s: Invalid packet type\n", __func__);
+ dev_err_ratelimited(wpriv->dev, "%s: Invalid packet type\n",
+ __func__);
ret = -EINVAL;
vfree(tx_buf);
break;
@@ -986,6 +987,7 @@ static int wdsp_glink_open(struct inode *inode, struct file *file)
goto err_wq;
}
+ wpriv->glink_state.link_state = GLINK_LINK_STATE_DOWN;
init_completion(&wpriv->rsp_complete);
init_waitqueue_head(&wpriv->link_state_wait);
mutex_init(&wpriv->rsp_mutex);
diff --git a/drivers/spi/spi_qsd.c b/drivers/spi/spi_qsd.c
index 4499dd35f2dd..da58f19dd6e6 100644
--- a/drivers/spi/spi_qsd.c
+++ b/drivers/spi/spi_qsd.c
@@ -1827,14 +1827,16 @@ static int msm_spi_setup(struct spi_device *spi)
mb();
if (dd->pdata->is_shared)
put_local_resources(dd);
- /* Counter-part of system-resume when runtime-pm is not enabled. */
- if (!pm_runtime_enabled(dd->dev))
- msm_spi_pm_suspend_runtime(dd->dev);
no_resources:
mutex_unlock(&dd->core_lock);
- pm_runtime_mark_last_busy(dd->dev);
- pm_runtime_put_autosuspend(dd->dev);
+ /* Counter-part of system-resume when runtime-pm is not enabled. */
+ if (!pm_runtime_enabled(dd->dev)) {
+ msm_spi_pm_suspend_runtime(dd->dev);
+ } else {
+ pm_runtime_mark_last_busy(dd->dev);
+ pm_runtime_put_autosuspend(dd->dev);
+ }
err_setup_exit:
return rc;
diff --git a/drivers/spi/spidev.c b/drivers/spi/spidev.c
index 9f161b2631f2..e5ca8f150617 100644
--- a/drivers/spi/spidev.c
+++ b/drivers/spi/spidev.c
@@ -696,6 +696,8 @@ static const struct of_device_id spidev_dt_ids[] = {
{ .compatible = "rohm,dh2228fv" },
{ .compatible = "lineartechnology,ltc2488" },
{ .compatible = "qcom,spi-msm-codec-slave", },
+ { .compatible = "nxp,mpc57xx", },
+ { .compatible = "infineon,sli97", },
{},
};
MODULE_DEVICE_TABLE(of, spidev_dt_ids);
diff --git a/drivers/thermal/msm_thermal.c b/drivers/thermal/msm_thermal.c
index 4b586f62cdc7..50d1619d7bc3 100644
--- a/drivers/thermal/msm_thermal.c
+++ b/drivers/thermal/msm_thermal.c
@@ -200,6 +200,7 @@ static bool cluster_info_probed;
static bool cluster_info_nodes_called;
static bool in_suspend, retry_in_progress;
static bool lmh_dcvs_available;
+static bool lmh_dcvs_is_supported;
static int *tsens_id_map;
static int *zone_id_tsens_map;
static DEFINE_MUTEX(vdd_rstr_mutex);
@@ -995,7 +996,7 @@ static int msm_thermal_cpufreq_callback(struct notifier_block *nfb,
switch (event) {
case CPUFREQ_ADJUST:
- max_freq_req = (lmh_dcvs_available) ? UINT_MAX :
+ max_freq_req = (lmh_dcvs_is_supported) ? UINT_MAX :
cpus[policy->cpu].parent_ptr->limited_max_freq;
min_freq_req = cpus[policy->cpu].parent_ptr->limited_min_freq;
pr_debug("mitigating CPU%d to freq max: %u min: %u\n",
@@ -5379,7 +5380,7 @@ int msm_thermal_init(struct msm_thermal_data *pdata)
if (ret)
pr_err("cannot register cpufreq notifier. err:%d\n", ret);
- if (!lmh_dcvs_available) {
+ if (!lmh_dcvs_is_supported) {
register_reboot_notifier(&msm_thermal_reboot_notifier);
pm_notifier(msm_thermal_suspend_callback, 0);
}
@@ -7414,6 +7415,7 @@ static int msm_thermal_dev_probe(struct platform_device *pdev)
if (ret)
goto probe_exit;
+ lmh_dcvs_is_supported = of_property_read_bool(node, "clock-names");
probe_cc(node, &data, pdev);
probe_freq_mitigation(node, &data, pdev);
probe_cx_phase_ctrl(node, &data, pdev);
diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c
index c2eba06f2ace..0744b14e120b 100644
--- a/drivers/usb/dwc3/core.c
+++ b/drivers/usb/dwc3/core.c
@@ -1333,8 +1333,6 @@ static int dwc3_remove(struct platform_device *pdev)
dwc3_event_buffers_cleanup(dwc);
dwc3_free_event_buffers(dwc);
- usb_phy_set_suspend(dwc->usb2_phy, 1);
- usb_phy_set_suspend(dwc->usb3_phy, 1);
phy_power_off(dwc->usb2_generic_phy);
phy_power_off(dwc->usb3_generic_phy);
diff --git a/drivers/usb/dwc3/dwc3-msm.c b/drivers/usb/dwc3/dwc3-msm.c
index c5fc77eae894..5ad68df298cd 100644
--- a/drivers/usb/dwc3/dwc3-msm.c
+++ b/drivers/usb/dwc3/dwc3-msm.c
@@ -1239,7 +1239,7 @@ static void gsi_set_clear_dbell(struct usb_ep *ep,
*/
static bool gsi_check_ready_to_suspend(struct usb_ep *ep, bool f_suspend)
{
- u32 timeout = 1500;
+ u32 timeout = 500;
u32 reg = 0;
struct dwc3_ep *dep = to_dwc3_ep(ep);
struct dwc3 *dwc = dep->dwc;
@@ -1252,6 +1252,7 @@ static bool gsi_check_ready_to_suspend(struct usb_ep *ep, bool f_suspend)
"Unable to suspend GSI ch. WR_CTRL_STATE != 0\n");
return false;
}
+ usleep_range(20, 22);
}
/* Check for U3 only if we are not handling Function Suspend */
if (!f_suspend) {
@@ -1933,6 +1934,7 @@ static int dwc3_msm_prepare_suspend(struct dwc3_msm *mdwc)
reg = dwc3_msm_read_reg(mdwc->base, PWR_EVNT_IRQ_STAT_REG);
if (reg & PWR_EVNT_LPM_IN_L2_MASK)
break;
+ usleep_range(20, 30);
}
if (!(reg & PWR_EVNT_LPM_IN_L2_MASK))
dev_err(mdwc->dev, "could not transition HS PHY to L2\n");
diff --git a/drivers/usb/phy/phy-msm-qusb.c b/drivers/usb/phy/phy-msm-qusb.c
index bd2722e8fc48..be63c6c0a86a 100644
--- a/drivers/usb/phy/phy-msm-qusb.c
+++ b/drivers/usb/phy/phy-msm-qusb.c
@@ -74,10 +74,6 @@
#define QUSB2PHY_PORT_TUNE4 0x8C
#define QUSB2PHY_PORT_TUNE5 0x90
-/* In case Efuse register shows zero, use this value */
-#define TUNE2_DEFAULT_HIGH_NIBBLE 0xB
-#define TUNE2_DEFAULT_LOW_NIBBLE 0x3
-
/* Get TUNE2's high nibble value read from efuse */
#define TUNE2_HIGH_NIBBLE_VAL(val, pos, mask) ((val >> pos) & mask)
@@ -147,6 +143,7 @@ struct qusb_phy {
u32 tune2_val;
int tune2_efuse_bit_pos;
int tune2_efuse_num_of_bits;
+ int tune2_efuse_correction;
bool power_enabled;
bool clocks_enabled;
@@ -433,6 +430,7 @@ static void qusb_phy_get_tune2_param(struct qusb_phy *qphy)
{
u8 num_of_bits;
u32 bit_mask = 1;
+ u8 reg_val;
pr_debug("%s(): num_of_bits:%d bit_pos:%d\n", __func__,
qphy->tune2_efuse_num_of_bits,
@@ -446,9 +444,8 @@ static void qusb_phy_get_tune2_param(struct qusb_phy *qphy)
/*
* Read EFUSE register having TUNE2 parameter's high nibble.
- * If efuse register shows value as 0x0, then use default value
- * as 0xB as high nibble. Otherwise use efuse register based
- * value for this purpose.
+ * If efuse register shows value as 0x0, then use previous value
+ * as it is. Otherwise use efuse register based value for this purpose.
*/
qphy->tune2_val = readl_relaxed(qphy->tune2_efuse_reg);
pr_debug("%s(): bit_mask:%d efuse based tune2 value:%d\n",
@@ -457,12 +454,24 @@ static void qusb_phy_get_tune2_param(struct qusb_phy *qphy)
qphy->tune2_val = TUNE2_HIGH_NIBBLE_VAL(qphy->tune2_val,
qphy->tune2_efuse_bit_pos, bit_mask);
- if (!qphy->tune2_val)
- qphy->tune2_val = TUNE2_DEFAULT_HIGH_NIBBLE;
+ /* Update higher nibble of TUNE2 value for better rise/fall times */
+ if (qphy->tune2_efuse_correction && qphy->tune2_val) {
+ if (qphy->tune2_efuse_correction > 5 ||
+ qphy->tune2_efuse_correction < -10)
+ pr_warn("Correction value is out of range : %d\n",
+ qphy->tune2_efuse_correction);
+ else
+ qphy->tune2_val = qphy->tune2_val +
+ qphy->tune2_efuse_correction;
+ }
+
+ reg_val = readb_relaxed(qphy->base + QUSB2PHY_PORT_TUNE2);
+ if (qphy->tune2_val) {
+ reg_val &= 0x0f;
+ reg_val |= (qphy->tune2_val << 4);
+ }
- /* Get TUNE2 byte value using high and low nibble value */
- qphy->tune2_val = ((qphy->tune2_val << 0x4) |
- TUNE2_DEFAULT_LOW_NIBBLE);
+ qphy->tune2_val = reg_val;
}
static void qusb_phy_write_seq(void __iomem *base, u32 *seq, int cnt,
@@ -570,7 +579,7 @@ static int qusb_phy_init(struct usb_phy *phy)
* and try to read EFUSE value only once i.e. not every USB
* cable connect case.
*/
- if (qphy->tune2_efuse_reg) {
+ if (qphy->tune2_efuse_reg && !tune2) {
if (!qphy->tune2_val)
qusb_phy_get_tune2_param(qphy);
@@ -929,6 +938,9 @@ static int qusb_phy_probe(struct platform_device *pdev)
"qcom,tune2-efuse-num-bits",
&qphy->tune2_efuse_num_of_bits);
}
+ of_property_read_u32(dev->of_node,
+ "qcom,tune2-efuse-correction",
+ &qphy->tune2_efuse_correction);
if (ret) {
dev_err(dev, "DT Value for tune2 efuse is invalid.\n");
diff --git a/drivers/video/fbdev/msm/mdss_dp.c b/drivers/video/fbdev/msm/mdss_dp.c
index a98e5a9007bd..be4d1ec1589b 100644
--- a/drivers/video/fbdev/msm/mdss_dp.c
+++ b/drivers/video/fbdev/msm/mdss_dp.c
@@ -1637,6 +1637,7 @@ int mdss_dp_on_hpd(struct mdss_dp_drv_pdata *dp_drv)
dp_drv->link_rate = mdss_dp_gen_link_clk(dp_drv);
if (!dp_drv->link_rate) {
pr_err("Unable to configure required link rate\n");
+ mdss_dp_clk_ctrl(dp_drv, DP_CORE_PM, false);
ret = -EINVAL;
goto exit;
}
diff --git a/drivers/video/fbdev/msm/mdss_dp_aux.c b/drivers/video/fbdev/msm/mdss_dp_aux.c
index 786fe10055da..c0632e8241a0 100644
--- a/drivers/video/fbdev/msm/mdss_dp_aux.c
+++ b/drivers/video/fbdev/msm/mdss_dp_aux.c
@@ -684,6 +684,11 @@ char mdss_dp_gen_link_clk(struct mdss_dp_drv_pdata *dp)
pr_debug("clk_rate=%llu, bpp= %d, lane_cnt=%d\n",
pinfo->clk_rate, pinfo->bpp, lane_cnt);
+ if (lane_cnt == 0) {
+ pr_warn("Invalid max lane count\n");
+ return 0;
+ }
+
/*
* The max pixel clock supported is 675Mhz. The
* current calculations below will make sure
diff --git a/drivers/video/fbdev/msm/mdss_hdmi_edid.c b/drivers/video/fbdev/msm/mdss_hdmi_edid.c
index 2143c2bdb84b..a49c5290753c 100644
--- a/drivers/video/fbdev/msm/mdss_hdmi_edid.c
+++ b/drivers/video/fbdev/msm/mdss_hdmi_edid.c
@@ -2322,6 +2322,13 @@ int hdmi_edid_parser(void *input)
goto bail;
}
+ /* Find out if CEA extension blocks exceeding max limit */
+ if (num_of_cea_blocks >= MAX_EDID_BLOCKS) {
+ DEV_WARN("%s: HDMI EDID exceeded max CEA blocks limit\n",
+ __func__);
+ num_of_cea_blocks = MAX_EDID_BLOCKS - 1;
+ }
+
/* check for valid CEA block */
if (edid_buf[EDID_BLOCK_SIZE] != 2) {
DEV_ERR("%s: Invalid CEA block\n", __func__);
diff --git a/drivers/video/fbdev/msm/mdss_mdp_layer.c b/drivers/video/fbdev/msm/mdss_mdp_layer.c
index ff93c343d41f..b07ba82fde34 100644
--- a/drivers/video/fbdev/msm/mdss_mdp_layer.c
+++ b/drivers/video/fbdev/msm/mdss_mdp_layer.c
@@ -3191,11 +3191,14 @@ int mdss_mdp_layer_atomic_validate_wfd(struct msm_fb_data_type *mfd,
goto validate_failed;
}
+ mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON);
rc = mdss_mdp_wfd_setup(wfd, output_layer);
if (rc) {
pr_err("fail to prepare wfd = %d\n", rc);
+ mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF);
goto validate_failed;
}
+ mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF);
rc = mdss_mdp_layer_atomic_validate(mfd, file, commit);
if (rc) {
diff --git a/include/linux/dma-iommu.h b/include/linux/dma-iommu.h
index fc481037478a..f3422440c45f 100644
--- a/include/linux/dma-iommu.h
+++ b/include/linux/dma-iommu.h
@@ -59,7 +59,6 @@ void iommu_dma_unmap_page(struct device *dev, dma_addr_t handle, size_t size,
enum dma_data_direction dir, struct dma_attrs *attrs);
void iommu_dma_unmap_sg(struct device *dev, struct scatterlist *sg, int nents,
enum dma_data_direction dir, struct dma_attrs *attrs);
-int iommu_dma_supported(struct device *dev, u64 mask);
int iommu_dma_mapping_error(struct device *dev, dma_addr_t dma_addr);
#else
diff --git a/include/linux/habmm.h b/include/linux/habmm.h
new file mode 100644
index 000000000000..4d3a81f536d9
--- /dev/null
+++ b/include/linux/habmm.h
@@ -0,0 +1,38 @@
+/* Copyright (c) 2016-2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+#include <uapi/linux/habmm.h>
+
+#ifndef _HABMM_H
+#define _HABMM_H
+
+int32_t habmm_socket_open(int32_t *handle, uint32_t mm_ip_id,
+ uint32_t timeout, uint32_t flags);
+int32_t habmm_socket_close(int32_t handle);
+int32_t habmm_socket_send(int32_t handle, void *src_buff, uint32_t size_bytes,
+ uint32_t flags);
+int32_t habmm_socket_recv(int32_t handle, void *dst_buff, uint32_t *size_bytes,
+ uint32_t timeout, uint32_t flags);
+int32_t habmm_socket_sendto(int32_t handle, void *src_buff, uint32_t size_bytes,
+ int32_t remote_handle, uint32_t flags);
+int32_t habmm_socket_recvfrom(int32_t handle, void *dst_buff,
+ uint32_t *size_bytes, uint32_t timeout,
+ int32_t *remote_handle, uint32_t flags);
+int32_t habmm_export(int32_t handle, void *buff_to_share, uint32_t size_bytes,
+ uint32_t *export_id, uint32_t flags);
+int32_t habmm_unexport(int32_t handle, uint32_t export_id, uint32_t flags);
+int32_t habmm_import(int32_t handle, void **buff_shared, uint32_t size_bytes,
+ uint32_t export_id, uint32_t flags);
+int32_t habmm_unimport(int32_t handle, uint32_t export_id, void *buff_shared,
+ uint32_t flags);
+
+#endif
diff --git a/include/linux/msm_audio_ion.h b/include/linux/msm_audio_ion.h
index ff2fd04a3b6c..9e77ac317c28 100644
--- a/include/linux/msm_audio_ion.h
+++ b/include/linux/msm_audio_ion.h
@@ -50,6 +50,12 @@ int msm_audio_ion_free_legacy(struct ion_client *client,
struct ion_handle *handle);
u32 msm_audio_populate_upper_32_bits(ion_phys_addr_t pa);
-int msm_audio_ion_phys_assign(const char *name, int fd, ion_phys_addr_t *paddr,
- size_t *pa_len, u8 assign_type);
+int msm_audio_ion_phys_assign(const char *name, struct ion_client **client,
+ struct ion_handle **handle,
+ int fd, ion_phys_addr_t *paddr,
+ size_t *pa_len, u8 assign_type);
+int msm_audio_ion_phys_free(struct ion_client *client,
+ struct ion_handle *handle,
+ ion_phys_addr_t *paddr,
+ size_t *pa_len, u8 assign_type);
#endif /* _LINUX_MSM_AUDIO_ION_H */
diff --git a/include/linux/power_supply.h b/include/linux/power_supply.h
index 982b93ccfbe4..8b8a46ce32d0 100644
--- a/include/linux/power_supply.h
+++ b/include/linux/power_supply.h
@@ -199,6 +199,8 @@ enum power_supply_property {
POWER_SUPPLY_PROP_LOW_POWER,
POWER_SUPPLY_PROP_COOL_TEMP,
POWER_SUPPLY_PROP_WARM_TEMP,
+ POWER_SUPPLY_PROP_COLD_TEMP,
+ POWER_SUPPLY_PROP_HOT_TEMP,
POWER_SUPPLY_PROP_SYSTEM_TEMP_LEVEL,
POWER_SUPPLY_PROP_RESISTANCE,
POWER_SUPPLY_PROP_RESISTANCE_CAPACITIVE,
diff --git a/include/linux/sched.h b/include/linux/sched.h
index 2fe0b38f5572..d1542e5cc81b 100644
--- a/include/linux/sched.h
+++ b/include/linux/sched.h
@@ -2501,6 +2501,7 @@ extern void do_set_cpus_allowed(struct task_struct *p,
extern int set_cpus_allowed_ptr(struct task_struct *p,
const struct cpumask *new_mask);
+extern bool cpupri_check_rt(void);
#else
static inline void do_set_cpus_allowed(struct task_struct *p,
const struct cpumask *new_mask)
@@ -2513,6 +2514,10 @@ static inline int set_cpus_allowed_ptr(struct task_struct *p,
return -EINVAL;
return 0;
}
+static inline bool cpupri_check_rt(void)
+{
+ return false;
+}
#endif
struct sched_load {
diff --git a/include/soc/qcom/minidump.h b/include/soc/qcom/minidump.h
index 5eb18cb1a365..d5970cfef643 100644
--- a/include/soc/qcom/minidump.h
+++ b/include/soc/qcom/minidump.h
@@ -39,11 +39,16 @@ struct md_region {
extern int msm_minidump_add_region(const struct md_region *entry);
/* Sets to true, if minidump table is initialized */
extern bool minidump_enabled;
+extern void dump_stack_minidump(u64 sp);
#else
static inline int msm_minidump_add_region(const struct md_region *entry)
{
/* Return quietly, if minidump is not supported */
return 0;
}
+
+static inline void dump_stack_minidump(u64 sp) {}
#endif
+
+
#endif
diff --git a/include/soc/qcom/ramdump.h b/include/soc/qcom/ramdump.h
index 50a17c8ad605..4e23ccf269a7 100644
--- a/include/soc/qcom/ramdump.h
+++ b/include/soc/qcom/ramdump.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011-2014, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2011-2014, 2017 The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -16,6 +16,7 @@
struct device;
struct ramdump_segment {
+ char *name;
unsigned long address;
void *v_address;
unsigned long size;
@@ -28,6 +29,8 @@ extern int do_ramdump(void *handle, struct ramdump_segment *segments,
int nsegments);
extern int do_elf_ramdump(void *handle, struct ramdump_segment *segments,
int nsegments);
+extern int do_minidump(void *handle, struct ramdump_segment *segments,
+ int nsegments);
#else
static inline void *create_ramdump_device(const char *dev_name,
diff --git a/include/soc/qcom/socinfo.h b/include/soc/qcom/socinfo.h
index 2e8d71754c98..9110963d0e9f 100644
--- a/include/soc/qcom/socinfo.h
+++ b/include/soc/qcom/socinfo.h
@@ -96,6 +96,10 @@
of_flat_dt_is_compatible(of_get_flat_dt_root(), "qcom,sdm660")
#define early_machine_is_sda660() \
of_flat_dt_is_compatible(of_get_flat_dt_root(), "qcom,sda660")
+#define early_machine_is_sdm636() \
+ of_flat_dt_is_compatible(of_get_flat_dt_root(), "qcom,sdm636")
+#define early_machine_is_sda636() \
+ of_flat_dt_is_compatible(of_get_flat_dt_root(), "qcom,sda636")
#define early_machine_is_sdm658() \
of_flat_dt_is_compatible(of_get_flat_dt_root(), "qcom,sdm658")
#define early_machine_is_sda658() \
@@ -142,6 +146,8 @@
#define early_machine_is_msmhamster() 0
#define early_machine_is_sdm660() 0
#define early_machine_is_sda660() 0
+#define early_machine_is_sdm636() 0
+#define early_machine_is_sda636() 0
#define early_machine_is_sdm658() 0
#define early_machine_is_sda658() 0
#define early_machine_is_sdm630() 0
@@ -206,6 +212,7 @@ enum msm_cpu {
MSM_CPU_HAMSTER,
MSM_CPU_660,
MSM_CPU_630,
+ MSM_CPU_636,
};
struct msm_soc_info {
diff --git a/include/sound/q6asm-v2.h b/include/sound/q6asm-v2.h
index 2ff0a2b02d4a..9ddd02cac9ac 100644
--- a/include/sound/q6asm-v2.h
+++ b/include/sound/q6asm-v2.h
@@ -639,7 +639,8 @@ int q6asm_send_audio_effects_params(struct audio_client *ac, char *params,
int q6asm_send_stream_cmd(struct audio_client *ac,
struct msm_adsp_event_data *data);
-int q6asm_audio_map_shm_fd(struct audio_client *ac, int fd);
+int q6asm_audio_map_shm_fd(struct audio_client *ac, struct ion_client **client,
+ struct ion_handle **handle, int fd);
int q6asm_send_rtic_event_ack(struct audio_client *ac,
void *param, uint32_t params_length);
diff --git a/include/uapi/drm/sde_drm.h b/include/uapi/drm/sde_drm.h
index bef841446247..71159cb377d8 100644
--- a/include/uapi/drm/sde_drm.h
+++ b/include/uapi/drm/sde_drm.h
@@ -337,4 +337,14 @@ struct sde_drm_wb_cfg {
uint64_t modes;
};
+/**
+ * Define extended power modes supported by the SDE connectors.
+ */
+#define SDE_MODE_DPMS_ON 0
+#define SDE_MODE_DPMS_LP1 1
+#define SDE_MODE_DPMS_LP2 2
+#define SDE_MODE_DPMS_STANDBY 3
+#define SDE_MODE_DPMS_SUSPEND 4
+#define SDE_MODE_DPMS_OFF 5
+
#endif /* _SDE_DRM_H_ */
diff --git a/include/uapi/linux/Kbuild b/include/uapi/linux/Kbuild
index 3d912dd57c08..b041334338f9 100644
--- a/include/uapi/linux/Kbuild
+++ b/include/uapi/linux/Kbuild
@@ -528,3 +528,4 @@ header-y += ipa_qmi_service_v01.h
header-y += rmnet_ipa_fd_ioctl.h
header-y += msm_ipa.h
header-y += smcinvoke.h
+header-y += habmm.h
diff --git a/include/uapi/linux/habmm.h b/include/uapi/linux/habmm.h
new file mode 100644
index 000000000000..902bd35ee474
--- /dev/null
+++ b/include/uapi/linux/habmm.h
@@ -0,0 +1,143 @@
+#ifndef HABMM_H
+#define HABMM_H
+
+#include <linux/types.h>
+
+struct hab_send {
+ __u64 data;
+ __s32 vcid;
+ __u32 sizebytes;
+ __u32 flags;
+};
+
+struct hab_recv {
+ __u64 data;
+ __s32 vcid;
+ __u32 sizebytes;
+ __u32 flags;
+};
+
+struct hab_open {
+ __s32 vcid;
+ __u32 mmid;
+ __u32 timeout;
+ __u32 flags;
+};
+
+struct hab_close {
+ __s32 vcid;
+ __u32 flags;
+};
+
+struct hab_export {
+ __u64 buffer;
+ __s32 vcid;
+ __u32 sizebytes;
+ __u32 exportid;
+ __u32 flags;
+};
+
+struct hab_import {
+ __u64 index;
+ __u64 kva;
+ __s32 vcid;
+ __u32 sizebytes;
+ __u32 exportid;
+ __u32 flags;
+};
+
+struct hab_unexport {
+ __s32 vcid;
+ __u32 exportid;
+ __u32 flags;
+};
+
+struct hab_unimport {
+ __s32 vcid;
+ __u32 exportid;
+ __u64 kva;
+ __u32 flags;
+};
+
+#define HAB_IOC_TYPE 0x0A
+#define HAB_MAX_MSG_SIZEBYTES 0x1000
+#define HAB_MAX_EXPORT_SIZE 0x8000000
+
+#define HAB_MMID_CREATE(major, minor) ((major&0xFFFF) | ((minor&0xFF)<<16))
+
+#define MM_AUD_START 100
+#define MM_AUD_1 101
+#define MM_AUD_2 102
+#define MM_AUD_3 103
+#define MM_AUD_4 104
+#define MM_AUD_END 105
+
+#define MM_CAM_START 200
+#define MM_CAM 201
+#define MM_CAM_END 202
+
+#define MM_DISP_START 300
+#define MM_DISP_1 301
+#define MM_DISP_2 302
+#define MM_DISP_3 303
+#define MM_DISP_4 304
+#define MM_DISP_5 305
+#define MM_DISP_END 306
+
+#define MM_GFX_START 400
+#define MM_GFX 401
+#define MM_GFX_END 402
+
+#define MM_VID_START 500
+#define MM_VID 501
+#define MM_VID_END 502
+
+#define MM_MISC_START 600
+#define MM_MISC 601
+#define MM_MISC_END 602
+
+#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_ID_MAX 706
+
+#define HABMM_SOCKET_OPEN_FLAGS_SINGLE_BE_SINGLE_FE 0x00000000
+#define HABMM_SOCKET_OPEN_FLAGS_SINGLE_BE_SINGLE_DOMU 0x00000001
+#define HABMM_SOCKET_OPEN_FLAGS_SINGLE_BE_MULTI_DOMUS 0x00000002
+
+#define HABMM_SOCKET_SEND_FLAGS_NON_BLOCKING 0x00000001
+
+#define HABMM_SOCKET_RECV_FLAGS_NON_BLOCKING 0x00000001
+
+#define HABMM_EXP_MEM_TYPE_DMA 0x00000001
+
+#define HABMM_IMPORT_FLAGS_CACHED 0x00000001
+
+#define IOCTL_HAB_SEND \
+ _IOW(HAB_IOC_TYPE, 0x2, struct hab_send)
+
+#define IOCTL_HAB_RECV \
+ _IOWR(HAB_IOC_TYPE, 0x3, struct hab_recv)
+
+#define IOCTL_HAB_VC_OPEN \
+ _IOWR(HAB_IOC_TYPE, 0x4, struct hab_open)
+
+#define IOCTL_HAB_VC_CLOSE \
+ _IOW(HAB_IOC_TYPE, 0x5, struct hab_close)
+
+#define IOCTL_HAB_VC_EXPORT \
+ _IOWR(HAB_IOC_TYPE, 0x6, struct hab_export)
+
+#define IOCTL_HAB_VC_IMPORT \
+ _IOWR(HAB_IOC_TYPE, 0x7, struct hab_import)
+
+#define IOCTL_HAB_VC_UNEXPORT \
+ _IOW(HAB_IOC_TYPE, 0x8, struct hab_unexport)
+
+#define IOCTL_HAB_VC_UNIMPORT \
+ _IOW(HAB_IOC_TYPE, 0x9, struct hab_unimport)
+
+#endif /* HABMM_H */
diff --git a/include/uapi/linux/msm_ipa.h b/include/uapi/linux/msm_ipa.h
index 4d0b992d0ba6..322fb09b8614 100644
--- a/include/uapi/linux/msm_ipa.h
+++ b/include/uapi/linux/msm_ipa.h
@@ -91,7 +91,11 @@
#define IPA_IOCTL_ALLOC_IPV6CT_TABLE 49
#define IPA_IOCTL_DEL_NAT_TABLE 50
#define IPA_IOCTL_DEL_IPV6CT_TABLE 51
-#define IPA_IOCTL_MAX 52
+#define IPA_IOCTL_ADD_VLAN_IFACE 52
+#define IPA_IOCTL_DEL_VLAN_IFACE 53
+#define IPA_IOCTL_ADD_L2TP_VLAN_MAPPING 54
+#define IPA_IOCTL_DEL_L2TP_VLAN_MAPPING 55
+#define IPA_IOCTL_MAX 56
/**
* max size of the header to be inserted
@@ -435,7 +439,16 @@ enum ipa_ssr_event {
IPA_SSR_EVENT_MAX
};
-#define IPA_EVENT_MAX_NUM ((int)IPA_SSR_EVENT_MAX)
+enum ipa_vlan_l2tp_event {
+ ADD_VLAN_IFACE = IPA_SSR_EVENT_MAX,
+ DEL_VLAN_IFACE,
+ ADD_L2TP_VLAN_MAPPING,
+ DEL_L2TP_VLAN_MAPPING,
+ IPA_VLAN_L2TP_EVENT_MAX,
+};
+
+#define IPA_EVENT_MAX_NUM (IPA_VLAN_L2TP_EVENT_MAX)
+#define IPA_EVENT_MAX ((int)IPA_EVENT_MAX_NUM)
/**
* enum ipa_rm_resource_name - IPA RM clients identification names
@@ -1448,6 +1461,30 @@ struct ipa_ioc_nat_pdn_entry {
};
/**
+ * struct ipa_ioc_vlan_iface_info - add vlan interface
+ * @name: interface name
+ * @vlan_id: VLAN ID
+ */
+struct ipa_ioc_vlan_iface_info {
+ char name[IPA_RESOURCE_NAME_MAX];
+ uint8_t vlan_id;
+};
+
+/**
+ * struct ipa_ioc_l2tp_vlan_mapping_info - l2tp->vlan mapping info
+ * @iptype: l2tp tunnel IP type
+ * @l2tp_iface_name: l2tp interface name
+ * @l2tp_session_id: l2tp session id
+ * @vlan_iface_name: vlan interface name
+ */
+struct ipa_ioc_l2tp_vlan_mapping_info {
+ enum ipa_ip_type iptype;
+ char l2tp_iface_name[IPA_RESOURCE_NAME_MAX];
+ uint8_t l2tp_session_id;
+ char vlan_iface_name[IPA_RESOURCE_NAME_MAX];
+};
+
+/**
* struct ipa_msg_meta - Format of the message meta-data.
* @msg_type: the type of the message
* @rsvd: reserved bits for future use.
@@ -1742,6 +1779,21 @@ enum ipacm_client_enum {
IPA_IOCTL_GET_HW_VERSION, \
enum ipa_hw_type *)
+#define IPA_IOC_ADD_VLAN_IFACE _IOWR(IPA_IOC_MAGIC, \
+ IPA_IOCTL_ADD_VLAN_IFACE, \
+ struct ipa_ioc_vlan_iface_info *)
+
+#define IPA_IOC_DEL_VLAN_IFACE _IOWR(IPA_IOC_MAGIC, \
+ IPA_IOCTL_DEL_VLAN_IFACE, \
+ struct ipa_ioc_vlan_iface_info *)
+
+#define IPA_IOC_ADD_L2TP_VLAN_MAPPING _IOWR(IPA_IOC_MAGIC, \
+ IPA_IOCTL_ADD_L2TP_VLAN_MAPPING, \
+ struct ipa_ioc_l2tp_vlan_mapping_info *)
+
+#define IPA_IOC_DEL_L2TP_VLAN_MAPPING _IOWR(IPA_IOC_MAGIC, \
+ IPA_IOCTL_DEL_L2TP_VLAN_MAPPING, \
+ struct ipa_ioc_l2tp_vlan_mapping_info *)
/*
* unique magic number of the Tethering bridge ioctls
*/
diff --git a/include/uapi/media/ais/msm_ais_sensor.h b/include/uapi/media/ais/msm_ais_sensor.h
index f8b98def850a..eb9c24024383 100644
--- a/include/uapi/media/ais/msm_ais_sensor.h
+++ b/include/uapi/media/ais/msm_ais_sensor.h
@@ -178,6 +178,27 @@ enum cci_i2c_master_t {
MASTER_MAX,
};
+struct msm_sensor_event_data {
+ uint16_t sensor_slave_addr;
+};
+
+enum msm_sensor_event_mask_index {
+ SENSOR_EVENT_MASK_INDEX_SIGNAL_STATUS = 2,
+};
+
+#define SENSOR_EVENT_SUBS_MASK_NONE 0
+
+#define SENSOR_EVENT_SUBS_MASK_SIGNAL_STATUS \
+ (1 << SENSOR_EVENT_MASK_INDEX_SIGNAL_STATUS)
+
+enum msm_sensor_event_idx {
+ SENSOR_SIGNAL_STATUS = 2,
+ SENSOR_EVENT_MAX = 15
+};
+
+#define SENSOR_EVENT_BASE (V4L2_EVENT_PRIVATE_START)
+#define SENSOR_EVENT_SIGNAL_STATUS (SENSOR_EVENT_BASE + SENSOR_SIGNAL_STATUS)
+
struct msm_camera_i2c_array_write_config {
struct msm_camera_i2c_reg_setting conf_array;
uint16_t slave_addr;
diff --git a/include/uapi/media/ais/msm_ais_sensor_sdk.h b/include/uapi/media/ais/msm_ais_sensor_sdk.h
index c2a93a51a985..3f63bde39cf3 100644
--- a/include/uapi/media/ais/msm_ais_sensor_sdk.h
+++ b/include/uapi/media/ais/msm_ais_sensor_sdk.h
@@ -285,6 +285,11 @@ struct msm_sensor_id_info_t {
unsigned short sensor_id_mask;
};
+struct msm_camera_sensor_gpio_intr_config {
+ int gpio_num;
+ uint32_t gpio_trigger;
+};
+
struct msm_camera_sensor_slave_info {
char sensor_name[32];
char eeprom_name[32];
@@ -300,6 +305,9 @@ struct msm_camera_sensor_slave_info {
unsigned char is_init_params_valid;
struct msm_sensor_init_params sensor_init_params;
enum msm_sensor_output_format_t output_format;
+ struct msm_camera_sensor_gpio_intr_config
+ gpio_intr_config;
+ unsigned int camera_sensor_device_id;
};
struct msm_camera_i2c_reg_array {
diff --git a/kernel/panic.c b/kernel/panic.c
index 679254405510..75f564a94a82 100644
--- a/kernel/panic.c
+++ b/kernel/panic.c
@@ -24,6 +24,7 @@
#include <linux/init.h>
#include <linux/nmi.h>
#include <linux/console.h>
+#include <soc/qcom/minidump.h>
#define CREATE_TRACE_POINTS
#include <trace/events/exception.h>
@@ -108,6 +109,7 @@ void panic(const char *fmt, ...)
va_start(args, fmt);
vsnprintf(buf, sizeof(buf), fmt, args);
va_end(args);
+ dump_stack_minidump(0);
pr_emerg("Kernel panic - not syncing: %s\n", buf);
#ifdef CONFIG_DEBUG_BUGVERBOSE
/*
diff --git a/kernel/sched/cpupri.c b/kernel/sched/cpupri.c
index 1d00cf8c00fa..14225d5d8617 100644
--- a/kernel/sched/cpupri.c
+++ b/kernel/sched/cpupri.c
@@ -279,3 +279,14 @@ void cpupri_cleanup(struct cpupri *cp)
for (i = 0; i < CPUPRI_NR_PRIORITIES; i++)
free_cpumask_var(cp->pri_to_cpu[i].mask);
}
+
+/*
+ * cpupri_check_rt - check if CPU has a RT task
+ * should be called from rcu-sched read section.
+ */
+bool cpupri_check_rt(void)
+{
+ int cpu = raw_smp_processor_id();
+
+ return cpu_rq(cpu)->rd->cpupri.cpu_to_pri[cpu] > CPUPRI_NORMAL;
+}
diff --git a/kernel/softirq.c b/kernel/softirq.c
index 39ffd41594ce..9029227e5f57 100644
--- a/kernel/softirq.c
+++ b/kernel/softirq.c
@@ -234,6 +234,8 @@ static inline bool lockdep_softirq_start(void) { return false; }
static inline void lockdep_softirq_end(bool in_hardirq) { }
#endif
+#define long_softirq_pending() (local_softirq_pending() & LONG_SOFTIRQ_MASK)
+#define defer_for_rt() (long_softirq_pending() && cpupri_check_rt())
asmlinkage __visible void __do_softirq(void)
{
unsigned long end = jiffies + MAX_SOFTIRQ_TIME;
@@ -297,6 +299,7 @@ restart:
pending = local_softirq_pending();
if (pending) {
if (time_before(jiffies, end) && !need_resched() &&
+ !defer_for_rt() &&
--max_restart)
goto restart;
@@ -349,7 +352,7 @@ void irq_enter(void)
static inline void invoke_softirq(void)
{
- if (!force_irqthreads) {
+ if (!force_irqthreads && !defer_for_rt()) {
#ifdef CONFIG_HAVE_IRQ_EXIT_ON_IRQ_STACK
/*
* We can safely execute softirq on the current stack if
diff --git a/lib/stackdepot.c b/lib/stackdepot.c
index 192134b225ca..076eb03e316b 100644
--- a/lib/stackdepot.c
+++ b/lib/stackdepot.c
@@ -242,6 +242,7 @@ depot_stack_handle_t depot_save_stack(struct stack_trace *trace,
*/
alloc_flags &= ~GFP_ZONEMASK;
alloc_flags &= (GFP_ATOMIC | GFP_KERNEL);
+ alloc_flags |= __GFP_NOWARN;
page = alloc_pages(alloc_flags, STACK_ALLOC_ORDER);
if (page)
prealloc = page_address(page);
diff --git a/sound/soc/codecs/sdm660_cdc/msm-analog-cdc.c b/sound/soc/codecs/sdm660_cdc/msm-analog-cdc.c
index 025a592b4015..cc7132d190b8 100644
--- a/sound/soc/codecs/sdm660_cdc/msm-analog-cdc.c
+++ b/sound/soc/codecs/sdm660_cdc/msm-analog-cdc.c
@@ -3662,18 +3662,6 @@ static const struct sdm660_cdc_reg_mask_val
{MSM89XX_PMIC_ANALOG_RX_COM_OCP_COUNT, 0xFF, 0xFF},
};
-static void msm_anlg_cdc_codec_init_cache(struct snd_soc_codec *codec)
-{
- u32 i;
-
- regcache_cache_only(codec->component.regmap, true);
- /* update cache with POR values */
- for (i = 0; i < ARRAY_SIZE(msm89xx_pmic_cdc_defaults); i++)
- snd_soc_write(codec, msm89xx_pmic_cdc_defaults[i].reg,
- msm89xx_pmic_cdc_defaults[i].def);
- regcache_cache_only(codec->component.regmap, false);
-}
-
static void msm_anlg_cdc_codec_init_reg(struct snd_soc_codec *codec)
{
u32 i;
@@ -3719,7 +3707,7 @@ static struct regulator *msm_anlg_cdc_find_regulator(
return sdm660_cdc->supplies[i].consumer;
}
- dev_err(sdm660_cdc->dev, "Error: regulator not found:%s\n"
+ dev_dbg(sdm660_cdc->dev, "Error: regulator not found:%s\n"
, name);
return NULL;
}
@@ -4171,7 +4159,6 @@ static int msm_anlg_cdc_soc_probe(struct snd_soc_codec *codec)
ARRAY_SIZE(hph_type_detect_controls));
msm_anlg_cdc_bringup(codec);
- msm_anlg_cdc_codec_init_cache(codec);
msm_anlg_cdc_codec_init_reg(codec);
msm_anlg_cdc_update_reg_defaults(codec);
diff --git a/sound/soc/codecs/sdm660_cdc/msm-digital-cdc.c b/sound/soc/codecs/sdm660_cdc/msm-digital-cdc.c
index 4249ada17c87..e64956aa2f40 100644
--- a/sound/soc/codecs/sdm660_cdc/msm-digital-cdc.c
+++ b/sound/soc/codecs/sdm660_cdc/msm-digital-cdc.c
@@ -1327,6 +1327,9 @@ static const struct snd_soc_dapm_route audio_dig_map[] = {
{"RX2 MIX1 INP2", "RX3", "I2S RX3"},
{"RX2 MIX1 INP2", "IIR1", "IIR1"},
{"RX2 MIX1 INP2", "IIR2", "IIR2"},
+ {"RX2 MIX1 INP3", "RX1", "I2S RX1"},
+ {"RX2 MIX1 INP3", "RX2", "I2S RX2"},
+ {"RX2 MIX1 INP3", "RX3", "I2S RX3"},
{"RX3 MIX1 INP1", "RX1", "I2S RX1"},
{"RX3 MIX1 INP1", "RX2", "I2S RX2"},
@@ -1338,6 +1341,9 @@ static const struct snd_soc_dapm_route audio_dig_map[] = {
{"RX3 MIX1 INP2", "RX3", "I2S RX3"},
{"RX3 MIX1 INP2", "IIR1", "IIR1"},
{"RX3 MIX1 INP2", "IIR2", "IIR2"},
+ {"RX3 MIX1 INP3", "RX1", "I2S RX1"},
+ {"RX3 MIX1 INP3", "RX2", "I2S RX2"},
+ {"RX3 MIX1 INP3", "RX3", "I2S RX3"},
{"RX1 MIX2 INP1", "IIR1", "IIR1"},
{"RX2 MIX2 INP1", "IIR1", "IIR1"},
diff --git a/sound/soc/codecs/wsa881x.c b/sound/soc/codecs/wsa881x.c
index 058f6c5fa676..e4f6df077d98 100644
--- a/sound/soc/codecs/wsa881x.c
+++ b/sound/soc/codecs/wsa881x.c
@@ -968,6 +968,8 @@ static void wsa881x_init(struct snd_soc_codec *codec)
wsa881x->version = snd_soc_read(codec, WSA881X_CHIP_ID1);
wsa881x_regmap_defaults(wsa881x->regmap, wsa881x->version);
+ /* Enable software reset output from soundwire slave */
+ snd_soc_update_bits(codec, WSA881X_SWR_RESET_EN, 0x07, 0x07);
/* Bring out of analog reset */
snd_soc_update_bits(codec, WSA881X_CDC_RST_CTL, 0x02, 0x02);
/* Bring out of digital reset */
diff --git a/sound/soc/msm/Kconfig b/sound/soc/msm/Kconfig
index eb650d19a97c..629a9c3d91db 100644
--- a/sound/soc/msm/Kconfig
+++ b/sound/soc/msm/Kconfig
@@ -166,7 +166,7 @@ config SND_SOC_EXT_CODEC
config SND_SOC_MSM8996
tristate "SoC Machine driver for MSM8996 boards"
- depends on ARCH_MSM8996
+ depends on ARCH_MSM8996 || MSM_GVM_QUIN
select SND_SOC_COMPRESS
select SND_SOC_QDSP6V2
select SND_SOC_MSM_STUB
@@ -176,7 +176,7 @@ config SND_SOC_MSM8996
select MSM_QDSP6V2_CODECS
select SND_SOC_WCD9335
select SND_SOC_WSA881X
- select SND_SOC_MSM_HDMI_CODEC_RX
+ select SND_SOC_MSM_HDMI_CODEC_RX if ARCH_MSM8996
select DTS_SRS_TM
select QTI_PP
select QTI_PP_AUDIOSPHERE
diff --git a/sound/soc/msm/qdsp6v2/msm-compress-q6-v2.c b/sound/soc/msm/qdsp6v2/msm-compress-q6-v2.c
index 076dbed207a9..c462f682e160 100644
--- a/sound/soc/msm/qdsp6v2/msm-compress-q6-v2.c
+++ b/sound/soc/msm/qdsp6v2/msm-compress-q6-v2.c
@@ -159,6 +159,10 @@ struct msm_compr_audio {
uint32_t start_delay_msw;
int32_t shm_ion_fd;
+ struct ion_client *lib_ion_client;
+ struct ion_client *shm_ion_client;
+ struct ion_handle *lib_ion_handle;
+ struct ion_handle *shm_ion_handle;
uint64_t marker_timestamp;
@@ -1510,20 +1514,16 @@ static int msm_compr_configure_dsp_for_capture(struct snd_compr_stream *cstream)
return ret;
}
-static int msm_compr_map_unmap_fd(int fd, bool add_pages)
+static int msm_compr_map_ion_fd(struct msm_compr_audio *prtd, int fd)
{
ion_phys_addr_t paddr;
size_t pa_len = 0;
int ret = 0;
- u8 assign_type;
- if (add_pages)
- assign_type = HLOS_TO_ADSP;
- else
- assign_type = ADSP_TO_HLOS;
-
- ret = msm_audio_ion_phys_assign("audio_lib_mem_client", fd,
- &paddr, &pa_len, assign_type);
+ ret = msm_audio_ion_phys_assign("audio_lib_mem_client",
+ &prtd->lib_ion_client,
+ &prtd->lib_ion_handle,
+ fd, &paddr, &pa_len, HLOS_TO_ADSP);
if (ret) {
pr_err("%s: audio lib ION phys failed, rc = %d\n",
__func__, ret);
@@ -1531,19 +1531,48 @@ static int msm_compr_map_unmap_fd(int fd, bool add_pages)
}
ret = q6core_add_remove_pool_pages(paddr, pa_len,
- ADSP_MEMORY_MAP_HLOS_PHYSPOOL, add_pages);
+ ADSP_MEMORY_MAP_HLOS_PHYSPOOL, true);
if (ret) {
pr_err("%s: add remove pages failed, rc = %d\n", __func__, ret);
/* Assign back to HLOS if add pages cmd failed */
- if (add_pages)
- msm_audio_ion_phys_assign("audio_lib_mem_client", fd,
- &paddr, &pa_len, ADSP_TO_HLOS);
+ msm_audio_ion_phys_free(prtd->lib_ion_client,
+ prtd->lib_ion_handle,
+ &paddr, &pa_len, ADSP_TO_HLOS);
}
done:
return ret;
}
+static int msm_compr_unmap_ion_fd(struct msm_compr_audio *prtd)
+{
+ ion_phys_addr_t paddr;
+ size_t pa_len = 0;
+ int ret = 0;
+
+ if (!prtd->lib_ion_client || !prtd->lib_ion_handle) {
+ pr_err("%s: ion_client or ion_handle is NULL", __func__);
+ return -EINVAL;
+ }
+
+ ret = msm_audio_ion_phys_free(prtd->lib_ion_client,
+ prtd->lib_ion_handle,
+ &paddr, &pa_len, ADSP_TO_HLOS);
+ if (ret) {
+ pr_err("%s: audio lib ION phys failed, rc = %d\n",
+ __func__, ret);
+ goto done;
+ }
+
+ ret = q6core_add_remove_pool_pages(paddr, pa_len,
+ ADSP_MEMORY_MAP_HLOS_PHYSPOOL, false);
+ if (ret)
+ pr_err("%s: add remove pages failed, rc = %d\n", __func__, ret);
+
+done:
+ return ret;
+}
+
static int msm_compr_playback_open(struct snd_compr_stream *cstream)
{
struct snd_compr_runtime *runtime = cstream->runtime;
@@ -1628,8 +1657,8 @@ static int msm_compr_playback_open(struct snd_compr_stream *cstream)
prtd->session_id = prtd->audio_client->session;
msm_adsp_init_mixer_ctl_pp_event_queue(rtd);
if (pdata->ion_fd[rtd->dai_link->be_id] > 0) {
- ret = msm_compr_map_unmap_fd(
- pdata->ion_fd[rtd->dai_link->be_id], true);
+ ret = msm_compr_map_ion_fd(prtd,
+ pdata->ion_fd[rtd->dai_link->be_id]);
if (ret < 0)
goto map_err;
}
@@ -1800,12 +1829,11 @@ static int msm_compr_playback_free(struct snd_compr_stream *cstream)
q6asm_audio_client_buf_free_contiguous(dir, ac);
if (prtd->shm_ion_fd > 0)
- msm_audio_ion_phys_assign("audio_shm_mem_client",
- prtd->shm_ion_fd,
- &paddr, &pa_len, ADSP_TO_HLOS);
+ msm_audio_ion_phys_free(prtd->shm_ion_client,
+ prtd->shm_ion_handle,
+ &paddr, &pa_len, ADSP_TO_HLOS);
if (pdata->ion_fd[soc_prtd->dai_link->be_id] > 0) {
- msm_compr_map_unmap_fd(pdata->ion_fd[soc_prtd->dai_link->be_id],
- false);
+ msm_compr_unmap_ion_fd(prtd);
pdata->ion_fd[soc_prtd->dai_link->be_id] = 0;
}
@@ -3715,6 +3743,119 @@ done:
return ret;
}
+static int msm_compr_playback_dnmix_ctl_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ int ret = 0;
+ int len = 0;
+ int i = 0;
+ struct snd_soc_component *comp = snd_kcontrol_chip(kcontrol);
+ unsigned long fe_id = kcontrol->private_value;
+ struct msm_compr_pdata *pdata = (struct msm_compr_pdata *)
+ snd_soc_component_get_drvdata(comp);
+ struct snd_compr_stream *cstream = NULL;
+ struct msm_compr_audio *prtd;
+ struct asm_stream_pan_ctrl_params dnmix_param;
+ int be_id = ucontrol->value.integer.value[len++];
+ int stream_id = 0;
+ /*
+ * Max index for this mixer control includes below
+ * be_id (1)
+ * num_output_channels (1)
+ * num_input_channels (1)
+ * output ch map (max) (8)
+ * input ch map (max) (8)
+ * mix matrix coefficients (max)(64)
+ */
+ int max_index = 0;
+ int max_mixer_ctrl_value_size = 128;
+
+ if (fe_id >= MSM_FRONTEND_DAI_MAX) {
+ pr_err("%s Received out of bounds invalid fe_id %lu\n",
+ __func__, fe_id);
+ ret = -EINVAL;
+ goto done;
+ }
+
+ cstream = pdata->cstream[fe_id];
+ if (cstream == NULL) {
+ pr_err("%s cstream is null\n", __func__);
+ ret = -EINVAL;
+ goto done;
+ }
+
+ prtd = cstream->runtime->private_data;
+ if (!prtd) {
+ pr_err("%s: prtd is null\n", __func__);
+ ret = -EINVAL;
+ goto done;
+ }
+
+ if (prtd->audio_client == NULL) {
+ pr_err("%s: audio_client is null\n", __func__);
+ ret = -EINVAL;
+ goto done;
+ }
+
+ stream_id = prtd->audio_client->session;
+ if (len >= max_mixer_ctrl_value_size) {
+ ret = -EINVAL;
+ goto done;
+ }
+ dnmix_param.num_output_channels =
+ ucontrol->value.integer.value[len++];
+ if (dnmix_param.num_output_channels >
+ PCM_FORMAT_MAX_NUM_CHANNEL) {
+ ret = -EINVAL;
+ goto done;
+ }
+ if (len >= max_mixer_ctrl_value_size) {
+ ret = -EINVAL;
+ goto done;
+ }
+ dnmix_param.num_input_channels =
+ ucontrol->value.integer.value[len++];
+ if (dnmix_param.num_input_channels >
+ PCM_FORMAT_MAX_NUM_CHANNEL) {
+ ret = -EINVAL;
+ goto done;
+ }
+ max_index = len + dnmix_param.num_output_channels +
+ dnmix_param.num_input_channels +
+ dnmix_param.num_output_channels *
+ dnmix_param.num_input_channels;
+ if (max_index >= max_mixer_ctrl_value_size) {
+ ret = -EINVAL;
+ goto done;
+ }
+
+ if (ucontrol->value.integer.value[len++]) {
+ for (i = 0; i < dnmix_param.num_output_channels; i++) {
+ dnmix_param.output_channel_map[i] =
+ ucontrol->value.integer.value[len++];
+ }
+ }
+ if (ucontrol->value.integer.value[len++]) {
+ for (i = 0; i < dnmix_param.num_input_channels; i++) {
+ dnmix_param.input_channel_map[i] =
+ ucontrol->value.integer.value[len++];
+ }
+ }
+ if (ucontrol->value.integer.value[len++]) {
+ for (i = 0; i < dnmix_param.num_output_channels *
+ dnmix_param.num_input_channels; i++) {
+ dnmix_param.gain[i] =
+ ucontrol->value.integer.value[len++];
+ }
+ }
+ msm_routing_set_downmix_control_data(be_id,
+ stream_id,
+ &dnmix_param);
+
+done:
+ return ret;
+}
+
static int msm_compr_shm_ion_fd_map_put(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
@@ -3755,7 +3896,9 @@ static int msm_compr_shm_ion_fd_map_put(struct snd_kcontrol *kcontrol,
memcpy(&prtd->shm_ion_fd, ucontrol->value.bytes.data,
sizeof(prtd->shm_ion_fd));
- ret = q6asm_audio_map_shm_fd(prtd->audio_client, prtd->shm_ion_fd);
+ ret = q6asm_audio_map_shm_fd(prtd->audio_client,
+ &prtd->shm_ion_client,
+ &prtd->shm_ion_handle, prtd->shm_ion_fd);
if (ret < 0)
pr_err("%s: failed to map shm mem\n", __func__);
done:
@@ -3984,6 +4127,16 @@ static int msm_compr_channel_map_info(struct snd_kcontrol *kcontrol,
return 0;
}
+static int msm_compr_device_downmix_info(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_info *uinfo)
+{
+ uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+ uinfo->count = 128;
+ uinfo->value.integer.min = 0;
+ uinfo->value.integer.max = 0xFFFFFFFF;
+ return 0;
+}
+
static int msm_compr_add_volume_control(struct snd_soc_pcm_runtime *rtd)
{
const char *mixer_ctl_name = "Compress Playback";
@@ -4282,6 +4435,53 @@ static int msm_compr_add_dec_runtime_params_control(
return 0;
}
+static int msm_compr_add_device_down_mix_controls(
+ struct snd_soc_pcm_runtime *rtd)
+{
+ const char *playback_mixer_ctl_name = "Audio Device";
+ const char *deviceNo = "NN";
+ const char *suffix = "Downmix Control";
+ char *mixer_str = NULL;
+ int ctl_len = 0, ret = 0;
+ struct snd_kcontrol_new device_downmix_control[1] = {
+ {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .name = "?",
+ .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
+ .info = msm_compr_device_downmix_info,
+ .put = msm_compr_playback_dnmix_ctl_put,
+ .private_value = 0,
+ }
+ };
+
+ if (!rtd) {
+ pr_err("%s NULL rtd\n", __func__);
+ ret = -EINVAL;
+ goto done;
+ }
+ ctl_len = strlen(playback_mixer_ctl_name) + 1 +
+ strlen(deviceNo) + 1 + strlen(suffix) + 1;
+ mixer_str = kzalloc(ctl_len, GFP_KERNEL);
+ if (!mixer_str) {
+ ret = -ENOMEM;
+ goto done;
+ }
+
+ snprintf(mixer_str, ctl_len, "%s %d %s",
+ playback_mixer_ctl_name, rtd->pcm->device, suffix);
+ device_downmix_control[0].name = mixer_str;
+ device_downmix_control[0].private_value = rtd->dai_link->be_id;
+ ret = snd_soc_add_platform_controls(rtd->platform,
+ device_downmix_control,
+ ARRAY_SIZE(device_downmix_control));
+ if (ret < 0)
+ pr_err("%s: failed to add ctl %s\n", __func__, mixer_str);
+
+ kfree(mixer_str);
+done:
+ return ret;
+}
+
static int msm_compr_add_app_type_cfg_control(struct snd_soc_pcm_runtime *rtd)
{
const char *playback_mixer_ctl_name = "Audio Stream";
@@ -4585,6 +4785,11 @@ static int msm_compr_new(struct snd_soc_pcm_runtime *rtd)
pr_err("%s: Could not add Compr event ack Control\n",
__func__);
+ rc = msm_compr_add_device_down_mix_controls(rtd);
+ if (rc)
+ pr_err("%s: Could not add Compr downmix Control\n",
+ __func__);
+
rc = msm_compr_add_query_audio_effect_control(rtd);
if (rc)
pr_err("%s: Could not add Compr Query Audio Effect Control\n",
diff --git a/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c b/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c
index 7326e658c947..2114adae72d7 100644
--- a/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c
+++ b/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c
@@ -12211,8 +12211,16 @@ static const struct snd_soc_dapm_widget msm_qdsp6_widgets[] = {
0, 0, 0, 0),
SND_SOC_DAPM_AIF_OUT("INT0_MI2S_RX", "INT0 MI2S Playback",
0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_OUT("INT2_MI2S_RX", "INT2 MI2S Playback",
+ 0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_OUT("INT3_MI2S_RX", "INT3 MI2S Playback",
+ 0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_OUT("INT5_MI2S_RX", "INT5 MI2S Playback",
+ 0, 0, 0, 0),
SND_SOC_DAPM_AIF_OUT("INT4_MI2S_RX", "INT4 MI2S Playback",
0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_OUT("INT4_MI2S_TX", "INT4 MI2S Capture",
+ 0, 0, 0, 0),
SND_SOC_DAPM_AIF_OUT("QUIN_MI2S_RX", "Quinary MI2S Playback",
0, 0, 0, 0),
SND_SOC_DAPM_AIF_IN("PRI_I2S_TX", "Primary I2S Capture", 0, 0, 0, 0),
@@ -12223,6 +12231,8 @@ static const struct snd_soc_dapm_widget msm_qdsp6_widgets[] = {
0, 0, 0, 0),
SND_SOC_DAPM_AIF_IN("TERT_MI2S_TX", "Tertiary MI2S Capture",
0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_IN("INT0_MI2S_TX", "INT0 MI2S Capture",
+ 0, 0, 0, 0),
SND_SOC_DAPM_AIF_IN("INT2_MI2S_TX", "INT2 MI2S Capture",
0, 0, 0, 0),
SND_SOC_DAPM_AIF_IN("INT3_MI2S_TX", "INT3 MI2S Capture",
@@ -15485,6 +15495,9 @@ static const struct snd_soc_dapm_route intercon[] = {
{"BE_OUT", NULL, "PRI_MI2S_RX"},
{"BE_OUT", NULL, "INT0_MI2S_RX"},
{"BE_OUT", NULL, "INT4_MI2S_RX"},
+ {"BE_OUT", NULL, "INT2_MI2S_RX"},
+ {"BE_OUT", NULL, "INT3_MI2S_RX"},
+ {"BE_OUT", NULL, "INT5_MI2S_RX"},
{"BE_OUT", NULL, "INT_BT_SCO_RX"},
{"BE_OUT", NULL, "INT_BT_A2DP_RX"},
{"BE_OUT", NULL, "INT_FM_RX"},
@@ -15524,8 +15537,10 @@ static const struct snd_soc_dapm_route intercon[] = {
{"QUIN_MI2S_TX", NULL, "BE_IN"},
{"PRI_MI2S_TX", NULL, "BE_IN"},
{"TERT_MI2S_TX", NULL, "BE_IN"},
+ {"INT0_MI2S_TX", NULL, "BE_IN"},
{"INT2_MI2S_TX", NULL, "BE_IN"},
{"INT3_MI2S_TX", NULL, "BE_IN"},
+ {"INT4_MI2S_TX", NULL, "BE_IN"},
{"INT5_MI2S_TX", NULL, "BE_IN"},
{"SEC_MI2S_TX", NULL, "BE_IN"},
{"SENARY_MI2S_TX", NULL, "BE_IN" },
diff --git a/sound/soc/msm/qdsp6v2/msm-transcode-loopback-q6-v2.c b/sound/soc/msm/qdsp6v2/msm-transcode-loopback-q6-v2.c
index fdeb8a15ffee..18cac3424054 100644
--- a/sound/soc/msm/qdsp6v2/msm-transcode-loopback-q6-v2.c
+++ b/sound/soc/msm/qdsp6v2/msm-transcode-loopback-q6-v2.c
@@ -92,6 +92,10 @@ struct msm_transcode_loopback {
int session_id;
struct audio_client *audio_client;
int32_t shm_ion_fd;
+ struct ion_client *lib_ion_client;
+ struct ion_client *shm_ion_client;
+ struct ion_handle *lib_ion_handle;
+ struct ion_handle *shm_ion_handle;
};
/* Transcode loopback global info struct */
@@ -192,20 +196,17 @@ static void populate_codec_list(struct msm_transcode_loopback *trans,
}
}
-static int msm_transcode_map_unmap_fd(int fd, bool add_pages)
+static int msm_transcode_map_ion_fd(struct msm_transcode_loopback *trans,
+ int fd)
{
ion_phys_addr_t paddr;
size_t pa_len = 0;
int ret = 0;
- u8 assign_type;
- if (add_pages)
- assign_type = HLOS_TO_ADSP;
- else
- assign_type = ADSP_TO_HLOS;
-
- ret = msm_audio_ion_phys_assign("audio_lib_mem_client", fd,
- &paddr, &pa_len, assign_type);
+ ret = msm_audio_ion_phys_assign("audio_lib_mem_client",
+ &trans->lib_ion_client,
+ &trans->lib_ion_handle, fd,
+ &paddr, &pa_len, HLOS_TO_ADSP);
if (ret) {
pr_err("%s: audio lib ION phys failed, rc = %d\n", __func__,
ret);
@@ -213,19 +214,47 @@ static int msm_transcode_map_unmap_fd(int fd, bool add_pages)
}
ret = q6core_add_remove_pool_pages(paddr, pa_len,
- ADSP_MEMORY_MAP_HLOS_PHYSPOOL, add_pages);
+ ADSP_MEMORY_MAP_HLOS_PHYSPOOL, true);
if (ret) {
- pr_err("%s: add remove pages failed, rc = %d\n", __func__, ret);
+ pr_err("%s: add pages failed, rc = %d\n", __func__, ret);
/* Assign back to HLOS if add pages cmd failed */
- if (add_pages)
- msm_audio_ion_phys_assign("audio_lib_mem_client", fd,
- &paddr, &pa_len, ADSP_TO_HLOS);
+ msm_audio_ion_phys_free(trans->lib_ion_client,
+ trans->lib_ion_handle,
+ &paddr, &pa_len, ADSP_TO_HLOS);
}
done:
return ret;
}
+static int msm_transcode_unmap_ion_fd(struct msm_transcode_loopback *trans)
+{
+ ion_phys_addr_t paddr;
+ size_t pa_len = 0;
+ int ret = 0;
+
+ if (!trans->lib_ion_client || !trans->lib_ion_handle) {
+ pr_err("%s: ion_client or ion_handle is NULL", __func__);
+ return -EINVAL;
+ }
+ ret = msm_audio_ion_phys_free(trans->lib_ion_client,
+ trans->lib_ion_handle,
+ &paddr, &pa_len, ADSP_TO_HLOS);
+ if (ret) {
+ pr_err("%s: audio lib ION phys failed, rc = %d\n", __func__,
+ ret);
+ goto done;
+ }
+
+ ret = q6core_add_remove_pool_pages(paddr, pa_len,
+ ADSP_MEMORY_MAP_HLOS_PHYSPOOL, false);
+ if (ret)
+ pr_err("%s: remove pages failed, rc = %d\n", __func__, ret);
+
+done:
+ return ret;
+}
+
static int msm_transcode_loopback_open(struct snd_compr_stream *cstream)
{
int ret = 0;
@@ -272,9 +301,8 @@ static int msm_transcode_loopback_open(struct snd_compr_stream *cstream)
}
msm_adsp_init_mixer_ctl_pp_event_queue(rtd);
if (pdata->ion_fd[rtd->dai_link->be_id] > 0) {
- ret = msm_transcode_map_unmap_fd(
- pdata->ion_fd[rtd->dai_link->be_id],
- true);
+ ret = msm_transcode_map_ion_fd(trans,
+ pdata->ion_fd[rtd->dai_link->be_id]);
if (ret < 0)
goto exit;
}
@@ -345,16 +373,13 @@ static int msm_transcode_loopback_free(struct snd_compr_stream *cstream)
memset(&trans->sink, 0, sizeof(struct loopback_stream));
msm_adsp_clean_mixer_ctl_pp_event_queue(rtd);
if (trans->shm_ion_fd > 0) {
- msm_audio_ion_phys_assign("audio_shm_mem_client",
- trans->shm_ion_fd,
- &paddr, &pa_len,
- ADSP_TO_HLOS);
+ msm_audio_ion_phys_free(trans->shm_ion_client,
+ trans->shm_ion_handle,
+ &paddr, &pa_len, ADSP_TO_HLOS);
trans->shm_ion_fd = 0;
}
if (pdata->ion_fd[rtd->dai_link->be_id] > 0) {
- msm_transcode_map_unmap_fd(
- pdata->ion_fd[rtd->dai_link->be_id],
- false);
+ msm_transcode_unmap_ion_fd(trans);
pdata->ion_fd[rtd->dai_link->be_id] = 0;
}
} else if (cstream->direction == SND_COMPRESS_CAPTURE) {
@@ -713,7 +738,9 @@ static int msm_transcode_shm_ion_fd_map_put(struct snd_kcontrol *kcontrol,
memcpy(&prtd->shm_ion_fd, ucontrol->value.bytes.data,
sizeof(prtd->shm_ion_fd));
- ret = q6asm_audio_map_shm_fd(prtd->audio_client, prtd->shm_ion_fd);
+ ret = q6asm_audio_map_shm_fd(prtd->audio_client,
+ &prtd->shm_ion_client,
+ &prtd->shm_ion_handle, prtd->shm_ion_fd);
if (ret < 0)
pr_err("%s: failed to map shm mem\n", __func__);
done:
diff --git a/sound/soc/msm/qdsp6v2/q6asm.c b/sound/soc/msm/qdsp6v2/q6asm.c
index 609ae8cd82ac..14f9411104b3 100644
--- a/sound/soc/msm/qdsp6v2/q6asm.c
+++ b/sound/soc/msm/qdsp6v2/q6asm.c
@@ -7118,7 +7118,8 @@ fail_cmd:
return rc;
}
-int q6asm_audio_map_shm_fd(struct audio_client *ac, int fd)
+int q6asm_audio_map_shm_fd(struct audio_client *ac, struct ion_client **client,
+ struct ion_handle **handle, int fd)
{
ion_phys_addr_t paddr;
size_t pa_len = 0;
@@ -7137,7 +7138,8 @@ int q6asm_audio_map_shm_fd(struct audio_client *ac, int fd)
goto fail_cmd;
}
- ret = msm_audio_ion_phys_assign("audio_shm_mem_client", fd,
+ ret = msm_audio_ion_phys_assign("audio_shm_mem_client", client,
+ handle, fd,
&paddr, &pa_len, HLOS_TO_ADSP);
if (ret) {
pr_err("%s: shm ION phys failed, rc = %d\n", __func__, ret);
diff --git a/sound/soc/msm/sdm660-internal.c b/sound/soc/msm/sdm660-internal.c
index 0f28e100f535..948fb287023d 100644
--- a/sound/soc/msm/sdm660-internal.c
+++ b/sound/soc/msm/sdm660-internal.c
@@ -1291,6 +1291,9 @@ static int msm_audrx_init(struct snd_soc_pcm_runtime *rtd)
snd_soc_dapm_ignore_suspend(dapm, "AMIC1");
snd_soc_dapm_ignore_suspend(dapm, "AMIC2");
snd_soc_dapm_ignore_suspend(dapm, "AMIC3");
+ snd_soc_dapm_sync(dapm);
+
+ dapm = snd_soc_codec_get_dapm(dig_cdc);
snd_soc_dapm_ignore_suspend(dapm, "DMIC1");
snd_soc_dapm_ignore_suspend(dapm, "DMIC2");
snd_soc_dapm_ignore_suspend(dapm, "DMIC3");