summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--AndroidKernel.mk35
-rw-r--r--Documentation/devicetree/bindings/arm/msm/msm.txt8
-rw-r--r--Documentation/devicetree/bindings/fb/mdss-dsi-panel.txt13
-rw-r--r--Documentation/devicetree/bindings/pci/msm_pcie.txt10
-rw-r--r--Documentation/devicetree/bindings/power/supply/qcom/qpnp-fg-gen3.txt22
-rw-r--r--Documentation/devicetree/bindings/power/supply/qcom/qpnp-smb2.txt12
-rw-r--r--Documentation/devicetree/bindings/power/supply/qcom/smb138x-charger.txt8
-rw-r--r--Documentation/devicetree/bindings/regulator/qpnp-labibb-regulator.txt4
-rw-r--r--Documentation/devicetree/bindings/regulator/qpnp-oledb-regulator.txt13
-rw-r--r--Documentation/devicetree/bindings/spmi/qcom,spmi-pmic-arb.txt4
-rw-r--r--Documentation/kernel-parameters.txt5
-rw-r--r--android/configs/android-base.cfg1
-rw-r--r--arch/arm/Kconfig2
-rw-r--r--arch/arm/boot/dts/qcom/Makefile40
-rw-r--r--arch/arm/boot/dts/qcom/apq8096-auto-dragonboard.dtsi45
-rw-r--r--arch/arm/boot/dts/qcom/apq8098-cdp.dts (renamed from arch/arm/boot/dts/qcom/apq8998-cdp.dts)8
-rw-r--r--arch/arm/boot/dts/qcom/apq8098-mtp.dts (renamed from arch/arm/boot/dts/qcom/apq8998-mtp.dts)8
-rw-r--r--arch/arm/boot/dts/qcom/apq8098-v2-cdp.dts (renamed from arch/arm/boot/dts/qcom/apq8998-v2.1-cdp.dts)8
-rw-r--r--arch/arm/boot/dts/qcom/apq8098-v2-mtp.dts (renamed from arch/arm/boot/dts/qcom/apq8998-v2.1-mtp.dts)8
-rw-r--r--arch/arm/boot/dts/qcom/apq8098-v2-qrd-skuk-hdk.dts (renamed from arch/arm/boot/dts/qcom/apq8998-v2-qrd-skuk-hdk.dts)4
-rw-r--r--arch/arm/boot/dts/qcom/apq8098-v2-qrd.dts (renamed from arch/arm/boot/dts/qcom/apq8998-v2-qrd.dts)8
-rw-r--r--arch/arm/boot/dts/qcom/apq8098-v2.1-cdp.dts (renamed from arch/arm/boot/dts/qcom/apq8998-v2-cdp.dts)8
-rw-r--r--arch/arm/boot/dts/qcom/apq8098-v2.1-mediabox.dts (renamed from arch/arm/boot/dts/qcom/apq8998-v2.1-mediabox.dts)6
-rw-r--r--arch/arm/boot/dts/qcom/apq8098-v2.1-mtp.dts (renamed from arch/arm/boot/dts/qcom/apq8998-v2-mtp.dts)8
-rw-r--r--arch/arm/boot/dts/qcom/apq8098-v2.1-qrd.dts (renamed from arch/arm/boot/dts/qcom/apq8998-v2.1-qrd.dts)8
-rw-r--r--arch/arm/boot/dts/qcom/apq8098-v2.1.dtsi (renamed from arch/arm/boot/dts/qcom/apq8998-v2.1.dtsi)4
-rw-r--r--arch/arm/boot/dts/qcom/apq8098-v2.dtsi (renamed from arch/arm/boot/dts/qcom/apq8998-v2.dtsi)4
-rw-r--r--arch/arm/boot/dts/qcom/apq8098.dtsi (renamed from arch/arm/boot/dts/qcom/apq8998.dtsi)4
-rw-r--r--arch/arm/boot/dts/qcom/dsi-panel-jdi-a407-dualmipi-wqhd-cmd.dtsi3
-rw-r--r--arch/arm/boot/dts/qcom/dsi-panel-rm67195-amoled-fhd-cmd.dtsi16
-rw-r--r--arch/arm/boot/dts/qcom/dsi-panel-sharp-split-link-wuxga-video.dtsi68
-rw-r--r--arch/arm/boot/dts/qcom/msm-pm660.dtsi18
-rw-r--r--arch/arm/boot/dts/qcom/msm-pm660l.dtsi13
-rw-r--r--arch/arm/boot/dts/qcom/msm-pmi8998.dtsi9
-rw-r--r--arch/arm/boot/dts/qcom/msm8996-agave-adp.dtsi39
-rw-r--r--arch/arm/boot/dts/qcom/msm8996-auto-cdp.dtsi49
-rw-r--r--arch/arm/boot/dts/qcom/msm8996-mmxf-adp.dtsi45
-rw-r--r--arch/arm/boot/dts/qcom/msm8996.dtsi270
-rw-r--r--arch/arm/boot/dts/qcom/msm8998-cdp-overlay.dts28
-rw-r--r--arch/arm/boot/dts/qcom/msm8998-cdp.dtsi3
-rw-r--r--arch/arm/boot/dts/qcom/msm8998-interposer-sdm660.dtsi4
-rw-r--r--arch/arm/boot/dts/qcom/msm8998-mdss-panels.dtsi2
-rw-r--r--arch/arm/boot/dts/qcom/msm8998-mtp-overlay.dts28
-rw-r--r--arch/arm/boot/dts/qcom/msm8998-mtp.dtsi5
-rw-r--r--arch/arm/boot/dts/qcom/msm8998-pinctrl.dtsi14
-rw-r--r--arch/arm/boot/dts/qcom/msm8998-qrd-skuk.dtsi2
-rw-r--r--arch/arm/boot/dts/qcom/msm8998-qrd-vr1.dtsi2
-rw-r--r--arch/arm/boot/dts/qcom/msm8998-qrd.dtsi2
-rw-r--r--arch/arm/boot/dts/qcom/msm8998-v2-cdp-overlay.dts28
-rw-r--r--arch/arm/boot/dts/qcom/msm8998-v2-mtp-overlay.dts28
-rw-r--r--arch/arm/boot/dts/qcom/msm8998-v2.1-cdp-overlay.dts28
-rw-r--r--arch/arm/boot/dts/qcom/msm8998-v2.1-mtp-overlay.dts28
-rw-r--r--arch/arm/boot/dts/qcom/msm8998-v2.1.dts23
-rw-r--r--arch/arm/boot/dts/qcom/msm8998-v2.dts23
-rw-r--r--arch/arm/boot/dts/qcom/msm8998-v2.dtsi112
-rw-r--r--arch/arm/boot/dts/qcom/msm8998.dts23
-rw-r--r--arch/arm/boot/dts/qcom/msm8998.dtsi10
-rw-r--r--arch/arm/boot/dts/qcom/sdm630-cdp.dtsi23
-rw-r--r--arch/arm/boot/dts/qcom/sdm630-mdss-panels.dtsi103
-rw-r--r--arch/arm/boot/dts/qcom/sdm630-mtp.dtsi12
-rw-r--r--arch/arm/boot/dts/qcom/sdm630-qrd.dtsi19
-rw-r--r--arch/arm/boot/dts/qcom/sdm630-regulator.dtsi68
-rw-r--r--arch/arm/boot/dts/qcom/sdm630.dtsi12
-rw-r--r--arch/arm/boot/dts/qcom/sdm660-common.dtsi36
-rw-r--r--arch/arm/boot/dts/qcom/sdm660-mdss-panels.dtsi62
-rw-r--r--arch/arm/boot/dts/qcom/sdm660-pinctrl.dtsi14
-rw-r--r--arch/arm/boot/dts/qcom/sdm660-regulator.dtsi2
-rw-r--r--arch/arm/boot/dts/qcom/sdm660.dtsi1
-rw-r--r--arch/arm/configs/sdm660_defconfig1
-rw-r--r--arch/arm/mm/dma-mapping.c201
-rw-r--r--arch/arm64/Kconfig7
-rw-r--r--arch/arm64/Makefile4
-rw-r--r--arch/arm64/configs/msmcortex-perf_defconfig7
-rw-r--r--arch/arm64/configs/msmcortex_defconfig10
-rw-r--r--arch/arm64/configs/msmcortex_mediabox_defconfig2
-rw-r--r--arch/arm64/configs/sdm660_defconfig2
-rw-r--r--arch/arm64/include/asm/cache.h12
-rw-r--r--arch/arm64/kernel/cpufeature.c6
-rw-r--r--drivers/android/Kconfig2
-rw-r--r--drivers/android/binder.c398
-rw-r--r--drivers/char/Kconfig2
-rw-r--r--drivers/char/adsprpc.c99
-rw-r--r--drivers/char/diag/diag_masks.c9
-rw-r--r--drivers/char/diag/diagchar.h1
-rw-r--r--drivers/char/diag/diagfwd.c30
-rw-r--r--drivers/char/diag/diagfwd_cntl.c44
-rw-r--r--drivers/char/diag/diagfwd_glink.c4
-rw-r--r--drivers/char/diag/diagfwd_peripheral.c102
-rw-r--r--drivers/clk/qcom/clk-cpu-osm.c2
-rw-r--r--drivers/clk/qcom/gcc-sdm660.c4
-rw-r--r--drivers/cpuidle/lpm-levels.c8
-rw-r--r--drivers/crypto/msm/qcedev.c51
-rw-r--r--drivers/gpu/drm/drm_edid.c809
-rw-r--r--drivers/gpu/drm/msm/Makefile2
-rw-r--r--drivers/gpu/drm/msm/adreno/a5xx_gpu.c6
-rw-r--r--drivers/gpu/drm/msm/hdmi-staging/sde_hdmi.c727
-rw-r--r--drivers/gpu/drm/msm/hdmi-staging/sde_hdmi.h132
-rw-r--r--drivers/gpu/drm/msm/hdmi-staging/sde_hdmi_bridge.c267
-rw-r--r--drivers/gpu/drm/msm/hdmi-staging/sde_hdmi_edid.c227
-rw-r--r--drivers/gpu/drm/msm/hdmi/hdmi.xml.h14
-rw-r--r--drivers/gpu/drm/msm/sde/sde_crtc.c47
-rw-r--r--drivers/gpu/drm/msm/sde/sde_crtc.h3
-rw-r--r--drivers/gpu/drm/msm/sde/sde_encoder.c28
-rw-r--r--drivers/gpu/drm/msm/sde/sde_encoder.h11
-rw-r--r--drivers/gpu/drm/msm/sde_edid_parser.c512
-rw-r--r--drivers/gpu/drm/msm/sde_edid_parser.h148
-rw-r--r--drivers/gpu/msm/kgsl.c28
-rw-r--r--drivers/iio/adc/qcom-tadc.c49
-rw-r--r--drivers/input/misc/hbtp_input.c104
-rw-r--r--drivers/iommu/arm-smmu.c37
-rw-r--r--drivers/iommu/dma-mapping-fast.c38
-rw-r--r--drivers/iommu/io-pgtable-fast.c19
-rw-r--r--drivers/leds/leds-qpnp-flash-v2.c210
-rw-r--r--drivers/media/platform/msm/camera_v2/isp/msm_isp.h3
-rw-r--r--drivers/media/platform/msm/camera_v2/isp/msm_isp_axi_util.c106
-rw-r--r--drivers/media/platform/msm/camera_v2/isp/msm_isp_axi_util.h5
-rw-r--r--drivers/media/platform/msm/camera_v2/isp/msm_isp_stats_util.c5
-rw-r--r--drivers/media/platform/msm/camera_v2/isp/msm_isp_util.c4
-rw-r--r--drivers/media/platform/msm/camera_v2/ispif/msm_ispif.c335
-rw-r--r--drivers/media/platform/msm/camera_v2/ispif/msm_ispif_hwreg_v1.h6
-rw-r--r--drivers/media/platform/msm/camera_v2/ispif/msm_ispif_hwreg_v2.h8
-rw-r--r--drivers/media/platform/msm/camera_v2/ispif/msm_ispif_hwreg_v3.h7
-rw-r--r--drivers/media/platform/msm/camera_v2/sensor/cci/msm_cci.c59
-rw-r--r--drivers/media/platform/msm/camera_v2/sensor/cci/msm_cci.h3
-rw-r--r--drivers/media/platform/msm/camera_v2/sensor/csid/msm_csid.c20
-rw-r--r--drivers/media/platform/msm/camera_v2/sensor/msm_sensor.h1
-rw-r--r--drivers/media/platform/msm/camera_v2/sensor/msm_sensor_driver.c30
-rw-r--r--drivers/media/platform/msm/sde/rotator/sde_rotator_r3.c100
-rw-r--r--drivers/media/platform/msm/vidc/msm_v4l2_vidc.c3
-rw-r--r--drivers/media/platform/msm/vidc/msm_vdec.c32
-rw-r--r--drivers/media/platform/msm/vidc/msm_venc.c75
-rw-r--r--drivers/media/platform/msm/vidc/msm_vidc_common.c13
-rw-r--r--drivers/media/platform/msm/vidc/msm_vidc_debug.c33
-rw-r--r--drivers/media/platform/msm/vidc/msm_vidc_debug.h1
-rw-r--r--drivers/media/platform/msm/vidc/msm_vidc_res_parse.c2
-rw-r--r--drivers/mfd/wcd934x-regmap.c1
-rw-r--r--drivers/misc/qcom/qdsp6v2/audio_hwacc_effects.c34
-rw-r--r--drivers/misc/qcom/qdsp6v2/ultrasound/usf.c13
-rw-r--r--drivers/mmc/core/mmc.c2
-rw-r--r--drivers/net/wireless/ath/ath10k/mac.c11
-rw-r--r--drivers/net/wireless/ath/ath10k/qmi.c51
-rw-r--r--drivers/net/wireless/ath/ath10k/qmi.h2
-rw-r--r--drivers/net/wireless/ath/ath10k/snoc.c3
-rw-r--r--drivers/net/wireless/ath/wil6210/cfg80211.c45
-rw-r--r--drivers/net/wireless/ath/wil6210/main.c62
-rw-r--r--drivers/net/wireless/ath/wil6210/pcie_bus.c16
-rw-r--r--drivers/net/wireless/ath/wil6210/pm.c16
-rw-r--r--drivers/net/wireless/ath/wil6210/sysfs.c65
-rw-r--r--drivers/net/wireless/ath/wil6210/wil6210.h30
-rw-r--r--drivers/net/wireless/ath/wil6210/wmi.c81
-rw-r--r--drivers/net/wireless/cnss_prealloc/cnss_prealloc.c1
-rw-r--r--drivers/net/wireless/wcnss/wcnss_wlan.c25
-rw-r--r--drivers/pci/host/pci-msm.c141
-rw-r--r--drivers/platform/msm/ipa/ipa_v2/ipa.c26
-rw-r--r--drivers/platform/msm/ipa/ipa_v2/ipa_dp.c32
-rw-r--r--drivers/platform/msm/ipa/ipa_v2/ipa_hdr.c21
-rw-r--r--drivers/platform/msm/ipa/ipa_v2/ipa_intf.c4
-rw-r--r--drivers/platform/msm/ipa/ipa_v2/ipa_rt.c7
-rw-r--r--drivers/platform/msm/ipa/ipa_v3/ipa.c40
-rw-r--r--drivers/platform/msm/ipa/ipa_v3/ipa_i.h8
-rw-r--r--drivers/platform/msm/ipa/ipa_v3/ipa_intf.c4
-rw-r--r--drivers/platform/msm/ipa/ipa_v3/ipa_utils.c79
-rw-r--r--drivers/platform/msm/ipa/ipa_v3/rmnet_ipa.c29
-rw-r--r--drivers/platform/msm/seemp_core/seemp_logk.c11
-rw-r--r--drivers/power/qcom/msm-core.c4
-rw-r--r--drivers/power/supply/qcom/battery.c74
-rw-r--r--drivers/power/supply/qcom/fg-core.h32
-rw-r--r--drivers/power/supply/qcom/fg-reg.h1
-rw-r--r--drivers/power/supply/qcom/qpnp-fg-gen3.c257
-rw-r--r--drivers/power/supply/qcom/qpnp-qnovo.c37
-rw-r--r--drivers/power/supply/qcom/qpnp-smb2.c57
-rw-r--r--drivers/power/supply/qcom/smb-lib.c818
-rw-r--r--drivers/power/supply/qcom/smb-lib.h19
-rw-r--r--drivers/power/supply/qcom/smb-reg.h10
-rw-r--r--drivers/power/supply/qcom/smb138x-charger.c258
-rw-r--r--drivers/pps/clients/pps-gpio.c2
-rw-r--r--drivers/regulator/qpnp-labibb-regulator.c51
-rw-r--r--drivers/regulator/qpnp-oledb-regulator.c78
-rw-r--r--drivers/scsi/sd.c8
-rw-r--r--drivers/scsi/sd.h5
-rw-r--r--drivers/soc/qcom/glink.c9
-rw-r--r--drivers/soc/qcom/glink_smem_native_xprt.c6
-rw-r--r--drivers/soc/qcom/msm_glink_pkt.c3
-rw-r--r--drivers/soc/qcom/qdsp6v2/apr_tal_glink.c2
-rw-r--r--drivers/soc/qcom/qdsp6v2/audio_notifier.c2
-rw-r--r--drivers/soc/qcom/qpnp-haptic.c92
-rw-r--r--drivers/soc/qcom/rpm-smd.c6
-rw-r--r--drivers/soc/qcom/service-locator.c138
-rw-r--r--drivers/soc/qcom/service-notifier.c179
-rw-r--r--drivers/soc/qcom/socinfo.c44
-rw-r--r--drivers/soc/qcom/spcom.c2
-rw-r--r--drivers/soc/qcom/subsystem_restart.c105
-rw-r--r--drivers/spi/spi_qsd.c197
-rw-r--r--drivers/spi/spi_qsd.h12
-rw-r--r--drivers/spmi/spmi-pmic-arb.c13
-rw-r--r--drivers/staging/android/ion/ion_cma_heap.c2
-rw-r--r--drivers/staging/android/ion/ion_system_secure_heap.c4
-rw-r--r--drivers/staging/android/lowmemorykiller.c34
-rw-r--r--drivers/usb/gadget/configfs.c2
-rw-r--r--drivers/usb/gadget/function/f_ccid.h36
-rw-r--r--drivers/usb/gadget/function/f_fs.c43
-rw-r--r--drivers/usb/gadget/function/f_mass_storage.c7
-rw-r--r--drivers/usb/phy/phy-msm-ssusb-qmp.c15
-rw-r--r--drivers/video/fbdev/msm/mdss_dp.c8
-rw-r--r--drivers/video/fbdev/msm/mdss_dsi.c5
-rw-r--r--drivers/video/fbdev/msm/mdss_dsi.h1
-rw-r--r--drivers/video/fbdev/msm/mdss_dsi_host.c80
-rw-r--r--drivers/video/fbdev/msm/mdss_dsi_panel.c44
-rw-r--r--drivers/video/fbdev/msm/mdss_dsi_status.c31
-rw-r--r--drivers/video/fbdev/msm/mdss_fb.c27
-rw-r--r--drivers/video/fbdev/msm/mdss_fb.h7
-rw-r--r--drivers/video/fbdev/msm/mdss_hdcp_1x.c4
-rw-r--r--drivers/video/fbdev/msm/mdss_mdp.c3
-rw-r--r--drivers/video/fbdev/msm/mdss_mdp.h3
-rw-r--r--drivers/video/fbdev/msm/mdss_mdp_cdm.c13
-rw-r--r--drivers/video/fbdev/msm/mdss_mdp_ctl.c17
-rw-r--r--drivers/video/fbdev/msm/mdss_mdp_hwio.h4
-rw-r--r--drivers/video/fbdev/msm/mdss_mdp_intf_video.c25
-rw-r--r--drivers/video/fbdev/msm/mdss_mdp_intf_writeback.c4
-rw-r--r--drivers/video/fbdev/msm/mdss_mdp_overlay.c27
-rw-r--r--drivers/video/fbdev/msm/mdss_mdp_pipe.c6
-rw-r--r--drivers/video/fbdev/msm/mdss_panel.h3
-rw-r--r--drivers/video/fbdev/msm/mdss_smmu.c37
-rw-r--r--drivers/video/fbdev/msm/msm_mdss_io_8974.c329
-rw-r--r--drivers/video/hdmi.c4
-rw-r--r--fs/ext4/inline.c14
-rw-r--r--fs/ext4/inode.c54
-rw-r--r--fs/ext4/readpage.c47
-rw-r--r--fs/f2fs/data.c41
-rw-r--r--fs/f2fs/inline.c18
-rw-r--r--fs/mpage.c36
-rw-r--r--include/drm/drm_crtc.h29
-rw-r--r--include/drm/drm_displayid.h17
-rw-r--r--include/drm/drm_edid.h5
-rw-r--r--include/linux/hdmi.h3
-rw-r--r--include/linux/ieee80211.h3
-rw-r--r--include/linux/io-pgtable-fast.h3
-rw-r--r--include/linux/leds-qpnp-flash.h3
-rw-r--r--include/linux/mm.h12
-rw-r--r--include/linux/msm_mhi.h4
-rw-r--r--include/linux/poison.h4
-rw-r--r--include/linux/qpnp/qpnp-revid.h8
-rw-r--r--include/linux/regulator/qpnp-labibb-regulator.h1
-rw-r--r--include/linux/sched.h9
-rw-r--r--include/linux/shrinker.h1
-rw-r--r--include/linux/usb/audio-v3.h172
-rw-r--r--include/linux/usb/ccid_desc.h44
-rw-r--r--include/media/msm_cam_sensor.h1
-rw-r--r--include/net/cfg80211.h12
-rw-r--r--include/soc/qcom/socinfo.h6
-rw-r--r--include/soc/qcom/subsystem_restart.h3
-rw-r--r--include/trace/events/android_fs.h65
-rw-r--r--include/trace/events/android_fs_template.h57
-rw-r--r--include/uapi/drm/drm_mode.h3
-rw-r--r--include/uapi/linux/hbtp_input.h9
-rw-r--r--include/uapi/linux/nl80211.h21
-rw-r--r--include/uapi/linux/usb/audio.h1
-rw-r--r--include/uapi/media/msm_camsensor_sdk.h3
-rw-r--r--include/uapi/media/msmb_ispif.h10
-rw-r--r--kernel/cpu.c40
-rw-r--r--kernel/power/hibernate.c17
-rw-r--r--kernel/sched/core.c21
-rw-r--r--kernel/sched/core_ctl.c60
-rw-r--r--kernel/trace/trace.c2
-rw-r--r--kernel/watchdog.c2
-rw-r--r--mm/Kconfig.debug53
-rw-r--r--mm/Makefile2
-rw-r--r--mm/page_alloc.c10
-rw-r--r--mm/page_ext.c13
-rw-r--r--mm/page_poison.c (renamed from mm/debug-pagealloc.c)93
-rw-r--r--mm/vmscan.c54
-rw-r--r--net/ipv6/netfilter/Kconfig12
-rw-r--r--net/ipv6/netfilter/ip6_tables.c30
-rw-r--r--net/ipv6/route.c6
-rw-r--r--net/mac80211/mlme.c12
-rw-r--r--net/wireless/core.h2
-rw-r--r--net/wireless/db.txt3
-rw-r--r--net/wireless/mlme.c6
-rw-r--r--net/wireless/nl80211.c39
-rw-r--r--scripts/Makefile.build5
-rw-r--r--scripts/Makefile.dtbo24
-rw-r--r--scripts/Makefile.lib8
-rw-r--r--scripts/dtc/Makefile2
-rw-r--r--security/pfe/pfk_ecryptfs.c2
-rw-r--r--security/pfe/pfk_ecryptfs.h4
-rw-r--r--security/pfe/pfk_ext4.c4
-rw-r--r--security/pfe/pfk_ext4.h4
-rw-r--r--sound/soc/codecs/wcd-mbhc-v2.c3
-rw-r--r--sound/soc/codecs/wcd-spi.c2
-rw-r--r--sound/soc/codecs/wcd9335.c4
-rw-r--r--sound/soc/codecs/wcd934x/wcd934x.c13
-rw-r--r--sound/soc/codecs/wcd_cpe_core.c2
-rw-r--r--sound/soc/msm/apq8096-auto.c149
-rw-r--r--sound/soc/msm/msm-dai-fe.c2
-rw-r--r--sound/soc/msm/msm8998.c25
-rw-r--r--sound/soc/msm/qdsp6v2/msm-dai-slim.c20
-rw-r--r--sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c5
-rw-r--r--sound/soc/msm/qdsp6v2/q6afe.c2
-rw-r--r--sound/soc/msm/sdm660-common.c3
-rw-r--r--sound/usb/Makefile3
-rw-r--r--sound/usb/badd.c137
-rw-r--r--sound/usb/card.c39
-rw-r--r--sound/usb/clock.c4
-rw-r--r--sound/usb/format.c49
-rw-r--r--sound/usb/mixer.c496
-rw-r--r--sound/usb/stream.c87
-rw-r--r--sound/usb/usb_audio_qmi_svc.c49
307 files changed, 10265 insertions, 3144 deletions
diff --git a/AndroidKernel.mk b/AndroidKernel.mk
index 3db9ac9f0bcb..beefecad0ab0 100644
--- a/AndroidKernel.mk
+++ b/AndroidKernel.mk
@@ -6,6 +6,13 @@ ifeq ($(KERNEL_TARGET),)
INSTALLED_KERNEL_TARGET := $(PRODUCT_OUT)/kernel
endif
+TARGET_KERNEL_MAKE_ENV := $(strip $(TARGET_KERNEL_MAKE_ENV))
+ifeq ($(TARGET_KERNEL_MAKE_ENV),)
+KERNEL_MAKE_ENV :=
+else
+KERNEL_MAKE_ENV := $(TARGET_KERNEL_MAKE_ENV)
+endif
+
TARGET_KERNEL_ARCH := $(strip $(TARGET_KERNEL_ARCH))
ifeq ($(TARGET_KERNEL_ARCH),)
KERNEL_ARCH := arm
@@ -91,8 +98,8 @@ TARGET_PREBUILT_INT_KERNEL := $(TARGET_PREBUILT_INT_KERNEL)-dtb
endif
KERNEL_HEADERS_INSTALL := $(KERNEL_OUT)/usr
-KERNEL_MODULES_INSTALL := system
-KERNEL_MODULES_OUT := $(TARGET_OUT)/lib/modules
+KERNEL_MODULES_INSTALL ?= system
+KERNEL_MODULES_OUT ?= $(PRODUCT_OUT)/$(KERNEL_MODULES_INSTALL)/lib/modules
TARGET_PREBUILT_KERNEL := $(TARGET_PREBUILT_INT_KERNEL)
@@ -124,43 +131,43 @@ $(KERNEL_OUT):
mkdir -p $(KERNEL_OUT)
$(KERNEL_CONFIG): $(KERNEL_OUT)
- $(MAKE) -C $(TARGET_KERNEL_SOURCE) O=$(BUILD_ROOT_LOC)$(KERNEL_OUT) ARCH=$(KERNEL_ARCH) CROSS_COMPILE=$(KERNEL_CROSS_COMPILE) $(KERNEL_DEFCONFIG)
+ $(MAKE) -C $(TARGET_KERNEL_SOURCE) O=$(BUILD_ROOT_LOC)$(KERNEL_OUT) $(KERNEL_MAKE_ENV) ARCH=$(KERNEL_ARCH) CROSS_COMPILE=$(KERNEL_CROSS_COMPILE) $(KERNEL_DEFCONFIG)
$(hide) if [ ! -z "$(KERNEL_CONFIG_OVERRIDE)" ]; then \
echo "Overriding kernel config with '$(KERNEL_CONFIG_OVERRIDE)'"; \
echo $(KERNEL_CONFIG_OVERRIDE) >> $(KERNEL_OUT)/.config; \
- $(MAKE) -C $(TARGET_KERNEL_SOURCE) O=$(BUILD_ROOT_LOC)$(KERNEL_OUT) ARCH=$(KERNEL_ARCH) CROSS_COMPILE=$(KERNEL_CROSS_COMPILE) oldconfig; fi
+ $(MAKE) -C $(TARGET_KERNEL_SOURCE) O=$(BUILD_ROOT_LOC)$(KERNEL_OUT) $(KERNEL_MAKE_ENV) ARCH=$(KERNEL_ARCH) CROSS_COMPILE=$(KERNEL_CROSS_COMPILE) oldconfig; fi
$(TARGET_PREBUILT_INT_KERNEL): $(KERNEL_OUT) $(KERNEL_HEADERS_INSTALL)
$(hide) echo "Building kernel..."
$(hide) rm -rf $(KERNEL_OUT)/arch/$(KERNEL_ARCH)/boot/dts
- $(MAKE) -C $(TARGET_KERNEL_SOURCE) O=$(BUILD_ROOT_LOC)$(KERNEL_OUT) ARCH=$(KERNEL_ARCH) CROSS_COMPILE=$(KERNEL_CROSS_COMPILE) $(KERNEL_CFLAGS)
- $(MAKE) -C $(TARGET_KERNEL_SOURCE) O=$(BUILD_ROOT_LOC)$(KERNEL_OUT) ARCH=$(KERNEL_ARCH) CROSS_COMPILE=$(KERNEL_CROSS_COMPILE) $(KERNEL_CFLAGS) modules
- $(MAKE) -C $(TARGET_KERNEL_SOURCE) O=$(BUILD_ROOT_LOC)$(KERNEL_OUT) INSTALL_MOD_PATH=$(BUILD_ROOT_LOC)../$(KERNEL_MODULES_INSTALL) INSTALL_MOD_STRIP=1 ARCH=$(KERNEL_ARCH) CROSS_COMPILE=$(KERNEL_CROSS_COMPILE) modules_install
+ $(MAKE) -C $(TARGET_KERNEL_SOURCE) O=$(BUILD_ROOT_LOC)$(KERNEL_OUT) $(KERNEL_MAKE_ENV) ARCH=$(KERNEL_ARCH) CROSS_COMPILE=$(KERNEL_CROSS_COMPILE) $(KERNEL_CFLAGS)
+ $(MAKE) -C $(TARGET_KERNEL_SOURCE) O=$(BUILD_ROOT_LOC)$(KERNEL_OUT) $(KERNEL_MAKE_ENV) ARCH=$(KERNEL_ARCH) CROSS_COMPILE=$(KERNEL_CROSS_COMPILE) $(KERNEL_CFLAGS) modules
+ $(MAKE) -C $(TARGET_KERNEL_SOURCE) O=$(BUILD_ROOT_LOC)$(KERNEL_OUT) INSTALL_MOD_PATH=$(BUILD_ROOT_LOC)../$(KERNEL_MODULES_INSTALL) INSTALL_MOD_STRIP=1 $(KERNEL_MAKE_ENV) ARCH=$(KERNEL_ARCH) CROSS_COMPILE=$(KERNEL_CROSS_COMPILE) modules_install
$(mv-modules)
$(clean-module-folder)
$(KERNEL_HEADERS_INSTALL): $(KERNEL_OUT)
$(hide) if [ ! -z "$(KERNEL_HEADER_DEFCONFIG)" ]; then \
rm -f $(BUILD_ROOT_LOC)$(KERNEL_CONFIG); \
- $(MAKE) -C $(TARGET_KERNEL_SOURCE) O=$(BUILD_ROOT_LOC)$(KERNEL_OUT) ARCH=$(KERNEL_HEADER_ARCH) CROSS_COMPILE=$(KERNEL_CROSS_COMPILE) $(KERNEL_HEADER_DEFCONFIG); \
- $(MAKE) -C $(TARGET_KERNEL_SOURCE) O=$(BUILD_ROOT_LOC)$(KERNEL_OUT) ARCH=$(KERNEL_HEADER_ARCH) CROSS_COMPILE=$(KERNEL_CROSS_COMPILE) headers_install; fi
+ $(MAKE) -C $(TARGET_KERNEL_SOURCE) O=$(BUILD_ROOT_LOC)$(KERNEL_OUT) $(KERNEL_MAKE_ENV) ARCH=$(KERNEL_HEADER_ARCH) CROSS_COMPILE=$(KERNEL_CROSS_COMPILE) $(KERNEL_HEADER_DEFCONFIG); \
+ $(MAKE) -C $(TARGET_KERNEL_SOURCE) O=$(BUILD_ROOT_LOC)$(KERNEL_OUT) $(KERNEL_MAKE_ENV) ARCH=$(KERNEL_HEADER_ARCH) CROSS_COMPILE=$(KERNEL_CROSS_COMPILE) headers_install; fi
$(hide) if [ "$(KERNEL_HEADER_DEFCONFIG)" != "$(KERNEL_DEFCONFIG)" ]; then \
echo "Used a different defconfig for header generation"; \
rm -f $(BUILD_ROOT_LOC)$(KERNEL_CONFIG); \
- $(MAKE) -C $(TARGET_KERNEL_SOURCE) O=$(BUILD_ROOT_LOC)$(KERNEL_OUT) ARCH=$(KERNEL_ARCH) CROSS_COMPILE=$(KERNEL_CROSS_COMPILE) $(KERNEL_DEFCONFIG); fi
+ $(MAKE) -C $(TARGET_KERNEL_SOURCE) O=$(BUILD_ROOT_LOC)$(KERNEL_OUT) $(KERNEL_MAKE_ENV) ARCH=$(KERNEL_ARCH) CROSS_COMPILE=$(KERNEL_CROSS_COMPILE) $(KERNEL_DEFCONFIG); fi
$(hide) if [ ! -z "$(KERNEL_CONFIG_OVERRIDE)" ]; then \
echo "Overriding kernel config with '$(KERNEL_CONFIG_OVERRIDE)'"; \
echo $(KERNEL_CONFIG_OVERRIDE) >> $(KERNEL_OUT)/.config; \
- $(MAKE) -C $(TARGET_KERNEL_SOURCE) O=$(BUILD_ROOT_LOC)$(KERNEL_OUT) ARCH=$(KERNEL_ARCH) CROSS_COMPILE=$(KERNEL_CROSS_COMPILE) oldconfig; fi
+ $(MAKE) -C $(TARGET_KERNEL_SOURCE) O=$(BUILD_ROOT_LOC)$(KERNEL_OUT) $(KERNEL_MAKE_ENV) ARCH=$(KERNEL_ARCH) CROSS_COMPILE=$(KERNEL_CROSS_COMPILE) oldconfig; fi
kerneltags: $(KERNEL_OUT) $(KERNEL_CONFIG)
- $(MAKE) -C $(TARGET_KERNEL_SOURCE) O=$(BUILD_ROOT_LOC)$(KERNEL_OUT) ARCH=$(KERNEL_ARCH) CROSS_COMPILE=$(KERNEL_CROSS_COMPILE) tags
+ $(MAKE) -C $(TARGET_KERNEL_SOURCE) O=$(BUILD_ROOT_LOC)$(KERNEL_OUT) $(KERNEL_MAKE_ENV) ARCH=$(KERNEL_ARCH) CROSS_COMPILE=$(KERNEL_CROSS_COMPILE) tags
kernelconfig: $(KERNEL_OUT) $(KERNEL_CONFIG)
env KCONFIG_NOTIMESTAMP=true \
- $(MAKE) -C $(TARGET_KERNEL_SOURCE) O=$(BUILD_ROOT_LOC)$(KERNEL_OUT) ARCH=$(KERNEL_ARCH) CROSS_COMPILE=$(KERNEL_CROSS_COMPILE) menuconfig
+ $(MAKE) -C $(TARGET_KERNEL_SOURCE) O=$(BUILD_ROOT_LOC)$(KERNEL_OUT) $(KERNEL_MAKE_ENV) ARCH=$(KERNEL_ARCH) CROSS_COMPILE=$(KERNEL_CROSS_COMPILE) menuconfig
env KCONFIG_NOTIMESTAMP=true \
- $(MAKE) -C $(TARGET_KERNEL_SOURCE) O=$(BUILD_ROOT_LOC)$(KERNEL_OUT) ARCH=$(KERNEL_ARCH) CROSS_COMPILE=$(KERNEL_CROSS_COMPILE) savedefconfig
+ $(MAKE) -C $(TARGET_KERNEL_SOURCE) O=$(BUILD_ROOT_LOC)$(KERNEL_OUT) $(KERNEL_MAKE_ENV) ARCH=$(KERNEL_ARCH) CROSS_COMPILE=$(KERNEL_CROSS_COMPILE) savedefconfig
cp $(KERNEL_OUT)/defconfig $(TARGET_KERNEL_SOURCE)/arch/$(KERNEL_ARCH)/configs/$(KERNEL_DEFCONFIG)
endif
diff --git a/Documentation/devicetree/bindings/arm/msm/msm.txt b/Documentation/devicetree/bindings/arm/msm/msm.txt
index 02bf809740c3..5647b22eede0 100644
--- a/Documentation/devicetree/bindings/arm/msm/msm.txt
+++ b/Documentation/devicetree/bindings/arm/msm/msm.txt
@@ -48,7 +48,7 @@ SoCs:
compatible = "qcom,apqtitanium"
- APQ8998
- compatible = "qcom,apq8998"
+ compatible = "qcom,apq8098"
- MDM9630
compatible = "qcom,mdm9630"
@@ -195,9 +195,9 @@ compatible = "qcom,apq8037-cdp"
compatible = "qcom,apq8037-mtp"
compatible = "qcom,apqtitanium-cdp"
compatible = "qcom,apqtitanium-mtp"
-compatible = "qcom,apq8998-cdp"
-compatible = "qcom,apq8998-mtp"
-compatible = "qcom,apq8998-qrd"
+compatible = "qcom,apq8098-cdp"
+compatible = "qcom,apq8098-mtp"
+compatible = "qcom,apq8098-qrd"
compatible = "qcom,mdm9630-cdp"
compatible = "qcom,mdm9630-mtp"
compatible = "qcom,mdm9630-sim"
diff --git a/Documentation/devicetree/bindings/fb/mdss-dsi-panel.txt b/Documentation/devicetree/bindings/fb/mdss-dsi-panel.txt
index 90ccfa7c62e2..ce5ee56ada68 100644
--- a/Documentation/devicetree/bindings/fb/mdss-dsi-panel.txt
+++ b/Documentation/devicetree/bindings/fb/mdss-dsi-panel.txt
@@ -581,6 +581,15 @@ Additional properties added to the second level nodes that represent timings pro
commands.
"dsi_lp_mode" = DSI low power mode (default)
"dsi_hs_mode" = DSI high speed mode
+- qcom,sublinks-count: An integer value indicates the number of sublinks in the panel.
+ Default value is 1. This property is used only if qcom,split-link-enabled
+ is defined.
+- qcom,lanes-per-sublink: An integer value indicates the number of data lanes per sublink in the panel.
+ Default value is 1. This property is used only if qcom,split-link-enabled
+ is defined.
+- qcom,split-link-enabled: A boolean value to enable/disable the split link feature. If qcom,sublinks-count
+ or qcom,lanes-per-sublink are not defined, default values are used.
+
Note, if a given optional qcom,* binding is not present, then the driver will configure
the default values specified.
@@ -808,6 +817,10 @@ Example:
qcom,mdss-dsc-version = <0x11>;
qcom,mdss-dsc-scr-version = <0x1>;
+ qcom,split-link-enabled;
+ qcom,sublinks-count = <2>;
+ qcom,lanes-per-sublink = <2>;
+
dsi_sim_vid_config0: config0 {
qcom,lm-split = <360 360>;
qcom,mdss-dsc-encoders = <2>;
diff --git a/Documentation/devicetree/bindings/pci/msm_pcie.txt b/Documentation/devicetree/bindings/pci/msm_pcie.txt
index a50e0c2b2c35..fc019bda50a7 100644
--- a/Documentation/devicetree/bindings/pci/msm_pcie.txt
+++ b/Documentation/devicetree/bindings/pci/msm_pcie.txt
@@ -79,8 +79,12 @@ Optional Properties:
PCIe port PHY.
Should be specified in groups (offset, value, delay).
- qcom,use-19p2mhz-aux-clk: The frequency of PCIe AUX clock is 19.2MHz.
- - qcom,ep-wakeirq: The endpoint will issue wake signal when it is up, and the
- root complex has the capability to enumerate the endpoint for this case.
+ - qcom,boot-option: Bits that alter PCIe bus driver boot sequence.
+ Below details what happens when each bit is set
+ BIT(0): PCIe bus driver will not start enumeration during its probe.
+ Clients will control when PCIe bus driver should do enumeration.
+ BIT(1): PCIe bus driver will not start enumeration if it receives a WAKE
+ interrupt.
- qcom,msi-gicm-addr: MSI address for GICv2m.
- qcom,msi-gicm-base: MSI IRQ base for GICv2m.
- qcom,ext-ref-clk: The reference clock is external.
@@ -263,7 +267,7 @@ Example:
qcom,aux-clk-sync;
qcom,n-fts = <0x50>;
qcom,pcie-phy-ver = <1>;
- qcom,ep-wakeirq;
+ qcom,boot-option = <0x1>;
qcom,msi-gicm-addr = <0xf9040040>;
qcom,msi-gicm-base = <0x160>;
qcom,ext-ref-clk;
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 9638888ebc9e..12d32ec74369 100644
--- a/Documentation/devicetree/bindings/power/supply/qcom/qpnp-fg-gen3.txt
+++ b/Documentation/devicetree/bindings/power/supply/qcom/qpnp-fg-gen3.txt
@@ -96,6 +96,14 @@ First Level Node - FG Gen3 device
This value has to be specified in negative values for
the charging current.
+- qcom,fg-chg-term-base-current
+ Usage: optional
+ Value type: <u32>
+ Definition: Battery current (in mA) upper boundary at which the fuel
+ gauge will issue an end of charge during discharging. If
+ this property is not specified, then the default value used
+ will be 75mA.
+
- qcom,fg-delta-soc-thr
Usage: optional
Value type: <u32>
@@ -154,6 +162,20 @@ First Level Node - FG Gen3 device
asleep and the battery is discharging. This option requires
qcom,fg-esr-timer-awake to be defined.
+- qcom,fg-esr-pulse-thresh-ma
+ Usage: optional
+ Value type: <u32>
+ Definition: ESR pulse qualification threshold in mA. If this is not
+ specified, a default value of 110 mA will be configured.
+ Allowed values are from 1 to 997.
+
+- qcom,fg-esr-meas-curr-ma
+ Usage: optional
+ Value type: <u32>
+ Definition: ESR measurement current in mA. If this is not specified,
+ a default value of 120 mA will be configured. Allowed
+ values are 60, 120, 180 and 240.
+
- qcom,cycle-counter-en
Usage: optional
Value type: <empty>
diff --git a/Documentation/devicetree/bindings/power/supply/qcom/qpnp-smb2.txt b/Documentation/devicetree/bindings/power/supply/qcom/qpnp-smb2.txt
index 5a2c3ecd3d1e..894c34553a22 100644
--- a/Documentation/devicetree/bindings/power/supply/qcom/qpnp-smb2.txt
+++ b/Documentation/devicetree/bindings/power/supply/qcom/qpnp-smb2.txt
@@ -169,6 +169,18 @@ Charger specific properties:
Definition: Boolean flag which when present enables intput suspend for
debug battery.
+- qcom,min-freq-khz
+ Usage: optional
+ Value type: <u32>
+ Definition: Specifies the minimum charger buck/boost switching frequency
+ in KHz. It overrides the min frequency defined for the charger.
+
+- qcom,max-freq-khz
+ Usage: optional
+ Value type: <u32>
+ Definition: Specifies the maximum charger buck/boost switching frequency in
+ KHz. It overrides the max frequency defined for the charger.
+
=============================================
Second Level Nodes - SMB2 Charger Peripherals
=============================================
diff --git a/Documentation/devicetree/bindings/power/supply/qcom/smb138x-charger.txt b/Documentation/devicetree/bindings/power/supply/qcom/smb138x-charger.txt
index 92ef23c3a290..5529e30811fb 100644
--- a/Documentation/devicetree/bindings/power/supply/qcom/smb138x-charger.txt
+++ b/Documentation/devicetree/bindings/power/supply/qcom/smb138x-charger.txt
@@ -22,7 +22,8 @@ Charger specific properties:
Definition: String which indicates the charging mode. Can be one of the
following:
Standalone/Parallel Master - "qcom,smb138x-charger"
- Parallel Slave - "qcom,smb138x-parallel-slave"
+ smb138x Parallel Slave - "qcom,smb138x-parallel-slave"
+ smb1355 Parallel Slave - "qcom,smb1355-parallel-slave",
- qcom,pmic-revid
Usage: required
@@ -35,7 +36,8 @@ Charger specific properties:
Usage: optional
Value type: <u32>
Definition: Specifies parallel charging mode. If not specified, MID-MID
- option is selected by default.
+ option is selected by default. Note that smb1355 can only
+ run in MID-MID configuration.
- qcom,suspend-input
Usage: optional
@@ -125,7 +127,7 @@ Example
=======
smb138x_charger: qcom,smb138x-charger {
- compatible = "qcom,qpnp-smb138x-charger";
+ compatible = "qcom,smb138x-charger";
#address-cells = <1>;
#size-cells = <1>;
diff --git a/Documentation/devicetree/bindings/regulator/qpnp-labibb-regulator.txt b/Documentation/devicetree/bindings/regulator/qpnp-labibb-regulator.txt
index c9cfc889faba..0d53b9fa4378 100644
--- a/Documentation/devicetree/bindings/regulator/qpnp-labibb-regulator.txt
+++ b/Documentation/devicetree/bindings/regulator/qpnp-labibb-regulator.txt
@@ -151,6 +151,10 @@ LAB subnode optional properties:
any value in the allowed limit.
- qcom,notify-lab-vreg-ok-sts: A boolean property which upon set will
poll and notify the lab_vreg_ok status.
+- qcom,qpnp-lab-sc-wait-time-ms: This property is used to specify the time
+ (in ms) to poll for the short circuit
+ detection. If not specified the default time
+ is 5 sec.
Following properties are available only for PM660A:
diff --git a/Documentation/devicetree/bindings/regulator/qpnp-oledb-regulator.txt b/Documentation/devicetree/bindings/regulator/qpnp-oledb-regulator.txt
index 38f599ba5321..55fde0d4feb6 100644
--- a/Documentation/devicetree/bindings/regulator/qpnp-oledb-regulator.txt
+++ b/Documentation/devicetree/bindings/regulator/qpnp-oledb-regulator.txt
@@ -14,6 +14,11 @@ Required Node Structure
Value type: <string>
Definition: should be "qcom,qpnp-oledb-regulator".
+- qcom,pmic-revid
+ Usage: required
+ Value type: <phandle>
+ Definition: Used to identify the PMIC subtype.
+
- reg
Usage: required
Value type: <prop-encoded-array>
@@ -57,13 +62,6 @@ Required Node Structure
rail. This property is applicable only if qcom,ext-pin-ctl
property is specified and it is specific to PM660A.
-- qcom,force-pd-control
- Usage: optional
- Value type: <bool>
- Definition: Used to enable the pull down control forcibly via SPMI by
- disabling the pull down configuration done by hardware
- automatically through SWIRE pulses.
-
- qcom,pbs-client
Usage: optional
Value type: <phandle>
@@ -224,6 +222,7 @@ pm660a_oledb: qpnp-oledb@e000 {
compatible = "qcom,qpnp-oledb-regulator";
#address-cells = <1>;
#size-cells = <1>;
+ qcom,pmic-revid = <&pm660l_revid>;
reg = <0xe000 0x100>;
label = "oledb";
diff --git a/Documentation/devicetree/bindings/spmi/qcom,spmi-pmic-arb.txt b/Documentation/devicetree/bindings/spmi/qcom,spmi-pmic-arb.txt
index bef919334574..633abd2b8d08 100644
--- a/Documentation/devicetree/bindings/spmi/qcom,spmi-pmic-arb.txt
+++ b/Documentation/devicetree/bindings/spmi/qcom,spmi-pmic-arb.txt
@@ -42,6 +42,9 @@ Required properties:
cell 4: interrupt flags indicating level-sense information, as defined in
dt-bindings/interrupt-controller/irq.h
+Optional properties:
+- qcom,reserved-chan : Reserved channel for debug purpose
+
Example V1 PMIC-Arbiter:
spmi {
@@ -56,6 +59,7 @@ Example V1 PMIC-Arbiter:
qcom,ee = <0>;
qcom,channel = <0>;
+ qcom,reserved-chan = <511>;
#address-cells = <2>;
#size-cells = <0>;
diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt
index 0220f18658e8..e953469cbe5e 100644
--- a/Documentation/kernel-parameters.txt
+++ b/Documentation/kernel-parameters.txt
@@ -2692,6 +2692,11 @@ bytes respectively. Such letter suffixes can also be entirely omitted.
we can turn it on.
on: enable the feature
+ page_poison= [KNL] Boot-time parameter changing the state of
+ poisoning on the buddy allocator.
+ off: turn off poisoning
+ on: turn on poisoning
+
panic= [KNL] Kernel behaviour on panic: delay <timeout>
timeout > 0: seconds before rebooting
timeout = 0: wait forever
diff --git a/android/configs/android-base.cfg b/android/configs/android-base.cfg
index f10371a981b7..7f672485f9c2 100644
--- a/android/configs/android-base.cfg
+++ b/android/configs/android-base.cfg
@@ -7,6 +7,7 @@
# CONFIG_SYSVIPC is not set
CONFIG_ANDROID=y
CONFIG_ANDROID_BINDER_IPC=y
+CONFIG_ANDROID_BINDER_DEVICES=binder,hwbinder,vndbinder
CONFIG_ANDROID_LOW_MEMORY_KILLER=y
CONFIG_ARMV8_DEPRECATED=y
CONFIG_ASHMEM=y
diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
index 1886a65eee87..588393412271 100644
--- a/arch/arm/Kconfig
+++ b/arch/arm/Kconfig
@@ -113,7 +113,7 @@ if ARM_DMA_USE_IOMMU
config ARM_DMA_IOMMU_ALIGNMENT
int "Maximum PAGE_SIZE order of alignment for DMA IOMMU buffers"
range 4 9
- default 8
+ default 9
help
DMA mapping framework by default aligns all buffers to the smallest
PAGE_SIZE order which is greater than or equal to the requested buffer
diff --git a/arch/arm/boot/dts/qcom/Makefile b/arch/arm/boot/dts/qcom/Makefile
index 74aefe4e616d..0b60560281c7 100644
--- a/arch/arm/boot/dts/qcom/Makefile
+++ b/arch/arm/boot/dts/qcom/Makefile
@@ -102,6 +102,22 @@ dtb-$(CONFIG_ARCH_MSM8996) += msm8996-v2-pmi8994-cdp.dtb \
apq8096-v3-pmi8996-mdm9x55-slimbus-mtp.dtb \
apq8096-v3-pmi8996-dragonboard.dtb
+ifeq ($(CONFIG_BUILD_ARM64_DT_OVERLAY),y)
+dtbo-$(CONFIG_ARCH_MSM8998) += \
+ msm8998-cdp-overlay.dtbo \
+ msm8998-mtp-overlay.dtbo \
+ msm8998-v2-cdp-overlay.dtbo \
+ msm8998-v2-mtp-overlay.dtbo \
+ msm8998-v2.1-cdp-overlay.dtbo \
+ msm8998-v2.1-mtp-overlay.dtbo
+
+msm8998-cdp-overlay.dtbo-base := msm8998.dtb
+msm8998-mtp-overlay.dtbo-base := msm8998.dtb
+msm8998-v2-cdp-overlay.dtbo-base := msm8998-v2.dtb
+msm8998-v2-mtp-overlay.dtbo-base := msm8998-v2.dtb
+msm8998-v2.1-cdp-overlay.dtbo-base := msm8998-v2.1.dtb
+msm8998-v2.1-mtp-overlay.dtbo-base := msm8998-v2.1.dtb
+else
dtb-$(CONFIG_ARCH_MSM8998) += msm8998-sim.dtb \
msm8998-rumi.dtb \
msm8998-cdp.dtb \
@@ -118,22 +134,23 @@ dtb-$(CONFIG_ARCH_MSM8998) += msm8998-sim.dtb \
msm8998-v2-qrd-vr1.dtb \
msm8998-v2-qrd-skuk-evt3.dtb \
msm8998-v2-qrd-skuk-hdk.dtb \
- apq8998-mtp.dtb \
- apq8998-cdp.dtb \
- apq8998-v2-mtp.dtb \
- apq8998-v2-cdp.dtb \
- apq8998-v2-qrd.dtb \
- apq8998-v2-qrd-skuk-hdk.dtb \
+ apq8098-mtp.dtb \
+ apq8098-cdp.dtb \
+ apq8098-v2-mtp.dtb \
+ apq8098-v2-cdp.dtb \
+ apq8098-v2-qrd.dtb \
+ apq8098-v2-qrd-skuk-hdk.dtb \
msm8998-v2.1-mtp.dtb \
msm8998-v2.1-cdp.dtb \
msm8998-v2.1-qrd.dtb \
- apq8998-v2.1-mtp.dtb \
- apq8998-v2.1-cdp.dtb \
- apq8998-v2.1-qrd.dtb \
- apq8998-v2.1-mediabox.dtb \
+ apq8098-v2.1-mtp.dtb \
+ apq8098-v2.1-cdp.dtb \
+ apq8098-v2.1-qrd.dtb \
+ apq8098-v2.1-mediabox.dtb \
msm8998-v2.1-interposer-sdm660-cdp.dtb \
msm8998-v2.1-interposer-sdm660-mtp.dtb \
msm8998-v2.1-interposer-sdm660-qrd.dtb
+endif
dtb-$(CONFIG_ARCH_MSMHAMSTER) += msmhamster-rumi.dtb
@@ -218,6 +235,7 @@ dtb-$(CONFIG_ARCH_SDM630) += sdm630-rumi.dtb \
ifeq ($(CONFIG_ARM64),y)
always := $(dtb-y)
+always += $(dtbo-y)
subdir-y := $(dts-dirs)
else
targets += dtbs
@@ -228,4 +246,4 @@ $(obj)/../%.dtb: $(src)/%.dts FORCE
dtbs: $(addprefix $(obj)/../,$(dtb-y))
endif
-clean-files := *.dtb
+clean-files := *.dtbo *.dtb
diff --git a/arch/arm/boot/dts/qcom/apq8096-auto-dragonboard.dtsi b/arch/arm/boot/dts/qcom/apq8096-auto-dragonboard.dtsi
index e74aded8c9e3..57a0467c6fc2 100644
--- a/arch/arm/boot/dts/qcom/apq8096-auto-dragonboard.dtsi
+++ b/arch/arm/boot/dts/qcom/apq8096-auto-dragonboard.dtsi
@@ -633,12 +633,13 @@
<&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",
@@ -650,12 +651,13 @@
"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";
};
@@ -689,6 +691,25 @@
};
};
+ qcom,msm-dai-tdm-tert-rx {
+ qcom,msm-cpudai-tdm-group-num-ports = <5>;
+ qcom,msm-cpudai-tdm-group-port-id = <36896 36898 36900
+ 36902 36904>;
+ pinctrl-names = "default", "sleep";
+ pinctrl-0 = <&tert_tdm_dout_active>;
+ pinctrl-1 = <&tert_tdm_dout_sleep>;
+ 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-quat-rx {
pinctrl-names = "default", "sleep";
pinctrl-0 = <&quat_tdm_dout_active>;
diff --git a/arch/arm/boot/dts/qcom/apq8998-cdp.dts b/arch/arm/boot/dts/qcom/apq8098-cdp.dts
index 8acd2dabe18a..c8011ff957c0 100644
--- a/arch/arm/boot/dts/qcom/apq8998-cdp.dts
+++ b/arch/arm/boot/dts/qcom/apq8098-cdp.dts
@@ -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
@@ -12,11 +12,11 @@
/dts-v1/;
-#include "apq8998.dtsi"
+#include "apq8098.dtsi"
#include "msm8998-cdp.dtsi"
/ {
- model = "Qualcomm Technologies, Inc. APQ 8998 CDP";
- compatible = "qcom,apq8998-cdp", "qcom,apq8998", "qcom,cdp";
+ model = "Qualcomm Technologies, Inc. APQ 8098 CDP";
+ compatible = "qcom,apq8098-cdp", "qcom,apq8098", "qcom,cdp";
qcom,board-id = <1 0>;
};
diff --git a/arch/arm/boot/dts/qcom/apq8998-mtp.dts b/arch/arm/boot/dts/qcom/apq8098-mtp.dts
index 5bed816f77d6..7af82a91e935 100644
--- a/arch/arm/boot/dts/qcom/apq8998-mtp.dts
+++ b/arch/arm/boot/dts/qcom/apq8098-mtp.dts
@@ -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
@@ -12,11 +12,11 @@
/dts-v1/;
-#include "apq8998.dtsi"
+#include "apq8098.dtsi"
#include "msm8998-mtp.dtsi"
/ {
- model = "Qualcomm Technologies, Inc. APQ 8998 MTP";
- compatible = "qcom,apq8998-mtp", "qcom,apq8998", "qcom,mtp";
+ model = "Qualcomm Technologies, Inc. APQ 8098 MTP";
+ compatible = "qcom,apq8098-mtp", "qcom,apq8098", "qcom,mtp";
qcom,board-id = <8 0>;
};
diff --git a/arch/arm/boot/dts/qcom/apq8998-v2.1-cdp.dts b/arch/arm/boot/dts/qcom/apq8098-v2-cdp.dts
index 94c6031854fa..b01c85bdbac6 100644
--- a/arch/arm/boot/dts/qcom/apq8998-v2.1-cdp.dts
+++ b/arch/arm/boot/dts/qcom/apq8098-v2-cdp.dts
@@ -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
@@ -12,11 +12,11 @@
/dts-v1/;
-#include "apq8998-v2.1.dtsi"
+#include "apq8098-v2.dtsi"
#include "msm8998-cdp.dtsi"
/ {
- model = "Qualcomm Technologies, Inc. APQ 8998 V2.1 CDP";
- compatible = "qcom,apq8998-cdp", "qcom,apq8998", "qcom,cdp";
+ model = "Qualcomm Technologies, Inc. APQ 8098 V2 CDP";
+ compatible = "qcom,apq8098-cdp", "qcom,apq8098", "qcom,cdp";
qcom,board-id = <1 0>;
};
diff --git a/arch/arm/boot/dts/qcom/apq8998-v2.1-mtp.dts b/arch/arm/boot/dts/qcom/apq8098-v2-mtp.dts
index fa4e28e515b5..a6e6f15bfa34 100644
--- a/arch/arm/boot/dts/qcom/apq8998-v2.1-mtp.dts
+++ b/arch/arm/boot/dts/qcom/apq8098-v2-mtp.dts
@@ -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
@@ -12,11 +12,11 @@
/dts-v1/;
-#include "apq8998-v2.1.dtsi"
+#include "apq8098-v2.dtsi"
#include "msm8998-mtp.dtsi"
/ {
- model = "Qualcomm Technologies, Inc. APQ 8998 V2.1 MTP";
- compatible = "qcom,apq8998-mtp", "qcom,apq8998", "qcom,mtp";
+ model = "Qualcomm Technologies, Inc. APQ 8098 V2 MTP";
+ compatible = "qcom,apq8098-mtp", "qcom,apq8098", "qcom,mtp";
qcom,board-id = <8 0>;
};
diff --git a/arch/arm/boot/dts/qcom/apq8998-v2-qrd-skuk-hdk.dts b/arch/arm/boot/dts/qcom/apq8098-v2-qrd-skuk-hdk.dts
index 6406fe52242d..7aeb8e36cca2 100644
--- a/arch/arm/boot/dts/qcom/apq8998-v2-qrd-skuk-hdk.dts
+++ b/arch/arm/boot/dts/qcom/apq8098-v2-qrd-skuk-hdk.dts
@@ -13,11 +13,11 @@
/dts-v1/;
-#include "apq8998-v2.dtsi"
+#include "apq8098-v2.dtsi"
#include "msm8998-qrd-skuk-hdk.dtsi"
/ {
- model = "Qualcomm Technologies, Inc. APQ 8998 SKUK HDK";
+ model = "Qualcomm Technologies, Inc. APQ 8098 SKUK HDK";
compatible = "qcom,msm8998-qrd", "qcom,msm8998", "qcom,qrd";
qcom,board-id = <0x06000b 0x10>;
};
diff --git a/arch/arm/boot/dts/qcom/apq8998-v2-qrd.dts b/arch/arm/boot/dts/qcom/apq8098-v2-qrd.dts
index 4f7efa7b4357..0b808e47c915 100644
--- a/arch/arm/boot/dts/qcom/apq8998-v2-qrd.dts
+++ b/arch/arm/boot/dts/qcom/apq8098-v2-qrd.dts
@@ -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
@@ -12,11 +12,11 @@
/dts-v1/;
-#include "apq8998-v2.dtsi"
+#include "apq8098-v2.dtsi"
#include "msm8998-qrd.dtsi"
/ {
- model = "Qualcomm Technologies, Inc. APQ 8998 V2 QRD";
- compatible = "qcom,apq8998-qrd", "qcom,apq8998", "qcom,qrd";
+ model = "Qualcomm Technologies, Inc. APQ 8098 V2 QRD";
+ compatible = "qcom,apq8098-qrd", "qcom,apq8098", "qcom,qrd";
qcom,board-id = <11 0>;
};
diff --git a/arch/arm/boot/dts/qcom/apq8998-v2-cdp.dts b/arch/arm/boot/dts/qcom/apq8098-v2.1-cdp.dts
index 397892dbb540..e41a66eff103 100644
--- a/arch/arm/boot/dts/qcom/apq8998-v2-cdp.dts
+++ b/arch/arm/boot/dts/qcom/apq8098-v2.1-cdp.dts
@@ -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
@@ -12,11 +12,11 @@
/dts-v1/;
-#include "apq8998-v2.dtsi"
+#include "apq8098-v2.1.dtsi"
#include "msm8998-cdp.dtsi"
/ {
- model = "Qualcomm Technologies, Inc. APQ 8998 V2 CDP";
- compatible = "qcom,apq8998-cdp", "qcom,apq8998", "qcom,cdp";
+ model = "Qualcomm Technologies, Inc. APQ 8098 V2.1 CDP";
+ compatible = "qcom,apq8098-cdp", "qcom,apq8098", "qcom,cdp";
qcom,board-id = <1 0>;
};
diff --git a/arch/arm/boot/dts/qcom/apq8998-v2.1-mediabox.dts b/arch/arm/boot/dts/qcom/apq8098-v2.1-mediabox.dts
index 9d4b1457f990..d9b1cb8741eb 100644
--- a/arch/arm/boot/dts/qcom/apq8998-v2.1-mediabox.dts
+++ b/arch/arm/boot/dts/qcom/apq8098-v2.1-mediabox.dts
@@ -12,12 +12,12 @@
/dts-v1/;
-#include "apq8998-v2.1.dtsi"
+#include "apq8098-v2.1.dtsi"
#include "msm8998-cdp.dtsi"
/ {
- model = "Qualcomm Technologies, Inc. APQ 8998 V2.1 mediabox";
- compatible = "qcom,apq8998-cdp", "qcom,apq8998", "qcom,cdp";
+ model = "Qualcomm Technologies, Inc. APQ 8098 V2.1 mediabox";
+ compatible = "qcom,apq8098-cdp", "qcom,apq8098", "qcom,cdp";
qcom,board-id = <8 1>;
};
diff --git a/arch/arm/boot/dts/qcom/apq8998-v2-mtp.dts b/arch/arm/boot/dts/qcom/apq8098-v2.1-mtp.dts
index 4dc735c8d182..5684e1849b0d 100644
--- a/arch/arm/boot/dts/qcom/apq8998-v2-mtp.dts
+++ b/arch/arm/boot/dts/qcom/apq8098-v2.1-mtp.dts
@@ -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
@@ -12,11 +12,11 @@
/dts-v1/;
-#include "apq8998-v2.dtsi"
+#include "apq8098-v2.1.dtsi"
#include "msm8998-mtp.dtsi"
/ {
- model = "Qualcomm Technologies, Inc. APQ 8998 V2 MTP";
- compatible = "qcom,apq8998-mtp", "qcom,apq8998", "qcom,mtp";
+ model = "Qualcomm Technologies, Inc. APQ 8098 V2.1 MTP";
+ compatible = "qcom,apq8098-mtp", "qcom,apq8098", "qcom,mtp";
qcom,board-id = <8 0>;
};
diff --git a/arch/arm/boot/dts/qcom/apq8998-v2.1-qrd.dts b/arch/arm/boot/dts/qcom/apq8098-v2.1-qrd.dts
index 6a91b966a9b7..0f315d7c893d 100644
--- a/arch/arm/boot/dts/qcom/apq8998-v2.1-qrd.dts
+++ b/arch/arm/boot/dts/qcom/apq8098-v2.1-qrd.dts
@@ -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
@@ -12,11 +12,11 @@
/dts-v1/;
-#include "apq8998-v2.1.dtsi"
+#include "apq8098-v2.1.dtsi"
#include "msm8998-qrd.dtsi"
/ {
- model = "Qualcomm Technologies, Inc. APQ 8998 V2.1 QRD";
- compatible = "qcom,apq8998-qrd", "qcom,apq8998", "qcom,qrd";
+ model = "Qualcomm Technologies, Inc. APQ 8098 V2.1 QRD";
+ compatible = "qcom,apq8098-qrd", "qcom,apq8098", "qcom,qrd";
qcom,board-id = <11 0>;
};
diff --git a/arch/arm/boot/dts/qcom/apq8998-v2.1.dtsi b/arch/arm/boot/dts/qcom/apq8098-v2.1.dtsi
index c7d44816c7d6..a5fa81b71537 100644
--- a/arch/arm/boot/dts/qcom/apq8998-v2.1.dtsi
+++ b/arch/arm/boot/dts/qcom/apq8098-v2.1.dtsi
@@ -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
@@ -13,6 +13,6 @@
#include "msm8998-v2.1.dtsi"
/ {
- model = "Qualcomm Technologies, Inc. APQ 8998 V2.1";
+ model = "Qualcomm Technologies, Inc. APQ 8098 V2.1";
qcom,msm-id = <319 0x20001>;
};
diff --git a/arch/arm/boot/dts/qcom/apq8998-v2.dtsi b/arch/arm/boot/dts/qcom/apq8098-v2.dtsi
index 2be3db45bf37..e51e310f7131 100644
--- a/arch/arm/boot/dts/qcom/apq8998-v2.dtsi
+++ b/arch/arm/boot/dts/qcom/apq8098-v2.dtsi
@@ -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
@@ -13,6 +13,6 @@
#include "msm8998-v2.dtsi"
/ {
- model = "Qualcomm Technologies, Inc. APQ 8998 V2";
+ model = "Qualcomm Technologies, Inc. APQ 8098 V2";
qcom,msm-id = <319 0x20000>;
};
diff --git a/arch/arm/boot/dts/qcom/apq8998.dtsi b/arch/arm/boot/dts/qcom/apq8098.dtsi
index 99d3459e39ce..8cb0c6b17689 100644
--- a/arch/arm/boot/dts/qcom/apq8998.dtsi
+++ b/arch/arm/boot/dts/qcom/apq8098.dtsi
@@ -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
@@ -13,7 +13,7 @@
#include "msm8998.dtsi"
/ {
- model = "Qualcomm Technologies, Inc. APQ 8998";
+ model = "Qualcomm Technologies, Inc. APQ 8098";
qcom,msm-id = <319 0x10000>;
};
diff --git a/arch/arm/boot/dts/qcom/dsi-panel-jdi-a407-dualmipi-wqhd-cmd.dtsi b/arch/arm/boot/dts/qcom/dsi-panel-jdi-a407-dualmipi-wqhd-cmd.dtsi
index 62115cf6f98a..0ff02042600d 100644
--- a/arch/arm/boot/dts/qcom/dsi-panel-jdi-a407-dualmipi-wqhd-cmd.dtsi
+++ b/arch/arm/boot/dts/qcom/dsi-panel-jdi-a407-dualmipi-wqhd-cmd.dtsi
@@ -15,6 +15,7 @@
qcom,mdss-dsi-panel-name = "JDI a407 wqhd cmd mode dsi panel";
qcom,mdss-dsi-panel-type = "dsi_cmd_mode";
qcom,mdss-dsi-panel-framerate = <60>;
+ qcom,mdss-dsi-panel-clockrate = <838600000>;
qcom,mdss-dsi-virtual-channel-id = <0>;
qcom,mdss-dsi-stream = <0>;
qcom,mdss-dsi-panel-width = <720>;
@@ -79,6 +80,8 @@
qcom,adjust-timer-wakeup-ms = <1>;
qcom,mdss-dsi-reset-sequence = <1 20>, <0 10>, <1 20>;
+ qcom,dcs-cmd-by-left;
+
qcom,config-select = <&dsi_dual_jdi_a407_cmd_config0>;
dsi_dual_jdi_a407_cmd_config0: config0 {
diff --git a/arch/arm/boot/dts/qcom/dsi-panel-rm67195-amoled-fhd-cmd.dtsi b/arch/arm/boot/dts/qcom/dsi-panel-rm67195-amoled-fhd-cmd.dtsi
index 8757dad98b3e..7d3e3d362946 100644
--- a/arch/arm/boot/dts/qcom/dsi-panel-rm67195-amoled-fhd-cmd.dtsi
+++ b/arch/arm/boot/dts/qcom/dsi-panel-rm67195-amoled-fhd-cmd.dtsi
@@ -20,11 +20,11 @@
qcom,mdss-dsi-stream = <0>;
qcom,mdss-dsi-panel-width = <1080>;
qcom,mdss-dsi-panel-height = <1920>;
- qcom,mdss-dsi-h-front-porch = <32>;
- qcom,mdss-dsi-h-back-porch = <40>;
- qcom,mdss-dsi-h-pulse-width = <8>;
+ qcom,mdss-dsi-h-front-porch = <120>;
+ qcom,mdss-dsi-h-back-porch = <60>;
+ qcom,mdss-dsi-h-pulse-width = <12>;
qcom,mdss-dsi-h-sync-skew = <0>;
- qcom,mdss-dsi-v-back-porch = <16>;
+ qcom,mdss-dsi-v-back-porch = <12>;
qcom,mdss-dsi-v-front-porch = <8>;
qcom,mdss-dsi-v-pulse-width = <4>;
qcom,mdss-dsi-h-left-border = <0>;
@@ -52,8 +52,12 @@
15 01 00 00 00 00 02 28 40
15 01 00 00 02 00 02 29 4f
15 01 00 00 00 00 02 fe 04
+ 15 01 00 00 00 00 02 0a d8
+ 15 01 00 00 00 00 02 0c e6
+ 15 01 00 00 00 00 02 4e 20
15 01 00 00 00 00 02 4f 1b
- 15 01 00 00 02 00 02 50 2f
+ 15 01 00 00 00 00 02 50 2f
+ 15 01 00 00 02 00 02 51 08
15 01 00 00 00 00 02 fe 09
15 01 00 00 00 00 02 00 08
15 01 00 00 00 00 02 01 08
@@ -104,6 +108,8 @@
qcom,mdss-dsi-lane-1-state;
qcom,mdss-dsi-lane-2-state;
qcom,mdss-dsi-lane-3-state;
+ qcom,mdss-dsi-t-clk-post = <0x0d>;
+ qcom,mdss-dsi-t-clk-pre = <0x2f>;
qcom,mdss-dsi-wr-mem-start = <0x2c>;
qcom,mdss-dsi-wr-mem-continue = <0x3c>;
qcom,mdss-dsi-te-pin-select = <1>;
diff --git a/arch/arm/boot/dts/qcom/dsi-panel-sharp-split-link-wuxga-video.dtsi b/arch/arm/boot/dts/qcom/dsi-panel-sharp-split-link-wuxga-video.dtsi
new file mode 100644
index 000000000000..143b0152dcf4
--- /dev/null
+++ b/arch/arm/boot/dts/qcom/dsi-panel-sharp-split-link-wuxga-video.dtsi
@@ -0,0 +1,68 @@
+/* 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.
+ */
+
+&mdss_mdp {
+ dsi_sharp_split_link_wuxga_video:
+ qcom,mdss_dsi_sharp_split_link_wuxga_video {
+ qcom,mdss-dsi-panel-name =
+ "SHARP split DSI video mode dsi panel";
+ qcom,mdss-dsi-panel-type = "dsi_video_mode";
+ qcom,mdss-dsi-panel-framerate = <60>;
+ qcom,mdss-dsi-virtual-channel-id = <0>;
+ qcom,mdss-dsi-stream = <0>;
+ qcom,mdss-dsi-panel-width = <600>;
+ qcom,mdss-dsi-panel-height = <1920>;
+ qcom,mdss-dsi-h-front-porch = <54>;
+ qcom,mdss-dsi-h-back-porch = <4>;
+ qcom,mdss-dsi-h-pulse-width = <6>;
+ qcom,mdss-dsi-h-sync-skew = <0>;
+ qcom,mdss-dsi-v-back-porch = <6>;
+ qcom,mdss-dsi-v-front-porch = <12>;
+ qcom,mdss-dsi-v-pulse-width = <2>;
+ qcom,mdss-dsi-bpp = <24>;
+ qcom,mdss-dsi-underflow-color = <0x654321>;
+ qcom,mdss-dsi-border-color = <0>;
+ qcom,mdss-dsi-on-command = [05 01 00 00 a0 00 02 11 00];
+ qcom,mdss-dsi-pre-off-command = [05 01 00 00 02 00 02 28 00
+ 05 01 00 00 a0 00 02 10 00];
+ qcom,mdss-dsi-post-panel-on-command =
+ [05 01 00 00 a0 00 02 29 00];
+ qcom,mdss-dsi-on-command-state = "dsi_lp_mode";
+ qcom,mdss-dsi-off-command-state = "dsi_hs_mode";
+ qcom,mdss-dsi-h-sync-pulse = <0>;
+ qcom,mdss-dsi-traffic-mode = "non_burst_sync_event";
+ qcom,mdss-dsi-bllp-eof-power-mode;
+ qcom,mdss-dsi-bllp-power-mode;
+ qcom,mdss-dsi-lane-0-state;
+ qcom,mdss-dsi-lane-1-state;
+ qcom,mdss-dsi-lane-2-state;
+ qcom,mdss-dsi-lane-3-state;
+ qcom,mdss-dsi-panel-timings =
+ [00 24 07 08 0e 14 07 09 07 03 04 00];
+ qcom,mdss-dsi-t-clk-post = <0x0e>;
+ qcom,mdss-dsi-t-clk-pre = <0x35>;
+ qcom,mdss-dsi-bl-min-level = <1>;
+ qcom,mdss-dsi-bl-max-level = <4095>;
+ qcom,mdss-dsi-dma-trigger = "trigger_sw";
+ qcom,mdss-dsi-mdp-trigger = "none";
+ qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_pwm";
+ qcom,mdss-dsi-bl-pmic-pwm-frequency = <50>;
+ qcom,mdss-dsi-bl-pmic-bank-select = <2>;
+ qcom,mdss-dsi-reset-sequence = <1 2>, <0 5>, <1 120>;
+ qcom,mdss-pan-physical-width-dimension = <83>;
+ qcom,mdss-pan-physical-height-dimension = <133>;
+ qcom,mdss-dsi-tx-eot-append;
+ qcom,split-link-enabled = <1>;
+ qcom,sublinks-count = <2>;
+ qcom,lanes-per-sublink = <2>;
+ };
+};
diff --git a/arch/arm/boot/dts/qcom/msm-pm660.dtsi b/arch/arm/boot/dts/qcom/msm-pm660.dtsi
index 07bd9ea842f0..f20238123bca 100644
--- a/arch/arm/boot/dts/qcom/msm-pm660.dtsi
+++ b/arch/arm/boot/dts/qcom/msm-pm660.dtsi
@@ -287,6 +287,18 @@
qcom,vadc-thermal-node;
};
+ chan@4f {
+ label = "pa_therm0";
+ reg = <0x4f>;
+ qcom,decimation = <2>;
+ qcom,pre-div-channel-scaling = <0>;
+ qcom,calibration-type = "ratiometric";
+ qcom,scale-function = <2>;
+ qcom,hw-settle-time = <2>;
+ qcom,fast-avg-setup = <0>;
+ qcom,vadc-thermal-node;
+ };
+
chan@1d {
label = "drax_temp";
reg = <0x1d>;
@@ -527,8 +539,10 @@
#address-cells = <1>;
#size-cells = <1>;
qcom,pmic-revid = <&pm660_revid>;
- io-channels = <&pm660_rradc 0>;
- io-channel-names = "rradc_batt_id";
+ io-channels = <&pm660_rradc 0>,
+ <&pm660_rradc 7>;
+ 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>;
diff --git a/arch/arm/boot/dts/qcom/msm-pm660l.dtsi b/arch/arm/boot/dts/qcom/msm-pm660l.dtsi
index 7f386957d555..679149a78833 100644
--- a/arch/arm/boot/dts/qcom/msm-pm660l.dtsi
+++ b/arch/arm/boot/dts/qcom/msm-pm660l.dtsi
@@ -330,9 +330,6 @@
qcom,ires-ua = <12500>;
qcom,hdrm-voltage-mv = <325>;
qcom,hdrm-vol-hi-lo-win-mv = <100>;
- pinctrl-names = "led_enable","led_disable";
- pinctrl-0 = <&led_enable>;
- pinctrl-1 = <&led_disable>;
};
pm660l_torch0: qcom,torch_0 {
@@ -369,9 +366,6 @@
qcom,ires-ua = <12500>;
qcom,hdrm-voltage-mv = <325>;
qcom,hdrm-vol-hi-lo-win-mv = <100>;
- pinctrl-names = "led_enable","led_disable";
- pinctrl-0 = <&led_enable>;
- pinctrl-1 = <&led_disable>;
};
pm660l_switch0: qcom,led_switch_0 {
@@ -386,6 +380,9 @@
qcom,led-name = "led:switch_1";
qcom,led-mask = <4>;
qcom,default-led-trigger = "switch1_trigger";
+ pinctrl-names = "led_enable","led_disable";
+ pinctrl-0 = <&led_enable>;
+ pinctrl-1 = <&led_disable>;
};
};
@@ -418,7 +415,9 @@
compatible = "qcom,qpnp-oledb-regulator";
#address-cells = <1>;
#size-cells = <1>;
+ qcom,pmic-revid = <&pm660l_revid>;
reg = <0xe000 0x100>;
+ qcom,pbs-client = <&pm660l_pbs>;
label = "oledb";
regulator-name = "regulator-oledb";
@@ -466,6 +465,8 @@
qcom,qpnp-lab-slew-rate = <5000>;
qcom,qpnp-lab-init-voltage = <4600000>;
qcom,qpnp-lab-init-amoled-voltage = <4600000>;
+
+ qcom,notify-lab-vreg-ok-sts;
};
};
};
diff --git a/arch/arm/boot/dts/qcom/msm-pmi8998.dtsi b/arch/arm/boot/dts/qcom/msm-pmi8998.dtsi
index 0cf67dd938e6..2d2b628ca815 100644
--- a/arch/arm/boot/dts/qcom/msm-pmi8998.dtsi
+++ b/arch/arm/boot/dts/qcom/msm-pmi8998.dtsi
@@ -712,9 +712,6 @@
qcom,ires-ua = <12500>;
qcom,hdrm-voltage-mv = <325>;
qcom,hdrm-vol-hi-lo-win-mv = <100>;
- pinctrl-names = "led_enable","led_disable";
- pinctrl-0 = <&led_enable>;
- pinctrl-1 = <&led_disable>;
};
pmi8998_torch0: qcom,torch_0 {
@@ -751,9 +748,6 @@
qcom,ires-ua = <12500>;
qcom,hdrm-voltage-mv = <325>;
qcom,hdrm-vol-hi-lo-win-mv = <100>;
- pinctrl-names = "led_enable","led_disable";
- pinctrl-0 = <&led_enable>;
- pinctrl-1 = <&led_disable>;
};
pmi8998_switch0: qcom,led_switch_0 {
@@ -768,6 +762,9 @@
qcom,led-name = "led:switch_1";
qcom,led-mask = <4>;
qcom,default-led-trigger = "switch1_trigger";
+ pinctrl-names = "led_enable","led_disable";
+ pinctrl-0 = <&led_enable>;
+ pinctrl-1 = <&led_disable>;
};
};
};
diff --git a/arch/arm/boot/dts/qcom/msm8996-agave-adp.dtsi b/arch/arm/boot/dts/qcom/msm8996-agave-adp.dtsi
index d007e8bcfc33..c1fa33f5ca32 100644
--- a/arch/arm/boot/dts/qcom/msm8996-agave-adp.dtsi
+++ b/arch/arm/boot/dts/qcom/msm8996-agave-adp.dtsi
@@ -616,12 +616,13 @@
<&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",
@@ -633,12 +634,13 @@
"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";
};
@@ -678,9 +680,22 @@
};
qcom,msm-dai-tdm-tert-rx {
+ qcom,msm-cpudai-tdm-group-num-ports = <5>;
+ qcom,msm-cpudai-tdm-group-port-id = <36896 36898 36900
+ 36902 36904>;
pinctrl-names = "default", "sleep";
pinctrl-0 = <&tert_tdm_dout_active>;
pinctrl-1 = <&tert_tdm_dout_sleep>;
+ 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-quat-rx {
diff --git a/arch/arm/boot/dts/qcom/msm8996-auto-cdp.dtsi b/arch/arm/boot/dts/qcom/msm8996-auto-cdp.dtsi
index 97036ae144ae..a5a6bad16176 100644
--- a/arch/arm/boot/dts/qcom/msm8996-auto-cdp.dtsi
+++ b/arch/arm/boot/dts/qcom/msm8996-auto-cdp.dtsi
@@ -637,12 +637,13 @@
<&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",
@@ -654,12 +655,13 @@
"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";
};
@@ -709,6 +711,25 @@
};
};
+ qcom,msm-dai-tdm-tert-rx {
+ qcom,msm-cpudai-tdm-group-num-ports = <5>;
+ qcom,msm-cpudai-tdm-group-port-id = <36896 36898 36900
+ 36902 36904>;
+ pinctrl-names = "default", "sleep";
+ pinctrl-0 = <&tert_tdm_dout_active>;
+ pinctrl-1 = <&tert_tdm_dout_sleep>;
+ 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-quat-rx {
pinctrl-names = "default", "sleep";
pinctrl-0 = <&quat_tdm_dout_active>;
@@ -974,14 +995,14 @@
};
&pcie1 {
- /delete-property/ qcom,ep-wakeirq;
+ /delete-property/ qcom,boot-option;
};
&pcie2 {
perst-gpio = <&tlmm 90 0>;
wake-gpio = <&tlmm 54 0>;
- /delete-property/ qcom,ep-wakeirq;
+ /delete-property/ qcom,boot-option;
};
&wsa881x_211 {
diff --git a/arch/arm/boot/dts/qcom/msm8996-mmxf-adp.dtsi b/arch/arm/boot/dts/qcom/msm8996-mmxf-adp.dtsi
index b6e6fb4193b4..c5b6e7d0a3dc 100644
--- a/arch/arm/boot/dts/qcom/msm8996-mmxf-adp.dtsi
+++ b/arch/arm/boot/dts/qcom/msm8996-mmxf-adp.dtsi
@@ -542,12 +542,13 @@
<&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",
@@ -559,12 +560,13 @@
"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";
};
@@ -592,6 +594,25 @@
};
};
+ qcom,msm-dai-tdm-tert-rx {
+ qcom,msm-cpudai-tdm-group-num-ports = <5>;
+ qcom,msm-cpudai-tdm-group-port-id = <36896 36898 36900
+ 36902 36904>;
+ pinctrl-names = "default", "sleep";
+ pinctrl-0 = <&tert_tdm_dout_active>;
+ pinctrl-1 = <&tert_tdm_dout_sleep>;
+ 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-quat-rx {
pinctrl-names = "default", "sleep";
pinctrl-0 = <&quat_tdm_dout_active>;
diff --git a/arch/arm/boot/dts/qcom/msm8996.dtsi b/arch/arm/boot/dts/qcom/msm8996.dtsi
index 7c0f8e3c331f..398aee9d3ab8 100644
--- a/arch/arm/boot/dts/qcom/msm8996.dtsi
+++ b/arch/arm/boot/dts/qcom/msm8996.dtsi
@@ -1284,50 +1284,50 @@
39 40 41 42 43>;
#interrupt-cells = <1>;
interrupt-map-mask = <0x0 0x0 0x0 0xffffffff>;
- interrupt-map = <0x0 0x0 0x0 0 &intc 0 405 0
- 0x0 0x0 0x0 1 &intc 0 244 0
- 0x0 0x0 0x0 2 &intc 0 245 0
- 0x0 0x0 0x0 3 &intc 0 247 0
- 0x0 0x0 0x0 4 &intc 0 248 0
- 0x0 0x0 0x0 5 &intc 0 249 0
- 0x0 0x0 0x0 6 &intc 0 250 0
- 0x0 0x0 0x0 7 &intc 0 251 0
- 0x0 0x0 0x0 8 &intc 0 252 0
- 0x0 0x0 0x0 9 &intc 0 253 0
- 0x0 0x0 0x0 10 &intc 0 254 0
- 0x0 0x0 0x0 11 &intc 0 255 0
- 0x0 0x0 0x0 12 &intc 0 512 0
- 0x0 0x0 0x0 13 &intc 0 513 0
- 0x0 0x0 0x0 14 &intc 0 514 0
- 0x0 0x0 0x0 15 &intc 0 515 0
- 0x0 0x0 0x0 16 &intc 0 516 0
- 0x0 0x0 0x0 17 &intc 0 517 0
- 0x0 0x0 0x0 18 &intc 0 518 0
- 0x0 0x0 0x0 19 &intc 0 519 0
- 0x0 0x0 0x0 20 &intc 0 520 0
- 0x0 0x0 0x0 21 &intc 0 521 0
- 0x0 0x0 0x0 22 &intc 0 522 0
- 0x0 0x0 0x0 23 &intc 0 523 0
- 0x0 0x0 0x0 24 &intc 0 524 0
- 0x0 0x0 0x0 25 &intc 0 525 0
- 0x0 0x0 0x0 26 &intc 0 526 0
- 0x0 0x0 0x0 27 &intc 0 527 0
- 0x0 0x0 0x0 28 &intc 0 528 0
- 0x0 0x0 0x0 29 &intc 0 529 0
- 0x0 0x0 0x0 30 &intc 0 530 0
- 0x0 0x0 0x0 31 &intc 0 531 0
- 0x0 0x0 0x0 32 &intc 0 532 0
- 0x0 0x0 0x0 33 &intc 0 533 0
- 0x0 0x0 0x0 34 &intc 0 534 0
- 0x0 0x0 0x0 35 &intc 0 535 0
- 0x0 0x0 0x0 36 &intc 0 536 0
- 0x0 0x0 0x0 37 &intc 0 537 0
- 0x0 0x0 0x0 38 &intc 0 538 0
- 0x0 0x0 0x0 39 &intc 0 539 0
- 0x0 0x0 0x0 40 &intc 0 540 0
- 0x0 0x0 0x0 41 &intc 0 541 0
- 0x0 0x0 0x0 42 &intc 0 542 0
- 0x0 0x0 0x0 43 &intc 0 543 0>;
+ interrupt-map = <0x0 0x0 0x0 0 &intc 0 0 405 0
+ 0x0 0x0 0x0 1 &intc 0 0 244 0
+ 0x0 0x0 0x0 2 &intc 0 0 245 0
+ 0x0 0x0 0x0 3 &intc 0 0 247 0
+ 0x0 0x0 0x0 4 &intc 0 0 248 0
+ 0x0 0x0 0x0 5 &intc 0 0 249 0
+ 0x0 0x0 0x0 6 &intc 0 0 250 0
+ 0x0 0x0 0x0 7 &intc 0 0 251 0
+ 0x0 0x0 0x0 8 &intc 0 0 252 0
+ 0x0 0x0 0x0 9 &intc 0 0 253 0
+ 0x0 0x0 0x0 10 &intc 0 0 254 0
+ 0x0 0x0 0x0 11 &intc 0 0 255 0
+ 0x0 0x0 0x0 12 &intc 0 0 512 0
+ 0x0 0x0 0x0 13 &intc 0 0 513 0
+ 0x0 0x0 0x0 14 &intc 0 0 514 0
+ 0x0 0x0 0x0 15 &intc 0 0 515 0
+ 0x0 0x0 0x0 16 &intc 0 0 516 0
+ 0x0 0x0 0x0 17 &intc 0 0 517 0
+ 0x0 0x0 0x0 18 &intc 0 0 518 0
+ 0x0 0x0 0x0 19 &intc 0 0 519 0
+ 0x0 0x0 0x0 20 &intc 0 0 520 0
+ 0x0 0x0 0x0 21 &intc 0 0 521 0
+ 0x0 0x0 0x0 22 &intc 0 0 522 0
+ 0x0 0x0 0x0 23 &intc 0 0 523 0
+ 0x0 0x0 0x0 24 &intc 0 0 524 0
+ 0x0 0x0 0x0 25 &intc 0 0 525 0
+ 0x0 0x0 0x0 26 &intc 0 0 526 0
+ 0x0 0x0 0x0 27 &intc 0 0 527 0
+ 0x0 0x0 0x0 28 &intc 0 0 528 0
+ 0x0 0x0 0x0 29 &intc 0 0 529 0
+ 0x0 0x0 0x0 30 &intc 0 0 530 0
+ 0x0 0x0 0x0 31 &intc 0 0 531 0
+ 0x0 0x0 0x0 32 &intc 0 0 532 0
+ 0x0 0x0 0x0 33 &intc 0 0 533 0
+ 0x0 0x0 0x0 34 &intc 0 0 534 0
+ 0x0 0x0 0x0 35 &intc 0 0 535 0
+ 0x0 0x0 0x0 36 &intc 0 0 536 0
+ 0x0 0x0 0x0 37 &intc 0 0 537 0
+ 0x0 0x0 0x0 38 &intc 0 0 538 0
+ 0x0 0x0 0x0 39 &intc 0 0 539 0
+ 0x0 0x0 0x0 40 &intc 0 0 540 0
+ 0x0 0x0 0x0 41 &intc 0 0 541 0
+ 0x0 0x0 0x0 42 &intc 0 0 542 0
+ 0x0 0x0 0x0 43 &intc 0 0 543 0>;
interrupt-names = "int_msi", "int_a", "int_b", "int_c", "int_d",
"int_pls_pme", "int_pme_legacy", "int_pls_err",
@@ -1371,7 +1371,7 @@
iommus = <&anoc0_smmu>;
- qcom,ep-wakeirq;
+ qcom,boot-option = <0x1>;
linux,pci-domain = <0>;
@@ -1440,50 +1440,50 @@
39 40 41 42 43>;
#interrupt-cells = <1>;
interrupt-map-mask = <0x0 0x0 0x0 0xffffffff>;
- interrupt-map = <0x0 0x0 0x0 0 &intc 0 413 0
- 0x0 0x0 0x0 1 &intc 0 272 0
- 0x0 0x0 0x0 2 &intc 0 273 0
- 0x0 0x0 0x0 3 &intc 0 274 0
- 0x0 0x0 0x0 4 &intc 0 275 0
- 0x0 0x0 0x0 5 &intc 0 276 0
- 0x0 0x0 0x0 6 &intc 0 277 0
- 0x0 0x0 0x0 7 &intc 0 278 0
- 0x0 0x0 0x0 8 &intc 0 279 0
- 0x0 0x0 0x0 9 &intc 0 280 0
- 0x0 0x0 0x0 10 &intc 0 281 0
- 0x0 0x0 0x0 11 &intc 0 282 0
- 0x0 0x0 0x0 12 &intc 0 544 0
- 0x0 0x0 0x0 13 &intc 0 545 0
- 0x0 0x0 0x0 14 &intc 0 546 0
- 0x0 0x0 0x0 15 &intc 0 547 0
- 0x0 0x0 0x0 16 &intc 0 548 0
- 0x0 0x0 0x0 17 &intc 0 549 0
- 0x0 0x0 0x0 18 &intc 0 550 0
- 0x0 0x0 0x0 19 &intc 0 551 0
- 0x0 0x0 0x0 20 &intc 0 552 0
- 0x0 0x0 0x0 21 &intc 0 553 0
- 0x0 0x0 0x0 22 &intc 0 554 0
- 0x0 0x0 0x0 23 &intc 0 555 0
- 0x0 0x0 0x0 24 &intc 0 556 0
- 0x0 0x0 0x0 25 &intc 0 557 0
- 0x0 0x0 0x0 26 &intc 0 558 0
- 0x0 0x0 0x0 27 &intc 0 559 0
- 0x0 0x0 0x0 28 &intc 0 560 0
- 0x0 0x0 0x0 29 &intc 0 561 0
- 0x0 0x0 0x0 30 &intc 0 562 0
- 0x0 0x0 0x0 31 &intc 0 563 0
- 0x0 0x0 0x0 32 &intc 0 564 0
- 0x0 0x0 0x0 33 &intc 0 565 0
- 0x0 0x0 0x0 34 &intc 0 566 0
- 0x0 0x0 0x0 35 &intc 0 567 0
- 0x0 0x0 0x0 36 &intc 0 568 0
- 0x0 0x0 0x0 37 &intc 0 569 0
- 0x0 0x0 0x0 38 &intc 0 570 0
- 0x0 0x0 0x0 39 &intc 0 571 0
- 0x0 0x0 0x0 40 &intc 0 572 0
- 0x0 0x0 0x0 41 &intc 0 573 0
- 0x0 0x0 0x0 42 &intc 0 574 0
- 0x0 0x0 0x0 43 &intc 0 575 0>;
+ interrupt-map = <0x0 0x0 0x0 0 &intc 0 0 413 0
+ 0x0 0x0 0x0 1 &intc 0 0 272 0
+ 0x0 0x0 0x0 2 &intc 0 0 273 0
+ 0x0 0x0 0x0 3 &intc 0 0 274 0
+ 0x0 0x0 0x0 4 &intc 0 0 275 0
+ 0x0 0x0 0x0 5 &intc 0 0 276 0
+ 0x0 0x0 0x0 6 &intc 0 0 277 0
+ 0x0 0x0 0x0 7 &intc 0 0 278 0
+ 0x0 0x0 0x0 8 &intc 0 0 279 0
+ 0x0 0x0 0x0 9 &intc 0 0 280 0
+ 0x0 0x0 0x0 10 &intc 0 0 281 0
+ 0x0 0x0 0x0 11 &intc 0 0 282 0
+ 0x0 0x0 0x0 12 &intc 0 0 544 0
+ 0x0 0x0 0x0 13 &intc 0 0 545 0
+ 0x0 0x0 0x0 14 &intc 0 0 546 0
+ 0x0 0x0 0x0 15 &intc 0 0 547 0
+ 0x0 0x0 0x0 16 &intc 0 0 548 0
+ 0x0 0x0 0x0 17 &intc 0 0 549 0
+ 0x0 0x0 0x0 18 &intc 0 0 550 0
+ 0x0 0x0 0x0 19 &intc 0 0 551 0
+ 0x0 0x0 0x0 20 &intc 0 0 552 0
+ 0x0 0x0 0x0 21 &intc 0 0 553 0
+ 0x0 0x0 0x0 22 &intc 0 0 554 0
+ 0x0 0x0 0x0 23 &intc 0 0 555 0
+ 0x0 0x0 0x0 24 &intc 0 0 556 0
+ 0x0 0x0 0x0 25 &intc 0 0 557 0
+ 0x0 0x0 0x0 26 &intc 0 0 558 0
+ 0x0 0x0 0x0 27 &intc 0 0 559 0
+ 0x0 0x0 0x0 28 &intc 0 0 560 0
+ 0x0 0x0 0x0 29 &intc 0 0 561 0
+ 0x0 0x0 0x0 30 &intc 0 0 562 0
+ 0x0 0x0 0x0 31 &intc 0 0 563 0
+ 0x0 0x0 0x0 32 &intc 0 0 564 0
+ 0x0 0x0 0x0 33 &intc 0 0 565 0
+ 0x0 0x0 0x0 34 &intc 0 0 566 0
+ 0x0 0x0 0x0 35 &intc 0 0 567 0
+ 0x0 0x0 0x0 36 &intc 0 0 568 0
+ 0x0 0x0 0x0 37 &intc 0 0 569 0
+ 0x0 0x0 0x0 38 &intc 0 0 570 0
+ 0x0 0x0 0x0 39 &intc 0 0 571 0
+ 0x0 0x0 0x0 40 &intc 0 0 572 0
+ 0x0 0x0 0x0 41 &intc 0 0 573 0
+ 0x0 0x0 0x0 42 &intc 0 0 574 0
+ 0x0 0x0 0x0 43 &intc 0 0 575 0>;
interrupt-names = "int_msi", "int_a", "int_b", "int_c", "int_d",
"int_pls_pme", "int_pme_legacy", "int_pls_err",
@@ -1524,7 +1524,7 @@
iommus = <&anoc0_smmu>;
- qcom,ep-wakeirq;
+ qcom,boot-option = <0x1>;
qcom,ep-latency = <10>;
@@ -1592,50 +1592,50 @@
39 40 41 42 43>;
#interrupt-cells = <1>;
interrupt-map-mask = <0x0 0x0 0x0 0xffffffff>;
- interrupt-map = <0x0 0x0 0x0 0 &intc 0 421 0
- 0x0 0x0 0x0 1 &intc 0 142 0
- 0x0 0x0 0x0 2 &intc 0 143 0
- 0x0 0x0 0x0 3 &intc 0 144 0
- 0x0 0x0 0x0 4 &intc 0 145 0
- 0x0 0x0 0x0 5 &intc 0 146 0
- 0x0 0x0 0x0 6 &intc 0 147 0
- 0x0 0x0 0x0 7 &intc 0 148 0
- 0x0 0x0 0x0 8 &intc 0 149 0
- 0x0 0x0 0x0 9 &intc 0 260 0
- 0x0 0x0 0x0 10 &intc 0 261 0
- 0x0 0x0 0x0 11 &intc 0 262 0
- 0x0 0x0 0x0 12 &intc 0 576 0
- 0x0 0x0 0x0 13 &intc 0 577 0
- 0x0 0x0 0x0 14 &intc 0 578 0
- 0x0 0x0 0x0 15 &intc 0 579 0
- 0x0 0x0 0x0 16 &intc 0 580 0
- 0x0 0x0 0x0 17 &intc 0 581 0
- 0x0 0x0 0x0 18 &intc 0 582 0
- 0x0 0x0 0x0 19 &intc 0 583 0
- 0x0 0x0 0x0 20 &intc 0 584 0
- 0x0 0x0 0x0 21 &intc 0 585 0
- 0x0 0x0 0x0 22 &intc 0 586 0
- 0x0 0x0 0x0 23 &intc 0 587 0
- 0x0 0x0 0x0 24 &intc 0 588 0
- 0x0 0x0 0x0 25 &intc 0 589 0
- 0x0 0x0 0x0 26 &intc 0 590 0
- 0x0 0x0 0x0 27 &intc 0 591 0
- 0x0 0x0 0x0 28 &intc 0 592 0
- 0x0 0x0 0x0 29 &intc 0 593 0
- 0x0 0x0 0x0 30 &intc 0 594 0
- 0x0 0x0 0x0 31 &intc 0 595 0
- 0x0 0x0 0x0 32 &intc 0 596 0
- 0x0 0x0 0x0 33 &intc 0 597 0
- 0x0 0x0 0x0 34 &intc 0 598 0
- 0x0 0x0 0x0 35 &intc 0 599 0
- 0x0 0x0 0x0 36 &intc 0 600 0
- 0x0 0x0 0x0 37 &intc 0 601 0
- 0x0 0x0 0x0 38 &intc 0 602 0
- 0x0 0x0 0x0 39 &intc 0 603 0
- 0x0 0x0 0x0 40 &intc 0 604 0
- 0x0 0x0 0x0 41 &intc 0 605 0
- 0x0 0x0 0x0 42 &intc 0 606 0
- 0x0 0x0 0x0 43 &intc 0 607 0>;
+ interrupt-map = <0x0 0x0 0x0 0 &intc 0 0 421 0
+ 0x0 0x0 0x0 1 &intc 0 0 142 0
+ 0x0 0x0 0x0 2 &intc 0 0 143 0
+ 0x0 0x0 0x0 3 &intc 0 0 144 0
+ 0x0 0x0 0x0 4 &intc 0 0 145 0
+ 0x0 0x0 0x0 5 &intc 0 0 146 0
+ 0x0 0x0 0x0 6 &intc 0 0 147 0
+ 0x0 0x0 0x0 7 &intc 0 0 148 0
+ 0x0 0x0 0x0 8 &intc 0 0 149 0
+ 0x0 0x0 0x0 9 &intc 0 0 260 0
+ 0x0 0x0 0x0 10 &intc 0 0 261 0
+ 0x0 0x0 0x0 11 &intc 0 0 262 0
+ 0x0 0x0 0x0 12 &intc 0 0 576 0
+ 0x0 0x0 0x0 13 &intc 0 0 577 0
+ 0x0 0x0 0x0 14 &intc 0 0 578 0
+ 0x0 0x0 0x0 15 &intc 0 0 579 0
+ 0x0 0x0 0x0 16 &intc 0 0 580 0
+ 0x0 0x0 0x0 17 &intc 0 0 581 0
+ 0x0 0x0 0x0 18 &intc 0 0 582 0
+ 0x0 0x0 0x0 19 &intc 0 0 583 0
+ 0x0 0x0 0x0 20 &intc 0 0 584 0
+ 0x0 0x0 0x0 21 &intc 0 0 585 0
+ 0x0 0x0 0x0 22 &intc 0 0 586 0
+ 0x0 0x0 0x0 23 &intc 0 0 587 0
+ 0x0 0x0 0x0 24 &intc 0 0 588 0
+ 0x0 0x0 0x0 25 &intc 0 0 589 0
+ 0x0 0x0 0x0 26 &intc 0 0 590 0
+ 0x0 0x0 0x0 27 &intc 0 0 591 0
+ 0x0 0x0 0x0 28 &intc 0 0 592 0
+ 0x0 0x0 0x0 29 &intc 0 0 593 0
+ 0x0 0x0 0x0 30 &intc 0 0 594 0
+ 0x0 0x0 0x0 31 &intc 0 0 595 0
+ 0x0 0x0 0x0 32 &intc 0 0 596 0
+ 0x0 0x0 0x0 33 &intc 0 0 597 0
+ 0x0 0x0 0x0 34 &intc 0 0 598 0
+ 0x0 0x0 0x0 35 &intc 0 0 599 0
+ 0x0 0x0 0x0 36 &intc 0 0 600 0
+ 0x0 0x0 0x0 37 &intc 0 0 601 0
+ 0x0 0x0 0x0 38 &intc 0 0 602 0
+ 0x0 0x0 0x0 39 &intc 0 0 603 0
+ 0x0 0x0 0x0 40 &intc 0 0 604 0
+ 0x0 0x0 0x0 41 &intc 0 0 605 0
+ 0x0 0x0 0x0 42 &intc 0 0 606 0
+ 0x0 0x0 0x0 43 &intc 0 0 607 0>;
interrupt-names = "int_msi", "int_a", "int_b", "int_c", "int_d",
"int_pls_pme", "int_pme_legacy", "int_pls_err",
@@ -1677,7 +1677,7 @@
iommus = <&anoc0_smmu>;
- qcom,ep-wakeirq;
+ qcom,boot-option = <0x1>;
qcom,ep-latency = <10>;
diff --git a/arch/arm/boot/dts/qcom/msm8998-cdp-overlay.dts b/arch/arm/boot/dts/qcom/msm8998-cdp-overlay.dts
new file mode 100644
index 000000000000..5fe0d0176618
--- /dev/null
+++ b/arch/arm/boot/dts/qcom/msm8998-cdp-overlay.dts
@@ -0,0 +1,28 @@
+/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+
+/dts-v1/;
+/plugin/;
+
+#include <dt-bindings/clock/msm-clocks-8998.h>
+#include <dt-bindings/regulator/qcom,rpm-smd-regulator.h>
+#include <dt-bindings/interrupt-controller/arm-gic.h>
+
+#include "msm8998-cdp.dtsi"
+
+/ {
+ model = "Qualcomm Technologies, Inc. MSM 8998 v1 CDP";
+ compatible = "qcom,msm8998-cdp", "qcom,msm8998", "qcom,cdp";
+ qcom,msm-id = <292 0x0>;
+ qcom,board-id = <1 0>;
+};
diff --git a/arch/arm/boot/dts/qcom/msm8998-cdp.dtsi b/arch/arm/boot/dts/qcom/msm8998-cdp.dtsi
index 2b925250c5c0..9f57fa5127d7 100644
--- a/arch/arm/boot/dts/qcom/msm8998-cdp.dtsi
+++ b/arch/arm/boot/dts/qcom/msm8998-cdp.dtsi
@@ -10,9 +10,8 @@
* GNU General Public License for more details.
*/
-#include "msm8998-pinctrl.dtsi"
#include "msm8998-camera-sensor-cdp.dtsi"
-/ {
+&vendor {
bluetooth: bt_wcn3990 {
compatible = "qca,wcn3990";
qca,bt-vdd-io-supply = <&pm8998_s3>;
diff --git a/arch/arm/boot/dts/qcom/msm8998-interposer-sdm660.dtsi b/arch/arm/boot/dts/qcom/msm8998-interposer-sdm660.dtsi
index cfb71e3b1cb3..4a47942ce5dd 100644
--- a/arch/arm/boot/dts/qcom/msm8998-interposer-sdm660.dtsi
+++ b/arch/arm/boot/dts/qcom/msm8998-interposer-sdm660.dtsi
@@ -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
@@ -1590,7 +1590,7 @@
qcom,ep-latency = <10>;
- qcom,ep-wakeirq;
+ qcom,boot-option = <0x1>;
linux,pci-domain = <0>;
diff --git a/arch/arm/boot/dts/qcom/msm8998-mdss-panels.dtsi b/arch/arm/boot/dts/qcom/msm8998-mdss-panels.dtsi
index d0d13332595a..64f377f1a576 100644
--- a/arch/arm/boot/dts/qcom/msm8998-mdss-panels.dtsi
+++ b/arch/arm/boot/dts/qcom/msm8998-mdss-panels.dtsi
@@ -10,8 +10,6 @@
* GNU General Public License for more details.
*/
-#include "dsi-panel-sim-video.dtsi"
-#include "dsi-panel-sim-dualmipi-video.dtsi"
#include "dsi-panel-nt35597-dualmipi-wqxga-video.dtsi"
#include "dsi-panel-nt35597-dualmipi-wqxga-cmd.dtsi"
#include "dsi-panel-nt35597-truly-dualmipi-wqxga-video.dtsi"
diff --git a/arch/arm/boot/dts/qcom/msm8998-mtp-overlay.dts b/arch/arm/boot/dts/qcom/msm8998-mtp-overlay.dts
new file mode 100644
index 000000000000..8525d781aae2
--- /dev/null
+++ b/arch/arm/boot/dts/qcom/msm8998-mtp-overlay.dts
@@ -0,0 +1,28 @@
+/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+
+/dts-v1/;
+/plugin/;
+
+#include <dt-bindings/clock/msm-clocks-8998.h>
+#include <dt-bindings/regulator/qcom,rpm-smd-regulator.h>
+#include <dt-bindings/interrupt-controller/arm-gic.h>
+
+#include "msm8998-mtp.dtsi"
+
+/ {
+ model = "Qualcomm Technologies, Inc. MSM 8998 v1 MTP";
+ compatible = "qcom,msm8998-mtp", "qcom,msm8998", "qcom,mtp";
+ qcom,msm-id = <292 0x0>;
+ qcom,board-id = <8 0>;
+};
diff --git a/arch/arm/boot/dts/qcom/msm8998-mtp.dtsi b/arch/arm/boot/dts/qcom/msm8998-mtp.dtsi
index f7dcfc7c149f..859e77679e44 100644
--- a/arch/arm/boot/dts/qcom/msm8998-mtp.dtsi
+++ b/arch/arm/boot/dts/qcom/msm8998-mtp.dtsi
@@ -11,9 +11,8 @@
*/
#include <dt-bindings/interrupt-controller/irq.h>
-#include "msm8998-pinctrl.dtsi"
#include "msm8998-camera-sensor-mtp.dtsi"
-/ {
+&vendor {
bluetooth: bt_wcn3990 {
compatible = "qca,wcn3990";
qca,bt-vdd-io-supply = <&pm8998_s3>;
@@ -586,7 +585,7 @@
};
};
-/{
+&vendor {
mtp_batterydata: qcom,battery-data {
qcom,batt-id-range-pct = <15>;
#include "fg-gen3-batterydata-itech-3000mah.dtsi"
diff --git a/arch/arm/boot/dts/qcom/msm8998-pinctrl.dtsi b/arch/arm/boot/dts/qcom/msm8998-pinctrl.dtsi
index d2e18db982ef..220bad31d7f8 100644
--- a/arch/arm/boot/dts/qcom/msm8998-pinctrl.dtsi
+++ b/arch/arm/boot/dts/qcom/msm8998-pinctrl.dtsi
@@ -1960,16 +1960,28 @@
led_enable: led_enable {
mux {
pins = "gpio21";
- drive_strength = <16>;
+ function = "gpio";
+ };
+
+ config {
+ pins = "gpio21";
+ drive_strength = <2>;
output-high;
+ bias-disable;
};
};
led_disable: led_disable {
mux {
pins = "gpio21";
+ function = "gpio";
+ };
+
+ config {
+ pins = "gpio21";
drive_strength = <2>;
output-low;
+ bias-disable;
};
};
diff --git a/arch/arm/boot/dts/qcom/msm8998-qrd-skuk.dtsi b/arch/arm/boot/dts/qcom/msm8998-qrd-skuk.dtsi
index bc87b375ff50..97c4c5b1d455 100644
--- a/arch/arm/boot/dts/qcom/msm8998-qrd-skuk.dtsi
+++ b/arch/arm/boot/dts/qcom/msm8998-qrd-skuk.dtsi
@@ -289,7 +289,7 @@
qcom,panel-supply-entries = <&dsi_panel_pwr_supply>;
};
-/{
+&vendor {
qrd_batterydata: qcom,battery-data {
qcom,batt-id-range-pct = <15>;
#include "fg-gen3-batterydata-qrd-skuk-4v4-3000mah.dtsi"
diff --git a/arch/arm/boot/dts/qcom/msm8998-qrd-vr1.dtsi b/arch/arm/boot/dts/qcom/msm8998-qrd-vr1.dtsi
index aa95872da385..0d0c66d7f26e 100644
--- a/arch/arm/boot/dts/qcom/msm8998-qrd-vr1.dtsi
+++ b/arch/arm/boot/dts/qcom/msm8998-qrd-vr1.dtsi
@@ -219,7 +219,7 @@
};
};
-/{
+&vendor {
qrd_batterydata: qcom,battery-data {
qcom,batt-id-range-pct = <15>;
#include "fg-gen3-batterydata-qrd-skuk-4v4-3000mah.dtsi"
diff --git a/arch/arm/boot/dts/qcom/msm8998-qrd.dtsi b/arch/arm/boot/dts/qcom/msm8998-qrd.dtsi
index 1c2db6833bde..a3eb3e5ab0d0 100644
--- a/arch/arm/boot/dts/qcom/msm8998-qrd.dtsi
+++ b/arch/arm/boot/dts/qcom/msm8998-qrd.dtsi
@@ -539,7 +539,7 @@
};
};
-/{
+&vendor {
qrd_batterydata: qcom,battery-data {
qcom,batt-id-range-pct = <15>;
#include "fg-gen3-batterydata-itech-3000mah.dtsi"
diff --git a/arch/arm/boot/dts/qcom/msm8998-v2-cdp-overlay.dts b/arch/arm/boot/dts/qcom/msm8998-v2-cdp-overlay.dts
new file mode 100644
index 000000000000..c602459815b2
--- /dev/null
+++ b/arch/arm/boot/dts/qcom/msm8998-v2-cdp-overlay.dts
@@ -0,0 +1,28 @@
+/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+
+/dts-v1/;
+/plugin/;
+
+#include <dt-bindings/clock/msm-clocks-8998.h>
+#include <dt-bindings/regulator/qcom,rpm-smd-regulator.h>
+#include <dt-bindings/interrupt-controller/arm-gic.h>
+
+#include "msm8998-cdp.dtsi"
+
+/ {
+ model = "Qualcomm Technologies, Inc. MSM 8998 v2 CDP";
+ compatible = "qcom,msm8998-cdp", "qcom,msm8998", "qcom,cdp";
+ qcom,msm-id = <292 0x20000>;
+ qcom,board-id = <1 0>;
+};
diff --git a/arch/arm/boot/dts/qcom/msm8998-v2-mtp-overlay.dts b/arch/arm/boot/dts/qcom/msm8998-v2-mtp-overlay.dts
new file mode 100644
index 000000000000..660fc4d51f9f
--- /dev/null
+++ b/arch/arm/boot/dts/qcom/msm8998-v2-mtp-overlay.dts
@@ -0,0 +1,28 @@
+/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+
+/dts-v1/;
+/plugin/;
+
+#include <dt-bindings/clock/msm-clocks-8998.h>
+#include <dt-bindings/regulator/qcom,rpm-smd-regulator.h>
+#include <dt-bindings/interrupt-controller/arm-gic.h>
+
+#include "msm8998-mtp.dtsi"
+
+/ {
+ model = "Qualcomm Technologies, Inc. MSM 8998 v2 MTP";
+ compatible = "qcom,msm8998-mtp", "qcom,msm8998", "qcom,mtp";
+ qcom,msm-id = <292 0x20000>;
+ qcom,board-id = <8 0>;
+};
diff --git a/arch/arm/boot/dts/qcom/msm8998-v2.1-cdp-overlay.dts b/arch/arm/boot/dts/qcom/msm8998-v2.1-cdp-overlay.dts
new file mode 100644
index 000000000000..47c55a045017
--- /dev/null
+++ b/arch/arm/boot/dts/qcom/msm8998-v2.1-cdp-overlay.dts
@@ -0,0 +1,28 @@
+/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+
+/dts-v1/;
+/plugin/;
+
+#include <dt-bindings/clock/msm-clocks-8998.h>
+#include <dt-bindings/regulator/qcom,rpm-smd-regulator.h>
+#include <dt-bindings/interrupt-controller/arm-gic.h>
+
+#include "msm8998-cdp.dtsi"
+
+/ {
+ model = "Qualcomm Technologies, Inc. MSM 8998 v2.1 CDP";
+ compatible = "qcom,msm8998-cdp", "qcom,msm8998", "qcom,cdp";
+ qcom,msm-id = <292 0x20001>;
+ qcom,board-id = <1 0>;
+};
diff --git a/arch/arm/boot/dts/qcom/msm8998-v2.1-mtp-overlay.dts b/arch/arm/boot/dts/qcom/msm8998-v2.1-mtp-overlay.dts
new file mode 100644
index 000000000000..54a0e98cdce7
--- /dev/null
+++ b/arch/arm/boot/dts/qcom/msm8998-v2.1-mtp-overlay.dts
@@ -0,0 +1,28 @@
+/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+
+/dts-v1/;
+/plugin/;
+
+#include <dt-bindings/clock/msm-clocks-8998.h>
+#include <dt-bindings/regulator/qcom,rpm-smd-regulator.h>
+#include <dt-bindings/interrupt-controller/arm-gic.h>
+
+#include "msm8998-mtp.dtsi"
+
+/ {
+ model = "Qualcomm Technologies, Inc. MSM 8998 v2.1 MTP";
+ compatible = "qcom,msm8998-mtp", "qcom,msm8998", "qcom,mtp";
+ qcom,msm-id = <292 0x20001>;
+ qcom,board-id = <8 0>;
+};
diff --git a/arch/arm/boot/dts/qcom/msm8998-v2.1.dts b/arch/arm/boot/dts/qcom/msm8998-v2.1.dts
new file mode 100644
index 000000000000..64559c71307f
--- /dev/null
+++ b/arch/arm/boot/dts/qcom/msm8998-v2.1.dts
@@ -0,0 +1,23 @@
+/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+
+/dts-v1/;
+
+#include <dt-bindings/clock/msm-clocks-8998.h>
+#include "msm8998-v2.1.dtsi"
+
+/ {
+ model = "Qualcomm Technologies, Inc. MSM 8998 v2.1 SoC";
+ compatible = "qcom,msm8998";
+ qcom,board-id = <0 0>;
+};
diff --git a/arch/arm/boot/dts/qcom/msm8998-v2.dts b/arch/arm/boot/dts/qcom/msm8998-v2.dts
new file mode 100644
index 000000000000..f1b5af9f14c8
--- /dev/null
+++ b/arch/arm/boot/dts/qcom/msm8998-v2.dts
@@ -0,0 +1,23 @@
+/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+
+/dts-v1/;
+
+#include <dt-bindings/clock/msm-clocks-8998.h>
+#include "msm8998-v2.dtsi"
+
+/ {
+ model = "Qualcomm Technologies, Inc. MSM 8998 v2 SoC";
+ compatible = "qcom,msm8998";
+ qcom,board-id = <0 0>;
+};
diff --git a/arch/arm/boot/dts/qcom/msm8998-v2.dtsi b/arch/arm/boot/dts/qcom/msm8998-v2.dtsi
index 348faf9b69c3..b2f30de94bbc 100644
--- a/arch/arm/boot/dts/qcom/msm8998-v2.dtsi
+++ b/arch/arm/boot/dts/qcom/msm8998-v2.dtsi
@@ -591,53 +591,53 @@
qcom,cpr-open-loop-voltage-adjustment =
/* Speed bin 0 */
- <(-4000) (-4000) (-4000) (-4000) (-4000)
- (-4000) (-4000) (-4000) (-8000) (-8000)
- (-8000) (-12000) (-12000) (-12000) (-12000)
+ < 0 0 0 0 0
+ 0 0 0 0 0
+ 0 (-12000) (-12000) (-12000) (-12000)
(-12000) (-16000) (-16000) (-20000) (-24000)
(-28000) (-28000)>,
/* Speed bin 1 */
- <(-4000) (-4000) (-4000) (-4000) (-4000)
- (-4000) (-4000) (-4000) (-8000) (-8000)
- (-8000) (-12000) (-12000) (-12000) (-12000)
+ < 0 0 0 0 0
+ 0 0 0 0 0
+ 0 (-12000) (-12000) (-12000) (-12000)
(-12000) (-16000) (-16000) (-20000) (-24000)
(-28000) (-28000)>,
/* Speed bin 2 */
- <(-4000) (-4000) (-4000) (-4000) (-4000)
- (-4000) (-4000) (-4000) (-8000) (-8000)
- (-8000) (-12000) (-12000) (-12000) (-12000)
+ < 0 0 0 0 0
+ 0 0 0 0 0
+ 0 (-12000) (-12000) (-12000) (-12000)
(-12000) (-16000) (-16000) (-20000) (-24000)
(-28000) (-28000)>,
/* Speed bin 3 */
- <(-4000) (-4000) (-4000) (-4000) (-4000)
- (-4000) (-4000) (-4000) (-8000) (-8000)
- (-8000) (-12000) (-12000) (-12000) (-12000)
+ < 0 0 0 0 0
+ 0 0 0 0 0
+ 0 (-12000) (-12000) (-12000) (-12000)
(-12000) (-16000) (-16000) (-20000) (-24000)
(-28000) (-28000)>;
qcom,cpr-closed-loop-voltage-adjustment =
/* Speed bin 0 */
- <(-5000) (-5000) (-5000) (-5000) (-5000)
- (-5000) (-5000) (-5000) (-7000) (-8000)
- (-10000) (-10000) (-11000) (-12000) (-13000)
+ < 0 0 0 0 0
+ 0 0 0 0 0
+ 0 (-10000) (-11000) (-12000) (-13000)
(-14000) (-14000) (-15000) (-21000) (-24000)
(-26000) (-28000)>,
/* Speed bin 1 */
- <(-5000) (-5000) (-5000) (-5000) (-5000)
- (-5000) (-5000) (-5000) (-7000) (-8000)
- (-10000) (-10000) (-11000) (-12000) (-13000)
+ < 0 0 0 0 0
+ 0 0 0 0 0
+ 0 (-10000) (-11000) (-12000) (-13000)
(-14000) (-14000) (-15000) (-21000) (-24000)
(-26000) (-28000)>,
/* Speed bin 2 */
- <(-5000) (-5000) (-5000) (-5000) (-5000)
- (-5000) (-5000) (-5000) (-7000) (-8000)
- (-10000) (-10000) (-11000) (-12000) (-13000)
+ < 0 0 0 0 0
+ 0 0 0 0 0
+ 0 (-10000) (-11000) (-12000) (-13000)
(-14000) (-14000) (-15000) (-21000) (-24000)
(-26000) (-28000)>,
/* Speed bin 3 */
- <(-5000) (-5000) (-5000) (-5000) (-5000)
- (-5000) (-5000) (-5000) (-7000) (-8000)
- (-10000) (-10000) (-11000) (-12000) (-13000)
+ < 0 0 0 0 0
+ 0 0 0 0 0
+ 0 (-10000) (-11000) (-12000) (-13000)
(-14000) (-14000) (-15000) (-21000) (-24000)
(-26000) (-28000)>;
@@ -926,65 +926,65 @@
qcom,cpr-open-loop-voltage-adjustment =
/* Speed bin 0 */
- <(-4000) (-4000) (-4000) (-4000) (-4000)
- (-4000) (-4000) (-4000) (-8000) (-8000)
- (-8000) (-8000) (-12000) (-12000) (-12000)
+ < 0 0 0 0 0
+ 0 0 0 0 0
+ 0 (-8000) (-12000) (-12000) (-12000)
(-12000) (-12000) (-12000) (-16000) (-16000)
- (-20000) (-20000) (-24000) (-24000) (-24000)
+ (-20000) (-16000) (-16000) (-16000) (-12000)
(-28000) (-28000) (-28000) (-28000) (-28000)
(-28000) (-28000)>,
/* Speed bin 1 */
- <(-4000) (-4000) (-4000) (-4000) (-4000)
- (-4000) (-4000) (-4000) (-8000) (-8000)
- (-8000) (-8000) (-12000) (-12000) (-12000)
+ < 0 0 0 0 0
+ 0 0 0 0 0
+ 0 (-8000) (-12000) (-12000) (-12000)
(-12000) (-12000) (-12000) (-16000) (-16000)
- (-20000) (-20000) (-24000) (-24000) (-28000)
+ (-20000) (-16000) (-16000) (-16000) (-16000)
(-28000)>,
/* Speed bin 2 */
- <(-4000) (-4000) (-4000) (-4000) (-4000)
- (-4000) (-4000) (-4000) (-8000) (-8000)
- (-8000) (-8000) (-12000) (-12000) (-12000)
+ < 0 0 0 0 0
+ 0 0 0 0 0
+ 0 (-8000) (-12000) (-12000) (-12000)
(-12000) (-12000) (-12000) (-16000) (-16000)
- (-20000) (-20000) (-24000) (-24000) (-24000)
+ (-20000) (-16000) (-16000) (-16000) (-12000)
(-28000) (-28000) (-28000) (-28000) (-28000)>,
/* Speed bin 3 */
- <(-4000) (-4000) (-4000) (-4000) (-4000)
- (-4000) (-4000) (-4000) (-8000) (-8000)
- (-8000) (-8000) (-12000) (-12000) (-12000)
+ < 0 0 0 0 0
+ 0 0 0 0 0
+ 0 (-8000) (-12000) (-12000) (-12000)
(-12000) (-12000) (-12000) (-16000) (-16000)
- (-20000) (-20000) (-24000) (-24000) (-24000)
+ (-20000) (-16000) (-16000) (-16000) (-12000)
(-28000) (-28000) (-28000) (-28000) (-28000)
(-28000)>;
qcom,cpr-closed-loop-voltage-adjustment =
/* Speed bin 0 */
- <(-5000) (-5000) (-5000) (-5000) (-5000)
- (-5000) (-5000) (-5000) (-6000) (-7000)
- (-9000) (-10000) (-10000) (-11000) (-12000)
+ < 0 0 0 0 0
+ 0 0 0 0 0
+ 0 (-10000) (-10000) (-11000) (-12000)
(-12000) (-13000) (-14000) (-14000) (-15000)
- (-18000) (-21000) (-24000) (-25000) (-25000)
+ (-16000) (-16000) (-17000) (-15000) (-13000)
(-26000) (-26000) (-27000) (-27000) (-28000)
(-28000) (-28000)>,
/* Speed bin 1 */
- <(-5000) (-5000) (-5000) (-5000) (-5000)
- (-5000) (-5000) (-5000) (-6000) (-7000)
- (-9000) (-10000) (-10000) (-11000) (-12000)
+ < 0 0 0 0 0
+ 0 0 0 0 0
+ 0 (-10000) (-10000) (-11000) (-12000)
(-12000) (-13000) (-14000) (-14000) (-15000)
- (-18000) (-21000) (-24000) (-26000) (-27000)
+ (-16000) (-16000) (-17000) (-16000) (-15000)
(-28000)>,
/* Speed bin 2 */
- <(-5000) (-5000) (-5000) (-5000) (-5000)
- (-5000) (-5000) (-5000) (-6000) (-7000)
- (-9000) (-10000) (-10000) (-11000) (-12000)
+ < 0 0 0 0 0
+ 0 0 0 0 0
+ 0 (-10000) (-10000) (-11000) (-12000)
(-12000) (-13000) (-14000) (-14000) (-15000)
- (-18000) (-21000) (-24000) (-25000) (-26000)
+ (-16000) (-16000) (-17000) (-15000) (-14000)
(-27000) (-27000) (-28000) (-28000) (-28000)>,
/* Speed bin 3 */
- <(-5000) (-5000) (-5000) (-5000) (-5000)
- (-5000) (-5000) (-5000) (-6000) (-7000)
- (-9000) (-10000) (-10000) (-11000) (-12000)
+ < 0 0 0 0 0
+ 0 0 0 0 0
+ 0 (-10000) (-10000) (-11000) (-12000)
(-12000) (-13000) (-14000) (-14000) (-15000)
- (-18000) (-21000) (-24000) (-25000) (-26000)
+ (-16000) (-16000) (-17000) (-15000) (-14000)
(-26000) (-27000) (-27000) (-28000) (-28000)
(-28000)>;
diff --git a/arch/arm/boot/dts/qcom/msm8998.dts b/arch/arm/boot/dts/qcom/msm8998.dts
new file mode 100644
index 000000000000..b340b6de4c00
--- /dev/null
+++ b/arch/arm/boot/dts/qcom/msm8998.dts
@@ -0,0 +1,23 @@
+/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+
+/dts-v1/;
+
+#include <dt-bindings/clock/msm-clocks-8998.h>
+#include "msm8998.dtsi"
+
+/ {
+ model = "Qualcomm Technologies, Inc. MSM 8998 v1 SoC";
+ compatible = "qcom,msm8998";
+ qcom,board-id = <0 0>;
+};
diff --git a/arch/arm/boot/dts/qcom/msm8998.dtsi b/arch/arm/boot/dts/qcom/msm8998.dtsi
index d1194b3ffcec..9b5092cf7f14 100644
--- a/arch/arm/boot/dts/qcom/msm8998.dtsi
+++ b/arch/arm/boot/dts/qcom/msm8998.dtsi
@@ -275,6 +275,13 @@
soc: soc { };
+ vendor: vendor {
+ #address-cells = <1>;
+ #size-cells = <1>;
+ ranges = <0 0 0 0xffffffff>;
+ compatible = "simple-bus";
+ };
+
reserved-memory {
#address-cells = <2>;
#size-cells = <2>;
@@ -434,6 +441,7 @@
interrupts = <GIC_SPI 326 IRQ_TYPE_NONE>;
qcom,ee = <0>;
qcom,channel = <0>;
+ qcom,reserved-chan = <511>;
#address-cells = <2>;
#size-cells = <0>;
interrupt-controller;
@@ -2678,7 +2686,7 @@
qcom,ep-latency = <10>;
- qcom,ep-wakeirq;
+ qcom,boot-option = <0x1>;
linux,pci-domain = <0>;
diff --git a/arch/arm/boot/dts/qcom/sdm630-cdp.dtsi b/arch/arm/boot/dts/qcom/sdm630-cdp.dtsi
index 55e6943bf327..9df521f33e05 100644
--- a/arch/arm/boot/dts/qcom/sdm630-cdp.dtsi
+++ b/arch/arm/boot/dts/qcom/sdm630-cdp.dtsi
@@ -192,3 +192,26 @@
qcom,partial-update-enabled = "single_roi";
qcom,panel-roi-alignment = <2 2 4 2 1080 2>;
};
+
+&pm660l_pwm_4 {
+ qcom,dtest-line = <2>; /* DTEST2 */
+ qcom,dtest-output = <2>; /* OUTPUT PWM */
+};
+
+&pm660l_gpios {
+ gpio@c500 {
+ qcom,mode = <1>; /* DIG_OUT */
+ qcom,output-type = <0>; /* CMOS */
+ qcom,src-sel = <7>; /* DTEST2 */
+ qcom,master-en = <1>; /* Enable MPP */
+ qcom,invert = <0>; /* Enable MPP */
+ };
+};
+
+&dsi_sharp_split_link_wuxga_video {
+ pwms = <&pm660l_pwm_4 0 0>;
+ qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_pwm";
+ qcom,mdss-dsi-bl-pwm-pmi;
+ qcom,mdss-dsi-bl-pmic-pwm-frequency = <100>;
+ qcom,panel-supply-entries = <&dsi_panel_split_link_pwr_supply>;
+};
diff --git a/arch/arm/boot/dts/qcom/sdm630-mdss-panels.dtsi b/arch/arm/boot/dts/qcom/sdm630-mdss-panels.dtsi
index 81e0c6930bf3..4e3ebd445814 100644
--- a/arch/arm/boot/dts/qcom/sdm630-mdss-panels.dtsi
+++ b/arch/arm/boot/dts/qcom/sdm630-mdss-panels.dtsi
@@ -16,6 +16,7 @@
#include "dsi-panel-truly-1080p-cmd.dtsi"
#include "dsi-panel-truly-1080p-video.dtsi"
#include "dsi-panel-rm67195-amoled-fhd-cmd.dtsi"
+#include "dsi-panel-sharp-split-link-wuxga-video.dtsi"
&soc {
dsi_panel_pwr_supply: dsi_panel_pwr_supply {
@@ -51,6 +52,48 @@
};
};
+ dsi_panel_split_link_pwr_supply: dsi_panel_split_link_pwr_supply {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ qcom,panel-supply-entry@0 {
+ reg = <0>;
+ qcom,supply-name = "wqhd-vddio";
+ qcom,supply-min-voltage = <1800000>;
+ qcom,supply-max-voltage = <1950000>;
+ qcom,supply-enable-load = <32000>;
+ qcom,supply-disable-load = <80>;
+ };
+
+ qcom,panel-supply-entry@1 {
+ reg = <1>;
+ qcom,supply-name = "vdda-3p3";
+ qcom,supply-min-voltage = <3300000>;
+ qcom,supply-max-voltage = <3300000>;
+ qcom,supply-enable-load = <13900>;
+ qcom,supply-disable-load = <100>;
+ };
+
+ qcom,panel-supply-entry@2 {
+ reg = <2>;
+ qcom,supply-name = "lab";
+ qcom,supply-min-voltage = <5500000>;
+ qcom,supply-max-voltage = <6000000>;
+ qcom,supply-enable-load = <100000>;
+ qcom,supply-disable-load = <100>;
+ };
+
+ qcom,panel-supply-entry@3 {
+ reg = <3>;
+ qcom,supply-name = "ibb";
+ qcom,supply-min-voltage = <5500000>;
+ qcom,supply-max-voltage = <6000000>;
+ qcom,supply-enable-load = <100000>;
+ qcom,supply-disable-load = <100>;
+ qcom,supply-post-on-sleep = <10>;
+ };
+ };
+
dsi_panel_pwr_supply_labibb_amoled:
dsi_panel_pwr_supply_labibb_amoled {
#address-cells = <1>;
@@ -114,7 +157,14 @@
qcom,mdss-dsi-pan-enable-dynamic-fps;
qcom,mdss-dsi-pan-fps-update = "dfps_immediate_porch_mode_vfp";
qcom,esd-check-enabled;
- qcom,mdss-dsi-panel-status-check-mode = "bta_check";
+ qcom,mdss-dsi-panel-status-check-mode = "reg_read";
+ qcom,mdss-dsi-panel-status-command = [06 01 00 01 00 00 01 0a];
+ qcom,mdss-dsi-panel-status-command-state = "dsi_hs_mode";
+ qcom,mdss-dsi-panel-status-value = <0x9c>;
+ qcom,mdss-dsi-panel-on-check-value = <0x9c>;
+ qcom,mdss-dsi-panel-status-read-length = <1>;
+ qcom,mdss-dsi-panel-max-error-count = <3>;
+
};
&dsi_nt35695b_truly_fhd_cmd {
@@ -124,7 +174,14 @@
24 1e 08 09 05 03 04 a0
24 1a 08 09 05 03 04 a0];
qcom,esd-check-enabled;
- qcom,mdss-dsi-panel-status-check-mode = "bta_check";
+ qcom,mdss-dsi-panel-status-check-mode = "reg_read";
+ qcom,mdss-dsi-panel-status-command = [06 01 00 01 00 00 01 0a];
+ qcom,mdss-dsi-panel-status-command-state = "dsi_hs_mode";
+ qcom,mdss-dsi-panel-status-value = <0x9c>;
+ qcom,mdss-dsi-panel-on-check-value = <0x9c>;
+ qcom,mdss-dsi-panel-status-read-length = <1>;
+ qcom,mdss-dsi-panel-max-error-count = <3>;
+
};
&dsi_truly_1080_vid {
@@ -138,7 +195,14 @@
qcom,mdss-dsi-pan-enable-dynamic-fps;
qcom,mdss-dsi-pan-fps-update = "dfps_immediate_porch_mode_vfp";
qcom,esd-check-enabled;
- qcom,mdss-dsi-panel-status-check-mode = "bta_check";
+ qcom,mdss-dsi-panel-status-check-mode = "reg_read";
+ qcom,mdss-dsi-panel-status-command = [06 01 00 01 00 00 01 0a];
+ qcom,mdss-dsi-panel-status-command-state = "dsi_hs_mode";
+ qcom,mdss-dsi-panel-status-value = <0x1c>;
+ qcom,mdss-dsi-panel-on-check-value = <0x1c>;
+ qcom,mdss-dsi-panel-status-read-length = <1>;
+ qcom,mdss-dsi-panel-max-error-count = <3>;
+
};
&dsi_truly_1080_cmd {
@@ -148,15 +212,34 @@
23 1e 08 09 05 03 04 a0
23 1a 08 09 05 03 04 a0];
qcom,esd-check-enabled;
- qcom,mdss-dsi-panel-status-check-mode = "bta_check";
+ qcom,mdss-dsi-panel-status-check-mode = "reg_read";
+ qcom,mdss-dsi-panel-status-command = [06 01 00 01 00 00 01 0a];
+ qcom,mdss-dsi-panel-status-command-state = "dsi_hs_mode";
+ qcom,mdss-dsi-panel-status-value = <0x1c>;
+ qcom,mdss-dsi-panel-on-check-value = <0x1c>;
+ qcom,mdss-dsi-panel-status-read-length = <1>;
+ qcom,mdss-dsi-panel-max-error-count = <3>;
+
};
&dsi_rm67195_amoled_fhd_cmd {
- qcom,mdss-dsi-panel-timings-phy-v2 = [23 1e 07 08 05 03 04 a0
- 23 1e 07 08 05 03 04 a0
- 23 1e 07 08 05 03 04 a0
- 23 1e 07 08 05 03 04 a0
- 23 19 07 08 05 03 04 a0];
+ qcom,mdss-dsi-panel-timings-phy-v2 = [24 1f 08 09 05 03 04 a0
+ 24 1f 08 09 05 03 04 a0
+ 24 1f 08 09 05 03 04 a0
+ 24 1f 08 09 05 03 04 a0
+ 24 1a 08 09 05 03 04 a0];
qcom,mdss-dsi-t-clk-post = <0x0d>;
- qcom,mdss-dsi-t-clk-pre = <0x2d>;
+ qcom,mdss-dsi-t-clk-pre = <0x2f>;
+};
+
+&dsi_sharp_split_link_wuxga_video {
+ qcom,mdss-dsi-panel-timings-phy-v2 = [25 1f 09 0a 06 03 04 a0
+ 25 1f 09 0a 06 03 04 a0
+ 25 1f 09 0a 06 03 04 a0
+ 25 1f 09 0a 06 03 04 a0
+ 25 1f 08 0a 06 03 04 a0];
+ qcom,mdss-dsi-min-refresh-rate = <48>;
+ 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";
};
diff --git a/arch/arm/boot/dts/qcom/sdm630-mtp.dtsi b/arch/arm/boot/dts/qcom/sdm630-mtp.dtsi
index 0619d62526b1..9e61f48e3503 100644
--- a/arch/arm/boot/dts/qcom/sdm630-mtp.dtsi
+++ b/arch/arm/boot/dts/qcom/sdm630-mtp.dtsi
@@ -190,3 +190,15 @@
qcom,mdss-dsi-bl-max-level = <4095>;
qcom,panel-supply-entries = <&dsi_panel_pwr_supply>;
};
+
+&i2c_2 {
+ status = "ok";
+ smb1351-charger@1d {
+ compatible = "qcom,smb1351-charger";
+ reg = <0x1d>;
+ qcom,parallel-charger;
+ qcom,float-voltage-mv = <4400>;
+ qcom,recharge-mv = <100>;
+ qcom,parallel-en-pin-polarity = <1>;
+ };
+};
diff --git a/arch/arm/boot/dts/qcom/sdm630-qrd.dtsi b/arch/arm/boot/dts/qcom/sdm630-qrd.dtsi
index fb24f727fb49..c677df529dd7 100644
--- a/arch/arm/boot/dts/qcom/sdm630-qrd.dtsi
+++ b/arch/arm/boot/dts/qcom/sdm630-qrd.dtsi
@@ -22,11 +22,13 @@
#address-cells = <1>;
#size-cells = <1>;
interrupt-parent = <&tlmm>;
- interrupts = <21 0x0>;
+ interrupts = <21 IRQ_TYPE_LEVEL_LOW>;
interrupt_names = "smb138x";
interrupt-controller;
#interrupt-cells = <3>;
qcom,periph-map = <0x10 0x11 0x12 0x13 0x14 0x16 0x36>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&smb_int_default>;
smb138x_revid: qcom,revid@100 {
compatible = "qcom,qpnp-revid";
@@ -131,6 +133,21 @@
};
};
+&tlmm {
+ smb_int_default: smb_int_default {
+ mux {
+ pins = "gpio21";
+ function = "gpio";
+ };
+
+ config {
+ pins = "gpio21";
+ drive-strength = <2>;
+ bias-pull-up;
+ };
+ };
+};
+
/ {
qrd_batterydata: qcom,battery-data {
qcom,batt-id-range-pct = <15>;
diff --git a/arch/arm/boot/dts/qcom/sdm630-regulator.dtsi b/arch/arm/boot/dts/qcom/sdm630-regulator.dtsi
index eded8b08528a..c4adcfe1bdfb 100644
--- a/arch/arm/boot/dts/qcom/sdm630-regulator.dtsi
+++ b/arch/arm/boot/dts/qcom/sdm630-regulator.dtsi
@@ -28,7 +28,7 @@
rpm-regulator-smpa5 {
status = "okay";
pm660_s5: regulator-s5 {
- regulator-min-microvolt = <1350000>;
+ regulator-min-microvolt = <1224000>;
regulator-max-microvolt = <1350000>;
status = "okay";
};
@@ -657,6 +657,7 @@
qcom,cpr-up-error-step-limit = <1>;
qcom,cpr-corner-switch-delay-time = <1042>;
qcom,cpr-voltage-settling-time = <1760>;
+ qcom,cpr-reset-step-quot-loop-en;
qcom,apm-threshold-voltage = <872000>;
qcom,apm-crossover-voltage = <872000>;
@@ -665,6 +666,9 @@
qcom,voltage-base = <400000>;
qcom,cpr-saw-use-unit-mV;
+ qcom,cpr-enable;
+ qcom,cpr-hw-closed-loop;
+
qcom,cpr-panic-reg-addr-list =
<0x179cbaa4 0x17912c18>;
qcom,cpr-panic-reg-name-list =
@@ -705,6 +709,24 @@
qcom,allow-voltage-interpolation;
qcom,allow-quotient-interpolation;
qcom,cpr-scaled-open-loop-voltage-as-ceiling;
+
+ qcom,cpr-ro-scaling-factor =
+ <3600 3600 3830 2430 2520 2700 1790
+ 1760 1970 1880 2110 2010 2510 4900
+ 4370 4780>,
+ <3600 3600 3830 2430 2520 2700 1790
+ 1760 1970 1880 2110 2010 2510 4900
+ 4370 4780>,
+ <3600 3600 3830 2430 2520 2700 1790
+ 1760 1970 1880 2110 2010 2510 4900
+ 4370 4780>;
+
+ qcom,cpr-closed-loop-voltage-fuse-adjustment =
+ <(-30000) (-30000) (-30000)>;
+
+ qcom,cpr-floor-to-ceiling-max-range =
+ <32000 32000 32000 40000 44000
+ 40000 40000 40000>;
};
};
};
@@ -731,6 +753,7 @@
qcom,cpr-up-error-step-limit = <1>;
qcom,cpr-corner-switch-delay-time = <1042>;
qcom,cpr-voltage-settling-time = <1760>;
+ qcom,cpr-reset-step-quot-loop-en;
qcom,apm-threshold-voltage = <872000>;
qcom,apm-crossover-voltage = <872000>;
@@ -739,6 +762,9 @@
qcom,voltage-base = <400000>;
qcom,cpr-saw-use-unit-mV;
+ qcom,cpr-enable;
+ qcom,cpr-hw-closed-loop;
+
qcom,cpr-panic-reg-addr-list =
<0x179c7aa4 0x17812c18>;
qcom,cpr-panic-reg-name-list =
@@ -834,6 +860,46 @@
qcom,allow-voltage-interpolation;
qcom,allow-quotient-interpolation;
qcom,cpr-scaled-open-loop-voltage-as-ceiling;
+
+ qcom,cpr-ro-scaling-factor =
+ <4040 4230 0000 2210 2560 2450 2230
+ 2220 2410 2300 2560 2470 1600 3120
+ 2620 2280>,
+ <4040 4230 0000 2210 2560 2450 2230
+ 2220 2410 2300 2560 2470 1600 3120
+ 2620 2280>,
+ <4040 4230 0000 2210 2560 2450 2230
+ 2220 2410 2300 2560 2470 1600 3120
+ 2620 2280>,
+ <4040 4230 0000 2210 2560 2450 2230
+ 2220 2410 2300 2560 2470 1600 3120
+ 2620 2280>,
+ <4040 4230 0000 2210 2560 2450 2230
+ 2220 2410 2300 2560 2470 1600 3120
+ 2620 2280>;
+
+ qcom,cpr-open-loop-voltage-fuse-adjustment =
+ <15000 5000 5000 0 0>;
+
+ qcom,cpr-closed-loop-voltage-fuse-adjustment =
+ <(-30000) (-30000) (-30000)
+ (-30000) (-30000)>;
+
+ qcom,cpr-floor-to-ceiling-max-range =
+ /* Speed bin 0 */
+ <40000 40000 40000 40000
+ 40000 40000 40000 66000
+ 66000 40000>,
+
+ /* Speed bin 1 */
+ <40000 40000 40000 40000
+ 40000 40000 40000 66000
+ 66000 40000>,
+
+ /* Speed bin 2 */
+ <40000 40000 40000 40000
+ 40000 40000 40000 66000
+ 66000 40000 40000>;
};
};
};
diff --git a/arch/arm/boot/dts/qcom/sdm630.dtsi b/arch/arm/boot/dts/qcom/sdm630.dtsi
index 67e899d8ba5e..24a935ffebec 100644
--- a/arch/arm/boot/dts/qcom/sdm630.dtsi
+++ b/arch/arm/boot/dts/qcom/sdm630.dtsi
@@ -304,10 +304,16 @@
#size-cells = <2>;
ranges;
- removed_region: removed_region0@85800000 {
+ removed_region0: removed_region0@85800000 {
compatible = "removed-dma-pool";
no-map;
- reg = <0x0 0x85800000 0x0 0x3700000>;
+ reg = <0x0 0x85800000 0x0 0x700000>;
+ };
+
+ removed_region1: removed_region1@86000000 {
+ compatible = "removed-dma-pool";
+ no-map;
+ reg = <0x0 0x86000000 0x0 0x2f00000>;
};
modem_fw_mem: modem_fw_region@8ac00000 {
@@ -1982,12 +1988,12 @@
interrupts = <GIC_SPI 326 IRQ_TYPE_NONE>;
qcom,ee = <0>;
qcom,channel = <0>;
+ qcom,reserved-chan = <511>;
#address-cells = <2>;
#size-cells = <0>;
interrupt-controller;
#interrupt-cells = <4>;
cell-index = <0>;
- qcom,not-wakeup; /* Needed until Full-boot-chain enabled */
status = "ok";
};
diff --git a/arch/arm/boot/dts/qcom/sdm660-common.dtsi b/arch/arm/boot/dts/qcom/sdm660-common.dtsi
index fbe6d1d8cc74..76130f177fad 100644
--- a/arch/arm/boot/dts/qcom/sdm660-common.dtsi
+++ b/arch/arm/boot/dts/qcom/sdm660-common.dtsi
@@ -181,6 +181,7 @@
"cfg_ahb_clk", "xo";
qcom,core-clk-rate = <133330000>;
+ qcom,core-clk-rate-hs = <66666667>;
resets = <&clock_gcc GCC_USB_30_BCR>;
reset-names = "core_reset";
@@ -192,6 +193,7 @@
interrupts = <0 131 0>;
usb-phy = <&qusb_phy0>, <&ssphy>;
tx-fifo-resize;
+ snps,usb3-u1u2-disable;
snps,nominal-elastic-buffer;
snps,disable-clk-gating;
snps,has-lpm-erratum;
@@ -452,6 +454,40 @@
qcom,reset-ep-after-lpm-resume;
};
+ qusb_phy1: qusb@c014000 {
+ compatible = "qcom,qusb2phy";
+ reg = <0x0c014000 0x180>,
+ <0x00188014 0x4>;
+ reg-names = "qusb_phy_base",
+ "ref_clk_addr";
+ vdd-supply = <&pm660l_l1>;
+ vdda18-supply = <&pm660_l10>;
+ vdda33-supply = <&pm660l_l7>;
+ qcom,vdd-voltage-level = <1 5 7>;
+ qcom,qusb-phy-init-seq = <0xF8 0x80
+ 0xB3 0x84
+ 0x83 0x88
+ 0xC0 0x8C
+ 0x30 0x08
+ 0x79 0x0C
+ 0x21 0x10
+ 0x14 0x9C
+ 0x9F 0x1C
+ 0x00 0x18>;
+ phy_type = "utmi";
+ qcom,phy-clk-scheme = "cml";
+ qcom,major-rev = <1>;
+ qcom,hold-reset;
+
+ clocks = <&clock_gcc GCC_USB_PHY_CFG_AHB2PHY_CLK>,
+ <&clock_gcc GCC_RX1_USB2_CLKREF_CLK>,
+ <&clock_rpmcc RPM_LN_BB_CLK1>;
+ clock-names = "cfg_ahb_clk", "ref_clk", "ref_clk_src";
+
+ resets = <&clock_gcc GCC_QUSB2PHY_SEC_BCR>;
+ reset-names = "phy_reset";
+ };
+
sdhc_1: sdhci@c0c4000 {
compatible = "qcom,sdhci-msm-v5";
reg = <0xc0c4000 0x1000>, <0xc0c5000 0x1000>;
diff --git a/arch/arm/boot/dts/qcom/sdm660-mdss-panels.dtsi b/arch/arm/boot/dts/qcom/sdm660-mdss-panels.dtsi
index e93190ffcf44..19862f02aa84 100644
--- a/arch/arm/boot/dts/qcom/sdm660-mdss-panels.dtsi
+++ b/arch/arm/boot/dts/qcom/sdm660-mdss-panels.dtsi
@@ -147,7 +147,13 @@
23 1e 07 08 05 03 04 a0
23 18 07 08 04 03 04 a0];
qcom,esd-check-enabled;
- qcom,mdss-dsi-panel-status-check-mode = "bta_check";
+ qcom,mdss-dsi-panel-status-check-mode = "reg_read";
+ qcom,mdss-dsi-panel-status-command = [06 01 00 01 00 00 01 0a];
+ qcom,mdss-dsi-panel-status-command-state = "dsi_hs_mode";
+ qcom,mdss-dsi-panel-status-value = <0x9c>;
+ qcom,mdss-dsi-panel-on-check-value = <0x9c>;
+ qcom,mdss-dsi-panel-status-read-length = <1>;
+ qcom,mdss-dsi-panel-max-error-count = <3>;
};
&dsi_dual_nt36850_truly_cmd {
@@ -195,7 +201,13 @@
20 12 05 06 03 13 04 a0];
qcom,config-select = <&dsi_nt35597_truly_dsc_cmd_config2>;
qcom,esd-check-enabled;
- qcom,mdss-dsi-panel-status-check-mode = "bta_check";
+ qcom,mdss-dsi-panel-status-check-mode = "reg_read";
+ qcom,mdss-dsi-panel-status-command = [06 01 00 01 00 00 01 0a];
+ qcom,mdss-dsi-panel-status-command-state = "dsi_hs_mode";
+ qcom,mdss-dsi-panel-status-value = <0x9c>;
+ qcom,mdss-dsi-panel-on-check-value = <0x9c>;
+ qcom,mdss-dsi-panel-status-read-length = <1>;
+ qcom,mdss-dsi-panel-max-error-count = <3>;
};
&dsi_dual_nt35597_video {
@@ -229,7 +241,13 @@
qcom,mdss-dsi-pan-enable-dynamic-fps;
qcom,mdss-dsi-pan-fps-update = "dfps_immediate_porch_mode_vfp";
qcom,esd-check-enabled;
- qcom,mdss-dsi-panel-status-check-mode = "bta_check";
+ qcom,mdss-dsi-panel-status-check-mode = "reg_read";
+ qcom,mdss-dsi-panel-status-command = [06 01 00 01 00 00 01 0a];
+ qcom,mdss-dsi-panel-status-command-state = "dsi_hs_mode";
+ qcom,mdss-dsi-panel-status-value = <0x9c>;
+ qcom,mdss-dsi-panel-on-check-value = <0x9c>;
+ qcom,mdss-dsi-panel-status-read-length = <1>;
+ qcom,mdss-dsi-panel-max-error-count = <3>;
};
&dsi_nt35695b_truly_fhd_cmd {
@@ -239,7 +257,13 @@
24 1e 08 09 05 03 04 a0
24 1a 08 09 05 03 04 a0];
qcom,esd-check-enabled;
- qcom,mdss-dsi-panel-status-check-mode = "bta_check";
+ qcom,mdss-dsi-panel-status-check-mode = "reg_read";
+ qcom,mdss-dsi-panel-status-command = [06 01 00 01 00 00 01 0a];
+ qcom,mdss-dsi-panel-status-command-state = "dsi_hs_mode";
+ qcom,mdss-dsi-panel-status-value = <0x9c>;
+ qcom,mdss-dsi-panel-on-check-value = <0x9c>;
+ qcom,mdss-dsi-panel-status-read-length = <1>;
+ qcom,mdss-dsi-panel-max-error-count = <3>;
};
&dsi_truly_1080_vid {
@@ -253,7 +277,14 @@
qcom,mdss-dsi-pan-enable-dynamic-fps;
qcom,mdss-dsi-pan-fps-update = "dfps_immediate_porch_mode_vfp";
qcom,esd-check-enabled;
- qcom,mdss-dsi-panel-status-check-mode = "bta_check";
+ qcom,mdss-dsi-panel-status-check-mode = "reg_read";
+ qcom,mdss-dsi-panel-status-command = [06 01 00 01 00 00 01 0a];
+ qcom,mdss-dsi-panel-status-command-state = "dsi_hs_mode";
+ qcom,mdss-dsi-panel-status-value = <0x1c>;
+ qcom,mdss-dsi-panel-on-check-value = <0x1c>;
+ qcom,mdss-dsi-panel-status-read-length = <1>;
+ qcom,mdss-dsi-panel-max-error-count = <3>;
+
};
&dsi_truly_1080_cmd {
@@ -263,15 +294,22 @@
23 1e 08 09 05 03 04 a0
23 1a 08 09 05 03 04 a0];
qcom,esd-check-enabled;
- qcom,mdss-dsi-panel-status-check-mode = "bta_check";
+ qcom,mdss-dsi-panel-status-check-mode = "reg_read";
+ qcom,mdss-dsi-panel-status-command = [06 01 00 01 00 00 01 0a];
+ qcom,mdss-dsi-panel-status-command-state = "dsi_hs_mode";
+ qcom,mdss-dsi-panel-status-value = <0x1c>;
+ qcom,mdss-dsi-panel-on-check-value = <0x1c>;
+ qcom,mdss-dsi-panel-status-read-length = <1>;
+ qcom,mdss-dsi-panel-max-error-count = <3>;
+
};
&dsi_rm67195_amoled_fhd_cmd {
- qcom,mdss-dsi-panel-timings-phy-v2 = [23 1e 07 08 05 03 04 a0
- 23 1e 07 08 05 03 04 a0
- 23 1e 07 08 05 03 04 a0
- 23 1e 07 08 05 03 04 a0
- 23 19 07 08 05 03 04 a0];
+ qcom,mdss-dsi-panel-timings-phy-v2 = [24 1f 08 09 05 03 04 a0
+ 24 1f 08 09 05 03 04 a0
+ 24 1f 08 09 05 03 04 a0
+ 24 1f 08 09 05 03 04 a0
+ 24 1a 08 09 05 03 04 a0];
qcom,mdss-dsi-t-clk-post = <0x0d>;
- qcom,mdss-dsi-t-clk-pre = <0x2d>;
+ qcom,mdss-dsi-t-clk-pre = <0x2f>;
};
diff --git a/arch/arm/boot/dts/qcom/sdm660-pinctrl.dtsi b/arch/arm/boot/dts/qcom/sdm660-pinctrl.dtsi
index 37a88ea0dcec..efe58563a1f3 100644
--- a/arch/arm/boot/dts/qcom/sdm660-pinctrl.dtsi
+++ b/arch/arm/boot/dts/qcom/sdm660-pinctrl.dtsi
@@ -36,16 +36,28 @@
led_enable: led_enable {
mux {
pins = "gpio40";
- drive_strength = <16>;
+ function = "gpio";
+ };
+
+ config {
+ pins = "gpio40";
+ drive_strength = <2>;
output-high;
+ bias-disable;
};
};
led_disable: led_disable {
mux {
pins = "gpio40";
+ function = "gpio";
+ };
+
+ config {
+ pins = "gpio40";
drive_strength = <2>;
output-low;
+ bias-disable;
};
};
diff --git a/arch/arm/boot/dts/qcom/sdm660-regulator.dtsi b/arch/arm/boot/dts/qcom/sdm660-regulator.dtsi
index a93efdc38f41..8b6bbac171f4 100644
--- a/arch/arm/boot/dts/qcom/sdm660-regulator.dtsi
+++ b/arch/arm/boot/dts/qcom/sdm660-regulator.dtsi
@@ -28,7 +28,7 @@
rpm-regulator-smpa5 {
status = "okay";
pm660_s5: regulator-s5 {
- regulator-min-microvolt = <1350000>;
+ regulator-min-microvolt = <1224000>;
regulator-max-microvolt = <1350000>;
status = "okay";
};
diff --git a/arch/arm/boot/dts/qcom/sdm660.dtsi b/arch/arm/boot/dts/qcom/sdm660.dtsi
index be200f8dd531..2e576a51677f 100644
--- a/arch/arm/boot/dts/qcom/sdm660.dtsi
+++ b/arch/arm/boot/dts/qcom/sdm660.dtsi
@@ -466,6 +466,7 @@
interrupts = <GIC_SPI 326 IRQ_TYPE_NONE>;
qcom,ee = <0>;
qcom,channel = <0>;
+ qcom,reserved-chan = <511>;
#address-cells = <2>;
#size-cells = <0>;
interrupt-controller;
diff --git a/arch/arm/configs/sdm660_defconfig b/arch/arm/configs/sdm660_defconfig
index c4b0eabe2fbf..30a71904747f 100644
--- a/arch/arm/configs/sdm660_defconfig
+++ b/arch/arm/configs/sdm660_defconfig
@@ -635,6 +635,7 @@ CONFIG_MAGIC_SYSRQ=y
CONFIG_DEBUG_PAGEALLOC=y
CONFIG_DEBUG_PAGEALLOC_ENABLE_DEFAULT=y
CONFIG_SLUB_DEBUG_PANIC_ON=y
+CONFIG_PAGE_POISONING_ENABLE_DEFAULT=y
CONFIG_DEBUG_OBJECTS=y
CONFIG_DEBUG_OBJECTS_FREE=y
CONFIG_DEBUG_OBJECTS_TIMERS=y
diff --git a/arch/arm/mm/dma-mapping.c b/arch/arm/mm/dma-mapping.c
index b58d8e0d9ed1..8bda55f00b7b 100644
--- a/arch/arm/mm/dma-mapping.c
+++ b/arch/arm/mm/dma-mapping.c
@@ -67,7 +67,8 @@ __dma_alloc_remap(struct page *page, size_t size, gfp_t gfp, pgprot_t prot,
static void __dma_free_remap(void *cpu_addr, size_t size, bool no_warn);
-static inline pgprot_t __get_dma_pgprot(struct dma_attrs *attrs, pgprot_t prot);
+static inline pgprot_t __get_dma_pgprot(struct dma_attrs *attrs, pgprot_t prot,
+ bool coherent);
static void *arm_dma_remap(struct device *dev, void *cpu_addr,
dma_addr_t handle, size_t size,
@@ -76,6 +77,33 @@ static void *arm_dma_remap(struct device *dev, void *cpu_addr,
static void arm_dma_unremap(struct device *dev, void *remapped_addr,
size_t size);
+static bool is_dma_coherent(struct device *dev, struct dma_attrs *attrs)
+{
+ bool is_coherent;
+
+ if (dma_get_attr(DMA_ATTR_FORCE_COHERENT, attrs))
+ is_coherent = true;
+ else if (dma_get_attr(DMA_ATTR_FORCE_NON_COHERENT, attrs))
+ is_coherent = false;
+ else if (is_device_dma_coherent(dev))
+ is_coherent = true;
+ else
+ is_coherent = false;
+
+ return is_coherent;
+}
+
+static int __get_iommu_pgprot(struct dma_attrs *attrs, int prot,
+ bool coherent)
+{
+ if (!dma_get_attr(DMA_ATTR_EXEC_MAPPING, attrs))
+ prot |= IOMMU_NOEXEC;
+ if (coherent)
+ prot |= IOMMU_CACHE;
+
+ return prot;
+}
+
/**
* arm_dma_map_page - map a portion of a page for streaming DMA
* @dev: valid struct device pointer, or NULL for ISA and EISA-like devices
@@ -245,7 +273,7 @@ static u64 get_coherent_dma_mask(struct device *dev)
}
static void __dma_clear_buffer(struct page *page, size_t size,
- struct dma_attrs *attrs)
+ struct dma_attrs *attrs, bool is_coherent)
{
/*
* Ensure that the allocated pages are zeroed, and that any data
@@ -258,18 +286,22 @@ static void __dma_clear_buffer(struct page *page, size_t size,
void *ptr = kmap_atomic(page);
if (!dma_get_attr(DMA_ATTR_SKIP_ZEROING, attrs))
memset(ptr, 0, PAGE_SIZE);
- dmac_flush_range(ptr, ptr + PAGE_SIZE);
+ if (!is_coherent)
+ dmac_flush_range(ptr, ptr + PAGE_SIZE);
kunmap_atomic(ptr);
page++;
size -= PAGE_SIZE;
}
- outer_flush_range(base, end);
+ if (!is_coherent)
+ outer_flush_range(base, end);
} else {
void *ptr = page_address(page);
if (!dma_get_attr(DMA_ATTR_SKIP_ZEROING, attrs))
memset(ptr, 0, size);
- dmac_flush_range(ptr, ptr + size);
- outer_flush_range(__pa(ptr), __pa(ptr) + size);
+ if (!is_coherent) {
+ dmac_flush_range(ptr, ptr + size);
+ outer_flush_range(__pa(ptr), __pa(ptr) + size);
+ }
}
}
@@ -277,7 +309,8 @@ static void __dma_clear_buffer(struct page *page, size_t size,
* Allocate a DMA buffer for 'dev' of size 'size' using the
* specified gfp mask. Note that 'size' must be page aligned.
*/
-static struct page *__dma_alloc_buffer(struct device *dev, size_t size, gfp_t gfp)
+static struct page *__dma_alloc_buffer(struct device *dev, size_t size,
+ gfp_t gfp, bool coherent)
{
unsigned long order = get_order(size);
struct page *page, *p, *e;
@@ -293,7 +326,7 @@ static struct page *__dma_alloc_buffer(struct device *dev, size_t size, gfp_t gf
for (p = page + (size >> PAGE_SHIFT), e = page + (1 << order); p < e; p++)
__free_page(p);
- __dma_clear_buffer(page, size, NULL);
+ __dma_clear_buffer(page, size, NULL, coherent);
return page;
}
@@ -527,7 +560,7 @@ static void *__alloc_remap_buffer(struct device *dev, size_t size, gfp_t gfp,
{
struct page *page;
void *ptr = NULL;
- page = __dma_alloc_buffer(dev, size, gfp);
+ page = __dma_alloc_buffer(dev, size, gfp, false);
if (!page)
return NULL;
if (!want_vaddr)
@@ -602,7 +635,7 @@ static void *__alloc_from_contiguous(struct device *dev, size_t size,
*/
if (!(dma_get_attr(DMA_ATTR_SKIP_CPU_SYNC, attrs) &&
dma_get_attr(DMA_ATTR_SKIP_ZEROING, attrs)))
- __dma_clear_buffer(page, size, attrs);
+ __dma_clear_buffer(page, size, attrs, false);
if (PageHighMem(page)) {
if (!want_vaddr) {
@@ -643,15 +676,13 @@ static void __free_from_contiguous(struct device *dev, struct page *page,
dma_release_from_contiguous(dev, page, size >> PAGE_SHIFT);
}
-static inline pgprot_t __get_dma_pgprot(struct dma_attrs *attrs, pgprot_t prot)
+static inline pgprot_t __get_dma_pgprot(struct dma_attrs *attrs, pgprot_t prot,
+ bool coherent)
{
- if (dma_get_attr(DMA_ATTR_WRITE_COMBINE, attrs))
- prot = pgprot_writecombine(prot);
- else if (dma_get_attr(DMA_ATTR_STRONGLY_ORDERED, attrs))
+ if (dma_get_attr(DMA_ATTR_STRONGLY_ORDERED, attrs))
prot = pgprot_stronglyordered(prot);
- /* if non-consistent just pass back what was given */
- else if (!dma_get_attr(DMA_ATTR_NON_CONSISTENT, attrs))
- prot = pgprot_dmacoherent(prot);
+ else if (!coherent || dma_get_attr(DMA_ATTR_WRITE_COMBINE, attrs))
+ prot = pgprot_writecombine(prot);
return prot;
}
@@ -673,10 +704,10 @@ static inline pgprot_t __get_dma_pgprot(struct dma_attrs *attrs, pgprot_t prot)
#endif /* CONFIG_MMU */
static void *__alloc_simple_buffer(struct device *dev, size_t size, gfp_t gfp,
- struct page **ret_page)
+ struct page **ret_page, bool coherent)
{
struct page *page;
- page = __dma_alloc_buffer(dev, size, gfp);
+ page = __dma_alloc_buffer(dev, size, gfp, coherent);
if (!page)
return NULL;
@@ -724,12 +755,14 @@ static void *__dma_alloc(struct device *dev, size_t size, dma_addr_t *handle,
want_vaddr = !dma_get_attr(DMA_ATTR_NO_KERNEL_MAPPING, attrs);
if (nommu())
- addr = __alloc_simple_buffer(dev, size, gfp, &page);
+ addr = __alloc_simple_buffer(dev, size, gfp, &page,
+ is_coherent);
else if (dev_get_cma_area(dev) && (gfp & __GFP_DIRECT_RECLAIM))
addr = __alloc_from_contiguous(dev, size, prot, &page,
caller, attrs);
else if (is_coherent)
- addr = __alloc_simple_buffer(dev, size, gfp, &page);
+ addr = __alloc_simple_buffer(dev, size, gfp, &page,
+ is_coherent);
else if (!gfpflags_allow_blocking(gfp))
addr = __alloc_from_pool(size, &page);
else
@@ -749,7 +782,7 @@ static void *__dma_alloc(struct device *dev, size_t size, dma_addr_t *handle,
void *arm_dma_alloc(struct device *dev, size_t size, dma_addr_t *handle,
gfp_t gfp, struct dma_attrs *attrs)
{
- pgprot_t prot = __get_dma_pgprot(attrs, PAGE_KERNEL);
+ pgprot_t prot = __get_dma_pgprot(attrs, PAGE_KERNEL, false);
return __dma_alloc(dev, size, handle, gfp, prot, false,
attrs, __builtin_return_address(0));
@@ -792,8 +825,9 @@ static void *arm_dma_remap(struct device *dev, void *cpu_addr,
struct dma_attrs *attrs)
{
void *ptr;
+ bool is_coherent = is_dma_coherent(dev, attrs);
struct page *page = pfn_to_page(dma_to_pfn(dev, handle));
- pgprot_t prot = __get_dma_pgprot(attrs, PAGE_KERNEL);
+ pgprot_t prot = __get_dma_pgprot(attrs, PAGE_KERNEL, is_coherent);
unsigned long offset = handle & ~PAGE_MASK;
size = PAGE_ALIGN(size + offset);
@@ -837,7 +871,8 @@ int arm_dma_mmap(struct device *dev, struct vm_area_struct *vma,
struct dma_attrs *attrs)
{
#ifdef CONFIG_MMU
- vma->vm_page_prot = __get_dma_pgprot(attrs, vma->vm_page_prot);
+ vma->vm_page_prot = __get_dma_pgprot(attrs, vma->vm_page_prot,
+ false);
#endif /* CONFIG_MMU */
return __arm_dma_mmap(dev, vma, cpu_addr, dma_addr, size, attrs);
}
@@ -1238,6 +1273,7 @@ static struct page **__iommu_alloc_buffer(struct device *dev, size_t size,
size_t count = size >> PAGE_SHIFT;
size_t array_size = count * sizeof(struct page *);
int i = 0;
+ bool is_coherent = is_dma_coherent(dev, attrs);
if (array_size <= PAGE_SIZE)
pages = kzalloc(array_size, GFP_KERNEL);
@@ -1255,7 +1291,7 @@ static struct page **__iommu_alloc_buffer(struct device *dev, size_t size,
if (!page)
goto error;
- __dma_clear_buffer(page, size, NULL);
+ __dma_clear_buffer(page, size, attrs, is_coherent);
for (i = 0; i < count; i++)
pages[i] = page + i;
@@ -1299,7 +1335,8 @@ static struct page **__iommu_alloc_buffer(struct device *dev, size_t size,
pages[i + j] = pages[i] + j;
}
- __dma_clear_buffer(pages[i], PAGE_SIZE << order, NULL);
+ __dma_clear_buffer(pages[i], PAGE_SIZE << order, attrs,
+ is_coherent);
i += 1 << order;
count -= 1 << order;
}
@@ -1353,16 +1390,20 @@ __iommu_alloc_remap(struct page **pages, size_t size, gfp_t gfp, pgprot_t prot,
* Create a mapping in device IO address space for specified pages
*/
static dma_addr_t
-__iommu_create_mapping(struct device *dev, struct page **pages, size_t size)
+__iommu_create_mapping(struct device *dev, struct page **pages, size_t size,
+ struct dma_attrs *attrs)
{
struct dma_iommu_mapping *mapping = to_dma_iommu_mapping(dev);
unsigned int count = PAGE_ALIGN(size) >> PAGE_SHIFT;
dma_addr_t dma_addr, iova;
int i;
+ int prot = IOMMU_READ | IOMMU_WRITE;
dma_addr = __alloc_iova(mapping, size);
if (dma_addr == DMA_ERROR_CODE)
return dma_addr;
+ prot = __get_iommu_pgprot(attrs, prot,
+ is_dma_coherent(dev, attrs));
iova = dma_addr;
for (i = 0; i < count; ) {
@@ -1377,8 +1418,7 @@ __iommu_create_mapping(struct device *dev, struct page **pages, size_t size)
break;
len = (j - i) << PAGE_SHIFT;
- ret = iommu_map(mapping->domain, iova, phys, len,
- IOMMU_READ|IOMMU_WRITE);
+ ret = iommu_map(mapping->domain, iova, phys, len, prot);
if (ret < 0)
goto fail;
iova += len;
@@ -1435,23 +1475,52 @@ static struct page **__iommu_get_pages(void *cpu_addr, struct dma_attrs *attrs)
}
static void *__iommu_alloc_atomic(struct device *dev, size_t size,
- dma_addr_t *handle)
+ dma_addr_t *handle, gfp_t gfp,
+ struct dma_attrs *attrs)
{
struct page *page;
+ struct page **pages;
+ size_t count = size >> PAGE_SHIFT;
+ size_t array_size = count * sizeof(struct page *);
void *addr;
+ int i;
+ bool coherent = is_dma_coherent(dev, attrs);
- addr = __alloc_from_pool(size, &page);
- if (!addr)
+ if (array_size <= PAGE_SIZE)
+ pages = kzalloc(array_size, gfp);
+ else
+ pages = vzalloc(array_size);
+
+ if (!pages)
return NULL;
- *handle = __iommu_create_mapping(dev, &page, size);
+ if (coherent) {
+ page = alloc_pages(gfp, get_order(size));
+ addr = page ? page_address(page) : NULL;
+ } else {
+ addr = __alloc_from_pool(size, &page);
+ }
+
+ if (!addr)
+ goto err_free;
+
+ for (i = 0; i < count ; i++)
+ pages[i] = page + i;
+
+ *handle = __iommu_create_mapping(dev, pages, size, attrs);
if (*handle == DMA_ERROR_CODE)
goto err_mapping;
+ kvfree(pages);
return addr;
err_mapping:
- __free_from_pool(addr, size);
+ if (coherent)
+ __free_pages(page, get_order(size));
+ else
+ __free_from_pool(addr, size);
+err_free:
+ kvfree(pages);
return NULL;
}
@@ -1465,7 +1534,9 @@ static void __iommu_free_atomic(struct device *dev, void *cpu_addr,
static void *arm_iommu_alloc_attrs(struct device *dev, size_t size,
dma_addr_t *handle, gfp_t gfp, struct dma_attrs *attrs)
{
- pgprot_t prot = __get_dma_pgprot(attrs, PAGE_KERNEL);
+
+ bool coherent = is_dma_coherent(dev, attrs);
+ pgprot_t prot = __get_dma_pgprot(attrs, PAGE_KERNEL, coherent);
struct page **pages;
void *addr = NULL;
@@ -1473,7 +1544,7 @@ static void *arm_iommu_alloc_attrs(struct device *dev, size_t size,
size = PAGE_ALIGN(size);
if (!gfpflags_allow_blocking(gfp))
- return __iommu_alloc_atomic(dev, size, handle);
+ return __iommu_alloc_atomic(dev, size, handle, gfp, attrs);
/*
* Following is a work-around (a.k.a. hack) to prevent pages
@@ -1488,7 +1559,7 @@ static void *arm_iommu_alloc_attrs(struct device *dev, size_t size,
if (!pages)
return NULL;
- *handle = __iommu_create_mapping(dev, pages, size);
+ *handle = __iommu_create_mapping(dev, pages, size, attrs);
if (*handle == DMA_ERROR_CODE)
goto err_buffer;
@@ -1518,8 +1589,10 @@ static int arm_iommu_mmap_attrs(struct device *dev, struct vm_area_struct *vma,
struct page **pages = __iommu_get_pages(cpu_addr, attrs);
unsigned long nr_pages = PAGE_ALIGN(size) >> PAGE_SHIFT;
unsigned long off = vma->vm_pgoff;
+ bool coherent = is_dma_coherent(dev, attrs);
- vma->vm_page_prot = __get_dma_pgprot(attrs, vma->vm_page_prot);
+ vma->vm_page_prot = __get_dma_pgprot(attrs, vma->vm_page_prot,
+ coherent);
if (!pages)
return -ENXIO;
@@ -1750,6 +1823,8 @@ int arm_iommu_map_sg(struct device *dev, struct scatterlist *sg,
dev_err(dev, "Couldn't allocate iova for sg %p\n", sg);
return 0;
}
+ prot = __get_iommu_pgprot(attrs, prot,
+ is_dma_coherent(dev, attrs));
ret = iommu_map_sg(mapping->domain, iova, sg, nents, prot);
if (ret != total_length) {
@@ -1836,6 +1911,13 @@ void arm_iommu_sync_sg_for_cpu(struct device *dev, struct scatterlist *sg,
{
struct scatterlist *s;
int i;
+ struct dma_iommu_mapping *mapping = dev->archdata.mapping;
+ dma_addr_t iova = sg_dma_address(sg);
+ bool iova_coherent = iommu_is_iova_coherent(mapping->domain, iova);
+
+ if (iova_coherent)
+ return;
+
for_each_sg(sg, s, nents, i)
__dma_page_dev_to_cpu(sg_page(s), s->offset, s->length, dir);
@@ -1854,6 +1936,12 @@ void arm_iommu_sync_sg_for_device(struct device *dev, struct scatterlist *sg,
{
struct scatterlist *s;
int i;
+ struct dma_iommu_mapping *mapping = dev->archdata.mapping;
+ dma_addr_t iova = sg_dma_address(sg);
+ bool iova_coherent = iommu_is_iova_coherent(mapping->domain, iova);
+
+ if (iova_coherent)
+ return;
for_each_sg(sg, s, nents, i)
__dma_page_cpu_to_dev(sg_page(s), s->offset, s->length, dir);
@@ -1887,6 +1975,8 @@ static dma_addr_t arm_coherent_iommu_map_page(struct device *dev, struct page *p
return dma_addr;
prot = __dma_direction_to_prot(dir);
+ prot = __get_iommu_pgprot(attrs, prot,
+ is_dma_coherent(dev, attrs));
ret = iommu_map(mapping->domain, dma_addr, page_to_phys(page) +
start_offset, len, prot);
@@ -1913,7 +2003,8 @@ static dma_addr_t arm_iommu_map_page(struct device *dev, struct page *page,
unsigned long offset, size_t size, enum dma_data_direction dir,
struct dma_attrs *attrs)
{
- if (!dma_get_attr(DMA_ATTR_SKIP_CPU_SYNC, attrs))
+ if (!is_dma_coherent(dev, attrs) &&
+ !dma_get_attr(DMA_ATTR_SKIP_CPU_SYNC, attrs))
__dma_page_cpu_to_dev(page, offset, size, dir);
return arm_coherent_iommu_map_page(dev, page, offset, size, dir, attrs);
@@ -1960,7 +2051,8 @@ static void arm_iommu_unmap_page(struct device *dev, dma_addr_t handle,
int offset = handle & ~PAGE_MASK;
int len = PAGE_ALIGN(size + offset);
- if (!dma_get_attr(DMA_ATTR_SKIP_CPU_SYNC, attrs))
+ if (!(is_dma_coherent(dev, attrs) ||
+ dma_get_attr(DMA_ATTR_SKIP_CPU_SYNC, attrs)))
__dma_page_dev_to_cpu(page, offset, size, dir);
iommu_unmap(mapping->domain, iova, len);
@@ -1974,8 +2066,10 @@ static void arm_iommu_sync_single_for_cpu(struct device *dev,
dma_addr_t iova = handle & PAGE_MASK;
struct page *page = phys_to_page(iommu_iova_to_phys(mapping->domain, iova));
unsigned int offset = handle & ~PAGE_MASK;
+ bool iova_coherent = iommu_is_iova_coherent(mapping->domain, handle);
- __dma_page_dev_to_cpu(page, offset, size, dir);
+ if (!iova_coherent)
+ __dma_page_dev_to_cpu(page, offset, size, dir);
}
static void arm_iommu_sync_single_for_device(struct device *dev,
@@ -1985,10 +2079,31 @@ static void arm_iommu_sync_single_for_device(struct device *dev,
dma_addr_t iova = handle & PAGE_MASK;
struct page *page = phys_to_page(iommu_iova_to_phys(mapping->domain, iova));
unsigned int offset = handle & ~PAGE_MASK;
+ bool iova_coherent = iommu_is_iova_coherent(mapping->domain, handle);
- __dma_page_cpu_to_dev(page, offset, size, dir);
+ if (!iova_coherent)
+ __dma_page_cpu_to_dev(page, offset, size, dir);
}
+static int arm_iommu_dma_supported(struct device *dev, u64 mask)
+{
+ struct dma_iommu_mapping *mapping = to_dma_iommu_mapping(dev);
+
+ if (!mapping) {
+ dev_warn(dev, "No IOMMU mapping for device\n");
+ return 0;
+ }
+
+ return iommu_dma_supported(mapping->domain, dev, mask);
+}
+
+static int arm_iommu_mapping_error(struct device *dev,
+ dma_addr_t dma_addr)
+{
+ return dma_addr == DMA_ERROR_CODE;
+}
+
+
const struct dma_map_ops iommu_ops = {
.alloc = arm_iommu_alloc_attrs,
.free = arm_iommu_free_attrs,
@@ -2006,6 +2121,8 @@ const struct dma_map_ops iommu_ops = {
.sync_sg_for_device = arm_iommu_sync_sg_for_device,
.set_dma_mask = arm_dma_set_mask,
+ .dma_supported = arm_iommu_dma_supported,
+ .mapping_error = arm_iommu_mapping_error,
};
const struct dma_map_ops iommu_coherent_ops = {
diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig
index cbfb3f4428e0..3c89828b9af2 100644
--- a/arch/arm64/Kconfig
+++ b/arch/arm64/Kconfig
@@ -210,7 +210,7 @@ if ARM64_DMA_USE_IOMMU
config ARM64_DMA_IOMMU_ALIGNMENT
int "Maximum PAGE_SIZE order of alignment for DMA IOMMU buffers"
range 4 9
- default 8
+ default 9
help
DMA mapping framework by default aligns all buffers to the smallest
PAGE_SIZE order which is greater than or equal to the requested buffer
@@ -1030,6 +1030,11 @@ config BUILD_ARM64_APPENDED_DTB_IMAGE_NAMES
Space separated list of names of dtbs to append when
building a concatenated Image.gz-dtb.
+config BUILD_ARM64_DT_OVERLAY
+ bool "enable DT overlay compilation support"
+ depends on OF
+ help
+ This option enables support for DT overlay compilation.
endmenu
menu "Userspace binary formats"
diff --git a/arch/arm64/Makefile b/arch/arm64/Makefile
index 101632379b8b..fcfa3c7dedc1 100644
--- a/arch/arm64/Makefile
+++ b/arch/arm64/Makefile
@@ -92,6 +92,10 @@ endif
KBUILD_DTBS := dtbs
+ifeq ($(CONFIG_BUILD_ARM64_DT_OVERLAY),y)
+export DTC_FLAGS := -@
+endif
+
all: $(KBUILD_IMAGE) $(KBUILD_DTBS)
boot := arch/arm64/boot
diff --git a/arch/arm64/configs/msmcortex-perf_defconfig b/arch/arm64/configs/msmcortex-perf_defconfig
index 94f9a8edfd12..4b0918e2136d 100644
--- a/arch/arm64/configs/msmcortex-perf_defconfig
+++ b/arch/arm64/configs/msmcortex-perf_defconfig
@@ -273,9 +273,15 @@ CONFIG_SMSC911X=y
CONFIG_PPP=y
CONFIG_PPP_BSDCOMP=y
CONFIG_PPP_DEFLATE=y
+CONFIG_PPP_FILTER=y
CONFIG_PPP_MPPE=y
+CONFIG_PPP_MULTILINK=y
+CONFIG_PPPOE=y
+CONFIG_PPPOL2TP=y
CONFIG_PPPOLAC=y
CONFIG_PPPOPNS=y
+CONFIG_PPP_ASYNC=y
+CONFIG_PPP_SYNC_TTY=y
CONFIG_USB_USBNET=y
CONFIG_WCNSS_MEM_PRE_ALLOC=y
CONFIG_ATH_CARDS=y
@@ -582,7 +588,6 @@ CONFIG_PWM_QPNP=y
CONFIG_ARM_GIC_V3_ACL=y
CONFIG_ANDROID=y
CONFIG_ANDROID_BINDER_IPC=y
-CONFIG_ANDROID_BINDER_DEVICES="binder,hwbinder"
CONFIG_MSM_TZ_LOG=y
CONFIG_SENSORS_SSC=y
CONFIG_EXT2_FS=y
diff --git a/arch/arm64/configs/msmcortex_defconfig b/arch/arm64/configs/msmcortex_defconfig
index b86787f5f467..caa140651102 100644
--- a/arch/arm64/configs/msmcortex_defconfig
+++ b/arch/arm64/configs/msmcortex_defconfig
@@ -82,6 +82,7 @@ CONFIG_CPU_FREQ_GOV_USERSPACE=y
CONFIG_CPU_FREQ_GOV_ONDEMAND=y
CONFIG_CPU_FREQ_GOV_INTERACTIVE=y
CONFIG_CPU_FREQ_GOV_CONSERVATIVE=y
+CONFIG_CPU_BOOST=y
CONFIG_NET=y
CONFIG_PACKET=y
CONFIG_UNIX=y
@@ -273,9 +274,15 @@ CONFIG_RNDIS_IPA=y
CONFIG_PPP=y
CONFIG_PPP_BSDCOMP=y
CONFIG_PPP_DEFLATE=y
+CONFIG_PPP_FILTER=y
CONFIG_PPP_MPPE=y
+CONFIG_PPP_MULTILINK=y
+CONFIG_PPPOE=y
+CONFIG_PPPOL2TP=y
CONFIG_PPPOLAC=y
CONFIG_PPPOPNS=y
+CONFIG_PPP_ASYNC=y
+CONFIG_PPP_SYNC_TTY=y
CONFIG_USB_USBNET=y
CONFIG_WCNSS_MEM_PRE_ALLOC=y
CONFIG_ATH_CARDS=y
@@ -603,7 +610,6 @@ CONFIG_ARM_GIC_V3_ACL=y
CONFIG_PHY_XGENE=y
CONFIG_ANDROID=y
CONFIG_ANDROID_BINDER_IPC=y
-CONFIG_ANDROID_BINDER_DEVICES="binder,hwbinder"
CONFIG_MSM_TZ_LOG=y
CONFIG_SENSORS_SSC=y
CONFIG_EXT2_FS=y
@@ -632,6 +638,8 @@ CONFIG_PAGE_OWNER_ENABLE_DEFAULT=y
CONFIG_MAGIC_SYSRQ=y
CONFIG_DEBUG_PAGEALLOC_ENABLE_DEFAULT=y
CONFIG_SLUB_DEBUG_PANIC_ON=y
+CONFIG_PAGE_POISONING=y
+CONFIG_PAGE_POISONING_ENABLE_DEFAULT=y
CONFIG_DEBUG_OBJECTS=y
CONFIG_DEBUG_OBJECTS_FREE=y
CONFIG_DEBUG_OBJECTS_TIMERS=y
diff --git a/arch/arm64/configs/msmcortex_mediabox_defconfig b/arch/arm64/configs/msmcortex_mediabox_defconfig
index ccd653eaec7d..3322f8fa11fc 100644
--- a/arch/arm64/configs/msmcortex_mediabox_defconfig
+++ b/arch/arm64/configs/msmcortex_mediabox_defconfig
@@ -194,6 +194,7 @@ CONFIG_L2TP_V3=y
CONFIG_L2TP_IP=y
CONFIG_L2TP_ETH=y
CONFIG_BRIDGE=y
+CONFIG_VLAN_8021Q=y
CONFIG_NET_SCHED=y
CONFIG_NET_SCH_HTB=y
CONFIG_NET_SCH_PRIO=y
@@ -543,7 +544,6 @@ CONFIG_QCOM_WATCHDOG_V2=y
CONFIG_QCOM_IRQ_HELPER=y
CONFIG_QCOM_MEMORY_DUMP_V2=y
CONFIG_ICNSS=y
-CONFIG_ICNSS_DEBUG=y
CONFIG_MSM_GLADIATOR_ERP_V2=y
CONFIG_PANIC_ON_GLADIATOR_ERROR_V2=y
CONFIG_MSM_GLADIATOR_HANG_DETECT=y
diff --git a/arch/arm64/configs/sdm660_defconfig b/arch/arm64/configs/sdm660_defconfig
index bba52749284a..13ae21bdd562 100644
--- a/arch/arm64/configs/sdm660_defconfig
+++ b/arch/arm64/configs/sdm660_defconfig
@@ -645,6 +645,8 @@ CONFIG_PAGE_OWNER_ENABLE_DEFAULT=y
CONFIG_MAGIC_SYSRQ=y
CONFIG_DEBUG_PAGEALLOC_ENABLE_DEFAULT=y
CONFIG_SLUB_DEBUG_PANIC_ON=y
+CONFIG_PAGE_POISONING=y
+CONFIG_PAGE_POISONING_ENABLE_DEFAULT=y
CONFIG_DEBUG_OBJECTS=y
CONFIG_DEBUG_OBJECTS_FREE=y
CONFIG_DEBUG_OBJECTS_TIMERS=y
diff --git a/arch/arm64/include/asm/cache.h b/arch/arm64/include/asm/cache.h
index 5082b30bc2c0..f9359d32fae5 100644
--- a/arch/arm64/include/asm/cache.h
+++ b/arch/arm64/include/asm/cache.h
@@ -18,17 +18,17 @@
#include <asm/cachetype.h>
-#define L1_CACHE_SHIFT 7
+#define L1_CACHE_SHIFT 6
#define L1_CACHE_BYTES (1 << L1_CACHE_SHIFT)
/*
* Memory returned by kmalloc() may be used for DMA, so we must make
- * sure that all such allocations are cache aligned. Otherwise,
- * unrelated code may cause parts of the buffer to be read into the
- * cache before the transfer is done, causing old data to be seen by
- * the CPU.
+ * sure that all such allocations are aligned to the maximum *known*
+ * cache line size on ARMv8 systems. Otherwise, unrelated code may
+ * cause parts of the buffer to be read into the cache before the
+ * transfer is done, causing old data to be seen by the CPU.
*/
-#define ARCH_DMA_MINALIGN L1_CACHE_BYTES
+#define ARCH_DMA_MINALIGN (128)
#ifndef __ASSEMBLY__
diff --git a/arch/arm64/kernel/cpufeature.c b/arch/arm64/kernel/cpufeature.c
index cdf1dca64133..f75000996e4c 100644
--- a/arch/arm64/kernel/cpufeature.c
+++ b/arch/arm64/kernel/cpufeature.c
@@ -992,9 +992,9 @@ void __init setup_cpu_features(void)
if (!cwg)
pr_warn("No Cache Writeback Granule information, assuming cache line size %d\n",
cls);
- if (L1_CACHE_BYTES < cls)
- pr_warn("L1_CACHE_BYTES smaller than the Cache Writeback Granule (%d < %d)\n",
- L1_CACHE_BYTES, cls);
+ if (ARCH_DMA_MINALIGN < cls)
+ pr_warn("ARCH_DMA_MINALIGN smaller than the Cache Writeback Granule (%d < %d)\n",
+ ARCH_DMA_MINALIGN, cls);
}
static bool __maybe_unused
diff --git a/drivers/android/Kconfig b/drivers/android/Kconfig
index a82fc022d34b..4d4cdc1a6e25 100644
--- a/drivers/android/Kconfig
+++ b/drivers/android/Kconfig
@@ -22,7 +22,7 @@ config ANDROID_BINDER_IPC
config ANDROID_BINDER_DEVICES
string "Android Binder devices"
depends on ANDROID_BINDER_IPC
- default "binder"
+ default "binder,hwbinder,vndbinder"
---help---
Default value for the binder.devices parameter.
diff --git a/drivers/android/binder.c b/drivers/android/binder.c
index d0334e50f2f9..d1490be45c67 100644
--- a/drivers/android/binder.c
+++ b/drivers/android/binder.c
@@ -18,6 +18,7 @@
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
#include <asm/cacheflush.h>
+#include <linux/atomic.h>
#include <linux/fdtable.h>
#include <linux/file.h>
#include <linux/freezer.h>
@@ -46,19 +47,11 @@
#include <uapi/linux/android/binder.h>
#include "binder_trace.h"
-static DEFINE_MUTEX(binder_main_lock);
-static DEFINE_MUTEX(binder_deferred_lock);
-static DEFINE_MUTEX(binder_mmap_lock);
-
static HLIST_HEAD(binder_devices);
-static HLIST_HEAD(binder_procs);
-static HLIST_HEAD(binder_deferred_list);
-static HLIST_HEAD(binder_dead_nodes);
static struct dentry *binder_debugfs_dir_entry_root;
static struct dentry *binder_debugfs_dir_entry_proc;
-static int binder_last_id;
-static struct workqueue_struct *binder_deferred_workqueue;
+atomic_t binder_last_id;
#define BINDER_DEBUG_ENTRY(name) \
static int binder_##name##_open(struct inode *inode, struct file *file) \
@@ -173,20 +166,24 @@ enum binder_stat_types {
struct binder_stats {
int br[_IOC_NR(BR_FAILED_REPLY) + 1];
int bc[_IOC_NR(BC_REPLY_SG) + 1];
- int obj_created[BINDER_STAT_COUNT];
- int obj_deleted[BINDER_STAT_COUNT];
};
-static struct binder_stats binder_stats;
+/* These are still global, since it's not always easy to get the context */
+struct binder_obj_stats {
+ atomic_t obj_created[BINDER_STAT_COUNT];
+ atomic_t obj_deleted[BINDER_STAT_COUNT];
+};
+
+static struct binder_obj_stats binder_obj_stats;
static inline void binder_stats_deleted(enum binder_stat_types type)
{
- binder_stats.obj_deleted[type]++;
+ atomic_inc(&binder_obj_stats.obj_deleted[type]);
}
static inline void binder_stats_created(enum binder_stat_types type)
{
- binder_stats.obj_created[type]++;
+ atomic_inc(&binder_obj_stats.obj_created[type]);
}
struct binder_transaction_log_entry {
@@ -207,8 +204,6 @@ struct binder_transaction_log {
int full;
struct binder_transaction_log_entry entry[32];
};
-static struct binder_transaction_log binder_transaction_log;
-static struct binder_transaction_log binder_transaction_log_failed;
static struct binder_transaction_log_entry *binder_transaction_log_add(
struct binder_transaction_log *log)
@@ -229,6 +224,21 @@ struct binder_context {
struct binder_node *binder_context_mgr_node;
kuid_t binder_context_mgr_uid;
const char *name;
+
+ struct mutex binder_main_lock;
+ struct mutex binder_deferred_lock;
+ struct mutex binder_mmap_lock;
+
+ struct hlist_head binder_procs;
+ struct hlist_head binder_dead_nodes;
+ struct hlist_head binder_deferred_list;
+
+ struct work_struct deferred_work;
+ struct workqueue_struct *binder_deferred_workqueue;
+ struct binder_transaction_log transaction_log;
+ struct binder_transaction_log transaction_log_failed;
+
+ struct binder_stats binder_stats;
};
struct binder_device {
@@ -459,18 +469,19 @@ static long task_close_fd(struct binder_proc *proc, unsigned int fd)
return retval;
}
-static inline void binder_lock(const char *tag)
+static inline void binder_lock(struct binder_context *context, const char *tag)
{
trace_binder_lock(tag);
- mutex_lock(&binder_main_lock);
+ mutex_lock(&context->binder_main_lock);
preempt_disable();
trace_binder_locked(tag);
}
-static inline void binder_unlock(const char *tag)
+static inline void binder_unlock(struct binder_context *context,
+ const char *tag)
{
trace_binder_unlock(tag);
- mutex_unlock(&binder_main_lock);
+ mutex_unlock(&context->binder_main_lock);
preempt_enable();
}
@@ -1017,7 +1028,7 @@ static struct binder_node *binder_new_node(struct binder_proc *proc,
binder_stats_created(BINDER_STAT_NODE);
rb_link_node(&node->rb_node, parent, p);
rb_insert_color(&node->rb_node, &proc->nodes);
- node->debug_id = ++binder_last_id;
+ node->debug_id = atomic_inc_return(&binder_last_id);
node->proc = proc;
node->ptr = ptr;
node->cookie = cookie;
@@ -1159,7 +1170,7 @@ static struct binder_ref *binder_get_ref_for_node(struct binder_proc *proc,
if (new_ref == NULL)
return NULL;
binder_stats_created(BINDER_STAT_REF);
- new_ref->debug_id = ++binder_last_id;
+ new_ref->debug_id = atomic_inc_return(&binder_last_id);
new_ref->proc = proc;
new_ref->node = node;
rb_link_node(&new_ref->rb_node_node, parent, p);
@@ -1920,7 +1931,7 @@ static void binder_transaction(struct binder_proc *proc,
binder_size_t last_fixup_min_off = 0;
struct binder_context *context = proc->context;
- e = binder_transaction_log_add(&binder_transaction_log);
+ e = binder_transaction_log_add(&context->transaction_log);
e->call_type = reply ? 2 : !!(tr->flags & TF_ONE_WAY);
e->from_proc = proc->pid;
e->from_thread = thread->pid;
@@ -2042,7 +2053,7 @@ static void binder_transaction(struct binder_proc *proc,
}
binder_stats_created(BINDER_STAT_TRANSACTION_COMPLETE);
- t->debug_id = ++binder_last_id;
+ t->debug_id = atomic_inc_return(&binder_last_id);
e->debug_id = t->debug_id;
if (reply)
@@ -2315,7 +2326,8 @@ err_no_context_mgr_node:
{
struct binder_transaction_log_entry *fe;
- fe = binder_transaction_log_add(&binder_transaction_log_failed);
+ fe = binder_transaction_log_add(
+ &context->transaction_log_failed);
*fe = *e;
}
@@ -2343,8 +2355,8 @@ static int binder_thread_write(struct binder_proc *proc,
return -EFAULT;
ptr += sizeof(uint32_t);
trace_binder_command(cmd);
- if (_IOC_NR(cmd) < ARRAY_SIZE(binder_stats.bc)) {
- binder_stats.bc[_IOC_NR(cmd)]++;
+ if (_IOC_NR(cmd) < ARRAY_SIZE(context->binder_stats.bc)) {
+ context->binder_stats.bc[_IOC_NR(cmd)]++;
proc->stats.bc[_IOC_NR(cmd)]++;
thread->stats.bc[_IOC_NR(cmd)]++;
}
@@ -2710,8 +2722,8 @@ static void binder_stat_br(struct binder_proc *proc,
struct binder_thread *thread, uint32_t cmd)
{
trace_binder_return(cmd);
- if (_IOC_NR(cmd) < ARRAY_SIZE(binder_stats.br)) {
- binder_stats.br[_IOC_NR(cmd)]++;
+ if (_IOC_NR(cmd) < ARRAY_SIZE(proc->stats.br)) {
+ proc->context->binder_stats.br[_IOC_NR(cmd)]++;
proc->stats.br[_IOC_NR(cmd)]++;
thread->stats.br[_IOC_NR(cmd)]++;
}
@@ -2775,7 +2787,7 @@ retry:
if (wait_for_proc_work)
proc->ready_threads++;
- binder_unlock(__func__);
+ binder_unlock(proc->context, __func__);
trace_binder_wait_for_work(wait_for_proc_work,
!!thread->transaction_stack,
@@ -2802,7 +2814,7 @@ retry:
ret = wait_event_freezable(thread->wait, binder_has_thread_work(thread));
}
- binder_lock(__func__);
+ binder_lock(proc->context, __func__);
if (wait_for_proc_work)
proc->ready_threads--;
@@ -3188,14 +3200,14 @@ static unsigned int binder_poll(struct file *filp,
struct binder_thread *thread = NULL;
int wait_for_proc_work;
- binder_lock(__func__);
+ binder_lock(proc->context, __func__);
thread = binder_get_thread(proc);
wait_for_proc_work = thread->transaction_stack == NULL &&
list_empty(&thread->todo) && thread->return_error == BR_OK;
- binder_unlock(__func__);
+ binder_unlock(proc->context, __func__);
if (wait_for_proc_work) {
if (binder_has_proc_work(proc, thread))
@@ -3322,6 +3334,7 @@ static long binder_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
{
int ret;
struct binder_proc *proc = filp->private_data;
+ struct binder_context *context = proc->context;
struct binder_thread *thread;
unsigned int size = _IOC_SIZE(cmd);
void __user *ubuf = (void __user *)arg;
@@ -3335,7 +3348,7 @@ static long binder_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
if (ret)
goto err_unlocked;
- binder_lock(__func__);
+ binder_lock(context, __func__);
thread = binder_get_thread(proc);
if (thread == NULL) {
ret = -ENOMEM;
@@ -3386,7 +3399,7 @@ static long binder_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
err:
if (thread)
thread->looper &= ~BINDER_LOOPER_STATE_NEED_RETURN;
- binder_unlock(__func__);
+ binder_unlock(context, __func__);
wait_event_interruptible(binder_user_error_wait, binder_stop_on_user_error < 2);
if (ret && ret != -ERESTARTSYS)
pr_info("%d:%d ioctl %x %lx returned %d\n", proc->pid, current->pid, cmd, arg, ret);
@@ -3440,7 +3453,7 @@ static int binder_mmap(struct file *filp, struct vm_area_struct *vma)
const char *failure_string;
struct binder_buffer *buffer;
- if (proc->tsk != current)
+ if (proc->tsk != current->group_leader)
return -EINVAL;
if ((vma->vm_end - vma->vm_start) > SZ_4M)
@@ -3459,7 +3472,7 @@ static int binder_mmap(struct file *filp, struct vm_area_struct *vma)
}
vma->vm_flags = (vma->vm_flags | VM_DONTCOPY) & ~VM_MAYWRITE;
- mutex_lock(&binder_mmap_lock);
+ mutex_lock(&proc->context->binder_mmap_lock);
if (proc->buffer) {
ret = -EBUSY;
failure_string = "already mapped";
@@ -3474,7 +3487,7 @@ static int binder_mmap(struct file *filp, struct vm_area_struct *vma)
}
proc->buffer = area->addr;
proc->user_buffer_offset = vma->vm_start - (uintptr_t)proc->buffer;
- mutex_unlock(&binder_mmap_lock);
+ mutex_unlock(&proc->context->binder_mmap_lock);
#ifdef CONFIG_CPU_CACHE_VIPT
if (cache_is_vipt_aliasing()) {
@@ -3523,12 +3536,12 @@ err_alloc_small_buf_failed:
kfree(proc->pages);
proc->pages = NULL;
err_alloc_pages_failed:
- mutex_lock(&binder_mmap_lock);
+ mutex_lock(&proc->context->binder_mmap_lock);
vfree(proc->buffer);
proc->buffer = NULL;
err_get_vm_area_failed:
err_already_mapped:
- mutex_unlock(&binder_mmap_lock);
+ mutex_unlock(&proc->context->binder_mmap_lock);
err_bad_arg:
pr_err("binder_mmap: %d %lx-%lx %s failed %d\n",
proc->pid, vma->vm_start, vma->vm_end, failure_string, ret);
@@ -3546,8 +3559,8 @@ static int binder_open(struct inode *nodp, struct file *filp)
proc = kzalloc(sizeof(*proc), GFP_KERNEL);
if (proc == NULL)
return -ENOMEM;
- get_task_struct(current);
- proc->tsk = current;
+ get_task_struct(current->group_leader);
+ proc->tsk = current->group_leader;
INIT_LIST_HEAD(&proc->todo);
init_waitqueue_head(&proc->wait);
proc->default_priority = task_nice(current);
@@ -3555,15 +3568,15 @@ static int binder_open(struct inode *nodp, struct file *filp)
miscdev);
proc->context = &binder_dev->context;
- binder_lock(__func__);
+ binder_lock(proc->context, __func__);
binder_stats_created(BINDER_STAT_PROC);
- hlist_add_head(&proc->proc_node, &binder_procs);
+ hlist_add_head(&proc->proc_node, &proc->context->binder_procs);
proc->pid = current->group_leader->pid;
INIT_LIST_HEAD(&proc->delivered_death);
filp->private_data = proc;
- binder_unlock(__func__);
+ binder_unlock(proc->context, __func__);
if (binder_debugfs_dir_entry_proc) {
char strbuf[11];
@@ -3628,6 +3641,7 @@ static int binder_release(struct inode *nodp, struct file *filp)
static int binder_node_release(struct binder_node *node, int refs)
{
struct binder_ref *ref;
+ struct binder_context *context = node->proc->context;
int death = 0;
list_del_init(&node->work.entry);
@@ -3643,7 +3657,7 @@ static int binder_node_release(struct binder_node *node, int refs)
node->proc = NULL;
node->local_strong_refs = 0;
node->local_weak_refs = 0;
- hlist_add_head(&node->dead_node, &binder_dead_nodes);
+ hlist_add_head(&node->dead_node, &context->binder_dead_nodes);
hlist_for_each_entry(ref, &node->refs, node_entry) {
refs++;
@@ -3708,7 +3722,8 @@ static void binder_deferred_release(struct binder_proc *proc)
node = rb_entry(n, struct binder_node, rb_node);
nodes++;
rb_erase(&node->rb_node, &proc->nodes);
- incoming_refs = binder_node_release(node, incoming_refs);
+ incoming_refs = binder_node_release(node,
+ incoming_refs);
}
outgoing_refs = 0;
@@ -3780,18 +3795,20 @@ static void binder_deferred_func(struct work_struct *work)
{
struct binder_proc *proc;
struct files_struct *files;
+ struct binder_context *context =
+ container_of(work, struct binder_context, deferred_work);
int defer;
do {
trace_binder_lock(__func__);
- mutex_lock(&binder_main_lock);
+ mutex_lock(&context->binder_main_lock);
trace_binder_locked(__func__);
- mutex_lock(&binder_deferred_lock);
+ mutex_lock(&context->binder_deferred_lock);
preempt_disable();
- if (!hlist_empty(&binder_deferred_list)) {
- proc = hlist_entry(binder_deferred_list.first,
+ if (!hlist_empty(&context->binder_deferred_list)) {
+ proc = hlist_entry(context->binder_deferred_list.first,
struct binder_proc, deferred_work_node);
hlist_del_init(&proc->deferred_work_node);
defer = proc->deferred_work;
@@ -3800,7 +3817,7 @@ static void binder_deferred_func(struct work_struct *work)
proc = NULL;
defer = 0;
}
- mutex_unlock(&binder_deferred_lock);
+ mutex_unlock(&context->binder_deferred_lock);
files = NULL;
if (defer & BINDER_DEFERRED_PUT_FILES) {
@@ -3816,25 +3833,25 @@ static void binder_deferred_func(struct work_struct *work)
binder_deferred_release(proc); /* frees proc */
trace_binder_unlock(__func__);
- mutex_unlock(&binder_main_lock);
+ mutex_unlock(&context->binder_main_lock);
preempt_enable_no_resched();
if (files)
put_files_struct(files);
} while (proc);
}
-static DECLARE_WORK(binder_deferred_work, binder_deferred_func);
static void
binder_defer_work(struct binder_proc *proc, enum binder_deferred_state defer)
{
- mutex_lock(&binder_deferred_lock);
+ mutex_lock(&proc->context->binder_deferred_lock);
proc->deferred_work |= defer;
if (hlist_unhashed(&proc->deferred_work_node)) {
hlist_add_head(&proc->deferred_work_node,
- &binder_deferred_list);
- queue_work(binder_deferred_workqueue, &binder_deferred_work);
+ &proc->context->binder_deferred_list);
+ queue_work(proc->context->binder_deferred_workqueue,
+ &proc->context->deferred_work);
}
- mutex_unlock(&binder_deferred_lock);
+ mutex_unlock(&proc->context->binder_deferred_lock);
}
static void print_binder_transaction(struct seq_file *m, const char *prefix,
@@ -4065,8 +4082,20 @@ static const char * const binder_objstat_strings[] = {
"transaction_complete"
};
+static void add_binder_stats(struct binder_stats *from, struct binder_stats *to)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(to->bc); i++)
+ to->bc[i] += from->bc[i];
+
+ for (i = 0; i < ARRAY_SIZE(to->br); i++)
+ to->br[i] += from->br[i];
+}
+
static void print_binder_stats(struct seq_file *m, const char *prefix,
- struct binder_stats *stats)
+ struct binder_stats *stats,
+ struct binder_obj_stats *obj_stats)
{
int i;
@@ -4086,16 +4115,21 @@ static void print_binder_stats(struct seq_file *m, const char *prefix,
binder_return_strings[i], stats->br[i]);
}
- BUILD_BUG_ON(ARRAY_SIZE(stats->obj_created) !=
+ if (!obj_stats)
+ return;
+
+ BUILD_BUG_ON(ARRAY_SIZE(obj_stats->obj_created) !=
ARRAY_SIZE(binder_objstat_strings));
- BUILD_BUG_ON(ARRAY_SIZE(stats->obj_created) !=
- ARRAY_SIZE(stats->obj_deleted));
- for (i = 0; i < ARRAY_SIZE(stats->obj_created); i++) {
- if (stats->obj_created[i] || stats->obj_deleted[i])
+ BUILD_BUG_ON(ARRAY_SIZE(obj_stats->obj_created) !=
+ ARRAY_SIZE(obj_stats->obj_deleted));
+ for (i = 0; i < ARRAY_SIZE(obj_stats->obj_created); i++) {
+ int obj_created = atomic_read(&obj_stats->obj_created[i]);
+ int obj_deleted = atomic_read(&obj_stats->obj_deleted[i]);
+
+ if (obj_created || obj_deleted)
seq_printf(m, "%s%s: active %d total %d\n", prefix,
- binder_objstat_strings[i],
- stats->obj_created[i] - stats->obj_deleted[i],
- stats->obj_created[i]);
+ binder_objstat_strings[i],
+ obj_created - obj_deleted, obj_created);
}
}
@@ -4150,85 +4184,131 @@ static void print_binder_proc_stats(struct seq_file *m,
}
seq_printf(m, " pending transactions: %d\n", count);
- print_binder_stats(m, " ", &proc->stats);
+ print_binder_stats(m, " ", &proc->stats, NULL);
}
static int binder_state_show(struct seq_file *m, void *unused)
{
+ struct binder_device *device;
+ struct binder_context *context;
struct binder_proc *proc;
struct binder_node *node;
int do_lock = !binder_debug_no_lock;
-
- if (do_lock)
- binder_lock(__func__);
+ bool wrote_dead_nodes_header = false;
seq_puts(m, "binder state:\n");
- if (!hlist_empty(&binder_dead_nodes))
- seq_puts(m, "dead nodes:\n");
- hlist_for_each_entry(node, &binder_dead_nodes, dead_node)
- print_binder_node(m, node);
+ hlist_for_each_entry(device, &binder_devices, hlist) {
+ context = &device->context;
+ if (do_lock)
+ binder_lock(context, __func__);
+ if (!wrote_dead_nodes_header &&
+ !hlist_empty(&context->binder_dead_nodes)) {
+ seq_puts(m, "dead nodes:\n");
+ wrote_dead_nodes_header = true;
+ }
+ hlist_for_each_entry(node, &context->binder_dead_nodes,
+ dead_node)
+ print_binder_node(m, node);
+
+ if (do_lock)
+ binder_unlock(context, __func__);
+ }
- hlist_for_each_entry(proc, &binder_procs, proc_node)
- print_binder_proc(m, proc, 1);
- if (do_lock)
- binder_unlock(__func__);
+ hlist_for_each_entry(device, &binder_devices, hlist) {
+ context = &device->context;
+ if (do_lock)
+ binder_lock(context, __func__);
+
+ hlist_for_each_entry(proc, &context->binder_procs, proc_node)
+ print_binder_proc(m, proc, 1);
+ if (do_lock)
+ binder_unlock(context, __func__);
+ }
return 0;
}
static int binder_stats_show(struct seq_file *m, void *unused)
{
+ struct binder_device *device;
+ struct binder_context *context;
struct binder_proc *proc;
+ struct binder_stats total_binder_stats;
int do_lock = !binder_debug_no_lock;
- if (do_lock)
- binder_lock(__func__);
+ memset(&total_binder_stats, 0, sizeof(struct binder_stats));
+
+ hlist_for_each_entry(device, &binder_devices, hlist) {
+ context = &device->context;
+ if (do_lock)
+ binder_lock(context, __func__);
+
+ add_binder_stats(&context->binder_stats, &total_binder_stats);
+
+ if (do_lock)
+ binder_unlock(context, __func__);
+ }
seq_puts(m, "binder stats:\n");
+ print_binder_stats(m, "", &total_binder_stats, &binder_obj_stats);
- print_binder_stats(m, "", &binder_stats);
+ hlist_for_each_entry(device, &binder_devices, hlist) {
+ context = &device->context;
+ if (do_lock)
+ binder_lock(context, __func__);
- hlist_for_each_entry(proc, &binder_procs, proc_node)
- print_binder_proc_stats(m, proc);
- if (do_lock)
- binder_unlock(__func__);
+ hlist_for_each_entry(proc, &context->binder_procs, proc_node)
+ print_binder_proc_stats(m, proc);
+ if (do_lock)
+ binder_unlock(context, __func__);
+ }
return 0;
}
static int binder_transactions_show(struct seq_file *m, void *unused)
{
+ struct binder_device *device;
+ struct binder_context *context;
struct binder_proc *proc;
int do_lock = !binder_debug_no_lock;
- if (do_lock)
- binder_lock(__func__);
-
seq_puts(m, "binder transactions:\n");
- hlist_for_each_entry(proc, &binder_procs, proc_node)
- print_binder_proc(m, proc, 0);
- if (do_lock)
- binder_unlock(__func__);
+ hlist_for_each_entry(device, &binder_devices, hlist) {
+ context = &device->context;
+ if (do_lock)
+ binder_lock(context, __func__);
+
+ hlist_for_each_entry(proc, &context->binder_procs, proc_node)
+ print_binder_proc(m, proc, 0);
+ if (do_lock)
+ binder_unlock(context, __func__);
+ }
return 0;
}
static int binder_proc_show(struct seq_file *m, void *unused)
{
+ struct binder_device *device;
+ struct binder_context *context;
struct binder_proc *itr;
int pid = (unsigned long)m->private;
int do_lock = !binder_debug_no_lock;
- if (do_lock)
- binder_lock(__func__);
+ hlist_for_each_entry(device, &binder_devices, hlist) {
+ context = &device->context;
+ if (do_lock)
+ binder_lock(context, __func__);
- hlist_for_each_entry(itr, &binder_procs, proc_node) {
- if (itr->pid == pid) {
- seq_puts(m, "binder proc state:\n");
- print_binder_proc(m, itr, 1);
+ hlist_for_each_entry(itr, &context->binder_procs, proc_node) {
+ if (itr->pid == pid) {
+ seq_puts(m, "binder proc state:\n");
+ print_binder_proc(m, itr, 1);
+ }
}
+ if (do_lock)
+ binder_unlock(context, __func__);
}
- if (do_lock)
- binder_unlock(__func__);
return 0;
}
@@ -4243,11 +4323,10 @@ static void print_binder_transaction_log_entry(struct seq_file *m,
e->to_node, e->target_handle, e->data_size, e->offsets_size);
}
-static int binder_transaction_log_show(struct seq_file *m, void *unused)
+static int print_binder_transaction_log(struct seq_file *m,
+ struct binder_transaction_log *log)
{
- struct binder_transaction_log *log = m->private;
int i;
-
if (log->full) {
for (i = log->next; i < ARRAY_SIZE(log->entry); i++)
print_binder_transaction_log_entry(m, &log->entry[i]);
@@ -4257,6 +4336,31 @@ static int binder_transaction_log_show(struct seq_file *m, void *unused)
return 0;
}
+static int binder_transaction_log_show(struct seq_file *m, void *unused)
+{
+ struct binder_device *device;
+ struct binder_context *context;
+
+ hlist_for_each_entry(device, &binder_devices, hlist) {
+ context = &device->context;
+ print_binder_transaction_log(m, &context->transaction_log);
+ }
+ return 0;
+}
+
+static int binder_failed_transaction_log_show(struct seq_file *m, void *unused)
+{
+ struct binder_device *device;
+ struct binder_context *context;
+
+ hlist_for_each_entry(device, &binder_devices, hlist) {
+ context = &device->context;
+ print_binder_transaction_log(m,
+ &context->transaction_log_failed);
+ }
+ return 0;
+}
+
static const struct file_operations binder_fops = {
.owner = THIS_MODULE,
.poll = binder_poll,
@@ -4272,11 +4376,20 @@ BINDER_DEBUG_ENTRY(state);
BINDER_DEBUG_ENTRY(stats);
BINDER_DEBUG_ENTRY(transactions);
BINDER_DEBUG_ENTRY(transaction_log);
+BINDER_DEBUG_ENTRY(failed_transaction_log);
+
+static void __init free_binder_device(struct binder_device *device)
+{
+ if (device->context.binder_deferred_workqueue)
+ destroy_workqueue(device->context.binder_deferred_workqueue);
+ kfree(device);
+}
static int __init init_binder_device(const char *name)
{
int ret;
struct binder_device *binder_device;
+ struct binder_context *context;
binder_device = kzalloc(sizeof(*binder_device), GFP_KERNEL);
if (!binder_device)
@@ -4286,31 +4399,65 @@ static int __init init_binder_device(const char *name)
binder_device->miscdev.minor = MISC_DYNAMIC_MINOR;
binder_device->miscdev.name = name;
- binder_device->context.binder_context_mgr_uid = INVALID_UID;
- binder_device->context.name = name;
+ context = &binder_device->context;
+ context->binder_context_mgr_uid = INVALID_UID;
+ context->name = name;
+
+ mutex_init(&context->binder_main_lock);
+ mutex_init(&context->binder_deferred_lock);
+ mutex_init(&context->binder_mmap_lock);
+
+ context->binder_deferred_workqueue =
+ create_singlethread_workqueue(name);
+
+ if (!context->binder_deferred_workqueue) {
+ ret = -ENOMEM;
+ goto err_create_singlethread_workqueue_failed;
+ }
+
+ INIT_HLIST_HEAD(&context->binder_procs);
+ INIT_HLIST_HEAD(&context->binder_dead_nodes);
+ INIT_HLIST_HEAD(&context->binder_deferred_list);
+ INIT_WORK(&context->deferred_work, binder_deferred_func);
ret = misc_register(&binder_device->miscdev);
if (ret < 0) {
- kfree(binder_device);
- return ret;
+ goto err_misc_register_failed;
}
hlist_add_head(&binder_device->hlist, &binder_devices);
+ return ret;
+
+err_create_singlethread_workqueue_failed:
+err_misc_register_failed:
+ free_binder_device(binder_device);
return ret;
}
static int __init binder_init(void)
{
- int ret;
+ int ret = 0;
char *device_name, *device_names;
struct binder_device *device;
struct hlist_node *tmp;
- binder_deferred_workqueue = create_singlethread_workqueue("binder");
- if (!binder_deferred_workqueue)
+ /*
+ * Copy the module_parameter string, because we don't want to
+ * tokenize it in-place.
+ */
+ device_names = kzalloc(strlen(binder_devices_param) + 1, GFP_KERNEL);
+ if (!device_names)
return -ENOMEM;
+ strcpy(device_names, binder_devices_param);
+
+ while ((device_name = strsep(&device_names, ","))) {
+ ret = init_binder_device(device_name);
+ if (ret)
+ goto err_init_binder_device_failed;
+ }
+
binder_debugfs_dir_entry_root = debugfs_create_dir("binder", NULL);
if (binder_debugfs_dir_entry_root)
binder_debugfs_dir_entry_proc = debugfs_create_dir("proc",
@@ -4335,30 +4482,13 @@ static int __init binder_init(void)
debugfs_create_file("transaction_log",
S_IRUGO,
binder_debugfs_dir_entry_root,
- &binder_transaction_log,
+ NULL,
&binder_transaction_log_fops);
debugfs_create_file("failed_transaction_log",
S_IRUGO,
binder_debugfs_dir_entry_root,
- &binder_transaction_log_failed,
- &binder_transaction_log_fops);
- }
-
- /*
- * Copy the module_parameter string, because we don't want to
- * tokenize it in-place.
- */
- device_names = kzalloc(strlen(binder_devices_param) + 1, GFP_KERNEL);
- if (!device_names) {
- ret = -ENOMEM;
- goto err_alloc_device_names_failed;
- }
- strcpy(device_names, binder_devices_param);
-
- while ((device_name = strsep(&device_names, ","))) {
- ret = init_binder_device(device_name);
- if (ret)
- goto err_init_binder_device_failed;
+ NULL,
+ &binder_failed_transaction_log_fops);
}
return ret;
@@ -4367,12 +4497,8 @@ err_init_binder_device_failed:
hlist_for_each_entry_safe(device, tmp, &binder_devices, hlist) {
misc_deregister(&device->miscdev);
hlist_del(&device->hlist);
- kfree(device);
+ free_binder_device(device);
}
-err_alloc_device_names_failed:
- debugfs_remove_recursive(binder_debugfs_dir_entry_root);
-
- destroy_workqueue(binder_deferred_workqueue);
return ret;
}
diff --git a/drivers/char/Kconfig b/drivers/char/Kconfig
index ebbe31fee7ae..8e3bff9c7fe9 100644
--- a/drivers/char/Kconfig
+++ b/drivers/char/Kconfig
@@ -607,7 +607,7 @@ source "drivers/char/xillybus/Kconfig"
config MSM_ADSPRPC
tristate "QTI ADSP RPC driver"
- depends on MSM_GLINK
+ depends on MSM_SMD
help
Provides a communication mechanism that allows for clients to
make remote method invocations across processor boundary to
diff --git a/drivers/char/adsprpc.c b/drivers/char/adsprpc.c
index 479599473381..10c4d8ce2410 100644
--- a/drivers/char/adsprpc.c
+++ b/drivers/char/adsprpc.c
@@ -25,6 +25,7 @@
#include <linux/hash.h>
#include <linux/msm_ion.h>
#include <soc/qcom/secure_buffer.h>
+#include <soc/qcom/smd.h>
#include <soc/qcom/glink.h>
#include <soc/qcom/subsystem_notif.h>
#include <soc/qcom/subsystem_restart.h>
@@ -213,6 +214,7 @@ struct fastrpc_channel_ctx {
struct completion work;
struct notifier_block nb;
struct kref kref;
+ int channel;
int sesscount;
int ssrcount;
void *handle;
@@ -238,6 +240,7 @@ struct fastrpc_apps {
spinlock_t hlock;
struct ion_client *client;
struct device *dev;
+ bool glink;
};
struct fastrpc_mmap {
@@ -298,18 +301,21 @@ static struct fastrpc_channel_ctx gcinfo[NUM_CHANNELS] = {
{
.name = "adsprpc-smd",
.subsys = "adsp",
+ .channel = SMD_APPS_QDSP,
.link.link_info.edge = "lpass",
.link.link_info.transport = "smem",
},
{
.name = "mdsprpc-smd",
.subsys = "modem",
+ .channel = SMD_APPS_MODEM,
.link.link_info.edge = "mpss",
.link.link_info.transport = "smem",
},
{
.name = "sdsprpc-smd",
.subsys = "slpi",
+ .channel = SMD_APPS_DSPS,
.link.link_info.edge = "dsps",
.link.link_info.transport = "smem",
.vmid = VMID_SSC_Q6,
@@ -1382,7 +1388,7 @@ static int fastrpc_invoke_send(struct smq_invoke_ctx *ctx,
struct smq_msg *msg = &ctx->msg;
struct fastrpc_file *fl = ctx->fl;
struct fastrpc_channel_ctx *channel_ctx = &fl->apps->channel[fl->cid];
- int err = 0;
+ int err = 0, len;
VERIFY(err, 0 != channel_ctx->chan);
if (err)
@@ -1397,21 +1403,64 @@ static int fastrpc_invoke_send(struct smq_invoke_ctx *ctx,
msg->invoke.page.addr = ctx->buf ? ctx->buf->phys : 0;
msg->invoke.page.size = buf_page_size(ctx->used);
- if (fl->ssrcount != channel_ctx->ssrcount) {
- err = -ECONNRESET;
- goto bail;
+ if (fl->apps->glink) {
+ if (fl->ssrcount != channel_ctx->ssrcount) {
+ err = -ECONNRESET;
+ goto bail;
+ }
+ VERIFY(err, channel_ctx->link.port_state ==
+ FASTRPC_LINK_CONNECTED);
+ if (err)
+ goto bail;
+ err = glink_tx(channel_ctx->chan,
+ (void *)&fl->apps->channel[fl->cid], msg, sizeof(*msg),
+ GLINK_TX_REQ_INTENT);
+ } else {
+ spin_lock(&fl->apps->hlock);
+ len = smd_write((smd_channel_t *)
+ channel_ctx->chan,
+ msg, sizeof(*msg));
+ spin_unlock(&fl->apps->hlock);
+ VERIFY(err, len == sizeof(*msg));
}
- VERIFY(err, channel_ctx->link.port_state ==
- FASTRPC_LINK_CONNECTED);
- if (err)
- goto bail;
- err = glink_tx(channel_ctx->chan,
- (void *)&fl->apps->channel[fl->cid], msg, sizeof(*msg),
- GLINK_TX_REQ_INTENT);
bail:
return err;
}
+static void fastrpc_smd_read_handler(int cid)
+{
+ struct fastrpc_apps *me = &gfa;
+ struct smq_invoke_rsp rsp = {0};
+ int ret = 0;
+
+ do {
+ ret = smd_read_from_cb(me->channel[cid].chan, &rsp,
+ sizeof(rsp));
+ if (ret != sizeof(rsp))
+ break;
+ rsp.ctx = rsp.ctx & ~1;
+ context_notify_user(uint64_to_ptr(rsp.ctx), rsp.retval);
+ } while (ret == sizeof(rsp));
+}
+
+static void smd_event_handler(void *priv, unsigned event)
+{
+ struct fastrpc_apps *me = &gfa;
+ int cid = (int)(uintptr_t)priv;
+
+ switch (event) {
+ case SMD_EVENT_OPEN:
+ complete(&me->channel[cid].work);
+ break;
+ case SMD_EVENT_CLOSE:
+ fastrpc_notify_drivers(me, cid);
+ break;
+ case SMD_EVENT_DATA:
+ fastrpc_smd_read_handler(cid);
+ break;
+ }
+}
+
static void fastrpc_init(struct fastrpc_apps *me)
{
int i;
@@ -1987,10 +2036,12 @@ static void fastrpc_channel_close(struct kref *kref)
ctx = container_of(kref, struct fastrpc_channel_ctx, kref);
cid = ctx - &gcinfo[0];
- fastrpc_glink_close(ctx->chan, cid);
+ if (!me->glink)
+ smd_close(ctx->chan);
+ else
+ fastrpc_glink_close(ctx->chan, cid);
+
ctx->chan = 0;
- glink_unregister_link_state_cb(ctx->link.link_notify_handle);
- ctx->link.link_notify_handle = 0;
mutex_unlock(&me->smd_mutex);
pr_info("'closed /dev/%s c %d %d'\n", gcinfo[cid].name,
MAJOR(me->dev_no), cid);
@@ -2405,8 +2456,16 @@ static int fastrpc_channel_open(struct fastrpc_file *fl)
fl->ssrcount = me->channel[cid].ssrcount;
if ((kref_get_unless_zero(&me->channel[cid].kref) == 0) ||
(me->channel[cid].chan == 0)) {
- fastrpc_glink_register(cid, me);
- VERIFY(err, 0 == fastrpc_glink_open(cid));
+ if (me->glink) {
+ fastrpc_glink_register(cid, me);
+ VERIFY(err, 0 == fastrpc_glink_open(cid));
+ } else {
+ VERIFY(err, !smd_named_open_on_edge(FASTRPC_SMD_GUID,
+ gcinfo[cid].channel,
+ (smd_channel_t **)&me->channel[cid].chan,
+ (void *)(uintptr_t)cid,
+ smd_event_handler));
+ }
if (err)
goto bail;
@@ -2635,7 +2694,11 @@ static int fastrpc_restart_notifier_cb(struct notifier_block *nb,
ctx->ssrcount++;
ctx->issubsystemup = 0;
if (ctx->chan) {
- fastrpc_glink_close(ctx->chan, cid);
+ if (me->glink)
+ fastrpc_glink_close(ctx->chan, cid);
+ else
+ smd_close(ctx->chan);
+
ctx->chan = 0;
pr_info("'restart notifier: closed /dev/%s c %d %d'\n",
gcinfo[cid].name, MAJOR(me->dev_no), cid);
@@ -2859,7 +2922,7 @@ static int fastrpc_probe(struct platform_device *pdev)
}
return 0;
}
-
+ me->glink = of_property_read_bool(dev->of_node, "qcom,fastrpc-glink");
VERIFY(err, !of_platform_populate(pdev->dev.of_node,
fastrpc_match_table,
NULL, &pdev->dev));
diff --git a/drivers/char/diag/diag_masks.c b/drivers/char/diag/diag_masks.c
index 0c958d855f94..437077c4d44d 100644
--- a/drivers/char/diag/diag_masks.c
+++ b/drivers/char/diag/diag_masks.c
@@ -456,8 +456,13 @@ static void diag_send_feature_mask_update(uint8_t peripheral)
DIAG_SET_FEATURE_MASK(F_DIAG_REQ_RSP_SUPPORT);
if (driver->supports_apps_hdlc_encoding)
DIAG_SET_FEATURE_MASK(F_DIAG_APPS_HDLC_ENCODE);
- if (driver->supports_apps_header_untagging)
- DIAG_SET_FEATURE_MASK(F_DIAG_PKT_HEADER_UNTAG);
+ if (driver->supports_apps_header_untagging) {
+ if (peripheral == PERIPHERAL_MODEM) {
+ DIAG_SET_FEATURE_MASK(F_DIAG_PKT_HEADER_UNTAG);
+ driver->peripheral_untag[peripheral] =
+ ENABLE_PKT_HEADER_UNTAGGING;
+ }
+ }
DIAG_SET_FEATURE_MASK(F_DIAG_MASK_CENTRALIZATION);
if (driver->supports_sockets)
DIAG_SET_FEATURE_MASK(F_DIAG_SOCKETS_ENABLED);
diff --git a/drivers/char/diag/diagchar.h b/drivers/char/diag/diagchar.h
index 511b019e33ec..b68a47219132 100644
--- a/drivers/char/diag/diagchar.h
+++ b/drivers/char/diag/diagchar.h
@@ -503,6 +503,7 @@ struct diagchar_dev {
int supports_separate_cmdrsp;
int supports_apps_hdlc_encoding;
int supports_apps_header_untagging;
+ int peripheral_untag[NUM_PERIPHERALS];
int supports_sockets;
/* The state requested in the STM command */
int stm_state_requested[NUM_STM_PROCESSORS];
diff --git a/drivers/char/diag/diagfwd.c b/drivers/char/diag/diagfwd.c
index 532d2b149317..07c90b741fa0 100644
--- a/drivers/char/diag/diagfwd.c
+++ b/drivers/char/diag/diagfwd.c
@@ -259,11 +259,17 @@ static void pack_rsp_and_send(unsigned char *buf, int len,
}
if (info && info->peripheral_mask) {
- for (i = 0; i <= NUM_PERIPHERALS; i++) {
- if (info->peripheral_mask & (1 << i))
- break;
+ if (info->peripheral_mask == DIAG_CON_ALL ||
+ (info->peripheral_mask & (1 << APPS_DATA)) ||
+ (info->peripheral_mask & (1 << PERIPHERAL_MODEM))) {
+ rsp_ctxt = SET_BUF_CTXT(APPS_DATA, TYPE_CMD, 1);
+ } else {
+ for (i = 0; i <= NUM_PERIPHERALS; i++) {
+ if (info->peripheral_mask & (1 << i))
+ break;
+ }
+ rsp_ctxt = SET_BUF_CTXT(i, TYPE_CMD, 1);
}
- rsp_ctxt = SET_BUF_CTXT(i, TYPE_CMD, 1);
} else
rsp_ctxt = driver->rsp_buf_ctxt;
@@ -337,11 +343,17 @@ static void encode_rsp_and_send(unsigned char *buf, int len,
}
if (info && info->peripheral_mask) {
- for (i = 0; i <= NUM_PERIPHERALS; i++) {
- if (info->peripheral_mask & (1 << i))
- break;
+ if (info->peripheral_mask == DIAG_CON_ALL ||
+ (info->peripheral_mask & (1 << APPS_DATA)) ||
+ (info->peripheral_mask & (1 << PERIPHERAL_MODEM))) {
+ rsp_ctxt = SET_BUF_CTXT(APPS_DATA, TYPE_CMD, 1);
+ } else {
+ for (i = 0; i <= NUM_PERIPHERALS; i++) {
+ if (info->peripheral_mask & (1 << i))
+ break;
+ }
+ rsp_ctxt = SET_BUF_CTXT(i, TYPE_CMD, 1);
}
- rsp_ctxt = SET_BUF_CTXT(i, TYPE_CMD, 1);
} else
rsp_ctxt = driver->rsp_buf_ctxt;
@@ -1588,6 +1600,8 @@ int diagfwd_init(void)
driver->supports_separate_cmdrsp = 1;
driver->supports_apps_hdlc_encoding = 1;
driver->supports_apps_header_untagging = 1;
+ for (i = 0; i < NUM_PERIPHERALS; i++)
+ driver->peripheral_untag[i] = 0;
mutex_init(&driver->diag_hdlc_mutex);
mutex_init(&driver->diag_cntl_mutex);
mutex_init(&driver->mode_lock);
diff --git a/drivers/char/diag/diagfwd_cntl.c b/drivers/char/diag/diagfwd_cntl.c
index ae749725f6db..82a67f1f6f47 100644
--- a/drivers/char/diag/diagfwd_cntl.c
+++ b/drivers/char/diag/diagfwd_cntl.c
@@ -110,6 +110,8 @@ void diag_notify_md_client(uint8_t peripheral, int data)
{
int stat = 0;
struct siginfo info;
+ struct pid *pid_struct;
+ struct task_struct *result;
if (peripheral > NUM_PERIPHERALS)
return;
@@ -122,20 +124,38 @@ void diag_notify_md_client(uint8_t peripheral, int data)
info.si_code = SI_QUEUE;
info.si_int = (PERIPHERAL_MASK(peripheral) | data);
info.si_signo = SIGCONT;
- if (driver->md_session_map[peripheral] &&
- driver->md_session_map[peripheral]->task) {
- if (driver->md_session_map[peripheral]->
- md_client_thread_info->task != NULL
- && driver->md_session_map[peripheral]->pid ==
- driver->md_session_map[peripheral]->task->tgid) {
+
+ if (!driver->md_session_map[peripheral] ||
+ driver->md_session_map[peripheral]->pid <= 0) {
+ pr_err("diag: md_session_map[%d] is invalid\n", peripheral);
+ mutex_unlock(&driver->md_session_lock);
+ return;
+ }
+
+ pid_struct = find_get_pid(
+ driver->md_session_map[peripheral]->pid);
+ DIAG_LOG(DIAG_DEBUG_PERIPHERALS,
+ "md_session_map[%d] pid = %d task = %pK\n",
+ peripheral,
+ driver->md_session_map[peripheral]->pid,
+ driver->md_session_map[peripheral]->task);
+
+ if (pid_struct) {
+ result = get_pid_task(pid_struct, PIDTYPE_PID);
+
+ if (!result) {
DIAG_LOG(DIAG_DEBUG_PERIPHERALS,
- "md_session %d pid = %d, md_session %d task tgid = %d\n",
- peripheral,
- driver->md_session_map[peripheral]->pid,
+ "diag: md_session_map[%d] with pid = %d Exited..\n",
peripheral,
- driver->md_session_map[peripheral]->task->tgid);
- stat = send_sig_info(info.si_signo, &info,
- driver->md_session_map[peripheral]->task);
+ driver->md_session_map[peripheral]->pid);
+ mutex_unlock(&driver->md_session_lock);
+ return;
+ }
+
+ if (driver->md_session_map[peripheral] &&
+ driver->md_session_map[peripheral]->task == result) {
+ stat = send_sig_info(info.si_signo,
+ &info, result);
if (stat)
pr_err("diag: Err sending signal to memory device client, signal data: 0x%x, stat: %d\n",
info.si_int, stat);
diff --git a/drivers/char/diag/diagfwd_glink.c b/drivers/char/diag/diagfwd_glink.c
index 37f3bd2626c8..2784cf71cc2b 100644
--- a/drivers/char/diag/diagfwd_glink.c
+++ b/drivers/char/diag/diagfwd_glink.c
@@ -468,7 +468,7 @@ static void diag_glink_connect_work_fn(struct work_struct *work)
struct diag_glink_info *glink_info = container_of(work,
struct diag_glink_info,
connect_work);
- if (!glink_info || glink_info->hdl)
+ if (!glink_info || !glink_info->hdl)
return;
atomic_set(&glink_info->opened, 1);
diagfwd_channel_open(glink_info->fwd_ctxt);
@@ -480,7 +480,7 @@ static void diag_glink_remote_disconnect_work_fn(struct work_struct *work)
struct diag_glink_info *glink_info = container_of(work,
struct diag_glink_info,
remote_disconnect_work);
- if (!glink_info || glink_info->hdl)
+ if (!glink_info || !glink_info->hdl)
return;
atomic_set(&glink_info->opened, 0);
diagfwd_channel_close(glink_info->fwd_ctxt);
diff --git a/drivers/char/diag/diagfwd_peripheral.c b/drivers/char/diag/diagfwd_peripheral.c
index 55d36abe4679..aaa587975469 100644
--- a/drivers/char/diag/diagfwd_peripheral.c
+++ b/drivers/char/diag/diagfwd_peripheral.c
@@ -351,7 +351,8 @@ static void diagfwd_data_read_untag_done(struct diagfwd_info *fwd_info,
}
if (driver->feature[fwd_info->peripheral].encode_hdlc &&
- driver->feature[fwd_info->peripheral].untag_header) {
+ driver->feature[fwd_info->peripheral].untag_header &&
+ driver->peripheral_untag[fwd_info->peripheral]) {
mutex_lock(&driver->diagfwd_untag_mutex);
temp_buf_cpd = buf;
temp_buf_main = buf;
@@ -990,10 +991,20 @@ static void __diag_fwd_open(struct diagfwd_info *fwd_info)
if (!fwd_info->inited)
return;
- if (fwd_info->buf_1)
- atomic_set(&fwd_info->buf_1->in_busy, 0);
- if (fwd_info->buf_2)
- atomic_set(&fwd_info->buf_2->in_busy, 0);
+ /*
+ * Logging mode here is reflecting previous mode
+ * status and will be updated to new mode later.
+ *
+ * Keeping the buffers busy for Memory Device Mode.
+ */
+
+ if ((driver->logging_mode != DIAG_USB_MODE) ||
+ driver->usb_connected) {
+ if (fwd_info->buf_1)
+ atomic_set(&fwd_info->buf_1->in_busy, 0);
+ if (fwd_info->buf_2)
+ atomic_set(&fwd_info->buf_2->in_busy, 0);
+ }
if (fwd_info->p_ops && fwd_info->p_ops->open)
fwd_info->p_ops->open(fwd_info->ctxt);
@@ -1155,11 +1166,13 @@ void diagfwd_write_done(uint8_t peripheral, uint8_t type, int ctxt)
return;
fwd_info = &peripheral_info[type][peripheral];
- if (ctxt == 1 && fwd_info->buf_1)
+ if (ctxt == 1 && fwd_info->buf_1) {
atomic_set(&fwd_info->buf_1->in_busy, 0);
- else if (ctxt == 2 && fwd_info->buf_2)
+ driver->cpd_len_1 = 0;
+ } else if (ctxt == 2 && fwd_info->buf_2) {
atomic_set(&fwd_info->buf_2->in_busy, 0);
- else if (ctxt == 3 && fwd_info->buf_upd_1_a) {
+ driver->cpd_len_2 = 0;
+ } else if (ctxt == 3 && fwd_info->buf_upd_1_a) {
atomic_set(&fwd_info->buf_upd_1_a->in_busy, 0);
if (driver->cpd_len_1 == 0)
atomic_set(&fwd_info->buf_1->in_busy, 0);
@@ -1299,7 +1312,7 @@ static void diagfwd_queue_read(struct diagfwd_info *fwd_info)
void diagfwd_buffers_init(struct diagfwd_info *fwd_info)
{
- unsigned char *temp_buf;
+ unsigned char *temp_buf = NULL;
if (!fwd_info)
return;
@@ -1311,18 +1324,20 @@ void diagfwd_buffers_init(struct diagfwd_info *fwd_info)
}
mutex_lock(&fwd_info->buf_mutex);
+
if (!fwd_info->buf_1) {
fwd_info->buf_1 = kzalloc(sizeof(struct diagfwd_buf_t),
GFP_KERNEL);
- if (!fwd_info->buf_1)
+ if (ZERO_OR_NULL_PTR(fwd_info->buf_1))
goto err;
kmemleak_not_leak(fwd_info->buf_1);
}
+
if (!fwd_info->buf_1->data) {
fwd_info->buf_1->data = kzalloc(PERIPHERAL_BUF_SZ +
APF_DIAG_PADDING,
GFP_KERNEL);
- if (!fwd_info->buf_1->data)
+ if (ZERO_OR_NULL_PTR(fwd_info->buf_1->data))
goto err;
fwd_info->buf_1->len = PERIPHERAL_BUF_SZ;
kmemleak_not_leak(fwd_info->buf_1->data);
@@ -1334,7 +1349,7 @@ void diagfwd_buffers_init(struct diagfwd_info *fwd_info)
if (!fwd_info->buf_2) {
fwd_info->buf_2 = kzalloc(sizeof(struct diagfwd_buf_t),
GFP_KERNEL);
- if (!fwd_info->buf_2)
+ if (ZERO_OR_NULL_PTR(fwd_info->buf_2))
goto err;
kmemleak_not_leak(fwd_info->buf_2);
}
@@ -1343,7 +1358,7 @@ void diagfwd_buffers_init(struct diagfwd_info *fwd_info)
fwd_info->buf_2->data = kzalloc(PERIPHERAL_BUF_SZ +
APF_DIAG_PADDING,
GFP_KERNEL);
- if (!fwd_info->buf_2->data)
+ if (ZERO_OR_NULL_PTR(fwd_info->buf_2->data))
goto err;
fwd_info->buf_2->len = PERIPHERAL_BUF_SZ;
kmemleak_not_leak(fwd_info->buf_2->data);
@@ -1352,48 +1367,53 @@ void diagfwd_buffers_init(struct diagfwd_info *fwd_info)
fwd_info->type, 2);
}
- if (driver->feature[fwd_info->peripheral].untag_header) {
+ if (driver->feature[fwd_info->peripheral].untag_header) {
if (!fwd_info->buf_upd_1_a) {
fwd_info->buf_upd_1_a =
kzalloc(sizeof(struct diagfwd_buf_t),
GFP_KERNEL);
- if (!fwd_info->buf_upd_1_a)
+ if (ZERO_OR_NULL_PTR(fwd_info->buf_upd_1_a))
goto err;
kmemleak_not_leak(fwd_info->buf_upd_1_a);
}
- if (!fwd_info->buf_upd_1_a->data) {
+ if (fwd_info->buf_upd_1_a &&
+ !fwd_info->buf_upd_1_a->data) {
fwd_info->buf_upd_1_a->data =
kzalloc(PERIPHERAL_BUF_SZ +
APF_DIAG_PADDING,
GFP_KERNEL);
- if (!fwd_info->buf_upd_1_a->data)
+ temp_buf = fwd_info->buf_upd_1_a->data;
+ if (ZERO_OR_NULL_PTR(temp_buf))
goto err;
fwd_info->buf_upd_1_a->len = PERIPHERAL_BUF_SZ;
- kmemleak_not_leak(fwd_info->buf_upd_1_a->data);
+ kmemleak_not_leak(temp_buf);
fwd_info->buf_upd_1_a->ctxt = SET_BUF_CTXT(
fwd_info->peripheral,
fwd_info->type, 3);
}
+
if (!fwd_info->buf_upd_1_b) {
- fwd_info->buf_upd_1_b =
+ fwd_info->buf_upd_1_b =
kzalloc(sizeof(struct diagfwd_buf_t),
GFP_KERNEL);
- if (!fwd_info->buf_upd_1_b)
- goto err;
- kmemleak_not_leak(fwd_info->buf_upd_1_b);
+ if (ZERO_OR_NULL_PTR(fwd_info->buf_upd_1_b))
+ goto err;
+ kmemleak_not_leak(fwd_info->buf_upd_1_b);
}
- if (!fwd_info->buf_upd_1_b->data) {
+ if (fwd_info->buf_upd_1_b &&
+ !fwd_info->buf_upd_1_b->data) {
fwd_info->buf_upd_1_b->data =
kzalloc(PERIPHERAL_BUF_SZ +
APF_DIAG_PADDING,
GFP_KERNEL);
- if (!fwd_info->buf_upd_1_b->data)
+ temp_buf = fwd_info->buf_upd_1_b->data;
+ if (ZERO_OR_NULL_PTR(temp_buf))
goto err;
fwd_info->buf_upd_1_b->len =
PERIPHERAL_BUF_SZ;
- kmemleak_not_leak(fwd_info->buf_upd_1_b->data);
+ kmemleak_not_leak(temp_buf);
fwd_info->buf_upd_1_b->ctxt = SET_BUF_CTXT(
fwd_info->peripheral,
fwd_info->type, 4);
@@ -1407,50 +1427,56 @@ void diagfwd_buffers_init(struct diagfwd_info *fwd_info)
kzalloc(PERIPHERAL_BUF_SZ +
APF_DIAG_PADDING,
GFP_KERNEL);
- if (!fwd_info->buf_1->data_raw)
+ temp_buf = fwd_info->buf_1->data_raw;
+ if (ZERO_OR_NULL_PTR(temp_buf))
goto err;
fwd_info->buf_1->len_raw =
PERIPHERAL_BUF_SZ;
- kmemleak_not_leak(fwd_info->buf_1->data_raw);
+ kmemleak_not_leak(temp_buf);
}
+
if (!fwd_info->buf_2->data_raw) {
fwd_info->buf_2->data_raw =
kzalloc(PERIPHERAL_BUF_SZ +
APF_DIAG_PADDING,
GFP_KERNEL);
- if (!fwd_info->buf_2->data_raw)
+ temp_buf = fwd_info->buf_2->data_raw;
+ if (ZERO_OR_NULL_PTR(temp_buf))
goto err;
fwd_info->buf_2->len_raw =
PERIPHERAL_BUF_SZ;
- kmemleak_not_leak(fwd_info->buf_2->data_raw);
+ kmemleak_not_leak(temp_buf);
}
if (driver->feature[fwd_info->peripheral].
- untag_header) {
- if (!fwd_info->buf_upd_1_a->data_raw) {
+ untag_header) {
+ if (fwd_info->buf_upd_1_a &&
+ !fwd_info->buf_upd_1_a->data_raw) {
fwd_info->buf_upd_1_a->data_raw =
kzalloc(PERIPHERAL_BUF_SZ +
APF_DIAG_PADDING,
GFP_KERNEL);
- if (!fwd_info->buf_upd_1_a->data_raw)
+ temp_buf =
+ fwd_info->buf_upd_1_a->data_raw;
+ if (ZERO_OR_NULL_PTR(temp_buf))
goto err;
fwd_info->buf_upd_1_a->len_raw =
PERIPHERAL_BUF_SZ;
- temp_buf =
- fwd_info->buf_upd_1_a->data_raw;
kmemleak_not_leak(temp_buf);
}
- if (!fwd_info->buf_upd_1_b->data_raw) {
+
+ if (fwd_info->buf_upd_1_b &&
+ !fwd_info->buf_upd_1_b->data_raw) {
fwd_info->buf_upd_1_b->data_raw =
kzalloc(PERIPHERAL_BUF_SZ +
APF_DIAG_PADDING,
GFP_KERNEL);
- if (!fwd_info->buf_upd_1_b->data_raw)
+ temp_buf =
+ fwd_info->buf_upd_1_b->data_raw;
+ if (ZERO_OR_NULL_PTR(temp_buf))
goto err;
fwd_info->buf_upd_1_b->len_raw =
PERIPHERAL_BUF_SZ;
- temp_buf =
- fwd_info->buf_upd_1_b->data_raw;
kmemleak_not_leak(temp_buf);
}
}
diff --git a/drivers/clk/qcom/clk-cpu-osm.c b/drivers/clk/qcom/clk-cpu-osm.c
index f82ddc3b008b..d3914ab5f47c 100644
--- a/drivers/clk/qcom/clk-cpu-osm.c
+++ b/drivers/clk/qcom/clk-cpu-osm.c
@@ -772,7 +772,7 @@ static const char * const gcc_parent_names_1[] = {
};
static struct freq_tbl ftbl_osm_clk_src[] = {
- F(200000000, LMH_LITE_CLK_SRC, 3, 0, 0),
+ F(200000000, LMH_LITE_CLK_SRC, 1.5, 0, 0),
{ }
};
diff --git a/drivers/clk/qcom/gcc-sdm660.c b/drivers/clk/qcom/gcc-sdm660.c
index b55310e091af..b10f9ca9fe1a 100644
--- a/drivers/clk/qcom/gcc-sdm660.c
+++ b/drivers/clk/qcom/gcc-sdm660.c
@@ -732,6 +732,7 @@ static struct clk_rcg2 gp3_clk_src = {
};
static const struct freq_tbl ftbl_hmss_gpll0_clk_src[] = {
+ F(300000000, P_GPLL0_OUT_MAIN, 2, 0, 0),
F(600000000, P_GPLL0_OUT_MAIN, 1, 0, 0),
{ }
};
@@ -2755,6 +2756,9 @@ static int gcc_660_probe(struct platform_device *pdev)
/* Keep bimc gfx clock port on all the time */
clk_prepare_enable(gcc_bimc_gfx_clk.clkr.hw.clk);
+ /* Set the HMSS_GPLL0_SRC for 300MHz to CPU subsystem */
+ clk_set_rate(hmss_gpll0_clk_src.clkr.hw.clk, 300000000);
+
dev_info(&pdev->dev, "Registered GCC clocks\n");
return ret;
diff --git a/drivers/cpuidle/lpm-levels.c b/drivers/cpuidle/lpm-levels.c
index ce67145bb142..37535a72e066 100644
--- a/drivers/cpuidle/lpm-levels.c
+++ b/drivers/cpuidle/lpm-levels.c
@@ -72,6 +72,8 @@ enum debug_event {
CLUSTER_ENTER,
CLUSTER_EXIT,
PRE_PC_CB,
+ CPU_HP_STARTING,
+ CPU_HP_DYING,
};
struct lpm_debug {
@@ -341,10 +343,16 @@ static int lpm_cpu_callback(struct notifier_block *cpu_nb,
switch (action & ~CPU_TASKS_FROZEN) {
case CPU_DYING:
+ update_debug_pc_event(CPU_HP_DYING, cpu,
+ cluster->num_children_in_sync.bits[0],
+ cluster->child_cpus.bits[0], false);
cluster_prepare(cluster, get_cpu_mask((unsigned int) cpu),
NR_LPM_LEVELS, false, 0);
break;
case CPU_STARTING:
+ update_debug_pc_event(CPU_HP_STARTING, cpu,
+ cluster->num_children_in_sync.bits[0],
+ cluster->child_cpus.bits[0], false);
cluster_unprepare(cluster, get_cpu_mask((unsigned int) cpu),
NR_LPM_LEVELS, false, 0);
break;
diff --git a/drivers/crypto/msm/qcedev.c b/drivers/crypto/msm/qcedev.c
index 7459401979fe..d04ca6f28f90 100644
--- a/drivers/crypto/msm/qcedev.c
+++ b/drivers/crypto/msm/qcedev.c
@@ -56,6 +56,7 @@ static uint8_t _std_init_vector_sha256_uint8[] = {
static DEFINE_MUTEX(send_cmd_lock);
static DEFINE_MUTEX(qcedev_sent_bw_req);
+static DEFINE_MUTEX(hash_access_lock);
static void qcedev_ce_high_bw_req(struct qcedev_control *podev,
bool high_bw_req)
@@ -1648,12 +1649,18 @@ long qcedev_ioctl(struct file *file, unsigned cmd, unsigned long arg)
(void __user *)arg,
sizeof(struct qcedev_sha_op_req)))
return -EFAULT;
- if (qcedev_check_sha_params(&qcedev_areq.sha_op_req, podev))
+ mutex_lock(&hash_access_lock);
+ if (qcedev_check_sha_params(&qcedev_areq.sha_op_req, podev)) {
+ mutex_unlock(&hash_access_lock);
return -EINVAL;
+ }
qcedev_areq.op_type = QCEDEV_CRYPTO_OPER_SHA;
err = qcedev_hash_init(&qcedev_areq, handle, &sg_src);
- if (err)
+ if (err) {
+ mutex_unlock(&hash_access_lock);
return err;
+ }
+ mutex_unlock(&hash_access_lock);
if (copy_to_user((void __user *)arg, &qcedev_areq.sha_op_req,
sizeof(struct qcedev_sha_op_req)))
return -EFAULT;
@@ -1671,32 +1678,42 @@ long qcedev_ioctl(struct file *file, unsigned cmd, unsigned long arg)
(void __user *)arg,
sizeof(struct qcedev_sha_op_req)))
return -EFAULT;
- if (qcedev_check_sha_params(&qcedev_areq.sha_op_req, podev))
+ mutex_lock(&hash_access_lock);
+ if (qcedev_check_sha_params(&qcedev_areq.sha_op_req, podev)) {
+ mutex_unlock(&hash_access_lock);
return -EINVAL;
+ }
qcedev_areq.op_type = QCEDEV_CRYPTO_OPER_SHA;
if (qcedev_areq.sha_op_req.alg == QCEDEV_ALG_AES_CMAC) {
err = qcedev_hash_cmac(&qcedev_areq, handle, &sg_src);
- if (err)
+ if (err) {
+ mutex_unlock(&hash_access_lock);
return err;
+ }
} else {
if (handle->sha_ctxt.init_done == false) {
pr_err("%s Init was not called\n", __func__);
+ mutex_unlock(&hash_access_lock);
return -EINVAL;
}
err = qcedev_hash_update(&qcedev_areq, handle, &sg_src);
- if (err)
+ if (err) {
+ 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;
}
memcpy(&qcedev_areq.sha_op_req.digest[0],
&handle->sha_ctxt.digest[0],
handle->sha_ctxt.diglen);
+ mutex_unlock(&hash_access_lock);
if (copy_to_user((void __user *)arg, &qcedev_areq.sha_op_req,
sizeof(struct qcedev_sha_op_req)))
return -EFAULT;
@@ -1713,16 +1730,22 @@ long qcedev_ioctl(struct file *file, unsigned cmd, unsigned long arg)
(void __user *)arg,
sizeof(struct qcedev_sha_op_req)))
return -EFAULT;
- if (qcedev_check_sha_params(&qcedev_areq.sha_op_req, podev))
+ mutex_lock(&hash_access_lock);
+ if (qcedev_check_sha_params(&qcedev_areq.sha_op_req, podev)) {
+ mutex_unlock(&hash_access_lock);
return -EINVAL;
+ }
qcedev_areq.op_type = QCEDEV_CRYPTO_OPER_SHA;
err = qcedev_hash_final(&qcedev_areq, handle);
- if (err)
+ if (err) {
+ mutex_unlock(&hash_access_lock);
return err;
+ }
qcedev_areq.sha_op_req.diglen = handle->sha_ctxt.diglen;
memcpy(&qcedev_areq.sha_op_req.digest[0],
&handle->sha_ctxt.digest[0],
handle->sha_ctxt.diglen);
+ mutex_unlock(&hash_access_lock);
if (copy_to_user((void __user *)arg, &qcedev_areq.sha_op_req,
sizeof(struct qcedev_sha_op_req)))
return -EFAULT;
@@ -1737,20 +1760,28 @@ long qcedev_ioctl(struct file *file, unsigned cmd, unsigned long arg)
(void __user *)arg,
sizeof(struct qcedev_sha_op_req)))
return -EFAULT;
- if (qcedev_check_sha_params(&qcedev_areq.sha_op_req, podev))
+ mutex_lock(&hash_access_lock);
+ if (qcedev_check_sha_params(&qcedev_areq.sha_op_req, podev)) {
+ mutex_unlock(&hash_access_lock);
return -EINVAL;
+ }
qcedev_areq.op_type = QCEDEV_CRYPTO_OPER_SHA;
qcedev_hash_init(&qcedev_areq, handle, &sg_src);
err = qcedev_hash_update(&qcedev_areq, handle, &sg_src);
- if (err)
+ if (err) {
+ mutex_unlock(&hash_access_lock);
return err;
+ }
err = qcedev_hash_final(&qcedev_areq, handle);
- if (err)
+ if (err) {
+ mutex_unlock(&hash_access_lock);
return err;
+ }
qcedev_areq.sha_op_req.diglen = handle->sha_ctxt.diglen;
memcpy(&qcedev_areq.sha_op_req.digest[0],
&handle->sha_ctxt.digest[0],
handle->sha_ctxt.diglen);
+ mutex_unlock(&hash_access_lock);
if (copy_to_user((void __user *)arg, &qcedev_areq.sha_op_req,
sizeof(struct qcedev_sha_op_req)))
return -EFAULT;
diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c
index cc1e16fd7e76..02a60a1df50d 100644
--- a/drivers/gpu/drm/drm_edid.c
+++ b/drivers/gpu/drm/drm_edid.c
@@ -89,6 +89,14 @@ struct detailed_mode_closure {
#define LEVEL_GTF2 2
#define LEVEL_CVT 3
+/*Enum storing luminance types for HDR blocks in EDID*/
+enum luminance_value {
+ NO_LUMINANCE_DATA = 3,
+ MAXIMUM_LUMINANCE = 4,
+ FRAME_AVERAGE_LUMINANCE = 5,
+ MINIMUM_LUMINANCE = 6
+};
+
static struct edid_quirk {
char vendor[4];
int product_id;
@@ -992,6 +1000,221 @@ static const struct drm_display_mode edid_cea_modes[] = {
2492, 2640, 0, 1080, 1084, 1094, 1125, 0,
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC),
.vrefresh = 100, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_16_9, },
+ /* 65 - 1280x720@24Hz */
+ { DRM_MODE("1280x720", DRM_MODE_TYPE_DRIVER, 59400, 1280, 3040,
+ 3080, 3300, 0, 720, 725, 730, 750, 0,
+ DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC),
+ .vrefresh = 24, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_64_27, },
+ /* 66 - 1280x720@25Hz */
+ { DRM_MODE("1280x720", DRM_MODE_TYPE_DRIVER, 74250, 1280, 3700,
+ 3740, 3960, 0, 720, 725, 730, 750, 0,
+ DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC),
+ .vrefresh = 25, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_64_27, },
+ /* 67 - 1280x720@30Hz */
+ { DRM_MODE("1280x720", DRM_MODE_TYPE_DRIVER, 74250, 1280, 3040,
+ 3080, 3300, 0, 720, 725, 730, 750, 0,
+ DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC),
+ .vrefresh = 30, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_64_27, },
+ /* 68 - 1280x720@50Hz */
+ { DRM_MODE("1280x720", DRM_MODE_TYPE_DRIVER, 74250, 1280, 1720,
+ 1760, 1980, 0, 720, 725, 730, 750, 0,
+ DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC),
+ .vrefresh = 50, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_64_27, },
+ /* 69 - 1280x720@60Hz */
+ { DRM_MODE("1280x720", DRM_MODE_TYPE_DRIVER, 74250, 1280, 1390,
+ 1430, 1650, 0, 720, 725, 730, 750, 0,
+ DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC),
+ .vrefresh = 60, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_64_27, },
+ /* 70 - 1280x720@100Hz */
+ { DRM_MODE("1280x720", DRM_MODE_TYPE_DRIVER, 148500, 1280, 1720,
+ 1760, 1980, 0, 720, 725, 730, 750, 0,
+ DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC),
+ .vrefresh = 100, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_64_27, },
+ /* 71 - 1280x720@120Hz */
+ { DRM_MODE("1280x720", DRM_MODE_TYPE_DRIVER, 148500, 1280, 1390,
+ 1430, 1650, 0, 720, 725, 730, 750, 0,
+ DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC),
+ .vrefresh = 120, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_64_27, },
+ /* 72 - 1920x1080@24Hz */
+ { DRM_MODE("1920x1080", DRM_MODE_TYPE_DRIVER, 74250, 1920, 2558,
+ 2602, 2750, 0, 1080, 1084, 1089, 1125, 0,
+ DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC),
+ .vrefresh = 24, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_64_27, },
+ /* 73 - 1920x1080@25Hz */
+ { DRM_MODE("1920x1080", DRM_MODE_TYPE_DRIVER, 74250, 1920, 2448,
+ 2492, 2640, 0, 1080, 1084, 1089, 1125, 0,
+ DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC),
+ .vrefresh = 25, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_64_27, },
+ /* 74 - 1920x1080@30Hz */
+ { DRM_MODE("1920x1080", DRM_MODE_TYPE_DRIVER, 74250, 1920, 2008,
+ 2052, 2200, 0, 1080, 1084, 1089, 1125, 0,
+ DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC),
+ .vrefresh = 30, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_64_27, },
+ /* 75 - 1920x1080@50Hz */
+ { DRM_MODE("1920x1080", DRM_MODE_TYPE_DRIVER, 148500, 1920, 2448,
+ 2492, 2640, 0, 1080, 1084, 1089, 1125, 0,
+ DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC),
+ .vrefresh = 50, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_64_27, },
+ /* 76 - 1920x1080@60Hz */
+ { DRM_MODE("1920x1080", DRM_MODE_TYPE_DRIVER, 148500, 1920, 2008,
+ 2052, 2200, 0, 1080, 1084, 1089, 1125, 0,
+ DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC),
+ .vrefresh = 60, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_64_27, },
+ /* 77 - 1920x1080@100Hz */
+ { DRM_MODE("1920x1080", DRM_MODE_TYPE_DRIVER, 297000, 1920, 2448,
+ 2492, 2640, 0, 1080, 1084, 1094, 1125, 0,
+ DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC),
+ .vrefresh = 100, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_64_27, },
+ /* 78 - 1920x1080@120Hz */
+ { DRM_MODE("1920x1080", DRM_MODE_TYPE_DRIVER, 297000, 1920, 2008,
+ 2052, 2200, 0, 1080, 1084, 1089, 1125, 0,
+ DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC),
+ .vrefresh = 120, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_64_27, },
+ /* 79 - 1680x720@24Hz */
+ { DRM_MODE("1680x720", DRM_MODE_TYPE_DRIVER, 59400, 1680, 3040,
+ 3080, 3300, 0, 720, 725, 730, 750, 0,
+ DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC),
+ .vrefresh = 24, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_64_27, },
+ /* 80 - 1680x720@25Hz */
+ { DRM_MODE("1680x720", DRM_MODE_TYPE_DRIVER, 59400, 1680, 2908,
+ 2948, 3168, 0, 720, 725, 730, 750, 0,
+ DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC),
+ .vrefresh = 25, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_64_27, },
+ /* 81 - 1680x720@30Hz */
+ { DRM_MODE("1680x720", DRM_MODE_TYPE_DRIVER, 59400, 1680, 2380,
+ 2420, 2640, 0, 720, 725, 730, 750, 0,
+ DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC),
+ .vrefresh = 30, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_64_27, },
+ /* 82 - 1680x720@50Hz */
+ { DRM_MODE("1680x720", DRM_MODE_TYPE_DRIVER, 82500, 1680, 1940,
+ 1980, 2200, 0, 720, 725, 730, 750, 0,
+ DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC),
+ .vrefresh = 50, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_64_27, },
+ /* 83 - 1680x720@60Hz */
+ { DRM_MODE("1680x720", DRM_MODE_TYPE_DRIVER, 99000, 1680, 1940,
+ 1980, 2200, 0, 720, 725, 730, 750, 0,
+ DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC),
+ .vrefresh = 60, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_64_27, },
+ /* 84 - 1680x720@100Hz */
+ { DRM_MODE("1680x720", DRM_MODE_TYPE_DRIVER, 165000, 1680, 1740,
+ 1780, 2000, 0, 720, 725, 730, 825, 0,
+ DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC),
+ .vrefresh = 100, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_64_27, },
+ /* 85 - 1680x720@120Hz */
+ { DRM_MODE("1680x720", DRM_MODE_TYPE_DRIVER, 198000, 1680, 1740,
+ 1780, 2000, 0, 720, 725, 730, 825, 0,
+ DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC),
+ .vrefresh = 120, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_64_27, },
+ /* 86 - 2560x1080@24Hz */
+ { DRM_MODE("2560x1080", DRM_MODE_TYPE_DRIVER, 99000, 2560, 3558,
+ 3602, 3750, 0, 1080, 1084, 1089, 1100, 0,
+ DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC),
+ .vrefresh = 24, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_64_27, },
+ /* 87 - 2560x1080@25Hz */
+ { DRM_MODE("2560x1080", DRM_MODE_TYPE_DRIVER, 90000, 2560, 3008,
+ 3052, 3200, 0, 1080, 1084, 1089, 1125, 0,
+ DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC),
+ .vrefresh = 25, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_64_27, },
+ /* 88 - 2560x1080@30Hz */
+ { DRM_MODE("2560x1080", DRM_MODE_TYPE_DRIVER, 118800, 2560, 3328,
+ 3372, 3520, 0, 1080, 1084, 1089, 1125, 0,
+ DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC),
+ .vrefresh = 30, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_64_27, },
+ /* 89 - 2560x1080@50Hz */
+ { DRM_MODE("2560x1080", DRM_MODE_TYPE_DRIVER, 185625, 2560, 3108,
+ 3152, 3300, 0, 1080, 1084, 1089, 1125, 0,
+ DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC),
+ .vrefresh = 50, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_64_27, },
+ /* 90 - 2560x1080@60Hz */
+ { DRM_MODE("2560x1080", DRM_MODE_TYPE_DRIVER, 198000, 2560, 2808,
+ 2852, 3000, 0, 1080, 1084, 1089, 1100, 0,
+ DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC),
+ .vrefresh = 60, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_64_27, },
+ /* 91 - 2560x1080@100Hz */
+ { DRM_MODE("2560x1080", DRM_MODE_TYPE_DRIVER, 371250, 2560, 2778,
+ 2822, 2970, 0, 1080, 1084, 1089, 1250, 0,
+ DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC),
+ .vrefresh = 100, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_64_27, },
+ /* 92 - 2560x1080@120Hz */
+ { DRM_MODE("2560x1080", DRM_MODE_TYPE_DRIVER, 495000, 2560, 3108,
+ 3152, 3300, 0, 1080, 1084, 1089, 1250, 0,
+ DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC),
+ .vrefresh = 120, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_64_27, },
+ /* 93 - 3840x2160p@24Hz 16:9 */
+ { DRM_MODE("3840x2160", DRM_MODE_TYPE_DRIVER, 297000, 3840, 5116,
+ 5204, 5500, 0, 2160, 2168, 2178, 2250, 0,
+ DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC),
+ .vrefresh = 24, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_16_9,},
+ /* 94 - 3840x2160p@25Hz 16:9 */
+ { DRM_MODE("3840x2160", DRM_MODE_TYPE_DRIVER, 297000, 3840, 4896,
+ 4984, 5280, 0, 2160, 2168, 2178, 2250, 0,
+ DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC),
+ .vrefresh = 25, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_16_9},
+ /* 95 - 3840x2160p@30Hz 16:9 */
+ { DRM_MODE("3840x2160", DRM_MODE_TYPE_DRIVER, 297000, 3840, 4016,
+ 4104, 4400, 0, 2160, 2168, 2178, 2250, 0,
+ DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC),
+ .vrefresh = 30, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_16_9},
+ /* 96 - 3840x2160p@50Hz 16:9 */
+ { DRM_MODE("3840x2160", DRM_MODE_TYPE_DRIVER, 594000, 3840, 4896,
+ 4984, 5280, 0, 2160, 2168, 2178, 2250, 0,
+ DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC),
+ .vrefresh = 50, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_16_9},
+ /* 97 - 3840x2160p@60Hz 16:9 */
+ { DRM_MODE("3840x2160", DRM_MODE_TYPE_DRIVER, 594000, 3840, 4016,
+ 4104, 4400, 0, 2160, 2168, 2178, 2250, 0,
+ DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC),
+ .vrefresh = 60, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_16_9},
+ /* 98 - 4096x2160p@24Hz 256:135 */
+ { DRM_MODE("4096x2160", DRM_MODE_TYPE_DRIVER, 297000, 4096, 5116,
+ 5204, 5500, 0, 2160, 2168, 2178, 2250, 0,
+ DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC),
+ .vrefresh = 24, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_256_135},
+ /* 99 - 4096x2160p@25Hz 256:135 */
+ { DRM_MODE("4096x2160", DRM_MODE_TYPE_DRIVER, 297000, 4096, 5064,
+ 5152, 5280, 0, 2160, 2168, 2178, 2250, 0,
+ DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC),
+ .vrefresh = 25, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_256_135},
+ /* 100 - 4096x2160p@30Hz 256:135 */
+ { DRM_MODE("4096x2160", DRM_MODE_TYPE_DRIVER, 297000, 4096, 4184,
+ 4272, 4400, 0, 2160, 2168, 2178, 2250, 0,
+ DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC),
+ .vrefresh = 30, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_256_135},
+ /* 101 - 4096x2160p@50Hz 256:135 */
+ { DRM_MODE("4096x2160", DRM_MODE_TYPE_DRIVER, 594000, 4096, 5064,
+ 5152, 5280, 0, 2160, 2168, 2178, 2250, 0,
+ DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC),
+ .vrefresh = 50, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_256_135},
+ /* 102 - 4096x2160p@60Hz 256:135 */
+ { DRM_MODE("4096x2160", DRM_MODE_TYPE_DRIVER, 594000, 4096, 4184,
+ 4272, 4400, 0, 2160, 2168, 2178, 2250, 0,
+ DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC),
+ .vrefresh = 60, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_256_135},
+ /* 103 - 3840x2160p@24Hz 64:27 */
+ { DRM_MODE("3840x2160", DRM_MODE_TYPE_DRIVER, 297000, 3840, 5116,
+ 5204, 5500, 0, 2160, 2168, 2178, 2250, 0,
+ DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC),
+ .vrefresh = 24, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_64_27},
+ /* 104 - 3840x2160p@25Hz 64:27 */
+ { DRM_MODE("3840x2160", DRM_MODE_TYPE_DRIVER, 297000, 3840, 4016,
+ 4104, 4400, 0, 2160, 2168, 2178, 2250, 0,
+ DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC),
+ .vrefresh = 25, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_64_27},
+ /* 105 - 3840x2160p@30Hz 64:27 */
+ { DRM_MODE("3840x2160", DRM_MODE_TYPE_DRIVER, 297000, 3840, 4016,
+ 4104, 4400, 0, 2160, 2168, 2178, 2250, 0,
+ DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC),
+ .vrefresh = 30, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_64_27},
+ /* 106 - 3840x2160p@50Hz 64:27 */
+ { DRM_MODE("3840x2160", DRM_MODE_TYPE_DRIVER, 594000, 3840, 4896,
+ 4984, 5280, 0, 2160, 2168, 2178, 2250, 0,
+ DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC),
+ .vrefresh = 50, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_64_27},
+ /* 107 - 3840x2160p@60Hz 64:27 */
+ { DRM_MODE("3840x2160", DRM_MODE_TYPE_DRIVER, 594000, 3840, 4016,
+ 4104, 4400, 0, 2160, 2168, 2178, 2250, 0,
+ DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC),
+ .vrefresh = 60, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_64_27},
};
/*
@@ -2482,12 +2705,15 @@ add_detailed_modes(struct drm_connector *connector, struct edid *edid,
return closure.modes;
}
-
+#define VIDEO_CAPABILITY_EXTENDED_DATA_BLOCK 0x0
#define AUDIO_BLOCK 0x01
#define VIDEO_BLOCK 0x02
#define VENDOR_BLOCK 0x03
#define SPEAKER_BLOCK 0x04
+#define HDR_STATIC_METADATA_EXTENDED_DATA_BLOCK 0x06
+#define EXTENDED_TAG 0x07
#define VIDEO_CAPABILITY_BLOCK 0x07
+#define Y420_VIDEO_DATA_BLOCK 0x0E
#define EDID_BASIC_AUDIO (1 << 6)
#define EDID_CEA_YCRCB444 (1 << 5)
#define EDID_CEA_YCRCB422 (1 << 4)
@@ -3076,6 +3302,21 @@ static bool cea_db_is_hdmi_vsdb(const u8 *db)
return hdmi_id == HDMI_IEEE_OUI;
}
+static bool cea_db_is_hdmi_hf_vsdb(const u8 *db)
+{
+ int hdmi_id;
+
+ if (cea_db_tag(db) != VENDOR_BLOCK)
+ return false;
+
+ if (cea_db_payload_len(db) < 7)
+ return false;
+
+ hdmi_id = db[1] | (db[2] << 8) | (db[3] << 16);
+
+ return hdmi_id == HDMI_IEEE_OUI_HF;
+}
+
#define for_each_cea_db(cea, i, start, end) \
for ((i) = (start); (i) < (end) && (i) + cea_db_payload_len(&(cea)[(i)]) < (end); (i) += cea_db_payload_len(&(cea)[(i)]) + 1)
@@ -3199,6 +3440,258 @@ parse_hdmi_vsdb(struct drm_connector *connector, const u8 *db)
}
static void
+parse_hdmi_hf_vsdb(struct drm_connector *connector, const u8 *db)
+{
+ u8 len = cea_db_payload_len(db);
+
+ if (len < 7)
+ return;
+
+ if (db[4] != 1)
+ return; /* invalid version */
+
+ connector->max_tmds_char = db[5] * 5;
+ connector->scdc_present = db[6] & (1 << 7);
+ connector->rr_capable = db[6] & (1 << 6);
+ connector->flags_3d = db[6] & 0x7;
+ connector->supports_scramble = connector->scdc_present &&
+ (db[6] & (1 << 3));
+
+ DRM_DEBUG_KMS("HDMI v2: max TMDS char %d, "
+ "scdc %s, "
+ "rr %s, "
+ "3D flags 0x%x, "
+ "scramble %s\n",
+ connector->max_tmds_char,
+ connector->scdc_present ? "available" : "not available",
+ connector->rr_capable ? "capable" : "not capable",
+ connector->flags_3d,
+ connector->supports_scramble ?
+ "supported" : "not supported");
+}
+
+static void
+drm_hdmi_extract_vsdbs_info(struct drm_connector *connector, struct edid *edid)
+{
+ const u8 *cea = drm_find_cea_extension(edid);
+ const u8 *db = NULL;
+
+ if (cea && cea_revision(cea) >= 3) {
+ int i, start, end;
+
+ if (cea_db_offsets(cea, &start, &end))
+ return;
+
+ for_each_cea_db(cea, i, start, end) {
+ db = &cea[i];
+
+ if (cea_db_tag(db) == VENDOR_BLOCK) {
+ /* HDMI Vendor-Specific Data Block */
+ if (cea_db_is_hdmi_vsdb(db))
+ parse_hdmi_vsdb(connector, db);
+ /* HDMI Forum Vendor-Specific Data Block */
+ else if (cea_db_is_hdmi_hf_vsdb(db))
+ parse_hdmi_hf_vsdb(connector, db);
+ }
+ }
+ }
+}
+
+/*
+ * drm_extract_vcdb_info - Parse the HDMI Video Capability Data Block
+ * @connector: connector corresponding to the HDMI sink
+ * @db: start of the CEA vendor specific block
+ *
+ * Parses the HDMI VCDB to extract sink info for @connector.
+ */
+static void
+drm_extract_vcdb_info(struct drm_connector *connector, const u8 *db)
+{
+ /*
+ * Check if the sink specifies underscan
+ * support for:
+ * BIT 5: preferred video format
+ * BIT 3: IT video format
+ * BIT 1: CE video format
+ */
+
+ connector->pt_scan_info =
+ (db[2] & (BIT(4) | BIT(5))) >> 4;
+ connector->it_scan_info =
+ (db[2] & (BIT(3) | BIT(2))) >> 2;
+ connector->ce_scan_info =
+ db[2] & (BIT(1) | BIT(0));
+
+ DRM_DEBUG_KMS("Scan Info (pt|it|ce): (%d|%d|%d)",
+ (int) connector->pt_scan_info,
+ (int) connector->it_scan_info,
+ (int) connector->ce_scan_info);
+}
+
+static bool drm_edid_is_luminance_value_present(
+u32 block_length, enum luminance_value value)
+{
+ return block_length > NO_LUMINANCE_DATA && value <= block_length;
+}
+
+/*
+ * drm_extract_hdr_db - Parse the HDMI HDR extended block
+ * @connector: connector corresponding to the HDMI sink
+ * @db: start of the HDMI HDR extended block
+ *
+ * Parses the HDMI HDR extended block to extract sink info for @connector.
+ */
+static void
+drm_extract_hdr_db(struct drm_connector *connector, const u8 *db)
+{
+
+ u8 len = 0;
+
+ if (!db) {
+ DRM_ERROR("invalid db\n");
+ return;
+ }
+
+ len = db[0] & 0x1f;
+ /* Byte 3: Electro-Optical Transfer Functions */
+ connector->hdr_eotf = db[2] & 0x3F;
+
+ /* Byte 4: Static Metadata Descriptor Type 1 */
+ connector->hdr_metadata_type_one = (db[3] & BIT(0));
+
+ /* Byte 5: Desired Content Maximum Luminance */
+ if (drm_edid_is_luminance_value_present(len, MAXIMUM_LUMINANCE))
+ connector->hdr_max_luminance =
+ db[MAXIMUM_LUMINANCE];
+
+ /* Byte 6: Desired Content Max Frame-average Luminance */
+ if (drm_edid_is_luminance_value_present(len, FRAME_AVERAGE_LUMINANCE))
+ connector->hdr_avg_luminance =
+ db[FRAME_AVERAGE_LUMINANCE];
+
+ /* Byte 7: Desired Content Min Luminance */
+ if (drm_edid_is_luminance_value_present(len, MINIMUM_LUMINANCE))
+ connector->hdr_min_luminance =
+ db[MINIMUM_LUMINANCE];
+
+ connector->hdr_supported = true;
+
+ DRM_DEBUG_KMS("HDR electro-optical %d\n", connector->hdr_eotf);
+ DRM_DEBUG_KMS("metadata desc 1 %d\n", connector->hdr_metadata_type_one);
+ DRM_DEBUG_KMS("max luminance %d\n", connector->hdr_max_luminance);
+ DRM_DEBUG_KMS("avg luminance %d\n", connector->hdr_avg_luminance);
+ DRM_DEBUG_KMS("min luminance %d\n", connector->hdr_min_luminance);
+}
+
+/*
+ * drm_hdmi_extract_extended_blk_info - Parse the HDMI extended tag blocks
+ * @connector: connector corresponding to the HDMI sink
+ * @edid: handle to the EDID structure
+ * Parses the all extended tag blocks extract sink info for @connector.
+ */
+static void
+drm_hdmi_extract_extended_blk_info(struct drm_connector *connector,
+struct edid *edid)
+{
+ const u8 *cea = drm_find_cea_extension(edid);
+ const u8 *db = NULL;
+
+ if (cea && cea_revision(cea) >= 3) {
+ int i, start, end;
+
+ if (cea_db_offsets(cea, &start, &end))
+ return;
+
+ for_each_cea_db(cea, i, start, end) {
+ db = &cea[i];
+
+ if (cea_db_tag(db) == EXTENDED_TAG) {
+ DRM_DEBUG_KMS("found extended tag block = %d\n",
+ db[1]);
+ switch (db[1]) {
+ case VIDEO_CAPABILITY_EXTENDED_DATA_BLOCK:
+ drm_extract_vcdb_info(connector, db);
+ break;
+ case HDR_STATIC_METADATA_EXTENDED_DATA_BLOCK:
+ drm_extract_hdr_db(connector, db);
+ break;
+ default:
+ break;
+ }
+ }
+ }
+ }
+}
+
+static u8 *
+drm_edid_find_extended_tag_block(struct edid *edid, int blk_id)
+{
+ u8 *db = NULL;
+ u8 *cea = NULL;
+
+ if (!edid) {
+ pr_err("%s: invalid input\n", __func__);
+ return NULL;
+ }
+
+ cea = drm_find_cea_extension(edid);
+
+ if (cea && cea_revision(cea) >= 3) {
+ int i, start, end;
+
+ if (cea_db_offsets(cea, &start, &end))
+ return NULL;
+
+ for_each_cea_db(cea, i, start, end) {
+ db = &cea[i];
+ if ((cea_db_tag(db) == EXTENDED_TAG) &&
+ (db[1] == blk_id))
+ return db;
+ }
+ }
+ return NULL;
+}
+
+/*
+ * add_YCbCr420VDB_modes - add the modes found in Ycbcr420 VDB block
+ * @connector: connector corresponding to the HDMI sink
+ * @edid: handle to the EDID structure
+ * Parses the YCbCr420 VDB block and adds the modes to @connector.
+ */
+static int
+add_YCbCr420VDB_modes(struct drm_connector *connector, struct edid *edid)
+{
+
+ const u8 *db = NULL;
+ u32 i = 0;
+ u32 modes = 0;
+ u32 video_format = 0;
+ u8 len = 0;
+
+ /*Find the YCbCr420 VDB*/
+ db = drm_edid_find_extended_tag_block(edid, Y420_VIDEO_DATA_BLOCK);
+ /* Offset to byte 3 */
+ if (db) {
+ len = db[0] & 0x1F;
+ db += 2;
+ for (i = 0; i < len - 1; i++) {
+ struct drm_display_mode *mode;
+
+ video_format = *(db + i) & 0x7F;
+ mode = drm_display_mode_from_vic_index(connector,
+ db, len-1, i);
+ if (mode) {
+ DRM_DEBUG_KMS("Adding mode for vic = %d\n",
+ video_format);
+ drm_mode_probed_add(connector, mode);
+ modes++;
+ }
+ }
+ }
+ return modes;
+}
+
+static void
monitor_name(struct detailed_timing *t, void *data)
{
if (t->data.other_data.type == EDID_DETAIL_MONITOR_NAME)
@@ -3277,6 +3770,9 @@ void drm_edid_to_eld(struct drm_connector *connector, struct edid *edid)
/* HDMI Vendor-Specific Data Block */
if (cea_db_is_hdmi_vsdb(db))
parse_hdmi_vsdb(connector, db);
+ /* HDMI Forum Vendor-Specific Data Block */
+ else if (cea_db_is_hdmi_hf_vsdb(db))
+ parse_hdmi_hf_vsdb(connector, db);
break;
default:
break;
@@ -3733,6 +4229,10 @@ static void drm_add_display_info(struct edid *edid,
info->color_formats |= DRM_COLOR_FORMAT_YCRCB422;
}
+ /* Extract audio and video latency fields for the sink */
+ drm_hdmi_extract_vsdbs_info(connector, edid);
+ /* Extract info from extended tag blocks */
+ drm_hdmi_extract_extended_blk_info(connector, edid);
/* HDMI deep color modes supported? Assign to info, if so */
drm_assign_hdmi_deep_color_info(edid, info, connector);
@@ -3775,6 +4275,148 @@ static void drm_add_display_info(struct edid *edid,
info->color_formats |= DRM_COLOR_FORMAT_YCRCB422;
}
+static int validate_displayid(u8 *displayid, int length, int idx)
+{
+ int i;
+ u8 csum = 0;
+ struct displayid_hdr *base;
+
+ base = (struct displayid_hdr *)&displayid[idx];
+
+ DRM_DEBUG_KMS("base revision 0x%x, length %d, %d %d\n",
+ base->rev, base->bytes, base->prod_id, base->ext_count);
+
+ if (base->bytes + 5 > length - idx)
+ return -EINVAL;
+ for (i = idx; i <= base->bytes + 5; i++)
+ csum += displayid[i];
+
+ if (csum) {
+ DRM_ERROR("DisplayID checksum invalid, remainder is %d\n",
+ csum);
+ return -EINVAL;
+ }
+ return 0;
+}
+
+static struct drm_display_mode *
+drm_mode_displayid_detailed(struct drm_device *dev,
+struct displayid_detailed_timings_1 *timings)
+{
+ struct drm_display_mode *mode;
+ unsigned pixel_clock = (timings->pixel_clock[0] |
+ (timings->pixel_clock[1] << 8) |
+ (timings->pixel_clock[2] << 16));
+ unsigned hactive = (timings->hactive[0] | timings->hactive[1] << 8) + 1;
+ unsigned hblank =
+ (timings->hblank[0] |
+ timings->hblank[1] << 8) + 1;
+ unsigned hsync = (timings->hsync[0] |
+ (timings->hsync[1] & 0x7f) << 8) + 1;
+ unsigned hsync_width = (timings->hsw[0] | timings->hsw[1] << 8) + 1;
+ unsigned vactive = (timings->vactive[0] | timings->vactive[1] << 8) + 1;
+ unsigned vblank =
+ (timings->vblank[0] |
+ timings->vblank[1] << 8) + 1;
+ unsigned vsync =
+ (timings->vsync[0] |
+ (timings->vsync[1] & 0x7f) << 8) + 1;
+ unsigned vsync_width = (timings->vsw[0] | timings->vsw[1] << 8) + 1;
+ bool hsync_positive = (timings->hsync[1] >> 7) & 0x1;
+ bool vsync_positive = (timings->vsync[1] >> 7) & 0x1;
+
+ mode = drm_mode_create(dev);
+ if (!mode)
+ return NULL;
+
+ mode->clock = pixel_clock * 10;
+ mode->hdisplay = hactive;
+ mode->hsync_start = mode->hdisplay + hsync;
+ mode->hsync_end = mode->hsync_start + hsync_width;
+ mode->htotal = mode->hdisplay + hblank;
+
+ mode->vdisplay = vactive;
+ mode->vsync_start = mode->vdisplay + vsync;
+ mode->vsync_end = mode->vsync_start + vsync_width;
+ mode->vtotal = mode->vdisplay + vblank;
+
+ mode->flags = 0;
+ mode->flags |= hsync_positive ?
+ DRM_MODE_FLAG_PHSYNC : DRM_MODE_FLAG_NHSYNC;
+ mode->flags |= vsync_positive ?
+ DRM_MODE_FLAG_PVSYNC : DRM_MODE_FLAG_NVSYNC;
+ mode->type = DRM_MODE_TYPE_DRIVER;
+
+ if (timings->flags & 0x80)
+ mode->type |= DRM_MODE_TYPE_PREFERRED;
+ mode->vrefresh = drm_mode_vrefresh(mode);
+ drm_mode_set_name(mode);
+
+ return mode;
+}
+
+static int add_displayid_detailed_1_modes(struct drm_connector *connector,
+ struct displayid_block *block)
+{
+ struct displayid_detailed_timing_block *det =
+ (struct displayid_detailed_timing_block *)block;
+ int i;
+ int num_timings;
+ struct drm_display_mode *newmode;
+ int num_modes = 0;
+ /* blocks must be multiple of 20 bytes length */
+ if (block->num_bytes % 20)
+ return 0;
+
+ num_timings = block->num_bytes / 20;
+ for (i = 0; i < num_timings; i++) {
+ struct displayid_detailed_timings_1 *timings = &det->timings[i];
+
+ newmode = drm_mode_displayid_detailed(connector->dev, timings);
+ if (!newmode)
+ continue;
+
+ drm_mode_probed_add(connector, newmode);
+ num_modes++;
+ }
+ return num_modes;
+}
+
+static int add_displayid_detailed_modes(struct drm_connector *connector,
+ struct edid *edid)
+{
+ u8 *displayid;
+ int ret;
+ int idx = 1;
+ int length = EDID_LENGTH;
+ struct displayid_block *block;
+ int num_modes = 0;
+
+ displayid = drm_find_displayid_extension(edid);
+ if (!displayid)
+ return 0;
+
+ ret = validate_displayid(displayid, length, idx);
+ if (ret)
+ return 0;
+
+ idx += sizeof(struct displayid_hdr);
+ while (block = (struct displayid_block *)&displayid[idx],
+ idx + sizeof(struct displayid_block) <= length &&
+ idx + sizeof(struct displayid_block) +
+ block->num_bytes <= length &&
+ block->num_bytes > 0) {
+ idx += block->num_bytes + sizeof(struct displayid_block);
+ switch (block->tag) {
+ case DATA_BLOCK_TYPE_1_DETAILED_TIMING:
+ num_modes += add_displayid_detailed_1_modes(connector,
+ block);
+ break;
+ }
+ }
+ return num_modes;
+}
+
/**
* drm_add_edid_modes - add modes from EDID data, if available
* @connector: connector we're probing
@@ -3820,6 +4462,8 @@ int drm_add_edid_modes(struct drm_connector *connector, struct edid *edid)
num_modes += add_established_modes(connector, edid);
num_modes += add_cea_modes(connector, edid);
num_modes += add_alternate_cea_modes(connector, edid);
+ num_modes += add_displayid_detailed_modes(connector, edid);
+ num_modes += add_YCbCr420VDB_modes(connector, edid);
if (edid->features & DRM_EDID_FEATURE_DEFAULT_GTF)
num_modes += add_inferred_modes(connector, edid);
@@ -4029,96 +4673,105 @@ drm_hdmi_vendor_infoframe_from_display_mode(struct hdmi_vendor_infoframe *frame,
}
EXPORT_SYMBOL(drm_hdmi_vendor_infoframe_from_display_mode);
+static int drm_parse_tiled_block(struct drm_connector *connector,
+ struct displayid_block *block)
+{
+ struct displayid_tiled_block *tile =
+ (struct displayid_tiled_block *)block;
+ u16 w, h;
+ u8 tile_v_loc, tile_h_loc;
+ u8 num_v_tile, num_h_tile;
+ struct drm_tile_group *tg;
+
+ w = tile->tile_size[0] | tile->tile_size[1] << 8;
+ h = tile->tile_size[2] | tile->tile_size[3] << 8;
+
+ num_v_tile = (tile->topo[0] & 0xf) | (tile->topo[2] & 0x30);
+ num_h_tile = (tile->topo[0] >> 4) | ((tile->topo[2] >> 2) & 0x30);
+ tile_v_loc = (tile->topo[1] & 0xf) | ((tile->topo[2] & 0x3) << 4);
+ tile_h_loc = (tile->topo[1] >> 4) | (((tile->topo[2] >> 2) & 0x3) << 4);
+
+ connector->has_tile = true;
+ if (tile->tile_cap & 0x80)
+ connector->tile_is_single_monitor = true;
+
+ connector->num_h_tile = num_h_tile + 1;
+ connector->num_v_tile = num_v_tile + 1;
+ connector->tile_h_loc = tile_h_loc;
+ connector->tile_v_loc = tile_v_loc;
+ connector->tile_h_size = w + 1;
+ connector->tile_v_size = h + 1;
+
+ DRM_DEBUG_KMS("tile cap 0x%x\n", tile->tile_cap);
+ DRM_DEBUG_KMS("tile_size %d x %d\n", w + 1, h + 1);
+ DRM_DEBUG_KMS("topo num tiles %dx%d, location %dx%d\n",
+ num_h_tile + 1, num_v_tile + 1, tile_h_loc, tile_v_loc);
+ DRM_DEBUG_KMS("vend %c%c%c\n", tile->topology_id[0],
+ tile->topology_id[1], tile->topology_id[2]);
+
+ tg = drm_mode_get_tile_group(connector->dev, tile->topology_id);
+ if (!tg)
+ tg = drm_mode_create_tile_group(connector->dev,
+ tile->topology_id);
+
+ if (!tg)
+ return -ENOMEM;
+
+ if (connector->tile_group != tg) {
+ /* if we haven't got a pointer,
+ * take the reference, drop ref to old tile group
+ */
+ if (connector->tile_group)
+ drm_mode_put_tile_group(connector->dev,
+ connector->tile_group);
+
+ connector->tile_group = tg;
+ } else
+ /* if same tile group, then release the ref we just took. */
+ drm_mode_put_tile_group(connector->dev, tg);
+ return 0;
+}
+
static int drm_parse_display_id(struct drm_connector *connector,
u8 *displayid, int length,
bool is_edid_extension)
{
/* if this is an EDID extension the first byte will be 0x70 */
int idx = 0;
- struct displayid_hdr *base;
struct displayid_block *block;
- u8 csum = 0;
- int i;
+ int ret;
if (is_edid_extension)
idx = 1;
- base = (struct displayid_hdr *)&displayid[idx];
-
- DRM_DEBUG_KMS("base revision 0x%x, length %d, %d %d\n",
- base->rev, base->bytes, base->prod_id, base->ext_count);
-
- if (base->bytes + 5 > length - idx)
- return -EINVAL;
-
- for (i = idx; i <= base->bytes + 5; i++) {
- csum += displayid[i];
- }
- if (csum) {
- DRM_ERROR("DisplayID checksum invalid, remainder is %d\n", csum);
- return -EINVAL;
- }
+ ret = validate_displayid(displayid, length, idx);
+ if (ret)
+ return ret;
- block = (struct displayid_block *)&displayid[idx + 4];
- DRM_DEBUG_KMS("block id %d, rev %d, len %d\n",
- block->tag, block->rev, block->num_bytes);
-
- switch (block->tag) {
- case DATA_BLOCK_TILED_DISPLAY: {
- struct displayid_tiled_block *tile = (struct displayid_tiled_block *)block;
-
- u16 w, h;
- u8 tile_v_loc, tile_h_loc;
- u8 num_v_tile, num_h_tile;
- struct drm_tile_group *tg;
-
- w = tile->tile_size[0] | tile->tile_size[1] << 8;
- h = tile->tile_size[2] | tile->tile_size[3] << 8;
-
- num_v_tile = (tile->topo[0] & 0xf) | (tile->topo[2] & 0x30);
- num_h_tile = (tile->topo[0] >> 4) | ((tile->topo[2] >> 2) & 0x30);
- tile_v_loc = (tile->topo[1] & 0xf) | ((tile->topo[2] & 0x3) << 4);
- tile_h_loc = (tile->topo[1] >> 4) | (((tile->topo[2] >> 2) & 0x3) << 4);
-
- connector->has_tile = true;
- if (tile->tile_cap & 0x80)
- connector->tile_is_single_monitor = true;
-
- connector->num_h_tile = num_h_tile + 1;
- connector->num_v_tile = num_v_tile + 1;
- connector->tile_h_loc = tile_h_loc;
- connector->tile_v_loc = tile_v_loc;
- connector->tile_h_size = w + 1;
- connector->tile_v_size = h + 1;
-
- DRM_DEBUG_KMS("tile cap 0x%x\n", tile->tile_cap);
- DRM_DEBUG_KMS("tile_size %d x %d\n", w + 1, h + 1);
- DRM_DEBUG_KMS("topo num tiles %dx%d, location %dx%d\n",
- num_h_tile + 1, num_v_tile + 1, tile_h_loc, tile_v_loc);
- DRM_DEBUG_KMS("vend %c%c%c\n", tile->topology_id[0], tile->topology_id[1], tile->topology_id[2]);
-
- tg = drm_mode_get_tile_group(connector->dev, tile->topology_id);
- if (!tg) {
- tg = drm_mode_create_tile_group(connector->dev, tile->topology_id);
+ idx += sizeof(struct displayid_hdr);
+ while (block = (struct displayid_block *)&displayid[idx],
+ idx + sizeof(struct displayid_block) <= length &&
+ idx + sizeof(struct displayid_block) +
+ block->num_bytes <= length &&
+ block->num_bytes > 0) {
+ idx += block->num_bytes + sizeof(struct displayid_block);
+ DRM_DEBUG_KMS("block id 0x%x, rev %d, len %d\n",
+ block->tag, block->rev, block->num_bytes);
+
+ switch (block->tag) {
+ case DATA_BLOCK_TILED_DISPLAY:
+ ret = drm_parse_tiled_block(connector, block);
+ if (ret)
+ return ret;
+ break;
+ case DATA_BLOCK_TYPE_1_DETAILED_TIMING:
+ /* handled in mode gathering code. */
+ break;
+ default:
+ DRM_DEBUG_KMS("found DisplayID tag 0x%x, unhandled\n",
+ block->tag);
+ break;
}
- if (!tg)
- return -ENOMEM;
-
- if (connector->tile_group != tg) {
- /* if we haven't got a pointer,
- take the reference, drop ref to old tile group */
- if (connector->tile_group) {
- drm_mode_put_tile_group(connector->dev, connector->tile_group);
- }
- connector->tile_group = tg;
- } else
- /* if same tile group, then release the ref we just took. */
- drm_mode_put_tile_group(connector->dev, tg);
- }
- break;
- default:
- printk("unknown displayid tag %d\n", block->tag);
- break;
}
return 0;
}
diff --git a/drivers/gpu/drm/msm/Makefile b/drivers/gpu/drm/msm/Makefile
index ebf8be80a3d9..3d0617dbc514 100644
--- a/drivers/gpu/drm/msm/Makefile
+++ b/drivers/gpu/drm/msm/Makefile
@@ -49,6 +49,7 @@ msm_drm-y := \
sde/sde_vbif.o \
sde_dbg_evtlog.o \
sde_io_util.o \
+ sde_edid_parser.o
# use drm gpu driver only if qcom_kgsl driver not available
ifneq ($(CONFIG_QCOM_KGSL),y)
@@ -102,7 +103,6 @@ msm_drm-$(CONFIG_DRM_SDE_HDMI) += \
hdmi-staging/sde_hdmi.o \
hdmi-staging/sde_hdmi_bridge.o \
hdmi-staging/sde_hdmi_audio.o \
- hdmi-staging/sde_hdmi_edid.o
msm_drm-$(CONFIG_DRM_MSM_DSI_PLL) += dsi/pll/dsi_pll.o \
dsi/pll/dsi_pll_28nm.o
diff --git a/drivers/gpu/drm/msm/adreno/a5xx_gpu.c b/drivers/gpu/drm/msm/adreno/a5xx_gpu.c
index 02c4f2e3155d..32b2c7fab839 100644
--- a/drivers/gpu/drm/msm/adreno/a5xx_gpu.c
+++ b/drivers/gpu/drm/msm/adreno/a5xx_gpu.c
@@ -613,7 +613,7 @@ static int a5xx_hw_init(struct msm_gpu *gpu)
/* Set the GMEM VA range [0x100000:0x100000 + gpu->gmem - 1] */
gpu_write64(gpu, REG_A5XX_UCHE_GMEM_RANGE_MIN_LO,
- REG_A5XX_UCHE_GMEM_RANGE_MIN_LO, 0x00100000);
+ REG_A5XX_UCHE_GMEM_RANGE_MIN_HI, 0x00100000);
gpu_write64(gpu, REG_A5XX_UCHE_GMEM_RANGE_MAX_LO,
REG_A5XX_UCHE_GMEM_RANGE_MAX_HI,
@@ -1039,8 +1039,10 @@ static irqreturn_t a5xx_irq(struct msm_gpu *gpu)
if (status & A5XX_RBBM_INT_0_MASK_GPMU_VOLTAGE_DROOP)
a5xx_gpmu_err_irq(gpu);
- if (status & A5XX_RBBM_INT_0_MASK_CP_CACHE_FLUSH_TS)
+ if (status & A5XX_RBBM_INT_0_MASK_CP_CACHE_FLUSH_TS) {
+ a5xx_preempt_trigger(gpu);
msm_gpu_retire(gpu);
+ }
if (status & A5XX_RBBM_INT_0_MASK_CP_SW)
a5xx_preempt_irq(gpu);
diff --git a/drivers/gpu/drm/msm/hdmi-staging/sde_hdmi.c b/drivers/gpu/drm/msm/hdmi-staging/sde_hdmi.c
index 347b78886b24..6a6d02c5444d 100644
--- a/drivers/gpu/drm/msm/hdmi-staging/sde_hdmi.c
+++ b/drivers/gpu/drm/msm/hdmi-staging/sde_hdmi.c
@@ -32,6 +32,22 @@
static DEFINE_MUTEX(sde_hdmi_list_lock);
static LIST_HEAD(sde_hdmi_list);
+/* HDMI SCDC register offsets */
+#define HDMI_SCDC_UPDATE_0 0x10
+#define HDMI_SCDC_UPDATE_1 0x11
+#define HDMI_SCDC_TMDS_CONFIG 0x20
+#define HDMI_SCDC_SCRAMBLER_STATUS 0x21
+#define HDMI_SCDC_CONFIG_0 0x30
+#define HDMI_SCDC_STATUS_FLAGS_0 0x40
+#define HDMI_SCDC_STATUS_FLAGS_1 0x41
+#define HDMI_SCDC_ERR_DET_0_L 0x50
+#define HDMI_SCDC_ERR_DET_0_H 0x51
+#define HDMI_SCDC_ERR_DET_1_L 0x52
+#define HDMI_SCDC_ERR_DET_1_H 0x53
+#define HDMI_SCDC_ERR_DET_2_L 0x54
+#define HDMI_SCDC_ERR_DET_2_H 0x55
+#define HDMI_SCDC_ERR_DET_CHECKSUM 0x56
+
static const struct of_device_id sde_hdmi_dt_match[] = {
{.compatible = "qcom,hdmi-display"},
{}
@@ -69,16 +85,328 @@ static ssize_t _sde_hdmi_debugfs_dump_info_read(struct file *file,
return len;
}
+static ssize_t _sde_hdmi_debugfs_edid_modes_read(struct file *file,
+ char __user *buff,
+ size_t count,
+ loff_t *ppos)
+{
+ struct sde_hdmi *display = file->private_data;
+ char *buf;
+ u32 len = 0;
+ struct drm_connector *connector;
+ u32 mode_count = 0;
+ struct drm_display_mode *mode;
+
+ if (!display)
+ return -ENODEV;
+
+ if (!display->ctrl.ctrl ||
+ !display->ctrl.ctrl->connector) {
+ SDE_ERROR("sde_hdmi=%p or hdmi or connector is NULL\n",
+ display);
+ return -ENOMEM;
+ }
+
+ if (*ppos)
+ return 0;
+
+ connector = display->ctrl.ctrl->connector;
+
+ list_for_each_entry(mode, &connector->modes, head) {
+ mode_count++;
+ }
+
+ /* Adding one more to store title */
+ mode_count++;
+
+ buf = kzalloc((mode_count * sizeof(*mode)), GFP_KERNEL);
+ if (!buf)
+ return -ENOMEM;
+
+ len += snprintf(buf + len, PAGE_SIZE - len,
+ "name refresh (Hz) hdisp hss hse htot vdisp");
+
+ len += snprintf(buf + len, PAGE_SIZE - len,
+ " vss vse vtot flags\n");
+
+ list_for_each_entry(mode, &connector->modes, head) {
+ len += snprintf(buf + len, SZ_4K - len,
+ "%s %d %d %d %d %d %d %d %d %d 0x%x\n",
+ mode->name, mode->vrefresh, mode->hdisplay,
+ mode->hsync_start, mode->hsync_end, mode->htotal,
+ mode->vdisplay, mode->vsync_start, mode->vsync_end,
+ mode->vtotal, mode->flags);
+ }
+
+ if (copy_to_user(buff, buf, len)) {
+ kfree(buf);
+ return -EFAULT;
+ }
+
+ *ppos += len;
+
+ kfree(buf);
+ return len;
+}
+
+static ssize_t _sde_hdmi_debugfs_edid_vsdb_info_read(struct file *file,
+ char __user *buff,
+ size_t count,
+ loff_t *ppos)
+{
+ struct sde_hdmi *display = file->private_data;
+ char buf[200];
+ u32 len = 0;
+ struct drm_connector *connector;
+
+ if (!display)
+ return -ENODEV;
+
+ if (!display->ctrl.ctrl ||
+ !display->ctrl.ctrl->connector) {
+ SDE_ERROR("sde_hdmi=%p or hdmi or connector is NULL\n",
+ display);
+ return -ENOMEM;
+ }
+
+ SDE_HDMI_DEBUG("%s +", __func__);
+ if (*ppos)
+ return 0;
+
+ connector = display->ctrl.ctrl->connector;
+ len += snprintf(buf + len, sizeof(buf) - len,
+ "max_tmds_clock = %d\n",
+ connector->max_tmds_clock);
+ len += snprintf(buf + len, sizeof(buf) - len,
+ "latency_present %d %d\n",
+ connector->latency_present[0],
+ connector->latency_present[1]);
+ len += snprintf(buf + len, sizeof(buf) - len,
+ "video_latency %d %d\n",
+ connector->video_latency[0],
+ connector->video_latency[1]);
+ len += snprintf(buf + len, sizeof(buf) - len,
+ "audio_latency %d %d\n",
+ connector->audio_latency[0],
+ connector->audio_latency[1]);
+ len += snprintf(buf + len, sizeof(buf) - len,
+ "dvi_dual %d\n",
+ (int)connector->dvi_dual);
+
+ if (copy_to_user(buff, buf, len))
+ return -EFAULT;
+
+ *ppos += len;
+ SDE_HDMI_DEBUG("%s - ", __func__);
+ return len;
+}
+
+static ssize_t _sde_hdmi_debugfs_edid_hdr_info_read(struct file *file,
+ char __user *buff,
+ size_t count,
+ loff_t *ppos)
+{
+ struct sde_hdmi *display = file->private_data;
+ char buf[200];
+ u32 len = 0;
+ struct drm_connector *connector;
+
+ if (!display)
+ return -ENODEV;
+
+ if (!display->ctrl.ctrl ||
+ !display->ctrl.ctrl->connector) {
+ SDE_ERROR("sde_hdmi=%p or hdmi or connector is NULL\n",
+ display);
+ return -ENOMEM;
+ }
+
+ SDE_HDMI_DEBUG("%s +", __func__);
+ if (*ppos)
+ return 0;
+
+ connector = display->ctrl.ctrl->connector;
+ len += snprintf(buf, sizeof(buf), "hdr_eotf = %d\n"
+ "hdr_metadata_type_one %d\n"
+ "hdr_max_luminance %d\n"
+ "hdr_avg_luminance %d\n"
+ "hdr_min_luminance %d\n"
+ "hdr_supported %d\n",
+ connector->hdr_eotf,
+ connector->hdr_metadata_type_one,
+ connector->hdr_max_luminance,
+ connector->hdr_avg_luminance,
+ connector->hdr_min_luminance,
+ (int)connector->hdr_supported);
+
+ if (copy_to_user(buff, buf, len))
+ return -EFAULT;
+
+ *ppos += len;
+ SDE_HDMI_DEBUG("%s - ", __func__);
+ return len;
+}
+
+static ssize_t _sde_hdmi_debugfs_edid_hfvsdb_info_read(struct file *file,
+ char __user *buff,
+ size_t count,
+ loff_t *ppos)
+{
+ struct sde_hdmi *display = file->private_data;
+ char buf[200];
+ u32 len = 0;
+ struct drm_connector *connector;
+
+ if (!display)
+ return -ENODEV;
+
+ if (!display->ctrl.ctrl ||
+ !display->ctrl.ctrl->connector) {
+ SDE_ERROR("sde_hdmi=%p or hdmi or connector is NULL\n",
+ display);
+ return -ENOMEM;
+ }
+
+ SDE_HDMI_DEBUG("%s +", __func__);
+ if (*ppos)
+ return 0;
+
+ connector = display->ctrl.ctrl->connector;
+ len += snprintf(buf, PAGE_SIZE - len, "max_tmds_char = %d\n"
+ "scdc_present %d\n"
+ "rr_capable %d\n"
+ "supports_scramble %d\n"
+ "flags_3d %d\n",
+ connector->max_tmds_char,
+ (int)connector->scdc_present,
+ (int)connector->rr_capable,
+ (int)connector->supports_scramble,
+ connector->flags_3d);
+
+ if (copy_to_user(buff, buf, len))
+ return -EFAULT;
+
+ *ppos += len;
+ return len;
+}
+
+static ssize_t _sde_hdmi_debugfs_edid_vcdb_info_read(struct file *file,
+ char __user *buff,
+ size_t count,
+ loff_t *ppos)
+{
+ struct sde_hdmi *display = file->private_data;
+ char buf[100];
+ u32 len = 0;
+ struct drm_connector *connector;
+
+ if (!display)
+ return -ENODEV;
+
+ if (!display->ctrl.ctrl ||
+ !display->ctrl.ctrl->connector) {
+ SDE_ERROR("sde_hdmi=%p or hdmi or connector is NULL\n",
+ display);
+ return -ENOMEM;
+ }
+
+ SDE_HDMI_DEBUG("%s +", __func__);
+ if (*ppos)
+ return 0;
+
+ connector = display->ctrl.ctrl->connector;
+ len += snprintf(buf, PAGE_SIZE - len, "pt_scan_info = %d\n"
+ "it_scan_info = %d\n"
+ "ce_scan_info = %d\n",
+ (int)connector->pt_scan_info,
+ (int)connector->it_scan_info,
+ (int)connector->ce_scan_info);
+
+ if (copy_to_user(buff, buf, len))
+ return -EFAULT;
+
+ *ppos += len;
+ SDE_HDMI_DEBUG("%s - ", __func__);
+ return len;
+}
+
+static ssize_t _sde_hdmi_edid_vendor_name_read(struct file *file,
+ char __user *buff,
+ size_t count,
+ loff_t *ppos)
+{
+ struct sde_hdmi *display = file->private_data;
+ char buf[100];
+ u32 len = 0;
+ struct drm_connector *connector;
+
+ if (!display)
+ return -ENODEV;
+
+ if (!display->ctrl.ctrl ||
+ !display->ctrl.ctrl->connector) {
+ SDE_ERROR("sde_hdmi=%p or hdmi or connector is NULL\n",
+ display);
+ return -ENOMEM;
+ }
+
+ SDE_HDMI_DEBUG("%s +", __func__);
+ if (*ppos)
+ return 0;
+
+ connector = display->ctrl.ctrl->connector;
+ len += snprintf(buf, PAGE_SIZE - len, "Vendor ID is %s\n",
+ display->edid_ctrl->vendor_id);
+
+ if (copy_to_user(buff, buf, len))
+ return -EFAULT;
+
+ *ppos += len;
+ SDE_HDMI_DEBUG("%s - ", __func__);
+ return len;
+}
static const struct file_operations dump_info_fops = {
.open = simple_open,
.read = _sde_hdmi_debugfs_dump_info_read,
};
+static const struct file_operations edid_modes_fops = {
+ .open = simple_open,
+ .read = _sde_hdmi_debugfs_edid_modes_read,
+};
+
+static const struct file_operations edid_vsdb_info_fops = {
+ .open = simple_open,
+ .read = _sde_hdmi_debugfs_edid_vsdb_info_read,
+};
+
+static const struct file_operations edid_hdr_info_fops = {
+ .open = simple_open,
+ .read = _sde_hdmi_debugfs_edid_hdr_info_read,
+};
+
+static const struct file_operations edid_hfvsdb_info_fops = {
+ .open = simple_open,
+ .read = _sde_hdmi_debugfs_edid_hfvsdb_info_read,
+};
+
+static const struct file_operations edid_vcdb_info_fops = {
+ .open = simple_open,
+ .read = _sde_hdmi_debugfs_edid_vcdb_info_read,
+};
+
+static const struct file_operations edid_vendor_name_fops = {
+ .open = simple_open,
+ .read = _sde_hdmi_edid_vendor_name_read,
+};
+
static int _sde_hdmi_debugfs_init(struct sde_hdmi *display)
{
int rc = 0;
- struct dentry *dir, *dump_file;
+ struct dentry *dir, *dump_file, *edid_modes;
+ struct dentry *edid_vsdb_info, *edid_hdr_info, *edid_hfvsdb_info;
+ struct dentry *edid_vcdb_info, *edid_vendor_name;
dir = debugfs_create_dir(display->name, NULL);
if (!dir) {
@@ -100,6 +428,83 @@ static int _sde_hdmi_debugfs_init(struct sde_hdmi *display)
goto error_remove_dir;
}
+ edid_modes = debugfs_create_file("edid_modes",
+ 0444,
+ dir,
+ display,
+ &edid_modes_fops);
+
+ if (IS_ERR_OR_NULL(edid_modes)) {
+ rc = PTR_ERR(edid_modes);
+ SDE_ERROR("[%s]debugfs create file failed, rc=%d\n",
+ display->name, rc);
+ goto error_remove_dir;
+ }
+
+ edid_vsdb_info = debugfs_create_file("edid_vsdb_info",
+ 0444,
+ dir,
+ display,
+ &edid_vsdb_info_fops);
+
+ if (IS_ERR_OR_NULL(edid_vsdb_info)) {
+ rc = PTR_ERR(edid_vsdb_info);
+ SDE_ERROR("[%s]debugfs create file failed, rc=%d\n",
+ display->name, rc);
+ goto error_remove_dir;
+ }
+
+ edid_hdr_info = debugfs_create_file("edid_hdr_info",
+ 0444,
+ dir,
+ display,
+ &edid_hdr_info_fops);
+ if (IS_ERR_OR_NULL(edid_hdr_info)) {
+ rc = PTR_ERR(edid_hdr_info);
+ SDE_ERROR("[%s]debugfs create file failed, rc=%d\n",
+ display->name, rc);
+ goto error_remove_dir;
+ }
+
+ edid_hfvsdb_info = debugfs_create_file("edid_hfvsdb_info",
+ 0444,
+ dir,
+ display,
+ &edid_hfvsdb_info_fops);
+
+ if (IS_ERR_OR_NULL(edid_hfvsdb_info)) {
+ rc = PTR_ERR(edid_hfvsdb_info);
+ SDE_ERROR("[%s]debugfs create file failed, rc=%d\n",
+ display->name, rc);
+ goto error_remove_dir;
+ }
+
+ edid_vcdb_info = debugfs_create_file("edid_vcdb_info",
+ 0444,
+ dir,
+ display,
+ &edid_vcdb_info_fops);
+
+ if (IS_ERR_OR_NULL(edid_vcdb_info)) {
+ rc = PTR_ERR(edid_vcdb_info);
+ SDE_ERROR("[%s]debugfs create file failed, rc=%d\n",
+ display->name, rc);
+ goto error_remove_dir;
+ }
+
+ edid_vendor_name = debugfs_create_file("edid_vendor_name",
+ 0444,
+ dir,
+ display,
+ &edid_vendor_name_fops);
+
+ if (IS_ERR_OR_NULL(edid_vendor_name)) {
+ rc = PTR_ERR(edid_vendor_name);
+ SDE_ERROR("[%s]debugfs create file failed, rc=%d\n",
+ display->name, rc);
+ goto error_remove_dir;
+ }
+
display->root = dir;
return rc;
error_remove_dir:
@@ -395,20 +800,28 @@ static void _sde_hdmi_hotplug_work(struct work_struct *work)
struct sde_hdmi *sde_hdmi =
container_of(work, struct sde_hdmi, hpd_work);
struct drm_connector *connector;
+ struct hdmi *hdmi = NULL;
+ u32 hdmi_ctrl;
if (!sde_hdmi || !sde_hdmi->ctrl.ctrl ||
- !sde_hdmi->ctrl.ctrl->connector) {
+ !sde_hdmi->ctrl.ctrl->connector ||
+ !sde_hdmi->edid_ctrl) {
SDE_ERROR("sde_hdmi=%p or hdmi or connector is NULL\n",
sde_hdmi);
return;
}
-
+ hdmi = sde_hdmi->ctrl.ctrl;
connector = sde_hdmi->ctrl.ctrl->connector;
- if (sde_hdmi->connected)
- sde_hdmi_get_edid(connector, sde_hdmi);
- else
- sde_hdmi_free_edid(sde_hdmi);
+ if (sde_hdmi->connected) {
+ hdmi_ctrl = hdmi_read(hdmi, REG_HDMI_CTRL);
+ hdmi_write(hdmi, REG_HDMI_CTRL, hdmi_ctrl | HDMI_CTRL_ENABLE);
+ sde_get_edid(connector, hdmi->i2c,
+ (void **)&sde_hdmi->edid_ctrl);
+ hdmi_write(hdmi, REG_HDMI_CTRL, hdmi_ctrl);
+ hdmi->hdmi_mode = sde_detect_hdmi_monitor(sde_hdmi->edid_ctrl);
+ } else
+ sde_free_edid((void **)&sde_hdmi->edid_ctrl);
sde_hdmi_notify_clients(connector, sde_hdmi->connected);
drm_helper_hpd_irq_event(connector->dev);
@@ -431,7 +844,7 @@ static void _sde_hdmi_connector_irq(struct sde_hdmi *sde_hdmi)
hdmi_write(hdmi, REG_HDMI_HPD_INT_CTRL,
HDMI_HPD_INT_CTRL_INT_ACK);
- DRM_DEBUG("status=%04x, ctrl=%04x", hpd_int_status,
+ SDE_HDMI_DEBUG("status=%04x, ctrl=%04x", hpd_int_status,
hpd_int_ctrl);
/* detect disconnect if we are connected or visa versa: */
@@ -504,11 +917,11 @@ static int _sde_hdmi_get_audio_edid_blk(struct platform_device *pdev,
return -ENODEV;
}
- blk->audio_data_blk = display->edid.audio_data_block;
- blk->audio_data_blk_size = display->edid.adb_size;
+ blk->audio_data_blk = display->edid_ctrl->audio_data_block;
+ blk->audio_data_blk_size = display->edid_ctrl->adb_size;
- blk->spk_alloc_data_blk = display->edid.spkr_alloc_data_block;
- blk->spk_alloc_data_blk_size = display->edid.sadb_size;
+ blk->spk_alloc_data_blk = display->edid_ctrl->spkr_alloc_data_block;
+ blk->spk_alloc_data_blk_size = display->edid_ctrl->sadb_size;
return 0;
}
@@ -634,10 +1047,249 @@ void sde_hdmi_set_mode(struct hdmi *hdmi, bool power_on)
hdmi_write(hdmi, REG_HDMI_CTRL, ctrl);
spin_unlock_irqrestore(&hdmi->reg_lock, flags);
- DRM_DEBUG("HDMI Core: %s, HDMI_CTRL=0x%08x\n",
+ SDE_HDMI_DEBUG("HDMI Core: %s, HDMI_CTRL=0x%08x\n",
power_on ? "Enable" : "Disable", ctrl);
}
+int sde_hdmi_ddc_read(struct hdmi *hdmi, u16 addr, u8 offset,
+ u8 *data, u16 data_len)
+{
+ int rc;
+ int retry = 5;
+ struct i2c_msg msgs[] = {
+ {
+ .addr = addr >> 1,
+ .flags = 0,
+ .len = 1,
+ .buf = &offset,
+ }, {
+ .addr = addr >> 1,
+ .flags = I2C_M_RD,
+ .len = data_len,
+ .buf = data,
+ }
+ };
+
+ SDE_HDMI_DEBUG("Start DDC read");
+ retry:
+ rc = i2c_transfer(hdmi->i2c, msgs, 2);
+
+ retry--;
+ if (rc == 2)
+ rc = 0;
+ else if (retry > 0)
+ goto retry;
+ else
+ rc = -EIO;
+
+ SDE_HDMI_DEBUG("End DDC read %d", rc);
+
+ return rc;
+}
+
+#define DDC_WRITE_MAX_BYTE_NUM 32
+
+int sde_hdmi_ddc_write(struct hdmi *hdmi, u16 addr, u8 offset,
+ u8 *data, u16 data_len)
+{
+ int rc;
+ int retry = 10;
+ u8 buf[DDC_WRITE_MAX_BYTE_NUM];
+ struct i2c_msg msgs[] = {
+ {
+ .addr = addr >> 1,
+ .flags = 0,
+ .len = 1,
+ }
+ };
+
+ SDE_HDMI_DEBUG("Start DDC write");
+ if (data_len > (DDC_WRITE_MAX_BYTE_NUM - 1)) {
+ SDE_ERROR("%s: write size too big\n", __func__);
+ return -ERANGE;
+ }
+
+ buf[0] = offset;
+ memcpy(&buf[1], data, data_len);
+ msgs[0].buf = buf;
+ msgs[0].len = data_len + 1;
+ retry:
+ rc = i2c_transfer(hdmi->i2c, msgs, 1);
+
+ retry--;
+ if (rc == 1)
+ rc = 0;
+ else if (retry > 0)
+ goto retry;
+ else
+ rc = -EIO;
+
+ SDE_HDMI_DEBUG("End DDC write %d", rc);
+
+ return rc;
+}
+
+int sde_hdmi_scdc_read(struct hdmi *hdmi, u32 data_type, u32 *val)
+{
+ int rc = 0;
+ u8 data_buf[2] = {0};
+ u16 dev_addr, data_len;
+ u8 offset;
+
+ if (!hdmi || !hdmi->i2c || !val) {
+ SDE_ERROR("Bad Parameters\n");
+ return -EINVAL;
+ }
+
+ if (data_type >= HDMI_TX_SCDC_MAX) {
+ SDE_ERROR("Unsupported data type\n");
+ return -EINVAL;
+ }
+
+ dev_addr = 0xA8;
+
+ switch (data_type) {
+ case HDMI_TX_SCDC_SCRAMBLING_STATUS:
+ data_len = 1;
+ offset = HDMI_SCDC_SCRAMBLER_STATUS;
+ break;
+ case HDMI_TX_SCDC_SCRAMBLING_ENABLE:
+ case HDMI_TX_SCDC_TMDS_BIT_CLOCK_RATIO_UPDATE:
+ data_len = 1;
+ offset = HDMI_SCDC_TMDS_CONFIG;
+ break;
+ case HDMI_TX_SCDC_CLOCK_DET_STATUS:
+ case HDMI_TX_SCDC_CH0_LOCK_STATUS:
+ case HDMI_TX_SCDC_CH1_LOCK_STATUS:
+ case HDMI_TX_SCDC_CH2_LOCK_STATUS:
+ data_len = 1;
+ offset = HDMI_SCDC_STATUS_FLAGS_0;
+ break;
+ case HDMI_TX_SCDC_CH0_ERROR_COUNT:
+ data_len = 2;
+ offset = HDMI_SCDC_ERR_DET_0_L;
+ break;
+ case HDMI_TX_SCDC_CH1_ERROR_COUNT:
+ data_len = 2;
+ offset = HDMI_SCDC_ERR_DET_1_L;
+ break;
+ case HDMI_TX_SCDC_CH2_ERROR_COUNT:
+ data_len = 2;
+ offset = HDMI_SCDC_ERR_DET_2_L;
+ break;
+ case HDMI_TX_SCDC_READ_ENABLE:
+ data_len = 1;
+ offset = HDMI_SCDC_CONFIG_0;
+ break;
+ default:
+ break;
+ }
+
+ rc = sde_hdmi_ddc_read(hdmi, dev_addr, offset, data_buf, data_len);
+ if (rc) {
+ SDE_ERROR("DDC Read failed for %d\n", data_type);
+ return rc;
+ }
+
+ switch (data_type) {
+ case HDMI_TX_SCDC_SCRAMBLING_STATUS:
+ *val = (data_buf[0] & BIT(0)) ? 1 : 0;
+ break;
+ case HDMI_TX_SCDC_SCRAMBLING_ENABLE:
+ *val = (data_buf[0] & BIT(0)) ? 1 : 0;
+ break;
+ case HDMI_TX_SCDC_TMDS_BIT_CLOCK_RATIO_UPDATE:
+ *val = (data_buf[0] & BIT(1)) ? 1 : 0;
+ break;
+ case HDMI_TX_SCDC_CLOCK_DET_STATUS:
+ *val = (data_buf[0] & BIT(0)) ? 1 : 0;
+ break;
+ case HDMI_TX_SCDC_CH0_LOCK_STATUS:
+ *val = (data_buf[0] & BIT(1)) ? 1 : 0;
+ break;
+ case HDMI_TX_SCDC_CH1_LOCK_STATUS:
+ *val = (data_buf[0] & BIT(2)) ? 1 : 0;
+ break;
+ case HDMI_TX_SCDC_CH2_LOCK_STATUS:
+ *val = (data_buf[0] & BIT(3)) ? 1 : 0;
+ break;
+ case HDMI_TX_SCDC_CH0_ERROR_COUNT:
+ case HDMI_TX_SCDC_CH1_ERROR_COUNT:
+ case HDMI_TX_SCDC_CH2_ERROR_COUNT:
+ if (data_buf[1] & BIT(7))
+ *val = (data_buf[0] | ((data_buf[1] & 0x7F) << 8));
+ else
+ *val = 0;
+ break;
+ case HDMI_TX_SCDC_READ_ENABLE:
+ *val = (data_buf[0] & BIT(0)) ? 1 : 0;
+ break;
+ default:
+ break;
+ }
+
+ return 0;
+}
+
+int sde_hdmi_scdc_write(struct hdmi *hdmi, u32 data_type, u32 val)
+{
+ int rc = 0;
+ u8 data_buf[2] = {0};
+ u8 read_val = 0;
+ u16 dev_addr, data_len;
+ u8 offset;
+
+ if (!hdmi || !hdmi->i2c) {
+ SDE_ERROR("Bad Parameters\n");
+ return -EINVAL;
+ }
+
+ if (data_type >= HDMI_TX_SCDC_MAX) {
+ SDE_ERROR("Unsupported data type\n");
+ return -EINVAL;
+ }
+
+ dev_addr = 0xA8;
+
+ switch (data_type) {
+ case HDMI_TX_SCDC_SCRAMBLING_ENABLE:
+ case HDMI_TX_SCDC_TMDS_BIT_CLOCK_RATIO_UPDATE:
+ dev_addr = 0xA8;
+ data_len = 1;
+ offset = HDMI_SCDC_TMDS_CONFIG;
+ rc = sde_hdmi_ddc_read(hdmi, dev_addr, offset, &read_val,
+ data_len);
+ if (rc) {
+ SDE_ERROR("scdc read failed\n");
+ return rc;
+ }
+ if (data_type == HDMI_TX_SCDC_SCRAMBLING_ENABLE) {
+ data_buf[0] = ((((u8)(read_val & 0xFF)) & (~BIT(0))) |
+ ((u8)(val & BIT(0))));
+ } else {
+ data_buf[0] = ((((u8)(read_val & 0xFF)) & (~BIT(1))) |
+ (((u8)(val & BIT(0))) << 1));
+ }
+ break;
+ case HDMI_TX_SCDC_READ_ENABLE:
+ data_len = 1;
+ offset = HDMI_SCDC_CONFIG_0;
+ data_buf[0] = (u8)(val & 0x1);
+ break;
+ default:
+ SDE_ERROR("Cannot write to read only reg (%d)\n",
+ data_type);
+ return -EINVAL;
+ }
+
+ rc = sde_hdmi_ddc_write(hdmi, dev_addr, offset, data_buf, data_len);
+ if (rc) {
+ SDE_ERROR("DDC Read failed for %d\n", data_type);
+ return rc;
+ }
+ return 0;
+}
+
int sde_hdmi_get_info(struct msm_display_info *info,
void *display)
{
@@ -746,7 +1398,7 @@ int sde_hdmi_connector_post_init(struct drm_connector *connector,
if (info)
sde_kms_info_add_keystr(info,
- "DISPLAY_TYPE",
+ "display type",
sde_hdmi->display_type);
hdmi->connector = connector;
@@ -775,8 +1427,6 @@ sde_hdmi_connector_detect(struct drm_connector *connector,
return status;
}
- SDE_DEBUG("\n");
-
/* get display dsi_info */
memset(&info, 0x0, sizeof(info));
rc = sde_hdmi_get_info(&info, display);
@@ -797,25 +1447,6 @@ sde_hdmi_connector_detect(struct drm_connector *connector,
return status;
}
-int _sde_hdmi_update_modes(struct drm_connector *connector,
- struct sde_hdmi *display)
-{
- int rc = 0;
- struct hdmi_edid_ctrl *edid_ctrl = &display->edid;
-
- if (edid_ctrl->edid) {
- drm_mode_connector_update_edid_property(connector,
- edid_ctrl->edid);
-
- rc = drm_add_edid_modes(connector, edid_ctrl->edid);
- return rc;
- }
-
- drm_mode_connector_update_edid_property(connector, NULL);
-
- return rc;
-}
-
int sde_hdmi_connector_get_modes(struct drm_connector *connector, void *display)
{
struct sde_hdmi *hdmi_display = (struct sde_hdmi *)display;
@@ -828,8 +1459,6 @@ int sde_hdmi_connector_get_modes(struct drm_connector *connector, void *display)
return 0;
}
- SDE_DEBUG("\n");
-
if (hdmi_display->non_pluggable) {
list_for_each_entry(mode, &hdmi_display->mode_list, head) {
m = drm_mode_duplicate(connector->dev, mode);
@@ -842,7 +1471,9 @@ int sde_hdmi_connector_get_modes(struct drm_connector *connector, void *display)
}
ret = hdmi_display->num_of_modes;
} else {
- ret = _sde_hdmi_update_modes(connector, display);
+ /* pluggable case assumes EDID is read when HPD */
+ ret = _sde_edid_update_modes(connector,
+ hdmi_display->edid_ctrl);
}
return ret;
@@ -864,8 +1495,6 @@ enum drm_mode_status sde_hdmi_mode_valid(struct drm_connector *connector,
return 0;
}
- SDE_DEBUG("\n");
-
hdmi = hdmi_display->ctrl.ctrl;
priv = connector->dev->dev_private;
kms = priv->kms;
@@ -873,7 +1502,7 @@ enum drm_mode_status sde_hdmi_mode_valid(struct drm_connector *connector,
actual = kms->funcs->round_pixclk(kms,
requested, hdmi->encoder);
- SDE_DEBUG("requested=%ld, actual=%ld", requested, actual);
+ SDE_HDMI_DEBUG("requested=%ld, actual=%ld", requested, actual);
if (actual != requested)
return MODE_CLOCK_RANGE;
@@ -909,7 +1538,7 @@ static int sde_hdmi_bind(struct device *dev, struct device *master, void *data)
struct msm_drm_private *priv = NULL;
struct platform_device *pdev = to_platform_device(dev);
- SDE_ERROR("E\n");
+ SDE_HDMI_DEBUG(" %s +\n", __func__);
if (!dev || !pdev || !master) {
pr_err("invalid param(s), dev %pK, pdev %pK, master %pK\n",
dev, pdev, master);
@@ -941,18 +1570,20 @@ static int sde_hdmi_bind(struct device *dev, struct device *master, void *data)
goto error;
}
- rc = sde_hdmi_edid_init(display);
- if (rc) {
- SDE_ERROR("[%s]Ext Disp init failed, rc=%d\n",
- display->name, rc);
+ display->edid_ctrl = sde_edid_init();
+ if (!display->edid_ctrl) {
+ SDE_ERROR("[%s]sde edid init failed\n",
+ display->name);
+ rc = -ENOMEM;
goto error;
}
display_ctrl = &display->ctrl;
display_ctrl->ctrl = priv->hdmi;
- SDE_ERROR("display_ctrl->ctrl=%p\n", display_ctrl->ctrl);
display->drm_dev = drm;
+ mutex_unlock(&display->display_lock);
+ return rc;
error:
(void)_sde_hdmi_debugfs_deinit(display);
debug_error:
@@ -978,7 +1609,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_hdmi_edid_deinit(display);
+ (void)sde_edid_deinit((void **)&display->edid_ctrl);
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 869d1bebf9db..bb3061a6ed00 100644
--- a/drivers/gpu/drm/msm/hdmi-staging/sde_hdmi.h
+++ b/drivers/gpu/drm/msm/hdmi-staging/sde_hdmi.h
@@ -25,9 +25,13 @@
#include <drm/drm_crtc.h>
#include "hdmi.h"
-#define MAX_NUMBER_ADB 5
-#define MAX_AUDIO_DATA_BLOCK_SIZE 30
-#define MAX_SPKR_ALLOC_DATA_BLOCK_SIZE 3
+#include "sde_edid_parser.h"
+
+#ifdef HDMI_DEBUG_ENABLE
+#define SDE_HDMI_DEBUG(fmt, args...) SDE_ERROR(fmt, ##args)
+#else
+#define SDE_HDMI_DEBUG(fmt, args...) SDE_DEBUG(fmt, ##args)
+#endif
/**
* struct sde_hdmi_info - defines hdmi display properties
@@ -64,14 +68,6 @@ struct sde_hdmi_ctrl {
u32 hdmi_ctrl_idx;
};
-struct hdmi_edid_ctrl {
- struct edid *edid;
- u8 audio_data_block[MAX_NUMBER_ADB * MAX_AUDIO_DATA_BLOCK_SIZE];
- int adb_size;
- u8 spkr_alloc_data_block[MAX_SPKR_ALLOC_DATA_BLOCK_SIZE];
- int sadb_size;
-};
-
/**
* struct sde_hdmi - hdmi display information
* @pdev: Pointer to platform device.
@@ -102,7 +98,7 @@ struct sde_hdmi {
struct platform_device *ext_pdev;
struct msm_ext_disp_init_data ext_audio_data;
- struct hdmi_edid_ctrl edid;
+ struct sde_edid_ctrl *edid_ctrl;
bool non_pluggable;
u32 num_of_modes;
@@ -116,6 +112,38 @@ struct sde_hdmi {
struct dentry *root;
};
+/**
+ * hdmi_tx_scdc_access_type() - hdmi 2.0 DDC functionalities.
+ */
+enum hdmi_tx_scdc_access_type {
+ HDMI_TX_SCDC_SCRAMBLING_STATUS,
+ HDMI_TX_SCDC_SCRAMBLING_ENABLE,
+ HDMI_TX_SCDC_TMDS_BIT_CLOCK_RATIO_UPDATE,
+ HDMI_TX_SCDC_CLOCK_DET_STATUS,
+ HDMI_TX_SCDC_CH0_LOCK_STATUS,
+ HDMI_TX_SCDC_CH1_LOCK_STATUS,
+ HDMI_TX_SCDC_CH2_LOCK_STATUS,
+ HDMI_TX_SCDC_CH0_ERROR_COUNT,
+ HDMI_TX_SCDC_CH1_ERROR_COUNT,
+ HDMI_TX_SCDC_CH2_ERROR_COUNT,
+ HDMI_TX_SCDC_READ_ENABLE,
+ HDMI_TX_SCDC_MAX,
+};
+
+#define HDMI_KHZ_TO_HZ 1000
+#define HDMI_MHZ_TO_HZ 1000000
+/**
+ * hdmi_tx_ddc_timer_type() - hdmi DDC timer functionalities.
+ */
+enum hdmi_tx_ddc_timer_type {
+ HDMI_TX_DDC_TIMER_HDCP2P2_RD_MSG,
+ HDMI_TX_DDC_TIMER_SCRAMBLER_STATUS,
+ HDMI_TX_DDC_TIMER_UPDATE_FLAGS,
+ HDMI_TX_DDC_TIMER_STATUS_FLAGS,
+ HDMI_TX_DDC_TIMER_CED,
+ HDMI_TX_DDC_TIMER_MAX,
+ };
+
#ifdef CONFIG_DRM_SDE_HDMI
/**
* sde_hdmi_get_num_of_displays() - returns number of display devices
@@ -259,6 +287,52 @@ struct drm_bridge *sde_hdmi_bridge_init(struct hdmi *hdmi);
void sde_hdmi_set_mode(struct hdmi *hdmi, bool power_on);
/**
+ * sde_hdmi_ddc_read() - common hdmi ddc read API.
+ * @hdmi: Handle to the hdmi.
+ * @addr: Command address.
+ * @offset: Command offset.
+ * @data: Data buffer for read back.
+ * @data_len: Data buffer length.
+ *
+ * Return: error code.
+ */
+int sde_hdmi_ddc_read(struct hdmi *hdmi, u16 addr, u8 offset,
+ u8 *data, u16 data_len);
+
+/**
+ * sde_hdmi_ddc_write() - common hdmi ddc write API.
+ * @hdmi: Handle to the hdmi.
+ * @addr: Command address.
+ * @offset: Command offset.
+ * @data: Data buffer for write.
+ * @data_len: Data buffer length.
+ *
+ * Return: error code.
+ */
+int sde_hdmi_ddc_write(struct hdmi *hdmi, u16 addr, u8 offset,
+ u8 *data, u16 data_len);
+
+/**
+ * sde_hdmi_scdc_read() - hdmi 2.0 ddc read API.
+ * @hdmi: Handle to the hdmi.
+ * @data_type: DDC data type, refer to enum hdmi_tx_scdc_access_type.
+ * @val: Read back value.
+ *
+ * Return: error code.
+ */
+int sde_hdmi_scdc_read(struct hdmi *hdmi, u32 data_type, u32 *val);
+
+/**
+ * sde_hdmi_scdc_write() - hdmi 2.0 ddc write API.
+ * @hdmi: Handle to the hdmi.
+ * @data_type: DDC data type, refer to enum hdmi_tx_scdc_access_type.
+ * @val: Value write through DDC.
+ *
+ * Return: error code.
+ */
+int sde_hdmi_scdc_write(struct hdmi *hdmi, u32 data_type, u32 val);
+
+/**
* sde_hdmi_audio_on() - enable hdmi audio.
* @hdmi: Handle to the hdmi.
* @params: audio setup parameters from codec.
@@ -305,40 +379,6 @@ void sde_hdmi_notify_clients(struct drm_connector *connector,
void sde_hdmi_ack_state(struct drm_connector *connector,
enum drm_connector_status status);
-/**
- * sde_hdmi_edid_init() - init edid structure.
- * @display: Handle to the sde_hdmi.
- *
- * Return: error code.
- */
-int sde_hdmi_edid_init(struct sde_hdmi *display);
-
-/**
- * sde_hdmi_edid_deinit() - deinit edid structure.
- * @display: Handle to the sde_hdmi.
- *
- * Return: error code.
- */
-int sde_hdmi_edid_deinit(struct sde_hdmi *display);
-
-/**
- * sde_hdmi_get_edid() - get edid info.
- * @connector: Handle to the drm_connector.
- * @display: Handle to the sde_hdmi.
- *
- * Return: void.
- */
-void sde_hdmi_get_edid(struct drm_connector *connector,
- struct sde_hdmi *display);
-
-/**
- * sde_hdmi_free_edid() - free edid structure.
- * @display: Handle to the sde_hdmi.
- *
- * Return: error code.
- */
-int sde_hdmi_free_edid(struct sde_hdmi *display);
-
#else /*#ifdef CONFIG_DRM_SDE_HDMI*/
static inline u32 sde_hdmi_get_num_of_displays(void)
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 681dca501f9b..c76e42c67885 100644
--- a/drivers/gpu/drm/msm/hdmi-staging/sde_hdmi_bridge.c
+++ b/drivers/gpu/drm/msm/hdmi-staging/sde_hdmi_bridge.c
@@ -28,6 +28,13 @@ struct sde_hdmi_bridge {
};
#define to_hdmi_bridge(x) container_of(x, struct sde_hdmi_bridge, base)
+/* TX major version that supports scrambling */
+#define HDMI_TX_SCRAMBLER_MIN_TX_VERSION 0x04
+#define HDMI_TX_SCRAMBLER_THRESHOLD_RATE_KHZ 340000
+#define HDMI_TX_SCRAMBLER_TIMEOUT_MSEC 200
+/* default hsyncs for 4k@60 for 200ms */
+#define HDMI_DEFAULT_TIMEOUT_HSYNC 28571
+
/* for AVI program */
#define HDMI_AVI_INFOFRAME_BUFFER_SIZE \
(HDMI_INFOFRAME_HEADER_SIZE + HDMI_AVI_INFOFRAME_SIZE)
@@ -101,6 +108,265 @@ static void _sde_hdmi_bridge_power_off(struct drm_bridge *bridge)
}
}
+static int _sde_hdmi_bridge_ddc_clear_irq(struct hdmi *hdmi,
+ char *what)
+{
+ u32 ddc_int_ctrl, ddc_status, in_use, timeout;
+ u32 sw_done_mask = BIT(2);
+ u32 sw_done_ack = BIT(1);
+ u32 in_use_by_sw = BIT(0);
+ u32 in_use_by_hw = BIT(1);
+
+ /* clear and enable interrutps */
+ ddc_int_ctrl = sw_done_mask | sw_done_ack;
+
+ hdmi_write(hdmi, REG_HDMI_DDC_INT_CTRL, ddc_int_ctrl);
+
+ /* wait until DDC HW is free */
+ timeout = 100;
+ do {
+ ddc_status = hdmi_read(hdmi, REG_HDMI_DDC_HW_STATUS);
+ in_use = ddc_status & (in_use_by_sw | in_use_by_hw);
+ if (in_use) {
+ SDE_DEBUG("ddc is in use by %s, timeout(%d)\n",
+ ddc_status & in_use_by_sw ? "sw" : "hw",
+ timeout);
+ udelay(100);
+ }
+ } while (in_use && --timeout);
+
+ if (!timeout) {
+ SDE_ERROR("%s: timedout\n", what);
+ return -ETIMEDOUT;
+ }
+
+ return 0;
+}
+
+static int _sde_hdmi_bridge_scrambler_ddc_check_status(struct hdmi *hdmi)
+{
+ int rc = 0;
+ u32 reg_val;
+
+ /* check for errors and clear status */
+ reg_val = hdmi_read(hdmi, REG_HDMI_SCRAMBLER_STATUS_DDC_STATUS);
+ if (reg_val & BIT(4)) {
+ SDE_ERROR("ddc aborted\n");
+ reg_val |= BIT(5);
+ rc = -ECONNABORTED;
+ }
+
+ if (reg_val & BIT(8)) {
+ SDE_ERROR("timed out\n");
+ reg_val |= BIT(9);
+ rc = -ETIMEDOUT;
+ }
+
+ if (reg_val & BIT(12)) {
+ SDE_ERROR("NACK0\n");
+ reg_val |= BIT(13);
+ rc = -EIO;
+ }
+ if (reg_val & BIT(14)) {
+ SDE_ERROR("NACK1\n");
+ reg_val |= BIT(15);
+ rc = -EIO;
+ }
+ hdmi_write(hdmi, REG_HDMI_SCRAMBLER_STATUS_DDC_STATUS, reg_val);
+
+ return rc;
+}
+
+static void _sde_hdmi_bridge_scrambler_ddc_reset(struct hdmi *hdmi)
+{
+ u32 reg_val;
+
+ /* clear ack and disable interrupts */
+ reg_val = BIT(14) | BIT(9) | BIT(5) | BIT(1);
+ hdmi_write(hdmi, REG_HDMI_DDC_INT_CTRL2, reg_val);
+
+ /* Reset DDC timers */
+ reg_val = BIT(0) | hdmi_read(hdmi, REG_HDMI_SCRAMBLER_STATUS_DDC_CTRL);
+ hdmi_write(hdmi, REG_HDMI_SCRAMBLER_STATUS_DDC_CTRL, reg_val);
+
+ reg_val = hdmi_read(hdmi, REG_HDMI_SCRAMBLER_STATUS_DDC_CTRL);
+ reg_val &= ~BIT(0);
+ hdmi_write(hdmi, REG_HDMI_SCRAMBLER_STATUS_DDC_CTRL, reg_val);
+}
+
+static void _sde_hdmi_bridge_scrambler_ddc_disable(struct hdmi *hdmi)
+{
+ u32 reg_val;
+
+ _sde_hdmi_bridge_scrambler_ddc_reset(hdmi);
+ /* Disable HW DDC access to RxStatus register */
+ reg_val = hdmi_read(hdmi, REG_HDMI_HW_DDC_CTRL);
+ reg_val &= ~(BIT(8) | BIT(9));
+ hdmi_write(hdmi, REG_HDMI_HW_DDC_CTRL, reg_val);
+}
+
+static int _sde_hdmi_bridge_scrambler_status_timer_setup(struct hdmi *hdmi,
+ u32 timeout_hsync)
+{
+ u32 reg_val;
+ int rc;
+
+ _sde_hdmi_bridge_ddc_clear_irq(hdmi, "scrambler");
+
+ hdmi_write(hdmi, REG_HDMI_SCRAMBLER_STATUS_DDC_TIMER_CTRL,
+ timeout_hsync);
+ hdmi_write(hdmi, REG_HDMI_SCRAMBLER_STATUS_DDC_TIMER_CTRL2,
+ timeout_hsync);
+ reg_val = hdmi_read(hdmi, REG_HDMI_DDC_INT_CTRL5);
+ reg_val |= BIT(10);
+ hdmi_write(hdmi, REG_HDMI_DDC_INT_CTRL5, reg_val);
+
+ reg_val = hdmi_read(hdmi, REG_HDMI_DDC_INT_CTRL2);
+ /* Trigger interrupt if scrambler status is 0 or DDC failure */
+ reg_val |= BIT(10);
+ reg_val &= ~(BIT(15) | BIT(16));
+ reg_val |= BIT(16);
+ hdmi_write(hdmi, REG_HDMI_DDC_INT_CTRL2, reg_val);
+
+ /* Enable DDC access */
+ reg_val = hdmi_read(hdmi, REG_HDMI_HW_DDC_CTRL);
+
+ reg_val &= ~(BIT(8) | BIT(9));
+ reg_val |= BIT(8);
+ hdmi_write(hdmi, REG_HDMI_HW_DDC_CTRL, reg_val);
+
+ /* WAIT for 200ms as per HDMI 2.0 standard for sink to respond */
+ msleep(200);
+
+ /* clear the scrambler status */
+ rc = _sde_hdmi_bridge_scrambler_ddc_check_status(hdmi);
+ if (rc)
+ SDE_ERROR("scrambling ddc error %d\n", rc);
+
+ _sde_hdmi_bridge_scrambler_ddc_disable(hdmi);
+
+ return rc;
+}
+
+static int _sde_hdmi_bridge_setup_ddc_timers(struct hdmi *hdmi,
+ u32 type, u32 to_in_num_lines)
+{
+ if (type >= HDMI_TX_DDC_TIMER_MAX) {
+ SDE_ERROR("Invalid timer type %d\n", type);
+ return -EINVAL;
+ }
+
+ switch (type) {
+ case HDMI_TX_DDC_TIMER_SCRAMBLER_STATUS:
+ _sde_hdmi_bridge_scrambler_status_timer_setup(hdmi,
+ to_in_num_lines);
+ break;
+ default:
+ SDE_ERROR("%d type not supported\n", type);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static inline int _sde_hdmi_bridge_get_timeout_in_hysnc(
+ struct drm_display_mode *mode, u32 timeout_ms)
+{
+ /*
+ * pixel clock = h_total * v_total * fps
+ * 1 sec = pixel clock number of pixels are transmitted.
+ * time taken by one line (h_total) = 1s / (v_total * fps).
+ * lines for give time = (time_ms * 1000) / (1000000 / (v_total * fps))
+ * = (time_ms * clock) / h_total
+ */
+
+ return (timeout_ms * mode->clock / mode->htotal);
+}
+
+static int _sde_hdmi_bridge_setup_scrambler(struct hdmi *hdmi,
+ struct drm_display_mode *mode)
+{
+ int rc = 0;
+ int timeout_hsync;
+ u32 reg_val = 0;
+ u32 tmds_clock_ratio = 0;
+ bool scrambler_on = false;
+
+ struct drm_connector *connector = NULL;
+
+ if (!hdmi || !mode) {
+ SDE_ERROR("invalid input\n");
+ return -EINVAL;
+ }
+ connector = hdmi->connector;
+
+ /* Read HDMI version */
+ reg_val = hdmi_read(hdmi, REG_HDMI_VERSION);
+ reg_val = (reg_val & 0xF0000000) >> 28;
+ /* Scrambling is supported from HDMI TX 4.0 */
+ if (reg_val < HDMI_TX_SCRAMBLER_MIN_TX_VERSION) {
+ DRM_INFO("scrambling not supported by tx\n");
+ return 0;
+ }
+
+ if (mode->clock > HDMI_TX_SCRAMBLER_THRESHOLD_RATE_KHZ) {
+ scrambler_on = true;
+ tmds_clock_ratio = 1;
+ } else {
+ scrambler_on = connector->supports_scramble;
+ }
+
+ DRM_INFO("scrambler %s\n", scrambler_on ? "on" : "off");
+
+ if (scrambler_on) {
+ rc = sde_hdmi_scdc_write(hdmi,
+ HDMI_TX_SCDC_TMDS_BIT_CLOCK_RATIO_UPDATE,
+ tmds_clock_ratio);
+ if (rc) {
+ SDE_ERROR("TMDS CLK RATIO ERR\n");
+ return rc;
+ }
+
+ 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);
+
+ rc = sde_hdmi_scdc_write(hdmi,
+ HDMI_TX_SCDC_SCRAMBLING_ENABLE, 0x1);
+ if (rc) {
+ SDE_ERROR("failed to enable scrambling\n");
+ return rc;
+ }
+
+ /*
+ * Setup hardware to periodically check for scrambler
+ * status bit on the sink. Sink should set this bit
+ * with in 200ms after scrambler is enabled.
+ */
+ timeout_hsync = _sde_hdmi_bridge_get_timeout_in_hysnc(
+ mode,
+ HDMI_TX_SCRAMBLER_TIMEOUT_MSEC);
+ if (timeout_hsync <= 0) {
+ SDE_ERROR("err in timeout hsync calc\n");
+ timeout_hsync = HDMI_DEFAULT_TIMEOUT_HSYNC;
+ }
+ SDE_DEBUG("timeout for scrambling en: %d hsyncs\n",
+ timeout_hsync);
+
+ rc = _sde_hdmi_bridge_setup_ddc_timers(hdmi,
+ HDMI_TX_DDC_TIMER_SCRAMBLER_STATUS, timeout_hsync);
+ } 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);
+ }
+ return rc;
+}
+
static void _sde_hdmi_bridge_pre_enable(struct drm_bridge *bridge)
{
struct sde_hdmi_bridge *sde_hdmi_bridge = to_hdmi_bridge(bridge);
@@ -373,6 +639,7 @@ static void _sde_hdmi_bridge_mode_set(struct drm_bridge *bridge,
_sde_hdmi_bridge_set_spd_infoframe(hdmi, mode);
DRM_DEBUG("hdmi setup info frame\n");
}
+ _sde_hdmi_bridge_setup_scrambler(hdmi, mode);
}
static const struct drm_bridge_funcs _sde_hdmi_bridge_funcs = {
diff --git a/drivers/gpu/drm/msm/hdmi-staging/sde_hdmi_edid.c b/drivers/gpu/drm/msm/hdmi-staging/sde_hdmi_edid.c
deleted file mode 100644
index 57c79e2aa812..000000000000
--- a/drivers/gpu/drm/msm/hdmi-staging/sde_hdmi_edid.c
+++ /dev/null
@@ -1,227 +0,0 @@
-/* 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 <drm/drm_edid.h>
-
-#include "sde_kms.h"
-#include "sde_hdmi.h"
-
-/* TODO: copy from drm_edid.c and mdss_hdmi_edid.c. remove if using ELD */
-#define DBC_START_OFFSET 4
-#define EDID_DTD_LEN 18
-
-enum data_block_types {
- RESERVED,
- AUDIO_DATA_BLOCK,
- VIDEO_DATA_BLOCK,
- VENDOR_SPECIFIC_DATA_BLOCK,
- SPEAKER_ALLOCATION_DATA_BLOCK,
- VESA_DTC_DATA_BLOCK,
- RESERVED2,
- USE_EXTENDED_TAG
-};
-
-static u8 *_sde_hdmi_edid_find_cea_extension(struct edid *edid)
-{
- u8 *edid_ext = NULL;
- int i;
-
- /* No EDID or EDID extensions */
- if (edid == NULL || edid->extensions == 0)
- return NULL;
-
- /* Find CEA extension */
- for (i = 0; i < edid->extensions; i++) {
- edid_ext = (u8 *)edid + EDID_LENGTH * (i + 1);
- if (edid_ext[0] == CEA_EXT)
- break;
- }
-
- if (i == edid->extensions)
- return NULL;
-
- return edid_ext;
-}
-
-static const u8 *_sde_hdmi_edid_find_block(const u8 *in_buf, u32 start_offset,
- u8 type, u8 *len)
-{
- /* the start of data block collection, start of Video Data Block */
- u32 offset = start_offset;
- u32 dbc_offset = in_buf[2];
-
- /*
- * * edid buffer 1, byte 2 being 4 means no non-DTD/Data block
- * collection present.
- * * edid buffer 1, byte 2 being 0 means no non-DTD/DATA block
- * collection present and no DTD data present.
- */
- if ((dbc_offset == 0) || (dbc_offset == 4)) {
- SDE_ERROR("EDID: no DTD or non-DTD data present\n");
- return NULL;
- }
-
- while (offset < dbc_offset) {
- u8 block_len = in_buf[offset] & 0x1F;
-
- if ((offset + block_len <= dbc_offset) &&
- (in_buf[offset] >> 5) == type) {
- *len = block_len;
- SDE_DEBUG("EDID: block=%d found @ 0x%x w/ len=%d\n",
- type, offset, block_len);
-
- return in_buf + offset;
- }
- offset += 1 + block_len;
- }
-
- return NULL;
-}
-
-static void _sde_hdmi_extract_audio_data_blocks(
- struct hdmi_edid_ctrl *edid_ctrl)
-{
- u8 len = 0;
- u8 adb_max = 0;
- const u8 *adb = NULL;
- u32 offset = DBC_START_OFFSET;
- u8 *cea = NULL;
-
- if (!edid_ctrl) {
- SDE_ERROR("invalid edid_ctrl\n");
- return;
- }
-
- cea = _sde_hdmi_edid_find_cea_extension(edid_ctrl->edid);
- if (!cea) {
- SDE_DEBUG("CEA extension not found\n");
- return;
- }
-
- edid_ctrl->adb_size = 0;
-
- memset(edid_ctrl->audio_data_block, 0,
- sizeof(edid_ctrl->audio_data_block));
-
- do {
- len = 0;
- adb = _sde_hdmi_edid_find_block(cea, offset, AUDIO_DATA_BLOCK,
- &len);
-
- if ((adb == NULL) || (len > MAX_AUDIO_DATA_BLOCK_SIZE ||
- adb_max >= MAX_NUMBER_ADB)) {
- if (!edid_ctrl->adb_size) {
- SDE_DEBUG("No/Invalid Audio Data Block\n");
- return;
- }
-
- continue;
- }
-
- memcpy(edid_ctrl->audio_data_block + edid_ctrl->adb_size,
- adb + 1, len);
- offset = (adb - cea) + 1 + len;
-
- edid_ctrl->adb_size += len;
- adb_max++;
- } while (adb);
-
-}
-
-static void _sde_hdmi_extract_speaker_allocation_data(
- struct hdmi_edid_ctrl *edid_ctrl)
-{
- u8 len;
- const u8 *sadb = NULL;
- u8 *cea = NULL;
-
- if (!edid_ctrl) {
- SDE_ERROR("invalid edid_ctrl\n");
- return;
- }
-
- cea = _sde_hdmi_edid_find_cea_extension(edid_ctrl->edid);
- if (!cea) {
- SDE_DEBUG("CEA extension not found\n");
- return;
- }
-
- sadb = _sde_hdmi_edid_find_block(cea, DBC_START_OFFSET,
- SPEAKER_ALLOCATION_DATA_BLOCK, &len);
- if ((sadb == NULL) || (len != MAX_SPKR_ALLOC_DATA_BLOCK_SIZE)) {
- SDE_DEBUG("No/Invalid Speaker Allocation Data Block\n");
- return;
- }
-
- memcpy(edid_ctrl->spkr_alloc_data_block, sadb + 1, len);
- edid_ctrl->sadb_size = len;
-
- SDE_DEBUG("EDID: speaker alloc data SP byte = %08x %s%s%s%s%s%s%s\n",
- sadb[1],
- (sadb[1] & BIT(0)) ? "FL/FR," : "",
- (sadb[1] & BIT(1)) ? "LFE," : "",
- (sadb[1] & BIT(2)) ? "FC," : "",
- (sadb[1] & BIT(3)) ? "RL/RR," : "",
- (sadb[1] & BIT(4)) ? "RC," : "",
- (sadb[1] & BIT(5)) ? "FLC/FRC," : "",
- (sadb[1] & BIT(6)) ? "RLC/RRC," : "");
-}
-
-int sde_hdmi_edid_init(struct sde_hdmi *display)
-{
- int rc = 0;
-
- if (!display) {
- SDE_ERROR("[%s]Invalid params\n", display->name);
- return -EINVAL;
- }
-
- memset(&display->edid, 0, sizeof(display->edid));
-
- return rc;
-}
-
-int sde_hdmi_free_edid(struct sde_hdmi *display)
-{
- struct hdmi_edid_ctrl *edid_ctrl = &display->edid;
-
- kfree(edid_ctrl->edid);
- edid_ctrl->edid = NULL;
-
- return 0;
-}
-
-int sde_hdmi_edid_deinit(struct sde_hdmi *display)
-{
- return sde_hdmi_free_edid(display);
-}
-
-void sde_hdmi_get_edid(struct drm_connector *connector,
- struct sde_hdmi *display)
-{
- u32 hdmi_ctrl;
- struct hdmi_edid_ctrl *edid_ctrl = &display->edid;
- struct hdmi *hdmi = display->ctrl.ctrl;
-
- /* Read EDID */
- hdmi_ctrl = hdmi_read(hdmi, REG_HDMI_CTRL);
- hdmi_write(hdmi, REG_HDMI_CTRL, hdmi_ctrl | HDMI_CTRL_ENABLE);
- edid_ctrl->edid = drm_get_edid(connector, hdmi->i2c);
- hdmi_write(hdmi, REG_HDMI_CTRL, hdmi_ctrl);
-
- if (edid_ctrl->edid) {
- hdmi->hdmi_mode = drm_detect_hdmi_monitor(edid_ctrl->edid);
-
- _sde_hdmi_extract_audio_data_blocks(edid_ctrl);
- _sde_hdmi_extract_speaker_allocation_data(edid_ctrl);
- }
-};
diff --git a/drivers/gpu/drm/msm/hdmi/hdmi.xml.h b/drivers/gpu/drm/msm/hdmi/hdmi.xml.h
index aef20f76bf02..0956617442af 100644
--- a/drivers/gpu/drm/msm/hdmi/hdmi.xml.h
+++ b/drivers/gpu/drm/msm/hdmi/hdmi.xml.h
@@ -563,6 +563,20 @@ static inline uint32_t HDMI_VSYNC_TOTAL_F2_V_TOTAL(uint32_t val)
#define REG_HDMI_CEC_WR_CHECK_CONFIG 0x00000370
+#define REG_HDMI_DDC_INT_CTRL0 0x00000430
+#define REG_HDMI_DDC_INT_CTRL1 0x00000434
+#define REG_HDMI_DDC_INT_CTRL2 0x00000438
+#define REG_HDMI_DDC_INT_CTRL3 0x0000043C
+#define REG_HDMI_DDC_INT_CTRL4 0x00000440
+#define REG_HDMI_DDC_INT_CTRL5 0x00000444
+#define REG_HDMI_SCRAMBLER_STATUS_DDC_CTRL 0x00000464
+#define REG_HDMI_SCRAMBLER_STATUS_DDC_TIMER_CTRL 0x00000468
+#define REG_HDMI_SCRAMBLER_STATUS_DDC_TIMER_CTRL2 0x0000046C
+#define REG_HDMI_SCRAMBLER_STATUS_DDC_STATUS 0x00000470
+#define REG_HDMI_SCRAMBLER_STATUS_DDC_TIMER_STATUS 0x00000474
+#define REG_HDMI_SCRAMBLER_STATUS_DDC_TIMER_STATUS2 0x00000478
+#define REG_HDMI_HW_DDC_CTRL 0x000004CC
+
#define REG_HDMI_8x60_PHY_REG0 0x00000300
#define HDMI_8x60_PHY_REG0_DESER_DEL_CTRL__MASK 0x0000001c
#define HDMI_8x60_PHY_REG0_DESER_DEL_CTRL__SHIFT 2
diff --git a/drivers/gpu/drm/msm/sde/sde_crtc.c b/drivers/gpu/drm/msm/sde/sde_crtc.c
index 82da4c1bc86c..41322045ced3 100644
--- a/drivers/gpu/drm/msm/sde/sde_crtc.c
+++ b/drivers/gpu/drm/msm/sde/sde_crtc.c
@@ -51,6 +51,9 @@
#define LEFT_MIXER 0
#define RIGHT_MIXER 1
+/* indicates pending page flip events */
+#define PENDING_FLIP 0x2
+
static inline struct sde_kms *_sde_crtc_get_kms(struct drm_crtc *crtc)
{
struct msm_drm_private *priv = crtc->dev->dev_private;
@@ -399,13 +402,18 @@ static void sde_crtc_vblank_cb(void *data)
{
struct drm_crtc *crtc = (struct drm_crtc *)data;
struct sde_crtc *sde_crtc = to_sde_crtc(crtc);
+ unsigned pending;
+ pending = atomic_xchg(&sde_crtc->pending, 0);
/* keep statistics on vblank callback - with auto reset via debugfs */
if (ktime_equal(sde_crtc->vblank_cb_time, ktime_set(0, 0)))
sde_crtc->vblank_cb_time = ktime_get();
else
sde_crtc->vblank_cb_count++;
- _sde_crtc_complete_flip(crtc, NULL);
+
+ if (pending & PENDING_FLIP)
+ _sde_crtc_complete_flip(crtc, NULL);
+
drm_crtc_handle_vblank(crtc);
DRM_DEBUG_VBL("crtc%d\n", crtc->base.id);
SDE_EVT32_IRQ(DRMID(crtc));
@@ -519,6 +527,28 @@ static void sde_crtc_frame_event_cb(void *data, u32 event)
queue_kthread_work(&priv->disp_thread[pipe_id].worker, &fevent->work);
}
+/**
+ * sde_crtc_request_flip_cb - callback to request page_flip events
+ * Once the HW flush is complete , userspace must be notified of
+ * PAGE_FLIP completed event in the next vblank event.
+ * Using this callback, a hint is set to signal any callers waiting
+ * for a PAGE_FLIP complete event.
+ * This is called within the enc_spinlock.
+ * @data: Pointer to cb private data
+ */
+static void sde_crtc_request_flip_cb(void *data)
+{
+ struct drm_crtc *crtc = (struct drm_crtc *)data;
+ struct sde_crtc *sde_crtc;
+
+ if (!crtc) {
+ SDE_ERROR("invalid parameters\n");
+ return;
+ }
+ sde_crtc = to_sde_crtc(crtc);
+ atomic_or(PENDING_FLIP, &sde_crtc->pending);
+}
+
void sde_crtc_complete_commit(struct drm_crtc *crtc,
struct drm_crtc_state *old_state)
{
@@ -679,7 +709,6 @@ static void sde_crtc_atomic_begin(struct drm_crtc *crtc,
{
struct sde_crtc *sde_crtc;
struct drm_device *dev;
- unsigned long flags;
u32 i;
if (!crtc) {
@@ -701,14 +730,6 @@ static void sde_crtc_atomic_begin(struct drm_crtc *crtc,
if (!sde_crtc->num_mixers)
_sde_crtc_setup_mixers(crtc);
- if (sde_crtc->event) {
- WARN_ON(sde_crtc->event);
- } else {
- spin_lock_irqsave(&dev->event_lock, flags);
- sde_crtc->event = crtc->state->event;
- spin_unlock_irqrestore(&dev->event_lock, flags);
- }
-
/* Reset flush mask from previous commit */
for (i = 0; i < ARRAY_SIZE(sde_crtc->mixers); i++) {
struct sde_hw_ctl *ctl = sde_crtc->mixers[i].hw_ctl;
@@ -763,7 +784,8 @@ static void sde_crtc_atomic_flush(struct drm_crtc *crtc,
dev = crtc->dev;
if (sde_crtc->event) {
- SDE_DEBUG("already received sde_crtc->event\n");
+ SDE_ERROR("%s already received sde_crtc->event\n",
+ sde_crtc->name);
} else {
spin_lock_irqsave(&dev->event_lock, flags);
sde_crtc->event = crtc->state->event;
@@ -999,6 +1021,7 @@ static void sde_crtc_disable(struct drm_crtc *crtc)
if (encoder->crtc != crtc)
continue;
sde_encoder_register_frame_event_callback(encoder, NULL, NULL);
+ sde_encoder_register_request_flip_callback(encoder, NULL, NULL);
}
memset(sde_crtc->mixers, 0, sizeof(sde_crtc->mixers));
@@ -1039,6 +1062,8 @@ static void sde_crtc_enable(struct drm_crtc *crtc)
continue;
sde_encoder_register_frame_event_callback(encoder,
sde_crtc_frame_event_cb, (void *)crtc);
+ sde_encoder_register_request_flip_callback(encoder,
+ sde_crtc_request_flip_cb, (void *)crtc);
}
for (i = 0; i < sde_crtc->num_mixers; i++) {
diff --git a/drivers/gpu/drm/msm/sde/sde_crtc.h b/drivers/gpu/drm/msm/sde/sde_crtc.h
index 25a93e882e6d..97a20b987ef5 100644
--- a/drivers/gpu/drm/msm/sde/sde_crtc.h
+++ b/drivers/gpu/drm/msm/sde/sde_crtc.h
@@ -89,6 +89,7 @@ struct sde_crtc_frame_event {
* @frame_pending : Whether or not an update is pending
* @frame_events : static allocation of in-flight frame events
* @frame_event_list : available frame event list
+ * @pending : Whether any page-flip events are pending signal
* @spin_lock : spin lock for frame event, transaction status, etc...
*/
struct sde_crtc {
@@ -109,7 +110,7 @@ struct sde_crtc {
/* output fence support */
struct sde_fence output_fence;
-
+ atomic_t pending;
struct sde_hw_stage_cfg stage_cfg;
struct dentry *debugfs_root;
diff --git a/drivers/gpu/drm/msm/sde/sde_encoder.c b/drivers/gpu/drm/msm/sde/sde_encoder.c
index 8cffb03fdfbb..030b192e5df4 100644
--- a/drivers/gpu/drm/msm/sde/sde_encoder.c
+++ b/drivers/gpu/drm/msm/sde/sde_encoder.c
@@ -83,6 +83,8 @@
* Bit0 = phys_encs[0] etc.
* @crtc_frame_event_cb: callback handler for frame event
* @crtc_frame_event_cb_data: callback handler private data
+ * @crtc_request_flip_cb: callback handler for requesting page-flip event
+ * @crtc_request_flip_cb_data: callback handler private data
* @crtc_frame_event: callback event
* @frame_done_timeout: frame done timeout in Hz
* @frame_done_timer: watchdog timer for frame done event
@@ -107,8 +109,9 @@ struct sde_encoder_virt {
DECLARE_BITMAP(frame_busy_mask, MAX_PHYS_ENCODERS_PER_VIRTUAL);
void (*crtc_frame_event_cb)(void *, u32 event);
void *crtc_frame_event_cb_data;
+ void (*crtc_request_flip_cb)(void *);
+ void *crtc_request_flip_cb_data;
u32 crtc_frame_event;
-
atomic_t frame_done_timeout;
struct timer_list frame_done_timer;
};
@@ -584,6 +587,24 @@ void sde_encoder_register_frame_event_callback(struct drm_encoder *drm_enc,
spin_unlock_irqrestore(&sde_enc->enc_spinlock, lock_flags);
}
+void sde_encoder_register_request_flip_callback(struct drm_encoder *drm_enc,
+ void (*request_flip_cb)(void *),
+ void *request_flip_cb_data)
+{
+ struct sde_encoder_virt *sde_enc = to_sde_encoder_virt(drm_enc);
+ unsigned long lock_flags;
+
+ if (!drm_enc) {
+ SDE_ERROR("invalid encoder\n");
+ return;
+ }
+
+ spin_lock_irqsave(&sde_enc->enc_spinlock, lock_flags);
+ sde_enc->crtc_request_flip_cb = request_flip_cb;
+ sde_enc->crtc_request_flip_cb_data = request_flip_cb_data;
+ spin_unlock_irqrestore(&sde_enc->enc_spinlock, lock_flags);
+}
+
static void sde_encoder_frame_done_callback(
struct drm_encoder *drm_enc,
struct sde_encoder_phys *ready_phys, u32 event)
@@ -759,6 +780,11 @@ static void _sde_encoder_kickoff_phys(struct sde_encoder_virt *sde_enc)
pending_flush);
}
+ /* HW flush has happened, request a flip complete event now */
+ if (sde_enc->crtc_request_flip_cb)
+ sde_enc->crtc_request_flip_cb(
+ sde_enc->crtc_request_flip_cb_data);
+
_sde_encoder_trigger_start(sde_enc->cur_master);
spin_unlock_irqrestore(&sde_enc->enc_spinlock, lock_flags);
diff --git a/drivers/gpu/drm/msm/sde/sde_encoder.h b/drivers/gpu/drm/msm/sde/sde_encoder.h
index 82576b479bf8..6b74dca13ae9 100644
--- a/drivers/gpu/drm/msm/sde/sde_encoder.h
+++ b/drivers/gpu/drm/msm/sde/sde_encoder.h
@@ -72,6 +72,17 @@ void sde_encoder_register_frame_event_callback(struct drm_encoder *encoder,
void (*cb)(void *, u32), void *data);
/**
+ * sde_encoder_register_request_flip_callback - provide callback to encoder that
+ * will be called after HW flush is complete to request
+ * a page flip event from CRTC.
+ * @encoder: encoder pointer
+ * @cb: callback pointer, provide NULL to deregister
+ * @data: user data provided to callback
+ */
+void sde_encoder_register_request_flip_callback(struct drm_encoder *encoder,
+ void (*cb)(void *), void *data);
+
+/**
* sde_encoder_prepare_for_kickoff - schedule double buffer flip of the ctl
* path (i.e. ctl flush and start) at next appropriate time.
* Immediately: if no previous commit is outstanding.
diff --git a/drivers/gpu/drm/msm/sde_edid_parser.c b/drivers/gpu/drm/msm/sde_edid_parser.c
new file mode 100644
index 000000000000..69ab367307ea
--- /dev/null
+++ b/drivers/gpu/drm/msm/sde_edid_parser.c
@@ -0,0 +1,512 @@
+/* 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 <drm/drm_edid.h>
+
+#include "sde_kms.h"
+#include "sde_edid_parser.h"
+
+/* TODO: copy from drm_edid.c and mdss_hdmi_edid.c. remove if using ELD */
+#define DBC_START_OFFSET 4
+#define EDID_DTD_LEN 18
+
+enum data_block_types {
+ RESERVED,
+ AUDIO_DATA_BLOCK,
+ VIDEO_DATA_BLOCK,
+ VENDOR_SPECIFIC_DATA_BLOCK,
+ SPEAKER_ALLOCATION_DATA_BLOCK,
+ VESA_DTC_DATA_BLOCK,
+ RESERVED2,
+ USE_EXTENDED_TAG
+};
+
+static u8 *sde_find_edid_extension(struct edid *edid, int ext_id)
+{
+ u8 *edid_ext = NULL;
+ int i;
+
+ /* No EDID or EDID extensions */
+ if (edid == NULL || edid->extensions == 0)
+ return NULL;
+
+ /* Find CEA extension */
+ for (i = 0; i < edid->extensions; i++) {
+ edid_ext = (u8 *)edid + EDID_LENGTH * (i + 1);
+ if (edid_ext[0] == ext_id)
+ break;
+ }
+
+ if (i == edid->extensions)
+ return NULL;
+
+ return edid_ext;
+}
+
+static u8 *sde_find_cea_extension(struct edid *edid)
+{
+ return sde_find_edid_extension(edid, SDE_CEA_EXT);
+}
+
+static int
+sde_cea_db_payload_len(const u8 *db)
+{
+ return db[0] & 0x1f;
+}
+
+static int
+sde_cea_db_tag(const u8 *db)
+{
+ return db[0] >> 5;
+}
+
+static int
+sde_cea_revision(const u8 *cea)
+{
+ return cea[1];
+}
+
+static int
+sde_cea_db_offsets(const u8 *cea, int *start, int *end)
+{
+ /* Data block offset in CEA extension block */
+ *start = 4;
+ *end = cea[2];
+ if (*end == 0)
+ *end = 127;
+ if (*end < 4 || *end > 127)
+ return -ERANGE;
+ return 0;
+}
+
+#define sde_for_each_cea_db(cea, i, start, end) \
+for ((i) = (start); \
+(i) < (end) && (i) + sde_cea_db_payload_len(&(cea)[(i)]) < (end); \
+(i) += sde_cea_db_payload_len(&(cea)[(i)]) + 1)
+
+static u8 *sde_edid_find_extended_tag_block(struct edid *edid, int blk_id)
+{
+ u8 *db = NULL;
+ u8 *cea = NULL;
+
+ if (!edid) {
+ pr_err("%s: invalid input\n", __func__);
+ return NULL;
+ }
+
+ cea = sde_find_cea_extension(edid);
+
+ if (cea && sde_cea_revision(cea) >= 3) {
+ int i, start, end;
+
+ if (sde_cea_db_offsets(cea, &start, &end))
+ return NULL;
+
+ sde_for_each_cea_db(cea, i, start, end) {
+ db = &cea[i];
+ if ((sde_cea_db_tag(db) == SDE_EXTENDED_TAG) &&
+ (db[1] == blk_id))
+ return db;
+ }
+ }
+ return NULL;
+}
+
+static u8 *
+sde_edid_find_block(struct edid *edid, int blk_id)
+{
+ u8 *db = NULL;
+ u8 *cea = NULL;
+
+ if (!edid) {
+ pr_err("%s: invalid input\n", __func__);
+ return NULL;
+ }
+
+ cea = sde_find_cea_extension(edid);
+
+ if (cea && sde_cea_revision(cea) >= 3) {
+ int i, start, end;
+
+ if (sde_cea_db_offsets(cea, &start, &end))
+ return 0;
+
+ sde_for_each_cea_db(cea, i, start, end) {
+ db = &cea[i];
+ if (sde_cea_db_tag(db) == blk_id)
+ return db;
+ }
+ }
+ return NULL;
+}
+
+
+static const u8 *_sde_edid_find_block(const u8 *in_buf, u32 start_offset,
+ u8 type, u8 *len)
+{
+ /* the start of data block collection, start of Video Data Block */
+ u32 offset = start_offset;
+ u32 dbc_offset = in_buf[2];
+
+ SDE_EDID_DEBUG("%s +", __func__);
+ /*
+ * * edid buffer 1, byte 2 being 4 means no non-DTD/Data block
+ * collection present.
+ * * edid buffer 1, byte 2 being 0 means no non-DTD/DATA block
+ * collection present and no DTD data present.
+ */
+ if ((dbc_offset == 0) || (dbc_offset == 4)) {
+ SDE_ERROR("EDID: no DTD or non-DTD data present\n");
+ return NULL;
+ }
+
+ while (offset < dbc_offset) {
+ u8 block_len = in_buf[offset] & 0x1F;
+
+ if ((offset + block_len <= dbc_offset) &&
+ (in_buf[offset] >> 5) == type) {
+ *len = block_len;
+ SDE_EDID_DEBUG("block=%d found @ 0x%x w/ len=%d\n",
+ type, offset, block_len);
+
+ return in_buf + offset;
+ }
+ offset += 1 + block_len;
+ }
+
+ return NULL;
+}
+
+static void sde_edid_extract_vendor_id(struct sde_edid_ctrl *edid_ctrl)
+{
+ char *vendor_id;
+ u32 id_codes;
+
+ SDE_EDID_DEBUG("%s +", __func__);
+ if (!edid_ctrl) {
+ SDE_ERROR("%s: invalid input\n", __func__);
+ return;
+ }
+
+ vendor_id = edid_ctrl->vendor_id;
+ id_codes = ((u32)edid_ctrl->edid->mfg_id[0] << 8) +
+ edid_ctrl->edid->mfg_id[1];
+
+ vendor_id[0] = 'A' - 1 + ((id_codes >> 10) & 0x1F);
+ vendor_id[1] = 'A' - 1 + ((id_codes >> 5) & 0x1F);
+ vendor_id[2] = 'A' - 1 + (id_codes & 0x1F);
+ vendor_id[3] = 0;
+ SDE_EDID_DEBUG("vendor id is %s ", vendor_id);
+ SDE_EDID_DEBUG("%s -", __func__);
+}
+
+static void sde_edid_set_y420_support(struct drm_connector *connector,
+u32 video_format)
+{
+ u8 cea_mode = 0;
+ struct drm_display_mode *mode;
+
+ /* Need to add Y420 support flag to the modes */
+ list_for_each_entry(mode, &connector->probed_modes, head) {
+ cea_mode = drm_match_cea_mode(mode);
+ if ((cea_mode != 0) && (cea_mode == video_format)) {
+ SDE_EDID_DEBUG("%s found match for %d ", __func__,
+ video_format);
+ mode->flags |= DRM_MODE_FLAG_SUPPORTS_YUV;
+ }
+ }
+}
+
+static void sde_edid_parse_Y420CMDB(
+struct drm_connector *connector, struct sde_edid_ctrl *edid_ctrl,
+const u8 *db)
+{
+ u32 offset = 0;
+ u8 len = 0;
+ u8 svd_len = 0;
+ const u8 *svd = NULL;
+ u32 i = 0, j = 0;
+ u32 video_format = 0;
+
+ if (!edid_ctrl) {
+ DEV_ERR("%s: edid_ctrl is NULL\n", __func__);
+ return;
+ }
+
+ if (!db) {
+ DEV_ERR("%s: invalid input\n", __func__);
+ return;
+ }
+ SDE_EDID_DEBUG("%s +\n", __func__);
+ len = db[0] & 0x1f;
+
+ if (len < 7)
+ return;
+ /* Byte 3 to L+1 contain SVDs */
+ offset += 2;
+
+ svd = sde_edid_find_block(edid_ctrl->edid, VIDEO_DATA_BLOCK);
+
+ if (svd) {
+ /*moving to the next byte as vic info begins there*/
+ ++svd;
+ svd_len = svd[0] & 0x1f;
+ }
+
+ for (i = 0; i < svd_len; i++, j++) {
+ video_format = *svd & 0x7F;
+ if (db[offset] & (1 << j))
+ sde_edid_set_y420_support(connector, video_format);
+
+ if (j & 0x80) {
+ j = j/8;
+ offset++;
+ if (offset >= len)
+ break;
+ }
+ }
+
+ SDE_EDID_DEBUG("%s -\n", __func__);
+
+}
+
+static void sde_edid_parse_Y420VDB(
+struct drm_connector *connector, struct sde_edid_ctrl *edid_ctrl,
+const u8 *db)
+{
+ u8 len = db[0] & 0x1f;
+ u32 i = 0;
+ u32 video_format = 0;
+
+ if (!edid_ctrl) {
+ DEV_ERR("%s: invalid input\n", __func__);
+ return;
+ }
+
+ SDE_EDID_DEBUG("%s +\n", __func__);
+
+ /* Offset to byte 3 */
+ db += 2;
+ for (i = 0; i < len - 1; i++) {
+ video_format = *(db + i) & 0x7F;
+ /*
+ * mode was already added in get_modes()
+ * only need to set the Y420 support flag
+ */
+ sde_edid_set_y420_support(connector, video_format);
+ }
+ SDE_EDID_DEBUG("%s -", __func__);
+}
+
+static void sde_edid_set_mode_format(
+struct drm_connector *connector, struct sde_edid_ctrl *edid_ctrl)
+{
+ const u8 *db = NULL;
+ struct drm_display_mode *mode;
+
+ SDE_EDID_DEBUG("%s +\n", __func__);
+ /* Set YUV mode support flags for YCbcr420VDB */
+ db = sde_edid_find_extended_tag_block(edid_ctrl->edid,
+ Y420_VIDEO_DATA_BLOCK);
+ if (db)
+ sde_edid_parse_Y420VDB(connector, edid_ctrl, db);
+ else
+ SDE_EDID_DEBUG("YCbCr420 VDB is not present\n");
+
+ /* Set RGB supported on all modes where YUV is not set */
+ list_for_each_entry(mode, &connector->probed_modes, head) {
+ if (!(mode->flags & DRM_MODE_FLAG_SUPPORTS_YUV))
+ mode->flags |= DRM_MODE_FLAG_SUPPORTS_RGB;
+ }
+
+
+ db = sde_edid_find_extended_tag_block(edid_ctrl->edid,
+ Y420_CAPABILITY_MAP_DATA_BLOCK);
+ if (db)
+ sde_edid_parse_Y420CMDB(connector, edid_ctrl, db);
+ else
+ SDE_EDID_DEBUG("YCbCr420 CMDB is not present\n");
+
+ SDE_EDID_DEBUG("%s -\n", __func__);
+}
+
+static void _sde_edid_extract_audio_data_blocks(
+ struct sde_edid_ctrl *edid_ctrl)
+{
+ u8 len = 0;
+ u8 adb_max = 0;
+ const u8 *adb = NULL;
+ u32 offset = DBC_START_OFFSET;
+ u8 *cea = NULL;
+
+ if (!edid_ctrl) {
+ SDE_ERROR("invalid edid_ctrl\n");
+ return;
+ }
+ SDE_EDID_DEBUG("%s +", __func__);
+ cea = sde_find_cea_extension(edid_ctrl->edid);
+ if (!cea) {
+ SDE_DEBUG("CEA extension not found\n");
+ return;
+ }
+
+ edid_ctrl->adb_size = 0;
+
+ memset(edid_ctrl->audio_data_block, 0,
+ sizeof(edid_ctrl->audio_data_block));
+
+ do {
+ len = 0;
+ adb = _sde_edid_find_block(cea, offset, AUDIO_DATA_BLOCK,
+ &len);
+
+ if ((adb == NULL) || (len > MAX_AUDIO_DATA_BLOCK_SIZE ||
+ adb_max >= MAX_NUMBER_ADB)) {
+ if (!edid_ctrl->adb_size) {
+ SDE_DEBUG("No/Invalid Audio Data Block\n");
+ return;
+ }
+
+ continue;
+ }
+
+ memcpy(edid_ctrl->audio_data_block + edid_ctrl->adb_size,
+ adb + 1, len);
+ offset = (adb - cea) + 1 + len;
+
+ edid_ctrl->adb_size += len;
+ adb_max++;
+ } while (adb);
+ SDE_EDID_DEBUG("%s -", __func__);
+}
+
+static void _sde_edid_extract_speaker_allocation_data(
+ struct sde_edid_ctrl *edid_ctrl)
+{
+ u8 len;
+ const u8 *sadb = NULL;
+ u8 *cea = NULL;
+
+ if (!edid_ctrl) {
+ SDE_ERROR("invalid edid_ctrl\n");
+ return;
+ }
+ SDE_EDID_DEBUG("%s +", __func__);
+ cea = sde_find_cea_extension(edid_ctrl->edid);
+ if (!cea) {
+ SDE_DEBUG("CEA extension not found\n");
+ return;
+ }
+
+ sadb = _sde_edid_find_block(cea, DBC_START_OFFSET,
+ SPEAKER_ALLOCATION_DATA_BLOCK, &len);
+ if ((sadb == NULL) || (len != MAX_SPKR_ALLOC_DATA_BLOCK_SIZE)) {
+ SDE_DEBUG("No/Invalid Speaker Allocation Data Block\n");
+ return;
+ }
+
+ memcpy(edid_ctrl->spkr_alloc_data_block, sadb + 1, len);
+ edid_ctrl->sadb_size = len;
+
+ SDE_EDID_DEBUG("speaker alloc data SP byte = %08x %s%s%s%s%s%s%s\n",
+ sadb[1],
+ (sadb[1] & BIT(0)) ? "FL/FR," : "",
+ (sadb[1] & BIT(1)) ? "LFE," : "",
+ (sadb[1] & BIT(2)) ? "FC," : "",
+ (sadb[1] & BIT(3)) ? "RL/RR," : "",
+ (sadb[1] & BIT(4)) ? "RC," : "",
+ (sadb[1] & BIT(5)) ? "FLC/FRC," : "",
+ (sadb[1] & BIT(6)) ? "RLC/RRC," : "");
+ SDE_EDID_DEBUG("%s -", __func__);
+}
+
+struct sde_edid_ctrl *sde_edid_init(void)
+{
+ struct sde_edid_ctrl *edid_ctrl = NULL;
+
+ SDE_EDID_DEBUG("%s +\n", __func__);
+ edid_ctrl = kzalloc(sizeof(*edid_ctrl), GFP_KERNEL);
+ if (!edid_ctrl) {
+ SDE_ERROR("edid_ctrl alloc failed\n");
+ return NULL;
+ }
+ memset((edid_ctrl), 0, sizeof(*edid_ctrl));
+ SDE_EDID_DEBUG("%s -\n", __func__);
+ return edid_ctrl;
+}
+
+void sde_free_edid(void **input)
+{
+ struct sde_edid_ctrl *edid_ctrl = (struct sde_edid_ctrl *)(*input);
+
+ SDE_EDID_DEBUG("%s +", __func__);
+ kfree(edid_ctrl->edid);
+ edid_ctrl->edid = NULL;
+}
+
+void sde_edid_deinit(void **input)
+{
+ struct sde_edid_ctrl *edid_ctrl = (struct sde_edid_ctrl *)(*input);
+
+ SDE_EDID_DEBUG("%s +", __func__);
+ sde_free_edid((void *)&edid_ctrl);
+ kfree(edid_ctrl);
+ SDE_EDID_DEBUG("%s -", __func__);
+}
+
+int _sde_edid_update_modes(struct drm_connector *connector,
+ void *input)
+{
+ int rc = 0;
+ struct sde_edid_ctrl *edid_ctrl = (struct sde_edid_ctrl *)(input);
+
+ SDE_EDID_DEBUG("%s +", __func__);
+ if (edid_ctrl->edid) {
+ drm_mode_connector_update_edid_property(connector,
+ edid_ctrl->edid);
+
+ rc = drm_add_edid_modes(connector, edid_ctrl->edid);
+ sde_edid_set_mode_format(connector, edid_ctrl);
+ SDE_EDID_DEBUG("%s -", __func__);
+ return rc;
+ }
+
+ drm_mode_connector_update_edid_property(connector, NULL);
+ SDE_EDID_DEBUG("%s null edid -", __func__);
+ return rc;
+}
+
+bool sde_detect_hdmi_monitor(void *input)
+{
+ struct sde_edid_ctrl *edid_ctrl = (struct sde_edid_ctrl *)(input);
+
+ return drm_detect_hdmi_monitor(edid_ctrl->edid);
+}
+
+void sde_get_edid(struct drm_connector *connector,
+ struct i2c_adapter *adapter, void **input)
+{
+ struct sde_edid_ctrl *edid_ctrl = (struct sde_edid_ctrl *)(*input);
+
+ edid_ctrl->edid = drm_get_edid(connector, adapter);
+ SDE_EDID_DEBUG("%s +\n", __func__);
+
+ if (!edid_ctrl->edid)
+ SDE_ERROR("EDID read failed\n");
+
+ if (edid_ctrl->edid) {
+ sde_edid_extract_vendor_id(edid_ctrl);
+ _sde_edid_extract_audio_data_blocks(edid_ctrl);
+ _sde_edid_extract_speaker_allocation_data(edid_ctrl);
+ }
+ SDE_EDID_DEBUG("%s -\n", __func__);
+};
diff --git a/drivers/gpu/drm/msm/sde_edid_parser.h b/drivers/gpu/drm/msm/sde_edid_parser.h
new file mode 100644
index 000000000000..1143dc2c7bec
--- /dev/null
+++ b/drivers/gpu/drm/msm/sde_edid_parser.h
@@ -0,0 +1,148 @@
+/*
+ * 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.
+ *
+ */
+
+#ifndef _SDE_EDID_PARSER_H_
+#define _SDE_EDID_PARSER_H_
+
+#include <linux/types.h>
+#include <linux/bitops.h>
+#include <linux/debugfs.h>
+#include <linux/of_device.h>
+#include <linux/i2c.h>
+#include <drm/drmP.h>
+#include <drm/drm_crtc.h>
+#include <drm/drm_edid.h>
+
+
+#define MAX_NUMBER_ADB 5
+#define MAX_AUDIO_DATA_BLOCK_SIZE 30
+#define MAX_SPKR_ALLOC_DATA_BLOCK_SIZE 3
+#define EDID_VENDOR_ID_SIZE 4
+
+#define SDE_CEA_EXT 0x02
+#define SDE_EXTENDED_TAG 0x07
+
+enum extended_data_block_types {
+ VIDEO_CAPABILITY_DATA_BLOCK = 0x0,
+ VENDOR_SPECIFIC_VIDEO_DATA_BLOCK = 0x01,
+ HDMI_VIDEO_DATA_BLOCK = 0x04,
+ HDR_STATIC_METADATA_DATA_BLOCK = 0x06,
+ Y420_VIDEO_DATA_BLOCK = 0x0E,
+ VIDEO_FORMAT_PREFERENCE_DATA_BLOCK = 0x0D,
+ Y420_CAPABILITY_MAP_DATA_BLOCK = 0x0F,
+ VENDOR_SPECIFIC_AUDIO_DATA_BLOCK = 0x11,
+ INFOFRAME_DATA_BLOCK = 0x20,
+};
+
+#ifdef SDE_EDID_DEBUG_ENABLE
+#define SDE_EDID_DEBUG(fmt, args...) SDE_ERROR(fmt, ##args)
+#else
+#define SDE_EDID_DEBUG(fmt, args...) SDE_DEBUG(fmt, ##args)
+#endif
+
+/*
+ * struct hdmi_edid_hdr_data - HDR Static Metadata
+ * @eotf: Electro-Optical Transfer Function
+ * @metadata_type_one: Static Metadata Type 1 support
+ * @max_luminance: Desired Content Maximum Luminance
+ * @avg_luminance: Desired Content Frame-average Luminance
+ * @min_luminance: Desired Content Minimum Luminance
+ */
+struct sde_edid_hdr_data {
+ u32 eotf;
+ bool metadata_type_one;
+ u32 max_luminance;
+ u32 avg_luminance;
+ u32 min_luminance;
+};
+
+struct sde_edid_sink_caps {
+ u32 max_pclk_in_hz;
+ bool scdc_present;
+ bool scramble_support; /* scramble support for less than 340Mcsc */
+ bool read_req_support;
+ bool osd_disparity;
+ bool dual_view_support;
+ bool ind_view_support;
+};
+
+struct sde_edid_ctrl {
+ struct edid *edid;
+ u8 pt_scan_info;
+ u8 it_scan_info;
+ u8 ce_scan_info;
+ u8 audio_data_block[MAX_NUMBER_ADB * MAX_AUDIO_DATA_BLOCK_SIZE];
+ int adb_size;
+ u8 spkr_alloc_data_block[MAX_SPKR_ALLOC_DATA_BLOCK_SIZE];
+ int sadb_size;
+ bool hdr_supported;
+ char vendor_id[EDID_VENDOR_ID_SIZE];
+ struct sde_edid_sink_caps sink_caps;
+ struct sde_edid_hdr_data hdr_data;
+};
+
+/**
+ * sde_edid_init() - init edid structure.
+ * @edid_ctrl: Handle to the edid_ctrl structure.
+ * Return: handle to sde_edid_ctrl for the client.
+ */
+struct sde_edid_ctrl *sde_edid_init(void);
+
+/**
+ * sde_edid_deinit() - deinit edid structure.
+ * @edid_ctrl: Handle to the edid_ctrl structure.
+ *
+ * Return: void.
+ */
+void sde_edid_deinit(void **edid_ctrl);
+
+/**
+ * sde_get_edid() - get edid info.
+ * @connector: Handle to the drm_connector.
+ * @adapter: handle to i2c adapter for DDC read
+ * @edid_ctrl: Handle to the edid_ctrl structure.
+ *
+ * Return: void.
+ */
+void sde_get_edid(struct drm_connector *connector,
+struct i2c_adapter *adapter,
+void **edid_ctrl);
+
+/**
+ * sde_free_edid() - free edid structure.
+ * @edid_ctrl: Handle to the edid_ctrl structure.
+ *
+ * Return: void.
+ */
+void sde_free_edid(void **edid_ctrl);
+
+/**
+ * sde_detect_hdmi_monitor() - detect HDMI mode.
+ * @edid_ctrl: Handle to the edid_ctrl structure.
+ *
+ * Return: error code.
+ */
+bool sde_detect_hdmi_monitor(void *edid_ctrl);
+
+/**
+ * _sde_edid_update_modes() - populate EDID modes.
+ * @edid_ctrl: Handle to the edid_ctrl structure.
+ *
+ * Return: error code.
+ */
+int _sde_edid_update_modes(struct drm_connector *connector,
+ void *edid_ctrl);
+
+#endif /* _SDE_EDID_PARSER_H_ */
+
diff --git a/drivers/gpu/msm/kgsl.c b/drivers/gpu/msm/kgsl.c
index 1de8e212a703..986026aa1b66 100644
--- a/drivers/gpu/msm/kgsl.c
+++ b/drivers/gpu/msm/kgsl.c
@@ -260,9 +260,12 @@ kgsl_mem_entry_create(void)
{
struct kgsl_mem_entry *entry = kzalloc(sizeof(*entry), GFP_KERNEL);
- if (entry != NULL)
+ if (entry != NULL) {
kref_init(&entry->refcount);
+ /* put this ref in the caller functions after init */
+ kref_get(&entry->refcount);
+ }
return entry;
}
#ifdef CONFIG_DMA_SHARED_BUFFER
@@ -1764,9 +1767,9 @@ long kgsl_ioctl_drawctxt_create(struct kgsl_device_private *dev_priv,
/* Commit the pointer to the context in context_idr */
write_lock(&device->context_lock);
idr_replace(&device->context_idr, context, context->id);
+ param->drawctxt_id = context->id;
write_unlock(&device->context_lock);
- param->drawctxt_id = context->id;
done:
return result;
}
@@ -2399,6 +2402,9 @@ long kgsl_ioctl_gpuobj_import(struct kgsl_device_private *dev_priv,
trace_kgsl_mem_map(entry, fd);
kgsl_mem_entry_commit_process(entry);
+
+ /* put the extra refcount for kgsl_mem_entry_create() */
+ kgsl_mem_entry_put(entry);
return 0;
unmap:
@@ -2705,6 +2711,9 @@ long kgsl_ioctl_map_user_mem(struct kgsl_device_private *dev_priv,
trace_kgsl_mem_map(entry, param->fd);
kgsl_mem_entry_commit_process(entry);
+
+ /* put the extra refcount for kgsl_mem_entry_create() */
+ kgsl_mem_entry_put(entry);
return result;
error_attach:
@@ -3143,6 +3152,9 @@ long kgsl_ioctl_gpuobj_alloc(struct kgsl_device_private *dev_priv,
param->mmapsize = kgsl_memdesc_footprint(&entry->memdesc);
param->id = entry->id;
+ /* put the extra refcount for kgsl_mem_entry_create() */
+ kgsl_mem_entry_put(entry);
+
return 0;
}
@@ -3166,6 +3178,9 @@ long kgsl_ioctl_gpumem_alloc(struct kgsl_device_private *dev_priv,
param->size = (size_t) entry->memdesc.size;
param->flags = (unsigned int) entry->memdesc.flags;
+ /* put the extra refcount for kgsl_mem_entry_create() */
+ kgsl_mem_entry_put(entry);
+
return 0;
}
@@ -3189,6 +3204,9 @@ long kgsl_ioctl_gpumem_alloc_id(struct kgsl_device_private *dev_priv,
param->mmapsize = (size_t) kgsl_memdesc_footprint(&entry->memdesc);
param->gpuaddr = (unsigned long) entry->memdesc.gpuaddr;
+ /* put the extra refcount for kgsl_mem_entry_create() */
+ kgsl_mem_entry_put(entry);
+
return 0;
}
@@ -3306,6 +3324,9 @@ long kgsl_ioctl_sparse_phys_alloc(struct kgsl_device_private *dev_priv,
trace_sparse_phys_alloc(entry->id, param->size, param->pagesize);
kgsl_mem_entry_commit_process(entry);
+ /* put the extra refcount for kgsl_mem_entry_create() */
+ kgsl_mem_entry_put(entry);
+
return 0;
err_invalid_pages:
@@ -3385,6 +3406,9 @@ long kgsl_ioctl_sparse_virt_alloc(struct kgsl_device_private *dev_priv,
trace_sparse_virt_alloc(entry->id, param->size, param->pagesize);
kgsl_mem_entry_commit_process(entry);
+ /* put the extra refcount for kgsl_mem_entry_create() */
+ kgsl_mem_entry_put(entry);
+
return 0;
}
diff --git a/drivers/iio/adc/qcom-tadc.c b/drivers/iio/adc/qcom-tadc.c
index 054dfcc8556a..05b1985ba378 100644
--- a/drivers/iio/adc/qcom-tadc.c
+++ b/drivers/iio/adc/qcom-tadc.c
@@ -228,6 +228,7 @@ struct tadc_chip {
struct votable *tadc_disable_votable;
struct work_struct status_change_work;
struct notifier_block nb;
+ u8 hwtrig_conv;
};
struct tadc_pt {
@@ -356,6 +357,26 @@ unlock:
return rc;
}
+static int tadc_masked_write(struct tadc_chip *chip, u16 reg, u8 mask, u8 data)
+{
+ int rc = 0;
+
+ mutex_lock(&chip->write_lock);
+ if (tadc_is_reg_locked(chip, reg)) {
+ rc = regmap_write(chip->regmap, (reg & 0xFF00) | 0xD0, 0xA5);
+ if (rc < 0) {
+ pr_err("Couldn't unlock secure register rc=%d\n", rc);
+ goto unlock;
+ }
+ }
+
+ rc = regmap_update_bits(chip->regmap, reg, mask, data);
+
+unlock:
+ mutex_unlock(&chip->write_lock);
+ return rc;
+}
+
static int tadc_lerp(const struct tadc_pt *pts, size_t size, bool inv,
s32 input, s32 *output)
{
@@ -880,6 +901,12 @@ static int tadc_disable_vote_callback(struct votable *votable,
if (timeleft == 0)
pr_err("Timed out waiting for eoc, disabling hw conversions regardless\n");
+ rc = tadc_read(chip, TADC_HWTRIG_CONV_CH_EN_REG(chip),
+ &chip->hwtrig_conv, 1);
+ if (rc < 0) {
+ pr_err("Couldn't save hw conversions rc=%d\n", rc);
+ return rc;
+ }
rc = tadc_write(chip, TADC_HWTRIG_CONV_CH_EN_REG(chip), 0x00);
if (rc < 0) {
pr_err("Couldn't disable hw conversions rc=%d\n", rc);
@@ -896,9 +923,10 @@ static int tadc_disable_vote_callback(struct votable *votable,
pr_err("Couldn't disable direct test mode rc=%d\n", rc);
return rc;
}
- rc = tadc_write(chip, TADC_HWTRIG_CONV_CH_EN_REG(chip), 0x07);
+ rc = tadc_write(chip, TADC_HWTRIG_CONV_CH_EN_REG(chip),
+ chip->hwtrig_conv);
if (rc < 0) {
- pr_err("Couldn't enable hw conversions rc=%d\n", rc);
+ pr_err("Couldn't restore hw conversions rc=%d\n", rc);
return rc;
}
}
@@ -1126,16 +1154,23 @@ static int tadc_init_hw(struct tadc_chip *chip)
return rc;
}
- /* enable all temperature hardware triggers */
- rc = tadc_write(chip, TADC_HWTRIG_CONV_CH_EN_REG(chip),
- BIT(TADC_THERM1) |
- BIT(TADC_THERM2) |
- BIT(TADC_DIE_TEMP));
+ /* enable connector and die temp hardware triggers */
+ rc = tadc_masked_write(chip, TADC_HWTRIG_CONV_CH_EN_REG(chip),
+ BIT(TADC_THERM2) | BIT(TADC_DIE_TEMP),
+ BIT(TADC_THERM2) | BIT(TADC_DIE_TEMP));
if (rc < 0) {
pr_err("Couldn't enable hardware triggers rc=%d\n", rc);
return rc;
}
+ /* save hw triggered conversion configuration */
+ rc = tadc_read(chip, TADC_HWTRIG_CONV_CH_EN_REG(chip),
+ &chip->hwtrig_conv, 1);
+ if (rc < 0) {
+ pr_err("Couldn't save hw conversions rc=%d\n", rc);
+ return rc;
+ }
+
return 0;
}
diff --git a/drivers/input/misc/hbtp_input.c b/drivers/input/misc/hbtp_input.c
index 1df5d8812991..6d2e7a569044 100644
--- a/drivers/input/misc/hbtp_input.c
+++ b/drivers/input/misc/hbtp_input.c
@@ -1,5 +1,5 @@
-/* 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
@@ -47,6 +47,8 @@ struct hbtp_data {
struct input_dev *input_dev;
s32 count;
struct mutex mutex;
+ struct mutex sensormutex;
+ struct hbtp_sensor_data *sensor_data;
bool touch_status[HBTP_MAX_FINGER];
#if defined(CONFIG_FB)
struct notifier_block fb_notif;
@@ -87,10 +89,14 @@ struct hbtp_data {
u32 power_on_delay;
u32 power_off_delay;
bool manage_pin_ctrl;
+ s16 ROI[MAX_ROI_SIZE];
+ s16 accelBuffer[MAX_ACCEL_SIZE];
};
static struct hbtp_data *hbtp;
+static struct kobject *sensor_kobject;
+
#if defined(CONFIG_FB)
static int hbtp_fb_suspend(struct hbtp_data *ts);
static int hbtp_fb_early_resume(struct hbtp_data *ts);
@@ -150,6 +156,46 @@ static int fb_notifier_callback(struct notifier_block *self,
}
#endif
+static ssize_t hbtp_sensor_roi_show(struct file *dev, struct kobject *kobj,
+ struct bin_attribute *attr, char *buf, loff_t pos,
+ size_t size) {
+ mutex_lock(&hbtp->sensormutex);
+ memcpy(buf, hbtp->ROI, size);
+ mutex_unlock(&hbtp->sensormutex);
+
+ return size;
+}
+
+static ssize_t hbtp_sensor_vib_show(struct file *dev, struct kobject *kobj,
+ struct bin_attribute *attr, char *buf, loff_t pos,
+ size_t size) {
+ mutex_lock(&hbtp->sensormutex);
+ memcpy(buf, hbtp->accelBuffer, size);
+ mutex_unlock(&hbtp->sensormutex);
+
+ return size;
+}
+
+static struct bin_attribute capdata_attr = {
+ .attr = {
+ .name = "capdata",
+ .mode = S_IRUGO,
+ },
+ .size = 1024,
+ .read = hbtp_sensor_roi_show,
+ .write = NULL,
+};
+
+static struct bin_attribute vibdata_attr = {
+ .attr = {
+ .name = "vib_data",
+ .mode = S_IRUGO,
+ },
+ .size = MAX_ACCEL_SIZE*sizeof(int16_t),
+ .read = hbtp_sensor_vib_show,
+ .write = NULL,
+};
+
static int hbtp_input_open(struct inode *inode, struct file *file)
{
mutex_lock(&hbtp->mutex);
@@ -748,6 +794,22 @@ static long hbtp_input_ioctl_handler(struct file *file, unsigned int cmd,
return -EINVAL;
}
break;
+
+ case HBTP_SET_SENSORDATA:
+ if (copy_from_user(hbtp->sensor_data, (void *)arg,
+ sizeof(struct hbtp_sensor_data))) {
+ pr_err("%s: Error copying data\n", __func__);
+ return -EFAULT;
+ }
+ mutex_lock(&hbtp->sensormutex);
+ memcpy(hbtp->ROI, hbtp->sensor_data->ROI, sizeof(hbtp->ROI));
+ memcpy(hbtp->accelBuffer, hbtp->sensor_data->accelBuffer,
+ sizeof(hbtp->accelBuffer));
+ mutex_unlock(&hbtp->sensormutex);
+
+ error = 0;
+ break;
+
default:
pr_err("%s: Unsupported ioctl command %u\n", __func__, cmd);
error = -EINVAL;
@@ -1358,7 +1420,13 @@ static int __init hbtp_init(void)
if (!hbtp)
return -ENOMEM;
+ hbtp->sensor_data = kzalloc(sizeof(struct hbtp_sensor_data),
+ GFP_KERNEL);
+ if (!hbtp->sensor_data)
+ goto err_sensordata;
+
mutex_init(&hbtp->mutex);
+ mutex_init(&hbtp->sensormutex);
error = misc_register(&hbtp_input_misc);
if (error) {
@@ -1376,6 +1444,28 @@ static int __init hbtp_init(void)
}
#endif
+ sensor_kobject = kobject_create_and_add("hbtpsensor", kernel_kobj);
+ if (!sensor_kobject) {
+ pr_err("%s: Could not create hbtpsensor kobject\n", __func__);
+ goto err_kobject_create;
+ }
+
+ error = sysfs_create_bin_file(sensor_kobject, &capdata_attr);
+ if (error < 0) {
+ pr_err("%s: hbtp capdata sysfs creation failed: %d\n", __func__,
+ error);
+ goto err_sysfs_create_capdata;
+ }
+ pr_debug("capdata sysfs creation success\n");
+
+ error = sysfs_create_bin_file(sensor_kobject, &vibdata_attr);
+ if (error < 0) {
+ pr_err("%s: vibdata sysfs creation failed: %d\n", __func__,
+ error);
+ goto err_sysfs_create_vibdata;
+ }
+ pr_debug("vibdata sysfs creation success\n");
+
error = platform_driver_register(&hbtp_pdev_driver);
if (error) {
pr_err("Failed to register platform driver: %d\n", error);
@@ -1385,12 +1475,20 @@ static int __init hbtp_init(void)
return 0;
err_platform_drv_reg:
+ sysfs_remove_bin_file(sensor_kobject, &vibdata_attr);
+err_sysfs_create_vibdata:
+ sysfs_remove_bin_file(sensor_kobject, &capdata_attr);
+err_sysfs_create_capdata:
+ kobject_put(sensor_kobject);
+err_kobject_create:
#if defined(CONFIG_FB)
fb_unregister_client(&hbtp->fb_notif);
err_fb_reg:
#endif
misc_deregister(&hbtp_input_misc);
err_misc_reg:
+ kfree(hbtp->sensor_data);
+err_sensordata:
kfree(hbtp);
return error;
@@ -1398,6 +1496,9 @@ err_misc_reg:
static void __exit hbtp_exit(void)
{
+ sysfs_remove_bin_file(sensor_kobject, &vibdata_attr);
+ sysfs_remove_bin_file(sensor_kobject, &capdata_attr);
+ kobject_put(sensor_kobject);
misc_deregister(&hbtp_input_misc);
if (hbtp->input_dev)
input_unregister_device(hbtp->input_dev);
@@ -1408,6 +1509,7 @@ static void __exit hbtp_exit(void)
platform_driver_unregister(&hbtp_pdev_driver);
+ kfree(hbtp->sensor_data);
kfree(hbtp);
}
diff --git a/drivers/iommu/arm-smmu.c b/drivers/iommu/arm-smmu.c
index 51159711b1d8..25fe6c85a34e 100644
--- a/drivers/iommu/arm-smmu.c
+++ b/drivers/iommu/arm-smmu.c
@@ -3288,6 +3288,43 @@ static int arm_smmu_domain_set_attr(struct iommu_domain *domain,
1 << DOMAIN_ATTR_ENABLE_TTBR1;
ret = 0;
break;
+ case DOMAIN_ATTR_GEOMETRY: {
+ struct iommu_domain_geometry *geometry =
+ (struct iommu_domain_geometry *)data;
+
+ if (smmu_domain->smmu != NULL) {
+ dev_err(smmu_domain->smmu->dev,
+ "cannot set geometry attribute while attached\n");
+ ret = -EBUSY;
+ break;
+ }
+
+ if (geometry->aperture_start >= SZ_1G * 4ULL ||
+ geometry->aperture_end >= SZ_1G * 4ULL) {
+ pr_err("fastmap does not support IOVAs >= 4GB\n");
+ ret = -EINVAL;
+ break;
+ }
+ if (smmu_domain->attributes
+ & (1 << DOMAIN_ATTR_GEOMETRY)) {
+ if (geometry->aperture_start
+ < domain->geometry.aperture_start)
+ domain->geometry.aperture_start =
+ geometry->aperture_start;
+
+ if (geometry->aperture_end
+ > domain->geometry.aperture_end)
+ domain->geometry.aperture_end =
+ geometry->aperture_end;
+ } else {
+ smmu_domain->attributes |= 1 << DOMAIN_ATTR_GEOMETRY;
+ domain->geometry.aperture_start =
+ geometry->aperture_start;
+ domain->geometry.aperture_end = geometry->aperture_end;
+ }
+ ret = 0;
+ break;
+ }
default:
ret = -ENODEV;
break;
diff --git a/drivers/iommu/dma-mapping-fast.c b/drivers/iommu/dma-mapping-fast.c
index 8c6364f03eac..0881d68f34d8 100644
--- a/drivers/iommu/dma-mapping-fast.c
+++ b/drivers/iommu/dma-mapping-fast.c
@@ -188,7 +188,9 @@ static dma_addr_t __fast_smmu_alloc_iova(struct dma_fast_smmu_mapping *mapping,
iommu_tlbiall(mapping->domain);
mapping->have_stale_tlbs = false;
- av8l_fast_clear_stale_ptes(mapping->pgtbl_pmds, mapping->base,
+ av8l_fast_clear_stale_ptes(mapping->pgtbl_pmds,
+ mapping->domain->geometry.aperture_start,
+ mapping->base,
mapping->base + mapping->size - 1,
skip_sync);
}
@@ -367,7 +369,8 @@ static dma_addr_t fast_smmu_map_page(struct device *dev, struct page *page,
if (unlikely(iova == DMA_ERROR_CODE))
goto fail;
- pmd = iopte_pmd_offset(mapping->pgtbl_pmds, mapping->base, iova);
+ pmd = iopte_pmd_offset(mapping->pgtbl_pmds,
+ mapping->domain->geometry.aperture_start, iova);
if (unlikely(av8l_fast_map_public(pmd, phys_to_map, len, prot)))
goto fail_free_iova;
@@ -391,7 +394,8 @@ static void fast_smmu_unmap_page(struct device *dev, dma_addr_t iova,
struct dma_fast_smmu_mapping *mapping = dev->archdata.mapping->fast;
unsigned long flags;
av8l_fast_iopte *pmd = iopte_pmd_offset(mapping->pgtbl_pmds,
- mapping->base, iova);
+ mapping->domain->geometry.aperture_start,
+ iova);
unsigned long offset = iova & ~FAST_PAGE_MASK;
size_t len = ALIGN(size + offset, FAST_PAGE_SIZE);
int nptes = len >> FAST_PAGE_SHIFT;
@@ -414,7 +418,8 @@ static void fast_smmu_sync_single_for_cpu(struct device *dev,
{
struct dma_fast_smmu_mapping *mapping = dev->archdata.mapping->fast;
av8l_fast_iopte *pmd = iopte_pmd_offset(mapping->pgtbl_pmds,
- mapping->base, iova);
+ mapping->domain->geometry.aperture_start,
+ iova);
unsigned long offset = iova & ~FAST_PAGE_MASK;
struct page *page = phys_to_page((*pmd & FAST_PTE_ADDR_MASK));
@@ -427,7 +432,8 @@ static void fast_smmu_sync_single_for_device(struct device *dev,
{
struct dma_fast_smmu_mapping *mapping = dev->archdata.mapping->fast;
av8l_fast_iopte *pmd = iopte_pmd_offset(mapping->pgtbl_pmds,
- mapping->base, iova);
+ mapping->domain->geometry.aperture_start,
+ iova);
unsigned long offset = iova & ~FAST_PAGE_MASK;
struct page *page = phys_to_page((*pmd & FAST_PTE_ADDR_MASK));
@@ -555,8 +561,9 @@ static void *fast_smmu_alloc(struct device *dev, size_t size,
while (sg_miter_next(&miter)) {
int nptes = miter.length >> FAST_PAGE_SHIFT;
- ptep = iopte_pmd_offset(mapping->pgtbl_pmds, mapping->base,
- iova_iter);
+ ptep = iopte_pmd_offset(mapping->pgtbl_pmds,
+ mapping->domain->geometry.aperture_start,
+ iova_iter);
if (unlikely(av8l_fast_map_public(
ptep, page_to_phys(miter.page),
miter.length, prot))) {
@@ -584,7 +591,9 @@ static void *fast_smmu_alloc(struct device *dev, size_t size,
out_unmap:
/* need to take the lock again for page tables and iova */
spin_lock_irqsave(&mapping->lock, flags);
- ptep = iopte_pmd_offset(mapping->pgtbl_pmds, mapping->base, dma_addr);
+ ptep = iopte_pmd_offset(mapping->pgtbl_pmds,
+ mapping->domain->geometry.aperture_start,
+ dma_addr);
av8l_fast_unmap_public(ptep, size);
fast_dmac_clean_range(mapping, ptep, ptep + count);
out_free_iova:
@@ -616,7 +625,8 @@ static void fast_smmu_free(struct device *dev, size_t size,
pages = area->pages;
dma_common_free_remap(vaddr, size, VM_USERMAP, false);
- ptep = iopte_pmd_offset(mapping->pgtbl_pmds, mapping->base, dma_handle);
+ ptep = iopte_pmd_offset(mapping->pgtbl_pmds,
+ mapping->domain->geometry.aperture_start, dma_handle);
spin_lock_irqsave(&mapping->lock, flags);
av8l_fast_unmap_public(ptep, size);
fast_dmac_clean_range(mapping, ptep, ptep + count);
@@ -720,7 +730,7 @@ static const struct dma_map_ops fast_smmu_dma_ops = {
*
* Creates a mapping structure which holds information about used/unused IO
* address ranges, which is required to perform mapping with IOMMU aware
- * functions. The only VA range supported is [0, 4GB).
+ * functions. The only VA range supported is [0, 4GB].
*
* The client device need to be attached to the mapping with
* fast_smmu_attach_device function.
@@ -774,6 +784,7 @@ int fast_smmu_attach_device(struct device *dev,
struct iommu_domain *domain = mapping->domain;
struct iommu_pgtbl_info info;
u64 size = (u64)mapping->bits << PAGE_SHIFT;
+ struct iommu_domain_geometry geometry;
if (mapping->base + size > (SZ_1G * 4ULL))
return -EINVAL;
@@ -788,8 +799,11 @@ int fast_smmu_attach_device(struct device *dev,
mapping->fast->domain = domain;
mapping->fast->dev = dev;
- domain->geometry.aperture_start = mapping->base;
- domain->geometry.aperture_end = mapping->base + size - 1;
+ geometry.aperture_start = mapping->base;
+ geometry.aperture_end = mapping->base + size - 1;
+ if (iommu_domain_set_attr(domain, DOMAIN_ATTR_GEOMETRY,
+ &geometry))
+ return -EINVAL;
if (iommu_attach_device(domain, dev))
return -EINVAL;
diff --git a/drivers/iommu/io-pgtable-fast.c b/drivers/iommu/io-pgtable-fast.c
index 3582e206db68..5378e95c4627 100644
--- a/drivers/iommu/io-pgtable-fast.c
+++ b/drivers/iommu/io-pgtable-fast.c
@@ -133,6 +133,9 @@ struct av8l_fast_io_pgtable {
#define AV8L_FAST_TCR_EPD1_SHIFT 23
#define AV8L_FAST_TCR_EPD1_FAULT 1
+#define AV8L_FAST_TCR_SEP_SHIFT (15 + 32)
+#define AV8L_FAST_TCR_SEP_UPSTREAM 7ULL
+
#define AV8L_FAST_MAIR_ATTR_SHIFT(n) ((n) << 3)
#define AV8L_FAST_MAIR_ATTR_MASK 0xff
#define AV8L_FAST_MAIR_ATTR_DEVICE 0x04
@@ -173,12 +176,12 @@ static void __av8l_check_for_stale_tlb(av8l_fast_iopte *ptep)
}
void av8l_fast_clear_stale_ptes(av8l_fast_iopte *pmds, u64 base,
- u64 end, bool skip_sync)
+ u64 start, u64 end, bool skip_sync)
{
int i;
- av8l_fast_iopte *pmdp = pmds;
+ av8l_fast_iopte *pmdp = iopte_pmd_offset(pmds, base, start);
- for (i = base >> AV8L_FAST_PAGE_SHIFT;
+ for (i = start >> AV8L_FAST_PAGE_SHIFT;
i <= (end >> AV8L_FAST_PAGE_SHIFT); ++i) {
if (!(*pmdp & AV8L_FAST_PTE_VALID)) {
*pmdp = 0;
@@ -256,16 +259,17 @@ void av8l_fast_unmap_public(av8l_fast_iopte *ptep, size_t size)
__av8l_fast_unmap(ptep, size, true);
}
-/* upper layer must take care of TLB invalidation */
static size_t av8l_fast_unmap(struct io_pgtable_ops *ops, unsigned long iova,
size_t size)
{
struct av8l_fast_io_pgtable *data = iof_pgtable_ops_to_data(ops);
+ struct io_pgtable *iop = &data->iop;
av8l_fast_iopte *ptep = iopte_pmd_offset(data->pmds, data->base, iova);
unsigned long nptes = size >> AV8L_FAST_PAGE_SHIFT;
__av8l_fast_unmap(ptep, size, false);
dmac_clean_range(ptep, ptep + nptes);
+ iop->cfg.tlb->tlb_flush_all(iop->cookie);
return size;
}
@@ -522,6 +526,7 @@ av8l_fast_alloc_pgtable(struct io_pgtable_cfg *cfg, void *cookie)
#if defined(CONFIG_ARM)
reg |= ARM_32_LPAE_TCR_EAE;
#endif
+ reg |= AV8L_FAST_TCR_SEP_UPSTREAM << AV8L_FAST_TCR_SEP_SHIFT;
cfg->av8l_fast_cfg.tcr = reg;
/* MAIRs */
@@ -668,7 +673,7 @@ static int __init av8l_fast_positive_testing(void)
}
/* sweep up TLB proving PTEs */
- av8l_fast_clear_stale_ptes(pmds, base, max, false);
+ av8l_fast_clear_stale_ptes(pmds, base, base, max, false);
/* map the entire 4GB VA space with 8K map calls */
for (iova = base; iova < max; iova += SZ_8K) {
@@ -689,7 +694,7 @@ static int __init av8l_fast_positive_testing(void)
}
/* sweep up TLB proving PTEs */
- av8l_fast_clear_stale_ptes(pmds, base, max, false);
+ av8l_fast_clear_stale_ptes(pmds, base, base, max, false);
/* map the entire 4GB VA space with 16K map calls */
for (iova = base; iova < max; iova += SZ_16K) {
@@ -710,7 +715,7 @@ static int __init av8l_fast_positive_testing(void)
}
/* sweep up TLB proving PTEs */
- av8l_fast_clear_stale_ptes(pmds, base, max, false);
+ av8l_fast_clear_stale_ptes(pmds, base, base, max, false);
/* map the entire 4GB VA space with 64K map calls */
for (iova = base; iova < max; iova += SZ_64K) {
diff --git a/drivers/leds/leds-qpnp-flash-v2.c b/drivers/leds/leds-qpnp-flash-v2.c
index a8bf5b4b24c5..1a6cad946a25 100644
--- a/drivers/leds/leds-qpnp-flash-v2.c
+++ b/drivers/leds/leds-qpnp-flash-v2.c
@@ -127,11 +127,11 @@
#define FLASH_LED_LMH_MITIGATION_DISABLE 0
#define FLASH_LED_CHGR_MITIGATION_ENABLE BIT(4)
#define FLASH_LED_CHGR_MITIGATION_DISABLE 0
-#define FLASH_LED_MITIGATION_SEL_DEFAULT 2
+#define FLASH_LED_LMH_MITIGATION_SEL_DEFAULT 2
#define FLASH_LED_MITIGATION_SEL_MAX 2
#define FLASH_LED_CHGR_MITIGATION_SEL_SHIFT 4
-#define FLASH_LED_MITIGATION_THRSH_DEFAULT 0xA
-#define FLASH_LED_MITIGATION_THRSH_MAX 0x1F
+#define FLASH_LED_CHGR_MITIGATION_THRSH_DEFAULT 0xA
+#define FLASH_LED_CHGR_MITIGATION_THRSH_MAX 0x1F
#define FLASH_LED_LMH_OCV_THRESH_DEFAULT_UV 3700000
#define FLASH_LED_LMH_RBATT_THRESH_DEFAULT_UOHM 400000
#define FLASH_LED_IRES_BASE 3
@@ -152,12 +152,17 @@
#define FLASH_LED_MOD_ENABLE BIT(7)
#define FLASH_LED_DISABLE 0x00
#define FLASH_LED_SAFETY_TMR_DISABLED 0x13
-#define FLASH_LED_MIN_CURRENT_MA 25
#define FLASH_LED_MAX_TOTAL_CURRENT_MA 3750
/* notifier call chain for flash-led irqs */
static ATOMIC_NOTIFIER_HEAD(irq_notifier_list);
+enum flash_charger_mitigation {
+ FLASH_DISABLE_CHARGER_MITIGATION,
+ FLASH_HW_CHARGER_MITIGATION_BY_ILED_THRSHLD,
+ FLASH_SW_CHARGER_MITIGATION,
+};
+
enum flash_led_type {
FLASH_LED_TYPE_FLASH,
FLASH_LED_TYPE_TORCH,
@@ -175,15 +180,14 @@ enum {
struct flash_node_data {
struct platform_device *pdev;
struct led_classdev cdev;
- struct pinctrl *pinctrl;
- struct pinctrl_state *gpio_state_active;
- struct pinctrl_state *gpio_state_suspend;
+ struct pinctrl *strobe_pinctrl;
struct pinctrl_state *hw_strobe_state_active;
struct pinctrl_state *hw_strobe_state_suspend;
int hw_strobe_gpio;
int ires_ua;
int max_current;
int current_ma;
+ int prev_current_ma;
u8 duration;
u8 id;
u8 type;
@@ -198,6 +202,9 @@ struct flash_node_data {
struct flash_switch_data {
struct platform_device *pdev;
struct regulator *vreg;
+ struct pinctrl *led_en_pinctrl;
+ struct pinctrl_state *gpio_state_active;
+ struct pinctrl_state *gpio_state_suspend;
struct led_classdev cdev;
int led_mask;
bool regulator_on;
@@ -260,6 +267,7 @@ struct qpnp_flash_led {
int num_fnodes;
int num_snodes;
int enable;
+ int total_current_ma;
u16 base;
bool trigger_lmh;
bool trigger_chgr;
@@ -486,10 +494,12 @@ static int qpnp_flash_led_init_settings(struct qpnp_flash_led *led)
if (rc < 0)
return rc;
+ val = led->pdata->chgr_mitigation_sel
+ << FLASH_LED_CHGR_MITIGATION_SEL_SHIFT;
rc = qpnp_flash_led_masked_write(led,
FLASH_LED_REG_MITIGATION_SEL(led->base),
FLASH_LED_CHGR_MITIGATION_SEL_MASK,
- led->pdata->chgr_mitigation_sel);
+ val);
if (rc < 0)
return rc;
@@ -570,9 +580,9 @@ static int qpnp_flash_led_hw_strobe_enable(struct flash_node_data *fnode,
if (gpio_is_valid(fnode->hw_strobe_gpio)) {
gpio_set_value(fnode->hw_strobe_gpio, on ? 1 : 0);
- } else if (fnode->hw_strobe_state_active &&
+ } else if (fnode->strobe_pinctrl && fnode->hw_strobe_state_active &&
fnode->hw_strobe_state_suspend) {
- rc = pinctrl_select_state(fnode->pinctrl,
+ rc = pinctrl_select_state(fnode->strobe_pinctrl,
on ? fnode->hw_strobe_state_active :
fnode->hw_strobe_state_suspend);
if (rc < 0) {
@@ -875,14 +885,29 @@ static int qpnp_flash_led_get_max_avail_current(struct qpnp_flash_led *led)
return max_avail_current;
}
+static void qpnp_flash_led_aggregate_max_current(struct flash_node_data *fnode)
+{
+ struct qpnp_flash_led *led = dev_get_drvdata(&fnode->pdev->dev);
+
+ if (fnode->current_ma)
+ led->total_current_ma += fnode->current_ma
+ - fnode->prev_current_ma;
+ else
+ led->total_current_ma -= fnode->prev_current_ma;
+
+ fnode->prev_current_ma = fnode->current_ma;
+}
+
static void qpnp_flash_led_node_set(struct flash_node_data *fnode, int value)
{
int prgm_current_ma = value;
+ int min_ma = fnode->ires_ua / 1000;
+ struct qpnp_flash_led *led = dev_get_drvdata(&fnode->pdev->dev);
if (value <= 0)
prgm_current_ma = 0;
- else if (value < FLASH_LED_MIN_CURRENT_MA)
- prgm_current_ma = FLASH_LED_MIN_CURRENT_MA;
+ else if (value < min_ma)
+ prgm_current_ma = min_ma;
prgm_current_ma = min(prgm_current_ma, fnode->max_current);
fnode->current_ma = prgm_current_ma;
@@ -890,6 +915,13 @@ static void qpnp_flash_led_node_set(struct flash_node_data *fnode, int value)
fnode->current_reg_val = CURRENT_MA_TO_REG_VAL(prgm_current_ma,
fnode->ires_ua);
fnode->led_on = prgm_current_ma != 0;
+
+ if (led->pdata->chgr_mitigation_sel == FLASH_SW_CHARGER_MITIGATION) {
+ qpnp_flash_led_aggregate_max_current(fnode);
+ led->trigger_chgr = false;
+ if (led->total_current_ma >= 1000)
+ led->trigger_chgr = true;
+ }
}
static int qpnp_flash_led_switch_disable(struct flash_switch_data *snode)
@@ -948,15 +980,6 @@ static int qpnp_flash_led_switch_disable(struct flash_switch_data *snode)
led->fnode[i].led_on = false;
- if (led->fnode[i].pinctrl) {
- rc = pinctrl_select_state(led->fnode[i].pinctrl,
- led->fnode[i].gpio_state_suspend);
- if (rc < 0) {
- pr_err("failed to disable GPIO, rc=%d\n", rc);
- return rc;
- }
- }
-
if (led->fnode[i].trigger & FLASH_LED_HW_SW_STROBE_SEL_BIT) {
rc = qpnp_flash_led_hw_strobe_enable(&led->fnode[i],
led->pdata->hw_strobe_option, false);
@@ -968,6 +991,17 @@ static int qpnp_flash_led_switch_disable(struct flash_switch_data *snode)
}
}
+ if (snode->led_en_pinctrl) {
+ pr_debug("Selecting suspend state for %s\n", snode->cdev.name);
+ rc = pinctrl_select_state(snode->led_en_pinctrl,
+ snode->gpio_state_suspend);
+ if (rc < 0) {
+ pr_err("failed to select pinctrl suspend state rc=%d\n",
+ rc);
+ return rc;
+ }
+ }
+
snode->enabled = false;
return 0;
}
@@ -1038,15 +1072,6 @@ static int qpnp_flash_led_switch_set(struct flash_switch_data *snode, bool on)
val |= FLASH_LED_ENABLE << led->fnode[i].id;
- if (led->fnode[i].pinctrl) {
- rc = pinctrl_select_state(led->fnode[i].pinctrl,
- led->fnode[i].gpio_state_active);
- if (rc < 0) {
- pr_err("failed to enable GPIO rc=%d\n", rc);
- return rc;
- }
- }
-
if (led->fnode[i].trigger & FLASH_LED_HW_SW_STROBE_SEL_BIT) {
rc = qpnp_flash_led_hw_strobe_enable(&led->fnode[i],
led->pdata->hw_strobe_option, true);
@@ -1058,6 +1083,17 @@ static int qpnp_flash_led_switch_set(struct flash_switch_data *snode, bool on)
}
}
+ if (snode->led_en_pinctrl) {
+ pr_debug("Selecting active state for %s\n", snode->cdev.name);
+ rc = pinctrl_select_state(snode->led_en_pinctrl,
+ snode->gpio_state_active);
+ if (rc < 0) {
+ pr_err("failed to select pinctrl active state rc=%d\n",
+ rc);
+ return rc;
+ }
+ }
+
if (led->enable == 0) {
rc = qpnp_flash_led_masked_write(led,
FLASH_LED_REG_MOD_CTRL(led->base),
@@ -1153,10 +1189,6 @@ int qpnp_flash_led_prepare(struct led_trigger *trig, int options,
*max_current = rc;
}
- led->trigger_chgr = false;
- if (options & PRE_FLASH)
- led->trigger_chgr = true;
-
return 0;
}
@@ -1330,7 +1362,7 @@ static int qpnp_flash_led_parse_each_led_dt(struct qpnp_flash_led *led,
struct flash_node_data *fnode, struct device_node *node)
{
const char *temp_string;
- int rc;
+ int rc, min_ma;
u32 val;
bool strobe_sel = 0, edge_trigger = 0, active_high = 0;
@@ -1386,10 +1418,11 @@ static int qpnp_flash_led_parse_each_led_dt(struct qpnp_flash_led *led,
return rc;
}
+ min_ma = fnode->ires_ua / 1000;
rc = of_property_read_u32(node, "qcom,max-current", &val);
if (!rc) {
- if (val < FLASH_LED_MIN_CURRENT_MA)
- val = FLASH_LED_MIN_CURRENT_MA;
+ if (val < min_ma)
+ val = min_ma;
fnode->max_current = val;
fnode->cdev.max_brightness = val;
} else {
@@ -1399,11 +1432,10 @@ static int qpnp_flash_led_parse_each_led_dt(struct qpnp_flash_led *led,
rc = of_property_read_u32(node, "qcom,current-ma", &val);
if (!rc) {
- if (val < FLASH_LED_MIN_CURRENT_MA ||
- val > fnode->max_current)
+ if (val < min_ma || val > fnode->max_current)
pr_warn("Invalid operational current specified, capping it\n");
- if (val < FLASH_LED_MIN_CURRENT_MA)
- val = FLASH_LED_MIN_CURRENT_MA;
+ if (val < min_ma)
+ val = min_ma;
if (val > fnode->max_current)
val = fnode->max_current;
fnode->current_ma = val;
@@ -1460,6 +1492,20 @@ static int qpnp_flash_led_parse_each_led_dt(struct qpnp_flash_led *led,
}
fnode->trigger = (strobe_sel << 2) | (edge_trigger << 1) | active_high;
+ rc = led_classdev_register(&led->pdev->dev, &fnode->cdev);
+ if (rc < 0) {
+ pr_err("Unable to register led node %d\n", fnode->id);
+ return rc;
+ }
+
+ fnode->cdev.dev->of_node = node;
+ fnode->strobe_pinctrl = devm_pinctrl_get(fnode->cdev.dev);
+ if (IS_ERR_OR_NULL(fnode->strobe_pinctrl)) {
+ pr_debug("No pinctrl defined for %s, err=%ld\n",
+ fnode->cdev.name, PTR_ERR(fnode->strobe_pinctrl));
+ fnode->strobe_pinctrl = NULL;
+ }
+
if (fnode->trigger & FLASH_LED_HW_SW_STROBE_SEL_BIT) {
if (of_find_property(node, "qcom,hw-strobe-gpio", NULL)) {
fnode->hw_strobe_gpio = of_get_named_gpio(node,
@@ -1469,11 +1515,11 @@ static int qpnp_flash_led_parse_each_led_dt(struct qpnp_flash_led *led,
return fnode->hw_strobe_gpio;
}
gpio_direction_output(fnode->hw_strobe_gpio, 0);
- } else {
+ } else if (fnode->strobe_pinctrl) {
fnode->hw_strobe_gpio = -1;
fnode->hw_strobe_state_active =
- pinctrl_lookup_state(fnode->pinctrl,
- "strobe_enable");
+ pinctrl_lookup_state(fnode->strobe_pinctrl,
+ "strobe_enable");
if (IS_ERR_OR_NULL(fnode->hw_strobe_state_active)) {
pr_err("No active pin for hardware strobe, rc=%ld\n",
PTR_ERR(fnode->hw_strobe_state_active));
@@ -1481,8 +1527,8 @@ static int qpnp_flash_led_parse_each_led_dt(struct qpnp_flash_led *led,
}
fnode->hw_strobe_state_suspend =
- pinctrl_lookup_state(fnode->pinctrl,
- "strobe_disable");
+ pinctrl_lookup_state(fnode->strobe_pinctrl,
+ "strobe_disable");
if (IS_ERR_OR_NULL(fnode->hw_strobe_state_suspend)) {
pr_err("No suspend pin for hardware strobe, rc=%ld\n",
PTR_ERR(fnode->hw_strobe_state_suspend)
@@ -1492,38 +1538,6 @@ static int qpnp_flash_led_parse_each_led_dt(struct qpnp_flash_led *led,
}
}
- rc = led_classdev_register(&led->pdev->dev, &fnode->cdev);
- if (rc < 0) {
- pr_err("Unable to register led node %d\n", fnode->id);
- return rc;
- }
-
- fnode->cdev.dev->of_node = node;
-
- fnode->pinctrl = devm_pinctrl_get(fnode->cdev.dev);
- if (IS_ERR_OR_NULL(fnode->pinctrl)) {
- pr_debug("No pinctrl defined\n");
- fnode->pinctrl = NULL;
- } else {
- fnode->gpio_state_active =
- pinctrl_lookup_state(fnode->pinctrl, "led_enable");
- if (IS_ERR_OR_NULL(fnode->gpio_state_active)) {
- pr_err("Cannot lookup LED active state\n");
- devm_pinctrl_put(fnode->pinctrl);
- fnode->pinctrl = NULL;
- return PTR_ERR(fnode->gpio_state_active);
- }
-
- fnode->gpio_state_suspend =
- pinctrl_lookup_state(fnode->pinctrl, "led_disable");
- if (IS_ERR_OR_NULL(fnode->gpio_state_suspend)) {
- pr_err("Cannot lookup LED disable state\n");
- devm_pinctrl_put(fnode->pinctrl);
- fnode->pinctrl = NULL;
- return PTR_ERR(fnode->gpio_state_suspend);
- }
- }
-
return 0;
}
@@ -1588,6 +1602,36 @@ static int qpnp_flash_led_parse_and_register_switch(struct qpnp_flash_led *led,
}
snode->cdev.dev->of_node = node;
+
+ snode->led_en_pinctrl = devm_pinctrl_get(snode->cdev.dev);
+ if (IS_ERR_OR_NULL(snode->led_en_pinctrl)) {
+ pr_debug("No pinctrl defined for %s, err=%ld\n",
+ snode->cdev.name, PTR_ERR(snode->led_en_pinctrl));
+ snode->led_en_pinctrl = NULL;
+ }
+
+ if (snode->led_en_pinctrl) {
+ snode->gpio_state_active =
+ pinctrl_lookup_state(snode->led_en_pinctrl,
+ "led_enable");
+ if (IS_ERR_OR_NULL(snode->gpio_state_active)) {
+ pr_err("Cannot lookup LED active state\n");
+ devm_pinctrl_put(snode->led_en_pinctrl);
+ snode->led_en_pinctrl = NULL;
+ return PTR_ERR(snode->gpio_state_active);
+ }
+
+ snode->gpio_state_suspend =
+ pinctrl_lookup_state(snode->led_en_pinctrl,
+ "led_disable");
+ if (IS_ERR_OR_NULL(snode->gpio_state_suspend)) {
+ pr_err("Cannot lookup LED disable state\n");
+ devm_pinctrl_put(snode->led_en_pinctrl);
+ snode->led_en_pinctrl = NULL;
+ return PTR_ERR(snode->gpio_state_suspend);
+ }
+ }
+
return 0;
}
@@ -1939,7 +1983,7 @@ static int qpnp_flash_led_parse_common_dt(struct qpnp_flash_led *led,
return rc;
}
- led->pdata->lmh_mitigation_sel = FLASH_LED_MITIGATION_SEL_DEFAULT;
+ led->pdata->lmh_mitigation_sel = FLASH_LED_LMH_MITIGATION_SEL_DEFAULT;
rc = of_property_read_u32(node, "qcom,lmh-mitigation-sel", &val);
if (!rc) {
led->pdata->lmh_mitigation_sel = val;
@@ -1953,7 +1997,7 @@ static int qpnp_flash_led_parse_common_dt(struct qpnp_flash_led *led,
return -EINVAL;
}
- led->pdata->chgr_mitigation_sel = FLASH_LED_MITIGATION_SEL_DEFAULT;
+ led->pdata->chgr_mitigation_sel = FLASH_SW_CHARGER_MITIGATION;
rc = of_property_read_u32(node, "qcom,chgr-mitigation-sel", &val);
if (!rc) {
led->pdata->chgr_mitigation_sel = val;
@@ -1967,9 +2011,7 @@ static int qpnp_flash_led_parse_common_dt(struct qpnp_flash_led *led,
return -EINVAL;
}
- led->pdata->chgr_mitigation_sel <<= FLASH_LED_CHGR_MITIGATION_SEL_SHIFT;
-
- led->pdata->iled_thrsh_val = FLASH_LED_MITIGATION_THRSH_DEFAULT;
+ led->pdata->iled_thrsh_val = FLASH_LED_CHGR_MITIGATION_THRSH_DEFAULT;
rc = of_property_read_u32(node, "qcom,iled-thrsh-ma", &val);
if (!rc) {
led->pdata->iled_thrsh_val = MITIGATION_THRSH_MA_TO_VAL(val);
@@ -1978,7 +2020,7 @@ static int qpnp_flash_led_parse_common_dt(struct qpnp_flash_led *led,
return rc;
}
- if (led->pdata->iled_thrsh_val > FLASH_LED_MITIGATION_THRSH_MAX) {
+ if (led->pdata->iled_thrsh_val > FLASH_LED_CHGR_MITIGATION_THRSH_MAX) {
pr_err("Invalid iled_thrsh_val specified\n");
return -EINVAL;
}
diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp.h b/drivers/media/platform/msm/camera_v2/isp/msm_isp.h
index 139a4c9b49ee..b283f6277b87 100644
--- a/drivers/media/platform/msm/camera_v2/isp/msm_isp.h
+++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp.h
@@ -497,6 +497,7 @@ struct msm_vfe_src_info {
enum msm_vfe_dual_hw_type dual_hw_type;
struct msm_vfe_dual_hw_ms_info dual_hw_ms_info;
bool accept_frame;
+ uint32_t lpm;
};
struct msm_vfe_fetch_engine_info {
@@ -599,7 +600,7 @@ struct msm_vfe_tasklet_queue_cmd {
struct vfe_device *vfe_dev;
};
-#define MSM_VFE_TASKLETQ_SIZE 200
+#define MSM_VFE_TASKLETQ_SIZE 400
enum msm_vfe_overflow_state {
NO_OVERFLOW,
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 ebd3a32281d7..63e46125c292 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
@@ -773,6 +773,40 @@ void msm_isp_check_for_output_error(struct vfe_device *vfe_dev,
}
}
+static int msm_isp_check_sync_time(struct msm_vfe_src_info *src_info,
+ struct msm_isp_timestamp *ts,
+ struct master_slave_resource_info *ms_res)
+{
+ int i;
+ struct msm_vfe_src_info *master_src_info = NULL;
+ uint32_t master_time = 0, current_time;
+
+ if (!ms_res->src_sof_mask)
+ return 0;
+
+ for (i = 0; i < MAX_VFE * VFE_SRC_MAX; i++) {
+ if (ms_res->src_info[i] == NULL)
+ continue;
+ if (src_info == ms_res->src_info[i] ||
+ ms_res->src_info[i]->active == 0)
+ continue;
+ if (ms_res->src_sof_mask &
+ (1 << ms_res->src_info[i]->dual_hw_ms_info.index)) {
+ master_src_info = ms_res->src_info[i];
+ break;
+ }
+ }
+ if (!master_src_info)
+ return 0;
+ master_time = master_src_info->
+ dual_hw_ms_info.sof_info.mono_timestamp_ms;
+ current_time = ts->buf_time.tv_sec * 1000 +
+ ts->buf_time.tv_usec / 1000;
+ if ((current_time - master_time) > ms_res->sof_delta_threshold)
+ return 1;
+ return 0;
+}
+
static void msm_isp_sync_dual_cam_frame_id(
struct vfe_device *vfe_dev,
struct master_slave_resource_info *ms_res,
@@ -787,11 +821,24 @@ static void msm_isp_sync_dual_cam_frame_id(
if (src_info->dual_hw_ms_info.sync_state ==
ms_res->dual_sync_mode) {
- (frame_src == VFE_PIX_0) ? src_info->frame_id +=
+ if (msm_isp_check_sync_time(src_info, ts, ms_res) == 0) {
+ (frame_src == VFE_PIX_0) ? src_info->frame_id +=
vfe_dev->axi_data.src_info[frame_src].
sof_counter_step :
src_info->frame_id++;
- return;
+ return;
+ }
+ ms_res->src_sof_mask = 0;
+ ms_res->active_src_mask = 0;
+ for (i = 0; i < MAX_VFE * VFE_SRC_MAX; i++) {
+ if (ms_res->src_info[i] == NULL)
+ continue;
+ if (ms_res->src_info[i]->active == 0)
+ continue;
+ ms_res->src_info[i]->dual_hw_ms_info.
+ sync_state =
+ MSM_ISP_DUAL_CAM_ASYNC;
+ }
}
WARN_ON(ms_res->dual_sync_mode == MSM_ISP_DUAL_CAM_ASYNC);
@@ -948,8 +995,6 @@ static void msm_isp_update_pd_stats_idx(struct vfe_device *vfe_dev,
uint32_t pingpong_status = 0, pingpong_bit = 0;
struct msm_isp_buffer *done_buf = NULL;
int vfe_idx = -1;
- /* initialize pd_buf_idx with an invalid index 0xF */
- vfe_dev->pd_buf_idx = 0xF;
if (frame_src < VFE_RAW_0 || frame_src > VFE_RAW_2)
return;
@@ -2421,6 +2466,7 @@ int msm_isp_ab_ib_update_lpm_mode(struct vfe_device *vfe_dev, void *arg)
int i, rc = 0;
uint64_t total_bandwidth = 0;
int vfe_idx;
+ uint32_t intf;
unsigned long flags;
struct msm_vfe_axi_stream *stream_info;
struct msm_vfe_dual_lpm_mode *ab_ib_vote = NULL;
@@ -2436,7 +2482,13 @@ int msm_isp_ab_ib_update_lpm_mode(struct vfe_device *vfe_dev, void *arg)
stream_info =
msm_isp_get_stream_common_data(vfe_dev,
ab_ib_vote->stream_src[i]);
+ if (stream_info == NULL)
+ continue;
+ /* loop all stream on current session */
spin_lock_irqsave(&stream_info->lock, flags);
+ intf = SRC_TO_INTF(stream_info->stream_src);
+ vfe_dev->axi_data.src_info[intf].lpm =
+ ab_ib_vote->lpm_mode;
if (stream_info->state == ACTIVE) {
vfe_idx =
msm_isp_get_vfe_idx_for_stream(vfe_dev,
@@ -2457,7 +2509,12 @@ int msm_isp_ab_ib_update_lpm_mode(struct vfe_device *vfe_dev, void *arg)
stream_info =
msm_isp_get_stream_common_data(vfe_dev,
ab_ib_vote->stream_src[i]);
+ if (stream_info == NULL)
+ continue;
spin_lock_irqsave(&stream_info->lock, flags);
+ intf = SRC_TO_INTF(stream_info->stream_src);
+ vfe_dev->axi_data.src_info[intf].lpm =
+ ab_ib_vote->lpm_mode;
if (stream_info->state == PAUSED) {
vfe_idx =
msm_isp_get_vfe_idx_for_stream(vfe_dev,
@@ -2883,7 +2940,9 @@ static void __msm_isp_stop_axi_streams(struct vfe_device *vfe_dev,
* those state transitions instead of directly forcing stream to
* be INACTIVE
*/
- if (stream_info->state != PAUSED) {
+ intf = SRC_TO_INTF(stream_info->stream_src);
+ if ((!vfe_dev->axi_data.src_info[intf].lpm) ||
+ stream_info->state != PAUSED) {
while (stream_info->state != ACTIVE)
__msm_isp_axi_stream_update(stream_info,
&timestamp);
@@ -2900,10 +2959,12 @@ static void __msm_isp_stop_axi_streams(struct vfe_device *vfe_dev,
vfe_dev->hw_info->vfe_ops.axi_ops.
clear_wm_irq_mask(vfe_dev, stream_info);
}
- if (stream_info->state == ACTIVE) {
+ if (stream_info->state == ACTIVE &&
+ !vfe_dev->axi_data.src_info[intf].lpm) {
init_completion(&stream_info->inactive_comp);
stream_info->state = STOP_PENDING;
- } else if (stream_info->state == PAUSED) {
+ } else if (vfe_dev->axi_data.src_info[intf].lpm ||
+ stream_info->state == PAUSED) {
/* don't wait for reg update */
stream_info->state = STOP_PENDING;
msm_isp_axi_stream_enable_cfg(stream_info);
@@ -3018,6 +3079,7 @@ static int msm_isp_start_axi_stream(struct vfe_device *vfe_dev_ioctl,
int k;
struct vfe_device *vfe_dev;
struct msm_vfe_axi_shared_data *axi_data = &vfe_dev_ioctl->axi_data;
+ uint32_t intf;
if (stream_cfg_cmd->num_streams > MAX_NUM_STREAM)
return -EINVAL;
@@ -3081,7 +3143,7 @@ static int msm_isp_start_axi_stream(struct vfe_device *vfe_dev_ioctl,
cfg_wm_irq_mask(vfe_dev, stream_info);
}
}
-
+ intf = SRC_TO_INTF(stream_info->stream_src);
init_completion(&stream_info->active_comp);
stream_info->state = START_PENDING;
msm_isp_update_intf_stream_cnt(stream_info, 1);
@@ -3091,6 +3153,11 @@ static int msm_isp_start_axi_stream(struct vfe_device *vfe_dev_ioctl,
vfe_dev_ioctl->pdev->id);
if (src_state) {
src_mask |= (1 << SRC_TO_INTF(stream_info->stream_src));
+ if (vfe_dev_ioctl->axi_data.src_info[intf].lpm) {
+ while (stream_info->state != ACTIVE)
+ __msm_isp_axi_stream_update(
+ stream_info, &timestamp);
+ }
} else {
for (k = 0; k < stream_info->num_isp; k++) {
vfe_dev = stream_info->vfe_dev[k];
@@ -3365,22 +3432,21 @@ static int msm_isp_request_frame(struct vfe_device *vfe_dev,
/*
* If frame_id = 1 then no eof check is needed
*/
- if (vfe_dev->axi_data.src_info[VFE_PIX_0].active &&
- vfe_dev->axi_data.src_info[VFE_PIX_0].accept_frame == false) {
+ if (vfe_dev->axi_data.src_info[frame_src].active &&
+ frame_src == VFE_PIX_0 &&
+ vfe_dev->axi_data.src_info[frame_src].accept_frame == false) {
pr_debug("%s:%d invalid time to request frame %d\n",
__func__, __LINE__, frame_id);
goto error;
}
- if ((vfe_dev->axi_data.src_info[VFE_PIX_0].active && (frame_id !=
- vfe_dev->axi_data.src_info[VFE_PIX_0].frame_id + vfe_dev->
- axi_data.src_info[VFE_PIX_0].sof_counter_step)) ||
- ((!vfe_dev->axi_data.src_info[VFE_PIX_0].active) && (frame_id !=
+ if ((vfe_dev->axi_data.src_info[frame_src].active && (frame_id !=
vfe_dev->axi_data.src_info[frame_src].frame_id + vfe_dev->
- axi_data.src_info[frame_src].sof_counter_step))) {
+ axi_data.src_info[VFE_PIX_0].sof_counter_step)) ||
+ ((!vfe_dev->axi_data.src_info[frame_src].active))) {
pr_debug("%s:%d invalid frame id %d cur frame id %d pix %d\n",
__func__, __LINE__, frame_id,
- vfe_dev->axi_data.src_info[VFE_PIX_0].frame_id,
- vfe_dev->axi_data.src_info[VFE_PIX_0].active);
+ vfe_dev->axi_data.src_info[frame_src].frame_id,
+ vfe_dev->axi_data.src_info[frame_src].active);
goto error;
}
if (stream_info->undelivered_request_cnt >= MAX_BUFFERS_IN_HW) {
@@ -3887,6 +3953,12 @@ int msm_isp_update_axi_stream(struct vfe_device *vfe_dev, void *arg)
&update_cmd->req_frm_ver2;
stream_info = msm_isp_get_stream_common_data(vfe_dev,
HANDLE_TO_IDX(req_frm->stream_handle));
+ if (stream_info == NULL) {
+ pr_err_ratelimited("%s: stream_info is NULL\n",
+ __func__);
+ rc = -EINVAL;
+ break;
+ }
rc = msm_isp_request_frame(vfe_dev, stream_info,
req_frm->user_stream_id,
req_frm->frame_id,
diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp_axi_util.h b/drivers/media/platform/msm/camera_v2/isp/msm_isp_axi_util.h
index 65009cb22286..a8d4cfb43927 100644
--- a/drivers/media/platform/msm/camera_v2/isp/msm_isp_axi_util.h
+++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp_axi_util.h
@@ -141,6 +141,11 @@ static inline struct msm_vfe_axi_stream *msm_isp_get_stream_common_data(
struct msm_vfe_common_dev_data *common_data = vfe_dev->common_data;
struct msm_vfe_axi_stream *stream_info;
+ if (stream_idx >= VFE_AXI_SRC_MAX) {
+ pr_err("invalid stream_idx %d\n", stream_idx);
+ return NULL;
+ }
+
if (vfe_dev->is_split && stream_idx < RDI_INTF_0)
stream_info = &common_data->streams[stream_idx];
else
diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp_stats_util.c b/drivers/media/platform/msm/camera_v2/isp/msm_isp_stats_util.c
index f2cf4d477b3f..f92c67150215 100644
--- a/drivers/media/platform/msm/camera_v2/isp/msm_isp_stats_util.c
+++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp_stats_util.c
@@ -228,9 +228,10 @@ static int32_t msm_isp_stats_buf_divert(struct vfe_device *vfe_dev,
done_buf->buf_idx;
stats_event->pd_stats_idx = 0xF;
- if (stream_info->stats_type == MSM_ISP_STATS_BF)
+ if (stream_info->stats_type == MSM_ISP_STATS_BF) {
stats_event->pd_stats_idx = vfe_dev->pd_buf_idx;
-
+ vfe_dev->pd_buf_idx = 0xF;
+ }
if (comp_stats_type_mask == NULL) {
stats_event->stats_mask =
1 << stream_info->stats_type;
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 765bf6521759..2a9bb6e8e505 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
@@ -2070,6 +2070,7 @@ static void msm_isp_enqueue_tasklet_cmd(struct vfe_device *vfe_dev,
if (queue_cmd->cmd_used) {
pr_err("%s: Tasklet queue overflow: %d\n",
__func__, vfe_dev->pdev->id);
+ spin_unlock_irqrestore(&tasklet->tasklet_lock, flags);
return;
} else {
atomic_add(1, &vfe_dev->irq_cnt);
@@ -2314,6 +2315,9 @@ int msm_isp_open_node(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
vfe_dev->reg_update_requested = 0;
/* Register page fault handler */
vfe_dev->buf_mgr->pagefault_debug_disable = 0;
+ /* initialize pd_buf_idx with an invalid index 0xF */
+ vfe_dev->pd_buf_idx = 0xF;
+
cam_smmu_reg_client_page_fault_handler(
vfe_dev->buf_mgr->iommu_hdl,
msm_vfe_iommu_fault_handler, vfe_dev);
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 41d8ef577a27..caf6639f5151 100644
--- a/drivers/media/platform/msm/camera_v2/ispif/msm_ispif.c
+++ b/drivers/media/platform/msm/camera_v2/ispif/msm_ispif.c
@@ -49,17 +49,31 @@
#define ISPIF_TIMEOUT_ALL_US 1000000
#define ISPIF_SOF_DEBUG_COUNT 5
+/* 3D Threshold value according guidelines for line width 1280 */
+#define STEREO_DEFAULT_3D_THRESHOLD 0x36
+
+/*
+ * Overflows before restarting interface during stereo usecase
+ * to give some tolerance for cases when the two sensors sync fails
+ * this value is chosen by experiment
+ */
+#define MAX_PIX_OVERFLOW_ERROR_COUNT 10
+static int pix_overflow_error_count[VFE_MAX] = { 0 };
+
#undef CDBG
#ifdef CONFIG_MSMB_CAMERA_DEBUG
#define CDBG(fmt, args...) pr_debug(fmt, ##args)
#else
-#define CDBG(fmt, args...) do { } while (0)
+#define CDBG(fmt, args...)
#endif
static int msm_ispif_clk_ahb_enable(struct ispif_device *ispif, int enable);
static int ispif_close_node(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh);
static long msm_ispif_subdev_ioctl_unlocked(struct v4l2_subdev *sd,
unsigned int cmd, void *arg);
+static long msm_ispif_dispatch_cmd(enum ispif_cfg_type_t cmd,
+ struct ispif_device *ispif,
+ struct msm_ispif_param_data_ext *params);
int msm_ispif_get_clk_info(struct ispif_device *ispif_dev,
struct platform_device *pdev);
@@ -249,16 +263,7 @@ static long msm_ispif_cmd_ext(struct v4l2_subdev *sd,
}
mutex_lock(&ispif->mutex);
- switch (pcdata.cfg_type) {
- case ISPIF_CFG2:
- rc = msm_ispif_config2(ispif, params);
- msm_ispif_io_dump_reg(ispif);
- break;
- default:
- pr_err("%s: invalid cfg_type\n", __func__);
- rc = -EINVAL;
- break;
- }
+ rc = msm_ispif_dispatch_cmd(pcdata.cfg_type, ispif, params);
mutex_unlock(&ispif->mutex);
kfree(params);
return rc;
@@ -855,15 +860,34 @@ static uint16_t msm_ispif_get_cids_mask_from_cfg(
return cids_mask;
}
+
+static uint16_t msm_ispif_get_right_cids_mask_from_cfg(
+ struct msm_ispif_right_param_entry *entry, int num_cids)
+{
+ int i;
+ uint16_t cids_mask = 0;
+
+ if (WARN_ON(!entry))
+ return cids_mask;
+
+ for (i = 0; i < num_cids && i < MAX_CID_CH_PARAM_ENTRY; i++) {
+ if (entry->cids[i] < CID_MAX)
+ cids_mask |= (1 << entry->cids[i]);
+ }
+
+ return cids_mask;
+}
+
static int msm_ispif_config(struct ispif_device *ispif,
void *data)
{
int rc = 0, i = 0;
- uint16_t cid_mask;
+ uint16_t cid_mask = 0;
+ uint16_t cid_right_mask = 0;
enum msm_ispif_intftype intftype;
enum msm_ispif_vfe_intf vfe_intf;
- struct msm_ispif_param_data *params =
- (struct msm_ispif_param_data *)data;
+ struct msm_ispif_param_data_ext *params =
+ (struct msm_ispif_param_data_ext *)data;
BUG_ON(!ispif);
BUG_ON(!params);
@@ -913,9 +937,15 @@ static int msm_ispif_config(struct ispif_device *ispif,
return -EINVAL;
}
- if (ispif->csid_version >= CSID_VERSION_V30)
+ if (ispif->csid_version >= CSID_VERSION_V30) {
msm_ispif_select_clk_mux(ispif, intftype,
params->entries[i].csid, vfe_intf);
+ if (intftype == PIX0 && params->stereo_enable &&
+ params->right_entries[i].csid < CSID_MAX)
+ msm_ispif_select_clk_mux(ispif, PIX1,
+ params->right_entries[i].csid,
+ vfe_intf);
+ }
rc = msm_ispif_validate_intf_status(ispif, intftype, vfe_intf);
if (rc) {
@@ -926,10 +956,26 @@ static int msm_ispif_config(struct ispif_device *ispif,
msm_ispif_sel_csid_core(ispif, intftype,
params->entries[i].csid, vfe_intf);
+ if (intftype == PIX0 && params->stereo_enable &&
+ params->right_entries[i].csid < CSID_MAX)
+ /* configure right stereo csid */
+ msm_ispif_sel_csid_core(ispif, PIX1,
+ params->right_entries[i].csid, vfe_intf);
+
cid_mask = msm_ispif_get_cids_mask_from_cfg(
&params->entries[i]);
msm_ispif_enable_intf_cids(ispif, intftype,
cid_mask, vfe_intf, 1);
+ if (params->stereo_enable)
+ cid_right_mask = msm_ispif_get_right_cids_mask_from_cfg(
+ &params->right_entries[i],
+ params->entries[i].num_cids);
+ else
+ cid_right_mask = 0;
+ if (cid_right_mask && params->stereo_enable)
+ /* configure right stereo cids */
+ msm_ispif_enable_intf_cids(ispif, PIX1,
+ cid_right_mask, vfe_intf, 1);
if (params->entries[i].crop_enable)
msm_ispif_enable_crop(ispif, intftype, vfe_intf,
params->entries[i].crop_start_pixel,
@@ -962,8 +1008,28 @@ static int msm_ispif_config(struct ispif_device *ispif,
return rc;
}
+static void msm_ispif_config_stereo(struct ispif_device *ispif,
+ struct msm_ispif_param_data_ext *params) {
+
+ int i;
+ enum msm_ispif_vfe_intf vfe_intf;
+
+ for (i = 0; i < params->num; i++) {
+ if (params->entries[i].intftype == PIX0 &&
+ params->stereo_enable &&
+ params->right_entries[i].csid < CSID_MAX) {
+ vfe_intf = params->entries[i].vfe_intf;
+ msm_camera_io_w_mb(0x3,
+ ispif->base + ISPIF_VFE_m_OUTPUT_SEL(vfe_intf));
+ msm_camera_io_w_mb(STEREO_DEFAULT_3D_THRESHOLD,
+ ispif->base +
+ ISPIF_VFE_m_3D_THRESHOLD(vfe_intf));
+ }
+ }
+}
+
static void msm_ispif_intf_cmd(struct ispif_device *ispif, uint32_t cmd_bits,
- struct msm_ispif_param_data *params)
+ struct msm_ispif_param_data_ext *params)
{
uint8_t vc;
int i, k;
@@ -1008,6 +1074,19 @@ static void msm_ispif_intf_cmd(struct ispif_device *ispif, uint32_t cmd_bits,
ispif->applied_intf_cmd[vfe_intf].intf_cmd |=
(cmd_bits << (vc * 2 + intf_type * 8));
}
+ if (intf_type == PIX0 && params->stereo_enable &&
+ params->right_entries[i].cids[k] < CID_MAX) {
+ cid = params->right_entries[i].cids[k];
+ vc = cid / 4;
+
+ /* fill right stereo command */
+ /* zero 2 bits */
+ ispif->applied_intf_cmd[vfe_intf].intf_cmd &=
+ ~(0x3 << (vc * 2 + PIX1 * 8));
+ /* set cmd bits */
+ ispif->applied_intf_cmd[vfe_intf].intf_cmd |=
+ (cmd_bits << (vc * 2 + PIX1 * 8));
+ }
}
/* cmd for PIX0, PIX1, RDI0, RDI1 */
if (ispif->applied_intf_cmd[vfe_intf].intf_cmd != 0xFFFFFFFF)
@@ -1024,7 +1103,7 @@ static void msm_ispif_intf_cmd(struct ispif_device *ispif, uint32_t cmd_bits,
}
static int msm_ispif_stop_immediately(struct ispif_device *ispif,
- struct msm_ispif_param_data *params)
+ struct msm_ispif_param_data_ext *params)
{
int i, rc = 0;
uint16_t cid_mask = 0;
@@ -1052,13 +1131,22 @@ static int msm_ispif_stop_immediately(struct ispif_device *ispif,
&params->entries[i]);
msm_ispif_enable_intf_cids(ispif, params->entries[i].intftype,
cid_mask, params->entries[i].vfe_intf, 0);
+ if (params->stereo_enable) {
+ cid_mask = msm_ispif_get_right_cids_mask_from_cfg(
+ &params->right_entries[i],
+ params->entries[i].num_cids);
+ if (cid_mask)
+ msm_ispif_enable_intf_cids(ispif,
+ params->entries[i].intftype, cid_mask,
+ params->entries[i].vfe_intf, 0);
+ }
}
return rc;
}
static int msm_ispif_start_frame_boundary(struct ispif_device *ispif,
- struct msm_ispif_param_data *params)
+ struct msm_ispif_param_data_ext *params)
{
int rc = 0;
@@ -1074,13 +1162,14 @@ static int msm_ispif_start_frame_boundary(struct ispif_device *ispif,
rc = -EINVAL;
return rc;
}
+ msm_ispif_config_stereo(ispif, params);
msm_ispif_intf_cmd(ispif, ISPIF_INTF_CMD_ENABLE_FRAME_BOUNDARY, params);
return rc;
}
static int msm_ispif_restart_frame_boundary(struct ispif_device *ispif,
- struct msm_ispif_param_data *params)
+ struct msm_ispif_param_data_ext *params)
{
int rc = 0, i;
long timeout = 0;
@@ -1222,10 +1311,11 @@ end:
}
static int msm_ispif_stop_frame_boundary(struct ispif_device *ispif,
- struct msm_ispif_param_data *params)
+ struct msm_ispif_param_data_ext *params)
{
int i, rc = 0;
uint16_t cid_mask = 0;
+ uint16_t cid_right_mask = 0;
uint32_t intf_addr;
enum msm_ispif_vfe_intf vfe_intf;
uint32_t stop_flag = 0;
@@ -1263,6 +1353,13 @@ static int msm_ispif_stop_frame_boundary(struct ispif_device *ispif,
for (i = 0; i < params->num; i++) {
cid_mask =
msm_ispif_get_cids_mask_from_cfg(&params->entries[i]);
+ if (params->stereo_enable)
+ cid_right_mask =
+ msm_ispif_get_right_cids_mask_from_cfg(
+ &params->right_entries[i],
+ params->entries[i].num_cids);
+ else
+ cid_right_mask = 0;
vfe_intf = params->entries[i].vfe_intf;
switch (params->entries[i].intftype) {
@@ -1294,10 +1391,24 @@ static int msm_ispif_stop_frame_boundary(struct ispif_device *ispif,
ISPIF_TIMEOUT_ALL_US);
if (rc < 0)
goto end;
+ if (cid_right_mask) {
+ intf_addr = ISPIF_VFE_m_PIX_INTF_n_STATUS(vfe_intf, 1);
+ rc = readl_poll_timeout(ispif->base + intf_addr,
+ stop_flag,
+ (stop_flag & 0xF) == 0xF,
+ ISPIF_TIMEOUT_SLEEP_US,
+ ISPIF_TIMEOUT_ALL_US);
+ if (rc < 0)
+ goto end;
+ }
/* disable CIDs in CID_MASK register */
msm_ispif_enable_intf_cids(ispif, params->entries[i].intftype,
cid_mask, vfe_intf, 0);
+ if (cid_right_mask)
+ msm_ispif_enable_intf_cids(ispif,
+ params->entries[i].intftype, cid_right_mask,
+ params->entries[i].vfe_intf, 0);
}
end:
@@ -1318,6 +1429,14 @@ static void ispif_process_irq(struct ispif_device *ispif,
ispif->sof_count[vfe_id].sof_cnt[PIX0]++;
ispif->ispif_sof_debug++;
}
+ if (out[vfe_id].ispifIrqStatus1 &
+ ISPIF_IRQ_STATUS_PIX_SOF_MASK) {
+ if (ispif->ispif_sof_debug < ISPIF_SOF_DEBUG_COUNT*2)
+ pr_err("%s: PIX1 frame id: %u\n", __func__,
+ ispif->sof_count[vfe_id].sof_cnt[PIX1]);
+ ispif->sof_count[vfe_id].sof_cnt[PIX1]++;
+ ispif->ispif_sof_debug++;
+ }
if (out[vfe_id].ispifIrqStatus0 &
ISPIF_IRQ_STATUS_RDI0_SOF_MASK) {
if (ispif->ispif_rdi0_debug < ISPIF_SOF_DEBUG_COUNT)
@@ -1344,12 +1463,55 @@ static void ispif_process_irq(struct ispif_device *ispif,
}
}
+static int msm_ispif_reconfig_3d_output(struct ispif_device *ispif,
+ enum msm_ispif_vfe_intf vfe_id)
+{
+ uint32_t reg_data;
+
+ if (WARN_ON(!ispif))
+ return -EINVAL;
+
+ if (!((vfe_id == VFE0) || (vfe_id == VFE1))) {
+ pr_err("%s;%d Cannot reconfigure 3D mode for VFE%d", __func__,
+ __LINE__, vfe_id);
+ return -EINVAL;
+ }
+ pr_info("%s;%d Reconfiguring 3D mode for VFE%d", __func__, __LINE__,
+ vfe_id);
+ reg_data = 0xFFFCFFFC;
+ msm_camera_io_w_mb(reg_data, ispif->base +
+ ISPIF_VFE_m_INTF_CMD_0(vfe_id));
+ msm_camera_io_w_mb(reg_data, ispif->base +
+ ISPIF_IRQ_GLOBAL_CLEAR_CMD_ADDR);
+
+ if (vfe_id == VFE0) {
+ reg_data = 0;
+ reg_data |= (PIX_0_VFE_RST_STB | PIX_1_VFE_RST_STB |
+ STROBED_RST_EN | PIX_0_CSID_RST_STB |
+ PIX_1_CSID_RST_STB | PIX_OUTPUT_0_MISR_RST_STB);
+ msm_camera_io_w_mb(reg_data, ispif->base + ISPIF_RST_CMD_ADDR);
+ } else {
+ reg_data = 0;
+ reg_data |= (PIX_0_VFE_RST_STB | PIX_1_VFE_RST_STB |
+ STROBED_RST_EN | PIX_0_CSID_RST_STB |
+ PIX_1_CSID_RST_STB | PIX_OUTPUT_0_MISR_RST_STB);
+ msm_camera_io_w_mb(reg_data, ispif->base +
+ ISPIF_RST_CMD_1_ADDR);
+ }
+
+ reg_data = 0xFFFDFFFD;
+ msm_camera_io_w_mb(reg_data, ispif->base +
+ ISPIF_VFE_m_INTF_CMD_0(vfe_id));
+ return 0;
+}
+
static inline void msm_ispif_read_irq_status(struct ispif_irq_status *out,
void *data)
{
struct ispif_device *ispif = (struct ispif_device *)data;
bool fatal_err = false;
int i = 0;
+ uint32_t reg_data;
BUG_ON(!ispif);
BUG_ON(!out);
@@ -1400,6 +1562,12 @@ static inline void msm_ispif_read_irq_status(struct ispif_irq_status *out,
fatal_err = true;
}
+ if (out[VFE0].ispifIrqStatus1 & PIX_INTF_1_OVERFLOW_IRQ) {
+ pr_err_ratelimited("%s: VFE0 pix1 overflow.\n",
+ __func__);
+ fatal_err = true;
+ }
+
if (out[VFE0].ispifIrqStatus0 & RAW_INTF_0_OVERFLOW_IRQ) {
pr_err_ratelimited("%s: VFE0 rdi0 overflow.\n",
__func__);
@@ -1432,6 +1600,12 @@ static inline void msm_ispif_read_irq_status(struct ispif_irq_status *out,
fatal_err = true;
}
+ if (out[VFE1].ispifIrqStatus1 & PIX_INTF_1_OVERFLOW_IRQ) {
+ pr_err_ratelimited("%s: VFE1 pix1 overflow.\n",
+ __func__);
+ fatal_err = true;
+ }
+
if (out[VFE1].ispifIrqStatus0 & RAW_INTF_0_OVERFLOW_IRQ) {
pr_err_ratelimited("%s: VFE1 rdi0 overflow.\n",
__func__);
@@ -1453,6 +1627,43 @@ static inline void msm_ispif_read_irq_status(struct ispif_irq_status *out,
ispif_process_irq(ispif, out, VFE1);
}
+ if ((out[VFE0].ispifIrqStatus0 & PIX_INTF_0_OVERFLOW_IRQ) ||
+ (out[VFE0].ispifIrqStatus1 & PIX_INTF_0_OVERFLOW_IRQ) ||
+ (out[VFE0].ispifIrqStatus2 & (L_R_SOF_MISMATCH_ERR_IRQ |
+ L_R_EOF_MISMATCH_ERR_IRQ | L_R_SOL_MISMATCH_ERR_IRQ))) {
+ reg_data = msm_camera_io_r(ispif->base +
+ ISPIF_VFE_m_OUTPUT_SEL(VFE0));
+ if ((reg_data & 0x03) == VFE_PIX_INTF_SEL_3D) {
+ pix_overflow_error_count[VFE0]++;
+ if (pix_overflow_error_count[VFE0] >=
+ MAX_PIX_OVERFLOW_ERROR_COUNT) {
+ msm_ispif_reconfig_3d_output(ispif, VFE0);
+ pix_overflow_error_count[VFE0] = 0;
+ }
+ fatal_err = false;
+ }
+ }
+
+ if (ispif->vfe_info.num_vfe > 1) {
+ if ((out[VFE1].ispifIrqStatus0 & PIX_INTF_0_OVERFLOW_IRQ) ||
+ (out[VFE1].ispifIrqStatus1 & PIX_INTF_0_OVERFLOW_IRQ) ||
+ (out[VFE1].ispifIrqStatus2 & (L_R_SOF_MISMATCH_ERR_IRQ |
+ L_R_EOF_MISMATCH_ERR_IRQ | L_R_SOL_MISMATCH_ERR_IRQ))) {
+ reg_data = msm_camera_io_r(ispif->base +
+ ISPIF_VFE_m_OUTPUT_SEL(VFE1));
+ if ((reg_data & 0x03) == VFE_PIX_INTF_SEL_3D) {
+ pix_overflow_error_count[VFE1]++;
+ if (pix_overflow_error_count[VFE1] >=
+ MAX_PIX_OVERFLOW_ERROR_COUNT) {
+ msm_ispif_reconfig_3d_output(ispif,
+ VFE1);
+ pix_overflow_error_count[VFE1] = 0;
+ }
+ }
+ fatal_err = false;
+ }
+ }
+
if (fatal_err == true) {
pr_err_ratelimited("%s: fatal error, stop ispif immediately\n",
__func__);
@@ -1561,61 +1772,97 @@ static void msm_ispif_release(struct ispif_device *ispif)
pr_err("%s: failed to remove vote for AHB\n", __func__);
}
-static long msm_ispif_cmd(struct v4l2_subdev *sd, void *arg)
+static long msm_ispif_dispatch_cmd(enum ispif_cfg_type_t cmd,
+ struct ispif_device *ispif,
+ struct msm_ispif_param_data_ext *params)
{
long rc = 0;
- struct ispif_cfg_data *pcdata = (struct ispif_cfg_data *)arg;
- struct ispif_device *ispif =
- (struct ispif_device *)v4l2_get_subdevdata(sd);
-
- BUG_ON(!sd);
- BUG_ON(!pcdata);
- mutex_lock(&ispif->mutex);
- switch (pcdata->cfg_type) {
- case ISPIF_ENABLE_REG_DUMP:
- ispif->enb_dump_reg = pcdata->reg_dump; /* save dump config */
- break;
- case ISPIF_INIT:
- rc = msm_ispif_init(ispif, pcdata->csid_version);
- msm_ispif_io_dump_reg(ispif);
- break;
+ switch (cmd) {
case ISPIF_CFG:
- rc = msm_ispif_config(ispif, &pcdata->params);
+ rc = msm_ispif_config(ispif, params);
msm_ispif_io_dump_reg(ispif);
break;
case ISPIF_START_FRAME_BOUNDARY:
- rc = msm_ispif_start_frame_boundary(ispif, &pcdata->params);
+ rc = msm_ispif_start_frame_boundary(ispif, params);
msm_ispif_io_dump_reg(ispif);
break;
case ISPIF_RESTART_FRAME_BOUNDARY:
- rc = msm_ispif_restart_frame_boundary(ispif, &pcdata->params);
+ rc = msm_ispif_restart_frame_boundary(ispif, params);
msm_ispif_io_dump_reg(ispif);
break;
-
case ISPIF_STOP_FRAME_BOUNDARY:
- rc = msm_ispif_stop_frame_boundary(ispif, &pcdata->params);
+ rc = msm_ispif_stop_frame_boundary(ispif, params);
msm_ispif_io_dump_reg(ispif);
break;
case ISPIF_STOP_IMMEDIATELY:
- rc = msm_ispif_stop_immediately(ispif, &pcdata->params);
+ rc = msm_ispif_stop_immediately(ispif, params);
msm_ispif_io_dump_reg(ispif);
break;
case ISPIF_RELEASE:
msm_ispif_reset(ispif);
msm_ispif_reset_hw(ispif);
break;
- case ISPIF_SET_VFE_INFO:
- rc = msm_ispif_set_vfe_info(ispif, &pcdata->vfe_info);
+ case ISPIF_CFG2:
+ rc = msm_ispif_config2(ispif, params);
+ msm_ispif_io_dump_reg(ispif);
break;
default:
pr_err("%s: invalid cfg_type\n", __func__);
rc = -EINVAL;
break;
}
+ return rc;
+}
+
+static long msm_ispif_cmd(struct v4l2_subdev *sd, void *arg)
+{
+ long rc = 0;
+ struct ispif_cfg_data *pcdata = (struct ispif_cfg_data *)arg;
+ struct ispif_device *ispif =
+ (struct ispif_device *)v4l2_get_subdevdata(sd);
+ int i;
+ struct msm_ispif_param_data_ext params;
+
+ if (WARN_ON(!sd) || WARN_ON(!pcdata))
+ return -EINVAL;
+
+ mutex_lock(&ispif->mutex);
+ switch (pcdata->cfg_type) {
+ case ISPIF_ENABLE_REG_DUMP:
+ /* save dump config */
+ ispif->enb_dump_reg = pcdata->reg_dump;
+ break;
+ case ISPIF_INIT:
+ rc = msm_ispif_init(ispif, pcdata->csid_version);
+ msm_ispif_io_dump_reg(ispif);
+ break;
+ case ISPIF_SET_VFE_INFO:
+ rc = msm_ispif_set_vfe_info(ispif, &pcdata->vfe_info);
+ break;
+ default:
+ memset(&params, 0, sizeof(params));
+ if (pcdata->params.num > MAX_PARAM_ENTRIES) {
+ pr_err("%s: invalid num entries %u\n", __func__,
+ pcdata->params.num);
+ rc = -EINVAL;
+ } else {
+ params.num = pcdata->params.num;
+ for (i = 0; i < pcdata->params.num; i++)
+ memcpy(&params.entries[i],
+ &pcdata->params.entries[i],
+ sizeof(struct msm_ispif_params_entry));
+ params.stereo_enable = 0;
+ rc = msm_ispif_dispatch_cmd(pcdata->cfg_type, ispif,
+ &params);
+ }
+ break;
+ }
mutex_unlock(&ispif->mutex);
+
return rc;
}
+
static struct v4l2_file_operations msm_ispif_v4l2_subdev_fops;
static long msm_ispif_subdev_ioctl_unlocked(struct v4l2_subdev *sd,
diff --git a/drivers/media/platform/msm/camera_v2/ispif/msm_ispif_hwreg_v1.h b/drivers/media/platform/msm/camera_v2/ispif/msm_ispif_hwreg_v1.h
index d488ca618537..49d7d0f7624e 100644
--- a/drivers/media/platform/msm/camera_v2/ispif/msm_ispif_hwreg_v1.h
+++ b/drivers/media/platform/msm/camera_v2/ispif/msm_ispif_hwreg_v1.h
@@ -87,6 +87,12 @@
#define MISC_LOGIC_RST_STB BIT(1)
#define STROBED_RST_EN BIT(0)
+#define VFE_PIX_INTF_SEL_3D 0x3
+#define PIX_OUTPUT_0_MISR_RST_STB BIT(16)
+#define L_R_SOF_MISMATCH_ERR_IRQ BIT(16)
+#define L_R_EOF_MISMATCH_ERR_IRQ BIT(17)
+#define L_R_SOL_MISMATCH_ERR_IRQ BIT(18)
+
#define ISPIF_RST_CMD_MASK 0xFE1C77FF
#define ISPIF_RST_CMD_1_MASK 0xFFFFFFFF /* undefined */
diff --git a/drivers/media/platform/msm/camera_v2/ispif/msm_ispif_hwreg_v2.h b/drivers/media/platform/msm/camera_v2/ispif/msm_ispif_hwreg_v2.h
index 8ae61dc2d4f6..9abf55efc46c 100644
--- a/drivers/media/platform/msm/camera_v2/ispif/msm_ispif_hwreg_v2.h
+++ b/drivers/media/platform/msm/camera_v2/ispif/msm_ispif_hwreg_v2.h
@@ -22,6 +22,7 @@
#define ISPIF_VFE(m) ((m) * 0x200)
#define ISPIF_VFE_m_CTRL_0(m) (0x200 + ISPIF_VFE(m))
+#define ISPIF_VFE_m_CTRL_1(m) (0x204 + ISPIF_VFE(m))
#define ISPIF_VFE_m_IRQ_MASK_0(m) (0x208 + ISPIF_VFE(m))
#define ISPIF_VFE_m_IRQ_MASK_1(m) (0x20C + ISPIF_VFE(m))
#define ISPIF_VFE_m_IRQ_MASK_2(m) (0x210 + ISPIF_VFE(m))
@@ -71,6 +72,12 @@
#define MISC_LOGIC_RST_STB BIT(1)
#define STROBED_RST_EN BIT(0)
+#define VFE_PIX_INTF_SEL_3D 0x3
+#define PIX_OUTPUT_0_MISR_RST_STB BIT(16)
+#define L_R_SOF_MISMATCH_ERR_IRQ BIT(16)
+#define L_R_EOF_MISMATCH_ERR_IRQ BIT(17)
+#define L_R_SOL_MISMATCH_ERR_IRQ BIT(18)
+
#define ISPIF_RST_CMD_MASK 0xFE0F1FFF
#define ISPIF_RST_CMD_1_MASK 0xFC0F1FF9
@@ -78,6 +85,7 @@
#define ISPIF_RST_CMD_1_MASK_RESTART 0x00001FF9
#define PIX_INTF_0_OVERFLOW_IRQ BIT(12)
+#define PIX_INTF_1_OVERFLOW_IRQ BIT(12)
#define RAW_INTF_0_OVERFLOW_IRQ BIT(25)
#define RAW_INTF_1_OVERFLOW_IRQ BIT(25)
#define RAW_INTF_2_OVERFLOW_IRQ BIT(12)
diff --git a/drivers/media/platform/msm/camera_v2/ispif/msm_ispif_hwreg_v3.h b/drivers/media/platform/msm/camera_v2/ispif/msm_ispif_hwreg_v3.h
index 94cc974441ee..5f2aa06f3e13 100644
--- a/drivers/media/platform/msm/camera_v2/ispif/msm_ispif_hwreg_v3.h
+++ b/drivers/media/platform/msm/camera_v2/ispif/msm_ispif_hwreg_v3.h
@@ -74,6 +74,12 @@
#define MISC_LOGIC_RST_STB BIT(1)
#define STROBED_RST_EN BIT(0)
+#define VFE_PIX_INTF_SEL_3D 0x3
+#define PIX_OUTPUT_0_MISR_RST_STB BIT(16)
+#define L_R_SOF_MISMATCH_ERR_IRQ BIT(16)
+#define L_R_EOF_MISMATCH_ERR_IRQ BIT(17)
+#define L_R_SOL_MISMATCH_ERR_IRQ BIT(18)
+
#define ISPIF_RST_CMD_MASK 0xFE7F1FFF
#define ISPIF_RST_CMD_1_MASK 0xFC7F1FF9
@@ -81,6 +87,7 @@
#define ISPIF_RST_CMD_1_MASK_RESTART 0x7F1FF9
#define PIX_INTF_0_OVERFLOW_IRQ BIT(12)
+#define PIX_INTF_1_OVERFLOW_IRQ BIT(12)
#define RAW_INTF_0_OVERFLOW_IRQ BIT(25)
#define RAW_INTF_1_OVERFLOW_IRQ BIT(25)
#define RAW_INTF_2_OVERFLOW_IRQ BIT(12)
diff --git a/drivers/media/platform/msm/camera_v2/sensor/cci/msm_cci.c b/drivers/media/platform/msm/camera_v2/sensor/cci/msm_cci.c
index b067c4916341..0ff270bb8410 100644
--- a/drivers/media/platform/msm/camera_v2/sensor/cci/msm_cci.c
+++ b/drivers/media/platform/msm/camera_v2/sensor/cci/msm_cci.c
@@ -201,6 +201,7 @@ static int32_t msm_cci_validate_queue(struct cci_device *cci_dev,
enum cci_i2c_queue_t queue)
{
int32_t rc = 0;
+ unsigned long flags;
uint32_t read_val = 0;
uint32_t reg_offset = master * 0x200 + queue * 0x100;
read_val = msm_camera_io_r_mb(cci_dev->base +
@@ -223,6 +224,8 @@ static int32_t msm_cci_validate_queue(struct cci_device *cci_dev,
CCI_I2C_M0_Q0_EXEC_WORD_CNT_ADDR + reg_offset);
reg_val = 1 << ((master * 2) + queue);
CDBG("%s:%d CCI_QUEUE_START_ADDR\n", __func__, __LINE__);
+ spin_lock_irqsave(&cci_dev->cci_master_info[master].
+ lock_q[queue], flags);
atomic_set(&cci_dev->cci_master_info[master].
done_pending[queue], 1);
msm_camera_io_w_mb(reg_val, cci_dev->base +
@@ -230,6 +233,8 @@ static int32_t msm_cci_validate_queue(struct cci_device *cci_dev,
CDBG("%s line %d wait_for_completion_timeout\n",
__func__, __LINE__);
atomic_set(&cci_dev->cci_master_info[master].q_free[queue], 1);
+ spin_unlock_irqrestore(&cci_dev->cci_master_info[master].
+ lock_q[queue], flags);
rc = wait_for_completion_timeout(&cci_dev->
cci_master_info[master].report_q[queue], CCI_TIMEOUT);
if (rc <= 0) {
@@ -438,10 +443,17 @@ static int32_t msm_cci_wait_report_cmd(struct cci_device *cci_dev,
enum cci_i2c_master_t master,
enum cci_i2c_queue_t queue)
{
+ unsigned long flags;
uint32_t reg_val = 1 << ((master * 2) + queue);
msm_cci_load_report_cmd(cci_dev, master, queue);
+
+ spin_lock_irqsave(&cci_dev->cci_master_info[master].
+ lock_q[queue], flags);
atomic_set(&cci_dev->cci_master_info[master].q_free[queue], 1);
atomic_set(&cci_dev->cci_master_info[master].done_pending[queue], 1);
+ spin_unlock_irqrestore(&cci_dev->cci_master_info[master].
+ lock_q[queue], flags);
+
msm_camera_io_w_mb(reg_val, cci_dev->base +
CCI_QUEUE_START_ADDR);
return msm_cci_wait(cci_dev, master, queue);
@@ -451,13 +463,19 @@ static void msm_cci_process_half_q(struct cci_device *cci_dev,
enum cci_i2c_master_t master,
enum cci_i2c_queue_t queue)
{
+ unsigned long flags;
uint32_t reg_val = 1 << ((master * 2) + queue);
+
+ spin_lock_irqsave(&cci_dev->cci_master_info[master].
+ lock_q[queue], flags);
if (0 == atomic_read(&cci_dev->cci_master_info[master].q_free[queue])) {
msm_cci_load_report_cmd(cci_dev, master, queue);
atomic_set(&cci_dev->cci_master_info[master].q_free[queue], 1);
msm_camera_io_w_mb(reg_val, cci_dev->base +
CCI_QUEUE_START_ADDR);
}
+ spin_unlock_irqrestore(&cci_dev->cci_master_info[master].
+ lock_q[queue], flags);
}
static int32_t msm_cci_process_full_q(struct cci_device *cci_dev,
@@ -465,15 +483,23 @@ static int32_t msm_cci_process_full_q(struct cci_device *cci_dev,
enum cci_i2c_queue_t queue)
{
int32_t rc = 0;
+ unsigned long flags;
+
+ spin_lock_irqsave(&cci_dev->cci_master_info[master].
+ lock_q[queue], flags);
if (1 == atomic_read(&cci_dev->cci_master_info[master].q_free[queue])) {
atomic_set(&cci_dev->cci_master_info[master].
done_pending[queue], 1);
+ spin_unlock_irqrestore(&cci_dev->cci_master_info[master].
+ lock_q[queue], flags);
rc = msm_cci_wait(cci_dev, master, queue);
if (rc < 0) {
pr_err("%s: %d failed rc %d\n", __func__, __LINE__, rc);
return rc;
}
} else {
+ spin_unlock_irqrestore(&cci_dev->cci_master_info[master].
+ lock_q[queue], flags);
rc = msm_cci_wait_report_cmd(cci_dev, master, queue);
if (rc < 0) {
pr_err("%s: %d failed rc %d\n", __func__, __LINE__, rc);
@@ -501,8 +527,13 @@ static int32_t msm_cci_transfer_end(struct cci_device *cci_dev,
enum cci_i2c_queue_t queue)
{
int32_t rc = 0;
+ unsigned long flags;
+ spin_lock_irqsave(&cci_dev->cci_master_info[master].
+ lock_q[queue], flags);
if (0 == atomic_read(&cci_dev->cci_master_info[master].q_free[queue])) {
+ spin_unlock_irqrestore(&cci_dev->cci_master_info[master].
+ lock_q[queue], flags);
rc = msm_cci_lock_queue(cci_dev, master, queue, 0);
if (rc < 0) {
pr_err("%s failed line %d\n", __func__, __LINE__);
@@ -516,6 +547,8 @@ static int32_t msm_cci_transfer_end(struct cci_device *cci_dev,
} else {
atomic_set(&cci_dev->cci_master_info[master].
done_pending[queue], 1);
+ spin_unlock_irqrestore(&cci_dev->cci_master_info[master].
+ lock_q[queue], flags);
rc = msm_cci_wait(cci_dev, master, queue);
if (rc < 0) {
pr_err("%s: %d failed rc %d\n", __func__, __LINE__, rc);
@@ -570,6 +603,7 @@ static int32_t msm_cci_data_queue(struct cci_device *cci_dev,
uint32_t reg_offset;
uint32_t val = 0;
uint32_t max_queue_size;
+ unsigned long flags;
if (i2c_cmd == NULL) {
pr_err("%s:%d Failed line\n", __func__,
@@ -613,7 +647,11 @@ static int32_t msm_cci_data_queue(struct cci_device *cci_dev,
msm_camera_io_w_mb(val, cci_dev->base + CCI_I2C_M0_Q0_LOAD_DATA_ADDR +
reg_offset);
+ spin_lock_irqsave(&cci_dev->cci_master_info[master].
+ lock_q[queue], flags);
atomic_set(&cci_dev->cci_master_info[master].q_free[queue], 0);
+ spin_unlock_irqrestore(&cci_dev->cci_master_info[master].
+ lock_q[queue], flags);
max_queue_size = cci_dev->cci_i2c_queue_info[master][queue].
max_queue_size;
@@ -1641,6 +1679,7 @@ static int32_t msm_cci_config(struct v4l2_subdev *sd,
static irqreturn_t msm_cci_irq(int irq_num, void *data)
{
uint32_t irq;
+ unsigned long flags;
struct cci_device *cci_dev = data;
irq = msm_camera_io_r_mb(cci_dev->base + CCI_IRQ_STATUS_0_ADDR);
msm_camera_io_w_mb(irq, cci_dev->base + CCI_IRQ_CLEAR_0_ADDR);
@@ -1667,22 +1706,30 @@ static irqreturn_t msm_cci_irq(int irq_num, void *data)
if (irq & CCI_IRQ_STATUS_0_I2C_M0_Q0_REPORT_BMSK) {
struct msm_camera_cci_master_info *cci_master_info;
cci_master_info = &cci_dev->cci_master_info[MASTER_0];
+ spin_lock_irqsave(&cci_dev->cci_master_info[MASTER_0].
+ lock_q[QUEUE_0], flags);
atomic_set(&cci_master_info->q_free[QUEUE_0], 0);
cci_master_info->status = 0;
if (atomic_read(&cci_master_info->done_pending[QUEUE_0]) == 1) {
complete(&cci_master_info->report_q[QUEUE_0]);
atomic_set(&cci_master_info->done_pending[QUEUE_0], 0);
}
+ spin_unlock_irqrestore(&cci_dev->cci_master_info[MASTER_0].
+ lock_q[QUEUE_0], flags);
}
if (irq & CCI_IRQ_STATUS_0_I2C_M0_Q1_REPORT_BMSK) {
struct msm_camera_cci_master_info *cci_master_info;
cci_master_info = &cci_dev->cci_master_info[MASTER_0];
+ spin_lock_irqsave(&cci_dev->cci_master_info[MASTER_0].
+ lock_q[QUEUE_1], flags);
atomic_set(&cci_master_info->q_free[QUEUE_1], 0);
cci_master_info->status = 0;
if (atomic_read(&cci_master_info->done_pending[QUEUE_1]) == 1) {
complete(&cci_master_info->report_q[QUEUE_1]);
atomic_set(&cci_master_info->done_pending[QUEUE_1], 0);
}
+ spin_unlock_irqrestore(&cci_dev->cci_master_info[MASTER_0].
+ lock_q[QUEUE_1], flags);
}
if (irq & CCI_IRQ_STATUS_0_I2C_M1_RD_DONE_BMSK) {
cci_dev->cci_master_info[MASTER_1].status = 0;
@@ -1691,22 +1738,30 @@ static irqreturn_t msm_cci_irq(int irq_num, void *data)
if (irq & CCI_IRQ_STATUS_0_I2C_M1_Q0_REPORT_BMSK) {
struct msm_camera_cci_master_info *cci_master_info;
cci_master_info = &cci_dev->cci_master_info[MASTER_1];
+ spin_lock_irqsave(&cci_dev->cci_master_info[MASTER_1].
+ lock_q[QUEUE_0], flags);
atomic_set(&cci_master_info->q_free[QUEUE_0], 0);
cci_master_info->status = 0;
if (atomic_read(&cci_master_info->done_pending[QUEUE_0]) == 1) {
complete(&cci_master_info->report_q[QUEUE_0]);
atomic_set(&cci_master_info->done_pending[QUEUE_0], 0);
}
+ spin_unlock_irqrestore(&cci_dev->cci_master_info[MASTER_1].
+ lock_q[QUEUE_0], flags);
}
if (irq & CCI_IRQ_STATUS_0_I2C_M1_Q1_REPORT_BMSK) {
struct msm_camera_cci_master_info *cci_master_info;
cci_master_info = &cci_dev->cci_master_info[MASTER_1];
+ spin_lock_irqsave(&cci_dev->cci_master_info[MASTER_1].
+ lock_q[QUEUE_1], flags);
atomic_set(&cci_master_info->q_free[QUEUE_1], 0);
cci_master_info->status = 0;
if (atomic_read(&cci_master_info->done_pending[QUEUE_1]) == 1) {
complete(&cci_master_info->report_q[QUEUE_1]);
atomic_set(&cci_master_info->done_pending[QUEUE_1], 0);
}
+ spin_unlock_irqrestore(&cci_dev->cci_master_info[MASTER_1].
+ lock_q[QUEUE_1], flags);
}
if (irq & CCI_IRQ_STATUS_0_I2C_M0_Q0Q1_HALT_ACK_BMSK) {
cci_dev->cci_master_info[MASTER_0].reset_pending = TRUE;
@@ -1795,7 +1850,9 @@ static void msm_cci_init_cci_params(struct cci_device *new_cci_dev)
mutex_init(&new_cci_dev->cci_master_info[i].mutex_q[j]);
init_completion(&new_cci_dev->
cci_master_info[i].report_q[j]);
- }
+ spin_lock_init(&new_cci_dev->
+ cci_master_info[i].lock_q[j]);
+ }
}
return;
}
diff --git a/drivers/media/platform/msm/camera_v2/sensor/cci/msm_cci.h b/drivers/media/platform/msm/camera_v2/sensor/cci/msm_cci.h
index 6e39d814bd73..eb615cc7a62c 100644
--- a/drivers/media/platform/msm/camera_v2/sensor/cci/msm_cci.h
+++ b/drivers/media/platform/msm/camera_v2/sensor/cci/msm_cci.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
@@ -125,6 +125,7 @@ struct msm_camera_cci_master_info {
struct mutex mutex_q[NUM_QUEUES];
struct completion report_q[NUM_QUEUES];
atomic_t done_pending[NUM_QUEUES];
+ spinlock_t lock_q[NUM_QUEUES];
};
struct msm_cci_clk_params_t {
diff --git a/drivers/media/platform/msm/camera_v2/sensor/csid/msm_csid.c b/drivers/media/platform/msm/camera_v2/sensor/csid/msm_csid.c
index 55a743737c59..7ae071176ef4 100644
--- a/drivers/media/platform/msm/camera_v2/sensor/csid/msm_csid.c
+++ b/drivers/media/platform/msm/camera_v2/sensor/csid/msm_csid.c
@@ -227,16 +227,34 @@ static void msm_csid_set_sof_freeze_debug_reg(
static int msm_csid_reset(struct csid_device *csid_dev)
{
int32_t rc = 0;
+ uint32_t irq = 0, irq_bitshift;
+
+ irq_bitshift = csid_dev->ctrl_reg->csid_reg.csid_rst_done_irq_bitshift;
msm_camera_io_w(csid_dev->ctrl_reg->csid_reg.csid_rst_stb_all,
csid_dev->base +
csid_dev->ctrl_reg->csid_reg.csid_rst_cmd_addr);
rc = wait_for_completion_timeout(&csid_dev->reset_complete,
CSID_TIMEOUT);
- if (rc <= 0) {
+ if (rc < 0) {
pr_err("wait_for_completion in msm_csid_reset fail rc = %d\n",
rc);
+ } else if (rc == 0) {
+ irq = msm_camera_io_r(csid_dev->base +
+ csid_dev->ctrl_reg->csid_reg.csid_irq_status_addr);
+ pr_err_ratelimited("%s CSID%d_IRQ_STATUS_ADDR = 0x%x\n",
+ __func__, csid_dev->pdev->id, irq);
+ if (irq & (0x1 << irq_bitshift)) {
+ rc = 1;
+ CDBG("%s succeeded", __func__);
+ } else {
+ rc = 0;
+ pr_err("%s reset csid_irq_status failed = 0x%x\n",
+ __func__, irq);
+ }
if (rc == 0)
rc = -ETIMEDOUT;
+ } else {
+ CDBG("%s succeeded", __func__);
}
return rc;
}
diff --git a/drivers/media/platform/msm/camera_v2/sensor/msm_sensor.h b/drivers/media/platform/msm/camera_v2/sensor/msm_sensor.h
index 5d57ec8c28ff..8f55f453bf03 100644
--- a/drivers/media/platform/msm/camera_v2/sensor/msm_sensor.h
+++ b/drivers/media/platform/msm/camera_v2/sensor/msm_sensor.h
@@ -89,6 +89,7 @@ struct msm_sensor_ctrl_t {
uint32_t set_mclk_23880000;
uint8_t is_csid_tg_mode;
uint32_t is_secure;
+ uint8_t bypass_video_node_creation;
};
int msm_sensor_config(struct msm_sensor_ctrl_t *s_ctrl, void __user *argp);
diff --git a/drivers/media/platform/msm/camera_v2/sensor/msm_sensor_driver.c b/drivers/media/platform/msm/camera_v2/sensor/msm_sensor_driver.c
index 1dd2b0d26007..344f1a6f8d92 100644
--- a/drivers/media/platform/msm/camera_v2/sensor/msm_sensor_driver.c
+++ b/drivers/media/platform/msm/camera_v2/sensor/msm_sensor_driver.c
@@ -86,11 +86,14 @@ static int32_t msm_sensor_driver_create_i2c_v4l_subdev
struct i2c_client *client = s_ctrl->sensor_i2c_client->client;
CDBG("%s %s I2c probe succeeded\n", __func__, client->name);
- rc = camera_init_v4l2(&client->dev, &session_id);
- if (rc < 0) {
- pr_err("failed: camera_init_i2c_v4l2 rc %d", rc);
- return rc;
+ if (s_ctrl->bypass_video_node_creation == 0) {
+ rc = camera_init_v4l2(&client->dev, &session_id);
+ if (rc < 0) {
+ pr_err("failed: camera_init_i2c_v4l2 rc %d", rc);
+ return rc;
+ }
}
+
CDBG("%s rc %d session_id %d\n", __func__, rc, session_id);
snprintf(s_ctrl->msm_sd.sd.name,
sizeof(s_ctrl->msm_sd.sd.name), "%s",
@@ -123,11 +126,14 @@ static int32_t msm_sensor_driver_create_v4l_subdev
int32_t rc = 0;
uint32_t session_id = 0;
- rc = camera_init_v4l2(&s_ctrl->pdev->dev, &session_id);
- if (rc < 0) {
- pr_err("failed: camera_init_v4l2 rc %d", rc);
- return rc;
+ if (s_ctrl->bypass_video_node_creation == 0) {
+ rc = camera_init_v4l2(&s_ctrl->pdev->dev, &session_id);
+ if (rc < 0) {
+ pr_err("failed: camera_init_v4l2 rc %d", rc);
+ return rc;
+ }
}
+
CDBG("rc %d session_id %d", rc, session_id);
s_ctrl->sensordata->sensor_info->session_id = session_id;
@@ -773,6 +779,8 @@ int32_t msm_sensor_driver_probe(void *setting,
slave_info32->sensor_init_params;
slave_info->output_format =
slave_info32->output_format;
+ slave_info->bypass_video_node_creation =
+ !!slave_info32->bypass_video_node_creation;
kfree(slave_info32);
} else
#endif
@@ -800,7 +808,8 @@ int32_t msm_sensor_driver_probe(void *setting,
slave_info->sensor_init_params.position);
CDBG("mount %d",
slave_info->sensor_init_params.sensor_mount_angle);
-
+ CDBG("bypass video node creation %d",
+ slave_info->bypass_video_node_creation);
/* Validate camera id */
if (slave_info->camera_id >= MAX_CAMERAS) {
pr_err("failed: invalid camera id %d max %d",
@@ -980,6 +989,9 @@ CSID_TG:
*/
s_ctrl->is_probe_succeed = 1;
+ s_ctrl->bypass_video_node_creation =
+ slave_info->bypass_video_node_creation;
+
/*
* Create /dev/videoX node, comment for now until dummy /dev/videoX
* node is created and used by HAL
diff --git a/drivers/media/platform/msm/sde/rotator/sde_rotator_r3.c b/drivers/media/platform/msm/sde/rotator/sde_rotator_r3.c
index c3a0cfb390c4..34ec6529d8ae 100644
--- a/drivers/media/platform/msm/sde/rotator/sde_rotator_r3.c
+++ b/drivers/media/platform/msm/sde/rotator/sde_rotator_r3.c
@@ -1245,6 +1245,33 @@ static int sde_hw_rotator_swts_create(struct sde_hw_rotator *rot)
goto err_detach;
}
+ ion_free(rot->iclient, handle);
+
+ sde_smmu_ctrl(0);
+
+ return rc;
+err_detach:
+ dma_buf_detach(data->srcp_dma_buf, data->srcp_attachment);
+err_put:
+ dma_buf_put(data->srcp_dma_buf);
+ data->srcp_dma_buf = NULL;
+imap_err:
+ ion_free(rot->iclient, handle);
+
+ return rc;
+}
+
+/*
+ * sde_hw_rotator_swts_map - map software timestamp buffer
+ * @rot: Pointer to rotator hw
+ *
+ */
+static int sde_hw_rotator_swts_map(struct sde_hw_rotator *rot)
+{
+ int rc = 0;
+ struct sde_mdp_img_data *data = &rot->swts_buf;
+
+ sde_smmu_ctrl(1);
rc = sde_smmu_map_dma_buf(data->srcp_dma_buf, data->srcp_table,
SDE_IOMMU_DOMAIN_ROT_UNSECURE, &data->addr,
&data->len, DMA_BIDIRECTIONAL);
@@ -1264,35 +1291,25 @@ static int sde_hw_rotator_swts_create(struct sde_hw_rotator *rot)
data->mapped = true;
SDEROT_DBG("swts buffer mapped: %pad/%lx va:%p\n", &data->addr,
- data->len, rot->swts_buffer);
-
- ion_free(rot->iclient, handle);
-
+ data->len, rot->swts_buffer);
sde_smmu_ctrl(0);
-
return rc;
+
kmap_err:
sde_smmu_unmap_dma_buf(data->srcp_table, SDE_IOMMU_DOMAIN_ROT_UNSECURE,
DMA_FROM_DEVICE, data->srcp_dma_buf);
err_unmap:
dma_buf_unmap_attachment(data->srcp_attachment, data->srcp_table,
DMA_FROM_DEVICE);
-err_detach:
- dma_buf_detach(data->srcp_dma_buf, data->srcp_attachment);
-err_put:
- dma_buf_put(data->srcp_dma_buf);
- data->srcp_dma_buf = NULL;
-imap_err:
- ion_free(rot->iclient, handle);
return rc;
}
/*
- * sde_hw_rotator_swtc_destroy - destroy software timestamp buffer
+ * sde_hw_rotator_swtc_unmap - unmap software timestamp buffer
* @rot: Pointer to rotator hw
*/
-static void sde_hw_rotator_swtc_destroy(struct sde_hw_rotator *rot)
+static void sde_hw_rotator_swtc_unmap(struct sde_hw_rotator *rot)
{
struct sde_mdp_img_data *data;
@@ -1301,9 +1318,29 @@ static void sde_hw_rotator_swtc_destroy(struct sde_hw_rotator *rot)
dma_buf_end_cpu_access(data->srcp_dma_buf, 0, data->len,
DMA_FROM_DEVICE);
dma_buf_kunmap(data->srcp_dma_buf, 0, rot->swts_buffer);
+ rot->swts_buffer = NULL;
sde_smmu_unmap_dma_buf(data->srcp_table, SDE_IOMMU_DOMAIN_ROT_UNSECURE,
DMA_FROM_DEVICE, data->srcp_dma_buf);
+ data->addr = 0x0;
+ data->len = 0;
+
+ data->mapped = false;
+}
+
+/*
+ * sde_hw_rotator_swtc_destroy - destroy software timestamp buffer
+ * @rot: Pointer to rotator hw
+ */
+static void sde_hw_rotator_swtc_destroy(struct sde_hw_rotator *rot)
+{
+ struct sde_mdp_img_data *data;
+
+ data = &rot->swts_buf;
+
+ if (data->mapped)
+ sde_hw_rotator_swtc_unmap(rot);
+
dma_buf_unmap_attachment(data->srcp_attachment, data->srcp_table,
DMA_FROM_DEVICE);
dma_buf_detach(data->srcp_dma_buf, data->srcp_attachment);
@@ -1436,6 +1473,7 @@ static struct sde_rot_hw_resource *sde_hw_rotator_alloc_ext(
struct sde_rot_mgr *mgr, u32 pipe_id, u32 wb_id)
{
struct sde_hw_rotator_resource_info *resinfo;
+ int ret = 0;
if (!mgr || !mgr->hw_data) {
SDEROT_ERR("null parameters\n");
@@ -1463,8 +1501,21 @@ static struct sde_rot_hw_resource *sde_hw_rotator_alloc_ext(
else {
resinfo->hw.max_active = SDE_HW_ROT_REGDMA_TOTAL_CTX - 1;
- if (resinfo->rot->iclient == NULL)
- sde_hw_rotator_swts_create(resinfo->rot);
+ if (resinfo->rot->iclient == NULL) {
+ ret = sde_hw_rotator_swts_create(resinfo->rot);
+ if (ret) {
+ SDEROT_ERR("swts buffer create failed\n");
+ goto swts_fail;
+ }
+ }
+
+ if (resinfo->rot->swts_buf.mapped == false) {
+ ret = sde_hw_rotator_swts_map(resinfo->rot);
+ if (ret) {
+ SDEROT_ERR("swts buffer map failed\n");
+ goto swts_fail;
+ }
+ }
}
if (resinfo->rot->irq_num >= 0)
@@ -1474,6 +1525,10 @@ static struct sde_rot_hw_resource *sde_hw_rotator_alloc_ext(
resinfo, wb_id);
return &resinfo->hw;
+
+swts_fail:
+ devm_kfree(&mgr->pdev->dev, resinfo);
+ return NULL;
}
/*
@@ -1485,6 +1540,7 @@ static void sde_hw_rotator_free_ext(struct sde_rot_mgr *mgr,
struct sde_rot_hw_resource *hw)
{
struct sde_hw_rotator_resource_info *resinfo;
+ struct sde_rot_data_type *mdata = sde_rot_get_mdata();
if (!mgr || !mgr->hw_data)
return;
@@ -1499,6 +1555,18 @@ static void sde_hw_rotator_free_ext(struct sde_rot_mgr *mgr,
if (resinfo->rot->irq_num >= 0)
sde_hw_rotator_disable_irq(resinfo->rot);
+ /*
+ * For SDM660 and SDM630, the IOMMU is shared between MDP and rotator.
+ * If IOMMU is detached from MDP driver, the timestamp buffer will be
+ * invalidated. It is safer to unmap the timestamp buffer when the
+ * rotator session ends, so that it will be mapped again when a fresh
+ * session starts.
+ */
+ if (((mdata->mdss_version == MDSS_MDP_HW_REV_320) ||
+ (mdata->mdss_version == MDSS_MDP_HW_REV_330)) &&
+ resinfo->rot->swts_buf.mapped)
+ sde_hw_rotator_swtc_unmap(resinfo->rot);
+
devm_kfree(&mgr->pdev->dev, resinfo);
}
diff --git a/drivers/media/platform/msm/vidc/msm_v4l2_vidc.c b/drivers/media/platform/msm/vidc/msm_v4l2_vidc.c
index a63279715de6..a8dc1d010d62 100644
--- a/drivers/media/platform/msm/vidc/msm_v4l2_vidc.c
+++ b/drivers/media/platform/msm/vidc/msm_v4l2_vidc.c
@@ -766,6 +766,8 @@ static int __init msm_vidc_init(void)
if (rc) {
dprintk(VIDC_ERR,
"Failed to register platform driver\n");
+ msm_vidc_debugfs_deinit_drv();
+ debugfs_remove_recursive(vidc_driver->debugfs_root);
kfree(vidc_driver);
vidc_driver = NULL;
}
@@ -776,6 +778,7 @@ static int __init msm_vidc_init(void)
static void __exit msm_vidc_exit(void)
{
platform_driver_unregister(&msm_vidc_driver);
+ msm_vidc_debugfs_deinit_drv();
debugfs_remove_recursive(vidc_driver->debugfs_root);
mutex_destroy(&vidc_driver->lock);
kfree(vidc_driver);
diff --git a/drivers/media/platform/msm/vidc/msm_vdec.c b/drivers/media/platform/msm/vidc/msm_vdec.c
index 24eb8fff905b..953780e3c220 100644
--- a/drivers/media/platform/msm/vidc/msm_vdec.c
+++ b/drivers/media/platform/msm/vidc/msm_vdec.c
@@ -2587,6 +2587,12 @@ static int try_set_ext_ctrl(struct msm_vidc_inst *inst,
int rc = 0, i = 0, fourcc = 0;
struct v4l2_ext_control *ext_control;
struct v4l2_control control;
+ u32 old_mode = 0;
+ bool mode_changed = false;
+ enum mode {
+ PRIMARY = V4L2_CID_MPEG_VIDC_VIDEO_STREAM_OUTPUT_PRIMARY,
+ SECONDARY = V4L2_CID_MPEG_VIDC_VIDEO_STREAM_OUTPUT_SECONDARY
+ };
if (!inst || !inst->core || !ctrl) {
dprintk(VIDC_ERR,
@@ -2595,19 +2601,21 @@ static int try_set_ext_ctrl(struct msm_vidc_inst *inst,
}
ext_control = ctrl->controls;
- control.id =
- V4L2_CID_MPEG_VIDC_VIDEO_STREAM_OUTPUT_MODE;
+ control.id = V4L2_CID_MPEG_VIDC_VIDEO_STREAM_OUTPUT_MODE;
+ old_mode = msm_comm_g_ctrl_for_id(inst, control.id);
for (i = 0; i < ctrl->count; i++) {
switch (ext_control[i].id) {
case V4L2_CID_MPEG_VIDC_VIDEO_STREAM_OUTPUT_MODE:
control.value = ext_control[i].value;
-
rc = msm_comm_s_ctrl(inst, &control);
if (rc)
dprintk(VIDC_ERR,
"%s Failed setting stream output mode : %d\n",
__func__, rc);
+
+ if (old_mode == SECONDARY && control.value == PRIMARY)
+ mode_changed = true;
break;
case V4L2_CID_MPEG_VIDC_VIDEO_DPB_COLOR_FORMAT:
switch (ext_control[i].value) {
@@ -2620,6 +2628,24 @@ static int try_set_ext_ctrl(struct msm_vidc_inst *inst,
"%s Release output buffers failed\n",
__func__);
}
+ /* Update buffer reqmt for split to comb mode */
+ if (mode_changed) {
+ fourcc =
+ inst->fmts[CAPTURE_PORT].fourcc;
+ msm_comm_set_color_format(inst,
+ HAL_BUFFER_OUTPUT, fourcc);
+ if (rc) {
+ dprintk(VIDC_ERR,
+ "%s Failed setting output color format : %d\n",
+ __func__, rc);
+ break;
+ }
+ rc = msm_comm_try_get_bufreqs(inst);
+ if (rc)
+ dprintk(VIDC_ERR,
+ "%s Failed to get buffer requirements : %d\n",
+ __func__, rc);
+ }
break;
case V4L2_MPEG_VIDC_VIDEO_DPB_COLOR_FMT_UBWC:
case V4L2_MPEG_VIDC_VIDEO_DPB_COLOR_FMT_TP10_UBWC:
diff --git a/drivers/media/platform/msm/vidc/msm_venc.c b/drivers/media/platform/msm/vidc/msm_venc.c
index ca9d7fba4ee3..30726354164b 100644
--- a/drivers/media/platform/msm/vidc/msm_venc.c
+++ b/drivers/media/platform/msm/vidc/msm_venc.c
@@ -3511,6 +3511,48 @@ static int try_set_ctrl(struct msm_vidc_inst *inst, struct v4l2_ctrl *ctrl)
frameqp = ctrl->val;
pdata = &frameqp;
break;
+ case V4L2_CID_MPEG_VIDC_VIDEO_INITIAL_I_FRAME_QP:
+ {
+ rc = msm_venc_validate_qp_value(inst, ctrl);
+ if (rc) {
+ dprintk(VIDC_ERR, "Invalid Initial I QP\n");
+ break;
+ }
+ /*
+ * Defer sending property from here, set_ext_ctrl
+ * will send it based on the rc value.
+ */
+ property_id = 0;
+ break;
+ }
+ case V4L2_CID_MPEG_VIDC_VIDEO_INITIAL_B_FRAME_QP:
+ {
+ rc = msm_venc_validate_qp_value(inst, ctrl);
+ if (rc) {
+ dprintk(VIDC_ERR, "Invalid Initial B QP\n");
+ break;
+ }
+ /*
+ * Defer sending property from here, set_ext_ctrl
+ * will send it based on the rc value.
+ */
+ property_id = 0;
+ break;
+ }
+ case V4L2_CID_MPEG_VIDC_VIDEO_INITIAL_P_FRAME_QP:
+ {
+ rc = msm_venc_validate_qp_value(inst, ctrl);
+ if (rc) {
+ dprintk(VIDC_ERR, "Invalid Initial P QP\n");
+ break;
+ }
+ /*
+ * Defer sending property from here, set_ext_ctrl
+ * will send it based on the rc value.
+ */
+ property_id = 0;
+ break;
+ }
case V4L2_CID_MPEG_VIDC_VIDEO_VQZIP_SEI:
property_id = HAL_PARAM_VENC_VQZIP_SEI;
enable.enable = ctrl->val;
@@ -3745,7 +3787,7 @@ static int try_set_ext_ctrl(struct msm_vidc_inst *inst,
struct hal_aspect_ratio sar;
struct hal_bitrate bitrate;
struct hal_frame_size blur_res;
- struct v4l2_ctrl *temp_ctrl;
+ struct v4l2_control temp_ctrl;
if (!inst || !inst->core || !inst->core->device || !ctrl) {
dprintk(VIDC_ERR, "%s invalid parameters\n", __func__);
@@ -3812,12 +3854,15 @@ static int try_set_ext_ctrl(struct msm_vidc_inst *inst,
/* Sanity check for the QP boundaries as we are using
* same control to set Initial QP for all the codecs
*/
- temp_ctrl->id =
+ temp_ctrl.id =
V4L2_CID_MPEG_VIDC_VIDEO_INITIAL_I_FRAME_QP;
- temp_ctrl->val = control[i].value;
- rc = msm_venc_validate_qp_value(inst, temp_ctrl);
+ temp_ctrl.value = control[i].value;
+
+ rc = msm_comm_s_ctrl(inst, &temp_ctrl);
if (rc) {
- dprintk(VIDC_ERR, "Invalid Initial I QP\n");
+ dprintk(VIDC_ERR,
+ "%s Failed setting Initial I Frame QP : %d\n",
+ __func__, rc);
break;
}
quant.qpi = control[i].value;
@@ -3825,12 +3870,14 @@ static int try_set_ext_ctrl(struct msm_vidc_inst *inst,
pdata = &quant;
break;
case V4L2_CID_MPEG_VIDC_VIDEO_INITIAL_P_FRAME_QP:
- temp_ctrl->id =
+ temp_ctrl.id =
V4L2_CID_MPEG_VIDC_VIDEO_INITIAL_P_FRAME_QP;
- temp_ctrl->val = control[i].value;
- rc = msm_venc_validate_qp_value(inst, temp_ctrl);
+ temp_ctrl.value = control[i].value;
+ rc = msm_comm_s_ctrl(inst, &temp_ctrl);
if (rc) {
- dprintk(VIDC_ERR, "Invalid Initial P QP\n");
+ dprintk(VIDC_ERR,
+ "%s Failed setting Initial P Frame QP : %d\n",
+ __func__, rc);
break;
}
quant.qpp = control[i].value;
@@ -3838,12 +3885,14 @@ static int try_set_ext_ctrl(struct msm_vidc_inst *inst,
pdata = &quant;
break;
case V4L2_CID_MPEG_VIDC_VIDEO_INITIAL_B_FRAME_QP:
- temp_ctrl->id =
+ temp_ctrl.id =
V4L2_CID_MPEG_VIDC_VIDEO_INITIAL_B_FRAME_QP;
- temp_ctrl->val = control[i].value;
- rc = msm_venc_validate_qp_value(inst, temp_ctrl);
+ temp_ctrl.value = control[i].value;
+ rc = msm_comm_s_ctrl(inst, &temp_ctrl);
if (rc) {
- dprintk(VIDC_ERR, "Invalid Initial B QP\n");
+ dprintk(VIDC_ERR,
+ "%s Failed setting Initial B Frame QP : %d\n",
+ __func__, rc);
break;
}
quant.qpb = control[i].value;
diff --git a/drivers/media/platform/msm/vidc/msm_vidc_common.c b/drivers/media/platform/msm/vidc/msm_vidc_common.c
index 8b459e4da618..7b28e80979f2 100644
--- a/drivers/media/platform/msm/vidc/msm_vidc_common.c
+++ b/drivers/media/platform/msm/vidc/msm_vidc_common.c
@@ -902,7 +902,7 @@ static int wait_for_sess_signal_receipt(struct msm_vidc_inst *inst,
dprintk(VIDC_ERR,
"sess resp timeout can potentially crash the system\n");
msm_comm_print_debug_info(inst);
- BUG_ON(inst->core->resources.debug_timeout);
+ BUG_ON(msm_vidc_debug_timeout);
msm_comm_kill_session(inst);
rc = -EIO;
} else {
@@ -1748,7 +1748,7 @@ static void handle_sys_error(enum hal_command_response cmd, void *data)
msm_comm_print_inst_info(inst);
mutex_unlock(&core->lock);
- BUG_ON(core->resources.debug_timeout);
+ BUG_ON(msm_vidc_debug_timeout);
}
void msm_comm_session_clean(struct msm_vidc_inst *inst)
@@ -2543,7 +2543,7 @@ static int msm_comm_session_abort(struct msm_vidc_inst *inst)
"ABORT timeout can potentially crash the system\n");
msm_comm_print_debug_info(inst);
- BUG_ON(inst->core->resources.debug_timeout);
+ BUG_ON(msm_vidc_debug_timeout);
rc = -EBUSY;
} else {
rc = 0;
@@ -2645,7 +2645,7 @@ int msm_comm_check_core_init(struct msm_vidc_core *core)
msm_comm_print_debug_info(inst);
mutex_lock(&core->lock);
- BUG_ON(core->resources.debug_timeout);
+ BUG_ON(msm_vidc_debug_timeout);
rc = -EIO;
goto exit;
} else {
@@ -4110,10 +4110,9 @@ int msm_comm_try_get_prop(struct msm_vidc_inst *inst, enum hal_property ptype,
call_hfi_op(hdev, flush_debug_queue, hdev->hfi_device_data);
dprintk(VIDC_ERR,
"SESS_PROP timeout can potentially crash the system\n");
- if (inst->core->resources.debug_timeout)
- msm_comm_print_debug_info(inst);
+ msm_comm_print_debug_info(inst);
- BUG_ON(inst->core->resources.debug_timeout);
+ BUG_ON(msm_vidc_debug_timeout);
msm_comm_kill_session(inst);
rc = -ETIMEDOUT;
goto exit;
diff --git a/drivers/media/platform/msm/vidc/msm_vidc_debug.c b/drivers/media/platform/msm/vidc/msm_vidc_debug.c
index 1248a1c08103..a9b367d6fe93 100644
--- a/drivers/media/platform/msm/vidc/msm_vidc_debug.c
+++ b/drivers/media/platform/msm/vidc/msm_vidc_debug.c
@@ -38,6 +38,7 @@ bool msm_vidc_debug_timeout = false;
#define MAX_DBG_BUF_SIZE 4096
struct debug_buffer {
+ struct mutex lock;
char ptr[MAX_DBG_BUF_SIZE];
char *curr;
u32 filled_size;
@@ -64,8 +65,12 @@ static u32 write_str(struct debug_buffer *buffer, const char *fmt, ...)
{
va_list args;
u32 size;
+
+ char *curr = buffer->curr;
+ char *end = buffer->ptr + MAX_DBG_BUF_SIZE;
+
va_start(args, fmt);
- size = vscnprintf(buffer->curr, MAX_DBG_BUF_SIZE - 1, fmt, args);
+ size = vscnprintf(curr, end - curr, fmt, args);
va_end(args);
buffer->curr += size;
buffer->filled_size += size;
@@ -79,12 +84,15 @@ static ssize_t core_info_read(struct file *file, char __user *buf,
struct hfi_device *hdev;
struct hal_fw_info fw_info = { {0} };
int i = 0, rc = 0;
+ ssize_t len = 0;
if (!core || !core->device) {
dprintk(VIDC_ERR, "Invalid params, core: %pK\n", core);
return 0;
}
hdev = core->device;
+
+ mutex_lock(&dbg_buf.lock);
INIT_DBG_BUF(dbg_buf);
write_str(&dbg_buf, "===============================\n");
write_str(&dbg_buf, "CORE %d: %pK\n", core->id, core);
@@ -108,8 +116,11 @@ err_fw_info:
completion_done(&core->completions[SYS_MSG_INDEX(i)]) ?
"pending" : "done");
}
- return simple_read_from_buffer(buf, count, ppos,
+ len = simple_read_from_buffer(buf, count, ppos,
dbg_buf.ptr, dbg_buf.filled_size);
+
+ mutex_unlock(&dbg_buf.lock);
+ return len;
}
static const struct file_operations core_info_fops = {
@@ -147,7 +158,10 @@ static const struct file_operations ssr_fops = {
struct dentry *msm_vidc_debugfs_init_drv(void)
{
bool ok = false;
- struct dentry *dir = debugfs_create_dir("msm_vidc", NULL);
+ struct dentry *dir = NULL;
+
+ mutex_init(&dbg_buf.lock);
+ dir = debugfs_create_dir("msm_vidc", NULL);
if (IS_ERR_OR_NULL(dir)) {
dir = NULL;
goto failed_create_dir;
@@ -216,6 +230,7 @@ struct dentry *msm_vidc_debugfs_init_core(struct msm_vidc_core *core,
dprintk(VIDC_ERR, "Failed to create debugfs for msm_vidc\n");
goto failed_create_dir;
}
+
if (!debugfs_create_file("info", S_IRUGO, dir, core, &core_info_fops)) {
dprintk(VIDC_ERR, "debugfs_create_file: fail\n");
goto failed_create_dir;
@@ -269,11 +284,14 @@ static ssize_t inst_info_read(struct file *file, char __user *buf,
{
struct msm_vidc_inst *inst = file->private_data;
int i, j;
+ ssize_t len = 0;
if (!inst) {
dprintk(VIDC_ERR, "Invalid params, inst %pK\n", inst);
return 0;
}
+
+ mutex_lock(&dbg_buf.lock);
INIT_DBG_BUF(dbg_buf);
write_str(&dbg_buf, "===============================\n");
write_str(&dbg_buf, "INSTANCE: %pK (%s)\n", inst,
@@ -331,8 +349,10 @@ static ssize_t inst_info_read(struct file *file, char __user *buf,
publish_unreleased_reference(inst);
- return simple_read_from_buffer(buf, count, ppos,
+ len = simple_read_from_buffer(buf, count, ppos,
dbg_buf.ptr, dbg_buf.filled_size);
+ mutex_unlock(&dbg_buf.lock);
+ return len;
}
static const struct file_operations inst_info_fops = {
@@ -413,3 +433,8 @@ void msm_vidc_debugfs_update(struct msm_vidc_inst *inst,
}
}
+void msm_vidc_debugfs_deinit_drv(void)
+{
+ mutex_destroy(&dbg_buf.lock);
+}
+
diff --git a/drivers/media/platform/msm/vidc/msm_vidc_debug.h b/drivers/media/platform/msm/vidc/msm_vidc_debug.h
index 39ac6273f34e..853ce4b89f2b 100644
--- a/drivers/media/platform/msm/vidc/msm_vidc_debug.h
+++ b/drivers/media/platform/msm/vidc/msm_vidc_debug.h
@@ -126,6 +126,7 @@ struct dentry *msm_vidc_debugfs_init_inst(struct msm_vidc_inst *inst,
struct dentry *parent);
void msm_vidc_debugfs_update(struct msm_vidc_inst *inst,
enum msm_vidc_debugfs_event e);
+void msm_vidc_debugfs_deinit_drv(void);
static inline void tic(struct msm_vidc_inst *i, enum profiling_points p,
char *b)
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 a65e22c66e30..4cc977e568ee 100644
--- a/drivers/media/platform/msm/vidc/msm_vidc_res_parse.c
+++ b/drivers/media/platform/msm/vidc/msm_vidc_res_parse.c
@@ -1123,7 +1123,7 @@ int read_platform_resources_from_dt(
res->debug_timeout = of_property_read_bool(pdev->dev.of_node,
"qcom,debug-timeout");
- res->debug_timeout |= msm_vidc_debug_timeout;
+ msm_vidc_debug_timeout |= res->debug_timeout;
of_property_read_u32(pdev->dev.of_node,
"qcom,pm-qos-latency-us", &res->pm_qos_latency_us);
diff --git a/drivers/mfd/wcd934x-regmap.c b/drivers/mfd/wcd934x-regmap.c
index e8ba1495de2b..27249eeec013 100644
--- a/drivers/mfd/wcd934x-regmap.c
+++ b/drivers/mfd/wcd934x-regmap.c
@@ -1937,7 +1937,6 @@ static bool wcd934x_is_volatile_register(struct device *dev, unsigned int reg)
case WCD934X_BIAS_VBG_FINE_ADJ:
case WCD934X_CODEC_CPR_SVS_CX_VDD:
case WCD934X_CODEC_CPR_SVS2_CX_VDD:
- case WCD934X_CDC_TOP_TOP_CFG1:
case WCD934X_CDC_CLK_RST_CTRL_FS_CNT_CONTROL:
return true;
}
diff --git a/drivers/misc/qcom/qdsp6v2/audio_hwacc_effects.c b/drivers/misc/qcom/qdsp6v2/audio_hwacc_effects.c
index 9889d9c4723b..84761747f129 100644
--- a/drivers/misc/qcom/qdsp6v2/audio_hwacc_effects.c
+++ b/drivers/misc/qcom/qdsp6v2/audio_hwacc_effects.c
@@ -148,6 +148,8 @@ static int audio_effects_shared_ioctl(struct file *file, unsigned cmd,
case AUDIO_START: {
pr_debug("%s: AUDIO_START\n", __func__);
+ mutex_lock(&effects->lock);
+
rc = q6asm_open_read_write_v2(effects->ac,
FORMAT_LINEAR_PCM,
FORMAT_MULTI_CHANNEL_LINEAR_PCM,
@@ -159,6 +161,7 @@ static int audio_effects_shared_ioctl(struct file *file, unsigned cmd,
pr_err("%s: Open failed for hw accelerated effects:rc=%d\n",
__func__, rc);
rc = -EINVAL;
+ mutex_unlock(&effects->lock);
goto ioctl_fail;
}
effects->opened = 1;
@@ -175,6 +178,7 @@ static int audio_effects_shared_ioctl(struct file *file, unsigned cmd,
pr_err("%s: Write buffer Allocation failed rc = %d\n",
__func__, rc);
rc = -ENOMEM;
+ mutex_unlock(&effects->lock);
goto ioctl_fail;
}
atomic_set(&effects->in_count, effects->config.input.num_buf);
@@ -185,6 +189,7 @@ static int audio_effects_shared_ioctl(struct file *file, unsigned cmd,
pr_err("%s: Read buffer Allocation failed rc = %d\n",
__func__, rc);
rc = -ENOMEM;
+ mutex_unlock(&effects->lock);
goto readbuf_fail;
}
atomic_set(&effects->out_count, effects->config.output.num_buf);
@@ -199,6 +204,7 @@ static int audio_effects_shared_ioctl(struct file *file, unsigned cmd,
if (rc < 0) {
pr_err("%s: pcm read block config failed\n", __func__);
rc = -EINVAL;
+ mutex_unlock(&effects->lock);
goto cfg_fail;
}
pr_debug("%s: dec: sample_rate: %d, num_channels: %d, bit_width: %d\n",
@@ -213,6 +219,7 @@ static int audio_effects_shared_ioctl(struct file *file, unsigned cmd,
pr_err("%s: pcm write format block config failed\n",
__func__);
rc = -EINVAL;
+ mutex_unlock(&effects->lock);
goto cfg_fail;
}
@@ -225,6 +232,7 @@ static int audio_effects_shared_ioctl(struct file *file, unsigned cmd,
effects->started = 0;
pr_err("%s: ASM run state failed\n", __func__);
}
+ mutex_unlock(&effects->lock);
break;
}
case AUDIO_EFFECTS_WRITE: {
@@ -286,8 +294,11 @@ static int audio_effects_shared_ioctl(struct file *file, unsigned cmd,
uint32_t idx = 0;
uint32_t size = 0;
+ mutex_lock(&effects->lock);
+
if (!effects->started) {
rc = -EFAULT;
+ mutex_unlock(&effects->lock);
goto ioctl_fail;
}
@@ -304,11 +315,13 @@ static int audio_effects_shared_ioctl(struct file *file, unsigned cmd,
if (!rc) {
pr_err("%s: read wait_event_timeout\n", __func__);
rc = -EFAULT;
+ mutex_unlock(&effects->lock);
goto ioctl_fail;
}
if (!atomic_read(&effects->in_count)) {
pr_err("%s: pcm stopped in_count 0\n", __func__);
rc = -EFAULT;
+ mutex_unlock(&effects->lock);
goto ioctl_fail;
}
@@ -316,15 +329,18 @@ static int audio_effects_shared_ioctl(struct file *file, unsigned cmd,
if (bufptr) {
if (!((void *)arg)) {
rc = -EFAULT;
+ mutex_unlock(&effects->lock);
goto ioctl_fail;
}
if ((effects->config.buf_cfg.input_len > size) ||
copy_to_user((void *)arg, bufptr,
effects->config.buf_cfg.input_len)) {
rc = -EFAULT;
+ mutex_unlock(&effects->lock);
goto ioctl_fail;
}
}
+ mutex_unlock(&effects->lock);
break;
}
default:
@@ -456,6 +472,7 @@ static long audio_effects_ioctl(struct file *file, unsigned int cmd,
switch (cmd) {
case AUDIO_SET_EFFECTS_CONFIG: {
pr_debug("%s: AUDIO_SET_EFFECTS_CONFIG\n", __func__);
+ mutex_lock(&effects->lock);
memset(&effects->config, 0, sizeof(effects->config));
if (copy_from_user(&effects->config, (void *)arg,
sizeof(effects->config))) {
@@ -473,6 +490,7 @@ static long audio_effects_ioctl(struct file *file, unsigned int cmd,
effects->config.input.num_buf,
effects->config.input.sample_rate,
effects->config.input.num_channels);
+ mutex_unlock(&effects->lock);
break;
}
case AUDIO_EFFECTS_SET_BUF_LEN: {
@@ -494,6 +512,7 @@ static long audio_effects_ioctl(struct file *file, unsigned int cmd,
buf_avail.input_num_avail = atomic_read(&effects->in_count);
buf_avail.output_num_avail = atomic_read(&effects->out_count);
+ mutex_lock(&effects->lock);
pr_debug("%s: write buf avail: %d, read buf avail: %d\n",
__func__, buf_avail.output_num_avail,
buf_avail.input_num_avail);
@@ -503,16 +522,20 @@ static long audio_effects_ioctl(struct file *file, unsigned int cmd,
__func__);
rc = -EFAULT;
}
+ mutex_unlock(&effects->lock);
break;
}
case AUDIO_EFFECTS_SET_PP_PARAMS: {
+ mutex_lock(&effects->lock);
if (copy_from_user(argvalues, (void *)arg,
MAX_PP_PARAMS_SZ*sizeof(long))) {
pr_err("%s: copy from user for pp params failed\n",
__func__);
+ mutex_unlock(&effects->lock);
return -EFAULT;
}
rc = audio_effects_set_pp_param(effects, argvalues);
+ mutex_unlock(&effects->lock);
break;
}
default:
@@ -578,12 +601,14 @@ static long audio_effects_compat_ioctl(struct file *file, unsigned int cmd,
case AUDIO_SET_EFFECTS_CONFIG32: {
struct msm_hwacc_effects_config32 config32;
struct msm_hwacc_effects_config *config = &effects->config;
+ mutex_lock(&effects->lock);
memset(&effects->config, 0, sizeof(effects->config));
if (copy_from_user(&config32, (void *)arg,
sizeof(config32))) {
pr_err("%s: copy to user for AUDIO_SET_EFFECTS_CONFIG failed\n",
__func__);
rc = -EFAULT;
+ mutex_unlock(&effects->lock);
break;
}
config->input.buf_size = config32.input.buf_size;
@@ -620,16 +645,19 @@ static long audio_effects_compat_ioctl(struct file *file, unsigned int cmd,
effects->config.input.num_buf,
effects->config.input.sample_rate,
effects->config.input.num_channels);
+ mutex_unlock(&effects->lock);
break;
}
case AUDIO_EFFECTS_SET_BUF_LEN32: {
struct msm_hwacc_buf_cfg32 buf_cfg32;
struct msm_hwacc_effects_config *config = &effects->config;
+ mutex_lock(&effects->lock);
if (copy_from_user(&buf_cfg32, (void *)arg,
sizeof(buf_cfg32))) {
pr_err("%s: copy from user for AUDIO_EFFECTS_SET_BUF_LEN failed\n",
__func__);
rc = -EFAULT;
+ mutex_unlock(&effects->lock);
break;
}
config->buf_cfg.input_len = buf_cfg32.input_len;
@@ -637,6 +665,7 @@ static long audio_effects_compat_ioctl(struct file *file, unsigned int cmd,
pr_debug("%s: write buf len: %d, read buf len: %d\n",
__func__, effects->config.buf_cfg.output_len,
effects->config.buf_cfg.input_len);
+ mutex_unlock(&effects->lock);
break;
}
case AUDIO_EFFECTS_GET_BUF_AVAIL32: {
@@ -644,6 +673,7 @@ static long audio_effects_compat_ioctl(struct file *file, unsigned int cmd,
memset(&buf_avail, 0, sizeof(buf_avail));
+ mutex_lock(&effects->lock);
buf_avail.input_num_avail = atomic_read(&effects->in_count);
buf_avail.output_num_avail = atomic_read(&effects->out_count);
pr_debug("%s: write buf avail: %d, read buf avail: %d\n",
@@ -655,22 +685,26 @@ static long audio_effects_compat_ioctl(struct file *file, unsigned int cmd,
__func__);
rc = -EFAULT;
}
+ mutex_unlock(&effects->lock);
break;
}
case AUDIO_EFFECTS_SET_PP_PARAMS32: {
long argvalues[MAX_PP_PARAMS_SZ] = {0};
int argvalues32[MAX_PP_PARAMS_SZ] = {0};
+ mutex_lock(&effects->lock);
if (copy_from_user(argvalues32, (void *)arg,
MAX_PP_PARAMS_SZ*sizeof(int))) {
pr_err("%s: copy from user failed for pp params\n",
__func__);
+ mutex_unlock(&effects->lock);
return -EFAULT;
}
for (i = 0; i < MAX_PP_PARAMS_SZ; i++)
argvalues[i] = argvalues32[i];
rc = audio_effects_set_pp_param(effects, argvalues);
+ mutex_unlock(&effects->lock);
break;
}
case AUDIO_START32: {
diff --git a/drivers/misc/qcom/qdsp6v2/ultrasound/usf.c b/drivers/misc/qcom/qdsp6v2/ultrasound/usf.c
index 3bb95f50bc13..52f7d3d2f268 100644
--- a/drivers/misc/qcom/qdsp6v2/ultrasound/usf.c
+++ b/drivers/misc/qcom/qdsp6v2/ultrasound/usf.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
@@ -179,7 +179,7 @@ static const int s_button_map[] = {
};
/* The opened devices container */
-static int s_opened_devs[MAX_DEVS_NUMBER];
+static atomic_t s_opened_devs[MAX_DEVS_NUMBER];
static struct wakeup_source usf_wakeup_source;
@@ -2338,14 +2338,11 @@ static uint16_t add_opened_dev(int minor)
uint16_t ind = 0;
for (ind = 0; ind < MAX_DEVS_NUMBER; ++ind) {
- if (minor == s_opened_devs[ind]) {
+ if (minor == atomic_cmpxchg(&s_opened_devs[ind], 0, minor)) {
pr_err("%s: device %d is already opened\n",
__func__, minor);
return USF_UNDEF_DEV_ID;
- }
-
- if (s_opened_devs[ind] == 0) {
- s_opened_devs[ind] = minor;
+ } else {
pr_debug("%s: device %d is added; ind=%d\n",
__func__, minor, ind);
return ind;
@@ -2401,7 +2398,7 @@ static int usf_release(struct inode *inode, struct file *file)
usf_disable(&usf->usf_tx);
usf_disable(&usf->usf_rx);
- s_opened_devs[usf->dev_ind] = 0;
+ atomic_set(&s_opened_devs[usf->dev_ind], 0);
wakeup_source_trash(&usf_wakeup_source);
mutex_unlock(&usf->mutex);
diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c
index 5ab09b4ae868..3b79f514350e 100644
--- a/drivers/mmc/core/mmc.c
+++ b/drivers/mmc/core/mmc.c
@@ -2031,7 +2031,7 @@ reinit:
err = mmc_select_hs400(card);
if (err)
goto free_card;
- } else {
+ } else if (!mmc_card_hs400(card)) {
/* Select the desired bus width optionally */
err = mmc_select_bus_width(card);
if (!IS_ERR_VALUE(err) && mmc_card_hs(card)) {
diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c
index 35e5d980ed49..d1775748a7cd 100644
--- a/drivers/net/wireless/ath/ath10k/mac.c
+++ b/drivers/net/wireless/ath/ath10k/mac.c
@@ -4671,7 +4671,8 @@ static int ath10k_mac_txpower_recalc(struct ath10k *ar)
lockdep_assert_held(&ar->conf_mutex);
list_for_each_entry(arvif, &ar->arvifs, list) {
- WARN_ON(arvif->txpower < 0);
+ if (arvif->txpower <= 0)
+ continue;
if (txpower == -1)
txpower = arvif->txpower;
@@ -4679,8 +4680,8 @@ static int ath10k_mac_txpower_recalc(struct ath10k *ar)
txpower = min(txpower, arvif->txpower);
}
- if (WARN_ON(txpower == -1))
- return -EINVAL;
+ if (txpower == -1)
+ return 0;
ret = ath10k_mac_txpower_setup(ar, txpower);
if (ret) {
@@ -5190,6 +5191,10 @@ static void ath10k_remove_interface(struct ieee80211_hw *hw,
ath10k_warn(ar, "failed to recalc monitor: %d\n", ret);
}
+ ret = ath10k_mac_txpower_recalc(ar);
+ if (ret)
+ ath10k_warn(ar, "failed to recalc tx power: %d\n", ret);
+
spin_lock_bh(&ar->htt.tx_lock);
ath10k_mac_vif_tx_unlock_all(arvif);
spin_unlock_bh(&ar->htt.tx_lock);
diff --git a/drivers/net/wireless/ath/ath10k/qmi.c b/drivers/net/wireless/ath/ath10k/qmi.c
index 7d20f087da71..84a9b1a9577c 100644
--- a/drivers/net/wireless/ath/ath10k/qmi.c
+++ b/drivers/net/wireless/ath/ath10k/qmi.c
@@ -29,21 +29,34 @@ ath10k_snoc_service_notifier_notify(struct notifier_block *nb,
service_notifier_nb);
enum pd_subsys_state *state = data;
struct ath10k *ar = ar_snoc->ar;
+ struct ath10k_snoc_qmi_config *qmi_cfg = &ar_snoc->qmi_cfg;
+ int ret;
switch (notification) {
case SERVREG_NOTIF_SERVICE_STATE_DOWN_V01:
ath10k_dbg(ar, ATH10K_DBG_SNOC, "Service down, data: 0x%pK\n",
data);
- if (!state || *state != ROOT_PD_SHUTDOWN)
+ if (!state || *state != ROOT_PD_SHUTDOWN) {
atomic_set(&ar_snoc->fw_crashed, 1);
+ atomic_set(&qmi_cfg->fw_ready, 0);
+ }
ath10k_dbg(ar, ATH10K_DBG_SNOC, "PD went down %d\n",
atomic_read(&ar_snoc->fw_crashed));
break;
case SERVREG_NOTIF_SERVICE_STATE_UP_V01:
ath10k_dbg(ar, ATH10K_DBG_SNOC, "Service up\n");
- queue_work(ar->workqueue, &ar->restart_work);
+ ret = wait_event_timeout(ath10k_fw_ready_wait_event,
+ (atomic_read(&qmi_cfg->fw_ready) &&
+ atomic_read(&qmi_cfg->server_connected)),
+ msecs_to_jiffies(ATH10K_SNOC_WLAN_FW_READY_TIMEOUT));
+ if (ret) {
+ queue_work(ar->workqueue, &ar->restart_work);
+ } else {
+ ath10k_err(ar, "restart failed, fw_ready timed out\n");
+ return NOTIFY_OK;
+ }
break;
default:
ath10k_dbg(ar, ATH10K_DBG_SNOC,
@@ -188,17 +201,18 @@ static int ath10k_snoc_modem_notifier_nb(struct notifier_block *nb,
struct ath10k_snoc *ar_snoc = container_of(nb, struct ath10k_snoc,
modem_ssr_nb);
struct ath10k *ar = ar_snoc->ar;
+ struct ath10k_snoc_qmi_config *qmi_cfg = &ar_snoc->qmi_cfg;
if (code != SUBSYS_BEFORE_SHUTDOWN)
return NOTIFY_OK;
- if (notif->crashed)
+ if (notif->crashed) {
atomic_set(&ar_snoc->fw_crashed, 1);
+ atomic_set(&qmi_cfg->fw_ready, 0);
+ }
ath10k_dbg(ar, ATH10K_DBG_SNOC, "Modem went down %d\n",
atomic_read(&ar_snoc->fw_crashed));
- if (notif->crashed)
- queue_work(ar->workqueue, &ar->restart_work);
return NOTIFY_OK;
}
@@ -255,6 +269,7 @@ ath10k_snoc_driver_event_post(enum ath10k_snoc_driver_event_type type,
{
int ret = 0;
int i = 0;
+ unsigned long irq_flags;
struct ath10k *ar = (struct ath10k *)data;
struct ath10k_snoc *ar_snoc = ath10k_snoc_priv(ar);
struct ath10k_snoc_qmi_config *qmi_cfg = &ar_snoc->qmi_cfg;
@@ -267,7 +282,7 @@ ath10k_snoc_driver_event_post(enum ath10k_snoc_driver_event_type type,
return -EINVAL;
}
- spin_lock_bh(&qmi_cfg->event_lock);
+ spin_lock_irqsave(&qmi_cfg->event_lock, irq_flags);
for (i = 0; i < ATH10K_SNOC_DRIVER_EVENT_MAX; i++) {
if (atomic_read(&qmi_cfg->qmi_ev_list[i].event_handled)) {
@@ -288,7 +303,7 @@ ath10k_snoc_driver_event_post(enum ath10k_snoc_driver_event_type type,
if (i >= ATH10K_SNOC_DRIVER_EVENT_MAX)
i = ATH10K_SNOC_DRIVER_EVENT_SERVER_ARRIVE;
- spin_unlock_bh(&qmi_cfg->event_lock);
+ spin_unlock_irqrestore(&qmi_cfg->event_lock, irq_flags);
queue_work(qmi_cfg->event_wq, &qmi_cfg->event_work);
@@ -304,16 +319,16 @@ ath10k_snoc_driver_event_post(enum ath10k_snoc_driver_event_type type,
ath10k_dbg(ar, ATH10K_DBG_SNOC, "Completed event: %s(%d)\n",
ath10k_snoc_driver_event_to_str(type), type);
- spin_lock_bh(&qmi_cfg->event_lock);
+ spin_lock_irqsave(&qmi_cfg->event_lock, irq_flags);
if (ret == -ERESTARTSYS &&
qmi_cfg->qmi_ev_list[i].ret == ATH10K_SNOC_EVENT_PENDING) {
qmi_cfg->qmi_ev_list[i].sync = false;
atomic_set(&qmi_cfg->qmi_ev_list[i].event_handled, 1);
- spin_unlock_bh(&qmi_cfg->event_lock);
+ spin_unlock_irqrestore(&qmi_cfg->event_lock, irq_flags);
ret = -EINTR;
goto out;
}
- spin_unlock_bh(&qmi_cfg->event_lock);
+ spin_unlock_irqrestore(&qmi_cfg->event_lock, irq_flags);
out:
return ret;
@@ -714,22 +729,23 @@ static int ath10k_snoc_driver_event_fw_ready_ind(struct ath10k *ar)
static void ath10k_snoc_driver_event_work(struct work_struct *work)
{
- struct ath10k_snoc_qmi_driver_event *event;
int ret;
+ unsigned long irq_flags;
+ struct ath10k_snoc_qmi_driver_event *event;
struct ath10k_snoc_qmi_config *qmi_cfg =
container_of(work, struct ath10k_snoc_qmi_config, event_work);
struct ath10k_snoc *ar_snoc =
container_of(qmi_cfg, struct ath10k_snoc, qmi_cfg);
struct ath10k *ar = ar_snoc->ar;
- spin_lock_bh(&qmi_cfg->event_lock);
+ spin_lock_irqsave(&qmi_cfg->event_lock, irq_flags);
while (!list_empty(&qmi_cfg->event_list)) {
event = list_first_entry(&qmi_cfg->event_list,
struct ath10k_snoc_qmi_driver_event,
list);
list_del(&event->list);
- spin_unlock_bh(&qmi_cfg->event_lock);
+ spin_unlock_irqrestore(&qmi_cfg->event_lock, irq_flags);
ath10k_dbg(ar, ATH10K_DBG_SNOC, "Processing event: %s%s(%d)\n",
ath10k_snoc_driver_event_to_str(event->type),
@@ -756,17 +772,17 @@ static void ath10k_snoc_driver_event_work(struct work_struct *work)
"Event Processed: %s%s(%d), ret: %d\n",
ath10k_snoc_driver_event_to_str(event->type),
event->sync ? "-sync" : "", event->type, ret);
- spin_lock_bh(&qmi_cfg->event_lock);
+ spin_lock_irqsave(&qmi_cfg->event_lock, irq_flags);
if (event->sync) {
event->ret = ret;
complete(&event->complete);
continue;
}
- spin_unlock_bh(&qmi_cfg->event_lock);
- spin_lock_bh(&qmi_cfg->event_lock);
+ spin_unlock_irqrestore(&qmi_cfg->event_lock, irq_flags);
+ spin_lock_irqsave(&qmi_cfg->event_lock, irq_flags);
}
- spin_unlock_bh(&qmi_cfg->event_lock);
+ spin_unlock_irqrestore(&qmi_cfg->event_lock, irq_flags);
}
static int
@@ -838,7 +854,6 @@ int ath10k_snoc_start_qmi_service(struct ath10k *ar)
goto out_destroy_wq;
}
- atomic_set(&qmi_cfg->fw_ready, 1);
ath10k_dbg(ar, ATH10K_DBG_SNOC, "QMI service started successfully\n");
return 0;
diff --git a/drivers/net/wireless/ath/ath10k/qmi.h b/drivers/net/wireless/ath/ath10k/qmi.h
index c8bc26bb96b2..29ad5acdf414 100644
--- a/drivers/net/wireless/ath/ath10k/qmi.h
+++ b/drivers/net/wireless/ath/ath10k/qmi.h
@@ -18,7 +18,7 @@
#define ATH10K_SNOC_WLAN_FW_READY_TIMEOUT 8000
#define WLFW_SERVICE_INS_ID_V01 0
-#define WLFW_CLIENT_ID 0x4b4e454c
+#define WLFW_CLIENT_ID 0x41544851
#define WLFW_TIMEOUT_MS 20000
enum ath10k_snoc_driver_event_type {
diff --git a/drivers/net/wireless/ath/ath10k/snoc.c b/drivers/net/wireless/ath/ath10k/snoc.c
index add0a7cd9edb..2cbc8ee9abf9 100644
--- a/drivers/net/wireless/ath/ath10k/snoc.c
+++ b/drivers/net/wireless/ath/ath10k/snoc.c
@@ -650,6 +650,9 @@ static int ath10k_snoc_hif_tx_sg(struct ath10k *ar, u8 pipe_id,
if (!ar_snoc)
return -EINVAL;
+ if (atomic_read(&ar_snoc->fw_crashed))
+ return -ESHUTDOWN;
+
snoc_pipe = &ar_snoc->pipe_info[pipe_id];
ce_pipe = snoc_pipe->ce_hdl;
src_ring = ce_pipe->src_ring;
diff --git a/drivers/net/wireless/ath/wil6210/cfg80211.c b/drivers/net/wireless/ath/wil6210/cfg80211.c
index 923fe470360c..37898146f01d 100644
--- a/drivers/net/wireless/ath/wil6210/cfg80211.c
+++ b/drivers/net/wireless/ath/wil6210/cfg80211.c
@@ -501,9 +501,9 @@ static int wil_cfg80211_scan(struct wiphy *wiphy,
for (i = 0; i < request->n_ssids; i++) {
wil_dbg_misc(wil, "SSID[%d]", i);
- print_hex_dump_bytes("SSID ", DUMP_PREFIX_OFFSET,
- request->ssids[i].ssid,
- request->ssids[i].ssid_len);
+ wil_hex_dump_misc("SSID ", DUMP_PREFIX_OFFSET, 16, 1,
+ request->ssids[i].ssid,
+ request->ssids[i].ssid_len, true);
}
if (request->n_ssids)
@@ -540,8 +540,8 @@ static int wil_cfg80211_scan(struct wiphy *wiphy,
}
if (request->ie_len)
- print_hex_dump_bytes("Scan IE ", DUMP_PREFIX_OFFSET,
- request->ie, request->ie_len);
+ wil_hex_dump_misc("Scan IE ", DUMP_PREFIX_OFFSET, 16, 1,
+ request->ie, request->ie_len, true);
else
wil_dbg_misc(wil, "Scan has no IE's\n");
@@ -766,6 +766,7 @@ static int wil_cfg80211_connect(struct wiphy *wiphy,
if (rc == 0) {
netif_carrier_on(ndev);
wil6210_bus_request(wil, WIL_MAX_BUS_REQUEST_KBPS);
+ wil->bss = bss;
/* Connect can take lots of time */
mod_timer(&wil->connect_timer,
jiffies + msecs_to_jiffies(2000));
@@ -794,6 +795,7 @@ static int wil_cfg80211_disconnect(struct wiphy *wiphy,
return 0;
}
+ wil->locally_generated_disc = true;
rc = wmi_call(wil, WMI_DISCONNECT_CMDID, NULL, 0,
WMI_DISCONNECT_EVENTID, NULL, 0,
WIL6210_DISCONNECT_TO_MS);
@@ -847,7 +849,8 @@ int wil_cfg80211_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev,
*/
wil_dbg_misc(wil, "mgmt_tx\n");
- print_hex_dump_bytes("mgmt tx frame ", DUMP_PREFIX_OFFSET, buf, len);
+ wil_hex_dump_misc("mgmt tx frame ", DUMP_PREFIX_OFFSET, 16, 1, buf,
+ len, true);
cmd = kmalloc(sizeof(*cmd) + len, GFP_KERNEL);
if (!cmd) {
@@ -1180,18 +1183,18 @@ static int _wil_cfg80211_merge_extra_ies(const u8 *ies1, u16 ies1_len,
static void wil_print_bcon_data(struct cfg80211_beacon_data *b)
{
- print_hex_dump_bytes("head ", DUMP_PREFIX_OFFSET,
- b->head, b->head_len);
- print_hex_dump_bytes("tail ", DUMP_PREFIX_OFFSET,
- b->tail, b->tail_len);
- print_hex_dump_bytes("BCON IE ", DUMP_PREFIX_OFFSET,
- b->beacon_ies, b->beacon_ies_len);
- print_hex_dump_bytes("PROBE ", DUMP_PREFIX_OFFSET,
- b->probe_resp, b->probe_resp_len);
- print_hex_dump_bytes("PROBE IE ", DUMP_PREFIX_OFFSET,
- b->proberesp_ies, b->proberesp_ies_len);
- print_hex_dump_bytes("ASSOC IE ", DUMP_PREFIX_OFFSET,
- b->assocresp_ies, b->assocresp_ies_len);
+ wil_hex_dump_misc("head ", DUMP_PREFIX_OFFSET, 16, 1,
+ b->head, b->head_len, true);
+ wil_hex_dump_misc("tail ", DUMP_PREFIX_OFFSET, 16, 1,
+ b->tail, b->tail_len, true);
+ wil_hex_dump_misc("BCON IE ", DUMP_PREFIX_OFFSET, 16, 1,
+ b->beacon_ies, b->beacon_ies_len, true);
+ wil_hex_dump_misc("PROBE ", DUMP_PREFIX_OFFSET, 16, 1,
+ b->probe_resp, b->probe_resp_len, true);
+ wil_hex_dump_misc("PROBE IE ", DUMP_PREFIX_OFFSET, 16, 1,
+ b->proberesp_ies, b->proberesp_ies_len, true);
+ wil_hex_dump_misc("ASSOC IE ", DUMP_PREFIX_OFFSET, 16, 1,
+ b->assocresp_ies, b->assocresp_ies_len, true);
}
/* internal functions for device reset and starting AP */
@@ -1387,8 +1390,8 @@ static int wil_cfg80211_start_ap(struct wiphy *wiphy,
wil_dbg_misc(wil, "BI %d DTIM %d\n", info->beacon_interval,
info->dtim_period);
wil_dbg_misc(wil, "PBSS %d\n", info->pbss);
- print_hex_dump_bytes("SSID ", DUMP_PREFIX_OFFSET,
- info->ssid, info->ssid_len);
+ wil_hex_dump_misc("SSID ", DUMP_PREFIX_OFFSET, 16, 1,
+ info->ssid, info->ssid_len, true);
wil_print_bcon_data(bcon);
wil_print_crypto(wil, crypto);
@@ -1411,6 +1414,8 @@ static int wil_cfg80211_stop_ap(struct wiphy *wiphy,
wil6210_bus_request(wil, WIL_DEFAULT_BUS_REQUEST_KBPS);
wil_set_recovery_state(wil, fw_recovery_idle);
+ set_bit(wil_status_resetting, wil->status);
+
mutex_lock(&wil->mutex);
wmi_pcp_stop(wil);
diff --git a/drivers/net/wireless/ath/wil6210/main.c b/drivers/net/wireless/ath/wil6210/main.c
index 54d978d884ff..fca8acffeed5 100644
--- a/drivers/net/wireless/ath/wil6210/main.c
+++ b/drivers/net/wireless/ath/wil6210/main.c
@@ -30,8 +30,8 @@ bool debug_fw; /* = false; */
module_param(debug_fw, bool, 0444);
MODULE_PARM_DESC(debug_fw, " do not perform card reset. For FW debug");
-static bool oob_mode;
-module_param(oob_mode, bool, 0444);
+static u8 oob_mode;
+module_param(oob_mode, byte, 0444);
MODULE_PARM_DESC(oob_mode,
" enable out of the box (OOB) mode in FW, for diagnostics and certification");
@@ -190,6 +190,7 @@ __acquires(&sta->tid_rx_lock) __releases(&sta->tid_rx_lock)
break;
}
sta->status = wil_sta_unused;
+ sta->fst_link_loss = false;
}
/* reorder buffers */
for (i = 0; i < WIL_STA_TID_NUM; i++) {
@@ -276,11 +277,15 @@ static void _wil6210_disconnect(struct wil6210_priv *wil, const u8 *bssid,
if (test_bit(wil_status_fwconnected, wil->status)) {
clear_bit(wil_status_fwconnected, wil->status);
cfg80211_disconnected(ndev, reason_code,
- NULL, 0, false, GFP_KERNEL);
+ NULL, 0,
+ wil->locally_generated_disc,
+ GFP_KERNEL);
+ wil->locally_generated_disc = false;
} else if (test_bit(wil_status_fwconnecting, wil->status)) {
cfg80211_connect_result(ndev, bssid, NULL, 0, NULL, 0,
WLAN_STATUS_UNSPECIFIED_FAILURE,
GFP_KERNEL);
+ wil->bss = NULL;
}
clear_bit(wil_status_fwconnecting, wil->status);
break;
@@ -302,10 +307,34 @@ static void wil_disconnect_worker(struct work_struct *work)
{
struct wil6210_priv *wil = container_of(work,
struct wil6210_priv, disconnect_worker);
+ struct net_device *ndev = wil_to_ndev(wil);
+ int rc;
+ struct {
+ struct wmi_cmd_hdr wmi;
+ struct wmi_disconnect_event evt;
+ } __packed reply;
- mutex_lock(&wil->mutex);
- _wil6210_disconnect(wil, NULL, WLAN_REASON_UNSPECIFIED, false);
- mutex_unlock(&wil->mutex);
+ if (test_bit(wil_status_fwconnected, wil->status))
+ /* connect succeeded after all */
+ return;
+
+ if (!test_bit(wil_status_fwconnecting, wil->status))
+ /* already disconnected */
+ return;
+
+ rc = wmi_call(wil, WMI_DISCONNECT_CMDID, NULL, 0,
+ WMI_DISCONNECT_EVENTID, &reply, sizeof(reply),
+ WIL6210_DISCONNECT_TO_MS);
+ if (rc) {
+ wil_err(wil, "disconnect error %d\n", rc);
+ return;
+ }
+
+ wil_update_net_queues_bh(wil, NULL, true);
+ netif_carrier_off(ndev);
+ cfg80211_connect_result(ndev, NULL, NULL, 0, NULL, 0,
+ WLAN_STATUS_UNSPECIFIED_FAILURE, GFP_KERNEL);
+ clear_bit(wil_status_fwconnecting, wil->status);
}
static void wil_connect_timer_fn(ulong x)
@@ -614,13 +643,25 @@ static inline void wil_release_cpu(struct wil6210_priv *wil)
wil_w(wil, RGF_USER_USER_CPU_0, 1);
}
-static void wil_set_oob_mode(struct wil6210_priv *wil, bool enable)
+static void wil_set_oob_mode(struct wil6210_priv *wil, u8 mode)
{
- wil_info(wil, "enable=%d\n", enable);
- if (enable)
+ wil_info(wil, "oob_mode to %d\n", mode);
+ switch (mode) {
+ case 0:
+ wil_c(wil, RGF_USER_USAGE_6, BIT_USER_OOB_MODE |
+ BIT_USER_OOB_R2_MODE);
+ break;
+ case 1:
+ wil_c(wil, RGF_USER_USAGE_6, BIT_USER_OOB_R2_MODE);
wil_s(wil, RGF_USER_USAGE_6, BIT_USER_OOB_MODE);
- else
+ break;
+ case 2:
wil_c(wil, RGF_USER_USAGE_6, BIT_USER_OOB_MODE);
+ wil_s(wil, RGF_USER_USAGE_6, BIT_USER_OOB_R2_MODE);
+ break;
+ default:
+ wil_err(wil, "invalid oob_mode: %d\n", mode);
+ }
}
static int wil_target_reset(struct wil6210_priv *wil)
@@ -1164,6 +1205,7 @@ void wil_halp_vote(struct wil6210_priv *wil)
wil->halp.ref_cnt);
if (++wil->halp.ref_cnt == 1) {
+ reinit_completion(&wil->halp.comp);
wil6210_set_halp(wil);
rc = wait_for_completion_timeout(&wil->halp.comp, to_jiffies);
if (!rc) {
diff --git a/drivers/net/wireless/ath/wil6210/pcie_bus.c b/drivers/net/wireless/ath/wil6210/pcie_bus.c
index d472e13fb9d9..2a515e848820 100644
--- a/drivers/net/wireless/ath/wil6210/pcie_bus.c
+++ b/drivers/net/wireless/ath/wil6210/pcie_bus.c
@@ -26,6 +26,10 @@ static bool use_msi = true;
module_param(use_msi, bool, 0444);
MODULE_PARM_DESC(use_msi, " Use MSI interrupt, default - true");
+static bool ftm_mode;
+module_param(ftm_mode, bool, 0444);
+MODULE_PARM_DESC(ftm_mode, " Set factory test mode, default - false");
+
#ifdef CONFIG_PM
#ifdef CONFIG_PM_SLEEP
static int wil6210_pm_notify(struct notifier_block *notify_block,
@@ -36,13 +40,15 @@ static int wil6210_pm_notify(struct notifier_block *notify_block,
static
void wil_set_capabilities(struct wil6210_priv *wil)
{
+ const char *wil_fw_name;
u32 jtag_id = wil_r(wil, RGF_USER_JTAG_DEV_ID);
u8 chip_revision = (wil_r(wil, RGF_USER_REVISION_ID) &
RGF_USER_REVISION_ID_MASK);
bitmap_zero(wil->hw_capabilities, hw_capability_last);
bitmap_zero(wil->fw_capabilities, WMI_FW_CAPABILITY_MAX);
- wil->wil_fw_name = WIL_FW_NAME_DEFAULT;
+ wil->wil_fw_name = ftm_mode ? WIL_FW_NAME_FTM_DEFAULT :
+ WIL_FW_NAME_DEFAULT;
wil->chip_revision = chip_revision;
switch (jtag_id) {
@@ -51,9 +57,11 @@ void wil_set_capabilities(struct wil6210_priv *wil)
case REVISION_ID_SPARROW_D0:
wil->hw_name = "Sparrow D0";
wil->hw_version = HW_VER_SPARROW_D0;
- if (wil_fw_verify_file_exists(wil,
- WIL_FW_NAME_SPARROW_PLUS))
- wil->wil_fw_name = WIL_FW_NAME_SPARROW_PLUS;
+ wil_fw_name = ftm_mode ? WIL_FW_NAME_FTM_SPARROW_PLUS :
+ WIL_FW_NAME_SPARROW_PLUS;
+
+ if (wil_fw_verify_file_exists(wil, wil_fw_name))
+ wil->wil_fw_name = wil_fw_name;
break;
case REVISION_ID_SPARROW_B0:
wil->hw_name = "Sparrow B0";
diff --git a/drivers/net/wireless/ath/wil6210/pm.c b/drivers/net/wireless/ath/wil6210/pm.c
index 7260bef314a4..2ae4fe85cc8c 100644
--- a/drivers/net/wireless/ath/wil6210/pm.c
+++ b/drivers/net/wireless/ath/wil6210/pm.c
@@ -71,6 +71,11 @@ int wil_suspend(struct wil6210_priv *wil, bool is_runtime)
wil_dbg_pm(wil, "suspend: %s\n", is_runtime ? "runtime" : "system");
+ if (test_bit(wil_status_suspended, wil->status)) {
+ wil_dbg_pm(wil, "trying to suspend while suspended\n");
+ return 0;
+ }
+
/* if netif up, hardware is alive, shut it down */
if (ndev->flags & IFF_UP) {
rc = wil_down(wil);
@@ -86,10 +91,14 @@ int wil_suspend(struct wil6210_priv *wil, bool is_runtime)
if (wil->platform_ops.suspend) {
rc = wil->platform_ops.suspend(wil->platform_handle);
- if (rc)
+ if (rc) {
wil_enable_irq(wil);
+ goto out;
+ }
}
+ set_bit(wil_status_suspended, wil->status);
+
out:
wil_dbg_pm(wil, "suspend: %s => %d\n",
is_runtime ? "runtime" : "system", rc);
@@ -117,10 +126,13 @@ int wil_resume(struct wil6210_priv *wil, bool is_runtime)
/* if netif up, bring hardware up
* During open(), IFF_UP set after actual device method
- * invocation. This prevent recursive call to wil_up()
+ * invocation. This prevent recursive call to wil_up().
+ * wil_status_suspended will be cleared in wil_reset
*/
if (ndev->flags & IFF_UP)
rc = wil_up(wil);
+ else
+ clear_bit(wil_status_suspended, wil->status);
out:
wil_dbg_pm(wil, "resume: %s => %d\n",
diff --git a/drivers/net/wireless/ath/wil6210/sysfs.c b/drivers/net/wireless/ath/wil6210/sysfs.c
index a3689738a070..b4c4d09011b4 100644
--- a/drivers/net/wireless/ath/wil6210/sysfs.c
+++ b/drivers/net/wireless/ath/wil6210/sysfs.c
@@ -204,9 +204,74 @@ out:
static DEVICE_ATTR(thermal_throttling, 0644,
wil_tt_sysfs_show, wil_tt_sysfs_store);
+static ssize_t
+wil_fst_link_loss_sysfs_show(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ struct wil6210_priv *wil = dev_get_drvdata(dev);
+ ssize_t len = 0;
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(wil->sta); i++)
+ if (wil->sta[i].status == wil_sta_connected)
+ len += snprintf(buf + len, PAGE_SIZE - len,
+ "[%d] %pM %s\n", i, wil->sta[i].addr,
+ wil->sta[i].fst_link_loss ?
+ "On" : "Off");
+
+ return len;
+}
+
+static ssize_t
+wil_fst_link_loss_sysfs_store(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct wil6210_priv *wil = dev_get_drvdata(dev);
+ u8 addr[ETH_ALEN];
+ char *token, *dupbuf, *tmp;
+ int rc = -EINVAL;
+ bool fst_link_loss;
+
+ tmp = kmemdup(buf, count + 1, GFP_KERNEL);
+ if (!tmp)
+ return -ENOMEM;
+
+ tmp[count] = '\0';
+ dupbuf = tmp;
+
+ token = strsep(&dupbuf, " ");
+ if (!token)
+ goto out;
+
+ /* mac address */
+ if (sscanf(token, "%hhx:%hhx:%hhx:%hhx:%hhx:%hhx",
+ &addr[0], &addr[1], &addr[2],
+ &addr[3], &addr[4], &addr[5]) != 6)
+ goto out;
+
+ /* On/Off */
+ if (strtobool(dupbuf, &fst_link_loss))
+ goto out;
+
+ wil_dbg_misc(wil, "set [%pM] with %d\n", addr, fst_link_loss);
+
+ rc = wmi_link_maintain_cfg_write(wil, addr, fst_link_loss);
+ if (!rc)
+ rc = count;
+
+out:
+ kfree(tmp);
+ return rc;
+}
+
+static DEVICE_ATTR(fst_link_loss, 0644,
+ wil_fst_link_loss_sysfs_show,
+ wil_fst_link_loss_sysfs_store);
+
static struct attribute *wil6210_sysfs_entries[] = {
&dev_attr_ftm_txrx_offset.attr,
&dev_attr_thermal_throttling.attr,
+ &dev_attr_fst_link_loss.attr,
NULL
};
diff --git a/drivers/net/wireless/ath/wil6210/wil6210.h b/drivers/net/wireless/ath/wil6210/wil6210.h
index 6111ef6408ea..0529d10a8268 100644
--- a/drivers/net/wireless/ath/wil6210/wil6210.h
+++ b/drivers/net/wireless/ath/wil6210/wil6210.h
@@ -37,8 +37,13 @@ extern bool debug_fw;
extern bool disable_ap_sme;
#define WIL_NAME "wil6210"
-#define WIL_FW_NAME_DEFAULT "wil6210.fw" /* code Sparrow B0 */
-#define WIL_FW_NAME_SPARROW_PLUS "wil6210_sparrow_plus.fw" /* code Sparrow D0 */
+
+#define WIL_FW_NAME_DEFAULT "wil6210.fw"
+#define WIL_FW_NAME_FTM_DEFAULT "wil6210_ftm.fw"
+
+#define WIL_FW_NAME_SPARROW_PLUS "wil6210_sparrow_plus.fw"
+#define WIL_FW_NAME_FTM_SPARROW_PLUS "wil6210_sparrow_plus_ftm.fw"
+
#define WIL_BOARD_FILE_NAME "wil6210.brd" /* board & radio parameters */
#define WIL_DEFAULT_BUS_REQUEST_KBPS 128000 /* ~1Gbps */
@@ -141,6 +146,7 @@ struct RGF_ICR {
#define RGF_USER_USAGE_1 (0x880004)
#define RGF_USER_USAGE_6 (0x880018)
#define BIT_USER_OOB_MODE BIT(31)
+ #define BIT_USER_OOB_R2_MODE BIT(30)
#define RGF_USER_USAGE_8 (0x880020)
#define BIT_USER_PREVENT_DEEP_SLEEP BIT(0)
#define BIT_USER_SUPPORT_T_POWER_ON_0 BIT(1)
@@ -417,6 +423,7 @@ enum { /* for wil6210_priv.status */
wil_status_irqen, /* FIXME: interrupts enabled - for debug */
wil_status_napi_en, /* NAPI enabled protected by wil->mutex */
wil_status_resetting, /* reset in progress */
+ wil_status_suspended, /* suspend completed, device is suspended */
wil_status_last /* keep last */
};
@@ -532,6 +539,7 @@ struct wil_sta_info {
struct wil_tid_crypto_rx tid_crypto_rx[WIL_STA_TID_NUM];
struct wil_tid_crypto_rx group_crypto_rx;
u8 aid; /* 1-254; 0 if unknown/not reported */
+ bool fst_link_loss;
};
enum {
@@ -620,6 +628,8 @@ struct wil6210_priv {
u16 channel; /* relevant in AP mode */
int sinfo_gen;
u32 ap_isolate; /* no intra-BSS communication */
+ struct cfg80211_bss *bss; /* connected bss, relevant in STA mode */
+ int locally_generated_disc; /* relevant in STA mode */
/* interrupt moderation */
u32 tx_max_burst_duration;
u32 tx_interframe_timeout;
@@ -777,6 +787,12 @@ static inline void wil_c(struct wil6210_priv *wil, u32 reg, u32 val)
print_hex_dump_debug("DBG[ WMI]" prefix_str,\
prefix_type, rowsize, \
groupsize, buf, len, ascii)
+
+#define wil_hex_dump_misc(prefix_str, prefix_type, rowsize, \
+ groupsize, buf, len, ascii) \
+ print_hex_dump_debug("DBG[MISC]" prefix_str,\
+ prefix_type, rowsize, \
+ groupsize, buf, len, ascii)
#else /* defined(CONFIG_DYNAMIC_DEBUG) */
static inline
void wil_hex_dump_txrx(const char *prefix_str, int prefix_type, int rowsize,
@@ -789,6 +805,12 @@ void wil_hex_dump_wmi(const char *prefix_str, int prefix_type, int rowsize,
int groupsize, const void *buf, size_t len, bool ascii)
{
}
+
+static inline
+void wil_hex_dump_misc(const char *prefix_str, int prefix_type, int rowsize,
+ int groupsize, const void *buf, size_t len, bool ascii)
+{
+}
#endif /* defined(CONFIG_DYNAMIC_DEBUG) */
void wil_memcpy_fromio_32(void *dst, const volatile void __iomem *src,
@@ -974,5 +996,9 @@ void wil_ftm_evt_per_dest_res(struct wil6210_priv *wil,
void wil_aoa_evt_meas(struct wil6210_priv *wil,
struct wmi_aoa_meas_event *evt,
int len);
+/* link loss */
+int wmi_link_maintain_cfg_write(struct wil6210_priv *wil,
+ const u8 *addr,
+ bool fst_link_loss);
#endif /* __WIL6210_H__ */
diff --git a/drivers/net/wireless/ath/wil6210/wmi.c b/drivers/net/wireless/ath/wil6210/wmi.c
index 6a6ba02beba0..41afbdc34c18 100644
--- a/drivers/net/wireless/ath/wil6210/wmi.c
+++ b/drivers/net/wireless/ath/wil6210/wmi.c
@@ -518,16 +518,16 @@ static void wmi_evt_connect(struct wil6210_priv *wil, int id, void *d, int len)
assoc_resp_ielen = 0;
}
- mutex_lock(&wil->mutex);
if (test_bit(wil_status_resetting, wil->status) ||
!test_bit(wil_status_fwready, wil->status)) {
wil_err(wil, "status_resetting, cancel connect event, CID %d\n",
evt->cid);
- mutex_unlock(&wil->mutex);
/* no need for cleanup, wil_reset will do that */
return;
}
+ mutex_lock(&wil->mutex);
+
if ((wdev->iftype == NL80211_IFTYPE_STATION) ||
(wdev->iftype == NL80211_IFTYPE_P2P_CLIENT)) {
if (!test_bit(wil_status_fwconnecting, wil->status)) {
@@ -573,12 +573,16 @@ static void wmi_evt_connect(struct wil6210_priv *wil, int id, void *d, int len)
GFP_KERNEL);
goto out;
} else {
- cfg80211_connect_result(ndev, evt->bssid,
- assoc_req_ie, assoc_req_ielen,
- assoc_resp_ie, assoc_resp_ielen,
- WLAN_STATUS_SUCCESS,
- GFP_KERNEL);
+ struct wiphy *wiphy = wil_to_wiphy(wil);
+
+ cfg80211_ref_bss(wiphy, wil->bss);
+ cfg80211_connect_bss(ndev, evt->bssid, wil->bss,
+ assoc_req_ie, assoc_req_ielen,
+ assoc_resp_ie, assoc_resp_ielen,
+ WLAN_STATUS_SUCCESS, GFP_KERNEL,
+ NL80211_TIMEOUT_UNSPECIFIED);
}
+ wil->bss = NULL;
} else if ((wdev->iftype == NL80211_IFTYPE_AP) ||
(wdev->iftype == NL80211_IFTYPE_P2P_GO)) {
if (rc) {
@@ -627,6 +631,13 @@ static void wmi_evt_disconnect(struct wil6210_priv *wil, int id,
wil->sinfo_gen++;
+ if (test_bit(wil_status_resetting, wil->status) ||
+ !test_bit(wil_status_fwready, wil->status)) {
+ wil_err(wil, "status_resetting, cancel disconnect event\n");
+ /* no need for cleanup, wil_reset will do that */
+ return;
+ }
+
mutex_lock(&wil->mutex);
wil6210_disconnect(wil, evt->bssid, reason_code, true);
mutex_unlock(&wil->mutex);
@@ -1524,6 +1535,7 @@ int wmi_disconnect_sta(struct wil6210_priv *wil, const u8 *mac,
wil_dbg_wmi(wil, "disconnect_sta: (%pM, reason %d)\n", mac, reason);
+ wil->locally_generated_disc = true;
if (del_sta) {
ether_addr_copy(del_sta_cmd.dst_mac, mac);
rc = wmi_call(wil, WMI_DEL_STA_CMDID, &del_sta_cmd,
@@ -1841,6 +1853,61 @@ void wmi_event_flush(struct wil6210_priv *wil)
spin_unlock_irqrestore(&wil->wmi_ev_lock, flags);
}
+int wmi_link_maintain_cfg_write(struct wil6210_priv *wil,
+ const u8 *addr,
+ bool fst_link_loss)
+{
+ int rc;
+ int cid = wil_find_cid(wil, addr);
+ u32 cfg_type;
+ struct wmi_link_maintain_cfg_write_cmd cmd;
+ struct {
+ struct wmi_cmd_hdr wmi;
+ struct wmi_link_maintain_cfg_write_done_event evt;
+ } __packed reply;
+
+ if (cid < 0)
+ return cid;
+
+ switch (wil->wdev->iftype) {
+ case NL80211_IFTYPE_STATION:
+ cfg_type = fst_link_loss ?
+ WMI_LINK_MAINTAIN_CFG_TYPE_DEFAULT_FST_STA :
+ WMI_LINK_MAINTAIN_CFG_TYPE_DEFAULT_NORMAL_STA;
+ break;
+ case NL80211_IFTYPE_AP:
+ cfg_type = fst_link_loss ?
+ WMI_LINK_MAINTAIN_CFG_TYPE_DEFAULT_FST_AP :
+ WMI_LINK_MAINTAIN_CFG_TYPE_DEFAULT_NORMAL_AP;
+ break;
+ default:
+ wil_err(wil, "Unsupported for iftype %d", wil->wdev->iftype);
+ return -EINVAL;
+ }
+
+ wil_dbg_misc(wil, "Setting cid:%d with cfg_type:%d\n", cid, cfg_type);
+
+ cmd.cfg_type = cpu_to_le32(cfg_type);
+ cmd.cid = cpu_to_le32(cid);
+
+ reply.evt.status = cpu_to_le32(WMI_FW_STATUS_FAILURE);
+
+ rc = wmi_call(wil, WMI_LINK_MAINTAIN_CFG_WRITE_CMDID, &cmd, sizeof(cmd),
+ WMI_LINK_MAINTAIN_CFG_WRITE_DONE_EVENTID, &reply,
+ sizeof(reply), 250);
+ if (rc) {
+ wil_err(wil, "Failed to %s FST link loss",
+ fst_link_loss ? "enable" : "disable");
+ } else if (reply.evt.status == WMI_FW_STATUS_SUCCESS) {
+ wil->sta[cid].fst_link_loss = fst_link_loss;
+ } else {
+ wil_err(wil, "WMI_LINK_MAINTAIN_CFG_WRITE_CMDID returned status %d",
+ reply.evt.status);
+ rc = -EINVAL;
+ }
+ return rc;
+}
+
static bool wmi_evt_call_handler(struct wil6210_priv *wil, int id,
void *d, int len)
{
diff --git a/drivers/net/wireless/cnss_prealloc/cnss_prealloc.c b/drivers/net/wireless/cnss_prealloc/cnss_prealloc.c
index e93416ebd343..09c37c2383c6 100644
--- a/drivers/net/wireless/cnss_prealloc/cnss_prealloc.c
+++ b/drivers/net/wireless/cnss_prealloc/cnss_prealloc.c
@@ -181,7 +181,6 @@ void *wcnss_prealloc_get(unsigned int size)
pr_err("wcnss: %s: prealloc not available for size: %d\n",
__func__, size);
- WARN_ON(1);
return NULL;
}
diff --git a/drivers/net/wireless/wcnss/wcnss_wlan.c b/drivers/net/wireless/wcnss/wcnss_wlan.c
index 3f9eeabc5464..9db2871e8150 100644
--- a/drivers/net/wireless/wcnss/wcnss_wlan.c
+++ b/drivers/net/wireless/wcnss/wcnss_wlan.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
@@ -192,6 +192,8 @@ static DEFINE_SPINLOCK(reg_spinlock);
#define WCNSS_USR_WLAN_MAC_ADDR (WCNSS_USR_CTRL_MSG_START + 3)
#define MAC_ADDRESS_STR "%02x:%02x:%02x:%02x:%02x:%02x"
+#define SHOW_MAC_ADDRESS_STR "%02x:%02x:%02x:%02x:%02x:%02x\n"
+#define WCNSS_USER_MAC_ADDR_LENGTH 18
/* message types */
#define WCNSS_CTRL_MSG_START 0x01000000
@@ -427,23 +429,28 @@ static struct {
static ssize_t wcnss_wlan_macaddr_store(struct device *dev,
struct device_attribute *attr, const char *buf, size_t count)
{
- char macAddr[WLAN_MAC_ADDR_SIZE];
+ int index;
+ int macAddr[WLAN_MAC_ADDR_SIZE];
if (!penv)
return -ENODEV;
- pr_debug("%s: Receive MAC Addr From user space: %s\n", __func__, buf);
+ if (strlen(buf) != WCNSS_USER_MAC_ADDR_LENGTH) {
+ dev_err(dev, "%s: Invalid MAC addr length\n", __func__);
+ return -EINVAL;
+ }
if (WLAN_MAC_ADDR_SIZE != sscanf(buf, MAC_ADDRESS_STR,
- (int *)&macAddr[0], (int *)&macAddr[1],
- (int *)&macAddr[2], (int *)&macAddr[3],
- (int *)&macAddr[4], (int *)&macAddr[5])) {
-
+ &macAddr[0], &macAddr[1], &macAddr[2],
+ &macAddr[3], &macAddr[4], &macAddr[5])) {
pr_err("%s: Failed to Copy MAC\n", __func__);
return -EINVAL;
}
- memcpy(penv->wlan_nv_macAddr, macAddr, sizeof(penv->wlan_nv_macAddr));
+ for (index = 0; index < WLAN_MAC_ADDR_SIZE; index++) {
+ memcpy(&penv->wlan_nv_macAddr[index],
+ (char *)&macAddr[index], sizeof(char));
+ }
pr_info("%s: Write MAC Addr:" MAC_ADDRESS_STR "\n", __func__,
penv->wlan_nv_macAddr[0], penv->wlan_nv_macAddr[1],
@@ -459,7 +466,7 @@ static ssize_t wcnss_wlan_macaddr_show(struct device *dev,
if (!penv)
return -ENODEV;
- return scnprintf(buf, PAGE_SIZE, MAC_ADDRESS_STR,
+ return scnprintf(buf, PAGE_SIZE, SHOW_MAC_ADDRESS_STR,
penv->wlan_nv_macAddr[0], penv->wlan_nv_macAddr[1],
penv->wlan_nv_macAddr[2], penv->wlan_nv_macAddr[3],
penv->wlan_nv_macAddr[4], penv->wlan_nv_macAddr[5]);
diff --git a/drivers/pci/host/pci-msm.c b/drivers/pci/host/pci-msm.c
index 72695d3b9224..f364882943e1 100644
--- a/drivers/pci/host/pci-msm.c
+++ b/drivers/pci/host/pci-msm.c
@@ -481,6 +481,11 @@ enum msm_pcie_link_status {
MSM_PCIE_LINK_DISABLED
};
+enum msm_pcie_boot_option {
+ MSM_PCIE_NO_PROBE_ENUMERATION = BIT(0),
+ MSM_PCIE_NO_WAKE_ENUMERATION = BIT(1)
+};
+
/* gpio info structure */
struct msm_pcie_gpio_info_t {
char *name;
@@ -629,7 +634,7 @@ struct msm_pcie_dev_t {
uint32_t perst_delay_us_max;
uint32_t tlp_rd_size;
bool linkdown_panic;
- bool ep_wakeirq;
+ uint32_t boot_option;
uint32_t rc_idx;
uint32_t phy_ver;
@@ -1947,8 +1952,8 @@ static void msm_pcie_show_status(struct msm_pcie_dev_t *dev)
dev->aer_enable ? "" : "not");
PCIE_DBG_FS(dev, "ext_ref_clk is %d\n",
dev->ext_ref_clk);
- PCIE_DBG_FS(dev, "ep_wakeirq is %d\n",
- dev->ep_wakeirq);
+ PCIE_DBG_FS(dev, "boot_option is 0x%x\n",
+ dev->boot_option);
PCIE_DBG_FS(dev, "phy_ver is %d\n",
dev->phy_ver);
PCIE_DBG_FS(dev, "drv_ready is %d\n",
@@ -2563,7 +2568,7 @@ static struct dentry *dfile_linkdown_panic;
static struct dentry *dfile_wr_offset;
static struct dentry *dfile_wr_mask;
static struct dentry *dfile_wr_value;
-static struct dentry *dfile_ep_wakeirq;
+static struct dentry *dfile_boot_option;
static struct dentry *dfile_aer_enable;
static struct dentry *dfile_corr_counter_limit;
@@ -2832,13 +2837,13 @@ const struct file_operations msm_pcie_wr_value_ops = {
.write = msm_pcie_set_wr_value,
};
-static ssize_t msm_pcie_set_ep_wakeirq(struct file *file,
+static ssize_t msm_pcie_set_boot_option(struct file *file,
const char __user *buf,
size_t count, loff_t *ppos)
{
unsigned long ret;
char str[MAX_MSG_LEN];
- u32 new_ep_wakeirq = 0;
+ u32 new_boot_option = 0;
int i;
memset(str, 0, sizeof(str));
@@ -2847,33 +2852,33 @@ static ssize_t msm_pcie_set_ep_wakeirq(struct file *file,
return -EFAULT;
for (i = 0; i < sizeof(str) && (str[i] >= '0') && (str[i] <= '9'); ++i)
- new_ep_wakeirq = (new_ep_wakeirq * 10) + (str[i] - '0');
+ new_boot_option = (new_boot_option * 10) + (str[i] - '0');
- if (new_ep_wakeirq <= 1) {
+ if (new_boot_option <= 1) {
for (i = 0; i < MAX_RC_NUM; i++) {
if (!rc_sel) {
- msm_pcie_dev[0].ep_wakeirq = new_ep_wakeirq;
+ msm_pcie_dev[0].boot_option = new_boot_option;
PCIE_DBG_FS(&msm_pcie_dev[0],
- "PCIe: RC0: ep_wakeirq is now %d\n",
- msm_pcie_dev[0].ep_wakeirq);
+ "PCIe: RC0: boot_option is now 0x%x\n",
+ msm_pcie_dev[0].boot_option);
break;
} else if (rc_sel & (1 << i)) {
- msm_pcie_dev[i].ep_wakeirq = new_ep_wakeirq;
+ msm_pcie_dev[i].boot_option = new_boot_option;
PCIE_DBG_FS(&msm_pcie_dev[i],
- "PCIe: RC%d: ep_wakeirq is now %d\n",
- i, msm_pcie_dev[i].ep_wakeirq);
+ "PCIe: RC%d: boot_option is now 0x%x\n",
+ i, msm_pcie_dev[i].boot_option);
}
}
} else {
- pr_err("PCIe: Invalid input for ep_wakeirq: %d. Please enter 0 or 1.\n",
- new_ep_wakeirq);
+ pr_err("PCIe: Invalid input for boot_option: 0x%x.\n",
+ new_boot_option);
}
return count;
}
-const struct file_operations msm_pcie_ep_wakeirq_ops = {
- .write = msm_pcie_set_ep_wakeirq,
+const struct file_operations msm_pcie_boot_option_ops = {
+ .write = msm_pcie_set_boot_option,
};
static ssize_t msm_pcie_set_aer_enable(struct file *file,
@@ -3026,12 +3031,12 @@ static void msm_pcie_debugfs_init(void)
goto wr_value_error;
}
- dfile_ep_wakeirq = debugfs_create_file("ep_wakeirq", 0664,
+ dfile_boot_option = debugfs_create_file("boot_option", 0664,
dent_msm_pcie, 0,
- &msm_pcie_ep_wakeirq_ops);
- if (!dfile_ep_wakeirq || IS_ERR(dfile_ep_wakeirq)) {
- pr_err("PCIe: fail to create the file for debug_fs ep_wakeirq.\n");
- goto ep_wakeirq_error;
+ &msm_pcie_boot_option_ops);
+ if (!dfile_boot_option || IS_ERR(dfile_boot_option)) {
+ pr_err("PCIe: fail to create the file for debug_fs boot_option.\n");
+ goto boot_option_error;
}
dfile_aer_enable = debugfs_create_file("aer_enable", 0664,
@@ -3054,8 +3059,8 @@ static void msm_pcie_debugfs_init(void)
corr_counter_limit_error:
debugfs_remove(dfile_aer_enable);
aer_enable_error:
- debugfs_remove(dfile_ep_wakeirq);
-ep_wakeirq_error:
+ debugfs_remove(dfile_boot_option);
+boot_option_error:
debugfs_remove(dfile_wr_value);
wr_value_error:
debugfs_remove(dfile_wr_mask);
@@ -3082,7 +3087,7 @@ static void msm_pcie_debugfs_exit(void)
debugfs_remove(dfile_wr_offset);
debugfs_remove(dfile_wr_mask);
debugfs_remove(dfile_wr_value);
- debugfs_remove(dfile_ep_wakeirq);
+ debugfs_remove(dfile_boot_option);
debugfs_remove(dfile_aer_enable);
debugfs_remove(dfile_corr_counter_limit);
}
@@ -3313,7 +3318,7 @@ static inline int msm_pcie_oper_conf(struct pci_bus *bus, u32 devfn, int oper,
word_offset = where & ~0x3;
byte_offset = where & 0x3;
- mask = (~0 >> (8 * (4 - size))) << (8 * byte_offset);
+ mask = ((u32)~0 >> (8 * (4 - size))) << (8 * byte_offset);
if (rc || !dev->enumerated) {
config_base = rc ? dev->dm_core : dev->conf;
@@ -3348,12 +3353,17 @@ static inline int msm_pcie_oper_conf(struct pci_bus *bus, u32 devfn, int oper,
writel_relaxed(wr_val, config_base + word_offset);
wmb(); /* ensure config data is written to hardware register */
- if (rd_val == PCIE_LINK_DOWN)
- PCIE_ERR(dev,
- "Read of RC%d %d:0x%02x + 0x%04x[%d] is all FFs\n",
- rc_idx, bus->number, devfn, where, size);
- else if (dev->shadow_en)
- msm_pcie_save_shadow(dev, word_offset, wr_val, bdf, rc);
+ if (dev->shadow_en) {
+ if (rd_val == PCIE_LINK_DOWN &&
+ (readl_relaxed(config_base) == PCIE_LINK_DOWN))
+ PCIE_ERR(dev,
+ "Read of RC%d %d:0x%02x + 0x%04x[%d] is all FFs\n",
+ rc_idx, bus->number, devfn,
+ where, size);
+ else
+ msm_pcie_save_shadow(dev, word_offset, wr_val,
+ bdf, rc);
+ }
PCIE_DBG3(dev,
"RC%d %d:0x%02x + 0x%04x[%d] <- 0x%08x; rd 0x%08x val 0x%08x\n",
@@ -5411,14 +5421,10 @@ static irqreturn_t handle_wake_irq(int irq, void *data)
PCIE_DBG2(dev, "PCIe WAKE is asserted by Endpoint of RC%d\n",
dev->rc_idx);
- if (!dev->enumerated) {
- PCIE_DBG(dev, "Start enumeating RC%d\n", dev->rc_idx);
- if (dev->ep_wakeirq)
- schedule_work(&dev->handle_wake_work);
- else
- PCIE_DBG(dev,
- "wake irq is received but ep_wakeirq is not supported for RC%d.\n",
- dev->rc_idx);
+ if (!dev->enumerated && !(dev->boot_option &
+ MSM_PCIE_NO_WAKE_ENUMERATION)) {
+ PCIE_DBG(dev, "Start enumerating RC%d\n", dev->rc_idx);
+ schedule_work(&dev->handle_wake_work);
} else {
PCIE_DBG2(dev, "Wake up RC%d\n", dev->rc_idx);
__pm_stay_awake(&dev->ws);
@@ -5562,7 +5568,7 @@ static irqreturn_t handle_global_irq(int irq, void *data)
handle_aer_irq(irq, data);
break;
default:
- PCIE_ERR(dev,
+ PCIE_DUMP(dev,
"PCIe: RC%d: Unexpected event %d is caught!\n",
dev->rc_idx, i);
}
@@ -5805,9 +5811,10 @@ static int msm_pcie_map_qgic_addr(struct msm_pcie_dev_t *dev,
struct msi_msg *msg)
{
struct iommu_domain *domain = iommu_get_domain_for_dev(&pdev->dev);
- int ret, bypass_en = 0;
+ struct iommu_domain_geometry geometry;
+ int ret, fastmap_en = 0, bypass_en = 0;
dma_addr_t iova;
- phys_addr_t pcie_base_addr, gicm_db_offset;
+ phys_addr_t gicm_db_offset;
msg->address_hi = 0;
msg->address_lo = dev->msi_gicm_addr;
@@ -5829,16 +5836,25 @@ static int msm_pcie_map_qgic_addr(struct msm_pcie_dev_t *dev,
if (bypass_en)
return 0;
- gicm_db_offset = dev->msi_gicm_addr -
- rounddown(dev->msi_gicm_addr, PAGE_SIZE);
- /*
- * Use PCIe DBI address as the IOVA since client cannot
- * use this address for their IOMMU mapping. This will
- * prevent any conflicts between PCIe host and
- * client's mapping.
- */
- pcie_base_addr = dev->res[MSM_PCIE_RES_DM_CORE].resource->start;
- iova = rounddown(pcie_base_addr, PAGE_SIZE);
+ iommu_domain_get_attr(domain, DOMAIN_ATTR_FAST, &fastmap_en);
+ if (fastmap_en) {
+ iommu_domain_get_attr(domain, DOMAIN_ATTR_GEOMETRY, &geometry);
+ iova = geometry.aperture_start;
+ PCIE_DBG(dev,
+ "PCIe: RC%d: Use client's IOVA 0x%llx to map QGIC MSI address\n",
+ dev->rc_idx, iova);
+ } else {
+ phys_addr_t pcie_base_addr;
+
+ /*
+ * Use PCIe DBI address as the IOVA since client cannot
+ * use this address for their IOMMU mapping. This will
+ * prevent any conflicts between PCIe host and
+ * client's mapping.
+ */
+ pcie_base_addr = dev->res[MSM_PCIE_RES_DM_CORE].resource->start;
+ iova = rounddown(pcie_base_addr, PAGE_SIZE);
+ }
ret = iommu_map(domain, iova, rounddown(dev->msi_gicm_addr, PAGE_SIZE),
PAGE_SIZE, IOMMU_READ | IOMMU_WRITE);
@@ -5849,6 +5865,8 @@ static int msm_pcie_map_qgic_addr(struct msm_pcie_dev_t *dev,
return -ENOMEM;
}
+ gicm_db_offset = dev->msi_gicm_addr -
+ rounddown(dev->msi_gicm_addr, PAGE_SIZE);
msg->address_lo = iova + gicm_db_offset;
return 0;
@@ -6200,12 +6218,12 @@ static int msm_pcie_probe(struct platform_device *pdev)
msm_pcie_dev[rc_idx].rc_idx,
msm_pcie_dev[rc_idx].smmu_sid_base);
- msm_pcie_dev[rc_idx].ep_wakeirq =
- of_property_read_bool((&pdev->dev)->of_node,
- "qcom,ep-wakeirq");
+ msm_pcie_dev[rc_idx].boot_option = 0;
+ ret = of_property_read_u32((&pdev->dev)->of_node, "qcom,boot-option",
+ &msm_pcie_dev[rc_idx].boot_option);
PCIE_DBG(&msm_pcie_dev[rc_idx],
- "PCIe: EP of RC%d does %s assert wake when it is up.\n",
- rc_idx, msm_pcie_dev[rc_idx].ep_wakeirq ? "" : "not");
+ "PCIe: RC%d boot option is 0x%x.\n",
+ rc_idx, msm_pcie_dev[rc_idx].boot_option);
msm_pcie_dev[rc_idx].phy_ver = 1;
ret = of_property_read_u32((&pdev->dev)->of_node,
@@ -6484,9 +6502,10 @@ static int msm_pcie_probe(struct platform_device *pdev)
msm_pcie_dev[rc_idx].drv_ready = true;
- if (msm_pcie_dev[rc_idx].ep_wakeirq) {
+ if (msm_pcie_dev[rc_idx].boot_option &
+ MSM_PCIE_NO_PROBE_ENUMERATION) {
PCIE_DBG(&msm_pcie_dev[rc_idx],
- "PCIe: RC%d will be enumerated upon WAKE signal from Endpoint.\n",
+ "PCIe: RC%d will be enumerated by client or endpoint.\n",
rc_idx);
mutex_unlock(&pcie_drv.drv_lock);
return 0;
diff --git a/drivers/platform/msm/ipa/ipa_v2/ipa.c b/drivers/platform/msm/ipa/ipa_v2/ipa.c
index 100bbd582a5e..f01743d04e84 100644
--- a/drivers/platform/msm/ipa/ipa_v2/ipa.c
+++ b/drivers/platform/msm/ipa/ipa_v2/ipa.c
@@ -1584,6 +1584,7 @@ static int ipa_init_smem_region(int memory_region_size,
struct ipa_hw_imm_cmd_dma_shared_mem *cmd = NULL;
struct ipa_desc desc;
struct ipa_mem_buffer mem;
+ gfp_t flag = GFP_KERNEL | (ipa_ctx->use_dma_zone ? GFP_DMA : 0);
int rc;
if (memory_region_size == 0)
@@ -1603,7 +1604,7 @@ static int ipa_init_smem_region(int memory_region_size,
memset(mem.base, 0, mem.size);
cmd = kzalloc(sizeof(*cmd),
- GFP_KERNEL);
+ flag);
if (cmd == NULL) {
IPAERR("Failed to alloc immediate command object\n");
rc = -ENOMEM;
@@ -2166,6 +2167,7 @@ int _ipa_init_sram_v2(void)
struct ipa_hw_imm_cmd_dma_shared_mem *cmd = NULL;
struct ipa_desc desc = {0};
struct ipa_mem_buffer mem;
+ gfp_t flag = GFP_KERNEL | (ipa_ctx->use_dma_zone ? GFP_DMA : 0);
int rc = 0;
phys_addr = ipa_ctx->ipa_wrapper_base +
@@ -2203,7 +2205,7 @@ int _ipa_init_sram_v2(void)
}
memset(mem.base, 0, mem.size);
- cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
+ cmd = kzalloc(sizeof(*cmd), flag);
if (cmd == NULL) {
IPAERR("Failed to alloc immediate command object\n");
rc = -ENOMEM;
@@ -2314,6 +2316,7 @@ int _ipa_init_hdr_v2(void)
struct ipa_desc desc = { 0 };
struct ipa_mem_buffer mem;
struct ipa_hdr_init_local *cmd = NULL;
+ gfp_t flag = GFP_KERNEL | (ipa_ctx->use_dma_zone ? GFP_DMA : 0);
int rc = 0;
mem.size = IPA_MEM_PART(modem_hdr_size) + IPA_MEM_PART(apps_hdr_size);
@@ -2325,7 +2328,7 @@ int _ipa_init_hdr_v2(void)
}
memset(mem.base, 0, mem.size);
- cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
+ cmd = kzalloc(sizeof(*cmd), flag);
if (cmd == NULL) {
IPAERR("Failed to alloc header init command object\n");
rc = -ENOMEM;
@@ -2360,6 +2363,7 @@ int _ipa_init_hdr_v2_5(void)
struct ipa_mem_buffer mem;
struct ipa_hdr_init_local *cmd = NULL;
struct ipa_hw_imm_cmd_dma_shared_mem *dma_cmd = NULL;
+ gfp_t flag = GFP_KERNEL | (ipa_ctx->use_dma_zone ? GFP_DMA : 0);
mem.size = IPA_MEM_PART(modem_hdr_size) + IPA_MEM_PART(apps_hdr_size);
mem.base = dma_alloc_coherent(ipa_ctx->pdev, mem.size, &mem.phys_base,
@@ -2370,7 +2374,7 @@ int _ipa_init_hdr_v2_5(void)
}
memset(mem.base, 0, mem.size);
- cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
+ cmd = kzalloc(sizeof(*cmd), flag);
if (cmd == NULL) {
IPAERR("Failed to alloc header init command object\n");
dma_free_coherent(ipa_ctx->pdev, mem.size, mem.base,
@@ -2411,7 +2415,7 @@ int _ipa_init_hdr_v2_5(void)
memset(mem.base, 0, mem.size);
memset(&desc, 0, sizeof(desc));
- dma_cmd = kzalloc(sizeof(*dma_cmd), GFP_KERNEL);
+ dma_cmd = kzalloc(sizeof(*dma_cmd), flag);
if (dma_cmd == NULL) {
IPAERR("Failed to alloc immediate command object\n");
dma_free_coherent(ipa_ctx->pdev,
@@ -2462,6 +2466,7 @@ int _ipa_init_rt4_v2(void)
struct ipa_desc desc = { 0 };
struct ipa_mem_buffer mem;
struct ipa_ip_v4_routing_init *v4_cmd = NULL;
+ gfp_t flag = GFP_KERNEL | (ipa_ctx->use_dma_zone ? GFP_DMA : 0);
u32 *entry;
int i;
int rc = 0;
@@ -2486,7 +2491,7 @@ int _ipa_init_rt4_v2(void)
entry++;
}
- v4_cmd = kzalloc(sizeof(*v4_cmd), GFP_KERNEL);
+ v4_cmd = kzalloc(sizeof(*v4_cmd), flag);
if (v4_cmd == NULL) {
IPAERR("Failed to alloc v4 routing init command object\n");
rc = -ENOMEM;
@@ -2522,6 +2527,7 @@ int _ipa_init_rt6_v2(void)
struct ipa_desc desc = { 0 };
struct ipa_mem_buffer mem;
struct ipa_ip_v6_routing_init *v6_cmd = NULL;
+ gfp_t flag = GFP_KERNEL | (ipa_ctx->use_dma_zone ? GFP_DMA : 0);
u32 *entry;
int i;
int rc = 0;
@@ -2546,7 +2552,7 @@ int _ipa_init_rt6_v2(void)
entry++;
}
- v6_cmd = kzalloc(sizeof(*v6_cmd), GFP_KERNEL);
+ v6_cmd = kzalloc(sizeof(*v6_cmd), flag);
if (v6_cmd == NULL) {
IPAERR("Failed to alloc v6 routing init command object\n");
rc = -ENOMEM;
@@ -2582,6 +2588,7 @@ int _ipa_init_flt4_v2(void)
struct ipa_desc desc = { 0 };
struct ipa_mem_buffer mem;
struct ipa_ip_v4_filter_init *v4_cmd = NULL;
+ gfp_t flag = GFP_KERNEL | (ipa_ctx->use_dma_zone ? GFP_DMA : 0);
u32 *entry;
int i;
int rc = 0;
@@ -2604,7 +2611,7 @@ int _ipa_init_flt4_v2(void)
entry++;
}
- v4_cmd = kzalloc(sizeof(*v4_cmd), GFP_KERNEL);
+ v4_cmd = kzalloc(sizeof(*v4_cmd), flag);
if (v4_cmd == NULL) {
IPAERR("Failed to alloc v4 fliter init command object\n");
rc = -ENOMEM;
@@ -2640,6 +2647,7 @@ int _ipa_init_flt6_v2(void)
struct ipa_desc desc = { 0 };
struct ipa_mem_buffer mem;
struct ipa_ip_v6_filter_init *v6_cmd = NULL;
+ gfp_t flag = GFP_KERNEL | (ipa_ctx->use_dma_zone ? GFP_DMA : 0);
u32 *entry;
int i;
int rc = 0;
@@ -2662,7 +2670,7 @@ int _ipa_init_flt6_v2(void)
entry++;
}
- v6_cmd = kzalloc(sizeof(*v6_cmd), GFP_KERNEL);
+ v6_cmd = kzalloc(sizeof(*v6_cmd), flag);
if (v6_cmd == NULL) {
IPAERR("Failed to alloc v6 fliter init command object\n");
rc = -ENOMEM;
diff --git a/drivers/platform/msm/ipa/ipa_v2/ipa_dp.c b/drivers/platform/msm/ipa/ipa_v2/ipa_dp.c
index 25364e8efa38..2fdb20d99ce2 100644
--- a/drivers/platform/msm/ipa/ipa_v2/ipa_dp.c
+++ b/drivers/platform/msm/ipa/ipa_v2/ipa_dp.c
@@ -322,8 +322,8 @@ int ipa_send_one(struct ipa_sys_context *sys, struct ipa_desc *desc,
dma_address = desc->dma_address;
tx_pkt->no_unmap_dma = true;
}
- if (!dma_address) {
- IPAERR("failed to DMA wrap\n");
+ if (dma_mapping_error(ipa_ctx->pdev, dma_address)) {
+ IPAERR("dma_map_single failed\n");
goto fail_dma_map;
}
@@ -445,7 +445,7 @@ int ipa_send(struct ipa_sys_context *sys, u32 num_desc, struct ipa_desc *desc,
}
dma_addr = dma_map_single(ipa_ctx->pdev,
transfer.iovec, size, DMA_TO_DEVICE);
- if (!dma_addr) {
+ if (dma_mapping_error(ipa_ctx->pdev, dma_addr)) {
IPAERR("dma_map_single failed for sps xfr buff\n");
kfree(transfer.iovec);
return -EFAULT;
@@ -493,6 +493,15 @@ 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;
@@ -1874,8 +1883,8 @@ begin:
rx_pkt->data.dma_addr = dma_map_single(ipa_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(ipa_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);
@@ -2030,8 +2039,8 @@ static void ipa_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(ipa_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(ipa_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;
@@ -2102,8 +2111,8 @@ static void ipa_replenish_rx_cache(struct ipa_sys_context *sys)
rx_pkt->data.dma_addr = dma_map_single(ipa_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(ipa_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;
@@ -2160,9 +2169,10 @@ static void ipa_replenish_rx_cache_recycle(struct ipa_sys_context *sys)
ptr = skb_put(rx_pkt->data.skb, sys->rx_buff_sz);
rx_pkt->data.dma_addr = dma_map_single(ipa_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(ipa_ctx->pdev, rx_pkt->data.dma_addr)) {
+ IPAERR("dma_map_single failure for rx_pkt\n");
goto fail_dma_mapping;
+ }
list_add_tail(&rx_pkt->link, &sys->head_desc_list);
rx_len_cached = ++sys->len;
diff --git a/drivers/platform/msm/ipa/ipa_v2/ipa_hdr.c b/drivers/platform/msm/ipa/ipa_v2/ipa_hdr.c
index e23de3f26613..f43981f15c31 100644
--- a/drivers/platform/msm/ipa/ipa_v2/ipa_hdr.c
+++ b/drivers/platform/msm/ipa/ipa_v2/ipa_hdr.c
@@ -268,6 +268,7 @@ int __ipa_commit_hdr_v2(void)
struct ipa_mem_buffer mem;
struct ipa_hdr_init_system *cmd = NULL;
struct ipa_hw_imm_cmd_dma_shared_mem *dma_cmd = NULL;
+ gfp_t flag = GFP_ATOMIC | (ipa_ctx->use_dma_zone ? GFP_DMA : 0);
int rc = -EFAULT;
if (ipa_generate_hdr_hw_tbl(&mem)) {
@@ -281,7 +282,7 @@ int __ipa_commit_hdr_v2(void)
IPA_MEM_PART(apps_hdr_size));
goto fail_send_cmd;
} else {
- dma_cmd = kzalloc(sizeof(*dma_cmd), GFP_ATOMIC);
+ dma_cmd = kzalloc(sizeof(*dma_cmd), flag);
if (dma_cmd == NULL) {
IPAERR("fail to alloc immediate cmd\n");
rc = -ENOMEM;
@@ -303,7 +304,7 @@ int __ipa_commit_hdr_v2(void)
IPA_MEM_PART(apps_hdr_size_ddr));
goto fail_send_cmd;
} else {
- cmd = kzalloc(sizeof(*cmd), GFP_ATOMIC);
+ cmd = kzalloc(sizeof(*cmd), flag);
if (cmd == NULL) {
IPAERR("fail to alloc hdr init cmd\n");
rc = -ENOMEM;
@@ -359,6 +360,7 @@ int __ipa_commit_hdr_v2_5(void)
struct ipa_hw_imm_cmd_dma_shared_mem *dma_cmd_hdr = NULL;
struct ipa_hw_imm_cmd_dma_shared_mem *dma_cmd_ctx = NULL;
struct ipa_register_write *reg_write_cmd = NULL;
+ gfp_t flag = GFP_ATOMIC | (ipa_ctx->use_dma_zone ? GFP_DMA : 0);
int rc = -EFAULT;
u32 proc_ctx_size;
u32 proc_ctx_ofst;
@@ -383,7 +385,7 @@ int __ipa_commit_hdr_v2_5(void)
IPA_MEM_PART(apps_hdr_size));
goto fail_send_cmd1;
} else {
- dma_cmd_hdr = kzalloc(sizeof(*dma_cmd_hdr), GFP_ATOMIC);
+ dma_cmd_hdr = kzalloc(sizeof(*dma_cmd_hdr), flag);
if (dma_cmd_hdr == NULL) {
IPAERR("fail to alloc immediate cmd\n");
rc = -ENOMEM;
@@ -406,7 +408,7 @@ int __ipa_commit_hdr_v2_5(void)
goto fail_send_cmd1;
} else {
hdr_init_cmd = kzalloc(sizeof(*hdr_init_cmd),
- GFP_ATOMIC);
+ flag);
if (hdr_init_cmd == NULL) {
IPAERR("fail to alloc immediate cmd\n");
rc = -ENOMEM;
@@ -431,7 +433,7 @@ int __ipa_commit_hdr_v2_5(void)
goto fail_send_cmd1;
} else {
dma_cmd_ctx = kzalloc(sizeof(*dma_cmd_ctx),
- GFP_ATOMIC);
+ flag);
if (dma_cmd_ctx == NULL) {
IPAERR("fail to alloc immediate cmd\n");
rc = -ENOMEM;
@@ -456,7 +458,7 @@ int __ipa_commit_hdr_v2_5(void)
goto fail_send_cmd1;
} else {
reg_write_cmd = kzalloc(sizeof(*reg_write_cmd),
- GFP_ATOMIC);
+ flag);
if (reg_write_cmd == NULL) {
IPAERR("fail to alloc immediate cmd\n");
rc = -ENOMEM;
@@ -722,6 +724,11 @@ static int __ipa_add_hdr(struct ipa_hdr_add *hdr)
entry->hdr,
entry->hdr_len,
DMA_TO_DEVICE);
+ if (dma_mapping_error(ipa_ctx->pdev,
+ entry->phys_base)) {
+ IPAERR("dma_map_single failure for entry\n");
+ goto fail_dma_mapping;
+ }
}
} else {
entry->is_hdr_proc_ctx = false;
@@ -798,6 +805,8 @@ fail_add_proc_ctx:
list_del(&entry->link);
dma_unmap_single(ipa_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(ipa_ctx->hdr_cache, entry);
diff --git a/drivers/platform/msm/ipa/ipa_v2/ipa_intf.c b/drivers/platform/msm/ipa/ipa_v2/ipa_intf.c
index f8f8fd12161a..5c07bc7d43b5 100644
--- a/drivers/platform/msm/ipa/ipa_v2/ipa_intf.c
+++ b/drivers/platform/msm/ipa/ipa_v2/ipa_intf.c
@@ -562,6 +562,8 @@ ssize_t ipa_read(struct file *filp, char __user *buf, size_t count,
mutex_unlock(&ipa_ctx->msg_lock);
if (copy_to_user(buf, &msg->meta,
sizeof(struct ipa_msg_meta))) {
+ kfree(msg);
+ msg = NULL;
ret = -EFAULT;
break;
}
@@ -570,6 +572,8 @@ ssize_t ipa_read(struct file *filp, char __user *buf, size_t count,
if (msg->buff) {
if (copy_to_user(buf, msg->buff,
msg->meta.msg_len)) {
+ kfree(msg);
+ msg = NULL;
ret = -EFAULT;
break;
}
diff --git a/drivers/platform/msm/ipa/ipa_v2/ipa_rt.c b/drivers/platform/msm/ipa/ipa_v2/ipa_rt.c
index f5dea76764f8..11c77934e04f 100644
--- a/drivers/platform/msm/ipa/ipa_v2/ipa_rt.c
+++ b/drivers/platform/msm/ipa/ipa_v2/ipa_rt.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
@@ -698,6 +698,7 @@ int __ipa_commit_rt_v2(enum ipa_ip_type ip)
struct ipa_mem_buffer head;
struct ipa_hw_imm_cmd_dma_shared_mem *cmd1 = NULL;
struct ipa_hw_imm_cmd_dma_shared_mem *cmd2 = NULL;
+ gfp_t flag = GFP_KERNEL | (ipa_ctx->use_dma_zone ? GFP_DMA : 0);
u16 avail;
u32 num_modem_rt_index;
int rc = 0;
@@ -748,7 +749,7 @@ int __ipa_commit_rt_v2(enum ipa_ip_type ip)
}
cmd1 = kzalloc(sizeof(struct ipa_hw_imm_cmd_dma_shared_mem),
- GFP_KERNEL);
+ flag);
if (cmd1 == NULL) {
IPAERR("Failed to alloc immediate command object\n");
rc = -ENOMEM;
@@ -765,7 +766,7 @@ int __ipa_commit_rt_v2(enum ipa_ip_type ip)
if (lcl) {
cmd2 = kzalloc(sizeof(struct ipa_hw_imm_cmd_dma_shared_mem),
- GFP_KERNEL);
+ flag);
if (cmd2 == NULL) {
IPAERR("Failed to alloc immediate command object\n");
rc = -ENOMEM;
diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa.c b/drivers/platform/msm/ipa/ipa_v3/ipa.c
index ddff50834f03..5ee6e5d2d9e3 100644
--- a/drivers/platform/msm/ipa/ipa_v3/ipa.c
+++ b/drivers/platform/msm/ipa/ipa_v3/ipa.c
@@ -2276,6 +2276,36 @@ static int ipa3_q6_set_ex_path_to_apps(void)
desc[num_descs].len = cmd_pyld->len;
num_descs++;
}
+
+ /* disable statuses for modem producers */
+ if (IPA_CLIENT_IS_Q6_PROD(client_idx)) {
+ ipa_assert_on(num_descs >= ipa3_ctx->ipa_num_pipes);
+
+ reg_write.skip_pipeline_clear = false;
+ reg_write.pipeline_clear_options =
+ IPAHAL_HPS_CLEAR;
+ reg_write.offset =
+ ipahal_get_reg_n_ofst(IPA_ENDP_STATUS_n,
+ ep_idx);
+ reg_write.value = 0;
+ reg_write.value_mask = ~0;
+ cmd_pyld = ipahal_construct_imm_cmd(
+ IPA_IMM_CMD_REGISTER_WRITE, &reg_write, false);
+ if (!cmd_pyld) {
+ IPAERR("fail construct register_write cmd\n");
+ ipa_assert();
+ return -EFAULT;
+ }
+
+ desc[num_descs].opcode = ipahal_imm_cmd_get_opcode(
+ IPA_IMM_CMD_REGISTER_WRITE);
+ desc[num_descs].type = IPA_IMM_CMD_DESC;
+ desc[num_descs].callback = ipa3_destroy_imm;
+ desc[num_descs].user1 = cmd_pyld;
+ desc[num_descs].pyld = cmd_pyld->data;
+ desc[num_descs].len = cmd_pyld->len;
+ num_descs++;
+ }
}
/* Will wait 500msecs for IPA tag process completion */
@@ -4036,6 +4066,7 @@ fail_register_device:
unregister_chrdev_region(ipa3_ctx->dev_num, 1);
if (ipa3_ctx->pipe_mem_pool)
gen_pool_destroy(ipa3_ctx->pipe_mem_pool);
+ ipa3_free_dma_task_for_gsi();
ipa3_destroy_flt_tbl_idrs();
idr_destroy(&ipa3_ctx->ipa_idr);
kmem_cache_destroy(ipa3_ctx->rx_pkt_wrapper_cache);
@@ -4551,6 +4582,13 @@ static int ipa3_pre_init(const struct ipa3_plat_drv_res *resource_p,
goto fail_dma_pool;
}
+ /* allocate memory for DMA_TASK workaround */
+ result = ipa3_allocate_dma_task_for_gsi();
+ if (result) {
+ IPAERR("failed to allocate dma task\n");
+ goto fail_dma_task;
+ }
+
/* init the various list heads */
INIT_LIST_HEAD(&ipa3_ctx->hdr_tbl.head_hdr_entry_list);
for (i = 0; i < IPA_HDR_BIN_MAX; i++) {
@@ -4723,6 +4761,8 @@ fail_cdev_add:
fail_device_create:
unregister_chrdev_region(ipa3_ctx->dev_num, 1);
fail_alloc_chrdev_region:
+ ipa3_free_dma_task_for_gsi();
+fail_dma_task:
if (ipa3_ctx->pipe_mem_pool)
gen_pool_destroy(ipa3_ctx->pipe_mem_pool);
ipa3_destroy_flt_tbl_idrs();
diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_i.h b/drivers/platform/msm/ipa/ipa_v3/ipa_i.h
index 0cf77bbde496..ac7ef6a21952 100644
--- a/drivers/platform/msm/ipa/ipa_v3/ipa_i.h
+++ b/drivers/platform/msm/ipa/ipa_v3/ipa_i.h
@@ -1027,6 +1027,11 @@ struct ipa_tz_unlock_reg_info {
u32 size;
};
+struct ipa_dma_task_info {
+ struct ipa_mem_buffer mem;
+ struct ipahal_imm_cmd_pyld *cmd_pyld;
+};
+
/**
* struct ipa3_context - IPA context
* @class: pointer to the struct class
@@ -1246,6 +1251,7 @@ struct ipa3_context {
struct ipa3_smp2p_info smp2p_info;
u32 ipa_tz_unlock_reg_num;
struct ipa_tz_unlock_reg_info *ipa_tz_unlock_reg;
+ struct ipa_dma_task_info dma_task_info;
};
/**
@@ -2053,4 +2059,6 @@ int ipa3_get_ntn_stats(struct Ipa3HwStatsNTNInfoData_t *stats);
struct dentry *ipa_debugfs_get_root(void);
bool ipa3_is_msm_device(void);
struct device *ipa3_get_pdev(void);
+int ipa3_allocate_dma_task_for_gsi(void);
+void ipa3_free_dma_task_for_gsi(void);
#endif /* _IPA3_I_H_ */
diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_intf.c b/drivers/platform/msm/ipa/ipa_v3/ipa_intf.c
index b687b711dc20..16a567644f79 100644
--- a/drivers/platform/msm/ipa/ipa_v3/ipa_intf.c
+++ b/drivers/platform/msm/ipa/ipa_v3/ipa_intf.c
@@ -572,6 +572,8 @@ ssize_t ipa3_read(struct file *filp, char __user *buf, size_t count,
if (copy_to_user(buf, &msg->meta,
sizeof(struct ipa_msg_meta))) {
ret = -EFAULT;
+ kfree(msg);
+ msg = NULL;
break;
}
buf += sizeof(struct ipa_msg_meta);
@@ -580,6 +582,8 @@ ssize_t ipa3_read(struct file *filp, char __user *buf, size_t count,
if (copy_to_user(buf, msg->buff,
msg->meta.msg_len)) {
ret = -EFAULT;
+ kfree(msg);
+ msg = NULL;
break;
}
buf += msg->meta.msg_len;
diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_utils.c b/drivers/platform/msm/ipa/ipa_v3/ipa_utils.c
index c8ff06ddda87..f4a7319ca290 100644
--- a/drivers/platform/msm/ipa/ipa_v3/ipa_utils.c
+++ b/drivers/platform/msm/ipa/ipa_v3/ipa_utils.c
@@ -3430,6 +3430,7 @@ static void ipa3_gsi_poll_after_suspend(struct ipa3_ep_context *ep)
/* queue a work to start polling if don't have one */
atomic_set(&ipa3_ctx->transport_pm.eot_activity, 1);
if (!atomic_read(&ep->sys->curr_polling_state)) {
+ ipa3_inc_acquire_wakelock();
atomic_set(&ep->sys->curr_polling_state, 1);
queue_work(ep->sys->wq, &ep->sys->work);
}
@@ -3482,6 +3483,51 @@ void ipa3_suspend_apps_pipes(bool suspend)
}
}
+int ipa3_allocate_dma_task_for_gsi(void)
+{
+ struct ipahal_imm_cmd_dma_task_32b_addr cmd = { 0 };
+
+ IPADBG("Allocate mem\n");
+ ipa3_ctx->dma_task_info.mem.size = IPA_GSI_CHANNEL_STOP_PKT_SIZE;
+ ipa3_ctx->dma_task_info.mem.base = dma_alloc_coherent(ipa3_ctx->pdev,
+ ipa3_ctx->dma_task_info.mem.size,
+ &ipa3_ctx->dma_task_info.mem.phys_base,
+ GFP_KERNEL);
+ if (!ipa3_ctx->dma_task_info.mem.base) {
+ IPAERR("no mem\n");
+ return -EFAULT;
+ }
+
+ cmd.flsh = 1;
+ cmd.size1 = ipa3_ctx->dma_task_info.mem.size;
+ cmd.addr1 = ipa3_ctx->dma_task_info.mem.phys_base;
+ cmd.packet_size = ipa3_ctx->dma_task_info.mem.size;
+ ipa3_ctx->dma_task_info.cmd_pyld = ipahal_construct_imm_cmd(
+ IPA_IMM_CMD_DMA_TASK_32B_ADDR, &cmd, false);
+ if (!ipa3_ctx->dma_task_info.cmd_pyld) {
+ IPAERR("failed to construct dma_task_32b_addr cmd\n");
+ dma_free_coherent(ipa3_ctx->pdev,
+ ipa3_ctx->dma_task_info.mem.size,
+ ipa3_ctx->dma_task_info.mem.base,
+ ipa3_ctx->dma_task_info.mem.phys_base);
+ memset(&ipa3_ctx->dma_task_info, 0,
+ sizeof(ipa3_ctx->dma_task_info));
+ return -EFAULT;
+ }
+
+ return 0;
+}
+
+void ipa3_free_dma_task_for_gsi(void)
+{
+ dma_free_coherent(ipa3_ctx->pdev,
+ ipa3_ctx->dma_task_info.mem.size,
+ ipa3_ctx->dma_task_info.mem.base,
+ ipa3_ctx->dma_task_info.mem.phys_base);
+ ipahal_destroy_imm_cmd(ipa3_ctx->dma_task_info.cmd_pyld);
+ memset(&ipa3_ctx->dma_task_info, 0, sizeof(ipa3_ctx->dma_task_info));
+}
+
/**
* ipa3_inject_dma_task_for_gsi()- Send DMA_TASK to IPA for GSI stop channel
*
@@ -3490,41 +3536,12 @@ void ipa3_suspend_apps_pipes(bool suspend)
*/
int ipa3_inject_dma_task_for_gsi(void)
{
- static struct ipa_mem_buffer mem = {0};
- struct ipahal_imm_cmd_dma_task_32b_addr cmd = {0};
- static struct ipahal_imm_cmd_pyld *cmd_pyld;
struct ipa3_desc desc = {0};
- /* allocate the memory only for the very first time */
- if (!mem.base) {
- IPADBG("Allocate mem\n");
- mem.size = IPA_GSI_CHANNEL_STOP_PKT_SIZE;
- mem.base = dma_alloc_coherent(ipa3_ctx->pdev,
- mem.size,
- &mem.phys_base,
- GFP_KERNEL);
- if (!mem.base) {
- IPAERR("no mem\n");
- return -EFAULT;
- }
- }
- if (!cmd_pyld) {
- cmd.flsh = 1;
- cmd.size1 = mem.size;
- cmd.addr1 = mem.phys_base;
- cmd.packet_size = mem.size;
- cmd_pyld = ipahal_construct_imm_cmd(
- IPA_IMM_CMD_DMA_TASK_32B_ADDR, &cmd, false);
- if (!cmd_pyld) {
- IPAERR("failed to construct dma_task_32b_addr cmd\n");
- return -EFAULT;
- }
- }
-
desc.opcode = ipahal_imm_cmd_get_opcode_param(
IPA_IMM_CMD_DMA_TASK_32B_ADDR, 1);
- desc.pyld = cmd_pyld->data;
- desc.len = cmd_pyld->len;
+ desc.pyld = ipa3_ctx->dma_task_info.cmd_pyld->data;
+ desc.len = ipa3_ctx->dma_task_info.cmd_pyld->len;
desc.type = IPA_IMM_CMD_DESC;
IPADBG("sending 1B packet to IPA\n");
diff --git a/drivers/platform/msm/ipa/ipa_v3/rmnet_ipa.c b/drivers/platform/msm/ipa/ipa_v3/rmnet_ipa.c
index 6731150ce4e7..e3f8f4c0be46 100644
--- a/drivers/platform/msm/ipa/ipa_v3/rmnet_ipa.c
+++ b/drivers/platform/msm/ipa/ipa_v3/rmnet_ipa.c
@@ -2365,32 +2365,41 @@ static int rmnet_ipa_ap_suspend(struct device *dev)
{
struct net_device *netdev = IPA_NETDEV();
struct ipa3_wwan_private *wwan_ptr;
+ int ret;
+
+ IPAWANDBG("Enter...\n");
- IPAWANDBG_LOW("Enter...\n");
if (netdev == NULL) {
IPAWANERR("netdev is NULL.\n");
- return 0;
+ ret = 0;
+ goto bail;
}
+ netif_tx_lock_bh(netdev);
wwan_ptr = netdev_priv(netdev);
if (wwan_ptr == NULL) {
IPAWANERR("wwan_ptr is NULL.\n");
- return 0;
+ ret = 0;
+ goto unlock_and_bail;
}
/* Do not allow A7 to suspend in case there are oustanding packets */
if (atomic_read(&wwan_ptr->outstanding_pkts) != 0) {
IPAWANDBG("Outstanding packets, postponing AP suspend.\n");
- return -EAGAIN;
+ ret = -EAGAIN;
+ goto unlock_and_bail;
}
/* Make sure that there is no Tx operation ongoing */
- netif_tx_lock_bh(netdev);
+ netif_stop_queue(netdev);
ipa_rm_release_resource(IPA_RM_RESOURCE_WWAN_0_PROD);
- netif_tx_unlock_bh(netdev);
- IPAWANDBG_LOW("Exit\n");
+ ret = 0;
- return 0;
+unlock_and_bail:
+ netif_tx_unlock_bh(netdev);
+bail:
+ IPAWANDBG("Exit with %d\n", ret);
+ return ret;
}
/**
@@ -2407,10 +2416,10 @@ static int rmnet_ipa_ap_resume(struct device *dev)
{
struct net_device *netdev = IPA_NETDEV();
- IPAWANDBG_LOW("Enter...\n");
+ IPAWANDBG("Enter...\n");
if (netdev)
netif_wake_queue(netdev);
- IPAWANDBG_LOW("Exit\n");
+ IPAWANDBG("Exit\n");
return 0;
}
diff --git a/drivers/platform/msm/seemp_core/seemp_logk.c b/drivers/platform/msm/seemp_core/seemp_logk.c
index 9b6096485c39..d0f21943cb0f 100644
--- a/drivers/platform/msm/seemp_core/seemp_logk.c
+++ b/drivers/platform/msm/seemp_core/seemp_logk.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2014-2015, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2014-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
@@ -184,6 +184,8 @@ static int seemp_logk_usr_record(const char __user *buf, size_t count)
if (copy_from_user(&usr_blk.payload, &local_blk->payload,
sizeof(struct blk_payload)) != 0)
return -EFAULT;
+ } else {
+ return -EFAULT;
}
idx = ret = 0;
now = current_kernel_time();
@@ -283,7 +285,12 @@ static bool seemp_logk_get_bit_from_vector(__u8 *pVec, __u32 index)
{
unsigned int byte_num = index/8;
unsigned int bit_num = index%8;
- unsigned char byte = pVec[byte_num];
+ unsigned char byte;
+
+ if (DIV_ROUND_UP(index, 8) > MASK_BUFFER_SIZE)
+ return false;
+
+ byte = pVec[byte_num];
return !(byte & (1 << bit_num));
}
diff --git a/drivers/power/qcom/msm-core.c b/drivers/power/qcom/msm-core.c
index 3ac4611da9bd..43ad33ea234b 100644
--- a/drivers/power/qcom/msm-core.c
+++ b/drivers/power/qcom/msm-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
@@ -1069,6 +1069,7 @@ static int msm_core_dev_probe(struct platform_device *pdev)
if (ret)
goto failed;
+ INIT_DEFERRABLE_WORK(&sampling_work, samplequeue_handle);
ret = msm_core_task_init(&pdev->dev);
if (ret)
goto failed;
@@ -1076,7 +1077,6 @@ static int msm_core_dev_probe(struct platform_device *pdev)
for_each_possible_cpu(cpu)
set_threshold(&activity[cpu]);
- INIT_DEFERRABLE_WORK(&sampling_work, samplequeue_handle);
schedule_delayed_work(&sampling_work, msecs_to_jiffies(0));
cpufreq_register_notifier(&cpu_policy, CPUFREQ_POLICY_NOTIFIER);
pm_notifier(system_suspend_handler, 0);
diff --git a/drivers/power/supply/qcom/battery.c b/drivers/power/supply/qcom/battery.c
index 914a6e4eae64..539e757d3e99 100644
--- a/drivers/power/supply/qcom/battery.c
+++ b/drivers/power/supply/qcom/battery.c
@@ -434,23 +434,28 @@ static int pl_fcc_vote_callback(struct votable *votable, void *data,
return rc;
}
- split_fcc(chip, total_fcc_ua, &master_fcc_ua, &slave_fcc_ua);
- pval.intval = slave_fcc_ua;
- rc = power_supply_set_property(chip->pl_psy,
- POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX, &pval);
- if (rc < 0) {
- pr_err("Couldn't set parallel fcc, rc=%d\n", rc);
- return rc;
- }
+ if (chip->pl_mode != POWER_SUPPLY_PL_NONE) {
+ split_fcc(chip, total_fcc_ua, &master_fcc_ua, &slave_fcc_ua);
+
+ pval.intval = slave_fcc_ua;
+ rc = power_supply_set_property(chip->pl_psy,
+ POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX,
+ &pval);
+ if (rc < 0) {
+ pr_err("Couldn't set parallel fcc, rc=%d\n", rc);
+ return rc;
+ }
- chip->slave_fcc_ua = slave_fcc_ua;
+ chip->slave_fcc_ua = slave_fcc_ua;
- pval.intval = master_fcc_ua;
- rc = power_supply_set_property(chip->main_psy,
- POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX, &pval);
- if (rc < 0) {
- pr_err("Could not set main fcc, rc=%d\n", rc);
- return rc;
+ pval.intval = master_fcc_ua;
+ rc = power_supply_set_property(chip->main_psy,
+ POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX,
+ &pval);
+ if (rc < 0) {
+ pr_err("Could not set main fcc, rc=%d\n", rc);
+ return rc;
+ }
}
pl_dbg(chip, PR_PARALLEL, "master_fcc=%d slave_fcc=%d distribution=(%d/%d)\n",
@@ -511,13 +516,14 @@ static int pl_fv_vote_callback(struct votable *votable, void *data,
return 0;
}
-#define ICL_STEP_UV 25000
+#define ICL_STEP_UA 25000
static int usb_icl_vote_callback(struct votable *votable, void *data,
int icl_ua, const char *client)
{
int rc;
struct pl_data *chip = data;
union power_supply_propval pval = {0, };
+ bool rerun_aicl = false;
if (!chip->main_psy)
return 0;
@@ -543,22 +549,28 @@ static int usb_icl_vote_callback(struct votable *votable, void *data,
}
/* rerun AICL if new ICL is above settled ICL */
- if (icl_ua > pval.intval) {
+ if (icl_ua > pval.intval)
+ rerun_aicl = true;
+
+ if (rerun_aicl) {
/* set a lower ICL */
- pval.intval = max(pval.intval - ICL_STEP_UV, ICL_STEP_UV);
+ pval.intval = max(pval.intval - ICL_STEP_UA, ICL_STEP_UA);
power_supply_set_property(chip->main_psy,
POWER_SUPPLY_PROP_CURRENT_MAX,
&pval);
/* wait for ICL change */
msleep(100);
+ }
- pval.intval = icl_ua;
- power_supply_set_property(chip->main_psy,
- POWER_SUPPLY_PROP_CURRENT_MAX,
- &pval);
+ /* set the effective ICL */
+ pval.intval = icl_ua;
+ 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);
return 0;
@@ -678,9 +690,6 @@ static bool is_main_available(struct pl_data *chip)
chip->main_psy = power_supply_get_by_name("main");
- if (chip->main_psy)
- rerun_election(chip->usb_icl_votable);
-
return !!chip->main_psy;
}
@@ -859,7 +868,18 @@ static void status_change_work(struct work_struct *work)
struct pl_data *chip = container_of(work,
struct pl_data, status_change_work);
- if (!is_main_available(chip))
+ if (!chip->main_psy && is_main_available(chip)) {
+ /*
+ * re-run election for FCC/FV/ICL once main_psy
+ * is available to ensure all votes are reflected
+ * on hardware
+ */
+ rerun_election(chip->usb_icl_votable);
+ rerun_election(chip->fcc_votable);
+ rerun_election(chip->fv_votable);
+ }
+
+ if (!chip->main_psy)
return;
if (!is_batt_available(chip))
diff --git a/drivers/power/supply/qcom/fg-core.h b/drivers/power/supply/qcom/fg-core.h
index f2047592a94b..25c9d0251cf1 100644
--- a/drivers/power/supply/qcom/fg-core.h
+++ b/drivers/power/supply/qcom/fg-core.h
@@ -128,11 +128,6 @@ enum fg_irq_index {
FG_IRQ_MAX,
};
-/* WA flags */
-enum {
- DELTA_SOC_IRQ_WA = BIT(0),
-};
-
/*
* List of FG_SRAM parameters. Please add a parameter only if it is an entry
* that will be used either to configure an entity (e.g. termination current)
@@ -152,6 +147,7 @@ enum fg_sram_param_id {
FG_SRAM_CC_SOC,
FG_SRAM_CC_SOC_SW,
FG_SRAM_ACT_BATT_CAP,
+ FG_SRAM_TIMEBASE,
/* Entries below here are configurable during initialization */
FG_SRAM_CUTOFF_VOLT,
FG_SRAM_EMPTY_VOLT,
@@ -162,14 +158,17 @@ enum fg_sram_param_id {
FG_SRAM_ESR_TIMER_DISCHG_INIT,
FG_SRAM_ESR_TIMER_CHG_MAX,
FG_SRAM_ESR_TIMER_CHG_INIT,
+ FG_SRAM_ESR_PULSE_THRESH,
FG_SRAM_SYS_TERM_CURR,
FG_SRAM_CHG_TERM_CURR,
+ FG_SRAM_CHG_TERM_BASE_CURR,
FG_SRAM_DELTA_MSOC_THR,
FG_SRAM_DELTA_BSOC_THR,
FG_SRAM_RECHARGE_SOC_THR,
FG_SRAM_RECHARGE_VBATT_THR,
FG_SRAM_KI_COEFF_MED_DISCHG,
FG_SRAM_KI_COEFF_HI_DISCHG,
+ FG_SRAM_KI_COEFF_FULL_SOC,
FG_SRAM_ESR_TIGHT_FILTER,
FG_SRAM_ESR_BROAD_FILTER,
FG_SRAM_SLOPE_LIMIT,
@@ -209,6 +208,7 @@ struct fg_alg_flag {
enum wa_flags {
PMI8998_V1_REV_WA = BIT(0),
+ PM660_TSMC_OSC_WA = BIT(1),
};
enum slope_limit_status {
@@ -228,6 +228,7 @@ struct fg_dt_props {
int empty_volt_mv;
int vbatt_low_thr_mv;
int chg_term_curr_ma;
+ int chg_term_base_curr_ma;
int sys_term_curr_ma;
int delta_soc_thr;
int recharge_soc_thr;
@@ -253,6 +254,8 @@ struct fg_dt_props {
int esr_tight_lt_flt_upct;
int esr_broad_lt_flt_upct;
int slope_limit_temp;
+ int esr_pulse_thresh_ma;
+ int esr_meas_curr_ma;
int jeita_thresholds[NUM_JEITA_LEVELS];
int ki_coeff_soc[KI_COEFF_SOC_LEVELS];
int ki_coeff_med_dischg[KI_COEFF_SOC_LEVELS];
@@ -319,6 +322,23 @@ static const struct fg_pt fg_ln_table[] = {
{ 128000, 4852 },
};
+/* each tuple is - <temperature in degC, Timebase> */
+static const struct fg_pt fg_tsmc_osc_table[] = {
+ { -20, 395064 },
+ { -10, 398114 },
+ { 0, 401669 },
+ { 10, 404641 },
+ { 20, 408856 },
+ { 25, 412449 },
+ { 30, 416532 },
+ { 40, 420289 },
+ { 50, 425020 },
+ { 60, 430160 },
+ { 70, 434175 },
+ { 80, 439475 },
+ { 90, 444992 },
+};
+
struct fg_chip {
struct device *dev;
struct pmic_revid_data *pmic_rev_id;
@@ -330,6 +350,7 @@ struct fg_chip {
struct power_supply *dc_psy;
struct power_supply *parallel_psy;
struct iio_channel *batt_id_chan;
+ struct iio_channel *die_temp_chan;
struct fg_memif *sram;
struct fg_irq_info *irqs;
struct votable *awake_votable;
@@ -353,6 +374,7 @@ struct fg_chip {
u32 rradc_base;
u32 wa_flags;
int batt_id_ohms;
+ int ki_coeff_full_soc;
int charge_status;
int prev_charge_status;
int charge_done;
diff --git a/drivers/power/supply/qcom/fg-reg.h b/drivers/power/supply/qcom/fg-reg.h
index bf2827fb550d..cd0b2fb4391f 100644
--- a/drivers/power/supply/qcom/fg-reg.h
+++ b/drivers/power/supply/qcom/fg-reg.h
@@ -167,6 +167,7 @@
/* BATT_INFO_ESR_PULL_DN_CFG */
#define ESR_PULL_DOWN_IVAL_MASK GENMASK(3, 2)
+#define ESR_PULL_DOWN_IVAL_SHIFT 2
#define ESR_MEAS_CUR_60MA 0x0
#define ESR_MEAS_CUR_120MA 0x1
#define ESR_MEAS_CUR_180MA 0x2
diff --git a/drivers/power/supply/qcom/qpnp-fg-gen3.c b/drivers/power/supply/qcom/qpnp-fg-gen3.c
index 59216a567662..a12183f5f387 100644
--- a/drivers/power/supply/qcom/qpnp-fg-gen3.c
+++ b/drivers/power/supply/qcom/qpnp-fg-gen3.c
@@ -31,6 +31,8 @@
#define FG_MEM_INFO_PMI8998 0x0D
/* SRAM address and offset in ascending order */
+#define ESR_PULSE_THRESH_WORD 2
+#define ESR_PULSE_THRESH_OFFSET 3
#define SLOPE_LIMIT_WORD 3
#define SLOPE_LIMIT_OFFSET 0
#define CUTOFF_VOLT_WORD 5
@@ -45,11 +47,14 @@
#define ESR_UPD_TIGHT_LOW_TEMP_OFFSET 2
#define ESR_UPD_BROAD_LOW_TEMP_OFFSET 3
#define KI_COEFF_MED_DISCHG_WORD 9
+#define TIMEBASE_OFFSET 1
#define KI_COEFF_MED_DISCHG_OFFSET 3
#define KI_COEFF_HI_DISCHG_WORD 10
#define KI_COEFF_HI_DISCHG_OFFSET 0
#define KI_COEFF_LOW_DISCHG_WORD 10
#define KI_COEFF_LOW_DISCHG_OFFSET 2
+#define KI_COEFF_FULL_SOC_WORD 12
+#define KI_COEFF_FULL_SOC_OFFSET 2
#define DELTA_MSOC_THR_WORD 12
#define DELTA_MSOC_THR_OFFSET 3
#define DELTA_BSOC_THR_WORD 13
@@ -126,6 +131,7 @@
#define RECHARGE_SOC_THR_v2_WORD 14
#define RECHARGE_SOC_THR_v2_OFFSET 1
#define CHG_TERM_CURR_v2_WORD 15
+#define CHG_TERM_BASE_CURR_v2_OFFSET 0
#define CHG_TERM_CURR_v2_OFFSET 1
#define EMPTY_VOLT_v2_WORD 15
#define EMPTY_VOLT_v2_OFFSET 3
@@ -216,12 +222,17 @@ static struct fg_sram_param pmi8998_v1_sram_params[] = {
ESR_TIMER_CHG_MAX_OFFSET, 2, 1, 1, 0, fg_encode_default, NULL),
PARAM(ESR_TIMER_CHG_INIT, ESR_TIMER_CHG_INIT_WORD,
ESR_TIMER_CHG_INIT_OFFSET, 2, 1, 1, 0, fg_encode_default, NULL),
+ PARAM(ESR_PULSE_THRESH, ESR_PULSE_THRESH_WORD, ESR_PULSE_THRESH_OFFSET,
+ 1, 100000, 390625, 0, fg_encode_default, NULL),
PARAM(KI_COEFF_MED_DISCHG, KI_COEFF_MED_DISCHG_WORD,
KI_COEFF_MED_DISCHG_OFFSET, 1, 1000, 244141, 0,
fg_encode_default, NULL),
PARAM(KI_COEFF_HI_DISCHG, KI_COEFF_HI_DISCHG_WORD,
KI_COEFF_HI_DISCHG_OFFSET, 1, 1000, 244141, 0,
fg_encode_default, NULL),
+ PARAM(KI_COEFF_FULL_SOC, KI_COEFF_FULL_SOC_WORD,
+ KI_COEFF_FULL_SOC_OFFSET, 1, 1000, 244141, 0,
+ fg_encode_default, NULL),
PARAM(ESR_TIGHT_FILTER, ESR_FILTER_WORD, ESR_UPD_TIGHT_OFFSET,
1, 512, 1000000, 0, fg_encode_default, NULL),
PARAM(ESR_BROAD_FILTER, ESR_FILTER_WORD, ESR_UPD_BROAD_OFFSET,
@@ -251,6 +262,8 @@ static struct fg_sram_param pmi8998_v2_sram_params[] = {
fg_decode_cc_soc),
PARAM(ACT_BATT_CAP, ACT_BATT_CAP_BKUP_WORD, ACT_BATT_CAP_BKUP_OFFSET, 2,
1, 1, 0, NULL, fg_decode_default),
+ PARAM(TIMEBASE, KI_COEFF_MED_DISCHG_WORD, TIMEBASE_OFFSET, 2, 1000,
+ 61000, 0, fg_encode_default, NULL),
/* Entries below here are configurable during initialization */
PARAM(CUTOFF_VOLT, CUTOFF_VOLT_WORD, CUTOFF_VOLT_OFFSET, 2, 1000000,
244141, 0, fg_encode_voltage, NULL),
@@ -266,6 +279,9 @@ static struct fg_sram_param pmi8998_v2_sram_params[] = {
1000000, 122070, 0, fg_encode_current, NULL),
PARAM(CHG_TERM_CURR, CHG_TERM_CURR_v2_WORD, CHG_TERM_CURR_v2_OFFSET, 1,
100000, 390625, 0, fg_encode_current, NULL),
+ PARAM(CHG_TERM_BASE_CURR, CHG_TERM_CURR_v2_WORD,
+ CHG_TERM_BASE_CURR_v2_OFFSET, 1, 1024, 1000, 0,
+ fg_encode_current, NULL),
PARAM(DELTA_MSOC_THR, DELTA_MSOC_THR_v2_WORD, DELTA_MSOC_THR_v2_OFFSET,
1, 2048, 100, 0, fg_encode_default, NULL),
PARAM(DELTA_BSOC_THR, DELTA_BSOC_THR_v2_WORD, DELTA_BSOC_THR_v2_OFFSET,
@@ -286,12 +302,17 @@ static struct fg_sram_param pmi8998_v2_sram_params[] = {
ESR_TIMER_CHG_MAX_OFFSET, 2, 1, 1, 0, fg_encode_default, NULL),
PARAM(ESR_TIMER_CHG_INIT, ESR_TIMER_CHG_INIT_WORD,
ESR_TIMER_CHG_INIT_OFFSET, 2, 1, 1, 0, fg_encode_default, NULL),
+ PARAM(ESR_PULSE_THRESH, ESR_PULSE_THRESH_WORD, ESR_PULSE_THRESH_OFFSET,
+ 1, 100000, 390625, 0, fg_encode_default, NULL),
PARAM(KI_COEFF_MED_DISCHG, KI_COEFF_MED_DISCHG_v2_WORD,
KI_COEFF_MED_DISCHG_v2_OFFSET, 1, 1000, 244141, 0,
fg_encode_default, NULL),
PARAM(KI_COEFF_HI_DISCHG, KI_COEFF_HI_DISCHG_v2_WORD,
KI_COEFF_HI_DISCHG_v2_OFFSET, 1, 1000, 244141, 0,
fg_encode_default, NULL),
+ PARAM(KI_COEFF_FULL_SOC, KI_COEFF_FULL_SOC_WORD,
+ KI_COEFF_FULL_SOC_OFFSET, 1, 1000, 244141, 0,
+ fg_encode_default, NULL),
PARAM(ESR_TIGHT_FILTER, ESR_FILTER_WORD, ESR_UPD_TIGHT_OFFSET,
1, 512, 1000000, 0, fg_encode_default, NULL),
PARAM(ESR_BROAD_FILTER, ESR_FILTER_WORD, ESR_UPD_BROAD_OFFSET,
@@ -981,6 +1002,29 @@ static inline void get_batt_temp_delta(int delta, u8 *val)
};
}
+static inline void get_esr_meas_current(int curr_ma, u8 *val)
+{
+ switch (curr_ma) {
+ case 60:
+ *val = ESR_MEAS_CUR_60MA;
+ break;
+ case 120:
+ *val = ESR_MEAS_CUR_120MA;
+ break;
+ case 180:
+ *val = ESR_MEAS_CUR_180MA;
+ break;
+ case 240:
+ *val = ESR_MEAS_CUR_240MA;
+ break;
+ default:
+ *val = ESR_MEAS_CUR_120MA;
+ break;
+ };
+
+ *val <<= ESR_PULL_DOWN_IVAL_SHIFT;
+}
+
static int fg_set_esr_timer(struct fg_chip *chip, int cycles, bool charging,
int flags)
{
@@ -1453,6 +1497,37 @@ static int fg_adjust_ki_coeff_dischg(struct fg_chip *chip)
return 0;
}
+#define KI_COEFF_FULL_SOC_DEFAULT 733
+static int fg_adjust_ki_coeff_full_soc(struct fg_chip *chip, int batt_temp)
+{
+ int rc, ki_coeff_full_soc;
+ u8 val;
+
+ if (batt_temp < 0)
+ ki_coeff_full_soc = 0;
+ else
+ ki_coeff_full_soc = KI_COEFF_FULL_SOC_DEFAULT;
+
+ if (chip->ki_coeff_full_soc == ki_coeff_full_soc)
+ return 0;
+
+ fg_encode(chip->sp, FG_SRAM_KI_COEFF_FULL_SOC, ki_coeff_full_soc, &val);
+ rc = fg_sram_write(chip,
+ chip->sp[FG_SRAM_KI_COEFF_FULL_SOC].addr_word,
+ chip->sp[FG_SRAM_KI_COEFF_FULL_SOC].addr_byte, &val,
+ chip->sp[FG_SRAM_KI_COEFF_FULL_SOC].len,
+ FG_IMA_DEFAULT);
+ if (rc < 0) {
+ pr_err("Error in writing ki_coeff_full_soc, rc=%d\n", rc);
+ return rc;
+ }
+
+ chip->ki_coeff_full_soc = ki_coeff_full_soc;
+ fg_dbg(chip, FG_STATUS, "Wrote ki_coeff_full_soc %d\n",
+ ki_coeff_full_soc);
+ return 0;
+}
+
static int fg_set_recharge_voltage(struct fg_chip *chip, int voltage_mv)
{
u8 buf;
@@ -2037,6 +2112,11 @@ static void status_change_work(struct work_struct *work)
if (rc < 0)
pr_err("Error in configuring slope limiter rc:%d\n",
rc);
+
+ rc = fg_adjust_ki_coeff_full_soc(chip, batt_temp);
+ if (rc < 0)
+ pr_err("Error in configuring ki_coeff_full_soc rc:%d\n",
+ rc);
}
fg_batt_avg_update(chip);
@@ -2189,6 +2269,35 @@ static int fg_get_cycle_count(struct fg_chip *chip)
return count;
}
+static int fg_bp_params_config(struct fg_chip *chip)
+{
+ int rc = 0;
+ u8 buf;
+
+ /* This SRAM register is only present in v2.0 and above */
+ if (!(chip->wa_flags & PMI8998_V1_REV_WA) &&
+ chip->bp.float_volt_uv > 0) {
+ fg_encode(chip->sp, FG_SRAM_FLOAT_VOLT,
+ chip->bp.float_volt_uv / 1000, &buf);
+ rc = fg_sram_write(chip, chip->sp[FG_SRAM_FLOAT_VOLT].addr_word,
+ chip->sp[FG_SRAM_FLOAT_VOLT].addr_byte, &buf,
+ chip->sp[FG_SRAM_FLOAT_VOLT].len, FG_IMA_DEFAULT);
+ if (rc < 0) {
+ pr_err("Error in writing float_volt, rc=%d\n", rc);
+ return rc;
+ }
+ }
+
+ if (chip->bp.vbatt_full_mv > 0) {
+ rc = fg_set_constant_chg_voltage(chip,
+ chip->bp.vbatt_full_mv * 1000);
+ if (rc < 0)
+ return rc;
+ }
+
+ return rc;
+}
+
#define PROFILE_LOAD_BIT BIT(0)
#define BOOTLOADER_LOAD_BIT BIT(1)
#define BOOTLOADER_RESTART_BIT BIT(2)
@@ -2367,6 +2476,11 @@ static void profile_load_work(struct work_struct *work)
}
done:
+ rc = fg_bp_params_config(chip);
+ if (rc < 0)
+ pr_err("Error in configuring battery profile params, rc:%d\n",
+ rc);
+
rc = fg_sram_read(chip, NOM_CAP_WORD, NOM_CAP_OFFSET, buf, 2,
FG_IMA_DEFAULT);
if (rc < 0) {
@@ -3018,27 +3132,6 @@ static int fg_hw_init(struct fg_chip *chip)
return rc;
}
- /* This SRAM register is only present in v2.0 and above */
- if (!(chip->wa_flags & PMI8998_V1_REV_WA) &&
- chip->bp.float_volt_uv > 0) {
- fg_encode(chip->sp, FG_SRAM_FLOAT_VOLT,
- chip->bp.float_volt_uv / 1000, buf);
- rc = fg_sram_write(chip, chip->sp[FG_SRAM_FLOAT_VOLT].addr_word,
- chip->sp[FG_SRAM_FLOAT_VOLT].addr_byte, buf,
- chip->sp[FG_SRAM_FLOAT_VOLT].len, FG_IMA_DEFAULT);
- if (rc < 0) {
- pr_err("Error in writing float_volt, rc=%d\n", rc);
- return rc;
- }
- }
-
- if (chip->bp.vbatt_full_mv > 0) {
- rc = fg_set_constant_chg_voltage(chip,
- chip->bp.vbatt_full_mv * 1000);
- if (rc < 0)
- return rc;
- }
-
fg_encode(chip->sp, FG_SRAM_CHG_TERM_CURR, chip->dt.chg_term_curr_ma,
buf);
rc = fg_sram_write(chip, chip->sp[FG_SRAM_CHG_TERM_CURR].addr_word,
@@ -3059,6 +3152,21 @@ static int fg_hw_init(struct fg_chip *chip)
return rc;
}
+ if (!(chip->wa_flags & PMI8998_V1_REV_WA)) {
+ fg_encode(chip->sp, FG_SRAM_CHG_TERM_BASE_CURR,
+ chip->dt.chg_term_base_curr_ma, buf);
+ rc = fg_sram_write(chip,
+ chip->sp[FG_SRAM_CHG_TERM_BASE_CURR].addr_word,
+ chip->sp[FG_SRAM_CHG_TERM_BASE_CURR].addr_byte,
+ buf, chip->sp[FG_SRAM_CHG_TERM_BASE_CURR].len,
+ FG_IMA_DEFAULT);
+ if (rc < 0) {
+ pr_err("Error in writing chg_term_base_curr, rc=%d\n",
+ rc);
+ return rc;
+ }
+ }
+
if (chip->dt.vbatt_low_thr_mv > 0) {
fg_encode(chip->sp, FG_SRAM_VBATT_LOW,
chip->dt.vbatt_low_thr_mv, buf);
@@ -3234,6 +3342,24 @@ static int fg_hw_init(struct fg_chip *chip)
return rc;
}
+ fg_encode(chip->sp, FG_SRAM_ESR_PULSE_THRESH,
+ chip->dt.esr_pulse_thresh_ma, buf);
+ rc = fg_sram_write(chip, chip->sp[FG_SRAM_ESR_PULSE_THRESH].addr_word,
+ chip->sp[FG_SRAM_ESR_PULSE_THRESH].addr_byte, buf,
+ chip->sp[FG_SRAM_ESR_PULSE_THRESH].len, FG_IMA_DEFAULT);
+ if (rc < 0) {
+ pr_err("Error in writing esr_pulse_thresh_ma, rc=%d\n", rc);
+ return rc;
+ }
+
+ get_esr_meas_current(chip->dt.esr_meas_curr_ma, &val);
+ rc = fg_masked_write(chip, BATT_INFO_ESR_PULL_DN_CFG(chip),
+ ESR_PULL_DOWN_IVAL_MASK, val);
+ if (rc < 0) {
+ pr_err("Error in writing esr_meas_curr_ma, rc=%d\n", rc);
+ return rc;
+ }
+
return 0;
}
@@ -3242,6 +3368,40 @@ static int fg_memif_init(struct fg_chip *chip)
return fg_ima_init(chip);
}
+static int fg_adjust_timebase(struct fg_chip *chip)
+{
+ int rc = 0, die_temp;
+ s32 time_base = 0;
+ u8 buf[2] = {0};
+
+ if ((chip->wa_flags & PM660_TSMC_OSC_WA) && chip->die_temp_chan) {
+ rc = iio_read_channel_processed(chip->die_temp_chan, &die_temp);
+ if (rc < 0) {
+ pr_err("Error in reading die_temp, rc:%d\n", rc);
+ return rc;
+ }
+
+ rc = fg_lerp(fg_tsmc_osc_table, ARRAY_SIZE(fg_tsmc_osc_table),
+ die_temp / 1000, &time_base);
+ if (rc < 0) {
+ pr_err("Error to lookup fg_tsmc_osc_table rc=%d\n", rc);
+ return rc;
+ }
+
+ fg_encode(chip->sp, FG_SRAM_TIMEBASE, time_base, buf);
+ rc = fg_sram_write(chip,
+ chip->sp[FG_SRAM_TIMEBASE].addr_word,
+ chip->sp[FG_SRAM_TIMEBASE].addr_byte, buf,
+ chip->sp[FG_SRAM_TIMEBASE].len, FG_IMA_DEFAULT);
+ if (rc < 0) {
+ pr_err("Error in writing timebase, rc=%d\n", rc);
+ return rc;
+ }
+ }
+
+ return 0;
+}
+
/* INTERRUPT HANDLERS STAY HERE */
static irqreturn_t fg_mem_xcp_irq_handler(int irq, void *data)
@@ -3349,6 +3509,10 @@ static irqreturn_t fg_delta_batt_temp_irq_handler(int irq, void *data)
if (rc < 0)
pr_err("Error in configuring slope limiter rc:%d\n", rc);
+ rc = fg_adjust_ki_coeff_full_soc(chip, batt_temp);
+ if (rc < 0)
+ pr_err("Error in configuring ki_coeff_full_soc rc:%d\n", rc);
+
if (!batt_psy_initialized(chip)) {
chip->last_batt_temp = batt_temp;
return IRQ_HANDLED;
@@ -3359,6 +3523,10 @@ static irqreturn_t fg_delta_batt_temp_irq_handler(int irq, void *data)
chip->health = prop.intval;
if (chip->last_batt_temp != batt_temp) {
+ rc = fg_adjust_timebase(chip);
+ if (rc < 0)
+ pr_err("Error in adjusting timebase, rc=%d\n", rc);
+
chip->last_batt_temp = batt_temp;
power_supply_changed(chip->batt_psy);
}
@@ -3428,6 +3596,10 @@ static irqreturn_t fg_delta_msoc_irq_handler(int irq, void *data)
if (rc < 0)
pr_err("Error in validating ESR, rc=%d\n", rc);
+ rc = fg_adjust_timebase(chip);
+ if (rc < 0)
+ pr_err("Error in adjusting timebase, rc=%d\n", rc);
+
if (batt_psy_initialized(chip))
power_supply_changed(chip->batt_psy);
@@ -3695,6 +3867,7 @@ static int fg_parse_ki_coefficients(struct fg_chip *chip)
#define DEFAULT_EMPTY_VOLT_MV 2800
#define DEFAULT_RECHARGE_VOLT_MV 4250
#define DEFAULT_CHG_TERM_CURR_MA 100
+#define DEFAULT_CHG_TERM_BASE_CURR_MA 75
#define DEFAULT_SYS_TERM_CURR_MA -125
#define DEFAULT_DELTA_SOC_THR 1
#define DEFAULT_RECHARGE_SOC_THR 95
@@ -3717,6 +3890,8 @@ static int fg_parse_ki_coefficients(struct fg_chip *chip)
#define DEFAULT_ESR_TIGHT_LT_FLT_UPCT 48829
#define DEFAULT_ESR_BROAD_LT_FLT_UPCT 148438
#define DEFAULT_ESR_CLAMP_MOHMS 20
+#define DEFAULT_ESR_PULSE_THRESH_MA 110
+#define DEFAULT_ESR_MEAS_CURR_MA 120
static int fg_parse_dt(struct fg_chip *chip)
{
struct device_node *child, *revid_node, *node = chip->dev->of_node;
@@ -3767,6 +3942,8 @@ static int fg_parse_dt(struct fg_chip *chip)
chip->sp = pmi8998_v2_sram_params;
chip->alg_flags = pmi8998_v2_alg_flags;
chip->use_ima_single_mode = true;
+ if (chip->pmic_rev_id->fab_id == PM660_FAB_ID_TSMC)
+ chip->wa_flags |= PM660_TSMC_OSC_WA;
break;
default:
return -EINVAL;
@@ -3847,6 +4024,12 @@ static int fg_parse_dt(struct fg_chip *chip)
else
chip->dt.sys_term_curr_ma = temp;
+ rc = of_property_read_u32(node, "qcom,fg-chg-term-base-current", &temp);
+ if (rc < 0)
+ chip->dt.chg_term_base_curr_ma = DEFAULT_CHG_TERM_BASE_CURR_MA;
+ else
+ chip->dt.chg_term_base_curr_ma = temp;
+
rc = of_property_read_u32(node, "qcom,fg-delta-soc-thr", &temp);
if (rc < 0)
chip->dt.delta_soc_thr = DEFAULT_DELTA_SOC_THR;
@@ -4035,6 +4218,22 @@ static int fg_parse_dt(struct fg_chip *chip)
else
chip->dt.esr_clamp_mohms = temp;
+ chip->dt.esr_pulse_thresh_ma = DEFAULT_ESR_PULSE_THRESH_MA;
+ rc = of_property_read_u32(node, "qcom,fg-esr-pulse-thresh-ma", &temp);
+ if (!rc) {
+ /* ESR pulse qualification threshold range is 1-997 mA */
+ if (temp > 0 && temp < 997)
+ chip->dt.esr_pulse_thresh_ma = temp;
+ }
+
+ chip->dt.esr_meas_curr_ma = DEFAULT_ESR_MEAS_CURR_MA;
+ rc = of_property_read_u32(node, "qcom,fg-esr-meas-curr-ma", &temp);
+ if (!rc) {
+ /* ESR measurement current range is 60-240 mA */
+ if (temp >= 60 || temp <= 240)
+ chip->dt.esr_meas_curr_ma = temp;
+ }
+
return 0;
}
@@ -4069,6 +4268,7 @@ static int fg_gen3_probe(struct platform_device *pdev)
chip->irqs = fg_irqs;
chip->charge_status = -EINVAL;
chip->prev_charge_status = -EINVAL;
+ chip->ki_coeff_full_soc = -EINVAL;
chip->regmap = dev_get_regmap(chip->dev->parent, NULL);
if (!chip->regmap) {
dev_err(chip->dev, "Parent regmap is unavailable\n");
@@ -4085,6 +4285,21 @@ static int fg_gen3_probe(struct platform_device *pdev)
return rc;
}
+ rc = of_property_match_string(chip->dev->of_node,
+ "io-channel-names", "rradc_die_temp");
+ if (rc >= 0) {
+ chip->die_temp_chan = iio_channel_get(chip->dev,
+ "rradc_die_temp");
+ if (IS_ERR(chip->die_temp_chan)) {
+ if (PTR_ERR(chip->die_temp_chan) != -EPROBE_DEFER)
+ pr_err("rradc_die_temp unavailable %ld\n",
+ PTR_ERR(chip->die_temp_chan));
+ rc = PTR_ERR(chip->die_temp_chan);
+ chip->die_temp_chan = NULL;
+ return rc;
+ }
+ }
+
chip->awake_votable = create_votable("FG_WS", VOTE_SET_ANY, fg_awake_cb,
chip);
if (IS_ERR(chip->awake_votable)) {
diff --git a/drivers/power/supply/qcom/qpnp-qnovo.c b/drivers/power/supply/qcom/qpnp-qnovo.c
index c74dc8989821..eb97eb0ff2ac 100644
--- a/drivers/power/supply/qcom/qpnp-qnovo.c
+++ b/drivers/power/supply/qcom/qpnp-qnovo.c
@@ -89,7 +89,16 @@
#define QNOVO_STRM_CTRL 0xA8
#define QNOVO_IADC_OFFSET_OVR_VAL 0xA9
#define QNOVO_IADC_OFFSET_OVR 0xAA
+
#define QNOVO_DISABLE_CHARGING 0xAB
+#define ERR_SWITCHER_DISABLED BIT(7)
+#define ERR_JEITA_SOFT_CONDITION BIT(6)
+#define ERR_BAT_OV BIT(5)
+#define ERR_CV_MODE BIT(4)
+#define ERR_BATTERY_MISSING BIT(3)
+#define ERR_SAFETY_TIMER_EXPIRED BIT(2)
+#define ERR_CHARGING_DISABLED BIT(1)
+#define ERR_JEITA_HARD_CONDITION BIT(0)
#define QNOVO_TR_IADC_OFFSET_0 0xF1
#define QNOVO_TR_IADC_OFFSET_1 0xF2
@@ -1107,24 +1116,28 @@ static int qnovo_update_status(struct qnovo *chip)
{
u8 val = 0;
int rc;
- bool charging;
+ bool ok_to_qnovo;
bool changed = false;
rc = qnovo_read(chip, QNOVO_ERROR_STS2, &val, 1);
if (rc < 0) {
pr_err("Couldn't read error sts rc = %d\n", rc);
- charging = false;
+ ok_to_qnovo = false;
} else {
- charging = !(val & QNOVO_ERROR_CHARGING_DISABLED);
+ /*
+ * For CV mode keep qnovo enabled, userspace is expected to
+ * disable it after few runs
+ */
+ ok_to_qnovo = (val == ERR_CV_MODE || val == 0) ? true : false;
}
- if (chip->ok_to_qnovo ^ charging) {
+ if (chip->ok_to_qnovo ^ ok_to_qnovo) {
- vote(chip->disable_votable, OK_TO_QNOVO_VOTER, !charging, 0);
- if (!charging)
+ vote(chip->disable_votable, OK_TO_QNOVO_VOTER, !ok_to_qnovo, 0);
+ if (!ok_to_qnovo)
vote(chip->disable_votable, USER_VOTER, true, 0);
- chip->ok_to_qnovo = charging;
+ chip->ok_to_qnovo = ok_to_qnovo;
changed = true;
}
@@ -1247,6 +1260,16 @@ static int qnovo_hw_init(struct qnovo *chip)
chip->v_gain_mega = 1000000000 + (s64)(s8)vadc_gain * GAIN_LSB_FACTOR;
chip->v_gain_mega = div_s64(chip->v_gain_mega, 1000);
+ /* allow charger error conditions to disable qnovo, CV mode excluded */
+ val = ERR_SWITCHER_DISABLED | ERR_JEITA_SOFT_CONDITION | ERR_BAT_OV |
+ ERR_BATTERY_MISSING | ERR_SAFETY_TIMER_EXPIRED |
+ ERR_CHARGING_DISABLED | ERR_JEITA_HARD_CONDITION;
+ rc = qnovo_write(chip, QNOVO_DISABLE_CHARGING, &val, 1);
+ if (rc < 0) {
+ pr_err("Couldn't write QNOVO_DISABLE_CHARGING rc = %d\n", rc);
+ return rc;
+ }
+
return 0;
}
diff --git a/drivers/power/supply/qcom/qpnp-smb2.c b/drivers/power/supply/qcom/qpnp-smb2.c
index 4dfa43012b54..8855a1c74e0b 100644
--- a/drivers/power/supply/qcom/qpnp-smb2.c
+++ b/drivers/power/supply/qcom/qpnp-smb2.c
@@ -244,6 +244,8 @@ struct smb_dt_props {
int boost_threshold_ua;
int fv_uv;
int wipower_max_uw;
+ int min_freq_khz;
+ int max_freq_khz;
u32 step_soc_threshold[STEP_CHARGING_MAX_STEPS - 1];
s32 step_cc_delta[STEP_CHARGING_MAX_STEPS];
struct device_node *revid_dev_node;
@@ -338,6 +340,18 @@ static int smb2_parse_dt(struct smb2 *chip)
if (rc < 0)
chip->dt.boost_threshold_ua = MICRO_P1A;
+ rc = of_property_read_u32(node,
+ "qcom,min-freq-khz",
+ &chip->dt.min_freq_khz);
+ if (rc < 0)
+ chip->dt.min_freq_khz = -EINVAL;
+
+ rc = of_property_read_u32(node,
+ "qcom,max-freq-khz",
+ &chip->dt.max_freq_khz);
+ if (rc < 0)
+ chip->dt.max_freq_khz = -EINVAL;
+
rc = of_property_read_u32(node, "qcom,wipower-max-uw",
&chip->dt.wipower_max_uw);
if (rc < 0)
@@ -526,6 +540,12 @@ static int smb2_usb_set_prop(struct power_supply *psy,
struct smb_charger *chg = &chip->chg;
int rc = 0;
+ mutex_lock(&chg->lock);
+ if (!chg->typec_present) {
+ rc = -EINVAL;
+ goto unlock;
+ }
+
switch (psp) {
case POWER_SUPPLY_PROP_VOLTAGE_MIN:
rc = smblib_set_prop_usb_voltage_min(chg, val);
@@ -564,6 +584,8 @@ static int smb2_usb_set_prop(struct power_supply *psy,
break;
}
+unlock:
+ mutex_unlock(&chg->lock);
return rc;
}
@@ -1336,10 +1358,12 @@ static int smb2_configure_typec(struct smb_charger *chg)
return rc;
}
- /* disable try.SINK mode */
- rc = smblib_masked_write(chg, TYPE_C_CFG_3_REG, EN_TRYSINK_MODE_BIT, 0);
+ /* disable try.SINK mode and legacy cable IRQs */
+ rc = smblib_masked_write(chg, TYPE_C_CFG_3_REG, EN_TRYSINK_MODE_BIT |
+ TYPEC_NONCOMPLIANT_LEGACY_CABLE_INT_EN_BIT |
+ TYPEC_LEGACY_CABLE_INT_EN_BIT, 0);
if (rc < 0) {
- dev_err(chg->dev, "Couldn't set TRYSINK_MODE rc=%d\n", rc);
+ dev_err(chg->dev, "Couldn't set Type-C config rc=%d\n", rc);
return rc;
}
@@ -1438,6 +1462,16 @@ static int smb2_init_hw(struct smb2 *chip)
smblib_get_charge_param(chg, &chg->param.dc_icl,
&chip->dt.dc_icl_ua);
+ if (chip->dt.min_freq_khz > 0) {
+ chg->param.freq_buck.min_u = chip->dt.min_freq_khz;
+ chg->param.freq_boost.min_u = chip->dt.min_freq_khz;
+ }
+
+ if (chip->dt.max_freq_khz > 0) {
+ chg->param.freq_buck.max_u = chip->dt.max_freq_khz;
+ chg->param.freq_boost.max_u = chip->dt.max_freq_khz;
+ }
+
/* set a slower soft start setting for OTG */
rc = smblib_masked_write(chg, DC_ENG_SSUPPLY_CFG2_REG,
ENG_SSUPPLY_IVREF_OTG_SS_MASK, OTG_SS_SLOW);
@@ -1485,6 +1519,8 @@ static int smb2_init_hw(struct smb2 *chip)
DEFAULT_VOTER, true, chip->dt.dc_icl_ua);
vote(chg->hvdcp_disable_votable_indirect, PD_INACTIVE_VOTER,
true, 0);
+ vote(chg->hvdcp_disable_votable_indirect, VBUS_CC_SHORT_VOTER,
+ true, 0);
vote(chg->hvdcp_disable_votable_indirect, DEFAULT_VOTER,
chip->dt.hvdcp_disable, 0);
vote(chg->pd_disallowed_votable_indirect, CC_DETACHED_VOTER,
@@ -2022,6 +2058,16 @@ static int smb2_request_interrupts(struct smb2 *chip)
return rc;
}
+static void smb2_disable_interrupts(struct smb_charger *chg)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(smb2_irqs); i++) {
+ if (smb2_irqs[i].irq > 0)
+ disable_irq(smb2_irqs[i].irq);
+ }
+}
+
#if defined(CONFIG_DEBUG_FS)
static int force_batt_psy_update_write(void *data, u64 val)
@@ -2233,7 +2279,7 @@ static int smb2_probe(struct platform_device *pdev)
rc = smblib_get_prop_batt_health(chg, &val);
if (rc < 0) {
pr_err("Couldn't get batt health rc=%d\n", rc);
- goto cleanup;
+ val.intval = POWER_SUPPLY_HEALTH_UNKNOWN;
}
batt_health = val.intval;
@@ -2284,6 +2330,9 @@ static void smb2_shutdown(struct platform_device *pdev)
struct smb2 *chip = platform_get_drvdata(pdev);
struct smb_charger *chg = &chip->chg;
+ /* disable all interrupts */
+ smb2_disable_interrupts(chg);
+
/* configure power role for UFP */
smblib_masked_write(chg, TYPE_C_INTRPT_ENB_SOFTWARE_CTRL_REG,
TYPEC_POWER_ROLE_CMD_MASK, UFP_EN_CMD_BIT);
diff --git a/drivers/power/supply/qcom/smb-lib.c b/drivers/power/supply/qcom/smb-lib.c
index bd96703579f6..1e417e8aa22d 100644
--- a/drivers/power/supply/qcom/smb-lib.c
+++ b/drivers/power/supply/qcom/smb-lib.c
@@ -543,30 +543,6 @@ static void smblib_rerun_apsd(struct smb_charger *chg)
smblib_err(chg, "Couldn't re-run APSD rc=%d\n", rc);
}
-static int try_rerun_apsd_for_hvdcp(struct smb_charger *chg)
-{
- const struct apsd_result *apsd_result;
-
- /*
- * PD_INACTIVE_VOTER on hvdcp_disable_votable indicates whether
- * apsd rerun was tried earlier
- */
- if (get_client_vote(chg->hvdcp_disable_votable_indirect,
- PD_INACTIVE_VOTER)) {
- vote(chg->hvdcp_disable_votable_indirect,
- PD_INACTIVE_VOTER, false, 0);
- /* ensure hvdcp is enabled */
- if (!get_effective_result(
- chg->hvdcp_disable_votable_indirect)) {
- apsd_result = smblib_get_apsd_result(chg);
- if (apsd_result->bit & (QC_2P0_BIT | QC_3P0_BIT)) {
- smblib_rerun_apsd(chg);
- }
- }
- }
- return 0;
-}
-
static const struct apsd_result *smblib_update_usb_type(struct smb_charger *chg)
{
const struct apsd_result *apsd_result = smblib_get_apsd_result(chg);
@@ -685,6 +661,7 @@ static void smblib_uusb_removal(struct smb_charger *chg)
chg->voltage_max_uv = MICRO_5V;
chg->usb_icl_delta_ua = 0;
chg->pulse_cnt = 0;
+ chg->uusb_apsd_rerun_done = false;
/* clear USB ICL vote for USB_PSY_VOTER */
rc = vote(chg->usb_icl_votable, USB_PSY_VOTER, false, 0);
@@ -752,6 +729,7 @@ int smblib_rerun_apsd_if_required(struct smb_charger *chg)
rc);
}
+ chg->uusb_apsd_rerun_done = true;
smblib_rerun_apsd(chg);
return 0;
@@ -1021,6 +999,7 @@ static int smblib_hvdcp_enable_vote_callback(struct votable *votable,
struct smb_charger *chg = data;
int rc;
u8 val = HVDCP_AUTH_ALG_EN_CFG_BIT | HVDCP_EN_BIT;
+ u8 stat;
/* vote to enable/disable HW autonomous INOV */
vote(chg->hvdcp_hw_inov_dis_votable, client, !hvdcp_enable, 0);
@@ -1042,6 +1021,16 @@ static int smblib_hvdcp_enable_vote_callback(struct votable *votable,
return rc;
}
+ 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;
+ }
+
+ /* re-run APSD if HVDCP was detected */
+ if (stat & QC_CHARGER_BIT)
+ smblib_rerun_apsd(chg);
+
return 0;
}
@@ -1135,6 +1124,22 @@ static int smblib_usb_irq_enable_vote_callback(struct votable *votable,
return 0;
}
+static int smblib_typec_irq_disable_vote_callback(struct votable *votable,
+ void *data, int disable, const char *client)
+{
+ struct smb_charger *chg = data;
+
+ if (!chg->irq_info[TYPE_C_CHANGE_IRQ].irq)
+ return 0;
+
+ if (disable)
+ disable_irq_nosync(chg->irq_info[TYPE_C_CHANGE_IRQ].irq);
+ else
+ enable_irq(chg->irq_info[TYPE_C_CHANGE_IRQ].irq);
+
+ return 0;
+}
+
/*******************
* VCONN REGULATOR *
* *****************/
@@ -1143,7 +1148,7 @@ static int smblib_usb_irq_enable_vote_callback(struct votable *votable,
static int _smblib_vconn_regulator_enable(struct regulator_dev *rdev)
{
struct smb_charger *chg = rdev_get_drvdata(rdev);
- u8 otg_stat, stat4;
+ u8 otg_stat, val;
int rc = 0, i;
if (!chg->external_vconn) {
@@ -1174,17 +1179,12 @@ static int _smblib_vconn_regulator_enable(struct regulator_dev *rdev)
* VCONN_EN_ORIENTATION is overloaded with overriding the CC pin used
* for Vconn, and it should be set with reverse polarity of CC_OUT.
*/
- rc = smblib_read(chg, TYPE_C_STATUS_4_REG, &stat4);
- if (rc < 0) {
- smblib_err(chg, "Couldn't read TYPE_C_STATUS_4 rc=%d\n", rc);
- return rc;
- }
-
smblib_dbg(chg, PR_OTG, "enabling VCONN\n");
- stat4 = stat4 & CC_ORIENTATION_BIT ? 0 : VCONN_EN_ORIENTATION_BIT;
+ val = chg->typec_status[3] &
+ CC_ORIENTATION_BIT ? 0 : VCONN_EN_ORIENTATION_BIT;
rc = smblib_masked_write(chg, TYPE_C_INTRPT_ENB_SOFTWARE_CTRL_REG,
VCONN_EN_VALUE_BIT | VCONN_EN_ORIENTATION_BIT,
- VCONN_EN_VALUE_BIT | stat4);
+ VCONN_EN_VALUE_BIT | val);
if (rc < 0) {
smblib_err(chg, "Couldn't enable vconn setting rc=%d\n", rc);
return rc;
@@ -1532,6 +1532,21 @@ int smblib_get_prop_batt_status(struct smb_charger *chg,
break;
}
+ if (val->intval != POWER_SUPPLY_STATUS_CHARGING)
+ return 0;
+
+ rc = smblib_read(chg, BATTERY_CHARGER_STATUS_7_REG, &stat);
+ if (rc < 0) {
+ smblib_err(chg, "Couldn't read BATTERY_CHARGER_STATUS_2 rc=%d\n",
+ rc);
+ return rc;
+ }
+
+ stat &= ENABLE_TRICKLE_BIT | ENABLE_PRE_CHARGING_BIT |
+ ENABLE_FAST_CHARGING_BIT | ENABLE_FULLON_MODE_BIT;
+ if (!stat)
+ val->intval = POWER_SUPPLY_STATUS_NOT_CHARGING;
+
return 0;
}
@@ -2132,23 +2147,13 @@ int smblib_get_prop_charger_temp_max(struct smb_charger *chg,
int smblib_get_prop_typec_cc_orientation(struct smb_charger *chg,
union power_supply_propval *val)
{
- int rc = 0;
- u8 stat;
-
- rc = smblib_read(chg, TYPE_C_STATUS_4_REG, &stat);
- if (rc < 0) {
- smblib_err(chg, "Couldn't read TYPE_C_STATUS_4 rc=%d\n", rc);
- return rc;
- }
- smblib_dbg(chg, PR_REGISTER, "TYPE_C_STATUS_4 = 0x%02x\n",
- stat);
-
- if (stat & CC_ATTACHED_BIT)
- val->intval = (bool)(stat & CC_ORIENTATION_BIT) + 1;
+ if (chg->typec_status[3] & CC_ATTACHED_BIT)
+ val->intval =
+ (bool)(chg->typec_status[3] & CC_ORIENTATION_BIT) + 1;
else
val->intval = 0;
- return rc;
+ return 0;
}
static const char * const smblib_typec_mode_name[] = {
@@ -2166,17 +2171,7 @@ static const char * const smblib_typec_mode_name[] = {
static int smblib_get_prop_ufp_mode(struct smb_charger *chg)
{
- int rc;
- u8 stat;
-
- rc = smblib_read(chg, TYPE_C_STATUS_1_REG, &stat);
- if (rc < 0) {
- smblib_err(chg, "Couldn't read TYPE_C_STATUS_1 rc=%d\n", rc);
- return POWER_SUPPLY_TYPEC_NONE;
- }
- smblib_dbg(chg, PR_REGISTER, "TYPE_C_STATUS_1 = 0x%02x\n", stat);
-
- switch (stat) {
+ switch (chg->typec_status[0]) {
case 0:
return POWER_SUPPLY_TYPEC_NONE;
case UFP_TYPEC_RDSTD_BIT:
@@ -2194,17 +2189,7 @@ static int smblib_get_prop_ufp_mode(struct smb_charger *chg)
static int smblib_get_prop_dfp_mode(struct smb_charger *chg)
{
- int rc;
- u8 stat;
-
- rc = smblib_read(chg, TYPE_C_STATUS_2_REG, &stat);
- if (rc < 0) {
- smblib_err(chg, "Couldn't read TYPE_C_STATUS_2 rc=%d\n", rc);
- return POWER_SUPPLY_TYPEC_NONE;
- }
- smblib_dbg(chg, PR_REGISTER, "TYPE_C_STATUS_2 = 0x%02x\n", stat);
-
- switch (stat & DFP_TYPEC_MASK) {
+ switch (chg->typec_status[1] & DFP_TYPEC_MASK) {
case DFP_RA_RA_BIT:
return POWER_SUPPLY_TYPEC_SINK_AUDIO_ADAPTER;
case DFP_RD_RD_BIT:
@@ -2225,28 +2210,17 @@ static int smblib_get_prop_dfp_mode(struct smb_charger *chg)
int smblib_get_prop_typec_mode(struct smb_charger *chg,
union power_supply_propval *val)
{
- int rc;
- u8 stat;
-
- rc = smblib_read(chg, TYPE_C_STATUS_4_REG, &stat);
- if (rc < 0) {
- smblib_err(chg, "Couldn't read TYPE_C_STATUS_4 rc=%d\n", rc);
+ if (!(chg->typec_status[3] & TYPEC_DEBOUNCE_DONE_STATUS_BIT)) {
val->intval = POWER_SUPPLY_TYPEC_NONE;
- return rc;
- }
- smblib_dbg(chg, PR_REGISTER, "TYPE_C_STATUS_4 = 0x%02x\n", stat);
-
- if (!(stat & TYPEC_DEBOUNCE_DONE_STATUS_BIT)) {
- val->intval = POWER_SUPPLY_TYPEC_NONE;
- return rc;
+ return 0;
}
- if (stat & UFP_DFP_MODE_STATUS_BIT)
+ if (chg->typec_status[3] & UFP_DFP_MODE_STATUS_BIT)
val->intval = smblib_get_prop_dfp_mode(chg);
else
val->intval = smblib_get_prop_ufp_mode(chg);
- return rc;
+ return 0;
}
int smblib_get_prop_typec_power_role(struct smb_charger *chg,
@@ -2338,16 +2312,7 @@ int smblib_get_prop_input_voltage_settled(struct smb_charger *chg,
int smblib_get_prop_pd_in_hard_reset(struct smb_charger *chg,
union power_supply_propval *val)
{
- int rc;
- u8 ctrl;
-
- rc = smblib_read(chg, TYPE_C_INTRPT_ENB_SOFTWARE_CTRL_REG, &ctrl);
- if (rc < 0) {
- smblib_err(chg, "Couldn't read TYPE_C_INTRPT_ENB_SOFTWARE_CTRL_REG rc=%d\n",
- rc);
- return rc;
- }
- val->intval = ctrl & EXIT_SNK_BASED_ON_CC_BIT;
+ val->intval = chg->pd_hard_reset;
return 0;
}
@@ -2543,53 +2508,60 @@ int smblib_set_prop_pd_active(struct smb_charger *chg,
const union power_supply_propval *val)
{
int rc;
- u8 stat = 0;
- bool cc_debounced;
- bool orientation;
- bool pd_active = val->intval;
+ bool orientation, cc_debounced, sink_attached, hvdcp;
+ u8 stat;
- if (!get_effective_result(chg->pd_allowed_votable)) {
- smblib_err(chg, "PD is not allowed\n");
+ if (!get_effective_result(chg->pd_allowed_votable))
return -EINVAL;
- }
- vote(chg->apsd_disable_votable, PD_VOTER, pd_active, 0);
- vote(chg->pd_allowed_votable, PD_VOTER, pd_active, 0);
- vote(chg->usb_irq_enable_votable, PD_VOTER, pd_active, 0);
-
- /*
- * VCONN_EN_ORIENTATION_BIT controls whether to use CC1 or CC2 line
- * when TYPEC_SPARE_CFG_BIT (CC pin selection s/w override) is set
- * or when VCONN_EN_VALUE_BIT is set.
- */
- rc = smblib_read(chg, TYPE_C_STATUS_4_REG, &stat);
+ rc = smblib_read(chg, APSD_STATUS_REG, &stat);
if (rc < 0) {
- smblib_err(chg, "Couldn't read TYPE_C_STATUS_4 rc=%d\n", rc);
+ smblib_err(chg, "Couldn't read APSD status rc=%d\n", rc);
return rc;
}
- if (pd_active) {
- orientation = stat & CC_ORIENTATION_BIT;
+ 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);
+ vote(chg->pd_allowed_votable, PD_VOTER, true, 0);
+ vote(chg->usb_irq_enable_votable, PD_VOTER, true, 0);
+
+ /*
+ * VCONN_EN_ORIENTATION_BIT controls whether to use CC1 or CC2
+ * line when TYPEC_SPARE_CFG_BIT (CC pin selection s/w override)
+ * is set or when VCONN_EN_VALUE_BIT is set.
+ */
+ orientation = chg->typec_status[3] & CC_ORIENTATION_BIT;
rc = smblib_masked_write(chg,
TYPE_C_INTRPT_ENB_SOFTWARE_CTRL_REG,
VCONN_EN_ORIENTATION_BIT,
orientation ? 0 : VCONN_EN_ORIENTATION_BIT);
- if (rc < 0) {
+ if (rc < 0)
smblib_err(chg,
"Couldn't enable vconn on CC line rc=%d\n", rc);
- return rc;
- }
+
+ /* SW controlled CC_OUT */
+ rc = smblib_masked_write(chg, TAPER_TIMER_SEL_CFG_REG,
+ TYPEC_SPARE_CFG_BIT, TYPEC_SPARE_CFG_BIT);
+ if (rc < 0)
+ smblib_err(chg, "Couldn't enable SW cc_out rc=%d\n",
+ rc);
+
/*
* Enforce 500mA for PD until the real vote comes in later.
* It is guaranteed that pd_active is set prior to
* pd_current_max
*/
rc = vote(chg->usb_icl_votable, PD_VOTER, true, USBIN_500MA);
- if (rc < 0) {
+ if (rc < 0)
smblib_err(chg, "Couldn't vote for USB ICL rc=%d\n",
- rc);
- return rc;
- }
+ rc);
/* since PD was found the cable must be non-legacy */
vote(chg->usb_icl_votable, LEGACY_UNKNOWN_VOTER, false, 0);
@@ -2597,36 +2569,40 @@ int smblib_set_prop_pd_active(struct smb_charger *chg,
/* clear USB ICL vote for DCP_VOTER */
rc = vote(chg->usb_icl_votable, DCP_VOTER, false, 0);
if (rc < 0)
- smblib_err(chg,
- "Couldn't un-vote DCP from USB ICL rc=%d\n",
- rc);
+ smblib_err(chg, "Couldn't un-vote DCP from USB ICL rc=%d\n",
+ rc);
/* remove USB_PSY_VOTER */
rc = vote(chg->usb_icl_votable, USB_PSY_VOTER, false, 0);
- if (rc < 0) {
+ if (rc < 0)
smblib_err(chg, "Couldn't unvote USB_PSY rc=%d\n", rc);
- return rc;
- }
- }
+ } else {
+ 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);
+ vote(chg->hvdcp_disable_votable_indirect, PD_INACTIVE_VOTER,
+ false, 0);
- /* CC pin selection s/w override in PD session; h/w otherwise. */
- rc = smblib_masked_write(chg, TAPER_TIMER_SEL_CFG_REG,
- TYPEC_SPARE_CFG_BIT,
- pd_active ? TYPEC_SPARE_CFG_BIT : 0);
- if (rc < 0) {
- smblib_err(chg, "Couldn't change cc_out ctrl to %s rc=%d\n",
- pd_active ? "SW" : "HW", rc);
- return rc;
- }
+ /* HW controlled CC_OUT */
+ rc = smblib_masked_write(chg, TAPER_TIMER_SEL_CFG_REG,
+ TYPEC_SPARE_CFG_BIT, 0);
+ if (rc < 0)
+ smblib_err(chg, "Couldn't enable HW cc_out rc=%d\n",
+ rc);
- cc_debounced = (bool)(stat & TYPEC_DEBOUNCE_DONE_STATUS_BIT);
- if (!pd_active && cc_debounced)
- try_rerun_apsd_for_hvdcp(chg);
+ /*
+ * This WA should only run for HVDCP. Non-legacy SDP/CDP could
+ * draw more, but this WA will remove Rd causing VBUS to drop,
+ * 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)
+ schedule_work(&chg->legacy_detection_work);
+ }
- chg->pd_active = pd_active;
smblib_update_usb_type(chg);
power_supply_changed(chg->usb_psy);
-
return rc;
}
@@ -2729,88 +2705,70 @@ static struct reg_info cc2_detach_settings[] = {
static int smblib_cc2_sink_removal_enter(struct smb_charger *chg)
{
- int rc = 0;
- union power_supply_propval cc2_val = {0, };
+ int rc, ccout, ufp_mode;
+ u8 stat;
if ((chg->wa_flags & TYPEC_CC2_REMOVAL_WA_BIT) == 0)
- return rc;
+ return 0;
- if (chg->cc2_sink_detach_flag != CC2_SINK_NONE)
- return rc;
+ if (chg->cc2_detach_wa_active)
+ return 0;
- rc = smblib_get_prop_typec_cc_orientation(chg, &cc2_val);
+ rc = smblib_read(chg, TYPE_C_STATUS_4_REG, &stat);
if (rc < 0) {
- smblib_err(chg, "Couldn't get cc orientation rc=%d\n", rc);
+ smblib_err(chg, "Couldn't read TYPE_C_STATUS_4 rc=%d\n", rc);
return rc;
}
- if (cc2_val.intval == 1)
- return rc;
+ ccout = (stat & CC_ATTACHED_BIT) ?
+ (!!(stat & CC_ORIENTATION_BIT) + 1) : 0;
+ ufp_mode = (stat & TYPEC_DEBOUNCE_DONE_STATUS_BIT) ?
+ !(stat & UFP_DFP_MODE_STATUS_BIT) : 0;
- rc = smblib_get_prop_typec_mode(chg, &cc2_val);
- if (rc < 0) {
- smblib_err(chg, "Couldn't get prop typec mode rc=%d\n", rc);
- return rc;
- }
+ if (ccout != 2)
+ return 0;
- switch (cc2_val.intval) {
- case POWER_SUPPLY_TYPEC_SOURCE_DEFAULT:
- smblib_reg_block_update(chg, cc2_detach_settings);
- chg->cc2_sink_detach_flag = CC2_SINK_STD;
- schedule_work(&chg->rdstd_cc2_detach_work);
- break;
- case POWER_SUPPLY_TYPEC_SOURCE_MEDIUM:
- case POWER_SUPPLY_TYPEC_SOURCE_HIGH:
- chg->cc2_sink_detach_flag = CC2_SINK_MEDIUM_HIGH;
- break;
- default:
- break;
- }
+ if (!ufp_mode)
+ return 0;
+ chg->cc2_detach_wa_active = true;
+ /* The CC2 removal WA will cause a type-c-change IRQ storm */
+ smblib_reg_block_update(chg, cc2_detach_settings);
+ schedule_work(&chg->rdstd_cc2_detach_work);
return rc;
}
static int smblib_cc2_sink_removal_exit(struct smb_charger *chg)
{
- int rc = 0;
-
if ((chg->wa_flags & TYPEC_CC2_REMOVAL_WA_BIT) == 0)
- return rc;
-
- if (chg->cc2_sink_detach_flag == CC2_SINK_STD) {
- cancel_work_sync(&chg->rdstd_cc2_detach_work);
- smblib_reg_block_restore(chg, cc2_detach_settings);
- }
+ return 0;
- chg->cc2_sink_detach_flag = CC2_SINK_NONE;
+ if (!chg->cc2_detach_wa_active)
+ return 0;
- return rc;
+ chg->cc2_detach_wa_active = false;
+ cancel_work_sync(&chg->rdstd_cc2_detach_work);
+ smblib_reg_block_restore(chg, cc2_detach_settings);
+ return 0;
}
int smblib_set_prop_pd_in_hard_reset(struct smb_charger *chg,
const union power_supply_propval *val)
{
- int rc;
+ int rc = 0;
- rc = smblib_masked_write(chg, TYPE_C_INTRPT_ENB_SOFTWARE_CTRL_REG,
- EXIT_SNK_BASED_ON_CC_BIT,
- (val->intval) ? EXIT_SNK_BASED_ON_CC_BIT : 0);
- if (rc < 0) {
- smblib_err(chg, "Could not set EXIT_SNK_BASED_ON_CC rc=%d\n",
- rc);
+ if (chg->pd_hard_reset == val->intval)
return rc;
- }
- vote(chg->apsd_disable_votable, PD_HARD_RESET_VOTER, val->intval, 0);
+ chg->pd_hard_reset = val->intval;
+ rc = smblib_masked_write(chg, TYPE_C_INTRPT_ENB_SOFTWARE_CTRL_REG,
+ EXIT_SNK_BASED_ON_CC_BIT,
+ (chg->pd_hard_reset) ? EXIT_SNK_BASED_ON_CC_BIT : 0);
+ if (rc < 0)
+ smblib_err(chg, "Couldn't set EXIT_SNK_BASED_ON_CC rc=%d\n",
+ rc);
- if (val->intval)
- rc = smblib_cc2_sink_removal_enter(chg);
- else
- rc = smblib_cc2_sink_removal_exit(chg);
-
- if (rc < 0) {
- smblib_err(chg, "Could not detect cc2 removal rc=%d\n", rc);
- return rc;
- }
+ vote(chg->apsd_disable_votable, PD_HARD_RESET_VOTER,
+ chg->pd_hard_reset, 0);
return rc;
}
@@ -3117,25 +3075,43 @@ irqreturn_t smblib_handle_usbin_uv(int irq, void *data)
return IRQ_HANDLED;
}
+static void smblib_micro_usb_plugin(struct smb_charger *chg, bool vbus_rising)
+{
+ if (vbus_rising) {
+ /* use the typec flag even though its not typec */
+ chg->typec_present = 1;
+ } else {
+ chg->typec_present = 0;
+ smblib_update_usb_type(chg);
+ extcon_set_cable_state_(chg->extcon, EXTCON_USB, false);
+ smblib_uusb_removal(chg);
+ }
+}
+
+static void smblib_typec_usb_plugin(struct smb_charger *chg, bool vbus_rising)
+{
+ if (vbus_rising)
+ smblib_cc2_sink_removal_exit(chg);
+ else
+ smblib_cc2_sink_removal_enter(chg);
+}
+
#define PL_DELAY_MS 30000
-irqreturn_t smblib_handle_usb_plugin(int irq, void *data)
+void smblib_usb_plugin_locked(struct smb_charger *chg)
{
- struct smb_irq_data *irq_data = data;
- struct smb_charger *chg = irq_data->parent_data;
int rc;
u8 stat;
bool vbus_rising;
rc = smblib_read(chg, USBIN_BASE + INT_RT_STS_OFFSET, &stat);
if (rc < 0) {
- dev_err(chg->dev, "Couldn't read USB_INT_RT_STS rc=%d\n", rc);
- return IRQ_HANDLED;
+ smblib_err(chg, "Couldn't read USB_INT_RT_STS rc=%d\n", rc);
+ return;
}
vbus_rising = (bool)(stat & USBIN_PLUGIN_RT_STS_BIT);
- smblib_set_opt_freq_buck(chg,
- vbus_rising ? chg->chg_freq.freq_5V :
- chg->chg_freq.freq_removal);
+ smblib_set_opt_freq_buck(chg, vbus_rising ? chg->chg_freq.freq_5V :
+ chg->chg_freq.freq_removal);
/* fetch the DPDM regulator */
if (!chg->dpdm_reg && of_get_property(chg->dev->of_node,
@@ -3172,17 +3148,26 @@ irqreturn_t smblib_handle_usb_plugin(int irq, void *data)
smblib_err(chg, "Couldn't disable dpdm regulator rc=%d\n",
rc);
}
-
- if (chg->micro_usb_mode) {
- smblib_update_usb_type(chg);
- extcon_set_cable_state_(chg->extcon, EXTCON_USB, false);
- smblib_uusb_removal(chg);
- }
}
+ if (chg->micro_usb_mode)
+ smblib_micro_usb_plugin(chg, vbus_rising);
+ else
+ smblib_typec_usb_plugin(chg, vbus_rising);
+
power_supply_changed(chg->usb_psy);
- smblib_dbg(chg, PR_INTERRUPT, "IRQ: %s %s\n",
- irq_data->name, vbus_rising ? "attached" : "detached");
+ smblib_dbg(chg, PR_INTERRUPT, "IRQ: usbin-plugin %s\n",
+ vbus_rising ? "attached" : "detached");
+}
+
+irqreturn_t smblib_handle_usb_plugin(int irq, void *data)
+{
+ struct smb_irq_data *irq_data = data;
+ struct smb_charger *chg = irq_data->parent_data;
+
+ mutex_lock(&chg->lock);
+ smblib_usb_plugin_locked(chg);
+ mutex_unlock(&chg->lock);
return IRQ_HANDLED;
}
@@ -3351,9 +3336,6 @@ static void smblib_handle_hvdcp_check_timeout(struct smb_charger *chg,
if (rising) {
vote(chg->pd_disallowed_votable_indirect, HVDCP_TIMEOUT_VOTER,
false, 0);
- if (get_effective_result(chg->pd_disallowed_votable_indirect))
- /* could be a legacy cable, try doing hvdcp */
- try_rerun_apsd_for_hvdcp(chg);
/* enable HDC and ICL irq for QC2/3 charger */
if (qc_charger)
@@ -3388,6 +3370,10 @@ static void smblib_handle_hvdcp_detect_done(struct smb_charger *chg,
static void smblib_force_legacy_icl(struct smb_charger *chg, int pst)
{
+ /* while PD is active it should have complete ICL control */
+ if (chg->pd_active)
+ return;
+
switch (pst) {
case POWER_SUPPLY_TYPE_USB:
/*
@@ -3427,7 +3413,7 @@ static void smblib_handle_apsd_done(struct smb_charger *chg, bool rising)
apsd_result = smblib_update_usb_type(chg);
- if (!chg->pd_active)
+ if (!chg->typec_legacy_valid)
smblib_force_legacy_icl(chg, apsd_result->pst);
switch (apsd_result->bit) {
@@ -3469,6 +3455,17 @@ irqreturn_t smblib_handle_usb_source_change(int irq, void *data)
}
smblib_dbg(chg, PR_REGISTER, "APSD_STATUS = 0x%02x\n", stat);
+ if (chg->micro_usb_mode && (stat & APSD_DTC_STATUS_DONE_BIT)
+ && !chg->uusb_apsd_rerun_done) {
+ /*
+ * Force re-run APSD to handle slow insertion related
+ * charger-mis-detection.
+ */
+ chg->uusb_apsd_rerun_done = true;
+ smblib_rerun_apsd(chg);
+ return IRQ_HANDLED;
+ }
+
smblib_handle_apsd_done(chg,
(bool)(stat & APSD_DTC_STATUS_DONE_BIT));
@@ -3502,71 +3499,6 @@ irqreturn_t smblib_handle_usb_source_change(int irq, void *data)
return IRQ_HANDLED;
}
-static void typec_source_removal(struct smb_charger *chg)
-{
- int rc;
-
- /* reset legacy unknown vote */
- vote(chg->usb_icl_votable, LEGACY_UNKNOWN_VOTER, false, 0);
-
- /* reset both usbin current and voltage votes */
- vote(chg->pl_enable_votable_indirect, USBIN_I_VOTER, false, 0);
- vote(chg->pl_enable_votable_indirect, USBIN_V_VOTER, false, 0);
-
- cancel_delayed_work_sync(&chg->hvdcp_detect_work);
-
- if (chg->wa_flags & QC_AUTH_INTERRUPT_WA_BIT) {
- /* re-enable AUTH_IRQ_EN_CFG_BIT */
- rc = smblib_masked_write(chg,
- USBIN_SOURCE_CHANGE_INTRPT_ENB_REG,
- AUTH_IRQ_EN_CFG_BIT, AUTH_IRQ_EN_CFG_BIT);
- if (rc < 0)
- smblib_err(chg,
- "Couldn't enable QC auth setting rc=%d\n", rc);
- }
-
- /* reconfigure allowed voltage for HVDCP */
- rc = smblib_set_adapter_allowance(chg,
- USBIN_ADAPTER_ALLOW_5V_OR_9V_TO_12V);
- if (rc < 0)
- smblib_err(chg, "Couldn't set USBIN_ADAPTER_ALLOW_5V_OR_9V_TO_12V rc=%d\n",
- rc);
-
- chg->voltage_min_uv = MICRO_5V;
- chg->voltage_max_uv = MICRO_5V;
-
- /* clear USB ICL vote for PD_VOTER */
- rc = vote(chg->usb_icl_votable, PD_VOTER, false, 0);
- if (rc < 0)
- smblib_err(chg, "Couldn't un-vote PD from USB ICL rc=%d\n", rc);
-
- /* clear USB ICL vote for USB_PSY_VOTER */
- rc = vote(chg->usb_icl_votable, USB_PSY_VOTER, false, 0);
- if (rc < 0)
- smblib_err(chg,
- "Couldn't un-vote USB_PSY from USB ICL rc=%d\n", rc);
-
- /* clear USB ICL vote for DCP_VOTER */
- rc = vote(chg->usb_icl_votable, DCP_VOTER, false, 0);
- if (rc < 0)
- smblib_err(chg,
- "Couldn't un-vote DCP from USB ICL rc=%d\n", rc);
-
-}
-
-static void typec_source_insertion(struct smb_charger *chg)
-{
- /*
- * at any time we want LEGACY_UNKNOWN, PD, or USB_PSY to be voting for
- * ICL, so vote LEGACY_UNKNOWN here if none of the above three have
- * casted their votes
- */
- if (!is_client_vote_enabled(chg->usb_icl_votable, LEGACY_UNKNOWN_VOTER)
- && !is_client_vote_enabled(chg->usb_icl_votable, PD_VOTER)
- && !is_client_vote_enabled(chg->usb_icl_votable, USB_PSY_VOTER))
- vote(chg->usb_icl_votable, LEGACY_UNKNOWN_VOTER, true, 100000);
-}
-
static void typec_sink_insertion(struct smb_charger *chg)
{
/* when a sink is inserted we should not wait on hvdcp timeout to
@@ -3587,30 +3519,50 @@ static void smblib_handle_typec_removal(struct smb_charger *chg)
{
int rc;
+ chg->cc2_detach_wa_active = false;
+
+ /* reset APSD voters */
+ vote(chg->apsd_disable_votable, PD_HARD_RESET_VOTER, false, 0);
+ vote(chg->apsd_disable_votable, PD_VOTER, false, 0);
+
cancel_delayed_work_sync(&chg->pl_enable_work);
- vote(chg->pl_disable_votable, PL_DELAY_VOTER, true, 0);
- vote(chg->awake_votable, PL_DELAY_VOTER, false, 0);
+ cancel_delayed_work_sync(&chg->hvdcp_detect_work);
+
+ /* reset input current limit voters */
+ vote(chg->usb_icl_votable, LEGACY_UNKNOWN_VOTER, true, 100000);
+ vote(chg->usb_icl_votable, PD_VOTER, false, 0);
+ vote(chg->usb_icl_votable, USB_PSY_VOTER, false, 0);
+ vote(chg->usb_icl_votable, DCP_VOTER, false, 0);
+ vote(chg->usb_icl_votable, PL_USBIN_USBIN_VOTER, false, 0);
+ /* reset hvdcp voters */
+ vote(chg->hvdcp_disable_votable_indirect, VBUS_CC_SHORT_VOTER, true, 0);
+ vote(chg->hvdcp_disable_votable_indirect, PD_INACTIVE_VOTER, true, 0);
+
+ /* reset power delivery voters */
+ vote(chg->pd_allowed_votable, PD_VOTER, false, 0);
vote(chg->pd_disallowed_votable_indirect, CC_DETACHED_VOTER, true, 0);
vote(chg->pd_disallowed_votable_indirect, HVDCP_TIMEOUT_VOTER, true, 0);
+
+ /* reset usb irq voters */
vote(chg->usb_irq_enable_votable, PD_VOTER, false, 0);
vote(chg->usb_irq_enable_votable, QC_VOTER, false, 0);
- /* reset votes from vbus_cc_short */
- vote(chg->hvdcp_disable_votable_indirect, VBUS_CC_SHORT_VOTER,
- true, 0);
- vote(chg->hvdcp_disable_votable_indirect, PD_INACTIVE_VOTER,
- true, 0);
- /*
- * cable could be removed during hard reset, remove its vote to
- * disable apsd
- */
- vote(chg->apsd_disable_votable, PD_HARD_RESET_VOTER, false, 0);
+ /* reset parallel voters */
+ vote(chg->pl_disable_votable, PL_DELAY_VOTER, true, 0);
+ vote(chg->pl_enable_votable_indirect, USBIN_I_VOTER, false, 0);
+ vote(chg->pl_enable_votable_indirect, USBIN_V_VOTER, false, 0);
+ vote(chg->awake_votable, PL_DELAY_VOTER, false, 0);
chg->vconn_attempts = 0;
chg->otg_attempts = 0;
chg->pulse_cnt = 0;
chg->usb_icl_delta_ua = 0;
+ chg->voltage_min_uv = MICRO_5V;
+ chg->voltage_max_uv = MICRO_5V;
+ chg->pd_active = 0;
+ chg->pd_hard_reset = 0;
+ chg->typec_legacy_valid = false;
/* enable APSD CC trigger for next insertion */
rc = smblib_masked_write(chg, TYPE_C_CFG_REG,
@@ -3618,15 +3570,48 @@ static void smblib_handle_typec_removal(struct smb_charger *chg)
if (rc < 0)
smblib_err(chg, "Couldn't enable APSD_START_ON_CC rc=%d\n", rc);
- smblib_update_usb_type(chg);
- typec_source_removal(chg);
+ if (chg->wa_flags & QC_AUTH_INTERRUPT_WA_BIT) {
+ /* re-enable AUTH_IRQ_EN_CFG_BIT */
+ rc = smblib_masked_write(chg,
+ USBIN_SOURCE_CHANGE_INTRPT_ENB_REG,
+ AUTH_IRQ_EN_CFG_BIT, AUTH_IRQ_EN_CFG_BIT);
+ if (rc < 0)
+ smblib_err(chg,
+ "Couldn't enable QC auth setting rc=%d\n", rc);
+ }
+
+ /* reconfigure allowed voltage for HVDCP */
+ rc = smblib_set_adapter_allowance(chg,
+ USBIN_ADAPTER_ALLOW_5V_OR_9V_TO_12V);
+ if (rc < 0)
+ smblib_err(chg, "Couldn't set USBIN_ADAPTER_ALLOW_5V_OR_9V_TO_12V rc=%d\n",
+ rc);
+
+ /* enable DRP */
+ rc = smblib_masked_write(chg, TYPE_C_INTRPT_ENB_SOFTWARE_CTRL_REG,
+ TYPEC_POWER_ROLE_CMD_MASK, 0);
+ if (rc < 0)
+ smblib_err(chg, "Couldn't enable DRP rc=%d\n", rc);
+
+ /* HW controlled CC_OUT */
+ rc = smblib_masked_write(chg, TAPER_TIMER_SEL_CFG_REG,
+ TYPEC_SPARE_CFG_BIT, 0);
+ if (rc < 0)
+ smblib_err(chg, "Couldn't enable HW cc_out rc=%d\n", rc);
+
+ /* restore crude sensor */
+ rc = smblib_write(chg, TM_IO_DTEST4_SEL, 0xA5);
+ if (rc < 0)
+ smblib_err(chg, "Couldn't restore crude sensor 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, bool legacy_cable)
+ bool sink_attached)
{
- int rp, rc;
+ int rc;
vote(chg->pd_disallowed_votable_indirect, CC_DETACHED_VOTER, false, 0);
@@ -3636,59 +3621,36 @@ 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) {
- typec_source_removal(chg);
+ if (sink_attached)
typec_sink_insertion(chg);
- } else {
- typec_source_insertion(chg);
+ else
typec_sink_removal(chg);
- }
-
- rp = smblib_get_prop_ufp_mode(chg);
- if (rp == POWER_SUPPLY_TYPEC_SOURCE_HIGH
- || rp == POWER_SUPPLY_TYPEC_NON_COMPLIANT) {
- smblib_dbg(chg, PR_MISC, "VBUS & CC could be shorted; keeping HVDCP disabled\n");
- vote(chg->hvdcp_disable_votable_indirect, VBUS_CC_SHORT_VOTER,
- true, 0);
- } else {
- vote(chg->hvdcp_disable_votable_indirect, VBUS_CC_SHORT_VOTER,
- false, 0);
- }
}
static void smblib_handle_typec_debounce_done(struct smb_charger *chg,
- bool rising, bool sink_attached, bool legacy_cable)
+ bool rising, bool sink_attached)
{
int rc;
union power_supply_propval pval = {0, };
- if (rising)
- smblib_handle_typec_insertion(chg, sink_attached, legacy_cable);
- else
- smblib_handle_typec_removal(chg);
+ 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);
+ }
+ }
rc = smblib_get_prop_typec_mode(chg, &pval);
if (rc < 0)
smblib_err(chg, "Couldn't get prop typec mode rc=%d\n", rc);
- /*
- * HW BUG - after cable is removed, medium or high rd reading
- * falls to std. Use it for signal of typec cc detachment in
- * software WA.
- */
- if (chg->cc2_sink_detach_flag == CC2_SINK_MEDIUM_HIGH
- && pval.intval == POWER_SUPPLY_TYPEC_SOURCE_DEFAULT) {
-
- chg->cc2_sink_detach_flag = CC2_SINK_WA_DONE;
-
- 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 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]);
@@ -3714,50 +3676,54 @@ irqreturn_t smblib_handle_usb_typec_change_for_uusb(struct smb_charger *chg)
return IRQ_HANDLED;
}
-irqreturn_t smblib_handle_usb_typec_change(int irq, void *data)
+static void smblib_usb_typec_change(struct smb_charger *chg)
{
- struct smb_irq_data *irq_data = data;
- struct smb_charger *chg = irq_data->parent_data;
int rc;
- u8 stat4, stat5;
- bool debounce_done, sink_attached, legacy_cable;
-
- if (chg->micro_usb_mode)
- return smblib_handle_usb_typec_change_for_uusb(chg);
-
- /* WA - not when PD hard_reset WIP on cc2 in sink mode */
- if (chg->cc2_sink_detach_flag == CC2_SINK_STD)
- return IRQ_HANDLED;
-
- rc = smblib_read(chg, TYPE_C_STATUS_4_REG, &stat4);
- if (rc < 0) {
- smblib_err(chg, "Couldn't read TYPE_C_STATUS_4 rc=%d\n", rc);
- return IRQ_HANDLED;
- }
+ bool debounce_done, sink_attached;
- rc = smblib_read(chg, TYPE_C_STATUS_5_REG, &stat5);
+ rc = smblib_multibyte_read(chg, TYPE_C_STATUS_1_REG,
+ chg->typec_status, 5);
if (rc < 0) {
- smblib_err(chg, "Couldn't read TYPE_C_STATUS_5 rc=%d\n", rc);
- return IRQ_HANDLED;
+ smblib_err(chg, "Couldn't cache USB Type-C status rc=%d\n", rc);
+ return;
}
- debounce_done = (bool)(stat4 & TYPEC_DEBOUNCE_DONE_STATUS_BIT);
- sink_attached = (bool)(stat4 & UFP_DFP_MODE_STATUS_BIT);
- legacy_cable = (bool)(stat5 & TYPEC_LEGACY_CABLE_STATUS_BIT);
+ 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, legacy_cable);
+ smblib_handle_typec_debounce_done(chg, debounce_done, sink_attached);
- if (stat4 & TYPEC_VBUS_ERROR_STATUS_BIT)
- smblib_dbg(chg, PR_INTERRUPT, "IRQ: %s vbus-error\n",
- irq_data->name);
+ if (chg->typec_status[3] & TYPEC_VBUS_ERROR_STATUS_BIT)
+ smblib_dbg(chg, PR_INTERRUPT, "IRQ: vbus-error\n");
- if (stat4 & TYPEC_VCONN_OVERCURR_STATUS_BIT)
+ if (chg->typec_status[3] & TYPEC_VCONN_OVERCURR_STATUS_BIT)
schedule_work(&chg->vconn_oc_work);
power_supply_changed(chg->usb_psy);
- smblib_dbg(chg, PR_REGISTER, "TYPE_C_STATUS_4 = 0x%02x\n", stat4);
- smblib_dbg(chg, PR_REGISTER, "TYPE_C_STATUS_5 = 0x%02x\n", stat5);
+}
+
+irqreturn_t smblib_handle_usb_typec_change(int irq, void *data)
+{
+ struct smb_irq_data *irq_data = data;
+ struct smb_charger *chg = irq_data->parent_data;
+
+ if (chg->micro_usb_mode) {
+ smblib_handle_usb_typec_change_for_uusb(chg);
+ return IRQ_HANDLED;
+ }
+
+ if (chg->cc2_detach_wa_active || chg->typec_en_dis_active) {
+ smblib_dbg(chg, PR_INTERRUPT, "Ignoring since %s active\n",
+ chg->cc2_detach_wa_active ?
+ "cc2_detach_wa" : "typec_en_dis");
+ return IRQ_HANDLED;
+ }
+
+ mutex_lock(&chg->lock);
+ smblib_usb_typec_change(chg);
+ mutex_unlock(&chg->lock);
return IRQ_HANDLED;
}
@@ -3785,7 +3751,7 @@ irqreturn_t smblib_handle_switcher_power_ok(int irq, void *data)
{
struct smb_irq_data *irq_data = data;
struct smb_charger *chg = irq_data->parent_data;
- int rc;
+ int rc, usb_icl;
u8 stat;
if (!(chg->wa_flags & BOOST_BACK_WA))
@@ -3797,8 +3763,9 @@ irqreturn_t smblib_handle_switcher_power_ok(int irq, void *data)
return IRQ_HANDLED;
}
- if ((stat & USE_USBIN_BIT) &&
- get_effective_result(chg->usb_icl_votable) < USBIN_25MA)
+ /* skip suspending input if its already suspended by some other voter */
+ usb_icl = get_effective_result(chg->usb_icl_votable);
+ if ((stat & USE_USBIN_BIT) && usb_icl >= 0 && usb_icl < USBIN_25MA)
return IRQ_HANDLED;
if (stat & USE_DCIN_BIT)
@@ -3836,12 +3803,7 @@ static void smblib_hvdcp_detect_work(struct work_struct *work)
vote(chg->pd_disallowed_votable_indirect, HVDCP_TIMEOUT_VOTER,
false, 0);
- if (get_effective_result(chg->pd_disallowed_votable_indirect))
- /* pd is still disabled, try hvdcp */
- try_rerun_apsd_for_hvdcp(chg);
- else
- /* notify pd now that pd is allowed */
- power_supply_changed(chg->usb_psy);
+ power_supply_changed(chg->usb_psy);
}
static void bms_update_work(struct work_struct *work)
@@ -3882,11 +3844,13 @@ static void clear_hdc_work(struct work_struct *work)
static void rdstd_cc2_detach_work(struct work_struct *work)
{
int rc;
- u8 stat;
- struct smb_irq_data irq_data = {NULL, "cc2-removal-workaround"};
+ u8 stat4, stat5;
struct smb_charger *chg = container_of(work, struct smb_charger,
rdstd_cc2_detach_work);
+ if (!chg->cc2_detach_wa_active)
+ return;
+
/*
* WA steps -
* 1. Enable both UFP and DFP, wait for 10ms.
@@ -3894,7 +3858,7 @@ static void rdstd_cc2_detach_work(struct work_struct *work)
* 3. Removal detected if both TYPEC_DEBOUNCE_DONE_STATUS
* and TIMER_STAGE bits are gone, otherwise repeat all by
* work rescheduling.
- * Note, work will be cancelled when pd_hard_reset is 0.
+ * Note, work will be cancelled when USB_PLUGIN rises.
*/
rc = smblib_masked_write(chg, TYPE_C_INTRPT_ENB_SOFTWARE_CTRL_REG,
@@ -3917,30 +3881,35 @@ static void rdstd_cc2_detach_work(struct work_struct *work)
usleep_range(30000, 31000);
- rc = smblib_read(chg, TYPE_C_STATUS_4_REG, &stat);
+ rc = smblib_read(chg, TYPE_C_STATUS_4_REG, &stat4);
if (rc < 0) {
- smblib_err(chg, "Couldn't read TYPE_C_STATUS_4 rc=%d\n",
- rc);
+ smblib_err(chg, "Couldn't read TYPE_C_STATUS_4 rc=%d\n", rc);
return;
}
- if (stat & TYPEC_DEBOUNCE_DONE_STATUS_BIT)
- goto rerun;
- rc = smblib_read(chg, TYPE_C_STATUS_5_REG, &stat);
+ rc = smblib_read(chg, TYPE_C_STATUS_5_REG, &stat5);
if (rc < 0) {
smblib_err(chg,
"Couldn't read TYPE_C_STATUS_5_REG rc=%d\n", rc);
return;
}
- if (stat & TIMER_STAGE_2_BIT)
+
+ if ((stat4 & TYPEC_DEBOUNCE_DONE_STATUS_BIT)
+ || (stat5 & TIMER_STAGE_2_BIT)) {
+ smblib_dbg(chg, PR_MISC, "rerunning DD=%d TS2BIT=%d\n",
+ (int)(stat4 & TYPEC_DEBOUNCE_DONE_STATUS_BIT),
+ (int)(stat5 & TIMER_STAGE_2_BIT));
goto rerun;
+ }
- /* Bingo, cc2 removal detected */
+ smblib_dbg(chg, PR_MISC, "Bingo CC2 Removal detected\n");
+ chg->cc2_detach_wa_active = false;
+ rc = smblib_masked_write(chg, TYPE_C_INTRPT_ENB_SOFTWARE_CTRL_REG,
+ EXIT_SNK_BASED_ON_CC_BIT, 0);
smblib_reg_block_restore(chg, cc2_detach_settings);
- chg->cc2_sink_detach_flag = CC2_SINK_WA_DONE;
- irq_data.parent_data = chg;
- smblib_handle_usb_typec_change(0, &irq_data);
-
+ mutex_lock(&chg->lock);
+ smblib_usb_typec_change(chg);
+ mutex_unlock(&chg->lock);
return;
rerun:
@@ -4163,6 +4132,56 @@ static void smblib_pl_enable_work(struct work_struct *work)
vote(chg->awake_votable, PL_DELAY_VOTER, false, 0);
}
+static void smblib_legacy_detection_work(struct work_struct *work)
+{
+ struct smb_charger *chg = container_of(work, struct smb_charger,
+ legacy_detection_work);
+ int rc;
+ u8 stat;
+ bool legacy, rp_high;
+
+ mutex_lock(&chg->lock);
+ chg->typec_en_dis_active = 1;
+ smblib_dbg(chg, PR_MISC, "running legacy unknown workaround\n");
+ rc = smblib_masked_write(chg,
+ TYPE_C_INTRPT_ENB_SOFTWARE_CTRL_REG,
+ TYPEC_DISABLE_CMD_BIT,
+ TYPEC_DISABLE_CMD_BIT);
+ if (rc < 0)
+ smblib_err(chg, "Couldn't disable type-c rc=%d\n", rc);
+
+ /* wait for the adapter to turn off VBUS */
+ msleep(500);
+
+ rc = smblib_masked_write(chg,
+ TYPE_C_INTRPT_ENB_SOFTWARE_CTRL_REG,
+ TYPEC_DISABLE_CMD_BIT, 0);
+ if (rc < 0)
+ smblib_err(chg, "Couldn't enable type-c rc=%d\n", rc);
+
+ /* wait for type-c detection to complete */
+ msleep(100);
+
+ rc = smblib_read(chg, TYPE_C_STATUS_5_REG, &stat);
+ if (rc < 0) {
+ smblib_err(chg, "Couldn't read typec stat5 rc = %d\n", rc);
+ goto unlock;
+ }
+
+ 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;
+ if (!legacy || !rp_high)
+ vote(chg->hvdcp_disable_votable_indirect, VBUS_CC_SHORT_VOTER,
+ false, 0);
+
+unlock:
+ chg->typec_en_dis_active = 0;
+ mutex_unlock(&chg->lock);
+}
+
static int smblib_create_votables(struct smb_charger *chg)
{
int rc = 0;
@@ -4295,6 +4314,15 @@ static int smblib_create_votables(struct smb_charger *chg)
return rc;
}
+ chg->typec_irq_disable_votable = create_votable("TYPEC_IRQ_DISABLE",
+ VOTE_SET_ANY,
+ smblib_typec_irq_disable_vote_callback,
+ chg);
+ if (IS_ERR(chg->typec_irq_disable_votable)) {
+ rc = PTR_ERR(chg->typec_irq_disable_votable);
+ return rc;
+ }
+
return rc;
}
@@ -4320,6 +4348,8 @@ static void smblib_destroy_votables(struct smb_charger *chg)
destroy_votable(chg->apsd_disable_votable);
if (chg->hvdcp_hw_inov_dis_votable)
destroy_votable(chg->hvdcp_hw_inov_dis_votable);
+ if (chg->typec_irq_disable_votable)
+ destroy_votable(chg->typec_irq_disable_votable);
}
static void smblib_iio_deinit(struct smb_charger *chg)
@@ -4340,6 +4370,7 @@ int smblib_init(struct smb_charger *chg)
{
int rc = 0;
+ mutex_init(&chg->lock);
mutex_init(&chg->write_lock);
mutex_init(&chg->otg_oc_lock);
INIT_WORK(&chg->bms_update_work, bms_update_work);
@@ -4352,6 +4383,7 @@ int smblib_init(struct smb_charger *chg)
INIT_DELAYED_WORK(&chg->otg_ss_done_work, smblib_otg_ss_done_work);
INIT_DELAYED_WORK(&chg->icl_change_work, smblib_icl_change_work);
INIT_DELAYED_WORK(&chg->pl_enable_work, smblib_pl_enable_work);
+ INIT_WORK(&chg->legacy_detection_work, smblib_legacy_detection_work);
chg->fake_capacity = -EINVAL;
switch (chg->mode) {
diff --git a/drivers/power/supply/qcom/smb-lib.h b/drivers/power/supply/qcom/smb-lib.h
index 49b9d3da783c..b0d84f014b0d 100644
--- a/drivers/power/supply/qcom/smb-lib.h
+++ b/drivers/power/supply/qcom/smb-lib.h
@@ -61,6 +61,7 @@ enum print_reason {
#define SW_QC3_VOTER "SW_QC3_VOTER"
#define AICL_RERUN_VOTER "AICL_RERUN_VOTER"
#define LEGACY_UNKNOWN_VOTER "LEGACY_UNKNOWN_VOTER"
+#define CC2_WA_VOTER "CC2_WA_VOTER"
#define VCONN_MAX_ATTEMPTS 3
#define OTG_MAX_ATTEMPTS 3
@@ -71,13 +72,6 @@ enum smb_mode {
NUM_MODES,
};
-enum cc2_sink_type {
- CC2_SINK_NONE = 0,
- CC2_SINK_STD,
- CC2_SINK_MEDIUM_HIGH,
- CC2_SINK_WA_DONE,
-};
-
enum {
QC_CHARGER_DETECTION_WA_BIT = BIT(0),
BOOST_BACK_WA = BIT(1),
@@ -236,6 +230,7 @@ struct smb_charger {
int smb_version;
/* locks */
+ struct mutex lock;
struct mutex write_lock;
struct mutex ps_change_lock;
struct mutex otg_oc_lock;
@@ -276,6 +271,7 @@ struct smb_charger {
struct votable *apsd_disable_votable;
struct votable *hvdcp_hw_inov_dis_votable;
struct votable *usb_irq_enable_votable;
+ struct votable *typec_irq_disable_votable;
/* work */
struct work_struct bms_update_work;
@@ -289,6 +285,7 @@ struct smb_charger {
struct delayed_work otg_ss_done_work;
struct delayed_work icl_change_work;
struct delayed_work pl_enable_work;
+ struct work_struct legacy_detection_work;
/* cached status */
int voltage_min_uv;
@@ -312,10 +309,16 @@ struct smb_charger {
int vconn_attempts;
int default_icl_ua;
int otg_cl_ua;
+ bool uusb_apsd_rerun_done;
+ bool pd_hard_reset;
+ bool typec_present;
+ u8 typec_status[5];
+ bool typec_legacy_valid;
/* workaround flag */
u32 wa_flags;
- enum cc2_sink_type cc2_sink_detach_flag;
+ bool cc2_detach_wa_active;
+ bool typec_en_dis_active;
int boost_current_ua;
int temp_speed_reading_count;
diff --git a/drivers/power/supply/qcom/smb-reg.h b/drivers/power/supply/qcom/smb-reg.h
index 167666a8c548..3f260a407721 100644
--- a/drivers/power/supply/qcom/smb-reg.h
+++ b/drivers/power/supply/qcom/smb-reg.h
@@ -1025,4 +1025,14 @@ enum {
/* CHGR FREQ Peripheral registers */
#define FREQ_CLK_DIV_REG (CHGR_FREQ_BASE + 0x50)
+/* SMB1355 specific registers */
+#define SMB1355_TEMP_COMP_STATUS_REG (MISC_BASE + 0x07)
+#define SKIN_TEMP_RST_HOT_BIT BIT(6)
+#define SKIN_TEMP_UB_HOT_BIT BIT(5)
+#define SKIN_TEMP_LB_HOT_BIT BIT(4)
+#define DIE_TEMP_TSD_HOT_BIT BIT(3)
+#define DIE_TEMP_RST_HOT_BIT BIT(2)
+#define DIE_TEMP_UB_HOT_BIT BIT(1)
+#define DIE_TEMP_LB_HOT_BIT BIT(0)
+
#endif /* __SMB2_CHARGER_REG_H */
diff --git a/drivers/power/supply/qcom/smb138x-charger.c b/drivers/power/supply/qcom/smb138x-charger.c
index 694591c3ec56..4e710cae6b78 100644
--- a/drivers/power/supply/qcom/smb138x-charger.c
+++ b/drivers/power/supply/qcom/smb138x-charger.c
@@ -104,6 +104,8 @@ struct smb138x {
struct smb_dt_props dt;
struct power_supply *parallel_psy;
u32 wa_flags;
+ struct pmic_revid_data *pmic_rev_id;
+ char *name;
};
static int __debug_mask;
@@ -167,6 +169,14 @@ static int smb138x_parse_dt(struct smb138x *chip)
if (rc < 0)
chip->dt.pl_mode = POWER_SUPPLY_PL_USBMID_USBMID;
+ /* check that smb1355 is configured to run in mid-mid mode */
+ if (chip->pmic_rev_id->pmic_subtype == SMB1355_SUBTYPE
+ && chip->dt.pl_mode != POWER_SUPPLY_PL_USBMID_USBMID) {
+ pr_err("Smb1355 can only run in MID-MID mode, saw = %d mode\n",
+ chip->dt.pl_mode);
+ return -EINVAL;
+ }
+
chip->dt.suspend_input = of_property_read_bool(node,
"qcom,suspend-input");
@@ -479,6 +489,30 @@ static int smb138x_init_batt_psy(struct smb138x *chip)
* PARALLEL PSY REGISTRATION *
*****************************/
+static int smb1355_get_prop_connector_health(struct smb138x *chip)
+{
+ struct smb_charger *chg = &chip->chg;
+ u8 temp;
+ int rc;
+
+ rc = smblib_read(chg, SMB1355_TEMP_COMP_STATUS_REG, &temp);
+ if (rc < 0) {
+ pr_err("Couldn't read comp stat reg rc = %d\n", rc);
+ return POWER_SUPPLY_HEALTH_UNKNOWN;
+ }
+
+ if (temp & SKIN_TEMP_RST_HOT_BIT)
+ return POWER_SUPPLY_HEALTH_OVERHEAT;
+
+ if (temp & SKIN_TEMP_UB_HOT_BIT)
+ return POWER_SUPPLY_HEALTH_HOT;
+
+ if (temp & SKIN_TEMP_LB_HOT_BIT)
+ return POWER_SUPPLY_HEALTH_WARM;
+
+ return POWER_SUPPLY_HEALTH_COOL;
+}
+
static int smb138x_get_prop_connector_health(struct smb138x *chip)
{
struct smb_charger *chg = &chip->chg;
@@ -536,16 +570,32 @@ static enum power_supply_property smb138x_parallel_props[] = {
POWER_SUPPLY_PROP_PIN_ENABLED,
POWER_SUPPLY_PROP_INPUT_SUSPEND,
POWER_SUPPLY_PROP_INPUT_CURRENT_LIMITED,
- POWER_SUPPLY_PROP_CURRENT_MAX,
POWER_SUPPLY_PROP_VOLTAGE_MAX,
POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX,
- POWER_SUPPLY_PROP_CURRENT_NOW,
+ POWER_SUPPLY_PROP_MODEL_NAME,
+ POWER_SUPPLY_PROP_PARALLEL_MODE,
+ POWER_SUPPLY_PROP_CONNECTOR_HEALTH,
+ POWER_SUPPLY_PROP_SET_SHIP_MODE,
POWER_SUPPLY_PROP_CHARGER_TEMP,
POWER_SUPPLY_PROP_CHARGER_TEMP_MAX,
+ POWER_SUPPLY_PROP_CURRENT_NOW,
+ POWER_SUPPLY_PROP_CURRENT_MAX,
+};
+
+static enum power_supply_property smb1355_parallel_props[] = {
+ POWER_SUPPLY_PROP_CHARGE_TYPE,
+ POWER_SUPPLY_PROP_CHARGING_ENABLED,
+ POWER_SUPPLY_PROP_PIN_ENABLED,
+ POWER_SUPPLY_PROP_INPUT_SUSPEND,
+ POWER_SUPPLY_PROP_INPUT_CURRENT_LIMITED,
+ POWER_SUPPLY_PROP_VOLTAGE_MAX,
+ POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX,
POWER_SUPPLY_PROP_MODEL_NAME,
POWER_SUPPLY_PROP_PARALLEL_MODE,
POWER_SUPPLY_PROP_CONNECTOR_HEALTH,
POWER_SUPPLY_PROP_SET_SHIP_MODE,
+ POWER_SUPPLY_PROP_CHARGER_TEMP,
+ POWER_SUPPLY_PROP_CHARGER_TEMP_MAX,
};
static int smb138x_parallel_get_prop(struct power_supply *psy,
@@ -583,14 +633,6 @@ static int smb138x_parallel_get_prop(struct power_supply *psy,
else
val->intval = 0;
break;
- case POWER_SUPPLY_PROP_CURRENT_MAX:
- if ((chip->dt.pl_mode == POWER_SUPPLY_PL_USBIN_USBIN)
- || (chip->dt.pl_mode == POWER_SUPPLY_PL_USBIN_USBIN_EXT))
- rc = smblib_get_charge_param(chg, &chg->param.usb_icl,
- &val->intval);
- else
- val->intval = 0;
- break;
case POWER_SUPPLY_PROP_VOLTAGE_MAX:
rc = smblib_get_charge_param(chg, &chg->param.fv, &val->intval);
break;
@@ -598,28 +640,46 @@ static int smb138x_parallel_get_prop(struct power_supply *psy,
rc = smblib_get_charge_param(chg, &chg->param.fcc,
&val->intval);
break;
- case POWER_SUPPLY_PROP_CURRENT_NOW:
- rc = smblib_get_prop_slave_current_now(chg, val);
- break;
- case POWER_SUPPLY_PROP_CHARGER_TEMP:
- rc = smb138x_get_prop_charger_temp(chip, val);
- break;
- case POWER_SUPPLY_PROP_CHARGER_TEMP_MAX:
- rc = smblib_get_prop_charger_temp_max(chg, val);
- break;
case POWER_SUPPLY_PROP_MODEL_NAME:
- val->strval = "smb138x";
+ val->strval = chip->name;
break;
case POWER_SUPPLY_PROP_PARALLEL_MODE:
val->intval = chip->dt.pl_mode;
break;
case POWER_SUPPLY_PROP_CONNECTOR_HEALTH:
- val->intval = smb138x_get_prop_connector_health(chip);
+ if (chip->pmic_rev_id->pmic_subtype != SMB1355_SUBTYPE)
+ val->intval = smb138x_get_prop_connector_health(chip);
+ else
+ val->intval = smb1355_get_prop_connector_health(chip);
break;
case POWER_SUPPLY_PROP_SET_SHIP_MODE:
/* Not in ship mode as long as device is active */
val->intval = 0;
break;
+ case POWER_SUPPLY_PROP_CHARGER_TEMP:
+ if (chip->pmic_rev_id->pmic_subtype != SMB1355_SUBTYPE)
+ rc = smb138x_get_prop_charger_temp(chip, val);
+ else
+ rc = smblib_get_prop_charger_temp(chg, val);
+ break;
+ case POWER_SUPPLY_PROP_CHARGER_TEMP_MAX:
+ rc = smblib_get_prop_charger_temp_max(chg, val);
+ break;
+ case POWER_SUPPLY_PROP_CURRENT_NOW:
+ if (chip->pmic_rev_id->pmic_subtype != SMB1355_SUBTYPE)
+ rc = smblib_get_prop_slave_current_now(chg, val);
+ else
+ rc = -ENODATA;
+ break;
+ case POWER_SUPPLY_PROP_CURRENT_MAX:
+ if ((chip->pmic_rev_id->pmic_subtype != SMB1355_SUBTYPE)
+ && ((chip->dt.pl_mode == POWER_SUPPLY_PL_USBIN_USBIN)
+ || (chip->dt.pl_mode == POWER_SUPPLY_PL_USBIN_USBIN_EXT)))
+ rc = smblib_get_charge_param(chg, &chg->param.usb_icl,
+ &val->intval);
+ else
+ rc = -ENODATA;
+ break;
default:
pr_err("parallel power supply get prop %d not supported\n",
prop);
@@ -703,7 +763,7 @@ static int smb138x_parallel_prop_is_writeable(struct power_supply *psy,
return 0;
}
-static const struct power_supply_desc parallel_psy_desc = {
+static struct power_supply_desc parallel_psy_desc = {
.name = "parallel",
.type = POWER_SUPPLY_TYPE_PARALLEL,
.properties = smb138x_parallel_props,
@@ -731,6 +791,28 @@ static int smb138x_init_parallel_psy(struct smb138x *chip)
return 0;
}
+static int smb1355_init_parallel_psy(struct smb138x *chip)
+{
+ struct power_supply_config parallel_cfg = {};
+ struct smb_charger *chg = &chip->chg;
+
+ parallel_cfg.drv_data = chip;
+ parallel_cfg.of_node = chg->dev->of_node;
+
+ /* change to smb1355's property list */
+ parallel_psy_desc.properties = smb1355_parallel_props;
+ parallel_psy_desc.num_properties = ARRAY_SIZE(smb1355_parallel_props);
+ chip->parallel_psy = devm_power_supply_register(chg->dev,
+ &parallel_psy_desc,
+ &parallel_cfg);
+ if (IS_ERR(chip->parallel_psy)) {
+ pr_err("Couldn't register parallel power supply\n");
+ return PTR_ERR(chip->parallel_psy);
+ }
+
+ return 0;
+}
+
/******************************
* VBUS REGULATOR REGISTRATION *
******************************/
@@ -1050,7 +1132,6 @@ static int smb138x_init_hw(struct smb138x *chip)
static int smb138x_setup_wa_flags(struct smb138x *chip)
{
- struct pmic_revid_data *pmic_rev_id;
struct device_node *revid_dev_node;
revid_dev_node = of_parse_phandle(chip->chg.dev->of_node,
@@ -1060,8 +1141,8 @@ static int smb138x_setup_wa_flags(struct smb138x *chip)
return -EINVAL;
}
- pmic_rev_id = get_revid_data(revid_dev_node);
- if (IS_ERR_OR_NULL(pmic_rev_id)) {
+ chip->pmic_rev_id = get_revid_data(revid_dev_node);
+ if (IS_ERR_OR_NULL(chip->pmic_rev_id)) {
/*
* the revid peripheral must be registered, any failure
* here only indicates that the rev-id module has not
@@ -1070,14 +1151,14 @@ static int smb138x_setup_wa_flags(struct smb138x *chip)
return -EPROBE_DEFER;
}
- switch (pmic_rev_id->pmic_subtype) {
+ switch (chip->pmic_rev_id->pmic_subtype) {
case SMB1381_SUBTYPE:
- if (pmic_rev_id->rev4 < 2) /* SMB1381 rev 1.0 */
+ if (chip->pmic_rev_id->rev4 < 2) /* SMB1381 rev 1.0 */
chip->wa_flags |= OOB_COMP_WA_BIT;
break;
default:
pr_err("PMIC subtype %d not supported\n",
- pmic_rev_id->pmic_subtype);
+ chip->pmic_rev_id->pmic_subtype);
return -EINVAL;
}
@@ -1375,6 +1456,7 @@ static int smb138x_master_probe(struct smb138x *chip)
chg->param = v1_params;
+ chip->name = "smb1381";
rc = smblib_init(chg);
if (rc < 0) {
pr_err("Couldn't initialize smblib rc=%d\n", rc);
@@ -1435,7 +1517,7 @@ static int smb138x_master_probe(struct smb138x *chip)
return rc;
}
-static int smb138x_slave_probe(struct smb138x *chip)
+static int smb1355_slave_probe(struct smb138x *chip)
{
struct smb_charger *chg = &chip->chg;
int rc = 0;
@@ -1448,6 +1530,55 @@ static int smb138x_slave_probe(struct smb138x *chip)
goto cleanup;
}
+ rc = smb138x_parse_dt(chip);
+ if (rc < 0) {
+ pr_err("Couldn't parse device tree rc=%d\n", rc);
+ goto cleanup;
+ }
+
+ rc = smb138x_init_slave_hw(chip);
+ if (rc < 0) {
+ pr_err("Couldn't initialize hardware rc=%d\n", rc);
+ goto cleanup;
+ }
+
+ rc = smb1355_init_parallel_psy(chip);
+ if (rc < 0) {
+ pr_err("Couldn't initialize parallel psy rc=%d\n", rc);
+ goto cleanup;
+ }
+
+ rc = smb138x_determine_initial_slave_status(chip);
+ if (rc < 0) {
+ pr_err("Couldn't determine initial status rc=%d\n", rc);
+ goto cleanup;
+ }
+
+ rc = smb138x_request_interrupts(chip);
+ if (rc < 0) {
+ pr_err("Couldn't request interrupts rc=%d\n", rc);
+ goto cleanup;
+ }
+
+ return 0;
+
+cleanup:
+ smblib_deinit(chg);
+ return rc;
+}
+
+static int smb1381_slave_probe(struct smb138x *chip)
+{
+ struct smb_charger *chg = &chip->chg;
+ int rc = 0;
+
+ chg->param = v1_params;
+
+ rc = smblib_init(chg);
+ if (rc < 0) {
+ pr_err("Couldn't initialize smblib rc=%d\n", rc);
+ goto cleanup;
+ }
chg->iio.temp_max_chan = iio_channel_get(chg->dev, "charger_temp_max");
if (IS_ERR(chg->iio.temp_max_chan)) {
rc = PTR_ERR(chg->iio.temp_max_chan);
@@ -1515,25 +1646,71 @@ static int smb138x_slave_probe(struct smb138x *chip)
goto cleanup;
}
- return rc;
+ return 0;
cleanup:
smblib_deinit(chg);
- if (chip->parallel_psy)
- power_supply_unregister(chip->parallel_psy);
- if (chg->vbus_vreg && chg->vbus_vreg->rdev)
- regulator_unregister(chg->vbus_vreg->rdev);
return rc;
}
+static int slave_probe(struct smb138x *chip)
+{
+ struct device_node *revid_dev_node;
+ int rc = 0;
+
+ revid_dev_node = of_parse_phandle(chip->chg.dev->of_node,
+ "qcom,pmic-revid", 0);
+ if (!revid_dev_node) {
+ pr_err("Missing qcom,pmic-revid property\n");
+ return -EINVAL;
+ }
+
+ chip->pmic_rev_id = get_revid_data(revid_dev_node);
+ if (IS_ERR_OR_NULL(chip->pmic_rev_id)) {
+ /*
+ * the revid peripheral must be registered, any failure
+ * here only indicates that the rev-id module has not
+ * probed yet.
+ */
+ return -EPROBE_DEFER;
+ }
+
+ switch (chip->pmic_rev_id->pmic_subtype) {
+ case SMB1355_SUBTYPE:
+ chip->name = "smb1355";
+ rc = smb1355_slave_probe(chip);
+ break;
+ case SMB1381_SUBTYPE:
+ chip->name = "smb1381";
+ rc = smb1381_slave_probe(chip);
+ break;
+ default:
+ pr_err("Unsupported pmic subtype = 0x%02x\n",
+ chip->pmic_rev_id->pmic_subtype);
+ rc = -EINVAL;
+ }
+
+ if (rc < 0) {
+ if (rc != -EPROBE_DEFER)
+ pr_err("Couldn't probe SMB138X rc=%d\n", rc);
+ return rc;
+ }
+
+ return 0;
+}
+
static const struct of_device_id match_table[] = {
{
- .compatible = "qcom,smb138x-charger",
- .data = (void *) PARALLEL_MASTER
+ .compatible = "qcom,smb138x-charger",
+ .data = (void *) PARALLEL_MASTER,
+ },
+ {
+ .compatible = "qcom,smb138x-parallel-slave",
+ .data = (void *) PARALLEL_SLAVE,
},
{
- .compatible = "qcom,smb138x-parallel-slave",
- .data = (void *) PARALLEL_SLAVE
+ .compatible = "qcom,smb1355-parallel-slave",
+ .data = (void *) PARALLEL_SLAVE,
},
{ },
};
@@ -1580,7 +1757,7 @@ static int smb138x_probe(struct platform_device *pdev)
rc = smb138x_master_probe(chip);
break;
case PARALLEL_SLAVE:
- rc = smb138x_slave_probe(chip);
+ rc = slave_probe(chip);
break;
default:
pr_err("Couldn't find a matching mode %d\n", chip->chg.mode);
@@ -1594,7 +1771,8 @@ static int smb138x_probe(struct platform_device *pdev)
goto cleanup;
}
- pr_info("SMB138X probed successfully mode=%d\n", chip->chg.mode);
+ pr_info("%s probed successfully mode=%d pl_mode = %d\n",
+ chip->name, chip->chg.mode, chip->dt.pl_mode);
return rc;
cleanup:
diff --git a/drivers/pps/clients/pps-gpio.c b/drivers/pps/clients/pps-gpio.c
index 333ad7d5b45b..da72b0b59c3a 100644
--- a/drivers/pps/clients/pps-gpio.c
+++ b/drivers/pps/clients/pps-gpio.c
@@ -57,7 +57,7 @@ static irqreturn_t pps_gpio_irq_handler(int irq, void *data)
int rising_edge;
/* Get the time stamp first */
- pps_get_ts(&ts);
+ get_monotonic_boottime(&ts.ts_real);
info = data;
diff --git a/drivers/regulator/qpnp-labibb-regulator.c b/drivers/regulator/qpnp-labibb-regulator.c
index dbe2a08f1776..858ddcc228df 100644
--- a/drivers/regulator/qpnp-labibb-regulator.c
+++ b/drivers/regulator/qpnp-labibb-regulator.c
@@ -559,6 +559,7 @@ struct lab_regulator {
int step_size;
int slew_rate;
int soft_start;
+ int sc_wait_time_ms;
int vreg_enabled;
};
@@ -608,6 +609,8 @@ struct qpnp_labibb {
bool skip_2nd_swire_cmd;
bool pfm_enable;
bool notify_lab_vreg_ok_sts;
+ bool detect_lab_sc;
+ bool sc_detected;
u32 swire_2nd_cmd_delay;
u32 swire_ibb_ps_enable_delay;
};
@@ -2138,8 +2141,10 @@ static void qpnp_lab_vreg_notifier_work(struct work_struct *work)
u8 val;
struct qpnp_labibb *labibb = container_of(work, struct qpnp_labibb,
lab_vreg_ok_work);
+ if (labibb->lab_vreg.sc_wait_time_ms != -EINVAL)
+ retries = labibb->lab_vreg.sc_wait_time_ms / 5;
- while (retries--) {
+ while (retries) {
rc = qpnp_labibb_read(labibb, labibb->lab_base +
REG_LAB_STATUS1, &val, 1);
if (rc < 0) {
@@ -2155,10 +2160,30 @@ static void qpnp_lab_vreg_notifier_work(struct work_struct *work)
}
usleep_range(dly, dly + 100);
+ retries--;
}
- if (!retries)
- pr_err("LAB_VREG_OK not set, failed to notify\n");
+ if (!retries) {
+ if (labibb->detect_lab_sc) {
+ pr_crit("short circuit detected on LAB rail.. disabling the LAB/IBB/OLEDB modules\n");
+ /* Disable LAB module */
+ val = 0;
+ rc = qpnp_labibb_write(labibb, labibb->lab_base +
+ REG_LAB_MODULE_RDY, &val, 1);
+ if (rc < 0) {
+ pr_err("write register %x failed rc = %d\n",
+ REG_LAB_MODULE_RDY, rc);
+ return;
+ }
+ raw_notifier_call_chain(&labibb_notifier,
+ LAB_VREG_NOT_OK, NULL);
+ labibb->sc_detected = true;
+ labibb->lab_vreg.vreg_enabled = 0;
+ labibb->ibb_vreg.vreg_enabled = 0;
+ } else {
+ pr_err("LAB_VREG_OK not set, failed to notify\n");
+ }
+ }
}
static int qpnp_labibb_regulator_enable(struct qpnp_labibb *labibb)
@@ -2323,6 +2348,11 @@ static int qpnp_lab_regulator_enable(struct regulator_dev *rdev)
struct qpnp_labibb *labibb = rdev_get_drvdata(rdev);
+ if (labibb->sc_detected) {
+ pr_info("Short circuit detected: disabled LAB/IBB rails\n");
+ return 0;
+ }
+
if (labibb->skip_2nd_swire_cmd) {
rc = qpnp_ibb_ps_config(labibb, false);
if (rc < 0) {
@@ -2363,7 +2393,7 @@ static int qpnp_lab_regulator_enable(struct regulator_dev *rdev)
labibb->lab_vreg.vreg_enabled = 1;
}
- if (labibb->notify_lab_vreg_ok_sts)
+ if (labibb->notify_lab_vreg_ok_sts || labibb->detect_lab_sc)
schedule_work(&labibb->lab_vreg_ok_work);
return 0;
@@ -2621,6 +2651,12 @@ static int register_qpnp_lab_regulator(struct qpnp_labibb *labibb,
labibb->notify_lab_vreg_ok_sts = of_property_read_bool(of_node,
"qcom,notify-lab-vreg-ok-sts");
+ labibb->lab_vreg.sc_wait_time_ms = -EINVAL;
+ if (labibb->pmic_rev_id->pmic_subtype == PM660L_SUBTYPE &&
+ labibb->detect_lab_sc)
+ of_property_read_u32(of_node, "qcom,qpnp-lab-sc-wait-time-ms",
+ &labibb->lab_vreg.sc_wait_time_ms);
+
rc = of_property_read_u32(of_node, "qcom,qpnp-lab-soft-start",
&(labibb->lab_vreg.soft_start));
if (!rc) {
@@ -3255,6 +3291,11 @@ static int qpnp_ibb_regulator_enable(struct regulator_dev *rdev)
u8 val;
struct qpnp_labibb *labibb = rdev_get_drvdata(rdev);
+ if (labibb->sc_detected) {
+ pr_info("Short circuit detected: disabled LAB/IBB rails\n");
+ return 0;
+ }
+
if (!labibb->ibb_vreg.vreg_enabled && !labibb->swire_control) {
if (!labibb->standalone)
@@ -3731,6 +3772,8 @@ static int qpnp_labibb_regulator_probe(struct platform_device *pdev)
if (labibb->pmic_rev_id->pmic_subtype == PM660L_SUBTYPE) {
labibb->mode = QPNP_LABIBB_AMOLED_MODE;
+ /* Enable polling for LAB short circuit detection for PM660A */
+ labibb->detect_lab_sc = true;
} else {
rc = of_property_read_string(labibb->dev->of_node,
"qcom,qpnp-labibb-mode", &mode_name);
diff --git a/drivers/regulator/qpnp-oledb-regulator.c b/drivers/regulator/qpnp-oledb-regulator.c
index c012f373e80e..bee9a3d82eeb 100644
--- a/drivers/regulator/qpnp-oledb-regulator.c
+++ b/drivers/regulator/qpnp-oledb-regulator.c
@@ -27,6 +27,7 @@
#include <linux/regulator/of_regulator.h>
#include <linux/regulator/qpnp-labibb-regulator.h>
#include <linux/qpnp/qpnp-pbs.h>
+#include <linux/qpnp/qpnp-revid.h>
#define QPNP_OLEDB_REGULATOR_DRIVER_NAME "qcom,qpnp-oledb-regulator"
#define OLEDB_VOUT_STEP_MV 100
@@ -162,6 +163,7 @@ struct qpnp_oledb {
struct notifier_block oledb_nb;
struct mutex bus_lock;
struct device_node *pbs_dev_node;
+ struct pmic_revid_data *pmic_rev_id;
u32 base;
u8 mod_enable;
@@ -181,6 +183,8 @@ struct qpnp_oledb {
bool dynamic_ext_pinctl_config;
bool pbs_control;
bool force_pd_control;
+ bool handle_lab_sc_notification;
+ bool lab_sc_detected;
};
static const u16 oledb_warmup_dly_ns[] = {6700, 13300, 26700, 53400};
@@ -275,6 +279,11 @@ static int qpnp_oledb_regulator_enable(struct regulator_dev *rdev)
struct qpnp_oledb *oledb = rdev_get_drvdata(rdev);
+ if (oledb->lab_sc_detected == true) {
+ pr_info("Short circuit detected: Disabled OLEDB rail\n");
+ return 0;
+ }
+
if (oledb->ext_pin_control) {
rc = qpnp_oledb_read(oledb, oledb->base + OLEDB_EXT_PIN_CTL,
&val, 1);
@@ -368,12 +377,19 @@ static int qpnp_oledb_regulator_disable(struct regulator_dev *rdev)
}
if (val & OLEDB_FORCE_PD_CTL_SPARE_BIT) {
- rc = qpnp_pbs_trigger_event(oledb->pbs_dev_node,
- trigger_bitmap);
+ rc = qpnp_oledb_sec_masked_write(oledb, oledb->base +
+ OLEDB_SPARE_CTL,
+ OLEDB_FORCE_PD_CTL_SPARE_BIT, 0);
if (rc < 0) {
- pr_err("Failed to trigger the PBS sequence\n");
+ pr_err("Failed to write SPARE_CTL rc=%d\n", rc);
return rc;
}
+
+ rc = qpnp_pbs_trigger_event(oledb->pbs_dev_node,
+ trigger_bitmap);
+ if (rc < 0)
+ pr_err("Failed to trigger the PBS sequence\n");
+
pr_debug("PBS event triggered\n");
} else {
pr_debug("OLEDB_SPARE_CTL register bit not set\n");
@@ -1085,8 +1101,22 @@ static int qpnp_oledb_parse_fast_precharge(struct qpnp_oledb *oledb)
static int qpnp_oledb_parse_dt(struct qpnp_oledb *oledb)
{
int rc = 0;
+ struct device_node *revid_dev_node;
struct device_node *of_node = oledb->dev->of_node;
+ revid_dev_node = of_parse_phandle(oledb->dev->of_node,
+ "qcom,pmic-revid", 0);
+ if (!revid_dev_node) {
+ pr_err("Missing qcom,pmic-revid property - driver failed\n");
+ return -EINVAL;
+ }
+
+ oledb->pmic_rev_id = get_revid_data(revid_dev_node);
+ if (IS_ERR(oledb->pmic_rev_id)) {
+ pr_debug("Unable to get revid data\n");
+ return -EPROBE_DEFER;
+ }
+
oledb->swire_control =
of_property_read_bool(of_node, "qcom,swire-control");
@@ -1100,8 +1130,14 @@ static int qpnp_oledb_parse_dt(struct qpnp_oledb *oledb)
oledb->pbs_control =
of_property_read_bool(of_node, "qcom,pbs-control");
- oledb->force_pd_control =
- of_property_read_bool(of_node, "qcom,force-pd-control");
+ /* Use the force_pd_control only for PM660A versions <= v2.0 */
+ if (oledb->pmic_rev_id->pmic_subtype == PM660L_SUBTYPE &&
+ oledb->pmic_rev_id->rev4 <= PM660L_V2P0_REV4) {
+ if (!(oledb->pmic_rev_id->rev4 == PM660L_V2P0_REV4 &&
+ oledb->pmic_rev_id->rev2 > PM660L_V2P0_REV2)) {
+ oledb->force_pd_control = true;
+ }
+ }
if (oledb->force_pd_control) {
oledb->pbs_dev_node = of_parse_phandle(of_node,
@@ -1199,13 +1235,6 @@ static int qpnp_oledb_force_pulldown_config(struct qpnp_oledb *oledb)
int rc = 0;
u8 val;
- rc = qpnp_oledb_sec_masked_write(oledb, oledb->base +
- OLEDB_SPARE_CTL, OLEDB_FORCE_PD_CTL_SPARE_BIT, 0);
- if (rc < 0) {
- pr_err("Failed to write SPARE_CTL rc=%d\n", rc);
- return rc;
- }
-
val = 1;
rc = qpnp_oledb_write(oledb, oledb->base + OLEDB_PD_CTL,
&val, 1);
@@ -1227,14 +1256,31 @@ static int qpnp_labibb_notifier_cb(struct notifier_block *nb,
unsigned long action, void *data)
{
int rc = 0;
+ u8 val;
struct qpnp_oledb *oledb = container_of(nb, struct qpnp_oledb,
oledb_nb);
+ if (action == LAB_VREG_NOT_OK) {
+ /* short circuit detected. Disable OLEDB module */
+ val = 0;
+ rc = qpnp_oledb_write(oledb, oledb->base + OLEDB_MODULE_RDY,
+ &val, 1);
+ if (rc < 0) {
+ pr_err("Failed to write MODULE_RDY rc=%d\n", rc);
+ return NOTIFY_STOP;
+ }
+ oledb->lab_sc_detected = true;
+ oledb->mod_enable = false;
+ pr_crit("LAB SC detected, disabling OLEDB forever!\n");
+ }
+
if (action == LAB_VREG_OK) {
/* Disable SWIRE pull down control and enable via spmi mode */
rc = qpnp_oledb_force_pulldown_config(oledb);
- if (rc < 0)
+ if (rc < 0) {
+ pr_err("Failed to config force pull down\n");
return NOTIFY_STOP;
+ }
}
return NOTIFY_OK;
@@ -1281,7 +1327,11 @@ static int qpnp_oledb_regulator_probe(struct platform_device *pdev)
return rc;
}
- if (oledb->force_pd_control) {
+ /* Enable LAB short circuit notification support */
+ if (oledb->pmic_rev_id->pmic_subtype == PM660L_SUBTYPE)
+ oledb->handle_lab_sc_notification = true;
+
+ if (oledb->force_pd_control || oledb->handle_lab_sc_notification) {
oledb->oledb_nb.notifier_call = qpnp_labibb_notifier_cb;
rc = qpnp_labibb_notifier_register(&oledb->oledb_nb);
if (rc < 0) {
diff --git a/drivers/scsi/sd.c b/drivers/scsi/sd.c
index d5c00951cf93..5d81bcc1dc75 100644
--- a/drivers/scsi/sd.c
+++ b/drivers/scsi/sd.c
@@ -2806,10 +2806,10 @@ static int sd_revalidate_disk(struct gendisk *disk)
if (sdkp->opt_xfer_blocks &&
sdkp->opt_xfer_blocks <= dev_max &&
sdkp->opt_xfer_blocks <= SD_DEF_XFER_BLOCKS &&
- logical_to_bytes(sdp, sdkp->opt_xfer_blocks) >= PAGE_CACHE_SIZE) {
- q->limits.io_opt = logical_to_bytes(sdp, sdkp->opt_xfer_blocks);
- rw_max = logical_to_sectors(sdp, sdkp->opt_xfer_blocks);
- } else
+ sdkp->opt_xfer_blocks * sdp->sector_size >= PAGE_CACHE_SIZE)
+ rw_max = q->limits.io_opt =
+ sdkp->opt_xfer_blocks * sdp->sector_size;
+ else
rw_max = BLK_DEF_MAX_SECTORS;
/* Combine with controller limits */
diff --git a/drivers/scsi/sd.h b/drivers/scsi/sd.h
index 765a6f1ac1b7..654630bb7d0e 100644
--- a/drivers/scsi/sd.h
+++ b/drivers/scsi/sd.h
@@ -151,11 +151,6 @@ static inline sector_t logical_to_sectors(struct scsi_device *sdev, sector_t blo
return blocks << (ilog2(sdev->sector_size) - 9);
}
-static inline unsigned int logical_to_bytes(struct scsi_device *sdev, sector_t blocks)
-{
- return blocks * sdev->sector_size;
-}
-
/*
* A DIF-capable target device can be formatted with different
* protection schemes. Currently 0 through 3 are defined:
diff --git a/drivers/soc/qcom/glink.c b/drivers/soc/qcom/glink.c
index cc809cbdd839..72f5829d1eb6 100644
--- a/drivers/soc/qcom/glink.c
+++ b/drivers/soc/qcom/glink.c
@@ -1845,7 +1845,7 @@ static void glink_ch_ctx_release(struct rwref_lock *ch_st_lock)
/**
* ch_name_to_ch_ctx_create() - lookup a channel by name, create the channel if
- * it is not found.
+ * it is not found and get reference of context.
* @xprt_ctx: Transport to search for a matching channel.
* @name: Name of the desired channel.
*
@@ -1901,6 +1901,7 @@ check_ctx:
spin_unlock_irqrestore(&xprt_ctx->xprt_ctx_lock_lhb1,
flags);
kfree(ctx);
+ rwref_get(&entry->ch_state_lhb2);
rwref_write_put(&xprt_ctx->xprt_state_lhb0);
return entry;
}
@@ -1935,6 +1936,7 @@ check_ctx:
"%s: local:GLINK_CHANNEL_CLOSED\n",
__func__);
}
+ rwref_get(&ctx->ch_state_lhb2);
spin_unlock_irqrestore(&xprt_ctx->xprt_ctx_lock_lhb1, flags);
rwref_write_put(&xprt_ctx->xprt_state_lhb0);
mutex_lock(&xprt_ctx->xprt_dbgfs_lock_lhb4);
@@ -2579,6 +2581,7 @@ void *glink_open(const struct glink_open_config *cfg)
GLINK_INFO_CH_XPRT(ctx, transport_ptr,
"%s: Channel not ready to be re-opened. State: %u\n",
__func__, ctx->local_open_state);
+ rwref_put(&ctx->ch_state_lhb2);
return ERR_PTR(-EBUSY);
}
@@ -2627,11 +2630,13 @@ void *glink_open(const struct glink_open_config *cfg)
ctx->local_open_state = GLINK_CHANNEL_CLOSED;
GLINK_ERR_CH(ctx, "%s: Unable to send open command %d\n",
__func__, ret);
+ rwref_put(&ctx->ch_state_lhb2);
return ERR_PTR(ret);
}
GLINK_INFO_CH(ctx, "%s: Created channel, sent OPEN command. ctx %p\n",
__func__, ctx);
+ rwref_put(&ctx->ch_state_lhb2);
return ctx;
}
EXPORT_SYMBOL(glink_open);
@@ -4804,6 +4809,7 @@ static void glink_core_rx_cmd_ch_remote_open(struct glink_transport_if *if_ptr,
GLINK_ERR_CH(ctx,
"%s: Duplicate remote open for rcid %u, name '%s'\n",
__func__, rcid, name);
+ rwref_put(&ctx->ch_state_lhb2);
glink_core_migration_edge_unlock(if_ptr->glink_core_priv);
return;
}
@@ -4826,6 +4832,7 @@ static void glink_core_rx_cmd_ch_remote_open(struct glink_transport_if *if_ptr,
if (do_migrate)
ch_migrate(NULL, ctx);
+ rwref_put(&ctx->ch_state_lhb2);
glink_core_migration_edge_unlock(if_ptr->glink_core_priv);
}
diff --git a/drivers/soc/qcom/glink_smem_native_xprt.c b/drivers/soc/qcom/glink_smem_native_xprt.c
index 2dc4208cbc51..85d51807077c 100644
--- a/drivers/soc/qcom/glink_smem_native_xprt.c
+++ b/drivers/soc/qcom/glink_smem_native_xprt.c
@@ -798,6 +798,12 @@ static bool get_rx_fifo(struct edge_info *einfo)
einfo->remote_proc_id,
SMEM_ITEM_CACHED_FLAG);
if (!einfo->rx_fifo)
+ einfo->rx_fifo = smem_get_entry(
+ SMEM_GLINK_NATIVE_XPRT_FIFO_1,
+ &einfo->rx_fifo_size,
+ einfo->remote_proc_id,
+ 0);
+ if (!einfo->rx_fifo)
return false;
}
diff --git a/drivers/soc/qcom/msm_glink_pkt.c b/drivers/soc/qcom/msm_glink_pkt.c
index 78f6a2aa8f66..a92e5c416678 100644
--- a/drivers/soc/qcom/msm_glink_pkt.c
+++ b/drivers/soc/qcom/msm_glink_pkt.c
@@ -625,14 +625,17 @@ ssize_t glink_pkt_read(struct file *file,
return -ENETRESET;
}
+ mutex_lock(&devp->ch_lock);
if (!glink_rx_intent_exists(devp->handle, count)) {
ret = glink_queue_rx_intent(devp->handle, devp, count);
if (ret) {
GLINK_PKT_ERR("%s: failed to queue_rx_intent ret[%d]\n",
__func__, ret);
+ mutex_unlock(&devp->ch_lock);
return ret;
}
}
+ mutex_unlock(&devp->ch_lock);
GLINK_PKT_INFO("Begin %s on glink_pkt_dev id:%d buffer_size %zu\n",
__func__, devp->i, count);
diff --git a/drivers/soc/qcom/qdsp6v2/apr_tal_glink.c b/drivers/soc/qcom/qdsp6v2/apr_tal_glink.c
index 3a6d84140bc9..8a2be787b70e 100644
--- a/drivers/soc/qcom/qdsp6v2/apr_tal_glink.c
+++ b/drivers/soc/qcom/qdsp6v2/apr_tal_glink.c
@@ -114,7 +114,7 @@ int apr_tal_write(struct apr_svc_ch_dev *apr_ch, void *data,
{
int rc = 0, retries = 0;
void *pkt_data = NULL;
- struct apr_tx_buf *tx_buf;
+ struct apr_tx_buf *tx_buf = NULL;
struct apr_pkt_priv *pkt_priv_ptr = pkt_priv;
if (!apr_ch->handle || !pkt_priv)
diff --git a/drivers/soc/qcom/qdsp6v2/audio_notifier.c b/drivers/soc/qcom/qdsp6v2/audio_notifier.c
index a59b436234c7..b46cd2067441 100644
--- a/drivers/soc/qcom/qdsp6v2/audio_notifier.c
+++ b/drivers/soc/qcom/qdsp6v2/audio_notifier.c
@@ -510,7 +510,7 @@ int audio_notifier_deregister(char *client_name)
int ret = 0;
int ret2;
struct list_head *ptr, *next;
- struct client_data *client_data;
+ struct client_data *client_data = NULL;
if (client_name == NULL) {
pr_err("%s: client_name is NULL\n", __func__);
diff --git a/drivers/soc/qcom/qpnp-haptic.c b/drivers/soc/qcom/qpnp-haptic.c
index c86eebcd390f..70cf11359e97 100644
--- a/drivers/soc/qcom/qpnp-haptic.c
+++ b/drivers/soc/qcom/qpnp-haptic.c
@@ -138,7 +138,7 @@
#define QPNP_HAP_WAV_SAMP_MAX 0x7E
#define QPNP_HAP_BRAKE_PAT_LEN 4
#define QPNP_HAP_PLAY_EN 0x80
-#define QPNP_HAP_EN 0x80
+#define QPNP_HAP_EN_BIT BIT(7)
#define QPNP_HAP_BRAKE_MASK BIT(0)
#define QPNP_HAP_AUTO_RES_MASK BIT(7)
#define AUTO_RES_ENABLE BIT(7)
@@ -305,7 +305,6 @@ struct qpnp_pwm_info {
* @ wave_samp - array of wave samples
* @ shadow_wave_samp - shadow array of wave samples
* @ brake_pat - pattern for active breaking
- * @ reg_en_ctl - enable control register
* @ reg_play - play register
* @ lra_res_cal_period - period for resonance calibration
* @ sc_duration - counter to determine the duration of short circuit condition
@@ -358,6 +357,7 @@ struct qpnp_hap {
u32 sc_irq;
u32 status_flags;
u16 base;
+ u16 last_rate_cfg;
u16 drive_period_code_max_limit;
u16 drive_period_code_min_limit;
u16 lra_res_cal_period;
@@ -368,7 +368,6 @@ struct qpnp_hap {
u8 wave_samp[QPNP_HAP_WAV_SAMP_LEN];
u8 shadow_wave_samp[QPNP_HAP_WAV_SAMP_LEN];
u8 brake_pat[QPNP_HAP_BRAKE_PAT_LEN];
- u8 reg_en_ctl;
u8 reg_play;
u8 sc_duration;
u8 ext_pwm_dtest_line;
@@ -391,6 +390,18 @@ struct qpnp_hap {
static struct qpnp_hap *ghap;
/* helper to read a pmic register */
+static int qpnp_hap_read_mult_reg(struct qpnp_hap *hap, u16 addr, u8 *val,
+ int len)
+{
+ int rc;
+
+ rc = regmap_bulk_read(hap->regmap, addr, val, len);
+ if (rc < 0)
+ pr_err("Error reading address: %X - ret %X\n", addr, rc);
+
+ return rc;
+}
+
static int qpnp_hap_read_reg(struct qpnp_hap *hap, u16 addr, u8 *val)
{
int rc;
@@ -399,11 +410,28 @@ static int qpnp_hap_read_reg(struct qpnp_hap *hap, u16 addr, u8 *val)
rc = regmap_read(hap->regmap, addr, &tmp);
if (rc < 0)
pr_err("Error reading address: %X - ret %X\n", addr, rc);
- *val = (u8)tmp;
+ else
+ *val = (u8)tmp;
+
return rc;
}
/* helper to write a pmic register */
+static int qpnp_hap_write_mult_reg(struct qpnp_hap *hap, u16 addr, u8 *val,
+ int len)
+{
+ unsigned long flags;
+ int rc;
+
+ spin_lock_irqsave(&hap->bus_lock, flags);
+ rc = regmap_bulk_write(hap->regmap, addr, val, len);
+ if (rc < 0)
+ pr_err("Error writing address: %X - ret %X\n", addr, rc);
+
+ spin_unlock_irqrestore(&hap->bus_lock, flags);
+ return rc;
+}
+
static int qpnp_hap_write_reg(struct qpnp_hap *hap, u16 addr, u8 val)
{
unsigned long flags;
@@ -480,15 +508,12 @@ static void qpnp_handle_sc_irq(struct work_struct *work)
}
}
-static int qpnp_hap_mod_enable(struct qpnp_hap *hap, int on)
+static int qpnp_hap_mod_enable(struct qpnp_hap *hap, bool on)
{
u8 val;
int rc, i;
- val = hap->reg_en_ctl;
- if (on) {
- val |= QPNP_HAP_EN;
- } else {
+ if (!on) {
for (i = 0; i < QPNP_HAP_MAX_RETRIES; i++) {
/* wait for 4 cycles of play rate */
unsigned long sleep_time =
@@ -511,16 +536,13 @@ static int qpnp_hap_mod_enable(struct qpnp_hap *hap, int on)
if (i >= QPNP_HAP_MAX_RETRIES)
pr_debug("Haptics Busy. Force disable\n");
-
- val &= ~QPNP_HAP_EN;
}
+ val = on ? QPNP_HAP_EN_BIT : 0;
rc = qpnp_hap_write_reg(hap, QPNP_HAP_EN_CTL_REG(hap->base), val);
if (rc < 0)
return rc;
- hap->reg_en_ctl = val;
-
return 0;
}
@@ -1517,20 +1539,23 @@ static int qpnp_hap_auto_res_enable(struct qpnp_hap *hap, int enable)
static void update_lra_frequency(struct qpnp_hap *hap)
{
- u8 lra_auto_res_lo = 0, lra_auto_res_hi = 0, val;
+ u8 lra_auto_res[2], val;
u32 play_rate_code;
+ u16 rate_cfg;
int rc;
- qpnp_hap_read_reg(hap, QPNP_HAP_LRA_AUTO_RES_LO(hap->base),
- &lra_auto_res_lo);
- qpnp_hap_read_reg(hap, QPNP_HAP_LRA_AUTO_RES_HI(hap->base),
- &lra_auto_res_hi);
+ rc = qpnp_hap_read_mult_reg(hap, QPNP_HAP_LRA_AUTO_RES_LO(hap->base),
+ lra_auto_res, 2);
+ if (rc < 0) {
+ pr_err("Error in reading LRA_AUTO_RES_LO/HI, rc=%d\n", rc);
+ return;
+ }
play_rate_code =
- (lra_auto_res_hi & 0xF0) << 4 | (lra_auto_res_lo & 0xFF);
+ (lra_auto_res[1] & 0xF0) << 4 | (lra_auto_res[0] & 0xFF);
pr_debug("lra_auto_res_lo = 0x%x lra_auto_res_hi = 0x%x play_rate_code = 0x%x\n",
- lra_auto_res_lo, lra_auto_res_hi, play_rate_code);
+ lra_auto_res[0], lra_auto_res[1], play_rate_code);
rc = qpnp_hap_read_reg(hap, QPNP_HAP_STATUS(hap->base), &val);
if (rc < 0)
@@ -1559,12 +1584,21 @@ static void update_lra_frequency(struct qpnp_hap *hap)
return;
}
- qpnp_hap_write_reg(hap, QPNP_HAP_RATE_CFG1_REG(hap->base),
- lra_auto_res_lo);
+ lra_auto_res[1] >>= 4;
+ rate_cfg = lra_auto_res[1] << 8 | lra_auto_res[0];
+ if (hap->last_rate_cfg == rate_cfg) {
+ pr_debug("Same rate_cfg, skip updating\n");
+ return;
+ }
- lra_auto_res_hi = lra_auto_res_hi >> 4;
- qpnp_hap_write_reg(hap, QPNP_HAP_RATE_CFG2_REG(hap->base),
- lra_auto_res_hi);
+ rc = qpnp_hap_write_mult_reg(hap, QPNP_HAP_RATE_CFG1_REG(hap->base),
+ lra_auto_res, 2);
+ if (rc < 0) {
+ pr_err("Error in writing to RATE_CFG1/2, rc=%d\n", rc);
+ } else {
+ pr_debug("Update RATE_CFG with [0x%x]\n", rate_cfg);
+ hap->last_rate_cfg = rate_cfg;
+ }
}
static enum hrtimer_restart detect_auto_res_error(struct hrtimer *timer)
@@ -1983,6 +2017,8 @@ static int qpnp_hap_config(struct qpnp_hap *hap)
if (rc)
return rc;
+ hap->last_rate_cfg = hap->init_drive_period_code;
+
if (hap->act_type == QPNP_HAP_LRA &&
hap->perform_lra_auto_resonance_search)
calculate_lra_code(hap);
@@ -2019,12 +2055,6 @@ static int qpnp_hap_config(struct qpnp_hap *hap)
return rc;
}
- /* Cache enable control register */
- rc = qpnp_hap_read_reg(hap, QPNP_HAP_EN_CTL_REG(hap->base), &val);
- if (rc < 0)
- return rc;
- hap->reg_en_ctl = val;
-
/* Cache play register */
rc = qpnp_hap_read_reg(hap, QPNP_HAP_PLAY_REG(hap->base), &val);
if (rc < 0)
diff --git a/drivers/soc/qcom/rpm-smd.c b/drivers/soc/qcom/rpm-smd.c
index f2784dedbc7a..e792c953f31f 100644
--- a/drivers/soc/qcom/rpm-smd.c
+++ b/drivers/soc/qcom/rpm-smd.c
@@ -108,9 +108,7 @@ static struct glink_apps_rpm_data *glink_data;
#define RPM_DATA_LEN_SIZE 16
#define RPM_HDR_SIZE ((rpm_msg_fmt_ver == RPM_MSG_V0_FMT) ?\
sizeof(struct rpm_v0_hdr) : sizeof(struct rpm_v1_hdr))
-#define GET_FIELD(offset, size) (((1U << (offset + size)) - 1) - \
- ((1U << offset) - 1))
-#define CLEAR_FIELD(offset, size) (~GET_FIELD(offset, size))
+#define CLEAR_FIELD(offset, size) (~GENMASK(offset + size - 1, offset))
static ATOMIC_NOTIFIER_HEAD(msm_rpm_sleep_notifier);
static bool standalone;
@@ -223,7 +221,7 @@ static uint32_t msm_rpm_get_next_msg_id(void);
static inline uint32_t get_offset_value(uint32_t val, uint32_t offset,
uint32_t size)
{
- return (((val) & GET_FIELD(offset, size))
+ return (((val) & GENMASK(offset + size - 1, offset))
>> offset);
}
diff --git a/drivers/soc/qcom/service-locator.c b/drivers/soc/qcom/service-locator.c
index 0625f75de373..97cd11201262 100644
--- a/drivers/soc/qcom/service-locator.c
+++ b/drivers/soc/qcom/service-locator.c
@@ -24,7 +24,6 @@
#include <linux/device.h>
#include <linux/delay.h>
#include <linux/workqueue.h>
-#include <linux/debugfs.h>
#include <soc/qcom/msm_qmi_interface.h>
#include <soc/qcom/service-locator.h>
@@ -440,140 +439,3 @@ int find_subsys(const char *pd_path, char *subsys)
return 0;
}
EXPORT_SYMBOL(find_subsys);
-
-static struct pd_qmi_client_data test_data;
-
-static int servloc_test_pdr_cb(struct notifier_block *this,
- unsigned long opcode, void *ptr)
-{
- int i, rc = 0;
- char subsys[QMI_SERVREG_LOC_NAME_LENGTH_V01];
- struct pd_qmi_client_data *return_data;
-
- return_data = (struct pd_qmi_client_data *)ptr;
-
- if (opcode) {
- pr_err("%s: Failed to get process domain!, opcode = %lu\n",
- __func__, opcode);
- return -EIO;
- }
-
- pr_err("Service Name: %s\tTotal Domains: %d\n",
- return_data->service_name, return_data->total_domains);
-
- for (i = 0; i < return_data->total_domains; i++) {
- pr_err("Instance ID: %d\t ",
- return_data->domain_list[i].instance_id);
- pr_err("Domain Name: %s\n",
- return_data->domain_list[i].name);
- rc = find_subsys(return_data->domain_list[i].name,
- subsys);
- if (rc < 0)
- pr_err("No valid subsys found for %s!\n",
- return_data->domain_list[i].name);
- else
- pr_err("Subsys: %s\n", subsys);
- }
- return 0;
-}
-
-static struct notifier_block pdr_service_nb = {
- .notifier_call = servloc_test_pdr_cb,
-};
-
-static ssize_t servloc_read(struct file *filp, char __user *ubuf,
- size_t cnt, loff_t *ppos)
-{
- int rc = 0;
- char *node_name = filp->private_data;
-
- if (!strcmp(node_name, "test_servloc_get"))
- rc = get_service_location(test_data.client_name,
- test_data.service_name, &pdr_service_nb);
-
- return rc;
-}
-
-static ssize_t servloc_write(struct file *fp, const char __user *buf,
- size_t count, loff_t *unused)
-{
- char *node_name = fp->private_data;
-
- if (!buf)
- return -EIO;
- if (!strcmp(node_name, "service_name")) {
- snprintf(test_data.service_name, sizeof(test_data.service_name),
- "%.*s", (int) min((size_t)count - 1,
- (sizeof(test_data.service_name) - 1)), buf);
- } else {
- snprintf(test_data.client_name, sizeof(test_data.client_name),
- "%.*s", (int) min((size_t)count - 1,
- (sizeof(test_data.client_name) - 1)), buf);
- }
- return count;
-}
-
-static const struct file_operations servloc_fops = {
- .open = simple_open,
- .read = servloc_read,
- .write = servloc_write,
-};
-
-static struct dentry *servloc_base_dir;
-static struct dentry *test_servloc_file;
-
-static int __init servloc_debugfs_init(void)
-{
- servloc_base_dir = debugfs_create_dir("test_servloc", NULL);
- return !servloc_base_dir ? -ENOMEM : 0;
-}
-
-static void servloc_debugfs_exit(void)
-{
- debugfs_remove_recursive(servloc_base_dir);
-}
-
-static int servloc_debugfs_add(void)
-{
- int rc;
-
- if (!servloc_base_dir)
- return -ENOMEM;
-
- test_servloc_file = debugfs_create_file("client_name",
- S_IRUGO | S_IWUSR, servloc_base_dir,
- "client_name", &servloc_fops);
- rc = !test_servloc_file ? -ENOMEM : 0;
-
- if (rc == 0) {
- test_servloc_file = debugfs_create_file("service_name",
- S_IRUGO | S_IWUSR, servloc_base_dir,
- "service_name", &servloc_fops);
- rc = !test_servloc_file ? -ENOMEM : 0;
- }
-
- if (rc == 0) {
- test_servloc_file = debugfs_create_file("test_servloc_get",
- S_IRUGO | S_IWUSR, servloc_base_dir,
- "test_servloc_get", &servloc_fops);
- rc = !test_servloc_file ? -ENOMEM : 0;
- }
- return rc;
-}
-
-static int __init service_locator_init(void)
-{
- pr_debug("service_locator_status = %d\n", locator_status);
- if (servloc_debugfs_init())
- pr_err("Could not create test_servloc base directory!");
- if (servloc_debugfs_add())
- pr_err("Could not create test_servloc node entries!");
- return 0;
-}
-
-static void __exit service_locator_exit(void)
-{
- servloc_debugfs_exit();
-}
-module_init(service_locator_init);
-module_exit(service_locator_exit);
diff --git a/drivers/soc/qcom/service-notifier.c b/drivers/soc/qcom/service-notifier.c
index fa916ac5ade4..2b6e05a1720f 100644
--- a/drivers/soc/qcom/service-notifier.c
+++ b/drivers/soc/qcom/service-notifier.c
@@ -21,7 +21,6 @@
#include <linux/slab.h>
#include <linux/of.h>
#include <linux/err.h>
-#include <linux/debugfs.h>
#include <linux/uaccess.h>
#include <soc/qcom/subsystem_restart.h>
@@ -188,7 +187,7 @@ static void root_service_clnt_notify(struct qmi_handle *handle,
switch (event) {
case QMI_RECV_MSG:
- schedule_work(&data->svc_rcv_msg);
+ queue_work(data->svc_event_wq, &data->svc_rcv_msg);
break;
default:
break;
@@ -752,179 +751,3 @@ int service_notif_unregister_notifier(void *service_notif_handle,
&service_notif->service_notif_rcvr_list, nb);
}
EXPORT_SYMBOL(service_notif_unregister_notifier);
-
-struct service_notifier_test_data {
- char service_path[MAX_STRING_LEN];
- int instance_id;
- struct notifier_block nb;
- void *service_notif_handle;
-};
-
-static struct service_notifier_test_data test_data;
-
-static void print_service_provider_state(int notification, char *type)
-{
- if (notification == SERVREG_NOTIF_SERVICE_STATE_DOWN_V01)
- pr_info("%s: Service %s down!\n", type, test_data.service_path);
- else if (notification == SERVREG_NOTIF_SERVICE_STATE_UP_V01)
- pr_info("%s: Service %s up!\n", type, test_data.service_path);
- else if (notification == SERVREG_NOTIF_SERVICE_STATE_UNINIT_V01)
- pr_info("%s: Service %s state uninit!\n", type,
- test_data.service_path);
- else
- pr_info("%s: Service %s state Unknown 0x%x!\n", type,
- test_data.service_path, notification);
-}
-
-static int nb_callback(struct notifier_block *nb,
- unsigned long notification,
- void *data)
-{
- print_service_provider_state((int)notification, "Notification:");
- return 0;
-}
-
-static ssize_t show_service_path(struct seq_file *f, void *unused)
-{
- if (test_data.service_notif_handle)
- seq_printf(f, "Service Path: %s\n", test_data.service_path);
- else
- seq_puts(f, "No existing notifier\n");
- return 0;
-}
-
-
-static ssize_t set_service_notifier_register(struct file *fp,
- const char __user *buf,
- size_t count, loff_t *ppos)
-{
- int curr_state = INT_MAX, rc;
-
- if (!buf)
- return -EIO;
- if (test_data.service_notif_handle) {
- service_notif_unregister_notifier(
- test_data.service_notif_handle,
- &test_data.nb);
- test_data.service_notif_handle = NULL;
- pr_info("Unregistering existing notifier for %s\n",
- test_data.service_path);
- }
- rc = simple_write_to_buffer(test_data.service_path, MAX_STRING_LEN,
- ppos, buf, count - 1);
- if (rc != count - 1) {
- pr_err("Unable to read data into kernel buffer\n");
- goto err;
- }
- test_data.nb.notifier_call = nb_callback;
- test_data.service_notif_handle = service_notif_register_notifier(
- test_data.service_path,
- test_data.instance_id, &test_data.nb,
- &curr_state);
- if (!IS_ERR(test_data.service_notif_handle)) {
- pr_info("Notifier Registered for service %s\n",
- test_data.service_path);
- print_service_provider_state(curr_state, "Initial State");
- return count;
- }
-err:
- test_data.service_notif_handle = NULL;
- pr_err("Unable to register notifier for %s\n", test_data.service_path);
- return -EIO;
-}
-
-static int open_service_notifier_register(struct inode *inode, struct file *f)
-{
- return single_open(f, (void *) show_service_path,
- inode->i_private);
-}
-
-static const struct file_operations service_notifier_register_fops = {
- .open = open_service_notifier_register,
- .read = seq_read,
- .write = set_service_notifier_register,
- .llseek = seq_lseek,
- .release = seq_release,
-};
-
-static ssize_t show_service_notifier_id(struct seq_file *f, void *unused)
-{
- seq_printf(f, "Service instance ID: %d\n", test_data.instance_id);
- return 0;
-}
-
-static ssize_t set_service_notifier_id(struct file *fp,
- const char __user *buf,
- size_t count, loff_t *unused)
-{
- int val, rc;
- char kbuf[MAX_STRING_LEN];
-
- if (count > MAX_STRING_LEN) {
- rc = -EIO;
- goto err;
- }
- rc = copy_from_user(kbuf, buf, count);
- if (rc != 0) {
- rc = -EFAULT;
- goto err;
- }
-
- kbuf[count - 1] = '\0';
- rc = kstrtoint(kbuf, 0, &val);
- if (rc < 0)
- goto err;
-
- test_data.instance_id = val;
- return count;
-err:
- pr_err("Invalid input parameters: rc = %d\n", rc);
- return rc;
-}
-
-static int open_service_notifier_id(struct inode *inode, struct file *f)
-{
- return single_open(f, (void *) show_service_notifier_id,
- inode->i_private);
-}
-
-static const struct file_operations service_notifier_id_fops = {
- .open = open_service_notifier_id,
- .read = seq_read,
- .write = set_service_notifier_id,
- .llseek = seq_lseek,
- .release = seq_release,
-};
-
-static struct dentry *service_notifier_dir;
-static struct dentry *service_path_file;
-static struct dentry *service_id_file;
-
-static int __init service_notifier_init(void)
-{
- service_notifier_dir = debugfs_create_dir("service_notifier", NULL);
- if (service_notifier_dir) {
- service_path_file = debugfs_create_file("service_path",
- S_IRUGO | S_IWUSR, service_notifier_dir, NULL,
- &service_notifier_register_fops);
- if (!service_path_file)
- goto err;
- service_id_file = debugfs_create_file("service_id",
- S_IRUGO | S_IWUSR, service_notifier_dir, NULL,
- &service_notifier_id_fops);
- if (!service_id_file)
- goto err;
- }
- return 0;
-err:
- debugfs_remove_recursive(service_notifier_dir);
- return 0;
-}
-
-static void __exit service_notifier_exit(void)
-{
- debugfs_remove_recursive(service_notifier_dir);
- test_data.nb.notifier_call = nb_callback;
-}
-module_init(service_notifier_init);
-module_exit(service_notifier_exit);
diff --git a/drivers/soc/qcom/socinfo.c b/drivers/soc/qcom/socinfo.c
index dd3e545eb7da..c1d8748a5d08 100644
--- a/drivers/soc/qcom/socinfo.c
+++ b/drivers/soc/qcom/socinfo.c
@@ -46,6 +46,7 @@
#define SMEM_IMAGE_VERSION_OEM_OFFSET 95
#define SMEM_IMAGE_VERSION_PARTITION_APPS 10
+static DECLARE_RWSEM(current_image_rwsem);
enum {
HW_PLATFORM_UNKNOWN = 0,
HW_PLATFORM_SURF = 1,
@@ -530,7 +531,7 @@ static struct msm_soc_info cpu_of_id[] = {
/* Cobalt IDs */
[292] = {MSM_CPU_8998, "MSM8998"},
- [319] = {MSM_CPU_8998, "APQ8998"},
+ [319] = {MSM_CPU_8998, "APQ8098"},
/* Hamster ID */
[306] = {MSM_CPU_HAMSTER, "MSMHAMSTER"},
@@ -899,7 +900,9 @@ msm_get_image_version(struct device *dev,
pr_err("Failed to get image version base address");
return snprintf(buf, SMEM_IMAGE_VERSION_NAME_SIZE, "Unknown");
}
+ down_read(&current_image_rwsem);
string_address += current_image * SMEM_IMAGE_VERSION_SINGLE_BLOCK_SIZE;
+ up_read(&current_image_rwsem);
return snprintf(buf, SMEM_IMAGE_VERSION_NAME_SIZE, "%-.75s\n",
string_address);
}
@@ -912,14 +915,19 @@ msm_set_image_version(struct device *dev,
{
char *store_address;
- if (current_image != SMEM_IMAGE_VERSION_PARTITION_APPS)
+ down_read(&current_image_rwsem);
+ if (current_image != SMEM_IMAGE_VERSION_PARTITION_APPS) {
+ up_read(&current_image_rwsem);
return count;
+ }
store_address = socinfo_get_image_version_base_address();
if (IS_ERR_OR_NULL(store_address)) {
pr_err("Failed to get image version base address");
+ up_read(&current_image_rwsem);
return count;
}
store_address += current_image * SMEM_IMAGE_VERSION_SINGLE_BLOCK_SIZE;
+ up_read(&current_image_rwsem);
snprintf(store_address, SMEM_IMAGE_VERSION_NAME_SIZE, "%-.75s", buf);
return count;
}
@@ -937,7 +945,9 @@ msm_get_image_variant(struct device *dev,
return snprintf(buf, SMEM_IMAGE_VERSION_VARIANT_SIZE,
"Unknown");
}
+ down_read(&current_image_rwsem);
string_address += current_image * SMEM_IMAGE_VERSION_SINGLE_BLOCK_SIZE;
+ up_read(&current_image_rwsem);
string_address += SMEM_IMAGE_VERSION_VARIANT_OFFSET;
return snprintf(buf, SMEM_IMAGE_VERSION_VARIANT_SIZE, "%-.20s\n",
string_address);
@@ -951,14 +961,19 @@ msm_set_image_variant(struct device *dev,
{
char *store_address;
- if (current_image != SMEM_IMAGE_VERSION_PARTITION_APPS)
+ down_read(&current_image_rwsem);
+ if (current_image != SMEM_IMAGE_VERSION_PARTITION_APPS) {
+ up_read(&current_image_rwsem);
return count;
+ }
store_address = socinfo_get_image_version_base_address();
if (IS_ERR_OR_NULL(store_address)) {
pr_err("Failed to get image version base address");
+ up_read(&current_image_rwsem);
return count;
}
store_address += current_image * SMEM_IMAGE_VERSION_SINGLE_BLOCK_SIZE;
+ up_read(&current_image_rwsem);
store_address += SMEM_IMAGE_VERSION_VARIANT_OFFSET;
snprintf(store_address, SMEM_IMAGE_VERSION_VARIANT_SIZE, "%-.20s", buf);
return count;
@@ -976,7 +991,9 @@ msm_get_image_crm_version(struct device *dev,
pr_err("Failed to get image version base address");
return snprintf(buf, SMEM_IMAGE_VERSION_OEM_SIZE, "Unknown");
}
+ down_read(&current_image_rwsem);
string_address += current_image * SMEM_IMAGE_VERSION_SINGLE_BLOCK_SIZE;
+ up_read(&current_image_rwsem);
string_address += SMEM_IMAGE_VERSION_OEM_OFFSET;
return snprintf(buf, SMEM_IMAGE_VERSION_OEM_SIZE, "%-.33s\n",
string_address);
@@ -990,14 +1007,19 @@ msm_set_image_crm_version(struct device *dev,
{
char *store_address;
- if (current_image != SMEM_IMAGE_VERSION_PARTITION_APPS)
+ down_read(&current_image_rwsem);
+ if (current_image != SMEM_IMAGE_VERSION_PARTITION_APPS) {
+ up_read(&current_image_rwsem);
return count;
+ }
store_address = socinfo_get_image_version_base_address();
if (IS_ERR_OR_NULL(store_address)) {
pr_err("Failed to get image version base address");
+ up_read(&current_image_rwsem);
return count;
}
store_address += current_image * SMEM_IMAGE_VERSION_SINGLE_BLOCK_SIZE;
+ up_read(&current_image_rwsem);
store_address += SMEM_IMAGE_VERSION_OEM_OFFSET;
snprintf(store_address, SMEM_IMAGE_VERSION_OEM_SIZE, "%-.33s", buf);
return count;
@@ -1008,8 +1030,14 @@ msm_get_image_number(struct device *dev,
struct device_attribute *attr,
char *buf)
{
- return snprintf(buf, PAGE_SIZE, "%d\n",
+ int ret;
+
+ down_read(&current_image_rwsem);
+ ret = snprintf(buf, PAGE_SIZE, "%d\n",
current_image);
+ up_read(&current_image_rwsem);
+ return ret;
+
}
static ssize_t
@@ -1021,10 +1049,12 @@ msm_select_image(struct device *dev, struct device_attribute *attr,
ret = kstrtoint(buf, 10, &digit);
if (ret)
return ret;
+ down_write(&current_image_rwsem);
if (0 <= digit && digit < SMEM_IMAGE_VERSION_BLOCKS_COUNT)
current_image = digit;
else
current_image = 0;
+ up_write(&current_image_rwsem);
return count;
}
@@ -1235,9 +1265,9 @@ static void * __init setup_dummy_socinfo(void)
dummy_socinfo.id = 327;
strlcpy(dummy_socinfo.build_id, "sda630 - ",
sizeof(dummy_socinfo.build_id));
- } else if (early_machine_is_apq8998()) {
+ } else if (early_machine_is_apq8098()) {
dummy_socinfo.id = 319;
- strlcpy(dummy_socinfo.build_id, "apq8998 - ",
+ strlcpy(dummy_socinfo.build_id, "apq8098 - ",
sizeof(dummy_socinfo.build_id));
}
diff --git a/drivers/soc/qcom/spcom.c b/drivers/soc/qcom/spcom.c
index 0c44d76bc7c7..f7b9c3f85a30 100644
--- a/drivers/soc/qcom/spcom.c
+++ b/drivers/soc/qcom/spcom.c
@@ -898,12 +898,12 @@ static int spcom_rx(struct spcom_channel *ch,
goto exit_err;
}
+copy_buf:
if (!ch->glink_rx_buf) {
pr_err("invalid glink_rx_buf.\n");
goto exit_err;
}
-copy_buf:
/* Copy from glink buffer to spcom buffer */
size = min_t(int, ch->actual_rx_size, size);
memcpy(buf, ch->glink_rx_buf, size);
diff --git a/drivers/soc/qcom/subsystem_restart.c b/drivers/soc/qcom/subsystem_restart.c
index c35ec26fefa2..d3d0b8594c9f 100644
--- a/drivers/soc/qcom/subsystem_restart.c
+++ b/drivers/soc/qcom/subsystem_restart.c
@@ -28,7 +28,6 @@
#include <linux/spinlock.h>
#include <linux/device.h>
#include <linux/idr.h>
-#include <linux/debugfs.h>
#include <linux/interrupt.h>
#include <linux/of_gpio.h>
#include <linux/cdev.h>
@@ -149,7 +148,6 @@ struct restart_log {
* @restart_level: restart level (0 - panic, 1 - related, 2 - independent, etc.)
* @restart_order: order of other devices this devices restarts with
* @crash_count: number of times the device has crashed
- * @dentry: debugfs directory for this device
* @do_ramdump_on_put: ramdump on subsystem_put() if true
* @err_ready: completion variable to record error ready from subsystem
* @crashed: indicates if subsystem has crashed
@@ -171,9 +169,6 @@ struct subsys_device {
int restart_level;
int crash_count;
struct subsys_soc_restart_order *restart_order;
-#ifdef CONFIG_DEBUG_FS
- struct dentry *dentry;
-#endif
bool do_ramdump_on_put;
struct cdev char_dev;
dev_t dev_no;
@@ -352,10 +347,11 @@ static struct device_attribute subsys_attrs[] = {
__ATTR_NULL,
};
-static struct bus_type subsys_bus_type = {
+struct bus_type subsys_bus_type = {
.name = "msm_subsys",
.dev_attrs = subsys_attrs,
};
+EXPORT_SYMBOL(subsys_bus_type);
static DEFINE_IDA(subsys_ida);
@@ -1169,87 +1165,6 @@ void notify_proxy_unvote(struct device *device)
notify_each_subsys_device(&dev, 1, SUBSYS_PROXY_UNVOTE, NULL);
}
-#ifdef CONFIG_DEBUG_FS
-static ssize_t subsys_debugfs_read(struct file *filp, char __user *ubuf,
- size_t cnt, loff_t *ppos)
-{
- int r;
- char buf[40];
- struct subsys_device *subsys = filp->private_data;
-
- r = snprintf(buf, sizeof(buf), "%d\n", subsys->count);
- return simple_read_from_buffer(ubuf, cnt, ppos, buf, r);
-}
-
-static ssize_t subsys_debugfs_write(struct file *filp,
- const char __user *ubuf, size_t cnt, loff_t *ppos)
-{
- struct subsys_device *subsys = filp->private_data;
- char buf[10];
- char *cmp;
-
- cnt = min(cnt, sizeof(buf) - 1);
- if (copy_from_user(&buf, ubuf, cnt))
- return -EFAULT;
- buf[cnt] = '\0';
- cmp = strstrip(buf);
-
- if (!strcmp(cmp, "restart")) {
- if (subsystem_restart_dev(subsys))
- return -EIO;
- } else if (!strcmp(cmp, "get")) {
- if (subsystem_get(subsys->desc->name))
- return -EIO;
- } else if (!strcmp(cmp, "put")) {
- subsystem_put(subsys);
- } else {
- return -EINVAL;
- }
-
- return cnt;
-}
-
-static const struct file_operations subsys_debugfs_fops = {
- .open = simple_open,
- .read = subsys_debugfs_read,
- .write = subsys_debugfs_write,
-};
-
-static struct dentry *subsys_base_dir;
-
-static int __init subsys_debugfs_init(void)
-{
- subsys_base_dir = debugfs_create_dir("msm_subsys", NULL);
- return !subsys_base_dir ? -ENOMEM : 0;
-}
-
-static void subsys_debugfs_exit(void)
-{
- debugfs_remove_recursive(subsys_base_dir);
-}
-
-static int subsys_debugfs_add(struct subsys_device *subsys)
-{
- if (!subsys_base_dir)
- return -ENOMEM;
-
- subsys->dentry = debugfs_create_file(subsys->desc->name,
- S_IRUGO | S_IWUSR, subsys_base_dir,
- subsys, &subsys_debugfs_fops);
- return !subsys->dentry ? -ENOMEM : 0;
-}
-
-static void subsys_debugfs_remove(struct subsys_device *subsys)
-{
- debugfs_remove(subsys->dentry);
-}
-#else
-static int __init subsys_debugfs_init(void) { return 0; };
-static void subsys_debugfs_exit(void) { }
-static int subsys_debugfs_add(struct subsys_device *subsys) { return 0; }
-static void subsys_debugfs_remove(struct subsys_device *subsys) { }
-#endif
-
static int subsys_device_open(struct inode *inode, struct file *file)
{
struct subsys_device *device, *subsys_dev = 0;
@@ -1686,17 +1601,8 @@ struct subsys_device *subsys_register(struct subsys_desc *desc)
mutex_init(&subsys->track.lock);
- ret = subsys_debugfs_add(subsys);
- if (ret) {
- ida_simple_remove(&subsys_ida, subsys->id);
- wakeup_source_trash(&subsys->ssr_wlock);
- kfree(subsys);
- return ERR_PTR(ret);
- }
-
ret = device_register(&subsys->dev);
if (ret) {
- subsys_debugfs_remove(subsys);
put_device(&subsys->dev);
return ERR_PTR(ret);
}
@@ -1758,7 +1664,6 @@ err_setup_irqs:
if (ofnode)
subsys_remove_restart_order(ofnode);
err_register:
- subsys_debugfs_remove(subsys);
device_unregister(&subsys->dev);
return ERR_PTR(ret);
}
@@ -1787,7 +1692,6 @@ void subsys_unregister(struct subsys_device *subsys)
WARN_ON(subsys->count);
device_unregister(&subsys->dev);
mutex_unlock(&subsys->track.lock);
- subsys_debugfs_remove(subsys);
subsys_char_device_remove(subsys);
sysmon_notifier_unregister(subsys->desc);
if (subsys->desc->edge)
@@ -1827,9 +1731,6 @@ static int __init subsys_restart_init(void)
ret = bus_register(&subsys_bus_type);
if (ret)
goto err_bus;
- ret = subsys_debugfs_init();
- if (ret)
- goto err_debugfs;
char_class = class_create(THIS_MODULE, "subsys");
if (IS_ERR(char_class)) {
@@ -1848,8 +1749,6 @@ static int __init subsys_restart_init(void)
err_soc:
class_destroy(char_class);
err_class:
- subsys_debugfs_exit();
-err_debugfs:
bus_unregister(&subsys_bus_type);
err_bus:
destroy_workqueue(ssr_wq);
diff --git a/drivers/spi/spi_qsd.c b/drivers/spi/spi_qsd.c
index 6f75eee8f921..8efe18dcc98f 100644
--- a/drivers/spi/spi_qsd.c
+++ b/drivers/spi/spi_qsd.c
@@ -45,6 +45,8 @@
#include <linux/msm-bus-board.h>
#include "spi_qsd.h"
+#define SPI_MAX_BYTES_PER_WORD (4)
+
static int msm_spi_pm_resume_runtime(struct device *device);
static int msm_spi_pm_suspend_runtime(struct device *device);
static inline void msm_spi_dma_unmap_buffers(struct msm_spi *dd);
@@ -438,10 +440,12 @@ static void msm_spi_read_word_from_fifo(struct msm_spi *dd)
u32 data_in;
int i;
int shift;
+ int read_bytes = (dd->pack_words ?
+ SPI_MAX_BYTES_PER_WORD : dd->bytes_per_word);
data_in = readl_relaxed(dd->base + SPI_INPUT_FIFO);
if (dd->read_buf) {
- for (i = 0; (i < dd->bytes_per_word) &&
+ for (i = 0; (i < read_bytes) &&
dd->rx_bytes_remaining; i++) {
/* The data format depends on bytes_per_word:
4 bytes: 0x12345678
@@ -454,8 +458,8 @@ static void msm_spi_read_word_from_fifo(struct msm_spi *dd)
dd->rx_bytes_remaining--;
}
} else {
- if (dd->rx_bytes_remaining >= dd->bytes_per_word)
- dd->rx_bytes_remaining -= dd->bytes_per_word;
+ if (dd->rx_bytes_remaining >= read_bytes)
+ dd->rx_bytes_remaining -= read_bytes;
else
dd->rx_bytes_remaining = 0;
}
@@ -552,7 +556,7 @@ msm_spi_set_bpw_and_no_io_flags(struct msm_spi *dd, u32 *config, int n)
if (n != (*config & SPI_CFG_N))
*config = (*config & ~SPI_CFG_N) | n;
- if (dd->mode == SPI_BAM_MODE) {
+ if (dd->tx_mode == SPI_BAM_MODE) {
if (dd->read_buf == NULL)
*config |= SPI_NO_INPUT;
if (dd->write_buf == NULL)
@@ -617,25 +621,34 @@ static void msm_spi_set_spi_config(struct msm_spi *dd, int bpw)
static void msm_spi_set_mx_counts(struct msm_spi *dd, u32 n_words)
{
/*
- * n_words cannot exceed fifo_size, and only one READ COUNT
- * interrupt is generated per transaction, so for transactions
- * larger than fifo size READ COUNT must be disabled.
- * For those transactions we usually move to Data Mover mode.
+ * For FIFO mode:
+ * - Set the MX_OUTPUT_COUNT/MX_INPUT_COUNT registers to 0
+ * - Set the READ/WRITE_COUNT registers to 0 (infinite mode)
+ * or num bytes (finite mode) if less than fifo worth of data.
+ * For Block mode:
+ * - Set the MX_OUTPUT/MX_INPUT_COUNT registers to num xfer bytes.
+ * - Set the READ/WRITE_COUNT registers to 0.
*/
- if (dd->mode == SPI_FIFO_MODE) {
- if (n_words <= dd->input_fifo_size) {
- writel_relaxed(n_words,
- dd->base + SPI_MX_READ_COUNT);
- msm_spi_set_write_count(dd, n_words);
- } else {
- writel_relaxed(0, dd->base + SPI_MX_READ_COUNT);
- msm_spi_set_write_count(dd, 0);
- }
- if (dd->qup_ver == SPI_QUP_VERSION_BFAM) {
- /* must be zero for FIFO */
- writel_relaxed(0, dd->base + SPI_MX_INPUT_COUNT);
+ if (dd->tx_mode != SPI_BAM_MODE) {
+ if (dd->tx_mode == SPI_FIFO_MODE) {
+ if (n_words <= dd->input_fifo_size)
+ msm_spi_set_write_count(dd, n_words);
+ else
+ msm_spi_set_write_count(dd, 0);
writel_relaxed(0, dd->base + SPI_MX_OUTPUT_COUNT);
- }
+ } else
+ writel_relaxed(n_words, dd->base + SPI_MX_OUTPUT_COUNT);
+
+ if (dd->rx_mode == SPI_FIFO_MODE) {
+ if (n_words <= dd->input_fifo_size)
+ writel_relaxed(n_words,
+ dd->base + SPI_MX_READ_COUNT);
+ else
+ writel_relaxed(0,
+ dd->base + SPI_MX_READ_COUNT);
+ writel_relaxed(0, dd->base + SPI_MX_INPUT_COUNT);
+ } else
+ writel_relaxed(n_words, dd->base + SPI_MX_INPUT_COUNT);
} else {
/* must be zero for BAM and DMOV */
writel_relaxed(0, dd->base + SPI_MX_READ_COUNT);
@@ -882,7 +895,7 @@ xfr_err:
static int
msm_spi_bam_next_transfer(struct msm_spi *dd)
{
- if (dd->mode != SPI_BAM_MODE)
+ if (dd->tx_mode != SPI_BAM_MODE)
return 0;
if (dd->tx_bytes_remaining > 0) {
@@ -901,7 +914,7 @@ msm_spi_bam_next_transfer(struct msm_spi *dd)
static int msm_spi_dma_send_next(struct msm_spi *dd)
{
int ret = 0;
- if (dd->mode == SPI_BAM_MODE)
+ if (dd->tx_mode == SPI_BAM_MODE)
ret = msm_spi_bam_next_transfer(dd);
return ret;
}
@@ -932,32 +945,38 @@ static inline irqreturn_t msm_spi_qup_irq(int irq, void *dev_id)
}
op = readl_relaxed(dd->base + SPI_OPERATIONAL);
+ writel_relaxed(op, dd->base + SPI_OPERATIONAL);
+ /*
+ * Ensure service flag was cleared before further
+ * processing of interrupt.
+ */
+ mb();
if (op & SPI_OP_INPUT_SERVICE_FLAG) {
- writel_relaxed(SPI_OP_INPUT_SERVICE_FLAG,
- dd->base + SPI_OPERATIONAL);
- /*
- * Ensure service flag was cleared before further
- * processing of interrupt.
- */
- mb();
ret |= msm_spi_input_irq(irq, dev_id);
}
if (op & SPI_OP_OUTPUT_SERVICE_FLAG) {
- writel_relaxed(SPI_OP_OUTPUT_SERVICE_FLAG,
- dd->base + SPI_OPERATIONAL);
- /*
- * Ensure service flag was cleared before further
- * processing of interrupt.
- */
- mb();
ret |= msm_spi_output_irq(irq, dev_id);
}
- if (dd->done) {
+ if (dd->tx_mode != SPI_BAM_MODE) {
+ if (!dd->rx_done) {
+ if (dd->rx_bytes_remaining == 0)
+ dd->rx_done = true;
+ }
+ if (!dd->tx_done) {
+ if (!dd->tx_bytes_remaining &&
+ (op & SPI_OP_IP_FIFO_NOT_EMPTY)) {
+ dd->tx_done = true;
+ }
+ }
+ }
+ if (dd->tx_done && dd->rx_done) {
+ msm_spi_set_state(dd, SPI_OP_STATE_RESET);
+ dd->tx_done = false;
+ dd->rx_done = false;
complete(&dd->rx_transfer_complete);
complete(&dd->tx_transfer_complete);
- dd->done = 0;
}
return ret;
}
@@ -968,17 +987,23 @@ static irqreturn_t msm_spi_input_irq(int irq, void *dev_id)
dd->stat_rx++;
- if (dd->mode == SPI_MODE_NONE)
+ if (dd->rx_mode == SPI_MODE_NONE)
return IRQ_HANDLED;
- if (dd->mode == SPI_FIFO_MODE) {
+ if (dd->rx_mode == SPI_FIFO_MODE) {
while ((readl_relaxed(dd->base + SPI_OPERATIONAL) &
SPI_OP_IP_FIFO_NOT_EMPTY) &&
(dd->rx_bytes_remaining > 0)) {
msm_spi_read_word_from_fifo(dd);
}
- if (dd->rx_bytes_remaining == 0)
- msm_spi_complete(dd);
+ } else if (dd->rx_mode == SPI_BLOCK_MODE) {
+ int count = 0;
+
+ while (dd->rx_bytes_remaining &&
+ (count < dd->input_block_size)) {
+ msm_spi_read_word_from_fifo(dd);
+ count += SPI_MAX_BYTES_PER_WORD;
+ }
}
return IRQ_HANDLED;
@@ -989,18 +1014,20 @@ static void msm_spi_write_word_to_fifo(struct msm_spi *dd)
u32 word;
u8 byte;
int i;
+ int write_bytes =
+ (dd->pack_words ? SPI_MAX_BYTES_PER_WORD : dd->bytes_per_word);
word = 0;
if (dd->write_buf) {
- for (i = 0; (i < dd->bytes_per_word) &&
+ for (i = 0; (i < write_bytes) &&
dd->tx_bytes_remaining; i++) {
dd->tx_bytes_remaining--;
byte = *dd->write_buf++;
word |= (byte << (BITS_PER_BYTE * i));
}
} else
- if (dd->tx_bytes_remaining > dd->bytes_per_word)
- dd->tx_bytes_remaining -= dd->bytes_per_word;
+ if (dd->tx_bytes_remaining > write_bytes)
+ dd->tx_bytes_remaining -= write_bytes;
else
dd->tx_bytes_remaining = 0;
dd->write_xfr_cnt++;
@@ -1012,11 +1039,22 @@ static inline void msm_spi_write_rmn_to_fifo(struct msm_spi *dd)
{
int count = 0;
- while ((dd->tx_bytes_remaining > 0) && (count < dd->input_fifo_size) &&
- !(readl_relaxed(dd->base + SPI_OPERATIONAL) &
- SPI_OP_OUTPUT_FIFO_FULL)) {
- msm_spi_write_word_to_fifo(dd);
- count++;
+ if (dd->tx_mode == SPI_FIFO_MODE) {
+ while ((dd->tx_bytes_remaining > 0) &&
+ (count < dd->input_fifo_size) &&
+ !(readl_relaxed(dd->base + SPI_OPERATIONAL)
+ & SPI_OP_OUTPUT_FIFO_FULL)) {
+ msm_spi_write_word_to_fifo(dd);
+ count++;
+ }
+ }
+
+ if (dd->tx_mode == SPI_BLOCK_MODE) {
+ while (dd->tx_bytes_remaining &&
+ (count < dd->output_block_size)) {
+ msm_spi_write_word_to_fifo(dd);
+ count += SPI_MAX_BYTES_PER_WORD;
+ }
}
}
@@ -1026,11 +1064,11 @@ static irqreturn_t msm_spi_output_irq(int irq, void *dev_id)
dd->stat_tx++;
- if (dd->mode == SPI_MODE_NONE)
+ if (dd->tx_mode == SPI_MODE_NONE)
return IRQ_HANDLED;
/* Output FIFO is empty. Transmit any outstanding write data. */
- if (dd->mode == SPI_FIFO_MODE)
+ if ((dd->tx_mode == SPI_FIFO_MODE) || (dd->tx_mode == SPI_BLOCK_MODE))
msm_spi_write_rmn_to_fifo(dd);
return IRQ_HANDLED;
@@ -1106,7 +1144,7 @@ error:
static int msm_spi_dma_map_buffers(struct msm_spi *dd)
{
int ret = 0;
- if (dd->mode == SPI_BAM_MODE)
+ if (dd->tx_mode == SPI_BAM_MODE)
ret = msm_spi_bam_map_buffers(dd);
return ret;
}
@@ -1135,7 +1173,7 @@ static void msm_spi_bam_unmap_buffers(struct msm_spi *dd)
static inline void msm_spi_dma_unmap_buffers(struct msm_spi *dd)
{
- if (dd->mode == SPI_BAM_MODE)
+ if (dd->tx_mode == SPI_BAM_MODE)
msm_spi_bam_unmap_buffers(dd);
}
@@ -1197,9 +1235,11 @@ static void
msm_spi_set_transfer_mode(struct msm_spi *dd, u8 bpw, u32 read_count)
{
if (msm_spi_use_dma(dd, dd->cur_transfer, bpw)) {
- dd->mode = SPI_BAM_MODE;
+ dd->tx_mode = SPI_BAM_MODE;
+ dd->rx_mode = SPI_BAM_MODE;
} else {
- dd->mode = SPI_FIFO_MODE;
+ dd->rx_mode = SPI_FIFO_MODE;
+ dd->tx_mode = SPI_FIFO_MODE;
dd->read_len = dd->cur_transfer->len;
dd->write_len = dd->cur_transfer->len;
}
@@ -1215,14 +1255,23 @@ static void msm_spi_set_qup_io_modes(struct msm_spi *dd)
spi_iom = readl_relaxed(dd->base + SPI_IO_MODES);
/* Set input and output transfer mode: FIFO, DMOV, or BAM */
spi_iom &= ~(SPI_IO_M_INPUT_MODE | SPI_IO_M_OUTPUT_MODE);
- spi_iom = (spi_iom | (dd->mode << OUTPUT_MODE_SHIFT));
- spi_iom = (spi_iom | (dd->mode << INPUT_MODE_SHIFT));
- /* Turn on packing for data mover */
- if (dd->mode == SPI_BAM_MODE)
+ spi_iom = (spi_iom | (dd->tx_mode << OUTPUT_MODE_SHIFT));
+ spi_iom = (spi_iom | (dd->rx_mode << INPUT_MODE_SHIFT));
+
+ /* Always enable packing for the BAM mode and for non BAM mode only
+ * if bpw is % 8 and transfer length is % 4 Bytes.
+ */
+ if (dd->tx_mode == SPI_BAM_MODE ||
+ ((dd->cur_msg_len % SPI_MAX_BYTES_PER_WORD == 0) &&
+ (dd->cur_transfer->bits_per_word) &&
+ (dd->cur_transfer->bits_per_word <= 32) &&
+ (dd->cur_transfer->bits_per_word % 8 == 0))) {
spi_iom |= SPI_IO_M_PACK_EN | SPI_IO_M_UNPACK_EN;
- else {
+ dd->pack_words = true;
+ } else {
spi_iom &= ~(SPI_IO_M_PACK_EN | SPI_IO_M_UNPACK_EN);
spi_iom |= SPI_IO_M_OUTPUT_BIT_SHIFT_EN;
+ dd->pack_words = false;
}
/*if (dd->mode == SPI_BAM_MODE) {
@@ -1280,7 +1329,7 @@ static void msm_spi_set_qup_op_mask(struct msm_spi *dd)
{
/* mask INPUT and OUTPUT service flags in to prevent IRQs on FIFO status
* change in BAM mode */
- u32 mask = (dd->mode == SPI_BAM_MODE) ?
+ u32 mask = (dd->tx_mode == SPI_BAM_MODE) ?
QUP_OP_MASK_OUTPUT_SERVICE_FLAG | QUP_OP_MASK_INPUT_SERVICE_FLAG
: 0;
writel_relaxed(mask, dd->base + QUP_OPERATIONAL_MASK);
@@ -1321,6 +1370,8 @@ static int msm_spi_process_transfer(struct msm_spi *dd)
dd->rx_bytes_remaining = dd->cur_msg_len;
dd->read_buf = dd->cur_transfer->rx_buf;
dd->write_buf = dd->cur_transfer->tx_buf;
+ dd->tx_done = false;
+ dd->rx_done = false;
init_completion(&dd->tx_transfer_complete);
init_completion(&dd->rx_transfer_complete);
if (dd->cur_transfer->bits_per_word)
@@ -1351,10 +1402,12 @@ static int msm_spi_process_transfer(struct msm_spi *dd)
msm_spi_set_transfer_mode(dd, bpw, read_count);
msm_spi_set_mx_counts(dd, read_count);
- if (dd->mode == SPI_BAM_MODE) {
+ if (dd->tx_mode == SPI_BAM_MODE) {
ret = msm_spi_dma_map_buffers(dd);
if (ret < 0) {
pr_err("Mapping DMA buffers\n");
+ dd->tx_mode = SPI_MODE_NONE;
+ dd->rx_mode = SPI_MODE_NONE;
return ret;
}
}
@@ -1368,11 +1421,11 @@ static int msm_spi_process_transfer(struct msm_spi *dd)
the first. Restricting this to one write avoids contention
issues and race conditions between this thread and the int handler
*/
- if (dd->mode == SPI_FIFO_MODE) {
+ if (dd->tx_mode != SPI_BAM_MODE) {
if (msm_spi_prepare_for_write(dd))
goto transfer_end;
msm_spi_start_write(dd, read_count);
- } else if (dd->mode == SPI_BAM_MODE) {
+ } else {
if ((msm_spi_bam_begin_transfer(dd)) < 0) {
dev_err(dd->dev, "%s: BAM transfer setup failed\n",
__func__);
@@ -1388,11 +1441,11 @@ static int msm_spi_process_transfer(struct msm_spi *dd)
* might fire before the first word is written resulting in a
* possible race condition.
*/
- if (dd->mode != SPI_BAM_MODE)
+ if (dd->tx_mode != SPI_BAM_MODE)
if (msm_spi_set_state(dd, SPI_OP_STATE_RUN)) {
dev_warn(dd->dev,
"%s: Failed to set QUP to run-state. Mode:%d",
- __func__, dd->mode);
+ __func__, dd->tx_mode);
goto transfer_end;
}
@@ -1422,10 +1475,11 @@ static int msm_spi_process_transfer(struct msm_spi *dd)
msm_spi_udelay(dd->xfrs_delay_usec);
transfer_end:
- if ((dd->mode == SPI_BAM_MODE) && status)
+ if ((dd->tx_mode == SPI_BAM_MODE) && status)
msm_spi_bam_flush(dd);
msm_spi_dma_unmap_buffers(dd);
- dd->mode = SPI_MODE_NONE;
+ dd->tx_mode = SPI_MODE_NONE;
+ dd->rx_mode = SPI_MODE_NONE;
msm_spi_set_state(dd, SPI_OP_STATE_RESET);
if (!dd->cur_transfer->cs_change)
@@ -2349,7 +2403,8 @@ static int init_resources(struct platform_device *pdev)
pclk_enabled = 0;
dd->transfer_pending = 0;
- dd->mode = SPI_MODE_NONE;
+ dd->tx_mode = SPI_MODE_NONE;
+ dd->rx_mode = SPI_MODE_NONE;
rc = msm_spi_request_irq(dd, pdev, master);
if (rc)
diff --git a/drivers/spi/spi_qsd.h b/drivers/spi/spi_qsd.h
index 7a5cfadaa5a0..47d69965f18a 100644
--- a/drivers/spi/spi_qsd.h
+++ b/drivers/spi/spi_qsd.h
@@ -113,6 +113,8 @@
#define INPUT_MODE_SHIFT QSD_REG(10) QUP_REG(12)
/* SPI_OPERATIONAL fields */
+#define SPI_OP_IN_BLK_RD_REQ_FLAG 0x00002000
+#define SPI_OP_OUT_BLK_WR_REQ_FLAG 0x00001000
#define SPI_OP_MAX_INPUT_DONE_FLAG 0x00000800
#define SPI_OP_MAX_OUTPUT_DONE_FLAG 0x00000400
#define SPI_OP_INPUT_SERVICE_FLAG 0x00000200
@@ -321,7 +323,8 @@ struct msm_spi {
bool transfer_pending;
wait_queue_head_t continue_suspend;
/* DMA data */
- enum msm_spi_mode mode;
+ enum msm_spi_mode tx_mode;
+ enum msm_spi_mode rx_mode;
bool use_dma;
int tx_dma_chan;
int tx_dma_crci;
@@ -353,7 +356,8 @@ struct msm_spi {
#endif
struct msm_spi_platform_data *pdata; /* Platform data */
/* When set indicates multiple transfers in a single message */
- bool done;
+ bool rx_done;
+ bool tx_done;
u32 cur_msg_len;
/* Used in FIFO mode to keep track of the transfer being processed */
struct spi_transfer *cur_tx_transfer;
@@ -371,6 +375,7 @@ struct msm_spi {
struct pinctrl_state *pins_active;
struct pinctrl_state *pins_sleep;
bool is_init_complete;
+ bool pack_words;
};
/* Forward declaration */
@@ -524,7 +529,8 @@ static inline void msm_spi_set_write_count(struct msm_spi *dd, int val)
static inline void msm_spi_complete(struct msm_spi *dd)
{
- dd->done = 1;
+ dd->tx_done = true;
+ dd->rx_done = true;
}
static inline void msm_spi_enable_error_flags(struct msm_spi *dd)
diff --git a/drivers/spmi/spmi-pmic-arb.c b/drivers/spmi/spmi-pmic-arb.c
index a5bfeab596ac..d1802bcba0fb 100644
--- a/drivers/spmi/spmi-pmic-arb.c
+++ b/drivers/spmi/spmi-pmic-arb.c
@@ -166,6 +166,7 @@ struct spmi_pmic_arb {
u16 max_apid;
u16 max_periph;
u32 *mapping_table;
+ int reserved_chan;
DECLARE_BITMAP(mapping_table_valid, PMIC_ARB_MAX_PERIPHS);
struct irq_domain *domain;
struct spmi_controller *spmic;
@@ -861,6 +862,10 @@ static u16 pmic_arb_find_apid(struct spmi_pmic_arb *pa, u16 ppid)
* ppid_to_apid is an in-memory invert of that table.
*/
for (apid = pa->last_apid; apid < pa->max_periph; apid++) {
+ /* Do not keep the reserved channel in the mapping table */
+ if (pa->reserved_chan >= 0 && apid == pa->reserved_chan)
+ continue;
+
regval = readl_relaxed(pa->cnfg +
SPMI_OWNERSHIP_TABLE_REG(apid));
pa->apid_data[apid].irq_owner
@@ -920,6 +925,10 @@ static int pmic_arb_read_apid_map_v5(struct spmi_pmic_arb *pa)
* receive interrupts from the PPID.
*/
for (apid = 0; apid < pa->max_periph; apid++) {
+ /* Do not keep the reserved channel in the mapping table */
+ if (pa->reserved_chan >= 0 && apid == pa->reserved_chan)
+ continue;
+
offset = pa->ver_ops->channel_map_offset(apid);
if (offset >= pa->core_size)
break;
@@ -1340,6 +1349,10 @@ static int spmi_pmic_arb_probe(struct platform_device *pdev)
pa->ee = ee;
+ pa->reserved_chan = -EINVAL;
+ of_property_read_u32(pdev->dev.of_node, "qcom,reserved-chan",
+ &pa->reserved_chan);
+
pa->mapping_table = devm_kcalloc(&ctrl->dev, PMIC_ARB_MAX_PERIPHS - 1,
sizeof(*pa->mapping_table), GFP_KERNEL);
if (!pa->mapping_table) {
diff --git a/drivers/staging/android/ion/ion_cma_heap.c b/drivers/staging/android/ion/ion_cma_heap.c
index b5905fc81147..dfb6d2f77af1 100644
--- a/drivers/staging/android/ion/ion_cma_heap.c
+++ b/drivers/staging/android/ion/ion_cma_heap.c
@@ -238,7 +238,7 @@ void ion_cma_heap_destroy(struct ion_heap *heap)
static void ion_secure_cma_free(struct ion_buffer *buffer)
{
int ret = 0;
- u32 source_vm;
+ int source_vm;
int dest_vmid;
int dest_perms;
struct ion_cma_buffer_info *info = buffer->priv_virt;
diff --git a/drivers/staging/android/ion/ion_system_secure_heap.c b/drivers/staging/android/ion/ion_system_secure_heap.c
index ec09f9f12b47..803811597f37 100644
--- a/drivers/staging/android/ion/ion_system_secure_heap.c
+++ b/drivers/staging/android/ion/ion_system_secure_heap.c
@@ -1,6 +1,6 @@
/*
*
- * 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
@@ -78,7 +78,7 @@ int ion_system_secure_heap_unassign_sg(struct sg_table *sgt, int source_vmid)
int ion_system_secure_heap_assign_sg(struct sg_table *sgt, int dest_vmid)
{
- u32 source_vmid = VMID_HLOS;
+ int source_vmid = VMID_HLOS;
u32 dest_perms = PERM_READ | PERM_WRITE;
struct scatterlist *sg;
int ret, i;
diff --git a/drivers/staging/android/lowmemorykiller.c b/drivers/staging/android/lowmemorykiller.c
index bec687853c5d..205af6627b80 100644
--- a/drivers/staging/android/lowmemorykiller.c
+++ b/drivers/staging/android/lowmemorykiller.c
@@ -217,6 +217,22 @@ static int test_task_flag(struct task_struct *p, int flag)
return 0;
}
+static int test_task_state(struct task_struct *p, int state)
+{
+ struct task_struct *t;
+
+ for_each_thread(p, t) {
+ task_lock(t);
+ if (t->state & state) {
+ task_unlock(t);
+ return 1;
+ }
+ task_unlock(t);
+ }
+
+ return 0;
+}
+
static DEFINE_MUTEX(scan_mutex);
int can_use_cma_pages(gfp_t gfp_mask)
@@ -404,7 +420,7 @@ static unsigned long lowmem_scan(struct shrinker *s, struct shrink_control *sc)
int other_free;
int other_file;
- if (mutex_lock_interruptible(&scan_mutex) < 0)
+ if (!mutex_trylock(&scan_mutex))
return 0;
other_free = global_page_state(NR_FREE_PAGES);
@@ -462,8 +478,6 @@ static unsigned long lowmem_scan(struct shrinker *s, struct shrink_control *sc)
if (time_before_eq(jiffies, lowmem_deathpending_timeout)) {
if (test_task_flag(tsk, TIF_MEMDIE)) {
rcu_read_unlock();
- /* give the system time to free up the memory */
- msleep_interruptible(20);
mutex_unlock(&scan_mutex);
return 0;
}
@@ -497,6 +511,17 @@ static unsigned long lowmem_scan(struct shrinker *s, struct shrink_control *sc)
}
if (selected) {
long cache_size, cache_limit, free;
+
+ if (test_task_flag(selected, TIF_MEMDIE) &&
+ (test_task_state(selected, TASK_UNINTERRUPTIBLE))) {
+ lowmem_print(2, "'%s' (%d) is already killed\n",
+ selected->comm,
+ selected->pid);
+ rcu_read_unlock();
+ mutex_unlock(&scan_mutex);
+ return 0;
+ }
+
task_lock(selected);
send_sig(SIGKILL, selected, 0);
/*
@@ -565,7 +590,8 @@ static unsigned long lowmem_scan(struct shrinker *s, struct shrink_control *sc)
static struct shrinker lowmem_shrinker = {
.scan_objects = lowmem_scan,
.count_objects = lowmem_count,
- .seeks = DEFAULT_SEEKS * 16
+ .seeks = DEFAULT_SEEKS * 16,
+ .flags = SHRINKER_LMK
};
static int __init lowmem_init(void)
diff --git a/drivers/usb/gadget/configfs.c b/drivers/usb/gadget/configfs.c
index c31aaf7a9880..e5d3a0bdf32a 100644
--- a/drivers/usb/gadget/configfs.c
+++ b/drivers/usb/gadget/configfs.c
@@ -160,7 +160,7 @@ static int usb_string_copy(const char *s, char **s_copy)
if (!str)
return -ENOMEM;
}
- strncpy(str, s, MAX_USB_STRING_WITH_NULL_LEN);
+ strlcpy(str, s, MAX_USB_STRING_WITH_NULL_LEN);
if (str[ret - 1] == '\n')
str[ret - 1] = '\0';
*s_copy = str;
diff --git a/drivers/usb/gadget/function/f_ccid.h b/drivers/usb/gadget/function/f_ccid.h
index 42a7ebbbccfc..935308cff0bc 100644
--- a/drivers/usb/gadget/function/f_ccid.h
+++ b/drivers/usb/gadget/function/f_ccid.h
@@ -55,29 +55,29 @@
#define CCID_READ_DTR _IOR('C', 3, int)
struct usb_ccid_notification {
- unsigned char buf[4];
+ __u8 buf[4];
} __packed;
struct ccid_bulk_in_header {
- unsigned char bMessageType;
- unsigned long wLength;
- unsigned char bSlot;
- unsigned char bSeq;
- unsigned char bStatus;
- unsigned char bError;
- unsigned char bSpecific;
- unsigned char abData[ABDATA_SIZE];
- unsigned char bSizeToSend;
+ __u8 bMessageType;
+ __u32 wLength;
+ __u8 bSlot;
+ __u8 bSeq;
+ __u8 bStatus;
+ __u8 bError;
+ __u8 bSpecific;
+ __u8 abData[ABDATA_SIZE];
+ __u8 bSizeToSend;
} __packed;
struct ccid_bulk_out_header {
- unsigned char bMessageType;
- unsigned long wLength;
- unsigned char bSlot;
- unsigned char bSeq;
- unsigned char bSpecific_0;
- unsigned char bSpecific_1;
- unsigned char bSpecific_2;
- unsigned char APDU[ABDATA_SIZE];
+ __u8 bMessageType;
+ __u32 wLength;
+ __u8 bSlot;
+ __u8 bSeq;
+ __u8 bSpecific_0;
+ __u8 bSpecific_1;
+ __u8 bSpecific_2;
+ __u8 APDU[ABDATA_SIZE];
} __packed;
#endif
diff --git a/drivers/usb/gadget/function/f_fs.c b/drivers/usb/gadget/function/f_fs.c
index a1c00525a598..7c35241a487a 100644
--- a/drivers/usb/gadget/function/f_fs.c
+++ b/drivers/usb/gadget/function/f_fs.c
@@ -71,6 +71,7 @@ __ffs_data_got_strings(struct ffs_data *ffs, char *data, size_t len);
/* The function structure ***************************************************/
struct ffs_ep;
+static bool first_read_done;
struct ffs_function {
struct usb_configuration *conf;
@@ -756,6 +757,7 @@ static ssize_t ffs_epfile_io(struct file *file, struct ffs_io_data *io_data)
{
struct ffs_epfile *epfile = file->private_data;
struct ffs_ep *ep;
+ struct ffs_data *ffs = epfile->ffs;
char *data = NULL;
ssize_t ret, data_len = -EINVAL;
int halt;
@@ -764,6 +766,7 @@ static ssize_t ffs_epfile_io(struct file *file, struct ffs_io_data *io_data)
atomic_read(&epfile->error), io_data->read ? "READ" : "WRITE");
smp_mb__before_atomic();
+retry:
if (atomic_read(&epfile->error))
return -ENODEV;
@@ -968,10 +971,36 @@ static ssize_t ffs_epfile_io(struct file *file, struct ffs_io_data *io_data)
* disabled (disconnect) or changed
* (composition switch) ?
*/
- if (epfile->ep == ep)
+ if (epfile->ep == ep) {
ret = ep->status;
- else
+ if (ret >= 0)
+ first_read_done = true;
+ } else {
ret = -ENODEV;
+ }
+
+ /* do wait again if func eps are not enabled */
+ if (io_data->read && !first_read_done
+ && ret < 0) {
+ unsigned short count = ffs->eps_count;
+
+ pr_debug("%s: waiting for the online state\n",
+ __func__);
+ ret = 0;
+ kfree(data);
+ data = NULL;
+ data_len = -EINVAL;
+ spin_unlock_irq(&epfile->ffs->eps_lock);
+ mutex_unlock(&epfile->mutex);
+ epfile = ffs->epfiles;
+ do {
+ atomic_set(&epfile->error, 0);
+ ++epfile;
+ } while (--count);
+ epfile = file->private_data;
+ goto retry;
+ }
+
spin_unlock_irq(&epfile->ffs->eps_lock);
if (io_data->read && ret > 0) {
@@ -1038,6 +1067,7 @@ ffs_epfile_open(struct inode *inode, struct file *file)
smp_mb__before_atomic();
atomic_set(&epfile->error, 0);
+ first_read_done = false;
ffs_log("exit:state %d setup_state %d flag %lu", epfile->ffs->state,
epfile->ffs->setup_state, epfile->ffs->flags);
@@ -1159,7 +1189,7 @@ static ssize_t ffs_epfile_read_iter(struct kiocb *kiocb, struct iov_iter *to)
*to = p->data;
}
- ffs_log("enter");
+ ffs_log("exit");
return res;
}
@@ -3354,6 +3384,8 @@ static int ffs_func_set_alt(struct usb_function *f,
if (ffs->func) {
ffs_func_eps_disable(ffs->func);
ffs->func = NULL;
+ /* matching put to allow LPM on disconnect */
+ usb_gadget_autopm_put_async(ffs->gadget);
}
if (ffs->state == FFS_DEACTIVATED) {
@@ -3387,14 +3419,9 @@ static int ffs_func_set_alt(struct usb_function *f,
static void ffs_func_disable(struct usb_function *f)
{
- struct ffs_function *func = ffs_func_from_usb(f);
- struct ffs_data *ffs = func->ffs;
-
ffs_log("enter");
ffs_func_set_alt(f, 0, (unsigned)-1);
- /* matching put to allow LPM on disconnect */
- usb_gadget_autopm_put_async(ffs->gadget);
ffs_log("exit");
}
diff --git a/drivers/usb/gadget/function/f_mass_storage.c b/drivers/usb/gadget/function/f_mass_storage.c
index 1fd5a95b6e99..59d6ac67d072 100644
--- a/drivers/usb/gadget/function/f_mass_storage.c
+++ b/drivers/usb/gadget/function/f_mass_storage.c
@@ -2284,16 +2284,15 @@ reset:
fsg->bulk_out_enabled = 0;
}
+ /* allow usb LPM after eps are disabled */
+ usb_gadget_autopm_put_async(common->gadget);
common->fsg = NULL;
wake_up(&common->fsg_wait);
}
common->running = 0;
- if (!new_fsg || rc) {
- /* allow usb LPM after eps are disabled */
- usb_gadget_autopm_put_async(common->gadget);
+ if (!new_fsg || rc)
return rc;
- }
common->fsg = new_fsg;
fsg = common->fsg;
diff --git a/drivers/usb/phy/phy-msm-ssusb-qmp.c b/drivers/usb/phy/phy-msm-ssusb-qmp.c
index aa11cf2f7417..6ba742076baa 100644
--- a/drivers/usb/phy/phy-msm-ssusb-qmp.c
+++ b/drivers/usb/phy/phy-msm-ssusb-qmp.c
@@ -222,11 +222,6 @@ static int msm_ssusb_qmp_ldo_enable(struct msm_ssphy_qmp *phy, int on)
"enable phy->fpc_redrive_ldo failed\n");
return rc;
}
-
- dev_dbg(phy->phy.dev,
- "fpc redrive ldo: min_vol:%duV max_vol:%duV\n",
- phy->redrive_voltage_levels[VOLTAGE_LEVEL_MIN],
- phy->redrive_voltage_levels[VOLTAGE_LEVEL_MAX]);
}
rc = msm_ldo_enable(phy, phy->vdd, phy->vdd_levels,
@@ -236,11 +231,6 @@ static int msm_ssusb_qmp_ldo_enable(struct msm_ssphy_qmp *phy, int on)
goto disable_fpc_redrive;
}
- dev_dbg(phy->phy.dev,
- "vdd ldo: min_vol:%duV max_vol:%duV\n",
- phy->vdd_levels[VOLTAGE_LEVEL_MIN],
- phy->vdd_levels[VOLTAGE_LEVEL_MAX]);
-
rc = msm_ldo_enable(phy, phy->core_ldo, phy->core_voltage_levels,
USB_SSPHY_HPM_LOAD);
if (rc < 0) {
@@ -248,11 +238,6 @@ static int msm_ssusb_qmp_ldo_enable(struct msm_ssphy_qmp *phy, int on)
goto disable_vdd;
}
- dev_dbg(phy->phy.dev,
- "core ldo: min_vol:%duV max_vol:%duV\n",
- phy->core_voltage_levels[VOLTAGE_LEVEL_MIN],
- phy->core_voltage_levels[VOLTAGE_LEVEL_MAX]);
-
return 0;
disable_regulators:
diff --git a/drivers/video/fbdev/msm/mdss_dp.c b/drivers/video/fbdev/msm/mdss_dp.c
index f57a3abf7eca..1e878e9a00cb 100644
--- a/drivers/video/fbdev/msm/mdss_dp.c
+++ b/drivers/video/fbdev/msm/mdss_dp.c
@@ -3048,7 +3048,7 @@ static int mdss_dp_event_handler(struct mdss_panel_data *pdata,
mdss_dp_update_hdcp_info(dp);
if (dp_is_hdcp_enabled(dp)) {
- cancel_delayed_work(&dp->hdcp_cb_work);
+ cancel_delayed_work_sync(&dp->hdcp_cb_work);
dp->hdcp_status = HDCP_STATE_AUTHENTICATING;
queue_delayed_work(dp->workq,
@@ -3068,7 +3068,7 @@ static int mdss_dp_event_handler(struct mdss_panel_data *pdata,
if (dp_is_hdcp_enabled(dp)) {
dp->hdcp_status = HDCP_STATE_INACTIVE;
- cancel_delayed_work(&dp->hdcp_cb_work);
+ cancel_delayed_work_sync(&dp->hdcp_cb_work);
if (dp->hdcp.ops->off)
dp->hdcp.ops->off(dp->hdcp.data);
}
@@ -3768,7 +3768,7 @@ static int mdss_dp_process_audio_pattern_request(struct mdss_dp_drv_pdata *dp)
return -EINVAL;
if (dp_is_hdcp_enabled(dp) && dp->hdcp.ops->off) {
- cancel_delayed_work(&dp->hdcp_cb_work);
+ cancel_delayed_work_sync(&dp->hdcp_cb_work);
dp->hdcp.ops->off(dp->hdcp.data);
}
@@ -4076,7 +4076,7 @@ static void mdss_dp_process_attention(struct mdss_dp_drv_pdata *dp_drv)
}
if (dp_is_hdcp_enabled(dp_drv) && dp_drv->hdcp.ops->off) {
- cancel_delayed_work(&dp_drv->hdcp_cb_work);
+ cancel_delayed_work_sync(&dp_drv->hdcp_cb_work);
dp_drv->hdcp.ops->off(dp_drv->hdcp.data);
}
diff --git a/drivers/video/fbdev/msm/mdss_dsi.c b/drivers/video/fbdev/msm/mdss_dsi.c
index 17722eac3006..b1552829508d 100644
--- a/drivers/video/fbdev/msm/mdss_dsi.c
+++ b/drivers/video/fbdev/msm/mdss_dsi.c
@@ -2713,10 +2713,7 @@ static int mdss_dsi_event_handler(struct mdss_panel_data *pdata,
rc = mdss_dsi_reconfig(pdata, mode);
break;
case MDSS_EVENT_DSI_PANEL_STATUS:
- if (ctrl_pdata->check_status)
- rc = ctrl_pdata->check_status(ctrl_pdata);
- else
- rc = true;
+ rc = mdss_dsi_check_panel_status(ctrl_pdata, arg);
break;
case MDSS_EVENT_PANEL_TIMING_SWITCH:
rc = mdss_dsi_panel_timing_switch(ctrl_pdata, arg);
diff --git a/drivers/video/fbdev/msm/mdss_dsi.h b/drivers/video/fbdev/msm/mdss_dsi.h
index 2a76466abf3e..00f23380591b 100644
--- a/drivers/video/fbdev/msm/mdss_dsi.h
+++ b/drivers/video/fbdev/msm/mdss_dsi.h
@@ -704,6 +704,7 @@ void mdss_dsi_cfg_lane_ctrl(struct mdss_dsi_ctrl_pdata *ctrl,
void mdss_dsi_set_reg(struct mdss_dsi_ctrl_pdata *ctrl, int off,
u32 mask, u32 val);
int mdss_dsi_phy_pll_reset_status(struct mdss_dsi_ctrl_pdata *ctrl);
+int mdss_dsi_check_panel_status(struct mdss_dsi_ctrl_pdata *ctrl, void *arg);
static inline const char *__mdss_dsi_pm_name(enum dsi_pm_type module)
{
diff --git a/drivers/video/fbdev/msm/mdss_dsi_host.c b/drivers/video/fbdev/msm/mdss_dsi_host.c
index 9f4b7eb52492..3b48bb642792 100644
--- a/drivers/video/fbdev/msm/mdss_dsi_host.c
+++ b/drivers/video/fbdev/msm/mdss_dsi_host.c
@@ -778,6 +778,12 @@ static void mdss_dsi_ctl_phy_reset(struct mdss_dsi_ctrl_pdata *ctrl, u32 event)
u32 loop = 10, u_dly = 200;
pr_debug("%s: MDSS DSI CTRL and PHY reset. ctrl-num = %d\n",
__func__, ctrl->ndx);
+
+ if (ctrl->panel_mode == DSI_CMD_MODE) {
+ pr_warn("ctl_phy_reset not applicable for cmd mode\n");
+ return;
+ }
+
if (event == DSI_EV_DLNx_FIFO_OVERFLOW) {
mask = BIT(20); /* clock lane only for overflow recovery */
} else if (event == DSI_EV_LP_RX_TIMEOUT) {
@@ -792,15 +798,6 @@ static void mdss_dsi_ctl_phy_reset(struct mdss_dsi_ctrl_pdata *ctrl, u32 event)
ctrl0 = mdss_dsi_get_ctrl_by_index(DSI_CTRL_0);
ctrl1 = mdss_dsi_get_ctrl_by_index(DSI_CTRL_1);
- if (ctrl0->recovery) {
- rc = ctrl0->recovery->fxn(ctrl0->recovery->data,
- MDP_INTF_DSI_VIDEO_FIFO_OVERFLOW);
- if (rc < 0) {
- pr_debug("%s: Target is in suspend/shutdown\n",
- __func__);
- return;
- }
- }
/*
* Disable PHY contention detection and receive.
* Configure the strength ctrl 1 register.
@@ -874,6 +871,15 @@ static void mdss_dsi_ctl_phy_reset(struct mdss_dsi_ctrl_pdata *ctrl, u32 event)
MIPI_OUTP(ctrl0->ctrl_base + 0x0ac, ln_ctrl0 & ~mask);
MIPI_OUTP(ctrl1->ctrl_base + 0x0ac, ln_ctrl1 & ~mask);
+ if (ctrl0->recovery) {
+ rc = ctrl0->recovery->fxn(ctrl0->recovery->data,
+ MDP_INTF_DSI_VIDEO_FIFO_OVERFLOW);
+ if (rc < 0) {
+ pr_debug("%s: Target is in suspend/shutdown\n",
+ __func__);
+ return;
+ }
+ }
/* Enable Video mode for DSI controller */
MIPI_OUTP(ctrl0->ctrl_base + 0x004, data0);
MIPI_OUTP(ctrl1->ctrl_base + 0x004, data1);
@@ -890,15 +896,6 @@ static void mdss_dsi_ctl_phy_reset(struct mdss_dsi_ctrl_pdata *ctrl, u32 event)
*/
udelay(200);
} else {
- if (ctrl->recovery) {
- rc = ctrl->recovery->fxn(ctrl->recovery->data,
- MDP_INTF_DSI_VIDEO_FIFO_OVERFLOW);
- if (rc < 0) {
- pr_debug("%s: Target is in suspend/shutdown\n",
- __func__);
- return;
- }
- }
/* Disable PHY contention detection and receive */
MIPI_OUTP((ctrl->phy_io.base) + 0x0188, 0);
@@ -951,6 +948,15 @@ static void mdss_dsi_ctl_phy_reset(struct mdss_dsi_ctrl_pdata *ctrl, u32 event)
__func__, ln0);
MIPI_OUTP(ctrl->ctrl_base + 0x0ac, ln_ctrl0 & ~mask);
+ if (ctrl->recovery) {
+ rc = ctrl->recovery->fxn(ctrl->recovery->data,
+ MDP_INTF_DSI_VIDEO_FIFO_OVERFLOW);
+ if (rc < 0) {
+ pr_debug("%s: Target is in suspend/shutdown\n",
+ __func__);
+ return;
+ }
+ }
/* Enable Video mode for DSI controller */
MIPI_OUTP(ctrl->ctrl_base + 0x004, data0);
/* Enable PHY contention detection and receiver */
@@ -1311,6 +1317,31 @@ void mdss_dsi_set_burst_mode(struct mdss_dsi_ctrl_pdata *ctrl)
}
+static void mdss_dsi_split_link_setup(struct mdss_dsi_ctrl_pdata *ctrl_pdata)
+{
+ u32 data = 0;
+ struct mdss_panel_info *pinfo;
+
+ if (!ctrl_pdata)
+ return;
+
+ pinfo = &ctrl_pdata->panel_data.panel_info;
+ if (!pinfo->split_link_enabled)
+ return;
+
+ pr_debug("%s: enable split link\n", __func__);
+
+ data = MIPI_INP((ctrl_pdata->ctrl_base) + 0x330);
+ /* DMA_LINK_SEL */
+ data |= 0x3 << 12;
+ /* MDP0_LINK_SEL */
+ data |= 0x5 << 20;
+ /* EN */
+ data |= 0x1;
+ /* DSI_SPLIT_LINK_CTRL */
+ MIPI_OUTP((ctrl_pdata->ctrl_base) + 0x330, data);
+}
+
static void mdss_dsi_mode_setup(struct mdss_panel_data *pdata)
{
struct mdss_dsi_ctrl_pdata *ctrl_pdata = NULL;
@@ -1429,6 +1460,8 @@ static void mdss_dsi_mode_setup(struct mdss_panel_data *pdata)
}
mdss_dsi_dsc_config(ctrl_pdata, dsc);
+
+ mdss_dsi_split_link_setup(ctrl_pdata);
}
void mdss_dsi_ctrl_setup(struct mdss_dsi_ctrl_pdata *ctrl)
@@ -2998,7 +3031,10 @@ bool mdss_dsi_ack_err_status(struct mdss_dsi_ctrl_pdata *ctrl)
* warning message is ignored.
*/
if (ctrl->panel_data.panel_info.esd_check_enabled &&
- (ctrl->status_mode == ESD_BTA) && (status & 0x1008000))
+ ((ctrl->status_mode == ESD_BTA) ||
+ (ctrl->status_mode == ESD_REG) ||
+ (ctrl->status_mode == ESD_REG_NT35596)) &&
+ (status & 0x1008000))
return false;
pr_err("%s: status=%x\n", __func__, status);
@@ -3229,8 +3265,10 @@ irqreturn_t mdss_dsi_isr(int irq, void *ptr)
* cleared.
*/
if (ctrl->panel_data.panel_info.esd_check_enabled &&
- (ctrl->status_mode == ESD_BTA) &&
- (ctrl->panel_mode == DSI_VIDEO_MODE)) {
+ ((ctrl->status_mode == ESD_BTA) ||
+ (ctrl->status_mode == ESD_REG) ||
+ (ctrl->status_mode == ESD_REG_NT35596)) &&
+ (ctrl->panel_mode == DSI_VIDEO_MODE)) {
isr &= ~DSI_INTR_ERROR;
/* clear only overflow */
mdss_dsi_set_reg(ctrl, 0x0c, 0x44440000, 0x44440000);
diff --git a/drivers/video/fbdev/msm/mdss_dsi_panel.c b/drivers/video/fbdev/msm/mdss_dsi_panel.c
index 6f20c0ed0455..9faa1531c256 100644
--- a/drivers/video/fbdev/msm/mdss_dsi_panel.c
+++ b/drivers/video/fbdev/msm/mdss_dsi_panel.c
@@ -1350,6 +1350,44 @@ static int mdss_dsi_parse_hdr_settings(struct device_node *np,
return 0;
}
+static int mdss_dsi_parse_split_link_settings(struct device_node *np,
+ struct mdss_panel_info *pinfo)
+{
+ u32 tmp;
+ int rc = 0;
+
+ if (!np) {
+ pr_err("%s: device node pointer is NULL\n", __func__);
+ return -EINVAL;
+ }
+
+ if (!pinfo) {
+ pr_err("%s: panel info is NULL\n", __func__);
+ return -EINVAL;
+ }
+
+ pinfo->split_link_enabled = of_property_read_bool(np,
+ "qcom,split-link-enabled");
+
+ if (pinfo->split_link_enabled) {
+ rc = of_property_read_u32(np,
+ "qcom,sublinks-count", &tmp);
+ /* default num of sublink is 1*/
+ pinfo->mipi.num_of_sublinks = (!rc ? tmp : 1);
+
+ rc = of_property_read_u32(np,
+ "qcom,lanes-per-sublink", &tmp);
+ /* default num of lanes per sublink is 1 */
+ pinfo->mipi.lanes_per_sublink = (!rc ? tmp : 1);
+ }
+
+ pr_info("%s: enable %d sublinks-count %d lanes per sublink %d\n",
+ __func__, pinfo->split_link_enabled,
+ pinfo->mipi.num_of_sublinks,
+ pinfo->mipi.lanes_per_sublink);
+ return 0;
+}
+
static int mdss_dsi_parse_dsc_version(struct device_node *np,
struct mdss_panel_timing *timing)
{
@@ -2734,9 +2772,15 @@ static int mdss_panel_parse_dt(struct device_node *np,
pinfo->mipi.data_lane3 = of_property_read_bool(np,
"qcom,mdss-dsi-lane-3-state");
+ /* parse split link properties */
+ rc = mdss_dsi_parse_split_link_settings(np, pinfo);
+ if (rc)
+ return rc;
+
rc = mdss_panel_parse_display_timings(np, &ctrl_pdata->panel_data);
if (rc)
return rc;
+
rc = mdss_dsi_parse_hdr_settings(np, pinfo);
if (rc)
return rc;
diff --git a/drivers/video/fbdev/msm/mdss_dsi_status.c b/drivers/video/fbdev/msm/mdss_dsi_status.c
index 4208c2c43efb..0f24f66dbcc6 100644
--- a/drivers/video/fbdev/msm/mdss_dsi_status.c
+++ b/drivers/video/fbdev/msm/mdss_dsi_status.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
@@ -39,6 +39,35 @@ static uint32_t interval = STATUS_CHECK_INTERVAL_MS;
static int32_t dsi_status_disable = DSI_STATUS_CHECK_INIT;
struct dsi_status_data *pstatus_data;
+int mdss_dsi_check_panel_status(struct mdss_dsi_ctrl_pdata *ctrl, void *arg)
+{
+ struct mdss_mdp_ctl *ctl = NULL;
+ struct msm_fb_data_type *mfd = arg;
+ int ret = 0;
+
+ if (!mfd)
+ return -EINVAL;
+
+ ctl = mfd_to_ctl(mfd);
+
+ if (!ctl || !ctrl)
+ return -EINVAL;
+
+ mutex_lock(&ctl->offlock);
+ /*
+ * if check_status method is not defined
+ * then no need to fail this function,
+ * instead return a positive value.
+ */
+ if (ctrl->check_status)
+ ret = ctrl->check_status(ctrl);
+ else
+ ret = 1;
+ mutex_unlock(&ctl->offlock);
+
+ return ret;
+}
+
/*
* check_dsi_ctrl_status() - Reads MFD structure and
* calls platform specific DSI ctrl Status function.
diff --git a/drivers/video/fbdev/msm/mdss_fb.c b/drivers/video/fbdev/msm/mdss_fb.c
index fc47de7692e7..698c5633cf6a 100644
--- a/drivers/video/fbdev/msm/mdss_fb.c
+++ b/drivers/video/fbdev/msm/mdss_fb.c
@@ -374,7 +374,8 @@ static int mdss_fb_get_panel_xres(struct mdss_panel_info *pinfo)
xres = pinfo->xres;
if (pdata->next && pdata->next->active)
xres += mdss_fb_get_panel_xres(&pdata->next->panel_info);
-
+ if (pinfo->split_link_enabled)
+ xres = xres * pinfo->mipi.num_of_sublinks;
return xres;
}
@@ -652,7 +653,7 @@ static ssize_t mdss_fb_get_panel_status(struct device *dev,
ret = scnprintf(buf, PAGE_SIZE, "panel_status=%s\n", "suspend");
} else {
panel_status = mdss_fb_send_panel_event(mfd,
- MDSS_EVENT_DSI_PANEL_STATUS, NULL);
+ MDSS_EVENT_DSI_PANEL_STATUS, mfd);
ret = scnprintf(buf, PAGE_SIZE, "panel_status=%s\n",
panel_status > 0 ? "alive" : "dead");
}
@@ -1595,13 +1596,30 @@ static int mdss_fb_resume(struct platform_device *pdev)
static int mdss_fb_pm_suspend(struct device *dev)
{
struct msm_fb_data_type *mfd = dev_get_drvdata(dev);
+ int rc = 0;
if (!mfd)
return -ENODEV;
dev_dbg(dev, "display pm suspend\n");
- return mdss_fb_suspend_sub(mfd);
+ rc = mdss_fb_suspend_sub(mfd);
+
+ /*
+ * Call MDSS footswitch control to ensure GDSC is
+ * off after pm suspend call. There are cases when
+ * mdss runtime call doesn't trigger even when clock
+ * ref count is zero after fb pm suspend.
+ */
+ if (!rc) {
+ if (mfd->mdp.footswitch_ctrl)
+ mfd->mdp.footswitch_ctrl(false);
+ } else {
+ pr_err("fb pm suspend failed, rc: %d\n", rc);
+ }
+
+ return rc;
+
}
static int mdss_fb_pm_resume(struct device *dev)
@@ -1621,6 +1639,9 @@ static int mdss_fb_pm_resume(struct device *dev)
pm_runtime_set_suspended(dev);
pm_runtime_enable(dev);
+ if (mfd->mdp.footswitch_ctrl)
+ mfd->mdp.footswitch_ctrl(true);
+
return mdss_fb_resume_sub(mfd);
}
#endif
diff --git a/drivers/video/fbdev/msm/mdss_fb.h b/drivers/video/fbdev/msm/mdss_fb.h
index f046ff08cbf7..518c24810acd 100644
--- a/drivers/video/fbdev/msm/mdss_fb.h
+++ b/drivers/video/fbdev/msm/mdss_fb.h
@@ -232,6 +232,7 @@ struct msm_mdp_interface {
int (*configure_panel)(struct msm_fb_data_type *mfd, int mode,
int dest_ctrl);
int (*input_event_handler)(struct msm_fb_data_type *mfd);
+ void (*footswitch_ctrl)(bool on);
int (*pp_release_fnc)(struct msm_fb_data_type *mfd);
void *private1;
};
@@ -392,6 +393,12 @@ static inline void mdss_fb_update_notify_update(struct msm_fb_data_type *mfd)
}
}
+/* Function returns true for split link */
+static inline bool is_panel_split_link(struct msm_fb_data_type *mfd)
+{
+ return mfd && mfd->panel_info && mfd->panel_info->split_link_enabled;
+}
+
/* Function returns true for either any kind of dual display */
static inline bool is_panel_split(struct msm_fb_data_type *mfd)
{
diff --git a/drivers/video/fbdev/msm/mdss_hdcp_1x.c b/drivers/video/fbdev/msm/mdss_hdcp_1x.c
index 834726e84bda..2dc9c8f96c5b 100644
--- a/drivers/video/fbdev/msm/mdss_hdcp_1x.c
+++ b/drivers/video/fbdev/msm/mdss_hdcp_1x.c
@@ -1381,7 +1381,8 @@ int hdcp_1x_authenticate(void *input)
flush_delayed_work(&hdcp->hdcp_auth_work);
- if (!hdcp_1x_state(HDCP_STATE_INACTIVE)) {
+ if (!hdcp_1x_state(HDCP_STATE_INACTIVE) &&
+ !hdcp_1x_state(HDCP_STATE_AUTH_FAIL)) {
pr_err("invalid state\n");
return -EINVAL;
}
@@ -1443,7 +1444,6 @@ int hdcp_1x_reauthenticate(void *input)
DSS_REG_W(io, reg_set->reset, reg & ~reg_set->reset_bit);
- hdcp->hdcp_state = HDCP_STATE_INACTIVE;
hdcp_1x_authenticate(hdcp);
return ret;
diff --git a/drivers/video/fbdev/msm/mdss_mdp.c b/drivers/video/fbdev/msm/mdss_mdp.c
index 171f44815430..a645a3495593 100644
--- a/drivers/video/fbdev/msm/mdss_mdp.c
+++ b/drivers/video/fbdev/msm/mdss_mdp.c
@@ -233,7 +233,6 @@ static struct mdss_mdp_irq mdp_irq_map[] = {
static struct intr_callback *mdp_intr_cb;
-static void mdss_mdp_footswitch_ctrl(struct mdss_data_type *mdata, int on);
static int mdss_mdp_parse_dt(struct platform_device *pdev);
static int mdss_mdp_parse_dt_pipe(struct platform_device *pdev);
static int mdss_mdp_parse_dt_mixer(struct platform_device *pdev);
@@ -5172,7 +5171,7 @@ static void mdss_mdp_notify_idle_pc(struct mdss_data_type *mdata)
* active (but likely in an idle state), the vote for the CX and the batfet
* rails should not be released.
*/
-static void mdss_mdp_footswitch_ctrl(struct mdss_data_type *mdata, int on)
+void mdss_mdp_footswitch_ctrl(struct mdss_data_type *mdata, int on)
{
int ret;
int active_cnt = 0;
diff --git a/drivers/video/fbdev/msm/mdss_mdp.h b/drivers/video/fbdev/msm/mdss_mdp.h
index 2fd047edd3e8..db037ed263b4 100644
--- a/drivers/video/fbdev/msm/mdss_mdp.h
+++ b/drivers/video/fbdev/msm/mdss_mdp.h
@@ -1267,6 +1267,8 @@ static inline u32 get_panel_width(struct mdss_mdp_ctl *ctl)
width = get_panel_xres(&ctl->panel_data->panel_info);
if (ctl->panel_data->next && is_pingpong_split(ctl->mfd))
width += get_panel_xres(&ctl->panel_data->next->panel_info);
+ else if (is_panel_split_link(ctl->mfd))
+ width *= (ctl->panel_data->panel_info.mipi.num_of_sublinks);
return width;
}
@@ -1638,6 +1640,7 @@ int mdss_mdp_set_intr_callback_nosync(u32 intr_type, u32 intf_num,
void (*fnc_ptr)(void *), void *arg);
u32 mdss_mdp_get_irq_mask(u32 intr_type, u32 intf_num);
+void mdss_mdp_footswitch_ctrl(struct mdss_data_type *mdata, int on);
void mdss_mdp_footswitch_ctrl_splash(int on);
void mdss_mdp_batfet_ctrl(struct mdss_data_type *mdata, int enable);
void mdss_mdp_set_clk_rate(unsigned long min_clk_rate, bool locked);
diff --git a/drivers/video/fbdev/msm/mdss_mdp_cdm.c b/drivers/video/fbdev/msm/mdss_mdp_cdm.c
index f1d1bdd301e3..10928e6bceaa 100644
--- a/drivers/video/fbdev/msm/mdss_mdp_cdm.c
+++ b/drivers/video/fbdev/msm/mdss_mdp_cdm.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
@@ -377,6 +377,17 @@ int mdss_mdp_cdm_destroy(struct mdss_mdp_cdm *cdm)
return -EINVAL;
}
+ mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON);
+ mutex_lock(&cdm->lock);
+ /* Disable HDMI packer */
+ writel_relaxed(0x0, cdm->base + MDSS_MDP_REG_CDM_HDMI_PACK_OP_MODE);
+
+ /* Put CDM in bypass */
+ writel_relaxed(0x0, cdm->mdata->mdp_base + MDSS_MDP_MDP_OUT_CTL_0);
+
+ mutex_unlock(&cdm->lock);
+ mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF);
+
kref_put(&cdm->kref, mdss_mdp_cdm_free);
return rc;
diff --git a/drivers/video/fbdev/msm/mdss_mdp_ctl.c b/drivers/video/fbdev/msm/mdss_mdp_ctl.c
index 49348e5e16a9..a66ecb7a57b7 100644
--- a/drivers/video/fbdev/msm/mdss_mdp_ctl.c
+++ b/drivers/video/fbdev/msm/mdss_mdp_ctl.c
@@ -709,6 +709,8 @@ int mdss_mdp_get_panel_params(struct mdss_mdp_pipe *pipe,
*h_total += mdss_panel_get_htotal(
&mixer->ctl->panel_data->next->panel_info,
false);
+ else if (is_panel_split_link(mixer->ctl->mfd))
+ *h_total *= pinfo->mipi.num_of_sublinks;
} else {
*v_total = mixer->height;
*xres = mixer->width;
@@ -4090,6 +4092,13 @@ static void mdss_mdp_ctl_split_display_enable(int enable,
if (is_pingpong_split(main_ctl->mfd))
lower |= BIT(2);
upper = lower;
+
+ /*
+ * align command mode stream0 output for
+ * intferace 1 and 2 to start of frame.
+ */
+ if (main_ctl->mdata->mdp_rev >= MDSS_MDP_HW_REV_320)
+ lower |= BIT(12);
} else {
/* interface controlling sw trigger (video mode) */
if (main_ctl->intf_num == MDSS_MDP_INTF2) {
@@ -4101,6 +4110,9 @@ static void mdss_mdp_ctl_split_display_enable(int enable,
}
}
}
+
+ if (is_panel_split_link(main_ctl->mfd))
+ upper = lower = 0;
writel_relaxed(upper, main_ctl->mdata->mdp_base +
MDSS_MDP_REG_SPLIT_DISPLAY_UPPER_PIPE_CTRL);
writel_relaxed(lower, main_ctl->mdata->mdp_base +
@@ -4269,7 +4281,8 @@ void mdss_mdp_ctl_restore(bool locked)
if (sctl) {
mdss_mdp_ctl_restore_sub(sctl);
mdss_mdp_ctl_split_display_enable(1, ctl, sctl);
- } else if (is_pingpong_split(ctl->mfd)) {
+ } else if (is_pingpong_split(ctl->mfd) ||
+ is_panel_split_link(ctl->mfd)) {
mdss_mdp_ctl_pp_split_display_enable(1, ctl);
}
@@ -4396,6 +4409,8 @@ int mdss_mdp_ctl_start(struct mdss_mdp_ctl *ctl, bool handoff)
} else if (is_pingpong_split(ctl->mfd)) {
ctl->slave_intf_num = (ctl->intf_num + 1);
mdss_mdp_ctl_pp_split_display_enable(true, ctl);
+ } else if (is_panel_split_link(ctl->mfd)) {
+ mdss_mdp_ctl_pp_split_display_enable(true, ctl);
}
}
diff --git a/drivers/video/fbdev/msm/mdss_mdp_hwio.h b/drivers/video/fbdev/msm/mdss_mdp_hwio.h
index 7d495232c198..d9e2b042bfc3 100644
--- a/drivers/video/fbdev/msm/mdss_mdp_hwio.h
+++ b/drivers/video/fbdev/msm/mdss_mdp_hwio.h
@@ -850,4 +850,8 @@ enum mdss_mdp_pingpong_index {
#define MDSS_MDP_REG_TRAFFIC_SHAPER_WR_CLIENT(num) (0x060 + (num * 4))
#define MDSS_MDP_REG_TRAFFIC_SHAPER_FIXPOINT_FACTOR 4
+#define MDSS_MDP_REG_SPLIT_LINK 0x00060
+#define MDSS_MDP_REG_SPLIT_LINK_LEFT_LINK_EN BIT(1)
+#define MDSS_MDP_REG_SPLIT_LINK_RIGHT_LINK_EN BIT(2)
+
#endif
diff --git a/drivers/video/fbdev/msm/mdss_mdp_intf_video.c b/drivers/video/fbdev/msm/mdss_mdp_intf_video.c
index a3511a1a07ef..fe258d85b667 100644
--- a/drivers/video/fbdev/msm/mdss_mdp_intf_video.c
+++ b/drivers/video/fbdev/msm/mdss_mdp_intf_video.c
@@ -1071,6 +1071,13 @@ static int mdss_mdp_video_stop(struct mdss_mdp_ctl *ctl, int panel_power_state)
{
int intfs_num, ret = 0;
+ if (ctl->cdm) {
+ if (!mdss_mdp_cdm_destroy(ctl->cdm))
+ mdss_mdp_ctl_write(ctl,
+ MDSS_MDP_REG_CTL_FLUSH, BIT(26));
+ ctl->cdm = NULL;
+ }
+
intfs_num = ctl->intf_num - MDSS_MDP_INTF0;
ret = mdss_mdp_video_intfs_stop(ctl, ctl->panel_data, intfs_num);
if (IS_ERR_VALUE(ret)) {
@@ -1083,10 +1090,6 @@ static int mdss_mdp_video_stop(struct mdss_mdp_ctl *ctl, int panel_power_state)
mdss_mdp_ctl_reset(ctl, false);
ctl->intf_ctx[MASTER_CTX] = NULL;
- if (ctl->cdm) {
- mdss_mdp_cdm_destroy(ctl->cdm);
- ctl->cdm = NULL;
- }
return 0;
}
@@ -1682,6 +1685,16 @@ static int mdss_mdp_video_display(struct mdss_mdp_ctl *ctl, void *arg)
mdss_bus_bandwidth_ctrl(true);
+ /* configure the split link to both sublinks */
+ if (is_panel_split_link(ctl->mfd)) {
+ mdp_video_write(ctx, MDSS_MDP_REG_SPLIT_LINK, 0x3);
+ /*
+ * ensure split link register is written before
+ * enabling timegen
+ */
+ wmb();
+ }
+
mdp_video_write(ctx, MDSS_MDP_REG_INTF_TIMING_ENGINE_EN, 1);
wmb();
@@ -1796,7 +1809,9 @@ int mdss_mdp_video_reconfigure_splash_done(struct mdss_mdp_ctl *ctl,
mdss_mdp_video_timegen_flush(ctl, sctx);
/* wait for 1 VSYNC for the pipe to be unstaged */
- msleep(20);
+ mdss_mdp_video_wait4comp(ctl, NULL);
+ if (sctl)
+ mdss_mdp_video_wait4comp(sctl, NULL);
ret = mdss_mdp_ctl_intf_event(ctl,
MDSS_EVENT_CONT_SPLASH_FINISH, NULL,
diff --git a/drivers/video/fbdev/msm/mdss_mdp_intf_writeback.c b/drivers/video/fbdev/msm/mdss_mdp_intf_writeback.c
index 87ed56028edd..9b63499e64b0 100644
--- a/drivers/video/fbdev/msm/mdss_mdp_intf_writeback.c
+++ b/drivers/video/fbdev/msm/mdss_mdp_intf_writeback.c
@@ -792,7 +792,9 @@ static int mdss_mdp_writeback_stop(struct mdss_mdp_ctl *ctl,
}
if (ctl->cdm) {
- mdss_mdp_cdm_destroy(ctl->cdm);
+ if (!mdss_mdp_cdm_destroy(ctl->cdm))
+ mdss_mdp_ctl_write(ctl,
+ MDSS_MDP_REG_CTL_FLUSH, BIT(26));
ctl->cdm = NULL;
}
return 0;
diff --git a/drivers/video/fbdev/msm/mdss_mdp_overlay.c b/drivers/video/fbdev/msm/mdss_mdp_overlay.c
index 8eb12d764be3..8c612e2b83fb 100644
--- a/drivers/video/fbdev/msm/mdss_mdp_overlay.c
+++ b/drivers/video/fbdev/msm/mdss_mdp_overlay.c
@@ -2601,6 +2601,18 @@ int mdss_mdp_overlay_kickoff(struct msm_fb_data_type *mfd,
mdss_mdp_splash_cleanup(mfd, true);
/*
+ * Wait for pingpong done only during resume for
+ * command mode panels. Ensure that one commit is
+ * sent before kickoff completes so that backlight
+ * update happens after it.
+ */
+ if (mdss_fb_is_power_off(mfd) &&
+ mfd->panel_info->type == MIPI_CMD_PANEL) {
+ pr_debug("wait for pp done after resume for cmd mode\n");
+ mdss_mdp_display_wait4pingpong(ctl, true);
+ }
+
+ /*
* Configure Timing Engine, if new fps was set.
* We need to do this after the wait for vsync
* to guarantee that mdp flush bit and dsi flush
@@ -6279,6 +6291,13 @@ int mdss_mdp_input_event_handler(struct msm_fb_data_type *mfd)
return rc;
}
+void mdss_mdp_footswitch_ctrl_handler(bool on)
+{
+ struct mdss_data_type *mdata = mdss_mdp_get_mdata();
+
+ mdss_mdp_footswitch_ctrl(mdata, on);
+}
+
int mdss_mdp_overlay_init(struct msm_fb_data_type *mfd)
{
struct device *dev = mfd->fbi->dev;
@@ -6321,6 +6340,14 @@ int mdss_mdp_overlay_init(struct msm_fb_data_type *mfd)
mdp5_interface->configure_panel = mdss_mdp_update_panel_info;
mdp5_interface->input_event_handler = mdss_mdp_input_event_handler;
+ /*
+ * Register footswitch control only for primary fb pm
+ * suspend/resume calls.
+ */
+ if (mfd->panel_info->is_prim_panel)
+ mdp5_interface->footswitch_ctrl =
+ mdss_mdp_footswitch_ctrl_handler;
+
if (mfd->panel_info->type == WRITEBACK_PANEL) {
mdp5_interface->atomic_validate =
mdss_mdp_layer_atomic_validate_wfd;
diff --git a/drivers/video/fbdev/msm/mdss_mdp_pipe.c b/drivers/video/fbdev/msm/mdss_mdp_pipe.c
index 8d7bd60318ad..724913f376a7 100644
--- a/drivers/video/fbdev/msm/mdss_mdp_pipe.c
+++ b/drivers/video/fbdev/msm/mdss_mdp_pipe.c
@@ -2292,6 +2292,9 @@ static int mdss_mdp_src_addr_setup(struct mdss_mdp_pipe *pipe,
mdss_mdp_pipe_write(pipe, MDSS_MDP_REG_SSPP_SRC3_ADDR, addr[2]);
}
+ MDSS_XLOG(pipe->num, pipe->multirect.num, pipe->mixer_left->num,
+ pipe->play_cnt, addr[0], addr[1], addr[2], addr[3]);
+
return 0;
}
@@ -2734,9 +2737,6 @@ int mdss_mdp_pipe_queue_data(struct mdss_mdp_pipe *pipe,
goto update_nobuf;
}
- MDSS_XLOG(pipe->num, pipe->multirect.num, pipe->mixer_left->num,
- pipe->play_cnt, 0x222);
-
if (params_changed) {
pipe->params_changed = 0;
diff --git a/drivers/video/fbdev/msm/mdss_panel.h b/drivers/video/fbdev/msm/mdss_panel.h
index 92413e078244..fa1df94976f9 100644
--- a/drivers/video/fbdev/msm/mdss_panel.h
+++ b/drivers/video/fbdev/msm/mdss_panel.h
@@ -533,6 +533,8 @@ struct mipi_panel_info {
char lp11_init;
u32 init_delay;
u32 post_init_delay;
+ u32 num_of_sublinks;
+ u32 lanes_per_sublink;
};
struct edp_panel_info {
@@ -847,6 +849,7 @@ struct mdss_panel_info {
bool is_lpm_mode;
bool is_split_display; /* two DSIs in one display, pp split or not */
bool use_pingpong_split;
+ bool split_link_enabled;
/*
* index[0] = left layer mixer, value of 0 not valid
diff --git a/drivers/video/fbdev/msm/mdss_smmu.c b/drivers/video/fbdev/msm/mdss_smmu.c
index 62e25500060e..f56158446c0d 100644
--- a/drivers/video/fbdev/msm/mdss_smmu.c
+++ b/drivers/video/fbdev/msm/mdss_smmu.c
@@ -600,24 +600,30 @@ int mdss_smmu_fault_handler(struct iommu_domain *domain, struct device *dev,
(struct mdss_smmu_client *)user_data;
u32 fsynr1, mid, i;
- if (!mdss_smmu || !mdss_smmu->mmu_base)
+ if (!mdss_smmu)
goto end;
- fsynr1 = readl_relaxed(mdss_smmu->mmu_base + SMMU_CBN_FSYNR1);
- mid = fsynr1 & 0xff;
- pr_err("mdss_smmu: iova:0x%lx flags:0x%x fsynr1: 0x%x mid: 0x%x\n",
- iova, flags, fsynr1, mid);
+ if (mdss_smmu->mmu_base) {
+ fsynr1 = readl_relaxed(mdss_smmu->mmu_base + SMMU_CBN_FSYNR1);
+ mid = fsynr1 & 0xff;
+ pr_err("mdss_smmu: iova:0x%lx flags:0x%x fsynr1: 0x%x mid: 0x%x\n",
+ iova, flags, fsynr1, mid);
- /* get domain id information */
- for (i = 0; i < MDSS_IOMMU_MAX_DOMAIN; i++) {
- if (mdss_smmu == mdss_smmu_get_cb(i))
- break;
- }
+ /* get domain id information */
+ for (i = 0; i < MDSS_IOMMU_MAX_DOMAIN; i++) {
+ if (mdss_smmu == mdss_smmu_get_cb(i))
+ break;
+ }
- if (i == MDSS_IOMMU_MAX_DOMAIN)
- goto end;
+ if (i == MDSS_IOMMU_MAX_DOMAIN)
+ goto end;
- mdss_mdp_debug_mid(mid);
+ mdss_mdp_debug_mid(mid);
+ } else {
+ pr_err("mdss_smmu: iova:0x%lx flags:0x%x\n",
+ iova, flags);
+ MDSS_XLOG_TOUT_HANDLER("mdp");
+ }
end:
return -ENOSYS;
}
@@ -844,14 +850,13 @@ int mdss_smmu_probe(struct platform_device *pdev)
mdss_smmu->base.dev = dev;
+ iommu_set_fault_handler(mdss_smmu->mmu_mapping->domain,
+ mdss_smmu_fault_handler, mdss_smmu);
address = of_get_address_by_name(pdev->dev.of_node, "mmu_cb", 0, 0);
if (address) {
size = address + 1;
mdss_smmu->mmu_base = ioremap(be32_to_cpu(*address),
be32_to_cpu(*size));
- if (mdss_smmu->mmu_base)
- iommu_set_fault_handler(mdss_smmu->mmu_mapping->domain,
- mdss_smmu_fault_handler, mdss_smmu);
} else {
pr_debug("unable to map context bank base\n");
}
diff --git a/drivers/video/fbdev/msm/msm_mdss_io_8974.c b/drivers/video/fbdev/msm/msm_mdss_io_8974.c
index 03e78733d168..9c156af6b63c 100644
--- a/drivers/video/fbdev/msm/msm_mdss_io_8974.c
+++ b/drivers/video/fbdev/msm/msm_mdss_io_8974.c
@@ -38,16 +38,23 @@
#define MDSS_DSI_DSIPHY_GLBL_TEST_CTRL 0x1d4
#define MDSS_DSI_DSIPHY_CTRL_0 0x170
#define MDSS_DSI_DSIPHY_CTRL_1 0x174
+#define MDSS_DSI_DSIPHY_CMN_CLK_CFG0 0x0010
+#define MDSS_DSI_DSIPHY_CMN_CLK_CFG1 0x0014
+
+#define MDSS_DSI_NUM_DATA_LANES 0x04
+#define MDSS_DSI_NUM_CLK_LANES 0x01
#define SW_RESET BIT(2)
#define SW_RESET_PLL BIT(0)
#define PWRDN_B BIT(7)
/* 8996 */
-#define DATALANE_OFFSET_FROM_BASE_8996 0x100
-#define DSIPHY_CMN_PLL_CNTRL 0x0048
+#define DATALANE_OFFSET_FROM_BASE_8996 0x100
+#define CLKLANE_OFFSET_FROM_BASE_8996 0x300
#define DATALANE_SIZE_8996 0x80
+#define CLKLANE_SIZE_8996 0x80
+#define DSIPHY_CMN_PLL_CNTRL 0x0048
#define DSIPHY_CMN_GLBL_TEST_CTRL 0x0018
#define DSIPHY_CMN_CTRL_0 0x001c
#define DSIPHY_CMN_CTRL_1 0x0020
@@ -55,6 +62,24 @@
#define DSIPHY_PLL_CLKBUFLR_EN 0x041c
#define DSIPHY_PLL_PLL_BANDGAP 0x0508
+#define DSIPHY_LANE_STRENGTH_CTRL_NUM 0x0002
+#define DSIPHY_LANE_STRENGTH_CTRL_OFFSET 0x0004
+#define DSIPHY_LANE_STRENGTH_CTRL_BASE 0x0038
+
+#define DSIPHY_LANE_CFG_NUM 0x0004
+#define DSIPHY_LANE_CFG_OFFSET 0x0004
+#define DSIPHY_LANE_CFG_BASE 0x0000
+
+#define DSIPHY_LANE_VREG_NUM 0x0001
+#define DSIPHY_LANE_VREG_OFFSET 0x0004
+#define DSIPHY_LANE_VREG_BASE 0x0064
+
+#define DSIPHY_LANE_TIMING_CTRL_NUM 0x0008
+#define DSIPHY_LANE_TIMING_CTRL_OFFSET 0x0004
+#define DSIPHY_LANE_TIMING_CTRL_BASE 0x0018
+
+#define DSIPHY_LANE_TEST_STR 0x0014
+
#define DSIPHY_LANE_STRENGTH_CTRL_1 0x003c
#define DSIPHY_LANE_VREG_CNTRL 0x0064
@@ -131,6 +156,8 @@
#define DSIPHY_PLL_RESETSM_CNTRL5 0x043c
+#define DSIPHY_CMN_CLK_CFG1_SPLIT_LINK 0x1
+
#define PLL_CALC_DATA(addr0, addr1, data0, data1) \
(((data1) << 24) | ((((addr1)/4) & 0xFF) << 16) | \
((data0) << 8) | (((addr0)/4) & 0xFF))
@@ -911,35 +938,59 @@ static void mdss_dsi_8996_phy_regulator_enable(
int j, off, ln, cnt, ln_off;
char *ip;
void __iomem *base;
+ struct mdss_panel_info *panel_info;
+
+ if (!ctrl) {
+ pr_warn("%s: null ctrl pdata\n", __func__);
+ return;
+ }
+ panel_info = &((ctrl->panel_data).panel_info);
pd = &(((ctrl->panel_data).panel_info.mipi).dsi_phy_db);
- if (pd->regulator_len != 5) {
+ if (pd->regulator_len != (MDSS_DSI_NUM_DATA_LANES +
+ MDSS_DSI_NUM_CLK_LANES)) {
pr_warn("%s: invalid regulator settings\n", __func__);
return;
}
- /* 4 lanes + clk lane configuration */
- for (ln = 0; ln < 5; ln++) {
- /*
- * data lane offset frome base: 0x100
- * data lane size: 0x80
- */
- base = ctrl->phy_io.base +
- DATALANE_OFFSET_FROM_BASE_8996;
- base += (ln * DATALANE_SIZE_8996); /* lane base */
-
- /* vreg ctrl, 1 * 5 */
- cnt = 1;
+ /*
+ * data lane offset from base: 0x100
+ * data lane size: 0x80
+ */
+ base = ctrl->phy_io.base + DATALANE_OFFSET_FROM_BASE_8996;
+ /* data lanes configuration */
+ for (ln = 0; ln < MDSS_DSI_NUM_DATA_LANES; ln++) {
+ /* vreg ctrl, 1 * MDSS_DSI_NUM_DATA_LANES */
+ cnt = DSIPHY_LANE_VREG_NUM;
+ off = DSIPHY_LANE_VREG_BASE;
ln_off = cnt * ln;
ip = &pd->regulator[ln_off];
- off = 0x64;
- for (j = 0; j < cnt; j++, off += 4)
+ for (j = 0; j < cnt; j++) {
MIPI_OUTP(base + off, *ip++);
+ off += DSIPHY_LANE_VREG_OFFSET;
+ }
+ base += DATALANE_SIZE_8996; /* next lane */
}
- wmb(); /* make sure registers committed */
+ /*
+ * clk lane offset from base: 0x300
+ * clk lane size: 0x80
+ */
+ base = ctrl->phy_io.base + CLKLANE_OFFSET_FROM_BASE_8996;
+ /*
+ * clk lane configuration for vreg ctrl
+ * for split link there are two clock lanes, one
+ * clock lane per sublink needs to be configured
+ */
+ off = DSIPHY_LANE_VREG_BASE;
+ ln_off = MDSS_DSI_NUM_DATA_LANES;
+ ip = &pd->regulator[ln_off];
+ MIPI_OUTP(base + off, *ip);
+ if (panel_info->split_link_enabled)
+ MIPI_OUTP(base + CLKLANE_SIZE_8996 + off, *ip);
+ wmb(); /* make sure registers committed */
}
static void mdss_dsi_8996_phy_power_off(
@@ -948,31 +999,51 @@ static void mdss_dsi_8996_phy_power_off(
int ln;
void __iomem *base;
u32 data;
+ struct mdss_panel_info *panel_info;
+
+ if (ctrl) {
+ panel_info = &((ctrl->panel_data).panel_info);
+ } else {
+ pr_warn("%s: null ctrl pdata\n", __func__);
+ return;
+ }
/* Turn off PLL power */
data = MIPI_INP(ctrl->phy_io.base + DSIPHY_CMN_CTRL_0);
MIPI_OUTP(ctrl->phy_io.base + DSIPHY_CMN_CTRL_0, data & ~BIT(7));
- /* 4 lanes + clk lane configuration */
- for (ln = 0; ln < 5; ln++) {
- base = ctrl->phy_io.base +
- DATALANE_OFFSET_FROM_BASE_8996;
- base += (ln * DATALANE_SIZE_8996); /* lane base */
-
+ /* data lanes configuration */
+ base = ctrl->phy_io.base + DATALANE_OFFSET_FROM_BASE_8996;
+ for (ln = 0; ln < MDSS_DSI_NUM_DATA_LANES; ln++) {
/* turn off phy ldo */
- MIPI_OUTP(base + DSIPHY_LANE_VREG_CNTRL, 0x1c);
+ MIPI_OUTP(base + DSIPHY_LANE_VREG_BASE, 0x1c);
+ base += DATALANE_SIZE_8996; /* next lane */
}
- MIPI_OUTP((ctrl->phy_io.base) + DSIPHY_CMN_LDO_CNTRL, 0x1c);
- /* 4 lanes + clk lane configuration */
- for (ln = 0; ln < 5; ln++) {
- base = ctrl->phy_io.base +
- DATALANE_OFFSET_FROM_BASE_8996;
- base += (ln * DATALANE_SIZE_8996); /* lane base */
+ /* clk lane configuration */
+ base = ctrl->phy_io.base + CLKLANE_OFFSET_FROM_BASE_8996;
+ /* turn off phy ldo */
+ MIPI_OUTP(base + DSIPHY_LANE_VREG_BASE, 0x1c);
+ if (panel_info->split_link_enabled)
+ MIPI_OUTP(base + CLKLANE_SIZE_8996 +
+ DSIPHY_LANE_VREG_BASE, 0x1c);
+
+ MIPI_OUTP((ctrl->phy_io.base) + DSIPHY_CMN_LDO_CNTRL, 0x1c);
+ /* data lanes configuration */
+ base = ctrl->phy_io.base + DATALANE_OFFSET_FROM_BASE_8996;
+ for (ln = 0; ln < MDSS_DSI_NUM_DATA_LANES; ln++) {
MIPI_OUTP(base + DSIPHY_LANE_STRENGTH_CTRL_1, 0x0);
+ base += DATALANE_SIZE_8996; /* next lane */
}
+ /* clk lane configuration */
+ base = ctrl->phy_io.base + CLKLANE_OFFSET_FROM_BASE_8996;
+ MIPI_OUTP(base + DSIPHY_LANE_STRENGTH_CTRL_1, 0x0);
+ if (panel_info->split_link_enabled)
+ MIPI_OUTP(base + CLKLANE_SIZE_8996 +
+ DSIPHY_LANE_STRENGTH_CTRL_1, 0x0);
+
wmb(); /* make sure registers committed */
}
@@ -1008,22 +1079,46 @@ static void mdss_dsi_8996_phy_power_on(
struct mdss_dsi_phy_ctrl *pd;
char *ip;
u32 data;
+ struct mdss_panel_info *panel_info;
- pd = &(((ctrl->panel_data).panel_info.mipi).dsi_phy_db);
+ if (ctrl) {
+ panel_info = &((ctrl->panel_data).panel_info);
+ } else {
+ pr_warn("%s: null ctrl pdata\n", __func__);
+ return;
+ }
- /* 4 lanes + clk lane configuration */
- for (ln = 0; ln < 5; ln++) {
- base = ctrl->phy_io.base +
- DATALANE_OFFSET_FROM_BASE_8996;
- base += (ln * DATALANE_SIZE_8996); /* lane base */
+ pd = &(((ctrl->panel_data).panel_info.mipi).dsi_phy_db);
- /* strength, 2 * 5 */
- cnt = 2;
+ /* data lanes configuration */
+ base = ctrl->phy_io.base + DATALANE_OFFSET_FROM_BASE_8996;
+ for (ln = 0; ln < MDSS_DSI_NUM_DATA_LANES; ln++) {
+ /* strength, 2 * MDSS_DSI_NUM_DATA_LANES */
+ cnt = DSIPHY_LANE_STRENGTH_CTRL_NUM;
ln_off = cnt * ln;
ip = &pd->strength[ln_off];
- off = 0x38;
- for (j = 0; j < cnt; j++, off += 4)
+ off = DSIPHY_LANE_STRENGTH_CTRL_BASE;
+ for (j = 0; j < cnt; j++,
+ off += DSIPHY_LANE_STRENGTH_CTRL_OFFSET)
MIPI_OUTP(base + off, *ip++);
+ base += DATALANE_SIZE_8996; /* next lane */
+ }
+
+ /*
+ * clk lane configuration for strength ctrl
+ * for split link there are two clock lanes, one
+ * clock lane per sublink needs to be configured
+ */
+ base = ctrl->phy_io.base + CLKLANE_OFFSET_FROM_BASE_8996;
+ cnt = DSIPHY_LANE_STRENGTH_CTRL_NUM;
+ ln_off = MDSS_DSI_NUM_DATA_LANES;
+ ip = &pd->strength[ln_off];
+ off = DSIPHY_LANE_STRENGTH_CTRL_BASE;
+ for (j = 0; j < cnt; j++,
+ off += DSIPHY_LANE_STRENGTH_CTRL_OFFSET) {
+ MIPI_OUTP(base + off, *ip);
+ if (panel_info->split_link_enabled)
+ MIPI_OUTP(base + CLKLANE_SIZE_8996 + off, *ip);
}
mdss_dsi_8996_phy_regulator_enable(ctrl);
@@ -1051,67 +1146,126 @@ static void mdss_dsi_8996_phy_config(struct mdss_dsi_ctrl_pdata *ctrl)
int j, off, ln, cnt, ln_off;
char *ip;
void __iomem *base;
+ struct mdss_panel_info *panel_info;
+ int num_of_lanes = 0;
+
+ if (ctrl) {
+ panel_info = &((ctrl->panel_data).panel_info);
+ } else {
+ pr_warn("%s: null ctrl pdata\n", __func__);
+ return;
+ }
pd = &(((ctrl->panel_data).panel_info.mipi).dsi_phy_db);
+ num_of_lanes = MDSS_DSI_NUM_DATA_LANES + MDSS_DSI_NUM_CLK_LANES;
MIPI_OUTP((ctrl->phy_io.base) + DSIPHY_CMN_LDO_CNTRL, 0x1c);
/* clk_en */
MIPI_OUTP((ctrl->phy_io.base) + DSIPHY_CMN_GLBL_TEST_CTRL, 0x1);
- if (pd->lanecfg_len != 20) {
+ if (pd->lanecfg_len != (num_of_lanes * DSIPHY_LANE_CFG_NUM)) {
pr_err("%s: wrong lane cfg\n", __func__);
return;
}
- if (pd->strength_len != 10) {
+ if (pd->strength_len != (num_of_lanes *
+ DSIPHY_LANE_STRENGTH_CTRL_NUM)) {
pr_err("%s: wrong strength ctrl\n", __func__);
return;
}
- if (pd->regulator_len != 5) {
+ if (pd->regulator_len != (num_of_lanes * DSIPHY_LANE_VREG_NUM)) {
pr_err("%s: wrong regulator setting\n", __func__);
return;
}
- /* 4 lanes + clk lane configuration */
- for (ln = 0; ln < 5; ln++) {
- /*
- * data lane offset frome base: 0x100
- * data lane size: 0x80
- */
- base = ctrl->phy_io.base +
- DATALANE_OFFSET_FROM_BASE_8996;
- base += (ln * DATALANE_SIZE_8996); /* lane base */
-
- /* lane cfg, 4 * 5 */
- cnt = 4;
+ /* data lanes configuration */
+ base = ctrl->phy_io.base + DATALANE_OFFSET_FROM_BASE_8996;
+ for (ln = 0; ln < MDSS_DSI_NUM_DATA_LANES; ln++) {
+ /* lane cfg, 4 * MDSS_DSI_NUM_DATA_LANES */
+ cnt = DSIPHY_LANE_CFG_NUM;
+ off = DSIPHY_LANE_CFG_BASE;
ln_off = cnt * ln;
ip = &pd->lanecfg[ln_off];
- off = 0x0;
for (j = 0; j < cnt; j++) {
MIPI_OUTP(base + off, *ip++);
- off += 4;
+ off += DSIPHY_LANE_CFG_OFFSET;
}
/* test str */
- MIPI_OUTP(base + 0x14, 0x0088); /* fixed */
+ MIPI_OUTP(base + DSIPHY_LANE_TEST_STR, 0x88); /* fixed */
- /* phy timing, 8 * 5 */
- cnt = 8;
+ /* phy timing, 8 * MDSS_DSI_NUM_DATA_LANES */
+ cnt = DSIPHY_LANE_TIMING_CTRL_NUM;
+ off = DSIPHY_LANE_TIMING_CTRL_BASE;
ln_off = cnt * ln;
ip = &pd->timing_8996[ln_off];
- off = 0x18;
- for (j = 0; j < cnt; j++, off += 4)
+ for (j = 0; j < cnt; j++) {
MIPI_OUTP(base + off, *ip++);
+ off += DSIPHY_LANE_TIMING_CTRL_OFFSET;
+ }
- /* strength, 2 * 5 */
- cnt = 2;
+ /* strength, 2 * MDSS_DSI_NUM_DATA_LANES */
+ cnt = DSIPHY_LANE_STRENGTH_CTRL_NUM;
+ off = DSIPHY_LANE_STRENGTH_CTRL_BASE;
ln_off = cnt * ln;
ip = &pd->strength[ln_off];
- off = 0x38;
- for (j = 0; j < cnt; j++, off += 4)
+ for (j = 0; j < cnt; j++) {
MIPI_OUTP(base + off, *ip++);
+ off += DSIPHY_LANE_STRENGTH_CTRL_OFFSET;
+ }
+
+ base += DATALANE_SIZE_8996; /* next lane */
+ }
+
+ /*
+ * clk lane configuration
+ * for split link there are two clock lanes, one
+ * clock lane per sublink needs to be configured
+ */
+ base = ctrl->phy_io.base + CLKLANE_OFFSET_FROM_BASE_8996;
+ cnt = DSIPHY_LANE_CFG_NUM;
+ off = DSIPHY_LANE_CFG_BASE;
+ ln_off = cnt * MDSS_DSI_NUM_DATA_LANES;
+ ip = &pd->lanecfg[ln_off];
+ for (j = 0; j < cnt; j++, *ip++) {
+ MIPI_OUTP(base + off, *ip);
+ if (panel_info->split_link_enabled)
+ MIPI_OUTP(base + CLKLANE_SIZE_8996 + off, *ip);
+ off += DSIPHY_LANE_CFG_OFFSET;
+ }
+
+ /* test str */
+ MIPI_OUTP(base + DSIPHY_LANE_TEST_STR, 0x88); /* fixed */
+ if (panel_info->split_link_enabled)
+ MIPI_OUTP(base + CLKLANE_SIZE_8996 + off, 0x88);
+
+ cnt = DSIPHY_LANE_TIMING_CTRL_NUM;
+ off = DSIPHY_LANE_TIMING_CTRL_BASE;
+ ln_off = cnt * MDSS_DSI_NUM_DATA_LANES;
+ ip = &pd->timing_8996[ln_off];
+ for (j = 0; j < cnt; j++, *ip++) {
+ MIPI_OUTP(base + off, *ip);
+ if (panel_info->split_link_enabled)
+ MIPI_OUTP(base + CLKLANE_SIZE_8996 + off, *ip);
+ off += DSIPHY_LANE_TIMING_CTRL_OFFSET;
+ }
+
+ /*
+ * clk lane configuration for timing
+ * for split link there are two clock lanes, one
+ * clock lane per sublink needs to be configured
+ */
+ cnt = DSIPHY_LANE_STRENGTH_CTRL_NUM;
+ off = DSIPHY_LANE_STRENGTH_CTRL_BASE;
+ ln_off = cnt * MDSS_DSI_NUM_DATA_LANES;
+ ip = &pd->strength[ln_off];
+ for (j = 0; j < cnt; j++, *ip++) {
+ MIPI_OUTP(base + off, *ip);
+ if (panel_info->split_link_enabled)
+ MIPI_OUTP(base + CLKLANE_SIZE_8996 + off, *ip);
+ off += DSIPHY_LANE_STRENGTH_CTRL_OFFSET;
}
wmb(); /* make sure registers committed */
@@ -1665,6 +1819,9 @@ int mdss_dsi_clk_div_config(struct mdss_panel_info *panel_info,
u32 dsi_pclk_rate;
u8 lanes = 0, bpp;
+ if (!panel_info)
+ return -EINVAL;
+
if (panel_info->mipi.data_lane3)
lanes += 1;
if (panel_info->mipi.data_lane2)
@@ -1690,6 +1847,8 @@ int mdss_dsi_clk_div_config(struct mdss_panel_info *panel_info,
}
h_period = mdss_panel_get_htotal(panel_info, true);
+ if (panel_info->split_link_enabled)
+ h_period *= panel_info->mipi.num_of_sublinks;
v_period = mdss_panel_get_vtotal(panel_info);
if (ctrl_pdata->refresh_clk_rate || is_diff_frame_rate(panel_info,
@@ -1710,7 +1869,12 @@ int mdss_dsi_clk_div_config(struct mdss_panel_info *panel_info,
clk_rate = panel_info->clk_rate;
do_div(clk_rate, 8 * bpp);
- dsi_pclk_rate = (u32) clk_rate * lanes;
+
+ if (panel_info->split_link_enabled)
+ dsi_pclk_rate = (u32) clk_rate *
+ panel_info->mipi.lanes_per_sublink;
+ else
+ dsi_pclk_rate = (u32) clk_rate * lanes;
if ((dsi_pclk_rate < 3300000) || (dsi_pclk_rate > 250000000))
dsi_pclk_rate = 35000000;
@@ -2320,6 +2484,32 @@ int mdss_dsi_pre_clkoff_cb(void *priv,
return rc;
}
+static void mdss_dsi_split_link_clk_cfg(struct mdss_dsi_ctrl_pdata *ctrl,
+ int enable)
+{
+ struct mdss_panel_data *pdata = NULL;
+ void __iomem *base;
+ u32 data = 0;
+
+ if (ctrl)
+ pdata = &ctrl->panel_data;
+ else {
+ pr_err("%s: ctrl pdata is NULL\n", __func__);
+ return;
+ }
+
+ /*
+ * for split link there are two clock lanes, and
+ * both clock lanes needs to be enabled
+ */
+ if (pdata->panel_info.split_link_enabled) {
+ base = ctrl->phy_io.base;
+ data = MIPI_INP(base + MDSS_DSI_DSIPHY_CMN_CLK_CFG1);
+ data |= (enable << DSIPHY_CMN_CLK_CFG1_SPLIT_LINK);
+ MIPI_OUTP(base + MDSS_DSI_DSIPHY_CMN_CLK_CFG1, data);
+ }
+}
+
int mdss_dsi_post_clkon_cb(void *priv,
enum mdss_dsi_clk_type clk,
enum mdss_dsi_clk_state curr_state)
@@ -2393,6 +2583,9 @@ int mdss_dsi_post_clkon_cb(void *priv,
}
if (pdata->panel_info.mipi.force_clk_lane_hs)
mdss_dsi_cfg_lane_ctrl(ctrl, BIT(28), 1);
+
+ /* enable split link for cmn clk cfg1 */
+ mdss_dsi_split_link_clk_cfg(ctrl, 1);
}
error:
return rc;
diff --git a/drivers/video/hdmi.c b/drivers/video/hdmi.c
index 162689227a23..1cf907ecded4 100644
--- a/drivers/video/hdmi.c
+++ b/drivers/video/hdmi.c
@@ -533,6 +533,10 @@ hdmi_picture_aspect_get_name(enum hdmi_picture_aspect picture_aspect)
return "4:3";
case HDMI_PICTURE_ASPECT_16_9:
return "16:9";
+ case HDMI_PICTURE_ASPECT_64_27:
+ return "64:27";
+ case HDMI_PICTURE_ASPECT_256_135:
+ return "256:135";
case HDMI_PICTURE_ASPECT_RESERVED:
return "Reserved";
}
diff --git a/fs/ext4/inline.c b/fs/ext4/inline.c
index cb3d6f6419cd..db81acb686c0 100644
--- a/fs/ext4/inline.c
+++ b/fs/ext4/inline.c
@@ -18,6 +18,7 @@
#include "ext4.h"
#include "xattr.h"
#include "truncate.h"
+#include <trace/events/android_fs.h>
#define EXT4_XATTR_SYSTEM_DATA "data"
#define EXT4_MIN_INLINE_DATA_SIZE ((sizeof(__le32) * EXT4_N_BLOCKS))
@@ -502,6 +503,17 @@ int ext4_readpage_inline(struct inode *inode, struct page *page)
return -EAGAIN;
}
+ if (trace_android_fs_dataread_start_enabled()) {
+ char *path, pathbuf[MAX_TRACE_PATHBUF_LEN];
+
+ path = android_fstrace_get_pathname(pathbuf,
+ MAX_TRACE_PATHBUF_LEN,
+ inode);
+ trace_android_fs_dataread_start(inode, page_offset(page),
+ PAGE_SIZE, current->pid,
+ path, current->comm);
+ }
+
/*
* Current inline data can only exist in the 1st page,
* So for all the other pages, just set them uptodate.
@@ -513,6 +525,8 @@ int ext4_readpage_inline(struct inode *inode, struct page *page)
SetPageUptodate(page);
}
+ trace_android_fs_dataread_end(inode, page_offset(page), PAGE_SIZE);
+
up_read(&EXT4_I(inode)->xattr_sem);
unlock_page(page);
diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c
index 99fa2fca52b1..72b384931f66 100644
--- a/fs/ext4/inode.c
+++ b/fs/ext4/inode.c
@@ -45,6 +45,7 @@
#include "ext4_ice.h"
#include <trace/events/ext4.h>
+#include <trace/events/android_fs.h>
#define MPAGE_DA_EXTENT_TAIL 0x01
@@ -1018,6 +1019,16 @@ static int ext4_write_begin(struct file *file, struct address_space *mapping,
pgoff_t index;
unsigned from, to;
+ if (trace_android_fs_datawrite_start_enabled()) {
+ char *path, pathbuf[MAX_TRACE_PATHBUF_LEN];
+
+ path = android_fstrace_get_pathname(pathbuf,
+ MAX_TRACE_PATHBUF_LEN,
+ inode);
+ trace_android_fs_datawrite_start(inode, pos, len,
+ current->pid, path,
+ current->comm);
+ }
trace_ext4_write_begin(inode, pos, len, flags);
/*
* Reserve one block more for addition to orphan list in case
@@ -1154,6 +1165,7 @@ static int ext4_write_end(struct file *file,
int ret = 0, ret2;
int i_size_changed = 0;
+ trace_android_fs_datawrite_end(inode, pos, len);
trace_ext4_write_end(inode, pos, len, copied);
if (ext4_test_inode_state(inode, EXT4_STATE_ORDERED_MODE)) {
ret = ext4_jbd2_file_inode(handle, inode);
@@ -1267,6 +1279,7 @@ static int ext4_journalled_write_end(struct file *file,
unsigned from, to;
int size_changed = 0;
+ trace_android_fs_datawrite_end(inode, pos, len);
trace_ext4_journalled_write_end(inode, pos, len, copied);
from = pos & (PAGE_CACHE_SIZE - 1);
to = from + len;
@@ -2742,6 +2755,16 @@ static int ext4_da_write_begin(struct file *file, struct address_space *mapping,
len, flags, pagep, fsdata);
}
*fsdata = (void *)0;
+ if (trace_android_fs_datawrite_start_enabled()) {
+ char *path, pathbuf[MAX_TRACE_PATHBUF_LEN];
+
+ path = android_fstrace_get_pathname(pathbuf,
+ MAX_TRACE_PATHBUF_LEN,
+ inode);
+ trace_android_fs_datawrite_start(inode, pos, len,
+ current->pid,
+ path, current->comm);
+ }
trace_ext4_da_write_begin(inode, pos, len, flags);
if (ext4_test_inode_state(inode, EXT4_STATE_MAY_INLINE_DATA)) {
@@ -2860,6 +2883,7 @@ static int ext4_da_write_end(struct file *file,
return ext4_write_end(file, mapping, pos,
len, copied, page, fsdata);
+ trace_android_fs_datawrite_end(inode, pos, len);
trace_ext4_da_write_end(inode, pos, len, copied);
start = pos & (PAGE_CACHE_SIZE - 1);
end = start + copied - 1;
@@ -3352,12 +3376,42 @@ static ssize_t ext4_direct_IO(struct kiocb *iocb, struct iov_iter *iter,
if (ext4_has_inline_data(inode))
return 0;
+ if (trace_android_fs_dataread_start_enabled() &&
+ (iov_iter_rw(iter) == READ)) {
+ char *path, pathbuf[MAX_TRACE_PATHBUF_LEN];
+
+ path = android_fstrace_get_pathname(pathbuf,
+ MAX_TRACE_PATHBUF_LEN,
+ inode);
+ trace_android_fs_dataread_start(inode, offset, count,
+ current->pid, path,
+ current->comm);
+ }
+ if (trace_android_fs_datawrite_start_enabled() &&
+ (iov_iter_rw(iter) == WRITE)) {
+ char *path, pathbuf[MAX_TRACE_PATHBUF_LEN];
+
+ path = android_fstrace_get_pathname(pathbuf,
+ MAX_TRACE_PATHBUF_LEN,
+ inode);
+ trace_android_fs_datawrite_start(inode, offset, count,
+ current->pid, path,
+ current->comm);
+ }
trace_ext4_direct_IO_enter(inode, offset, count, iov_iter_rw(iter));
if (ext4_test_inode_flag(inode, EXT4_INODE_EXTENTS))
ret = ext4_ext_direct_IO(iocb, iter, offset);
else
ret = ext4_ind_direct_IO(iocb, iter, offset);
trace_ext4_direct_IO_exit(inode, offset, count, iov_iter_rw(iter), ret);
+
+ if (trace_android_fs_dataread_start_enabled() &&
+ (iov_iter_rw(iter) == READ))
+ trace_android_fs_dataread_end(inode, offset, count);
+ if (trace_android_fs_datawrite_start_enabled() &&
+ (iov_iter_rw(iter) == WRITE))
+ trace_android_fs_datawrite_end(inode, offset, count);
+
return ret;
}
diff --git a/fs/ext4/readpage.c b/fs/ext4/readpage.c
index 71a08a294529..99f1bd8c7f05 100644
--- a/fs/ext4/readpage.c
+++ b/fs/ext4/readpage.c
@@ -46,6 +46,7 @@
#include "ext4.h"
#include "ext4_ice.h"
+#include <trace/events/android_fs.h>
/*
* Call ext4_decrypt on every single page, reusing the encryption
@@ -92,6 +93,17 @@ static inline bool ext4_bio_encrypted(struct bio *bio)
#endif
}
+static void
+ext4_trace_read_completion(struct bio *bio)
+{
+ struct page *first_page = bio->bi_io_vec[0].bv_page;
+
+ if (first_page != NULL)
+ trace_android_fs_dataread_end(first_page->mapping->host,
+ page_offset(first_page),
+ bio->bi_iter.bi_size);
+}
+
/*
* I/O completion handler for multipage BIOs.
*
@@ -109,6 +121,9 @@ static void mpage_end_io(struct bio *bio)
struct bio_vec *bv;
int i;
+ if (trace_android_fs_dataread_start_enabled())
+ ext4_trace_read_completion(bio);
+
if (ext4_bio_encrypted(bio)) {
struct ext4_crypto_ctx *ctx = bio->bi_private;
@@ -136,6 +151,30 @@ static void mpage_end_io(struct bio *bio)
bio_put(bio);
}
+static void
+ext4_submit_bio_read(struct bio *bio)
+{
+ if (trace_android_fs_dataread_start_enabled()) {
+ struct page *first_page = bio->bi_io_vec[0].bv_page;
+
+ if (first_page != NULL) {
+ char *path, pathbuf[MAX_TRACE_PATHBUF_LEN];
+
+ path = android_fstrace_get_pathname(pathbuf,
+ MAX_TRACE_PATHBUF_LEN,
+ first_page->mapping->host);
+ trace_android_fs_dataread_start(
+ first_page->mapping->host,
+ page_offset(first_page),
+ bio->bi_iter.bi_size,
+ current->pid,
+ path,
+ current->comm);
+ }
+ }
+ submit_bio(READ, bio);
+}
+
int ext4_mpage_readpages(struct address_space *mapping,
struct list_head *pages, struct page *page,
unsigned nr_pages)
@@ -277,7 +316,7 @@ int ext4_mpage_readpages(struct address_space *mapping,
*/
if (bio && (last_block_in_bio != blocks[0] - 1)) {
submit_and_realloc:
- submit_bio(READ, bio);
+ ext4_submit_bio_read(bio);
bio = NULL;
}
if (bio == NULL) {
@@ -309,14 +348,14 @@ int ext4_mpage_readpages(struct address_space *mapping,
if (((map.m_flags & EXT4_MAP_BOUNDARY) &&
(relative_block == map.m_len)) ||
(first_hole != blocks_per_page)) {
- submit_bio(READ, bio);
+ ext4_submit_bio_read(bio);
bio = NULL;
} else
last_block_in_bio = blocks[blocks_per_page - 1];
goto next_page;
confused:
if (bio) {
- submit_bio(READ, bio);
+ ext4_submit_bio_read(bio);
bio = NULL;
}
if (!PageUptodate(page))
@@ -329,6 +368,6 @@ int ext4_mpage_readpages(struct address_space *mapping,
}
BUG_ON(pages && !list_empty(pages));
if (bio)
- submit_bio(READ, bio);
+ ext4_submit_bio_read(bio);
return 0;
}
diff --git a/fs/f2fs/data.c b/fs/f2fs/data.c
index f53826ec30f3..4fb5709256fd 100644
--- a/fs/f2fs/data.c
+++ b/fs/f2fs/data.c
@@ -26,6 +26,7 @@
#include "segment.h"
#include "trace.h"
#include <trace/events/f2fs.h>
+#include <trace/events/android_fs.h>
static void f2fs_read_end_io(struct bio *bio)
{
@@ -1405,6 +1406,16 @@ static int f2fs_write_begin(struct file *file, struct address_space *mapping,
struct dnode_of_data dn;
int err = 0;
+ if (trace_android_fs_datawrite_start_enabled()) {
+ char *path, pathbuf[MAX_TRACE_PATHBUF_LEN];
+
+ path = android_fstrace_get_pathname(pathbuf,
+ MAX_TRACE_PATHBUF_LEN,
+ inode);
+ trace_android_fs_datawrite_start(inode, pos, len,
+ current->pid, path,
+ current->comm);
+ }
trace_f2fs_write_begin(inode, pos, len, flags);
f2fs_balance_fs(sbi);
@@ -1533,6 +1544,7 @@ static int f2fs_write_end(struct file *file,
{
struct inode *inode = page->mapping->host;
+ trace_android_fs_datawrite_end(inode, pos, len);
trace_f2fs_write_end(inode, pos, len, copied);
set_page_dirty(page);
@@ -1586,6 +1598,28 @@ static ssize_t f2fs_direct_IO(struct kiocb *iocb, struct iov_iter *iter,
trace_f2fs_direct_IO_enter(inode, offset, count, iov_iter_rw(iter));
+ if (trace_android_fs_dataread_start_enabled() &&
+ (iov_iter_rw(iter) == READ)) {
+ char *path, pathbuf[MAX_TRACE_PATHBUF_LEN];
+
+ path = android_fstrace_get_pathname(pathbuf,
+ MAX_TRACE_PATHBUF_LEN,
+ inode);
+ trace_android_fs_dataread_start(inode, offset,
+ count, current->pid, path,
+ current->comm);
+ }
+ if (trace_android_fs_datawrite_start_enabled() &&
+ (iov_iter_rw(iter) == WRITE)) {
+ char *path, pathbuf[MAX_TRACE_PATHBUF_LEN];
+
+ path = android_fstrace_get_pathname(pathbuf,
+ MAX_TRACE_PATHBUF_LEN,
+ inode);
+ trace_android_fs_datawrite_start(inode, offset, count,
+ current->pid, path,
+ current->comm);
+ }
if (iov_iter_rw(iter) == WRITE) {
__allocate_data_blocks(inode, offset, count);
if (unlikely(f2fs_cp_error(F2FS_I_SB(inode)))) {
@@ -1599,6 +1633,13 @@ out:
if (err < 0 && iov_iter_rw(iter) == WRITE)
f2fs_write_failed(mapping, offset + count);
+ if (trace_android_fs_dataread_start_enabled() &&
+ (iov_iter_rw(iter) == READ))
+ trace_android_fs_dataread_end(inode, offset, count);
+ if (trace_android_fs_datawrite_start_enabled() &&
+ (iov_iter_rw(iter) == WRITE))
+ trace_android_fs_datawrite_end(inode, offset, count);
+
trace_f2fs_direct_IO_exit(inode, offset, count, iov_iter_rw(iter), err);
return err;
diff --git a/fs/f2fs/inline.c b/fs/f2fs/inline.c
index bda7126466c0..dbb2cc4df603 100644
--- a/fs/f2fs/inline.c
+++ b/fs/f2fs/inline.c
@@ -13,6 +13,7 @@
#include "f2fs.h"
#include "node.h"
+#include <trace/events/android_fs.h>
bool f2fs_may_inline_data(struct inode *inode)
{
@@ -84,14 +85,29 @@ int f2fs_read_inline_data(struct inode *inode, struct page *page)
{
struct page *ipage;
+ if (trace_android_fs_dataread_start_enabled()) {
+ char *path, pathbuf[MAX_TRACE_PATHBUF_LEN];
+
+ path = android_fstrace_get_pathname(pathbuf,
+ MAX_TRACE_PATHBUF_LEN,
+ inode);
+ trace_android_fs_dataread_start(inode, page_offset(page),
+ PAGE_SIZE, current->pid,
+ path, current->comm);
+ }
+
ipage = get_node_page(F2FS_I_SB(inode), inode->i_ino);
if (IS_ERR(ipage)) {
+ trace_android_fs_dataread_end(inode, page_offset(page),
+ PAGE_SIZE);
unlock_page(page);
return PTR_ERR(ipage);
}
if (!f2fs_has_inline_data(inode)) {
f2fs_put_page(ipage, 1);
+ trace_android_fs_dataread_end(inode, page_offset(page),
+ PAGE_SIZE);
return -EAGAIN;
}
@@ -102,6 +118,8 @@ int f2fs_read_inline_data(struct inode *inode, struct page *page)
SetPageUptodate(page);
f2fs_put_page(ipage, 1);
+ trace_android_fs_dataread_end(inode, page_offset(page),
+ PAGE_SIZE);
unlock_page(page);
return 0;
}
diff --git a/fs/mpage.c b/fs/mpage.c
index 1480d3a18037..0fd48fdcc1b1 100644
--- a/fs/mpage.c
+++ b/fs/mpage.c
@@ -30,6 +30,14 @@
#include <linux/cleancache.h>
#include "internal.h"
+#define CREATE_TRACE_POINTS
+#include <trace/events/android_fs.h>
+
+EXPORT_TRACEPOINT_SYMBOL(android_fs_datawrite_start);
+EXPORT_TRACEPOINT_SYMBOL(android_fs_datawrite_end);
+EXPORT_TRACEPOINT_SYMBOL(android_fs_dataread_start);
+EXPORT_TRACEPOINT_SYMBOL(android_fs_dataread_end);
+
/*
* I/O completion handler for multipage BIOs.
*
@@ -47,6 +55,16 @@ static void mpage_end_io(struct bio *bio)
struct bio_vec *bv;
int i;
+ if (trace_android_fs_dataread_end_enabled() &&
+ (bio_data_dir(bio) == READ)) {
+ struct page *first_page = bio->bi_io_vec[0].bv_page;
+
+ if (first_page != NULL)
+ trace_android_fs_dataread_end(first_page->mapping->host,
+ page_offset(first_page),
+ bio->bi_iter.bi_size);
+ }
+
bio_for_each_segment_all(bv, bio, i) {
struct page *page = bv->bv_page;
page_endio(page, bio_data_dir(bio), bio->bi_error);
@@ -57,6 +75,24 @@ static void mpage_end_io(struct bio *bio)
static struct bio *mpage_bio_submit(int rw, struct bio *bio)
{
+ if (trace_android_fs_dataread_start_enabled() && (rw == READ)) {
+ struct page *first_page = bio->bi_io_vec[0].bv_page;
+
+ if (first_page != NULL) {
+ char *path, pathbuf[MAX_TRACE_PATHBUF_LEN];
+
+ path = android_fstrace_get_pathname(pathbuf,
+ MAX_TRACE_PATHBUF_LEN,
+ first_page->mapping->host);
+ trace_android_fs_dataread_start(
+ first_page->mapping->host,
+ page_offset(first_page),
+ bio->bi_iter.bi_size,
+ current->pid,
+ path,
+ current->comm);
+ }
+ }
bio->bi_end_io = mpage_end_io;
guard_bio_eod(rw, bio);
submit_bio(rw, bio);
diff --git a/include/drm/drm_crtc.h b/include/drm/drm_crtc.h
index aab1530661a5..6555fdbee88a 100644
--- a/include/drm/drm_crtc.h
+++ b/include/drm/drm_crtc.h
@@ -644,6 +644,20 @@ struct drm_encoder {
* @audio_latency: audio latency info from ELD, if found
* @null_edid_counter: track sinks that give us all zeros for the EDID
* @bad_edid_counter: track sinks that give us an EDID with invalid checksum
+ * @max_tmds_char: indicates the maximum TMDS Character Rate supported
+ * @scdc_present: when set the sink supports SCDC functionality
+ * @rr_capable: when set the sink is capable of initiating an SCDC read request
+ * @supports_scramble: when set the sink supports less than 340Mcsc scrambling
+ * @flags_3d: 3D view(s) supported by the sink, see drm_edid.h (DRM_EDID_3D_*)
+ * @pt_scan_info: PT scan info obtained from the VCDB of EDID
+ * @it_scan_info: IT scan info obtained from the VCDB of EDID
+ * @ce_scan_info: CE scan info obtained from the VCDB of EDID
+ * @hdr_eotf: Electro optical transfer function obtained from HDR block
+ * @hdr_metadata_type_one: Metadata type one obtained from HDR block
+ * @hdr_max_luminance: desired max luminance obtained from HDR block
+ * @hdr_avg_luminance: desired avg luminance obtained from HDR block
+ * @hdr_min_luminance: desired min luminance obtained from HDR block
+ * @hdr_supported: does the sink support HDR content
* @edid_corrupt: indicates whether the last read EDID was corrupt
* @debugfs_entry: debugfs directory for this connector
* @state: current atomic state for this connector
@@ -717,6 +731,21 @@ struct drm_connector {
int null_edid_counter; /* needed to workaround some HW bugs where we get all 0s */
unsigned bad_edid_counter;
+ /* EDID bits HDMI 2.0 */
+ int max_tmds_char; /* in Mcsc */
+ bool scdc_present;
+ bool rr_capable;
+ bool supports_scramble;
+ int flags_3d;
+ u8 pt_scan_info;
+ u8 it_scan_info;
+ u8 ce_scan_info;
+ u32 hdr_eotf;
+ bool hdr_metadata_type_one;
+ u32 hdr_max_luminance;
+ u32 hdr_avg_luminance;
+ u32 hdr_min_luminance;
+ bool hdr_supported;
/* Flag for raw EDID header corruption - used in Displayport
* compliance testing - * Displayport Link CTS Core 1.2 rev1.1 4.2.2.6
*/
diff --git a/include/drm/drm_displayid.h b/include/drm/drm_displayid.h
index 623b4e98e748..c0d4df6a606f 100644
--- a/include/drm/drm_displayid.h
+++ b/include/drm/drm_displayid.h
@@ -73,4 +73,21 @@ struct displayid_tiled_block {
u8 topology_id[8];
} __packed;
+struct displayid_detailed_timings_1 {
+ u8 pixel_clock[3];
+ u8 flags;
+ u8 hactive[2];
+ u8 hblank[2];
+ u8 hsync[2];
+ u8 hsw[2];
+ u8 vactive[2];
+ u8 vblank[2];
+ u8 vsync[2];
+ u8 vsw[2];
+} __packed;
+
+struct displayid_detailed_timing_block {
+ struct displayid_block base;
+ struct displayid_detailed_timings_1 timings[0];
+};
#endif
diff --git a/include/drm/drm_edid.h b/include/drm/drm_edid.h
index 2af97691e878..4317ea41382f 100644
--- a/include/drm/drm_edid.h
+++ b/include/drm/drm_edid.h
@@ -266,6 +266,11 @@ struct detailed_timing {
#define DRM_ELD_CEA_SAD(mnl, sad) (20 + (mnl) + 3 * (sad))
+/* HDMI 2.0 */
+#define DRM_EDID_3D_INDEPENDENT_VIEW (1 << 2)
+#define DRM_EDID_3D_DUAL_VIEW (1 << 1)
+#define DRM_EDID_3D_OSD_DISPARITY (1 << 0)
+
struct edid {
u8 header[8];
/* Vendor & product info */
diff --git a/include/linux/hdmi.h b/include/linux/hdmi.h
index e9744202fa29..bc38b99a9fc9 100644
--- a/include/linux/hdmi.h
+++ b/include/linux/hdmi.h
@@ -35,6 +35,7 @@ enum hdmi_infoframe_type {
};
#define HDMI_IEEE_OUI 0x000c03
+#define HDMI_IEEE_OUI_HF 0xc45dd8
#define HDMI_INFOFRAME_HEADER_SIZE 4
#define HDMI_AVI_INFOFRAME_SIZE 13
#define HDMI_SPD_INFOFRAME_SIZE 25
@@ -78,6 +79,8 @@ enum hdmi_picture_aspect {
HDMI_PICTURE_ASPECT_NONE,
HDMI_PICTURE_ASPECT_4_3,
HDMI_PICTURE_ASPECT_16_9,
+ HDMI_PICTURE_ASPECT_64_27,
+ HDMI_PICTURE_ASPECT_256_135,
HDMI_PICTURE_ASPECT_RESERVED,
};
diff --git a/include/linux/ieee80211.h b/include/linux/ieee80211.h
index 452c0b0d2f32..d8f4316167d8 100644
--- a/include/linux/ieee80211.h
+++ b/include/linux/ieee80211.h
@@ -1535,6 +1535,9 @@ struct ieee80211_vht_operation {
#define WLAN_AUTH_SHARED_KEY 1
#define WLAN_AUTH_FT 2
#define WLAN_AUTH_SAE 3
+#define WLAN_AUTH_FILS_SK 4
+#define WLAN_AUTH_FILS_SK_PFS 5
+#define WLAN_AUTH_FILS_PK 6
#define WLAN_AUTH_LEAP 128
#define WLAN_AUTH_CHALLENGE_LEN 128
diff --git a/include/linux/io-pgtable-fast.h b/include/linux/io-pgtable-fast.h
index 029e11f9919b..6a56f0039f15 100644
--- a/include/linux/io-pgtable-fast.h
+++ b/include/linux/io-pgtable-fast.h
@@ -37,7 +37,7 @@ void av8l_fast_unmap_public(av8l_fast_iopte *ptep, size_t size);
#define AV8L_FAST_PTE_UNMAPPED_NEED_TLBI 0xa
void av8l_fast_clear_stale_ptes(av8l_fast_iopte *puds, u64 base,
- u64 end, bool skip_sync);
+ u64 start, u64 end, bool skip_sync);
void av8l_register_notify(struct notifier_block *nb);
#else /* !CONFIG_IOMMU_IO_PGTABLE_FAST_PROVE_TLB */
@@ -46,6 +46,7 @@ void av8l_register_notify(struct notifier_block *nb);
static inline void av8l_fast_clear_stale_ptes(av8l_fast_iopte *puds,
u64 base,
+ u64 start,
u64 end,
bool skip_sync)
{
diff --git a/include/linux/leds-qpnp-flash.h b/include/linux/leds-qpnp-flash.h
index 4b5a339970fa..1fe6e1709fa6 100644
--- a/include/linux/leds-qpnp-flash.h
+++ b/include/linux/leds-qpnp-flash.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2016, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2016-2017, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -18,7 +18,6 @@
#define ENABLE_REGULATOR BIT(0)
#define DISABLE_REGULATOR BIT(1)
#define QUERY_MAX_CURRENT BIT(2)
-#define PRE_FLASH BIT(3)
#define FLASH_LED_PREPARE_OPTIONS_MASK GENMASK(3, 0)
diff --git a/include/linux/mm.h b/include/linux/mm.h
index 186d2ab9cd13..3c10d4638646 100644
--- a/include/linux/mm.h
+++ b/include/linux/mm.h
@@ -2146,6 +2146,17 @@ static inline void vm_stat_account(struct mm_struct *mm,
}
#endif /* CONFIG_PROC_FS */
+#ifdef CONFIG_PAGE_POISONING
+extern bool page_poisoning_enabled(void);
+extern void kernel_poison_pages(struct page *page, int numpages, int enable);
+extern bool page_is_poisoned(struct page *page);
+#else
+static inline bool page_poisoning_enabled(void) { return false; }
+static inline void kernel_poison_pages(struct page *page, int numpages,
+ int enable) { }
+static inline bool page_is_poisoned(struct page *page) { return false; }
+#endif
+
#ifdef CONFIG_DEBUG_PAGEALLOC
extern bool _debug_pagealloc_enabled;
extern void __kernel_map_pages(struct page *page, int numpages, int enable);
@@ -2295,7 +2306,6 @@ extern void copy_user_huge_page(struct page *dst, struct page *src,
#endif /* CONFIG_TRANSPARENT_HUGEPAGE || CONFIG_HUGETLBFS */
extern struct page_ext_operations debug_guardpage_ops;
-extern struct page_ext_operations page_poisoning_ops;
#ifdef CONFIG_DEBUG_PAGEALLOC
extern unsigned int _debug_guardpage_minorder;
diff --git a/include/linux/msm_mhi.h b/include/linux/msm_mhi.h
index 2b50ce59406e..c01cb1af4231 100644
--- a/include/linux/msm_mhi.h
+++ b/include/linux/msm_mhi.h
@@ -62,7 +62,9 @@ enum MHI_CLIENT_CHANNEL {
MHI_CLIENT_CSVT_IN = 43,
MHI_CLIENT_SMCT_OUT = 44,
MHI_CLIENT_SMCT_IN = 45,
- MHI_CLIENT_RESERVED_1_LOWER = 46,
+ MHI_CLIENT_IP_SW_4_OUT = 46,
+ MHI_CLIENT_IP_SW_4_IN = 47,
+ MHI_CLIENT_RESERVED_1_LOWER = 48,
MHI_CLIENT_RESERVED_1_UPPER = 99,
MHI_CLIENT_IP_HW_0_OUT = 100,
MHI_CLIENT_IP_HW_0_IN = 101,
diff --git a/include/linux/poison.h b/include/linux/poison.h
index 317e16de09e5..199ffec4bdf3 100644
--- a/include/linux/poison.h
+++ b/include/linux/poison.h
@@ -30,7 +30,11 @@
#define TIMER_ENTRY_STATIC ((void *) 0x74737461)
/********** mm/debug-pagealloc.c **********/
+#ifdef CONFIG_PAGE_POISONING_ZERO
+#define PAGE_POISON 0x00
+#else
#define PAGE_POISON 0xaa
+#endif
/********** mm/slab.c **********/
/*
diff --git a/include/linux/qpnp/qpnp-revid.h b/include/linux/qpnp/qpnp-revid.h
index 7254f4d16176..b025df568259 100644
--- a/include/linux/qpnp/qpnp-revid.h
+++ b/include/linux/qpnp/qpnp-revid.h
@@ -214,6 +214,11 @@
#define PM660L_V1P1_REV3 0x01
#define PM660L_V1P1_REV4 0x01
+#define PM660L_V2P0_REV1 0x00
+#define PM660L_V2P0_REV2 0x00
+#define PM660L_V2P0_REV3 0x00
+#define PM660L_V2P0_REV4 0x02
+
/* PMI8998 FAB_ID */
#define PMI8998_FAB_ID_SMIC 0x11
#define PMI8998_FAB_ID_GF 0x30
@@ -235,6 +240,9 @@
/* SMB1381 */
#define SMB1381_SUBTYPE 0x17
+/* SMB1355 */
+#define SMB1355_SUBTYPE 0x1C
+
struct pmic_revid_data {
u8 rev1;
u8 rev2;
diff --git a/include/linux/regulator/qpnp-labibb-regulator.h b/include/linux/regulator/qpnp-labibb-regulator.h
index 247069507fd9..33985afeb6e9 100644
--- a/include/linux/regulator/qpnp-labibb-regulator.h
+++ b/include/linux/regulator/qpnp-labibb-regulator.h
@@ -15,6 +15,7 @@
enum labibb_notify_event {
LAB_VREG_OK = 1,
+ LAB_VREG_NOT_OK,
};
int qpnp_labibb_notifier_register(struct notifier_block *nb);
diff --git a/include/linux/sched.h b/include/linux/sched.h
index 95d758d63784..4b56a62a0a58 100644
--- a/include/linux/sched.h
+++ b/include/linux/sched.h
@@ -3247,6 +3247,15 @@ static inline void cond_resched_rcu(void)
#endif
}
+static inline unsigned long get_preempt_disable_ip(struct task_struct *p)
+{
+#ifdef CONFIG_DEBUG_PREEMPT
+ return p->preempt_disable_ip;
+#else
+ return 0;
+#endif
+}
+
/*
* Does a critical section need to be broken due to another
* task waiting?: (technically does not depend on CONFIG_PREEMPT,
diff --git a/include/linux/shrinker.h b/include/linux/shrinker.h
index 4fcacd915d45..e77f648f9662 100644
--- a/include/linux/shrinker.h
+++ b/include/linux/shrinker.h
@@ -66,6 +66,7 @@ struct shrinker {
/* Flags */
#define SHRINKER_NUMA_AWARE (1 << 0)
#define SHRINKER_MEMCG_AWARE (1 << 1)
+#define SHRINKER_LMK (1 << 2)
extern int register_shrinker(struct shrinker *);
extern void unregister_shrinker(struct shrinker *);
diff --git a/include/linux/usb/audio-v3.h b/include/linux/usb/audio-v3.h
new file mode 100644
index 000000000000..f2322f3c74f7
--- /dev/null
+++ b/include/linux/usb/audio-v3.h
@@ -0,0 +1,172 @@
+/*
+ * 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.
+ *
+ * This file holds USB constants and structures defined
+ * by the USB Device Class Definition for Audio Devices in version 3.0.
+ * Comments below reference relevant sections of the documents contained
+ * in http://www.usb.org/developers/docs/devclass_docs/USB_Audio_v3.0.zip
+ */
+
+#ifndef __LINUX_USB_AUDIO_V3_H
+#define __LINUX_USB_AUDIO_V3_H
+
+#include <linux/types.h>
+
+#define UAC3_MIXER_UNIT_V3 0x05
+#define UAC3_FEATURE_UNIT_V3 0x07
+#define UAC3_CLOCK_SOURCE 0x0b
+
+#define BADD_MAXPSIZE_SYNC_MONO_16 0x0060
+#define BADD_MAXPSIZE_SYNC_MONO_24 0x0090
+#define BADD_MAXPSIZE_SYNC_STEREO_16 0x00c0
+#define BADD_MAXPSIZE_SYNC_STEREO_24 0x0120
+
+#define BADD_MAXPSIZE_ASYNC_MONO_16 0x0062
+#define BADD_MAXPSIZE_ASYNC_MONO_24 0x0093
+#define BADD_MAXPSIZE_ASYNC_STEREO_16 0x00c4
+#define BADD_MAXPSIZE_ASYNC_STEREO_24 0x0126
+
+#define BIT_RES_16_BIT 0x10
+#define BIT_RES_24_BIT 0x18
+
+#define SUBSLOTSIZE_16_BIT 0x02
+#define SUBSLOTSIZE_24_BIT 0x03
+
+#define BADD_SAMPLING_RATE 48000
+
+#define NUM_CHANNELS_MONO 1
+#define NUM_CHANNELS_STEREO 2
+#define BADD_CH_CONFIG_MONO 0
+#define BADD_CH_CONFIG_STEREO 3
+#define CLUSTER_ID_MONO 0x0001
+#define CLUSTER_ID_STEREO 0x0002
+
+#define FULL_ADC_PROFILE 0x01
+
+/* BADD Profile IDs */
+#define PROF_GENERIC_IO 0x20
+#define PROF_HEADPHONE 0x21
+#define PROF_SPEAKER 0x22
+#define PROF_MICROPHONE 0x23
+#define PROF_HEADSET 0x24
+#define PROF_HEADSET_ADAPTER 0x25
+#define PROF_SPEAKERPHONE 0x26
+
+/* BADD Entity IDs */
+#define BADD_OUT_TERM_ID_BAOF 0x03
+#define BADD_OUT_TERM_ID_BAIF 0x06
+#define BADD_IN_TERM_ID_BAOF 0x01
+#define BADD_IN_TERM_ID_BAIF 0x04
+#define BADD_FU_ID_BAOF 0x02
+#define BADD_FU_ID_BAIF 0x05
+#define BADD_CLOCK_SOURCE 0x09
+#define BADD_FU_ID_BAIOF 0x07
+#define BADD_MU_ID_BAIOF 0x08
+
+#define UAC_BIDIR_TERMINAL_HEADSET 0x0402
+#define UAC_BIDIR_TERMINAL_SPEAKERPHONE 0x0403
+
+#define NUM_BADD_DESCS 7
+
+struct uac3_input_terminal_descriptor {
+ __u8 bLength;
+ __u8 bDescriptorType;
+ __u8 bDescriptorSubtype;
+ __u8 bTerminalID;
+ __u16 wTerminalType;
+ __u8 bAssocTerminal;
+ __u8 bCSourceID;
+ __u32 bmControls;
+ __u16 wClusterDescrID;
+ __u16 wExTerminalDescrID;
+ __u16 wConnectorsDescrID;
+ __u16 wTerminalDescrStr;
+} __packed;
+
+#define UAC3_DT_INPUT_TERMINAL_SIZE 0x14
+
+extern struct uac3_input_terminal_descriptor badd_baif_in_term_desc;
+extern struct uac3_input_terminal_descriptor badd_baof_in_term_desc;
+
+struct uac3_output_terminal_descriptor {
+ __u8 bLength;
+ __u8 bDescriptorType;
+ __u8 bDescriptorSubtype;
+ __u8 bTerminalID;
+ __u16 wTerminalType;
+ __u8 bAssocTerminal;
+ __u8 bSourceID;
+ __u8 bCSourceID;
+ __u32 bmControls;
+ __u16 wExTerminalDescrID;
+ __u16 wConnectorsDescrID;
+ __u16 wTerminalDescrStr;
+} __packed;
+
+#define UAC3_DT_OUTPUT_TERMINAL_SIZE 0x13
+
+extern struct uac3_output_terminal_descriptor badd_baif_out_term_desc;
+extern struct uac3_output_terminal_descriptor badd_baof_out_term_desc;
+
+extern __u8 monoControls[];
+extern __u8 stereoControls[];
+extern __u8 badd_mu_src_ids[];
+
+struct uac3_mixer_unit_descriptor {
+ __u8 bLength;
+ __u8 bDescriptorType;
+ __u8 bDescriptorSubtype;
+ __u8 bUnitID;
+ __u8 bNrInPins;
+ __u8 *baSourceID;
+ __u16 wClusterDescrID;
+ __u8 bmMixerControls;
+ __u32 bmControls;
+ __u16 wMixerDescrStr;
+} __packed;
+
+#define UAC3_DT_MIXER_UNIT_SIZE 0x10
+
+extern struct uac3_mixer_unit_descriptor badd_baiof_mu_desc;
+
+struct uac3_feature_unit_descriptor {
+ __u8 bLength;
+ __u8 bDescriptorType;
+ __u8 bDescriptorSubtype;
+ __u8 bUnitID;
+ __u8 bSourceID;
+ __u8 *bmaControls;
+ __u16 wFeatureDescrStr;
+} __packed;
+
+extern struct uac3_feature_unit_descriptor badd_baif_fu_desc;
+extern struct uac3_feature_unit_descriptor badd_baof_fu_desc;
+extern struct uac3_feature_unit_descriptor badd_baiof_fu_desc;
+
+struct uac3_clock_source_descriptor {
+ __u8 bLength;
+ __u8 bDescriptorType;
+ __u8 bDescriptorSubtype;
+ __u8 bClockID;
+ __u8 bmAttributes;
+ __u32 bmControls;
+ __u8 bReferenceTerminal;
+ __u16 wClockSourceStr;
+} __packed;
+
+#define UAC3_DT_CLOCK_SRC_SIZE 0x0c
+
+extern struct uac3_clock_source_descriptor badd_clock_desc;
+
+extern void *badd_desc_list[];
+
+#endif /* __LINUX_USB_AUDIO_V3_H */
diff --git a/include/linux/usb/ccid_desc.h b/include/linux/usb/ccid_desc.h
index 9a0c72650cd2..2e6dbb5afe71 100644
--- a/include/linux/usb/ccid_desc.h
+++ b/include/linux/usb/ccid_desc.h
@@ -86,27 +86,27 @@
* Table 5.1-1 Smart Card Device Class descriptors
*/
struct usb_ccid_class_descriptor {
- unsigned char bLength;
- unsigned char bDescriptorType;
- unsigned short bcdCCID;
- unsigned char bMaxSlotIndex;
- unsigned char bVoltageSupport;
- unsigned long dwProtocols;
- unsigned long dwDefaultClock;
- unsigned long dwMaximumClock;
- unsigned char bNumClockSupported;
- unsigned long dwDataRate;
- unsigned long dwMaxDataRate;
- unsigned char bNumDataRatesSupported;
- unsigned long dwMaxIFSD;
- unsigned long dwSynchProtocols;
- unsigned long dwMechanical;
- unsigned long dwFeatures;
- unsigned long dwMaxCCIDMessageLength;
- unsigned char bClassGetResponse;
- unsigned char bClassEnvelope;
- unsigned short wLcdLayout;
- unsigned char bPINSupport;
- unsigned char bMaxCCIDBusySlots;
+ __u8 bLength;
+ __u8 bDescriptorType;
+ __u16 bcdCCID;
+ __u8 bMaxSlotIndex;
+ __u8 bVoltageSupport;
+ __u32 dwProtocols;
+ __u32 dwDefaultClock;
+ __u32 dwMaximumClock;
+ __u8 bNumClockSupported;
+ __u32 dwDataRate;
+ __u32 dwMaxDataRate;
+ __u8 bNumDataRatesSupported;
+ __u32 dwMaxIFSD;
+ __u32 dwSynchProtocols;
+ __u32 dwMechanical;
+ __u32 dwFeatures;
+ __u32 dwMaxCCIDMessageLength;
+ __u8 bClassGetResponse;
+ __u8 bClassEnvelope;
+ __u16 wLcdLayout;
+ __u8 bPINSupport;
+ __u8 bMaxCCIDBusySlots;
} __packed;
#endif
diff --git a/include/media/msm_cam_sensor.h b/include/media/msm_cam_sensor.h
index 75d0912aa459..762f1c51620c 100644
--- a/include/media/msm_cam_sensor.h
+++ b/include/media/msm_cam_sensor.h
@@ -41,6 +41,7 @@ struct msm_camera_sensor_slave_info32 {
uint8_t is_init_params_valid;
struct msm_sensor_init_params sensor_init_params;
enum msm_sensor_output_format_t output_format;
+ uint8_t bypass_video_node_creation;
};
struct msm_camera_csid_lut_params32 {
diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h
index 85534884c1a0..e9277e860bd7 100644
--- a/include/net/cfg80211.h
+++ b/include/net/cfg80211.h
@@ -1783,9 +1783,11 @@ const u8 *ieee80211_bss_get_ie(struct cfg80211_bss *bss, u8 ie);
* @key_len: length of WEP key for shared key authentication
* @key_idx: index of WEP key for shared key authentication
* @key: WEP key for shared key authentication
- * @sae_data: Non-IE data to use with SAE or %NULL. This starts with
- * Authentication transaction sequence number field.
- * @sae_data_len: Length of sae_data buffer in octets
+ * @auth_data: Fields and elements in Authentication frames. This contains
+ * the authentication frame body (non-IE and IE data), excluding the
+ * Authentication algorithm number, i.e., starting at the Authentication
+ * transaction sequence number field.
+ * @auth_data_len: Length of auth_data buffer in octets
*/
struct cfg80211_auth_request {
struct cfg80211_bss *bss;
@@ -1794,8 +1796,8 @@ struct cfg80211_auth_request {
enum nl80211_auth_type auth_type;
const u8 *key;
u8 key_len, key_idx;
- const u8 *sae_data;
- size_t sae_data_len;
+ const u8 *auth_data;
+ size_t auth_data_len;
};
/**
diff --git a/include/soc/qcom/socinfo.h b/include/soc/qcom/socinfo.h
index ac36df5769ee..dfb0280d146c 100644
--- a/include/soc/qcom/socinfo.h
+++ b/include/soc/qcom/socinfo.h
@@ -90,8 +90,8 @@
of_flat_dt_is_compatible(of_get_flat_dt_root(), "qcom,msm8929")
#define early_machine_is_msm8998() \
of_flat_dt_is_compatible(of_get_flat_dt_root(), "qcom,msm8998")
-#define early_machine_is_apq8998() \
- of_flat_dt_is_compatible(of_get_flat_dt_root(), "qcom,apq8998")
+#define early_machine_is_apq8098() \
+ of_flat_dt_is_compatible(of_get_flat_dt_root(), "qcom,apq8098")
#define early_machine_is_msmhamster() \
of_flat_dt_is_compatible(of_get_flat_dt_root(), "qcom,msmhamster")
#define early_machine_is_sdm660() \
@@ -140,7 +140,7 @@
#define early_machine_is_msm8976() 0
#define early_machine_is_msm8929() 0
#define early_machine_is_msm8998() 0
-#define early_machine_is_apq8998() 0
+#define early_machine_is_apq8098() 0
#define early_machine_is_msmhamster() 0
#define early_machine_is_sdm660() 0
#define early_machine_is_sda660() 0
diff --git a/include/soc/qcom/subsystem_restart.h b/include/soc/qcom/subsystem_restart.h
index 763eaa9ad918..59749210001a 100644
--- a/include/soc/qcom/subsystem_restart.h
+++ b/include/soc/qcom/subsystem_restart.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
@@ -18,6 +18,7 @@
#include <linux/interrupt.h>
struct subsys_device;
+extern struct bus_type subsys_bus_type;
enum {
RESET_SOC = 0,
diff --git a/include/trace/events/android_fs.h b/include/trace/events/android_fs.h
new file mode 100644
index 000000000000..49509533d3fa
--- /dev/null
+++ b/include/trace/events/android_fs.h
@@ -0,0 +1,65 @@
+#undef TRACE_SYSTEM
+#define TRACE_SYSTEM android_fs
+
+#if !defined(_TRACE_ANDROID_FS_H) || defined(TRACE_HEADER_MULTI_READ)
+#define _TRACE_ANDROID_FS_H
+
+#include <linux/tracepoint.h>
+#include <trace/events/android_fs_template.h>
+
+DEFINE_EVENT(android_fs_data_start_template, android_fs_dataread_start,
+ TP_PROTO(struct inode *inode, loff_t offset, int bytes,
+ pid_t pid, char *pathname, char *command),
+ TP_ARGS(inode, offset, bytes, pid, pathname, command));
+
+DEFINE_EVENT(android_fs_data_end_template, android_fs_dataread_end,
+ TP_PROTO(struct inode *inode, loff_t offset, int bytes),
+ TP_ARGS(inode, offset, bytes));
+
+DEFINE_EVENT(android_fs_data_start_template, android_fs_datawrite_start,
+ TP_PROTO(struct inode *inode, loff_t offset, int bytes,
+ pid_t pid, char *pathname, char *command),
+ TP_ARGS(inode, offset, bytes, pid, pathname, command));
+
+DEFINE_EVENT(android_fs_data_end_template, android_fs_datawrite_end,
+ TP_PROTO(struct inode *inode, loff_t offset, int bytes),
+ TP_ARGS(inode, offset, bytes));
+
+#endif /* _TRACE_ANDROID_FS_H */
+
+/* This part must be outside protection */
+#include <trace/define_trace.h>
+
+#ifndef ANDROID_FSTRACE_GET_PATHNAME
+#define ANDROID_FSTRACE_GET_PATHNAME
+
+/* Sizes an on-stack array, so careful if sizing this up ! */
+#define MAX_TRACE_PATHBUF_LEN 256
+
+static inline char *
+android_fstrace_get_pathname(char *buf, int buflen, struct inode *inode)
+{
+ char *path;
+ struct dentry *d;
+
+ /*
+ * d_obtain_alias() will either iput() if it locates an existing
+ * dentry or transfer the reference to the new dentry created.
+ * So get an extra reference here.
+ */
+ ihold(inode);
+ d = d_obtain_alias(inode);
+ if (likely(!IS_ERR(d))) {
+ path = dentry_path_raw(d, buf, buflen);
+ if (unlikely(IS_ERR(path))) {
+ strcpy(buf, "ERROR");
+ path = buf;
+ }
+ dput(d);
+ } else {
+ strcpy(buf, "ERROR");
+ path = buf;
+ }
+ return path;
+}
+#endif
diff --git a/include/trace/events/android_fs_template.h b/include/trace/events/android_fs_template.h
new file mode 100644
index 000000000000..4e61ffe7a814
--- /dev/null
+++ b/include/trace/events/android_fs_template.h
@@ -0,0 +1,57 @@
+#if !defined(_TRACE_ANDROID_FS_TEMPLATE_H) || defined(TRACE_HEADER_MULTI_READ)
+#define _TRACE_ANDROID_FS_TEMPLATE_H
+
+#include <linux/tracepoint.h>
+
+DECLARE_EVENT_CLASS(android_fs_data_start_template,
+ TP_PROTO(struct inode *inode, loff_t offset, int bytes,
+ pid_t pid, char *pathname, char *command),
+ TP_ARGS(inode, offset, bytes, pid, pathname, command),
+ TP_STRUCT__entry(
+ __string(pathbuf, pathname);
+ __field(loff_t, offset);
+ __field(int, bytes);
+ __field(loff_t, i_size);
+ __string(cmdline, command);
+ __field(pid_t, pid);
+ __field(ino_t, ino);
+ ),
+ TP_fast_assign(
+ {
+ __assign_str(pathbuf, pathname);
+ __entry->offset = offset;
+ __entry->bytes = bytes;
+ __entry->i_size = i_size_read(inode);
+ __assign_str(cmdline, command);
+ __entry->pid = pid;
+ __entry->ino = inode->i_ino;
+ }
+ ),
+ TP_printk("entry_name %s, offset %llu, bytes %d, cmdline %s,"
+ " pid %d, i_size %llu, ino %lu",
+ __get_str(pathbuf), __entry->offset, __entry->bytes,
+ __get_str(cmdline), __entry->pid, __entry->i_size,
+ (unsigned long) __entry->ino)
+);
+
+DECLARE_EVENT_CLASS(android_fs_data_end_template,
+ TP_PROTO(struct inode *inode, loff_t offset, int bytes),
+ TP_ARGS(inode, offset, bytes),
+ TP_STRUCT__entry(
+ __field(ino_t, ino);
+ __field(loff_t, offset);
+ __field(int, bytes);
+ ),
+ TP_fast_assign(
+ {
+ __entry->ino = inode->i_ino;
+ __entry->offset = offset;
+ __entry->bytes = bytes;
+ }
+ ),
+ TP_printk("ino %lu, offset %llu, bytes %d",
+ (unsigned long) __entry->ino,
+ __entry->offset, __entry->bytes)
+);
+
+#endif /* _TRACE_ANDROID_FS_TEMPLATE_H */
diff --git a/include/uapi/drm/drm_mode.h b/include/uapi/drm/drm_mode.h
index 09c22caf34dd..1c5e74f1ea39 100644
--- a/include/uapi/drm/drm_mode.h
+++ b/include/uapi/drm/drm_mode.h
@@ -73,7 +73,8 @@
#define DRM_MODE_FLAG_3D_TOP_AND_BOTTOM (7<<14)
#define DRM_MODE_FLAG_3D_SIDE_BY_SIDE_HALF (8<<14)
#define DRM_MODE_FLAG_SEAMLESS (1<<19)
-
+#define DRM_MODE_FLAG_SUPPORTS_RGB (1<<20)
+#define DRM_MODE_FLAG_SUPPORTS_YUV (1<<21)
/* DPMS flags */
/* bit compatible with the xorg definitions. */
diff --git a/include/uapi/linux/hbtp_input.h b/include/uapi/linux/hbtp_input.h
index 9173c2ab72ed..3b124ffcdcf3 100644
--- a/include/uapi/linux/hbtp_input.h
+++ b/include/uapi/linux/hbtp_input.h
@@ -6,6 +6,8 @@
#define HBTP_MAX_FINGER 20
#define HBTP_ABS_MT_FIRST ABS_MT_TOUCH_MAJOR
#define HBTP_ABS_MT_LAST ABS_MT_TOOL_Y
+#define MAX_ROI_SIZE 144
+#define MAX_ACCEL_SIZE 128
#define HBTP_EVENT_TYPE_DISPLAY "EVENT_TYPE=HBTP_DISPLAY"
@@ -20,6 +22,11 @@ struct hbtp_input_touch {
__s32 orientation;
};
+struct hbtp_sensor_data {
+ __s16 accelBuffer[MAX_ACCEL_SIZE];
+ __s16 ROI[MAX_ROI_SIZE];
+};
+
struct hbtp_input_mt {
__s32 num_touches;
struct hbtp_input_touch touches[HBTP_MAX_FINGER];
@@ -68,6 +75,8 @@ enum hbtp_afe_power_ctrl {
enum hbtp_afe_signal)
#define HBTP_SET_POWER_CTRL _IOW(HBTP_INPUT_IOCTL_BASE, 206, \
enum hbtp_afe_power_ctrl)
+#define HBTP_SET_SENSORDATA _IOW(HBTP_INPUT_IOCTL_BASE, 207, \
+ struct hbtp_sensor_data)
#endif /* _UAPI_HBTP_INPUT_H */
diff --git a/include/uapi/linux/nl80211.h b/include/uapi/linux/nl80211.h
index 8a5c59a9ff0e..960aa84e3b61 100644
--- a/include/uapi/linux/nl80211.h
+++ b/include/uapi/linux/nl80211.h
@@ -1637,8 +1637,16 @@ enum nl80211_commands {
* the connection request from a station. nl80211_connect_failed_reason
* enum has different reasons of connection failure.
*
- * @NL80211_ATTR_SAE_DATA: SAE elements in Authentication frames. This starts
- * with the Authentication transaction sequence number field.
+ * @NL80211_ATTR_AUTH_DATA: Fields and elements in Authentication frames.
+ * This contains the authentication frame body (non-IE and IE data),
+ * excluding the Authentication algorithm number, i.e., starting at the
+ * Authentication transaction sequence number field. It is used with
+ * authentication algorithms that need special fields to be added into
+ * the frames (SAE and FILS). Currently, only the SAE cases use the
+ * initial two fields (Authentication transaction sequence number and
+ * Status code). However, those fields are included in the attribute data
+ * for all authentication algorithms to keep the attribute definition
+ * consistent.
*
* @NL80211_ATTR_VHT_CAPABILITY: VHT Capability information element (from
* association request when used with NL80211_CMD_NEW_STATION)
@@ -2215,7 +2223,7 @@ enum nl80211_attrs {
NL80211_ATTR_CONN_FAILED_REASON,
- NL80211_ATTR_SAE_DATA,
+ NL80211_ATTR_AUTH_DATA,
NL80211_ATTR_VHT_CAPABILITY,
@@ -2379,6 +2387,7 @@ enum nl80211_attrs {
#define NL80211_ATTR_SCAN_GENERATION NL80211_ATTR_GENERATION
#define NL80211_ATTR_MESH_PARAMS NL80211_ATTR_MESH_CONFIG
#define NL80211_ATTR_IFACE_SOCKET_OWNER NL80211_ATTR_SOCKET_OWNER
+#define NL80211_ATTR_SAE_DATA NL80211_ATTR_AUTH_DATA
/*
* Allow user space programs to use #ifdef on new attributes by defining them
@@ -3666,6 +3675,9 @@ enum nl80211_bss_status {
* @NL80211_AUTHTYPE_FT: Fast BSS Transition (IEEE 802.11r)
* @NL80211_AUTHTYPE_NETWORK_EAP: Network EAP (some Cisco APs and mainly LEAP)
* @NL80211_AUTHTYPE_SAE: Simultaneous authentication of equals
+ * @NL80211_AUTHTYPE_FILS_SK: Fast Initial Link Setup shared key
+ * @NL80211_AUTHTYPE_FILS_SK_PFS: Fast Initial Link Setup shared key with PFS
+ * @NL80211_AUTHTYPE_FILS_PK: Fast Initial Link Setup public key
* @__NL80211_AUTHTYPE_NUM: internal
* @NL80211_AUTHTYPE_MAX: maximum valid auth algorithm
* @NL80211_AUTHTYPE_AUTOMATIC: determine automatically (if necessary by
@@ -3678,6 +3690,9 @@ enum nl80211_auth_type {
NL80211_AUTHTYPE_FT,
NL80211_AUTHTYPE_NETWORK_EAP,
NL80211_AUTHTYPE_SAE,
+ NL80211_AUTHTYPE_FILS_SK,
+ NL80211_AUTHTYPE_FILS_SK_PFS,
+ NL80211_AUTHTYPE_FILS_PK,
/* keep last */
__NL80211_AUTHTYPE_NUM,
diff --git a/include/uapi/linux/usb/audio.h b/include/uapi/linux/usb/audio.h
index d2314be4f0c0..c6f5b096c594 100644
--- a/include/uapi/linux/usb/audio.h
+++ b/include/uapi/linux/usb/audio.h
@@ -26,6 +26,7 @@
/* bInterfaceProtocol values to denote the version of the standard used */
#define UAC_VERSION_1 0x00
#define UAC_VERSION_2 0x20
+#define UAC_VERSION_3 0x30
/* A.2 Audio Interface Subclass Codes */
#define USB_SUBCLASS_AUDIOCONTROL 0x01
diff --git a/include/uapi/media/msm_camsensor_sdk.h b/include/uapi/media/msm_camsensor_sdk.h
index ad0825e33217..83927c614e91 100644
--- a/include/uapi/media/msm_camsensor_sdk.h
+++ b/include/uapi/media/msm_camsensor_sdk.h
@@ -48,6 +48,8 @@
#define MSM_EEPROM_MEMORY_MAP_MAX_SIZE 80
#define MSM_EEPROM_MAX_MEM_MAP_CNT 8
+#define MSM_SENSOR_BYPASS_VIDEO_NODE 1
+
enum msm_sensor_camera_id_t {
CAMERA_0,
CAMERA_1,
@@ -300,6 +302,7 @@ struct msm_camera_sensor_slave_info {
unsigned char is_init_params_valid;
struct msm_sensor_init_params sensor_init_params;
enum msm_sensor_output_format_t output_format;
+ uint8_t bypass_video_node_creation;
};
struct msm_camera_i2c_reg_array {
diff --git a/include/uapi/media/msmb_ispif.h b/include/uapi/media/msmb_ispif.h
index 3720056aa28d..c3a6e006b2ff 100644
--- a/include/uapi/media/msmb_ispif.h
+++ b/include/uapi/media/msmb_ispif.h
@@ -36,7 +36,6 @@ enum msm_ispif_intftype {
#define RDI1_MASK (1 << RDI1)
#define RDI2_MASK (1 << RDI2)
-
enum msm_ispif_vc {
VC0,
VC1,
@@ -102,10 +101,17 @@ struct msm_ispif_params_entry {
uint16_t crop_end_pixel;
};
+struct msm_ispif_right_param_entry {
+ enum msm_ispif_cid cids[MAX_CID_CH_PARAM_ENTRY];
+ enum msm_ispif_csid csid;
+};
+
struct msm_ispif_param_data_ext {
uint32_t num;
struct msm_ispif_params_entry entries[MAX_PARAM_ENTRIES];
struct msm_ispif_pack_cfg pack_cfg[CID_MAX];
+ struct msm_ispif_right_param_entry right_entries[MAX_PARAM_ENTRIES];
+ uint32_t stereo_enable;
};
struct msm_ispif_param_data {
@@ -157,6 +163,8 @@ struct ispif_cfg_data_ext {
#define ISPIF_RDI_PACK_MODE_SUPPORT 1
+#define ISPIF_3D_SUPPORT 1
+
#define VIDIOC_MSM_ISPIF_CFG \
_IOWR('V', BASE_VIDIOC_PRIVATE, struct ispif_cfg_data)
diff --git a/kernel/cpu.c b/kernel/cpu.c
index 8b6940755e4a..e822cb0e18d5 100644
--- a/kernel/cpu.c
+++ b/kernel/cpu.c
@@ -530,9 +530,41 @@ out:
return ret;
}
+static int switch_to_rt_policy(void)
+{
+ struct sched_param param = { .sched_priority = MAX_RT_PRIO - 1 };
+ unsigned int policy = current->policy;
+ int err;
+
+ /* Nobody should be attempting hotplug from these policy contexts. */
+ if (policy == SCHED_BATCH || policy == SCHED_IDLE ||
+ policy == SCHED_DEADLINE)
+ return -EPERM;
+
+ if (policy == SCHED_FIFO || policy == SCHED_RR)
+ return 1;
+
+ /* Only SCHED_NORMAL left. */
+ err = sched_setscheduler_nocheck(current, SCHED_FIFO, &param);
+ return err;
+
+}
+
+static int switch_to_fair_policy(void)
+{
+ struct sched_param param = { .sched_priority = 0 };
+
+ return sched_setscheduler_nocheck(current, SCHED_NORMAL, &param);
+}
+
int cpu_up(unsigned int cpu)
{
int err = 0;
+ int switch_err = 0;
+
+ switch_err = switch_to_rt_policy();
+ if (switch_err < 0)
+ return switch_err;
if (!cpu_possible(cpu)) {
pr_err("can't online cpu %d because it is not configured as may-hotadd at boot time\n",
@@ -558,6 +590,14 @@ int cpu_up(unsigned int cpu)
out:
cpu_maps_update_done();
+
+ if (!switch_err) {
+ switch_err = switch_to_fair_policy();
+ if (switch_err)
+ pr_err("Hotplug policy switch err=%d Task %s pid=%d\n",
+ switch_err, current->comm, current->pid);
+ }
+
return err;
}
EXPORT_SYMBOL_GPL(cpu_up);
diff --git a/kernel/power/hibernate.c b/kernel/power/hibernate.c
index 3124cebaec31..2fc1177383a0 100644
--- a/kernel/power/hibernate.c
+++ b/kernel/power/hibernate.c
@@ -1159,6 +1159,22 @@ static int __init kaslr_nohibernate_setup(char *str)
return nohibernate_setup(str);
}
+static int __init page_poison_nohibernate_setup(char *str)
+{
+#ifdef CONFIG_PAGE_POISONING_ZERO
+ /*
+ * The zeroing option for page poison skips the checks on alloc.
+ * since hibernation doesn't save free pages there's no way to
+ * guarantee the pages will still be zeroed.
+ */
+ if (!strcmp(str, "on")) {
+ pr_info("Disabling hibernation due to page poisoning\n");
+ return nohibernate_setup(str);
+ }
+#endif
+ return 1;
+}
+
__setup("noresume", noresume_setup);
__setup("resume_offset=", resume_offset_setup);
__setup("resume=", resume_setup);
@@ -1167,3 +1183,4 @@ __setup("resumewait", resumewait_setup);
__setup("resumedelay=", resumedelay_setup);
__setup("nohibernate", nohibernate_setup);
__setup("kaslr", kaslr_nohibernate_setup);
+__setup("page_poison=", page_poison_nohibernate_setup);
diff --git a/kernel/sched/core.c b/kernel/sched/core.c
index 1017a3f77391..e107c4d6b385 100644
--- a/kernel/sched/core.c
+++ b/kernel/sched/core.c
@@ -3364,6 +3364,9 @@ NOKPROBE_SYMBOL(preempt_count_sub);
*/
static noinline void __schedule_bug(struct task_struct *prev)
{
+ /* Save this before calling printk(), since that will clobber it */
+ unsigned long preempt_disable_ip = get_preempt_disable_ip(current);
+
if (oops_in_progress)
return;
@@ -3374,13 +3377,12 @@ static noinline void __schedule_bug(struct task_struct *prev)
print_modules();
if (irqs_disabled())
print_irqtrace_events(prev);
-#ifdef CONFIG_DEBUG_PREEMPT
- if (in_atomic_preempt_off()) {
+ if (IS_ENABLED(CONFIG_DEBUG_PREEMPT)
+ && in_atomic_preempt_off()) {
pr_err("Preemption disabled at:");
- print_ip_sym(current->preempt_disable_ip);
+ print_ip_sym(preempt_disable_ip);
pr_cont("\n");
}
-#endif
#ifdef CONFIG_PANIC_ON_SCHED_BUG
BUG();
#endif
@@ -8513,6 +8515,7 @@ EXPORT_SYMBOL(__might_sleep);
void ___might_sleep(const char *file, int line, int preempt_offset)
{
static unsigned long prev_jiffy; /* ratelimiting */
+ unsigned long preempt_disable_ip;
rcu_sleep_check(); /* WARN_ON_ONCE() by default, no rate limit reqd. */
if ((preempt_count_equals(preempt_offset) && !irqs_disabled() &&
@@ -8525,6 +8528,9 @@ void ___might_sleep(const char *file, int line, int preempt_offset)
return;
prev_jiffy = jiffies;
+ /* Save this before calling printk(), since that will clobber it */
+ preempt_disable_ip = get_preempt_disable_ip(current);
+
printk(KERN_ERR
"BUG: sleeping function called from invalid context at %s:%d\n",
file, line);
@@ -8539,13 +8545,12 @@ void ___might_sleep(const char *file, int line, int preempt_offset)
debug_show_held_locks(current);
if (irqs_disabled())
print_irqtrace_events(current);
-#ifdef CONFIG_DEBUG_PREEMPT
- if (!preempt_count_equals(preempt_offset)) {
+ if (IS_ENABLED(CONFIG_DEBUG_PREEMPT)
+ && !preempt_count_equals(preempt_offset)) {
pr_err("Preemption disabled at:");
- print_ip_sym(current->preempt_disable_ip);
+ print_ip_sym(preempt_disable_ip);
pr_cont("\n");
}
-#endif
#ifdef CONFIG_PANIC_ON_SCHED_BUG
BUG();
#endif
diff --git a/kernel/sched/core_ctl.c b/kernel/sched/core_ctl.c
index 1dde338d30f2..0b5f2dea18a1 100644
--- a/kernel/sched/core_ctl.c
+++ b/kernel/sched/core_ctl.c
@@ -35,6 +35,7 @@ struct cluster_data {
unsigned int busy_down_thres[MAX_CPUS_PER_CLUSTER];
unsigned int active_cpus;
unsigned int num_cpus;
+ unsigned int nr_isolated_cpus;
cpumask_t cpu_mask;
unsigned int need_cpus;
unsigned int task_thres;
@@ -260,6 +261,7 @@ static ssize_t show_global_state(const struct cluster_data *state, char *buf)
ssize_t count = 0;
unsigned int cpu;
+ spin_lock_irq(&state_lock);
for_each_possible_cpu(cpu) {
c = &per_cpu(cpu_state, cpu);
cluster = c->cluster;
@@ -293,8 +295,12 @@ static ssize_t show_global_state(const struct cluster_data *state, char *buf)
count += snprintf(buf + count, PAGE_SIZE - count,
"\tNeed CPUs: %u\n", cluster->need_cpus);
count += snprintf(buf + count, PAGE_SIZE - count,
+ "\tNr isolated CPUs: %u\n",
+ cluster->nr_isolated_cpus);
+ count += snprintf(buf + count, PAGE_SIZE - count,
"\tBoost: %u\n", (unsigned int) cluster->boost);
}
+ spin_unlock_irq(&state_lock);
return count;
}
@@ -525,7 +531,7 @@ static bool adjustment_possible(const struct cluster_data *cluster,
unsigned int need)
{
return (need < cluster->active_cpus || (need > cluster->active_cpus &&
- sched_isolate_count(&cluster->cpu_mask, false)));
+ cluster->nr_isolated_cpus));
}
static bool eval_need(struct cluster_data *cluster)
@@ -535,9 +541,8 @@ static bool eval_need(struct cluster_data *cluster)
unsigned int need_cpus = 0, last_need, thres_idx;
int ret = 0;
bool need_flag = false;
- unsigned int active_cpus;
unsigned int new_need;
- s64 now;
+ s64 now, elapsed;
if (unlikely(!cluster->inited))
return 0;
@@ -547,8 +552,8 @@ static bool eval_need(struct cluster_data *cluster)
if (cluster->boost) {
need_cpus = cluster->max_cpus;
} else {
- active_cpus = get_active_cpu_count(cluster);
- thres_idx = active_cpus ? active_cpus - 1 : 0;
+ cluster->active_cpus = get_active_cpu_count(cluster);
+ thres_idx = cluster->active_cpus ? cluster->active_cpus - 1 : 0;
list_for_each_entry(c, &cluster->lru, sib) {
if (c->busy >= cluster->busy_up_thres[thres_idx])
c->is_busy = true;
@@ -564,17 +569,16 @@ static bool eval_need(struct cluster_data *cluster)
last_need = cluster->need_cpus;
now = ktime_to_ms(ktime_get());
- if (new_need == last_need) {
- cluster->need_ts = now;
- spin_unlock_irqrestore(&state_lock, flags);
- return 0;
- }
-
- if (need_cpus > cluster->active_cpus) {
+ if (new_need > cluster->active_cpus) {
ret = 1;
- } else if (need_cpus < cluster->active_cpus) {
- s64 elapsed = now - cluster->need_ts;
+ } else {
+ if (new_need == last_need) {
+ cluster->need_ts = now;
+ spin_unlock_irqrestore(&state_lock, flags);
+ return 0;
+ }
+ elapsed = now - cluster->need_ts;
ret = elapsed >= cluster->offline_delay_ms;
}
@@ -582,7 +586,7 @@ static bool eval_need(struct cluster_data *cluster)
cluster->need_ts = now;
cluster->need_cpus = new_need;
}
- trace_core_ctl_eval_need(cluster->first_cpu, last_need, need_cpus,
+ trace_core_ctl_eval_need(cluster->first_cpu, last_need, new_need,
ret && need_flag);
spin_unlock_irqrestore(&state_lock, flags);
@@ -718,6 +722,7 @@ static void try_to_isolate(struct cluster_data *cluster, unsigned int need)
struct cpu_data *c, *tmp;
unsigned long flags;
unsigned int num_cpus = cluster->num_cpus;
+ unsigned int nr_isolated = 0;
/*
* Protect against entry being removed (and added at tail) by other
@@ -742,12 +747,14 @@ static void try_to_isolate(struct cluster_data *cluster, unsigned int need)
if (!sched_isolate_cpu(c->cpu)) {
c->isolated_by_us = true;
move_cpu_lru(c);
+ nr_isolated++;
} else {
pr_debug("Unable to isolate CPU%u\n", c->cpu);
}
cluster->active_cpus = get_active_cpu_count(cluster);
spin_lock_irqsave(&state_lock, flags);
}
+ cluster->nr_isolated_cpus += nr_isolated;
spin_unlock_irqrestore(&state_lock, flags);
/*
@@ -757,6 +764,7 @@ static void try_to_isolate(struct cluster_data *cluster, unsigned int need)
if (cluster->active_cpus <= cluster->max_cpus)
return;
+ nr_isolated = 0;
num_cpus = cluster->num_cpus;
spin_lock_irqsave(&state_lock, flags);
list_for_each_entry_safe(c, tmp, &cluster->lru, sib) {
@@ -774,12 +782,14 @@ static void try_to_isolate(struct cluster_data *cluster, unsigned int need)
if (!sched_isolate_cpu(c->cpu)) {
c->isolated_by_us = true;
move_cpu_lru(c);
+ nr_isolated++;
} else {
pr_debug("Unable to isolate CPU%u\n", c->cpu);
}
cluster->active_cpus = get_active_cpu_count(cluster);
spin_lock_irqsave(&state_lock, flags);
}
+ cluster->nr_isolated_cpus += nr_isolated;
spin_unlock_irqrestore(&state_lock, flags);
}
@@ -790,6 +800,7 @@ static void __try_to_unisolate(struct cluster_data *cluster,
struct cpu_data *c, *tmp;
unsigned long flags;
unsigned int num_cpus = cluster->num_cpus;
+ unsigned int nr_unisolated = 0;
/*
* Protect against entry being removed (and added at tail) by other
@@ -814,12 +825,14 @@ static void __try_to_unisolate(struct cluster_data *cluster,
if (!sched_unisolate_cpu(c->cpu)) {
c->isolated_by_us = false;
move_cpu_lru(c);
+ nr_unisolated++;
} else {
pr_debug("Unable to unisolate CPU%u\n", c->cpu);
}
cluster->active_cpus = get_active_cpu_count(cluster);
spin_lock_irqsave(&state_lock, flags);
}
+ cluster->nr_isolated_cpus -= nr_unisolated;
spin_unlock_irqrestore(&state_lock, flags);
}
@@ -885,10 +898,11 @@ static int __ref cpu_callback(struct notifier_block *nfb,
struct cpu_data *state = &per_cpu(cpu_state, cpu);
struct cluster_data *cluster = state->cluster;
unsigned int need;
- int ret = NOTIFY_OK;
+ bool do_wakeup, unisolated = false;
+ unsigned long flags;
if (unlikely(!cluster || !cluster->inited))
- return NOTIFY_OK;
+ return NOTIFY_DONE;
switch (action & ~CPU_TASKS_FROZEN) {
case CPU_ONLINE:
@@ -911,6 +925,7 @@ static int __ref cpu_callback(struct notifier_block *nfb,
if (state->isolated_by_us) {
sched_unisolate_cpu_unlocked(cpu);
state->isolated_by_us = false;
+ unisolated = true;
}
/* Move a CPU to the end of the LRU when it goes offline. */
@@ -919,13 +934,20 @@ static int __ref cpu_callback(struct notifier_block *nfb,
state->busy = 0;
cluster->active_cpus = get_active_cpu_count(cluster);
break;
+ default:
+ return NOTIFY_DONE;
}
need = apply_limits(cluster, cluster->need_cpus);
- if (adjustment_possible(cluster, need))
+ spin_lock_irqsave(&state_lock, flags);
+ if (unisolated)
+ cluster->nr_isolated_cpus--;
+ do_wakeup = adjustment_possible(cluster, need);
+ spin_unlock_irqrestore(&state_lock, flags);
+ if (do_wakeup)
wake_up_core_ctl_thread(cluster);
- return ret;
+ return NOTIFY_OK;
}
static struct notifier_block __refdata cpu_notifier = {
diff --git a/kernel/trace/trace.c b/kernel/trace/trace.c
index 66d9e907aa07..c0c10a335b3b 100644
--- a/kernel/trace/trace.c
+++ b/kernel/trace/trace.c
@@ -1634,7 +1634,7 @@ static void __trace_find_cmdline(int pid, char comm[])
map = savedcmd->map_pid_to_cmdline[pid];
if (map != NO_CMDLINE_MAP)
- strcpy(comm, get_saved_cmdlines(map));
+ strlcpy(comm, get_saved_cmdlines(map), TASK_COMM_LEN - 1);
else
strcpy(comm, "<...>");
}
diff --git a/kernel/watchdog.c b/kernel/watchdog.c
index 1de2ef8ec926..f527d8e65d69 100644
--- a/kernel/watchdog.c
+++ b/kernel/watchdog.c
@@ -123,9 +123,7 @@ static unsigned long soft_lockup_nmi_warn;
#ifdef CONFIG_HARDLOCKUP_DETECTOR
unsigned int __read_mostly hardlockup_panic =
CONFIG_BOOTPARAM_HARDLOCKUP_PANIC_VALUE;
-#ifdef CONFIG_HARDLOCKUP_DETECTOR_NMI
static unsigned long __maybe_unused hardlockup_allcpu_dumped;
-#endif
/*
* We may not want to enable hard lockup detection by default in all cases,
* for example when running the kernel as a guest on a hypervisor. In these
diff --git a/mm/Kconfig.debug b/mm/Kconfig.debug
index 9e55d6b141aa..7470fd60fc59 100644
--- a/mm/Kconfig.debug
+++ b/mm/Kconfig.debug
@@ -40,9 +40,6 @@ config DEBUG_PAGEALLOC_ENABLE_DEFAULT
Enable debug page memory allocations by default? This value
can be overridden by debug_pagealloc=off|on.
-config PAGE_POISONING
- bool
-
config SLUB_DEBUG_PANIC_ON
bool "Enable to Panic on SLUB corruption detection"
depends on SLUB_DEBUG
@@ -52,3 +49,53 @@ config SLUB_DEBUG_PANIC_ON
debug options this may not be desirable as it prevents from
investigating the root cause which may be rooted within cache
or memory.
+
+config PAGE_POISONING
+ bool "Poison pages after freeing"
+ select PAGE_EXTENSION
+ select PAGE_POISONING_NO_SANITY if HIBERNATION
+ ---help---
+ Fill the pages with poison patterns after free_pages() and verify
+ the patterns before alloc_pages. The filling of the memory helps
+ reduce the risk of information leaks from freed data. This does
+ have a potential performance impact.
+
+ Note that "poison" here is not the same thing as the "HWPoison"
+ for CONFIG_MEMORY_FAILURE. This is software poisoning only.
+
+ If unsure, say N
+
+config PAGE_POISONING_ENABLE_DEFAULT
+ bool "Enable page poisoning by default?"
+ default n
+ depends on PAGE_POISONING
+ ---help---
+ Enable page poisoning of free pages by default? This value
+ can be overridden by page_poison=off|on. This can be used
+ to avoid passing the kernel parameter and let page poisoning
+ feature enabled by default.
+
+config PAGE_POISONING_NO_SANITY
+ depends on PAGE_POISONING
+ bool "Only poison, don't sanity check"
+ ---help---
+ Skip the sanity checking on alloc, only fill the pages with
+ poison on free. This reduces some of the overhead of the
+ poisoning feature.
+
+ If you are only interested in sanitization, say Y. Otherwise
+ say N.
+
+config PAGE_POISONING_ZERO
+ bool "Use zero for poisoning instead of random data"
+ depends on PAGE_POISONING
+ ---help---
+ Instead of using the existing poison value, fill the pages with
+ zeros. This makes it harder to detect when errors are occurring
+ due to sanitization but the zeroing at free means that it is
+ no longer necessary to write zeros when GFP_ZERO is used on
+ allocation.
+
+ Enabling page poisoning with this option will disable hibernation
+
+ If unsure, say N
diff --git a/mm/Makefile b/mm/Makefile
index 4b1a69abce7a..130d06ac56e0 100644
--- a/mm/Makefile
+++ b/mm/Makefile
@@ -52,7 +52,7 @@ obj-$(CONFIG_SPARSEMEM_VMEMMAP) += sparse-vmemmap.o
obj-$(CONFIG_SLOB) += slob.o
obj-$(CONFIG_MMU_NOTIFIER) += mmu_notifier.o
obj-$(CONFIG_KSM) += ksm.o
-obj-$(CONFIG_PAGE_POISONING) += debug-pagealloc.o
+obj-$(CONFIG_PAGE_POISONING) += page_poison.o
obj-$(CONFIG_SLAB) += slab.o
obj-$(CONFIG_SLUB) += slub.o
obj-$(CONFIG_KMEMCHECK) += kmemcheck.o
diff --git a/mm/page_alloc.c b/mm/page_alloc.c
index 28f60d9ea074..170c1486e5c9 100644
--- a/mm/page_alloc.c
+++ b/mm/page_alloc.c
@@ -1012,6 +1012,7 @@ static bool free_pages_prepare(struct page *page, unsigned int order)
PAGE_SIZE << order);
}
arch_free_page(page, order);
+ kernel_poison_pages(page, 1 << order, 0);
kernel_map_pages(page, 1 << order, 0);
kasan_free_pages(page, order);
@@ -1396,6 +1397,12 @@ static inline int check_new_page(struct page *page)
return 0;
}
+static inline bool free_pages_prezeroed(void)
+{
+ return IS_ENABLED(CONFIG_PAGE_POISONING_ZERO) &&
+ page_poisoning_enabled();
+}
+
static int prep_new_page(struct page *page, unsigned int order, gfp_t gfp_flags,
int alloc_flags)
{
@@ -1413,8 +1420,9 @@ static int prep_new_page(struct page *page, unsigned int order, gfp_t gfp_flags,
kasan_alloc_pages(page, order);
arch_alloc_page(page, order);
kernel_map_pages(page, 1 << order, 1);
+ kernel_poison_pages(page, 1 << order, 1);
- if (gfp_flags & __GFP_ZERO)
+ if (!free_pages_prezeroed() && (gfp_flags & __GFP_ZERO))
for (i = 0; i < (1 << order); i++)
clear_highpage(page + i);
diff --git a/mm/page_ext.c b/mm/page_ext.c
index 292ca7b8debd..916accfec86a 100644
--- a/mm/page_ext.c
+++ b/mm/page_ext.c
@@ -54,9 +54,6 @@
static struct page_ext_operations *page_ext_ops[] = {
&debug_guardpage_ops,
-#ifdef CONFIG_PAGE_POISONING
- &page_poisoning_ops,
-#endif
#ifdef CONFIG_PAGE_OWNER
&page_owner_ops,
#endif
@@ -106,12 +103,15 @@ struct page_ext *lookup_page_ext(struct page *page)
struct page_ext *base;
base = NODE_DATA(page_to_nid(page))->node_page_ext;
-#ifdef CONFIG_DEBUG_VM
+#if defined(CONFIG_DEBUG_VM) || defined(CONFIG_PAGE_POISONING)
/*
* The sanity checks the page allocator does upon freeing a
* page can reach here before the page_ext arrays are
* allocated when feeding a range of pages to the allocator
* for the first time during bootup or memory hotplug.
+ *
+ * This check is also necessary for ensuring page poisoning
+ * works as expected when enabled
*/
if (unlikely(!base))
return NULL;
@@ -180,12 +180,15 @@ struct page_ext *lookup_page_ext(struct page *page)
{
unsigned long pfn = page_to_pfn(page);
struct mem_section *section = __pfn_to_section(pfn);
-#ifdef CONFIG_DEBUG_VM
+#if defined(CONFIG_DEBUG_VM) || defined(CONFIG_PAGE_POISONING)
/*
* The sanity checks the page allocator does upon freeing a
* page can reach here before the page_ext arrays are
* allocated when feeding a range of pages to the allocator
* for the first time during bootup or memory hotplug.
+ *
+ * This check is also necessary for ensuring page poisoning
+ * works as expected when enabled
*/
if (!section->page_ext)
return NULL;
diff --git a/mm/debug-pagealloc.c b/mm/page_poison.c
index 100963091cc6..c8cf230dbfcb 100644
--- a/mm/debug-pagealloc.c
+++ b/mm/page_poison.c
@@ -6,68 +6,41 @@
#include <linux/poison.h>
#include <linux/ratelimit.h>
-#ifndef mark_addr_rdonly
-#define mark_addr_rdonly(a)
-#endif
-
-#ifndef mark_addr_rdwrite
-#define mark_addr_rdwrite(a)
-#endif
-
-static bool page_poisoning_enabled __read_mostly;
-
-static bool need_page_poisoning(void)
-{
- if (!debug_pagealloc_enabled())
- return false;
-
- return true;
-}
-
-static void init_page_poisoning(void)
-{
- if (!debug_pagealloc_enabled())
- return;
-
- page_poisoning_enabled = true;
-}
-
-struct page_ext_operations page_poisoning_ops = {
- .need = need_page_poisoning,
- .init = init_page_poisoning,
-};
+static bool want_page_poisoning __read_mostly
+ = IS_ENABLED(CONFIG_PAGE_POISONING_ENABLE_DEFAULT);
-static inline void set_page_poison(struct page *page)
+static int early_page_poison_param(char *buf)
{
- struct page_ext *page_ext;
+ if (!buf)
+ return -EINVAL;
- page_ext = lookup_page_ext(page);
- __set_bit(PAGE_EXT_DEBUG_POISON, &page_ext->flags);
-}
-
-static inline void clear_page_poison(struct page *page)
-{
- struct page_ext *page_ext;
+ if (strcmp(buf, "on") == 0)
+ want_page_poisoning = true;
+ else if (strcmp(buf, "off") == 0)
+ want_page_poisoning = false;
- page_ext = lookup_page_ext(page);
- __clear_bit(PAGE_EXT_DEBUG_POISON, &page_ext->flags);
+ return 0;
}
+early_param("page_poison", early_page_poison_param);
-static inline bool page_poison(struct page *page)
+bool page_poisoning_enabled(void)
{
- struct page_ext *page_ext;
-
- page_ext = lookup_page_ext(page);
- return test_bit(PAGE_EXT_DEBUG_POISON, &page_ext->flags);
+ /*
+ * Assumes that debug_pagealloc_enabled is set before
+ * free_all_bootmem.
+ * Page poisoning is debug page alloc for some arches. If
+ * either of those options are enabled, enable poisoning.
+ */
+ return (want_page_poisoning ||
+ (!IS_ENABLED(CONFIG_ARCH_SUPPORTS_DEBUG_PAGEALLOC) &&
+ debug_pagealloc_enabled()));
}
static void poison_page(struct page *page)
{
void *addr = kmap_atomic(page);
- set_page_poison(page);
memset(addr, PAGE_POISON, PAGE_SIZE);
- mark_addr_rdonly(addr);
kunmap_atomic(addr);
}
@@ -93,6 +66,9 @@ static void check_poison_mem(struct page *page,
unsigned char *start;
unsigned char *end;
+ if (IS_ENABLED(CONFIG_PAGE_POISONING_NO_SANITY))
+ return;
+
start = memchr_inv(mem, PAGE_POISON, bytes);
if (!start)
return;
@@ -121,13 +97,13 @@ static void unpoison_page(struct page *page)
{
void *addr;
- if (!page_poison(page))
- return;
-
addr = kmap_atomic(page);
+ /*
+ * Page poisoning when enabled poisons each and every page
+ * that is freed to buddy. Thus no extra check is done to
+ * see if a page was posioned.
+ */
check_poison_mem(page, addr, PAGE_SIZE);
- mark_addr_rdwrite(addr);
- clear_page_poison(page);
kunmap_atomic(addr);
}
@@ -139,9 +115,9 @@ static void unpoison_pages(struct page *page, int n)
unpoison_page(page + i);
}
-void __kernel_map_pages(struct page *page, int numpages, int enable)
+void kernel_poison_pages(struct page *page, int numpages, int enable)
{
- if (!page_poisoning_enabled)
+ if (!page_poisoning_enabled())
return;
if (enable)
@@ -149,3 +125,10 @@ void __kernel_map_pages(struct page *page, int numpages, int enable)
else
poison_pages(page, numpages);
}
+
+#ifndef CONFIG_ARCH_SUPPORTS_DEBUG_PAGEALLOC
+void __kernel_map_pages(struct page *page, int numpages, int enable)
+{
+ /* This function does nothing, all work is done via poison pages */
+}
+#endif
diff --git a/mm/vmscan.c b/mm/vmscan.c
index 5e9e74955bd1..94fecacf0ddc 100644
--- a/mm/vmscan.c
+++ b/mm/vmscan.c
@@ -399,6 +399,35 @@ static unsigned long do_shrink_slab(struct shrink_control *shrinkctl,
return freed;
}
+static void shrink_slab_lmk(gfp_t gfp_mask, int nid,
+ struct mem_cgroup *memcg,
+ unsigned long nr_scanned,
+ unsigned long nr_eligible)
+{
+ struct shrinker *shrinker;
+
+ if (nr_scanned == 0)
+ nr_scanned = SWAP_CLUSTER_MAX;
+
+ if (!down_read_trylock(&shrinker_rwsem))
+ goto out;
+
+ list_for_each_entry(shrinker, &shrinker_list, list) {
+ struct shrink_control sc = {
+ .gfp_mask = gfp_mask,
+ };
+
+ if (!(shrinker->flags & SHRINKER_LMK))
+ continue;
+
+ do_shrink_slab(&sc, shrinker, nr_scanned, nr_eligible);
+ }
+
+ up_read(&shrinker_rwsem);
+out:
+ cond_resched();
+}
+
/**
* shrink_slab - shrink slab caches
* @gfp_mask: allocation context
@@ -460,6 +489,9 @@ static unsigned long shrink_slab(gfp_t gfp_mask, int nid,
.memcg = memcg,
};
+ if (shrinker->flags & SHRINKER_LMK)
+ continue;
+
if (memcg && !(shrinker->flags & SHRINKER_MEMCG_AWARE))
continue;
@@ -2626,6 +2658,7 @@ static bool shrink_zones(struct zonelist *zonelist, struct scan_control *sc)
gfp_t orig_mask;
enum zone_type requested_highidx = gfp_zone(sc->gfp_mask);
bool reclaimable = false;
+ unsigned long lru_pages = 0;
/*
* If the number of buffer_heads in the machine exceeds the maximum
@@ -2653,6 +2686,7 @@ static bool shrink_zones(struct zonelist *zonelist, struct scan_control *sc)
* to global LRU.
*/
if (global_reclaim(sc)) {
+ lru_pages += zone_reclaimable_pages(zone);
if (!cpuset_zone_allowed(zone,
GFP_KERNEL | __GFP_HARDWALL))
continue;
@@ -2703,6 +2737,9 @@ static bool shrink_zones(struct zonelist *zonelist, struct scan_control *sc)
reclaimable = true;
}
+ if (global_reclaim(sc))
+ shrink_slab_lmk(sc->gfp_mask, 0, NULL,
+ sc->nr_scanned, lru_pages);
/*
* Restore to original mask to avoid the impact on the caller if we
* promoted it to __GFP_HIGHMEM.
@@ -3181,7 +3218,8 @@ static bool prepare_kswapd_sleep(pg_data_t *pgdat, int order, long remaining,
*/
static bool kswapd_shrink_zone(struct zone *zone,
int classzone_idx,
- struct scan_control *sc)
+ struct scan_control *sc,
+ unsigned long lru_pages)
{
unsigned long balance_gap;
bool lowmem_pressure;
@@ -3208,6 +3246,8 @@ static bool kswapd_shrink_zone(struct zone *zone,
return true;
shrink_zone(zone, sc, zone_idx(zone) == classzone_idx);
+ shrink_slab_lmk(sc->gfp_mask, zone_to_nid(zone), NULL,
+ sc->nr_scanned, lru_pages);
clear_bit(ZONE_WRITEBACK, &zone->flags);
@@ -3265,6 +3305,7 @@ static int balance_pgdat(pg_data_t *pgdat, int order, int classzone_idx)
do {
bool raise_priority = true;
+ unsigned long lru_pages = 0;
sc.nr_reclaimed = 0;
@@ -3322,6 +3363,15 @@ static int balance_pgdat(pg_data_t *pgdat, int order, int classzone_idx)
if (sc.priority < DEF_PRIORITY - 2)
sc.may_writepage = 1;
+ for (i = 0; i <= end_zone; i++) {
+ struct zone *zone = pgdat->node_zones + i;
+
+ if (!populated_zone(zone))
+ continue;
+
+ lru_pages += zone_reclaimable_pages(zone);
+ }
+
/*
* Now scan the zone in the dma->highmem direction, stopping
* at the last zone which needs scanning.
@@ -3358,7 +3408,7 @@ static int balance_pgdat(pg_data_t *pgdat, int order, int classzone_idx)
* that that high watermark would be met at 100%
* efficiency.
*/
- if (kswapd_shrink_zone(zone, end_zone, &sc))
+ if (kswapd_shrink_zone(zone, end_zone, &sc, lru_pages))
raise_priority = false;
}
diff --git a/net/ipv6/netfilter/Kconfig b/net/ipv6/netfilter/Kconfig
index e10a04c9cdc7..cf336d670f8b 100644
--- a/net/ipv6/netfilter/Kconfig
+++ b/net/ipv6/netfilter/Kconfig
@@ -135,6 +135,18 @@ config IP6_NF_IPTABLES
if IP6_NF_IPTABLES
+config IP6_NF_IPTABLES_128
+ tristate "128 bit arithmetic for iptables matching"
+ depends on IP6_NF_IPTABLES
+ help
+ This enables 128 bit matching in ip6tables to help optimize cases
+ where there is no match required. ip6tables matching for ipv6 always
+ has a mask if an address is specified for match. Adding a check for
+ mask prior to that helps to improve performance as it avoids the
+ masked comparison.
+
+ Note that this feature depends on the architecture. If unsure, say N.
+
# The simple matches.
config IP6_NF_MATCH_AH
tristate '"ah" match support'
diff --git a/net/ipv6/netfilter/ip6_tables.c b/net/ipv6/netfilter/ip6_tables.c
index 22f39e00bef3..6fd784643d6e 100644
--- a/net/ipv6/netfilter/ip6_tables.c
+++ b/net/ipv6/netfilter/ip6_tables.c
@@ -94,22 +94,26 @@ ip6_packet_match(const struct sk_buff *skb,
{
unsigned long ret;
const struct ipv6hdr *ipv6 = ipv6_hdr(skb);
+#if IS_ENABLED(IP6_NF_IPTABLES_128)
+ const __uint128_t *ulm1 = (const __uint128_t *)&ip6info->smsk;
+ const __uint128_t *ulm2 = (const __uint128_t *)&ip6info->dmsk;
+#endif
#define FWINV(bool, invflg) ((bool) ^ !!(ip6info->invflags & (invflg)))
- if (FWINV(ipv6_masked_addr_cmp(&ipv6->saddr, &ip6info->smsk,
- &ip6info->src), IP6T_INV_SRCIP) ||
- FWINV(ipv6_masked_addr_cmp(&ipv6->daddr, &ip6info->dmsk,
- &ip6info->dst), IP6T_INV_DSTIP)) {
- dprintf("Source or dest mismatch.\n");
-/*
- dprintf("SRC: %u. Mask: %u. Target: %u.%s\n", ip->saddr,
- ipinfo->smsk.s_addr, ipinfo->src.s_addr,
- ipinfo->invflags & IP6T_INV_SRCIP ? " (INV)" : "");
- dprintf("DST: %u. Mask: %u. Target: %u.%s\n", ip->daddr,
- ipinfo->dmsk.s_addr, ipinfo->dst.s_addr,
- ipinfo->invflags & IP6T_INV_DSTIP ? " (INV)" : "");*/
- return false;
+#if IS_ENABLED(IP6_NF_IPTABLES_128)
+ if (*ulm1 || *ulm2)
+#endif
+ {
+ if (FWINV(ipv6_masked_addr_cmp
+ (&ipv6->saddr, &ip6info->smsk, &ip6info->src),
+ IP6T_INV_SRCIP) ||
+ FWINV(ipv6_masked_addr_cmp(&ipv6->daddr, &ip6info->dmsk,
+ &ip6info->dst),
+ IP6T_INV_DSTIP)) {
+ dprintf("Source or dest mismatch.\n");
+ return false;
+ }
}
ret = ifname_compare_aligned(indev, ip6info->iniface, ip6info->iniface_mask);
diff --git a/net/ipv6/route.c b/net/ipv6/route.c
index 83ddc8074e55..add152e8352c 100644
--- a/net/ipv6/route.c
+++ b/net/ipv6/route.c
@@ -3200,6 +3200,10 @@ int rt6_dump_route(struct rt6_info *rt, void *p_arg)
{
struct rt6_rtnl_dump_arg *arg = (struct rt6_rtnl_dump_arg *) p_arg;
int prefix;
+ struct net *net = arg->net;
+
+ if (rt == net->ipv6.ip6_null_entry)
+ return 0;
if (nlmsg_len(arg->cb->nlh) >= sizeof(struct rtmsg)) {
struct rtmsg *rtm = nlmsg_data(arg->cb->nlh);
@@ -3207,7 +3211,7 @@ int rt6_dump_route(struct rt6_info *rt, void *p_arg)
} else
prefix = 0;
- return rt6_fill_node(arg->net,
+ return rt6_fill_node(net,
arg->skb, rt, NULL, NULL, 0, RTM_NEWROUTE,
NETLINK_CB(arg->cb->skb).portid, arg->cb->nlh->nlmsg_seq,
prefix, 0, NLM_F_MULTI);
diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c
index 23095d5e0199..f3deee7da389 100644
--- a/net/mac80211/mlme.c
+++ b/net/mac80211/mlme.c
@@ -4490,20 +4490,20 @@ int ieee80211_mgd_auth(struct ieee80211_sub_if_data *sdata,
return -EOPNOTSUPP;
}
- auth_data = kzalloc(sizeof(*auth_data) + req->sae_data_len +
+ auth_data = kzalloc(sizeof(*auth_data) + req->auth_data_len +
req->ie_len, GFP_KERNEL);
if (!auth_data)
return -ENOMEM;
auth_data->bss = req->bss;
- if (req->sae_data_len >= 4) {
- __le16 *pos = (__le16 *) req->sae_data;
+ if (req->auth_data_len >= 4) {
+ __le16 *pos = (__le16 *) req->auth_data;
auth_data->sae_trans = le16_to_cpu(pos[0]);
auth_data->sae_status = le16_to_cpu(pos[1]);
- memcpy(auth_data->data, req->sae_data + 4,
- req->sae_data_len - 4);
- auth_data->data_len += req->sae_data_len - 4;
+ memcpy(auth_data->data, req->auth_data + 4,
+ req->auth_data_len - 4);
+ auth_data->data_len += req->auth_data_len - 4;
}
if (req->ie && req->ie_len) {
diff --git a/net/wireless/core.h b/net/wireless/core.h
index 54865316358e..5cfe6fd72d52 100644
--- a/net/wireless/core.h
+++ b/net/wireless/core.h
@@ -335,7 +335,7 @@ int cfg80211_mlme_auth(struct cfg80211_registered_device *rdev,
const u8 *ssid, int ssid_len,
const u8 *ie, int ie_len,
const u8 *key, int key_len, int key_idx,
- const u8 *sae_data, int sae_data_len);
+ const u8 *auth_data, int auth_data_len);
int cfg80211_mlme_assoc(struct cfg80211_registered_device *rdev,
struct net_device *dev,
struct ieee80211_channel *chan,
diff --git a/net/wireless/db.txt b/net/wireless/db.txt
index 449e4a31a3ec..a71f8801edb3 100644
--- a/net/wireless/db.txt
+++ b/net/wireless/db.txt
@@ -54,7 +54,8 @@ country AN: DFS-ETSI
country AR:
(2402 - 2482 @ 40), (36)
- (5170 - 5330 @ 160), (23)
+ (5170 - 5250 @ 80), (23), AUTO-BW
+ (5250 - 5330 @ 80), (36), AUTO-BW
(5490 - 5590 @ 80), (36)
(5650 - 5730 @ 80), (36)
(5735 - 5835 @ 80), (36)
diff --git a/net/wireless/mlme.c b/net/wireless/mlme.c
index 1b97f978ccd6..e2b1333cc4e4 100644
--- a/net/wireless/mlme.c
+++ b/net/wireless/mlme.c
@@ -217,14 +217,14 @@ int cfg80211_mlme_auth(struct cfg80211_registered_device *rdev,
const u8 *ssid, int ssid_len,
const u8 *ie, int ie_len,
const u8 *key, int key_len, int key_idx,
- const u8 *sae_data, int sae_data_len)
+ const u8 *auth_data, int auth_data_len)
{
struct wireless_dev *wdev = dev->ieee80211_ptr;
struct cfg80211_auth_request req = {
.ie = ie,
.ie_len = ie_len,
- .sae_data = sae_data,
- .sae_data_len = sae_data_len,
+ .auth_data = auth_data,
+ .auth_data_len = auth_data_len,
.auth_type = auth_type,
.key = key,
.key_len = key_len,
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index 58b45366c42c..adc62ec5507a 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -354,7 +354,7 @@ static const struct nla_policy nl80211_policy[NUM_NL80211_ATTR] = {
[NL80211_ATTR_BG_SCAN_PERIOD] = { .type = NLA_U16 },
[NL80211_ATTR_WDEV] = { .type = NLA_U64 },
[NL80211_ATTR_USER_REG_HINT_TYPE] = { .type = NLA_U32 },
- [NL80211_ATTR_SAE_DATA] = { .type = NLA_BINARY, },
+ [NL80211_ATTR_AUTH_DATA] = { .type = NLA_BINARY, },
[NL80211_ATTR_VHT_CAPABILITY] = { .len = NL80211_VHT_CAPABILITY_LEN },
[NL80211_ATTR_SCAN_FLAGS] = { .type = NLA_U32 },
[NL80211_ATTR_P2P_CTWINDOW] = { .type = NLA_U8 },
@@ -3661,12 +3661,23 @@ static bool nl80211_valid_auth_type(struct cfg80211_registered_device *rdev,
if (!(rdev->wiphy.features & NL80211_FEATURE_SAE) &&
auth_type == NL80211_AUTHTYPE_SAE)
return false;
+ if (!wiphy_ext_feature_isset(&rdev->wiphy,
+ NL80211_EXT_FEATURE_FILS_STA) &&
+ (auth_type == NL80211_AUTHTYPE_FILS_SK ||
+ auth_type == NL80211_AUTHTYPE_FILS_SK_PFS ||
+ auth_type == NL80211_AUTHTYPE_FILS_PK))
+ return false;
return true;
case NL80211_CMD_CONNECT:
case NL80211_CMD_START_AP:
/* SAE not supported yet */
if (auth_type == NL80211_AUTHTYPE_SAE)
return false;
+ /* FILS not supported yet */
+ if (auth_type == NL80211_AUTHTYPE_FILS_SK ||
+ auth_type == NL80211_AUTHTYPE_FILS_SK_PFS ||
+ auth_type == NL80211_AUTHTYPE_FILS_PK)
+ return false;
return true;
default:
return false;
@@ -7489,8 +7500,8 @@ static int nl80211_authenticate(struct sk_buff *skb, struct genl_info *info)
struct cfg80211_registered_device *rdev = info->user_ptr[0];
struct net_device *dev = info->user_ptr[1];
struct ieee80211_channel *chan;
- const u8 *bssid, *ssid, *ie = NULL, *sae_data = NULL;
- int err, ssid_len, ie_len = 0, sae_data_len = 0;
+ const u8 *bssid, *ssid, *ie = NULL, *auth_data = NULL;
+ int err, ssid_len, ie_len = 0, auth_data_len = 0;
enum nl80211_auth_type auth_type;
struct key_parse key;
bool local_state_change;
@@ -7569,17 +7580,23 @@ static int nl80211_authenticate(struct sk_buff *skb, struct genl_info *info)
if (!nl80211_valid_auth_type(rdev, auth_type, NL80211_CMD_AUTHENTICATE))
return -EINVAL;
- if (auth_type == NL80211_AUTHTYPE_SAE &&
- !info->attrs[NL80211_ATTR_SAE_DATA])
+ if ((auth_type == NL80211_AUTHTYPE_SAE ||
+ auth_type == NL80211_AUTHTYPE_FILS_SK ||
+ auth_type == NL80211_AUTHTYPE_FILS_SK_PFS ||
+ auth_type == NL80211_AUTHTYPE_FILS_PK) &&
+ !info->attrs[NL80211_ATTR_AUTH_DATA])
return -EINVAL;
- if (info->attrs[NL80211_ATTR_SAE_DATA]) {
- if (auth_type != NL80211_AUTHTYPE_SAE)
+ if (info->attrs[NL80211_ATTR_AUTH_DATA]) {
+ if (auth_type != NL80211_AUTHTYPE_SAE &&
+ auth_type != NL80211_AUTHTYPE_FILS_SK &&
+ auth_type != NL80211_AUTHTYPE_FILS_SK_PFS &&
+ auth_type != NL80211_AUTHTYPE_FILS_PK)
return -EINVAL;
- sae_data = nla_data(info->attrs[NL80211_ATTR_SAE_DATA]);
- sae_data_len = nla_len(info->attrs[NL80211_ATTR_SAE_DATA]);
+ auth_data = nla_data(info->attrs[NL80211_ATTR_AUTH_DATA]);
+ auth_data_len = nla_len(info->attrs[NL80211_ATTR_AUTH_DATA]);
/* need to include at least Auth Transaction and Status Code */
- if (sae_data_len < 4)
+ if (auth_data_len < 4)
return -EINVAL;
}
@@ -7596,7 +7613,7 @@ static int nl80211_authenticate(struct sk_buff *skb, struct genl_info *info)
err = cfg80211_mlme_auth(rdev, dev, chan, auth_type, bssid,
ssid, ssid_len, ie, ie_len,
key.p.key, key.p.key_len, key.idx,
- sae_data, sae_data_len);
+ auth_data, auth_data_len);
wdev_unlock(dev->ieee80211_ptr);
return err;
}
diff --git a/scripts/Makefile.build b/scripts/Makefile.build
index 01df30af4d4a..45473ca4290c 100644
--- a/scripts/Makefile.build
+++ b/scripts/Makefile.build
@@ -64,6 +64,11 @@ ifneq ($(hostprogs-y)$(hostprogs-m),)
include scripts/Makefile.host
endif
+# Do not include host rules unless needed
+ifneq ($(dtbo-y),)
+include scripts/Makefile.dtbo
+endif
+
ifneq ($(KBUILD_SRC),)
# Create output directory if not already present
_dummy := $(shell [ -d $(obj) ] || mkdir -p $(obj))
diff --git a/scripts/Makefile.dtbo b/scripts/Makefile.dtbo
new file mode 100644
index 000000000000..db4a0f4b9a56
--- /dev/null
+++ b/scripts/Makefile.dtbo
@@ -0,0 +1,24 @@
+__dtbo := $(sort $(dtbo-y))
+
+dtbo-base := $(sort $(foreach m,$(__dtbo),$($(m)-base)))
+dtbo := $(foreach m,$(__dtbo),$(if $($(m)-base),$(m)))
+
+__dtbo := $(addprefix $(obj)/,$(__dtbo))
+dtbo-base := $(addprefix $(obj)/,$(dtbo-base))
+dtbo := $(addprefix $(obj)/,$(dtbo))
+
+ifneq ($(DTC_OVERLAY_TEST_EXT),)
+DTC_OVERLAY_TEST = $(DTC_OVERLAY_TEST_EXT)
+quiet_cmd_dtbo_verify = VERIFY $@
+cmd_dtbo_verify = $(DTC_OVERLAY_TEST) $(addprefix $(obj)/,$($(@F)-base)) $@ $(dot-target).dtb
+else
+cmd_dtbo_verify = true
+endif
+
+$(obj)/%.dtbo: $(src)/%.dts FORCE
+ $(call if_changed_dep,dtc)
+ $(call if_changed,dtbo_verify)
+
+$(call multi_depend, $(dtbo), , -base)
+
+always += $(dtbo)
diff --git a/scripts/Makefile.lib b/scripts/Makefile.lib
index 861a2acd8cba..46881f329561 100644
--- a/scripts/Makefile.lib
+++ b/scripts/Makefile.lib
@@ -287,10 +287,16 @@ cmd_dt_S_dtb= \
$(obj)/%.dtb.S: $(obj)/%.dtb
$(call cmd,dt_S_dtb)
+ifneq ($(DTC_EXT),)
+DTC = $(DTC_EXT)
+else
+DTC = $(objtree)/scripts/dtc/dtc
+endif
+
quiet_cmd_dtc = DTC $@
cmd_dtc = mkdir -p $(dir ${dtc-tmp}) ; \
$(CPP) $(dtc_cpp_flags) -x assembler-with-cpp -o $(dtc-tmp) $< ; \
- $(objtree)/scripts/dtc/dtc -O dtb -o $@ -b 0 \
+ $(DTC) -O dtb -o $@ -b 0 \
-i $(dir $<) $(DTC_FLAGS) \
-d $(depfile).dtc.tmp $(dtc-tmp) ; \
cat $(depfile).pre.tmp $(depfile).dtc.tmp > $(depfile)
diff --git a/scripts/dtc/Makefile b/scripts/dtc/Makefile
index 2a48022c41e7..2eb4aec040f4 100644
--- a/scripts/dtc/Makefile
+++ b/scripts/dtc/Makefile
@@ -1,7 +1,9 @@
# scripts/dtc makefile
hostprogs-y := dtc
+ifeq ($(DTC_EXT),)
always := $(hostprogs-y)
+endif
dtc-objs := dtc.o flattree.o fstree.o data.o livetree.o treesource.o \
srcpos.o checks.o util.o
diff --git a/security/pfe/pfk_ecryptfs.c b/security/pfe/pfk_ecryptfs.c
index f98d85ab4841..f55ee83c30ed 100644
--- a/security/pfe/pfk_ecryptfs.c
+++ b/security/pfe/pfk_ecryptfs.c
@@ -112,7 +112,7 @@ static int __init pfk_ecryptfs_lsm_init(void)
/*
* pfk_ecryptfs_deinit() - Deinit function, should be invoked by upper PFK layer
*/
-void __exit pfk_ecryptfs_deinit(void)
+void pfk_ecryptfs_deinit(void)
{
pfk_ecryptfs_ready = false;
ecryptfs_unregister_from_events(g_events_handle);
diff --git a/security/pfe/pfk_ecryptfs.h b/security/pfe/pfk_ecryptfs.h
index 1d9942c4c09b..bd3a8f2800b8 100644
--- a/security/pfe/pfk_ecryptfs.h
+++ b/security/pfe/pfk_ecryptfs.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
@@ -34,6 +34,6 @@ bool pfk_ecryptfs_allow_merge_bio(const struct bio *bio1,
int __init pfk_ecryptfs_init(void);
-void __exit pfk_ecryptfs_deinit(void);
+void pfk_ecryptfs_deinit(void);
#endif /* _PFK_ECRYPTFS_H_ */
diff --git a/security/pfe/pfk_ext4.c b/security/pfe/pfk_ext4.c
index 07e2c7ab829c..b9df18f9fb01 100644
--- a/security/pfe/pfk_ext4.c
+++ b/security/pfe/pfk_ext4.c
@@ -1,5 +1,5 @@
/*
- * 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
@@ -44,7 +44,7 @@ static bool pfk_ext4_ready;
/*
* pfk_ext4_deinit() - Deinit function, should be invoked by upper PFK layer
*/
-void __exit pfk_ext4_deinit(void)
+void pfk_ext4_deinit(void)
{
pfk_ext4_ready = false;
}
diff --git a/security/pfe/pfk_ext4.h b/security/pfe/pfk_ext4.h
index 6b367b428e50..1f336325f1db 100644
--- a/security/pfe/pfk_ext4.h
+++ b/security/pfe/pfk_ext4.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
@@ -32,6 +32,6 @@ bool pfk_ext4_allow_merge_bio(const struct bio *bio1,
int __init pfk_ext4_init(void);
-void __exit pfk_ext4_deinit(void);
+void pfk_ext4_deinit(void);
#endif /* _PFK_EXT4_H_ */
diff --git a/sound/soc/codecs/wcd-mbhc-v2.c b/sound/soc/codecs/wcd-mbhc-v2.c
index 7f9ad8ebcd3d..44141ae5668e 100644
--- a/sound/soc/codecs/wcd-mbhc-v2.c
+++ b/sound/soc/codecs/wcd-mbhc-v2.c
@@ -2217,7 +2217,7 @@ static int wcd_mbhc_initialise(struct wcd_mbhc *mbhc)
INIT_WORK(&mbhc->correct_plug_swch, wcd_correct_swch_plug);
- init_completion(&mbhc->btn_press_compl);
+ reinit_completion(&mbhc->btn_press_compl);
WCD_MBHC_RSC_UNLOCK(mbhc);
pr_debug("%s: leave\n", __func__);
@@ -2854,6 +2854,7 @@ int wcd_mbhc_init(struct wcd_mbhc *mbhc, struct snd_soc_codec *codec,
}
mutex_init(&mbhc->hphl_pa_lock);
mutex_init(&mbhc->hphr_pa_lock);
+ init_completion(&mbhc->btn_press_compl);
/* Register event notifier */
mbhc->nblock.notifier_call = wcd_event_notify;
diff --git a/sound/soc/codecs/wcd-spi.c b/sound/soc/codecs/wcd-spi.c
index 3d2fe2c6bed9..fde1d3e815d3 100644
--- a/sound/soc/codecs/wcd-spi.c
+++ b/sound/soc/codecs/wcd-spi.c
@@ -553,7 +553,7 @@ static int wcd_spi_clk_enable(struct spi_device *spi)
{
struct wcd_spi_priv *wcd_spi = spi_get_drvdata(spi);
int ret;
- u32 rd_status;
+ u32 rd_status = 0;
ret = wcd_spi_cmd_nop(spi);
if (IS_ERR_VALUE(ret)) {
diff --git a/sound/soc/codecs/wcd9335.c b/sound/soc/codecs/wcd9335.c
index d533984558f0..7ad3aeaa8fb7 100644
--- a/sound/soc/codecs/wcd9335.c
+++ b/sound/soc/codecs/wcd9335.c
@@ -192,7 +192,7 @@ module_param(sido_buck_svs_voltage, int,
MODULE_PARM_DESC(sido_buck_svs_voltage,
"setting for SVS voltage for SIDO BUCK");
-#define TASHA_TX_UNMUTE_DELAY_MS 25
+#define TASHA_TX_UNMUTE_DELAY_MS 40
static int tx_unmute_delay = TASHA_TX_UNMUTE_DELAY_MS;
module_param(tx_unmute_delay, int,
@@ -4945,7 +4945,7 @@ static int tasha_codec_enable_spline_src(struct snd_soc_codec *codec,
int src_num,
int event)
{
- u16 src_paired_reg;
+ u16 src_paired_reg = 0;
struct tasha_priv *tasha;
u16 rx_path_cfg_reg = WCD9335_CDC_RX1_RX_PATH_CFG0;
u16 rx_path_ctl_reg = WCD9335_CDC_RX1_RX_PATH_CTL;
diff --git a/sound/soc/codecs/wcd934x/wcd934x.c b/sound/soc/codecs/wcd934x/wcd934x.c
index e125ed8c2a16..a0514c8a1ee5 100644
--- a/sound/soc/codecs/wcd934x/wcd934x.c
+++ b/sound/soc/codecs/wcd934x/wcd934x.c
@@ -507,7 +507,7 @@ static const DECLARE_TLV_DB_SCALE(digital_gain, 0, 1, 0);
static const DECLARE_TLV_DB_SCALE(line_gain, 0, 7, 1);
static const DECLARE_TLV_DB_SCALE(analog_gain, 0, 25, 1);
-#define WCD934X_TX_UNMUTE_DELAY_MS 25
+#define WCD934X_TX_UNMUTE_DELAY_MS 40
static int tx_unmute_delay = WCD934X_TX_UNMUTE_DELAY_MS;
module_param(tx_unmute_delay, int,
@@ -5476,7 +5476,7 @@ static int tavil_mad_input_put(struct snd_kcontrol *kcontrol,
u32 adc, i, mic_bias_found = 0;
int ret = 0;
char *mad_input;
- bool is_adc2_input = false;
+ bool is_adc_input = false;
tavil_mad_input = ucontrol->value.integer.value[0];
@@ -5524,8 +5524,7 @@ static int tavil_mad_input_put(struct snd_kcontrol *kcontrol,
snprintf(mad_amic_input_widget, 6, "%s%u", "AMIC", adc);
mad_input_widget = mad_amic_input_widget;
- if (adc == 2)
- is_adc2_input = true;
+ is_adc_input = true;
} else {
/* DMIC type input widget*/
mad_input_widget = tavil_conn_mad_text[tavil_mad_input];
@@ -5533,7 +5532,7 @@ static int tavil_mad_input_put(struct snd_kcontrol *kcontrol,
dev_dbg(codec->dev,
"%s: tavil input widget = %s, adc_input = %s\n", __func__,
- mad_input_widget, is_adc2_input ? "true" : "false");
+ mad_input_widget, is_adc_input ? "true" : "false");
for (i = 0; i < card->num_of_dapm_routes; i++) {
if (!strcmp(card->of_dapm_routes[i].sink, mad_input_widget)) {
@@ -5578,8 +5577,8 @@ static int tavil_mad_input_put(struct snd_kcontrol *kcontrol,
0x0F, tavil_mad_input);
snd_soc_update_bits(codec, WCD934X_ANA_MAD_SETUP,
0x07, mic_bias_found);
- /* for adc2 input, mad should be in micbias mode with BG enabled */
- if (is_adc2_input)
+ /* for all adc inputs, mad should be in micbias mode with BG enabled */
+ if (is_adc_input)
snd_soc_update_bits(codec, WCD934X_ANA_MAD_SETUP,
0x88, 0x88);
else
diff --git a/sound/soc/codecs/wcd_cpe_core.c b/sound/soc/codecs/wcd_cpe_core.c
index 2082c356203d..3b681f53b17a 100644
--- a/sound/soc/codecs/wcd_cpe_core.c
+++ b/sound/soc/codecs/wcd_cpe_core.c
@@ -3556,6 +3556,8 @@ static int wcd_cpe_lsm_lab_control(
pr_debug("%s: enter payload_size = %d Enable %d\n",
__func__, pld_size, enable);
+ memset(&cpe_lab_enable, 0, sizeof(cpe_lab_enable));
+
if (fill_lsm_cmd_header_v0_inband(&cpe_lab_enable.hdr, session->id,
(u8) pld_size, CPE_LSM_SESSION_CMD_SET_PARAMS_V2)) {
return -EINVAL;
diff --git a/sound/soc/msm/apq8096-auto.c b/sound/soc/msm/apq8096-auto.c
index 7b363bdca291..e1baca358d5f 100644
--- a/sound/soc/msm/apq8096-auto.c
+++ b/sound/soc/msm/apq8096-auto.c
@@ -22,6 +22,7 @@
#include <linux/module.h>
#include <linux/switch.h>
#include <linux/input.h>
+#include <linux/qdsp6v2/apr.h>
#include <sound/core.h>
#include <sound/soc.h>
#include <sound/soc-dapm.h>
@@ -68,6 +69,7 @@ static int msm_tert_tdm_rx_0_ch = 2; /* ICC STREAM */
static int msm_tert_tdm_rx_1_ch = 2;
static int msm_tert_tdm_rx_2_ch = 2;
static int msm_tert_tdm_rx_3_ch = 2;
+static int msm_tert_tdm_rx_4_ch;
static int msm_tert_tdm_tx_0_ch = 6; /* EC_REF1-EC_REF6(6 CHAN) */
static int msm_tert_tdm_tx_1_ch = 1;
@@ -94,6 +96,7 @@ static int msm_tert_tdm_rx_0_bit_format = SNDRV_PCM_FORMAT_S16_LE;
static int msm_tert_tdm_rx_1_bit_format = SNDRV_PCM_FORMAT_S16_LE;
static int msm_tert_tdm_rx_2_bit_format = SNDRV_PCM_FORMAT_S16_LE;
static int msm_tert_tdm_rx_3_bit_format = SNDRV_PCM_FORMAT_S16_LE;
+static int msm_tert_tdm_rx_4_bit_format = SNDRV_PCM_FORMAT_S16_LE;
static int msm_tert_tdm_tx_0_bit_format = SNDRV_PCM_FORMAT_S16_LE;
static int msm_tert_tdm_tx_1_bit_format = SNDRV_PCM_FORMAT_S16_LE;
@@ -309,9 +312,9 @@ static unsigned int tdm_slot_offset_custom[TDM_MAX][TDM_SLOT_OFFSET_MAX] = {
{0xFFFF}, /* not used */
{0xFFFF}, /* not used */
/* QUAT_TDM_TX */
- {0, 2, 0xFFFF},
- {4, 6, 8, 10, 12, 14, 16, 18},
- {20, 22, 24, 26, 28, 30, 0xFFFF},
+ {0, 2, 4, 6, 8, 10, 12, 0xFFFF},
+ {14, 16, 0xFFFF},
+ {18, 20, 22, 24, 26, 28, 30, 0xFFFF},
{0xFFFF}, /* not used */
{0xFFFF}, /* not used */
{0xFFFF}, /* not used */
@@ -327,9 +330,9 @@ static unsigned int tdm_slot_offset_custom[TDM_MAX][TDM_SLOT_OFFSET_MAX] = {
{28, 30, 0xFFFF},
{0xFFFF}, /* not used */
/* TERT_TDM_TX */
- {0, 2, 4, 6, 8, 10, 12, 0xFFFF},
- {14, 16, 0xFFFF},
- {18, 20, 22, 24, 26, 28, 30, 0xFFFF},
+ {0, 2, 0xFFFF},
+ {4, 6, 8, 10, 12, 14, 16, 18},
+ {20, 22, 24, 26, 28, 30, 0xFFFF},
{0xFFFF}, /* not used */
{0xFFFF}, /* not used */
{0xFFFF}, /* not used */
@@ -836,6 +839,24 @@ static int msm_tert_tdm_rx_3_ch_put(struct snd_kcontrol *kcontrol,
return 0;
}
+static int msm_tert_tdm_rx_4_ch_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ pr_debug("%s: msm_tert_tdm_rx_4_ch = %d\n", __func__,
+ msm_tert_tdm_rx_4_ch);
+ ucontrol->value.integer.value[0] = msm_tert_tdm_rx_4_ch - 1;
+ return 0;
+}
+
+static int msm_tert_tdm_rx_4_ch_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ msm_tert_tdm_rx_4_ch = ucontrol->value.integer.value[0] + 1;
+ pr_debug("%s: msm_tert_tdm_rx_4_ch = %d\n", __func__,
+ msm_tert_tdm_rx_4_ch);
+ return 0;
+}
+
static int msm_tert_tdm_tx_0_ch_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
@@ -1324,6 +1345,40 @@ static int msm_tert_tdm_rx_3_bit_format_put(struct snd_kcontrol *kcontrol,
return 0;
}
+static int msm_tert_tdm_rx_4_bit_format_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ switch (msm_tert_tdm_rx_4_bit_format) {
+ case SNDRV_PCM_FORMAT_S24_LE:
+ ucontrol->value.integer.value[0] = 1;
+ break;
+ case SNDRV_PCM_FORMAT_S16_LE:
+ default:
+ ucontrol->value.integer.value[0] = 0;
+ break;
+ }
+ pr_debug("%s: msm_tert_tdm_rx_4_bit_format = %ld\n",
+ __func__, ucontrol->value.integer.value[0]);
+ return 0;
+}
+
+static int msm_tert_tdm_rx_4_bit_format_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ switch (ucontrol->value.integer.value[0]) {
+ case 1:
+ msm_tert_tdm_rx_4_bit_format = SNDRV_PCM_FORMAT_S24_LE;
+ break;
+ case 0:
+ default:
+ msm_tert_tdm_rx_4_bit_format = SNDRV_PCM_FORMAT_S16_LE;
+ break;
+ }
+ pr_debug("%s: msm_tert_tdm_rx_4_bit_format = %d\n",
+ __func__, msm_tert_tdm_rx_4_bit_format);
+ return 0;
+}
+
static int msm_tert_tdm_tx_0_bit_format_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
@@ -2020,6 +2075,11 @@ static int msm_tdm_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
param_set_mask(params, SNDRV_PCM_HW_PARAM_FORMAT,
msm_tert_tdm_rx_3_bit_format);
break;
+ case AFE_PORT_ID_TERTIARY_TDM_RX_4:
+ channels->min = channels->max = msm_tert_tdm_rx_4_ch;
+ param_set_mask(params, SNDRV_PCM_HW_PARAM_FORMAT,
+ msm_tert_tdm_rx_4_bit_format);
+ break;
case AFE_PORT_ID_TERTIARY_TDM_TX:
channels->min = channels->max = msm_tert_tdm_tx_0_ch;
param_set_mask(params, SNDRV_PCM_HW_PARAM_FORMAT,
@@ -2600,6 +2660,8 @@ static const struct snd_kcontrol_new msm_snd_controls[] = {
msm_tert_tdm_rx_2_ch_get, msm_tert_tdm_rx_2_ch_put),
SOC_ENUM_EXT("TERT_TDM_RX_3 Channels", msm_snd_enum[5],
msm_tert_tdm_rx_3_ch_get, msm_tert_tdm_rx_3_ch_put),
+ SOC_ENUM_EXT("TERT_TDM_RX_4 Channels", msm_snd_enum[5],
+ msm_tert_tdm_rx_4_ch_get, msm_tert_tdm_rx_4_ch_put),
SOC_ENUM_EXT("TERT_TDM_TX_0 Channels", msm_snd_enum[5],
msm_tert_tdm_tx_0_ch_get, msm_tert_tdm_tx_0_ch_put),
SOC_ENUM_EXT("TERT_TDM_TX_1 Channels", msm_snd_enum[5],
@@ -2648,6 +2710,9 @@ static const struct snd_kcontrol_new msm_snd_controls[] = {
SOC_ENUM_EXT("TERT_TDM_RX_3 Bit Format", msm_snd_enum[6],
msm_tert_tdm_rx_3_bit_format_get,
msm_tert_tdm_rx_3_bit_format_put),
+ SOC_ENUM_EXT("TERT_TDM_RX_4 Bit Format", msm_snd_enum[6],
+ msm_tert_tdm_rx_4_bit_format_get,
+ msm_tert_tdm_rx_4_bit_format_put),
SOC_ENUM_EXT("TERT_TDM_TX_0 Bit Format", msm_snd_enum[6],
msm_tert_tdm_tx_0_bit_format_get,
msm_tert_tdm_tx_0_bit_format_put),
@@ -3835,6 +3900,55 @@ static struct snd_soc_dai_link apq8096_custom_fe_dai_links[] = {
.be_id = MSM_FRONTEND_DAI_MULTIMEDIA9,
.ops = &apq8096_ll_ops,
},
+ {
+ .name = "INT_HFP_BT Hostless",
+ .stream_name = "INT_HFP_BT Hostless",
+ .cpu_dai_name = "INT_HFP_BT_HOSTLESS",
+ .platform_name = "msm-pcm-hostless",
+ .dynamic = 1,
+ .dpcm_playback = 1,
+ .dpcm_capture = 1,
+ .trigger = {SND_SOC_DPCM_TRIGGER_POST,
+ SND_SOC_DPCM_TRIGGER_POST},
+ .no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
+ .ignore_suspend = 1,
+ /* this dainlink has playback support */
+ .ignore_pmdown_time = 1,
+ .codec_dai_name = "snd-soc-dummy-dai",
+ .codec_name = "snd-soc-dummy",
+ },
+ {
+ .name = "AUXPCM Hostless",
+ .stream_name = "AUXPCM Hostless",
+ .cpu_dai_name = "AUXPCM_HOSTLESS",
+ .platform_name = "msm-pcm-hostless",
+ .dynamic = 1,
+ .dpcm_playback = 1,
+ .dpcm_capture = 1,
+ .trigger = {SND_SOC_DPCM_TRIGGER_POST,
+ SND_SOC_DPCM_TRIGGER_POST},
+ .no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
+ .ignore_suspend = 1,
+ /* this dainlink has playback support */
+ .ignore_pmdown_time = 1,
+ .codec_dai_name = "snd-soc-dummy-dai",
+ .codec_name = "snd-soc-dummy",
+ },
+ {
+ .name = "Tertiary MI2S TX_Hostless",
+ .stream_name = "Tertiary MI2S_TX Hostless Capture",
+ .cpu_dai_name = "TERT_MI2S_TX_HOSTLESS",
+ .platform_name = "msm-pcm-hostless",
+ .dynamic = 1,
+ .dpcm_capture = 1,
+ .trigger = {SND_SOC_DPCM_TRIGGER_POST,
+ SND_SOC_DPCM_TRIGGER_POST},
+ .no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
+ .ignore_suspend = 1,
+ .ignore_pmdown_time = 1,
+ .codec_dai_name = "snd-soc-dummy-dai",
+ .codec_name = "snd-soc-dummy",
+ },
};
static struct snd_soc_dai_link apq8096_common_be_dai_links[] = {
@@ -4111,6 +4225,20 @@ static struct snd_soc_dai_link apq8096_auto_be_dai_links[] = {
.ignore_suspend = 1,
},
{
+ .name = LPASS_BE_TERT_TDM_RX_4,
+ .stream_name = "Tertiary TDM4 Playback",
+ .cpu_dai_name = "msm-dai-q6-tdm.36904",
+ .platform_name = "msm-pcm-routing",
+ .codec_name = "msm-stub-codec.1",
+ .codec_dai_name = "msm-stub-rx",
+ .no_pcm = 1,
+ .dpcm_playback = 1,
+ .be_id = MSM_BACKEND_DAI_TERT_TDM_RX_4,
+ .be_hw_params_fixup = msm_tdm_be_hw_params_fixup,
+ .ops = &apq8096_tdm_be_ops,
+ .ignore_suspend = 1,
+ },
+ {
.name = LPASS_BE_TERT_TDM_TX_0,
.stream_name = "Tertiary TDM0 Capture",
.cpu_dai_name = "msm-dai-q6-tdm.36897",
@@ -4557,12 +4685,21 @@ static int apq8096_asoc_machine_probe(struct platform_device *pdev)
struct snd_soc_card *card;
const struct of_device_id *match;
int ret;
+ enum apr_subsys_state q6_state;
if (!pdev->dev.of_node) {
dev_err(&pdev->dev, "No platform supplied from device tree\n");
return -EINVAL;
}
+ q6_state = apr_get_q6_state();
+ if (q6_state == APR_SUBSYS_DOWN) {
+ dev_dbg(&pdev->dev, "deferring %s, adsp_state %d\n",
+ __func__, q6_state);
+ ret = -EPROBE_DEFER;
+ goto err;
+ }
+
card = populate_snd_card_dailinks(&pdev->dev);
if (!card) {
dev_err(&pdev->dev, "%s: Card uninitialized\n", __func__);
diff --git a/sound/soc/msm/msm-dai-fe.c b/sound/soc/msm/msm-dai-fe.c
index a7a25ea070da..33443ab151e9 100644
--- a/sound/soc/msm/msm-dai-fe.c
+++ b/sound/soc/msm/msm-dai-fe.c
@@ -113,7 +113,7 @@ static struct snd_soc_dai_driver msm_fe_dais[] = {
SNDRV_PCM_FMTBIT_S24_3LE |
SNDRV_PCM_FMTBIT_S32_LE),
.channels_min = 1,
- .channels_max = 4,
+ .channels_max = 8,
.rate_min = 8000,
.rate_max = 48000,
},
diff --git a/sound/soc/msm/msm8998.c b/sound/soc/msm/msm8998.c
index ec02cdf3ca3c..f6a5d1344568 100644
--- a/sound/soc/msm/msm8998.c
+++ b/sound/soc/msm/msm8998.c
@@ -4155,9 +4155,6 @@ static void update_mi2s_clk_val(int dai_id, int stream)
mi2s_clk[dai_id].clk_freq_in_hz =
mi2s_tx_cfg[dai_id].sample_rate * 2 * bit_per_sample;
}
-
- if (!mi2s_intf_conf[dai_id].msm_is_mi2s_master)
- mi2s_clk[dai_id].clk_freq_in_hz = 0;
}
static int msm_mi2s_set_sclk(struct snd_pcm_substream *substream, bool enable)
@@ -4206,6 +4203,13 @@ static int msm_set_pinctrl(struct msm_pinctrl_info *pinctrl_info,
ret = -EINVAL;
goto err;
}
+
+ if (pinctrl_info->pinctrl == NULL) {
+ pr_err("%s: pinctrl_info->pinctrl is NULL\n", __func__);
+ ret = -EINVAL;
+ goto err;
+ }
+
curr_state = pinctrl_info->curr_state;
pinctrl_info->curr_state = new_state;
pr_debug("%s: curr_state = %s new_state = %s\n", __func__,
@@ -4474,6 +4478,7 @@ static int msm_mi2s_snd_startup(struct snd_pcm_substream *substream)
struct snd_soc_card *card = rtd->card;
struct msm_asoc_mach_data *pdata = snd_soc_card_get_drvdata(card);
struct msm_pinctrl_info *pinctrl_info = &pdata->pinctrl_info;
+ int ret_pinctrl = 0;
dev_dbg(rtd->card->dev,
"%s: substream = %s stream = %d, dai name %s, dai ID %d\n",
@@ -4488,11 +4493,10 @@ static int msm_mi2s_snd_startup(struct snd_pcm_substream *substream)
goto done;
}
if (index == QUAT_MI2S) {
- ret = msm_set_pinctrl(pinctrl_info, STATE_MI2S_ACTIVE);
- if (ret) {
+ ret_pinctrl = msm_set_pinctrl(pinctrl_info, STATE_MI2S_ACTIVE);
+ if (ret_pinctrl) {
pr_err("%s: MI2S TLMM pinctrl set failed with %d\n",
- __func__, ret);
- goto done;
+ __func__, ret_pinctrl);
}
}
@@ -4551,6 +4555,7 @@ static void msm_mi2s_snd_shutdown(struct snd_pcm_substream *substream)
struct snd_soc_card *card = rtd->card;
struct msm_asoc_mach_data *pdata = snd_soc_card_get_drvdata(card);
struct msm_pinctrl_info *pinctrl_info = &pdata->pinctrl_info;
+ int ret_pinctrl = 0;
pr_debug("%s(): substream = %s stream = %d\n", __func__,
substream->name, substream->stream);
@@ -4571,10 +4576,10 @@ static void msm_mi2s_snd_shutdown(struct snd_pcm_substream *substream)
mutex_unlock(&mi2s_intf_conf[index].lock);
if (index == QUAT_MI2S) {
- ret = msm_set_pinctrl(pinctrl_info, STATE_DISABLE);
- if (ret)
+ ret_pinctrl = msm_set_pinctrl(pinctrl_info, STATE_DISABLE);
+ if (ret_pinctrl)
pr_err("%s: MI2S TLMM pinctrl set failed with %d\n",
- __func__, ret);
+ __func__, ret_pinctrl);
}
}
diff --git a/sound/soc/msm/qdsp6v2/msm-dai-slim.c b/sound/soc/msm/qdsp6v2/msm-dai-slim.c
index 43a27eb35a44..64ecd7e031f0 100644
--- a/sound/soc/msm/qdsp6v2/msm-dai-slim.c
+++ b/sound/soc/msm/qdsp6v2/msm-dai-slim.c
@@ -1,5 +1,5 @@
/*
- * 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
@@ -314,7 +314,7 @@ static int msm_dai_slim_prepare(struct snd_pcm_substream *substream,
struct msm_slim_dai_data *dai_data = NULL;
struct slim_ch prop;
int rc;
- u8 i;
+ u8 i, j;
dai_data = msm_slim_get_dai_data(drv_data, dai);
if (!dai_data) {
@@ -351,10 +351,6 @@ static int msm_dai_slim_prepare(struct snd_pcm_substream *substream,
}
}
- /* To decrement the channel ref count*/
- for (i = 0; i < dai_data->ch_cnt; i++)
- slim_dealloc_ch(drv_data->sdev, dai_data->chan_h[i]);
-
prop.prot = SLIM_AUTO_ISO;
prop.baser = SLIM_RATE_4000HZ;
prop.dataf = SLIM_CH_DATAF_NOT_DEFINED;
@@ -378,6 +374,8 @@ static int msm_dai_slim_prepare(struct snd_pcm_substream *substream,
error_define_chan:
error_chan_query:
+ for (j = 0; j < i; j++)
+ slim_dealloc_ch(drv_data->sdev, dai_data->chan_h[j]);
return rc;
}
@@ -387,6 +385,7 @@ static void msm_dai_slim_shutdown(struct snd_pcm_substream *stream,
struct msm_dai_slim_drv_data *drv_data = dev_get_drvdata(dai->dev);
struct msm_slim_dma_data *dma_data = NULL;
struct msm_slim_dai_data *dai_data;
+ int i, rc = 0;
dai_data = msm_slim_get_dai_data(drv_data, dai);
dma_data = snd_soc_dai_get_dma_data(dai, stream);
@@ -405,6 +404,15 @@ static void msm_dai_slim_shutdown(struct snd_pcm_substream *stream,
return;
}
+ for (i = 0; i < dai_data->ch_cnt; i++) {
+ rc = slim_dealloc_ch(drv_data->sdev, dai_data->chan_h[i]);
+ if (rc) {
+ dev_err(dai->dev,
+ "%s: dealloc_ch failed, err = %d\n",
+ __func__, rc);
+ }
+ }
+
snd_soc_dai_set_dma_data(dai, stream, NULL);
/* clear prepared state for the dai */
CLR_DAI_STATE(dai_data->status, DAI_STATE_PREPARED);
diff --git a/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c b/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c
index 7ce73484a681..08c78f91920e 100644
--- a/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c
+++ b/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c
@@ -7933,6 +7933,9 @@ static const struct snd_kcontrol_new aux_pcm_rx_port_mixer_controls[] = {
SOC_SINGLE_EXT("SEC_AUX_PCM_UL_TX", MSM_BACKEND_DAI_AUXPCM_RX,
MSM_BACKEND_DAI_SEC_AUXPCM_TX, 1, 0, msm_routing_get_port_mixer,
msm_routing_put_port_mixer),
+ SOC_SINGLE_EXT("QUAT_TDM_TX_0", MSM_BACKEND_DAI_AUXPCM_RX,
+ MSM_BACKEND_DAI_QUAT_TDM_TX_0, 1, 0, msm_routing_get_port_mixer,
+ msm_routing_put_port_mixer),
};
static const struct snd_kcontrol_new sec_auxpcm_rx_port_mixer_controls[] = {
@@ -13325,6 +13328,7 @@ static const struct snd_soc_dapm_route intercon[] = {
{"SLIM7_UL_HL", NULL, "HFP_SLIM7_UL_HL"},
{"HFP_SLIM7_UL_HL", "Switch", "SLIMBUS_7_TX"},
{"AUX_PCM_RX", NULL, "AUXPCM_DL_HL"},
+ {"AUX_PCM_RX", NULL, "INTHFP_DL_HL"},
{"AUXPCM_UL_HL", NULL, "AUX_PCM_TX"},
{"MI2S_RX", NULL, "MI2S_DL_HL"},
{"MI2S_UL_HL", NULL, "MI2S_TX"},
@@ -13729,6 +13733,7 @@ static const struct snd_soc_dapm_route intercon[] = {
{"AUX_PCM_RX Port Mixer", "SLIM_0_TX", "SLIMBUS_0_TX"},
{"AUX_PCM_RX Port Mixer", "SLIM_1_TX", "SLIMBUS_1_TX"},
{"AUX_PCM_RX Port Mixer", "SEC_AUX_PCM_UL_TX", "SEC_AUX_PCM_TX"},
+ {"AUX_PCM_RX Port Mixer", "QUAT_TDM_TX_0", "QUAT_TDM_TX_0"},
{"AUX_PCM_RX", NULL, "AUX_PCM_RX Port Mixer"},
{"SEC_AUXPCM_RX Port Mixer", "AUX_PCM_UL_TX", "AUX_PCM_TX"},
diff --git a/sound/soc/msm/qdsp6v2/q6afe.c b/sound/soc/msm/qdsp6v2/q6afe.c
index 6616edcd3347..f0a78dc8aee8 100644
--- a/sound/soc/msm/qdsp6v2/q6afe.c
+++ b/sound/soc/msm/qdsp6v2/q6afe.c
@@ -5193,7 +5193,7 @@ static int afe_sidetone(u16 tx_port_id, u16 rx_port_id, bool enable)
AFE_API_VERSION_LOOPBACK_CONFIG;
cmd_sidetone.cfg_data.dst_port_id = rx_port_id;
cmd_sidetone.cfg_data.routing_mode = LB_MODE_SIDETONE;
- cmd_sidetone.cfg_data.enable = ((enable == 1) ? sidetone_enable : 0);
+ cmd_sidetone.cfg_data.enable = enable;
pr_debug("%s rx(0x%x) tx(0x%x) enable(%d) mid(0x%x) gain(%d) sidetone_enable(%d)\n",
__func__, rx_port_id, tx_port_id,
diff --git a/sound/soc/msm/sdm660-common.c b/sound/soc/msm/sdm660-common.c
index edf5719fbf3e..90b661dff7ec 100644
--- a/sound/soc/msm/sdm660-common.c
+++ b/sound/soc/msm/sdm660-common.c
@@ -2412,9 +2412,6 @@ static void update_mi2s_clk_val(int dai_id, int stream)
mi2s_clk[dai_id].clk_freq_in_hz =
mi2s_tx_cfg[dai_id].sample_rate * 2 * bit_per_sample;
}
-
- if (!mi2s_intf_conf[dai_id].msm_is_mi2s_master)
- mi2s_clk[dai_id].clk_freq_in_hz = 0;
}
static int msm_mi2s_set_sclk(struct snd_pcm_substream *substream, bool enable)
diff --git a/sound/usb/Makefile b/sound/usb/Makefile
index d2ac0386d3da..083887ba0346 100644
--- a/sound/usb/Makefile
+++ b/sound/usb/Makefile
@@ -13,7 +13,8 @@ snd-usb-audio-objs := card.o \
pcm.o \
proc.o \
quirks.o \
- stream.o
+ stream.o \
+ badd.o
snd-usbmidi-lib-objs := midi.o
diff --git a/sound/usb/badd.c b/sound/usb/badd.c
new file mode 100644
index 000000000000..cc6c26cbb624
--- /dev/null
+++ b/sound/usb/badd.c
@@ -0,0 +1,137 @@
+/*
+ * 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/usb.h>
+#include <linux/usb/audio.h>
+#include <linux/usb/audio-v2.h>
+#include <linux/usb/audio-v3.h>
+
+struct uac3_input_terminal_descriptor badd_baif_in_term_desc = {
+ .bLength = UAC3_DT_INPUT_TERMINAL_SIZE,
+ .bDescriptorType = USB_DT_CS_INTERFACE,
+ .bDescriptorSubtype = UAC_INPUT_TERMINAL,
+ .bTerminalID = BADD_IN_TERM_ID_BAIF,
+ .bCSourceID = BADD_CLOCK_SOURCE,
+ .wExTerminalDescrID = 0x0000,
+ .wTerminalDescrStr = 0x0000
+};
+
+struct uac3_input_terminal_descriptor badd_baof_in_term_desc = {
+ .bLength = UAC3_DT_INPUT_TERMINAL_SIZE,
+ .bDescriptorType = USB_DT_CS_INTERFACE,
+ .bDescriptorSubtype = UAC_INPUT_TERMINAL,
+ .bTerminalID = BADD_IN_TERM_ID_BAOF,
+ .wTerminalType = UAC_TERMINAL_STREAMING,
+ .bAssocTerminal = 0x00,
+ .bCSourceID = BADD_CLOCK_SOURCE,
+ .bmControls = 0x00000000,
+ .wExTerminalDescrID = 0x0000,
+ .wConnectorsDescrID = 0x0000,
+ .wTerminalDescrStr = 0x0000
+};
+
+struct uac3_output_terminal_descriptor badd_baif_out_term_desc = {
+ .bLength = UAC3_DT_OUTPUT_TERMINAL_SIZE,
+ .bDescriptorType = USB_DT_CS_INTERFACE,
+ .bDescriptorSubtype = UAC_OUTPUT_TERMINAL,
+ .bTerminalID = BADD_OUT_TERM_ID_BAIF,
+ .wTerminalType = UAC_TERMINAL_STREAMING,
+ .bAssocTerminal = 0x00, /* No associated terminal */
+ .bSourceID = BADD_FU_ID_BAIF,
+ .bCSourceID = BADD_CLOCK_SOURCE,
+ .bmControls = 0x00000000, /* No controls */
+ .wExTerminalDescrID = 0x0000,
+ .wConnectorsDescrID = 0x0000,
+ .wTerminalDescrStr = 0x0000
+};
+
+struct uac3_output_terminal_descriptor badd_baof_out_term_desc = {
+ .bLength = UAC3_DT_OUTPUT_TERMINAL_SIZE,
+ .bDescriptorType = USB_DT_CS_INTERFACE,
+ .bDescriptorSubtype = UAC_OUTPUT_TERMINAL,
+ .bTerminalID = BADD_OUT_TERM_ID_BAOF,
+ .bSourceID = BADD_FU_ID_BAOF,
+ .bCSourceID = BADD_CLOCK_SOURCE,
+ .wExTerminalDescrID = 0x0000,
+ .wTerminalDescrStr = 0x0000
+};
+
+__u8 monoControls[] = {
+ 0x03, 0x00, 0x00, 0x00,
+ 0x0c, 0x00, 0x00, 0x00};
+
+__u8 stereoControls[] = {
+ 0x03, 0x00, 0x00, 0x00,
+ 0x0c, 0x00, 0x00, 0x00,
+ 0x0c, 0x00, 0x00, 0x00
+};
+
+__u8 badd_mu_src_ids[] = {BADD_IN_TERM_ID_BAOF, BADD_FU_ID_BAIOF};
+
+struct uac3_mixer_unit_descriptor badd_baiof_mu_desc = {
+ .bLength = UAC3_DT_MIXER_UNIT_SIZE,
+ .bDescriptorType = USB_DT_CS_INTERFACE,
+ .bDescriptorSubtype = UAC3_MIXER_UNIT_V3,
+ .bUnitID = BADD_MU_ID_BAIOF,
+ .bNrInPins = 0x02,
+ .baSourceID = badd_mu_src_ids,
+ .bmMixerControls = 0x00,
+ .bmControls = 0x00000000,
+ .wMixerDescrStr = 0x0000
+};
+
+struct uac3_feature_unit_descriptor badd_baif_fu_desc = {
+ .bDescriptorType = USB_DT_CS_INTERFACE,
+ .bDescriptorSubtype = UAC3_FEATURE_UNIT_V3,
+ .bUnitID = BADD_FU_ID_BAIF,
+ .bSourceID = BADD_IN_TERM_ID_BAIF,
+ .wFeatureDescrStr = 0x0000
+};
+
+struct uac3_feature_unit_descriptor badd_baof_fu_desc = {
+ .bDescriptorType = USB_DT_CS_INTERFACE,
+ .bDescriptorSubtype = UAC3_FEATURE_UNIT_V3,
+ .bUnitID = BADD_FU_ID_BAOF,
+ .wFeatureDescrStr = 0x0000
+};
+
+struct uac3_feature_unit_descriptor badd_baiof_fu_desc = {
+ .bLength = 0x0f,
+ .bDescriptorType = USB_DT_CS_INTERFACE,
+ .bDescriptorSubtype = UAC3_FEATURE_UNIT_V3,
+ .bUnitID = BADD_FU_ID_BAIOF,
+ .bSourceID = BADD_IN_TERM_ID_BAIF,
+ .bmaControls = monoControls,
+ .wFeatureDescrStr = 0x0000
+};
+
+struct uac3_clock_source_descriptor badd_clock_desc = {
+ .bLength = UAC3_DT_CLOCK_SRC_SIZE,
+ .bDescriptorType = USB_DT_CS_INTERFACE,
+ .bDescriptorSubtype = UAC3_CLOCK_SOURCE,
+ .bClockID = BADD_CLOCK_SOURCE,
+ .bmControls = 0x00000001,
+ .bReferenceTerminal = 0x00,
+ .wClockSourceStr = 0x0000
+};
+
+void *badd_desc_list[] = {
+ &badd_baif_in_term_desc,
+ &badd_baof_in_term_desc,
+ &badd_baiof_mu_desc,
+ &badd_baif_fu_desc,
+ &badd_baof_fu_desc,
+ &badd_baiof_fu_desc,
+ &badd_clock_desc
+};
+
diff --git a/sound/usb/card.c b/sound/usb/card.c
index 7bc935bab369..23ea575f3bcf 100644
--- a/sound/usb/card.c
+++ b/sound/usb/card.c
@@ -45,6 +45,7 @@
#include <linux/usb/audio.h>
#include <linux/usb/audio-v2.h>
#include <linux/module.h>
+#include <linux/usb/audio-v3.h>
#include <sound/control.h>
#include <sound/core.h>
@@ -281,7 +282,6 @@ static int snd_usb_create_streams(struct snd_usb_audio *chip, int ctrlif)
struct usb_host_interface *host_iface;
struct usb_interface_descriptor *altsd;
struct usb_interface *usb_iface;
- void *control_header;
int i, protocol;
usb_iface = usb_ifnum_to_if(dev, ctrlif);
@@ -298,16 +298,13 @@ static int snd_usb_create_streams(struct snd_usb_audio *chip, int ctrlif)
return -EINVAL;
}
- control_header = snd_usb_find_csint_desc(host_iface->extra,
- host_iface->extralen,
- NULL, UAC_HEADER);
altsd = get_iface_desc(host_iface);
protocol = altsd->bInterfaceProtocol;
- if (!control_header) {
- dev_err(&dev->dev, "cannot find UAC_HEADER\n");
- return -EINVAL;
- }
+ /*
+ * UAC 1.0 devices use AC HEADER Desc for linking AS interfaces;
+ * UAC 2.0 and 3.0 devices use IAD for linking AS interfaces
+ */
switch (protocol) {
default:
@@ -317,8 +314,17 @@ static int snd_usb_create_streams(struct snd_usb_audio *chip, int ctrlif)
/* fall through */
case UAC_VERSION_1: {
- struct uac1_ac_header_descriptor *h1 = control_header;
+ void *control_header;
+ struct uac1_ac_header_descriptor *h1;
+
+ control_header = snd_usb_find_csint_desc(host_iface->extra,
+ host_iface->extralen, NULL, UAC_HEADER);
+ if (!control_header) {
+ dev_err(&dev->dev, "cannot find UAC_HEADER\n");
+ return -EINVAL;
+ }
+ h1 = control_header;
if (!h1->bInCollection) {
dev_info(&dev->dev, "skipping empty audio interface (v1)\n");
return -EINVAL;
@@ -335,7 +341,8 @@ static int snd_usb_create_streams(struct snd_usb_audio *chip, int ctrlif)
break;
}
- case UAC_VERSION_2: {
+ case UAC_VERSION_2:
+ case UAC_VERSION_3: {
struct usb_interface_assoc_descriptor *assoc =
usb_iface->intf_assoc;
if (!assoc) {
@@ -354,7 +361,8 @@ static int snd_usb_create_streams(struct snd_usb_audio *chip, int ctrlif)
}
if (!assoc) {
- dev_err(&dev->dev, "Audio class v2 interfaces need an interface association\n");
+ dev_err(&dev->dev, "Audio class V%d interfaces need an interface association\n",
+ protocol);
return -EINVAL;
}
@@ -554,6 +562,15 @@ static int usb_audio_probe(struct usb_interface *intf,
struct usb_host_interface *alts;
int ifnum;
u32 id;
+ struct usb_interface_assoc_descriptor *assoc;
+
+ assoc = intf->intf_assoc;
+ if (assoc && assoc->bFunctionClass == USB_CLASS_AUDIO &&
+ assoc->bFunctionProtocol == UAC_VERSION_3 &&
+ assoc->bFunctionSubClass == FULL_ADC_PROFILE) {
+ dev_info(&dev->dev, "No support for full-fledged ADC 3.0 yet!!\n");
+ return -EINVAL;
+ }
alts = &intf->altsetting[0];
ifnum = get_iface_desc(alts)->bInterfaceNumber;
diff --git a/sound/usb/clock.c b/sound/usb/clock.c
index 7ccbcaf6a147..2cd09ceba5e9 100644
--- a/sound/usb/clock.c
+++ b/sound/usb/clock.c
@@ -424,6 +424,10 @@ int snd_usb_init_sample_rate(struct snd_usb_audio *chip, int iface,
case UAC_VERSION_2:
return set_sample_rate_v2(chip, iface, alts, fmt, rate);
+
+ /* Clock rate is fixed at 48 kHz for BADD devices */
+ case UAC_VERSION_3:
+ return 0;
}
}
diff --git a/sound/usb/format.c b/sound/usb/format.c
index 789d19ec035d..2cc3b92f1fba 100644
--- a/sound/usb/format.c
+++ b/sound/usb/format.c
@@ -20,6 +20,7 @@
#include <linux/usb.h>
#include <linux/usb/audio.h>
#include <linux/usb/audio-v2.h>
+#include <linux/usb/audio-v3.h>
#include <sound/core.h>
#include <sound/pcm.h>
@@ -69,6 +70,30 @@ static u64 parse_audio_format_i_type(struct snd_usb_audio *chip,
format <<= 1;
break;
}
+
+ case UAC_VERSION_3: {
+ switch (fp->maxpacksize) {
+ case BADD_MAXPSIZE_SYNC_MONO_16:
+ case BADD_MAXPSIZE_SYNC_STEREO_16:
+ case BADD_MAXPSIZE_ASYNC_MONO_16:
+ case BADD_MAXPSIZE_ASYNC_STEREO_16: {
+ sample_width = BIT_RES_16_BIT;
+ sample_bytes = SUBSLOTSIZE_16_BIT;
+ break;
+ }
+
+ case BADD_MAXPSIZE_SYNC_MONO_24:
+ case BADD_MAXPSIZE_SYNC_STEREO_24:
+ case BADD_MAXPSIZE_ASYNC_MONO_24:
+ case BADD_MAXPSIZE_ASYNC_STEREO_24: {
+ sample_width = BIT_RES_24_BIT;
+ sample_bytes = SUBSLOTSIZE_24_BIT;
+ break;
+ }
+ }
+ format = 1 << format;
+ break;
+ }
}
if ((pcm_formats == 0) &&
@@ -366,6 +391,22 @@ err:
return ret;
}
+static int badd_set_audio_rate_v3(struct snd_usb_audio *chip,
+ struct audioformat *fp)
+{
+ unsigned int rate;
+
+ fp->rate_table = kmalloc(sizeof(int), GFP_KERNEL);
+ if (fp->rate_table == NULL)
+ return -ENOMEM;
+
+ fp->nr_rates = 1;
+ rate = BADD_SAMPLING_RATE;
+ fp->rate_min = fp->rate_max = fp->rate_table[0] = rate;
+ fp->rates |= snd_pcm_rate_to_rate_bit(rate);
+ return 0;
+}
+
/*
* parse the format type I and III descriptors
*/
@@ -415,6 +456,9 @@ static int parse_audio_format_i(struct snd_usb_audio *chip,
/* fp->channels is already set in this case */
ret = parse_audio_format_rates_v2(chip, fp);
break;
+ case UAC_VERSION_3:
+ ret = badd_set_audio_rate_v3(chip, fp);
+ break;
}
if (fp->channels < 1) {
@@ -502,7 +546,10 @@ int snd_usb_parse_audio_format(struct snd_usb_audio *chip,
fmt->bFormatType);
return -ENOTSUPP;
}
- fp->fmt_type = fmt->bFormatType;
+ if (fp->protocol == UAC_VERSION_3)
+ fp->fmt_type = UAC_FORMAT_TYPE_I;
+ else
+ fp->fmt_type = fmt->bFormatType;
if (err < 0)
return err;
#if 1
diff --git a/sound/usb/mixer.c b/sound/usb/mixer.c
index 157c0704817c..b9d9d2e99c78 100644
--- a/sound/usb/mixer.c
+++ b/sound/usb/mixer.c
@@ -50,6 +50,7 @@
#include <linux/usb.h>
#include <linux/usb/audio.h>
#include <linux/usb/audio-v2.h>
+#include <linux/usb/audio-v3.h>
#include <sound/core.h>
#include <sound/control.h>
@@ -184,6 +185,17 @@ static void *find_audio_control_unit(struct mixer_build *state,
/* we just parse the header */
struct uac_feature_unit_descriptor *hdr = NULL;
+ if (state->mixer->protocol == UAC_VERSION_3) {
+ int i;
+
+ for (i = 0; i < NUM_BADD_DESCS; i++) {
+ hdr = (void *)badd_desc_list[i];
+ if (hdr->bUnitID == unit)
+ return hdr;
+ }
+
+ return NULL;
+ }
while ((hdr = snd_usb_find_desc(state->buffer, state->buflen, hdr,
USB_DT_CS_INTERFACE)) != NULL) {
if (hdr->bLength >= 4 &&
@@ -717,7 +729,7 @@ static int check_input_term(struct mixer_build *state, int id,
term->channels = d->bNrChannels;
term->chconfig = le16_to_cpu(d->wChannelConfig);
term->name = d->iTerminal;
- } else { /* UAC_VERSION_2 */
+ } else if (state->mixer->protocol == UAC_VERSION_2) {
struct uac2_input_terminal_descriptor *d = p1;
/* call recursively to verify that the
@@ -734,6 +746,24 @@ static int check_input_term(struct mixer_build *state, int id,
term->channels = d->bNrChannels;
term->chconfig = le32_to_cpu(d->bmChannelConfig);
term->name = d->iTerminal;
+ } else { /* UAC_VERSION_3 */
+ struct uac3_input_terminal_descriptor *d = p1;
+
+ err = check_input_term(state,
+ d->bCSourceID, term);
+ if (err < 0)
+ return err;
+
+ term->id = id;
+ term->type = d->wTerminalType;
+ if (d->wClusterDescrID == CLUSTER_ID_MONO) {
+ term->channels = NUM_CHANNELS_MONO;
+ term->chconfig = BADD_CH_CONFIG_MONO;
+ } else {
+ term->channels = NUM_CHANNELS_STEREO;
+ term->chconfig = BADD_CH_CONFIG_STEREO;
+ }
+ term->name = d->wTerminalDescrStr;
}
return 0;
case UAC_FEATURE_UNIT: {
@@ -751,41 +781,81 @@ static int check_input_term(struct mixer_build *state, int id,
return 0;
}
case UAC_SELECTOR_UNIT:
- case UAC2_CLOCK_SELECTOR: {
- struct uac_selector_unit_descriptor *d = p1;
- /* call recursively to retrieve the channel info */
- err = check_input_term(state, d->baSourceID[0], term);
- if (err < 0)
- return err;
- term->type = d->bDescriptorSubtype << 16; /* virtual type */
- term->id = id;
- term->name = uac_selector_unit_iSelector(d);
+ /* UAC3_MIXER_UNIT_V3 */
+ case UAC2_CLOCK_SELECTOR:
+ /* UAC3_CLOCK_SOURCE */ {
+ if (state->mixer->protocol == UAC_VERSION_3
+ && hdr[2] == UAC3_CLOCK_SOURCE) {
+ struct uac3_clock_source_descriptor *d = p1;
+
+ term->type = d->bDescriptorSubtype << 16;
+ term->id = id;
+ term->name = d->wClockSourceStr;
+ } else if (state->mixer->protocol == UAC_VERSION_3
+ && hdr[2] == UAC3_MIXER_UNIT_V3) {
+ struct uac3_mixer_unit_descriptor *d = p1;
+
+ term->type = d->bDescriptorSubtype << 16;
+ if (d->wClusterDescrID == CLUSTER_ID_MONO) {
+ term->channels = NUM_CHANNELS_MONO;
+ term->chconfig = BADD_CH_CONFIG_MONO;
+ } else {
+ term->channels = NUM_CHANNELS_STEREO;
+ term->chconfig = BADD_CH_CONFIG_STEREO;
+ }
+ term->name = d->wMixerDescrStr;
+ } else {
+ struct uac_selector_unit_descriptor *d = p1;
+ /* call recursively to retrieve channel info */
+ err = check_input_term(state,
+ d->baSourceID[0], term);
+ if (err < 0)
+ return err;
+ /* virtual type */
+ term->type = d->bDescriptorSubtype << 16;
+ term->id = id;
+ term->name = uac_selector_unit_iSelector(d);
+ }
return 0;
}
case UAC1_PROCESSING_UNIT:
case UAC1_EXTENSION_UNIT:
/* UAC2_PROCESSING_UNIT_V2 */
/* UAC2_EFFECT_UNIT */
+ /* UAC3_FEATURE_UNIT_V3 */
case UAC2_EXTENSION_UNIT_V2: {
- struct uac_processing_unit_descriptor *d = p1;
+ if (state->mixer->protocol == UAC_VERSION_3) {
+ struct uac_feature_unit_descriptor *d = p1;
+
+ id = d->bSourceID;
+ } else {
+ struct uac_processing_unit_descriptor *d = p1;
+
+ if (state->mixer->protocol == UAC_VERSION_2 &&
+ hdr[2] == UAC2_EFFECT_UNIT) {
+ /* UAC2/UAC1 unit IDs overlap here in an
+ * uncompatible way. Ignore this unit
+ * for now.
+ */
+ return 0;
+ }
- if (state->mixer->protocol == UAC_VERSION_2 &&
- hdr[2] == UAC2_EFFECT_UNIT) {
- /* UAC2/UAC1 unit IDs overlap here in an
- * uncompatible way. Ignore this unit for now.
- */
+ if (d->bNrInPins) {
+ id = d->baSourceID[0];
+ break; /* continue to parse */
+ }
+ /* virtual type */
+ term->type = d->bDescriptorSubtype << 16;
+ term->channels =
+ uac_processing_unit_bNrChannels(d);
+ term->chconfig =
+ uac_processing_unit_wChannelConfig(
+ d, state->mixer->protocol);
+ term->name = uac_processing_unit_iProcessing(
+ d, state->mixer->protocol);
return 0;
}
-
- if (d->bNrInPins) {
- id = d->baSourceID[0];
- break; /* continue to parse */
- }
- term->type = d->bDescriptorSubtype << 16; /* virtual type */
- term->channels = uac_processing_unit_bNrChannels(d);
- term->chconfig = uac_processing_unit_wChannelConfig(d, state->mixer->protocol);
- term->name = uac_processing_unit_iProcessing(d, state->mixer->protocol);
- return 0;
+ break;
}
case UAC2_CLOCK_SOURCE: {
struct uac_clock_source_descriptor *d = p1;
@@ -1232,12 +1302,18 @@ static void build_feature_ctl(struct mixer_build *state, void *raw_desc,
struct usb_feature_control_info *ctl_info;
unsigned int len = 0;
int mapped_name = 0;
- int nameid = uac_feature_unit_iFeature(desc);
+ int nameid;
struct snd_kcontrol *kctl;
struct usb_mixer_elem_info *cval;
const struct usbmix_name_map *map;
unsigned int range;
+ if (state->mixer->protocol == UAC_VERSION_3)
+ nameid = ((struct uac3_feature_unit_descriptor *)
+ raw_desc)->wFeatureDescrStr;
+ else
+ nameid = uac_feature_unit_iFeature(desc);
+
control++; /* change from zero-based to 1-based value */
if (control == UAC_FU_GRAPHIC_EQUALIZER) {
@@ -1258,7 +1334,7 @@ static void build_feature_ctl(struct mixer_build *state, void *raw_desc,
ctl_info = &audio_feature_info[control-1];
if (state->mixer->protocol == UAC_VERSION_1)
cval->val_type = ctl_info->type;
- else /* UAC_VERSION_2 */
+ else /* UAC_VERSION_2 or UAC_VERSION_3*/
cval->val_type = ctl_info->type_uac2 >= 0 ?
ctl_info->type_uac2 : ctl_info->type;
@@ -1381,6 +1457,62 @@ static void build_feature_ctl(struct mixer_build *state, void *raw_desc,
snd_usb_mixer_add_control(&cval->head, kctl);
}
+static int find_num_channels(struct mixer_build *state, int dir)
+{
+ int num_ch = -EINVAL, num, i, j, wMaxPacketSize;
+ int ctrlif = get_iface_desc(state->mixer->hostif)->bInterfaceNumber;
+ struct usb_interface *usb_iface =
+ usb_ifnum_to_if(state->mixer->chip->dev, ctrlif);
+ struct usb_interface_assoc_descriptor *assoc = usb_iface->intf_assoc;
+ struct usb_host_interface *alts;
+
+ for (i = 0; i < assoc->bInterfaceCount; i++) {
+ int intf = assoc->bFirstInterface + i;
+
+ if (intf != ctrlif) {
+ struct usb_interface *iface =
+ usb_ifnum_to_if(state->mixer->chip->dev, intf);
+
+ alts = &iface->altsetting[1];
+ if (dir == USB_DIR_OUT &&
+ get_endpoint(alts, 0)->bEndpointAddress &
+ USB_DIR_IN)
+ continue;
+ if (dir == USB_DIR_IN &&
+ !(get_endpoint(alts, 0)->bEndpointAddress &
+ USB_DIR_IN))
+ continue;
+ num = iface->num_altsetting;
+ for (j = 1; j < num; j++) {
+ num_ch = NUM_CHANNELS_MONO;
+ alts = &iface->altsetting[j];
+ wMaxPacketSize = le16_to_cpu(
+ get_endpoint(alts, 0)->
+ wMaxPacketSize);
+ switch (wMaxPacketSize) {
+ case BADD_MAXPSIZE_SYNC_MONO_16:
+ case BADD_MAXPSIZE_SYNC_MONO_24:
+ case BADD_MAXPSIZE_ASYNC_MONO_16:
+ case BADD_MAXPSIZE_ASYNC_MONO_24:
+ break;
+ case BADD_MAXPSIZE_SYNC_STEREO_16:
+ case BADD_MAXPSIZE_SYNC_STEREO_24:
+ case BADD_MAXPSIZE_ASYNC_STEREO_16:
+ case BADD_MAXPSIZE_ASYNC_STEREO_24:
+ num_ch = NUM_CHANNELS_STEREO;
+ break;
+ }
+ if (num_ch == NUM_CHANNELS_MONO)
+ continue;
+ else
+ break;
+ }
+ }
+ }
+
+ return num_ch;
+}
+
/*
* parse a feature unit
*
@@ -1412,7 +1544,7 @@ static int parse_audio_feature_unit(struct mixer_build *state, int unitid,
unitid);
return -EINVAL;
}
- } else {
+ } else if (state->mixer->protocol == UAC_VERSION_2) {
struct uac2_feature_unit_descriptor *ftr = _ftr;
csize = 4;
channels = (hdr->bLength - 6) / 4 - 1;
@@ -1423,11 +1555,114 @@ static int parse_audio_feature_unit(struct mixer_build *state, int unitid,
unitid);
return -EINVAL;
}
+ } else {
+ struct usb_interface *usb_iface =
+ usb_ifnum_to_if(state->mixer->chip->dev,
+ get_iface_desc(state->mixer->hostif)->bInterfaceNumber);
+ struct usb_interface_assoc_descriptor *assoc =
+ usb_iface->intf_assoc;
+
+ csize = 4;
+ switch (unitid) {
+ case BADD_FU_ID_BAIOF:
+ channels = NUM_CHANNELS_MONO;
+ bmaControls = monoControls;
+ badd_baif_in_term_desc.wClusterDescrID =
+ CLUSTER_ID_MONO;
+ break;
+
+ case BADD_FU_ID_BAOF:
+ switch (assoc->bFunctionSubClass) {
+ case PROF_HEADPHONE:
+ case PROF_HEADSET_ADAPTER:
+ channels = NUM_CHANNELS_STEREO;
+ bmaControls = stereoControls;
+ badd_baiof_mu_desc.wClusterDescrID =
+ CLUSTER_ID_MONO;
+ break;
+ case PROF_SPEAKERPHONE:
+ channels = NUM_CHANNELS_MONO;
+ bmaControls = monoControls;
+ badd_baof_in_term_desc.wClusterDescrID =
+ CLUSTER_ID_MONO;
+ break;
+ default:
+ channels = find_num_channels(state,
+ USB_DIR_OUT);
+ if (channels < 0) {
+ usb_audio_err(state->chip,
+ "unit %u: Cant find num of channels\n",
+ unitid);
+ return channels;
+ }
+
+ bmaControls = (channels == NUM_CHANNELS_MONO) ?
+ monoControls : stereoControls;
+ badd_baof_in_term_desc.wClusterDescrID =
+ (channels == NUM_CHANNELS_MONO) ?
+ CLUSTER_ID_MONO : CLUSTER_ID_STEREO;
+ break;
+ }
+ break;
+
+ case BADD_FU_ID_BAIF:
+ switch (assoc->bFunctionSubClass) {
+ case PROF_HEADSET:
+ case PROF_HEADSET_ADAPTER:
+ case PROF_SPEAKERPHONE:
+ channels = NUM_CHANNELS_MONO;
+ bmaControls = monoControls;
+ badd_baif_in_term_desc.wClusterDescrID =
+ CLUSTER_ID_MONO;
+ break;
+ default:
+ channels = find_num_channels(state, USB_DIR_IN);
+ if (channels < 0) {
+ usb_audio_err(state->chip,
+ "unit %u: Cant find num of channels\n",
+ unitid);
+ return channels;
+ }
+
+ bmaControls = (channels == NUM_CHANNELS_MONO) ?
+ monoControls : stereoControls;
+ badd_baif_in_term_desc.wClusterDescrID =
+ (channels == NUM_CHANNELS_MONO) ?
+ CLUSTER_ID_MONO : CLUSTER_ID_STEREO;
+ break;
+ }
+ break;
+ }
}
/* parse the source unit */
- if ((err = parse_audio_unit(state, hdr->bSourceID)) < 0)
- return err;
+ if (state->mixer->protocol != UAC_VERSION_3) {
+ err = parse_audio_unit(state, hdr->bSourceID);
+ if (err < 0)
+ return err;
+ } else {
+ struct usb_interface *usb_iface =
+ usb_ifnum_to_if(state->mixer->chip->dev,
+ get_iface_desc(state->mixer->hostif)->bInterfaceNumber);
+ struct usb_interface_assoc_descriptor *assoc =
+ usb_iface->intf_assoc;
+
+ switch (unitid) {
+ case BADD_FU_ID_BAOF:
+ switch (assoc->bFunctionSubClass) {
+ case PROF_HEADSET:
+ case PROF_HEADSET_ADAPTER:
+ hdr->bSourceID = BADD_MU_ID_BAIOF;
+ break;
+ default:
+ hdr->bSourceID = BADD_IN_TERM_ID_BAOF;
+ break;
+ }
+ }
+ err = parse_audio_unit(state, hdr->bSourceID);
+ if (err < 0)
+ return err;
+ }
/* determine the input source type and name */
err = check_input_term(state, hdr->bSourceID, &iterm);
@@ -1481,7 +1716,7 @@ static int parse_audio_feature_unit(struct mixer_build *state, int unitid,
build_feature_ctl(state, _ftr, 0, i, &iterm,
unitid, 0);
}
- } else { /* UAC_VERSION_2 */
+ } else { /* UAC_VERSION_2 or UAC_VERSION_3*/
for (i = 0; i < ARRAY_SIZE(audio_feature_info); i++) {
unsigned int ch_bits = 0;
unsigned int ch_read_only = 0;
@@ -1599,12 +1834,19 @@ static int parse_audio_mixer_unit(struct mixer_build *state, int unitid,
int input_pins, num_ins, num_outs;
int pin, ich, err;
- if (desc->bLength < 11 || !(input_pins = desc->bNrInPins) ||
- !(num_outs = uac_mixer_unit_bNrChannels(desc))) {
- usb_audio_err(state->chip,
- "invalid MIXER UNIT descriptor %d\n",
- unitid);
- return -EINVAL;
+ if (state->mixer->protocol == UAC_VERSION_3) {
+ input_pins = badd_baiof_mu_desc.bNrInPins;
+ num_outs =
+ (badd_baiof_mu_desc.wClusterDescrID == CLUSTER_ID_MONO) ?
+ NUM_CHANNELS_MONO : NUM_CHANNELS_STEREO;
+ } else {
+ if (desc->bLength < 11 || !(input_pins = desc->bNrInPins) ||
+ !(num_outs = uac_mixer_unit_bNrChannels(desc))) {
+ usb_audio_err(state->chip,
+ "invalid MIXER UNIT descriptor %d\n",
+ unitid);
+ return -EINVAL;
+ }
}
num_ins = 0;
@@ -1624,9 +1866,14 @@ static int parse_audio_mixer_unit(struct mixer_build *state, int unitid,
int och, ich_has_controls = 0;
for (och = 0; och < num_outs; och++) {
- __u8 *c = uac_mixer_unit_bmControls(desc,
- state->mixer->protocol);
+ __u8 *c = NULL;
+ if (state->mixer->protocol == UAC_VERSION_3)
+ c =
+ &(badd_baiof_mu_desc.bmMixerControls);
+ else
+ c = uac_mixer_unit_bmControls(desc,
+ state->mixer->protocol);
if (check_matrix_bitmap(c, ich, och, num_outs)) {
ich_has_controls = 1;
break;
@@ -2134,16 +2381,28 @@ static int parse_audio_unit(struct mixer_build *state, int unitid)
case UAC_MIXER_UNIT:
return parse_audio_mixer_unit(state, unitid, p1);
case UAC_SELECTOR_UNIT:
+ /* UAC3_MIXER_UNIT_V3 has the same value */
case UAC2_CLOCK_SELECTOR:
- return parse_audio_selector_unit(state, unitid, p1);
+ /* UAC3_CLOCK_SOURCE has the same value */
+ if (state->mixer->protocol == UAC_VERSION_3 &&
+ p1[2] == UAC3_CLOCK_SOURCE)
+ return 0; /* NOP */
+ else if (state->mixer->protocol == UAC_VERSION_3
+ && p1[2] == UAC3_MIXER_UNIT_V3)
+ return parse_audio_mixer_unit(state, unitid, p1);
+ else
+ return parse_audio_selector_unit(state, unitid, p1);
case UAC_FEATURE_UNIT:
return parse_audio_feature_unit(state, unitid, p1);
case UAC1_PROCESSING_UNIT:
/* UAC2_EFFECT_UNIT has the same value */
+ /* UAC3_FEATURE_UNIT_V3 has the same value */
if (state->mixer->protocol == UAC_VERSION_1)
return parse_audio_processing_unit(state, unitid, p1);
- else
+ else if (state->mixer->protocol == UAC_VERSION_2)
return 0; /* FIXME - effect units not implemented yet */
+ else
+ return parse_audio_feature_unit(state, unitid, p1);
case UAC1_EXTENSION_UNIT:
/* UAC2_PROCESSING_UNIT_V2 has the same value */
if (state->mixer->protocol == UAC_VERSION_1)
@@ -2178,6 +2437,23 @@ static int snd_usb_mixer_dev_free(struct snd_device *device)
return 0;
}
+static int make_out_term(struct mixer_build state, int wTerminalType)
+{
+ struct uac3_output_terminal_descriptor *desc = NULL;
+
+ if (wTerminalType == UAC_TERMINAL_STREAMING)
+ desc = &badd_baif_out_term_desc;
+ else {
+ desc = &badd_baof_out_term_desc;
+ desc->wTerminalType = wTerminalType;
+ }
+ set_bit(desc->bTerminalID, state.unitbitmap);
+ state.oterm.id = desc->bTerminalID;
+ state.oterm.type = desc->wTerminalType;
+ state.oterm.name = desc->wTerminalDescrStr;
+ return parse_audio_unit(&state, desc->bSourceID);
+}
+
/*
* create mixer controls
*
@@ -2186,9 +2462,8 @@ static int snd_usb_mixer_dev_free(struct snd_device *device)
static int snd_usb_mixer_controls(struct usb_mixer_interface *mixer)
{
struct mixer_build state;
- int err;
+ int err = -EINVAL;
const struct usbmix_ctl_map *map;
- void *p;
memset(&state, 0, sizeof(state));
state.chip = mixer->chip;
@@ -2206,44 +2481,108 @@ static int snd_usb_mixer_controls(struct usb_mixer_interface *mixer)
}
}
- p = NULL;
- while ((p = snd_usb_find_csint_desc(mixer->hostif->extra,
- mixer->hostif->extralen,
- p, UAC_OUTPUT_TERMINAL)) != NULL) {
- if (mixer->protocol == UAC_VERSION_1) {
- struct uac1_output_terminal_descriptor *desc = p;
-
- if (desc->bLength < sizeof(*desc))
- continue; /* invalid descriptor? */
- /* mark terminal ID as visited */
- set_bit(desc->bTerminalID, state.unitbitmap);
- state.oterm.id = desc->bTerminalID;
- state.oterm.type = le16_to_cpu(desc->wTerminalType);
- state.oterm.name = desc->iTerminal;
- err = parse_audio_unit(&state, desc->bSourceID);
+ if (mixer->protocol == UAC_VERSION_3) {
+ struct usb_interface *usb_iface =
+ usb_ifnum_to_if(mixer->chip->dev,
+ get_iface_desc(mixer->hostif)->bInterfaceNumber);
+ struct usb_interface_assoc_descriptor *assoc =
+ usb_iface->intf_assoc;
+
+ switch (assoc->bFunctionSubClass) {
+ case PROF_GENERIC_IO: {
+ if (assoc->bInterfaceCount == 0x02) {
+ if (get_endpoint(mixer->hostif,
+ 0)->bEndpointAddress | USB_DIR_IN)
+ err = make_out_term(state,
+ UAC_TERMINAL_STREAMING);
+ else
+ err = make_out_term(state,
+ UAC_OUTPUT_TERMINAL_UNDEFINED);
+ } else {
+ err = make_out_term(state,
+ UAC_OUTPUT_TERMINAL_UNDEFINED);
+ if (err < 0 && err != -EINVAL)
+ return err;
+ err = make_out_term(state,
+ UAC_TERMINAL_STREAMING);
+ }
+ break;
+ }
+
+ case PROF_HEADPHONE:
+ err = make_out_term(state,
+ UAC_OUTPUT_TERMINAL_HEADPHONES);
+ break;
+ case PROF_SPEAKER:
+ err = make_out_term(state, UAC_OUTPUT_TERMINAL_SPEAKER);
+ break;
+ case PROF_MICROPHONE:
+ err = make_out_term(state, UAC_TERMINAL_STREAMING);
+ break;
+ case PROF_HEADSET:
+ case PROF_HEADSET_ADAPTER:
+ err = make_out_term(state, UAC_BIDIR_TERMINAL_HEADSET);
if (err < 0 && err != -EINVAL)
return err;
- } else { /* UAC_VERSION_2 */
- struct uac2_output_terminal_descriptor *desc = p;
-
- if (desc->bLength < sizeof(*desc))
- continue; /* invalid descriptor? */
- /* mark terminal ID as visited */
- set_bit(desc->bTerminalID, state.unitbitmap);
- state.oterm.id = desc->bTerminalID;
- state.oterm.type = le16_to_cpu(desc->wTerminalType);
- state.oterm.name = desc->iTerminal;
- err = parse_audio_unit(&state, desc->bSourceID);
+ err = make_out_term(state, UAC_TERMINAL_STREAMING);
+ break;
+ case PROF_SPEAKERPHONE:
+ err = make_out_term(state,
+ UAC_BIDIR_TERMINAL_SPEAKERPHONE);
if (err < 0 && err != -EINVAL)
return err;
+ err = make_out_term(state, UAC_TERMINAL_STREAMING);
+ break;
+ }
+ if (err < 0 && err != -EINVAL)
+ return err;
+ } else {
+ void *p;
+
+ p = NULL;
+ while ((p = snd_usb_find_csint_desc(mixer->hostif->extra,
+ mixer->hostif->extralen, p,
+ UAC_OUTPUT_TERMINAL)) != NULL) {
+ if (mixer->protocol == UAC_VERSION_1) {
+ struct uac1_output_terminal_descriptor *desc =
+ p;
+
+ if (desc->bLength < sizeof(*desc))
+ continue; /* invalid descriptor? */
+ /* mark terminal ID as visited */
+ set_bit(desc->bTerminalID, state.unitbitmap);
+ state.oterm.id = desc->bTerminalID;
+ state.oterm.type =
+ le16_to_cpu(desc->wTerminalType);
+ state.oterm.name = desc->iTerminal;
+ err = parse_audio_unit(&state, desc->bSourceID);
+ if (err < 0 && err != -EINVAL)
+ return err;
+ } else { /* UAC_VERSION_2 */
+ struct uac2_output_terminal_descriptor *desc =
+ p;
+
+ if (desc->bLength < sizeof(*desc))
+ continue; /* invalid descriptor? */
+ /* mark terminal ID as visited */
+ set_bit(desc->bTerminalID, state.unitbitmap);
+ state.oterm.id = desc->bTerminalID;
+ state.oterm.type =
+ le16_to_cpu(desc->wTerminalType);
+ state.oterm.name = desc->iTerminal;
+ err = parse_audio_unit(&state, desc->bSourceID);
+ if (err < 0 && err != -EINVAL)
+ return err;
- /*
- * For UAC2, use the same approach to also add the
- * clock selectors
- */
- err = parse_audio_unit(&state, desc->bCSourceID);
- if (err < 0 && err != -EINVAL)
- return err;
+ /*
+ * For UAC2, use the same approach to also add
+ * the clock selectors
+ */
+ err = parse_audio_unit(&state,
+ desc->bCSourceID);
+ if (err < 0 && err != -EINVAL)
+ return err;
+ }
}
}
@@ -2478,6 +2817,9 @@ int snd_usb_create_mixer(struct snd_usb_audio *chip, int ctrlif,
case UAC_VERSION_2:
mixer->protocol = UAC_VERSION_2;
break;
+ case UAC_VERSION_3:
+ mixer->protocol = UAC_VERSION_3;
+ break;
}
if ((err = snd_usb_mixer_controls(mixer)) < 0 ||
diff --git a/sound/usb/stream.c b/sound/usb/stream.c
index 98b2c28ae46b..2bb503576134 100644
--- a/sound/usb/stream.c
+++ b/sound/usb/stream.c
@@ -20,6 +20,7 @@
#include <linux/usb.h>
#include <linux/usb/audio.h>
#include <linux/usb/audio-v2.h>
+#include <linux/usb/audio-v3.h>
#include <sound/core.h>
#include <sound/pcm.h>
@@ -284,8 +285,6 @@ static struct snd_pcm_chmap_elem *convert_chmap(int channels, unsigned int bits,
0 /* terminator */
};
struct snd_pcm_chmap_elem *chmap;
- const unsigned int *maps;
- int c;
if (channels > ARRAY_SIZE(chmap->map))
return NULL;
@@ -294,27 +293,42 @@ static struct snd_pcm_chmap_elem *convert_chmap(int channels, unsigned int bits,
if (!chmap)
return NULL;
- maps = protocol == UAC_VERSION_2 ? uac2_maps : uac1_maps;
chmap->channels = channels;
- c = 0;
- if (bits) {
- for (; bits && *maps; maps++, bits >>= 1)
- if (bits & 1)
- chmap->map[c++] = *maps;
+ if (protocol == UAC_VERSION_3) {
+ switch (channels) {
+ case 1:
+ chmap->map[0] = SNDRV_CHMAP_MONO;
+ break;
+ case 2:
+ chmap->map[0] = SNDRV_CHMAP_FL;
+ chmap->map[1] = SNDRV_CHMAP_FR;
+ break;
+ }
} else {
- /* If we're missing wChannelConfig, then guess something
- to make sure the channel map is not skipped entirely */
- if (channels == 1)
- chmap->map[c++] = SNDRV_CHMAP_MONO;
- else
- for (; c < channels && *maps; maps++)
- chmap->map[c++] = *maps;
+ int c = 0;
+ const unsigned int *maps =
+ protocol == UAC_VERSION_2 ? uac2_maps : uac1_maps;
+
+ if (bits) {
+ for (; bits && *maps; maps++, bits >>= 1)
+ if (bits & 1)
+ chmap->map[c++] = *maps;
+ } else {
+ /*
+ * If we're missing wChannelConfig, then guess something
+ * to make sure the channel map is not skipped entirely
+ */
+ if (channels == 1)
+ chmap->map[c++] = SNDRV_CHMAP_MONO;
+ else
+ for (; c < channels && *maps; maps++)
+ chmap->map[c++] = *maps;
+ }
+ for (; c < channels; c++)
+ chmap->map[c] = SNDRV_CHMAP_UNKNOWN;
}
- for (; c < channels; c++)
- chmap->map[c] = SNDRV_CHMAP_UNKNOWN;
-
return chmap;
}
@@ -411,6 +425,9 @@ static int parse_uac_endpoint_attributes(struct snd_usb_audio *chip,
struct usb_interface_descriptor *altsd = get_iface_desc(alts);
int attributes = 0;
+ if (protocol == UAC_VERSION_3)
+ return 0;
+
csep = snd_usb_find_desc(alts->endpoint[0].extra, alts->endpoint[0].extralen, NULL, USB_DT_CS_ENDPOINT);
/* Creamware Noah has this descriptor after the 2nd endpoint */
@@ -631,6 +648,39 @@ int snd_usb_parse_audio_interface(struct snd_usb_audio *chip, int iface_no)
iface_no, altno, as->bTerminalLink);
continue;
}
+
+ case UAC_VERSION_3: {
+ int wMaxPacketSize;
+
+ format = UAC_FORMAT_TYPE_I_PCM;
+ clock = BADD_CLOCK_SOURCE;
+ wMaxPacketSize = le16_to_cpu(get_endpoint(alts, 0)
+ ->wMaxPacketSize);
+ switch (wMaxPacketSize) {
+ case BADD_MAXPSIZE_SYNC_MONO_16:
+ case BADD_MAXPSIZE_SYNC_MONO_24:
+ case BADD_MAXPSIZE_ASYNC_MONO_16:
+ case BADD_MAXPSIZE_ASYNC_MONO_24: {
+ num_channels = NUM_CHANNELS_MONO;
+ chconfig = BADD_CH_CONFIG_MONO;
+ goto populate_fp;
+ }
+
+ case BADD_MAXPSIZE_SYNC_STEREO_16:
+ case BADD_MAXPSIZE_SYNC_STEREO_24:
+ case BADD_MAXPSIZE_ASYNC_STEREO_16:
+ case BADD_MAXPSIZE_ASYNC_STEREO_24: {
+ num_channels = NUM_CHANNELS_STEREO;
+ chconfig = BADD_CH_CONFIG_STEREO;
+ goto populate_fp;
+ }
+ default:
+ dev_err(&dev->dev,
+ "%u:%d: invalid wMaxPacketSize\n",
+ iface_no, altno);
+ continue;
+ }
+ }
}
/* get format type */
@@ -664,6 +714,7 @@ int snd_usb_parse_audio_interface(struct snd_usb_audio *chip, int iface_no)
fp->maxpacksize * 2)
continue;
+populate_fp:
fp = kzalloc(sizeof(*fp), GFP_KERNEL);
if (! fp) {
dev_err(&dev->dev, "cannot malloc\n");
diff --git a/sound/usb/usb_audio_qmi_svc.c b/sound/usb/usb_audio_qmi_svc.c
index a495a7f6cb22..14ea2239fe11 100644
--- a/sound/usb/usb_audio_qmi_svc.c
+++ b/sound/usb/usb_audio_qmi_svc.c
@@ -28,6 +28,7 @@
#include <linux/iommu.h>
#include <linux/qcom_iommu.h>
#include <linux/platform_device.h>
+#include <linux/usb/audio-v3.h>
#include "usbaudio.h"
#include "card.h"
@@ -428,12 +429,14 @@ static int prepare_qmi_response(struct snd_usb_substream *subs,
protocol = altsd->bInterfaceProtocol;
/* get format type */
- fmt = snd_usb_find_csint_desc(alts->extra, alts->extralen, NULL,
- UAC_FORMAT_TYPE);
- if (!fmt) {
- pr_err("%s: %u:%d : no UAC_FORMAT_TYPE desc\n", __func__,
- subs->interface, subs->altset_idx);
- goto err;
+ if (protocol != UAC_VERSION_3) {
+ fmt = snd_usb_find_csint_desc(alts->extra, alts->extralen, NULL,
+ UAC_FORMAT_TYPE);
+ if (!fmt) {
+ pr_err("%s: %u:%d : no UAC_FORMAT_TYPE desc\n",
+ __func__, subs->interface, subs->altset_idx);
+ goto err;
+ }
}
if (!uadev[card_num].ctrl_intf) {
@@ -441,12 +444,15 @@ static int prepare_qmi_response(struct snd_usb_substream *subs,
goto err;
}
- hdr_ptr = snd_usb_find_csint_desc(uadev[card_num].ctrl_intf->extra,
- uadev[card_num].ctrl_intf->extralen,
- NULL, UAC_HEADER);
- if (!hdr_ptr) {
- pr_err("%s: no UAC_HEADER desc\n", __func__);
- goto err;
+ if (protocol != UAC_VERSION_3) {
+ hdr_ptr = snd_usb_find_csint_desc(
+ uadev[card_num].ctrl_intf->extra,
+ uadev[card_num].ctrl_intf->extralen,
+ NULL, UAC_HEADER);
+ if (!hdr_ptr) {
+ pr_err("%s: no UAC_HEADER desc\n", __func__);
+ goto err;
+ }
}
if (protocol == UAC_VERSION_1) {
@@ -474,6 +480,25 @@ static int prepare_qmi_response(struct snd_usb_substream *subs,
resp->usb_audio_spec_revision =
((struct uac2_ac_header_descriptor *)hdr_ptr)->bcdADC;
resp->usb_audio_spec_revision_valid = 1;
+ } else if (protocol == UAC_VERSION_3) {
+ switch (le16_to_cpu(get_endpoint(alts, 0)->wMaxPacketSize)) {
+ case BADD_MAXPSIZE_SYNC_MONO_16:
+ case BADD_MAXPSIZE_SYNC_STEREO_16:
+ case BADD_MAXPSIZE_ASYNC_MONO_16:
+ case BADD_MAXPSIZE_ASYNC_STEREO_16: {
+ resp->usb_audio_subslot_size = SUBSLOTSIZE_16_BIT;
+ break;
+ }
+
+ case BADD_MAXPSIZE_SYNC_MONO_24:
+ case BADD_MAXPSIZE_SYNC_STEREO_24:
+ case BADD_MAXPSIZE_ASYNC_MONO_24:
+ case BADD_MAXPSIZE_ASYNC_STEREO_24: {
+ resp->usb_audio_subslot_size = SUBSLOTSIZE_24_BIT;
+ break;
+ }
+ }
+ resp->usb_audio_subslot_size_valid = 1;
} else {
pr_err("%s: unknown protocol version %x\n", __func__, protocol);
goto err;