summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Documentation/devicetree/bindings/arm/cpus.txt1
-rw-r--r--Documentation/devicetree/bindings/arm/msm/adv7481.txt54
-rw-r--r--Documentation/devicetree/bindings/arm/msm/android.txt54
-rw-r--r--Documentation/devicetree/bindings/arm/msm/msm_ipc_router_glink_xprt.txt2
-rw-r--r--Documentation/devicetree/bindings/display/msm/cec.txt75
-rw-r--r--Documentation/devicetree/bindings/fb/mdss-dsi.txt4
-rw-r--r--Documentation/devicetree/bindings/fb/mdss-pll.txt7
-rw-r--r--Documentation/devicetree/bindings/iommu/arm,smmu.txt6
-rw-r--r--Documentation/devicetree/bindings/mhi/msm_mhi.txt2
-rw-r--r--Documentation/devicetree/bindings/power/supply/qcom/qpnp-fg-gen3.txt20
-rw-r--r--Documentation/devicetree/bindings/regulator/rpm-smd-regulator.txt6
-rw-r--r--Documentation/devicetree/bindings/sound/qcom-audio-dev.txt11
-rw-r--r--arch/arm/boot/dts/qcom/apq8096-auto-dragonboard.dtsi77
-rw-r--r--arch/arm/boot/dts/qcom/apq8096pro-v1.1-auto-adp.dts4
-rw-r--r--arch/arm/boot/dts/qcom/apq8096pro-v1.1-auto-cdp.dts4
-rw-r--r--arch/arm/boot/dts/qcom/msm-arm-smmu-660.dtsi1
-rw-r--r--arch/arm/boot/dts/qcom/msm-audio-lpass.dtsi4
-rw-r--r--arch/arm/boot/dts/qcom/msm-pm660.dtsi6
-rw-r--r--arch/arm/boot/dts/qcom/msm-pmi8998.dtsi5
-rw-r--r--arch/arm/boot/dts/qcom/msm8996-agave-adp.dtsi87
-rw-r--r--arch/arm/boot/dts/qcom/msm8996-auto-cdp.dtsi223
-rw-r--r--arch/arm/boot/dts/qcom/msm8996-coresight-v3.dtsi829
-rw-r--r--arch/arm/boot/dts/qcom/msm8996-mmxf-adp.dtsi4
-rw-r--r--arch/arm/boot/dts/qcom/msm8998-audio.dtsi9
-rw-r--r--arch/arm/boot/dts/qcom/msm8998-cdp.dtsi2
-rw-r--r--arch/arm/boot/dts/qcom/msm8998-mdss-panels.dtsi4
-rw-r--r--arch/arm/boot/dts/qcom/msm8998-mdss.dtsi4
-rw-r--r--arch/arm/boot/dts/qcom/msm8998-mtp.dtsi2
-rw-r--r--arch/arm/boot/dts/qcom/msm8998-pinctrl.dtsi2
-rw-r--r--arch/arm/boot/dts/qcom/msm8998-qrd-skuk-hdk.dtsi10
-rw-r--r--arch/arm/boot/dts/qcom/msm8998-qrd-vr1.dtsi10
-rw-r--r--arch/arm/boot/dts/qcom/msm8998-regulator.dtsi8
-rw-r--r--arch/arm/boot/dts/qcom/msm8998-sde-display.dtsi34
-rw-r--r--arch/arm/boot/dts/qcom/msm8998-sde.dtsi4
-rw-r--r--arch/arm/boot/dts/qcom/msm8998.dtsi22
-rw-r--r--arch/arm/boot/dts/qcom/sdm630-camera.dtsi1
-rw-r--r--arch/arm/boot/dts/qcom/vplatform-lfv-msm8996.dts107
-rw-r--r--arch/arm/include/asm/perf_event.h87
-rw-r--r--arch/arm64/configs/msm-auto-perf_defconfig33
-rw-r--r--arch/arm64/configs/msm-auto_defconfig33
-rw-r--r--arch/arm64/configs/msmcortex_mediabox-perf_defconfig1
-rw-r--r--arch/arm64/configs/msmcortex_mediabox_defconfig1
-rw-r--r--arch/arm64/include/asm/perf_event.h87
-rw-r--r--arch/arm64/kernel/Makefile3
-rw-r--r--drivers/bluetooth/bluetooth-power.c4
-rw-r--r--drivers/bluetooth/btfm_slim_codec.c4
-rw-r--r--drivers/char/diag/diag_dci.c57
-rw-r--r--drivers/char/diag/diag_debugfs.c13
-rw-r--r--drivers/char/diag/diag_masks.c75
-rw-r--r--drivers/char/diag/diag_memorydevice.c4
-rw-r--r--drivers/char/diag/diagchar.h11
-rw-r--r--drivers/char/diag/diagchar_core.c68
-rw-r--r--drivers/char/diag/diagfwd.c5
-rw-r--r--drivers/char/diag/diagfwd_cntl.c341
-rw-r--r--drivers/char/diag/diagfwd_cntl.h54
-rw-r--r--drivers/char/diag/diagfwd_mhi.c29
-rw-r--r--drivers/clk/msm/clock-local2.c37
-rw-r--r--drivers/clk/msm/clock-osm.c6
-rw-r--r--drivers/clk/msm/mdss/mdss-hdmi-pll-8998.c240
-rw-r--r--drivers/clk/msm/mdss/mdss-hdmi-pll.h16
-rw-r--r--drivers/clk/msm/mdss/mdss-pll.c14
-rw-r--r--drivers/clk/msm/mdss/mdss-pll.h5
-rw-r--r--drivers/cpuidle/lpm-levels.c26
-rw-r--r--drivers/crypto/msm/qcedev.c12
-rw-r--r--drivers/devfreq/governor_msm_adreno_tz.c2
-rw-r--r--drivers/firmware/psci.c13
-rw-r--r--drivers/gpio/gpiolib-acpi.c2
-rw-r--r--drivers/gpu/drm/drm_mm.c248
-rw-r--r--drivers/gpu/drm/msm/Kconfig2
-rw-r--r--drivers/gpu/drm/msm/adreno/a5xx_gpu.c6
-rw-r--r--drivers/gpu/drm/msm/adreno/a5xx_power.c2
-rw-r--r--drivers/gpu/drm/msm/adreno/a5xx_preempt.c2
-rw-r--r--drivers/gpu/drm/msm/adreno/a5xx_snapshot.c7
-rw-r--r--drivers/gpu/drm/msm/adreno/adreno_gpu.c2
-rw-r--r--drivers/gpu/drm/msm/dsi/dsi_host.c5
-rw-r--r--drivers/gpu/drm/msm/hdmi-staging/sde_hdmi.c47
-rw-r--r--drivers/gpu/drm/msm/hdmi-staging/sde_hdmi.h3
-rw-r--r--drivers/gpu/drm/msm/hdmi-staging/sde_hdmi_bridge.c2
-rw-r--r--drivers/gpu/drm/msm/mdp/mdp4/mdp4_crtc.c2
-rw-r--r--drivers/gpu/drm/msm/mdp/mdp4/mdp4_kms.c2
-rw-r--r--drivers/gpu/drm/msm/msm_drv.c35
-rw-r--r--drivers/gpu/drm/msm/msm_drv.h25
-rw-r--r--drivers/gpu/drm/msm/msm_fbdev.c6
-rw-r--r--drivers/gpu/drm/msm/msm_gem.c634
-rw-r--r--drivers/gpu/drm/msm/msm_gem.h31
-rw-r--r--drivers/gpu/drm/msm/msm_gem_submit.c28
-rw-r--r--drivers/gpu/drm/msm/msm_gem_vma.c68
-rw-r--r--drivers/gpu/drm/msm/msm_gpu.c7
-rw-r--r--drivers/gpu/drm/msm/msm_rd.c2
-rw-r--r--drivers/gpu/drm/msm/msm_ringbuffer.c5
-rw-r--r--drivers/gpu/drm/msm/msm_smmu.c56
-rw-r--r--drivers/gpu/msm/kgsl_sharedmem.c57
-rw-r--r--drivers/hwtracing/coresight/coresight-stm.c3
-rw-r--r--drivers/input/touchscreen/synaptics_dsx/Kconfig22
-rw-r--r--drivers/input/touchscreen/synaptics_dsx/Makefile2
-rwxr-xr-xdrivers/input/touchscreen/synaptics_dsx/synaptics_dsx_proximity.c671
-rw-r--r--drivers/input/touchscreen/synaptics_dsx/synaptics_dsx_rmi_dev.c810
-rw-r--r--drivers/iommu/arm-smmu.c196
-rw-r--r--drivers/iommu/io-pgtable-arm.c31
-rw-r--r--drivers/iommu/io-pgtable.h1
-rw-r--r--drivers/iommu/iommu-debug.c402
-rw-r--r--drivers/iommu/iommu-debug.h23
-rw-r--r--drivers/iommu/iommu.c3
-rw-r--r--drivers/leds/leds-qpnp-flash-v2.c3
-rw-r--r--drivers/md/dm-android-verity.c2
-rw-r--r--drivers/md/dm.c5
-rw-r--r--drivers/media/Kconfig4
-rw-r--r--drivers/media/Makefile4
-rw-r--r--drivers/media/cec-notifier.c129
-rw-r--r--drivers/media/cec/cec-core.c22
-rw-r--r--drivers/media/i2c/adv7481.c1619
-rw-r--r--drivers/media/i2c/adv7481_reg.h702
-rw-r--r--drivers/media/platform/msm/ais/common/cam_soc_api.c14
-rw-r--r--drivers/media/platform/msm/ais/isp/msm_buf_mgr.c26
-rw-r--r--drivers/media/platform/msm/ais/msm_buf_mgr/msm_generic_buf_mgr.c4
-rw-r--r--drivers/media/platform/msm/ais/pproc/cpp/msm_cpp.c7
-rw-r--r--drivers/media/platform/msm/ais/sensor/csiphy/msm_csiphy.c90
-rw-r--r--drivers/media/platform/msm/ais/sensor/csiphy/msm_csiphy.h4
-rw-r--r--drivers/media/platform/msm/camera_v2/common/cam_smmu_api.c90
-rw-r--r--drivers/media/platform/msm/camera_v2/common/cam_smmu_api.h26
-rw-r--r--drivers/media/platform/msm/camera_v2/isp/msm_buf_mgr.c5
-rw-r--r--drivers/media/platform/msm/camera_v2/isp/msm_isp_axi_util.c10
-rw-r--r--drivers/media/platform/msm/camera_v2/isp/msm_isp_util.c6
-rw-r--r--drivers/media/platform/msm/camera_v2/ispif/msm_ispif.c2
-rw-r--r--drivers/media/platform/msm/camera_v2/pproc/cpp/msm_cpp.c153
-rw-r--r--drivers/media/platform/msm/camera_v2/pproc/cpp/msm_cpp.h7
-rw-r--r--drivers/media/platform/msm/camera_v2/sensor/csiphy/include/msm_csiphy_5_0_1_hwreg.h2
-rw-r--r--drivers/media/platform/msm/camera_v2/sensor/csiphy/include/msm_csiphy_5_0_hwreg.h2
-rw-r--r--drivers/media/platform/msm/camera_v2/sensor/csiphy/msm_csiphy.c18
-rw-r--r--drivers/media/platform/msm/camera_v2/sensor/csiphy/msm_csiphy.h2
-rw-r--r--drivers/media/platform/msm/sde/Kconfig12
-rw-r--r--drivers/media/platform/msm/sde/Makefile1
-rw-r--r--drivers/media/platform/msm/sde/cec/Makefile3
-rw-r--r--drivers/media/platform/msm/sde/cec/sde_hdmi_cec.c429
-rw-r--r--drivers/media/platform/msm/sde/cec/sde_hdmi_cec_util.c743
-rw-r--r--drivers/media/platform/msm/sde/cec/sde_hdmi_cec_util.h93
-rw-r--r--drivers/media/platform/msm/sde/rotator/sde_rotator_r1.c4
-rw-r--r--drivers/media/platform/msm/sde/rotator/sde_rotator_smmu.c7
-rw-r--r--drivers/media/platform/msm/vidc/msm_vdec.c25
-rw-r--r--drivers/media/platform/msm/vidc/msm_venc.c30
-rw-r--r--drivers/media/platform/msm/vidc/msm_vidc.c12
-rw-r--r--drivers/media/platform/msm/vidc/msm_vidc_debug.c25
-rw-r--r--drivers/media/platform/msm/vidc/msm_vidc_res_parse.c7
-rw-r--r--drivers/mfd/wcd9xxx-irq.c30
-rw-r--r--drivers/misc/qcom/qdsp6v2/audio_utils_aio.c3
-rw-r--r--drivers/misc/qseecom.c2
-rw-r--r--drivers/mmc/card/block.c2
-rw-r--r--drivers/mmc/core/core.c42
-rw-r--r--drivers/mmc/core/debugfs.c11
-rw-r--r--drivers/mmc/host/sdhci-msm.c10
-rw-r--r--drivers/net/wireless/ath/regd.c18
-rw-r--r--drivers/net/wireless/ath/wil6210/cfg80211.c550
-rw-r--r--drivers/net/wireless/ath/wil6210/ioctl.c4
-rw-r--r--drivers/net/wireless/ath/wil6210/pcie_bus.c17
-rw-r--r--drivers/net/wireless/ath/wil6210/pm.c34
-rw-r--r--drivers/net/wireless/ath/wil6210/txrx.c5
-rw-r--r--drivers/net/wireless/ath/wil6210/wil6210.h4
-rw-r--r--drivers/net/wireless/ath/wil6210/wmi.c4
-rw-r--r--drivers/perf/Makefile1
-rw-r--r--drivers/perf/perf_event_armv8.c (renamed from arch/arm64/kernel/perf_event.c)37
-rw-r--r--drivers/phy/phy-qcom-ufs-qmp-v3.h6
-rw-r--r--drivers/pinctrl/qcom/pinctrl-lpi.c5
-rw-r--r--drivers/platform/msm/ipa/ipa_v2/ipa.c3
-rw-r--r--drivers/platform/msm/ipa/ipa_v2/ipa_dp.c55
-rw-r--r--drivers/platform/msm/ipa/ipa_v2/ipa_flt.c6
-rw-r--r--drivers/platform/msm/ipa/ipa_v2/ipa_hdr.c6
-rw-r--r--drivers/platform/msm/ipa/ipa_v2/ipa_nat.c17
-rw-r--r--drivers/platform/msm/ipa/ipa_v2/ipa_rt.c3
-rw-r--r--drivers/platform/msm/ipa/ipa_v2/ipa_utils.c3
-rw-r--r--drivers/platform/msm/ipa/ipa_v3/ipa_dp.c68
-rw-r--r--drivers/platform/msm/ipa/ipa_v3/ipa_hdr.c7
-rw-r--r--drivers/platform/msm/mhi/mhi_bhi.c119
-rw-r--r--drivers/platform/msm/mhi/mhi_bhi.h1
-rw-r--r--drivers/platform/msm/mhi/mhi_iface.c49
-rw-r--r--drivers/platform/msm/mhi/mhi_macros.h4
-rw-r--r--drivers/platform/msm/mhi/mhi_main.c49
-rw-r--r--drivers/platform/msm/mhi/mhi_pm.c105
-rw-r--r--drivers/platform/msm/mhi/mhi_states.c29
-rw-r--r--drivers/platform/msm/mhi_uci/mhi_uci.c200
-rw-r--r--drivers/power/qcom/debug_core.c6
-rw-r--r--drivers/power/supply/qcom/battery.c5
-rw-r--r--drivers/power/supply/qcom/fg-core.h13
-rw-r--r--drivers/power/supply/qcom/qpnp-fg-gen3.c252
-rw-r--r--drivers/power/supply/qcom/qpnp-smb2.c15
-rw-r--r--drivers/power/supply/qcom/smb-lib.c176
-rw-r--r--drivers/power/supply/qcom/smb-lib.h8
-rw-r--r--drivers/power/supply/qcom/smb-reg.h2
-rw-r--r--drivers/power/supply/qcom/smb1351-charger.c4
-rw-r--r--drivers/power/supply/qcom/smb138x-charger.c9
-rw-r--r--drivers/regulator/cpr3-hmss-regulator.c4
-rw-r--r--drivers/regulator/cpr3-regulator.c3
-rw-r--r--drivers/regulator/cprh-kbss-regulator.c2
-rw-r--r--drivers/regulator/qpnp-regulator.c99
-rw-r--r--drivers/regulator/rpm-smd-regulator.c59
-rw-r--r--drivers/regulator/spm-regulator.c309
-rw-r--r--drivers/scsi/ufs/ufshcd.c6
-rw-r--r--drivers/soc/qcom/glink_smem_native_xprt.c2
-rw-r--r--drivers/soc/qcom/ipc_router_glink_xprt.c21
-rw-r--r--drivers/soc/qcom/msm_bus/msm_bus_rules.c2
-rw-r--r--drivers/soc/qcom/peripheral-loader.c9
-rw-r--r--drivers/soc/qcom/pil-msa.c4
-rw-r--r--drivers/soc/qcom/pil-q6v5.c2
-rw-r--r--drivers/soc/qcom/qbt1000.c13
-rw-r--r--drivers/soc/qcom/qdsp6v2/apr.c15
-rw-r--r--drivers/soc/qcom/smp2p_sleepstate.c3
-rw-r--r--drivers/soc/qcom/spcom.c8
-rw-r--r--drivers/soc/qcom/subsys-pil-tz.c1
-rw-r--r--drivers/soc/qcom/subsystem_restart.c3
-rw-r--r--drivers/soundwire/swr-wcd-ctrl.c2
-rw-r--r--drivers/staging/android/lowmemorykiller.c2
-rw-r--r--drivers/thermal/msm-tsens.c2
-rw-r--r--drivers/usb/dwc3/dwc3-msm.c13
-rw-r--r--drivers/usb/gadget/function/f_audio_source.c8
-rw-r--r--drivers/usb/host/xhci-hub.c12
-rw-r--r--drivers/usb/pd/policy_engine.c130
-rw-r--r--drivers/usb/pd/qpnp-pdphy.c32
-rw-r--r--drivers/usb/pd/usbpd.h7
-rw-r--r--drivers/video/fbdev/core/fbmem.c7
-rw-r--r--drivers/video/fbdev/msm/mdss_dba_utils.c3
-rw-r--r--drivers/video/fbdev/msm/mdss_dp_util.c2
-rw-r--r--drivers/video/fbdev/msm/mdss_dsi.c13
-rw-r--r--drivers/video/fbdev/msm/mdss_dsi.h2
-rw-r--r--drivers/video/fbdev/msm/mdss_dsi_host.c2
-rw-r--r--drivers/video/fbdev/msm/mdss_dsi_panel.c35
-rw-r--r--drivers/video/fbdev/msm/mdss_fb.c10
-rw-r--r--drivers/video/fbdev/msm/mdss_hdmi_edid.c33
-rw-r--r--drivers/video/fbdev/msm/mdss_hdmi_edid.h6
-rw-r--r--drivers/video/fbdev/msm/mdss_hdmi_tx.c21
-rw-r--r--drivers/video/fbdev/msm/mdss_hdmi_util.c4
-rw-r--r--drivers/video/fbdev/msm/mdss_mdp.c1
-rw-r--r--drivers/video/fbdev/msm/mdss_mdp.h4
-rw-r--r--drivers/video/fbdev/msm/mdss_mdp_ctl.c20
-rw-r--r--drivers/video/fbdev/msm/mdss_mdp_intf_video.c14
-rw-r--r--drivers/video/fbdev/msm/mdss_mdp_layer.c9
-rw-r--r--drivers/video/fbdev/msm/mdss_mdp_util.c4
-rw-r--r--drivers/video/fbdev/msm/mdss_panel.h3
-rw-r--r--drivers/video/fbdev/msm/mdss_rotator.c2
-rw-r--r--fs/proc/task_mmu.c3
-rw-r--r--include/drm/drm_mm.h15
-rw-r--r--include/linux/ipc_router.h12
-rw-r--r--include/linux/ipc_router_xprt.h6
-rw-r--r--include/linux/mmc/host.h2
-rw-r--r--include/linux/msm_mhi.h141
-rw-r--r--include/linux/sched.h4
-rw-r--r--include/linux/sde_io_util.h2
-rw-r--r--include/media/cec-notifier.h111
-rw-r--r--include/media/cec.h10
-rw-r--r--include/sound/apr_audio-v2.h5
-rw-r--r--include/sound/q6adm-v2.h1
-rw-r--r--include/trace/events/sched.h14
-rw-r--r--include/trace/events/trace_msm_pil_event.h88
-rw-r--r--include/uapi/drm/msm_drm.h12
-rw-r--r--include/uapi/linux/spcom.h8
-rw-r--r--kernel/irq/msi.c2
-rw-r--r--kernel/sched/core_ctl.c79
-rw-r--r--kernel/sched/fair.c12
-rw-r--r--kernel/sched/hmp.c78
-rw-r--r--kernel/sched/sched.h9
-rw-r--r--kernel/sched/sched_avg.c40
-rw-r--r--kernel/time/hrtimer.c49
-rw-r--r--kernel/time/posix-cpu-timers.c2
-rw-r--r--net/ipc_router/ipc_router_core.c28
-rw-r--r--net/netfilter/xt_HARDIDLETIMER.c4
-rw-r--r--net/netfilter/xt_IDLETIMER.c2
-rw-r--r--net/sched/sch_api.c5
-rw-r--r--net/unix/af_unix.c2
-rw-r--r--sound/soc/codecs/msm_sdw/msm-sdw-tables.c97
-rw-r--r--sound/soc/codecs/msm_sdw/msm_sdw.h1
-rw-r--r--sound/soc/codecs/msm_sdw/msm_sdw_cdc.c4
-rw-r--r--sound/soc/codecs/msm_sdw/msm_sdw_regmap.c8
-rw-r--r--sound/soc/codecs/sdm660_cdc/msm-analog-cdc.c4
-rw-r--r--sound/soc/codecs/sdm660_cdc/msm-cdc-common.h3
-rw-r--r--sound/soc/codecs/sdm660_cdc/msm-digital-cdc.c29
-rw-r--r--sound/soc/codecs/sdm660_cdc/sdm660-regmap.c137
-rw-r--r--sound/soc/codecs/wcd9335.c3
-rw-r--r--sound/soc/codecs/wcd934x/wcd934x.c46
-rw-r--r--sound/soc/msm/apq8096-auto.c6
-rw-r--r--sound/soc/msm/msm-dai-fe.c2
-rw-r--r--sound/soc/msm/msm8998.c36
-rw-r--r--sound/soc/msm/qdsp6v2/Makefile2
-rw-r--r--sound/soc/msm/qdsp6v2/msm-compress-q6-v2.c68
-rw-r--r--sound/soc/msm/qdsp6v2/msm-lsm-client.c34
-rw-r--r--sound/soc/msm/qdsp6v2/msm-pcm-loopback-v2.c68
-rw-r--r--sound/soc/msm/qdsp6v2/msm-pcm-q6-noirq.c97
-rw-r--r--sound/soc/msm/qdsp6v2/msm-pcm-q6-v2.c68
-rw-r--r--sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c98
-rw-r--r--sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.h13
-rw-r--r--sound/soc/msm/qdsp6v2/msm-transcode-loopback-q6-v2.c971
-rw-r--r--sound/soc/msm/qdsp6v2/q6adm.c10
-rw-r--r--sound/soc/msm/qdsp6v2/q6asm.c56
290 files changed, 11510 insertions, 4849 deletions
diff --git a/Documentation/devicetree/bindings/arm/cpus.txt b/Documentation/devicetree/bindings/arm/cpus.txt
index 9a9c045dbf6a..0d7034e20d8d 100644
--- a/Documentation/devicetree/bindings/arm/cpus.txt
+++ b/Documentation/devicetree/bindings/arm/cpus.txt
@@ -190,6 +190,7 @@ nodes to be present and contain the properties described below.
"allwinner,sun6i-a31"
"allwinner,sun8i-a23"
"arm,psci"
+ "psci"
"brcm,brahma-b15"
"marvell,armada-375-smp"
"marvell,armada-380-smp"
diff --git a/Documentation/devicetree/bindings/arm/msm/adv7481.txt b/Documentation/devicetree/bindings/arm/msm/adv7481.txt
new file mode 100644
index 000000000000..974c0877ac30
--- /dev/null
+++ b/Documentation/devicetree/bindings/arm/msm/adv7481.txt
@@ -0,0 +1,54 @@
+ADV7481 chip driver (VIDEO_ADV7481)
+
+VIDEO_ADV7481 is a kernel platform driver that is used for video decoder
+and dual mode HDMI/MHL receiver.
+
+The devicetree representation of the VIDEO_ADV7481 block should be:
+
+Required properties
+
+- compatible: "qcom,adv7481"
+- reg: The i2c slave address of adv7481 device.
+- qcom,cci-master: The i2c master id to be used for adv7481 driver.
+- gpios: The GPIOs required to be configured for the driver. It should
+ be in the order I2C data line, i2c clock line, reset line,
+ interrupt 1, interrupt 2 and interrupt 3.
+- cam_vdig-supply: Should contain regulator to be used for the digital
+ vdd.
+- cam_vio-supply: Should contain regulator to be used for the IO vdd.
+- cam_vana-supply: Should contain regulator from which analog voltage
+ is supplied.
+- qcom,cam-vreg-name: Should specify array of regulator names required
+ for the device.
+- qcom,cam-vreg-min-voltage: Should specify array of minimum voltage
+ level in uV for the regulators specified in the property
+ "qcom,cam-vreg-name".
+- qcom,cam-vreg-max-voltage: Should specify array of maximum voltage
+ level in uV for the regulators specified in the property
+ "qcom,cam-vreg-name".
+- qcom,cam-vreg-op-mode: Should specify array of current level in uA
+ for the regulators specified in the property "qcom,cam-vreg-name".
+
+Example:
+
+ qcom,adv7481@70 {
+ compatible = "qcom,adv7481";
+ reg = <0x70 0xff>;
+ cam_vdig-supply = <&vph_pwr_vreg>;
+ /* Cameras powered by PMIC: */
+ cam_vio-supply = <&pm8994_lvs1>;
+ cam_vana-supply = <&pm8994_l17>;
+ /* Self-powered cameras: */
+ qcom,cam-vreg-name = "cam_vdig", "cam_vio", "cam_vana";
+ qcom,cam-vreg-min-voltage = <1300000 0 2500000>;
+ qcom,cam-vreg-max-voltage = <1300000 0 2500000>;
+ qcom,cam-vreg-op-mode = <105000 0 80000>;
+ qcom,cci-master = <0>;
+ qcom,slave-addr = <0x70>;
+ gpios = <&tlmm 17 0>, /* I2C SDA */
+ <&tlmm 18 0>, /* I2C SCL */
+ <&pm8994_gpios 4 0>, /* RST */
+ <&pm8994_gpios 5 0>, /* INT1 */
+ <&pm8994_gpios 6 0>, /* INT2 */
+ <&pm8994_gpios 7 0>; /* INT3 */
+ };
diff --git a/Documentation/devicetree/bindings/arm/msm/android.txt b/Documentation/devicetree/bindings/arm/msm/android.txt
new file mode 100644
index 000000000000..db52284892af
--- /dev/null
+++ b/Documentation/devicetree/bindings/arm/msm/android.txt
@@ -0,0 +1,54 @@
+Android firmware
+
+Node to specify early mount of vendor partition.
+
+Required properties
+
+-compatible: "android,firmware"
+
+Child nodes:
+------------
+
+fstab:
+------------------------------
+
+fstab entry to specify mount attributes of vendor partition.
+
+Required properties:
+
+-compatible: "android,fstab"
+
+Child nodes:
+------------
+
+vendor:
+-----------------
+
+vendor partition specification.
+
+Required properties:
+
+-compatible: "android, vendor"
+-dev: block device corresponding to vendor partition
+-type: file system type of vendor partition
+-mnt_flags: mount flags
+-fsmgr_flags: fsmgr flags
+
+Example:
+
+ firmware: firmware {
+ android {
+ compatible = "android,firmware";
+ fstab {
+ compatible = "android,fstab";
+ vendor {
+ compatible = "android,vendor";
+ dev = "/dev/block/platform/soc/1da4000.ufshc/by-name/vendor";
+ type = "ext4";
+ mnt_flags = "ro,barrier=1,discard";
+ fsmgr_flags = "wait,slotselect";
+ status = "ok";
+ };
+ };
+ };
+ };
diff --git a/Documentation/devicetree/bindings/arm/msm/msm_ipc_router_glink_xprt.txt b/Documentation/devicetree/bindings/arm/msm/msm_ipc_router_glink_xprt.txt
index 9e1d230432cf..c5d052cd6039 100644
--- a/Documentation/devicetree/bindings/arm/msm/msm_ipc_router_glink_xprt.txt
+++ b/Documentation/devicetree/bindings/arm/msm/msm_ipc_router_glink_xprt.txt
@@ -17,6 +17,8 @@ Optional properties:
by pil. Absence of this property indicates that
subsystem loading through pil voting is disabled for
that subsystem.
+-qcom,dynamic-wakeup-source: Boolean property to indicate that G-Link
+ transport supports dynamic wakeup source
Example:
qcom,ipc_router_modem_xprt {
diff --git a/Documentation/devicetree/bindings/display/msm/cec.txt b/Documentation/devicetree/bindings/display/msm/cec.txt
new file mode 100644
index 000000000000..e5282f1f5e9e
--- /dev/null
+++ b/Documentation/devicetree/bindings/display/msm/cec.txt
@@ -0,0 +1,75 @@
+Qualcomm Technologies, Inc. CEC device
+
+CEC is a protocol that provides high-level control functions between all of the
+various audiovisual products in a user environment.
+
+Required properties:
+- compatible: Must be "qcom,hdmi-cec".
+- qcom,hdmi-dev: Phandle for the hdmi device node.
+- interrupt-parent: Must be the hdmi interrupt controller.
+- interrupts: Interrupt associated with cec.
+- reg: Physical base address and length of the controller's registers.
+- reg-names: "hdmi_cec".
+- clocks: List of Phandles for clock device nodes needed by the device.
+- clock-names: List of clock names needed by the device.
+- pinctrl-names: Should contain only two values: "cec_active" and "cec_sleep" which stands for the
+ active and sleep state of pinctrl used in this CEC driver.
+- pinctrl-0: The active pinctrl state which is a list of phandles pointing to a pin configuration node.
+- pinctrl-1: The sleep pinctrl state which is a list of phandles pointing to a pin configuration node.
+- cec-gdsc-supply: Phandle for cec gdsc supply regulator device node.
+- qcom,platform-supply-entries: A sub node that lists the elements of the supply. There can be more
+ than one instance of this binding, in which case the entry would be
+ appended with the supply entry index. e.g. qcom,platform-supply-entry@0.
+ -- reg: offset and length of the register set for the device.
+ -- qcom,supply-name: name of the supply (vdd/vdda/vddio).
+ -- qcom,supply-min-voltage: minimum voltage level (uV).
+ -- qcom,supply-max-voltage: maximum voltage level (uV).
+ -- qcom,supply-enable-load: load drawn (uA) from enabled supply.
+ -- qcom,supply-disable-load: load drawn (uA) from disabled supply.
+
+
+Optional properties:
+- qcom,platform-supply-entries: A sub node that lists the elements of the supply. There can be more
+ than one instance of this binding, in which case the entry would be
+ appended with the supply entry index. e.g. qcom,platform-supply-entry@0.
+ -- qcom,supply-pre-on-sleep: time to sleep (ms) before turning on.
+ -- qcom,supply-post-on-sleep: time to sleep (ms) after turning on.
+ -- qcom,supply-pre-off-sleep: time to sleep (ms) before turning off.
+ -- qcom,supply-post-off-sleep: time to sleep (ms) after turning off.
+
+Example:
+
+sde_hdmi_cec: qcom,hdmi-cec@c9a0000 {
+ compatible = "qcom,hdmi-cec";
+ label = "sde_hdmi_cec";
+ qcom,hdmi-dev = <&sde_hdmi>;
+ interrupt-parent = <&sde_hdmi_tx>;
+ interrupts = <1 0>;
+
+ reg = <0xc9a0000 0x50c>;
+ reg-names = "hdmi_cec";
+
+ clocks = <&clock_mmss clk_mmss_mnoc_ahb_clk>,
+ <&clock_mmss clk_mmss_mdss_ahb_clk>,
+ <&clock_mmss clk_mmss_mdss_hdmi_clk>;
+ clock-names = "cec_mnoc_clk", "cec_iface_clk", "cec_core_clk";
+
+ pinctrl-names = "cec_active", "cec_sleep";
+ pinctrl-0 = <&mdss_hdmi_cec_active>;
+ pinctrl-1 = <&mdss_hdmi_cec_suspend>;
+
+ cec-gdsc-supply = <&gdsc_mdss>;
+ qcom,platform-supply-entries {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ qcom,platform-supply-entry@0 {
+ reg = <0>;
+ qcom,supply-name = "cec-gdsc";
+ qcom,supply-min-voltage = <0>;
+ qcom,supply-max-voltage = <0>;
+ qcom,supply-enable-load = <0>;
+ qcom,supply-disable-load = <0>;
+ };
+ };
+};
diff --git a/Documentation/devicetree/bindings/fb/mdss-dsi.txt b/Documentation/devicetree/bindings/fb/mdss-dsi.txt
index 0d55389f3790..f28de379f84c 100644
--- a/Documentation/devicetree/bindings/fb/mdss-dsi.txt
+++ b/Documentation/devicetree/bindings/fb/mdss-dsi.txt
@@ -105,7 +105,9 @@ Optional properties:
- qcom,platform-reset-gpio: Specifies the panel reset gpio.
- qcom,platform-te-gpio: Specifies the gpio used for TE.
- qcom,platform-bklight-en-gpio: Specifies the gpio used to enable display back-light
-- qcom,platform-bklight-en-gpio-invert: Invert the gpio used to enable display back-light
+- qcom,platform-bklight-en-gpio-invert: Boolean to invert the gpio used to enable display back-light
+- qcom,platform-avdd-en-gpio: Specifies the gpio used to enable AMOLED AVDD
+- qcom,platform-avdd-en-gpio-invert: Boolean to invert the gpio used to enable AMOLED AVDD
- qcom,panel-mode-gpio: Specifies the GPIO to select video/command/single-port/dual-port
mode of panel through gpio when it supports these modes.
- pinctrl-names: List of names to assign mdss pin states defined in pinctrl device node
diff --git a/Documentation/devicetree/bindings/fb/mdss-pll.txt b/Documentation/devicetree/bindings/fb/mdss-pll.txt
index 2e9d2dae51a2..4ba9060222c2 100644
--- a/Documentation/devicetree/bindings/fb/mdss-pll.txt
+++ b/Documentation/devicetree/bindings/fb/mdss-pll.txt
@@ -15,9 +15,10 @@ Required properties:
"qcom,mdss_hdmi_pll_8996_v2", "qcom,mdss_dsi_pll_8996_v2",
"qcom,mdss_hdmi_pll_8996_v3", "qcom,mdss_hdmi_pll_8996_v3_1p8",
"qcom,mdss_dsi_pll_8998", "qcom,mdss_dp_pll_8998",
- "qcom,mdss_hdmi_pll_8998", "qcom,mdss_dsi_pll_sdm660",
- "qcom,mdss_dp_pll_sdm660", "qcom,mdss_dsi_pll_sdm630",
- "qcom,mdss_dp_pll_sdm630"
+ "qcom,mdss_hdmi_pll_8998", "qcom,mdss_hdmi_pll_8998_1p8",
+ "qcom,mdss_dsi_pll_sdm660", "qcom,mdss_dp_pll_sdm660",
+ "qcom,mdss_dsi_pll_sdm630", "qcom,mdss_dp_pll_sdm630"
+
- cell-index: Specifies the controller used
- reg: offset and length of the register set for the device.
- reg-names : names to refer to register sets related to this device
diff --git a/Documentation/devicetree/bindings/iommu/arm,smmu.txt b/Documentation/devicetree/bindings/iommu/arm,smmu.txt
index 9e512d1ea763..c16084a89ccf 100644
--- a/Documentation/devicetree/bindings/iommu/arm,smmu.txt
+++ b/Documentation/devicetree/bindings/iommu/arm,smmu.txt
@@ -121,6 +121,12 @@ conditions.
supported as we are directly comparing client SID with ID bits
of SMR registers.
+- qcom,deferred-regulator-disable-delay : The time delay for deferred regulator
+ disable in ms. In case of unmap call, regulator is
+ enabled/disabled. This may introduce additional delay. For
+ clients who do not detach, it's not possible to keep regulator
+ vote while smmu is attached. Type is <u32>.
+
- clocks : List of clocks to be used during SMMU register access. See
Documentation/devicetree/bindings/clock/clock-bindings.txt
for information about the format. For each clock specified
diff --git a/Documentation/devicetree/bindings/mhi/msm_mhi.txt b/Documentation/devicetree/bindings/mhi/msm_mhi.txt
index 5f950604d186..9c5c2fee78d0 100644
--- a/Documentation/devicetree/bindings/mhi/msm_mhi.txt
+++ b/Documentation/devicetree/bindings/mhi/msm_mhi.txt
@@ -17,7 +17,7 @@ Main node properties:
Definition: "qcom,mhi"
- qcom,pci-dev_id
- Usage: required
+ Usage: optional
Value type: <u32>
Definition: Device id reported by modem
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 12d32ec74369..012368275db3 100644
--- a/Documentation/devicetree/bindings/power/supply/qcom/qpnp-fg-gen3.txt
+++ b/Documentation/devicetree/bindings/power/supply/qcom/qpnp-fg-gen3.txt
@@ -145,22 +145,30 @@ First Level Node - FG Gen3 device
- qcom,fg-esr-timer-charging
Usage: optional
- Value type: <u32>
+ Value type: <prop-encoded-array>
Definition: Number of cycles between ESR pulses while the battery is
- charging.
+ charging. Array of 2 elements if specified.
+ Element 0 - Retry value for timer
+ Element 1 - Maximum value for timer
- qcom,fg-esr-timer-awake
Usage: optional
- Value type: <u32>
+ Value type: <prop-encoded-array>
Definition: Number of cycles between ESR pulses while the system is
- awake and the battery is discharging.
+ awake and the battery is discharging. Array of 2 elements
+ if specified.
+ Element 0 - Retry value for timer
+ Element 1 - Maximum value for timer
- qcom,fg-esr-timer-asleep
Usage: optional
- Value type: <u32>
+ Value type: <prop-encoded-array>
Definition: Number of cycles between ESR pulses while the system is
asleep and the battery is discharging. This option requires
- qcom,fg-esr-timer-awake to be defined.
+ qcom,fg-esr-timer-awake to be defined. Array of 2 elements
+ if specified.
+ Element 0 - Retry value for timer
+ Element 1 - Maximum value for timer
- qcom,fg-esr-pulse-thresh-ma
Usage: optional
diff --git a/Documentation/devicetree/bindings/regulator/rpm-smd-regulator.txt b/Documentation/devicetree/bindings/regulator/rpm-smd-regulator.txt
index 1eb27f4c1c56..559ee5b6fc08 100644
--- a/Documentation/devicetree/bindings/regulator/rpm-smd-regulator.txt
+++ b/Documentation/devicetree/bindings/regulator/rpm-smd-regulator.txt
@@ -104,6 +104,12 @@ Optional properties:
parameter. Only one pin may be specified per
regulator. This property only applies to BoB
type regulators.
+- qcom,pwm-threshold-current: Minimum current in mA which requires regulator
+ to be in PWM mode. Load currents below this
+ threshold use AUTO mode. This property only
+ applies to BoB and SMPS type regulators.
+ If this property is not specified, then the
+ hardware default mode will be used all the time.
- qcom,always-send-voltage: Flag which indicates that updates to the
voltage, voltage corner or voltage level set
point should always be sent immediately to the
diff --git a/Documentation/devicetree/bindings/sound/qcom-audio-dev.txt b/Documentation/devicetree/bindings/sound/qcom-audio-dev.txt
index dec5442b33d6..38e056cdc0ee 100644
--- a/Documentation/devicetree/bindings/sound/qcom-audio-dev.txt
+++ b/Documentation/devicetree/bindings/sound/qcom-audio-dev.txt
@@ -182,6 +182,12 @@ Optional properties:
- qcom,msm-pcm-loopback-low-latency : Flag indicating whether
the device node is of type low latency.
+* msm-transcode-loopback
+
+Required properties:
+
+ - compatible : "qcom,msm-transcode-loopback"
+
* msm-dai-q6
[First Level Nodes]
@@ -2401,14 +2407,15 @@ Example:
qcom,tasha-mclk-clk-freq = <9600000>;
asoc-platform = <&pcm0>, <&pcm1>, <&pcm2>, <&voip>, <&voice>,
<&loopback>, <&compress>, <&hostless>,
- <&afe>, <&lsm>, <&routing>, <&cpe>, <&compr>;
+ <&afe>, <&lsm>, <&routing>, <&cpe>, <&compr>,
+ <&trans_loopback>;
asoc-platform-names = "msm-pcm-dsp.0", "msm-pcm-dsp.1",
"msm-pcm-dsp.2", "msm-voip-dsp",
"msm-pcm-voice", "msm-pcm-loopback",
"msm-compress-dsp", "msm-pcm-hostless",
"msm-pcm-afe", "msm-lsm-client",
"msm-pcm-routing", "msm-cpe-lsm",
- "msm-compr-dsp";
+ "msm-compr-dsp","msm-transcode-loopback";
asoc-cpu = <&dai_hdmi>,
<&sb_0_rx>, <&sb_0_tx>, <&sb_1_rx>, <&sb_1_tx>,
<&sb_2_rx>, <&sb_2_tx>, <&sb_3_rx>, <&sb_3_tx>,
diff --git a/arch/arm/boot/dts/qcom/apq8096-auto-dragonboard.dtsi b/arch/arm/boot/dts/qcom/apq8096-auto-dragonboard.dtsi
index ea8fc87c9b67..4081a21b3134 100644
--- a/arch/arm/boot/dts/qcom/apq8096-auto-dragonboard.dtsi
+++ b/arch/arm/boot/dts/qcom/apq8096-auto-dragonboard.dtsi
@@ -339,6 +339,77 @@
&mdss_mdp {
qcom,mdss-pref-prim-intf = "dsi";
+ qcom,sde-plane-id-map {
+ qcom,sde-plane-id@0 {
+ reg = <0x0>;
+ qcom,display-type = "primary";
+ qcom,plane-name = "rgb0", "rgb1";
+ qcom,plane-type = "primary";
+ };
+
+ qcom,sde-plane-id@1 {
+ reg = <0x1>;
+ qcom,display-type = "primary";
+ qcom,plane-name = "vig0", "vig1";
+ qcom,plane-type = "overlay";
+ };
+
+ qcom,sde-plane-id@2 {
+ reg = <0x2>;
+ qcom,display-type = "primary";
+ qcom,plane-name = "cursor0";
+ qcom,plane-type = "cursor";
+ };
+
+ qcom,sde-plane-id@3 {
+ reg = <0x3>;
+ qcom,display-type = "secondary";
+ qcom,plane-name = "rgb2";
+ qcom,plane-type = "primary";
+ };
+
+ qcom,sde-plane-id@4 {
+ reg = <0x4>;
+ qcom,display-type = "secondary";
+ qcom,plane-name = "vig2";
+ qcom,plane-type = "overlay";
+ };
+
+ qcom,sde-plane-id@5 {
+ reg = <0x5>;
+ qcom,display-type = "secondary";
+ qcom,plane-name = "dma0";
+ qcom,plane-type = "overlay";
+ };
+
+ qcom,sde-plane-id@6 {
+ reg = <0x6>;
+ qcom,display-type = "secondary";
+ qcom,plane-name = "cursor1";
+ qcom,plane-type = "cursor";
+ };
+
+ qcom,sde-plane-id@7 {
+ reg = <0x7>;
+ qcom,display-type = "tertiary";
+ qcom,plane-name = "rgb3";
+ qcom,plane-type = "primary";
+ };
+
+ qcom,sde-plane-id@8 {
+ reg = <0x8>;
+ qcom,display-type = "tertiary";
+ qcom,plane-name = "vig3";
+ qcom,plane-type = "overlay";
+ };
+
+ qcom,sde-plane-id@9 {
+ reg = <0x9>;
+ qcom,display-type = "tertiary";
+ qcom,plane-name = "dma1";
+ qcom,plane-type = "overlay";
+ };
+ };
};
&mdss_dsi {
@@ -627,14 +698,14 @@
asoc-platform = <&pcm0>, <&pcm1>, <&pcm2>, <&voip>, <&voice>,
<&loopback>, <&compress>, <&hostless>,
- <&afe>, <&lsm>, <&routing>, <&compr>,
+ <&afe>, <&lsm>, <&routing>, <&pcmnoirq>,
<&loopback1>;
asoc-platform-names = "msm-pcm-dsp.0", "msm-pcm-dsp.1",
"msm-pcm-dsp.2", "msm-voip-dsp",
"msm-pcm-voice", "msm-pcm-loopback",
"msm-compress-dsp", "msm-pcm-hostless",
"msm-pcm-afe", "msm-lsm-client",
- "msm-pcm-routing", "msm-compr-dsp",
+ "msm-pcm-routing", "msm-pcm-dsp-noirq",
"msm-pcm-loopback.1";
asoc-cpu = <&dai_pri_auxpcm>, <&dai_sec_auxpcm>, <&dai_hdmi>,
<&dai_mi2s_sec>, <&dai_mi2s>, <&dai_mi2s_quat>,
@@ -796,7 +867,7 @@
qcom,vin-sel = <2>; /* 1.8 */
qcom,out-strength = <1>;
qcom,src-sel = <0>; /* GPIO */
- qcom,master-en = <1>; /* Enable GPIO */
+ qcom,master-en = <0>; /* Disable GPIO */
status = "okay";
};
diff --git a/arch/arm/boot/dts/qcom/apq8096pro-v1.1-auto-adp.dts b/arch/arm/boot/dts/qcom/apq8096pro-v1.1-auto-adp.dts
index 497f3f10fe24..840d82fa9084 100644
--- a/arch/arm/boot/dts/qcom/apq8096pro-v1.1-auto-adp.dts
+++ b/arch/arm/boot/dts/qcom/apq8096pro-v1.1-auto-adp.dts
@@ -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
@@ -22,7 +22,7 @@
model = "Qualcomm Technologies, Inc. MSM 8996pro AUTO ADP";
compatible = "qcom,apq8096-adp", "qcom,msm8996", "qcom,adp";
qcom,msm-id = <316 0x10001>;
- qcom,board-id = <0x02010019 0>;
+ qcom,board-id = <0x02010019 0>, <0x00010001 0>;
};
&spi_9 {
diff --git a/arch/arm/boot/dts/qcom/apq8096pro-v1.1-auto-cdp.dts b/arch/arm/boot/dts/qcom/apq8096pro-v1.1-auto-cdp.dts
index 2c54dfe19e18..ecde7c667f9a 100644
--- a/arch/arm/boot/dts/qcom/apq8096pro-v1.1-auto-cdp.dts
+++ b/arch/arm/boot/dts/qcom/apq8096pro-v1.1-auto-cdp.dts
@@ -1,4 +1,4 @@
-/* Copyright (c) 2015-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
@@ -21,7 +21,7 @@
model = "Qualcomm Technologies, Inc. APQ 8096 pro v1.1 AUTO CDP";
compatible = "qcom,msm8996-cdp", "qcom,msm8996", "qcom,cdp";
qcom,msm-id = <316 0x10001>;
- qcom,board-id = <0x03010001 0>;
+ qcom,board-id = <0x03010001 0>, <0x00010001 0>;
};
&spi_9 {
diff --git a/arch/arm/boot/dts/qcom/msm-arm-smmu-660.dtsi b/arch/arm/boot/dts/qcom/msm-arm-smmu-660.dtsi
index 33bd86654363..06935e80e07b 100644
--- a/arch/arm/boot/dts/qcom/msm-arm-smmu-660.dtsi
+++ b/arch/arm/boot/dts/qcom/msm-arm-smmu-660.dtsi
@@ -157,6 +157,7 @@
<GIC_SPI 117 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 349 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 350 IRQ_TYPE_LEVEL_HIGH>;
+ qcom,deferred-regulator-disable-delay = <80>;
vdd-supply = <&gdsc_gpu_cx>;
clocks = <&clock_gcc GCC_GPU_CFG_AHB_CLK>,
<&clock_gcc GCC_BIMC_GFX_CLK>,
diff --git a/arch/arm/boot/dts/qcom/msm-audio-lpass.dtsi b/arch/arm/boot/dts/qcom/msm-audio-lpass.dtsi
index d4962df321ed..7fce7606720c 100644
--- a/arch/arm/boot/dts/qcom/msm-audio-lpass.dtsi
+++ b/arch/arm/boot/dts/qcom/msm-audio-lpass.dtsi
@@ -85,6 +85,10 @@
compatible = "qcom,msm-pcm-loopback";
};
+ trans_loopback: qcom,msm-transcode-loopback {
+ compatible = "qcom,msm-transcode-loopback";
+ };
+
qcom,msm-dai-mi2s {
compatible = "qcom,msm-dai-mi2s";
dai_mi2s0: qcom,msm-dai-q6-mi2s-prim {
diff --git a/arch/arm/boot/dts/qcom/msm-pm660.dtsi b/arch/arm/boot/dts/qcom/msm-pm660.dtsi
index 05225f7178e9..93aeef07cfe0 100644
--- a/arch/arm/boot/dts/qcom/msm-pm660.dtsi
+++ b/arch/arm/boot/dts/qcom/msm-pm660.dtsi
@@ -550,9 +550,9 @@
io-channel-names = "rradc_batt_id",
"rradc_die_temp";
qcom,rradc-base = <0x4500>;
- qcom,fg-esr-timer-awake = <96>;
- qcom,fg-esr-timer-asleep = <256>;
- qcom,fg-esr-timer-charging = <96>;
+ qcom,fg-esr-timer-awake = <96 96>;
+ qcom,fg-esr-timer-asleep = <256 256>;
+ qcom,fg-esr-timer-charging = <0 96>;
qcom,cycle-counter-en;
status = "okay";
diff --git a/arch/arm/boot/dts/qcom/msm-pmi8998.dtsi b/arch/arm/boot/dts/qcom/msm-pmi8998.dtsi
index 2b0fcb77eaf2..684f6cf9b389 100644
--- a/arch/arm/boot/dts/qcom/msm-pmi8998.dtsi
+++ b/arch/arm/boot/dts/qcom/msm-pmi8998.dtsi
@@ -337,8 +337,9 @@
io-channels = <&pmi8998_rradc 0>;
io-channel-names = "rradc_batt_id";
qcom,rradc-base = <0x4500>;
- qcom,fg-esr-timer-awake = <96>;
- qcom,fg-esr-timer-asleep = <256>;
+ qcom,fg-esr-timer-awake = <96 96>;
+ qcom,fg-esr-timer-asleep = <256 256>;
+ qcom,fg-esr-timer-charging = <0 96>;
qcom,cycle-counter-en;
status = "okay";
diff --git a/arch/arm/boot/dts/qcom/msm8996-agave-adp.dtsi b/arch/arm/boot/dts/qcom/msm8996-agave-adp.dtsi
index eae8c29fe21e..a600008341c2 100644
--- a/arch/arm/boot/dts/qcom/msm8996-agave-adp.dtsi
+++ b/arch/arm/boot/dts/qcom/msm8996-agave-adp.dtsi
@@ -548,6 +548,77 @@
&mdss_mdp {
qcom,mdss-pref-prim-intf = "dsi";
+ qcom,sde-plane-id-map {
+ qcom,sde-plane-id@0 {
+ reg = <0x0>;
+ qcom,display-type = "primary";
+ qcom,plane-name = "rgb0", "rgb1";
+ qcom,plane-type = "primary";
+ };
+
+ qcom,sde-plane-id@1 {
+ reg = <0x1>;
+ qcom,display-type = "primary";
+ qcom,plane-name = "vig0", "vig1";
+ qcom,plane-type = "overlay";
+ };
+
+ qcom,sde-plane-id@2 {
+ reg = <0x2>;
+ qcom,display-type = "primary";
+ qcom,plane-name = "cursor0";
+ qcom,plane-type = "cursor";
+ };
+
+ qcom,sde-plane-id@3 {
+ reg = <0x3>;
+ qcom,display-type = "secondary";
+ qcom,plane-name = "rgb2";
+ qcom,plane-type = "primary";
+ };
+
+ qcom,sde-plane-id@4 {
+ reg = <0x4>;
+ qcom,display-type = "secondary";
+ qcom,plane-name = "vig2";
+ qcom,plane-type = "overlay";
+ };
+
+ qcom,sde-plane-id@5 {
+ reg = <0x5>;
+ qcom,display-type = "secondary";
+ qcom,plane-name = "dma0";
+ qcom,plane-type = "overlay";
+ };
+
+ qcom,sde-plane-id@6 {
+ reg = <0x6>;
+ qcom,display-type = "secondary";
+ qcom,plane-name = "cursor1";
+ qcom,plane-type = "cursor";
+ };
+
+ qcom,sde-plane-id@7 {
+ reg = <0x7>;
+ qcom,display-type = "tertiary";
+ qcom,plane-name = "rgb3";
+ qcom,plane-type = "primary";
+ };
+
+ qcom,sde-plane-id@8 {
+ reg = <0x8>;
+ qcom,display-type = "tertiary";
+ qcom,plane-name = "vig3";
+ qcom,plane-type = "overlay";
+ };
+
+ qcom,sde-plane-id@9 {
+ reg = <0x9>;
+ qcom,display-type = "tertiary";
+ qcom,plane-name = "dma1";
+ qcom,plane-type = "overlay";
+ };
+ };
};
&dsi_adv_7533_1 {
@@ -797,6 +868,13 @@
qcom,ntn-rst-delay-msec = <100>;
qcom,ntn-rc-num = <1>;
+
+ 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>;
};
i2c@75ba000 {
@@ -919,14 +997,14 @@
asoc-platform = <&pcm0>, <&pcm1>, <&pcm2>, <&voip>, <&voice>,
<&loopback>, <&compress>, <&hostless>,
- <&afe>, <&lsm>, <&routing>, <&compr>,
+ <&afe>, <&lsm>, <&routing>, <&pcmnoirq>,
<&loopback1>;
asoc-platform-names = "msm-pcm-dsp.0", "msm-pcm-dsp.1",
"msm-pcm-dsp.2", "msm-voip-dsp",
"msm-pcm-voice", "msm-pcm-loopback",
"msm-compress-dsp", "msm-pcm-hostless",
"msm-pcm-afe", "msm-lsm-client",
- "msm-pcm-routing", "msm-compr-dsp",
+ "msm-pcm-routing", "msm-pcm-dsp-noirq",
"msm-pcm-loopback.1";
asoc-cpu = <&dai_pri_auxpcm>, <&dai_sec_auxpcm>, <&dai_hdmi>,
<&dai_mi2s_sec>, <&dai_mi2s>, <&dai_mi2s_quat>,
@@ -1112,7 +1190,7 @@
qcom,vin-sel = <2>; /* 1.8 */
qcom,out-strength = <1>;
qcom,src-sel = <0>; /* GPIO */
- qcom,master-en = <1>; /* Enable GPIO */
+ qcom,master-en = <0>; /* Disable GPIO */
status = "okay";
};
@@ -1160,9 +1238,6 @@
&usb2s {
status = "ok";
- dwc3@7600000 {
- dr_mode = "host";
- };
};
&usb3 {
diff --git a/arch/arm/boot/dts/qcom/msm8996-auto-cdp.dtsi b/arch/arm/boot/dts/qcom/msm8996-auto-cdp.dtsi
index a1299027ae18..7c07102a1fed 100644
--- a/arch/arm/boot/dts/qcom/msm8996-auto-cdp.dtsi
+++ b/arch/arm/boot/dts/qcom/msm8996-auto-cdp.dtsi
@@ -302,7 +302,7 @@
&mdss_hdmi_cec_suspend>;
};
-#include "msm8996-mdss-panels.dtsi"
+#include "msm8996-sde-display.dtsi"
&pmx_mdss {
mdss_dsi_active: mdss_dsi_active {
@@ -335,32 +335,201 @@
&mdss_mdp {
qcom,mdss-pref-prim-intf = "dsi";
+ qcom,sde-plane-id-map {
+ qcom,sde-plane-id@0 {
+ reg = <0x0>;
+ qcom,display-type = "primary";
+ qcom,plane-name = "rgb0", "rgb1";
+ qcom,plane-type = "primary";
+ };
+
+ qcom,sde-plane-id@1 {
+ reg = <0x1>;
+ qcom,display-type = "primary";
+ qcom,plane-name = "vig0", "vig1";
+ qcom,plane-type = "overlay";
+ };
+
+ qcom,sde-plane-id@2 {
+ reg = <0x2>;
+ qcom,display-type = "primary";
+ qcom,plane-name = "cursor0";
+ qcom,plane-type = "cursor";
+ };
+
+ qcom,sde-plane-id@3 {
+ reg = <0x3>;
+ qcom,display-type = "secondary";
+ qcom,plane-name = "rgb2";
+ qcom,plane-type = "primary";
+ };
+
+ qcom,sde-plane-id@4 {
+ reg = <0x4>;
+ qcom,display-type = "secondary";
+ qcom,plane-name = "vig2";
+ qcom,plane-type = "overlay";
+ };
+
+ qcom,sde-plane-id@5 {
+ reg = <0x5>;
+ qcom,display-type = "secondary";
+ qcom,plane-name = "dma0";
+ qcom,plane-type = "overlay";
+ };
+
+ qcom,sde-plane-id@6 {
+ reg = <0x6>;
+ qcom,display-type = "secondary";
+ qcom,plane-name = "cursor1";
+ qcom,plane-type = "cursor";
+ };
+
+ qcom,sde-plane-id@7 {
+ reg = <0x7>;
+ qcom,display-type = "tertiary";
+ qcom,plane-name = "rgb3";
+ qcom,plane-type = "primary";
+ };
+
+ qcom,sde-plane-id@8 {
+ reg = <0x8>;
+ qcom,display-type = "tertiary";
+ qcom,plane-name = "vig3";
+ qcom,plane-type = "overlay";
+ };
+
+ qcom,sde-plane-id@9 {
+ reg = <0x9>;
+ qcom,display-type = "tertiary";
+ qcom,plane-name = "dma1";
+ qcom,plane-type = "overlay";
+ };
+ };
+};
+
+&dsi_adv_7533_1 {
+ qcom,dsi-display-active;
+ qcom,dsi-panel = <&dsi_adv7533_1080p>;
+
+ qcom,panel-supply-entries {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ qcom,panel-supply-entry@0 {
+ reg = <0>;
+ qcom,supply-name = "vdd";
+ qcom,supply-min-voltage = <3300000>;
+ qcom,supply-max-voltage = <3300000>;
+ qcom,supply-enable-load = <100000>;
+ qcom,supply-disable-load = <100>;
+ };
+
+ qcom,panel-supply-entry@1 {
+ reg = <1>;
+ qcom,supply-name = "vddio";
+ qcom,supply-min-voltage = <1800000>;
+ qcom,supply-max-voltage = <1800000>;
+ qcom,supply-enable-load = <100000>;
+ qcom,supply-disable-load = <100>;
+ };
+ };
+};
+
+&dsi_adv_7533_2 {
+ qcom,dsi-display-active;
+ qcom,dsi-panel = <&dsi_adv7533_1080p>;
+
+ qcom,panel-supply-entries {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ qcom,panel-supply-entry@0 {
+ reg = <0>;
+ qcom,supply-name = "vdd";
+ qcom,supply-min-voltage = <3300000>;
+ qcom,supply-max-voltage = <3300000>;
+ qcom,supply-enable-load = <100000>;
+ qcom,supply-disable-load = <100>;
+ };
+
+ qcom,panel-supply-entry@1 {
+ reg = <1>;
+ qcom,supply-name = "vddio";
+ qcom,supply-min-voltage = <1800000>;
+ qcom,supply-max-voltage = <1800000>;
+ qcom,supply-enable-load = <100000>;
+ qcom,supply-disable-load = <100>;
+ };
+ };
};
&mdss_dsi {
- hw-config = "split_dsi";
+ hw-config = "dual_dsi";
};
&mdss_dsi0 {
- qcom,dsi-pref-prim-pan = <&dsi_dual_nt35597_video>;
+ qcom,dsi-pref-prim-pan = <&dsi_adv7533_1080p>;
pinctrl-names = "mdss_default", "mdss_sleep";
pinctrl-0 = <&mdss_dsi_active &mdss_te_active>;
pinctrl-1 = <&mdss_dsi_suspend &mdss_te_suspend>;
- qcom,platform-enable-gpio = <&tlmm 70 0>;
- qcom,platform-te-gpio = <&tlmm 10 0>;
- qcom,platform-reset-gpio = <&tlmm 8 0>;
- qcom,platform-bklight-en-gpio = <&pm8994_gpios 10 0>;
+ qcom,display-id = "primary";
+ qcom,bridge-index = <0>;
+
+ qcom,panel-supply-entries {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ qcom,panel-supply-entry@0 {
+ reg = <0>;
+ qcom,supply-name = "vdd";
+ qcom,supply-min-voltage = <3300000>;
+ qcom,supply-max-voltage = <3300000>;
+ qcom,supply-enable-load = <100000>;
+ qcom,supply-disable-load = <100>;
+ };
+
+ qcom,panel-supply-entry@1 {
+ reg = <1>;
+ qcom,supply-name = "vddio";
+ qcom,supply-min-voltage = <1800000>;
+ qcom,supply-max-voltage = <1800000>;
+ qcom,supply-enable-load = <100000>;
+ qcom,supply-disable-load = <100>;
+ };
+ };
};
&mdss_dsi1 {
- qcom,dsi-pref-prim-pan = <&dsi_dual_nt35597_video>;
+ qcom,dsi-pref-prim-pan = <&dsi_adv7533_1080p>;
pinctrl-names = "mdss_default", "mdss_sleep";
pinctrl-0 = <&mdss_dsi_active &mdss_te_active>;
pinctrl-1 = <&mdss_dsi_suspend &mdss_te_suspend>;
- qcom,platform-enable-gpio = <&tlmm 70 0>;
- qcom,platform-te-gpio = <&tlmm 10 0>;
- qcom,platform-reset-gpio = <&tlmm 8 0>;
- qcom,platform-bklight-en-gpio = <&pm8994_gpios 10 0>;
+ qcom,display-id = "tertiary";
+ qcom,bridge-index = <1>;
+
+ qcom,panel-supply-entries {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ qcom,panel-supply-entry@0 {
+ reg = <0>;
+ qcom,supply-name = "vdd";
+ qcom,supply-min-voltage = <3300000>;
+ qcom,supply-max-voltage = <3300000>;
+ qcom,supply-enable-load = <100000>;
+ qcom,supply-disable-load = <100>;
+ };
+
+ qcom,panel-supply-entry@1 {
+ reg = <1>;
+ qcom,supply-name = "vddio";
+ qcom,supply-min-voltage = <1800000>;
+ qcom,supply-max-voltage = <1800000>;
+ qcom,supply-enable-load = <100000>;
+ qcom,supply-disable-load = <100>;
+ };
+ };
};
&dsi_dual_sharp_video {
@@ -466,6 +635,13 @@
qcom,ntn-rst-delay-msec = <100>;
qcom,ntn-rc-num = <1>;
qcom,ntn-bus-num = <1>;
+
+ 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>;
};
ntn2: ntn_avb@2 { /*Neutrino device on RC2*/
@@ -473,6 +649,13 @@
qcom,ntn-rst-delay-msec = <100>;
qcom,ntn-rc-num = <2>;
qcom,ntn-bus-num = <1>;
+
+ qcom,msm-bus,name = "ntn";
+ qcom,msm-bus,num-cases = <2>;
+ qcom,msm-bus,num-paths = <1>;
+ qcom,msm-bus,vectors-KBps =
+ <108 512 0 0>,
+ <108 512 207108 14432000>;
};
i2c@75ba000 {
@@ -517,9 +700,8 @@
pinctrl-1 = <&adv7533_0_int_suspend
&adv7533_0_hpd_int_suspend
&adv7533_0_switch_suspend>;
- adi,irq-gpio = <&tlmm 106 0x2002>;
- adi,hpd-irq-gpio = <&tlmm 106 0x2003>;
- adi,switch-gpio = <&tlmm 105 0x1>;
+ adi,irq-gpio = <&tlmm 71 0x2002>;
+ adi,switch-gpio = <&tlmm 72 0x1>;
};
adv7533@39 {
@@ -538,9 +720,8 @@
pinctrl-1 = <&adv7533_1_int_suspend
&adv7533_1_hpd_int_suspend
&adv7533_1_switch_suspend>;
- adi,irq-gpio = <&tlmm 108 0x2002>;
- adi,hpd-irq-gpio = <&tlmm 106 0x2003>;
- adi,switch-gpio = <&tlmm 107 0x0>;
+ adi,irq-gpio = <&tlmm 73 0x2002>;
+ adi,switch-gpio = <&tlmm 74 0x0>;
};
};
@@ -639,14 +820,14 @@
asoc-platform = <&pcm0>, <&pcm1>, <&pcm2>, <&voip>, <&voice>,
<&loopback>, <&compress>, <&hostless>,
- <&afe>, <&lsm>, <&routing>, <&compr>,
+ <&afe>, <&lsm>, <&routing>, <&pcmnoirq>,
<&loopback1>;
asoc-platform-names = "msm-pcm-dsp.0", "msm-pcm-dsp.1",
"msm-pcm-dsp.2", "msm-voip-dsp",
"msm-pcm-voice", "msm-pcm-loopback",
"msm-compress-dsp", "msm-pcm-hostless",
"msm-pcm-afe", "msm-lsm-client",
- "msm-pcm-routing", "msm-compr-dsp",
+ "msm-pcm-routing", "msm-pcm-dsp-noirq",
"msm-pcm-loopback.1";
asoc-cpu = <&dai_pri_auxpcm>, <&dai_sec_auxpcm>, <&dai_hdmi>,
<&dai_mi2s_sec>, <&dai_mi2s>, <&dai_mi2s_quat>,
@@ -835,7 +1016,7 @@
qcom,vin-sel = <2>; /* 1.8 */
qcom,out-strength = <1>;
qcom,src-sel = <0>; /* GPIO */
- qcom,master-en = <1>; /* Enable GPIO */
+ qcom,master-en = <0>; /* Disable GPIO */
status = "okay";
};
diff --git a/arch/arm/boot/dts/qcom/msm8996-coresight-v3.dtsi b/arch/arm/boot/dts/qcom/msm8996-coresight-v3.dtsi
index f9c9d07c3078..b5f6232badfe 100644
--- a/arch/arm/boot/dts/qcom/msm8996-coresight-v3.dtsi
+++ b/arch/arm/boot/dts/qcom/msm8996-coresight-v3.dtsi
@@ -1,4 +1,4 @@
-/* Copyright (c) 2015, 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
@@ -12,36 +12,44 @@
&soc {
tmc_etr: tmc@3028000 {
- compatible = "arm,coresight-tmc";
+ compatible = "arm,primecell";
+ arm,primecell-periphid = <0x0003b961>;
+
reg = <0x3028000 0x1000>,
<0x3084000 0x15000>;
reg-names = "tmc-base", "bam-base";
+
interrupts = <0 270 0>;
interrupt-names = "byte-cntr-irq";
- qcom,memory-size = <0x400000>;
- qcom,tmc-flush-powerdown;
- qcom,sg-enable;
- qcom,force-reg-dump;
+ arm,buffer-size = <0x400000>;
+ arm,sg-enable;
+
+ coresight-ctis = <&cti0 &cti8>;
- coresight-id = <0>;
coresight-name = "coresight-tmc-etr";
coresight-nr-inports = <1>;
- coresight-ctis = <&cti0 &cti8>;
clocks = <&clock_gcc clk_qdss_clk>,
<&clock_gcc clk_qdss_a_clk>;
- clock-names = "core_clk", "core_a_clk";
+ clock-names = "apb_pclk", "core_a_clk";
+
+ port{
+ tmc_etr_in_replicator: endpoint {
+ slave-mode;
+ remote-endpoint = <&replicator_out_tmc_etr>;
+ };
+ };
};
tpiu: tpiu@3020000 {
- compatible = "arm,coresight-tpiu";
+ compatible = "arm,primecell";
+ arm,primecell-periphid = <0x0003b912>;
+
reg = <0x3020000 0x1000>;
reg-names = "tpiu-base";
- coresight-id = <1>;
coresight-name = "coresight-tpiu";
- coresight-nr-inports = <1>;
vdd-supply = <&pm8994_l21>;
qcom,vdd-voltage-level = <2950000 2950000>;
@@ -57,182 +65,443 @@
clocks = <&clock_gcc clk_qdss_clk>,
<&clock_gcc clk_qdss_a_clk>;
- clock-names = "core_clk", "core_a_clk";
+ clock-names = "apb_pclk", "core_a_clk";
+
+ port{
+ tpiu_in_replicator: endpoint {
+ slave-mode;
+ remote-endpoint = <&replicator_out_tpiu>;
+ };
+ };
};
replicator: replicator@3026000 {
- compatible = "qcom,coresight-replicator";
+ compatible = "arm,primecell";
+ arm,primecell-periphid = <0x0003b909>;
+
reg = <0x3026000 0x1000>;
reg-names = "replicator-base";
- coresight-id = <2>;
coresight-name = "coresight-replicator";
- coresight-nr-inports = <1>;
- coresight-outports = <0 1>;
- coresight-child-list = <&tmc_etr &tpiu>;
- coresight-child-ports = <0 0>;
clocks = <&clock_gcc clk_qdss_clk>,
<&clock_gcc clk_qdss_a_clk>;
- clock-names = "core_clk", "core_a_clk";
+ clock-names = "apb_pclk", "core_a_clk";
+
+ ports{
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ port@0 {
+ reg = <0>;
+ replicator_out_tmc_etr:endpoint {
+ remote-endpoint =
+ <&tmc_etr_in_replicator>;
+ };
+ };
+ port@1 {
+ reg = <1>;
+ replicator_out_tpiu:endpoint {
+ remote-endpoint =
+ <&tpiu_in_replicator>;
+ };
+ };
+ port@2 {
+ reg = <0>;
+ replicator_in_tmc_etf:endpoint {
+ slave-mode;
+ remote-endpoint =
+ <&tmc_etf_out_replicator>;
+ };
+ };
+ };
};
tmc_etf: tmc@3027000 {
- compatible = "arm,coresight-tmc";
+ compatible = "arm,primecell";
+ arm,primecell-periphid = <0x0003b961>;
+
reg = <0x3027000 0x1000>;
reg-names = "tmc-base";
- coresight-id = <3>;
- coresight-name = "coresight-tmc-etf";
- coresight-nr-inports = <1>;
- coresight-outports = <0>;
- coresight-child-list = <&replicator>;
- coresight-child-ports = <0>;
- coresight-default-sink;
coresight-ctis = <&cti0 &cti8>;
+ coresight-name = "coresight-tmc-etf";
+
+ arm,default-sink;
+
qcom,tmc-flush-powerdown;
qcom,force-reg-dump;
clocks = <&clock_gcc clk_qdss_clk>,
<&clock_gcc clk_qdss_a_clk>;
- clock-names = "core_clk", "core_a_clk";
+ clock-names = "apb_pclk", "core_a_clk";
+
+ ports{
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ port@0 {
+ reg = <0>;
+ tmc_etf_out_replicator:endpoint {
+ remote-endpoint =
+ <&replicator_in_tmc_etf>;
+ };
+ };
+ port@1 {
+ reg = <0>;
+ tmc_etf_in_funnel_merg:endpoint {
+ slave-mode;
+ remote-endpoint =
+ <&funnel_merg_out_tmc_etf>;
+ };
+ };
+ };
};
funnel_merg: funnel@3025000 {
- compatible = "arm,coresight-funnel";
+ compatible = "arm,primecell";
+ arm,primecell-periphid = <0x0003b908>;
+
reg = <0x3025000 0x1000>;
reg-names = "funnel-base";
- coresight-id = <4>;
coresight-name = "coresight-funnel-merg";
- coresight-nr-inports = <2>;
- coresight-outports = <0>;
- coresight-child-list = <&tmc_etf>;
- coresight-child-ports = <0>;
clocks = <&clock_gcc clk_qdss_clk>,
<&clock_gcc clk_qdss_a_clk>;
- clock-names = "core_clk", "core_a_clk";
+ clock-names = "apb_pclk", "core_a_clk";
+
+ ports {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ port@0 {
+ reg = <0>;
+ funnel_merg_out_tmc_etf:endpoint {
+ remote-endpoint =
+ <&tmc_etf_in_funnel_merg>;
+ };
+ };
+ port@1 {
+ reg = <0>;
+ funnel_merg_in_funnel_in0:endpoint {
+ slave-mode;
+ remote-endpoint =
+ <&funnel_in0_out_funnel_merg>;
+ };
+ };
+ port@2 {
+ reg = <1>;
+ funnel_merg_in_funnel_in1:endpoint {
+ slave-mode;
+ remote-endpoint =
+ <&funnel_in1_out_funnel_merg>;
+ };
+ };
+ port@3 {
+ reg = <2>;
+ funnel_merg_in_funnel_in2:endpoint {
+ slave-mode;
+ remote-endpoint =
+ <&funnel_in2_out_funnel_merg>;
+ };
+ };
+ };
};
funnel_in0: funnel@3021000 {
- compatible = "arm,coresight-funnel";
+ compatible = "arm,primecell";
+ arm,primecell-periphid = <0x0003b908>;
+
reg = <0x3021000 0x1000>;
reg-names = "funnel-base";
- coresight-id = <5>;
coresight-name = "coresight-funnel-in0";
- coresight-nr-inports = <8>;
- coresight-outports = <0>;
- coresight-child-list = <&funnel_merg>;
- coresight-child-ports = <0>;
clocks = <&clock_gcc clk_qdss_clk>,
<&clock_gcc clk_qdss_a_clk>;
- clock-names = "core_clk", "core_a_clk";
+ clock-names = "apb_pclk", "core_a_clk";
+
+ ports {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ port@0 {
+ reg = <0>;
+ funnel_in0_out_funnel_merg: endpoint {
+ remote-endpoint =
+ <&funnel_merg_in_funnel_in0>;
+ };
+ };
+ port@1 {
+ reg = <0>;
+ funnel_in0_in_rpm_etm0: endpoint {
+ slave-mode;
+ remote-endpoint =
+ <&rpm_etm0_out_funnel_in0>;
+ };
+ };
+ port@2 {
+ reg = <1>;
+ funnel_in0_in_funnel_mmss: endpoint {
+ slave-mode;
+ remote-endpoint =
+ <&funnel_mmss_out_funnel_in0>;
+ };
+ };
+ port@3 {
+ reg = <2>;
+ funnel_in0_in_audio_etm0: endpoint {
+ slave-mode;
+ remote-endpoint =
+ <&audio_etm0_out_funnel_in0>;
+ };
+ };
+ port@4 {
+ reg = <3>;
+ funnel_in0_in_tpda: endpoint {
+ slave-mode;
+ remote-endpoint =
+ <&tpda_out_funnel_in0>;
+ };
+ };
+ port@5 {
+ reg = <7>;
+ funnel_in0_in_stm: endpoint {
+ slave-mode;
+ remote-endpoint = <&stm_out_funnel_in0>;
+ };
+ };
+ };
};
funnel_in1: funnel@3022000 {
- compatible = "arm,coresight-funnel";
+ compatible = "arm,primecell";
+ arm,primecell-periphid = <0x0003b908>;
+
reg = <0x3022000 0x1000>;
reg-names = "funnel-base";
- coresight-id = <6>;
coresight-name = "coresight-funnel-in1";
- coresight-nr-inports = <8>;
- coresight-outports = <0>;
- coresight-child-list = <&funnel_merg>;
- coresight-child-ports = <1>;
clocks = <&clock_gcc clk_qdss_clk>,
<&clock_gcc clk_qdss_a_clk>;
- clock-names = "core_clk", "core_a_clk";
+ clock-names = "apb_pclk", "core_a_clk";
+
+ ports {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ port@0 {
+ reg = <0>;
+ funnel_in1_out_funnel_merg: endpoint {
+ remote-endpoint =
+ <&funnel_merg_in_funnel_in1>;
+ };
+ };
+ port@1 {
+ reg = <6>;
+ funnel_in1_in_funnel_apss_merg: endpoint {
+ slave-mode;
+ remote-endpoint =
+ <&funnel_apss_merg_out_funnel_in1>;
+ };
+ };
+ };
};
funnel_in2: funnel@3023000 {
- compatible = "arm,coresight-funnel";
+ compatible = "arm,primecell";
+ arm,primecell-periphid = <0x0003b908>;
+
reg = <0x3023000 0x1000>;
reg-names = "funnel-base";
- coresight-id = <7>;
coresight-name = "coresight-funnel-in2";
- coresight-nr-inports = <8>;
- coresight-outports = <0>;
- coresight-child-list = <&funnel_merg>;
- coresight-child-ports = <2>;
clocks = <&clock_gcc clk_qdss_clk>,
<&clock_gcc clk_qdss_a_clk>;
- clock-names = "core_clk", "core_a_clk";
+ clock-names = "apb_pclk", "core_a_clk";
+
+ ports {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ port@0 {
+ reg = <0>;
+ funnel_in2_out_funnel_merg: endpoint {
+ remote-endpoint =
+ <&funnel_merg_in_funnel_in2>;
+ };
+ };
+ port@1 {
+ reg = <0>;
+ funnel_in2_in_modem_etm0: endpoint {
+ slave-mode;
+ remote-endpoint =
+ <&modem_etm0_out_funnel_in2>;
+ };
+ };
+ };
+
};
funnel_apss_merge: funnel@3bc0000 {
- compatible = "arm,coresight-funnel";
+ compatible = "arm,primecell";
+ arm,primecell-periphid = <0x0003b908>;
+
reg = <0x3bc0000 0x1000>;
reg-names = "funnel-base";
- coresight-id = <8>;
coresight-name = "coresight-funnel-apss-merge";
- coresight-nr-inports = <4>;
- coresight-outports = <0>;
- coresight-child-list = <&funnel_in1>;
- coresight-child-ports = <6>;
clocks = <&clock_gcc clk_qdss_clk>,
<&clock_gcc clk_qdss_a_clk>;
- clock-names = "core_clk", "core_a_clk";
+ clock-names = "apb_pclk", "core_a_clk";
+
+ ports {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ port@0 {
+ reg = <0>;
+ funnel_apss_merg_out_funnel_in1: endpoint {
+ remote-endpoint =
+ <&funnel_in1_in_funnel_apss_merg>;
+ };
+ };
+ port@1 {
+ reg = <0>;
+ funnel_apss_merg_in_funnel_apss0: endpoint {
+ slave-mode;
+ remote-endpoint =
+ <&funnel_apss0_out_funnel_apss_merg>;
+ };
+ };
+ port@2 {
+ reg = <1>;
+ funnel_apss_merg_in_funnel_apss1: endpoint {
+ slave-mode;
+ remote-endpoint =
+ <&funnel_apss1_out_funnel_apss_merg>;
+ };
+ };
+ port@3 {
+ reg = <2>;
+ funnel_apss_merg_in_tpda_apss: endpoint {
+ slave-mode;
+ remote-endpoint =
+ <&tpda_apss_out_funnel_apss_merg>;
+ };
+ };
+ };
};
funnel_apss0: funnel@39b0000 {
- compatible = "arm,coresight-funnel";
+ compatible = "arm,primecell";
+ arm,primecell-periphid = <0x0003b908>;
+
reg = <0x39b0000 0x1000>;
reg-names = "funnel-base";
- coresight-id = <9>;
coresight-name = "coresight-funnel-apss0";
- coresight-nr-inports = <2>;
- coresight-outports = <0>;
- coresight-child-list = <&funnel_apss_merge>;
- coresight-child-ports = <0>;
clocks = <&clock_gcc clk_qdss_clk>,
<&clock_gcc clk_qdss_a_clk>;
- clock-names = "core_clk", "core_a_clk";
+ clock-names = "apb_pclk", "core_a_clk";
+
+ ports {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ port@0 {
+ reg = <0>;
+ funnel_apss0_out_funnel_apss_merg: endpoint {
+ remote-endpoint =
+ <&funnel_apss_merg_in_funnel_apss0>;
+ };
+ };
+ port@1 {
+ reg = <0>;
+ funnel_apss0_in_etm0: endpoint {
+ slave-mode;
+ remote-endpoint =
+ <&etm0_out_funnel_apss0>;
+ };
+ };
+ port@2 {
+ reg = <1>;
+ funnel_apss0_in_etm1: endpoint {
+ slave-mode;
+ remote-endpoint =
+ <&etm1_out_funnel_apss0>;
+ };
+ };
+ };
};
funnel_apss1: funnel@3bb0000 {
- compatible = "arm,coresight-funnel";
+ compatible = "arm,primecell";
+ arm,primecell-periphid = <0x0003b908>;
+
reg = <0x3bb0000 0x1000>;
reg-names = "funnel-base";
- coresight-id = <10>;
coresight-name = "coresight-funnel-apss1";
- coresight-nr-inports = <2>;
- coresight-outports = <0>;
- coresight-child-list = <&funnel_apss_merge>;
- coresight-child-ports = <1>;
clocks = <&clock_gcc clk_qdss_clk>,
<&clock_gcc clk_qdss_a_clk>;
- clock-names = "core_clk", "core_a_clk";
+ clock-names = "apb_pclk", "core_a_clk";
+
+ ports {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ port@0 {
+ reg = <0>;
+ funnel_apss1_out_funnel_apss_merg: endpoint {
+ remote-endpoint =
+ <&funnel_apss_merg_in_funnel_apss1>;
+ };
+ };
+ port@1 {
+ reg = <0>;
+ funnel_apss1_in_etm2: endpoint {
+ slave-mode;
+ remote-endpoint =
+ <&etm2_out_funnel_apss1>;
+ };
+ };
+ port@2 {
+ reg = <1>;
+ funnel_apss1_in_etm3: endpoint {
+ slave-mode;
+ remote-endpoint =
+ <&etm3_out_funnel_apss1>;
+ };
+ };
+ };
};
funnel_mmss: funnel@3184000 {
- compatible = "arm,coresight-funnel";
+ compatible = "arm,primecell";
+ arm,primecell-periphid = <0x0003b908>;
+
reg = <0x3184000 0x1000>;
reg-names = "funnel-base";
- coresight-id = <11>;
coresight-name = "coresight-funnel-mmss";
- coresight-nr-inports = <8>;
- coresight-outports = <0>;
- coresight-child-list = <&funnel_in0>;
- coresight-child-ports = <1>;
clocks = <&clock_gcc clk_qdss_clk>,
<&clock_gcc clk_qdss_a_clk>;
- clock-names = "core_clk", "core_a_clk";
+ clock-names = "apb_pclk", "core_a_clk";
+
+ port{
+ funnel_mmss_out_funnel_in0: endpoint {
+ remote-endpoint = <&funnel_in0_in_funnel_mmss>;
+ };
+ };
};
tpda: tpda@3003000 {
@@ -240,12 +509,7 @@
reg = <0x3003000 0x1000>;
reg-names = "tpda-base";
- coresight-id = <13>;
coresight-name = "coresight-tpda";
- coresight-nr-inports = <32>;
- coresight-outports = <0>;
- coresight-child-list = <&funnel_in0>;
- coresight-child-ports = <3>;
qcom,tpda-atid = <65>;
qcom,bc-elem-size = <3 32>,
@@ -263,6 +527,66 @@
clocks = <&clock_gcc clk_qdss_clk>,
<&clock_gcc clk_qdss_a_clk>;
clock-names = "core_clk", "core_a_clk";
+
+ ports {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ port@0 {
+ reg = <0>;
+ tpda_out_funnel_in0: endpoint {
+ remote-endpoint =
+ <&funnel_in0_in_tpda>;
+ };
+ };
+ port@1 {
+ reg = <0>;
+ tpda_in_tpdm_vsense: endpoint {
+ slave-mode;
+ remote-endpoint =
+ <&tpdm_vsense_out_tpda>;
+ };
+ };
+ port@2 {
+ reg = <1>;
+ tpda_in_tpdm_dcc: endpoint {
+ slave-mode;
+ remote-endpoint =
+ <&tpdm_dcc_out_tpda>;
+ };
+ };
+ port@3 {
+ reg = <2>;
+ tpda_in_tpdm_prng: endpoint {
+ slave-mode;
+ remote-endpoint =
+ <&tpdm_prng_out_tpda>;
+ };
+ };
+ port@4 {
+ reg = <3>;
+ tpda_in_tpdm_dsat: endpoint {
+ slave-mode;
+ remote-endpoint =
+ <&tpdm_dsat_out_tpda>;
+ };
+ };
+ port@5 {
+ reg = <6>;
+ tpda_in_tpdm_pimem: endpoint {
+ slave-mode;
+ remote-endpoint =
+ <&tpdm_pimem_out_tpda>;
+ };
+ };
+ port@6 {
+ reg = <7>;
+ tpda_in_tpdm_hwevents: endpoint {
+ slave-mode;
+ remote-endpoint =
+ <&tpdm_hwevents_out_tpda>;
+ };
+ };
+ };
};
tpda_apss: tpda@39e0000 {
@@ -270,12 +594,7 @@
reg = <0x39e0000 0x1000>;
reg-names = "tpda-base";
- coresight-id = <14>;
coresight-name = "coresight-tpda-apss";
- coresight-nr-inports = <32>;
- coresight-outports = <0>;
- coresight-child-list = <&funnel_apss_merge>;
- coresight-child-ports = <2>;
qcom,tpda-atid = <66>;
qcom,bc-elem-size = <0 32>,
@@ -285,6 +604,26 @@
clocks = <&clock_gcc clk_qdss_clk>,
<&clock_gcc clk_qdss_a_clk>;
clock-names = "core_clk", "core_a_clk";
+
+ ports {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ port@0 {
+ reg = <0>;
+ tpda_apss_out_funnel_apss_merg: endpoint {
+ remote-endpoint =
+ <&funnel_apss_merg_in_tpda_apss>;
+ };
+ };
+ port@1 {
+ reg = <0>;
+ tpda_apss_in_tpdm_m4m: endpoint {
+ slave-mode;
+ remote-endpoint =
+ <&tpdm_m4m_out_tpda_apss>;
+ };
+ };
+ };
};
tpdm_vsense: tpdm@3038000 {
@@ -292,16 +631,17 @@
reg = <0x3038000 0x1000>;
reg-names = "tpdm-base";
- coresight-id = <15>;
coresight-name = "coresight-tpdm-vsense";
- coresight-nr-inports = <0>;
- coresight-outports = <0>;
- coresight-child-list = <&tpda>;
- coresight-child-ports = <0>;
clocks = <&clock_gcc clk_qdss_clk>,
<&clock_gcc clk_qdss_a_clk>;
clock-names = "core_clk", "core_a_clk";
+
+ port{
+ tpdm_vsense_out_tpda: endpoint {
+ remote-endpoint = <&tpda_in_tpdm_vsense>;
+ };
+ };
};
tpdm_dcc: tpdm@3054000 {
@@ -309,16 +649,17 @@
reg = <0x3054000 0x1000>;
reg-names = "tpdm-base";
- coresight-id = <16>;
coresight-name = "coresight-tpdm-dcc";
- coresight-nr-inports = <0>;
- coresight-outports = <0>;
- coresight-child-list = <&tpda>;
- coresight-child-ports = <1>;
clocks = <&clock_gcc clk_qdss_clk>,
<&clock_gcc clk_qdss_a_clk>;
clock-names = "core_clk", "core_a_clk";
+
+ port{
+ tpdm_dcc_out_tpda: endpoint {
+ remote-endpoint = <&tpda_in_tpdm_dcc>;
+ };
+ };
};
tpdm_prng: tpdm@304c000 {
@@ -326,16 +667,17 @@
reg = <0x304c000 0x1000>;
reg-names = "tpdm-base";
- coresight-id = <17>;
coresight-name = "coresight-tpdm-prng";
- coresight-nr-inports = <0>;
- coresight-outports = <0>;
- coresight-child-list = <&tpda>;
- coresight-child-ports = <2>;
clocks = <&clock_gcc clk_qdss_clk>,
<&clock_gcc clk_qdss_a_clk>;
clock-names = "core_clk", "core_a_clk";
+
+ port{
+ tpdm_prng_out_tpda: endpoint {
+ remote-endpoint = <&tpda_in_tpdm_prng>;
+ };
+ };
};
tpdm_dsat: tpdm@3185000 {
@@ -343,16 +685,17 @@
reg = <0x3185000 0x1000>;
reg-names = "tpdm-base";
- coresight-id = <18>;
coresight-name = "coresight-tpdm-dsat";
- coresight-nr-inports = <0>;
- coresight-outports = <0>;
- coresight-child-list = <&tpda>;
- coresight-child-ports = <3>;
clocks = <&clock_gcc clk_qdss_clk>,
<&clock_gcc clk_qdss_a_clk>;
clock-names = "core_clk", "core_a_clk";
+
+ port{
+ tpdm_dsat_out_tpda: endpoint {
+ remote-endpoint = <&tpda_in_tpdm_dsat>;
+ };
+ };
};
tpdm_pimem: tpdm@3050000 {
@@ -360,16 +703,17 @@
reg = <0x3050000 0x1000>;
reg-names = "tpdm-base";
- coresight-id = <19>;
coresight-name = "coresight-tpdm-pimem";
- coresight-nr-inports = <0>;
- coresight-outports = <0>;
- coresight-child-list = <&tpda>;
- coresight-child-ports = <6>;
clocks = <&clock_gcc clk_qdss_clk>,
<&clock_gcc clk_qdss_a_clk>;
clock-names = "core_clk", "core_a_clk";
+
+ port{
+ tpdm_pimem_out_tpda: endpoint {
+ remote-endpoint = <&tpda_in_tpdm_pimem>;
+ };
+ };
};
tpdm_hwevents: tpdm@3004000 {
@@ -377,16 +721,17 @@
reg = <0x3004000 0x1000>;
reg-names = "tpdm-base";
- coresight-id = <20>;
coresight-name = "coresight-tpdm-hwevents";
- coresight-nr-inports = <0>;
- coresight-outports = <0>;
- coresight-child-list = <&tpda>;
- coresight-child-ports = <7>;
clocks = <&clock_gcc clk_qdss_clk>,
<&clock_gcc clk_qdss_a_clk>;
clock-names = "core_clk", "core_a_clk";
+
+ port{
+ tpdm_hwevents_out_tpda: endpoint {
+ remote-endpoint = <&tpda_in_tpdm_hwevents>;
+ };
+ };
};
tpdm_m4m: tpdm@38e0000 {
@@ -394,147 +739,163 @@
reg = <0x38e0000 0x1000>;
reg-names = "tpdm-base";
- coresight-id = <21>;
coresight-name = "coresight-tpdm-m4m";
- coresight-nr-inports = <0>;
- coresight-outports = <0>;
- coresight-child-list = <&tpda_apss>;
- coresight-child-ports = <0>;
qcom,clk-enable;
clocks = <&clock_gcc clk_qdss_clk>,
<&clock_gcc clk_qdss_a_clk>;
clock-names = "core_clk", "core_a_clk";
+
+ port{
+ tpdm_m4m_out_tpda_apss: endpoint {
+ remote-endpoint = <&tpda_apss_in_tpdm_m4m>;
+ };
+ };
};
stm: stm@3002000 {
- compatible = "arm,coresight-stm";
+ compatible = "arm,primecell";
+ arm,primecell-periphid = <0x0003b962>;
+
reg = <0x3002000 0x1000>,
<0x8280000 0x180000>;
reg-names = "stm-base", "stm-data-base";
- coresight-id = <23>;
coresight-name = "coresight-stm";
- coresight-nr-inports = <0>;
- coresight-outports = <0>;
- coresight-child-list = <&funnel_in0>;
- coresight-child-ports = <7>;
clocks = <&clock_gcc clk_qdss_clk>,
<&clock_gcc clk_qdss_a_clk>;
- clock-names = "core_clk", "core_a_clk";
+ clock-names = "apb_pclk", "core_a_clk";
+
+ port{
+ stm_out_funnel_in0: endpoint {
+ remote-endpoint = <&funnel_in0_in_stm>;
+ };
+ };
};
etm0: etm@3840000 {
- compatible = "arm,coresight-etmv4";
+ compatible = "arm,primecell";
+ arm,primecell-periphid = <0x0003b95d>;
+
reg = <0x3840000 0x1000>;
- reg-names = "etm-base";
+ cpu = <&CPU0>;
- coresight-id = <24>;
coresight-name = "coresight-etm0";
- coresight-nr-inports = <0>;
- coresight-outports = <0>;
- coresight-child-list = <&funnel_apss0>;
- coresight-child-ports = <0>;
- coresight-etm-cpu = <&CPU0>;
clocks = <&clock_gcc clk_qdss_clk>,
<&clock_gcc clk_qdss_a_clk>;
- clock-names = "core_clk", "core_a_clk";
+ clock-names = "apb_pclk", "core_a_clk";
+
+ port{
+ etm0_out_funnel_apss0: endpoint {
+ remote-endpoint = <&funnel_apss0_in_etm0>;
+ };
+ };
};
etm1: etm@3940000 {
- compatible = "arm,coresight-etmv4";
+ compatible = "arm,primecell";
+ arm,primecell-periphid = <0x0003b95d>;
+
reg = <0x3940000 0x1000>;
- reg-names = "etm-base";
+ cpu = <&CPU1>;
- coresight-id = <25>;
coresight-name = "coresight-etm1";
- coresight-nr-inports = <0>;
- coresight-outports = <0>;
- coresight-child-list = <&funnel_apss0>;
- coresight-child-ports = <1>;
- coresight-etm-cpu = <&CPU1>;
clocks = <&clock_gcc clk_qdss_clk>,
<&clock_gcc clk_qdss_a_clk>;
- clock-names = "core_clk", "core_a_clk";
+ clock-names = "apb_pclk", "core_a_clk";
+
+ port{
+ etm1_out_funnel_apss0: endpoint {
+ remote-endpoint = <&funnel_apss0_in_etm1>;
+ };
+ };
};
etm2: etm@3a40000 {
- compatible = "arm,coresight-etmv4";
+ compatible = "arm,primecell";
+ arm,primecell-periphid = <0x0003b95d>;
+
reg = <0x3a40000 0x1000>;
- reg-names = "etm-base";
+ cpu = <&CPU2>;
- coresight-id = <26>;
coresight-name = "coresight-etm2";
- coresight-nr-inports = <0>;
- coresight-outports = <0>;
- coresight-child-list = <&funnel_apss1>;
- coresight-child-ports = <0>;
- coresight-etm-cpu = <&CPU2>;
clocks = <&clock_gcc clk_qdss_clk>,
<&clock_gcc clk_qdss_a_clk>;
- clock-names = "core_clk", "core_a_clk";
+ clock-names = "apb_pclk", "core_a_clk";
+
+ port{
+ etm2_out_funnel_apss1: endpoint {
+ remote-endpoint = <&funnel_apss1_in_etm2>;
+ };
+ };
};
etm3: etm@3b40000 {
- compatible = "arm,coresight-etmv4";
+ compatible = "arm,primecell";
+ arm,primecell-periphid = <0x0003b95d>;
+
reg = <0x3b40000 0x1000>;
- reg-names = "etm-base";
+ cpu = <&CPU3>;
- coresight-id = <27>;
coresight-name = "coresight-etm3";
- coresight-nr-inports = <0>;
- coresight-outports = <0>;
- coresight-child-list = <&funnel_apss1>;
- coresight-child-ports = <1>;
- coresight-etm-cpu = <&CPU3>;
clocks = <&clock_gcc clk_qdss_clk>,
<&clock_gcc clk_qdss_a_clk>;
- clock-names = "core_clk", "core_a_clk";
+ clock-names = "apb_pclk", "core_a_clk";
+
+ port{
+ etm3_out_funnel_apss1: endpoint {
+ remote-endpoint = <&funnel_apss1_in_etm3>;
+ };
+ };
};
audio_etm0 {
compatible = "qcom,coresight-remote-etm";
- coresight-id = <28>;
coresight-name = "coresight-audio-etm0";
- coresight-nr-inports = <0>;
- coresight-outports = <0>;
- coresight-child-list = <&funnel_in0>;
- coresight-child-ports = <2>;
qcom,inst-id = <5>;
+
+ port{
+ audio_etm0_out_funnel_in0: endpoint {
+ remote-endpoint = <&funnel_in0_in_audio_etm0>;
+ };
+ };
+
};
rpm_etm0 {
compatible = "qcom,coresight-remote-etm";
- coresight-id = <29>;
coresight-name = "coresight-rpm-etm0";
- coresight-nr-inports = <0>;
- coresight-outports = <0>;
- coresight-child-list = <&funnel_in0>;
- coresight-child-ports = <0>;
qcom,inst-id = <4>;
+
+ port{
+ rpm_etm0_out_funnel_in0: endpoint {
+ remote-endpoint = <&funnel_in0_in_rpm_etm0>;
+ };
+ };
};
modem_etm0 {
compatible = "qcom,coresight-remote-etm";
- coresight-id = <30>;
coresight-name = "coresight-modem-etm0";
- coresight-nr-inports = <0>;
- coresight-outports = <0>;
- coresight-child-list = <&funnel_in2>;
- coresight-child-ports = <0>;
qcom,inst-id = <2>;
+
+ port{
+ modem_etm0_out_funnel_in2: endpoint {
+ remote-endpoint = <&funnel_in2_in_modem_etm0>;
+ };
+ };
};
csr: csr@3001000 {
@@ -542,9 +903,7 @@
reg = <0x3001000 0x1000>;
reg-names = "csr-base";
- coresight-id = <31>;
coresight-name = "coresight-csr";
- coresight-nr-inports = <0>;
qcom,blk-size = <1>;
};
@@ -554,9 +913,7 @@
reg = <0x3010000 0x1000>;
reg-names = "cti-base";
- coresight-id = <32>;
coresight-name = "coresight-cti0";
- coresight-nr-inports = <0>;
clocks = <&clock_gcc clk_qdss_clk>,
<&clock_gcc clk_qdss_a_clk>;
@@ -568,9 +925,7 @@
reg = <0x3011000 0x1000>;
reg-names = "cti-base";
- coresight-id = <33>;
coresight-name = "coresight-cti1";
- coresight-nr-inports = <0>;
clocks = <&clock_gcc clk_qdss_clk>,
<&clock_gcc clk_qdss_a_clk>;
@@ -582,9 +937,7 @@
reg = <0x3012000 0x1000>;
reg-names = "cti-base";
- coresight-id = <34>;
coresight-name = "coresight-cti2";
- coresight-nr-inports = <0>;
clocks = <&clock_gcc clk_qdss_clk>,
<&clock_gcc clk_qdss_a_clk>;
@@ -596,9 +949,7 @@
reg = <0x3013000 0x1000>;
reg-names = "cti-base";
- coresight-id = <35>;
coresight-name = "coresight-cti3";
- coresight-nr-inports = <0>;
clocks = <&clock_gcc clk_qdss_clk>,
<&clock_gcc clk_qdss_a_clk>;
@@ -610,9 +961,7 @@
reg = <0x3014000 0x1000>;
reg-names = "cti-base";
- coresight-id = <36>;
coresight-name = "coresight-cti4";
- coresight-nr-inports = <0>;
clocks = <&clock_gcc clk_qdss_clk>,
<&clock_gcc clk_qdss_a_clk>;
@@ -624,9 +973,7 @@
reg = <0x3015000 0x1000>;
reg-names = "cti-base";
- coresight-id = <37>;
coresight-name = "coresight-cti5";
- coresight-nr-inports = <0>;
clocks = <&clock_gcc clk_qdss_clk>,
<&clock_gcc clk_qdss_a_clk>;
@@ -638,9 +985,7 @@
reg = <0x3016000 0x1000>;
reg-names = "cti-base";
- coresight-id = <38>;
coresight-name = "coresight-cti6";
- coresight-nr-inports = <0>;
clocks = <&clock_gcc clk_qdss_clk>,
<&clock_gcc clk_qdss_a_clk>;
@@ -656,9 +1001,7 @@
reg = <0x3017000 0x1000>;
reg-names = "cti-base";
- coresight-id = <39>;
coresight-name = "coresight-cti7";
- coresight-nr-inports = <0>;
clocks = <&clock_gcc clk_qdss_clk>,
<&clock_gcc clk_qdss_a_clk>;
@@ -670,9 +1013,7 @@
reg = <0x3018000 0x1000>;
reg-names = "cti-base";
- coresight-id = <40>;
coresight-name = "coresight-cti8";
- coresight-nr-inports = <0>;
clocks = <&clock_gcc clk_qdss_clk>,
<&clock_gcc clk_qdss_a_clk>;
@@ -684,9 +1025,7 @@
reg = <0x3019000 0x1000>;
reg-names = "cti-base";
- coresight-id = <41>;
coresight-name = "coresight-cti9";
- coresight-nr-inports = <0>;
clocks = <&clock_gcc clk_qdss_clk>,
<&clock_gcc clk_qdss_a_clk>;
@@ -698,9 +1037,7 @@
reg = <0x301a000 0x1000>;
reg-names = "cti-base";
- coresight-id = <42>;
coresight-name = "coresight-cti10";
- coresight-nr-inports = <0>;
clocks = <&clock_gcc clk_qdss_clk>,
<&clock_gcc clk_qdss_a_clk>;
@@ -712,9 +1049,7 @@
reg = <0x301b000 0x1000>;
reg-names = "cti-base";
- coresight-id = <43>;
coresight-name = "coresight-cti11";
- coresight-nr-inports = <0>;
clocks = <&clock_gcc clk_qdss_clk>,
<&clock_gcc clk_qdss_a_clk>;
@@ -726,9 +1061,7 @@
reg = <0x301c000 0x1000>;
reg-names = "cti-base";
- coresight-id = <44>;
coresight-name = "coresight-cti12";
- coresight-nr-inports = <0>;
clocks = <&clock_gcc clk_qdss_clk>,
<&clock_gcc clk_qdss_a_clk>;
@@ -740,9 +1073,7 @@
reg = <0x301d000 0x1000>;
reg-names = "cti-base";
- coresight-id = <45>;
coresight-name = "coresight-cti13";
- coresight-nr-inports = <0>;
clocks = <&clock_gcc clk_qdss_clk>,
<&clock_gcc clk_qdss_a_clk>;
@@ -754,9 +1085,7 @@
reg = <0x301e000 0x1000>;
reg-names = "cti-base";
- coresight-id = <46>;
coresight-name = "coresight-cti14";
- coresight-nr-inports = <0>;
clocks = <&clock_gcc clk_qdss_clk>,
<&clock_gcc clk_qdss_a_clk>;
@@ -768,10 +1097,8 @@
reg = <0x3820000 0x1000>;
reg-names = "cti-base";
- coresight-id = <47>;
coresight-name = "coresight-cti-cpu0";
- coresight-nr-inports = <0>;
- coresight-cti-cpu = <&CPU0>;
+ cpu = <&CPU0>;
clocks = <&clock_gcc clk_qdss_clk>,
<&clock_gcc clk_qdss_a_clk>;
@@ -783,10 +1110,8 @@
reg = <0x3920000 0x1000>;
reg-names = "cti-base";
- coresight-id = <48>;
coresight-name = "coresight-cti-cpu1";
- coresight-nr-inports = <0>;
- coresight-cti-cpu = <&CPU1>;
+ cpu = <&CPU1>;
clocks = <&clock_gcc clk_qdss_clk>,
<&clock_gcc clk_qdss_a_clk>;
@@ -798,10 +1123,8 @@
reg = <0x3a20000 0x1000>;
reg-names = "cti-base";
- coresight-id = <49>;
coresight-name = "coresight-cti-cpu2";
- coresight-nr-inports = <0>;
- coresight-cti-cpu = <&CPU2>;
+ cpu = <&CPU2>;
clocks = <&clock_gcc clk_qdss_clk>,
<&clock_gcc clk_qdss_a_clk>;
@@ -813,10 +1136,8 @@
reg = <0x3b20000 0x1000>;
reg-names = "cti-base";
- coresight-id = <50>;
coresight-name = "coresight-cti-cpu3";
- coresight-nr-inports = <0>;
- coresight-cti-cpu = <&CPU3>;
+ cpu = <&CPU3>;
clocks = <&clock_gcc clk_qdss_clk>,
<&clock_gcc clk_qdss_a_clk>;
@@ -828,10 +1149,8 @@
reg = <0x38a0000 0x1000>;
reg-names = "cti-base";
- coresight-id = <51>;
coresight-name = "coresight-cti-pmu-cpu0";
- coresight-nr-inports = <0>;
- coresight-cti-cpu = <&CPU0>;
+ cpu = <&CPU0>;
clocks = <&clock_gcc clk_qdss_clk>,
<&clock_gcc clk_qdss_a_clk>;
@@ -843,10 +1162,8 @@
reg = <0x39a0000 0x1000>;
reg-names = "cti-base";
- coresight-id = <52>;
coresight-name = "coresight-cti-pmu-cpu1";
- coresight-nr-inports = <0>;
- coresight-cti-cpu = <&CPU1>;
+ cpu = <&CPU1>;
clocks = <&clock_gcc clk_qdss_clk>,
<&clock_gcc clk_qdss_a_clk>;
@@ -858,10 +1175,8 @@
reg = <0x3aa0000 0x1000>;
reg-names = "cti-base";
- coresight-id = <53>;
coresight-name = "coresight-cti-pmu-cpu2";
- coresight-nr-inports = <0>;
- coresight-cti-cpu = <&CPU2>;
+ cpu = <&CPU2>;
clocks = <&clock_gcc clk_qdss_clk>,
<&clock_gcc clk_qdss_a_clk>;
@@ -873,10 +1188,8 @@
reg = <0x3ba0000 0x1000>;
reg-names = "cti-base";
- coresight-id = <54>;
coresight-name = "coresight-cti-pmu-cpu3";
- coresight-nr-inports = <0>;
- coresight-cti-cpu = <&CPU3>;
+ cpu = <&CPU3>;
clocks = <&clock_gcc clk_qdss_clk>,
<&clock_gcc clk_qdss_a_clk>;
@@ -888,9 +1201,7 @@
reg = <0x38b0000 0x1000>;
reg-names = "cti-base";
- coresight-id = <55>;
coresight-name = "coresight-cti-l2pmu-cluster0";
- coresight-nr-inports = <0>;
clocks = <&clock_gcc clk_qdss_clk>,
<&clock_gcc clk_qdss_a_clk>;
@@ -902,9 +1213,7 @@
reg = <0x3ab0000 0x1000>;
reg-names = "cti-base";
- coresight-id = <56>;
coresight-name = "coresight-cti-l2pmu-cluster1";
- coresight-nr-inports = <0>;
clocks = <&clock_gcc clk_qdss_clk>,
<&clock_gcc clk_qdss_a_clk>;
@@ -916,9 +1225,7 @@
reg = <0x3ad0000 0x1000>;
reg-names = "cti-base";
- coresight-id = <57>;
coresight-name = "coresight-cti-l3";
- coresight-nr-inports = <0>;
clocks = <&clock_gcc clk_qdss_clk>,
<&clock_gcc clk_qdss_a_clk>;
@@ -930,9 +1237,7 @@
reg = <0x39c0000 0x1000>;
reg-names = "cti-base";
- coresight-id = <58>;
coresight-name = "coresight-cti-lm-cluster0";
- coresight-nr-inports = <0>;
clocks = <&clock_gcc clk_qdss_clk>,
<&clock_gcc clk_qdss_a_clk>;
@@ -944,9 +1249,7 @@
reg = <0x39d0000 0x1000>;
reg-names = "cti-base";
- coresight-id = <59>;
coresight-name = "coresight-cti-lm-cluster1";
- coresight-nr-inports = <0>;
clocks = <&clock_gcc clk_qdss_clk>,
<&clock_gcc clk_qdss_a_clk>;
@@ -958,9 +1261,7 @@
reg = <0x38d0000 0x1000>;
reg-names = "cti-base";
- coresight-id = <60>;
coresight-name = "coresight-cti-m4m";
- coresight-nr-inports = <0>;
clocks = <&clock_gcc clk_qdss_clk>,
<&clock_gcc clk_qdss_a_clk>;
@@ -972,9 +1273,7 @@
reg = <0x39f0000 0x1000>;
reg-names = "cti-base";
- coresight-id = <61>;
coresight-name = "coresight-cti-tpda-apss";
- coresight-nr-inports = <0>;
clocks = <&clock_gcc clk_qdss_clk>,
<&clock_gcc clk_qdss_a_clk>;
@@ -986,9 +1285,7 @@
reg = <0x3180000 0x1000>;
reg-names = "cti-base";
- coresight-id = <64>;
coresight-name = "coresight-cti-venus-cpu0";
- coresight-nr-inports = <0>;
clocks = <&clock_gcc clk_qdss_clk>,
<&clock_gcc clk_qdss_a_clk>;
@@ -1000,9 +1297,7 @@
reg = <0x3044000 0x1000>;
reg-names = "cti-base";
- coresight-id = <65>;
coresight-name = "coresight-cti-audio-cpu0";
- coresight-nr-inports = <0>;
clocks = <&clock_gcc clk_qdss_clk>,
<&clock_gcc clk_qdss_a_clk>;
@@ -1014,9 +1309,7 @@
reg = <0x3048000 0x1000>;
reg-names = "cti-base";
- coresight-id = <66>;
coresight-name = "coresight-cti-rpm-cpu0";
- coresight-nr-inports = <0>;
clocks = <&clock_gcc clk_qdss_clk>,
<&clock_gcc clk_qdss_a_clk>;
@@ -1028,9 +1321,7 @@
reg = <0x3040000 0x1000>;
reg-names = "cti-base";
- coresight-id = <67>;
coresight-name = "coresight-cti-modem-cpu0";
- coresight-nr-inports = <0>;
clocks = <&clock_gcc clk_qdss_clk>,
<&clock_gcc clk_qdss_a_clk>;
@@ -1057,9 +1348,7 @@
"pcie1-hwev", "pcie2-hwev", "tcsr-mux", "mss-mux0",
"mss-mux1";
- coresight-id = <70>;
coresight-name = "coresight-hwevent";
- coresight-nr-inports = <0>;
clocks = <&clock_gcc clk_qdss_clk>,
<&clock_gcc clk_qdss_a_clk>,
@@ -1075,9 +1364,7 @@
<0x76014 0x4>;
reg-names = "fuse-base", "qpdi-fuse-base";
- coresight-id = <71>;
coresight-name = "coresight-fuse";
- coresight-nr-inports = <0>;
};
qpdi: qpdi@7a1000 {
@@ -1085,9 +1372,7 @@
reg = <0x7a1000 0x4>;
reg-names = "qpdi-base";
- coresight-id = <72>;
coresight-name = "coresight-qpdi";
- coresight-nr-inports = <0>;
vdd-supply = <&pm8994_l21>;
qcom,vdd-voltage-level = <2950000 2950000>;
diff --git a/arch/arm/boot/dts/qcom/msm8996-mmxf-adp.dtsi b/arch/arm/boot/dts/qcom/msm8996-mmxf-adp.dtsi
index 53c3c7e727bc..d3ea51268590 100644
--- a/arch/arm/boot/dts/qcom/msm8996-mmxf-adp.dtsi
+++ b/arch/arm/boot/dts/qcom/msm8996-mmxf-adp.dtsi
@@ -523,14 +523,14 @@
asoc-platform = <&pcm0>, <&pcm1>, <&pcm2>, <&voip>, <&voice>,
<&loopback>, <&compress>, <&hostless>,
- <&afe>, <&lsm>, <&routing>, <&compr>,
+ <&afe>, <&lsm>, <&routing>, <&pcmnoirq>,
<&loopback1>;
asoc-platform-names = "msm-pcm-dsp.0", "msm-pcm-dsp.1",
"msm-pcm-dsp.2", "msm-voip-dsp",
"msm-pcm-voice", "msm-pcm-loopback",
"msm-compress-dsp", "msm-pcm-hostless",
"msm-pcm-afe", "msm-lsm-client",
- "msm-pcm-routing", "msm-compr-dsp",
+ "msm-pcm-routing", "msm-pcm-dsp-noirq",
"msm-pcm-loopback.1";
asoc-cpu = <&dai_pri_auxpcm>, <&dai_sec_auxpcm>, <&dai_hdmi>,
<&dai_mi2s_sec>, <&dai_mi2s>, <&dai_mi2s_quat>,
diff --git a/arch/arm/boot/dts/qcom/msm8998-audio.dtsi b/arch/arm/boot/dts/qcom/msm8998-audio.dtsi
index c4e6393997ec..9a263510b27d 100644
--- a/arch/arm/boot/dts/qcom/msm8998-audio.dtsi
+++ b/arch/arm/boot/dts/qcom/msm8998-audio.dtsi
@@ -89,7 +89,7 @@
asoc-platform = <&pcm0>, <&pcm1>, <&pcm2>, <&voip>, <&voice>,
<&loopback>, <&compress>, <&hostless>,
<&afe>, <&lsm>, <&routing>, <&cpe>, <&compr>,
- <&pcm_noirq>, <&cpe3>;
+ <&pcm_noirq>, <&cpe3>, <&trans_loopback>;
asoc-platform-names = "msm-pcm-dsp.0", "msm-pcm-dsp.1",
"msm-pcm-dsp.2", "msm-voip-dsp",
"msm-pcm-voice", "msm-pcm-loopback",
@@ -97,7 +97,7 @@
"msm-pcm-afe", "msm-lsm-client",
"msm-pcm-routing", "msm-cpe-lsm",
"msm-compr-dsp", "msm-pcm-dsp-noirq",
- "msm-cpe-lsm.3";
+ "msm-cpe-lsm.3", "msm-transcode-loopback";
asoc-cpu = <&dai_hdmi>, <&dai_dp>,
<&dai_mi2s0>, <&dai_mi2s1>,
<&dai_mi2s2>, <&dai_mi2s3>,
@@ -222,14 +222,15 @@
asoc-platform = <&pcm0>, <&pcm1>, <&pcm2>, <&voip>, <&voice>,
<&loopback>, <&compress>, <&hostless>,
<&afe>, <&lsm>, <&routing>, <&cpe>, <&compr>,
- <&pcm_noirq>;
+ <&pcm_noirq>, <&trans_loopback>;
asoc-platform-names = "msm-pcm-dsp.0", "msm-pcm-dsp.1",
"msm-pcm-dsp.2", "msm-voip-dsp",
"msm-pcm-voice", "msm-pcm-loopback",
"msm-compress-dsp", "msm-pcm-hostless",
"msm-pcm-afe", "msm-lsm-client",
"msm-pcm-routing", "msm-cpe-lsm",
- "msm-compr-dsp", "msm-pcm-dsp-noirq";
+ "msm-compr-dsp", "msm-pcm-dsp-noirq",
+ "msm-transcode-loopback";
asoc-cpu = <&dai_hdmi>, <&dai_dp>,
<&dai_mi2s0>, <&dai_mi2s1>,
<&dai_mi2s2>, <&dai_mi2s3>,
diff --git a/arch/arm/boot/dts/qcom/msm8998-cdp.dtsi b/arch/arm/boot/dts/qcom/msm8998-cdp.dtsi
index 80888b73ef12..6ff62544b03c 100644
--- a/arch/arm/boot/dts/qcom/msm8998-cdp.dtsi
+++ b/arch/arm/boot/dts/qcom/msm8998-cdp.dtsi
@@ -258,7 +258,7 @@
qcom,mdss-dsi-mode-sel-gpio-state = "dual_port";
qcom,panel-supply-entries = <&dsi_panel_pwr_supply>;
qcom,partial-update-enabled = "single_roi";
- qcom,panel-roi-alignment = <720 128 720 128 1440 128>;
+ qcom,panel-roi-alignment = <720 256 720 256 1440 256>;
};
&dsi_dual_nt35597_truly_video {
diff --git a/arch/arm/boot/dts/qcom/msm8998-mdss-panels.dtsi b/arch/arm/boot/dts/qcom/msm8998-mdss-panels.dtsi
index 7de4fbbbf9ff..b53ff87d5092 100644
--- a/arch/arm/boot/dts/qcom/msm8998-mdss-panels.dtsi
+++ b/arch/arm/boot/dts/qcom/msm8998-mdss-panels.dtsi
@@ -152,6 +152,10 @@
qcom,mdss-dsi-panel-timings = [00 35 0a 0c 15 1b 09 0d 0a 03 04 00];
qcom,mdss-dsi-t-clk-post = <0x0d>;
qcom,mdss-dsi-t-clk-pre = <0x26>;
+ qcom,mdss-dsi-min-refresh-rate = <55>;
+ qcom,mdss-dsi-max-refresh-rate = <60>;
+ qcom,mdss-dsi-pan-enable-dynamic-fps;
+ qcom,mdss-dsi-pan-fps-update = "dfps_immediate_porch_mode_vfp";
};
&dsi_sharp_4k_dsc_cmd {
diff --git a/arch/arm/boot/dts/qcom/msm8998-mdss.dtsi b/arch/arm/boot/dts/qcom/msm8998-mdss.dtsi
index b7651aee5a67..5708fce44378 100644
--- a/arch/arm/boot/dts/qcom/msm8998-mdss.dtsi
+++ b/arch/arm/boot/dts/qcom/msm8998-mdss.dtsi
@@ -387,6 +387,8 @@
qcom,mdss-mdp = <&mdss_mdp>;
qcom,mdss-fb-map = <&mdss_fb0>;
+ qcom,null-insertion-enabled;
+
clocks = <&clock_mmss clk_mmss_mdss_byte0_clk>,
<&clock_mmss clk_mmss_mdss_pclk0_clk>,
<&clock_mmss clk_mmss_mdss_esc0_clk>,
@@ -425,6 +427,8 @@
qcom,mdss-mdp = <&mdss_mdp>;
qcom,mdss-fb-map = <&mdss_fb0>;
+ qcom,null-insertion-enabled;
+
clocks = <&clock_mmss clk_mmss_mdss_byte1_clk>,
<&clock_mmss clk_mmss_mdss_pclk1_clk>,
<&clock_mmss clk_mmss_mdss_esc1_clk>,
diff --git a/arch/arm/boot/dts/qcom/msm8998-mtp.dtsi b/arch/arm/boot/dts/qcom/msm8998-mtp.dtsi
index e3e9d45bc784..bafe29211ef0 100644
--- a/arch/arm/boot/dts/qcom/msm8998-mtp.dtsi
+++ b/arch/arm/boot/dts/qcom/msm8998-mtp.dtsi
@@ -319,7 +319,7 @@
qcom,mdss-dsi-mode-sel-gpio-state = "dual_port";
qcom,panel-supply-entries = <&dsi_panel_pwr_supply>;
qcom,partial-update-enabled = "single_roi";
- qcom,panel-roi-alignment = <720 128 720 128 1440 128>;
+ qcom,panel-roi-alignment = <720 256 720 256 1440 256>;
};
&dsi_dual_nt35597_truly_video {
diff --git a/arch/arm/boot/dts/qcom/msm8998-pinctrl.dtsi b/arch/arm/boot/dts/qcom/msm8998-pinctrl.dtsi
index 318dc5d7c791..71593012148d 100644
--- a/arch/arm/boot/dts/qcom/msm8998-pinctrl.dtsi
+++ b/arch/arm/boot/dts/qcom/msm8998-pinctrl.dtsi
@@ -975,7 +975,7 @@
config {
pins = "gpio26", "gpio126";
- bias-disable;
+ bias-pull-up;
drive-strength = <2>; /* 2 MA */
};
};
diff --git a/arch/arm/boot/dts/qcom/msm8998-qrd-skuk-hdk.dtsi b/arch/arm/boot/dts/qcom/msm8998-qrd-skuk-hdk.dtsi
index 3c76519acdcf..7809b81fcefd 100644
--- a/arch/arm/boot/dts/qcom/msm8998-qrd-skuk-hdk.dtsi
+++ b/arch/arm/boot/dts/qcom/msm8998-qrd-skuk-hdk.dtsi
@@ -87,8 +87,8 @@
qcom,platform-te-gpio = <&tlmm 10 0>;
qcom,platform-enable-gpio = <&tlmm 52 0>;
qcom,platform-reset-gpio = <&tlmm 94 0>;
- qcom,platform-bklight-en-gpio = <&pmi8998_gpios 1 0>;
- qcom,platform-bklight-en-gpio-invert;
+ qcom,platform-avdd-en-gpio = <&pmi8998_gpios 1 0>;
+ qcom,platform-avdd-en-gpio-invert;
};
&mdss_dsi1 {
@@ -99,8 +99,8 @@
qcom,platform-te-gpio = <&tlmm 10 0>;
qcom,platform-enable-gpio = <&tlmm 52 0>;
qcom,platform-reset-gpio = <&tlmm 94 0>;
- qcom,platform-bklight-en-gpio = <&pmi8998_gpios 1 0>;
- qcom,platform-bklight-en-gpio-invert;
+ qcom,platform-avdd-en-gpio = <&pmi8998_gpios 1 0>;
+ qcom,platform-avdd-en-gpio-invert;
};
&pmi8998_wled {
@@ -114,7 +114,7 @@
};
&pmi8998_gpios {
- /* GPIO 1 for WLED power enable */
+ /* GPIO 1 for AVDD power enable */
gpio@c000 {
qcom,mode = <1>;
qcom,output-type = <0>;
diff --git a/arch/arm/boot/dts/qcom/msm8998-qrd-vr1.dtsi b/arch/arm/boot/dts/qcom/msm8998-qrd-vr1.dtsi
index 0d0c66d7f26e..9b1145242cc0 100644
--- a/arch/arm/boot/dts/qcom/msm8998-qrd-vr1.dtsi
+++ b/arch/arm/boot/dts/qcom/msm8998-qrd-vr1.dtsi
@@ -420,8 +420,8 @@
qcom,platform-te-gpio = <&tlmm 10 0>;
qcom,platform-enable-gpio = <&tlmm 52 0>;
qcom,platform-reset-gpio = <&tlmm 94 0>;
- qcom,platform-bklight-en-gpio = <&pmi8998_gpios 1 0>;
- qcom,platform-bklight-en-gpio-invert;
+ qcom,platform-avdd-en-gpio = <&pmi8998_gpios 1 0>;
+ qcom,platform-avdd-en-gpio-invert;
};
&mdss_dsi1 {
@@ -432,8 +432,8 @@
qcom,platform-te-gpio = <&tlmm 10 0>;
qcom,platform-enable-gpio = <&tlmm 52 0>;
qcom,platform-reset-gpio = <&tlmm 94 0>;
- qcom,platform-bklight-en-gpio = <&pmi8998_gpios 1 0>;
- qcom,platform-bklight-en-gpio-invert;
+ qcom,platform-avdd-en-gpio = <&pmi8998_gpios 1 0>;
+ qcom,platform-avdd-en-gpio-invert;
};
&pmi8998_wled {
@@ -447,7 +447,7 @@
};
&pmi8998_gpios {
- /* GPIO 1 for WLED power enable */
+ /* GPIO 1 for AVDD power enable */
gpio@c000 {
qcom,mode = <1>;
qcom,output-type = <0>;
diff --git a/arch/arm/boot/dts/qcom/msm8998-regulator.dtsi b/arch/arm/boot/dts/qcom/msm8998-regulator.dtsi
index be70f129e272..bfd2a035d2a4 100644
--- a/arch/arm/boot/dts/qcom/msm8998-regulator.dtsi
+++ b/arch/arm/boot/dts/qcom/msm8998-regulator.dtsi
@@ -502,6 +502,8 @@
pmi8998_bob: regulator-bob {
regulator-min-microvolt = <3312000>;
regulator-max-microvolt = <3600000>;
+ qcom,pwm-threshold-current = <2000000>;
+ qcom,init-bob-mode = <2>;
status = "okay";
};
pmi8998_bob_pin1: regulator-bob-pin1 {
@@ -510,6 +512,8 @@
qcom,set = <3>;
regulator-min-microvolt = <3312000>;
regulator-max-microvolt = <3600000>;
+ qcom,pwm-threshold-current = <2000000>;
+ qcom,init-bob-mode = <2>;
qcom,use-pin-ctrl-voltage1;
};
pmi8998_bob_pin2: regulator-bob-pin2 {
@@ -518,6 +522,8 @@
qcom,set = <3>;
regulator-min-microvolt = <3312000>;
regulator-max-microvolt = <3600000>;
+ qcom,pwm-threshold-current = <2000000>;
+ qcom,init-bob-mode = <2>;
qcom,use-pin-ctrl-voltage2;
};
pmi8998_bob_pin3: regulator-bob-pin3 {
@@ -526,6 +532,8 @@
qcom,set = <3>;
regulator-min-microvolt = <3312000>;
regulator-max-microvolt = <3600000>;
+ qcom,pwm-threshold-current = <2000000>;
+ qcom,init-bob-mode = <2>;
qcom,use-pin-ctrl-voltage3;
};
};
diff --git a/arch/arm/boot/dts/qcom/msm8998-sde-display.dtsi b/arch/arm/boot/dts/qcom/msm8998-sde-display.dtsi
index 6098a96db206..6e19c77995c1 100644
--- a/arch/arm/boot/dts/qcom/msm8998-sde-display.dtsi
+++ b/arch/arm/boot/dts/qcom/msm8998-sde-display.dtsi
@@ -34,6 +34,40 @@
qcom,msm_ext_disp = <&msm_ext_disp>;
};
+ sde_hdmi_cec: qcom,hdmi-cec@c9a0000 {
+ compatible = "qcom,hdmi-cec";
+ label = "sde_hdmi_cec";
+ qcom,hdmi-dev = <&sde_hdmi>;
+ interrupt-parent = <&sde_hdmi_tx>;
+ interrupts = <1 0>;
+
+ reg = <0xc9a0000 0x50c>;
+ reg-names = "hdmi_cec";
+
+ clocks = <&clock_mmss clk_mmss_mnoc_ahb_clk>,
+ <&clock_mmss clk_mmss_mdss_ahb_clk>,
+ <&clock_mmss clk_mmss_mdss_hdmi_clk>;
+ clock-names = "cec_mnoc_clk", "cec_iface_clk", "cec_core_clk";
+
+ pinctrl-names = "cec_active", "cec_sleep";
+ pinctrl-0 = <&mdss_hdmi_cec_active>;
+ pinctrl-1 = <&mdss_hdmi_cec_suspend>;
+
+ cec-gdsc-supply = <&gdsc_mdss>;
+ qcom,platform-supply-entries {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ qcom,platform-supply-entry@0 {
+ reg = <0>;
+ qcom,supply-name = "cec-gdsc";
+ qcom,supply-min-voltage = <0>;
+ qcom,supply-max-voltage = <0>;
+ qcom,supply-enable-load = <0>;
+ qcom,supply-disable-load = <0>;
+ };
+ };
+ };
};
&sde_kms {
diff --git a/arch/arm/boot/dts/qcom/msm8998-sde.dtsi b/arch/arm/boot/dts/qcom/msm8998-sde.dtsi
index f7dbda515643..795635d8d13d 100644
--- a/arch/arm/boot/dts/qcom/msm8998-sde.dtsi
+++ b/arch/arm/boot/dts/qcom/msm8998-sde.dtsi
@@ -175,6 +175,8 @@
reg-names = "core_physical", "qfprom_physical", "hdcp_physical";
interrupt-parent = <&sde_kms>;
interrupts = <8 0>;
+ interrupt-controller;
+ #interrupt-cells = <1>;
qcom,hdmi-tx-ddc-clk-gpio = <&tlmm 32 0>;
qcom,hdmi-tx-ddc-data-gpio = <&tlmm 33 0>;
qcom,hdmi-tx-hpd-gpio = <&tlmm 34 0>;
@@ -182,11 +184,9 @@
pinctrl-names = "default", "sleep";
pinctrl-0 = <&mdss_hdmi_hpd_active
&mdss_hdmi_ddc_active
- &mdss_hdmi_cec_active
&mdss_hdmi_5v_active>;
pinctrl-1 = <&mdss_hdmi_hpd_suspend
&mdss_hdmi_ddc_suspend
- &mdss_hdmi_cec_suspend
&mdss_hdmi_5v_suspend>;
hpd-gdsc-supply = <&gdsc_mdss>;
qcom,supply-names = "hpd-gdsc";
diff --git a/arch/arm/boot/dts/qcom/msm8998.dtsi b/arch/arm/boot/dts/qcom/msm8998.dtsi
index 0fb84e024698..3dbb019443c4 100644
--- a/arch/arm/boot/dts/qcom/msm8998.dtsi
+++ b/arch/arm/boot/dts/qcom/msm8998.dtsi
@@ -282,6 +282,23 @@
compatible = "simple-bus";
};
+ firmware: firmware {
+ android {
+ compatible = "android,firmware";
+ fstab {
+ compatible = "android,fstab";
+ vendor {
+ compatible = "android,vendor";
+ dev = "/dev/block/platform/soc/1da4000.ufshc/by-name/vendor";
+ type = "ext4";
+ mnt_flags = "ro,barrier=1,discard";
+ fsmgr_flags = "wait,slotselect";
+ status = "ok";
+ };
+ };
+ };
+ };
+
reserved-memory {
#address-cells = <2>;
#size-cells = <2>;
@@ -2635,7 +2652,7 @@
0x260 0x10 0x00
0x28c 0x06 0x00
0x504 0x03 0x00
- 0x500 0x1c 0x00
+ 0x500 0x10 0x00
0x50c 0x14 0x00
0x4d4 0x0a 0x00
0x4d8 0x04 0x00
@@ -2657,7 +2674,7 @@
0x9a8 0x00 0x00
0x8a4 0x01 0x00
0x8a8 0x73 0x00
- 0x9d8 0x99 0x00
+ 0x9d8 0xaa 0x00
0x9b0 0x03 0x00
0x804 0x03 0x00
0x800 0x00 0x00
@@ -3205,6 +3222,7 @@
qcom,smmu-fast-map;
qcom,smmu-coherent;
qcom,smmu-mapping = <0x20000000 0xe0000000>;
+ qcom,keep-radio-on-during-sleep;
status = "disabled";
};
diff --git a/arch/arm/boot/dts/qcom/sdm630-camera.dtsi b/arch/arm/boot/dts/qcom/sdm630-camera.dtsi
index 75b30791ffdc..834a5706a525 100644
--- a/arch/arm/boot/dts/qcom/sdm630-camera.dtsi
+++ b/arch/arm/boot/dts/qcom/sdm630-camera.dtsi
@@ -395,6 +395,7 @@
reset-names = "micro_iface_reset";
qcom,src-clock-rates = <120000000 256000000 384000000
480000000 540000000 576000000>;
+ qcom,micro-reset;
qcom,cpp-fw-payload-info {
qcom,stripe-base = <790>;
qcom,plane-base = <715>;
diff --git a/arch/arm/boot/dts/qcom/vplatform-lfv-msm8996.dts b/arch/arm/boot/dts/qcom/vplatform-lfv-msm8996.dts
index 99f17844e508..8ad7ca7f9743 100644
--- a/arch/arm/boot/dts/qcom/vplatform-lfv-msm8996.dts
+++ b/arch/arm/boot/dts/qcom/vplatform-lfv-msm8996.dts
@@ -63,14 +63,14 @@
asoc-platform = <&pcm0>, <&pcm1>, <&pcm2>, <&voip>, <&voice>,
<&loopback>, <&compress>, <&hostless>,
- <&afe>, <&lsm>, <&routing>, <&compr>,
+ <&afe>, <&lsm>, <&routing>, <&pcmnoirq>,
<&loopback1>;
asoc-platform-names = "msm-pcm-dsp.0", "msm-pcm-dsp.1",
"msm-pcm-dsp.2", "msm-voip-dsp",
"msm-pcm-voice", "msm-pcm-loopback",
"msm-compress-dsp", "msm-pcm-hostless",
"msm-pcm-afe", "msm-lsm-client",
- "msm-pcm-routing", "msm-compr-dsp",
+ "msm-pcm-routing", "msm-pcm-dsp-noirq",
"msm-pcm-loopback.1";
asoc-cpu = <&dai_pri_auxpcm>, <&dai_sec_auxpcm>, <&dai_hdmi>,
<&dai_mi2s_sec>, <&dai_mi2s>, <&dai_mi2s_quat>,
@@ -78,14 +78,17 @@
<&afe_proxy_rx>, <&afe_proxy_tx>,
<&incall_record_rx>, <&incall_record_tx>,
<&incall_music_rx>, <&incall_music2_rx>,
+ <&dai_sec_tdm_tx_0>, <&dai_sec_tdm_tx_1>,
+ <&dai_sec_tdm_tx_2>, <&dai_sec_tdm_tx_3>,
<&dai_tert_tdm_rx_0>, <&dai_tert_tdm_rx_1>,
<&dai_tert_tdm_rx_2>, <&dai_tert_tdm_rx_3>,
- <&dai_tert_tdm_tx_0>, <&dai_tert_tdm_tx_1>,
- <&dai_tert_tdm_tx_2>, <&dai_tert_tdm_tx_3>,
- <&dai_quat_tdm_rx_0>, <&dai_quat_tdm_rx_1>,
- <&dai_quat_tdm_rx_2>, <&dai_quat_tdm_rx_3>,
- <&dai_quat_tdm_tx_0>, <&dai_quat_tdm_tx_1>,
- <&dai_quat_tdm_tx_2>, <&dai_quat_tdm_tx_3>;
+ <&dai_tert_tdm_rx_4>, <&dai_tert_tdm_tx_0>,
+ <&dai_tert_tdm_tx_1>, <&dai_tert_tdm_tx_2>,
+ <&dai_tert_tdm_tx_3>, <&dai_quat_tdm_rx_0>,
+ <&dai_quat_tdm_rx_1>, <&dai_quat_tdm_rx_2>,
+ <&dai_quat_tdm_rx_3>, <&dai_quat_tdm_tx_0>,
+ <&dai_quat_tdm_tx_1>, <&dai_quat_tdm_tx_2>,
+ <&dai_quat_tdm_tx_3>;
asoc-cpu-names = "msm-dai-q6-auxpcm.1", "msm-dai-q6-auxpcm.2",
"msm-dai-q6-hdmi.8", "msm-dai-q6-mi2s.1",
"msm-dai-q6-mi2s.2", "msm-dai-q6-mi2s.3",
@@ -93,14 +96,17 @@
"msm-dai-q6-dev.241", "msm-dai-q6-dev.240",
"msm-dai-q6-dev.32771", "msm-dai-q6-dev.32772",
"msm-dai-q6-dev.32773", "msm-dai-q6-dev.32770",
+ "msm-dai-q6-tdm.36881", "msm-dai-q6-tdm.36883",
+ "msm-dai-q6-tdm.36885", "msm-dai-q6-tdm.36887",
"msm-dai-q6-tdm.36896", "msm-dai-q6-tdm.36898",
"msm-dai-q6-tdm.36900", "msm-dai-q6-tdm.36902",
- "msm-dai-q6-tdm.36897", "msm-dai-q6-tdm.36899",
- "msm-dai-q6-tdm.36901", "msm-dai-q6-tdm.36903",
- "msm-dai-q6-tdm.36912", "msm-dai-q6-tdm.36914",
- "msm-dai-q6-tdm.36916", "msm-dai-q6-tdm.36918",
- "msm-dai-q6-tdm.36913", "msm-dai-q6-tdm.36915",
- "msm-dai-q6-tdm.36917", "msm-dai-q6-tdm.36919";
+ "msm-dai-q6-tdm.36904", "msm-dai-q6-tdm.36897",
+ "msm-dai-q6-tdm.36899", "msm-dai-q6-tdm.36901",
+ "msm-dai-q6-tdm.36903", "msm-dai-q6-tdm.36912",
+ "msm-dai-q6-tdm.36914", "msm-dai-q6-tdm.36916",
+ "msm-dai-q6-tdm.36918", "msm-dai-q6-tdm.36913",
+ "msm-dai-q6-tdm.36915", "msm-dai-q6-tdm.36917",
+ "msm-dai-q6-tdm.36919";
asoc-codec = <&stub_codec>;
asoc-codec-names = "msm-stub-codec.1";
};
@@ -134,14 +140,16 @@
compatible = "qcom,msm-pcm-routing";
};
- compr: qcom,msm-compr-dsp {
- compatible = "qcom,msm-compr-dsp";
- };
-
compress: qcom,msm-compress-dsp {
compatible = "qcom,msm-compress-dsp";
};
+ pcmnoirq: qcom,msm-pcm-dsp-noirq {
+ compatible = "qcom,msm-pcm-dsp-noirq";
+ qcom,msm-pcm-low-latency;
+ qcom,latency-level = "ultra";
+ };
+
voip: qcom,msm-voip-dsp {
compatible = "qcom,msm-voip-dsp";
};
@@ -280,8 +288,9 @@
qcom,msm-dai-tdm-tert-rx {
compatible = "qcom,msm-dai-tdm";
qcom,msm-cpudai-tdm-group-id = <37152>;
- qcom,msm-cpudai-tdm-group-num-ports = <4>;
- qcom,msm-cpudai-tdm-group-port-id = <36896 36898 36900 36902>;
+ qcom,msm-cpudai-tdm-group-num-ports = <5>;
+ qcom,msm-cpudai-tdm-group-port-id =
+ <36896 36898 36900 36902 36904>;
qcom,msm-cpudai-tdm-clk-rate = <0>;
dai_tert_tdm_rx_0: qcom,msm-dai-q6-tdm-tert-rx-0 {
compatible = "qcom,msm-dai-q6-tdm";
@@ -326,6 +335,16 @@
qcom,msm-cpudai-tdm-data-delay = <0>;
qcom,msm-cpudai-tdm-data-align = <0>;
};
+ dai_tert_tdm_rx_4: qcom,msm-dai-q6-tdm-tert-rx-4 {
+ compatible = "qcom,msm-dai-q6-tdm";
+ qcom,msm-cpudai-tdm-dev-id = <36904>;
+ qcom,msm-cpudai-tdm-sync-mode = <1>;
+ qcom,msm-cpudai-tdm-sync-src = <0>;
+ qcom,msm-cpudai-tdm-data-out = <0>;
+ qcom,msm-cpudai-tdm-invert-sync = <0>;
+ qcom,msm-cpudai-tdm-data-delay = <0>;
+ qcom,msm-cpudai-tdm-data-align = <0>;
+ };
};
qcom,msm-dai-tdm-tert-tx {
@@ -481,6 +500,54 @@
};
};
+ qcom,msm-dai-tdm-sec-tx {
+ compatible = "qcom,msm-dai-tdm";
+ qcom,msm-cpudai-tdm-group-id = <37137>;
+ qcom,msm-cpudai-tdm-group-num-ports = <4>;
+ qcom,msm-cpudai-tdm-group-port-id = <36881 36883 36885 36887>;
+ qcom,msm-cpudai-tdm-clk-rate = <0>;
+ dai_sec_tdm_tx_0: qcom,msm-dai-q6-tdm-sec-tx-0 {
+ compatible = "qcom,msm-dai-q6-tdm";
+ qcom,msm-cpudai-tdm-dev-id = <36881>;
+ qcom,msm-cpudai-tdm-sync-mode = <1>;
+ qcom,msm-cpudai-tdm-sync-src = <0>;
+ qcom,msm-cpudai-tdm-data-out = <0>;
+ qcom,msm-cpudai-tdm-invert-sync = <0>;
+ qcom,msm-cpudai-tdm-data-delay = <0>;
+ qcom,msm-cpudai-tdm-data-align = <0>;
+ };
+ dai_sec_tdm_tx_1: qcom,msm-dai-q6-tdm-sec-tx-1 {
+ compatible = "qcom,msm-dai-q6-tdm";
+ qcom,msm-cpudai-tdm-dev-id = <36883>;
+ qcom,msm-cpudai-tdm-sync-mode = <1>;
+ qcom,msm-cpudai-tdm-sync-src = <0>;
+ qcom,msm-cpudai-tdm-data-out = <0>;
+ qcom,msm-cpudai-tdm-invert-sync = <0>;
+ qcom,msm-cpudai-tdm-data-delay = <0>;
+ qcom,msm-cpudai-tdm-data-align = <0>;
+ };
+ dai_sec_tdm_tx_2: qcom,msm-dai-q6-tdm-sec-tx-2 {
+ compatible = "qcom,msm-dai-q6-tdm";
+ qcom,msm-cpudai-tdm-dev-id = <36885>;
+ qcom,msm-cpudai-tdm-sync-mode = <1>;
+ qcom,msm-cpudai-tdm-sync-src = <0>;
+ qcom,msm-cpudai-tdm-data-out = <0>;
+ qcom,msm-cpudai-tdm-invert-sync = <0>;
+ qcom,msm-cpudai-tdm-data-delay = <0>;
+ qcom,msm-cpudai-tdm-data-align = <0>;
+ };
+ dai_sec_tdm_tx_3: qcom,msm-dai-q6-tdm-sec-tx-3 {
+ compatible = "qcom,msm-dai-q6-tdm";
+ qcom,msm-cpudai-tdm-dev-id = <36887>;
+ qcom,msm-cpudai-tdm-sync-mode = <1>;
+ qcom,msm-cpudai-tdm-sync-src = <0>;
+ qcom,msm-cpudai-tdm-data-out = <0>;
+ qcom,msm-cpudai-tdm-invert-sync = <0>;
+ qcom,msm-cpudai-tdm-data-delay = <0>;
+ qcom,msm-cpudai-tdm-data-align = <0>;
+ };
+ };
+
hostless: qcom,msm-pcm-hostless {
compatible = "qcom,msm-pcm-hostless";
};
diff --git a/arch/arm/include/asm/perf_event.h b/arch/arm/include/asm/perf_event.h
index 4f9dec489931..306c4f4e778e 100644
--- a/arch/arm/include/asm/perf_event.h
+++ b/arch/arm/include/asm/perf_event.h
@@ -26,4 +26,91 @@ extern unsigned long perf_misc_flags(struct pt_regs *regs);
(regs)->ARM_cpsr = SVC_MODE; \
}
+static inline u32 armv8pmu_pmcr_read_reg(void)
+{
+ u32 val;
+
+ asm volatile("mrc p15, 0, %0, c9, c12, 0" : "=r" (val));
+ return val;
+}
+
+static inline u32 armv8pmu_pmccntr_read_reg(void)
+{
+ u32 val;
+
+ asm volatile("mrc p15, 0, %0, c9, c13, 0" : "=r" (val));
+ return val;
+}
+
+static inline u32 armv8pmu_pmxevcntr_read_reg(void)
+{
+ u32 val;
+
+ asm volatile("mrc p15, 0, %0, c9, c13, 2" : "=r" (val));
+ return val;
+}
+
+static inline u32 armv8pmu_pmovsclr_read_reg(void)
+{
+ u32 val;
+
+ asm volatile("mrc p15, 0, %0, c9, c12, 3" : "=r" (val));
+ return val;
+}
+
+static inline void armv8pmu_pmcr_write_reg(u32 val)
+{
+ asm volatile("mcr p15, 0, %0, c9, c12, 0" : : "r" (val));
+}
+
+static inline void armv8pmu_pmselr_write_reg(u32 val)
+{
+ asm volatile("mcr p15, 0, %0, c9, c12, 5" : : "r" (val));
+}
+
+static inline void armv8pmu_pmccntr_write_reg(u32 val)
+{
+ asm volatile("mcr p15, 0, %0, c9, c13, 0" : : "r" (val));
+}
+
+static inline void armv8pmu_pmxevcntr_write_reg(u32 val)
+{
+ asm volatile("mcr p15, 0, %0, c9, c13, 2" : : "r" (val));
+}
+
+static inline void armv8pmu_pmxevtyper_write_reg(u32 val)
+{
+ asm volatile("mcr p15, 0, %0, c9, c13, 1" : : "r" (val));
+}
+
+static inline void armv8pmu_pmcntenset_write_reg(u32 val)
+{
+ asm volatile("mcr p15, 0, %0, c9, c12, 1" : : "r" (val));
+}
+
+static inline void armv8pmu_pmcntenclr_write_reg(u32 val)
+{
+ asm volatile("mcr p15, 0, %0, c9, c12, 2" : : "r" (val));
+}
+
+static inline void armv8pmu_pmintenset_write_reg(u32 val)
+{
+ asm volatile("mcr p15, 0, %0, c9, c14, 1" : : "r" (val));
+}
+
+static inline void armv8pmu_pmintenclr_write_reg(u32 val)
+{
+ asm volatile("mcr p15, 0, %0, c9, c14, 2" : : "r" (val));
+}
+
+static inline void armv8pmu_pmovsclr_write_reg(u32 val)
+{
+ asm volatile("mcr p15, 0, %0, c9, c12, 3" : : "r" (val));
+}
+
+static inline void armv8pmu_pmuserenr_write_reg(u32 val)
+{
+ asm volatile("mcr p15, 0, %0, c9, c14, 0" : : "r" (val));
+}
+
#endif /* __ARM_PERF_EVENT_H__ */
diff --git a/arch/arm64/configs/msm-auto-perf_defconfig b/arch/arm64/configs/msm-auto-perf_defconfig
index 81fa3afa8cca..c9dfe25b938a 100644
--- a/arch/arm64/configs/msm-auto-perf_defconfig
+++ b/arch/arm64/configs/msm-auto-perf_defconfig
@@ -10,6 +10,8 @@ CONFIG_TASK_XACCT=y
CONFIG_TASK_IO_ACCOUNTING=y
CONFIG_RCU_EXPERT=y
CONFIG_RCU_FAST_NO_HZ=y
+CONFIG_RCU_NOCB_CPU=y
+CONFIG_RCU_NOCB_CPU_ALL=y
CONFIG_IKCONFIG=y
CONFIG_IKCONFIG_PROC=y
CONFIG_LOG_CPU_MAX_BUF_SHIFT=15
@@ -358,37 +360,13 @@ CONFIG_VIDEO_V4L2_SUBDEV_API=y
CONFIG_V4L_PLATFORM_DRIVERS=y
CONFIG_SOC_CAMERA=y
CONFIG_SOC_CAMERA_PLATFORM=y
-CONFIG_MSM_CAMERA=y
-CONFIG_MSM_CAMERA_DEBUG=y
-CONFIG_MSMB_CAMERA=y
-CONFIG_MSMB_CAMERA_DEBUG=y
-CONFIG_MSM_CAMERA_SENSOR=y
-CONFIG_MSM_CPP=y
-CONFIG_MSM_CCI=y
-CONFIG_MSM_CSI20_HEADER=y
-CONFIG_MSM_CSI22_HEADER=y
-CONFIG_MSM_CSI30_HEADER=y
-CONFIG_MSM_CSI31_HEADER=y
-CONFIG_MSM_CSIPHY=y
-CONFIG_MSM_CSID=y
-CONFIG_MSM_EEPROM=y
-CONFIG_MSM_ISPIF=y
-CONFIG_IMX134=y
-CONFIG_IMX132=y
-CONFIG_OV9724=y
-CONFIG_OV5648=y
-CONFIG_GC0339=y
-CONFIG_OV8825=y
-CONFIG_OV8865=y
-CONFIG_s5k4e1=y
-CONFIG_OV12830=y
-CONFIG_MSMB_JPEG=y
-CONFIG_MSM_FD=y
-CONFIG_MSM_JPEGDMA=y
CONFIG_MSM_VIDC_V4L2=y
CONFIG_MSM_VIDC_VMEM=y
CONFIG_MSM_VIDC_GOVERNORS=y
CONFIG_MSM_SDE_ROTATOR=y
+CONFIG_MSM_AIS=y
+CONFIG_MSM_AIS_DEBUG=y
+CONFIG_MSM_AIS_CAMERA_SENSOR=y
CONFIG_QCOM_KGSL=y
CONFIG_FB=y
CONFIG_FB_MSM=y
@@ -600,6 +578,7 @@ CONFIG_DEBUG_ALIGN_RODATA=y
CONFIG_CORESIGHT=y
CONFIG_CORESIGHT_EVENT=y
CONFIG_CORESIGHT_LINK_AND_SINK_TMC=y
+CONFIG_CORESIGHT_SINK_TPIU=y
CONFIG_CORESIGHT_QCOM_REPLICATOR=y
CONFIG_CORESIGHT_STM=y
CONFIG_CORESIGHT_HWEVENT=y
diff --git a/arch/arm64/configs/msm-auto_defconfig b/arch/arm64/configs/msm-auto_defconfig
index 70674f6043cf..7a139efa1455 100644
--- a/arch/arm64/configs/msm-auto_defconfig
+++ b/arch/arm64/configs/msm-auto_defconfig
@@ -8,6 +8,8 @@ CONFIG_TASKSTATS=y
CONFIG_TASK_XACCT=y
CONFIG_TASK_IO_ACCOUNTING=y
CONFIG_RCU_EXPERT=y
+CONFIG_RCU_NOCB_CPU=y
+CONFIG_RCU_NOCB_CPU_ALL=y
CONFIG_IKCONFIG=y
CONFIG_IKCONFIG_PROC=y
CONFIG_LOG_CPU_MAX_BUF_SHIFT=15
@@ -362,37 +364,13 @@ CONFIG_VIDEO_ADV_DEBUG=y
CONFIG_V4L_PLATFORM_DRIVERS=y
CONFIG_SOC_CAMERA=y
CONFIG_SOC_CAMERA_PLATFORM=y
-CONFIG_MSM_CAMERA=y
-CONFIG_MSM_CAMERA_DEBUG=y
-CONFIG_MSMB_CAMERA=y
-CONFIG_MSMB_CAMERA_DEBUG=y
-CONFIG_MSM_CAMERA_SENSOR=y
-CONFIG_MSM_CPP=y
-CONFIG_MSM_CCI=y
-CONFIG_MSM_CSI20_HEADER=y
-CONFIG_MSM_CSI22_HEADER=y
-CONFIG_MSM_CSI30_HEADER=y
-CONFIG_MSM_CSI31_HEADER=y
-CONFIG_MSM_CSIPHY=y
-CONFIG_MSM_CSID=y
-CONFIG_MSM_EEPROM=y
-CONFIG_MSM_ISPIF=y
-CONFIG_IMX134=y
-CONFIG_IMX132=y
-CONFIG_OV9724=y
-CONFIG_OV5648=y
-CONFIG_GC0339=y
-CONFIG_OV8825=y
-CONFIG_OV8865=y
-CONFIG_s5k4e1=y
-CONFIG_OV12830=y
-CONFIG_MSMB_JPEG=y
-CONFIG_MSM_FD=y
-CONFIG_MSM_JPEGDMA=y
CONFIG_MSM_VIDC_V4L2=y
CONFIG_MSM_VIDC_VMEM=y
CONFIG_MSM_VIDC_GOVERNORS=y
CONFIG_MSM_SDE_ROTATOR=y
+CONFIG_MSM_AIS=y
+CONFIG_MSM_AIS_DEBUG=y
+CONFIG_MSM_AIS_CAMERA_SENSOR=y
CONFIG_QCOM_KGSL=y
CONFIG_FB=y
CONFIG_FB_MSM=y
@@ -640,6 +618,7 @@ CONFIG_FREE_PAGES_RDONLY=y
CONFIG_CORESIGHT=y
CONFIG_CORESIGHT_EVENT=y
CONFIG_CORESIGHT_LINK_AND_SINK_TMC=y
+CONFIG_CORESIGHT_SINK_TPIU=y
CONFIG_CORESIGHT_SOURCE_ETM4X=y
CONFIG_CORESIGHT_REMOTE_ETM=y
CONFIG_CORESIGHT_REMOTE_ETM_DEFAULT_ENABLE=0
diff --git a/arch/arm64/configs/msmcortex_mediabox-perf_defconfig b/arch/arm64/configs/msmcortex_mediabox-perf_defconfig
index 953d700c20cc..b359c78a0d29 100644
--- a/arch/arm64/configs/msmcortex_mediabox-perf_defconfig
+++ b/arch/arm64/configs/msmcortex_mediabox-perf_defconfig
@@ -405,6 +405,7 @@ CONFIG_MSM_VIDC_VMEM=y
CONFIG_MSM_VIDC_GOVERNORS=y
CONFIG_MSM_SDE_ROTATOR=y
CONFIG_MSM_SDE_ROTATOR_EVTLOG_DEBUG=y
+CONFIG_MSM_SDE_HDMI_CEC=y
CONFIG_DVB_MPQ=m
CONFIG_DVB_MPQ_DEMUX=m
CONFIG_DVB_MPQ_MEDIA_BOX_DEMUX=y
diff --git a/arch/arm64/configs/msmcortex_mediabox_defconfig b/arch/arm64/configs/msmcortex_mediabox_defconfig
index d81c10d11318..994b0f230968 100644
--- a/arch/arm64/configs/msmcortex_mediabox_defconfig
+++ b/arch/arm64/configs/msmcortex_mediabox_defconfig
@@ -407,6 +407,7 @@ CONFIG_MSM_VIDC_VMEM=y
CONFIG_MSM_VIDC_GOVERNORS=y
CONFIG_MSM_SDE_ROTATOR=y
CONFIG_MSM_SDE_ROTATOR_EVTLOG_DEBUG=y
+CONFIG_MSM_SDE_HDMI_CEC=y
CONFIG_DVB_MPQ=m
CONFIG_DVB_MPQ_DEMUX=m
CONFIG_DVB_MPQ_MEDIA_BOX_DEMUX=y
diff --git a/arch/arm64/include/asm/perf_event.h b/arch/arm64/include/asm/perf_event.h
index 7bd3cdb533ea..da4397e14e0d 100644
--- a/arch/arm64/include/asm/perf_event.h
+++ b/arch/arm64/include/asm/perf_event.h
@@ -31,4 +31,91 @@ extern unsigned long perf_misc_flags(struct pt_regs *regs);
(regs)->pstate = PSR_MODE_EL1h; \
}
+static inline u32 armv8pmu_pmcr_read_reg(void)
+{
+ u32 val;
+
+ asm volatile("mrs %0, pmcr_el0" : "=r" (val));
+ return val;
+}
+
+static inline u32 armv8pmu_pmccntr_read_reg(void)
+{
+ u32 val;
+
+ asm volatile("mrs %0, pmccntr_el0" : "=r" (val));
+ return val;
+}
+
+static inline u32 armv8pmu_pmxevcntr_read_reg(void)
+{
+ u32 val;
+
+ asm volatile("mrs %0, pmxevcntr_el0" : "=r" (val));
+ return val;
+}
+
+static inline u32 armv8pmu_pmovsclr_read_reg(void)
+{
+ u32 val;
+
+ asm volatile("mrs %0, pmovsclr_el0" : "=r" (val));
+ return val;
+}
+
+static inline void armv8pmu_pmcr_write_reg(u32 val)
+{
+ asm volatile("msr pmcr_el0, %0" :: "r" (val));
+}
+
+static inline void armv8pmu_pmselr_write_reg(u32 val)
+{
+ asm volatile("msr pmselr_el0, %0" :: "r" (val));
+}
+
+static inline void armv8pmu_pmccntr_write_reg(u32 val)
+{
+ asm volatile("msr pmccntr_el0, %0" :: "r" (val));
+}
+
+static inline void armv8pmu_pmxevcntr_write_reg(u32 val)
+{
+ asm volatile("msr pmxevcntr_el0, %0" :: "r" (val));
+}
+
+static inline void armv8pmu_pmxevtyper_write_reg(u32 val)
+{
+ asm volatile("msr pmxevtyper_el0, %0" :: "r" (val));
+}
+
+static inline void armv8pmu_pmcntenset_write_reg(u32 val)
+{
+ asm volatile("msr pmcntenset_el0, %0" :: "r" (val));
+}
+
+static inline void armv8pmu_pmcntenclr_write_reg(u32 val)
+{
+ asm volatile("msr pmcntenclr_el0, %0" :: "r" (val));
+}
+
+static inline void armv8pmu_pmintenset_write_reg(u32 val)
+{
+ asm volatile("msr pmintenset_el1, %0" :: "r" (val));
+}
+
+static inline void armv8pmu_pmintenclr_write_reg(u32 val)
+{
+ asm volatile("msr pmintenclr_el1, %0" :: "r" (val));
+}
+
+static inline void armv8pmu_pmovsclr_write_reg(u32 val)
+{
+ asm volatile("msr pmovsclr_el0, %0" :: "r" (val));
+}
+
+static inline void armv8pmu_pmuserenr_write_reg(u32 val)
+{
+ asm volatile("msr pmuserenr_el0, %0" :: "r" (val));
+}
+
#endif
diff --git a/arch/arm64/kernel/Makefile b/arch/arm64/kernel/Makefile
index 99f4410833b4..bc1b1b0ed6ff 100644
--- a/arch/arm64/kernel/Makefile
+++ b/arch/arm64/kernel/Makefile
@@ -31,8 +31,7 @@ arm64-obj-$(CONFIG_FUNCTION_TRACER) += ftrace.o entry-ftrace.o
arm64-obj-$(CONFIG_MODULES) += arm64ksyms.o module.o
arm64-obj-$(CONFIG_ARM64_MODULE_PLTS) += module-plts.o
arm64-obj-$(CONFIG_PERF_EVENTS) += perf_regs.o perf_callchain.o
-arm64-obj-$(CONFIG_HW_PERF_EVENTS) += perf_event.o perf_debug.o \
- perf_trace_counters.o \
+arm64-obj-$(CONFIG_HW_PERF_EVENTS) += perf_debug.o perf_trace_counters.o \
perf_trace_user.o
arm64-obj-$(CONFIG_HAVE_HW_BREAKPOINT) += hw_breakpoint.o
arm64-obj-$(CONFIG_CPU_PM) += sleep.o suspend.o
diff --git a/drivers/bluetooth/bluetooth-power.c b/drivers/bluetooth/bluetooth-power.c
index 59245ba320f6..99c18e3d66d7 100644
--- a/drivers/bluetooth/bluetooth-power.c
+++ b/drivers/bluetooth/bluetooth-power.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2009-2010, 2013-2016 The Linux Foundation. All rights reserved.
+/* Copyright (c) 2009-2010, 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
@@ -682,7 +682,7 @@ int bt_register_slimdev(struct device *dev)
static long bt_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{
- int ret, pwr_cntrl = 0;
+ int ret = 0, pwr_cntrl = 0;
switch (cmd) {
case BT_CMD_SLIM_TEST:
diff --git a/drivers/bluetooth/btfm_slim_codec.c b/drivers/bluetooth/btfm_slim_codec.c
index 05da1fb1f975..1faebb1759e2 100644
--- a/drivers/bluetooth/btfm_slim_codec.c
+++ b/drivers/bluetooth/btfm_slim_codec.c
@@ -296,9 +296,9 @@ static int btfm_slim_dai_get_channel_map(struct snd_soc_dai *dai,
unsigned int *tx_num, unsigned int *tx_slot,
unsigned int *rx_num, unsigned int *rx_slot)
{
- int i, ret = -EINVAL, *slot, j = 0, num = 1;
+ int i, ret = -EINVAL, *slot = NULL, j = 0, num = 1;
struct btfmslim *btfmslim = dai->dev->platform_data;
- struct btfmslim_ch *ch;
+ struct btfmslim_ch *ch = NULL;
if (!btfmslim)
return ret;
diff --git a/drivers/char/diag/diag_dci.c b/drivers/char/diag/diag_dci.c
index 4748012a37cd..fb45af9c49d3 100644
--- a/drivers/char/diag/diag_dci.c
+++ b/drivers/char/diag/diag_dci.c
@@ -1466,6 +1466,8 @@ void diag_dci_notify_client(int peripheral_mask, int data, int proc)
struct siginfo info;
struct list_head *start, *temp;
struct diag_dci_client_tbl *entry = NULL;
+ struct pid *pid_struct = NULL;
+ struct task_struct *dci_task = NULL;
memset(&info, 0, sizeof(struct siginfo));
info.si_code = SI_QUEUE;
@@ -1483,20 +1485,32 @@ void diag_dci_notify_client(int peripheral_mask, int data, int proc)
continue;
if (entry->client_info.notification_list & peripheral_mask) {
info.si_signo = entry->client_info.signal_type;
- if (entry->client &&
- entry->tgid == entry->client->tgid) {
- DIAG_LOG(DIAG_DEBUG_DCI,
- "entry tgid = %d, dci client tgid = %d\n",
- entry->tgid, entry->client->tgid);
- stat = send_sig_info(
- entry->client_info.signal_type,
- &info, entry->client);
- if (stat)
- pr_err("diag: Err sending dci signal to client, signal data: 0x%x, stat: %d\n",
+ pid_struct = find_get_pid(entry->tgid);
+ if (pid_struct) {
+ dci_task = get_pid_task(pid_struct,
+ PIDTYPE_PID);
+ if (!dci_task) {
+ DIAG_LOG(DIAG_DEBUG_PERIPHERALS,
+ "diag: dci client with pid = %d Exited..\n",
+ entry->tgid);
+ mutex_unlock(&driver->dci_mutex);
+ return;
+ }
+ if (entry->client &&
+ entry->tgid == dci_task->tgid) {
+ DIAG_LOG(DIAG_DEBUG_DCI,
+ "entry tgid = %d, dci client tgid = %d\n",
+ entry->tgid, dci_task->tgid);
+ stat = send_sig_info(
+ entry->client_info.signal_type,
+ &info, dci_task);
+ if (stat)
+ pr_err("diag: Err sending dci signal to client, signal data: 0x%x, stat: %d\n",
info.si_int, stat);
- } else
- pr_err("diag: client data is corrupted, signal data: 0x%x, stat: %d\n",
+ } else
+ pr_err("diag: client data is corrupted, signal data: 0x%x, stat: %d\n",
info.si_int, stat);
+ }
}
}
mutex_unlock(&driver->dci_mutex);
@@ -2230,9 +2244,26 @@ struct diag_dci_client_tbl *dci_lookup_client_entry_pid(int tgid)
{
struct list_head *start, *temp;
struct diag_dci_client_tbl *entry = NULL;
+ struct pid *pid_struct = NULL;
+ struct task_struct *task_s = NULL;
+
list_for_each_safe(start, temp, &driver->dci_client_list) {
entry = list_entry(start, struct diag_dci_client_tbl, track);
- if (entry->client && entry->tgid == entry->client->tgid)
+ pid_struct = find_get_pid(entry->tgid);
+ if (!pid_struct) {
+ DIAG_LOG(DIAG_DEBUG_DCI,
+ "diag: valid pid doesn't exist for pid = %d\n",
+ entry->tgid);
+ continue;
+ }
+ task_s = get_pid_task(pid_struct, PIDTYPE_PID);
+ if (!task_s) {
+ DIAG_LOG(DIAG_DEBUG_DCI,
+ "diag: valid task doesn't exist for pid = %d\n",
+ entry->tgid);
+ continue;
+ }
+ if (task_s == entry->client)
if (entry->client->tgid == tgid)
return entry;
}
diff --git a/drivers/char/diag/diag_debugfs.c b/drivers/char/diag/diag_debugfs.c
index ca7dd88048ac..c963e4658c07 100644
--- a/drivers/char/diag/diag_debugfs.c
+++ b/drivers/char/diag/diag_debugfs.c
@@ -80,7 +80,8 @@ static ssize_t diag_dbgfs_read_status(struct file *file, char __user *ubuf,
"Time Sync Enabled: %d\n"
"MD session mode: %d\n"
"MD session mask: %d\n"
- "Uses Time API: %d\n",
+ "Uses Time API: %d\n"
+ "Supports PD buffering: %d\n",
chk_config_get_id(),
chk_polling_response(),
driver->polling_reg_flag,
@@ -95,11 +96,12 @@ static ssize_t diag_dbgfs_read_status(struct file *file, char __user *ubuf,
driver->time_sync_enabled,
driver->md_session_mode,
driver->md_session_mask,
- driver->uses_time_api);
+ driver->uses_time_api,
+ driver->supports_pd_buffering);
for (i = 0; i < NUM_PERIPHERALS; i++) {
ret += scnprintf(buf+ret, buf_size-ret,
- "p: %s Feature: %02x %02x |%c%c%c%c%c%c%c%c%c|\n",
+ "p: %s Feature: %02x %02x |%c%c%c%c%c%c%c%c%c%c|\n",
PERIPHERAL_STRING(i),
driver->feature[i].feature_mask[0],
driver->feature[i].feature_mask[1],
@@ -108,6 +110,7 @@ static ssize_t diag_dbgfs_read_status(struct file *file, char __user *ubuf,
driver->feature[i].separate_cmd_rsp ? 'C':'c',
driver->feature[i].encode_hdlc ? 'H':'h',
driver->feature[i].mask_centralization ? 'M':'m',
+ driver->feature[i].pd_buffering ? 'P':'p',
driver->feature[i].stm_support ? 'Q':'q',
driver->feature[i].sockets_enabled ? 'S':'s',
driver->feature[i].sent_feature_mask ? 'T':'t',
@@ -273,8 +276,10 @@ static ssize_t diag_dbgfs_read_table(struct file *file, char __user *ubuf,
struct list_head *temp;
struct diag_cmd_reg_t *item = NULL;
+ mutex_lock(&driver->cmd_reg_mutex);
if (diag_dbgfs_table_index == driver->cmd_reg_count) {
diag_dbgfs_table_index = 0;
+ mutex_unlock(&driver->cmd_reg_mutex);
return 0;
}
@@ -283,6 +288,7 @@ static ssize_t diag_dbgfs_read_table(struct file *file, char __user *ubuf,
buf = kzalloc(sizeof(char) * buf_size, GFP_KERNEL);
if (ZERO_OR_NULL_PTR(buf)) {
pr_err("diag: %s, Error allocating memory\n", __func__);
+ mutex_unlock(&driver->cmd_reg_mutex);
return -ENOMEM;
}
buf_size = ksize(buf);
@@ -327,6 +333,7 @@ static ssize_t diag_dbgfs_read_table(struct file *file, char __user *ubuf,
break;
}
diag_dbgfs_table_index = i;
+ mutex_unlock(&driver->cmd_reg_mutex);
*ppos = 0;
ret = simple_read_from_buffer(ubuf, count, ppos, buf, bytes_in_buffer);
diff --git a/drivers/char/diag/diag_masks.c b/drivers/char/diag/diag_masks.c
index 382717bad828..21994d53db91 100644
--- a/drivers/char/diag/diag_masks.c
+++ b/drivers/char/diag/diag_masks.c
@@ -28,7 +28,8 @@
#define DIAG_SET_FEATURE_MASK(x) (feature_bytes[(x)/8] |= (1 << (x & 0x7)))
#define diag_check_update(x) \
- (!info || (info && (info->peripheral_mask & MD_PERIPHERAL_MASK(x)))) \
+ (!info || (info && (info->peripheral_mask & MD_PERIPHERAL_MASK(x))) \
+ || (info && (info->peripheral_mask & MD_PERIPHERAL_PD_MASK(x)))) \
struct diag_mask_info msg_mask;
struct diag_mask_info msg_bt_mask;
@@ -89,7 +90,7 @@ static void diag_send_log_mask_update(uint8_t peripheral, int equip_id)
int err = 0;
int send_once = 0;
int header_len = sizeof(struct diag_ctrl_log_mask);
- uint8_t *buf = NULL;
+ uint8_t *buf = NULL, upd = 0;
uint8_t *temp = NULL;
uint32_t mask_size = 0;
struct diag_ctrl_log_mask ctrl_pkt;
@@ -106,11 +107,25 @@ static void diag_send_log_mask_update(uint8_t peripheral, int equip_id)
return;
}
- if (driver->md_session_mask != 0 &&
- driver->md_session_mask & MD_PERIPHERAL_MASK(peripheral))
- mask_info = driver->md_session_map[peripheral]->log_mask;
- else
+ if (driver->md_session_mask != 0) {
+ if (driver->md_session_mask & MD_PERIPHERAL_MASK(peripheral)) {
+ if (driver->md_session_map[peripheral])
+ mask_info =
+ driver->md_session_map[peripheral]->log_mask;
+ } else if (driver->md_session_mask &
+ MD_PERIPHERAL_PD_MASK(peripheral)) {
+ upd = diag_mask_to_pd_value(driver->md_session_mask);
+ if (upd && driver->md_session_map[upd])
+ mask_info =
+ driver->md_session_map[upd]->log_mask;
+ } else {
+ DIAG_LOG(DIAG_DEBUG_MASKS,
+ "asking for mask update with unknown session mask\n");
+ return;
+ }
+ } else {
mask_info = &log_mask;
+ }
if (!mask_info || !mask_info->ptr || !mask_info->update_buf)
return;
@@ -195,7 +210,7 @@ static void diag_send_log_mask_update(uint8_t peripheral, int equip_id)
static void diag_send_event_mask_update(uint8_t peripheral)
{
- uint8_t *buf = NULL;
+ uint8_t *buf = NULL, upd = 0;
uint8_t *temp = NULL;
struct diag_ctrl_event_mask header;
struct diag_mask_info *mask_info = NULL;
@@ -220,11 +235,25 @@ static void diag_send_event_mask_update(uint8_t peripheral)
return;
}
- if (driver->md_session_mask != 0 &&
- (driver->md_session_mask & MD_PERIPHERAL_MASK(peripheral)))
- mask_info = driver->md_session_map[peripheral]->event_mask;
- else
+ if (driver->md_session_mask != 0) {
+ if (driver->md_session_mask & MD_PERIPHERAL_MASK(peripheral)) {
+ if (driver->md_session_map[peripheral])
+ mask_info =
+ driver->md_session_map[peripheral]->event_mask;
+ } else if (driver->md_session_mask &
+ MD_PERIPHERAL_PD_MASK(peripheral)) {
+ upd = diag_mask_to_pd_value(driver->md_session_mask);
+ if (upd && driver->md_session_map[upd])
+ mask_info =
+ driver->md_session_map[upd]->event_mask;
+ } else {
+ DIAG_LOG(DIAG_DEBUG_MASKS,
+ "asking for mask update with unknown session mask\n");
+ return;
+ }
+ } else {
mask_info = &event_mask;
+ }
if (!mask_info || !mask_info->ptr || !mask_info->update_buf)
return;
@@ -284,7 +313,7 @@ static void diag_send_msg_mask_update(uint8_t peripheral, int first, int last)
int err = 0;
int header_len = sizeof(struct diag_ctrl_msg_mask);
int temp_len = 0;
- uint8_t *buf = NULL;
+ uint8_t *buf = NULL, upd = 0;
uint8_t *temp = NULL;
uint32_t mask_size = 0;
struct diag_mask_info *mask_info = NULL;
@@ -301,11 +330,25 @@ static void diag_send_msg_mask_update(uint8_t peripheral, int first, int last)
return;
}
- if (driver->md_session_mask != 0 &&
- (driver->md_session_mask & MD_PERIPHERAL_MASK(peripheral)))
- mask_info = driver->md_session_map[peripheral]->msg_mask;
- else
+ if (driver->md_session_mask != 0) {
+ if (driver->md_session_mask & MD_PERIPHERAL_MASK(peripheral)) {
+ if (driver->md_session_map[peripheral])
+ mask_info =
+ driver->md_session_map[peripheral]->msg_mask;
+ } else if (driver->md_session_mask &
+ MD_PERIPHERAL_PD_MASK(peripheral)) {
+ upd = diag_mask_to_pd_value(driver->md_session_mask);
+ if (upd && driver->md_session_map[upd])
+ mask_info =
+ driver->md_session_map[upd]->msg_mask;
+ } else {
+ DIAG_LOG(DIAG_DEBUG_MASKS,
+ "asking for mask update with unknown session mask\n");
+ return;
+ }
+ } else {
mask_info = &msg_mask;
+ }
if (!mask_info || !mask_info->ptr || !mask_info->update_buf)
return;
diff --git a/drivers/char/diag/diag_memorydevice.c b/drivers/char/diag/diag_memorydevice.c
index a5d92c51cc0b..7b414bd7d808 100644
--- a/drivers/char/diag/diag_memorydevice.c
+++ b/drivers/char/diag/diag_memorydevice.c
@@ -360,10 +360,6 @@ drop_data:
err = copy_to_user(buf + sizeof(int),
(void *)&num_data,
sizeof(int));
- } else {
- DIAG_LOG(DIAG_DEBUG_PERIPHERALS,
- "diag: md_session_map[%d] with pid = %d Exited..\n",
- peripheral, driver->md_session_map[peripheral]->pid);
}
diag_ws_on_copy_complete(DIAG_WS_MUX);
if (drain_again)
diff --git a/drivers/char/diag/diagchar.h b/drivers/char/diag/diagchar.h
index 4047a2c42bb7..a7d7fd176302 100644
--- a/drivers/char/diag/diagchar.h
+++ b/drivers/char/diag/diagchar.h
@@ -235,6 +235,10 @@
#define MD_PERIPHERAL_MASK(x) (1 << x)
+#define MD_PERIPHERAL_PD_MASK(x) \
+ ((x == PERIPHERAL_MODEM) ? (1 << UPD_WLAN) : \
+ ((x == PERIPHERAL_LPASS) ? (1 << UPD_AUDIO | 1 << UPD_SENSORS) : 0))\
+
/*
* Number of stm processors includes all the peripherals and
* apps.Added 1 below to indicate apps
@@ -478,6 +482,7 @@ struct diag_feature_t {
uint8_t encode_hdlc;
uint8_t untag_header;
uint8_t peripheral_buffering;
+ uint8_t pd_buffering;
uint8_t mask_centralization;
uint8_t stm_support;
uint8_t sockets_enabled;
@@ -509,6 +514,7 @@ struct diagchar_dev {
int supports_separate_cmdrsp;
int supports_apps_hdlc_encoding;
int supports_apps_header_untagging;
+ int supports_pd_buffering;
int peripheral_untag[NUM_PERIPHERALS];
int supports_sockets;
/* The state requested in the STM command */
@@ -561,8 +567,8 @@ struct diagchar_dev {
struct diagfwd_info *diagfwd_cmd[NUM_PERIPHERALS];
struct diagfwd_info *diagfwd_dci_cmd[NUM_PERIPHERALS];
struct diag_feature_t feature[NUM_PERIPHERALS];
- struct diag_buffering_mode_t buffering_mode[NUM_PERIPHERALS];
- uint8_t buffering_flag[NUM_PERIPHERALS];
+ struct diag_buffering_mode_t buffering_mode[NUM_MD_SESSIONS];
+ uint8_t buffering_flag[NUM_MD_SESSIONS];
struct mutex mode_lock;
unsigned char *user_space_data_buf;
uint8_t user_space_data_busy;
@@ -673,6 +679,7 @@ void diag_cmd_remove_reg_by_proc(int proc);
int diag_cmd_chk_polling(struct diag_cmd_reg_entry_t *entry);
int diag_mask_param(void);
void diag_clear_masks(struct diag_md_session_t *info);
+uint8_t diag_mask_to_pd_value(uint32_t peripheral_mask);
void diag_record_stats(int type, int flag);
diff --git a/drivers/char/diag/diagchar_core.c b/drivers/char/diag/diagchar_core.c
index 60bfb2af49d0..6be7c48f75a8 100644
--- a/drivers/char/diag/diagchar_core.c
+++ b/drivers/char/diag/diagchar_core.c
@@ -403,6 +403,30 @@ static uint32_t diag_translate_kernel_to_user_mask(uint32_t peripheral_mask)
ret |= DIAG_CON_UPD_SENSORS;
return ret;
}
+
+uint8_t diag_mask_to_pd_value(uint32_t peripheral_mask)
+{
+ uint8_t upd = 0;
+ uint32_t pd_mask = 0;
+
+ pd_mask = diag_translate_kernel_to_user_mask(peripheral_mask);
+ switch (pd_mask) {
+ case DIAG_CON_UPD_WLAN:
+ upd = UPD_WLAN;
+ break;
+ case DIAG_CON_UPD_AUDIO:
+ upd = UPD_AUDIO;
+ break;
+ case DIAG_CON_UPD_SENSORS:
+ upd = UPD_SENSORS;
+ break;
+ default:
+ DIAG_LOG(DIAG_DEBUG_MASKS,
+ "asking for mask update with no pd mask set\n");
+ }
+ return upd;
+}
+
int diag_mask_param(void)
{
return diag_mask_clear_param;
@@ -1908,12 +1932,33 @@ static int diag_ioctl_get_real_time(unsigned long ioarg)
static int diag_ioctl_set_buffering_mode(unsigned long ioarg)
{
struct diag_buffering_mode_t params;
+ int peripheral = 0;
+ uint8_t diag_id = 0;
if (copy_from_user(&params, (void __user *)ioarg, sizeof(params)))
return -EFAULT;
- if (params.peripheral >= NUM_PERIPHERALS)
- return -EINVAL;
+ diag_map_pd_to_diagid(params.peripheral, &diag_id, &peripheral);
+
+ if ((peripheral < 0) ||
+ peripheral >= NUM_PERIPHERALS) {
+ pr_err("diag: In %s, invalid peripheral %d\n", __func__,
+ peripheral);
+ return -EIO;
+ }
+
+ if (params.peripheral > NUM_PERIPHERALS &&
+ !driver->feature[peripheral].pd_buffering) {
+ pr_err("diag: In %s, pd buffering not supported for peripheral:%d\n",
+ __func__, peripheral);
+ return -EIO;
+ }
+
+ if (!driver->feature[peripheral].peripheral_buffering) {
+ pr_err("diag: In %s, peripheral %d doesn't support buffering\n",
+ __func__, peripheral);
+ return -EIO;
+ }
mutex_lock(&driver->mode_lock);
driver->buffering_flag[params.peripheral] = 1;
@@ -1924,24 +1969,29 @@ static int diag_ioctl_set_buffering_mode(unsigned long ioarg)
static int diag_ioctl_peripheral_drain_immediate(unsigned long ioarg)
{
- uint8_t peripheral;
+ uint8_t pd, diag_id = 0;
+ int peripheral = 0;
- if (copy_from_user(&peripheral, (void __user *)ioarg, sizeof(uint8_t)))
+ if (copy_from_user(&pd, (void __user *)ioarg, sizeof(uint8_t)))
return -EFAULT;
- if (peripheral >= NUM_PERIPHERALS) {
+ diag_map_pd_to_diagid(pd, &diag_id, &peripheral);
+
+ if ((peripheral < 0) ||
+ peripheral >= NUM_PERIPHERALS) {
pr_err("diag: In %s, invalid peripheral %d\n", __func__,
peripheral);
return -EINVAL;
}
- if (!driver->feature[peripheral].peripheral_buffering) {
- pr_err("diag: In %s, peripheral %d doesn't support buffering\n",
- __func__, peripheral);
+ if (pd > NUM_PERIPHERALS &&
+ !driver->feature[peripheral].pd_buffering) {
+ pr_err("diag: In %s, pd buffering not supported for peripheral:%d\n",
+ __func__, peripheral);
return -EIO;
}
- return diag_send_peripheral_drain_immediate(peripheral);
+ return diag_send_peripheral_drain_immediate(pd, diag_id, peripheral);
}
static int diag_ioctl_dci_support(unsigned long ioarg)
diff --git a/drivers/char/diag/diagfwd.c b/drivers/char/diag/diagfwd.c
index 8fb724305c03..019bf1946ac3 100644
--- a/drivers/char/diag/diagfwd.c
+++ b/drivers/char/diag/diagfwd.c
@@ -1601,6 +1601,7 @@ int diagfwd_init(void)
driver->supports_separate_cmdrsp = 1;
driver->supports_apps_hdlc_encoding = 1;
driver->supports_apps_header_untagging = 1;
+ driver->supports_pd_buffering = 1;
for (i = 0; i < NUM_PERIPHERALS; i++)
driver->peripheral_untag[i] = 0;
mutex_init(&driver->diag_hdlc_mutex);
@@ -1631,12 +1632,16 @@ int diagfwd_init(void)
driver->feature[i].stm_support = DISABLE_STM;
driver->feature[i].rcvd_feature_mask = 0;
driver->feature[i].peripheral_buffering = 0;
+ driver->feature[i].pd_buffering = 0;
driver->feature[i].encode_hdlc = 0;
driver->feature[i].untag_header =
DISABLE_PKT_HEADER_UNTAGGING;
driver->feature[i].mask_centralization = 0;
driver->feature[i].log_on_demand = 0;
driver->feature[i].sent_feature_mask = 0;
+ }
+
+ for (i = 0; i < NUM_MD_SESSIONS; i++) {
driver->buffering_mode[i].peripheral = i;
driver->buffering_mode[i].mode = DIAG_BUFFERING_MODE_STREAMING;
driver->buffering_mode[i].high_wm_val = DEFAULT_HIGH_WM_VAL;
diff --git a/drivers/char/diag/diagfwd_cntl.c b/drivers/char/diag/diagfwd_cntl.c
index 729fbf4fc145..4ae2158b5a6b 100644
--- a/drivers/char/diag/diagfwd_cntl.c
+++ b/drivers/char/diag/diagfwd_cntl.c
@@ -418,6 +418,8 @@ static void process_incoming_feature_mask(uint8_t *buf, uint32_t len,
driver->feature[peripheral].mask_centralization = 1;
if (FEATURE_SUPPORTED(F_DIAG_PERIPHERAL_BUFFERING))
driver->feature[peripheral].peripheral_buffering = 1;
+ if (FEATURE_SUPPORTED(F_DIAG_PD_BUFFERING))
+ driver->feature[peripheral].pd_buffering = 1;
if (FEATURE_SUPPORTED(F_DIAG_SOCKETS_ENABLED))
enable_socket_feature(peripheral);
}
@@ -792,32 +794,54 @@ static int diag_compute_real_time(int idx)
}
static void diag_create_diag_mode_ctrl_pkt(unsigned char *dest_buf,
- int real_time)
+ uint8_t diag_id, int real_time)
{
struct diag_ctrl_msg_diagmode diagmode;
+ struct diag_ctrl_msg_diagmode_v2 diagmode_v2;
int msg_size = sizeof(struct diag_ctrl_msg_diagmode);
+ int msg_size_2 = sizeof(struct diag_ctrl_msg_diagmode_v2);
if (!dest_buf)
return;
- diagmode.ctrl_pkt_id = DIAG_CTRL_MSG_DIAGMODE;
- diagmode.ctrl_pkt_data_len = DIAG_MODE_PKT_LEN;
- diagmode.version = 1;
- diagmode.sleep_vote = real_time ? 1 : 0;
- /*
- * 0 - Disables real-time logging (to prevent
- * frequent APPS wake-ups, etc.).
- * 1 - Enable real-time logging
- */
- diagmode.real_time = real_time;
- diagmode.use_nrt_values = 0;
- diagmode.commit_threshold = 0;
- diagmode.sleep_threshold = 0;
- diagmode.sleep_time = 0;
- diagmode.drain_timer_val = 0;
- diagmode.event_stale_timer_val = 0;
-
- memcpy(dest_buf, &diagmode, msg_size);
+ if (diag_id) {
+ diagmode_v2.ctrl_pkt_id = DIAG_CTRL_MSG_DIAGMODE;
+ diagmode_v2.ctrl_pkt_data_len = DIAG_MODE_PKT_LEN_V2;
+ diagmode_v2.version = 2;
+ diagmode_v2.sleep_vote = real_time ? 1 : 0;
+ /*
+ * 0 - Disables real-time logging (to prevent
+ * frequent APPS wake-ups, etc.).
+ * 1 - Enable real-time logging
+ */
+ diagmode_v2.real_time = real_time;
+ diagmode_v2.use_nrt_values = 0;
+ diagmode_v2.commit_threshold = 0;
+ diagmode_v2.sleep_threshold = 0;
+ diagmode_v2.sleep_time = 0;
+ diagmode_v2.drain_timer_val = 0;
+ diagmode_v2.event_stale_timer_val = 0;
+ diagmode_v2.diag_id = diag_id;
+ memcpy(dest_buf, &diagmode_v2, msg_size_2);
+ } else {
+ diagmode.ctrl_pkt_id = DIAG_CTRL_MSG_DIAGMODE;
+ diagmode.ctrl_pkt_data_len = DIAG_MODE_PKT_LEN;
+ diagmode.version = 1;
+ diagmode.sleep_vote = real_time ? 1 : 0;
+ /*
+ * 0 - Disables real-time logging (to prevent
+ * frequent APPS wake-ups, etc.).
+ * 1 - Enable real-time logging
+ */
+ diagmode.real_time = real_time;
+ diagmode.use_nrt_values = 0;
+ diagmode.commit_threshold = 0;
+ diagmode.sleep_threshold = 0;
+ diagmode.sleep_time = 0;
+ diagmode.drain_timer_val = 0;
+ diagmode.event_stale_timer_val = 0;
+ memcpy(dest_buf, &diagmode, msg_size);
+ }
}
void diag_update_proc_vote(uint16_t proc, uint8_t vote, int index)
@@ -902,7 +926,7 @@ static void diag_send_diag_mode_update_remote(int token, int real_time)
memcpy(buf + write_len, &dci_header, dci_header_size);
write_len += dci_header_size;
- diag_create_diag_mode_ctrl_pkt(buf + write_len, real_time);
+ diag_create_diag_mode_ctrl_pkt(buf + write_len, 0, real_time);
write_len += msg_size;
*(buf + write_len) = CONTROL_CHAR; /* End Terminator */
write_len += sizeof(uint8_t);
@@ -1008,14 +1032,18 @@ void diag_real_time_work_fn(struct work_struct *work)
}
#endif
-static int __diag_send_real_time_update(uint8_t peripheral, int real_time)
+static int __diag_send_real_time_update(uint8_t peripheral, int real_time,
+ uint8_t diag_id)
{
- char buf[sizeof(struct diag_ctrl_msg_diagmode)];
- int msg_size = sizeof(struct diag_ctrl_msg_diagmode);
+ char buf[sizeof(struct diag_ctrl_msg_diagmode_v2)];
+ int msg_size = 0;
int err = 0;
- if (peripheral >= NUM_PERIPHERALS)
+ if (peripheral >= NUM_PERIPHERALS) {
+ pr_err("diag: In %s, invalid peripheral %d\n", __func__,
+ peripheral);
return -EINVAL;
+ }
if (!driver->diagfwd_cntl[peripheral] ||
!driver->diagfwd_cntl[peripheral]->ch_open) {
@@ -1030,12 +1058,17 @@ static int __diag_send_real_time_update(uint8_t peripheral, int real_time)
return -EINVAL;
}
- diag_create_diag_mode_ctrl_pkt(buf, real_time);
+ msg_size = (diag_id ? sizeof(struct diag_ctrl_msg_diagmode_v2) :
+ sizeof(struct diag_ctrl_msg_diagmode));
+
+ diag_create_diag_mode_ctrl_pkt(buf, diag_id, real_time);
mutex_lock(&driver->diag_cntl_mutex);
+
err = diagfwd_write(peripheral, TYPE_CNTL, buf, msg_size);
+
if (err && err != -ENODEV) {
- pr_err("diag: In %s, unable to write to smd, peripheral: %d, type: %d, len: %d, err: %d\n",
+ pr_err("diag: In %s, unable to write, peripheral: %d, type: %d, len: %d, err: %d\n",
__func__, peripheral, TYPE_CNTL,
msg_size, err);
} else {
@@ -1061,27 +1094,79 @@ int diag_send_real_time_update(uint8_t peripheral, int real_time)
return -EINVAL;
}
- return __diag_send_real_time_update(peripheral, real_time);
+ return __diag_send_real_time_update(peripheral, real_time, 0);
+}
+
+void diag_map_pd_to_diagid(uint8_t pd, uint8_t *diag_id, int *peripheral)
+{
+ switch (pd) {
+ case UPD_WLAN:
+ *diag_id = DIAG_ID_WLAN;
+ *peripheral = PERIPHERAL_MODEM;
+ break;
+ case UPD_AUDIO:
+ *diag_id = DIAG_ID_AUDIO;
+ *peripheral = PERIPHERAL_LPASS;
+ break;
+ case UPD_SENSORS:
+ *diag_id = DIAG_ID_SENSORS;
+ *peripheral = PERIPHERAL_LPASS;
+ break;
+ case PERIPHERAL_MODEM:
+ *diag_id = DIAG_ID_MPSS;
+ *peripheral = PERIPHERAL_MODEM;
+ break;
+ case PERIPHERAL_LPASS:
+ *diag_id = DIAG_ID_LPASS;
+ *peripheral = PERIPHERAL_LPASS;
+ break;
+ case PERIPHERAL_CDSP:
+ *diag_id = DIAG_ID_CDSP;
+ *peripheral = PERIPHERAL_CDSP;
+ break;
+ default:
+ pr_err("diag: In %s, invalid peripheral %d\n", __func__,
+ pd);
+ *peripheral = -EINVAL;
+ break;
+ }
+
+ if (*peripheral > 0)
+ if (!driver->feature[*peripheral].pd_buffering)
+ *diag_id = 0;
}
int diag_send_peripheral_buffering_mode(struct diag_buffering_mode_t *params)
{
int err = 0;
int mode = MODE_REALTIME;
- uint8_t peripheral = 0;
+ int peripheral = 0;
+ uint8_t diag_id = 0;
if (!params)
return -EIO;
- peripheral = params->peripheral;
- if (peripheral >= NUM_PERIPHERALS) {
+ diag_map_pd_to_diagid(params->peripheral,
+ &diag_id, &peripheral);
+
+ if ((peripheral < 0) ||
+ peripheral >= NUM_PERIPHERALS) {
pr_err("diag: In %s, invalid peripheral %d\n", __func__,
peripheral);
return -EINVAL;
}
- if (!driver->buffering_flag[peripheral])
+ if (!driver->buffering_flag[params->peripheral]) {
+ pr_err("diag: In %s, buffering flag not set for %d\n", __func__,
+ params->peripheral);
return -EINVAL;
+ }
+
+ if (!driver->feature[peripheral].peripheral_buffering) {
+ pr_err("diag: In %s, peripheral %d doesn't support buffering\n",
+ __func__, peripheral);
+ return -EIO;
+ }
switch (params->mode) {
case DIAG_BUFFERING_MODE_STREAMING:
@@ -1100,7 +1185,7 @@ int diag_send_peripheral_buffering_mode(struct diag_buffering_mode_t *params)
if (!driver->feature[peripheral].peripheral_buffering) {
pr_debug("diag: In %s, peripheral %d doesn't support buffering\n",
__func__, peripheral);
- driver->buffering_flag[peripheral] = 0;
+ driver->buffering_flag[params->peripheral] = 0;
return -EIO;
}
@@ -1115,35 +1200,39 @@ int diag_send_peripheral_buffering_mode(struct diag_buffering_mode_t *params)
(params->low_wm_val != DIAG_MIN_WM_VAL))) {
pr_err("diag: In %s, invalid watermark values, high: %d, low: %d, peripheral: %d\n",
__func__, params->high_wm_val, params->low_wm_val,
- peripheral);
+ params->peripheral);
return -EINVAL;
}
mutex_lock(&driver->mode_lock);
- err = diag_send_buffering_tx_mode_pkt(peripheral, params);
+ err = diag_send_buffering_tx_mode_pkt(peripheral, diag_id, params);
if (err) {
pr_err("diag: In %s, unable to send buffering mode packet to peripheral %d, err: %d\n",
__func__, peripheral, err);
goto fail;
}
- err = diag_send_buffering_wm_values(peripheral, params);
+ err = diag_send_buffering_wm_values(peripheral, diag_id, params);
if (err) {
pr_err("diag: In %s, unable to send buffering wm value packet to peripheral %d, err: %d\n",
__func__, peripheral, err);
goto fail;
}
- err = __diag_send_real_time_update(peripheral, mode);
+ err = __diag_send_real_time_update(peripheral, mode, diag_id);
if (err) {
pr_err("diag: In %s, unable to send mode update to peripheral %d, mode: %d, err: %d\n",
__func__, peripheral, mode, err);
goto fail;
}
- driver->buffering_mode[peripheral].peripheral = peripheral;
- driver->buffering_mode[peripheral].mode = params->mode;
- driver->buffering_mode[peripheral].low_wm_val = params->low_wm_val;
- driver->buffering_mode[peripheral].high_wm_val = params->high_wm_val;
+ driver->buffering_mode[params->peripheral].peripheral =
+ params->peripheral;
+ driver->buffering_mode[params->peripheral].mode =
+ params->mode;
+ driver->buffering_mode[params->peripheral].low_wm_val =
+ params->low_wm_val;
+ driver->buffering_mode[params->peripheral].high_wm_val =
+ params->high_wm_val;
if (params->mode == DIAG_BUFFERING_MODE_STREAMING)
- driver->buffering_flag[peripheral] = 0;
+ driver->buffering_flag[params->peripheral] = 0;
fail:
mutex_unlock(&driver->mode_lock);
return err;
@@ -1182,10 +1271,12 @@ int diag_send_stm_state(uint8_t peripheral, uint8_t stm_control_data)
return err;
}
-int diag_send_peripheral_drain_immediate(uint8_t peripheral)
+int diag_send_peripheral_drain_immediate(uint8_t pd,
+ uint8_t diag_id, int peripheral)
{
int err = 0;
struct diag_ctrl_drain_immediate ctrl_pkt;
+ struct diag_ctrl_drain_immediate_v2 ctrl_pkt_v2;
if (!driver->feature[peripheral].peripheral_buffering) {
pr_debug("diag: In %s, peripheral %d doesn't support buffering\n",
@@ -1200,32 +1291,57 @@ int diag_send_peripheral_drain_immediate(uint8_t peripheral)
return -ENODEV;
}
- ctrl_pkt.pkt_id = DIAG_CTRL_MSG_PERIPHERAL_BUF_DRAIN_IMM;
- /* The length of the ctrl pkt is size of version and stream id */
- ctrl_pkt.len = sizeof(uint32_t) + sizeof(uint8_t);
- ctrl_pkt.version = 1;
- ctrl_pkt.stream_id = 1;
-
- err = diagfwd_write(peripheral, TYPE_CNTL, &ctrl_pkt, sizeof(ctrl_pkt));
- if (err && err != -ENODEV) {
- pr_err("diag: Unable to send drain immediate ctrl packet to peripheral %d, err: %d\n",
- peripheral, err);
+ if (diag_id && driver->feature[peripheral].pd_buffering) {
+ ctrl_pkt_v2.pkt_id = DIAG_CTRL_MSG_PERIPHERAL_BUF_DRAIN_IMM;
+ /*
+ * The length of the ctrl pkt is size of version,
+ * diag_id and stream id
+ */
+ ctrl_pkt_v2.len = sizeof(uint32_t) + (2 * sizeof(uint8_t));
+ ctrl_pkt_v2.version = 2;
+ ctrl_pkt_v2.diag_id = diag_id;
+ ctrl_pkt_v2.stream_id = 1;
+ err = diagfwd_write(peripheral, TYPE_CNTL, &ctrl_pkt_v2,
+ sizeof(ctrl_pkt_v2));
+ if (err && err != -ENODEV) {
+ pr_err("diag: Unable to send drain immediate ctrl packet to peripheral %d, err: %d\n",
+ peripheral, err);
+ }
+ } else {
+ ctrl_pkt.pkt_id = DIAG_CTRL_MSG_PERIPHERAL_BUF_DRAIN_IMM;
+ /*
+ * The length of the ctrl pkt is
+ * size of version and stream id
+ */
+ ctrl_pkt.len = sizeof(uint32_t) + sizeof(uint8_t);
+ ctrl_pkt.version = 1;
+ ctrl_pkt.stream_id = 1;
+ err = diagfwd_write(peripheral, TYPE_CNTL, &ctrl_pkt,
+ sizeof(ctrl_pkt));
+ if (err && err != -ENODEV) {
+ pr_err("diag: Unable to send drain immediate ctrl packet to peripheral %d, err: %d\n",
+ peripheral, err);
+ }
}
return err;
}
int diag_send_buffering_tx_mode_pkt(uint8_t peripheral,
- struct diag_buffering_mode_t *params)
+ uint8_t diag_id, struct diag_buffering_mode_t *params)
{
int err = 0;
struct diag_ctrl_peripheral_tx_mode ctrl_pkt;
+ struct diag_ctrl_peripheral_tx_mode_v2 ctrl_pkt_v2;
if (!params)
return -EIO;
- if (peripheral >= NUM_PERIPHERALS)
+ if (peripheral >= NUM_PERIPHERALS) {
+ pr_err("diag: In %s, invalid peripheral %d\n", __func__,
+ peripheral);
return -EINVAL;
+ }
if (!driver->feature[peripheral].peripheral_buffering) {
pr_debug("diag: In %s, peripheral %d doesn't support buffering\n",
@@ -1233,9 +1349,6 @@ int diag_send_buffering_tx_mode_pkt(uint8_t peripheral,
return -EINVAL;
}
- if (params->peripheral != peripheral)
- return -EINVAL;
-
switch (params->mode) {
case DIAG_BUFFERING_MODE_STREAMING:
case DIAG_BUFFERING_MODE_THRESHOLD:
@@ -1247,36 +1360,67 @@ int diag_send_buffering_tx_mode_pkt(uint8_t peripheral,
return -EINVAL;
}
- ctrl_pkt.pkt_id = DIAG_CTRL_MSG_CONFIG_PERIPHERAL_TX_MODE;
- /* Control packet length is size of version, stream_id and tx_mode */
- ctrl_pkt.len = sizeof(uint32_t) + (2 * sizeof(uint8_t));
- ctrl_pkt.version = 1;
- ctrl_pkt.stream_id = 1;
- ctrl_pkt.tx_mode = params->mode;
+ if (diag_id &&
+ driver->feature[peripheral].pd_buffering) {
- err = diagfwd_write(peripheral, TYPE_CNTL, &ctrl_pkt, sizeof(ctrl_pkt));
- if (err && err != -ENODEV) {
- pr_err("diag: Unable to send tx_mode ctrl packet to peripheral %d, err: %d\n",
- peripheral, err);
- goto fail;
+ ctrl_pkt_v2.pkt_id = DIAG_CTRL_MSG_CONFIG_PERIPHERAL_TX_MODE;
+ /*
+ * Control packet length is size of version, diag_id,
+ * stream_id and tx_mode
+ */
+ ctrl_pkt_v2.len = sizeof(uint32_t) + (3 * sizeof(uint8_t));
+ ctrl_pkt_v2.version = 2;
+ ctrl_pkt_v2.diag_id = diag_id;
+ ctrl_pkt_v2.stream_id = 1;
+ ctrl_pkt_v2.tx_mode = params->mode;
+
+ err = diagfwd_write(peripheral, TYPE_CNTL, &ctrl_pkt_v2,
+ sizeof(ctrl_pkt_v2));
+ if (err && err != -ENODEV) {
+ pr_err("diag: Unable to send tx_mode ctrl packet to peripheral %d, err: %d\n",
+ peripheral, err);
+ goto fail;
+ }
+ } else {
+ ctrl_pkt.pkt_id = DIAG_CTRL_MSG_CONFIG_PERIPHERAL_TX_MODE;
+ /*
+ * Control packet length is size of version,
+ * stream_id and tx_mode
+ */
+ ctrl_pkt.len = sizeof(uint32_t) + (2 * sizeof(uint8_t));
+ ctrl_pkt.version = 1;
+ ctrl_pkt.stream_id = 1;
+ ctrl_pkt.tx_mode = params->mode;
+
+ err = diagfwd_write(peripheral, TYPE_CNTL, &ctrl_pkt,
+ sizeof(ctrl_pkt));
+ if (err && err != -ENODEV) {
+ pr_err("diag: Unable to send tx_mode ctrl packet to peripheral %d, err: %d\n",
+ peripheral, err);
+ goto fail;
+ }
}
- driver->buffering_mode[peripheral].mode = params->mode;
+ driver->buffering_mode[params->peripheral].mode = params->mode;
fail:
return err;
}
int diag_send_buffering_wm_values(uint8_t peripheral,
- struct diag_buffering_mode_t *params)
+ uint8_t diag_id, struct diag_buffering_mode_t *params)
{
int err = 0;
struct diag_ctrl_set_wq_val ctrl_pkt;
+ struct diag_ctrl_set_wq_val_v2 ctrl_pkt_v2;
if (!params)
return -EIO;
- if (peripheral >= NUM_PERIPHERALS)
+ if (peripheral >= NUM_PERIPHERALS) {
+ pr_err("diag: In %s, invalid peripheral %d\n", __func__,
+ peripheral);
return -EINVAL;
+ }
if (!driver->feature[peripheral].peripheral_buffering) {
pr_debug("diag: In %s, peripheral %d doesn't support buffering\n",
@@ -1291,9 +1435,6 @@ int diag_send_buffering_wm_values(uint8_t peripheral,
return -ENODEV;
}
- if (params->peripheral != peripheral)
- return -EINVAL;
-
switch (params->mode) {
case DIAG_BUFFERING_MODE_STREAMING:
case DIAG_BUFFERING_MODE_THRESHOLD:
@@ -1305,21 +1446,45 @@ int diag_send_buffering_wm_values(uint8_t peripheral,
return -EINVAL;
}
- ctrl_pkt.pkt_id = DIAG_CTRL_MSG_CONFIG_PERIPHERAL_WMQ_VAL;
- /* Control packet length is size of version, stream_id and wmq values */
- ctrl_pkt.len = sizeof(uint32_t) + (3 * sizeof(uint8_t));
- ctrl_pkt.version = 1;
- ctrl_pkt.stream_id = 1;
- ctrl_pkt.high_wm_val = params->high_wm_val;
- ctrl_pkt.low_wm_val = params->low_wm_val;
-
- err = diagfwd_write(peripheral, TYPE_CNTL, &ctrl_pkt,
- sizeof(ctrl_pkt));
- if (err && err != -ENODEV) {
- pr_err("diag: Unable to send watermark values to peripheral %d, err: %d\n",
- peripheral, err);
+ if (diag_id &&
+ driver->feature[peripheral].pd_buffering) {
+ ctrl_pkt_v2.pkt_id = DIAG_CTRL_MSG_CONFIG_PERIPHERAL_WMQ_VAL;
+ /*
+ * Control packet length is size of version, diag_id,
+ * stream_id and wmq values
+ */
+ ctrl_pkt_v2.len = sizeof(uint32_t) + (4 * sizeof(uint8_t));
+ ctrl_pkt_v2.version = 2;
+ ctrl_pkt_v2.diag_id = diag_id;
+ ctrl_pkt_v2.stream_id = 1;
+ ctrl_pkt_v2.high_wm_val = params->high_wm_val;
+ ctrl_pkt_v2.low_wm_val = params->low_wm_val;
+
+ err = diagfwd_write(peripheral, TYPE_CNTL, &ctrl_pkt_v2,
+ sizeof(ctrl_pkt_v2));
+ if (err && err != -ENODEV) {
+ pr_err("diag: Unable to send watermark values to peripheral %d, err: %d\n",
+ peripheral, err);
+ }
+ } else {
+ ctrl_pkt.pkt_id = DIAG_CTRL_MSG_CONFIG_PERIPHERAL_WMQ_VAL;
+ /*
+ * Control packet length is size of version,
+ * stream_id and wmq values
+ */
+ ctrl_pkt.len = sizeof(uint32_t) + (3 * sizeof(uint8_t));
+ ctrl_pkt.version = 1;
+ ctrl_pkt.stream_id = 1;
+ ctrl_pkt.high_wm_val = params->high_wm_val;
+ ctrl_pkt.low_wm_val = params->low_wm_val;
+
+ err = diagfwd_write(peripheral, TYPE_CNTL, &ctrl_pkt,
+ sizeof(ctrl_pkt));
+ if (err && err != -ENODEV) {
+ pr_err("diag: Unable to send watermark values to peripheral %d, err: %d\n",
+ peripheral, err);
+ }
}
-
return err;
}
diff --git a/drivers/char/diag/diagfwd_cntl.h b/drivers/char/diag/diagfwd_cntl.h
index e8608f47ff14..86442d838471 100644
--- a/drivers/char/diag/diagfwd_cntl.h
+++ b/drivers/char/diag/diagfwd_cntl.h
@@ -68,6 +68,7 @@
#define F_DIAG_SOCKETS_ENABLED 13
#define F_DIAG_DCI_EXTENDED_HEADER_SUPPORT 14
#define F_DIAG_PKT_HEADER_UNTAG 16
+#define F_DIAG_PD_BUFFERING 17
#define ENABLE_SEPARATE_CMDRSP 1
#define DISABLE_SEPARATE_CMDRSP 0
@@ -85,7 +86,8 @@
#define ENABLE_PKT_HEADER_UNTAGGING 1
#define DISABLE_PKT_HEADER_UNTAGGING 0
-#define DIAG_MODE_PKT_LEN 36
+#define DIAG_MODE_PKT_LEN 36
+#define DIAG_MODE_PKT_LEN_V2 37
struct diag_ctrl_pkt_header_t {
uint32_t pkt_id;
@@ -171,6 +173,21 @@ struct diag_ctrl_msg_diagmode {
uint32_t event_stale_timer_val;
} __packed;
+struct diag_ctrl_msg_diagmode_v2 {
+ uint32_t ctrl_pkt_id;
+ uint32_t ctrl_pkt_data_len;
+ uint32_t version;
+ uint32_t sleep_vote;
+ uint32_t real_time;
+ uint32_t use_nrt_values;
+ uint32_t commit_threshold;
+ uint32_t sleep_threshold;
+ uint32_t sleep_time;
+ uint32_t drain_timer_val;
+ uint32_t event_stale_timer_val;
+ uint8_t diag_id;
+} __packed;
+
struct diag_ctrl_msg_stm {
uint32_t ctrl_pkt_id;
uint32_t ctrl_pkt_data_len;
@@ -249,6 +266,15 @@ struct diag_ctrl_peripheral_tx_mode {
uint8_t tx_mode;
} __packed;
+struct diag_ctrl_peripheral_tx_mode_v2 {
+ uint32_t pkt_id;
+ uint32_t len;
+ uint32_t version;
+ uint8_t diag_id;
+ uint8_t stream_id;
+ uint8_t tx_mode;
+} __packed;
+
struct diag_ctrl_drain_immediate {
uint32_t pkt_id;
uint32_t len;
@@ -256,6 +282,14 @@ struct diag_ctrl_drain_immediate {
uint8_t stream_id;
} __packed;
+struct diag_ctrl_drain_immediate_v2 {
+ uint32_t pkt_id;
+ uint32_t len;
+ uint32_t version;
+ uint8_t diag_id;
+ uint8_t stream_id;
+} __packed;
+
struct diag_ctrl_set_wq_val {
uint32_t pkt_id;
uint32_t len;
@@ -265,6 +299,16 @@ struct diag_ctrl_set_wq_val {
uint8_t low_wm_val;
} __packed;
+struct diag_ctrl_set_wq_val_v2 {
+ uint32_t pkt_id;
+ uint32_t len;
+ uint32_t version;
+ uint8_t diag_id;
+ uint8_t stream_id;
+ uint8_t high_wm_val;
+ uint8_t low_wm_val;
+} __packed;
+
int diagfwd_cntl_init(void);
void diagfwd_cntl_channel_init(void);
void diagfwd_cntl_exit(void);
@@ -273,14 +317,16 @@ void diag_cntl_channel_close(struct diagfwd_info *p_info);
void diag_cntl_process_read_data(struct diagfwd_info *p_info, void *buf,
int len);
int diag_send_real_time_update(uint8_t peripheral, int real_time);
+void diag_map_pd_to_diagid(uint8_t pd, uint8_t *diag_id, int *peripheral);
int diag_send_peripheral_buffering_mode(struct diag_buffering_mode_t *params);
void diag_update_proc_vote(uint16_t proc, uint8_t vote, int index);
void diag_update_real_time_vote(uint16_t proc, uint8_t real_time, int index);
void diag_real_time_work_fn(struct work_struct *work);
int diag_send_stm_state(uint8_t peripheral, uint8_t stm_control_data);
-int diag_send_peripheral_drain_immediate(uint8_t peripheral);
+int diag_send_peripheral_drain_immediate(uint8_t pd,
+ uint8_t diag_id, int peripheral);
int diag_send_buffering_tx_mode_pkt(uint8_t peripheral,
- struct diag_buffering_mode_t *params);
+ uint8_t diag_id, struct diag_buffering_mode_t *params);
int diag_send_buffering_wm_values(uint8_t peripheral,
- struct diag_buffering_mode_t *params);
+ uint8_t diag_id, struct diag_buffering_mode_t *params);
#endif
diff --git a/drivers/char/diag/diagfwd_mhi.c b/drivers/char/diag/diagfwd_mhi.c
index 8b0e1f32bdc5..03133a5a89aa 100644
--- a/drivers/char/diag/diagfwd_mhi.c
+++ b/drivers/char/diag/diagfwd_mhi.c
@@ -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
@@ -553,6 +553,8 @@ static void mhi_notifier(struct mhi_cb_info *cb_info)
struct mhi_result *result = NULL;
struct diag_mhi_ch_t *ch = NULL;
void *buf = NULL;
+ struct diag_mhi_info *mhi_info = NULL;
+ unsigned long flags;
if (!cb_info)
return;
@@ -604,13 +606,6 @@ static void mhi_notifier(struct mhi_cb_info *cb_info)
queue_work(diag_mhi[index].mhi_wq,
&(diag_mhi[index].open_work));
break;
- case MHI_CB_MHI_DISABLED:
- DIAG_LOG(DIAG_DEBUG_BRIDGE,
- "received mhi disabled notifiation port: %d ch: %d\n",
- index, ch->type);
- atomic_set(&(ch->opened), 0);
- __mhi_close(&diag_mhi[index], CHANNELS_CLOSED);
- break;
case MHI_CB_XFER:
/*
* If the channel is a read channel, this is a read
@@ -637,6 +632,24 @@ static void mhi_notifier(struct mhi_cb_info *cb_info)
result->bytes_xferd,
diag_mhi[index].id);
break;
+ case MHI_CB_MHI_DISABLED:
+ case MHI_CB_SYS_ERROR:
+ case MHI_CB_MHI_SHUTDOWN:
+ DIAG_LOG(DIAG_DEBUG_BRIDGE,
+ "received mhi link down cb: %d port: %d ch: %d\n",
+ cb_info->cb_reason, index, ch->type);
+ mhi_info = &diag_mhi[index];
+ if (!mhi_info->enabled)
+ return;
+ spin_lock_irqsave(&mhi_info->lock, flags);
+ mhi_info->enabled = 0;
+ spin_unlock_irqrestore(&mhi_info->lock, flags);
+ atomic_set(&(mhi_info->read_ch.opened), 0);
+ atomic_set(&(mhi_info->write_ch.opened), 0);
+ flush_workqueue(mhi_info->mhi_wq);
+ mhi_buf_tbl_clear(mhi_info);
+ diag_remote_dev_close(mhi_info->dev_id);
+ break;
default:
pr_err("diag: In %s, invalid cb reason 0x%x\n", __func__,
cb_info->cb_reason);
diff --git a/drivers/clk/msm/clock-local2.c b/drivers/clk/msm/clock-local2.c
index adb07cdb7e8d..076ead6aaf34 100644
--- a/drivers/clk/msm/clock-local2.c
+++ b/drivers/clk/msm/clock-local2.c
@@ -1339,34 +1339,6 @@ static struct frac_entry frac_table_810m[] = { /* Link rate of 162M */
{0, 0},
};
-static bool is_same_rcg_config(struct rcg_clk *rcg, struct clk_freq_tbl *freq,
- bool has_mnd)
-{
- u32 cfg;
-
- /* RCG update pending */
- if (readl_relaxed(CMD_RCGR_REG(rcg)) & CMD_RCGR_CONFIG_DIRTY_MASK)
- return false;
- if (has_mnd)
- if (readl_relaxed(M_REG(rcg)) != freq->m_val ||
- readl_relaxed(N_REG(rcg)) != freq->n_val ||
- readl_relaxed(D_REG(rcg)) != freq->d_val)
- return false;
- /*
- * Both 0 and 1 represent same divider value in HW.
- * Always use 0 to simplify comparison.
- */
- if ((freq->div_src_val & CFG_RCGR_DIV_MASK) == 1)
- freq->div_src_val &= ~CFG_RCGR_DIV_MASK;
- cfg = readl_relaxed(CFG_RCGR_REG(rcg));
- if ((cfg & CFG_RCGR_DIV_MASK) == 1)
- cfg &= ~CFG_RCGR_DIV_MASK;
- if (cfg != freq->div_src_val)
- return false;
-
- return true;
-}
-
static int set_rate_edp_pixel(struct clk *clk, unsigned long rate)
{
struct rcg_clk *rcg = to_rcg_clk(clk);
@@ -1404,8 +1376,7 @@ static int set_rate_edp_pixel(struct clk *clk, unsigned long rate)
pixel_freq->d_val = ~frac->den;
}
spin_lock_irqsave(&local_clock_reg_lock, flags);
- if (!is_same_rcg_config(rcg, pixel_freq, true))
- __set_rate_mnd(rcg, pixel_freq);
+ __set_rate_mnd(rcg, pixel_freq);
spin_unlock_irqrestore(&local_clock_reg_lock, flags);
return 0;
}
@@ -1466,8 +1437,7 @@ static int set_rate_byte(struct clk *clk, unsigned long rate)
byte_freq->div_src_val |= BVAL(4, 0, div);
spin_lock_irqsave(&local_clock_reg_lock, flags);
- if (!is_same_rcg_config(rcg, byte_freq, false))
- __set_rate_hid(rcg, byte_freq);
+ __set_rate_hid(rcg, byte_freq);
spin_unlock_irqrestore(&local_clock_reg_lock, flags);
return 0;
@@ -1788,8 +1758,7 @@ static int rcg_clk_set_rate_dp(struct clk *clk, unsigned long rate)
}
spin_lock_irqsave(&local_clock_reg_lock, flags);
- if (!is_same_rcg_config(rcg, freq_tbl, true))
- __set_rate_mnd(rcg, freq_tbl);
+ __set_rate_mnd(rcg, freq_tbl);
spin_unlock_irqrestore(&local_clock_reg_lock, flags);
return 0;
}
diff --git a/drivers/clk/msm/clock-osm.c b/drivers/clk/msm/clock-osm.c
index 9d9aa61c480a..7cc1c56a2090 100644
--- a/drivers/clk/msm/clock-osm.c
+++ b/drivers/clk/msm/clock-osm.c
@@ -1541,8 +1541,8 @@ static int clk_osm_setup_hw_table(struct clk_osm *c)
{
struct osm_entry *entry = c->osm_table;
int i;
- u32 freq_val, volt_val, override_val, spare_val;
- u32 table_entry_offset, last_spare, last_virtual_corner = 0;
+ u32 freq_val = 0, volt_val = 0, override_val = 0, spare_val = 0;
+ u32 table_entry_offset = 0, last_spare = 0, last_virtual_corner = 0;
for (i = 0; i < OSM_TABLE_SIZE; i++) {
if (i < c->num_entries) {
@@ -2758,7 +2758,7 @@ static ssize_t debugfs_trace_method_get(struct file *file, char __user *buf,
size_t count, loff_t *ppos)
{
struct clk_osm *c = file->private_data;
- int len, rc;
+ int len = 0, rc;
if (IS_ERR(file) || file == NULL) {
pr_err("input error %ld\n", PTR_ERR(file));
diff --git a/drivers/clk/msm/mdss/mdss-hdmi-pll-8998.c b/drivers/clk/msm/mdss/mdss-hdmi-pll-8998.c
index c60c4864442f..c4215f30acce 100644
--- a/drivers/clk/msm/mdss/mdss-hdmi-pll-8998.c
+++ b/drivers/clk/msm/mdss/mdss-hdmi-pll-8998.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
@@ -29,6 +29,10 @@
#define _W(x, y, z) MDSS_PLL_REG_W(x, y, z)
#define _R(x, y) MDSS_PLL_REG_R(x, y)
+/* CONSTANTS */
+#define HDMI_VERSION_8998_3_3 1
+#define HDMI_VERSION_8998_1_8 2
+
/* PLL REGISTERS */
#define FREQ_UPDATE (0x008)
#define BIAS_EN_CLKBUFLR_EN (0x034)
@@ -277,7 +281,7 @@ find_optimal_index:
}
static int hdmi_8998_config_phy(unsigned long rate,
- struct hdmi_8998_reg_cfg *cfg)
+ struct hdmi_8998_reg_cfg *cfg, u32 ver)
{
u64 const high_freq_bit_clk_threshold = 3400000000UL;
u64 const dig_freq_bit_clk_threshold = 1500000000UL;
@@ -359,6 +363,7 @@ static int hdmi_8998_config_phy(unsigned long rate,
pr_debug("INTEGLOOP_GAIN = %llu\n", integloop_gain);
pr_debug("CMP_RNG = %llu\n", cmp_rng);
pr_debug("PLL_CMP = %llu\n", pll_cmp);
+ pr_debug("VER=%d\n", ver);
cfg->svs_mode_clk_sel = (digclk_divsel & 0xFF);
cfg->hsclk_sel = (0x20 | hsclk_sel);
@@ -382,82 +387,105 @@ static int hdmi_8998_config_phy(unsigned long rate,
cfg->core_clk_en = 0x2C;
cfg->coreclk_div_mode0 = 0x5;
cfg->phy_mode = (tmds_bclk_ratio ? 0x5 : 0x4);
+ /* V1P8_SEL */
+ if (ver == HDMI_VERSION_8998_1_8)
+ cfg->phy_mode |= 1 << 4;
cfg->ssc_en_center = 0x0;
- if (bclk > high_freq_bit_clk_threshold) {
- cfg->l0_tx_drv_lvl = 0xA;
- cfg->l0_tx_emp_post1_lvl = 0x3;
- cfg->l1_tx_drv_lvl = 0xA;
- cfg->l1_tx_emp_post1_lvl = 0x3;
- cfg->l2_tx_drv_lvl = 0xA;
- cfg->l2_tx_emp_post1_lvl = 0x3;
- cfg->l3_tx_drv_lvl = 0x8;
- cfg->l3_tx_emp_post1_lvl = 0x3;
- cfg->l0_pre_driver_1 = 0x0;
- cfg->l0_pre_driver_2 = 0x1C;
- cfg->l1_pre_driver_1 = 0x0;
- cfg->l1_pre_driver_2 = 0x1C;
- cfg->l2_pre_driver_1 = 0x0;
- cfg->l2_pre_driver_2 = 0x1C;
- cfg->l3_pre_driver_1 = 0x0;
- cfg->l3_pre_driver_2 = 0x0;
- } else if (bclk > dig_freq_bit_clk_threshold) {
- cfg->l0_tx_drv_lvl = 0x9;
- cfg->l0_tx_emp_post1_lvl = 0x3;
- cfg->l1_tx_drv_lvl = 0x9;
- cfg->l1_tx_emp_post1_lvl = 0x3;
- cfg->l2_tx_drv_lvl = 0x9;
- cfg->l2_tx_emp_post1_lvl = 0x3;
- cfg->l3_tx_drv_lvl = 0x8;
- cfg->l3_tx_emp_post1_lvl = 0x3;
- cfg->l0_pre_driver_1 = 0x0;
- cfg->l0_pre_driver_2 = 0x16;
- cfg->l1_pre_driver_1 = 0x0;
- cfg->l1_pre_driver_2 = 0x16;
- cfg->l2_pre_driver_1 = 0x0;
- cfg->l2_pre_driver_2 = 0x16;
- cfg->l3_pre_driver_1 = 0x0;
- cfg->l3_pre_driver_2 = 0x0;
- } else if (bclk > mid_freq_bit_clk_threshold) {
- cfg->l0_tx_drv_lvl = 0x9;
- cfg->l0_tx_emp_post1_lvl = 0x3;
- cfg->l1_tx_drv_lvl = 0x9;
- cfg->l1_tx_emp_post1_lvl = 0x3;
- cfg->l2_tx_drv_lvl = 0x9;
- cfg->l2_tx_emp_post1_lvl = 0x3;
- cfg->l3_tx_drv_lvl = 0x8;
- cfg->l3_tx_emp_post1_lvl = 0x3;
- cfg->l0_pre_driver_1 = 0x0;
- cfg->l0_pre_driver_2 = 0x0E;
- cfg->l1_pre_driver_1 = 0x0;
- cfg->l1_pre_driver_2 = 0x0E;
- cfg->l2_pre_driver_1 = 0x0;
- cfg->l2_pre_driver_2 = 0x0E;
- cfg->l3_pre_driver_1 = 0x0;
- cfg->l3_pre_driver_2 = 0x0;
+ if (ver == HDMI_VERSION_8998_3_3) {
+ if (bclk > high_freq_bit_clk_threshold) {
+ cfg->l0_tx_drv_lvl = 0xA;
+ cfg->l0_tx_emp_post1_lvl = 0x3;
+ cfg->l1_tx_drv_lvl = 0xA;
+ cfg->l1_tx_emp_post1_lvl = 0x3;
+ cfg->l2_tx_drv_lvl = 0xA;
+ cfg->l2_tx_emp_post1_lvl = 0x3;
+ cfg->l3_tx_drv_lvl = 0x8;
+ cfg->l3_tx_emp_post1_lvl = 0x3;
+ cfg->l0_pre_driver_1 = 0x0;
+ cfg->l0_pre_driver_2 = 0x1C;
+ cfg->l1_pre_driver_1 = 0x0;
+ cfg->l1_pre_driver_2 = 0x1C;
+ cfg->l2_pre_driver_1 = 0x0;
+ cfg->l2_pre_driver_2 = 0x1C;
+ cfg->l3_pre_driver_1 = 0x0;
+ cfg->l3_pre_driver_2 = 0x0;
+ } else if (bclk > dig_freq_bit_clk_threshold) {
+ cfg->l0_tx_drv_lvl = 0x9;
+ cfg->l0_tx_emp_post1_lvl = 0x3;
+ cfg->l1_tx_drv_lvl = 0x9;
+ cfg->l1_tx_emp_post1_lvl = 0x3;
+ cfg->l2_tx_drv_lvl = 0x9;
+ cfg->l2_tx_emp_post1_lvl = 0x3;
+ cfg->l3_tx_drv_lvl = 0x8;
+ cfg->l3_tx_emp_post1_lvl = 0x3;
+ cfg->l0_pre_driver_1 = 0x0;
+ cfg->l0_pre_driver_2 = 0x16;
+ cfg->l1_pre_driver_1 = 0x0;
+ cfg->l1_pre_driver_2 = 0x16;
+ cfg->l2_pre_driver_1 = 0x0;
+ cfg->l2_pre_driver_2 = 0x16;
+ cfg->l3_pre_driver_1 = 0x0;
+ cfg->l3_pre_driver_2 = 0x0;
+ } else if (bclk > mid_freq_bit_clk_threshold) {
+ cfg->l0_tx_drv_lvl = 0x9;
+ cfg->l0_tx_emp_post1_lvl = 0x3;
+ cfg->l1_tx_drv_lvl = 0x9;
+ cfg->l1_tx_emp_post1_lvl = 0x3;
+ cfg->l2_tx_drv_lvl = 0x9;
+ cfg->l2_tx_emp_post1_lvl = 0x3;
+ cfg->l3_tx_drv_lvl = 0x8;
+ cfg->l3_tx_emp_post1_lvl = 0x3;
+ cfg->l0_pre_driver_1 = 0x0;
+ cfg->l0_pre_driver_2 = 0x0E;
+ cfg->l1_pre_driver_1 = 0x0;
+ cfg->l1_pre_driver_2 = 0x0E;
+ cfg->l2_pre_driver_1 = 0x0;
+ cfg->l2_pre_driver_2 = 0x0E;
+ cfg->l3_pre_driver_1 = 0x0;
+ cfg->l3_pre_driver_2 = 0x0;
+ } else {
+ cfg->l0_tx_drv_lvl = 0x0;
+ cfg->l0_tx_emp_post1_lvl = 0x0;
+ cfg->l1_tx_drv_lvl = 0x0;
+ cfg->l1_tx_emp_post1_lvl = 0x0;
+ cfg->l2_tx_drv_lvl = 0x0;
+ cfg->l2_tx_emp_post1_lvl = 0x0;
+ cfg->l3_tx_drv_lvl = 0x0;
+ cfg->l3_tx_emp_post1_lvl = 0x0;
+ cfg->l0_pre_driver_1 = 0x0;
+ cfg->l0_pre_driver_2 = 0x01;
+ cfg->l1_pre_driver_1 = 0x0;
+ cfg->l1_pre_driver_2 = 0x01;
+ cfg->l2_pre_driver_1 = 0x0;
+ cfg->l2_pre_driver_2 = 0x01;
+ cfg->l3_pre_driver_1 = 0x0;
+ cfg->l3_pre_driver_2 = 0x0;
+ }
} else {
- cfg->l0_tx_drv_lvl = 0x0;
- cfg->l0_tx_emp_post1_lvl = 0x0;
- cfg->l1_tx_drv_lvl = 0x0;
- cfg->l1_tx_emp_post1_lvl = 0x0;
- cfg->l2_tx_drv_lvl = 0x0;
- cfg->l2_tx_emp_post1_lvl = 0x0;
- cfg->l3_tx_drv_lvl = 0x0;
+ cfg->l0_tx_drv_lvl = 0xF;
+ cfg->l0_tx_emp_post1_lvl = 0x5;
+ cfg->l1_tx_drv_lvl = 0xF;
+ cfg->l1_tx_emp_post1_lvl = 0x2;
+ cfg->l2_tx_drv_lvl = 0xF;
+ cfg->l2_tx_emp_post1_lvl = 0x2;
+ cfg->l3_tx_drv_lvl = 0xF;
cfg->l3_tx_emp_post1_lvl = 0x0;
cfg->l0_pre_driver_1 = 0x0;
- cfg->l0_pre_driver_2 = 0x01;
+ cfg->l0_pre_driver_2 = 0x1E;
cfg->l1_pre_driver_1 = 0x0;
- cfg->l1_pre_driver_2 = 0x01;
+ cfg->l1_pre_driver_2 = 0x1E;
cfg->l2_pre_driver_1 = 0x0;
- cfg->l2_pre_driver_2 = 0x01;
+ cfg->l2_pre_driver_2 = 0x1E;
cfg->l3_pre_driver_1 = 0x0;
- cfg->l3_pre_driver_2 = 0x0;
+ cfg->l3_pre_driver_2 = 0x10;
}
return rc;
}
-static int hdmi_8998_pll_set_clk_rate(struct clk *c, unsigned long rate)
+static int hdmi_8998_pll_set_clk_rate(struct clk *c, unsigned long rate,
+ u32 ver)
{
int rc = 0;
struct hdmi_pll_vco_clk *vco = to_hdmi_vco_clk(c);
@@ -465,7 +493,7 @@ static int hdmi_8998_pll_set_clk_rate(struct clk *c, unsigned long rate)
struct hdmi_8998_reg_cfg cfg = {0};
void __iomem *phy = io->phy_base, *pll = io->pll_base;
- rc = hdmi_8998_config_phy(rate, &cfg);
+ rc = hdmi_8998_config_phy(rate, &cfg, ver);
if (rc) {
pr_err("rate calculation failed\n, rc=%d", rc);
return rc;
@@ -699,7 +727,7 @@ static int hdmi_8998_vco_get_lock_range(struct clk *c,
}
static int hdmi_8998_vco_rate_atomic_update(struct clk *c,
- unsigned long rate)
+ unsigned long rate, u32 ver)
{
struct hdmi_pll_vco_clk *vco = to_hdmi_vco_clk(c);
struct mdss_pll_resources *io = vco->priv;
@@ -707,7 +735,7 @@ static int hdmi_8998_vco_rate_atomic_update(struct clk *c,
struct hdmi_8998_reg_cfg cfg = {0};
int rc = 0;
- rc = hdmi_8998_config_phy(rate, &cfg);
+ rc = hdmi_8998_config_phy(rate, &cfg, ver);
if (rc) {
pr_err("rate calculation failed\n, rc=%d", rc);
goto end;
@@ -728,7 +756,7 @@ end:
return rc;
}
-static int hdmi_8998_vco_set_rate(struct clk *c, unsigned long rate)
+static int hdmi_8998_vco_set_rate(struct clk *c, unsigned long rate, u32 ver)
{
struct hdmi_pll_vco_clk *vco = to_hdmi_vco_clk(c);
struct mdss_pll_resources *io = vco->priv;
@@ -767,9 +795,9 @@ static int hdmi_8998_vco_set_rate(struct clk *c, unsigned long rate)
set_power_dwn = 1;
if (atomic_update)
- rc = hdmi_8998_vco_rate_atomic_update(c, rate);
+ rc = hdmi_8998_vco_rate_atomic_update(c, rate, ver);
else
- rc = hdmi_8998_pll_set_clk_rate(c, rate);
+ rc = hdmi_8998_pll_set_clk_rate(c, rate, ver);
if (rc) {
pr_err("failed to set clk rate\n");
@@ -806,7 +834,7 @@ static long hdmi_8998_vco_round_rate(struct clk *c, unsigned long rate)
return rrate;
}
-static int hdmi_8998_vco_prepare(struct clk *c)
+static int hdmi_8998_vco_prepare(struct clk *c, u32 ver)
{
struct hdmi_pll_vco_clk *vco = to_hdmi_vco_clk(c);
struct mdss_pll_resources *io = vco->priv;
@@ -824,7 +852,7 @@ static int hdmi_8998_vco_prepare(struct clk *c)
}
if (!vco->rate_set && vco->rate) {
- rc = hdmi_8998_pll_set_clk_rate(c, vco->rate);
+ rc = hdmi_8998_pll_set_clk_rate(c, vco->rate, ver);
if (rc) {
pr_err("set rate failed, rc=%d\n", rc);
goto error;
@@ -902,10 +930,38 @@ static enum handoff hdmi_8998_vco_handoff(struct clk *c)
return ret;
}
-static struct clk_ops hdmi_8998_vco_clk_ops = {
- .set_rate = hdmi_8998_vco_set_rate,
+static int hdmi_8998_3p3_vco_set_rate(struct clk *c, unsigned long rate)
+{
+ return hdmi_8998_vco_set_rate(c, rate, HDMI_VERSION_8998_3_3);
+}
+
+static int hdmi_8998_1p8_vco_set_rate(struct clk *c, unsigned long rate)
+{
+ return hdmi_8998_vco_set_rate(c, rate, HDMI_VERSION_8998_1_8);
+}
+
+static int hdmi_8998_3p3_vco_prepare(struct clk *c)
+{
+ return hdmi_8998_vco_prepare(c, HDMI_VERSION_8998_3_3);
+}
+
+static int hdmi_8998_1p8_vco_prepare(struct clk *c)
+{
+ return hdmi_8998_vco_prepare(c, HDMI_VERSION_8998_1_8);
+}
+
+static struct clk_ops hdmi_8998_3p3_vco_clk_ops = {
+ .set_rate = hdmi_8998_3p3_vco_set_rate,
+ .round_rate = hdmi_8998_vco_round_rate,
+ .prepare = hdmi_8998_3p3_vco_prepare,
+ .unprepare = hdmi_8998_vco_unprepare,
+ .handoff = hdmi_8998_vco_handoff,
+};
+
+static struct clk_ops hdmi_8998_1p8_vco_clk_ops = {
+ .set_rate = hdmi_8998_1p8_vco_set_rate,
.round_rate = hdmi_8998_vco_round_rate,
- .prepare = hdmi_8998_vco_prepare,
+ .prepare = hdmi_8998_1p8_vco_prepare,
.unprepare = hdmi_8998_vco_unprepare,
.handoff = hdmi_8998_vco_handoff,
};
@@ -915,7 +971,7 @@ static struct hdmi_pll_vco_clk hdmi_vco_clk = {
.max_rate = HDMI_VCO_MAX_RATE_HZ,
.c = {
.dbg_name = "hdmi_8998_vco_clk",
- .ops = &hdmi_8998_vco_clk_ops,
+ .ops = &hdmi_8998_3p3_vco_clk_ops,
CLK_INIT(hdmi_vco_clk.c),
},
};
@@ -925,7 +981,7 @@ static struct clk_lookup hdmipllcc_8998[] = {
};
int hdmi_8998_pll_clock_register(struct platform_device *pdev,
- struct mdss_pll_resources *pll_res)
+ struct mdss_pll_resources *pll_res, u32 ver)
{
int rc = 0;
@@ -936,8 +992,20 @@ int hdmi_8998_pll_clock_register(struct platform_device *pdev,
hdmi_vco_clk.priv = pll_res;
+ switch (ver) {
+ case HDMI_VERSION_8998_3_3:
+ hdmi_vco_clk.c.ops = &hdmi_8998_3p3_vco_clk_ops;
+ break;
+ case HDMI_VERSION_8998_1_8:
+ hdmi_vco_clk.c.ops = &hdmi_8998_1p8_vco_clk_ops;
+ break;
+ default:
+ hdmi_vco_clk.c.ops = &hdmi_8998_3p3_vco_clk_ops;
+ break;
+ };
+
rc = of_msm_clock_register(pdev->dev.of_node, hdmipllcc_8998,
- ARRAY_SIZE(hdmipllcc_8998));
+ ARRAY_SIZE(hdmipllcc_8998));
if (rc) {
pr_err("clock register failed, rc=%d\n", rc);
return rc;
@@ -945,3 +1013,17 @@ int hdmi_8998_pll_clock_register(struct platform_device *pdev,
return rc;
}
+
+int hdmi_8998_3p3_pll_clock_register(struct platform_device *pdev,
+ struct mdss_pll_resources *pll_res)
+{
+ return hdmi_8998_pll_clock_register(pdev, pll_res,
+ HDMI_VERSION_8998_3_3);
+}
+
+int hdmi_8998_1p8_pll_clock_register(struct platform_device *pdev,
+ struct mdss_pll_resources *pll_res)
+{
+ return hdmi_8998_pll_clock_register(pdev, pll_res,
+ HDMI_VERSION_8998_1_8);
+}
diff --git a/drivers/clk/msm/mdss/mdss-hdmi-pll.h b/drivers/clk/msm/mdss/mdss-hdmi-pll.h
index 19f9b925644a..9e6a39481286 100644
--- a/drivers/clk/msm/mdss/mdss-hdmi-pll.h
+++ b/drivers/clk/msm/mdss/mdss-hdmi-pll.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012-2016, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-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
@@ -45,17 +45,19 @@ int hdmi_20nm_pll_clock_register(struct platform_device *pdev,
struct mdss_pll_resources *pll_res);
int hdmi_8996_v1_pll_clock_register(struct platform_device *pdev,
- struct mdss_pll_resources *pll_res);
+ struct mdss_pll_resources *pll_res);
int hdmi_8996_v2_pll_clock_register(struct platform_device *pdev,
- struct mdss_pll_resources *pll_res);
+ struct mdss_pll_resources *pll_res);
int hdmi_8996_v3_pll_clock_register(struct platform_device *pdev,
- struct mdss_pll_resources *pll_res);
+ struct mdss_pll_resources *pll_res);
int hdmi_8996_v3_1p8_pll_clock_register(struct platform_device *pdev,
- struct mdss_pll_resources *pll_res);
+ struct mdss_pll_resources *pll_res);
-int hdmi_8998_pll_clock_register(struct platform_device *pdev,
- struct mdss_pll_resources *pll_res);
+int hdmi_8998_3p3_pll_clock_register(struct platform_device *pdev,
+ struct mdss_pll_resources *pll_res);
+int hdmi_8998_1p8_pll_clock_register(struct platform_device *pdev,
+ struct mdss_pll_resources *pll_res);
#endif
diff --git a/drivers/clk/msm/mdss/mdss-pll.c b/drivers/clk/msm/mdss/mdss-pll.c
index 01ce2b1817f2..b5c98774ba92 100644
--- a/drivers/clk/msm/mdss/mdss-pll.c
+++ b/drivers/clk/msm/mdss/mdss-pll.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2013-2016, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2013-2017, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -149,7 +149,9 @@ static int mdss_pll_resource_parse(struct platform_device *pdev,
"qcom,mdss_hdmi_pll_8996_v3_1p8")) {
pll_res->pll_interface_type = MDSS_HDMI_PLL_8996_V3_1_8;
} else if (!strcmp(compatible_stream, "qcom,mdss_hdmi_pll_8998")) {
- pll_res->pll_interface_type = MDSS_HDMI_PLL_8998;
+ pll_res->pll_interface_type = MDSS_HDMI_PLL_8998_3_3;
+ } else if (!strcmp(compatible_stream, "qcom,mdss_hdmi_pll_8998_1p8")) {
+ pll_res->pll_interface_type = MDSS_HDMI_PLL_8998_1_8;
} else {
goto err;
}
@@ -193,8 +195,11 @@ static int mdss_pll_clock_register(struct platform_device *pdev,
case MDSS_HDMI_PLL_8996_V3_1_8:
rc = hdmi_8996_v3_1p8_pll_clock_register(pdev, pll_res);
break;
- case MDSS_HDMI_PLL_8998:
- rc = hdmi_8998_pll_clock_register(pdev, pll_res);
+ case MDSS_HDMI_PLL_8998_3_3:
+ rc = hdmi_8998_3p3_pll_clock_register(pdev, pll_res);
+ break;
+ case MDSS_HDMI_PLL_8998_1_8:
+ rc = hdmi_8998_1p8_pll_clock_register(pdev, pll_res);
break;
case MDSS_UNKNOWN_PLL:
default:
@@ -401,6 +406,7 @@ static const struct of_device_id mdss_pll_dt_match[] = {
{.compatible = "qcom,mdss_hdmi_pll_8996_v3_1p8"},
{.compatible = "qcom,mdss_dp_pll_8998"},
{.compatible = "qcom,mdss_hdmi_pll_8998"},
+ {.compatible = "qcom,mdss_hdmi_pll_8998_1p8"},
{}
};
diff --git a/drivers/clk/msm/mdss/mdss-pll.h b/drivers/clk/msm/mdss/mdss-pll.h
index 8fffaf30d4ec..0120d71f0daf 100644
--- a/drivers/clk/msm/mdss/mdss-pll.h
+++ b/drivers/clk/msm/mdss/mdss-pll.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2013-2016, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2013-2017, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -37,7 +37,8 @@ enum {
MDSS_HDMI_PLL_8996_V2,
MDSS_HDMI_PLL_8996_V3,
MDSS_HDMI_PLL_8996_V3_1_8,
- MDSS_HDMI_PLL_8998,
+ MDSS_HDMI_PLL_8998_3_3,
+ MDSS_HDMI_PLL_8998_1_8,
MDSS_UNKNOWN_PLL,
};
diff --git a/drivers/cpuidle/lpm-levels.c b/drivers/cpuidle/lpm-levels.c
index 4224b594f1b8..b69e59eeeae1 100644
--- a/drivers/cpuidle/lpm-levels.c
+++ b/drivers/cpuidle/lpm-levels.c
@@ -363,6 +363,24 @@ static int lpm_cpu_callback(struct notifier_block *cpu_nb,
return NOTIFY_OK;
}
+#ifdef CONFIG_ARM_PSCI
+
+static int __init set_cpuidle_ops(void)
+{
+ int ret = 0, cpu;
+
+ for_each_possible_cpu(cpu) {
+ ret = arm_cpuidle_init(cpu);
+ if (ret)
+ goto exit;
+ }
+
+exit:
+ return ret;
+}
+
+#endif
+
static enum hrtimer_restart lpm_hrtimer_cb(struct hrtimer *h)
{
return HRTIMER_NORESTART;
@@ -1954,6 +1972,14 @@ static int __init lpm_levels_module_init(void)
goto fail;
}
+#ifdef CONFIG_ARM_PSCI
+ rc = set_cpuidle_ops();
+ if (rc) {
+ pr_err("%s(): Failed to set cpuidle ops\n", __func__);
+ goto fail;
+ }
+#endif
+
fail:
return rc;
}
diff --git a/drivers/crypto/msm/qcedev.c b/drivers/crypto/msm/qcedev.c
index d04ca6f28f90..beeb99e479c7 100644
--- a/drivers/crypto/msm/qcedev.c
+++ b/drivers/crypto/msm/qcedev.c
@@ -1741,6 +1741,12 @@ long qcedev_ioctl(struct file *file, unsigned cmd, unsigned long arg)
mutex_unlock(&hash_access_lock);
return err;
}
+ if (handle->sha_ctxt.diglen > QCEDEV_MAX_SHA_DIGEST) {
+ pr_err("Invalid sha_ctxt.diglen %d\n",
+ handle->sha_ctxt.diglen);
+ mutex_unlock(&hash_access_lock);
+ return -EINVAL;
+ }
qcedev_areq.sha_op_req.diglen = handle->sha_ctxt.diglen;
memcpy(&qcedev_areq.sha_op_req.digest[0],
&handle->sha_ctxt.digest[0],
@@ -1777,6 +1783,12 @@ long qcedev_ioctl(struct file *file, unsigned cmd, unsigned long arg)
mutex_unlock(&hash_access_lock);
return err;
}
+ if (handle->sha_ctxt.diglen > QCEDEV_MAX_SHA_DIGEST) {
+ pr_err("Invalid sha_ctxt.diglen %d\n",
+ handle->sha_ctxt.diglen);
+ mutex_unlock(&hash_access_lock);
+ return -EINVAL;
+ }
qcedev_areq.sha_op_req.diglen = handle->sha_ctxt.diglen;
memcpy(&qcedev_areq.sha_op_req.digest[0],
&handle->sha_ctxt.digest[0],
diff --git a/drivers/devfreq/governor_msm_adreno_tz.c b/drivers/devfreq/governor_msm_adreno_tz.c
index de21a231b73f..f31089d63e0c 100644
--- a/drivers/devfreq/governor_msm_adreno_tz.c
+++ b/drivers/devfreq/governor_msm_adreno_tz.c
@@ -534,8 +534,6 @@ static int tz_handler(struct devfreq *devfreq, unsigned int event, void *data)
(devfreq->profile),
struct msm_adreno_extended_profile,
profile);
- BUG_ON(devfreq == NULL);
-
switch (event) {
case DEVFREQ_GOV_START:
result = tz_start(devfreq);
diff --git a/drivers/firmware/psci.c b/drivers/firmware/psci.c
index af0060d6a22a..d652f3b53635 100644
--- a/drivers/firmware/psci.c
+++ b/drivers/firmware/psci.c
@@ -230,6 +230,13 @@ static int __init psci_features(u32 psci_func_id)
#ifdef CONFIG_CPU_IDLE
static DEFINE_PER_CPU_READ_MOSTLY(u32 *, psci_power_state);
+#ifdef CONFIG_ARM_PSCI
+static int psci_cpu_init(struct device_node *cpu_node, int cpu)
+{
+ return 0;
+}
+#endif
+
static int psci_dt_cpu_init_idle(struct device_node *cpu_node, int cpu)
{
int i, ret, count = 0;
@@ -333,10 +340,14 @@ int psci_cpu_suspend_enter(unsigned long state_id)
#ifdef CONFIG_ARM
static struct cpuidle_ops psci_cpuidle_ops __initdata = {
.suspend = psci_cpu_suspend_enter,
+#ifdef CONFIG_ARM_PSCI
+ .init = psci_cpu_init,
+#else
.init = psci_dt_cpu_init_idle,
+#endif
};
-CPUIDLE_METHOD_OF_DECLARE(psci, "arm,psci", &psci_cpuidle_ops);
+CPUIDLE_METHOD_OF_DECLARE(psci, "psci", &psci_cpuidle_ops);
#endif
#endif
diff --git a/drivers/gpio/gpiolib-acpi.c b/drivers/gpio/gpiolib-acpi.c
index 16a7b6816744..8decab2a9cce 100644
--- a/drivers/gpio/gpiolib-acpi.c
+++ b/drivers/gpio/gpiolib-acpi.c
@@ -597,7 +597,7 @@ int acpi_dev_gpio_irq_get(struct acpi_device *adev, int index)
int idx, i;
for (i = 0, idx = 0; idx <= index; i++) {
- struct acpi_gpio_info info;
+ struct acpi_gpio_info info = {0, 0};
struct gpio_desc *desc;
desc = acpi_get_gpiod_by_index(adev, NULL, i, &info);
diff --git a/drivers/gpu/drm/drm_mm.c b/drivers/gpu/drm/drm_mm.c
index 04de6fd88f8c..6e4dd62d4ed9 100644
--- a/drivers/gpu/drm/drm_mm.c
+++ b/drivers/gpu/drm/drm_mm.c
@@ -46,6 +46,8 @@
#include <linux/slab.h>
#include <linux/seq_file.h>
#include <linux/export.h>
+#include <linux/interval_tree_generic.h>
+#include <linux/rbtree.h>
/**
* DOC: Overview
@@ -73,7 +75,8 @@
* allocations and avoiding too much fragmentation. This means free space
* searches are O(num_holes). Given that all the fancy features drm_mm supports
* something better would be fairly complex and since gfx thrashing is a fairly
- * steep cliff not a real concern. Removing a node again is O(1).
+ * steep cliff not a real concern. Removing a node again is O(1). With the
+ * rbtree to track free holes, free hole search becomes O(log(num_holes)).
*
* drm_mm supports a few features: Alignment and range restrictions can be
* supplied. Further more every &drm_mm_node has a color value (which is just an
@@ -103,6 +106,98 @@ static struct drm_mm_node *drm_mm_search_free_in_range_generic(const struct drm_
u64 end,
enum drm_mm_search_flags flags);
+#define START(node) ((node)->start)
+#define LAST(node) ((node)->start + (node)->size - 1)
+
+INTERVAL_TREE_DEFINE(struct drm_mm_node, rb,
+ u64, __subtree_last,
+ START, LAST, static inline, drm_mm_interval_tree)
+
+struct drm_mm_node *
+drm_mm_interval_first(struct drm_mm *mm, u64 start, u64 last)
+{
+ return drm_mm_interval_tree_iter_first(&mm->interval_tree,
+ start, last);
+}
+EXPORT_SYMBOL(drm_mm_interval_first);
+
+struct drm_mm_node *
+drm_mm_interval_next(struct drm_mm_node *node, u64 start, u64 last)
+{
+ return drm_mm_interval_tree_iter_next(node, start, last);
+}
+EXPORT_SYMBOL(drm_mm_interval_next);
+
+static void drm_mm_interval_tree_add_node(struct drm_mm_node *hole_node,
+ struct drm_mm_node *node)
+{
+ struct drm_mm *mm = hole_node->mm;
+ struct rb_node **link, *rb;
+ struct drm_mm_node *parent;
+
+ node->__subtree_last = LAST(node);
+
+ if (hole_node->allocated) {
+ rb = &hole_node->rb;
+ while (rb) {
+ parent = rb_entry(rb, struct drm_mm_node, rb);
+ if (parent->__subtree_last >= node->__subtree_last)
+ break;
+
+ parent->__subtree_last = node->__subtree_last;
+ rb = rb_parent(rb);
+ }
+
+ rb = &hole_node->rb;
+ link = &hole_node->rb.rb_right;
+ } else {
+ rb = NULL;
+ link = &mm->interval_tree.rb_node;
+ }
+
+ while (*link) {
+ rb = *link;
+ parent = rb_entry(rb, struct drm_mm_node, rb);
+ if (parent->__subtree_last < node->__subtree_last)
+ parent->__subtree_last = node->__subtree_last;
+ if (node->start < parent->start)
+ link = &parent->rb.rb_left;
+ else
+ link = &parent->rb.rb_right;
+ }
+
+ rb_link_node(&node->rb, rb, link);
+ rb_insert_augmented(&node->rb,
+ &mm->interval_tree,
+ &drm_mm_interval_tree_augment);
+}
+
+static void
+rb_insert_hole_node(struct drm_mm_node *hole_node, struct drm_mm *mm)
+{
+ struct rb_node **new = &(mm->holes_tree.rb_node);
+ struct rb_node *parent = NULL;
+ struct drm_mm_node *cur;
+
+ while (*new) {
+ parent = *new;
+ cur = rb_entry(parent, struct drm_mm_node, hole_node);
+
+ if (__drm_mm_hole_node_start(hole_node)
+ < __drm_mm_hole_node_start(cur))
+ new = &parent->rb_left;
+ else
+ new = &parent->rb_right;
+ }
+ rb_link_node(&hole_node->hole_node, parent, new);
+ rb_insert_color(&hole_node->hole_node, &mm->holes_tree);
+}
+
+static void rb_erase_hole_node(struct drm_mm_node *hole_node, struct drm_mm *mm)
+{
+ rb_erase(&hole_node->hole_node, &mm->holes_tree);
+}
+
static void drm_mm_insert_helper(struct drm_mm_node *hole_node,
struct drm_mm_node *node,
u64 size, unsigned alignment,
@@ -142,6 +237,7 @@ static void drm_mm_insert_helper(struct drm_mm_node *hole_node,
if (adj_start == hole_start) {
hole_node->hole_follows = 0;
list_del(&hole_node->hole_stack);
+ rb_erase_hole_node(hole_node, mm);
}
node->start = adj_start;
@@ -150,14 +246,16 @@ static void drm_mm_insert_helper(struct drm_mm_node *hole_node,
node->color = color;
node->allocated = 1;
- INIT_LIST_HEAD(&node->hole_stack);
list_add(&node->node_list, &hole_node->node_list);
+ drm_mm_interval_tree_add_node(hole_node, node);
+
BUG_ON(node->start + node->size > adj_end);
node->hole_follows = 0;
if (__drm_mm_hole_node_start(node) < hole_end) {
list_add(&node->hole_stack, &mm->hole_stack);
+ rb_insert_hole_node(node, mm);
node->hole_follows = 1;
}
}
@@ -178,39 +276,54 @@ static void drm_mm_insert_helper(struct drm_mm_node *hole_node,
*/
int drm_mm_reserve_node(struct drm_mm *mm, struct drm_mm_node *node)
{
- struct drm_mm_node *hole;
u64 end = node->start + node->size;
- u64 hole_start;
- u64 hole_end;
+ struct drm_mm_node *hole;
+ u64 hole_start, hole_end;
- BUG_ON(node == NULL);
+ if (WARN_ON(node->size == 0))
+ return -EINVAL;
/* Find the relevant hole to add our node to */
- drm_mm_for_each_hole(hole, mm, hole_start, hole_end) {
- if (hole_start > node->start || hole_end < end)
- continue;
+ hole = drm_mm_interval_tree_iter_first(&mm->interval_tree,
+ node->start, ~(u64)0);
+ if (hole) {
+ if (hole->start < end)
+ return -ENOSPC;
+ } else {
+ hole = list_entry(&mm->head_node.node_list,
+ typeof(*hole), node_list);
+ }
- node->mm = mm;
- node->allocated = 1;
+ hole = list_last_entry(&hole->node_list, typeof(*hole), node_list);
+ if (!hole->hole_follows)
+ return -ENOSPC;
- INIT_LIST_HEAD(&node->hole_stack);
- list_add(&node->node_list, &hole->node_list);
+ hole_start = __drm_mm_hole_node_start(hole);
+ hole_end = __drm_mm_hole_node_end(hole);
+ if (hole_start > node->start || hole_end < end)
+ return -ENOSPC;
- if (node->start == hole_start) {
- hole->hole_follows = 0;
- list_del_init(&hole->hole_stack);
- }
+ node->mm = mm;
+ node->allocated = 1;
- node->hole_follows = 0;
- if (end != hole_end) {
- list_add(&node->hole_stack, &mm->hole_stack);
- node->hole_follows = 1;
- }
+ list_add(&node->node_list, &hole->node_list);
- return 0;
+ drm_mm_interval_tree_add_node(hole, node);
+
+ if (node->start == hole_start) {
+ hole->hole_follows = 0;
+ list_del(&hole->hole_stack);
+ rb_erase_hole_node(hole, mm);
}
- return -ENOSPC;
+ node->hole_follows = 0;
+ if (end != hole_end) {
+ list_add(&node->hole_stack, &mm->hole_stack);
+ rb_insert_hole_node(node, mm);
+ node->hole_follows = 1;
+ }
+
+ return 0;
}
EXPORT_SYMBOL(drm_mm_reserve_node);
@@ -237,6 +350,9 @@ int drm_mm_insert_node_generic(struct drm_mm *mm, struct drm_mm_node *node,
{
struct drm_mm_node *hole_node;
+ if (WARN_ON(size == 0))
+ return -EINVAL;
+
hole_node = drm_mm_search_free_generic(mm, size, alignment,
color, sflags);
if (!hole_node)
@@ -289,6 +405,7 @@ static void drm_mm_insert_helper_range(struct drm_mm_node *hole_node,
if (adj_start == hole_start) {
hole_node->hole_follows = 0;
list_del(&hole_node->hole_stack);
+ rb_erase_hole_node(hole_node, mm);
}
node->start = adj_start;
@@ -297,9 +414,10 @@ static void drm_mm_insert_helper_range(struct drm_mm_node *hole_node,
node->color = color;
node->allocated = 1;
- INIT_LIST_HEAD(&node->hole_stack);
list_add(&node->node_list, &hole_node->node_list);
+ drm_mm_interval_tree_add_node(hole_node, node);
+
BUG_ON(node->start < start);
BUG_ON(node->start < adj_start);
BUG_ON(node->start + node->size > adj_end);
@@ -308,6 +426,7 @@ static void drm_mm_insert_helper_range(struct drm_mm_node *hole_node,
node->hole_follows = 0;
if (__drm_mm_hole_node_start(node) < hole_end) {
list_add(&node->hole_stack, &mm->hole_stack);
+ rb_insert_hole_node(node, mm);
node->hole_follows = 1;
}
}
@@ -338,6 +457,9 @@ int drm_mm_insert_node_in_range_generic(struct drm_mm *mm, struct drm_mm_node *n
{
struct drm_mm_node *hole_node;
+ if (WARN_ON(size == 0))
+ return -EINVAL;
+
hole_node = drm_mm_search_free_in_range_generic(mm,
size, alignment, color,
start, end, sflags);
@@ -377,6 +499,7 @@ void drm_mm_remove_node(struct drm_mm_node *node)
BUG_ON(__drm_mm_hole_node_start(node) ==
__drm_mm_hole_node_end(node));
list_del(&node->hole_stack);
+ rb_erase_hole_node(node, mm);
} else
BUG_ON(__drm_mm_hole_node_start(node) !=
__drm_mm_hole_node_end(node));
@@ -385,9 +508,11 @@ void drm_mm_remove_node(struct drm_mm_node *node)
if (!prev_node->hole_follows) {
prev_node->hole_follows = 1;
list_add(&prev_node->hole_stack, &mm->hole_stack);
+ rb_insert_hole_node(prev_node, mm);
} else
list_move(&prev_node->hole_stack, &mm->hole_stack);
+ drm_mm_interval_tree_remove(node, &mm->interval_tree);
list_del(&node->node_list);
node->allocated = 0;
}
@@ -410,6 +535,46 @@ static int check_free_hole(u64 start, u64 end, u64 size, unsigned alignment)
return end >= start + size;
}
+static struct drm_mm_node *get_first_hole(const struct drm_mm *mm,
+ enum drm_mm_search_flags flags)
+{
+ if (flags & DRM_MM_SEARCH_BOTTOM_UP) {
+ struct rb_node *node = rb_first(&mm->holes_tree);
+
+ return rb_entry(node, struct drm_mm_node, hole_node);
+ } else if (flags & DRM_MM_SEARCH_BELOW) {
+ return list_entry((mm)->hole_stack.prev,
+ struct drm_mm_node, hole_stack);
+ } else {
+ return list_entry((mm)->hole_stack.next,
+ struct drm_mm_node, hole_stack);
+ }
+}
+
+static struct drm_mm_node *get_next_hole(struct drm_mm_node *entry,
+ enum drm_mm_search_flags flags)
+{
+ if (flags & DRM_MM_SEARCH_BOTTOM_UP) {
+ return rb_entry(rb_next(&entry->hole_node),
+ struct drm_mm_node, hole_node);
+ } else if (flags & DRM_MM_SEARCH_BELOW) {
+ return list_entry(entry->hole_stack.prev,
+ struct drm_mm_node, hole_stack);
+ } else {
+ return list_entry(entry->hole_stack.next,
+ struct drm_mm_node, hole_stack);
+ }
+}
+
+static bool drm_mm_hole_traversal_condition(const struct drm_mm *mm,
+ struct drm_mm_node *entry, enum drm_mm_search_flags flags)
+{
+ if (flags & DRM_MM_SEARCH_BOTTOM_UP)
+ return entry ? 1 : 0;
+ else
+ return (&entry->hole_stack != &(mm)->hole_stack) ? 1 : 0;
+}
+
static struct drm_mm_node *drm_mm_search_free_generic(const struct drm_mm *mm,
u64 size,
unsigned alignment,
@@ -427,9 +592,14 @@ static struct drm_mm_node *drm_mm_search_free_generic(const struct drm_mm *mm,
best = NULL;
best_size = ~0UL;
- __drm_mm_for_each_hole(entry, mm, adj_start, adj_end,
- flags & DRM_MM_SEARCH_BELOW) {
- u64 hole_size = adj_end - adj_start;
+ for (entry = get_first_hole(mm, flags);
+ drm_mm_hole_traversal_condition(mm, entry, flags);
+ entry = get_next_hole(entry, flags)) {
+ u64 hole_size;
+
+ adj_start = drm_mm_hole_node_start(entry);
+ adj_end = drm_mm_hole_node_end(entry);
+ hole_size = adj_end - adj_start;
if (mm->color_adjust) {
mm->color_adjust(entry, color, &adj_start, &adj_end);
@@ -471,9 +641,14 @@ static struct drm_mm_node *drm_mm_search_free_in_range_generic(const struct drm_
best = NULL;
best_size = ~0UL;
- __drm_mm_for_each_hole(entry, mm, adj_start, adj_end,
- flags & DRM_MM_SEARCH_BELOW) {
- u64 hole_size = adj_end - adj_start;
+ for (entry = get_first_hole(mm, flags);
+ drm_mm_hole_traversal_condition(mm, entry, flags);
+ entry = get_next_hole(entry, flags)) {
+ u64 hole_size;
+
+ adj_start = drm_mm_hole_node_start(entry);
+ adj_end = drm_mm_hole_node_end(entry);
+ hole_size = adj_end - adj_start;
if (adj_start < start)
adj_start = start;
@@ -514,14 +689,21 @@ void drm_mm_replace_node(struct drm_mm_node *old, struct drm_mm_node *new)
{
list_replace(&old->node_list, &new->node_list);
list_replace(&old->hole_stack, &new->hole_stack);
+ rb_replace_node(&old->rb, &new->rb, &old->mm->interval_tree);
new->hole_follows = old->hole_follows;
new->mm = old->mm;
new->start = old->start;
new->size = old->size;
new->color = old->color;
+ new->__subtree_last = old->__subtree_last;
old->allocated = 0;
new->allocated = 1;
+
+ if (old->hole_follows)
+ rb_replace_node(&old->hole_node, &new->hole_node,
+ &old->mm->holes_tree);
+
}
EXPORT_SYMBOL(drm_mm_replace_node);
@@ -746,7 +928,6 @@ void drm_mm_init(struct drm_mm * mm, u64 start, u64 size)
/* Clever trick to avoid a special case in the free hole tracking. */
INIT_LIST_HEAD(&mm->head_node.node_list);
- INIT_LIST_HEAD(&mm->head_node.hole_stack);
mm->head_node.hole_follows = 1;
mm->head_node.scanned_block = 0;
mm->head_node.scanned_prev_free = 0;
@@ -756,7 +937,10 @@ void drm_mm_init(struct drm_mm * mm, u64 start, u64 size)
mm->head_node.size = start - mm->head_node.start;
list_add_tail(&mm->head_node.hole_stack, &mm->hole_stack);
+ mm->interval_tree = RB_ROOT;
mm->color_adjust = NULL;
+ mm->holes_tree = RB_ROOT;
+ rb_insert_hole_node(&mm->head_node, mm);
}
EXPORT_SYMBOL(drm_mm_init);
diff --git a/drivers/gpu/drm/msm/Kconfig b/drivers/gpu/drm/msm/Kconfig
index 5838545468f8..dbc198b00792 100644
--- a/drivers/gpu/drm/msm/Kconfig
+++ b/drivers/gpu/drm/msm/Kconfig
@@ -12,6 +12,8 @@ config DRM_MSM
select QCOM_SCM
select BACKLIGHT_CLASS_DEVICE
select MSM_EXT_DISPLAY
+ select MMU_NOTIFIER
+ select INTERVAL_TREE
default y
help
DRM/KMS driver for MSM/snapdragon.
diff --git a/drivers/gpu/drm/msm/adreno/a5xx_gpu.c b/drivers/gpu/drm/msm/adreno/a5xx_gpu.c
index 3caa460aa5ba..8a136fef86f1 100644
--- a/drivers/gpu/drm/msm/adreno/a5xx_gpu.c
+++ b/drivers/gpu/drm/msm/adreno/a5xx_gpu.c
@@ -481,10 +481,8 @@ static struct drm_gem_object *a5xx_ucode_load_bo(struct msm_gpu *gpu,
struct drm_gem_object *bo;
void *ptr;
- mutex_lock(&drm->struct_mutex);
bo = msm_gem_new(drm, fw->size - 4,
MSM_BO_UNCACHED | MSM_BO_GPU_READONLY);
- mutex_unlock(&drm->struct_mutex);
if (IS_ERR(bo))
return bo;
@@ -1408,8 +1406,8 @@ struct msm_gpu *a5xx_gpu_init(struct drm_device *dev)
* Set the user domain range to fall into the TTBR1 region for global
* objects
*/
- a5xx_config.va_start = 0x800000000;
- a5xx_config.va_end = 0x8ffffffff;
+ a5xx_config.va_start = 0xfffffff000000000ULL;
+ a5xx_config.va_end = 0xffffffffffffffffULL;
a5xx_config.secure_va_start = SECURE_VA_START;
a5xx_config.secure_va_end = SECURE_VA_START + SECURE_VA_SIZE - 1;
diff --git a/drivers/gpu/drm/msm/adreno/a5xx_power.c b/drivers/gpu/drm/msm/adreno/a5xx_power.c
index e04feaadefb9..0025922540df 100644
--- a/drivers/gpu/drm/msm/adreno/a5xx_power.c
+++ b/drivers/gpu/drm/msm/adreno/a5xx_power.c
@@ -458,10 +458,8 @@ void a5xx_gpmu_ucode_init(struct msm_gpu *gpu)
*/
bosize = (cmds_size + (cmds_size / TYPE4_MAX_PAYLOAD) + 1) << 2;
- mutex_lock(&drm->struct_mutex);
a5xx_gpu->gpmu_bo = msm_gem_new(drm, bosize,
MSM_BO_UNCACHED | MSM_BO_GPU_READONLY);
- mutex_unlock(&drm->struct_mutex);
if (IS_ERR(a5xx_gpu->gpmu_bo))
goto err;
diff --git a/drivers/gpu/drm/msm/adreno/a5xx_preempt.c b/drivers/gpu/drm/msm/adreno/a5xx_preempt.c
index 648494c75abc..57046089434c 100644
--- a/drivers/gpu/drm/msm/adreno/a5xx_preempt.c
+++ b/drivers/gpu/drm/msm/adreno/a5xx_preempt.c
@@ -24,9 +24,7 @@ static void *alloc_kernel_bo(struct drm_device *drm, struct msm_gpu *gpu,
void *ptr;
int ret;
- mutex_lock(&drm->struct_mutex);
_bo = msm_gem_new(drm, size, flags);
- mutex_unlock(&drm->struct_mutex);
if (IS_ERR(_bo))
return _bo;
diff --git a/drivers/gpu/drm/msm/adreno/a5xx_snapshot.c b/drivers/gpu/drm/msm/adreno/a5xx_snapshot.c
index 690e6f546e60..c2773cb325d5 100644
--- a/drivers/gpu/drm/msm/adreno/a5xx_snapshot.c
+++ b/drivers/gpu/drm/msm/adreno/a5xx_snapshot.c
@@ -217,18 +217,19 @@ static int crashdump_init(struct msm_gpu *gpu, struct crashdump *crashdump)
struct drm_device *drm = gpu->dev;
int ret = -ENOMEM;
- crashdump->bo = msm_gem_new(drm, CRASHDUMP_BO_SIZE, MSM_BO_UNCACHED);
+ crashdump->bo = msm_gem_new_locked(drm, CRASHDUMP_BO_SIZE,
+ MSM_BO_UNCACHED);
if (IS_ERR(crashdump->bo)) {
ret = PTR_ERR(crashdump->bo);
crashdump->bo = NULL;
return ret;
}
- crashdump->ptr = msm_gem_vaddr_locked(crashdump->bo);
+ crashdump->ptr = msm_gem_vaddr(crashdump->bo);
if (!crashdump->ptr)
goto out;
- ret = msm_gem_get_iova_locked(crashdump->bo, gpu->aspace,
+ ret = msm_gem_get_iova(crashdump->bo, gpu->aspace,
&crashdump->iova);
out:
diff --git a/drivers/gpu/drm/msm/adreno/adreno_gpu.c b/drivers/gpu/drm/msm/adreno/adreno_gpu.c
index d3cb497411c4..81fa37ee9671 100644
--- a/drivers/gpu/drm/msm/adreno/adreno_gpu.c
+++ b/drivers/gpu/drm/msm/adreno/adreno_gpu.c
@@ -563,10 +563,8 @@ int adreno_gpu_init(struct drm_device *drm, struct platform_device *pdev,
}
}
- mutex_lock(&drm->struct_mutex);
adreno_gpu->memptrs_bo = msm_gem_new(drm, sizeof(*adreno_gpu->memptrs),
MSM_BO_UNCACHED);
- mutex_unlock(&drm->struct_mutex);
if (IS_ERR(adreno_gpu->memptrs_bo)) {
ret = PTR_ERR(adreno_gpu->memptrs_bo);
adreno_gpu->memptrs_bo = NULL;
diff --git a/drivers/gpu/drm/msm/dsi/dsi_host.c b/drivers/gpu/drm/msm/dsi/dsi_host.c
index 4580a6e3c877..e2b8deda46c2 100644
--- a/drivers/gpu/drm/msm/dsi/dsi_host.c
+++ b/drivers/gpu/drm/msm/dsi/dsi_host.c
@@ -838,22 +838,19 @@ static int dsi_tx_buf_alloc(struct msm_dsi_host *msm_host, int size)
int ret;
u64 iova;
- mutex_lock(&dev->struct_mutex);
msm_host->tx_gem_obj = msm_gem_new(dev, size, MSM_BO_UNCACHED);
if (IS_ERR(msm_host->tx_gem_obj)) {
ret = PTR_ERR(msm_host->tx_gem_obj);
pr_err("%s: failed to allocate gem, %d\n", __func__, ret);
msm_host->tx_gem_obj = NULL;
- mutex_unlock(&dev->struct_mutex);
return ret;
}
- ret = msm_gem_get_iova_locked(msm_host->tx_gem_obj, 0, &iova);
+ ret = msm_gem_get_iova(msm_host->tx_gem_obj, NULL, &iova);
if (ret) {
pr_err("%s: failed to get iova, %d\n", __func__, ret);
return ret;
}
- mutex_unlock(&dev->struct_mutex);
if (iova & 0x07) {
pr_err("%s: buf NOT 8 bytes aligned\n", __func__);
diff --git a/drivers/gpu/drm/msm/hdmi-staging/sde_hdmi.c b/drivers/gpu/drm/msm/hdmi-staging/sde_hdmi.c
index 4c70472bd338..acc417737558 100644
--- a/drivers/gpu/drm/msm/hdmi-staging/sde_hdmi.c
+++ b/drivers/gpu/drm/msm/hdmi-staging/sde_hdmi.c
@@ -907,6 +907,17 @@ static void _sde_hdmi_hdp_disable(struct sde_hdmi *sde_hdmi)
}
}
+static void _sde_hdmi_cec_update_phys_addr(struct sde_hdmi *display)
+{
+ struct edid *edid = display->edid_ctrl->edid;
+
+ if (edid)
+ cec_notifier_set_phys_addr_from_edid(display->notifier, edid);
+ else
+ cec_notifier_set_phys_addr(display->notifier,
+ CEC_PHYS_ADDR_INVALID);
+}
+
static void _sde_hdmi_hotplug_work(struct work_struct *work)
{
struct sde_hdmi *sde_hdmi =
@@ -936,6 +947,7 @@ static void _sde_hdmi_hotplug_work(struct work_struct *work)
sde_free_edid((void **)&sde_hdmi->edid_ctrl);
drm_helper_hpd_irq_event(connector->dev);
+ _sde_hdmi_cec_update_phys_addr(sde_hdmi);
}
static void _sde_hdmi_connector_irq(struct sde_hdmi *sde_hdmi)
@@ -1673,10 +1685,28 @@ int sde_hdmi_dev_deinit(struct sde_hdmi *display)
SDE_ERROR("Invalid params\n");
return -EINVAL;
}
+ return 0;
+}
+
+static int _sde_hdmi_cec_init(struct sde_hdmi *display)
+{
+ struct platform_device *pdev = display->pdev;
+
+ display->notifier = cec_notifier_get(&pdev->dev);
+ if (!display->notifier) {
+ SDE_ERROR("CEC notifier get failed\n");
+ return -ENOMEM;
+ }
return 0;
}
+static void _sde_hdmi_cec_deinit(struct sde_hdmi *display)
+{
+ cec_notifier_set_phys_addr(display->notifier, CEC_PHYS_ADDR_INVALID);
+ cec_notifier_put(display->notifier);
+}
+
static int sde_hdmi_bind(struct device *dev, struct device *master, void *data)
{
int rc = 0;
@@ -1715,7 +1745,14 @@ static int sde_hdmi_bind(struct device *dev, struct device *master, void *data)
if (rc) {
SDE_ERROR("[%s]Ext Disp init failed, rc=%d\n",
display->name, rc);
- goto error;
+ goto ext_error;
+ }
+
+ rc = _sde_hdmi_cec_init(display);
+ if (rc) {
+ SDE_ERROR("[%s]CEC init failed, rc=%d\n",
+ display->name, rc);
+ goto ext_error;
}
display->edid_ctrl = sde_edid_init();
@@ -1723,7 +1760,7 @@ static int sde_hdmi_bind(struct device *dev, struct device *master, void *data)
SDE_ERROR("[%s]sde edid init failed\n",
display->name);
rc = -ENOMEM;
- goto error;
+ goto cec_error;
}
display_ctrl = &display->ctrl;
@@ -1732,7 +1769,10 @@ static int sde_hdmi_bind(struct device *dev, struct device *master, void *data)
mutex_unlock(&display->display_lock);
return rc;
-error:
+
+cec_error:
+ (void)_sde_hdmi_cec_deinit(display);
+ext_error:
(void)_sde_hdmi_debugfs_deinit(display);
debug_error:
mutex_unlock(&display->display_lock);
@@ -1758,6 +1798,7 @@ static void sde_hdmi_unbind(struct device *dev, struct device *master,
mutex_lock(&display->display_lock);
(void)_sde_hdmi_debugfs_deinit(display);
(void)sde_edid_deinit((void **)&display->edid_ctrl);
+ (void)_sde_hdmi_cec_deinit(display);
display->drm_dev = NULL;
mutex_unlock(&display->display_lock);
}
diff --git a/drivers/gpu/drm/msm/hdmi-staging/sde_hdmi.h b/drivers/gpu/drm/msm/hdmi-staging/sde_hdmi.h
index 54506da4f9b0..dff245dec764 100644
--- a/drivers/gpu/drm/msm/hdmi-staging/sde_hdmi.h
+++ b/drivers/gpu/drm/msm/hdmi-staging/sde_hdmi.h
@@ -23,6 +23,7 @@
#include <drm/drmP.h>
#include <drm/drm_crtc.h>
+#include <media/cec-notifier.h>
#include "hdmi.h"
#include "sde_edid_parser.h"
@@ -87,6 +88,7 @@ struct sde_hdmi_ctrl {
* @codec_ready: If audio codec is ready.
* @client_notify_pending: If there is client notification pending.
* @irq_domain: IRQ domain structure.
+ * @notifier: CEC notifider to convey physical address information.
* @root: Debug fs root entry.
*/
struct sde_hdmi {
@@ -116,6 +118,7 @@ struct sde_hdmi {
bool client_notify_pending;
struct irq_domain *irq_domain;
+ struct cec_notifier *notifier;
/* DEBUG FS */
struct dentry *root;
diff --git a/drivers/gpu/drm/msm/hdmi-staging/sde_hdmi_bridge.c b/drivers/gpu/drm/msm/hdmi-staging/sde_hdmi_bridge.c
index 34268aaedfc0..26a0638f7792 100644
--- a/drivers/gpu/drm/msm/hdmi-staging/sde_hdmi_bridge.c
+++ b/drivers/gpu/drm/msm/hdmi-staging/sde_hdmi_bridge.c
@@ -328,7 +328,6 @@ static int _sde_hdmi_bridge_setup_scrambler(struct hdmi *hdmi,
}
reg_val = hdmi_read(hdmi, REG_HDMI_CTRL);
- reg_val |= BIT(31); /* Enable Update DATAPATH_MODE */
reg_val |= BIT(28); /* Set SCRAMBLER_EN bit */
hdmi_write(hdmi, REG_HDMI_CTRL, reg_val);
@@ -360,7 +359,6 @@ static int _sde_hdmi_bridge_setup_scrambler(struct hdmi *hdmi,
} else {
sde_hdmi_scdc_write(hdmi, HDMI_TX_SCDC_SCRAMBLING_ENABLE, 0x0);
reg_val = hdmi_read(hdmi, REG_HDMI_CTRL);
- reg_val &= ~BIT(31); /* Disable Update DATAPATH_MODE */
reg_val &= ~BIT(28); /* Unset SCRAMBLER_EN bit */
hdmi_write(hdmi, REG_HDMI_CTRL, reg_val);
}
diff --git a/drivers/gpu/drm/msm/mdp/mdp4/mdp4_crtc.c b/drivers/gpu/drm/msm/mdp/mdp4/mdp4_crtc.c
index caad2be87ae4..e5f42fe983c1 100644
--- a/drivers/gpu/drm/msm/mdp/mdp4/mdp4_crtc.c
+++ b/drivers/gpu/drm/msm/mdp/mdp4/mdp4_crtc.c
@@ -392,7 +392,7 @@ static void update_cursor(struct drm_crtc *crtc)
if (next_bo) {
/* take a obj ref + iova ref when we start scanning out: */
drm_gem_object_reference(next_bo);
- msm_gem_get_iova_locked(next_bo, mdp4_kms->aspace,
+ msm_gem_get_iova(next_bo, mdp4_kms->aspace,
&iova);
/* enable cursor: */
diff --git a/drivers/gpu/drm/msm/mdp/mdp4/mdp4_kms.c b/drivers/gpu/drm/msm/mdp/mdp4/mdp4_kms.c
index 119221eacb43..40509434a913 100644
--- a/drivers/gpu/drm/msm/mdp/mdp4/mdp4_kms.c
+++ b/drivers/gpu/drm/msm/mdp/mdp4/mdp4_kms.c
@@ -536,9 +536,7 @@ struct msm_kms *mdp4_kms_init(struct drm_device *dev)
goto fail;
}
- mutex_lock(&dev->struct_mutex);
mdp4_kms->blank_cursor_bo = msm_gem_new(dev, SZ_16K, MSM_BO_WC);
- mutex_unlock(&dev->struct_mutex);
if (IS_ERR(mdp4_kms->blank_cursor_bo)) {
ret = PTR_ERR(mdp4_kms->blank_cursor_bo);
dev_err(dev->dev, "could not allocate blank-cursor bo: %d\n", ret);
diff --git a/drivers/gpu/drm/msm/msm_drv.c b/drivers/gpu/drm/msm/msm_drv.c
index 665f8db0e04f..74f298d7328d 100644
--- a/drivers/gpu/drm/msm/msm_drv.c
+++ b/drivers/gpu/drm/msm/msm_drv.c
@@ -322,6 +322,7 @@ static int msm_init_vram(struct drm_device *dev)
priv->vram.size = size;
drm_mm_init(&priv->vram.mm, 0, (size >> PAGE_SHIFT) - 1);
+ spin_lock_init(&priv->vram.lock);
dma_set_attr(DMA_ATTR_NO_KERNEL_MAPPING, &attrs);
dma_set_attr(DMA_ATTR_WRITE_COMBINE, &attrs);
@@ -390,6 +391,8 @@ static int msm_load(struct drm_device *dev, unsigned long flags)
INIT_LIST_HEAD(&priv->vblank_ctrl.event_list);
init_kthread_work(&priv->vblank_ctrl.work, vblank_ctrl_worker);
spin_lock_init(&priv->vblank_ctrl.lock);
+ hash_init(priv->mn_hash);
+ mutex_init(&priv->mn_lock);
drm_mode_config_init(dev);
@@ -558,7 +561,8 @@ static struct msm_file_private *setup_pagetable(struct msm_drm_private *priv)
return ERR_PTR(-ENOMEM);
ctx->aspace = msm_gem_address_space_create_instance(
- priv->gpu->aspace->mmu, "gpu", 0x100000000, 0x1ffffffff);
+ priv->gpu->aspace->mmu, "gpu", 0x100000000ULL,
+ TASK_SIZE_64 - 1);
if (IS_ERR(ctx->aspace)) {
int ret = PTR_ERR(ctx->aspace);
@@ -631,12 +635,10 @@ static void msm_postclose(struct drm_device *dev, struct drm_file *file)
if (priv->gpu)
msm_gpu_cleanup_counters(priv->gpu, ctx);
- mutex_lock(&dev->struct_mutex);
if (ctx && ctx->aspace && ctx->aspace != priv->gpu->aspace) {
ctx->aspace->mmu->funcs->detach(ctx->aspace->mmu);
msm_gem_address_space_put(ctx->aspace);
}
- mutex_unlock(&dev->struct_mutex);
kfree(ctx);
}
@@ -1142,6 +1144,20 @@ static int msm_ioctl_gem_new(struct drm_device *dev, void *data,
args->flags, &args->handle);
}
+static int msm_ioctl_gem_svm_new(struct drm_device *dev, void *data,
+ struct drm_file *file)
+{
+ struct drm_msm_gem_svm_new *args = data;
+
+ if (args->flags & ~MSM_BO_FLAGS) {
+ DRM_ERROR("invalid flags: %08x\n", args->flags);
+ return -EINVAL;
+ }
+
+ return msm_gem_svm_new_handle(dev, file, args->hostptr, args->size,
+ args->flags, &args->handle);
+}
+
static inline ktime_t to_ktime(struct drm_msm_timespec timeout)
{
return ktime_set(timeout.tv_sec, timeout.tv_nsec);
@@ -1194,6 +1210,7 @@ static int msm_ioctl_gem_info(struct drm_device *dev, void *data,
{
struct drm_msm_gem_info *args = data;
struct drm_gem_object *obj;
+ struct msm_gem_object *msm_obj;
struct msm_file_private *ctx = file->driver_priv;
int ret = 0;
@@ -1204,10 +1221,10 @@ static int msm_ioctl_gem_info(struct drm_device *dev, void *data,
if (!obj)
return -ENOENT;
+ msm_obj = to_msm_bo(obj);
if (args->flags & MSM_INFO_IOVA) {
struct msm_gem_address_space *aspace = NULL;
struct msm_drm_private *priv = dev->dev_private;
- struct msm_gem_object *msm_obj = to_msm_bo(obj);
uint64_t iova;
if (msm_obj->flags & MSM_BO_SECURE && priv->gpu)
@@ -1224,6 +1241,14 @@ static int msm_ioctl_gem_info(struct drm_device *dev, void *data,
if (!ret)
args->offset = iova;
} else {
+ if (msm_obj->flags & MSM_BO_SVM) {
+ /*
+ * Offset for an SVM object is not needed as they are
+ * already mmap'ed before the SVM ioctl is invoked.
+ */
+ ret = -EACCES;
+ goto out;
+ }
args->offset = msm_gem_mmap_offset(obj);
}
@@ -1701,6 +1726,8 @@ static const struct drm_ioctl_desc msm_ioctls[] = {
DRM_AUTH|DRM_RENDER_ALLOW),
DRM_IOCTL_DEF_DRV(MSM_GEM_SYNC, msm_ioctl_gem_sync,
DRM_AUTH|DRM_RENDER_ALLOW),
+ DRM_IOCTL_DEF_DRV(MSM_GEM_SVM_NEW, msm_ioctl_gem_svm_new,
+ DRM_AUTH|DRM_RENDER_ALLOW),
};
static const struct vm_operations_struct vm_ops = {
diff --git a/drivers/gpu/drm/msm/msm_drv.h b/drivers/gpu/drm/msm/msm_drv.h
index 94f429cb83a7..4083e990b2c8 100644
--- a/drivers/gpu/drm/msm/msm_drv.h
+++ b/drivers/gpu/drm/msm/msm_drv.h
@@ -34,6 +34,7 @@
#include <linux/of_graph.h>
#include <linux/of_device.h>
#include <linux/sde_io_util.h>
+#include <linux/hashtable.h>
#include <asm/sizes.h>
#include <linux/kthread.h>
@@ -325,6 +326,11 @@ struct msm_drm_private {
unsigned int num_connectors;
struct drm_connector *connectors[MAX_CONNECTORS];
+ /* hash to store mm_struct to msm_mmu_notifier mappings */
+ DECLARE_HASHTABLE(mn_hash, 7);
+ /* protects mn_hash and the msm_mmu_notifier for the process */
+ struct mutex mn_lock;
+
/* Properties */
struct drm_property *plane_property[PLANE_PROP_COUNT];
struct drm_property *crtc_property[CRTC_PROP_COUNT];
@@ -341,6 +347,7 @@ struct msm_drm_private {
* and position mm_node->start is in # of pages:
*/
struct drm_mm mm;
+ spinlock_t lock; /* Protects drm_mm node allocation/removal */
} vram;
struct msm_vblank_ctrl vblank_ctrl;
@@ -403,10 +410,15 @@ void msm_update_fence(struct drm_device *dev, uint32_t fence);
void msm_gem_unmap_vma(struct msm_gem_address_space *aspace,
struct msm_gem_vma *vma, struct sg_table *sgt,
- void *priv);
+ void *priv, bool invalidated);
int msm_gem_map_vma(struct msm_gem_address_space *aspace,
struct msm_gem_vma *vma, struct sg_table *sgt,
void *priv, unsigned int flags);
+int msm_gem_reserve_iova(struct msm_gem_address_space *aspace,
+ struct msm_gem_vma *domain,
+ uint64_t hostptr, uint64_t size);
+void msm_gem_release_iova(struct msm_gem_address_space *aspace,
+ struct msm_gem_vma *vma);
void msm_gem_address_space_put(struct msm_gem_address_space *aspace);
@@ -431,8 +443,6 @@ int msm_gem_mmap_obj(struct drm_gem_object *obj,
int msm_gem_mmap(struct file *filp, struct vm_area_struct *vma);
int msm_gem_fault(struct vm_area_struct *vma, struct vm_fault *vmf);
uint64_t msm_gem_mmap_offset(struct drm_gem_object *obj);
-int msm_gem_get_iova_locked(struct drm_gem_object *obj,
- struct msm_gem_address_space *aspace, uint64_t *iova);
int msm_gem_get_iova(struct drm_gem_object *obj,
struct msm_gem_address_space *aspace, uint64_t *iova);
uint64_t msm_gem_iova(struct drm_gem_object *obj,
@@ -453,7 +463,6 @@ struct drm_gem_object *msm_gem_prime_import_sg_table(struct drm_device *dev,
struct dma_buf_attachment *attach, struct sg_table *sg);
int msm_gem_prime_pin(struct drm_gem_object *obj);
void msm_gem_prime_unpin(struct drm_gem_object *obj);
-void *msm_gem_vaddr_locked(struct drm_gem_object *obj);
void *msm_gem_vaddr(struct drm_gem_object *obj);
int msm_gem_queue_inactive_cb(struct drm_gem_object *obj,
struct msm_fence_cb *cb);
@@ -468,9 +477,17 @@ int msm_gem_new_handle(struct drm_device *dev, struct drm_file *file,
uint32_t size, uint32_t flags, uint32_t *handle);
struct drm_gem_object *msm_gem_new(struct drm_device *dev,
uint32_t size, uint32_t flags);
+struct drm_gem_object *msm_gem_new_locked(struct drm_device *dev,
+ uint32_t size, uint32_t flags);
struct drm_gem_object *msm_gem_import(struct drm_device *dev,
uint32_t size, struct sg_table *sgt, u32 flags);
void msm_gem_sync(struct drm_gem_object *obj, u32 op);
+int msm_gem_svm_new_handle(struct drm_device *dev, struct drm_file *file,
+ uint64_t hostptr, uint64_t size,
+ uint32_t flags, uint32_t *handle);
+struct drm_gem_object *msm_gem_svm_new(struct drm_device *dev,
+ struct drm_file *file, uint64_t hostptr,
+ uint64_t size, uint32_t flags);
int msm_framebuffer_prepare(struct drm_framebuffer *fb,
struct msm_gem_address_space *aspace);
diff --git a/drivers/gpu/drm/msm/msm_fbdev.c b/drivers/gpu/drm/msm/msm_fbdev.c
index cf127250c0d0..28b98cc1433c 100644
--- a/drivers/gpu/drm/msm/msm_fbdev.c
+++ b/drivers/gpu/drm/msm/msm_fbdev.c
@@ -104,10 +104,8 @@ static int msm_fbdev_create(struct drm_fb_helper *helper,
/* allocate backing bo */
size = mode_cmd.pitches[0] * mode_cmd.height;
DBG("allocating %d bytes for fb %d", size, dev->primary->index);
- mutex_lock(&dev->struct_mutex);
fbdev->bo = msm_gem_new(dev, size, MSM_BO_SCANOUT |
MSM_BO_WC | MSM_BO_STOLEN);
- mutex_unlock(&dev->struct_mutex);
if (IS_ERR(fbdev->bo)) {
ret = PTR_ERR(fbdev->bo);
fbdev->bo = NULL;
@@ -133,7 +131,7 @@ static int msm_fbdev_create(struct drm_fb_helper *helper,
* in panic (ie. lock-safe, etc) we could avoid pinning the
* buffer now:
*/
- ret = msm_gem_get_iova_locked(fbdev->bo, 0, &paddr);
+ ret = msm_gem_get_iova(fbdev->bo, 0, &paddr);
if (ret) {
dev_err(dev->dev, "failed to get buffer obj iova: %d\n", ret);
goto fail_unlock;
@@ -163,7 +161,7 @@ static int msm_fbdev_create(struct drm_fb_helper *helper,
/* FIXME: Verify paddr < 32 bits? */
dev->mode_config.fb_base = lower_32_bits(paddr);
- fbi->screen_base = msm_gem_vaddr_locked(fbdev->bo);
+ fbi->screen_base = msm_gem_vaddr(fbdev->bo);
fbi->screen_size = fbdev->bo->size;
fbi->fix.smem_start = lower_32_bits(paddr);
fbi->fix.smem_len = fbdev->bo->size;
diff --git a/drivers/gpu/drm/msm/msm_gem.c b/drivers/gpu/drm/msm/msm_gem.c
index 4bee797da746..6bb29c62378d 100644
--- a/drivers/gpu/drm/msm/msm_gem.c
+++ b/drivers/gpu/drm/msm/msm_gem.c
@@ -25,6 +25,129 @@
#include "msm_gpu.h"
#include "msm_mmu.h"
+static void msm_gem_mn_free(struct kref *refcount)
+{
+ struct msm_mmu_notifier *msm_mn = container_of(refcount,
+ struct msm_mmu_notifier, refcount);
+
+ mmu_notifier_unregister(&msm_mn->mn, msm_mn->mm);
+ hash_del(&msm_mn->node);
+
+ kfree(msm_mn);
+}
+
+static int msm_gem_mn_get(struct msm_mmu_notifier *msm_mn)
+{
+ if (msm_mn)
+ return kref_get_unless_zero(&msm_mn->refcount);
+ return 0;
+}
+
+static void msm_gem_mn_put(struct msm_mmu_notifier *msm_mn)
+{
+ if (msm_mn) {
+ struct msm_drm_private *msm_dev = msm_mn->msm_dev;
+
+ mutex_lock(&msm_dev->mn_lock);
+ kref_put(&msm_mn->refcount, msm_gem_mn_free);
+ mutex_unlock(&msm_dev->mn_lock);
+ }
+}
+
+void msm_mn_invalidate_range_start(struct mmu_notifier *mn,
+ struct mm_struct *mm, unsigned long start, unsigned long end);
+
+static const struct mmu_notifier_ops msm_mn_ops = {
+ .invalidate_range_start = msm_mn_invalidate_range_start,
+};
+
+static struct msm_mmu_notifier *
+msm_gem_mn_find(struct msm_drm_private *msm_dev, struct mm_struct *mm,
+ struct msm_gem_address_space *aspace)
+{
+ struct msm_mmu_notifier *msm_mn;
+ int ret = 0;
+
+ mutex_lock(&msm_dev->mn_lock);
+ hash_for_each_possible(msm_dev->mn_hash, msm_mn, node,
+ (unsigned long) mm) {
+ if (msm_mn->mm == mm) {
+ if (!msm_gem_mn_get(msm_mn)) {
+ ret = -EINVAL;
+ goto fail;
+ }
+ mutex_unlock(&msm_dev->mn_lock);
+ return msm_mn;
+ }
+ }
+
+ msm_mn = kzalloc(sizeof(*msm_mn), GFP_KERNEL);
+ if (!msm_mn) {
+ ret = -ENOMEM;
+ goto fail;
+ }
+
+ msm_mn->mm = current->mm;
+ msm_mn->mn.ops = &msm_mn_ops;
+ ret = mmu_notifier_register(&msm_mn->mn, msm_mn->mm);
+ if (ret) {
+ kfree(msm_mn);
+ goto fail;
+ }
+
+ msm_mn->svm_tree = RB_ROOT;
+ spin_lock_init(&msm_mn->svm_tree_lock);
+ kref_init(&msm_mn->refcount);
+ msm_mn->msm_dev = msm_dev;
+
+ /* Insert the msm_mn into the hash */
+ hash_add(msm_dev->mn_hash, &msm_mn->node, (unsigned long) msm_mn->mm);
+ mutex_unlock(&msm_dev->mn_lock);
+
+ return msm_mn;
+
+fail:
+ mutex_unlock(&msm_dev->mn_lock);
+ return ERR_PTR(ret);
+}
+
+static int msm_gem_mn_register(struct msm_gem_svm_object *msm_svm_obj,
+ struct msm_gem_address_space *aspace)
+{
+ struct drm_gem_object *obj = &msm_svm_obj->msm_obj_base.base;
+ struct msm_drm_private *msm_dev = obj->dev->dev_private;
+ struct msm_mmu_notifier *msm_mn;
+
+ msm_svm_obj->mm = current->mm;
+ msm_svm_obj->svm_node.start = msm_svm_obj->hostptr;
+ msm_svm_obj->svm_node.last = msm_svm_obj->hostptr + obj->size - 1;
+
+ msm_mn = msm_gem_mn_find(msm_dev, msm_svm_obj->mm, aspace);
+ if (IS_ERR(msm_mn))
+ return PTR_ERR(msm_mn);
+
+ msm_svm_obj->msm_mn = msm_mn;
+
+ spin_lock(&msm_mn->svm_tree_lock);
+ interval_tree_insert(&msm_svm_obj->svm_node, &msm_mn->svm_tree);
+ spin_unlock(&msm_mn->svm_tree_lock);
+
+ return 0;
+}
+
+static void msm_gem_mn_unregister(struct msm_gem_svm_object *msm_svm_obj)
+{
+ struct msm_mmu_notifier *msm_mn = msm_svm_obj->msm_mn;
+
+ /* invalid: bo already unregistered */
+ if (!msm_mn || msm_svm_obj->invalid)
+ return;
+
+ spin_lock(&msm_mn->svm_tree_lock);
+ interval_tree_remove(&msm_svm_obj->svm_node, &msm_mn->svm_tree);
+ spin_unlock(&msm_mn->svm_tree_lock);
+}
+
static int protect_pages(struct msm_gem_object *msm_obj)
{
int perm = PERM_READ | PERM_WRITE;
@@ -63,8 +186,7 @@ static bool use_pages(struct drm_gem_object *obj)
}
/* allocate pages from VRAM carveout, used when no IOMMU: */
-static struct page **get_pages_vram(struct drm_gem_object *obj,
- int npages)
+static struct page **get_pages_vram(struct drm_gem_object *obj, int npages)
{
struct msm_gem_object *msm_obj = to_msm_bo(obj);
struct msm_drm_private *priv = obj->dev->dev_private;
@@ -76,8 +198,10 @@ static struct page **get_pages_vram(struct drm_gem_object *obj,
if (!p)
return ERR_PTR(-ENOMEM);
+ spin_lock(&priv->vram.lock);
ret = drm_mm_insert_node(&priv->vram.mm, msm_obj->vram_node,
npages, 0, DRM_MM_SEARCH_DEFAULT);
+ spin_unlock(&priv->vram.lock);
if (ret) {
drm_free_large(p);
return ERR_PTR(ret);
@@ -92,7 +216,6 @@ static struct page **get_pages_vram(struct drm_gem_object *obj,
return p;
}
-/* called with dev->struct_mutex held */
static struct page **get_pages(struct drm_gem_object *obj)
{
struct msm_gem_object *msm_obj = to_msm_bo(obj);
@@ -113,13 +236,15 @@ static struct page **get_pages(struct drm_gem_object *obj)
return p;
}
+ msm_obj->pages = p;
+
msm_obj->sgt = drm_prime_pages_to_sg(p, npages);
if (IS_ERR(msm_obj->sgt)) {
- dev_err(dev->dev, "failed to allocate sgt\n");
- return ERR_CAST(msm_obj->sgt);
- }
+ void *ptr = ERR_CAST(msm_obj->sgt);
- msm_obj->pages = p;
+ msm_obj->sgt = NULL;
+ return ptr;
+ }
/*
* Make sure to flush the CPU cache for newly allocated memory
@@ -147,6 +272,18 @@ static struct page **get_pages(struct drm_gem_object *obj)
return msm_obj->pages;
}
+static void put_pages_vram(struct drm_gem_object *obj)
+{
+ struct msm_gem_object *msm_obj = to_msm_bo(obj);
+ struct msm_drm_private *priv = obj->dev->dev_private;
+
+ spin_lock(&priv->vram.lock);
+ drm_mm_remove_node(msm_obj->vram_node);
+ spin_unlock(&priv->vram.lock);
+
+ drm_free_large(msm_obj->pages);
+}
+
static void put_pages(struct drm_gem_object *obj)
{
struct msm_gem_object *msm_obj = to_msm_bo(obj);
@@ -157,14 +294,22 @@ static void put_pages(struct drm_gem_object *obj)
msm_obj->flags &= ~MSM_BO_LOCKED;
}
- sg_free_table(msm_obj->sgt);
+ if (msm_obj->sgt)
+ sg_free_table(msm_obj->sgt);
kfree(msm_obj->sgt);
if (use_pages(obj)) {
- drm_gem_put_pages(obj, msm_obj->pages, true, false);
+ if (msm_obj->flags & MSM_BO_SVM) {
+ int npages = obj->size >> PAGE_SHIFT;
+
+ release_pages(msm_obj->pages, npages, 0);
+ kfree(msm_obj->pages);
+ } else {
+ drm_gem_put_pages(obj, msm_obj->pages,
+ true, false);
+ }
} else {
- drm_mm_remove_node(msm_obj->vram_node);
- drm_free_large(msm_obj->pages);
+ put_pages_vram(obj);
}
msm_obj->pages = NULL;
@@ -173,11 +318,12 @@ static void put_pages(struct drm_gem_object *obj)
struct page **msm_gem_get_pages(struct drm_gem_object *obj)
{
- struct drm_device *dev = obj->dev;
+ struct msm_gem_object *msm_obj = to_msm_bo(obj);
struct page **p;
- mutex_lock(&dev->struct_mutex);
+
+ mutex_lock(&msm_obj->lock);
p = get_pages(obj);
- mutex_unlock(&dev->struct_mutex);
+ mutex_unlock(&msm_obj->lock);
return p;
}
@@ -191,8 +337,8 @@ int msm_gem_mmap_obj(struct drm_gem_object *obj,
{
struct msm_gem_object *msm_obj = to_msm_bo(obj);
- /* We can't mmap secure objects */
- if (msm_obj->flags & MSM_BO_SECURE) {
+ /* We can't mmap secure objects or SVM objects */
+ if (msm_obj->flags & (MSM_BO_SECURE | MSM_BO_SVM)) {
drm_gem_vm_close(vma);
return -EACCES;
}
@@ -237,16 +383,17 @@ int msm_gem_mmap(struct file *filp, struct vm_area_struct *vma)
int msm_gem_fault(struct vm_area_struct *vma, struct vm_fault *vmf)
{
struct drm_gem_object *obj = vma->vm_private_data;
- struct drm_device *dev = obj->dev;
+ struct msm_gem_object *msm_obj = to_msm_bo(obj);
struct page **pages;
unsigned long pfn;
pgoff_t pgoff;
int ret;
- /* Make sure we don't parallel update on a fault, nor move or remove
- * something from beneath our feet
+ /*
+ * vm_ops.open and close get and put a reference on obj.
+ * So, we dont need to hold one here.
*/
- ret = mutex_lock_interruptible(&dev->struct_mutex);
+ ret = mutex_lock_interruptible(&msm_obj->lock);
if (ret)
goto out;
@@ -269,7 +416,7 @@ int msm_gem_fault(struct vm_area_struct *vma, struct vm_fault *vmf)
ret = vm_insert_mixed(vma, (unsigned long)vmf->virtual_address, pfn);
out_unlock:
- mutex_unlock(&dev->struct_mutex);
+ mutex_unlock(&msm_obj->lock);
out:
switch (ret) {
case -EAGAIN:
@@ -293,9 +440,10 @@ out:
static uint64_t mmap_offset(struct drm_gem_object *obj)
{
struct drm_device *dev = obj->dev;
+ struct msm_gem_object *msm_obj = to_msm_bo(obj);
int ret;
- WARN_ON(!mutex_is_locked(&dev->struct_mutex));
+ WARN_ON(!mutex_is_locked(&msm_obj->lock));
/* Make it mmapable */
ret = drm_gem_create_mmap_offset(obj);
@@ -311,9 +459,11 @@ static uint64_t mmap_offset(struct drm_gem_object *obj)
uint64_t msm_gem_mmap_offset(struct drm_gem_object *obj)
{
uint64_t offset;
- mutex_lock(&obj->dev->struct_mutex);
+ struct msm_gem_object *msm_obj = to_msm_bo(obj);
+
+ mutex_lock(&msm_obj->lock);
offset = mmap_offset(obj);
- mutex_unlock(&obj->dev->struct_mutex);
+ mutex_unlock(&msm_obj->lock);
return offset;
}
@@ -325,19 +475,26 @@ static void obj_remove_domain(struct msm_gem_vma *domain)
}
}
+/* Called with msm_obj->lock locked */
static void
put_iova(struct drm_gem_object *obj)
{
- struct drm_device *dev = obj->dev;
struct msm_gem_object *msm_obj = to_msm_bo(obj);
+ struct msm_gem_svm_object *msm_svm_obj;
struct msm_gem_vma *domain, *tmp;
+ bool invalid = false;
- WARN_ON(!mutex_is_locked(&dev->struct_mutex));
+ WARN_ON(!mutex_is_locked(&msm_obj->lock));
+
+ if (msm_obj->flags & MSM_BO_SVM) {
+ msm_svm_obj = to_msm_svm_obj(msm_obj);
+ invalid = msm_svm_obj->invalid;
+ }
list_for_each_entry_safe(domain, tmp, &msm_obj->domains, list) {
if (iommu_present(&platform_bus_type)) {
msm_gem_unmap_vma(domain->aspace, domain,
- msm_obj->sgt, get_dmabuf_ptr(obj));
+ msm_obj->sgt, get_dmabuf_ptr(obj), invalid);
}
obj_remove_domain(domain);
@@ -378,14 +535,8 @@ static struct msm_gem_vma *obj_get_domain(struct drm_gem_object *obj,
#define IOMMU_PRIV 0
#endif
-/* should be called under struct_mutex.. although it can be called
- * from atomic context without struct_mutex to acquire an extra
- * iova ref if you know one is already held.
- *
- * That means when I do eventually need to add support for unpinning
- * the refcnt counter needs to be atomic_t.
- */
-int msm_gem_get_iova_locked(struct drm_gem_object *obj,
+/* A reference to obj must be held before calling this function. */
+int msm_gem_get_iova(struct drm_gem_object *obj,
struct msm_gem_address_space *aspace, uint64_t *iova)
{
struct msm_gem_object *msm_obj = to_msm_bo(obj);
@@ -393,13 +544,18 @@ int msm_gem_get_iova_locked(struct drm_gem_object *obj,
struct msm_gem_vma *domain;
int ret = 0;
+ mutex_lock(&msm_obj->lock);
+
if (!iommu_present(&platform_bus_type)) {
pages = get_pages(obj);
- if (IS_ERR(pages))
+ if (IS_ERR(pages)) {
+ mutex_unlock(&msm_obj->lock);
return PTR_ERR(pages);
+ }
*iova = (uint64_t) physaddr(obj);
+ mutex_unlock(&msm_obj->lock);
return 0;
}
@@ -407,12 +563,15 @@ int msm_gem_get_iova_locked(struct drm_gem_object *obj,
if (!domain) {
domain = obj_add_domain(obj, aspace);
- if (IS_ERR(domain))
+ if (IS_ERR(domain)) {
+ mutex_unlock(&msm_obj->lock);
return PTR_ERR(domain);
+ }
pages = get_pages(obj);
if (IS_ERR(pages)) {
obj_remove_domain(domain);
+ mutex_unlock(&msm_obj->lock);
return PTR_ERR(pages);
}
@@ -425,26 +584,8 @@ int msm_gem_get_iova_locked(struct drm_gem_object *obj,
else
obj_remove_domain(domain);
- return ret;
-}
-
-/* get iova, taking a reference. Should have a matching put */
-int msm_gem_get_iova(struct drm_gem_object *obj,
- struct msm_gem_address_space *aspace, uint64_t *iova)
-{
- struct msm_gem_vma *domain;
- int ret;
-
- domain = obj_get_domain(obj, aspace);
- if (domain) {
- *iova = domain->iova;
- return 0;
- }
-
- mutex_lock(&obj->dev->struct_mutex);
- ret = msm_gem_get_iova_locked(obj, aspace, iova);
- mutex_unlock(&obj->dev->struct_mutex);
- return ret;
+ mutex_unlock(&msm_obj->lock);
+ return 0;
}
/* get iova without taking a reference, used in places where you have
@@ -453,11 +594,17 @@ int msm_gem_get_iova(struct drm_gem_object *obj,
uint64_t msm_gem_iova(struct drm_gem_object *obj,
struct msm_gem_address_space *aspace)
{
- struct msm_gem_vma *domain = obj_get_domain(obj, aspace);
+ struct msm_gem_object *msm_obj = to_msm_bo(obj);
+ struct msm_gem_vma *domain;
+ uint64_t iova;
+ mutex_lock(&msm_obj->lock);
+ domain = obj_get_domain(obj, aspace);
WARN_ON(!domain);
+ iova = domain ? domain->iova : 0;
+ mutex_unlock(&msm_obj->lock);
- return domain ? domain->iova : 0;
+ return iova;
}
void msm_gem_put_iova(struct drm_gem_object *obj,
@@ -501,27 +648,23 @@ fail:
return ret;
}
-void *msm_gem_vaddr_locked(struct drm_gem_object *obj)
+void *msm_gem_vaddr(struct drm_gem_object *obj)
{
struct msm_gem_object *msm_obj = to_msm_bo(obj);
- WARN_ON(!mutex_is_locked(&obj->dev->struct_mutex));
+
+ mutex_lock(&msm_obj->lock);
if (!msm_obj->vaddr) {
struct page **pages = get_pages(obj);
- if (IS_ERR(pages))
+ if (IS_ERR(pages)) {
+ mutex_unlock(&msm_obj->lock);
return ERR_CAST(pages);
+ }
msm_obj->vaddr = vmap(pages, obj->size >> PAGE_SHIFT,
VM_MAP, pgprot_writecombine(PAGE_KERNEL));
}
- return msm_obj->vaddr;
-}
+ mutex_unlock(&msm_obj->lock);
-void *msm_gem_vaddr(struct drm_gem_object *obj)
-{
- void *ret;
- mutex_lock(&obj->dev->struct_mutex);
- ret = msm_gem_vaddr_locked(obj);
- mutex_unlock(&obj->dev->struct_mutex);
- return ret;
+ return msm_obj->vaddr;
}
/* setup callback for when bo is no longer busy..
@@ -654,21 +797,32 @@ void msm_gem_free_object(struct drm_gem_object *obj)
{
struct drm_device *dev = obj->dev;
struct msm_gem_object *msm_obj = to_msm_bo(obj);
+ struct msm_gem_svm_object *msm_svm_obj = NULL;
WARN_ON(!mutex_is_locked(&dev->struct_mutex));
/* object should not be on active list: */
WARN_ON(is_active(msm_obj));
+ if (msm_obj->flags & MSM_BO_SVM)
+ msm_svm_obj = to_msm_svm_obj(msm_obj);
+
list_del(&msm_obj->mm_list);
+ /* Unregister SVM object from mmu notifications */
+ if (msm_obj->flags & MSM_BO_SVM) {
+ msm_gem_mn_unregister(msm_svm_obj);
+ msm_gem_mn_put(msm_svm_obj->msm_mn);
+ msm_svm_obj->msm_mn = NULL;
+ }
+
+ mutex_lock(&msm_obj->lock);
put_iova(obj);
if (obj->import_attach) {
if (msm_obj->vaddr)
dma_buf_vunmap(obj->import_attach->dmabuf,
msm_obj->vaddr);
-
/* Don't drop the pages for imported dmabuf, as they are not
* ours, just free the array we allocated:
*/
@@ -685,8 +839,12 @@ void msm_gem_free_object(struct drm_gem_object *obj)
reservation_object_fini(msm_obj->resv);
drm_gem_object_release(obj);
+ mutex_unlock(&msm_obj->lock);
- kfree(msm_obj);
+ if (msm_obj->flags & MSM_BO_SVM)
+ kfree(msm_svm_obj);
+ else
+ kfree(msm_obj);
}
/* convenience method to construct a GEM buffer object, and userspace handle */
@@ -696,13 +854,28 @@ int msm_gem_new_handle(struct drm_device *dev, struct drm_file *file,
struct drm_gem_object *obj;
int ret;
- ret = mutex_lock_interruptible(&dev->struct_mutex);
- if (ret)
- return ret;
-
obj = msm_gem_new(dev, size, flags);
- mutex_unlock(&dev->struct_mutex);
+ if (IS_ERR(obj))
+ return PTR_ERR(obj);
+
+ ret = drm_gem_handle_create(file, obj, handle);
+
+ /* drop reference from allocate - handle holds it now */
+ drm_gem_object_unreference_unlocked(obj);
+
+ return ret;
+}
+
+/* convenience method to construct an SVM buffer object, and userspace handle */
+int msm_gem_svm_new_handle(struct drm_device *dev, struct drm_file *file,
+ uint64_t hostptr, uint64_t size,
+ uint32_t flags, uint32_t *handle)
+{
+ struct drm_gem_object *obj;
+ int ret;
+
+ obj = msm_gem_svm_new(dev, file, hostptr, size, flags);
if (IS_ERR(obj))
return PTR_ERR(obj);
@@ -715,12 +888,11 @@ int msm_gem_new_handle(struct drm_device *dev, struct drm_file *file,
return ret;
}
-static int msm_gem_new_impl(struct drm_device *dev,
+static int msm_gem_obj_init(struct drm_device *dev,
uint32_t size, uint32_t flags,
- struct drm_gem_object **obj)
+ struct msm_gem_object *msm_obj, bool struct_mutex_locked)
{
struct msm_drm_private *priv = dev->dev_private;
- struct msm_gem_object *msm_obj;
bool use_vram = false;
switch (flags & MSM_BO_CACHE_MASK) {
@@ -742,9 +914,7 @@ static int msm_gem_new_impl(struct drm_device *dev,
if (WARN_ON(use_vram && !priv->vram.size))
return -EINVAL;
- msm_obj = kzalloc(sizeof(*msm_obj), GFP_KERNEL);
- if (!msm_obj)
- return -ENOMEM;
+ mutex_init(&msm_obj->lock);
if (use_vram) {
struct msm_gem_vma *domain = obj_add_domain(&msm_obj->base, 0);
@@ -758,23 +928,45 @@ static int msm_gem_new_impl(struct drm_device *dev,
msm_obj->resv = &msm_obj->_resv;
reservation_object_init(msm_obj->resv);
+ INIT_LIST_HEAD(&msm_obj->mm_list);
INIT_LIST_HEAD(&msm_obj->submit_entry);
INIT_LIST_HEAD(&msm_obj->domains);
- list_add_tail(&msm_obj->mm_list, &priv->inactive_list);
-
- *obj = &msm_obj->base;
+ if (struct_mutex_locked) {
+ list_add_tail(&msm_obj->mm_list, &priv->inactive_list);
+ } else {
+ mutex_lock(&dev->struct_mutex);
+ list_add_tail(&msm_obj->mm_list, &priv->inactive_list);
+ mutex_unlock(&dev->struct_mutex);
+ }
return 0;
}
-struct drm_gem_object *msm_gem_new(struct drm_device *dev,
- uint32_t size, uint32_t flags)
+static struct drm_gem_object *msm_gem_new_impl(struct drm_device *dev,
+ uint32_t size, uint32_t flags, bool struct_mutex_locked)
{
- struct drm_gem_object *obj = NULL;
+ struct msm_gem_object *msm_obj;
int ret;
- WARN_ON(!mutex_is_locked(&dev->struct_mutex));
+ msm_obj = kzalloc(sizeof(*msm_obj), GFP_KERNEL);
+ if (!msm_obj)
+ return ERR_PTR(-ENOMEM);
+
+ ret = msm_gem_obj_init(dev, size, flags, msm_obj, struct_mutex_locked);
+ if (ret) {
+ kfree(msm_obj);
+ return ERR_PTR(ret);
+ }
+
+ return &msm_obj->base;
+}
+
+static struct drm_gem_object *_msm_gem_new(struct drm_device *dev,
+ uint32_t size, uint32_t flags, bool struct_mutex_locked)
+{
+ struct drm_gem_object *obj;
+ int ret;
size = PAGE_ALIGN(size);
@@ -785,9 +977,9 @@ struct drm_gem_object *msm_gem_new(struct drm_device *dev,
if (!size)
return ERR_PTR(-EINVAL);
- ret = msm_gem_new_impl(dev, size, flags, &obj);
- if (ret)
- goto fail;
+ obj = msm_gem_new_impl(dev, size, flags, struct_mutex_locked);
+ if (IS_ERR(obj))
+ return obj;
if (use_pages(obj)) {
ret = drm_gem_object_init(dev, obj, size);
@@ -800,8 +992,156 @@ struct drm_gem_object *msm_gem_new(struct drm_device *dev,
return obj;
fail:
- if (obj)
- drm_gem_object_unreference(obj);
+ drm_gem_object_unreference_unlocked(obj);
+
+ return ERR_PTR(ret);
+}
+
+struct drm_gem_object *msm_gem_new_locked(struct drm_device *dev,
+ uint32_t size, uint32_t flags)
+{
+ return _msm_gem_new(dev, size, flags, true);
+}
+
+struct drm_gem_object *msm_gem_new(struct drm_device *dev,
+ uint32_t size, uint32_t flags)
+{
+ return _msm_gem_new(dev, size, flags, false);
+}
+
+static struct drm_gem_object *msm_svm_gem_new_impl(struct drm_device *dev,
+ uint32_t size, uint32_t flags)
+{
+ struct msm_gem_svm_object *msm_svm_obj;
+ struct msm_gem_object *msm_obj;
+ int ret;
+
+ msm_svm_obj = kzalloc(sizeof(*msm_svm_obj), GFP_KERNEL);
+ if (!msm_svm_obj)
+ return ERR_PTR(-ENOMEM);
+
+ msm_obj = &msm_svm_obj->msm_obj_base;
+
+ ret = msm_gem_obj_init(dev, size, flags | MSM_BO_SVM, msm_obj, false);
+ if (ret) {
+ kfree(msm_svm_obj);
+ return ERR_PTR(ret);
+ }
+
+ return &msm_obj->base;
+}
+
+/* convenience method to construct an SVM GEM bo, and userspace handle */
+struct drm_gem_object *msm_gem_svm_new(struct drm_device *dev,
+ struct drm_file *file, uint64_t hostptr,
+ uint64_t size, uint32_t flags)
+{
+ struct drm_gem_object *obj;
+ struct msm_file_private *ctx = file->driver_priv;
+ struct msm_gem_address_space *aspace = ctx->aspace;
+ struct msm_gem_object *msm_obj;
+ struct msm_gem_svm_object *msm_svm_obj;
+ struct msm_gem_vma *domain = NULL;
+ struct page **p;
+ int npages;
+ int num_pinned = 0;
+ int write;
+ int ret;
+
+ /* if we don't have IOMMU, don't bother pretending we can import: */
+ if (!iommu_present(&platform_bus_type)) {
+ dev_err_once(dev->dev, "cannot import without IOMMU\n");
+ return ERR_PTR(-EINVAL);
+ }
+
+ /* hostptr and size must be page-aligned */
+ if (offset_in_page(hostptr | size))
+ return ERR_PTR(-EINVAL);
+
+ /* Only CPU cached SVM objects are allowed */
+ if ((flags & MSM_BO_CACHE_MASK) != MSM_BO_CACHED)
+ return ERR_PTR(-EINVAL);
+
+ /* Allocate and initialize a new msm_gem_object */
+ obj = msm_svm_gem_new_impl(dev, size, flags);
+ if (IS_ERR(obj))
+ return obj;
+
+ drm_gem_private_object_init(dev, obj, size);
+
+ msm_obj = to_msm_bo(obj);
+ domain = obj_add_domain(&msm_obj->base, aspace);
+ if (IS_ERR(domain)) {
+ drm_gem_object_unreference_unlocked(obj);
+ return ERR_CAST(domain);
+ }
+
+ /* Reserve iova if not already in use, else fail */
+ ret = msm_gem_reserve_iova(aspace, domain, hostptr, size);
+ if (ret) {
+ obj_remove_domain(domain);
+ drm_gem_object_unreference_unlocked(obj);
+ return ERR_PTR(ret);
+ }
+
+ msm_svm_obj = to_msm_svm_obj(msm_obj);
+ msm_svm_obj->hostptr = hostptr;
+ msm_svm_obj->invalid = false;
+
+ ret = msm_gem_mn_register(msm_svm_obj, aspace);
+ if (ret)
+ goto fail;
+
+ /*
+ * Get physical pages and map into smmu in the ioctl itself.
+ * The driver handles iova allocation, physical page allocation and
+ * SMMU map all in one go. If we break this, then we have to maintain
+ * state to tell if physical pages allocation/map needs to happen.
+ * For SVM, iova reservation needs to happen in the ioctl itself,
+ * so do the rest right here as well.
+ */
+ npages = size >> PAGE_SHIFT;
+ p = kcalloc(npages, sizeof(struct page *), GFP_KERNEL);
+ if (!p) {
+ ret = -ENOMEM;
+ goto fail;
+ }
+
+ write = (msm_obj->flags & MSM_BO_GPU_READONLY) ? 0 : 1;
+ /* This may hold mm->mmap_sem */
+ num_pinned = get_user_pages_fast(hostptr, npages, write, p);
+ if (num_pinned != npages) {
+ ret = -EINVAL;
+ goto free_pages;
+ }
+
+ msm_obj->sgt = drm_prime_pages_to_sg(p, npages);
+ if (IS_ERR(msm_obj->sgt)) {
+ ret = PTR_ERR(msm_obj->sgt);
+ goto free_pages;
+ }
+
+ msm_obj->pages = p;
+
+ ret = aspace->mmu->funcs->map(aspace->mmu, domain->iova,
+ msm_obj->sgt, msm_obj->flags, get_dmabuf_ptr(obj));
+ if (ret)
+ goto free_pages;
+
+ kref_get(&aspace->kref);
+
+ return obj;
+
+free_pages:
+ release_pages(p, num_pinned, 0);
+ kfree(p);
+
+fail:
+ if (domain)
+ msm_gem_release_iova(aspace, domain);
+
+ obj_remove_domain(domain);
+ drm_gem_object_unreference_unlocked(obj);
return ERR_PTR(ret);
}
@@ -821,21 +1161,20 @@ struct drm_gem_object *msm_gem_import(struct drm_device *dev,
size = PAGE_ALIGN(size);
- mutex_lock(&dev->struct_mutex);
- ret = msm_gem_new_impl(dev, size, MSM_BO_WC, &obj);
- mutex_unlock(&dev->struct_mutex);
-
- if (ret)
- goto fail;
+ obj = msm_gem_new_impl(dev, size, MSM_BO_WC, false);
+ if (IS_ERR(obj))
+ return obj;
drm_gem_private_object_init(dev, obj, size);
npages = size / PAGE_SIZE;
msm_obj = to_msm_bo(obj);
+ mutex_lock(&msm_obj->lock);
msm_obj->sgt = sgt;
msm_obj->pages = drm_malloc_ab(npages, sizeof(struct page *));
if (!msm_obj->pages) {
+ mutex_unlock(&msm_obj->lock);
ret = -ENOMEM;
goto fail;
}
@@ -843,15 +1182,98 @@ struct drm_gem_object *msm_gem_import(struct drm_device *dev,
/* OR the passed in flags */
msm_obj->flags |= flags;
- ret = drm_prime_sg_to_page_addr_arrays(sgt, msm_obj->pages, NULL, npages);
- if (ret)
+ ret = drm_prime_sg_to_page_addr_arrays(sgt, msm_obj->pages,
+ NULL, npages);
+ if (ret) {
+ mutex_unlock(&msm_obj->lock);
goto fail;
+ }
+
+ mutex_unlock(&msm_obj->lock);
return obj;
fail:
- if (obj)
- drm_gem_object_unreference_unlocked(obj);
+ drm_gem_object_unreference_unlocked(obj);
return ERR_PTR(ret);
}
+
+/* Timeout in ms, long enough so we are sure the GPU is hung */
+#define SVM_OBJ_WAIT_TIMEOUT 10000
+static void invalidate_svm_object(struct msm_gem_svm_object *msm_svm_obj)
+{
+ struct msm_gem_object *msm_obj = &msm_svm_obj->msm_obj_base;
+ struct drm_device *dev = msm_obj->base.dev;
+ struct msm_gem_vma *domain, *tmp;
+ uint32_t fence;
+ int ret;
+
+ if (is_active(msm_obj)) {
+ ktime_t timeout = ktime_add_ms(ktime_get(),
+ SVM_OBJ_WAIT_TIMEOUT);
+
+ /* Get the most recent fence that touches the object */
+ fence = msm_gem_fence(msm_obj, MSM_PREP_READ | MSM_PREP_WRITE);
+
+ /* Wait for the fence to retire */
+ ret = msm_wait_fence(dev, fence, &timeout, true);
+ if (ret)
+ /* The GPU could be hung! Not much we can do */
+ dev_err(dev->dev, "drm: Error (%d) waiting for svm object: 0x%llx",
+ ret, msm_svm_obj->hostptr);
+ }
+
+ /* GPU is done, unmap object from SMMU */
+ mutex_lock(&msm_obj->lock);
+ list_for_each_entry_safe(domain, tmp, &msm_obj->domains, list) {
+ struct msm_gem_address_space *aspace = domain->aspace;
+
+ if (domain->iova)
+ aspace->mmu->funcs->unmap(aspace->mmu,
+ domain->iova, msm_obj->sgt,
+ get_dmabuf_ptr(&msm_obj->base));
+ }
+ /* Let go of the physical pages */
+ put_pages(&msm_obj->base);
+ mutex_unlock(&msm_obj->lock);
+}
+
+void msm_mn_invalidate_range_start(struct mmu_notifier *mn,
+ struct mm_struct *mm, unsigned long start, unsigned long end)
+{
+ struct msm_mmu_notifier *msm_mn =
+ container_of(mn, struct msm_mmu_notifier, mn);
+ struct interval_tree_node *itn = NULL;
+ struct msm_gem_svm_object *msm_svm_obj;
+ struct drm_gem_object *obj;
+ LIST_HEAD(inv_list);
+
+ if (!msm_gem_mn_get(msm_mn))
+ return;
+
+ spin_lock(&msm_mn->svm_tree_lock);
+ itn = interval_tree_iter_first(&msm_mn->svm_tree, start, end - 1);
+ while (itn) {
+ msm_svm_obj = container_of(itn,
+ struct msm_gem_svm_object, svm_node);
+ obj = &msm_svm_obj->msm_obj_base.base;
+
+ if (kref_get_unless_zero(&obj->refcount))
+ list_add(&msm_svm_obj->lnode, &inv_list);
+
+ itn = interval_tree_iter_next(itn, start, end - 1);
+ }
+ spin_unlock(&msm_mn->svm_tree_lock);
+
+ list_for_each_entry(msm_svm_obj, &inv_list, lnode) {
+ obj = &msm_svm_obj->msm_obj_base.base;
+ /* Unregister SVM object from mmu notifications */
+ msm_gem_mn_unregister(msm_svm_obj);
+ msm_svm_obj->invalid = true;
+ invalidate_svm_object(msm_svm_obj);
+ drm_gem_object_unreference_unlocked(obj);
+ }
+
+ msm_gem_mn_put(msm_mn);
+}
diff --git a/drivers/gpu/drm/msm/msm_gem.h b/drivers/gpu/drm/msm/msm_gem.h
index 41b4b5a4fd66..04e6c658b5f3 100644
--- a/drivers/gpu/drm/msm/msm_gem.h
+++ b/drivers/gpu/drm/msm/msm_gem.h
@@ -20,17 +20,21 @@
#include <linux/kref.h>
#include <linux/reservation.h>
+#include <linux/mmu_notifier.h>
+#include <linux/interval_tree.h>
#include "msm_drv.h"
/* Additional internal-use only BO flags: */
#define MSM_BO_STOLEN 0x10000000 /* try to use stolen/splash memory */
#define MSM_BO_LOCKED 0x20000000 /* Pages have been securely locked */
+#define MSM_BO_SVM 0x40000000 /* bo is SVM */
struct msm_gem_address_space {
const char *name;
struct msm_mmu *mmu;
struct kref kref;
struct drm_mm mm;
+ spinlock_t lock; /* Protects drm_mm node allocation/removal */
u64 va_len;
};
@@ -80,9 +84,36 @@ struct msm_gem_object {
* an IOMMU. Also used for stolen/splashscreen buffer.
*/
struct drm_mm_node *vram_node;
+ struct mutex lock; /* Protects resources associated with bo */
};
#define to_msm_bo(x) container_of(x, struct msm_gem_object, base)
+struct msm_mmu_notifier {
+ struct mmu_notifier mn;
+ struct mm_struct *mm; /* mm_struct owning the mmu notifier mn */
+ struct hlist_node node;
+ struct rb_root svm_tree; /* interval tree holding all svm bos */
+ spinlock_t svm_tree_lock; /* Protects svm_tree*/
+ struct msm_drm_private *msm_dev;
+ struct kref refcount;
+};
+
+struct msm_gem_svm_object {
+ struct msm_gem_object msm_obj_base;
+ uint64_t hostptr;
+ struct mm_struct *mm; /* mm_struct the svm bo belongs to */
+ struct interval_tree_node svm_node;
+ struct msm_mmu_notifier *msm_mn;
+ struct list_head lnode;
+ /* bo has been unmapped on CPU, cannot be part of GPU submits */
+ bool invalid;
+};
+
+#define to_msm_svm_obj(x) \
+ ((struct msm_gem_svm_object *) \
+ container_of(x, struct msm_gem_svm_object, msm_obj_base))
+
+
static inline bool is_active(struct msm_gem_object *msm_obj)
{
return msm_obj->gpu != NULL;
diff --git a/drivers/gpu/drm/msm/msm_gem_submit.c b/drivers/gpu/drm/msm/msm_gem_submit.c
index 12cc28acec18..c861bfd77537 100644
--- a/drivers/gpu/drm/msm/msm_gem_submit.c
+++ b/drivers/gpu/drm/msm/msm_gem_submit.c
@@ -34,11 +34,15 @@ static inline void __user *to_user_ptr(u64 address)
}
static struct msm_gem_submit *submit_create(struct drm_device *dev,
- struct msm_gem_address_space *aspace, int nr_bos, int nr_cmds)
+ struct msm_gem_address_space *aspace,
+ uint32_t nr_bos, uint32_t nr_cmds)
{
struct msm_gem_submit *submit;
- int sz = sizeof(*submit) + (nr_bos * sizeof(submit->bos[0])) +
- (nr_cmds * sizeof(*submit->cmd));
+ uint64_t sz = sizeof(*submit) + (nr_bos * sizeof(submit->bos[0])) +
+ (nr_cmds * sizeof(submit->cmd[0]));
+
+ if (sz > SIZE_MAX)
+ return NULL;
submit = kmalloc(sz, GFP_TEMPORARY | __GFP_NOWARN | __GFP_NORETRY);
if (submit) {
@@ -213,9 +217,21 @@ retry:
submit->bos[i].flags |= BO_LOCKED;
}
+ /*
+ * An invalid SVM object is part of
+ * this submit's buffer list, fail.
+ */
+ if (msm_obj->flags & MSM_BO_SVM) {
+ struct msm_gem_svm_object *msm_svm_obj =
+ to_msm_svm_obj(msm_obj);
+ if (msm_svm_obj->invalid) {
+ ret = -EINVAL;
+ goto fail;
+ }
+ }
/* if locking succeeded, pin bo: */
- ret = msm_gem_get_iova_locked(&msm_obj->base, aspace, &iova);
+ ret = msm_gem_get_iova(&msm_obj->base, aspace, &iova);
/* this would break the logic in the fail path.. there is no
* reason for this to happen, but just to be on the safe side
@@ -303,7 +319,7 @@ static int submit_reloc(struct msm_gem_submit *submit, struct msm_gem_object *ob
/* For now, just map the entire thing. Eventually we probably
* to do it page-by-page, w/ kmap() if not vmap()d..
*/
- ptr = msm_gem_vaddr_locked(&obj->base);
+ ptr = msm_gem_vaddr(&obj->base);
if (IS_ERR(ptr)) {
ret = PTR_ERR(ptr);
@@ -466,7 +482,7 @@ int msm_ioctl_gem_submit(struct drm_device *dev, void *data,
if (submit_cmd.type == MSM_SUBMIT_CMD_PROFILE_BUF) {
submit->profile_buf_iova = submit->cmd[i].iova;
submit->profile_buf_vaddr =
- msm_gem_vaddr_locked(&msm_obj->base);
+ msm_gem_vaddr(&msm_obj->base);
}
if (submit->valid)
diff --git a/drivers/gpu/drm/msm/msm_gem_vma.c b/drivers/gpu/drm/msm/msm_gem_vma.c
index 47f7436854fb..f399d24019e4 100644
--- a/drivers/gpu/drm/msm/msm_gem_vma.c
+++ b/drivers/gpu/drm/msm/msm_gem_vma.c
@@ -52,6 +52,7 @@ msm_gem_address_space_new(struct msm_mmu *mmu, const char *name,
if (!aspace)
return ERR_PTR(-ENOMEM);
+ spin_lock_init(&aspace->lock);
aspace->name = name;
aspace->mmu = mmu;
@@ -77,14 +78,19 @@ static int allocate_iova(struct msm_gem_address_space *aspace,
if (!aspace->va_len)
return 0;
- if (WARN_ON(drm_mm_node_allocated(&vma->node)))
- return 0;
-
for_each_sg(sgt->sgl, sg, sgt->nents, i)
size += sg->length + sg->offset;
- ret = drm_mm_insert_node(&aspace->mm, &vma->node, size >> PAGE_SHIFT,
- 0, DRM_MM_SEARCH_DEFAULT);
+ spin_lock(&aspace->lock);
+
+ if (WARN_ON(drm_mm_node_allocated(&vma->node))) {
+ spin_unlock(&aspace->lock);
+ return 0;
+ }
+ ret = drm_mm_insert_node(&aspace->mm, &vma->node,
+ size >> PAGE_SHIFT, 0, DRM_MM_SEARCH_BOTTOM_UP);
+
+ spin_unlock(&aspace->lock);
if (!ret && iova)
*iova = vma->node.start << PAGE_SHIFT;
@@ -92,6 +98,45 @@ static int allocate_iova(struct msm_gem_address_space *aspace,
return ret;
}
+int msm_gem_reserve_iova(struct msm_gem_address_space *aspace,
+ struct msm_gem_vma *vma,
+ uint64_t hostptr, uint64_t size)
+{
+ struct drm_mm *mm = &aspace->mm;
+ uint64_t start = hostptr >> PAGE_SHIFT;
+ uint64_t last = (hostptr + size - 1) >> PAGE_SHIFT;
+ int ret;
+
+ spin_lock(&aspace->lock);
+
+ if (drm_mm_interval_first(mm, start, last)) {
+ /* iova already in use, fail */
+ spin_unlock(&aspace->lock);
+ return -EADDRINUSE;
+ }
+
+ vma->node.start = hostptr >> PAGE_SHIFT;
+ vma->node.size = size >> PAGE_SHIFT;
+ vma->node.color = 0;
+
+ ret = drm_mm_reserve_node(mm, &vma->node);
+ if (!ret)
+ vma->iova = hostptr;
+
+ spin_unlock(&aspace->lock);
+
+ return ret;
+}
+
+void msm_gem_release_iova(struct msm_gem_address_space *aspace,
+ struct msm_gem_vma *vma)
+{
+ spin_lock(&aspace->lock);
+ if (drm_mm_node_allocated(&vma->node))
+ drm_mm_remove_node(&vma->node);
+ spin_unlock(&aspace->lock);
+}
+
int msm_gem_map_vma(struct msm_gem_address_space *aspace,
struct msm_gem_vma *vma, struct sg_table *sgt,
void *priv, unsigned int flags)
@@ -110,9 +155,7 @@ int msm_gem_map_vma(struct msm_gem_address_space *aspace,
flags, priv);
if (ret) {
- if (drm_mm_node_allocated(&vma->node))
- drm_mm_remove_node(&vma->node);
-
+ msm_gem_release_iova(aspace, vma);
return ret;
}
@@ -123,15 +166,16 @@ int msm_gem_map_vma(struct msm_gem_address_space *aspace,
}
void msm_gem_unmap_vma(struct msm_gem_address_space *aspace,
- struct msm_gem_vma *vma, struct sg_table *sgt, void *priv)
+ struct msm_gem_vma *vma, struct sg_table *sgt,
+ void *priv, bool invalidated)
{
if (!aspace || !vma->iova)
return;
- aspace->mmu->funcs->unmap(aspace->mmu, vma->iova, sgt, priv);
+ if (!invalidated)
+ aspace->mmu->funcs->unmap(aspace->mmu, vma->iova, sgt, priv);
- if (drm_mm_node_allocated(&vma->node))
- drm_mm_remove_node(&vma->node);
+ msm_gem_release_iova(aspace, vma);
vma->iova = 0;
diff --git a/drivers/gpu/drm/msm/msm_gpu.c b/drivers/gpu/drm/msm/msm_gpu.c
index bef6e81de82a..81bab9cc22af 100644
--- a/drivers/gpu/drm/msm/msm_gpu.c
+++ b/drivers/gpu/drm/msm/msm_gpu.c
@@ -580,8 +580,7 @@ int msm_gpu_submit(struct msm_gpu *gpu, struct msm_gem_submit *submit)
/* ring takes a reference to the bo and iova: */
drm_gem_object_reference(&msm_obj->base);
- msm_gem_get_iova_locked(&msm_obj->base,
- aspace, &iova);
+ msm_gem_get_iova(&msm_obj->base, aspace, &iova);
}
if (submit->bos[i].flags & MSM_SUBMIT_BO_READ)
@@ -890,10 +889,8 @@ int msm_gpu_init(struct drm_device *drm, struct platform_device *pdev,
/* Create ringbuffer(s): */
for (i = 0; i < nr_rings; i++) {
- mutex_lock(&drm->struct_mutex);
- gpu->rb[i] = msm_ringbuffer_new(gpu, i);
- mutex_unlock(&drm->struct_mutex);
+ gpu->rb[i] = msm_ringbuffer_new(gpu, i);
if (IS_ERR(gpu->rb[i])) {
ret = PTR_ERR(gpu->rb[i]);
gpu->rb[i] = NULL;
diff --git a/drivers/gpu/drm/msm/msm_rd.c b/drivers/gpu/drm/msm/msm_rd.c
index 6dbb516cd4dc..2d112f24a902 100644
--- a/drivers/gpu/drm/msm/msm_rd.c
+++ b/drivers/gpu/drm/msm/msm_rd.c
@@ -310,7 +310,7 @@ void msm_rd_dump_submit(struct msm_gem_submit *submit)
uint64_t iova = submit->cmd[i].iova;
uint32_t szd = submit->cmd[i].size; /* in dwords */
struct msm_gem_object *obj = submit->bos[idx].obj;
- const char *buf = msm_gem_vaddr_locked(&obj->base);
+ const char *buf = msm_gem_vaddr(&obj->base);
buf += iova - submit->bos[idx].iova;
diff --git a/drivers/gpu/drm/msm/msm_ringbuffer.c b/drivers/gpu/drm/msm/msm_ringbuffer.c
index 14a16c4578d9..382c71bb0ebe 100644
--- a/drivers/gpu/drm/msm/msm_ringbuffer.c
+++ b/drivers/gpu/drm/msm/msm_ringbuffer.c
@@ -34,14 +34,15 @@ struct msm_ringbuffer *msm_ringbuffer_new(struct msm_gpu *gpu, int id)
ring->gpu = gpu;
ring->id = id;
- ring->bo = msm_gem_new(gpu->dev, MSM_GPU_RINGBUFFER_SZ, MSM_BO_WC);
+ ring->bo = msm_gem_new(gpu->dev, MSM_GPU_RINGBUFFER_SZ,
+ MSM_BO_WC);
if (IS_ERR(ring->bo)) {
ret = PTR_ERR(ring->bo);
ring->bo = NULL;
goto fail;
}
- ring->start = msm_gem_vaddr_locked(ring->bo);
+ ring->start = msm_gem_vaddr(ring->bo);
ring->end = ring->start + (MSM_GPU_RINGBUFFER_SZ >> 2);
ring->next = ring->start;
ring->cur = ring->start;
diff --git a/drivers/gpu/drm/msm/msm_smmu.c b/drivers/gpu/drm/msm/msm_smmu.c
index c2dd5f96521e..a6efb22b5ed4 100644
--- a/drivers/gpu/drm/msm/msm_smmu.c
+++ b/drivers/gpu/drm/msm/msm_smmu.c
@@ -120,16 +120,30 @@ static int msm_smmu_map(struct msm_mmu *mmu, uint64_t iova,
{
struct msm_smmu *smmu = to_msm_smmu(mmu);
struct msm_smmu_client *client = msm_smmu_to_client(smmu);
+ struct iommu_domain *domain;
int ret;
- if (priv)
- ret = msm_dma_map_sg_lazy(client->dev, sgt->sgl, sgt->nents,
- DMA_BIDIRECTIONAL, priv);
- else
- ret = dma_map_sg(client->dev, sgt->sgl, sgt->nents,
- DMA_BIDIRECTIONAL);
+ if (!client || !sgt)
+ return -EINVAL;
+
+ if (iova != 0) {
+ if (!client->mmu_mapping || !client->mmu_mapping->domain)
+ return -EINVAL;
+
+ domain = client->mmu_mapping->domain;
+
+ return iommu_map_sg(domain, iova, sgt->sgl,
+ sgt->nents, flags);
+ } else {
+ if (priv)
+ ret = msm_dma_map_sg_lazy(client->dev, sgt->sgl,
+ sgt->nents, DMA_BIDIRECTIONAL, priv);
+ else
+ ret = dma_map_sg(client->dev, sgt->sgl, sgt->nents,
+ DMA_BIDIRECTIONAL);
- return (ret != sgt->nents) ? -ENOMEM : 0;
+ return (ret != sgt->nents) ? -ENOMEM : 0;
+ }
}
static void msm_smmu_unmap(struct msm_mmu *mmu, uint64_t iova,
@@ -137,13 +151,27 @@ static void msm_smmu_unmap(struct msm_mmu *mmu, uint64_t iova,
{
struct msm_smmu *smmu = to_msm_smmu(mmu);
struct msm_smmu_client *client = msm_smmu_to_client(smmu);
-
- if (priv)
- msm_dma_unmap_sg(client->dev, sgt->sgl, sgt->nents,
- DMA_BIDIRECTIONAL, priv);
- else
- dma_unmap_sg(client->dev, sgt->sgl, sgt->nents,
- DMA_BIDIRECTIONAL);
+ struct iommu_domain *domain = client->mmu_mapping->domain;
+ struct scatterlist *sg;
+ size_t len = 0;
+ int unmapped, i = 0;
+
+ if (iova != 0) {
+ for_each_sg(sgt->sgl, sg, sgt->nents, i)
+ len += sg->length;
+
+ unmapped = iommu_unmap(domain, iova, len);
+ if (unmapped < len)
+ dev_warn(mmu->dev,
+ "could not unmap iova@%llx\n", iova);
+ } else {
+ if (priv)
+ msm_dma_unmap_sg(client->dev, sgt->sgl,
+ sgt->nents, DMA_BIDIRECTIONAL, priv);
+ else
+ dma_unmap_sg(client->dev, sgt->sgl, sgt->nents,
+ DMA_BIDIRECTIONAL);
+ }
}
static void msm_smmu_destroy(struct msm_mmu *mmu)
diff --git a/drivers/gpu/msm/kgsl_sharedmem.c b/drivers/gpu/msm/kgsl_sharedmem.c
index fa95b4dfe718..7f4a5a3b251f 100644
--- a/drivers/gpu/msm/kgsl_sharedmem.c
+++ b/drivers/gpu/msm/kgsl_sharedmem.c
@@ -623,6 +623,9 @@ int kgsl_cache_range_op(struct kgsl_memdesc *memdesc, uint64_t offset,
uint64_t size, unsigned int op)
{
void *addr = NULL;
+ struct sg_table *sgt = NULL;
+ struct scatterlist *sg;
+ unsigned int i, pos = 0;
int ret = 0;
if (size == 0 || size > UINT_MAX)
@@ -650,40 +653,38 @@ int kgsl_cache_range_op(struct kgsl_memdesc *memdesc, uint64_t offset,
* If the buffer is not to mapped to kernel, perform cache
* operations after mapping to kernel.
*/
- if (memdesc->sgt != NULL) {
- struct scatterlist *sg;
- unsigned int i, pos = 0;
+ if (memdesc->sgt != NULL)
+ sgt = memdesc->sgt;
+ else {
+ if (memdesc->pages == NULL)
+ return ret;
+
+ sgt = kgsl_alloc_sgt_from_pages(memdesc);
+ if (IS_ERR(sgt))
+ return PTR_ERR(sgt);
+ }
- for_each_sg(memdesc->sgt->sgl, sg, memdesc->sgt->nents, i) {
- uint64_t sg_offset, sg_left;
+ for_each_sg(sgt->sgl, sg, sgt->nents, i) {
+ uint64_t sg_offset, sg_left;
- if (offset >= (pos + sg->length)) {
- pos += sg->length;
- continue;
- }
- sg_offset = offset > pos ? offset - pos : 0;
- sg_left = (sg->length - sg_offset > size) ? size :
- sg->length - sg_offset;
- ret = kgsl_do_cache_op(sg_page(sg), NULL, sg_offset,
- sg_left, op);
- size -= sg_left;
- if (size == 0)
- break;
+ if (offset >= (pos + sg->length)) {
pos += sg->length;
+ continue;
}
- } else if (memdesc->pages != NULL) {
- addr = vmap(memdesc->pages, memdesc->page_count,
- VM_IOREMAP, pgprot_writecombine(PAGE_KERNEL));
- if (addr == NULL)
- return -ENOMEM;
+ sg_offset = offset > pos ? offset - pos : 0;
+ sg_left = (sg->length - sg_offset > size) ? size :
+ sg->length - sg_offset;
+ ret = kgsl_do_cache_op(sg_page(sg), NULL, sg_offset,
+ sg_left, op);
+ size -= sg_left;
+ if (size == 0)
+ break;
+ pos += sg->length;
+ }
- /* Make sure the offset + size do not overflow the address */
- if (addr + ((size_t) offset + (size_t) size) < addr)
- return -ERANGE;
+ if (memdesc->sgt == NULL)
+ kgsl_free_sgt(sgt);
- ret = kgsl_do_cache_op(NULL, addr, offset, size, op);
- vunmap(addr);
- }
return ret;
}
EXPORT_SYMBOL(kgsl_cache_range_op);
diff --git a/drivers/hwtracing/coresight/coresight-stm.c b/drivers/hwtracing/coresight/coresight-stm.c
index 11500fccc770..d85bcd8e121a 100644
--- a/drivers/hwtracing/coresight/coresight-stm.c
+++ b/drivers/hwtracing/coresight/coresight-stm.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012-2016, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-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
@@ -866,7 +866,6 @@ err:
coresight_unregister(drvdata->csdev);
return ret;
err1:
- pm_runtime_put(&adev->dev);
return -EPERM;
}
diff --git a/drivers/input/touchscreen/synaptics_dsx/Kconfig b/drivers/input/touchscreen/synaptics_dsx/Kconfig
index 86263fddacea..18d473969261 100644
--- a/drivers/input/touchscreen/synaptics_dsx/Kconfig
+++ b/drivers/input/touchscreen/synaptics_dsx/Kconfig
@@ -50,17 +50,6 @@ config TOUCHSCREEN_SYNAPTICS_DSX_CORE_v21
To compile this driver as a module, choose M here: the
module will be called synaptics_dsx_core.
-config TOUCHSCREEN_SYNAPTICS_DSX_RMI_DEV_v21
- tristate "Synaptics DSX touchscreen RMI device module"
- depends on TOUCHSCREEN_SYNAPTICS_DSX_CORE_v21
- help
- Say Y here to enable support for direct RMI register access.
-
- If unsure, say N.
-
- To compile this driver as a module, choose M here: the
- module will be called synaptics_dsx_rmi_dev.
-
config TOUCHSCREEN_SYNAPTICS_DSX_FW_UPDATE_v21
tristate "Synaptics DSX touchscreen firmware update module"
depends on TOUCHSCREEN_SYNAPTICS_DSX_CORE_v21
@@ -72,15 +61,4 @@ config TOUCHSCREEN_SYNAPTICS_DSX_FW_UPDATE_v21
To compile this driver as a module, choose M here: the
module will be called synaptics_dsx_fw_update.
-config TOUCHSCREEN_SYNAPTICS_DSX_PROXIMITY_v21
- tristate "Synaptics DSX touchscreen proximity module"
- depends on TOUCHSCREEN_SYNAPTICS_DSX_CORE_v21
- help
- Say Y here to enable support for proximity functionalities.
-
- If unsure, say N.
-
- To compile this driver as a module, choose M here: the
- module will be called synaptics_dsx_proximity.
-
endif
diff --git a/drivers/input/touchscreen/synaptics_dsx/Makefile b/drivers/input/touchscreen/synaptics_dsx/Makefile
index b35b222d5ae2..0bffb8da94ea 100644
--- a/drivers/input/touchscreen/synaptics_dsx/Makefile
+++ b/drivers/input/touchscreen/synaptics_dsx/Makefile
@@ -7,6 +7,4 @@
obj-$(CONFIG_TOUCHSCREEN_SYNAPTICS_DSX_I2C_v21) += synaptics_dsx_i2c.o
obj-$(CONFIG_TOUCHSCREEN_SYNAPTICS_DSX_SPI_v21) += synaptics_dsx_spi.o
obj-$(CONFIG_TOUCHSCREEN_SYNAPTICS_DSX_CORE_v21) += synaptics_dsx_core.o
-obj-$(CONFIG_TOUCHSCREEN_SYNAPTICS_DSX_RMI_DEV_v21) += synaptics_dsx_rmi_dev.o
obj-$(CONFIG_TOUCHSCREEN_SYNAPTICS_DSX_FW_UPDATE_v21) += synaptics_dsx_fw_update.o
-obj-$(CONFIG_TOUCHSCREEN_SYNAPTICS_DSX_PROXIMITY_v21) += synaptics_dsx_proximity.o
diff --git a/drivers/input/touchscreen/synaptics_dsx/synaptics_dsx_proximity.c b/drivers/input/touchscreen/synaptics_dsx/synaptics_dsx_proximity.c
deleted file mode 100755
index 99c05e6845c0..000000000000
--- a/drivers/input/touchscreen/synaptics_dsx/synaptics_dsx_proximity.c
+++ /dev/null
@@ -1,671 +0,0 @@
-/*
- * Synaptics DSX touchscreen driver
- *
- * Copyright (C) 2012 Synaptics Incorporated
- *
- * Copyright (C) 2012 Alexandra Chin <alexandra.chin@tw.synaptics.com>
- * Copyright (C) 2012 Scott Lin <scott.lin@tw.synaptics.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * 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/kernel.h>
-#include <linux/module.h>
-#include <linux/slab.h>
-#include <linux/interrupt.h>
-#include <linux/delay.h>
-#include <linux/input.h>
-#include <linux/platform_device.h>
-#include <linux/input/synaptics_dsx_v2.h>
-#include "synaptics_dsx_core.h"
-
-#define PROX_PHYS_NAME "synaptics_dsx/input1"
-
-#define HOVER_Z_MAX (255)
-
-#define HOVERING_FINGER_EN (1 << 4)
-
-static ssize_t synaptics_rmi4_hover_finger_en_show(struct device *dev,
- struct device_attribute *attr, char *buf);
-
-static ssize_t synaptics_rmi4_hover_finger_en_store(struct device *dev,
- struct device_attribute *attr, const char *buf, size_t count);
-
-static struct device_attribute attrs[] = {
- __ATTR(hover_finger_en, (S_IRUGO | S_IWUGO),
- synaptics_rmi4_hover_finger_en_show,
- synaptics_rmi4_hover_finger_en_store),
-};
-
-struct synaptics_rmi4_f12_query_5 {
- union {
- struct {
- unsigned char size_of_query6;
- struct {
- unsigned char ctrl0_is_present:1;
- unsigned char ctrl1_is_present:1;
- unsigned char ctrl2_is_present:1;
- unsigned char ctrl3_is_present:1;
- unsigned char ctrl4_is_present:1;
- unsigned char ctrl5_is_present:1;
- unsigned char ctrl6_is_present:1;
- unsigned char ctrl7_is_present:1;
- } __packed;
- struct {
- unsigned char ctrl8_is_present:1;
- unsigned char ctrl9_is_present:1;
- unsigned char ctrl10_is_present:1;
- unsigned char ctrl11_is_present:1;
- unsigned char ctrl12_is_present:1;
- unsigned char ctrl13_is_present:1;
- unsigned char ctrl14_is_present:1;
- unsigned char ctrl15_is_present:1;
- } __packed;
- struct {
- unsigned char ctrl16_is_present:1;
- unsigned char ctrl17_is_present:1;
- unsigned char ctrl18_is_present:1;
- unsigned char ctrl19_is_present:1;
- unsigned char ctrl20_is_present:1;
- unsigned char ctrl21_is_present:1;
- unsigned char ctrl22_is_present:1;
- unsigned char ctrl23_is_present:1;
- } __packed;
- };
- unsigned char data[4];
- };
-};
-
-struct synaptics_rmi4_f12_query_8 {
- union {
- struct {
- unsigned char size_of_query9;
- struct {
- unsigned char data0_is_present:1;
- unsigned char data1_is_present:1;
- unsigned char data2_is_present:1;
- unsigned char data3_is_present:1;
- unsigned char data4_is_present:1;
- unsigned char data5_is_present:1;
- unsigned char data6_is_present:1;
- unsigned char data7_is_present:1;
- } __packed;
- };
- unsigned char data[2];
- };
-};
-
-struct prox_finger_data {
- union {
- struct {
- unsigned char object_type_and_status;
- unsigned char x_lsb;
- unsigned char x_msb;
- unsigned char y_lsb;
- unsigned char y_msb;
- unsigned char z;
- } __packed;
- unsigned char proximity_data[6];
- };
-};
-
-struct synaptics_rmi4_prox_handle {
- bool hover_finger_present;
- bool hover_finger_en;
- unsigned char intr_mask;
- unsigned short query_base_addr;
- unsigned short control_base_addr;
- unsigned short data_base_addr;
- unsigned short command_base_addr;
- unsigned short hover_finger_en_addr;
- unsigned short hover_finger_data_addr;
- struct input_dev *prox_dev;
- struct prox_finger_data *finger_data;
- struct synaptics_rmi4_data *rmi4_data;
-};
-
-static struct synaptics_rmi4_prox_handle *prox;
-
-DECLARE_COMPLETION(prox_remove_complete);
-
-static void prox_hover_finger_lift(void)
-{
- input_report_key(prox->prox_dev, BTN_TOUCH, 0);
- input_report_key(prox->prox_dev, BTN_TOOL_FINGER, 0);
- input_sync(prox->prox_dev);
- prox->hover_finger_present = false;
-
- return;
-}
-
-static void prox_hover_finger_report(void)
-{
- int retval;
- int x;
- int y;
- int z;
- struct prox_finger_data *data;
- struct synaptics_rmi4_data *rmi4_data = prox->rmi4_data;
-
- data = prox->finger_data;
-
- retval = synaptics_rmi4_reg_read(rmi4_data,
- prox->hover_finger_data_addr,
- data->proximity_data,
- sizeof(data->proximity_data));
- if (retval < 0) {
- dev_err(rmi4_data->pdev->dev.parent,
- "%s: Failed to read hovering finger data\n",
- __func__);
- return;
- }
-
- if (data->object_type_and_status != F12_HOVERING_FINGER_STATUS) {
- if (prox->hover_finger_present)
- prox_hover_finger_lift();
-
- return;
- }
-
- x = (data->x_msb << 8) | (data->x_lsb);
- y = (data->y_msb << 8) | (data->y_lsb);
- z = HOVER_Z_MAX - data->z;
-
- input_report_key(prox->prox_dev, BTN_TOUCH, 0);
- input_report_key(prox->prox_dev, BTN_TOOL_FINGER, 1);
- input_report_abs(prox->prox_dev, ABS_X, x);
- input_report_abs(prox->prox_dev, ABS_Y, y);
- input_report_abs(prox->prox_dev, ABS_DISTANCE, z);
-
- input_sync(prox->prox_dev);
-
- dev_dbg(rmi4_data->pdev->dev.parent,
- "%s: x = %d y = %d z = %d\n",
- __func__, x, y, z);
-
- prox->hover_finger_present = true;
-
- return;
-}
-
-static int prox_set_hover_finger_en(void)
-{
- int retval;
- unsigned char object_report_enable;
- struct synaptics_rmi4_data *rmi4_data = prox->rmi4_data;
-
- retval = synaptics_rmi4_reg_read(rmi4_data,
- prox->hover_finger_en_addr,
- &object_report_enable,
- sizeof(object_report_enable));
- if (retval < 0) {
- dev_err(rmi4_data->pdev->dev.parent,
- "%s: Failed to read from object report enable register\n",
- __func__);
- return retval;
- }
-
- if (prox->hover_finger_en)
- object_report_enable |= HOVERING_FINGER_EN;
- else
- object_report_enable &= ~HOVERING_FINGER_EN;
-
- retval = synaptics_rmi4_reg_write(rmi4_data,
- prox->hover_finger_en_addr,
- &object_report_enable,
- sizeof(object_report_enable));
- if (retval < 0) {
- dev_err(rmi4_data->pdev->dev.parent,
- "%s: Failed to write to object report enable register\n",
- __func__);
- return retval;
- }
-
- return 0;
-}
-
-static void prox_set_params(void)
-{
- input_set_abs_params(prox->prox_dev, ABS_X, 0,
- prox->rmi4_data->sensor_max_x, 0, 0);
- input_set_abs_params(prox->prox_dev, ABS_Y, 0,
- prox->rmi4_data->sensor_max_y, 0, 0);
- input_set_abs_params(prox->prox_dev, ABS_DISTANCE, 0,
- HOVER_Z_MAX, 0, 0);
-
- return;
-}
-
-static int prox_reg_init(void)
-{
- int retval;
- unsigned char ctrl_23_offset;
- unsigned char data_1_offset;
- struct synaptics_rmi4_f12_query_5 query_5;
- struct synaptics_rmi4_f12_query_8 query_8;
- struct synaptics_rmi4_data *rmi4_data = prox->rmi4_data;
-
- retval = synaptics_rmi4_reg_read(rmi4_data,
- prox->query_base_addr + 5,
- query_5.data,
- sizeof(query_5.data));
- if (retval < 0)
- return retval;
-
- ctrl_23_offset = query_5.ctrl0_is_present +
- query_5.ctrl1_is_present +
- query_5.ctrl2_is_present +
- query_5.ctrl3_is_present +
- query_5.ctrl4_is_present +
- query_5.ctrl5_is_present +
- query_5.ctrl6_is_present +
- query_5.ctrl7_is_present +
- query_5.ctrl8_is_present +
- query_5.ctrl9_is_present +
- query_5.ctrl10_is_present +
- query_5.ctrl11_is_present +
- query_5.ctrl12_is_present +
- query_5.ctrl13_is_present +
- query_5.ctrl14_is_present +
- query_5.ctrl15_is_present +
- query_5.ctrl16_is_present +
- query_5.ctrl17_is_present +
- query_5.ctrl18_is_present +
- query_5.ctrl19_is_present +
- query_5.ctrl20_is_present +
- query_5.ctrl21_is_present +
- query_5.ctrl22_is_present;
-
- prox->hover_finger_en_addr = prox->control_base_addr + ctrl_23_offset;
-
- retval = synaptics_rmi4_reg_read(rmi4_data,
- prox->query_base_addr + 8,
- query_8.data,
- sizeof(query_8.data));
- if (retval < 0)
- return retval;
-
- data_1_offset = query_8.data0_is_present;
- prox->hover_finger_data_addr = prox->data_base_addr + data_1_offset;
-
- return retval;
-}
-
-static int prox_scan_pdt(void)
-{
- int retval;
- unsigned char ii;
- unsigned char page;
- unsigned char intr_count = 0;
- unsigned char intr_off;
- unsigned char intr_src;
- unsigned short addr;
- struct synaptics_rmi4_fn_desc fd;
- struct synaptics_rmi4_data *rmi4_data = prox->rmi4_data;
-
- for (page = 0; page < PAGES_TO_SERVICE; page++) {
- for (addr = PDT_START; addr > PDT_END; addr -= PDT_ENTRY_SIZE) {
- addr |= (page << 8);
-
- retval = synaptics_rmi4_reg_read(rmi4_data,
- addr,
- (unsigned char *)&fd,
- sizeof(fd));
- if (retval < 0)
- return retval;
-
- addr &= ~(MASK_8BIT << 8);
-
- if (fd.fn_number) {
- dev_dbg(rmi4_data->pdev->dev.parent,
- "%s: Found F%02x\n",
- __func__, fd.fn_number);
- switch (fd.fn_number) {
- case SYNAPTICS_RMI4_F12:
- goto f12_found;
- break;
- }
- } else {
- break;
- }
-
- intr_count += (fd.intr_src_count & MASK_3BIT);
- }
- }
-
- dev_err(rmi4_data->pdev->dev.parent,
- "%s: Failed to find F12\n",
- __func__);
- return -EINVAL;
-
-f12_found:
- prox->query_base_addr = fd.query_base_addr | (page << 8);
- prox->control_base_addr = fd.ctrl_base_addr | (page << 8);
- prox->data_base_addr = fd.data_base_addr | (page << 8);
- prox->command_base_addr = fd.cmd_base_addr | (page << 8);
-
- retval = prox_reg_init();
- if (retval < 0) {
- dev_err(rmi4_data->pdev->dev.parent,
- "%s: Failed to initialize proximity registers\n",
- __func__);
- return retval;
- }
-
- prox->intr_mask = 0;
- intr_src = fd.intr_src_count;
- intr_off = intr_count % 8;
- for (ii = intr_off;
- ii < ((intr_src & MASK_3BIT) +
- intr_off);
- ii++) {
- prox->intr_mask |= 1 << ii;
- }
-
- rmi4_data->intr_mask[0] |= prox->intr_mask;
-
- addr = rmi4_data->f01_ctrl_base_addr + 1;
-
- retval = synaptics_rmi4_reg_write(rmi4_data,
- addr,
- &(rmi4_data->intr_mask[0]),
- sizeof(rmi4_data->intr_mask[0]));
- if (retval < 0) {
- dev_err(rmi4_data->pdev->dev.parent,
- "%s: Failed to set interrupt enable bit\n",
- __func__);
- return retval;
- }
-
- return 0;
-}
-
-static ssize_t synaptics_rmi4_hover_finger_en_show(struct device *dev,
- struct device_attribute *attr, char *buf)
-{
- if (!prox)
- return -ENODEV;
-
- return snprintf(buf, PAGE_SIZE, "%u\n",
- prox->hover_finger_en);
-}
-
-static ssize_t synaptics_rmi4_hover_finger_en_store(struct device *dev,
- struct device_attribute *attr, const char *buf, size_t count)
-{
- int retval;
- unsigned int input;
- struct synaptics_rmi4_data *rmi4_data = prox->rmi4_data;
-
- if (!prox)
- return -ENODEV;
-
- if (sscanf(buf, "%x", &input) != 1)
- return -EINVAL;
-
- if (input == 1)
- prox->hover_finger_en = true;
- else if (input == 0)
- prox->hover_finger_en = false;
- else
- return -EINVAL;
-
- retval = prox_set_hover_finger_en();
- if (retval < 0) {
- dev_err(rmi4_data->pdev->dev.parent,
- "%s: Failed to change hovering finger enable setting\n",
- __func__);
- return retval;
- }
-
- return count;
-}
-
-int synaptics_rmi4_prox_hover_finger_en(bool enable)
-{
- int retval;
-
- if (!prox)
- return -ENODEV;
-
- prox->hover_finger_en = enable;
-
- retval = prox_set_hover_finger_en();
- if (retval < 0)
- return retval;
-
- return 0;
-}
-EXPORT_SYMBOL(synaptics_rmi4_prox_hover_finger_en);
-
-static void synaptics_rmi4_prox_attn(struct synaptics_rmi4_data *rmi4_data,
- unsigned char intr_mask)
-{
- if (!prox)
- return;
-
- if (prox->intr_mask & intr_mask)
- prox_hover_finger_report();
-
- return;
-}
-
-static int synaptics_rmi4_prox_init(struct synaptics_rmi4_data *rmi4_data)
-{
- int retval;
- unsigned char attr_count;
-
- prox = kzalloc(sizeof(*prox), GFP_KERNEL);
- if (!prox) {
- dev_err(rmi4_data->pdev->dev.parent,
- "%s: Failed to alloc mem for prox\n",
- __func__);
- retval = -ENOMEM;
- goto exit;
- }
-
- prox->finger_data = kzalloc(sizeof(*(prox->finger_data)), GFP_KERNEL);
- if (!prox->finger_data) {
- dev_err(rmi4_data->pdev->dev.parent,
- "%s: Failed to alloc mem for finger_data\n",
- __func__);
- retval = -ENOMEM;
- goto exit_free_prox;
- }
-
- prox->rmi4_data = rmi4_data;
-
- retval = prox_scan_pdt();
- if (retval < 0)
- goto exit_free_finger_data;
-
- prox->hover_finger_en = true;
-
- retval = prox_set_hover_finger_en();
- if (retval < 0)
- return retval;
-
- prox->prox_dev = input_allocate_device();
- if (prox->prox_dev == NULL) {
- dev_err(rmi4_data->pdev->dev.parent,
- "%s: Failed to allocate proximity device\n",
- __func__);
- retval = -ENOMEM;
- goto exit_free_finger_data;
- }
-
- prox->prox_dev->name = PLATFORM_DRIVER_NAME;
- prox->prox_dev->phys = PROX_PHYS_NAME;
- prox->prox_dev->id.product = SYNAPTICS_DSX_DRIVER_PRODUCT;
- prox->prox_dev->id.version = SYNAPTICS_DSX_DRIVER_VERSION;
- prox->prox_dev->dev.parent = rmi4_data->pdev->dev.parent;
- input_set_drvdata(prox->prox_dev, rmi4_data);
-
- set_bit(EV_KEY, prox->prox_dev->evbit);
- set_bit(EV_ABS, prox->prox_dev->evbit);
- set_bit(BTN_TOUCH, prox->prox_dev->keybit);
- set_bit(BTN_TOOL_FINGER, prox->prox_dev->keybit);
-#ifdef INPUT_PROP_DIRECT
- set_bit(INPUT_PROP_DIRECT, prox->prox_dev->propbit);
-#endif
-
- prox_set_params();
-
- retval = input_register_device(prox->prox_dev);
- if (retval) {
- dev_err(rmi4_data->pdev->dev.parent,
- "%s: Failed to register proximity device\n",
- __func__);
- goto exit_free_input_device;
- }
-
- for (attr_count = 0; attr_count < ARRAY_SIZE(attrs); attr_count++) {
- retval = sysfs_create_file(&rmi4_data->input_dev->dev.kobj,
- &attrs[attr_count].attr);
- if (retval < 0) {
- dev_err(rmi4_data->pdev->dev.parent,
- "%s: Failed to create sysfs attributes\n",
- __func__);
- goto exit_free_sysfs;
- }
- }
-
- return 0;
-
-exit_free_sysfs:
- for (attr_count--; attr_count >= 0; attr_count--) {
- sysfs_remove_file(&rmi4_data->input_dev->dev.kobj,
- &attrs[attr_count].attr);
- }
-
- input_unregister_device(prox->prox_dev);
- prox->prox_dev = NULL;
-
-exit_free_input_device:
- if (prox->prox_dev)
- input_free_device(prox->prox_dev);
-
-exit_free_finger_data:
- kfree(prox->finger_data);
-
-exit_free_prox:
- kfree(prox);
- prox = NULL;
-
-exit:
- return retval;
-}
-
-static void synaptics_rmi4_prox_remove(struct synaptics_rmi4_data *rmi4_data)
-{
- unsigned char attr_count;
-
- if (!prox)
- goto exit;
-
- for (attr_count = 0; attr_count < ARRAY_SIZE(attrs); attr_count++) {
- sysfs_remove_file(&rmi4_data->input_dev->dev.kobj,
- &attrs[attr_count].attr);
- }
-
- input_unregister_device(prox->prox_dev);
- kfree(prox->finger_data);
- kfree(prox);
- prox = NULL;
-
-exit:
- complete(&prox_remove_complete);
-
- return;
-}
-
-static void synaptics_rmi4_prox_reset(struct synaptics_rmi4_data *rmi4_data)
-{
- if (!prox)
- return;
-
- prox_hover_finger_lift();
-
- prox_scan_pdt();
-
- prox_set_hover_finger_en();
-
- prox_set_params();
-
- return;
-}
-
-static void synaptics_rmi4_prox_reinit(struct synaptics_rmi4_data *rmi4_data)
-{
- if (!prox)
- return;
-
- prox_hover_finger_lift();
-
- prox_set_hover_finger_en();
-
- return;
-}
-
-static void synaptics_rmi4_prox_e_suspend(struct synaptics_rmi4_data *rmi4_data)
-{
- if (!prox)
- return;
-
- prox_hover_finger_lift();
-
- return;
-}
-
-static void synaptics_rmi4_prox_suspend(struct synaptics_rmi4_data *rmi4_data)
-{
- if (!prox)
- return;
-
- prox_hover_finger_lift();
-
- return;
-}
-
-static struct synaptics_rmi4_exp_fn proximity_module = {
- .fn_type = RMI_PROXIMITY,
- .init = synaptics_rmi4_prox_init,
- .remove = synaptics_rmi4_prox_remove,
- .reset = synaptics_rmi4_prox_reset,
- .reinit = synaptics_rmi4_prox_reinit,
- .early_suspend = synaptics_rmi4_prox_e_suspend,
- .suspend = synaptics_rmi4_prox_suspend,
- .resume = NULL,
- .late_resume = NULL,
- .attn = synaptics_rmi4_prox_attn,
-};
-
-static int __init rmi4_proximity_module_init(void)
-{
- synaptics_rmi4_dsx_new_function(&proximity_module, true);
-
- return 0;
-}
-
-static void __exit rmi4_proximity_module_exit(void)
-{
- synaptics_rmi4_dsx_new_function(&proximity_module, false);
-
- wait_for_completion(&prox_remove_complete);
-
- return;
-}
-
-module_init(rmi4_proximity_module_init);
-module_exit(rmi4_proximity_module_exit);
-
-MODULE_AUTHOR("Synaptics, Inc.");
-MODULE_DESCRIPTION("Synaptics DSX Proximity Module");
-MODULE_LICENSE("GPL v2");
diff --git a/drivers/input/touchscreen/synaptics_dsx/synaptics_dsx_rmi_dev.c b/drivers/input/touchscreen/synaptics_dsx/synaptics_dsx_rmi_dev.c
deleted file mode 100644
index c1cbec81d7d6..000000000000
--- a/drivers/input/touchscreen/synaptics_dsx/synaptics_dsx_rmi_dev.c
+++ /dev/null
@@ -1,810 +0,0 @@
-/*
- * Synaptics DSX touchscreen driver
- *
- * Copyright (C) 2012 Synaptics Incorporated
- *
- * Copyright (C) 2012 Alexandra Chin <alexandra.chin@tw.synaptics.com>
- * Copyright (C) 2012 Scott Lin <scott.lin@tw.synaptics.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * 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/kernel.h>
-#include <linux/module.h>
-#include <linux/slab.h>
-#include <linux/interrupt.h>
-#include <linux/delay.h>
-#include <linux/input.h>
-#include <linux/gpio.h>
-#include <linux/uaccess.h>
-#include <linux/cdev.h>
-#include <linux/platform_device.h>
-#include <linux/input/synaptics_dsx_v2.h>
-#include "synaptics_dsx_core.h"
-
-#define CHAR_DEVICE_NAME "rmi"
-#define DEVICE_CLASS_NAME "rmidev"
-#define SYSFS_FOLDER_NAME "rmidev"
-#define DEV_NUMBER 1
-#define REG_ADDR_LIMIT 0xFFFF
-
-static ssize_t rmidev_sysfs_data_show(struct file *data_file,
- struct kobject *kobj, struct bin_attribute *attributes,
- char *buf, loff_t pos, size_t count);
-
-static ssize_t rmidev_sysfs_data_store(struct file *data_file,
- struct kobject *kobj, struct bin_attribute *attributes,
- char *buf, loff_t pos, size_t count);
-
-static ssize_t rmidev_sysfs_open_store(struct device *dev,
- struct device_attribute *attr, const char *buf, size_t count);
-
-static ssize_t rmidev_sysfs_release_store(struct device *dev,
- struct device_attribute *attr, const char *buf, size_t count);
-
-static ssize_t rmidev_sysfs_attn_state_show(struct device *dev,
- struct device_attribute *attr, char *buf);
-
-struct rmidev_handle {
- dev_t dev_no;
- struct device dev;
- struct synaptics_rmi4_data *rmi4_data;
- struct kobject *sysfs_dir;
- void *data;
- bool irq_enabled;
-};
-
-struct rmidev_data {
- int ref_count;
- struct cdev main_dev;
- struct class *device_class;
- struct mutex file_mutex;
- struct rmidev_handle *rmi_dev;
-};
-
-static struct bin_attribute attr_data = {
- .attr = {
- .name = "data",
- .mode = (S_IRUGO | S_IWUSR),
- },
- .size = 0,
- .read = rmidev_sysfs_data_show,
- .write = rmidev_sysfs_data_store,
-};
-
-static struct device_attribute attrs[] = {
- __ATTR(open, S_IWUSR | S_IWGRP,
- NULL,
- rmidev_sysfs_open_store),
- __ATTR(release, S_IWUSR | S_IWGRP,
- NULL,
- rmidev_sysfs_release_store),
- __ATTR(attn_state, S_IRUGO,
- rmidev_sysfs_attn_state_show,
- synaptics_rmi4_store_error),
-};
-
-static int rmidev_major_num;
-
-static struct class *rmidev_device_class;
-
-static struct rmidev_handle *rmidev;
-
-DECLARE_COMPLETION(rmidev_remove_complete);
-
-static irqreturn_t rmidev_sysfs_irq(int irq, void *data)
-{
- struct synaptics_rmi4_data *rmi4_data = data;
-
- sysfs_notify(&rmi4_data->input_dev->dev.kobj,
- SYSFS_FOLDER_NAME, "attn_state");
-
- return IRQ_HANDLED;
-}
-
-static int rmidev_sysfs_irq_enable(struct synaptics_rmi4_data *rmi4_data,
- bool enable)
-{
- int retval = 0;
- unsigned char intr_status[MAX_INTR_REGISTERS];
- unsigned long irq_flags = IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING;
-
- if (enable) {
- if (rmidev->irq_enabled)
- return retval;
-
- /* Clear interrupts first */
- retval = synaptics_rmi4_reg_read(rmi4_data,
- rmi4_data->f01_data_base_addr + 1,
- intr_status,
- rmi4_data->num_of_intr_regs);
- if (retval < 0)
- return retval;
-
- retval = request_threaded_irq(rmi4_data->irq, NULL,
- rmidev_sysfs_irq, irq_flags,
- "synaptics_dsx_rmidev", rmi4_data);
- if (retval < 0) {
- dev_err(rmi4_data->pdev->dev.parent,
- "%s: Failed to create irq thread\n",
- __func__);
- return retval;
- }
-
- rmidev->irq_enabled = true;
- } else {
- if (rmidev->irq_enabled) {
- disable_irq(rmi4_data->irq);
- free_irq(rmi4_data->irq, rmi4_data);
- rmidev->irq_enabled = false;
- }
- }
-
- return retval;
-}
-
-static ssize_t rmidev_sysfs_data_show(struct file *data_file,
- struct kobject *kobj, struct bin_attribute *attributes,
- char *buf, loff_t pos, size_t count)
-{
- int retval;
- unsigned int length = (unsigned int)count;
- unsigned short address = (unsigned short)pos;
- struct synaptics_rmi4_data *rmi4_data = rmidev->rmi4_data;
-
- if (length > (REG_ADDR_LIMIT - address)) {
- dev_err(rmi4_data->pdev->dev.parent,
- "%s: Out of register map limit\n",
- __func__);
- return -EINVAL;
- }
-
- if (length) {
- retval = synaptics_rmi4_reg_read(rmi4_data,
- address,
- (unsigned char *)buf,
- length);
- if (retval < 0) {
- dev_err(rmi4_data->pdev->dev.parent,
- "%s: Failed to read data\n",
- __func__);
- return retval;
- }
- } else {
- return -EINVAL;
- }
-
- return length;
-}
-
-static ssize_t rmidev_sysfs_data_store(struct file *data_file,
- struct kobject *kobj, struct bin_attribute *attributes,
- char *buf, loff_t pos, size_t count)
-{
- int retval;
- unsigned int length = (unsigned int)count;
- unsigned short address = (unsigned short)pos;
- struct synaptics_rmi4_data *rmi4_data = rmidev->rmi4_data;
-
- if (length > (REG_ADDR_LIMIT - address)) {
- dev_err(rmi4_data->pdev->dev.parent,
- "%s: Out of register map limit\n",
- __func__);
- return -EINVAL;
- }
-
- if (length) {
- retval = synaptics_rmi4_reg_write(rmi4_data,
- address,
- (unsigned char *)buf,
- length);
- if (retval < 0) {
- dev_err(rmi4_data->pdev->dev.parent,
- "%s: Failed to write data\n",
- __func__);
- return retval;
- }
- } else {
- return -EINVAL;
- }
-
- return length;
-}
-
-static ssize_t rmidev_sysfs_open_store(struct device *dev,
- struct device_attribute *attr, const char *buf, size_t count)
-{
- unsigned int input;
- struct synaptics_rmi4_data *rmi4_data = rmidev->rmi4_data;
-
- if (sscanf(buf, "%u", &input) != 1)
- return -EINVAL;
-
- if (input != 1)
- return -EINVAL;
-
- rmi4_data->irq_enable(rmi4_data, false);
- rmidev_sysfs_irq_enable(rmi4_data, true);
-
- dev_dbg(rmi4_data->pdev->dev.parent,
- "%s: Attention interrupt disabled\n",
- __func__);
-
- return count;
-}
-
-static ssize_t rmidev_sysfs_release_store(struct device *dev,
- struct device_attribute *attr, const char *buf, size_t count)
-{
- unsigned int input;
- struct synaptics_rmi4_data *rmi4_data = rmidev->rmi4_data;
-
- if (sscanf(buf, "%u", &input) != 1)
- return -EINVAL;
-
- if (input != 1)
- return -EINVAL;
-
- rmi4_data->reset_device(rmi4_data);
-
- rmidev_sysfs_irq_enable(rmi4_data, false);
- rmi4_data->irq_enable(rmi4_data, true);
-
- dev_dbg(rmi4_data->pdev->dev.parent,
- "%s: Attention interrupt enabled\n",
- __func__);
-
- return count;
-}
-
-static ssize_t rmidev_sysfs_attn_state_show(struct device *dev,
- struct device_attribute *attr, char *buf)
-{
- int attn_state;
- struct synaptics_rmi4_data *rmi4_data = rmidev->rmi4_data;
- const struct synaptics_dsx_board_data *bdata =
- rmi4_data->hw_if->board_data;
-
- attn_state = gpio_get_value(bdata->irq_gpio);
-
- return snprintf(buf, PAGE_SIZE, "%u\n", attn_state);
-}
-
-/*
- * rmidev_llseek - used to set up register address
- *
- * @filp: file structure for seek
- * @off: offset
- * if whence == SEEK_SET,
- * high 16 bits: page address
- * low 16 bits: register address
- * if whence == SEEK_CUR,
- * offset from current position
- * if whence == SEEK_END,
- * offset from end position (0xFFFF)
- * @whence: SEEK_SET, SEEK_CUR, or SEEK_END
- */
-static loff_t rmidev_llseek(struct file *filp, loff_t off, int whence)
-{
- loff_t newpos;
- struct rmidev_data *dev_data = filp->private_data;
- struct synaptics_rmi4_data *rmi4_data = rmidev->rmi4_data;
-
- if (IS_ERR(dev_data)) {
- pr_err("%s: Pointer of char device data is invalid", __func__);
- return -EBADF;
- }
-
- mutex_lock(&(dev_data->file_mutex));
-
- switch (whence) {
- case SEEK_SET:
- newpos = off;
- break;
- case SEEK_CUR:
- newpos = filp->f_pos + off;
- break;
- case SEEK_END:
- newpos = REG_ADDR_LIMIT + off;
- break;
- default:
- newpos = -EINVAL;
- goto clean_up;
- }
-
- if (newpos < 0 || newpos > REG_ADDR_LIMIT) {
- dev_err(rmi4_data->pdev->dev.parent,
- "%s: New position 0x%04x is invalid\n",
- __func__, (unsigned int)newpos);
- newpos = -EINVAL;
- goto clean_up;
- }
-
- filp->f_pos = newpos;
-
-clean_up:
- mutex_unlock(&(dev_data->file_mutex));
-
- return newpos;
-}
-
-/*
- * rmidev_read: - use to read data from rmi device
- *
- * @filp: file structure for read
- * @buf: user space buffer pointer
- * @count: number of bytes to read
- * @f_pos: offset (starting register address)
- */
-static ssize_t rmidev_read(struct file *filp, char __user *buf,
- size_t count, loff_t *f_pos)
-{
- ssize_t retval;
- unsigned char *tmpbuf;
- struct rmidev_data *dev_data = filp->private_data;
-
- if (IS_ERR(dev_data)) {
- pr_err("%s: Pointer of char device data is invalid", __func__);
- return -EBADF;
- }
-
- mutex_lock(&(dev_data->file_mutex));
-
- if (count > (REG_ADDR_LIMIT - *f_pos))
- count = REG_ADDR_LIMIT - *f_pos;
-
- if (count == 0) {
- retval = 0;
- goto unlock;
- }
-
- if (*f_pos > REG_ADDR_LIMIT) {
- retval = -EFAULT;
- goto unlock;
- }
- tmpbuf = kzalloc(count + 1, GFP_KERNEL);
- if (!tmpbuf) {
- retval = -ENOMEM;
- goto unlock;
- }
- retval = synaptics_rmi4_reg_read(rmidev->rmi4_data,
- *f_pos,
- tmpbuf,
- count);
- if (retval < 0)
- goto clean_up;
-
- if (copy_to_user(buf, tmpbuf, count))
- retval = -EFAULT;
- else
- *f_pos += retval;
-
-clean_up:
- kfree(tmpbuf);
-unlock:
- mutex_unlock(&(dev_data->file_mutex));
- return retval;
-}
-
-/*
- * rmidev_write: - used to write data to rmi device
- *
- * @filep: file structure for write
- * @buf: user space buffer pointer
- * @count: number of bytes to write
- * @f_pos: offset (starting register address)
- */
-static ssize_t rmidev_write(struct file *filp, const char __user *buf,
- size_t count, loff_t *f_pos)
-{
- ssize_t retval;
- unsigned char *tmpbuf;
- struct rmidev_data *dev_data = filp->private_data;
-
- if (IS_ERR(dev_data)) {
- pr_err("%s: Pointer of char device data is invalid", __func__);
- return -EBADF;
- }
-
- mutex_lock(&(dev_data->file_mutex));
-
- if (*f_pos > REG_ADDR_LIMIT) {
- retval = -EFAULT;
- goto unlock;
- }
-
- if (count > (REG_ADDR_LIMIT - *f_pos))
- count = REG_ADDR_LIMIT - *f_pos;
-
- if (count == 0) {
- retval = 0;
- goto unlock;
- }
-
- tmpbuf = kzalloc(count + 1, GFP_KERNEL);
- if (!tmpbuf) {
- retval = -ENOMEM;
- goto unlock;
- }
-
- if (copy_from_user(tmpbuf, buf, count)) {
- retval = -EFAULT;
- goto clean_up;
- }
-
- retval = synaptics_rmi4_reg_write(rmidev->rmi4_data,
- *f_pos,
- tmpbuf,
- count);
- if (retval >= 0)
- *f_pos += retval;
-
-clean_up:
- kfree(tmpbuf);
-unlock:
- mutex_unlock(&(dev_data->file_mutex));
- return retval;
-}
-
-/*
- * rmidev_open: enable access to rmi device
- * @inp: inode struture
- * @filp: file structure
- */
-static int rmidev_open(struct inode *inp, struct file *filp)
-{
- int retval = 0;
- struct synaptics_rmi4_data *rmi4_data = rmidev->rmi4_data;
- struct rmidev_data *dev_data =
- container_of(inp->i_cdev, struct rmidev_data, main_dev);
-
- if (!dev_data)
- return -EACCES;
-
- filp->private_data = dev_data;
-
- mutex_lock(&(dev_data->file_mutex));
-
- rmi4_data->irq_enable(rmi4_data, false);
- dev_dbg(rmi4_data->pdev->dev.parent,
- "%s: Attention interrupt disabled\n",
- __func__);
-
- if (dev_data->ref_count < 1)
- dev_data->ref_count++;
- else
- retval = -EACCES;
-
- mutex_unlock(&(dev_data->file_mutex));
-
- return retval;
-}
-
-/*
- * rmidev_release: - release access to rmi device
- * @inp: inode structure
- * @filp: file structure
- */
-static int rmidev_release(struct inode *inp, struct file *filp)
-{
- struct synaptics_rmi4_data *rmi4_data = rmidev->rmi4_data;
- struct rmidev_data *dev_data =
- container_of(inp->i_cdev, struct rmidev_data, main_dev);
-
- if (!dev_data)
- return -EACCES;
-
- rmi4_data->reset_device(rmi4_data);
-
- mutex_lock(&(dev_data->file_mutex));
-
- dev_data->ref_count--;
- if (dev_data->ref_count < 0)
- dev_data->ref_count = 0;
-
- rmi4_data->irq_enable(rmi4_data, true);
- dev_dbg(rmi4_data->pdev->dev.parent,
- "%s: Attention interrupt enabled\n",
- __func__);
-
- mutex_unlock(&(dev_data->file_mutex));
-
- return 0;
-}
-
-static const struct file_operations rmidev_fops = {
- .owner = THIS_MODULE,
- .llseek = rmidev_llseek,
- .read = rmidev_read,
- .write = rmidev_write,
- .open = rmidev_open,
- .release = rmidev_release,
-};
-
-static void rmidev_device_cleanup(struct rmidev_data *dev_data)
-{
- dev_t devno;
- struct synaptics_rmi4_data *rmi4_data = rmidev->rmi4_data;
-
- if (dev_data) {
- devno = dev_data->main_dev.dev;
-
- if (dev_data->device_class)
- device_destroy(dev_data->device_class, devno);
-
- cdev_del(&dev_data->main_dev);
-
- unregister_chrdev_region(devno, 1);
-
- dev_dbg(rmi4_data->pdev->dev.parent,
- "%s: rmidev device removed\n",
- __func__);
- }
-
- return;
-}
-
-static char *rmi_char_devnode(struct device *dev, umode_t *mode)
-{
- if (!mode)
- return NULL;
-
- *mode = (S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH);
-
- return kasprintf(GFP_KERNEL, "rmi/%s", dev_name(dev));
-}
-
-static int rmidev_create_device_class(void)
-{
- rmidev_device_class = class_create(THIS_MODULE, DEVICE_CLASS_NAME);
-
- if (IS_ERR(rmidev_device_class)) {
- pr_err("%s: Failed to create /dev/%s\n",
- __func__, CHAR_DEVICE_NAME);
- return -ENODEV;
- }
-
- rmidev_device_class->devnode = rmi_char_devnode;
-
- return 0;
-}
-
-static int rmidev_init_device(struct synaptics_rmi4_data *rmi4_data)
-{
- int retval;
- dev_t dev_no;
- unsigned char attr_count;
- struct rmidev_data *dev_data;
- struct device *device_ptr;
- const struct synaptics_dsx_board_data *bdata =
- rmi4_data->hw_if->board_data;
-
- rmidev = kzalloc(sizeof(*rmidev), GFP_KERNEL);
- if (!rmidev) {
- dev_err(rmi4_data->pdev->dev.parent,
- "%s: Failed to alloc mem for rmidev\n",
- __func__);
- retval = -ENOMEM;
- goto err_rmidev;
- }
-
- rmidev->rmi4_data = rmi4_data;
-
- retval = rmidev_create_device_class();
- if (retval < 0) {
- dev_err(rmi4_data->pdev->dev.parent,
- "%s: Failed to create device class\n",
- __func__);
- goto err_device_class;
- }
-
- if (rmidev_major_num) {
- dev_no = MKDEV(rmidev_major_num, DEV_NUMBER);
- retval = register_chrdev_region(dev_no, 1, CHAR_DEVICE_NAME);
- } else {
- retval = alloc_chrdev_region(&dev_no, 0, 1, CHAR_DEVICE_NAME);
- if (retval < 0) {
- dev_err(rmi4_data->pdev->dev.parent,
- "%s: Failed to allocate char device region\n",
- __func__);
- goto err_device_region;
- }
-
- rmidev_major_num = MAJOR(dev_no);
- dev_dbg(rmi4_data->pdev->dev.parent,
- "%s: Major number of rmidev = %d\n",
- __func__, rmidev_major_num);
- }
-
- dev_data = kzalloc(sizeof(*dev_data), GFP_KERNEL);
- if (!dev_data) {
- dev_err(rmi4_data->pdev->dev.parent,
- "%s: Failed to alloc mem for dev_data\n",
- __func__);
- retval = -ENOMEM;
- goto err_dev_data;
- }
-
- mutex_init(&dev_data->file_mutex);
- dev_data->rmi_dev = rmidev;
- rmidev->data = dev_data;
-
- cdev_init(&dev_data->main_dev, &rmidev_fops);
-
- retval = cdev_add(&dev_data->main_dev, dev_no, 1);
- if (retval < 0) {
- dev_err(rmi4_data->pdev->dev.parent,
- "%s: Failed to add rmi char device\n",
- __func__);
- goto err_char_device;
- }
-
- dev_set_name(&rmidev->dev, "rmidev%d", MINOR(dev_no));
- dev_data->device_class = rmidev_device_class;
-
- device_ptr = device_create(dev_data->device_class, NULL, dev_no,
- NULL, CHAR_DEVICE_NAME"%d", MINOR(dev_no));
- if (IS_ERR(device_ptr)) {
- dev_err(rmi4_data->pdev->dev.parent,
- "%s: Failed to create rmi char device\n",
- __func__);
- retval = -ENODEV;
- goto err_char_device;
- }
-
- retval = gpio_export(bdata->irq_gpio, false);
- if (retval < 0) {
- dev_err(rmi4_data->pdev->dev.parent,
- "%s: Failed to export attention gpio\n",
- __func__);
- } else {
- retval = gpio_export_link(&(rmi4_data->input_dev->dev),
- "attn", bdata->irq_gpio);
- if (retval < 0) {
- dev_err(rmi4_data->pdev->dev.parent,
- "%s Failed to create gpio symlink\n",
- __func__);
- } else {
- dev_dbg(rmi4_data->pdev->dev.parent,
- "%s: Exported attention gpio %d\n",
- __func__, bdata->irq_gpio);
- }
- }
-
- rmidev->sysfs_dir = kobject_create_and_add(SYSFS_FOLDER_NAME,
- &rmi4_data->input_dev->dev.kobj);
- if (!rmidev->sysfs_dir) {
- dev_err(rmi4_data->pdev->dev.parent,
- "%s: Failed to create sysfs directory\n",
- __func__);
- retval = -ENODEV;
- goto err_sysfs_dir;
- }
-
- retval = sysfs_create_bin_file(rmidev->sysfs_dir,
- &attr_data);
- if (retval < 0) {
- dev_err(rmi4_data->pdev->dev.parent,
- "%s: Failed to create sysfs bin file\n",
- __func__);
- goto err_sysfs_bin;
- }
-
- for (attr_count = 0; attr_count < ARRAY_SIZE(attrs); attr_count++) {
- retval = sysfs_create_file(rmidev->sysfs_dir,
- &attrs[attr_count].attr);
- if (retval < 0) {
- dev_err(rmi4_data->pdev->dev.parent,
- "%s: Failed to create sysfs attributes\n",
- __func__);
- retval = -ENODEV;
- goto err_sysfs_attrs;
- }
- }
-
- return 0;
-
-err_sysfs_attrs:
- for (attr_count--; attr_count >= 0; attr_count--)
- sysfs_remove_file(rmidev->sysfs_dir, &attrs[attr_count].attr);
-
- sysfs_remove_bin_file(rmidev->sysfs_dir, &attr_data);
-
-err_sysfs_bin:
- kobject_put(rmidev->sysfs_dir);
-
-err_sysfs_dir:
-err_char_device:
- rmidev_device_cleanup(dev_data);
- kfree(dev_data);
-
-err_dev_data:
- unregister_chrdev_region(dev_no, 1);
-
-err_device_region:
- class_destroy(rmidev_device_class);
-
-err_device_class:
- kfree(rmidev);
- rmidev = NULL;
-
-err_rmidev:
- return retval;
-}
-
-static void rmidev_remove_device(struct synaptics_rmi4_data *rmi4_data)
-{
- unsigned char attr_count;
- struct rmidev_data *dev_data;
-
- if (!rmidev)
- goto exit;
-
- for (attr_count = 0; attr_count < ARRAY_SIZE(attrs); attr_count++)
- sysfs_remove_file(rmidev->sysfs_dir, &attrs[attr_count].attr);
-
- sysfs_remove_bin_file(rmidev->sysfs_dir, &attr_data);
-
- kobject_put(rmidev->sysfs_dir);
-
- dev_data = rmidev->data;
- if (dev_data) {
- rmidev_device_cleanup(dev_data);
- kfree(dev_data);
- }
-
- unregister_chrdev_region(rmidev->dev_no, 1);
-
- class_destroy(rmidev_device_class);
-
- kfree(rmidev);
- rmidev = NULL;
-
-exit:
- complete(&rmidev_remove_complete);
-
- return;
-}
-
-static struct synaptics_rmi4_exp_fn rmidev_module = {
- .fn_type = RMI_DEV,
- .init = rmidev_init_device,
- .remove = rmidev_remove_device,
- .reset = NULL,
- .reinit = NULL,
- .early_suspend = NULL,
- .suspend = NULL,
- .resume = NULL,
- .late_resume = NULL,
- .attn = NULL,
-};
-
-static int __init rmidev_module_init(void)
-{
- synaptics_rmi4_dsx_new_function(&rmidev_module, true);
-
- return 0;
-}
-
-static void __exit rmidev_module_exit(void)
-{
- synaptics_rmi4_dsx_new_function(&rmidev_module, false);
-
- wait_for_completion(&rmidev_remove_complete);
-
- return;
-}
-
-module_init(rmidev_module_init);
-module_exit(rmidev_module_exit);
-
-MODULE_AUTHOR("Synaptics, Inc.");
-MODULE_DESCRIPTION("Synaptics DSX RMI Dev Module");
-MODULE_LICENSE("GPL v2");
diff --git a/drivers/iommu/arm-smmu.c b/drivers/iommu/arm-smmu.c
index dc44b40a85f3..c6f74b149706 100644
--- a/drivers/iommu/arm-smmu.c
+++ b/drivers/iommu/arm-smmu.c
@@ -367,6 +367,8 @@ struct arm_smmu_device {
u32 num_mapping_groups;
DECLARE_BITMAP(smr_map, ARM_SMMU_MAX_SMRS);
+ u32 ubs;
+
unsigned long va_size;
unsigned long ipa_size;
unsigned long pa_size;
@@ -404,6 +406,7 @@ struct arm_smmu_device {
struct msm_bus_scale_pdata *bus_pdata;
enum tz_smmu_device_id sec_id;
+ int regulator_defer;
};
struct arm_smmu_cfg {
@@ -497,6 +500,19 @@ struct static_cbndx_entry {
u8 type;
};
+struct arm_iommus_node {
+ struct device_node *master;
+ struct list_head list;
+ struct list_head iommuspec_list;
+};
+
+struct arm_iommus_spec {
+ struct of_phandle_args iommu_spec;
+ struct list_head list;
+};
+
+static LIST_HEAD(iommus_nodes);
+
static int arm_smmu_enable_clocks_atomic(struct arm_smmu_device *smmu);
static void arm_smmu_disable_clocks_atomic(struct arm_smmu_device *smmu);
static void arm_smmu_prepare_pgtable(void *addr, void *cookie);
@@ -683,39 +699,40 @@ static int register_smmu_master(struct arm_smmu_device *smmu,
return insert_smmu_master(smmu, master);
}
-static int arm_smmu_parse_iommus_properties(struct arm_smmu_device *smmu,
- int *num_masters)
+static int arm_smmu_parse_iommus_properties(struct arm_smmu_device *smmu)
{
- struct of_phandle_args iommuspec;
- struct device_node *master;
+ struct arm_iommus_node *node, *nex;
- *num_masters = 0;
-
- for_each_node_with_property(master, "iommus") {
- int arg_ind = 0;
- struct iommus_entry *entry, *n;
+ list_for_each_entry_safe(node, nex, &iommus_nodes, list) {
+ struct iommus_entry *entry, *next;
+ struct arm_iommus_spec *iommuspec_node, *n;
LIST_HEAD(iommus);
+ int node_found = 0;
- while (!of_parse_phandle_with_args(
- master, "iommus", "#iommu-cells",
- arg_ind, &iommuspec)) {
- if (iommuspec.np != smmu->dev->of_node) {
- arg_ind++;
+ list_for_each_entry_safe(iommuspec_node, n,
+ &node->iommuspec_list, list) {
+ if (iommuspec_node->iommu_spec.np != smmu->dev->of_node)
continue;
- }
+
+ /*
+ * Since each master node will have iommu spec(s) of the
+ * same device, we can delete this master node after
+ * the devices are registered.
+ */
+ node_found = 1;
list_for_each_entry(entry, &iommus, list)
- if (entry->node == master)
+ if (entry->node == node->master)
break;
if (&entry->list == &iommus) {
entry = devm_kzalloc(smmu->dev, sizeof(*entry),
GFP_KERNEL);
if (!entry)
return -ENOMEM;
- entry->node = master;
+ entry->node = node->master;
list_add(&entry->list, &iommus);
}
- switch (iommuspec.args_count) {
+ switch (iommuspec_node->iommu_spec.args_count) {
case 0:
/*
* For pci-e devices the SIDs are provided
@@ -725,25 +742,29 @@ static int arm_smmu_parse_iommus_properties(struct arm_smmu_device *smmu,
case 1:
entry->num_sids++;
entry->streamids[entry->num_sids - 1]
- = iommuspec.args[0];
+ = iommuspec_node->iommu_spec.args[0];
break;
default:
BUG();
}
- arg_ind++;
+ list_del(&iommuspec_node->list);
+ kfree(iommuspec_node);
}
- list_for_each_entry_safe(entry, n, &iommus, list) {
+ list_for_each_entry_safe(entry, next, &iommus, list) {
int rc = register_smmu_master(smmu, entry);
- if (rc) {
+
+ if (rc)
dev_err(smmu->dev, "Couldn't register %s\n",
- entry->node->name);
- } else {
- (*num_masters)++;
- }
+ entry->node->name);
list_del(&entry->list);
devm_kfree(smmu->dev, entry);
}
+
+ if (node_found) {
+ list_del(&node->list);
+ kfree(node);
+ }
}
return 0;
@@ -932,7 +953,8 @@ static int arm_smmu_disable_regulators(struct arm_smmu_device *smmu)
arm_smmu_unprepare_clocks(smmu);
arm_smmu_unrequest_bus(smmu);
if (smmu->gdsc) {
- ret = regulator_disable(smmu->gdsc);
+ ret = regulator_disable_deferred(smmu->gdsc,
+ smmu->regulator_defer);
WARN(ret, "%s: Regulator disable failed\n",
dev_name(smmu->dev));
}
@@ -1736,6 +1758,7 @@ static int arm_smmu_init_domain_context(struct iommu_domain *domain,
{
int irq, start, ret = 0;
unsigned long ias, oas;
+ int sep = 0;
struct io_pgtable_ops *pgtbl_ops;
enum io_pgtable_fmt fmt;
struct arm_smmu_domain *smmu_domain = to_smmu_domain(domain);
@@ -1777,9 +1800,27 @@ static int arm_smmu_init_domain_context(struct iommu_domain *domain,
start = smmu->num_s2_context_banks;
ias = smmu->va_size;
oas = smmu->ipa_size;
- if (IS_ENABLED(CONFIG_64BIT))
+ if (IS_ENABLED(CONFIG_64BIT)) {
fmt = ARM_64_LPAE_S1;
- else
+
+ if (quirks & IO_PGTABLE_QUIRK_ARM_TTBR1) {
+
+ /*
+ * When the UBS id is 5 we know that the bus
+ * size is 49 bits and that bit 48 is the fixed
+ * sign extension bit. For any other bus size
+ * we need to specify the sign extension bit
+ * and adjust the input size accordingly
+ */
+
+ if (smmu->ubs == 5) {
+ sep = 48;
+ } else {
+ sep = ias - 1;
+ ias--;
+ }
+ }
+ } else
fmt = ARM_32_LPAE_S1;
break;
case ARM_SMMU_DOMAIN_NESTED:
@@ -1841,6 +1882,7 @@ static int arm_smmu_init_domain_context(struct iommu_domain *domain,
.pgsize_bitmap = arm_smmu_ops.pgsize_bitmap,
.ias = ias,
.oas = oas,
+ .sep = sep,
.tlb = &arm_smmu_gather_ops,
.iommu_dev = smmu->dev,
.iova_base = domain->geometry.aperture_start,
@@ -3592,6 +3634,12 @@ static int arm_smmu_init_regulators(struct arm_smmu_device *smmu)
if (!of_get_property(dev->of_node, "vdd-supply", NULL))
return 0;
+ if (!of_property_read_u32(dev->of_node,
+ "qcom,deferred-regulator-disable-delay",
+ &(smmu->regulator_defer)))
+ dev_info(dev, "regulator defer delay %d\n",
+ smmu->regulator_defer);
+
smmu->gdsc = devm_regulator_get(dev, "vdd");
if (IS_ERR(smmu->gdsc))
return PTR_ERR(smmu->gdsc);
@@ -3870,12 +3918,13 @@ static int arm_smmu_device_cfg_probe(struct arm_smmu_device *smmu)
smmu->va_size = smmu->ipa_size;
size = SZ_4K | SZ_2M | SZ_1G;
} else {
- size = (id >> ID2_UBS_SHIFT) & ID2_UBS_MASK;
- smmu->va_size = arm_smmu_id_size_to_bits(size);
+ smmu->ubs = (id >> ID2_UBS_SHIFT) & ID2_UBS_MASK;
+
+ smmu->va_size = arm_smmu_id_size_to_bits(smmu->ubs);
#ifndef CONFIG_64BIT
smmu->va_size = min(32UL, smmu->va_size);
#endif
- smmu->va_size = min(36UL, smmu->va_size);
+ smmu->va_size = min(39UL, smmu->va_size);
size = 0;
if (id & ID2_PTFS_4K)
size |= SZ_4K | SZ_2M | SZ_1G;
@@ -3973,7 +4022,7 @@ static int arm_smmu_device_dt_probe(struct platform_device *pdev)
struct arm_smmu_device *smmu;
struct device *dev = &pdev->dev;
struct rb_node *node;
- int num_irqs, i, err, num_masters;
+ int num_irqs, i, err;
smmu = devm_kzalloc(dev, sizeof(*smmu), GFP_KERNEL);
if (!smmu) {
@@ -4036,33 +4085,33 @@ static int arm_smmu_device_dt_probe(struct platform_device *pdev)
}
i = 0;
- smmu->masters = RB_ROOT;
- err = arm_smmu_parse_iommus_properties(smmu, &num_masters);
- if (err)
- goto out_put_masters;
-
- dev_dbg(dev, "registered %d master devices\n", num_masters);
err = arm_smmu_parse_impl_def_registers(smmu);
if (err)
- goto out_put_masters;
+ goto out;
err = arm_smmu_init_regulators(smmu);
if (err)
- goto out_put_masters;
+ goto out;
err = arm_smmu_init_clocks(smmu);
if (err)
- goto out_put_masters;
+ goto out;
err = arm_smmu_init_bus_scaling(pdev, smmu);
if (err)
- goto out_put_masters;
+ goto out;
parse_driver_options(smmu);
err = arm_smmu_enable_clocks(smmu);
if (err)
+ goto out;
+
+ /* No probe deferral occurred! Proceed with iommu property parsing. */
+ smmu->masters = RB_ROOT;
+ err = arm_smmu_parse_iommus_properties(smmu);
+ if (err)
goto out_put_masters;
smmu->sec_id = msm_dev_to_device_id(dev);
@@ -4122,7 +4171,7 @@ out_put_masters:
= container_of(node, struct arm_smmu_master, node);
of_node_put(master->of_node);
}
-
+out:
return err;
}
@@ -4173,6 +4222,58 @@ static int arm_smmu_device_remove(struct platform_device *pdev)
return 0;
}
+static void arm_smmu_free_master_nodes(void)
+{
+ struct arm_iommus_node *node, *nex;
+ struct arm_iommus_spec *entry, *n;
+
+ list_for_each_entry_safe(node, nex, &iommus_nodes, list) {
+ list_for_each_entry_safe(entry, n,
+ &node->iommuspec_list, list) {
+ list_del(&entry->list);
+ kfree(entry);
+ }
+ list_del(&node->list);
+ kfree(node);
+ }
+}
+
+static int arm_smmu_get_master_nodes(void)
+{
+ struct arm_iommus_node *node;
+ struct device_node *master;
+ struct of_phandle_args iommuspec;
+ struct arm_iommus_spec *entry;
+
+ for_each_node_with_property(master, "iommus") {
+ int arg_ind = 0;
+
+ node = kzalloc(sizeof(*node), GFP_KERNEL);
+ if (!node)
+ goto release_memory;
+ node->master = master;
+ list_add(&node->list, &iommus_nodes);
+
+ INIT_LIST_HEAD(&node->iommuspec_list);
+
+ while (!of_parse_phandle_with_args(master, "iommus",
+ "#iommu-cells", arg_ind, &iommuspec)) {
+ entry = kzalloc(sizeof(*entry), GFP_KERNEL);
+ if (!entry)
+ goto release_memory;
+ entry->iommu_spec = iommuspec;
+ list_add(&entry->list, &node->iommuspec_list);
+ arg_ind++;
+ }
+ }
+
+ return 0;
+
+release_memory:
+ arm_smmu_free_master_nodes();
+ return -ENOMEM;
+}
+
static struct platform_driver arm_smmu_driver = {
.driver = {
.name = "arm-smmu",
@@ -4198,10 +4299,15 @@ static int __init arm_smmu_init(void)
of_node_put(np);
- ret = platform_driver_register(&arm_smmu_driver);
+ ret = arm_smmu_get_master_nodes();
if (ret)
return ret;
+ ret = platform_driver_register(&arm_smmu_driver);
+ if (ret) {
+ arm_smmu_free_master_nodes();
+ return ret;
+ }
/* Oh, for a proper bus abstraction */
if (!iommu_present(&platform_bus_type))
bus_set_iommu(&platform_bus_type, &arm_smmu_ops);
diff --git a/drivers/iommu/io-pgtable-arm.c b/drivers/iommu/io-pgtable-arm.c
index 2d2583c78bdb..7651545e3f2e 100644
--- a/drivers/iommu/io-pgtable-arm.c
+++ b/drivers/iommu/io-pgtable-arm.c
@@ -550,9 +550,18 @@ static inline arm_lpae_iopte *arm_lpae_get_table(
{
struct io_pgtable_cfg *cfg = &data->iop.cfg;
- return ((cfg->quirks & IO_PGTABLE_QUIRK_ARM_TTBR1) &&
- (iova & (1UL << (cfg->ias - 1)))) ?
- data->pgd[1] : data->pgd[0];
+ /*
+ * iovas for TTBR1 will have all the bits set between the input address
+ * region and the sign extension bit
+ */
+ if (unlikely(cfg->quirks & IO_PGTABLE_QUIRK_ARM_TTBR1)) {
+ unsigned long mask = GENMASK(cfg->sep, cfg->ias);
+
+ if ((iova & mask) == mask)
+ return data->pgd[1];
+ }
+
+ return data->pgd[0];
}
static int arm_lpae_map(struct io_pgtable_ops *ops, unsigned long iova,
@@ -1089,26 +1098,26 @@ static u64 arm64_lpae_setup_ttbr1(struct io_pgtable_cfg *cfg,
/* Set T1SZ */
reg |= (64ULL - cfg->ias) << ARM_LPAE_TCR_T1SZ_SHIFT;
- /* Set the SEP bit based on the size */
- switch (cfg->ias) {
- case 32:
+ switch (cfg->sep) {
+ case 31:
reg |= (ARM_LPAE_TCR_SEP_31 << ARM_LPAE_TCR_SEP_SHIFT);
break;
- case 36:
+ case 35:
reg |= (ARM_LPAE_TCR_SEP_35 << ARM_LPAE_TCR_SEP_SHIFT);
break;
- case 40:
+ case 39:
reg |= (ARM_LPAE_TCR_SEP_39 << ARM_LPAE_TCR_SEP_SHIFT);
break;
- case 42:
+ case 41:
reg |= (ARM_LPAE_TCR_SEP_41 << ARM_LPAE_TCR_SEP_SHIFT);
break;
- case 44:
+ case 43:
reg |= (ARM_LPAE_TCR_SEP_43 << ARM_LPAE_TCR_SEP_SHIFT);
break;
- case 48:
+ case 47:
reg |= (ARM_LPAE_TCR_SEP_47 << ARM_LPAE_TCR_SEP_SHIFT);
break;
+ case 48:
default:
reg |= (ARM_LPAE_TCR_SEP_UPSTREAM << ARM_LPAE_TCR_SEP_SHIFT);
break;
diff --git a/drivers/iommu/io-pgtable.h b/drivers/iommu/io-pgtable.h
index 2cf213514221..0326bb6a4afa 100644
--- a/drivers/iommu/io-pgtable.h
+++ b/drivers/iommu/io-pgtable.h
@@ -67,6 +67,7 @@ struct io_pgtable_cfg {
unsigned long pgsize_bitmap;
unsigned int ias;
unsigned int oas;
+ int sep;
const struct iommu_gather_ops *tlb;
struct device *iommu_dev;
dma_addr_t iova_base;
diff --git a/drivers/iommu/iommu-debug.c b/drivers/iommu/iommu-debug.c
index 776e06facc11..c21846c1f8d5 100644
--- a/drivers/iommu/iommu-debug.c
+++ b/drivers/iommu/iommu-debug.c
@@ -28,6 +28,7 @@
#include <linux/dma-mapping.h>
#include <asm/cacheflush.h>
#include <asm/dma-iommu.h>
+#include "iommu-debug.h"
#if defined(CONFIG_IOMMU_DEBUG_TRACKING) || defined(CONFIG_IOMMU_TESTS)
@@ -84,371 +85,58 @@ static const char *iommu_debug_attr_to_string(enum iommu_attr attr)
static DEFINE_MUTEX(iommu_debug_attachments_lock);
static LIST_HEAD(iommu_debug_attachments);
-static struct dentry *debugfs_attachments_dir;
+/*
+ * Each group may have more than one domain; but each domain may
+ * only have one group.
+ * Used by debug tools to display the name of the device(s) associated
+ * with a particular domain.
+ */
struct iommu_debug_attachment {
struct iommu_domain *domain;
- struct device *dev;
- struct dentry *dentry;
+ struct iommu_group *group;
struct list_head list;
- unsigned long reg_offset;
};
-static int iommu_debug_attachment_info_show(struct seq_file *s, void *ignored)
-{
- struct iommu_debug_attachment *attach = s->private;
- phys_addr_t pt_phys;
- int secure_vmid;
-
- seq_printf(s, "Domain: 0x%p\n", attach->domain);
- if (iommu_domain_get_attr(attach->domain, DOMAIN_ATTR_PT_BASE_ADDR,
- &pt_phys)) {
- seq_puts(s, "PT_BASE_ADDR: (Unknown)\n");
- } else {
- void *pt_virt = phys_to_virt(pt_phys);
-
- seq_printf(s, "PT_BASE_ADDR: virt=0x%p phys=%pa\n",
- pt_virt, &pt_phys);
- }
-
- seq_puts(s, "SECURE_VMID: ");
- if (iommu_domain_get_attr(attach->domain,
- DOMAIN_ATTR_SECURE_VMID,
- &secure_vmid))
- seq_puts(s, "(Unknown)\n");
- else
- seq_printf(s, "%s (0x%x)\n",
- msm_secure_vmid_to_string(secure_vmid), secure_vmid);
-
- return 0;
-}
-
-static int iommu_debug_attachment_info_open(struct inode *inode,
- struct file *file)
-{
- return single_open(file, iommu_debug_attachment_info_show,
- inode->i_private);
-}
-
-static const struct file_operations iommu_debug_attachment_info_fops = {
- .open = iommu_debug_attachment_info_open,
- .read = seq_read,
- .llseek = seq_lseek,
- .release = single_release,
-};
-
-static ssize_t iommu_debug_attachment_trigger_fault_write(
- struct file *file, const char __user *ubuf, size_t count,
- loff_t *offset)
-{
- struct iommu_debug_attachment *attach = file->private_data;
- unsigned long flags;
-
- if (kstrtoul_from_user(ubuf, count, 0, &flags)) {
- pr_err("Invalid flags format\n");
- return -EFAULT;
- }
-
- iommu_trigger_fault(attach->domain, flags);
-
- return count;
-}
-
-static const struct file_operations
-iommu_debug_attachment_trigger_fault_fops = {
- .open = simple_open,
- .write = iommu_debug_attachment_trigger_fault_write,
-};
-
-static ssize_t iommu_debug_attachment_reg_offset_write(
- struct file *file, const char __user *ubuf, size_t count,
- loff_t *offset)
-{
- struct iommu_debug_attachment *attach = file->private_data;
- unsigned long reg_offset;
-
- if (kstrtoul_from_user(ubuf, count, 0, &reg_offset)) {
- pr_err("Invalid reg_offset format\n");
- return -EFAULT;
- }
-
- attach->reg_offset = reg_offset;
-
- return count;
-}
-
-static const struct file_operations iommu_debug_attachment_reg_offset_fops = {
- .open = simple_open,
- .write = iommu_debug_attachment_reg_offset_write,
-};
-
-static ssize_t iommu_debug_attachment_reg_read_read(
- struct file *file, char __user *ubuf, size_t count, loff_t *offset)
-{
- struct iommu_debug_attachment *attach = file->private_data;
- unsigned long val;
- char *val_str;
- ssize_t val_str_len;
-
- if (*offset)
- return 0;
-
- val = iommu_reg_read(attach->domain, attach->reg_offset);
- val_str = kasprintf(GFP_KERNEL, "0x%lx\n", val);
- if (!val_str)
- return -ENOMEM;
- val_str_len = strlen(val_str);
-
- if (copy_to_user(ubuf, val_str, val_str_len)) {
- pr_err("copy_to_user failed\n");
- val_str_len = -EFAULT;
- goto out;
- }
- *offset = 1; /* non-zero means we're done */
-
-out:
- kfree(val_str);
- return val_str_len;
-}
-
-static const struct file_operations iommu_debug_attachment_reg_read_fops = {
- .open = simple_open,
- .read = iommu_debug_attachment_reg_read_read,
-};
-
-static ssize_t iommu_debug_attachment_reg_write_write(
- struct file *file, const char __user *ubuf, size_t count,
- loff_t *offset)
-{
- struct iommu_debug_attachment *attach = file->private_data;
- unsigned long val;
-
- if (kstrtoul_from_user(ubuf, count, 0, &val)) {
- pr_err("Invalid val format\n");
- return -EFAULT;
- }
-
- iommu_reg_write(attach->domain, attach->reg_offset, val);
-
- return count;
-}
-
-static const struct file_operations iommu_debug_attachment_reg_write_fops = {
- .open = simple_open,
- .write = iommu_debug_attachment_reg_write_write,
-};
-
-/* should be called with iommu_debug_attachments_lock locked */
-static int iommu_debug_attach_add_debugfs(
- struct iommu_debug_attachment *attach)
-{
- const char *attach_name;
- struct device *dev = attach->dev;
- struct iommu_domain *domain = attach->domain;
- int is_dynamic;
-
- if (iommu_domain_get_attr(domain, DOMAIN_ATTR_DYNAMIC, &is_dynamic))
- is_dynamic = 0;
-
- if (is_dynamic) {
- uuid_le uuid;
-
- uuid_le_gen(&uuid);
- attach_name = kasprintf(GFP_KERNEL, "%s-%pUl", dev_name(dev),
- uuid.b);
- if (!attach_name)
- return -ENOMEM;
- } else {
- attach_name = dev_name(dev);
- }
-
- attach->dentry = debugfs_create_dir(attach_name,
- debugfs_attachments_dir);
- if (!attach->dentry) {
- pr_err("Couldn't create iommu/attachments/%s debugfs directory for domain 0x%p\n",
- attach_name, domain);
- if (is_dynamic)
- kfree(attach_name);
- return -EIO;
- }
-
- if (is_dynamic)
- kfree(attach_name);
-
- if (!debugfs_create_file(
- "info", S_IRUSR, attach->dentry, attach,
- &iommu_debug_attachment_info_fops)) {
- pr_err("Couldn't create iommu/attachments/%s/info debugfs file for domain 0x%p\n",
- dev_name(dev), domain);
- goto err_rmdir;
- }
-
- if (!debugfs_create_file(
- "trigger_fault", S_IRUSR, attach->dentry, attach,
- &iommu_debug_attachment_trigger_fault_fops)) {
- pr_err("Couldn't create iommu/attachments/%s/trigger_fault debugfs file for domain 0x%p\n",
- dev_name(dev), domain);
- goto err_rmdir;
- }
-
- if (!debugfs_create_file(
- "reg_offset", S_IRUSR, attach->dentry, attach,
- &iommu_debug_attachment_reg_offset_fops)) {
- pr_err("Couldn't create iommu/attachments/%s/reg_offset debugfs file for domain 0x%p\n",
- dev_name(dev), domain);
- goto err_rmdir;
- }
-
- if (!debugfs_create_file(
- "reg_read", S_IRUSR, attach->dentry, attach,
- &iommu_debug_attachment_reg_read_fops)) {
- pr_err("Couldn't create iommu/attachments/%s/reg_read debugfs file for domain 0x%p\n",
- dev_name(dev), domain);
- goto err_rmdir;
- }
-
- if (!debugfs_create_file(
- "reg_write", S_IRUSR, attach->dentry, attach,
- &iommu_debug_attachment_reg_write_fops)) {
- pr_err("Couldn't create iommu/attachments/%s/reg_write debugfs file for domain 0x%p\n",
- dev_name(dev), domain);
- goto err_rmdir;
- }
-
- return 0;
-
-err_rmdir:
- debugfs_remove_recursive(attach->dentry);
- return -EIO;
-}
-
-void iommu_debug_domain_add(struct iommu_domain *domain)
+void iommu_debug_attach_device(struct iommu_domain *domain,
+ struct device *dev)
{
struct iommu_debug_attachment *attach;
+ struct iommu_group *group;
- mutex_lock(&iommu_debug_attachments_lock);
+ group = iommu_group_get(dev);
+ if (!group)
+ return;
- attach = kmalloc(sizeof(*attach), GFP_KERNEL);
+ attach = kzalloc(sizeof(*attach), GFP_KERNEL);
if (!attach)
- goto out_unlock;
+ return;
attach->domain = domain;
- attach->dev = NULL;
- list_add(&attach->list, &iommu_debug_attachments);
+ attach->group = group;
+ INIT_LIST_HEAD(&attach->list);
-out_unlock:
+ mutex_lock(&iommu_debug_attachments_lock);
+ list_add(&attach->list, &iommu_debug_attachments);
mutex_unlock(&iommu_debug_attachments_lock);
}
void iommu_debug_domain_remove(struct iommu_domain *domain)
{
- struct iommu_debug_attachment *it;
+ struct iommu_debug_attachment *it, *tmp;
mutex_lock(&iommu_debug_attachments_lock);
- list_for_each_entry(it, &iommu_debug_attachments, list)
- if (it->domain == domain && it->dev == NULL)
- break;
-
- if (&it->list == &iommu_debug_attachments) {
- WARN(1, "Couldn't find debug attachment for domain=0x%p",
- domain);
- } else {
+ list_for_each_entry_safe(it, tmp, &iommu_debug_attachments, list) {
+ if (it->domain != domain)
+ continue;
list_del(&it->list);
+ iommu_group_put(it->group);
kfree(it);
}
- mutex_unlock(&iommu_debug_attachments_lock);
-}
-
-void iommu_debug_attach_device(struct iommu_domain *domain,
- struct device *dev)
-{
- struct iommu_debug_attachment *attach;
-
- mutex_lock(&iommu_debug_attachments_lock);
-
- list_for_each_entry(attach, &iommu_debug_attachments, list)
- if (attach->domain == domain && attach->dev == NULL)
- break;
-
- if (&attach->list == &iommu_debug_attachments) {
- WARN(1, "Couldn't find debug attachment for domain=0x%p dev=%s",
- domain, dev_name(dev));
- } else {
- attach->dev = dev;
-
- /*
- * we might not init until after other drivers start calling
- * iommu_attach_device. Only set up the debugfs nodes if we've
- * already init'd to avoid polluting the top-level debugfs
- * directory (by calling debugfs_create_dir with a NULL
- * parent). These will be flushed out later once we init.
- */
-
- if (debugfs_attachments_dir)
- iommu_debug_attach_add_debugfs(attach);
- }
-
- mutex_unlock(&iommu_debug_attachments_lock);
-}
-
-void iommu_debug_detach_device(struct iommu_domain *domain,
- struct device *dev)
-{
- struct iommu_debug_attachment *it;
-
- mutex_lock(&iommu_debug_attachments_lock);
- list_for_each_entry(it, &iommu_debug_attachments, list)
- if (it->domain == domain && it->dev == dev)
- break;
-
- if (&it->list == &iommu_debug_attachments) {
- WARN(1, "Couldn't find debug attachment for domain=0x%p dev=%s",
- domain, dev_name(dev));
- } else {
- /*
- * Just remove debugfs entry and mark dev as NULL on
- * iommu_detach call. We would remove the actual
- * attachment entry from the list only on domain_free call.
- * This is to ensure we keep track of unattached domains too.
- */
-
- debugfs_remove_recursive(it->dentry);
- it->dev = NULL;
- }
- mutex_unlock(&iommu_debug_attachments_lock);
-}
-
-static int iommu_debug_init_tracking(void)
-{
- int ret = 0;
- struct iommu_debug_attachment *attach;
-
- mutex_lock(&iommu_debug_attachments_lock);
- debugfs_attachments_dir = debugfs_create_dir("attachments",
- iommu_debugfs_top);
- if (!debugfs_attachments_dir) {
- pr_err("Couldn't create iommu/attachments debugfs directory\n");
- ret = -ENODEV;
- goto out_unlock;
- }
-
- /* set up debugfs entries for attachments made during early boot */
- list_for_each_entry(attach, &iommu_debug_attachments, list)
- if (attach->dev)
- iommu_debug_attach_add_debugfs(attach);
-out_unlock:
mutex_unlock(&iommu_debug_attachments_lock);
- return ret;
}
-static void iommu_debug_destroy_tracking(void)
-{
- debugfs_remove_recursive(debugfs_attachments_dir);
-}
-#else
-static inline int iommu_debug_init_tracking(void) { return 0; }
-static inline void iommu_debug_destroy_tracking(void) { }
#endif
#ifdef CONFIG_IOMMU_TESTS
@@ -479,6 +167,8 @@ struct iommu_debug_device {
u64 phys;
size_t len;
struct list_head list;
+ struct mutex clk_lock;
+ unsigned int clk_count;
};
static int iommu_debug_build_phoney_sg_table(struct device *dev,
@@ -1518,6 +1208,7 @@ static int iommu_debug_attach_do_attach(struct iommu_debug_device *ddev,
return -ENOMEM;
}
+ val = VMID_CP_CAMERA;
if (is_secure && iommu_domain_set_attr(ddev->domain,
DOMAIN_ATTR_SECURE_VMID,
&val)) {
@@ -1800,6 +1491,10 @@ static ssize_t iommu_debug_pte_read(struct file *file, char __user *ubuf,
ssize_t retval;
size_t buflen;
+ if (kptr_restrict != 0) {
+ pr_err("kptr_restrict needs to be disabled.\n");
+ return -EPERM;
+ }
if (!dev->archdata.mapping) {
pr_err("No mapping. Did you already attach?\n");
return -EINVAL;
@@ -1867,6 +1562,10 @@ static ssize_t iommu_debug_atos_read(struct file *file, char __user *ubuf,
ssize_t retval;
size_t buflen;
+ if (kptr_restrict != 0) {
+ pr_err("kptr_restrict needs to be disabled.\n");
+ return -EPERM;
+ }
if (!ddev->domain) {
pr_err("No domain. Did you already attach?\n");
return -EINVAL;
@@ -1915,6 +1614,10 @@ static ssize_t iommu_debug_dma_atos_read(struct file *file, char __user *ubuf,
ssize_t retval;
size_t buflen;
+ if (kptr_restrict != 0) {
+ pr_err("kptr_restrict needs to be disabled.\n");
+ return -EPERM;
+ }
if (!dev->archdata.mapping) {
pr_err("No mapping. Did you already attach?\n");
return -EINVAL;
@@ -2355,20 +2058,34 @@ static ssize_t iommu_debug_config_clocks_write(struct file *file,
return -EFAULT;
}
+ mutex_lock(&ddev->clk_lock);
switch (buf) {
case '0':
+ if (ddev->clk_count == 0) {
+ dev_err(dev, "Config clocks already disabled\n");
+ break;
+ }
+
+ if (--ddev->clk_count > 0)
+ break;
+
dev_err(dev, "Disabling config clocks\n");
iommu_disable_config_clocks(ddev->domain);
break;
case '1':
+ if (ddev->clk_count++ > 0)
+ break;
+
dev_err(dev, "Enabling config clocks\n");
if (iommu_enable_config_clocks(ddev->domain))
dev_err(dev, "Failed!\n");
break;
default:
dev_err(dev, "Invalid value. Should be 0 or 1.\n");
+ mutex_unlock(&ddev->clk_lock);
return -EINVAL;
}
+ mutex_unlock(&ddev->clk_lock);
return count;
}
@@ -2394,6 +2111,7 @@ static int snarf_iommu_devices(struct device *dev, const char *name)
ddev = kzalloc(sizeof(*ddev), GFP_KERNEL);
if (!ddev)
return -ENODEV;
+ mutex_init(&ddev->clk_lock);
ddev->dev = dev;
dir = debugfs_create_dir(name, debugfs_tests_dir);
if (!dir) {
@@ -2547,6 +2265,9 @@ err:
static int pass_iommu_devices(struct device *dev, void *ignored)
{
+ if (!of_device_is_compatible(dev->of_node, "iommu-debug-test"))
+ return 0;
+
if (!of_find_property(dev->of_node, "iommus", NULL))
return 0;
@@ -2560,6 +2281,9 @@ static int iommu_debug_populate_devices(void)
const char *cb_name;
for_each_compatible_node(np, NULL, "qcom,msm-smmu-v2-ctx") {
+ if (!of_device_is_compatible(np, "iommu-debug-test"))
+ continue;
+
ret = of_property_read_string(np, "label", &cb_name);
if (ret)
return ret;
@@ -2625,9 +2349,6 @@ static struct platform_driver iommu_debug_driver = {
static int iommu_debug_init(void)
{
- if (iommu_debug_init_tracking())
- return -ENODEV;
-
if (iommu_debug_init_tests())
return -ENODEV;
@@ -2637,7 +2358,6 @@ static int iommu_debug_init(void)
static void iommu_debug_exit(void)
{
platform_driver_unregister(&iommu_debug_driver);
- iommu_debug_destroy_tracking();
iommu_debug_destroy_tests();
}
diff --git a/drivers/iommu/iommu-debug.h b/drivers/iommu/iommu-debug.h
index 3dc87032f2a0..91c418d9e37f 100644
--- a/drivers/iommu/iommu-debug.h
+++ b/drivers/iommu/iommu-debug.h
@@ -1,11 +1,21 @@
+/* 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.
+ */
+
#ifndef IOMMU_DEBUG_H
#define IOMMU_DEBUG_H
#ifdef CONFIG_IOMMU_DEBUG_TRACKING
void iommu_debug_attach_device(struct iommu_domain *domain, struct device *dev);
-void iommu_debug_detach_device(struct iommu_domain *domain, struct device *dev);
-void iommu_debug_domain_add(struct iommu_domain *domain);
void iommu_debug_domain_remove(struct iommu_domain *domain);
#else /* !CONFIG_IOMMU_DEBUG_TRACKING */
@@ -15,15 +25,6 @@ static inline void iommu_debug_attach_device(struct iommu_domain *domain,
{
}
-static inline void iommu_debug_detach_device(struct iommu_domain *domain,
- struct device *dev)
-{
-}
-
-static inline void iommu_debug_domain_add(struct iommu_domain *domain)
-{
-}
-
static inline void iommu_debug_domain_remove(struct iommu_domain *domain)
{
}
diff --git a/drivers/iommu/iommu.c b/drivers/iommu/iommu.c
index b831796b5b7d..33176a4aa6ef 100644
--- a/drivers/iommu/iommu.c
+++ b/drivers/iommu/iommu.c
@@ -1118,8 +1118,6 @@ static struct iommu_domain *__iommu_domain_alloc(struct bus_type *bus,
domain->ops = bus->iommu_ops;
domain->type = type;
- iommu_debug_domain_add(domain);
-
return domain;
}
@@ -1186,7 +1184,6 @@ static void __iommu_detach_device(struct iommu_domain *domain,
if (unlikely(domain->ops->detach_dev == NULL))
return;
- iommu_debug_detach_device(domain, dev);
domain->ops->detach_dev(domain, dev);
trace_detach_device_from_domain(dev);
}
diff --git a/drivers/leds/leds-qpnp-flash-v2.c b/drivers/leds/leds-qpnp-flash-v2.c
index a89a92d253ac..564d20079715 100644
--- a/drivers/leds/leds-qpnp-flash-v2.c
+++ b/drivers/leds/leds-qpnp-flash-v2.c
@@ -721,7 +721,8 @@ static int qpnp_flash_led_get_voltage_headroom(struct qpnp_flash_led *led)
#define VIN_FLASH_MIN_UV 3300000LL
static int qpnp_flash_led_calc_max_current(struct qpnp_flash_led *led)
{
- int ocv_uv, rbatt_uohm, ibat_now, voltage_hdrm_mv, rc;
+ int ocv_uv = 0, rbatt_uohm = 0, ibat_now = 0, voltage_hdrm_mv = 0;
+ int rc = 0;
int64_t ibat_flash_ua, avail_flash_ua, avail_flash_power_fw;
int64_t ibat_safe_ua, vin_flash_uv, vph_flash_uv, vph_flash_vdip;
diff --git a/drivers/md/dm-android-verity.c b/drivers/md/dm-android-verity.c
index 7cef735a01a7..4f6086970131 100644
--- a/drivers/md/dm-android-verity.c
+++ b/drivers/md/dm-android-verity.c
@@ -691,7 +691,7 @@ static int android_verity_ctr(struct dm_target *ti, unsigned argc, char **argv)
dev_t uninitialized_var(dev);
struct android_metadata *metadata = NULL;
int err = 0, i, mode;
- char *key_id, *table_ptr, dummy, *target_device,
+ char *key_id = NULL, *table_ptr, dummy, *target_device,
*verity_table_args[VERITY_TABLE_ARGS + 2 + VERITY_TABLE_OPT_FEC_ARGS];
/* One for specifying number of opt args and one for mode */
sector_t data_sectors;
diff --git a/drivers/md/dm.c b/drivers/md/dm.c
index 5d42d8f09421..1a7b11d57256 100644
--- a/drivers/md/dm.c
+++ b/drivers/md/dm.c
@@ -2191,8 +2191,11 @@ static void dm_request_fn(struct request_queue *q)
tio = tio_from_request(rq);
/* Establish tio->ti before queuing work (map_tio_request) */
tio->ti = ti;
- queue_kthread_work(&md->kworker, &tio->work);
+ spin_unlock(q->queue_lock);
+ if (map_request(tio, rq, md) == DM_MAPIO_REQUEUE)
+ dm_requeue_original_request(md, rq);
BUG_ON(!irqs_disabled());
+ spin_lock(q->queue_lock);
}
goto out;
diff --git a/drivers/media/Kconfig b/drivers/media/Kconfig
index 0b219a81e8a2..c1b999c6cff2 100644
--- a/drivers/media/Kconfig
+++ b/drivers/media/Kconfig
@@ -99,6 +99,10 @@ config MEDIA_CEC_DEBUG
config MEDIA_CEC_EDID
bool
+config MEDIA_CEC_NOTIFIER
+ bool
+ select MEDIA_CEC_EDID
+
#
# Media controller
# Selectable only for webcam/grabbers, as other drivers don't use it
diff --git a/drivers/media/Makefile b/drivers/media/Makefile
index ba516dcbc6aa..6c7801919b98 100644
--- a/drivers/media/Makefile
+++ b/drivers/media/Makefile
@@ -10,6 +10,10 @@ ifeq ($(CONFIG_MEDIA_CEC_SUPPORT),y)
obj-$(CONFIG_MEDIA_SUPPORT) += cec/
endif
+ifeq ($(CONFIG_MEDIA_CEC_NOTIFIER),y)
+ obj-$(CONFIG_MEDIA_SUPPORT) += cec-notifier.o
+endif
+
media-objs := media-device.o media-devnode.o media-entity.o
#
diff --git a/drivers/media/cec-notifier.c b/drivers/media/cec-notifier.c
new file mode 100644
index 000000000000..5f5209a73665
--- /dev/null
+++ b/drivers/media/cec-notifier.c
@@ -0,0 +1,129 @@
+/*
+ * cec-notifier.c - notify CEC drivers of physical address changes
+ *
+ * Copyright 2016 Russell King <rmk+kernel@arm.linux.org.uk>
+ * Copyright 2016-2017 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
+ *
+ * This program is free software; you may redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include <linux/export.h>
+#include <linux/string.h>
+#include <linux/slab.h>
+#include <linux/list.h>
+#include <linux/kref.h>
+
+#include <media/cec-notifier.h>
+#include <drm/drm_edid.h>
+
+struct cec_notifier {
+ struct mutex lock;
+ struct list_head head;
+ struct kref kref;
+ struct device *dev;
+ struct cec_adapter *cec_adap;
+ void (*callback)(struct cec_adapter *adap, u16 pa);
+
+ u16 phys_addr;
+};
+
+static LIST_HEAD(cec_notifiers);
+static DEFINE_MUTEX(cec_notifiers_lock);
+
+struct cec_notifier *cec_notifier_get(struct device *dev)
+{
+ struct cec_notifier *n;
+
+ mutex_lock(&cec_notifiers_lock);
+ list_for_each_entry(n, &cec_notifiers, head) {
+ if (n->dev == dev) {
+ kref_get(&n->kref);
+ mutex_unlock(&cec_notifiers_lock);
+ return n;
+ }
+ }
+ n = kzalloc(sizeof(*n), GFP_KERNEL);
+ if (!n)
+ goto unlock;
+ n->dev = dev;
+ n->phys_addr = CEC_PHYS_ADDR_INVALID;
+ mutex_init(&n->lock);
+ kref_init(&n->kref);
+ list_add_tail(&n->head, &cec_notifiers);
+unlock:
+ mutex_unlock(&cec_notifiers_lock);
+ return n;
+}
+EXPORT_SYMBOL_GPL(cec_notifier_get);
+
+static void cec_notifier_release(struct kref *kref)
+{
+ struct cec_notifier *n =
+ container_of(kref, struct cec_notifier, kref);
+
+ list_del(&n->head);
+ kfree(n);
+}
+
+void cec_notifier_put(struct cec_notifier *n)
+{
+ mutex_lock(&cec_notifiers_lock);
+ kref_put(&n->kref, cec_notifier_release);
+ mutex_unlock(&cec_notifiers_lock);
+}
+EXPORT_SYMBOL_GPL(cec_notifier_put);
+
+void cec_notifier_set_phys_addr(struct cec_notifier *n, u16 pa)
+{
+ mutex_lock(&n->lock);
+ n->phys_addr = pa;
+ if (n->callback)
+ n->callback(n->cec_adap, n->phys_addr);
+ mutex_unlock(&n->lock);
+}
+EXPORT_SYMBOL_GPL(cec_notifier_set_phys_addr);
+
+void cec_notifier_set_phys_addr_from_edid(struct cec_notifier *n,
+ const struct edid *edid)
+{
+ u16 pa = CEC_PHYS_ADDR_INVALID;
+
+ if (edid && edid->extensions)
+ pa = cec_get_edid_phys_addr((const u8 *)edid,
+ EDID_LENGTH * (edid->extensions + 1), NULL);
+ cec_notifier_set_phys_addr(n, pa);
+}
+EXPORT_SYMBOL_GPL(cec_notifier_set_phys_addr_from_edid);
+
+void cec_notifier_register(struct cec_notifier *n,
+ struct cec_adapter *adap,
+ void (*callback)(struct cec_adapter *adap, u16 pa))
+{
+ kref_get(&n->kref);
+ mutex_lock(&n->lock);
+ n->cec_adap = adap;
+ n->callback = callback;
+ n->callback(adap, n->phys_addr);
+ mutex_unlock(&n->lock);
+}
+EXPORT_SYMBOL_GPL(cec_notifier_register);
+
+void cec_notifier_unregister(struct cec_notifier *n)
+{
+ mutex_lock(&n->lock);
+ n->callback = NULL;
+ mutex_unlock(&n->lock);
+ cec_notifier_put(n);
+}
+EXPORT_SYMBOL_GPL(cec_notifier_unregister);
diff --git a/drivers/media/cec/cec-core.c b/drivers/media/cec/cec-core.c
index aca3ab83a8a1..61adc28ec8ec 100644
--- a/drivers/media/cec/cec-core.c
+++ b/drivers/media/cec/cec-core.c
@@ -195,6 +195,24 @@ static void cec_devnode_unregister(struct cec_devnode *devnode)
put_device(&devnode->dev);
}
+#ifdef CONFIG_MEDIA_CEC_NOTIFIER
+static void cec_cec_notify(struct cec_adapter *adap, u16 pa)
+{
+ cec_s_phys_addr(adap, pa, false);
+}
+
+void cec_register_cec_notifier(struct cec_adapter *adap,
+ struct cec_notifier *notifier)
+{
+ if (WARN_ON(!adap->devnode.registered))
+ return;
+
+ adap->notifier = notifier;
+ cec_notifier_register(adap->notifier, adap, cec_cec_notify);
+}
+EXPORT_SYMBOL_GPL(cec_register_cec_notifier);
+#endif
+
struct cec_adapter *cec_allocate_adapter(const struct cec_adap_ops *ops,
void *priv, const char *name, u32 caps,
u8 available_las)
@@ -344,6 +362,10 @@ void cec_unregister_adapter(struct cec_adapter *adap)
adap->rc = NULL;
#endif
debugfs_remove_recursive(adap->cec_dir);
+#ifdef CONFIG_MEDIA_CEC_NOTIFIER
+ if (adap->notifier)
+ cec_notifier_unregister(adap->notifier);
+#endif
cec_devnode_unregister(&adap->devnode);
}
EXPORT_SYMBOL_GPL(cec_unregister_adapter);
diff --git a/drivers/media/i2c/adv7481.c b/drivers/media/i2c/adv7481.c
index 359a860fdabb..b382a1d83d92 100644
--- a/drivers/media/i2c/adv7481.c
+++ b/drivers/media/i2c/adv7481.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2014-2015, 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
@@ -27,29 +27,68 @@
#include <media/v4l2-ctrls.h>
#include <linux/mutex.h>
#include <linux/delay.h>
+
+#include <linux/platform_device.h>
+#include <linux/of_platform.h>
+#include <linux/of_gpio.h>
+
#include <media/adv7481.h>
#include <media/msm_ba.h>
#include "adv7481_reg.h"
+#include "msm_cci.h"
+#include "msm_camera_i2c.h"
+#include "msm_camera_io_util.h"
+#include "msm_camera_dt_util.h"
+
#define DRIVER_NAME "adv7481"
-#define I2C_RW_DELAY 100
-#define I2C_SW_RST_DELAY 10000
-#define GPIO_HW_DELAY_LOW 100000
-#define GPIO_HW_DELAY_HI 10000
+#define I2C_RW_DELAY 1
+#define I2C_SW_RST_DELAY 5000
+#define GPIO_HW_RST_DELAY_HI 10000
+#define GPIO_HW_RST_DELAY_LOW 10000
#define SDP_MIN_SLEEP 5000
#define SDP_MAX_SLEEP 6000
#define SDP_NUM_TRIES 30
#define LOCK_MIN_SLEEP 5000
#define LOCK_MAX_SLEEP 6000
-#define LOCK_NUM_TRIES 20
+#define LOCK_NUM_TRIES 200
+
+#define MAX_DEFAULT_WIDTH 1280
+#define MAX_DEFAULT_HEIGHT 720
+#define MAX_DEFAULT_FRAME_RATE 60
+#define MAX_DEFAULT_PIX_CLK_HZ 74240000
#define ONE_MHZ_TO_HZ 1000000
+#define I2C_BLOCK_WRITE_SIZE 1024
+
+enum adv7481_gpio_t {
+
+ CCI_I2C_SDA = 0,
+ CCI_I2C_SCL,
+
+ ADV7481_GPIO_RST,
+
+ ADV7481_GPIO_INT1,
+ ADV7481_GPIO_INT2,
+ ADV7481_GPIO_INT3,
+
+ ADV7481_GPIO_MAX,
+};
struct adv7481_state {
- /* Platform Data */
- struct adv7481_platform_data pdata;
+ struct device *dev;
+
+ /* VREG */
+ struct camera_vreg_t *cci_vreg;
+ struct regulator *cci_reg_ptr[MAX_REGULATOR];
+ int32_t regulator_count;
+
+ /* I2C */
+ struct msm_camera_i2c_client i2c_client;
+ u32 cci_master;
+ u32 i2c_slave_addr;
/* V4L2 Data */
struct v4l2_subdev sd;
@@ -63,19 +102,25 @@ struct adv7481_state {
struct workqueue_struct *work_queues;
struct mutex mutex;
- struct i2c_client *client;
- struct i2c_client *i2c_csi_txa;
- struct i2c_client *i2c_csi_txb;
- struct i2c_client *i2c_hdmi;
- struct i2c_client *i2c_edid;
- struct i2c_client *i2c_cp;
- struct i2c_client *i2c_sdp;
- struct i2c_client *i2c_rep;
+ uint8_t i2c_io_addr;
+ uint8_t i2c_csi_txa_addr;
+ uint8_t i2c_csi_txb_addr;
+ uint8_t i2c_hdmi_addr;
+ uint8_t i2c_edid_addr;
+ uint8_t i2c_cp_addr;
+ uint8_t i2c_sdp_addr;
+ uint8_t i2c_rep_addr;
+ uint8_t i2c_cbus_addr;
/* device status and Flags */
int irq;
int device_num;
int powerup;
+ int cec_detected;
+ int clocks_requested;
+
+ /* GPIOs */
+ struct gpio gpio_array[ADV7481_GPIO_MAX];
/* routing configuration data */
int csia_src;
@@ -196,6 +241,9 @@ const uint8_t adv7481_default_edid_data[] = {
#define ADV7481_EDID_SIZE ARRAY_SIZE(adv7481_default_edid_data)
+static u32 adv7481_inp_to_ba(u32 adv_input);
+static bool adv7481_is_timing_locked(struct adv7481_state *state);
+
static inline struct v4l2_subdev *to_sd(struct v4l2_ctrl *ctrl)
{
return &(container_of(ctrl->handler,
@@ -208,56 +256,151 @@ static inline struct adv7481_state *to_state(struct v4l2_subdev *sd)
}
/* I2C Rd/Rw Functions */
-static int adv7481_wr_byte(struct i2c_client *i2c_client, unsigned int reg,
- unsigned int value)
+static int32_t adv7481_cci_i2c_write(struct msm_camera_i2c_client *i2c_client,
+ uint8_t reg, uint16_t *data,
+ enum msm_camera_i2c_data_type data_type)
{
- int ret;
+ return i2c_client->i2c_func_tbl->i2c_write(i2c_client, reg,
+ *data, data_type);
+}
- ret = i2c_smbus_write_byte_data(i2c_client, reg & 0xFF, value);
- usleep_range(I2C_RW_DELAY, 2*I2C_RW_DELAY);
+static int32_t adv7481_cci_i2c_write_seq(
+ struct msm_camera_i2c_client *i2c_client,
+ uint8_t reg, const uint8_t *data, uint32_t size)
+{
+ return i2c_client->i2c_func_tbl->i2c_write_seq(i2c_client, reg,
+ (uint8_t *)data, size);
+}
+
+static int32_t adv7481_cci_i2c_read(struct msm_camera_i2c_client *i2c_client,
+ uint8_t reg, uint16_t *data,
+ enum msm_camera_i2c_data_type data_type)
+{
+ return i2c_client->i2c_func_tbl->i2c_read(i2c_client, reg,
+ data, data_type);
+}
+
+static int32_t adv7481_wr_byte(struct msm_camera_i2c_client *c_i2c_client,
+ uint8_t sid, uint8_t reg, uint8_t data)
+{
+ uint16_t write_data = data;
+ int ret = 0;
+
+ c_i2c_client->cci_client->sid = sid;
+
+ ret = adv7481_cci_i2c_write(c_i2c_client, reg, &write_data,
+ MSM_CAMERA_I2C_BYTE_DATA);
+ if (ret < 0)
+ pr_err("Error %d writing cci i2c\n", ret);
return ret;
}
-static int adv7481_rd_byte(struct i2c_client *i2c_client, unsigned int reg)
+static int32_t adv7481_wr_block(struct msm_camera_i2c_client *c_i2c_client,
+ uint8_t sid, uint8_t reg, const uint8_t *data, uint32_t size)
{
- int ret;
+ int ret = 0;
- ret = i2c_smbus_read_byte_data(i2c_client, reg & 0xFF);
- usleep_range(I2C_RW_DELAY, 2*I2C_RW_DELAY);
+ c_i2c_client->cci_client->sid = sid;
+
+ ret = adv7481_cci_i2c_write_seq(c_i2c_client, reg, data, size);
+ if (ret < 0)
+ pr_err("Error %d writing cci i2c block data\n", ret);
return ret;
}
+static uint8_t adv7481_rd_byte(struct msm_camera_i2c_client *c_i2c_client,
+ uint8_t sid, uint8_t reg)
+{
+ uint16_t data = 0;
+ int ret = 0;
+
+ c_i2c_client->cci_client->sid = sid;
+ ret = adv7481_cci_i2c_read(c_i2c_client, reg, &data,
+ MSM_CAMERA_I2C_BYTE_DATA);
+ if (ret < 0) {
+ pr_err("Error %d reading cci i2c\n", ret);
+ return ret;
+ }
+
+ return (uint8_t)(data & 0xFF);
+}
+
+static uint16_t adv7481_rd_word(struct msm_camera_i2c_client *c_i2c_client,
+ uint8_t sid, uint8_t reg)
+{
+ uint16_t data = 0;
+ int ret;
+
+ c_i2c_client->cci_client->sid = sid;
+ ret = adv7481_cci_i2c_read(c_i2c_client, reg, &data,
+ MSM_CAMERA_I2C_WORD_DATA);
+ if (ret < 0) {
+ pr_err("Error %d reading cci i2c\n", ret);
+ return ret;
+ }
+
+ return data;
+}
+
static int adv7481_set_irq(struct adv7481_state *state)
{
int ret = 0;
- ret = adv7481_wr_byte(state->client, IO_REG_PAD_CTRL_1_ADDR,
+ ret = adv7481_wr_byte(&state->i2c_client, state->i2c_io_addr,
+ IO_REG_PAD_CTRL_1_ADDR,
ADV_REG_SETFIELD(1, IO_PDN_INT2) |
ADV_REG_SETFIELD(1, IO_PDN_INT3) |
ADV_REG_SETFIELD(1, IO_INV_LLC) |
ADV_REG_SETFIELD(AD_MID_DRIVE_STRNGTH, IO_DRV_LLC_PAD));
- ret |= adv7481_wr_byte(state->client, IO_REG_INT1_CONF_ADDR,
+ ret |= adv7481_wr_byte(&state->i2c_client, state->i2c_io_addr,
+ IO_REG_INT1_CONF_ADDR,
ADV_REG_SETFIELD(AD_ACTIVE_UNTIL_CLR,
IO_INTRQ_DUR_SEL) |
ADV_REG_SETFIELD(AD_OP_DRIVE_LOW, IO_INTRQ_OP_SEL));
- ret |= adv7481_wr_byte(state->client, IO_REG_INT2_CONF_ADDR,
+ ret |= adv7481_wr_byte(&state->i2c_client, state->i2c_io_addr,
+ IO_REG_INT2_CONF_ADDR,
ADV_REG_SETFIELD(1, IO_CP_LOCK_UNLOCK_EDGE_SEL));
- ret |= adv7481_wr_byte(state->client, IO_REG_DATAPATH_INT_MASKB_ADDR,
+ ret |= adv7481_wr_byte(&state->i2c_client, state->i2c_io_addr,
+ IO_REG_DATAPATH_INT_MASKB_ADDR,
ADV_REG_SETFIELD(1, IO_CP_LOCK_CP_MB1) |
ADV_REG_SETFIELD(1, IO_CP_UNLOCK_CP_MB1) |
ADV_REG_SETFIELD(1, IO_VMUTE_REQUEST_HDMI_MB1) |
ADV_REG_SETFIELD(1, IO_INT_SD_MB1));
- /* Set hpa */
- ret |= adv7481_wr_byte(state->client, IO_HDMI_LVL_INT_MASKB_3_ADDR,
- ADV_REG_SETFIELD(1, IO_CABLE_DET_A_MB1));
+ /* Set cable detect */
+ ret |= adv7481_wr_byte(&state->i2c_client, state->i2c_io_addr,
+ IO_HDMI_LVL_INT_MASKB_3_ADDR,
+ ADV_REG_SETFIELD(1, IO_CABLE_DET_A_MB1) |
+ ADV_REG_SETFIELD(1, IO_V_LOCKED_MB1) |
+ ADV_REG_SETFIELD(1, IO_DE_REGEN_LCK_MB1));
+
+ /* set CVBS lock/unlock interrupts */
+ /* Select SDP MAP 1 */
+ adv7481_wr_byte(&state->i2c_client, state->i2c_sdp_addr,
+ SDP_RW_MAP_REG, 0x20);
+ adv7481_wr_byte(&state->i2c_client, state->i2c_sdp_addr,
+ SDP_RW_LOCK_UNLOCK_MASK_ADDR, 0x03);
+ adv7481_wr_byte(&state->i2c_client, state->i2c_sdp_addr,
+ SDP_RW_MAP_REG, 0x00);
if (ret)
pr_err("%s: Failed %d to setup interrupt regs\n",
__func__, ret);
- else
- enable_irq(state->irq);
+
+ return ret;
+}
+
+static int adv7481_reset_irq(struct adv7481_state *state)
+{
+ int ret = 0;
+
+ disable_irq(state->irq);
+
+ ret = adv7481_wr_byte(&state->i2c_client, state->i2c_io_addr,
+ IO_REG_DATAPATH_INT_MASKB_ADDR, 0x00);
+ ret |= adv7481_wr_byte(&state->i2c_client, state->i2c_io_addr,
+ IO_HDMI_LVL_INT_MASKB_3_ADDR, 0x00);
return ret;
}
@@ -267,27 +410,42 @@ static int adv7481_set_edid(struct adv7481_state *state)
int i;
int ret = 0;
uint8_t edid_state;
+ uint32_t data_left = 0;
+ uint32_t start_pos;
/* Enable Manual Control of EDID on Port A */
- ret |= adv7481_wr_byte(state->i2c_rep, 0x74, 0x01);
+ ret |= adv7481_wr_byte(&state->i2c_client, state->i2c_rep_addr, 0x74,
+ 0x01);
/* Disable Auto Enable of EDID */
- ret |= adv7481_wr_byte(state->i2c_rep, 0x7A, 0x08);
+ ret |= adv7481_wr_byte(&state->i2c_client, state->i2c_rep_addr, 0x7A,
+ 0x08);
/* Set Primary EDID Size to 256 Bytes */
- ret |= adv7481_wr_byte(state->i2c_rep, 0x70, 0x20);
+ ret |= adv7481_wr_byte(&state->i2c_client, state->i2c_rep_addr, 0x70,
+ 0x20);
/*
* Readback EDID enable state after a combination of manual
* and automatic functions
*/
- edid_state = adv7481_rd_byte(state->i2c_rep,
+ edid_state = adv7481_rd_byte(&state->i2c_client, state->i2c_rep_addr,
HDMI_REG_RO_EDID_DEBUG_2_ADDR);
pr_debug("%s: Readback EDID enable state: 0x%x\n", __func__,
edid_state);
- for (i = 0; i < ADV7481_EDID_SIZE; i++) {
- ret |= adv7481_wr_byte(state->i2c_edid, i,
- adv7481_default_edid_data[i]);
- }
+ for (i = 0; i < ADV7481_EDID_SIZE && !ret; i += I2C_BLOCK_WRITE_SIZE)
+ ret |= adv7481_wr_block(&state->i2c_client,
+ state->i2c_edid_addr,
+ i, &adv7481_default_edid_data[i],
+ I2C_BLOCK_WRITE_SIZE);
+
+ data_left = ADV7481_EDID_SIZE % I2C_BLOCK_WRITE_SIZE;
+ start_pos = ADV7481_EDID_SIZE - data_left;
+ if (data_left && !ret)
+ ret |= adv7481_wr_block(&state->i2c_client,
+ state->i2c_edid_addr,
+ start_pos,
+ &adv7481_default_edid_data[start_pos],
+ data_left);
return ret;
}
@@ -301,47 +459,232 @@ static irqreturn_t adv7481_irq(int irq, void *dev)
return IRQ_HANDLED;
}
+/* Request CCI clocks for adv7481 register access */
+static int adv7481_request_cci_clks(struct adv7481_state *state)
+{
+ int ret = 0;
+
+ if (state->clocks_requested == TRUE)
+ return ret;
+
+ ret = state->i2c_client.i2c_func_tbl->i2c_util(
+ &state->i2c_client, MSM_CCI_INIT);
+ if (ret < 0)
+ pr_err("%s - cci_init failed\n", __func__);
+ else
+ state->clocks_requested = TRUE;
+
+ /* enable camera voltage regulator */
+ ret = msm_camera_enable_vreg(state->dev, state->cci_vreg,
+ state->regulator_count, NULL, 0,
+ &state->cci_reg_ptr[0], 1);
+ if (ret < 0)
+ pr_err("%s:cci enable_vreg failed\n", __func__);
+ else
+ pr_debug("%s - VREG Initialized...\n", __func__);
+
+ return ret;
+}
+
+static int adv7481_release_cci_clks(struct adv7481_state *state)
+{
+ int ret = 0;
+
+ if (state->clocks_requested == FALSE)
+ return ret;
+
+ ret = state->i2c_client.i2c_func_tbl->i2c_util(
+ &state->i2c_client, MSM_CCI_RELEASE);
+ if (ret < 0)
+ pr_err("%s - cci_release failed\n", __func__);
+ else
+ state->clocks_requested = FALSE;
+
+ /* disable camera voltage regulator */
+ ret = msm_camera_enable_vreg(state->dev, state->cci_vreg,
+ state->regulator_count, NULL, 0,
+ &state->cci_reg_ptr[0], 0);
+ if (ret < 0)
+ pr_err("%s:cci disable vreg failed\n", __func__);
+ else
+ pr_debug("%s - VREG Initialized...\n", __func__);
+
+ return ret;
+}
+
static void adv7481_irq_delay_work(struct work_struct *work)
{
struct adv7481_state *state;
- uint8_t status;
+ uint8_t int_raw_status;
+ uint8_t int_status;
+ uint8_t raw_status;
state = container_of(work, struct adv7481_state,
irq_delayed_work.work);
mutex_lock(&state->mutex);
- /* workaround for irq trigger */
- status = adv7481_rd_byte(state->client,
+ /* Read raw irq status register */
+ int_raw_status = adv7481_rd_byte(&state->i2c_client, state->i2c_io_addr,
IO_REG_INT_RAW_STATUS_ADDR);
pr_debug("%s: dev: %d got int raw status: 0x%x\n", __func__,
- state->device_num, status);
+ state->device_num, int_raw_status);
+ state->cec_detected = ADV_REG_GETFIELD(int_raw_status, IO_INT_CEC_ST);
+
+ while (int_raw_status) {
+ if (ADV_REG_GETFIELD(int_raw_status, IO_INTRQ1_RAW)) {
+ int lock_status = -1;
+ struct v4l2_event event = {0};
+ int *ptr = (int *)event.u.data;
+
+ pr_debug("%s: dev: %d got intrq1_raw\n", __func__,
+ state->device_num);
+ int_status = adv7481_rd_byte(&state->i2c_client,
+ state->i2c_io_addr,
+ IO_REG_DATAPATH_INT_STATUS_ADDR);
+
+ raw_status = adv7481_rd_byte(&state->i2c_client,
+ state->i2c_io_addr,
+ IO_REG_DATAPATH_RAW_STATUS_ADDR);
+
+ adv7481_wr_byte(&state->i2c_client, state->i2c_io_addr,
+ IO_REG_DATAPATH_INT_CLEAR_ADDR, int_status);
+
+ pr_debug("%s: dev: %d got datapath int status: 0x%x\n",
+ __func__, state->device_num, int_status);
+
+ pr_debug("%s: dev: %d got datapath raw status: 0x%x\n",
+ __func__, state->device_num, raw_status);
+
+ if (ADV_REG_GETFIELD(int_status, IO_INT_SD_ST) &&
+ ADV_REG_GETFIELD(raw_status, IO_INT_SD_RAW)) {
+ uint8_t sdp_sts = 0;
+
+ adv7481_wr_byte(&state->i2c_client,
+ state->i2c_sdp_addr, SDP_RW_MAP_REG,
+ 0x01);
+ sdp_sts = adv7481_rd_byte(&state->i2c_client,
+ state->i2c_sdp_addr,
+ SDP_RO_MAIN_STATUS1_ADDR);
+ pr_debug("%s: dev: %d got sdp status: 0x%x\n",
+ __func__, state->device_num, sdp_sts);
+ adv7481_wr_byte(&state->i2c_client,
+ state->i2c_sdp_addr, SDP_RW_MAP_REG,
+ 0x00);
+ if (ADV_REG_GETFIELD(sdp_sts,
+ SDP_RO_MAIN_IN_LOCK)) {
+ lock_status = 0;
+ pr_debug(
+ "%s: set lock_status SDP_IN_LOCK:0x%x\n",
+ __func__, lock_status);
+ } else {
+ lock_status = 1;
+ pr_debug(
+ "%s: set lock_status SDP_UNLOCK:0x%x\n",
+ __func__, lock_status);
+ }
+ adv7481_wr_byte(&state->i2c_client,
+ state->i2c_sdp_addr, SDP_RW_MAP_REG,
+ 0x20);
+ adv7481_wr_byte(&state->i2c_client,
+ state->i2c_sdp_addr,
+ SDP_RW_LOCK_UNLOCK_CLR_ADDR, sdp_sts);
+ adv7481_wr_byte(&state->i2c_client,
+ state->i2c_sdp_addr, SDP_RW_MAP_REG,
+ 0x00);
+ } else {
+ if (ADV_REG_GETFIELD(int_status,
+ IO_CP_LOCK_CP_ST) &&
+ ADV_REG_GETFIELD(raw_status,
+ IO_CP_LOCK_CP_RAW)) {
+ lock_status = 0;
+ pr_debug(
+ "%s: set lock_status IO_CP_LOCK_CP_RAW:0x%x\n",
+ __func__, lock_status);
+ }
+ if (ADV_REG_GETFIELD(int_status,
+ IO_CP_UNLOCK_CP_ST) &&
+ ADV_REG_GETFIELD(raw_status,
+ IO_CP_UNLOCK_CP_RAW)) {
+ lock_status = 1;
+ pr_debug(
+ "%s: set lock_status IO_CP_UNLOCK_CP_RAW:0x%x\n",
+ __func__, lock_status);
+ }
+ }
+
+ if (lock_status >= 0) {
+ ptr[0] = adv7481_inp_to_ba(state->mode);
+ ptr[1] = lock_status;
+ event.type = lock_status ?
+ V4L2_EVENT_MSM_BA_SIGNAL_LOST_LOCK :
+ V4L2_EVENT_MSM_BA_SIGNAL_IN_LOCK;
+ v4l2_subdev_notify(&state->sd,
+ event.type, &event);
+ }
+ }
- status = adv7481_rd_byte(state->client,
- IO_REG_DATAPATH_INT_STATUS_ADDR);
+ if (ADV_REG_GETFIELD(int_raw_status, IO_INT_HDMI_ST)) {
+ int cable_detected = 0;
+ struct v4l2_event event = {0};
+ int *ptr = (int *)event.u.data;
- pr_debug("%s: dev: %d got datapath int status: 0x%x\n", __func__,
- state->device_num, status);
+ ptr[0] = adv7481_inp_to_ba(state->mode);
- adv7481_wr_byte(state->client,
- IO_REG_DATAPATH_INT_CLEAR_ADDR, status);
+ pr_debug("%s: dev: %d got int_hdmi_st\n", __func__,
+ state->device_num);
- status = adv7481_rd_byte(state->client,
- IO_REG_DATAPATH_RAW_STATUS_ADDR);
+ int_status = adv7481_rd_byte(&state->i2c_client,
+ state->i2c_io_addr,
+ IO_HDMI_LVL_INT_STATUS_3_ADDR);
- pr_debug("%s: dev: %d got datapath rawstatus: 0x%x\n", __func__,
- state->device_num, status);
+ raw_status = adv7481_rd_byte(&state->i2c_client,
+ state->i2c_io_addr,
+ IO_HDMI_LVL_RAW_STATUS_3_ADDR);
- status = adv7481_rd_byte(state->client,
- IO_HDMI_LVL_INT_STATUS_3_ADDR);
+ adv7481_wr_byte(&state->i2c_client, state->i2c_io_addr,
+ IO_HDMI_LVL_INT_CLEAR_3_ADDR, int_status);
- pr_debug("%s: dev: %d got hdmi lvl int status 3: 0x%x\n", __func__,
- state->device_num, status);
+ pr_debug("%s: dev: %d got hdmi lvl int status 3: 0x%x\n",
+ __func__, state->device_num, int_status);
+ pr_debug("%s: dev: %d got hdmi lvl raw status 3: 0x%x\n",
+ __func__, state->device_num, raw_status);
- adv7481_wr_byte(state->client,
- IO_HDMI_LVL_INT_CLEAR_3_ADDR, status);
+ if (ADV_REG_GETFIELD(int_status, IO_CABLE_DET_A_ST)) {
+ cable_detected = ADV_REG_GETFIELD(raw_status,
+ IO_CABLE_DET_A_RAW);
+ pr_debug("%s: set cable_detected: 0x%x\n",
+ __func__, cable_detected);
+ ptr[1] = cable_detected;
+ event.type = V4L2_EVENT_MSM_BA_CABLE_DETECT;
+ v4l2_subdev_notify(&state->sd,
+ event.type, &event);
+ }
+ /* Assumption is that vertical sync int
+ * is the last one to come
+ */
+ if (ADV_REG_GETFIELD(int_status, IO_V_LOCKED_ST)) {
+ if (ADV_REG_GETFIELD(raw_status,
+ IO_TMDSPLL_LCK_A_RAW) &&
+ ADV_REG_GETFIELD(raw_status,
+ IO_V_LOCKED_RAW) &&
+ ADV_REG_GETFIELD(raw_status,
+ IO_DE_REGEN_LCK_RAW)) {
+ pr_debug("%s: port settings changed\n",
+ __func__);
+ event.type =
+ V4L2_EVENT_MSM_BA_PORT_SETTINGS_CHANGED;
+ v4l2_subdev_notify(&state->sd,
+ event.type, &event);
+ }
+ }
+ }
+ int_raw_status = adv7481_rd_byte(&state->i2c_client,
+ state->i2c_io_addr,
+ IO_REG_INT_RAW_STATUS_ADDR);
+ }
mutex_unlock(&state->mutex);
}
@@ -350,110 +693,100 @@ static int adv7481_cec_wakeup(struct adv7481_state *state, bool enable)
uint8_t val;
int ret = 0;
- val = adv7481_rd_byte(state->client,
+ val = adv7481_rd_byte(&state->i2c_client, state->i2c_io_addr,
IO_REG_PWR_DN2_XTAL_HIGH_ADDR);
val = ADV_REG_GETFIELD(val, IO_PROG_XTAL_FREQ_HIGH);
if (enable) {
/* CEC wake up enabled in power-down mode */
val |= ADV_REG_SETFIELD(1, IO_CTRL_CEC_WAKE_UP_PWRDN2B) |
ADV_REG_SETFIELD(0, IO_CTRL_CEC_WAKE_UP_PWRDNB);
- ret = adv7481_wr_byte(state->client,
+ ret = adv7481_wr_byte(&state->i2c_client, state->i2c_io_addr,
IO_REG_PWR_DN2_XTAL_HIGH_ADDR, val);
} else {
/* CEC wake up disabled in power-down mode */
val |= ADV_REG_SETFIELD(0, IO_CTRL_CEC_WAKE_UP_PWRDN2B) |
ADV_REG_SETFIELD(1, IO_CTRL_CEC_WAKE_UP_PWRDNB);
- ret = adv7481_wr_byte(state->client,
+ ret = adv7481_wr_byte(&state->i2c_client, state->i2c_io_addr,
IO_REG_PWR_DN2_XTAL_HIGH_ADDR, val);
}
return ret;
}
/* Initialize adv7481 I2C Settings */
-static int adv7481_dev_init(struct adv7481_state *state,
- struct i2c_client *client)
+static int adv7481_dev_init(struct adv7481_state *state)
{
+ uint16_t chip_rev_id;
int ret;
mutex_lock(&state->mutex);
/* Soft reset */
- ret = adv7481_wr_byte(state->client,
- IO_REG_MAIN_RST_ADDR, IO_REG_MAIN_RST_VALUE);
+ ret = adv7481_wr_byte(&state->i2c_client, state->i2c_io_addr,
+ IO_REG_MAIN_RST_ADDR, IO_REG_MAIN_RST_VALUE);
/* Delay required following I2C reset and I2C transactions */
- usleep_range(I2C_SW_RST_DELAY, I2C_SW_RST_DELAY+1000);
+ udelay(I2C_SW_RST_DELAY);
+
+ chip_rev_id = adv7481_rd_word(&state->i2c_client, state->i2c_io_addr,
+ IO_REG_CHIP_REV_ID_1_ADDR);
+ pr_debug("%s: ADV7481 chip rev id: 0x%x", __func__, chip_rev_id);
/* Disable CEC wake up in power-down mode */
ret |= adv7481_cec_wakeup(state, 0);
/* Setting Vid_Std to 720x480p60 */
- ret |= adv7481_wr_byte(state->client,
- IO_REG_CP_VID_STD_ADDR, 0x4A);
+ ret |= adv7481_wr_byte(&state->i2c_client, state->i2c_io_addr,
+ IO_REG_CP_VID_STD_ADDR, 0x4A);
/* Configure I2C Maps and I2C Communication Settings */
/* io_reg_f2 I2C Auto Increment */
- ret |= adv7481_wr_byte(state->client, IO_REG_I2C_CFG_ADDR,
- IO_REG_I2C_AUTOINC_EN_REG_VALUE);
+ ret |= adv7481_wr_byte(&state->i2c_client, state->i2c_io_addr,
+ IO_REG_I2C_CFG_ADDR, IO_REG_I2C_AUTOINC_EN_REG_VALUE);
/* DPLL Map Address */
- ret |= adv7481_wr_byte(state->client, IO_REG_DPLL_ADDR,
- IO_REG_DPLL_SADDR);
+ ret |= adv7481_wr_byte(&state->i2c_client, state->i2c_io_addr,
+ IO_REG_DPLL_ADDR, IO_REG_DPLL_SADDR);
/* CP Map Address */
- ret |= adv7481_wr_byte(state->client, IO_REG_CP_ADDR,
- IO_REG_CP_SADDR);
+ ret |= adv7481_wr_byte(&state->i2c_client, state->i2c_io_addr,
+ IO_REG_CP_ADDR, IO_REG_CP_SADDR);
/* HDMI RX Map Address */
- ret |= adv7481_wr_byte(state->client, IO_REG_HDMI_ADDR,
- IO_REG_HDMI_SADDR);
+ ret |= adv7481_wr_byte(&state->i2c_client, state->i2c_io_addr,
+ IO_REG_HDMI_ADDR, IO_REG_HDMI_SADDR);
/* EDID Map Address */
- ret |= adv7481_wr_byte(state->client, IO_REG_EDID_ADDR,
- IO_REG_EDID_SADDR);
+ ret |= adv7481_wr_byte(&state->i2c_client, state->i2c_io_addr,
+ IO_REG_EDID_ADDR, IO_REG_EDID_SADDR);
/* HDMI RX Repeater Map Address */
- ret |= adv7481_wr_byte(state->client, IO_REG_HDMI_REP_ADDR,
- IO_REG_HDMI_REP_SADDR);
+ ret |= adv7481_wr_byte(&state->i2c_client, state->i2c_io_addr,
+ IO_REG_HDMI_REP_ADDR, IO_REG_HDMI_REP_SADDR);
/* HDMI RX Info-frame Map Address */
- ret |= adv7481_wr_byte(state->client, IO_REG_HDMI_INF_ADDR,
- IO_REG_HDMI_INF_SADDR);
+ ret |= adv7481_wr_byte(&state->i2c_client, state->i2c_io_addr,
+ IO_REG_HDMI_INF_ADDR, IO_REG_HDMI_INF_SADDR);
/* CBUS Map Address */
- ret |= adv7481_wr_byte(state->client, IO_REG_CBUS_ADDR,
- IO_REG_CBUS_SADDR);
+ ret |= adv7481_wr_byte(&state->i2c_client, state->i2c_io_addr,
+ IO_REG_CBUS_ADDR, IO_REG_CBUS_SADDR);
/* CEC Map Address */
- ret |= adv7481_wr_byte(state->client, IO_REG_CEC_ADDR,
- IO_REG_CEC_SADDR);
+ ret |= adv7481_wr_byte(&state->i2c_client, state->i2c_io_addr,
+ IO_REG_CEC_ADDR, IO_REG_CEC_SADDR);
/* SDP Main Map Address */
- ret |= adv7481_wr_byte(state->client, IO_REG_SDP_ADDR,
- IO_REG_SDP_SADDR);
+ ret |= adv7481_wr_byte(&state->i2c_client, state->i2c_io_addr,
+ IO_REG_SDP_ADDR, IO_REG_SDP_SADDR);
/* CSI-TXB Map Address */
- ret |= adv7481_wr_byte(state->client, IO_REG_CSI_TXB_ADDR,
- IO_REG_CSI_TXB_SADDR);
+ ret |= adv7481_wr_byte(&state->i2c_client, state->i2c_io_addr,
+ IO_REG_CSI_TXB_ADDR, IO_REG_CSI_TXB_SADDR);
/* CSI-TXA Map Address */
- ret |= adv7481_wr_byte(state->client, IO_REG_CSI_TXA_ADDR,
- IO_REG_CSI_TXA_SADDR);
+ ret |= adv7481_wr_byte(&state->i2c_client, state->i2c_io_addr,
+ IO_REG_CSI_TXA_ADDR, IO_REG_CSI_TXA_SADDR);
if (ret) {
pr_err("%s: Failed dev init %d\n", __func__, ret);
goto err_exit;
}
/* Configure i2c clients */
- state->i2c_csi_txa = i2c_new_dummy(client->adapter,
- IO_REG_CSI_TXA_SADDR >> 1);
- state->i2c_csi_txb = i2c_new_dummy(client->adapter,
- IO_REG_CSI_TXB_SADDR >> 1);
- state->i2c_cp = i2c_new_dummy(client->adapter,
- IO_REG_CP_SADDR >> 1);
- state->i2c_hdmi = i2c_new_dummy(client->adapter,
- IO_REG_HDMI_SADDR >> 1);
- state->i2c_edid = i2c_new_dummy(client->adapter,
- IO_REG_EDID_SADDR >> 1);
- state->i2c_sdp = i2c_new_dummy(client->adapter,
- IO_REG_SDP_SADDR >> 1);
- state->i2c_rep = i2c_new_dummy(client->adapter,
- IO_REG_HDMI_REP_SADDR >> 1);
-
- if (!state->i2c_csi_txa || !state->i2c_csi_txb || !state->i2c_cp ||
- !state->i2c_sdp || !state->i2c_hdmi || !state->i2c_edid ||
- !state->i2c_rep) {
- pr_err("%s: Additional I2C Client Fail\n", __func__);
- ret = -EFAULT;
- goto err_exit;
- }
+ state->i2c_csi_txa_addr = IO_REG_CSI_TXA_SADDR >> 1;
+ state->i2c_csi_txb_addr = IO_REG_CSI_TXB_SADDR >> 1;
+ state->i2c_cp_addr = IO_REG_CP_SADDR >> 1;
+ state->i2c_hdmi_addr = IO_REG_HDMI_SADDR >> 1;
+ state->i2c_edid_addr = IO_REG_EDID_SADDR >> 1;
+ state->i2c_sdp_addr = IO_REG_SDP_SADDR >> 1;
+ state->i2c_rep_addr = IO_REG_HDMI_REP_SADDR >> 1;
+ state->i2c_cbus_addr = IO_REG_CBUS_SADDR >> 1;
ret = adv7481_set_edid(state);
ret |= adv7481_set_irq(state);
@@ -465,28 +798,25 @@ err_exit:
}
/* Initialize adv7481 hardware */
-static int adv7481_hw_init(struct adv7481_platform_data *pdata,
- struct adv7481_state *state)
+static int adv7481_hw_init(struct adv7481_state *state)
{
int ret = 0;
- if (!pdata) {
- pr_err("%s: PDATA is NULL\n", __func__);
- return -EFAULT;
- }
-
mutex_lock(&state->mutex);
- if (gpio_is_valid(pdata->rstb_gpio)) {
- ret = gpio_request(pdata->rstb_gpio, "rstb_gpio");
- if (ret) {
- pr_err("%s: Request GPIO Fail %d\n", __func__, ret);
- goto err_exit;
- }
- ret = gpio_direction_output(pdata->rstb_gpio, 0);
- usleep_range(GPIO_HW_DELAY_LOW, GPIO_HW_DELAY_LOW+1000);
- ret = gpio_direction_output(pdata->rstb_gpio, 1);
- usleep_range(GPIO_HW_DELAY_HI, GPIO_HW_DELAY_HI+1000);
+ /* Bring ADV7481 out of reset */
+ ret = gpio_request_array(&state->gpio_array[ADV7481_GPIO_RST], 1);
+ if (ret < 0) {
+ pr_err("%s: Failed to request reset GPIO %d\n", __func__, ret);
+ goto err_exit;
+ }
+ if (gpio_is_valid(state->gpio_array[ADV7481_GPIO_RST].gpio)) {
+ ret |= gpio_direction_output(
+ state->gpio_array[ADV7481_GPIO_RST].gpio, 0);
+ udelay(GPIO_HW_RST_DELAY_LOW);
+ ret |= gpio_direction_output(
+ state->gpio_array[ADV7481_GPIO_RST].gpio, 1);
+ udelay(GPIO_HW_RST_DELAY_HI);
if (ret) {
pr_err("%s: Set GPIO Fail %d\n", __func__, ret);
goto err_exit;
@@ -494,22 +824,21 @@ static int adv7481_hw_init(struct adv7481_platform_data *pdata,
}
/* Only setup IRQ1 for now... */
- if (gpio_is_valid(pdata->irq1_gpio)) {
- ret = gpio_request(pdata->irq1_gpio, "irq_gpio");
- if (ret) {
- pr_err("%s: Failed to request irq_gpio %d\n",
- __func__, ret);
- goto err_exit;
- }
-
- ret = gpio_direction_input(pdata->irq1_gpio);
+ ret = gpio_request_array(&state->gpio_array[ADV7481_GPIO_INT1], 1);
+ if (ret < 0) {
+ pr_err("%s: Failed to request irq_gpio %d\n", __func__, ret);
+ goto err_exit;
+ }
+ if (gpio_is_valid(state->gpio_array[ADV7481_GPIO_INT1].gpio)) {
+ ret |= gpio_direction_input(
+ state->gpio_array[ADV7481_GPIO_INT1].gpio);
if (ret) {
pr_err("%s: Failed gpio_direction irq %d\n",
__func__, ret);
goto err_exit;
}
-
- state->irq = gpio_to_irq(pdata->irq1_gpio);
+ state->irq = gpio_to_irq(
+ state->gpio_array[ADV7481_GPIO_INT1].gpio);
if (state->irq) {
ret = request_irq(state->irq, adv7481_irq,
IRQF_ONESHOT | IRQF_TRIGGER_FALLING,
@@ -519,18 +848,16 @@ static int adv7481_hw_init(struct adv7481_platform_data *pdata,
__func__, ret);
goto err_exit;
}
+ /* disable irq until chip interrupts are programmed */
+ disable_irq(state->irq);
} else {
pr_err("%s: Failed gpio_to_irq %d\n", __func__, ret);
ret = -EINVAL;
goto err_exit;
}
-
- /* disable irq until chip interrupts are programmed */
- disable_irq(state->irq);
-
- INIT_DELAYED_WORK(&state->irq_delayed_work,
- adv7481_irq_delay_work);
}
+ INIT_DELAYED_WORK(&state->irq_delayed_work,
+ adv7481_irq_delay_work);
err_exit:
mutex_unlock(&state->mutex);
@@ -548,31 +875,40 @@ static int adv7481_s_ctrl(struct v4l2_ctrl *ctrl)
pr_debug("Enter %s: id = 0x%x\n", __func__, ctrl->id);
switch (ctrl->id) {
case V4L2_CID_BRIGHTNESS:
- temp = adv7481_rd_byte(state->client, CP_REG_VID_ADJ);
+ temp = adv7481_rd_byte(&state->i2c_client, state->i2c_io_addr,
+ CP_REG_VID_ADJ);
temp |= CP_CTR_VID_ADJ_EN;
- ret = adv7481_wr_byte(state->client, CP_REG_VID_ADJ, temp);
- ret |= adv7481_wr_byte(state->client,
- CP_REG_BRIGHTNESS, ctrl->val);
+ ret = adv7481_wr_byte(&state->i2c_client, state->i2c_io_addr,
+ CP_REG_VID_ADJ, temp);
+ ret |= adv7481_wr_byte(&state->i2c_client, state->i2c_io_addr,
+ CP_REG_BRIGHTNESS, ctrl->val);
break;
case V4L2_CID_CONTRAST:
- temp = adv7481_rd_byte(state->client, CP_REG_VID_ADJ);
+ temp = adv7481_rd_byte(&state->i2c_client, state->i2c_io_addr,
+ CP_REG_VID_ADJ);
temp |= CP_CTR_VID_ADJ_EN;
- ret = adv7481_wr_byte(state->client, CP_REG_VID_ADJ, temp);
- ret |= adv7481_wr_byte(state->client,
- CP_REG_CONTRAST, ctrl->val);
+ ret = adv7481_wr_byte(&state->i2c_client, state->i2c_io_addr,
+ CP_REG_VID_ADJ, temp);
+ ret |= adv7481_wr_byte(&state->i2c_client, state->i2c_io_addr,
+ CP_REG_CONTRAST, ctrl->val);
break;
case V4L2_CID_SATURATION:
- temp = adv7481_rd_byte(state->client, CP_REG_VID_ADJ);
+ temp = adv7481_rd_byte(&state->i2c_client, state->i2c_io_addr,
+ CP_REG_VID_ADJ);
temp |= CP_CTR_VID_ADJ_EN;
- ret = adv7481_wr_byte(state->client, CP_REG_VID_ADJ, temp);
- ret |= adv7481_wr_byte(state->client,
- CP_REG_SATURATION, ctrl->val);
+ ret = adv7481_wr_byte(&state->i2c_client, state->i2c_io_addr,
+ CP_REG_VID_ADJ, temp);
+ ret |= adv7481_wr_byte(&state->i2c_client, state->i2c_io_addr,
+ CP_REG_SATURATION, ctrl->val);
break;
case V4L2_CID_HUE:
- temp = adv7481_rd_byte(state->client, CP_REG_VID_ADJ);
+ temp = adv7481_rd_byte(&state->i2c_client, state->i2c_io_addr,
+ CP_REG_VID_ADJ);
temp |= CP_CTR_VID_ADJ_EN;
- ret = adv7481_wr_byte(state->client, CP_REG_VID_ADJ, temp);
- ret |= adv7481_wr_byte(state->client, CP_REG_HUE, ctrl->val);
+ ret = adv7481_wr_byte(&state->i2c_client, state->i2c_io_addr,
+ CP_REG_VID_ADJ, temp);
+ ret |= adv7481_wr_byte(&state->i2c_client, state->i2c_io_addr,
+ CP_REG_HUE, ctrl->val);
break;
default:
break;
@@ -611,6 +947,108 @@ static int adv7481_s_power(struct v4l2_subdev *sd, int on)
return ret;
}
+static int adv7481_set_cec_logical_addr(struct adv7481_state *state, int *la)
+{
+ int rc = 0;
+ uint8_t val;
+
+ if (!la) {
+ pr_err("%s: NULL pointer provided\n", __func__);
+ return -EINVAL;
+ }
+
+ val = adv7481_rd_byte(&state->i2c_client, state->i2c_io_addr,
+ CEC_REG_LOG_ADDR_MASK_ADDR);
+ if (ADV_REG_GETFIELD(val, CEC_REG_LOG_ADDR_MASK0)) {
+ val = adv7481_rd_byte(&state->i2c_client, state->i2c_io_addr,
+ CEC_REG_LOGICAL_ADDRESS0_1_ADDR);
+ val = ADV_REG_RSTFIELD(val, CEC_REG_LOGICAL_ADDRESS0);
+ val |= ADV_REG_SETFIELD(*la, CEC_REG_LOGICAL_ADDRESS0);
+ rc = adv7481_wr_byte(&state->i2c_client, state->i2c_io_addr,
+ CEC_REG_LOGICAL_ADDRESS0_1_ADDR, val);
+ } else if (ADV_REG_GETFIELD(val, CEC_REG_LOG_ADDR_MASK1)) {
+ val = adv7481_rd_byte(&state->i2c_client, state->i2c_io_addr,
+ CEC_REG_LOGICAL_ADDRESS0_1_ADDR);
+ val = ADV_REG_RSTFIELD(val, CEC_REG_LOGICAL_ADDRESS1);
+ val |= ADV_REG_SETFIELD(*la, CEC_REG_LOGICAL_ADDRESS1);
+ rc = adv7481_wr_byte(&state->i2c_client, state->i2c_io_addr,
+ CEC_REG_LOGICAL_ADDRESS0_1_ADDR, val);
+ } else if (ADV_REG_GETFIELD(val, CEC_REG_LOG_ADDR_MASK2)) {
+ val = ADV_REG_SETFIELD(*la, CEC_REG_LOGICAL_ADDRESS2);
+ rc = adv7481_wr_byte(&state->i2c_client, state->i2c_io_addr,
+ CEC_REG_LOGICAL_ADDRESS2_ADDR, val);
+ } else {
+ pr_err("No cec logical address mask set\n");
+ }
+
+ return rc;
+}
+
+static int adv7481_cec_powerup(struct adv7481_state *state, int *powerup)
+{
+ int rc = 0;
+ uint8_t val = 0;
+
+ if (!powerup) {
+ pr_err("%s: NULL pointer provided\n", __func__);
+ return -EINVAL;
+ }
+
+ pr_debug("%s: set power %d\n", __func__, *powerup);
+
+ val = ADV_REG_SETFIELD(*powerup, CEC_REG_CEC_POWER_UP);
+ rc = adv7481_wr_byte(&state->i2c_client, state->i2c_io_addr,
+ CEC_REG_CEC_POWER_UP_ADDR, val);
+
+ return rc;
+}
+
+static long adv7481_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg)
+{
+ struct adv7481_state *state = to_state(sd);
+ int *ret_val = arg;
+ long ret = 0;
+ int param = 0;
+
+ pr_debug("Enter %s with command: 0x%x", __func__, cmd);
+
+ if (!sd)
+ return -EINVAL;
+
+ switch (cmd) {
+ case VIDIOC_HDMI_RX_CEC_S_LOGICAL:
+ ret = adv7481_set_cec_logical_addr(state, arg);
+ break;
+ case VIDIOC_HDMI_RX_CEC_CLEAR_LOGICAL:
+ ret = adv7481_set_cec_logical_addr(state, &param);
+ break;
+ case VIDIOC_HDMI_RX_CEC_G_PHYSICAL:
+ if (ret_val) {
+ *ret_val = 0;
+ } else {
+ pr_err("%s: NULL pointer provided\n", __func__);
+ ret = -EINVAL;
+ }
+ break;
+ case VIDIOC_HDMI_RX_CEC_G_CONNECTED:
+ if (ret_val) {
+ *ret_val = state->cec_detected;
+ } else {
+ pr_err("%s: NULL pointer provided\n", __func__);
+ ret = -EINVAL;
+ }
+ break;
+ case VIDIOC_HDMI_RX_CEC_S_ENABLE:
+ ret = adv7481_cec_powerup(state, arg);
+ break;
+ default:
+ pr_err("Not a typewriter! Command: 0x%x", cmd);
+ ret = -ENOTTY;
+ break;
+ }
+ return ret;
+}
+
static int adv7481_get_sd_timings(struct adv7481_state *state, int *sd_standard)
{
int ret = 0;
@@ -620,18 +1058,22 @@ static int adv7481_get_sd_timings(struct adv7481_state *state, int *sd_standard)
if (sd_standard == NULL)
return -EINVAL;
+ /* Select SDP read-only main Map */
+ adv7481_wr_byte(&state->i2c_client, state->i2c_sdp_addr,
+ SDP_RW_MAP_REG, 0x01);
do {
- sdp_stat = adv7481_rd_byte(state->i2c_sdp,
- SDP_RO_MAIN_STATUS1_ADDR);
+ sdp_stat = adv7481_rd_byte(&state->i2c_client,
+ state->i2c_sdp_addr, SDP_RO_MAIN_STATUS1_ADDR);
usleep_range(SDP_MIN_SLEEP, SDP_MAX_SLEEP);
timeout++;
- sdp_stat2 = adv7481_rd_byte(state->i2c_sdp,
- SDP_RO_MAIN_STATUS1_ADDR);
+ sdp_stat2 = adv7481_rd_byte(&state->i2c_client,
+ state->i2c_sdp_addr, SDP_RO_MAIN_STATUS1_ADDR);
} while ((sdp_stat != sdp_stat2) && (timeout < SDP_NUM_TRIES));
+ adv7481_wr_byte(&state->i2c_client, state->i2c_sdp_addr,
+ SDP_RW_MAP_REG, 0x00);
if (sdp_stat != sdp_stat2) {
- pr_err("%s(%d), adv7481 SDP status unstable: 1\n",
- __func__, __LINE__);
+ pr_err("%s, adv7481 SDP status unstable: 1\n", __func__);
return -ETIMEDOUT;
}
@@ -681,22 +1123,50 @@ static int adv7481_set_cvbs_mode(struct adv7481_state *state)
pr_debug("Enter %s\n", __func__);
state->mode = ADV7481_IP_CVBS_1;
/* cvbs video settings ntsc etc */
- ret = adv7481_wr_byte(state->client, 0x00, 0x30);
- ret |= adv7481_wr_byte(state->i2c_sdp, 0x0f, 0x00);
- ret |= adv7481_wr_byte(state->i2c_sdp, 0x00, 0x00);
- ret |= adv7481_wr_byte(state->i2c_sdp, 0x03, 0x42);
- ret |= adv7481_wr_byte(state->i2c_sdp, 0x04, 0x07);
- ret |= adv7481_wr_byte(state->i2c_sdp, 0x13, 0x00);
- ret |= adv7481_wr_byte(state->i2c_sdp, 0x17, 0x41);
- ret |= adv7481_wr_byte(state->i2c_sdp, 0x31, 0x12);
- ret |= adv7481_wr_byte(state->i2c_sdp, 0x52, 0xcd);
- ret |= adv7481_wr_byte(state->i2c_sdp, 0x0e, 0xff);
- val = adv7481_rd_byte(state->client, IO_REG_CSI_PIX_EN_SEL_ADDR);
+ ret = adv7481_wr_byte(&state->i2c_client, state->i2c_io_addr,
+ 0x00, 0x30);
+ ret = adv7481_wr_byte(&state->i2c_client, state->i2c_io_addr,
+ 0x0e, 0xff);
+ ret |= adv7481_wr_byte(&state->i2c_client, state->i2c_sdp_addr,
+ 0x0f, 0x00);
+ ret |= adv7481_wr_byte(&state->i2c_client, state->i2c_sdp_addr,
+ 0x52, 0xcd);
+ ret |= adv7481_wr_byte(&state->i2c_client, state->i2c_sdp_addr,
+ 0x00, 0x00);
+ ret |= adv7481_wr_byte(&state->i2c_client, state->i2c_sdp_addr,
+ SDP_RW_MAP_REG, 0x80);
+ ret |= adv7481_wr_byte(&state->i2c_client, state->i2c_sdp_addr,
+ 0x9c, 0x00);
+ ret |= adv7481_wr_byte(&state->i2c_client, state->i2c_sdp_addr,
+ 0x9c, 0xff);
+ ret |= adv7481_wr_byte(&state->i2c_client, state->i2c_sdp_addr,
+ SDP_RW_MAP_REG, 0x00);
+ ret |= adv7481_wr_byte(&state->i2c_client, state->i2c_sdp_addr,
+ 0x80, 0x51);
+ ret |= adv7481_wr_byte(&state->i2c_client, state->i2c_sdp_addr,
+ 0x81, 0x51);
+ ret |= adv7481_wr_byte(&state->i2c_client, state->i2c_sdp_addr,
+ 0x82, 0x68);
+ ret |= adv7481_wr_byte(&state->i2c_client, state->i2c_sdp_addr,
+ 0x03, 0x42);
+ ret |= adv7481_wr_byte(&state->i2c_client, state->i2c_sdp_addr,
+ 0x04, 0x07);
+ ret |= adv7481_wr_byte(&state->i2c_client, state->i2c_sdp_addr,
+ 0x13, 0x00);
+ ret |= adv7481_wr_byte(&state->i2c_client, state->i2c_sdp_addr,
+ 0x17, 0x41);
+ ret |= adv7481_wr_byte(&state->i2c_client, state->i2c_sdp_addr,
+ 0x31, 0x12);
+
+ val = adv7481_rd_byte(&state->i2c_client, state->i2c_io_addr,
+ IO_REG_CSI_PIX_EN_SEL_ADDR);
/* Output of SD core routed to MIPI CSI 4-lane Tx */
- val |= ADV_REG_SETFIELD(0x10, IO_CTRL_CSI4_IN_SEL);
- ret |= adv7481_wr_byte(state->client, IO_REG_CSI_PIX_EN_SEL_ADDR, val);
- /* Enable autodetect */
- ret |= adv7481_wr_byte(state->i2c_sdp, 0x0e, 0x81);
+ val = ADV_REG_SETFIELD(1, IO_CTRL_CSI4_EN) |
+ ADV_REG_SETFIELD(1, IO_CTRL_PIX_OUT_EN) |
+ ADV_REG_SETFIELD(0x2, IO_CTRL_CSI4_IN_SEL);
+
+ ret |= adv7481_wr_byte(&state->i2c_client, state->i2c_io_addr,
+ IO_REG_CSI_PIX_EN_SEL_ADDR, val);
return ret;
}
@@ -713,69 +1183,101 @@ static int adv7481_set_hdmi_mode(struct adv7481_state *state)
* YUV 422 out via TxA CSI: 4-Lane
*/
/* Disable chip powerdown & Enable HDMI Rx block */
- temp = adv7481_rd_byte(state->client, IO_REG_PWR_DOWN_CTRL_ADDR);
+ temp = adv7481_rd_byte(&state->i2c_client, state->i2c_io_addr,
+ IO_REG_PWR_DOWN_CTRL_ADDR);
val = ADV_REG_SETFIELD(1, IO_CTRL_RX_EN) |
ADV_REG_SETFIELD(0, IO_CTRL_RX_PWDN) |
ADV_REG_SETFIELD(0, IO_CTRL_XTAL_PWDN) |
ADV_REG_SETFIELD(0, IO_CTRL_CORE_PWDN) |
ADV_REG_SETFIELD(0, IO_CTRL_MASTER_PWDN);
- ret = adv7481_wr_byte(state->client, IO_REG_PWR_DOWN_CTRL_ADDR, val);
+ ret = adv7481_wr_byte(&state->i2c_client, state->i2c_io_addr,
+ IO_REG_PWR_DOWN_CTRL_ADDR, val);
/* SDR mode */
- ret |= adv7481_wr_byte(state->client, 0x11, 0x48);
+ ret |= adv7481_wr_byte(&state->i2c_client, state->i2c_io_addr,
+ 0x11, 0x48);
/* Set CP core to YUV out */
- ret |= adv7481_wr_byte(state->client, 0x04, 0x00);
+ ret |= adv7481_wr_byte(&state->i2c_client, state->i2c_io_addr,
+ 0x04, 0x00);
/* Set CP core to SDR 422 */
- ret |= adv7481_wr_byte(state->client, 0x12, 0xF2);
+ ret |= adv7481_wr_byte(&state->i2c_client, state->i2c_io_addr,
+ 0x12, 0xF2);
/* Saturate both Luma and Chroma values to 254 */
- ret |= adv7481_wr_byte(state->client, 0x17, 0x80);
+ ret |= adv7481_wr_byte(&state->i2c_client, state->i2c_io_addr,
+ 0x17, 0x80);
/* Set CP core to enable AV codes */
- ret |= adv7481_wr_byte(state->client, 0x03, 0x86);
+ ret |= adv7481_wr_byte(&state->i2c_client, state->i2c_io_addr,
+ 0x03, 0x86);
/* ADI RS CP Core: */
- ret |= adv7481_wr_byte(state->i2c_cp, 0x7C, 0x00);
+ ret |= adv7481_wr_byte(&state->i2c_client, state->i2c_cp_addr,
+ 0x7C, 0x00);
/* Set CP core Phase Adjustment */
- ret |= adv7481_wr_byte(state->client, 0x0C, 0xE0);
+ ret |= adv7481_wr_byte(&state->i2c_client, state->i2c_io_addr,
+ 0x0C, 0xE0);
/* LLC/PIX/SPI PINS TRISTATED AUD Outputs Enabled */
- ret |= adv7481_wr_byte(state->client, IO_PAD_CTRLS_ADDR, 0xDD);
+ ret |= adv7481_wr_byte(&state->i2c_client, state->i2c_io_addr,
+ IO_PAD_CTRLS_ADDR, 0xDD);
/* Enable Tx A CSI 4-Lane & data from CP core */
val = ADV_REG_SETFIELD(1, IO_CTRL_CSI4_EN) |
ADV_REG_SETFIELD(1, IO_CTRL_PIX_OUT_EN) |
ADV_REG_SETFIELD(0, IO_CTRL_CSI4_IN_SEL);
- ret |= adv7481_wr_byte(state->client, IO_REG_CSI_PIX_EN_SEL_ADDR,
- val);
+ ret |= adv7481_wr_byte(&state->i2c_client, state->i2c_io_addr,
+ IO_REG_CSI_PIX_EN_SEL_ADDR, val);
/* start to configure HDMI Rx once io-map is configured */
/* Enable HDCP 1.1 */
- ret |= adv7481_wr_byte(state->i2c_rep, 0x40, 0x83);
+ ret |= adv7481_wr_byte(&state->i2c_client, state->i2c_rep_addr,
+ 0x40, 0x83);
/* Foreground Channel = A */
- ret |= adv7481_wr_byte(state->i2c_hdmi, 0x00, 0x08);
+ ret |= adv7481_wr_byte(&state->i2c_client, state->i2c_hdmi_addr,
+ 0x00, 0x08);
/* ADI Required Write */
- ret |= adv7481_wr_byte(state->i2c_hdmi, 0x98, 0xFF);
- ret |= adv7481_wr_byte(state->i2c_hdmi, 0x99, 0xA3);
- ret |= adv7481_wr_byte(state->i2c_hdmi, 0x9A, 0x00);
- ret |= adv7481_wr_byte(state->i2c_hdmi, 0x9B, 0x0A);
- ret |= adv7481_wr_byte(state->i2c_hdmi, 0x9D, 0x40);
- ret |= adv7481_wr_byte(state->i2c_hdmi, 0xCB, 0x09);
+ ret |= adv7481_wr_byte(&state->i2c_client, state->i2c_hdmi_addr,
+ 0x98, 0xFF);
+ ret |= adv7481_wr_byte(&state->i2c_client, state->i2c_hdmi_addr,
+ 0x99, 0xA3);
+ ret |= adv7481_wr_byte(&state->i2c_client, state->i2c_hdmi_addr,
+ 0x9A, 0x00);
+ ret |= adv7481_wr_byte(&state->i2c_client, state->i2c_hdmi_addr,
+ 0x9B, 0x0A);
+ ret |= adv7481_wr_byte(&state->i2c_client, state->i2c_hdmi_addr,
+ 0x9D, 0x40);
+ ret |= adv7481_wr_byte(&state->i2c_client, state->i2c_hdmi_addr,
+ 0xCB, 0x09);
/* ADI RS */
- ret |= adv7481_wr_byte(state->i2c_hdmi, 0x3D, 0x10);
- ret |= adv7481_wr_byte(state->i2c_hdmi, 0x3E, 0x7B);
- ret |= adv7481_wr_byte(state->i2c_hdmi, 0x3F, 0x5E);
- ret |= adv7481_wr_byte(state->i2c_hdmi, 0x4E, 0xFE);
- ret |= adv7481_wr_byte(state->i2c_hdmi, 0x4F, 0x18);
- ret |= adv7481_wr_byte(state->i2c_hdmi, 0x57, 0xA3);
- ret |= adv7481_wr_byte(state->i2c_hdmi, 0x58, 0x04);
- ret |= adv7481_wr_byte(state->i2c_hdmi, 0x85, 0x10);
+ ret |= adv7481_wr_byte(&state->i2c_client, state->i2c_hdmi_addr,
+ 0x3D, 0x10);
+ ret |= adv7481_wr_byte(&state->i2c_client, state->i2c_hdmi_addr,
+ 0x3E, 0x7B);
+ ret |= adv7481_wr_byte(&state->i2c_client, state->i2c_hdmi_addr,
+ 0x3F, 0x5E);
+ ret |= adv7481_wr_byte(&state->i2c_client, state->i2c_hdmi_addr,
+ 0x4E, 0xFE);
+ ret |= adv7481_wr_byte(&state->i2c_client, state->i2c_hdmi_addr,
+ 0x4F, 0x18);
+ ret |= adv7481_wr_byte(&state->i2c_client, state->i2c_hdmi_addr,
+ 0x57, 0xA3);
+ ret |= adv7481_wr_byte(&state->i2c_client, state->i2c_hdmi_addr,
+ 0x58, 0x04);
+ ret |= adv7481_wr_byte(&state->i2c_client, state->i2c_hdmi_addr,
+ 0x85, 0x10);
/* Enable All Terminations */
- ret |= adv7481_wr_byte(state->i2c_hdmi, 0x83, 0x00);
+ ret |= adv7481_wr_byte(&state->i2c_client, state->i2c_hdmi_addr,
+ 0x83, 0x00);
/* ADI RS */
- ret |= adv7481_wr_byte(state->i2c_hdmi, 0xA3, 0x01);
- ret |= adv7481_wr_byte(state->i2c_hdmi, 0xBE, 0x00);
+ ret |= adv7481_wr_byte(&state->i2c_client, state->i2c_hdmi_addr,
+ 0xA3, 0x01);
+ ret |= adv7481_wr_byte(&state->i2c_client, state->i2c_hdmi_addr,
+ 0xBE, 0x00);
/* HPA Manual Enable */
- ret |= adv7481_wr_byte(state->i2c_hdmi, 0x6C, 0x01);
+ ret |= adv7481_wr_byte(&state->i2c_client, state->i2c_hdmi_addr,
+ 0x6C, 0x01);
/* HPA Asserted */
- ret |= adv7481_wr_byte(state->i2c_hdmi, 0xF8, 0x01);
+ ret |= adv7481_wr_byte(&state->i2c_client, state->i2c_hdmi_addr,
+ 0xF8, 0x01);
/* Audio Mute Speed Set to Fastest (Smallest Step Size) */
- ret |= adv7481_wr_byte(state->i2c_hdmi, 0x0F, 0x00);
+ ret |= adv7481_wr_byte(&state->i2c_client, state->i2c_hdmi_addr,
+ 0x0F, 0x00);
return ret;
}
@@ -860,7 +1362,7 @@ static int adv7481_set_ip_mode(struct adv7481_state *state, int input)
}
static int adv7481_set_op_src(struct adv7481_state *state,
- int output, int input)
+ int output, int input)
{
int ret = 0;
int temp = 0;
@@ -897,10 +1399,11 @@ static int adv7481_set_op_src(struct adv7481_state *state,
default:
ret = -EINVAL;
}
- temp = adv7481_rd_byte(state->client,
+ temp = adv7481_rd_byte(&state->i2c_client, state->i2c_io_addr,
IO_REG_PWR_DOWN_CTRL_ADDR);
temp |= val;
- adv7481_wr_byte(state->client, IO_REG_PWR_DOWN_CTRL_ADDR, temp);
+ adv7481_wr_byte(&state->i2c_client, state->i2c_io_addr,
+ IO_REG_PWR_DOWN_CTRL_ADDR, temp);
state->csia_src = input;
break;
case ADV7481_OP_CSIB:
@@ -915,11 +1418,11 @@ static int adv7481_set_op_src(struct adv7481_state *state,
return ret;
}
-static u32 ba_inp_to_adv7481(u32 input)
+static u32 ba_inp_to_adv7481(u32 ba_input)
{
u32 adv_input = ADV7481_IP_HDMI;
- switch (input) {
+ switch (ba_input) {
case BA_IP_CVBS_0:
adv_input = ADV7481_IP_CVBS_1;
break;
@@ -954,6 +1457,42 @@ static u32 ba_inp_to_adv7481(u32 input)
return adv_input;
}
+static u32 adv7481_inp_to_ba(u32 adv_input)
+{
+ u32 ba_input = BA_IP_HDMI_1;
+
+ switch (adv_input) {
+ case ADV7481_IP_CVBS_1:
+ ba_input = BA_IP_CVBS_0;
+ break;
+ case ADV7481_IP_CVBS_2:
+ ba_input = BA_IP_CVBS_1;
+ break;
+ case ADV7481_IP_CVBS_3:
+ ba_input = BA_IP_CVBS_2;
+ break;
+ case ADV7481_IP_CVBS_4:
+ ba_input = BA_IP_CVBS_3;
+ break;
+ case ADV7481_IP_CVBS_5:
+ ba_input = BA_IP_CVBS_4;
+ break;
+ case ADV7481_IP_CVBS_6:
+ ba_input = BA_IP_CVBS_5;
+ break;
+ case ADV7481_IP_HDMI:
+ ba_input = BA_IP_HDMI_1;
+ break;
+ case ADV7481_IP_TTL:
+ ba_input = BA_IP_TTL;
+ break;
+ default:
+ ba_input = BA_IP_HDMI_1;
+ break;
+ }
+ return ba_input;
+}
+
static int adv7481_s_routing(struct v4l2_subdev *sd, u32 input,
u32 output, u32 config)
{
@@ -971,14 +1510,11 @@ static int adv7481_s_routing(struct v4l2_subdev *sd, u32 input,
goto unlock_exit;
}
- if (state->mode != adv_input) {
- ret = adv7481_set_ip_mode(state, adv_input);
- if (ret)
- pr_err("%s: Set input mode failed: %d\n",
- __func__, ret);
- else
- state->mode = adv_input;
- }
+ ret = adv7481_set_ip_mode(state, adv_input);
+ if (ret)
+ pr_err("%s: Set input mode failed: %d\n", __func__, ret);
+ else
+ state->mode = adv_input;
unlock_exit:
mutex_unlock(&state->mutex);
@@ -986,6 +1522,27 @@ unlock_exit:
return ret;
}
+static bool adv7481_is_timing_locked(struct adv7481_state *state)
+{
+ bool ret = false;
+ int val1 = 0;
+ int val2 = 0;
+
+ /* Check Timing Lock IO Map Status3:0x71[0] && 0x71[1] && 0x71[7] */
+ val1 = adv7481_rd_byte(&state->i2c_client, state->i2c_io_addr,
+ IO_HDMI_LVL_RAW_STATUS_3_ADDR);
+ val2 = adv7481_rd_byte(&state->i2c_client, state->i2c_cp_addr,
+ CP_REG_STDI_CH_ADDR);
+
+ if (ADV_REG_GETFIELD(val1, IO_DE_REGEN_LCK_RAW) &&
+ ADV_REG_GETFIELD(val1, IO_V_LOCKED_RAW) &&
+ ADV_REG_GETFIELD(val1, IO_TMDSPLL_LCK_A_RAW) &&
+ ADV_REG_GETFIELD(val2, CP_STDI_DVALID_CH1))
+ ret = true;
+
+ return ret;
+}
+
static int adv7481_get_hdmi_timings(struct adv7481_state *state,
struct adv7481_vid_params *vid_params,
struct adv7481_hdmi_params *hdmi_params)
@@ -998,13 +1555,15 @@ static int adv7481_get_hdmi_timings(struct adv7481_state *state,
pr_debug("Enter %s\n", __func__);
/* Check TMDS PLL Lock and Frequency */
- temp1 = adv7481_rd_byte(state->i2c_hdmi, HDMI_REG_HDMI_PARAM4_ADDR);
+ temp1 = adv7481_rd_byte(&state->i2c_client, state->i2c_hdmi_addr,
+ HDMI_REG_HDMI_PARAM4_ADDR);
hdmi_params->pll_lock = ADV_REG_GETFIELD(temp1,
HDMI_REG_TMDS_PLL_LOCKED);
if (hdmi_params->pll_lock) {
- temp1 = adv7481_rd_byte(state->i2c_hdmi,
- HDMI_REG_TMDS_FREQ_ADDR);
- temp2 = adv7481_rd_byte(state->i2c_hdmi,
+ temp1 = adv7481_rd_byte(&state->i2c_client,
+ state->i2c_hdmi_addr, HDMI_REG_TMDS_FREQ_ADDR);
+ temp2 = adv7481_rd_byte(&state->i2c_client,
+ state->i2c_hdmi_addr,
HDMI_REG_TMDS_FREQ_FRAC_ADDR);
hdmi_params->tmds_freq = ADV_REG_GETFIELD(temp1,
HDMI_REG_TMDS_FREQ);
@@ -1015,34 +1574,29 @@ static int adv7481_get_hdmi_timings(struct adv7481_state *state,
hdmi_params->tmds_freq += ADV_REG_GETFIELD(temp2,
HDMI_REG_TMDS_FREQ_FRAC)*ONE_MHZ_TO_HZ/128;
} else {
- pr_err("%s: PLL not locked return EBUSY\n", __func__);
- return -EBUSY;
+ pr_err("%s(%d): PLL not locked return EBUSY\n",
+ __func__, __LINE__);
+ ret = -EBUSY;
+ goto set_default;
}
- /* Check Timing Lock IO Map Status3:0x71[0] && 0x71[1] && 0x71[7] */
+ /* Check Timing Lock */
do {
- temp1 = adv7481_rd_byte(state->client,
- IO_HDMI_LVL_RAW_STATUS_3_ADDR);
- temp2 = adv7481_rd_byte(state->i2c_cp,
- CP_REG_STDI_CH_ADDR);
-
- if (ADV_REG_GETFIELD(temp1, IO_DE_REGEN_LCK_RAW) &&
- ADV_REG_GETFIELD(temp1, IO_V_LOCKED_RAW) &&
- ADV_REG_GETFIELD(temp1, IO_TMDSPLL_LCK_A_RAW) &&
- ADV_REG_GETFIELD(temp2, CP_STDI_DVALID_CH1))
+ if (adv7481_is_timing_locked(state))
break;
count++;
usleep_range(LOCK_MIN_SLEEP, LOCK_MAX_SLEEP);
} while (count < LOCK_NUM_TRIES);
if (count >= LOCK_NUM_TRIES) {
- pr_err("%s(%d), adv7481 HDMI DE regeneration block NOT Locked: 0x%x",
- __func__, __LINE__, temp1);
+ pr_err("%s(%d), HDMI DE regeneration block NOT Locked\n",
+ __func__, __LINE__);
}
/* Check Timing Lock HDMI Map V:0x07[7], H:0x7[5] */
do {
- temp1 = adv7481_rd_byte(state->i2c_hdmi,
+ temp1 = adv7481_rd_byte(&state->i2c_client,
+ state->i2c_hdmi_addr,
HDMI_REG_LINE_WIDTH_1_ADDR);
if (ADV_REG_GETFIELD(temp1, HDMI_VERT_FILTER_LOCKED) &&
@@ -1059,7 +1613,8 @@ static int adv7481_get_hdmi_timings(struct adv7481_state *state,
}
/* Check HDMI Parameters */
- temp1 = adv7481_rd_byte(state->i2c_hdmi, HDMI_REG_FIELD1_HEIGHT1_ADDR);
+ temp1 = adv7481_rd_byte(&state->i2c_client, state->i2c_hdmi_addr,
+ HDMI_REG_FIELD1_HEIGHT1_ADDR);
hdmi_params->color_depth = ADV_REG_GETFIELD(temp1,
HDMI_REG_DEEP_COLOR_MODE);
@@ -1068,22 +1623,25 @@ static int adv7481_get_hdmi_timings(struct adv7481_state *state,
HDMI_REG_HDMI_INTERLACED);
fieldfactor = (vid_params->intrlcd == 1) ? 2 : 1;
- temp1 = adv7481_rd_byte(state->i2c_hdmi, HDMI_REG_HDMI_PARAM5_ADDR);
+ temp1 = adv7481_rd_byte(&state->i2c_client, state->i2c_hdmi_addr,
+ HDMI_REG_HDMI_PARAM5_ADDR);
hdmi_params->pix_rep = ADV_REG_GETFIELD(temp1,
HDMI_REG_PIXEL_REPETITION);
/* Get Active Timing Data HDMI Map H:0x07[4:0] + 0x08[7:0] */
- temp1 = adv7481_rd_byte(state->i2c_hdmi, HDMI_REG_LINE_WIDTH_1_ADDR);
- temp2 = adv7481_rd_byte(state->i2c_hdmi, HDMI_REG_LINE_WIDTH_2_ADDR);
+ temp1 = adv7481_rd_byte(&state->i2c_client, state->i2c_hdmi_addr,
+ HDMI_REG_LINE_WIDTH_1_ADDR);
+ temp2 = adv7481_rd_byte(&state->i2c_client, state->i2c_hdmi_addr,
+ HDMI_REG_LINE_WIDTH_2_ADDR);
vid_params->act_pix = (((ADV_REG_GETFIELD(temp1,
HDMI_REG_LINE_WIDTH_1) << 8) & 0x1F00) |
ADV_REG_GETFIELD(temp2,
HDMI_REG_LINE_WIDTH_2));
/* Get Total Timing Data HDMI Map H:0x1E[5:0] + 0x1F[7:0] */
- temp1 = adv7481_rd_byte(state->i2c_hdmi,
+ temp1 = adv7481_rd_byte(&state->i2c_client, state->i2c_hdmi_addr,
HDMI_REG_TOTAL_LINE_WIDTH_1_ADDR);
- temp2 = adv7481_rd_byte(state->i2c_hdmi,
+ temp2 = adv7481_rd_byte(&state->i2c_client, state->i2c_hdmi_addr,
HDMI_REG_TOTAL_LINE_WIDTH_2_ADDR);
vid_params->tot_pix = (((ADV_REG_GETFIELD(temp1,
HDMI_REG_TOTAL_LINE_WIDTH_1) << 8) & 0x3F00) |
@@ -1091,9 +1649,9 @@ static int adv7481_get_hdmi_timings(struct adv7481_state *state,
HDMI_REG_TOTAL_LINE_WIDTH_2));
/* Get Active Timing Data HDMI Map V:0x09[4:0] + 0x0A[7:0] */
- temp1 = adv7481_rd_byte(state->i2c_hdmi,
+ temp1 = adv7481_rd_byte(&state->i2c_client, state->i2c_hdmi_addr,
HDMI_REG_FIELD0_HEIGHT_1_ADDR);
- temp2 = adv7481_rd_byte(state->i2c_hdmi,
+ temp2 = adv7481_rd_byte(&state->i2c_client, state->i2c_hdmi_addr,
HDMI_REG_FIELD0_HEIGHT_2_ADDR);
vid_params->act_lines = (((ADV_REG_GETFIELD(temp1,
HDMI_REG_FIELD0_HEIGHT_1) << 8) & 0x1F00) |
@@ -1101,9 +1659,9 @@ static int adv7481_get_hdmi_timings(struct adv7481_state *state,
HDMI_REG_FIELD0_HEIGHT_2));
/* Get Total Timing Data HDMI Map V:0x26[5:0] + 0x27[7:0] */
- temp1 = adv7481_rd_byte(state->i2c_hdmi,
+ temp1 = adv7481_rd_byte(&state->i2c_client, state->i2c_hdmi_addr,
HDMI_REG_FIELD0_TOTAL_HEIGHT_1_ADDR);
- temp2 = adv7481_rd_byte(state->i2c_hdmi,
+ temp2 = adv7481_rd_byte(&state->i2c_client, state->i2c_hdmi_addr,
HDMI_REG_FIELD0_TOTAL_HEIGHT_2_ADDR);
vid_params->tot_lines = (((ADV_REG_GETFIELD(temp1,
HDMI_REG_FIELD0_TOT_HEIGHT_1) << 8) & 0x3F00) |
@@ -1139,6 +1697,18 @@ static int adv7481_get_hdmi_timings(struct adv7481_state *state,
(hdmi_params->pix_rep + 1));
}
+set_default:
+ if (ret) {
+ pr_debug("%s(%d), error %d resort to default fmt\n",
+ __func__, __LINE__, ret);
+ vid_params->act_pix = MAX_DEFAULT_WIDTH;
+ vid_params->act_lines = MAX_DEFAULT_HEIGHT;
+ vid_params->fr_rate = MAX_DEFAULT_FRAME_RATE;
+ vid_params->pix_clk = MAX_DEFAULT_PIX_CLK_HZ;
+ vid_params->intrlcd = 0;
+ ret = 0;
+ }
+
pr_debug("%s(%d), adv7481 TMDS Resolution: %d x %d @ %d fps\n",
__func__, __LINE__,
vid_params->act_pix, vid_params->act_lines,
@@ -1170,15 +1740,22 @@ static int adv7481_query_dv_timings(struct v4l2_subdev *sd,
switch (state->mode) {
case ADV7481_IP_HDMI:
case ADV7481_IP_CVBS_1_HDMI_SIM:
- adv7481_get_hdmi_timings(state, &vid_params, &hdmi_params);
- timings->type = V4L2_DV_BT_656_1120;
- bt_timings->width = vid_params.act_pix;
- bt_timings->height = vid_params.act_lines;
- bt_timings->pixelclock = vid_params.pix_clk;
- bt_timings->interlaced = vid_params.intrlcd ?
+ ret = adv7481_get_hdmi_timings(state, &vid_params,
+ &hdmi_params);
+ if (!ret) {
+ timings->type = V4L2_DV_BT_656_1120;
+ bt_timings->width = vid_params.act_pix;
+ bt_timings->height = vid_params.act_lines;
+ bt_timings->pixelclock = vid_params.pix_clk;
+ bt_timings->interlaced = vid_params.intrlcd ?
V4L2_DV_INTERLACED : V4L2_DV_PROGRESSIVE;
- if (bt_timings->interlaced == V4L2_DV_INTERLACED)
- bt_timings->height /= 2;
+ if (bt_timings->interlaced == V4L2_DV_INTERLACED)
+ bt_timings->height /= 2;
+ } else {
+ pr_err(
+ "%s: Error in adv7481_get_hdmi_timings. ret %d\n",
+ __func__, ret);
+ }
break;
default:
return -EINVAL;
@@ -1193,10 +1770,24 @@ static int adv7481_query_sd_std(struct v4l2_subdev *sd, v4l2_std_id *std)
int temp = 0;
struct adv7481_state *state = to_state(sd);
uint8_t tStatus = 0x0;
+ uint32_t count = 0;
pr_debug("Enter %s\n", __func__);
- tStatus = adv7481_rd_byte(state->i2c_sdp, SDP_RO_MAIN_STATUS1_ADDR);
- if (!ADV_REG_GETFIELD(tStatus, SDP_RO_MAIN_IN_LOCK))
+ /* Select SDP read-only main Map */
+ adv7481_wr_byte(&state->i2c_client, state->i2c_sdp_addr,
+ SDP_RW_MAP_REG, 0x01);
+ do {
+ tStatus = adv7481_rd_byte(&state->i2c_client,
+ state->i2c_sdp_addr, SDP_RO_MAIN_STATUS1_ADDR);
+ if (ADV_REG_GETFIELD(tStatus, SDP_RO_MAIN_IN_LOCK))
+ break;
+ count++;
+ usleep_range(LOCK_MIN_SLEEP, LOCK_MAX_SLEEP);
+ } while (count < LOCK_NUM_TRIES);
+
+ adv7481_wr_byte(&state->i2c_client, state->i2c_sdp_addr,
+ SDP_RW_MAP_REG, 0x00);
+ if (count >= LOCK_NUM_TRIES)
pr_err("%s(%d), adv7481 SD Input NOT Locked: 0x%x\n",
__func__, __LINE__, tStatus);
@@ -1245,13 +1836,15 @@ static int adv7481_g_frame_interval(struct v4l2_subdev *sd,
return 0;
}
-static int adv7481_g_mbus_fmt(struct v4l2_subdev *sd,
- struct v4l2_mbus_framefmt *fmt)
+static int adv7481_get_fmt(struct v4l2_subdev *sd,
+ struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_format *format)
{
int ret;
struct adv7481_vid_params vid_params;
struct adv7481_hdmi_params hdmi_params;
struct adv7481_state *state = to_state(sd);
+ struct v4l2_mbus_framefmt *fmt = &format->format;
if (!fmt)
return -EINVAL;
@@ -1267,17 +1860,29 @@ static int adv7481_g_mbus_fmt(struct v4l2_subdev *sd,
switch (state->mode) {
case ADV7481_IP_HDMI:
case ADV7481_IP_CVBS_1_HDMI_SIM:
- adv7481_get_hdmi_timings(state, &vid_params, &hdmi_params);
- fmt->width = vid_params.act_pix;
- fmt->height = vid_params.act_lines;
- if (vid_params.intrlcd)
- fmt->height /= 2;
+ ret = adv7481_get_hdmi_timings(state, &vid_params,
+ &hdmi_params);
+ if (!ret) {
+ fmt->width = vid_params.act_pix;
+ fmt->height = vid_params.act_lines;
+ if (vid_params.intrlcd)
+ fmt->height /= 2;
+ } else {
+ pr_err("%s: Error %d in adv7481_get_hdmi_timings\n",
+ __func__, ret);
+ }
+ break;
+ case ADV7481_IP_CVBS_1:
+ fmt->code = MEDIA_BUS_FMT_UYVY8_2X8;
+ fmt->colorspace = V4L2_COLORSPACE_SMPTE170M;
+ fmt->width = 720;
+ fmt->height = 576;
break;
default:
return -EINVAL;
}
mutex_unlock(&state->mutex);
- fmt->code = V4L2_MBUS_FMT_UYVY8_2X8;
+ fmt->code = MEDIA_BUS_FMT_UYVY8_2X8;
fmt->colorspace = V4L2_COLORSPACE_SMPTE170M;
return ret;
}
@@ -1290,17 +1895,17 @@ static int adv7481_set_audio_spdif(struct adv7481_state *state,
if (on) {
/* Configure I2S_SDATA output pin as an SPDIF output 0x6E[3] */
- val = adv7481_rd_byte(state->i2c_hdmi,
+ val = adv7481_rd_byte(&state->i2c_client, state->i2c_hdmi_addr,
HDMI_REG_MUX_SPDIF_TO_I2S_ADDR);
val |= ADV_REG_SETFIELD(1, HDMI_MUX_SPDIF_TO_I2S_EN);
- ret = adv7481_wr_byte(state->i2c_hdmi,
+ ret = adv7481_wr_byte(&state->i2c_client, state->i2c_hdmi_addr,
HDMI_REG_MUX_SPDIF_TO_I2S_ADDR, val);
} else {
/* Configure I2S_SDATA output pin as an I2S output 0x6E[3] */
- val = adv7481_rd_byte(state->i2c_hdmi,
+ val = adv7481_rd_byte(&state->i2c_client, state->i2c_hdmi_addr,
HDMI_REG_MUX_SPDIF_TO_I2S_ADDR);
val &= ~ADV_REG_SETFIELD(1, HDMI_MUX_SPDIF_TO_I2S_EN);
- ret = adv7481_wr_byte(state->i2c_hdmi,
+ ret = adv7481_wr_byte(&state->i2c_client, state->i2c_hdmi_addr,
HDMI_REG_MUX_SPDIF_TO_I2S_ADDR, val);
}
return ret;
@@ -1310,40 +1915,42 @@ static int adv7481_csi_powerdown(struct adv7481_state *state,
enum adv7481_output output)
{
int ret;
- struct i2c_client *csi_map;
+ uint8_t csi_map;
uint8_t val = 0;
pr_debug("Enter %s for output: %d\n", __func__, output);
/* Select CSI TX to configure data */
if (output == ADV7481_OP_CSIA) {
- csi_map = state->i2c_csi_txa;
+ csi_map = state->i2c_csi_txa_addr;
} else if (output == ADV7481_OP_CSIB) {
- csi_map = state->i2c_csi_txb;
+ csi_map = state->i2c_csi_txb_addr;
} else if (output == ADV7481_OP_TTL) {
/* For now use TxA */
- csi_map = state->i2c_csi_txa;
+ csi_map = state->i2c_csi_txa_addr;
} else {
/* Default to TxA */
- csi_map = state->i2c_csi_txa;
+ csi_map = state->i2c_csi_txa_addr;
}
/* CSI Tx: power down DPHY */
- ret = adv7481_wr_byte(csi_map, CSI_REG_TX_DPHY_PWDN_ADDR,
+ ret = adv7481_wr_byte(&state->i2c_client, csi_map,
+ CSI_REG_TX_DPHY_PWDN_ADDR,
ADV_REG_SETFIELD(1, CSI_CTRL_DPHY_PWDN));
/* ADI Required Write */
- ret |= adv7481_wr_byte(csi_map, 0x31, 0x82);
- ret |= adv7481_wr_byte(csi_map, 0x1e, 0x00);
+ ret |= adv7481_wr_byte(&state->i2c_client, csi_map, 0x31, 0x82);
+ ret |= adv7481_wr_byte(&state->i2c_client, csi_map, 0x1e, 0x00);
/* CSI TxA: # Lane : Power Off */
val = ADV_REG_SETFIELD(1, CSI_CTRL_TX_PWRDN) |
ADV_REG_SETFIELD(state->tx_lanes, CSI_CTRL_NUM_LANES);
- ret |= adv7481_wr_byte(csi_map, CSI_REG_TX_CFG1_ADDR, val);
+ ret |= adv7481_wr_byte(&state->i2c_client, csi_map,
+ CSI_REG_TX_CFG1_ADDR, val);
/*
* ADI Recommended power down sequence
* DPHY and CSI Tx A Power down Sequence
* CSI TxA: MIPI PLL DIS
*/
- ret |= adv7481_wr_byte(csi_map, 0xda, 0x00);
+ ret |= adv7481_wr_byte(&state->i2c_client, csi_map, 0xda, 0x00);
/* ADI Required Write */
- ret |= adv7481_wr_byte(csi_map, 0xc1, 0x3b);
+ ret |= adv7481_wr_byte(&state->i2c_client, csi_map, 0xc1, 0x3b);
pr_debug("Exit %s, ret: %d\n", __func__, ret);
@@ -1354,17 +1961,23 @@ static int adv7481_csi_powerup(struct adv7481_state *state,
enum adv7481_output output)
{
int ret;
- struct i2c_client *csi_map;
+ uint8_t csi_map;
uint8_t val = 0;
uint8_t csi_sel = 0;
pr_debug("Enter %s for output: %d\n", __func__, output);
/* Select CSI TX to configure data */
if (output == ADV7481_OP_CSIA) {
- csi_sel = ADV_REG_SETFIELD(1, IO_CTRL_CSI4_EN) |
- ADV_REG_SETFIELD(1, IO_CTRL_PIX_OUT_EN) |
- ADV_REG_SETFIELD(0, IO_CTRL_CSI4_IN_SEL);
- csi_map = state->i2c_csi_txa;
+ if (state->csia_src == ADV7481_IP_HDMI) {
+ csi_sel = ADV_REG_SETFIELD(1, IO_CTRL_CSI4_EN) |
+ ADV_REG_SETFIELD(1, IO_CTRL_PIX_OUT_EN) |
+ ADV_REG_SETFIELD(0, IO_CTRL_CSI4_IN_SEL);
+ } else {
+ csi_sel = ADV_REG_SETFIELD(1, IO_CTRL_CSI4_EN) |
+ ADV_REG_SETFIELD(1, IO_CTRL_PIX_OUT_EN) |
+ ADV_REG_SETFIELD(0x2, IO_CTRL_CSI4_IN_SEL);
+ }
+ csi_map = state->i2c_csi_txa_addr;
} else if (output == ADV7481_OP_CSIB) {
/* Enable 1-Lane MIPI Tx, enable pixel output and
* route SD through Pixel port
@@ -1373,54 +1986,57 @@ static int adv7481_csi_powerup(struct adv7481_state *state,
ADV_REG_SETFIELD(1, IO_CTRL_PIX_OUT_EN) |
ADV_REG_SETFIELD(1, IO_CTRL_SD_THRU_PIX_OUT) |
ADV_REG_SETFIELD(0, IO_CTRL_CSI4_IN_SEL);
- csi_map = state->i2c_csi_txb;
+ csi_map = state->i2c_csi_txb_addr;
} else if (output == ADV7481_OP_TTL) {
/* For now use TxA */
- csi_map = state->i2c_csi_txa;
+ csi_map = state->i2c_csi_txa_addr;
} else {
/* Default to TxA */
- csi_map = state->i2c_csi_txa;
+ csi_map = state->i2c_csi_txa_addr;
}
/* Enable Tx A/B CSI #-lane */
- ret = adv7481_wr_byte(state->client,
+ ret = adv7481_wr_byte(&state->i2c_client, state->i2c_io_addr,
IO_REG_CSI_PIX_EN_SEL_ADDR, csi_sel);
/* TXA MIPI lane settings for CSI */
/* CSI TxA: # Lane : Power Off */
val = ADV_REG_SETFIELD(1, CSI_CTRL_TX_PWRDN) |
ADV_REG_SETFIELD(state->tx_lanes, CSI_CTRL_NUM_LANES);
- ret |= adv7481_wr_byte(csi_map, CSI_REG_TX_CFG1_ADDR, val);
+ ret |= adv7481_wr_byte(&state->i2c_client, csi_map,
+ CSI_REG_TX_CFG1_ADDR, val);
/* CSI TxA: Auto D-PHY Timing */
val |= ADV_REG_SETFIELD(1, CSI_CTRL_AUTO_PARAMS);
- ret |= adv7481_wr_byte(csi_map, CSI_REG_TX_CFG1_ADDR, val);
+ ret |= adv7481_wr_byte(&state->i2c_client, csi_map,
+ CSI_REG_TX_CFG1_ADDR, val);
/* DPHY and CSI Tx A */
- ret |= adv7481_wr_byte(csi_map, 0xdb, 0x10);
- ret |= adv7481_wr_byte(csi_map, 0xd6, 0x07);
- ret |= adv7481_wr_byte(csi_map, 0xc4, 0x0a);
- ret |= adv7481_wr_byte(csi_map, 0x71, 0x33);
- ret |= adv7481_wr_byte(csi_map, 0x72, 0x11);
+ ret |= adv7481_wr_byte(&state->i2c_client, csi_map, 0xdb, 0x10);
+ ret |= adv7481_wr_byte(&state->i2c_client, csi_map, 0xd6, 0x07);
+ ret |= adv7481_wr_byte(&state->i2c_client, csi_map, 0xc4, 0x0a);
+ ret |= adv7481_wr_byte(&state->i2c_client, csi_map, 0x71, 0x33);
+ ret |= adv7481_wr_byte(&state->i2c_client, csi_map, 0x72, 0x11);
/* CSI TxA: power up DPHY */
- ret |= adv7481_wr_byte(csi_map, 0xf0, 0x00);
+ ret |= adv7481_wr_byte(&state->i2c_client, csi_map, 0xf0, 0x00);
/* ADI Required Write */
- ret |= adv7481_wr_byte(csi_map, 0x31, 0x82);
- ret |= adv7481_wr_byte(csi_map, 0x1e, 0x40);
+ ret |= adv7481_wr_byte(&state->i2c_client, csi_map, 0x31, 0x82);
+ ret |= adv7481_wr_byte(&state->i2c_client, csi_map, 0x1e, 0x40);
/* adi Recommended power up sequence */
/* DPHY and CSI Tx A Power up Sequence */
/* CSI TxA: MIPI PLL EN */
- ret |= adv7481_wr_byte(csi_map, 0xda, 0x01);
+ ret |= adv7481_wr_byte(&state->i2c_client, csi_map, 0xda, 0x01);
msleep(200);
/* CSI TxA: # MIPI Lane : Power ON */
val = ADV_REG_SETFIELD(0, CSI_CTRL_TX_PWRDN) |
ADV_REG_SETFIELD(1, CSI_CTRL_AUTO_PARAMS) |
ADV_REG_SETFIELD(state->tx_lanes, CSI_CTRL_NUM_LANES);
- ret |= adv7481_wr_byte(csi_map, CSI_REG_TX_CFG1_ADDR, val);
+ ret |= adv7481_wr_byte(&state->i2c_client, csi_map,
+ CSI_REG_TX_CFG1_ADDR, val);
msleep(100);
/* ADI Required Write */
- ret |= adv7481_wr_byte(csi_map, 0xc1, 0x2b);
+ ret |= adv7481_wr_byte(&state->i2c_client, csi_map, 0xc1, 0x2b);
msleep(100);
/* ADI Required Write */
- ret |= adv7481_wr_byte(csi_map, 0x31, 0x80);
+ ret |= adv7481_wr_byte(&state->i2c_client, csi_map, 0x31, 0x80);
pr_debug("Exit %s, ret: %d\n", __func__, ret);
@@ -1476,42 +2092,43 @@ static int adv7481_g_input_status(struct v4l2_subdev *sd, u32 *status)
{
int ret = 0;
struct adv7481_state *state = to_state(sd);
- uint8_t val1 = 0;
- uint8_t val2 = 0;
+ uint8_t val = 0;
uint32_t count = 0;
+ *status = 0;
pr_debug("Enter %s\n", __func__);
if (ADV7481_IP_HDMI == state->mode) {
- /*
- * Check Timing Lock IO Map Status3:0x71[0] &&
- * 0x71[1] && 0x71[7]
- */
+ /* Check Timing Lock */
do {
- val1 = adv7481_rd_byte(state->client,
- IO_HDMI_LVL_RAW_STATUS_3_ADDR);
- val2 = adv7481_rd_byte(state->i2c_cp,
- CP_REG_STDI_CH_ADDR);
-
- if (ADV_REG_GETFIELD(val1, IO_DE_REGEN_LCK_RAW) &&
- ADV_REG_GETFIELD(val1, IO_V_LOCKED_RAW) &&
- ADV_REG_GETFIELD(val1, IO_TMDSPLL_LCK_A_RAW) &&
- ADV_REG_GETFIELD(val2, CP_STDI_DVALID_CH1))
+ if (adv7481_is_timing_locked(state))
break;
count++;
usleep_range(LOCK_MIN_SLEEP, LOCK_MAX_SLEEP);
} while (count < LOCK_NUM_TRIES);
if (count >= LOCK_NUM_TRIES) {
- pr_err("%s(%d), HDMI DE regeneration block NOT Locked: 0x%x, 0x%x",
- __func__, __LINE__, val1, val2);
+ pr_err("%s(%d), HDMI DE regeneration block NOT Locked\n",
+ __func__, __LINE__);
*status |= V4L2_IN_ST_NO_SIGNAL;
}
} else {
- val1 = adv7481_rd_byte(state->i2c_sdp,
- SDP_RO_MAIN_STATUS1_ADDR);
- if (!ADV_REG_GETFIELD(val1, SDP_RO_MAIN_IN_LOCK)) {
+ /* Select SDP read-only main Map */
+ adv7481_wr_byte(&state->i2c_client, state->i2c_sdp_addr,
+ SDP_RW_MAP_REG, 0x01);
+ do {
+ val = adv7481_rd_byte(&state->i2c_client,
+ state->i2c_sdp_addr, SDP_RO_MAIN_STATUS1_ADDR);
+ if (ADV_REG_GETFIELD(val, SDP_RO_MAIN_IN_LOCK))
+ break;
+ count++;
+ usleep_range(LOCK_MIN_SLEEP, LOCK_MAX_SLEEP);
+ } while (count < LOCK_NUM_TRIES);
+
+ adv7481_wr_byte(&state->i2c_client, state->i2c_sdp_addr,
+ SDP_RW_MAP_REG, 0x00);
+ if (count >= LOCK_NUM_TRIES) {
pr_err("%s(%d), SD Input NOT Locked: 0x%x\n",
- __func__, __LINE__, val1);
+ __func__, __LINE__, val);
*status |= V4L2_IN_ST_NO_SIGNAL;
}
}
@@ -1530,7 +2147,6 @@ static int adv7481_s_stream(struct v4l2_subdev *sd, int on)
static const struct v4l2_subdev_video_ops adv7481_video_ops = {
.s_routing = adv7481_s_routing,
.g_frame_interval = adv7481_g_frame_interval,
- .g_mbus_fmt = adv7481_g_mbus_fmt,
.querystd = adv7481_query_sd_std,
.g_dv_timings = adv7481_query_dv_timings,
.g_input_status = adv7481_g_input_status,
@@ -1539,6 +2155,11 @@ static const struct v4l2_subdev_video_ops adv7481_video_ops = {
static const struct v4l2_subdev_core_ops adv7481_core_ops = {
.s_power = adv7481_s_power,
+ .ioctl = adv7481_ioctl,
+};
+
+static const struct v4l2_subdev_pad_ops adv7481_pad_ops = {
+ .get_fmt = adv7481_get_fmt,
};
static const struct v4l2_ctrl_ops adv7481_ctrl_ops = {
@@ -1548,10 +2169,13 @@ static const struct v4l2_ctrl_ops adv7481_ctrl_ops = {
static const struct v4l2_subdev_ops adv7481_ops = {
.core = &adv7481_core_ops,
.video = &adv7481_video_ops,
+ .pad = &adv7481_pad_ops,
};
static int adv7481_init_v4l2_controls(struct adv7481_state *state)
{
+ int ret = 0;
+
v4l2_ctrl_handler_init(&state->ctrl_hdl, 4);
v4l2_ctrl_new_std(&state->ctrl_hdl, &adv7481_ctrl_ops,
@@ -1565,59 +2189,195 @@ static int adv7481_init_v4l2_controls(struct adv7481_state *state)
state->sd.ctrl_handler = &state->ctrl_hdl;
if (state->ctrl_hdl.error) {
- int err = state->ctrl_hdl.error;
+ ret = state->ctrl_hdl.error;
v4l2_ctrl_handler_free(&state->ctrl_hdl);
- return err;
+ } else {
+ v4l2_ctrl_handler_setup(&state->ctrl_hdl);
}
- v4l2_ctrl_handler_setup(&state->ctrl_hdl);
- return 0;
+ pr_err("%s: Exit with ret: %d\n", __func__, ret);
+ return ret;
+}
+
+static struct msm_camera_i2c_fn_t msm_sensor_cci_func_tbl = {
+ .i2c_read = msm_camera_cci_i2c_read,
+ .i2c_read_seq = msm_camera_cci_i2c_read_seq,
+ .i2c_write = msm_camera_cci_i2c_write,
+ .i2c_write_seq = msm_camera_cci_i2c_write_seq,
+ .i2c_write_table = msm_camera_cci_i2c_write_table,
+ .i2c_write_seq_table = msm_camera_cci_i2c_write_seq_table,
+ .i2c_write_table_w_microdelay =
+ msm_camera_cci_i2c_write_table_w_microdelay,
+ .i2c_util = msm_sensor_cci_i2c_util,
+ .i2c_poll = msm_camera_cci_i2c_poll,
+};
+
+static int adv7481_cci_init(struct adv7481_state *state)
+{
+ struct msm_camera_cci_client *cci_client = NULL;
+ int ret = 0;
+
+ pr_err("%s: Enter\n", __func__);
+
+ state->i2c_client.i2c_func_tbl = &msm_sensor_cci_func_tbl;
+ state->i2c_client.addr_type = MSM_CAMERA_I2C_BYTE_ADDR;
+ state->i2c_client.cci_client = kzalloc(sizeof(
+ struct msm_camera_cci_client), GFP_KERNEL);
+ cci_client = state->i2c_client.cci_client;
+ if (!cci_client) {
+ ret = -ENOMEM;
+ goto err_cci_init;
+ }
+ cci_client->cci_subdev = msm_cci_get_subdev();
+ pr_debug("%s cci_subdev: %p\n", __func__, cci_client->cci_subdev);
+ if (!cci_client->cci_subdev) {
+ ret = -EPROBE_DEFER;
+ goto err_cci_init;
+ }
+ cci_client->cci_i2c_master = state->cci_master;
+ cci_client->sid = state->i2c_slave_addr;
+ cci_client->retries = 3;
+ cci_client->id_map = 0;
+ cci_client->i2c_freq_mode = I2C_CUSTOM_MODE;
+ ret = state->i2c_client.i2c_func_tbl->i2c_util(
+ &state->i2c_client, MSM_CCI_INIT);
+ if (ret < 0)
+ pr_err("%s - cci_init failed\n", __func__);
+ else
+ state->clocks_requested = TRUE;
+
+ pr_debug("%s i2c_client.client: %p\n", __func__,
+ state->i2c_client.client);
+
+err_cci_init:
+ return ret;
}
-static int adv7481_probe(struct i2c_client *client,
- const struct i2c_device_id *id)
+static int adv7481_parse_dt(struct platform_device *pdev,
+ struct adv7481_state *state)
+{
+ struct device_node *np = state->dev->of_node;
+ uint32_t i = 0;
+ int gpio_count = 0;
+ struct resource *adv_addr_res = NULL;
+ int ret = 0;
+
+ /* config CCI */
+ ret = of_property_read_u32(np, "qcom,cci-master",
+ &state->cci_master);
+ if (ret < 0 || state->cci_master >= MASTER_MAX) {
+ pr_err("%s: failed to read cci master . ret %d\n",
+ __func__, ret);
+ goto exit;
+ }
+ pr_debug("%s: cci_master: 0x%x\n", __func__, state->cci_master);
+ adv_addr_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!adv_addr_res) {
+ pr_err("%s: failed to read adv7481 resource.\n", __func__);
+ goto exit;
+ }
+ state->i2c_slave_addr = adv_addr_res->start;
+ pr_debug("%s: i2c_slave_addr: 0x%x\n", __func__, state->i2c_slave_addr);
+ state->i2c_io_addr = (uint8_t)state->i2c_slave_addr;
+
+ gpio_count = of_gpio_count(np);
+ if (gpio_count != ADV7481_GPIO_MAX) {
+ ret = -EFAULT;
+ pr_err("%s: dt gpio count %d doesn't match required. ret %d\n",
+ __func__, gpio_count, ret);
+ goto exit;
+ }
+ for (i = 0; i < ADV7481_GPIO_MAX; i++) {
+ state->gpio_array[i].gpio = of_get_gpio_flags(np, i,
+ (enum of_gpio_flags *)&state->gpio_array[i].flags);
+ if (!gpio_is_valid(state->gpio_array[i].gpio)) {
+ pr_err("invalid gpio setting for index %d\n", i);
+ ret = -EFAULT;
+ goto exit;
+ }
+ pr_debug("%s: gpio_array[%d] = %d flag = %ld\n", __func__, i,
+ state->gpio_array[i].gpio, state->gpio_array[i].flags);
+ }
+
+exit:
+ return ret;
+}
+
+static const struct of_device_id adv7481_id[] = {
+ { .compatible = "qcom,adv7481", },
+ { /* end of list */ },
+};
+MODULE_DEVICE_TABLE(of, adv7481_id);
+
+static int adv7481_probe(struct platform_device *pdev)
{
struct adv7481_state *state;
- struct adv7481_platform_data *pdata = NULL;
+ const struct of_device_id *device_id;
struct v4l2_subdev *sd;
- struct v4l2_ctrl_handler *hdl;
int ret;
- pr_debug("Attempting to probe...\n");
- /* Check if the adapter supports the needed features */
- if (!i2c_check_functionality(client->adapter,
- I2C_FUNC_SMBUS_BYTE_DATA)) {
- pr_err("%s %s Check i2c Functionality Fail\n",
- __func__, client->name);
- ret = -EIO;
+ device_id = of_match_device(adv7481_id, &pdev->dev);
+ if (!device_id) {
+ pr_err("%s: device_id is NULL\n", __func__);
+ ret = -ENODEV;
goto err;
}
- v4l_info(client, "chip found @ 0x%02x (%s)\n",
- client->addr, client->adapter->name);
/* Create 7481 State */
- state = devm_kzalloc(&client->dev,
- sizeof(struct adv7481_state), GFP_KERNEL);
+ state = devm_kzalloc(&pdev->dev,
+ sizeof(struct adv7481_state), GFP_KERNEL);
if (state == NULL) {
ret = -ENOMEM;
- pr_err("Check Kzalloc Fail\n");
- goto err_mem;
+ goto err;
}
- state->client = client;
+ platform_set_drvdata(pdev, state);
+ state->dev = &pdev->dev;
+
mutex_init(&state->mutex);
+ ret = adv7481_parse_dt(pdev, state);
+ if (ret < 0) {
+ pr_err("Error parsing dt tree\n");
+ goto err_mem_free;
+ }
- /* Get and Check Platform Data */
- pdata = (struct adv7481_platform_data *) client->dev.platform_data;
- if (!pdata) {
- ret = -ENOMEM;
- pr_err("Getting Platform data failed\n");
- goto err_mem;
+ ret = adv7481_cci_init(state);
+ if (ret < 0) {
+ pr_err("%s: failed adv7481_cci_init ret %d\n", __func__, ret);
+ goto err_mem_free;
+ }
+
+ /* config VREG */
+ ret = msm_camera_get_dt_vreg_data(pdev->dev.of_node,
+ &(state->cci_vreg), &(state->regulator_count));
+ if (ret < 0) {
+ pr_err("%s:cci get_dt_vreg failed\n", __func__);
+ goto err_mem_free;
+ }
+
+ ret = msm_camera_config_vreg(&pdev->dev, state->cci_vreg,
+ state->regulator_count, NULL, 0,
+ &state->cci_reg_ptr[0], 1);
+ if (ret < 0) {
+ pr_err("%s:cci config_vreg failed\n", __func__);
+ goto err_mem_free;
+ }
+
+ ret = msm_camera_enable_vreg(&pdev->dev, state->cci_vreg,
+ state->regulator_count, NULL, 0,
+ &state->cci_reg_ptr[0], 1);
+ if (ret < 0) {
+ pr_err("%s:cci enable_vreg failed\n", __func__);
+ goto err_mem_free;
}
+ pr_debug("%s - VREG Initialized...\n", __func__);
- /* Configure and Register V4L2 I2C Sub-device */
+ /* Configure and Register V4L2 Sub-device */
sd = &state->sd;
- v4l2_i2c_subdev_init(sd, client, &adv7481_ops);
+ v4l2_subdev_init(sd, &adv7481_ops);
+ sd->owner = pdev->dev.driver->owner;
+ v4l2_set_subdevdata(sd, state);
+ strlcpy(sd->name, DRIVER_NAME, sizeof(sd->name));
state->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
state->sd.flags |= V4L2_SUBDEV_FL_HAS_EVENTS;
@@ -1627,103 +2387,136 @@ static int adv7481_probe(struct i2c_client *client,
ret = media_entity_init(&state->sd.entity, 1, &state->pad, 0);
if (ret) {
ret = -EIO;
- pr_err("Media entity init failed\n");
+ pr_err("%s(%d): Media entity init failed\n",
+ __func__, __LINE__);
goto err_media_entity;
}
/* Initialize HW Config */
- ret = adv7481_hw_init(pdata, state);
+ ret = adv7481_hw_init(state);
if (ret) {
ret = -EIO;
- pr_err("HW Initialisation Failed\n");
+ pr_err("%s: HW Initialisation Failed\n", __func__);
goto err_media_entity;
}
/* Register V4l2 Control Functions */
- hdl = &state->ctrl_hdl;
- v4l2_ctrl_handler_init(hdl, 4);
- adv7481_init_v4l2_controls(state);
+ ret = adv7481_init_v4l2_controls(state);
+ if (ret) {
+ pr_err("%s: V4L2 Controls Initialisation Failed %d\n",
+ __func__, ret);
+ }
- /* Initials ADV7481 State Settings */
+ /* Initial ADV7481 State Settings */
state->tx_auto_params = ADV7481_AUTO_PARAMS;
- state->tx_lanes = ADV7481_MIPI_2LANE;
/* Initialize SW Init Settings and I2C sub maps 7481 */
- ret = adv7481_dev_init(state, client);
+ ret = adv7481_dev_init(state);
if (ret) {
ret = -EIO;
- pr_err("SW Initialisation Failed\n");
+ pr_err("%s(%d): SW Initialisation Failed\n",
+ __func__, __LINE__);
goto err_media_entity;
}
- /* Set hdmi settings */
- ret = adv7481_set_hdmi_mode(state);
-
/* BA registration */
- ret |= msm_ba_register_subdev_node(sd);
+ ret = msm_ba_register_subdev_node(sd);
if (ret) {
ret = -EIO;
- pr_err("BA INIT FAILED\n");
+ pr_err("%s: BA init failed\n", __func__);
goto err_media_entity;
}
+ enable_irq(state->irq);
pr_debug("Probe successful!\n");
return ret;
err_media_entity:
media_entity_cleanup(&sd->entity);
-err_mem:
- kfree(state);
+
+err_mem_free:
+ adv7481_release_cci_clks(state);
+ devm_kfree(&pdev->dev, state);
+
err:
- if (!ret)
- ret = 1;
return ret;
}
-static int adv7481_remove(struct i2c_client *client)
+static int adv7481_remove(struct platform_device *pdev)
{
- struct v4l2_subdev *sd = i2c_get_clientdata(client);
- struct adv7481_state *state = to_state(sd);
+ struct adv7481_state *state = platform_get_drvdata(pdev);
- msm_ba_unregister_subdev_node(sd);
- v4l2_device_unregister_subdev(sd);
- media_entity_cleanup(&sd->entity);
+ msm_ba_unregister_subdev_node(&state->sd);
+ v4l2_device_unregister_subdev(&state->sd);
+ media_entity_cleanup(&state->sd.entity);
v4l2_ctrl_handler_free(&state->ctrl_hdl);
+ adv7481_reset_irq(state);
if (state->irq > 0)
free_irq(state->irq, state);
- i2c_unregister_device(state->i2c_csi_txa);
- i2c_unregister_device(state->i2c_csi_txb);
- i2c_unregister_device(state->i2c_hdmi);
- i2c_unregister_device(state->i2c_edid);
- i2c_unregister_device(state->i2c_cp);
- i2c_unregister_device(state->i2c_sdp);
- i2c_unregister_device(state->i2c_rep);
+ cancel_delayed_work(&state->irq_delayed_work);
mutex_destroy(&state->mutex);
- kfree(state);
+ devm_kfree(&pdev->dev, state);
return 0;
}
-static const struct i2c_device_id adv7481_id[] = {
- { DRIVER_NAME, 0 },
- {},
-};
-MODULE_DEVICE_TABLE(i2c, adv7481_id);
+#ifdef CONFIG_PM_SLEEP
+static int adv7481_suspend(struct device *dev)
+{
+ struct adv7481_state *state;
+ int ret;
+
+ state = (struct adv7481_state *)dev_get_drvdata(dev);
+
+ /* release CCI clocks */
+ ret = adv7481_release_cci_clks(state);
+ if (ret)
+ pr_err("%s: adv7481 release cci clocks failed\n", __func__);
+ else
+ pr_debug("released cci clocks in suspend");
+
+ return 0;
+}
+
+static int adv7481_resume(struct device *dev)
+{
+ struct adv7481_state *state;
+ int ret;
+
+ state = (struct adv7481_state *)dev_get_drvdata(dev);
+
+ /* Request CCI clocks */
+ ret = adv7481_request_cci_clks(state);
+ if (ret)
+ pr_err("%s: adv7481 request cci clocks failed\n", __func__);
+ else
+ pr_debug("requested cci clocks in resume");
+
+ return 0;
+}
+
+static SIMPLE_DEV_PM_OPS(adv7481_pm_ops, adv7481_suspend, adv7481_resume);
+#define ADV7481_PM_OPS (&adv7481_pm_ops)
+#else
+#define ADV7481_PM_OPS NULL
+#endif
-static struct i2c_driver adv7481_driver = {
+static struct platform_driver adv7481_driver = {
.driver = {
.owner = THIS_MODULE,
.name = KBUILD_MODNAME,
+ .of_match_table = adv7481_id,
+ .pm = ADV7481_PM_OPS,
},
.probe = adv7481_probe,
.remove = adv7481_remove,
- .id_table = adv7481_id,
};
-module_i2c_driver(adv7481_driver);
+module_driver(adv7481_driver, platform_driver_register,
+ platform_driver_unregister);
MODULE_DESCRIPTION("ADI ADV7481 HDMI/MHL/SD video receiver");
diff --git a/drivers/media/i2c/adv7481_reg.h b/drivers/media/i2c/adv7481_reg.h
index a4e14fa18e0a..60b1301abbe6 100644
--- a/drivers/media/i2c/adv7481_reg.h
+++ b/drivers/media/i2c/adv7481_reg.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2014-2015, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2014-2016, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -19,329 +19,451 @@
#define ADV_REG_GETFIELD(val, field) \
(((val) & (field##_BMSK)) >> (field##_SHFT))
+#define ADV_REG_RSTFIELD(val, field) \
+ ((val) & ~((field##_BMSK) << (field##_SHFT)))
+
/* IO Map Registers */
-#define IO_REG_MAIN_RST_ADDR 0xFF
-#define IO_REG_MAIN_RST_VALUE 0xFF
-
-#define IO_REG_PWR_DOWN_CTRL_ADDR 0x00
-#define IO_CTRL_RX_EN_BMSK 0x0040
-#define IO_CTRL_RX_EN_SHFT 6
-#define IO_CTRL_RX_PWDN_BMSK 0x0020
-#define IO_CTRL_RX_PWDN_SHFT 5
-#define IO_CTRL_XTAL_PWDN_BMSK 0x0004
-#define IO_CTRL_XTAL_PWDN_SHFT 2
-#define IO_CTRL_CORE_PWDN_BMSK 0x0002
-#define IO_CTRL_CORE_PWDN_SHFT 1
-#define IO_CTRL_MASTER_PWDN_BMSK 0x0001
-#define IO_CTRL_MASTER_PWDN_SHFT 0
-
-#define IO_REG_PWR_DN2_XTAL_HIGH_ADDR 0x01
-#define IO_CTRL_CEC_WAKE_UP_PWRDN2B_BMSK 0x0080
-#define IO_CTRL_CEC_WAKE_UP_PWRDN2B_SHFT 7
-#define IO_CTRL_CEC_WAKE_UP_PWRDNB_BMSK 0x0040
-#define IO_CTRL_CEC_WAKE_UP_PWRDNB_SHFT 6
-#define IO_PROG_XTAL_FREQ_HIGH_BMSK 0x003F
-#define IO_PROG_XTAL_FREQ_HIGH_SHFT 0
-
-#define IO_REG_XTAL_FREQ_LOW_ADDR 0x02
-#define IO_PROG_XTAL_FREQ_LOW_BMSK 0x00FF
-#define IO_PROG_XTAL_FREQ_LOW_SHFT 0
-
-#define IO_REG_CP_VID_STD_ADDR 0x05
-
-#define IO_REG_CSI_PIX_EN_SEL_ADDR 0x10
-#define IO_CTRL_CSI4_EN_BMSK 0x0080
-#define IO_CTRL_CSI4_EN_SHFT 7
-#define IO_CTRL_CSI1_EN_BMSK 0x0040
-#define IO_CTRL_CSI1_EN_SHFT 6
-#define IO_CTRL_PIX_OUT_EN_BMSK 0x0020
-#define IO_CTRL_PIX_OUT_EN_SHFT 5
-#define IO_CTRL_SD_THRU_PIX_OUT_BMSK 0x0010
-#define IO_CTRL_SD_THRU_PIX_OUT_SHFT 4
-#define IO_CTRL_CSI4_IN_SEL_BMSK 0x000C
-#define IO_CTRL_CSI4_IN_SEL_SHFT 2
-
-#define IO_PAD_CTRLS_ADDR 0x0E
-
-#define IO_REG_I2C_CFG_ADDR 0xF2
-#define IO_REG_I2C_AUTOINC_EN_REG_VALUE 0x01
-
-#define IO_CTRL_MASTER_PWDN_REG_VALUE 0x01
-
-#define IO_HDMI_LVL_RAW_STATUS_3_ADDR 0x71
-#define IO_TMDSPLL_LCK_A_RAW_BMSK 0x0080
-#define IO_TMDSPLL_LCK_A_RAW_SHFT 7
-#define IO_CABLE_DET_A_RAW_BMSK 0x0040
-#define IO_CABLE_DET_A_RAW_SHFT 6
-#define IO_V_LOCKED_RAW_BMSK 0x0002
-#define IO_V_LOCKED_RAW_SHFT 1
-#define IO_DE_REGEN_LCK_RAW_BMSK 0x0001
-#define IO_DE_REGEN_LCK_RAW_SHFT 0
+#define IO_REG_MAIN_RST_ADDR 0xFF
+#define IO_REG_MAIN_RST_VALUE 0xFF
+
+#define IO_REG_PWR_DOWN_CTRL_ADDR 0x00
+#define IO_CTRL_RX_EN_BMSK 0x0040
+#define IO_CTRL_RX_EN_SHFT 6
+#define IO_CTRL_RX_PWDN_BMSK 0x0020
+#define IO_CTRL_RX_PWDN_SHFT 5
+#define IO_CTRL_XTAL_PWDN_BMSK 0x0004
+#define IO_CTRL_XTAL_PWDN_SHFT 2
+#define IO_CTRL_CORE_PWDN_BMSK 0x0002
+#define IO_CTRL_CORE_PWDN_SHFT 1
+#define IO_CTRL_MASTER_PWDN_BMSK 0x0001
+#define IO_CTRL_MASTER_PWDN_SHFT 0
+
+#define IO_REG_PWR_DN2_XTAL_HIGH_ADDR 0x01
+#define IO_CTRL_CEC_WAKE_UP_PWRDN2B_BMSK 0x0080
+#define IO_CTRL_CEC_WAKE_UP_PWRDN2B_SHFT 7
+#define IO_CTRL_CEC_WAKE_UP_PWRDNB_BMSK 0x0040
+#define IO_CTRL_CEC_WAKE_UP_PWRDNB_SHFT 6
+#define IO_PROG_XTAL_FREQ_HIGH_BMSK 0x003F
+#define IO_PROG_XTAL_FREQ_HIGH_SHFT 0
+
+#define IO_REG_XTAL_FREQ_LOW_ADDR 0x02
+#define IO_PROG_XTAL_FREQ_LOW_BMSK 0x00FF
+#define IO_PROG_XTAL_FREQ_LOW_SHFT 0
+
+#define IO_REG_CP_VID_STD_ADDR 0x05
+
+#define IO_REG_CSI_PIX_EN_SEL_ADDR 0x10
+#define IO_CTRL_CSI4_EN_BMSK 0x0080
+#define IO_CTRL_CSI4_EN_SHFT 7
+#define IO_CTRL_CSI1_EN_BMSK 0x0040
+#define IO_CTRL_CSI1_EN_SHFT 6
+#define IO_CTRL_PIX_OUT_EN_BMSK 0x0020
+#define IO_CTRL_PIX_OUT_EN_SHFT 5
+#define IO_CTRL_SD_THRU_PIX_OUT_BMSK 0x0010
+#define IO_CTRL_SD_THRU_PIX_OUT_SHFT 4
+#define IO_CTRL_CSI4_IN_SEL_BMSK 0x000C
+#define IO_CTRL_CSI4_IN_SEL_SHFT 2
+
+#define IO_PAD_CTRLS_ADDR 0x0E
+#define IO_PAD_FILTER_CTRLS_ADDR 0x0F
+
+#define IO_REG_I2C_CFG_ADDR 0xF2
+#define IO_REG_I2C_AUTOINC_EN_REG_VALUE 0x01
+
+#define IO_CTRL_MASTER_PWDN_REG_VALUE 0x01
/* Interrupts */
-#define IO_HDMI_LVL_INT_STATUS_3_ADDR 0x72
-#define IO_CABLE_DET_A_ST_BMSK 0x0040
-#define IO_CABLE_DET_A_ST_SHFT 6
-
-#define IO_HDMI_LVL_INT_CLEAR_3_ADDR 0x73
-#define IO_CABLE_DET_A_CLR_BMSK 0x0040
-#define IO_CABLE_DET_A_CLR_SHFT 6
-
-#define IO_HDMI_LVL_INT2_MASKB_3_ADDR 0x74
-#define IO_CABLE_DET_A_MB2_BMSK 0x0040
-#define IO_CABLE_DET_A_MB2_SHFT 6
-
-#define IO_HDMI_LVL_INT_MASKB_3_ADDR 0x75
-#define IO_CABLE_DET_A_MB1_BMSK 0x0040
-#define IO_CABLE_DET_A_MB1_SHFT 6
-
-#define IO_REG_PAD_CTRL_1_ADDR 0x1D
-#define IO_PDN_INT1_BMSK 0x0080
-#define IO_PDN_INT1_SHFT 7
-#define IO_PDN_INT2_BMSK 0x0040
-#define IO_PDN_INT2_SHFT 6
-#define IO_PDN_INT3_BMSK 0x0020
-#define IO_PDN_INT3_SHFT 5
-#define IO_INV_LLC_BMSK 0x0010
-#define IO_INV_LLC_SHFT 4
-#define IO_DRV_LLC_PAD_BMSK 0x000C
-#define IO_DRV_LLC_PAD_SHFT 2
-
-#define IO_REG_INT_RAW_STATUS_ADDR 0x3F
-
-#define IO_REG_INT1_CONF_ADDR 0x40
-#define IO_INTRQ_DUR_SEL_BMSK 0x00C0
-#define IO_INTRQ_DUR_SEL_SHFT 6
-#define IO_INTRQ_OP_SEL_BMSK 0x0003
-#define IO_INTRQ_OP_SEL_SHFT 0
-
-#define IO_REG_INT2_CONF_ADDR 0x41
-#define IO_INTRQ2_DUR_SEL_BMSK 0x00C0
-#define IO_INTRQ2_DUR_SEL_SHFT 6
-#define IO_CP_LOCK_UNLOCK_EDGE_SEL_BMSK 0x0020
-#define IO_CP_LOCK_UNLOCK_EDGE_SEL_SHFT 5
-#define IO_EN_UMASK_RAW_INTRQ2_BMSK 0x0008
-#define IO_EN_UMASK_RAW_INTRQ2_SHFT 3
-#define IO_INT2_EN_BMSK 0x0004
-#define IO_INT2_EN_SHFT 2
-#define IO_INTRQ2_OP_SEL_BMSK 0x0003
-#define IO_INTRQ2_OP_SEL_SHFT 0
-
-#define IO_REG_DATAPATH_RAW_STATUS_ADDR 0x43
-#define IO_REG_DATAPATH_INT_STATUS_ADDR 0x44
-#define IO_REG_DATAPATH_INT_CLEAR_ADDR 0x45
-
-#define IO_REG_DATAPATH_INT_MASKB_ADDR 0x47
-#define IO_CP_LOCK_CP_MB1_BMSK 0x0080
-#define IO_CP_LOCK_CP_MB1_SHFT 7
-#define IO_CP_UNLOCK_CP_MB1_BMSK 0x0040
-#define IO_CP_UNLOCK_CP_MB1_SHFT 6
-#define IO_VMUTE_REQUEST_HDMI_MB1_BMSK 0x0020
-#define IO_VMUTE_REQUEST_HDMI_MB1_SHFT 5
-#define IO_MPU_STIM_INTRQ_MB1_BMSK 0x0002
-#define IO_MPU_STIM_INTRQ_MB1_SHFT 1
-#define IO_INT_SD_MB1_BMSK 0x0001
-#define IO_INT_SD_MB1_SHFT 0
+#define IO_HDMI_LVL_INT_CLEAR_1_ADDR 0x69
+
+#define IO_HDMI_LVL_INT_MASKB_1_ADDR 0x6B
+#define IO_AVI_INFO_MB1_BMSK 0x0001
+#define IO_AVI_INFO_MB1_SHFT 0
+
+#define IO_HDMI_LVL_INT_CLEAR_2_ADDR 0x6E
+
+#define IO_HDMI_LVL_RAW_STATUS_3_ADDR 0x71
+#define IO_TMDSPLL_LCK_A_RAW_BMSK 0x0080
+#define IO_TMDSPLL_LCK_A_RAW_SHFT 7
+#define IO_CABLE_DET_A_RAW_BMSK 0x0040
+#define IO_CABLE_DET_A_RAW_SHFT 6
+#define IO_V_LOCKED_RAW_BMSK 0x0002
+#define IO_V_LOCKED_RAW_SHFT 1
+#define IO_DE_REGEN_LCK_RAW_BMSK 0x0001
+#define IO_DE_REGEN_LCK_RAW_SHFT 0
+
+#define IO_HDMI_LVL_INT_STATUS_3_ADDR 0x72
+#define IO_CABLE_DET_A_ST_BMSK 0x0040
+#define IO_CABLE_DET_A_ST_SHFT 6
+#define IO_V_LOCKED_ST_BMSK 0x0002
+#define IO_V_LOCKED_ST_SHFT 1
+#define IO_DE_REGEN_LCK_ST_BMSK 0x0001
+#define IO_DE_REGEN_LCK_ST_SHFT 0
+
+#define IO_HDMI_LVL_INT_CLEAR_3_ADDR 0x73
+#define IO_CABLE_DET_A_CLR_BMSK 0x0040
+#define IO_CABLE_DET_A_CLR_SHFT 6
+
+#define IO_HDMI_LVL_INT2_MASKB_3_ADDR 0x74
+#define IO_CABLE_DET_A_MB2_BMSK 0x0040
+#define IO_CABLE_DET_A_MB2_SHFT 6
+
+#define IO_HDMI_LVL_INT_MASKB_3_ADDR 0x75
+#define IO_CABLE_DET_A_MB1_BMSK 0x0040
+#define IO_CABLE_DET_A_MB1_SHFT 6
+#define IO_V_LOCKED_MB1_BMSK 0x0002
+#define IO_V_LOCKED_MB1_SHFT 1
+#define IO_DE_REGEN_LCK_MB1_BMSK 0x0001
+#define IO_DE_REGEN_LCK_MB1_SHFT 0
+
+#define IO_HDMI_EDG_RAW_STATUS_1_ADDR 0x80
+#define IO_NEW_AVI_INFO_RAW_BMSK 0x0001
+#define IO_NEW_AVI_INFO_RAW_SHFT 0
+
+#define IO_HDMI_EDG_INT_STATUS_1_ADDR 0x81
+#define IO_NEW_AVI_INFO_ST_BMSK 0x0001
+#define IO_NEW_AVI_INFO_ST_SHFT 0
+
+#define IO_HDMI_EDG_INT_CLEAR_1_ADDR 0x82
+#define IO_NEW_AVI_INFO_CLR_BMSK 0x0001
+#define IO_NEW_AVI_INFO_CLR_SHFT 0
+
+#define IO_HDMI_EDG_INT2_MASKB_1_ADDR 0x83
+#define IO_NEW_AVI_INFO_MB2_BMSK 0x0001
+#define IO_NEW_AVI_INFO_MB2_SHFT 0
+
+#define IO_HDMI_EDG_INT_MASKB_1_ADDR 0x84
+#define IO_NEW_AVI_INFO_MB1_BMSK 0x0001
+#define IO_NEW_AVI_INFO_MB1_SHFT 0
+
+#define IO_HDMI_EDG_INT_CLEAR_2_ADDR 0x87
+#define IO_HDMI_EDG_INT_CLEAR_3_ADDR 0x8C
+
+#define IO_REG_PAD_CTRL_1_ADDR 0x1D
+#define IO_PDN_INT1_BMSK 0x0080
+#define IO_PDN_INT1_SHFT 7
+#define IO_PDN_INT2_BMSK 0x0040
+#define IO_PDN_INT2_SHFT 6
+#define IO_PDN_INT3_BMSK 0x0020
+#define IO_PDN_INT3_SHFT 5
+#define IO_INV_LLC_BMSK 0x0010
+#define IO_INV_LLC_SHFT 4
+#define IO_DRV_LLC_PAD_BMSK 0x000C
+#define IO_DRV_LLC_PAD_SHFT 2
+
+#define IO_REG_INT_RAW_STATUS_ADDR 0x3F
+#define IO_INT_CEC_ST_BMSK 0x0010
+#define IO_INT_CEC_ST_SHFT 4
+#define IO_INT_HDMI_ST_BMSK 0x0008
+#define IO_INT_HDMI_ST_SHFT 3
+#define IO_INTRQ3_RAW_BMSK 0x0004
+#define IO_INTRQ3_RAW_SHFT 2
+#define IO_INTRQ2_RAW_BMSK 0x0002
+#define IO_INTRQ2_RAW_SHFT 1
+#define IO_INTRQ1_RAW_BMSK 0x0001
+#define IO_INTRQ1_RAW_SHFT 0
+
+#define IO_REG_INT1_CONF_ADDR 0x40
+#define IO_INTRQ_DUR_SEL_BMSK 0x00C0
+#define IO_INTRQ_DUR_SEL_SHFT 6
+#define IO_INTRQ_OP_SEL_BMSK 0x0003
+#define IO_INTRQ_OP_SEL_SHFT 0
+
+#define IO_REG_INT2_CONF_ADDR 0x41
+#define IO_INTRQ2_DUR_SEL_BMSK 0x00C0
+#define IO_INTRQ2_DUR_SEL_SHFT 6
+#define IO_CP_LOCK_UNLOCK_EDGE_SEL_BMSK 0x0020
+#define IO_CP_LOCK_UNLOCK_EDGE_SEL_SHFT 5
+#define IO_EN_UMASK_RAW_INTRQ2_BMSK 0x0008
+#define IO_EN_UMASK_RAW_INTRQ2_SHFT 3
+#define IO_INT2_EN_BMSK 0x0004
+#define IO_INT2_EN_SHFT 2
+#define IO_INTRQ2_OP_SEL_BMSK 0x0003
+#define IO_INTRQ2_OP_SEL_SHFT 0
+
+#define IO_REG_DATAPATH_RAW_STATUS_ADDR 0x43
+#define IO_CP_LOCK_CP_RAW_BMSK 0x0080
+#define IO_CP_LOCK_CP_RAW_SHFT 7
+#define IO_CP_UNLOCK_CP_RAW_BMSK 0x0040
+#define IO_CP_UNLOCK_CP_RAW_SHFT 6
+#define IO_VMUTE_REQUEST_HDMI_RAW_BMSK 0x0020
+#define IO_VMUTE_REQUEST_HDMI_RAW_SHFT 5
+#define IO_MPU_STIM_INTRQ_RAW_BMSK 0x0002
+#define IO_MPU_STIM_INTRQ_RAW_SHFT 1
+#define IO_INT_SD_RAW_BMSK 0x0001
+#define IO_INT_SD_RAW_SHFT 0
+
+#define IO_REG_DATAPATH_INT_STATUS_ADDR 0x44
+#define IO_CP_LOCK_CP_ST_BMSK 0x0080
+#define IO_CP_LOCK_CP_ST_SHFT 7
+#define IO_CP_UNLOCK_CP_ST_BMSK 0x0040
+#define IO_CP_UNLOCK_CP_ST_SHFT 6
+#define IO_VMUTE_REQUEST_HDMI_ST_BMSK 0x0020
+#define IO_VMUTE_REQUEST_HDMI_ST_SHFT 5
+#define IO_MPU_STIM_INTRQ_ST_BMSK 0x0002
+#define IO_MPU_STIM_INTRQ_ST_SHFT 1
+#define IO_INT_SD_ST_BMSK 0x0001
+#define IO_INT_SD_ST_SHFT 0
+
+#define IO_REG_DATAPATH_INT_CLEAR_ADDR 0x45
+
+#define IO_REG_DATAPATH_INT_MASKB_ADDR 0x47
+#define IO_CP_LOCK_CP_MB1_BMSK 0x0080
+#define IO_CP_LOCK_CP_MB1_SHFT 7
+#define IO_CP_UNLOCK_CP_MB1_BMSK 0x0040
+#define IO_CP_UNLOCK_CP_MB1_SHFT 6
+#define IO_VMUTE_REQUEST_HDMI_MB1_BMSK 0x0020
+#define IO_VMUTE_REQUEST_HDMI_MB1_SHFT 5
+#define IO_MPU_STIM_INTRQ_MB1_BMSK 0x0002
+#define IO_MPU_STIM_INTRQ_MB1_SHFT 1
+#define IO_INT_SD_MB1_BMSK 0x0001
+#define IO_INT_SD_MB1_SHFT 0
+
+#define IO_REG_CHIP_REV_ID_1_ADDR 0xDF
+#define IO_REG_CHIP_REV_ID_2_ADDR 0xE0
/* Offsets */
-#define IO_REG_DPLL_ADDR 0xF3
-#define IO_REG_CP_ADDR 0xF4
-#define IO_REG_HDMI_ADDR 0xF5
-#define IO_REG_EDID_ADDR 0xF6
-#define IO_REG_HDMI_REP_ADDR 0xF7
-#define IO_REG_HDMI_INF_ADDR 0xF8
-#define IO_REG_CBUS_ADDR 0xF9
-#define IO_REG_CEC_ADDR 0xFA
-#define IO_REG_SDP_ADDR 0xFB
-#define IO_REG_CSI_TXB_ADDR 0xFC
-#define IO_REG_CSI_TXA_ADDR 0xFD
+#define IO_REG_DPLL_ADDR 0xF3
+#define IO_REG_CP_ADDR 0xF4
+#define IO_REG_HDMI_ADDR 0xF5
+#define IO_REG_EDID_ADDR 0xF6
+#define IO_REG_HDMI_REP_ADDR 0xF7
+#define IO_REG_HDMI_INF_ADDR 0xF8
+#define IO_REG_CBUS_ADDR 0xF9
+#define IO_REG_CEC_ADDR 0xFA
+#define IO_REG_SDP_ADDR 0xFB
+#define IO_REG_CSI_TXB_ADDR 0xFC
+#define IO_REG_CSI_TXA_ADDR 0xFD
/* Sub Address Map Locations */
-#define IO_REG_DPLL_SADDR 0x4C
-#define IO_REG_CP_SADDR 0x44
-#define IO_REG_HDMI_SADDR 0x74
-#define IO_REG_EDID_SADDR 0x78
-#define IO_REG_HDMI_REP_SADDR 0x64
-#define IO_REG_HDMI_INF_SADDR 0x62
-#define IO_REG_CBUS_SADDR 0xF0
-#define IO_REG_CEC_SADDR 0x82
-#define IO_REG_SDP_SADDR 0xF2
-#define IO_REG_CSI_TXB_SADDR 0x90
-#define IO_REG_CSI_TXA_SADDR 0x94
+#define IO_REG_DPLL_SADDR 0x4C
+#define IO_REG_CP_SADDR 0x44
+#define IO_REG_HDMI_SADDR 0x74
+#define IO_REG_EDID_SADDR 0x78
+#define IO_REG_HDMI_REP_SADDR 0x64
+#define IO_REG_HDMI_INF_SADDR 0x62
+#define IO_REG_CBUS_SADDR 0xF0
+#define IO_REG_CEC_SADDR 0x82
+#define IO_REG_SDP_SADDR 0xF2
+#define IO_REG_CSI_TXB_SADDR 0x90
+#define IO_REG_CSI_TXA_SADDR 0x94
/* HDMI Map Registers */
-#define HDMI_REG_HDMI_PARAM4_ADDR 0x04
-#define HDMI_REG_AV_MUTE_BMSK 0x0040
-#define HDMI_REG_AV_MUTE_SHFT 6
-#define HDMI_REG_TMDS_PLL_LOCKED_BMSK 0x0002
-#define HDMI_REG_TMDS_PLL_LOCKED_SHFT 1
-#define HDMI_REG_AUDIO_PLL_LOCKED_BMSK 0x0001
-#define HDMI_REG_AUDIO_PLL_LOCKED_SHFT 0
-
-#define HDMI_REG_HDMI_PARAM5_ADDR 0x05
-#define HDMI_REG_HDMI_MODE_BMSK 0x0080
-#define HDMI_REG_TMDS_FREQ_0_SHFT 7
-#define HDMI_REG_HDMI_CONT_ENCRYPT_BMSK 0x0040
-#define HDMI_REG_HDMI_CONT_ENCRYPT_SHFT 6
-#define HDMI_REG_DVI_HSYNC_POLARITY_BMSK 0x0020
-#define HDMI_REG_DVI_HSYNC_POLARITY_SHFT 5
-#define HDMI_REG_DVI_VSYNC_POLARITY_BMSK 0x0010
-#define HDMI_REG_DVI_VSYNC_POLARITY_SHFT 4
-#define HDMI_REG_PIXEL_REPETITION_BMSK 0x000F
-#define HDMI_REG_PIXEL_REPETITION_SHFT 0
-
-#define HDMI_REG_LINE_WIDTH_1_ADDR 0x07
-#define HDMI_VERT_FILTER_LOCKED_BMSK 0x0080
-#define HDMI_VERT_FILTER_LOCKED_SHFT 7
-#define HDMI_AUDIO_CHANNEL_MODE_BMSK 0x0040
-#define HDMI_AUDIO_CHANNEL_MODE_SHFT 6
-#define HDMI_DE_REGEN_FILTER_LCK_BMSK 0x0020
-#define HDMI_DE_REGEN_FILTER_LCK_SHFT 5
-#define HDMI_REG_LINE_WIDTH_1_BMSK 0x001F
-#define HDMI_REG_LINE_WIDTH_1_SHFT 0
-
-#define HDMI_REG_LINE_WIDTH_2_ADDR 0x08
-#define HDMI_REG_LINE_WIDTH_2_BMSK 0x00FF
-#define HDMI_REG_LINE_WIDTH_2_SHFT 0
-
-#define HDMI_REG_FIELD0_HEIGHT_1_ADDR 0x09
-#define HDMI_REG_FIELD0_HEIGHT_1_BMSK 0x001F
-#define HDMI_REG_FIELD0_HEIGHT_1_SHFT 0
-#define HDMI_REG_FIELD0_HEIGHT_2_ADDR 0x0A
-#define HDMI_REG_FIELD0_HEIGHT_2_BMSK 0x00FF
-#define HDMI_REG_FIELD0_HEIGHT_2_SHFT 0
-
-#define HDMI_REG_FIELD1_HEIGHT1_ADDR 0x0B
-#define HDMI_REG_DEEP_COLOR_MODE_BMSK 0x00C0
-#define HDMI_REG_DEEP_COLOR_MODE_SHFT 6
-#define HDMI_REG_HDMI_INTERLACED_BMSK 0x0020
-#define HDMI_REG_HDMI_INTERLACED_SHFT 5
-
-#define HDMI_REG_TOTAL_LINE_WIDTH_1_ADDR 0x1E
-#define HDMI_REG_TOTAL_LINE_WIDTH_1_BMSK 0x003F
-#define HDMI_REG_TOTAL_LINE_WIDTH_1_SHFT 0
-
-#define HDMI_REG_TOTAL_LINE_WIDTH_2_ADDR 0x1F
-#define HDMI_REG_TOTAL_LINE_WIDTH_2_BMSK 0x00FF
-#define HDMI_REG_TOTAL_LINE_WIDTH_2_SHFT 0
-
-#define HDMI_REG_FIELD0_TOTAL_HEIGHT_1_ADDR 0x26
-#define HDMI_REG_FIELD0_TOT_HEIGHT_1_BMSK 0x003F
-#define HDMI_REG_FIELD0_TOT_HEIGHT_1_SHFT 0
-
-#define HDMI_REG_FIELD0_TOTAL_HEIGHT_2_ADDR 0x27
-#define HDMI_REG_FIELD0_TOT_HEIGHT_2_BMSK 0x00FF
-#define HDMI_REG_FIELD0_TOT_HEIGHT_2_SHFT 0
-
-#define HDMI_REG_DIS_CABLE_DET_RST_ADDR 0x48
-#define HDMI_DIS_CABLE_DET_RST_BMSK 0x0040
-#define HDMI_DIS_CABLE_DET_RST_SHFT 6
-
-#define HDMI_REG_TMDS_FREQ_ADDR 0x51
-#define HDMI_REG_TMDS_FREQ_BMSK 0x00FF
-#define HDMI_REG_TMDS_FREQ_SHFT 0
-
-#define HDMI_REG_TMDS_FREQ_FRAC_ADDR 0x52
-#define HDMI_REG_TMDS_FREQ_0_BMSK 0x0080
-#define HDMI_REG_TMDS_FREQ_0_SHFT 7
-#define HDMI_REG_TMDS_FREQ_FRAC_BMSK 0x007F
-#define HDMI_REG_TMDS_FREQ_FRAC_SHFT 0
-
-#define HDMI_REG_RST_CTRLS_ADDR 0x5A
-#define HDMI_HDCP_REPT_EDID_RST_BMSK 0x0008
-#define HDMI_HDCP_REPT_EDID_RST_SHFT 3
-
-#define HDMI_REG_MUX_SPDIF_TO_I2S_ADDR 0x6E
-#define HDMI_MUX_SPDIF_TO_I2S_EN_BMSK 0x0008
-#define HDMI_MUX_SPDIF_TO_I2S_EN_SHFT 3
+#define HDMI_REG_HDMI_PARAM4_ADDR 0x04
+#define HDMI_REG_AV_MUTE_BMSK 0x0040
+#define HDMI_REG_AV_MUTE_SHFT 6
+#define HDMI_REG_TMDS_PLL_LOCKED_BMSK 0x0002
+#define HDMI_REG_TMDS_PLL_LOCKED_SHFT 1
+#define HDMI_REG_AUDIO_PLL_LOCKED_BMSK 0x0001
+#define HDMI_REG_AUDIO_PLL_LOCKED_SHFT 0
+
+#define HDMI_REG_HDMI_PARAM5_ADDR 0x05
+#define HDMI_REG_HDMI_MODE_BMSK 0x0080
+#define HDMI_REG_TMDS_FREQ_0_SHFT 7
+#define HDMI_REG_HDMI_CONT_ENCRYPT_BMSK 0x0040
+#define HDMI_REG_HDMI_CONT_ENCRYPT_SHFT 6
+#define HDMI_REG_DVI_HSYNC_POLARITY_BMSK 0x0020
+#define HDMI_REG_DVI_HSYNC_POLARITY_SHFT 5
+#define HDMI_REG_DVI_VSYNC_POLARITY_BMSK 0x0010
+#define HDMI_REG_DVI_VSYNC_POLARITY_SHFT 4
+#define HDMI_REG_PIXEL_REPETITION_BMSK 0x000F
+#define HDMI_REG_PIXEL_REPETITION_SHFT 0
+
+#define HDMI_REG_LINE_WIDTH_1_ADDR 0x07
+#define HDMI_VERT_FILTER_LOCKED_BMSK 0x0080
+#define HDMI_VERT_FILTER_LOCKED_SHFT 7
+#define HDMI_AUDIO_CHANNEL_MODE_BMSK 0x0040
+#define HDMI_AUDIO_CHANNEL_MODE_SHFT 6
+#define HDMI_DE_REGEN_FILTER_LCK_BMSK 0x0020
+#define HDMI_DE_REGEN_FILTER_LCK_SHFT 5
+#define HDMI_REG_LINE_WIDTH_1_BMSK 0x001F
+#define HDMI_REG_LINE_WIDTH_1_SHFT 0
+
+#define HDMI_REG_LINE_WIDTH_2_ADDR 0x08
+#define HDMI_REG_LINE_WIDTH_2_BMSK 0x00FF
+#define HDMI_REG_LINE_WIDTH_2_SHFT 0
+
+#define HDMI_REG_FIELD0_HEIGHT_1_ADDR 0x09
+#define HDMI_REG_FIELD0_HEIGHT_1_BMSK 0x001F
+#define HDMI_REG_FIELD0_HEIGHT_1_SHFT 0
+#define HDMI_REG_FIELD0_HEIGHT_2_ADDR 0x0A
+#define HDMI_REG_FIELD0_HEIGHT_2_BMSK 0x00FF
+#define HDMI_REG_FIELD0_HEIGHT_2_SHFT 0
+
+#define HDMI_REG_FIELD1_HEIGHT1_ADDR 0x0B
+#define HDMI_REG_DEEP_COLOR_MODE_BMSK 0x00C0
+#define HDMI_REG_DEEP_COLOR_MODE_SHFT 6
+#define HDMI_REG_HDMI_INTERLACED_BMSK 0x0020
+#define HDMI_REG_HDMI_INTERLACED_SHFT 5
+
+#define HDMI_REG_TOTAL_LINE_WIDTH_1_ADDR 0x1E
+#define HDMI_REG_TOTAL_LINE_WIDTH_1_BMSK 0x003F
+#define HDMI_REG_TOTAL_LINE_WIDTH_1_SHFT 0
+
+#define HDMI_REG_TOTAL_LINE_WIDTH_2_ADDR 0x1F
+#define HDMI_REG_TOTAL_LINE_WIDTH_2_BMSK 0x00FF
+#define HDMI_REG_TOTAL_LINE_WIDTH_2_SHFT 0
+
+#define HDMI_REG_FIELD0_TOTAL_HEIGHT_1_ADDR 0x26
+#define HDMI_REG_FIELD0_TOT_HEIGHT_1_BMSK 0x003F
+#define HDMI_REG_FIELD0_TOT_HEIGHT_1_SHFT 0
+
+#define HDMI_REG_FIELD0_TOTAL_HEIGHT_2_ADDR 0x27
+#define HDMI_REG_FIELD0_TOT_HEIGHT_2_BMSK 0x00FF
+#define HDMI_REG_FIELD0_TOT_HEIGHT_2_SHFT 0
+
+#define HDMI_REG_DIS_CABLE_DET_RST_ADDR 0x48
+#define HDMI_DIS_CABLE_DET_RST_BMSK 0x0040
+#define HDMI_DIS_CABLE_DET_RST_SHFT 6
+
+#define HDMI_REG_TMDS_FREQ_ADDR 0x51
+#define HDMI_REG_TMDS_FREQ_BMSK 0x00FF
+#define HDMI_REG_TMDS_FREQ_SHFT 0
+
+#define HDMI_REG_TMDS_FREQ_FRAC_ADDR 0x52
+#define HDMI_REG_TMDS_FREQ_0_BMSK 0x0080
+#define HDMI_REG_TMDS_FREQ_0_SHFT 7
+#define HDMI_REG_TMDS_FREQ_FRAC_BMSK 0x007F
+#define HDMI_REG_TMDS_FREQ_FRAC_SHFT 0
+
+#define HDMI_REG_RST_CTRLS_ADDR 0x5A
+#define HDMI_HDCP_REPT_EDID_RST_BMSK 0x0008
+#define HDMI_HDCP_REPT_EDID_RST_SHFT 3
+
+#define HDMI_REG_MUX_SPDIF_TO_I2S_ADDR 0x6E
+#define HDMI_MUX_SPDIF_TO_I2S_EN_BMSK 0x0008
+#define HDMI_MUX_SPDIF_TO_I2S_EN_SHFT 3
/* HDMI Repeater Map Registers */
-#define HDMI_REG_HDCP_EDID_CTRLS_ADDR 0x74
-#define HDMI_MAN_EDID_A_ENABLE_BMSK 0x0001
-#define HDMI_MAN_EDID_A_ENABLE_SHFT 0
+#define HDMI_REG_HDCP_EDID_CTRLS_ADDR 0x74
+#define HDMI_MAN_EDID_A_ENABLE_BMSK 0x0001
+#define HDMI_MAN_EDID_A_ENABLE_SHFT 0
+
+#define HDMI_REG_RO_EDID_DEBUG_2_ADDR 0x76
+#define HDMI_EDID_A_ENABLE_BMSK 0x0001
+#define HDMI_EDID_A_ENABLE_SHFT 0
+
+/* CEC Map Registers */
+#define CEC_REG_LOG_ADDR_MASK_ADDR 0x27
+#define CEC_REG_LOG_ADDR_MASK2_BMSK 0x0040
+#define CEC_REG_LOG_ADDR_MASK2_SHFT 6
+#define CEC_REG_LOG_ADDR_MASK1_BMSK 0x0020
+#define CEC_REG_LOG_ADDR_MASK1_SHFT 5
+#define CEC_REG_LOG_ADDR_MASK0_BMSK 0x0010
+#define CEC_REG_LOG_ADDR_MASK0_SHFT 4
+#define CEC_REG_ERROR_REPORT_MODE_BMSK 0x0008
+#define CEC_REG_ERROR_REPORT_MODE_SHFT 3
+#define CEC_REG_ERROR_REPORT_DET_BMSK 0x0004
+#define CEC_REG_ERROR_REPORT_DET_SHFT 2
+#define CEC_REG_FORCE_NACK_BMSK 0x0002
+#define CEC_REG_FORCE_NACK_SHFT 1
+#define CEC_REG_FORCE_IGNORE_BMSK 0x0001
+#define CEC_REG_FORCE_IGNORE_SHFT 0
+
+#define CEC_REG_LOGICAL_ADDRESS0_1_ADDR 0x28
+#define CEC_REG_LOGICAL_ADDRESS1_BMSK 0x00F0
+#define CEC_REG_LOGICAL_ADDRESS1_SHFT 4
+#define CEC_REG_LOGICAL_ADDRESS0_BMSK 0x000F
+#define CEC_REG_LOGICAL_ADDRESS0_SHFT 0
+
+#define CEC_REG_LOGICAL_ADDRESS2_ADDR 0x29
+#define CEC_REG_LOGICAL_ADDRESS2_BMSK 0x000F
+#define CEC_REG_LOGICAL_ADDRESS2_SHFT 0
+
+#define CEC_REG_CEC_POWER_UP_ADDR 0x2A
+#define CEC_REG_CEC_POWER_UP_BMSK 0x0001
+#define CEC_REG_CEC_POWER_UP_SHFT 0
+
+#define CEC_REG_CLR_RX_RDY_SFT_RST_ADDR 0x2C
+#define CEC_REG_CEC_SOFT_RESET_BMSK 0x0001
+#define CEC_REG_CEC_SOFT_RESET_SHFT 0
-#define HDMI_REG_RO_EDID_DEBUG_2_ADDR 0x76
-#define HDMI_EDID_A_ENABLE_BMSK 0x0001
-#define HDMI_EDID_A_ENABLE_SHFT 0
/* CP Map Registers */
-#define CP_REG_CONTRAST 0x3A
-#define CP_REG_SATURATION 0x3B
-#define CP_REG_BRIGHTNESS 0x3C
-#define CP_REG_HUE 0x3D
-#define CP_REG_VID_ADJ 0x3E
-#define CP_CTR_VID_ADJ_EN 0x80
-#define CP_REG_STDI_CH_ADDR 0xB1
-#define CP_STDI_DVALID_CH1_BMSK 0x0080
-#define CP_STDI_DVALID_CH1_SHFT 7
+#define CP_REG_CONTRAST 0x3A
+#define CP_REG_SATURATION 0x3B
+#define CP_REG_BRIGHTNESS 0x3C
+#define CP_REG_HUE 0x3D
+#define CP_REG_VID_ADJ 0x3E
+#define CP_CTR_VID_ADJ_EN 0x80
+#define CP_REG_STDI_CH_ADDR 0xB1
+#define CP_STDI_DVALID_CH1_BMSK 0x0080
+#define CP_STDI_DVALID_CH1_SHFT 7
+
+/* SDP Main Map */
+#define SDP_RW_MAP_REG 0x0e
+
+/* SDP MAP 1 Registers */
+#define SDP_RW_LOCK_UNLOCK_CLR_ADDR 0x43
+#define SDP_RW_LOCK_UNLOCK_MASK_ADDR 0x44
/* SDP R/O Main Map Registers */
-#define SDP_RO_MAIN_STATUS1_ADDR 0x10
-#define SDP_RO_MAIN_COL_KILL_BMSK 0x0080
-#define SDP_RO_MAIN_COL_KILL_SHFT 7
-#define SDP_RO_MAIN_AD_RESULT_BMSK 0x0070
-#define SDP_RO_MAIN_AD_RESULT_SHFT 4
-#define SDP_RO_MAIN_FOLLOW_PW_BMSK 0x0008
-#define SDP_RO_MAIN_FOLLOW_PW_SHFT 3
-#define SDP_RO_MAIN_FSC_LOCK_BMSK 0x0004
-#define SDP_RO_MAIN_FSC_LOCK_SHFT 2
-#define SDP_RO_MAIN_LOST_LOCK_BMSK 0x0002
-#define SDP_RO_MAIN_LOST_LOCK_SHFT 1
-#define SDP_RO_MAIN_IN_LOCK_BMSK 0x0001
-#define SDP_RO_MAIN_IN_LOCK_SHFT 0
+#define SDP_RO_MAIN_STATUS1_ADDR 0x10
+#define SDP_RO_MAIN_COL_KILL_BMSK 0x0080
+#define SDP_RO_MAIN_COL_KILL_SHFT 7
+#define SDP_RO_MAIN_AD_RESULT_BMSK 0x0070
+#define SDP_RO_MAIN_AD_RESULT_SHFT 4
+#define SDP_RO_MAIN_FOLLOW_PW_BMSK 0x0008
+#define SDP_RO_MAIN_FOLLOW_PW_SHFT 3
+#define SDP_RO_MAIN_FSC_LOCK_BMSK 0x0004
+#define SDP_RO_MAIN_FSC_LOCK_SHFT 2
+#define SDP_RO_MAIN_LOST_LOCK_BMSK 0x0002
+#define SDP_RO_MAIN_LOST_LOCK_SHFT 1
+#define SDP_RO_MAIN_IN_LOCK_BMSK 0x0001
+#define SDP_RO_MAIN_IN_LOCK_SHFT 0
+
/*
* CSI Map Registers
*/
-#define CSI_REG_TX_CFG1_ADDR 0x00
-#define CSI_CTRL_TX_PWRDN_BMSK 0x0080
-#define CSI_CTRL_TX_PWRDN_SHFT 7
-#define CSI_CTRL_AUTO_PARAMS_BMSK 0x0020
-#define CSI_CTRL_AUTO_PARAMS_SHFT 5
-#define CSI_CTRL_NUM_LANES_BMSK 0x0007
-#define CSI_CTRL_NUM_LANES_SHFT 0
-
-#define CSI_REG_TX_DPHY_PWDN_ADDR 0xF0
-#define CSI_CTRL_DPHY_PWDN_BMSK 0x0001
-#define CSI_CTRL_DPHY_PWDN_SHFT 0
+#define CSI_REG_TX_CFG1_ADDR 0x00
+#define CSI_CTRL_TX_PWRDN_BMSK 0x0080
+#define CSI_CTRL_TX_PWRDN_SHFT 7
+#define CSI_CTRL_AUTO_PARAMS_BMSK 0x0020
+#define CSI_CTRL_AUTO_PARAMS_SHFT 5
+#define CSI_CTRL_NUM_LANES_BMSK 0x0007
+#define CSI_CTRL_NUM_LANES_SHFT 0
+
+#define CSI_REG_TX_DPHY_PWDN_ADDR 0xF0
+#define CSI_CTRL_DPHY_PWDN_BMSK 0x0001
+#define CSI_CTRL_DPHY_PWDN_SHFT 0
enum adv7481_adresult {
- AD_NTSM_M_J = 0x0,
- AD_NTSC_4_43 = 0x1,
- AD_PAL_M = 0x2,
- AD_PAL_60 = 0x3,
- AD_PAL_B_G = 0x4,
- AD_SECAM = 0x5,
- AD_PAL_COMB_N = 0x6,
- AD_SECAM_525 = 0x7,
+ AD_NTSM_M_J = 0x0,
+ AD_NTSC_4_43 = 0x1,
+ AD_PAL_M = 0x2,
+ AD_PAL_60 = 0x3,
+ AD_PAL_B_G = 0x4,
+ AD_SECAM = 0x5,
+ AD_PAL_COMB_N = 0x6,
+ AD_SECAM_525 = 0x7,
};
enum adv7481_color_depth {
- CD_8BIT = 0x0,
- CD_10BIT = 0x1,
- CD_12BIT = 0x2,
- CD_16BIT = 0x3,
+ CD_8BIT = 0x0,
+ CD_10BIT = 0x1,
+ CD_12BIT = 0x2,
+ CD_16BIT = 0x3,
};
enum adv7481_intrq_dur_sel {
- AD_4_XTAL_PER = 0x0,
- AD_16_XTAL_PER = 0x1,
- AD_64_XTAL_PER = 0x2,
- AD_ACTIVE_UNTIL_CLR = 0x3,
+ AD_4_XTAL_PER = 0x0,
+ AD_16_XTAL_PER = 0x1,
+ AD_64_XTAL_PER = 0x2,
+ AD_ACTIVE_UNTIL_CLR = 0x3,
};
enum adv7481_intrq_op_sel {
- AD_OP_OPEN_DRAIN = 0x0,
- AD_OP_DRIVE_LOW = 0x1,
- AD_OP_DRIVE_HIGH = 0x2,
- AD_OP_DISABLED = 0x3,
+ AD_OP_OPEN_DRAIN = 0x0,
+ AD_OP_DRIVE_LOW = 0x1,
+ AD_OP_DRIVE_HIGH = 0x2,
+ AD_OP_DISABLED = 0x3,
};
enum adv7481_drv_llc_pad {
- AD_LLC_PAD_NOT_USED = 0x0,
- AD_MIN_DRIVE_STRNGTH = 0x1,
- AD_MID_DRIVE_STRNGTH = 0x2,
- AD_MAX_DRIVE_STRNGTH = 0x3,
+ AD_LLC_PAD_NOT_USED = 0x0,
+ AD_MIN_DRIVE_STRNGTH = 0x1,
+ AD_MID_DRIVE_STRNGTH = 0x2,
+ AD_MAX_DRIVE_STRNGTH = 0x3,
};
#endif
diff --git a/drivers/media/platform/msm/ais/common/cam_soc_api.c b/drivers/media/platform/msm/ais/common/cam_soc_api.c
index 09d470ed6eb0..118d665a44d3 100644
--- a/drivers/media/platform/msm/ais/common/cam_soc_api.c
+++ b/drivers/media/platform/msm/ais/common/cam_soc_api.c
@@ -379,13 +379,13 @@ int msm_camera_clk_enable(struct device *dev,
clk_info[i].clk_name);
goto cam_clk_set_err;
}
- rc = clk_set_rate(clk_ptr[i],
- clk_rate);
- if (rc < 0) {
- pr_err("%s set rate failed\n",
- clk_info[i].clk_name);
- goto cam_clk_set_err;
- }
+ }
+ rc = clk_set_rate(clk_ptr[i],
+ clk_rate);
+ if (rc < 0) {
+ pr_err("%s set rate failed\n",
+ clk_info[i].clk_name);
+ goto cam_clk_set_err;
}
}
rc = clk_prepare_enable(clk_ptr[i]);
diff --git a/drivers/media/platform/msm/ais/isp/msm_buf_mgr.c b/drivers/media/platform/msm/ais/isp/msm_buf_mgr.c
index fcd803d4b138..2133f9391433 100644
--- a/drivers/media/platform/msm/ais/isp/msm_buf_mgr.c
+++ b/drivers/media/platform/msm/ais/isp/msm_buf_mgr.c
@@ -212,8 +212,8 @@ static int msm_isp_prepare_v4l2_buf(struct msm_isp_buf_mgr *buf_mgr,
mapped_info->paddr += accu_length;
accu_length += qbuf_buf->planes[i].length;
- CDBG("%s: plane: %d addr:%lu\n",
- __func__, i, (unsigned long)mapped_info->paddr);
+ CDBG("%s: plane: %d addr:%pK\n",
+ __func__, i, (void *)mapped_info->paddr);
}
buf_info->num_planes = qbuf_buf->num_planes;
@@ -275,8 +275,8 @@ static int msm_isp_map_buf(struct msm_isp_buf_mgr *buf_mgr,
pr_err_ratelimited("%s: cannot map address", __func__);
goto smmu_map_error;
}
- CDBG("%s: addr:%lu\n",
- __func__, (unsigned long)mapped_info->paddr);
+ CDBG("%s: addr:%pK\n",
+ __func__, (void *)mapped_info->paddr);
return rc;
smmu_map_error:
@@ -1367,14 +1367,15 @@ static int msm_isp_buf_mgr_debug(struct msm_isp_buf_mgr *buf_mgr,
struct msm_isp_buffer *bufs = NULL;
uint32_t i = 0, j = 0, k = 0, rc = 0;
char *print_buf = NULL, temp_buf[100];
- uint32_t start_addr = 0, end_addr = 0, print_buf_size = 2000;
+ uint32_t print_buf_size = 2000;
+ unsigned long start_addr = 0, end_addr = 0;
int buf_addr_delta = -1;
int temp_delta = 0;
uint32_t debug_output_id = 0;
uint32_t debug_buf_idx = 0;
uint32_t debug_buf_plane = 0;
- uint32_t debug_start_addr = 0;
- uint32_t debug_end_addr = 0;
+ unsigned long debug_start_addr = 0;
+ unsigned long debug_end_addr = 0;
uint32_t debug_frame_id = 0;
enum msm_isp_buffer_state debug_state = MSM_ISP_BUFFER_STATE_UNUSED;
unsigned long flags;
@@ -1433,8 +1434,8 @@ static int msm_isp_buf_mgr_debug(struct msm_isp_buf_mgr *buf_mgr,
debug_output_id, debug_frame_id);
pr_err("%s: nearby buf index %d, plane %d, state %d\n", __func__,
debug_buf_idx, debug_buf_plane, debug_state);
- pr_err("%s: buf address 0x%x -- 0x%x\n", __func__,
- debug_start_addr, debug_end_addr);
+ pr_err("%s: buf address %pK -- %pK\n", __func__,
+ (void *)debug_start_addr, (void *)debug_end_addr);
if (BUF_DEBUG_FULL) {
print_buf = kzalloc(print_buf_size, GFP_ATOMIC);
@@ -1469,9 +1470,10 @@ static int msm_isp_buf_mgr_debug(struct msm_isp_buf_mgr *buf_mgr,
mapped_info[k].len;
snprintf(temp_buf,
sizeof(temp_buf),
- " buf %d plane %d start_addr %x end_addr %x\n",
- j, k, start_addr,
- end_addr);
+ " buf %d plane %d start_addr %pK end_addr %pK\n",
+ j, k,
+ (void *)start_addr,
+ (void *)end_addr);
strlcat(print_buf, temp_buf,
print_buf_size);
}
diff --git a/drivers/media/platform/msm/ais/msm_buf_mgr/msm_generic_buf_mgr.c b/drivers/media/platform/msm/ais/msm_buf_mgr/msm_generic_buf_mgr.c
index 675bf6b24b03..073b91a6d2d9 100644
--- a/drivers/media/platform/msm/ais/msm_buf_mgr/msm_generic_buf_mgr.c
+++ b/drivers/media/platform/msm/ais/msm_buf_mgr/msm_generic_buf_mgr.c
@@ -561,8 +561,8 @@ static long msm_buf_mngr_subdev_ioctl(struct v4l2_subdev *sd,
sizeof(struct msm_buf_mngr_info))) {
return -EFAULT;
}
- MSM_CAM_GET_IOCTL_ARG_PTR(&k_ioctl.ioctl_ptr,
- &buf_info, sizeof(void *));
+ k_ioctl.ioctl_ptr = (uintptr_t)&buf_info;
+
argp = &k_ioctl;
rc = msm_cam_buf_mgr_ops(cmd, argp);
}
diff --git a/drivers/media/platform/msm/ais/pproc/cpp/msm_cpp.c b/drivers/media/platform/msm/ais/pproc/cpp/msm_cpp.c
index c9cb0080436a..811ac98beead 100644
--- a/drivers/media/platform/msm/ais/pproc/cpp/msm_cpp.c
+++ b/drivers/media/platform/msm/ais/pproc/cpp/msm_cpp.c
@@ -2889,6 +2889,8 @@ static int msm_cpp_validate_input(unsigned int cmd, void *arg,
case MSM_SD_SHUTDOWN:
case MSM_SD_NOTIFY_FREEZE:
case MSM_SD_UNNOTIFY_FREEZE:
+ case VIDIOC_MSM_CPP_IOMMU_ATTACH:
+ case VIDIOC_MSM_CPP_IOMMU_DETACH:
break;
default: {
if (ioctl_ptr == NULL) {
@@ -2897,8 +2899,9 @@ static int msm_cpp_validate_input(unsigned int cmd, void *arg,
}
*ioctl_ptr = arg;
- if ((*ioctl_ptr == NULL) ||
- (*ioctl_ptr)->ioctl_ptr == NULL) {
+ if (((*ioctl_ptr) == NULL) ||
+ ((*ioctl_ptr)->ioctl_ptr == NULL) ||
+ ((*ioctl_ptr)->len == 0)) {
pr_err("Error invalid ioctl argument cmd %u", cmd);
return -EINVAL;
}
diff --git a/drivers/media/platform/msm/ais/sensor/csiphy/msm_csiphy.c b/drivers/media/platform/msm/ais/sensor/csiphy/msm_csiphy.c
index 345fac905074..d146cc3d28a5 100644
--- a/drivers/media/platform/msm/ais/sensor/csiphy/msm_csiphy.c
+++ b/drivers/media/platform/msm/ais/sensor/csiphy/msm_csiphy.c
@@ -787,6 +787,25 @@ static int msm_csiphy_init(struct csiphy_device *csiphy_dev)
CDBG("%s:%d called\n", __func__, __LINE__);
+ rc = msm_camera_config_vreg(&csiphy_dev->pdev->dev,
+ csiphy_dev->csiphy_vreg,
+ csiphy_dev->regulator_count, NULL, 0,
+ &csiphy_dev->csiphy_reg_ptr[0], 1);
+ if (rc < 0) {
+ pr_err("%s:%d csiphy config_vreg failed\n",
+ __func__, __LINE__);
+ goto csiphy_vreg_config_fail;
+ }
+ rc = msm_camera_enable_vreg(&csiphy_dev->pdev->dev,
+ csiphy_dev->csiphy_vreg,
+ csiphy_dev->regulator_count, NULL, 0,
+ &csiphy_dev->csiphy_reg_ptr[0], 1);
+ if (rc < 0) {
+ pr_err("%s:%d csiphy enable_vreg failed\n",
+ __func__, __LINE__);
+ goto top_vreg_enable_failed;
+ }
+
rc = msm_camera_clk_enable(&csiphy_dev->pdev->dev,
csiphy_dev->csiphy_clk_info, csiphy_dev->csiphy_clk,
csiphy_dev->num_clk, true);
@@ -795,7 +814,7 @@ static int msm_csiphy_init(struct csiphy_device *csiphy_dev)
if (rc < 0) {
pr_err("%s: csiphy clk enable failed\n", __func__);
csiphy_dev->ref_count--;
- goto csiphy_resource_fail;
+ goto csiphy_enable_clk_fail;
}
CDBG("%s:%d called\n", __func__, __LINE__);
@@ -823,7 +842,17 @@ static int msm_csiphy_init(struct csiphy_device *csiphy_dev)
csiphy_dev->csiphy_state = CSIPHY_POWER_UP;
return 0;
-csiphy_resource_fail:
+csiphy_enable_clk_fail:
+ msm_camera_enable_vreg(&csiphy_dev->pdev->dev,
+ csiphy_dev->csiphy_vreg,
+ csiphy_dev->regulator_count, NULL, 0,
+ &csiphy_dev->csiphy_reg_ptr[0], 0);
+top_vreg_enable_failed:
+ msm_camera_config_vreg(&csiphy_dev->pdev->dev,
+ csiphy_dev->csiphy_vreg,
+ csiphy_dev->regulator_count, NULL, 0,
+ &csiphy_dev->csiphy_reg_ptr[0], 0);
+csiphy_vreg_config_fail:
if (cam_config_ahb_clk(NULL, 0, CAM_AHB_CLIENT_CSIPHY,
CAM_AHB_SUSPEND_VOTE) < 0)
pr_err("%s: failed to vote for AHB\n", __func__);
@@ -862,14 +891,34 @@ static int msm_csiphy_init(struct csiphy_device *csiphy_dev)
return rc;
}
+ rc = msm_camera_config_vreg(&csiphy_dev->pdev->dev,
+ csiphy_dev->csiphy_vreg,
+ csiphy_dev->regulator_count, NULL, 0,
+ &csiphy_dev->csiphy_reg_ptr[0], 1);
+ if (rc < 0) {
+ pr_err("%s:%d csiphy config_vreg failed\n",
+ __func__, __LINE__);
+ goto csiphy_vreg_config_fail;
+ }
+ rc = msm_camera_enable_vreg(&csiphy_dev->pdev->dev,
+ csiphy_dev->csiphy_vreg,
+ csiphy_dev->regulator_count, NULL, 0,
+ &csiphy_dev->csiphy_reg_ptr[0], 1);
+ if (rc < 0) {
+ pr_err("%s:%d csiphy enable_vreg failed\n",
+ __func__, __LINE__);
+ goto top_vreg_enable_failed;
+ }
+
rc = msm_camera_clk_enable(&csiphy_dev->pdev->dev,
csiphy_dev->csiphy_clk_info, csiphy_dev->csiphy_clk,
csiphy_dev->num_clk, true);
if (rc < 0) {
pr_err("%s: csiphy clk enable failed\n", __func__);
csiphy_dev->ref_count--;
- goto csiphy_resource_fail;
+ goto csiphy_enable_clk_fail;
}
+ CDBG("%s:%d clk enable success\n", __func__, __LINE__);
if (csiphy_dev->csiphy_3phase == CSI_3PHASE_HW)
msm_csiphy_3ph_reset(csiphy_dev);
@@ -890,7 +939,17 @@ static int msm_csiphy_init(struct csiphy_device *csiphy_dev)
csiphy_dev->csiphy_state = CSIPHY_POWER_UP;
return 0;
-csiphy_resource_fail:
+csiphy_enable_clk_fail:
+ msm_camera_enable_vreg(&csiphy_dev->pdev->dev,
+ csiphy_dev->csiphy_vreg,
+ csiphy_dev->regulator_count, NULL, 0,
+ &csiphy_dev->csiphy_reg_ptr[0], 0);
+top_vreg_enable_failed:
+ msm_camera_config_vreg(&csiphy_dev->pdev->dev,
+ csiphy_dev->csiphy_vreg,
+ csiphy_dev->regulator_count, NULL, 0,
+ &csiphy_dev->csiphy_reg_ptr[0], 0);
+csiphy_vreg_config_fail:
if (cam_config_ahb_clk(NULL, 0, CAM_AHB_CLIENT_CSIPHY,
CAM_AHB_SUSPEND_VOTE) < 0)
pr_err("%s: failed to vote for AHB\n", __func__);
@@ -999,6 +1058,14 @@ static int msm_csiphy_release(struct csiphy_device *csiphy_dev, void *arg)
csiphy_dev->csiphy_3p_clk, 2, false);
}
+ msm_camera_enable_vreg(&csiphy_dev->pdev->dev,
+ csiphy_dev->csiphy_vreg,
+ csiphy_dev->regulator_count, NULL, 0,
+ &csiphy_dev->csiphy_reg_ptr[0], 0);
+ msm_camera_config_vreg(&csiphy_dev->pdev->dev,
+ csiphy_dev->csiphy_vreg, csiphy_dev->regulator_count,
+ NULL, 0, &csiphy_dev->csiphy_reg_ptr[0], 0);
+
csiphy_dev->csiphy_state = CSIPHY_POWER_DOWN;
if (cam_config_ahb_clk(NULL, 0, CAM_AHB_CLIENT_CSIPHY,
@@ -1105,6 +1172,13 @@ static int msm_csiphy_release(struct csiphy_device *csiphy_dev, void *arg)
csiphy_dev->csiphy_3p_clk, 2, false);
}
+ msm_camera_enable_vreg(&csiphy_dev->pdev->dev,
+ csiphy_dev->csiphy_vreg, csiphy_dev->regulator_count,
+ NULL, 0, &csiphy_dev->csiphy_reg_ptr[0], 0);
+ msm_camera_config_vreg(&csiphy_dev->pdev->dev,
+ csiphy_dev->csiphy_vreg, csiphy_dev->regulator_count,
+ NULL, 0, &csiphy_dev->csiphy_reg_ptr[0], 0);
+
csiphy_dev->csiphy_state = CSIPHY_POWER_DOWN;
if (cam_config_ahb_clk(NULL, 0, CAM_AHB_CLIENT_CSIPHY,
@@ -1463,6 +1537,14 @@ static int csiphy_probe(struct platform_device *pdev)
goto csiphy_no_resource;
}
+ rc = msm_camera_get_dt_vreg_data(pdev->dev.of_node,
+ &(new_csiphy_dev->csiphy_vreg),
+ &(new_csiphy_dev->regulator_count));
+ if (rc < 0) {
+ pr_err("%s: get vreg data from dtsi fail\n", __func__);
+ rc = -EFAULT;
+ goto csiphy_no_resource;
+ }
/* ToDo: Enable 3phase clock for dynamic clock enable/disable */
rc = msm_csiphy_get_clk_info(new_csiphy_dev, pdev);
if (rc < 0) {
diff --git a/drivers/media/platform/msm/ais/sensor/csiphy/msm_csiphy.h b/drivers/media/platform/msm/ais/sensor/csiphy/msm_csiphy.h
index 9b38fa50ce98..025ce0d3e05a 100644
--- a/drivers/media/platform/msm/ais/sensor/csiphy/msm_csiphy.h
+++ b/drivers/media/platform/msm/ais/sensor/csiphy/msm_csiphy.h
@@ -20,6 +20,7 @@
#include <media/ais/msm_ais_sensor.h>
#include "msm_sd.h"
#include "msm_camera_io_util.h"
+#include "msm_camera_dt_util.h"
#include "cam_soc_api.h"
#define MAX_CSIPHY 3
@@ -169,6 +170,9 @@ struct csiphy_device {
uint32_t csiphy_sof_debug;
uint32_t csiphy_sof_debug_count;
uint32_t is_combo_mode;
+ struct camera_vreg_t *csiphy_vreg;
+ struct regulator *csiphy_reg_ptr[MAX_REGULATOR];
+ int32_t regulator_count;
struct msm_camera_csiphy_params csiphy_params;
};
diff --git a/drivers/media/platform/msm/camera_v2/common/cam_smmu_api.c b/drivers/media/platform/msm/camera_v2/common/cam_smmu_api.c
index 9cdcabb762c0..7d9edde62c1b 100644
--- a/drivers/media/platform/msm/camera_v2/common/cam_smmu_api.c
+++ b/drivers/media/platform/msm/camera_v2/common/cam_smmu_api.c
@@ -24,6 +24,7 @@
#include <linux/dma-mapping.h>
#include <linux/msm_dma_iommu_mapping.h>
#include <linux/workqueue.h>
+#include <linux/sizes.h>
#include <soc/qcom/scm.h>
#include <soc/qcom/secure_buffer.h>
#include <msm_camera_tz_util.h>
@@ -98,6 +99,7 @@ struct scratch_mapping {
struct cam_context_bank_info {
struct device *dev;
struct dma_iommu_mapping *mapping;
+ enum iommu_attr attr;
dma_addr_t va_start;
size_t va_len;
const char *name;
@@ -108,9 +110,8 @@ struct cam_context_bank_info {
struct mutex lock;
int handle;
enum cam_smmu_ops_param state;
- void (*handler[CAM_SMMU_CB_MAX])(struct iommu_domain *,
- struct device *, unsigned long,
- int, void*);
+ client_handler handler[CAM_SMMU_CB_MAX];
+ client_reset_handler hw_reset_handler[CAM_SMMU_CB_MAX];
void *token[CAM_SMMU_CB_MAX];
int cb_count;
int ref_cnt;
@@ -354,9 +355,9 @@ static void cam_smmu_check_vaddr_in_range(int idx, void *vaddr)
}
void cam_smmu_reg_client_page_fault_handler(int handle,
- void (*client_page_fault_handler)(struct iommu_domain *,
- struct device *, unsigned long,
- int, void*), void *token)
+ client_handler page_fault_handler,
+ client_reset_handler hw_reset_handler,
+ void *token)
{
int idx, i = 0;
@@ -380,7 +381,7 @@ void cam_smmu_reg_client_page_fault_handler(int handle,
return;
}
- if (client_page_fault_handler) {
+ if (page_fault_handler) {
if (iommu_cb_set.cb_info[idx].cb_count == CAM_SMMU_CB_MAX) {
pr_err("%s Should not regiester more handlers\n",
iommu_cb_set.cb_info[idx].name);
@@ -392,7 +393,9 @@ void cam_smmu_reg_client_page_fault_handler(int handle,
if (iommu_cb_set.cb_info[idx].token[i] == NULL) {
iommu_cb_set.cb_info[idx].token[i] = token;
iommu_cb_set.cb_info[idx].handler[i] =
- client_page_fault_handler;
+ page_fault_handler;
+ iommu_cb_set.cb_info[idx].hw_reset_handler[i] =
+ hw_reset_handler;
break;
}
}
@@ -420,6 +423,7 @@ static int cam_smmu_iommu_fault_handler(struct iommu_domain *domain,
{
char *cb_name;
int idx;
+ int j;
struct cam_smmu_work_payload *payload;
if (!token) {
@@ -453,6 +457,18 @@ static int cam_smmu_iommu_fault_handler(struct iommu_domain *domain,
payload->token = token;
payload->idx = idx;
+ /* trigger hw reset handler */
+ mutex_lock(&iommu_cb_set.cb_info[idx].lock);
+ for (j = 0; j < CAM_SMMU_CB_MAX; j++) {
+ if ((iommu_cb_set.cb_info[idx].hw_reset_handler[j])) {
+ iommu_cb_set.cb_info[idx].hw_reset_handler[j](
+ payload->domain,
+ payload->dev,
+ iommu_cb_set.cb_info[idx].token[j]);
+ }
+ }
+ mutex_unlock(&iommu_cb_set.cb_info[idx].lock);
+
mutex_lock(&iommu_cb_set.payload_list_lock);
list_add_tail(&payload->list, &iommu_cb_set.payload_list);
mutex_unlock(&iommu_cb_set.payload_list_lock);
@@ -876,6 +892,13 @@ static int cam_smmu_detach_device(int idx)
{
struct cam_context_bank_info *cb = &iommu_cb_set.cb_info[idx];
+ if (!list_empty_careful(&iommu_cb_set.cb_info[idx].smmu_buf_list)) {
+ pr_err("Client %s buffer list is not clean!\n",
+ iommu_cb_set.cb_info[idx].name);
+ cam_smmu_print_list(idx);
+ cam_smmu_clean_buffer_list(idx);
+ }
+
/* detach the mapping to device */
arm_iommu_detach_device(cb->dev);
iommu_cb_set.cb_info[idx].state = CAM_SMMU_DETACH;
@@ -1031,7 +1054,8 @@ static int cam_smmu_map_buffer_and_add_to_list(int idx, int ion_fd,
buf = dma_buf_get(ion_fd);
if (IS_ERR_OR_NULL(buf)) {
rc = PTR_ERR(buf);
- pr_err("Error: dma get buf failed. fd = %d\n", ion_fd);
+ pr_err("Error: dma get buf failed. fd = %d rc = %d\n",
+ ion_fd, rc);
goto err_out;
}
@@ -1096,7 +1120,9 @@ static int cam_smmu_map_buffer_and_add_to_list(int idx, int ion_fd,
rc = -ENOSPC;
goto err_mapping_info;
}
- CDBG("ion_fd = %d, dev = %pK, paddr= %pK, len = %u\n", ion_fd,
+ CDBG("name %s ion_fd = %d, dev = %pK, paddr= %pK, len = %u\n",
+ iommu_cb_set.cb_info[idx].name,
+ ion_fd,
(void *)iommu_cb_set.cb_info[idx].dev,
(void *)*paddr_ptr, (unsigned int)*len_ptr);
@@ -1305,6 +1331,48 @@ int cam_smmu_get_handle(char *identifier, int *handle_ptr)
}
EXPORT_SYMBOL(cam_smmu_get_handle);
+
+int cam_smmu_set_attr(int handle, uint32_t flags, int32_t *data)
+{
+ int ret = 0, idx;
+ struct cam_context_bank_info *cb = NULL;
+ struct iommu_domain *domain = NULL;
+
+ CDBG("E: set_attr\n");
+ idx = GET_SMMU_TABLE_IDX(handle);
+ if (handle == HANDLE_INIT || idx < 0 || idx >= iommu_cb_set.cb_num) {
+ pr_err("Error: handle or index invalid. idx = %d hdl = %x\n",
+ idx, handle);
+ return -EINVAL;
+ }
+ mutex_lock(&iommu_cb_set.cb_info[idx].lock);
+ if (iommu_cb_set.cb_info[idx].handle != handle) {
+ pr_err("Error: hdl is not valid, table_hdl = %x, hdl = %x\n",
+ iommu_cb_set.cb_info[idx].handle, handle);
+ mutex_unlock(&iommu_cb_set.cb_info[idx].lock);
+ return -EINVAL;
+ }
+
+ if (iommu_cb_set.cb_info[idx].state == CAM_SMMU_DETACH) {
+ domain = iommu_cb_set.cb_info[idx].mapping->domain;
+ cb = &iommu_cb_set.cb_info[idx];
+ cb->attr |= flags;
+ /* set attributes */
+ ret = iommu_domain_set_attr(domain, cb->attr, (void *)data);
+ if (ret < 0) {
+ mutex_unlock(&iommu_cb_set.cb_info[idx].lock);
+ pr_err("Error: set attr\n");
+ return -ENODEV;
+ }
+ } else {
+ ret = -EINVAL;
+ }
+ mutex_unlock(&iommu_cb_set.cb_info[idx].lock);
+ return ret;
+}
+EXPORT_SYMBOL(cam_smmu_set_attr);
+
+
int cam_smmu_ops(int handle, enum cam_smmu_ops_param ops)
{
int ret = 0, idx;
@@ -2226,7 +2294,7 @@ static int cam_smmu_setup_cb(struct cam_context_bank_info *cb,
}
} else {
cb->va_start = SZ_128K;
- cb->va_len = VA_SPACE_END - SZ_128K;
+ cb->va_len = VA_SPACE_END - SZ_128M;
}
/* create a virtual mapping */
diff --git a/drivers/media/platform/msm/camera_v2/common/cam_smmu_api.h b/drivers/media/platform/msm/camera_v2/common/cam_smmu_api.h
index 3b8481f8bf7e..189ab2488e65 100644
--- a/drivers/media/platform/msm/camera_v2/common/cam_smmu_api.h
+++ b/drivers/media/platform/msm/camera_v2/common/cam_smmu_api.h
@@ -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
@@ -49,6 +49,13 @@ enum cam_smmu_map_dir {
CAM_SMMU_MAP_INVALID
};
+typedef void (*client_handler)(struct iommu_domain *,
+ struct device *, unsigned long,
+ int, void*);
+
+typedef void (*client_reset_handler)(struct iommu_domain *,
+ struct device *, void*);
+
/**
* @param identifier: Unique identifier to be used by clients which they
* should get from device tree. CAM SMMU driver will
@@ -61,6 +68,16 @@ enum cam_smmu_map_dir {
*/
int cam_smmu_get_handle(char *identifier, int *handle_ptr);
+
+/**
+ * @param handle: Handle to identify the CAM SMMU client (VFE, CPP, FD etc.)
+ * @param flags : SMMU attribute type
+ * @data : Value of attribute
+ * @return Status of operation. Negative in case of error. Zero otherwise.
+ */
+int cam_smmu_set_attr(int handle, uint32_t flags, int32_t *data);
+
+
/**
* @param handle: Handle to identify the CAM SMMU client (VFE, CPP, FD etc.)
* @param op : Operation to be performed. Can be either CAM_SMMU_ATTACH
@@ -215,11 +232,12 @@ int cam_smmu_find_index_by_handle(int hdl);
/**
* @param handle: Handle to identify the CAM SMMU client (VFE, CPP, FD etc.)
* @param client_page_fault_handler: It is triggered in IOMMU page fault
+ * @param client_hw_reset_handler: It is triggered in IOMMU page fault
* @param token: It is input param when trigger page fault handler
*/
void cam_smmu_reg_client_page_fault_handler(int handle,
- void (*client_page_fault_handler)(struct iommu_domain *,
- struct device *, unsigned long,
- int, void*), void *token);
+ client_handler page_fault_handler,
+ client_reset_handler hw_reset_handler,
+ void *token);
#endif /* _CAM_SMMU_API_H_ */
diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_buf_mgr.c b/drivers/media/platform/msm/camera_v2/isp/msm_buf_mgr.c
index 5dbed80f5b85..8f3cffb4c3da 100644
--- a/drivers/media/platform/msm/camera_v2/isp/msm_buf_mgr.c
+++ b/drivers/media/platform/msm/camera_v2/isp/msm_buf_mgr.c
@@ -1166,10 +1166,15 @@ int msm_isp_smmu_attach(struct msm_isp_buf_mgr *buf_mgr,
{
struct msm_vfe_smmu_attach_cmd *cmd = arg;
int rc = 0;
+ int32_t stall_disable = 1;
pr_debug("%s: cmd->security_mode : %d\n", __func__, cmd->security_mode);
+
mutex_lock(&buf_mgr->lock);
if (cmd->iommu_attach_mode == IOMMU_ATTACH) {
+ /* disable smmu stall on fault */
+ cam_smmu_set_attr(buf_mgr->iommu_hdl,
+ DOMAIN_ATTR_CB_STALL_DISABLE, &stall_disable);
/*
* Call hypervisor thru scm call to notify secure or
* non-secure mode
diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp_axi_util.c b/drivers/media/platform/msm/camera_v2/isp/msm_isp_axi_util.c
index f9809615b407..7e74f2f10c8c 100644
--- a/drivers/media/platform/msm/camera_v2/isp/msm_isp_axi_util.c
+++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp_axi_util.c
@@ -1259,7 +1259,7 @@ void msm_isp_get_avtimer_ts(
int msm_isp_request_axi_stream(struct vfe_device *vfe_dev, void *arg)
{
- int rc = 0, i;
+ int rc = 0, i = 0;
uint32_t io_format = 0;
struct msm_vfe_axi_stream_request_cmd *stream_cfg_cmd = arg;
struct msm_vfe_axi_stream *stream_info;
@@ -1395,7 +1395,7 @@ done:
int msm_isp_release_axi_stream(struct vfe_device *vfe_dev, void *arg)
{
- int rc = 0, i;
+ int rc = 0, i = 0;
struct msm_vfe_axi_stream_release_cmd *stream_release_cmd = arg;
struct msm_vfe_axi_stream *stream_info;
struct msm_vfe_axi_stream_cfg_cmd stream_cfg;
@@ -2480,6 +2480,12 @@ int msm_isp_ab_ib_update_lpm_mode(struct vfe_device *vfe_dev, void *arg)
rc = -1;
return rc;
}
+ if (ab_ib_vote->num_src >= VFE_AXI_SRC_MAX) {
+ pr_err("%s: ab_ib_vote num_src is exceeding limit\n",
+ __func__);
+ rc = -1;
+ return rc;
+ }
if (ab_ib_vote->lpm_mode) {
for (i = 0; i < ab_ib_vote->num_src; i++) {
stream_info =
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 2f8134bc3efb..f19e6dd1cb01 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
@@ -2318,7 +2318,9 @@ int msm_isp_open_node(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
cam_smmu_reg_client_page_fault_handler(
vfe_dev->buf_mgr->iommu_hdl,
- msm_vfe_iommu_fault_handler, vfe_dev);
+ msm_vfe_iommu_fault_handler,
+ NULL,
+ vfe_dev);
mutex_unlock(&vfe_dev->core_mutex);
mutex_unlock(&vfe_dev->realtime_mutex);
return 0;
@@ -2367,7 +2369,7 @@ int msm_isp_close_node(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
/* Unregister page fault handler */
cam_smmu_reg_client_page_fault_handler(
vfe_dev->buf_mgr->iommu_hdl,
- NULL, vfe_dev);
+ NULL, NULL, vfe_dev);
rc = vfe_dev->hw_info->vfe_ops.axi_ops.halt(vfe_dev, 1);
if (rc <= 0)
diff --git a/drivers/media/platform/msm/camera_v2/ispif/msm_ispif.c b/drivers/media/platform/msm/camera_v2/ispif/msm_ispif.c
index 24e3223a79d0..ab7d4e86dcac 100644
--- a/drivers/media/platform/msm/camera_v2/ispif/msm_ispif.c
+++ b/drivers/media/platform/msm/camera_v2/ispif/msm_ispif.c
@@ -621,7 +621,7 @@ static int msm_ispif_reset(struct ispif_device *ispif)
ispif->base + ISPIF_VFE_m_INTF_CMD_0(i));
msm_camera_io_w(ISPIF_STOP_INTF_IMMEDIATELY,
ispif->base + ISPIF_VFE_m_INTF_CMD_1(i));
- pr_debug("%s: base %lx", __func__, (unsigned long)ispif->base);
+ pr_debug("%s: base %pK", __func__, ispif->base);
msm_camera_io_w(0, ispif->base +
ISPIF_VFE_m_PIX_INTF_n_CID_MASK(i, 0));
msm_camera_io_w(0, ispif->base +
diff --git a/drivers/media/platform/msm/camera_v2/pproc/cpp/msm_cpp.c b/drivers/media/platform/msm/camera_v2/pproc/cpp/msm_cpp.c
index b7feb126f707..25fc34b26bc1 100644
--- a/drivers/media/platform/msm/camera_v2/pproc/cpp/msm_cpp.c
+++ b/drivers/media/platform/msm/camera_v2/pproc/cpp/msm_cpp.c
@@ -424,7 +424,17 @@ static unsigned long msm_cpp_queue_buffer_info(struct cpp_device *cpp_dev,
list_for_each_entry_safe(buff, save, buff_head, entry) {
if (buff->map_info.buff_info.index == buffer_info->index) {
- pr_err("error buffer index already queued\n");
+ pr_err("error buf index already queued\n");
+ pr_err("error buf, fd %d idx %d native %d ssid %d %d\n",
+ buffer_info->fd, buffer_info->index,
+ buffer_info->native_buff,
+ buff_queue->session_id,
+ buff_queue->stream_id);
+ pr_err("existing buf,fd %d idx %d native %d id %x\n",
+ buff->map_info.buff_info.fd,
+ buff->map_info.buff_info.index,
+ buff->map_info.buff_info.native_buff,
+ buff->map_info.buff_info.identity);
goto error;
}
}
@@ -439,6 +449,11 @@ static unsigned long msm_cpp_queue_buffer_info(struct cpp_device *cpp_dev,
buff->map_info.buff_info = *buffer_info;
buff->map_info.buf_fd = buffer_info->fd;
+ trace_printk("fd %d index %d native_buff %d ssid %d %d\n",
+ buffer_info->fd, buffer_info->index,
+ buffer_info->native_buff, buff_queue->session_id,
+ buff_queue->stream_id);
+
if (buff_queue->security_mode == SECURE_MODE)
rc = cam_smmu_get_stage2_phy_addr(cpp_dev->iommu_hdl,
buffer_info->fd, CAM_SMMU_MAP_RW,
@@ -469,6 +484,11 @@ static void msm_cpp_dequeue_buffer_info(struct cpp_device *cpp_dev,
{
int ret = -1;
+ trace_printk("fd %d index %d native_buf %d ssid %d %d\n",
+ buff->map_info.buf_fd, buff->map_info.buff_info.index,
+ buff->map_info.buff_info.native_buff, buff_queue->session_id,
+ buff_queue->stream_id);
+
if (buff_queue->security_mode == SECURE_MODE)
ret = cam_smmu_put_stage2_phy_addr(cpp_dev->iommu_hdl,
buff->map_info.buf_fd);
@@ -770,6 +790,36 @@ static int msm_cpp_dump_addr(struct cpp_device *cpp_dev,
return 0;
}
+static void msm_cpp_iommu_fault_reset_handler(
+ struct iommu_domain *domain, struct device *dev,
+ void *token)
+{
+ struct cpp_device *cpp_dev = NULL;
+
+ if (!token) {
+ pr_err("Invalid token\n");
+ return;
+ }
+
+ cpp_dev = token;
+
+ if (cpp_dev->fault_status != CPP_IOMMU_FAULT_NONE) {
+ pr_err("fault already detected %d\n", cpp_dev->fault_status);
+ return;
+ }
+
+ cpp_dev->fault_status = CPP_IOMMU_FAULT_DETECTED;
+
+ /* mask IRQ status */
+ msm_camera_io_w(0xB, cpp_dev->cpp_hw_base + 0xC);
+
+ pr_err("Issue CPP HALT %d\n", cpp_dev->fault_status);
+
+ /* MMSS_A_CPP_AXI_CMD = 0x16C, reset 0x1*/
+ msm_camera_io_w(0x1, cpp_dev->cpp_hw_base + 0x16C);
+
+}
+
static void msm_cpp_iommu_fault_handler(struct iommu_domain *domain,
struct device *dev, unsigned long iova, int flags, void *token)
{
@@ -777,50 +827,94 @@ static void msm_cpp_iommu_fault_handler(struct iommu_domain *domain,
struct msm_cpp_frame_info_t *processed_frame[MAX_CPP_PROCESSING_FRAME];
int32_t i = 0, queue_len = 0;
struct msm_device_queue *queue = NULL;
- int32_t rc = 0;
+ int32_t ifd, ofd, dfd, t0fd, t1fd;
+ int counter = 0;
+ u32 result;
if (token) {
cpp_dev = token;
+
+ if (cpp_dev->fault_status != CPP_IOMMU_FAULT_DETECTED) {
+ pr_err("fault recovery already done %d\n",
+ cpp_dev->fault_status);
+ return;
+ }
+
disable_irq(cpp_dev->irq->start);
if (atomic_read(&cpp_timer.used)) {
atomic_set(&cpp_timer.used, 0);
del_timer_sync(&cpp_timer.cpp_timer);
}
- mutex_lock(&cpp_dev->mutex);
tasklet_kill(&cpp_dev->cpp_tasklet);
- rc = cpp_load_fw(cpp_dev, cpp_dev->fw_name_bin);
- if (rc < 0) {
- pr_err("load fw failure %d-retry\n", rc);
- rc = msm_cpp_reset_vbif_and_load_fw(cpp_dev);
- if (rc < 0) {
- msm_cpp_set_micro_irq_mask(cpp_dev, 1, 0x8);
- mutex_unlock(&cpp_dev->mutex);
- return;
- }
+
+ pr_err("in recovery, HALT status = 0x%x\n",
+ msm_camera_io_r(cpp_dev->cpp_hw_base + 0x10));
+
+ while (counter < MSM_CPP_POLL_RETRIES) {
+ result = msm_camera_io_r(cpp_dev->cpp_hw_base + 0x10);
+ if (result & 0x2)
+ break;
+ usleep_range(100, 200);
+ counter++;
}
+ /* MMSS_A_CPP_IRQ_STATUS_0 = 0x10 */
+ pr_err("counter %d HALT status later = 0x%x\n",
+ counter,
+ msm_camera_io_r(cpp_dev->cpp_hw_base + 0x10));
+
+ /* MMSS_A_CPP_RST_CMD_0 = 0x8 firmware reset = 0x3FFFF */
+ msm_camera_io_w(0x3FFFF, cpp_dev->cpp_hw_base + 0x8);
+
+ counter = 0;
+ while (counter < MSM_CPP_POLL_RETRIES) {
+ result = msm_camera_io_r(cpp_dev->cpp_hw_base + 0x10);
+ if (result & 0x1)
+ break;
+ usleep_range(100, 200);
+ counter++;
+ }
+
+ /* MMSS_A_CPP_IRQ_STATUS_0 = 0x10 */
+ pr_err("counter %d after reset IRQ_STATUS_0 = 0x%x\n",
+ counter,
+ msm_camera_io_r(cpp_dev->cpp_hw_base + 0x10));
+
+ /* MMSS_A_CPP_AXI_CMD = 0x16C, reset 0x1*/
+ msm_camera_io_w(0x0, cpp_dev->cpp_hw_base + 0x16C);
+
queue = &cpp_timer.data.cpp_dev->processing_q;
queue_len = queue->len;
if (!queue_len) {
pr_err("%s:%d: Invalid queuelen\n", __func__, __LINE__);
- msm_cpp_set_micro_irq_mask(cpp_dev, 1, 0x8);
- mutex_unlock(&cpp_dev->mutex);
- return;
}
+
for (i = 0; i < queue_len; i++) {
if (cpp_timer.data.processed_frame[i]) {
processed_frame[i] =
cpp_timer.data.processed_frame[i];
- pr_err("Fault on identity=0x%x, frame_id=%03d\n",
+ ifd = processed_frame[i]->input_buffer_info.fd;
+ ofd = processed_frame[i]->
+ output_buffer_info[0].fd;
+ dfd = processed_frame[i]->
+ duplicate_buffer_info.fd;
+ t0fd = processed_frame[i]->
+ tnr_scratch_buffer_info[0].fd;
+ t1fd = processed_frame[i]->
+ tnr_scratch_buffer_info[1].fd;
+ pr_err("Fault on identity=0x%x, frame_id=%03d\n",
processed_frame[i]->identity,
processed_frame[i]->frame_id);
+ pr_err("ifd %d ofd %d dfd %d t0fd %d t1fd %d\n",
+ ifd, ofd, dfd, t0fd, t1fd);
msm_cpp_dump_addr(cpp_dev, processed_frame[i]);
msm_cpp_dump_frame_cmd(processed_frame[i]);
}
}
msm_cpp_flush_queue_and_release_buffer(cpp_dev, queue_len);
- msm_cpp_set_micro_irq_mask(cpp_dev, 1, 0x8);
- mutex_unlock(&cpp_dev->mutex);
+ cpp_dev->fault_status = CPP_IOMMU_FAULT_RECOVERED;
+ pr_err("fault recovery successful\n");
}
+ return;
}
static int cpp_init_mem(struct cpp_device *cpp_dev)
@@ -842,7 +936,9 @@ static int cpp_init_mem(struct cpp_device *cpp_dev)
cpp_dev->iommu_hdl = iommu_hdl;
cam_smmu_reg_client_page_fault_handler(
cpp_dev->iommu_hdl,
- msm_cpp_iommu_fault_handler, cpp_dev);
+ msm_cpp_iommu_fault_handler,
+ msm_cpp_iommu_fault_reset_handler,
+ cpp_dev);
return 0;
}
@@ -981,6 +1077,7 @@ static int cpp_init_hardware(struct cpp_device *cpp_dev)
int rc = 0;
uint32_t vbif_version;
cpp_dev->turbo_vote = 0;
+ cpp_dev->fault_status = CPP_IOMMU_FAULT_NONE;
rc = msm_camera_regulator_enable(cpp_dev->cpp_vdd,
cpp_dev->num_reg, true);
@@ -1115,7 +1212,7 @@ static void cpp_release_hardware(struct cpp_device *cpp_dev)
rc = msm_cpp_update_bandwidth_setting(cpp_dev, 0, 0);
}
cpp_dev->stream_cnt = 0;
-
+ pr_info("cpp hw release done\n");
}
static int32_t cpp_load_fw(struct cpp_device *cpp_dev, char *fw_name_bin)
@@ -2536,6 +2633,16 @@ static int msm_cpp_cfg_frame(struct cpp_device *cpp_dev,
return -EINVAL;
}
+ if (cpp_dev->fault_status == CPP_IOMMU_FAULT_RECOVERED) {
+ pr_err("Error, page fault occurred %d\n",
+ cpp_dev->fault_status);
+ return -EINVAL;
+ } else if (cpp_dev->fault_status == CPP_IOMMU_FAULT_DETECTED) {
+ pr_err("drop frame, page fault occurred %d\n",
+ cpp_dev->fault_status);
+ return -EFAULT;
+ }
+
if (cpp_frame_msg[new_frame->msg_len - 1] !=
MSM_CPP_MSG_ID_TRAILER) {
pr_err("Invalid frame message\n");
@@ -3523,6 +3630,7 @@ STREAM_BUFF_END:
break;
case VIDIOC_MSM_CPP_IOMMU_ATTACH: {
if (cpp_dev->iommu_state == CPP_IOMMU_STATE_DETACHED) {
+ int32_t stall_disable;
struct msm_camera_smmu_attach_type cpp_attach_info;
if (ioctl_ptr->len !=
@@ -3540,7 +3648,10 @@ STREAM_BUFF_END:
}
cpp_dev->security_mode = cpp_attach_info.attach;
-
+ stall_disable = 1;
+ /* disable smmu stall on fault */
+ cam_smmu_set_attr(cpp_dev->iommu_hdl,
+ DOMAIN_ATTR_CB_STALL_DISABLE, &stall_disable);
if (cpp_dev->security_mode == SECURE_MODE) {
rc = cam_smmu_ops(cpp_dev->iommu_hdl,
CAM_SMMU_ATTACH_SEC_CPP);
diff --git a/drivers/media/platform/msm/camera_v2/pproc/cpp/msm_cpp.h b/drivers/media/platform/msm/camera_v2/pproc/cpp/msm_cpp.h
index a05448091e42..f2c544785f46 100644
--- a/drivers/media/platform/msm/camera_v2/pproc/cpp/msm_cpp.h
+++ b/drivers/media/platform/msm/camera_v2/pproc/cpp/msm_cpp.h
@@ -130,6 +130,12 @@ enum cpp_iommu_state {
CPP_IOMMU_STATE_ATTACHED,
};
+enum cpp_iommu_fault_state {
+ CPP_IOMMU_FAULT_NONE,
+ CPP_IOMMU_FAULT_DETECTED,
+ CPP_IOMMU_FAULT_RECOVERED,
+};
+
enum msm_queue {
MSM_CAM_Q_CTRL, /* control command or control command status */
MSM_CAM_Q_VFE_EVT, /* adsp event */
@@ -287,6 +293,7 @@ struct cpp_device {
struct msm_cpp_vbif_data *vbif_data;
bool turbo_vote;
struct cx_ipeak_client *cpp_cx_ipeak;
+ enum cpp_iommu_fault_state fault_status;
};
int msm_cpp_set_micro_clk(struct cpp_device *cpp_dev);
diff --git a/drivers/media/platform/msm/camera_v2/sensor/csiphy/include/msm_csiphy_5_0_1_hwreg.h b/drivers/media/platform/msm/camera_v2/sensor/csiphy/include/msm_csiphy_5_0_1_hwreg.h
index 9120a4cc85ca..5dbcbd219732 100644
--- a/drivers/media/platform/msm/camera_v2/sensor/csiphy/include/msm_csiphy_5_0_1_hwreg.h
+++ b/drivers/media/platform/msm/camera_v2/sensor/csiphy/include/msm_csiphy_5_0_1_hwreg.h
@@ -100,6 +100,8 @@ struct csiphy_reg_3ph_parms_t csiphy_v5_0_1_3ph = {
{0x38, 0xFE},
{0x81c, 0x2},
{0x700, 0x80},
+ {0x724, 0x04},
+ {0x024, 0x04},
};
struct csiphy_settings_t csiphy_combo_mode_v5_0_1 = {
diff --git a/drivers/media/platform/msm/camera_v2/sensor/csiphy/include/msm_csiphy_5_0_hwreg.h b/drivers/media/platform/msm/camera_v2/sensor/csiphy/include/msm_csiphy_5_0_hwreg.h
index 8591f0646080..98d0b933bba2 100644
--- a/drivers/media/platform/msm/camera_v2/sensor/csiphy/include/msm_csiphy_5_0_hwreg.h
+++ b/drivers/media/platform/msm/camera_v2/sensor/csiphy/include/msm_csiphy_5_0_hwreg.h
@@ -101,6 +101,8 @@ struct csiphy_reg_3ph_parms_t csiphy_v5_0_3ph = {
{0x38, 0xFE},
{0x81c, 0x6},
{0x700, 0x80},
+ {0x724, 0x04},
+ {0x024, 0x04},
};
struct csiphy_settings_t csiphy_combo_mode_v5_0 = {
diff --git a/drivers/media/platform/msm/camera_v2/sensor/csiphy/msm_csiphy.c b/drivers/media/platform/msm/camera_v2/sensor/csiphy/msm_csiphy.c
index 214dd6f3406d..8d091320cbca 100644
--- a/drivers/media/platform/msm/camera_v2/sensor/csiphy/msm_csiphy.c
+++ b/drivers/media/platform/msm/camera_v2/sensor/csiphy/msm_csiphy.c
@@ -684,14 +684,20 @@ static int msm_csiphy_2phase_lane_config_v50(
csiphybase + csiphy_dev->ctrl_reg->
csiphy_3ph_reg.
mipi_csiphy_2ph_lnn_ctrl15.addr + offset);
- if (mask == CLOCK_LANE)
+ if (mask == CLOCK_LANE) {
msm_camera_io_w(csiphy_dev->ctrl_reg->
csiphy_3ph_reg.
mipi_csiphy_2ph_lnck_ctrl0.data,
csiphybase + csiphy_dev->ctrl_reg->
csiphy_3ph_reg.
mipi_csiphy_2ph_lnck_ctrl0.addr);
- else
+ msm_camera_io_w(csiphy_dev->ctrl_reg->
+ csiphy_3ph_reg.
+ mipi_csiphy_2ph_lnck_ctrl9.data,
+ csiphybase + csiphy_dev->ctrl_reg->
+ csiphy_3ph_reg.
+ mipi_csiphy_2ph_lnck_ctrl9.addr);
+ } else {
msm_camera_io_w(csiphy_dev->ctrl_reg->
csiphy_3ph_reg.
mipi_csiphy_2ph_lnn_ctrl0.data,
@@ -699,6 +705,14 @@ static int msm_csiphy_2phase_lane_config_v50(
csiphy_3ph_reg.
mipi_csiphy_2ph_lnn_ctrl0.addr +
offset);
+ msm_camera_io_w(csiphy_dev->ctrl_reg->
+ csiphy_3ph_reg.
+ mipi_csiphy_2ph_lnn_ctrl9.data,
+ csiphybase + csiphy_dev->ctrl_reg->
+ csiphy_3ph_reg.
+ mipi_csiphy_2ph_lnn_ctrl9.addr +
+ offset);
+ }
msm_camera_io_w(csiphy_dev->ctrl_reg->
csiphy_3ph_reg.
mipi_csiphy_2ph_lnn_cfg1.data,
diff --git a/drivers/media/platform/msm/camera_v2/sensor/csiphy/msm_csiphy.h b/drivers/media/platform/msm/camera_v2/sensor/csiphy/msm_csiphy.h
index c1a9748e8af5..c33f183963cc 100644
--- a/drivers/media/platform/msm/camera_v2/sensor/csiphy/msm_csiphy.h
+++ b/drivers/media/platform/msm/camera_v2/sensor/csiphy/msm_csiphy.h
@@ -142,6 +142,8 @@ struct csiphy_reg_3ph_parms_t {
struct csiphy_reg_t mipi_csiphy_2ph_lnn_ctrl14;
struct csiphy_reg_t mipi_csiphy_3ph_cmn_ctrl7_cphy;
struct csiphy_reg_t mipi_csiphy_2ph_lnck_ctrl0;
+ struct csiphy_reg_t mipi_csiphy_2ph_lnck_ctrl9;
+ struct csiphy_reg_t mipi_csiphy_2ph_lnn_ctrl9;
};
struct csiphy_ctrl_t {
diff --git a/drivers/media/platform/msm/sde/Kconfig b/drivers/media/platform/msm/sde/Kconfig
index 85f5f4257ddb..d2c2e90f9de9 100644
--- a/drivers/media/platform/msm/sde/Kconfig
+++ b/drivers/media/platform/msm/sde/Kconfig
@@ -15,3 +15,15 @@ config MSM_SDE_ROTATOR_EVTLOG_DEBUG
features to: Dump rotator registers during driver errors, panic
driver during fatal errors and enable some rotator driver logging
into an internal buffer (this avoids logging overhead).
+
+config MSM_SDE_HDMI_CEC
+ bool "QTI SDE HDMI CEC Driver"
+ depends on DRM_SDE_HDMI
+ select MEDIA_CEC_SUPPORT
+ select MEDIA_CEC_EDID
+ select MEDIA_CEC_NOTIFIER
+ ---help---
+ The HDMI CEC driver provides support to enable HDMI CEC features
+ which allows various audiovisual products to communicate using HDMI
+ CEC links. CEC is a protocol defined in HDMI spec which consists of
+ both low-level and high-level protocol definition.
diff --git a/drivers/media/platform/msm/sde/Makefile b/drivers/media/platform/msm/sde/Makefile
index fe55d5044c3b..f39000a15993 100644
--- a/drivers/media/platform/msm/sde/Makefile
+++ b/drivers/media/platform/msm/sde/Makefile
@@ -1 +1,2 @@
obj-$(CONFIG_MSM_SDE_ROTATOR) += rotator/
+obj-$(CONFIG_MSM_SDE_HDMI_CEC) += cec/
diff --git a/drivers/media/platform/msm/sde/cec/Makefile b/drivers/media/platform/msm/sde/cec/Makefile
new file mode 100644
index 000000000000..2a9c30980512
--- /dev/null
+++ b/drivers/media/platform/msm/sde/cec/Makefile
@@ -0,0 +1,3 @@
+obj-y := \
+ sde_hdmi_cec.o \
+ sde_hdmi_cec_util.o
diff --git a/drivers/media/platform/msm/sde/cec/sde_hdmi_cec.c b/drivers/media/platform/msm/sde/cec/sde_hdmi_cec.c
new file mode 100644
index 000000000000..b3798e8a9d24
--- /dev/null
+++ b/drivers/media/platform/msm/sde/cec/sde_hdmi_cec.c
@@ -0,0 +1,429 @@
+/* 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.
+ */
+
+#define pr_fmt(fmt) "%s: " fmt, __func__
+
+#include <linux/clk.h>
+#include <linux/interrupt.h>
+#include <linux/kernel.h>
+#include <linux/mfd/syscon.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_platform.h>
+#include <linux/of_irq.h>
+#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
+#include <linux/cec.h>
+#include <media/cec.h>
+#include <media/cec-edid.h>
+#include <media/cec-notifier.h>
+
+#include "sde_hdmi_cec_util.h"
+
+#define CEC_NAME "sde-hdmi-cec"
+
+/* CEC Register Definition */
+#define CEC_INTR_MASK (BIT(1) | BIT(3) | BIT(7))
+#define CEC_SUPPORTED_HW_VERSION 0x30000001
+
+#define HDMI_CEC_WR_RANGE (0x000002DC)
+#define HDMI_CEC_RD_RANGE (0x000002E0)
+#define HDMI_VERSION (0x000002E4)
+#define HDMI_CEC_CTRL (0x0000028C)
+#define HDMI_CEC_WR_DATA (0x00000290)
+#define HDMI_CEC_RETRANSMIT (0x00000294)
+#define HDMI_CEC_STATUS (0x00000298)
+#define HDMI_CEC_INT (0x0000029C)
+#define HDMI_CEC_ADDR (0x000002A0)
+#define HDMI_CEC_TIME (0x000002A4)
+#define HDMI_CEC_REFTIMER (0x000002A8)
+#define HDMI_CEC_RD_DATA (0x000002AC)
+#define HDMI_CEC_RD_FILTER (0x000002B0)
+#define HDMI_CEC_COMPL_CTL (0x00000360)
+#define HDMI_CEC_RD_START_RANGE (0x00000364)
+#define HDMI_CEC_RD_TOTAL_RANGE (0x00000368)
+#define HDMI_CEC_RD_ERR_RESP_LO (0x0000036C)
+#define HDMI_CEC_WR_CHECK_CONFIG (0x00000370)
+
+enum cec_irq_status {
+ CEC_IRQ_FRAME_WR_DONE = 1 << 0,
+ CEC_IRQ_FRAME_RD_DONE = 1 << 1,
+ CEC_IRQ_FRAME_ERROR = 1 << 2,
+};
+
+struct sde_hdmi_cec {
+ struct cec_adapter *adap;
+ struct device *dev;
+ struct cec_hw_resource hw_res;
+ int irq;
+ enum cec_irq_status irq_status;
+ struct cec_notifier *notifier;
+};
+
+static int sde_hdmi_cec_adap_enable(struct cec_adapter *adap, bool enable)
+{
+ struct sde_hdmi_cec *cec = adap->priv;
+ struct cec_hw_resource *hw = &cec->hw_res;
+ u32 hdmi_hw_version, reg_val;
+
+ pr_debug("adap enable %d\n", enable);
+
+ if (enable) {
+ pm_runtime_get_sync(cec->dev);
+
+ /* 19.2Mhz * 0.00005 us = 950 = 0x3B6 */
+ CEC_REG_WRITE(hw, HDMI_CEC_REFTIMER, (0x3B6 & 0xFFF) | BIT(16));
+
+ hdmi_hw_version = CEC_REG_READ(hw, HDMI_VERSION);
+ if (hdmi_hw_version >= CEC_SUPPORTED_HW_VERSION) {
+ CEC_REG_WRITE(hw, HDMI_CEC_RD_RANGE, 0x30AB9888);
+ CEC_REG_WRITE(hw, HDMI_CEC_WR_RANGE, 0x888AA888);
+
+ CEC_REG_WRITE(hw, HDMI_CEC_RD_START_RANGE, 0x88888888);
+ CEC_REG_WRITE(hw, HDMI_CEC_RD_TOTAL_RANGE, 0x99);
+ CEC_REG_WRITE(hw, HDMI_CEC_COMPL_CTL, 0xF);
+ CEC_REG_WRITE(hw, HDMI_CEC_WR_CHECK_CONFIG, 0x4);
+ } else {
+ pr_err("CEC version %d is not supported.\n",
+ hdmi_hw_version);
+ return -EPERM;
+ }
+
+ CEC_REG_WRITE(hw, HDMI_CEC_RD_FILTER, BIT(0) | (0x7FF << 4));
+ CEC_REG_WRITE(hw, HDMI_CEC_TIME, BIT(0) | ((7 * 0x30) << 7));
+
+ /* Enable CEC interrupts */
+ CEC_REG_WRITE(hw, HDMI_CEC_INT, CEC_INTR_MASK);
+
+ /* Enable Engine */
+ CEC_REG_WRITE(hw, HDMI_CEC_CTRL, BIT(0));
+ } else {
+ /* Disable Engine */
+ CEC_REG_WRITE(hw, HDMI_CEC_CTRL, 0);
+
+ /* Disable CEC interrupts */
+ reg_val = CEC_REG_READ(hw, HDMI_CEC_INT);
+ CEC_REG_WRITE(hw, HDMI_CEC_INT, reg_val & ~CEC_INTR_MASK);
+
+ pm_runtime_put(cec->dev);
+ }
+
+ return 0;
+}
+
+static int sde_hdmi_cec_adap_log_addr(struct cec_adapter *adap, u8 logical_addr)
+{
+ struct sde_hdmi_cec *cec = adap->priv;
+ struct cec_hw_resource *hw = &cec->hw_res;
+
+ pr_debug("set log addr %d\n", logical_addr);
+
+ CEC_REG_WRITE(hw, HDMI_CEC_ADDR, logical_addr & 0xF);
+
+ return 0;
+}
+
+static int sde_hdmi_cec_adap_transmit(struct cec_adapter *adap, u8 attempts,
+ u32 signal_free_time, struct cec_msg *msg)
+{
+ struct sde_hdmi_cec *cec = adap->priv;
+ struct cec_hw_resource *hw = &cec->hw_res;
+ u32 frame_type;
+ int i;
+ u32 line_check_retry = 10;
+
+ pr_debug("transmit msg [%d]->[%d]: len = %d, attampts=%d, signal_free_time=%d\n",
+ cec_msg_initiator(msg), cec_msg_destination(msg), msg->len,
+ attempts, signal_free_time);
+
+ /* toggle cec in order to flush out bad hw state, if any */
+ CEC_REG_WRITE(hw, HDMI_CEC_CTRL, 0);
+ CEC_REG_WRITE(hw, HDMI_CEC_CTRL, BIT(0));
+
+ /* make sure state is cleared */
+ wmb();
+
+ CEC_REG_WRITE(hw, HDMI_CEC_RETRANSMIT,
+ ((attempts & 0xF) << 4) | BIT(0));
+
+ frame_type = cec_msg_is_broadcast(msg) ? BIT(0) : 0;
+
+ /* header block */
+ CEC_REG_WRITE(hw, HDMI_CEC_WR_DATA,
+ (((cec_msg_initiator(msg) << 4) |
+ cec_msg_destination(msg)) << 8) | frame_type);
+
+ /* data block 0 : opcode */
+ CEC_REG_WRITE(hw, HDMI_CEC_WR_DATA,
+ ((msg->len < 2 ? 0 : cec_msg_opcode(msg)) << 8) | frame_type);
+
+ /* data block 1-14 : operand 0-13 */
+ for (i = 2; i < msg->len; i++)
+ CEC_REG_WRITE(hw, HDMI_CEC_WR_DATA,
+ (msg->msg[i] << 8) | frame_type);
+
+ /* check line status */
+ while ((CEC_REG_READ(hw, HDMI_CEC_STATUS) & BIT(0)) &&
+ line_check_retry) {
+ line_check_retry--;
+ pr_debug("CEC line is busy(%d)\n", line_check_retry);
+ schedule();
+ }
+
+ if (!line_check_retry && (CEC_REG_READ(hw, HDMI_CEC_STATUS) & BIT(0))) {
+ pr_err("CEC line is busy. Retry failed\n");
+ return -EBUSY;
+ }
+
+ /* start transmission */
+ CEC_REG_WRITE(hw, HDMI_CEC_CTRL, BIT(0) | BIT(1) |
+ ((msg->len & 0x1F) << 4) | BIT(9));
+
+ return 0;
+}
+
+static void sde_hdmi_cec_handle_rx_done(struct sde_hdmi_cec *cec)
+{
+ struct cec_hw_resource *hw = &cec->hw_res;
+ struct cec_msg msg = {};
+ u32 data;
+ int i;
+
+ pr_debug("rx done\n");
+
+ data = CEC_REG_READ(hw, HDMI_CEC_RD_DATA);
+ msg.len = (data & 0x1F00) >> 8;
+ if (msg.len < 1 || msg.len > CEC_MAX_MSG_SIZE) {
+ pr_err("invalid message size %d", msg.len);
+ return;
+ }
+ msg.msg[0] = data & 0xFF;
+
+ for (i = 1; i < msg.len; i++)
+ msg.msg[i] = CEC_REG_READ(hw, HDMI_CEC_RD_DATA) & 0xFF;
+
+ cec_received_msg(cec->adap, &msg);
+}
+
+static void sde_hdmi_cec_handle_tx_done(struct sde_hdmi_cec *cec)
+{
+ pr_debug("tx done\n");
+ cec_transmit_done(cec->adap, CEC_TX_STATUS_OK, 0, 0, 0, 0);
+}
+
+static void sde_hdmi_cec_handle_tx_error(struct sde_hdmi_cec *cec)
+{
+ struct cec_hw_resource *hw = &cec->hw_res;
+ u32 cec_status = CEC_REG_READ(hw, HDMI_CEC_STATUS);
+
+ pr_debug("tx error status %x\n", cec_status);
+
+ if ((cec_status & 0xF0) == 0x10)
+ cec_transmit_done(cec->adap,
+ CEC_TX_STATUS_NACK, 0, 1, 0, 0);
+ else if ((cec_status & 0xF0) == 0x30)
+ cec_transmit_done(cec->adap,
+ CEC_TX_STATUS_ARB_LOST, 1, 0, 0, 0);
+ else
+ cec_transmit_done(cec->adap,
+ CEC_TX_STATUS_ERROR | CEC_TX_STATUS_MAX_RETRIES,
+ 0, 0, 0, 1);
+}
+
+static irqreturn_t sde_hdmi_cec_irq_handler_thread(int irq, void *priv)
+{
+ struct sde_hdmi_cec *cec = priv;
+
+ pr_debug("irq thread: status %x\n", cec->irq_status);
+
+ if (cec->irq_status & CEC_IRQ_FRAME_WR_DONE)
+ sde_hdmi_cec_handle_tx_done(cec);
+
+ if (cec->irq_status & CEC_IRQ_FRAME_ERROR)
+ sde_hdmi_cec_handle_tx_error(cec);
+
+ if (cec->irq_status & CEC_IRQ_FRAME_RD_DONE)
+ sde_hdmi_cec_handle_rx_done(cec);
+
+ cec->irq_status = 0;
+
+ return IRQ_HANDLED;
+}
+
+static irqreturn_t sde_hdmi_cec_irq_handler(int irq, void *priv)
+{
+ struct sde_hdmi_cec *cec = priv;
+ struct cec_hw_resource *hw = &cec->hw_res;
+ u32 data = CEC_REG_READ(hw, HDMI_CEC_INT);
+
+ CEC_REG_WRITE(hw, HDMI_CEC_INT, data);
+
+ pr_debug("irq handler: %x\n", data);
+
+ if ((data & BIT(0)) && (data & BIT(1)))
+ cec->irq_status |= CEC_IRQ_FRAME_WR_DONE;
+
+ if ((data & BIT(2)) && (data & BIT(3)))
+ cec->irq_status |= CEC_IRQ_FRAME_ERROR;
+
+ if ((data & BIT(6)) && (data & BIT(7)))
+ cec->irq_status |= CEC_IRQ_FRAME_RD_DONE;
+
+ return cec->irq_status ? IRQ_WAKE_THREAD : IRQ_HANDLED;
+}
+
+static const struct cec_adap_ops sde_hdmi_cec_adap_ops = {
+ .adap_enable = sde_hdmi_cec_adap_enable,
+ .adap_log_addr = sde_hdmi_cec_adap_log_addr,
+ .adap_transmit = sde_hdmi_cec_adap_transmit,
+};
+
+static int sde_hdmi_cec_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct sde_hdmi_cec *cec;
+ struct device_node *np;
+ struct platform_device *hdmi_dev;
+ int ret;
+
+ cec = devm_kzalloc(dev, sizeof(*cec), GFP_KERNEL);
+ if (!cec)
+ return -ENOMEM;
+
+ cec->dev = dev;
+
+ np = of_parse_phandle(pdev->dev.of_node, "qcom,hdmi-dev", 0);
+ if (!np) {
+ pr_err("failed to find hdmi node in device tree\n");
+ return -ENODEV;
+ }
+ hdmi_dev = of_find_device_by_node(np);
+ if (hdmi_dev == NULL)
+ return -EPROBE_DEFER;
+
+ cec->irq = of_irq_get(dev->of_node, 0);
+ if (cec->irq < 0) {
+ pr_err("failed to get irq\n");
+ return cec->irq;
+ }
+
+ ret = devm_request_threaded_irq(dev, cec->irq, sde_hdmi_cec_irq_handler,
+ sde_hdmi_cec_irq_handler_thread, 0,
+ pdev->name, cec);
+ if (ret)
+ return ret;
+
+ ret = sde_hdmi_cec_init_resource(pdev, &cec->hw_res);
+ if (ret)
+ return ret;
+
+ cec->adap = cec_allocate_adapter(&sde_hdmi_cec_adap_ops, cec,
+ CEC_NAME,
+ CEC_CAP_LOG_ADDRS | CEC_CAP_PASSTHROUGH |
+ CEC_CAP_TRANSMIT, 1);
+ ret = PTR_ERR_OR_ZERO(cec->adap);
+ if (ret)
+ return ret;
+
+ ret = cec_register_adapter(cec->adap, &pdev->dev);
+ if (ret)
+ goto err_del_adap;
+
+ cec->notifier = cec_notifier_get(&hdmi_dev->dev);
+ if (!cec->notifier) {
+ pr_err("failed to get cec notifier\n");
+ goto err_del_adap;
+ }
+
+ platform_set_drvdata(pdev, cec);
+
+ pm_runtime_enable(dev);
+
+ /*
+ * cec_register_cec_notifier has to be later than pm_runtime_enable
+ * because it calls adap_enable.
+ */
+ cec_register_cec_notifier(cec->adap, cec->notifier);
+
+ pr_debug("probe done\n");
+
+ return ret;
+
+err_del_adap:
+ cec_delete_adapter(cec->adap);
+ return ret;
+}
+
+static int sde_hdmi_cec_remove(struct platform_device *pdev)
+{
+ struct sde_hdmi_cec *cec = platform_get_drvdata(pdev);
+
+ pm_runtime_disable(&pdev->dev);
+
+ cec_unregister_adapter(cec->adap);
+ cec_notifier_put(cec->notifier);
+
+ devm_free_irq(&pdev->dev, cec->irq, cec);
+ sde_hdmi_cec_deinit_resource(pdev, &cec->hw_res);
+
+ pr_debug("remove done\n");
+
+ return 0;
+}
+
+static int __maybe_unused sde_hdmi_cec_runtime_suspend(struct device *dev)
+{
+ struct sde_hdmi_cec *cec = dev_get_drvdata(dev);
+ struct cec_hw_resource *hw = &cec->hw_res;
+
+ pr_debug("runtime suspend\n");
+
+ return sde_hdmi_cec_enable_power(hw, false);
+}
+
+static int __maybe_unused sde_hdmi_cec_runtime_resume(struct device *dev)
+{
+ struct sde_hdmi_cec *cec = dev_get_drvdata(dev);
+ struct cec_hw_resource *hw = &cec->hw_res;
+
+ pr_debug("runtime resume\n");
+
+ return sde_hdmi_cec_enable_power(hw, true);
+}
+
+static const struct dev_pm_ops sde_hdmi_cec_pm_ops = {
+ SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend,
+ pm_runtime_force_resume)
+ SET_RUNTIME_PM_OPS(sde_hdmi_cec_runtime_suspend,
+ sde_hdmi_cec_runtime_resume, NULL)
+};
+
+static const struct of_device_id sde_hdmi_cec_match[] = {
+ {
+ .compatible = "qcom,hdmi-cec",
+ },
+ {},
+};
+MODULE_DEVICE_TABLE(of, sde_hdmi_cec_match);
+
+static struct platform_driver sde_hdmi_cec_pdrv = {
+ .probe = sde_hdmi_cec_probe,
+ .remove = sde_hdmi_cec_remove,
+ .driver = {
+ .name = CEC_NAME,
+ .of_match_table = sde_hdmi_cec_match,
+ .pm = &sde_hdmi_cec_pm_ops,
+ },
+};
+
+module_platform_driver(sde_hdmi_cec_pdrv);
+MODULE_DESCRIPTION("MSM SDE HDMI CEC driver");
diff --git a/drivers/media/platform/msm/sde/cec/sde_hdmi_cec_util.c b/drivers/media/platform/msm/sde/cec/sde_hdmi_cec_util.c
new file mode 100644
index 000000000000..323e0805c886
--- /dev/null
+++ b/drivers/media/platform/msm/sde/cec/sde_hdmi_cec_util.c
@@ -0,0 +1,743 @@
+/* Copyright (c) 2012, 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.
+ */
+
+#define pr_fmt(fmt) "%s: " fmt, __func__
+
+#include <linux/clk.h>
+#include <linux/err.h>
+#include <linux/io.h>
+#include <linux/of.h>
+#include <linux/regulator/consumer.h>
+#include <linux/delay.h>
+
+#include "sde_hdmi_cec_util.h"
+
+void sde_hdmi_cec_reg_w(struct cec_io_data *io,
+ u32 offset, u32 value, bool debug)
+{
+ u32 in_val;
+
+ if (!io || !io->base) {
+ pr_err("invalid input\n");
+ return;
+ }
+
+ if (offset > io->len) {
+ pr_err("offset out of range\n");
+ return;
+ }
+
+ writel_relaxed(value, io->base + offset);
+ if (debug) {
+ in_val = readl_relaxed(io->base + offset);
+ pr_debug("[%08x] => %08x [%08x]\n",
+ (u32)(unsigned long)(io->base + offset),
+ value, in_val);
+ }
+}
+
+u32 sde_hdmi_cec_reg_r(struct cec_io_data *io, u32 offset, bool debug)
+{
+ u32 value;
+
+ if (!io || !io->base) {
+ pr_err("invalid input\n");
+ return -EINVAL;
+ }
+
+ if (offset > io->len) {
+ pr_err("offset out of range\n");
+ return -EINVAL;
+ }
+
+ value = readl_relaxed(io->base + offset);
+ if (debug)
+ pr_debug("[%08x] <= %08x\n",
+ (u32)(unsigned long)(io->base + offset), value);
+
+ return value;
+}
+
+void sde_hdmi_cec_reg_dump(void __iomem *base, u32 length, const char *prefix,
+ bool debug)
+{
+ if (debug)
+ print_hex_dump(KERN_INFO, prefix, DUMP_PREFIX_OFFSET, 32, 4,
+ __io_virt(base), length, false);
+}
+
+static int sde_hdmi_cec_config_vreg(struct device *dev,
+ struct cec_vreg *in_vreg, int num_vreg, bool config)
+{
+ int i = 0, rc = 0;
+ struct cec_vreg *curr_vreg = NULL;
+ enum cec_vreg_type type;
+
+ if (!in_vreg || !num_vreg)
+ return rc;
+
+ if (config) {
+ for (i = 0; i < num_vreg; i++) {
+ curr_vreg = &in_vreg[i];
+ curr_vreg->vreg = regulator_get(dev,
+ curr_vreg->vreg_name);
+ rc = PTR_RET(curr_vreg->vreg);
+ if (rc) {
+ pr_err("%s get failed. rc=%d\n",
+ curr_vreg->vreg_name, rc);
+ curr_vreg->vreg = NULL;
+ goto vreg_get_fail;
+ }
+ type = (regulator_count_voltages(curr_vreg->vreg) > 0)
+ ? CEC_REG_LDO : CEC_REG_VS;
+ if (type == CEC_REG_LDO) {
+ rc = regulator_set_voltage(
+ curr_vreg->vreg,
+ curr_vreg->min_voltage,
+ curr_vreg->max_voltage);
+ if (rc < 0) {
+ pr_err("%s set vltg fail\n",
+ curr_vreg->vreg_name);
+ goto vreg_set_voltage_fail;
+ }
+ }
+ }
+ } else {
+ for (i = num_vreg-1; i >= 0; i--) {
+ curr_vreg = &in_vreg[i];
+ if (curr_vreg->vreg) {
+ type = (regulator_count_voltages(
+ curr_vreg->vreg) > 0)
+ ? CEC_REG_LDO : CEC_REG_VS;
+ if (type == CEC_REG_LDO) {
+ regulator_set_voltage(curr_vreg->vreg,
+ 0, curr_vreg->max_voltage);
+ }
+ regulator_put(curr_vreg->vreg);
+ curr_vreg->vreg = NULL;
+ }
+ }
+ }
+ return 0;
+
+vreg_unconfig:
+if (type == CEC_REG_LDO)
+ regulator_set_load(curr_vreg->vreg, 0);
+
+vreg_set_voltage_fail:
+ regulator_put(curr_vreg->vreg);
+ curr_vreg->vreg = NULL;
+
+vreg_get_fail:
+ for (i--; i >= 0; i--) {
+ curr_vreg = &in_vreg[i];
+ type = (regulator_count_voltages(curr_vreg->vreg) > 0)
+ ? CEC_REG_LDO : CEC_REG_VS;
+ goto vreg_unconfig;
+ }
+ return rc;
+}
+
+static int sde_hdmi_cec_enable_vreg(struct cec_hw_resource *hw, int enable)
+{
+ int i = 0, rc = 0;
+ bool need_sleep;
+ struct cec_vreg *in_vreg = hw->vreg_config;
+ int num_vreg = hw->num_vreg;
+
+ if (enable) {
+ for (i = 0; i < num_vreg; i++) {
+ rc = PTR_RET(in_vreg[i].vreg);
+ if (rc) {
+ pr_err("%s regulator error. rc=%d\n",
+ in_vreg[i].vreg_name, rc);
+ goto vreg_set_opt_mode_fail;
+ }
+ need_sleep = !regulator_is_enabled(in_vreg[i].vreg);
+ if (in_vreg[i].pre_on_sleep && need_sleep)
+ usleep_range(in_vreg[i].pre_on_sleep * 1000,
+ in_vreg[i].pre_on_sleep * 1000);
+ rc = regulator_set_load(in_vreg[i].vreg,
+ in_vreg[i].enable_load);
+ if (rc < 0) {
+ pr_err("%s set opt m fail\n",
+ in_vreg[i].vreg_name);
+ goto vreg_set_opt_mode_fail;
+ }
+ rc = regulator_enable(in_vreg[i].vreg);
+ if (in_vreg[i].post_on_sleep && need_sleep)
+ usleep_range(in_vreg[i].post_on_sleep * 1000,
+ in_vreg[i].post_on_sleep * 1000);
+ if (rc < 0) {
+ pr_err("%s enable failed\n",
+ in_vreg[i].vreg_name);
+ goto disable_vreg;
+ }
+ }
+ } else {
+ for (i = num_vreg-1; i >= 0; i--) {
+ if (in_vreg[i].pre_off_sleep)
+ usleep_range(in_vreg[i].pre_off_sleep * 1000,
+ in_vreg[i].pre_off_sleep * 1000);
+ regulator_set_load(in_vreg[i].vreg,
+ in_vreg[i].disable_load);
+ regulator_disable(in_vreg[i].vreg);
+ if (in_vreg[i].post_off_sleep)
+ usleep_range(in_vreg[i].post_off_sleep * 1000,
+ in_vreg[i].post_off_sleep * 1000);
+ }
+ }
+ return rc;
+
+disable_vreg:
+ regulator_set_load(in_vreg[i].vreg, in_vreg[i].disable_load);
+
+vreg_set_opt_mode_fail:
+ for (i--; i >= 0; i--) {
+ if (in_vreg[i].pre_off_sleep)
+ usleep_range(in_vreg[i].pre_off_sleep * 1000,
+ in_vreg[i].pre_off_sleep * 1000);
+ regulator_set_load(in_vreg[i].vreg,
+ in_vreg[i].disable_load);
+ regulator_disable(in_vreg[i].vreg);
+ if (in_vreg[i].post_off_sleep)
+ usleep_range(in_vreg[i].post_off_sleep * 1000,
+ in_vreg[i].post_off_sleep * 1000);
+ }
+
+ return rc;
+}
+
+static void sde_hdmi_cec_put_clk(struct cec_clk *clk_arry, int num_clk)
+{
+ int i;
+
+ for (i = num_clk - 1; i >= 0; i--) {
+ if (clk_arry[i].clk)
+ clk_put(clk_arry[i].clk);
+ clk_arry[i].clk = NULL;
+ }
+}
+
+static int sde_hdmi_cec_get_clk(struct device *dev,
+ struct cec_clk *clk_arry, int num_clk)
+{
+ int i, rc = 0;
+
+ for (i = 0; i < num_clk; i++) {
+ clk_arry[i].clk = clk_get(dev, clk_arry[i].clk_name);
+ rc = PTR_RET(clk_arry[i].clk);
+ if (rc) {
+ pr_err("'%s' get failed. rc=%d\n",
+ clk_arry[i].clk_name, rc);
+ goto error;
+ }
+ }
+
+ return rc;
+
+error:
+ sde_hdmi_cec_put_clk(clk_arry, num_clk);
+
+ return rc;
+}
+
+static int sde_hdmi_cec_enable_clk(struct cec_hw_resource *hw, int enable)
+{
+ int i, rc = 0;
+ struct cec_clk *clk_arry = hw->clk_config;
+ int num_clk = hw->num_clk;
+
+ if (enable) {
+ for (i = 0; i < num_clk; i++) {
+ pr_debug("enable %s\n", clk_arry[i].clk_name);
+ if (clk_arry[i].clk) {
+ rc = clk_prepare_enable(clk_arry[i].clk);
+ if (rc)
+ pr_err("%s enable fail. rc=%d\n",
+ clk_arry[i].clk_name, rc);
+ } else {
+ pr_err("%s is not available\n",
+ clk_arry[i].clk_name);
+ rc = -EPERM;
+ }
+ }
+ } else {
+ for (i = num_clk - 1; i >= 0; i--) {
+ pr_debug("disable %s\n", clk_arry[i].clk_name);
+
+ if (clk_arry[i].clk)
+ clk_disable_unprepare(clk_arry[i].clk);
+ else
+ pr_err("%s is not available\n",
+ clk_arry[i].clk_name);
+ }
+ }
+
+ return rc;
+}
+
+static int sde_hdmi_cec_pinctrl_enable(struct cec_hw_resource *hw,
+ bool enable)
+{
+ struct pinctrl_state *pin_state = NULL;
+ int rc = 0;
+
+ if (!hw) {
+ pr_err("invalid input param hw:%pK\n", hw);
+ return -EINVAL;
+ }
+
+ pr_debug("set cec pinctrl state %d\n", enable);
+
+ pin_state = enable ? hw->pin_res.state_active : hw->pin_res.state_sleep;
+
+ if (!IS_ERR_OR_NULL(hw->pin_res.pinctrl))
+ rc = pinctrl_select_state(hw->pin_res.pinctrl,
+ pin_state);
+ else
+ pr_err("pinstate not found\n");
+
+ return rc;
+}
+
+static void sde_hdmi_cec_put_dt_clock(struct platform_device *pdev,
+ struct cec_hw_resource *hw)
+{
+ if (!pdev || !hw) {
+ pr_err("invalid input param pdev:%pK hw:%pK\n", pdev, hw);
+ return;
+ }
+
+ if (hw->clk_config) {
+ sde_hdmi_cec_put_clk(hw->clk_config, hw->num_clk);
+ devm_kfree(&pdev->dev, hw->clk_config);
+ hw->clk_config = NULL;
+ }
+ hw->num_clk = 0;
+
+ pr_debug("put dt clock\n");
+}
+
+static int sde_hdmi_cec_get_dt_clock(struct platform_device *pdev,
+ struct cec_hw_resource *hw)
+{
+ int i = 0;
+ int num_clk = 0;
+ const char *clock_name;
+ int rc = 0;
+
+ if (!pdev || !hw) {
+ pr_err("invalid input param pdev:%pK hw:%pK\n", pdev, hw);
+ return -EINVAL;
+ }
+
+ hw->num_clk = 0;
+ num_clk = of_property_count_strings(pdev->dev.of_node, "clock-names");
+ if (num_clk <= 0) {
+ pr_debug("clocks are not defined\n");
+ return 0;
+ }
+
+ hw->num_clk = num_clk;
+ hw->clk_config = devm_kzalloc(&pdev->dev,
+ sizeof(struct cec_clk) * num_clk, GFP_KERNEL);
+ if (!hw->clk_config) {
+ hw->num_clk = 0;
+ return -ENOMEM;
+ }
+
+ for (i = 0; i < num_clk; i++) {
+ of_property_read_string_index(pdev->dev.of_node, "clock-names",
+ i, &clock_name);
+ strlcpy(hw->clk_config[i].clk_name, clock_name,
+ sizeof(hw->clk_config[i].clk_name));
+ }
+
+ rc = sde_hdmi_cec_get_clk(&pdev->dev, hw->clk_config, hw->num_clk);
+ if (rc) {
+ sde_hdmi_cec_put_dt_clock(pdev, hw);
+ return rc;
+ }
+
+ pr_debug("get dt clock\n");
+
+ return 0;
+}
+
+static int sde_hdmi_cec_get_dt_supply(struct platform_device *pdev,
+ struct cec_hw_resource *hw)
+{
+ int i = 0, rc = 0;
+ u32 tmp = 0;
+ struct device_node *of_node = NULL, *supply_root_node = NULL;
+ struct device_node *supply_node = NULL;
+
+ if (!pdev || !hw) {
+ pr_err("invalid input param pdev:%pK hw:%pK\n", pdev, hw);
+ return -EINVAL;
+ }
+
+ of_node = pdev->dev.of_node;
+
+ hw->num_vreg = 0;
+ supply_root_node = of_get_child_by_name(of_node,
+ "qcom,platform-supply-entries");
+ if (!supply_root_node) {
+ pr_debug("no supply entry present\n");
+ return rc;
+ }
+
+ hw->num_vreg = of_get_available_child_count(supply_root_node);
+ if (hw->num_vreg == 0) {
+ pr_debug("no vreg present\n");
+ return rc;
+ }
+
+ pr_debug("vreg found. count=%d\n", hw->num_vreg);
+ hw->vreg_config = devm_kzalloc(&pdev->dev, sizeof(struct cec_vreg) *
+ hw->num_vreg, GFP_KERNEL);
+ if (!hw->vreg_config) {
+ rc = -ENOMEM;
+ return rc;
+ }
+
+ for_each_available_child_of_node(supply_root_node, supply_node) {
+ const char *st = NULL;
+
+ rc = of_property_read_string(supply_node,
+ "qcom,supply-name", &st);
+ if (rc) {
+ pr_err("error reading name. rc=%d\n", rc);
+ goto error;
+ }
+
+ strlcpy(hw->vreg_config[i].vreg_name, st,
+ sizeof(hw->vreg_config[i].vreg_name));
+
+ rc = of_property_read_u32(supply_node,
+ "qcom,supply-min-voltage", &tmp);
+ if (rc) {
+ pr_err("error reading min volt. rc=%d\n", rc);
+ goto error;
+ }
+ hw->vreg_config[i].min_voltage = tmp;
+
+ rc = of_property_read_u32(supply_node,
+ "qcom,supply-max-voltage", &tmp);
+ if (rc) {
+ pr_err("error reading max volt. rc=%d\n", rc);
+ goto error;
+ }
+ hw->vreg_config[i].max_voltage = tmp;
+
+ rc = of_property_read_u32(supply_node,
+ "qcom,supply-enable-load", &tmp);
+ if (rc) {
+ pr_err("error reading enable load. rc=%d\n", rc);
+ goto error;
+ }
+ hw->vreg_config[i].enable_load = tmp;
+
+ rc = of_property_read_u32(supply_node,
+ "qcom,supply-disable-load", &tmp);
+ if (rc) {
+ pr_err("error reading disable load. rc=%d\n", rc);
+ goto error;
+ }
+ hw->vreg_config[i].disable_load = tmp;
+
+ rc = of_property_read_u32(supply_node,
+ "qcom,supply-pre-on-sleep", &tmp);
+ if (rc)
+ pr_debug("no supply pre sleep value. rc=%d\n", rc);
+
+ hw->vreg_config[i].pre_on_sleep = (!rc ? tmp : 0);
+
+ rc = of_property_read_u32(supply_node,
+ "qcom,supply-pre-off-sleep", &tmp);
+ if (rc)
+ pr_debug("no supply pre sleep value. rc=%d\n", rc);
+
+ hw->vreg_config[i].pre_off_sleep = (!rc ? tmp : 0);
+
+ rc = of_property_read_u32(supply_node,
+ "qcom,supply-post-on-sleep", &tmp);
+ if (rc)
+ pr_debug("no supply post sleep value. rc=%d\n", rc);
+
+ hw->vreg_config[i].post_on_sleep = (!rc ? tmp : 0);
+
+ rc = of_property_read_u32(supply_node,
+ "qcom,supply-post-off-sleep", &tmp);
+ if (rc)
+ pr_debug("no supply post sleep value. rc=%d\n", rc);
+
+ hw->vreg_config[i].post_off_sleep = (!rc ? tmp : 0);
+
+ pr_debug("%s min=%d, max=%d, enable=%d, disable=%d, preonsleep=%d, postonsleep=%d, preoffsleep=%d, postoffsleep=%d\n",
+ hw->vreg_config[i].vreg_name,
+ hw->vreg_config[i].min_voltage,
+ hw->vreg_config[i].max_voltage,
+ hw->vreg_config[i].enable_load,
+ hw->vreg_config[i].disable_load,
+ hw->vreg_config[i].pre_on_sleep,
+ hw->vreg_config[i].post_on_sleep,
+ hw->vreg_config[i].pre_off_sleep,
+ hw->vreg_config[i].post_off_sleep);
+ ++i;
+
+ rc = 0;
+ }
+
+ rc = sde_hdmi_cec_config_vreg(&pdev->dev,
+ hw->vreg_config, hw->num_vreg, true);
+ if (rc)
+ goto error;
+
+ pr_debug("get dt supply\n");
+
+ return rc;
+
+error:
+ if (hw->vreg_config) {
+ devm_kfree(&pdev->dev, hw->vreg_config);
+ hw->vreg_config = NULL;
+ hw->num_vreg = 0;
+ }
+
+ return rc;
+}
+
+static void sde_hdmi_cec_put_dt_supply(struct platform_device *pdev,
+ struct cec_hw_resource *hw)
+{
+ if (!pdev || !hw) {
+ pr_err("invalid input param pdev:%pK hw:%pK\n", pdev, hw);
+ return;
+ }
+
+ sde_hdmi_cec_config_vreg(&pdev->dev,
+ hw->vreg_config, hw->num_vreg, false);
+
+ if (hw->vreg_config) {
+ devm_kfree(&pdev->dev, hw->vreg_config);
+ hw->vreg_config = NULL;
+ }
+ hw->num_vreg = 0;
+
+ pr_debug("put dt supply\n");
+}
+
+static int sde_hdmi_cec_get_dt_pinres(struct platform_device *pdev,
+ struct cec_hw_resource *hw)
+{
+ if (!pdev || !hw) {
+ pr_err("invalid input param pdev:%pK hw:%pK\n", pdev, hw);
+ return -EINVAL;
+ }
+
+ hw->pin_res.pinctrl = devm_pinctrl_get(&pdev->dev);
+ if (IS_ERR_OR_NULL(hw->pin_res.pinctrl)) {
+ pr_err("failed to get pinctrl\n");
+ return PTR_ERR(hw->pin_res.pinctrl);
+ }
+
+ hw->pin_res.state_active =
+ pinctrl_lookup_state(hw->pin_res.pinctrl, "cec_active");
+ if (IS_ERR_OR_NULL(hw->pin_res.state_active))
+ pr_debug("cannot get active pinstate\n");
+
+ hw->pin_res.state_sleep =
+ pinctrl_lookup_state(hw->pin_res.pinctrl, "cec_sleep");
+ if (IS_ERR_OR_NULL(hw->pin_res.state_sleep))
+ pr_debug("cannot get sleep pinstate\n");
+
+ pr_debug("get dt pinres data\n");
+
+ return 0;
+}
+
+static void sde_hdmi_cec_put_dt_pinres(struct platform_device *pdev,
+ struct cec_hw_resource *hw)
+{
+ if (!pdev || !hw) {
+ pr_err("invalid input param pdev:%pK hw:%pK\n", pdev, hw);
+ return;
+ }
+
+ if (!IS_ERR_OR_NULL(hw->pin_res.pinctrl))
+ devm_pinctrl_put(hw->pin_res.pinctrl);
+}
+
+static void sde_hdmi_cec_deinit_power(struct platform_device *pdev,
+ struct cec_hw_resource *hw)
+{
+ if (!pdev || !hw) {
+ pr_err("invalid input param pdev:%pK hw:%pK\n", pdev, hw);
+ return;
+ }
+
+ sde_hdmi_cec_put_dt_supply(pdev, hw);
+ sde_hdmi_cec_put_dt_clock(pdev, hw);
+ sde_hdmi_cec_put_dt_pinres(pdev, hw);
+
+ pr_debug("put dt power data\n");
+}
+
+static int sde_hdmi_cec_init_power(struct platform_device *pdev,
+ struct cec_hw_resource *hw)
+{
+ int rc = 0;
+
+ if (!pdev || !hw) {
+ pr_err("invalid input param pdev:%pK hw:%pK\n", pdev, hw);
+ return -EINVAL;
+ }
+
+ /* VREG */
+ rc = sde_hdmi_cec_get_dt_supply(pdev, hw);
+ if (rc) {
+ pr_err("get_dt_supply failed. rc=%d\n", rc);
+ goto error;
+ }
+
+ /* Clock */
+ rc = sde_hdmi_cec_get_dt_clock(pdev, hw);
+ if (rc) {
+ pr_err("get_dt_clock failed. rc=%d\n", rc);
+ goto error;
+ }
+
+ /* Pinctrl */
+ rc = sde_hdmi_cec_get_dt_pinres(pdev, hw);
+ if (rc) {
+ pr_err("get_dt_pinres failed. rc=%d\n", rc);
+ goto error;
+ }
+
+ pr_debug("get dt power data\n");
+
+ return rc;
+
+error:
+ sde_hdmi_cec_deinit_power(pdev, hw);
+ return rc;
+}
+
+static int sde_hdmi_cec_init_io(struct platform_device *pdev,
+ struct cec_hw_resource *hw)
+{
+ struct resource *res = NULL;
+ struct cec_io_data *io_data = NULL;
+ const char *reg_name;
+
+ if (!pdev || !hw) {
+ pr_err("invalid input\n");
+ return -EINVAL;
+ }
+
+ if (of_property_read_string(pdev->dev.of_node, "reg-names",
+ &reg_name)) {
+ pr_err("cec reg not defined\n");
+ return -ENODEV;
+ }
+
+ res = platform_get_resource_byname(pdev, IORESOURCE_MEM, reg_name);
+ if (!res) {
+ pr_err("%s get_res_byname failed\n", reg_name);
+ return -ENODEV;
+ }
+
+ io_data = &hw->io_res;
+ io_data->len = (u32)resource_size(res);
+ io_data->base = ioremap(res->start, io_data->len);
+ if (!io_data->base) {
+ pr_err("%s ioremap failed\n", reg_name);
+ return -EIO;
+ }
+
+ return 0;
+}
+
+static void sde_hdmi_cec_deinit_io(struct platform_device *pdev,
+ struct cec_hw_resource *hw)
+{
+ struct cec_io_data *io_data = NULL;
+
+ if (!pdev || !hw) {
+ pr_err("invalid input\n");
+ return;
+ }
+
+ io_data = &hw->io_res;
+
+ if (io_data->base) {
+ iounmap(io_data->base);
+ io_data->base = NULL;
+ }
+ io_data->len = 0;
+}
+
+int sde_hdmi_cec_init_resource(struct platform_device *pdev,
+ struct cec_hw_resource *hw)
+{
+ int rc = 0;
+
+ /* power */
+ rc = sde_hdmi_cec_init_power(pdev, hw);
+ if (rc)
+ return rc;
+
+ /* io */
+ rc = sde_hdmi_cec_init_io(pdev, hw);
+ if (rc)
+ goto io_error;
+
+ pr_debug("cec init resource\n");
+
+ return rc;
+
+io_error:
+ sde_hdmi_cec_deinit_power(pdev, hw);
+ return rc;
+}
+
+void sde_hdmi_cec_deinit_resource(struct platform_device *pdev,
+ struct cec_hw_resource *hw)
+{
+ sde_hdmi_cec_deinit_power(pdev, hw);
+ sde_hdmi_cec_deinit_io(pdev, hw);
+
+ pr_debug("cec deinit resource\n");
+}
+
+int sde_hdmi_cec_enable_power(struct cec_hw_resource *hw, bool enable)
+{
+ int rc = 0;
+
+ rc = sde_hdmi_cec_enable_vreg(hw, enable);
+ if (rc)
+ return rc;
+
+ rc = sde_hdmi_cec_pinctrl_enable(hw, enable);
+ if (rc)
+ return rc;
+
+ rc = sde_hdmi_cec_enable_clk(hw, enable);
+ if (rc)
+ return rc;
+
+ pr_debug("cec power enable = %d\n", enable);
+
+ return rc;
+}
diff --git a/drivers/media/platform/msm/sde/cec/sde_hdmi_cec_util.h b/drivers/media/platform/msm/sde/cec/sde_hdmi_cec_util.h
new file mode 100644
index 000000000000..f92c43ea3288
--- /dev/null
+++ b/drivers/media/platform/msm/sde/cec/sde_hdmi_cec_util.h
@@ -0,0 +1,93 @@
+/* Copyright (c) 2012, 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.
+ */
+
+#ifndef __SDE_HDMI_CEC_UTIL_H__
+#define __SDE_HDMI_CEC_UTIL_H__
+
+#include <linux/gpio.h>
+#include <linux/platform_device.h>
+#include <linux/regulator/consumer.h>
+#include <linux/pinctrl/consumer.h>
+#include <linux/types.h>
+
+#ifdef DEBUG
+#define CEC_REG_WRITE(hw, off, val) \
+ sde_hdmi_cec_reg_w(&(hw)->io_res, (off), (val), true)
+#define CEC_REG_READ(hw, off) \
+ sde_hdmi_cec_reg_r(&(hw)->io_res, (off), true)
+#else
+#define CEC_REG_WRITE(hw, off, val) \
+ sde_hdmi_cec_reg_w(&(hw)->io_res, (off), (val), false)
+#define CEC_REG_READ(hw, off) \
+ sde_hdmi_cec_reg_r(&(hw)->io_res, (off), false)
+#endif
+
+struct cec_io_data {
+ u32 len;
+ void __iomem *base;
+};
+
+enum cec_vreg_type {
+ CEC_REG_LDO,
+ CEC_REG_VS,
+};
+
+struct cec_vreg {
+ struct regulator *vreg; /* vreg handle */
+ char vreg_name[32];
+ int min_voltage;
+ int max_voltage;
+ int enable_load;
+ int disable_load;
+ int pre_on_sleep;
+ int post_on_sleep;
+ int pre_off_sleep;
+ int post_off_sleep;
+};
+
+struct cec_clk {
+ struct clk *clk; /* clk handle */
+ char clk_name[32];
+};
+
+struct cec_pin_res {
+ struct pinctrl *pinctrl;
+ struct pinctrl_state *state_active;
+ struct pinctrl_state *state_sleep;
+};
+
+struct cec_hw_resource {
+ /* power */
+ unsigned num_vreg;
+ struct cec_vreg *vreg_config;
+ unsigned num_clk;
+ struct cec_clk *clk_config;
+ struct cec_pin_res pin_res;
+
+ /* io */
+ struct cec_io_data io_res;
+};
+
+void sde_hdmi_cec_reg_w(struct cec_io_data *io,
+ u32 offset, u32 value, bool debug);
+u32 sde_hdmi_cec_reg_r(struct cec_io_data *io, u32 offset, bool debug);
+void sde_hdmi_cec_reg_dump(void __iomem *base, u32 length, const char *prefix,
+ bool debug);
+
+int sde_hdmi_cec_init_resource(struct platform_device *pdev,
+ struct cec_hw_resource *hw);
+void sde_hdmi_cec_deinit_resource(struct platform_device *pdev,
+ struct cec_hw_resource *hw);
+int sde_hdmi_cec_enable_power(struct cec_hw_resource *hw, bool enable);
+
+#endif /* __SDE_HDMI_CEC_UTIL_H__ */
+
diff --git a/drivers/media/platform/msm/sde/rotator/sde_rotator_r1.c b/drivers/media/platform/msm/sde/rotator/sde_rotator_r1.c
index 5b574ed9fabc..9e3d7d806a0c 100644
--- a/drivers/media/platform/msm/sde/rotator/sde_rotator_r1.c
+++ b/drivers/media/platform/msm/sde/rotator/sde_rotator_r1.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
@@ -145,7 +145,7 @@ static struct sde_mdp_hw_resource *sde_rotator_hw_alloc(
struct sde_mdp_hw_resource *mdp_hw;
struct sde_rot_data_type *mdata = sde_rot_get_mdata();
int pipe_ndx, offset = ctl_id;
- int ret;
+ int ret = 0;
mdp_hw = devm_kzalloc(&mgr->pdev->dev,
sizeof(struct sde_mdp_hw_resource), GFP_KERNEL);
diff --git a/drivers/media/platform/msm/sde/rotator/sde_rotator_smmu.c b/drivers/media/platform/msm/sde/rotator/sde_rotator_smmu.c
index 58cb160f118e..9273c0e95230 100644
--- a/drivers/media/platform/msm/sde/rotator/sde_rotator_smmu.c
+++ b/drivers/media/platform/msm/sde/rotator/sde_rotator_smmu.c
@@ -486,11 +486,8 @@ int sde_smmu_secure_ctrl(int enable)
mdata->iommu_attached = true;
} else {
rc = sde_smmu_detach(mdata);
- /*
- * keep iommu_attached equal to true,
- * so that driver does not attemp to attach
- * while in secure state
- */
+ if (!rc)
+ mdata->iommu_attached = false;
}
mutex_unlock(&sde_smmu_ref_cnt_lock);
diff --git a/drivers/media/platform/msm/vidc/msm_vdec.c b/drivers/media/platform/msm/vidc/msm_vdec.c
index 953780e3c220..8ac84ece2c2a 100644
--- a/drivers/media/platform/msm/vidc/msm_vdec.c
+++ b/drivers/media/platform/msm/vidc/msm_vdec.c
@@ -872,7 +872,7 @@ int msm_vdec_prepare_buf(struct msm_vidc_inst *inst,
dprintk(VIDC_ERR,
"Core %pK in bad state, ignoring prepare buf\n",
inst->core);
- goto exit;
+ return -EINVAL;
}
switch (b->type) {
@@ -925,7 +925,7 @@ int msm_vdec_prepare_buf(struct msm_vidc_inst *inst,
dprintk(VIDC_ERR, "Buffer type not recognized: %d\n", b->type);
break;
}
-exit:
+
return rc;
}
@@ -1767,6 +1767,7 @@ static int msm_vdec_start_streaming(struct vb2_queue *q, unsigned int count)
struct msm_vidc_inst *inst;
int rc = 0;
struct hfi_device *hdev;
+ struct vb2_buffer *vb;
struct vb2_buf_entry *temp, *next;
if (!q || !q->drv_priv) {
dprintk(VIDC_ERR, "Invalid input, q = %pK\n", q);
@@ -1777,6 +1778,12 @@ static int msm_vdec_start_streaming(struct vb2_queue *q, unsigned int count)
dprintk(VIDC_ERR, "%s invalid parameters\n", __func__);
return -EINVAL;
}
+
+ if (inst->state == MSM_VIDC_CORE_INVALID ||
+ inst->core->state == VIDC_CORE_INVALID ||
+ inst->core->state == VIDC_CORE_UNINIT)
+ return -EINVAL;
+
hdev = inst->core->device;
dprintk(VIDC_DBG, "Streamon called on: %d capability for inst: %pK\n",
q->type, inst);
@@ -1791,8 +1798,7 @@ static int msm_vdec_start_streaming(struct vb2_queue *q, unsigned int count)
break;
default:
dprintk(VIDC_ERR, "Queue type is not supported: %d\n", q->type);
- rc = -EINVAL;
- goto stream_start_failed;
+ return -EINVAL;
}
if (rc) {
dprintk(VIDC_ERR,
@@ -1811,12 +1817,15 @@ static int msm_vdec_start_streaming(struct vb2_queue *q, unsigned int count)
stream_start_failed:
if (rc) {
+ list_for_each_entry(vb, &q->queued_list, queued_entry) {
+ if (vb->type == q->type &&
+ vb->state == VB2_BUF_STATE_ACTIVE)
+ vb2_buffer_done(vb, VB2_BUF_STATE_QUEUED);
+ }
mutex_lock(&inst->pendingq.lock);
- list_for_each_entry_safe(temp, next, &inst->pendingq.list,
- list) {
+ list_for_each_entry_safe(temp, next,
+ &inst->pendingq.list, list) {
if (temp->vb->type == q->type) {
- vb2_buffer_done(temp->vb,
- VB2_BUF_STATE_QUEUED);
list_del(&temp->list);
kfree(temp);
}
diff --git a/drivers/media/platform/msm/vidc/msm_venc.c b/drivers/media/platform/msm/vidc/msm_venc.c
index 30726354164b..cdf91dd80ed3 100644
--- a/drivers/media/platform/msm/vidc/msm_venc.c
+++ b/drivers/media/platform/msm/vidc/msm_venc.c
@@ -54,12 +54,12 @@
* 3x3 transformation matrix coefficients in s4.9 fixed point format
*/
static u32 vpe_csc_601_to_709_matrix_coeff[HAL_MAX_MATRIX_COEFFS] = {
- 470, 8170, 8148, 0, 490, 50, 0, 34, 483
+ 440, 8140, 8098, 0, 460, 52, 0, 34, 463
};
/* offset coefficients in s9 fixed point format */
static u32 vpe_csc_601_to_709_bias_coeff[HAL_MAX_BIAS_COEFFS] = {
- 34, 0, 4
+ 53, 0, 4
};
/* clamping value for Y/U/V([min,max] for Y/U/V) */
@@ -1897,12 +1897,20 @@ static int msm_venc_start_streaming(struct vb2_queue *q, unsigned int count)
{
struct msm_vidc_inst *inst;
int rc = 0;
+ struct vb2_buffer *vb;
struct vb2_buf_entry *temp, *next;
+
if (!q || !q->drv_priv) {
dprintk(VIDC_ERR, "Invalid input, q = %pK\n", q);
return -EINVAL;
}
inst = q->drv_priv;
+
+ if (inst->state == MSM_VIDC_CORE_INVALID ||
+ inst->core->state == VIDC_CORE_INVALID ||
+ inst->core->state == VIDC_CORE_UNINIT)
+ return -EINVAL;
+
dprintk(VIDC_DBG, "Streamon called on: %d capability for inst: %pK\n",
q->type, inst);
switch (q->type) {
@@ -1916,8 +1924,7 @@ static int msm_venc_start_streaming(struct vb2_queue *q, unsigned int count)
break;
default:
dprintk(VIDC_ERR, "Queue type is not supported: %d\n", q->type);
- rc = -EINVAL;
- goto stream_start_failed;
+ return -EINVAL;
}
if (rc) {
dprintk(VIDC_ERR,
@@ -1936,12 +1943,15 @@ static int msm_venc_start_streaming(struct vb2_queue *q, unsigned int count)
stream_start_failed:
if (rc) {
+ list_for_each_entry(vb, &q->queued_list, queued_entry) {
+ if (vb->type == q->type &&
+ vb->state == VB2_BUF_STATE_ACTIVE)
+ vb2_buffer_done(vb, VB2_BUF_STATE_QUEUED);
+ }
mutex_lock(&inst->pendingq.lock);
- list_for_each_entry_safe(temp, next, &inst->pendingq.list,
- list) {
+ list_for_each_entry_safe(temp, next,
+ &inst->pendingq.list, list) {
if (temp->vb->type == q->type) {
- vb2_buffer_done(temp->vb,
- VB2_BUF_STATE_QUEUED);
list_del(&temp->list);
kfree(temp);
}
@@ -4425,7 +4435,7 @@ int msm_venc_prepare_buf(struct msm_vidc_inst *inst,
dprintk(VIDC_ERR,
"Core %pK in bad state, ignoring prepare buf\n",
inst->core);
- goto exit;
+ return -EINVAL;
}
switch (b->type) {
@@ -4473,7 +4483,7 @@ int msm_venc_prepare_buf(struct msm_vidc_inst *inst,
"Buffer type not recognized: %d\n", b->type);
break;
}
-exit:
+
return rc;
}
diff --git a/drivers/media/platform/msm/vidc/msm_vidc.c b/drivers/media/platform/msm/vidc/msm_vidc.c
index 1ff2ca4cb91f..f09c28fed6d2 100644
--- a/drivers/media/platform/msm/vidc/msm_vidc.c
+++ b/drivers/media/platform/msm/vidc/msm_vidc.c
@@ -1362,7 +1362,6 @@ static void cleanup_instance(struct msm_vidc_inst *inst)
int msm_vidc_destroy(struct msm_vidc_inst *inst)
{
struct msm_vidc_core *core;
- int i = 0;
if (!inst || !inst->core)
return -EINVAL;
@@ -1386,9 +1385,6 @@ int msm_vidc_destroy(struct msm_vidc_inst *inst)
v4l2_fh_del(&inst->event_handler);
v4l2_fh_exit(&inst->event_handler);
- for (i = 0; i < MAX_PORT_NUM; i++)
- vb2_queue_release(&inst->bufq[i].vb2_bufq);
-
mutex_destroy(&inst->sync_lock);
mutex_destroy(&inst->bufq[CAPTURE_PORT].lock);
mutex_destroy(&inst->bufq[OUTPUT_PORT].lock);
@@ -1412,7 +1408,7 @@ int msm_vidc_close(void *instance)
struct msm_vidc_inst *inst = instance;
struct buffer_info *bi, *dummy;
- int rc = 0;
+ int rc = 0, i = 0;
if (!inst || !inst->core)
return -EINVAL;
@@ -1449,6 +1445,12 @@ int msm_vidc_close(void *instance)
msm_comm_session_clean(inst);
msm_smem_delete_client(inst->mem_client);
+ for (i = 0; i < MAX_PORT_NUM; i++) {
+ mutex_lock(&inst->bufq[i].lock);
+ vb2_queue_release(&inst->bufq[i].vb2_bufq);
+ mutex_unlock(&inst->bufq[i].lock);
+ }
+
kref_put(&inst->kref, close_helper);
return 0;
}
diff --git a/drivers/media/platform/msm/vidc/msm_vidc_debug.c b/drivers/media/platform/msm/vidc/msm_vidc_debug.c
index a9b367d6fe93..885e61f8bf01 100644
--- a/drivers/media/platform/msm/vidc/msm_vidc_debug.c
+++ b/drivers/media/platform/msm/vidc/msm_vidc_debug.c
@@ -12,6 +12,7 @@
*/
#define CREATE_TRACE_POINTS
+#define MAX_SSR_STRING_LEN 10
#include "msm_vidc_debug.h"
#include "vidc_hfi_api.h"
@@ -136,17 +137,33 @@ static int trigger_ssr_open(struct inode *inode, struct file *file)
static ssize_t trigger_ssr_write(struct file *filp, const char __user *buf,
size_t count, loff_t *ppos) {
- u32 ssr_trigger_val;
- int rc;
+ unsigned long ssr_trigger_val = 0;
+ int rc = 0;
struct msm_vidc_core *core = filp->private_data;
- rc = sscanf(buf, "%d", &ssr_trigger_val);
- if (rc < 0) {
+ size_t size = MAX_SSR_STRING_LEN;
+ char kbuf[MAX_SSR_STRING_LEN + 1] = {0};
+
+ if (!count)
+ goto exit;
+
+ if (count < size)
+ size = count;
+
+ if (copy_from_user(kbuf, buf, size)) {
+ dprintk(VIDC_WARN, "%s User memory fault\n", __func__);
+ rc = -EFAULT;
+ goto exit;
+ }
+
+ rc = kstrtoul(kbuf, 0, &ssr_trigger_val);
+ if (rc) {
dprintk(VIDC_WARN, "returning error err %d\n", rc);
rc = -EINVAL;
} else {
msm_vidc_trigger_ssr(core, ssr_trigger_val);
rc = count;
}
+exit:
return rc;
}
diff --git a/drivers/media/platform/msm/vidc/msm_vidc_res_parse.c b/drivers/media/platform/msm/vidc/msm_vidc_res_parse.c
index 4cc977e568ee..59783dc87e5b 100644
--- a/drivers/media/platform/msm/vidc/msm_vidc_res_parse.c
+++ b/drivers/media/platform/msm/vidc/msm_vidc_res_parse.c
@@ -1137,8 +1137,11 @@ int read_platform_resources_from_dt(
"qcom,max-secure-instances",
&res->max_secure_inst_count);
- res->cx_ipeak_context = cx_ipeak_register(pdev->dev.of_node,
- "qcom,cx-ipeak-data");
+ if (of_find_property(pdev->dev.of_node,
+ "qcom,cx-ipeak-data", NULL)) {
+ res->cx_ipeak_context = cx_ipeak_register(
+ pdev->dev.of_node, "qcom,cx-ipeak-data");
+ }
if (IS_ERR(res->cx_ipeak_context)) {
rc = PTR_ERR(res->cx_ipeak_context);
diff --git a/drivers/mfd/wcd9xxx-irq.c b/drivers/mfd/wcd9xxx-irq.c
index 856179b96f37..43c6b0651064 100644
--- a/drivers/mfd/wcd9xxx-irq.c
+++ b/drivers/mfd/wcd9xxx-irq.c
@@ -290,7 +290,7 @@ static irqreturn_t wcd9xxx_irq_thread(int irq, void *data)
static DEFINE_RATELIMIT_STATE(ratelimit, 5 * HZ, 1);
struct wcd9xxx_core_resource *wcd9xxx_res = data;
int num_irq_regs = wcd9xxx_res->num_irq_regs;
- u8 status[num_irq_regs], status1[num_irq_regs];
+ u8 status[4], status1[4] = {0}, unmask_status[4] = {0};
if (unlikely(wcd9xxx_lock_sleep(wcd9xxx_res) == false)) {
dev_err(wcd9xxx_res->dev, "Failed to hold suspend\n");
@@ -314,6 +314,23 @@ static irqreturn_t wcd9xxx_irq_thread(int irq, void *data)
"Failed to read interrupt status: %d\n", ret);
goto err_disable_irq;
}
+ /*
+ * If status is 0 return without clearing.
+ * status contains: HW status - masked interrupts
+ * status1 contains: unhandled interrupts - masked interrupts
+ * unmasked_status contains: unhandled interrupts
+ */
+ if (unlikely(!memcmp(status, status1, sizeof(status)))) {
+ pr_debug("%s: status is 0\n", __func__);
+ wcd9xxx_unlock_sleep(wcd9xxx_res);
+ return IRQ_HANDLED;
+ }
+
+ /*
+ * Copy status to unmask_status before masking, otherwise SW may miss
+ * to clear masked interrupt in corner case.
+ */
+ memcpy(unmask_status, status, sizeof(unmask_status));
/* Apply masking */
for (i = 0; i < num_irq_regs; i++)
@@ -337,6 +354,8 @@ static irqreturn_t wcd9xxx_irq_thread(int irq, void *data)
wcd9xxx_irq_dispatch(wcd9xxx_res, &irqdata);
status1[BIT_BYTE(irqdata.intr_num)] &=
~BYTE_BIT_MASK(irqdata.intr_num);
+ unmask_status[BIT_BYTE(irqdata.intr_num)] &=
+ ~BYTE_BIT_MASK(irqdata.intr_num);
}
}
@@ -358,12 +377,13 @@ static irqreturn_t wcd9xxx_irq_thread(int irq, void *data)
linebuf, sizeof(linebuf), false);
pr_warn("%s: status1 : %s\n", __func__, linebuf);
}
-
- memset(status, 0xff, num_irq_regs);
-
+ /*
+ * unmask_status contains unhandled interrupts, hence clear all
+ * unhandled interrupts.
+ */
ret = regmap_bulk_write(wcd9xxx_res->wcd_core_regmap,
wcd9xxx_res->intr_reg[WCD9XXX_INTR_CLEAR_BASE],
- status, num_irq_regs);
+ unmask_status, num_irq_regs);
if (wcd9xxx_get_intf_type() == WCD9XXX_INTERFACE_TYPE_I2C)
regmap_write(wcd9xxx_res->wcd_core_regmap,
wcd9xxx_res->intr_reg[WCD9XXX_INTR_CLR_COMMIT],
diff --git a/drivers/misc/qcom/qdsp6v2/audio_utils_aio.c b/drivers/misc/qcom/qdsp6v2/audio_utils_aio.c
index e3f23caac5b8..5419bd1655c1 100644
--- a/drivers/misc/qcom/qdsp6v2/audio_utils_aio.c
+++ b/drivers/misc/qcom/qdsp6v2/audio_utils_aio.c
@@ -140,7 +140,8 @@ static int audio_aio_ion_lookup_vaddr(struct q6audio_aio *audio, void *addr,
list) {
if (addr >= region_elt->vaddr &&
addr < region_elt->vaddr + region_elt->len &&
- addr + len <= region_elt->vaddr + region_elt->len)
+ addr + len <= region_elt->vaddr + region_elt->len &&
+ addr + len > addr)
pr_err("\t%s[%pK]:%pK, %ld --> %pK\n",
__func__, audio,
region_elt->vaddr,
diff --git a/drivers/misc/qseecom.c b/drivers/misc/qseecom.c
index 1c7cc917faa6..7d09f22d3bc6 100644
--- a/drivers/misc/qseecom.c
+++ b/drivers/misc/qseecom.c
@@ -1257,7 +1257,7 @@ static int qseecom_unregister_listener(struct qseecom_dev_handle *data)
atomic_read(&data->ioctl_count) <= 1)) {
pr_err("Interrupted from abort\n");
ret = -ERESTARTSYS;
- break;
+ return ret;
}
}
diff --git a/drivers/mmc/card/block.c b/drivers/mmc/card/block.c
index 69e51cc96303..29c57d13744e 100644
--- a/drivers/mmc/card/block.c
+++ b/drivers/mmc/card/block.c
@@ -1017,7 +1017,7 @@ static int mmc_blk_ioctl_rpmb_cmd(struct block_device *bdev,
{
struct mmc_blk_ioc_rpmb_data *idata;
struct mmc_blk_data *md;
- struct mmc_card *card;
+ struct mmc_card *card = NULL;
struct mmc_command cmd = {0};
struct mmc_data data = {0};
struct mmc_request mrq = {NULL};
diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c
index 63f7bf87843f..2cb0ea03a338 100644
--- a/drivers/mmc/core/core.c
+++ b/drivers/mmc/core/core.c
@@ -616,17 +616,39 @@ static int mmc_devfreq_create_freq_table(struct mmc_host *host)
host->card->clk_scaling_lowest,
host->card->clk_scaling_highest);
+ /*
+ * Create the frequency table and initialize it with default values.
+ * Initialize it with platform specific frequencies if the frequency
+ * table supplied by platform driver is present, otherwise initialize
+ * it with min and max frequencies supported by the card.
+ */
if (!clk_scaling->freq_table) {
- pr_debug("%s: no frequency table defined - setting default\n",
- mmc_hostname(host));
+ if (clk_scaling->pltfm_freq_table_sz)
+ clk_scaling->freq_table_sz =
+ clk_scaling->pltfm_freq_table_sz;
+ else
+ clk_scaling->freq_table_sz = 2;
+
clk_scaling->freq_table = kzalloc(
- 2*sizeof(*(clk_scaling->freq_table)), GFP_KERNEL);
+ (clk_scaling->freq_table_sz *
+ sizeof(*(clk_scaling->freq_table))), GFP_KERNEL);
if (!clk_scaling->freq_table)
return -ENOMEM;
- clk_scaling->freq_table[0] = host->card->clk_scaling_lowest;
- clk_scaling->freq_table[1] = host->card->clk_scaling_highest;
- clk_scaling->freq_table_sz = 2;
- goto out;
+
+ if (clk_scaling->pltfm_freq_table) {
+ memcpy(clk_scaling->freq_table,
+ clk_scaling->pltfm_freq_table,
+ (clk_scaling->pltfm_freq_table_sz *
+ sizeof(*(clk_scaling->pltfm_freq_table))));
+ } else {
+ pr_debug("%s: no frequency table defined - setting default\n",
+ mmc_hostname(host));
+ clk_scaling->freq_table[0] =
+ host->card->clk_scaling_lowest;
+ clk_scaling->freq_table[1] =
+ host->card->clk_scaling_highest;
+ goto out;
+ }
}
if (host->card->clk_scaling_lowest >
@@ -835,7 +857,7 @@ int mmc_resume_clk_scaling(struct mmc_host *host)
devfreq_min_clk = host->clk_scaling.freq_table[0];
host->clk_scaling.curr_freq = devfreq_max_clk;
- if (host->ios.clock < host->card->clk_scaling_highest)
+ if (host->ios.clock < host->clk_scaling.freq_table[max_clk_idx])
host->clk_scaling.curr_freq = devfreq_min_clk;
host->clk_scaling.clk_scaling_in_progress = false;
@@ -895,6 +917,10 @@ int mmc_exit_clk_scaling(struct mmc_host *host)
host->clk_scaling.devfreq = NULL;
atomic_set(&host->clk_scaling.devfreq_abort, 1);
+
+ kfree(host->clk_scaling.freq_table);
+ host->clk_scaling.freq_table = NULL;
+
pr_debug("%s: devfreq was removed\n", mmc_hostname(host));
return 0;
diff --git a/drivers/mmc/core/debugfs.c b/drivers/mmc/core/debugfs.c
index 594fba08e623..72bfdd835178 100644
--- a/drivers/mmc/core/debugfs.c
+++ b/drivers/mmc/core/debugfs.c
@@ -337,10 +337,15 @@ static int mmc_force_err_set(void *data, u64 val)
{
struct mmc_host *host = data;
- if (host && host->ops && host->ops->force_err_irq) {
- mmc_host_clk_hold(host);
+ if (host && host->card && host->ops &&
+ host->ops->force_err_irq) {
+ /*
+ * To access the force error irq reg, we need to make
+ * sure the host is powered up and host clock is ticking.
+ */
+ mmc_get_card(host->card);
host->ops->force_err_irq(host, val);
- mmc_host_clk_release(host);
+ mmc_put_card(host->card);
}
return 0;
diff --git a/drivers/mmc/host/sdhci-msm.c b/drivers/mmc/host/sdhci-msm.c
index ca72ebfd55a3..1eeab7db9722 100644
--- a/drivers/mmc/host/sdhci-msm.c
+++ b/drivers/mmc/host/sdhci-msm.c
@@ -1837,13 +1837,13 @@ struct sdhci_msm_pltfm_data *sdhci_msm_populate_pdata(struct device *dev,
}
if (sdhci_msm_dt_get_array(dev, "qcom,devfreq,freq-table",
- &msm_host->mmc->clk_scaling.freq_table,
- &msm_host->mmc->clk_scaling.freq_table_sz, 0))
+ &msm_host->mmc->clk_scaling.pltfm_freq_table,
+ &msm_host->mmc->clk_scaling.pltfm_freq_table_sz, 0))
pr_debug("%s: no clock scaling frequencies were supplied\n",
dev_name(dev));
- else if (!msm_host->mmc->clk_scaling.freq_table ||
- !msm_host->mmc->clk_scaling.freq_table_sz)
- dev_err(dev, "bad dts clock scaling frequencies\n");
+ else if (!msm_host->mmc->clk_scaling.pltfm_freq_table ||
+ !msm_host->mmc->clk_scaling.pltfm_freq_table_sz)
+ dev_err(dev, "bad dts clock scaling frequencies\n");
/*
* Few hosts can support DDR52 mode at the same lower
diff --git a/drivers/net/wireless/ath/regd.c b/drivers/net/wireless/ath/regd.c
index 06ea6cc9e30a..096818610d40 100644
--- a/drivers/net/wireless/ath/regd.c
+++ b/drivers/net/wireless/ath/regd.c
@@ -38,28 +38,28 @@ static int __ath_regd_init(struct ath_regulatory *reg);
/* We enable active scan on these a case by case basis by regulatory domain */
#define ATH9K_2GHZ_CH12_13 REG_RULE(2467-10, 2472+10, 40, 0, 20,\
NL80211_RRF_NO_IR)
-#define ATH9K_2GHZ_CH14 REG_RULE(2484-10, 2484+10, 40, 0, 20,\
+#define ATH9K_2GHZ_CH14 REG_RULE(2484 - 10, 2484 + 10, 20, 0, 20,\
NL80211_RRF_NO_IR | \
NL80211_RRF_NO_OFDM)
/* We allow IBSS on these on a case by case basis by regulatory domain */
-#define ATH9K_5GHZ_5150_5350 REG_RULE(5150-10, 5350+10, 80, 0, 30,\
+#define ATH9K_5GHZ_5180_5320 REG_RULE(5180 - 10, 5320 + 10, 160, 0, 20,\
NL80211_RRF_NO_IR)
-#define ATH9K_5GHZ_5470_5850 REG_RULE(5470-10, 5850+10, 80, 0, 30,\
+#define ATH9K_5GHZ_5500_5825 REG_RULE(5500 - 10, 5825 + 10, 80, 0, 20,\
NL80211_RRF_NO_IR)
-#define ATH9K_5GHZ_5725_5850 REG_RULE(5725-10, 5850+10, 80, 0, 30,\
+#define ATH9K_5GHZ_5745_5825 REG_RULE(5745 - 10, 5825 + 10, 80, 0, 20,\
NL80211_RRF_NO_IR)
#define ATH9K_2GHZ_ALL ATH9K_2GHZ_CH01_11, \
ATH9K_2GHZ_CH12_13, \
ATH9K_2GHZ_CH14
-#define ATH9K_5GHZ_ALL ATH9K_5GHZ_5150_5350, \
- ATH9K_5GHZ_5470_5850
+#define ATH9K_5GHZ_ALL ATH9K_5GHZ_5180_5320, \
+ ATH9K_5GHZ_5500_5825
/* This one skips what we call "mid band" */
-#define ATH9K_5GHZ_NO_MIDBAND ATH9K_5GHZ_5150_5350, \
- ATH9K_5GHZ_5725_5850
+#define ATH9K_5GHZ_NO_MIDBAND ATH9K_5GHZ_5180_5320, \
+ ATH9K_5GHZ_5745_5825
/* Can be used for:
* 0x60, 0x61, 0x62 */
@@ -256,7 +256,7 @@ EXPORT_SYMBOL(ath_is_49ghz_allowed);
/* Frequency is one where radar detection is required */
static bool ath_is_radar_freq(u16 center_freq)
{
- return (center_freq >= 5260 && center_freq <= 5700);
+ return (center_freq >= 5260 && center_freq <= 5720);
}
static void ath_force_clear_no_ir_chan(struct wiphy *wiphy,
diff --git a/drivers/net/wireless/ath/wil6210/cfg80211.c b/drivers/net/wireless/ath/wil6210/cfg80211.c
index 69214fb2586c..e07b120f791f 100644
--- a/drivers/net/wireless/ath/wil6210/cfg80211.c
+++ b/drivers/net/wireless/ath/wil6210/cfg80211.c
@@ -16,6 +16,7 @@
#include <linux/etherdevice.h>
#include <linux/moduleparam.h>
+#include <net/netlink.h>
#include "wil6210.h"
#include "wmi.h"
#include "ftm.h"
@@ -56,6 +57,62 @@ static struct ieee80211_channel wil_60ghz_channels[] = {
#define QCA_NL80211_VENDOR_ID 0x001374
+#define WIL_MAX_RF_SECTORS (128)
+#define WIL_CID_ALL (0xff)
+
+enum qca_wlan_vendor_attr_rf_sector {
+ QCA_ATTR_MAC_ADDR = 6,
+ QCA_ATTR_PAD = 13,
+ QCA_ATTR_TSF = 29,
+ QCA_ATTR_DMG_RF_SECTOR_INDEX = 30,
+ QCA_ATTR_DMG_RF_SECTOR_TYPE = 31,
+ QCA_ATTR_DMG_RF_MODULE_MASK = 32,
+ QCA_ATTR_DMG_RF_SECTOR_CFG = 33,
+ QCA_ATTR_DMG_RF_SECTOR_MAX,
+};
+
+enum qca_wlan_vendor_attr_dmg_rf_sector_type {
+ QCA_ATTR_DMG_RF_SECTOR_TYPE_RX,
+ QCA_ATTR_DMG_RF_SECTOR_TYPE_TX,
+ QCA_ATTR_DMG_RF_SECTOR_TYPE_MAX
+};
+
+enum qca_wlan_vendor_attr_dmg_rf_sector_cfg {
+ QCA_ATTR_DMG_RF_SECTOR_CFG_INVALID = 0,
+ QCA_ATTR_DMG_RF_SECTOR_CFG_MODULE_INDEX,
+ QCA_ATTR_DMG_RF_SECTOR_CFG_ETYPE0,
+ QCA_ATTR_DMG_RF_SECTOR_CFG_ETYPE1,
+ QCA_ATTR_DMG_RF_SECTOR_CFG_ETYPE2,
+ QCA_ATTR_DMG_RF_SECTOR_CFG_PSH_HI,
+ QCA_ATTR_DMG_RF_SECTOR_CFG_PSH_LO,
+ QCA_ATTR_DMG_RF_SECTOR_CFG_DTYPE_X16,
+
+ /* keep last */
+ QCA_ATTR_DMG_RF_SECTOR_CFG_AFTER_LAST,
+ QCA_ATTR_DMG_RF_SECTOR_CFG_MAX =
+ QCA_ATTR_DMG_RF_SECTOR_CFG_AFTER_LAST - 1
+};
+
+static const struct
+nla_policy wil_rf_sector_policy[QCA_ATTR_DMG_RF_SECTOR_MAX + 1] = {
+ [QCA_ATTR_MAC_ADDR] = { .len = ETH_ALEN },
+ [QCA_ATTR_DMG_RF_SECTOR_INDEX] = { .type = NLA_U16 },
+ [QCA_ATTR_DMG_RF_SECTOR_TYPE] = { .type = NLA_U8 },
+ [QCA_ATTR_DMG_RF_MODULE_MASK] = { .type = NLA_U32 },
+ [QCA_ATTR_DMG_RF_SECTOR_CFG] = { .type = NLA_NESTED },
+};
+
+static const struct
+nla_policy wil_rf_sector_cfg_policy[QCA_ATTR_DMG_RF_SECTOR_CFG_MAX + 1] = {
+ [QCA_ATTR_DMG_RF_SECTOR_CFG_MODULE_INDEX] = { .type = NLA_U8 },
+ [QCA_ATTR_DMG_RF_SECTOR_CFG_ETYPE0] = { .type = NLA_U32 },
+ [QCA_ATTR_DMG_RF_SECTOR_CFG_ETYPE1] = { .type = NLA_U32 },
+ [QCA_ATTR_DMG_RF_SECTOR_CFG_ETYPE2] = { .type = NLA_U32 },
+ [QCA_ATTR_DMG_RF_SECTOR_CFG_PSH_HI] = { .type = NLA_U32 },
+ [QCA_ATTR_DMG_RF_SECTOR_CFG_PSH_LO] = { .type = NLA_U32 },
+ [QCA_ATTR_DMG_RF_SECTOR_CFG_DTYPE_X16] = { .type = NLA_U32 },
+};
+
enum qca_nl80211_vendor_subcmds {
QCA_NL80211_VENDOR_SUBCMD_LOC_GET_CAPA = 128,
QCA_NL80211_VENDOR_SUBCMD_FTM_START_SESSION = 129,
@@ -66,8 +123,25 @@ enum qca_nl80211_vendor_subcmds {
QCA_NL80211_VENDOR_SUBCMD_AOA_MEAS = 134,
QCA_NL80211_VENDOR_SUBCMD_AOA_ABORT_MEAS = 135,
QCA_NL80211_VENDOR_SUBCMD_AOA_MEAS_RESULT = 136,
+ QCA_NL80211_VENDOR_SUBCMD_DMG_RF_GET_SECTOR_CFG = 139,
+ QCA_NL80211_VENDOR_SUBCMD_DMG_RF_SET_SECTOR_CFG = 140,
+ QCA_NL80211_VENDOR_SUBCMD_DMG_RF_GET_SELECTED_SECTOR = 141,
+ QCA_NL80211_VENDOR_SUBCMD_DMG_RF_SET_SELECTED_SECTOR = 142,
};
+static int wil_rf_sector_get_cfg(struct wiphy *wiphy,
+ struct wireless_dev *wdev,
+ const void *data, int data_len);
+static int wil_rf_sector_set_cfg(struct wiphy *wiphy,
+ struct wireless_dev *wdev,
+ const void *data, int data_len);
+static int wil_rf_sector_get_selected(struct wiphy *wiphy,
+ struct wireless_dev *wdev,
+ const void *data, int data_len);
+static int wil_rf_sector_set_selected(struct wiphy *wiphy,
+ struct wireless_dev *wdev,
+ const void *data, int data_len);
+
/* vendor specific commands */
static const struct wiphy_vendor_command wil_nl80211_vendor_commands[] = {
{
@@ -112,6 +186,36 @@ static const struct wiphy_vendor_command wil_nl80211_vendor_commands[] = {
WIPHY_VENDOR_CMD_NEED_RUNNING,
.doit = wil_aoa_abort_measurement
},
+ {
+ .info.vendor_id = QCA_NL80211_VENDOR_ID,
+ .info.subcmd = QCA_NL80211_VENDOR_SUBCMD_DMG_RF_GET_SECTOR_CFG,
+ .flags = WIPHY_VENDOR_CMD_NEED_WDEV |
+ WIPHY_VENDOR_CMD_NEED_RUNNING,
+ .doit = wil_rf_sector_get_cfg
+ },
+ {
+ .info.vendor_id = QCA_NL80211_VENDOR_ID,
+ .info.subcmd = QCA_NL80211_VENDOR_SUBCMD_DMG_RF_SET_SECTOR_CFG,
+ .flags = WIPHY_VENDOR_CMD_NEED_WDEV |
+ WIPHY_VENDOR_CMD_NEED_RUNNING,
+ .doit = wil_rf_sector_set_cfg
+ },
+ {
+ .info.vendor_id = QCA_NL80211_VENDOR_ID,
+ .info.subcmd =
+ QCA_NL80211_VENDOR_SUBCMD_DMG_RF_GET_SELECTED_SECTOR,
+ .flags = WIPHY_VENDOR_CMD_NEED_WDEV |
+ WIPHY_VENDOR_CMD_NEED_RUNNING,
+ .doit = wil_rf_sector_get_selected
+ },
+ {
+ .info.vendor_id = QCA_NL80211_VENDOR_ID,
+ .info.subcmd =
+ QCA_NL80211_VENDOR_SUBCMD_DMG_RF_SET_SELECTED_SECTOR,
+ .flags = WIPHY_VENDOR_CMD_NEED_WDEV |
+ WIPHY_VENDOR_CMD_NEED_RUNNING,
+ .doit = wil_rf_sector_set_selected
+ },
};
/* vendor specific events */
@@ -1838,3 +1942,449 @@ void wil_p2p_wdev_free(struct wil6210_priv *wil)
kfree(p2p_wdev);
}
}
+
+static int wil_rf_sector_status_to_rc(u8 status)
+{
+ switch (status) {
+ case WMI_RF_SECTOR_STATUS_SUCCESS:
+ return 0;
+ case WMI_RF_SECTOR_STATUS_BAD_PARAMETERS_ERROR:
+ return -EINVAL;
+ case WMI_RF_SECTOR_STATUS_BUSY_ERROR:
+ return -EAGAIN;
+ case WMI_RF_SECTOR_STATUS_NOT_SUPPORTED_ERROR:
+ return -EOPNOTSUPP;
+ default:
+ return -EINVAL;
+ }
+}
+
+static int wil_rf_sector_get_cfg(struct wiphy *wiphy,
+ struct wireless_dev *wdev,
+ const void *data, int data_len)
+{
+ struct wil6210_priv *wil = wdev_to_wil(wdev);
+ int rc;
+ struct nlattr *tb[QCA_ATTR_DMG_RF_SECTOR_MAX + 1];
+ u16 sector_index;
+ u8 sector_type;
+ u32 rf_modules_vec;
+ struct wmi_get_rf_sector_params_cmd cmd;
+ struct {
+ struct wmi_cmd_hdr wmi;
+ struct wmi_get_rf_sector_params_done_event evt;
+ } __packed reply;
+ struct sk_buff *msg;
+ struct nlattr *nl_cfgs, *nl_cfg;
+ u32 i;
+ struct wmi_rf_sector_info *si;
+
+ if (!test_bit(WMI_FW_CAPABILITY_RF_SECTORS, wil->fw_capabilities))
+ return -EOPNOTSUPP;
+
+ rc = nla_parse(tb, QCA_ATTR_DMG_RF_SECTOR_MAX, data, data_len,
+ wil_rf_sector_policy);
+ if (rc) {
+ wil_err(wil, "Invalid rf sector ATTR\n");
+ return rc;
+ }
+
+ if (!tb[QCA_ATTR_DMG_RF_SECTOR_INDEX] ||
+ !tb[QCA_ATTR_DMG_RF_SECTOR_TYPE] ||
+ !tb[QCA_ATTR_DMG_RF_MODULE_MASK]) {
+ wil_err(wil, "Invalid rf sector spec\n");
+ return -EINVAL;
+ }
+
+ sector_index = nla_get_u16(
+ tb[QCA_ATTR_DMG_RF_SECTOR_INDEX]);
+ if (sector_index >= WIL_MAX_RF_SECTORS) {
+ wil_err(wil, "Invalid sector index %d\n", sector_index);
+ return -EINVAL;
+ }
+
+ sector_type = nla_get_u8(tb[QCA_ATTR_DMG_RF_SECTOR_TYPE]);
+ if (sector_type >= QCA_ATTR_DMG_RF_SECTOR_TYPE_MAX) {
+ wil_err(wil, "Invalid sector type %d\n", sector_type);
+ return -EINVAL;
+ }
+
+ rf_modules_vec = nla_get_u32(
+ tb[QCA_ATTR_DMG_RF_MODULE_MASK]);
+ if (rf_modules_vec >= BIT(WMI_MAX_RF_MODULES_NUM)) {
+ wil_err(wil, "Invalid rf module mask 0x%x\n", rf_modules_vec);
+ return -EINVAL;
+ }
+
+ cmd.sector_idx = cpu_to_le16(sector_index);
+ cmd.sector_type = sector_type;
+ cmd.rf_modules_vec = rf_modules_vec & 0xFF;
+ memset(&reply, 0, sizeof(reply));
+ rc = wmi_call(wil, WMI_GET_RF_SECTOR_PARAMS_CMDID, &cmd, sizeof(cmd),
+ WMI_GET_RF_SECTOR_PARAMS_DONE_EVENTID,
+ &reply, sizeof(reply),
+ 500);
+ if (rc)
+ return rc;
+ if (reply.evt.status) {
+ wil_err(wil, "get rf sector cfg failed with status %d\n",
+ reply.evt.status);
+ return wil_rf_sector_status_to_rc(reply.evt.status);
+ }
+
+ msg = cfg80211_vendor_cmd_alloc_reply_skb(
+ wiphy, 64 * WMI_MAX_RF_MODULES_NUM);
+ if (!msg)
+ return -ENOMEM;
+
+ if (nla_put_u64(msg, QCA_ATTR_TSF,
+ le64_to_cpu(reply.evt.tsf)))
+ goto nla_put_failure;
+
+ nl_cfgs = nla_nest_start(msg, QCA_ATTR_DMG_RF_SECTOR_CFG);
+ if (!nl_cfgs)
+ goto nla_put_failure;
+ for (i = 0; i < WMI_MAX_RF_MODULES_NUM; i++) {
+ if (!(rf_modules_vec & BIT(i)))
+ continue;
+ nl_cfg = nla_nest_start(msg, i);
+ if (!nl_cfg)
+ goto nla_put_failure;
+ si = &reply.evt.sectors_info[i];
+ if (nla_put_u8(msg, QCA_ATTR_DMG_RF_SECTOR_CFG_MODULE_INDEX,
+ i) ||
+ nla_put_u32(msg, QCA_ATTR_DMG_RF_SECTOR_CFG_ETYPE0,
+ le32_to_cpu(si->etype0)) ||
+ nla_put_u32(msg, QCA_ATTR_DMG_RF_SECTOR_CFG_ETYPE1,
+ le32_to_cpu(si->etype1)) ||
+ nla_put_u32(msg, QCA_ATTR_DMG_RF_SECTOR_CFG_ETYPE2,
+ le32_to_cpu(si->etype2)) ||
+ nla_put_u32(msg, QCA_ATTR_DMG_RF_SECTOR_CFG_PSH_HI,
+ le32_to_cpu(si->psh_hi)) ||
+ nla_put_u32(msg, QCA_ATTR_DMG_RF_SECTOR_CFG_PSH_LO,
+ le32_to_cpu(si->psh_lo)) ||
+ nla_put_u32(msg, QCA_ATTR_DMG_RF_SECTOR_CFG_DTYPE_X16,
+ le32_to_cpu(si->dtype_swch_off)))
+ goto nla_put_failure;
+ nla_nest_end(msg, nl_cfg);
+ }
+
+ nla_nest_end(msg, nl_cfgs);
+ rc = cfg80211_vendor_cmd_reply(msg);
+ return rc;
+nla_put_failure:
+ kfree_skb(msg);
+ return -ENOBUFS;
+}
+
+static int wil_rf_sector_set_cfg(struct wiphy *wiphy,
+ struct wireless_dev *wdev,
+ const void *data, int data_len)
+{
+ struct wil6210_priv *wil = wdev_to_wil(wdev);
+ int rc, tmp;
+ struct nlattr *tb[QCA_ATTR_DMG_RF_SECTOR_MAX + 1];
+ struct nlattr *tb2[QCA_ATTR_DMG_RF_SECTOR_CFG_MAX + 1];
+ u16 sector_index, rf_module_index;
+ u8 sector_type;
+ u32 rf_modules_vec = 0;
+ struct wmi_set_rf_sector_params_cmd cmd;
+ struct {
+ struct wmi_cmd_hdr wmi;
+ struct wmi_set_rf_sector_params_done_event evt;
+ } __packed reply;
+ struct nlattr *nl_cfg;
+ struct wmi_rf_sector_info *si;
+
+ if (!test_bit(WMI_FW_CAPABILITY_RF_SECTORS, wil->fw_capabilities))
+ return -EOPNOTSUPP;
+
+ rc = nla_parse(tb, QCA_ATTR_DMG_RF_SECTOR_MAX, data, data_len,
+ wil_rf_sector_policy);
+ if (rc) {
+ wil_err(wil, "Invalid rf sector ATTR\n");
+ return rc;
+ }
+
+ if (!tb[QCA_ATTR_DMG_RF_SECTOR_INDEX] ||
+ !tb[QCA_ATTR_DMG_RF_SECTOR_TYPE] ||
+ !tb[QCA_ATTR_DMG_RF_SECTOR_CFG]) {
+ wil_err(wil, "Invalid rf sector spec\n");
+ return -EINVAL;
+ }
+
+ sector_index = nla_get_u16(
+ tb[QCA_ATTR_DMG_RF_SECTOR_INDEX]);
+ if (sector_index >= WIL_MAX_RF_SECTORS) {
+ wil_err(wil, "Invalid sector index %d\n", sector_index);
+ return -EINVAL;
+ }
+
+ sector_type = nla_get_u8(tb[QCA_ATTR_DMG_RF_SECTOR_TYPE]);
+ if (sector_type >= QCA_ATTR_DMG_RF_SECTOR_TYPE_MAX) {
+ wil_err(wil, "Invalid sector type %d\n", sector_type);
+ return -EINVAL;
+ }
+
+ memset(&cmd, 0, sizeof(cmd));
+
+ cmd.sector_idx = cpu_to_le16(sector_index);
+ cmd.sector_type = sector_type;
+ nla_for_each_nested(nl_cfg, tb[QCA_ATTR_DMG_RF_SECTOR_CFG],
+ tmp) {
+ rc = nla_parse_nested(tb2, QCA_ATTR_DMG_RF_SECTOR_CFG_MAX,
+ nl_cfg, wil_rf_sector_cfg_policy);
+ if (rc) {
+ wil_err(wil, "invalid sector cfg\n");
+ return -EINVAL;
+ }
+
+ if (!tb2[QCA_ATTR_DMG_RF_SECTOR_CFG_MODULE_INDEX] ||
+ !tb2[QCA_ATTR_DMG_RF_SECTOR_CFG_ETYPE0] ||
+ !tb2[QCA_ATTR_DMG_RF_SECTOR_CFG_ETYPE1] ||
+ !tb2[QCA_ATTR_DMG_RF_SECTOR_CFG_ETYPE2] ||
+ !tb2[QCA_ATTR_DMG_RF_SECTOR_CFG_PSH_HI] ||
+ !tb2[QCA_ATTR_DMG_RF_SECTOR_CFG_PSH_LO] ||
+ !tb2[QCA_ATTR_DMG_RF_SECTOR_CFG_DTYPE_X16]) {
+ wil_err(wil, "missing cfg params\n");
+ return -EINVAL;
+ }
+
+ rf_module_index = nla_get_u8(
+ tb2[QCA_ATTR_DMG_RF_SECTOR_CFG_MODULE_INDEX]);
+ if (rf_module_index >= WMI_MAX_RF_MODULES_NUM) {
+ wil_err(wil, "invalid RF module index %d\n",
+ rf_module_index);
+ return -EINVAL;
+ }
+ rf_modules_vec |= BIT(rf_module_index);
+ si = &cmd.sectors_info[rf_module_index];
+ si->etype0 = cpu_to_le32(nla_get_u32(
+ tb2[QCA_ATTR_DMG_RF_SECTOR_CFG_ETYPE0]));
+ si->etype1 = cpu_to_le32(nla_get_u32(
+ tb2[QCA_ATTR_DMG_RF_SECTOR_CFG_ETYPE1]));
+ si->etype2 = cpu_to_le32(nla_get_u32(
+ tb2[QCA_ATTR_DMG_RF_SECTOR_CFG_ETYPE2]));
+ si->psh_hi = cpu_to_le32(nla_get_u32(
+ tb2[QCA_ATTR_DMG_RF_SECTOR_CFG_PSH_HI]));
+ si->psh_lo = cpu_to_le32(nla_get_u32(
+ tb2[QCA_ATTR_DMG_RF_SECTOR_CFG_PSH_LO]));
+ si->dtype_swch_off = cpu_to_le32(nla_get_u32(
+ tb2[QCA_ATTR_DMG_RF_SECTOR_CFG_DTYPE_X16]));
+ }
+
+ cmd.rf_modules_vec = rf_modules_vec & 0xFF;
+ memset(&reply, 0, sizeof(reply));
+ rc = wmi_call(wil, WMI_SET_RF_SECTOR_PARAMS_CMDID, &cmd, sizeof(cmd),
+ WMI_SET_RF_SECTOR_PARAMS_DONE_EVENTID,
+ &reply, sizeof(reply),
+ 500);
+ if (rc)
+ return rc;
+ return wil_rf_sector_status_to_rc(reply.evt.status);
+}
+
+static int wil_rf_sector_get_selected(struct wiphy *wiphy,
+ struct wireless_dev *wdev,
+ const void *data, int data_len)
+{
+ struct wil6210_priv *wil = wdev_to_wil(wdev);
+ int rc;
+ struct nlattr *tb[QCA_ATTR_DMG_RF_SECTOR_MAX + 1];
+ u8 sector_type, mac_addr[ETH_ALEN];
+ int cid = 0;
+ struct wmi_get_selected_rf_sector_index_cmd cmd;
+ struct {
+ struct wmi_cmd_hdr wmi;
+ struct wmi_get_selected_rf_sector_index_done_event evt;
+ } __packed reply;
+ struct sk_buff *msg;
+
+ if (!test_bit(WMI_FW_CAPABILITY_RF_SECTORS, wil->fw_capabilities))
+ return -EOPNOTSUPP;
+
+ rc = nla_parse(tb, QCA_ATTR_DMG_RF_SECTOR_MAX, data, data_len,
+ wil_rf_sector_policy);
+ if (rc) {
+ wil_err(wil, "Invalid rf sector ATTR\n");
+ return rc;
+ }
+
+ if (!tb[QCA_ATTR_DMG_RF_SECTOR_TYPE]) {
+ wil_err(wil, "Invalid rf sector spec\n");
+ return -EINVAL;
+ }
+ sector_type = nla_get_u8(tb[QCA_ATTR_DMG_RF_SECTOR_TYPE]);
+ if (sector_type >= QCA_ATTR_DMG_RF_SECTOR_TYPE_MAX) {
+ wil_err(wil, "Invalid sector type %d\n", sector_type);
+ return -EINVAL;
+ }
+
+ if (tb[QCA_ATTR_MAC_ADDR]) {
+ ether_addr_copy(mac_addr, nla_data(tb[QCA_ATTR_MAC_ADDR]));
+ cid = wil_find_cid(wil, mac_addr);
+ if (cid < 0) {
+ wil_err(wil, "invalid MAC address %pM\n", mac_addr);
+ return -ENOENT;
+ }
+ } else {
+ if (test_bit(wil_status_fwconnected, wil->status)) {
+ wil_err(wil, "must specify MAC address when connected\n");
+ return -EINVAL;
+ }
+ }
+
+ memset(&cmd, 0, sizeof(cmd));
+ cmd.cid = (u8)cid;
+ cmd.sector_type = sector_type;
+ memset(&reply, 0, sizeof(reply));
+ rc = wmi_call(wil, WMI_GET_SELECTED_RF_SECTOR_INDEX_CMDID,
+ &cmd, sizeof(cmd),
+ WMI_GET_SELECTED_RF_SECTOR_INDEX_DONE_EVENTID,
+ &reply, sizeof(reply),
+ 500);
+ if (rc)
+ return rc;
+ if (reply.evt.status) {
+ wil_err(wil, "get rf selected sector cfg failed with status %d\n",
+ reply.evt.status);
+ return wil_rf_sector_status_to_rc(reply.evt.status);
+ }
+
+ msg = cfg80211_vendor_cmd_alloc_reply_skb(
+ wiphy, 64 * WMI_MAX_RF_MODULES_NUM);
+ if (!msg)
+ return -ENOMEM;
+
+ if (nla_put_u64(msg, QCA_ATTR_TSF,
+ le64_to_cpu(reply.evt.tsf)) ||
+ nla_put_u16(msg, QCA_ATTR_DMG_RF_SECTOR_INDEX,
+ le16_to_cpu(reply.evt.sector_idx)))
+ goto nla_put_failure;
+
+ rc = cfg80211_vendor_cmd_reply(msg);
+ return rc;
+nla_put_failure:
+ kfree_skb(msg);
+ return -ENOBUFS;
+}
+
+static int wil_rf_sector_wmi_set_selected(struct wil6210_priv *wil,
+ u16 sector_index,
+ u8 sector_type, u8 cid)
+{
+ struct wmi_set_selected_rf_sector_index_cmd cmd;
+ struct {
+ struct wmi_cmd_hdr wmi;
+ struct wmi_set_selected_rf_sector_index_done_event evt;
+ } __packed reply;
+ int rc;
+
+ memset(&cmd, 0, sizeof(cmd));
+ cmd.sector_idx = cpu_to_le16(sector_index);
+ cmd.sector_type = sector_type;
+ cmd.cid = (u8)cid;
+ memset(&reply, 0, sizeof(reply));
+ rc = wmi_call(wil, WMI_SET_SELECTED_RF_SECTOR_INDEX_CMDID,
+ &cmd, sizeof(cmd),
+ WMI_SET_SELECTED_RF_SECTOR_INDEX_DONE_EVENTID,
+ &reply, sizeof(reply),
+ 500);
+ if (rc)
+ return rc;
+ return wil_rf_sector_status_to_rc(reply.evt.status);
+}
+
+static int wil_rf_sector_set_selected(struct wiphy *wiphy,
+ struct wireless_dev *wdev,
+ const void *data, int data_len)
+{
+ struct wil6210_priv *wil = wdev_to_wil(wdev);
+ int rc;
+ struct nlattr *tb[QCA_ATTR_DMG_RF_SECTOR_MAX + 1];
+ u16 sector_index;
+ u8 sector_type, mac_addr[ETH_ALEN], i;
+ int cid = 0;
+
+ if (!test_bit(WMI_FW_CAPABILITY_RF_SECTORS, wil->fw_capabilities))
+ return -EOPNOTSUPP;
+
+ rc = nla_parse(tb, QCA_ATTR_DMG_RF_SECTOR_MAX, data, data_len,
+ wil_rf_sector_policy);
+ if (rc) {
+ wil_err(wil, "Invalid rf sector ATTR\n");
+ return rc;
+ }
+
+ if (!tb[QCA_ATTR_DMG_RF_SECTOR_INDEX] ||
+ !tb[QCA_ATTR_DMG_RF_SECTOR_TYPE]) {
+ wil_err(wil, "Invalid rf sector spec\n");
+ return -EINVAL;
+ }
+
+ sector_index = nla_get_u16(
+ tb[QCA_ATTR_DMG_RF_SECTOR_INDEX]);
+ if (sector_index >= WIL_MAX_RF_SECTORS &&
+ sector_index != WMI_INVALID_RF_SECTOR_INDEX) {
+ wil_err(wil, "Invalid sector index %d\n", sector_index);
+ return -EINVAL;
+ }
+
+ sector_type = nla_get_u8(tb[QCA_ATTR_DMG_RF_SECTOR_TYPE]);
+ if (sector_type >= QCA_ATTR_DMG_RF_SECTOR_TYPE_MAX) {
+ wil_err(wil, "Invalid sector type %d\n", sector_type);
+ return -EINVAL;
+ }
+
+ if (tb[QCA_ATTR_MAC_ADDR]) {
+ ether_addr_copy(mac_addr, nla_data(tb[QCA_ATTR_MAC_ADDR]));
+ if (!is_broadcast_ether_addr(mac_addr)) {
+ cid = wil_find_cid(wil, mac_addr);
+ if (cid < 0) {
+ wil_err(wil, "invalid MAC address %pM\n",
+ mac_addr);
+ return -ENOENT;
+ }
+ } else {
+ if (sector_index != WMI_INVALID_RF_SECTOR_INDEX) {
+ wil_err(wil, "broadcast MAC valid only with unlocking\n");
+ return -EINVAL;
+ }
+ cid = -1;
+ }
+ } else {
+ if (test_bit(wil_status_fwconnected, wil->status)) {
+ wil_err(wil, "must specify MAC address when connected\n");
+ return -EINVAL;
+ }
+ /* otherwise, using cid=0 for unassociated station */
+ }
+
+ if (cid >= 0) {
+ rc = wil_rf_sector_wmi_set_selected(wil, sector_index,
+ sector_type, cid);
+ } else {
+ /* unlock all cids */
+ rc = wil_rf_sector_wmi_set_selected(
+ wil, WMI_INVALID_RF_SECTOR_INDEX, sector_type,
+ WIL_CID_ALL);
+ if (rc == -EINVAL) {
+ for (i = 0; i < WIL6210_MAX_CID; i++) {
+ rc = wil_rf_sector_wmi_set_selected(
+ wil, WMI_INVALID_RF_SECTOR_INDEX,
+ sector_type, i);
+ /* the FW will silently ignore and return
+ * success for unused cid, so abort the loop
+ * on any other error
+ */
+ if (rc) {
+ wil_err(wil, "unlock cid %d failed with status %d\n",
+ i, rc);
+ break;
+ }
+ }
+ }
+ }
+
+ return rc;
+}
diff --git a/drivers/net/wireless/ath/wil6210/ioctl.c b/drivers/net/wireless/ath/wil6210/ioctl.c
index bbdd232df3b7..f8d2c209482c 100644
--- a/drivers/net/wireless/ath/wil6210/ioctl.c
+++ b/drivers/net/wireless/ath/wil6210/ioctl.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2014 Qualcomm Atheros, Inc.
+ * Copyright (c) 2014,2017 Qualcomm Atheros, Inc.
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
@@ -54,7 +54,7 @@ static void __iomem *wil_ioc_addr(struct wil6210_priv *wil, uint32_t addr,
}
off = a - wil->csr;
- if (size >= WIL6210_MEM_SIZE - off) {
+ if (size >= wil->bar_size - off) {
wil_err(wil, "Requested block does not fit into memory: "
"off = 0x%08x size = 0x%08x\n", off, size);
return NULL;
diff --git a/drivers/net/wireless/ath/wil6210/pcie_bus.c b/drivers/net/wireless/ath/wil6210/pcie_bus.c
index 8d3d25333ba5..e91cddbacf24 100644
--- a/drivers/net/wireless/ath/wil6210/pcie_bus.c
+++ b/drivers/net/wireless/ath/wil6210/pcie_bus.c
@@ -198,16 +198,18 @@ static int wil_pcie_probe(struct pci_dev *pdev, const struct pci_device_id *id)
.ramdump = wil_platform_rop_ramdump,
.fw_recovery = wil_platform_rop_fw_recovery,
};
+ u32 bar_size = pci_resource_len(pdev, 0);
/* check HW */
dev_info(&pdev->dev, WIL_NAME
- " device found [%04x:%04x] (rev %x)\n",
- (int)pdev->vendor, (int)pdev->device, (int)pdev->revision);
-
- if (pci_resource_len(pdev, 0) != WIL6210_MEM_SIZE) {
- dev_err(&pdev->dev, "Not " WIL_NAME "? "
- "BAR0 size is %lu while expecting %lu\n",
- (ulong)pci_resource_len(pdev, 0), WIL6210_MEM_SIZE);
+ " device found [%04x:%04x] (rev %x) bar size 0x%x\n",
+ (int)pdev->vendor, (int)pdev->device, (int)pdev->revision,
+ bar_size);
+
+ if ((bar_size < WIL6210_MIN_MEM_SIZE) ||
+ (bar_size > WIL6210_MAX_MEM_SIZE)) {
+ dev_err(&pdev->dev, "Unexpected BAR0 size 0x%x\n",
+ bar_size);
return -ENODEV;
}
@@ -220,6 +222,7 @@ static int wil_pcie_probe(struct pci_dev *pdev, const struct pci_device_id *id)
wil->pdev = pdev;
pci_set_drvdata(pdev, wil);
+ wil->bar_size = bar_size;
/* rollback to if_free */
wil->platform_handle =
diff --git a/drivers/net/wireless/ath/wil6210/pm.c b/drivers/net/wireless/ath/wil6210/pm.c
index 015dc3c1493f..ce1f384e7f8e 100644
--- a/drivers/net/wireless/ath/wil6210/pm.c
+++ b/drivers/net/wireless/ath/wil6210/pm.c
@@ -80,6 +80,8 @@ static int wil_resume_keep_radio_on(struct wil6210_priv *wil)
wil_c(wil, RGF_USER_CLKS_CTL_0, BIT_USER_CLKS_RST_PWGD);
wil_unmask_irq(wil);
+ wil6210_bus_request(wil, wil->bus_request_kbps_pre_suspend);
+
/* Send WMI resume request to the device */
rc = wmi_resume(wil);
if (rc) {
@@ -96,7 +98,9 @@ static int wil_resume_keep_radio_on(struct wil6210_priv *wil)
}
}
- wil6210_bus_request(wil, wil->bus_request_kbps_pre_suspend);
+ /* Wake all queues */
+ if (test_bit(wil_status_fwconnected, wil->status))
+ wil_update_net_queues_bh(wil, NULL, false);
out:
if (rc)
@@ -113,6 +117,7 @@ static int wil_suspend_keep_radio_on(struct wil6210_priv *wil)
/* Prevent handling of new tx and wmi commands */
set_bit(wil_status_suspending, wil->status);
+ wil_update_net_queues_bh(wil, NULL, true);
if (!wil_is_tx_idle(wil)) {
wil_dbg_pm(wil, "Pending TX data, reject suspend\n");
@@ -175,42 +180,43 @@ static int wil_suspend_keep_radio_on(struct wil6210_priv *wil)
/* Disable device reset on PERST */
wil_s(wil, RGF_USER_CLKS_CTL_0, BIT_USER_CLKS_RST_PWGD);
- /* Save the current bus request to return to the same in resume */
- wil->bus_request_kbps_pre_suspend = wil->bus_request_kbps;
- wil6210_bus_request(wil, 0);
-
if (wil->platform_ops.suspend) {
rc = wil->platform_ops.suspend(wil->platform_handle, true);
if (rc) {
wil_err(wil, "platform device failed to suspend (%d)\n",
rc);
wil->suspend_stats.failed_suspends++;
- clear_bit(wil_status_suspending, wil->status);
- rc = wil_resume_keep_radio_on(wil);
- /* if resume succeeded, reject the suspend */
- if (!rc)
- rc = -EBUSY;
- goto out;
+ wil_c(wil, RGF_USER_CLKS_CTL_0, BIT_USER_CLKS_RST_PWGD);
+ wil_unmask_irq(wil);
+ goto resume_after_fail;
}
}
+ /* Save the current bus request to return to the same in resume */
+ wil->bus_request_kbps_pre_suspend = wil->bus_request_kbps;
+ wil6210_bus_request(wil, 0);
+
set_bit(wil_status_suspended, wil->status);
clear_bit(wil_status_suspending, wil->status);
return rc;
resume_after_fail:
+ set_bit(wil_status_resuming, wil->status);
clear_bit(wil_status_suspending, wil->status);
rc = wmi_resume(wil);
/* if resume succeeded, reject the suspend */
- if (!rc)
+ if (!rc) {
rc = -EBUSY;
-
-out:
+ if (test_bit(wil_status_fwconnected, wil->status))
+ wil_update_net_queues_bh(wil, NULL, false);
+ }
return rc;
reject_suspend:
clear_bit(wil_status_suspending, wil->status);
+ if (test_bit(wil_status_fwconnected, wil->status))
+ wil_update_net_queues_bh(wil, NULL, false);
return -EBUSY;
}
diff --git a/drivers/net/wireless/ath/wil6210/txrx.c b/drivers/net/wireless/ath/wil6210/txrx.c
index 439fe30936b6..8f1e79b425cf 100644
--- a/drivers/net/wireless/ath/wil6210/txrx.c
+++ b/drivers/net/wireless/ath/wil6210/txrx.c
@@ -1930,6 +1930,11 @@ static inline void __wil_update_net_queues(struct wil6210_priv *wil,
return;
}
+ /* Do not wake the queues in suspend flow */
+ if (test_bit(wil_status_suspending, wil->status) ||
+ test_bit(wil_status_suspended, wil->status))
+ return;
+
/* check wake */
for (i = 0; i < WIL6210_MAX_TX_RINGS; i++) {
struct vring *cur_vring = &wil->vring_tx[i];
diff --git a/drivers/net/wireless/ath/wil6210/wil6210.h b/drivers/net/wireless/ath/wil6210/wil6210.h
index e76ec6ed9995..9525f521d215 100644
--- a/drivers/net/wireless/ath/wil6210/wil6210.h
+++ b/drivers/net/wireless/ath/wil6210/wil6210.h
@@ -59,7 +59,8 @@ static inline u32 WIL_GET_BITS(u32 x, int b0, int b1)
return (x >> b0) & ((1 << (b1 - b0 + 1)) - 1);
}
-#define WIL6210_MEM_SIZE (2*1024*1024UL)
+#define WIL6210_MIN_MEM_SIZE (2 * 1024 * 1024UL)
+#define WIL6210_MAX_MEM_SIZE (4 * 1024 * 1024UL)
#define WIL_TX_Q_LEN_DEFAULT (4000)
#define WIL_RX_RING_SIZE_ORDER_DEFAULT (10)
@@ -620,6 +621,7 @@ extern u8 led_polarity;
struct wil6210_priv {
struct pci_dev *pdev;
+ u32 bar_size;
struct wireless_dev *wdev;
void __iomem *csr;
DECLARE_BITMAP(status, wil_status_last);
diff --git a/drivers/net/wireless/ath/wil6210/wmi.c b/drivers/net/wireless/ath/wil6210/wmi.c
index 24878ecf7e93..fba0d6a79ae2 100644
--- a/drivers/net/wireless/ath/wil6210/wmi.c
+++ b/drivers/net/wireless/ath/wil6210/wmi.c
@@ -160,7 +160,7 @@ void __iomem *wmi_buffer(struct wil6210_priv *wil, __le32 ptr_)
return NULL;
off = HOSTADDR(ptr);
- if (off > WIL6210_MEM_SIZE - 4)
+ if (off > wil->bar_size - 4)
return NULL;
return wil->csr + off;
@@ -180,7 +180,7 @@ void __iomem *wmi_addr(struct wil6210_priv *wil, u32 ptr)
return NULL;
off = HOSTADDR(ptr);
- if (off > WIL6210_MEM_SIZE - 4)
+ if (off > wil->bar_size - 4)
return NULL;
return wil->csr + off;
diff --git a/drivers/perf/Makefile b/drivers/perf/Makefile
index acd2397ded94..14a13007a973 100644
--- a/drivers/perf/Makefile
+++ b/drivers/perf/Makefile
@@ -1 +1,2 @@
obj-$(CONFIG_ARM_PMU) += arm_pmu.o
+obj-$(CONFIG_HW_PERF_EVENTS) += perf_event_armv8.o
diff --git a/arch/arm64/kernel/perf_event.c b/drivers/perf/perf_event_armv8.c
index eccd8c49ad69..443538a16aea 100644
--- a/arch/arm64/kernel/perf_event.c
+++ b/drivers/perf/perf_event_armv8.c
@@ -20,6 +20,7 @@
*/
#include <asm/irq_regs.h>
+#include <asm/perf_event.h>
#include <linux/of.h>
#include <linux/perf/arm_pmu.h>
@@ -239,16 +240,14 @@ struct arm_pmu_and_idle_nb {
static inline u32 armv8pmu_pmcr_read(void)
{
- u32 val;
- asm volatile("mrs %0, pmcr_el0" : "=r" (val));
- return val;
+ return armv8pmu_pmcr_read_reg();
}
inline void armv8pmu_pmcr_write(u32 val)
{
val &= ARMV8_PMCR_MASK;
isb();
- asm volatile("msr pmcr_el0, %0" :: "r" (val));
+ armv8pmu_pmcr_write_reg(val);
}
static inline int armv8pmu_has_overflowed(u32 pmovsr)
@@ -270,7 +269,7 @@ static inline int armv8pmu_counter_has_overflowed(u32 pmnc, int idx)
static inline int armv8pmu_select_counter(int idx)
{
u32 counter = ARMV8_IDX_TO_COUNTER(idx);
- asm volatile("msr pmselr_el0, %0" :: "r" (counter));
+ armv8pmu_pmselr_write_reg(counter);
isb();
return idx;
@@ -287,9 +286,9 @@ static inline u32 armv8pmu_read_counter(struct perf_event *event)
pr_err("CPU%u reading wrong counter %d\n",
smp_processor_id(), idx);
else if (idx == ARMV8_IDX_CYCLE_COUNTER)
- asm volatile("mrs %0, pmccntr_el0" : "=r" (value));
+ value = armv8pmu_pmccntr_read_reg();
else if (armv8pmu_select_counter(idx) == idx)
- asm volatile("mrs %0, pmxevcntr_el0" : "=r" (value));
+ value = armv8pmu_pmxevcntr_read_reg();
return value;
}
@@ -304,47 +303,47 @@ static inline void armv8pmu_write_counter(struct perf_event *event, u32 value)
pr_err("CPU%u writing wrong counter %d\n",
smp_processor_id(), idx);
else if (idx == ARMV8_IDX_CYCLE_COUNTER)
- asm volatile("msr pmccntr_el0, %0" :: "r" (value));
+ armv8pmu_pmccntr_write_reg(value);
else if (armv8pmu_select_counter(idx) == idx)
- asm volatile("msr pmxevcntr_el0, %0" :: "r" (value));
+ armv8pmu_pmxevcntr_write_reg(value);
}
inline void armv8pmu_write_evtype(int idx, u32 val)
{
if (armv8pmu_select_counter(idx) == idx) {
val &= ARMV8_EVTYPE_MASK;
- asm volatile("msr pmxevtyper_el0, %0" :: "r" (val));
+ armv8pmu_pmxevtyper_write_reg(val);
}
}
inline int armv8pmu_enable_counter(int idx)
{
u32 counter = ARMV8_IDX_TO_COUNTER(idx);
- asm volatile("msr pmcntenset_el0, %0" :: "r" (BIT(counter)));
+ armv8pmu_pmcntenset_write_reg(BIT(counter));
return idx;
}
inline int armv8pmu_disable_counter(int idx)
{
u32 counter = ARMV8_IDX_TO_COUNTER(idx);
- asm volatile("msr pmcntenclr_el0, %0" :: "r" (BIT(counter)));
+ armv8pmu_pmcntenclr_write_reg(BIT(counter));
return idx;
}
inline int armv8pmu_enable_intens(int idx)
{
u32 counter = ARMV8_IDX_TO_COUNTER(idx);
- asm volatile("msr pmintenset_el1, %0" :: "r" (BIT(counter)));
+ armv8pmu_pmintenset_write_reg(BIT(counter));
return idx;
}
inline int armv8pmu_disable_intens(int idx)
{
u32 counter = ARMV8_IDX_TO_COUNTER(idx);
- asm volatile("msr pmintenclr_el1, %0" :: "r" (BIT(counter)));
+ armv8pmu_pmintenclr_write_reg(BIT(counter));
isb();
/* Clear the overflow flag in case an interrupt is pending. */
- asm volatile("msr pmovsclr_el0, %0" :: "r" (BIT(counter)));
+ armv8pmu_pmovsclr_write_reg(BIT(counter));
isb();
return idx;
@@ -355,11 +354,11 @@ inline u32 armv8pmu_getreset_flags(void)
u32 value;
/* Read */
- asm volatile("mrs %0, pmovsclr_el0" : "=r" (value));
+ value = armv8pmu_pmovsclr_read_reg();
/* Write to clear flags */
value &= ARMV8_OVSR_MASK;
- asm volatile("msr pmovsclr_el0, %0" :: "r" (value));
+ armv8pmu_pmovsclr_write_reg(value);
return value;
}
@@ -566,14 +565,14 @@ static int armv8pmu_set_event_filter(struct hw_perf_event *event,
static void armv8pmu_init_usermode(void)
{
/* Enable access from userspace. */
- asm volatile("msr pmuserenr_el0, %0" :: "r" (0xF));
+ armv8pmu_pmuserenr_write_reg(0xF);
}
#else
static inline void armv8pmu_init_usermode(void)
{
/* Disable access from userspace. */
- asm volatile("msr pmuserenr_el0, %0" :: "r" (0));
+ armv8pmu_pmuserenr_write_reg(0);
}
#endif
diff --git a/drivers/phy/phy-qcom-ufs-qmp-v3.h b/drivers/phy/phy-qcom-ufs-qmp-v3.h
index 757ed7464e44..0c9c3e7896bf 100644
--- a/drivers/phy/phy-qcom-ufs-qmp-v3.h
+++ b/drivers/phy/phy-qcom-ufs-qmp-v3.h
@@ -1,5 +1,5 @@
/*
- * 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
@@ -261,7 +261,7 @@ static struct ufs_qcom_phy_calibration phy_cal_table_rate_A_3_0_0[] = {
UFS_QCOM_PHY_CAL_ENTRY(QSERDES_RX0_UCDR_SO_SATURATION_AND_ENABLE, 0x4B),
UFS_QCOM_PHY_CAL_ENTRY(QSERDES_RX0_UCDR_PI_CONTROLS, 0xF1),
UFS_QCOM_PHY_CAL_ENTRY(QSERDES_RX0_UCDR_FASTLOCK_COUNT_LOW, 0x80),
- UFS_QCOM_PHY_CAL_ENTRY(UFS_PHY_RX_SIGDET_CTRL2, 0x6C),
+ UFS_QCOM_PHY_CAL_ENTRY(UFS_PHY_RX_SIGDET_CTRL2, 0x6E),
UFS_QCOM_PHY_CAL_ENTRY(UFS_PHY_TX_LARGE_AMP_DRV_LVL, 0x0A),
UFS_QCOM_PHY_CAL_ENTRY(UFS_PHY_TX_SMALL_AMP_DRV_LVL, 0x02),
UFS_QCOM_PHY_CAL_ENTRY(UFS_PHY_RX_SYM_RESYNC_CTRL, 0x03),
@@ -339,7 +339,7 @@ static struct ufs_qcom_phy_calibration phy_cal_table_rate_A_3_1_0[] = {
UFS_QCOM_PHY_CAL_ENTRY(QSERDES_RX1_UCDR_PI_CONTROLS, 0xF1),
UFS_QCOM_PHY_CAL_ENTRY(QSERDES_RX1_UCDR_FASTLOCK_COUNT_LOW, 0x80),
UFS_QCOM_PHY_CAL_ENTRY(UFS_PHY_MULTI_LANE_CTRL1, 0x02),
- UFS_QCOM_PHY_CAL_ENTRY(UFS_PHY_RX_SIGDET_CTRL2, 0x6C),
+ UFS_QCOM_PHY_CAL_ENTRY(UFS_PHY_RX_SIGDET_CTRL2, 0x6E),
UFS_QCOM_PHY_CAL_ENTRY(UFS_PHY_TX_LARGE_AMP_DRV_LVL, 0x0A),
UFS_QCOM_PHY_CAL_ENTRY(UFS_PHY_TX_SMALL_AMP_DRV_LVL, 0x02),
UFS_QCOM_PHY_CAL_ENTRY(UFS_PHY_RX_SYM_RESYNC_CTRL, 0x03),
diff --git a/drivers/pinctrl/qcom/pinctrl-lpi.c b/drivers/pinctrl/qcom/pinctrl-lpi.c
index 3fe41ee4c3c1..e383f4b42599 100644
--- a/drivers/pinctrl/qcom/pinctrl-lpi.c
+++ b/drivers/pinctrl/qcom/pinctrl-lpi.c
@@ -414,8 +414,10 @@ static int lpi_notifier_service_cb(struct notifier_block *this,
switch (opcode) {
case AUDIO_NOTIFIER_SERVICE_DOWN:
- if (initial_boot)
+ if (initial_boot) {
+ initial_boot = false;
break;
+ }
lpi_dev_up = false;
break;
case AUDIO_NOTIFIER_SERVICE_UP:
@@ -463,6 +465,7 @@ static void lpi_gpio_dbg_show_one(struct seq_file *s,
"pull up"
};
+ pctldev = pctldev ? : to_gpio_state(chip)->ctrl;
pindesc = pctldev->desc->pins[offset];
pad = pctldev->desc->pins[offset].drv_data;
ctl_reg = lpi_gpio_read(pad, LPI_GPIO_REG_DIR_CTL);
diff --git a/drivers/platform/msm/ipa/ipa_v2/ipa.c b/drivers/platform/msm/ipa/ipa_v2/ipa.c
index 0629d6bca49a..0d17fa58a853 100644
--- a/drivers/platform/msm/ipa/ipa_v2/ipa.c
+++ b/drivers/platform/msm/ipa/ipa_v2/ipa.c
@@ -1836,6 +1836,7 @@ static int ipa_q6_clean_q6_tables(void)
struct ipa_mem_buffer mem = { 0 };
u32 *entry;
u32 max_cmds = ipa_get_max_flt_rt_cmds(ipa_ctx->ipa_num_pipes);
+ gfp_t flag = GFP_KERNEL | (ipa_ctx->use_dma_zone ? GFP_DMA : 0);
mem.base = dma_alloc_coherent(ipa_ctx->pdev, 4, &mem.phys_base,
GFP_ATOMIC);
@@ -1856,7 +1857,7 @@ static int ipa_q6_clean_q6_tables(void)
}
cmd = kcalloc(max_cmds, sizeof(struct ipa_hw_imm_cmd_dma_shared_mem),
- GFP_KERNEL);
+ flag);
if (!cmd) {
IPAERR("failed to allocate memory\n");
retval = -ENOMEM;
diff --git a/drivers/platform/msm/ipa/ipa_v2/ipa_dp.c b/drivers/platform/msm/ipa/ipa_v2/ipa_dp.c
index 23c8a5059c3b..826d449edbd2 100644
--- a/drivers/platform/msm/ipa/ipa_v2/ipa_dp.c
+++ b/drivers/platform/msm/ipa/ipa_v2/ipa_dp.c
@@ -420,15 +420,17 @@ int ipa_send(struct ipa_sys_context *sys, u32 num_desc, struct ipa_desc *desc,
int i = 0;
int j;
int result;
- int fail_dma_wrap = 0;
uint size = num_desc * sizeof(struct sps_iovec);
- u32 mem_flag = GFP_ATOMIC;
+ gfp_t mem_flag = GFP_ATOMIC;
struct sps_iovec iov;
int ret;
+ gfp_t flag;
if (unlikely(!in_atomic))
mem_flag = GFP_KERNEL;
+ flag = mem_flag | (ipa_ctx->use_dma_zone ? GFP_DMA : 0);
+
if (num_desc == IPA_NUM_DESC_PER_SW_TX) {
transfer.iovec = dma_pool_alloc(ipa_ctx->dma_pool, mem_flag,
&dma_addr);
@@ -437,7 +439,7 @@ int ipa_send(struct ipa_sys_context *sys, u32 num_desc, struct ipa_desc *desc,
return -EFAULT;
}
} else {
- transfer.iovec = kmalloc(size, mem_flag);
+ transfer.iovec = kmalloc(size, flag);
if (!transfer.iovec) {
IPAERR("fail to alloc mem for sps xfr buff ");
IPAERR("num_desc = %d size = %d\n", num_desc, size);
@@ -457,7 +459,6 @@ int ipa_send(struct ipa_sys_context *sys, u32 num_desc, struct ipa_desc *desc,
spin_lock_bh(&sys->spinlock);
for (i = 0; i < num_desc; i++) {
- fail_dma_wrap = 0;
tx_pkt = kmem_cache_zalloc(ipa_ctx->tx_pkt_wrapper_cache,
mem_flag);
if (!tx_pkt) {
@@ -493,15 +494,6 @@ int ipa_send(struct ipa_sys_context *sys, u32 num_desc, struct ipa_desc *desc,
tx_pkt->mem.base,
tx_pkt->mem.size,
DMA_TO_DEVICE);
-
- if (dma_mapping_error(ipa_ctx->pdev,
- tx_pkt->mem.phys_base)) {
- IPAERR("dma_map_single ");
- IPAERR("failed\n");
- fail_dma_wrap = 1;
- goto failure;
- }
-
} else {
tx_pkt->mem.phys_base = desc[i].dma_address;
tx_pkt->no_unmap_dma = true;
@@ -522,10 +514,9 @@ int ipa_send(struct ipa_sys_context *sys, u32 num_desc, struct ipa_desc *desc,
}
}
- if (!tx_pkt->mem.phys_base) {
- IPAERR("failed to alloc tx wrapper\n");
- fail_dma_wrap = 1;
- goto failure;
+ if (dma_mapping_error(ipa_ctx->pdev, tx_pkt->mem.phys_base)) {
+ IPAERR("dma_map_single failed\n");
+ goto failure_dma_map;
}
tx_pkt->sys = sys;
@@ -580,27 +571,30 @@ int ipa_send(struct ipa_sys_context *sys, u32 num_desc, struct ipa_desc *desc,
spin_unlock_bh(&sys->spinlock);
return 0;
+failure_dma_map:
+ kmem_cache_free(ipa_ctx->tx_pkt_wrapper_cache, tx_pkt);
+
failure:
tx_pkt = transfer.user;
for (j = 0; j < i; j++) {
next_pkt = list_next_entry(tx_pkt, link);
list_del(&tx_pkt->link);
- if (desc[j].type != IPA_DATA_DESC_SKB_PAGED) {
- dma_unmap_single(ipa_ctx->pdev, tx_pkt->mem.phys_base,
- tx_pkt->mem.size,
- DMA_TO_DEVICE);
- } else {
- dma_unmap_page(ipa_ctx->pdev, tx_pkt->mem.phys_base,
- tx_pkt->mem.size,
- DMA_TO_DEVICE);
+ if (!tx_pkt->no_unmap_dma) {
+ if (desc[j].type != IPA_DATA_DESC_SKB_PAGED) {
+ dma_unmap_single(ipa_ctx->pdev,
+ tx_pkt->mem.phys_base,
+ tx_pkt->mem.size,
+ DMA_TO_DEVICE);
+ } else {
+ dma_unmap_page(ipa_ctx->pdev,
+ tx_pkt->mem.phys_base,
+ tx_pkt->mem.size,
+ DMA_TO_DEVICE);
+ }
}
kmem_cache_free(ipa_ctx->tx_pkt_wrapper_cache, tx_pkt);
tx_pkt = next_pkt;
}
- if (j < num_desc)
- /* last desc failed */
- if (fail_dma_wrap)
- kmem_cache_free(ipa_ctx->tx_pkt_wrapper_cache, tx_pkt);
if (transfer.iovec_phys) {
if (num_desc == IPA_NUM_DESC_PER_SW_TX) {
dma_pool_free(ipa_ctx->dma_pool, transfer.iovec,
@@ -1659,6 +1653,7 @@ int ipa2_tx_dp(enum ipa_client_type dst, struct sk_buff *skb,
struct ipa_sys_context *sys;
int src_ep_idx;
int num_frags, f;
+ gfp_t flag = GFP_ATOMIC | (ipa_ctx->use_dma_zone ? GFP_DMA : 0);
if (unlikely(!ipa_ctx)) {
IPAERR("IPA driver was not initialized\n");
@@ -1724,7 +1719,7 @@ int ipa2_tx_dp(enum ipa_client_type dst, struct sk_buff *skb,
if (dst_ep_idx != -1) {
/* SW data path */
- cmd = kzalloc(sizeof(struct ipa_ip_packet_init), GFP_ATOMIC);
+ cmd = kzalloc(sizeof(struct ipa_ip_packet_init), flag);
if (!cmd) {
IPAERR("failed to alloc immediate command object\n");
goto fail_gen;
diff --git a/drivers/platform/msm/ipa/ipa_v2/ipa_flt.c b/drivers/platform/msm/ipa/ipa_v2/ipa_flt.c
index d94e8f9f0e12..80514f6c738e 100644
--- a/drivers/platform/msm/ipa/ipa_v2/ipa_flt.c
+++ b/drivers/platform/msm/ipa/ipa_v2/ipa_flt.c
@@ -653,6 +653,7 @@ int __ipa_commit_flt_v1_1(enum ipa_ip_type ip)
struct ipa_ip_v6_filter_init *v6;
u16 avail;
u16 size;
+ gfp_t flag = GFP_KERNEL | (ipa_ctx->use_dma_zone ? GFP_DMA : 0);
mem = kmalloc(sizeof(struct ipa_mem_buffer), GFP_KERNEL);
if (!mem) {
@@ -669,7 +670,7 @@ int __ipa_commit_flt_v1_1(enum ipa_ip_type ip)
IPA_MEM_PART(v6_flt_size_ddr);
size = sizeof(struct ipa_ip_v6_filter_init);
}
- cmd = kmalloc(size, GFP_KERNEL);
+ cmd = kmalloc(size, flag);
if (!cmd) {
IPAERR("failed to alloc immediate command object\n");
goto fail_alloc_cmd;
@@ -842,6 +843,7 @@ int __ipa_commit_flt_v2(enum ipa_ip_type ip)
int num_desc = 0;
int i;
u16 avail;
+ gfp_t flag = GFP_ATOMIC | (ipa_ctx->use_dma_zone ? GFP_DMA : 0);
desc = kzalloc(16 * sizeof(*desc), GFP_ATOMIC);
if (desc == NULL) {
@@ -850,7 +852,7 @@ int __ipa_commit_flt_v2(enum ipa_ip_type ip)
goto fail_desc;
}
- cmd = kzalloc(16 * sizeof(*cmd), GFP_ATOMIC);
+ cmd = kzalloc(16 * sizeof(*cmd), flag);
if (cmd == NULL) {
IPAERR("fail to alloc cmd blob ip %d\n", ip);
rc = -ENOMEM;
diff --git a/drivers/platform/msm/ipa/ipa_v2/ipa_hdr.c b/drivers/platform/msm/ipa/ipa_v2/ipa_hdr.c
index f43981f15c31..40c1971dfe96 100644
--- a/drivers/platform/msm/ipa/ipa_v2/ipa_hdr.c
+++ b/drivers/platform/msm/ipa/ipa_v2/ipa_hdr.c
@@ -176,6 +176,7 @@ int __ipa_commit_hdr_v1_1(void)
struct ipa_mem_buffer *mem;
struct ipa_hdr_init_local *cmd;
u16 len;
+ gfp_t flag = GFP_KERNEL | (ipa_ctx->use_dma_zone ? GFP_DMA : 0);
mem = kmalloc(sizeof(struct ipa_mem_buffer), GFP_KERNEL);
if (!mem) {
@@ -190,7 +191,7 @@ int __ipa_commit_hdr_v1_1(void)
* we can use init_local ptr for init_system due to layout of the
* struct
*/
- cmd = kmalloc(len, GFP_KERNEL);
+ cmd = kmalloc(len, flag);
if (!cmd) {
IPAERR("failed to alloc immediate command object\n");
goto fail_alloc_cmd;
@@ -663,6 +664,7 @@ static int __ipa_add_hdr(struct ipa_hdr_add *hdr)
struct ipa_hdr_tbl *htbl = &ipa_ctx->hdr_tbl;
int id;
int mem_size;
+ gfp_t flag = GFP_KERNEL | (ipa_ctx->use_dma_zone ? GFP_DMA : 0);
if (hdr->hdr_len == 0 || hdr->hdr_len > IPA_HDR_MAX_SIZE) {
IPAERR("bad parm\n");
@@ -674,7 +676,7 @@ static int __ipa_add_hdr(struct ipa_hdr_add *hdr)
goto error;
}
- entry = kmem_cache_zalloc(ipa_ctx->hdr_cache, GFP_KERNEL);
+ entry = kmem_cache_zalloc(ipa_ctx->hdr_cache, flag);
if (!entry) {
IPAERR("failed to alloc hdr object\n");
goto error;
diff --git a/drivers/platform/msm/ipa/ipa_v2/ipa_nat.c b/drivers/platform/msm/ipa/ipa_v2/ipa_nat.c
index 314b09593026..5dd8b225217d 100644
--- a/drivers/platform/msm/ipa/ipa_v2/ipa_nat.c
+++ b/drivers/platform/msm/ipa/ipa_v2/ipa_nat.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012-2016, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-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
@@ -325,6 +325,7 @@ int ipa2_nat_init_cmd(struct ipa_ioc_v4_nat_init *init)
int result;
u32 offset = 0;
size_t tmp;
+ gfp_t flag = GFP_KERNEL | (ipa_ctx->use_dma_zone ? GFP_DMA : 0);
IPADBG("\n");
if (init->table_entries == 0) {
@@ -406,7 +407,7 @@ int ipa2_nat_init_cmd(struct ipa_ioc_v4_nat_init *init)
memset(&desc, 0, sizeof(desc));
/* NO-OP IC for ensuring that IPA pipeline is empty */
- reg_write_nop = kzalloc(sizeof(*reg_write_nop), GFP_KERNEL);
+ reg_write_nop = kzalloc(sizeof(*reg_write_nop), flag);
if (!reg_write_nop) {
IPAERR("no mem\n");
result = -ENOMEM;
@@ -424,7 +425,7 @@ int ipa2_nat_init_cmd(struct ipa_ioc_v4_nat_init *init)
desc[0].pyld = (void *)reg_write_nop;
desc[0].len = sizeof(*reg_write_nop);
- cmd = kmalloc(size, GFP_KERNEL);
+ cmd = kmalloc(size, flag);
if (!cmd) {
IPAERR("Failed to alloc immediate command object\n");
result = -ENOMEM;
@@ -569,6 +570,7 @@ int ipa2_nat_dma_cmd(struct ipa_ioc_nat_dma_cmd *dma)
struct ipa_desc *desc = NULL;
u16 size = 0, cnt = 0;
int ret = 0;
+ gfp_t flag = GFP_KERNEL | (ipa_ctx->use_dma_zone ? GFP_DMA : 0);
IPADBG("\n");
if (dma->entries <= 0) {
@@ -652,7 +654,7 @@ int ipa2_nat_dma_cmd(struct ipa_ioc_nat_dma_cmd *dma)
}
size = sizeof(struct ipa_nat_dma);
- cmd = kzalloc(size, GFP_KERNEL);
+ cmd = kzalloc(size, flag);
if (cmd == NULL) {
IPAERR("Failed to alloc memory\n");
ret = -ENOMEM;
@@ -660,7 +662,7 @@ int ipa2_nat_dma_cmd(struct ipa_ioc_nat_dma_cmd *dma)
}
/* NO-OP IC for ensuring that IPA pipeline is empty */
- reg_write_nop = kzalloc(sizeof(*reg_write_nop), GFP_KERNEL);
+ reg_write_nop = kzalloc(sizeof(*reg_write_nop), flag);
if (!reg_write_nop) {
IPAERR("Failed to alloc memory\n");
ret = -ENOMEM;
@@ -754,6 +756,7 @@ int ipa2_nat_del_cmd(struct ipa_ioc_v4_nat_del *del)
u8 mem_type = IPA_NAT_SHARED_MEMORY;
u32 base_addr = IPA_NAT_PHYS_MEM_OFFSET;
int result;
+ gfp_t flag = GFP_KERNEL | (ipa_ctx->use_dma_zone ? GFP_DMA : 0);
IPADBG("\n");
if (ipa_ctx->nat_mem.is_tmp_mem) {
@@ -770,7 +773,7 @@ int ipa2_nat_del_cmd(struct ipa_ioc_v4_nat_del *del)
memset(&desc, 0, sizeof(desc));
/* NO-OP IC for ensuring that IPA pipeline is empty */
- reg_write_nop = kzalloc(sizeof(*reg_write_nop), GFP_KERNEL);
+ reg_write_nop = kzalloc(sizeof(*reg_write_nop), flag);
if (!reg_write_nop) {
IPAERR("no mem\n");
result = -ENOMEM;
@@ -788,7 +791,7 @@ int ipa2_nat_del_cmd(struct ipa_ioc_v4_nat_del *del)
desc[0].pyld = (void *)reg_write_nop;
desc[0].len = sizeof(*reg_write_nop);
- cmd = kmalloc(size, GFP_KERNEL);
+ cmd = kmalloc(size, flag);
if (cmd == NULL) {
IPAERR("Failed to alloc immediate command object\n");
result = -ENOMEM;
diff --git a/drivers/platform/msm/ipa/ipa_v2/ipa_rt.c b/drivers/platform/msm/ipa/ipa_v2/ipa_rt.c
index 4b6bc5b61bfc..2214dfe89df3 100644
--- a/drivers/platform/msm/ipa/ipa_v2/ipa_rt.c
+++ b/drivers/platform/msm/ipa/ipa_v2/ipa_rt.c
@@ -525,6 +525,7 @@ int __ipa_commit_rt_v1_1(enum ipa_ip_type ip)
struct ipa_ip_v6_routing_init *v6;
u16 avail;
u16 size;
+ gfp_t flag = GFP_KERNEL | (ipa_ctx->use_dma_zone ? GFP_DMA : 0);
mem = kmalloc(sizeof(struct ipa_mem_buffer), GFP_KERNEL);
if (!mem) {
@@ -541,7 +542,7 @@ int __ipa_commit_rt_v1_1(enum ipa_ip_type ip)
IPA_MEM_PART(v6_rt_size_ddr);
size = sizeof(struct ipa_ip_v6_routing_init);
}
- cmd = kmalloc(size, GFP_KERNEL);
+ cmd = kmalloc(size, flag);
if (!cmd) {
IPAERR("failed to alloc immediate command object\n");
goto fail_alloc_cmd;
diff --git a/drivers/platform/msm/ipa/ipa_v2/ipa_utils.c b/drivers/platform/msm/ipa/ipa_v2/ipa_utils.c
index be3c890db25c..9943095abe30 100644
--- a/drivers/platform/msm/ipa/ipa_v2/ipa_utils.c
+++ b/drivers/platform/msm/ipa/ipa_v2/ipa_utils.c
@@ -4507,6 +4507,7 @@ int ipa_tag_process(struct ipa_desc desc[],
int res;
struct ipa_tag_completion *comp;
int ep_idx;
+ gfp_t flag = GFP_KERNEL | (ipa_ctx->use_dma_zone ? GFP_DMA : 0);
/* Not enough room for the required descriptors for the tag process */
if (IPA_TAG_MAX_DESC - descs_num < REQUIRED_TAG_PROCESS_DESCRIPTORS) {
@@ -4524,7 +4525,7 @@ int ipa_tag_process(struct ipa_desc desc[],
}
sys = ipa_ctx->ep[ep_idx].sys;
- tag_desc = kzalloc(sizeof(*tag_desc) * IPA_TAG_MAX_DESC, GFP_KERNEL);
+ tag_desc = kzalloc(sizeof(*tag_desc) * IPA_TAG_MAX_DESC, flag);
if (!tag_desc) {
IPAERR("failed to allocate memory\n");
res = -ENOMEM;
diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_dp.c b/drivers/platform/msm/ipa/ipa_v3/ipa_dp.c
index 0492fa27c5b7..6a3a89e2cf8d 100644
--- a/drivers/platform/msm/ipa/ipa_v3/ipa_dp.c
+++ b/drivers/platform/msm/ipa/ipa_v3/ipa_dp.c
@@ -356,7 +356,7 @@ int ipa3_send_one(struct ipa3_sys_context *sys, struct ipa3_desc *desc,
dma_address = desc->dma_address;
tx_pkt->no_unmap_dma = true;
}
- if (!dma_address) {
+ if (dma_mapping_error(ipa3_ctx->pdev, dma_address)) {
IPAERR("failed to DMA wrap\n");
goto fail_dma_map;
}
@@ -471,7 +471,6 @@ int ipa3_send(struct ipa3_sys_context *sys,
int i = 0;
int j;
int result;
- int fail_dma_wrap = 0;
uint size;
u32 mem_flag = GFP_ATOMIC;
int ipa_ep_idx;
@@ -527,7 +526,7 @@ int ipa3_send(struct ipa3_sys_context *sys,
}
dma_addr = dma_map_single(ipa3_ctx->pdev,
transfer.iovec, size, DMA_TO_DEVICE);
- if (!dma_addr) {
+ if (dma_mapping_error(ipa3_ctx->pdev, dma_addr)) {
IPAERR("dma_map_single failed\n");
kfree(transfer.iovec);
return -EFAULT;
@@ -540,7 +539,6 @@ int ipa3_send(struct ipa3_sys_context *sys,
spin_lock_bh(&sys->spinlock);
for (i = 0; i < num_desc; i++) {
- fail_dma_wrap = 0;
tx_pkt = kmem_cache_zalloc(ipa3_ctx->tx_pkt_wrapper_cache,
mem_flag);
if (!tx_pkt) {
@@ -563,7 +561,7 @@ int ipa3_send(struct ipa3_sys_context *sys,
if (ipa_populate_tag_field(&desc[i], tx_pkt,
&tag_pyld_ret)) {
IPAERR("Failed to populate tag field\n");
- goto failure;
+ goto failure_dma_map;
}
}
@@ -579,11 +577,6 @@ int ipa3_send(struct ipa3_sys_context *sys,
tx_pkt->mem.base,
tx_pkt->mem.size,
DMA_TO_DEVICE);
- if (!tx_pkt->mem.phys_base) {
- IPAERR("failed to do dma map.\n");
- fail_dma_wrap = 1;
- goto failure;
- }
} else {
tx_pkt->mem.phys_base =
desc[i].dma_address;
@@ -599,17 +592,17 @@ int ipa3_send(struct ipa3_sys_context *sys,
desc[i].frag,
0, tx_pkt->mem.size,
DMA_TO_DEVICE);
- if (!tx_pkt->mem.phys_base) {
- IPAERR("dma map failed\n");
- fail_dma_wrap = 1;
- goto failure;
- }
} else {
tx_pkt->mem.phys_base =
desc[i].dma_address;
tx_pkt->no_unmap_dma = true;
}
}
+ if (dma_mapping_error(ipa3_ctx->pdev, tx_pkt->mem.phys_base)) {
+ IPAERR("failed to do dma map.\n");
+ goto failure_dma_map;
+ }
+
tx_pkt->sys = sys;
tx_pkt->callback = desc[i].callback;
tx_pkt->user1 = desc[i].user1;
@@ -704,29 +697,31 @@ int ipa3_send(struct ipa3_sys_context *sys,
spin_unlock_bh(&sys->spinlock);
return 0;
+failure_dma_map:
+ kmem_cache_free(ipa3_ctx->tx_pkt_wrapper_cache, tx_pkt);
+
failure:
ipahal_destroy_imm_cmd(tag_pyld_ret);
tx_pkt = tx_pkt_first;
for (j = 0; j < i; j++) {
next_pkt = list_next_entry(tx_pkt, link);
list_del(&tx_pkt->link);
- if (desc[j].type != IPA_DATA_DESC_SKB_PAGED) {
- dma_unmap_single(ipa3_ctx->pdev, tx_pkt->mem.phys_base,
- tx_pkt->mem.size,
- DMA_TO_DEVICE);
- } else {
- dma_unmap_page(ipa3_ctx->pdev, tx_pkt->mem.phys_base,
- tx_pkt->mem.size,
- DMA_TO_DEVICE);
+
+ if (!tx_pkt->no_unmap_dma) {
+ if (desc[j].type != IPA_DATA_DESC_SKB_PAGED) {
+ dma_unmap_single(ipa3_ctx->pdev,
+ tx_pkt->mem.phys_base,
+ tx_pkt->mem.size, DMA_TO_DEVICE);
+ } else {
+ dma_unmap_page(ipa3_ctx->pdev,
+ tx_pkt->mem.phys_base,
+ tx_pkt->mem.size,
+ DMA_TO_DEVICE);
+ }
}
kmem_cache_free(ipa3_ctx->tx_pkt_wrapper_cache, tx_pkt);
tx_pkt = next_pkt;
}
- if (j < num_desc)
- /* last desc failed */
- if (fail_dma_wrap)
- kmem_cache_free(ipa3_ctx->tx_pkt_wrapper_cache, tx_pkt);
-
if (ipa3_ctx->transport_prototype == IPA_TRANSPORT_TYPE_GSI) {
kfree(gsi_xfer_elem_array);
} else {
@@ -1973,8 +1968,7 @@ begin:
rx_pkt->data.dma_addr = dma_map_single(ipa3_ctx->pdev, ptr,
sys->rx_buff_sz,
DMA_FROM_DEVICE);
- if (rx_pkt->data.dma_addr == 0 ||
- rx_pkt->data.dma_addr == ~0) {
+ if (dma_mapping_error(ipa3_ctx->pdev, rx_pkt->data.dma_addr)) {
pr_err_ratelimited("%s dma map fail %p for %p sys=%p\n",
__func__, (void *)rx_pkt->data.dma_addr,
ptr, sys);
@@ -2141,8 +2135,7 @@ static void ipa3_alloc_wlan_rx_common_cache(u32 size)
ptr = skb_put(rx_pkt->data.skb, IPA_WLAN_RX_BUFF_SZ);
rx_pkt->data.dma_addr = dma_map_single(ipa3_ctx->pdev, ptr,
IPA_WLAN_RX_BUFF_SZ, DMA_FROM_DEVICE);
- if (rx_pkt->data.dma_addr == 0 ||
- rx_pkt->data.dma_addr == ~0) {
+ if (dma_mapping_error(ipa3_ctx->pdev, rx_pkt->data.dma_addr)) {
IPAERR("dma_map_single failure %p for %p\n",
(void *)rx_pkt->data.dma_addr, ptr);
goto fail_dma_mapping;
@@ -2213,8 +2206,7 @@ static void ipa3_replenish_rx_cache(struct ipa3_sys_context *sys)
rx_pkt->data.dma_addr = dma_map_single(ipa3_ctx->pdev, ptr,
sys->rx_buff_sz,
DMA_FROM_DEVICE);
- if (rx_pkt->data.dma_addr == 0 ||
- rx_pkt->data.dma_addr == ~0) {
+ if (dma_mapping_error(ipa3_ctx->pdev, rx_pkt->data.dma_addr)) {
IPAERR("dma_map_single failure %p for %p\n",
(void *)rx_pkt->data.dma_addr, ptr);
goto fail_dma_mapping;
@@ -2304,8 +2296,8 @@ static void ipa3_replenish_rx_cache_recycle(struct ipa3_sys_context *sys)
ptr = skb_put(rx_pkt->data.skb, sys->rx_buff_sz);
rx_pkt->data.dma_addr = dma_map_single(ipa3_ctx->pdev,
ptr, sys->rx_buff_sz, DMA_FROM_DEVICE);
- if (rx_pkt->data.dma_addr == 0 ||
- rx_pkt->data.dma_addr == ~0) {
+ if (dma_mapping_error(ipa3_ctx->pdev,
+ rx_pkt->data.dma_addr)) {
IPAERR("dma_map_single failure %p for %p\n",
(void *)rx_pkt->data.dma_addr, ptr);
goto fail_dma_mapping;
@@ -2320,8 +2312,8 @@ static void ipa3_replenish_rx_cache_recycle(struct ipa3_sys_context *sys)
ptr = skb_put(rx_pkt->data.skb, sys->rx_buff_sz);
rx_pkt->data.dma_addr = dma_map_single(ipa3_ctx->pdev,
ptr, sys->rx_buff_sz, DMA_FROM_DEVICE);
- if (rx_pkt->data.dma_addr == 0 ||
- rx_pkt->data.dma_addr == ~0) {
+ if (dma_mapping_error(ipa3_ctx->pdev,
+ rx_pkt->data.dma_addr)) {
IPAERR("dma_map_single failure %p for %p\n",
(void *)rx_pkt->data.dma_addr, ptr);
goto fail_dma_mapping;
diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_hdr.c b/drivers/platform/msm/ipa/ipa_v3/ipa_hdr.c
index 69dca7666346..e197ee8b06dd 100644
--- a/drivers/platform/msm/ipa/ipa_v3/ipa_hdr.c
+++ b/drivers/platform/msm/ipa/ipa_v3/ipa_hdr.c
@@ -494,6 +494,10 @@ static int __ipa_add_hdr(struct ipa_hdr_add *hdr)
entry->hdr,
entry->hdr_len,
DMA_TO_DEVICE);
+ if (dma_mapping_error(ipa3_ctx->pdev, entry->phys_base)) {
+ IPAERR("dma_map_single failure for entry\n");
+ goto fail_dma_mapping;
+ }
} else {
entry->is_hdr_proc_ctx = false;
if (list_empty(&htbl->head_free_offset_list[bin])) {
@@ -569,6 +573,9 @@ fail_add_proc_ctx:
list_del(&entry->link);
dma_unmap_single(ipa3_ctx->pdev, entry->phys_base,
entry->hdr_len, DMA_TO_DEVICE);
+fail_dma_mapping:
+ entry->is_hdr_proc_ctx = false;
+
bad_hdr_len:
entry->cookie = 0;
kmem_cache_free(ipa3_ctx->hdr_cache, entry);
diff --git a/drivers/platform/msm/mhi/mhi_bhi.c b/drivers/platform/msm/mhi/mhi_bhi.c
index 5b05270b1e66..4354b2600472 100644
--- a/drivers/platform/msm/mhi/mhi_bhi.c
+++ b/drivers/platform/msm/mhi/mhi_bhi.c
@@ -249,6 +249,13 @@ int bhi_rddm(struct mhi_device_ctxt *mhi_dev_ctxt, bool in_panic)
{
struct bhi_ctxt_t *bhi_ctxt = &mhi_dev_ctxt->bhi_ctxt;
struct bhie_vec_table *rddm_table = &bhi_ctxt->rddm_table;
+ struct bhie_mem_info *bhie_mem_info;
+ u32 rx_sequence, val, current_seq;
+ u32 timeout = (bhi_ctxt->poll_timeout * 1000) / BHIE_RDDM_DELAY_TIME_US;
+ int i;
+ u32 cur_exec, prev_exec = 0;
+ u32 state, prev_state = 0;
+ u32 rx_status, prev_status = 0;
if (!rddm_table->bhie_mem_info) {
mhi_log(mhi_dev_ctxt, MHI_MSG_INFO, "RDDM table == NULL\n");
@@ -258,9 +265,93 @@ int bhi_rddm(struct mhi_device_ctxt *mhi_dev_ctxt, bool in_panic)
if (!in_panic)
return bhi_rddm_graceful(mhi_dev_ctxt);
- mhi_log(mhi_dev_ctxt, MHI_MSG_ERROR,
- "RDDM collection in panic not yet supported\n");
- return -EINVAL;
+ /*
+ * Below code should only be executed during kernel panic,
+ * we expect other cores to be shutting down while we're
+ * executing rddm transfer. After returning from this function,
+ * we expect device to reset.
+ */
+
+ /* Trigger device into RDDM */
+ mhi_log(mhi_dev_ctxt, MHI_MSG_INFO, "pm_state:0x%x mhi_state:%s\n",
+ mhi_dev_ctxt->mhi_pm_state,
+ TO_MHI_STATE_STR(mhi_dev_ctxt->mhi_state));
+ if (!MHI_REG_ACCESS_VALID(mhi_dev_ctxt->mhi_pm_state)) {
+ mhi_log(mhi_dev_ctxt, MHI_MSG_ERROR,
+ "Register access not allowed\n");
+ return -EIO;
+ }
+
+ /*
+ * Normally we only set mhi_pm_state after grabbing pm_xfer_lock as a
+ * write, by function mhi_tryset_pm_state. Since we're in a kernel
+ * panic, we will set pm state w/o grabbing xfer lock. We're setting
+ * pm_state to LD as a safety precautions. If another core in middle
+ * of register access this should deter it. However, there is no
+ * no gurantee change will take effect.
+ */
+ mhi_dev_ctxt->mhi_pm_state = MHI_PM_LD_ERR_FATAL_DETECT;
+ /* change should take effect immediately */
+ smp_wmb();
+
+ bhie_mem_info = &rddm_table->
+ bhie_mem_info[rddm_table->segment_count - 1];
+ rx_sequence = rddm_table->sequence++;
+
+ /* program the vector table */
+ mhi_log(mhi_dev_ctxt, MHI_MSG_INFO, "Programming RXVEC table\n");
+ val = HIGH_WORD(bhie_mem_info->phys_addr);
+ mhi_reg_write(mhi_dev_ctxt, bhi_ctxt->bhi_base,
+ BHIE_RXVECADDR_HIGH_OFFS, val);
+ val = LOW_WORD(bhie_mem_info->phys_addr);
+ mhi_reg_write(mhi_dev_ctxt, bhi_ctxt->bhi_base, BHIE_RXVECADDR_LOW_OFFS,
+ val);
+ val = (u32)bhie_mem_info->size;
+ mhi_reg_write(mhi_dev_ctxt, bhi_ctxt->bhi_base, BHIE_RXVECSIZE_OFFS,
+ val);
+ mhi_reg_write_field(mhi_dev_ctxt, bhi_ctxt->bhi_base, BHIE_RXVECDB_OFFS,
+ BHIE_TXVECDB_SEQNUM_BMSK, BHIE_TXVECDB_SEQNUM_SHFT,
+ rx_sequence);
+
+ /* trigger device into rddm */
+ mhi_log(mhi_dev_ctxt, MHI_MSG_INFO,
+ "Triggering Device into RDDM mode\n");
+ mhi_set_m_state(mhi_dev_ctxt, MHI_STATE_SYS_ERR);
+ i = 0;
+
+ while (timeout--) {
+ cur_exec = mhi_reg_read(bhi_ctxt->bhi_base, BHI_EXECENV);
+ state = mhi_get_m_state(mhi_dev_ctxt);
+ rx_status = mhi_reg_read(bhi_ctxt->bhi_base,
+ BHIE_RXVECSTATUS_OFFS);
+ /* if reg. values changed or each sec (udelay(1000)) log it */
+ if (cur_exec != prev_exec || state != prev_state ||
+ rx_status != prev_status || !(i & (SZ_1K - 1))) {
+ mhi_log(mhi_dev_ctxt, MHI_MSG_INFO,
+ "EXECENV:0x%x MHISTATE:0x%x RXSTATUS:0x%x\n",
+ cur_exec, state, rx_status);
+ prev_exec = cur_exec;
+ prev_state = state;
+ prev_status = rx_status;
+ };
+ current_seq = (rx_status & BHIE_TXVECSTATUS_SEQNUM_BMSK) >>
+ BHIE_TXVECSTATUS_SEQNUM_SHFT;
+ rx_status = (rx_status & BHIE_TXVECSTATUS_STATUS_BMSK) >>
+ BHIE_TXVECSTATUS_STATUS_SHFT;
+
+ if ((rx_status == BHIE_TXVECSTATUS_STATUS_XFER_COMPL) &&
+ (current_seq == rx_sequence)) {
+ mhi_log(mhi_dev_ctxt, MHI_MSG_INFO,
+ "rddm transfer completed\n");
+ return 0;
+ }
+ udelay(BHIE_RDDM_DELAY_TIME_US);
+ i++;
+ }
+
+ mhi_log(mhi_dev_ctxt, MHI_MSG_ERROR, "rddm transfer timeout\n");
+
+ return -EIO;
}
static int bhi_load_firmware(struct mhi_device_ctxt *mhi_dev_ctxt,
@@ -439,7 +530,6 @@ void bhi_firmware_download(struct work_struct *work)
struct bhi_ctxt_t *bhi_ctxt;
struct bhie_mem_info mem_info;
int ret;
- long timeout;
mhi_dev_ctxt = container_of(work, struct mhi_device_ctxt,
bhi_ctxt.fw_load_work);
@@ -448,7 +538,14 @@ void bhi_firmware_download(struct work_struct *work)
mhi_log(mhi_dev_ctxt, MHI_MSG_INFO, "Enter\n");
wait_event_interruptible(*mhi_dev_ctxt->mhi_ev_wq.bhi_event,
- mhi_dev_ctxt->mhi_state == MHI_STATE_BHI);
+ mhi_dev_ctxt->mhi_state == MHI_STATE_BHI ||
+ mhi_dev_ctxt->mhi_pm_state == MHI_PM_LD_ERR_FATAL_DETECT);
+ if (mhi_dev_ctxt->mhi_pm_state == MHI_PM_LD_ERR_FATAL_DETECT ||
+ mhi_dev_ctxt->mhi_state != MHI_STATE_BHI) {
+ mhi_log(mhi_dev_ctxt, MHI_MSG_ERROR,
+ "MHI is not in valid state for firmware download\n");
+ return;
+ }
/* PBL image is the first segment in firmware vector table */
mem_info = *bhi_ctxt->fw_table.bhie_mem_info;
@@ -462,10 +559,12 @@ void bhi_firmware_download(struct work_struct *work)
mhi_init_state_transition(mhi_dev_ctxt,
STATE_TRANSITION_RESET);
- timeout = wait_event_timeout(*mhi_dev_ctxt->mhi_ev_wq.bhi_event,
- mhi_dev_ctxt->dev_exec_env == MHI_EXEC_ENV_BHIE,
- msecs_to_jiffies(bhi_ctxt->poll_timeout));
- if (!timeout) {
+ wait_event_timeout(*mhi_dev_ctxt->mhi_ev_wq.bhi_event,
+ mhi_dev_ctxt->dev_exec_env == MHI_EXEC_ENV_BHIE ||
+ mhi_dev_ctxt->mhi_pm_state == MHI_PM_LD_ERR_FATAL_DETECT,
+ msecs_to_jiffies(bhi_ctxt->poll_timeout));
+ if (mhi_dev_ctxt->mhi_pm_state == MHI_PM_LD_ERR_FATAL_DETECT ||
+ mhi_dev_ctxt->dev_exec_env != MHI_EXEC_ENV_BHIE) {
mhi_log(mhi_dev_ctxt, MHI_MSG_ERROR,
"Failed to Enter EXEC_ENV_BHIE\n");
return;
@@ -598,6 +697,7 @@ void bhi_exit(struct mhi_device_ctxt *mhi_dev_ctxt)
dma_free_coherent(dev, bhie_mem_info->alloc_size,
bhie_mem_info->pre_aligned,
bhie_mem_info->dma_handle);
+ kfree(fw_table->bhie_mem_info);
fw_table->bhie_mem_info = NULL;
/* vector table is the last entry in bhie_mem_info */
fw_table->bhi_vec_entry = NULL;
@@ -613,6 +713,7 @@ void bhi_exit(struct mhi_device_ctxt *mhi_dev_ctxt)
dma_free_coherent(dev, bhie_mem_info->alloc_size,
bhie_mem_info->pre_aligned,
bhie_mem_info->dma_handle);
+ kfree(rddm_table->bhie_mem_info);
rddm_table->bhie_mem_info = NULL;
rddm_table->bhi_vec_entry = NULL;
}
diff --git a/drivers/platform/msm/mhi/mhi_bhi.h b/drivers/platform/msm/mhi/mhi_bhi.h
index 8f7b3d69347c..8f9bc52bbbe0 100644
--- a/drivers/platform/msm/mhi/mhi_bhi.h
+++ b/drivers/platform/msm/mhi/mhi_bhi.h
@@ -87,6 +87,7 @@
#define BHI_POLL_SLEEP_TIME_MS 100
#define BHI_POLL_TIMEOUT_MS 2000
+#define BHIE_RDDM_DELAY_TIME_US (1000)
int bhi_probe(struct mhi_device_ctxt *mhi_dev_ctxt);
void bhi_firmware_download(struct work_struct *work);
diff --git a/drivers/platform/msm/mhi/mhi_iface.c b/drivers/platform/msm/mhi/mhi_iface.c
index 64a09a2f9fbb..a5936ea5a6aa 100644
--- a/drivers/platform/msm/mhi/mhi_iface.c
+++ b/drivers/platform/msm/mhi/mhi_iface.c
@@ -153,16 +153,19 @@ static int mhi_pci_probe(struct pci_dev *pcie_device,
u32 slot = PCI_SLOT(pcie_device->devfn);
unsigned long msi_requested, msi_required;
struct msm_pcie_register_event *mhi_pci_link_event;
+ struct pcie_core_info *core;
+ int i;
+ char node[32];
/* Find correct device context based on bdf & dev_id */
mutex_lock(&mhi_device_drv->lock);
list_for_each_entry(itr, &mhi_device_drv->head, node) {
- struct pcie_core_info *core = &itr->core;
-
- if (core->domain == domain &&
- core->bus == bus &&
- core->dev_id == dev_id &&
+ core = &itr->core;
+ if (core->domain == domain && core->bus == bus &&
+ (core->dev_id == PCI_ANY_ID || (core->dev_id == dev_id)) &&
core->slot == slot) {
+ /* change default dev_id to actual dev_id */
+ core->dev_id = dev_id;
mhi_dev_ctxt = itr;
break;
}
@@ -171,6 +174,11 @@ static int mhi_pci_probe(struct pci_dev *pcie_device,
if (!mhi_dev_ctxt)
return -EPROBE_DEFER;
+ snprintf(node, sizeof(node), "mhi_%04x_%02u.%02u.%02u",
+ core->dev_id, core->domain, core->bus, core->slot);
+ mhi_dev_ctxt->mhi_ipc_log =
+ ipc_log_context_create(MHI_IPC_LOG_PAGES, node, 0);
+
mhi_log(mhi_dev_ctxt, MHI_MSG_INFO,
"Processing Domain:%02u Bus:%04u dev:0x%04x slot:%04u\n",
domain, bus, dev_id, slot);
@@ -280,9 +288,22 @@ static int mhi_pci_probe(struct pci_dev *pcie_device,
mutex_lock(&mhi_dev_ctxt->pm_lock);
write_lock_irq(&mhi_dev_ctxt->pm_xfer_lock);
mhi_dev_ctxt->mhi_pm_state = MHI_PM_POR;
- ret_val = set_mhi_base_state(mhi_dev_ctxt);
+ write_unlock_irq(&mhi_dev_ctxt->pm_xfer_lock);
+ /* notify all registered clients we probed */
+ for (i = 0; i < MHI_MAX_CHANNELS; i++) {
+ struct mhi_client_handle *client_handle =
+ mhi_dev_ctxt->client_handle_list[i];
+
+ if (!client_handle)
+ continue;
+ client_handle->dev_id = core->dev_id;
+ mhi_notify_client(client_handle, MHI_CB_MHI_PROBED);
+ }
+ write_lock_irq(&mhi_dev_ctxt->pm_xfer_lock);
+ ret_val = set_mhi_base_state(mhi_dev_ctxt);
write_unlock_irq(&mhi_dev_ctxt->pm_xfer_lock);
+
if (ret_val) {
mhi_log(mhi_dev_ctxt,
MHI_MSG_ERROR,
@@ -344,7 +365,6 @@ static int mhi_plat_probe(struct platform_device *pdev)
int r = 0, len;
struct mhi_device_ctxt *mhi_dev_ctxt;
struct pcie_core_info *core;
- char node[32];
struct device_node *of_node = pdev->dev.of_node;
u64 address_window[2];
@@ -377,7 +397,7 @@ static int mhi_plat_probe(struct platform_device *pdev)
core = &mhi_dev_ctxt->core;
r = of_property_read_u32(of_node, "qcom,pci-dev_id", &core->dev_id);
if (r)
- return r;
+ core->dev_id = PCI_ANY_ID;
r = of_property_read_u32(of_node, "qcom,pci-slot", &core->slot);
if (r)
@@ -391,14 +411,6 @@ static int mhi_plat_probe(struct platform_device *pdev)
if (r)
return r;
- snprintf(node, sizeof(node),
- "mhi_%04x_%02u.%02u.%02u",
- core->dev_id, core->domain, core->bus, core->slot);
- mhi_dev_ctxt->mhi_ipc_log =
- ipc_log_context_create(MHI_IPC_LOG_PAGES, node, 0);
- if (!mhi_dev_ctxt->mhi_ipc_log)
- pr_err("%s: Error creating ipc_log buffer\n", __func__);
-
r = of_property_read_u32(of_node, "qcom,mhi-ready-timeout",
&mhi_dev_ctxt->poll_reset_timeout_ms);
if (r)
@@ -407,10 +419,6 @@ static int mhi_plat_probe(struct platform_device *pdev)
mhi_dev_ctxt->dev_space.start_win_addr = address_window[0];
mhi_dev_ctxt->dev_space.end_win_addr = address_window[1];
- mhi_log(mhi_dev_ctxt, MHI_MSG_INFO,
- "Start Addr:0x%llx End_Addr:0x%llx\n",
- mhi_dev_ctxt->dev_space.start_win_addr,
- mhi_dev_ctxt->dev_space.end_win_addr);
r = of_property_read_u32(of_node, "qcom,bhi-alignment",
&mhi_dev_ctxt->bhi_ctxt.alignment);
@@ -471,7 +479,6 @@ static int mhi_plat_probe(struct platform_device *pdev)
mutex_lock(&mhi_device_drv->lock);
list_add_tail(&mhi_dev_ctxt->node, &mhi_device_drv->head);
mutex_unlock(&mhi_device_drv->lock);
- mhi_log(mhi_dev_ctxt, MHI_MSG_INFO, "Exited\n");
return 0;
}
diff --git a/drivers/platform/msm/mhi/mhi_macros.h b/drivers/platform/msm/mhi/mhi_macros.h
index fc0e6f4bc27d..04ecf13991b3 100644
--- a/drivers/platform/msm/mhi/mhi_macros.h
+++ b/drivers/platform/msm/mhi/mhi_macros.h
@@ -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
@@ -45,7 +45,7 @@
#define MHI_PCIE_DEVICE_ID_ZIRC 0x0301
#define MHI_PCIE_DEVICE_ID_9x55 0x0302
-#define MHI_M2_DEBOUNCE_TMR_MS 10
+#define MHI_M2_DEBOUNCE_TMR_US 10000
#define MHI_EV_DB_INTERVAL 1
diff --git a/drivers/platform/msm/mhi/mhi_main.c b/drivers/platform/msm/mhi/mhi_main.c
index 78aa1beb870d..739915c4af6f 100644
--- a/drivers/platform/msm/mhi/mhi_main.c
+++ b/drivers/platform/msm/mhi/mhi_main.c
@@ -508,6 +508,7 @@ int mhi_register_channel(struct mhi_client_handle **client_handle,
struct mhi_client_config *client_config;
const char *node_name;
enum MHI_CLIENT_CHANNEL chan;
+ struct mhi_chan_info chan_info = {0};
int ret;
if (!client_info || client_info->dev->of_node == NULL)
@@ -537,6 +538,14 @@ int mhi_register_channel(struct mhi_client_handle **client_handle,
mhi_log(mhi_dev_ctxt, MHI_MSG_INFO,
"Registering channel 0x%x for client\n", chan);
+ /* check if it's a supported channel by endpoint */
+ ret = get_chan_props(mhi_dev_ctxt, chan, &chan_info);
+ if (ret) {
+ mhi_log(mhi_dev_ctxt, MHI_MSG_ERROR,
+ "Client try to register unsupported chan:%d\n", chan);
+ return -EINVAL;
+ }
+
*client_handle = kzalloc(sizeof(struct mhi_client_handle), GFP_KERNEL);
if (NULL == *client_handle)
return -ENOMEM;
@@ -553,6 +562,7 @@ int mhi_register_channel(struct mhi_client_handle **client_handle,
(*client_handle)->domain = mhi_dev_ctxt->core.domain;
(*client_handle)->bus = mhi_dev_ctxt->core.bus;
(*client_handle)->slot = mhi_dev_ctxt->core.slot;
+ (*client_handle)->enabled = false;
client_config = (*client_handle)->client_config;
client_config->mhi_dev_ctxt = mhi_dev_ctxt;
client_config->user_data = client_info->user_data;
@@ -567,7 +577,7 @@ int mhi_register_channel(struct mhi_client_handle **client_handle,
if (MHI_CLIENT_IP_HW_0_IN == chan)
client_config->intmod_t = 10;
- get_chan_props(mhi_dev_ctxt, chan, &client_config->chan_info);
+ client_config->chan_info = chan_info;
ret = enable_bb_ctxt(mhi_dev_ctxt, &mhi_dev_ctxt->chan_bb_list[chan],
client_config->chan_info.max_desc, chan,
client_config->client_info.max_payload);
@@ -579,11 +589,8 @@ int mhi_register_channel(struct mhi_client_handle **client_handle,
}
if (mhi_dev_ctxt->dev_exec_env == MHI_EXEC_ENV_AMSS &&
- mhi_dev_ctxt->flags.mhi_initialized) {
- mhi_log(mhi_dev_ctxt, MHI_MSG_INFO,
- "Exec env is AMSS notify client now chan:%u\n", chan);
- mhi_notify_client(*client_handle, MHI_CB_MHI_ENABLED);
- }
+ mhi_dev_ctxt->flags.mhi_initialized)
+ (*client_handle)->enabled = true;
mhi_log(mhi_dev_ctxt, MHI_MSG_VERBOSE,
"Successfuly registered chan:%u\n", chan);
@@ -1780,6 +1787,8 @@ int mhi_register_device(struct mhi_device *mhi_device,
u32 dev_id = pci_dev->device;
u32 slot = PCI_SLOT(pci_dev->devfn);
int ret, i;
+ char node[32];
+ struct pcie_core_info *core;
of_node = of_parse_phandle(mhi_device->dev->of_node, node_name, 0);
if (!of_node)
@@ -1792,13 +1801,13 @@ int mhi_register_device(struct mhi_device *mhi_device,
mutex_lock(&mhi_device_drv->lock);
list_for_each_entry(itr, &mhi_device_drv->head, node) {
struct platform_device *pdev = itr->plat_dev;
- struct pcie_core_info *core = &itr->core;
- if (pdev->dev.of_node == of_node &&
- core->domain == domain &&
- core->bus == bus &&
- core->dev_id == dev_id &&
- core->slot == slot) {
+ core = &itr->core;
+ if (pdev->dev.of_node == of_node && core->domain == domain &&
+ core->bus == bus && core->slot == slot &&
+ (core->dev_id == PCI_ANY_ID || (core->dev_id == dev_id))) {
+ /* change default dev_id to current dev_id */
+ core->dev_id = dev_id;
mhi_dev_ctxt = itr;
break;
}
@@ -1809,6 +1818,11 @@ int mhi_register_device(struct mhi_device *mhi_device,
if (!mhi_dev_ctxt)
return -EPROBE_DEFER;
+ snprintf(node, sizeof(node), "mhi_%04x_%02u.%02u.%02u",
+ core->dev_id, core->domain, core->bus, core->slot);
+ mhi_dev_ctxt->mhi_ipc_log =
+ ipc_log_context_create(MHI_IPC_LOG_PAGES, node, 0);
+
mhi_log(mhi_dev_ctxt, MHI_MSG_INFO,
"Registering Domain:%02u Bus:%04u dev:0x%04x slot:%04u\n",
domain, bus, dev_id, slot);
@@ -1890,6 +1904,17 @@ int mhi_register_device(struct mhi_device *mhi_device,
mhi_dev_ctxt->bhi_ctxt.rddm_size);
}
+ /* notify all the registered clients we probed */
+ for (i = 0; i < MHI_MAX_CHANNELS; i++) {
+ struct mhi_client_handle *client_handle =
+ mhi_dev_ctxt->client_handle_list[i];
+
+ if (!client_handle)
+ continue;
+ client_handle->dev_id = core->dev_id;
+ mhi_notify_client(client_handle, MHI_CB_MHI_PROBED);
+ }
+
mhi_log(mhi_dev_ctxt, MHI_MSG_INFO, "Exit success\n");
return 0;
}
diff --git a/drivers/platform/msm/mhi/mhi_pm.c b/drivers/platform/msm/mhi/mhi_pm.c
index caa34eadf8ea..ad9a6fd6b278 100644
--- a/drivers/platform/msm/mhi/mhi_pm.c
+++ b/drivers/platform/msm/mhi/mhi_pm.c
@@ -22,6 +22,22 @@
#include "mhi_hwio.h"
#include "mhi_bhi.h"
+static const char *const mhi_dev_ctrl_str[MHI_DEV_CTRL_MAXCMD] = {
+ [MHI_DEV_CTRL_INIT] = "INIT",
+ [MHI_DEV_CTRL_DE_INIT] = "DE-INIT",
+ [MHI_DEV_CTRL_SUSPEND] = "SUSPEND",
+ [MHI_DEV_CTRL_RESUME] = "RESUME",
+ [MHI_DEV_CTRL_POWER_OFF] = "OFF",
+ [MHI_DEV_CTRL_POWER_ON] = "ON",
+ [MHI_DEV_CTRL_TRIGGER_RDDM] = "TRIGGER RDDM",
+ [MHI_DEV_CTRL_RDDM] = "RDDM",
+ [MHI_DEV_CTRL_RDDM_KERNEL_PANIC] = "RDDM IN PANIC",
+ [MHI_DEV_CTRL_NOTIFY_LINK_ERROR] = "LD",
+};
+
+#define TO_MHI_DEV_CTRL_STR(cmd) ((cmd >= MHI_DEV_CTRL_MAXCMD) ? "INVALID" : \
+ mhi_dev_ctrl_str[cmd])
+
/* Write only sysfs attributes */
static DEVICE_ATTR(MHI_M0, S_IWUSR, NULL, sysfs_init_m0);
static DEVICE_ATTR(MHI_M3, S_IWUSR, NULL, sysfs_init_m3);
@@ -97,12 +113,14 @@ static int mhi_pm_initiate_m3(struct mhi_device_ctxt *mhi_dev_ctxt,
mhi_dev_ctxt->assert_wake(mhi_dev_ctxt, false);
read_unlock_bh(&mhi_dev_ctxt->pm_xfer_lock);
r = wait_event_timeout(*mhi_dev_ctxt->mhi_ev_wq.m0_event,
- mhi_dev_ctxt->mhi_state == MHI_STATE_M0 ||
- mhi_dev_ctxt->mhi_state == MHI_STATE_M1,
- msecs_to_jiffies(MHI_MAX_RESUME_TIMEOUT));
- if (!r) {
+ mhi_dev_ctxt->mhi_state == MHI_STATE_M0 ||
+ mhi_dev_ctxt->mhi_state == MHI_STATE_M1 ||
+ mhi_dev_ctxt->mhi_pm_state == MHI_PM_LD_ERR_FATAL_DETECT,
+ msecs_to_jiffies(MHI_MAX_RESUME_TIMEOUT));
+ if (!r || mhi_dev_ctxt->mhi_pm_state == MHI_PM_LD_ERR_FATAL_DETECT) {
mhi_log(mhi_dev_ctxt, MHI_MSG_ERROR,
- "Failed to get M0||M1 event, timeout, current state:%s\n",
+ "Failed to get M0||M1 event or LD pm_state:0x%x state:%s\n",
+ mhi_dev_ctxt->mhi_pm_state,
TO_MHI_STATE_STR(mhi_dev_ctxt->mhi_state));
return -EIO;
}
@@ -122,9 +140,10 @@ static int mhi_pm_initiate_m3(struct mhi_device_ctxt *mhi_dev_ctxt,
write_unlock_irq(&mhi_dev_ctxt->pm_xfer_lock);
mhi_log(mhi_dev_ctxt, MHI_MSG_INFO, "Waiting for M3 completion.\n");
r = wait_event_timeout(*mhi_dev_ctxt->mhi_ev_wq.m3_event,
- mhi_dev_ctxt->mhi_state == MHI_STATE_M3,
- msecs_to_jiffies(MHI_MAX_SUSPEND_TIMEOUT));
- if (!r) {
+ mhi_dev_ctxt->mhi_state == MHI_STATE_M3 ||
+ mhi_dev_ctxt->mhi_pm_state == MHI_PM_LD_ERR_FATAL_DETECT,
+ msecs_to_jiffies(MHI_MAX_SUSPEND_TIMEOUT));
+ if (!r || mhi_dev_ctxt->mhi_pm_state == MHI_PM_LD_ERR_FATAL_DETECT) {
mhi_log(mhi_dev_ctxt, MHI_MSG_ERROR,
"Failed to get M3 event, timeout, current state:%s\n",
TO_MHI_STATE_STR(mhi_dev_ctxt->mhi_state));
@@ -158,12 +177,13 @@ static int mhi_pm_initiate_m0(struct mhi_device_ctxt *mhi_dev_ctxt)
mhi_set_m_state(mhi_dev_ctxt, MHI_STATE_M0);
write_unlock_irq(&mhi_dev_ctxt->pm_xfer_lock);
r = wait_event_timeout(*mhi_dev_ctxt->mhi_ev_wq.m0_event,
- mhi_dev_ctxt->mhi_state == MHI_STATE_M0 ||
- mhi_dev_ctxt->mhi_state == MHI_STATE_M1,
- msecs_to_jiffies(MHI_MAX_RESUME_TIMEOUT));
- if (!r) {
+ mhi_dev_ctxt->mhi_state == MHI_STATE_M0 ||
+ mhi_dev_ctxt->mhi_state == MHI_STATE_M1 ||
+ mhi_dev_ctxt->mhi_pm_state == MHI_PM_LD_ERR_FATAL_DETECT,
+ msecs_to_jiffies(MHI_MAX_RESUME_TIMEOUT));
+ if (!r || mhi_dev_ctxt->mhi_pm_state == MHI_PM_LD_ERR_FATAL_DETECT) {
mhi_log(mhi_dev_ctxt, MHI_MSG_ERROR,
- "Failed to get M0 event, timeout\n");
+ "Failed to get M0 event, timeout or LD\n");
r = -EIO;
} else
r = 0;
@@ -295,13 +315,16 @@ static int mhi_pm_slave_mode_power_on(struct mhi_device_ctxt *mhi_dev_ctxt)
mhi_dev_ctxt->assert_wake(mhi_dev_ctxt, false);
read_unlock_irq(&mhi_dev_ctxt->pm_xfer_lock);
- ret_val = wait_for_completion_timeout(&mhi_dev_ctxt->cmd_complete,
- msecs_to_jiffies(timeout));
- if (!ret_val || mhi_dev_ctxt->dev_exec_env != MHI_EXEC_ENV_AMSS)
+ wait_for_completion_timeout(&mhi_dev_ctxt->cmd_complete,
+ msecs_to_jiffies(timeout));
+ if (mhi_dev_ctxt->dev_exec_env != MHI_EXEC_ENV_AMSS)
ret_val = -EIO;
else
ret_val = 0;
+ /* wait for firmware download to complete */
+ flush_work(&mhi_dev_ctxt->bhi_ctxt.fw_load_work);
+
if (ret_val) {
read_lock_irq(&mhi_dev_ctxt->pm_xfer_lock);
mhi_dev_ctxt->deassert_wake(mhi_dev_ctxt);
@@ -537,16 +560,16 @@ void mhi_link_state_cb(struct msm_pcie_notify *notify)
}
}
-int mhi_pm_control_device(struct mhi_device *mhi_device,
- enum mhi_dev_ctrl ctrl)
+int mhi_pm_control_device(struct mhi_device *mhi_device, enum mhi_dev_ctrl ctrl)
{
struct mhi_device_ctxt *mhi_dev_ctxt = mhi_device->mhi_dev_ctxt;
+ unsigned long flags;
if (!mhi_dev_ctxt)
return -EINVAL;
- mhi_log(mhi_dev_ctxt, MHI_MSG_INFO,
- "Entered with cmd:%d\n", ctrl);
+ mhi_log(mhi_dev_ctxt, MHI_MSG_INFO, "Entered with cmd:%s\n",
+ TO_MHI_DEV_CTRL_STR(ctrl));
switch (ctrl) {
case MHI_DEV_CTRL_INIT:
@@ -560,12 +583,46 @@ int mhi_pm_control_device(struct mhi_device *mhi_device,
case MHI_DEV_CTRL_POWER_OFF:
mhi_pm_slave_mode_power_off(mhi_dev_ctxt);
break;
+ case MHI_DEV_CTRL_TRIGGER_RDDM:
+ write_lock_irqsave(&mhi_dev_ctxt->pm_xfer_lock, flags);
+ if (!MHI_REG_ACCESS_VALID(mhi_dev_ctxt->mhi_pm_state)) {
+ write_unlock_irqrestore(&mhi_dev_ctxt->pm_xfer_lock,
+ flags);
+ mhi_log(mhi_dev_ctxt, MHI_MSG_INFO,
+ "failed to trigger rddm, no register access in state:0x%x\n",
+ mhi_dev_ctxt->mhi_pm_state);
+ return -EIO;
+ }
+ mhi_set_m_state(mhi_dev_ctxt, MHI_STATE_SYS_ERR);
+ write_unlock_irqrestore(&mhi_dev_ctxt->pm_xfer_lock, flags);
+ break;
case MHI_DEV_CTRL_RDDM:
return bhi_rddm(mhi_dev_ctxt, false);
+ case MHI_DEV_CTRL_RDDM_KERNEL_PANIC:
+ return bhi_rddm(mhi_dev_ctxt, true);
case MHI_DEV_CTRL_DE_INIT:
- if (mhi_dev_ctxt->mhi_pm_state != MHI_PM_DISABLE)
+ if (mhi_dev_ctxt->mhi_pm_state != MHI_PM_DISABLE) {
+ enum MHI_PM_STATE cur_state;
+ /*
+ * If bus master calls DE_INIT before calling POWER_OFF
+ * means a critical failure occurred during POWER_ON
+ * state transition and external PCIe device may not
+ * respond to host. Force PM state to PCIe linkdown
+ * state prior to starting shutdown process to avoid
+ * accessing PCIe link.
+ */
+ write_lock_irq(&mhi_dev_ctxt->pm_xfer_lock);
+ cur_state = mhi_tryset_pm_state(mhi_dev_ctxt,
+ MHI_PM_LD_ERR_FATAL_DETECT);
+ write_unlock_irq(&mhi_dev_ctxt->pm_xfer_lock);
+ if (unlikely(cur_state != MHI_PM_LD_ERR_FATAL_DETECT)) {
+ mhi_log(mhi_dev_ctxt, MHI_MSG_ERROR,
+ "Failed to transition to state 0x%x from 0x%x\n",
+ MHI_PM_LD_ERR_FATAL_DETECT, cur_state);
+ }
process_disable_transition(MHI_PM_SHUTDOWN_PROCESS,
mhi_dev_ctxt);
+ }
bhi_exit(mhi_dev_ctxt);
break;
case MHI_DEV_CTRL_NOTIFY_LINK_ERROR:
@@ -580,6 +637,12 @@ int mhi_pm_control_device(struct mhi_device *mhi_device,
mhi_log(mhi_dev_ctxt, MHI_MSG_INFO,
"Failed to transition to state 0x%x from 0x%x\n",
MHI_PM_LD_ERR_FATAL_DETECT, cur_state);
+
+ /* wake up all threads that's waiting for state change events */
+ complete(&mhi_dev_ctxt->cmd_complete);
+ wake_up_interruptible(mhi_dev_ctxt->mhi_ev_wq.bhi_event);
+ wake_up(mhi_dev_ctxt->mhi_ev_wq.m0_event);
+ wake_up(mhi_dev_ctxt->mhi_ev_wq.m3_event);
break;
}
default:
diff --git a/drivers/platform/msm/mhi/mhi_states.c b/drivers/platform/msm/mhi/mhi_states.c
index c0c23c4e0756..ea2a91bd2d06 100644
--- a/drivers/platform/msm/mhi/mhi_states.c
+++ b/drivers/platform/msm/mhi/mhi_states.c
@@ -147,7 +147,8 @@ void mhi_set_m_state(struct mhi_device_ctxt *mhi_dev_ctxt,
* M1 -> M3_ENTER --> M3
* L1: SYS_ERR_DETECT -> SYS_ERR_PROCESS --> POR
* L2: SHUTDOWN_PROCESS -> DISABLE -> SSR_PENDING (via SSR Notification only)
- * L3: LD_ERR_FATAL_DETECT -> SHUTDOWN_PROCESS
+ * L3: LD_ERR_FATAL_DETECT <--> LD_ERR_FATAL_DETECT
+ * LD_ERR_FATAL_DETECT -> SHUTDOWN_PROCESS
*/
static const struct mhi_pm_transitions const mhi_state_transitions[] = {
/* L0 States */
@@ -216,7 +217,7 @@ static const struct mhi_pm_transitions const mhi_state_transitions[] = {
/* L3 States */
{
MHI_PM_LD_ERR_FATAL_DETECT,
- MHI_PM_SHUTDOWN_PROCESS
+ MHI_PM_LD_ERR_FATAL_DETECT | MHI_PM_SHUTDOWN_PROCESS
},
/* From SSR notification only */
{
@@ -430,7 +431,7 @@ void process_m1_transition(struct work_struct *work)
mhi_set_m_state(mhi_dev_ctxt, MHI_STATE_M2);
write_unlock_irq(&mhi_dev_ctxt->pm_xfer_lock);
- msleep(MHI_M2_DEBOUNCE_TMR_MS);
+ usleep_range(MHI_M2_DEBOUNCE_TMR_US, MHI_M2_DEBOUNCE_TMR_US + 50);
write_lock_irq(&mhi_dev_ctxt->pm_xfer_lock);
/* During DEBOUNCE Time We could be receiving M0 Event */
@@ -590,26 +591,26 @@ static int process_reset_transition(
}
static void enable_clients(struct mhi_device_ctxt *mhi_dev_ctxt,
- enum MHI_EXEC_ENV exec_env)
+ enum MHI_EXEC_ENV exec_env)
{
struct mhi_client_handle *client_handle = NULL;
- struct mhi_cb_info cb_info;
- int i = 0, r = 0;
- struct mhi_chan_info chan_info;
-
- cb_info.cb_reason = MHI_CB_MHI_ENABLED;
+ struct mhi_chan_info *chan_info;
+ int i = 0;
mhi_log(mhi_dev_ctxt, MHI_MSG_INFO,
"Enabling Clients, exec env %d.\n", exec_env);
+
for (i = 0; i < MHI_MAX_CHANNELS; ++i) {
- if (!VALID_CHAN_NR(i))
+ if (!mhi_dev_ctxt->client_handle_list[i])
continue;
+
client_handle = mhi_dev_ctxt->client_handle_list[i];
- r = get_chan_props(mhi_dev_ctxt, i, &chan_info);
- if (!r && client_handle &&
- exec_env == GET_CHAN_PROPS(CHAN_BRINGUP_STAGE,
- chan_info.flags))
+ chan_info = &client_handle->client_config->chan_info;
+ if (exec_env == GET_CHAN_PROPS(CHAN_BRINGUP_STAGE,
+ chan_info->flags)) {
+ client_handle->enabled = true;
mhi_notify_client(client_handle, MHI_CB_MHI_ENABLED);
+ }
}
mhi_log(mhi_dev_ctxt, MHI_MSG_INFO, "Done.\n");
diff --git a/drivers/platform/msm/mhi_uci/mhi_uci.c b/drivers/platform/msm/mhi_uci/mhi_uci.c
index 3191ec065a95..4563810d7e5b 100644
--- a/drivers/platform/msm/mhi_uci/mhi_uci.c
+++ b/drivers/platform/msm/mhi_uci/mhi_uci.c
@@ -122,6 +122,7 @@ struct uci_client {
atomic_t out_pkt_pend_ack;
atomic_t completion_ack;
struct mhi_uci_ctxt_t *uci_ctxt;
+ struct cdev cdev;
bool enabled;
void *uci_ipc_log;
};
@@ -132,7 +133,6 @@ struct mhi_uci_ctxt_t {
struct uci_client client_handles[MHI_SOFTWARE_CLIENT_LIMIT];
dev_t dev_t;
struct mutex ctrl_mutex;
- struct cdev cdev[MHI_SOFTWARE_CLIENT_LIMIT];
struct uci_client *ctrl_client;
};
@@ -246,6 +246,7 @@ static int mhi_uci_client_release(struct inode *mhi_inode,
static unsigned int mhi_uci_client_poll(struct file *file, poll_table *wait);
static long mhi_uci_ctl_ioctl(struct file *file, unsigned int cmd,
unsigned long arg);
+static int mhi_uci_create_device(struct uci_client *uci_client);
static struct mhi_uci_drv_ctxt mhi_uci_drv_ctxt;
@@ -1174,6 +1175,14 @@ static void uci_xfer_cb(struct mhi_cb_info *cb_info)
uci_handle = cb_info->result->user_data;
switch (cb_info->cb_reason) {
+ case MHI_CB_MHI_PROBED:
+ /* If it's outbound channel create the node */
+ mutex_lock(&uci_handle->client_lock);
+ if (!uci_handle->dev &&
+ cb_info->chan == uci_handle->out_attr.chan_id)
+ mhi_uci_create_device(uci_handle);
+ mutex_unlock(&uci_handle->client_lock);
+ break;
case MHI_CB_MHI_ENABLED:
uci_log(uci_handle->uci_ipc_log, UCI_DBG_INFO,
"MHI enabled CB received for chan %d\n",
@@ -1295,17 +1304,65 @@ static const struct file_operations mhi_uci_client_fops = {
.unlocked_ioctl = mhi_uci_ctl_ioctl,
};
+static int mhi_uci_create_device(struct uci_client *uci_client)
+{
+ struct mhi_uci_ctxt_t *uci_ctxt = uci_client->uci_ctxt;
+ char node_name[32];
+ int index = uci_client - uci_ctxt->client_handles;
+ int ret;
+
+ uci_log(mhi_uci_drv_ctxt.mhi_uci_ipc_log, UCI_DBG_INFO,
+ "Creating dev node %04x_%02u.%02u.%02u_pipe%d\n",
+ uci_client->out_attr.mhi_handle->dev_id,
+ uci_client->out_attr.mhi_handle->domain,
+ uci_client->out_attr.mhi_handle->bus,
+ uci_client->out_attr.mhi_handle->slot,
+ uci_client->out_attr.chan_id);
+
+ cdev_init(&uci_client->cdev, &mhi_uci_client_fops);
+ uci_client->cdev.owner = THIS_MODULE;
+ ret = cdev_add(&uci_client->cdev, uci_ctxt->dev_t + index, 1);
+ if (ret) {
+ uci_log(mhi_uci_drv_ctxt.mhi_uci_ipc_log, UCI_DBG_ERROR,
+ "Failed to add cdev %d, ret:%d\n", index, ret);
+ return ret;
+ }
+ uci_client->dev = device_create(mhi_uci_drv_ctxt.mhi_uci_class, NULL,
+ uci_ctxt->dev_t + index, NULL,
+ DEVICE_NAME "_%04x_%02u.%02u.%02u%s%d",
+ uci_client->out_attr.mhi_handle->dev_id,
+ uci_client->out_attr.mhi_handle->domain,
+ uci_client->out_attr.mhi_handle->bus,
+ uci_client->out_attr.mhi_handle->slot,
+ "_pipe_",
+ uci_client->out_attr.chan_id);
+ if (IS_ERR(uci_client->dev)) {
+ uci_log(mhi_uci_drv_ctxt.mhi_uci_ipc_log, UCI_DBG_ERROR,
+ "Failed to add cdev %d\n", IS_ERR(uci_client->dev));
+ cdev_del(&uci_client->cdev);
+ return -EIO;
+ }
+
+ /* dev node created successfully, create logging buffer */
+ snprintf(node_name, sizeof(node_name), "mhi_uci_%04x_%02u.%02u.%02u_%d",
+ uci_client->out_attr.mhi_handle->dev_id,
+ uci_client->out_attr.mhi_handle->domain,
+ uci_client->out_attr.mhi_handle->bus,
+ uci_client->out_attr.mhi_handle->slot,
+ uci_client->out_attr.chan_id);
+ uci_client->uci_ipc_log = ipc_log_context_create(MHI_UCI_IPC_LOG_PAGES,
+ node_name, 0);
+
+ return 0;
+}
+
static int mhi_uci_probe(struct platform_device *pdev)
{
struct mhi_uci_ctxt_t *uci_ctxt;
int ret_val;
int i;
- char node_name[32];
- uci_log(mhi_uci_drv_ctxt.mhi_uci_ipc_log,
- UCI_DBG_INFO,
- "Entered with pdev:%p\n",
- pdev);
+ uci_log(mhi_uci_drv_ctxt.mhi_uci_ipc_log, UCI_DBG_INFO, "Entered\n");
if (mhi_is_device_ready(&pdev->dev, "qcom,mhi") == false)
return -EPROBE_DEFER;
@@ -1326,128 +1383,67 @@ static int mhi_uci_probe(struct platform_device *pdev)
uci_ctxt->pdev = pdev;
mutex_init(&uci_ctxt->ctrl_mutex);
- uci_log(mhi_uci_drv_ctxt.mhi_uci_ipc_log,
- UCI_DBG_INFO,
+ uci_log(mhi_uci_drv_ctxt.mhi_uci_ipc_log, UCI_DBG_INFO,
"Setting up channel attributes\n");
ret_val = uci_init_client_attributes(uci_ctxt,
pdev->dev.of_node);
if (ret_val) {
- uci_log(mhi_uci_drv_ctxt.mhi_uci_ipc_log,
- UCI_DBG_ERROR,
+ uci_log(mhi_uci_drv_ctxt.mhi_uci_ipc_log, UCI_DBG_ERROR,
"Failed to init client attributes\n");
return -EIO;
}
- uci_log(mhi_uci_drv_ctxt.mhi_uci_ipc_log,
- UCI_DBG_INFO,
+ uci_log(mhi_uci_drv_ctxt.mhi_uci_ipc_log, UCI_DBG_INFO,
+ "Allocating char devices\n");
+ ret_val = alloc_chrdev_region(&uci_ctxt->dev_t, 0,
+ MHI_SOFTWARE_CLIENT_LIMIT,
+ DEVICE_NAME);
+ if (IS_ERR_VALUE(ret_val)) {
+ uci_log(mhi_uci_drv_ctxt.mhi_uci_ipc_log, UCI_DBG_ERROR,
+ "Failed to alloc char devs, ret 0x%x\n", ret_val);
+ return ret_val;
+ }
+
+ uci_log(mhi_uci_drv_ctxt.mhi_uci_ipc_log, UCI_DBG_INFO,
"Registering for MHI events\n");
for (i = 0; i < MHI_SOFTWARE_CLIENT_LIMIT; ++i) {
struct uci_client *uci_client = &uci_ctxt->client_handles[i];
uci_client->uci_ctxt = uci_ctxt;
mutex_init(&uci_client->client_lock);
- if (uci_client->in_attr.uci_ownership) {
- ret_val = mhi_register_client(uci_client,
- &pdev->dev);
+ if (!uci_client->in_attr.uci_ownership)
+ continue;
+ ret_val = mhi_register_client(uci_client, &pdev->dev);
+ if (ret_val) {
+ uci_log(mhi_uci_drv_ctxt.mhi_uci_ipc_log,
+ UCI_DBG_CRITICAL,
+ "Failed to reg client %d ret %d\n",
+ ret_val, i);
+ return -EIO;
+ }
+
+ mutex_lock(&uci_client->client_lock);
+ /* If we have device id, create the node now */
+ if (uci_client->out_attr.mhi_handle->dev_id != PCI_ANY_ID) {
+ ret_val = mhi_uci_create_device(uci_client);
if (ret_val) {
uci_log(mhi_uci_drv_ctxt.mhi_uci_ipc_log,
UCI_DBG_CRITICAL,
- "Failed to reg client %d ret %d\n",
- ret_val,
- i);
-
+ "Failed to create device node, ret:%d\n",
+ ret_val);
+ mutex_unlock(&uci_client->client_lock);
return -EIO;
}
- snprintf(node_name,
- sizeof(node_name),
- "mhi_uci_%04x_%02u.%02u.%02u_%d",
- uci_client->out_attr.mhi_handle->dev_id,
- uci_client->out_attr.mhi_handle->domain,
- uci_client->out_attr.mhi_handle->bus,
- uci_client->out_attr.mhi_handle->slot,
- uci_client->out_attr.chan_id);
- uci_client->uci_ipc_log = ipc_log_context_create
- (MHI_UCI_IPC_LOG_PAGES,
- node_name,
- 0);
}
+ mutex_unlock(&uci_client->client_lock);
}
- uci_log(mhi_uci_drv_ctxt.mhi_uci_ipc_log,
- UCI_DBG_INFO,
- "Allocating char devices\n");
- ret_val = alloc_chrdev_region(&uci_ctxt->dev_t,
- 0,
- MHI_SOFTWARE_CLIENT_LIMIT,
- DEVICE_NAME);
- if (IS_ERR_VALUE(ret_val)) {
- uci_log(mhi_uci_drv_ctxt.mhi_uci_ipc_log,
- UCI_DBG_ERROR,
- "Failed to alloc char devs, ret 0x%x\n", ret_val);
- goto failed_char_alloc;
- }
-
- uci_log(mhi_uci_drv_ctxt.mhi_uci_ipc_log,
- UCI_DBG_INFO,
- "Setting up device nodes. for dev_t: 0x%x major:0x%x\n",
- uci_ctxt->dev_t,
- MAJOR(uci_ctxt->dev_t));
- for (i = 0; i < MHI_SOFTWARE_CLIENT_LIMIT; ++i) {
- struct uci_client *uci_client = &uci_ctxt->client_handles[i];
-
- if (uci_client->in_attr.uci_ownership) {
- cdev_init(&uci_ctxt->cdev[i], &mhi_uci_client_fops);
- uci_ctxt->cdev[i].owner = THIS_MODULE;
- ret_val = cdev_add(&uci_ctxt->cdev[i],
- uci_ctxt->dev_t + i, 1);
- if (IS_ERR_VALUE(ret_val)) {
- uci_log(uci_client->uci_ipc_log,
- UCI_DBG_ERROR,
- "Failed to add cdev %d, ret 0x%x\n",
- i, ret_val);
- goto failed_char_add;
- }
- uci_client->dev =
- device_create(mhi_uci_drv_ctxt.mhi_uci_class,
- NULL,
- uci_ctxt->dev_t + i,
- NULL,
- DEVICE_NAME "_%04x_%02u.%02u.%02u%s%d",
- uci_client->out_attr.mhi_handle->dev_id,
- uci_client->out_attr.mhi_handle->domain,
- uci_client->out_attr.mhi_handle->bus,
- uci_client->out_attr.mhi_handle->slot,
- "_pipe_",
- uci_client->out_attr.chan_id);
- if (IS_ERR(uci_client->dev)) {
- uci_log(uci_client->uci_ipc_log,
- UCI_DBG_ERROR,
- "Failed to add cdev %d\n", i);
- cdev_del(&uci_ctxt->cdev[i]);
- ret_val = -EIO;
- goto failed_device_create;
- }
- }
- }
platform_set_drvdata(pdev, uci_ctxt);
mutex_lock(&mhi_uci_drv_ctxt.list_lock);
list_add_tail(&uci_ctxt->node, &mhi_uci_drv_ctxt.head);
mutex_unlock(&mhi_uci_drv_ctxt.list_lock);
- return 0;
-
-failed_char_add:
-failed_device_create:
- while (--i >= 0) {
- cdev_del(&uci_ctxt->cdev[i]);
- device_destroy(mhi_uci_drv_ctxt.mhi_uci_class,
- MKDEV(MAJOR(uci_ctxt->dev_t), i));
- };
-
- unregister_chrdev_region(MAJOR(uci_ctxt->dev_t),
- MHI_SOFTWARE_CLIENT_LIMIT);
-failed_char_alloc:
- return ret_val;
+ return 0;
};
static int mhi_uci_remove(struct platform_device *pdev)
@@ -1462,7 +1458,7 @@ static int mhi_uci_remove(struct platform_device *pdev)
if (uci_client->in_attr.uci_ownership) {
mhi_deregister_channel(uci_client->out_attr.mhi_handle);
mhi_deregister_channel(uci_client->in_attr.mhi_handle);
- cdev_del(&uci_ctxt->cdev[i]);
+ cdev_del(&uci_client->cdev);
device_destroy(mhi_uci_drv_ctxt.mhi_uci_class,
MKDEV(MAJOR(uci_ctxt->dev_t), i));
}
diff --git a/drivers/power/qcom/debug_core.c b/drivers/power/qcom/debug_core.c
index ccef04ae9eb2..51b6d63fe994 100644
--- a/drivers/power/qcom/debug_core.c
+++ b/drivers/power/qcom/debug_core.c
@@ -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
@@ -288,8 +288,8 @@ static const struct file_operations msm_core_ptable_ops = {
int msm_core_debug_init(void)
{
- struct dentry *dir;
- struct dentry *file;
+ struct dentry *dir = NULL;
+ struct dentry *file = NULL;
int i;
msm_core_data = get_cpu_pwr_stats();
diff --git a/drivers/power/supply/qcom/battery.c b/drivers/power/supply/qcom/battery.c
index 8b4067b17103..5e8cc84fbfbf 100644
--- a/drivers/power/supply/qcom/battery.c
+++ b/drivers/power/supply/qcom/battery.c
@@ -550,8 +550,6 @@ static int usb_icl_vote_callback(struct votable *votable, void *data,
power_supply_set_property(chip->main_psy,
POWER_SUPPLY_PROP_CURRENT_MAX,
&pval);
- /* wait for ICL change */
- msleep(100);
}
/* set the effective ICL */
@@ -559,9 +557,6 @@ static int usb_icl_vote_callback(struct votable *votable, void *data,
power_supply_set_property(chip->main_psy,
POWER_SUPPLY_PROP_CURRENT_MAX,
&pval);
- if (rerun_aicl)
- /* wait for ICL change */
- msleep(100);
vote(chip->pl_disable_votable, ICL_CHANGE_VOTER, false, 0);
diff --git a/drivers/power/supply/qcom/fg-core.h b/drivers/power/supply/qcom/fg-core.h
index 25c9d0251cf1..c5346babf310 100644
--- a/drivers/power/supply/qcom/fg-core.h
+++ b/drivers/power/supply/qcom/fg-core.h
@@ -219,6 +219,12 @@ enum slope_limit_status {
SLOPE_LIMIT_NUM_COEFFS,
};
+enum esr_timer_config {
+ TIMER_RETRY = 0,
+ TIMER_MAX,
+ NUM_ESR_TIMERS,
+};
+
/* DT parameters for FG device */
struct fg_dt_props {
bool force_load_profile;
@@ -234,9 +240,9 @@ struct fg_dt_props {
int recharge_soc_thr;
int recharge_volt_thr_mv;
int rsense_sel;
- int esr_timer_charging;
- int esr_timer_awake;
- int esr_timer_asleep;
+ int esr_timer_charging[NUM_ESR_TIMERS];
+ int esr_timer_awake[NUM_ESR_TIMERS];
+ int esr_timer_asleep[NUM_ESR_TIMERS];
int rconn_mohms;
int esr_clamp_mohms;
int cl_start_soc;
@@ -385,6 +391,7 @@ struct fg_chip {
int maint_soc;
int delta_soc;
int last_msoc;
+ int esr_timer_charging_default[NUM_ESR_TIMERS];
enum slope_limit_status slope_limit_sts;
bool profile_available;
bool profile_loaded;
diff --git a/drivers/power/supply/qcom/qpnp-fg-gen3.c b/drivers/power/supply/qcom/qpnp-fg-gen3.c
index 26648595c55c..bd7231705319 100644
--- a/drivers/power/supply/qcom/qpnp-fg-gen3.c
+++ b/drivers/power/supply/qcom/qpnp-fg-gen3.c
@@ -491,7 +491,7 @@ static void fg_encode_default(struct fg_sram_param *sp,
int i, mask = 0xff;
int64_t temp;
- temp = DIV_ROUND_CLOSEST(val * sp[id].numrtr, sp[id].denmtr);
+ temp = (int64_t)div_s64((s64)val * sp[id].numrtr, sp[id].denmtr);
pr_debug("temp: %llx id: %d, val: %d, buf: [ ", temp, id, val);
for (i = 0; i < sp[id].len; i++) {
buf[i] = temp & mask;
@@ -1025,12 +1025,15 @@ static inline void get_esr_meas_current(int curr_ma, u8 *val)
*val <<= ESR_PULL_DOWN_IVAL_SHIFT;
}
-static int fg_set_esr_timer(struct fg_chip *chip, int cycles, bool charging,
- int flags)
+static int fg_set_esr_timer(struct fg_chip *chip, int cycles_init,
+ int cycles_max, bool charging, int flags)
{
u8 buf[2];
int rc, timer_max, timer_init;
+ if (cycles_init < 0 || cycles_max < 0)
+ return 0;
+
if (charging) {
timer_max = FG_SRAM_ESR_TIMER_CHG_MAX;
timer_init = FG_SRAM_ESR_TIMER_CHG_INIT;
@@ -1039,7 +1042,7 @@ static int fg_set_esr_timer(struct fg_chip *chip, int cycles, bool charging,
timer_init = FG_SRAM_ESR_TIMER_DISCHG_INIT;
}
- fg_encode(chip->sp, timer_max, cycles, buf);
+ fg_encode(chip->sp, timer_max, cycles_max, buf);
rc = fg_sram_write(chip,
chip->sp[timer_max].addr_word,
chip->sp[timer_max].addr_byte, buf,
@@ -1050,7 +1053,7 @@ static int fg_set_esr_timer(struct fg_chip *chip, int cycles, bool charging,
return rc;
}
- fg_encode(chip->sp, timer_init, cycles, buf);
+ fg_encode(chip->sp, timer_init, cycles_init, buf);
rc = fg_sram_write(chip,
chip->sp[timer_init].addr_word,
chip->sp[timer_init].addr_byte, buf,
@@ -1061,6 +1064,8 @@ static int fg_set_esr_timer(struct fg_chip *chip, int cycles, bool charging,
return rc;
}
+ fg_dbg(chip, FG_STATUS, "esr_%s_timer set to %d/%d\n",
+ charging ? "charging" : "discharging", cycles_init, cycles_max);
return 0;
}
@@ -1315,9 +1320,16 @@ static int fg_cap_learning_process_full_data(struct fg_chip *chip)
return rc;
}
- cc_soc_delta_pct = DIV_ROUND_CLOSEST(
- abs(cc_soc_sw - chip->cl.init_cc_soc_sw) * 100,
- CC_SOC_30BIT);
+ cc_soc_delta_pct =
+ div64_s64((int64_t)(cc_soc_sw - chip->cl.init_cc_soc_sw) * 100,
+ CC_SOC_30BIT);
+
+ /* If the delta is < 50%, then skip processing full data */
+ if (cc_soc_delta_pct < 50) {
+ pr_err("cc_soc_delta_pct: %d\n", cc_soc_delta_pct);
+ return -ERANGE;
+ }
+
delta_cc_uah = div64_s64(chip->cl.learned_cc_uah * cc_soc_delta_pct,
100);
chip->cl.final_cc_uah = chip->cl.init_cc_uah + delta_cc_uah;
@@ -1387,7 +1399,6 @@ out:
return rc;
}
-#define FULL_SOC_RAW 255
static void fg_cap_learning_update(struct fg_chip *chip)
{
int rc, batt_soc, batt_soc_msb;
@@ -2039,6 +2050,50 @@ static int fg_esr_fcc_config(struct fg_chip *chip)
return 0;
}
+static int fg_esr_timer_config(struct fg_chip *chip, bool sleep)
+{
+ int rc, cycles_init, cycles_max;
+ bool end_of_charge = false;
+
+ end_of_charge = is_input_present(chip) && chip->charge_done;
+ fg_dbg(chip, FG_STATUS, "sleep: %d eoc: %d\n", sleep, end_of_charge);
+
+ /* ESR discharging timer configuration */
+ cycles_init = sleep ? chip->dt.esr_timer_asleep[TIMER_RETRY] :
+ chip->dt.esr_timer_awake[TIMER_RETRY];
+ if (end_of_charge)
+ cycles_init = 0;
+
+ cycles_max = sleep ? chip->dt.esr_timer_asleep[TIMER_MAX] :
+ chip->dt.esr_timer_awake[TIMER_MAX];
+
+ rc = fg_set_esr_timer(chip, cycles_init, cycles_max, false,
+ sleep ? FG_IMA_NO_WLOCK : FG_IMA_DEFAULT);
+ if (rc < 0) {
+ pr_err("Error in setting ESR timer, rc=%d\n", rc);
+ return rc;
+ }
+
+ /* ESR charging timer configuration */
+ cycles_init = cycles_max = -EINVAL;
+ if (end_of_charge || sleep) {
+ cycles_init = chip->dt.esr_timer_charging[TIMER_RETRY];
+ cycles_max = chip->dt.esr_timer_charging[TIMER_MAX];
+ } else if (is_input_present(chip)) {
+ cycles_init = chip->esr_timer_charging_default[TIMER_RETRY];
+ cycles_max = chip->esr_timer_charging_default[TIMER_MAX];
+ }
+
+ rc = fg_set_esr_timer(chip, cycles_init, cycles_max, true,
+ sleep ? FG_IMA_NO_WLOCK : FG_IMA_DEFAULT);
+ if (rc < 0) {
+ pr_err("Error in setting ESR timer, rc=%d\n", rc);
+ return rc;
+ }
+
+ return 0;
+}
+
static void fg_batt_avg_update(struct fg_chip *chip)
{
if (chip->charge_status == chip->prev_charge_status)
@@ -2112,6 +2167,10 @@ static void status_change_work(struct work_struct *work)
if (rc < 0)
pr_err("Error in adjusting FCC for ESR, rc=%d\n", rc);
+ rc = fg_esr_timer_config(chip, false);
+ if (rc < 0)
+ pr_err("Error in configuring ESR timer, rc=%d\n", rc);
+
rc = fg_get_battery_temp(chip, &batt_temp);
if (!rc) {
rc = fg_slope_limit_config(chip, batt_temp);
@@ -3115,6 +3174,8 @@ static const struct power_supply_desc fg_psy_desc = {
/* INIT FUNCTIONS STAY HERE */
+#define DEFAULT_ESR_CHG_TIMER_RETRY 8
+#define DEFAULT_ESR_CHG_TIMER_MAX 16
static int fg_hw_init(struct fg_chip *chip)
{
int rc;
@@ -3283,22 +3344,29 @@ static int fg_hw_init(struct fg_chip *chip)
return rc;
}
- if (chip->dt.esr_timer_charging > 0) {
- rc = fg_set_esr_timer(chip, chip->dt.esr_timer_charging, true,
- FG_IMA_DEFAULT);
- if (rc < 0) {
- pr_err("Error in setting ESR timer, rc=%d\n", rc);
- return rc;
- }
+ if (chip->pmic_rev_id->pmic_subtype == PMI8998_SUBTYPE) {
+ chip->esr_timer_charging_default[TIMER_RETRY] =
+ DEFAULT_ESR_CHG_TIMER_RETRY;
+ chip->esr_timer_charging_default[TIMER_MAX] =
+ DEFAULT_ESR_CHG_TIMER_MAX;
+ } else {
+ /* We don't need this for pm660 at present */
+ chip->esr_timer_charging_default[TIMER_RETRY] = -EINVAL;
+ chip->esr_timer_charging_default[TIMER_MAX] = -EINVAL;
}
- if (chip->dt.esr_timer_awake > 0) {
- rc = fg_set_esr_timer(chip, chip->dt.esr_timer_awake, false,
- FG_IMA_DEFAULT);
- if (rc < 0) {
- pr_err("Error in setting ESR timer, rc=%d\n", rc);
- return rc;
- }
+ rc = fg_set_esr_timer(chip, chip->dt.esr_timer_charging[TIMER_RETRY],
+ chip->dt.esr_timer_charging[TIMER_MAX], true, FG_IMA_DEFAULT);
+ if (rc < 0) {
+ pr_err("Error in setting ESR timer, rc=%d\n", rc);
+ return rc;
+ }
+
+ rc = fg_set_esr_timer(chip, chip->dt.esr_timer_awake[TIMER_RETRY],
+ chip->dt.esr_timer_awake[TIMER_MAX], false, FG_IMA_DEFAULT);
+ if (rc < 0) {
+ pr_err("Error in setting ESR timer, rc=%d\n", rc);
+ return rc;
}
if (chip->cyc_ctr.en)
@@ -3778,6 +3846,32 @@ static int fg_register_interrupts(struct fg_chip *chip)
return 0;
}
+static int fg_parse_dt_property_u32_array(struct device_node *node,
+ const char *prop_name, int *buf, int len)
+{
+ int rc;
+
+ rc = of_property_count_elems_of_size(node, prop_name, sizeof(u32));
+ if (rc < 0) {
+ if (rc == -EINVAL)
+ return 0;
+ else
+ return rc;
+ } else if (rc != len) {
+ pr_err("Incorrect length %d for %s, rc=%d\n", len, prop_name,
+ rc);
+ return -EINVAL;
+ }
+
+ rc = of_property_read_u32_array(node, prop_name, buf, len);
+ if (rc < 0) {
+ pr_err("Error in reading %s, rc=%d\n", prop_name, rc);
+ return rc;
+ }
+
+ return 0;
+}
+
static int fg_parse_slope_limit_coefficients(struct fg_chip *chip)
{
struct device_node *node = chip->dev->of_node;
@@ -3788,17 +3882,10 @@ static int fg_parse_slope_limit_coefficients(struct fg_chip *chip)
if (rc < 0)
return 0;
- rc = of_property_count_elems_of_size(node, "qcom,slope-limit-coeffs",
- sizeof(u32));
- if (rc != SLOPE_LIMIT_NUM_COEFFS)
- return -EINVAL;
-
- rc = of_property_read_u32_array(node, "qcom,slope-limit-coeffs",
- chip->dt.slope_limit_coeffs, SLOPE_LIMIT_NUM_COEFFS);
- if (rc < 0) {
- pr_err("Error in reading qcom,slope-limit-coeffs, rc=%d\n", rc);
+ rc = fg_parse_dt_property_u32_array(node, "qcom,slope-limit-coeffs",
+ chip->dt.slope_limit_coeffs, SLOPE_LIMIT_NUM_COEFFS);
+ if (rc < 0)
return rc;
- }
for (i = 0; i < SLOPE_LIMIT_NUM_COEFFS; i++) {
if (chip->dt.slope_limit_coeffs[i] > SLOPE_LIMIT_COEFF_MAX ||
@@ -3817,44 +3904,20 @@ static int fg_parse_ki_coefficients(struct fg_chip *chip)
struct device_node *node = chip->dev->of_node;
int rc, i;
- rc = of_property_count_elems_of_size(node, "qcom,ki-coeff-soc-dischg",
- sizeof(u32));
- if (rc != KI_COEFF_SOC_LEVELS)
- return 0;
-
- rc = of_property_read_u32_array(node, "qcom,ki-coeff-soc-dischg",
- chip->dt.ki_coeff_soc, KI_COEFF_SOC_LEVELS);
- if (rc < 0) {
- pr_err("Error in reading ki-coeff-soc-dischg, rc=%d\n",
- rc);
+ rc = fg_parse_dt_property_u32_array(node, "qcom,ki-coeff-soc-dischg",
+ chip->dt.ki_coeff_soc, KI_COEFF_SOC_LEVELS);
+ if (rc < 0)
return rc;
- }
- rc = of_property_count_elems_of_size(node, "qcom,ki-coeff-med-dischg",
- sizeof(u32));
- if (rc != KI_COEFF_SOC_LEVELS)
- return 0;
-
- rc = of_property_read_u32_array(node, "qcom,ki-coeff-med-dischg",
- chip->dt.ki_coeff_med_dischg, KI_COEFF_SOC_LEVELS);
- if (rc < 0) {
- pr_err("Error in reading ki-coeff-med-dischg, rc=%d\n",
- rc);
+ rc = fg_parse_dt_property_u32_array(node, "qcom,ki-coeff-med-dischg",
+ chip->dt.ki_coeff_med_dischg, KI_COEFF_SOC_LEVELS);
+ if (rc < 0)
return rc;
- }
- rc = of_property_count_elems_of_size(node, "qcom,ki-coeff-hi-dischg",
- sizeof(u32));
- if (rc != KI_COEFF_SOC_LEVELS)
- return 0;
-
- rc = of_property_read_u32_array(node, "qcom,ki-coeff-hi-dischg",
- chip->dt.ki_coeff_hi_dischg, KI_COEFF_SOC_LEVELS);
- if (rc < 0) {
- pr_err("Error in reading ki-coeff-hi-dischg, rc=%d\n",
- rc);
+ rc = fg_parse_dt_property_u32_array(node, "qcom,ki-coeff-hi-dischg",
+ chip->dt.ki_coeff_hi_dischg, KI_COEFF_SOC_LEVELS);
+ if (rc < 0)
return rc;
- }
for (i = 0; i < KI_COEFF_SOC_LEVELS; i++) {
if (chip->dt.ki_coeff_soc[i] < 0 ||
@@ -4099,23 +4162,26 @@ static int fg_parse_dt(struct fg_chip *chip)
rc);
}
- rc = of_property_read_u32(node, "qcom,fg-esr-timer-charging", &temp);
- if (rc < 0)
- chip->dt.esr_timer_charging = -EINVAL;
- else
- chip->dt.esr_timer_charging = temp;
+ rc = fg_parse_dt_property_u32_array(node, "qcom,fg-esr-timer-charging",
+ chip->dt.esr_timer_charging, NUM_ESR_TIMERS);
+ if (rc < 0) {
+ chip->dt.esr_timer_charging[TIMER_RETRY] = -EINVAL;
+ chip->dt.esr_timer_charging[TIMER_MAX] = -EINVAL;
+ }
- rc = of_property_read_u32(node, "qcom,fg-esr-timer-awake", &temp);
- if (rc < 0)
- chip->dt.esr_timer_awake = -EINVAL;
- else
- chip->dt.esr_timer_awake = temp;
+ rc = fg_parse_dt_property_u32_array(node, "qcom,fg-esr-timer-awake",
+ chip->dt.esr_timer_awake, NUM_ESR_TIMERS);
+ if (rc < 0) {
+ chip->dt.esr_timer_awake[TIMER_RETRY] = -EINVAL;
+ chip->dt.esr_timer_awake[TIMER_MAX] = -EINVAL;
+ }
- rc = of_property_read_u32(node, "qcom,fg-esr-timer-asleep", &temp);
- if (rc < 0)
- chip->dt.esr_timer_asleep = -EINVAL;
- else
- chip->dt.esr_timer_asleep = temp;
+ rc = fg_parse_dt_property_u32_array(node, "qcom,fg-esr-timer-asleep",
+ chip->dt.esr_timer_asleep, NUM_ESR_TIMERS);
+ if (rc < 0) {
+ chip->dt.esr_timer_asleep[TIMER_RETRY] = -EINVAL;
+ chip->dt.esr_timer_asleep[TIMER_MAX] = -EINVAL;
+ }
chip->cyc_ctr.en = of_property_read_bool(node, "qcom,cycle-counter-en");
if (chip->cyc_ctr.en)
@@ -4453,15 +4519,9 @@ static int fg_gen3_suspend(struct device *dev)
struct fg_chip *chip = dev_get_drvdata(dev);
int rc;
- if (chip->dt.esr_timer_awake > 0 && chip->dt.esr_timer_asleep > 0) {
- rc = fg_set_esr_timer(chip, chip->dt.esr_timer_asleep, false,
- FG_IMA_NO_WLOCK);
- if (rc < 0) {
- pr_err("Error in setting ESR timer during suspend, rc=%d\n",
- rc);
- return rc;
- }
- }
+ rc = fg_esr_timer_config(chip, true);
+ if (rc < 0)
+ pr_err("Error in configuring ESR timer, rc=%d\n", rc);
cancel_delayed_work_sync(&chip->batt_avg_work);
if (fg_sram_dump)
@@ -4474,15 +4534,9 @@ static int fg_gen3_resume(struct device *dev)
struct fg_chip *chip = dev_get_drvdata(dev);
int rc;
- if (chip->dt.esr_timer_awake > 0 && chip->dt.esr_timer_asleep > 0) {
- rc = fg_set_esr_timer(chip, chip->dt.esr_timer_awake, false,
- FG_IMA_DEFAULT);
- if (rc < 0) {
- pr_err("Error in setting ESR timer during resume, rc=%d\n",
- rc);
- return rc;
- }
- }
+ rc = fg_esr_timer_config(chip, false);
+ if (rc < 0)
+ pr_err("Error in configuring ESR timer, rc=%d\n", rc);
fg_circ_buf_clr(&chip->ibatt_circ_buf);
fg_circ_buf_clr(&chip->vbatt_circ_buf);
diff --git a/drivers/power/supply/qcom/qpnp-smb2.c b/drivers/power/supply/qcom/qpnp-smb2.c
index d3abfbfbbc43..803851d2b3ef 100644
--- a/drivers/power/supply/qcom/qpnp-smb2.c
+++ b/drivers/power/supply/qcom/qpnp-smb2.c
@@ -432,6 +432,7 @@ static enum power_supply_property smb2_usb_props[] = {
POWER_SUPPLY_PROP_CTM_CURRENT_MAX,
POWER_SUPPLY_PROP_HW_CURRENT_MAX,
POWER_SUPPLY_PROP_REAL_TYPE,
+ POWER_SUPPLY_PROP_PR_SWAP,
};
static int smb2_usb_get_prop(struct power_supply *psy,
@@ -454,8 +455,7 @@ static int smb2_usb_get_prop(struct power_supply *psy,
if (!val->intval)
break;
- rc = smblib_get_prop_typec_mode(chg, val);
- if ((val->intval == POWER_SUPPLY_TYPEC_SOURCE_DEFAULT ||
+ if ((chg->typec_mode == POWER_SUPPLY_TYPEC_SOURCE_DEFAULT ||
chg->micro_usb_mode) &&
chg->real_charger_type == POWER_SUPPLY_TYPE_USB)
val->intval = 0;
@@ -492,7 +492,7 @@ static int smb2_usb_get_prop(struct power_supply *psy,
else if (chip->bad_part)
val->intval = POWER_SUPPLY_TYPEC_SOURCE_DEFAULT;
else
- rc = smblib_get_prop_typec_mode(chg, val);
+ val->intval = chg->typec_mode;
break;
case POWER_SUPPLY_PROP_TYPEC_POWER_ROLE:
if (chg->micro_usb_mode)
@@ -536,6 +536,9 @@ static int smb2_usb_get_prop(struct power_supply *psy,
case POWER_SUPPLY_PROP_HW_CURRENT_MAX:
rc = smblib_get_charge_current(chg, &val->intval);
break;
+ case POWER_SUPPLY_PROP_PR_SWAP:
+ rc = smblib_get_prop_pr_swap_in_progress(chg, val);
+ break;
default:
pr_err("get prop %d is not supported in usb\n", psp);
rc = -EINVAL;
@@ -594,6 +597,9 @@ static int smb2_usb_set_prop(struct power_supply *psy,
rc = vote(chg->usb_icl_votable, CTM_VOTER,
val->intval >= 0, val->intval);
break;
+ case POWER_SUPPLY_PROP_PR_SWAP:
+ rc = smblib_set_prop_pr_swap_in_progress(chg, val);
+ break;
default:
pr_err("set prop %d is not supported\n", psp);
rc = -EINVAL;
@@ -671,8 +677,7 @@ static int smb2_usb_port_get_prop(struct power_supply *psy,
if (!val->intval)
break;
- rc = smblib_get_prop_typec_mode(chg, val);
- if ((val->intval == POWER_SUPPLY_TYPEC_SOURCE_DEFAULT ||
+ if ((chg->typec_mode == POWER_SUPPLY_TYPEC_SOURCE_DEFAULT ||
chg->micro_usb_mode) &&
chg->real_charger_type == POWER_SUPPLY_TYPE_USB)
val->intval = 1;
diff --git a/drivers/power/supply/qcom/smb-lib.c b/drivers/power/supply/qcom/smb-lib.c
index 4c66bc500ab4..21bd718f0848 100644
--- a/drivers/power/supply/qcom/smb-lib.c
+++ b/drivers/power/supply/qcom/smb-lib.c
@@ -841,7 +841,6 @@ int smblib_set_icl_current(struct smb_charger *chg, int icl_ua)
{
int rc = 0;
bool override;
- union power_supply_propval pval;
/* suspend and return if 25mA or less is requested */
if (icl_ua < USBIN_25MA)
@@ -851,14 +850,8 @@ int smblib_set_icl_current(struct smb_charger *chg, int icl_ua)
if (icl_ua == INT_MAX)
goto override_suspend_config;
- rc = smblib_get_prop_typec_mode(chg, &pval);
- if (rc < 0) {
- smblib_err(chg, "Couldn't get typeC mode rc = %d\n", rc);
- goto enable_icl_changed_interrupt;
- }
-
/* configure current */
- if (pval.intval == POWER_SUPPLY_TYPEC_SOURCE_DEFAULT
+ if (chg->typec_mode == POWER_SUPPLY_TYPEC_SOURCE_DEFAULT
&& (chg->real_charger_type == POWER_SUPPLY_TYPE_USB)) {
rc = set_sdp_current(chg, icl_ua);
if (rc < 0) {
@@ -880,7 +873,7 @@ override_suspend_config:
if (icl_ua == INT_MAX) {
/* remove override if no voters - hw defaults is desired */
override = false;
- } else if (pval.intval == POWER_SUPPLY_TYPEC_SOURCE_DEFAULT) {
+ } else if (chg->typec_mode == POWER_SUPPLY_TYPEC_SOURCE_DEFAULT) {
if (chg->real_charger_type == POWER_SUPPLY_TYPE_USB)
/* For std cable with type = SDP never override */
override = false;
@@ -920,15 +913,8 @@ int smblib_get_icl_current(struct smb_charger *chg, int *icl_ua)
int rc = 0;
u8 load_cfg;
bool override;
- union power_supply_propval pval;
-
- rc = smblib_get_prop_typec_mode(chg, &pval);
- if (rc < 0) {
- smblib_err(chg, "Couldn't get typeC mode rc = %d\n", rc);
- return rc;
- }
- if ((pval.intval == POWER_SUPPLY_TYPEC_SOURCE_DEFAULT
+ if ((chg->typec_mode == POWER_SUPPLY_TYPEC_SOURCE_DEFAULT
|| chg->micro_usb_mode)
&& (chg->usb_psy_desc.type == POWER_SUPPLY_TYPE_USB)) {
rc = get_sdp_current(chg, icl_ua);
@@ -2219,8 +2205,6 @@ static const char * const smblib_typec_mode_name[] = {
static int smblib_get_prop_ufp_mode(struct smb_charger *chg)
{
switch (chg->typec_status[0]) {
- case 0:
- return POWER_SUPPLY_TYPEC_NONE;
case UFP_TYPEC_RDSTD_BIT:
return POWER_SUPPLY_TYPEC_SOURCE_DEFAULT;
case UFP_TYPEC_RD1P5_BIT:
@@ -2231,7 +2215,7 @@ static int smblib_get_prop_ufp_mode(struct smb_charger *chg)
break;
}
- return POWER_SUPPLY_TYPEC_NON_COMPLIANT;
+ return POWER_SUPPLY_TYPEC_NONE;
}
static int smblib_get_prop_dfp_mode(struct smb_charger *chg)
@@ -2245,8 +2229,6 @@ static int smblib_get_prop_dfp_mode(struct smb_charger *chg)
return POWER_SUPPLY_TYPEC_SINK_POWERED_CABLE;
case DFP_RD_OPEN_BIT:
return POWER_SUPPLY_TYPEC_SINK;
- case DFP_RA_OPEN_BIT:
- return POWER_SUPPLY_TYPEC_POWERED_CABLE_ONLY;
default:
break;
}
@@ -2254,20 +2236,12 @@ static int smblib_get_prop_dfp_mode(struct smb_charger *chg)
return POWER_SUPPLY_TYPEC_NONE;
}
-int smblib_get_prop_typec_mode(struct smb_charger *chg,
- union power_supply_propval *val)
+static int smblib_get_prop_typec_mode(struct smb_charger *chg)
{
- if (!(chg->typec_status[3] & TYPEC_DEBOUNCE_DONE_STATUS_BIT)) {
- val->intval = POWER_SUPPLY_TYPEC_NONE;
- return 0;
- }
-
if (chg->typec_status[3] & UFP_DFP_MODE_STATUS_BIT)
- val->intval = smblib_get_prop_dfp_mode(chg);
+ return smblib_get_prop_dfp_mode(chg);
else
- val->intval = smblib_get_prop_ufp_mode(chg);
-
- return 0;
+ return smblib_get_prop_ufp_mode(chg);
}
int smblib_get_prop_typec_power_role(struct smb_charger *chg,
@@ -2555,24 +2529,12 @@ int smblib_set_prop_pd_active(struct smb_charger *chg,
const union power_supply_propval *val)
{
int rc;
- bool orientation, cc_debounced, sink_attached, hvdcp;
+ bool orientation, sink_attached, hvdcp;
u8 stat;
if (!get_effective_result(chg->pd_allowed_votable))
return -EINVAL;
- rc = smblib_read(chg, APSD_STATUS_REG, &stat);
- if (rc < 0) {
- smblib_err(chg, "Couldn't read APSD status rc=%d\n", rc);
- return rc;
- }
-
- cc_debounced = (bool)
- (chg->typec_status[3] & TYPEC_DEBOUNCE_DONE_STATUS_BIT);
- sink_attached = (bool)
- (chg->typec_status[3] & UFP_DFP_MODE_STATUS_BIT);
- hvdcp = stat & QC_CHARGER_BIT;
-
chg->pd_active = val->intval;
if (chg->pd_active) {
vote(chg->apsd_disable_votable, PD_VOTER, true, 0);
@@ -2624,6 +2586,14 @@ int smblib_set_prop_pd_active(struct smb_charger *chg,
if (rc < 0)
smblib_err(chg, "Couldn't unvote USB_PSY rc=%d\n", rc);
} else {
+ rc = smblib_read(chg, APSD_STATUS_REG, &stat);
+ if (rc < 0) {
+ smblib_err(chg, "Couldn't read APSD status rc=%d\n",
+ rc);
+ return rc;
+ }
+
+ hvdcp = stat & QC_CHARGER_BIT;
vote(chg->apsd_disable_votable, PD_VOTER, false, 0);
vote(chg->pd_allowed_votable, PD_VOTER, true, 0);
vote(chg->usb_irq_enable_votable, PD_VOTER, true, 0);
@@ -2643,8 +2613,8 @@ int smblib_set_prop_pd_active(struct smb_charger *chg,
* and data could be interrupted. Non-legacy DCP could also draw
* more, but it may impact compliance.
*/
- if (!chg->typec_legacy_valid && cc_debounced &&
- !sink_attached && hvdcp)
+ sink_attached = chg->typec_status[3] & UFP_DFP_MODE_STATUS_BIT;
+ if (!chg->typec_legacy_valid && !sink_attached && hvdcp)
schedule_work(&chg->legacy_detection_work);
}
@@ -2766,6 +2736,7 @@ static int smblib_cc2_sink_removal_enter(struct smb_charger *chg)
smblib_err(chg, "Couldn't read TYPE_C_STATUS_4 rc=%d\n", rc);
return rc;
}
+
ccout = (stat & CC_ATTACHED_BIT) ?
(!!(stat & CC_ORIENTATION_BIT) + 1) : 0;
ufp_mode = (stat & TYPEC_DEBOUNCE_DONE_STATUS_BIT) ?
@@ -3629,6 +3600,11 @@ static void smblib_handle_typec_removal(struct smb_charger *chg)
chg->pd_hard_reset = 0;
chg->typec_legacy_valid = false;
+ /* reset back to 120mS tCC debounce */
+ rc = smblib_masked_write(chg, MISC_CFG_REG, TCC_DEBOUNCE_20MS_BIT, 0);
+ if (rc < 0)
+ smblib_err(chg, "Couldn't set 120mS tCC debounce rc=%d\n", rc);
+
/* enable APSD CC trigger for next insertion */
rc = smblib_masked_write(chg, TYPE_C_CFG_REG,
APSD_START_ON_CC_BIT, APSD_START_ON_CC_BIT);
@@ -3669,12 +3645,29 @@ static void smblib_handle_typec_removal(struct smb_charger *chg)
if (rc < 0)
smblib_err(chg, "Couldn't restore crude sensor rc=%d\n", rc);
+ mutex_lock(&chg->vconn_oc_lock);
+ if (!chg->vconn_en)
+ goto unlock;
+
+ smblib_masked_write(chg, TYPE_C_INTRPT_ENB_SOFTWARE_CTRL_REG,
+ VCONN_EN_VALUE_BIT, 0);
+ chg->vconn_en = false;
+
+unlock:
+ mutex_unlock(&chg->vconn_oc_lock);
+
+ /* clear exit sink based on cc */
+ rc = smblib_masked_write(chg, TYPE_C_INTRPT_ENB_SOFTWARE_CTRL_REG,
+ EXIT_SNK_BASED_ON_CC_BIT, 0);
+ if (rc < 0)
+ smblib_err(chg, "Couldn't clear exit_sink_based_on_cc rc=%d\n",
+ rc);
+
typec_sink_removal(chg);
smblib_update_usb_type(chg);
}
-static void smblib_handle_typec_insertion(struct smb_charger *chg,
- bool sink_attached)
+static void smblib_handle_typec_insertion(struct smb_charger *chg)
{
int rc;
@@ -3686,45 +3679,37 @@ static void smblib_handle_typec_insertion(struct smb_charger *chg,
smblib_err(chg, "Couldn't disable APSD_START_ON_CC rc=%d\n",
rc);
- if (sink_attached)
+ if (chg->typec_status[3] & UFP_DFP_MODE_STATUS_BIT)
typec_sink_insertion(chg);
else
typec_sink_removal(chg);
}
-static void smblib_handle_typec_debounce_done(struct smb_charger *chg,
- bool rising, bool sink_attached)
+static void smblib_handle_typec_cc_state_change(struct smb_charger *chg)
{
- int rc;
- union power_supply_propval pval = {0, };
+ if (chg->pr_swap_in_progress)
+ return;
- if (rising) {
- if (!chg->typec_present) {
- chg->typec_present = true;
- smblib_dbg(chg, PR_MISC, "TypeC insertion\n");
- smblib_handle_typec_insertion(chg, sink_attached);
- }
- } else {
- if (chg->typec_present) {
- chg->typec_present = false;
- smblib_dbg(chg, PR_MISC, "TypeC removal\n");
- smblib_handle_typec_removal(chg);
- }
+ chg->typec_mode = smblib_get_prop_typec_mode(chg);
+ if (!chg->typec_present && chg->typec_mode != POWER_SUPPLY_TYPEC_NONE) {
+ chg->typec_present = true;
+ smblib_dbg(chg, PR_MISC, "TypeC %s insertion\n",
+ smblib_typec_mode_name[chg->typec_mode]);
+ smblib_handle_typec_insertion(chg);
+ } else if (chg->typec_present &&
+ chg->typec_mode == POWER_SUPPLY_TYPEC_NONE) {
+ chg->typec_present = false;
+ smblib_dbg(chg, PR_MISC, "TypeC removal\n");
+ smblib_handle_typec_removal(chg);
}
- rc = smblib_get_prop_typec_mode(chg, &pval);
- if (rc < 0)
- smblib_err(chg, "Couldn't get prop typec mode rc=%d\n", rc);
-
- smblib_dbg(chg, PR_INTERRUPT, "IRQ: debounce-done %s; Type-C %s detected\n",
- rising ? "rising" : "falling",
- smblib_typec_mode_name[pval.intval]);
+ smblib_dbg(chg, PR_INTERRUPT, "IRQ: cc-state-change; Type-C %s detected\n",
+ smblib_typec_mode_name[chg->typec_mode]);
}
static void smblib_usb_typec_change(struct smb_charger *chg)
{
int rc;
- bool debounce_done, sink_attached;
rc = smblib_multibyte_read(chg, TYPE_C_STATUS_1_REG,
chg->typec_status, 5);
@@ -3733,12 +3718,7 @@ static void smblib_usb_typec_change(struct smb_charger *chg)
return;
}
- debounce_done =
- (bool)(chg->typec_status[3] & TYPEC_DEBOUNCE_DONE_STATUS_BIT);
- sink_attached =
- (bool)(chg->typec_status[3] & UFP_DFP_MODE_STATUS_BIT);
-
- smblib_handle_typec_debounce_done(chg, debounce_done, sink_attached);
+ smblib_handle_typec_cc_state_change(chg);
if (chg->typec_status[3] & TYPEC_VBUS_ERROR_STATUS_BIT)
smblib_dbg(chg, PR_INTERRUPT, "IRQ: vbus-error\n");
@@ -3841,6 +3821,36 @@ irqreturn_t smblib_handle_wdog_bark(int irq, void *data)
return IRQ_HANDLED;
}
+/**************
+ * Additional USB PSY getters/setters
+ * that call interrupt functions
+***************/
+
+int smblib_get_prop_pr_swap_in_progress(struct smb_charger *chg,
+ union power_supply_propval *val)
+{
+ val->intval = chg->pr_swap_in_progress;
+ return 0;
+}
+
+int smblib_set_prop_pr_swap_in_progress(struct smb_charger *chg,
+ const union power_supply_propval *val)
+{
+ int rc;
+
+ chg->pr_swap_in_progress = val->intval;
+ /*
+ * call the cc changed irq to handle real removals while
+ * PR_SWAP was in progress
+ */
+ smblib_usb_typec_change(chg);
+ rc = smblib_masked_write(chg, MISC_CFG_REG, TCC_DEBOUNCE_20MS_BIT,
+ val->intval ? TCC_DEBOUNCE_20MS_BIT : 0);
+ if (rc < 0)
+ smblib_err(chg, "Couldn't set tCC debounce rc=%d\n", rc);
+ return 0;
+}
+
/***************
* Work Queues *
***************/
@@ -4229,14 +4239,14 @@ static void smblib_legacy_detection_work(struct work_struct *work)
chg->typec_legacy_valid = true;
vote(chg->usb_icl_votable, LEGACY_UNKNOWN_VOTER, false, 0);
legacy = stat & TYPEC_LEGACY_CABLE_STATUS_BIT;
- rp_high = smblib_get_prop_ufp_mode(chg) ==
- POWER_SUPPLY_TYPEC_SOURCE_HIGH;
+ rp_high = chg->typec_mode == POWER_SUPPLY_TYPEC_SOURCE_HIGH;
if (!legacy || !rp_high)
vote(chg->hvdcp_disable_votable_indirect, VBUS_CC_SHORT_VOTER,
false, 0);
unlock:
chg->typec_en_dis_active = 0;
+ smblib_usb_typec_change(chg);
mutex_unlock(&chg->lock);
}
diff --git a/drivers/power/supply/qcom/smb-lib.h b/drivers/power/supply/qcom/smb-lib.h
index 41015d49b31e..8ba0a1dfe19f 100644
--- a/drivers/power/supply/qcom/smb-lib.h
+++ b/drivers/power/supply/qcom/smb-lib.h
@@ -321,6 +321,8 @@ struct smb_charger {
u8 typec_status[5];
bool typec_legacy_valid;
int fake_input_current_limited;
+ bool pr_swap_in_progress;
+ int typec_mode;
/* workaround flag */
u32 wa_flags;
@@ -452,8 +454,6 @@ int smblib_get_prop_usb_current_now(struct smb_charger *chg,
union power_supply_propval *val);
int smblib_get_prop_typec_cc_orientation(struct smb_charger *chg,
union power_supply_propval *val);
-int smblib_get_prop_typec_mode(struct smb_charger *chg,
- union power_supply_propval *val);
int smblib_get_prop_typec_power_role(struct smb_charger *chg,
union power_supply_propval *val);
int smblib_get_prop_pd_allowed(struct smb_charger *chg,
@@ -506,6 +506,10 @@ int smblib_rerun_aicl(struct smb_charger *chg);
int smblib_set_icl_current(struct smb_charger *chg, int icl_ua);
int smblib_get_icl_current(struct smb_charger *chg, int *icl_ua);
int smblib_get_charge_current(struct smb_charger *chg, int *total_current_ua);
+int smblib_get_prop_pr_swap_in_progress(struct smb_charger *chg,
+ union power_supply_propval *val);
+int smblib_set_prop_pr_swap_in_progress(struct smb_charger *chg,
+ const union power_supply_propval *val);
int smblib_init(struct smb_charger *chg);
int smblib_deinit(struct smb_charger *chg);
diff --git a/drivers/power/supply/qcom/smb-reg.h b/drivers/power/supply/qcom/smb-reg.h
index 167666a8c548..d8671ab1fd06 100644
--- a/drivers/power/supply/qcom/smb-reg.h
+++ b/drivers/power/supply/qcom/smb-reg.h
@@ -486,11 +486,11 @@ enum {
#define UFP_TYPEC_OPEN_OPEN_BIT BIT(0)
#define TYPE_C_STATUS_2_REG (USBIN_BASE + 0x0C)
-#define DFP_TYPEC_MASK 0x8F
#define DFP_RA_OPEN_BIT BIT(7)
#define TIMER_STAGE_BIT BIT(6)
#define EXIT_UFP_MODE_BIT BIT(5)
#define EXIT_DFP_MODE_BIT BIT(4)
+#define DFP_TYPEC_MASK GENMASK(3, 0)
#define DFP_RD_OPEN_BIT BIT(3)
#define DFP_RD_RA_VCONN_BIT BIT(2)
#define DFP_RD_RD_BIT BIT(1)
diff --git a/drivers/power/supply/qcom/smb1351-charger.c b/drivers/power/supply/qcom/smb1351-charger.c
index 7014fd706d9e..f5c8252b5e41 100644
--- a/drivers/power/supply/qcom/smb1351-charger.c
+++ b/drivers/power/supply/qcom/smb1351-charger.c
@@ -1416,6 +1416,7 @@ static enum power_supply_property smb1351_parallel_properties[] = {
POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX,
POWER_SUPPLY_PROP_CHARGE_TYPE,
POWER_SUPPLY_PROP_PARALLEL_MODE,
+ POWER_SUPPLY_PROP_INPUT_SUSPEND,
};
static int smb1351_parallel_set_chg_suspend(struct smb1351_charger *chip,
@@ -1702,6 +1703,9 @@ static int smb1351_parallel_get_property(struct power_supply *psy,
case POWER_SUPPLY_PROP_PARALLEL_MODE:
val->intval = chip->parallel_mode;
break;
+ case POWER_SUPPLY_PROP_INPUT_SUSPEND:
+ val->intval = chip->parallel_charger_suspended;
+ break;
default:
return -EINVAL;
}
diff --git a/drivers/power/supply/qcom/smb138x-charger.c b/drivers/power/supply/qcom/smb138x-charger.c
index 694591c3ec56..335b160e24a5 100644
--- a/drivers/power/supply/qcom/smb138x-charger.c
+++ b/drivers/power/supply/qcom/smb138x-charger.c
@@ -248,7 +248,7 @@ static int smb138x_usb_get_prop(struct power_supply *psy,
val->intval = chg->usb_psy_desc.type;
break;
case POWER_SUPPLY_PROP_TYPEC_MODE:
- rc = smblib_get_prop_typec_mode(chg, val);
+ val->intval = chg->typec_mode;
break;
case POWER_SUPPLY_PROP_TYPEC_POWER_ROLE:
rc = smblib_get_prop_typec_power_role(chg, val);
@@ -941,13 +941,6 @@ static int smb138x_init_slave_hw(struct smb138x *chip)
return rc;
}
- rc = smblib_write(chg, THERMREG_SRC_CFG_REG,
- THERMREG_SKIN_ADC_SRC_EN_BIT);
- if (rc < 0) {
- pr_err("Couldn't enable connector thermreg source rc=%d\n", rc);
- return rc;
- }
-
return 0;
}
diff --git a/drivers/regulator/cpr3-hmss-regulator.c b/drivers/regulator/cpr3-hmss-regulator.c
index 9a20b6925877..21381d1ad7fa 100644
--- a/drivers/regulator/cpr3-hmss-regulator.c
+++ b/drivers/regulator/cpr3-hmss-regulator.c
@@ -1505,7 +1505,7 @@ static int cpr3_hmss_init_regulator(struct cpr3_regulator *vreg)
static int cpr3_hmss_init_aging(struct cpr3_controller *ctrl)
{
struct cpr3_msm8996_hmss_fuses *fuse = NULL;
- struct cpr3_regulator *vreg;
+ struct cpr3_regulator *vreg = NULL;
u32 aging_ro_scale;
int i, j, rc;
@@ -1710,7 +1710,7 @@ static int cpr3_hmss_regulator_probe(struct platform_device *pdev)
struct device *dev = &pdev->dev;
const struct of_device_id *match;
struct cpr3_controller *ctrl;
- struct cpr3_regulator *vreg;
+ struct cpr3_regulator *vreg = NULL;
int i, j, rc;
if (!dev->of_node) {
diff --git a/drivers/regulator/cpr3-regulator.c b/drivers/regulator/cpr3-regulator.c
index d131a8ea4144..3adbd41ede88 100644
--- a/drivers/regulator/cpr3-regulator.c
+++ b/drivers/regulator/cpr3-regulator.c
@@ -3117,7 +3117,8 @@ static int _cpr3_regulator_update_ctrl_state(struct cpr3_controller *ctrl)
struct cpr4_sdelta *sdelta;
bool valid = false;
bool thread_valid;
- int i, j, rc, new_volt, vdd_volt, dynamic_floor_volt, last_corner_volt;
+ int i, j, rc;
+ int new_volt, vdd_volt, dynamic_floor_volt, last_corner_volt = 0;
u32 reg_last_measurement = 0, sdelta_size;
int *sdelta_table, *boost_table;
diff --git a/drivers/regulator/cprh-kbss-regulator.c b/drivers/regulator/cprh-kbss-regulator.c
index 2307da9497dc..ecf7885a4bff 100644
--- a/drivers/regulator/cprh-kbss-regulator.c
+++ b/drivers/regulator/cprh-kbss-regulator.c
@@ -1975,7 +1975,7 @@ static int cprh_kbss_init_regulator(struct cpr3_regulator *vreg)
static int cprh_kbss_init_aging(struct cpr3_controller *ctrl)
{
struct cprh_kbss_fuses *fuse = NULL;
- struct cpr3_regulator *vreg;
+ struct cpr3_regulator *vreg = NULL;
u32 aging_ro_scale;
int i, j, rc = 0;
diff --git a/drivers/regulator/qpnp-regulator.c b/drivers/regulator/qpnp-regulator.c
index bd706658348d..08e991fa7db3 100644
--- a/drivers/regulator/qpnp-regulator.c
+++ b/drivers/regulator/qpnp-regulator.c
@@ -127,6 +127,9 @@ enum qpnp_common_regulator_registers {
QPNP_COMMON_REG_ENABLE = 0x46,
QPNP_COMMON_REG_PULL_DOWN = 0x48,
QPNP_COMMON_REG_STEP_CTRL = 0x61,
+ QPNP_COMMON_REG_UL_LL_CTRL = 0x68,
+ QPNP_COMMON_REG_VOLTAGE_ULS_VALID = 0x6A,
+ QPNP_COMMON_REG_VOLTAGE_LLS_VALID = 0x6C,
};
/*
@@ -139,6 +142,8 @@ enum qpnp_common2_regulator_registers {
QPNP_COMMON2_REG_VOLTAGE_MSB = 0x41,
QPNP_COMMON2_REG_MODE = 0x45,
QPNP_COMMON2_REG_STEP_CTRL = 0x61,
+ QPNP_COMMON2_REG_VOLTAGE_ULS_LSB = 0x68,
+ QPNP_COMMON2_REG_VOLTAGE_ULS_MSB = 0x69,
};
enum qpnp_ldo_registers {
@@ -205,6 +210,10 @@ enum qpnp_common2_control_register_index {
/* Common regulator pull down control register layout */
#define QPNP_COMMON_PULL_DOWN_ENABLE_MASK 0x80
+/* Common regulator UL & LL limits control register layout */
+#define QPNP_COMMON_UL_EN_MASK 0x80
+#define QPNP_COMMON_LL_EN_MASK 0x40
+
/* LDO regulator current limit control register layout */
#define QPNP_LDO_CURRENT_LIMIT_ENABLE_MASK 0x80
@@ -1749,6 +1758,89 @@ static int qpnp_regulator_match(struct qpnp_regulator *vreg)
return rc;
}
+static int qpnp_regulator_check_constraints(struct qpnp_regulator *vreg,
+ struct qpnp_regulator_platform_data *pdata)
+{
+ struct qpnp_voltage_range *range = NULL;
+ int i, rc = 0, limit_min_uV, limit_max_uV, max_uV;
+ u8 reg[2];
+
+ limit_min_uV = 0;
+ limit_max_uV = INT_MAX;
+
+ if (vreg->logical_type == QPNP_REGULATOR_LOGICAL_TYPE_FTSMPS) {
+ max_uV = pdata->init_data.constraints.max_uV;
+ /* Find the range which max_uV is inside of. */
+ for (i = vreg->set_points->count - 1; i > 0; i--) {
+ range = &vreg->set_points->range[i];
+ if (range->set_point_max_uV > 0
+ && max_uV >= range->set_point_min_uV
+ && max_uV <= range->set_point_max_uV)
+ break;
+ }
+
+ if (i < 0 || range == NULL) {
+ vreg_err(vreg, "max_uV doesn't fit in any voltage range\n");
+ return -EINVAL;
+ }
+
+ rc = qpnp_vreg_read(vreg, QPNP_COMMON_REG_UL_LL_CTRL,
+ &reg[0], 1);
+ if (rc) {
+ vreg_err(vreg, "UL_LL register read failed, rc=%d\n",
+ rc);
+ return rc;
+ }
+
+ if (reg[0] & QPNP_COMMON_UL_EN_MASK) {
+ rc = qpnp_vreg_read(vreg,
+ QPNP_COMMON_REG_VOLTAGE_ULS_VALID,
+ &reg[1], 1);
+ if (rc) {
+ vreg_err(vreg, "ULS_VALID register read failed, rc=%d\n",
+ rc);
+ return rc;
+ }
+
+ limit_max_uV = range->step_uV * reg[1] + range->min_uV;
+ }
+
+ if (reg[0] & QPNP_COMMON_LL_EN_MASK) {
+ rc = qpnp_vreg_read(vreg,
+ QPNP_COMMON_REG_VOLTAGE_LLS_VALID,
+ &reg[1], 1);
+ if (rc) {
+ vreg_err(vreg, "LLS_VALID register read failed, rc=%d\n",
+ rc);
+ return rc;
+ }
+
+ limit_min_uV = range->step_uV * reg[1] + range->min_uV;
+ }
+ } else if (vreg->logical_type == QPNP_REGULATOR_LOGICAL_TYPE_FTSMPS2) {
+ rc = qpnp_vreg_read(vreg, QPNP_COMMON2_REG_VOLTAGE_ULS_LSB,
+ reg, 2);
+ if (rc) {
+ vreg_err(vreg, "ULS registers read failed, rc=%d\n",
+ rc);
+ return rc;
+ }
+
+ limit_max_uV = (((int)reg[1] << 8) | (int)reg[0]) * 1000;
+ }
+
+ if (pdata->init_data.constraints.min_uV < limit_min_uV
+ || pdata->init_data.constraints.max_uV > limit_max_uV) {
+ vreg_err(vreg, "regulator min/max(%d/%d) constraints do not fit within HW configured min/max(%d/%d) constraints\n",
+ pdata->init_data.constraints.min_uV,
+ pdata->init_data.constraints.max_uV,
+ limit_min_uV, limit_max_uV);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
static int qpnp_regulator_ftsmps_init_slew_rate(struct qpnp_regulator *vreg)
{
int rc;
@@ -2282,6 +2374,13 @@ static int qpnp_regulator_probe(struct platform_device *pdev)
}
}
+ rc = qpnp_regulator_check_constraints(vreg, pdata);
+ if (rc) {
+ vreg_err(vreg, "regulator constraints check failed, rc=%d\n",
+ rc);
+ goto bail;
+ }
+
rc = qpnp_regulator_init_registers(vreg, pdata);
if (rc) {
vreg_err(vreg, "common initialization failed, rc=%d\n", rc);
diff --git a/drivers/regulator/rpm-smd-regulator.c b/drivers/regulator/rpm-smd-regulator.c
index d26fd3bea788..a5dc1b983bcb 100644
--- a/drivers/regulator/rpm-smd-regulator.c
+++ b/drivers/regulator/rpm-smd-regulator.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012-2016, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-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
@@ -207,6 +207,7 @@ struct rpm_regulator {
bool use_pin_ctrl_for_enable;
struct rpm_vreg_request req;
int system_load;
+ int hpm_threshold_current;
int min_uV;
int max_uV;
u32 pin_ctrl_mask[RPM_VREG_PIN_CTRL_STATE_COUNT];
@@ -1030,6 +1031,34 @@ static unsigned int rpm_vreg_get_bob_mode(struct regulator_dev *rdev)
return mode;
}
+static unsigned int rpm_vreg_get_optimum_mode(struct regulator_dev *rdev,
+ int input_uV, int output_uV, int load_uA)
+{
+ struct rpm_regulator *reg = rdev_get_drvdata(rdev);
+ u32 mode = REGULATOR_MODE_NORMAL;
+
+ if (reg->hpm_threshold_current > 0) {
+ if (load_uA >= reg->hpm_threshold_current) {
+ /* PWM mode */
+ mode = (reg->rpm_vreg->regulator_type
+ == RPM_REGULATOR_TYPE_BOB)
+ ? REGULATOR_MODE_FAST
+ : REGULATOR_MODE_NORMAL;
+ } else {
+ /* AUTO mode */
+ mode = (reg->rpm_vreg->regulator_type
+ == RPM_REGULATOR_TYPE_BOB)
+ ? REGULATOR_MODE_NORMAL
+ : REGULATOR_MODE_IDLE;
+ }
+ } else {
+ /* Default to the current mode if no threshold is present. */
+ mode = reg->rdesc.ops->get_mode(rdev);
+ }
+
+ return mode;
+}
+
static int rpm_vreg_enable_time(struct regulator_dev *rdev)
{
struct rpm_regulator *reg = rdev_get_drvdata(rdev);
@@ -1402,6 +1431,18 @@ static struct regulator_ops smps_ops = {
.enable_time = rpm_vreg_enable_time,
};
+static struct regulator_ops smps_optimum_mode_ops = {
+ .enable = rpm_vreg_enable,
+ .disable = rpm_vreg_disable,
+ .is_enabled = rpm_vreg_is_enabled,
+ .set_voltage = rpm_vreg_set_voltage,
+ .get_voltage = rpm_vreg_get_voltage,
+ .set_mode = rpm_vreg_set_mode,
+ .get_mode = rpm_vreg_get_mode,
+ .get_optimum_mode = rpm_vreg_get_optimum_mode,
+ .enable_time = rpm_vreg_enable_time,
+};
+
static struct regulator_ops switch_ops = {
.enable = rpm_vreg_enable,
.disable = rpm_vreg_disable,
@@ -1426,6 +1467,7 @@ static struct regulator_ops bob_ops = {
.get_voltage = rpm_vreg_get_voltage,
.set_mode = rpm_vreg_set_bob_mode,
.get_mode = rpm_vreg_get_bob_mode,
+ .get_optimum_mode = rpm_vreg_get_optimum_mode,
.enable_time = rpm_vreg_enable_time,
};
@@ -1676,6 +1718,12 @@ static int rpm_vreg_device_probe(struct platform_device *pdev)
if (of_get_property(node, "parent-supply", NULL))
init_data->supply_regulator = "parent";
+ of_property_read_u32(node, "qcom,pwm-threshold-current",
+ &reg->hpm_threshold_current);
+ if (reg->hpm_threshold_current > 0
+ && regulator_type == RPM_REGULATOR_TYPE_SMPS)
+ reg->rdesc.ops = &smps_optimum_mode_ops;
+
/*
* Fill in ops and mode masks based on callbacks specified for
* this type of regulator.
@@ -1689,8 +1737,13 @@ static int rpm_vreg_device_probe(struct platform_device *pdev)
if (reg->rdesc.ops->get_mode) {
init_data->constraints.valid_ops_mask
|= REGULATOR_CHANGE_MODE | REGULATOR_CHANGE_DRMS;
- init_data->constraints.valid_modes_mask
- |= REGULATOR_MODE_NORMAL | REGULATOR_MODE_IDLE;
+
+ if (regulator_type == RPM_REGULATOR_TYPE_BOB)
+ init_data->constraints.valid_modes_mask
+ = REGULATOR_MODE_FAST | REGULATOR_MODE_NORMAL;
+ else
+ init_data->constraints.valid_modes_mask
+ |= REGULATOR_MODE_NORMAL | REGULATOR_MODE_IDLE;
}
reg->rdesc.name = init_data->constraints.name;
diff --git a/drivers/regulator/spm-regulator.c b/drivers/regulator/spm-regulator.c
index 484f0412addf..d469463a0b00 100644
--- a/drivers/regulator/spm-regulator.c
+++ b/drivers/regulator/spm-regulator.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2013-2016, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2013-2017, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -49,6 +49,7 @@ enum qpnp_regulator_uniq_type {
QPNP_TYPE_HF,
QPNP_TYPE_FTS2,
QPNP_TYPE_FTS2p5,
+ QPNP_TYPE_FTS426,
QPNP_TYPE_ULT_HF,
};
@@ -56,6 +57,7 @@ enum qpnp_regulator_type {
QPNP_HF_TYPE = 0x03,
QPNP_FTS2_TYPE = 0x1C,
QPNP_FTS2p5_TYPE = 0x1C,
+ QPNP_FTS426_TYPE = 0x1C,
QPNP_ULT_HF_TYPE = 0x22,
};
@@ -63,15 +65,22 @@ enum qpnp_regulator_subtype {
QPNP_FTS2_SUBTYPE = 0x08,
QPNP_HF_SUBTYPE = 0x08,
QPNP_FTS2p5_SUBTYPE = 0x09,
+ QPNP_FTS426_SUBTYPE = 0x0A,
QPNP_ULT_HF_SUBTYPE = 0x0D,
};
+enum qpnp_logical_mode {
+ QPNP_LOGICAL_MODE_AUTO,
+ QPNP_LOGICAL_MODE_PWM,
+};
+
static const struct voltage_range fts2_range0 = {0, 350000, 1275000, 5000};
static const struct voltage_range fts2_range1 = {0, 700000, 2040000, 10000};
static const struct voltage_range fts2p5_range0
= { 80000, 350000, 1355000, 5000};
static const struct voltage_range fts2p5_range1
= {160000, 700000, 2200000, 10000};
+static const struct voltage_range fts426_range = {0, 320000, 1352000, 4000};
static const struct voltage_range ult_hf_range0 = {375000, 375000, 1562500,
12500};
static const struct voltage_range ult_hf_range1 = {750000, 750000, 1525000,
@@ -86,17 +95,45 @@ static const struct voltage_range hf_range1 = {1550000, 1550000, 3125000,
#define QPNP_SMPS_REG_VOLTAGE_SETPOINT 0x41
#define QPNP_SMPS_REG_MODE 0x45
#define QPNP_SMPS_REG_STEP_CTRL 0x61
+#define QPNP_SMPS_REG_UL_LL_CTRL 0x68
+
+/* FTS426 voltage control registers */
+#define QPNP_FTS426_REG_VOLTAGE_LB 0x40
+#define QPNP_FTS426_REG_VOLTAGE_UB 0x41
+#define QPNP_FTS426_REG_VOLTAGE_VALID_LB 0x42
+#define QPNP_FTS426_REG_VOLTAGE_VALID_UB 0x43
+
+/* HF voltage limit registers */
+#define QPNP_HF_REG_VOLTAGE_ULS 0x69
+#define QPNP_HF_REG_VOLTAGE_LLS 0x6B
+
+/* FTS voltage limit registers */
+#define QPNP_FTS_REG_VOLTAGE_ULS_VALID 0x6A
+#define QPNP_FTS_REG_VOLTAGE_LLS_VALID 0x6C
+
+/* FTS426 voltage limit registers */
+#define QPNP_FTS426_REG_VOLTAGE_ULS_LB 0x68
+#define QPNP_FTS426_REG_VOLTAGE_ULS_UB 0x69
+
+/* Common regulator UL & LL limits control register layout */
+#define QPNP_COMMON_UL_EN_MASK 0x80
+#define QPNP_COMMON_LL_EN_MASK 0x40
#define QPNP_SMPS_MODE_PWM 0x80
#define QPNP_SMPS_MODE_AUTO 0x40
+#define QPNP_FTS426_MODE_PWM 0x07
+#define QPNP_FTS426_MODE_AUTO 0x06
#define QPNP_SMPS_STEP_CTRL_STEP_MASK 0x18
#define QPNP_SMPS_STEP_CTRL_STEP_SHIFT 3
#define QPNP_SMPS_STEP_CTRL_DELAY_MASK 0x07
#define QPNP_SMPS_STEP_CTRL_DELAY_SHIFT 0
+#define QPNP_FTS426_STEP_CTRL_DELAY_MASK 0x03
+#define QPNP_FTS426_STEP_CTRL_DELAY_SHIFT 0
/* Clock rate in kHz of the FTS2 regulator reference clock. */
#define QPNP_SMPS_CLOCK_RATE 19200
+#define QPNP_FTS426_CLOCK_RATE 4800
/* Time to delay in us to ensure that a mode change has completed. */
#define QPNP_FTS2_MODE_CHANGE_DELAY 50
@@ -107,6 +144,7 @@ static const struct voltage_range hf_range1 = {1550000, 1550000, 3125000,
/* Minimum voltage stepper delay for each step. */
#define QPNP_FTS2_STEP_DELAY 8
#define QPNP_HF_STEP_DELAY 20
+#define QPNP_FTS426_STEP_DELAY 2
/* Arbitrarily large max step size used to avoid possible numerical overflow */
#define SPM_REGULATOR_MAX_STEP_UV 10000000
@@ -117,6 +155,8 @@ static const struct voltage_range hf_range1 = {1550000, 1550000, 3125000,
*/
#define QPNP_FTS2_STEP_MARGIN_NUM 4
#define QPNP_FTS2_STEP_MARGIN_DEN 5
+#define QPNP_FTS426_STEP_MARGIN_NUM 10
+#define QPNP_FTS426_STEP_MARGIN_DEN 11
/*
* Settling delay for FTS2.5
@@ -140,8 +180,8 @@ struct spm_vreg {
u32 max_step_uV;
bool online;
u16 spmi_base_addr;
- u8 init_mode;
- u8 mode;
+ enum qpnp_logical_mode init_mode;
+ enum qpnp_logical_mode mode;
int step_rate;
enum qpnp_regulator_uniq_type regulator_type;
u32 cpu_num;
@@ -163,6 +203,9 @@ static int spm_regulator_uv_to_vlevel(struct spm_vreg *vreg, int uV)
{
int vlevel;
+ if (vreg->regulator_type == QPNP_TYPE_FTS426)
+ return roundup(uV, vreg->range->step_uV) / 1000;
+
vlevel = DIV_ROUND_UP(uV - vreg->range->min_uV, vreg->range->step_uV);
/* Fix VSET for ULT HF Buck */
@@ -177,6 +220,8 @@ static int spm_regulator_uv_to_vlevel(struct spm_vreg *vreg, int uV)
static int spm_regulator_vlevel_to_uv(struct spm_vreg *vreg, int vlevel)
{
+ if (vreg->regulator_type == QPNP_TYPE_FTS426)
+ return vlevel * 1000;
/*
* Calculate ULT HF buck VSET based on range:
* In case of range 0: VSET is a 7 bit value.
@@ -204,32 +249,91 @@ static unsigned spm_regulator_vlevel_to_selector(struct spm_vreg *vreg,
static int qpnp_smps_read_voltage(struct spm_vreg *vreg)
{
int rc;
- u8 reg = 0;
- uint val;
+ u8 val[2] = {0};
- rc = regmap_read(vreg->regmap,
- vreg->spmi_base_addr + QPNP_SMPS_REG_VOLTAGE_SETPOINT,
- &val);
- if (rc) {
- dev_err(&vreg->pdev->dev,
- "%s: could not read voltage setpoint register, rc=%d\n",
- __func__, rc);
- return rc;
+ if (vreg->regulator_type == QPNP_TYPE_FTS426) {
+ rc = regmap_bulk_read(vreg->regmap,
+ vreg->spmi_base_addr + QPNP_FTS426_REG_VOLTAGE_VALID_LB,
+ val, 2);
+ if (rc) {
+ dev_err(&vreg->pdev->dev, "%s: could not read voltage setpoint registers, rc=%d\n",
+ __func__, rc);
+ return rc;
+ }
+
+ vreg->last_set_vlevel = ((unsigned)val[1] << 8) | val[0];
+ } else {
+ rc = regmap_bulk_read(vreg->regmap,
+ vreg->spmi_base_addr + QPNP_SMPS_REG_VOLTAGE_SETPOINT,
+ val, 1);
+ if (rc) {
+ dev_err(&vreg->pdev->dev, "%s: could not read voltage setpoint register, rc=%d\n",
+ __func__, rc);
+ return rc;
+ }
+ vreg->last_set_vlevel = val[0];
}
- reg = (u8)val;
- vreg->last_set_vlevel = reg;
- vreg->last_set_uV = spm_regulator_vlevel_to_uv(vreg, reg);
+ vreg->last_set_uV = spm_regulator_vlevel_to_uv(vreg,
+ vreg->last_set_vlevel);
+ return rc;
+}
+
+static int qpnp_smps_write_voltage(struct spm_vreg *vreg, unsigned vlevel)
+{
+ int rc = 0;
+ u8 reg[2];
+
+ /* Set voltage control registers via SPMI. */
+ reg[0] = vlevel & 0xFF;
+ reg[1] = (vlevel >> 8) & 0xFF;
+
+ if (vreg->regulator_type == QPNP_TYPE_FTS426) {
+ rc = regmap_bulk_write(vreg->regmap,
+ vreg->spmi_base_addr + QPNP_FTS426_REG_VOLTAGE_LB,
+ reg, 2);
+ } else {
+ rc = regmap_write(vreg->regmap,
+ vreg->spmi_base_addr + QPNP_SMPS_REG_VOLTAGE_SETPOINT,
+ reg[0]);
+ }
+
+ if (rc)
+ pr_err("%s: regmap_write failed, rc=%d\n",
+ vreg->rdesc.name, rc);
return rc;
}
+static inline enum qpnp_logical_mode qpnp_regval_to_mode(struct spm_vreg *vreg,
+ u8 regval)
+{
+ if (vreg->regulator_type == QPNP_TYPE_FTS426)
+ return (regval == QPNP_FTS426_MODE_PWM)
+ ? QPNP_LOGICAL_MODE_PWM : QPNP_LOGICAL_MODE_AUTO;
+ else
+ return (regval & QPNP_SMPS_MODE_PWM)
+ ? QPNP_LOGICAL_MODE_PWM : QPNP_LOGICAL_MODE_AUTO;
+}
+
+static inline u8 qpnp_mode_to_regval(struct spm_vreg *vreg,
+ enum qpnp_logical_mode mode)
+{
+ if (vreg->regulator_type == QPNP_TYPE_FTS426)
+ return (mode == QPNP_LOGICAL_MODE_PWM)
+ ? QPNP_FTS426_MODE_PWM : QPNP_FTS426_MODE_AUTO;
+ else
+ return (mode == QPNP_LOGICAL_MODE_PWM)
+ ? QPNP_SMPS_MODE_PWM : QPNP_SMPS_MODE_AUTO;
+}
+
static int qpnp_smps_set_mode(struct spm_vreg *vreg, u8 mode)
{
int rc;
rc = regmap_write(vreg->regmap,
- vreg->spmi_base_addr + QPNP_SMPS_REG_MODE, mode);
+ vreg->spmi_base_addr + QPNP_SMPS_REG_MODE,
+ qpnp_mode_to_regval(vreg, mode));
if (rc)
dev_err(&vreg->pdev->dev,
"%s: could not write to mode register, rc=%d\n",
@@ -275,7 +379,6 @@ static int spm_regulator_write_voltage(struct spm_vreg *vreg, int uV)
bool spm_failed = false;
int rc = 0;
u32 slew_delay;
- u8 reg;
if (likely(!vreg->bypass_spm)) {
/* Set voltage control register via SPM. */
@@ -288,13 +391,9 @@ static int spm_regulator_write_voltage(struct spm_vreg *vreg, int uV)
}
if (unlikely(vreg->bypass_spm || spm_failed)) {
- /* Set voltage control register via SPMI. */
- reg = vlevel;
- rc = regmap_write(vreg->regmap,
- vreg->spmi_base_addr + QPNP_SMPS_REG_VOLTAGE_SETPOINT,
- reg);
+ rc = qpnp_smps_write_voltage(vreg, vlevel);
if (rc) {
- pr_err("%s: regmap_write failed, rc=%d\n",
+ pr_err("%s: voltage write failed, rc=%d\n",
vreg->rdesc.name, rc);
return rc;
}
@@ -351,12 +450,12 @@ static int _spm_regulator_set_voltage(struct regulator_dev *rdev)
return 0;
pwm_required = (vreg->regulator_type == QPNP_TYPE_FTS2)
- && !(vreg->init_mode & QPNP_SMPS_MODE_PWM)
+ && (vreg->init_mode != QPNP_LOGICAL_MODE_PWM)
&& vreg->uV > vreg->last_set_uV;
if (pwm_required) {
/* Switch to PWM mode so that voltage ramping is fast. */
- rc = qpnp_smps_set_mode(vreg, QPNP_SMPS_MODE_PWM);
+ rc = qpnp_smps_set_mode(vreg, QPNP_LOGICAL_MODE_PWM);
if (rc)
return rc;
}
@@ -375,7 +474,7 @@ static int _spm_regulator_set_voltage(struct regulator_dev *rdev)
/* Wait for mode transition to complete. */
udelay(QPNP_FTS2_MODE_CHANGE_DELAY - QPNP_SPMI_WRITE_MIN_DELAY);
/* Switch to AUTO mode so that power consumption is lowered. */
- rc = qpnp_smps_set_mode(vreg, QPNP_SMPS_MODE_AUTO);
+ rc = qpnp_smps_set_mode(vreg, QPNP_LOGICAL_MODE_AUTO);
if (rc)
return rc;
}
@@ -466,7 +565,7 @@ static unsigned int spm_regulator_get_mode(struct regulator_dev *rdev)
{
struct spm_vreg *vreg = rdev_get_drvdata(rdev);
- return vreg->mode == QPNP_SMPS_MODE_PWM
+ return vreg->mode == QPNP_LOGICAL_MODE_PWM
? REGULATOR_MODE_NORMAL : REGULATOR_MODE_IDLE;
}
@@ -480,8 +579,8 @@ static int spm_regulator_set_mode(struct regulator_dev *rdev, unsigned int mode)
* in the case that qcom,mode has been specified as "pwm" in device
* tree.
*/
- vreg->mode
- = mode == REGULATOR_MODE_NORMAL ? QPNP_SMPS_MODE_PWM : vreg->init_mode;
+ vreg->mode = (mode == REGULATOR_MODE_NORMAL) ? QPNP_LOGICAL_MODE_PWM
+ : vreg->init_mode;
return qpnp_smps_set_mode(vreg, vreg->mode);
}
@@ -538,7 +637,7 @@ static int spm_regulator_avs_set_voltage(struct regulator_dev *rdev, int min_uV,
return -EINVAL;
}
- vlevel_max = (uV - range->min_uV) / range->step_uV;
+ vlevel_max = spm_regulator_uv_to_vlevel(vreg, uV);
avs_max_uV = spm_regulator_vlevel_to_uv(vreg, vlevel_max);
if (avs_max_uV < min_uV) {
@@ -646,6 +745,9 @@ static int qpnp_smps_check_type(struct spm_vreg *vreg)
} else if (type[0] == QPNP_FTS2p5_TYPE
&& type[1] == QPNP_FTS2p5_SUBTYPE) {
vreg->regulator_type = QPNP_TYPE_FTS2p5;
+ } else if (type[0] == QPNP_FTS426_TYPE
+ && type[1] == QPNP_FTS426_SUBTYPE) {
+ vreg->regulator_type = QPNP_TYPE_FTS426;
} else if (type[0] == QPNP_ULT_HF_TYPE
&& type[1] == QPNP_ULT_HF_SUBTYPE) {
vreg->regulator_type = QPNP_TYPE_ULT_HF;
@@ -750,10 +852,10 @@ static int qpnp_smps_init_mode(struct spm_vreg *vreg)
&mode_name);
if (!rc) {
if (strcmp("pwm", mode_name) == 0) {
- vreg->init_mode = QPNP_SMPS_MODE_PWM;
+ vreg->init_mode = QPNP_LOGICAL_MODE_PWM;
} else if ((strcmp("auto", mode_name) == 0) &&
(vreg->regulator_type != QPNP_TYPE_ULT_HF)) {
- vreg->init_mode = QPNP_SMPS_MODE_AUTO;
+ vreg->init_mode = QPNP_LOGICAL_MODE_AUTO;
} else {
dev_err(&vreg->pdev->dev,
"%s: unknown regulator mode: %s\n",
@@ -761,13 +863,9 @@ static int qpnp_smps_init_mode(struct spm_vreg *vreg)
return -EINVAL;
}
- rc = regmap_write(vreg->regmap,
- vreg->spmi_base_addr + QPNP_SMPS_REG_MODE,
- *&vreg->init_mode);
+ rc = qpnp_smps_set_mode(vreg, vreg->init_mode);
if (rc)
- dev_err(&vreg->pdev->dev,
- "%s: could not write mode register, rc=%d\n",
- __func__, rc);
+ return rc;
} else {
rc = regmap_read(vreg->regmap,
vreg->spmi_base_addr + QPNP_SMPS_REG_MODE,
@@ -776,7 +874,7 @@ static int qpnp_smps_init_mode(struct spm_vreg *vreg)
dev_err(&vreg->pdev->dev,
"%s: could not read mode register, rc=%d\n",
__func__, rc);
- vreg->init_mode = (u8)val;
+ vreg->init_mode = qpnp_regval_to_mode(vreg, val);
}
vreg->mode = vreg->init_mode;
@@ -801,26 +899,41 @@ static int qpnp_smps_init_step_rate(struct spm_vreg *vreg)
}
reg = (u8)val;
- /* ULT buck does not support steps */
- if (vreg->regulator_type != QPNP_TYPE_ULT_HF)
+ /* ULT and FTS426 bucks do not support steps */
+ if (vreg->regulator_type != QPNP_TYPE_ULT_HF && vreg->regulator_type !=
+ QPNP_TYPE_FTS426)
step = (reg & QPNP_SMPS_STEP_CTRL_STEP_MASK)
>> QPNP_SMPS_STEP_CTRL_STEP_SHIFT;
- delay = (reg & QPNP_SMPS_STEP_CTRL_DELAY_MASK)
- >> QPNP_SMPS_STEP_CTRL_DELAY_SHIFT;
+ if (vreg->regulator_type == QPNP_TYPE_FTS426) {
+ delay = (reg & QPNP_FTS426_STEP_CTRL_DELAY_MASK)
+ >> QPNP_FTS426_STEP_CTRL_DELAY_SHIFT;
- /* step_rate has units of uV/us. */
- vreg->step_rate = QPNP_SMPS_CLOCK_RATE * vreg->range->step_uV
- * (1 << step);
+ /* step_rate has units of uV/us. */
+ vreg->step_rate = QPNP_FTS426_CLOCK_RATE * vreg->range->step_uV;
+ } else {
+ delay = (reg & QPNP_SMPS_STEP_CTRL_DELAY_MASK)
+ >> QPNP_SMPS_STEP_CTRL_DELAY_SHIFT;
+
+ /* step_rate has units of uV/us. */
+ vreg->step_rate = QPNP_SMPS_CLOCK_RATE * vreg->range->step_uV
+ * (1 << step);
+ }
if ((vreg->regulator_type == QPNP_TYPE_ULT_HF)
|| (vreg->regulator_type == QPNP_TYPE_HF))
vreg->step_rate /= 1000 * (QPNP_HF_STEP_DELAY << delay);
+ else if (vreg->regulator_type == QPNP_TYPE_FTS426)
+ vreg->step_rate /= 1000 * (QPNP_FTS426_STEP_DELAY << delay);
else
vreg->step_rate /= 1000 * (QPNP_FTS2_STEP_DELAY << delay);
- vreg->step_rate = vreg->step_rate * QPNP_FTS2_STEP_MARGIN_NUM
- / QPNP_FTS2_STEP_MARGIN_DEN;
+ if (vreg->regulator_type == QPNP_TYPE_FTS426)
+ vreg->step_rate = vreg->step_rate * QPNP_FTS426_STEP_MARGIN_NUM
+ / QPNP_FTS426_STEP_MARGIN_DEN;
+ else
+ vreg->step_rate = vreg->step_rate * QPNP_FTS2_STEP_MARGIN_NUM
+ / QPNP_FTS2_STEP_MARGIN_DEN;
/* Ensure that the stepping rate is greater than 0. */
vreg->step_rate = max(vreg->step_rate, 1);
@@ -828,10 +941,93 @@ static int qpnp_smps_init_step_rate(struct spm_vreg *vreg)
return rc;
}
+static int qpnp_smps_check_constraints(struct spm_vreg *vreg,
+ struct regulator_init_data *init_data)
+{
+ int rc = 0, limit_min_uV, limit_max_uV;
+ u16 ul_reg, ll_reg;
+ u8 reg[2];
+
+ limit_min_uV = 0;
+ limit_max_uV = INT_MAX;
+
+ ul_reg = QPNP_FTS_REG_VOLTAGE_ULS_VALID;
+ ll_reg = QPNP_FTS_REG_VOLTAGE_LLS_VALID;
+
+ switch (vreg->regulator_type) {
+ case QPNP_TYPE_HF:
+ ul_reg = QPNP_HF_REG_VOLTAGE_ULS;
+ ll_reg = QPNP_HF_REG_VOLTAGE_LLS;
+ case QPNP_TYPE_FTS2:
+ case QPNP_TYPE_FTS2p5:
+ rc = regmap_bulk_read(vreg->regmap, vreg->spmi_base_addr
+ + QPNP_SMPS_REG_UL_LL_CTRL, reg, 1);
+ if (rc) {
+ dev_err(&vreg->pdev->dev, "%s: UL_LL register read failed, rc=%d\n",
+ __func__, rc);
+ return rc;
+ }
+
+ if (reg[0] & QPNP_COMMON_UL_EN_MASK) {
+ rc = regmap_bulk_read(vreg->regmap, vreg->spmi_base_addr
+ + ul_reg, &reg[1], 1);
+ if (rc) {
+ dev_err(&vreg->pdev->dev, "%s: ULS register read failed, rc=%d\n",
+ __func__, rc);
+ return rc;
+ }
+
+ limit_max_uV = spm_regulator_vlevel_to_uv(vreg, reg[1]);
+ }
+
+ if (reg[0] & QPNP_COMMON_LL_EN_MASK) {
+ rc = regmap_bulk_read(vreg->regmap, vreg->spmi_base_addr
+ + ll_reg, &reg[1], 1);
+ if (rc) {
+ dev_err(&vreg->pdev->dev, "%s: LLS register read failed, rc=%d\n",
+ __func__, rc);
+ return rc;
+ }
+
+ limit_min_uV = spm_regulator_vlevel_to_uv(vreg, reg[1]);
+ }
+
+ break;
+ case QPNP_TYPE_FTS426:
+ rc = regmap_bulk_read(vreg->regmap, vreg->spmi_base_addr
+ + QPNP_FTS426_REG_VOLTAGE_ULS_LB,
+ reg, 2);
+ if (rc) {
+ dev_err(&vreg->pdev->dev, "%s: could not read voltage limit registers, rc=%d\n",
+ __func__, rc);
+ return rc;
+ }
+
+ limit_max_uV = spm_regulator_vlevel_to_uv(vreg,
+ ((unsigned)reg[1] << 8) | reg[0]);
+ break;
+ case QPNP_TYPE_ULT_HF:
+ /* no HW voltage limit configuration */
+ break;
+ }
+
+ if (init_data->constraints.min_uV < limit_min_uV
+ || init_data->constraints.max_uV > limit_max_uV) {
+ dev_err(&vreg->pdev->dev, "regulator min/max(%d/%d) constraints do not fit within HW configured min/max(%d/%d) constraints\n",
+ init_data->constraints.min_uV,
+ init_data->constraints.max_uV, limit_min_uV,
+ limit_max_uV);
+ return -EINVAL;
+ }
+
+ return rc;
+}
+
static bool spm_regulator_using_range0(struct spm_vreg *vreg)
{
return vreg->range == &fts2_range0 || vreg->range == &fts2p5_range0
- || vreg->range == &ult_hf_range0 || vreg->range == &hf_range0;
+ || vreg->range == &ult_hf_range0 || vreg->range == &hf_range0
+ || vreg->range == &fts426_range;
}
/* Register a regulator to enable/disable AVS and set AVS min/max limits. */
@@ -969,6 +1165,8 @@ static int spm_regulator_probe(struct platform_device *pdev)
rc = qpnp_smps_init_range(vreg, &fts2_range0, &fts2_range1);
else if (vreg->regulator_type == QPNP_TYPE_FTS2p5)
rc = qpnp_smps_init_range(vreg, &fts2p5_range0, &fts2p5_range1);
+ else if (vreg->regulator_type == QPNP_TYPE_FTS426)
+ vreg->range = &fts426_range;
else if (vreg->regulator_type == QPNP_TYPE_HF)
rc = qpnp_smps_init_range(vreg, &hf_range0, &hf_range1);
else if (vreg->regulator_type == QPNP_TYPE_ULT_HF)
@@ -1006,6 +1204,13 @@ static int spm_regulator_probe(struct platform_device *pdev)
return -EINVAL;
}
+ rc = qpnp_smps_check_constraints(vreg, init_data);
+ if (rc) {
+ dev_err(&pdev->dev, "%s: regulator constraints check failed, rc=%d\n",
+ __func__, rc);
+ return rc;
+ }
+
vreg->rdesc.name = init_data->constraints.name;
vreg->rdesc.type = REGULATOR_VOLTAGE;
vreg->rdesc.owner = THIS_MODULE;
@@ -1050,8 +1255,8 @@ static int spm_regulator_probe(struct platform_device *pdev)
vreg->rdesc.name,
spm_regulator_using_range0(vreg) ? "LV" : "MV",
vreg->uV,
- vreg->init_mode & QPNP_SMPS_MODE_PWM ? "PWM" :
- (vreg->init_mode & QPNP_SMPS_MODE_AUTO ? "AUTO" : "PFM"),
+ vreg->init_mode == QPNP_LOGICAL_MODE_PWM ? "PWM" :
+ (vreg->init_mode == QPNP_LOGICAL_MODE_AUTO ? "AUTO" : "PFM"),
vreg->step_rate);
return rc;
diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
index a90c51a113d2..b8dc7e834cf3 100644
--- a/drivers/scsi/ufs/ufshcd.c
+++ b/drivers/scsi/ufs/ufshcd.c
@@ -3285,8 +3285,10 @@ static int ufshcd_exec_dev_cmd(struct ufs_hba *hba,
/*
* May get invoked from shutdown and IOCTL contexts.
* In shutdown context, it comes in with lock acquired.
+ * In error recovery context, it may come with lock acquired.
*/
- if (!ufshcd_is_shutdown_ongoing(hba))
+
+ if (!ufshcd_is_shutdown_ongoing(hba) && !ufshcd_eh_in_progress(hba))
down_read(&hba->lock);
/*
@@ -3320,7 +3322,7 @@ static int ufshcd_exec_dev_cmd(struct ufs_hba *hba,
out_put_tag:
ufshcd_put_dev_cmd_tag(hba, tag);
wake_up(&hba->dev_cmd.tag_wq);
- if (!ufshcd_is_shutdown_ongoing(hba))
+ if (!ufshcd_is_shutdown_ongoing(hba) && !ufshcd_eh_in_progress(hba))
up_read(&hba->lock);
return err;
}
diff --git a/drivers/soc/qcom/glink_smem_native_xprt.c b/drivers/soc/qcom/glink_smem_native_xprt.c
index 168db46084df..8385987e8888 100644
--- a/drivers/soc/qcom/glink_smem_native_xprt.c
+++ b/drivers/soc/qcom/glink_smem_native_xprt.c
@@ -849,7 +849,7 @@ static void __rx_worker(struct edge_info *einfo, bool atomic_ctx)
rcu_id = srcu_read_lock(&einfo->use_ref);
- if (unlikely(!einfo->rx_fifo)) {
+ if (unlikely(!einfo->rx_fifo) && atomic_ctx) {
if (!get_rx_fifo(einfo)) {
srcu_read_unlock(&einfo->use_ref, rcu_id);
return;
diff --git a/drivers/soc/qcom/ipc_router_glink_xprt.c b/drivers/soc/qcom/ipc_router_glink_xprt.c
index 1f36dd0ba07e..7dd1683881fb 100644
--- a/drivers/soc/qcom/ipc_router_glink_xprt.c
+++ b/drivers/soc/qcom/ipc_router_glink_xprt.c
@@ -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
@@ -70,6 +70,7 @@ if (ipc_router_glink_xprt_debug_mask) \
* @xprt_version: IPC Router header version supported by this XPRT.
* @xprt_option: XPRT specific options to be handled by IPC Router.
* @disable_pil_loading: Disable PIL Loading of the subsystem.
+ * @dynamic_wakeup_source: Dynamic wakeup source for this subsystem.
*/
struct ipc_router_glink_xprt {
struct list_head list;
@@ -91,6 +92,7 @@ struct ipc_router_glink_xprt {
uint32_t cur_lo_intents_cnt;
uint32_t cur_md_intents_cnt;
uint32_t cur_hi_intents_cnt;
+ bool dynamic_wakeup_source;
};
struct ipc_router_glink_xprt_work {
@@ -127,6 +129,7 @@ static void glink_xprt_close_event(struct work_struct *work);
* @link_id: Network Cluster ID to which this XPRT belongs to.
* @xprt_version: IPC Router header version supported by this XPRT.
* @disable_pil_loading:Disable PIL Loading of the subsystem.
+ * @dynamic_wakeup_source: Dynamic wakeup source for this subsystem.
*/
struct ipc_router_glink_xprt_config {
char ch_name[GLINK_NAME_SIZE];
@@ -138,6 +141,7 @@ struct ipc_router_glink_xprt_config {
unsigned xprt_version;
unsigned xprt_option;
bool disable_pil_loading;
+ bool dynamic_wakeup_source;
};
#define MODULE_NAME "ipc_router_glink_xprt"
@@ -292,6 +296,14 @@ static void glink_xprt_sft_close_done(struct msm_ipc_router_xprt *xprt)
complete_all(&glink_xprtp->sft_close_complete);
}
+static bool ipc_router_glink_xprt_get_ws_info(struct msm_ipc_router_xprt *xprt)
+{
+ struct ipc_router_glink_xprt *glink_xprtp =
+ container_of(xprt, struct ipc_router_glink_xprt, xprt);
+
+ return glink_xprtp->dynamic_wakeup_source;
+}
+
static struct rr_packet *glink_xprt_copy_data(struct read_work *rx_work)
{
void *buf, *pbuf, *dest_buf;
@@ -705,6 +717,8 @@ static int ipc_router_glink_config_init(
glink_xprtp->xprt_option = glink_xprt_config->xprt_option;
glink_xprtp->disable_pil_loading =
glink_xprt_config->disable_pil_loading;
+ glink_xprtp->dynamic_wakeup_source =
+ glink_xprt_config->dynamic_wakeup_source;
if (!glink_xprtp->disable_pil_loading)
strlcpy(glink_xprtp->pil_edge, glink_xprt_config->pil_edge,
@@ -727,6 +741,7 @@ static int ipc_router_glink_config_init(
glink_xprtp->xprt.write = ipc_router_glink_xprt_write;
glink_xprtp->xprt.close = ipc_router_glink_xprt_close;
glink_xprtp->xprt.sft_close_done = glink_xprt_sft_close_done;
+ glink_xprtp->xprt.get_ws_info = ipc_router_glink_xprt_get_ws_info;
glink_xprtp->xprt.priv = NULL;
init_rwsem(&glink_xprtp->ss_reset_rwlock);
@@ -821,6 +836,10 @@ static int parse_devicetree(struct device_node *node,
scnprintf(glink_xprt_config->ipc_rtr_xprt_name, IPC_RTR_XPRT_NAME_LEN,
"%s_%s", edge, ch_name);
+ key = "qcom,dynamic-wakeup-source";
+ glink_xprt_config->dynamic_wakeup_source =
+ of_property_read_bool(node, key);
+
return 0;
error:
diff --git a/drivers/soc/qcom/msm_bus/msm_bus_rules.c b/drivers/soc/qcom/msm_bus/msm_bus_rules.c
index ea29e303bbde..43a892bbd27c 100644
--- a/drivers/soc/qcom/msm_bus/msm_bus_rules.c
+++ b/drivers/soc/qcom/msm_bus/msm_bus_rules.c
@@ -597,7 +597,7 @@ void msm_rule_register(int num_rules, struct bus_rule_type *rule,
static bool __rule_unregister(int num_rules, struct bus_rule_type *rule,
struct notifier_block *nb)
{
- int i;
+ int i = 0;
struct rule_node_info *node = NULL;
struct rule_node_info *node_tmp = NULL;
struct rules_def *node_rule;
diff --git a/drivers/soc/qcom/peripheral-loader.c b/drivers/soc/qcom/peripheral-loader.c
index ed8006cacc08..ace2bc4f30b6 100644
--- a/drivers/soc/qcom/peripheral-loader.c
+++ b/drivers/soc/qcom/peripheral-loader.c
@@ -39,6 +39,8 @@
#include <asm/uaccess.h>
#include <asm/setup.h>
#include <asm-generic/io-64-nonatomic-lo-hi.h>
+#define CREATE_TRACE_POINTS
+#include <trace/events/trace_msm_pil_event.h>
#include "peripheral-loader.h"
@@ -835,6 +837,7 @@ int pil_boot(struct pil_desc *desc)
goto release_fw;
}
+ trace_pil_event("before_init_image", desc);
if (desc->ops->init_image)
ret = desc->ops->init_image(desc, fw->data, fw->size);
if (ret) {
@@ -843,6 +846,7 @@ int pil_boot(struct pil_desc *desc)
goto err_boot;
}
+ trace_pil_event("before_mem_setup", desc);
if (desc->ops->mem_setup)
ret = desc->ops->mem_setup(desc, priv->region_start,
priv->region_end - priv->region_start);
@@ -858,6 +862,7 @@ int pil_boot(struct pil_desc *desc)
* Also for secure boot devices, modem memory has to be released
* after MBA is booted
*/
+ trace_pil_event("before_assign_mem", desc);
if (desc->modem_ssr) {
ret = pil_assign_mem_to_linux(desc, priv->region_start,
(priv->region_end - priv->region_start));
@@ -876,6 +881,7 @@ int pil_boot(struct pil_desc *desc)
hyp_assign = true;
}
+ trace_pil_event("before_load_seg", desc);
list_for_each_entry(seg, &desc->priv->segs, list) {
ret = pil_load_seg(desc, seg);
if (ret)
@@ -883,6 +889,7 @@ int pil_boot(struct pil_desc *desc)
}
if (desc->subsys_vmid > 0) {
+ trace_pil_event("before_reclaim_mem", desc);
ret = pil_reclaim_mem(desc, priv->region_start,
(priv->region_end - priv->region_start),
desc->subsys_vmid);
@@ -894,12 +901,14 @@ int pil_boot(struct pil_desc *desc)
hyp_assign = false;
}
+ trace_pil_event("before_auth_reset", desc);
ret = desc->ops->auth_and_reset(desc);
if (ret) {
pil_err(desc, "Failed to bring out of reset(rc:%d)\n", ret);
subsys_set_error(desc->subsys_dev, firmware_error_msg);
goto err_auth_and_reset;
}
+ trace_pil_event("reset_done", desc);
pil_info(desc, "Brought out of reset\n");
desc->modem_ssr = false;
err_auth_and_reset:
diff --git a/drivers/soc/qcom/pil-msa.c b/drivers/soc/qcom/pil-msa.c
index 988b6e8c9fd9..5fcb0f95733c 100644
--- a/drivers/soc/qcom/pil-msa.c
+++ b/drivers/soc/qcom/pil-msa.c
@@ -26,6 +26,7 @@
#include <linux/highmem.h>
#include <soc/qcom/scm.h>
#include <soc/qcom/secure_buffer.h>
+#include <trace/events/trace_msm_pil_event.h>
#include "peripheral-loader.h"
#include "pil-q6v5.h"
@@ -462,6 +463,7 @@ static int pil_mss_reset(struct pil_desc *pil)
phys_addr_t start_addr = pil_get_entry_addr(pil);
int ret;
+ trace_pil_func(__func__);
if (drv->mba_dp_phys)
start_addr = drv->mba_dp_phys;
@@ -555,6 +557,7 @@ int pil_mss_reset_load_mba(struct pil_desc *pil)
const u8 *data;
struct device *dma_dev = md->mba_mem_dev_fixed ?: &md->mba_mem_dev;
+ trace_pil_func(__func__);
fw_name_p = drv->non_elf_image ? fw_name_legacy : fw_name;
ret = request_firmware(&fw, fw_name_p, pil->dev);
if (ret) {
@@ -685,6 +688,7 @@ static int pil_msa_auth_modem_mdt(struct pil_desc *pil, const u8 *metadata,
DEFINE_DMA_ATTRS(attrs);
+ trace_pil_func(__func__);
dma_dev->coherent_dma_mask = DMA_BIT_MASK(sizeof(dma_addr_t) * 8);
dma_set_attr(DMA_ATTR_SKIP_ZEROING, &attrs);
dma_set_attr(DMA_ATTR_STRONGLY_ORDERED, &attrs);
diff --git a/drivers/soc/qcom/pil-q6v5.c b/drivers/soc/qcom/pil-q6v5.c
index 34228f072b28..15415e78f98e 100644
--- a/drivers/soc/qcom/pil-q6v5.c
+++ b/drivers/soc/qcom/pil-q6v5.c
@@ -22,6 +22,7 @@
#include <linux/regulator/consumer.h>
#include <linux/regulator/rpm-smd-regulator.h>
#include <linux/clk/msm-clk.h>
+#include <trace/events/trace_msm_pil_event.h>
#include "peripheral-loader.h"
#include "pil-q6v5.h"
@@ -360,6 +361,7 @@ static int __pil_q6v55_reset(struct pil_desc *pil)
u32 val;
int i;
+ trace_pil_func(__func__);
/* Override the ACC value if required */
if (drv->override_acc)
writel_relaxed(QDSP6SS_ACC_OVERRIDE_VAL,
diff --git a/drivers/soc/qcom/qbt1000.c b/drivers/soc/qcom/qbt1000.c
index 6e7d34ac9163..d14e82415c5a 100644
--- a/drivers/soc/qcom/qbt1000.c
+++ b/drivers/soc/qcom/qbt1000.c
@@ -145,18 +145,17 @@ static int get_cmd_rsp_buffers(struct qseecom_handle *hdl,
uint32_t *rsp_len)
{
/* 64 bytes alignment for QSEECOM */
- *cmd_len = ALIGN(*cmd_len, 64);
- *rsp_len = ALIGN(*rsp_len, 64);
+ uint64_t aligned_cmd_len = ALIGN((uint64_t)*cmd_len, 64);
+ uint64_t aligned_rsp_len = ALIGN((uint64_t)*rsp_len, 64);
- if (((uint64_t)*rsp_len + (uint64_t)*cmd_len)
- > (uint64_t)g_app_buf_size) {
- pr_err("buffer too small to hold cmd=%d and rsp=%d\n",
- *cmd_len, *rsp_len);
+ if ((aligned_rsp_len + aligned_cmd_len) > (uint64_t)g_app_buf_size)
return -ENOMEM;
- }
*cmd = hdl->sbuf;
+ *cmd_len = aligned_cmd_len;
*rsp = hdl->sbuf + *cmd_len;
+ *rsp_len = aligned_rsp_len;
+
return 0;
}
diff --git a/drivers/soc/qcom/qdsp6v2/apr.c b/drivers/soc/qcom/qdsp6v2/apr.c
index 2da8731c5753..eca992ec17e4 100644
--- a/drivers/soc/qcom/qdsp6v2/apr.c
+++ b/drivers/soc/qcom/qdsp6v2/apr.c
@@ -886,8 +886,10 @@ static int apr_notifier_service_cb(struct notifier_block *this,
* recovery notifications during initial boot
* up since everything is expected to be down.
*/
- if (is_initial_boot)
+ if (is_initial_boot) {
+ is_initial_boot = false;
break;
+ }
if (cb_data->domain == AUDIO_NOTIFIER_MODEM_DOMAIN)
apr_modem_down(opcode);
else
@@ -907,7 +909,12 @@ done:
return NOTIFY_OK;
}
-static struct notifier_block service_nb = {
+static struct notifier_block adsp_service_nb = {
+ .notifier_call = apr_notifier_service_cb,
+ .priority = 0,
+};
+
+static struct notifier_block modem_service_nb = {
.notifier_call = apr_notifier_service_cb,
.priority = 0,
};
@@ -937,9 +944,9 @@ static int __init apr_init(void)
is_initial_boot = true;
subsys_notif_register("apr_adsp", AUDIO_NOTIFIER_ADSP_DOMAIN,
- &service_nb);
+ &adsp_service_nb);
subsys_notif_register("apr_modem", AUDIO_NOTIFIER_MODEM_DOMAIN,
- &service_nb);
+ &modem_service_nb);
return 0;
}
diff --git a/drivers/soc/qcom/smp2p_sleepstate.c b/drivers/soc/qcom/smp2p_sleepstate.c
index 04b043fbd8ec..34b46d25a823 100644
--- a/drivers/soc/qcom/smp2p_sleepstate.c
+++ b/drivers/soc/qcom/smp2p_sleepstate.c
@@ -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
@@ -46,6 +46,7 @@ static int sleepstate_pm_notifier(struct notifier_block *nb,
static struct notifier_block sleepstate_pm_nb = {
.notifier_call = sleepstate_pm_notifier,
+ .priority = INT_MAX,
};
static int smp2p_sleepstate_probe(struct platform_device *pdev)
diff --git a/drivers/soc/qcom/spcom.c b/drivers/soc/qcom/spcom.c
index 0e1e4ae975b0..7f03aabf415e 100644
--- a/drivers/soc/qcom/spcom.c
+++ b/drivers/soc/qcom/spcom.c
@@ -96,8 +96,6 @@
/* SPCOM driver name */
#define DEVICE_NAME "spcom"
-#define SPCOM_MAX_CHANNELS 0x20
-
/* maximum ION buffers should be >= SPCOM_MAX_CHANNELS */
#define SPCOM_MAX_ION_BUF_PER_CH (SPCOM_MAX_CHANNELS + 4)
@@ -718,8 +716,10 @@ static int spcom_open(struct spcom_channel *ch, unsigned int timeout_msec)
/* only one client/server may use the channel */
if (ch->ref_count) {
- pr_err("channel [%s] already in use.\n", name);
- goto exit_err;
+ pr_err("channel [%s] is BUSY, already in use by pid [%d].\n",
+ name, ch->pid);
+ mutex_unlock(&ch->lock);
+ return -EBUSY;
}
pr_debug("ch [%s] opened by PID [%d], count [%d]\n",
diff --git a/drivers/soc/qcom/subsys-pil-tz.c b/drivers/soc/qcom/subsys-pil-tz.c
index 991bce363740..f85c4ba06b47 100644
--- a/drivers/soc/qcom/subsys-pil-tz.c
+++ b/drivers/soc/qcom/subsys-pil-tz.c
@@ -1113,6 +1113,7 @@ static int pil_tz_driver_probe(struct platform_device *pdev)
rc = PTR_ERR(d->subsys);
goto err_subsys;
}
+ d->desc.subsys_dev = d->subsys;
return 0;
err_subsys:
diff --git a/drivers/soc/qcom/subsystem_restart.c b/drivers/soc/qcom/subsystem_restart.c
index 6afe2fb8cd75..ae249f382339 100644
--- a/drivers/soc/qcom/subsystem_restart.c
+++ b/drivers/soc/qcom/subsystem_restart.c
@@ -35,6 +35,7 @@
#include <soc/qcom/subsystem_restart.h>
#include <soc/qcom/subsystem_notif.h>
#include <soc/qcom/sysmon.h>
+#include <trace/events/trace_msm_pil_event.h>
#include <asm/current.h>
@@ -539,8 +540,10 @@ static void notify_each_subsys_device(struct subsys_device **list,
notif_data.no_auth = dev->desc->no_auth;
notif_data.pdev = pdev;
+ trace_pil_notif("before_send_notif", notif, dev->desc->fw_name);
subsys_notif_queue_notification(dev->notify, notif,
&notif_data);
+ trace_pil_notif("after_send_notif", notif, dev->desc->fw_name);
}
}
diff --git a/drivers/soundwire/swr-wcd-ctrl.c b/drivers/soundwire/swr-wcd-ctrl.c
index e72663bd2138..14c13db991a1 100644
--- a/drivers/soundwire/swr-wcd-ctrl.c
+++ b/drivers/soundwire/swr-wcd-ctrl.c
@@ -540,7 +540,7 @@ static int swrm_read(struct swr_master *master, u8 dev_num, u16 reg_addr,
{
struct swr_mstr_ctrl *swrm = swr_get_ctrl_data(master);
int ret = 0;
- int val;
+ int val = 0;
u8 *reg_val = (u8 *)buf;
if (!swrm) {
diff --git a/drivers/staging/android/lowmemorykiller.c b/drivers/staging/android/lowmemorykiller.c
index 205af6627b80..1de3dddfd0f4 100644
--- a/drivers/staging/android/lowmemorykiller.c
+++ b/drivers/staging/android/lowmemorykiller.c
@@ -146,7 +146,7 @@ int adjust_minadj(short *min_score_adj)
static int lmk_vmpressure_notifier(struct notifier_block *nb,
unsigned long action, void *data)
{
- int other_free, other_file;
+ int other_free = 0, other_file = 0;
unsigned long pressure = action;
int array_size = ARRAY_SIZE(lowmem_adj);
diff --git a/drivers/thermal/msm-tsens.c b/drivers/thermal/msm-tsens.c
index d59b9736c570..5f955af4671a 100644
--- a/drivers/thermal/msm-tsens.c
+++ b/drivers/thermal/msm-tsens.c
@@ -2119,7 +2119,7 @@ static int get_device_tree_data(struct platform_device *pdev,
{
struct device_node *of_node = pdev->dev.of_node;
struct resource *res_mem = NULL;
- u32 *tsens_slope_data, *sensor_id, *client_id;
+ u32 *tsens_slope_data = NULL, *sensor_id, *client_id;
u32 *temp1_calib_offset_factor, *temp2_calib_offset_factor;
u32 rc = 0, i, tsens_num_sensors = 0;
u32 cycle_monitor = 0, wd_bark = 0;
diff --git a/drivers/usb/dwc3/dwc3-msm.c b/drivers/usb/dwc3/dwc3-msm.c
index 4ed46d9ca279..c2d788bc4bc5 100644
--- a/drivers/usb/dwc3/dwc3-msm.c
+++ b/drivers/usb/dwc3/dwc3-msm.c
@@ -2671,12 +2671,16 @@ static int dwc3_msm_extcon_register(struct dwc3_msm *mdwc)
{
struct device_node *node = mdwc->dev->of_node;
struct extcon_dev *edev;
+ struct dwc3 *dwc;
int ret = 0;
+ dwc = platform_get_drvdata(mdwc->dwc3);
if (!of_property_read_bool(node, "extcon")) {
- if (usb_get_dr_mode(&mdwc->dwc3->dev) == USB_DR_MODE_HOST)
+ dev_dbg(mdwc->dev, "extcon property doesn't exist\n");
+ if (usb_get_dr_mode(&mdwc->dwc3->dev) == USB_DR_MODE_HOST
+ || dwc->is_drd)
return 0;
- dev_err(mdwc->dev, "extcon property doesn't exist\n");
+ dev_err(mdwc->dev, "Neither host nor DRD, fail probe\n");
return -EINVAL;
}
@@ -3137,8 +3141,9 @@ static int dwc3_msm_probe(struct platform_device *pdev)
device_create_file(&pdev->dev, &dev_attr_speed);
host_mode = usb_get_dr_mode(&mdwc->dwc3->dev) == USB_DR_MODE_HOST;
- if (!dwc->is_drd && host_mode) {
- dev_dbg(&pdev->dev, "DWC3 in host only mode\n");
+ if (host_mode ||
+ (dwc->is_drd && !of_property_read_bool(node, "extcon"))) {
+ dev_dbg(&pdev->dev, "DWC3 in default host mode\n");
mdwc->id_state = DWC3_ID_GROUND;
dwc3_ext_event_notify(mdwc);
}
diff --git a/drivers/usb/gadget/function/f_audio_source.c b/drivers/usb/gadget/function/f_audio_source.c
index ab7441fcf66f..46be62b737f1 100644
--- a/drivers/usb/gadget/function/f_audio_source.c
+++ b/drivers/usb/gadget/function/f_audio_source.c
@@ -1050,8 +1050,14 @@ static struct usb_function_instance *audio_source_alloc_inst(void)
config_group_init_type_name(&fi_audio->func_inst.group, "",
&audio_source_func_type);
- snprintf(device_name, AUDIO_SOURCE_DEV_NAME_LENGTH,
+ if (!count) {
+ snprintf(device_name, AUDIO_SOURCE_DEV_NAME_LENGTH,
+ "f_audio_source");
+ count++;
+ } else {
+ snprintf(device_name, AUDIO_SOURCE_DEV_NAME_LENGTH,
"f_audio_source%d", count++);
+ }
dev = create_function_device(device_name);
diff --git a/drivers/usb/host/xhci-hub.c b/drivers/usb/host/xhci-hub.c
index d885033d3322..9dbd7595a7a3 100644
--- a/drivers/usb/host/xhci-hub.c
+++ b/drivers/usb/host/xhci-hub.c
@@ -376,10 +376,6 @@ static int xhci_stop_device(struct xhci_hcd *xhci, int slot_id, int suspend)
int i;
ret = 0;
- virt_dev = xhci->devs[slot_id];
- if (!virt_dev)
- return -ENODEV;
-
cmd = xhci_alloc_command(xhci, false, true, GFP_NOIO);
if (!cmd) {
xhci_dbg(xhci, "Couldn't allocate command structure.\n");
@@ -387,6 +383,13 @@ static int xhci_stop_device(struct xhci_hcd *xhci, int slot_id, int suspend)
}
spin_lock_irqsave(&xhci->lock, flags);
+ virt_dev = xhci->devs[slot_id];
+ if (!virt_dev) {
+ spin_unlock_irqrestore(&xhci->lock, flags);
+ xhci_free_command(xhci, cmd);
+ return -ENODEV;
+ }
+
for (i = LAST_EP_INDEX; i > 0; i--) {
if (virt_dev->eps[i].ring && virt_dev->eps[i].ring->dequeue) {
struct xhci_command *command;
@@ -403,6 +406,7 @@ static int xhci_stop_device(struct xhci_hcd *xhci, int slot_id, int suspend)
i, suspend);
if (ret) {
spin_unlock_irqrestore(&xhci->lock, flags);
+ xhci_free_command(xhci, command);
goto err_cmd_queue;
}
}
diff --git a/drivers/usb/pd/policy_engine.c b/drivers/usb/pd/policy_engine.c
index 7d893c5815e2..7a250c31f44d 100644
--- a/drivers/usb/pd/policy_engine.c
+++ b/drivers/usb/pd/policy_engine.c
@@ -29,6 +29,11 @@
#include <linux/usb/usbpd.h>
#include "usbpd.h"
+/* To start USB stack for USB3.1 complaince testing */
+static bool usb_compliance_mode;
+module_param(usb_compliance_mode, bool, S_IRUGO|S_IWUSR);
+MODULE_PARM_DESC(usb_compliance_mode, "Start USB stack for USB3.1 compliance testing");
+
enum usbpd_state {
PE_UNKNOWN,
PE_ERROR_RECOVERY,
@@ -187,6 +192,8 @@ static void *usbpd_ipc_log;
#define PD_MAX_MSG_ID 7
+#define PD_MAX_DATA_OBJ 7
+
#define PD_MSG_HDR(type, dr, pr, id, cnt, rev) \
(((type) & 0xF) | ((dr) << 5) | (rev << 6) | \
((pr) << 8) | ((id) << 9) | ((cnt) << 12))
@@ -308,7 +315,7 @@ struct usbpd {
struct list_head rx_q;
spinlock_t rx_lock;
- u32 received_pdos[7];
+ u32 received_pdos[PD_MAX_DATA_OBJ];
u16 src_cap_id;
u8 selected_pdo;
u8 requested_pdo;
@@ -481,13 +488,12 @@ static int pd_send_msg(struct usbpd *pd, u8 hdr_type, const u32 *data,
ret = pd_phy_write(hdr, (u8 *)data, num_data * sizeof(u32), type, 15);
/* TODO figure out timeout. based on tReceive=1.1ms x nRetryCount? */
- /* MessageID incremented regardless of Tx error */
- pd->tx_msgid = (pd->tx_msgid + 1) & PD_MAX_MSG_ID;
-
if (ret < 0)
return ret;
else if (ret != num_data * sizeof(u32))
return -EIO;
+
+ pd->tx_msgid = (pd->tx_msgid + 1) & PD_MAX_MSG_ID;
return 0;
}
@@ -547,6 +553,7 @@ static int pd_select_pdo(struct usbpd *pd, int pdo_pos, int uv, int ua)
static int pd_eval_src_caps(struct usbpd *pd)
{
+ int obj_cnt;
union power_supply_propval val;
u32 first_pdo = pd->received_pdos[0];
@@ -563,6 +570,13 @@ static int pd_eval_src_caps(struct usbpd *pd)
power_supply_set_property(pd->usb_psy,
POWER_SUPPLY_PROP_PD_USB_SUSPEND_SUPPORTED, &val);
+ for (obj_cnt = 1; obj_cnt < PD_MAX_DATA_OBJ; obj_cnt++) {
+ if ((PD_SRC_PDO_TYPE(pd->received_pdos[obj_cnt]) ==
+ PD_SRC_PDO_TYPE_AUGMENTED) &&
+ !PD_APDO_PPS(pd->received_pdos[obj_cnt]))
+ pd->spec_rev = USBPD_REV_30;
+ }
+
/* Select the first PDO (vSafe5V) immediately. */
pd_select_pdo(pd, 1, 0, 0);
@@ -571,6 +585,8 @@ static int pd_eval_src_caps(struct usbpd *pd)
static void pd_send_hard_reset(struct usbpd *pd)
{
+ union power_supply_propval val = {0};
+
usbpd_dbg(&pd->dev, "send hard reset");
/* Force CC logic to source/sink to keep Rp/Rd unchanged */
@@ -578,6 +594,7 @@ static void pd_send_hard_reset(struct usbpd *pd)
pd->hard_reset_count++;
pd_phy_signal(HARD_RESET_SIG, 5); /* tHardResetComplete */
pd->in_pr_swap = false;
+ power_supply_set_property(pd->usb_psy, POWER_SUPPLY_PROP_PR_SWAP, &val);
}
static void kick_sm(struct usbpd *pd, int ms)
@@ -593,6 +610,8 @@ static void kick_sm(struct usbpd *pd, int ms)
static void phy_sig_received(struct usbpd *pd, enum pd_sig_type type)
{
+ union power_supply_propval val = {1};
+
if (type != HARD_RESET_SIG) {
usbpd_err(&pd->dev, "invalid signal (%d) received\n", type);
return;
@@ -603,6 +622,9 @@ static void phy_sig_received(struct usbpd *pd, enum pd_sig_type type)
/* Force CC logic to source/sink to keep Rp/Rd unchanged */
set_power_role(pd, pd->current_pr);
pd->hard_reset_recvd = true;
+ power_supply_set_property(pd->usb_psy,
+ POWER_SUPPLY_PROP_PD_IN_HARD_RESET, &val);
+
kick_sm(pd, 0);
}
@@ -653,12 +675,6 @@ static void phy_msg_received(struct usbpd *pd, enum pd_msg_type type,
return;
}
- /* if spec rev differs (i.e. is older), update PHY */
- if (PD_MSG_HDR_REV(header) < pd->spec_rev) {
- pd->spec_rev = PD_MSG_HDR_REV(header);
- pd_phy_update_spec_rev(pd->spec_rev);
- }
-
rx_msg = kzalloc(sizeof(*rx_msg), GFP_KERNEL);
if (!rx_msg)
return;
@@ -701,7 +717,6 @@ static void usbpd_set_state(struct usbpd *pd, enum usbpd_state next_state)
.shutdown_cb = phy_shutdown,
.frame_filter_val = FRAME_FILTER_EN_SOP |
FRAME_FILTER_EN_HARD_RESET,
- .spec_rev = USBPD_REV_20,
};
union power_supply_propval val = {0};
unsigned long flags;
@@ -723,6 +738,15 @@ static void usbpd_set_state(struct usbpd *pd, enum usbpd_state next_state)
break;
/* Source states */
+ case PE_SRC_DISABLED:
+ /* are we still connected? */
+ if (pd->typec_mode == POWER_SUPPLY_TYPEC_NONE) {
+ pd->current_pr = PR_NONE;
+ kick_sm(pd, 0);
+ }
+
+ break;
+
case PE_SRC_STARTUP:
if (pd->current_dr == DR_NONE) {
pd->current_dr = DR_DFP;
@@ -739,8 +763,6 @@ static void usbpd_set_state(struct usbpd *pd, enum usbpd_state next_state)
power_supply_set_property(pd->usb_psy,
POWER_SUPPLY_PROP_TYPEC_POWER_ROLE, &val);
- /* support only PD 2.0 as a source */
- pd->spec_rev = USBPD_REV_20;
pd_reset_protocol(pd);
if (!pd->in_pr_swap) {
@@ -751,7 +773,6 @@ static void usbpd_set_state(struct usbpd *pd, enum usbpd_state next_state)
phy_params.data_role = pd->current_dr;
phy_params.power_role = pd->current_pr;
- phy_params.spec_rev = pd->spec_rev;
ret = pd_phy_open(&phy_params);
if (ret) {
@@ -763,14 +784,15 @@ static void usbpd_set_state(struct usbpd *pd, enum usbpd_state next_state)
}
pd->pd_phy_opened = true;
- } else {
- pd_phy_update_spec_rev(pd->spec_rev);
}
pd->current_state = PE_SRC_SEND_CAPABILITIES;
if (pd->in_pr_swap) {
kick_sm(pd, SWAP_SOURCE_START_TIME);
pd->in_pr_swap = false;
+ val.intval = 0;
+ power_supply_set_property(pd->usb_psy,
+ POWER_SUPPLY_PROP_PR_SWAP, &val);
break;
}
@@ -853,6 +875,10 @@ static void usbpd_set_state(struct usbpd *pd, enum usbpd_state next_state)
case PE_SRC_HARD_RESET:
case PE_SNK_HARD_RESET:
+ /* are we still connected? */
+ if (pd->typec_mode == POWER_SUPPLY_TYPEC_NONE)
+ pd->current_pr = PR_NONE;
+
/* hard reset may sleep; handle it in the workqueue */
kick_sm(pd, 0);
break;
@@ -879,7 +905,8 @@ static void usbpd_set_state(struct usbpd *pd, enum usbpd_state next_state)
pd->current_dr = DR_UFP;
if (pd->psy_type == POWER_SUPPLY_TYPE_USB ||
- pd->psy_type == POWER_SUPPLY_TYPE_USB_CDP)
+ pd->psy_type == POWER_SUPPLY_TYPE_USB_CDP ||
+ usb_compliance_mode)
start_usb_peripheral(pd);
}
@@ -896,11 +923,6 @@ static void usbpd_set_state(struct usbpd *pd, enum usbpd_state next_state)
if (!val.intval)
break;
- /*
- * support up to PD 3.0 as a sink; if source is 2.0,
- * phy_msg_received() will handle the downgrade.
- */
- pd->spec_rev = USBPD_REV_30;
pd_reset_protocol(pd);
if (!pd->in_pr_swap) {
@@ -911,7 +933,6 @@ static void usbpd_set_state(struct usbpd *pd, enum usbpd_state next_state)
phy_params.data_role = pd->current_dr;
phy_params.power_role = pd->current_pr;
- phy_params.spec_rev = pd->spec_rev;
ret = pd_phy_open(&phy_params);
if (ret) {
@@ -923,8 +944,6 @@ static void usbpd_set_state(struct usbpd *pd, enum usbpd_state next_state)
}
pd->pd_phy_opened = true;
- } else {
- pd_phy_update_spec_rev(pd->spec_rev);
}
pd->current_voltage = pd->requested_voltage = 5000000;
@@ -1563,7 +1582,6 @@ static void usbpd_sm(struct work_struct *w)
memset(&pd->received_pdos, 0, sizeof(pd->received_pdos));
rx_msg_cleanup(pd);
- val.intval = 0;
power_supply_set_property(pd->usb_psy,
POWER_SUPPLY_PROP_PD_IN_HARD_RESET, &val);
@@ -1594,6 +1612,10 @@ static void usbpd_sm(struct work_struct *w)
usleep_range(ERROR_RECOVERY_TIME * USEC_PER_MSEC,
(ERROR_RECOVERY_TIME + 5) * USEC_PER_MSEC);
+ val.intval = 0;
+ power_supply_set_property(pd->usb_psy,
+ POWER_SUPPLY_PROP_PR_SWAP, &val);
+
/* set due to dual_role class "mode" change */
if (pd->forced_pr != POWER_SUPPLY_TYPEC_PR_NONE)
val.intval = pd->forced_pr;
@@ -1617,11 +1639,22 @@ static void usbpd_sm(struct work_struct *w)
if (pd->hard_reset_recvd) {
pd->hard_reset_recvd = false;
- val.intval = 1;
+ if (pd->requested_current) {
+ val.intval = pd->requested_current = 0;
+ power_supply_set_property(pd->usb_psy,
+ POWER_SUPPLY_PROP_PD_CURRENT_MAX, &val);
+ }
+
+ pd->requested_voltage = 5000000;
+ val.intval = pd->requested_voltage;
power_supply_set_property(pd->usb_psy,
- POWER_SUPPLY_PROP_PD_IN_HARD_RESET, &val);
+ POWER_SUPPLY_PROP_VOLTAGE_MIN, &val);
pd->in_pr_swap = false;
+ val.intval = 0;
+ power_supply_set_property(pd->usb_psy,
+ POWER_SUPPLY_PROP_PR_SWAP, &val);
+
pd->in_explicit_contract = false;
pd->selected_pdo = pd->requested_pdo = 0;
pd->rdo = 0;
@@ -1725,14 +1758,8 @@ static void usbpd_sm(struct work_struct *w)
case PE_SRC_READY:
if (IS_CTRL(rx_msg, MSG_GET_SOURCE_CAP)) {
- ret = pd_send_msg(pd, MSG_SOURCE_CAPABILITIES,
- default_src_caps,
- ARRAY_SIZE(default_src_caps), SOP_MSG);
- if (ret) {
- usbpd_err(&pd->dev, "Error sending SRC CAPs\n");
- usbpd_set_state(pd, PE_SRC_SEND_SOFT_RESET);
- break;
- }
+ pd->current_state = PE_SRC_SEND_CAPABILITIES;
+ kick_sm(pd, 0);
} else if (IS_CTRL(rx_msg, MSG_GET_SINK_CAP)) {
ret = pd_send_msg(pd, MSG_SINK_CAPABILITIES,
pd->sink_caps, pd->num_sink_caps,
@@ -1888,6 +1915,9 @@ static void usbpd_sm(struct work_struct *w)
case PE_SNK_WAIT_FOR_CAPABILITIES:
pd->in_pr_swap = false;
+ val.intval = 0;
+ power_supply_set_property(pd->usb_psy,
+ POWER_SUPPLY_PROP_PR_SWAP, &val);
if (IS_DATA(rx_msg, MSG_SOURCE_CAPABILITIES)) {
val.intval = 0;
@@ -1907,15 +1937,6 @@ static void usbpd_sm(struct work_struct *w)
POWER_SUPPLY_PROP_PD_ACTIVE, &val);
} else if (pd->hard_reset_count < 3) {
usbpd_set_state(pd, PE_SNK_HARD_RESET);
- } else if (pd->pd_connected) {
- usbpd_info(&pd->dev, "Sink hard reset count exceeded, forcing reconnect\n");
-
- val.intval = 0;
- power_supply_set_property(pd->usb_psy,
- POWER_SUPPLY_PROP_PD_IN_HARD_RESET,
- &val);
-
- usbpd_set_state(pd, PE_ERROR_RECOVERY);
} else {
usbpd_dbg(&pd->dev, "Sink hard reset count exceeded, disabling PD\n");
@@ -2066,6 +2087,9 @@ static void usbpd_sm(struct work_struct *w)
}
pd->in_pr_swap = true;
+ val.intval = 1;
+ power_supply_set_property(pd->usb_psy,
+ POWER_SUPPLY_PROP_PR_SWAP, &val);
usbpd_set_state(pd, PE_PRS_SNK_SRC_TRANSITION_TO_OFF);
break;
} else if (IS_CTRL(rx_msg, MSG_VCONN_SWAP)) {
@@ -2209,6 +2233,9 @@ static void usbpd_sm(struct work_struct *w)
case PE_PRS_SRC_SNK_TRANSITION_TO_OFF:
pd->in_pr_swap = true;
+ val.intval = 1;
+ power_supply_set_property(pd->usb_psy,
+ POWER_SUPPLY_PROP_PR_SWAP, &val);
pd->in_explicit_contract = false;
if (pd->vbus_enabled) {
@@ -2249,6 +2276,9 @@ static void usbpd_sm(struct work_struct *w)
}
pd->in_pr_swap = true;
+ val.intval = 1;
+ power_supply_set_property(pd->usb_psy,
+ POWER_SUPPLY_PROP_PR_SWAP, &val);
usbpd_set_state(pd, PE_PRS_SNK_SRC_TRANSITION_TO_OFF);
break;
@@ -2308,6 +2338,14 @@ static void usbpd_sm(struct work_struct *w)
sm_done:
kfree(rx_msg);
+ spin_lock_irqsave(&pd->rx_lock, flags);
+ ret = list_empty(&pd->rx_q);
+ spin_unlock_irqrestore(&pd->rx_lock, flags);
+
+ /* requeue if there are any new/pending RX messages */
+ if (!ret)
+ kick_sm(pd, 0);
+
if (!pd->sm_queued)
pm_relax(&pd->dev);
}
@@ -3299,6 +3337,8 @@ struct usbpd *usbpd_create(struct device *parent)
pd->dual_role->drv_data = pd;
}
+ /* default support as PD 2.0 source or sink */
+ pd->spec_rev = USBPD_REV_20;
pd->current_pr = PR_NONE;
pd->current_dr = DR_NONE;
list_add_tail(&pd->instance, &_usbpd);
diff --git a/drivers/usb/pd/qpnp-pdphy.c b/drivers/usb/pd/qpnp-pdphy.c
index 588af94db6cd..e200c25bc23a 100644
--- a/drivers/usb/pd/qpnp-pdphy.c
+++ b/drivers/usb/pd/qpnp-pdphy.c
@@ -108,6 +108,7 @@ struct usb_pdphy {
int tx_status;
u8 frame_filter_val;
bool in_test_data_mode;
+ bool rx_busy;
enum data_role data_role;
enum power_role power_role;
@@ -334,15 +335,6 @@ int pd_phy_update_roles(enum data_role dr, enum power_role pr)
}
EXPORT_SYMBOL(pd_phy_update_roles);
-int pd_phy_update_spec_rev(enum pd_spec_rev rev)
-{
- struct usb_pdphy *pdphy = __pdphy;
-
- return pdphy_masked_write(pdphy, USB_PDPHY_MSG_CONFIG,
- MSG_CONFIG_SPEC_REV_MASK, rev);
-}
-EXPORT_SYMBOL(pd_phy_update_spec_rev);
-
int pd_phy_open(struct pd_phy_params *params)
{
int ret;
@@ -377,7 +369,9 @@ int pd_phy_open(struct pd_phy_params *params)
if (ret)
return ret;
- ret = pd_phy_update_spec_rev(params->spec_rev);
+ /* PD 2.0 phy */
+ ret = pdphy_masked_write(pdphy, USB_PDPHY_MSG_CONFIG,
+ MSG_CONFIG_SPEC_REV_MASK, USBPD_REV_20);
if (ret)
return ret;
@@ -492,6 +486,12 @@ int pd_phy_write(u16 hdr, const u8 *data, size_t data_len,
return -EINVAL;
}
+ ret = pdphy_reg_read(pdphy, &val, USB_PDPHY_RX_ACKNOWLEDGE, 1);
+ if (ret || val || pdphy->rx_busy) {
+ dev_err(pdphy->dev, "%s: RX message pending\n", __func__);
+ return -EBUSY;
+ }
+
pdphy->tx_status = -EINPROGRESS;
/* write 2 byte SOP message header */
@@ -664,6 +664,15 @@ static int pd_phy_bist_mode(u8 bist_mode)
BIST_MODE_MASK | BIST_ENABLE, bist_mode | BIST_ENABLE);
}
+static irqreturn_t pdphy_msg_rx_irq(int irq, void *data)
+{
+ struct usb_pdphy *pdphy = data;
+
+ pdphy->rx_busy = true;
+
+ return IRQ_WAKE_THREAD;
+}
+
static irqreturn_t pdphy_msg_rx_irq_thread(int irq, void *data)
{
u8 size, rx_status, frame_type;
@@ -720,6 +729,7 @@ static irqreturn_t pdphy_msg_rx_irq_thread(int irq, void *data)
false);
pdphy->rx_bytes += size + 1;
done:
+ pdphy->rx_busy = false;
return IRQ_HANDLED;
}
@@ -805,7 +815,7 @@ static int pdphy_probe(struct platform_device *pdev)
return ret;
ret = pdphy_request_irq(pdphy, pdev->dev.of_node,
- &pdphy->msg_rx_irq, "msg-rx", NULL,
+ &pdphy->msg_rx_irq, "msg-rx", pdphy_msg_rx_irq,
pdphy_msg_rx_irq_thread, (IRQF_TRIGGER_RISING | IRQF_ONESHOT));
if (ret < 0)
return ret;
diff --git a/drivers/usb/pd/usbpd.h b/drivers/usb/pd/usbpd.h
index b2663add7f3c..108701739f89 100644
--- a/drivers/usb/pd/usbpd.h
+++ b/drivers/usb/pd/usbpd.h
@@ -68,7 +68,6 @@ struct pd_phy_params {
enum data_role data_role;
enum power_role power_role;
u8 frame_filter_val;
- u8 spec_rev;
};
#if IS_ENABLED(CONFIG_QPNP_USB_PDPHY)
@@ -77,7 +76,6 @@ int pd_phy_signal(enum pd_sig_type type, unsigned int timeout_ms);
int pd_phy_write(u16 hdr, const u8 *data, size_t data_len,
enum pd_msg_type type, unsigned int timeout_ms);
int pd_phy_update_roles(enum data_role dr, enum power_role pr);
-int pd_phy_update_spec_rev(enum pd_spec_rev rev);
void pd_phy_close(void);
#else
static inline int pd_phy_open(struct pd_phy_params *params)
@@ -101,11 +99,6 @@ static inline int pd_phy_update_roles(enum data_role dr, enum power_role pr)
return -ENODEV;
}
-static inline int pd_phy_update_spec_rev(enum pd_spec_rev rev)
-{
- return -ENODEV;
-}
-
static inline void pd_phy_close(void)
{
}
diff --git a/drivers/video/fbdev/core/fbmem.c b/drivers/video/fbdev/core/fbmem.c
index c082ae8e50ce..2a708dd2ecee 100644
--- a/drivers/video/fbdev/core/fbmem.c
+++ b/drivers/video/fbdev/core/fbmem.c
@@ -1097,6 +1097,13 @@ static long do_fb_ioctl(struct fb_info *info, unsigned int cmd,
void __user *argp = (void __user *)arg;
long ret = 0;
+ memset(&var, 0, sizeof(var));
+ memset(&fix, 0, sizeof(fix));
+ memset(&con2fb, 0, sizeof(con2fb));
+ memset(&cmap_from, 0, sizeof(cmap_from));
+ memset(&cmap, 0, sizeof(cmap));
+ memset(&event, 0, sizeof(event));
+
switch (cmd) {
case FBIOGET_VSCREENINFO:
if (!lock_fb_info(info))
diff --git a/drivers/video/fbdev/msm/mdss_dba_utils.c b/drivers/video/fbdev/msm/mdss_dba_utils.c
index 3330f8f62b78..c6ff92ed1686 100644
--- a/drivers/video/fbdev/msm/mdss_dba_utils.c
+++ b/drivers/video/fbdev/msm/mdss_dba_utils.c
@@ -576,7 +576,6 @@ int mdss_dba_utils_video_on(void *data, struct mdss_panel_info *pinfo)
video_cfg.h_pulse_width = pinfo->lcdc.h_pulse_width;
video_cfg.v_pulse_width = pinfo->lcdc.v_pulse_width;
video_cfg.pclk_khz = (unsigned long)pinfo->clk_rate / 1000;
- video_cfg.hdmi_mode = !hdmi_edid_is_dvi_mode(ud->edid_data);
/* Calculate number of DSI lanes configured */
video_cfg.num_of_input_lanes = 0;
@@ -592,6 +591,8 @@ int mdss_dba_utils_video_on(void *data, struct mdss_panel_info *pinfo)
/* Get scan information from EDID */
video_cfg.vic = mdss_dba_get_vic_panel_info(ud, pinfo);
ud->current_vic = video_cfg.vic;
+ video_cfg.hdmi_mode = hdmi_edid_get_sink_mode(ud->edid_data,
+ video_cfg.vic);
video_cfg.scaninfo = hdmi_edid_get_sink_scaninfo(ud->edid_data,
video_cfg.vic);
if (ud->ops.video_on)
diff --git a/drivers/video/fbdev/msm/mdss_dp_util.c b/drivers/video/fbdev/msm/mdss_dp_util.c
index 0d9cf7b72b4d..e8c3fe9f4957 100644
--- a/drivers/video/fbdev/msm/mdss_dp_util.c
+++ b/drivers/video/fbdev/msm/mdss_dp_util.c
@@ -311,7 +311,7 @@ static void mdss_dp_calc_tu_parameters(u8 link_rate, u8 ln_cnt,
bool n_err_neg, nn_err_neg;
u8 hblank_margin = 16;
- u8 tu_size, tu_size_desired, tu_size_minus1;
+ u8 tu_size, tu_size_desired = 0, tu_size_minus1;
int valid_boundary_link;
u64 resulting_valid;
u64 total_valid;
diff --git a/drivers/video/fbdev/msm/mdss_dsi.c b/drivers/video/fbdev/msm/mdss_dsi.c
index 797c8b4a2eb1..4f1333426113 100644
--- a/drivers/video/fbdev/msm/mdss_dsi.c
+++ b/drivers/video/fbdev/msm/mdss_dsi.c
@@ -1815,7 +1815,7 @@ static int mdss_dsi_post_panel_on(struct mdss_panel_data *pdata)
return 0;
}
-irqreturn_t test_hw_vsync_handler(int irq, void *data)
+static irqreturn_t test_hw_vsync_handler(int irq, void *data)
{
struct mdss_panel_data *pdata = (struct mdss_panel_data *)data;
@@ -2091,7 +2091,7 @@ static int __mdss_dsi_dfps_update_clks(struct mdss_panel_data *pdata,
{
struct mdss_dsi_ctrl_pdata *ctrl_pdata = NULL;
struct mdss_dsi_ctrl_pdata *sctrl_pdata = NULL;
- struct mdss_panel_info *pinfo, *spinfo;
+ struct mdss_panel_info *pinfo, *spinfo = NULL;
int rc = 0;
if (pdata == NULL) {
@@ -4301,6 +4301,15 @@ static int mdss_dsi_parse_gpio_params(struct platform_device *ctrl_pdev,
of_property_read_bool(ctrl_pdev->dev.of_node,
"qcom,platform-bklight-en-gpio-invert");
+ ctrl_pdata->avdd_en_gpio = of_get_named_gpio(ctrl_pdev->dev.of_node,
+ "qcom,platform-avdd-en-gpio", 0);
+ if (!gpio_is_valid(ctrl_pdata->avdd_en_gpio))
+ pr_info("%s: avdd_en gpio not specified\n", __func__);
+
+ ctrl_pdata->avdd_en_gpio_invert =
+ of_property_read_bool(ctrl_pdev->dev.of_node,
+ "qcom,platform-avdd-en-gpio-invert");
+
ctrl_pdata->rst_gpio = of_get_named_gpio(ctrl_pdev->dev.of_node,
"qcom,platform-reset-gpio", 0);
if (!gpio_is_valid(ctrl_pdata->rst_gpio))
diff --git a/drivers/video/fbdev/msm/mdss_dsi.h b/drivers/video/fbdev/msm/mdss_dsi.h
index 62d88f0af652..7fabd4944cbd 100644
--- a/drivers/video/fbdev/msm/mdss_dsi.h
+++ b/drivers/video/fbdev/msm/mdss_dsi.h
@@ -455,6 +455,8 @@ struct mdss_dsi_ctrl_pdata {
int bklt_en_gpio;
bool bklt_en_gpio_invert;
bool bklt_en_gpio_state;
+ int avdd_en_gpio;
+ bool avdd_en_gpio_invert;
int lcd_mode_sel_gpio;
int bklt_ctrl; /* backlight ctrl */
bool pwm_pmi;
diff --git a/drivers/video/fbdev/msm/mdss_dsi_host.c b/drivers/video/fbdev/msm/mdss_dsi_host.c
index f0fb791a7b8d..b448153df1df 100644
--- a/drivers/video/fbdev/msm/mdss_dsi_host.c
+++ b/drivers/video/fbdev/msm/mdss_dsi_host.c
@@ -1161,6 +1161,8 @@ static int mdss_dsi_read_status(struct mdss_dsi_ctrl_pdata *ctrl)
rc = mdss_dsi_cmdlist_put(ctrl, &cmdreq);
if (rc <= 0) {
+ if (!mdss_dsi_sync_wait_enable(ctrl) ||
+ mdss_dsi_sync_wait_trigger(ctrl))
pr_err("%s: get status: fail\n", __func__);
return rc;
}
diff --git a/drivers/video/fbdev/msm/mdss_dsi_panel.c b/drivers/video/fbdev/msm/mdss_dsi_panel.c
index 60012c71449c..695dbfa95e29 100644
--- a/drivers/video/fbdev/msm/mdss_dsi_panel.c
+++ b/drivers/video/fbdev/msm/mdss_dsi_panel.c
@@ -260,6 +260,15 @@ static int mdss_dsi_request_gpios(struct mdss_dsi_ctrl_pdata *ctrl_pdata)
rc);
goto rst_gpio_err;
}
+ if (gpio_is_valid(ctrl_pdata->avdd_en_gpio)) {
+ rc = gpio_request(ctrl_pdata->avdd_en_gpio,
+ "avdd_enable");
+ if (rc) {
+ pr_err("request avdd_en gpio failed, rc=%d\n",
+ rc);
+ goto avdd_en_gpio_err;
+ }
+ }
if (gpio_is_valid(ctrl_pdata->lcd_mode_sel_gpio)) {
rc = gpio_request(ctrl_pdata->lcd_mode_sel_gpio, "mode_sel");
if (rc) {
@@ -272,6 +281,9 @@ static int mdss_dsi_request_gpios(struct mdss_dsi_ctrl_pdata *ctrl_pdata)
return rc;
lcd_mode_sel_gpio_err:
+ if (gpio_is_valid(ctrl_pdata->avdd_en_gpio))
+ gpio_free(ctrl_pdata->avdd_en_gpio);
+avdd_en_gpio_err:
gpio_free(ctrl_pdata->rst_gpio);
rst_gpio_err:
if (gpio_is_valid(ctrl_pdata->disp_en_gpio))
@@ -424,6 +436,21 @@ int mdss_dsi_panel_reset(struct mdss_panel_data *pdata, int enable)
if (pdata->panel_info.rst_seq[++i])
usleep_range(pinfo->rst_seq[i] * 1000, pinfo->rst_seq[i] * 1000);
}
+
+ if (gpio_is_valid(ctrl_pdata->avdd_en_gpio)) {
+ if (ctrl_pdata->avdd_en_gpio_invert) {
+ rc = gpio_direction_output(
+ ctrl_pdata->avdd_en_gpio, 0);
+ } else {
+ rc = gpio_direction_output(
+ ctrl_pdata->avdd_en_gpio, 1);
+ }
+ if (rc) {
+ pr_err("%s: unable to set dir for avdd_en gpio\n",
+ __func__);
+ goto exit;
+ }
+ }
}
if (gpio_is_valid(ctrl_pdata->lcd_mode_sel_gpio)) {
@@ -452,6 +479,14 @@ int mdss_dsi_panel_reset(struct mdss_panel_data *pdata, int enable)
pr_debug("%s: Reset panel done\n", __func__);
}
} else {
+ if (gpio_is_valid(ctrl_pdata->avdd_en_gpio)) {
+ if (ctrl_pdata->avdd_en_gpio_invert)
+ gpio_set_value((ctrl_pdata->avdd_en_gpio), 1);
+ else
+ gpio_set_value((ctrl_pdata->avdd_en_gpio), 0);
+
+ gpio_free(ctrl_pdata->avdd_en_gpio);
+ }
if (gpio_is_valid(ctrl_pdata->disp_en_gpio)) {
gpio_set_value((ctrl_pdata->disp_en_gpio), 0);
gpio_free(ctrl_pdata->disp_en_gpio);
diff --git a/drivers/video/fbdev/msm/mdss_fb.c b/drivers/video/fbdev/msm/mdss_fb.c
index 40a79c4af38e..31cba148ad28 100644
--- a/drivers/video/fbdev/msm/mdss_fb.c
+++ b/drivers/video/fbdev/msm/mdss_fb.c
@@ -3607,6 +3607,16 @@ static void mdss_fb_var_to_panelinfo(struct fb_var_screeninfo *var,
*/
if (pinfo->is_dba_panel)
pinfo->mipi.dsi_pclk_rate = pinfo->clk_rate;
+
+ if (var->sync & FB_SYNC_HOR_HIGH_ACT)
+ pinfo->lcdc.h_polarity = 0;
+ else
+ pinfo->lcdc.h_polarity = 1;
+
+ if (var->sync & FB_SYNC_VERT_HIGH_ACT)
+ pinfo->lcdc.v_polarity = 0;
+ else
+ pinfo->lcdc.v_polarity = 1;
}
void mdss_panelinfo_to_fb_var(struct mdss_panel_info *pinfo,
diff --git a/drivers/video/fbdev/msm/mdss_hdmi_edid.c b/drivers/video/fbdev/msm/mdss_hdmi_edid.c
index 102c22cba7dd..ddc5edbe010d 100644
--- a/drivers/video/fbdev/msm/mdss_hdmi_edid.c
+++ b/drivers/video/fbdev/msm/mdss_hdmi_edid.c
@@ -62,11 +62,6 @@
#define EDID_VENDOR_ID_SIZE 4
#define EDID_IEEE_REG_ID 0x0c03
-enum edid_sink_mode {
- SINK_MODE_DVI,
- SINK_MODE_HDMI
-};
-
enum luminance_value {
NO_LUMINANCE_DATA = 3,
MAXIMUM_LUMINANCE = 4,
@@ -2406,7 +2401,7 @@ end:
return scaninfo;
} /* hdmi_edid_get_sink_scaninfo */
-static u32 hdmi_edid_get_sink_mode(void *input)
+u32 hdmi_edid_get_sink_mode(void *input, u32 mode)
{
struct hdmi_edid_ctrl *edid_ctrl = (struct hdmi_edid_ctrl *)input;
bool sink_mode;
@@ -2419,8 +2414,13 @@ static u32 hdmi_edid_get_sink_mode(void *input)
if (edid_ctrl->edid_override &&
(edid_ctrl->override_data.sink_mode != -1))
sink_mode = edid_ctrl->override_data.sink_mode;
- else
- sink_mode = edid_ctrl->sink_mode;
+ else {
+ if (edid_ctrl->sink_mode &&
+ (mode > 0 && mode <= HDMI_EVFRMT_END))
+ sink_mode = SINK_MODE_HDMI;
+ else
+ sink_mode = SINK_MODE_DVI;
+ }
return sink_mode;
} /* hdmi_edid_get_sink_mode */
@@ -2435,10 +2435,21 @@ static u32 hdmi_edid_get_sink_mode(void *input)
*/
bool hdmi_edid_is_dvi_mode(void *input)
{
- if (hdmi_edid_get_sink_mode(input))
- return false;
- else
+ struct hdmi_edid_ctrl *edid_ctrl = (struct hdmi_edid_ctrl *)input;
+ int sink_mode;
+
+ if (!edid_ctrl) {
+ DEV_ERR("%s: invalid input\n", __func__);
return true;
+ }
+
+ if (edid_ctrl->edid_override &&
+ (edid_ctrl->override_data.sink_mode != -1))
+ sink_mode = edid_ctrl->override_data.sink_mode;
+ else
+ sink_mode = edid_ctrl->sink_mode;
+
+ return (sink_mode == SINK_MODE_DVI);
}
/**
diff --git a/drivers/video/fbdev/msm/mdss_hdmi_edid.h b/drivers/video/fbdev/msm/mdss_hdmi_edid.h
index af802bb45f89..c604d0fbf7b2 100644
--- a/drivers/video/fbdev/msm/mdss_hdmi_edid.h
+++ b/drivers/video/fbdev/msm/mdss_hdmi_edid.h
@@ -58,10 +58,16 @@ struct hdmi_edid_override_data {
int vic;
};
+enum edid_sink_mode {
+ SINK_MODE_DVI,
+ SINK_MODE_HDMI
+};
+
int hdmi_edid_parser(void *edid_ctrl);
u32 hdmi_edid_get_raw_data(void *edid_ctrl, u8 *buf, u32 size);
u8 hdmi_edid_get_sink_scaninfo(void *edid_ctrl, u32 resolution);
bool hdmi_edid_is_dvi_mode(void *input);
+u32 hdmi_edid_get_sink_mode(void *edid_ctrl, u32 mode);
bool hdmi_edid_sink_scramble_override(void *input);
bool hdmi_edid_get_sink_scrambler_support(void *input);
bool hdmi_edid_get_scdc_support(void *input);
diff --git a/drivers/video/fbdev/msm/mdss_hdmi_tx.c b/drivers/video/fbdev/msm/mdss_hdmi_tx.c
index 07592fa26a49..a9ab970fb4bc 100644
--- a/drivers/video/fbdev/msm/mdss_hdmi_tx.c
+++ b/drivers/video/fbdev/msm/mdss_hdmi_tx.c
@@ -66,7 +66,7 @@
#define HDMI_TX_4_MAX_PCLK_RATE 600000
#define hdmi_tx_get_fd(x) ((x && (ffs(x) > 0)) ? \
- hdmi_ctrl->feature_data[ffs(x) - 1] : 0)
+ hdmi_ctrl->feature_data[ffs(x) - 1] : NULL)
#define hdmi_tx_set_fd(x, y) {if (x && (ffs(x) > 0)) \
hdmi_ctrl->feature_data[ffs(x) - 1] = y; }
@@ -375,9 +375,12 @@ static void hdmi_tx_audio_setup(struct hdmi_tx_ctrl *hdmi_ctrl)
}
}
-static inline u32 hdmi_tx_is_dvi_mode(struct hdmi_tx_ctrl *hdmi_ctrl)
+static inline bool hdmi_tx_is_dvi_mode(struct hdmi_tx_ctrl *hdmi_ctrl)
{
- return hdmi_edid_is_dvi_mode(hdmi_tx_get_fd(HDMI_TX_FEAT_EDID));
+ void *data = hdmi_tx_get_fd(HDMI_TX_FEAT_EDID);
+
+ return (hdmi_edid_get_sink_mode(data,
+ hdmi_ctrl->vic) == SINK_MODE_DVI);
} /* hdmi_tx_is_dvi_mode */
static inline u32 hdmi_tx_is_in_splash(struct hdmi_tx_ctrl *hdmi_ctrl)
@@ -2156,6 +2159,8 @@ static int hdmi_tx_init_panel_info(struct hdmi_tx_ctrl *hdmi_ctrl)
pinfo->lcdc.v_front_porch = timing.front_porch_v;
pinfo->lcdc.v_pulse_width = timing.pulse_width_v;
pinfo->lcdc.frame_rate = timing.refresh_rate;
+ pinfo->lcdc.h_polarity = timing.active_low_h;
+ pinfo->lcdc.v_polarity = timing.active_low_v;
pinfo->type = DTV_PANEL;
pinfo->pdest = DISPLAY_3;
@@ -2442,6 +2447,7 @@ static void hdmi_tx_set_mode(struct hdmi_tx_ctrl *hdmi_ctrl, u32 power_on)
struct dss_io_data *io = NULL;
/* Defaults: Disable block, HDMI mode */
u32 hdmi_ctrl_reg = BIT(1);
+ void *data = hdmi_tx_get_fd(HDMI_TX_FEAT_EDID);
if (!hdmi_ctrl) {
DEV_ERR("%s: invalid input\n", __func__);
@@ -2470,7 +2476,8 @@ static void hdmi_tx_set_mode(struct hdmi_tx_ctrl *hdmi_ctrl, u32 power_on)
hdmi_ctrl_reg |= BIT(2);
/* Set transmission mode to DVI based in EDID info */
- if (hdmi_edid_is_dvi_mode(hdmi_tx_get_fd(HDMI_TX_FEAT_EDID)))
+ if (hdmi_edid_get_sink_mode(data,
+ hdmi_ctrl->vic) == SINK_MODE_DVI)
hdmi_ctrl_reg &= ~BIT(1); /* DVI mode */
/*
@@ -2929,7 +2936,6 @@ static int hdmi_tx_audio_info_setup(struct platform_device *pdev,
{
int rc = 0;
struct hdmi_tx_ctrl *hdmi_ctrl = platform_get_drvdata(pdev);
- u32 is_mode_dvi;
if (!hdmi_ctrl || !params) {
DEV_ERR("%s: invalid input\n", __func__);
@@ -2938,9 +2944,8 @@ static int hdmi_tx_audio_info_setup(struct platform_device *pdev,
mutex_lock(&hdmi_ctrl->tx_lock);
- is_mode_dvi = hdmi_tx_is_dvi_mode(hdmi_ctrl);
-
- if (!is_mode_dvi && hdmi_tx_is_panel_on(hdmi_ctrl)) {
+ if (!hdmi_tx_is_dvi_mode(hdmi_ctrl) &&
+ hdmi_tx_is_panel_on(hdmi_ctrl)) {
memcpy(&hdmi_ctrl->audio_params, params,
sizeof(struct msm_ext_disp_audio_setup_params));
diff --git a/drivers/video/fbdev/msm/mdss_hdmi_util.c b/drivers/video/fbdev/msm/mdss_hdmi_util.c
index 102c2f994646..827013d06412 100644
--- a/drivers/video/fbdev/msm/mdss_hdmi_util.c
+++ b/drivers/video/fbdev/msm/mdss_hdmi_util.c
@@ -857,7 +857,7 @@ static int hdmi_ddc_read_retry(struct hdmi_tx_ddc_ctrl *ddc_ctrl)
u32 reg_val, ndx, time_out_count, wait_time;
struct hdmi_tx_ddc_data *ddc_data;
int status;
- int busy_wait_us;
+ int busy_wait_us = 0;
if (!ddc_ctrl || !ddc_ctrl->io) {
pr_err("invalid input\n");
@@ -1335,7 +1335,7 @@ int hdmi_ddc_write(struct hdmi_tx_ddc_ctrl *ddc_ctrl)
u32 time_out_count;
struct hdmi_tx_ddc_data *ddc_data;
u32 wait_time;
- int busy_wait_us;
+ int busy_wait_us = 0;
if (!ddc_ctrl || !ddc_ctrl->io) {
pr_err("invalid input\n");
diff --git a/drivers/video/fbdev/msm/mdss_mdp.c b/drivers/video/fbdev/msm/mdss_mdp.c
index d88d87bd2092..6936c4c1f3cc 100644
--- a/drivers/video/fbdev/msm/mdss_mdp.c
+++ b/drivers/video/fbdev/msm/mdss_mdp.c
@@ -2180,7 +2180,6 @@ static void mdss_mdp_hw_rev_caps_init(struct mdss_data_type *mdata)
mdss_set_quirk(mdata, MDSS_QUIRK_MDP_CLK_SET_RATE);
mdata->has_wb_ubwc = true;
set_bit(MDSS_CAPS_10_BIT_SUPPORTED, mdata->mdss_caps_map);
- set_bit(MDSS_CAPS_AVR_SUPPORTED, mdata->mdss_caps_map);
set_bit(MDSS_CAPS_SEC_DETACH_SMMU, mdata->mdss_caps_map);
mdss_set_quirk(mdata, MDSS_QUIRK_HDR_SUPPORT_ENABLED);
break;
diff --git a/drivers/video/fbdev/msm/mdss_mdp.h b/drivers/video/fbdev/msm/mdss_mdp.h
index cd403f19c088..5a15b557e5c7 100644
--- a/drivers/video/fbdev/msm/mdss_mdp.h
+++ b/drivers/video/fbdev/msm/mdss_mdp.h
@@ -1107,9 +1107,9 @@ static inline enum mdss_mdp_pu_type mdss_mdp_get_pu_type(
if (!is_split_lm(mctl->mfd) || mdss_mdp_is_both_lm_valid(mctl))
pu_type = MDSS_MDP_DEFAULT_UPDATE;
- else if (mctl->mixer_left->valid_roi)
+ else if (mctl->mixer_left && mctl->mixer_left->valid_roi)
pu_type = MDSS_MDP_LEFT_ONLY_UPDATE;
- else if (mctl->mixer_right->valid_roi)
+ else if (mctl->mixer_right && mctl->mixer_right->valid_roi)
pu_type = MDSS_MDP_RIGHT_ONLY_UPDATE;
else
pr_err("%s: invalid pu_type\n", __func__);
diff --git a/drivers/video/fbdev/msm/mdss_mdp_ctl.c b/drivers/video/fbdev/msm/mdss_mdp_ctl.c
index 929eeb270f32..0da462394ab8 100644
--- a/drivers/video/fbdev/msm/mdss_mdp_ctl.c
+++ b/drivers/video/fbdev/msm/mdss_mdp_ctl.c
@@ -571,6 +571,9 @@ static u32 __calc_qseed3_mdp_clk_rate(struct mdss_mdp_pipe *pipe,
u64 ver_dwnscale;
u64 active_line;
u64 backfill_line;
+ struct mdss_mdp_ctl *ctl = pipe->mixer_left->ctl;
+ u64 pclk_rate;
+ struct mdss_panel_info *pinfo = &ctl->panel_data->panel_info;
ver_dwnscale = (u64)src_h << PHASE_STEP_SHIFT;
do_div(ver_dwnscale, dst.h);
@@ -596,12 +599,26 @@ static u32 __calc_qseed3_mdp_clk_rate(struct mdss_mdp_pipe *pipe,
total_cycle = active_line_cycle + backfill_cycle;
+ /*
+ * MDP clkrate = total_cycle * PixelClock / Dest-width
+ * if pixelClock not available:
+ * = total_cycle * fps * v_total
+ */
+ if ((pinfo->type == MIPI_CMD_PANEL) && dst.w) {
+ pclk_rate = (u64)mdss_panel_get_htotal(pinfo, false) *
+ v_total * fps;
+ do_div(pclk_rate, pinfo->xres);
+ total_cycle *= pclk_rate;
+ } else {
+ total_cycle *= (fps * v_total);
+ }
+
pr_debug("line: active=%lld backfill=%lld vds=%lld\n",
active_line, backfill_line, ver_dwnscale);
pr_debug("cycle: total=%lld active=%lld backfill=%lld\n",
total_cycle, active_line_cycle, backfill_cycle);
- return (u32)total_cycle * (fps * v_total);
+ return (u32)total_cycle;
}
static inline bool __is_vert_downscaling(u32 src_h,
@@ -659,6 +676,7 @@ static u32 get_pipe_mdp_clk_rate(struct mdss_mdp_pipe *pipe,
if (flags & PERF_CALC_PIPE_APPLY_CLK_FUDGE)
rate = mdss_mdp_clk_fudge_factor(mixer, rate);
+ rate = min(mdata->max_mdp_clk_rate, rate);
return rate;
}
diff --git a/drivers/video/fbdev/msm/mdss_mdp_intf_video.c b/drivers/video/fbdev/msm/mdss_mdp_intf_video.c
index 587150bbc9fa..d9aaac4526ea 100644
--- a/drivers/video/fbdev/msm/mdss_mdp_intf_video.c
+++ b/drivers/video/fbdev/msm/mdss_mdp_intf_video.c
@@ -58,6 +58,8 @@ struct intf_timing_params {
u32 v_front_porch;
u32 hsync_pulse_width;
u32 vsync_pulse_width;
+ u32 h_polarity;
+ u32 v_polarity;
u32 border_clr;
u32 underflow_clr;
@@ -641,13 +643,8 @@ static int mdss_mdp_video_timegen_setup(struct mdss_mdp_ctl *ctl,
display_hctl = (hsync_end_x << 16) | hsync_start_x;
den_polarity = 0;
- if (MDSS_INTF_HDMI == ctx->intf_type) {
- hsync_polarity = p->yres >= 720 ? 0 : 1;
- vsync_polarity = p->yres >= 720 ? 0 : 1;
- } else {
- hsync_polarity = 0;
- vsync_polarity = 0;
- }
+ hsync_polarity = p->h_polarity;
+ vsync_polarity = p->v_polarity;
polarity_ctl = (den_polarity << 2) | /* DEN Polarity */
(vsync_polarity << 1) | /* VSYNC Polarity */
(hsync_polarity << 0); /* HSYNC Polarity */
@@ -2178,7 +2175,8 @@ static int mdss_mdp_video_ctx_setup(struct mdss_mdp_ctl *ctl,
itp->width = dsc->pclk_per_line;
itp->xres = dsc->pclk_per_line;
}
-
+ itp->h_polarity = pinfo->lcdc.h_polarity;
+ itp->v_polarity = pinfo->lcdc.v_polarity;
itp->h_back_porch = pinfo->lcdc.h_back_porch;
itp->h_front_porch = pinfo->lcdc.h_front_porch;
itp->v_back_porch = pinfo->lcdc.v_back_porch;
diff --git a/drivers/video/fbdev/msm/mdss_mdp_layer.c b/drivers/video/fbdev/msm/mdss_mdp_layer.c
index 472f1e8e8e3b..a1d79a89b463 100644
--- a/drivers/video/fbdev/msm/mdss_mdp_layer.c
+++ b/drivers/video/fbdev/msm/mdss_mdp_layer.c
@@ -1812,13 +1812,16 @@ static int __validate_secure_session(struct mdss_overlay_private *mdp5_data)
pr_debug("pipe count:: secure display:%d non-secure:%d secure-vid:%d,secure-cam:%d\n",
sd_pipes, nonsd_pipes, secure_vid_pipes, secure_cam_pipes);
+ MDSS_XLOG(mdss_get_sd_client_cnt(), sd_pipes, nonsd_pipes,
+ secure_vid_pipes, secure_cam_pipes);
if (mdss_get_sd_client_cnt() && !mdp5_data->sd_enabled) {
pr_err("Secure session already enabled for other client\n");
return -EINVAL;
}
- if ((sd_pipes) &&
+ if (((sd_pipes) || (mdp5_data->ctl->is_video_mode &&
+ mdss_get_sd_client_cnt())) &&
(nonsd_pipes || secure_vid_pipes ||
secure_cam_pipes)) {
pr_err("non-secure layer validation request during secure display session\n");
@@ -2410,14 +2413,14 @@ static int __validate_layers(struct msm_fb_data_type *mfd,
int layer_count = commit->input_layer_cnt;
u32 ds_mode = 0;
- struct mdss_mdp_pipe *pipe, *tmp, *left_blend_pipe;
+ struct mdss_mdp_pipe *pipe = NULL, *tmp, *left_blend_pipe;
struct mdss_mdp_pipe *right_plist[MAX_PIPES_PER_LM] = {0};
struct mdss_mdp_pipe *left_plist[MAX_PIPES_PER_LM] = {0};
struct mdss_overlay_private *mdp5_data = mfd_to_mdp5_data(mfd);
struct mdss_data_type *mdata = mfd_to_mdata(mfd);
struct mdss_mdp_mixer *mixer = NULL;
- struct mdp_input_layer *layer, *layer_list;
+ struct mdp_input_layer *layer = NULL, *layer_list;
struct mdss_mdp_validate_info_t *validate_info_list = NULL;
bool is_single_layer = false, force_validate;
enum layer_pipe_q pipe_q_type;
diff --git a/drivers/video/fbdev/msm/mdss_mdp_util.c b/drivers/video/fbdev/msm/mdss_mdp_util.c
index 22656175edf8..1ae3d0ba4ec6 100644
--- a/drivers/video/fbdev/msm/mdss_mdp_util.c
+++ b/drivers/video/fbdev/msm/mdss_mdp_util.c
@@ -428,8 +428,8 @@ static int mdss_mdp_get_ubwc_plane_size(struct mdss_mdp_format_params *fmt,
if (fmt->format == MDP_Y_CBCR_H2V2_UBWC ||
fmt->format == MDP_Y_CBCR_H2V2_TP10_UBWC) {
- uint32_t y_stride_alignment, uv_stride_alignment;
- uint32_t y_height_alignment, uv_height_alignment;
+ uint32_t y_stride_alignment = 0, uv_stride_alignment = 0;
+ uint32_t y_height_alignment = 0, uv_height_alignment = 0;
uint32_t y_tile_width = fmt_ubwc->micro.tile_width;
uint32_t y_tile_height = fmt_ubwc->micro.tile_height;
uint32_t uv_tile_width = y_tile_width / 2;
diff --git a/drivers/video/fbdev/msm/mdss_panel.h b/drivers/video/fbdev/msm/mdss_panel.h
index 37b0ca7aa44b..e8255ff45726 100644
--- a/drivers/video/fbdev/msm/mdss_panel.h
+++ b/drivers/video/fbdev/msm/mdss_panel.h
@@ -406,9 +406,10 @@ struct lcd_panel_info {
/* Pad height */
u32 yres_pad;
u32 frame_rate;
+ u32 h_polarity;
+ u32 v_polarity;
};
-
/* DSI PHY configuration */
struct mdss_dsi_phy_ctrl {
char regulator[7]; /* 8996, 1 * 5 */
diff --git a/drivers/video/fbdev/msm/mdss_rotator.c b/drivers/video/fbdev/msm/mdss_rotator.c
index 399a12e3dcc8..61b0518d3ee6 100644
--- a/drivers/video/fbdev/msm/mdss_rotator.c
+++ b/drivers/video/fbdev/msm/mdss_rotator.c
@@ -687,7 +687,7 @@ static struct mdss_rot_hw_resource *mdss_rotator_hw_alloc(
struct mdss_rot_hw_resource *hw;
struct mdss_data_type *mdata = mdss_mdp_get_mdata();
u32 pipe_ndx, offset = mdss_mdp_get_wb_ctl_support(mdata, true);
- int ret;
+ int ret = 0;
hw = devm_kzalloc(&mgr->pdev->dev, sizeof(struct mdss_rot_hw_resource),
GFP_KERNEL);
diff --git a/fs/proc/task_mmu.c b/fs/proc/task_mmu.c
index fc5243c331c4..420f623e3441 100644
--- a/fs/proc/task_mmu.c
+++ b/fs/proc/task_mmu.c
@@ -1518,6 +1518,9 @@ struct reclaim_param reclaim_task_anon(struct task_struct *task,
if (vma->vm_file)
continue;
+ if (vma->vm_flags & VM_LOCKED)
+ continue;
+
if (!rp.nr_to_reclaim)
break;
diff --git a/include/drm/drm_mm.h b/include/drm/drm_mm.h
index 0de6290df4da..6649b6d8c437 100644
--- a/include/drm/drm_mm.h
+++ b/include/drm/drm_mm.h
@@ -37,6 +37,7 @@
* Generic range manager structs
*/
#include <linux/bug.h>
+#include <linux/rbtree.h>
#include <linux/kernel.h>
#include <linux/list.h>
#include <linux/spinlock.h>
@@ -48,6 +49,7 @@ enum drm_mm_search_flags {
DRM_MM_SEARCH_DEFAULT = 0,
DRM_MM_SEARCH_BEST = 1 << 0,
DRM_MM_SEARCH_BELOW = 1 << 1,
+ DRM_MM_SEARCH_BOTTOM_UP = 1 << 2,
};
enum drm_mm_allocator_flags {
@@ -61,6 +63,8 @@ enum drm_mm_allocator_flags {
struct drm_mm_node {
struct list_head node_list;
struct list_head hole_stack;
+ struct rb_node rb;
+ struct rb_node hole_node;
unsigned hole_follows : 1;
unsigned scanned_block : 1;
unsigned scanned_prev_free : 1;
@@ -70,6 +74,7 @@ struct drm_mm_node {
unsigned long color;
u64 start;
u64 size;
+ u64 __subtree_last;
struct drm_mm *mm;
};
@@ -79,6 +84,10 @@ struct drm_mm {
/* head_node.node_list is the list of all memory nodes, ordered
* according to the (increasing) start address of the memory node. */
struct drm_mm_node head_node;
+ /* Keep an interval_tree for fast lookup of drm_mm_nodes by address. */
+ struct rb_root interval_tree;
+ struct rb_root holes_tree;
+
unsigned int scan_check_range : 1;
unsigned scan_alignment;
unsigned long scan_color;
@@ -301,6 +310,12 @@ void drm_mm_init(struct drm_mm *mm,
void drm_mm_takedown(struct drm_mm *mm);
bool drm_mm_clean(struct drm_mm *mm);
+struct drm_mm_node *
+drm_mm_interval_first(struct drm_mm *mm, u64 start, u64 last);
+
+struct drm_mm_node *
+drm_mm_interval_next(struct drm_mm_node *node, u64 start, u64 last);
+
void drm_mm_init_scan(struct drm_mm *mm,
u64 size,
unsigned alignment,
diff --git a/include/linux/ipc_router.h b/include/linux/ipc_router.h
index b17f684a9895..04a06df66d4b 100644
--- a/include/linux/ipc_router.h
+++ b/include/linux/ipc_router.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012-2015, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-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
@@ -269,6 +269,14 @@ int register_ipcrtr_af_init_notifier(struct notifier_block *nb);
*/
int unregister_ipcrtr_af_init_notifier(struct notifier_block *nb);
+/**
+ * msm_ipc_router_set_ws_allowed() - To Enable/disable the wakeup source allowed
+ * flag
+ * @flag: Flag to set/clear the wakeup soruce allowed
+ *
+ */
+void msm_ipc_router_set_ws_allowed(bool flag);
+
#else
struct msm_ipc_port *msm_ipc_router_create_port(
@@ -341,6 +349,8 @@ int unregister_ipcrtr_af_init_notifier(struct notifier_block *nb)
return -ENODEV;
}
+void msm_ipc_router_set_ws_allowed(bool flag) { }
+
#endif
#endif
diff --git a/include/linux/ipc_router_xprt.h b/include/linux/ipc_router_xprt.h
index 276c79ff1591..ac6c1e4db8a4 100644
--- a/include/linux/ipc_router_xprt.h
+++ b/include/linux/ipc_router_xprt.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011-2015, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2011-2015,2017 The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -100,6 +100,7 @@ struct rr_opt_hdr {
* @pkt_fragment_q: Queue of SKBs containing payload.
* @length: Length of data in the chain of SKBs
* @ref: Reference count for the packet.
+ * @ws_need: Flag to check wakeup soruce need
*/
struct rr_packet {
struct list_head list;
@@ -108,6 +109,7 @@ struct rr_packet {
struct sk_buff_head *pkt_fragment_q;
uint32_t length;
struct kref ref;
+ bool ws_need;
};
/**
@@ -125,6 +127,7 @@ struct rr_packet {
* @close: Method to close the XPRT.
* @sft_close_done: Method to indicate to the XPRT that handling of reset
* event is complete.
+ * @get_ws_info: Method to get the wakeup soruce inforamtion of the XPRT
*/
struct msm_ipc_router_xprt {
char *name;
@@ -143,6 +146,7 @@ struct msm_ipc_router_xprt {
struct msm_ipc_router_xprt *xprt);
int (*close)(struct msm_ipc_router_xprt *xprt);
void (*sft_close_done)(struct msm_ipc_router_xprt *xprt);
+ bool (*get_ws_info)(struct msm_ipc_router_xprt *xprt);
};
void msm_ipc_router_xprt_notify(struct msm_ipc_router_xprt *xprt,
diff --git a/include/linux/mmc/host.h b/include/linux/mmc/host.h
index d9e12c1b1748..279411c42ded 100644
--- a/include/linux/mmc/host.h
+++ b/include/linux/mmc/host.h
@@ -330,7 +330,9 @@ struct mmc_devfeq_clk_scaling {
atomic_t devfreq_abort;
bool skip_clk_scale_freq_update;
int freq_table_sz;
+ int pltfm_freq_table_sz;
u32 *freq_table;
+ u32 *pltfm_freq_table;
unsigned long total_busy_time_us;
unsigned long target_freq;
unsigned long curr_freq;
diff --git a/include/linux/msm_mhi.h b/include/linux/msm_mhi.h
index c01cb1af4231..1704cb93e6a3 100644
--- a/include/linux/msm_mhi.h
+++ b/include/linux/msm_mhi.h
@@ -81,6 +81,7 @@ enum MHI_CB_REASON {
MHI_CB_MHI_SHUTDOWN,
MHI_CB_SYS_ERROR,
MHI_CB_RDDM,
+ MHI_CB_MHI_PROBED,
};
enum MHI_FLAGS {
@@ -119,6 +120,7 @@ struct mhi_client_handle {
u32 domain;
u32 bus;
u32 slot;
+ bool enabled;
struct mhi_client_config *client_config;
};
@@ -158,9 +160,11 @@ enum mhi_dev_ctrl {
MHI_DEV_CTRL_RESUME,
MHI_DEV_CTRL_POWER_OFF,
MHI_DEV_CTRL_POWER_ON,
+ MHI_DEV_CTRL_TRIGGER_RDDM,
MHI_DEV_CTRL_RDDM,
MHI_DEV_CTRL_RDDM_KERNEL_PANIC,
MHI_DEV_CTRL_NOTIFY_LINK_ERROR,
+ MHI_DEV_CTRL_MAXCMD,
};
enum mhi_rddm_segment {
@@ -168,6 +172,7 @@ enum mhi_rddm_segment {
MHI_RDDM_RD_SEGMENT,
};
+#if defined(CONFIG_MSM_MHI)
/**
* mhi_is_device_ready - Check if MHI is ready to register clients
*
@@ -187,11 +192,23 @@ bool mhi_is_device_ready(const struct device * const dev,
* @userdata: cb data for client
* @Return 0 on success
*/
-int mhi_register_device(struct mhi_device *mhi_device,
- const char *node_name,
+int mhi_register_device(struct mhi_device *mhi_device, const char *node_name,
void *user_data);
/**
+ * mhi_register_channel - Client must call this function to obtain a handle for
+ * any MHI operations
+ *
+ * @client_handle: Handle populated by MHI, opaque to client
+ * @client_info: Channel\device information provided by client to
+ * which the handle maps to.
+ *
+ * @Return errno
+ */
+int mhi_register_channel(struct mhi_client_handle **client_handle,
+ struct mhi_client_info_t *client_info);
+
+/**
* mhi_pm_control_device - power management control api
* @mhi_device: registered device structure
* @ctrl: specific command
@@ -219,19 +236,6 @@ int mhi_xfer_rddm(struct mhi_device *mhi_device, enum mhi_rddm_segment seg,
int mhi_deregister_channel(struct mhi_client_handle *client_handle);
/**
- * mhi_register_channel - Client must call this function to obtain a handle for
- * any MHI operations
- *
- * @client_handle: Handle populated by MHI, opaque to client
- * @client_info: Channel\device information provided by client to
- * which the handle maps to.
- *
- * @Return errno
- */
-int mhi_register_channel(struct mhi_client_handle **client_handle,
- struct mhi_client_info_t *client_info);
-
-/**
* mhi_open_channel - Client must call this function to open a channel
*
* @client_handle: Handle populated by MHI, opaque to client
@@ -258,8 +262,8 @@ int mhi_open_channel(struct mhi_client_handle *client_handle);
*
* @Return errno
*/
-int mhi_queue_xfer(struct mhi_client_handle *client_handle,
- void *buf, size_t buf_len, enum MHI_FLAGS mhi_flags);
+int mhi_queue_xfer(struct mhi_client_handle *client_handle, void *buf,
+ size_t buf_len, enum MHI_FLAGS mhi_flags);
/**
* mhi_close_channel - Client can request channel to be closed and handle freed
@@ -300,7 +304,7 @@ int mhi_get_free_desc(struct mhi_client_handle *client_handle);
* @Return non negative on success
*/
int mhi_poll_inbound(struct mhi_client_handle *client_handle,
- struct mhi_result *result);
+ struct mhi_result *result);
/**
* mhi_get_max_desc - Get the maximum number of descriptors
@@ -311,12 +315,107 @@ int mhi_poll_inbound(struct mhi_client_handle *client_handle,
*/
int mhi_get_max_desc(struct mhi_client_handle *client_handle);
-/* RmNET Reserved APIs, This APIs are reserved for use by the linux network
-* stack only. Use by other clients will introduce system wide issues
-*/
+/* following APIs meant to be used by rmnet interface only */
int mhi_set_lpm(struct mhi_client_handle *client_handle, bool enable_lpm);
int mhi_get_epid(struct mhi_client_handle *mhi_handle);
struct mhi_result *mhi_poll(struct mhi_client_handle *client_handle);
void mhi_mask_irq(struct mhi_client_handle *client_handle);
void mhi_unmask_irq(struct mhi_client_handle *client_handle);
+
+#else
+static inline bool mhi_is_device_ready(const struct device * const dev,
+ const char *node_name)
+{
+ return false;
+};
+
+static inline int mhi_register_device(struct mhi_device *mhi_device,
+ const char *node_name, void *user_data)
+{
+ return -EINVAL;
+};
+
+static inline int mhi_register_channel(struct mhi_client_handle **client_handle,
+ struct mhi_client_info_t *client_info)
+{
+ return -EINVAL;
+};
+
+static inline int mhi_pm_control_device(struct mhi_device *mhi_device,
+ enum mhi_dev_ctrl ctrl)
+{
+ return -EINVAL;
+};
+
+static inline int mhi_xfer_rddm(struct mhi_device *mhi_device,
+ enum mhi_rddm_segment seg,
+ struct scatterlist **sg_list)
+{
+ return -EINVAL;
+};
+
+static inline int mhi_deregister_channel(struct mhi_client_handle
+ *client_handle)
+{
+ return -EINVAL;
+};
+
+static inline int mhi_open_channel(struct mhi_client_handle *client_handle)
+{
+ return -EINVAL;
+};
+
+static inline int mhi_queue_xfer(struct mhi_client_handle *client_handle,
+ void *buf, size_t buf_len,
+ enum MHI_FLAGS mhi_flags)
+{
+ return -EINVAL;
+};
+
+static inline void mhi_close_channel(struct mhi_client_handle *client_handle)
+{
+};
+
+static inline int mhi_get_free_desc(struct mhi_client_handle *client_handle)
+{
+ return -EINVAL;
+};
+
+static inline int mhi_poll_inbound(struct mhi_client_handle *client_handle,
+ struct mhi_result *result)
+{
+ return -EINVAL;
+};
+
+static inline int mhi_get_max_desc(struct mhi_client_handle *client_handle)
+{
+ return -EINVAL;
+};
+
+static inline int mhi_set_lpm(struct mhi_client_handle *client_handle,
+ bool enable_lpm)
+{
+ return -EINVAL;
+};
+
+static inline int mhi_get_epid(struct mhi_client_handle *mhi_handle)
+{
+ return -EINVAL;
+};
+
+static inline struct mhi_result *mhi_poll(struct mhi_client_handle
+ *client_handle)
+{
+ return NULL;
+};
+
+static inline void mhi_mask_irq(struct mhi_client_handle *client_handle)
+{
+};
+
+static inline void mhi_unmask_irq(struct mhi_client_handle *client_handle)
+{
+};
+
+#endif
#endif
diff --git a/include/linux/sched.h b/include/linux/sched.h
index c71978453864..138fcf72508a 100644
--- a/include/linux/sched.h
+++ b/include/linux/sched.h
@@ -178,7 +178,9 @@ extern u64 nr_running_integral(unsigned int cpu);
#endif
extern void sched_update_nr_prod(int cpu, long delta, bool inc);
-extern void sched_get_nr_running_avg(int *avg, int *iowait_avg, int *big_avg);
+extern void sched_get_nr_running_avg(int *avg, int *iowait_avg, int *big_avg,
+ unsigned int *max_nr,
+ unsigned int *big_max_nr);
extern void calc_global_load(unsigned long ticks);
diff --git a/include/linux/sde_io_util.h b/include/linux/sde_io_util.h
index 6bd5c168ecd8..da4a50722984 100644
--- a/include/linux/sde_io_util.h
+++ b/include/linux/sde_io_util.h
@@ -58,6 +58,8 @@ struct dss_vreg {
int post_on_sleep;
int pre_off_sleep;
int post_off_sleep;
+ bool lp_disable_allowed;
+ bool disabled;
};
struct dss_gpio {
diff --git a/include/media/cec-notifier.h b/include/media/cec-notifier.h
new file mode 100644
index 000000000000..035712e0993d
--- /dev/null
+++ b/include/media/cec-notifier.h
@@ -0,0 +1,111 @@
+/*
+ * cec-notifier.h - notify CEC drivers of physical address changes
+ *
+ * Copyright 2016 Russell King <rmk+kernel@arm.linux.org.uk>
+ * Copyright 2016-2017 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
+ *
+ * This program is free software; you may redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#ifndef LINUX_CEC_NOTIFIER_H
+#define LINUX_CEC_NOTIFIER_H
+
+#include <linux/types.h>
+#include <media/cec-edid.h>
+
+struct device;
+struct edid;
+struct cec_adapter;
+struct cec_notifier;
+
+#ifdef CONFIG_MEDIA_CEC_NOTIFIER
+
+/**
+ * cec_notifier_get - find or create a new cec_notifier for the given device.
+ * @dev: device that sends the events.
+ *
+ * If a notifier for device @dev already exists, then increase the refcount
+ * and return that notifier.
+ *
+ * If it doesn't exist, then allocate a new notifier struct and return a
+ * pointer to that new struct.
+ *
+ * Return NULL if the memory could not be allocated.
+ */
+struct cec_notifier *cec_notifier_get(struct device *dev);
+
+/**
+ * cec_notifier_put - decrease refcount and delete when the refcount reaches 0.
+ * @n: notifier
+ */
+void cec_notifier_put(struct cec_notifier *n);
+
+/**
+ * cec_notifier_set_phys_addr - set a new physical address.
+ * @n: the CEC notifier
+ * @pa: the CEC physical address
+ *
+ * Set a new CEC physical address.
+ */
+void cec_notifier_set_phys_addr(struct cec_notifier *n, u16 pa);
+
+/**
+ * cec_notifier_set_phys_addr_from_edid - set parse the PA from the EDID.
+ * @n: the CEC notifier
+ * @edid: the struct edid pointer
+ *
+ * Parses the EDID to obtain the new CEC physical address and set it.
+ */
+void cec_notifier_set_phys_addr_from_edid(struct cec_notifier *n,
+ const struct edid *edid);
+
+/**
+ * cec_notifier_register - register a callback with the notifier
+ * @n: the CEC notifier
+ * @adap: the CEC adapter, passed as argument to the callback function
+ * @callback: the callback function
+ */
+void cec_notifier_register(struct cec_notifier *n,
+ struct cec_adapter *adap,
+ void (*callback)(struct cec_adapter *adap, u16 pa));
+
+/**
+ * cec_notifier_unregister - unregister the callback from the notifier.
+ * @n: the CEC notifier
+ */
+void cec_notifier_unregister(struct cec_notifier *n);
+
+#else
+static inline struct cec_notifier *cec_notifier_get(struct device *dev)
+{
+ /* A non-NULL pointer is expected on success */
+ return (struct cec_notifier *)0xdeadfeed;
+}
+
+static inline void cec_notifier_put(struct cec_notifier *n)
+{
+}
+
+static inline void cec_notifier_set_phys_addr(struct cec_notifier *n, u16 pa)
+{
+}
+
+static inline void cec_notifier_set_phys_addr_from_edid(struct cec_notifier *n,
+ const struct edid *edid)
+{
+}
+
+#endif
+
+#endif
diff --git a/include/media/cec.h b/include/media/cec.h
index 96a0aa770d61..307f5dcaf034 100644
--- a/include/media/cec.h
+++ b/include/media/cec.h
@@ -30,6 +30,7 @@
#include <linux/cec-funcs.h>
#include <media/rc-core.h>
#include <media/cec-edid.h>
+#include <media/cec-notifier.h>
/**
* struct cec_devnode - cec device node
@@ -173,6 +174,10 @@ struct cec_adapter {
bool passthrough;
struct cec_log_addrs log_addrs;
+#ifdef CONFIG_MEDIA_CEC_NOTIFIER
+ struct cec_notifier *notifier;
+#endif
+
struct dentry *cec_dir;
struct dentry *status_file;
@@ -213,6 +218,11 @@ void cec_transmit_done(struct cec_adapter *adap, u8 status, u8 arb_lost_cnt,
u8 nack_cnt, u8 low_drive_cnt, u8 error_cnt);
void cec_received_msg(struct cec_adapter *adap, struct cec_msg *msg);
+#ifdef CONFIG_MEDIA_CEC_NOTIFIER
+void cec_register_cec_notifier(struct cec_adapter *adap,
+ struct cec_notifier *notifier);
+#endif
+
#else
static inline int cec_register_adapter(struct cec_adapter *adap,
diff --git a/include/sound/apr_audio-v2.h b/include/sound/apr_audio-v2.h
index 1f19ff2210f8..74995a0cdbad 100644
--- a/include/sound/apr_audio-v2.h
+++ b/include/sound/apr_audio-v2.h
@@ -44,6 +44,8 @@ struct param_outband {
#define ADM_MATRIX_ID_COMPRESSED_AUDIO_RX 2
+#define ADM_MATRIX_ID_COMPRESSED_AUDIO_TX 3
+
#define ADM_MATRIX_ID_LISTEN_TX 4
/* Enumeration for an audio Tx matrix ID.*/
#define ADM_MATRIX_ID_AUDIOX 1
@@ -446,6 +448,9 @@ struct adm_param_data_v5 {
#define ASM_STREAM_CMD_REGISTER_PP_EVENTS 0x00013213
#define ASM_STREAM_PP_EVENT 0x00013214
+#define ASM_STREAM_CMD_REGISTER_IEC_61937_FMT_UPDATE 0x13333
+#define ASM_IEC_61937_MEDIA_FMT_EVENT 0x13334
+
#define DSP_STREAM_CMD "ADSP Stream Cmd"
#define DSP_STREAM_CALLBACK "ADSP Stream Callback Event"
#define DSP_STREAM_CALLBACK_QUEUE_SIZE 1024
diff --git a/include/sound/q6adm-v2.h b/include/sound/q6adm-v2.h
index caabb66bd0b4..900d2455993a 100644
--- a/include/sound/q6adm-v2.h
+++ b/include/sound/q6adm-v2.h
@@ -17,6 +17,7 @@
#define ADM_PATH_LIVE_REC 0x2
#define ADM_PATH_NONLIVE_REC 0x3
#define ADM_PATH_COMPRESSED_RX 0x5
+#define ADM_PATH_COMPRESSED_TX 0x6
#include <linux/qdsp6v2/rtac.h>
#include <sound/q6afe-v2.h>
#include <sound/q6audio-v2.h>
diff --git a/include/trace/events/sched.h b/include/trace/events/sched.h
index 0b92317f6263..9a1ff42a377e 100644
--- a/include/trace/events/sched.h
+++ b/include/trace/events/sched.h
@@ -1312,24 +1312,30 @@ TRACE_EVENT(sched_wake_idle_without_ipi,
TRACE_EVENT(sched_get_nr_running_avg,
- TP_PROTO(int avg, int big_avg, int iowait_avg),
+ TP_PROTO(int avg, int big_avg, int iowait_avg,
+ unsigned int max_nr, unsigned int big_max_nr),
- TP_ARGS(avg, big_avg, iowait_avg),
+ TP_ARGS(avg, big_avg, iowait_avg, max_nr, big_max_nr),
TP_STRUCT__entry(
__field( int, avg )
__field( int, big_avg )
__field( int, iowait_avg )
+ __field( unsigned int, max_nr )
+ __field( unsigned int, big_max_nr )
),
TP_fast_assign(
__entry->avg = avg;
__entry->big_avg = big_avg;
__entry->iowait_avg = iowait_avg;
+ __entry->max_nr = max_nr;
+ __entry->big_max_nr = big_max_nr;
),
- TP_printk("avg=%d big_avg=%d iowait_avg=%d",
- __entry->avg, __entry->big_avg, __entry->iowait_avg)
+ TP_printk("avg=%d big_avg=%d iowait_avg=%d max_nr=%u big_max_nr=%u",
+ __entry->avg, __entry->big_avg, __entry->iowait_avg,
+ __entry->max_nr, __entry->big_max_nr)
);
TRACE_EVENT(core_ctl_eval_need,
diff --git a/include/trace/events/trace_msm_pil_event.h b/include/trace/events/trace_msm_pil_event.h
new file mode 100644
index 000000000000..4795dc5e0b2e
--- /dev/null
+++ b/include/trace/events/trace_msm_pil_event.h
@@ -0,0 +1,88 @@
+/* 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.
+ */
+
+#undef TRACE_SYSTEM
+#define TRACE_SYSTEM msm_pil_event
+
+#if !defined(_TRACE_MSM_PIL_EVENT_H_) || defined(TRACE_HEADER_MULTI_READ)
+#define _TRACE_MSM_PIL_EVENT_H_
+
+#include <linux/tracepoint.h>
+#include <../drivers/soc/qcom/peripheral-loader.h>
+
+TRACE_EVENT(pil_event,
+
+ TP_PROTO(const char *event_name, struct pil_desc *desc),
+
+ TP_ARGS(event_name, desc),
+
+ TP_STRUCT__entry(
+ __string(event_name, event_name)
+ __string(fw_name, desc->fw_name)
+ ),
+
+ TP_fast_assign(
+ __assign_str(event_name, event_name);
+ __assign_str(fw_name, desc->fw_name);
+ ),
+
+ TP_printk("event_name=%s fw_name=%s",
+ __get_str(event_name),
+ __get_str(fw_name))
+);
+
+TRACE_EVENT(pil_notif,
+
+ TP_PROTO(const char *event_name, unsigned long code,
+ const char *fw_name),
+
+ TP_ARGS(event_name, code, fw_name),
+
+ TP_STRUCT__entry(
+ __string(event_name, event_name)
+ __field(unsigned long, code)
+ __string(fw_name, fw_name)
+ ),
+
+ TP_fast_assign(
+ __assign_str(event_name, event_name);
+ __entry->code = code;
+ __assign_str(fw_name, fw_name);
+ ),
+
+ TP_printk("event_name=%s code=%lu fw=%s",
+ __get_str(event_name),
+ __entry->code,
+ __get_str(fw_name))
+);
+
+TRACE_EVENT(pil_func,
+
+ TP_PROTO(const char *func_name),
+
+ TP_ARGS(func_name),
+
+ TP_STRUCT__entry(
+ __string(func_name, func_name)
+ ),
+
+ TP_fast_assign(
+ __assign_str(func_name, func_name);
+ ),
+
+ TP_printk("func_name=%s",
+ __get_str(func_name))
+);
+
+#endif
+#define TRACE_INCLUDE_FILE trace_msm_pil_event
+#include <trace/define_trace.h>
diff --git a/include/uapi/drm/msm_drm.h b/include/uapi/drm/msm_drm.h
index 7aa6496c7608..cc6d4fb42d9f 100644
--- a/include/uapi/drm/msm_drm.h
+++ b/include/uapi/drm/msm_drm.h
@@ -102,6 +102,13 @@ struct drm_msm_gem_new {
__u32 handle; /* out */
};
+struct drm_msm_gem_svm_new {
+ __u64 hostptr; /* in, must be page-aligned */
+ __u64 size; /* in, must be page-aligned */
+ __u32 flags; /* in, mask of MSM_BO_x */
+ __u32 handle; /* out */
+};
+
#define MSM_INFO_IOVA 0x01
#define MSM_INFO_FLAGS (MSM_INFO_IOVA)
@@ -356,6 +363,8 @@ struct drm_msm_gem_sync {
#define DRM_MSM_GEM_CPU_FINI 0x05
#define DRM_MSM_GEM_SUBMIT 0x06
#define DRM_MSM_WAIT_FENCE 0x07
+/* Gap for upstream DRM_MSM_GEM_MADVISE */
+#define DRM_MSM_GEM_SVM_NEW 0x09
#define DRM_SDE_WB_CONFIG 0x40
#define DRM_MSM_REGISTER_EVENT 0x41
@@ -395,6 +404,9 @@ struct drm_msm_gem_sync {
struct drm_msm_counter_read)
#define DRM_IOCTL_MSM_GEM_SYNC DRM_IOW(DRM_COMMAND_BASE + DRM_MSM_GEM_SYNC,\
struct drm_msm_gem_sync)
+#define DRM_IOCTL_MSM_GEM_SVM_NEW \
+ DRM_IOWR(DRM_COMMAND_BASE + DRM_MSM_GEM_SVM_NEW, \
+ struct drm_msm_gem_svm_new)
#if defined(__cplusplus)
}
diff --git a/include/uapi/linux/spcom.h b/include/uapi/linux/spcom.h
index 038a49d5ee57..39b1be03bde0 100644
--- a/include/uapi/linux/spcom.h
+++ b/include/uapi/linux/spcom.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
@@ -30,6 +30,12 @@
* with special size SPCOM_GET_NEXT_REQUEST_SIZE.
*/
+/*
+ * Maximum number of channel between Secure Processor and HLOS.
+ * including predefined channels, like "sp_kernel".
+ */
+#define SPCOM_MAX_CHANNELS 0x20
+
/* Maximum size (including null) for channel names */
#define SPCOM_CHANNEL_NAME_SIZE 32
diff --git a/kernel/irq/msi.c b/kernel/irq/msi.c
index cd6009006510..41b40f310c28 100644
--- a/kernel/irq/msi.c
+++ b/kernel/irq/msi.c
@@ -268,7 +268,7 @@ int msi_domain_alloc_irqs(struct irq_domain *domain, struct device *dev,
struct msi_domain_ops *ops = info->ops;
msi_alloc_info_t arg;
struct msi_desc *desc;
- int i, ret, virq;
+ int i, ret, virq = 0;
ret = ops->msi_check(domain, info, dev);
if (ret == 0)
diff --git a/kernel/sched/core_ctl.c b/kernel/sched/core_ctl.c
index 0b5f2dea18a1..ce15ae7fe76b 100644
--- a/kernel/sched/core_ctl.c
+++ b/kernel/sched/core_ctl.c
@@ -39,11 +39,13 @@ struct cluster_data {
cpumask_t cpu_mask;
unsigned int need_cpus;
unsigned int task_thres;
+ unsigned int max_nr;
s64 need_ts;
struct list_head lru;
bool pending;
spinlock_t pending_lock;
bool is_big_cluster;
+ bool enable;
int nrrun;
bool nrrun_changed;
struct task_struct *core_ctl_thread;
@@ -60,6 +62,7 @@ struct cpu_data {
struct cluster_data *cluster;
struct list_head sib;
bool isolated_by_us;
+ unsigned int max_nr;
};
static DEFINE_PER_CPU(struct cpu_data, cpu_state);
@@ -244,6 +247,29 @@ static ssize_t show_is_big_cluster(const struct cluster_data *state, char *buf)
return snprintf(buf, PAGE_SIZE, "%u\n", state->is_big_cluster);
}
+static ssize_t store_enable(struct cluster_data *state,
+ const char *buf, size_t count)
+{
+ unsigned int val;
+ bool bval;
+
+ if (sscanf(buf, "%u\n", &val) != 1)
+ return -EINVAL;
+
+ bval = !!val;
+ if (bval != state->enable) {
+ state->enable = bval;
+ apply_need(state);
+ }
+
+ return count;
+}
+
+static ssize_t show_enable(const struct cluster_data *state, char *buf)
+{
+ return scnprintf(buf, PAGE_SIZE, "%u\n", state->enable);
+}
+
static ssize_t show_need_cpus(const struct cluster_data *state, char *buf)
{
return snprintf(buf, PAGE_SIZE, "%u\n", state->need_cpus);
@@ -372,6 +398,7 @@ core_ctl_attr_ro(need_cpus);
core_ctl_attr_ro(active_cpus);
core_ctl_attr_ro(global_state);
core_ctl_attr_rw(not_preferred);
+core_ctl_attr_rw(enable);
static struct attribute *default_attrs[] = {
&min_cpus.attr,
@@ -381,6 +408,7 @@ static struct attribute *default_attrs[] = {
&busy_down_thres.attr,
&task_thres.attr,
&is_big_cluster.attr,
+ &enable.attr,
&need_cpus.attr,
&active_cpus.attr,
&global_state.attr,
@@ -429,7 +457,6 @@ static struct kobj_type ktype_core_ctl = {
#define RQ_AVG_TOLERANCE 2
#define RQ_AVG_DEFAULT_MS 20
-#define NR_RUNNING_TOLERANCE 5
static unsigned int rq_avg_period_ms = RQ_AVG_DEFAULT_MS;
static s64 rq_avg_timestamp_ms;
@@ -437,6 +464,7 @@ static s64 rq_avg_timestamp_ms;
static void update_running_avg(bool trigger_update)
{
int avg, iowait_avg, big_avg, old_nrrun;
+ int old_max_nr, max_nr, big_max_nr;
s64 now;
unsigned long flags;
struct cluster_data *cluster;
@@ -450,40 +478,23 @@ static void update_running_avg(bool trigger_update)
return;
}
rq_avg_timestamp_ms = now;
- sched_get_nr_running_avg(&avg, &iowait_avg, &big_avg);
+ sched_get_nr_running_avg(&avg, &iowait_avg, &big_avg,
+ &max_nr, &big_max_nr);
spin_unlock_irqrestore(&state_lock, flags);
- /*
- * Round up to the next integer if the average nr running tasks
- * is within NR_RUNNING_TOLERANCE/100 of the next integer.
- * If normal rounding up is used, it will allow a transient task
- * to trigger online event. By the time core is onlined, the task
- * has finished.
- * Rounding to closest suffers same problem because scheduler
- * might only provide running stats per jiffy, and a transient
- * task could skew the number for one jiffy. If core control
- * samples every 2 jiffies, it will observe 0.5 additional running
- * average which rounds up to 1 task.
- */
- avg = (avg + NR_RUNNING_TOLERANCE) / 100;
- big_avg = (big_avg + NR_RUNNING_TOLERANCE) / 100;
-
for_each_cluster(cluster, index) {
if (!cluster->inited)
continue;
+
old_nrrun = cluster->nrrun;
- /*
- * Big cluster only need to take care of big tasks, but if
- * there are not enough big cores, big tasks need to be run
- * on little as well. Thus for little's runqueue stat, it
- * has to use overall runqueue average, or derive what big
- * tasks would have to be run on little. The latter approach
- * is not easy to get given core control reacts much slower
- * than scheduler, and can't predict scheduler's behavior.
- */
+ old_max_nr = cluster->max_nr;
cluster->nrrun = cluster->is_big_cluster ? big_avg : avg;
- if (cluster->nrrun != old_nrrun) {
+ cluster->max_nr = cluster->is_big_cluster ? big_max_nr : max_nr;
+
+ if (cluster->nrrun != old_nrrun ||
+ cluster->max_nr != old_max_nr) {
+
if (trigger_update)
apply_need(cluster);
else
@@ -493,6 +504,7 @@ static void update_running_avg(bool trigger_update)
return;
}
+#define MAX_NR_THRESHOLD 4
/* adjust needed CPUs based on current runqueue information */
static unsigned int apply_task_need(const struct cluster_data *cluster,
unsigned int new_need)
@@ -503,7 +515,15 @@ static unsigned int apply_task_need(const struct cluster_data *cluster,
/* only unisolate more cores if there are tasks to run */
if (cluster->nrrun > new_need)
- return new_need + 1;
+ new_need = new_need + 1;
+
+ /*
+ * We don't want tasks to be overcrowded in a cluster.
+ * If any CPU has more than MAX_NR_THRESHOLD in the last
+ * window, bring another CPU to help out.
+ */
+ if (cluster->max_nr > MAX_NR_THRESHOLD)
+ new_need = new_need + 1;
return new_need;
}
@@ -549,7 +569,7 @@ static bool eval_need(struct cluster_data *cluster)
spin_lock_irqsave(&state_lock, flags);
- if (cluster->boost) {
+ if (cluster->boost || !cluster->enable) {
need_cpus = cluster->max_cpus;
} else {
cluster->active_cpus = get_active_cpu_count(cluster);
@@ -1046,6 +1066,7 @@ static int cluster_init(const struct cpumask *mask)
cluster->offline_delay_ms = 100;
cluster->task_thres = UINT_MAX;
cluster->nrrun = cluster->num_cpus;
+ cluster->enable = true;
INIT_LIST_HEAD(&cluster->lru);
spin_lock_init(&cluster->pending_lock);
diff --git a/kernel/sched/fair.c b/kernel/sched/fair.c
index 4d96380b35e8..9abc3e65dbd9 100644
--- a/kernel/sched/fair.c
+++ b/kernel/sched/fair.c
@@ -3536,6 +3536,16 @@ kick_active_balance(struct rq *rq, struct task_struct *p, int new_cpu)
static DEFINE_RAW_SPINLOCK(migration_lock);
+static bool do_migration(int reason, int new_cpu, int cpu)
+{
+ if ((reason == UP_MIGRATION || reason == DOWN_MIGRATION)
+ && same_cluster(new_cpu, cpu))
+ return false;
+
+ /* Inter cluster high irqload migrations are OK */
+ return new_cpu != cpu;
+}
+
/*
* Check if currently running task should be migrated to a better cpu.
*
@@ -3553,7 +3563,7 @@ void check_for_migration(struct rq *rq, struct task_struct *p)
raw_spin_lock(&migration_lock);
new_cpu = select_best_cpu(p, cpu, reason, 0);
- if (new_cpu != cpu) {
+ if (do_migration(reason, new_cpu, cpu)) {
active_balance = kick_active_balance(rq, p, new_cpu);
if (active_balance)
mark_reserved(new_cpu);
diff --git a/kernel/sched/hmp.c b/kernel/sched/hmp.c
index df47c26ab6d2..ae6876e62c0f 100644
--- a/kernel/sched/hmp.c
+++ b/kernel/sched/hmp.c
@@ -1602,7 +1602,7 @@ unsigned int nr_eligible_big_tasks(int cpu)
int nr_big = rq->hmp_stats.nr_big_tasks;
int nr = rq->nr_running;
- if (cpu_max_possible_capacity(cpu) != max_possible_capacity)
+ if (!is_max_capacity_cpu(cpu))
return nr_big;
return nr;
@@ -2521,10 +2521,42 @@ static inline u32 predict_and_update_buckets(struct rq *rq,
return pred_demand;
}
-static void update_task_cpu_cycles(struct task_struct *p, int cpu)
+#define THRESH_CC_UPDATE (2 * NSEC_PER_USEC)
+
+/*
+ * Assumes rq_lock is held and wallclock was recorded in the same critical
+ * section as this function's invocation.
+ */
+static inline u64 read_cycle_counter(int cpu, u64 wallclock)
+{
+ struct sched_cluster *cluster = cpu_rq(cpu)->cluster;
+ u64 delta;
+
+ if (unlikely(!cluster))
+ return cpu_cycle_counter_cb.get_cpu_cycle_counter(cpu);
+
+ /*
+ * Why don't we need locking here? Let's say that delta is negative
+ * because some other CPU happened to update last_cc_update with a
+ * more recent timestamp. We simply read the conter again in that case
+ * with no harmful side effects. This can happen if there is an FIQ
+ * between when we read the wallclock and when we use it here.
+ */
+ delta = wallclock - atomic64_read(&cluster->last_cc_update);
+ if (delta > THRESH_CC_UPDATE) {
+ atomic64_set(&cluster->cycles,
+ cpu_cycle_counter_cb.get_cpu_cycle_counter(cpu));
+ atomic64_set(&cluster->last_cc_update, wallclock);
+ }
+
+ return atomic64_read(&cluster->cycles);
+}
+
+static void update_task_cpu_cycles(struct task_struct *p, int cpu,
+ u64 wallclock)
{
if (use_cycle_counter)
- p->cpu_cycles = cpu_cycle_counter_cb.get_cpu_cycle_counter(cpu);
+ p->cpu_cycles = read_cycle_counter(cpu, wallclock);
}
static void
@@ -2542,7 +2574,7 @@ update_task_rq_cpu_cycles(struct task_struct *p, struct rq *rq, int event,
return;
}
- cur_cycles = cpu_cycle_counter_cb.get_cpu_cycle_counter(cpu);
+ cur_cycles = read_cycle_counter(cpu, wallclock);
/*
* If current task is idle task and irqtime == 0 CPU was
@@ -2579,7 +2611,8 @@ update_task_rq_cpu_cycles(struct task_struct *p, struct rq *rq, int event,
trace_sched_get_task_cpu_cycles(cpu, event, rq->cc.cycles, rq->cc.time);
}
-static int account_busy_for_task_demand(struct task_struct *p, int event)
+static int
+account_busy_for_task_demand(struct rq *rq, struct task_struct *p, int event)
{
/*
* No need to bother updating task demand for exiting tasks
@@ -2598,6 +2631,17 @@ static int account_busy_for_task_demand(struct task_struct *p, int event)
(event == PICK_NEXT_TASK || event == TASK_MIGRATE)))
return 0;
+ /*
+ * TASK_UPDATE can be called on sleeping task, when its moved between
+ * related groups
+ */
+ if (event == TASK_UPDATE) {
+ if (rq->curr == p)
+ return 1;
+
+ return p->on_rq ? SCHED_ACCOUNT_WAIT_TIME : 0;
+ }
+
return 1;
}
@@ -2738,7 +2782,7 @@ static u64 update_task_demand(struct task_struct *p, struct rq *rq,
u64 runtime;
new_window = mark_start < window_start;
- if (!account_busy_for_task_demand(p, event)) {
+ if (!account_busy_for_task_demand(rq, p, event)) {
if (new_window)
/*
* If the time accounted isn't being accounted as
@@ -2822,7 +2866,7 @@ void update_task_ravg(struct task_struct *p, struct rq *rq, int event,
update_window_start(rq, wallclock);
if (!p->ravg.mark_start) {
- update_task_cpu_cycles(p, cpu_of(rq));
+ update_task_cpu_cycles(p, cpu_of(rq), wallclock);
goto done;
}
@@ -2890,7 +2934,7 @@ void sched_account_irqstart(int cpu, struct task_struct *curr, u64 wallclock)
if (is_idle_task(curr)) {
/* We're here without rq->lock held, IRQ disabled */
raw_spin_lock(&rq->lock);
- update_task_cpu_cycles(curr, cpu);
+ update_task_cpu_cycles(curr, cpu, sched_ktime_clock());
raw_spin_unlock(&rq->lock);
}
}
@@ -2935,7 +2979,7 @@ void mark_task_starting(struct task_struct *p)
p->ravg.mark_start = p->last_wake_ts = wallclock;
p->last_cpu_selected_ts = wallclock;
p->last_switch_out_ts = 0;
- update_task_cpu_cycles(p, cpu_of(rq));
+ update_task_cpu_cycles(p, cpu_of(rq), wallclock);
}
void set_window_start(struct rq *rq)
@@ -3548,7 +3592,7 @@ void fixup_busy_time(struct task_struct *p, int new_cpu)
update_task_ravg(p, task_rq(p), TASK_MIGRATE,
wallclock, 0);
- update_task_cpu_cycles(p, new_cpu);
+ update_task_cpu_cycles(p, new_cpu, wallclock);
new_task = is_new_task(p);
/* Protected by rq_lock */
@@ -4303,8 +4347,20 @@ void note_task_waking(struct task_struct *p, u64 wallclock)
{
u64 sleep_time = wallclock - p->last_switch_out_ts;
- p->last_wake_ts = wallclock;
+ /*
+ * When a short burst and short sleeping task goes for a long
+ * sleep, the task's avg_sleep_time gets boosted. It will not
+ * come below short_sleep threshold for a lot of time and it
+ * results in incorrect packing. The idead behind tracking
+ * avg_sleep_time is to detect if a task is short sleeping
+ * or not. So limit the sleep time to twice the short sleep
+ * threshold. For regular long sleeping tasks, the avg_sleep_time
+ * would be higher than threshold, and packing happens correctly.
+ */
+ sleep_time = min_t(u64, sleep_time, 2 * sysctl_sched_short_sleep);
update_avg(&p->ravg.avg_sleep_time, sleep_time);
+
+ p->last_wake_ts = wallclock;
}
#ifdef CONFIG_CGROUP_SCHED
diff --git a/kernel/sched/sched.h b/kernel/sched/sched.h
index 276a2387f06f..a6733b57bcbc 100644
--- a/kernel/sched/sched.h
+++ b/kernel/sched/sched.h
@@ -397,6 +397,8 @@ struct sched_cluster {
unsigned int static_cluster_pwr_cost;
int notifier_sent;
bool wake_up_idle;
+ atomic64_t last_cc_update;
+ atomic64_t cycles;
};
extern unsigned long all_cluster_ids[];
@@ -1225,6 +1227,11 @@ static inline bool hmp_capable(void)
return max_possible_capacity != min_max_possible_capacity;
}
+static inline bool is_max_capacity_cpu(int cpu)
+{
+ return cpu_max_possible_capacity(cpu) == max_possible_capacity;
+}
+
/*
* 'load' is in reference to "best cpu" at its best frequency.
* Scale that in reference to a given cpu, accounting for how bad it is
@@ -1601,6 +1608,8 @@ static inline unsigned int nr_eligible_big_tasks(int cpu)
return 0;
}
+static inline bool is_max_capacity_cpu(int cpu) { return true; }
+
static inline int pct_task_load(struct task_struct *p) { return 0; }
static inline int cpu_capacity(int cpu)
diff --git a/kernel/sched/sched_avg.c b/kernel/sched/sched_avg.c
index 29d8a26a78ed..ba5a326a9fd8 100644
--- a/kernel/sched/sched_avg.c
+++ b/kernel/sched/sched_avg.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012, 2015-2016, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012, 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
@@ -26,11 +26,13 @@ static DEFINE_PER_CPU(u64, nr_prod_sum);
static DEFINE_PER_CPU(u64, last_time);
static DEFINE_PER_CPU(u64, nr_big_prod_sum);
static DEFINE_PER_CPU(u64, nr);
+static DEFINE_PER_CPU(u64, nr_max);
static DEFINE_PER_CPU(unsigned long, iowait_prod_sum);
static DEFINE_PER_CPU(spinlock_t, nr_lock) = __SPIN_LOCK_UNLOCKED(nr_lock);
static s64 last_get_time;
+#define DIV64_U64_ROUNDUP(X, Y) div64_u64((X) + (Y - 1), Y)
/**
* sched_get_nr_running_avg
* @return: Average nr_running, iowait and nr_big_tasks value since last poll.
@@ -40,7 +42,8 @@ static s64 last_get_time;
* Obtains the average nr_running value since the last poll.
* This function may not be called concurrently with itself
*/
-void sched_get_nr_running_avg(int *avg, int *iowait_avg, int *big_avg)
+void sched_get_nr_running_avg(int *avg, int *iowait_avg, int *big_avg,
+ unsigned int *max_nr, unsigned int *big_max_nr)
{
int cpu;
u64 curr_time = sched_clock();
@@ -50,6 +53,8 @@ void sched_get_nr_running_avg(int *avg, int *iowait_avg, int *big_avg)
*avg = 0;
*iowait_avg = 0;
*big_avg = 0;
+ *max_nr = 0;
+ *big_max_nr = 0;
if (!diff)
return;
@@ -78,17 +83,35 @@ void sched_get_nr_running_avg(int *avg, int *iowait_avg, int *big_avg)
per_cpu(nr_big_prod_sum, cpu) = 0;
per_cpu(iowait_prod_sum, cpu) = 0;
+ if (*max_nr < per_cpu(nr_max, cpu))
+ *max_nr = per_cpu(nr_max, cpu);
+
+ if (is_max_capacity_cpu(cpu)) {
+ if (*big_max_nr < per_cpu(nr_max, cpu))
+ *big_max_nr = per_cpu(nr_max, cpu);
+ }
+
+ per_cpu(nr_max, cpu) = per_cpu(nr, cpu);
spin_unlock_irqrestore(&per_cpu(nr_lock, cpu), flags);
}
diff = curr_time - last_get_time;
last_get_time = curr_time;
- *avg = (int)div64_u64(tmp_avg * 100, diff);
- *big_avg = (int)div64_u64(tmp_big_avg * 100, diff);
- *iowait_avg = (int)div64_u64(tmp_iowait * 100, diff);
-
- trace_sched_get_nr_running_avg(*avg, *big_avg, *iowait_avg);
+ /*
+ * Any task running on BIG cluster and BIG tasks running on little
+ * cluster contributes to big_avg. Small or medium tasks can also
+ * run on BIG cluster when co-location and scheduler boost features
+ * are activated. We don't want these tasks to downmigrate to little
+ * cluster when BIG CPUs are available but isolated. Round up the
+ * average values so that core_ctl aggressively unisolate BIG CPUs.
+ */
+ *avg = (int)DIV64_U64_ROUNDUP(tmp_avg, diff);
+ *big_avg = (int)DIV64_U64_ROUNDUP(tmp_big_avg, diff);
+ *iowait_avg = (int)DIV64_U64_ROUNDUP(tmp_iowait, diff);
+
+ trace_sched_get_nr_running_avg(*avg, *big_avg, *iowait_avg,
+ *max_nr, *big_max_nr);
BUG_ON(*avg < 0 || *big_avg < 0 || *iowait_avg < 0);
pr_debug("%s - avg:%d big_avg:%d iowait_avg:%d\n",
@@ -121,6 +144,9 @@ void sched_update_nr_prod(int cpu, long delta, bool inc)
BUG_ON((s64)per_cpu(nr, cpu) < 0);
+ if (per_cpu(nr, cpu) > per_cpu(nr_max, cpu))
+ per_cpu(nr_max, cpu) = per_cpu(nr, cpu);
+
per_cpu(nr_prod_sum, cpu) += nr_running * diff;
per_cpu(nr_big_prod_sum, cpu) += nr_eligible_big_tasks(cpu) * diff;
per_cpu(iowait_prod_sum, cpu) += nr_iowait_cpu(cpu) * diff;
diff --git a/kernel/time/hrtimer.c b/kernel/time/hrtimer.c
index 01a49614e942..e7c2392666cb 100644
--- a/kernel/time/hrtimer.c
+++ b/kernel/time/hrtimer.c
@@ -49,7 +49,6 @@
#include <linux/sched/deadline.h>
#include <linux/timer.h>
#include <linux/freezer.h>
-#include <linux/delay.h>
#include <asm/uaccess.h>
@@ -1593,42 +1592,22 @@ static void init_hrtimers_cpu(int cpu)
}
#if defined(CONFIG_HOTPLUG_CPU)
-static void migrate_hrtimer_list(struct hrtimer_cpu_base *old_base,
- struct hrtimer_cpu_base *new_base,
- unsigned int i,
- bool wait,
+static void migrate_hrtimer_list(struct hrtimer_clock_base *old_base,
+ struct hrtimer_clock_base *new_base,
bool remove_pinned)
{
struct hrtimer *timer;
struct timerqueue_node *node;
struct timerqueue_head pinned;
int is_pinned;
- struct hrtimer_clock_base *old_c_base = &old_base->clock_base[i];
- struct hrtimer_clock_base *new_c_base = &new_base->clock_base[i];
+ bool is_hotplug = !cpu_online(old_base->cpu_base->cpu);
timerqueue_init_head(&pinned);
- while ((node = timerqueue_getnext(&old_c_base->active))) {
+ while ((node = timerqueue_getnext(&old_base->active))) {
timer = container_of(node, struct hrtimer, node);
- if (wait) {
- /* Ensure timers are done running before continuing */
- while (hrtimer_callback_running(timer)) {
- raw_spin_unlock(&old_base->lock);
- raw_spin_unlock(&new_base->lock);
- cpu_relax();
- /*
- * cpu_relax may just be a barrier. Grant the
- * run_hrtimer_list code some time to obtain the
- * spinlock.
- */
- udelay(2);
- raw_spin_lock(&new_base->lock);
- raw_spin_lock_nested(&old_base->lock,
- SINGLE_DEPTH_NESTING);
- }
- } else {
+ if (is_hotplug)
BUG_ON(hrtimer_callback_running(timer));
- }
debug_deactivate(timer);
/*
@@ -1636,7 +1615,7 @@ static void migrate_hrtimer_list(struct hrtimer_cpu_base *old_base,
* timer could be seen as !active and just vanish away
* under us on another CPU
*/
- __remove_hrtimer(timer, old_c_base, HRTIMER_STATE_ENQUEUED, 0);
+ __remove_hrtimer(timer, old_base, HRTIMER_STATE_ENQUEUED, 0);
is_pinned = timer->state & HRTIMER_STATE_PINNED;
if (!remove_pinned && is_pinned) {
@@ -1644,7 +1623,7 @@ static void migrate_hrtimer_list(struct hrtimer_cpu_base *old_base,
continue;
}
- timer->base = new_c_base;
+ timer->base = new_base;
/*
* Enqueue the timers on the new cpu. This does not
* reprogram the event device in case the timer
@@ -1653,7 +1632,7 @@ static void migrate_hrtimer_list(struct hrtimer_cpu_base *old_base,
* sort out already expired timers and reprogram the
* event device.
*/
- enqueue_hrtimer(timer, new_c_base);
+ enqueue_hrtimer(timer, new_base);
}
/* Re-queue pinned timers for non-hotplug usecase */
@@ -1661,11 +1640,11 @@ static void migrate_hrtimer_list(struct hrtimer_cpu_base *old_base,
timer = container_of(node, struct hrtimer, node);
timerqueue_del(&pinned, &timer->node);
- enqueue_hrtimer(timer, old_c_base);
+ enqueue_hrtimer(timer, old_base);
}
}
-static void __migrate_hrtimers(int scpu, bool wait, bool remove_pinned)
+static void __migrate_hrtimers(int scpu, bool remove_pinned)
{
struct hrtimer_cpu_base *old_base, *new_base;
unsigned long flags;
@@ -1682,8 +1661,8 @@ static void __migrate_hrtimers(int scpu, bool wait, bool remove_pinned)
raw_spin_lock_nested(&old_base->lock, SINGLE_DEPTH_NESTING);
for (i = 0; i < HRTIMER_MAX_CLOCK_BASES; i++) {
- migrate_hrtimer_list(old_base, new_base, i, wait,
- remove_pinned);
+ migrate_hrtimer_list(&old_base->clock_base[i],
+ &new_base->clock_base[i], remove_pinned);
}
raw_spin_unlock(&old_base->lock);
@@ -1699,12 +1678,12 @@ static void migrate_hrtimers(int scpu)
BUG_ON(cpu_online(scpu));
tick_cancel_sched_timer(scpu);
- __migrate_hrtimers(scpu, false, true);
+ __migrate_hrtimers(scpu, true);
}
void hrtimer_quiesce_cpu(void *cpup)
{
- __migrate_hrtimers(*(int *)cpup, true, false);
+ __migrate_hrtimers(*(int *)cpup, false);
}
#endif /* CONFIG_HOTPLUG_CPU */
diff --git a/kernel/time/posix-cpu-timers.c b/kernel/time/posix-cpu-timers.c
index 80016b329d94..051544aec37c 100644
--- a/kernel/time/posix-cpu-timers.c
+++ b/kernel/time/posix-cpu-timers.c
@@ -1250,7 +1250,7 @@ void run_posix_cpu_timers(struct task_struct *tsk)
void set_process_cpu_timer(struct task_struct *tsk, unsigned int clock_idx,
cputime_t *newval, cputime_t *oldval)
{
- unsigned long long now;
+ unsigned long long now = 0;
WARN_ON_ONCE(clock_idx == CPUCLOCK_SCHED);
cpu_timer_sample_group(clock_idx, tsk, &now);
diff --git a/net/ipc_router/ipc_router_core.c b/net/ipc_router/ipc_router_core.c
index d23799a5b260..f08aef9509bb 100644
--- a/net/ipc_router/ipc_router_core.c
+++ b/net/ipc_router/ipc_router_core.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011-2016, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2011-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
@@ -149,6 +149,7 @@ struct msm_ipc_router_xprt_info {
void *log_ctx;
struct kref ref;
struct completion ref_complete;
+ bool dynamic_ws;
};
#define RT_HASH_SIZE 4
@@ -216,6 +217,13 @@ enum {
UP,
};
+static bool is_wakeup_source_allowed;
+
+void msm_ipc_router_set_ws_allowed(bool flag)
+{
+ is_wakeup_source_allowed = flag;
+}
+
static void init_routing_table(void)
{
int i;
@@ -581,6 +589,7 @@ struct rr_packet *clone_pkt(struct rr_packet *pkt)
}
cloned_pkt->pkt_fragment_q = pkt_fragment_q;
cloned_pkt->length = pkt->length;
+ cloned_pkt->ws_need = pkt->ws_need;
return cloned_pkt;
fail_clone:
@@ -1164,7 +1173,8 @@ static int post_pkt_to_port(struct msm_ipc_port *port_ptr,
}
mutex_lock(&port_ptr->port_rx_q_lock_lhc3);
- __pm_stay_awake(port_ptr->port_rx_ws);
+ if (pkt->ws_need)
+ __pm_stay_awake(port_ptr->port_rx_ws);
list_add_tail(&temp_pkt->list, &port_ptr->port_rx_q);
wake_up(&port_ptr->port_rx_wait_q);
notify = port_ptr->notify;
@@ -4064,6 +4074,9 @@ static int msm_ipc_router_add_xprt(struct msm_ipc_router_xprt *xprt)
INIT_LIST_HEAD(&xprt_info->list);
kref_init(&xprt_info->ref);
init_completion(&xprt_info->ref_complete);
+ xprt_info->dynamic_ws = 0;
+ if (xprt->get_ws_info)
+ xprt_info->dynamic_ws = xprt->get_ws_info(xprt);
xprt_info->workqueue = create_singlethread_workqueue(xprt->name);
if (!xprt_info->workqueue) {
@@ -4218,9 +4231,18 @@ void msm_ipc_router_xprt_notify(struct msm_ipc_router_xprt *xprt,
if (!pkt)
return;
+ pkt->ws_need = false;
mutex_lock(&xprt_info->rx_lock_lhb2);
list_add_tail(&pkt->list, &xprt_info->pkt_list);
- __pm_stay_awake(&xprt_info->ws);
+ if (!xprt_info->dynamic_ws) {
+ __pm_stay_awake(&xprt_info->ws);
+ pkt->ws_need = true;
+ } else {
+ if (is_wakeup_source_allowed) {
+ __pm_stay_awake(&xprt_info->ws);
+ pkt->ws_need = true;
+ }
+ }
mutex_unlock(&xprt_info->rx_lock_lhb2);
queue_work(xprt_info->workqueue, &xprt_info->read_data);
}
diff --git a/net/netfilter/xt_HARDIDLETIMER.c b/net/netfilter/xt_HARDIDLETIMER.c
index 06322e4de632..ecb4a7fb6bf8 100644
--- a/net/netfilter/xt_HARDIDLETIMER.c
+++ b/net/netfilter/xt_HARDIDLETIMER.c
@@ -4,7 +4,7 @@
* Netfilter module to trigger a timer when packet matches.
* After timer expires a kevent will be sent.
*
- * Copyright (c) 2014-2015, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2014-2015, 2017 The Linux Foundation. All rights reserved.
*
* Copyright (C) 2004, 2010 Nokia Corporation
*
@@ -187,6 +187,8 @@ static int hardidletimer_tg_create(struct hardidletimer_tg_info *info)
pr_debug("couldn't add file to sysfs");
goto out_free_attr;
}
+ /* notify userspace */
+ kobject_uevent(hardidletimer_tg_kobj, KOBJ_ADD);
list_add(&info->timer->entry, &hardidletimer_tg_list);
diff --git a/net/netfilter/xt_IDLETIMER.c b/net/netfilter/xt_IDLETIMER.c
index 80b32de1d99c..f9eb8641dc3a 100644
--- a/net/netfilter/xt_IDLETIMER.c
+++ b/net/netfilter/xt_IDLETIMER.c
@@ -307,6 +307,8 @@ static int idletimer_tg_create(struct idletimer_tg_info *info)
pr_debug("couldn't add file to sysfs");
goto out_free_attr;
}
+ /* notify userspace */
+ kobject_uevent(idletimer_tg_kobj, KOBJ_ADD);
list_add(&info->timer->entry, &idletimer_tg_list);
diff --git a/net/sched/sch_api.c b/net/sched/sch_api.c
index b855352167b1..5474dc7c125a 100644
--- a/net/sched/sch_api.c
+++ b/net/sched/sch_api.c
@@ -1200,12 +1200,7 @@ tc_qdisc_flow_control(struct net_device *dev, u32 tcm_handle, int enable_flow)
qdisc_len = q->q.qlen;
if (q->ops->change(q, &req.attr) != 0)
pr_err("%s(): qdisc change failed", __func__);
- } else {
- WARN_ONCE(1, "%s(): called on queue which does %s",
- __func__, "not support change() operation");
}
- } else {
- WARN_ONCE(1, "%s(): called on bad queue", __func__);
}
return qdisc_len;
}
diff --git a/net/unix/af_unix.c b/net/unix/af_unix.c
index b2e934ff2448..1f5d18d80fba 100644
--- a/net/unix/af_unix.c
+++ b/net/unix/af_unix.c
@@ -991,7 +991,7 @@ static int unix_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len)
struct sockaddr_un *sunaddr = (struct sockaddr_un *)uaddr;
char *sun_path = sunaddr->sun_path;
int err;
- unsigned int hash;
+ unsigned int hash = 0;
struct unix_address *addr;
struct hlist_head *list;
struct path path = { NULL, NULL };
diff --git a/sound/soc/codecs/msm_sdw/msm-sdw-tables.c b/sound/soc/codecs/msm_sdw/msm-sdw-tables.c
index 4cbdb728ef41..1b51805bb92e 100644
--- a/sound/soc/codecs/msm_sdw/msm-sdw-tables.c
+++ b/sound/soc/codecs/msm_sdw/msm-sdw-tables.c
@@ -220,3 +220,100 @@ const u8 msm_sdw_reg_readable[MSM_SDW_MAX_REGISTER] = {
[MSM_SDW_TOP_I2S_RESET] = 1,
[MSM_SDW_TOP_BLOCKS_RESET] = 1,
};
+
+const u8 msm_sdw_reg_writeable[MSM_SDW_MAX_REGISTER] = {
+ [MSM_SDW_PAGE_REGISTER] = 1,
+ [MSM_SDW_TX9_SPKR_PROT_PATH_CTL] = 1,
+ [MSM_SDW_TX9_SPKR_PROT_PATH_CFG0] = 1,
+ [MSM_SDW_TX10_SPKR_PROT_PATH_CTL] = 1,
+ [MSM_SDW_TX10_SPKR_PROT_PATH_CFG0] = 1,
+ [MSM_SDW_TX11_SPKR_PROT_PATH_CTL] = 1,
+ [MSM_SDW_TX11_SPKR_PROT_PATH_CFG0] = 1,
+ [MSM_SDW_TX12_SPKR_PROT_PATH_CTL] = 1,
+ [MSM_SDW_TX12_SPKR_PROT_PATH_CFG0] = 1,
+ [MSM_SDW_COMPANDER7_CTL0] = 1,
+ [MSM_SDW_COMPANDER7_CTL1] = 1,
+ [MSM_SDW_COMPANDER7_CTL2] = 1,
+ [MSM_SDW_COMPANDER7_CTL3] = 1,
+ [MSM_SDW_COMPANDER7_CTL4] = 1,
+ [MSM_SDW_COMPANDER7_CTL5] = 1,
+ [MSM_SDW_COMPANDER7_CTL7] = 1,
+ [MSM_SDW_COMPANDER8_CTL0] = 1,
+ [MSM_SDW_COMPANDER8_CTL1] = 1,
+ [MSM_SDW_COMPANDER8_CTL2] = 1,
+ [MSM_SDW_COMPANDER8_CTL3] = 1,
+ [MSM_SDW_COMPANDER8_CTL4] = 1,
+ [MSM_SDW_COMPANDER8_CTL5] = 1,
+ [MSM_SDW_COMPANDER8_CTL7] = 1,
+ [MSM_SDW_RX7_RX_PATH_CTL] = 1,
+ [MSM_SDW_RX7_RX_PATH_CFG0] = 1,
+ [MSM_SDW_RX7_RX_PATH_CFG1] = 1,
+ [MSM_SDW_RX7_RX_PATH_CFG2] = 1,
+ [MSM_SDW_RX7_RX_VOL_CTL] = 1,
+ [MSM_SDW_RX7_RX_PATH_MIX_CTL] = 1,
+ [MSM_SDW_RX7_RX_PATH_MIX_CFG] = 1,
+ [MSM_SDW_RX7_RX_VOL_MIX_CTL] = 1,
+ [MSM_SDW_RX7_RX_PATH_SEC0] = 1,
+ [MSM_SDW_RX7_RX_PATH_SEC1] = 1,
+ [MSM_SDW_RX7_RX_PATH_SEC2] = 1,
+ [MSM_SDW_RX7_RX_PATH_SEC3] = 1,
+ [MSM_SDW_RX7_RX_PATH_SEC5] = 1,
+ [MSM_SDW_RX7_RX_PATH_SEC6] = 1,
+ [MSM_SDW_RX7_RX_PATH_SEC7] = 1,
+ [MSM_SDW_RX7_RX_PATH_MIX_SEC0] = 1,
+ [MSM_SDW_RX7_RX_PATH_MIX_SEC1] = 1,
+ [MSM_SDW_RX8_RX_PATH_CTL] = 1,
+ [MSM_SDW_RX8_RX_PATH_CFG0] = 1,
+ [MSM_SDW_RX8_RX_PATH_CFG1] = 1,
+ [MSM_SDW_RX8_RX_PATH_CFG2] = 1,
+ [MSM_SDW_RX8_RX_VOL_CTL] = 1,
+ [MSM_SDW_RX8_RX_PATH_MIX_CTL] = 1,
+ [MSM_SDW_RX8_RX_PATH_MIX_CFG] = 1,
+ [MSM_SDW_RX8_RX_VOL_MIX_CTL] = 1,
+ [MSM_SDW_RX8_RX_PATH_SEC0] = 1,
+ [MSM_SDW_RX8_RX_PATH_SEC1] = 1,
+ [MSM_SDW_RX8_RX_PATH_SEC2] = 1,
+ [MSM_SDW_RX8_RX_PATH_SEC3] = 1,
+ [MSM_SDW_RX8_RX_PATH_SEC5] = 1,
+ [MSM_SDW_RX8_RX_PATH_SEC6] = 1,
+ [MSM_SDW_RX8_RX_PATH_SEC7] = 1,
+ [MSM_SDW_RX8_RX_PATH_MIX_SEC0] = 1,
+ [MSM_SDW_RX8_RX_PATH_MIX_SEC1] = 1,
+ [MSM_SDW_BOOST0_BOOST_PATH_CTL] = 1,
+ [MSM_SDW_BOOST0_BOOST_CTL] = 1,
+ [MSM_SDW_BOOST0_BOOST_CFG1] = 1,
+ [MSM_SDW_BOOST0_BOOST_CFG2] = 1,
+ [MSM_SDW_BOOST1_BOOST_PATH_CTL] = 1,
+ [MSM_SDW_BOOST1_BOOST_CTL] = 1,
+ [MSM_SDW_BOOST1_BOOST_CFG1] = 1,
+ [MSM_SDW_BOOST1_BOOST_CFG2] = 1,
+ [MSM_SDW_AHB_BRIDGE_WR_DATA_0] = 1,
+ [MSM_SDW_AHB_BRIDGE_WR_DATA_1] = 1,
+ [MSM_SDW_AHB_BRIDGE_WR_DATA_2] = 1,
+ [MSM_SDW_AHB_BRIDGE_WR_DATA_3] = 1,
+ [MSM_SDW_AHB_BRIDGE_WR_ADDR_0] = 1,
+ [MSM_SDW_AHB_BRIDGE_WR_ADDR_1] = 1,
+ [MSM_SDW_AHB_BRIDGE_WR_ADDR_2] = 1,
+ [MSM_SDW_AHB_BRIDGE_WR_ADDR_3] = 1,
+ [MSM_SDW_AHB_BRIDGE_RD_ADDR_0] = 1,
+ [MSM_SDW_AHB_BRIDGE_RD_ADDR_1] = 1,
+ [MSM_SDW_AHB_BRIDGE_RD_ADDR_2] = 1,
+ [MSM_SDW_AHB_BRIDGE_RD_ADDR_3] = 1,
+ [MSM_SDW_AHB_BRIDGE_ACCESS_CFG] = 1,
+ [MSM_SDW_CLK_RST_CTRL_MCLK_CONTROL] = 1,
+ [MSM_SDW_CLK_RST_CTRL_FS_CNT_CONTROL] = 1,
+ [MSM_SDW_CLK_RST_CTRL_SWR_CONTROL] = 1,
+ [MSM_SDW_TOP_TOP_CFG0] = 1,
+ [MSM_SDW_TOP_TOP_CFG1] = 1,
+ [MSM_SDW_TOP_RX_I2S_CTL] = 1,
+ [MSM_SDW_TOP_TX_I2S_CTL] = 1,
+ [MSM_SDW_TOP_RX7_PATH_INPUT0_MUX] = 1,
+ [MSM_SDW_TOP_RX7_PATH_INPUT1_MUX] = 1,
+ [MSM_SDW_TOP_RX8_PATH_INPUT0_MUX] = 1,
+ [MSM_SDW_TOP_RX8_PATH_INPUT1_MUX] = 1,
+ [MSM_SDW_TOP_FREQ_MCLK] = 1,
+ [MSM_SDW_TOP_DEBUG_BUS_SEL] = 1,
+ [MSM_SDW_TOP_DEBUG_EN] = 1,
+ [MSM_SDW_TOP_I2S_RESET] = 1,
+ [MSM_SDW_TOP_BLOCKS_RESET] = 1,
+};
diff --git a/sound/soc/codecs/msm_sdw/msm_sdw.h b/sound/soc/codecs/msm_sdw/msm_sdw.h
index 8e7612c85455..db991481e07d 100644
--- a/sound/soc/codecs/msm_sdw/msm_sdw.h
+++ b/sound/soc/codecs/msm_sdw/msm_sdw.h
@@ -21,6 +21,7 @@
extern const struct regmap_config msm_sdw_regmap_config;
extern const u8 msm_sdw_page_map[MSM_SDW_MAX_REGISTER];
extern const u8 msm_sdw_reg_readable[MSM_SDW_MAX_REGISTER];
+extern const u8 msm_sdw_reg_writeable[MSM_SDW_MAX_REGISTER];
enum {
MSM_SDW_RX4 = 0,
diff --git a/sound/soc/codecs/msm_sdw/msm_sdw_cdc.c b/sound/soc/codecs/msm_sdw/msm_sdw_cdc.c
index db723e5ec1f4..b91d13c8e010 100644
--- a/sound/soc/codecs/msm_sdw/msm_sdw_cdc.c
+++ b/sound/soc/codecs/msm_sdw/msm_sdw_cdc.c
@@ -1668,8 +1668,10 @@ static int msm_sdw_notifier_service_cb(struct notifier_block *nb,
mutex_lock(&msm_sdw->codec_mutex);
switch (opcode) {
case AUDIO_NOTIFIER_SERVICE_DOWN:
- if (initial_boot)
+ if (initial_boot) {
+ initial_boot = false;
break;
+ }
msm_sdw->int_mclk1_enabled = false;
msm_sdw->dev_up = false;
for (i = 0; i < msm_sdw->nr; i++)
diff --git a/sound/soc/codecs/msm_sdw/msm_sdw_regmap.c b/sound/soc/codecs/msm_sdw/msm_sdw_regmap.c
index e79db0ab17be..22663384ec35 100644
--- a/sound/soc/codecs/msm_sdw/msm_sdw_regmap.c
+++ b/sound/soc/codecs/msm_sdw/msm_sdw_regmap.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
@@ -115,6 +115,11 @@ static bool msm_sdw_is_readable_register(struct device *dev, unsigned int reg)
return msm_sdw_reg_readable[reg];
}
+static bool msm_sdw_is_writeable_register(struct device *dev, unsigned int reg)
+{
+ return msm_sdw_reg_writeable[reg];
+}
+
static bool msm_sdw_is_volatile_register(struct device *dev, unsigned int reg)
{
switch (reg) {
@@ -150,6 +155,7 @@ const struct regmap_config msm_sdw_regmap_config = {
.reg_defaults = msm_sdw_defaults,
.num_reg_defaults = ARRAY_SIZE(msm_sdw_defaults),
.max_register = MSM_SDW_MAX_REGISTER,
+ .writeable_reg = msm_sdw_is_writeable_register,
.volatile_reg = msm_sdw_is_volatile_register,
.readable_reg = msm_sdw_is_readable_register,
};
diff --git a/sound/soc/codecs/sdm660_cdc/msm-analog-cdc.c b/sound/soc/codecs/sdm660_cdc/msm-analog-cdc.c
index 9eaf6cc7b89b..00f2aa766363 100644
--- a/sound/soc/codecs/sdm660_cdc/msm-analog-cdc.c
+++ b/sound/soc/codecs/sdm660_cdc/msm-analog-cdc.c
@@ -3813,8 +3813,10 @@ static int sdm660_cdc_notifier_service_cb(struct notifier_block *nb,
switch (opcode) {
case AUDIO_NOTIFIER_SERVICE_DOWN:
- if (initial_boot)
+ if (initial_boot) {
+ initial_boot = false;
break;
+ }
dev_dbg(codec->dev,
"ADSP is about to power down. teardown/reset codec\n");
msm_anlg_cdc_device_down(codec);
diff --git a/sound/soc/codecs/sdm660_cdc/msm-cdc-common.h b/sound/soc/codecs/sdm660_cdc/msm-cdc-common.h
index 7a63a71ceeb1..5d5cee124bca 100644
--- a/sound/soc/codecs/sdm660_cdc/msm-cdc-common.h
+++ b/sound/soc/codecs/sdm660_cdc/msm-cdc-common.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2016, The Linux Foundation. All rights reserved.
+/* 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
@@ -19,6 +19,7 @@ extern struct reg_default
msm89xx_pmic_cdc_defaults[MSM89XX_PMIC_CDC_CACHE_SIZE];
bool msm89xx_cdc_core_readable_reg(struct device *dev, unsigned int reg);
+bool msm89xx_cdc_core_writeable_reg(struct device *dev, unsigned int reg);
bool msm89xx_cdc_core_volatile_reg(struct device *dev, unsigned int reg);
enum {
diff --git a/sound/soc/codecs/sdm660_cdc/msm-digital-cdc.c b/sound/soc/codecs/sdm660_cdc/msm-digital-cdc.c
index 6c702c8fc35f..4249ada17c87 100644
--- a/sound/soc/codecs/sdm660_cdc/msm-digital-cdc.c
+++ b/sound/soc/codecs/sdm660_cdc/msm-digital-cdc.c
@@ -77,8 +77,8 @@ static int msm_digcdc_clock_control(bool flag)
pdata = snd_soc_card_get_drvdata(registered_digcodec->component.card);
- mutex_lock(&pdata->cdc_int_mclk0_mutex);
if (flag) {
+ mutex_lock(&pdata->cdc_int_mclk0_mutex);
if (atomic_read(&pdata->int_mclk0_enabled) == false) {
pdata->digital_cdc_core_clk.enable = 1;
ret = afe_set_lpass_clock_v2(
@@ -93,7 +93,6 @@ static int msm_digcdc_clock_control(bool flag)
*/
if (ret == -ENODEV)
msm_dig_cdc->regmap->cache_only = true;
- mutex_unlock(&pdata->cdc_int_mclk0_mutex);
return ret;
}
pr_debug("enabled digital codec core clk\n");
@@ -102,10 +101,10 @@ static int msm_digcdc_clock_control(bool flag)
50);
}
} else {
+ mutex_unlock(&pdata->cdc_int_mclk0_mutex);
dev_dbg(registered_digcodec->dev,
"disable MCLK, workq to disable set already\n");
}
- mutex_unlock(&pdata->cdc_int_mclk0_mutex);
return 0;
}
@@ -116,6 +115,7 @@ static void enable_digital_callback(void *flag)
static void disable_digital_callback(void *flag)
{
+ msm_digcdc_clock_control(false);
pr_debug("disable mclk happens in workq\n");
}
@@ -982,6 +982,7 @@ static int msm_dig_cdc_event_notify(struct notifier_block *block,
struct snd_soc_codec *codec = registered_digcodec;
struct msm_dig_priv *msm_dig_cdc = snd_soc_codec_get_drvdata(codec);
struct msm_asoc_mach_data *pdata = NULL;
+ int ret = -EINVAL;
pdata = snd_soc_card_get_drvdata(codec->component.card);
@@ -1073,7 +1074,28 @@ static int msm_dig_cdc_event_notify(struct notifier_block *block,
case DIG_CDC_EVENT_SSR_UP:
regcache_cache_only(msm_dig_cdc->regmap, false);
regcache_mark_dirty(msm_dig_cdc->regmap);
+
+ mutex_lock(&pdata->cdc_int_mclk0_mutex);
+ pdata->digital_cdc_core_clk.enable = 1;
+ ret = afe_set_lpass_clock_v2(
+ AFE_PORT_ID_INT0_MI2S_RX,
+ &pdata->digital_cdc_core_clk);
+ if (ret < 0) {
+ pr_err("%s:failed to enable the MCLK\n",
+ __func__);
+ mutex_unlock(&pdata->cdc_int_mclk0_mutex);
+ break;
+ }
+ mutex_unlock(&pdata->cdc_int_mclk0_mutex);
+
regcache_sync(msm_dig_cdc->regmap);
+
+ mutex_lock(&pdata->cdc_int_mclk0_mutex);
+ pdata->digital_cdc_core_clk.enable = 0;
+ afe_set_lpass_clock_v2(
+ AFE_PORT_ID_INT0_MI2S_RX,
+ &pdata->digital_cdc_core_clk);
+ mutex_unlock(&pdata->cdc_int_mclk0_mutex);
break;
case DIG_CDC_EVENT_INVALID:
default:
@@ -2033,6 +2055,7 @@ const struct regmap_config msm_digital_regmap_config = {
.cache_type = REGCACHE_FLAT,
.reg_defaults = msm89xx_cdc_core_defaults,
.num_reg_defaults = MSM89XX_CDC_CORE_MAX_REGISTER,
+ .writeable_reg = msm89xx_cdc_core_writeable_reg,
.readable_reg = msm89xx_cdc_core_readable_reg,
.volatile_reg = msm89xx_cdc_core_volatile_reg,
.reg_format_endian = REGMAP_ENDIAN_NATIVE,
diff --git a/sound/soc/codecs/sdm660_cdc/sdm660-regmap.c b/sound/soc/codecs/sdm660_cdc/sdm660-regmap.c
index c9babac8ffaf..7d8ac6df14bb 100644
--- a/sound/soc/codecs/sdm660_cdc/sdm660-regmap.c
+++ b/sound/soc/codecs/sdm660_cdc/sdm660-regmap.c
@@ -12,6 +12,7 @@
*/
#include <linux/regmap.h>
+#include "msm-cdc-common.h"
#include "sdm660-cdc-registers.h"
/*
@@ -444,11 +445,147 @@ static const u8 msm89xx_cdc_core_reg_readable[MSM89XX_CDC_CORE_CACHE_SIZE] = {
[MSM89XX_CDC_CORE_TX4_DMIC_CTL] = 1,
};
+static const u8 msm89xx_cdc_core_reg_writeable[MSM89XX_CDC_CORE_CACHE_SIZE] = {
+ [MSM89XX_CDC_CORE_CLK_RX_RESET_CTL] = 1,
+ [MSM89XX_CDC_CORE_CLK_TX_RESET_B1_CTL] = 1,
+ [MSM89XX_CDC_CORE_CLK_DMIC_B1_CTL] = 1,
+ [MSM89XX_CDC_CORE_CLK_RX_I2S_CTL] = 1,
+ [MSM89XX_CDC_CORE_CLK_TX_I2S_CTL] = 1,
+ [MSM89XX_CDC_CORE_CLK_OTHR_RESET_B1_CTL] = 1,
+ [MSM89XX_CDC_CORE_CLK_TX_CLK_EN_B1_CTL] = 1,
+ [MSM89XX_CDC_CORE_CLK_OTHR_CTL] = 1,
+ [MSM89XX_CDC_CORE_CLK_RX_B1_CTL] = 1,
+ [MSM89XX_CDC_CORE_CLK_MCLK_CTL] = 1,
+ [MSM89XX_CDC_CORE_CLK_PDM_CTL] = 1,
+ [MSM89XX_CDC_CORE_CLK_SD_CTL] = 1,
+ [MSM89XX_CDC_CORE_CLK_DMIC_B2_CTL] = 1,
+ [MSM89XX_CDC_CORE_CLK_RX_B2_CTL] = 1,
+ [MSM89XX_CDC_CORE_CLK_TX2_I2S_CTL] = 1,
+ [MSM89XX_CDC_CORE_RX1_B1_CTL] = 1,
+ [MSM89XX_CDC_CORE_RX2_B1_CTL] = 1,
+ [MSM89XX_CDC_CORE_RX3_B1_CTL] = 1,
+ [MSM89XX_CDC_CORE_RX1_B2_CTL] = 1,
+ [MSM89XX_CDC_CORE_RX2_B2_CTL] = 1,
+ [MSM89XX_CDC_CORE_RX3_B2_CTL] = 1,
+ [MSM89XX_CDC_CORE_RX1_B3_CTL] = 1,
+ [MSM89XX_CDC_CORE_RX2_B3_CTL] = 1,
+ [MSM89XX_CDC_CORE_RX3_B3_CTL] = 1,
+ [MSM89XX_CDC_CORE_RX1_B4_CTL] = 1,
+ [MSM89XX_CDC_CORE_RX2_B4_CTL] = 1,
+ [MSM89XX_CDC_CORE_RX3_B4_CTL] = 1,
+ [MSM89XX_CDC_CORE_RX1_B5_CTL] = 1,
+ [MSM89XX_CDC_CORE_RX2_B5_CTL] = 1,
+ [MSM89XX_CDC_CORE_RX3_B5_CTL] = 1,
+ [MSM89XX_CDC_CORE_RX1_B6_CTL] = 1,
+ [MSM89XX_CDC_CORE_RX2_B6_CTL] = 1,
+ [MSM89XX_CDC_CORE_RX3_B6_CTL] = 1,
+ [MSM89XX_CDC_CORE_RX1_VOL_CTL_B1_CTL] = 1,
+ [MSM89XX_CDC_CORE_RX2_VOL_CTL_B1_CTL] = 1,
+ [MSM89XX_CDC_CORE_RX3_VOL_CTL_B1_CTL] = 1,
+ [MSM89XX_CDC_CORE_RX1_VOL_CTL_B2_CTL] = 1,
+ [MSM89XX_CDC_CORE_RX2_VOL_CTL_B2_CTL] = 1,
+ [MSM89XX_CDC_CORE_RX3_VOL_CTL_B2_CTL] = 1,
+ [MSM89XX_CDC_CORE_TOP_GAIN_UPDATE] = 1,
+ [MSM89XX_CDC_CORE_TOP_CTL] = 1,
+ [MSM89XX_CDC_CORE_COMP0_B1_CTL] = 1,
+ [MSM89XX_CDC_CORE_COMP0_B2_CTL] = 1,
+ [MSM89XX_CDC_CORE_COMP0_B3_CTL] = 1,
+ [MSM89XX_CDC_CORE_COMP0_B4_CTL] = 1,
+ [MSM89XX_CDC_CORE_COMP0_B5_CTL] = 1,
+ [MSM89XX_CDC_CORE_COMP0_B6_CTL] = 1,
+ [MSM89XX_CDC_CORE_COMP0_FS_CFG] = 1,
+ [MSM89XX_CDC_CORE_COMP0_DELAY_BUF_CTL] = 1,
+ [MSM89XX_CDC_CORE_DEBUG_DESER1_CTL] = 1,
+ [MSM89XX_CDC_CORE_DEBUG_DESER2_CTL] = 1,
+ [MSM89XX_CDC_CORE_DEBUG_B1_CTL_CFG] = 1,
+ [MSM89XX_CDC_CORE_DEBUG_B2_CTL_CFG] = 1,
+ [MSM89XX_CDC_CORE_DEBUG_B3_CTL_CFG] = 1,
+ [MSM89XX_CDC_CORE_IIR1_GAIN_B1_CTL] = 1,
+ [MSM89XX_CDC_CORE_IIR2_GAIN_B1_CTL] = 1,
+ [MSM89XX_CDC_CORE_IIR1_GAIN_B2_CTL] = 1,
+ [MSM89XX_CDC_CORE_IIR2_GAIN_B2_CTL] = 1,
+ [MSM89XX_CDC_CORE_IIR1_GAIN_B3_CTL] = 1,
+ [MSM89XX_CDC_CORE_IIR2_GAIN_B3_CTL] = 1,
+ [MSM89XX_CDC_CORE_IIR1_GAIN_B4_CTL] = 1,
+ [MSM89XX_CDC_CORE_IIR2_GAIN_B4_CTL] = 1,
+ [MSM89XX_CDC_CORE_IIR1_GAIN_B5_CTL] = 1,
+ [MSM89XX_CDC_CORE_IIR2_GAIN_B5_CTL] = 1,
+ [MSM89XX_CDC_CORE_IIR1_GAIN_B6_CTL] = 1,
+ [MSM89XX_CDC_CORE_IIR2_GAIN_B6_CTL] = 1,
+ [MSM89XX_CDC_CORE_IIR1_GAIN_B7_CTL] = 1,
+ [MSM89XX_CDC_CORE_IIR2_GAIN_B7_CTL] = 1,
+ [MSM89XX_CDC_CORE_IIR1_GAIN_B8_CTL] = 1,
+ [MSM89XX_CDC_CORE_IIR2_GAIN_B8_CTL] = 1,
+ [MSM89XX_CDC_CORE_IIR1_CTL] = 1,
+ [MSM89XX_CDC_CORE_IIR2_CTL] = 1,
+ [MSM89XX_CDC_CORE_IIR1_GAIN_TIMER_CTL] = 1,
+ [MSM89XX_CDC_CORE_IIR2_GAIN_TIMER_CTL] = 1,
+ [MSM89XX_CDC_CORE_IIR1_COEF_B1_CTL] = 1,
+ [MSM89XX_CDC_CORE_IIR2_COEF_B1_CTL] = 1,
+ [MSM89XX_CDC_CORE_IIR1_COEF_B2_CTL] = 1,
+ [MSM89XX_CDC_CORE_IIR2_COEF_B2_CTL] = 1,
+ [MSM89XX_CDC_CORE_CONN_RX1_B1_CTL] = 1,
+ [MSM89XX_CDC_CORE_CONN_RX1_B2_CTL] = 1,
+ [MSM89XX_CDC_CORE_CONN_RX1_B3_CTL] = 1,
+ [MSM89XX_CDC_CORE_CONN_RX2_B1_CTL] = 1,
+ [MSM89XX_CDC_CORE_CONN_RX2_B2_CTL] = 1,
+ [MSM89XX_CDC_CORE_CONN_RX2_B3_CTL] = 1,
+ [MSM89XX_CDC_CORE_CONN_RX3_B1_CTL] = 1,
+ [MSM89XX_CDC_CORE_CONN_RX3_B2_CTL] = 1,
+ [MSM89XX_CDC_CORE_CONN_TX_B1_CTL] = 1,
+ [MSM89XX_CDC_CORE_CONN_TX_B2_CTL] = 1,
+ [MSM89XX_CDC_CORE_CONN_EQ1_B1_CTL] = 1,
+ [MSM89XX_CDC_CORE_CONN_EQ1_B2_CTL] = 1,
+ [MSM89XX_CDC_CORE_CONN_EQ1_B3_CTL] = 1,
+ [MSM89XX_CDC_CORE_CONN_EQ1_B4_CTL] = 1,
+ [MSM89XX_CDC_CORE_CONN_EQ2_B1_CTL] = 1,
+ [MSM89XX_CDC_CORE_CONN_EQ2_B2_CTL] = 1,
+ [MSM89XX_CDC_CORE_CONN_EQ2_B3_CTL] = 1,
+ [MSM89XX_CDC_CORE_CONN_EQ2_B4_CTL] = 1,
+ [MSM89XX_CDC_CORE_CONN_TX_I2S_SD1_CTL] = 1,
+ [MSM89XX_CDC_CORE_CONN_TX_B3_CTL] = 1,
+ [MSM89XX_CDC_CORE_TX1_VOL_CTL_TIMER] = 1,
+ [MSM89XX_CDC_CORE_TX2_VOL_CTL_TIMER] = 1,
+ [MSM89XX_CDC_CORE_TX3_VOL_CTL_TIMER] = 1,
+ [MSM89XX_CDC_CORE_TX4_VOL_CTL_TIMER] = 1,
+ [MSM89XX_CDC_CORE_TX1_VOL_CTL_GAIN] = 1,
+ [MSM89XX_CDC_CORE_TX2_VOL_CTL_GAIN] = 1,
+ [MSM89XX_CDC_CORE_TX3_VOL_CTL_GAIN] = 1,
+ [MSM89XX_CDC_CORE_TX4_VOL_CTL_GAIN] = 1,
+ [MSM89XX_CDC_CORE_TX1_VOL_CTL_CFG] = 1,
+ [MSM89XX_CDC_CORE_TX2_VOL_CTL_CFG] = 1,
+ [MSM89XX_CDC_CORE_TX3_VOL_CTL_CFG] = 1,
+ [MSM89XX_CDC_CORE_TX4_VOL_CTL_CFG] = 1,
+ [MSM89XX_CDC_CORE_TX1_MUX_CTL] = 1,
+ [MSM89XX_CDC_CORE_TX2_MUX_CTL] = 1,
+ [MSM89XX_CDC_CORE_TX3_MUX_CTL] = 1,
+ [MSM89XX_CDC_CORE_TX4_MUX_CTL] = 1,
+ [MSM89XX_CDC_CORE_TX1_CLK_FS_CTL] = 1,
+ [MSM89XX_CDC_CORE_TX2_CLK_FS_CTL] = 1,
+ [MSM89XX_CDC_CORE_TX3_CLK_FS_CTL] = 1,
+ [MSM89XX_CDC_CORE_TX4_CLK_FS_CTL] = 1,
+ [MSM89XX_CDC_CORE_TX5_VOL_CTL_TIMER] = 1,
+ [MSM89XX_CDC_CORE_TX5_VOL_CTL_GAIN] = 1,
+ [MSM89XX_CDC_CORE_TX5_VOL_CTL_CFG] = 1,
+ [MSM89XX_CDC_CORE_TX5_MUX_CTL] = 1,
+ [MSM89XX_CDC_CORE_TX5_CLK_FS_CTL] = 1,
+ [MSM89XX_CDC_CORE_TX5_DMIC_CTL] = 1,
+ [MSM89XX_CDC_CORE_TX1_DMIC_CTL] = 1,
+ [MSM89XX_CDC_CORE_TX2_DMIC_CTL] = 1,
+ [MSM89XX_CDC_CORE_TX3_DMIC_CTL] = 1,
+ [MSM89XX_CDC_CORE_TX4_DMIC_CTL] = 1,
+};
+
bool msm89xx_cdc_core_readable_reg(struct device *dev, unsigned int reg)
{
return msm89xx_cdc_core_reg_readable[reg];
}
+bool msm89xx_cdc_core_writeable_reg(struct device *dev, unsigned int reg)
+{
+ return msm89xx_cdc_core_reg_writeable[reg];
+}
+
bool msm89xx_cdc_core_volatile_reg(struct device *dev, unsigned int reg)
{
switch (reg) {
diff --git a/sound/soc/codecs/wcd9335.c b/sound/soc/codecs/wcd9335.c
index 7ad3aeaa8fb7..189165ce14c6 100644
--- a/sound/soc/codecs/wcd9335.c
+++ b/sound/soc/codecs/wcd9335.c
@@ -5906,8 +5906,6 @@ static int tasha_codec_enable_dec(struct snd_soc_dapm_widget *w,
CF_MIN_3DB_150HZ << 5);
/* Enable TX PGA Mute */
snd_soc_update_bits(codec, tx_vol_ctl_reg, 0x10, 0x10);
- /* Enable APC */
- snd_soc_update_bits(codec, dec_cfg_reg, 0x08, 0x08);
break;
case SND_SOC_DAPM_POST_PMU:
snd_soc_update_bits(codec, hpf_gate_reg, 0x01, 0x00);
@@ -5934,7 +5932,6 @@ static int tasha_codec_enable_dec(struct snd_soc_dapm_widget *w,
hpf_cut_off_freq =
tasha->tx_hpf_work[decimator].hpf_cut_off_freq;
snd_soc_update_bits(codec, tx_vol_ctl_reg, 0x10, 0x10);
- snd_soc_update_bits(codec, dec_cfg_reg, 0x08, 0x00);
if (cancel_delayed_work_sync(
&tasha->tx_hpf_work[decimator].dwork)) {
if (hpf_cut_off_freq != CF_MIN_3DB_150HZ) {
diff --git a/sound/soc/codecs/wcd934x/wcd934x.c b/sound/soc/codecs/wcd934x/wcd934x.c
index 12a4d348d9a9..26320fd01a5a 100644
--- a/sound/soc/codecs/wcd934x/wcd934x.c
+++ b/sound/soc/codecs/wcd934x/wcd934x.c
@@ -123,6 +123,7 @@ static const struct snd_kcontrol_new name##_mux = \
#define WCD934X_DEC_PWR_LVL_DF 0x00
#define WCD934X_STRING_LEN 100
+#define WCD934X_CDC_SIDETONE_IIR_COEFF_MAX 5
#define WCD934X_DIG_CORE_REG_MIN WCD934X_CDC_ANC0_CLK_RESET_CTL
#define WCD934X_DIG_CORE_REG_MAX 0xFFF
@@ -654,6 +655,8 @@ struct tavil_priv {
struct tavil_idle_detect_config idle_det_cfg;
int power_active_ref;
+ int sidetone_coeff_array[IIR_MAX][BAND_MAX]
+ [WCD934X_CDC_SIDETONE_IIR_COEFF_MAX];
};
static const struct tavil_reg_mask_val tavil_spkr_default[] = {
@@ -5162,10 +5165,12 @@ static int tavil_iir_band_audio_mixer_put(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
+ struct tavil_priv *tavil = snd_soc_codec_get_drvdata(codec);
int iir_idx = ((struct soc_multi_mixer_control *)
kcontrol->private_value)->reg;
int band_idx = ((struct soc_multi_mixer_control *)
kcontrol->private_value)->shift;
+ int coeff_idx;
/*
* Mask top bit it is reserved
@@ -5175,16 +5180,15 @@ static int tavil_iir_band_audio_mixer_put(struct snd_kcontrol *kcontrol,
(WCD934X_CDC_SIDETONE_IIR0_IIR_COEF_B1_CTL + 16 * iir_idx),
(band_idx * BAND_MAX * sizeof(uint32_t)) & 0x7F);
- set_iir_band_coeff(codec, iir_idx, band_idx,
- ucontrol->value.integer.value[0]);
- set_iir_band_coeff(codec, iir_idx, band_idx,
- ucontrol->value.integer.value[1]);
- set_iir_band_coeff(codec, iir_idx, band_idx,
- ucontrol->value.integer.value[2]);
- set_iir_band_coeff(codec, iir_idx, band_idx,
- ucontrol->value.integer.value[3]);
- set_iir_band_coeff(codec, iir_idx, band_idx,
- ucontrol->value.integer.value[4]);
+ /* Store the coefficients in sidetone coeff array */
+ for (coeff_idx = 0; coeff_idx < WCD934X_CDC_SIDETONE_IIR_COEFF_MAX;
+ coeff_idx++) {
+ tavil->sidetone_coeff_array[iir_idx][band_idx][coeff_idx] =
+ ucontrol->value.integer.value[coeff_idx];
+ set_iir_band_coeff(codec, iir_idx, band_idx,
+ tavil->sidetone_coeff_array[iir_idx][band_idx]
+ [coeff_idx]);
+ }
pr_debug("%s: IIR #%d band #%d b0 = 0x%x\n"
"%s: IIR #%d band #%d b1 = 0x%x\n"
@@ -5204,6 +5208,26 @@ static int tavil_iir_band_audio_mixer_put(struct snd_kcontrol *kcontrol,
return 0;
}
+static void tavil_restore_iir_coeff(struct tavil_priv *tavil, int iir_idx)
+{
+ int band_idx = 0, coeff_idx = 0;
+ struct snd_soc_codec *codec = tavil->codec;
+
+ for (band_idx = 0; band_idx < BAND_MAX; band_idx++) {
+ snd_soc_write(codec,
+ (WCD934X_CDC_SIDETONE_IIR0_IIR_COEF_B1_CTL + 16 * iir_idx),
+ (band_idx * BAND_MAX * sizeof(uint32_t)) & 0x7F);
+
+ for (coeff_idx = 0;
+ coeff_idx < WCD934X_CDC_SIDETONE_IIR_COEFF_MAX;
+ coeff_idx++) {
+ set_iir_band_coeff(codec, iir_idx, band_idx,
+ tavil->sidetone_coeff_array[iir_idx][band_idx]
+ [coeff_idx]);
+ }
+ }
+}
+
static int tavil_compander_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
@@ -8156,6 +8180,8 @@ static int tavil_dig_core_remove_power_collapse(struct tavil_priv *tavil)
WCD934X_DIG_CORE_REG_MIN,
WCD934X_DIG_CORE_REG_MAX);
+ tavil_restore_iir_coeff(tavil, IIR0);
+ tavil_restore_iir_coeff(tavil, IIR1);
return 0;
}
diff --git a/sound/soc/msm/apq8096-auto.c b/sound/soc/msm/apq8096-auto.c
index be6a6a710dc1..b6121d75c148 100644
--- a/sound/soc/msm/apq8096-auto.c
+++ b/sound/soc/msm/apq8096-auto.c
@@ -3149,10 +3149,10 @@ static struct snd_soc_dai_link apq8096_common_dai_links[] = {
.be_id = MSM_FRONTEND_DAI_MULTIMEDIA10,
},
{
- .name = "MSM8996 Compr8",
- .stream_name = "COMPR8",
+ .name = "MSM8996 ULL NOIRQ",
+ .stream_name = "MM_NOIRQ",
.cpu_dai_name = "MultiMedia8",
- .platform_name = "msm-compr-dsp",
+ .platform_name = "msm-pcm-dsp-noirq",
.dynamic = 1,
.dpcm_playback = 1,
.dpcm_capture = 1,
diff --git a/sound/soc/msm/msm-dai-fe.c b/sound/soc/msm/msm-dai-fe.c
index 509574faebf8..24dbbedf0be7 100644
--- a/sound/soc/msm/msm-dai-fe.c
+++ b/sound/soc/msm/msm-dai-fe.c
@@ -2582,7 +2582,7 @@ static struct snd_soc_dai_driver msm_fe_dais[] = {
.channels_min = 1,
.channels_max = 8,
.rate_min = 8000,
- .rate_max = 48000,
+ .rate_max = 192000,
},
.ops = &msm_fe_Multimedia_dai_ops,
.compress_new = snd_soc_new_compress,
diff --git a/sound/soc/msm/msm8998.c b/sound/soc/msm/msm8998.c
index f6a5d1344568..0b37e7e073aa 100644
--- a/sound/soc/msm/msm8998.c
+++ b/sound/soc/msm/msm8998.c
@@ -4078,7 +4078,6 @@ static void msm_aux_pcm_snd_shutdown(struct snd_pcm_substream *substream)
dev_err(rtd->card->dev,
"%s lpaif_tert_muxsel_virt_addr is NULL\n",
__func__);
- auxpcm_intf_conf[index].ref_cnt++;
}
}
mutex_unlock(&auxpcm_intf_conf[index].lock);
@@ -4567,11 +4566,9 @@ static void msm_mi2s_snd_shutdown(struct snd_pcm_substream *substream)
mutex_lock(&mi2s_intf_conf[index].lock);
if (--mi2s_intf_conf[index].ref_cnt == 0) {
ret = msm_mi2s_set_sclk(substream, false);
- if (ret < 0) {
+ if (ret < 0)
pr_err("%s:clock disable failed for MI2S (%d); ret=%d\n",
__func__, index, ret);
- mi2s_intf_conf[index].ref_cnt++;
- }
}
mutex_unlock(&mi2s_intf_conf[index].lock);
@@ -5498,6 +5495,37 @@ static struct snd_soc_dai_link msm_common_misc_fe_dai_links[] = {
.codec_dai_name = "snd-soc-dummy-dai",
.codec_name = "snd-soc-dummy",
},
+ {
+ .name = MSM_DAILINK_NAME(Transcode Loopback Playback),
+ .stream_name = "Transcode Loopback Playback",
+ .cpu_dai_name = "MultiMedia14",
+ .platform_name = "msm-transcode-loopback",
+ .dynamic = 1,
+ .dpcm_playback = 1,
+ .trigger = {SND_SOC_DPCM_TRIGGER_POST,
+ SND_SOC_DPCM_TRIGGER_POST},
+ .codec_dai_name = "snd-soc-dummy-dai",
+ .codec_name = "snd-soc-dummy",
+ .ignore_suspend = 1,
+ .ignore_pmdown_time = 1,
+ /* this dainlink has playback support */
+ .be_id = MSM_FRONTEND_DAI_MULTIMEDIA14,
+ },
+ {
+ .name = MSM_DAILINK_NAME(Transcode Loopback Capture),
+ .stream_name = "Transcode Loopback Capture",
+ .cpu_dai_name = "MultiMedia18",
+ .platform_name = "msm-transcode-loopback",
+ .dynamic = 1,
+ .dpcm_capture = 1,
+ .trigger = {SND_SOC_DPCM_TRIGGER_POST,
+ SND_SOC_DPCM_TRIGGER_POST},
+ .codec_dai_name = "snd-soc-dummy-dai",
+ .codec_name = "snd-soc-dummy",
+ .ignore_suspend = 1,
+ .ignore_pmdown_time = 1,
+ .be_id = MSM_FRONTEND_DAI_MULTIMEDIA18,
+ },
};
static struct snd_soc_dai_link msm_common_be_dai_links[] = {
diff --git a/sound/soc/msm/qdsp6v2/Makefile b/sound/soc/msm/qdsp6v2/Makefile
index 219892a85da2..98c52a4db51f 100644
--- a/sound/soc/msm/qdsp6v2/Makefile
+++ b/sound/soc/msm/qdsp6v2/Makefile
@@ -4,7 +4,7 @@ snd-soc-qdsp6v2-objs += msm-dai-q6-v2.o msm-pcm-q6-v2.o msm-pcm-routing-v2.o \
msm-pcm-voice-v2.o msm-dai-q6-hdmi-v2.o \
msm-lsm-client.o msm-pcm-host-voice-v2.o \
msm-audio-effects-q6-v2.o msm-pcm-loopback-v2.o \
- msm-dai-slim.o \
+ msm-dai-slim.o msm-transcode-loopback-q6-v2.o \
adsp_err.o
obj-$(CONFIG_SND_SOC_QDSP6V2) += snd-soc-qdsp6v2.o msm-pcm-dtmf-v2.o \
msm-dai-stub-v2.o
diff --git a/sound/soc/msm/qdsp6v2/msm-compress-q6-v2.c b/sound/soc/msm/qdsp6v2/msm-compress-q6-v2.c
index d037f8696cac..0acf6e8ffe49 100644
--- a/sound/soc/msm/qdsp6v2/msm-compress-q6-v2.c
+++ b/sound/soc/msm/qdsp6v2/msm-compress-q6-v2.c
@@ -3433,21 +3433,18 @@ static int msm_compr_playback_app_type_cfg_put(struct snd_kcontrol *kcontrol,
u64 fe_id = kcontrol->private_value;
int session_type = SESSION_TYPE_RX;
int be_id = ucontrol->value.integer.value[3];
+ struct msm_pcm_stream_app_type_cfg cfg_data = {0, 0, 48000};
int ret = 0;
- int app_type;
- int acdb_dev_id;
- int sample_rate = 48000;
- app_type = ucontrol->value.integer.value[0];
- acdb_dev_id = ucontrol->value.integer.value[1];
+ cfg_data.app_type = ucontrol->value.integer.value[0];
+ cfg_data.acdb_dev_id = ucontrol->value.integer.value[1];
if (ucontrol->value.integer.value[2] != 0)
- sample_rate = ucontrol->value.integer.value[2];
+ cfg_data.sample_rate = ucontrol->value.integer.value[2];
pr_debug("%s: fe_id- %llu session_type- %d be_id- %d app_type- %d acdb_dev_id- %d sample_rate- %d\n",
__func__, fe_id, session_type, be_id,
- app_type, acdb_dev_id, sample_rate);
+ cfg_data.app_type, cfg_data.acdb_dev_id, cfg_data.sample_rate);
ret = msm_pcm_routing_reg_stream_app_type_cfg(fe_id, session_type,
- be_id, app_type,
- acdb_dev_id, sample_rate);
+ be_id, &cfg_data);
if (ret < 0)
pr_err("%s: msm_pcm_routing_reg_stream_app_type_cfg failed returned %d\n",
__func__, ret);
@@ -3460,28 +3457,25 @@ static int msm_compr_playback_app_type_cfg_get(struct snd_kcontrol *kcontrol,
{
u64 fe_id = kcontrol->private_value;
int session_type = SESSION_TYPE_RX;
- int be_id = ucontrol->value.integer.value[3];
+ int be_id = 0;
+ struct msm_pcm_stream_app_type_cfg cfg_data = {0};
int ret = 0;
- int app_type;
- int acdb_dev_id;
- int sample_rate;
ret = msm_pcm_routing_get_stream_app_type_cfg(fe_id, session_type,
- be_id, &app_type,
- &acdb_dev_id,
- &sample_rate);
+ &be_id, &cfg_data);
if (ret < 0) {
pr_err("%s: msm_pcm_routing_get_stream_app_type_cfg failed returned %d\n",
__func__, ret);
goto done;
}
- ucontrol->value.integer.value[0] = app_type;
- ucontrol->value.integer.value[1] = acdb_dev_id;
- ucontrol->value.integer.value[2] = sample_rate;
+ ucontrol->value.integer.value[0] = cfg_data.app_type;
+ ucontrol->value.integer.value[1] = cfg_data.acdb_dev_id;
+ ucontrol->value.integer.value[2] = cfg_data.sample_rate;
+ ucontrol->value.integer.value[3] = be_id;
pr_debug("%s: fedai_id %llu, session_type %d, be_id %d, app_type %d, acdb_dev_id %d, sample_rate %d\n",
__func__, fe_id, session_type, be_id,
- app_type, acdb_dev_id, sample_rate);
+ cfg_data.app_type, cfg_data.acdb_dev_id, cfg_data.sample_rate);
done:
return ret;
}
@@ -3492,21 +3486,18 @@ static int msm_compr_capture_app_type_cfg_put(struct snd_kcontrol *kcontrol,
u64 fe_id = kcontrol->private_value;
int session_type = SESSION_TYPE_TX;
int be_id = ucontrol->value.integer.value[3];
+ struct msm_pcm_stream_app_type_cfg cfg_data = {0, 0, 48000};
int ret = 0;
- int app_type;
- int acdb_dev_id;
- int sample_rate = 48000;
- app_type = ucontrol->value.integer.value[0];
- acdb_dev_id = ucontrol->value.integer.value[1];
+ cfg_data.app_type = ucontrol->value.integer.value[0];
+ cfg_data.acdb_dev_id = ucontrol->value.integer.value[1];
if (ucontrol->value.integer.value[2] != 0)
- sample_rate = ucontrol->value.integer.value[2];
+ cfg_data.sample_rate = ucontrol->value.integer.value[2];
pr_debug("%s: fe_id- %llu session_type- %d be_id- %d app_type- %d acdb_dev_id- %d sample_rate- %d\n",
__func__, fe_id, session_type, be_id,
- app_type, acdb_dev_id, sample_rate);
+ cfg_data.app_type, cfg_data.acdb_dev_id, cfg_data.sample_rate);
ret = msm_pcm_routing_reg_stream_app_type_cfg(fe_id, session_type,
- be_id, app_type,
- acdb_dev_id, sample_rate);
+ be_id, &cfg_data);
if (ret < 0)
pr_err("%s: msm_pcm_routing_reg_stream_app_type_cfg failed returned %d\n",
__func__, ret);
@@ -3519,28 +3510,25 @@ static int msm_compr_capture_app_type_cfg_get(struct snd_kcontrol *kcontrol,
{
u64 fe_id = kcontrol->private_value;
int session_type = SESSION_TYPE_TX;
- int be_id = ucontrol->value.integer.value[3];
+ int be_id = 0;
+ struct msm_pcm_stream_app_type_cfg cfg_data = {0};
int ret = 0;
- int app_type;
- int acdb_dev_id;
- int sample_rate;
ret = msm_pcm_routing_get_stream_app_type_cfg(fe_id, session_type,
- be_id, &app_type,
- &acdb_dev_id,
- &sample_rate);
+ &be_id, &cfg_data);
if (ret < 0) {
pr_err("%s: msm_pcm_routing_get_stream_app_type_cfg failed returned %d\n",
__func__, ret);
goto done;
}
- ucontrol->value.integer.value[0] = app_type;
- ucontrol->value.integer.value[1] = acdb_dev_id;
- ucontrol->value.integer.value[2] = sample_rate;
+ ucontrol->value.integer.value[0] = cfg_data.app_type;
+ ucontrol->value.integer.value[1] = cfg_data.acdb_dev_id;
+ ucontrol->value.integer.value[2] = cfg_data.sample_rate;
+ ucontrol->value.integer.value[3] = be_id;
pr_debug("%s: fedai_id %llu, session_type %d, be_id %d, app_type %d, acdb_dev_id %d, sample_rate %d\n",
__func__, fe_id, session_type, be_id,
- app_type, acdb_dev_id, sample_rate);
+ cfg_data.app_type, cfg_data.acdb_dev_id, cfg_data.sample_rate);
done:
return ret;
}
diff --git a/sound/soc/msm/qdsp6v2/msm-lsm-client.c b/sound/soc/msm/qdsp6v2/msm-lsm-client.c
index 1003dc8ddc5a..3e72aa130c18 100644
--- a/sound/soc/msm/qdsp6v2/msm-lsm-client.c
+++ b/sound/soc/msm/qdsp6v2/msm-lsm-client.c
@@ -2246,21 +2246,18 @@ static int msm_lsm_app_type_cfg_ctl_put(struct snd_kcontrol *kcontrol,
u64 fe_id = kcontrol->private_value;
int session_type = SESSION_TYPE_TX;
int be_id = ucontrol->value.integer.value[3];
+ struct msm_pcm_stream_app_type_cfg cfg_data = {0};
int ret = 0;
- int app_type;
- int acdb_dev_id;
- int sample_rate;
- app_type = ucontrol->value.integer.value[0];
- acdb_dev_id = ucontrol->value.integer.value[1];
- sample_rate = ucontrol->value.integer.value[2];
+ cfg_data.app_type = ucontrol->value.integer.value[0];
+ cfg_data.acdb_dev_id = ucontrol->value.integer.value[1];
+ cfg_data.sample_rate = ucontrol->value.integer.value[2];
pr_debug("%s: fe_id- %llu session_type- %d be_id- %d app_type- %d acdb_dev_id- %d sample_rate- %d\n",
__func__, fe_id, session_type, be_id,
- app_type, acdb_dev_id, sample_rate);
+ cfg_data.app_type, cfg_data.acdb_dev_id, cfg_data.sample_rate);
ret = msm_pcm_routing_reg_stream_app_type_cfg(fe_id, session_type,
- be_id, app_type,
- acdb_dev_id, sample_rate);
+ be_id, &cfg_data);
if (ret < 0)
pr_err("%s: msm_pcm_routing_reg_stream_app_type_cfg failed returned %d\n",
__func__, ret);
@@ -2273,28 +2270,25 @@ static int msm_lsm_app_type_cfg_ctl_get(struct snd_kcontrol *kcontrol,
{
u64 fe_id = kcontrol->private_value;
int session_type = SESSION_TYPE_TX;
- int be_id = ucontrol->value.integer.value[3];
+ int be_id = 0;
+ struct msm_pcm_stream_app_type_cfg cfg_data = {0};
int ret = 0;
- int app_type;
- int acdb_dev_id;
- int sample_rate;
ret = msm_pcm_routing_get_stream_app_type_cfg(fe_id, session_type,
- be_id, &app_type,
- &acdb_dev_id,
- &sample_rate);
+ &be_id, &cfg_data);
if (ret < 0) {
pr_err("%s: msm_pcm_routing_get_stream_app_type_cfg failed returned %d\n",
__func__, ret);
goto done;
}
- ucontrol->value.integer.value[0] = app_type;
- ucontrol->value.integer.value[1] = acdb_dev_id;
- ucontrol->value.integer.value[2] = sample_rate;
+ ucontrol->value.integer.value[0] = cfg_data.app_type;
+ ucontrol->value.integer.value[1] = cfg_data.acdb_dev_id;
+ ucontrol->value.integer.value[2] = cfg_data.sample_rate;
+ ucontrol->value.integer.value[3] = be_id;
pr_debug("%s: fedai_id %llu, session_type %d, be_id %d, app_type %d, acdb_dev_id %d, sample_rate %d\n",
__func__, fe_id, session_type, be_id,
- app_type, acdb_dev_id, sample_rate);
+ cfg_data.app_type, cfg_data.acdb_dev_id, cfg_data.sample_rate);
done:
return ret;
}
diff --git a/sound/soc/msm/qdsp6v2/msm-pcm-loopback-v2.c b/sound/soc/msm/qdsp6v2/msm-pcm-loopback-v2.c
index b8610b59ca63..44f59c49b670 100644
--- a/sound/soc/msm/qdsp6v2/msm-pcm-loopback-v2.c
+++ b/sound/soc/msm/qdsp6v2/msm-pcm-loopback-v2.c
@@ -558,21 +558,18 @@ static int msm_pcm_playback_app_type_cfg_ctl_put(struct snd_kcontrol *kcontrol,
u64 fe_id = kcontrol->private_value;
int session_type = SESSION_TYPE_RX;
int be_id = ucontrol->value.integer.value[3];
+ struct msm_pcm_stream_app_type_cfg cfg_data = {0, 0, 48000};
int ret = 0;
- int app_type;
- int acdb_dev_id;
- int sample_rate = 48000;
- app_type = ucontrol->value.integer.value[0];
- acdb_dev_id = ucontrol->value.integer.value[1];
+ cfg_data.app_type = ucontrol->value.integer.value[0];
+ cfg_data.acdb_dev_id = ucontrol->value.integer.value[1];
if (ucontrol->value.integer.value[2] != 0)
- sample_rate = ucontrol->value.integer.value[2];
+ cfg_data.sample_rate = ucontrol->value.integer.value[2];
pr_debug("%s: fe_id- %llu session_type- %d be_id- %d app_type- %d acdb_dev_id- %d sample_rate- %d\n",
__func__, fe_id, session_type, be_id,
- app_type, acdb_dev_id, sample_rate);
+ cfg_data.app_type, cfg_data.acdb_dev_id, cfg_data.sample_rate);
ret = msm_pcm_routing_reg_stream_app_type_cfg(fe_id, session_type,
- be_id, app_type,
- acdb_dev_id, sample_rate);
+ be_id, &cfg_data);
if (ret < 0)
pr_err("%s: msm_pcm_routing_reg_stream_app_type_cfg failed returned %d\n",
__func__, ret);
@@ -585,28 +582,25 @@ static int msm_pcm_playback_app_type_cfg_ctl_get(struct snd_kcontrol *kcontrol,
{
u64 fe_id = kcontrol->private_value;
int session_type = SESSION_TYPE_RX;
- int be_id = ucontrol->value.integer.value[3];
+ int be_id = 0;
+ struct msm_pcm_stream_app_type_cfg cfg_data = {0};
int ret = 0;
- int app_type;
- int acdb_dev_id;
- int sample_rate;
ret = msm_pcm_routing_get_stream_app_type_cfg(fe_id, session_type,
- be_id, &app_type,
- &acdb_dev_id,
- &sample_rate);
+ &be_id, &cfg_data);
if (ret < 0) {
pr_err("%s: msm_pcm_routing_get_stream_app_type_cfg failed returned %d\n",
__func__, ret);
goto done;
}
- ucontrol->value.integer.value[0] = app_type;
- ucontrol->value.integer.value[1] = acdb_dev_id;
- ucontrol->value.integer.value[2] = sample_rate;
+ ucontrol->value.integer.value[0] = cfg_data.app_type;
+ ucontrol->value.integer.value[1] = cfg_data.acdb_dev_id;
+ ucontrol->value.integer.value[2] = cfg_data.sample_rate;
+ ucontrol->value.integer.value[3] = be_id;
pr_debug("%s: fedai_id %llu, session_type %d, be_id %d, app_type %d, acdb_dev_id %d, sample_rate %d\n",
__func__, fe_id, session_type, be_id,
- app_type, acdb_dev_id, sample_rate);
+ cfg_data.app_type, cfg_data.acdb_dev_id, cfg_data.sample_rate);
done:
return ret;
}
@@ -617,21 +611,18 @@ static int msm_pcm_capture_app_type_cfg_ctl_put(struct snd_kcontrol *kcontrol,
u64 fe_id = kcontrol->private_value;
int session_type = SESSION_TYPE_TX;
int be_id = ucontrol->value.integer.value[3];
+ struct msm_pcm_stream_app_type_cfg cfg_data = {0, 0, 48000};
int ret = 0;
- int app_type;
- int acdb_dev_id;
- int sample_rate = 48000;
- app_type = ucontrol->value.integer.value[0];
- acdb_dev_id = ucontrol->value.integer.value[1];
+ cfg_data.app_type = ucontrol->value.integer.value[0];
+ cfg_data.acdb_dev_id = ucontrol->value.integer.value[1];
if (ucontrol->value.integer.value[2] != 0)
- sample_rate = ucontrol->value.integer.value[2];
+ cfg_data.sample_rate = ucontrol->value.integer.value[2];
pr_debug("%s: fe_id- %llu session_type- %d be_id- %d app_type- %d acdb_dev_id- %d sample_rate- %d\n",
__func__, fe_id, session_type, be_id,
- app_type, acdb_dev_id, sample_rate);
+ cfg_data.app_type, cfg_data.acdb_dev_id, cfg_data.sample_rate);
ret = msm_pcm_routing_reg_stream_app_type_cfg(fe_id, session_type,
- be_id, app_type,
- acdb_dev_id, sample_rate);
+ be_id, &cfg_data);
if (ret < 0)
pr_err("%s: msm_pcm_routing_reg_stream_app_type_cfg failed returned %d\n",
__func__, ret);
@@ -644,28 +635,25 @@ static int msm_pcm_capture_app_type_cfg_ctl_get(struct snd_kcontrol *kcontrol,
{
u64 fe_id = kcontrol->private_value;
int session_type = SESSION_TYPE_TX;
- int be_id = ucontrol->value.integer.value[3];
+ int be_id = 0;
+ struct msm_pcm_stream_app_type_cfg cfg_data = {0};
int ret = 0;
- int app_type;
- int acdb_dev_id;
- int sample_rate;
ret = msm_pcm_routing_get_stream_app_type_cfg(fe_id, session_type,
- be_id, &app_type,
- &acdb_dev_id,
- &sample_rate);
+ &be_id, &cfg_data);
if (ret < 0) {
pr_err("%s: msm_pcm_routing_get_stream_app_type_cfg failed returned %d\n",
__func__, ret);
goto done;
}
- ucontrol->value.integer.value[0] = app_type;
- ucontrol->value.integer.value[1] = acdb_dev_id;
- ucontrol->value.integer.value[2] = sample_rate;
+ ucontrol->value.integer.value[0] = cfg_data.app_type;
+ ucontrol->value.integer.value[1] = cfg_data.acdb_dev_id;
+ ucontrol->value.integer.value[2] = cfg_data.sample_rate;
+ ucontrol->value.integer.value[3] = be_id;
pr_debug("%s: fedai_id %llu, session_type %d, be_id %d, app_type %d, acdb_dev_id %d, sample_rate %d\n",
__func__, fe_id, session_type, be_id,
- app_type, acdb_dev_id, sample_rate);
+ cfg_data.app_type, cfg_data.acdb_dev_id, cfg_data.sample_rate);
done:
return ret;
}
diff --git a/sound/soc/msm/qdsp6v2/msm-pcm-q6-noirq.c b/sound/soc/msm/qdsp6v2/msm-pcm-q6-noirq.c
index c0ca9b24f544..6b026bafa276 100644
--- a/sound/soc/msm/qdsp6v2/msm-pcm-q6-noirq.c
+++ b/sound/soc/msm/qdsp6v2/msm-pcm-q6-noirq.c
@@ -842,26 +842,21 @@ static int msm_pcm_playback_app_type_cfg_ctl_put(struct snd_kcontrol *kcontrol,
u64 fe_id = kcontrol->private_value;
int session_type = SESSION_TYPE_RX;
int be_id = ucontrol->value.integer.value[3];
+ struct msm_pcm_stream_app_type_cfg cfg_data = {0, 0, 48000};
int ret = 0;
- int app_type;
- int acdb_dev_id;
- int sample_rate = 48000;
- app_type = ucontrol->value.integer.value[0];
- acdb_dev_id = ucontrol->value.integer.value[1];
+ cfg_data.app_type = ucontrol->value.integer.value[0];
+ cfg_data.acdb_dev_id = ucontrol->value.integer.value[1];
if (ucontrol->value.integer.value[2] != 0)
- sample_rate = ucontrol->value.integer.value[2];
-
- ret = msm_pcm_routing_reg_stream_app_type_cfg(fe_id, session_type,
- be_id, app_type,
- acdb_dev_id, sample_rate);
- if (ret < 0)
- pr_err("%s: msm_pcm_playback_app_type_cfg_ctl_put failed, err %d\n",
- __func__, ret);
-
+ cfg_data.sample_rate = ucontrol->value.integer.value[2];
pr_debug("%s: fe_id- %llu session_type- %d be_id- %d app_type- %d acdb_dev_id- %d sample_rate- %d\n",
__func__, fe_id, session_type, be_id,
- app_type, acdb_dev_id, sample_rate);
+ cfg_data.app_type, cfg_data.acdb_dev_id, cfg_data.sample_rate);
+ ret = msm_pcm_routing_reg_stream_app_type_cfg(fe_id, session_type,
+ be_id, &cfg_data);
+ if (ret < 0)
+ pr_err("%s: msm_pcm_routing_reg_stream_app_type_cfg failed returned %d\n",
+ __func__, ret);
return ret;
}
@@ -870,29 +865,25 @@ static int msm_pcm_playback_app_type_cfg_ctl_get(struct snd_kcontrol *kcontrol,
{
u64 fe_id = kcontrol->private_value;
int session_type = SESSION_TYPE_RX;
- int be_id = ucontrol->value.integer.value[3];
+ int be_id = 0;
+ struct msm_pcm_stream_app_type_cfg cfg_data = {0};
int ret = 0;
- int app_type;
- int acdb_dev_id;
- int sample_rate;
ret = msm_pcm_routing_get_stream_app_type_cfg(fe_id, session_type,
- be_id, &app_type,
- &acdb_dev_id,
- &sample_rate);
+ &be_id, &cfg_data);
if (ret < 0) {
- pr_err("%s: msm_pcm_playback_app_type_cfg_ctl_get failed, err: %d\n",
- __func__, ret);
+ pr_err("%s: msm_pcm_routing_get_stream_app_type_cfg failed returned %d\n",
+ __func__, ret);
goto done;
}
- ucontrol->value.integer.value[0] = app_type;
- ucontrol->value.integer.value[1] = acdb_dev_id;
- ucontrol->value.integer.value[2] = sample_rate;
-
+ ucontrol->value.integer.value[0] = cfg_data.app_type;
+ ucontrol->value.integer.value[1] = cfg_data.acdb_dev_id;
+ ucontrol->value.integer.value[2] = cfg_data.sample_rate;
+ ucontrol->value.integer.value[3] = be_id;
pr_debug("%s: fedai_id %llu, session_type %d, be_id %d, app_type %d, acdb_dev_id %d, sample_rate %d\n",
__func__, fe_id, session_type, be_id,
- app_type, acdb_dev_id, sample_rate);
+ cfg_data.app_type, cfg_data.acdb_dev_id, cfg_data.sample_rate);
done:
return ret;
}
@@ -903,26 +894,21 @@ static int msm_pcm_capture_app_type_cfg_ctl_put(struct snd_kcontrol *kcontrol,
u64 fe_id = kcontrol->private_value;
int session_type = SESSION_TYPE_TX;
int be_id = ucontrol->value.integer.value[3];
+ struct msm_pcm_stream_app_type_cfg cfg_data = {0, 0, 48000};
int ret = 0;
- int app_type;
- int acdb_dev_id;
- int sample_rate = 48000;
- app_type = ucontrol->value.integer.value[0];
- acdb_dev_id = ucontrol->value.integer.value[1];
+ cfg_data.app_type = ucontrol->value.integer.value[0];
+ cfg_data.acdb_dev_id = ucontrol->value.integer.value[1];
if (ucontrol->value.integer.value[2] != 0)
- sample_rate = ucontrol->value.integer.value[2];
-
- ret = msm_pcm_routing_reg_stream_app_type_cfg(fe_id, session_type,
- be_id, app_type,
- acdb_dev_id, sample_rate);
- if (ret < 0)
- pr_err("%s: msm_pcm_capture_app_type_cfg_ctl_put failed, err: %d\n",
- __func__, ret);
-
+ cfg_data.sample_rate = ucontrol->value.integer.value[2];
pr_debug("%s: fe_id- %llu session_type- %d be_id- %d app_type- %d acdb_dev_id- %d sample_rate- %d\n",
__func__, fe_id, session_type, be_id,
- app_type, acdb_dev_id, sample_rate);
+ cfg_data.app_type, cfg_data.acdb_dev_id, cfg_data.sample_rate);
+ ret = msm_pcm_routing_reg_stream_app_type_cfg(fe_id, session_type,
+ be_id, &cfg_data);
+ if (ret < 0)
+ pr_err("%s: msm_pcm_routing_reg_stream_app_type_cfg failed returned %d\n",
+ __func__, ret);
return ret;
}
@@ -932,28 +918,25 @@ static int msm_pcm_capture_app_type_cfg_ctl_get(struct snd_kcontrol *kcontrol,
{
u64 fe_id = kcontrol->private_value;
int session_type = SESSION_TYPE_TX;
- int be_id = ucontrol->value.integer.value[3];
+ int be_id = 0;
+ struct msm_pcm_stream_app_type_cfg cfg_data = {0};
int ret = 0;
- int app_type;
- int acdb_dev_id;
- int sample_rate;
ret = msm_pcm_routing_get_stream_app_type_cfg(fe_id, session_type,
- be_id, &app_type,
- &acdb_dev_id,
- &sample_rate);
+ &be_id, &cfg_data);
if (ret < 0) {
- pr_err("%s: msm_pcm_capture_app_type_cfg_ctl_get failed, err: %d\n",
- __func__, ret);
+ pr_err("%s: msm_pcm_routing_get_stream_app_type_cfg failed returned %d\n",
+ __func__, ret);
goto done;
}
- ucontrol->value.integer.value[0] = app_type;
- ucontrol->value.integer.value[1] = acdb_dev_id;
- ucontrol->value.integer.value[2] = sample_rate;
+ ucontrol->value.integer.value[0] = cfg_data.app_type;
+ ucontrol->value.integer.value[1] = cfg_data.acdb_dev_id;
+ ucontrol->value.integer.value[2] = cfg_data.sample_rate;
+ ucontrol->value.integer.value[3] = be_id;
pr_debug("%s: fedai_id %llu, session_type %d, be_id %d, app_type %d, acdb_dev_id %d, sample_rate %d\n",
__func__, fe_id, session_type, be_id,
- app_type, acdb_dev_id, sample_rate);
+ cfg_data.app_type, cfg_data.acdb_dev_id, cfg_data.sample_rate);
done:
return ret;
}
diff --git a/sound/soc/msm/qdsp6v2/msm-pcm-q6-v2.c b/sound/soc/msm/qdsp6v2/msm-pcm-q6-v2.c
index 3be6567aefab..46a3324d2d6b 100644
--- a/sound/soc/msm/qdsp6v2/msm-pcm-q6-v2.c
+++ b/sound/soc/msm/qdsp6v2/msm-pcm-q6-v2.c
@@ -1556,21 +1556,18 @@ static int msm_pcm_playback_app_type_cfg_ctl_put(struct snd_kcontrol *kcontrol,
u64 fe_id = kcontrol->private_value;
int session_type = SESSION_TYPE_RX;
int be_id = ucontrol->value.integer.value[3];
+ struct msm_pcm_stream_app_type_cfg cfg_data = {0, 0, 48000};
int ret = 0;
- int app_type;
- int acdb_dev_id;
- int sample_rate = 48000;
- app_type = ucontrol->value.integer.value[0];
- acdb_dev_id = ucontrol->value.integer.value[1];
+ cfg_data.app_type = ucontrol->value.integer.value[0];
+ cfg_data.acdb_dev_id = ucontrol->value.integer.value[1];
if (ucontrol->value.integer.value[2] != 0)
- sample_rate = ucontrol->value.integer.value[2];
+ cfg_data.sample_rate = ucontrol->value.integer.value[2];
pr_debug("%s: fe_id- %llu session_type- %d be_id- %d app_type- %d acdb_dev_id- %d sample_rate- %d\n",
__func__, fe_id, session_type, be_id,
- app_type, acdb_dev_id, sample_rate);
+ cfg_data.app_type, cfg_data.acdb_dev_id, cfg_data.sample_rate);
ret = msm_pcm_routing_reg_stream_app_type_cfg(fe_id, session_type,
- be_id, app_type,
- acdb_dev_id, sample_rate);
+ be_id, &cfg_data);
if (ret < 0)
pr_err("%s: msm_pcm_routing_reg_stream_app_type_cfg failed returned %d\n",
__func__, ret);
@@ -1583,28 +1580,25 @@ static int msm_pcm_playback_app_type_cfg_ctl_get(struct snd_kcontrol *kcontrol,
{
u64 fe_id = kcontrol->private_value;
int session_type = SESSION_TYPE_RX;
- int be_id = ucontrol->value.integer.value[3];
+ int be_id = 0;
+ struct msm_pcm_stream_app_type_cfg cfg_data = {0};
int ret = 0;
- int app_type;
- int acdb_dev_id;
- int sample_rate;
ret = msm_pcm_routing_get_stream_app_type_cfg(fe_id, session_type,
- be_id, &app_type,
- &acdb_dev_id,
- &sample_rate);
+ &be_id, &cfg_data);
if (ret < 0) {
pr_err("%s: msm_pcm_routing_get_stream_app_type_cfg failed returned %d\n",
__func__, ret);
goto done;
}
- ucontrol->value.integer.value[0] = app_type;
- ucontrol->value.integer.value[1] = acdb_dev_id;
- ucontrol->value.integer.value[2] = sample_rate;
+ ucontrol->value.integer.value[0] = cfg_data.app_type;
+ ucontrol->value.integer.value[1] = cfg_data.acdb_dev_id;
+ ucontrol->value.integer.value[2] = cfg_data.sample_rate;
+ ucontrol->value.integer.value[3] = be_id;
pr_debug("%s: fedai_id %llu, session_type %d, be_id %d, app_type %d, acdb_dev_id %d, sample_rate %d\n",
__func__, fe_id, session_type, be_id,
- app_type, acdb_dev_id, sample_rate);
+ cfg_data.app_type, cfg_data.acdb_dev_id, cfg_data.sample_rate);
done:
return ret;
}
@@ -1615,21 +1609,18 @@ static int msm_pcm_capture_app_type_cfg_ctl_put(struct snd_kcontrol *kcontrol,
u64 fe_id = kcontrol->private_value;
int session_type = SESSION_TYPE_TX;
int be_id = ucontrol->value.integer.value[3];
+ struct msm_pcm_stream_app_type_cfg cfg_data = {0, 0, 48000};
int ret = 0;
- int app_type;
- int acdb_dev_id;
- int sample_rate = 48000;
- app_type = ucontrol->value.integer.value[0];
- acdb_dev_id = ucontrol->value.integer.value[1];
+ cfg_data.app_type = ucontrol->value.integer.value[0];
+ cfg_data.acdb_dev_id = ucontrol->value.integer.value[1];
if (ucontrol->value.integer.value[2] != 0)
- sample_rate = ucontrol->value.integer.value[2];
+ cfg_data.sample_rate = ucontrol->value.integer.value[2];
pr_debug("%s: fe_id- %llu session_type- %d be_id- %d app_type- %d acdb_dev_id- %d sample_rate- %d\n",
__func__, fe_id, session_type, be_id,
- app_type, acdb_dev_id, sample_rate);
+ cfg_data.app_type, cfg_data.acdb_dev_id, cfg_data.sample_rate);
ret = msm_pcm_routing_reg_stream_app_type_cfg(fe_id, session_type,
- be_id, app_type,
- acdb_dev_id, sample_rate);
+ be_id, &cfg_data);
if (ret < 0)
pr_err("%s: msm_pcm_routing_reg_stream_app_type_cfg failed returned %d\n",
__func__, ret);
@@ -1642,28 +1633,25 @@ static int msm_pcm_capture_app_type_cfg_ctl_get(struct snd_kcontrol *kcontrol,
{
u64 fe_id = kcontrol->private_value;
int session_type = SESSION_TYPE_TX;
- int be_id = ucontrol->value.integer.value[3];
+ int be_id = 0;
+ struct msm_pcm_stream_app_type_cfg cfg_data = {0};
int ret = 0;
- int app_type;
- int acdb_dev_id;
- int sample_rate;
ret = msm_pcm_routing_get_stream_app_type_cfg(fe_id, session_type,
- be_id, &app_type,
- &acdb_dev_id,
- &sample_rate);
+ &be_id, &cfg_data);
if (ret < 0) {
pr_err("%s: msm_pcm_routing_get_stream_app_type_cfg failed returned %d\n",
__func__, ret);
goto done;
}
- ucontrol->value.integer.value[0] = app_type;
- ucontrol->value.integer.value[1] = acdb_dev_id;
- ucontrol->value.integer.value[2] = sample_rate;
+ ucontrol->value.integer.value[0] = cfg_data.app_type;
+ ucontrol->value.integer.value[1] = cfg_data.acdb_dev_id;
+ ucontrol->value.integer.value[2] = cfg_data.sample_rate;
+ ucontrol->value.integer.value[3] = be_id;
pr_debug("%s: fedai_id %llu, session_type %d, be_id %d, app_type %d, acdb_dev_id %d, sample_rate %d\n",
__func__, fe_id, session_type, be_id,
- app_type, acdb_dev_id, sample_rate);
+ cfg_data.app_type, cfg_data.acdb_dev_id, cfg_data.sample_rate);
done:
return ret;
}
diff --git a/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c b/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c
index 32f68fedcd3b..f41c6107aac8 100644
--- a/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c
+++ b/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c
@@ -675,6 +675,8 @@ static struct msm_pcm_routing_app_type_data lsm_app_type_cfg[MAX_APP_TYPES];
static struct msm_pcm_stream_app_type_cfg
fe_dai_app_type_cfg[MSM_FRONTEND_DAI_MAX][2][MSM_BACKEND_DAI_MAX];
+static int last_be_id_configured[MSM_FRONTEND_DAI_MAX][MAX_SESSION_TYPES];
+
/* The caller of this should aqcuire routing lock */
void msm_pcm_routing_get_bedai_info(int be_idx,
struct msm_pcm_routing_bdai_data *be_dai)
@@ -741,15 +743,22 @@ static bool is_mm_lsm_fe_id(int fe_id)
return rc;
}
-int msm_pcm_routing_reg_stream_app_type_cfg(int fedai_id, int session_type,
- int be_id, int app_type,
- int acdb_dev_id, int sample_rate)
+int msm_pcm_routing_reg_stream_app_type_cfg(
+ int fedai_id, int session_type, int be_id,
+ struct msm_pcm_stream_app_type_cfg *cfg_data)
{
int ret = 0;
+ if (cfg_data == NULL) {
+ pr_err("%s: Received NULL pointer for cfg_data\n", __func__);
+ ret = -EINVAL;
+ goto done;
+ }
+
pr_debug("%s: fedai_id %d, session_type %d, be_id %d, app_type %d, acdb_dev_id %d, sample_rate %d\n",
__func__, fedai_id, session_type, be_id,
- app_type, acdb_dev_id, sample_rate);
+ cfg_data->app_type, cfg_data->acdb_dev_id,
+ cfg_data->sample_rate);
if (!is_mm_lsm_fe_id(fedai_id)) {
pr_err("%s: Invalid machine driver ID %d\n",
@@ -771,15 +780,18 @@ int msm_pcm_routing_reg_stream_app_type_cfg(int fedai_id, int session_type,
goto done;
}
- fe_dai_app_type_cfg[fedai_id][session_type][be_id].app_type = app_type;
- fe_dai_app_type_cfg[fedai_id][session_type][be_id].acdb_dev_id =
- acdb_dev_id;
- fe_dai_app_type_cfg[fedai_id][session_type][be_id].sample_rate =
- sample_rate;
+ fe_dai_app_type_cfg[fedai_id][session_type][be_id] = *cfg_data;
+
+ /*
+ * Store the BE ID of the configuration information set as the latest so
+ * the get mixer control knows what to return.
+ */
+ last_be_id_configured[fedai_id][session_type] = be_id;
done:
return ret;
}
+EXPORT_SYMBOL(msm_pcm_routing_reg_stream_app_type_cfg);
/**
* msm_pcm_routing_get_stream_app_type_cfg
@@ -791,55 +803,48 @@ done:
* fedai_id - Passed value, front end ID for which app type config is wanted
* session_type - Passed value, session type for which app type config
* is wanted
- * be_id - Passed value, back end device id for which app type config is wanted
- * app_type - Returned value, app type used by app type config
- * acdb_dev_id - Returned value, ACDB device ID used by app type config
- * sample_rate - Returned value, sample rate used by app type config
+ * be_id - Returned value, back end device id the app type config data is for
+ * cfg_data - Returned value, configuration data used by app type config
*/
-int msm_pcm_routing_get_stream_app_type_cfg(int fedai_id, int session_type,
- int be_id, int *app_type,
- int *acdb_dev_id, int *sample_rate)
+int msm_pcm_routing_get_stream_app_type_cfg(
+ int fedai_id, int session_type, int *bedai_id,
+ struct msm_pcm_stream_app_type_cfg *cfg_data)
{
+ int be_id;
int ret = 0;
- if (app_type == NULL) {
- pr_err("%s: NULL pointer sent for app_type\n", __func__);
+ if (bedai_id == NULL) {
+ pr_err("%s: Received NULL pointer for backend ID\n", __func__);
ret = -EINVAL;
goto done;
- } else if (acdb_dev_id == NULL) {
- pr_err("%s: NULL pointer sent for acdb_dev_id\n", __func__);
- ret = -EINVAL;
- goto done;
- } else if (sample_rate == NULL) {
- pr_err("%s: NULL pointer sent for sample rate\n", __func__);
+ } else if (cfg_data == NULL) {
+ pr_err("%s: NULL pointer sent for cfg_data\n", __func__);
ret = -EINVAL;
goto done;
} else if (!is_mm_lsm_fe_id(fedai_id)) {
- pr_err("%s: Invalid FE ID %d\n",
- __func__, fedai_id);
+ pr_err("%s: Invalid FE ID %d\n", __func__, fedai_id);
ret = -EINVAL;
goto done;
} else if (session_type != SESSION_TYPE_RX &&
session_type != SESSION_TYPE_TX) {
- pr_err("%s: Invalid session type %d\n",
- __func__, session_type);
+ pr_err("%s: Invalid session type %d\n", __func__, session_type);
ret = -EINVAL;
goto done;
- } else if (be_id < 0 || be_id >= MSM_BACKEND_DAI_MAX) {
- pr_err("%s: Received out of bounds be_id %d\n",
- __func__, be_id);
- return -EINVAL;
}
- *app_type = fe_dai_app_type_cfg[fedai_id][session_type][be_id].app_type;
- *acdb_dev_id =
- fe_dai_app_type_cfg[fedai_id][session_type][be_id].acdb_dev_id;
- *sample_rate =
- fe_dai_app_type_cfg[fedai_id][session_type][be_id].sample_rate;
+ be_id = last_be_id_configured[fedai_id][session_type];
+ if (be_id < 0 || be_id >= MSM_BACKEND_DAI_MAX) {
+ pr_err("%s: Invalid BE ID %d\n", __func__, be_id);
+ ret = -EINVAL;
+ goto done;
+ }
+ *bedai_id = be_id;
+ *cfg_data = fe_dai_app_type_cfg[fedai_id][session_type][be_id];
pr_debug("%s: fedai_id %d, session_type %d, be_id %d, app_type %d, acdb_dev_id %d, sample_rate %d\n",
- __func__, fedai_id, session_type, be_id,
- *app_type, *acdb_dev_id, *sample_rate);
+ __func__, fedai_id, session_type, *bedai_id,
+ cfg_data->app_type, cfg_data->acdb_dev_id,
+ cfg_data->sample_rate);
done:
return ret;
}
@@ -1077,7 +1082,10 @@ int msm_pcm_routing_reg_phy_compr_stream(int fe_id, int perf_mode,
port_type = MSM_AFE_PORT_TYPE_RX;
} else if (stream_type == SNDRV_PCM_STREAM_CAPTURE) {
session_type = SESSION_TYPE_TX;
- path_type = ADM_PATH_LIVE_REC;
+ if (passthr_mode != LEGACY_PCM)
+ path_type = ADM_PATH_COMPRESSED_TX;
+ else
+ path_type = ADM_PATH_LIVE_REC;
port_type = MSM_AFE_PORT_TYPE_TX;
} else {
pr_err("%s: invalid stream type %d\n", __func__, stream_type);
@@ -1514,7 +1522,10 @@ static void msm_pcm_routing_process_audio(u16 reg, u16 val, int set)
path_type = ADM_PATH_PLAYBACK;
} else {
session_type = SESSION_TYPE_TX;
- path_type = ADM_PATH_LIVE_REC;
+ if (passthr_mode != LEGACY_PCM)
+ path_type = ADM_PATH_COMPRESSED_TX;
+ else
+ path_type = ADM_PATH_LIVE_REC;
}
is_lsm = (val >= MSM_FRONTEND_DAI_LSM1) &&
(val <= MSM_FRONTEND_DAI_LSM8);
@@ -6449,6 +6460,9 @@ static const struct snd_kcontrol_new mmul18_mixer_controls[] = {
SOC_SINGLE_EXT("PRI_MI2S_TX", MSM_BACKEND_DAI_PRI_MI2S_TX,
MSM_FRONTEND_DAI_MULTIMEDIA18, 1, 0, msm_routing_get_audio_mixer,
msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("QUAT_MI2S_TX", MSM_BACKEND_DAI_QUATERNARY_MI2S_TX,
+ MSM_FRONTEND_DAI_MULTIMEDIA18, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
SOC_SINGLE_EXT("INTERNAL_FM_TX", MSM_BACKEND_DAI_INT_FM_TX,
MSM_FRONTEND_DAI_MULTIMEDIA18, 1, 0, msm_routing_get_audio_mixer,
msm_routing_put_audio_mixer),
@@ -11913,6 +11927,7 @@ static const struct snd_soc_dapm_route intercon[] = {
{"MultiMedia18 Mixer", "PRI_MI2S_TX", "PRI_MI2S_TX"},
{"MultiMedia19 Mixer", "PRI_MI2S_TX", "PRI_MI2S_TX"},
{"MultiMedia8 Mixer", "PRI_MI2S_TX", "PRI_MI2S_TX"},
+ {"MultiMedia18 Mixer", "QUAT_MI2S_TX", "QUAT_MI2S_TX"},
{"MultiMedia8 Mixer", "INT3_MI2S_TX", "INT3_MI2S_TX"},
{"MultiMedia3 Mixer", "SLIM_0_TX", "SLIMBUS_0_TX"},
{"MultiMedia5 Mixer", "SLIM_0_TX", "SLIMBUS_0_TX"},
@@ -14948,6 +14963,7 @@ static int __init msm_soc_routing_platform_init(void)
(routing_cb)msm_pcm_get_dev_acdb_id_by_port_id);
memset(&be_dai_name_table, 0, sizeof(be_dai_name_table));
+ memset(&last_be_id_configured, 0, sizeof(last_be_id_configured));
return platform_driver_register(&msm_routing_pcm_driver);
}
diff --git a/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.h b/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.h
index 234d57ca1c40..19e726001d25 100644
--- a/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.h
+++ b/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.h
@@ -385,6 +385,7 @@ enum {
#define INVALID_SESSION -1
#define SESSION_TYPE_RX 0
#define SESSION_TYPE_TX 1
+#define MAX_SESSION_TYPES 2
#define INT_RX_VOL_MAX_STEPS 0x2000
#define INT_RX_VOL_GAIN 0x2000
@@ -476,10 +477,10 @@ void msm_pcm_routing_get_fedai_info(int fe_idx, int sess_type,
void msm_pcm_routing_acquire_lock(void);
void msm_pcm_routing_release_lock(void);
-int msm_pcm_routing_reg_stream_app_type_cfg(int fedai_id, int session_type,
- int be_id, int app_type,
- int acdb_dev_id, int sample_rate);
-int msm_pcm_routing_get_stream_app_type_cfg(int fedai_id, int session_type,
- int be_id, int *app_type,
- int *acdb_dev_id, int *sample_rate);
+int msm_pcm_routing_reg_stream_app_type_cfg(
+ int fedai_id, int session_type, int be_id,
+ struct msm_pcm_stream_app_type_cfg *cfg_data);
+int msm_pcm_routing_get_stream_app_type_cfg(
+ int fedai_id, int session_type, int *be_id,
+ struct msm_pcm_stream_app_type_cfg *cfg_data);
#endif /*_MSM_PCM_H*/
diff --git a/sound/soc/msm/qdsp6v2/msm-transcode-loopback-q6-v2.c b/sound/soc/msm/qdsp6v2/msm-transcode-loopback-q6-v2.c
new file mode 100644
index 000000000000..dbda90c3616d
--- /dev/null
+++ b/sound/soc/msm/qdsp6v2/msm-transcode-loopback-q6-v2.c
@@ -0,0 +1,971 @@
+/* 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 <linux/init.h>
+#include <linux/err.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/time.h>
+#include <linux/math64.h>
+#include <linux/wait.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/msm_audio_ion.h>
+#include <sound/core.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+#include <sound/pcm.h>
+#include <sound/initval.h>
+#include <sound/control.h>
+#include <sound/q6asm-v2.h>
+#include <sound/pcm_params.h>
+#include <sound/timer.h>
+#include <sound/tlv.h>
+#include <sound/apr_audio-v2.h>
+#include <sound/compress_params.h>
+#include <sound/compress_offload.h>
+#include <sound/compress_driver.h>
+#include <linux/msm_audio.h>
+
+#include "msm-pcm-routing-v2.h"
+#include "msm-qti-pp-config.h"
+
+#define LOOPBACK_SESSION_MAX_NUM_STREAMS 2
+
+static DEFINE_MUTEX(transcode_loopback_session_lock);
+
+struct trans_loopback_pdata {
+ struct snd_compr_stream *cstream[MSM_FRONTEND_DAI_MAX];
+};
+
+struct loopback_stream {
+ struct snd_compr_stream *cstream;
+ uint32_t codec_format;
+ bool start;
+};
+
+enum loopback_session_state {
+ /* One or both streams not opened */
+ LOOPBACK_SESSION_CLOSE = 0,
+ /* Loopback streams opened */
+ LOOPBACK_SESSION_READY,
+ /* Loopback streams opened and formats configured */
+ LOOPBACK_SESSION_START,
+ /* Trigger issued on either of streams when in START state */
+ LOOPBACK_SESSION_RUN
+};
+
+struct msm_transcode_loopback {
+ struct loopback_stream source;
+ struct loopback_stream sink;
+
+ struct snd_compr_caps source_compr_cap;
+ struct snd_compr_caps sink_compr_cap;
+
+ uint32_t instance;
+ uint32_t num_streams;
+ int session_state;
+
+ struct mutex lock;
+
+ int session_id;
+ struct audio_client *audio_client;
+};
+
+/* Transcode loopback global info struct */
+static struct msm_transcode_loopback transcode_info;
+
+static void loopback_event_handler(uint32_t opcode,
+ uint32_t token, uint32_t *payload, void *priv)
+{
+ struct msm_transcode_loopback *trans =
+ (struct msm_transcode_loopback *)priv;
+ struct snd_soc_pcm_runtime *rtd;
+ struct snd_compr_stream *cstream;
+ struct audio_client *ac;
+ int stream_id;
+ int ret;
+
+ if (!trans || !payload) {
+ pr_err("%s: rtd or payload is NULL\n", __func__);
+ return;
+ }
+
+ cstream = trans->source.cstream;
+ ac = trans->audio_client;
+
+ /*
+ * Token for rest of the compressed commands use to set
+ * session id, stream id, dir etc.
+ */
+ stream_id = q6asm_get_stream_id_from_token(token);
+
+ switch (opcode) {
+ case ASM_STREAM_CMD_ENCDEC_EVENTS:
+ case ASM_IEC_61937_MEDIA_FMT_EVENT:
+ pr_debug("%s: ASM_IEC_61937_MEDIA_FMT_EVENT\n", __func__);
+ rtd = cstream->private_data;
+ if (!rtd) {
+ pr_err("%s: rtd is NULL\n", __func__);
+ return;
+ }
+
+ ret = msm_adsp_inform_mixer_ctl(rtd, payload);
+ if (ret) {
+ pr_err("%s: failed to inform mixer ctrl. err = %d\n",
+ __func__, ret);
+ return;
+ }
+ break;
+ case APR_BASIC_RSP_RESULT: {
+ switch (payload[0]) {
+ case ASM_SESSION_CMD_RUN_V2:
+ pr_debug("%s: ASM_SESSION_CMD_RUN_V2:", __func__);
+ pr_debug("token 0x%x, stream id %d\n", token,
+ stream_id);
+ break;
+ case ASM_STREAM_CMD_CLOSE:
+ pr_debug("%s: ASM_DATA_CMD_CLOSE:", __func__);
+ pr_debug("token 0x%x, stream id %d\n", token,
+ stream_id);
+ break;
+ default:
+ break;
+ }
+ break;
+ }
+ default:
+ pr_debug("%s: Not Supported Event opcode[0x%x]\n",
+ __func__, opcode);
+ break;
+ }
+}
+
+static void populate_codec_list(struct msm_transcode_loopback *trans,
+ struct snd_compr_stream *cstream)
+{
+ struct snd_compr_caps compr_cap;
+
+ pr_debug("%s\n", __func__);
+
+ memset(&compr_cap, 0, sizeof(struct snd_compr_caps));
+
+ if (cstream->direction == SND_COMPRESS_CAPTURE) {
+ compr_cap.direction = SND_COMPRESS_CAPTURE;
+ compr_cap.num_codecs = 3;
+ compr_cap.codecs[0] = SND_AUDIOCODEC_PCM;
+ compr_cap.codecs[1] = SND_AUDIOCODEC_AC3;
+ compr_cap.codecs[2] = SND_AUDIOCODEC_EAC3;
+ memcpy(&trans->source_compr_cap, &compr_cap,
+ sizeof(struct snd_compr_caps));
+ }
+
+ if (cstream->direction == SND_COMPRESS_PLAYBACK) {
+ compr_cap.direction = SND_COMPRESS_PLAYBACK;
+ compr_cap.num_codecs = 1;
+ compr_cap.codecs[0] = SND_AUDIOCODEC_PCM;
+ memcpy(&trans->sink_compr_cap, &compr_cap,
+ sizeof(struct snd_compr_caps));
+ }
+}
+
+static int msm_transcode_loopback_open(struct snd_compr_stream *cstream)
+{
+ int ret = 0;
+ struct snd_compr_runtime *runtime;
+ struct snd_soc_pcm_runtime *rtd;
+ struct msm_transcode_loopback *trans = &transcode_info;
+ struct trans_loopback_pdata *pdata;
+
+ if (cstream == NULL) {
+ pr_err("%s: Invalid substream\n", __func__);
+ return -EINVAL;
+ }
+ runtime = cstream->runtime;
+ rtd = snd_pcm_substream_chip(cstream);
+ pdata = snd_soc_platform_get_drvdata(rtd->platform);
+ pdata->cstream[rtd->dai_link->be_id] = cstream;
+
+ mutex_lock(&trans->lock);
+ if (trans->num_streams > LOOPBACK_SESSION_MAX_NUM_STREAMS) {
+ pr_err("msm_transcode_open failed..invalid stream\n");
+ ret = -EINVAL;
+ goto exit;
+ }
+
+ if (cstream->direction == SND_COMPRESS_CAPTURE) {
+ if (trans->source.cstream == NULL) {
+ trans->source.cstream = cstream;
+ trans->num_streams++;
+ } else {
+ pr_err("%s: capture stream already opened\n",
+ __func__);
+ ret = -EINVAL;
+ goto exit;
+ }
+ } else if (cstream->direction == SND_COMPRESS_PLAYBACK) {
+ if (trans->sink.cstream == NULL) {
+ trans->sink.cstream = cstream;
+ trans->num_streams++;
+ } else {
+ pr_debug("%s: playback stream already opened\n",
+ __func__);
+ ret = -EINVAL;
+ goto exit;
+ }
+ }
+
+ pr_debug("%s: num stream%d, stream name %s\n", __func__,
+ trans->num_streams, cstream->name);
+
+ populate_codec_list(trans, cstream);
+
+ if (trans->num_streams == LOOPBACK_SESSION_MAX_NUM_STREAMS) {
+ pr_debug("%s: Moving loopback session to READY state %d\n",
+ __func__, trans->session_state);
+ trans->session_state = LOOPBACK_SESSION_READY;
+ }
+
+ runtime->private_data = trans;
+ if (trans->num_streams == 1)
+ msm_adsp_init_mixer_ctl_pp_event_queue(rtd);
+exit:
+ mutex_unlock(&trans->lock);
+ return ret;
+}
+
+static void stop_transcoding(struct msm_transcode_loopback *trans)
+{
+ struct snd_soc_pcm_runtime *soc_pcm_rx;
+ struct snd_soc_pcm_runtime *soc_pcm_tx;
+
+ if (trans->audio_client != NULL) {
+ q6asm_cmd(trans->audio_client, CMD_CLOSE);
+
+ if (trans->sink.cstream != NULL) {
+ soc_pcm_rx = trans->sink.cstream->private_data;
+ msm_pcm_routing_dereg_phy_stream(
+ soc_pcm_rx->dai_link->be_id,
+ SND_COMPRESS_PLAYBACK);
+ }
+ if (trans->source.cstream != NULL) {
+ soc_pcm_tx = trans->source.cstream->private_data;
+ msm_pcm_routing_dereg_phy_stream(
+ soc_pcm_tx->dai_link->be_id,
+ SND_COMPRESS_CAPTURE);
+ }
+ q6asm_audio_client_free(trans->audio_client);
+ trans->audio_client = NULL;
+ }
+}
+
+static int msm_transcode_loopback_free(struct snd_compr_stream *cstream)
+{
+ struct snd_compr_runtime *runtime = cstream->runtime;
+ struct msm_transcode_loopback *trans = runtime->private_data;
+ struct snd_soc_pcm_runtime *rtd = snd_pcm_substream_chip(cstream);
+ int ret = 0;
+
+ mutex_lock(&trans->lock);
+
+ pr_debug("%s: Transcode loopback end:%d, streams %d\n", __func__,
+ cstream->direction, trans->num_streams);
+ trans->num_streams--;
+ stop_transcoding(trans);
+
+ if (cstream->direction == SND_COMPRESS_PLAYBACK)
+ memset(&trans->sink, 0, sizeof(struct loopback_stream));
+ else if (cstream->direction == SND_COMPRESS_CAPTURE)
+ memset(&trans->source, 0, sizeof(struct loopback_stream));
+
+ trans->session_state = LOOPBACK_SESSION_CLOSE;
+ if (trans->num_streams == 1)
+ msm_adsp_clean_mixer_ctl_pp_event_queue(rtd);
+ mutex_unlock(&trans->lock);
+ return ret;
+}
+
+static int msm_transcode_loopback_trigger(struct snd_compr_stream *cstream,
+ int cmd)
+{
+ struct snd_compr_runtime *runtime = cstream->runtime;
+ struct msm_transcode_loopback *trans = runtime->private_data;
+
+ switch (cmd) {
+ case SNDRV_PCM_TRIGGER_START:
+ case SNDRV_PCM_TRIGGER_RESUME:
+ case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+
+ if (trans->session_state == LOOPBACK_SESSION_START) {
+ pr_debug("%s: Issue Loopback session %d RUN\n",
+ __func__, trans->instance);
+ q6asm_run_nowait(trans->audio_client, 0, 0, 0);
+ trans->session_state = LOOPBACK_SESSION_RUN;
+ }
+ break;
+ case SNDRV_PCM_TRIGGER_SUSPEND:
+ case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+ case SNDRV_PCM_TRIGGER_STOP:
+ pr_debug("%s: Issue Loopback session %d STOP\n", __func__,
+ trans->instance);
+ if (trans->session_state == LOOPBACK_SESSION_RUN)
+ q6asm_cmd_nowait(trans->audio_client, CMD_PAUSE);
+ trans->session_state = LOOPBACK_SESSION_START;
+ break;
+
+ default:
+ break;
+ }
+ return 0;
+}
+
+static int msm_transcode_loopback_set_params(struct snd_compr_stream *cstream,
+ struct snd_compr_params *codec_param)
+{
+
+ struct snd_compr_runtime *runtime = cstream->runtime;
+ struct msm_transcode_loopback *trans = runtime->private_data;
+ struct snd_soc_pcm_runtime *soc_pcm_rx;
+ struct snd_soc_pcm_runtime *soc_pcm_tx;
+ uint32_t bit_width = 16;
+ int ret = 0;
+
+ if (trans == NULL) {
+ pr_err("%s: Invalid param\n", __func__);
+ return -EINVAL;
+ }
+
+ mutex_lock(&trans->lock);
+
+ if (cstream->direction == SND_COMPRESS_PLAYBACK) {
+ if (codec_param->codec.id == SND_AUDIOCODEC_PCM) {
+ trans->sink.codec_format =
+ FORMAT_LINEAR_PCM;
+ switch (codec_param->codec.format) {
+ case SNDRV_PCM_FORMAT_S32_LE:
+ bit_width = 32;
+ break;
+ case SNDRV_PCM_FORMAT_S24_LE:
+ bit_width = 24;
+ break;
+ case SNDRV_PCM_FORMAT_S24_3LE:
+ bit_width = 24;
+ break;
+ case SNDRV_PCM_FORMAT_S16_LE:
+ default:
+ bit_width = 16;
+ break;
+ }
+ } else {
+ pr_debug("%s: unknown sink codec\n", __func__);
+ ret = -EINVAL;
+ goto exit;
+ }
+ trans->sink.start = true;
+ }
+
+ if (cstream->direction == SND_COMPRESS_CAPTURE) {
+ switch (codec_param->codec.id) {
+ case SND_AUDIOCODEC_PCM:
+ pr_debug("Source SND_AUDIOCODEC_PCM\n");
+ trans->source.codec_format =
+ FORMAT_LINEAR_PCM;
+ break;
+ case SND_AUDIOCODEC_AC3:
+ pr_debug("Source SND_AUDIOCODEC_AC3\n");
+ trans->source.codec_format =
+ FORMAT_AC3;
+ break;
+ case SND_AUDIOCODEC_EAC3:
+ pr_debug("Source SND_AUDIOCODEC_EAC3\n");
+ trans->source.codec_format =
+ FORMAT_EAC3;
+ break;
+ default:
+ pr_debug("%s: unknown source codec\n", __func__);
+ ret = -EINVAL;
+ goto exit;
+ }
+ trans->source.start = true;
+ }
+
+ pr_debug("%s: trans->source.start %d trans->sink.start %d trans->source.cstream %pK trans->sink.cstream %pK trans->session_state %d\n",
+ __func__, trans->source.start, trans->sink.start,
+ trans->source.cstream, trans->sink.cstream,
+ trans->session_state);
+
+ if ((trans->session_state == LOOPBACK_SESSION_READY) &&
+ trans->source.start && trans->sink.start) {
+ pr_debug("%s: Moving loopback session to start state\n",
+ __func__);
+ trans->session_state = LOOPBACK_SESSION_START;
+ }
+
+ if (trans->session_state == LOOPBACK_SESSION_START) {
+ if (trans->audio_client != NULL) {
+ pr_debug("%s: ASM client already opened, closing\n",
+ __func__);
+ stop_transcoding(trans);
+ }
+
+ trans->audio_client = q6asm_audio_client_alloc(
+ (app_cb)loopback_event_handler, trans);
+ if (!trans->audio_client) {
+ pr_err("%s: Could not allocate memory\n", __func__);
+ ret = -EINVAL;
+ goto exit;
+ }
+ pr_debug("%s: ASM client allocated, callback %pK\n", __func__,
+ loopback_event_handler);
+ trans->session_id = trans->audio_client->session;
+ trans->audio_client->perf_mode = false;
+ ret = q6asm_open_transcode_loopback(trans->audio_client,
+ bit_width,
+ trans->source.codec_format,
+ trans->sink.codec_format);
+ if (ret < 0) {
+ pr_err("%s: Session transcode loopback open failed\n",
+ __func__);
+ q6asm_audio_client_free(trans->audio_client);
+ trans->audio_client = NULL;
+ goto exit;
+ }
+
+ pr_debug("%s: Starting ADM open for loopback\n", __func__);
+ soc_pcm_rx = trans->sink.cstream->private_data;
+ soc_pcm_tx = trans->source.cstream->private_data;
+ if (trans->source.codec_format != FORMAT_LINEAR_PCM)
+ msm_pcm_routing_reg_phy_compr_stream(
+ soc_pcm_tx->dai_link->be_id,
+ trans->audio_client->perf_mode,
+ trans->session_id,
+ SNDRV_PCM_STREAM_CAPTURE,
+ true);
+ else
+ msm_pcm_routing_reg_phy_stream(
+ soc_pcm_tx->dai_link->be_id,
+ trans->audio_client->perf_mode,
+ trans->session_id,
+ SNDRV_PCM_STREAM_CAPTURE);
+
+ msm_pcm_routing_reg_phy_stream(
+ soc_pcm_rx->dai_link->be_id,
+ trans->audio_client->perf_mode,
+ trans->session_id,
+ SNDRV_PCM_STREAM_PLAYBACK);
+ pr_debug("%s: Successfully opened ADM sessions\n", __func__);
+ }
+exit:
+ mutex_unlock(&trans->lock);
+ return ret;
+}
+
+static int msm_transcode_loopback_get_caps(struct snd_compr_stream *cstream,
+ struct snd_compr_caps *arg)
+{
+ struct snd_compr_runtime *runtime;
+ struct msm_transcode_loopback *trans;
+
+ if (!arg || !cstream) {
+ pr_err("%s: Invalid arguments\n", __func__);
+ return -EINVAL;
+ }
+
+ runtime = cstream->runtime;
+ trans = runtime->private_data;
+ pr_debug("%s\n", __func__);
+ if (cstream->direction == SND_COMPRESS_CAPTURE)
+ memcpy(arg, &trans->source_compr_cap,
+ sizeof(struct snd_compr_caps));
+ else
+ memcpy(arg, &trans->sink_compr_cap,
+ sizeof(struct snd_compr_caps));
+ return 0;
+}
+
+static int msm_transcode_stream_cmd_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *comp = snd_kcontrol_chip(kcontrol);
+ unsigned long fe_id = kcontrol->private_value;
+ struct trans_loopback_pdata *pdata = (struct trans_loopback_pdata *)
+ snd_soc_component_get_drvdata(comp);
+ struct snd_compr_stream *cstream = NULL;
+ struct msm_transcode_loopback *prtd;
+ int ret = 0;
+ struct msm_adsp_event_data *event_data = NULL;
+
+ if (fe_id >= MSM_FRONTEND_DAI_MAX) {
+ pr_err("%s Received 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;
+ }
+
+ event_data = (struct msm_adsp_event_data *)ucontrol->value.bytes.data;
+ if ((event_data->event_type < ADSP_STREAM_PP_EVENT) ||
+ (event_data->event_type >= ADSP_STREAM_EVENT_MAX)) {
+ pr_err("%s: invalid event_type=%d",
+ __func__, event_data->event_type);
+ ret = -EINVAL;
+ goto done;
+ }
+
+ if ((sizeof(struct msm_adsp_event_data) + event_data->payload_len) >=
+ sizeof(ucontrol->value.bytes.data)) {
+ pr_err("%s param length=%d exceeds limit",
+ __func__, event_data->payload_len);
+ ret = -EINVAL;
+ goto done;
+ }
+
+ ret = q6asm_send_stream_cmd(prtd->audio_client, event_data);
+ if (ret < 0)
+ pr_err("%s: failed to send stream event cmd, err = %d\n",
+ __func__, ret);
+done:
+ return ret;
+}
+
+static int msm_transcode_ion_fd_map_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *comp = snd_kcontrol_chip(kcontrol);
+ unsigned long fe_id = kcontrol->private_value;
+ struct trans_loopback_pdata *pdata = (struct trans_loopback_pdata *)
+ snd_soc_component_get_drvdata(comp);
+ struct snd_compr_stream *cstream = NULL;
+ struct msm_transcode_loopback *prtd;
+ int fd;
+ int ret = 0;
+
+ 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;
+ }
+
+ memcpy(&fd, ucontrol->value.bytes.data, sizeof(fd));
+ ret = q6asm_send_ion_fd(prtd->audio_client, fd);
+ if (ret < 0)
+ pr_err("%s: failed to register ion fd\n", __func__);
+done:
+ return ret;
+}
+
+static int msm_transcode_rtic_event_ack_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *comp = snd_kcontrol_chip(kcontrol);
+ unsigned long fe_id = kcontrol->private_value;
+ struct trans_loopback_pdata *pdata = (struct trans_loopback_pdata *)
+ snd_soc_component_get_drvdata(comp);
+ struct snd_compr_stream *cstream = NULL;
+ struct msm_transcode_loopback *prtd;
+ int ret = 0;
+ int param_length = 0;
+
+ if (fe_id >= MSM_FRONTEND_DAI_MAX) {
+ pr_err("%s Received 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;
+ }
+
+ memcpy(&param_length, ucontrol->value.bytes.data,
+ sizeof(param_length));
+ if ((param_length + sizeof(param_length))
+ >= sizeof(ucontrol->value.bytes.data)) {
+ pr_err("%s param length=%d exceeds limit",
+ __func__, param_length);
+ ret = -EINVAL;
+ goto done;
+ }
+
+ ret = q6asm_send_rtic_event_ack(prtd->audio_client,
+ ucontrol->value.bytes.data + sizeof(param_length),
+ param_length);
+ if (ret < 0)
+ pr_err("%s: failed to send rtic event ack, err = %d\n",
+ __func__, ret);
+done:
+ return ret;
+}
+
+static int msm_transcode_stream_cmd_control(
+ struct snd_soc_pcm_runtime *rtd)
+{
+ const char *mixer_ctl_name = DSP_STREAM_CMD;
+ const char *deviceNo = "NN";
+ char *mixer_str = NULL;
+ int ctl_len = 0, ret = 0;
+ struct snd_kcontrol_new fe_loopback_stream_cmd_config_control[1] = {
+ {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .name = "?",
+ .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
+ .info = msm_adsp_stream_cmd_info,
+ .put = msm_transcode_stream_cmd_put,
+ .private_value = 0,
+ }
+ };
+
+ if (!rtd) {
+ pr_err("%s NULL rtd\n", __func__);
+ ret = -EINVAL;
+ goto done;
+ }
+
+ ctl_len = strlen(mixer_ctl_name) + 1 + strlen(deviceNo) + 1;
+ mixer_str = kzalloc(ctl_len, GFP_KERNEL);
+ if (!mixer_str) {
+ ret = -ENOMEM;
+ goto done;
+ }
+
+ snprintf(mixer_str, ctl_len, "%s %d", mixer_ctl_name, rtd->pcm->device);
+ fe_loopback_stream_cmd_config_control[0].name = mixer_str;
+ fe_loopback_stream_cmd_config_control[0].private_value =
+ rtd->dai_link->be_id;
+ pr_debug("%s: Registering new mixer ctl %s\n", __func__, mixer_str);
+ ret = snd_soc_add_platform_controls(rtd->platform,
+ fe_loopback_stream_cmd_config_control,
+ ARRAY_SIZE(fe_loopback_stream_cmd_config_control));
+ if (ret < 0)
+ pr_err("%s: failed to add ctl %s. err = %d\n",
+ __func__, mixer_str, ret);
+
+ kfree(mixer_str);
+done:
+ return ret;
+}
+
+static int msm_transcode_stream_callback_control(
+ struct snd_soc_pcm_runtime *rtd)
+{
+ const char *mixer_ctl_name = DSP_STREAM_CALLBACK;
+ const char *deviceNo = "NN";
+ char *mixer_str = NULL;
+ int ctl_len = 0, ret = 0;
+ struct snd_kcontrol *kctl;
+
+ struct snd_kcontrol_new fe_loopback_callback_config_control[1] = {
+ {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .name = "?",
+ .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
+ .info = msm_adsp_stream_callback_info,
+ .get = msm_adsp_stream_callback_get,
+ .private_value = 0,
+ }
+ };
+
+ if (!rtd) {
+ pr_err("%s: rtd is NULL\n", __func__);
+ ret = -EINVAL;
+ goto done;
+ }
+
+ ctl_len = strlen(mixer_ctl_name) + 1 + strlen(deviceNo) + 1;
+ mixer_str = kzalloc(ctl_len, GFP_KERNEL);
+ if (!mixer_str) {
+ ret = -ENOMEM;
+ goto done;
+ }
+
+ snprintf(mixer_str, ctl_len, "%s %d", mixer_ctl_name, rtd->pcm->device);
+ fe_loopback_callback_config_control[0].name = mixer_str;
+ fe_loopback_callback_config_control[0].private_value =
+ rtd->dai_link->be_id;
+ pr_debug("%s: Registering new mixer ctl %s\n", __func__, mixer_str);
+ ret = snd_soc_add_platform_controls(rtd->platform,
+ fe_loopback_callback_config_control,
+ ARRAY_SIZE(fe_loopback_callback_config_control));
+ if (ret < 0) {
+ pr_err("%s: failed to add ctl %s. err = %d\n",
+ __func__, mixer_str, ret);
+ ret = -EINVAL;
+ goto free_mixer_str;
+ }
+
+ kctl = snd_soc_card_get_kcontrol(rtd->card, mixer_str);
+ if (!kctl) {
+ pr_err("%s: failed to get kctl %s.\n", __func__, mixer_str);
+ ret = -EINVAL;
+ goto free_mixer_str;
+ }
+
+ kctl->private_data = NULL;
+free_mixer_str:
+ kfree(mixer_str);
+done:
+ return ret;
+}
+
+static int msm_transcode_add_ion_fd_cmd_control(struct snd_soc_pcm_runtime *rtd)
+{
+ const char *mixer_ctl_name = "Playback ION FD";
+ const char *deviceNo = "NN";
+ char *mixer_str = NULL;
+ int ctl_len = 0, ret = 0;
+ struct snd_kcontrol_new fe_ion_fd_config_control[1] = {
+ {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .name = "?",
+ .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
+ .info = msm_adsp_stream_cmd_info,
+ .put = msm_transcode_ion_fd_map_put,
+ .private_value = 0,
+ }
+ };
+
+ if (!rtd) {
+ pr_err("%s NULL rtd\n", __func__);
+ ret = -EINVAL;
+ goto done;
+ }
+
+ ctl_len = strlen(mixer_ctl_name) + 1 + strlen(deviceNo) + 1;
+ mixer_str = kzalloc(ctl_len, GFP_KERNEL);
+ if (!mixer_str) {
+ ret = -ENOMEM;
+ goto done;
+ }
+
+ snprintf(mixer_str, ctl_len, "%s %d", mixer_ctl_name, rtd->pcm->device);
+ fe_ion_fd_config_control[0].name = mixer_str;
+ fe_ion_fd_config_control[0].private_value = rtd->dai_link->be_id;
+ pr_debug("%s: Registering new mixer ctl %s\n", __func__, mixer_str);
+ ret = snd_soc_add_platform_controls(rtd->platform,
+ fe_ion_fd_config_control,
+ ARRAY_SIZE(fe_ion_fd_config_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_transcode_add_event_ack_cmd_control(
+ struct snd_soc_pcm_runtime *rtd)
+{
+ const char *mixer_ctl_name = "Playback Event Ack";
+ const char *deviceNo = "NN";
+ char *mixer_str = NULL;
+ int ctl_len = 0, ret = 0;
+ struct snd_kcontrol_new fe_event_ack_config_control[1] = {
+ {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .name = "?",
+ .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
+ .info = msm_adsp_stream_cmd_info,
+ .put = msm_transcode_rtic_event_ack_put,
+ .private_value = 0,
+ }
+ };
+
+ if (!rtd) {
+ pr_err("%s NULL rtd\n", __func__);
+ ret = -EINVAL;
+ goto done;
+ }
+
+ ctl_len = strlen(mixer_ctl_name) + 1 + strlen(deviceNo) + 1;
+ mixer_str = kzalloc(ctl_len, GFP_KERNEL);
+ if (!mixer_str) {
+ ret = -ENOMEM;
+ goto done;
+ }
+
+ snprintf(mixer_str, ctl_len, "%s %d", mixer_ctl_name, rtd->pcm->device);
+ fe_event_ack_config_control[0].name = mixer_str;
+ fe_event_ack_config_control[0].private_value = rtd->dai_link->be_id;
+ pr_debug("%s: Registering new mixer ctl %s\n", __func__, mixer_str);
+ ret = snd_soc_add_platform_controls(rtd->platform,
+ fe_event_ack_config_control,
+ ARRAY_SIZE(fe_event_ack_config_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_transcode_loopback_new(struct snd_soc_pcm_runtime *rtd)
+{
+ int rc;
+
+ rc = msm_transcode_stream_cmd_control(rtd);
+ if (rc)
+ pr_err("%s: ADSP Stream Cmd Control open failed\n", __func__);
+
+ rc = msm_transcode_stream_callback_control(rtd);
+ if (rc)
+ pr_err("%s: ADSP Stream callback Control open failed\n",
+ __func__);
+
+ rc = msm_transcode_add_ion_fd_cmd_control(rtd);
+ if (rc)
+ pr_err("%s: Could not add transcode ion fd Control\n",
+ __func__);
+
+ rc = msm_transcode_add_event_ack_cmd_control(rtd);
+ if (rc)
+ pr_err("%s: Could not add transcode event ack Control\n",
+ __func__);
+
+ return 0;
+}
+
+static struct snd_compr_ops msm_transcode_loopback_ops = {
+ .open = msm_transcode_loopback_open,
+ .free = msm_transcode_loopback_free,
+ .trigger = msm_transcode_loopback_trigger,
+ .set_params = msm_transcode_loopback_set_params,
+ .get_caps = msm_transcode_loopback_get_caps,
+};
+
+
+static int msm_transcode_loopback_probe(struct snd_soc_platform *platform)
+{
+ struct trans_loopback_pdata *pdata = NULL;
+
+ pr_debug("%s\n", __func__);
+ pdata = (struct trans_loopback_pdata *)
+ kzalloc(sizeof(struct trans_loopback_pdata),
+ GFP_KERNEL);
+ if (!pdata)
+ return -ENOMEM;
+
+ snd_soc_platform_set_drvdata(platform, pdata);
+ return 0;
+}
+
+static struct snd_soc_platform_driver msm_soc_platform = {
+ .probe = msm_transcode_loopback_probe,
+ .compr_ops = &msm_transcode_loopback_ops,
+ .pcm_new = msm_transcode_loopback_new,
+};
+
+static int msm_transcode_dev_probe(struct platform_device *pdev)
+{
+
+ pr_debug("%s: dev name %s\n", __func__, dev_name(&pdev->dev));
+ if (pdev->dev.of_node)
+ dev_set_name(&pdev->dev, "%s", "msm-transcode-loopback");
+
+ return snd_soc_register_platform(&pdev->dev,
+ &msm_soc_platform);
+}
+
+static int msm_transcode_remove(struct platform_device *pdev)
+{
+ snd_soc_unregister_platform(&pdev->dev);
+ return 0;
+}
+
+static const struct of_device_id msm_transcode_loopback_dt_match[] = {
+ {.compatible = "qcom,msm-transcode-loopback"},
+ {}
+};
+MODULE_DEVICE_TABLE(of, msm_transcode_loopback_dt_match);
+
+static struct platform_driver msm_transcode_loopback_driver = {
+ .driver = {
+ .name = "msm-transcode-loopback",
+ .owner = THIS_MODULE,
+ .of_match_table = msm_transcode_loopback_dt_match,
+ },
+ .probe = msm_transcode_dev_probe,
+ .remove = msm_transcode_remove,
+};
+
+static int __init msm_soc_platform_init(void)
+{
+ memset(&transcode_info, 0, sizeof(struct msm_transcode_loopback));
+ mutex_init(&transcode_info.lock);
+ return platform_driver_register(&msm_transcode_loopback_driver);
+}
+module_init(msm_soc_platform_init);
+
+static void __exit msm_soc_platform_exit(void)
+{
+ mutex_destroy(&transcode_info.lock);
+ platform_driver_unregister(&msm_transcode_loopback_driver);
+}
+module_exit(msm_soc_platform_exit);
+
+MODULE_DESCRIPTION("Transcode loopback platform driver");
+MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/msm/qdsp6v2/q6adm.c b/sound/soc/msm/qdsp6v2/q6adm.c
index 9f00e1bc4a3d..7cf19a9ed335 100644
--- a/sound/soc/msm/qdsp6v2/q6adm.c
+++ b/sound/soc/msm/qdsp6v2/q6adm.c
@@ -2156,7 +2156,8 @@ int adm_open(int port_id, int path, int rate, int channel_mode, int topology,
(topology == SRS_TRUMEDIA_TOPOLOGY_ID))
topology = DEFAULT_COPP_TOPOLOGY;
} else {
- if (path == ADM_PATH_COMPRESSED_RX)
+ if ((path == ADM_PATH_COMPRESSED_RX) ||
+ (path == ADM_PATH_COMPRESSED_TX))
flags = 0;
else
flags = ADM_LEGACY_DEVICE_SESSION;
@@ -2193,7 +2194,8 @@ int adm_open(int port_id, int path, int rate, int channel_mode, int topology,
acdb_id);
set_bit(ADM_STATUS_CALIBRATION_REQUIRED,
(void *)&this_adm.copp.adm_status[port_idx][copp_idx]);
- if (path != ADM_PATH_COMPRESSED_RX)
+ if ((path != ADM_PATH_COMPRESSED_RX) &&
+ (path != ADM_PATH_COMPRESSED_TX))
send_adm_custom_topology();
}
}
@@ -2465,6 +2467,10 @@ static void route_set_opcode_matrix_id(
route->hdr.opcode = ADM_CMD_STREAM_DEVICE_MAP_ROUTINGS_V5;
route->matrix_id = ADM_MATRIX_ID_COMPRESSED_AUDIO_RX;
break;
+ case ADM_PATH_COMPRESSED_TX:
+ route->hdr.opcode = ADM_CMD_STREAM_DEVICE_MAP_ROUTINGS_V5;
+ route->matrix_id = ADM_MATRIX_ID_COMPRESSED_AUDIO_TX;
+ break;
default:
pr_err("%s: Wrong path set[%d]\n", __func__, path);
break;
diff --git a/sound/soc/msm/qdsp6v2/q6asm.c b/sound/soc/msm/qdsp6v2/q6asm.c
index 0d142f77db50..da156bf61610 100644
--- a/sound/soc/msm/qdsp6v2/q6asm.c
+++ b/sound/soc/msm/qdsp6v2/q6asm.c
@@ -155,12 +155,37 @@ static int out_cold_index;
static char *out_buffer;
static char *in_buffer;
-static uint32_t adsp_reg_event_opcode[] = {ASM_STREAM_CMD_REGISTER_PP_EVENTS,
- ASM_STREAM_CMD_REGISTER_ENCDEC_EVENTS};
+static uint32_t adsp_reg_event_opcode[] = {
+ ASM_STREAM_CMD_REGISTER_PP_EVENTS,
+ ASM_STREAM_CMD_REGISTER_ENCDEC_EVENTS,
+ ASM_STREAM_CMD_REGISTER_IEC_61937_FMT_UPDATE };
-static uint32_t adsp_raise_event_opcode[] = {ASM_STREAM_PP_EVENT,
- ASM_STREAM_CMD_ENCDEC_EVENTS};
+static uint32_t adsp_raise_event_opcode[] = {
+ ASM_STREAM_PP_EVENT,
+ ASM_STREAM_CMD_ENCDEC_EVENTS,
+ ASM_IEC_61937_MEDIA_FMT_EVENT };
+static int is_adsp_reg_event(uint32_t cmd)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(adsp_reg_event_opcode); i++) {
+ if (cmd == adsp_reg_event_opcode[i])
+ return i;
+ }
+ return -EINVAL;
+}
+
+static int is_adsp_raise_event(uint32_t cmd)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(adsp_raise_event_opcode); i++) {
+ if (cmd == adsp_raise_event_opcode[i])
+ return i;
+ }
+ return -EINVAL;
+}
static inline void q6asm_set_flag_in_token(union asm_token_struct *asm_token,
int flag, int flag_offset)
@@ -1794,6 +1819,7 @@ static int32_t q6asm_callback(struct apr_client_data *data, void *priv)
case ASM_STREAM_CMD_SET_ENCDEC_PARAM:
case ASM_STREAM_CMD_SET_ENCDEC_PARAM_V2:
case ASM_STREAM_CMD_REGISTER_ENCDEC_EVENTS:
+ case ASM_STREAM_CMD_REGISTER_IEC_61937_FMT_UPDATE:
case ASM_DATA_CMD_REMOVE_INITIAL_SILENCE:
case ASM_DATA_CMD_REMOVE_TRAILING_SILENCE:
case ASM_SESSION_CMD_REGISTER_FOR_RX_UNDERFLOW_EVENTS:
@@ -1807,10 +1833,9 @@ static int32_t q6asm_callback(struct apr_client_data *data, void *priv)
pr_err("%s: cmd = 0x%x returned error = 0x%x\n",
__func__, payload[0], payload[1]);
if (wakeup_flag) {
- if (payload[0] ==
- ASM_STREAM_CMD_SET_PP_PARAMS_V2
- || payload[0] ==
- ASM_STREAM_CMD_REGISTER_ENCDEC_EVENTS)
+ if ((is_adsp_reg_event(payload[0]) >= 0)
+ || (payload[0] ==
+ ASM_STREAM_CMD_SET_PP_PARAMS_V2))
atomic_set(&ac->cmd_state_pp,
payload[1]);
else
@@ -1820,9 +1845,8 @@ static int32_t q6asm_callback(struct apr_client_data *data, void *priv)
}
return 0;
}
- if (payload[0] == ASM_STREAM_CMD_SET_PP_PARAMS_V2 ||
- payload[0] ==
- ASM_STREAM_CMD_REGISTER_ENCDEC_EVENTS) {
+ if ((is_adsp_reg_event(payload[0]) >= 0) ||
+ (payload[0] == ASM_STREAM_CMD_SET_PP_PARAMS_V2)) {
if (atomic_read(&ac->cmd_state_pp) &&
wakeup_flag) {
atomic_set(&ac->cmd_state_pp, 0);
@@ -2063,13 +2087,11 @@ static int32_t q6asm_callback(struct apr_client_data *data, void *priv)
break;
case ASM_STREAM_PP_EVENT:
case ASM_STREAM_CMD_ENCDEC_EVENTS:
- pr_debug("%s: ASM_STREAM_PP_EVENT payload[0][0x%x] payload[1][0x%x]",
+ case ASM_STREAM_CMD_REGISTER_IEC_61937_FMT_UPDATE:
+ pr_debug("%s: ASM_STREAM_EVENT payload[0][0x%x] payload[1][0x%x]",
__func__, payload[0], payload[1]);
- for (i = 0; i < ARRAY_SIZE(adsp_raise_event_opcode); i++)
- if (adsp_raise_event_opcode[i] == data->opcode)
- break;
-
- if (i >= ARRAY_SIZE(adsp_raise_event_opcode))
+ i = is_adsp_raise_event(data->opcode);
+ if (i < 0)
return 0;
/* repack payload for asm_stream_pp_event