summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Documentation/devicetree/bindings/arm/msm/qcom,osm.txt10
-rw-r--r--Documentation/devicetree/bindings/clock/qcom,mmcc.txt1
-rw-r--r--Documentation/devicetree/bindings/fb/mdss-dsi-panel.txt7
-rw-r--r--Documentation/devicetree/bindings/media/video/msm-vidc.txt16
-rw-r--r--Documentation/devicetree/bindings/power/qcom-charger/qpnp-fg-gen3.txt8
-rw-r--r--Documentation/devicetree/bindings/power/qcom-charger/qpnp-smb2.txt8
-rw-r--r--Documentation/devicetree/bindings/regulator/cprh-kbss-regulator.txt18
-rw-r--r--Documentation/devicetree/bindings/ufs/ufshcd-pltfrm.txt4
-rw-r--r--arch/arm/boot/dts/qcom/Makefile3
-rw-r--r--arch/arm/boot/dts/qcom/apq8998-v2.1-mediabox.dts30
-rw-r--r--arch/arm/boot/dts/qcom/fg-gen3-batterydata-ascent-3450mah.dtsi76
-rw-r--r--arch/arm/boot/dts/qcom/fg-gen3-batterydata-demo-6000mah.dtsi78
-rw-r--r--arch/arm/boot/dts/qcom/msm-audio.dtsi838
-rw-r--r--arch/arm/boot/dts/qcom/msm-pm3falcon.dtsi16
-rw-r--r--arch/arm/boot/dts/qcom/msm-pmfalcon.dtsi213
-rw-r--r--arch/arm/boot/dts/qcom/msm8998-camera-sensor-qrd-vr1.dtsi1
-rw-r--r--arch/arm/boot/dts/qcom/msm8998-camera-sensor-skuk.dtsi2
-rw-r--r--arch/arm/boot/dts/qcom/msm8998-interposer-camera-sensor-cdp.dtsi224
-rw-r--r--arch/arm/boot/dts/qcom/msm8998-interposer-camera-sensor-mtp.dtsi224
-rw-r--r--arch/arm/boot/dts/qcom/msm8998-interposer-msmfalcon-audio.dtsi73
-rw-r--r--arch/arm/boot/dts/qcom/msm8998-interposer-msmfalcon-cdp.dtsi8
-rw-r--r--arch/arm/boot/dts/qcom/msm8998-interposer-msmfalcon-mtp.dtsi8
-rw-r--r--arch/arm/boot/dts/qcom/msm8998-interposer-msmfalcon.dtsi17
-rw-r--r--arch/arm/boot/dts/qcom/msm8998-interposer-pmfalcon.dtsi19
-rw-r--r--arch/arm/boot/dts/qcom/msm8998-mtp.dtsi1
-rw-r--r--arch/arm/boot/dts/qcom/msm8998-pinctrl.dtsi46
-rw-r--r--arch/arm/boot/dts/qcom/msm8998-qrd-skuk.dtsi129
-rw-r--r--arch/arm/boot/dts/qcom/msm8998-qrd-vr1.dtsi129
-rw-r--r--arch/arm/boot/dts/qcom/msm8998-qrd.dtsi1
-rw-r--r--arch/arm/boot/dts/qcom/msm8998-v2-interposer-msmfalcon.dtsi19
-rw-r--r--arch/arm/boot/dts/qcom/msm8998-v2.1-interposer-msmfalcon-cdp.dts64
-rw-r--r--arch/arm/boot/dts/qcom/msm8998-v2.1-interposer-msmfalcon-mtp.dts64
-rw-r--r--arch/arm/boot/dts/qcom/msm8998-v2.1-interposer-msmfalcon-qrd.dtsi6
-rw-r--r--arch/arm/boot/dts/qcom/msm8998-v2.dtsi544
-rw-r--r--arch/arm/boot/dts/qcom/msm8998.dtsi9
-rw-r--r--arch/arm/boot/dts/qcom/msmfalcon-audio.dtsi136
-rw-r--r--arch/arm/boot/dts/qcom/msmfalcon-pinctrl.dtsi61
-rw-r--r--arch/arm/boot/dts/qcom/msmfalcon-regulator.dtsi10
-rw-r--r--arch/arm/boot/dts/qcom/msmfalcon-rumi.dts17
-rw-r--r--arch/arm/boot/dts/qcom/msmfalcon-sim.dts12
-rw-r--r--arch/arm/boot/dts/qcom/msmfalcon-vidc.dtsi268
-rw-r--r--arch/arm/boot/dts/qcom/msmfalcon-wcd.dtsi183
-rw-r--r--arch/arm/boot/dts/qcom/msmfalcon-wsa881x.dtsi79
-rw-r--r--arch/arm/boot/dts/qcom/msmfalcon.dtsi395
-rw-r--r--arch/arm/boot/dts/qcom/msmtriton-rumi.dts5
-rw-r--r--arch/arm/boot/dts/qcom/msmtriton.dtsi67
-rw-r--r--arch/arm/configs/msmfalcon-perf_defconfig607
-rw-r--r--arch/arm/configs/msmfalcon_defconfig78
-rw-r--r--arch/arm/mach-qcom/Kconfig4
-rw-r--r--arch/arm64/configs/msmfalcon-perf_defconfig2
-rw-r--r--arch/arm64/configs/msmfalcon_defconfig2
-rw-r--r--arch/arm64/mm/fault.c3
-rw-r--r--block/genhd.c1
-rw-r--r--block/ioprio.c2
-rw-r--r--drivers/char/diag/diagfwd.c2
-rw-r--r--drivers/char/diag/diagfwd_peripheral.c12
-rw-r--r--drivers/char/diag/diagfwd_smd.c5
-rw-r--r--drivers/clk/clk.c51
-rw-r--r--drivers/clk/msm/clock-osm.c150
-rw-r--r--drivers/clk/msm/clock.h2
-rw-r--r--drivers/clk/msm/mdss/mdss-hdmi-pll-8998.c246
-rw-r--r--drivers/clk/qcom/Kconfig10
-rw-r--r--drivers/clk/qcom/Makefile1
-rw-r--r--drivers/clk/qcom/clk-branch.c9
-rw-r--r--drivers/clk/qcom/clk-cpu-osm.c3301
-rw-r--r--drivers/clk/qcom/clk-smd-rpm.c19
-rw-r--r--drivers/clk/qcom/mmcc-msmfalcon.c3036
-rw-r--r--drivers/clk/qcom/vdd-level-falcon.h15
-rw-r--r--drivers/crypto/msm/qce50.c47
-rw-r--r--drivers/crypto/msm/qcedev.c120
-rw-r--r--drivers/devfreq/governor_msm_adreno_tz.c5
-rw-r--r--drivers/gpu/msm/adreno-gpulist.h16
-rw-r--r--drivers/gpu/msm/adreno.h2
-rw-r--r--drivers/gpu/msm/adreno_a5xx.c7
-rw-r--r--drivers/gpu/msm/adreno_a5xx_preempt.c16
-rw-r--r--drivers/gpu/msm/adreno_iommu.c11
-rw-r--r--drivers/gpu/msm/kgsl.c4
-rw-r--r--drivers/gpu/msm/kgsl_sharedmem.h3
-rw-r--r--drivers/hid/hid-core.c3
-rw-r--r--drivers/input/touchscreen/synaptics_dsx/synaptics_dsx_fw_update.c96
-rw-r--r--drivers/media/platform/msm/camera_v2/common/cam_smmu_api.c722
-rw-r--r--drivers/media/platform/msm/camera_v2/common/cam_smmu_api.h59
-rw-r--r--drivers/media/platform/msm/camera_v2/isp/msm_isp.h4
-rw-r--r--drivers/media/platform/msm/camera_v2/isp/msm_isp40.c83
-rw-r--r--drivers/media/platform/msm/camera_v2/isp/msm_isp47.c80
-rw-r--r--drivers/media/platform/msm/camera_v2/isp/msm_isp47.h2
-rw-r--r--drivers/media/platform/msm/camera_v2/isp/msm_isp48.c2
-rw-r--r--drivers/media/platform/msm/camera_v2/isp/msm_isp_axi_util.c93
-rw-r--r--drivers/media/platform/msm/camera_v2/isp/msm_isp_axi_util.h3
-rw-r--r--drivers/media/platform/msm/camera_v2/isp/msm_isp_util.c48
-rw-r--r--drivers/media/platform/msm/camera_v2/ispif/msm_ispif.c3
-rw-r--r--drivers/media/platform/msm/camera_v2/jpeg_10/msm_jpeg_dev.c18
-rw-r--r--drivers/media/platform/msm/camera_v2/jpeg_10/msm_jpeg_hw.c2
-rw-r--r--drivers/media/platform/msm/camera_v2/jpeg_dma/msm_jpeg_dma_dev.c23
-rw-r--r--drivers/media/platform/msm/camera_v2/pproc/cpp/msm_cpp.c150
-rw-r--r--drivers/media/platform/msm/camera_v2/pproc/cpp/msm_cpp.h3
-rw-r--r--drivers/media/platform/msm/camera_v2/sensor/cci/msm_cci.c12
-rw-r--r--drivers/media/platform/msm/sde/rotator/sde_rotator_core.c2
-rw-r--r--drivers/media/platform/msm/sde/rotator/sde_rotator_r3.c20
-rw-r--r--drivers/media/platform/msm/vidc/governors/msm_vidc_table_gov.c16
-rw-r--r--drivers/media/platform/msm/vidc/msm_vidc.c10
-rw-r--r--drivers/media/platform/msm/vidc/msm_vidc_common.c9
-rw-r--r--drivers/media/platform/msm/vidc/venus_hfi.c14
-rw-r--r--drivers/media/tuners/tuner-xc2028.c3
-rw-r--r--drivers/misc/hdcp.c171
-rw-r--r--drivers/misc/qcom/qdsp6v2/Makefile3
-rw-r--r--drivers/misc/qcom/qdsp6v2/audio_amrnb.c50
-rw-r--r--drivers/misc/qcom/qdsp6v2/audio_amrwb.c50
-rw-r--r--drivers/misc/qcom/qdsp6v2/audio_g711alaw.c396
-rw-r--r--drivers/misc/qcom/qdsp6v2/audio_g711mlaw.c396
-rw-r--r--drivers/misc/qcom/qdsp6v2/g711alaw_in.c382
-rw-r--r--drivers/misc/qcom/qdsp6v2/g711mlaw_in.c385
-rw-r--r--drivers/misc/qseecom.c215
-rw-r--r--drivers/mmc/card/block.c13
-rw-r--r--drivers/mmc/core/core.c6
-rw-r--r--drivers/mmc/host/cmdq_hci.c10
-rw-r--r--drivers/mmc/host/sdhci.c2
-rw-r--r--drivers/net/wireless/ath/wil6210/ftm.c97
-rw-r--r--drivers/net/wireless/ath/wil6210/ftm.h10
-rw-r--r--drivers/pinctrl/qcom/pinctrl-msm8998.c28
-rw-r--r--drivers/platform/msm/gsi/gsi.c30
-rw-r--r--drivers/platform/msm/ipa/ipa_api.c16
-rw-r--r--drivers/platform/msm/ipa/ipa_api.h2
-rw-r--r--drivers/platform/msm/ipa/ipa_v2/ipa_i.h1
-rw-r--r--drivers/platform/msm/ipa/ipa_v2/ipa_utils.c15
-rw-r--r--drivers/platform/msm/ipa/ipa_v3/ipa.c10
-rw-r--r--drivers/platform/msm/ipa/ipa_v3/ipa_i.h1
-rw-r--r--drivers/platform/msm/ipa/ipa_v3/ipa_utils.c15
-rw-r--r--drivers/power/qcom-charger/fg-core.h2
-rw-r--r--drivers/power/qcom-charger/qpnp-fg-gen3.c33
-rw-r--r--drivers/power/qcom-charger/qpnp-smb2.c44
-rw-r--r--drivers/power/qcom-charger/smb-lib.c27
-rw-r--r--drivers/regulator/cpr3-regulator.h11
-rw-r--r--drivers/regulator/cpr3-util.c70
-rw-r--r--drivers/regulator/cprh-kbss-regulator.c77
-rw-r--r--drivers/scsi/ufs/ufs-qcom.c8
-rw-r--r--drivers/scsi/ufs/ufshcd-pltfrm.c21
-rw-r--r--drivers/scsi/ufs/ufshcd.c89
-rw-r--r--drivers/scsi/ufs/ufshcd.h1
-rw-r--r--drivers/soc/qcom/Kconfig8
-rw-r--r--drivers/soc/qcom/gladiator_erp_v2.c8
-rw-r--r--drivers/soc/qcom/msm_bus/msm_bus_arb_adhoc.c2
-rw-r--r--drivers/soc/qcom/rpm-smd.c2
-rw-r--r--drivers/soc/qcom/scm.c10
-rw-r--r--drivers/soc/qcom/socinfo.c11
-rw-r--r--drivers/staging/android/ion/ion_cma_heap.c7
-rw-r--r--drivers/tty/tty_ldisc.c7
-rw-r--r--drivers/usb/dwc3/dwc3-msm.c9
-rw-r--r--drivers/usb/gadget/Kconfig9
-rw-r--r--drivers/usb/gadget/function/Makefile2
-rw-r--r--drivers/usb/gadget/function/f_fs.c10
-rw-r--r--drivers/usb/gadget/function/f_gsi.c4
-rw-r--r--drivers/usb/gadget/function/f_qdss.h8
-rw-r--r--drivers/usb/gadget/function/f_rmnet.c776
-rw-r--r--drivers/usb/gadget/function/u_ctrl_qti.c172
-rw-r--r--drivers/usb/gadget/function/u_data_ipa.c8
-rw-r--r--drivers/usb/gadget/function/u_data_ipa.h10
-rw-r--r--drivers/usb/gadget/function/u_rmnet.h48
-rw-r--r--drivers/usb/pd/Kconfig1
-rw-r--r--drivers/usb/pd/policy_engine.c531
-rw-r--r--drivers/usb/pd/qpnp-pdphy.c17
-rw-r--r--drivers/video/fbdev/msm/mdp3_ctrl.c8
-rw-r--r--drivers/video/fbdev/msm/mdss.h2
-rw-r--r--drivers/video/fbdev/msm/mdss_compat_utils.c2
-rw-r--r--drivers/video/fbdev/msm/mdss_dba_utils.c4
-rw-r--r--drivers/video/fbdev/msm/mdss_debug.c12
-rw-r--r--drivers/video/fbdev/msm/mdss_dp.c107
-rw-r--r--drivers/video/fbdev/msm/mdss_dp.h1
-rw-r--r--drivers/video/fbdev/msm/mdss_dp_hdcp2p2.c145
-rw-r--r--drivers/video/fbdev/msm/mdss_dp_util.c3
-rw-r--r--drivers/video/fbdev/msm/mdss_dp_util.h1
-rw-r--r--drivers/video/fbdev/msm/mdss_dsi.c49
-rw-r--r--drivers/video/fbdev/msm/mdss_dsi.h2
-rw-r--r--drivers/video/fbdev/msm/mdss_dsi_host.c30
-rw-r--r--drivers/video/fbdev/msm/mdss_dsi_panel.c3
-rw-r--r--drivers/video/fbdev/msm/mdss_fb.c40
-rw-r--r--drivers/video/fbdev/msm/mdss_fb.h1
-rw-r--r--drivers/video/fbdev/msm/mdss_hdcp_1x.c797
-rw-r--r--drivers/video/fbdev/msm/mdss_hdmi_edid.c142
-rw-r--r--drivers/video/fbdev/msm/mdss_hdmi_edid.h1
-rw-r--r--drivers/video/fbdev/msm/mdss_hdmi_hdcp2p2.c3
-rw-r--r--drivers/video/fbdev/msm/mdss_hdmi_panel.c54
-rw-r--r--drivers/video/fbdev/msm/mdss_hdmi_panel.h2
-rw-r--r--drivers/video/fbdev/msm/mdss_hdmi_tx.c313
-rw-r--r--drivers/video/fbdev/msm/mdss_hdmi_util.c29
-rw-r--r--drivers/video/fbdev/msm/mdss_hdmi_util.h2
-rw-r--r--drivers/video/fbdev/msm/mdss_mdp.c65
-rw-r--r--drivers/video/fbdev/msm/mdss_mdp.h15
-rw-r--r--drivers/video/fbdev/msm/mdss_mdp_cdm.c42
-rw-r--r--drivers/video/fbdev/msm/mdss_mdp_cdm.h3
-rw-r--r--drivers/video/fbdev/msm/mdss_mdp_ctl.c213
-rw-r--r--drivers/video/fbdev/msm/mdss_mdp_intf_cmd.c3
-rw-r--r--drivers/video/fbdev/msm/mdss_mdp_intf_video.c50
-rw-r--r--drivers/video/fbdev/msm/mdss_mdp_intf_writeback.c76
-rw-r--r--drivers/video/fbdev/msm/mdss_mdp_layer.c16
-rw-r--r--drivers/video/fbdev/msm/mdss_mdp_overlay.c188
-rw-r--r--drivers/video/fbdev/msm/mdss_mdp_pipe.c15
-rw-r--r--drivers/video/fbdev/msm/mdss_mdp_pp.c16
-rw-r--r--drivers/video/fbdev/msm/mdss_mdp_util.c9
-rw-r--r--drivers/video/fbdev/msm/mdss_mdp_wfd.c27
-rw-r--r--drivers/video/fbdev/msm/mdss_panel.h14
-rw-r--r--drivers/video/fbdev/msm/msm_mdss_io_8974.c15
-rw-r--r--fs/proc/array.c6
-rw-r--r--include/dt-bindings/clock/audio-ext-clk.h10
-rw-r--r--include/dt-bindings/clock/qcom,mmcc-msmfalcon.h82
-rw-r--r--include/linux/clk-provider.h11
-rw-r--r--include/linux/clk/msm-clk-provider.h4
-rw-r--r--include/linux/clk/msm-clk.h7
-rw-r--r--include/linux/sched.h2
-rw-r--r--include/net/cfg80211.h17
-rw-r--r--include/net/sock.h2
-rw-r--r--include/net/tcp.h2
-rw-r--r--include/sound/apr_audio-v2.h27
-rw-r--r--include/sound/q6asm-v2.h13
-rw-r--r--include/uapi/linux/Kbuild2
-rw-r--r--include/uapi/linux/msm_audio_g711.h17
-rw-r--r--include/uapi/linux/msm_audio_g711_dec.h16
-rw-r--r--include/uapi/linux/msm_mdp_ext.h13
-rw-r--r--include/uapi/media/msm_media_info.h220
-rw-r--r--include/uapi/media/msmb_isp.h30
-rw-r--r--include/uapi/sound/compress_params.h24
-rw-r--r--kernel/auditsc.c332
-rw-r--r--kernel/cgroup.c2
-rw-r--r--kernel/power/qos.c32
-rw-r--r--kernel/sched/core.c15
-rw-r--r--kernel/sched/core_ctl.c10
-rw-r--r--kernel/sched/hmp.c218
-rw-r--r--kernel/sched/sched.h3
-rw-r--r--mm/page_isolation.c3
-rw-r--r--net/core/sock.c14
-rw-r--r--net/netfilter/nfnetlink.c10
-rw-r--r--net/netlink/af_netlink.c37
-rw-r--r--net/netlink/af_netlink.h1
-rw-r--r--net/rmnet_data/rmnet_data_handlers.c2
-rw-r--r--net/wireless/chan.c2
-rw-r--r--net/wireless/core.c17
-rw-r--r--net/wireless/core.h3
-rw-r--r--net/wireless/nl80211.c35
-rw-r--r--net/wireless/reg.c2
-rw-r--r--net/wireless/sme.c6
-rw-r--r--net/wireless/util.c91
-rw-r--r--sound/soc/codecs/Makefile7
-rw-r--r--sound/soc/codecs/audio-ext-clk-up.c577
-rw-r--r--sound/soc/codecs/wcd9335.c1
-rw-r--r--sound/soc/codecs/wcd934x/wcd934x.c21
-rw-r--r--sound/soc/msm/msm-dai-fe.c57
-rw-r--r--sound/soc/msm/qdsp6v2/msm-compress-q6-v2.c613
-rw-r--r--sound/soc/msm/qdsp6v2/msm-dai-q6-v2.c12
-rw-r--r--sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c300
-rw-r--r--sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.h7
-rw-r--r--sound/soc/msm/qdsp6v2/q6asm.c171
-rw-r--r--sound/soc/soc-dapm.c3
252 files changed, 20303 insertions, 3089 deletions
diff --git a/Documentation/devicetree/bindings/arm/msm/qcom,osm.txt b/Documentation/devicetree/bindings/arm/msm/qcom,osm.txt
index adcaa6444ab8..a8334e1cfde7 100644
--- a/Documentation/devicetree/bindings/arm/msm/qcom,osm.txt
+++ b/Documentation/devicetree/bindings/arm/msm/qcom,osm.txt
@@ -289,6 +289,16 @@ Properties:
values per performance mode with a total of 4 tuples
corresponding to each supported performance mode.
+- qcom,perfcl-apcs-mem-acc-threshold-voltage
+ Usage: optional
+ Value type: <u32>
+ Definition: Specifies the highest MEM ACC threshold voltage in
+ microvolts for the Performance cluster. This voltage is
+ used to determine which MEM ACC setting is used for the
+ highest frequencies. If specified, the voltage must match
+ the MEM ACC threshold voltage specified for the
+ corresponding CPRh device.
+
- qcom,red-fsm-en
Usage: optional
Value type: <empty>
diff --git a/Documentation/devicetree/bindings/clock/qcom,mmcc.txt b/Documentation/devicetree/bindings/clock/qcom,mmcc.txt
index 8b0f7841af8d..6aaf89c47781 100644
--- a/Documentation/devicetree/bindings/clock/qcom,mmcc.txt
+++ b/Documentation/devicetree/bindings/clock/qcom,mmcc.txt
@@ -10,6 +10,7 @@ Required properties :
"qcom,mmcc-msm8960"
"qcom,mmcc-msm8974"
"qcom,mmcc-msm8996"
+ "qcom,mmcc-msmfalcon"
- reg : shall contain base register location and length
- #clock-cells : shall contain 1
diff --git a/Documentation/devicetree/bindings/fb/mdss-dsi-panel.txt b/Documentation/devicetree/bindings/fb/mdss-dsi-panel.txt
index 56ad8c361219..0174306135c1 100644
--- a/Documentation/devicetree/bindings/fb/mdss-dsi-panel.txt
+++ b/Documentation/devicetree/bindings/fb/mdss-dsi-panel.txt
@@ -459,7 +459,11 @@ the fps window.
fields in the supply entry, refer to the qcom,ctrl-supply-entries
binding above.
- qcom,config-select: Optional property to select default configuration.
-
+- qcom,panel-allow-phy-poweroff: A boolean property indicates that panel allows to turn off the phy power
+ supply during idle screen. A panel should able to handle the dsi lanes
+ in floating state(not LP00 or LP11) to turn on this property. Software
+ turns off PHY pmic power supply, phy ldo and DSI Lane ldo during
+ idle screen (footswitch control off) when this property is enabled.
[[Optional config sub-nodes]] These subnodes provide different configurations for a given same panel.
Default configuration can be chosen by specifying phandle of the
selected subnode in the qcom,config-select.
@@ -647,6 +651,7 @@ Example:
qcom,suspend-ulps-enabled;
qcom,panel-roi-alignment = <4 4 2 2 20 20>;
qcom,esd-check-enabled;
+ qcom,panel-allow-phy-poweroff;
qcom,mdss-dsi-panel-status-command = [06 01 00 01 05 00 02 0A 08];
qcom,mdss-dsi-panel-status-command-state = "dsi_lp_mode";
qcom,mdss-dsi-panel-status-check-mode = "reg_read";
diff --git a/Documentation/devicetree/bindings/media/video/msm-vidc.txt b/Documentation/devicetree/bindings/media/video/msm-vidc.txt
index b1869803d345..50b9b1ac8704 100644
--- a/Documentation/devicetree/bindings/media/video/msm-vidc.txt
+++ b/Documentation/devicetree/bindings/media/video/msm-vidc.txt
@@ -183,6 +183,9 @@ Optional properties:
- qcom,bus-rage-kbps : an array of two items (<min max>) that indicate the
minimum and maximum acceptable votes for the bus.
In the absence of this property <0 INT_MAX> is used.
+- qcom,ubwc-10bit : UBWC 10 bit content has different bus requirements,
+ this tag will be used to pick the appropriate bus as per the session profile
+ as shown below in example.
Example:
@@ -270,4 +273,17 @@ Example:
qcom,bus-governor = "msm-vidc-ddr";
qcom,bus-range-kbps = <1000 3388000>;
};
+ qcom,profile-dec-ubwc-10bit {
+ qcom,codec-mask = <0xffffffff>;
+ qcom,ubwc-10bit;
+ qcom,load-busfreq-tbl =
+ <979200 2446336>, /* UHD30D */
+ <864000 2108416>, /* 720p240D */
+ <489600 1207296>, /* 1080p60D */
+ <432000 1058816>, /* 720p120D */
+ <244800 616448>, /* 1080p30D */
+ <216000 534528>, /* 720p60D */
+ <108000 271360>, /* 720p30D */
+ <0 0>;
+ };
};
diff --git a/Documentation/devicetree/bindings/power/qcom-charger/qpnp-fg-gen3.txt b/Documentation/devicetree/bindings/power/qcom-charger/qpnp-fg-gen3.txt
index 421379116989..808e18b495d5 100644
--- a/Documentation/devicetree/bindings/power/qcom-charger/qpnp-fg-gen3.txt
+++ b/Documentation/devicetree/bindings/power/qcom-charger/qpnp-fg-gen3.txt
@@ -63,6 +63,14 @@ First Level Node - FG Gen3 device
Definition: The voltage threshold (in mV) which upon set will be used
for configuring the low battery voltage threshold.
+- qcom,fg-recharge-voltage
+ Usage: optional
+ Value type: <u32>
+ Definition: The voltage threshold (in mV) based on which the charging
+ will be resumed once the charging is complete. If this
+ property is not specified, then the default value will be
+ 4250mV.
+
- qcom,fg-chg-term-current
Usage: optional
Value type: <u32>
diff --git a/Documentation/devicetree/bindings/power/qcom-charger/qpnp-smb2.txt b/Documentation/devicetree/bindings/power/qcom-charger/qpnp-smb2.txt
index 9d8670c7594b..382587ea5922 100644
--- a/Documentation/devicetree/bindings/power/qcom-charger/qpnp-smb2.txt
+++ b/Documentation/devicetree/bindings/power/qcom-charger/qpnp-smb2.txt
@@ -138,6 +138,14 @@ Charger specific properties:
then charge inhibit will be disabled by default.
Allowed values are: 50, 100, 200, 300.
+- qcom,auto-recharge-soc
+ Usage: optional
+ Value type: <empty>
+ Definition: Specifies if automatic recharge needs to be based off battery
+ SOC. If this property is not specified, then auto recharge will
+ be based off battery voltage. For both SOC and battery voltage,
+ charger receives the signal from FG to resume charging.
+
=============================================
Second Level Nodes - SMB2 Charger Peripherals
=============================================
diff --git a/Documentation/devicetree/bindings/regulator/cprh-kbss-regulator.txt b/Documentation/devicetree/bindings/regulator/cprh-kbss-regulator.txt
index 8b806f4828bd..5b0770785dbe 100644
--- a/Documentation/devicetree/bindings/regulator/cprh-kbss-regulator.txt
+++ b/Documentation/devicetree/bindings/regulator/cprh-kbss-regulator.txt
@@ -73,6 +73,24 @@ KBSS specific properties:
switching. If this property is not specified, then a value
of 0 is assumed.
+- qcom,mem-acc-threshold-voltage
+ Usage: optional
+ Value type: <u32>
+ Definition: Specifies the highest memory accelerator (MEM ACC) threshold
+ voltage in microvolts. The floor to ceiling voltage range
+ for every corner is adjusted to ensure that it does not
+ intersect this voltage. The value of this property must
+ match with the MEM ACC threshold voltage defined in the OSM
+ device to ensure that MEM ACC settings are switched
+ appropriately.
+
+- qcom,mem-acc-crossover-voltage
+ Usage: required if qcom,mem-acc-threshold-voltage is specified
+ Value type: <u32>
+ Definition: Specifies the MEM ACC crossover voltage in microvolts which
+ corresponds to the voltage the VDD supply must be set to
+ when switching the MEM ACC configuration.
+
- qcom,voltage-base
Usage: required
Value type: <u32>
diff --git a/Documentation/devicetree/bindings/ufs/ufshcd-pltfrm.txt b/Documentation/devicetree/bindings/ufs/ufshcd-pltfrm.txt
index bceee5e1747d..a25961c6e7de 100644
--- a/Documentation/devicetree/bindings/ufs/ufshcd-pltfrm.txt
+++ b/Documentation/devicetree/bindings/ufs/ufshcd-pltfrm.txt
@@ -55,6 +55,10 @@ Optional properties:
- lanes-per-direction: number of lanes available per direction - either 1 or 2.
Note that it is assume same number of lanes is used both directions at once.
If not specified, default is 2 lanes per direction.
+- pinctrl-names, pinctrl-0, pinctrl-1,.. pinctrl-n: Refer to "Documentation/devicetree/bindings/pinctrl/pinctrl-bindings.txt"
+ for these optional properties
+
+
Note: If above properties are not defined it can be assumed that the supply
regulators or clocks are always on.
diff --git a/arch/arm/boot/dts/qcom/Makefile b/arch/arm/boot/dts/qcom/Makefile
index fdab1da887fa..730b76846c9d 100644
--- a/arch/arm/boot/dts/qcom/Makefile
+++ b/arch/arm/boot/dts/qcom/Makefile
@@ -113,7 +113,9 @@ dtb-$(CONFIG_ARCH_MSM8998) += msm8998-sim.dtb \
msm8998-v2-cdp.dtb \
msm8998-v2-qrd.dtb \
msm8998-qrd-skuk.dtb \
+ msm8998-v2-qrd-skuk.dtb \
msm8998-qrd-vr1.dtb \
+ msm8998-v2-qrd-vr1.dtb \
apq8998-mtp.dtb \
apq8998-cdp.dtb \
apq8998-v2-mtp.dtb \
@@ -125,6 +127,7 @@ dtb-$(CONFIG_ARCH_MSM8998) += msm8998-sim.dtb \
apq8998-v2.1-mtp.dtb \
apq8998-v2.1-cdp.dtb \
apq8998-v2.1-qrd.dtb \
+ apq8998-v2.1-mediabox.dtb \
msm8998-v2.1-interposer-msmfalcon-cdp.dtb \
msm8998-v2.1-interposer-msmfalcon-mtp.dtb \
msm8998-v2.1-interposer-msmfalcon-qrd.dtb
diff --git a/arch/arm/boot/dts/qcom/apq8998-v2.1-mediabox.dts b/arch/arm/boot/dts/qcom/apq8998-v2.1-mediabox.dts
new file mode 100644
index 000000000000..bc60d9a08c0b
--- /dev/null
+++ b/arch/arm/boot/dts/qcom/apq8998-v2.1-mediabox.dts
@@ -0,0 +1,30 @@
+/* Copyright (c) 2016, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * 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 "apq8998-v2.1.dtsi"
+#include "msm8998-cdp.dtsi"
+
+/ {
+ model = "Qualcomm Technologies, Inc. APQ 8998 V2.1 mediabox";
+ compatible = "qcom,apq8998-cdp", "qcom,apq8998", "qcom,cdp";
+ qcom,board-id = <8 1>;
+};
+
+&pil_modem {
+ status = "disabled";
+};
+
+&mdss_mdp {
+ qcom,mdss-pref-prim-intf = "hdmi";
+};
diff --git a/arch/arm/boot/dts/qcom/fg-gen3-batterydata-ascent-3450mah.dtsi b/arch/arm/boot/dts/qcom/fg-gen3-batterydata-ascent-3450mah.dtsi
index 69067f5f1cc7..364b83320015 100644
--- a/arch/arm/boot/dts/qcom/fg-gen3-batterydata-ascent-3450mah.dtsi
+++ b/arch/arm/boot/dts/qcom/fg-gen3-batterydata-ascent-3450mah.dtsi
@@ -11,53 +11,53 @@
*/
qcom,ascent_3450mah {
- /* #Ascent_860_82209_0000_3450mAh_averaged_MasterSlave_Jul20th2016*/
+ /* Ascent_with_connector_3450mAh_averaged_MasterSlave_Nov28th2016 */
qcom,max-voltage-uv = <4350000>;
qcom,fg-cc-cv-threshold-mv = <4340>;
qcom,nom-batt-capacity-mah = <3450>;
qcom,batt-id-kohm = <60>;
qcom,battery-beta = <3435>;
- qcom,battery-type = "ascent_860_82209_0000_3450mah";
- qcom,checksum = <0xD1D9>;
- qcom,gui-version = "PMI8998GUI - 0.0.0.82";
+ qcom,battery-type = "ascent_3450mah_averaged_masterslave_nov28th2016";
+ qcom,checksum = <0x2232>;
+ qcom,gui-version = "PMI8998GUI - 2.0.0.52";
qcom,fg-profile-data = [
- 2C 1F 3F FC
- E9 03 A1 FD
- 58 1D FD F5
- 27 12 2C 14
- 3F 18 FF 22
- 9B 45 A3 52
+ 9C 1F 85 05
+ 82 0A 73 FC
+ 2B 1D 6A EA
+ F2 03 63 0C
+ C8 17 F3 22
+ E0 45 1F 52
+ 5C 00 00 00
+ 10 00 00 00
+ 00 00 4A C4
+ C7 BC 48 C2
+ 0F 00 08 00
+ 92 00 5D ED
+ 8D FD B1 F3
+ 27 00 A6 12
+ 77 F4 0F 3B
+ 24 06 09 20
+ 27 00 14 00
+ 83 1F EE 05
+ 1F 0A 45 FD
+ 6B 1D 52 E5
+ EC 0B 31 14
+ 44 18 49 23
+ 18 45 A6 53
55 00 00 00
0E 00 00 00
- 00 00 1C AC
- F7 CD 71 B5
- 1A 00 0C 00
- 3C EB 54 E4
- EC 05 7F FA
- 76 05 F5 02
- CA F3 82 3A
- 2A 09 40 40
- 07 00 05 00
- 58 1F 42 06
- 85 03 35 F4
- 4D 1D 37 F2
- 23 0A 79 15
- B7 18 32 23
- 26 45 72 53
- 55 00 00 00
- 0D 00 00 00
- 00 00 13 CC
- 03 00 98 BD
- 16 00 00 00
- 3C EB 54 E4
- 9F FC A3 F3
- 0F FC DF FA
- FF E5 A9 23
- CB 33 08 33
+ 00 00 61 CC
+ B7 C3 0F BC
+ 0F 00 00 00
+ 92 00 5D ED
+ E3 06 81 F3
+ 75 FD 9C 03
+ 43 DB B3 22
+ CB 33 CC FF
07 10 00 00
- 81 0D 99 45
- 16 00 19 00
- 75 01 0A FA
+ 99 0D 99 45
+ 0F 00 40 00
+ AB 01 0A FA
FF 00 00 00
00 00 00 00
00 00 00 00
diff --git a/arch/arm/boot/dts/qcom/fg-gen3-batterydata-demo-6000mah.dtsi b/arch/arm/boot/dts/qcom/fg-gen3-batterydata-demo-6000mah.dtsi
new file mode 100644
index 000000000000..b107918a8e98
--- /dev/null
+++ b/arch/arm/boot/dts/qcom/fg-gen3-batterydata-demo-6000mah.dtsi
@@ -0,0 +1,78 @@
+/* Copyright (c) 2016, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * 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.
+ */
+
+qcom,demo_6000mah {
+ qcom,max-voltage-uv = <4350000>;
+ qcom,fg-cc-cv-threshold-mv = <4340>;
+ qcom,nom-batt-capacity-mah = <6000>;
+ qcom,batt-id-kohm = <75>;
+ qcom,battery-beta = <3435>;
+ qcom,battery-type = "Demo_battery_6000mah";
+ qcom,fg-profile-data = [
+ 2C 1F 3F FC
+ E9 03 A1 FD
+ 58 1D FD F5
+ 27 12 2C 14
+ 3F 18 FF 22
+ 9B 45 A3 52
+ 55 00 00 00
+ 0E 00 00 00
+ 00 00 1C AC
+ F7 CD 71 B5
+ 1A 00 0C 00
+ 3C EB 54 E4
+ EC 05 7F FA
+ 76 05 F5 02
+ CA F3 82 3A
+ 2A 09 40 40
+ 07 00 05 00
+ 58 1F 42 06
+ 85 03 35 F4
+ 4D 1D 37 F2
+ 23 0A 79 15
+ B7 18 32 23
+ 26 45 72 53
+ 55 00 00 00
+ 0D 00 00 00
+ 00 00 13 CC
+ 03 00 98 BD
+ 16 00 00 00
+ 3C EB 54 E4
+ 9F FC A3 F3
+ 0F FC DF FA
+ FF E5 A9 23
+ CB 33 08 33
+ 07 10 00 00
+ 81 0D 99 45
+ 16 00 19 00
+ 75 01 0A FA
+ FF 00 00 00
+ 00 00 00 00
+ 00 00 00 00
+ 00 00 00 00
+ 00 00 00 00
+ 00 00 00 00
+ 00 00 00 00
+ 00 00 00 00
+ 00 00 00 00
+ 00 00 00 00
+ 00 00 00 00
+ 00 00 00 00
+ 00 00 00 00
+ 00 00 00 00
+ 00 00 00 00
+ 00 00 00 00
+ 00 00 00 00
+ 00 00 00 00
+ 00 00 00 00
+ ];
+};
diff --git a/arch/arm/boot/dts/qcom/msm-audio.dtsi b/arch/arm/boot/dts/qcom/msm-audio.dtsi
new file mode 100644
index 000000000000..74c1779e6fca
--- /dev/null
+++ b/arch/arm/boot/dts/qcom/msm-audio.dtsi
@@ -0,0 +1,838 @@
+/*
+ * Copyright (c) 2015-2016, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+&soc {
+ pcm0: qcom,msm-pcm {
+ compatible = "qcom,msm-pcm-dsp";
+ qcom,msm-pcm-dsp-id = <0>;
+ };
+
+ routing: qcom,msm-pcm-routing {
+ compatible = "qcom,msm-pcm-routing";
+ };
+
+ compr: qcom,msm-compr-dsp {
+ compatible = "qcom,msm-compr-dsp";
+ };
+
+ pcm2: qcom,msm-ultra-low-latency {
+ compatible = "qcom,msm-pcm-dsp";
+ qcom,msm-pcm-dsp-id = <2>;
+ qcom,msm-pcm-low-latency;
+ qcom,latency-level = "ultra";
+ };
+
+ pcm1: qcom,msm-pcm-low-latency {
+ compatible = "qcom,msm-pcm-dsp";
+ qcom,msm-pcm-dsp-id = <1>;
+ qcom,msm-pcm-low-latency;
+ qcom,latency-level = "regular";
+ };
+
+ pcm2: qcom,msm-ultra-low-latency {
+ compatible = "qcom,msm-pcm-dsp";
+ qcom,msm-pcm-dsp-id = <2>;
+ qcom,msm-pcm-low-latency;
+ qcom,latency-level = "ultra";
+ };
+
+ pcm_noirq: qcom,msm-pcm-dsp-noirq {
+ compatible = "qcom,msm-pcm-dsp-noirq";
+ qcom,msm-pcm-low-latency;
+ qcom,latency-level = "ultra";
+ };
+
+ cpe: qcom,msm-cpe-lsm {
+ compatible = "qcom,msm-cpe-lsm";
+ };
+
+ cpe3: qcom,msm-cpe-lsm@3 {
+ compatible = "qcom,msm-cpe-lsm";
+ qcom,msm-cpe-lsm-id = <3>;
+ };
+
+ compress: qcom,msm-compress-dsp {
+ compatible = "qcom,msm-compress-dsp";
+ };
+
+ voip: qcom,msm-voip-dsp {
+ compatible = "qcom,msm-voip-dsp";
+ };
+
+ voice: qcom,msm-pcm-voice {
+ compatible = "qcom,msm-pcm-voice";
+ qcom,destroy-cvd;
+ };
+
+ stub_codec: qcom,msm-stub-codec {
+ compatible = "qcom,msm-stub-codec";
+ };
+
+ qcom,msm-dai-fe {
+ compatible = "qcom,msm-dai-fe";
+ };
+
+ afe: qcom,msm-pcm-afe {
+ compatible = "qcom,msm-pcm-afe";
+ };
+
+ loopback: qcom,msm-pcm-loopback {
+ compatible = "qcom,msm-pcm-loopback";
+ };
+
+ qcom,msm-dai-mi2s {
+ compatible = "qcom,msm-dai-mi2s";
+ dai_mi2s0: qcom,msm-dai-q6-mi2s-prim {
+ compatible = "qcom,msm-dai-q6-mi2s";
+ qcom,msm-dai-q6-mi2s-dev-id = <0>;
+ qcom,msm-mi2s-rx-lines = <3>;
+ qcom,msm-mi2s-tx-lines = <0>;
+ };
+
+ dai_mi2s1: qcom,msm-dai-q6-mi2s-sec {
+ compatible = "qcom,msm-dai-q6-mi2s";
+ qcom,msm-dai-q6-mi2s-dev-id = <1>;
+ qcom,msm-mi2s-rx-lines = <1>;
+ qcom,msm-mi2s-tx-lines = <0>;
+ };
+
+ dai_mi2s3: qcom,msm-dai-q6-mi2s-quat {
+ compatible = "qcom,msm-dai-q6-mi2s";
+ qcom,msm-dai-q6-mi2s-dev-id = <3>;
+ qcom,msm-mi2s-rx-lines = <1>;
+ qcom,msm-mi2s-tx-lines = <2>;
+ };
+
+ dai_mi2s2: qcom,msm-dai-q6-mi2s-tert {
+ compatible = "qcom,msm-dai-q6-mi2s";
+ qcom,msm-dai-q6-mi2s-dev-id = <2>;
+ qcom,msm-mi2s-rx-lines = <0>;
+ qcom,msm-mi2s-tx-lines = <3>;
+ };
+
+ dai_mi2s5: qcom,msm-dai-q6-mi2s-quin {
+ compatible = "qcom,msm-dai-q6-mi2s";
+ qcom,msm-dai-q6-mi2s-dev-id = <5>;
+ qcom,msm-mi2s-rx-lines = <1>;
+ qcom,msm-mi2s-tx-lines = <2>;
+ };
+
+ dai_mi2s6: qcom,msm-dai-q6-mi2s-senary {
+ compatible = "qcom,msm-dai-q6-mi2s";
+ qcom,msm-dai-q6-mi2s-dev-id = <6>;
+ qcom,msm-mi2s-rx-lines = <0>;
+ qcom,msm-mi2s-tx-lines = <3>;
+ };
+
+ dai_int_mi2s0: qcom,msm-dai-q6-int-mi2s0 {
+ compatible = "qcom,msm-dai-q6-mi2s";
+ qcom,msm-dai-q6-mi2s-dev-id = <7>;
+ qcom,msm-mi2s-rx-lines = <3>;
+ qcom,msm-mi2s-tx-lines = <0>;
+ };
+
+ dai_int_mi2s1: qcom,msm-dai-q6-int-mi2s1 {
+ compatible = "qcom,msm-dai-q6-mi2s";
+ qcom,msm-dai-q6-mi2s-dev-id = <8>;
+ qcom,msm-mi2s-rx-lines = <3>;
+ qcom,msm-mi2s-tx-lines = <0>;
+ };
+
+ dai_int_mi2s2: qcom,msm-dai-q6-int-mi2s2 {
+ compatible = "qcom,msm-dai-q6-mi2s";
+ qcom,msm-dai-q6-mi2s-dev-id = <9>;
+ qcom,msm-mi2s-rx-lines = <0>;
+ qcom,msm-mi2s-tx-lines = <3>;
+ };
+
+ dai_int_mi2s3: qcom,msm-dai-q6-int-mi2s3 {
+ compatible = "qcom,msm-dai-q6-mi2s";
+ qcom,msm-dai-q6-mi2s-dev-id = <10>;
+ qcom,msm-mi2s-rx-lines = <0>;
+ qcom,msm-mi2s-tx-lines = <3>;
+ };
+
+ dai_int_mi2s4: qcom,msm-dai-q6-int-mi2s4 {
+ compatible = "qcom,msm-dai-q6-mi2s";
+ qcom,msm-dai-q6-mi2s-dev-id = <11>;
+ qcom,msm-mi2s-rx-lines = <3>;
+ qcom,msm-mi2s-tx-lines = <0>;
+ };
+
+ dai_int_mi2s5: qcom,msm-dai-q6-int-mi2s5 {
+ compatible = "qcom,msm-dai-q6-mi2s";
+ qcom,msm-dai-q6-mi2s-dev-id = <12>;
+ qcom,msm-mi2s-rx-lines = <0>;
+ qcom,msm-mi2s-tx-lines = <3>;
+ };
+
+ dai_int_mi2s6: qcom,msm-dai-q6-int-mi2s6 {
+ compatible = "qcom,msm-dai-q6-mi2s";
+ qcom,msm-dai-q6-mi2s-dev-id = <13>;
+ qcom,msm-mi2s-rx-lines = <0>;
+ qcom,msm-mi2s-tx-lines = <3>;
+ };
+ };
+
+ lsm: qcom,msm-lsm-client {
+ compatible = "qcom,msm-lsm-client";
+ };
+
+ qcom,msm-dai-q6 {
+ compatible = "qcom,msm-dai-q6";
+ sb_0_rx: qcom,msm-dai-q6-sb-0-rx {
+ compatible = "qcom,msm-dai-q6-dev";
+ qcom,msm-dai-q6-dev-id = <16384>;
+ };
+
+ sb_0_tx: qcom,msm-dai-q6-sb-0-tx {
+ compatible = "qcom,msm-dai-q6-dev";
+ qcom,msm-dai-q6-dev-id = <16385>;
+ };
+
+ sb_1_rx: qcom,msm-dai-q6-sb-1-rx {
+ compatible = "qcom,msm-dai-q6-dev";
+ qcom,msm-dai-q6-dev-id = <16386>;
+ };
+
+ sb_1_tx: qcom,msm-dai-q6-sb-1-tx {
+ compatible = "qcom,msm-dai-q6-dev";
+ qcom,msm-dai-q6-dev-id = <16387>;
+ };
+
+ sb_2_rx: qcom,msm-dai-q6-sb-2-rx {
+ compatible = "qcom,msm-dai-q6-dev";
+ qcom,msm-dai-q6-dev-id = <16388>;
+ };
+
+ sb_2_tx: qcom,msm-dai-q6-sb-2-tx {
+ compatible = "qcom,msm-dai-q6-dev";
+ qcom,msm-dai-q6-dev-id = <16389>;
+ };
+
+
+ sb_3_rx: qcom,msm-dai-q6-sb-3-rx {
+ compatible = "qcom,msm-dai-q6-dev";
+ qcom,msm-dai-q6-dev-id = <16390>;
+ };
+
+ sb_3_tx: qcom,msm-dai-q6-sb-3-tx {
+ compatible = "qcom,msm-dai-q6-dev";
+ qcom,msm-dai-q6-dev-id = <16391>;
+ };
+
+ sb_4_rx: qcom,msm-dai-q6-sb-4-rx {
+ compatible = "qcom,msm-dai-q6-dev";
+ qcom,msm-dai-q6-dev-id = <16392>;
+ };
+
+ sb_4_tx: qcom,msm-dai-q6-sb-4-tx {
+ compatible = "qcom,msm-dai-q6-dev";
+ qcom,msm-dai-q6-dev-id = <16393>;
+ };
+
+ sb_5_tx: qcom,msm-dai-q6-sb-5-tx {
+ compatible = "qcom,msm-dai-q6-dev";
+ qcom,msm-dai-q6-dev-id = <16395>;
+ };
+
+ sb_5_rx: qcom,msm-dai-q6-sb-5-rx {
+ compatible = "qcom,msm-dai-q6-dev";
+ qcom,msm-dai-q6-dev-id = <16394>;
+ };
+
+ sb_6_rx: qcom,msm-dai-q6-sb-6-rx {
+ compatible = "qcom,msm-dai-q6-dev";
+ qcom,msm-dai-q6-dev-id = <16396>;
+ };
+
+ sb_7_tx: qcom,msm-dai-q6-sb-7-tx {
+ compatible = "qcom,msm-dai-q6-dev";
+ qcom,msm-dai-q6-dev-id = <16399>;
+ };
+
+ sb_7_rx: qcom,msm-dai-q6-sb-7-rx {
+ compatible = "qcom,msm-dai-q6-dev";
+ qcom,msm-dai-q6-dev-id = <16398>;
+ };
+
+ sb_8_tx: qcom,msm-dai-q6-sb-8-tx {
+ compatible = "qcom,msm-dai-q6-dev";
+ qcom,msm-dai-q6-dev-id = <16401>;
+ };
+
+ sb_8_rx: qcom,msm-dai-q6-sb-8-rx {
+ compatible = "qcom,msm-dai-q6-dev";
+ qcom,msm-dai-q6-dev-id = <16400>;
+ };
+
+ bt_sco_rx: qcom,msm-dai-q6-bt-sco-rx {
+ compatible = "qcom,msm-dai-q6-dev";
+ qcom,msm-dai-q6-dev-id = <12288>;
+ };
+
+ bt_sco_tx: qcom,msm-dai-q6-bt-sco-tx {
+ compatible = "qcom,msm-dai-q6-dev";
+ qcom,msm-dai-q6-dev-id = <12289>;
+ };
+
+ int_fm_rx: qcom,msm-dai-q6-int-fm-rx {
+ compatible = "qcom,msm-dai-q6-dev";
+ qcom,msm-dai-q6-dev-id = <12292>;
+ };
+
+ int_fm_tx: qcom,msm-dai-q6-int-fm-tx {
+ compatible = "qcom,msm-dai-q6-dev";
+ qcom,msm-dai-q6-dev-id = <12293>;
+ };
+
+ afe_pcm_rx: qcom,msm-dai-q6-be-afe-pcm-rx {
+ compatible = "qcom,msm-dai-q6-dev";
+ qcom,msm-dai-q6-dev-id = <224>;
+ };
+
+ afe_pcm_tx: qcom,msm-dai-q6-be-afe-pcm-tx {
+ compatible = "qcom,msm-dai-q6-dev";
+ qcom,msm-dai-q6-dev-id = <225>;
+ };
+
+ afe_proxy_rx: qcom,msm-dai-q6-afe-proxy-rx {
+ compatible = "qcom,msm-dai-q6-dev";
+ qcom,msm-dai-q6-dev-id = <241>;
+ };
+
+ afe_proxy_tx: qcom,msm-dai-q6-afe-proxy-tx {
+ compatible = "qcom,msm-dai-q6-dev";
+ qcom,msm-dai-q6-dev-id = <240>;
+ };
+
+ incall_record_rx: qcom,msm-dai-q6-incall-record-rx {
+ compatible = "qcom,msm-dai-q6-dev";
+ qcom,msm-dai-q6-dev-id = <32771>;
+ };
+
+ incall_record_tx: qcom,msm-dai-q6-incall-record-tx {
+ compatible = "qcom,msm-dai-q6-dev";
+ qcom,msm-dai-q6-dev-id = <32772>;
+ };
+
+ incall_music_rx: qcom,msm-dai-q6-incall-music-rx {
+ compatible = "qcom,msm-dai-q6-dev";
+ qcom,msm-dai-q6-dev-id = <32773>;
+ };
+
+ incall_music_2_rx: qcom,msm-dai-q6-incall-music-2-rx {
+ compatible = "qcom,msm-dai-q6-dev";
+ qcom,msm-dai-q6-dev-id = <32770>;
+ };
+
+ usb_audio_rx: qcom,msm-dai-q6-usb-audio-rx {
+ compatible = "qcom,msm-dai-q6-dev";
+ qcom,msm-dai-q6-dev-id = <28672>;
+ };
+
+ usb_audio_tx: qcom,msm-dai-q6-usb-audio-tx {
+ compatible = "qcom,msm-dai-q6-dev";
+ qcom,msm-dai-q6-dev-id = <28673>;
+ };
+ };
+
+ hostless: qcom,msm-pcm-hostless {
+ compatible = "qcom,msm-pcm-hostless";
+ };
+
+ dai_pri_auxpcm: qcom,msm-pri-auxpcm {
+ compatible = "qcom,msm-auxpcm-dev";
+ qcom,msm-cpudai-auxpcm-mode = <0>, <0>;
+ qcom,msm-cpudai-auxpcm-sync = <1>, <1>;
+ qcom,msm-cpudai-auxpcm-frame = <5>, <4>;
+ qcom,msm-cpudai-auxpcm-quant = <2>, <2>;
+ qcom,msm-cpudai-auxpcm-num-slots = <1>, <1>;
+ qcom,msm-cpudai-auxpcm-slot-mapping = <1>, <1>;
+ qcom,msm-cpudai-auxpcm-data = <0>, <0>;
+ qcom,msm-cpudai-auxpcm-pcm-clk-rate = <2048000>, <2048000>;
+ qcom,msm-auxpcm-interface = "primary";
+ };
+
+ dai_sec_auxpcm: qcom,msm-sec-auxpcm {
+ compatible = "qcom,msm-auxpcm-dev";
+ qcom,msm-cpudai-auxpcm-mode = <0>, <0>;
+ qcom,msm-cpudai-auxpcm-sync = <1>, <1>;
+ qcom,msm-cpudai-auxpcm-frame = <5>, <4>;
+ qcom,msm-cpudai-auxpcm-quant = <2>, <2>;
+ qcom,msm-cpudai-auxpcm-num-slots = <1>, <1>;
+ qcom,msm-cpudai-auxpcm-slot-mapping = <1>, <1>;
+ qcom,msm-cpudai-auxpcm-data = <0>, <0>;
+ qcom,msm-cpudai-auxpcm-pcm-clk-rate = <2048000>, <2048000>;
+ qcom,msm-auxpcm-interface = "secondary";
+ qcom,msm-cpudai-afe-clk-ver = <2>;
+ };
+
+ dai_tert_auxpcm: qcom,msm-tert-auxpcm {
+ compatible = "qcom,msm-auxpcm-dev";
+ qcom,msm-cpudai-auxpcm-mode = <0>, <0>;
+ qcom,msm-cpudai-auxpcm-sync = <1>, <1>;
+ qcom,msm-cpudai-auxpcm-frame = <5>, <4>;
+ qcom,msm-cpudai-auxpcm-quant = <2>, <2>;
+ qcom,msm-cpudai-auxpcm-num-slots = <1>, <1>;
+ qcom,msm-cpudai-auxpcm-slot-mapping = <1>, <1>;
+ qcom,msm-cpudai-auxpcm-data = <0>, <0>;
+ qcom,msm-cpudai-auxpcm-pcm-clk-rate = <2048000>, <2048000>;
+ qcom,msm-auxpcm-interface = "tertiary";
+ qcom,msm-cpudai-afe-clk-ver = <2>;
+ };
+
+ dai_quat_auxpcm: qcom,msm-quat-auxpcm {
+ compatible = "qcom,msm-auxpcm-dev";
+ qcom,msm-cpudai-auxpcm-mode = <0>, <0>;
+ qcom,msm-cpudai-auxpcm-sync = <1>, <1>;
+ qcom,msm-cpudai-auxpcm-frame = <5>, <4>;
+ qcom,msm-cpudai-auxpcm-quant = <2>, <2>;
+ qcom,msm-cpudai-auxpcm-num-slots = <1>, <1>;
+ qcom,msm-cpudai-auxpcm-slot-mapping = <1>, <1>;
+ qcom,msm-cpudai-auxpcm-data = <0>, <0>;
+ qcom,msm-cpudai-auxpcm-pcm-clk-rate = <2048000>, <2048000>;
+ qcom,msm-auxpcm-interface = "quaternary";
+ qcom,msm-cpudai-afe-clk-ver = <2>;
+ };
+
+ qcom,msm-audio-ion {
+ compatible = "qcom,msm-audio-ion";
+ qcom,smmu-version = <2>;
+ qcom,smmu-enabled;
+ iommus = <&lpass_q6_smmu 1>;
+ };
+
+ qcom,msm-adsp-loader {
+ compatible = "qcom,adsp-loader";
+ qcom,adsp-state = <0>;
+ };
+
+ qcom,msm-dai-tdm-pri-rx {
+ compatible = "qcom,msm-dai-tdm";
+ qcom,msm-cpudai-tdm-group-id = <37120>;
+ qcom,msm-cpudai-tdm-group-num-ports = <1>;
+ qcom,msm-cpudai-tdm-group-port-id = <36864>;
+ qcom,msm-cpudai-tdm-clk-rate = <1536000>;
+ dai_pri_tdm_rx_0: qcom,msm-dai-q6-tdm-pri-rx-0 {
+ compatible = "qcom,msm-dai-q6-tdm";
+ qcom,msm-cpudai-tdm-dev-id = <36864>;
+ qcom,msm-cpudai-tdm-sync-mode = <1>;
+ qcom,msm-cpudai-tdm-sync-src = <1>;
+ qcom,msm-cpudai-tdm-data-out = <0>;
+ qcom,msm-cpudai-tdm-invert-sync = <1>;
+ qcom,msm-cpudai-tdm-data-delay = <1>;
+ qcom,msm-cpudai-tdm-data-align = <0>;
+ };
+ };
+
+ qcom,msm-dai-tdm-pri-tx {
+ compatible = "qcom,msm-dai-tdm";
+ qcom,msm-cpudai-tdm-group-id = <37121>;
+ qcom,msm-cpudai-tdm-group-num-ports = <1>;
+ qcom,msm-cpudai-tdm-group-port-id = <36865>;
+ qcom,msm-cpudai-tdm-clk-rate = <1536000>;
+ dai_pri_tdm_tx_0: qcom,msm-dai-q6-tdm-pri-tx-0 {
+ compatible = "qcom,msm-dai-q6-tdm";
+ qcom,msm-cpudai-tdm-dev-id = <36865>;
+ qcom,msm-cpudai-tdm-sync-mode = <1>;
+ qcom,msm-cpudai-tdm-sync-src = <1>;
+ qcom,msm-cpudai-tdm-data-out = <0>;
+ qcom,msm-cpudai-tdm-invert-sync = <1>;
+ qcom,msm-cpudai-tdm-data-delay = <1>;
+ qcom,msm-cpudai-tdm-data-align = <0>;
+ };
+ };
+
+ qcom,msm-dai-tdm-sec-rx {
+ compatible = "qcom,msm-dai-tdm";
+ qcom,msm-cpudai-tdm-group-id = <37136>;
+ qcom,msm-cpudai-tdm-group-num-ports = <1>;
+ qcom,msm-cpudai-tdm-group-port-id = <36880>;
+ qcom,msm-cpudai-tdm-clk-rate = <1536000>;
+ dai_sec_tdm_rx_0: qcom,msm-dai-q6-tdm-sec-rx-0 {
+ compatible = "qcom,msm-dai-q6-tdm";
+ qcom,msm-cpudai-tdm-dev-id = <36880>;
+ qcom,msm-cpudai-tdm-sync-mode = <1>;
+ qcom,msm-cpudai-tdm-sync-src = <1>;
+ qcom,msm-cpudai-tdm-data-out = <0>;
+ qcom,msm-cpudai-tdm-invert-sync = <1>;
+ qcom,msm-cpudai-tdm-data-delay = <1>;
+ qcom,msm-cpudai-tdm-data-align = <0>;
+ };
+ };
+
+ qcom,msm-dai-tdm-sec-tx {
+ compatible = "qcom,msm-dai-tdm";
+ qcom,msm-cpudai-tdm-group-id = <37137>;
+ qcom,msm-cpudai-tdm-group-num-ports = <1>;
+ qcom,msm-cpudai-tdm-group-port-id = <36881>;
+ qcom,msm-cpudai-tdm-clk-rate = <1536000>;
+ dai_sec_tdm_tx_0: qcom,msm-dai-q6-tdm-sec-tx-0 {
+ compatible = "qcom,msm-dai-q6-tdm";
+ qcom,msm-cpudai-tdm-dev-id = <36881>;
+ qcom,msm-cpudai-tdm-sync-mode = <1>;
+ qcom,msm-cpudai-tdm-sync-src = <1>;
+ qcom,msm-cpudai-tdm-data-out = <0>;
+ qcom,msm-cpudai-tdm-invert-sync = <1>;
+ qcom,msm-cpudai-tdm-data-delay = <1>;
+ qcom,msm-cpudai-tdm-data-align = <0>;
+ };
+ };
+
+ qcom,msm-dai-tdm-tert-rx {
+ compatible = "qcom,msm-dai-tdm";
+ qcom,msm-cpudai-tdm-group-id = <37152>;
+ qcom,msm-cpudai-tdm-group-num-ports = <1>;
+ qcom,msm-cpudai-tdm-group-port-id = <36896>;
+ qcom,msm-cpudai-tdm-clk-rate = <1536000>;
+ dai_tert_tdm_rx_0: qcom,msm-dai-q6-tdm-tert-rx-0 {
+ compatible = "qcom,msm-dai-q6-tdm";
+ qcom,msm-cpudai-tdm-dev-id = <36896>;
+ qcom,msm-cpudai-tdm-sync-mode = <1>;
+ qcom,msm-cpudai-tdm-sync-src = <1>;
+ qcom,msm-cpudai-tdm-data-out = <0>;
+ qcom,msm-cpudai-tdm-invert-sync = <1>;
+ qcom,msm-cpudai-tdm-data-delay = <1>;
+ qcom,msm-cpudai-tdm-data-align = <0>;
+ };
+ };
+
+ qcom,msm-dai-tdm-tert-tx {
+ compatible = "qcom,msm-dai-tdm";
+ qcom,msm-cpudai-tdm-group-id = <37153>;
+ qcom,msm-cpudai-tdm-group-num-ports = <1>;
+ qcom,msm-cpudai-tdm-group-port-id = <36897 >;
+ qcom,msm-cpudai-tdm-clk-rate = <1536000>;
+ dai_tert_tdm_tx_0: qcom,msm-dai-q6-tdm-tert-tx-0 {
+ compatible = "qcom,msm-dai-q6-tdm";
+ qcom,msm-cpudai-tdm-dev-id = <36897 >;
+ qcom,msm-cpudai-tdm-sync-mode = <1>;
+ qcom,msm-cpudai-tdm-sync-src = <1>;
+ qcom,msm-cpudai-tdm-data-out = <0>;
+ qcom,msm-cpudai-tdm-invert-sync = <1>;
+ qcom,msm-cpudai-tdm-data-delay = <1>;
+ qcom,msm-cpudai-tdm-data-align = <0>;
+ };
+ };
+
+ qcom,msm-dai-tdm-quat-rx {
+ compatible = "qcom,msm-dai-tdm";
+ qcom,msm-cpudai-tdm-group-id = <37168>;
+ qcom,msm-cpudai-tdm-group-num-ports = <1>;
+ qcom,msm-cpudai-tdm-group-port-id = <36912>;
+ qcom,msm-cpudai-tdm-clk-rate = <1536000>;
+ dai_quat_tdm_rx_0: qcom,msm-dai-q6-tdm-quat-rx-0 {
+ compatible = "qcom,msm-dai-q6-tdm";
+ qcom,msm-cpudai-tdm-dev-id = <36912>;
+ qcom,msm-cpudai-tdm-sync-mode = <1>;
+ qcom,msm-cpudai-tdm-sync-src = <1>;
+ qcom,msm-cpudai-tdm-data-out = <0>;
+ qcom,msm-cpudai-tdm-invert-sync = <1>;
+ qcom,msm-cpudai-tdm-data-delay = <1>;
+ qcom,msm-cpudai-tdm-data-align = <0>;
+ };
+ };
+
+ qcom,msm-dai-tdm-quat-tx {
+ compatible = "qcom,msm-dai-tdm";
+ qcom,msm-cpudai-tdm-group-id = <37169>;
+ qcom,msm-cpudai-tdm-group-num-ports = <1>;
+ qcom,msm-cpudai-tdm-group-port-id = <36913 >;
+ qcom,msm-cpudai-tdm-clk-rate = <1536000>;
+ dai_quat_tdm_tx_0: qcom,msm-dai-q6-tdm-quat-tx-0 {
+ compatible = "qcom,msm-dai-q6-tdm";
+ qcom,msm-cpudai-tdm-dev-id = <36913 >;
+ qcom,msm-cpudai-tdm-sync-mode = <1>;
+ qcom,msm-cpudai-tdm-sync-src = <1>;
+ qcom,msm-cpudai-tdm-data-out = <0>;
+ qcom,msm-cpudai-tdm-invert-sync = <1>;
+ qcom,msm-cpudai-tdm-data-delay = <1>;
+ qcom,msm-cpudai-tdm-data-align = <0>;
+ };
+ };
+
+ qcom,avtimer@150f700c {
+ compatible = "qcom,avtimer";
+ reg = <0x150f700c 0x4>,
+ <0x150f7010 0x4>;
+ reg-names = "avtimer_lsb_addr", "avtimer_msb_addr";
+ qcom,clk-div = <27>;
+ };
+
+ tasha_snd: sound-9335 {
+ compatible = "qcom,msmfalcon-asoc-snd-tasha";
+ qcom,model = "msmfalcon-tasha-snd-card";
+ qcom,wcn-btfm;
+ qcom,mi2s-audio-intf;
+ qcom,auxpcm-audio-intf;
+ qcom,msm-mi2s-master = <1>, <1>, <1>, <1>;
+
+ reg = <0x1508a000 0x4>,
+ <0x1508b000 0x4>,
+ <0x1508c000 0x4>,
+ <0x1508d000 0x4>;
+ reg-names = "lpaif_pri_mode_muxsel",
+ "lpaif_sec_mode_muxsel",
+ "lpaif_tert_mode_muxsel",
+ "lpaif_quat_mode_muxsel";
+
+ qcom,audio-routing =
+ "AIF4 VI", "MCLK",
+ "RX_BIAS", "MCLK",
+ "MADINPUT", "MCLK",
+ "AMIC2", "MIC BIAS2",
+ "MIC BIAS2", "Headset Mic",
+ "AMIC3", "MIC BIAS2",
+ "MIC BIAS2", "ANCRight Headset Mic",
+ "AMIC4", "MIC BIAS2",
+ "MIC BIAS2", "ANCLeft Headset Mic",
+ "AMIC5", "MIC BIAS3",
+ "MIC BIAS3", "Handset Mic",
+ "AMIC6", "MIC BIAS4",
+ "MIC BIAS4", "Analog Mic6",
+ "DMIC0", "MIC BIAS1",
+ "MIC BIAS1", "Digital Mic0",
+ "DMIC1", "MIC BIAS1",
+ "MIC BIAS1", "Digital Mic1",
+ "DMIC2", "MIC BIAS3",
+ "MIC BIAS3", "Digital Mic2",
+ "DMIC3", "MIC BIAS3",
+ "MIC BIAS3", "Digital Mic3",
+ "DMIC4", "MIC BIAS4",
+ "MIC BIAS4", "Digital Mic4",
+ "DMIC5", "MIC BIAS4",
+ "MIC BIAS4", "Digital Mic5",
+ "SpkrLeft IN", "SPK1 OUT",
+ "SpkrRight IN", "SPK2 OUT";
+
+ qcom,msm-mbhc-hphl-swh = <0>;
+ qcom,msm-mbhc-gnd-swh = <0>;
+ qcom,us-euro-gpios = <&us_euro_gpio>;
+ qcom,tasha-mclk-clk-freq = <9600000>;
+ asoc-platform = <&pcm0>, <&pcm1>, <&pcm2>, <&voip>, <&voice>,
+ <&loopback>, <&compress>, <&hostless>,
+ <&afe>, <&lsm>, <&routing>, <&cpe>, <&compr>,
+ <&pcm_noirq>, <&cpe3>;
+ asoc-platform-names = "msm-pcm-dsp.0", "msm-pcm-dsp.1",
+ "msm-pcm-dsp.2", "msm-voip-dsp",
+ "msm-pcm-voice", "msm-pcm-loopback",
+ "msm-compress-dsp", "msm-pcm-hostless",
+ "msm-pcm-afe", "msm-lsm-client",
+ "msm-pcm-routing", "msm-cpe-lsm",
+ "msm-compr-dsp", "msm-pcm-dsp-noirq",
+ "msm-cpe-lsm.3";
+ asoc-cpu = <&dai_mi2s0>, <&dai_mi2s1>,
+ <&dai_mi2s2>, <&dai_mi2s3>,
+ <&dai_pri_auxpcm>, <&dai_sec_auxpcm>,
+ <&dai_tert_auxpcm>, <&dai_quat_auxpcm>,
+ <&sb_0_rx>, <&sb_0_tx>, <&sb_1_rx>, <&sb_1_tx>,
+ <&sb_2_rx>, <&sb_2_tx>, <&sb_3_rx>, <&sb_3_tx>,
+ <&sb_4_rx>, <&sb_4_tx>, <&sb_5_tx>,
+ <&afe_pcm_rx>, <&afe_pcm_tx>, <&afe_proxy_rx>,
+ <&afe_proxy_tx>, <&incall_record_rx>,
+ <&incall_record_tx>, <&incall_music_rx>,
+ <&incall_music_2_rx>, <&sb_5_rx>, <&sb_6_rx>,
+ <&sb_7_rx>, <&sb_7_tx>, <&sb_8_tx>, <&sb_8_rx>,
+ <&usb_audio_rx>, <&usb_audio_tx>,
+ <&dai_pri_tdm_rx_0>, <&dai_pri_tdm_tx_0>,
+ <&dai_sec_tdm_rx_0>, <&dai_sec_tdm_tx_0>,
+ <&dai_tert_tdm_rx_0>, <&dai_tert_tdm_tx_0>,
+ <&dai_quat_tdm_rx_0>, <&dai_quat_tdm_tx_0>;
+ asoc-cpu-names = "msm-dai-q6-mi2s.0", "msm-dai-q6-mi2s.1",
+ "msm-dai-q6-mi2s.2", "msm-dai-q6-mi2s.3",
+ "msm-dai-q6-auxpcm.1", "msm-dai-q6-auxpcm.2",
+ "msm-dai-q6-auxpcm.3", "msm-dai-q6-auxpcm.4",
+ "msm-dai-q6-dev.16384", "msm-dai-q6-dev.16385",
+ "msm-dai-q6-dev.16386", "msm-dai-q6-dev.16387",
+ "msm-dai-q6-dev.16388", "msm-dai-q6-dev.16389",
+ "msm-dai-q6-dev.16390", "msm-dai-q6-dev.16391",
+ "msm-dai-q6-dev.16392", "msm-dai-q6-dev.16393",
+ "msm-dai-q6-dev.16395", "msm-dai-q6-dev.224",
+ "msm-dai-q6-dev.225", "msm-dai-q6-dev.241",
+ "msm-dai-q6-dev.240", "msm-dai-q6-dev.32771",
+ "msm-dai-q6-dev.32772", "msm-dai-q6-dev.32773",
+ "msm-dai-q6-dev.32770", "msm-dai-q6-dev.16394",
+ "msm-dai-q6-dev.16396", "msm-dai-q6-dev.16398",
+ "msm-dai-q6-dev.16399", "msm-dai-q6-dev.16401",
+ "msm-dai-q6-dev.16400", "msm-dai-q6-dev.28672",
+ "msm-dai-q6-dev.28673", "msm-dai-q6-tdm.36864",
+ "msm-dai-q6-tdm.36865", "msm-dai-q6-tdm.36880",
+ "msm-dai-q6-tdm.36881", "msm-dai-q6-tdm.36896",
+ "msm-dai-q6-tdm.36897", "msm-dai-q6-tdm.36912",
+ "msm-dai-q6-tdm.36913";
+ asoc-codec = <&stub_codec>;
+ asoc-codec-names = "msm-stub-codec.1";
+ qcom,wsa-max-devs = <2>;
+ qcom,wsa-devs = <&wsa881x_0211>, <&wsa881x_0212>,
+ <&wsa881x_0213>, <&wsa881x_0214>;
+ qcom,wsa-aux-dev-prefix = "SpkrLeft", "SpkrRight",
+ "SpkrLeft", "SpkrRight";
+ };
+
+ tavil_snd: sound-tavil {
+ compatible = "qcom,msmfalcon-asoc-snd-tavil";
+ qcom,model = "msmfalcon-tavil-snd-card";
+ qcom,wcn-btfm;
+ qcom,mi2s-audio-intf;
+ qcom,auxpcm-audio-intf;
+ qcom,msm-mi2s-master = <1>, <1>, <1>, <1>;
+
+ reg = <0x1508a000 0x4>,
+ <0x1508b000 0x4>,
+ <0x1508c000 0x4>,
+ <0x1508d000 0x4>;
+ reg-names = "lpaif_pri_mode_muxsel",
+ "lpaif_sec_mode_muxsel",
+ "lpaif_tert_mode_muxsel",
+ "lpaif_quat_mode_muxsel";
+
+ qcom,audio-routing =
+ "RX_BIAS", "MCLK",
+ "MADINPUT", "MCLK",
+ "AMIC2", "MIC BIAS2",
+ "MIC BIAS2", "Headset Mic",
+ "AMIC3", "MIC BIAS2",
+ "MIC BIAS2", "ANCRight Headset Mic",
+ "AMIC4", "MIC BIAS2",
+ "MIC BIAS2", "ANCLeft Headset Mic",
+ "AMIC5", "MIC BIAS3",
+ "MIC BIAS3", "Handset Mic",
+ "DMIC0", "MIC BIAS1",
+ "MIC BIAS1", "Digital Mic0",
+ "DMIC1", "MIC BIAS1",
+ "MIC BIAS1", "Digital Mic1",
+ "DMIC2", "MIC BIAS3",
+ "MIC BIAS3", "Digital Mic2",
+ "DMIC3", "MIC BIAS3",
+ "MIC BIAS3", "Digital Mic3",
+ "DMIC4", "MIC BIAS4",
+ "MIC BIAS4", "Digital Mic4",
+ "DMIC5", "MIC BIAS4",
+ "MIC BIAS4", "Digital Mic5",
+ "SpkrLeft IN", "SPK1 OUT",
+ "SpkrRight IN", "SPK2 OUT";
+
+ qcom,msm-mbhc-hphl-swh = <0>;
+ qcom,msm-mbhc-gnd-swh = <0>;
+ qcom,us-euro-gpios = <&tavil_us_euro_sw>;
+ qcom,hph-en0-gpio = <&tavil_hph_en0>;
+ qcom,hph-en1-gpio = <&tavil_hph_en1>;
+ qcom,tavil-mclk-clk-freq = <9600000>;
+ asoc-platform = <&pcm0>, <&pcm1>, <&pcm2>, <&voip>, <&voice>,
+ <&loopback>, <&compress>, <&hostless>,
+ <&afe>, <&lsm>, <&routing>, <&cpe>, <&compr>,
+ <&pcm_noirq>;
+ asoc-platform-names = "msm-pcm-dsp.0", "msm-pcm-dsp.1",
+ "msm-pcm-dsp.2", "msm-voip-dsp",
+ "msm-pcm-voice", "msm-pcm-loopback",
+ "msm-compress-dsp", "msm-pcm-hostless",
+ "msm-pcm-afe", "msm-lsm-client",
+ "msm-pcm-routing", "msm-cpe-lsm",
+ "msm-compr-dsp", "msm-pcm-dsp-noirq";
+ asoc-cpu = <&dai_mi2s0>, <&dai_mi2s1>,
+ <&dai_mi2s2>, <&dai_mi2s3>,
+ <&dai_pri_auxpcm>, <&dai_sec_auxpcm>,
+ <&dai_tert_auxpcm>, <&dai_quat_auxpcm>,
+ <&sb_0_rx>, <&sb_0_tx>, <&sb_1_rx>, <&sb_1_tx>,
+ <&sb_2_rx>, <&sb_2_tx>, <&sb_3_rx>, <&sb_3_tx>,
+ <&sb_4_rx>, <&sb_4_tx>, <&sb_5_tx>,
+ <&afe_pcm_rx>, <&afe_pcm_tx>, <&afe_proxy_rx>,
+ <&afe_proxy_tx>, <&incall_record_rx>,
+ <&incall_record_tx>, <&incall_music_rx>,
+ <&incall_music_2_rx>, <&sb_5_rx>, <&sb_6_rx>,
+ <&sb_7_rx>, <&sb_7_tx>, <&sb_8_tx>, <&sb_8_rx>,
+ <&usb_audio_rx>, <&usb_audio_tx>,
+ <&dai_pri_tdm_rx_0>, <&dai_pri_tdm_tx_0>,
+ <&dai_sec_tdm_rx_0>, <&dai_sec_tdm_tx_0>,
+ <&dai_tert_tdm_rx_0>, <&dai_tert_tdm_tx_0>,
+ <&dai_quat_tdm_rx_0>, <&dai_quat_tdm_tx_0>;
+ asoc-cpu-names = "msm-dai-q6-mi2s.0", "msm-dai-q6-mi2s.1",
+ "msm-dai-q6-mi2s.2", "msm-dai-q6-mi2s.3",
+ "msm-dai-q6-auxpcm.1", "msm-dai-q6-auxpcm.2",
+ "msm-dai-q6-auxpcm.3", "msm-dai-q6-auxpcm.4",
+ "msm-dai-q6-dev.16384", "msm-dai-q6-dev.16385",
+ "msm-dai-q6-dev.16386", "msm-dai-q6-dev.16387",
+ "msm-dai-q6-dev.16388", "msm-dai-q6-dev.16389",
+ "msm-dai-q6-dev.16390", "msm-dai-q6-dev.16391",
+ "msm-dai-q6-dev.16392", "msm-dai-q6-dev.16393",
+ "msm-dai-q6-dev.16395", "msm-dai-q6-dev.224",
+ "msm-dai-q6-dev.225", "msm-dai-q6-dev.241",
+ "msm-dai-q6-dev.240", "msm-dai-q6-dev.32771",
+ "msm-dai-q6-dev.32772", "msm-dai-q6-dev.32773",
+ "msm-dai-q6-dev.32770", "msm-dai-q6-dev.16394",
+ "msm-dai-q6-dev.16396", "msm-dai-q6-dev.16398",
+ "msm-dai-q6-dev.16399", "msm-dai-q6-dev.16401",
+ "msm-dai-q6-dev.16400", "msm-dai-q6-dev.28672",
+ "msm-dai-q6-dev.28673", "msm-dai-q6-tdm.36864",
+ "msm-dai-q6-tdm.36865", "msm-dai-q6-tdm.36880",
+ "msm-dai-q6-tdm.36881", "msm-dai-q6-tdm.36896",
+ "msm-dai-q6-tdm.36897", "msm-dai-q6-tdm.36912",
+ "msm-dai-q6-tdm.36913";
+ asoc-codec = <&stub_codec>;
+ asoc-codec-names = "msm-stub-codec.1";
+ qcom,wsa-max-devs = <2>;
+ qcom,wsa-devs = <&wsa881x_0211>, <&wsa881x_0212>,
+ <&wsa881x_0213>, <&wsa881x_0214>;
+ qcom,wsa-aux-dev-prefix = "SpkrLeft", "SpkrRight",
+ "SpkrLeft", "SpkrRight";
+ };
+
+
+ us_euro_gpio: msm_cdc_pinctrl@75 {
+ compatible = "qcom,msm-cdc-pinctrl";
+ pinctrl-names = "aud_active", "aud_sleep";
+ pinctrl-0 = <&wcd_gnd_mic_swap_active>;
+ pinctrl-1 = <&wcd_gnd_mic_swap_idle>;
+ };
+
+ wcd9xxx_intc: wcd9xxx-irq {
+ compatible = "qcom,wcd9xxx-irq";
+ interrupt-controller;
+ #interrupt-cells = <1>;
+ interrupt-parent = <&tlmm>;
+ qcom,gpio-connect = <&tlmm 54 0>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&wcd_intr_default>;
+ };
+
+ clock_audio: audio_ext_clk {
+ compatible = "qcom,audio-ref-clk";
+ qcom,audio-ref-clk-gpio = <&pmfalcon_gpios 3 0>;
+ clock-names = "osr_clk";
+ clocks = <&clock_gcc clk_div_clk1>;
+ qcom,node_has_rpm_clock;
+ #clock-cells = <1>;
+ pinctrl-names = "sleep", "active";
+ pinctrl-0 = <&spkr_i2s_clk_sleep>;
+ pinctrl-1 = <&spkr_i2s_clk_active>;
+ };
+
+ clock_audio_lnbb: audio_ext_clk_lnbb {
+ compatible = "qcom,audio-ref-clk";
+ clock-names = "osr_clk";
+ clocks = <&clock_gcc clk_ln_bb_clk2>;
+ qcom,node_has_rpm_clock;
+ #clock-cells = <1>;
+ };
+
+ wcd_rst_gpio: msm_cdc_pinctrl@64 {
+ compatible = "qcom,msm-cdc-pinctrl";
+ qcom,cdc-rst-n-gpio = <&tlmm 64 0>;
+ pinctrl-names = "aud_active", "aud_sleep";
+ pinctrl-0 = <&cdc_reset_active>;
+ pinctrl-1 = <&cdc_reset_sleep>;
+ };
+
+};
+
diff --git a/arch/arm/boot/dts/qcom/msm-pm3falcon.dtsi b/arch/arm/boot/dts/qcom/msm-pm3falcon.dtsi
new file mode 100644
index 000000000000..dcf7030a78e4
--- /dev/null
+++ b/arch/arm/boot/dts/qcom/msm-pm3falcon.dtsi
@@ -0,0 +1,16 @@
+/* Copyright (c) 2016, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * 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.
+ */
+
+/* Disable WLED */
+&pm2falcon_wled {
+ status = "disabled";
+};
diff --git a/arch/arm/boot/dts/qcom/msm-pmfalcon.dtsi b/arch/arm/boot/dts/qcom/msm-pmfalcon.dtsi
index b8fac8a183a2..93cfab700aa9 100644
--- a/arch/arm/boot/dts/qcom/msm-pmfalcon.dtsi
+++ b/arch/arm/boot/dts/qcom/msm-pmfalcon.dtsi
@@ -273,6 +273,158 @@
};
};
+ pmfalcon_charger: qcom,qpnp-smb2 {
+ compatible = "qcom,qpnp-smb2";
+ #address-cells = <1>;
+ #size-cells = <1>;
+
+ qcom,pmic-revid = <&pmfalcon_revid>;
+
+ io-channels = <&pmfalcon_rradc 8>,
+ <&pmfalcon_rradc 10>,
+ <&pmfalcon_rradc 3>,
+ <&pmfalcon_rradc 4>;
+ io-channel-names = "charger_temp",
+ "charger_temp_max",
+ "usbin_i",
+ "usbin_v";
+
+ qcom,wipower-max-uw = <5000000>;
+ dpdm-supply = <&qusb_phy0>;
+
+ qcom,thermal-mitigation
+ = <3000000 1500000 1000000 500000>;
+
+ qcom,chgr@1000 {
+ reg = <0x1000 0x100>;
+ interrupts = <0x2 0x10 0x0 IRQ_TYPE_NONE>,
+ <0x2 0x10 0x1 IRQ_TYPE_NONE>,
+ <0x2 0x10 0x2 IRQ_TYPE_NONE>,
+ <0x2 0x10 0x3 IRQ_TYPE_NONE>,
+ <0x2 0x10 0x4 IRQ_TYPE_NONE>;
+
+ interrupt-names = "chg-error",
+ "chg-state-change",
+ "step-chg-state-change",
+ "step-chg-soc-update-fail",
+ "step-chg-soc-update-request";
+ };
+
+ qcom,otg@1100 {
+ reg = <0x1100 0x100>;
+ interrupts = <0x2 0x11 0x0 IRQ_TYPE_NONE>,
+ <0x2 0x11 0x1 IRQ_TYPE_NONE>,
+ <0x2 0x11 0x2 IRQ_TYPE_NONE>,
+ <0x2 0x11 0x3 IRQ_TYPE_NONE>;
+
+ interrupt-names = "otg-fail",
+ "otg-overcurrent",
+ "otg-oc-dis-sw-sts",
+ "testmode-change-detect";
+ };
+
+ qcom,bat-if@1200 {
+ reg = <0x1200 0x100>;
+ interrupts = <0x2 0x12 0x0 IRQ_TYPE_NONE>,
+ <0x2 0x12 0x1 IRQ_TYPE_NONE>,
+ <0x2 0x12 0x2 IRQ_TYPE_NONE>,
+ <0x2 0x12 0x3 IRQ_TYPE_NONE>,
+ <0x2 0x12 0x4 IRQ_TYPE_NONE>,
+ <0x2 0x12 0x5 IRQ_TYPE_NONE>;
+
+ interrupt-names = "bat-temp",
+ "bat-ocp",
+ "bat-ov",
+ "bat-low",
+ "bat-therm-or-id-missing",
+ "bat-terminal-missing";
+ };
+
+ qcom,usb-chgpth@1300 {
+ reg = <0x1300 0x100>;
+ interrupts = <0x2 0x13 0x0 IRQ_TYPE_NONE>,
+ <0x2 0x13 0x1 IRQ_TYPE_NONE>,
+ <0x2 0x13 0x2 IRQ_TYPE_NONE>,
+ <0x2 0x13 0x3 IRQ_TYPE_NONE>,
+ <0x2 0x13 0x4 IRQ_TYPE_NONE>,
+ <0x2 0x13 0x5 IRQ_TYPE_NONE>,
+ <0x2 0x13 0x6 IRQ_TYPE_NONE>,
+ <0x2 0x13 0x7 IRQ_TYPE_NONE>;
+
+ interrupt-names = "usbin-collapse",
+ "usbin-lt-3p6v",
+ "usbin-uv",
+ "usbin-ov",
+ "usbin-plugin",
+ "usbin-src-change",
+ "usbin-icl-change",
+ "type-c-change";
+ };
+
+ qcom,dc-chgpth@1400 {
+ reg = <0x1400 0x100>;
+ interrupts = <0x2 0x14 0x0 IRQ_TYPE_NONE>,
+ <0x2 0x14 0x1 IRQ_TYPE_NONE>,
+ <0x2 0x14 0x2 IRQ_TYPE_NONE>,
+ <0x2 0x14 0x3 IRQ_TYPE_NONE>,
+ <0x2 0x14 0x4 IRQ_TYPE_NONE>,
+ <0x2 0x14 0x5 IRQ_TYPE_NONE>,
+ <0x2 0x14 0x6 IRQ_TYPE_NONE>;
+
+ interrupt-names = "dcin-collapse",
+ "dcin-lt-3p6v",
+ "dcin-uv",
+ "dcin-ov",
+ "dcin-plugin",
+ "div2-en-dg",
+ "dcin-icl-change";
+ };
+
+ qcom,chgr-misc@1600 {
+ reg = <0x1600 0x100>;
+ interrupts = <0x2 0x16 0x0 IRQ_TYPE_NONE>,
+ <0x2 0x16 0x1 IRQ_TYPE_NONE>,
+ <0x2 0x16 0x2 IRQ_TYPE_NONE>,
+ <0x2 0x16 0x3 IRQ_TYPE_NONE>,
+ <0x2 0x16 0x4 IRQ_TYPE_NONE>,
+ <0x2 0x16 0x5 IRQ_TYPE_NONE>,
+ <0x2 0x16 0x6 IRQ_TYPE_NONE>,
+ <0x2 0x16 0x7 IRQ_TYPE_NONE>;
+
+ interrupt-names = "wdog-snarl",
+ "wdog-bark",
+ "aicl-fail",
+ "aicl-done",
+ "high-duty-cycle",
+ "input-current-limiting",
+ "temperature-change",
+ "switcher-power-ok";
+ };
+ };
+
+ pmfalcon_pdphy: qcom,usb-pdphy@1700 {
+ compatible = "qcom,qpnp-pdphy";
+ reg = <0x1700 0x100>;
+ vdd-pdphy-supply = <&pm2falcon_l7>;
+ vbus-supply = <&smb2_vbus>;
+ vconn-supply = <&smb2_vconn>;
+ interrupts = <0x0 0x17 0x0 IRQ_TYPE_EDGE_RISING>,
+ <0x0 0x17 0x1 IRQ_TYPE_EDGE_RISING>,
+ <0x0 0x17 0x2 IRQ_TYPE_EDGE_RISING>,
+ <0x0 0x17 0x3 IRQ_TYPE_EDGE_RISING>,
+ <0x0 0x17 0x4 IRQ_TYPE_EDGE_RISING>,
+ <0x0 0x17 0x5 IRQ_TYPE_EDGE_RISING>,
+ <0x0 0x17 0x6 IRQ_TYPE_EDGE_RISING>;
+
+ interrupt-names = "sig-tx",
+ "sig-rx",
+ "msg-tx",
+ "msg-rx",
+ "msg-tx-failed",
+ "msg-tx-discarded",
+ "msg-rx-discarded";
+ };
+
pmfalcon_adc_tm: vadc@3400 {
compatible = "qcom,qpnp-adc-tm-hc";
reg = <0x3400 0x100>;
@@ -337,6 +489,67 @@
#size-cells = <0>;
#io-channel-cells = <1>;
};
+
+ pmfalcon_fg: qpnp,fg {
+ compatible = "qcom,fg-gen3";
+ #address-cells = <1>;
+ #size-cells = <1>;
+ qcom,pmic-revid = <&pmfalcon_revid>;
+ io-channels = <&pmfalcon_rradc 0>;
+ io-channel-names = "rradc_batt_id";
+ qcom,fg-esr-timer-awake = <96>;
+ qcom,fg-esr-timer-asleep = <256>;
+ qcom,cycle-counter-en;
+ status = "okay";
+
+ qcom,fg-batt-soc@4000 {
+ status = "okay";
+ reg = <0x4000 0x100>;
+ interrupts = <0x2 0x40 0x0 IRQ_TYPE_EDGE_BOTH>,
+ <0x2 0x40 0x1 IRQ_TYPE_EDGE_BOTH>,
+ <0x2 0x40 0x2 IRQ_TYPE_EDGE_BOTH>,
+ <0x2 0x40 0x3 IRQ_TYPE_EDGE_BOTH>,
+ <0x2 0x40 0x4 IRQ_TYPE_EDGE_BOTH>,
+ <0x2 0x40 0x5
+ IRQ_TYPE_EDGE_RISING>,
+ <0x2 0x40 0x6 IRQ_TYPE_EDGE_BOTH>,
+ <0x2 0x40 0x7 IRQ_TYPE_EDGE_BOTH>;
+ interrupt-names = "soc-update",
+ "soc-ready",
+ "bsoc-delta",
+ "msoc-delta",
+ "msoc-low",
+ "msoc-empty",
+ "msoc-high",
+ "msoc-full";
+ };
+
+ qcom,fg-batt-info@4100 {
+ status = "okay";
+ reg = <0x4100 0x100>;
+ interrupts = <0x2 0x41 0x0 IRQ_TYPE_EDGE_BOTH>,
+ <0x2 0x41 0x1 IRQ_TYPE_EDGE_BOTH>,
+ <0x2 0x41 0x2 IRQ_TYPE_EDGE_BOTH>,
+ <0x2 0x41 0x3 IRQ_TYPE_EDGE_BOTH>,
+ <0x2 0x41 0x6 IRQ_TYPE_EDGE_BOTH>;
+ interrupt-names = "vbatt-pred-delta",
+ "vbatt-low",
+ "esr-delta",
+ "batt-missing",
+ "batt-temp-delta";
+ };
+
+ qcom,fg-memif@4400 {
+ status = "okay";
+ reg = <0x4400 0x100>;
+ interrupts = <0x2 0x44 0x0 IRQ_TYPE_EDGE_BOTH>,
+ <0x2 0x44 0x1 IRQ_TYPE_EDGE_BOTH>,
+ <0x2 0x44 0x2 IRQ_TYPE_EDGE_BOTH>;
+ interrupt-names = "ima-rdy",
+ "mem-xcp",
+ "dma-grant";
+ };
+ };
};
qcom,pmfalcon@1 {
diff --git a/arch/arm/boot/dts/qcom/msm8998-camera-sensor-qrd-vr1.dtsi b/arch/arm/boot/dts/qcom/msm8998-camera-sensor-qrd-vr1.dtsi
index a56e9836784c..14567c3b5010 100644
--- a/arch/arm/boot/dts/qcom/msm8998-camera-sensor-qrd-vr1.dtsi
+++ b/arch/arm/boot/dts/qcom/msm8998-camera-sensor-qrd-vr1.dtsi
@@ -220,6 +220,7 @@
cell-index = <0>;
compatible = "qcom,camera";
reg = <0x0>;
+ qcom,special-support-sensors = "imx362_gt24c64a";
qcom,csiphy-sd-index = <0>;
qcom,csid-sd-index = <0>;
qcom,mount-angle = <270>;
diff --git a/arch/arm/boot/dts/qcom/msm8998-camera-sensor-skuk.dtsi b/arch/arm/boot/dts/qcom/msm8998-camera-sensor-skuk.dtsi
index da568fd8979c..36441f9aa15a 100644
--- a/arch/arm/boot/dts/qcom/msm8998-camera-sensor-skuk.dtsi
+++ b/arch/arm/boot/dts/qcom/msm8998-camera-sensor-skuk.dtsi
@@ -184,6 +184,8 @@
qcom,csiphy-sd-index = <0>;
qcom,csid-sd-index = <0>;
qcom,mount-angle = <270>;
+ qcom,led-flash-src = <&led_flash0>;
+ qcom,actuator-src = <&actuator0>;
qcom,eeprom-src = <&eeprom0>;
cam_vio-supply = <&pm8998_lvs1>;
cam_vana-supply = <&pmi8998_bob>;
diff --git a/arch/arm/boot/dts/qcom/msm8998-interposer-camera-sensor-cdp.dtsi b/arch/arm/boot/dts/qcom/msm8998-interposer-camera-sensor-cdp.dtsi
new file mode 100644
index 000000000000..3ef09569a430
--- /dev/null
+++ b/arch/arm/boot/dts/qcom/msm8998-interposer-camera-sensor-cdp.dtsi
@@ -0,0 +1,224 @@
+/*
+ * Copyright (c) 2016, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+&soc {
+ qcom,csiphy@ca34000 {
+ qcom,clock-rates = <0 0 0 0 0 0 384000000 0 0 269333333 0
+ 0 384000000 0>;
+ };
+
+ qcom,csiphy@ca35000 {
+ qcom,clock-rates = <0 0 0 0 0 0 384000000 0 0 269333333 0
+ 0 384000000 0>;
+ };
+
+ qcom,csiphy@ca36000 {
+ qcom,clock-rates = <0 0 0 0 0 0 384000000 0 0 269333333 0
+ 0 384000000 0>;
+ };
+
+ qcom,csid@ca30000 {
+ qcom,csi-vdd-voltage = <1225000>;
+ qcom,mipi-csi-vdd-supply = <&pmfalcon_l1>;
+ gdscr-supply = <&gdsc_camss_top>;
+ vdd_sec-supply = <&pm2falcon_l1>;
+ bimc_smmu-supply = <&gdsc_bimc_smmu>;
+ qcom,cam-vreg-name = "vdd_sec", "gdscr", "bimc_smmu";
+ qcom,clock-rates = <0 0 0 0 0 0 0 384000000 384000000
+ 0 0 0 0 0>;
+ };
+
+ qcom,csid@ca30400 {
+ qcom,csi-vdd-voltage = <1225000>;
+ qcom,mipi-csi-vdd-supply = <&pmfalcon_l1>;
+ gdscr-supply = <&gdsc_camss_top>;
+ vdd_sec-supply = <&pm2falcon_l1>;
+ bimc_smmu-supply = <&gdsc_bimc_smmu>;
+ qcom,cam-vreg-name = "vdd_sec", "gdscr", "bimc_smmu";
+ qcom,clock-rates = <0 0 0 0 0 0 0 384000000 384000000
+ 0 0 0 0 0>;
+ };
+
+ qcom,csid@ca30800 {
+ qcom,csi-vdd-voltage = <1225000>;
+ qcom,mipi-csi-vdd-supply = <&pmfalcon_l1>;
+ gdscr-supply = <&gdsc_camss_top>;
+ vdd_sec-supply = <&pm2falcon_l1>;
+ bimc_smmu-supply = <&gdsc_bimc_smmu>;
+ qcom,cam-vreg-name = "vdd_sec", "gdscr", "bimc_smmu";
+ qcom,clock-rates = <0 0 0 0 0 0 0 384000000 384000000
+ 0 0 0 0 0>;
+ };
+
+ qcom,csid@ca30c00 {
+ qcom,csi-vdd-voltage = <1225000>;
+ qcom,mipi-csi-vdd-supply = <&pmfalcon_l1>;
+ gdscr-supply = <&gdsc_camss_top>;
+ vdd_sec-supply = <&pm2falcon_l1>;
+ bimc_smmu-supply = <&gdsc_bimc_smmu>;
+ qcom,cam-vreg-name = "vdd_sec", "gdscr", "bimc_smmu";
+ qcom,clock-rates = <0 0 0 0 0 0 0 384000000 384000000
+ 0 0 0 0 0>;
+ };
+};
+
+&cci {
+ actuator0: qcom,actuator@0 {
+ cell-index = <0>;
+ reg = <0x0>;
+ compatible = "qcom,actuator";
+ qcom,cci-master = <0>;
+ gpios = <&tlmm 27 0>;
+ qcom,gpio-vaf = <0>;
+ qcom,gpio-req-tbl-num = <0>;
+ qcom,gpio-req-tbl-flags = <0>;
+ qcom,gpio-req-tbl-label = "CAM_VAF";
+ pinctrl-names = "cam_default", "cam_suspend";
+ pinctrl-0 = <&cam_actuator_vaf_active>;
+ pinctrl-1 = <&cam_actuator_vaf_suspend>;
+ };
+
+ actuator1: qcom,actuator@1 {
+ cell-index = <1>;
+ reg = <0x1>;
+ compatible = "qcom,actuator";
+ qcom,cci-master = <1>;
+ gpios = <&tlmm 27 0>;
+ qcom,gpio-vaf = <0>;
+ qcom,gpio-req-tbl-num = <0>;
+ qcom,gpio-req-tbl-flags = <0>;
+ qcom,gpio-req-tbl-label = "CAM_VAF";
+ pinctrl-names = "cam_default", "cam_suspend";
+ pinctrl-0 = <&cam_actuator_vaf_active>;
+ pinctrl-1 = <&cam_actuator_vaf_suspend>;
+ };
+
+ ois0: qcom,ois@0 {
+ cell-index = <0>;
+ reg = <0x0>;
+ compatible = "qcom,ois";
+ qcom,cci-master = <0>;
+ gpios = <&tlmm 27 0>;
+ qcom,gpio-vaf = <0>;
+ qcom,gpio-req-tbl-num = <0>;
+ qcom,gpio-req-tbl-flags = <0>;
+ qcom,gpio-req-tbl-label = "CAM_VAF";
+ pinctrl-names = "cam_default", "cam_suspend";
+ pinctrl-0 = <&cam_actuator_vaf_active>;
+ pinctrl-1 = <&cam_actuator_vaf_suspend>;
+ status = "disabled";
+ };
+
+ eeprom0: qcom,eeprom@0 {
+ cell-index = <0>;
+ reg = <0>;
+ compatible = "qcom,eeprom";
+ cam_vio-supply = <&pmfalcon_l11>;
+ cam_vana-supply = <&pm2falcon_bob>;
+ cam_vdig-supply = <&pmfalcon_s5>;
+ qcom,cam-vreg-name = "cam_vio", "cam_vana", "cam_vdig";
+ qcom,cam-vreg-min-voltage = <0 3300000 1350000>;
+ qcom,cam-vreg-max-voltage = <0 3600000 1350000>;
+ qcom,cam-vreg-op-mode = <0 80000 105000>;
+ qcom,gpio-no-mux = <0>;
+ pinctrl-names = "cam_default", "cam_suspend";
+ pinctrl-0 = <&cam_sensor_mclk0_active
+ &cam_sensor_rear_active
+ &cam_actuator_vaf_active>;
+ pinctrl-1 = <&cam_sensor_mclk0_suspend
+ &cam_sensor_rear_suspend
+ &cam_actuator_vaf_suspend>;
+ gpios = <&tlmm 13 0>,
+ <&tlmm 30 0>,
+ <&pmfalcon_gpios 4 0>,
+ <&tlmm 29 0>,
+ <&tlmm 27 0>;
+ qcom,gpio-reset = <1>;
+ qcom,gpio-vdig = <2>;
+ qcom,gpio-vana = <3>;
+ qcom,gpio-vaf = <4>;
+ qcom,gpio-req-tbl-num = <0 1 2 3 4>;
+ qcom,gpio-req-tbl-flags = <1 0 0 0 0>;
+ qcom,gpio-req-tbl-label = "CAMIF_MCLK0",
+ "CAM_RESET0",
+ "CAM_VDIG",
+ "CAM_VANA",
+ "CAM_VAF";
+ qcom,sensor-position = <0>;
+ qcom,sensor-mode = <0>;
+ qcom,cci-master = <0>;
+ status = "ok";
+ clocks = <&clock_mmss clk_mclk0_clk_src>,
+ <&clock_mmss clk_mmss_camss_mclk0_clk>;
+ clock-names = "cam_src_clk", "cam_clk";
+ qcom,clock-rates = <24000000 0>;
+ };
+
+ qcom,camera@0 {
+ cell-index = <0>;
+ compatible = "qcom,camera";
+ reg = <0x0>;
+ qcom,csiphy-sd-index = <0>;
+ qcom,csid-sd-index = <0>;
+ qcom,mount-angle = <270>;
+ qcom,actuator-src = <&actuator0>;
+ qcom,ois-src = <&ois0>;
+ qcom,eeprom-src = <&eeprom0>;
+ cam_vio-supply = <&pmfalcon_l11>;
+ cam_vana-supply = <&pm2falcon_bob>;
+ cam_vdig-supply = <&pmfalcon_s5>;
+ qcom,cam-vreg-name = "cam_vio", "cam_vana", "cam_vdig";
+ qcom,cam-vreg-min-voltage = <0 3300000 1350000>;
+ qcom,cam-vreg-max-voltage = <0 3600000 1350000>;
+ qcom,cam-vreg-op-mode = <0 80000 105000>;
+ qcom,gpio-no-mux = <0>;
+ pinctrl-names = "cam_default", "cam_suspend";
+ pinctrl-0 = <&cam_sensor_mclk0_active
+ &cam_sensor_rear_active>;
+ pinctrl-1 = <&cam_sensor_mclk0_suspend
+ &cam_sensor_rear_suspend>;
+ gpios = <&tlmm 13 0>,
+ <&tlmm 30 0>,
+ <&pmfalcon_gpios 4 0>,
+ <&tlmm 29 0>;
+ qcom,gpio-reset = <1>;
+ qcom,gpio-vdig = <2>;
+ qcom,gpio-vana = <3>;
+ qcom,gpio-req-tbl-num = <0 1 2 3>;
+ qcom,gpio-req-tbl-flags = <1 0 0 0>;
+ qcom,gpio-req-tbl-label = "CAMIF_MCLK0",
+ "CAM_RESET0",
+ "CAM_VDIG",
+ "CAM_VANA";
+ qcom,sensor-position = <0>;
+ qcom,sensor-mode = <0>;
+ qcom,cci-master = <0>;
+ status = "ok";
+ clocks = <&clock_mmss clk_mclk0_clk_src>,
+ <&clock_mmss clk_mmss_camss_mclk0_clk>;
+ clock-names = "cam_src_clk", "cam_clk";
+ qcom,clock-rates = <24000000 0>;
+ };
+};
+
+&pmfalcon_gpios {
+ gpio@c300 { /* GPIO4 -CAMERA SENSOR 0 VDIG*/
+ qcom,mode = <1>; /* Output */
+ qcom,pull = <5>; /* No Pull */
+ qcom,vin-sel = <0>; /* VIN1 GPIO_LV */
+ qcom,src-sel = <0>; /* GPIO */
+ qcom,invert = <0>; /* Invert */
+ qcom,master-en = <1>; /* Enable GPIO */
+ status = "ok";
+ };
+};
diff --git a/arch/arm/boot/dts/qcom/msm8998-interposer-camera-sensor-mtp.dtsi b/arch/arm/boot/dts/qcom/msm8998-interposer-camera-sensor-mtp.dtsi
new file mode 100644
index 000000000000..3ef09569a430
--- /dev/null
+++ b/arch/arm/boot/dts/qcom/msm8998-interposer-camera-sensor-mtp.dtsi
@@ -0,0 +1,224 @@
+/*
+ * Copyright (c) 2016, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+&soc {
+ qcom,csiphy@ca34000 {
+ qcom,clock-rates = <0 0 0 0 0 0 384000000 0 0 269333333 0
+ 0 384000000 0>;
+ };
+
+ qcom,csiphy@ca35000 {
+ qcom,clock-rates = <0 0 0 0 0 0 384000000 0 0 269333333 0
+ 0 384000000 0>;
+ };
+
+ qcom,csiphy@ca36000 {
+ qcom,clock-rates = <0 0 0 0 0 0 384000000 0 0 269333333 0
+ 0 384000000 0>;
+ };
+
+ qcom,csid@ca30000 {
+ qcom,csi-vdd-voltage = <1225000>;
+ qcom,mipi-csi-vdd-supply = <&pmfalcon_l1>;
+ gdscr-supply = <&gdsc_camss_top>;
+ vdd_sec-supply = <&pm2falcon_l1>;
+ bimc_smmu-supply = <&gdsc_bimc_smmu>;
+ qcom,cam-vreg-name = "vdd_sec", "gdscr", "bimc_smmu";
+ qcom,clock-rates = <0 0 0 0 0 0 0 384000000 384000000
+ 0 0 0 0 0>;
+ };
+
+ qcom,csid@ca30400 {
+ qcom,csi-vdd-voltage = <1225000>;
+ qcom,mipi-csi-vdd-supply = <&pmfalcon_l1>;
+ gdscr-supply = <&gdsc_camss_top>;
+ vdd_sec-supply = <&pm2falcon_l1>;
+ bimc_smmu-supply = <&gdsc_bimc_smmu>;
+ qcom,cam-vreg-name = "vdd_sec", "gdscr", "bimc_smmu";
+ qcom,clock-rates = <0 0 0 0 0 0 0 384000000 384000000
+ 0 0 0 0 0>;
+ };
+
+ qcom,csid@ca30800 {
+ qcom,csi-vdd-voltage = <1225000>;
+ qcom,mipi-csi-vdd-supply = <&pmfalcon_l1>;
+ gdscr-supply = <&gdsc_camss_top>;
+ vdd_sec-supply = <&pm2falcon_l1>;
+ bimc_smmu-supply = <&gdsc_bimc_smmu>;
+ qcom,cam-vreg-name = "vdd_sec", "gdscr", "bimc_smmu";
+ qcom,clock-rates = <0 0 0 0 0 0 0 384000000 384000000
+ 0 0 0 0 0>;
+ };
+
+ qcom,csid@ca30c00 {
+ qcom,csi-vdd-voltage = <1225000>;
+ qcom,mipi-csi-vdd-supply = <&pmfalcon_l1>;
+ gdscr-supply = <&gdsc_camss_top>;
+ vdd_sec-supply = <&pm2falcon_l1>;
+ bimc_smmu-supply = <&gdsc_bimc_smmu>;
+ qcom,cam-vreg-name = "vdd_sec", "gdscr", "bimc_smmu";
+ qcom,clock-rates = <0 0 0 0 0 0 0 384000000 384000000
+ 0 0 0 0 0>;
+ };
+};
+
+&cci {
+ actuator0: qcom,actuator@0 {
+ cell-index = <0>;
+ reg = <0x0>;
+ compatible = "qcom,actuator";
+ qcom,cci-master = <0>;
+ gpios = <&tlmm 27 0>;
+ qcom,gpio-vaf = <0>;
+ qcom,gpio-req-tbl-num = <0>;
+ qcom,gpio-req-tbl-flags = <0>;
+ qcom,gpio-req-tbl-label = "CAM_VAF";
+ pinctrl-names = "cam_default", "cam_suspend";
+ pinctrl-0 = <&cam_actuator_vaf_active>;
+ pinctrl-1 = <&cam_actuator_vaf_suspend>;
+ };
+
+ actuator1: qcom,actuator@1 {
+ cell-index = <1>;
+ reg = <0x1>;
+ compatible = "qcom,actuator";
+ qcom,cci-master = <1>;
+ gpios = <&tlmm 27 0>;
+ qcom,gpio-vaf = <0>;
+ qcom,gpio-req-tbl-num = <0>;
+ qcom,gpio-req-tbl-flags = <0>;
+ qcom,gpio-req-tbl-label = "CAM_VAF";
+ pinctrl-names = "cam_default", "cam_suspend";
+ pinctrl-0 = <&cam_actuator_vaf_active>;
+ pinctrl-1 = <&cam_actuator_vaf_suspend>;
+ };
+
+ ois0: qcom,ois@0 {
+ cell-index = <0>;
+ reg = <0x0>;
+ compatible = "qcom,ois";
+ qcom,cci-master = <0>;
+ gpios = <&tlmm 27 0>;
+ qcom,gpio-vaf = <0>;
+ qcom,gpio-req-tbl-num = <0>;
+ qcom,gpio-req-tbl-flags = <0>;
+ qcom,gpio-req-tbl-label = "CAM_VAF";
+ pinctrl-names = "cam_default", "cam_suspend";
+ pinctrl-0 = <&cam_actuator_vaf_active>;
+ pinctrl-1 = <&cam_actuator_vaf_suspend>;
+ status = "disabled";
+ };
+
+ eeprom0: qcom,eeprom@0 {
+ cell-index = <0>;
+ reg = <0>;
+ compatible = "qcom,eeprom";
+ cam_vio-supply = <&pmfalcon_l11>;
+ cam_vana-supply = <&pm2falcon_bob>;
+ cam_vdig-supply = <&pmfalcon_s5>;
+ qcom,cam-vreg-name = "cam_vio", "cam_vana", "cam_vdig";
+ qcom,cam-vreg-min-voltage = <0 3300000 1350000>;
+ qcom,cam-vreg-max-voltage = <0 3600000 1350000>;
+ qcom,cam-vreg-op-mode = <0 80000 105000>;
+ qcom,gpio-no-mux = <0>;
+ pinctrl-names = "cam_default", "cam_suspend";
+ pinctrl-0 = <&cam_sensor_mclk0_active
+ &cam_sensor_rear_active
+ &cam_actuator_vaf_active>;
+ pinctrl-1 = <&cam_sensor_mclk0_suspend
+ &cam_sensor_rear_suspend
+ &cam_actuator_vaf_suspend>;
+ gpios = <&tlmm 13 0>,
+ <&tlmm 30 0>,
+ <&pmfalcon_gpios 4 0>,
+ <&tlmm 29 0>,
+ <&tlmm 27 0>;
+ qcom,gpio-reset = <1>;
+ qcom,gpio-vdig = <2>;
+ qcom,gpio-vana = <3>;
+ qcom,gpio-vaf = <4>;
+ qcom,gpio-req-tbl-num = <0 1 2 3 4>;
+ qcom,gpio-req-tbl-flags = <1 0 0 0 0>;
+ qcom,gpio-req-tbl-label = "CAMIF_MCLK0",
+ "CAM_RESET0",
+ "CAM_VDIG",
+ "CAM_VANA",
+ "CAM_VAF";
+ qcom,sensor-position = <0>;
+ qcom,sensor-mode = <0>;
+ qcom,cci-master = <0>;
+ status = "ok";
+ clocks = <&clock_mmss clk_mclk0_clk_src>,
+ <&clock_mmss clk_mmss_camss_mclk0_clk>;
+ clock-names = "cam_src_clk", "cam_clk";
+ qcom,clock-rates = <24000000 0>;
+ };
+
+ qcom,camera@0 {
+ cell-index = <0>;
+ compatible = "qcom,camera";
+ reg = <0x0>;
+ qcom,csiphy-sd-index = <0>;
+ qcom,csid-sd-index = <0>;
+ qcom,mount-angle = <270>;
+ qcom,actuator-src = <&actuator0>;
+ qcom,ois-src = <&ois0>;
+ qcom,eeprom-src = <&eeprom0>;
+ cam_vio-supply = <&pmfalcon_l11>;
+ cam_vana-supply = <&pm2falcon_bob>;
+ cam_vdig-supply = <&pmfalcon_s5>;
+ qcom,cam-vreg-name = "cam_vio", "cam_vana", "cam_vdig";
+ qcom,cam-vreg-min-voltage = <0 3300000 1350000>;
+ qcom,cam-vreg-max-voltage = <0 3600000 1350000>;
+ qcom,cam-vreg-op-mode = <0 80000 105000>;
+ qcom,gpio-no-mux = <0>;
+ pinctrl-names = "cam_default", "cam_suspend";
+ pinctrl-0 = <&cam_sensor_mclk0_active
+ &cam_sensor_rear_active>;
+ pinctrl-1 = <&cam_sensor_mclk0_suspend
+ &cam_sensor_rear_suspend>;
+ gpios = <&tlmm 13 0>,
+ <&tlmm 30 0>,
+ <&pmfalcon_gpios 4 0>,
+ <&tlmm 29 0>;
+ qcom,gpio-reset = <1>;
+ qcom,gpio-vdig = <2>;
+ qcom,gpio-vana = <3>;
+ qcom,gpio-req-tbl-num = <0 1 2 3>;
+ qcom,gpio-req-tbl-flags = <1 0 0 0>;
+ qcom,gpio-req-tbl-label = "CAMIF_MCLK0",
+ "CAM_RESET0",
+ "CAM_VDIG",
+ "CAM_VANA";
+ qcom,sensor-position = <0>;
+ qcom,sensor-mode = <0>;
+ qcom,cci-master = <0>;
+ status = "ok";
+ clocks = <&clock_mmss clk_mclk0_clk_src>,
+ <&clock_mmss clk_mmss_camss_mclk0_clk>;
+ clock-names = "cam_src_clk", "cam_clk";
+ qcom,clock-rates = <24000000 0>;
+ };
+};
+
+&pmfalcon_gpios {
+ gpio@c300 { /* GPIO4 -CAMERA SENSOR 0 VDIG*/
+ qcom,mode = <1>; /* Output */
+ qcom,pull = <5>; /* No Pull */
+ qcom,vin-sel = <0>; /* VIN1 GPIO_LV */
+ qcom,src-sel = <0>; /* GPIO */
+ qcom,invert = <0>; /* Invert */
+ qcom,master-en = <1>; /* Enable GPIO */
+ status = "ok";
+ };
+};
diff --git a/arch/arm/boot/dts/qcom/msm8998-interposer-msmfalcon-audio.dtsi b/arch/arm/boot/dts/qcom/msm8998-interposer-msmfalcon-audio.dtsi
new file mode 100644
index 000000000000..20c69e0a9a1a
--- /dev/null
+++ b/arch/arm/boot/dts/qcom/msm8998-interposer-msmfalcon-audio.dtsi
@@ -0,0 +1,73 @@
+/* Copyright (c) 2016, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * 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.
+ */
+
+&clock_audio {
+ qcom,audio-ref-clk-gpio = <&pmfalcon_gpios 3 0>;
+};
+
+&slim_aud {
+ tasha_codec {
+ cdc-vdd-buck-supply = <&pmfalcon_s4>;
+ qcom,cdc-vdd-buck-voltage = <1800000 1800000>;
+ qcom,cdc-vdd-buck-current = <650000>;
+
+ cdc-buck-sido-supply = <&pmfalcon_s4>;
+ qcom,cdc-buck-sido-voltage = <1800000 1800000>;
+ qcom,cdc-buck-sido-current = <250000>;
+
+ cdc-vdd-tx-h-supply = <&pmfalcon_s4>;
+ qcom,cdc-vdd-tx-h-voltage = <1800000 1800000>;
+ qcom,cdc-vdd-tx-h-current = <25000>;
+
+ cdc-vdd-rx-h-supply = <&pmfalcon_s4>;
+ qcom,cdc-vdd-rx-h-voltage = <1800000 1800000>;
+ qcom,cdc-vdd-rx-h-current = <25000>;
+
+ cdc-vddpx-1-supply = <&pmfalcon_s4>;
+ qcom,cdc-vddpx-1-voltage = <1800000 1800000>;
+ qcom,cdc-vddpx-1-current = <10000>;
+ };
+
+ tavil_codec {
+ cdc-vdd-buck-supply = <&pmfalcon_s4>;
+ qcom,cdc-vdd-buck-voltage = <1800000 1800000>;
+ qcom,cdc-vdd-buck-current = <650000>;
+
+ cdc-buck-sido-supply = <&pmfalcon_s4>;
+ qcom,cdc-buck-sido-voltage = <1800000 1800000>;
+ qcom,cdc-buck-sido-current = <250000>;
+
+ cdc-vdd-tx-h-supply = <&pmfalcon_s4>;
+ qcom,cdc-vdd-tx-h-voltage = <1800000 1800000>;
+ qcom,cdc-vdd-tx-h-current = <25000>;
+
+ cdc-vdd-rx-h-supply = <&pmfalcon_s4>;
+ qcom,cdc-vdd-rx-h-voltage = <1800000 1800000>;
+ qcom,cdc-vdd-rx-h-current = <25000>;
+
+ cdc-vddpx-1-supply = <&pmfalcon_s4>;
+ qcom,cdc-vddpx-1-voltage = <1800000 1800000>;
+ qcom,cdc-vddpx-1-current = <10000>;
+ };
+};
+
+&pmfalcon_gpios {
+ gpio@c200 {
+ status = "ok";
+ qcom,mode = <1>;
+ qcom,pull = <5>;
+ qcom,vin-sel = <0>;
+ qcom,src-sel = <2>;
+ qcom,master-en = <1>;
+ qcom,out-strength = <2>;
+ };
+};
diff --git a/arch/arm/boot/dts/qcom/msm8998-interposer-msmfalcon-cdp.dtsi b/arch/arm/boot/dts/qcom/msm8998-interposer-msmfalcon-cdp.dtsi
index 32f9dcdecb0c..76326e7ae86f 100644
--- a/arch/arm/boot/dts/qcom/msm8998-interposer-msmfalcon-cdp.dtsi
+++ b/arch/arm/boot/dts/qcom/msm8998-interposer-msmfalcon-cdp.dtsi
@@ -69,12 +69,12 @@
};
&sdhc_2 {
- vdd-supply = <&pm8998_l21>;
- qcom,vdd-voltage-level = <2950000 2960000>;
+ vdd-supply = <&pm2falcon_l5>;
+ qcom,vdd-voltage-level = <2950000 2950000>;
qcom,vdd-current-level = <200 800000>;
- vdd-io-supply = <&pm8998_l13>;
- qcom,vdd-io-voltage-level = <1808000 2960000>;
+ vdd-io-supply = <&pm2falcon_l2>;
+ qcom,vdd-io-voltage-level = <1800000 2950000>;
qcom,vdd-io-current-level = <200 22000>;
pinctrl-names = "active", "sleep";
diff --git a/arch/arm/boot/dts/qcom/msm8998-interposer-msmfalcon-mtp.dtsi b/arch/arm/boot/dts/qcom/msm8998-interposer-msmfalcon-mtp.dtsi
index e73ffc884210..5c55732e0de7 100644
--- a/arch/arm/boot/dts/qcom/msm8998-interposer-msmfalcon-mtp.dtsi
+++ b/arch/arm/boot/dts/qcom/msm8998-interposer-msmfalcon-mtp.dtsi
@@ -70,12 +70,12 @@
};
&sdhc_2 {
- vdd-supply = <&pm8998_l21>;
- qcom,vdd-voltage-level = <2950000 2960000>;
+ vdd-supply = <&pm2falcon_l5>;
+ qcom,vdd-voltage-level = <2950000 2950000>;
qcom,vdd-current-level = <200 800000>;
- vdd-io-supply = <&pm8998_l13>;
- qcom,vdd-io-voltage-level = <1808000 2960000>;
+ vdd-io-supply = <&pm2falcon_l2>;
+ qcom,vdd-io-voltage-level = <1800000 2950000>;
qcom,vdd-io-current-level = <200 22000>;
pinctrl-names = "active", "sleep";
diff --git a/arch/arm/boot/dts/qcom/msm8998-interposer-msmfalcon.dtsi b/arch/arm/boot/dts/qcom/msm8998-interposer-msmfalcon.dtsi
index 861be92a7bc2..1ca5ce6eabbb 100644
--- a/arch/arm/boot/dts/qcom/msm8998-interposer-msmfalcon.dtsi
+++ b/arch/arm/boot/dts/qcom/msm8998-interposer-msmfalcon.dtsi
@@ -1853,7 +1853,7 @@
<61 512 240000 800000>;
qcom,dwc-usb3-msm-tx-fifo-size = <21288>;
- extcon = <&pmi8998_pdphy>;
+ extcon = <&pmfalcon_pdphy>;
clocks = <&clock_gcc clk_gcc_usb30_master_clk>,
<&clock_gcc clk_gcc_cfg_noc_usb3_axi_clk>,
@@ -1921,9 +1921,9 @@
<0x01fcb24c 0x4>;
reg-names = "qusb_phy_base",
"tcsr_clamp_dig_n_1p8";
- vdd-supply = <&pm8998_l1>;
- vdda18-supply = <&pm8998_l12>;
- vdda33-supply = <&pm8998_l24>;
+ vdd-supply = <&pm2falcon_l1>;
+ vdda18-supply = <&pm2falcon_l10>;
+ vdda33-supply = <&pm2falcon_l7>;
qcom,vdd-voltage-level = <0 880000 880000>;
qcom,qusb-phy-init-seq =
/* <value reg_offset> */
@@ -1951,8 +1951,8 @@
reg-names = "qmp_phy_base",
"vls_clamp_reg",
"tcsr_usb3_dp_phymode";
- vdd-supply = <&pm8998_l1>;
- core-supply = <&pm8998_l2>;
+ vdd-supply = <&pm2falcon_l1>;
+ core-supply = <&pmfalcon_l1>;
qcom,vdd-voltage-level = <0 880000 880000>;
qcom,vbus-valid-override;
qcom,qmp-phy-init-seq =
@@ -3083,12 +3083,11 @@
#include "msm8998-bus.dtsi"
#include "msm8998-gpu.dtsi"
#include "msm8998-pinctrl.dtsi"
-#include "msm-audio-lpass.dtsi"
#include "msm8998-mdss.dtsi"
#include "msm8998-mdss-pll.dtsi"
#include "msm8998-blsp.dtsi"
-#include "msm8998-audio.dtsi"
-
+#include "msm-audio.dtsi"
+#include "msmfalcon-audio.dtsi"
/* GPU overrides */
&msm_gpu {
diff --git a/arch/arm/boot/dts/qcom/msm8998-interposer-pmfalcon.dtsi b/arch/arm/boot/dts/qcom/msm8998-interposer-pmfalcon.dtsi
index f5d5c7f400f9..54a2a4a00dc0 100644
--- a/arch/arm/boot/dts/qcom/msm8998-interposer-pmfalcon.dtsi
+++ b/arch/arm/boot/dts/qcom/msm8998-interposer-pmfalcon.dtsi
@@ -45,12 +45,6 @@
/delete-property/qcom,switch-source;
};
-&eeprom0 {
- /delete-property/cam_vio-supply;
- /delete-property/cam_vana-supply;
- /delete-property/cam_vdig-supply;
- /delete-property/gpios;
-};
&eeprom1 {
/delete-property/cam_vio-supply;
@@ -66,7 +60,6 @@
};
&cci {
- /delete-node/qcom,camera@0;
/delete-node/qcom,camera@1;
/delete-node/qcom,camera@2;
@@ -199,9 +192,7 @@
};
&gfx_cpr {
- reg = <0x05061000 0x4000>,
- <0x00784000 0x1000>;
- reg-names = "cpr_ctrl", "fuse_base";
+ status = "disabled";
/* disable aging and closed-loop */
/delete-property/vdd-supply;
@@ -212,6 +203,8 @@
};
&gfx_vreg {
+ status = "disabled";
+
/delete-property/qcom,cpr-aging-max-voltage-adjustment;
/delete-property/qcom,cpr-aging-ref-corner;
/delete-property/qcom,cpr-aging-ro-scaling-factor;
@@ -220,10 +213,6 @@
};
&soc {
- /delete-node/qcom,csid@ca30000;
- /delete-node/qcom,csid@ca30400;
- /delete-node/qcom,csid@ca30800;
- /delete-node/qcom,csid@ca30c00;
/delete-node/gpio_keys;
/delete-node/qcom,lpass@17300000;
/delete-node/qcom,mss@4080000;
@@ -263,6 +252,8 @@
#include "msm-pmfalcon.dtsi"
#include "msm-pm2falcon.dtsi"
+#include "msm-pmfalcon-rpm-regulator.dtsi"
+#include "msm-pm2falcon-rpm-regulator.dtsi"
#include "msmfalcon-regulator.dtsi"
/* dummy LCDB regulator nodes */
diff --git a/arch/arm/boot/dts/qcom/msm8998-mtp.dtsi b/arch/arm/boot/dts/qcom/msm8998-mtp.dtsi
index 76124833dc36..45d6398daf25 100644
--- a/arch/arm/boot/dts/qcom/msm8998-mtp.dtsi
+++ b/arch/arm/boot/dts/qcom/msm8998-mtp.dtsi
@@ -623,5 +623,6 @@
qcom,batt-id-range-pct = <15>;
#include "fg-gen3-batterydata-itech-3000mah.dtsi"
#include "fg-gen3-batterydata-ascent-3450mah.dtsi"
+ #include "fg-gen3-batterydata-demo-6000mah.dtsi"
};
};
diff --git a/arch/arm/boot/dts/qcom/msm8998-pinctrl.dtsi b/arch/arm/boot/dts/qcom/msm8998-pinctrl.dtsi
index 1f5facd5cde5..5685e9041fe4 100644
--- a/arch/arm/boot/dts/qcom/msm8998-pinctrl.dtsi
+++ b/arch/arm/boot/dts/qcom/msm8998-pinctrl.dtsi
@@ -1624,6 +1624,52 @@
};
};
+ ufs_dev_reset_assert: ufs_dev_reset_assert {
+ config {
+ pins = "ufs_reset";
+ bias-pull-down; /* default: pull down */
+ /*
+ * UFS_RESET driver strengths are having
+ * different values/steps compared to typical
+ * GPIO drive strengths.
+ *
+ * Following table clarifies:
+ *
+ * HDRV value | UFS_RESET | Typical GPIO
+ * (dec) | (mA) | (mA)
+ * 0 | 0.8 | 2
+ * 1 | 1.55 | 4
+ * 2 | 2.35 | 6
+ * 3 | 3.1 | 8
+ * 4 | 3.9 | 10
+ * 5 | 4.65 | 12
+ * 6 | 5.4 | 14
+ * 7 | 6.15 | 16
+ *
+ * POR value for UFS_RESET HDRV is 3 which means
+ * 3.1mA and we want to use that. Hence just
+ * specify 8mA to "drive-strength" binding and
+ * that should result into writing 3 to HDRV
+ * field.
+ */
+ drive-strength = <8>; /* default: 3.1 mA */
+ output-low; /* active low reset */
+ };
+ };
+
+ ufs_dev_reset_deassert: ufs_dev_reset_deassert {
+ config {
+ pins = "ufs_reset";
+ bias-pull-down; /* default: pull down */
+ /*
+ * default: 3.1 mA
+ * check comments under ufs_dev_reset_assert
+ */
+ drive-strength = <8>;
+ output-high; /* active low reset */
+ };
+ };
+
sdc2_clk_on: sdc2_clk_on {
config {
pins = "sdc2_clk";
diff --git a/arch/arm/boot/dts/qcom/msm8998-qrd-skuk.dtsi b/arch/arm/boot/dts/qcom/msm8998-qrd-skuk.dtsi
index cead74b02528..c09900597d87 100644
--- a/arch/arm/boot/dts/qcom/msm8998-qrd-skuk.dtsi
+++ b/arch/arm/boot/dts/qcom/msm8998-qrd-skuk.dtsi
@@ -15,6 +15,33 @@
#include "msm8998-audio.dtsi"
#include "msm8998-camera-sensor-skuk.dtsi"
+/ {
+ bluetooth: bt_wcn3990 {
+ compatible = "qca,wcn3990";
+ qca,bt-vdd-io-supply = <&pm8998_s3>;
+ qca,bt-vdd-xtal-supply = <&pm8998_s5>;
+ qca,bt-vdd-core-supply = <&pm8998_l7>;
+ qca,bt-vdd-pa-supply = <&pm8998_l17>;
+ qca,bt-vdd-ldo-supply = <&pm8998_l25>;
+ qca,bt-chip-pwd-supply = <&pmi8998_bob_pin1>;
+ clocks = <&clock_gcc clk_rf_clk2_pin>;
+ clock-names = "rf_clk2";
+
+ qca,bt-vdd-io-voltage-level = <1352000 1352000>;
+ qca,bt-vdd-xtal-voltage-level = <2040000 2040000>;
+ qca,bt-vdd-core-voltage-level = <1800000 1800000>;
+ qca,bt-vdd-pa-voltage-level = <1304000 1304000>;
+ qca,bt-vdd-ldo-voltage-level = <3312000 3312000>;
+ qca,bt-chip-pwd-voltage-level = <3600000 3600000>;
+
+ qca,bt-vdd-io-current-level = <1>; /* LPM/PFM */
+ qca,bt-vdd-xtal-current-level = <1>; /* LPM/PFM */
+ qca,bt-vdd-core-current-level = <1>; /* LPM/PFM */
+ qca,bt-vdd-pa-current-level = <1>; /* LPM/PFM */
+ qca,bt-vdd-ldo-current-level = <1>; /* LPM/PFM */
+ };
+};
+
&blsp1_uart3_hs {
status = "ok";
};
@@ -210,3 +237,105 @@
&pmi8998_haptics {
status = "okay";
};
+
+&pm8998_vadc {
+ chan@83 {
+ label = "vph_pwr";
+ reg = <0x83>;
+ qcom,decimation = <2>;
+ qcom,pre-div-channel-scaling = <1>;
+ qcom,calibration-type = "absolute";
+ qcom,scale-function = <0>;
+ qcom,hw-settle-time = <0>;
+ qcom,fast-avg-setup = <0>;
+ };
+
+ chan@85 {
+ label = "vcoin";
+ reg = <0x85>;
+ qcom,decimation = <2>;
+ qcom,pre-div-channel-scaling = <1>;
+ qcom,calibration-type = "absolute";
+ qcom,scale-function = <0>;
+ qcom,hw-settle-time = <0>;
+ qcom,fast-avg-setup = <0>;
+ };
+
+ chan@4c {
+ label = "xo_therm";
+ reg = <0x4c>;
+ qcom,decimation = <2>;
+ qcom,pre-div-channel-scaling = <0>;
+ qcom,calibration-type = "ratiometric";
+ qcom,scale-function = <4>;
+ qcom,hw-settle-time = <2>;
+ qcom,fast-avg-setup = <0>;
+ };
+
+ chan@4d {
+ label = "msm_therm";
+ reg = <0x4d>;
+ 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>;
+ };
+
+ chan@51 {
+ label = "quiet_therm";
+ reg = <0x51>;
+ 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>;
+ };
+};
+
+&pm8998_adc_tm {
+ chan@83 {
+ label = "vph_pwr";
+ reg = <0x83>;
+ qcom,pre-div-channel-scaling = <1>;
+ qcom,calibration-type = "absolute";
+ qcom,scale-function = <0>;
+ qcom,hw-settle-time = <0>;
+ qcom,btm-channel-number = <0x60>;
+ };
+
+ chan@4d {
+ label = "msm_therm";
+ reg = <0x4d>;
+ qcom,pre-div-channel-scaling = <0>;
+ qcom,calibration-type = "ratiometric";
+ qcom,scale-function = <2>;
+ qcom,hw-settle-time = <2>;
+ qcom,btm-channel-number = <0x68>;
+ qcom,thermal-node;
+ };
+
+ chan@51 {
+ label = "quiet_therm";
+ reg = <0x51>;
+ qcom,pre-div-channel-scaling = <0>;
+ qcom,calibration-type = "ratiometric";
+ qcom,scale-function = <2>;
+ qcom,hw-settle-time = <2>;
+ qcom,btm-channel-number = <0x70>;
+ qcom,thermal-node;
+ };
+
+ chan@4c {
+ label = "xo_therm";
+ reg = <0x4c>;
+ qcom,pre-div-channel-scaling = <0>;
+ qcom,calibration-type = "ratiometric";
+ qcom,scale-function = <4>;
+ qcom,hw-settle-time = <2>;
+ qcom,btm-channel-number = <0x78>;
+ qcom,thermal-node;
+ };
+};
diff --git a/arch/arm/boot/dts/qcom/msm8998-qrd-vr1.dtsi b/arch/arm/boot/dts/qcom/msm8998-qrd-vr1.dtsi
index ccdfe7ee03f6..bd9d8147dd82 100644
--- a/arch/arm/boot/dts/qcom/msm8998-qrd-vr1.dtsi
+++ b/arch/arm/boot/dts/qcom/msm8998-qrd-vr1.dtsi
@@ -14,6 +14,33 @@
#include "msm8998-pinctrl.dtsi"
#include "msm8998-camera-sensor-qrd-vr1.dtsi"
+/ {
+ bluetooth: bt_wcn3990 {
+ compatible = "qca,wcn3990";
+ qca,bt-vdd-io-supply = <&pm8998_s3>;
+ qca,bt-vdd-xtal-supply = <&pm8998_s5>;
+ qca,bt-vdd-core-supply = <&pm8998_l7>;
+ qca,bt-vdd-pa-supply = <&pm8998_l17>;
+ qca,bt-vdd-ldo-supply = <&pm8998_l25>;
+ qca,bt-chip-pwd-supply = <&pmi8998_bob_pin1>;
+ clocks = <&clock_gcc clk_rf_clk2_pin>;
+ clock-names = "rf_clk2";
+
+ qca,bt-vdd-io-voltage-level = <1352000 1352000>;
+ qca,bt-vdd-xtal-voltage-level = <2040000 2040000>;
+ qca,bt-vdd-core-voltage-level = <1800000 1800000>;
+ qca,bt-vdd-pa-voltage-level = <1304000 1304000>;
+ qca,bt-vdd-ldo-voltage-level = <3312000 3312000>;
+ qca,bt-chip-pwd-voltage-level = <3600000 3600000>;
+
+ qca,bt-vdd-io-current-level = <1>; /* LPM/PFM */
+ qca,bt-vdd-xtal-current-level = <1>; /* LPM/PFM */
+ qca,bt-vdd-core-current-level = <1>; /* LPM/PFM */
+ qca,bt-vdd-pa-current-level = <1>; /* LPM/PFM */
+ qca,bt-vdd-ldo-current-level = <1>; /* LPM/PFM */
+ };
+};
+
&blsp1_uart3_hs {
status = "ok";
};
@@ -144,3 +171,105 @@
&pmi8998_haptics {
status = "okay";
};
+
+&pm8998_vadc {
+ chan@83 {
+ label = "vph_pwr";
+ reg = <0x83>;
+ qcom,decimation = <2>;
+ qcom,pre-div-channel-scaling = <1>;
+ qcom,calibration-type = "absolute";
+ qcom,scale-function = <0>;
+ qcom,hw-settle-time = <0>;
+ qcom,fast-avg-setup = <0>;
+ };
+
+ chan@85 {
+ label = "vcoin";
+ reg = <0x85>;
+ qcom,decimation = <2>;
+ qcom,pre-div-channel-scaling = <1>;
+ qcom,calibration-type = "absolute";
+ qcom,scale-function = <0>;
+ qcom,hw-settle-time = <0>;
+ qcom,fast-avg-setup = <0>;
+ };
+
+ chan@4c {
+ label = "xo_therm";
+ reg = <0x4c>;
+ qcom,decimation = <2>;
+ qcom,pre-div-channel-scaling = <0>;
+ qcom,calibration-type = "ratiometric";
+ qcom,scale-function = <4>;
+ qcom,hw-settle-time = <2>;
+ qcom,fast-avg-setup = <0>;
+ };
+
+ chan@4d {
+ label = "msm_therm";
+ reg = <0x4d>;
+ 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>;
+ };
+
+ chan@51 {
+ label = "quiet_therm";
+ reg = <0x51>;
+ 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>;
+ };
+};
+
+&pm8998_adc_tm {
+ chan@83 {
+ label = "vph_pwr";
+ reg = <0x83>;
+ qcom,pre-div-channel-scaling = <1>;
+ qcom,calibration-type = "absolute";
+ qcom,scale-function = <0>;
+ qcom,hw-settle-time = <0>;
+ qcom,btm-channel-number = <0x60>;
+ };
+
+ chan@4d {
+ label = "msm_therm";
+ reg = <0x4d>;
+ qcom,pre-div-channel-scaling = <0>;
+ qcom,calibration-type = "ratiometric";
+ qcom,scale-function = <2>;
+ qcom,hw-settle-time = <2>;
+ qcom,btm-channel-number = <0x68>;
+ qcom,thermal-node;
+ };
+
+ chan@51 {
+ label = "quiet_therm";
+ reg = <0x51>;
+ qcom,pre-div-channel-scaling = <0>;
+ qcom,calibration-type = "ratiometric";
+ qcom,scale-function = <2>;
+ qcom,hw-settle-time = <2>;
+ qcom,btm-channel-number = <0x70>;
+ qcom,thermal-node;
+ };
+
+ chan@4c {
+ label = "xo_therm";
+ reg = <0x4c>;
+ qcom,pre-div-channel-scaling = <0>;
+ qcom,calibration-type = "ratiometric";
+ qcom,scale-function = <4>;
+ qcom,hw-settle-time = <2>;
+ qcom,btm-channel-number = <0x78>;
+ qcom,thermal-node;
+ };
+};
diff --git a/arch/arm/boot/dts/qcom/msm8998-qrd.dtsi b/arch/arm/boot/dts/qcom/msm8998-qrd.dtsi
index 41f9c3c69fe9..0a011b3656be 100644
--- a/arch/arm/boot/dts/qcom/msm8998-qrd.dtsi
+++ b/arch/arm/boot/dts/qcom/msm8998-qrd.dtsi
@@ -11,7 +11,6 @@
*/
#include <dt-bindings/interrupt-controller/irq.h>
-#include "msm8998-mtp.dtsi"
#include "msm8998-pinctrl.dtsi"
#include "msm8998-camera-sensor-qrd.dtsi"
/ {
diff --git a/arch/arm/boot/dts/qcom/msm8998-v2-interposer-msmfalcon.dtsi b/arch/arm/boot/dts/qcom/msm8998-v2-interposer-msmfalcon.dtsi
index d207628f06a1..dc548f8f499b 100644
--- a/arch/arm/boot/dts/qcom/msm8998-v2-interposer-msmfalcon.dtsi
+++ b/arch/arm/boot/dts/qcom/msm8998-v2-interposer-msmfalcon.dtsi
@@ -26,6 +26,25 @@
&clock_cpu {
compatible = "qcom,cpu-clock-osm-msm8998-v2";
+ reg = <0x179c0000 0x4000>,
+ <0x17916000 0x1000>,
+ <0x17816000 0x1000>,
+ <0x179d1000 0x1000>,
+ <0x17914800 0x800>,
+ <0x17814800 0x800>,
+ <0x00784130 0x8>,
+ <0x1791101c 0x8>;
+ reg-names = "osm", "pwrcl_pll", "perfcl_pll",
+ "apcs_common", "pwrcl_acd", "perfcl_acd",
+ "perfcl_efuse", "debug";
+
+ qcom,acdtd-val = <0x00009611 0x00009611>;
+ qcom,acdcr-val = <0x002b5ffd 0x002b5ffd>;
+ qcom,acdsscr-val = <0x00000501 0x00000501>;
+ qcom,acdextint0-val = <0x2cf9ae8 0x2cf9ae8>;
+ qcom,acdextint1-val = <0x2cf9afc 0x2cf9afc>;
+ qcom,acdautoxfer-val = <0x00000015 0x00000015>;
+
/delete-property/ qcom,llm-sw-overr;
qcom,pwrcl-speedbin0-v0 =
< 300000000 0x0004000f 0x01200020 0x1 1 >,
diff --git a/arch/arm/boot/dts/qcom/msm8998-v2.1-interposer-msmfalcon-cdp.dts b/arch/arm/boot/dts/qcom/msm8998-v2.1-interposer-msmfalcon-cdp.dts
index 3c00de27f285..bb7046ab58cb 100644
--- a/arch/arm/boot/dts/qcom/msm8998-v2.1-interposer-msmfalcon-cdp.dts
+++ b/arch/arm/boot/dts/qcom/msm8998-v2.1-interposer-msmfalcon-cdp.dts
@@ -16,9 +16,73 @@
#include "msm8998-v2.1-interposer-msmfalcon.dtsi"
#include "msm8998-interposer-msmfalcon-cdp.dtsi"
#include "msm8998-interposer-pmfalcon.dtsi"
+#include "msm8998-interposer-msmfalcon-audio.dtsi"
+#include "msm8998-interposer-camera-sensor-cdp.dtsi"
/ {
model = "Qualcomm Technologies, Inc. MSM 8998 v2.1 MSM FALCON Interposer CDP";
compatible = "qcom,msm8998-cdp", "qcom,msm8998", "qcom,cdp";
qcom,board-id = <1 1>;
};
+
+&pmfalcon_charger {
+ qcom,batteryless-platform;
+};
+
+&clock_gcc {
+ vdd_dig-supply = <&pm2falcon_s3_level>;
+ vdd_dig_ao-supply = <&pm2falcon_s3_level_ao>;
+};
+
+&clock_mmss {
+ vdd_dig-supply = <&pm2falcon_s3_level>;
+ vdd_mmsscc_mx-supply = <&pm2falcon_s5_level>;
+};
+
+&clock_gpu {
+ vdd_dig-supply = <&pm2falcon_s3_level>;
+};
+
+&clock_gfx {
+ /* GFX Rail = CX */
+ vdd_gpucc-supply = <&pm2falcon_s3_level>;
+ vdd_mx-supply = <&pm2falcon_s5_level>;
+ vdd_gpu_mx-supply = <&pm2falcon_s5_level>;
+ qcom,gfxfreq-speedbin0 =
+ < 0 0 0 >,
+ < 180000000 RPM_SMD_REGULATOR_LEVEL_MIN_SVS
+ RPM_SMD_REGULATOR_LEVEL_SVS >,
+ < 257000000 RPM_SMD_REGULATOR_LEVEL_LOW_SVS
+ RPM_SMD_REGULATOR_LEVEL_SVS >,
+ < 342000000 RPM_SMD_REGULATOR_LEVEL_SVS
+ RPM_SMD_REGULATOR_LEVEL_SVS >,
+ < 414000000 RPM_SMD_REGULATOR_LEVEL_SVS_PLUS
+ RPM_SMD_REGULATOR_LEVEL_SVS >,
+ < 515000000 RPM_SMD_REGULATOR_LEVEL_NOM
+ RPM_SMD_REGULATOR_LEVEL_NOM >,
+ < 596000000 RPM_SMD_REGULATOR_LEVEL_NOM_PLUS
+ RPM_SMD_REGULATOR_LEVEL_NOM >,
+ < 670000000 RPM_SMD_REGULATOR_LEVEL_TURBO
+ RPM_SMD_REGULATOR_LEVEL_TURBO >,
+ < 710000000 RPM_SMD_REGULATOR_LEVEL_TURBO
+ RPM_SMD_REGULATOR_LEVEL_TURBO >;
+ qcom,gfxfreq-mx-speedbin0 =
+ < 0 0 >,
+ < 180000000 RPM_SMD_REGULATOR_LEVEL_SVS >,
+ < 257000000 RPM_SMD_REGULATOR_LEVEL_SVS >,
+ < 342000000 RPM_SMD_REGULATOR_LEVEL_SVS >,
+ < 414000000 RPM_SMD_REGULATOR_LEVEL_SVS >,
+ < 515000000 RPM_SMD_REGULATOR_LEVEL_NOM >,
+ < 596000000 RPM_SMD_REGULATOR_LEVEL_NOM >,
+ < 670000000 RPM_SMD_REGULATOR_LEVEL_TURBO >,
+ < 710000000 RPM_SMD_REGULATOR_LEVEL_TURBO >;
+};
+
+&gdsc_gpu_gx {
+ clock-names = "core_root_clk";
+ clocks = <&clock_gfx clk_gfx3d_clk_src>;
+ qcom,force-enable-root-clk;
+ /* GFX Rail = CX */
+ parent-supply = <&pm2falcon_s3_level>;
+ status = "ok";
+};
diff --git a/arch/arm/boot/dts/qcom/msm8998-v2.1-interposer-msmfalcon-mtp.dts b/arch/arm/boot/dts/qcom/msm8998-v2.1-interposer-msmfalcon-mtp.dts
index 7d0fe5a33875..166e09577d46 100644
--- a/arch/arm/boot/dts/qcom/msm8998-v2.1-interposer-msmfalcon-mtp.dts
+++ b/arch/arm/boot/dts/qcom/msm8998-v2.1-interposer-msmfalcon-mtp.dts
@@ -16,9 +16,73 @@
#include "msm8998-v2.1-interposer-msmfalcon.dtsi"
#include "msm8998-interposer-msmfalcon-mtp.dtsi"
#include "msm8998-interposer-pmfalcon.dtsi"
+#include "msm8998-interposer-msmfalcon-audio.dtsi"
+#include "msm8998-interposer-camera-sensor-mtp.dtsi"
/ {
model = "Qualcomm Technologies, Inc. MSM 8998 v2.1 MSM FALCON Interposer MTP";
compatible = "qcom,msm8998-mtp", "qcom,msm8998", "qcom,mtp";
qcom,board-id = <8 2>;
};
+
+&pmfalcon_fg {
+ qcom,battery-data = <&mtp_batterydata>;
+};
+
+&clock_gcc {
+ vdd_dig-supply = <&pm2falcon_s3_level>;
+ vdd_dig_ao-supply = <&pm2falcon_s3_level_ao>;
+};
+
+&clock_mmss {
+ vdd_dig-supply = <&pm2falcon_s3_level>;
+ vdd_mmsscc_mx-supply = <&pm2falcon_s5_level>;
+};
+
+&clock_gpu {
+ vdd_dig-supply = <&pm2falcon_s3_level>;
+};
+
+&clock_gfx {
+ /* GFX Rail = CX */
+ vdd_gpucc-supply = <&pm2falcon_s3_level>;
+ vdd_mx-supply = <&pm2falcon_s5_level>;
+ vdd_gpu_mx-supply = <&pm2falcon_s5_level>;
+ qcom,gfxfreq-speedbin0 =
+ < 0 0 0 >,
+ < 180000000 RPM_SMD_REGULATOR_LEVEL_MIN_SVS
+ RPM_SMD_REGULATOR_LEVEL_SVS >,
+ < 257000000 RPM_SMD_REGULATOR_LEVEL_LOW_SVS
+ RPM_SMD_REGULATOR_LEVEL_SVS >,
+ < 342000000 RPM_SMD_REGULATOR_LEVEL_SVS
+ RPM_SMD_REGULATOR_LEVEL_SVS >,
+ < 414000000 RPM_SMD_REGULATOR_LEVEL_SVS_PLUS
+ RPM_SMD_REGULATOR_LEVEL_SVS >,
+ < 515000000 RPM_SMD_REGULATOR_LEVEL_NOM
+ RPM_SMD_REGULATOR_LEVEL_NOM >,
+ < 596000000 RPM_SMD_REGULATOR_LEVEL_NOM_PLUS
+ RPM_SMD_REGULATOR_LEVEL_NOM >,
+ < 670000000 RPM_SMD_REGULATOR_LEVEL_TURBO
+ RPM_SMD_REGULATOR_LEVEL_TURBO >,
+ < 710000000 RPM_SMD_REGULATOR_LEVEL_TURBO
+ RPM_SMD_REGULATOR_LEVEL_TURBO >;
+ qcom,gfxfreq-mx-speedbin0 =
+ < 0 0 >,
+ < 180000000 RPM_SMD_REGULATOR_LEVEL_SVS >,
+ < 257000000 RPM_SMD_REGULATOR_LEVEL_SVS >,
+ < 342000000 RPM_SMD_REGULATOR_LEVEL_SVS >,
+ < 414000000 RPM_SMD_REGULATOR_LEVEL_SVS >,
+ < 515000000 RPM_SMD_REGULATOR_LEVEL_NOM >,
+ < 596000000 RPM_SMD_REGULATOR_LEVEL_NOM >,
+ < 670000000 RPM_SMD_REGULATOR_LEVEL_TURBO >,
+ < 710000000 RPM_SMD_REGULATOR_LEVEL_TURBO >;
+};
+
+&gdsc_gpu_gx {
+ clock-names = "core_root_clk";
+ clocks = <&clock_gfx clk_gfx3d_clk_src>;
+ qcom,force-enable-root-clk;
+ /* GFX Rail = CX */
+ parent-supply = <&pm2falcon_s3_level>;
+ status = "ok";
+};
diff --git a/arch/arm/boot/dts/qcom/msm8998-v2.1-interposer-msmfalcon-qrd.dtsi b/arch/arm/boot/dts/qcom/msm8998-v2.1-interposer-msmfalcon-qrd.dtsi
index 0f03ebd28b0f..cd0e20a295d9 100644
--- a/arch/arm/boot/dts/qcom/msm8998-v2.1-interposer-msmfalcon-qrd.dtsi
+++ b/arch/arm/boot/dts/qcom/msm8998-v2.1-interposer-msmfalcon-qrd.dtsi
@@ -20,6 +20,9 @@
};
&ufsphy1 {
+ vdda-phy-supply = <&pm2falcon_l1>;
+ vdda-pll-supply = <&pmfalcon_l10>;
+ vddp-ref-clk-supply = <&pmfalcon_l8>;
vdda-phy-max-microamp = <51400>;
vdda-pll-max-microamp = <14600>;
vddp-ref-clk-max-microamp = <100>;
@@ -30,6 +33,9 @@
&ufs1 {
vdd-hba-supply = <&gdsc_ufs>;
vdd-hba-fixed-regulator;
+ vcc-supply = <&pm2falcon_l4>;
+ vccq-supply = <&pmfalcon_l8>;
+ vccq2-supply = <&pmfalcon_l8>;
vcc-max-microamp = <750000>;
vccq-max-microamp = <560000>;
vccq2-max-microamp = <750000>;
diff --git a/arch/arm/boot/dts/qcom/msm8998-v2.dtsi b/arch/arm/boot/dts/qcom/msm8998-v2.dtsi
index dc1922851a77..cc4e48ede2ad 100644
--- a/arch/arm/boot/dts/qcom/msm8998-v2.dtsi
+++ b/arch/arm/boot/dts/qcom/msm8998-v2.dtsi
@@ -26,6 +26,27 @@
&clock_cpu {
compatible = "qcom,cpu-clock-osm-msm8998-v2";
+ reg = <0x179c0000 0x4000>,
+ <0x17916000 0x1000>,
+ <0x17816000 0x1000>,
+ <0x179d1000 0x1000>,
+ <0x17914800 0x800>,
+ <0x17814800 0x800>,
+ <0x00784130 0x8>,
+ <0x1791101c 0x8>;
+ reg-names = "osm", "pwrcl_pll", "perfcl_pll",
+ "apcs_common", "pwrcl_acd", "perfcl_acd",
+ "perfcl_efuse", "debug";
+
+ qcom,acdtd-val = <0x00009611 0x00009611>;
+ qcom,acdcr-val = <0x002b5ffd 0x002b5ffd>;
+ qcom,acdsscr-val = <0x00000501 0x00000501>;
+ qcom,acdextint0-val = <0x2cf9ae8 0x2cf9ae8>;
+ qcom,acdextint1-val = <0x2cf9afe 0x2cf9afe>;
+ qcom,acdautoxfer-val = <0x00000015 0x00000015>;
+ qcom,perfcl-apcs-mem-acc-threshold-voltage = <852000>;
+ qcom,apm-threshold-voltage = <800000>;
+
/delete-property/ qcom,llm-sw-overr;
qcom,pwrcl-speedbin0-v0 =
< 300000000 0x0004000f 0x01200020 0x1 1 >,
@@ -77,11 +98,20 @@
< 1958400000 0x04040066 0x09520052 0x2 23 >,
< 2035200000 0x0404006a 0x09550055 0x3 24 >,
< 2112000000 0x0404006e 0x0a580058 0x3 25 >,
- < 2188800000 0x04040072 0x0a5b005b 0x3 26 >,
+ < 2208000000 0x04040073 0x0a5c005c 0x3 26 >,
+ < 2265600000 0x04010076 0x0a5e005e 0x3 26 >,
< 2265600000 0x04040076 0x0a5e005e 0x3 27 >,
+ < 2342400000 0x0401007a 0x0a620062 0x3 27 >,
< 2342400000 0x0404007a 0x0a620062 0x3 28 >,
+ < 2419200000 0x0401007e 0x0a650065 0x3 28 >,
< 2419200000 0x0404007e 0x0a650065 0x3 29 >,
- < 2496000000 0x04040082 0x0a680068 0x3 30 >;
+ < 2496000000 0x04010082 0x0a680068 0x3 29 >,
+ < 2457600000 0x04040080 0x0a660066 0x3 30 >,
+ < 2553600000 0x04010085 0x0a6a006a 0x3 30 >,
+ < 2476800000 0x04040081 0x0a670067 0x3 31 >,
+ < 2572800000 0x04010086 0x0a6b006b 0x3 31 >,
+ < 2496000000 0x04040082 0x0a680068 0x3 32 >,
+ < 2592000000 0x04010087 0x0a6c006c 0x3 32 >;
qcom,perfcl-speedbin1-v0 =
< 300000000 0x0004000f 0x01200020 0x1 1 >,
@@ -110,7 +140,81 @@
< 2035200000 0x0404006a 0x09550055 0x3 24 >,
< 2112000000 0x0404006e 0x0a580058 0x3 25 >,
< 2208000000 0x04040073 0x0a5c005c 0x3 26 >,
- < 2304000000 0x04010078 0x0a5c005c 0x3 26 >;
+ < 2304000000 0x04010078 0x0a600060 0x3 26 >;
+
+ qcom,perfcl-speedbin2-v0 =
+ < 300000000 0x0004000f 0x01200020 0x1 1 >,
+ < 345600000 0x05040012 0x01200020 0x1 2 >,
+ < 422400000 0x05040016 0x02200020 0x1 3 >,
+ < 499200000 0x0504001a 0x02200020 0x1 4 >,
+ < 576000000 0x0504001e 0x02200020 0x1 5 >,
+ < 652800000 0x05040022 0x03200020 0x1 6 >,
+ < 729600000 0x05040026 0x03200020 0x1 7 >,
+ < 806400000 0x0504002a 0x03220022 0x1 8 >,
+ < 902400000 0x0404002f 0x04260026 0x1 9 >,
+ < 979200000 0x04040033 0x04290029 0x1 10 >,
+ < 1056000000 0x04040037 0x052c002c 0x1 11 >,
+ < 1132800000 0x0404003b 0x052f002f 0x1 12 >,
+ < 1190400000 0x0404003e 0x05320032 0x2 13 >,
+ < 1267200000 0x04040042 0x06350035 0x2 14 >,
+ < 1344000000 0x04040046 0x06380038 0x2 15 >,
+ < 1420800000 0x0404004a 0x063b003b 0x2 16 >,
+ < 1497600000 0x0404004e 0x073e003e 0x2 17 >,
+ < 1574400000 0x04040052 0x07420042 0x2 18 >,
+ < 1651200000 0x04040056 0x07450045 0x2 19 >,
+ < 1728000000 0x0404005a 0x08480048 0x2 20 >,
+ < 1804800000 0x0404005e 0x084b004b 0x2 21 >,
+ < 1881600000 0x04040062 0x094e004e 0x2 22 >,
+ < 1958400000 0x04040066 0x09520052 0x2 23 >,
+ < 2035200000 0x0404006a 0x09550055 0x3 24 >,
+ < 2112000000 0x0404006e 0x0a580058 0x3 25 >,
+ < 2208000000 0x04040073 0x0a5c005c 0x3 26 >,
+ < 2265600000 0x04010076 0x0a5e005e 0x3 26 >,
+ < 2265600000 0x04040076 0x0a5e005e 0x3 27 >,
+ < 2342400000 0x0401007a 0x0a620062 0x3 27 >,
+ < 2323200000 0x04040079 0x0a610061 0x3 28 >,
+ < 2419200000 0x0401007e 0x0a650065 0x3 28 >,
+ < 2342400000 0x0404007a 0x0a620062 0x3 29 >,
+ < 2438400000 0x0401007f 0x0a660066 0x3 29 >,
+ < 2361600000 0x0404007b 0x0a620062 0x3 30 >,
+ < 2457600000 0x04010080 0x0a660066 0x3 30 >;
+
+ qcom,perfcl-speedbin3-v0 =
+ < 300000000 0x0004000f 0x01200020 0x1 1 >,
+ < 345600000 0x05040012 0x01200020 0x1 2 >,
+ < 422400000 0x05040016 0x02200020 0x1 3 >,
+ < 499200000 0x0504001a 0x02200020 0x1 4 >,
+ < 576000000 0x0504001e 0x02200020 0x1 5 >,
+ < 652800000 0x05040022 0x03200020 0x1 6 >,
+ < 729600000 0x05040026 0x03200020 0x1 7 >,
+ < 806400000 0x0504002a 0x03220022 0x1 8 >,
+ < 902400000 0x0404002f 0x04260026 0x1 9 >,
+ < 979200000 0x04040033 0x04290029 0x1 10 >,
+ < 1056000000 0x04040037 0x052c002c 0x1 11 >,
+ < 1132800000 0x0404003b 0x052f002f 0x1 12 >,
+ < 1190400000 0x0404003e 0x05320032 0x2 13 >,
+ < 1267200000 0x04040042 0x06350035 0x2 14 >,
+ < 1344000000 0x04040046 0x06380038 0x2 15 >,
+ < 1420800000 0x0404004a 0x063b003b 0x2 16 >,
+ < 1497600000 0x0404004e 0x073e003e 0x2 17 >,
+ < 1574400000 0x04040052 0x07420042 0x2 18 >,
+ < 1651200000 0x04040056 0x07450045 0x2 19 >,
+ < 1728000000 0x0404005a 0x08480048 0x2 20 >,
+ < 1804800000 0x0404005e 0x084b004b 0x2 21 >,
+ < 1881600000 0x04040062 0x094e004e 0x2 22 >,
+ < 1958400000 0x04040066 0x09520052 0x2 23 >,
+ < 2035200000 0x0404006a 0x09550055 0x3 24 >,
+ < 2112000000 0x0404006e 0x0a580058 0x3 25 >,
+ < 2208000000 0x04040073 0x0a5c005c 0x3 26 >,
+ < 2265600000 0x04010076 0x0a5e005e 0x3 26 >,
+ < 2265600000 0x04040076 0x0a5e005e 0x3 27 >,
+ < 2342400000 0x0401007a 0x0a620062 0x3 27 >,
+ < 2323200000 0x04040079 0x0a610061 0x3 28 >,
+ < 2419200000 0x0401007e 0x0a650065 0x3 28 >,
+ < 2342400000 0x0404007a 0x0a620062 0x3 29 >,
+ < 2438400000 0x0401007f 0x0a660066 0x3 29 >,
+ < 2361600000 0x0404007b 0x0a620062 0x3 30 >,
+ < 2457600000 0x04010080 0x0a660066 0x3 30 >;
};
&msm_cpufreq {
@@ -164,11 +268,17 @@
< 1958400 >,
< 2035200 >,
< 2112000 >,
- < 2188800 >,
+ < 2208000 >,
< 2265600 >,
+ < 2304000 >,
+ < 2323200 >,
< 2342400 >,
+ < 2361600 >,
< 2419200 >,
- < 2496000 >;
+ < 2457600 >,
+ < 2476800 >,
+ < 2496000 >,
+ < 2592000 >;
};
&bwmon {
@@ -339,34 +449,21 @@
compatible = "qcom,cprh-msm8998-v2-kbss-regulator";
qcom,cpr-corner-switch-delay-time = <1042>;
qcom,cpr-aging-ref-voltage = <1056000>;
+ qcom,apm-threshold-voltage = <800000>;
+ qcom,apm-hysteresis-voltage = <0>;
};
&apc0_pwrcl_vreg {
regulator-max-microvolt = <23>;
- qcom,cpr-fuse-combos = <16>;
- qcom,cpr-speed-bins = <2>;
- qcom,cpr-speed-bin-corners = <22 22>;
- qcom,cpr-corners =
- /* Speed bin 0 */
- <22 22 22 22 22 22 22 22>,
- /* Speed bin 1 */
- <22 22 22 22 22 22 22 22>;
+ qcom,cpr-fuse-combos = <32>;
+ qcom,cpr-speed-bins = <4>;
+ qcom,cpr-speed-bin-corners = <22 22 22 22>;
+ qcom,cpr-corners = <22>;
- qcom,cpr-corner-fmax-map =
- /* Speed bin 0 */
- <8 11 18 22>,
- /* Speed bin 1 */
- <8 11 18 22>;
+ qcom,cpr-corner-fmax-map = <8 11 18 22>;
qcom,cpr-voltage-ceiling =
- /* Speed bin 0 */
- <828000 828000 828000 828000 828000
- 828000 828000 828000 828000 828000
- 828000 900000 900000 900000 900000
- 900000 900000 900000 952000 952000
- 1056000 1056000>,
- /* Speed bin 1 */
<828000 828000 828000 828000 828000
828000 828000 828000 828000 828000
828000 900000 900000 900000 900000
@@ -374,13 +471,6 @@
1056000 1056000>;
qcom,cpr-voltage-floor =
- /* Speed bin 0 */
- <568000 568000 568000 568000 568000
- 568000 568000 568000 568000 568000
- 568000 632000 632000 632000 632000
- 632000 632000 632000 712000 712000
- 772000 772000>,
- /* Speed bin 1 */
<568000 568000 568000 568000 568000
568000 568000 568000 568000 568000
568000 632000 632000 632000 632000
@@ -388,32 +478,14 @@
772000 772000>;
qcom,cpr-floor-to-ceiling-max-range =
- /* Speed bin 0 */
- <55000 55000 55000 55000
- 55000 55000 55000 55000
- 55000 55000 55000 65000
- 65000 65000 65000 65000
- 65000 65000 65000 65000
- 65000 65000>,
- /* Speed bin 1 */
- <55000 55000 55000 55000
- 55000 55000 55000 55000
- 55000 55000 55000 65000
- 65000 65000 65000 65000
- 65000 65000 65000 65000
- 65000 65000>;
+ <32000 32000 32000 32000
+ 32000 32000 32000 32000
+ 32000 32000 32000 32000
+ 32000 32000 32000 32000
+ 32000 32000 40000 40000
+ 40000 40000>;
qcom,corner-frequencies =
- /* Speed bin 0 */
- <300000000 364800000 441600000
- 518400000 595200000 672000000
- 748800000 825600000 883200000
- 960000000 1036800000 1094400000
- 1171200000 1248000000 1324800000
- 1401600000 1478400000 1555200000
- 1670400000 1747200000 1824000000
- 1900800000>,
- /* Speed bin 1 */
<300000000 364800000 441600000
518400000 595200000 672000000
748800000 825600000 883200000
@@ -439,78 +511,128 @@
qcom,cpr-open-loop-voltage-fuse-adjustment =
/* Speed bin 0 */
- <40000 24000 0 30000>,
- <40000 24000 0 30000>,
- <40000 24000 0 30000>,
- <40000 24000 0 30000>,
- <25000 9000 (-15000) 15000>,
- <25000 9000 (-15000) 15000>,
- <25000 9000 (-15000) 15000>,
- <25000 9000 (-15000) 15000>,
+ <40000 24000 12000 30000>,
+ <40000 24000 12000 30000>,
+ <40000 24000 12000 30000>,
+ <40000 24000 12000 30000>,
+ <25000 9000 (-3000) 15000>,
+ <25000 9000 (-3000) 15000>,
+ <25000 9000 (-3000) 15000>,
+ <25000 9000 (-3000) 15000>,
/* Speed bin 1 */
- <40000 24000 0 30000>,
- <40000 24000 0 30000>,
- <40000 24000 0 30000>,
- <40000 24000 0 30000>,
- <25000 9000 (-15000) 15000>,
- <25000 9000 (-15000) 15000>,
- <25000 9000 (-15000) 15000>,
- <25000 9000 (-15000) 15000>;
+ <40000 24000 12000 30000>,
+ <40000 24000 12000 30000>,
+ <40000 24000 12000 30000>,
+ <40000 24000 12000 30000>,
+ <25000 9000 (-3000) 15000>,
+ <25000 9000 (-3000) 15000>,
+ <25000 9000 (-3000) 15000>,
+ <25000 9000 (-3000) 15000>,
+ /* Speed bin 2 */
+ <40000 24000 12000 30000>,
+ <40000 24000 12000 30000>,
+ <40000 24000 12000 30000>,
+ <40000 24000 12000 30000>,
+ <25000 9000 (-3000) 15000>,
+ <25000 9000 (-3000) 15000>,
+ <25000 9000 (-3000) 15000>,
+ <25000 9000 (-3000) 15000>,
+ /* Speed bin 3 */
+ <40000 24000 12000 30000>,
+ <40000 24000 12000 30000>,
+ <40000 24000 12000 30000>,
+ <40000 24000 12000 30000>,
+ <25000 9000 (-3000) 15000>,
+ <25000 9000 (-3000) 15000>,
+ <25000 9000 (-3000) 15000>,
+ <25000 9000 (-3000) 15000>;
qcom,cpr-closed-loop-voltage-fuse-adjustment =
/* Speed bin 0 */
- <20000 26000 0 30000>,
- <20000 26000 0 30000>,
- <20000 26000 0 30000>,
- <20000 26000 0 30000>,
- < 5000 11000 (-15000) 15000>,
- < 5000 11000 (-15000) 15000>,
- < 5000 11000 (-15000) 15000>,
- < 5000 11000 (-15000) 15000>,
+ <20000 26000 12000 30000>,
+ <20000 26000 12000 30000>,
+ <20000 26000 12000 30000>,
+ <20000 26000 12000 30000>,
+ < 5000 11000 (-3000) 15000>,
+ < 5000 11000 (-3000) 15000>,
+ < 5000 11000 (-3000) 15000>,
+ < 5000 11000 (-3000) 15000>,
/* Speed bin 1 */
- <20000 26000 0 30000>,
- <20000 26000 0 30000>,
- <20000 26000 0 30000>,
- <20000 26000 0 30000>,
- < 5000 11000 (-15000) 15000>,
- < 5000 11000 (-15000) 15000>,
- < 5000 11000 (-15000) 15000>,
- < 5000 11000 (-15000) 15000>;
+ <20000 26000 12000 30000>,
+ <20000 26000 12000 30000>,
+ <20000 26000 12000 30000>,
+ <20000 26000 12000 30000>,
+ < 5000 11000 (-3000) 15000>,
+ < 5000 11000 (-3000) 15000>,
+ < 5000 11000 (-3000) 15000>,
+ < 5000 11000 (-3000) 15000>,
+ /* Speed bin 2 */
+ <20000 26000 12000 30000>,
+ <20000 26000 12000 30000>,
+ <20000 26000 12000 30000>,
+ <20000 26000 12000 30000>,
+ < 5000 11000 (-3000) 15000>,
+ < 5000 11000 (-3000) 15000>,
+ < 5000 11000 (-3000) 15000>,
+ < 5000 11000 (-3000) 15000>,
+ /* Speed bin 3 */
+ <20000 26000 12000 30000>,
+ <20000 26000 12000 30000>,
+ <20000 26000 12000 30000>,
+ <20000 26000 12000 30000>,
+ < 5000 11000 (-3000) 15000>,
+ < 5000 11000 (-3000) 15000>,
+ < 5000 11000 (-3000) 15000>,
+ < 5000 11000 (-3000) 15000>;
qcom,allow-voltage-interpolation;
qcom,allow-quotient-interpolation;
qcom,cpr-scaled-open-loop-voltage-as-ceiling;
- qcom,cpr-aging-ref-corner = <22 22>;
+ qcom,cpr-aging-ref-corner = <22>;
qcom,cpr-aging-ro-scaling-factor = <1620>;
qcom,allow-aging-voltage-adjustment =
<0 0 0 0 1 1 1 1>,
+ <0 0 0 0 1 1 1 1>,
+ <0 0 0 0 1 1 1 1>,
<0 0 0 0 1 1 1 1>;
};
&apc1_cpr {
compatible = "qcom,cprh-msm8998-v2-kbss-regulator";
qcom,cpr-corner-switch-delay-time = <1042>;
- qcom,cpr-aging-ref-voltage = <1056000>;
+ qcom,cpr-aging-ref-voltage = <1136000>;
+ qcom,apm-threshold-voltage = <800000>;
+ qcom,apm-hysteresis-voltage = <0>;
+ qcom,mem-acc-threshold-voltage = <852000>;
+ qcom,mem-acc-crossover-voltage = <852000>;
};
&apc1_perfcl_vreg {
- regulator-max-microvolt = <31>;
+ regulator-max-microvolt = <34>;
- qcom,cpr-fuse-combos = <16>;
- qcom,cpr-speed-bins = <2>;
- qcom,cpr-speed-bin-corners = <30 26>;
+ qcom,cpr-fuse-combos = <32>;
+ qcom,cpr-speed-bins = <4>;
+ qcom,cpr-speed-bin-corners = <32 26 30 31>;
qcom,cpr-corners =
/* Speed bin 0 */
- <30 30 30 30 30 30 30 30>,
+ <32 32 32 32 32 32 32 32>,
/* Speed bin 1 */
- <26 26 26 26 26 26 26 26>;
+ <26 26 26 26 26 26 26 26>,
+ /* Speed bin 2 */
+ <30 30 30 30 30 30 30 30>,
+ /* Speed bin 3 */
+ <31 31 31 31 31 31 31 31>;
qcom,cpr-corner-fmax-map =
/* Speed bin 0 */
- <8 12 20 30>,
+ <8 12 20 32>,
/* Speed bin 1 */
- <8 12 20 26>;
+ <8 12 20 26>,
+ /* Speed bin 2 */
+ <8 12 20 30>,
+ /* Speed bin 3 */
+ <8 12 20 31>;
qcom,cpr-voltage-ceiling =
/* Speed bin 0 */
@@ -518,15 +640,31 @@
828000 828000 828000 828000 828000
828000 828000 900000 900000 900000
900000 900000 900000 900000 900000
- 952000 952000 952000 1056000 1056000
- 1056000 1056000 1056000 1056000 1056000>,
+ 952000 952000 952000 1136000 1136000
+ 1136000 1136000 1136000 1136000 1136000
+ 1136000 1136000>,
/* Speed bin 1 */
<828000 828000 828000 828000 828000
828000 828000 828000 828000 828000
828000 828000 900000 900000 900000
900000 900000 900000 900000 900000
- 952000 952000 952000 1056000 1056000
- 1056000>;
+ 952000 952000 952000 1136000 1136000
+ 1136000>,
+ /* Speed bin 2 */
+ <828000 828000 828000 828000 828000
+ 828000 828000 828000 828000 828000
+ 828000 828000 900000 900000 900000
+ 900000 900000 900000 900000 900000
+ 952000 952000 952000 1136000 1136000
+ 1136000 1136000 1136000 1136000 1136000>,
+ /* Speed bin 3 */
+ <828000 828000 828000 828000 828000
+ 828000 828000 828000 828000 828000
+ 828000 828000 900000 900000 900000
+ 900000 900000 900000 900000 900000
+ 952000 952000 952000 1136000 1136000
+ 1136000 1136000 1136000 1136000 1136000
+ 1136000>;
qcom,cpr-voltage-floor =
/* Speed bin 0 */
@@ -535,33 +673,67 @@
568000 568000 632000 632000 632000
632000 632000 632000 632000 632000
712000 712000 712000 772000 772000
- 772000 772000 772000 772000 772000>,
+ 772000 772000 772000 772000 772000
+ 772000 772000>,
/* Speed bin 1 */
<568000 568000 568000 568000 568000
568000 568000 568000 568000 568000
568000 568000 632000 632000 632000
632000 632000 632000 632000 632000
712000 712000 712000 772000 772000
+ 772000>,
+ /* Speed bin 2 */
+ <568000 568000 568000 568000 568000
+ 568000 568000 568000 568000 568000
+ 568000 568000 632000 632000 632000
+ 632000 632000 632000 632000 632000
+ 712000 712000 712000 772000 772000
+ 772000 772000 772000 772000 772000>,
+ /* Speed bin 3 */
+ <568000 568000 568000 568000 568000
+ 568000 568000 568000 568000 568000
+ 568000 568000 632000 632000 632000
+ 632000 632000 632000 632000 632000
+ 712000 712000 712000 772000 772000
+ 772000 772000 772000 772000 772000
772000>;
qcom,cpr-floor-to-ceiling-max-range =
/* Speed bin 0 */
- <55000 55000 55000 55000
- 55000 55000 55000 55000
- 55000 55000 55000 55000
- 65000 65000 65000 65000
- 65000 65000 65000 65000
- 65000 65000 65000 65000
- 65000 65000 65000 65000
- 65000 65000>,
+ <32000 32000 32000 32000
+ 32000 32000 32000 32000
+ 32000 32000 32000 32000
+ 32000 32000 32000 32000
+ 32000 32000 32000 32000
+ 40000 40000 40000 40000
+ 40000 40000 40000 40000
+ 40000 40000 40000 40000>,
/* Speed bin 1 */
- <55000 55000 55000 55000
- 55000 55000 55000 55000
- 55000 55000 55000 55000
- 65000 65000 65000 65000
- 65000 65000 65000 65000
- 65000 65000 65000 65000
- 65000 65000>;
+ <32000 32000 32000 32000
+ 32000 32000 32000 32000
+ 32000 32000 32000 32000
+ 32000 32000 32000 32000
+ 32000 32000 32000 32000
+ 40000 40000 40000 40000
+ 40000 40000>,
+ /* Speed bin 2 */
+ <32000 32000 32000 32000
+ 32000 32000 32000 32000
+ 32000 32000 32000 32000
+ 32000 32000 32000 32000
+ 32000 32000 32000 32000
+ 40000 40000 40000 40000
+ 40000 40000 40000 40000
+ 40000 40000>,
+ /* Speed bin 3 */
+ <32000 32000 32000 32000
+ 32000 32000 32000 32000
+ 32000 32000 32000 32000
+ 32000 32000 32000 32000
+ 32000 32000 32000 32000
+ 40000 40000 40000 40000
+ 40000 40000 40000 40000
+ 40000 40000 40000>;
qcom,corner-frequencies =
/* Speed bin 0 */
@@ -573,8 +745,9 @@
1420800000 1497600000 1574400000
1651200000 1728000000 1804800000
1881600000 1958400000 2035200000
- 2112000000 2188800000 2265600000
- 2342400000 2419200000 2496000000>,
+ 2112000000 2208000000 2265600000
+ 2342400000 2419200000 2457600000
+ 2476800000 2496000000>,
/* Speed bin 1 */
<300000000 345600000 422400000
499200000 576000000 652800000
@@ -584,7 +757,30 @@
1420800000 1497600000 1574400000
1651200000 1728000000 1804800000
1881600000 1958400000 2035200000
- 2112000000 2208000000>;
+ 2112000000 2208000000>,
+ /* Speed bin 2 */
+ <300000000 345600000 422400000
+ 499200000 576000000 652800000
+ 729600000 806400000 902400000
+ 979200000 1056000000 1132800000
+ 1190400000 1267200000 1344000000
+ 1420800000 1497600000 1574400000
+ 1651200000 1728000000 1804800000
+ 1881600000 1958400000 2035200000
+ 2112000000 2208000000 2265600000
+ 2323200000 2342400000 2361600000>,
+ /* Speed bin 3 */
+ <300000000 345600000 422400000
+ 499200000 576000000 652800000
+ 729600000 806400000 902400000
+ 979200000 1056000000 1132800000
+ 1190400000 1267200000 1344000000
+ 1420800000 1497600000 1574400000
+ 1651200000 1728000000 1804800000
+ 1881600000 1958400000 2035200000
+ 2112000000 2208000000 2265600000
+ 2323200000 2342400000 2361600000
+ 2457600000>;
qcom,cpr-ro-scaling-factor =
<2857 3057 2828 2952 2699 2798 2446
@@ -602,52 +798,90 @@
qcom,cpr-open-loop-voltage-fuse-adjustment =
/* Speed bin 0 */
- < 8000 0 0 52000>,
- < 8000 0 0 52000>,
- < 8000 0 0 52000>,
- < 8000 0 0 52000>,
- <(-7000) (-15000) (-15000) 37000>,
- <(-7000) (-15000) (-15000) 37000>,
- <(-7000) (-15000) (-15000) 37000>,
- <(-7000) (-15000) (-15000) 37000>,
+ < 8000 0 12000 52000>,
+ < 8000 0 12000 52000>,
+ < 8000 0 12000 52000>,
+ < 8000 0 12000 52000>,
+ <(-7000) (-15000) (-3000) 37000>,
+ <(-7000) (-15000) (-3000) 37000>,
+ <(-7000) (-15000) (-3000) 37000>,
+ <(-7000) (-15000) (-3000) 37000>,
/* Speed bin 1 */
- < 8000 0 0 52000>,
- < 8000 0 0 52000>,
- < 8000 0 0 52000>,
- < 8000 0 0 52000>,
- <(-7000) (-15000) (-15000) 37000>,
- <(-7000) (-15000) (-15000) 37000>,
- <(-7000) (-15000) (-15000) 37000>,
- <(-7000) (-15000) (-15000) 37000>;
+ < 8000 0 12000 52000>,
+ < 8000 0 12000 52000>,
+ < 8000 0 12000 52000>,
+ < 8000 0 12000 52000>,
+ <(-7000) (-15000) (-3000) 37000>,
+ <(-7000) (-15000) (-3000) 37000>,
+ <(-7000) (-15000) (-3000) 37000>,
+ <(-7000) (-15000) (-3000) 37000>,
+ /* Speed bin 2 */
+ < 8000 0 12000 52000>,
+ < 8000 0 12000 52000>,
+ < 8000 0 12000 52000>,
+ < 8000 0 12000 52000>,
+ <(-7000) (-15000) (-3000) 37000>,
+ <(-7000) (-15000) (-3000) 37000>,
+ <(-7000) (-15000) (-3000) 37000>,
+ <(-7000) (-15000) (-3000) 37000>,
+ /* Speed bin 3 */
+ < 8000 0 12000 52000>,
+ < 8000 0 12000 52000>,
+ < 8000 0 12000 52000>,
+ < 8000 0 12000 52000>,
+ <(-7000) (-15000) (-3000) 37000>,
+ <(-7000) (-15000) (-3000) 37000>,
+ <(-7000) (-15000) (-3000) 37000>,
+ <(-7000) (-15000) (-3000) 37000>;
qcom,cpr-closed-loop-voltage-fuse-adjustment =
/* Speed bin 0 */
- < 0 0 0 50000>,
- < 0 0 0 50000>,
- < 0 0 0 50000>,
- < 0 0 0 50000>,
- <(-15000) (-15000) (-15000) 35000>,
- <(-15000) (-15000) (-15000) 35000>,
- <(-15000) (-15000) (-15000) 35000>,
- <(-15000) (-15000) (-15000) 35000>,
+ < 0 0 12000 50000>,
+ < 0 0 12000 50000>,
+ < 0 0 12000 50000>,
+ < 0 0 12000 50000>,
+ <(-15000) (-15000) (-3000) 35000>,
+ <(-15000) (-15000) (-3000) 35000>,
+ <(-15000) (-15000) (-3000) 35000>,
+ <(-15000) (-15000) (-3000) 35000>,
+ /* Speed bin 1 */
+ < 0 0 12000 50000>,
+ < 0 0 12000 50000>,
+ < 0 0 12000 50000>,
+ < 0 0 12000 50000>,
+ <(-15000) (-15000) (-3000) 35000>,
+ <(-15000) (-15000) (-3000) 35000>,
+ <(-15000) (-15000) (-3000) 35000>,
+ <(-15000) (-15000) (-3000) 35000>,
+ /* Speed bin 0 */
+ < 0 0 12000 50000>,
+ < 0 0 12000 50000>,
+ < 0 0 12000 50000>,
+ < 0 0 12000 50000>,
+ <(-15000) (-15000) (-3000) 35000>,
+ <(-15000) (-15000) (-3000) 35000>,
+ <(-15000) (-15000) (-3000) 35000>,
+ <(-15000) (-15000) (-3000) 35000>,
/* Speed bin 1 */
- < 0 0 0 50000>,
- < 0 0 0 50000>,
- < 0 0 0 50000>,
- < 0 0 0 50000>,
- <(-15000) (-15000) (-15000) 35000>,
- <(-15000) (-15000) (-15000) 35000>,
- <(-15000) (-15000) (-15000) 35000>,
- <(-15000) (-15000) (-15000) 35000>;
+ < 0 0 12000 50000>,
+ < 0 0 12000 50000>,
+ < 0 0 12000 50000>,
+ < 0 0 12000 50000>,
+ <(-15000) (-15000) (-3000) 35000>,
+ <(-15000) (-15000) (-3000) 35000>,
+ <(-15000) (-15000) (-3000) 35000>,
+ <(-15000) (-15000) (-3000) 35000>;
qcom,allow-voltage-interpolation;
qcom,allow-quotient-interpolation;
qcom,cpr-scaled-open-loop-voltage-as-ceiling;
- qcom,cpr-aging-ref-corner = <30 26>;
+ qcom,cpr-aging-ref-corner = <32 26 30 31>;
qcom,cpr-aging-ro-scaling-factor = <1700>;
qcom,allow-aging-voltage-adjustment =
<0 0 0 0 1 1 1 1>,
+ <0 0 0 0 1 1 1 1>,
+ <0 0 0 0 1 1 1 1>,
<0 0 0 0 1 1 1 1>;
};
@@ -839,7 +1073,7 @@
&soc {
/* Gold L2 SAW */
qcom,spm@178120000 {
- qcom,saw2-avs-limit = <0x4200420>;
+ qcom,saw2-avs-limit = <0x4700470>;
};
/* Silver L2 SAW */
diff --git a/arch/arm/boot/dts/qcom/msm8998.dtsi b/arch/arm/boot/dts/qcom/msm8998.dtsi
index 7f7f2f65deee..ef488bbe0010 100644
--- a/arch/arm/boot/dts/qcom/msm8998.dtsi
+++ b/arch/arm/boot/dts/qcom/msm8998.dtsi
@@ -1660,6 +1660,10 @@
qcom,pm-qos-cpu-group-latency-us = <70 70>;
qcom,pm-qos-default-cpu = <0>;
+ pinctrl-names = "dev-reset-assert", "dev-reset-deassert";
+ pinctrl-0 = <&ufs_dev_reset_assert>;
+ pinctrl-1 = <&ufs_dev_reset_deassert>;
+
resets = <&clock_gcc UFS_BCR>;
reset-names = "core_reset";
@@ -2994,11 +2998,6 @@
vdd-3.3-ch0-supply = <&pm8998_l25_pin_ctrl>;
qcom,vdd-0.8-cx-mx-config = <800000 800000>;
qcom,vdd-3.3-ch0-config = <3104000 3312000>;
- qcom,msm-bus,name = "msm-icnss";
- qcom,msm-bus,num-cases = <2>;
- qcom,msm-bus,num-paths = <1>;
- qcom,msm-bus,vectors-KBps = <81 10065 0 0>,
- <81 10065 0 16000>;
qcom,icnss-vadc = <&pm8998_vadc>;
qcom,icnss-adc_tm = <&pm8998_adc_tm>;
};
diff --git a/arch/arm/boot/dts/qcom/msmfalcon-audio.dtsi b/arch/arm/boot/dts/qcom/msmfalcon-audio.dtsi
new file mode 100644
index 000000000000..b6b3c1f6245f
--- /dev/null
+++ b/arch/arm/boot/dts/qcom/msmfalcon-audio.dtsi
@@ -0,0 +1,136 @@
+/*
+ * Copyright (c) 2015-2016, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * 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 "msmfalcon-wsa881x.dtsi"
+
+&slim_aud {
+ msm_dai_slim {
+ compatible = "qcom,msm-dai-slim";
+ elemental-addr = [ff ff ff fe 17 02];
+ };
+
+ tasha_codec {
+ compatible = "qcom,tasha-slim-pgd";
+ elemental-addr = [00 01 a0 01 17 02];
+
+ interrupt-parent = <&wcd9xxx_intc>;
+ interrupts = <0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
+ 17 18 19 20 21 22 23 24 25 26 27 28 29
+ 30>;
+
+ qcom,wcd-rst-gpio-node = <&wcd_rst_gpio>;
+
+ clock-names = "wcd_clk", "wcd_native_clk";
+ clocks = <&clock_audio clk_audio_pmi_clk>,
+ <&clock_audio clk_audio_ap_clk2>;
+
+ cdc-vdd-buck-supply = <&pmfalcon_s4>;
+ qcom,cdc-vdd-buck-voltage = <1800000 1800000>;
+ qcom,cdc-vdd-buck-current = <650000>;
+
+ cdc-buck-sido-supply = <&pmfalcon_s4>;
+ qcom,cdc-buck-sido-voltage = <1800000 1800000>;
+ qcom,cdc-buck-sido-current = <250000>;
+
+ cdc-vdd-tx-h-supply = <&pmfalcon_s4>;
+ qcom,cdc-vdd-tx-h-voltage = <1800000 1800000>;
+ qcom,cdc-vdd-tx-h-current = <25000>;
+
+ cdc-vdd-rx-h-supply = <&pmfalcon_s4>;
+ qcom,cdc-vdd-rx-h-voltage = <1800000 1800000>;
+ qcom,cdc-vdd-rx-h-current = <25000>;
+
+ cdc-vddpx-1-supply = <&pmfalcon_s4>;
+ qcom,cdc-vddpx-1-voltage = <1800000 1800000>;
+ qcom,cdc-vddpx-1-current = <10000>;
+
+ qcom,cdc-static-supplies = "cdc-vdd-buck",
+ "cdc-buck-sido",
+ "cdc-vdd-tx-h",
+ "cdc-vdd-rx-h",
+ "cdc-vddpx-1";
+
+ qcom,cdc-micbias1-mv = <1800>;
+ qcom,cdc-micbias2-mv = <1800>;
+ qcom,cdc-micbias3-mv = <1800>;
+ qcom,cdc-micbias4-mv = <1800>;
+
+ qcom,cdc-mclk-clk-rate = <9600000>;
+ qcom,cdc-slim-ifd = "tasha-slim-ifd";
+ qcom,cdc-slim-ifd-elemental-addr = [00 00 a0 01 17 02];
+ qcom,cdc-dmic-sample-rate = <4800000>;
+ qcom,cdc-mad-dmic-rate = <600000>;
+ };
+
+ wcd934x_cdc: tavil_codec {
+ compatible = "qcom,tavil-slim-pgd";
+ elemental-addr = [00 01 50 02 17 02];
+
+ interrupt-parent = <&wcd9xxx_intc>;
+ interrupts = <0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
+ 17 18 19 20 21 22 23 24 25 26 27 28 29
+ 30 31>;
+
+ qcom,wcd-rst-gpio-node = <&wcd_rst_gpio>;
+
+ clock-names = "wcd_clk";
+ clocks = <&clock_audio_lnbb clk_audio_pmi_lnbb_clk>;
+
+ cdc-vdd-buck-supply = <&pmfalcon_s4>;
+ qcom,cdc-vdd-buck-voltage = <1800000 1800000>;
+ qcom,cdc-vdd-buck-current = <650000>;
+
+ cdc-buck-sido-supply = <&pmfalcon_s4>;
+ qcom,cdc-buck-sido-voltage = <1800000 1800000>;
+ qcom,cdc-buck-sido-current = <250000>;
+
+ cdc-vdd-tx-h-supply = <&pmfalcon_s4>;
+ qcom,cdc-vdd-tx-h-voltage = <1800000 1800000>;
+ qcom,cdc-vdd-tx-h-current = <25000>;
+
+ cdc-vdd-rx-h-supply = <&pmfalcon_s4>;
+ qcom,cdc-vdd-rx-h-voltage = <1800000 1800000>;
+ qcom,cdc-vdd-rx-h-current = <25000>;
+
+ cdc-vddpx-1-supply = <&pmfalcon_s4>;
+ qcom,cdc-vddpx-1-voltage = <1800000 1800000>;
+ qcom,cdc-vddpx-1-current = <10000>;
+
+ qcom,cdc-static-supplies = "cdc-vdd-buck",
+ "cdc-buck-sido",
+ "cdc-vdd-tx-h",
+ "cdc-vdd-rx-h",
+ "cdc-vddpx-1";
+
+ qcom,cdc-micbias1-mv = <1800>;
+ qcom,cdc-micbias2-mv = <1800>;
+ qcom,cdc-micbias3-mv = <1800>;
+ qcom,cdc-micbias4-mv = <1800>;
+
+ qcom,cdc-mclk-clk-rate = <9600000>;
+ qcom,cdc-slim-ifd = "tavil-slim-ifd";
+ qcom,cdc-slim-ifd-elemental-addr = [00 00 50 02 17 02];
+ qcom,cdc-dmic-sample-rate = <4800000>;
+ qcom,cdc-mad-dmic-rate = <600000>;
+
+ qcom,wdsp-cmpnt-dev-name = "tavil_codec";
+
+ wcd_spi_0: wcd_spi {
+ compatible = "qcom,wcd-spi-v2";
+ qcom,master-bus-num = <10>;
+ qcom,chip-select = <0>;
+ qcom,max-frequency = <24000000>;
+ qcom,mem-base-addr = <0x100000>;
+ };
+ };
+};
diff --git a/arch/arm/boot/dts/qcom/msmfalcon-pinctrl.dtsi b/arch/arm/boot/dts/qcom/msmfalcon-pinctrl.dtsi
index 90aa771332a3..a029d8689111 100644
--- a/arch/arm/boot/dts/qcom/msmfalcon-pinctrl.dtsi
+++ b/arch/arm/boot/dts/qcom/msmfalcon-pinctrl.dtsi
@@ -595,6 +595,67 @@
};
};
+ /* WSA speaker reset pins */
+ spkr_1_sd_n {
+ spkr_1_sd_n_sleep: spkr_1_sd_n_sleep {
+ mux {
+ pins = "gpio26";
+ function = "gpio";
+ };
+
+ config {
+ pins = "gpio26";
+ drive-strength = <2>; /* 2 mA */
+ bias-pull-down;
+ input-enable;
+ };
+ };
+
+ spkr_1_sd_n_active: spkr_1_sd_n_active {
+ mux {
+ pins = "gpio26";
+ function = "gpio";
+ };
+
+ config {
+ pins = "gpio26";
+ drive-strength = <16>; /* 16 mA */
+ bias-disable;
+ output-high;
+ };
+ };
+ };
+
+ spkr_2_sd_n {
+ spkr_2_sd_n_sleep: spkr_2_sd_n_sleep {
+ mux {
+ pins = "gpio27";
+ function = "gpio";
+ };
+
+ config {
+ pins = "gpio27";
+ drive-strength = <2>; /* 2 mA */
+ bias-pull-down;
+ input-enable;
+ };
+ };
+
+ spkr_2_sd_n_active: spkr_2_sd_n_active {
+ mux {
+ pins = "gpio27";
+ function = "gpio";
+ };
+
+ config {
+ pins = "gpio27";
+ drive-strength = <16>; /* 16 mA */
+ bias-disable;
+ output-high;
+ };
+ };
+ };
+
/* HS UART CONFIGURATION */
blsp1_uart1_active: blsp1_uart1_active {
mux {
diff --git a/arch/arm/boot/dts/qcom/msmfalcon-regulator.dtsi b/arch/arm/boot/dts/qcom/msmfalcon-regulator.dtsi
index cfe968a7310a..0ab76c273ac3 100644
--- a/arch/arm/boot/dts/qcom/msmfalcon-regulator.dtsi
+++ b/arch/arm/boot/dts/qcom/msmfalcon-regulator.dtsi
@@ -440,6 +440,16 @@
};
};
+&pmfalcon_charger {
+ smb2_vbus: qcom,smb2-vbus {
+ regulator-name = "smb2-vbus";
+ };
+
+ smb2_vconn: qcom,smb2-vconn {
+ regulator-name = "smb2-vconn";
+ };
+};
+
/* Stub regulators */
/ {
/* GFX Supply */
diff --git a/arch/arm/boot/dts/qcom/msmfalcon-rumi.dts b/arch/arm/boot/dts/qcom/msmfalcon-rumi.dts
index 1840221359e3..2b8a78ee1fdc 100644
--- a/arch/arm/boot/dts/qcom/msmfalcon-rumi.dts
+++ b/arch/arm/boot/dts/qcom/msmfalcon-rumi.dts
@@ -94,3 +94,20 @@
compatible = "qcom,dummycc";
clock-output-names = "gcc_clocks";
};
+
+&pmfalcon_charger {
+ status = "disabled";
+};
+
+&pmfalcon_fg {
+ status = "disabled";
+};
+
+&clock_gfx {
+ compatible = "qcom,dummycc";
+ clock-output-names = "gfx_clocks";
+};
+
+&pmfalcon_pdphy {
+ status = "disabled";
+};
diff --git a/arch/arm/boot/dts/qcom/msmfalcon-sim.dts b/arch/arm/boot/dts/qcom/msmfalcon-sim.dts
index 47759c9ce3ff..d279e742c23a 100644
--- a/arch/arm/boot/dts/qcom/msmfalcon-sim.dts
+++ b/arch/arm/boot/dts/qcom/msmfalcon-sim.dts
@@ -73,3 +73,15 @@
status = "ok";
};
+
+&pmfalcon_charger {
+ status = "disabled";
+};
+
+&pmfalcon_fg {
+ status = "disabled";
+};
+
+&pmfalcon_pdphy {
+ status = "disabled";
+};
diff --git a/arch/arm/boot/dts/qcom/msmfalcon-vidc.dtsi b/arch/arm/boot/dts/qcom/msmfalcon-vidc.dtsi
new file mode 100644
index 000000000000..73d1cac48f9e
--- /dev/null
+++ b/arch/arm/boot/dts/qcom/msmfalcon-vidc.dtsi
@@ -0,0 +1,268 @@
+/* Copyright (c) 2016, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * 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 <dt-bindings/interrupt-controller/arm-gic.h>
+#include <dt-bindings/msm/msm-bus-ids.h>
+#include <dt-bindings/clock/qcom,gcc-msmfalcon.h>
+#include <dt-bindings/clock/qcom,mmcc-msmfalcon.h>
+
+&soc {
+ msm_vidc: qcom,vidc@cc00000 {
+ compatible = "qcom,msm-vidc";
+ status = "ok";
+ reg = <0xcc00000 0x100000>;
+ interrupts = <GIC_SPI 287 IRQ_TYPE_LEVEL_HIGH>;
+ qcom,hfi = "venus";
+ qcom,hfi-version = "3xx";
+ qcom,firmware-name = "venus";
+ qcom,sw-power-collapse;
+ qcom,debug-timeout;
+ qcom,reg-presets =
+ <0x80124 0x00000003>,
+ <0x80550 0x01111111>,
+ <0x80560 0x01111111>,
+ <0x80568 0x01111111>,
+ <0x80570 0x01111111>,
+ <0x80580 0x01111111>,
+ <0x80588 0x01111111>,
+ <0xe2010 0x00000000>;
+
+ qcom,max-hw-load = <1036800>; /* Full 4k @ 30 */
+ qcom,allowed-clock-rates =
+ /* TURBO NOM+ NOM
+ * SVS+ SVS SVS-
+ */
+ <518400000 441600000 404000000
+ 320000000 269330000 133330000>;
+
+ qcom,dcvs-tbl =
+ /* Dec UHD@30 All decoder - NOM to SVS+ */
+ <897600 734400 979200 0x3f00000c>,
+
+ /* Dec DCI@24 HEVC - NOM to SVS+ */
+ <816000 734400 829440 0x0c000000>,
+
+ /* Enc UHD@30 H264/HEVC - TURBO to NOM+ */
+ <897600 897600 979200 0x4000004>;
+ qcom,dcvs-limit =
+ <32400 30>, /* Encoder UHD */
+ <32400 24>; /* Decoder UHD */
+
+ /* Regulators */
+ smmu-vdd-supply = <&gdsc_bimc_smmu>;
+ venus-supply = <&gdsc_venus>;
+ venus-core0-supply = <&gdsc_venus_core0>;
+
+ /* Clocks */
+ clock-names = "gcc_mmss_sys_noc_axi_clk",
+ "mmssnoc_axi_clk", "mmss_mnoc_ahb_clk",
+ "mmss_bimc_smmu_ahb_clk", "mmss_bimc_smmu_axi_clk",
+ "mmss_video_core_clk", "mmss_video_ahb_clk",
+ "mmss_video_axi_clk",
+ "mmss_video_core0_clk";
+ clocks = <&clock_gcc GCC_MMSS_SYS_NOC_AXI_CLK>,
+ <&clock_gcc MMSSNOC_AXI_CLK>,
+ <&clock_mmss MMSS_MNOC_AHB_CLK>,
+ <&clock_mmss MMSS_BIMC_SMMU_AHB_CLK>,
+ <&clock_mmss MMSS_BIMC_SMMU_AXI_CLK>,
+ <&clock_mmss MMSS_VIDEO_CORE_CLK>,
+ <&clock_mmss MMSS_VIDEO_AHB_CLK>,
+ <&clock_mmss MMSS_VIDEO_AXI_CLK>,
+ <&clock_mmss MMSS_VIDEO_SUBCORE0_CLK>;
+ qcom,clock-configs = <0x0 0x0 0x0 0x0 0x0
+ 0x3 0x0 0x2 0x3>;
+
+ /* Buses */
+ bus_cnoc {
+ compatible = "qcom,msm-vidc,bus";
+ label = "cnoc";
+ qcom,bus-master = <MSM_BUS_MASTER_AMPSS_M0>;
+ qcom,bus-slave = <MSM_BUS_SLAVE_VENUS_CFG>;
+ qcom,bus-governor = "performance";
+ qcom,bus-range-kbps = <1 1>;
+ };
+
+ venus_bus_ddr {
+ compatible = "qcom,msm-vidc,bus";
+ label = "venus-ddr";
+ qcom,bus-master = <MSM_BUS_MASTER_VIDEO_P0>;
+ qcom,bus-slave = <MSM_BUS_SLAVE_EBI_CH0>;
+ qcom,bus-governor = "venus-ddr-gov";
+ qcom,bus-range-kbps = <1000 2365000>;
+ };
+
+ arm9_bus_ddr {
+ compatible = "qcom,msm-vidc,bus";
+ label = "venus-arm9-ddr";
+ qcom,bus-master = <MSM_BUS_MASTER_VIDEO_P0>;
+ qcom,bus-slave = <MSM_BUS_SLAVE_EBI_CH0>;
+ qcom,bus-governor = "performance";
+ qcom,bus-range-kbps = <1 1>;
+ };
+
+ qcom,clock-freq-tbl {
+ qcom,profile-enc {
+ qcom,codec-mask = <0x55555555>;
+ qcom,cycles-per-mb = <863>;
+ qcom,low-power-mode-factor = <35616>;
+ };
+ qcom,profile-dec {
+ qcom,codec-mask = <0xf3ffffff>;
+ qcom,cycles-per-mb = <355>;
+ };
+ qcom,profile-hevcdec {
+ qcom,codec-mask = <0x0c000000>;
+ qcom,cycles-per-mb = <400>;
+ };
+ };
+
+ venus-ddr-gov {
+ compatible = "qcom,msm-vidc,governor,table";
+ name = "venus-ddr-gov";
+ status = "ok";
+ qcom,bus-freq-table {
+ qcom,profile-enc {
+ qcom,codec-mask = <0x55555555>;
+ qcom,load-busfreq-tbl =
+ <979200 1044000>, /* UHD30E */
+ <864000 887000>, /* 720p240LPE */
+ <489600 666000>, /* 1080p60E */
+ <432000 578000>, /* 720p120E */
+ <244800 346000>, /* 1080p30E */
+ <216000 293000>, /* 720p60E */
+ <108000 151000>, /* 720p30E */
+ <0 0>;
+ };
+ qcom,profile-dec {
+ qcom,codec-mask = <0xffffffff>;
+ qcom,load-busfreq-tbl =
+ <979200 2365000>, /* UHD30D */
+ <864000 1978000>, /* 720p240D */
+ <489600 1133000>, /* 1080p60D */
+ <432000 994000>, /* 720p120D */
+ <244800 580000>, /* 1080p30D */
+ <216000 501000>, /* 720p60E */
+ <108000 255000>, /* 720p30D */
+ <0 0>;
+ };
+ qcom,profile-dec-ubwc {
+ qcom,codec-mask = <0xffffffff>;
+ qcom,ubwc-mode;
+ qcom,load-busfreq-tbl =
+ <979200 1892000>, /* UHD30D */
+ <864000 1554000>, /* 720p240D */
+ <489600 895000>, /* 1080p60D */
+ <432000 781000>, /* 720p120D */
+ <244800 460000>, /* 1080p30D */
+ <216000 301000>, /* 720p60E */
+ <108000 202000>, /* 720p30D */
+ <0 0>;
+ };
+ qcom,profile-dec-ubwc-10bit {
+ qcom,codec-mask = <0xffffffff>;
+ qcom,ubwc-10bit;
+ qcom,load-busfreq-tbl =
+ <979200 2446336>, /* UHD30D */
+ <864000 2108416>, /* 720p240D */
+ <489600 1207296>, /* 1080p60D */
+ <432000 1058816>, /* 720p120D */
+ <244800 616448>, /* 1080p30D */
+ <216000 534528>, /* 720p60D */
+ <108000 271360>, /* 720p30D */
+ <0 0>;
+ };
+ };
+ };
+
+
+ /* MMUs */
+ non_secure_cb {
+ compatible = "qcom,msm-vidc,context-bank";
+ label = "venus_ns";
+ iommus =
+ <&mmss_bimc_smmu 0x400>,
+ <&mmss_bimc_smmu 0x401>,
+ <&mmss_bimc_smmu 0x40a>,
+ <&mmss_bimc_smmu 0x407>,
+ <&mmss_bimc_smmu 0x40e>,
+ <&mmss_bimc_smmu 0x40f>,
+ <&mmss_bimc_smmu 0x408>,
+ <&mmss_bimc_smmu 0x409>,
+ <&mmss_bimc_smmu 0x40b>,
+ <&mmss_bimc_smmu 0x40c>,
+ <&mmss_bimc_smmu 0x40d>,
+ <&mmss_bimc_smmu 0x410>,
+ <&mmss_bimc_smmu 0x421>,
+ <&mmss_bimc_smmu 0x428>,
+ <&mmss_bimc_smmu 0x429>,
+ <&mmss_bimc_smmu 0x42b>,
+ <&mmss_bimc_smmu 0x42c>,
+ <&mmss_bimc_smmu 0x42d>,
+ <&mmss_bimc_smmu 0x411>,
+ <&mmss_bimc_smmu 0x431>;
+ buffer-types = <0xfff>;
+ virtual-addr-pool = <0x70800000 0x8f800000>;
+ };
+
+ firmware_cb {
+ compatible = "qcom,msm-vidc,context-bank";
+ qcom,fw-context-bank;
+ iommus = <&mmss_bimc_smmu 0x580>,
+ <&mmss_bimc_smmu 0x586>;
+ };
+ secure_bitstream_cb {
+ compatible = "qcom,msm-vidc,context-bank";
+ label = "venus_sec_bitstream";
+ iommus = <&mmss_bimc_smmu 0x500>,
+ <&mmss_bimc_smmu 0x502>,
+ <&mmss_bimc_smmu 0x509>,
+ <&mmss_bimc_smmu 0x50a>,
+ <&mmss_bimc_smmu 0x50b>,
+ <&mmss_bimc_smmu 0x50e>,
+ <&mmss_bimc_smmu 0x526>,
+ <&mmss_bimc_smmu 0x529>,
+ <&mmss_bimc_smmu 0x52b>;
+ buffer-types = <0x241>;
+ virtual-addr-pool = <0x4b000000 0x25800000>;
+ qcom,secure-context-bank;
+ };
+
+ venus_secure_pixel_cb: secure_pixel_cb {
+ compatible = "qcom,msm-vidc,context-bank";
+ label = "venus_sec_pixel";
+ iommus = <&mmss_bimc_smmu 0x504>,
+ <&mmss_bimc_smmu 0x50c>,
+ <&mmss_bimc_smmu 0x510>,
+ <&mmss_bimc_smmu 0x52c>;
+ buffer-types = <0x106>;
+ virtual-addr-pool = <0x25800000 0x25800000>;
+ qcom,secure-context-bank;
+ };
+
+ venus_secure_non_pixel_cb: secure_non_pixel_cb {
+ compatible = "qcom,msm-vidc,context-bank";
+ label = "venus_sec_non_pixel";
+ iommus = <&mmss_bimc_smmu 0x505>,
+ <&mmss_bimc_smmu 0x507>,
+ <&mmss_bimc_smmu 0x508>,
+ <&mmss_bimc_smmu 0x50d>,
+ <&mmss_bimc_smmu 0x50f>,
+ <&mmss_bimc_smmu 0x525>,
+ <&mmss_bimc_smmu 0x528>,
+ <&mmss_bimc_smmu 0x52d>,
+ <&mmss_bimc_smmu 0x540>;
+ buffer-types = <0x480>;
+ virtual-addr-pool = <0x1000000 0x24800000>;
+ qcom,secure-context-bank;
+ };
+ };
+};
diff --git a/arch/arm/boot/dts/qcom/msmfalcon-wcd.dtsi b/arch/arm/boot/dts/qcom/msmfalcon-wcd.dtsi
new file mode 100644
index 000000000000..29f4ccaede9f
--- /dev/null
+++ b/arch/arm/boot/dts/qcom/msmfalcon-wcd.dtsi
@@ -0,0 +1,183 @@
+/* Copyright (c) 2016, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * 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.
+ */
+
+&slim_aud {
+ tasha_codec {
+ wsa_spkr_sd1: msm_cdc_pinctrll {
+ compatible = "qcom,msm-cdc-pinctrl";
+ pinctrl-names = "aud_active", "aud_sleep";
+ pinctrl-0 = <&spkr_1_sd_n_active>;
+ pinctrl-1 = <&spkr_1_sd_n_sleep>;
+ };
+
+ wsa_spkr_sd2: msm_cdc_pinctrlr {
+ compatible = "qcom,msm-cdc-pinctrl";
+ pinctrl-names = "aud_active", "aud_sleep";
+ pinctrl-0 = <&spkr_2_sd_n_active>;
+ pinctrl-1 = <&spkr_2_sd_n_sleep>;
+ };
+ };
+
+ tavil_codec {
+ wcd: wcd_pinctrl@5 {
+ compatible = "qcom,wcd-pinctrl";
+ qcom,num-gpios = <5>;
+ gpio-controller;
+ #gpio-cells = <2>;
+
+ us_euro_sw_wcd_active: us_euro_sw_wcd_active {
+ mux {
+ pins = "gpio1";
+ };
+
+ config {
+ pins = "gpio1";
+ output-high;
+ };
+ };
+
+ us_euro_sw_wcd_sleep: us_euro_sw_wcd_sleep {
+ mux {
+ pins = "gpio1";
+ };
+
+ config {
+ pins = "gpio1";
+ output-low;
+ };
+ };
+
+ spkr_1_wcd_en_active: spkr_1_wcd_en_active {
+ mux {
+ pins = "gpio2";
+ };
+
+ config {
+ pins = "gpio2";
+ output-high;
+ };
+ };
+
+ spkr_1_wcd_en_sleep: spkr_1_wcd_en_sleep {
+ mux {
+ pins = "gpio2";
+ };
+
+ config {
+ pins = "gpio2";
+ input-enable;
+ };
+ };
+
+ spkr_2_wcd_en_active: spkr_2_sd_n_active {
+ mux {
+ pins = "gpio3";
+ };
+
+ config {
+ pins = "gpio3";
+ output-high;
+ };
+ };
+
+ spkr_2_wcd_en_sleep: spkr_2_sd_n_sleep {
+ mux {
+ pins = "gpio3";
+ };
+
+ config {
+ pins = "gpio3";
+ input-enable;
+ };
+ };
+
+ hph_en0_wcd_active: hph_en0_wcd_active {
+ mux {
+ pins = "gpio4";
+ };
+
+ config {
+ pins = "gpio4";
+ output-high;
+ };
+ };
+
+ hph_en0_wcd_sleep: hph_en0_wcd_sleep {
+ mux {
+ pins = "gpio4";
+ };
+
+ config {
+ pins = "gpio4";
+ output-low;
+ };
+ };
+
+ hph_en1_wcd_active: hph_en1_wcd_active {
+ mux {
+ pins = "gpio5";
+ };
+
+ config {
+ pins = "gpio5";
+ output-high;
+ };
+ };
+
+ hph_en1_wcd_sleep: hph_en1_wcd_sleep {
+ mux {
+ pins = "gpio5";
+ };
+
+ config {
+ pins = "gpio5";
+ output-low;
+ };
+ };
+ };
+
+ wsa_spkr_wcd_sd1: msm_cdc_pinctrll {
+ compatible = "qcom,msm-cdc-pinctrl";
+ pinctrl-names = "aud_active", "aud_sleep";
+ pinctrl-0 = <&spkr_1_wcd_en_active>;
+ pinctrl-1 = <&spkr_1_wcd_en_sleep>;
+ };
+
+ wsa_spkr_wcd_sd2: msm_cdc_pinctrlr {
+ compatible = "qcom,msm-cdc-pinctrl";
+ pinctrl-names = "aud_active", "aud_sleep";
+ pinctrl-0 = <&spkr_2_wcd_en_active>;
+ pinctrl-1 = <&spkr_2_wcd_en_sleep>;
+ };
+
+ tavil_us_euro_sw: msm_cdc_pinctrl_us_euro_sw {
+ compatible = "qcom,msm-cdc-pinctrl";
+ pinctrl-names = "aud_active", "aud_sleep";
+ pinctrl-0 = <&us_euro_sw_wcd_active>;
+ pinctrl-1 = <&us_euro_sw_wcd_sleep>;
+ };
+
+ tavil_hph_en0: msm_cdc_pinctrl_hph_en0 {
+ compatible = "qcom,msm-cdc-pinctrl";
+ pinctrl-names = "aud_active", "aud_sleep";
+ pinctrl-0 = <&hph_en0_wcd_active>;
+ pinctrl-1 = <&hph_en0_wcd_sleep>;
+ };
+
+ tavil_hph_en1: msm_cdc_pinctrl_hph_en1 {
+ compatible = "qcom,msm-cdc-pinctrl";
+ pinctrl-names = "aud_active", "aud_sleep";
+ pinctrl-0 = <&hph_en1_wcd_active>;
+ pinctrl-1 = <&hph_en1_wcd_sleep>;
+ };
+ };
+};
diff --git a/arch/arm/boot/dts/qcom/msmfalcon-wsa881x.dtsi b/arch/arm/boot/dts/qcom/msmfalcon-wsa881x.dtsi
new file mode 100644
index 000000000000..123f922facdd
--- /dev/null
+++ b/arch/arm/boot/dts/qcom/msmfalcon-wsa881x.dtsi
@@ -0,0 +1,79 @@
+/* Copyright (c) 2016, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * 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 "msmfalcon-wcd.dtsi"
+
+&slim_aud {
+ tasha_codec {
+ swr_master {
+ compatible = "qcom,swr-wcd";
+ #address-cells = <2>;
+ #size-cells = <0>;
+
+ wsa881x_211: wsa881x@20170211 {
+ compatible = "qcom,wsa881x";
+ reg = <0x0 0x20170211>;
+ qcom,spkr-sd-n-node = <&wsa_spkr_sd1>;
+ };
+
+ wsa881x_212: wsa881x@20170212 {
+ compatible = "qcom,wsa881x";
+ reg = <0x0 0x20170212>;
+ qcom,spkr-sd-n-node = <&wsa_spkr_sd2>;
+ };
+
+ wsa881x_213: wsa881x@21170213 {
+ compatible = "qcom,wsa881x";
+ reg = <0x0 0x21170213>;
+ qcom,spkr-sd-n-node = <&wsa_spkr_sd1>;
+ };
+
+ wsa881x_214: wsa881x@21170214 {
+ compatible = "qcom,wsa881x";
+ reg = <0x0 0x21170214>;
+ qcom,spkr-sd-n-node = <&wsa_spkr_sd2>;
+ };
+ };
+ };
+
+ tavil_codec {
+ swr_master {
+ compatible = "qcom,swr-wcd";
+ #address-cells = <2>;
+ #size-cells = <0>;
+
+ wsa881x_0211: wsa881x@20170211 {
+ compatible = "qcom,wsa881x";
+ reg = <0x0 0x20170211>;
+ qcom,spkr-sd-n-node = <&wsa_spkr_wcd_sd1>;
+ };
+
+ wsa881x_0212: wsa881x@20170212 {
+ compatible = "qcom,wsa881x";
+ reg = <0x0 0x20170212>;
+ qcom,spkr-sd-n-node = <&wsa_spkr_wcd_sd2>;
+ };
+
+ wsa881x_0213: wsa881x@21170213 {
+ compatible = "qcom,wsa881x";
+ reg = <0x0 0x21170213>;
+ qcom,spkr-sd-n-node = <&wsa_spkr_wcd_sd1>;
+ };
+
+ wsa881x_0214: wsa881x@21170214 {
+ compatible = "qcom,wsa881x";
+ reg = <0x0 0x21170214>;
+ qcom,spkr-sd-n-node = <&wsa_spkr_wcd_sd2>;
+ };
+ };
+ };
+};
diff --git a/arch/arm/boot/dts/qcom/msmfalcon.dtsi b/arch/arm/boot/dts/qcom/msmfalcon.dtsi
index 23d3043fcc3b..6ef443c4de11 100644
--- a/arch/arm/boot/dts/qcom/msmfalcon.dtsi
+++ b/arch/arm/boot/dts/qcom/msmfalcon.dtsi
@@ -47,6 +47,8 @@
compatible = "arm,armv8";
reg = <0x0 0x0>;
enable-method = "psci";
+ qcom,limits-info = <&mitigation_profile0>;
+ qcom,ea = <&ea0>;
};
CPU1: cpu@1 {
@@ -54,6 +56,8 @@
compatible = "arm,armv8";
reg = <0x0 0x1>;
enable-method = "psci";
+ qcom,limits-info = <&mitigation_profile0>;
+ qcom,ea = <&ea1>;
};
CPU2: cpu@2 {
@@ -61,6 +65,8 @@
compatible = "arm,armv8";
reg = <0x0 0x2>;
enable-method = "psci";
+ qcom,limits-info = <&mitigation_profile0>;
+ qcom,ea = <&ea2>;
};
CPU3: cpu@3 {
@@ -68,6 +74,8 @@
compatible = "arm,armv8";
reg = <0x0 0x3>;
enable-method = "psci";
+ qcom,limits-info = <&mitigation_profile0>;
+ qcom,ea = <&ea3>;
};
CPU4: cpu@100 {
@@ -75,6 +83,8 @@
compatible = "arm,armv8";
reg = <0x0 0x100>;
enable-method = "psci";
+ qcom,limits-info = <&mitigation_profile1>;
+ qcom,ea = <&ea4>;
};
CPU5: cpu@101 {
@@ -82,6 +92,8 @@
compatible = "arm,armv8";
reg = <0x0 0x101>;
enable-method = "psci";
+ qcom,limits-info = <&mitigation_profile2>;
+ qcom,ea = <&ea5>;
};
CPU6: cpu@102 {
@@ -89,6 +101,8 @@
compatible = "arm,armv8";
reg = <0x0 0x102>;
enable-method = "psci";
+ qcom,limits-info = <&mitigation_profile3>;
+ qcom,ea = <&ea6>;
};
CPU7: cpu@103 {
@@ -96,6 +110,8 @@
compatible = "arm,armv8";
reg = <0x0 0x103>;
enable-method = "psci";
+ qcom,limits-info = <&mitigation_profile4>;
+ qcom,ea = <&ea7>;
};
cpu-map {
@@ -265,6 +281,13 @@
qcom,summing-threshold = <0x10>;
};
+ restart@10ac000 {
+ compatible = "qcom,pshold";
+ reg = <0x10ac000 0x4>,
+ <0x1fd3000 0x4>;
+ reg-names = "pshold-base", "tcsr-boot-misc-detect";
+ };
+
spmi_bus: qcom,spmi@800f000 {
compatible = "qcom,spmi-pmic-arb";
reg = <0x800f000 0x1000>,
@@ -351,6 +374,219 @@
clock-names = "core", "iface";
};
+ qcom,sensor-information {
+ compatible = "qcom,sensor-information";
+ sensor_information0: qcom,sensor-information-0 {
+ qcom,sensor-type = "tsens";
+ qcom,sensor-name = "tsens_tz_sensor0";
+ qcom,scaling-factor = <10>;
+ };
+ sensor_information1: qcom,sensor-information-1 {
+ qcom,sensor-type = "tsens";
+ qcom,sensor-name = "tsens_tz_sensor1";
+ qcom,scaling-factor = <10>;
+ };
+ sensor_information2: qcom,sensor-information-2 {
+ qcom,sensor-type = "tsens";
+ qcom,sensor-name = "tsens_tz_sensor2";
+ qcom,scaling-factor = <10>;
+ };
+ sensor_information3: qcom,sensor-information-3 {
+ qcom,sensor-type = "tsens";
+ qcom,sensor-name = "tsens_tz_sensor3";
+ qcom,scaling-factor = <10>;
+ };
+ sensor_information4: qcom,sensor-information-4 {
+ qcom,sensor-type = "tsens";
+ qcom,sensor-name = "tsens_tz_sensor4";
+ qcom,scaling-factor = <10>;
+ };
+ sensor_information5: qcom,sensor-information-5 {
+ qcom,sensor-type = "tsens";
+ qcom,sensor-name = "tsens_tz_sensor5";
+ qcom,scaling-factor = <10>;
+ };
+ sensor_information6: qcom,sensor-information-6 {
+ qcom,sensor-type = "tsens";
+ qcom,sensor-name = "tsens_tz_sensor6";
+ qcom,scaling-factor = <10>;
+ };
+ sensor_information7: qcom,sensor-information-7 {
+ qcom,sensor-type = "tsens";
+ qcom,sensor-name = "tsens_tz_sensor7";
+ qcom,scaling-factor = <10>;
+ };
+ sensor_information8: qcom,sensor-information-8 {
+ qcom,sensor-type = "tsens";
+ qcom,sensor-name = "tsens_tz_sensor8";
+ qcom,scaling-factor = <10>;
+ qcom,alias-name = "gpu";
+ };
+ sensor_information9: qcom,sensor-information-9 {
+ qcom,sensor-type = "tsens";
+ qcom,sensor-name = "tsens_tz_sensor9";
+ qcom,scaling-factor = <10>;
+ };
+ sensor_information10: qcom,sensor-information-10 {
+ qcom,sensor-type = "tsens";
+ qcom,sensor-name = "tsens_tz_sensor10";
+ qcom,scaling-factor = <10>;
+ };
+ sensor_information11: qcom,sensor-information-11 {
+ qcom,sensor-type = "tsens";
+ qcom,sensor-name = "tsens_tz_sensor11";
+ qcom,scaling-factor = <10>;
+ };
+ sensor_information12: qcom,sensor-information-12 {
+ qcom,sensor-type = "tsens";
+ qcom,sensor-name = "tsens_tz_sensor12";
+ qcom,scaling-factor = <10>;
+ };
+ sensor_information13: qcom,sensor-information-13 {
+ qcom,sensor-type = "tsens";
+ qcom,sensor-name = "tsens_tz_sensor13";
+ qcom,scaling-factor = <10>;
+ };
+ sensor_information14: qcom,sensor-information-14 {
+ qcom,sensor-type = "alarm";
+ qcom,sensor-name = "pmfalcon_tz";
+ qcom,scaling-factor = <1000>;
+ };
+ sensor_information15: qcom,sensor-information-15 {
+ qcom,sensor-type = "adc";
+ qcom,sensor-name = "msm_therm";
+ };
+ sensor_information16: qcom,sensor-information-16 {
+ qcom,sensor-type = "adc";
+ qcom,sensor-name = "xo_therm";
+ };
+ sensor_information17: qcom,sensor-information-17 {
+ qcom,sensor-type = "adc";
+ qcom,sensor-name = "pa_therm0";
+ };
+ sensor_information18: qcom,sensor-information-18 {
+ qcom,sensor-type = "adc";
+ qcom,sensor-name = "pa_therm1";
+ };
+ sensor_information19: qcom,sensor-information-19 {
+ qcom,sensor-type = "adc";
+ qcom,sensor-name = "quiet_therm";
+ };
+ sensor_information20: qcom,sensor-information-20 {
+ qcom,sensor-type = "llm";
+ qcom,sensor-name = "limits_sensor-00";
+ };
+ sensor_information21: qcom,sensor-information-21 {
+ qcom,sensor-type = "llm";
+ qcom,sensor-name = "limits_sensor-01";
+ };
+ };
+
+ mitigation_profile0: qcom,limit_info-0 {
+ qcom,temperature-sensor = <&sensor_information1>;
+ qcom,hotplug-mitigation-enable;
+ };
+
+ mitigation_profile1: qcom,limit_info-1 {
+ qcom,temperature-sensor = <&sensor_information3>;
+ qcom,hotplug-mitigation-enable;
+ };
+
+ mitigation_profile2: qcom,limit_info-2 {
+ qcom,temperature-sensor = <&sensor_information4>;
+ qcom,hotplug-mitigation-enable;
+ };
+
+ mitigation_profile3: qcom,limit_info-3 {
+ qcom,temperature-sensor = <&sensor_information5>;
+ qcom,hotplug-mitigation-enable;
+ };
+
+ mitigation_profile4: qcom,limit_info-4 {
+ qcom,temperature-sensor = <&sensor_information6>;
+ qcom,hotplug-mitigation-enable;
+ };
+
+ qcom,msm-thermal {
+ compatible = "qcom,msm-thermal";
+ qcom,sensor-id = <1>;
+ qcom,poll-ms = <100>;
+ qcom,therm-reset-temp = <115>;
+ qcom,core-limit-temp = <70>;
+ qcom,core-temp-hysteresis = <10>;
+ qcom,hotplug-temp = <105>;
+ qcom,hotplug-temp-hysteresis = <20>;
+ qcom,online-hotplug-core;
+ qcom,synchronous-cluster-id = <0 1>;
+ qcom,synchronous-cluster-map = <0 4 &CPU0 &CPU1 &CPU2 &CPU3>,
+ <1 4 &CPU4 &CPU5 &CPU6 &CPU7>;
+
+ qcom,vdd-restriction-temp = <5>;
+ qcom,vdd-restriction-temp-hysteresis = <10>;
+
+ vdd-dig-supply = <&pm2falcon_s3_floor_level>;
+ vdd-gfx-supply = <&gfx_vreg_corner>;
+
+ qcom,vdd-dig-rstr{
+ qcom,vdd-rstr-reg = "vdd-dig";
+ qcom,levels = <RPM_SMD_REGULATOR_LEVEL_NOM
+ RPM_SMD_REGULATOR_LEVEL_TURBO
+ RPM_SMD_REGULATOR_LEVEL_TURBO>;
+ qcom,min-level = <RPM_SMD_REGULATOR_LEVEL_NONE>;
+ };
+
+ qcom,vdd-gfx-rstr{
+ qcom,vdd-rstr-reg = "vdd-gfx";
+ qcom,levels = <5 6 6>; /* Nominal, Turbo, Turbo */
+ qcom,min-level = <1>; /* No Request */
+ };
+
+ msm_thermal_freq: qcom,vdd-apps-rstr{
+ qcom,vdd-rstr-reg = "vdd-apps";
+ qcom,levels = <1248000>;
+ qcom,freq-req;
+ };
+ };
+
+ qcom,msm-core@780000 {
+ compatible = "qcom,apss-core-ea";
+ reg = <0x780000 0x1000>;
+ qcom,low-hyst-temp = <10>;
+ qcom,high-hyst-temp = <5>;
+
+ ea0: ea0 {
+ sensor = <&sensor_information1>;
+ };
+
+ ea1: ea1 {
+ sensor = <&sensor_information1>;
+ };
+
+ ea2: ea2 {
+ sensor = <&sensor_information1>;
+ };
+
+ ea3: ea3 {
+ sensor = <&sensor_information1>;
+ };
+
+ ea4: ea4 {
+ sensor = <&sensor_information3>;
+ };
+
+ ea5: ea5 {
+ sensor = <&sensor_information4>;
+ };
+
+ ea6: ea6 {
+ sensor = <&sensor_information5>;
+ };
+
+ ea7: ea7 {
+ sensor = <&sensor_information6>;
+ };
+ };
+
uartblsp2dm1: serial@0c1b0000 {
compatible = "qcom,msm-uartdm-v1.4", "qcom,msm-uartdm";
reg = <0xc1b0000 0x1000>;
@@ -467,8 +703,21 @@
};
clock_gfx: clock-controller@5065000 {
- compatible = "qcom,dummycc";
- clock-output-names = "gfx_clocks";
+ compatible = "qcom,gpucc-msmfalcon";
+ reg = <0x5065000 0x10000>;
+ vdd_dig_gfx-supply = <&pm2falcon_s3_level>;
+ vdd_mx_gfx-supply = <&pm2falcon_s5_level>;
+ vdd_gfx-supply = <&gfx_vreg_corner>;
+ qcom,gfxfreq-corner =
+ < 0 0>,
+ < 160000000 1>, /* MinSVS */
+ < 266000000 2>, /* LowSVS */
+ < 370000000 3>, /* SVS */
+ < 465000000 4>, /* SVS_L1 */
+ < 588000000 5>, /* NOM */
+ < 647000000 6>, /* NOM_L1 */
+ < 700000000 7>, /* TURBO */
+ < 750000000 7>; /* TURBO */
#clock-cells = <1>;
#reset-cells = <1>;
};
@@ -493,6 +742,72 @@
status = "disabled";
};
+ ipa_hw: qcom,ipa@14780000 {
+ compatible = "qcom,ipa";
+ reg = <0x14780000 0x4effc>, <0x14784000 0x26934>;
+ reg-names = "ipa-base", "bam-base";
+ interrupts = <0 333 0>,
+ <0 432 0>;
+ interrupt-names = "ipa-irq", "bam-irq";
+ qcom,ipa-hw-ver = <6>; /* IPA core version = IPAv2.6L */
+ qcom,ipa-hw-mode = <0>; /* IPA hw type = Normal */
+ qcom,wan-rx-ring-size = <192>; /* IPA WAN-rx-ring-size*/
+ qcom,lan-rx-ring-size = <192>; /* IPA LAN-rx-ring-size*/
+ clocks = <&clock_rpmcc RPM_IPA_CLK>,
+ <&clock_rpmcc RPM_AGGR2_NOC_CLK>;
+ clock-names = "core_clk", "smmu_clk";
+ qcom,arm-smmu;
+ qcom,smmu-disable-htw;
+ qcom,smmu-s1-bypass;
+ qcom,ee = <0>;
+ qcom,use-ipa-tethering-bridge;
+ qcom,modem-cfg-emb-pipe-flt;
+ qcom,msm-bus,name = "ipa";
+ qcom,msm-bus,num-cases = <4>;
+ qcom,msm-bus,num-paths = <2>;
+ qcom,msm-bus,vectors-KBps =
+ /* No vote */
+ <90 512 0 0>,
+ <1 676 0 0>,
+ /* SVS */
+ <90 512 80000 640000>,
+ <1 676 80000 80000>,
+ /* NOMINAL */
+ <90 512 206000 960000>,
+ <1 676 206000 160000>,
+ /* TURBO */
+ <90 512 206000 960000>,
+ <1 676 206000 160000>;
+ qcom,bus-vector-names = "MIN", "SVS", "PERF", "TURBO";
+ qcom,rx-polling-sleep-ms = <2>; /* Polling sleep interval */
+ qcom,ipa-polling-iteration = <5>; /* Polling Iteration */
+
+ ipa_smmu_ap: ipa_smmu_ap {
+ compatible = "qcom,ipa-smmu-ap-cb";
+ iommus = <&anoc2_smmu 0x19C0>;
+ qcom,iova-mapping = <0x10000000 0x40000000>;
+ };
+
+ ipa_smmu_wlan: ipa_smmu_wlan {
+ status = "disabled";
+ compatible = "qcom,ipa-smmu-wlan-cb";
+ iommus = <&anoc2_smmu 0x19C1>;
+ };
+
+ ipa_smmu_uc: ipa_smmu_uc {
+ compatible = "qcom,ipa-smmu-uc-cb";
+ iommus = <&anoc2_smmu 0x19C2>;
+ qcom,iova-mapping = <0x40000000 0x20000000>;
+ };
+ };
+
+ qcom,rmnet-ipa {
+ compatible = "qcom,rmnet-ipa";
+ qcom,rmnet-ipa-ssr;
+ qcom,ipa-loaduC;
+ qcom,ipa-advertise-sg-support;
+ };
+
qcom,ipc-spinlock@1f40000 {
compatible = "qcom,ipc-spinlock-sfpb";
reg = <0x1f40000 0x8000>;
@@ -877,6 +1192,17 @@
status = "ok";
};
+ qcom,msm-rtb {
+ compatible = "qcom,msm-rtb";
+ qcom,rtb-size = <0x100000>;
+ };
+
+ qcom,mpm2-sleep-counter@10a3000 {
+ compatible = "qcom,mpm2-sleep-counter";
+ reg = <0x10a3000 0x1000>;
+ clock-frequency = <32768>;
+ };
+
qcom,msm-imem@146bf000 {
compatible = "qcom,msm-imem";
reg = <0x146bf000 0x1000>;
@@ -884,6 +1210,21 @@
#address-cells = <1>;
#size-cells = <1>;
+ dload_type@18 {
+ compatible = "qcom,msm-imem-dload-type";
+ reg = <0x18 4>;
+ };
+
+ restart_reason@65c {
+ compatible = "qcom,msm-imem-restart_reason";
+ reg = <0x65c 4>;
+ };
+
+ boot_stats@6b0 {
+ compatible = "qcom,msm-imem-boot_stats";
+ reg = <0x6b0 32>;
+ };
+
pil@94c {
compatible = "qcom,msm-imem-pil";
reg = <0x94c 200>;
@@ -906,18 +1247,52 @@
clock-names = "atb_clk";
clocks = <&clock_rpmcc RPM_QDSS_CLK>;
};
+
+ cpu_pmu: cpu-pmu {
+ compatible = "arm,armv8-pmuv3";
+ qcom,irq-is-percpu;
+ interrupts = <1 6 4>;
+ };
+
+ qcom_seecom: qseecom@86d00000 {
+ compatible = "qcom,qseecom";
+ reg = <0x86d00000 0x2200000>;
+ reg-names = "secapp-region";
+ qcom,hlos-num-ce-hw-instances = <1>;
+ qcom,hlos-ce-hw-instance = <0>;
+ qcom,qsee-ce-hw-instance = <0>;
+ qcom,disk-encrypt-pipe-pair = <2>;
+ qcom,support-fde;
+ qcom,no-clock-support;
+ qcom,msm-bus,name = "qseecom-noc";
+ qcom,msm-bus,num-cases = <4>;
+ qcom,msm-bus,num-paths = <1>;
+ qcom,msm-bus,vectors-KBps =
+ <55 512 0 0>,
+ <55 512 200000 400000>,
+ <55 512 300000 800000>,
+ <55 512 400000 1000000>;
+ clock-names = "core_clk_src", "core_clk",
+ "iface_clk", "bus_clk";
+ clocks = <&clock_gcc QSEECOM_CE1_CLK>,
+ <&clock_gcc QSEECOM_CE1_CLK>,
+ <&clock_gcc QSEECOM_CE1_CLK>,
+ <&clock_gcc QSEECOM_CE1_CLK>;
+ qcom,ce-opp-freq = <171430000>;
+ qcom,qsee-reentrancy-support = <2>;
+ };
};
#include "msmfalcon-ion.dtsi"
#include "msmfalcon-bus.dtsi"
+#include "msm-pmfalcon.dtsi"
+#include "msm-pm2falcon.dtsi"
#include "msm-pmfalcon-rpm-regulator.dtsi"
#include "msm-pm2falcon-rpm-regulator.dtsi"
#include "msmfalcon-regulator.dtsi"
#include "msm-gdsc-falcon.dtsi"
&gdsc_usb30 {
- clock-names = "core_clk";
- clocks = <&clock_gcc GCC_USB30_MASTER_CLK>;
status = "ok";
};
@@ -974,19 +1349,14 @@
};
&gdsc_mdss {
- clock-names = "bus_clk", "rot_clk";
- clocks = <&clock_mmss MMSS_MDSS_AXI_CLK>,
- <&clock_mmss MMSS_MDSS_ROT_CLK>;
proxy-supply = <&gdsc_mdss>;
qcom,proxy-consumer-enable;
status = "ok";
};
&gdsc_gpu_gx {
- clock-names = "bimc_core_clk", "core_clk", "core_root_clk";
- clocks = <&clock_gcc GCC_GPU_BIMC_GFX_CLK>,
- <&clock_gfx GPUCC_GFX3D_CLK>,
- <&clock_gfx GFX3D_CLK_SRC>;
+ clock-names = "core_root_clk";
+ clocks = <&clock_gfx GFX3D_CLK_SRC>;
qcom,force-enable-root-clk;
parent-supply = <&gfx_vreg_corner>;
status = "ok";
@@ -996,9 +1366,8 @@
status = "ok";
};
-#include "msm-pmfalcon.dtsi"
-#include "msm-pm2falcon.dtsi"
#include "msm-arm-smmu-falcon.dtsi"
#include "msm-arm-smmu-impl-defs-falcon.dtsi"
#include "msmfalcon-common.dtsi"
#include "msmfalcon-blsp.dtsi"
+#include "msmfalcon-vidc.dtsi"
diff --git a/arch/arm/boot/dts/qcom/msmtriton-rumi.dts b/arch/arm/boot/dts/qcom/msmtriton-rumi.dts
index 08809fb38cae..491b55aab9a6 100644
--- a/arch/arm/boot/dts/qcom/msmtriton-rumi.dts
+++ b/arch/arm/boot/dts/qcom/msmtriton-rumi.dts
@@ -63,3 +63,8 @@
compatible = "qcom,dummycc";
clock-output-names = "gcc_clocks";
};
+
+&clock_gfx {
+ compatible = "qcom,dummycc";
+ clock-output-names = "gfx_clocks";
+};
diff --git a/arch/arm/boot/dts/qcom/msmtriton.dtsi b/arch/arm/boot/dts/qcom/msmtriton.dtsi
index cd751f3181ee..2a22772c8d1d 100644
--- a/arch/arm/boot/dts/qcom/msmtriton.dtsi
+++ b/arch/arm/boot/dts/qcom/msmtriton.dtsi
@@ -241,6 +241,13 @@
clock-frequency = <19200000>;
};
+ restart@10ac000 {
+ compatible = "qcom,pshold";
+ reg = <0x10ac000 0x4>,
+ <0x1fd3000 0x4>;
+ reg-names = "pshold-base", "tcsr-boot-misc-detect";
+ };
+
qcom,sps {
compatible = "qcom,msm_sps_4k";
qcom,pipe-attr-ee;
@@ -382,8 +389,21 @@
};
clock_gfx: clock-controller@5065000 {
- compatible = "qcom,dummycc";
- clock-output-names = "gfx_clocks";
+ compatible = "qcom,gpucc-msmfalcon";
+ reg = <0x5065000 0x10000>;
+ vdd_dig_gfx-supply = <&pm2falcon_s3_level>;
+ vdd_mx_gfx-supply = <&pm2falcon_s5_level>;
+ vdd_gfx-supply = <&gfx_vreg_corner>;
+ qcom,gfxfreq-corner =
+ < 0 0>,
+ < 160000000 1>, /* MinSVS */
+ < 266000000 2>, /* LowSVS */
+ < 370000000 3>, /* SVS */
+ < 465000000 4>, /* SVS_L1 */
+ < 588000000 5>, /* NOM */
+ < 647000000 6>, /* NOM_L1 */
+ < 700000000 7>, /* TURBO */
+ < 750000000 7>; /* TURBO */
#clock-cells = <1>;
#reset-cells = <1>;
};
@@ -698,6 +718,17 @@
status = "ok";
};
+ qcom,msm-rtb {
+ compatible = "qcom,msm-rtb";
+ qcom,rtb-size = <0x100000>;
+ };
+
+ qcom,mpm2-sleep-counter@10a3000 {
+ compatible = "qcom,mpm2-sleep-counter";
+ reg = <0x10a3000 0x1000>;
+ clock-frequency = <32768>;
+ };
+
qcom,msm-imem@146bf000 {
compatible = "qcom,msm-imem";
reg = <0x146bf000 0x1000>;
@@ -705,6 +736,21 @@
#address-cells = <1>;
#size-cells = <1>;
+ dload_type@18 {
+ compatible = "qcom,msm-imem-dload-type";
+ reg = <0x18 4>;
+ };
+
+ restart_reason@65c {
+ compatible = "qcom,msm-imem-restart_reason";
+ reg = <0x65c 4>;
+ };
+
+ boot_stats@6b0 {
+ compatible = "qcom,msm-imem-boot_stats";
+ reg = <0x6b0 32>;
+ };
+
pil@94c {
compatible = "qcom,msm-imem-pil";
reg = <0x94c 200>;
@@ -727,6 +773,12 @@
clock-names = "atb_clk";
clocks = <&clock_rpmcc RPM_QDSS_CLK>;
};
+
+ cpu_pmu: cpu-pmu {
+ compatible = "arm,armv8-pmuv3";
+ qcom,irq-is-percpu;
+ interrupts = <1 6 4>;
+ };
};
#include "msmtriton-ion.dtsi"
@@ -735,8 +787,6 @@
#include "msmfalcon-common.dtsi"
&gdsc_usb30 {
- clock-names = "core_clk";
- clocks = <&clock_gcc GCC_USB30_MASTER_CLK>;
status = "ok";
};
@@ -785,19 +835,14 @@
};
&gdsc_mdss {
- clock-names = "bus_clk", "rot_clk";
- clocks = <&clock_mmss MMSS_MDSS_AXI_CLK>,
- <&clock_mmss MMSS_MDSS_ROT_CLK>;
proxy-supply = <&gdsc_mdss>;
qcom,proxy-consumer-enable;
status = "ok";
};
&gdsc_gpu_gx {
- clock-names = "bimc_core_clk", "core_clk", "core_root_clk";
- clocks = <&clock_gcc GCC_GPU_BIMC_GFX_CLK>,
- <&clock_gfx GPUCC_GFX3D_CLK>,
- <&clock_gfx GFX3D_CLK_SRC>;
+ clock-names = "core_root_clk";
+ clocks = <&clock_gfx GFX3D_CLK_SRC>;
qcom,force-enable-root-clk;
parent-supply = <&gfx_vreg_corner>;
status = "ok";
diff --git a/arch/arm/configs/msmfalcon-perf_defconfig b/arch/arm/configs/msmfalcon-perf_defconfig
new file mode 100644
index 000000000000..1f8d22153a32
--- /dev/null
+++ b/arch/arm/configs/msmfalcon-perf_defconfig
@@ -0,0 +1,607 @@
+# CONFIG_LOCALVERSION_AUTO is not set
+CONFIG_AUDIT=y
+CONFIG_NO_HZ=y
+CONFIG_HIGH_RES_TIMERS=y
+CONFIG_IRQ_TIME_ACCOUNTING=y
+CONFIG_RCU_EXPERT=y
+CONFIG_RCU_FAST_NO_HZ=y
+CONFIG_IKCONFIG=y
+CONFIG_IKCONFIG_PROC=y
+CONFIG_LOG_CPU_MAX_BUF_SHIFT=17
+CONFIG_CGROUP_FREEZER=y
+CONFIG_CPUSETS=y
+CONFIG_CGROUP_CPUACCT=y
+CONFIG_CGROUP_SCHEDTUNE=y
+CONFIG_RT_GROUP_SCHED=y
+CONFIG_SCHED_HMP=y
+CONFIG_SCHED_HMP_CSTATE_AWARE=y
+CONFIG_SCHED_CORE_CTL=y
+CONFIG_NAMESPACES=y
+# CONFIG_UTS_NS is not set
+# CONFIG_PID_NS is not set
+CONFIG_SCHED_AUTOGROUP=y
+CONFIG_SCHED_TUNE=y
+CONFIG_BLK_DEV_INITRD=y
+# CONFIG_RD_XZ is not set
+# CONFIG_RD_LZO is not set
+# CONFIG_RD_LZ4 is not set
+CONFIG_CC_OPTIMIZE_FOR_SIZE=y
+CONFIG_KALLSYMS_ALL=y
+# CONFIG_MEMBARRIER is not set
+CONFIG_EMBEDDED=y
+# CONFIG_SLUB_DEBUG is not set
+# CONFIG_COMPAT_BRK is not set
+CONFIG_PROFILING=y
+CONFIG_CC_STACKPROTECTOR_REGULAR=y
+CONFIG_MODULES=y
+CONFIG_MODULE_UNLOAD=y
+CONFIG_MODULE_FORCE_UNLOAD=y
+CONFIG_MODVERSIONS=y
+CONFIG_MODULE_SIG=y
+CONFIG_MODULE_SIG_FORCE=y
+CONFIG_MODULE_SIG_SHA512=y
+# CONFIG_BLK_DEV_BSG is not set
+CONFIG_PARTITION_ADVANCED=y
+# CONFIG_IOSCHED_DEADLINE is not set
+CONFIG_ARCH_QCOM=y
+CONFIG_ARCH_MSMFALCON=y
+CONFIG_ARCH_MSMTRITON=y
+CONFIG_ARM_KERNMEM_PERMS=y
+CONFIG_SMP=y
+CONFIG_SCHED_MC=y
+CONFIG_NR_CPUS=8
+CONFIG_ARM_PSCI=y
+CONFIG_PREEMPT=y
+CONFIG_AEABI=y
+CONFIG_HIGHMEM=y
+# CONFIG_HIGHPTE is not set
+CONFIG_CLEANCACHE=y
+CONFIG_CMA=y
+CONFIG_CMA_DEBUGFS=y
+CONFIG_ZSMALLOC=y
+CONFIG_SECCOMP=y
+CONFIG_BUILD_ARM_APPENDED_DTB_IMAGE=y
+# CONFIG_CPU_FREQ_STAT is not set
+CONFIG_CPU_FREQ_GOV_POWERSAVE=y
+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_CPU_IDLE=y
+CONFIG_VFP=y
+CONFIG_NEON=y
+CONFIG_KERNEL_MODE_NEON=y
+# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set
+CONFIG_PM_AUTOSLEEP=y
+CONFIG_PM_WAKELOCKS=y
+CONFIG_PM_WAKELOCKS_LIMIT=0
+# CONFIG_PM_WAKELOCKS_GC is not set
+CONFIG_PM_DEBUG=y
+CONFIG_NET=y
+CONFIG_PACKET=y
+CONFIG_UNIX=y
+CONFIG_XFRM_USER=y
+CONFIG_XFRM_STATISTICS=y
+CONFIG_NET_KEY=y
+CONFIG_INET=y
+CONFIG_IP_ADVANCED_ROUTER=y
+CONFIG_IP_MULTIPLE_TABLES=y
+CONFIG_IP_ROUTE_VERBOSE=y
+CONFIG_IP_PNP=y
+CONFIG_IP_PNP_DHCP=y
+CONFIG_INET_AH=y
+CONFIG_INET_ESP=y
+CONFIG_INET_IPCOMP=y
+# CONFIG_INET_LRO is not set
+CONFIG_IPV6_ROUTER_PREF=y
+CONFIG_IPV6_ROUTE_INFO=y
+CONFIG_IPV6_OPTIMISTIC_DAD=y
+CONFIG_INET6_AH=y
+CONFIG_INET6_ESP=y
+CONFIG_INET6_IPCOMP=y
+CONFIG_IPV6_MIP6=y
+CONFIG_IPV6_MULTIPLE_TABLES=y
+CONFIG_IPV6_SUBTREES=y
+CONFIG_NETFILTER=y
+CONFIG_NF_CONNTRACK=y
+CONFIG_NF_CONNTRACK_SECMARK=y
+CONFIG_NF_CONNTRACK_EVENTS=y
+CONFIG_NF_CT_PROTO_DCCP=y
+CONFIG_NF_CT_PROTO_SCTP=y
+CONFIG_NF_CT_PROTO_UDPLITE=y
+CONFIG_NF_CONNTRACK_AMANDA=y
+CONFIG_NF_CONNTRACK_FTP=y
+CONFIG_NF_CONNTRACK_H323=y
+CONFIG_NF_CONNTRACK_IRC=y
+CONFIG_NF_CONNTRACK_NETBIOS_NS=y
+CONFIG_NF_CONNTRACK_PPTP=y
+CONFIG_NF_CONNTRACK_SANE=y
+CONFIG_NF_CONNTRACK_TFTP=y
+CONFIG_NF_CT_NETLINK=y
+CONFIG_NETFILTER_XT_TARGET_CLASSIFY=y
+CONFIG_NETFILTER_XT_TARGET_CONNMARK=y
+CONFIG_NETFILTER_XT_TARGET_CONNSECMARK=y
+CONFIG_NETFILTER_XT_TARGET_IDLETIMER=y
+CONFIG_NETFILTER_XT_TARGET_HARDIDLETIMER=y
+CONFIG_NETFILTER_XT_TARGET_LOG=y
+CONFIG_NETFILTER_XT_TARGET_MARK=y
+CONFIG_NETFILTER_XT_TARGET_NFLOG=y
+CONFIG_NETFILTER_XT_TARGET_NFQUEUE=y
+CONFIG_NETFILTER_XT_TARGET_NOTRACK=y
+CONFIG_NETFILTER_XT_TARGET_TEE=y
+CONFIG_NETFILTER_XT_TARGET_TPROXY=y
+CONFIG_NETFILTER_XT_TARGET_TRACE=y
+CONFIG_NETFILTER_XT_TARGET_SECMARK=y
+CONFIG_NETFILTER_XT_TARGET_TCPMSS=y
+CONFIG_NETFILTER_XT_MATCH_COMMENT=y
+CONFIG_NETFILTER_XT_MATCH_CONNLIMIT=y
+CONFIG_NETFILTER_XT_MATCH_CONNMARK=y
+CONFIG_NETFILTER_XT_MATCH_CONNTRACK=y
+CONFIG_NETFILTER_XT_MATCH_DSCP=y
+CONFIG_NETFILTER_XT_MATCH_ESP=y
+CONFIG_NETFILTER_XT_MATCH_HASHLIMIT=y
+CONFIG_NETFILTER_XT_MATCH_HELPER=y
+CONFIG_NETFILTER_XT_MATCH_IPRANGE=y
+# CONFIG_NETFILTER_XT_MATCH_L2TP is not set
+CONFIG_NETFILTER_XT_MATCH_LENGTH=y
+CONFIG_NETFILTER_XT_MATCH_LIMIT=y
+CONFIG_NETFILTER_XT_MATCH_MAC=y
+CONFIG_NETFILTER_XT_MATCH_MARK=y
+CONFIG_NETFILTER_XT_MATCH_MULTIPORT=y
+CONFIG_NETFILTER_XT_MATCH_POLICY=y
+CONFIG_NETFILTER_XT_MATCH_PKTTYPE=y
+CONFIG_NETFILTER_XT_MATCH_QTAGUID=y
+CONFIG_NETFILTER_XT_MATCH_QUOTA=y
+CONFIG_NETFILTER_XT_MATCH_QUOTA2=y
+CONFIG_NETFILTER_XT_MATCH_SOCKET=y
+CONFIG_NETFILTER_XT_MATCH_STATE=y
+CONFIG_NETFILTER_XT_MATCH_STATISTIC=y
+CONFIG_NETFILTER_XT_MATCH_STRING=y
+CONFIG_NETFILTER_XT_MATCH_TIME=y
+CONFIG_NETFILTER_XT_MATCH_U32=y
+CONFIG_NF_CONNTRACK_IPV4=y
+CONFIG_IP_NF_IPTABLES=y
+CONFIG_IP_NF_MATCH_AH=y
+CONFIG_IP_NF_MATCH_ECN=y
+CONFIG_IP_NF_MATCH_TTL=y
+CONFIG_IP_NF_FILTER=y
+CONFIG_IP_NF_TARGET_REJECT=y
+CONFIG_IP_NF_NAT=y
+CONFIG_IP_NF_TARGET_MASQUERADE=y
+CONFIG_IP_NF_TARGET_NETMAP=y
+CONFIG_IP_NF_TARGET_REDIRECT=y
+CONFIG_IP_NF_MANGLE=y
+CONFIG_IP_NF_RAW=y
+CONFIG_IP_NF_SECURITY=y
+CONFIG_IP_NF_ARPTABLES=y
+CONFIG_IP_NF_ARPFILTER=y
+CONFIG_IP_NF_ARP_MANGLE=y
+CONFIG_NF_CONNTRACK_IPV6=y
+CONFIG_IP6_NF_IPTABLES=y
+CONFIG_IP6_NF_FILTER=y
+CONFIG_IP6_NF_TARGET_REJECT=y
+CONFIG_IP6_NF_MANGLE=y
+CONFIG_IP6_NF_RAW=y
+CONFIG_BRIDGE_NF_EBTABLES=y
+CONFIG_BRIDGE_EBT_BROUTE=y
+CONFIG_L2TP=y
+CONFIG_L2TP_DEBUGFS=y
+CONFIG_L2TP_V3=y
+CONFIG_L2TP_IP=y
+CONFIG_L2TP_ETH=y
+CONFIG_BRIDGE=y
+CONFIG_NET_SCHED=y
+CONFIG_NET_SCH_HTB=y
+CONFIG_NET_SCH_PRIO=y
+CONFIG_NET_SCH_MULTIQ=y
+CONFIG_NET_SCH_INGRESS=y
+CONFIG_NET_CLS_FW=y
+CONFIG_NET_CLS_U32=y
+CONFIG_CLS_U32_MARK=y
+CONFIG_NET_CLS_FLOW=y
+CONFIG_NET_EMATCH=y
+CONFIG_NET_EMATCH_CMP=y
+CONFIG_NET_EMATCH_NBYTE=y
+CONFIG_NET_EMATCH_U32=y
+CONFIG_NET_EMATCH_META=y
+CONFIG_NET_EMATCH_TEXT=y
+CONFIG_NET_CLS_ACT=y
+CONFIG_NET_ACT_GACT=y
+CONFIG_NET_ACT_MIRRED=y
+CONFIG_NET_ACT_SKBEDIT=y
+CONFIG_DNS_RESOLVER=y
+CONFIG_RMNET_DATA=y
+CONFIG_RMNET_DATA_FC=y
+CONFIG_RMNET_DATA_DEBUG_PKT=y
+CONFIG_SOCKEV_NLMCAST=y
+CONFIG_BT=y
+CONFIG_MSM_BT_POWER=y
+CONFIG_BTFM_SLIM=y
+CONFIG_BTFM_SLIM_WCN3990=y
+CONFIG_CFG80211=y
+CONFIG_CFG80211_INTERNAL_REGDB=y
+# CONFIG_CFG80211_CRDA_SUPPORT is not set
+CONFIG_RFKILL=y
+CONFIG_NFC_NQ=y
+CONFIG_IPC_ROUTER=y
+CONFIG_IPC_ROUTER_SECURITY=y
+CONFIG_FW_LOADER_USER_HELPER_FALLBACK=y
+CONFIG_DMA_CMA=y
+CONFIG_CMA_SIZE_MBYTES=40
+CONFIG_ZRAM=y
+CONFIG_BLK_DEV_LOOP=y
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_SIZE=8192
+CONFIG_QSEECOM=y
+CONFIG_HDCP_QSEECOM=y
+CONFIG_UID_CPUTIME=y
+CONFIG_MSM_ULTRASOUND=y
+CONFIG_SCSI=y
+CONFIG_BLK_DEV_SD=y
+CONFIG_CHR_DEV_SG=y
+CONFIG_CHR_DEV_SCH=y
+CONFIG_SCSI_CONSTANTS=y
+CONFIG_SCSI_LOGGING=y
+CONFIG_SCSI_SCAN_ASYNC=y
+CONFIG_SCSI_UFSHCD=y
+CONFIG_SCSI_UFSHCD_PLATFORM=y
+CONFIG_SCSI_UFS_QCOM=y
+CONFIG_MD=y
+CONFIG_BLK_DEV_DM=y
+CONFIG_DM_CRYPT=y
+CONFIG_DM_REQ_CRYPT=y
+CONFIG_DM_UEVENT=y
+CONFIG_DM_VERITY=y
+CONFIG_NETDEVICES=y
+CONFIG_BONDING=y
+CONFIG_DUMMY=y
+CONFIG_TUN=y
+CONFIG_RNDIS_IPA=y
+CONFIG_PHYLIB=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_WCNSS_MEM_PRE_ALLOC=y
+CONFIG_ATH_CARDS=y
+CONFIG_CLD_LL_CORE=y
+CONFIG_QPNP_POWER_ON=y
+CONFIG_INPUT_EVDEV=y
+CONFIG_INPUT_KEYRESET=y
+CONFIG_KEYBOARD_GPIO=y
+# CONFIG_INPUT_MOUSE is not set
+CONFIG_INPUT_JOYSTICK=y
+CONFIG_INPUT_TOUCHSCREEN=y
+CONFIG_TOUCHSCREEN_SYNAPTICS_DSX_CORE_v21=y
+CONFIG_TOUCHSCREEN_SYNAPTICS_DSX_FW_UPDATE_v21=y
+CONFIG_SECURE_TOUCH=y
+CONFIG_INPUT_MISC=y
+CONFIG_INPUT_HBTP_INPUT=y
+CONFIG_INPUT_KEYCHORD=y
+CONFIG_INPUT_UINPUT=y
+CONFIG_INPUT_GPIO=y
+# CONFIG_SERIO_SERPORT is not set
+# CONFIG_VT is not set
+# CONFIG_LEGACY_PTYS is not set
+# CONFIG_DEVMEM is not set
+# CONFIG_DEVKMEM is not set
+CONFIG_SERIAL_MSM=y
+CONFIG_SERIAL_MSM_HS=y
+CONFIG_SERIAL_MSM_SMD=y
+CONFIG_DIAG_CHAR=y
+CONFIG_HW_RANDOM=y
+CONFIG_HW_RANDOM_MSM_LEGACY=y
+CONFIG_MSM_ADSPRPC=y
+CONFIG_I2C_CHARDEV=y
+CONFIG_I2C_MSM_V2=y
+CONFIG_SLIMBUS=y
+CONFIG_SLIMBUS_MSM_NGD=y
+CONFIG_SOUNDWIRE=y
+CONFIG_SPI=y
+CONFIG_SPI_QUP=y
+CONFIG_SPI_SPIDEV=y
+CONFIG_SPMI=y
+CONFIG_PINCTRL_MSMFALCON=y
+CONFIG_GPIO_SYSFS=y
+CONFIG_GPIO_QPNP_PIN=y
+CONFIG_POWER_RESET=y
+CONFIG_POWER_RESET_QCOM=y
+CONFIG_QCOM_DLOAD_MODE=y
+CONFIG_POWER_RESET_SYSCON=y
+CONFIG_APSS_CORE_EA=y
+CONFIG_MSM_APM=y
+CONFIG_QPNP_SMBCHARGER=y
+CONFIG_SMB135X_CHARGER=y
+CONFIG_SMB1351_USB_CHARGER=y
+CONFIG_MSM_BCL_CTL=y
+CONFIG_MSM_BCL_PERIPHERAL_CTL=y
+CONFIG_BATTERY_BCL=y
+CONFIG_QPNP_SMB2=y
+CONFIG_SMB138X_CHARGER=y
+CONFIG_SENSORS_QPNP_ADC_VOLTAGE=y
+CONFIG_THERMAL=y
+CONFIG_CPU_THERMAL=y
+CONFIG_LIMITS_MONITOR=y
+CONFIG_LIMITS_LITE_HW=y
+CONFIG_THERMAL_MONITOR=y
+CONFIG_THERMAL_TSENS8974=y
+CONFIG_THERMAL_QPNP=y
+CONFIG_THERMAL_QPNP_ADC_TM=y
+CONFIG_QCOM_THERMAL_LIMITS_DCVS=y
+CONFIG_MFD_SPMI_PMIC=y
+CONFIG_MFD_I2C_PMIC=y
+CONFIG_MSM_CDC_PINCTRL=y
+CONFIG_MSM_CDC_SUPPLY=y
+CONFIG_REGULATOR=y
+CONFIG_REGULATOR_FIXED_VOLTAGE=y
+CONFIG_REGULATOR_RPM_SMD=y
+CONFIG_REGULATOR_QPNP=y
+CONFIG_REGULATOR_QPNP_LABIBB=y
+CONFIG_REGULATOR_SPM=y
+CONFIG_REGULATOR_CPR3_HMSS=y
+CONFIG_REGULATOR_CPR3_MMSS=y
+CONFIG_REGULATOR_CPRH_KBSS=y
+CONFIG_REGULATOR_MEM_ACC=y
+CONFIG_REGULATOR_PROXY_CONSUMER=y
+CONFIG_REGULATOR_STUB=y
+CONFIG_MEDIA_SUPPORT=y
+CONFIG_MEDIA_CAMERA_SUPPORT=y
+CONFIG_MEDIA_CONTROLLER=y
+CONFIG_VIDEO_V4L2_SUBDEV_API=y
+CONFIG_VIDEO_ADV_DEBUG=y
+CONFIG_VIDEO_FIXED_MINOR_RANGES=y
+CONFIG_V4L_PLATFORM_DRIVERS=y
+CONFIG_MSM_CAMERA=y
+CONFIG_MSM_CAMERA_DEBUG=y
+CONFIG_MSM_SDE_ROTATOR=y
+CONFIG_QCOM_KGSL=y
+CONFIG_FB=y
+CONFIG_FB_VIRTUAL=y
+CONFIG_FB_MSM=y
+CONFIG_FB_MSM_MDSS=y
+CONFIG_FB_MSM_MDSS_WRITEBACK=y
+CONFIG_FB_MSM_MDSS_HDMI_PANEL=y
+CONFIG_FB_MSM_MDSS_DP_PANEL=y
+CONFIG_FB_MSM_MDSS_XLOG_DEBUG=y
+CONFIG_LOGO=y
+# CONFIG_LOGO_LINUX_MONO is not set
+# CONFIG_LOGO_LINUX_VGA16 is not set
+CONFIG_SOUND=y
+CONFIG_SND=y
+CONFIG_SND_DYNAMIC_MINORS=y
+CONFIG_SND_USB_AUDIO=y
+CONFIG_SND_USB_AUDIO_QMI=y
+CONFIG_SND_SOC=y
+CONFIG_UHID=y
+CONFIG_HID_APPLE=y
+CONFIG_HID_ELECOM=y
+CONFIG_HID_MAGICMOUSE=y
+CONFIG_HID_MICROSOFT=y
+CONFIG_HID_MULTITOUCH=y
+CONFIG_HID_PLANTRONICS=y
+CONFIG_USB=y
+CONFIG_USB_ANNOUNCE_NEW_DEVICES=y
+CONFIG_USB_XHCI_HCD=y
+CONFIG_USB_EHCI_HCD=y
+CONFIG_USB_EHCI_HCD_PLATFORM=y
+CONFIG_USB_OHCI_HCD=y
+CONFIG_USB_OHCI_HCD_PLATFORM=y
+CONFIG_USB_STORAGE=y
+CONFIG_USB_DWC3=y
+CONFIG_USB_ISP1760=y
+CONFIG_USB_ISP1760_HOST_ROLE=y
+CONFIG_USB_PD_POLICY=y
+CONFIG_QPNP_USB_PDPHY=y
+CONFIG_USB_OTG_WAKELOCK=y
+CONFIG_NOP_USB_XCEIV=y
+CONFIG_USB_MSM_SSPHY_QMP=y
+CONFIG_MSM_QUSB_PHY=y
+CONFIG_DUAL_ROLE_USB_INTF=y
+CONFIG_USB_GADGET=y
+CONFIG_USB_GADGET_VBUS_DRAW=500
+CONFIG_USB_CONFIGFS=y
+CONFIG_USB_CONFIGFS_NCM=y
+CONFIG_USB_CONFIGFS_MASS_STORAGE=y
+CONFIG_USB_CONFIGFS_F_FS=y
+CONFIG_USB_CONFIGFS_F_MTP=y
+CONFIG_USB_CONFIGFS_F_PTP=y
+CONFIG_USB_CONFIGFS_F_ACC=y
+CONFIG_USB_CONFIGFS_UEVENT=y
+CONFIG_USB_CONFIGFS_F_MIDI=y
+CONFIG_USB_CONFIGFS_F_HID=y
+CONFIG_USB_CONFIGFS_F_DIAG=y
+CONFIG_USB_CONFIGFS_F_GSI=y
+CONFIG_USB_CONFIGFS_F_CDEV=y
+CONFIG_USB_CONFIGFS_F_QDSS=y
+CONFIG_MMC=y
+CONFIG_MMC_PERF_PROFILING=y
+CONFIG_MMC_PARANOID_SD_INIT=y
+CONFIG_MMC_CLKGATE=y
+CONFIG_MMC_BLOCK_MINORS=32
+CONFIG_MMC_TEST=y
+CONFIG_MMC_SDHCI=y
+CONFIG_MMC_SDHCI_PLTFM=y
+CONFIG_MMC_SDHCI_MSM=y
+CONFIG_NEW_LEDS=y
+CONFIG_LEDS_CLASS=y
+CONFIG_LEDS_QPNP=y
+CONFIG_LEDS_QPNP_FLASH_V2=y
+CONFIG_LEDS_QPNP_WLED=y
+CONFIG_LEDS_SYSCON=y
+CONFIG_LEDS_TRIGGERS=y
+CONFIG_LEDS_TRIGGER_HEARTBEAT=y
+CONFIG_LEDS_TRIGGER_CPU=y
+CONFIG_SWITCH=y
+CONFIG_EDAC=y
+CONFIG_EDAC_MM_EDAC=y
+CONFIG_RTC_CLASS=y
+CONFIG_RTC_DRV_QPNP=y
+CONFIG_DMADEVICES=y
+CONFIG_QCOM_SPS_DMA=y
+CONFIG_UIO=y
+CONFIG_UIO_MSM_SHAREDMEM=y
+CONFIG_STAGING=y
+CONFIG_ASHMEM=y
+CONFIG_ANDROID_TIMED_GPIO=y
+CONFIG_ANDROID_LOW_MEMORY_KILLER=y
+CONFIG_ION=y
+CONFIG_ION_MSM=y
+CONFIG_QPNP_REVID=y
+CONFIG_QPNP_COINCELL=y
+CONFIG_SPS=y
+CONFIG_SPS_SUPPORT_NDP_BAM=y
+CONFIG_IPA=y
+CONFIG_RMNET_IPA=y
+CONFIG_GSI=y
+CONFIG_IPA3=y
+CONFIG_RMNET_IPA3=y
+CONFIG_GPIO_USB_DETECT=y
+CONFIG_SEEMP_CORE=y
+CONFIG_USB_BAM=y
+CONFIG_QCOM_CLK_SMD_RPM=y
+CONFIG_MSM_GCC_FALCON=y
+CONFIG_REMOTE_SPINLOCK_MSM=y
+CONFIG_ARM_SMMU=y
+CONFIG_QCOM_COMMON_LOG=y
+CONFIG_MSM_SMEM=y
+CONFIG_QPNP_HAPTIC=y
+CONFIG_MSM_SMD=y
+CONFIG_MSM_SMD_DEBUG=y
+CONFIG_MSM_GLINK=y
+CONFIG_MSM_GLINK_LOOPBACK_SERVER=y
+CONFIG_MSM_GLINK_SMD_XPRT=y
+CONFIG_MSM_GLINK_SMEM_NATIVE_XPRT=y
+CONFIG_MSM_SPCOM=y
+CONFIG_MSM_SMEM_LOGGING=y
+CONFIG_MSM_SMP2P=y
+CONFIG_MSM_SMP2P_TEST=y
+CONFIG_MSM_QMI_INTERFACE=y
+CONFIG_QCOM_BUS_SCALING=y
+CONFIG_MSM_SERVICE_LOCATOR=y
+CONFIG_QCOM_DCC=y
+CONFIG_MSM_IPC_ROUTER_SMD_XPRT=y
+CONFIG_MSM_SYSMON_GLINK_COMM=y
+CONFIG_MSM_IPC_ROUTER_GLINK_XPRT=y
+CONFIG_MSM_GLINK_PKT=y
+CONFIG_MSM_SPM=y
+CONFIG_QCOM_SCM=y
+CONFIG_QCOM_WATCHDOG_V2=y
+CONFIG_QCOM_IRQ_HELPER=y
+CONFIG_QCOM_MEMORY_DUMP_V2=y
+CONFIG_ICNSS=y
+CONFIG_MSM_GLADIATOR_ERP_V2=y
+CONFIG_PANIC_ON_GLADIATOR_ERROR_V2=y
+CONFIG_MSM_GLADIATOR_HANG_DETECT=y
+CONFIG_MSM_RUN_QUEUE_STATS=y
+CONFIG_MSM_BOOT_STATS=y
+CONFIG_QCOM_CPUSS_DUMP=y
+CONFIG_MSM_QDSP6_APRV2_GLINK=y
+CONFIG_MSM_ADSP_LOADER=y
+CONFIG_MSM_PERFORMANCE=y
+CONFIG_MSM_SUBSYSTEM_RESTART=y
+CONFIG_MSM_PIL=y
+CONFIG_MSM_PIL_SSR_GENERIC=y
+CONFIG_MSM_PIL_MSS_QDSP6V5=y
+CONFIG_TRACER_PKT=y
+CONFIG_QCOM_FORCE_WDOG_BITE_ON_PANIC=y
+CONFIG_MSM_MPM_OF=y
+CONFIG_MSM_EVENT_TIMER=y
+CONFIG_MSM_AVTIMER=y
+CONFIG_QCOM_REMOTEQDSS=y
+CONFIG_MSM_SERVICE_NOTIFIER=y
+CONFIG_MSM_RPM_RBCPR_STATS_V2_LOG=y
+CONFIG_MSM_RPM_LOG=y
+CONFIG_MSM_RPM_STATS_LOG=y
+CONFIG_MEM_SHARE_QMI_SERVICE=y
+CONFIG_QCOM_BIMC_BWMON=y
+CONFIG_ARM_MEMLAT_MON=y
+CONFIG_DEVFREQ_GOV_QCOM_BW_HWMON=y
+CONFIG_DEVFREQ_GOV_MEMLAT=y
+CONFIG_QCOM_DEVFREQ_DEVBW=y
+CONFIG_DEVFREQ_SPDM=y
+CONFIG_PM_DEVFREQ_EVENT=y
+CONFIG_EXTCON=y
+CONFIG_IIO=y
+CONFIG_QCOM_RRADC=y
+CONFIG_QCOM_TADC=y
+CONFIG_PWM=y
+CONFIG_PWM_QPNP=y
+CONFIG_ARM_GIC_V3_ACL=y
+CONFIG_ANDROID=y
+CONFIG_ANDROID_BINDER_IPC=y
+CONFIG_MSM_TZ_LOG=y
+CONFIG_SENSORS_SSC=y
+CONFIG_EXT2_FS=y
+CONFIG_EXT2_FS_XATTR=y
+CONFIG_EXT3_FS=y
+CONFIG_EXT4_FS_SECURITY=y
+CONFIG_EXT4_ENCRYPTION=y
+CONFIG_EXT4_FS_ENCRYPTION=y
+CONFIG_EXT4_DEBUG=y
+CONFIG_FUSE_FS=y
+CONFIG_MSDOS_FS=y
+CONFIG_VFAT_FS=y
+CONFIG_TMPFS=y
+CONFIG_TMPFS_POSIX_ACL=y
+CONFIG_ECRYPT_FS=y
+CONFIG_ECRYPT_FS_MESSAGING=y
+# CONFIG_NETWORK_FILESYSTEMS is not set
+CONFIG_NLS_CODEPAGE_437=y
+CONFIG_NLS_ISO8859_1=y
+CONFIG_PRINTK_TIME=y
+CONFIG_DEBUG_INFO=y
+CONFIG_MAGIC_SYSRQ=y
+CONFIG_PAGE_EXTENSION=y
+CONFIG_LOCKUP_DETECTOR=y
+CONFIG_WQ_WATCHDOG=y
+CONFIG_PANIC_TIMEOUT=5
+# CONFIG_SCHED_DEBUG is not set
+CONFIG_PANIC_ON_SCHED_BUG=y
+CONFIG_PANIC_ON_RT_THROTTLING=y
+CONFIG_SCHEDSTATS=y
+CONFIG_SCHED_STACK_END_CHECK=y
+CONFIG_TIMER_STATS=y
+# CONFIG_DEBUG_PREEMPT is not set
+CONFIG_IPC_LOGGING=y
+CONFIG_FUNCTION_TRACER=y
+CONFIG_TRACER_SNAPSHOT=y
+CONFIG_BLK_DEV_IO_TRACE=y
+CONFIG_CPU_FREQ_SWITCH_PROFILER=y
+CONFIG_PID_IN_CONTEXTIDR=y
+CONFIG_DEBUG_SET_MODULE_RONX=y
+CONFIG_CORESIGHT=y
+CONFIG_CORESIGHT_EVENT=y
+CONFIG_CORESIGHT_LINKS_AND_SINKS=y
+CONFIG_CORESIGHT_QCOM_REPLICATOR=y
+CONFIG_CORESIGHT_STM=y
+CONFIG_CORESIGHT_HWEVENT=y
+CONFIG_CORESIGHT_CTI=y
+CONFIG_CORESIGHT_TPDA=y
+CONFIG_CORESIGHT_TPDM=y
+CONFIG_CORESIGHT_QPDI=y
+CONFIG_CORESIGHT_SOURCE_DUMMY=y
+CONFIG_PFK=y
+CONFIG_SECURITY=y
+CONFIG_SECURITY_SELINUX=y
+CONFIG_SECURITY_SMACK=y
+CONFIG_CRYPTO_ECHAINIV=y
+CONFIG_CRYPTO_XCBC=y
+CONFIG_CRYPTO_MD4=y
+CONFIG_CRYPTO_TWOFISH=y
+CONFIG_CRYPTO_ANSI_CPRNG=y
+CONFIG_CRYPTO_DEV_QCRYPTO=y
+CONFIG_CRYPTO_DEV_QCOM_MSM_QCE=y
+CONFIG_CRYPTO_DEV_QCEDEV=y
+CONFIG_CRYPTO_DEV_OTA_CRYPTO=y
+CONFIG_CRYPTO_DEV_QCE=y
+CONFIG_CRYPTO_DEV_QCOM_ICE=y
+CONFIG_XZ_DEC=y
diff --git a/arch/arm/configs/msmfalcon_defconfig b/arch/arm/configs/msmfalcon_defconfig
index 8039441cc972..06faf702156f 100644
--- a/arch/arm/configs/msmfalcon_defconfig
+++ b/arch/arm/configs/msmfalcon_defconfig
@@ -6,16 +6,22 @@ CONFIG_IRQ_TIME_ACCOUNTING=y
CONFIG_RCU_EXPERT=y
CONFIG_IKCONFIG=y
CONFIG_IKCONFIG_PROC=y
+CONFIG_LOG_CPU_MAX_BUF_SHIFT=17
CONFIG_CGROUPS=y
CONFIG_CGROUP_DEBUG=y
CONFIG_CGROUP_FREEZER=y
+CONFIG_CPUSETS=y
CONFIG_CGROUP_CPUACCT=y
+CONFIG_CGROUP_SCHEDTUNE=y
CONFIG_CGROUP_SCHED=y
CONFIG_RT_GROUP_SCHED=y
CONFIG_SCHED_HMP=y
+CONFIG_SCHED_HMP_CSTATE_AWARE=y
+CONFIG_SCHED_CORE_CTL=y
CONFIG_NAMESPACES=y
# CONFIG_UTS_NS is not set
# CONFIG_PID_NS is not set
+CONFIG_SCHED_TUNE=y
CONFIG_BLK_DEV_INITRD=y
# CONFIG_RD_XZ is not set
# CONFIG_RD_LZO is not set
@@ -32,6 +38,7 @@ CONFIG_MODULE_UNLOAD=y
CONFIG_MODULE_FORCE_UNLOAD=y
CONFIG_MODVERSIONS=y
CONFIG_MODULE_SIG=y
+CONFIG_MODULE_SIG_FORCE=y
CONFIG_MODULE_SIG_SHA512=y
# CONFIG_BLK_DEV_BSG is not set
CONFIG_PARTITION_ADVANCED=y
@@ -39,6 +46,7 @@ CONFIG_PARTITION_ADVANCED=y
CONFIG_ARCH_QCOM=y
CONFIG_ARCH_MSMFALCON=y
CONFIG_ARCH_MSMTRITON=y
+CONFIG_ARM_KERNMEM_PERMS=y
CONFIG_SMP=y
CONFIG_SCHED_MC=y
CONFIG_NR_CPUS=8
@@ -49,6 +57,7 @@ CONFIG_HIGHMEM=y
# CONFIG_HIGHPTE is not set
CONFIG_CLEANCACHE=y
CONFIG_CMA=y
+CONFIG_CMA_DEBUGFS=y
CONFIG_ZSMALLOC=y
CONFIG_SECCOMP=y
CONFIG_BUILD_ARM_APPENDED_DTB_IMAGE=y
@@ -239,6 +248,8 @@ CONFIG_SCSI_UFSHCD_PLATFORM=y
CONFIG_SCSI_UFS_QCOM=y
CONFIG_MD=y
CONFIG_BLK_DEV_DM=y
+CONFIG_DM_CRYPT=y
+CONFIG_DM_REQ_CRYPT=y
CONFIG_DM_UEVENT=y
CONFIG_DM_VERITY=y
CONFIG_NETDEVICES=y
@@ -250,9 +261,15 @@ CONFIG_PHYLIB=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_WCNSS_MEM_PRE_ALLOC=y
CONFIG_ATH_CARDS=y
CONFIG_CLD_LL_CORE=y
@@ -265,6 +282,7 @@ CONFIG_INPUT_JOYSTICK=y
CONFIG_INPUT_TOUCHSCREEN=y
CONFIG_TOUCHSCREEN_SYNAPTICS_DSX_CORE_v21=y
CONFIG_TOUCHSCREEN_SYNAPTICS_DSX_FW_UPDATE_v21=y
+CONFIG_SECURE_TOUCH=y
CONFIG_INPUT_MISC=y
CONFIG_INPUT_HBTP_INPUT=y
CONFIG_INPUT_KEYCHORD=y
@@ -277,6 +295,7 @@ CONFIG_SERIAL_MSM=y
CONFIG_SERIAL_MSM_CONSOLE=y
CONFIG_SERIAL_MSM_HS=y
CONFIG_SERIAL_MSM_SMD=y
+CONFIG_DIAG_CHAR=y
CONFIG_HW_RANDOM=y
CONFIG_HW_RANDOM_MSM_LEGACY=y
CONFIG_MSM_ADSPRPC=y
@@ -289,10 +308,13 @@ CONFIG_SPI=y
CONFIG_SPI_QUP=y
CONFIG_SPI_SPIDEV=y
CONFIG_SPMI=y
-CONFIG_PINCTRL_MSM8998=y
CONFIG_PINCTRL_MSMFALCON=y
CONFIG_GPIO_SYSFS=y
CONFIG_GPIO_QPNP_PIN=y
+CONFIG_POWER_RESET=y
+CONFIG_POWER_RESET_QCOM=y
+CONFIG_QCOM_DLOAD_MODE=y
+CONFIG_POWER_RESET_SYSCON=y
CONFIG_APSS_CORE_EA=y
CONFIG_MSM_APM=y
CONFIG_QPNP_SMBCHARGER=y
@@ -300,10 +322,19 @@ CONFIG_SMB135X_CHARGER=y
CONFIG_SMB1351_USB_CHARGER=y
CONFIG_MSM_BCL_CTL=y
CONFIG_MSM_BCL_PERIPHERAL_CTL=y
+CONFIG_BATTERY_BCL=y
CONFIG_QPNP_SMB2=y
CONFIG_SMB138X_CHARGER=y
CONFIG_SENSORS_QPNP_ADC_VOLTAGE=y
CONFIG_THERMAL=y
+CONFIG_CPU_THERMAL=y
+CONFIG_LIMITS_MONITOR=y
+CONFIG_LIMITS_LITE_HW=y
+CONFIG_THERMAL_MONITOR=y
+CONFIG_THERMAL_TSENS8974=y
+CONFIG_THERMAL_QPNP=y
+CONFIG_THERMAL_QPNP_ADC_TM=y
+CONFIG_QCOM_THERMAL_LIMITS_DCVS=y
CONFIG_MFD_SPMI_PMIC=y
CONFIG_MFD_I2C_PMIC=y
CONFIG_MSM_CDC_PINCTRL=y
@@ -329,7 +360,10 @@ CONFIG_VIDEO_FIXED_MINOR_RANGES=y
CONFIG_V4L_PLATFORM_DRIVERS=y
CONFIG_MSM_CAMERA=y
CONFIG_MSM_CAMERA_DEBUG=y
+CONFIG_MSM_VIDC_V4L2=m
+CONFIG_MSM_VIDC_GOVERNORS=m
CONFIG_MSM_SDE_ROTATOR=y
+CONFIG_MSM_SDE_ROTATOR_EVTLOG_DEBUG=y
CONFIG_QCOM_KGSL=y
CONFIG_FB=y
CONFIG_FB_VIRTUAL=y
@@ -345,10 +379,16 @@ CONFIG_LOGO=y
CONFIG_SOUND=y
CONFIG_SND=y
CONFIG_SND_DYNAMIC_MINORS=y
+CONFIG_SND_USB_AUDIO=y
+CONFIG_SND_USB_AUDIO_QMI=y
CONFIG_SND_SOC=y
CONFIG_UHID=y
CONFIG_HID_APPLE=y
+CONFIG_HID_ELECOM=y
+CONFIG_HID_MAGICMOUSE=y
CONFIG_HID_MICROSOFT=y
+CONFIG_HID_MULTITOUCH=y
+CONFIG_HID_PLANTRONICS=y
CONFIG_USB=y
CONFIG_USB_XHCI_HCD=y
CONFIG_USB_EHCI_HCD=y
@@ -359,6 +399,8 @@ CONFIG_USB_STORAGE=y
CONFIG_USB_DWC3=y
CONFIG_USB_ISP1760=y
CONFIG_USB_ISP1760_HOST_ROLE=y
+CONFIG_USB_PD_POLICY=y
+CONFIG_QPNP_USB_PDPHY=y
CONFIG_USB_OTG_WAKELOCK=y
CONFIG_NOP_USB_XCEIV=y
CONFIG_USB_MSM_SSPHY_QMP=y
@@ -367,12 +409,14 @@ CONFIG_DUAL_ROLE_USB_INTF=y
CONFIG_USB_GADGET=y
CONFIG_USB_GADGET_VBUS_DRAW=500
CONFIG_USB_CONFIGFS=y
+CONFIG_USB_CONFIGFS_NCM=y
CONFIG_USB_CONFIGFS_MASS_STORAGE=y
CONFIG_USB_CONFIGFS_F_FS=y
CONFIG_USB_CONFIGFS_F_MTP=y
CONFIG_USB_CONFIGFS_F_PTP=y
CONFIG_USB_CONFIGFS_F_ACC=y
CONFIG_USB_CONFIGFS_UEVENT=y
+CONFIG_USB_CONFIGFS_F_MIDI=y
CONFIG_USB_CONFIGFS_F_HID=y
CONFIG_USB_CONFIGFS_F_DIAG=y
CONFIG_USB_CONFIGFS_F_GSI=y
@@ -392,6 +436,7 @@ CONFIG_LEDS_CLASS=y
CONFIG_LEDS_QPNP=y
CONFIG_LEDS_QPNP_FLASH_V2=y
CONFIG_LEDS_QPNP_WLED=y
+CONFIG_LEDS_SYSCON=y
CONFIG_LEDS_TRIGGERS=y
CONFIG_LEDS_TRIGGER_HEARTBEAT=y
CONFIG_LEDS_TRIGGER_CPU=y
@@ -420,9 +465,10 @@ CONFIG_GSI=y
CONFIG_IPA3=y
CONFIG_RMNET_IPA3=y
CONFIG_GPIO_USB_DETECT=y
+CONFIG_SEEMP_CORE=y
CONFIG_USB_BAM=y
CONFIG_QCOM_CLK_SMD_RPM=y
-CONFIG_MSM_GCC_FALCON=y
+CONFIG_MSM_GPUCC_FALCON=y
CONFIG_REMOTE_SPINLOCK_MSM=y
CONFIG_ARM_SMMU=y
CONFIG_IOMMU_DEBUG=y
@@ -438,6 +484,7 @@ CONFIG_MSM_GLINK_LOOPBACK_SERVER=y
CONFIG_MSM_GLINK_SMD_XPRT=y
CONFIG_MSM_GLINK_SMEM_NATIVE_XPRT=y
CONFIG_MSM_SPCOM=y
+CONFIG_MSM_SPSS_UTILS=y
CONFIG_MSM_SMEM_LOGGING=y
CONFIG_MSM_SMP2P=y
CONFIG_MSM_SMP2P_TEST=y
@@ -464,6 +511,7 @@ CONFIG_MSM_RUN_QUEUE_STATS=y
CONFIG_MSM_BOOT_STATS=y
CONFIG_QCOM_CPUSS_DUMP=y
CONFIG_MSM_QDSP6_APRV2_GLINK=y
+CONFIG_MSM_ADSP_LOADER=y
CONFIG_MSM_PERFORMANCE=y
CONFIG_MSM_SUBSYSTEM_RESTART=y
CONFIG_MSM_PIL=y
@@ -473,15 +521,25 @@ CONFIG_TRACER_PKT=y
CONFIG_QCOM_FORCE_WDOG_BITE_ON_PANIC=y
CONFIG_MSM_MPM_OF=y
CONFIG_MSM_EVENT_TIMER=y
+CONFIG_MSM_AVTIMER=y
CONFIG_QCOM_REMOTEQDSS=y
CONFIG_MSM_SERVICE_NOTIFIER=y
+CONFIG_MSM_RPM_RBCPR_STATS_V2_LOG=y
+CONFIG_MSM_RPM_LOG=y
+CONFIG_MSM_RPM_STATS_LOG=y
+CONFIG_QCOM_EARLY_RANDOM=y
CONFIG_MEM_SHARE_QMI_SERVICE=y
CONFIG_QCOM_BIMC_BWMON=y
+CONFIG_ARM_MEMLAT_MON=y
CONFIG_DEVFREQ_GOV_QCOM_BW_HWMON=y
+CONFIG_DEVFREQ_GOV_MEMLAT=y
CONFIG_QCOM_DEVFREQ_DEVBW=y
+CONFIG_SPDM_SCM=y
+CONFIG_DEVFREQ_SPDM=y
CONFIG_EXTCON=y
CONFIG_IIO=y
CONFIG_QCOM_RRADC=y
+CONFIG_QCOM_TADC=y
CONFIG_PWM=y
CONFIG_PWM_QPNP=y
CONFIG_ARM_GIC_V3_ACL=y
@@ -493,6 +551,9 @@ CONFIG_EXT2_FS=y
CONFIG_EXT2_FS_XATTR=y
CONFIG_EXT3_FS=y
CONFIG_EXT4_FS_SECURITY=y
+CONFIG_EXT4_ENCRYPTION=y
+CONFIG_EXT4_FS_ENCRYPTION=y
+CONFIG_EXT4_FS_ICE_ENCRYPTION=y
CONFIG_FUSE_FS=y
CONFIG_MSDOS_FS=y
CONFIG_VFAT_FS=y
@@ -509,6 +570,8 @@ CONFIG_DEBUG_INFO=y
CONFIG_PAGE_OWNER=y
CONFIG_PAGE_OWNER_ENABLE_DEFAULT=y
CONFIG_MAGIC_SYSRQ=y
+CONFIG_DEBUG_PAGEALLOC=y
+CONFIG_DEBUG_PAGEALLOC_ENABLE_DEFAULT=y
CONFIG_SLUB_DEBUG_PANIC_ON=y
CONFIG_DEBUG_OBJECTS=y
CONFIG_DEBUG_OBJECTS_FREE=y
@@ -542,8 +605,10 @@ CONFIG_FAULT_INJECTION_DEBUG_FS=y
CONFIG_FAULT_INJECTION_STACKTRACE_FILTER=y
CONFIG_IPC_LOGGING=y
CONFIG_QCOM_RTB=y
+CONFIG_QCOM_RTB_SEPARATE_CPUS=y
CONFIG_FUNCTION_TRACER=y
-CONFIG_TRACER_SNAPSHOT=y
+CONFIG_IRQSOFF_TRACER=y
+CONFIG_PREEMPT_TRACER=y
CONFIG_BLK_DEV_IO_TRACE=y
CONFIG_CPU_FREQ_SWITCH_PROFILER=y
CONFIG_MEMTEST=y
@@ -551,13 +616,19 @@ CONFIG_PANIC_ON_DATA_CORRUPTION=y
CONFIG_PID_IN_CONTEXTIDR=y
CONFIG_DEBUG_SET_MODULE_RONX=y
CONFIG_CORESIGHT=y
+CONFIG_CORESIGHT_EVENT=y
+CONFIG_CORESIGHT_LINKS_AND_SINKS=y
CONFIG_CORESIGHT_REMOTE_ETM=y
CONFIG_CORESIGHT_REMOTE_ETM_DEFAULT_ENABLE=0
+CONFIG_CORESIGHT_QCOM_REPLICATOR=y
+CONFIG_CORESIGHT_STM=y
+CONFIG_CORESIGHT_HWEVENT=y
CONFIG_CORESIGHT_CTI=y
CONFIG_CORESIGHT_TPDA=y
CONFIG_CORESIGHT_TPDM=y
CONFIG_CORESIGHT_QPDI=y
CONFIG_CORESIGHT_SOURCE_DUMMY=y
+CONFIG_PFK=y
CONFIG_SECURITY=y
CONFIG_SECURITY_SELINUX=y
CONFIG_SECURITY_SMACK=y
@@ -571,4 +642,5 @@ CONFIG_CRYPTO_DEV_QCOM_MSM_QCE=y
CONFIG_CRYPTO_DEV_QCEDEV=y
CONFIG_CRYPTO_DEV_OTA_CRYPTO=y
CONFIG_CRYPTO_DEV_QCE=y
+CONFIG_CRYPTO_DEV_QCOM_ICE=y
CONFIG_XZ_DEC=y
diff --git a/arch/arm/mach-qcom/Kconfig b/arch/arm/mach-qcom/Kconfig
index cbccbeb483c9..a4fba1af7744 100644
--- a/arch/arm/mach-qcom/Kconfig
+++ b/arch/arm/mach-qcom/Kconfig
@@ -2,7 +2,7 @@ if ARCH_QCOM
menu "QCOM SoC Type"
config ARCH_MSMFALCON
- bool "Enable Support for Qualcomm MSMFALCON"
+ bool "Enable Support for MSMFALCON"
select CLKDEV_LOOKUP
select HAVE_CLK
select HAVE_CLK_PREPARE
@@ -40,7 +40,7 @@ config ARCH_MSMFALCON
wish to build a kernel that runs on this chipset, say 'N' here.
config ARCH_MSMTRITON
- bool "Enable Support for Qualcomm MSMTRITON"
+ bool "Enable Support for MSMTRITON"
select CLKDEV_LOOKUP
select HAVE_CLK
select HAVE_CLK_PREPARE
diff --git a/arch/arm64/configs/msmfalcon-perf_defconfig b/arch/arm64/configs/msmfalcon-perf_defconfig
index 54925c6bcf4e..1074672d252f 100644
--- a/arch/arm64/configs/msmfalcon-perf_defconfig
+++ b/arch/arm64/configs/msmfalcon-perf_defconfig
@@ -489,7 +489,7 @@ CONFIG_GPIO_USB_DETECT=y
CONFIG_SEEMP_CORE=y
CONFIG_USB_BAM=y
CONFIG_QCOM_CLK_SMD_RPM=y
-CONFIG_MSM_GCC_FALCON=y
+CONFIG_MSM_GPUCC_FALCON=y
CONFIG_REMOTE_SPINLOCK_MSM=y
CONFIG_IOMMU_IO_PGTABLE_FAST=y
CONFIG_ARM_SMMU=y
diff --git a/arch/arm64/configs/msmfalcon_defconfig b/arch/arm64/configs/msmfalcon_defconfig
index 820385a0217a..6d8d9eeab2d5 100644
--- a/arch/arm64/configs/msmfalcon_defconfig
+++ b/arch/arm64/configs/msmfalcon_defconfig
@@ -498,7 +498,7 @@ CONFIG_GPIO_USB_DETECT=y
CONFIG_SEEMP_CORE=y
CONFIG_USB_BAM=y
CONFIG_QCOM_CLK_SMD_RPM=y
-CONFIG_MSM_GCC_FALCON=y
+CONFIG_MSM_GPUCC_FALCON=y
CONFIG_REMOTE_SPINLOCK_MSM=y
CONFIG_IOMMU_IO_PGTABLE_FAST=y
CONFIG_IOMMU_IO_PGTABLE_FAST_SELFTEST=y
diff --git a/arch/arm64/mm/fault.c b/arch/arm64/mm/fault.c
index 55b944a913cb..7326be306618 100644
--- a/arch/arm64/mm/fault.c
+++ b/arch/arm64/mm/fault.c
@@ -283,7 +283,8 @@ static int __kprobes do_page_fault(unsigned long addr, unsigned int esr,
if (esr & ESR_LNX_EXEC) {
vm_flags = VM_EXEC;
- } else if ((esr & ESR_ELx_WNR) && !(esr & ESR_ELx_CM)) {
+ } else if (((esr & ESR_ELx_WNR) && !(esr & ESR_ELx_CM)) ||
+ ((esr & ESR_ELx_CM) && !(mm_flags & FAULT_FLAG_USER))) {
vm_flags = VM_WRITE;
mm_flags |= FAULT_FLAG_WRITE;
}
diff --git a/block/genhd.c b/block/genhd.c
index 817c67c9e45e..82bc52cad1c1 100644
--- a/block/genhd.c
+++ b/block/genhd.c
@@ -831,6 +831,7 @@ static void disk_seqf_stop(struct seq_file *seqf, void *v)
if (iter) {
class_dev_iter_exit(iter);
kfree(iter);
+ seqf->private = NULL;
}
}
diff --git a/block/ioprio.c b/block/ioprio.c
index cc7800e9eb44..01b8116298a1 100644
--- a/block/ioprio.c
+++ b/block/ioprio.c
@@ -150,8 +150,10 @@ static int get_task_ioprio(struct task_struct *p)
if (ret)
goto out;
ret = IOPRIO_PRIO_VALUE(IOPRIO_CLASS_NONE, IOPRIO_NORM);
+ task_lock(p);
if (p->io_context)
ret = p->io_context->ioprio;
+ task_unlock(p);
out:
return ret;
}
diff --git a/drivers/char/diag/diagfwd.c b/drivers/char/diag/diagfwd.c
index 0111b02634c8..876b455624b2 100644
--- a/drivers/char/diag/diagfwd.c
+++ b/drivers/char/diag/diagfwd.c
@@ -1275,6 +1275,7 @@ static uint8_t hdlc_reset;
static void hdlc_reset_timer_start(struct diag_md_session_t *info)
{
+ mutex_lock(&driver->md_session_lock);
if (!hdlc_timer_in_progress) {
hdlc_timer_in_progress = 1;
if (info)
@@ -1284,6 +1285,7 @@ static void hdlc_reset_timer_start(struct diag_md_session_t *info)
mod_timer(&driver->hdlc_reset_timer,
jiffies + msecs_to_jiffies(200));
}
+ mutex_unlock(&driver->md_session_lock);
}
static void hdlc_reset_timer_func(unsigned long data)
diff --git a/drivers/char/diag/diagfwd_peripheral.c b/drivers/char/diag/diagfwd_peripheral.c
index c78a5f4fbe74..9c9d000c94db 100644
--- a/drivers/char/diag/diagfwd_peripheral.c
+++ b/drivers/char/diag/diagfwd_peripheral.c
@@ -989,8 +989,6 @@ void diagfwd_channel_read(struct diagfwd_info *fwd_info)
}
if (fwd_info->buf_1 && !atomic_read(&fwd_info->buf_1->in_busy)) {
- temp_buf = fwd_info->buf_1;
- atomic_set(&temp_buf->in_busy, 1);
if (driver->feature[fwd_info->peripheral].encode_hdlc &&
(fwd_info->type == TYPE_DATA ||
fwd_info->type == TYPE_CMD)) {
@@ -1000,9 +998,11 @@ void diagfwd_channel_read(struct diagfwd_info *fwd_info)
read_buf = fwd_info->buf_1->data;
read_len = fwd_info->buf_1->len;
}
+ if (read_buf) {
+ temp_buf = fwd_info->buf_1;
+ atomic_set(&temp_buf->in_busy, 1);
+ }
} else if (fwd_info->buf_2 && !atomic_read(&fwd_info->buf_2->in_busy)) {
- temp_buf = fwd_info->buf_2;
- atomic_set(&temp_buf->in_busy, 1);
if (driver->feature[fwd_info->peripheral].encode_hdlc &&
(fwd_info->type == TYPE_DATA ||
fwd_info->type == TYPE_CMD)) {
@@ -1012,6 +1012,10 @@ void diagfwd_channel_read(struct diagfwd_info *fwd_info)
read_buf = fwd_info->buf_2->data;
read_len = fwd_info->buf_2->len;
}
+ if (read_buf) {
+ temp_buf = fwd_info->buf_2;
+ atomic_set(&temp_buf->in_busy, 1);
+ }
} else {
pr_debug("diag: In %s, both buffers are empty for p: %d, t: %d\n",
__func__, fwd_info->peripheral, fwd_info->type);
diff --git a/drivers/char/diag/diagfwd_smd.c b/drivers/char/diag/diagfwd_smd.c
index 12069df1224d..f0698f0814d6 100644
--- a/drivers/char/diag/diagfwd_smd.c
+++ b/drivers/char/diag/diagfwd_smd.c
@@ -765,14 +765,13 @@ static int diag_smd_read(void *ctxt, unsigned char *buf, int buf_len)
}
/*
- * In this case don't reset the buffers as there is no need to further
- * read over peripherals. Also release the wake source hold earlier.
+ * Reset the buffers. Also release the wake source hold earlier.
*/
if (atomic_read(&smd_info->diag_state) == 0) {
DIAG_LOG(DIAG_DEBUG_PERIPHERALS,
"%s closing read thread. diag state is closed\n",
smd_info->name);
- diag_ws_release();
+ diagfwd_channel_read_done(smd_info->fwd_ctxt, buf, 0);
return 0;
}
diff --git a/drivers/clk/clk.c b/drivers/clk/clk.c
index 25ab30063072..c1865f9ee8b3 100644
--- a/drivers/clk/clk.c
+++ b/drivers/clk/clk.c
@@ -825,6 +825,9 @@ static void clk_core_unprepare(struct clk_core *core)
if (WARN_ON(core->prepare_count == 0))
return;
+ if (WARN_ON(core->prepare_count == 1 && core->flags & CLK_IS_CRITICAL))
+ return;
+
if (--core->prepare_count > 0)
return;
@@ -940,6 +943,9 @@ static void clk_core_disable(struct clk_core *core)
if (WARN_ON(core->enable_count == 0))
return;
+ if (WARN_ON(core->enable_count == 1 && core->flags & CLK_IS_CRITICAL))
+ return;
+
if (--core->enable_count > 0)
return;
@@ -3121,6 +3127,16 @@ static int __clk_init(struct device *dev, struct clk *clk_user)
if (core->ops->init)
core->ops->init(core->hw);
+ if (core->flags & CLK_IS_CRITICAL) {
+ unsigned long flags;
+
+ clk_core_prepare(core);
+
+ flags = clk_enable_lock();
+ clk_core_enable(core);
+ clk_enable_unlock(flags);
+ }
+
kref_init(&core->ref);
out:
clk_prepare_unlock();
@@ -3853,6 +3869,41 @@ static int parent_ready(struct device_node *np)
}
/**
+ * of_clk_detect_critical() - set CLK_IS_CRITICAL flag from Device Tree
+ * @np: Device node pointer associated with clock provider
+ * @index: clock index
+ * @flags: pointer to clk_core->flags
+ *
+ * Detects if the clock-critical property exists and, if so, sets the
+ * corresponding CLK_IS_CRITICAL flag.
+ *
+ * Do not use this function. It exists only for legacy Device Tree
+ * bindings, such as the one-clock-per-node style that are outdated.
+ * Those bindings typically put all clock data into .dts and the Linux
+ * driver has no clock data, thus making it impossible to set this flag
+ * correctly from the driver. Only those drivers may call
+ * of_clk_detect_critical from their setup functions.
+ *
+ * Return: error code or zero on success
+ */
+int of_clk_detect_critical(struct device_node *np,
+ int index, unsigned long *flags)
+{
+ struct property *prop;
+ const __be32 *cur;
+ uint32_t idx;
+
+ if (!np || !flags)
+ return -EINVAL;
+
+ of_property_for_each_u32(np, "clock-critical", prop, cur, idx)
+ if (index == idx)
+ *flags |= CLK_IS_CRITICAL;
+
+ return 0;
+}
+
+/**
* of_clk_init() - Scan and init clock providers from the DT
* @matches: array of compatible values and init functions for providers.
*
diff --git a/drivers/clk/msm/clock-osm.c b/drivers/clk/msm/clock-osm.c
index b9e977088126..9ce6a1430250 100644
--- a/drivers/clk/msm/clock-osm.c
+++ b/drivers/clk/msm/clock-osm.c
@@ -85,7 +85,9 @@ enum clk_osm_trace_packet_id {
#define OSM_TABLE_SIZE 40
#define MAX_CLUSTER_CNT 2
-#define MAX_CONFIG 4
+#define CORE_COUNT_VAL(val) ((val & GENMASK(18, 16)) >> 16)
+#define SINGLE_CORE 1
+#define MAX_CORE_COUNT 4
#define LLM_SW_OVERRIDE_CNT 3
#define ENABLE_REG 0x1004
@@ -357,6 +359,8 @@ struct clk_osm {
u32 irq;
u32 apm_crossover_vc;
u32 apm_threshold_vc;
+ u32 mem_acc_crossover_vc;
+ u32 mem_acc_threshold_vc;
u32 cycle_counter_reads;
u32 cycle_counter_delay;
u32 cycle_counter_factor;
@@ -642,11 +646,25 @@ static long clk_osm_round_rate(struct clk *c, unsigned long rate)
static int clk_osm_search_table(struct osm_entry *table, int entries, long rate)
{
- int i;
+ int quad_core_index, single_core_index = 0;
+ int core_count;
+
+ for (quad_core_index = 0; quad_core_index < entries;
+ quad_core_index++) {
+ core_count =
+ CORE_COUNT_VAL(table[quad_core_index].freq_data);
+ if (rate == table[quad_core_index].frequency &&
+ core_count == SINGLE_CORE) {
+ single_core_index = quad_core_index;
+ continue;
+ }
+ if (rate == table[quad_core_index].frequency &&
+ core_count == MAX_CORE_COUNT)
+ return quad_core_index;
+ }
+ if (single_core_index)
+ return single_core_index;
- for (i = 0; i < entries; i++)
- if (rate == table[i].frequency)
- return i;
return -EINVAL;
}
@@ -829,6 +847,8 @@ static void clk_osm_print_osm_table(struct clk_osm *c)
}
pr_debug("APM threshold corner=%d, crossover corner=%d\n",
c->apm_threshold_vc, c->apm_crossover_vc);
+ pr_debug("MEM-ACC threshold corner=%d, crossover corner=%d\n",
+ c->mem_acc_threshold_vc, c->mem_acc_crossover_vc);
}
static int clk_osm_get_lut(struct platform_device *pdev,
@@ -839,8 +859,10 @@ static int clk_osm_get_lut(struct platform_device *pdev,
int prop_len, total_elems, num_rows, i, j, k;
int rc = 0;
u32 *array;
+ u32 *fmax_temp;
u32 data;
bool last_entry = false;
+ unsigned long abs_fmax = 0;
if (!of_find_property(of, prop_name, &prop_len)) {
dev_err(&pdev->dev, "missing %s\n", prop_name);
@@ -855,9 +877,9 @@ static int clk_osm_get_lut(struct platform_device *pdev,
num_rows = total_elems / NUM_FIELDS;
- clk->fmax = devm_kzalloc(&pdev->dev, num_rows * sizeof(unsigned long),
- GFP_KERNEL);
- if (!clk->fmax)
+ fmax_temp = devm_kzalloc(&pdev->dev, num_rows * sizeof(unsigned long),
+ GFP_KERNEL);
+ if (!fmax_temp)
return -ENOMEM;
array = devm_kzalloc(&pdev->dev, prop_len, GFP_KERNEL);
@@ -893,18 +915,33 @@ static int clk_osm_get_lut(struct platform_device *pdev,
c->osm_table[j].spare_data);
data = (array[i + FREQ_DATA] & GENMASK(18, 16)) >> 16;
- if (!last_entry) {
- clk->fmax[k] = array[i];
+ if (!last_entry && data == MAX_CORE_COUNT) {
+ fmax_temp[k] = array[i];
k++;
}
if (i < total_elems - NUM_FIELDS)
i += NUM_FIELDS;
- else
+ else {
+ abs_fmax = array[i];
last_entry = true;
+ }
+ }
+
+ fmax_temp[k++] = abs_fmax;
+ clk->fmax = devm_kzalloc(&pdev->dev, k * sizeof(unsigned long),
+ GFP_KERNEL);
+ if (!clk->fmax) {
+ rc = -ENOMEM;
+ goto exit;
}
+
+ for (i = 0; i < k; i++)
+ clk->fmax[i] = fmax_temp[i];
+
clk->num_fmax = k;
exit:
+ devm_kfree(&pdev->dev, fmax_temp);
devm_kfree(&pdev->dev, array);
return rc;
}
@@ -1490,20 +1527,27 @@ static int clk_osm_resolve_open_loop_voltages(struct clk_osm *c)
}
static int clk_osm_resolve_crossover_corners(struct clk_osm *c,
- struct platform_device *pdev)
+ struct platform_device *pdev,
+ const char *mem_acc_prop)
{
struct regulator *regulator = c->vdd_reg;
- int count, vc, i, threshold, rc = 0;
+ int count, vc, i, apm_threshold;
+ int mem_acc_threshold = 0;
+ int rc = 0;
u32 corner_volt;
rc = of_property_read_u32(pdev->dev.of_node,
"qcom,apm-threshold-voltage",
- &threshold);
+ &apm_threshold);
if (rc) {
pr_info("qcom,apm-threshold-voltage property not specified\n");
return rc;
}
+ if (mem_acc_prop)
+ of_property_read_u32(pdev->dev.of_node, mem_acc_prop,
+ &mem_acc_threshold);
+
/* Determine crossover virtual corner */
count = regulator_count_voltages(regulator);
if (count < 0) {
@@ -1511,19 +1555,49 @@ static int clk_osm_resolve_crossover_corners(struct clk_osm *c,
return count;
}
- c->apm_crossover_vc = count - 1;
+ /*
+ * CPRh corners (in hardware) are ordered:
+ * 0 - n-1 - for n functional corners
+ * APM crossover - required for OSM
+ * [MEM ACC crossover] - optional
+ *
+ * 'count' corresponds to the total number of corners including n
+ * functional corners, the APM crossover corner, and potentially the
+ * MEM ACC cross over corner.
+ */
+ if (mem_acc_threshold) {
+ c->apm_crossover_vc = count - 2;
+ c->mem_acc_crossover_vc = count - 1;
+ } else {
+ c->apm_crossover_vc = count - 1;
+ }
- /* Determine threshold virtual corner */
+ /* Determine APM threshold virtual corner */
for (i = 0; i < OSM_TABLE_SIZE; i++) {
vc = c->osm_table[i].virtual_corner + 1;
corner_volt = regulator_list_corner_voltage(regulator, vc);
- if (corner_volt >= threshold) {
+ if (corner_volt >= apm_threshold) {
c->apm_threshold_vc = c->osm_table[i].virtual_corner;
break;
}
}
+ /* Determine MEM ACC threshold virtual corner */
+ if (mem_acc_threshold) {
+ for (i = 0; i < OSM_TABLE_SIZE; i++) {
+ vc = c->osm_table[i].virtual_corner + 1;
+ corner_volt
+ = regulator_list_corner_voltage(regulator, vc);
+
+ if (corner_volt >= mem_acc_threshold) {
+ c->mem_acc_threshold_vc
+ = c->osm_table[i].virtual_corner;
+ break;
+ }
+ }
+ }
+
return 0;
}
@@ -1822,6 +1896,7 @@ static void clk_osm_program_mem_acc_regs(struct clk_osm *c)
{
int i, curr_level, j = 0;
int mem_acc_level_map[MAX_MEM_ACC_LEVELS] = {0, 0, 0};
+ int threshold_vc[4];
curr_level = c->osm_table[0].spare_data;
for (i = 0; i < c->num_entries; i++) {
@@ -1829,7 +1904,8 @@ static void clk_osm_program_mem_acc_regs(struct clk_osm *c)
break;
if (c->osm_table[i].spare_data != curr_level) {
- mem_acc_level_map[j++] = i - 1;
+ mem_acc_level_map[j++]
+ = c->osm_table[i].virtual_corner - 1;
curr_level = c->osm_table[i].spare_data;
}
}
@@ -1855,14 +1931,37 @@ static void clk_osm_program_mem_acc_regs(struct clk_osm *c)
clk_osm_write_reg(c, c->apcs_mem_acc_cfg[i],
MEM_ACC_SEQ_REG_CFG_START(i));
} else {
+ if (c->mem_acc_crossover_vc)
+ scm_io_write(c->pbases[OSM_BASE] + SEQ_REG(88),
+ c->mem_acc_crossover_vc);
+
+ threshold_vc[0] = mem_acc_level_map[0];
+ threshold_vc[1] = mem_acc_level_map[0] + 1;
+ threshold_vc[2] = mem_acc_level_map[1];
+ threshold_vc[3] = mem_acc_level_map[1] + 1;
+
+ /*
+ * Use dynamic MEM ACC threshold voltage based value for the
+ * highest MEM ACC threshold if it is specified instead of the
+ * fixed mapping in the LUT.
+ */
+ if (c->mem_acc_threshold_vc) {
+ threshold_vc[2] = c->mem_acc_threshold_vc - 1;
+ threshold_vc[3] = c->mem_acc_threshold_vc;
+ if (threshold_vc[1] >= threshold_vc[2])
+ threshold_vc[1] = threshold_vc[2] - 1;
+ if (threshold_vc[0] >= threshold_vc[1])
+ threshold_vc[0] = threshold_vc[1] - 1;
+ }
+
scm_io_write(c->pbases[OSM_BASE] + SEQ_REG(55),
- mem_acc_level_map[0]);
+ threshold_vc[0]);
scm_io_write(c->pbases[OSM_BASE] + SEQ_REG(56),
- mem_acc_level_map[0] + 1);
+ threshold_vc[1]);
scm_io_write(c->pbases[OSM_BASE] + SEQ_REG(57),
- mem_acc_level_map[1]);
+ threshold_vc[2]);
scm_io_write(c->pbases[OSM_BASE] + SEQ_REG(58),
- mem_acc_level_map[1] + 1);
+ threshold_vc[3]);
/* SEQ_REG(49) = SEQ_REG(28) init by TZ */
}
@@ -3076,13 +3175,14 @@ static int cpu_clock_osm_driver_probe(struct platform_device *pdev)
return rc;
}
- rc = clk_osm_resolve_crossover_corners(&pwrcl_clk, pdev);
+ rc = clk_osm_resolve_crossover_corners(&pwrcl_clk, pdev, NULL);
if (rc)
dev_info(&pdev->dev, "No APM crossover corner programmed\n");
- rc = clk_osm_resolve_crossover_corners(&perfcl_clk, pdev);
+ rc = clk_osm_resolve_crossover_corners(&perfcl_clk, pdev,
+ "qcom,perfcl-apcs-mem-acc-threshold-voltage");
if (rc)
- dev_info(&pdev->dev, "No APM crossover corner programmed\n");
+ dev_info(&pdev->dev, "No MEM-ACC crossover corner programmed\n");
clk_osm_setup_cycle_counters(&pwrcl_clk);
clk_osm_setup_cycle_counters(&perfcl_clk);
diff --git a/drivers/clk/msm/clock.h b/drivers/clk/msm/clock.h
index b7aa946f1931..6d286a5d2e5b 100644
--- a/drivers/clk/msm/clock.h
+++ b/drivers/clk/msm/clock.h
@@ -41,6 +41,8 @@ extern struct list_head orphan_clk_list;
#if defined(CONFIG_DEBUG_FS) && defined(CONFIG_COMMON_CLK_MSM)
int clock_debug_register(struct clk *clk);
void clock_debug_print_enabled(void);
+#elif defined(CONFIG_DEBUG_FS) && defined(CONFIG_COMMON_CLK_QCOM)
+void clock_debug_print_enabled(void);
#else
static inline int clock_debug_register(struct clk *unused)
{
diff --git a/drivers/clk/msm/mdss/mdss-hdmi-pll-8998.c b/drivers/clk/msm/mdss/mdss-hdmi-pll-8998.c
index c74162ae8148..029f779979c7 100644
--- a/drivers/clk/msm/mdss/mdss-hdmi-pll-8998.c
+++ b/drivers/clk/msm/mdss/mdss-hdmi-pll-8998.c
@@ -21,6 +21,7 @@
#include <linux/clk/msm-clk.h>
#include <linux/clk/msm-clock-generic.h>
#include <dt-bindings/clock/msm-clocks-8998.h>
+#include <linux/math64.h>
#include "mdss-pll.h"
#include "mdss-hdmi-pll.h"
@@ -29,6 +30,7 @@
#define _R(x, y) MDSS_PLL_REG_R(x, y)
/* PLL REGISTERS */
+#define FREQ_UPDATE (0x008)
#define BIAS_EN_CLKBUFLR_EN (0x034)
#define CLK_ENABLE1 (0x038)
#define SYS_CLK_CTRL (0x03C)
@@ -77,9 +79,12 @@
#define PHY_CMN_CTRL (0x68)
#define PHY_STATUS (0xB4)
+#define HDMI_VCO_MAX_FREQ 12000000000
+#define HDMI_VCO_MIN_FREQ 8000000000
#define HDMI_BIT_CLK_TO_PIX_CLK_RATIO 10
#define HDMI_MHZ_TO_HZ 1000000
#define HDMI_HZ_TO_MHZ 1000000
+#define HDMI_KHZ_TO_HZ 1000
#define HDMI_REF_CLOCK_MHZ 19.2
#define HDMI_REF_CLOCK_HZ (HDMI_REF_CLOCK_MHZ * 1000000)
#define HDMI_VCO_MIN_RATE_HZ 25000000
@@ -109,7 +114,7 @@ struct hdmi_8998_reg_cfg {
u32 core_clk_en;
u32 coreclk_div_mode0;
u32 phy_mode;
- u32 vco_freq;
+ u64 vco_freq;
u32 hsclk_divsel;
u32 vco_ratio;
u32 ssc_en_center;
@@ -142,17 +147,19 @@ static void hdmi_8998_get_div(struct hdmi_8998_reg_cfg *cfg, unsigned long pclk)
u32 const band_list[] = {0, 1, 2, 3};
u32 const sz_ratio = ARRAY_SIZE(ratio_list);
u32 const sz_band = ARRAY_SIZE(band_list);
- u32 const min_freq = 8000, max_freq = 12000;
u32 const cmp_cnt = 1024;
u32 const th_min = 500, th_max = 1000;
- u64 bit_clk = ((u64)pclk) * HDMI_BIT_CLK_TO_PIX_CLK_RATIO;
u32 half_rate_mode = 0;
- u32 freq_optimal, list_elements;
+ u32 list_elements;
int optimal_index;
u32 i, j, k;
- u32 freq_list[sz_ratio * sz_band];
u32 found_hsclk_divsel = 0, found_vco_ratio;
- u32 found_tx_band_sel, found_vco_freq;
+ u32 found_tx_band_sel;
+ u64 const min_freq = HDMI_VCO_MIN_FREQ, max_freq = HDMI_VCO_MAX_FREQ;
+ u64 const bit_clk = ((u64)pclk) * HDMI_BIT_CLK_TO_PIX_CLK_RATIO;
+ u64 freq_list[sz_ratio * sz_band];
+ u64 found_vco_freq;
+ u64 freq_optimal;
find_optimal_index:
freq_optimal = max_freq;
@@ -164,7 +171,6 @@ find_optimal_index:
u64 freq = div_u64(bit_clk, (1 << half_rate_mode));
freq *= (ratio_list[i] * (1 << band_list[j]));
- do_div(freq, (u64) HDMI_MHZ_TO_HZ);
freq_list[list_elements++] = freq;
}
}
@@ -172,23 +178,23 @@ find_optimal_index:
for (k = 0; k < ARRAY_SIZE(freq_list); k++) {
u32 const clks_pll_div = 2, core_clk_div = 5;
u32 const rng1 = 16, rng2 = 8;
- u32 core_clk, rvar1;
u32 th1, th2;
+ u64 core_clk, rvar1, rem;
core_clk = (((freq_list[k] /
ratio_list[k / sz_band]) /
clks_pll_div) / core_clk_div);
- rvar1 = HDMI_REF_CLOCK_HZ / cmp_cnt;
- rvar1 *= rng1;
- rvar1 /= core_clk;
-
+ rvar1 = HDMI_REF_CLOCK_HZ * rng1 * HDMI_MHZ_TO_HZ;
+ rvar1 = div64_u64_rem(rvar1, (cmp_cnt * core_clk), &rem);
+ if (rem > ((cmp_cnt * core_clk) >> 1))
+ rvar1++;
th1 = rvar1;
- rvar1 = HDMI_REF_CLOCK_HZ / cmp_cnt;
- rvar1 *= rng2;
- rvar1 /= core_clk;
-
+ rvar1 = HDMI_REF_CLOCK_HZ * rng2 * HDMI_MHZ_TO_HZ;
+ rvar1 = div64_u64_rem(rvar1, (cmp_cnt * core_clk), &rem);
+ if (rem > ((cmp_cnt * core_clk) >> 1))
+ rvar1++;
th2 = rvar1;
if (freq_list[k] >= min_freq &&
@@ -257,7 +263,7 @@ find_optimal_index:
break;
};
- pr_debug("found_vco_freq=%d\n", found_vco_freq);
+ pr_debug("found_vco_freq=%llu\n", found_vco_freq);
pr_debug("found_hsclk_divsel=%d\n", found_hsclk_divsel);
pr_debug("found_vco_ratio=%d\n", found_vco_ratio);
pr_debug("found_tx_band_sel=%d\n", found_tx_band_sel);
@@ -278,9 +284,9 @@ static int hdmi_8998_config_phy(unsigned long rate,
u64 const mid_freq_bit_clk_threshold = 750000000;
int rc = 0;
u64 fdata, tmds_clk;
- u64 pll_div = 4 * HDMI_REF_CLOCK_HZ;
+ u32 pll_div = 4 * HDMI_REF_CLOCK_HZ;
u64 bclk;
- u64 vco_freq_mhz;
+ u64 vco_freq;
u64 hsclk_sel, dec_start, div_frac_start;
u64 rem;
u64 cpctrl, rctrl, cctrl;
@@ -302,15 +308,15 @@ static int hdmi_8998_config_phy(unsigned long rate,
hdmi_8998_get_div(cfg, rate);
- vco_freq_mhz = cfg->vco_freq * (u64) HDMI_HZ_TO_MHZ;
+ vco_freq = cfg->vco_freq;
fdata = cfg->vco_freq;
do_div(fdata, cfg->vco_ratio);
hsclk_sel = cfg->hsclk_divsel;
- dec_start = vco_freq_mhz;
+ dec_start = vco_freq;
do_div(dec_start, pll_div);
- div_frac_start = vco_freq_mhz * (1 << 20);
+ div_frac_start = vco_freq * (1 << 20);
rem = do_div(div_frac_start, pll_div);
div_frac_start -= (dec_start * (1 << 20));
if (rem > (pll_div >> 1))
@@ -330,19 +336,19 @@ static int hdmi_8998_config_phy(unsigned long rate,
integloop_gain = ((div_frac_start != 0) ||
(gen_ssc == true)) ? 0x3F : 0xC4;
- integloop_gain <<= digclk_divsel;
+ integloop_gain <<= (digclk_divsel == 2 ? 1 : 0);
integloop_gain = (integloop_gain <= 2046 ? integloop_gain : 0x7FE);
cmp_rng = gen_ssc ? 0x40 : 0x10;
pll_cmp = cmp_cnt * fdata;
- rem = do_div(pll_cmp, (u64)(HDMI_REF_CLOCK_MHZ * 10));
- if (rem > ((u64)(HDMI_REF_CLOCK_MHZ * 10) >> 1))
+ rem = do_div(pll_cmp, (u32)(HDMI_REF_CLOCK_HZ * 10));
+ if (rem > ((u64)(HDMI_REF_CLOCK_HZ * 10) >> 1))
pll_cmp++;
pll_cmp = pll_cmp - 1;
- pr_debug("VCO_FREQ = %u\n", cfg->vco_freq);
+ pr_debug("VCO_FREQ = %llu\n", cfg->vco_freq);
pr_debug("FDATA = %llu\n", fdata);
pr_debug("DEC_START = %llu\n", dec_start);
pr_debug("DIV_FRAC_START = %llu\n", div_frac_start);
@@ -609,49 +615,6 @@ static int hdmi_8998_phy_ready_status(struct mdss_pll_resources *io)
return rc;
}
-static int hdmi_8998_vco_set_rate(struct clk *c, unsigned long rate)
-{
- int rc = 0;
- struct hdmi_pll_vco_clk *vco = to_hdmi_vco_clk(c);
- struct mdss_pll_resources *io = vco->priv;
-
- rc = mdss_pll_resource_enable(io, true);
- if (rc) {
- pr_err("pll resource enable failed, rc=%d\n", rc);
- return rc;
- }
-
- if (io->pll_on)
- goto error;
-
- rc = hdmi_8998_pll_set_clk_rate(c, rate);
- if (rc) {
- pr_err("failed to set clk rate, rc=%d\n", rc);
- goto error;
- }
-
- vco->rate = rate;
- vco->rate_set = true;
-
-error:
- (void)mdss_pll_resource_enable(io, false);
-
- return rc;
-}
-
-static long hdmi_8998_vco_round_rate(struct clk *c, unsigned long rate)
-{
- unsigned long rrate = rate;
- struct hdmi_pll_vco_clk *vco = to_hdmi_vco_clk(c);
-
- if (rate < vco->min_rate)
- rrate = vco->min_rate;
- if (rate > vco->max_rate)
- rrate = vco->max_rate;
-
- return rrate;
-}
-
static int hdmi_8998_pll_enable(struct clk *c)
{
int rc = 0;
@@ -700,6 +663,151 @@ static int hdmi_8998_pll_enable(struct clk *c)
return rc;
}
+/*
+ * Get the clock range allowed in atomic update. If clock rate
+ * goes beyond this range, a full tear down is required to set
+ * the new pixel clock.
+ */
+static int hdmi_8998_vco_get_lock_range(struct clk *c,
+ unsigned long pixel_clk)
+{
+ const u32 rng = 64, cmp_cnt = 1024;
+ const u32 coreclk_div = 5, clks_pll_divsel = 2;
+ u32 vco_freq, vco_ratio, ppm_range;
+ struct hdmi_8998_reg_cfg cfg = {0};
+
+ pr_debug("rate=%ld\n", pixel_clk);
+
+ hdmi_8998_get_div(&cfg, pixel_clk);
+ if (cfg.vco_ratio <= 0 || cfg.vco_freq <= 0) {
+ pr_err("couldn't get post div\n");
+ return -EINVAL;
+ }
+
+ do_div(cfg.vco_freq, HDMI_KHZ_TO_HZ * HDMI_KHZ_TO_HZ);
+
+ vco_freq = (u32) cfg.vco_freq;
+ vco_ratio = (u32) cfg.vco_ratio;
+
+ pr_debug("freq %d, ratio %d\n", vco_freq, vco_ratio);
+
+ ppm_range = (rng * HDMI_REF_CLOCK_HZ) / cmp_cnt;
+ ppm_range /= vco_freq / vco_ratio;
+ ppm_range *= coreclk_div * clks_pll_divsel;
+
+ pr_debug("ppm range: %d\n", ppm_range);
+
+ return ppm_range;
+}
+
+static int hdmi_8998_vco_rate_atomic_update(struct clk *c,
+ unsigned long rate)
+{
+ struct hdmi_pll_vco_clk *vco = to_hdmi_vco_clk(c);
+ struct mdss_pll_resources *io = vco->priv;
+ void __iomem *pll;
+ struct hdmi_8998_reg_cfg cfg = {0};
+ int rc = 0;
+
+ rc = hdmi_8998_config_phy(rate, &cfg);
+ if (rc) {
+ pr_err("rate calculation failed\n, rc=%d", rc);
+ goto end;
+ }
+
+ pll = io->pll_base;
+
+ _W(pll, DEC_START_MODE0, cfg.dec_start_mode0);
+ _W(pll, DIV_FRAC_START1_MODE0, cfg.div_frac_start1_mode0);
+ _W(pll, DIV_FRAC_START2_MODE0, cfg.div_frac_start2_mode0);
+ _W(pll, DIV_FRAC_START3_MODE0, cfg.div_frac_start3_mode0);
+
+ _W(pll, FREQ_UPDATE, 0x01);
+ _W(pll, FREQ_UPDATE, 0x00);
+
+ pr_debug("updated to rate %ld\n", rate);
+end:
+ return rc;
+}
+
+static int hdmi_8998_vco_set_rate(struct clk *c, unsigned long rate)
+{
+ struct hdmi_pll_vco_clk *vco = to_hdmi_vco_clk(c);
+ struct mdss_pll_resources *io = vco->priv;
+ unsigned int set_power_dwn = 0;
+ bool atomic_update = false;
+ int pll_lock_range = 0;
+ int rc = 0;
+
+ rc = mdss_pll_resource_enable(io, true);
+ if (rc) {
+ pr_err("pll resource enable failed, rc=%d\n", rc);
+ return rc;
+ }
+
+ pr_debug("rate %ld, vco_rate %ld\n", rate, vco->rate);
+
+ if (_R(io->pll_base, C_READY_STATUS) & BIT(0) &&
+ _R(io->phy_base, PHY_STATUS) & BIT(0)) {
+ pll_lock_range = hdmi_8998_vco_get_lock_range(c, vco->rate);
+
+ if (pll_lock_range > 0 && vco->rate) {
+ u32 range_limit;
+
+ range_limit = pll_lock_range *
+ (vco->rate / HDMI_KHZ_TO_HZ);
+ range_limit /= HDMI_KHZ_TO_HZ;
+
+ pr_debug("range limit %d\n", range_limit);
+
+ if (abs(rate - vco->rate) < range_limit)
+ atomic_update = true;
+ }
+ }
+
+ if (io->pll_on && !atomic_update)
+ set_power_dwn = 1;
+
+ if (atomic_update)
+ rc = hdmi_8998_vco_rate_atomic_update(c, rate);
+ else
+ rc = hdmi_8998_pll_set_clk_rate(c, rate);
+
+ if (rc) {
+ pr_err("failed to set clk rate\n");
+ goto error;
+ }
+
+ if (set_power_dwn) {
+ rc = hdmi_8998_pll_enable(c);
+ if (rc) {
+ pr_err("failed to enable pll, rc=%d\n", rc);
+ goto error;
+ }
+ }
+
+ vco->rate = rate;
+ vco->rate_set = true;
+
+error:
+ (void)mdss_pll_resource_enable(io, false);
+
+ return rc;
+}
+
+static long hdmi_8998_vco_round_rate(struct clk *c, unsigned long rate)
+{
+ unsigned long rrate = rate;
+ struct hdmi_pll_vco_clk *vco = to_hdmi_vco_clk(c);
+
+ if (rate < vco->min_rate)
+ rrate = vco->min_rate;
+ if (rate > vco->max_rate)
+ rrate = vco->max_rate;
+
+ return rrate;
+}
+
static int hdmi_8998_vco_prepare(struct clk *c)
{
struct hdmi_pll_vco_clk *vco = to_hdmi_vco_clk(c);
diff --git a/drivers/clk/qcom/Kconfig b/drivers/clk/qcom/Kconfig
index e39686ca4feb..36ab5cf68740 100644
--- a/drivers/clk/qcom/Kconfig
+++ b/drivers/clk/qcom/Kconfig
@@ -173,6 +173,16 @@ config MSM_GPUCC_FALCON
Say Y if you want to support graphics controller devices which will
be required to enable those device.
+config MSM_MMCC_FALCON
+ tristate "MSMFALCON Multimedia Clock Controller"
+ select MSM_GCC_FALCON
+ depends on COMMON_CLK_QCOM
+ help
+ Support for the multimedia clock controller on Qualcomm Technologies, Inc
+ MSMfalcon devices.
+ Say Y if you want to support multimedia devices such as display,
+ video encode/decode, camera, etc.
+
config QCOM_HFPLL
tristate "High-Frequency PLL (HFPLL) Clock Controller"
depends on COMMON_CLK_QCOM
diff --git a/drivers/clk/qcom/Makefile b/drivers/clk/qcom/Makefile
index adebefd63e71..595254f69db1 100644
--- a/drivers/clk/qcom/Makefile
+++ b/drivers/clk/qcom/Makefile
@@ -30,6 +30,7 @@ obj-$(CONFIG_MSM_MMCC_8960) += mmcc-msm8960.o
obj-$(CONFIG_MSM_MMCC_8974) += mmcc-msm8974.o
obj-$(CONFIG_MSM_MMCC_8996) += mmcc-msm8996.o
obj-$(CONFIG_MSM_GPUCC_FALCON) += gpucc-msmfalcon.o
+obj-$(CONFIG_MSM_MMCC_FALCON) += mmcc-msmfalcon.o
obj-$(CONFIG_KPSS_XCC) += kpss-xcc.o
obj-$(CONFIG_QCOM_HFPLL) += hfpll.o
obj-$(CONFIG_KRAITCC) += krait-cc.o
diff --git a/drivers/clk/qcom/clk-branch.c b/drivers/clk/qcom/clk-branch.c
index 6a975052cc85..ec3d02e8dcb1 100644
--- a/drivers/clk/qcom/clk-branch.c
+++ b/drivers/clk/qcom/clk-branch.c
@@ -286,11 +286,20 @@ static void clk_gate2_list_registers(struct seq_file *f, struct clk_hw *hw)
}
}
+static int clk_gate2_set_flags(struct clk_hw *hw, unsigned flags)
+{
+ struct clk_gate2 *gt = to_clk_gate2(hw);
+
+ return clk_cbcr_set_flags(gt->clkr.regmap, gt->clkr.enable_reg,
+ flags);
+}
+
const struct clk_ops clk_gate2_ops = {
.enable = clk_gate2_enable,
.disable = clk_gate2_disable,
.is_enabled = clk_is_enabled_regmap,
.list_registers = clk_gate2_list_registers,
+ .set_flags = clk_gate2_set_flags,
};
EXPORT_SYMBOL_GPL(clk_gate2_ops);
diff --git a/drivers/clk/qcom/clk-cpu-osm.c b/drivers/clk/qcom/clk-cpu-osm.c
new file mode 100644
index 000000000000..f97cd1b03c81
--- /dev/null
+++ b/drivers/clk/qcom/clk-cpu-osm.c
@@ -0,0 +1,3301 @@
+/*
+ * Copyright (c) 2016, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#define pr_fmt(fmt) "%s: " fmt, __func__
+
+#include <linux/debugfs.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/io.h>
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <linux/errno.h>
+#include <linux/clk.h>
+#include <linux/clk/msm-clk-provider.h>
+#include <linux/clk/msm-clk.h>
+#include <linux/clk/msm-clock-generic.h>
+#include <linux/cpu.h>
+#include <linux/platform_device.h>
+#include <linux/of_platform.h>
+#include <linux/pm_opp.h>
+#include <linux/pm_qos.h>
+#include <linux/interrupt.h>
+#include <linux/regulator/driver.h>
+#include <linux/uaccess.h>
+#include <linux/sched.h>
+
+#include <soc/qcom/scm.h>
+#include <soc/qcom/clock-pll.h>
+#include <soc/qcom/clock-local2.h>
+#include <soc/qcom/clock-alpha-pll.h>
+
+#include <dt-bindings/clock/msm-clocks-hwio-cobalt.h>
+#include <dt-bindings/clock/msm-clocks-cobalt.h>
+
+#include "clock.h"
+
+enum clk_osm_bases {
+ OSM_BASE,
+ PLL_BASE,
+ EFUSE_BASE,
+ ACD_BASE,
+ NUM_BASES,
+};
+
+enum clk_osm_lut_data {
+ FREQ,
+ FREQ_DATA,
+ PLL_OVERRIDES,
+ SPARE_DATA,
+ VIRTUAL_CORNER,
+ NUM_FIELDS,
+};
+
+enum clk_osm_trace_method {
+ XOR_PACKET,
+ PERIODIC_PACKET,
+};
+
+enum clk_osm_trace_packet_id {
+ TRACE_PACKET0,
+ TRACE_PACKET1,
+ TRACE_PACKET2,
+ TRACE_PACKET3,
+};
+
+#define SEQ_REG(n) (0x300 + (n) * 4)
+#define MEM_ACC_SEQ_REG_CFG_START(n) (SEQ_REG(12 + (n)))
+#define MEM_ACC_SEQ_CONST(n) (n)
+#define MEM_ACC_INSTR_COMP(n) (0x67 + ((n) * 0x40))
+#define MEM_ACC_SEQ_REG_VAL_START(n) (SEQ_REG(60 + (n)))
+#define SEQ_REG1_MSMCOBALT_V2 0x1048
+#define VERSION_REG 0x0
+#define VERSION_1P1 0x00010100
+
+#define OSM_TABLE_SIZE 40
+#define MAX_CLUSTER_CNT 2
+#define MAX_CONFIG 4
+#define LLM_SW_OVERRIDE_CNT 3
+
+#define ENABLE_REG 0x1004
+#define INDEX_REG 0x1150
+#define FREQ_REG 0x1154
+#define VOLT_REG 0x1158
+#define OVERRIDE_REG 0x115C
+#define SPARE_REG 0x1164
+
+#define OSM_CYCLE_COUNTER_CTRL_REG 0x1F00
+#define OSM_CYCLE_COUNTER_STATUS_REG 0x1F04
+#define DCVS_PERF_STATE_DESIRED_REG 0x1F10
+#define DCVS_PERF_STATE_DEVIATION_INTR_STAT 0x1F14
+#define DCVS_PERF_STATE_DEVIATION_INTR_EN 0x1F18
+#define DCVS_PERF_STATE_DEVIATION_INTR_CLEAR 0x1F1C
+#define DCVS_PERF_STATE_DEVIATION_CORRECTED_INTR_STAT 0x1F20
+#define DCVS_PERF_STATE_DEVIATION_CORRECTED_INTR_EN 0x1F24
+#define DCVS_PERF_STATE_DEVIATION_CORRECTED_INTR_CLEAR 0x1F28
+#define DCVS_PERF_STATE_MET_INTR_STAT 0x1F2C
+#define DCVS_PERF_STATE_MET_INTR_EN 0x1F30
+#define DCVS_PERF_STATE_MET_INTR_CLR 0x1F34
+#define OSM_CORE_TABLE_SIZE 8192
+#define OSM_REG_SIZE 32
+
+#define WDOG_DOMAIN_PSTATE_STATUS 0x1c00
+#define WDOG_PROGRAM_COUNTER 0x1c74
+
+#define OSM_CYCLE_COUNTER_USE_XO_EDGE_EN BIT(8)
+#define PLL_MODE 0x0
+#define PLL_L_VAL 0x4
+#define PLL_USER_CTRL 0xC
+#define PLL_CONFIG_CTL_LO 0x10
+#define PLL_TEST_CTL_HI 0x1C
+#define PLL_STATUS 0x2C
+#define PLL_LOCK_DET_MASK BIT(16)
+#define PLL_WAIT_LOCK_TIME_US 10
+#define PLL_WAIT_LOCK_TIME_NS (PLL_WAIT_LOCK_TIME_US * 1000)
+#define PLL_MIN_LVAL 43
+
+#define CC_ZERO_BEHAV_CTRL 0x100C
+#define SPM_CC_DCVS_DISABLE 0x1020
+#define SPM_CC_CTRL 0x1028
+#define SPM_CC_HYSTERESIS 0x101C
+#define SPM_CORE_RET_MAPPING 0x1024
+#define CFG_DELAY_VAL_3 0x12C
+
+#define LLM_FREQ_VOTE_HYSTERESIS 0x102C
+#define LLM_VOLT_VOTE_HYSTERESIS 0x1030
+#define LLM_INTF_DCVS_DISABLE 0x1034
+
+#define ENABLE_OVERRIDE BIT(0)
+
+#define ITM_CL0_DISABLE_CL1_ENABLED 0x2
+#define ITM_CL0_ENABLED_CL1_DISABLE 0x1
+
+#define APM_MX_MODE 0
+#define APM_APC_MODE BIT(1)
+#define APM_MODE_SWITCH_MASK (BVAL(4, 2, 7) | BVAL(1, 0, 3))
+#define APM_MX_MODE_VAL 0
+#define APM_APC_MODE_VAL 0x3
+
+#define GPLL_SEL 0x400
+#define PLL_EARLY_SEL 0x500
+#define PLL_MAIN_SEL 0x300
+#define RCG_UPDATE 0x3
+#define RCG_UPDATE_SUCCESS 0x2
+#define PLL_POST_DIV1 0x1F
+#define PLL_POST_DIV2 0x11F
+
+#define LLM_SW_OVERRIDE_REG 0x1038
+#define VMIN_REDUC_ENABLE_REG 0x103C
+#define VMIN_REDUC_TIMER_REG 0x1040
+#define PDN_FSM_CTRL_REG 0x1070
+#define CC_BOOST_TIMER_REG0 0x1074
+#define CC_BOOST_TIMER_REG1 0x1078
+#define CC_BOOST_TIMER_REG2 0x107C
+#define CC_BOOST_EN_MASK BIT(0)
+#define PS_BOOST_EN_MASK BIT(1)
+#define DCVS_BOOST_EN_MASK BIT(2)
+#define PC_RET_EXIT_DROOP_EN_MASK BIT(3)
+#define WFX_DROOP_EN_MASK BIT(4)
+#define DCVS_DROOP_EN_MASK BIT(5)
+#define LMH_PS_EN_MASK BIT(6)
+#define IGNORE_PLL_LOCK_MASK BIT(15)
+#define SAFE_FREQ_WAIT_NS 5000
+#define DEXT_DECREMENT_WAIT_NS 1000
+#define DCVS_BOOST_TIMER_REG0 0x1084
+#define DCVS_BOOST_TIMER_REG1 0x1088
+#define DCVS_BOOST_TIMER_REG2 0x108C
+#define PS_BOOST_TIMER_REG0 0x1094
+#define PS_BOOST_TIMER_REG1 0x1098
+#define PS_BOOST_TIMER_REG2 0x109C
+#define BOOST_PROG_SYNC_DELAY_REG 0x10A0
+#define DROOP_CTRL_REG 0x10A4
+#define DROOP_RELEASE_TIMER_CTRL 0x10A8
+#define DROOP_PROG_SYNC_DELAY_REG 0x10BC
+#define DROOP_UNSTALL_TIMER_CTRL_REG 0x10AC
+#define DROOP_WAIT_TO_RELEASE_TIMER_CTRL0_REG 0x10B0
+#define DROOP_WAIT_TO_RELEASE_TIMER_CTRL1_REG 0x10B4
+#define OSM_PLL_SW_OVERRIDE_EN 0x10C0
+
+#define PLL_SW_OVERRIDE_DROOP_EN BIT(0)
+#define DCVS_DROOP_TIMER_CTRL 0x10B8
+#define SEQ_MEM_ADDR 0x500
+#define SEQ_CFG_BR_ADDR 0x170
+#define MAX_INSTRUCTIONS 256
+#define MAX_BR_INSTRUCTIONS 49
+
+#define MAX_MEM_ACC_LEVELS 3
+#define MAX_MEM_ACC_VAL_PER_LEVEL 3
+#define MAX_MEM_ACC_VALUES (MAX_MEM_ACC_LEVELS * \
+ MAX_MEM_ACC_VAL_PER_LEVEL)
+#define MEM_ACC_APM_READ_MASK 0xff
+
+#define TRACE_CTRL 0x1F38
+#define TRACE_CTRL_EN_MASK BIT(0)
+#define TRACE_CTRL_ENABLE 1
+#define TRACE_CTRL_DISABLE 0
+#define TRACE_CTRL_ENABLE_WDOG_STATUS BIT(30)
+#define TRACE_CTRL_PACKET_TYPE_MASK BVAL(2, 1, 3)
+#define TRACE_CTRL_PACKET_TYPE_SHIFT 1
+#define TRACE_CTRL_PERIODIC_TRACE_EN_MASK BIT(3)
+#define TRACE_CTRL_PERIODIC_TRACE_ENABLE BIT(3)
+#define PERIODIC_TRACE_TIMER_CTRL 0x1F3C
+#define PERIODIC_TRACE_MIN_NS 1000
+#define PERIODIC_TRACE_MAX_NS 21474836475
+#define PERIODIC_TRACE_DEFAULT_NS 1000000
+
+#define PLL_DD_USER_CTL_LO_ENABLE 0x0f04c408
+#define PLL_DD_USER_CTL_LO_DISABLE 0x1f04c41f
+#define PLL_DD_D0_USER_CTL_LO 0x17916208
+#define PLL_DD_D1_USER_CTL_LO 0x17816208
+
+#define PWRCL_EFUSE_SHIFT 0
+#define PWRCL_EFUSE_MASK 0
+#define PERFCL_EFUSE_SHIFT 29
+#define PERFCL_EFUSE_MASK 0x7
+
+#define MSMCOBALTV1_PWRCL_BOOT_RATE 1478400000
+#define MSMCOBALTV1_PERFCL_BOOT_RATE 1536000000
+#define MSMCOBALTV2_PWRCL_BOOT_RATE 1555200000
+#define MSMCOBALTV2_PERFCL_BOOT_RATE 1728000000
+
+/* ACD registers */
+#define ACD_HW_VERSION 0x0
+#define ACDCR 0x4
+#define ACDTD 0x8
+#define ACDSSCR 0x28
+#define ACD_EXTINT_CFG 0x30
+#define ACD_DCVS_SW 0x34
+#define ACD_GFMUX_CFG 0x3c
+#define ACD_READOUT_CFG 0x48
+#define ACD_AUTOXFER_CFG 0x80
+#define ACD_AUTOXFER 0x84
+#define ACD_AUTOXFER_CTL 0x88
+#define ACD_AUTOXFER_STATUS 0x8c
+#define ACD_WRITE_CTL 0x90
+#define ACD_WRITE_STATUS 0x94
+#define ACD_READOUT 0x98
+
+#define ACD_MASTER_ONLY_REG_ADDR 0x80
+#define ACD_WRITE_CTL_UPDATE_EN BIT(0)
+#define ACD_WRITE_CTL_SELECT_SHIFT 1
+#define ACD_GFMUX_CFG_SELECT BIT(0)
+#define ACD_AUTOXFER_START_CLEAR 0
+#define ACD_AUTOXFER_START_SET BIT(0)
+#define AUTO_XFER_DONE_MASK BIT(0)
+#define ACD_DCVS_SW_DCVS_IN_PRGR_SET BIT(0)
+#define ACD_DCVS_SW_DCVS_IN_PRGR_CLEAR 0
+#define ACD_LOCAL_TRANSFER_TIMEOUT_NS 500
+
+static void __iomem *virt_base;
+static void __iomem *debug_base;
+
+#define lmh_lite_clk_src_source_val 1
+
+#define ACD_REG_RELATIVE_ADDR(addr) (addr / 4)
+#define ACD_REG_RELATIVE_ADDR_BITMASK(addr) \
+ (1 << (ACD_REG_RELATIVE_ADDR(addr)))
+
+#define FIXDIV(div) (div ? (2 * (div) - 1) : (0))
+
+#define F(f, s, div, m, n) \
+ { \
+ .freq_hz = (f), \
+ .src_clk = &s.c, \
+ .m_val = (m), \
+ .n_val = ~((n)-(m)) * !!(n), \
+ .d_val = ~(n),\
+ .div_src_val = BVAL(4, 0, (int)FIXDIV(div)) \
+ | BVAL(10, 8, s##_source_val), \
+ }
+
+static u32 seq_instr[] = {
+ 0xc2005000, 0x2c9e3b21, 0xc0ab2cdc, 0xc2882525, 0x359dc491,
+ 0x700a500b, 0x5001aefc, 0xaefd7000, 0x390938c8, 0xcb44c833,
+ 0xce56cd54, 0x341336e0, 0xa4baadba, 0xb480a493, 0x10004000,
+ 0x70005001, 0x1000500c, 0xc792c5a1, 0x501625e1, 0x3da335a2,
+ 0x50170006, 0x50150006, 0x1000c633, 0x1000acb3, 0xc422acb4,
+ 0xaefc1000, 0x700a500b, 0x70005001, 0x5010aefd, 0x5012700b,
+ 0xad41700c, 0x84e5adb9, 0xb3808566, 0x239b0003, 0x856484e3,
+ 0xb9800007, 0x2bad0003, 0xac3aa20b, 0x0003181b, 0x0003bb40,
+ 0xa30d239b, 0x500c181b, 0x5011500f, 0x181b3413, 0x853984b9,
+ 0x0003bd80, 0xa0012ba4, 0x72050803, 0x500e1000, 0x500c1000,
+ 0x1c011c0a, 0x3b181c06, 0x1c073b43, 0x1c061000, 0x1c073983,
+ 0x1c02500c, 0x10001c0a, 0x70015002, 0x81031000, 0x70025003,
+ 0x70035004, 0x3b441000, 0x81553985, 0x70025003, 0x50054003,
+ 0xa1467009, 0x0003b1c0, 0x4005238b, 0x835a1000, 0x855c84db,
+ 0x1000a51f, 0x84de835d, 0xa52c855c, 0x50061000, 0x39cd3a4c,
+ 0x3ad03a8f, 0x10004006, 0x70065007, 0xa00f2c12, 0x08034007,
+ 0xaefc7205, 0xaefd700d, 0xa9641000, 0x40071c1a, 0x700daefc,
+ 0x1000aefd, 0x70065007, 0x50101c16, 0x40075012, 0x700daefc,
+ 0x2411aefd, 0xa8211000, 0x0803a00f, 0x500c7005, 0x1c1591e0,
+ 0x500f5014, 0x10005011, 0x500c2bd4, 0x0803a00f, 0x10007205,
+ 0xa00fa9d1, 0x0803a821, 0xa9d07005, 0x91e0500c, 0x500f1c15,
+ 0x10005011, 0x1c162bce, 0x50125010, 0xa022a82a, 0x70050803,
+ 0x1c1591df, 0x5011500f, 0x5014500c, 0x0803a00f, 0x10007205,
+ 0x501391a4, 0x22172217, 0x70075008, 0xa9634008, 0x1c1a0006,
+ 0x70085009, 0x10004009, 0x00008ed9, 0x3e05c8dd, 0x1c033604,
+ 0xabaf1000, 0x856284e1, 0x0003bb80, 0x1000239f, 0x0803a037,
+ 0x10007205, 0x8dc61000, 0x38a71c2a, 0x1c2a8dc4, 0x100038a6,
+ 0x1c2a8dc5, 0x8dc73867, 0x38681c2a, 0x8c491000, 0x8d4b8cca,
+ 0x10001c00, 0x8ccd8c4c, 0x1c008d4e, 0x8c4f1000, 0x8d518cd0,
+ 0x10001c00, 0xa759a79a, 0x1000a718, 0xbf80af9b, 0x00001000,
+};
+
+static u32 seq_br_instr[] = {
+ 0x248, 0x20e, 0x21c, 0xf6, 0x112,
+ 0x11c, 0xe4, 0xea, 0xc6, 0xd6,
+ 0x126, 0x108, 0x184, 0x1a8, 0x1b0,
+ 0x134, 0x158, 0x16e, 0x14a, 0xc2,
+ 0x190, 0x1d2, 0x1cc, 0x1d4, 0x1e8,
+ 0x0, 0x1f6, 0x32, 0x66, 0xb0,
+ 0xa6, 0x1fc, 0x3c, 0x44, 0x5c,
+ 0x60, 0x204, 0x30, 0x22a, 0x234,
+ 0x23e, 0x0, 0x250, 0x0, 0x0, 0x9a,
+ 0x20c,
+};
+
+DEFINE_EXT_CLK(xo_ao, NULL);
+DEFINE_EXT_CLK(sys_apcsaux_clk_gcc, NULL);
+DEFINE_EXT_CLK(lmh_lite_clk_src, NULL);
+
+struct osm_entry {
+ u16 virtual_corner;
+ u16 open_loop_volt;
+ u32 freq_data;
+ u32 override_data;
+ u32 spare_data;
+ long frequency;
+};
+
+static struct dentry *osm_debugfs_base;
+
+struct clk_osm {
+ struct clk c;
+ struct osm_entry osm_table[OSM_TABLE_SIZE];
+ struct dentry *debugfs;
+ struct regulator *vdd_reg;
+ struct platform_device *vdd_dev;
+ void *vbases[NUM_BASES];
+ unsigned long pbases[NUM_BASES];
+ spinlock_t lock;
+
+ u32 version;
+ u32 cpu_reg_mask;
+ u32 num_entries;
+ u32 cluster_num;
+ u32 irq;
+ u32 apm_crossover_vc;
+ u32 apm_threshold_vc;
+ u32 cycle_counter_reads;
+ u32 cycle_counter_delay;
+ u32 cycle_counter_factor;
+ u64 total_cycle_counter;
+ u32 prev_cycle_counter;
+ u32 l_val_base;
+ u32 apcs_itm_present;
+ u32 apcs_cfg_rcgr;
+ u32 apcs_cmd_rcgr;
+ u32 apcs_pll_user_ctl;
+ u32 apcs_mem_acc_cfg[MAX_MEM_ACC_VAL_PER_LEVEL];
+ u32 apcs_mem_acc_val[MAX_MEM_ACC_VALUES];
+ u32 llm_sw_overr[LLM_SW_OVERRIDE_CNT];
+ u32 apm_mode_ctl;
+ u32 apm_ctrl_status;
+ u32 osm_clk_rate;
+ u32 xo_clk_rate;
+ u32 acd_td;
+ u32 acd_cr;
+ u32 acd_sscr;
+ u32 acd_extint0_cfg;
+ u32 acd_extint1_cfg;
+ u32 acd_autoxfer_ctl;
+ u32 acd_debugfs_addr;
+ bool acd_init;
+ bool secure_init;
+ bool red_fsm_en;
+ bool boost_fsm_en;
+ bool safe_fsm_en;
+ bool ps_fsm_en;
+ bool droop_fsm_en;
+ bool wfx_fsm_en;
+ bool pc_fsm_en;
+
+ enum clk_osm_trace_method trace_method;
+ enum clk_osm_trace_packet_id trace_id;
+ struct notifier_block panic_notifier;
+ u32 trace_periodic_timer;
+ bool trace_en;
+ bool wdog_trace_en;
+};
+
+static bool msmcobalt_v1;
+static bool msmcobalt_v2;
+
+static inline void clk_osm_masked_write_reg(struct clk_osm *c, u32 val,
+ u32 offset, u32 mask)
+{
+ u32 val2, orig_val;
+
+ val2 = orig_val = readl_relaxed((char *)c->vbases[OSM_BASE] + offset);
+ val2 &= ~mask;
+ val2 |= val & mask;
+
+ if (val2 != orig_val)
+ writel_relaxed(val2, (char *)c->vbases[OSM_BASE] + offset);
+}
+
+static inline void clk_osm_write_reg(struct clk_osm *c, u32 val, u32 offset)
+{
+ writel_relaxed(val, (char *)c->vbases[OSM_BASE] + offset);
+}
+
+static inline int clk_osm_read_reg(struct clk_osm *c, u32 offset)
+{
+ return readl_relaxed((char *)c->vbases[OSM_BASE] + offset);
+}
+
+static inline int clk_osm_read_reg_no_log(struct clk_osm *c, u32 offset)
+{
+ return readl_relaxed_no_log((char *)c->vbases[OSM_BASE] + offset);
+}
+
+static inline int clk_osm_mb(struct clk_osm *c, int base)
+{
+ return readl_relaxed_no_log((char *)c->vbases[base] + VERSION_REG);
+}
+
+static inline int clk_osm_acd_mb(struct clk_osm *c)
+{
+ return readl_relaxed_no_log((char *)c->vbases[ACD_BASE] +
+ ACD_HW_VERSION);
+}
+
+static inline void clk_osm_acd_master_write_reg(struct clk_osm *c,
+ u32 val, u32 offset)
+{
+ writel_relaxed(val, (char *)c->vbases[ACD_BASE] + offset);
+}
+
+static int clk_osm_acd_local_read_reg(struct clk_osm *c, u32 offset)
+{
+ u32 reg = 0;
+ int timeout;
+
+ if (offset >= ACD_MASTER_ONLY_REG_ADDR) {
+ pr_err("ACD register at offset=0x%x not locally readable\n",
+ offset);
+ return -EINVAL;
+ }
+
+ /* Set select field in read control register */
+ writel_relaxed(ACD_REG_RELATIVE_ADDR(offset),
+ (char *)c->vbases[ACD_BASE] + ACD_READOUT_CFG);
+
+ /* Clear write control register */
+ writel_relaxed(reg, (char *)c->vbases[ACD_BASE] + ACD_WRITE_CTL);
+
+ /* Set select and update_en fields in write control register */
+ reg = (ACD_REG_RELATIVE_ADDR(ACD_READOUT_CFG)
+ << ACD_WRITE_CTL_SELECT_SHIFT)
+ | ACD_WRITE_CTL_UPDATE_EN;
+ writel_relaxed(reg, (char *)c->vbases[ACD_BASE] + ACD_WRITE_CTL);
+
+ /* Ensure writes complete before polling */
+ clk_osm_acd_mb(c);
+
+ /* Poll write status register */
+ for (timeout = ACD_LOCAL_TRANSFER_TIMEOUT_NS; timeout > 0;
+ timeout -= 100) {
+ reg = readl_relaxed((char *)c->vbases[ACD_BASE]
+ + ACD_WRITE_STATUS);
+ if ((reg & (ACD_REG_RELATIVE_ADDR_BITMASK(ACD_READOUT_CFG))))
+ break;
+ ndelay(100);
+ }
+
+ if (!timeout) {
+ pr_err("local read timed out, offset=0x%x status=0x%x\n",
+ offset, reg);
+ return -ETIMEDOUT;
+ }
+
+ reg = readl_relaxed((char *)c->vbases[ACD_BASE]
+ + ACD_READOUT);
+ return reg;
+}
+
+static int clk_osm_acd_local_write_reg(struct clk_osm *c, u32 val, u32 offset)
+{
+ u32 reg = 0;
+ int timeout;
+
+ if (offset >= ACD_MASTER_ONLY_REG_ADDR) {
+ pr_err("ACD register at offset=0x%x not transferrable\n",
+ offset);
+ return -EINVAL;
+ }
+
+ /* Clear write control register */
+ writel_relaxed(reg, (char *)c->vbases[ACD_BASE] + ACD_WRITE_CTL);
+
+ /* Set select and update_en fields in write control register */
+ reg = (ACD_REG_RELATIVE_ADDR(offset) << ACD_WRITE_CTL_SELECT_SHIFT)
+ | ACD_WRITE_CTL_UPDATE_EN;
+ writel_relaxed(reg, (char *)c->vbases[ACD_BASE] + ACD_WRITE_CTL);
+
+ /* Ensure writes complete before polling */
+ clk_osm_acd_mb(c);
+
+ /* Poll write status register */
+ for (timeout = ACD_LOCAL_TRANSFER_TIMEOUT_NS; timeout > 0;
+ timeout -= 100) {
+ reg = readl_relaxed((char *)c->vbases[ACD_BASE]
+ + ACD_WRITE_STATUS);
+ if ((reg & (ACD_REG_RELATIVE_ADDR_BITMASK(offset))))
+ break;
+ ndelay(100);
+ }
+
+ if (!timeout) {
+ pr_err("local write timed out, offset=0x%x val=0x%x status=0x%x\n",
+ offset, val, reg);
+ return -ETIMEDOUT;
+ }
+
+ return 0;
+}
+
+static int clk_osm_acd_master_write_through_reg(struct clk_osm *c,
+ u32 val, u32 offset)
+{
+ writel_relaxed(val, (char *)c->vbases[ACD_BASE] + offset);
+
+ /* Ensure writes complete before transfer to local copy */
+ clk_osm_acd_mb(c);
+
+ return clk_osm_acd_local_write_reg(c, val, offset);
+}
+
+static int clk_osm_acd_auto_local_write_reg(struct clk_osm *c, u32 mask)
+{
+ u32 numregs, bitmask = mask;
+ u32 reg = 0;
+ int timeout;
+
+ /* count number of bits set in register mask */
+ for (numregs = 0; bitmask; numregs++)
+ bitmask &= bitmask - 1;
+
+ /* Program auto-transfter mask */
+ writel_relaxed(mask, (char *)c->vbases[ACD_BASE] + ACD_AUTOXFER_CFG);
+
+ /* Clear start field in auto-transfer register */
+ writel_relaxed(ACD_AUTOXFER_START_CLEAR,
+ (char *)c->vbases[ACD_BASE] + ACD_AUTOXFER);
+
+ /* Set start field in auto-transfer register */
+ writel_relaxed(ACD_AUTOXFER_START_SET,
+ (char *)c->vbases[ACD_BASE] + ACD_AUTOXFER);
+
+ /* Ensure writes complete before polling */
+ clk_osm_acd_mb(c);
+
+ /* Poll auto-transfer status register */
+ for (timeout = ACD_LOCAL_TRANSFER_TIMEOUT_NS * numregs;
+ timeout > 0; timeout -= 100) {
+ reg = readl_relaxed((char *)c->vbases[ACD_BASE]
+ + ACD_AUTOXFER_STATUS);
+ if (reg & AUTO_XFER_DONE_MASK)
+ break;
+ ndelay(100);
+ }
+
+ if (!timeout) {
+ pr_err("local register auto-transfer timed out, mask=0x%x registers=%d status=0x%x\n",
+ mask, numregs, reg);
+ return -ETIMEDOUT;
+ }
+
+ return 0;
+}
+
+static inline int clk_osm_count_ns(struct clk_osm *c, u64 nsec)
+{
+ u64 temp;
+
+ temp = (u64)c->osm_clk_rate * nsec;
+ do_div(temp, 1000000000);
+
+ return temp;
+}
+
+static inline struct clk_osm *to_clk_osm(struct clk *c)
+{
+ return container_of(c, struct clk_osm, c);
+}
+
+static enum handoff clk_osm_handoff(struct clk *c)
+{
+ return HANDOFF_DISABLED_CLK;
+}
+
+static long clk_osm_list_rate(struct clk *c, unsigned n)
+{
+ if (n >= c->num_fmax)
+ return -ENXIO;
+ return c->fmax[n];
+}
+
+static long clk_osm_round_rate(struct clk *c, unsigned long rate)
+{
+ int i;
+ unsigned long rrate = 0;
+
+ /*
+ * If the rate passed in is 0, return the first frequency in
+ * the FMAX table.
+ */
+ if (!rate)
+ return c->fmax[0];
+
+ for (i = 0; i < c->num_fmax; i++) {
+ if (is_better_rate(rate, rrate, c->fmax[i])) {
+ rrate = c->fmax[i];
+ if (rrate == rate)
+ break;
+ }
+ }
+
+ return rrate;
+}
+
+static int clk_osm_search_table(struct osm_entry *table, int entries, long rate)
+{
+ int i;
+
+ for (i = 0; i < entries; i++)
+ if (rate == table[i].frequency)
+ return i;
+ return -EINVAL;
+}
+
+static int clk_osm_set_rate(struct clk *c, unsigned long rate)
+{
+ struct clk_osm *cpuclk = to_clk_osm(c);
+ int index = 0;
+ unsigned long r_rate;
+
+ r_rate = clk_osm_round_rate(c, rate);
+
+ if (rate != r_rate) {
+ pr_err("invalid rate requested rate=%ld\n", rate);
+ return -EINVAL;
+ }
+
+ /* Convert rate to table index */
+ index = clk_osm_search_table(cpuclk->osm_table,
+ cpuclk->num_entries, r_rate);
+ if (index < 0) {
+ pr_err("cannot set cluster %u to %lu\n",
+ cpuclk->cluster_num, rate);
+ return -EINVAL;
+ }
+ pr_debug("rate: %lu --> index %d\n", rate, index);
+
+ if (cpuclk->llm_sw_overr[0]) {
+ clk_osm_write_reg(cpuclk, cpuclk->llm_sw_overr[0],
+ LLM_SW_OVERRIDE_REG);
+ clk_osm_write_reg(cpuclk, cpuclk->llm_sw_overr[1],
+ LLM_SW_OVERRIDE_REG);
+ udelay(1);
+ }
+
+ /* Choose index and send request to OSM hardware */
+ clk_osm_write_reg(cpuclk, index, DCVS_PERF_STATE_DESIRED_REG);
+
+ if (cpuclk->llm_sw_overr[0]) {
+ udelay(1);
+ clk_osm_write_reg(cpuclk, cpuclk->llm_sw_overr[2],
+ LLM_SW_OVERRIDE_REG);
+ }
+
+ /* Make sure the write goes through before proceeding */
+ clk_osm_mb(cpuclk, OSM_BASE);
+
+ return 0;
+}
+
+static int clk_osm_enable(struct clk *c)
+{
+ struct clk_osm *cpuclk = to_clk_osm(c);
+
+ clk_osm_write_reg(cpuclk, 1, ENABLE_REG);
+
+ /* Make sure the write goes through before proceeding */
+ clk_osm_mb(cpuclk, OSM_BASE);
+
+ /* Wait for 5us for OSM hardware to enable */
+ udelay(5);
+
+ pr_debug("OSM clk enabled for cluster=%d\n", cpuclk->cluster_num);
+
+ return 0;
+}
+
+static struct clk_ops clk_ops_cpu_osm = {
+ .enable = clk_osm_enable,
+ .set_rate = clk_osm_set_rate,
+ .round_rate = clk_osm_round_rate,
+ .list_rate = clk_osm_list_rate,
+ .handoff = clk_osm_handoff,
+};
+
+static struct regulator *vdd_pwrcl;
+static struct regulator *vdd_perfcl;
+
+static struct clk_freq_tbl ftbl_osm_clk_src[] = {
+ F( 200000000, lmh_lite_clk_src, 1.5, 0, 0),
+ F_END
+};
+
+static struct rcg_clk osm_clk_src = {
+ .cmd_rcgr_reg = APCS_COMMON_LMH_CMD_RCGR,
+ .set_rate = set_rate_hid,
+ .freq_tbl = ftbl_osm_clk_src,
+ .current_freq = &rcg_dummy_freq,
+ .base = &virt_base,
+ .c = {
+ .dbg_name = "osm_clk_src",
+ .ops = &clk_ops_rcg,
+ CLK_INIT(osm_clk_src.c),
+ },
+};
+
+static struct clk_osm pwrcl_clk = {
+ .cluster_num = 0,
+ .cpu_reg_mask = 0x3,
+ .c = {
+ .dbg_name = "pwrcl_clk",
+ .ops = &clk_ops_cpu_osm,
+ .parent = &xo_ao.c,
+ CLK_INIT(pwrcl_clk.c),
+ },
+};
+
+static struct clk_osm perfcl_clk = {
+ .cluster_num = 1,
+ .cpu_reg_mask = 0x103,
+ .c = {
+ .dbg_name = "perfcl_clk",
+ .ops = &clk_ops_cpu_osm,
+ .parent = &xo_ao.c,
+ CLK_INIT(perfcl_clk.c),
+ },
+};
+
+static struct clk_ops clk_ops_cpu_dbg_mux;
+
+static struct mux_clk cpu_debug_mux = {
+ .offset = 0x0,
+ .mask = 0x3,
+ .shift = 8,
+ .ops = &mux_reg_ops,
+ MUX_SRC_LIST(
+ { &pwrcl_clk.c, 0x00 },
+ { &perfcl_clk.c, 0x01 },
+ ),
+ .base = &debug_base,
+ .c = {
+ .dbg_name = "cpu_debug_mux",
+ .ops = &clk_ops_cpu_dbg_mux,
+ .flags = CLKFLAG_NO_RATE_CACHE,
+ CLK_INIT(cpu_debug_mux.c),
+ },
+};
+
+static struct clk_lookup cpu_clocks_osm[] = {
+ CLK_LIST(pwrcl_clk),
+ CLK_LIST(perfcl_clk),
+ CLK_LIST(sys_apcsaux_clk_gcc),
+ CLK_LIST(xo_ao),
+ CLK_LIST(osm_clk_src),
+ CLK_LIST(cpu_debug_mux),
+};
+
+static unsigned long cpu_dbg_mux_get_rate(struct clk *clk)
+{
+ /* Account for the divider between the clock and the debug mux */
+ if (!strcmp(clk->parent->dbg_name, "pwrcl_clk"))
+ return clk->rate/4;
+ else if (!strcmp(clk->parent->dbg_name, "perfcl_clk"))
+ return clk->rate/8;
+ return clk->rate;
+}
+
+static void clk_osm_print_osm_table(struct clk_osm *c)
+{
+ int i;
+ struct osm_entry *table = c->osm_table;
+ u32 pll_src, pll_div, lval, core_count;
+
+ pr_debug("Index, Frequency, VC, OLV (mv), Core Count, PLL Src, PLL Div, L-Val, ACC Level\n");
+ for (i = 0; i < c->num_entries; i++) {
+ pll_src = (table[i].freq_data & GENMASK(27, 26)) >> 26;
+ pll_div = (table[i].freq_data & GENMASK(25, 24)) >> 24;
+ lval = table[i].freq_data & GENMASK(7, 0);
+ core_count = (table[i].freq_data & GENMASK(18, 16)) >> 16;
+
+ pr_debug("%3d, %11lu, %2u, %5u, %2u, %6u, %8u, %7u, %5u\n",
+ i,
+ table[i].frequency,
+ table[i].virtual_corner,
+ table[i].open_loop_volt,
+ core_count,
+ pll_src,
+ pll_div,
+ lval,
+ table[i].spare_data);
+ }
+ pr_debug("APM threshold corner=%d, crossover corner=%d\n",
+ c->apm_threshold_vc, c->apm_crossover_vc);
+}
+
+static int clk_osm_get_lut(struct platform_device *pdev,
+ struct clk_osm *c, char *prop_name)
+{
+ struct clk *clk = &c->c;
+ struct device_node *of = pdev->dev.of_node;
+ int prop_len, total_elems, num_rows, i, j, k;
+ int rc = 0;
+ u32 *array;
+ u32 data;
+ bool last_entry = false;
+
+ if (!of_find_property(of, prop_name, &prop_len)) {
+ dev_err(&pdev->dev, "missing %s\n", prop_name);
+ return -EINVAL;
+ }
+
+ total_elems = prop_len / sizeof(u32);
+ if (total_elems % NUM_FIELDS) {
+ dev_err(&pdev->dev, "bad length %d\n", prop_len);
+ return -EINVAL;
+ }
+
+ num_rows = total_elems / NUM_FIELDS;
+
+ clk->fmax = devm_kzalloc(&pdev->dev, num_rows * sizeof(unsigned long),
+ GFP_KERNEL);
+ if (!clk->fmax)
+ return -ENOMEM;
+
+ array = devm_kzalloc(&pdev->dev, prop_len, GFP_KERNEL);
+ if (!array)
+ return -ENOMEM;
+
+ rc = of_property_read_u32_array(of, prop_name, array, total_elems);
+ if (rc) {
+ dev_err(&pdev->dev, "Unable to parse OSM table, rc=%d\n", rc);
+ goto exit;
+ }
+
+ pr_debug("%s: Entries in Table: %d\n", __func__, num_rows);
+ c->num_entries = num_rows;
+ if (c->num_entries > OSM_TABLE_SIZE) {
+ pr_err("LUT entries %d exceed maximum size %d\n",
+ c->num_entries, OSM_TABLE_SIZE);
+ return -EINVAL;
+ }
+
+ for (i = 0, j = 0, k = 0; j < OSM_TABLE_SIZE; j++) {
+ c->osm_table[j].frequency = array[i + FREQ];
+ c->osm_table[j].freq_data = array[i + FREQ_DATA];
+ c->osm_table[j].override_data = array[i + PLL_OVERRIDES];
+ c->osm_table[j].spare_data = array[i + SPARE_DATA];
+ /* Voltage corners are 0 based in the OSM LUT */
+ c->osm_table[j].virtual_corner = array[i + VIRTUAL_CORNER] - 1;
+ pr_debug("index=%d freq=%ld virtual_corner=%d freq_data=0x%x override_data=0x%x spare_data=0x%x\n",
+ j, c->osm_table[j].frequency,
+ c->osm_table[j].virtual_corner,
+ c->osm_table[j].freq_data,
+ c->osm_table[j].override_data,
+ c->osm_table[j].spare_data);
+
+ data = (array[i + FREQ_DATA] & GENMASK(18, 16)) >> 16;
+ if (!last_entry) {
+ clk->fmax[k] = array[i];
+ k++;
+ }
+
+ if (i < total_elems - NUM_FIELDS)
+ i += NUM_FIELDS;
+ else
+ last_entry = true;
+ }
+ clk->num_fmax = k;
+exit:
+ devm_kfree(&pdev->dev, array);
+ return rc;
+}
+
+static int clk_osm_parse_dt_configs(struct platform_device *pdev)
+{
+ struct device_node *of = pdev->dev.of_node;
+ u32 *array;
+ int i, rc = 0;
+
+ array = devm_kzalloc(&pdev->dev, MAX_CLUSTER_CNT * sizeof(u32),
+ GFP_KERNEL);
+ if (!array)
+ return -ENOMEM;
+
+ rc = of_property_read_u32_array(of, "qcom,l-val-base",
+ array, MAX_CLUSTER_CNT);
+ if (rc) {
+ dev_err(&pdev->dev, "unable to find qcom,l-val-base property, rc=%d\n",
+ rc);
+ return -EINVAL;
+ }
+
+ pwrcl_clk.l_val_base = array[pwrcl_clk.cluster_num];
+ perfcl_clk.l_val_base = array[perfcl_clk.cluster_num];
+
+ rc = of_property_read_u32_array(of, "qcom,apcs-itm-present",
+ array, MAX_CLUSTER_CNT);
+ if (rc) {
+ dev_err(&pdev->dev, "unable to find qcom,apcs-itm-present property, rc=%d\n",
+ rc);
+ return -EINVAL;
+ }
+
+ pwrcl_clk.apcs_itm_present = array[pwrcl_clk.cluster_num];
+ perfcl_clk.apcs_itm_present = array[perfcl_clk.cluster_num];
+
+ rc = of_property_read_u32_array(of, "qcom,apcs-cfg-rcgr",
+ array, MAX_CLUSTER_CNT);
+ if (rc) {
+ dev_err(&pdev->dev, "unable to find qcom,apcs-cfg-rcgr property, rc=%d\n",
+ rc);
+ return -EINVAL;
+ }
+
+ pwrcl_clk.apcs_cfg_rcgr = array[pwrcl_clk.cluster_num];
+ perfcl_clk.apcs_cfg_rcgr = array[perfcl_clk.cluster_num];
+
+ rc = of_property_read_u32_array(of, "qcom,apcs-cmd-rcgr",
+ array, MAX_CLUSTER_CNT);
+ if (rc) {
+ dev_err(&pdev->dev, "unable to find qcom,apcs-cmd-rcgr property, rc=%d\n",
+ rc);
+ return -EINVAL;
+ }
+
+ pwrcl_clk.apcs_cmd_rcgr = array[pwrcl_clk.cluster_num];
+ perfcl_clk.apcs_cmd_rcgr = array[perfcl_clk.cluster_num];
+
+ rc = of_property_read_u32_array(of, "qcom,apcs-pll-user-ctl",
+ array, MAX_CLUSTER_CNT);
+ if (rc) {
+ dev_err(&pdev->dev, "unable to find qcom,apcs-pll-user-ctl property, rc=%d\n",
+ rc);
+ return -EINVAL;
+ }
+
+ pwrcl_clk.apcs_pll_user_ctl = array[pwrcl_clk.cluster_num];
+ perfcl_clk.apcs_pll_user_ctl = array[perfcl_clk.cluster_num];
+
+ rc = of_property_read_u32_array(of, "qcom,apm-mode-ctl",
+ array, MAX_CLUSTER_CNT);
+ if (rc) {
+ dev_err(&pdev->dev, "unable to find qcom,apm-mode-ctl property, rc=%d\n",
+ rc);
+ return -EINVAL;
+ }
+
+ pwrcl_clk.apm_mode_ctl = array[pwrcl_clk.cluster_num];
+ perfcl_clk.apm_mode_ctl = array[perfcl_clk.cluster_num];
+
+ rc = of_property_read_u32_array(of, "qcom,apm-ctrl-status",
+ array, MAX_CLUSTER_CNT);
+ if (rc) {
+ dev_err(&pdev->dev, "unable to find qcom,apm-ctrl-status property, rc=%d\n",
+ rc);
+ return -EINVAL;
+ }
+
+ pwrcl_clk.apm_ctrl_status = array[pwrcl_clk.cluster_num];
+ perfcl_clk.apm_ctrl_status = array[perfcl_clk.cluster_num];
+
+ for (i = 0; i < LLM_SW_OVERRIDE_CNT; i++)
+ of_property_read_u32_index(of, "qcom,llm-sw-overr",
+ pwrcl_clk.cluster_num *
+ LLM_SW_OVERRIDE_CNT + i,
+ &pwrcl_clk.llm_sw_overr[i]);
+
+ for (i = 0; i < LLM_SW_OVERRIDE_CNT; i++)
+ of_property_read_u32_index(of, "qcom,llm-sw-overr",
+ perfcl_clk.cluster_num *
+ LLM_SW_OVERRIDE_CNT + i,
+ &perfcl_clk.llm_sw_overr[i]);
+
+ if (pwrcl_clk.acd_init || perfcl_clk.acd_init) {
+ rc = of_property_read_u32_array(of, "qcom,acdtd-val",
+ array, MAX_CLUSTER_CNT);
+ if (rc) {
+ dev_err(&pdev->dev, "unable to find qcom,acdtd-val property, rc=%d\n",
+ rc);
+ return -EINVAL;
+ }
+
+ pwrcl_clk.acd_td = array[pwrcl_clk.cluster_num];
+ perfcl_clk.acd_td = array[perfcl_clk.cluster_num];
+
+ rc = of_property_read_u32_array(of, "qcom,acdcr-val",
+ array, MAX_CLUSTER_CNT);
+ if (rc) {
+ dev_err(&pdev->dev, "unable to find qcom,acdcr-val property, rc=%d\n",
+ rc);
+ return -EINVAL;
+ }
+
+ pwrcl_clk.acd_cr = array[pwrcl_clk.cluster_num];
+ perfcl_clk.acd_cr = array[perfcl_clk.cluster_num];
+
+ rc = of_property_read_u32_array(of, "qcom,acdsscr-val",
+ array, MAX_CLUSTER_CNT);
+ if (rc) {
+ dev_err(&pdev->dev, "unable to find qcom,acdsscr-val property, rc=%d\n",
+ rc);
+ return -EINVAL;
+ }
+
+ pwrcl_clk.acd_sscr = array[pwrcl_clk.cluster_num];
+ perfcl_clk.acd_sscr = array[perfcl_clk.cluster_num];
+
+ rc = of_property_read_u32_array(of, "qcom,acdextint0-val",
+ array, MAX_CLUSTER_CNT);
+ if (rc) {
+ dev_err(&pdev->dev, "unable to find qcom,acdextint0-val property, rc=%d\n",
+ rc);
+ return -EINVAL;
+ }
+
+ pwrcl_clk.acd_extint0_cfg = array[pwrcl_clk.cluster_num];
+ perfcl_clk.acd_extint0_cfg = array[perfcl_clk.cluster_num];
+
+ rc = of_property_read_u32_array(of, "qcom,acdextint1-val",
+ array, MAX_CLUSTER_CNT);
+ if (rc) {
+ dev_err(&pdev->dev, "unable to find qcom,acdextint1-val property, rc=%d\n",
+ rc);
+ return -EINVAL;
+ }
+
+ pwrcl_clk.acd_extint1_cfg = array[pwrcl_clk.cluster_num];
+ perfcl_clk.acd_extint1_cfg = array[perfcl_clk.cluster_num];
+
+ rc = of_property_read_u32_array(of, "qcom,acdautoxfer-val",
+ array, MAX_CLUSTER_CNT);
+ if (rc) {
+ dev_err(&pdev->dev, "unable to find qcom,acdautoxfer-val property, rc=%d\n",
+ rc);
+ return -EINVAL;
+ }
+
+ pwrcl_clk.acd_autoxfer_ctl = array[pwrcl_clk.cluster_num];
+ perfcl_clk.acd_autoxfer_ctl = array[perfcl_clk.cluster_num];
+ }
+
+ rc = of_property_read_u32(of, "qcom,xo-clk-rate",
+ &pwrcl_clk.xo_clk_rate);
+ if (rc) {
+ dev_err(&pdev->dev, "unable to find qcom,xo-clk-rate property, rc=%d\n",
+ rc);
+ return -EINVAL;
+ }
+
+ perfcl_clk.xo_clk_rate = pwrcl_clk.xo_clk_rate;
+
+ rc = of_property_read_u32(of, "qcom,osm-clk-rate",
+ &pwrcl_clk.osm_clk_rate);
+ if (rc) {
+ dev_err(&pdev->dev, "unable to find qcom,osm-clk-rate property, rc=%d\n",
+ rc);
+ return -EINVAL;
+ }
+ perfcl_clk.osm_clk_rate = pwrcl_clk.osm_clk_rate;
+
+ rc = of_property_read_u32(of, "qcom,cc-reads",
+ &pwrcl_clk.cycle_counter_reads);
+ if (rc) {
+ dev_err(&pdev->dev, "unable to find qcom,cc-reads property, rc=%d\n",
+ rc);
+ return -EINVAL;
+ }
+ perfcl_clk.cycle_counter_reads = pwrcl_clk.cycle_counter_reads;
+
+ rc = of_property_read_u32(of, "qcom,cc-delay",
+ &pwrcl_clk.cycle_counter_delay);
+ if (rc)
+ dev_dbg(&pdev->dev, "no delays between cycle counter reads\n");
+ else
+ perfcl_clk.cycle_counter_delay = pwrcl_clk.cycle_counter_delay;
+
+ rc = of_property_read_u32(of, "qcom,cc-factor",
+ &pwrcl_clk.cycle_counter_factor);
+ if (rc)
+ dev_dbg(&pdev->dev, "no factor specified for cycle counter estimation\n");
+ else
+ perfcl_clk.cycle_counter_factor =
+ pwrcl_clk.cycle_counter_factor;
+
+ perfcl_clk.red_fsm_en = pwrcl_clk.red_fsm_en =
+ of_property_read_bool(of, "qcom,red-fsm-en");
+
+ perfcl_clk.boost_fsm_en = pwrcl_clk.boost_fsm_en =
+ of_property_read_bool(of, "qcom,boost-fsm-en");
+
+ perfcl_clk.safe_fsm_en = pwrcl_clk.safe_fsm_en =
+ of_property_read_bool(of, "qcom,safe-fsm-en");
+
+ perfcl_clk.ps_fsm_en = pwrcl_clk.ps_fsm_en =
+ of_property_read_bool(of, "qcom,ps-fsm-en");
+
+ perfcl_clk.droop_fsm_en = pwrcl_clk.droop_fsm_en =
+ of_property_read_bool(of, "qcom,droop-fsm-en");
+
+ perfcl_clk.wfx_fsm_en = pwrcl_clk.wfx_fsm_en =
+ of_property_read_bool(of, "qcom,wfx-fsm-en");
+
+ perfcl_clk.pc_fsm_en = pwrcl_clk.pc_fsm_en =
+ of_property_read_bool(of, "qcom,pc-fsm-en");
+
+ devm_kfree(&pdev->dev, array);
+
+ perfcl_clk.secure_init = pwrcl_clk.secure_init =
+ of_property_read_bool(pdev->dev.of_node, "qcom,osm-no-tz");
+
+ if (!pwrcl_clk.secure_init)
+ return rc;
+
+ rc = of_property_read_u32_array(of, "qcom,pwrcl-apcs-mem-acc-cfg",
+ pwrcl_clk.apcs_mem_acc_cfg,
+ MAX_MEM_ACC_VAL_PER_LEVEL);
+ if (rc) {
+ dev_err(&pdev->dev, "unable to find qcom,pwrcl-apcs-mem-acc-cfg property, rc=%d\n",
+ rc);
+ return -EINVAL;
+ }
+
+ of_property_read_u32_array(of, "qcom,perfcl-apcs-mem-acc-cfg",
+ perfcl_clk.apcs_mem_acc_cfg,
+ MAX_MEM_ACC_VAL_PER_LEVEL);
+ if (rc) {
+ dev_err(&pdev->dev, "unable to find qcom,perfcl-apcs-mem-acc-cfg property, rc=%d\n",
+ rc);
+ return -EINVAL;
+ }
+
+ rc = of_property_read_u32_array(of, "qcom,pwrcl-apcs-mem-acc-val",
+ pwrcl_clk.apcs_mem_acc_val,
+ MAX_MEM_ACC_VALUES);
+ if (rc) {
+ dev_err(&pdev->dev, "unable to find qcom,pwrcl-apcs-mem-acc-val property, rc=%d\n",
+ rc);
+ return -EINVAL;
+ }
+
+ rc = of_property_read_u32_array(of, "qcom,perfcl-apcs-mem-acc-val",
+ perfcl_clk.apcs_mem_acc_val,
+ MAX_MEM_ACC_VALUES);
+ if (rc) {
+ dev_err(&pdev->dev, "unable to find qcom,perfcl-apcs-mem-acc-val property, rc=%d\n",
+ rc);
+ return -EINVAL;
+ }
+
+ return rc;
+}
+
+static int clk_osm_resources_init(struct platform_device *pdev)
+{
+ struct device_node *node;
+ struct resource *res;
+ struct clk *c;
+ unsigned long pbase;
+ int i, rc = 0;
+ void *vbase;
+
+ res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "osm");
+ if (!res) {
+ dev_err(&pdev->dev,
+ "Unable to get platform resource for osm");
+ return -ENOMEM;
+ }
+
+ pwrcl_clk.pbases[OSM_BASE] = (unsigned long)res->start;
+ pwrcl_clk.vbases[OSM_BASE] = devm_ioremap(&pdev->dev, res->start,
+ resource_size(res));
+ if (!pwrcl_clk.vbases[OSM_BASE]) {
+ dev_err(&pdev->dev, "Unable to map in osm base\n");
+ return -ENOMEM;
+ }
+
+ perfcl_clk.pbases[OSM_BASE] = pwrcl_clk.pbases[OSM_BASE] +
+ perfcl_clk.cluster_num * OSM_CORE_TABLE_SIZE;
+ perfcl_clk.vbases[OSM_BASE] = pwrcl_clk.vbases[OSM_BASE] +
+ perfcl_clk.cluster_num * OSM_CORE_TABLE_SIZE;
+
+ for (i = 0; i < MAX_CLUSTER_CNT; i++) {
+ res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
+ i == pwrcl_clk.cluster_num ?
+ "pwrcl_pll" : "perfcl_pll");
+ if (!res) {
+ dev_err(&pdev->dev,
+ "Unable to get platform resource\n");
+ return -ENOMEM;
+ }
+ pbase = (unsigned long)res->start;
+ vbase = devm_ioremap(&pdev->dev, res->start,
+ resource_size(res));
+
+ if (!vbase) {
+ dev_err(&pdev->dev, "Unable to map in base\n");
+ return -ENOMEM;
+ }
+
+ if (i == pwrcl_clk.cluster_num) {
+ pwrcl_clk.pbases[PLL_BASE] = pbase;
+ pwrcl_clk.vbases[PLL_BASE] = vbase;
+ } else {
+ perfcl_clk.pbases[PLL_BASE] = pbase;
+ perfcl_clk.vbases[PLL_BASE] = vbase;
+ }
+ }
+
+ res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "debug");
+ if (!res) {
+ dev_err(&pdev->dev, "Failed to get debug mux base\n");
+ return -EINVAL;
+ }
+
+ debug_base = devm_ioremap(&pdev->dev, res->start,
+ resource_size(res));
+ if (!debug_base) {
+ dev_err(&pdev->dev, "Unable to map in debug mux base\n");
+ return -ENOMEM;
+ }
+
+ clk_ops_cpu_dbg_mux = clk_ops_gen_mux;
+ clk_ops_cpu_dbg_mux.get_rate = cpu_dbg_mux_get_rate;
+
+ res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "apcs_common");
+ if (!res) {
+ dev_err(&pdev->dev, "Failed to get apcs common base\n");
+ return -EINVAL;
+ }
+
+ virt_base = devm_ioremap(&pdev->dev, res->start, resource_size(res));
+ if (!virt_base) {
+ dev_err(&pdev->dev, "Failed to map apcs common registers\n");
+ return -ENOMEM;
+ }
+
+ /* efuse speed bin fuses are optional */
+ res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
+ "pwrcl_efuse");
+ if (res) {
+ pbase = (unsigned long)res->start;
+ vbase = devm_ioremap(&pdev->dev, res->start,
+ resource_size(res));
+ if (!vbase) {
+ dev_err(&pdev->dev, "Unable to map in pwrcl_efuse base\n");
+ return -ENOMEM;
+ }
+ pwrcl_clk.pbases[EFUSE_BASE] = pbase;
+ pwrcl_clk.vbases[EFUSE_BASE] = vbase;
+ }
+
+ res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
+ "perfcl_efuse");
+ if (res) {
+ pbase = (unsigned long)res->start;
+ vbase = devm_ioremap(&pdev->dev, res->start,
+ resource_size(res));
+ if (!vbase) {
+ dev_err(&pdev->dev, "Unable to map in perfcl_efuse base\n");
+ return -ENOMEM;
+ }
+ perfcl_clk.pbases[EFUSE_BASE] = pbase;
+ perfcl_clk.vbases[EFUSE_BASE] = vbase;
+ }
+
+ res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
+ "pwrcl_acd");
+ if (res) {
+ pbase = (unsigned long)res->start;
+ vbase = devm_ioremap(&pdev->dev, res->start,
+ resource_size(res));
+ if (!vbase) {
+ dev_err(&pdev->dev, "Unable to map in pwrcl_acd base\n");
+ return -ENOMEM;
+ }
+ pwrcl_clk.pbases[ACD_BASE] = pbase;
+ pwrcl_clk.vbases[ACD_BASE] = vbase;
+ pwrcl_clk.acd_init = true;
+ } else {
+ pwrcl_clk.acd_init = false;
+ }
+
+ res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
+ "perfcl_acd");
+ if (res) {
+ pbase = (unsigned long)res->start;
+ vbase = devm_ioremap(&pdev->dev, res->start,
+ resource_size(res));
+ if (!vbase) {
+ dev_err(&pdev->dev, "Unable to map in perfcl_acd base\n");
+ return -ENOMEM;
+ }
+ perfcl_clk.pbases[ACD_BASE] = pbase;
+ perfcl_clk.vbases[ACD_BASE] = vbase;
+ perfcl_clk.acd_init = true;
+ } else {
+ perfcl_clk.acd_init = false;
+ }
+
+ vdd_pwrcl = devm_regulator_get(&pdev->dev, "vdd-pwrcl");
+ if (IS_ERR(vdd_pwrcl)) {
+ rc = PTR_ERR(vdd_pwrcl);
+ if (rc != -EPROBE_DEFER)
+ dev_err(&pdev->dev, "Unable to get the pwrcl vreg, rc=%d\n",
+ rc);
+ return rc;
+ }
+
+ vdd_perfcl = devm_regulator_get(&pdev->dev, "vdd-perfcl");
+ if (IS_ERR(vdd_perfcl)) {
+ rc = PTR_ERR(vdd_perfcl);
+ if (rc != -EPROBE_DEFER)
+ dev_err(&pdev->dev, "Unable to get the perfcl vreg, rc=%d\n",
+ rc);
+ return rc;
+ }
+
+ pwrcl_clk.vdd_reg = vdd_pwrcl;
+ perfcl_clk.vdd_reg = vdd_perfcl;
+
+ node = of_parse_phandle(pdev->dev.of_node, "vdd-pwrcl-supply", 0);
+ if (!node) {
+ pr_err("Unable to find vdd-pwrcl-supply\n");
+ return -EINVAL;
+ }
+
+ pwrcl_clk.vdd_dev = of_find_device_by_node(node->parent->parent);
+ if (!pwrcl_clk.vdd_dev) {
+ pr_err("Unable to find device for vdd-pwrcl-supply node\n");
+ return -EINVAL;
+ }
+
+ node = of_parse_phandle(pdev->dev.of_node,
+ "vdd-perfcl-supply", 0);
+ if (!node) {
+ pr_err("Unable to find vdd-perfcl-supply\n");
+ return -EINVAL;
+ }
+
+ perfcl_clk.vdd_dev = of_find_device_by_node(node->parent->parent);
+ if (!perfcl_clk.vdd_dev) {
+ pr_err("Unable to find device for vdd-perfcl-supply\n");
+ return -EINVAL;
+ }
+
+ c = devm_clk_get(&pdev->dev, "aux_clk");
+ if (IS_ERR(c)) {
+ rc = PTR_ERR(c);
+ if (rc != -EPROBE_DEFER)
+ dev_err(&pdev->dev, "Unable to get aux_clk, rc=%d\n",
+ rc);
+ return rc;
+ }
+ sys_apcsaux_clk_gcc.c.parent = c;
+
+ c = devm_clk_get(&pdev->dev, "xo_ao");
+ if (IS_ERR(c)) {
+ rc = PTR_ERR(c);
+ if (rc != -EPROBE_DEFER)
+ dev_err(&pdev->dev, "Unable to get xo_ao clk, rc=%d\n",
+ rc);
+ return rc;
+ }
+ xo_ao.c.parent = c;
+
+ return 0;
+}
+
+static void clk_osm_setup_cluster_pll(struct clk_osm *c)
+{
+ writel_relaxed(0x0, c->vbases[PLL_BASE] + PLL_MODE);
+ writel_relaxed(0x20, c->vbases[PLL_BASE] + PLL_L_VAL);
+ writel_relaxed(0x01000008, c->vbases[PLL_BASE] +
+ PLL_USER_CTRL);
+ writel_relaxed(0x20004AA8, c->vbases[PLL_BASE] +
+ PLL_CONFIG_CTL_LO);
+ writel_relaxed(0x2, c->vbases[PLL_BASE] +
+ PLL_MODE);
+
+ /* Ensure writes complete before delaying */
+ clk_osm_mb(c, PLL_BASE);
+
+ udelay(PLL_WAIT_LOCK_TIME_US);
+
+ writel_relaxed(0x6, c->vbases[PLL_BASE] + PLL_MODE);
+
+ /* Ensure write completes before delaying */
+ clk_osm_mb(c, PLL_BASE);
+
+ usleep_range(50, 75);
+
+ writel_relaxed(0x7, c->vbases[PLL_BASE] + PLL_MODE);
+}
+
+static int clk_osm_setup_hw_table(struct clk_osm *c)
+{
+ struct osm_entry *entry = c->osm_table;
+ int i;
+ u32 freq_val, volt_val, override_val, spare_val;
+ u32 table_entry_offset, last_spare, last_virtual_corner = 0;
+
+ for (i = 0; i < OSM_TABLE_SIZE; i++) {
+ if (i < c->num_entries) {
+ freq_val = entry[i].freq_data;
+ volt_val = BVAL(21, 16, entry[i].virtual_corner)
+ | BVAL(11, 0, entry[i].open_loop_volt);
+ override_val = entry[i].override_data;
+ spare_val = entry[i].spare_data;
+
+ if (last_virtual_corner && last_virtual_corner ==
+ entry[i].virtual_corner && last_spare !=
+ entry[i].spare_data) {
+ pr_err("invalid LUT entry at row=%d virtual_corner=%d, spare_data=%d\n",
+ i, entry[i].virtual_corner,
+ entry[i].spare_data);
+ return -EINVAL;
+ }
+ last_virtual_corner = entry[i].virtual_corner;
+ last_spare = entry[i].spare_data;
+ }
+
+ table_entry_offset = i * OSM_REG_SIZE;
+ clk_osm_write_reg(c, i, INDEX_REG + table_entry_offset);
+ clk_osm_write_reg(c, freq_val, FREQ_REG + table_entry_offset);
+ clk_osm_write_reg(c, volt_val, VOLT_REG + table_entry_offset);
+ clk_osm_write_reg(c, override_val, OVERRIDE_REG +
+ table_entry_offset);
+ clk_osm_write_reg(c, spare_val, SPARE_REG +
+ table_entry_offset);
+ }
+
+ /* Make sure all writes go through */
+ clk_osm_mb(c, OSM_BASE);
+
+ return 0;
+}
+
+static int clk_osm_resolve_open_loop_voltages(struct clk_osm *c)
+{
+ struct regulator *regulator = c->vdd_reg;
+ u32 vc, mv;
+ int i;
+
+ for (i = 0; i < OSM_TABLE_SIZE; i++) {
+ vc = c->osm_table[i].virtual_corner + 1;
+ /* Voltage is in uv. Convert to mv */
+ mv = regulator_list_corner_voltage(regulator, vc) / 1000;
+ c->osm_table[i].open_loop_volt = mv;
+ }
+
+ return 0;
+}
+
+static int clk_osm_resolve_crossover_corners(struct clk_osm *c,
+ struct platform_device *pdev)
+{
+ struct regulator *regulator = c->vdd_reg;
+ int count, vc, i, threshold, rc = 0;
+ u32 corner_volt;
+
+ rc = of_property_read_u32(pdev->dev.of_node,
+ "qcom,apm-threshold-voltage",
+ &threshold);
+ if (rc) {
+ pr_info("qcom,apm-threshold-voltage property not specified\n");
+ return rc;
+ }
+
+ /* Determine crossover virtual corner */
+ count = regulator_count_voltages(regulator);
+ if (count < 0) {
+ pr_err("Failed to get the number of virtual corners supported\n");
+ return count;
+ }
+
+ c->apm_crossover_vc = count - 1;
+
+ /* Determine threshold virtual corner */
+ for (i = 0; i < OSM_TABLE_SIZE; i++) {
+ vc = c->osm_table[i].virtual_corner + 1;
+ corner_volt = regulator_list_corner_voltage(regulator, vc);
+
+ if (corner_volt >= threshold) {
+ c->apm_threshold_vc = c->osm_table[i].virtual_corner;
+ break;
+ }
+ }
+
+ return 0;
+}
+
+static int clk_osm_set_cc_policy(struct platform_device *pdev)
+{
+ int rc = 0, val;
+ u32 *array;
+ struct device_node *of = pdev->dev.of_node;
+
+ array = devm_kzalloc(&pdev->dev, MAX_CLUSTER_CNT * sizeof(u32),
+ GFP_KERNEL);
+ if (!array)
+ return -ENOMEM;
+
+ rc = of_property_read_u32_array(of, "qcom,up-timer", array,
+ MAX_CLUSTER_CNT);
+ if (rc) {
+ dev_dbg(&pdev->dev, "No up timer value, rc=%d\n",
+ rc);
+ } else {
+ val = clk_osm_read_reg(&pwrcl_clk, SPM_CC_HYSTERESIS)
+ | BVAL(31, 16, clk_osm_count_ns(&pwrcl_clk,
+ array[pwrcl_clk.cluster_num]));
+ clk_osm_write_reg(&pwrcl_clk, val, SPM_CC_HYSTERESIS);
+ val = clk_osm_read_reg(&perfcl_clk, SPM_CC_HYSTERESIS)
+ | BVAL(31, 16, clk_osm_count_ns(&perfcl_clk,
+ array[perfcl_clk.cluster_num]));
+ clk_osm_write_reg(&perfcl_clk, val, SPM_CC_HYSTERESIS);
+ }
+
+ rc = of_property_read_u32_array(of, "qcom,down-timer",
+ array, MAX_CLUSTER_CNT);
+ if (rc) {
+ dev_dbg(&pdev->dev, "No down timer value, rc=%d\n", rc);
+ } else {
+ val = clk_osm_read_reg(&pwrcl_clk, SPM_CC_HYSTERESIS)
+ | BVAL(15, 0, clk_osm_count_ns(&pwrcl_clk,
+ array[pwrcl_clk.cluster_num]));
+ clk_osm_write_reg(&pwrcl_clk, val, SPM_CC_HYSTERESIS);
+ val = clk_osm_read_reg(&perfcl_clk, SPM_CC_HYSTERESIS)
+ | BVAL(15, 0, clk_osm_count_ns(&perfcl_clk,
+ array[perfcl_clk.cluster_num]));
+ clk_osm_write_reg(&perfcl_clk, val, SPM_CC_HYSTERESIS);
+ }
+
+ /* OSM index override for cluster PC */
+ rc = of_property_read_u32_array(of, "qcom,pc-override-index",
+ array, MAX_CLUSTER_CNT);
+ if (rc) {
+ dev_dbg(&pdev->dev, "No PC override index value, rc=%d\n",
+ rc);
+ clk_osm_write_reg(&pwrcl_clk, 0, CC_ZERO_BEHAV_CTRL);
+ clk_osm_write_reg(&perfcl_clk, 0, CC_ZERO_BEHAV_CTRL);
+ } else {
+ val = BVAL(6, 1, array[pwrcl_clk.cluster_num])
+ | ENABLE_OVERRIDE;
+ clk_osm_write_reg(&pwrcl_clk, val, CC_ZERO_BEHAV_CTRL);
+ val = BVAL(6, 1, array[perfcl_clk.cluster_num])
+ | ENABLE_OVERRIDE;
+ clk_osm_write_reg(&perfcl_clk, val, CC_ZERO_BEHAV_CTRL);
+ }
+
+ /* Wait for the writes to complete */
+ clk_osm_mb(&perfcl_clk, OSM_BASE);
+
+ rc = of_property_read_bool(pdev->dev.of_node, "qcom,set-ret-inactive");
+ if (rc) {
+ dev_dbg(&pdev->dev, "Treat cores in retention as active\n");
+ val = 0;
+ } else {
+ dev_dbg(&pdev->dev, "Treat cores in retention as inactive\n");
+ val = 1;
+ }
+
+ clk_osm_write_reg(&pwrcl_clk, val, SPM_CORE_RET_MAPPING);
+ clk_osm_write_reg(&perfcl_clk, val, SPM_CORE_RET_MAPPING);
+
+ rc = of_property_read_bool(pdev->dev.of_node, "qcom,disable-cc-dvcs");
+ if (rc) {
+ dev_dbg(&pdev->dev, "Disabling CC based DCVS\n");
+ val = 1;
+ } else
+ val = 0;
+
+ clk_osm_write_reg(&pwrcl_clk, val, SPM_CC_DCVS_DISABLE);
+ clk_osm_write_reg(&perfcl_clk, val, SPM_CC_DCVS_DISABLE);
+
+ /* Wait for the writes to complete */
+ clk_osm_mb(&perfcl_clk, OSM_BASE);
+
+ devm_kfree(&pdev->dev, array);
+ return 0;
+}
+
+static void clk_osm_setup_itm_to_osm_handoff(void)
+{
+ /* Program address of ITM_PRESENT of CPUSS */
+ clk_osm_write_reg(&pwrcl_clk, pwrcl_clk.apcs_itm_present,
+ SEQ_REG(37));
+ clk_osm_write_reg(&pwrcl_clk, 0, SEQ_REG(38));
+ clk_osm_write_reg(&perfcl_clk, perfcl_clk.apcs_itm_present,
+ SEQ_REG(37));
+ clk_osm_write_reg(&perfcl_clk, 0, SEQ_REG(38));
+
+ /*
+ * Program data to write to ITM_PRESENT assuming ITM for other domain
+ * is enabled and the ITM for this domain is to be disabled.
+ */
+ clk_osm_write_reg(&pwrcl_clk, ITM_CL0_DISABLE_CL1_ENABLED,
+ SEQ_REG(39));
+ clk_osm_write_reg(&perfcl_clk, ITM_CL0_ENABLED_CL1_DISABLE,
+ SEQ_REG(39));
+}
+
+static int clk_osm_set_llm_freq_policy(struct platform_device *pdev)
+{
+ struct device_node *of = pdev->dev.of_node;
+ u32 *array;
+ int rc = 0, val, regval;
+
+ array = devm_kzalloc(&pdev->dev, MAX_CLUSTER_CNT * sizeof(u32),
+ GFP_KERNEL);
+ if (!array)
+ return -ENOMEM;
+
+ /*
+ * Setup Timer to control how long OSM should wait before performing
+ * DCVS when a LLM up frequency request is received.
+ * Time is specified in us.
+ */
+ rc = of_property_read_u32_array(of, "qcom,llm-freq-up-timer", array,
+ MAX_CLUSTER_CNT);
+ if (rc) {
+ dev_dbg(&pdev->dev, "Unable to get CC up timer value: %d\n",
+ rc);
+ } else {
+ val = clk_osm_read_reg(&pwrcl_clk, LLM_FREQ_VOTE_HYSTERESIS)
+ | BVAL(31, 16, clk_osm_count_ns(&pwrcl_clk,
+ array[pwrcl_clk.cluster_num]));
+ clk_osm_write_reg(&pwrcl_clk, val, LLM_FREQ_VOTE_HYSTERESIS);
+ val = clk_osm_read_reg(&perfcl_clk, LLM_FREQ_VOTE_HYSTERESIS)
+ | BVAL(31, 16, clk_osm_count_ns(&perfcl_clk,
+ array[perfcl_clk.cluster_num]));
+ clk_osm_write_reg(&perfcl_clk, val, LLM_FREQ_VOTE_HYSTERESIS);
+ }
+
+ /*
+ * Setup Timer to control how long OSM should wait before performing
+ * DCVS when a LLM down frequency request is received.
+ * Time is specified in us.
+ */
+ rc = of_property_read_u32_array(of, "qcom,llm-freq-down-timer",
+ array, MAX_CLUSTER_CNT);
+ if (rc) {
+ dev_dbg(&pdev->dev, "No LLM Frequency down timer value: %d\n",
+ rc);
+ } else {
+ val = clk_osm_read_reg(&pwrcl_clk, LLM_FREQ_VOTE_HYSTERESIS)
+ | BVAL(15, 0, clk_osm_count_ns(&pwrcl_clk,
+ array[pwrcl_clk.cluster_num]));
+ clk_osm_write_reg(&pwrcl_clk, val, LLM_FREQ_VOTE_HYSTERESIS);
+ val = clk_osm_read_reg(&perfcl_clk, LLM_FREQ_VOTE_HYSTERESIS)
+ | BVAL(15, 0, clk_osm_count_ns(&perfcl_clk,
+ array[perfcl_clk.cluster_num]));
+ clk_osm_write_reg(&perfcl_clk, val, LLM_FREQ_VOTE_HYSTERESIS);
+ }
+
+ /* Enable or disable honoring of LLM frequency requests */
+ rc = of_property_read_bool(pdev->dev.of_node,
+ "qcom,enable-llm-freq-vote");
+ if (rc) {
+ dev_dbg(&pdev->dev, "Honoring LLM Frequency requests\n");
+ val = 0;
+ } else
+ val = 1;
+
+ /* Enable or disable LLM FREQ DVCS */
+ regval = val | clk_osm_read_reg(&pwrcl_clk, LLM_INTF_DCVS_DISABLE);
+ clk_osm_write_reg(&pwrcl_clk, regval, LLM_INTF_DCVS_DISABLE);
+ regval = val | clk_osm_read_reg(&perfcl_clk, LLM_INTF_DCVS_DISABLE);
+ clk_osm_write_reg(&perfcl_clk, regval, LLM_INTF_DCVS_DISABLE);
+
+ /* Wait for the write to complete */
+ clk_osm_mb(&perfcl_clk, OSM_BASE);
+
+ devm_kfree(&pdev->dev, array);
+ return 0;
+}
+
+static int clk_osm_set_llm_volt_policy(struct platform_device *pdev)
+{
+ struct device_node *of = pdev->dev.of_node;
+ u32 *array;
+ int rc = 0, val, regval;
+
+ array = devm_kzalloc(&pdev->dev, MAX_CLUSTER_CNT * sizeof(u32),
+ GFP_KERNEL);
+ if (!array)
+ return -ENOMEM;
+
+ /*
+ * Setup Timer to control how long OSM should wait before performing
+ * DCVS when a LLM up voltage request is received.
+ * Time is specified in us.
+ */
+ rc = of_property_read_u32_array(of, "qcom,llm-volt-up-timer",
+ array, MAX_CLUSTER_CNT);
+ if (rc) {
+ dev_dbg(&pdev->dev, "No LLM voltage up timer value, rc=%d\n",
+ rc);
+ } else {
+ val = clk_osm_read_reg(&pwrcl_clk, LLM_VOLT_VOTE_HYSTERESIS)
+ | BVAL(31, 16, clk_osm_count_ns(&pwrcl_clk,
+ array[pwrcl_clk.cluster_num]));
+ clk_osm_write_reg(&pwrcl_clk, val, LLM_VOLT_VOTE_HYSTERESIS);
+ val = clk_osm_read_reg(&perfcl_clk, LLM_VOLT_VOTE_HYSTERESIS)
+ | BVAL(31, 16, clk_osm_count_ns(&perfcl_clk,
+ array[perfcl_clk.cluster_num]));
+ clk_osm_write_reg(&perfcl_clk, val, LLM_VOLT_VOTE_HYSTERESIS);
+ }
+
+ /*
+ * Setup Timer to control how long OSM should wait before performing
+ * DCVS when a LLM down voltage request is received.
+ * Time is specified in us.
+ */
+ rc = of_property_read_u32_array(of, "qcom,llm-volt-down-timer",
+ array, MAX_CLUSTER_CNT);
+ if (rc) {
+ dev_dbg(&pdev->dev, "No LLM Voltage down timer value: %d\n",
+ rc);
+ } else {
+ val = clk_osm_read_reg(&pwrcl_clk, LLM_VOLT_VOTE_HYSTERESIS)
+ | BVAL(15, 0, clk_osm_count_ns(&pwrcl_clk,
+ array[pwrcl_clk.cluster_num]));
+ clk_osm_write_reg(&pwrcl_clk, val, LLM_VOLT_VOTE_HYSTERESIS);
+ val = clk_osm_read_reg(&perfcl_clk, LLM_VOLT_VOTE_HYSTERESIS)
+ | BVAL(15, 0, clk_osm_count_ns(&perfcl_clk,
+ array[perfcl_clk.cluster_num]));
+ clk_osm_write_reg(&perfcl_clk, val, LLM_VOLT_VOTE_HYSTERESIS);
+ }
+
+ /* Enable or disable honoring of LLM Voltage requests */
+ rc = of_property_read_bool(pdev->dev.of_node,
+ "qcom,enable-llm-volt-vote");
+ if (rc) {
+ dev_dbg(&pdev->dev, "Honoring LLM Voltage requests\n");
+ val = 0;
+ } else
+ val = BIT(1);
+
+ /* Enable or disable LLM VOLT DVCS */
+ regval = val | clk_osm_read_reg(&pwrcl_clk, LLM_INTF_DCVS_DISABLE);
+ clk_osm_write_reg(&pwrcl_clk, val, LLM_INTF_DCVS_DISABLE);
+ regval = val | clk_osm_read_reg(&perfcl_clk, LLM_INTF_DCVS_DISABLE);
+ clk_osm_write_reg(&perfcl_clk, val, LLM_INTF_DCVS_DISABLE);
+
+ /* Wait for the writes to complete */
+ clk_osm_mb(&perfcl_clk, OSM_BASE);
+
+ devm_kfree(&pdev->dev, array);
+ return 0;
+}
+
+static void clk_osm_program_apm_regs(struct clk_osm *c)
+{
+ /*
+ * Program address of the control register used to configure
+ * the Array Power Mux controller
+ */
+ clk_osm_write_reg(c, c->apm_mode_ctl, SEQ_REG(2));
+
+ /* Program address of controller status register */
+ clk_osm_write_reg(c, c->apm_ctrl_status, SEQ_REG(3));
+
+ /* Program mode value to switch APM from VDD_APCC to VDD_MX */
+ clk_osm_write_reg(c, APM_MX_MODE, SEQ_REG(77));
+
+ /* Program value used to determine current APM power supply is VDD_MX */
+ clk_osm_write_reg(c, APM_MX_MODE_VAL, SEQ_REG(78));
+
+ /* Program mask used to determine status of APM power supply switch */
+ clk_osm_write_reg(c, APM_MODE_SWITCH_MASK, SEQ_REG(79));
+
+ /* Program mode value to switch APM from VDD_MX to VDD_APCC */
+ clk_osm_write_reg(c, APM_APC_MODE, SEQ_REG(80));
+
+ /*
+ * Program value used to determine current APM power supply
+ * is VDD_APCC
+ */
+ clk_osm_write_reg(c, APM_APC_MODE_VAL, SEQ_REG(81));
+}
+
+static void clk_osm_program_mem_acc_regs(struct clk_osm *c)
+{
+ int i, curr_level, j = 0;
+ int mem_acc_level_map[MAX_MEM_ACC_LEVELS] = {0, 0, 0};
+
+ curr_level = c->osm_table[0].spare_data;
+ for (i = 0; i < c->num_entries; i++) {
+ if (curr_level == MAX_MEM_ACC_LEVELS)
+ break;
+
+ if (c->osm_table[i].spare_data != curr_level) {
+ mem_acc_level_map[j++] = i - 1;
+ curr_level = c->osm_table[i].spare_data;
+ }
+ }
+
+ if (c->secure_init) {
+ clk_osm_write_reg(c, MEM_ACC_SEQ_CONST(1), SEQ_REG(51));
+ clk_osm_write_reg(c, MEM_ACC_SEQ_CONST(2), SEQ_REG(52));
+ clk_osm_write_reg(c, MEM_ACC_SEQ_CONST(3), SEQ_REG(53));
+ clk_osm_write_reg(c, MEM_ACC_SEQ_CONST(4), SEQ_REG(54));
+ clk_osm_write_reg(c, MEM_ACC_APM_READ_MASK, SEQ_REG(59));
+ clk_osm_write_reg(c, mem_acc_level_map[0], SEQ_REG(55));
+ clk_osm_write_reg(c, mem_acc_level_map[0] + 1, SEQ_REG(56));
+ clk_osm_write_reg(c, mem_acc_level_map[1], SEQ_REG(57));
+ clk_osm_write_reg(c, mem_acc_level_map[1] + 1, SEQ_REG(58));
+ clk_osm_write_reg(c, c->pbases[OSM_BASE] + SEQ_REG(28),
+ SEQ_REG(49));
+
+ for (i = 0; i < MAX_MEM_ACC_VALUES; i++)
+ clk_osm_write_reg(c, c->apcs_mem_acc_val[i],
+ MEM_ACC_SEQ_REG_VAL_START(i));
+
+ for (i = 0; i < MAX_MEM_ACC_VAL_PER_LEVEL; i++)
+ clk_osm_write_reg(c, c->apcs_mem_acc_cfg[i],
+ MEM_ACC_SEQ_REG_CFG_START(i));
+ } else {
+ scm_io_write(c->pbases[OSM_BASE] + SEQ_REG(55),
+ mem_acc_level_map[0]);
+ scm_io_write(c->pbases[OSM_BASE] + SEQ_REG(56),
+ mem_acc_level_map[0] + 1);
+ scm_io_write(c->pbases[OSM_BASE] + SEQ_REG(57),
+ mem_acc_level_map[1]);
+ scm_io_write(c->pbases[OSM_BASE] + SEQ_REG(58),
+ mem_acc_level_map[1] + 1);
+ /* SEQ_REG(49) = SEQ_REG(28) init by TZ */
+ }
+}
+
+void clk_osm_setup_sequencer(struct clk_osm *c)
+{
+ u32 i;
+
+ pr_debug("Setting up sequencer for cluster=%d\n", c->cluster_num);
+ for (i = 0; i < ARRAY_SIZE(seq_instr); i++) {
+ clk_osm_write_reg(c, seq_instr[i],
+ (long)(SEQ_MEM_ADDR + i * 4));
+ }
+
+ pr_debug("Setting up sequencer branch instructions for cluster=%d\n",
+ c->cluster_num);
+ for (i = 0; i < ARRAY_SIZE(seq_br_instr); i++) {
+ clk_osm_write_reg(c, seq_br_instr[i],
+ (long)(SEQ_CFG_BR_ADDR + i * 4));
+ }
+}
+
+static void clk_osm_setup_cycle_counters(struct clk_osm *c)
+{
+ u32 ratio = c->osm_clk_rate;
+ u32 val = 0;
+
+ /* Enable cycle counter */
+ val |= BIT(0);
+ /* Setup OSM clock to XO ratio */
+ do_div(ratio, c->xo_clk_rate);
+ val |= BVAL(5, 1, ratio - 1) | OSM_CYCLE_COUNTER_USE_XO_EDGE_EN;
+ clk_osm_write_reg(c, val, OSM_CYCLE_COUNTER_CTRL_REG);
+ c->total_cycle_counter = 0;
+ c->prev_cycle_counter = 0;
+ pr_debug("OSM to XO clock ratio: %d\n", ratio);
+}
+
+static void clk_osm_setup_osm_was(struct clk_osm *c)
+{
+ u32 cc_hyst;
+ u32 val;
+
+ if (msmcobalt_v2)
+ return;
+
+ val = clk_osm_read_reg(c, PDN_FSM_CTRL_REG);
+ val |= IGNORE_PLL_LOCK_MASK;
+ cc_hyst = clk_osm_read_reg(c, SPM_CC_HYSTERESIS);
+
+ if (c->secure_init) {
+ clk_osm_write_reg(c, val, SEQ_REG(47));
+ val &= ~IGNORE_PLL_LOCK_MASK;
+ clk_osm_write_reg(c, val, SEQ_REG(48));
+
+ clk_osm_write_reg(c, c->pbases[OSM_BASE] + SEQ_REG(42),
+ SEQ_REG(40));
+ clk_osm_write_reg(c, c->pbases[OSM_BASE] + SEQ_REG(43),
+ SEQ_REG(41));
+ clk_osm_write_reg(c, 0x1, SEQ_REG(44));
+ clk_osm_write_reg(c, 0x0, SEQ_REG(45));
+ clk_osm_write_reg(c, c->pbases[OSM_BASE] + PDN_FSM_CTRL_REG,
+ SEQ_REG(46));
+
+ /* C2D/C3 + D2D workaround */
+ clk_osm_write_reg(c, c->pbases[OSM_BASE] + SPM_CC_HYSTERESIS,
+ SEQ_REG(6));
+ clk_osm_write_reg(c, cc_hyst, SEQ_REG(7));
+
+ /* Droop detector PLL lock detect workaround */
+ clk_osm_write_reg(c, PLL_DD_USER_CTL_LO_ENABLE, SEQ_REG(4));
+ clk_osm_write_reg(c, PLL_DD_USER_CTL_LO_DISABLE, SEQ_REG(5));
+ clk_osm_write_reg(c, c->cluster_num == 0 ? PLL_DD_D0_USER_CTL_LO
+ : PLL_DD_D1_USER_CTL_LO, SEQ_REG(21));
+
+ /* PLL lock detect and HMSS AHB clock workaround */
+ clk_osm_write_reg(c, 0x640, CFG_DELAY_VAL_3);
+
+ /* DxFSM workaround */
+ clk_osm_write_reg(c, c->cluster_num == 0 ? 0x17911200 :
+ 0x17811200, SEQ_REG(22));
+ clk_osm_write_reg(c, 0x80800, SEQ_REG(23));
+ clk_osm_write_reg(c, 0x179D1100, SEQ_REG(24));
+ clk_osm_write_reg(c, 0x11f, SEQ_REG(25));
+ clk_osm_write_reg(c, c->cluster_num == 0 ? 0x17912000 :
+ 0x17811290, SEQ_REG(26));
+ clk_osm_write_reg(c, c->cluster_num == 0 ? 0x17911290 :
+ 0x17811290, SEQ_REG(20));
+ clk_osm_write_reg(c, c->cluster_num == 0 ? 0x17811290 :
+ 0x17911290, SEQ_REG(32));
+ clk_osm_write_reg(c, 0x179D4020, SEQ_REG(35));
+ clk_osm_write_reg(c, 0x11f, SEQ_REG(25));
+ clk_osm_write_reg(c, 0xa, SEQ_REG(86));
+ clk_osm_write_reg(c, 0xe, SEQ_REG(87));
+ clk_osm_write_reg(c, 0x00400000, SEQ_REG(88));
+ clk_osm_write_reg(c, 0x00700000, SEQ_REG(89));
+ } else {
+ scm_io_write(c->pbases[OSM_BASE] + SEQ_REG(47), val);
+ val &= ~IGNORE_PLL_LOCK_MASK;
+ scm_io_write(c->pbases[OSM_BASE] + SEQ_REG(48), val);
+
+ /* C2D/C3 + D2D workaround */
+ scm_io_write(c->pbases[OSM_BASE] + SEQ_REG(7),
+ cc_hyst);
+
+ /* Droop detector PLL lock detect workaround */
+ scm_io_write(c->pbases[OSM_BASE] + SEQ_REG(4),
+ PLL_DD_USER_CTL_LO_ENABLE);
+ }
+
+ if (c->cluster_num == 0) {
+ val = readl_relaxed(c->vbases[PLL_BASE] + PLL_TEST_CTL_HI)
+ | BIT(13);
+ writel_relaxed(val, c->vbases[PLL_BASE] +
+ PLL_TEST_CTL_HI);
+ }
+
+ /* Ensure writes complete before returning */
+ clk_osm_mb(c, OSM_BASE);
+}
+
+static void clk_osm_setup_fsms(struct clk_osm *c)
+{
+ u32 val;
+
+ /* Reduction FSM */
+ if (c->red_fsm_en) {
+ val = clk_osm_read_reg(c, VMIN_REDUC_ENABLE_REG) | BIT(0);
+ clk_osm_write_reg(c, val, VMIN_REDUC_ENABLE_REG);
+ clk_osm_write_reg(c, BVAL(15, 0, clk_osm_count_ns(c, 10000)),
+ VMIN_REDUC_TIMER_REG);
+ }
+
+ /* Boost FSM */
+ if (c->boost_fsm_en) {
+ val = clk_osm_read_reg(c, PDN_FSM_CTRL_REG);
+ clk_osm_write_reg(c, val | CC_BOOST_EN_MASK, PDN_FSM_CTRL_REG);
+
+ val = clk_osm_read_reg(c, CC_BOOST_TIMER_REG0);
+ val |= BVAL(15, 0, clk_osm_count_ns(c, PLL_WAIT_LOCK_TIME_NS));
+ val |= BVAL(31, 16, clk_osm_count_ns(c, SAFE_FREQ_WAIT_NS));
+ clk_osm_write_reg(c, val, CC_BOOST_TIMER_REG0);
+
+ val = clk_osm_read_reg(c, CC_BOOST_TIMER_REG1);
+ val |= BVAL(15, 0, clk_osm_count_ns(c, PLL_WAIT_LOCK_TIME_NS));
+ val |= BVAL(31, 16, clk_osm_count_ns(c, PLL_WAIT_LOCK_TIME_NS));
+ clk_osm_write_reg(c, val, CC_BOOST_TIMER_REG1);
+
+ val = clk_osm_read_reg(c, CC_BOOST_TIMER_REG2);
+ val |= BVAL(15, 0, clk_osm_count_ns(c, DEXT_DECREMENT_WAIT_NS));
+ clk_osm_write_reg(c, val, CC_BOOST_TIMER_REG2);
+ }
+
+ /* Safe Freq FSM */
+ if (c->safe_fsm_en) {
+ val = clk_osm_read_reg(c, PDN_FSM_CTRL_REG);
+ clk_osm_write_reg(c, val | DCVS_BOOST_EN_MASK,
+ PDN_FSM_CTRL_REG);
+
+ val = clk_osm_read_reg(c, DCVS_BOOST_TIMER_REG0);
+ val |= BVAL(15, 0, clk_osm_count_ns(c, PLL_WAIT_LOCK_TIME_NS));
+ val |= BVAL(31, 16, clk_osm_count_ns(c, SAFE_FREQ_WAIT_NS));
+ clk_osm_write_reg(c, val, DCVS_BOOST_TIMER_REG0);
+
+ val = clk_osm_read_reg(c, DCVS_BOOST_TIMER_REG1);
+ val |= BVAL(15, 0, clk_osm_count_ns(c, PLL_WAIT_LOCK_TIME_NS));
+ val |= BVAL(31, 16, clk_osm_count_ns(c, PLL_WAIT_LOCK_TIME_NS));
+ clk_osm_write_reg(c, val, DCVS_BOOST_TIMER_REG1);
+
+ val = clk_osm_read_reg(c, DCVS_BOOST_TIMER_REG2);
+ val |= BVAL(15, 0, clk_osm_count_ns(c, DEXT_DECREMENT_WAIT_NS));
+ clk_osm_write_reg(c, val, DCVS_BOOST_TIMER_REG2);
+
+ }
+
+ /* PS FSM */
+ if (c->ps_fsm_en) {
+ val = clk_osm_read_reg(c, PDN_FSM_CTRL_REG);
+ clk_osm_write_reg(c, val | PS_BOOST_EN_MASK, PDN_FSM_CTRL_REG);
+
+ val = clk_osm_read_reg(c, PS_BOOST_TIMER_REG0);
+ val |= BVAL(15, 0, clk_osm_count_ns(c, PLL_WAIT_LOCK_TIME_NS));
+ val |= BVAL(31, 16, clk_osm_count_ns(c, SAFE_FREQ_WAIT_NS));
+ clk_osm_write_reg(c, val, PS_BOOST_TIMER_REG0);
+
+ val = clk_osm_read_reg(c, PS_BOOST_TIMER_REG1);
+ val |= BVAL(15, 0, clk_osm_count_ns(c, PLL_WAIT_LOCK_TIME_NS));
+ val |= BVAL(31, 16, clk_osm_count_ns(c, PLL_WAIT_LOCK_TIME_NS));
+ clk_osm_write_reg(c, val, PS_BOOST_TIMER_REG1);
+
+ val = clk_osm_read_reg(c, PS_BOOST_TIMER_REG2);
+ val |= BVAL(15, 0, clk_osm_count_ns(c, DEXT_DECREMENT_WAIT_NS));
+ clk_osm_write_reg(c, val, PS_BOOST_TIMER_REG2);
+ }
+
+ /* PLL signal timing control */
+ if (c->boost_fsm_en || c->safe_fsm_en || c->ps_fsm_en)
+ clk_osm_write_reg(c, 0x5, BOOST_PROG_SYNC_DELAY_REG);
+
+ /* Droop FSM */
+ if (c->wfx_fsm_en) {
+ /* WFx FSM */
+ val = clk_osm_read_reg(c, PDN_FSM_CTRL_REG);
+ clk_osm_write_reg(c, val | WFX_DROOP_EN_MASK, PDN_FSM_CTRL_REG);
+
+ val = clk_osm_read_reg(c, DROOP_UNSTALL_TIMER_CTRL_REG);
+ val |= BVAL(31, 16, clk_osm_count_ns(c, 500));
+ clk_osm_write_reg(c, val, DROOP_UNSTALL_TIMER_CTRL_REG);
+
+ val = clk_osm_read_reg(c,
+ DROOP_WAIT_TO_RELEASE_TIMER_CTRL0_REG);
+ val |= BVAL(31, 16, clk_osm_count_ns(c, 250));
+ clk_osm_write_reg(c, val,
+ DROOP_WAIT_TO_RELEASE_TIMER_CTRL0_REG);
+ }
+
+ /* PC/RET FSM */
+ if (c->pc_fsm_en) {
+ val = clk_osm_read_reg(c, PDN_FSM_CTRL_REG);
+ clk_osm_write_reg(c, val | PC_RET_EXIT_DROOP_EN_MASK,
+ PDN_FSM_CTRL_REG);
+
+ val = clk_osm_read_reg(c, DROOP_UNSTALL_TIMER_CTRL_REG);
+ val |= BVAL(15, 0, clk_osm_count_ns(c, 500));
+ clk_osm_write_reg(c, val, DROOP_UNSTALL_TIMER_CTRL_REG);
+
+ val = clk_osm_read_reg(c,
+ DROOP_WAIT_TO_RELEASE_TIMER_CTRL0_REG);
+ val |= BVAL(15, 0, clk_osm_count_ns(c, 250));
+ clk_osm_write_reg(c, val,
+ DROOP_WAIT_TO_RELEASE_TIMER_CTRL0_REG);
+ }
+
+ /* DCVS droop FSM - only if RCGwRC is not used for di/dt control */
+ if (c->droop_fsm_en) {
+ val = clk_osm_read_reg(c, PDN_FSM_CTRL_REG);
+ clk_osm_write_reg(c, val | DCVS_DROOP_EN_MASK,
+ PDN_FSM_CTRL_REG);
+ }
+
+ if (c->wfx_fsm_en || c->ps_fsm_en || c->droop_fsm_en) {
+ clk_osm_write_reg(c, 0x1, DROOP_PROG_SYNC_DELAY_REG);
+ clk_osm_write_reg(c, clk_osm_count_ns(c, 5),
+ DROOP_RELEASE_TIMER_CTRL);
+ clk_osm_write_reg(c, clk_osm_count_ns(c, 500),
+ DCVS_DROOP_TIMER_CTRL);
+ val = clk_osm_read_reg(c, DROOP_CTRL_REG);
+ val |= BIT(31) | BVAL(22, 16, 0x2) |
+ BVAL(6, 0, 0x8);
+ clk_osm_write_reg(c, val, DROOP_CTRL_REG);
+ }
+
+ /* Enable the PLL Droop Override */
+ val = clk_osm_read_reg(c, OSM_PLL_SW_OVERRIDE_EN);
+ val |= PLL_SW_OVERRIDE_DROOP_EN;
+ clk_osm_write_reg(c, val, OSM_PLL_SW_OVERRIDE_EN);
+}
+
+static void clk_osm_do_additional_setup(struct clk_osm *c,
+ struct platform_device *pdev)
+{
+ if (!c->secure_init)
+ return;
+
+ dev_info(&pdev->dev, "Performing additional OSM setup due to lack of TZ for cluster=%d\n",
+ c->cluster_num);
+
+ clk_osm_write_reg(c, BVAL(23, 16, 0xF), SPM_CC_CTRL);
+
+ /* PLL LVAL programming */
+ clk_osm_write_reg(c, c->l_val_base, SEQ_REG(0));
+ clk_osm_write_reg(c, PLL_MIN_LVAL, SEQ_REG(21));
+
+ /* PLL post-div programming */
+ clk_osm_write_reg(c, c->apcs_pll_user_ctl, SEQ_REG(18));
+ clk_osm_write_reg(c, PLL_POST_DIV2, SEQ_REG(19));
+ clk_osm_write_reg(c, PLL_POST_DIV1, SEQ_REG(29));
+
+ /* APM Programming */
+ clk_osm_program_apm_regs(c);
+
+ /* GFMUX Programming */
+ clk_osm_write_reg(c, c->apcs_cfg_rcgr, SEQ_REG(16));
+ clk_osm_write_reg(c, c->apcs_cmd_rcgr, SEQ_REG(33));
+ clk_osm_write_reg(c, RCG_UPDATE, SEQ_REG(34));
+ clk_osm_write_reg(c, GPLL_SEL, SEQ_REG(17));
+ clk_osm_write_reg(c, PLL_EARLY_SEL, SEQ_REG(82));
+ clk_osm_write_reg(c, PLL_MAIN_SEL, SEQ_REG(83));
+ clk_osm_write_reg(c, RCG_UPDATE_SUCCESS, SEQ_REG(84));
+ clk_osm_write_reg(c, RCG_UPDATE, SEQ_REG(85));
+
+ /* ITM to OSM handoff */
+ clk_osm_setup_itm_to_osm_handoff();
+
+ pr_debug("seq_size: %lu, seqbr_size: %lu\n", ARRAY_SIZE(seq_instr),
+ ARRAY_SIZE(seq_br_instr));
+ clk_osm_setup_sequencer(&pwrcl_clk);
+ clk_osm_setup_sequencer(&perfcl_clk);
+}
+
+static void clk_osm_apm_vc_setup(struct clk_osm *c)
+{
+ /*
+ * APM crossover virtual corner corresponds to switching
+ * voltage during APM transition. APM threshold virtual
+ * corner is the first corner which requires switch
+ * sequence of APM from MX to APC.
+ */
+ if (c->secure_init) {
+ clk_osm_write_reg(c, c->apm_threshold_vc, SEQ_REG(1));
+ clk_osm_write_reg(c, c->apm_crossover_vc, SEQ_REG(72));
+ clk_osm_write_reg(c, c->pbases[OSM_BASE] + SEQ_REG(1),
+ SEQ_REG(8));
+ clk_osm_write_reg(c, c->apm_threshold_vc,
+ SEQ_REG(15));
+ clk_osm_write_reg(c, c->apm_threshold_vc != 0 ?
+ c->apm_threshold_vc - 1 : 0xff,
+ SEQ_REG(31));
+ clk_osm_write_reg(c, 0x3b | c->apm_threshold_vc << 6,
+ SEQ_REG(73));
+ clk_osm_write_reg(c, 0x39 | c->apm_threshold_vc << 6,
+ SEQ_REG(76));
+
+ /* Ensure writes complete before returning */
+ clk_osm_mb(c, OSM_BASE);
+ } else {
+ if (msmcobalt_v1) {
+ scm_io_write(c->pbases[OSM_BASE] + SEQ_REG(1),
+ c->apm_threshold_vc);
+ scm_io_write(c->pbases[OSM_BASE] + SEQ_REG(73),
+ 0x3b | c->apm_threshold_vc << 6);
+ } else if (msmcobalt_v2) {
+ clk_osm_write_reg(c, c->apm_threshold_vc,
+ SEQ_REG1_MSMCOBALT_V2);
+ }
+ scm_io_write(c->pbases[OSM_BASE] + SEQ_REG(72),
+ c->apm_crossover_vc);
+ scm_io_write(c->pbases[OSM_BASE] + SEQ_REG(15),
+ c->apm_threshold_vc);
+ scm_io_write(c->pbases[OSM_BASE] + SEQ_REG(31),
+ c->apm_threshold_vc != 0 ?
+ c->apm_threshold_vc - 1 : 0xff);
+ scm_io_write(c->pbases[OSM_BASE] + SEQ_REG(76),
+ 0x39 | c->apm_threshold_vc << 6);
+ }
+}
+
+static irqreturn_t clk_osm_debug_irq_cb(int irq, void *data)
+{
+ struct clk_osm *c = data;
+ unsigned long first, second, total_delta = 0;
+ u32 val, factor;
+ int i;
+
+ val = clk_osm_read_reg(c, DCVS_PERF_STATE_DEVIATION_INTR_STAT);
+ if (val & BIT(0)) {
+ pr_info("OS DCVS performance state deviated\n");
+ clk_osm_write_reg(c, BIT(0),
+ DCVS_PERF_STATE_DEVIATION_INTR_CLEAR);
+ }
+
+ val = clk_osm_read_reg(c,
+ DCVS_PERF_STATE_DEVIATION_CORRECTED_INTR_STAT);
+ if (val & BIT(0)) {
+ pr_info("OS DCVS performance state corrected\n");
+ clk_osm_write_reg(c, BIT(0),
+ DCVS_PERF_STATE_DEVIATION_CORRECTED_INTR_CLEAR);
+ }
+
+ val = clk_osm_read_reg(c, DCVS_PERF_STATE_MET_INTR_STAT);
+ if (val & BIT(0)) {
+ pr_info("OS DCVS performance state desired reached\n");
+ clk_osm_write_reg(c, BIT(0), DCVS_PERF_STATE_MET_INTR_CLR);
+ }
+
+ factor = c->cycle_counter_factor ? c->cycle_counter_factor : 1;
+
+ for (i = 0; i < c->cycle_counter_reads; i++) {
+ first = clk_osm_read_reg(c, OSM_CYCLE_COUNTER_STATUS_REG);
+
+ if (c->cycle_counter_delay)
+ udelay(c->cycle_counter_delay);
+
+ second = clk_osm_read_reg(c, OSM_CYCLE_COUNTER_STATUS_REG);
+ total_delta = total_delta + ((second - first) / factor);
+ }
+
+ pr_info("cluster=%d, L_VAL (estimated)=%lu\n",
+ c->cluster_num, total_delta / c->cycle_counter_factor);
+
+ return IRQ_HANDLED;
+}
+
+static int clk_osm_setup_irq(struct platform_device *pdev, struct clk_osm *c,
+ char *irq_name)
+{
+ int rc = 0;
+
+ rc = c->irq = platform_get_irq_byname(pdev, irq_name);
+ if (rc < 0) {
+ dev_err(&pdev->dev, "%s irq not specified\n", irq_name);
+ return rc;
+ }
+
+ rc = devm_request_irq(&pdev->dev, c->irq,
+ clk_osm_debug_irq_cb,
+ IRQF_TRIGGER_RISING | IRQF_SHARED,
+ "OSM IRQ", c);
+ if (rc)
+ dev_err(&pdev->dev, "Request IRQ failed for OSM IRQ\n");
+
+ return rc;
+}
+
+static u32 find_voltage(struct clk_osm *c, unsigned long rate)
+{
+ struct osm_entry *table = c->osm_table;
+ int entries = c->num_entries, i;
+
+ for (i = 0; i < entries; i++) {
+ if (rate == table[i].frequency) {
+ /* OPP table voltages have units of mV */
+ return table[i].open_loop_volt * 1000;
+ }
+ }
+
+ return -EINVAL;
+}
+
+static int add_opp(struct clk_osm *c, struct device *dev)
+{
+ unsigned long rate = 0;
+ u32 uv;
+ long rc;
+ int j = 0;
+ unsigned long min_rate = c->c.fmax[0];
+ unsigned long max_rate = c->c.fmax[c->c.num_fmax - 1];
+
+ while (1) {
+ rate = c->c.fmax[j++];
+ uv = find_voltage(c, rate);
+ if (uv <= 0) {
+ pr_warn("No voltage for %lu.\n", rate);
+ return -EINVAL;
+ }
+
+ rc = dev_pm_opp_add(dev, rate, uv);
+ if (rc) {
+ pr_warn("failed to add OPP for %lu\n", rate);
+ return rc;
+ }
+
+ /*
+ * Print the OPP pair for the lowest and highest frequency for
+ * each device that we're populating. This is important since
+ * this information will be used by thermal mitigation and the
+ * scheduler.
+ */
+ if (rate == min_rate)
+ pr_info("Set OPP pair (%lu Hz, %d uv) on %s\n",
+ rate, uv, dev_name(dev));
+
+ if (rate == max_rate && max_rate != min_rate) {
+ pr_info("Set OPP pair (%lu Hz, %d uv) on %s\n",
+ rate, uv, dev_name(dev));
+ break;
+ }
+
+ if (min_rate == max_rate)
+ break;
+ }
+
+ return 0;
+}
+
+static struct clk *logical_cpu_to_clk(int cpu)
+{
+ struct device_node *cpu_node;
+ const u32 *cell;
+ u64 hwid;
+ static struct clk *cpu_clk_map[NR_CPUS];
+
+ if (cpu_clk_map[cpu])
+ return cpu_clk_map[cpu];
+
+ cpu_node = of_get_cpu_node(cpu, NULL);
+ if (!cpu_node)
+ goto fail;
+
+ cell = of_get_property(cpu_node, "reg", NULL);
+ if (!cell) {
+ pr_err("%s: missing reg property\n", cpu_node->full_name);
+ goto fail;
+ }
+
+ hwid = of_read_number(cell, of_n_addr_cells(cpu_node));
+ if ((hwid | pwrcl_clk.cpu_reg_mask) == pwrcl_clk.cpu_reg_mask) {
+ cpu_clk_map[cpu] = &pwrcl_clk.c;
+ return &pwrcl_clk.c;
+ }
+ if ((hwid | perfcl_clk.cpu_reg_mask) == perfcl_clk.cpu_reg_mask) {
+ cpu_clk_map[cpu] = &perfcl_clk.c;
+ return &perfcl_clk.c;
+ }
+
+fail:
+ return NULL;
+}
+
+static u64 clk_osm_get_cpu_cycle_counter(int cpu)
+{
+ struct clk_osm *c;
+ u32 val;
+ unsigned long flags;
+
+ if (logical_cpu_to_clk(cpu) == &pwrcl_clk.c)
+ c = &pwrcl_clk;
+ else if (logical_cpu_to_clk(cpu) == &perfcl_clk.c)
+ c = &perfcl_clk;
+ else {
+ pr_err("no clock device for CPU=%d\n", cpu);
+ return 0;
+ }
+
+ spin_lock_irqsave(&c->lock, flags);
+ val = clk_osm_read_reg_no_log(c, OSM_CYCLE_COUNTER_STATUS_REG);
+
+ if (val < c->prev_cycle_counter) {
+ /* Handle counter overflow */
+ c->total_cycle_counter += UINT_MAX -
+ c->prev_cycle_counter + val;
+ c->prev_cycle_counter = val;
+ } else {
+ c->total_cycle_counter += val - c->prev_cycle_counter;
+ c->prev_cycle_counter = val;
+ }
+ spin_unlock_irqrestore(&c->lock, flags);
+
+ return c->total_cycle_counter;
+}
+
+static void populate_opp_table(struct platform_device *pdev)
+{
+ int cpu;
+
+ for_each_possible_cpu(cpu) {
+ if (logical_cpu_to_clk(cpu) == &pwrcl_clk.c) {
+ WARN(add_opp(&pwrcl_clk, get_cpu_device(cpu)),
+ "Failed to add OPP levels for power cluster\n");
+ }
+ if (logical_cpu_to_clk(cpu) == &perfcl_clk.c) {
+ WARN(add_opp(&perfcl_clk, get_cpu_device(cpu)),
+ "Failed to add OPP levels for perf cluster\n");
+ }
+ }
+}
+
+static int debugfs_get_trace_enable(void *data, u64 *val)
+{
+ struct clk_osm *c = data;
+
+ *val = c->trace_en;
+ return 0;
+}
+
+static int debugfs_set_trace_enable(void *data, u64 val)
+{
+ struct clk_osm *c = data;
+
+ clk_osm_masked_write_reg(c, val ? TRACE_CTRL_ENABLE :
+ TRACE_CTRL_DISABLE,
+ TRACE_CTRL, TRACE_CTRL_EN_MASK);
+ c->trace_en = val ? true : false;
+ return 0;
+}
+DEFINE_SIMPLE_ATTRIBUTE(debugfs_trace_enable_fops,
+ debugfs_get_trace_enable,
+ debugfs_set_trace_enable,
+ "%llu\n");
+
+static int debugfs_get_wdog_trace(void *data, u64 *val)
+{
+ struct clk_osm *c = data;
+
+ *val = c->wdog_trace_en;
+ return 0;
+}
+
+static int debugfs_set_wdog_trace(void *data, u64 val)
+{
+ struct clk_osm *c = data;
+ int regval;
+
+ if (c->version >= VERSION_1P1) {
+ regval = clk_osm_read_reg(c, TRACE_CTRL);
+ regval = val ? regval | TRACE_CTRL_ENABLE_WDOG_STATUS :
+ regval & ~TRACE_CTRL_ENABLE_WDOG_STATUS;
+ clk_osm_write_reg(c, regval, TRACE_CTRL);
+ c->wdog_trace_en = val ? true : false;
+ } else {
+ pr_info("wdog status registers enabled by default\n");
+ }
+
+ return 0;
+}
+DEFINE_SIMPLE_ATTRIBUTE(debugfs_trace_wdog_enable_fops,
+ debugfs_get_wdog_trace,
+ debugfs_set_wdog_trace,
+ "%llu\n");
+
+#define MAX_DEBUG_BUF_LEN 15
+
+static DEFINE_MUTEX(debug_buf_mutex);
+static char debug_buf[MAX_DEBUG_BUF_LEN];
+
+static ssize_t debugfs_trace_method_set(struct file *file,
+ const char __user *buf,
+ size_t count, loff_t *ppos)
+{
+ struct clk_osm *c = file->private_data;
+ u32 val;
+
+ if (IS_ERR(file) || file == NULL) {
+ pr_err("input error %ld\n", PTR_ERR(file));
+ return -EINVAL;
+ }
+
+ if (!c) {
+ pr_err("invalid clk_osm handle\n");
+ return -EINVAL;
+ }
+
+ if (count < MAX_DEBUG_BUF_LEN) {
+ mutex_lock(&debug_buf_mutex);
+
+ if (copy_from_user(debug_buf, (void __user *) buf, count)) {
+ mutex_unlock(&debug_buf_mutex);
+ return -EFAULT;
+ }
+ debug_buf[count] = '\0';
+ mutex_unlock(&debug_buf_mutex);
+
+ /* check that user entered a supported packet type */
+ if (strcmp(debug_buf, "periodic\n") == 0) {
+ clk_osm_write_reg(c, clk_osm_count_ns(c,
+ PERIODIC_TRACE_DEFAULT_NS),
+ PERIODIC_TRACE_TIMER_CTRL);
+ clk_osm_masked_write_reg(c,
+ TRACE_CTRL_PERIODIC_TRACE_ENABLE,
+ TRACE_CTRL, TRACE_CTRL_PERIODIC_TRACE_EN_MASK);
+ c->trace_method = PERIODIC_PACKET;
+ c->trace_periodic_timer = PERIODIC_TRACE_DEFAULT_NS;
+ return count;
+ } else if (strcmp(debug_buf, "xor\n") == 0) {
+ val = clk_osm_read_reg(c, TRACE_CTRL);
+ val &= ~TRACE_CTRL_PERIODIC_TRACE_ENABLE;
+ clk_osm_write_reg(c, val, TRACE_CTRL);
+ c->trace_method = XOR_PACKET;
+ return count;
+ }
+ }
+
+ pr_err("error, supported trace mode types: 'periodic' or 'xor'\n");
+ return -EINVAL;
+}
+
+static ssize_t debugfs_trace_method_get(struct file *file, char __user *buf,
+ size_t count, loff_t *ppos)
+{
+ struct clk_osm *c = file->private_data;
+ int len, rc;
+
+ if (IS_ERR(file) || file == NULL) {
+ pr_err("input error %ld\n", PTR_ERR(file));
+ return -EINVAL;
+ }
+
+ if (!c) {
+ pr_err("invalid clk_osm handle\n");
+ return -EINVAL;
+ }
+
+ mutex_lock(&debug_buf_mutex);
+
+ if (c->trace_method == PERIODIC_PACKET)
+ len = snprintf(debug_buf, sizeof(debug_buf), "periodic\n");
+ else if (c->trace_method == XOR_PACKET)
+ len = snprintf(debug_buf, sizeof(debug_buf), "xor\n");
+
+ rc = simple_read_from_buffer((void __user *) buf, len, ppos,
+ (void *) debug_buf, len);
+
+ mutex_unlock(&debug_buf_mutex);
+
+ return rc;
+}
+
+static int debugfs_trace_method_open(struct inode *inode, struct file *file)
+{
+ if (IS_ERR(file) || file == NULL) {
+ pr_err("input error %ld\n", PTR_ERR(file));
+ return -EINVAL;
+ }
+
+ file->private_data = inode->i_private;
+ return 0;
+}
+
+static const struct file_operations debugfs_trace_method_fops = {
+ .write = debugfs_trace_method_set,
+ .open = debugfs_trace_method_open,
+ .read = debugfs_trace_method_get,
+};
+
+static int debugfs_get_trace_packet_id(void *data, u64 *val)
+{
+ struct clk_osm *c = data;
+
+ *val = c->trace_id;
+ return 0;
+}
+
+static int debugfs_set_trace_packet_id(void *data, u64 val)
+{
+ struct clk_osm *c = data;
+
+ if (val < TRACE_PACKET0 || val > TRACE_PACKET3) {
+ pr_err("supported trace IDs=%d-%d\n",
+ TRACE_PACKET0, TRACE_PACKET3);
+ return 0;
+ }
+
+ clk_osm_masked_write_reg(c, val << TRACE_CTRL_PACKET_TYPE_SHIFT,
+ TRACE_CTRL, TRACE_CTRL_PACKET_TYPE_MASK);
+ c->trace_id = val;
+ return 0;
+}
+DEFINE_SIMPLE_ATTRIBUTE(debugfs_trace_packet_id_fops,
+ debugfs_get_trace_packet_id,
+ debugfs_set_trace_packet_id,
+ "%llu\n");
+
+static int debugfs_get_trace_periodic_timer(void *data, u64 *val)
+{
+ struct clk_osm *c = data;
+
+ *val = c->trace_periodic_timer;
+ return 0;
+}
+
+static int debugfs_set_trace_periodic_timer(void *data, u64 val)
+{
+ struct clk_osm *c = data;
+
+ if (val < PERIODIC_TRACE_MIN_NS || val > PERIODIC_TRACE_MAX_NS) {
+ pr_err("supported periodic trace periods=%d-%ld ns\n",
+ PERIODIC_TRACE_MIN_NS, PERIODIC_TRACE_MAX_NS);
+ return 0;
+ }
+
+ clk_osm_write_reg(c, clk_osm_count_ns(c, val),
+ PERIODIC_TRACE_TIMER_CTRL);
+ c->trace_periodic_timer = val;
+ return 0;
+}
+DEFINE_SIMPLE_ATTRIBUTE(debugfs_trace_periodic_timer_fops,
+ debugfs_get_trace_periodic_timer,
+ debugfs_set_trace_periodic_timer,
+ "%llu\n");
+
+static int debugfs_get_perf_state_met_irq(void *data, u64 *val)
+{
+ struct clk_osm *c = data;
+
+ *val = clk_osm_read_reg(c, DCVS_PERF_STATE_MET_INTR_EN);
+ return 0;
+}
+
+static int debugfs_set_perf_state_met_irq(void *data, u64 val)
+{
+ struct clk_osm *c = data;
+
+ clk_osm_write_reg(c, val ? 1 : 0,
+ DCVS_PERF_STATE_MET_INTR_EN);
+ return 0;
+}
+DEFINE_SIMPLE_ATTRIBUTE(debugfs_perf_state_met_irq_fops,
+ debugfs_get_perf_state_met_irq,
+ debugfs_set_perf_state_met_irq,
+ "%llu\n");
+
+static int debugfs_get_perf_state_deviation_irq(void *data, u64 *val)
+{
+ struct clk_osm *c = data;
+
+ *val = clk_osm_read_reg(c,
+ DCVS_PERF_STATE_DEVIATION_INTR_EN);
+ return 0;
+}
+
+static int debugfs_set_perf_state_deviation_irq(void *data, u64 val)
+{
+ struct clk_osm *c = data;
+
+ clk_osm_write_reg(c, val ? 1 : 0,
+ DCVS_PERF_STATE_DEVIATION_INTR_EN);
+ return 0;
+}
+DEFINE_SIMPLE_ATTRIBUTE(debugfs_perf_state_deviation_irq_fops,
+ debugfs_get_perf_state_deviation_irq,
+ debugfs_set_perf_state_deviation_irq,
+ "%llu\n");
+
+static int debugfs_get_perf_state_deviation_corrected_irq(void *data, u64 *val)
+{
+ struct clk_osm *c = data;
+
+ *val = clk_osm_read_reg(c,
+ DCVS_PERF_STATE_DEVIATION_CORRECTED_INTR_EN);
+ return 0;
+}
+
+static int debugfs_set_perf_state_deviation_corrected_irq(void *data, u64 val)
+{
+ struct clk_osm *c = data;
+
+ clk_osm_write_reg(c, val ? 1 : 0,
+ DCVS_PERF_STATE_DEVIATION_CORRECTED_INTR_EN);
+ return 0;
+}
+DEFINE_SIMPLE_ATTRIBUTE(debugfs_perf_state_deviation_corrected_irq_fops,
+ debugfs_get_perf_state_deviation_corrected_irq,
+ debugfs_set_perf_state_deviation_corrected_irq,
+ "%llu\n");
+
+static int debugfs_get_debug_reg(void *data, u64 *val)
+{
+ struct clk_osm *c = data;
+
+ if (c->acd_debugfs_addr >= ACD_MASTER_ONLY_REG_ADDR)
+ *val = readl_relaxed((char *)c->vbases[ACD_BASE] +
+ c->acd_debugfs_addr);
+ else
+ *val = clk_osm_acd_local_read_reg(c, c->acd_debugfs_addr);
+ return 0;
+}
+
+static int debugfs_set_debug_reg(void *data, u64 val)
+{
+ struct clk_osm *c = data;
+
+ if (c->acd_debugfs_addr >= ACD_MASTER_ONLY_REG_ADDR)
+ clk_osm_acd_master_write_reg(c, val, c->acd_debugfs_addr);
+ else
+ clk_osm_acd_master_write_through_reg(c, val,
+ c->acd_debugfs_addr);
+
+ return 0;
+}
+DEFINE_SIMPLE_ATTRIBUTE(debugfs_acd_debug_reg_fops,
+ debugfs_get_debug_reg,
+ debugfs_set_debug_reg,
+ "0x%llx\n");
+
+static int debugfs_get_debug_reg_addr(void *data, u64 *val)
+{
+ struct clk_osm *c = data;
+
+ *val = c->acd_debugfs_addr;
+ return 0;
+}
+
+static int debugfs_set_debug_reg_addr(void *data, u64 val)
+{
+ struct clk_osm *c = data;
+
+ c->acd_debugfs_addr = val;
+ return 0;
+}
+DEFINE_SIMPLE_ATTRIBUTE(debugfs_acd_debug_reg_addr_fops,
+ debugfs_get_debug_reg_addr,
+ debugfs_set_debug_reg_addr,
+ "%llu\n");
+
+static void populate_debugfs_dir(struct clk_osm *c)
+{
+ struct dentry *temp;
+
+ if (osm_debugfs_base == NULL) {
+ osm_debugfs_base = debugfs_create_dir("osm", NULL);
+ if (IS_ERR_OR_NULL(osm_debugfs_base)) {
+ pr_err("osm debugfs base directory creation failed\n");
+ osm_debugfs_base = NULL;
+ return;
+ }
+ }
+
+ c->debugfs = debugfs_create_dir(c->c.dbg_name, osm_debugfs_base);
+ if (IS_ERR_OR_NULL(c->debugfs)) {
+ pr_err("osm debugfs directory creation failed\n");
+ return;
+ }
+
+ temp = debugfs_create_file("perf_state_met_irq_enable",
+ S_IRUGO | S_IWUSR,
+ c->debugfs, c,
+ &debugfs_perf_state_met_irq_fops);
+ if (IS_ERR_OR_NULL(temp)) {
+ pr_err("perf_state_met_irq_enable debugfs file creation failed\n");
+ goto exit;
+ }
+
+ temp = debugfs_create_file("perf_state_deviation_irq_enable",
+ S_IRUGO | S_IWUSR,
+ c->debugfs, c,
+ &debugfs_perf_state_deviation_irq_fops);
+ if (IS_ERR_OR_NULL(temp)) {
+ pr_err("perf_state_deviation_irq_enable debugfs file creation failed\n");
+ goto exit;
+ }
+
+ temp = debugfs_create_file("perf_state_deviation_corrected_irq_enable",
+ S_IRUGO | S_IWUSR,
+ c->debugfs, c,
+ &debugfs_perf_state_deviation_corrected_irq_fops);
+ if (IS_ERR_OR_NULL(temp)) {
+ pr_err("debugfs_perf_state_deviation_corrected_irq_fops debugfs file creation failed\n");
+ goto exit;
+ }
+
+ temp = debugfs_create_file("wdog_trace_enable",
+ S_IRUGO | S_IWUSR,
+ c->debugfs, c,
+ &debugfs_trace_wdog_enable_fops);
+ if (IS_ERR_OR_NULL(temp)) {
+ pr_err("debugfs_trace_wdog_enable_fops debugfs file creation failed\n");
+ goto exit;
+ }
+
+ temp = debugfs_create_file("trace_enable",
+ S_IRUGO | S_IWUSR,
+ c->debugfs, c,
+ &debugfs_trace_enable_fops);
+ if (IS_ERR_OR_NULL(temp)) {
+ pr_err("debugfs_trace_enable_fops debugfs file creation failed\n");
+ goto exit;
+ }
+
+ temp = debugfs_create_file("trace_method",
+ S_IRUGO | S_IWUSR,
+ c->debugfs, c,
+ &debugfs_trace_method_fops);
+ if (IS_ERR_OR_NULL(temp)) {
+ pr_err("debugfs_trace_method_fops debugfs file creation failed\n");
+ goto exit;
+ }
+
+ temp = debugfs_create_file("trace_packet_id",
+ S_IRUGO | S_IWUSR,
+ c->debugfs, c,
+ &debugfs_trace_packet_id_fops);
+ if (IS_ERR_OR_NULL(temp)) {
+ pr_err("debugfs_trace_packet_id_fops debugfs file creation failed\n");
+ goto exit;
+ }
+
+ temp = debugfs_create_file("trace_periodic_timer",
+ S_IRUGO | S_IWUSR,
+ c->debugfs, c,
+ &debugfs_trace_periodic_timer_fops);
+ if (IS_ERR_OR_NULL(temp)) {
+ pr_err("debugfs_trace_periodic_timer_fops debugfs file creation failed\n");
+ goto exit;
+ }
+
+ temp = debugfs_create_file("acd_debug_reg",
+ S_IRUGO | S_IWUSR,
+ c->debugfs, c,
+ &debugfs_acd_debug_reg_fops);
+ if (IS_ERR_OR_NULL(temp)) {
+ pr_err("debugfs_acd_debug_reg_fops debugfs file creation failed\n");
+ goto exit;
+ }
+
+ temp = debugfs_create_file("acd_debug_reg_addr",
+ S_IRUGO | S_IWUSR,
+ c->debugfs, c,
+ &debugfs_acd_debug_reg_addr_fops);
+ if (IS_ERR_OR_NULL(temp)) {
+ pr_err("debugfs_acd_debug_reg_addr_fops debugfs file creation failed\n");
+ goto exit;
+ }
+
+exit:
+ if (IS_ERR_OR_NULL(temp))
+ debugfs_remove_recursive(c->debugfs);
+}
+
+static int clk_osm_panic_callback(struct notifier_block *nfb,
+ unsigned long event,
+ void *data)
+{
+ void __iomem *virt_addr;
+ u32 value, reg;
+ struct clk_osm *c = container_of(nfb,
+ struct clk_osm,
+ panic_notifier);
+
+ reg = c->pbases[OSM_BASE] + WDOG_DOMAIN_PSTATE_STATUS;
+ virt_addr = ioremap(reg, 0x4);
+ if (virt_addr != NULL) {
+ value = readl_relaxed(virt_addr);
+ pr_err("DOM%d_PSTATE_STATUS[0x%08x]=0x%08x\n", c->cluster_num,
+ reg, value);
+ iounmap(virt_addr);
+ }
+
+ reg = c->pbases[OSM_BASE] + WDOG_PROGRAM_COUNTER;
+ virt_addr = ioremap(reg, 0x4);
+ if (virt_addr != NULL) {
+ value = readl_relaxed(virt_addr);
+ pr_err("DOM%d_PROGRAM_COUNTER[0x%08x]=0x%08x\n", c->cluster_num,
+ reg, value);
+ iounmap(virt_addr);
+ }
+
+ virt_addr = ioremap(c->apm_ctrl_status, 0x4);
+ if (virt_addr != NULL) {
+ value = readl_relaxed(virt_addr);
+ pr_err("APM_CTLER_STATUS_%d[0x%08x]=0x%08x\n", c->cluster_num,
+ c->apm_ctrl_status, value);
+ iounmap(virt_addr);
+ }
+
+ return NOTIFY_OK;
+}
+
+static int clk_osm_acd_init(struct clk_osm *c)
+{
+
+ int rc = 0;
+ u32 auto_xfer_mask = 0;
+
+ if (!c->acd_init)
+ return 0;
+
+ c->acd_debugfs_addr = ACD_HW_VERSION;
+
+ /* Program ACD tunable-length delay register */
+ clk_osm_acd_master_write_reg(c, c->acd_td, ACDTD);
+ auto_xfer_mask |= ACD_REG_RELATIVE_ADDR_BITMASK(ACDTD);
+
+ /* Program ACD control register */
+ clk_osm_acd_master_write_reg(c, c->acd_cr, ACDCR);
+ auto_xfer_mask |= ACD_REG_RELATIVE_ADDR_BITMASK(ACDCR);
+
+ /* Program ACD soft start control register */
+ clk_osm_acd_master_write_reg(c, c->acd_sscr, ACDSSCR);
+ auto_xfer_mask |= ACD_REG_RELATIVE_ADDR_BITMASK(ACDSSCR);
+
+ /* Program initial ACD external interface configuration register */
+ clk_osm_acd_master_write_reg(c, c->acd_extint0_cfg, ACD_EXTINT_CFG);
+ auto_xfer_mask |= ACD_REG_RELATIVE_ADDR_BITMASK(ACD_EXTINT_CFG);
+
+ /* Program ACD auto-register transfer control register */
+ clk_osm_acd_master_write_reg(c, c->acd_autoxfer_ctl, ACD_AUTOXFER_CTL);
+
+ /* Ensure writes complete before transfers to local copy */
+ clk_osm_acd_mb(c);
+
+ /* Transfer master copies */
+ rc = clk_osm_acd_auto_local_write_reg(c, auto_xfer_mask);
+ if (rc)
+ return rc;
+
+ /* Switch CPUSS clock source to ACD clock */
+ rc = clk_osm_acd_master_write_through_reg(c, ACD_GFMUX_CFG_SELECT,
+ ACD_GFMUX_CFG);
+ if (rc)
+ return rc;
+
+ /* Program ACD_DCVS_SW */
+ rc = clk_osm_acd_master_write_through_reg(c,
+ ACD_DCVS_SW_DCVS_IN_PRGR_SET,
+ ACD_DCVS_SW);
+ if (rc)
+ return rc;
+
+ rc = clk_osm_acd_master_write_through_reg(c,
+ ACD_DCVS_SW_DCVS_IN_PRGR_CLEAR,
+ ACD_DCVS_SW);
+ if (rc)
+ return rc;
+
+ udelay(1);
+
+ /* Program final ACD external interface configuration register */
+ rc = clk_osm_acd_master_write_through_reg(c, c->acd_extint1_cfg,
+ ACD_EXTINT_CFG);
+ if (rc)
+ return rc;
+
+ /*
+ * ACDCR, ACDTD, ACDSSCR, ACD_EXTINT_CFG, ACD_GFMUX_CFG
+ * must be copied from master to local copy on PC exit.
+ */
+ auto_xfer_mask |= ACD_REG_RELATIVE_ADDR_BITMASK(ACD_GFMUX_CFG);
+ clk_osm_acd_master_write_reg(c, auto_xfer_mask, ACD_AUTOXFER_CFG);
+
+ return 0;
+}
+
+static unsigned long init_rate = 300000000;
+static unsigned long osm_clk_init_rate = 200000000;
+
+static int cpu_clock_osm_driver_probe(struct platform_device *pdev)
+{
+ int rc, cpu;
+ int speedbin = 0, pvs_ver = 0;
+ u32 pte_efuse;
+ char pwrclspeedbinstr[] = "qcom,pwrcl-speedbin0-v0";
+ char perfclspeedbinstr[] = "qcom,perfcl-speedbin0-v0";
+ struct cpu_cycle_counter_cb cb = {
+ .get_cpu_cycle_counter = clk_osm_get_cpu_cycle_counter,
+ };
+
+ if (of_find_compatible_node(NULL, NULL,
+ "qcom,cpu-clock-osm-msmcobalt-v1")) {
+ msmcobalt_v1 = true;
+ } else if (of_find_compatible_node(NULL, NULL,
+ "qcom,cpu-clock-osm-msmcobalt-v2")) {
+ msmcobalt_v2 = true;
+ }
+
+ rc = clk_osm_resources_init(pdev);
+ if (rc) {
+ if (rc != -EPROBE_DEFER)
+ dev_err(&pdev->dev, "resources init failed, rc=%d\n",
+ rc);
+ return rc;
+ }
+
+ rc = clk_osm_parse_dt_configs(pdev);
+ if (rc) {
+ dev_err(&pdev->dev, "Unable to parse device tree configurations\n");
+ return rc;
+ }
+
+ if ((pwrcl_clk.secure_init || perfcl_clk.secure_init) &&
+ msmcobalt_v2) {
+ pr_err("unsupported configuration for msmcobalt v2\n");
+ return -EINVAL;
+ }
+
+ if (pwrcl_clk.vbases[EFUSE_BASE]) {
+ /* Multiple speed-bins are supported */
+ pte_efuse = readl_relaxed(pwrcl_clk.vbases[EFUSE_BASE]);
+ speedbin = ((pte_efuse >> PWRCL_EFUSE_SHIFT) &
+ PWRCL_EFUSE_MASK);
+ snprintf(pwrclspeedbinstr, ARRAY_SIZE(pwrclspeedbinstr),
+ "qcom,pwrcl-speedbin%d-v%d", speedbin, pvs_ver);
+ }
+
+ dev_info(&pdev->dev, "using pwrcl speed bin %u and pvs_ver %d\n",
+ speedbin, pvs_ver);
+
+ rc = clk_osm_get_lut(pdev, &pwrcl_clk,
+ pwrclspeedbinstr);
+ if (rc) {
+ dev_err(&pdev->dev, "Unable to get OSM LUT for power cluster, rc=%d\n",
+ rc);
+ return rc;
+ }
+
+ if (perfcl_clk.vbases[EFUSE_BASE]) {
+ /* Multiple speed-bins are supported */
+ pte_efuse = readl_relaxed(perfcl_clk.vbases[EFUSE_BASE]);
+ speedbin = ((pte_efuse >> PERFCL_EFUSE_SHIFT) &
+ PERFCL_EFUSE_MASK);
+ snprintf(perfclspeedbinstr, ARRAY_SIZE(perfclspeedbinstr),
+ "qcom,perfcl-speedbin%d-v%d", speedbin, pvs_ver);
+ }
+
+ dev_info(&pdev->dev, "using perfcl speed bin %u and pvs_ver %d\n",
+ speedbin, pvs_ver);
+
+ rc = clk_osm_get_lut(pdev, &perfcl_clk, perfclspeedbinstr);
+ if (rc) {
+ dev_err(&pdev->dev, "Unable to get OSM LUT for perf cluster, rc=%d\n",
+ rc);
+ return rc;
+ }
+
+ rc = clk_osm_resolve_open_loop_voltages(&pwrcl_clk);
+ if (rc) {
+ if (rc == -EPROBE_DEFER)
+ return rc;
+ dev_err(&pdev->dev, "Unable to determine open-loop voltages for power cluster, rc=%d\n",
+ rc);
+ return rc;
+ }
+
+ rc = clk_osm_resolve_open_loop_voltages(&perfcl_clk);
+ if (rc) {
+ if (rc == -EPROBE_DEFER)
+ return rc;
+ dev_err(&pdev->dev, "Unable to determine open-loop voltages for perf cluster, rc=%d\n",
+ rc);
+ return rc;
+ }
+
+ rc = clk_osm_resolve_crossover_corners(&pwrcl_clk, pdev);
+ if (rc)
+ dev_info(&pdev->dev, "No APM crossover corner programmed\n");
+
+ rc = clk_osm_resolve_crossover_corners(&perfcl_clk, pdev);
+ if (rc)
+ dev_info(&pdev->dev, "No APM crossover corner programmed\n");
+
+ clk_osm_setup_cycle_counters(&pwrcl_clk);
+ clk_osm_setup_cycle_counters(&perfcl_clk);
+
+ clk_osm_print_osm_table(&pwrcl_clk);
+ clk_osm_print_osm_table(&perfcl_clk);
+
+ rc = clk_osm_setup_hw_table(&pwrcl_clk);
+ if (rc) {
+ dev_err(&pdev->dev, "failed to setup power cluster hardware table\n");
+ goto exit;
+ }
+ rc = clk_osm_setup_hw_table(&perfcl_clk);
+ if (rc) {
+ dev_err(&pdev->dev, "failed to setup perf cluster hardware table\n");
+ goto exit;
+ }
+
+ /* Policy tuning */
+ rc = clk_osm_set_cc_policy(pdev);
+ if (rc < 0) {
+ dev_err(&pdev->dev, "cc policy setup failed");
+ goto exit;
+ }
+
+ /* LLM Freq Policy Tuning */
+ rc = clk_osm_set_llm_freq_policy(pdev);
+ if (rc < 0) {
+ dev_err(&pdev->dev, "LLM Frequency Policy setup failed");
+ goto exit;
+ }
+
+ /* LLM Voltage Policy Tuning */
+ rc = clk_osm_set_llm_volt_policy(pdev);
+ if (rc < 0) {
+ dev_err(&pdev->dev, "Failed to set LLM voltage Policy");
+ goto exit;
+ }
+
+ clk_osm_setup_fsms(&pwrcl_clk);
+ clk_osm_setup_fsms(&perfcl_clk);
+
+ /*
+ * Perform typical secure-world HW initialization
+ * as necessary.
+ */
+ clk_osm_do_additional_setup(&pwrcl_clk, pdev);
+ clk_osm_do_additional_setup(&perfcl_clk, pdev);
+
+ /* MEM-ACC Programming */
+ clk_osm_program_mem_acc_regs(&pwrcl_clk);
+ clk_osm_program_mem_acc_regs(&perfcl_clk);
+
+ /* Program APM crossover corners */
+ clk_osm_apm_vc_setup(&pwrcl_clk);
+ clk_osm_apm_vc_setup(&perfcl_clk);
+
+ rc = clk_osm_setup_irq(pdev, &pwrcl_clk, "pwrcl-irq");
+ if (rc)
+ pr_err("Debug IRQ not set for pwrcl\n");
+
+ rc = clk_osm_setup_irq(pdev, &perfcl_clk, "perfcl-irq");
+ if (rc)
+ pr_err("Debug IRQ not set for perfcl\n");
+
+ clk_osm_setup_osm_was(&pwrcl_clk);
+ clk_osm_setup_osm_was(&perfcl_clk);
+
+ if (of_property_read_bool(pdev->dev.of_node,
+ "qcom,osm-pll-setup")) {
+ clk_osm_setup_cluster_pll(&pwrcl_clk);
+ clk_osm_setup_cluster_pll(&perfcl_clk);
+ }
+
+ rc = clk_osm_acd_init(&pwrcl_clk);
+ if (rc) {
+ pr_err("failed to initialize ACD for pwrcl, rc=%d\n", rc);
+ return rc;
+ }
+ rc = clk_osm_acd_init(&perfcl_clk);
+ if (rc) {
+ pr_err("failed to initialize ACD for perfcl, rc=%d\n", rc);
+ return rc;
+ }
+
+ spin_lock_init(&pwrcl_clk.lock);
+ spin_lock_init(&perfcl_clk.lock);
+
+ pwrcl_clk.panic_notifier.notifier_call = clk_osm_panic_callback;
+ atomic_notifier_chain_register(&panic_notifier_list,
+ &pwrcl_clk.panic_notifier);
+ perfcl_clk.panic_notifier.notifier_call = clk_osm_panic_callback;
+ atomic_notifier_chain_register(&panic_notifier_list,
+ &perfcl_clk.panic_notifier);
+
+ rc = of_msm_clock_register(pdev->dev.of_node, cpu_clocks_osm,
+ ARRAY_SIZE(cpu_clocks_osm));
+ if (rc) {
+ dev_err(&pdev->dev, "Unable to register CPU clocks, rc=%d\n",
+ rc);
+ return rc;
+ }
+
+ /*
+ * The hmss_gpll0 clock runs at 300 MHz. Ensure it is at the correct
+ * frequency before enabling OSM. LUT index 0 is always sourced from
+ * this clock.
+ */
+ rc = clk_set_rate(&sys_apcsaux_clk_gcc.c, init_rate);
+ if (rc) {
+ dev_err(&pdev->dev, "Unable to set init rate on hmss_gpll0, rc=%d\n",
+ rc);
+ return rc;
+ }
+ clk_prepare_enable(&sys_apcsaux_clk_gcc.c);
+
+ rc = clk_set_rate(&osm_clk_src.c, osm_clk_init_rate);
+ if (rc) {
+ dev_err(&pdev->dev, "Unable to set init rate on osm_clk, rc=%d\n",
+ rc);
+ goto exit2;
+ }
+
+ /* Make sure index zero is selected */
+ rc = clk_set_rate(&pwrcl_clk.c, init_rate);
+ if (rc) {
+ dev_err(&pdev->dev, "Unable to set init rate on pwr cluster, rc=%d\n",
+ rc);
+ goto exit2;
+ }
+
+ rc = clk_set_rate(&perfcl_clk.c, init_rate);
+ if (rc) {
+ dev_err(&pdev->dev, "Unable to set init rate on perf cluster, rc=%d\n",
+ rc);
+ goto exit2;
+ }
+
+ get_online_cpus();
+
+ /* Enable OSM */
+ for_each_online_cpu(cpu) {
+ WARN(clk_prepare_enable(logical_cpu_to_clk(cpu)),
+ "Failed to enable clock for cpu %d\n", cpu);
+ }
+
+ /* Set final boot rate */
+ rc = clk_set_rate(&pwrcl_clk.c, msmcobalt_v1 ?
+ MSMCOBALTV1_PWRCL_BOOT_RATE :
+ MSMCOBALTV2_PWRCL_BOOT_RATE);
+ if (rc) {
+ dev_err(&pdev->dev, "Unable to set boot rate on pwr cluster, rc=%d\n",
+ rc);
+ goto exit2;
+ }
+
+ rc = clk_set_rate(&perfcl_clk.c, msmcobalt_v1 ?
+ MSMCOBALTV1_PERFCL_BOOT_RATE :
+ MSMCOBALTV2_PERFCL_BOOT_RATE);
+ if (rc) {
+ dev_err(&pdev->dev, "Unable to set boot rate on perf cluster, rc=%d\n",
+ rc);
+ goto exit2;
+ }
+
+ pwrcl_clk.version = clk_osm_read_reg(&pwrcl_clk, VERSION_REG);
+ perfcl_clk.version = clk_osm_read_reg(&perfcl_clk, VERSION_REG);
+
+ populate_opp_table(pdev);
+ populate_debugfs_dir(&pwrcl_clk);
+ populate_debugfs_dir(&perfcl_clk);
+
+ of_platform_populate(pdev->dev.of_node, NULL, NULL, &pdev->dev);
+
+ register_cpu_cycle_counter_cb(&cb);
+
+ pr_info("OSM driver inited\n");
+ put_online_cpus();
+
+ return 0;
+
+exit2:
+ clk_disable_unprepare(&sys_apcsaux_clk_gcc.c);
+exit:
+ dev_err(&pdev->dev, "OSM driver failed to initialize, rc=%d\n",
+ rc);
+ panic("Unable to Setup OSM");
+}
+
+static const struct of_device_id match_table[] = {
+ { .compatible = "qcom,cpu-clock-osm-msmcobalt-v1" },
+ { .compatible = "qcom,cpu-clock-osm-msmcobalt-v2" },
+ {}
+};
+
+static struct platform_driver cpu_clock_osm_driver = {
+ .probe = cpu_clock_osm_driver_probe,
+ .driver = {
+ .name = "cpu-clock-osm",
+ .of_match_table = match_table,
+ .owner = THIS_MODULE,
+ },
+};
+
+static int __init cpu_clock_osm_init(void)
+{
+ return platform_driver_register(&cpu_clock_osm_driver);
+}
+arch_initcall(cpu_clock_osm_init);
+
+static void __exit cpu_clock_osm_exit(void)
+{
+ platform_driver_unregister(&cpu_clock_osm_driver);
+}
+module_exit(cpu_clock_osm_exit);
+
+MODULE_DESCRIPTION("CPU clock driver for OSM");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/clk/qcom/clk-smd-rpm.c b/drivers/clk/qcom/clk-smd-rpm.c
index bc982c9bfa71..c6ea293a8df3 100644
--- a/drivers/clk/qcom/clk-smd-rpm.c
+++ b/drivers/clk/qcom/clk-smd-rpm.c
@@ -250,7 +250,8 @@ static int clk_smd_rpm_set_rate_sleep(struct clk_smd_rpm *r,
static void to_active_sleep(struct clk_smd_rpm *r, unsigned long rate,
unsigned long *active, unsigned long *sleep)
{
- *active = rate;
+ /* Convert the rate (hz) to khz */
+ *active = DIV_ROUND_UP(rate, 1000);
/*
* Active-only clocks don't care what the rate is during sleep. So,
@@ -533,9 +534,9 @@ DEFINE_CLK_SMD_RPM(msm8996, ipa_clk, ipa_a_clk, QCOM_SMD_RPM_IPA_CLK, 0);
DEFINE_CLK_SMD_RPM(msm8996, ce1_clk, ce1_a_clk, QCOM_SMD_RPM_CE_CLK, 0);
DEFINE_CLK_SMD_RPM_BRANCH(msm8996, cxo, cxo_a, QCOM_SMD_RPM_MISC_CLK, 0, 19200000);
DEFINE_CLK_SMD_RPM_BRANCH(msm8996, aggre1_noc_clk, aggre1_noc_a_clk,
- QCOM_SMD_RPM_AGGR_CLK, 0, 1000);
-DEFINE_CLK_SMD_RPM_BRANCH(msm8996, aggre2_noc_clk, aggre2_noc_a_clk,
QCOM_SMD_RPM_AGGR_CLK, 1, 1000);
+DEFINE_CLK_SMD_RPM_BRANCH(msm8996, aggre2_noc_clk, aggre2_noc_a_clk,
+ QCOM_SMD_RPM_AGGR_CLK, 2, 1000);
DEFINE_CLK_SMD_RPM_QDSS(msm8996, qdss_clk, qdss_a_clk, QCOM_SMD_RPM_MISC_CLK, 1);
DEFINE_CLK_SMD_RPM_XO_BUFFER(msm8996, bb_clk1, bb_clk1_a, 1);
DEFINE_CLK_SMD_RPM_XO_BUFFER(msm8996, bb_clk2, bb_clk2_a, 2);
@@ -544,7 +545,7 @@ DEFINE_CLK_SMD_RPM_XO_BUFFER(msm8996, rf_clk2, rf_clk2_a, 5);
DEFINE_CLK_SMD_RPM_XO_BUFFER(msm8996, ln_bb_clk, ln_bb_a_clk, 8);
DEFINE_CLK_SMD_RPM_XO_BUFFER(msm8996, div_clk1, div_clk1_ao, 0xb);
DEFINE_CLK_SMD_RPM_XO_BUFFER(msm8996, div_clk2, div_clk2_ao, 0xc);
-DEFINE_CLK_SMD_RPM_XO_BUFFER(msm8996, div_clk3, div_clk3_ao, 0xc);
+DEFINE_CLK_SMD_RPM_XO_BUFFER(msm8996, div_clk3, div_clk3_ao, 0xd);
DEFINE_CLK_SMD_RPM_XO_BUFFER_PINCTRL(msm8996, bb_clk1_pin, bb_clk1_a_pin, 1);
DEFINE_CLK_SMD_RPM_XO_BUFFER_PINCTRL(msm8996, bb_clk2_pin, bb_clk2_a_pin, 2);
DEFINE_CLK_SMD_RPM_XO_BUFFER_PINCTRL(msm8996, rf_clk1_pin, rf_clk1_a_pin, 4);
@@ -613,13 +614,13 @@ DEFINE_CLK_SMD_RPM(msmfalcon, aggre2_noc_clk, aggre2_noc_a_clk,
QCOM_SMD_RPM_AGGR_CLK, 2);
DEFINE_CLK_SMD_RPM_QDSS(msmfalcon, qdss_clk, qdss_a_clk,
QCOM_SMD_RPM_MISC_CLK, 1);
-DEFINE_CLK_SMD_RPM_XO_BUFFER(msmfalcon, rf_clk2, rf_clk2_ao, 5);
+DEFINE_CLK_SMD_RPM_XO_BUFFER(msmfalcon, rf_clk1, rf_clk1_ao, 4);
DEFINE_CLK_SMD_RPM_XO_BUFFER(msmfalcon, div_clk1, div_clk1_ao, 0xb);
DEFINE_CLK_SMD_RPM_XO_BUFFER(msmfalcon, ln_bb_clk1, ln_bb_clk1_ao, 0x1);
DEFINE_CLK_SMD_RPM_XO_BUFFER(msmfalcon, ln_bb_clk2, ln_bb_clk2_ao, 0x2);
DEFINE_CLK_SMD_RPM_XO_BUFFER(msmfalcon, ln_bb_clk3, ln_bb_clk3_ao, 0x3);
-DEFINE_CLK_SMD_RPM_XO_BUFFER_PINCTRL(msmfalcon, rf_clk2_pin, rf_clk2_a_pin, 5);
+DEFINE_CLK_SMD_RPM_XO_BUFFER_PINCTRL(msmfalcon, rf_clk1_pin, rf_clk1_ao_pin, 4);
DEFINE_CLK_SMD_RPM_XO_BUFFER_PINCTRL(msmfalcon, ln_bb_clk1_pin,
ln_bb_clk1_pin_ao, 0x1);
DEFINE_CLK_SMD_RPM_XO_BUFFER_PINCTRL(msmfalcon, ln_bb_clk2_pin,
@@ -656,8 +657,10 @@ static struct clk_hw *msmfalcon_clks[] = {
[RPM_BIMC_A_CLK] = &msmfalcon_bimc_a_clk.hw,
[RPM_QDSS_CLK] = &msmfalcon_qdss_clk.hw,
[RPM_QDSS_A_CLK] = &msmfalcon_qdss_a_clk.hw,
- [RPM_RF_CLK2_PIN] = &msmfalcon_rf_clk2_pin.hw,
- [RPM_RF_CLK2_A_PIN] = &msmfalcon_rf_clk2_a_pin.hw,
+ [RPM_RF_CLK1] = &msmfalcon_rf_clk1.hw,
+ [RPM_RF_CLK1_A] = &msmfalcon_rf_clk1_ao.hw,
+ [RPM_RF_CLK1_PIN] = &msmfalcon_rf_clk1_pin.hw,
+ [RPM_RF_CLK1_A_PIN] = &msmfalcon_rf_clk1_ao_pin.hw,
[RPM_AGGR2_NOC_CLK] = &msmfalcon_aggre2_noc_clk.hw,
[RPM_AGGR2_NOC_A_CLK] = &msmfalcon_aggre2_noc_a_clk.hw,
[RPM_CNOC_CLK] = &msmfalcon_cnoc_clk.hw,
diff --git a/drivers/clk/qcom/mmcc-msmfalcon.c b/drivers/clk/qcom/mmcc-msmfalcon.c
new file mode 100644
index 000000000000..e4a84765430a
--- /dev/null
+++ b/drivers/clk/qcom/mmcc-msmfalcon.c
@@ -0,0 +1,3036 @@
+/*
+ * Copyright (c) 2016, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * 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/kernel.h>
+#include <linux/bitops.h>
+#include <linux/err.h>
+#include <linux/platform_device.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/clk-provider.h>
+#include <linux/regmap.h>
+#include <linux/reset-controller.h>
+#include <dt-bindings/clock/qcom,mmcc-msmfalcon.h>
+
+#include "clk-alpha-pll.h"
+#include "clk-branch.h"
+#include "common.h"
+#include "clk-pll.h"
+#include "clk-rcg.h"
+#include "clk-regmap.h"
+#include "clk-regmap-divider.h"
+#include "reset.h"
+#include "vdd-level-falcon.h"
+
+#define F(f, s, h, m, n) { (f), (s), (2 * (h) - 1), (m), (n) }
+#define F_SLEW(f, s, h, m, n, src_freq) { (f), (s), (2 * (h) - 1), (m), (n), \
+ (src_freq) }
+
+enum vdd_a_levels {
+ VDDA_NONE,
+ VDDA_LOWER, /* SVS2 */
+ VDDA_NUM,
+};
+
+static int vdda_levels[] = {
+ 0,
+ 1800000,
+};
+
+#define VDDA_FMAX_MAP1(l1, f1) \
+ .vdd_class = &vdda, \
+ .rate_max = (unsigned long[VDDA_NUM]) { \
+ [VDDA_##l1] = (f1), \
+ }, \
+ .num_rate_max = VDDA_NUM
+
+static DEFINE_VDD_REGULATORS(vdd_dig, VDD_DIG_NUM, 1, vdd_corner);
+static DEFINE_VDD_REGULATORS(vdd_mx, VDD_DIG_NUM, 1, vdd_corner);
+static DEFINE_VDD_REGULATORS(vdda, VDDA_NUM, 1, vdda_levels);
+
+enum {
+ P_CORE_BI_PLL_TEST_SE,
+ P_CORE_PI_SLEEP_CLK,
+ P_CXO,
+ P_DP_PHY_PLL_LINK_CLK,
+ P_DP_PHY_PLL_VCO_DIV,
+ P_DSI0_PHY_PLL_OUT_BYTECLK,
+ P_DSI0_PHY_PLL_OUT_DSICLK,
+ P_DSI1_PHY_PLL_OUT_BYTECLK,
+ P_DSI1_PHY_PLL_OUT_DSICLK,
+ P_GPLL0_OUT_MAIN,
+ P_GPLL0_OUT_MAIN_DIV,
+ P_MMPLL0_PLL_OUT_MAIN,
+ P_MMPLL10_PLL_OUT_MAIN,
+ P_MMPLL3_PLL_OUT_MAIN,
+ P_MMPLL4_PLL_OUT_MAIN,
+ P_MMPLL5_PLL_OUT_MAIN,
+ P_MMPLL6_PLL_OUT_MAIN,
+ P_MMPLL7_PLL_OUT_MAIN,
+ P_MMPLL8_PLL_OUT_MAIN,
+};
+
+static const struct parent_map mmcc_parent_map_0[] = {
+ { P_CXO, 0 },
+ { P_MMPLL0_PLL_OUT_MAIN, 1 },
+ { P_MMPLL4_PLL_OUT_MAIN, 2 },
+ { P_MMPLL7_PLL_OUT_MAIN, 3 },
+ { P_MMPLL8_PLL_OUT_MAIN, 4 },
+ { P_GPLL0_OUT_MAIN, 5 },
+ { P_GPLL0_OUT_MAIN_DIV, 6 },
+ { P_CORE_BI_PLL_TEST_SE, 7 },
+};
+
+static const char * const mmcc_parent_names_0[] = {
+ "xo",
+ "mmpll0_pll_out_main",
+ "mmpll4_pll_out_main",
+ "mmpll7_pll_out_main",
+ "mmpll8_pll_out_main",
+ "gcc_mmss_gpll0_clk",
+ "gcc_mmss_gpll0_div_clk",
+ "core_bi_pll_test_se",
+};
+
+static const struct parent_map mmcc_parent_map_1[] = {
+ { P_CXO, 0 },
+ { P_DSI0_PHY_PLL_OUT_BYTECLK, 1 },
+ { P_DSI1_PHY_PLL_OUT_BYTECLK, 2 },
+ { P_CORE_BI_PLL_TEST_SE, 7 },
+};
+
+static const char * const mmcc_parent_names_1[] = {
+ "xo",
+ "dsi0_phy_pll_out_byteclk",
+ "dsi1_phy_pll_out_byteclk",
+ "core_bi_pll_test_se",
+};
+
+static const struct parent_map mmcc_parent_map_2[] = {
+ { P_CXO, 0 },
+ { P_MMPLL0_PLL_OUT_MAIN, 1 },
+ { P_MMPLL4_PLL_OUT_MAIN, 2 },
+ { P_MMPLL7_PLL_OUT_MAIN, 3 },
+ { P_MMPLL10_PLL_OUT_MAIN, 4 },
+ { P_GPLL0_OUT_MAIN, 5 },
+ { P_GPLL0_OUT_MAIN_DIV, 6 },
+ { P_CORE_BI_PLL_TEST_SE, 7 },
+};
+
+static const char * const mmcc_parent_names_2[] = {
+ "xo",
+ "mmpll0_pll_out_main",
+ "mmpll4_pll_out_main",
+ "mmpll7_pll_out_main",
+ "mmpll10_pll_out_main",
+ "gcc_mmss_gpll0_clk",
+ "gcc_mmss_gpll0_div_clk",
+ "core_bi_pll_test_se",
+};
+
+static const struct parent_map mmcc_parent_map_3[] = {
+ { P_CXO, 0 },
+ { P_MMPLL4_PLL_OUT_MAIN, 1 },
+ { P_MMPLL7_PLL_OUT_MAIN, 2 },
+ { P_MMPLL10_PLL_OUT_MAIN, 3 },
+ { P_CORE_PI_SLEEP_CLK, 4 },
+ { P_GPLL0_OUT_MAIN, 5 },
+ { P_GPLL0_OUT_MAIN_DIV, 6 },
+ { P_CORE_BI_PLL_TEST_SE, 7 },
+};
+
+static const char * const mmcc_parent_names_3[] = {
+ "xo",
+ "mmpll4_pll_out_main",
+ "mmpll7_pll_out_main",
+ "mmpll10_pll_out_main",
+ "core_pi_sleep_clk",
+ "gcc_mmss_gpll0_clk",
+ "gcc_mmss_gpll0_div_clk",
+ "core_bi_pll_test_se",
+};
+
+static const struct parent_map mmcc_parent_map_4[] = {
+ { P_CXO, 0 },
+ { P_MMPLL0_PLL_OUT_MAIN, 1 },
+ { P_MMPLL7_PLL_OUT_MAIN, 2 },
+ { P_MMPLL10_PLL_OUT_MAIN, 3 },
+ { P_CORE_PI_SLEEP_CLK, 4 },
+ { P_GPLL0_OUT_MAIN, 5 },
+ { P_GPLL0_OUT_MAIN_DIV, 6 },
+ { P_CORE_BI_PLL_TEST_SE, 7 },
+};
+
+static const char * const mmcc_parent_names_4[] = {
+ "xo",
+ "mmpll0_pll_out_main",
+ "mmpll7_pll_out_main",
+ "mmpll10_pll_out_main",
+ "core_pi_sleep_clk",
+ "gcc_mmss_gpll0_clk",
+ "gcc_mmss_gpll0_div_clk",
+ "core_bi_pll_test_se",
+};
+
+static const struct parent_map mmcc_parent_map_5[] = {
+ { P_CXO, 0 },
+ { P_GPLL0_OUT_MAIN, 5 },
+ { P_GPLL0_OUT_MAIN_DIV, 6 },
+ { P_CORE_BI_PLL_TEST_SE, 7 },
+};
+
+static const char * const mmcc_parent_names_5[] = {
+ "xo",
+ "gcc_mmss_gpll0_clk",
+ "gcc_mmss_gpll0_div_clk",
+ "core_bi_pll_test_se",
+};
+
+static const struct parent_map mmcc_parent_map_6[] = {
+ { P_CXO, 0 },
+ { P_DP_PHY_PLL_LINK_CLK, 1 },
+ { P_DP_PHY_PLL_VCO_DIV, 2 },
+ { P_CORE_BI_PLL_TEST_SE, 7 },
+};
+
+static const char * const mmcc_parent_names_6[] = {
+ "xo",
+ "dp_phy_pll_link_clk",
+ "dp_phy_pll_vco_div",
+ "core_bi_pll_test_se",
+};
+
+static const struct parent_map mmcc_parent_map_7[] = {
+ { P_CXO, 0 },
+ { P_MMPLL0_PLL_OUT_MAIN, 1 },
+ { P_MMPLL5_PLL_OUT_MAIN, 2 },
+ { P_MMPLL7_PLL_OUT_MAIN, 3 },
+ { P_GPLL0_OUT_MAIN, 5 },
+ { P_GPLL0_OUT_MAIN_DIV, 6 },
+ { P_CORE_BI_PLL_TEST_SE, 7 },
+};
+
+static const char * const mmcc_parent_names_7[] = {
+ "xo",
+ "mmpll0_pll_out_main",
+ "mmpll5_pll_out_main",
+ "mmpll7_pll_out_main",
+ "gcc_mmss_gpll0_clk",
+ "gcc_mmss_gpll0_div_clk",
+ "core_bi_pll_test_se",
+};
+
+static const struct parent_map mmcc_parent_map_8[] = {
+ { P_CXO, 0 },
+ { P_DSI0_PHY_PLL_OUT_DSICLK, 1 },
+ { P_DSI1_PHY_PLL_OUT_DSICLK, 2 },
+ { P_CORE_BI_PLL_TEST_SE, 7 },
+};
+
+static const char * const mmcc_parent_names_8[] = {
+ "xo",
+ "dsi0_phy_pll_out_dsiclk",
+ "dsi1_phy_pll_out_dsiclk",
+ "core_bi_pll_test_se",
+};
+
+static const struct parent_map mmcc_parent_map_9[] = {
+ { P_CXO, 0 },
+ { P_MMPLL0_PLL_OUT_MAIN, 1 },
+ { P_MMPLL4_PLL_OUT_MAIN, 2 },
+ { P_MMPLL7_PLL_OUT_MAIN, 3 },
+ { P_MMPLL10_PLL_OUT_MAIN, 4 },
+ { P_MMPLL6_PLL_OUT_MAIN, 5 },
+ { P_GPLL0_OUT_MAIN, 6 },
+ { P_CORE_BI_PLL_TEST_SE, 7 },
+};
+
+static const char * const mmcc_parent_names_9[] = {
+ "xo",
+ "mmpll0_pll_out_main",
+ "mmpll4_pll_out_main",
+ "mmpll7_pll_out_main",
+ "mmpll10_pll_out_main",
+ "mmpll6_pll_out_main",
+ "gcc_mmss_gpll0_clk",
+ "core_bi_pll_test_se",
+};
+
+static const struct parent_map mmcc_parent_map_10[] = {
+ { P_CXO, 0 },
+ { P_MMPLL0_PLL_OUT_MAIN, 1 },
+ { P_GPLL0_OUT_MAIN, 5 },
+ { P_GPLL0_OUT_MAIN_DIV, 6 },
+ { P_CORE_BI_PLL_TEST_SE, 7 },
+};
+
+static const char * const mmcc_parent_names_10[] = {
+ "xo",
+ "mmpll0_pll_out_main",
+ "gcc_mmss_gpll0_clk",
+ "gcc_mmss_gpll0_div_clk",
+ "core_bi_pll_test_se",
+};
+
+static const struct parent_map mmcc_parent_map_11[] = {
+ { P_CXO, 0 },
+ { P_MMPLL0_PLL_OUT_MAIN, 1 },
+ { P_MMPLL4_PLL_OUT_MAIN, 2 },
+ { P_MMPLL7_PLL_OUT_MAIN, 3 },
+ { P_MMPLL10_PLL_OUT_MAIN, 4 },
+ { P_GPLL0_OUT_MAIN, 5 },
+ { P_MMPLL6_PLL_OUT_MAIN, 6 },
+ { P_CORE_BI_PLL_TEST_SE, 7 },
+};
+
+static const char * const mmcc_parent_names_11[] = {
+ "xo",
+ "mmpll0_pll_out_main",
+ "mmpll4_pll_out_main",
+ "mmpll7_pll_out_main",
+ "mmpll10_pll_out_main",
+ "gcc_mmss_gpll0_clk",
+ "mmpll6_pll_out_main",
+ "core_bi_pll_test_se",
+};
+
+static const struct parent_map mmcc_parent_map_12[] = {
+ { P_CXO, 0 },
+ { P_MMPLL0_PLL_OUT_MAIN, 1 },
+ { P_MMPLL8_PLL_OUT_MAIN, 2 },
+ { P_MMPLL3_PLL_OUT_MAIN, 3 },
+ { P_MMPLL6_PLL_OUT_MAIN, 4 },
+ { P_GPLL0_OUT_MAIN, 5 },
+ { P_MMPLL7_PLL_OUT_MAIN, 6 },
+ { P_CORE_BI_PLL_TEST_SE, 7 },
+};
+
+static const char * const mmcc_parent_names_12[] = {
+ "xo",
+ "mmpll0_pll_out_main",
+ "mmpll8_pll_out_main",
+ "mmpll3_pll_out_main",
+ "mmpll6_pll_out_main",
+ "gcc_mmss_gpll0_clk",
+ "mmpll7_pll_out_main",
+ "core_bi_pll_test_se",
+};
+
+/* Voteable PLL */
+static struct clk_alpha_pll mmpll0_pll_out_main = {
+ .offset = 0xc000,
+ .clkr = {
+ .enable_reg = 0x1f0,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "mmpll0_pll_out_main",
+ .parent_names = (const char *[]){ "xo" },
+ .num_parents = 1,
+ .ops = &clk_alpha_pll_ops,
+ VDD_MMSS_PLL_DIG_FMAX_MAP2(LOWER, 404000000,
+ LOW, 808000000),
+ },
+ },
+};
+
+static struct clk_alpha_pll mmpll6_pll_out_main = {
+ .offset = 0xf0,
+ .clkr = {
+ .enable_reg = 0x1f0,
+ .enable_mask = BIT(2),
+ .hw.init = &(struct clk_init_data){
+ .name = "mmpll6_pll_out_main",
+ .parent_names = (const char *[]){ "xo" },
+ .num_parents = 1,
+ .ops = &clk_alpha_pll_ops,
+ VDD_MMSS_PLL_DIG_FMAX_MAP2(LOWER, 540000000,
+ LOW_L1, 1080000000),
+ },
+ },
+};
+
+/* APSS controlled PLLs */
+static struct pll_vco vco[] = {
+ { 1000000000, 2000000000, 0 },
+ { 750000000, 1500000000, 1 },
+ { 500000000, 1000000000, 2 },
+ { 250000000, 500000000, 3 },
+};
+
+static const struct pll_config mmpll10_config = {
+ .l = 0x1e,
+ .config_ctl_val = 0x00004289,
+ .main_output_mask = 0x1,
+};
+
+static struct clk_alpha_pll mmpll10_pll_out_main = {
+ .offset = 0x190,
+ .clkr = {
+ .hw.init = &(struct clk_init_data){
+ .name = "mmpll10_pll_out_main",
+ .parent_names = (const char *[]){ "xo" },
+ .num_parents = 1,
+ .ops = &clk_alpha_pll_ops,
+ VDDA_FMAX_MAP1(LOWER, 576000000),
+ },
+ },
+};
+
+static struct pll_vco mmpll3_vco[] = {
+ { 750000000, 1500000000, 1 },
+};
+
+static const struct pll_config mmpll3_config = {
+ .l = 0x2e,
+ .config_ctl_val = 0x4001055b,
+ .vco_val = 0x1 << 20,
+ .vco_mask = 0x3 << 20,
+ .main_output_mask = 0x1,
+};
+
+static struct clk_alpha_pll mmpll3_pll_out_main = {
+ .offset = 0x0,
+ .vco_table = mmpll3_vco,
+ .num_vco = ARRAY_SIZE(mmpll3_vco),
+ .clkr = {
+ .hw.init = &(struct clk_init_data){
+ .name = "mmpll3_pll_out_main",
+ .parent_names = (const char *[]){ "xo" },
+ .num_parents = 1,
+ .ops = &clk_alpha_pll_slew_ops,
+ VDD_MMSS_PLL_DIG_FMAX_MAP2(LOWER, 441600000,
+ NOMINAL, 1036800000),
+ },
+ },
+};
+
+static const struct pll_config mmpll4_config = {
+ .l = 0x28,
+ .config_ctl_val = 0x4001055b,
+ .vco_val = 0x2 << 20,
+ .vco_mask = 0x3 << 20,
+ .main_output_mask = 0x1,
+};
+
+static struct clk_alpha_pll mmpll4_pll_out_main = {
+ .offset = 0x50,
+ .vco_table = vco,
+ .num_vco = ARRAY_SIZE(vco),
+ .clkr = {
+ .hw.init = &(struct clk_init_data){
+ .name = "mmpll4_pll_out_main",
+ .parent_names = (const char *[]){ "xo" },
+ .num_parents = 1,
+ .ops = &clk_alpha_pll_ops,
+ VDD_MMSS_PLL_DIG_FMAX_MAP2(LOWER, 384000000,
+ LOW, 768000000),
+ },
+ },
+};
+
+static const struct pll_config mmpll5_config = {
+ .l = 0x2a,
+ .config_ctl_val = 0x4001055b,
+ .alpha_u = 0xf8,
+ .alpha_en_mask = BIT(24),
+ .vco_val = 0x2 << 20,
+ .vco_mask = 0x3 << 20,
+ .main_output_mask = 0x1,
+};
+
+static struct clk_alpha_pll mmpll5_pll_out_main = {
+ .offset = 0xa0,
+ .vco_table = vco,
+ .num_vco = ARRAY_SIZE(vco),
+ .clkr = {
+ .hw.init = &(struct clk_init_data){
+ .name = "mmpll5_pll_out_main",
+ .parent_names = (const char *[]){ "xo" },
+ .num_parents = 1,
+ .ops = &clk_alpha_pll_ops,
+ VDD_MMSS_PLL_DIG_FMAX_MAP2(LOWER, 421500000,
+ LOW, 825000000),
+ },
+ },
+};
+
+static const struct pll_config mmpll7_config = {
+ .l = 0x32,
+ .config_ctl_val = 0x4001055b,
+ .vco_val = 0x2 << 20,
+ .vco_mask = 0x3 << 20,
+ .main_output_mask = 0x1,
+};
+
+static struct clk_alpha_pll mmpll7_pll_out_main = {
+ .offset = 0x140,
+ .vco_table = vco,
+ .num_vco = ARRAY_SIZE(vco),
+ .clkr = {
+ .hw.init = &(struct clk_init_data){
+ .name = "mmpll7_pll_out_main",
+ .parent_names = (const char *[]){ "xo" },
+ .num_parents = 1,
+ .ops = &clk_alpha_pll_ops,
+ VDD_MMSS_PLL_DIG_FMAX_MAP2(LOWER, 480000000,
+ LOW, 960000000),
+ },
+ },
+};
+
+static const struct pll_config mmpll8_config = {
+ .l = 0x30,
+ .alpha_u = 0x70,
+ .alpha_en_mask = BIT(24),
+ .config_ctl_val = 0x4001055b,
+ .vco_val = 0x2 << 20,
+ .vco_mask = 0x3 << 20,
+ .main_output_mask = 0x1,
+};
+
+static struct clk_alpha_pll mmpll8_pll_out_main = {
+ .offset = 0x1c0,
+ .vco_table = vco,
+ .num_vco = ARRAY_SIZE(vco),
+ .clkr = {
+ .hw.init = &(struct clk_init_data){
+ .name = "mmpll8_pll_out_main",
+ .parent_names = (const char *[]){ "xo" },
+ .num_parents = 1,
+ .ops = &clk_alpha_pll_ops,
+ VDD_MMSS_PLL_DIG_FMAX_MAP2(LOWER, 465000000,
+ LOW, 930000000),
+ },
+ },
+};
+
+static const struct freq_tbl ftbl_ahb_clk_src[] = {
+ F(19200000, P_CXO, 1, 0, 0),
+ F(40000000, P_GPLL0_OUT_MAIN_DIV, 7.5, 0, 0),
+ F(80800000, P_MMPLL0_PLL_OUT_MAIN, 10, 0, 0),
+ { }
+};
+
+static struct clk_rcg2 ahb_clk_src = {
+ .cmd_rcgr = 0x5000,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .parent_map = mmcc_parent_map_10,
+ .freq_tbl = ftbl_ahb_clk_src,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "ahb_clk_src",
+ .parent_names = mmcc_parent_names_10,
+ .num_parents = 5,
+ .ops = &clk_rcg2_ops,
+ VDD_DIG_FMAX_MAP3(
+ LOWER, 19200000,
+ LOW, 40000000,
+ NOMINAL, 80800000),
+ },
+};
+
+static struct clk_rcg2 byte0_clk_src = {
+ .cmd_rcgr = 0x2120,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .parent_map = mmcc_parent_map_1,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "byte0_clk_src",
+ .parent_names = mmcc_parent_names_1,
+ .num_parents = 4,
+ .ops = &clk_byte2_ops,
+ .flags = CLK_SET_RATE_PARENT | CLK_GET_RATE_NOCACHE,
+ VDD_DIG_FMAX_MAP3(
+ LOWER, 131250000,
+ LOW, 210000000,
+ NOMINAL, 262500000),
+ },
+};
+
+static struct clk_rcg2 byte1_clk_src = {
+ .cmd_rcgr = 0x2140,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .parent_map = mmcc_parent_map_1,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "byte1_clk_src",
+ .parent_names = mmcc_parent_names_1,
+ .num_parents = 4,
+ .ops = &clk_byte2_ops,
+ .flags = CLK_SET_RATE_PARENT | CLK_GET_RATE_NOCACHE,
+ VDD_DIG_FMAX_MAP3(
+ LOWER, 131250000,
+ LOW, 210000000,
+ NOMINAL, 262500000),
+ },
+};
+
+static const struct freq_tbl ftbl_camss_gp0_clk_src[] = {
+ F(10000, P_CXO, 16, 1, 120),
+ F(24000, P_CXO, 16, 1, 50),
+ F(6000000, P_GPLL0_OUT_MAIN_DIV, 10, 1, 5),
+ F(12000000, P_GPLL0_OUT_MAIN_DIV, 10, 2, 5),
+ F(13043478, P_GPLL0_OUT_MAIN_DIV, 1, 1, 23),
+ F(24000000, P_GPLL0_OUT_MAIN_DIV, 1, 2, 25),
+ F(50000000, P_GPLL0_OUT_MAIN_DIV, 6, 0, 0),
+ F(100000000, P_GPLL0_OUT_MAIN_DIV, 3, 0, 0),
+ F(200000000, P_GPLL0_OUT_MAIN, 3, 0, 0),
+ { }
+};
+
+static struct clk_rcg2 camss_gp0_clk_src = {
+ .cmd_rcgr = 0x3420,
+ .mnd_width = 8,
+ .hid_width = 5,
+ .parent_map = mmcc_parent_map_4,
+ .freq_tbl = ftbl_camss_gp0_clk_src,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "camss_gp0_clk_src",
+ .parent_names = mmcc_parent_names_4,
+ .num_parents = 8,
+ .ops = &clk_rcg2_ops,
+ VDD_DIG_FMAX_MAP3(
+ LOWER, 50000000,
+ LOW, 100000000,
+ NOMINAL, 200000000),
+ },
+};
+
+static struct clk_rcg2 camss_gp1_clk_src = {
+ .cmd_rcgr = 0x3450,
+ .mnd_width = 8,
+ .hid_width = 5,
+ .parent_map = mmcc_parent_map_4,
+ .freq_tbl = ftbl_camss_gp0_clk_src,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "camss_gp1_clk_src",
+ .parent_names = mmcc_parent_names_4,
+ .num_parents = 8,
+ .ops = &clk_rcg2_ops,
+ VDD_DIG_FMAX_MAP3(
+ LOWER, 50000000,
+ LOW, 100000000,
+ NOMINAL, 200000000),
+ },
+};
+
+static const struct freq_tbl ftbl_cci_clk_src[] = {
+ F(37500000, P_GPLL0_OUT_MAIN_DIV, 8, 0, 0),
+ F(50000000, P_GPLL0_OUT_MAIN_DIV, 6, 0, 0),
+ F(100000000, P_GPLL0_OUT_MAIN, 6, 0, 0),
+ { }
+};
+
+static struct clk_rcg2 cci_clk_src = {
+ .cmd_rcgr = 0x3300,
+ .mnd_width = 8,
+ .hid_width = 5,
+ .parent_map = mmcc_parent_map_4,
+ .freq_tbl = ftbl_cci_clk_src,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "cci_clk_src",
+ .parent_names = mmcc_parent_names_4,
+ .num_parents = 8,
+ .ops = &clk_rcg2_ops,
+ VDD_DIG_FMAX_MAP3(
+ LOWER, 37500000,
+ LOW, 50000000,
+ NOMINAL, 100000000),
+ },
+};
+
+static const struct freq_tbl ftbl_cpp_clk_src[] = {
+ F(120000000, P_GPLL0_OUT_MAIN, 5, 0, 0),
+ F(256000000, P_MMPLL4_PLL_OUT_MAIN, 3, 0, 0),
+ F(384000000, P_MMPLL4_PLL_OUT_MAIN, 2, 0, 0),
+ F(480000000, P_MMPLL7_PLL_OUT_MAIN, 2, 0, 0),
+ F(540000000, P_MMPLL6_PLL_OUT_MAIN, 2, 0, 0),
+ F(576000000, P_MMPLL10_PLL_OUT_MAIN, 1, 0, 0),
+ { }
+};
+
+static struct clk_rcg2 cpp_clk_src = {
+ .cmd_rcgr = 0x3640,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .parent_map = mmcc_parent_map_11,
+ .freq_tbl = ftbl_cpp_clk_src,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "cpp_clk_src",
+ .parent_names = mmcc_parent_names_11,
+ .num_parents = 8,
+ .ops = &clk_rcg2_ops,
+ VDD_DIG_FMAX_MAP6(
+ LOWER, 120000000,
+ LOW, 256000000,
+ LOW_L1, 384000000,
+ NOMINAL, 480000000,
+ NOMINAL_L1, 540000000,
+ HIGH, 576000000),
+ },
+};
+
+static const struct freq_tbl ftbl_csi0_clk_src[] = {
+ F(100000000, P_GPLL0_OUT_MAIN_DIV, 3, 0, 0),
+ F(200000000, P_GPLL0_OUT_MAIN, 3, 0, 0),
+ F(310000000, P_MMPLL8_PLL_OUT_MAIN, 3, 0, 0),
+ F(404000000, P_MMPLL0_PLL_OUT_MAIN, 2, 0, 0),
+ F(465000000, P_MMPLL8_PLL_OUT_MAIN, 2, 0, 0),
+ { }
+};
+
+static struct clk_rcg2 csi0_clk_src = {
+ .cmd_rcgr = 0x3090,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .parent_map = mmcc_parent_map_0,
+ .freq_tbl = ftbl_csi0_clk_src,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "csi0_clk_src",
+ .parent_names = mmcc_parent_names_0,
+ .num_parents = 8,
+ .ops = &clk_rcg2_ops,
+ VDD_DIG_FMAX_MAP5(
+ LOWER, 100000000,
+ LOW, 200000000,
+ LOW_L1, 310000000,
+ NOMINAL, 404000000,
+ NOMINAL_L1, 465000000),
+ },
+};
+
+static const struct freq_tbl ftbl_csi0phytimer_clk_src[] = {
+ F(100000000, P_GPLL0_OUT_MAIN_DIV, 3, 0, 0),
+ F(200000000, P_GPLL0_OUT_MAIN, 3, 0, 0),
+ F(269333333, P_MMPLL0_PLL_OUT_MAIN, 3, 0, 0),
+ { }
+};
+
+static struct clk_rcg2 csi0phytimer_clk_src = {
+ .cmd_rcgr = 0x3000,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .parent_map = mmcc_parent_map_2,
+ .freq_tbl = ftbl_csi0phytimer_clk_src,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "csi0phytimer_clk_src",
+ .parent_names = mmcc_parent_names_2,
+ .num_parents = 8,
+ .ops = &clk_rcg2_ops,
+ VDD_DIG_FMAX_MAP3(
+ LOWER, 100000000,
+ LOW, 200000000,
+ LOW_L1, 269333333),
+ },
+};
+
+static struct clk_rcg2 csi1_clk_src = {
+ .cmd_rcgr = 0x3100,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .parent_map = mmcc_parent_map_0,
+ .freq_tbl = ftbl_csi0_clk_src,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "csi1_clk_src",
+ .parent_names = mmcc_parent_names_0,
+ .num_parents = 8,
+ .ops = &clk_rcg2_ops,
+ VDD_DIG_FMAX_MAP5(
+ LOWER, 100000000,
+ LOW, 200000000,
+ LOW_L1, 310000000,
+ NOMINAL, 404000000,
+ NOMINAL_L1, 465000000),
+ },
+};
+
+static struct clk_rcg2 csi1phytimer_clk_src = {
+ .cmd_rcgr = 0x3030,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .parent_map = mmcc_parent_map_2,
+ .freq_tbl = ftbl_csi0phytimer_clk_src,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "csi1phytimer_clk_src",
+ .parent_names = mmcc_parent_names_2,
+ .num_parents = 8,
+ .ops = &clk_rcg2_ops,
+ VDD_DIG_FMAX_MAP3(
+ LOWER, 100000000,
+ LOW, 200000000,
+ LOW_L1, 269333333),
+ },
+};
+
+static struct clk_rcg2 csi2_clk_src = {
+ .cmd_rcgr = 0x3160,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .parent_map = mmcc_parent_map_0,
+ .freq_tbl = ftbl_csi0_clk_src,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "csi2_clk_src",
+ .parent_names = mmcc_parent_names_0,
+ .num_parents = 8,
+ .ops = &clk_rcg2_ops,
+ VDD_DIG_FMAX_MAP5(
+ LOWER, 100000000,
+ LOW, 200000000,
+ LOW_L1, 310000000,
+ NOMINAL, 404000000,
+ NOMINAL_L1, 465000000),
+ },
+};
+
+static struct clk_rcg2 csi2phytimer_clk_src = {
+ .cmd_rcgr = 0x3060,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .parent_map = mmcc_parent_map_2,
+ .freq_tbl = ftbl_csi0phytimer_clk_src,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "csi2phytimer_clk_src",
+ .parent_names = mmcc_parent_names_2,
+ .num_parents = 8,
+ .ops = &clk_rcg2_ops,
+ VDD_DIG_FMAX_MAP3(
+ LOWER, 100000000,
+ LOW, 200000000,
+ LOW_L1, 269333333),
+ },
+};
+
+static struct clk_rcg2 csi3_clk_src = {
+ .cmd_rcgr = 0x31c0,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .parent_map = mmcc_parent_map_0,
+ .freq_tbl = ftbl_csi0_clk_src,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "csi3_clk_src",
+ .parent_names = mmcc_parent_names_0,
+ .num_parents = 8,
+ .ops = &clk_rcg2_ops,
+ VDD_DIG_FMAX_MAP5(
+ LOWER, 100000000,
+ LOW, 200000000,
+ LOW_L1, 310000000,
+ NOMINAL, 404000000,
+ NOMINAL_L1, 465000000),
+ },
+};
+
+static const struct freq_tbl ftbl_csiphy_clk_src[] = {
+ F(100000000, P_GPLL0_OUT_MAIN_DIV, 3, 0, 0),
+ F(200000000, P_GPLL0_OUT_MAIN, 3, 0, 0),
+ F(269333333, P_MMPLL0_PLL_OUT_MAIN, 3, 0, 0),
+ F(320000000, P_MMPLL7_PLL_OUT_MAIN, 3, 0, 0),
+ { }
+};
+
+static struct clk_rcg2 csiphy_clk_src = {
+ .cmd_rcgr = 0x3800,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .parent_map = mmcc_parent_map_0,
+ .freq_tbl = ftbl_csiphy_clk_src,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "csiphy_clk_src",
+ .parent_names = mmcc_parent_names_0,
+ .num_parents = 8,
+ .ops = &clk_rcg2_ops,
+ VDD_DIG_FMAX_MAP4(
+ LOWER, 100000000,
+ LOW, 200000000,
+ LOW_L1, 269333333,
+ NOMINAL, 320000000),
+ },
+};
+
+static const struct freq_tbl ftbl_dp_aux_clk_src[] = {
+ F(19200000, P_CXO, 1, 0, 0),
+ { }
+};
+
+static struct clk_rcg2 dp_aux_clk_src = {
+ .cmd_rcgr = 0x2260,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .parent_map = mmcc_parent_map_5,
+ .freq_tbl = ftbl_dp_aux_clk_src,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "dp_aux_clk_src",
+ .parent_names = mmcc_parent_names_5,
+ .num_parents = 4,
+ .ops = &clk_rcg2_ops,
+ VDD_DIG_FMAX_MAP1(
+ LOWER, 19200000),
+ },
+};
+
+static const struct freq_tbl ftbl_dp_crypto_clk_src[] = {
+ F(101250000, P_DP_PHY_PLL_VCO_DIV, 4, 0, 0),
+ F(168750000, P_DP_PHY_PLL_VCO_DIV, 4, 0, 0),
+ F(337500000, P_DP_PHY_PLL_VCO_DIV, 4, 0, 0),
+ { }
+};
+
+static struct clk_rcg2 dp_crypto_clk_src = {
+ .cmd_rcgr = 0x2220,
+ .mnd_width = 8,
+ .hid_width = 5,
+ .parent_map = mmcc_parent_map_6,
+ .freq_tbl = ftbl_dp_crypto_clk_src,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "dp_crypto_clk_src",
+ .parent_names = mmcc_parent_names_6,
+ .num_parents = 4,
+ .ops = &clk_rcg2_ops,
+ VDD_DIG_FMAX_MAP3(
+ LOWER, 101250000,
+ LOW, 168750000,
+ NOMINAL, 337500000),
+ },
+};
+
+static const struct freq_tbl ftbl_dp_gtc_clk_src[] = {
+ F(40000000, P_GPLL0_OUT_MAIN_DIV, 7.5, 0, 0),
+ F(300000000, P_GPLL0_OUT_MAIN_DIV, 1, 0, 0),
+ { }
+};
+
+static struct clk_rcg2 dp_gtc_clk_src = {
+ .cmd_rcgr = 0x2280,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .parent_map = mmcc_parent_map_5,
+ .freq_tbl = ftbl_dp_gtc_clk_src,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "dp_gtc_clk_src",
+ .parent_names = mmcc_parent_names_5,
+ .num_parents = 4,
+ .ops = &clk_rcg2_ops,
+ VDD_DIG_FMAX_MAP2(
+ LOWER, 40000000,
+ LOW, 300000000),
+ },
+};
+
+static const struct freq_tbl ftbl_dp_link_clk_src[] = {
+ F(162000000, P_DP_PHY_PLL_LINK_CLK, 2, 0, 0),
+ F(270000000, P_DP_PHY_PLL_LINK_CLK, 2, 0, 0),
+ F(540000000, P_DP_PHY_PLL_LINK_CLK, 2, 0, 0),
+ { }
+};
+
+static struct clk_rcg2 dp_link_clk_src = {
+ .cmd_rcgr = 0x2200,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .parent_map = mmcc_parent_map_6,
+ .freq_tbl = ftbl_dp_link_clk_src,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "dp_link_clk_src",
+ .parent_names = mmcc_parent_names_6,
+ .num_parents = 4,
+ .ops = &clk_rcg2_ops,
+ .flags = CLK_GET_RATE_NOCACHE | CLK_SET_RATE_PARENT,
+ VDD_DIG_FMAX_MAP3(
+ LOWER, 162000000,
+ LOW, 270000000,
+ NOMINAL, 540000000),
+ },
+};
+
+static struct clk_rcg2 dp_pixel_clk_src = {
+ .cmd_rcgr = 0x2240,
+ .mnd_width = 16,
+ .hid_width = 5,
+ .parent_map = mmcc_parent_map_6,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "dp_pixel_clk_src",
+ .parent_names = mmcc_parent_names_6,
+ .num_parents = 4,
+ .ops = &clk_dp_ops,
+ VDD_DIG_FMAX_MAP3(
+ LOWER, 148380000,
+ LOW, 296740000,
+ NOMINAL, 593470000),
+ },
+};
+
+static struct clk_rcg2 esc0_clk_src = {
+ .cmd_rcgr = 0x2160,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .parent_map = mmcc_parent_map_1,
+ .freq_tbl = ftbl_dp_aux_clk_src,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "esc0_clk_src",
+ .parent_names = mmcc_parent_names_1,
+ .num_parents = 4,
+ .ops = &clk_rcg2_ops,
+ VDD_DIG_FMAX_MAP1(
+ LOWER, 19200000),
+ },
+};
+
+static struct clk_rcg2 esc1_clk_src = {
+ .cmd_rcgr = 0x2180,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .parent_map = mmcc_parent_map_1,
+ .freq_tbl = ftbl_dp_aux_clk_src,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "esc1_clk_src",
+ .parent_names = mmcc_parent_names_1,
+ .num_parents = 4,
+ .ops = &clk_rcg2_ops,
+ VDD_DIG_FMAX_MAP1(
+ LOWER, 19200000),
+ },
+};
+
+static const struct freq_tbl ftbl_jpeg0_clk_src[] = {
+ F(66666667, P_GPLL0_OUT_MAIN_DIV, 4.5, 0, 0),
+ F(133333333, P_GPLL0_OUT_MAIN, 4.5, 0, 0),
+ F(219428571, P_MMPLL4_PLL_OUT_MAIN, 3.5, 0, 0),
+ F(320000000, P_MMPLL7_PLL_OUT_MAIN, 3, 0, 0),
+ F(480000000, P_MMPLL7_PLL_OUT_MAIN, 2, 0, 0),
+ { }
+};
+
+static struct clk_rcg2 jpeg0_clk_src = {
+ .cmd_rcgr = 0x3500,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .parent_map = mmcc_parent_map_2,
+ .freq_tbl = ftbl_jpeg0_clk_src,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "jpeg0_clk_src",
+ .parent_names = mmcc_parent_names_2,
+ .num_parents = 8,
+ .ops = &clk_rcg2_ops,
+ VDD_DIG_FMAX_MAP5(
+ LOWER, 66666667,
+ LOW, 133333333,
+ LOW_L1, 219428571,
+ NOMINAL, 320000000,
+ NOMINAL_L1, 480000000),
+ },
+};
+
+static const struct freq_tbl ftbl_mclk0_clk_src[] = {
+ F(4800000, P_CXO, 4, 0, 0),
+ F(6000000, P_GPLL0_OUT_MAIN_DIV, 10, 1, 5),
+ F(8000000, P_GPLL0_OUT_MAIN_DIV, 1, 2, 75),
+ F(9600000, P_CXO, 2, 0, 0),
+ F(16666667, P_GPLL0_OUT_MAIN_DIV, 2, 1, 9),
+ F(19200000, P_CXO, 1, 0, 0),
+ F(24000000, P_GPLL0_OUT_MAIN_DIV, 1, 2, 25),
+ F(33333333, P_GPLL0_OUT_MAIN_DIV, 1, 1, 9),
+ F(48000000, P_GPLL0_OUT_MAIN, 1, 2, 25),
+ F(66666667, P_GPLL0_OUT_MAIN, 1, 1, 9),
+ { }
+};
+
+static struct clk_rcg2 mclk0_clk_src = {
+ .cmd_rcgr = 0x3360,
+ .mnd_width = 8,
+ .hid_width = 5,
+ .parent_map = mmcc_parent_map_3,
+ .freq_tbl = ftbl_mclk0_clk_src,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "mclk0_clk_src",
+ .parent_names = mmcc_parent_names_3,
+ .num_parents = 8,
+ .ops = &clk_rcg2_ops,
+ VDD_DIG_FMAX_MAP2(
+ LOWER, 33333333,
+ LOW, 66666667),
+ },
+};
+
+static struct clk_rcg2 mclk1_clk_src = {
+ .cmd_rcgr = 0x3390,
+ .mnd_width = 8,
+ .hid_width = 5,
+ .parent_map = mmcc_parent_map_3,
+ .freq_tbl = ftbl_mclk0_clk_src,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "mclk1_clk_src",
+ .parent_names = mmcc_parent_names_3,
+ .num_parents = 8,
+ .ops = &clk_rcg2_ops,
+ VDD_DIG_FMAX_MAP2(
+ LOWER, 33333333,
+ LOW, 66666667),
+ },
+};
+
+static struct clk_rcg2 mclk2_clk_src = {
+ .cmd_rcgr = 0x33c0,
+ .mnd_width = 8,
+ .hid_width = 5,
+ .parent_map = mmcc_parent_map_3,
+ .freq_tbl = ftbl_mclk0_clk_src,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "mclk2_clk_src",
+ .parent_names = mmcc_parent_names_3,
+ .num_parents = 8,
+ .ops = &clk_rcg2_ops,
+ VDD_DIG_FMAX_MAP2(
+ LOWER, 33333333,
+ LOW, 66666667),
+ },
+};
+
+static struct clk_rcg2 mclk3_clk_src = {
+ .cmd_rcgr = 0x33f0,
+ .mnd_width = 8,
+ .hid_width = 5,
+ .parent_map = mmcc_parent_map_3,
+ .freq_tbl = ftbl_mclk0_clk_src,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "mclk3_clk_src",
+ .parent_names = mmcc_parent_names_3,
+ .num_parents = 8,
+ .ops = &clk_rcg2_ops,
+ VDD_DIG_FMAX_MAP2(
+ LOWER, 33333333,
+ LOW, 66666667),
+ },
+};
+
+static const struct freq_tbl ftbl_mdp_clk_src[] = {
+ F(100000000, P_GPLL0_OUT_MAIN_DIV, 3, 0, 0),
+ F(150000000, P_GPLL0_OUT_MAIN_DIV, 2, 0, 0),
+ F(171428571, P_GPLL0_OUT_MAIN, 3.5, 0, 0),
+ F(200000000, P_GPLL0_OUT_MAIN, 3, 0, 0),
+ F(275000000, P_MMPLL5_PLL_OUT_MAIN, 3, 0, 0),
+ F(300000000, P_GPLL0_OUT_MAIN, 2, 0, 0),
+ F(330000000, P_MMPLL5_PLL_OUT_MAIN, 2.5, 0, 0),
+ F(412500000, P_MMPLL5_PLL_OUT_MAIN, 2, 0, 0),
+ { }
+};
+
+static struct clk_rcg2 mdp_clk_src = {
+ .cmd_rcgr = 0x2040,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .parent_map = mmcc_parent_map_7,
+ .freq_tbl = ftbl_mdp_clk_src,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "mdp_clk_src",
+ .parent_names = mmcc_parent_names_7,
+ .num_parents = 7,
+ .ops = &clk_rcg2_ops,
+ VDD_DIG_FMAX_MAP4(
+ LOWER, 171428571,
+ LOW, 275000000,
+ NOMINAL, 330000000,
+ HIGH, 412500000),
+ },
+};
+
+static struct clk_rcg2 pclk0_clk_src = {
+ .cmd_rcgr = 0x2000,
+ .mnd_width = 8,
+ .hid_width = 5,
+ .parent_map = mmcc_parent_map_8,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "pclk0_clk_src",
+ .parent_names = mmcc_parent_names_8,
+ .num_parents = 4,
+ .ops = &clk_pixel_ops,
+ .flags = CLK_SET_RATE_PARENT | CLK_GET_RATE_NOCACHE,
+ VDD_DIG_FMAX_MAP3(
+ LOWER, 175000000,
+ LOW, 280000000,
+ NOMINAL, 350000000),
+ },
+};
+
+static struct clk_rcg2 pclk1_clk_src = {
+ .cmd_rcgr = 0x2020,
+ .mnd_width = 8,
+ .hid_width = 5,
+ .parent_map = mmcc_parent_map_8,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "pclk1_clk_src",
+ .parent_names = mmcc_parent_names_8,
+ .num_parents = 4,
+ .ops = &clk_pixel_ops,
+ .flags = CLK_SET_RATE_PARENT | CLK_GET_RATE_NOCACHE,
+ VDD_DIG_FMAX_MAP3(
+ LOWER, 175000000,
+ LOW, 280000000,
+ NOMINAL, 350000000),
+ },
+};
+
+static const struct freq_tbl ftbl_rot_clk_src[] = {
+ F(171428571, P_GPLL0_OUT_MAIN, 3.5, 0, 0),
+ F(275000000, P_MMPLL5_PLL_OUT_MAIN, 3, 0, 0),
+ F(330000000, P_MMPLL5_PLL_OUT_MAIN, 2.5, 0, 0),
+ F(412500000, P_MMPLL5_PLL_OUT_MAIN, 2, 0, 0),
+ { }
+};
+
+static struct clk_rcg2 rot_clk_src = {
+ .cmd_rcgr = 0x21a0,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .parent_map = mmcc_parent_map_7,
+ .freq_tbl = ftbl_rot_clk_src,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "rot_clk_src",
+ .parent_names = mmcc_parent_names_7,
+ .num_parents = 7,
+ .ops = &clk_rcg2_ops,
+ VDD_DIG_FMAX_MAP4(
+ LOWER, 171428571,
+ LOW, 275000000,
+ NOMINAL, 330000000,
+ HIGH, 412500000),
+ },
+};
+
+static const struct freq_tbl ftbl_vfe0_clk_src[] = {
+ F(120000000, P_GPLL0_OUT_MAIN, 5, 0, 0),
+ F(200000000, P_GPLL0_OUT_MAIN, 3, 0, 0),
+ F(256000000, P_MMPLL4_PLL_OUT_MAIN, 3, 0, 0),
+ F(300000000, P_GPLL0_OUT_MAIN, 2, 0, 0),
+ F(404000000, P_MMPLL0_PLL_OUT_MAIN, 2, 0, 0),
+ F(480000000, P_MMPLL7_PLL_OUT_MAIN, 2, 0, 0),
+ F(540000000, P_MMPLL6_PLL_OUT_MAIN, 2, 0, 0),
+ F(576000000, P_MMPLL10_PLL_OUT_MAIN, 1, 0, 0),
+ { }
+};
+
+static struct clk_rcg2 vfe0_clk_src = {
+ .cmd_rcgr = 0x3600,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .parent_map = mmcc_parent_map_9,
+ .freq_tbl = ftbl_vfe0_clk_src,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "vfe0_clk_src",
+ .parent_names = mmcc_parent_names_9,
+ .num_parents = 8,
+ .ops = &clk_rcg2_ops,
+ VDD_DIG_FMAX_MAP6(
+ LOWER, 120000000,
+ LOW, 256000000,
+ LOW_L1, 404000000,
+ NOMINAL, 480000000,
+ NOMINAL_L1, 540000000,
+ HIGH, 576000000),
+ },
+};
+
+static struct clk_rcg2 vfe1_clk_src = {
+ .cmd_rcgr = 0x3620,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .parent_map = mmcc_parent_map_9,
+ .freq_tbl = ftbl_vfe0_clk_src,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "vfe1_clk_src",
+ .parent_names = mmcc_parent_names_9,
+ .num_parents = 8,
+ .ops = &clk_rcg2_ops,
+ VDD_DIG_FMAX_MAP6(
+ LOWER, 120000000,
+ LOW, 256000000,
+ LOW_L1, 404000000,
+ NOMINAL, 480000000,
+ NOMINAL_L1, 540000000,
+ HIGH, 576000000),
+ },
+};
+
+static const struct freq_tbl ftbl_video_core_clk_src[] = {
+ F_SLEW(133333333, P_GPLL0_OUT_MAIN, 4.5, 0, 0, FIXED_FREQ_SRC),
+ F_SLEW(269333333, P_MMPLL0_PLL_OUT_MAIN, 3, 0, 0, FIXED_FREQ_SRC),
+ F_SLEW(320000000, P_MMPLL7_PLL_OUT_MAIN, 3, 0, 0, FIXED_FREQ_SRC),
+ F_SLEW(404000000, P_MMPLL0_PLL_OUT_MAIN, 2, 0, 0, FIXED_FREQ_SRC),
+ F_SLEW(441600000, P_MMPLL3_PLL_OUT_MAIN, 2, 0, 0, 883200000),
+ F_SLEW(518400000, P_MMPLL3_PLL_OUT_MAIN, 2, 0, 0, 1036800000),
+ { }
+};
+
+static struct clk_rcg2 video_core_clk_src = {
+ .cmd_rcgr = 0x1000,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .parent_map = mmcc_parent_map_12,
+ .freq_tbl = ftbl_video_core_clk_src,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "video_core_clk_src",
+ .parent_names = mmcc_parent_names_12,
+ .num_parents = 8,
+ .ops = &clk_rcg2_ops,
+ VDD_DIG_FMAX_MAP6(
+ LOWER, 133333333,
+ LOW, 269333333,
+ LOW_L1, 320000000,
+ NOMINAL, 404000000,
+ NOMINAL_L1, 441600000,
+ HIGH, 518400000),
+ },
+};
+
+static struct clk_rcg2 vsync_clk_src = {
+ .cmd_rcgr = 0x2080,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .parent_map = mmcc_parent_map_5,
+ .freq_tbl = ftbl_dp_aux_clk_src,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "vsync_clk_src",
+ .parent_names = mmcc_parent_names_5,
+ .num_parents = 4,
+ .ops = &clk_rcg2_ops,
+ VDD_DIG_FMAX_MAP1(
+ LOWER, 19200000),
+ },
+};
+
+static struct clk_branch mmss_bimc_smmu_ahb_clk = {
+ .halt_reg = 0xe004,
+ .halt_check = BRANCH_VOTED,
+ .clkr = {
+ .enable_reg = 0xe004,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "mmss_bimc_smmu_ahb_clk",
+ .parent_names = (const char *[]){
+ "ahb_clk_src",
+ },
+ .num_parents = 1,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch mmss_bimc_smmu_axi_clk = {
+ .halt_reg = 0xe008,
+ .halt_check = BRANCH_VOTED,
+ .clkr = {
+ .enable_reg = 0xe008,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "mmss_bimc_smmu_axi_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch mmss_camss_ahb_clk = {
+ .halt_reg = 0x348c,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x348c,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "mmss_camss_ahb_clk",
+ .parent_names = (const char *[]){
+ "ahb_clk_src",
+ },
+ .num_parents = 1,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch mmss_camss_cci_ahb_clk = {
+ .halt_reg = 0x3348,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x3348,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "mmss_camss_cci_ahb_clk",
+ .parent_names = (const char *[]){
+ "ahb_clk_src",
+ },
+ .num_parents = 1,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch mmss_camss_cci_clk = {
+ .halt_reg = 0x3344,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x3344,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "mmss_camss_cci_clk",
+ .parent_names = (const char *[]){
+ "cci_clk_src",
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch mmss_camss_cphy_csid0_clk = {
+ .halt_reg = 0x3730,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x3730,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "mmss_camss_cphy_csid0_clk",
+ .parent_names = (const char *[]){
+ "csiphy_clk_src",
+ },
+ .num_parents = 1,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch mmss_camss_cphy_csid1_clk = {
+ .halt_reg = 0x3734,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x3734,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "mmss_camss_cphy_csid1_clk",
+ .parent_names = (const char *[]){
+ "csiphy_clk_src",
+ },
+ .num_parents = 1,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch mmss_camss_cphy_csid2_clk = {
+ .halt_reg = 0x3738,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x3738,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "mmss_camss_cphy_csid2_clk",
+ .parent_names = (const char *[]){
+ "csiphy_clk_src",
+ },
+ .num_parents = 1,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch mmss_camss_cphy_csid3_clk = {
+ .halt_reg = 0x373c,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x373c,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "mmss_camss_cphy_csid3_clk",
+ .parent_names = (const char *[]){
+ "csiphy_clk_src",
+ },
+ .num_parents = 1,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch mmss_camss_cpp_ahb_clk = {
+ .halt_reg = 0x36b4,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x36b4,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "mmss_camss_cpp_ahb_clk",
+ .parent_names = (const char *[]){
+ "ahb_clk_src",
+ },
+ .num_parents = 1,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch mmss_camss_cpp_axi_clk = {
+ .halt_reg = 0x36c4,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x36c4,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "mmss_camss_cpp_axi_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch mmss_camss_cpp_clk = {
+ .halt_reg = 0x36b0,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x36b0,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "mmss_camss_cpp_clk",
+ .parent_names = (const char *[]){
+ "cpp_clk_src",
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch mmss_camss_cpp_vbif_ahb_clk = {
+ .halt_reg = 0x36c8,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x36c8,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "mmss_camss_cpp_vbif_ahb_clk",
+ .parent_names = (const char *[]){
+ "ahb_clk_src",
+ },
+ .num_parents = 1,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch mmss_camss_csi0_ahb_clk = {
+ .halt_reg = 0x30bc,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x30bc,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "mmss_camss_csi0_ahb_clk",
+ .parent_names = (const char *[]){
+ "ahb_clk_src",
+ },
+ .num_parents = 1,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch mmss_camss_csi0_clk = {
+ .halt_reg = 0x30b4,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x30b4,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "mmss_camss_csi0_clk",
+ .parent_names = (const char *[]){
+ "csi0_clk_src",
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch mmss_camss_csi0phytimer_clk = {
+ .halt_reg = 0x3024,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x3024,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "mmss_camss_csi0phytimer_clk",
+ .parent_names = (const char *[]){
+ "csi0phytimer_clk_src",
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch mmss_camss_csi0pix_clk = {
+ .halt_reg = 0x30e4,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x30e4,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "mmss_camss_csi0pix_clk",
+ .parent_names = (const char *[]){
+ "csi0_clk_src",
+ },
+ .num_parents = 1,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch mmss_camss_csi0rdi_clk = {
+ .halt_reg = 0x30d4,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x30d4,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "mmss_camss_csi0rdi_clk",
+ .parent_names = (const char *[]){
+ "csi0_clk_src",
+ },
+ .num_parents = 1,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch mmss_camss_csi1_ahb_clk = {
+ .halt_reg = 0x3128,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x3128,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "mmss_camss_csi1_ahb_clk",
+ .parent_names = (const char *[]){
+ "ahb_clk_src",
+ },
+ .num_parents = 1,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch mmss_camss_csi1_clk = {
+ .halt_reg = 0x3124,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x3124,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "mmss_camss_csi1_clk",
+ .parent_names = (const char *[]){
+ "csi1_clk_src",
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch mmss_camss_csi1phytimer_clk = {
+ .halt_reg = 0x3054,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x3054,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "mmss_camss_csi1phytimer_clk",
+ .parent_names = (const char *[]){
+ "csi1phytimer_clk_src",
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch mmss_camss_csi1pix_clk = {
+ .halt_reg = 0x3154,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x3154,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "mmss_camss_csi1pix_clk",
+ .parent_names = (const char *[]){
+ "csi1_clk_src",
+ },
+ .num_parents = 1,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch mmss_camss_csi1rdi_clk = {
+ .halt_reg = 0x3144,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x3144,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "mmss_camss_csi1rdi_clk",
+ .parent_names = (const char *[]){
+ "csi1_clk_src",
+ },
+ .num_parents = 1,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch mmss_camss_csi2_ahb_clk = {
+ .halt_reg = 0x3188,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x3188,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "mmss_camss_csi2_ahb_clk",
+ .parent_names = (const char *[]){
+ "ahb_clk_src",
+ },
+ .num_parents = 1,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch mmss_camss_csi2_clk = {
+ .halt_reg = 0x3184,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x3184,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "mmss_camss_csi2_clk",
+ .parent_names = (const char *[]){
+ "csi2_clk_src",
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch mmss_camss_csi2phytimer_clk = {
+ .halt_reg = 0x3084,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x3084,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "mmss_camss_csi2phytimer_clk",
+ .parent_names = (const char *[]){
+ "csi2phytimer_clk_src",
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch mmss_camss_csi2pix_clk = {
+ .halt_reg = 0x31b4,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x31b4,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "mmss_camss_csi2pix_clk",
+ .parent_names = (const char *[]){
+ "csi2_clk_src",
+ },
+ .num_parents = 1,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch mmss_camss_csi2rdi_clk = {
+ .halt_reg = 0x31a4,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x31a4,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "mmss_camss_csi2rdi_clk",
+ .parent_names = (const char *[]){
+ "csi2_clk_src",
+ },
+ .num_parents = 1,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch mmss_camss_csi3_ahb_clk = {
+ .halt_reg = 0x31e8,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x31e8,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "mmss_camss_csi3_ahb_clk",
+ .parent_names = (const char *[]){
+ "ahb_clk_src",
+ },
+ .num_parents = 1,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch mmss_camss_csi3_clk = {
+ .halt_reg = 0x31e4,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x31e4,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "mmss_camss_csi3_clk",
+ .parent_names = (const char *[]){
+ "csi3_clk_src",
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch mmss_camss_csi3pix_clk = {
+ .halt_reg = 0x3214,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x3214,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "mmss_camss_csi3pix_clk",
+ .parent_names = (const char *[]){
+ "csi3_clk_src",
+ },
+ .num_parents = 1,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch mmss_camss_csi3rdi_clk = {
+ .halt_reg = 0x3204,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x3204,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "mmss_camss_csi3rdi_clk",
+ .parent_names = (const char *[]){
+ "csi3_clk_src",
+ },
+ .num_parents = 1,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch mmss_camss_csi_vfe0_clk = {
+ .halt_reg = 0x3704,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x3704,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "mmss_camss_csi_vfe0_clk",
+ .parent_names = (const char *[]){
+ "vfe0_clk_src",
+ },
+ .num_parents = 1,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch mmss_camss_csi_vfe1_clk = {
+ .halt_reg = 0x3714,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x3714,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "mmss_camss_csi_vfe1_clk",
+ .parent_names = (const char *[]){
+ "vfe1_clk_src",
+ },
+ .num_parents = 1,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch mmss_camss_csiphy0_clk = {
+ .halt_reg = 0x3740,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x3740,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "mmss_camss_csiphy0_clk",
+ .parent_names = (const char *[]){
+ "csiphy_clk_src",
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch mmss_camss_csiphy1_clk = {
+ .halt_reg = 0x3744,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x3744,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "mmss_camss_csiphy1_clk",
+ .parent_names = (const char *[]){
+ "csiphy_clk_src",
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch mmss_camss_csiphy2_clk = {
+ .halt_reg = 0x3748,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x3748,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "mmss_camss_csiphy2_clk",
+ .parent_names = (const char *[]){
+ "csiphy_clk_src",
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch mmss_camss_gp0_clk = {
+ .halt_reg = 0x3444,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x3444,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "mmss_camss_gp0_clk",
+ .parent_names = (const char *[]){
+ "camss_gp0_clk_src",
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch mmss_camss_gp1_clk = {
+ .halt_reg = 0x3474,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x3474,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "mmss_camss_gp1_clk",
+ .parent_names = (const char *[]){
+ "camss_gp1_clk_src",
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch mmss_camss_ispif_ahb_clk = {
+ .halt_reg = 0x3224,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x3224,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "mmss_camss_ispif_ahb_clk",
+ .parent_names = (const char *[]){
+ "ahb_clk_src",
+ },
+ .num_parents = 1,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch mmss_camss_jpeg0_clk = {
+ .halt_reg = 0x35a8,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x35a8,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "mmss_camss_jpeg0_clk",
+ .parent_names = (const char *[]){
+ "jpeg0_clk_src",
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch mmss_camss_jpeg_ahb_clk = {
+ .halt_reg = 0x35b4,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x35b4,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "mmss_camss_jpeg_ahb_clk",
+ .parent_names = (const char *[]){
+ "ahb_clk_src",
+ },
+ .num_parents = 1,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch mmss_camss_jpeg_axi_clk = {
+ .halt_reg = 0x35b8,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x35b8,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "mmss_camss_jpeg_axi_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch mmss_camss_mclk0_clk = {
+ .halt_reg = 0x3384,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x3384,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "mmss_camss_mclk0_clk",
+ .parent_names = (const char *[]){
+ "mclk0_clk_src",
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch mmss_camss_mclk1_clk = {
+ .halt_reg = 0x33b4,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x33b4,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "mmss_camss_mclk1_clk",
+ .parent_names = (const char *[]){
+ "mclk1_clk_src",
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch mmss_camss_mclk2_clk = {
+ .halt_reg = 0x33e4,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x33e4,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "mmss_camss_mclk2_clk",
+ .parent_names = (const char *[]){
+ "mclk2_clk_src",
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch mmss_camss_mclk3_clk = {
+ .halt_reg = 0x3414,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x3414,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "mmss_camss_mclk3_clk",
+ .parent_names = (const char *[]){
+ "mclk3_clk_src",
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch mmss_camss_micro_ahb_clk = {
+ .halt_reg = 0x3494,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x3494,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "mmss_camss_micro_ahb_clk",
+ .parent_names = (const char *[]){
+ "ahb_clk_src",
+ },
+ .num_parents = 1,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch mmss_camss_top_ahb_clk = {
+ .halt_reg = 0x3484,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x3484,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "mmss_camss_top_ahb_clk",
+ .parent_names = (const char *[]){
+ "ahb_clk_src",
+ },
+ .num_parents = 1,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch mmss_camss_vfe0_ahb_clk = {
+ .halt_reg = 0x3668,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x3668,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "mmss_camss_vfe0_ahb_clk",
+ .parent_names = (const char *[]){
+ "ahb_clk_src",
+ },
+ .num_parents = 1,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch mmss_camss_vfe0_clk = {
+ .halt_reg = 0x36a8,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x36a8,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "mmss_camss_vfe0_clk",
+ .parent_names = (const char *[]){
+ "vfe0_clk_src",
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch mmss_camss_vfe0_stream_clk = {
+ .halt_reg = 0x3720,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x3720,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "mmss_camss_vfe0_stream_clk",
+ .parent_names = (const char *[]){
+ "vfe0_clk_src",
+ },
+ .num_parents = 1,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch mmss_camss_vfe1_ahb_clk = {
+ .halt_reg = 0x3678,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x3678,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "mmss_camss_vfe1_ahb_clk",
+ .parent_names = (const char *[]){
+ "ahb_clk_src",
+ },
+ .num_parents = 1,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch mmss_camss_vfe1_clk = {
+ .halt_reg = 0x36ac,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x36ac,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "mmss_camss_vfe1_clk",
+ .parent_names = (const char *[]){
+ "vfe1_clk_src",
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch mmss_camss_vfe1_stream_clk = {
+ .halt_reg = 0x3724,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x3724,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "mmss_camss_vfe1_stream_clk",
+ .parent_names = (const char *[]){
+ "vfe1_clk_src",
+ },
+ .num_parents = 1,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch mmss_camss_vfe_vbif_ahb_clk = {
+ .halt_reg = 0x36b8,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x36b8,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "mmss_camss_vfe_vbif_ahb_clk",
+ .parent_names = (const char *[]){
+ "ahb_clk_src",
+ },
+ .num_parents = 1,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch mmss_camss_vfe_vbif_axi_clk = {
+ .halt_reg = 0x36bc,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x36bc,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "mmss_camss_vfe_vbif_axi_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch mmss_csiphy_ahb2crif_clk = {
+ .halt_reg = 0x374c,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x374c,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "mmss_csiphy_ahb2crif_clk",
+ .parent_names = (const char *[]){
+ "ahb_clk_src",
+ },
+ .num_parents = 1,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch mmss_mdss_ahb_clk = {
+ .halt_reg = 0x2308,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x2308,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "mmss_mdss_ahb_clk",
+ .parent_names = (const char *[]){
+ "ahb_clk_src",
+ },
+ .num_parents = 1,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch mmss_mdss_axi_clk = {
+ .halt_reg = 0x2310,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x2310,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "mmss_mdss_axi_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch mmss_mdss_byte0_clk = {
+ .halt_reg = 0x233c,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x233c,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "mmss_mdss_byte0_clk",
+ .parent_names = (const char *[]){
+ "byte0_clk_src",
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch mmss_mdss_byte0_intf_clk = {
+ .halt_reg = 0x2374,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x2374,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "mmss_mdss_byte0_intf_clk",
+ .parent_names = (const char *[]){
+ "mmss_mdss_byte0_intf_div_clk",
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_regmap_div mmss_mdss_byte0_intf_div_clk = {
+ .reg = 0x237c,
+ .shift = 0,
+ .width = 2,
+ /*
+ * NOTE: Op does not work for div-3. Current assumption is that div-3
+ * is not a recommended setting for this divider.
+ */
+ .clkr = {
+ .hw.init = &(struct clk_init_data){
+ .name = "mmss_mdss_byte0_intf_div_clk",
+ .parent_names = (const char *[]){
+ "byte0_clk_src",
+ },
+ .num_parents = 1,
+ .ops = &clk_regmap_div_ops,
+ .flags = CLK_SET_RATE_PARENT | CLK_GET_RATE_NOCACHE,
+ },
+ },
+};
+
+static struct clk_branch mmss_mdss_byte1_clk = {
+ .halt_reg = 0x2340,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x2340,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "mmss_mdss_byte1_clk",
+ .parent_names = (const char *[]){
+ "byte1_clk_src",
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch mmss_mdss_byte1_intf_clk = {
+ .halt_reg = 0x2378,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x2378,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "mmss_mdss_byte1_intf_clk",
+ .parent_names = (const char *[]){
+ "byte1_clk_src",
+ },
+ .num_parents = 1,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch mmss_mdss_dp_aux_clk = {
+ .halt_reg = 0x2364,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x2364,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "mmss_mdss_dp_aux_clk",
+ .parent_names = (const char *[]){
+ "dp_aux_clk_src",
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch mmss_mdss_dp_crypto_clk = {
+ .halt_reg = 0x235c,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x235c,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "mmss_mdss_dp_crypto_clk",
+ .parent_names = (const char *[]){
+ "dp_crypto_clk_src",
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch mmss_mdss_dp_gtc_clk = {
+ .halt_reg = 0x2368,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x2368,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "mmss_mdss_dp_gtc_clk",
+ .parent_names = (const char *[]){
+ "dp_gtc_clk_src",
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch mmss_mdss_dp_link_clk = {
+ .halt_reg = 0x2354,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x2354,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "mmss_mdss_dp_link_clk",
+ .parent_names = (const char *[]){
+ "dp_link_clk_src",
+ },
+ .num_parents = 1,
+ .flags = CLK_GET_RATE_NOCACHE | CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+/* Reset state of MMSS_MDSS_DP_LINK_INTF_DIV is 0x3 (div-4) */
+static struct clk_branch mmss_mdss_dp_link_intf_clk = {
+ .halt_reg = 0x2358,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x2358,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "mmss_mdss_dp_link_intf_clk",
+ .parent_names = (const char *[]){
+ "dp_link_clk_src",
+ },
+ .num_parents = 1,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch mmss_mdss_dp_pixel_clk = {
+ .halt_reg = 0x2360,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x2360,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "mmss_mdss_dp_pixel_clk",
+ .parent_names = (const char *[]){
+ "dp_pixel_clk_src",
+ },
+ .num_parents = 1,
+ .flags = CLK_GET_RATE_NOCACHE | CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch mmss_mdss_esc0_clk = {
+ .halt_reg = 0x2344,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x2344,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "mmss_mdss_esc0_clk",
+ .parent_names = (const char *[]){
+ "esc0_clk_src",
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch mmss_mdss_esc1_clk = {
+ .halt_reg = 0x2348,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x2348,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "mmss_mdss_esc1_clk",
+ .parent_names = (const char *[]){
+ "esc1_clk_src",
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch mmss_mdss_hdmi_dp_ahb_clk = {
+ .halt_reg = 0x230c,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x230c,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "mmss_mdss_hdmi_dp_ahb_clk",
+ .parent_names = (const char *[]){
+ "ahb_clk_src",
+ },
+ .num_parents = 1,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch mmss_mdss_mdp_clk = {
+ .halt_reg = 0x231c,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x231c,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "mmss_mdss_mdp_clk",
+ .parent_names = (const char *[]){
+ "mdp_clk_src",
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch mmss_mdss_pclk0_clk = {
+ .halt_reg = 0x2314,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x2314,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "mmss_mdss_pclk0_clk",
+ .parent_names = (const char *[]){
+ "pclk0_clk_src",
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch mmss_mdss_pclk1_clk = {
+ .halt_reg = 0x2318,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x2318,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "mmss_mdss_pclk1_clk",
+ .parent_names = (const char *[]){
+ "pclk1_clk_src",
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch mmss_mdss_rot_clk = {
+ .halt_reg = 0x2350,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x2350,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "mmss_mdss_rot_clk",
+ .parent_names = (const char *[]){
+ "rot_clk_src",
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch mmss_mdss_vsync_clk = {
+ .halt_reg = 0x2328,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x2328,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "mmss_mdss_vsync_clk",
+ .parent_names = (const char *[]){
+ "vsync_clk_src",
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch mmss_misc_ahb_clk = {
+ .halt_reg = 0x328,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x328,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "mmss_misc_ahb_clk",
+ /*
+ * Dependency to be enabled before the branch is
+ * enabled.
+ */
+ .parent_names = (const char *[]){
+ "mmss_mnoc_ahb_clk",
+ },
+ .num_parents = 1,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch mmss_misc_cxo_clk = {
+ .halt_reg = 0x324,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x324,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "mmss_misc_cxo_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch mmss_mnoc_ahb_clk = {
+ .halt_reg = 0x5024,
+ .halt_check = BRANCH_VOTED,
+ .clkr = {
+ .enable_reg = 0x5024,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "mmss_mnoc_ahb_clk",
+ .parent_names = (const char *[]){
+ "ahb_clk_src",
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch mmss_snoc_dvm_axi_clk = {
+ .halt_reg = 0xe040,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0xe040,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "mmss_snoc_dvm_axi_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch mmss_video_ahb_clk = {
+ .halt_reg = 0x1030,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x1030,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "mmss_video_ahb_clk",
+ .parent_names = (const char *[]){
+ "ahb_clk_src",
+ },
+ .num_parents = 1,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch mmss_video_axi_clk = {
+ .halt_reg = 0x1034,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x1034,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "mmss_video_axi_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch mmss_video_core_clk = {
+ .halt_reg = 0x1028,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x1028,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "mmss_video_core_clk",
+ .parent_names = (const char *[]){
+ "video_core_clk_src",
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch mmss_video_subcore0_clk = {
+ .halt_reg = 0x1048,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x1048,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "mmss_video_subcore0_clk",
+ .parent_names = (const char *[]){
+ "video_core_clk_src",
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT | CLK_GET_RATE_NOCACHE,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_regmap *mmcc_falcon_clocks[] = {
+ [AHB_CLK_SRC] = &ahb_clk_src.clkr,
+ [BYTE0_CLK_SRC] = &byte0_clk_src.clkr,
+ [BYTE1_CLK_SRC] = &byte1_clk_src.clkr,
+ [CAMSS_GP0_CLK_SRC] = &camss_gp0_clk_src.clkr,
+ [CAMSS_GP1_CLK_SRC] = &camss_gp1_clk_src.clkr,
+ [CCI_CLK_SRC] = &cci_clk_src.clkr,
+ [CPP_CLK_SRC] = &cpp_clk_src.clkr,
+ [CSI0_CLK_SRC] = &csi0_clk_src.clkr,
+ [CSI0PHYTIMER_CLK_SRC] = &csi0phytimer_clk_src.clkr,
+ [CSI1_CLK_SRC] = &csi1_clk_src.clkr,
+ [CSI1PHYTIMER_CLK_SRC] = &csi1phytimer_clk_src.clkr,
+ [CSI2_CLK_SRC] = &csi2_clk_src.clkr,
+ [CSI2PHYTIMER_CLK_SRC] = &csi2phytimer_clk_src.clkr,
+ [CSI3_CLK_SRC] = &csi3_clk_src.clkr,
+ [CSIPHY_CLK_SRC] = &csiphy_clk_src.clkr,
+ [DP_AUX_CLK_SRC] = &dp_aux_clk_src.clkr,
+ [DP_CRYPTO_CLK_SRC] = &dp_crypto_clk_src.clkr,
+ [DP_GTC_CLK_SRC] = &dp_gtc_clk_src.clkr,
+ [DP_LINK_CLK_SRC] = &dp_link_clk_src.clkr,
+ [DP_PIXEL_CLK_SRC] = &dp_pixel_clk_src.clkr,
+ [ESC0_CLK_SRC] = &esc0_clk_src.clkr,
+ [ESC1_CLK_SRC] = &esc1_clk_src.clkr,
+ [JPEG0_CLK_SRC] = &jpeg0_clk_src.clkr,
+ [MCLK0_CLK_SRC] = &mclk0_clk_src.clkr,
+ [MCLK1_CLK_SRC] = &mclk1_clk_src.clkr,
+ [MCLK2_CLK_SRC] = &mclk2_clk_src.clkr,
+ [MCLK3_CLK_SRC] = &mclk3_clk_src.clkr,
+ [MDP_CLK_SRC] = &mdp_clk_src.clkr,
+ [MMPLL0_PLL] = &mmpll0_pll_out_main.clkr,
+ [MMPLL10_PLL] = &mmpll10_pll_out_main.clkr,
+ [MMPLL3_PLL] = &mmpll3_pll_out_main.clkr,
+ [MMPLL4_PLL] = &mmpll4_pll_out_main.clkr,
+ [MMPLL5_PLL] = &mmpll5_pll_out_main.clkr,
+ [MMPLL6_PLL] = &mmpll6_pll_out_main.clkr,
+ [MMPLL7_PLL] = &mmpll7_pll_out_main.clkr,
+ [MMPLL8_PLL] = &mmpll8_pll_out_main.clkr,
+ [MMSS_BIMC_SMMU_AHB_CLK] = &mmss_bimc_smmu_ahb_clk.clkr,
+ [MMSS_BIMC_SMMU_AXI_CLK] = &mmss_bimc_smmu_axi_clk.clkr,
+ [MMSS_CAMSS_AHB_CLK] = &mmss_camss_ahb_clk.clkr,
+ [MMSS_CAMSS_CCI_AHB_CLK] = &mmss_camss_cci_ahb_clk.clkr,
+ [MMSS_CAMSS_CCI_CLK] = &mmss_camss_cci_clk.clkr,
+ [MMSS_CAMSS_CPHY_CSID0_CLK] = &mmss_camss_cphy_csid0_clk.clkr,
+ [MMSS_CAMSS_CPHY_CSID1_CLK] = &mmss_camss_cphy_csid1_clk.clkr,
+ [MMSS_CAMSS_CPHY_CSID2_CLK] = &mmss_camss_cphy_csid2_clk.clkr,
+ [MMSS_CAMSS_CPHY_CSID3_CLK] = &mmss_camss_cphy_csid3_clk.clkr,
+ [MMSS_CAMSS_CPP_AHB_CLK] = &mmss_camss_cpp_ahb_clk.clkr,
+ [MMSS_CAMSS_CPP_AXI_CLK] = &mmss_camss_cpp_axi_clk.clkr,
+ [MMSS_CAMSS_CPP_CLK] = &mmss_camss_cpp_clk.clkr,
+ [MMSS_CAMSS_CPP_VBIF_AHB_CLK] = &mmss_camss_cpp_vbif_ahb_clk.clkr,
+ [MMSS_CAMSS_CSI0_AHB_CLK] = &mmss_camss_csi0_ahb_clk.clkr,
+ [MMSS_CAMSS_CSI0_CLK] = &mmss_camss_csi0_clk.clkr,
+ [MMSS_CAMSS_CSI0PHYTIMER_CLK] = &mmss_camss_csi0phytimer_clk.clkr,
+ [MMSS_CAMSS_CSI0PIX_CLK] = &mmss_camss_csi0pix_clk.clkr,
+ [MMSS_CAMSS_CSI0RDI_CLK] = &mmss_camss_csi0rdi_clk.clkr,
+ [MMSS_CAMSS_CSI1_AHB_CLK] = &mmss_camss_csi1_ahb_clk.clkr,
+ [MMSS_CAMSS_CSI1_CLK] = &mmss_camss_csi1_clk.clkr,
+ [MMSS_CAMSS_CSI1PHYTIMER_CLK] = &mmss_camss_csi1phytimer_clk.clkr,
+ [MMSS_CAMSS_CSI1PIX_CLK] = &mmss_camss_csi1pix_clk.clkr,
+ [MMSS_CAMSS_CSI1RDI_CLK] = &mmss_camss_csi1rdi_clk.clkr,
+ [MMSS_CAMSS_CSI2_AHB_CLK] = &mmss_camss_csi2_ahb_clk.clkr,
+ [MMSS_CAMSS_CSI2_CLK] = &mmss_camss_csi2_clk.clkr,
+ [MMSS_CAMSS_CSI2PHYTIMER_CLK] = &mmss_camss_csi2phytimer_clk.clkr,
+ [MMSS_CAMSS_CSI2PIX_CLK] = &mmss_camss_csi2pix_clk.clkr,
+ [MMSS_CAMSS_CSI2RDI_CLK] = &mmss_camss_csi2rdi_clk.clkr,
+ [MMSS_CAMSS_CSI3_AHB_CLK] = &mmss_camss_csi3_ahb_clk.clkr,
+ [MMSS_CAMSS_CSI3_CLK] = &mmss_camss_csi3_clk.clkr,
+ [MMSS_CAMSS_CSI3PIX_CLK] = &mmss_camss_csi3pix_clk.clkr,
+ [MMSS_CAMSS_CSI3RDI_CLK] = &mmss_camss_csi3rdi_clk.clkr,
+ [MMSS_CAMSS_CSI_VFE0_CLK] = &mmss_camss_csi_vfe0_clk.clkr,
+ [MMSS_CAMSS_CSI_VFE1_CLK] = &mmss_camss_csi_vfe1_clk.clkr,
+ [MMSS_CAMSS_CSIPHY0_CLK] = &mmss_camss_csiphy0_clk.clkr,
+ [MMSS_CAMSS_CSIPHY1_CLK] = &mmss_camss_csiphy1_clk.clkr,
+ [MMSS_CAMSS_CSIPHY2_CLK] = &mmss_camss_csiphy2_clk.clkr,
+ [MMSS_CAMSS_GP0_CLK] = &mmss_camss_gp0_clk.clkr,
+ [MMSS_CAMSS_GP1_CLK] = &mmss_camss_gp1_clk.clkr,
+ [MMSS_CAMSS_ISPIF_AHB_CLK] = &mmss_camss_ispif_ahb_clk.clkr,
+ [MMSS_CAMSS_JPEG0_CLK] = &mmss_camss_jpeg0_clk.clkr,
+ [MMSS_CAMSS_JPEG_AHB_CLK] = &mmss_camss_jpeg_ahb_clk.clkr,
+ [MMSS_CAMSS_JPEG_AXI_CLK] = &mmss_camss_jpeg_axi_clk.clkr,
+ [MMSS_CAMSS_MCLK0_CLK] = &mmss_camss_mclk0_clk.clkr,
+ [MMSS_CAMSS_MCLK1_CLK] = &mmss_camss_mclk1_clk.clkr,
+ [MMSS_CAMSS_MCLK2_CLK] = &mmss_camss_mclk2_clk.clkr,
+ [MMSS_CAMSS_MCLK3_CLK] = &mmss_camss_mclk3_clk.clkr,
+ [MMSS_CAMSS_MICRO_AHB_CLK] = &mmss_camss_micro_ahb_clk.clkr,
+ [MMSS_CAMSS_TOP_AHB_CLK] = &mmss_camss_top_ahb_clk.clkr,
+ [MMSS_CAMSS_VFE0_AHB_CLK] = &mmss_camss_vfe0_ahb_clk.clkr,
+ [MMSS_CAMSS_VFE0_CLK] = &mmss_camss_vfe0_clk.clkr,
+ [MMSS_CAMSS_VFE0_STREAM_CLK] = &mmss_camss_vfe0_stream_clk.clkr,
+ [MMSS_CAMSS_VFE1_AHB_CLK] = &mmss_camss_vfe1_ahb_clk.clkr,
+ [MMSS_CAMSS_VFE1_CLK] = &mmss_camss_vfe1_clk.clkr,
+ [MMSS_CAMSS_VFE1_STREAM_CLK] = &mmss_camss_vfe1_stream_clk.clkr,
+ [MMSS_CAMSS_VFE_VBIF_AHB_CLK] = &mmss_camss_vfe_vbif_ahb_clk.clkr,
+ [MMSS_CAMSS_VFE_VBIF_AXI_CLK] = &mmss_camss_vfe_vbif_axi_clk.clkr,
+ [MMSS_CSIPHY_AHB2CRIF_CLK] = &mmss_csiphy_ahb2crif_clk.clkr,
+ [MMSS_MDSS_AHB_CLK] = &mmss_mdss_ahb_clk.clkr,
+ [MMSS_MDSS_AXI_CLK] = &mmss_mdss_axi_clk.clkr,
+ [MMSS_MDSS_BYTE0_CLK] = &mmss_mdss_byte0_clk.clkr,
+ [MMSS_MDSS_BYTE0_INTF_CLK] = &mmss_mdss_byte0_intf_clk.clkr,
+ [MMSS_MDSS_BYTE0_INTF_DIV_CLK] = &mmss_mdss_byte0_intf_div_clk.clkr,
+ [MMSS_MDSS_BYTE1_CLK] = &mmss_mdss_byte1_clk.clkr,
+ [MMSS_MDSS_BYTE1_INTF_CLK] = &mmss_mdss_byte1_intf_clk.clkr,
+ [MMSS_MDSS_DP_AUX_CLK] = &mmss_mdss_dp_aux_clk.clkr,
+ [MMSS_MDSS_DP_CRYPTO_CLK] = &mmss_mdss_dp_crypto_clk.clkr,
+ [MMSS_MDSS_DP_GTC_CLK] = &mmss_mdss_dp_gtc_clk.clkr,
+ [MMSS_MDSS_DP_LINK_CLK] = &mmss_mdss_dp_link_clk.clkr,
+ [MMSS_MDSS_DP_LINK_INTF_CLK] = &mmss_mdss_dp_link_intf_clk.clkr,
+ [MMSS_MDSS_DP_PIXEL_CLK] = &mmss_mdss_dp_pixel_clk.clkr,
+ [MMSS_MDSS_ESC0_CLK] = &mmss_mdss_esc0_clk.clkr,
+ [MMSS_MDSS_ESC1_CLK] = &mmss_mdss_esc1_clk.clkr,
+ [MMSS_MDSS_HDMI_DP_AHB_CLK] = &mmss_mdss_hdmi_dp_ahb_clk.clkr,
+ [MMSS_MDSS_MDP_CLK] = &mmss_mdss_mdp_clk.clkr,
+ [MMSS_MDSS_PCLK0_CLK] = &mmss_mdss_pclk0_clk.clkr,
+ [MMSS_MDSS_PCLK1_CLK] = &mmss_mdss_pclk1_clk.clkr,
+ [MMSS_MDSS_ROT_CLK] = &mmss_mdss_rot_clk.clkr,
+ [MMSS_MDSS_VSYNC_CLK] = &mmss_mdss_vsync_clk.clkr,
+ [MMSS_MISC_AHB_CLK] = &mmss_misc_ahb_clk.clkr,
+ [MMSS_MISC_CXO_CLK] = &mmss_misc_cxo_clk.clkr,
+ [MMSS_MNOC_AHB_CLK] = &mmss_mnoc_ahb_clk.clkr,
+ [MMSS_SNOC_DVM_AXI_CLK] = &mmss_snoc_dvm_axi_clk.clkr,
+ [MMSS_VIDEO_AHB_CLK] = &mmss_video_ahb_clk.clkr,
+ [MMSS_VIDEO_AXI_CLK] = &mmss_video_axi_clk.clkr,
+ [MMSS_VIDEO_CORE_CLK] = &mmss_video_core_clk.clkr,
+ [MMSS_VIDEO_SUBCORE0_CLK] = &mmss_video_subcore0_clk.clkr,
+ [PCLK0_CLK_SRC] = &pclk0_clk_src.clkr,
+ [PCLK1_CLK_SRC] = &pclk1_clk_src.clkr,
+ [ROT_CLK_SRC] = &rot_clk_src.clkr,
+ [VFE0_CLK_SRC] = &vfe0_clk_src.clkr,
+ [VFE1_CLK_SRC] = &vfe1_clk_src.clkr,
+ [VIDEO_CORE_CLK_SRC] = &video_core_clk_src.clkr,
+ [VSYNC_CLK_SRC] = &vsync_clk_src.clkr,
+};
+
+static const struct qcom_reset_map mmcc_falcon_resets[] = {
+ [CAMSS_MICRO_BCR] = { 0x3490 },
+};
+
+static const struct regmap_config mmcc_falcon_regmap_config = {
+ .reg_bits = 32,
+ .reg_stride = 4,
+ .val_bits = 32,
+ .max_register = 0x10004,
+ .fast_io = true,
+};
+
+static const struct qcom_cc_desc mmcc_falcon_desc = {
+ .config = &mmcc_falcon_regmap_config,
+ .clks = mmcc_falcon_clocks,
+ .num_clks = ARRAY_SIZE(mmcc_falcon_clocks),
+ .resets = mmcc_falcon_resets,
+ .num_resets = ARRAY_SIZE(mmcc_falcon_resets),
+};
+
+static const struct of_device_id mmcc_falcon_match_table[] = {
+ { .compatible = "qcom,mmcc-msmfalcon" },
+ { }
+};
+MODULE_DEVICE_TABLE(of, mmcc_falcon_match_table);
+
+static int mmcc_falcon_probe(struct platform_device *pdev)
+{
+ int ret = 0;
+ struct regmap *regmap;
+
+ regmap = qcom_cc_map(pdev, &mmcc_falcon_desc);
+ if (IS_ERR(regmap))
+ return PTR_ERR(regmap);
+
+ /* PLLs connected on Mx rails of MMSS_CC */
+ vdd_mx.regulator[0] = devm_regulator_get(&pdev->dev, "vdd_mx_mmss");
+ if (IS_ERR(vdd_mx.regulator[0])) {
+ if (!(PTR_ERR(vdd_mx.regulator[0]) == -EPROBE_DEFER))
+ dev_err(&pdev->dev,
+ "Unable to get vdd_mx_mmss regulator\n");
+ return PTR_ERR(vdd_mx.regulator[0]);
+ }
+
+ vdd_dig.regulator[0] = devm_regulator_get(&pdev->dev, "vdd_dig_mmss");
+ if (IS_ERR(vdd_dig.regulator[0])) {
+ if (!(PTR_ERR(vdd_dig.regulator[0]) == -EPROBE_DEFER))
+ dev_err(&pdev->dev,
+ "Unable to get vdd_dig regulator\n");
+ return PTR_ERR(vdd_dig.regulator[0]);
+ }
+
+ /* MMPLL10 connected to the Analog Rail */
+ vdda.regulator[0] = devm_regulator_get(&pdev->dev, "vdda");
+ if (IS_ERR(vdda.regulator[0])) {
+ if (!(PTR_ERR(vdda.regulator[0]) == -EPROBE_DEFER))
+ dev_err(&pdev->dev,
+ "Unable to get vdda regulator\n");
+ return PTR_ERR(vdda.regulator[0]);
+ }
+
+ clk_alpha_pll_configure(&mmpll3_pll_out_main, regmap, &mmpll3_config);
+ clk_alpha_pll_configure(&mmpll4_pll_out_main, regmap, &mmpll4_config);
+ clk_alpha_pll_configure(&mmpll5_pll_out_main, regmap, &mmpll5_config);
+ clk_alpha_pll_configure(&mmpll7_pll_out_main, regmap, &mmpll7_config);
+ clk_alpha_pll_configure(&mmpll8_pll_out_main, regmap, &mmpll8_config);
+ clk_alpha_pll_configure(&mmpll10_pll_out_main, regmap, &mmpll10_config);
+
+ ret = qcom_cc_really_probe(pdev, &mmcc_falcon_desc, regmap);
+ if (ret) {
+ dev_err(&pdev->dev, "Failed to register MMSS clocks\n");
+ return ret;
+ }
+
+ dev_info(&pdev->dev, "Registered MMSS clocks\n");
+
+ return ret;
+}
+
+static struct platform_driver mmcc_falcon_driver = {
+ .probe = mmcc_falcon_probe,
+ .driver = {
+ .name = "mmcc-msmfalcon",
+ .of_match_table = mmcc_falcon_match_table,
+ },
+};
+
+static int __init mmcc_falcon_init(void)
+{
+ return platform_driver_register(&mmcc_falcon_driver);
+}
+core_initcall_sync(mmcc_falcon_init);
+
+static void __exit mmcc_falcon_exit(void)
+{
+ platform_driver_unregister(&mmcc_falcon_driver);
+}
+module_exit(mmcc_falcon_exit);
diff --git a/drivers/clk/qcom/vdd-level-falcon.h b/drivers/clk/qcom/vdd-level-falcon.h
index d54e801ecc67..8f9eefe3a89c 100644
--- a/drivers/clk/qcom/vdd-level-falcon.h
+++ b/drivers/clk/qcom/vdd-level-falcon.h
@@ -116,6 +116,21 @@
}, \
.num_rate_max = VDD_DIG_NUM
+#define VDD_MMSS_PLL_DIG_FMAX_MAP1(l1, f1) \
+ .vdd_class = &vdd_mx, \
+ .rate_max = (unsigned long[VDD_DIG_NUM]) { \
+ [VDD_DIG_##l1] = (f1), \
+ }, \
+ .num_rate_max = VDD_DIG_NUM
+
+#define VDD_MMSS_PLL_DIG_FMAX_MAP2(l1, f1, l2, f2) \
+ .vdd_class = &vdd_mx, \
+ .rate_max = (unsigned long[VDD_DIG_NUM]) { \
+ [VDD_DIG_##l1] = (f1), \
+ [VDD_DIG_##l2] = (f2), \
+ }, \
+ .num_rate_max = VDD_DIG_NUM
+
enum vdd_dig_levels {
VDD_DIG_NONE,
VDD_DIG_MIN, /* MIN SVS */
diff --git a/drivers/crypto/msm/qce50.c b/drivers/crypto/msm/qce50.c
index 55c043b44cea..0bef7effe601 100644
--- a/drivers/crypto/msm/qce50.c
+++ b/drivers/crypto/msm/qce50.c
@@ -1347,7 +1347,8 @@ go_proc:
CRYPTO_CONFIG_REG));
/* issue go to crypto */
if (use_hw_key == false) {
- QCE_WRITE_REG(((1 << CRYPTO_GO) | (1 << CRYPTO_RESULTS_DUMP)),
+ QCE_WRITE_REG(((1 << CRYPTO_GO) | (1 << CRYPTO_RESULTS_DUMP) |
+ (1 << CRYPTO_CLR_CNTXT)),
pce_dev->iobase + CRYPTO_GOPROC_REG);
} else {
QCE_WRITE_REG(((1 << CRYPTO_GO) | (1 << CRYPTO_RESULTS_DUMP)),
@@ -1528,7 +1529,8 @@ static int _ce_setup_aead_direct(struct qce_device *pce_dev,
CRYPTO_CONFIG_REG));
/* issue go to crypto */
- QCE_WRITE_REG(((1 << CRYPTO_GO) | (1 << CRYPTO_RESULTS_DUMP)),
+ QCE_WRITE_REG(((1 << CRYPTO_GO) | (1 << CRYPTO_RESULTS_DUMP) |
+ (1 << CRYPTO_CLR_CNTXT)),
pce_dev->iobase + CRYPTO_GOPROC_REG);
/*
* Ensure previous instructions (setting the GO register)
@@ -1847,7 +1849,8 @@ static int _ce_setup_cipher_direct(struct qce_device *pce_dev,
CRYPTO_CONFIG_REG));
/* issue go to crypto */
if (use_hw_key == false) {
- QCE_WRITE_REG(((1 << CRYPTO_GO) | (1 << CRYPTO_RESULTS_DUMP)),
+ QCE_WRITE_REG(((1 << CRYPTO_GO) | (1 << CRYPTO_RESULTS_DUMP) |
+ (1 << CRYPTO_CLR_CNTXT)),
pce_dev->iobase + CRYPTO_GOPROC_REG);
} else {
QCE_WRITE_REG(((1 << CRYPTO_GO) | (1 << CRYPTO_RESULTS_DUMP)),
@@ -1935,7 +1938,8 @@ static int _ce_f9_setup_direct(struct qce_device *pce_dev,
QCE_WRITE_REG(pce_dev->reg.crypto_cfg_le, (pce_dev->iobase +
CRYPTO_CONFIG_REG));
/* write go */
- QCE_WRITE_REG(((1 << CRYPTO_GO) | (1 << CRYPTO_RESULTS_DUMP)),
+ QCE_WRITE_REG(((1 << CRYPTO_GO) | (1 << CRYPTO_RESULTS_DUMP) |
+ (1 << CRYPTO_CLR_CNTXT)),
pce_dev->iobase + CRYPTO_GOPROC_REG);
/*
* Ensure previous instructions (setting the GO register)
@@ -2012,7 +2016,8 @@ static int _ce_f8_setup_direct(struct qce_device *pce_dev,
QCE_WRITE_REG(pce_dev->reg.crypto_cfg_le, (pce_dev->iobase +
CRYPTO_CONFIG_REG));
/* write go */
- QCE_WRITE_REG(((1 << CRYPTO_GO) | (1 << CRYPTO_RESULTS_DUMP)),
+ QCE_WRITE_REG(((1 << CRYPTO_GO) | (1 << CRYPTO_RESULTS_DUMP) |
+ (1 << CRYPTO_CLR_CNTXT)),
pce_dev->iobase + CRYPTO_GOPROC_REG);
/*
* Ensure previous instructions (setting the GO register)
@@ -3336,8 +3341,8 @@ static int _setup_cipher_aes_cmdlistptrs(struct qce_device *pdev, int cri_index,
pdev->reg.crypto_cfg_le, NULL);
qce_add_cmd_element(pdev, &ce_vaddr, CRYPTO_GOPROC_REG,
- ((1 << CRYPTO_GO) | (1 << CRYPTO_RESULTS_DUMP)),
- &pcl_info->go_proc);
+ ((1 << CRYPTO_GO) | (1 << CRYPTO_RESULTS_DUMP) |
+ (1 << CRYPTO_CLR_CNTXT)), &pcl_info->go_proc);
pcl_info->size = (uintptr_t)ce_vaddr - (uintptr_t)ce_vaddr_start;
*pvaddr = (unsigned char *) ce_vaddr;
@@ -3450,8 +3455,8 @@ static int _setup_cipher_des_cmdlistptrs(struct qce_device *pdev, int cri_index,
pdev->reg.crypto_cfg_le, NULL);
qce_add_cmd_element(pdev, &ce_vaddr, CRYPTO_GOPROC_REG,
- ((1 << CRYPTO_GO) | (1 << CRYPTO_RESULTS_DUMP)),
- &pcl_info->go_proc);
+ ((1 << CRYPTO_GO) | (1 << CRYPTO_RESULTS_DUMP) |
+ (1 << CRYPTO_CLR_CNTXT)), &pcl_info->go_proc);
pcl_info->size = (uintptr_t)ce_vaddr - (uintptr_t)ce_vaddr_start;
*pvaddr = (unsigned char *) ce_vaddr;
@@ -3494,8 +3499,8 @@ static int _setup_cipher_null_cmdlistptrs(struct qce_device *pdev,
NULL);
qce_add_cmd_element(pdev, &ce_vaddr, CRYPTO_GOPROC_REG,
- ((1 << CRYPTO_GO) | (1 << CRYPTO_RESULTS_DUMP)),
- &pcl_info->go_proc);
+ ((1 << CRYPTO_GO) | (1 << CRYPTO_RESULTS_DUMP) |
+ (1 << CRYPTO_CLR_CNTXT)), &pcl_info->go_proc);
pcl_info->size = (uintptr_t)ce_vaddr - (uintptr_t)ce_vaddr_start;
*pvaddr = (unsigned char *) ce_vaddr;
@@ -3672,8 +3677,8 @@ static int _setup_auth_cmdlistptrs(struct qce_device *pdev, int cri_index,
pdev->reg.crypto_cfg_le, NULL);
qce_add_cmd_element(pdev, &ce_vaddr, CRYPTO_GOPROC_REG,
- ((1 << CRYPTO_GO) | (1 << CRYPTO_RESULTS_DUMP)),
- &pcl_info->go_proc);
+ ((1 << CRYPTO_GO) | (1 << CRYPTO_RESULTS_DUMP) |
+ (1 << CRYPTO_CLR_CNTXT)), &pcl_info->go_proc);
pcl_info->size = (uintptr_t)ce_vaddr - (uintptr_t)ce_vaddr_start;
*pvaddr = (unsigned char *) ce_vaddr;
@@ -3889,8 +3894,8 @@ static int _setup_aead_cmdlistptrs(struct qce_device *pdev,
pdev->reg.crypto_cfg_le, NULL);
qce_add_cmd_element(pdev, &ce_vaddr, CRYPTO_GOPROC_REG,
- ((1 << CRYPTO_GO) | (1 << CRYPTO_RESULTS_DUMP)),
- &pcl_info->go_proc);
+ ((1 << CRYPTO_GO) | (1 << CRYPTO_RESULTS_DUMP) |
+ (1 << CRYPTO_CLR_CNTXT)), &pcl_info->go_proc);
pcl_info->size = (uintptr_t)ce_vaddr - (uintptr_t)ce_vaddr_start;
*pvaddr = (unsigned char *) ce_vaddr;
@@ -4022,8 +4027,8 @@ static int _setup_aead_ccm_cmdlistptrs(struct qce_device *pdev, int cri_index,
pdev->reg.crypto_cfg_le, NULL);
qce_add_cmd_element(pdev, &ce_vaddr, CRYPTO_GOPROC_REG,
- ((1 << CRYPTO_GO) | (1 << CRYPTO_RESULTS_DUMP)),
- &pcl_info->go_proc);
+ ((1 << CRYPTO_GO) | (1 << CRYPTO_RESULTS_DUMP) |
+ (1 << CRYPTO_CLR_CNTXT)), &pcl_info->go_proc);
pcl_info->size = (uintptr_t)ce_vaddr - (uintptr_t)ce_vaddr_start;
*pvaddr = (unsigned char *) ce_vaddr;
@@ -4108,8 +4113,8 @@ static int _setup_f8_cmdlistptrs(struct qce_device *pdev, int cri_index,
pdev->reg.crypto_cfg_le, NULL);
qce_add_cmd_element(pdev, &ce_vaddr, CRYPTO_GOPROC_REG,
- ((1 << CRYPTO_GO) | (1 << CRYPTO_RESULTS_DUMP)),
- &pcl_info->go_proc);
+ ((1 << CRYPTO_GO) | (1 << CRYPTO_RESULTS_DUMP) |
+ (1 << CRYPTO_CLR_CNTXT)), &pcl_info->go_proc);
pcl_info->size = (uintptr_t)ce_vaddr - (uintptr_t)ce_vaddr_start;
*pvaddr = (unsigned char *) ce_vaddr;
@@ -4190,8 +4195,8 @@ static int _setup_f9_cmdlistptrs(struct qce_device *pdev, int cri_index,
pdev->reg.crypto_cfg_le, NULL);
qce_add_cmd_element(pdev, &ce_vaddr, CRYPTO_GOPROC_REG,
- ((1 << CRYPTO_GO) | (1 << CRYPTO_RESULTS_DUMP)),
- &pcl_info->go_proc);
+ ((1 << CRYPTO_GO) | (1 << CRYPTO_RESULTS_DUMP) |
+ (1 << CRYPTO_CLR_CNTXT)), &pcl_info->go_proc);
pcl_info->size = (uintptr_t)ce_vaddr - (uintptr_t)ce_vaddr_start;
*pvaddr = (unsigned char *) ce_vaddr;
diff --git a/drivers/crypto/msm/qcedev.c b/drivers/crypto/msm/qcedev.c
index e2099c4e7877..433e4783d1d1 100644
--- a/drivers/crypto/msm/qcedev.c
+++ b/drivers/crypto/msm/qcedev.c
@@ -603,7 +603,7 @@ static int qcedev_sha_update_max_xfer(struct qcedev_async_req *qcedev_areq,
while (len > 0) {
user_src =
(void __user *)qcedev_areq->sha_op_req.data[i].vaddr;
- if (user_src && __copy_from_user(k_src,
+ if (user_src && copy_from_user(k_src,
(void __user *)user_src,
qcedev_areq->sha_op_req.data[i].len))
return -EFAULT;
@@ -639,7 +639,7 @@ static int qcedev_sha_update_max_xfer(struct qcedev_async_req *qcedev_areq,
/* Copy data from user src(s) */
user_src = (void __user *)qcedev_areq->sha_op_req.data[0].vaddr;
- if (user_src && __copy_from_user(k_src,
+ if (user_src && copy_from_user(k_src,
(void __user *)user_src,
qcedev_areq->sha_op_req.data[0].len)) {
kzfree(k_buf_src);
@@ -648,7 +648,7 @@ static int qcedev_sha_update_max_xfer(struct qcedev_async_req *qcedev_areq,
k_src += qcedev_areq->sha_op_req.data[0].len;
for (i = 1; i < qcedev_areq->sha_op_req.entries; i++) {
user_src = (void __user *)qcedev_areq->sha_op_req.data[i].vaddr;
- if (user_src && __copy_from_user(k_src,
+ if (user_src && copy_from_user(k_src,
(void __user *)user_src,
qcedev_areq->sha_op_req.data[i].len)) {
kzfree(k_buf_src);
@@ -702,13 +702,6 @@ static int qcedev_sha_update(struct qcedev_async_req *qcedev_areq,
return -EINVAL;
}
- /* verify address src(s) */
- for (i = 0; i < qcedev_areq->sha_op_req.entries; i++)
- if (!access_ok(VERIFY_READ,
- (void __user *)qcedev_areq->sha_op_req.data[i].vaddr,
- qcedev_areq->sha_op_req.data[i].len))
- return -EFAULT;
-
if (qcedev_areq->sha_op_req.data_len > QCE_MAX_OPER_DATA) {
struct qcedev_sha_op_req *saved_req;
@@ -868,19 +861,7 @@ static int qcedev_hash_cmac(struct qcedev_async_req *qcedev_areq,
total = qcedev_areq->sha_op_req.data_len;
- /* verify address src(s) */
- for (i = 0; i < qcedev_areq->sha_op_req.entries; i++)
- if (!access_ok(VERIFY_READ,
- (void __user *)qcedev_areq->sha_op_req.data[i].vaddr,
- qcedev_areq->sha_op_req.data[i].len))
- return -EFAULT;
-
- /* Verify Source Address */
- if (!access_ok(VERIFY_READ,
- (void __user *)qcedev_areq->sha_op_req.authkey,
- qcedev_areq->sha_op_req.authklen))
- return -EFAULT;
- if (__copy_from_user(&handle->sha_ctxt.authkey[0],
+ if (copy_from_user(&handle->sha_ctxt.authkey[0],
(void __user *)qcedev_areq->sha_op_req.authkey,
qcedev_areq->sha_op_req.authklen))
return -EFAULT;
@@ -900,7 +881,7 @@ static int qcedev_hash_cmac(struct qcedev_async_req *qcedev_areq,
for (i = 0; i < qcedev_areq->sha_op_req.entries; i++) {
user_src =
(void __user *)qcedev_areq->sha_op_req.data[i].vaddr;
- if (user_src && __copy_from_user(k_src, (void __user *)user_src,
+ if (user_src && copy_from_user(k_src, (void __user *)user_src,
qcedev_areq->sha_op_req.data[i].len)) {
kzfree(k_buf_src);
return -EFAULT;
@@ -928,12 +909,7 @@ static int qcedev_set_hmac_auth_key(struct qcedev_async_req *areq,
if (areq->sha_op_req.authklen <= QCEDEV_MAX_KEY_SIZE) {
qcedev_sha_init(areq, handle);
- /* Verify Source Address */
- if (!access_ok(VERIFY_READ,
- (void __user *)areq->sha_op_req.authkey,
- areq->sha_op_req.authklen))
- return -EFAULT;
- if (__copy_from_user(&handle->sha_ctxt.authkey[0],
+ if (copy_from_user(&handle->sha_ctxt.authkey[0],
(void __user *)areq->sha_op_req.authkey,
areq->sha_op_req.authklen))
return -EFAULT;
@@ -1146,7 +1122,7 @@ static int qcedev_vbuf_ablk_cipher_max_xfer(struct qcedev_async_req *areq,
byteoffset = areq->cipher_op_req.byteoffset;
user_src = (void __user *)areq->cipher_op_req.vbuf.src[0].vaddr;
- if (user_src && __copy_from_user((k_align_src + byteoffset),
+ if (user_src && copy_from_user((k_align_src + byteoffset),
(void __user *)user_src,
areq->cipher_op_req.vbuf.src[0].len))
return -EFAULT;
@@ -1156,7 +1132,7 @@ static int qcedev_vbuf_ablk_cipher_max_xfer(struct qcedev_async_req *areq,
for (i = 1; i < areq->cipher_op_req.entries; i++) {
user_src =
(void __user *)areq->cipher_op_req.vbuf.src[i].vaddr;
- if (user_src && __copy_from_user(k_align_src,
+ if (user_src && copy_from_user(k_align_src,
(void __user *)user_src,
areq->cipher_op_req.vbuf.src[i].len)) {
return -EFAULT;
@@ -1188,7 +1164,7 @@ static int qcedev_vbuf_ablk_cipher_max_xfer(struct qcedev_async_req *areq,
while (creq->data_len > 0) {
if (creq->vbuf.dst[dst_i].len <= creq->data_len) {
- if (err == 0 && __copy_to_user(
+ if (err == 0 && copy_to_user(
(void __user *)creq->vbuf.dst[dst_i].vaddr,
(k_align_dst + byteoffset),
creq->vbuf.dst[dst_i].len))
@@ -1199,7 +1175,7 @@ static int qcedev_vbuf_ablk_cipher_max_xfer(struct qcedev_async_req *areq,
creq->data_len -= creq->vbuf.dst[dst_i].len;
dst_i++;
} else {
- if (err == 0 && __copy_to_user(
+ if (err == 0 && copy_to_user(
(void __user *)creq->vbuf.dst[dst_i].vaddr,
(k_align_dst + byteoffset),
creq->data_len))
@@ -1531,36 +1507,6 @@ static int qcedev_check_cipher_params(struct qcedev_cipher_op_req *req,
__func__, total, req->data_len);
goto error;
}
- /* Verify Source Address's */
- for (i = 0, total = 0; i < req->entries; i++) {
- if (total < req->data_len) {
- if (!access_ok(VERIFY_READ,
- (void __user *)req->vbuf.src[i].vaddr,
- req->vbuf.src[i].len)) {
- pr_err("%s:SRC RD_VERIFY err %d=0x%lx\n",
- __func__, i, (uintptr_t)
- req->vbuf.src[i].vaddr);
- goto error;
- }
- total += req->vbuf.src[i].len;
- }
- }
-
- /* Verify Destination Address's */
- for (i = 0, total = 0; i < QCEDEV_MAX_BUFFERS; i++) {
- if ((req->vbuf.dst[i].vaddr != 0) &&
- (total < req->data_len)) {
- if (!access_ok(VERIFY_WRITE,
- (void __user *)req->vbuf.dst[i].vaddr,
- req->vbuf.dst[i].len)) {
- pr_err("%s:DST WR_VERIFY err %d=0x%lx\n",
- __func__, i, (uintptr_t)
- req->vbuf.dst[i].vaddr);
- goto error;
- }
- total += req->vbuf.dst[i].len;
- }
- }
return 0;
error:
return -EINVAL;
@@ -1656,11 +1602,7 @@ long qcedev_ioctl(struct file *file, unsigned cmd, unsigned long arg)
switch (cmd) {
case QCEDEV_IOCTL_ENC_REQ:
case QCEDEV_IOCTL_DEC_REQ:
- if (!access_ok(VERIFY_WRITE, (void __user *)arg,
- sizeof(struct qcedev_cipher_op_req)))
- return -EFAULT;
-
- if (__copy_from_user(&qcedev_areq.cipher_op_req,
+ if (copy_from_user(&qcedev_areq.cipher_op_req,
(void __user *)arg,
sizeof(struct qcedev_cipher_op_req)))
return -EFAULT;
@@ -1673,20 +1615,17 @@ long qcedev_ioctl(struct file *file, unsigned cmd, unsigned long arg)
err = qcedev_vbuf_ablk_cipher(&qcedev_areq, handle);
if (err)
return err;
- if (__copy_to_user((void __user *)arg,
+ if (copy_to_user((void __user *)arg,
&qcedev_areq.cipher_op_req,
sizeof(struct qcedev_cipher_op_req)))
- return -EFAULT;
+ return -EFAULT;
break;
case QCEDEV_IOCTL_SHA_INIT_REQ:
{
struct scatterlist sg_src;
- if (!access_ok(VERIFY_WRITE, (void __user *)arg,
- sizeof(struct qcedev_sha_op_req)))
- return -EFAULT;
- if (__copy_from_user(&qcedev_areq.sha_op_req,
+ if (copy_from_user(&qcedev_areq.sha_op_req,
(void __user *)arg,
sizeof(struct qcedev_sha_op_req)))
return -EFAULT;
@@ -1696,9 +1635,9 @@ long qcedev_ioctl(struct file *file, unsigned cmd, unsigned long arg)
err = qcedev_hash_init(&qcedev_areq, handle, &sg_src);
if (err)
return err;
- if (__copy_to_user((void __user *)arg, &qcedev_areq.sha_op_req,
+ if (copy_to_user((void __user *)arg, &qcedev_areq.sha_op_req,
sizeof(struct qcedev_sha_op_req)))
- return -EFAULT;
+ return -EFAULT;
}
handle->sha_ctxt.init_done = true;
break;
@@ -1708,11 +1647,8 @@ long qcedev_ioctl(struct file *file, unsigned cmd, unsigned long arg)
case QCEDEV_IOCTL_SHA_UPDATE_REQ:
{
struct scatterlist sg_src;
- if (!access_ok(VERIFY_WRITE, (void __user *)arg,
- sizeof(struct qcedev_sha_op_req)))
- return -EFAULT;
- if (__copy_from_user(&qcedev_areq.sha_op_req,
+ if (copy_from_user(&qcedev_areq.sha_op_req,
(void __user *)arg,
sizeof(struct qcedev_sha_op_req)))
return -EFAULT;
@@ -1734,10 +1670,15 @@ long qcedev_ioctl(struct file *file, unsigned cmd, unsigned long arg)
return err;
}
+ if (handle->sha_ctxt.diglen > QCEDEV_MAX_SHA_DIGEST) {
+ pr_err("Invalid sha_ctxt.diglen %d\n",
+ handle->sha_ctxt.diglen);
+ return -EINVAL;
+ }
memcpy(&qcedev_areq.sha_op_req.digest[0],
&handle->sha_ctxt.digest[0],
handle->sha_ctxt.diglen);
- if (__copy_to_user((void __user *)arg, &qcedev_areq.sha_op_req,
+ if (copy_to_user((void __user *)arg, &qcedev_areq.sha_op_req,
sizeof(struct qcedev_sha_op_req)))
return -EFAULT;
}
@@ -1749,11 +1690,7 @@ long qcedev_ioctl(struct file *file, unsigned cmd, unsigned long arg)
pr_err("%s Init was not called\n", __func__);
return -EINVAL;
}
- if (!access_ok(VERIFY_WRITE, (void __user *)arg,
- sizeof(struct qcedev_sha_op_req)))
- return -EFAULT;
-
- if (__copy_from_user(&qcedev_areq.sha_op_req,
+ if (copy_from_user(&qcedev_areq.sha_op_req,
(void __user *)arg,
sizeof(struct qcedev_sha_op_req)))
return -EFAULT;
@@ -1767,7 +1704,7 @@ long qcedev_ioctl(struct file *file, unsigned cmd, unsigned long arg)
memcpy(&qcedev_areq.sha_op_req.digest[0],
&handle->sha_ctxt.digest[0],
handle->sha_ctxt.diglen);
- if (__copy_to_user((void __user *)arg, &qcedev_areq.sha_op_req,
+ if (copy_to_user((void __user *)arg, &qcedev_areq.sha_op_req,
sizeof(struct qcedev_sha_op_req)))
return -EFAULT;
handle->sha_ctxt.init_done = false;
@@ -1776,11 +1713,8 @@ long qcedev_ioctl(struct file *file, unsigned cmd, unsigned long arg)
case QCEDEV_IOCTL_GET_SHA_REQ:
{
struct scatterlist sg_src;
- if (!access_ok(VERIFY_WRITE, (void __user *)arg,
- sizeof(struct qcedev_sha_op_req)))
- return -EFAULT;
- if (__copy_from_user(&qcedev_areq.sha_op_req,
+ if (copy_from_user(&qcedev_areq.sha_op_req,
(void __user *)arg,
sizeof(struct qcedev_sha_op_req)))
return -EFAULT;
@@ -1798,7 +1732,7 @@ long qcedev_ioctl(struct file *file, unsigned cmd, unsigned long arg)
memcpy(&qcedev_areq.sha_op_req.digest[0],
&handle->sha_ctxt.digest[0],
handle->sha_ctxt.diglen);
- if (__copy_to_user((void __user *)arg, &qcedev_areq.sha_op_req,
+ if (copy_to_user((void __user *)arg, &qcedev_areq.sha_op_req,
sizeof(struct qcedev_sha_op_req)))
return -EFAULT;
}
diff --git a/drivers/devfreq/governor_msm_adreno_tz.c b/drivers/devfreq/governor_msm_adreno_tz.c
index eb5e3fc127e0..0276952debbb 100644
--- a/drivers/devfreq/governor_msm_adreno_tz.c
+++ b/drivers/devfreq/governor_msm_adreno_tz.c
@@ -92,14 +92,15 @@ static ssize_t gpu_load_show(struct device *dev,
struct device_attribute *attr,
char *buf)
{
- unsigned long sysfs_busy_perc;
+ unsigned long sysfs_busy_perc = 0;
/*
* Average out the samples taken since last read
* This will keep the average value in sync with
* with the client sampling duration.
*/
spin_lock(&sample_lock);
- sysfs_busy_perc = (acc_relative_busy * 100) / acc_total;
+ if (acc_total)
+ sysfs_busy_perc = (acc_relative_busy * 100) / acc_total;
/* Reset the parameters */
acc_total = 0;
diff --git a/drivers/gpu/msm/adreno-gpulist.h b/drivers/gpu/msm/adreno-gpulist.h
index a02ed40ba9d5..e6163384f9c1 100644
--- a/drivers/gpu/msm/adreno-gpulist.h
+++ b/drivers/gpu/msm/adreno-gpulist.h
@@ -269,7 +269,7 @@ static const struct adreno_gpu_core adreno_gpulist[] = {
.patchid = ANY_ID,
.features = ADRENO_PREEMPTION | ADRENO_64BIT |
ADRENO_CONTENT_PROTECTION |
- ADRENO_GPMU | ADRENO_SPTP_PC | ADRENO_LM,
+ ADRENO_GPMU | ADRENO_SPTP_PC,
.pm4fw_name = "a530_pm4.fw",
.pfpfw_name = "a530_pfp.fw",
.zap_name = "a540_zap",
@@ -283,4 +283,18 @@ static const struct adreno_gpu_core adreno_gpulist[] = {
.gpmu_tsens = 0x000C000D,
.max_power = 5448,
},
+ {
+ .gpurev = ADRENO_REV_A512,
+ .core = 5,
+ .major = 1,
+ .minor = 2,
+ .patchid = ANY_ID,
+ .features = ADRENO_64BIT,
+ .pm4fw_name = "a530_pm4.fw",
+ .pfpfw_name = "a530_pfp.fw",
+ .gpudev = &adreno_a5xx_gpudev,
+ .gmem_size = (SZ_256K + SZ_16K),
+ .num_protected_regs = 0x20,
+ .busy_mask = 0xFFFFFFFE,
+ },
};
diff --git a/drivers/gpu/msm/adreno.h b/drivers/gpu/msm/adreno.h
index d81142db5b58..1c30b43fdfcf 100644
--- a/drivers/gpu/msm/adreno.h
+++ b/drivers/gpu/msm/adreno.h
@@ -170,6 +170,7 @@ enum adreno_gpurev {
ADRENO_REV_A505 = 505,
ADRENO_REV_A506 = 506,
ADRENO_REV_A510 = 510,
+ ADRENO_REV_A512 = 512,
ADRENO_REV_A530 = 530,
ADRENO_REV_A540 = 540,
};
@@ -998,6 +999,7 @@ static inline int adreno_is_a5xx(struct adreno_device *adreno_dev)
ADRENO_TARGET(a505, ADRENO_REV_A505)
ADRENO_TARGET(a506, ADRENO_REV_A506)
ADRENO_TARGET(a510, ADRENO_REV_A510)
+ADRENO_TARGET(a512, ADRENO_REV_A512)
ADRENO_TARGET(a530, ADRENO_REV_A530)
ADRENO_TARGET(a540, ADRENO_REV_A540)
diff --git a/drivers/gpu/msm/adreno_a5xx.c b/drivers/gpu/msm/adreno_a5xx.c
index dc35c0080d11..90b833888d9d 100644
--- a/drivers/gpu/msm/adreno_a5xx.c
+++ b/drivers/gpu/msm/adreno_a5xx.c
@@ -57,6 +57,7 @@ static const struct adreno_vbif_data a540_vbif[] = {
static const struct adreno_vbif_platform a5xx_vbif_platforms[] = {
{ adreno_is_a540, a540_vbif },
{ adreno_is_a530, a530_vbif },
+ { adreno_is_a512, a540_vbif },
{ adreno_is_a510, a530_vbif },
{ adreno_is_a505, a530_vbif },
{ adreno_is_a506, a530_vbif },
@@ -1884,7 +1885,7 @@ static void a5xx_start(struct adreno_device *adreno_dev)
if (adreno_is_a505_or_a506(adreno_dev))
kgsl_regwrite(device, A5XX_PC_DBG_ECO_CNTL,
(0x100 << 11 | 0x100 << 22));
- else if (adreno_is_a510(adreno_dev))
+ else if (adreno_is_a510(adreno_dev) || adreno_is_a512(adreno_dev))
kgsl_regwrite(device, A5XX_PC_DBG_ECO_CNTL,
(0x200 << 11 | 0x200 << 22));
else
@@ -1976,8 +1977,8 @@ static void a5xx_start(struct adreno_device *adreno_dev)
kgsl_regwrite(device, A5XX_TPL1_MODE_CNTL, bit << 7);
kgsl_regwrite(device, A5XX_RB_MODE_CNTL, bit << 1);
-
- if (adreno_is_a540(adreno_dev))
+ if (adreno_is_a540(adreno_dev) ||
+ adreno_is_a512(adreno_dev))
kgsl_regwrite(device, A5XX_UCHE_DBG_ECO_CNTL_2,
bit);
}
diff --git a/drivers/gpu/msm/adreno_a5xx_preempt.c b/drivers/gpu/msm/adreno_a5xx_preempt.c
index 09c550c9f58c..0e56731b16e2 100644
--- a/drivers/gpu/msm/adreno_a5xx_preempt.c
+++ b/drivers/gpu/msm/adreno_a5xx_preempt.c
@@ -22,7 +22,7 @@
#define PREEMPT_SMMU_RECORD(_field) \
offsetof(struct a5xx_cp_smmu_info, _field)
-static void _update_wptr(struct adreno_device *adreno_dev)
+static void _update_wptr(struct adreno_device *adreno_dev, bool reset_timer)
{
struct adreno_ringbuffer *rb = adreno_dev->cur_rb;
unsigned int wptr;
@@ -35,10 +35,16 @@ static void _update_wptr(struct adreno_device *adreno_dev)
if (wptr != rb->wptr) {
adreno_writereg(adreno_dev, ADRENO_REG_CP_RB_WPTR,
rb->wptr);
+ /*
+ * In case something got submitted while preemption was on
+ * going, reset the timer.
+ */
+ reset_timer = 1;
+ }
+ if (reset_timer)
rb->dispatch_q.expires = jiffies +
msecs_to_jiffies(adreno_drawobj_timeout);
- }
spin_unlock_irqrestore(&rb->preempt_lock, flags);
}
@@ -90,7 +96,7 @@ static void _a5xx_preemption_done(struct adreno_device *adreno_dev)
adreno_dev->next_rb = NULL;
/* Update the wptr for the new command queue */
- _update_wptr(adreno_dev);
+ _update_wptr(adreno_dev, true);
/* Update the dispatcher timer for the new command queue */
mod_timer(&adreno_dev->dispatcher.timer,
@@ -213,7 +219,7 @@ void a5xx_preemption_trigger(struct adreno_device *adreno_dev)
*/
if (next != NULL) {
- _update_wptr(adreno_dev);
+ _update_wptr(adreno_dev, false);
mod_timer(&adreno_dev->dispatcher.timer,
adreno_dev->cur_rb->dispatch_q.expires);
@@ -304,7 +310,7 @@ void a5xx_preempt_callback(struct adreno_device *adreno_dev, int bit)
adreno_dev->next_rb = NULL;
/* Update the wptr if it changed while preemption was ongoing */
- _update_wptr(adreno_dev);
+ _update_wptr(adreno_dev, true);
/* Update the dispatcher timer for the new command queue */
mod_timer(&adreno_dev->dispatcher.timer,
diff --git a/drivers/gpu/msm/adreno_iommu.c b/drivers/gpu/msm/adreno_iommu.c
index aa00dcb84185..4bb7f6286664 100644
--- a/drivers/gpu/msm/adreno_iommu.c
+++ b/drivers/gpu/msm/adreno_iommu.c
@@ -856,6 +856,17 @@ int adreno_iommu_set_pt_ctx(struct adreno_ringbuffer *rb,
int result = 0;
int cpu_path = 0;
+ /* Just do the context switch incase of NOMMU */
+ if (kgsl_mmu_get_mmutype(device) == KGSL_MMU_TYPE_NONE) {
+ if ((!(flags & ADRENO_CONTEXT_SWITCH_FORCE_GPU)) &&
+ adreno_isidle(device))
+ _set_ctxt_cpu(rb, drawctxt);
+ else
+ result = _set_ctxt_gpu(rb, drawctxt);
+
+ return result;
+ }
+
if (rb->drawctxt_active)
cur_pt = rb->drawctxt_active->base.proc_priv->pagetable;
diff --git a/drivers/gpu/msm/kgsl.c b/drivers/gpu/msm/kgsl.c
index 699d99651f2c..6ef542416959 100644
--- a/drivers/gpu/msm/kgsl.c
+++ b/drivers/gpu/msm/kgsl.c
@@ -353,8 +353,10 @@ static int kgsl_mem_entry_track_gpuaddr(struct kgsl_device *device,
/*
* If SVM is enabled for this object then the address needs to be
* assigned elsewhere
+ * Also do not proceed further in case of NoMMU.
*/
- if (kgsl_memdesc_use_cpu_map(&entry->memdesc))
+ if (kgsl_memdesc_use_cpu_map(&entry->memdesc) ||
+ (kgsl_mmu_get_mmutype(device) == KGSL_MMU_TYPE_NONE))
return 0;
pagetable = kgsl_memdesc_is_secured(&entry->memdesc) ?
diff --git a/drivers/gpu/msm/kgsl_sharedmem.h b/drivers/gpu/msm/kgsl_sharedmem.h
index 03f278ead20f..c1c2afa68756 100644
--- a/drivers/gpu/msm/kgsl_sharedmem.h
+++ b/drivers/gpu/msm/kgsl_sharedmem.h
@@ -284,7 +284,8 @@ static inline int kgsl_allocate_global(struct kgsl_device *device,
memdesc->flags = flags;
memdesc->priv = priv;
- if ((memdesc->priv & KGSL_MEMDESC_CONTIG) != 0)
+ if (((memdesc->priv & KGSL_MEMDESC_CONTIG) != 0) ||
+ (kgsl_mmu_get_mmutype(device) == KGSL_MMU_TYPE_NONE))
ret = kgsl_sharedmem_alloc_contig(device, memdesc,
(size_t) size);
else {
diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c
index 9dc9f93f4e36..577183bea07c 100644
--- a/drivers/hid/hid-core.c
+++ b/drivers/hid/hid-core.c
@@ -1251,6 +1251,7 @@ static void hid_input_field(struct hid_device *hid, struct hid_field *field,
/* Ignore report if ErrorRollOver */
if (!(field->flags & HID_MAIN_ITEM_VARIABLE) &&
value[n] >= min && value[n] <= max &&
+ value[n] - min < field->maxusage &&
field->usage[value[n] - min].hid == HID_UP_KEYBOARD + 1)
goto exit;
}
@@ -1263,11 +1264,13 @@ static void hid_input_field(struct hid_device *hid, struct hid_field *field,
}
if (field->value[n] >= min && field->value[n] <= max
+ && field->value[n] - min < field->maxusage
&& field->usage[field->value[n] - min].hid
&& search(value, field->value[n], count))
hid_process_event(hid, field, &field->usage[field->value[n] - min], 0, interrupt);
if (value[n] >= min && value[n] <= max
+ && value[n] - min < field->maxusage
&& field->usage[value[n] - min].hid
&& search(field->value, value[n], count))
hid_process_event(hid, field, &field->usage[value[n] - min], 1, interrupt);
diff --git a/drivers/input/touchscreen/synaptics_dsx/synaptics_dsx_fw_update.c b/drivers/input/touchscreen/synaptics_dsx/synaptics_dsx_fw_update.c
index 2282fe005bc7..0ec16e606545 100644
--- a/drivers/input/touchscreen/synaptics_dsx/synaptics_dsx_fw_update.c
+++ b/drivers/input/touchscreen/synaptics_dsx/synaptics_dsx_fw_update.c
@@ -358,6 +358,7 @@ static struct device_attribute attrs[] = {
static struct synaptics_rmi4_fwu_handle *fwu;
DECLARE_COMPLETION(fwu_dsx_remove_complete);
+DEFINE_MUTEX(dsx_fwu_sysfs_mutex);
static unsigned int extract_uint_le(const unsigned char *ptr)
{
@@ -1589,39 +1590,72 @@ static ssize_t fwu_sysfs_show_image(struct file *data_file,
char *buf, loff_t pos, size_t count)
{
struct synaptics_rmi4_data *rmi4_data = fwu->rmi4_data;
+ ssize_t retval;
+
+ if (!mutex_trylock(&dsx_fwu_sysfs_mutex))
+ return -EBUSY;
if (count < fwu->config_size) {
dev_err(rmi4_data->pdev->dev.parent,
"%s: Not enough space (%zu bytes) in buffer\n",
__func__, count);
- return -EINVAL;
+ retval = -EINVAL;
+ goto show_image_exit;
}
memcpy(buf, fwu->read_config_buf, fwu->config_size);
-
- return fwu->config_size;
+ retval = fwu->config_size;
+show_image_exit:
+ mutex_unlock(&dsx_fwu_sysfs_mutex);
+ return retval;
}
static ssize_t fwu_sysfs_store_image(struct file *data_file,
struct kobject *kobj, struct bin_attribute *attributes,
char *buf, loff_t pos, size_t count)
{
+ ssize_t retval;
+
+ if (!mutex_trylock(&dsx_fwu_sysfs_mutex))
+ return -EBUSY;
+
+ if (count > (fwu->image_size - fwu->data_pos)) {
+ dev_err(fwu->rmi4_data->pdev->dev.parent,
+ "%s: Not enough space in buffer\n",
+ __func__);
+ retval = -EINVAL;
+ goto exit;
+ }
+
+ if (!fwu->ext_data_source) {
+ dev_err(fwu->rmi4_data->pdev->dev.parent,
+ "%s: Need to set imagesize\n",
+ __func__);
+ retval = -EINVAL;
+ goto exit;
+ }
+
memcpy((void *)(&fwu->ext_data_source[fwu->data_pos]),
(const void *)buf,
count);
fwu->data_pos += count;
+exit:
+ mutex_unlock(&dsx_fwu_sysfs_mutex);
return count;
}
static ssize_t fwu_sysfs_force_reflash_store(struct device *dev,
struct device_attribute *attr, const char *buf, size_t count)
{
- int retval;
+ ssize_t retval;
unsigned int input;
struct synaptics_rmi4_data *rmi4_data = fwu->rmi4_data;
+ if (!mutex_trylock(&dsx_fwu_sysfs_mutex))
+ return -EBUSY;
+
if (sscanf(buf, "%u", &input) != 1) {
retval = -EINVAL;
goto exit;
@@ -1650,6 +1684,9 @@ exit:
fwu->ext_data_source = NULL;
fwu->force_update = FORCE_UPDATE;
fwu->do_lockdown = DO_LOCKDOWN;
+ fwu->data_pos = 0;
+ fwu->image_size = 0;
+ mutex_unlock(&dsx_fwu_sysfs_mutex);
return retval;
}
@@ -1660,6 +1697,9 @@ static ssize_t fwu_sysfs_do_reflash_store(struct device *dev,
unsigned int input;
struct synaptics_rmi4_data *rmi4_data = fwu->rmi4_data;
+ if (!mutex_trylock(&dsx_fwu_sysfs_mutex))
+ return -EBUSY;
+
if (sscanf(buf, "%u", &input) != 1) {
retval = -EINVAL;
goto exit;
@@ -1693,6 +1733,9 @@ exit:
fwu->ext_data_source = NULL;
fwu->force_update = FORCE_UPDATE;
fwu->do_lockdown = DO_LOCKDOWN;
+ fwu->data_pos = 0;
+ fwu->image_size = 0;
+ mutex_unlock(&dsx_fwu_sysfs_mutex);
return retval;
}
@@ -1703,6 +1746,9 @@ static ssize_t fwu_sysfs_write_config_store(struct device *dev,
unsigned int input;
struct synaptics_rmi4_data *rmi4_data = fwu->rmi4_data;
+ if (!mutex_trylock(&dsx_fwu_sysfs_mutex))
+ return -EBUSY;
+
if (sscanf(buf, "%u", &input) != 1) {
retval = -EINVAL;
goto exit;
@@ -1726,6 +1772,9 @@ static ssize_t fwu_sysfs_write_config_store(struct device *dev,
exit:
kfree(fwu->ext_data_source);
fwu->ext_data_source = NULL;
+ fwu->data_pos = 0;
+ fwu->image_size = 0;
+ mutex_unlock(&dsx_fwu_sysfs_mutex);
return retval;
}
@@ -1742,7 +1791,11 @@ static ssize_t fwu_sysfs_read_config_store(struct device *dev,
if (input != 1)
return -EINVAL;
+ if (!mutex_trylock(&dsx_fwu_sysfs_mutex))
+ return -EBUSY;
retval = fwu_do_read_config();
+ mutex_unlock(&dsx_fwu_sysfs_mutex);
+
if (retval < 0) {
dev_err(rmi4_data->pdev->dev.parent,
"%s: Failed to read config\n",
@@ -1763,7 +1816,10 @@ static ssize_t fwu_sysfs_config_area_store(struct device *dev,
if (retval)
return retval;
+ if (!mutex_trylock(&dsx_fwu_sysfs_mutex))
+ return -EBUSY;
fwu->config_area = config_area;
+ mutex_unlock(&dsx_fwu_sysfs_mutex);
return count;
}
@@ -1771,17 +1827,30 @@ static ssize_t fwu_sysfs_config_area_store(struct device *dev,
static ssize_t fwu_sysfs_image_name_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
+ ssize_t retval;
+
+ if (!mutex_trylock(&dsx_fwu_sysfs_mutex))
+ return -EBUSY;
if (strnlen(fwu->rmi4_data->fw_name, SYNA_FW_NAME_MAX_LEN) > 0)
- return snprintf(buf, PAGE_SIZE, "%s\n",
+ retval = snprintf(buf, PAGE_SIZE, "%s\n",
fwu->rmi4_data->fw_name);
else
- return snprintf(buf, PAGE_SIZE, "No firmware name given\n");
+ retval = snprintf(buf, PAGE_SIZE, "No firmware name given\n");
+ mutex_unlock(&dsx_fwu_sysfs_mutex);
+ return retval;
}
static ssize_t fwu_sysfs_image_name_store(struct device *dev,
struct device_attribute *attr, const char *buf, size_t count)
{
- if (sscanf(buf, "%s", fwu->image_name) != 1)
+ ssize_t retval;
+
+ if (!mutex_trylock(&dsx_fwu_sysfs_mutex))
+ return -EBUSY;
+ retval = sscanf(buf, "%49s", fwu->image_name);
+ mutex_unlock(&dsx_fwu_sysfs_mutex);
+
+ if (retval != 1)
return -EINVAL;
return count;
@@ -1794,9 +1863,12 @@ static ssize_t fwu_sysfs_image_size_store(struct device *dev,
unsigned long size;
struct synaptics_rmi4_data *rmi4_data = fwu->rmi4_data;
+ if (!mutex_trylock(&dsx_fwu_sysfs_mutex))
+ return -EBUSY;
+
retval = sstrtoul(buf, 10, &size);
if (retval)
- return retval;
+ goto exit;
fwu->image_size = size;
fwu->data_pos = 0;
@@ -1807,10 +1879,14 @@ static ssize_t fwu_sysfs_image_size_store(struct device *dev,
dev_err(rmi4_data->pdev->dev.parent,
"%s: Failed to alloc mem for image data\n",
__func__);
- return -ENOMEM;
+ retval = -ENOMEM;
+ goto exit;
}
- return count;
+ retval = count;
+exit:
+ mutex_unlock(&dsx_fwu_sysfs_mutex);
+ return retval;
}
static ssize_t fwu_sysfs_block_size_show(struct device *dev,
diff --git a/drivers/media/platform/msm/camera_v2/common/cam_smmu_api.c b/drivers/media/platform/msm/camera_v2/common/cam_smmu_api.c
index feede3a14e07..d6b32036f31c 100644
--- a/drivers/media/platform/msm/camera_v2/common/cam_smmu_api.c
+++ b/drivers/media/platform/msm/camera_v2/common/cam_smmu_api.c
@@ -14,6 +14,7 @@
#include <linux/module.h>
#include <linux/dma-buf.h>
#include <asm/dma-iommu.h>
+#include <asm/cacheflush.h>
#include <linux/dma-direction.h>
#include <linux/dma-attrs.h>
#include <linux/of_platform.h>
@@ -23,6 +24,8 @@
#include <linux/dma-mapping.h>
#include <linux/msm_dma_iommu_mapping.h>
#include <linux/workqueue.h>
+#include <soc/qcom/scm.h>
+#include <soc/qcom/secure_buffer.h>
#include "cam_smmu_api.h"
#define SCRATCH_ALLOC_START SZ_128K
@@ -35,10 +38,15 @@
#define COOKIE_MASK ((1<<COOKIE_SIZE)-1)
#define HANDLE_INIT (-1)
#define CAM_SMMU_CB_MAX 2
+#define CAM_SMMU_SID_MAX 4
+
#define GET_SMMU_HDL(x, y) (((x) << COOKIE_SIZE) | ((y) & COOKIE_MASK))
#define GET_SMMU_TABLE_IDX(x) (((x) >> COOKIE_SIZE) & COOKIE_MASK)
+#define CAMERA_DEVICE_ID 0x16
+#define SECURE_SYSCALL_ID 0x18
+
#ifdef CONFIG_CAM_SMMU_DBG
#define CDBG(fmt, args...) pr_err(fmt, ##args)
#else
@@ -104,6 +112,8 @@ struct cam_context_bank_info {
int, void*);
void *token[CAM_SMMU_CB_MAX];
int cb_count;
+ int ref_cnt;
+ int sids[CAM_SMMU_SID_MAX];
};
struct cam_iommu_cb_set {
@@ -136,6 +146,17 @@ struct cam_dma_buff_info {
size_t phys_len;
};
+struct cam_sec_buff_info {
+ struct ion_handle *i_hdl;
+ struct ion_client *i_client;
+ enum dma_data_direction dir;
+ int ref_count;
+ dma_addr_t paddr;
+ struct list_head list;
+ int ion_fd;
+ size_t len;
+};
+
static struct cam_iommu_cb_set iommu_cb_set;
static enum dma_data_direction cam_smmu_translate_dir(
@@ -151,6 +172,9 @@ static int cam_smmu_create_add_handle_in_table(char *name,
static struct cam_dma_buff_info *cam_smmu_find_mapping_by_ion_index(int idx,
int ion_fd);
+static struct cam_sec_buff_info *cam_smmu_find_mapping_by_sec_buf_idx(int idx,
+ int ion_fd);
+
static int cam_smmu_init_scratch_map(struct scratch_mapping *scratch_map,
dma_addr_t base, size_t size,
int order);
@@ -477,10 +501,14 @@ void cam_smmu_reset_iommu_table(enum cam_smmu_init_dir ops)
iommu_cb_set.cb_info[i].state = CAM_SMMU_DETACH;
iommu_cb_set.cb_info[i].dev = NULL;
iommu_cb_set.cb_info[i].cb_count = 0;
+ iommu_cb_set.cb_info[i].ref_cnt = 0;
for (j = 0; j < CAM_SMMU_CB_MAX; j++) {
iommu_cb_set.cb_info[i].token[j] = NULL;
iommu_cb_set.cb_info[i].handler[j] = NULL;
}
+ for (j = 0; j < CAM_SMMU_SID_MAX; j++)
+ iommu_cb_set.cb_info[i].sids[j] = -1;
+
if (ops == CAM_SMMU_TABLE_INIT)
mutex_init(&iommu_cb_set.cb_info[i].lock);
else
@@ -549,6 +577,8 @@ static int cam_smmu_create_add_handle_in_table(char *name,
pr_err("Error: %s already got handle 0x%x\n",
name,
iommu_cb_set.cb_info[i].handle);
+ *hdl = iommu_cb_set.cb_info[i].handle;
+ iommu_cb_set.cb_info[i].ref_cnt++;
mutex_unlock(&iommu_cb_set.cb_info[i].lock);
return -EINVAL;
}
@@ -561,6 +591,7 @@ static int cam_smmu_create_add_handle_in_table(char *name,
/* put handle in the table */
iommu_cb_set.cb_info[i].handle = handle;
iommu_cb_set.cb_info[i].cb_count = 0;
+ iommu_cb_set.cb_info[i].ref_cnt++;
*hdl = handle;
CDBG("%s creates handle 0x%x\n", name, handle);
mutex_unlock(&iommu_cb_set.cb_info[i].lock);
@@ -698,6 +729,23 @@ static struct cam_dma_buff_info *cam_smmu_find_mapping_by_ion_index(int idx,
return NULL;
}
+static struct cam_sec_buff_info *cam_smmu_find_mapping_by_sec_buf_idx(int idx,
+ int ion_fd)
+{
+ struct cam_sec_buff_info *mapping;
+
+ list_for_each_entry(mapping, &iommu_cb_set.cb_info[idx].smmu_buf_list,
+ list) {
+ if (mapping->ion_fd == ion_fd) {
+ CDBG("[sec_cam] find ion_fd %d\n", ion_fd);
+ return mapping;
+ }
+ }
+ pr_err("Error: Cannot find fd %d by index %d\n",
+ ion_fd, idx);
+ return NULL;
+}
+
static void cam_smmu_clean_buffer_list(int idx)
{
int ret;
@@ -754,6 +802,148 @@ static int cam_smmu_attach(int idx)
return ret;
}
+static int cam_smmu_send_syscall_cpp_intf(int vmid, int idx)
+{
+ int rc = 0;
+ struct scm_desc desc = {0};
+ struct cam_context_bank_info *cb = &iommu_cb_set.cb_info[idx];
+ uint32_t sid_info;
+
+
+ sid_info = cb->sids[0]; /* CPP SID */
+
+ desc.arginfo = SCM_ARGS(4, SCM_VAL, SCM_RW, SCM_VAL, SCM_VAL);
+ desc.args[0] = CAMERA_DEVICE_ID;
+ desc.args[1] = SCM_BUFFER_PHYS(&sid_info);
+ desc.args[2] = sizeof(uint32_t);
+ desc.args[3] = vmid;
+ /*
+ * Syscall to hypervisor to switch CPP SID's
+ * between secure and non-secure contexts
+ */
+ dmac_flush_range(&sid_info, &sid_info + 1);
+ if (scm_call2(SCM_SIP_FNID(SCM_SVC_MP, SECURE_SYSCALL_ID),
+ &desc)){
+ pr_err("call to hypervisor failed\n");
+ return -EINVAL;
+ }
+ return rc;
+}
+
+static int cam_smmu_send_syscall_pix_intf(int vmid, int idx)
+{
+ int rc = 0;
+ struct scm_desc desc = {0};
+ uint32_t *sid_info = NULL;
+ struct cam_context_bank_info *cb = &iommu_cb_set.cb_info[idx];
+
+ sid_info = kzalloc(sizeof(uint32_t) * 2, GFP_KERNEL);
+ if (!sid_info)
+ return -ENOMEM;
+
+ sid_info[0] = cb->sids[0]; /* VFE 0 Image SID */
+ sid_info[1] = cb->sids[2]; /* VFE 1 Image SID */
+
+ desc.arginfo = SCM_ARGS(4, SCM_VAL, SCM_RW, SCM_VAL, SCM_VAL);
+ desc.args[0] = CAMERA_DEVICE_ID;
+ desc.args[1] = SCM_BUFFER_PHYS(sid_info);
+ desc.args[2] = sizeof(uint32_t) * 2;
+ desc.args[3] = vmid;
+ /*
+ * Syscall to hypervisor to switch VFE SID's
+ * between secure and non-secure contexts
+ */
+ dmac_flush_range(sid_info, sid_info + 2);
+ if (scm_call2(SCM_SIP_FNID(SCM_SVC_MP, SECURE_SYSCALL_ID),
+ &desc)){
+ pr_err("call to hypervisor failed\n");
+ kfree(sid_info);
+ return -EINVAL;
+ }
+
+ kfree(sid_info);
+ return rc;
+}
+
+static int cam_smmu_detach_device(int idx)
+{
+ struct cam_context_bank_info *cb = &iommu_cb_set.cb_info[idx];
+
+ /* detach the mapping to device */
+ arm_iommu_detach_device(cb->dev);
+ iommu_cb_set.cb_info[idx].state = CAM_SMMU_DETACH;
+ return 0;
+}
+
+static int cam_smmu_attach_sec_cpp(int idx)
+{
+ /*
+ * When switching to secure, detach CPP NS, do scm call
+ * with CPP SID and no need of attach again, because
+ * all cpp sids are shared in SCM call. so no need of
+ * attach again.
+ */
+
+ if (cam_smmu_send_syscall_cpp_intf(VMID_CP_CAMERA, idx)) {
+ pr_err("error: syscall failed\n");
+ return -EINVAL;
+ }
+ return 0;
+}
+
+static int cam_smmu_detach_sec_cpp(int idx)
+{
+ /*
+ * When exiting secure, do scm call to attach
+ * with CPP SID in NS mode.
+ */
+ if (cam_smmu_send_syscall_cpp_intf(VMID_HLOS, idx)) {
+ pr_err("error: syscall failed\n");
+ return -EINVAL;
+ }
+ return 0;
+}
+
+static int cam_smmu_attach_sec_vfe_ns_stats(int idx)
+{
+ /*
+ *When switching to secure, for secure pixel and non-secure stats
+ *localizing scm/attach of non-secure SID's in attach secure
+ */
+ if (cam_smmu_send_syscall_pix_intf(VMID_CP_CAMERA, idx)) {
+ pr_err("error: syscall failed\n");
+ return -EINVAL;
+ }
+
+ if (iommu_cb_set.cb_info[idx].state != CAM_SMMU_ATTACH) {
+ if (cam_smmu_attach(idx)) {
+ pr_err("error: failed to attach\n");
+ return -EINVAL;
+ }
+ }
+ return 0;
+}
+
+static int cam_smmu_detach_sec_vfe_ns_stats(int idx)
+{
+ /*
+ *While exiting from secure mode for secure pixel and non-secure stats,
+ *localizing detach/scm of non-secure SID's to detach secure
+ */
+ if (iommu_cb_set.cb_info[idx].state != CAM_SMMU_DETACH) {
+ if (cam_smmu_detach_device(idx) < 0) {
+ pr_err("Error: ARM IOMMU detach failed\n");
+ return -ENODEV;
+ }
+ }
+
+ if (cam_smmu_send_syscall_pix_intf(VMID_HLOS, idx)) {
+ pr_err("error: syscall failed\n");
+ return -EINVAL;
+ }
+ return 0;
+}
+
static int cam_smmu_map_buffer_and_add_to_list(int idx, int ion_fd,
enum dma_data_direction dma_dir, dma_addr_t *paddr_ptr,
size_t *len_ptr)
@@ -805,7 +995,7 @@ static int cam_smmu_map_buffer_and_add_to_list(int idx, int ion_fd,
} else {
rc = -EINVAL;
pr_err("Error: table sgl is null\n");
- goto err_unmap_sg;
+ goto err_map_addr;
}
/* fill up mapping_info */
@@ -813,7 +1003,7 @@ static int cam_smmu_map_buffer_and_add_to_list(int idx, int ion_fd,
if (!mapping_info) {
pr_err("Error: No enough space!\n");
rc = -ENOSPC;
- goto err_unmap_sg;
+ goto err_map_addr;
}
mapping_info->ion_fd = ion_fd;
mapping_info->buf = buf;
@@ -831,7 +1021,7 @@ static int cam_smmu_map_buffer_and_add_to_list(int idx, int ion_fd,
if (!*paddr_ptr || !*len_ptr) {
pr_err("Error: Space Allocation failed!\n");
rc = -ENOSPC;
- goto err_unmap_sg;
+ goto err_mapping_info;
}
CDBG("ion_fd = %d, dev = %pK, paddr= %pK, len = %u\n", ion_fd,
(void *)iommu_cb_set.cb_info[idx].dev,
@@ -841,6 +1031,12 @@ static int cam_smmu_map_buffer_and_add_to_list(int idx, int ion_fd,
list_add(&mapping_info->list, &iommu_cb_set.cb_info[idx].smmu_buf_list);
return 0;
+err_mapping_info:
+ kzfree(mapping_info);
+err_map_addr:
+ msm_dma_unmap_sg(iommu_cb_set.cb_info[idx].dev,
+ table->sgl, table->nents,
+ dma_dir, buf);
err_unmap_sg:
dma_buf_unmap_attachment(attach, table, dma_dir);
err_detach:
@@ -851,6 +1047,98 @@ err_out:
return rc;
}
+static int cam_smmu_map_secure_buffer_and_add_to_list(int idx,
+ struct dma_buf *buf,
+ enum dma_data_direction dma_dir, dma_addr_t *paddr_ptr,
+ size_t *len_ptr)
+{
+ int rc = -1;
+ struct cam_dma_buff_info *mapping_info;
+ struct dma_buf_attachment *attach = NULL;
+ struct sg_table *table = NULL;
+
+ attach = dma_buf_attach(buf, iommu_cb_set.cb_info[idx].dev);
+ if (IS_ERR_OR_NULL(attach)) {
+ rc = PTR_ERR(attach);
+ pr_err("Error: dma buf attach failed\n");
+ goto err_put;
+ }
+
+ table = dma_buf_map_attachment(attach, dma_dir);
+ if (IS_ERR_OR_NULL(table)) {
+ rc = PTR_ERR(table);
+ pr_err("Error: dma buf map attachment failed\n");
+ goto err_detach;
+ }
+
+ rc = msm_dma_map_sg_lazy(iommu_cb_set.cb_info[idx].dev, table->sgl,
+ table->nents, dma_dir, buf);
+ if (!rc) {
+ pr_err("Error: msm_dma_map_sg_lazy failed\n");
+ goto err_unmap_sg;
+ }
+
+ if (table->sgl) {
+ CDBG("DMA buf: %p, device: %p, attach: %p, table: %p\n",
+ (void *)buf,
+ (void *)iommu_cb_set.cb_info[idx].dev,
+ (void *)attach, (void *)table);
+ CDBG("table sgl: %p, rc: %d, dma_address: 0x%x\n",
+ (void *)table->sgl, rc,
+ (unsigned int)table->sgl->dma_address);
+ } else {
+ rc = -EINVAL;
+ pr_err("Error: table sgl is null\n");
+ goto err_map_addr;
+ }
+
+ /* fill up mapping_info */
+ mapping_info = kzalloc(sizeof(struct cam_dma_buff_info), GFP_KERNEL);
+ if (!mapping_info) {
+ rc = -ENOSPC;
+ goto err_map_addr;
+ }
+ mapping_info->ion_fd = 0;
+ mapping_info->buf = buf;
+ mapping_info->attach = attach;
+ mapping_info->table = table;
+ mapping_info->paddr = sg_dma_address(table->sgl);
+ mapping_info->len = (size_t)sg_dma_len(table->sgl);
+ mapping_info->dir = dma_dir;
+ mapping_info->ref_count = 1;
+
+ /* return paddr and len to client */
+ *paddr_ptr = sg_dma_address(table->sgl);
+ *len_ptr = (size_t)sg_dma_len(table->sgl);
+
+ if (!*paddr_ptr || !*len_ptr) {
+ pr_err("Error: Invalid dma address/length\n");
+ rc = -ENOSPC;
+ goto err_mapping_info;
+ }
+ CDBG("dev = %p, paddr= %p, len = %u\n",
+ (void *)iommu_cb_set.cb_info[idx].dev,
+ (void *)*paddr_ptr, (unsigned int)*len_ptr);
+
+ /* add to the list */
+ list_add(&mapping_info->list, &iommu_cb_set.cb_info[idx].smmu_buf_list);
+
+ return 0;
+
+err_mapping_info:
+ kzfree(mapping_info);
+err_map_addr:
+ msm_dma_unmap_sg(iommu_cb_set.cb_info[idx].dev,
+ table->sgl, table->nents,
+ dma_dir, buf);
+err_unmap_sg:
+ dma_buf_unmap_attachment(attach, table, dma_dir);
+err_detach:
+ dma_buf_detach(buf, attach);
+err_put:
+ return rc;
+}
+
static int cam_smmu_unmap_buf_and_remove_from_list(
struct cam_dma_buff_info *mapping_info,
int idx)
@@ -951,7 +1239,23 @@ int cam_smmu_ops(int handle, enum cam_smmu_ops_param ops)
break;
}
case CAM_SMMU_DETACH: {
- ret = 0;
+ ret = cam_smmu_detach_device(idx);
+ break;
+ }
+ case CAM_SMMU_ATTACH_SEC_VFE_NS_STATS: {
+ ret = cam_smmu_attach_sec_vfe_ns_stats(idx);
+ break;
+ }
+ case CAM_SMMU_DETACH_SEC_VFE_NS_STATS: {
+ ret = cam_smmu_detach_sec_vfe_ns_stats(idx);
+ break;
+ }
+ case CAM_SMMU_ATTACH_SEC_CPP: {
+ ret = cam_smmu_attach_sec_cpp(idx);
+ break;
+ }
+ case CAM_SMMU_DETACH_SEC_CPP: {
+ ret = cam_smmu_detach_sec_cpp(idx);
break;
}
case CAM_SMMU_VOTE:
@@ -1126,7 +1430,7 @@ int cam_smmu_get_phy_addr_scratch(int handle,
size_t virt_len,
size_t phys_len)
{
- int idx, rc;
+ int idx, rc = 0;
unsigned int iommu_dir;
if (!paddr_ptr || !virt_len || !phys_len) {
@@ -1250,12 +1554,384 @@ int cam_smmu_put_phy_addr_scratch(int handle,
pr_err("Error: unmap or remove list fail\n");
goto handle_err;
}
+handle_err:
+ mutex_unlock(&iommu_cb_set.cb_info[idx].lock);
+ return rc;
+}
+
+int cam_smmu_get_phy_addr_secure_scratch(int handle,
+ enum cam_smmu_map_dir dir,
+ struct dma_buf *scratch_buf,
+ dma_addr_t *paddr_ptr,
+ size_t *len_ptr)
+{
+ int idx, rc;
+ enum dma_data_direction dma_dir;
+
+ if (!paddr_ptr || !len_ptr) {
+ pr_err("Error: Input pointer or lengths invalid\n");
+ return -EINVAL;
+ }
+
+ dma_dir = cam_smmu_translate_dir(dir);
+ if (dma_dir == DMA_NONE) {
+ pr_err("Error: translate direction failed. dir = %d\n", dir);
+ return -EINVAL;
+ }
+
+ idx = GET_SMMU_TABLE_IDX(handle);
+ if (handle == HANDLE_INIT || idx < 0 || idx >= iommu_cb_set.cb_num) {
+ pr_err("Error: handle or index invalid. idx = %d hdl = %x\n",
+ idx, handle);
+ return -EINVAL;
+ }
+
+ mutex_lock(&iommu_cb_set.cb_info[idx].lock);
+ if (iommu_cb_set.cb_info[idx].handle != handle) {
+ pr_err("Error: hdl is not valid, table_hdl = %x, hdl = %x\n",
+ iommu_cb_set.cb_info[idx].handle, handle);
+ rc = -EINVAL;
+ goto error;
+ }
+
+ CDBG("%s: smmu handle = %x, idx = %d, dir = %d\n",
+ __func__, handle, idx, dir);
+
+ if (iommu_cb_set.cb_info[idx].state != CAM_SMMU_ATTACH) {
+ pr_err("Error: Device %s should call SMMU attach before map buffer\n",
+ iommu_cb_set.cb_info[idx].name);
+ rc = -EINVAL;
+ goto error;
+ }
+
+ rc = cam_smmu_map_secure_buffer_and_add_to_list(idx,
+ scratch_buf,
+ dma_dir,
+ paddr_ptr,
+ len_ptr);
+ if (rc < 0) {
+ pr_err("Error: mapping or add list fail\n");
+ goto error;
+ }
+
+ CDBG("Mapped scratch buffer physical address is %lx\n",
+ (unsigned long)*paddr_ptr);
+error:
+ mutex_unlock(&iommu_cb_set.cb_info[idx].lock);
+ return rc;
+}
+
+int cam_smmu_put_phy_addr_secure_scratch(int handle,
+ dma_addr_t paddr)
+{
+ int idx;
+ int rc = -1;
+ struct cam_dma_buff_info *mapping_info;
+
+ /* find index in the iommu_cb_set.cb_info */
+ idx = GET_SMMU_TABLE_IDX(handle);
+ if (handle == HANDLE_INIT || idx < 0 || idx >= iommu_cb_set.cb_num) {
+ pr_err("Error: handle or index invalid. idx = %d hdl = %x\n",
+ idx, handle);
+ return -EINVAL;
+ }
+
+ mutex_lock(&iommu_cb_set.cb_info[idx].lock);
+ if (iommu_cb_set.cb_info[idx].handle != handle) {
+ pr_err("Error: hdl is not valid, table_hdl = %x, hdl = %x\n",
+ iommu_cb_set.cb_info[idx].handle, handle);
+ rc = -EINVAL;
+ goto handle_err;
+ }
+
+ /* Based on virtual address and index, we can find mapping info
+ * of the scratch buffer
+ */
+ mapping_info = cam_smmu_find_mapping_by_virt_address(idx, paddr);
+ if (!mapping_info) {
+ pr_err("Error: Invalid params\n");
+ rc = -EINVAL;
+ goto handle_err;
+ }
+
+ /* unmapping one buffer from device */
+ rc = cam_smmu_unmap_buf_and_remove_from_list(mapping_info, idx);
+ if (rc < 0) {
+ pr_err("Error: unmap or remove list fail\n");
+ goto handle_err;
+ }
+ CDBG("Unmap secure scratch buffer %lx success fully\n",
+ (unsigned long)paddr);
handle_err:
mutex_unlock(&iommu_cb_set.cb_info[idx].lock);
return rc;
}
+int cam_smmu_alloc_get_stage2_scratch_mem(int handle,
+ enum cam_smmu_map_dir dir, struct ion_client *client,
+ struct ion_handle **sc_handle, ion_phys_addr_t *addr,
+ size_t *len_ptr)
+{
+ int idx, rc = 0;
+ enum dma_data_direction dma_dir;
+
+ dma_dir = cam_smmu_translate_dir(dir);
+ if (dma_dir == DMA_NONE) {
+ pr_err("Error: translate direction failed. dir = %d\n", dir);
+ return -EINVAL;
+ }
+ idx = GET_SMMU_TABLE_IDX(handle);
+ if (handle == HANDLE_INIT || idx < 0 || idx >= iommu_cb_set.cb_num) {
+ pr_err("Error: handle or index invalid. idx = %d hdl = %x\n",
+ idx, handle);
+ return -EINVAL;
+ }
+ if (iommu_cb_set.cb_info[idx].handle != handle) {
+ pr_err("Error: hdl is not valid, table_hdl = %x, hdl = %x\n",
+ iommu_cb_set.cb_info[idx].handle, handle);
+ return -EINVAL;
+ }
+
+ if (iommu_cb_set.cb_info[idx].state != CAM_SMMU_ATTACH) {
+ pr_err("Error: Device %s should call SMMU attach before map buffer\n",
+ iommu_cb_set.cb_info[idx].name);
+ return -EINVAL;
+ }
+ *sc_handle = ion_alloc(client, SZ_2M, SZ_2M,
+ ION_HEAP(ION_SECURE_DISPLAY_HEAP_ID),
+ ION_FLAG_SECURE | ION_FLAG_CP_CAMERA);
+ if (IS_ERR_OR_NULL((void *) (*sc_handle))) {
+ rc = -ENOMEM;
+ goto err_ion_handle;
+ }
+
+ /* return addr and len to client */
+ rc = ion_phys(client, *sc_handle, addr, len_ptr);
+ if (rc) {
+ pr_err("%s: ION Get Physical failed, rc = %d\n",
+ __func__, rc);
+ rc = -EINVAL;
+ goto err_ion_phys;
+ }
+
+ CDBG("dev = %pK, paddr= %pK, len = %u\n",
+ (void *)iommu_cb_set.cb_info[idx].dev,
+ (void *)*addr, (unsigned int)*len_ptr);
+ return rc;
+
+err_ion_phys:
+ ion_free(client, *sc_handle);
+
+err_ion_handle:
+ *sc_handle = NULL;
+ return rc;
+}
+
+int cam_smmu_free_stage2_scratch_mem(int handle,
+ struct ion_client *client, struct ion_handle *sc_handle)
+{
+ int idx = 0;
+ /* find index in the iommu_cb_set.cb_info */
+ idx = GET_SMMU_TABLE_IDX(handle);
+ if (handle == HANDLE_INIT || idx < 0 || idx >= iommu_cb_set.cb_num) {
+ pr_err("Error: handle or index invalid. idx = %d hdl = %x\n",
+ idx, handle);
+ return -EINVAL;
+ }
+ ion_free(client, sc_handle);
+ return 0;
+}
+
+static int cam_smmu_secure_unmap_buf_and_remove_from_list(
+ struct cam_sec_buff_info *mapping_info,
+ int idx)
+{
+ if (!mapping_info) {
+ pr_err("Error: List doesn't exist\n");
+ return -EINVAL;
+ }
+ ion_free(mapping_info->i_client, mapping_info->i_hdl);
+ list_del_init(&mapping_info->list);
+
+ /* free one buffer */
+ kfree(mapping_info);
+ return 0;
+}
+
+int cam_smmu_put_stage2_phy_addr(int handle, int ion_fd)
+{
+ int idx, rc;
+ struct cam_sec_buff_info *mapping_info;
+
+ /* find index in the iommu_cb_set.cb_info */
+ idx = GET_SMMU_TABLE_IDX(handle);
+ if (handle == HANDLE_INIT || idx < 0 || idx >= iommu_cb_set.cb_num) {
+ pr_err("Error: handle or index invalid. idx = %d hdl = %x\n",
+ idx, handle);
+ return -EINVAL;
+ }
+
+ mutex_lock(&iommu_cb_set.cb_info[idx].lock);
+ if (iommu_cb_set.cb_info[idx].handle != handle) {
+ pr_err("Error: hdl is not valid, table_hdl = %x, hdl = %x\n",
+ iommu_cb_set.cb_info[idx].handle, handle);
+ rc = -EINVAL;
+ goto put_addr_end;
+ }
+
+ /* based on ion fd and index, we can find mapping info of buffer */
+ mapping_info = cam_smmu_find_mapping_by_sec_buf_idx(idx, ion_fd);
+ if (!mapping_info) {
+ pr_err("Error: Invalid params! idx = %d, fd = %d\n",
+ idx, ion_fd);
+ rc = -EINVAL;
+ goto put_addr_end;
+ }
+
+ mapping_info->ref_count--;
+ if (mapping_info->ref_count > 0) {
+ CDBG("There are still %u buffer(s) with same fd %d",
+ mapping_info->ref_count, mapping_info->ion_fd);
+ rc = 0;
+ goto put_addr_end;
+ }
+
+ /* unmapping one buffer from device */
+ rc = cam_smmu_secure_unmap_buf_and_remove_from_list(mapping_info, idx);
+ if (rc < 0) {
+ pr_err("Error: unmap or remove list fail\n");
+ goto put_addr_end;
+ }
+
+put_addr_end:
+ mutex_unlock(&iommu_cb_set.cb_info[idx].lock);
+ return rc;
+}
+EXPORT_SYMBOL(cam_smmu_put_stage2_phy_addr);
+
+static int cam_smmu_map_stage2_buffer_and_add_to_list(int idx, int ion_fd,
+ enum dma_data_direction dma_dir, struct ion_client *client,
+ dma_addr_t *paddr_ptr,
+ size_t *len_ptr)
+{
+ int rc = 0;
+ struct ion_handle *i_handle = NULL;
+ struct cam_sec_buff_info *mapping_info;
+
+
+ /* clean the content from clients */
+ *paddr_ptr = (dma_addr_t)NULL;
+ *len_ptr = (size_t)0;
+
+ if (iommu_cb_set.cb_info[idx].state != CAM_SMMU_ATTACH) {
+ pr_err("Error: Device %s should call SMMU attach before map buffer\n",
+ iommu_cb_set.cb_info[idx].name);
+ return -EINVAL;
+ }
+
+ i_handle = ion_import_dma_buf(client, ion_fd);
+ if (IS_ERR_OR_NULL((void *)(i_handle))) {
+ pr_err("%s: ion import dma buffer failed\n", __func__);
+ return -EINVAL;
+ }
+
+ /* return addr and len to client */
+ rc = ion_phys(client, i_handle, paddr_ptr, len_ptr);
+ if (rc) {
+ pr_err("%s: ION Get Physical failed, rc = %d\n",
+ __func__, rc);
+ return -EINVAL;
+ }
+
+ /* fill up mapping_info */
+ mapping_info = kzalloc(sizeof(struct cam_sec_buff_info), GFP_KERNEL);
+ if (!mapping_info)
+ return -ENOSPC;
+
+ mapping_info->ion_fd = ion_fd;
+ mapping_info->paddr = *paddr_ptr;
+ mapping_info->len = *len_ptr;
+ mapping_info->dir = dma_dir;
+ mapping_info->ref_count = 1;
+ mapping_info->i_hdl = i_handle;
+ mapping_info->i_client = client;
+
+ CDBG("ion_fd = %d, dev = %pK, paddr= %pK, len = %u\n", ion_fd,
+ (void *)iommu_cb_set.cb_info[idx].dev,
+ (void *)*paddr_ptr, (unsigned int)*len_ptr);
+
+ /* add to the list */
+ list_add(&mapping_info->list, &iommu_cb_set.cb_info[idx].smmu_buf_list);
+
+ return rc;
+}
+
+int cam_smmu_get_stage2_phy_addr(int handle,
+ int ion_fd, enum cam_smmu_map_dir dir,
+ struct ion_client *client, ion_phys_addr_t *paddr_ptr,
+ size_t *len_ptr)
+{
+ int idx, rc;
+ enum dma_data_direction dma_dir;
+ enum cam_smmu_buf_state buf_state;
+
+ if (!paddr_ptr || !len_ptr) {
+ pr_err("Error: Input pointers are invalid\n");
+ return -EINVAL;
+ }
+ /* clean the content from clients */
+ *paddr_ptr = (dma_addr_t)NULL;
+ *len_ptr = (size_t)0;
+
+ dma_dir = cam_smmu_translate_dir(dir);
+ if (dma_dir == DMA_NONE) {
+ pr_err("Error: translate direction failed. dir = %d\n", dir);
+ return -EINVAL;
+ }
+
+ idx = GET_SMMU_TABLE_IDX(handle);
+ if (handle == HANDLE_INIT || idx < 0 || idx >= iommu_cb_set.cb_num) {
+ pr_err("Error: handle or index invalid. idx = %d hdl = %x\n",
+ idx, handle);
+ return -EINVAL;
+ }
+
+ mutex_lock(&iommu_cb_set.cb_info[idx].lock);
+ if (iommu_cb_set.cb_info[idx].handle != handle) {
+ pr_err("Error: hdl is not valid, table_hdl = %x, hdl = %x\n",
+ iommu_cb_set.cb_info[idx].handle, handle);
+ rc = -EINVAL;
+ goto get_addr_end;
+ }
+
+ if (iommu_cb_set.cb_info[idx].state != CAM_SMMU_ATTACH) {
+ pr_err("Error: Device %s should call SMMU attach before map buffer\n",
+ iommu_cb_set.cb_info[idx].name);
+ rc = -EINVAL;
+ goto get_addr_end;
+ }
+
+ buf_state = cam_smmu_check_fd_in_list(idx, ion_fd, paddr_ptr, len_ptr);
+ if (buf_state == CAM_SMMU_BUFF_EXIST) {
+ CDBG("ion_fd:%d already in the list, give same addr back",
+ ion_fd);
+ rc = 0;
+ goto get_addr_end;
+ }
+ rc = cam_smmu_map_stage2_buffer_and_add_to_list(idx, ion_fd, dma_dir,
+ client, paddr_ptr, len_ptr);
+ if (rc < 0) {
+ pr_err("Error: mapping or add list fail\n");
+ goto get_addr_end;
+ }
+
+get_addr_end:
+ mutex_unlock(&iommu_cb_set.cb_info[idx].lock);
+ return rc;
+}
+
+
int cam_smmu_get_phy_addr(int handle, int ion_fd,
enum cam_smmu_map_dir dir, dma_addr_t *paddr_ptr,
size_t *len_ptr)
@@ -1383,6 +2059,11 @@ int cam_smmu_destroy_handle(int handle)
}
mutex_lock(&iommu_cb_set.cb_info[idx].lock);
+ if (--iommu_cb_set.cb_info[idx].ref_cnt != 0) {
+ mutex_unlock(&iommu_cb_set.cb_info[idx].lock);
+ return 0;
+ }
+
if (iommu_cb_set.cb_info[idx].handle != handle) {
pr_err("Error: hdl is not valid, table_hdl = %x, hdl = %x\n",
iommu_cb_set.cb_info[idx].handle, handle);
@@ -1469,6 +2150,28 @@ end:
return rc;
}
+static int cam_smmu_populate_sids(struct device *dev,
+ struct cam_context_bank_info *cb)
+{
+ int i, j, rc = 0;
+ unsigned int cnt = 0;
+ const void *property;
+
+ /* set the name of the context bank */
+ property = of_get_property(dev->of_node, "iommus", &cnt);
+ cnt /= 4;
+ for (i = 0, j = 0; i < cnt; i = i + 2, j++) {
+ rc = of_property_read_u32_index(dev->of_node,
+ "iommus", i + 1, &cb->sids[j]);
+ if (rc < 0)
+ pr_err("misconfiguration, can't fetch SID\n");
+
+ pr_err("__debug cnt = %d, cb->name: :%s sid [%d] = %d\n,",
+ cnt, cb->name, j, cb->sids[j]);
+ }
+ return rc;
+}
+
static int cam_alloc_smmu_context_banks(struct device *dev)
{
struct device_node *domains_child_node = NULL;
@@ -1541,6 +2244,11 @@ static int cam_populate_smmu_context_banks(struct device *dev,
goto cb_init_fail;
}
+ /* populate SID's for each cb */
+ rc = cam_smmu_populate_sids(dev, cb);
+ if (rc < 0)
+ pr_err("Error: failed to populate sids : %s\n", cb->name);
+
/* Check if context bank supports scratch buffers */
if (of_property_read_bool(dev->of_node, "qcom,scratch-buf-support"))
cb->scratch_buf_support = 1;
@@ -1549,9 +2257,9 @@ static int cam_populate_smmu_context_banks(struct device *dev,
/* set the secure/non secure domain type */
if (of_property_read_bool(dev->of_node, "qcom,secure-context"))
- cb->is_secure = CAM_SECURE;
+ cb->is_secure = true;
else
- cb->is_secure = CAM_NON_SECURE;
+ cb->is_secure = false;
CDBG("cb->name :%s, cb->is_secure :%d, cb->scratch_support :%d\n",
cb->name, cb->is_secure, cb->scratch_buf_support);
diff --git a/drivers/media/platform/msm/camera_v2/common/cam_smmu_api.h b/drivers/media/platform/msm/camera_v2/common/cam_smmu_api.h
index 59d085989a9c..3b8481f8bf7e 100644
--- a/drivers/media/platform/msm/camera_v2/common/cam_smmu_api.h
+++ b/drivers/media/platform/msm/camera_v2/common/cam_smmu_api.h
@@ -23,6 +23,8 @@
#include <linux/random.h>
#include <linux/spinlock_types.h>
#include <linux/mutex.h>
+#include <linux/msm_ion.h>
+
/*
* Enum for possible CAM SMMU operations
@@ -31,6 +33,10 @@
enum cam_smmu_ops_param {
CAM_SMMU_ATTACH,
CAM_SMMU_DETACH,
+ CAM_SMMU_ATTACH_SEC_VFE_NS_STATS,
+ CAM_SMMU_DETACH_SEC_VFE_NS_STATS,
+ CAM_SMMU_ATTACH_SEC_CPP,
+ CAM_SMMU_DETACH_SEC_CPP,
CAM_SMMU_VOTE,
CAM_SMMU_DEVOTE,
CAM_SMMU_OPS_INVALID
@@ -87,6 +93,59 @@ int cam_smmu_get_phy_addr(int handle,
int cam_smmu_put_phy_addr(int handle, int ion_fd);
/**
+ * @param handle: Client has to pass back the smmu handle provided.
+ * @param ion_fd: ION handle identifying the memory buffer.
+ * @dir : Mapping direction: which will traslate toDMA_BIDIRECTIONAL,
+ * DMA_TO_DEVICE or DMA_FROM_DEVICE
+ * @client : Client has to pass the ion_client pointer created by the client.
+ * @phys_addr : Pointer to physical address where mapped address will be
+ * returned.
+ * @len : Length of buffer mapped returned by CAM SMMU driver.
+ * @return Status of operation. Negative in case of error. Zero otherwise.
+ */
+int cam_smmu_get_stage2_phy_addr(int handle,
+ int ion_fd, enum cam_smmu_map_dir dir,
+ struct ion_client *client, ion_phys_addr_t *addr,
+ size_t *len_ptr);
+
+/**
+ * @param handle: Handle to identify the CAMSMMU client (VFE, CPP, FD etc.)
+ * @param ion_fd: ION handle identifying the memory buffer.
+ *
+ * @return Status of operation. Negative in case of error. Zero otherwise.
+ */
+int cam_smmu_put_stage2_phy_addr(int handle, int ion_fd);
+
+/**
+ * @param handle: Client has to pass back the smmu handle provided.
+ * @dir : Mapping direction: which will traslate toDMA_BIDIRECTIONAL,
+ * DMA_TO_DEVICE or DMA_FROM_DEVICE, client has to pass.
+ * @client : Client has to pass the ion_client pointer created by the client.
+ * @ion_handle : handle to the buffer returned by CAM SMMU driver.
+ * @phys_addr : Pointer to physical address where mapped address will be
+ * returned.
+ * @len : Length of buffer mapped returned by CAM SMMU driver.
+ * @return Status of operation. Negative in case of error. Zero otherwise.
+ */
+int cam_smmu_alloc_get_stage2_scratch_mem(int handle,
+ enum cam_smmu_map_dir dir, struct ion_client *client,
+ struct ion_handle **sc_handle, ion_phys_addr_t *addr,
+ size_t *len_ptr);
+
+
+/**
+ * @param handle: Client has to pass back the smmu handle provided.
+ * @client : Client has to pass the ion_client pointer provided by SMMU
+ * driver.
+ * @ion_handle : Client has to pass the ion_handle provided by SMMU
+ * driver.
+ * @return Status of operation. Negative in case of error. Zero otherwise.
+ */
+
+int cam_smmu_free_stage2_scratch_mem(int handle,
+ struct ion_client *client, struct ion_handle *sc_handle);
+
+/**
* @brief : Allocates a scratch buffer
*
* This function allocates a scratch virtual buffer of length virt_len in the
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 3b6a2eecb4b6..13a7a398759b 100644
--- a/drivers/media/platform/msm/camera_v2/isp/msm_isp.h
+++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp.h
@@ -243,6 +243,8 @@ struct msm_vfe_core_ops {
bool (*is_module_cfg_lock_needed)(uint32_t reg_offset);
int (*ahb_clk_cfg)(struct vfe_device *vfe_dev,
struct msm_isp_ahb_clk_cfg *ahb_cfg);
+ int (*start_fetch_eng_multi_pass)(struct vfe_device *vfe_dev,
+ void *arg);
};
struct msm_vfe_stats_ops {
int (*get_stats_idx)(enum msm_isp_stats_type stats_type);
@@ -774,7 +776,7 @@ struct vfe_device {
struct msm_isp_statistics *stats;
uint64_t msm_isp_last_overflow_ab;
uint64_t msm_isp_last_overflow_ib;
- uint64_t msm_isp_vfe_clk_rate;
+ uint32_t msm_isp_vfe_clk_rate;
struct msm_isp_ub_info *ub_info;
uint32_t isp_sof_debug;
uint32_t isp_raw0_debug;
diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp40.c b/drivers/media/platform/msm/camera_v2/isp/msm_isp40.c
index 96f9e61578f2..1375d3ce8c65 100644
--- a/drivers/media/platform/msm/camera_v2/isp/msm_isp40.c
+++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp40.c
@@ -1054,11 +1054,72 @@ static int msm_vfe40_start_fetch_engine(struct vfe_device *vfe_dev,
return 0;
}
+static int msm_vfe40_start_fetch_engine_multi_pass(struct vfe_device *vfe_dev,
+ void *arg)
+{
+ int rc = 0;
+ uint32_t bufq_handle = 0;
+ struct msm_isp_buffer *buf = NULL;
+ struct msm_vfe_fetch_eng_multi_pass_start *fe_cfg = arg;
+ struct msm_isp_buffer_mapped_info mapped_info;
+
+ if (vfe_dev->fetch_engine_info.is_busy == 1) {
+ pr_err("%s: fetch engine busy\n", __func__);
+ return -EINVAL;
+ }
+ memset(&mapped_info, 0, sizeof(struct msm_isp_buffer_mapped_info));
+ /* There is other option of passing buffer address from user,
+ * in such case, driver needs to map the buffer and use it
+ */
+ vfe_dev->fetch_engine_info.session_id = fe_cfg->session_id;
+ vfe_dev->fetch_engine_info.stream_id = fe_cfg->stream_id;
+ vfe_dev->fetch_engine_info.offline_mode = fe_cfg->offline_mode;
+ vfe_dev->fetch_engine_info.fd = fe_cfg->fd;
+
+ if (!fe_cfg->offline_mode) {
+ bufq_handle = vfe_dev->buf_mgr->ops->get_bufq_handle(
+ vfe_dev->buf_mgr, fe_cfg->session_id,
+ fe_cfg->stream_id);
+ vfe_dev->fetch_engine_info.bufq_handle = bufq_handle;
+
+ rc = vfe_dev->buf_mgr->ops->get_buf_by_index(
+ vfe_dev->buf_mgr, bufq_handle, fe_cfg->buf_idx, &buf);
+ if (rc < 0 || !buf) {
+ pr_err("%s: No fetch buffer rc= %d buf= %p\n",
+ __func__, rc, buf);
+ return -EINVAL;
+ }
+ mapped_info = buf->mapped_info[0];
+ buf->state = MSM_ISP_BUFFER_STATE_DISPATCHED;
+ } else {
+ rc = vfe_dev->buf_mgr->ops->map_buf(vfe_dev->buf_mgr,
+ &mapped_info, fe_cfg->fd);
+ if (rc < 0) {
+ pr_err("%s: can not map buffer\n", __func__);
+ return -EINVAL;
+ }
+ }
+ vfe_dev->fetch_engine_info.buf_idx = fe_cfg->buf_idx;
+ vfe_dev->fetch_engine_info.is_busy = 1;
+
+ msm_camera_io_w(mapped_info.paddr + fe_cfg->input_buf_offset,
+ vfe_dev->vfe_base + 0x228);
+
+ msm_camera_io_w_mb(0x1, vfe_dev->vfe_base + 0x378);
+
+ msm_camera_io_w_mb(0x10000, vfe_dev->vfe_base + 0x4C);
+ msm_camera_io_w_mb(0x20000, vfe_dev->vfe_base + 0x4C);
+
+ ISP_DBG("%s:VFE%d Fetch Engine ready\n", __func__, vfe_dev->pdev->id);
+ return 0;
+}
+
static void msm_vfe40_cfg_fetch_engine(struct vfe_device *vfe_dev,
struct msm_vfe_pix_cfg *pix_cfg)
{
uint32_t x_size_word;
uint32_t temp = 0;
+ uint32_t main_unpack_pattern = 0;
struct msm_vfe_fetch_engine_cfg *fe_cfg = NULL;
if (pix_cfg->input_mux != EXTERNAL_READ) {
@@ -1089,10 +1150,14 @@ static void msm_vfe40_cfg_fetch_engine(struct vfe_device *vfe_dev,
/* need to update to use formulae to calculate X_SIZE_WORD*/
x_size_word = msm_isp_cal_word_per_line(
vfe_dev->axi_data.src_info[VFE_PIX_0].input_format,
- fe_cfg->fetch_width);
+ fe_cfg->buf_width);
msm_camera_io_w((x_size_word - 1) << 16, vfe_dev->vfe_base + 0x23C);
+ x_size_word = msm_isp_cal_word_per_line(
+ vfe_dev->axi_data.src_info[VFE_PIX_0].input_format,
+ fe_cfg->fetch_width);
+
temp = msm_camera_io_r(vfe_dev->vfe_base + 0x1C);
temp |= 2 << 16 | pix_cfg->pixel_pattern;
msm_camera_io_w(temp, vfe_dev->vfe_base + 0x1C);
@@ -1118,7 +1183,19 @@ static void msm_vfe40_cfg_fetch_engine(struct vfe_device *vfe_dev,
}
/* need to use formulae to calculate MAIN_UNPACK_PATTERN*/
- msm_camera_io_w(0xF6543210, vfe_dev->vfe_base + 0x248);
+ switch (vfe_dev->axi_data.src_info[VFE_PIX_0].input_format) {
+ case V4L2_PIX_FMT_P16BGGR10:
+ case V4L2_PIX_FMT_P16GBRG10:
+ case V4L2_PIX_FMT_P16GRBG10:
+ case V4L2_PIX_FMT_P16RGGB10:
+ main_unpack_pattern = 0xB210;
+ break;
+ default:
+ main_unpack_pattern = 0xF6543210;
+ break;
+ }
+ msm_camera_io_w(main_unpack_pattern,
+ vfe_dev->vfe_base + 0x248);
msm_camera_io_w(0xF, vfe_dev->vfe_base + 0x264);
return;
@@ -2261,6 +2338,8 @@ struct msm_vfe_hardware_info vfe40_hw_info = {
.is_module_cfg_lock_needed =
msm_vfe40_is_module_cfg_lock_needed,
.ahb_clk_cfg = NULL,
+ .start_fetch_eng_multi_pass =
+ msm_vfe40_start_fetch_engine_multi_pass,
},
.stats_ops = {
.get_stats_idx = msm_vfe40_get_stats_idx,
diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp47.c b/drivers/media/platform/msm/camera_v2/isp/msm_isp47.c
index c50c55a69fb5..98e73d48ad15 100644
--- a/drivers/media/platform/msm/camera_v2/isp/msm_isp47.c
+++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp47.c
@@ -1077,11 +1077,70 @@ int msm_vfe47_start_fetch_engine(struct vfe_device *vfe_dev,
return 0;
}
+int msm_vfe47_start_fetch_engine_multi_pass(struct vfe_device *vfe_dev,
+ void *arg)
+{
+ int rc = 0;
+ uint32_t bufq_handle = 0;
+ struct msm_isp_buffer *buf = NULL;
+ struct msm_vfe_fetch_eng_multi_pass_start *fe_cfg = arg;
+ struct msm_isp_buffer_mapped_info mapped_info;
+
+ if (vfe_dev->fetch_engine_info.is_busy == 1) {
+ pr_err("%s: fetch engine busy\n", __func__);
+ return -EINVAL;
+ }
+
+ memset(&mapped_info, 0, sizeof(struct msm_isp_buffer_mapped_info));
+
+ vfe_dev->fetch_engine_info.session_id = fe_cfg->session_id;
+ vfe_dev->fetch_engine_info.stream_id = fe_cfg->stream_id;
+ vfe_dev->fetch_engine_info.offline_mode = fe_cfg->offline_mode;
+ vfe_dev->fetch_engine_info.fd = fe_cfg->fd;
+
+ if (!fe_cfg->offline_mode) {
+ bufq_handle = vfe_dev->buf_mgr->ops->get_bufq_handle(
+ vfe_dev->buf_mgr, fe_cfg->session_id,
+ fe_cfg->stream_id);
+ vfe_dev->fetch_engine_info.bufq_handle = bufq_handle;
+
+ rc = vfe_dev->buf_mgr->ops->get_buf_by_index(
+ vfe_dev->buf_mgr, bufq_handle, fe_cfg->buf_idx, &buf);
+ if (rc < 0 || !buf) {
+ pr_err("%s: No fetch buffer rc= %d buf= %pK\n",
+ __func__, rc, buf);
+ return -EINVAL;
+ }
+ mapped_info = buf->mapped_info[0];
+ buf->state = MSM_ISP_BUFFER_STATE_DISPATCHED;
+ } else {
+ rc = vfe_dev->buf_mgr->ops->map_buf(vfe_dev->buf_mgr,
+ &mapped_info, fe_cfg->fd);
+ if (rc < 0) {
+ pr_err("%s: can not map buffer\n", __func__);
+ return -EINVAL;
+ }
+ }
+
+ vfe_dev->fetch_engine_info.buf_idx = fe_cfg->buf_idx;
+ vfe_dev->fetch_engine_info.is_busy = 1;
+
+ msm_camera_io_w(mapped_info.paddr + fe_cfg->input_buf_offset,
+ vfe_dev->vfe_base + 0x2F4);
+ msm_camera_io_w_mb(0x100000, vfe_dev->vfe_base + 0x80);
+ msm_camera_io_w_mb(0x200000, vfe_dev->vfe_base + 0x80);
+
+ ISP_DBG("%s:VFE%d Fetch Engine ready\n", __func__, vfe_dev->pdev->id);
+
+ return 0;
+}
+
void msm_vfe47_cfg_fetch_engine(struct vfe_device *vfe_dev,
struct msm_vfe_pix_cfg *pix_cfg)
{
uint32_t x_size_word, temp;
struct msm_vfe_fetch_engine_cfg *fe_cfg = NULL;
+ uint32_t main_unpack_pattern = 0;
if (pix_cfg->input_mux == EXTERNAL_READ) {
fe_cfg = &pix_cfg->fetch_engine_cfg;
@@ -1107,10 +1166,13 @@ void msm_vfe47_cfg_fetch_engine(struct vfe_device *vfe_dev,
x_size_word = msm_isp_cal_word_per_line(
vfe_dev->axi_data.src_info[VFE_PIX_0].input_format,
- fe_cfg->fetch_width);
+ fe_cfg->buf_width);
msm_camera_io_w((x_size_word - 1) << 16,
vfe_dev->vfe_base + 0x30c);
+ x_size_word = msm_isp_cal_word_per_line(
+ vfe_dev->axi_data.src_info[VFE_PIX_0].input_format,
+ fe_cfg->fetch_width);
msm_camera_io_w(x_size_word << 16 |
(temp & 0x3FFF) << 2 | VFE47_FETCH_BURST_LEN,
vfe_dev->vfe_base + 0x310);
@@ -1120,7 +1182,19 @@ void msm_vfe47_cfg_fetch_engine(struct vfe_device *vfe_dev,
msm_camera_io_w(temp, vfe_dev->vfe_base + 0x314);
/* need to use formulae to calculate MAIN_UNPACK_PATTERN*/
- msm_camera_io_w(0xF6543210, vfe_dev->vfe_base + 0x318);
+ switch (vfe_dev->axi_data.src_info[VFE_PIX_0].input_format) {
+ case V4L2_PIX_FMT_P16BGGR10:
+ case V4L2_PIX_FMT_P16GBRG10:
+ case V4L2_PIX_FMT_P16GRBG10:
+ case V4L2_PIX_FMT_P16RGGB10:
+ main_unpack_pattern = 0xB210;
+ break;
+ default:
+ main_unpack_pattern = 0xF6543210;
+ break;
+ }
+ msm_camera_io_w(main_unpack_pattern,
+ vfe_dev->vfe_base + 0x318);
msm_camera_io_w(0xF, vfe_dev->vfe_base + 0x334);
temp = msm_camera_io_r(vfe_dev->vfe_base + 0x50);
@@ -2721,6 +2795,8 @@ struct msm_vfe_hardware_info vfe47_hw_info = {
.is_module_cfg_lock_needed =
msm_vfe47_is_module_cfg_lock_needed,
.ahb_clk_cfg = msm_isp47_ahb_clk_cfg,
+ .start_fetch_eng_multi_pass =
+ msm_vfe47_start_fetch_engine_multi_pass,
},
.stats_ops = {
.get_stats_idx = msm_vfe47_get_stats_idx,
diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp47.h b/drivers/media/platform/msm/camera_v2/isp/msm_isp47.h
index 3955196d1deb..6524ac84edf3 100644
--- a/drivers/media/platform/msm/camera_v2/isp/msm_isp47.h
+++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp47.h
@@ -65,6 +65,8 @@ int32_t msm_vfe47_cfg_io_format(struct vfe_device *vfe_dev,
enum msm_vfe_axi_stream_src stream_src, uint32_t io_format);
int msm_vfe47_start_fetch_engine(struct vfe_device *vfe_dev,
void *arg);
+int msm_vfe47_start_fetch_engine_multi_pass(struct vfe_device *vfe_dev,
+ void *arg);
void msm_vfe47_cfg_fetch_engine(struct vfe_device *vfe_dev,
struct msm_vfe_pix_cfg *pix_cfg);
void msm_vfe47_cfg_testgen(struct vfe_device *vfe_dev,
diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp48.c b/drivers/media/platform/msm/camera_v2/isp/msm_isp48.c
index 49520bb44ad8..568125e2d7c2 100644
--- a/drivers/media/platform/msm/camera_v2/isp/msm_isp48.c
+++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp48.c
@@ -309,6 +309,8 @@ struct msm_vfe_hardware_info vfe48_hw_info = {
.is_module_cfg_lock_needed =
msm_vfe47_is_module_cfg_lock_needed,
.ahb_clk_cfg = msm_isp47_ahb_clk_cfg,
+ .start_fetch_eng_multi_pass =
+ msm_vfe47_start_fetch_engine_multi_pass,
},
.stats_ops = {
.get_stats_idx = msm_vfe47_get_stats_idx,
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 e8289f05d28f..3b9c3c9d3926 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
@@ -1691,6 +1691,76 @@ static struct msm_isp_buffer *msm_isp_get_stream_buffer(
return buf;
}
+int msm_isp_cfg_offline_ping_pong_address(struct vfe_device *vfe_dev,
+ struct msm_vfe_axi_stream *stream_info, uint32_t pingpong_status,
+ uint32_t buf_idx)
+{
+ int i, rc = 0;
+ struct msm_isp_buffer *buf = NULL;
+ uint32_t pingpong_bit;
+ uint32_t buffer_size_byte = 0;
+ int32_t word_per_line = 0;
+ dma_addr_t paddr;
+ uint32_t bufq_handle = 0;
+ int vfe_idx;
+
+ bufq_handle = stream_info->bufq_handle[VFE_BUF_QUEUE_DEFAULT];
+
+ if (!vfe_dev->is_split) {
+ rc = vfe_dev->buf_mgr->ops->get_buf_by_index(
+ vfe_dev->buf_mgr, bufq_handle, buf_idx, &buf);
+ if (rc < 0 || !buf) {
+ pr_err("%s: No fetch buffer rc= %d buf= %p\n",
+ __func__, rc, buf);
+ return -EINVAL;
+ }
+
+ if (buf->num_planes != stream_info->num_planes) {
+ pr_err("%s: Invalid buffer\n", __func__);
+ vfe_dev->buf_mgr->ops->put_buf(vfe_dev->buf_mgr,
+ bufq_handle, buf->buf_idx);
+ return -EINVAL;
+ }
+ vfe_idx = msm_isp_get_vfe_idx_for_stream(vfe_dev, stream_info);
+ pingpong_bit = ((pingpong_status >>
+ stream_info->wm[vfe_idx][0]) & 0x1);
+
+ for (i = 0; i < stream_info->num_planes; i++) {
+ word_per_line = msm_isp_cal_word_per_line(
+ stream_info->output_format,
+ stream_info->plane_cfg[vfe_idx][i].
+ output_stride);
+ if (word_per_line < 0) {
+ /* 0 means no prefetch*/
+ word_per_line = 0;
+ buffer_size_byte = 0;
+ } else {
+ buffer_size_byte = (word_per_line * 8 *
+ stream_info->plane_cfg[vfe_idx][i].
+ output_scan_lines) -
+ stream_info->
+ plane_cfg[vfe_idx][i].plane_addr_offset;
+ }
+ paddr = buf->mapped_info[i].paddr;
+
+ vfe_dev->hw_info->vfe_ops.axi_ops.
+ update_ping_pong_addr(
+ vfe_dev->vfe_base, stream_info->wm[vfe_idx][i],
+ pingpong_bit, paddr +
+ stream_info->
+ plane_cfg[vfe_idx][i].plane_addr_offset,
+ buffer_size_byte);
+ stream_info->buf[!pingpong_bit] = buf;
+ buf->pingpong_bit = !pingpong_bit;
+ }
+ buf->state = MSM_ISP_BUFFER_STATE_DEQUEUED;
+ stream_info->buf[!pingpong_bit] = buf;
+ buf->pingpong_bit = !pingpong_bit;
+ }
+ return rc;
+
+}
+
static int msm_isp_cfg_ping_pong_address(
struct msm_vfe_axi_stream *stream_info, uint32_t pingpong_status)
{
@@ -1888,6 +1958,11 @@ static int msm_isp_process_done_buf(struct vfe_device *vfe_dev,
buf_event.u.buf_done.buf_idx = buf->buf_idx;
buf_event.u.buf_done.output_format =
stream_info->runtime_output_format;
+ if (vfe_dev->fetch_engine_info.is_busy &&
+ SRC_TO_INTF(stream_info->stream_src) == VFE_PIX_0) {
+ vfe_dev->fetch_engine_info.is_busy = 0;
+ }
+
if (stream_info->buf_divert &&
buf_src != MSM_ISP_BUFFER_SRC_SCRATCH) {
@@ -2065,7 +2140,8 @@ static void msm_isp_input_enable(struct vfe_device *vfe_dev,
continue;
/* activate the input since it is deactivated */
axi_data->src_info[i].frame_id = 0;
- axi_data->src_info[i].active = 1;
+ if (axi_data->src_info[i].input_mux != EXTERNAL_READ)
+ axi_data->src_info[i].active = 1;
if (i >= VFE_RAW_0 && sync_frame_id_src) {
/*
* Incase PIX and RDI streams are part
@@ -3534,6 +3610,7 @@ int msm_isp_update_axi_stream(struct vfe_device *vfe_dev, void *arg)
unsigned long flags;
struct msm_isp_timestamp timestamp;
uint32_t frame_id;
+ int vfe_idx;
/*num_stream is uint32 and update_info[] bound by MAX_NUM_STREAM*/
if (update_cmd->num_streams > MAX_NUM_STREAM)
@@ -3746,6 +3823,20 @@ int msm_isp_update_axi_stream(struct vfe_device *vfe_dev, void *arg)
__func__);
break;
}
+ case UPDATE_STREAM_OFFLINE_AXI_CONFIG: {
+ for (i = 0; i < update_cmd->num_streams; i++) {
+ update_info =
+ (struct msm_vfe_axi_stream_cfg_update_info *)
+ &update_cmd->update_info[i];
+ stream_info = msm_isp_get_stream_common_data(vfe_dev,
+ HANDLE_TO_IDX(update_info->stream_handle));
+ vfe_idx = msm_isp_get_vfe_idx_for_stream(
+ vfe_dev, stream_info);
+ msm_isp_stream_axi_cfg_update(vfe_dev, stream_info,
+ update_info);
+ }
+ break;
+ }
default:
pr_err("%s: Invalid update type %d\n", __func__,
update_cmd->update_type);
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 9c642370b1a1..f9ae5fb74281 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
@@ -157,4 +157,7 @@ static inline struct msm_vfe_axi_stream *msm_isp_vfe_get_stream(
index);
}
+int msm_isp_cfg_offline_ping_pong_address(struct vfe_device *vfe_dev,
+ struct msm_vfe_axi_stream *stream_info, uint32_t pingpong_status,
+ uint32_t buf_idx);
#endif /* __MSM_ISP_AXI_UTIL_H__ */
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 b0789ce4a71c..72eac5d81627 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
@@ -375,6 +375,47 @@ static int msm_isp_start_fetch_engine(struct vfe_device *vfe_dev,
start_fetch_eng(vfe_dev, arg);
}
+static int msm_isp_start_fetch_engine_multi_pass(struct vfe_device *vfe_dev,
+ void *arg)
+{
+ struct msm_vfe_fetch_eng_multi_pass_start *fe_cfg = arg;
+ struct msm_vfe_axi_stream *stream_info = NULL;
+ int i = 0, rc;
+ uint32_t wm_reload_mask = 0;
+ int vfe_idx;
+ /*
+ * For Offline VFE, HAL expects same frame id
+ * for offline output which it requested in do_reprocess.
+ */
+ vfe_dev->axi_data.src_info[VFE_PIX_0].frame_id =
+ fe_cfg->frame_id;
+ if (fe_cfg->offline_pass == OFFLINE_SECOND_PASS) {
+ stream_info = msm_isp_get_stream_common_data(vfe_dev,
+ HANDLE_TO_IDX(fe_cfg->output_stream_id));
+ if (stream_info == NULL) {
+ pr_err("%s: Error in Offline process\n", __func__);
+ return -EINVAL;
+ }
+ vfe_idx = msm_isp_get_vfe_idx_for_stream(vfe_dev, stream_info);
+ msm_isp_reset_framedrop(vfe_dev, stream_info);
+
+ rc = msm_isp_cfg_offline_ping_pong_address(vfe_dev, stream_info,
+ VFE_PING_FLAG, fe_cfg->output_buf_idx);
+ if (rc < 0) {
+ pr_err("%s: Fetch engine config failed\n", __func__);
+ return -EINVAL;
+ }
+ for (i = 0; i < stream_info->num_planes; i++)
+ wm_reload_mask |= (1 << stream_info->wm[vfe_idx][i]);
+ vfe_dev->hw_info->vfe_ops.core_ops.reg_update(vfe_dev,
+ VFE_SRC_MAX);
+ vfe_dev->hw_info->vfe_ops.axi_ops.reload_wm(vfe_dev,
+ vfe_dev->vfe_base, wm_reload_mask);
+ }
+ return vfe_dev->hw_info->vfe_ops.core_ops.
+ start_fetch_eng_multi_pass(vfe_dev, arg);
+}
+
void msm_isp_fetch_engine_done_notify(struct vfe_device *vfe_dev,
struct msm_vfe_fetch_engine_info *fetch_engine_info)
{
@@ -880,6 +921,13 @@ static long msm_isp_ioctl_unlocked(struct v4l2_subdev *sd,
rc = msm_isp_start_fetch_engine(vfe_dev, arg);
mutex_unlock(&vfe_dev->core_mutex);
break;
+
+ case VIDIOC_MSM_ISP_FETCH_ENG_MULTI_PASS_START:
+ case VIDIOC_MSM_ISP_MAP_BUF_START_MULTI_PASS_FE:
+ mutex_lock(&vfe_dev->core_mutex);
+ rc = msm_isp_start_fetch_engine_multi_pass(vfe_dev, arg);
+ mutex_unlock(&vfe_dev->core_mutex);
+ break;
case VIDIOC_MSM_ISP_REG_UPDATE_CMD:
if (arg) {
enum msm_vfe_input_src frame_src =
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 094a7861831a..dc2061fc4537 100644
--- a/drivers/media/platform/msm/camera_v2/ispif/msm_ispif.c
+++ b/drivers/media/platform/msm/camera_v2/ispif/msm_ispif.c
@@ -1444,7 +1444,8 @@ static inline void msm_ispif_read_irq_status(struct ispif_irq_status *out,
}
if (fatal_err == true) {
- pr_err("%s: fatal error, stop ispif immediately\n", __func__);
+ pr_err_ratelimited("%s: fatal error, stop ispif immediately\n",
+ __func__);
for (i = 0; i < ispif->vfe_info.num_vfe; i++) {
msm_camera_io_w(ISPIF_STOP_INTF_IMMEDIATELY,
ispif->base + ISPIF_VFE_m_INTF_CMD_0(i));
diff --git a/drivers/media/platform/msm/camera_v2/jpeg_10/msm_jpeg_dev.c b/drivers/media/platform/msm/camera_v2/jpeg_10/msm_jpeg_dev.c
index 437af72a6a55..de27e585f63d 100644
--- a/drivers/media/platform/msm/camera_v2/jpeg_10/msm_jpeg_dev.c
+++ b/drivers/media/platform/msm/camera_v2/jpeg_10/msm_jpeg_dev.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012-2015, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-2016, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -71,8 +71,8 @@ static long msm_jpeg_compat_ioctl(struct file *filp, unsigned int cmd,
int rc;
struct msm_jpeg_device *pgmn_dev = filp->private_data;
- JPEG_DBG("%s:%d] cmd=%d pgmn_dev=0x%lx arg=0x%lx\n", __func__,
- __LINE__, _IOC_NR(cmd), (unsigned long)pgmn_dev,
+ JPEG_DBG("%s:%d] cmd=%d pgmn_dev=0x%pK arg=0x%lx\n", __func__,
+ __LINE__, _IOC_NR(cmd), pgmn_dev,
(unsigned long)arg);
rc = __msm_jpeg_compat_ioctl(pgmn_dev, cmd, arg);
@@ -87,8 +87,8 @@ static long msm_jpeg_ioctl(struct file *filp, unsigned int cmd,
int rc;
struct msm_jpeg_device *pgmn_dev = filp->private_data;
- JPEG_DBG("%s:%d] cmd=%d pgmn_dev=0x%lx arg=0x%lx\n", __func__,
- __LINE__, _IOC_NR(cmd), (unsigned long)pgmn_dev,
+ JPEG_DBG("%s:%d] cmd=%d pgmn_dev=0x%pK arg=0x%lx\n", __func__,
+ __LINE__, _IOC_NR(cmd), pgmn_dev,
(unsigned long)arg);
rc = __msm_jpeg_ioctl(pgmn_dev, cmd, arg);
@@ -114,9 +114,9 @@ int msm_jpeg_subdev_init(struct v4l2_subdev *jpeg_sd)
struct msm_jpeg_device *pgmn_dev =
(struct msm_jpeg_device *)jpeg_sd->host_priv;
- JPEG_DBG("%s:%d: jpeg_sd=0x%lx pgmn_dev=0x%lx\n",
+ JPEG_DBG("%s:%d: jpeg_sd=0x%lx pgmn_dev=0x%pK\n",
__func__, __LINE__, (unsigned long)jpeg_sd,
- (unsigned long)pgmn_dev);
+ pgmn_dev);
rc = __msm_jpeg_open(pgmn_dev);
JPEG_DBG("%s:%d: rc=%d\n",
__func__, __LINE__, rc);
@@ -132,7 +132,7 @@ static long msm_jpeg_subdev_ioctl(struct v4l2_subdev *sd,
JPEG_DBG("%s: cmd=%d\n", __func__, cmd);
- JPEG_DBG("%s: pgmn_dev 0x%lx", __func__, (unsigned long)pgmn_dev);
+ JPEG_DBG("%s: pgmn_dev 0x%pK", __func__, pgmn_dev);
JPEG_DBG("%s: Calling __msm_jpeg_ioctl\n", __func__);
@@ -146,7 +146,7 @@ void msm_jpeg_subdev_release(struct v4l2_subdev *jpeg_sd)
int rc;
struct msm_jpeg_device *pgmn_dev =
(struct msm_jpeg_device *)jpeg_sd->host_priv;
- JPEG_DBG("%s:pgmn_dev=0x%lx", __func__, (unsigned long)pgmn_dev);
+ JPEG_DBG("%s:pgmn_dev=0x%pK", __func__, pgmn_dev);
rc = __msm_jpeg_release(pgmn_dev);
JPEG_DBG("%s:rc=%d", __func__, rc);
}
diff --git a/drivers/media/platform/msm/camera_v2/jpeg_10/msm_jpeg_hw.c b/drivers/media/platform/msm/camera_v2/jpeg_10/msm_jpeg_hw.c
index 071ce0a41ed9..e40869d41a5d 100644
--- a/drivers/media/platform/msm/camera_v2/jpeg_10/msm_jpeg_hw.c
+++ b/drivers/media/platform/msm/camera_v2/jpeg_10/msm_jpeg_hw.c
@@ -847,7 +847,7 @@ int msm_jpeg_hw_exec_cmds(struct msm_jpeg_hw_cmd *hw_cmd_p, uint32_t m_cmds,
uint32_t data;
while (m_cmds--) {
- if (hw_cmd_p->offset > max_size) {
+ if (hw_cmd_p->offset >= max_size) {
JPEG_PR_ERR("%s:%d] %d exceed hw region %d\n", __func__,
__LINE__, hw_cmd_p->offset, max_size);
return -EFAULT;
diff --git a/drivers/media/platform/msm/camera_v2/jpeg_dma/msm_jpeg_dma_dev.c b/drivers/media/platform/msm/camera_v2/jpeg_dma/msm_jpeg_dma_dev.c
index 63d7e715162b..3301fc446193 100644
--- a/drivers/media/platform/msm/camera_v2/jpeg_dma/msm_jpeg_dma_dev.c
+++ b/drivers/media/platform/msm/camera_v2/jpeg_dma/msm_jpeg_dma_dev.c
@@ -128,6 +128,21 @@ static inline void msm_jpegdma_schedule_next_config(struct jpegdma_ctx *ctx)
}
/*
+ * msm_jpegdma_cast_long_to_buff_ptr - Cast long to buffer pointer.
+ * @vaddr: vaddr as long
+ * @buff_ptr_head: buffer pointer head
+ */
+static inline void msm_jpegdma_cast_long_to_buff_ptr(unsigned long vaddr,
+ struct msm_jpeg_dma_buff **buff_ptr_head)
+{
+#ifdef CONFIG_COMPAT
+ *buff_ptr_head = compat_ptr(vaddr);
+#else
+ *buff_ptr_head = (struct msm_jpeg_dma_buff *) vaddr;
+#endif
+}
+
+/*
* msm_jpegdma_get_format_idx - Get jpeg dma format lookup index.
* @ctx: Pointer to dma ctx.
* @f: v4l2 format.
@@ -410,10 +425,12 @@ static void *msm_jpegdma_get_userptr(void *alloc_ctx,
{
struct msm_jpegdma_device *dma = alloc_ctx;
struct msm_jpegdma_buf_handle *buf;
- struct msm_jpeg_dma_buff __user *up_buff = compat_ptr(vaddr);
+ struct msm_jpeg_dma_buff __user *up_buff;
struct msm_jpeg_dma_buff kp_buff;
int ret;
+ msm_jpegdma_cast_long_to_buff_ptr(vaddr, &up_buff);
+
if (!access_ok(VERIFY_READ, up_buff,
sizeof(struct msm_jpeg_dma_buff)) ||
get_user(kp_buff.fd, &up_buff->fd)) {
@@ -813,10 +830,12 @@ static int msm_jpegdma_qbuf(struct file *file, void *fh,
struct v4l2_buffer *buf)
{
struct jpegdma_ctx *ctx = msm_jpegdma_ctx_from_fh(fh);
- struct msm_jpeg_dma_buff __user *up_buff = compat_ptr(buf->m.userptr);
+ struct msm_jpeg_dma_buff __user *up_buff;
struct msm_jpeg_dma_buff kp_buff;
int ret;
+ msm_jpegdma_cast_long_to_buff_ptr(buf->m.userptr, &up_buff);
+
if (!access_ok(VERIFY_READ, up_buff,
sizeof(struct msm_jpeg_dma_buff)) ||
get_user(kp_buff.fd, &up_buff->fd) ||
diff --git a/drivers/media/platform/msm/camera_v2/pproc/cpp/msm_cpp.c b/drivers/media/platform/msm/camera_v2/pproc/cpp/msm_cpp.c
index ab074ffbcdfb..7e452e9e4ee2 100644
--- a/drivers/media/platform/msm/camera_v2/pproc/cpp/msm_cpp.c
+++ b/drivers/media/platform/msm/camera_v2/pproc/cpp/msm_cpp.c
@@ -220,6 +220,7 @@ void msm_cpp_deinit_bandwidth_mgr(struct cpp_device *cpp_dev)
static int msm_cpp_update_bandwidth_setting(struct cpp_device *cpp_dev,
uint64_t ab, uint64_t ib) {
int rc;
+
if (cpp_dev->bus_master_flag)
rc = msm_cpp_update_bandwidth(cpp_dev, ab, ib);
else
@@ -242,6 +243,7 @@ static void msm_enqueue(struct msm_device_queue *queue,
struct list_head *entry)
{
unsigned long flags;
+
spin_lock_irqsave(&queue->lock, flags);
queue->len++;
if (queue->len > queue->max) {
@@ -302,6 +304,7 @@ static void msm_cpp_timer_queue_update(struct cpp_device *cpp_dev)
{
uint32_t i;
unsigned long flags;
+
CPP_DBG("Frame done qlen %d\n", cpp_dev->processing_q.len);
if (cpp_dev->processing_q.len <= 1) {
msm_cpp_clear_timer(cpp_dev);
@@ -323,6 +326,7 @@ static void msm_cpp_timer_queue_update(struct cpp_device *cpp_dev)
static uint32_t msm_cpp_read(void __iomem *cpp_base)
{
uint32_t tmp, retry = 0;
+
do {
tmp = msm_camera_io_r(cpp_base + MSM_CPP_MICRO_FIFO_TX_STAT);
} while (((tmp & 0x2) == 0x0) && (retry++ < 10));
@@ -409,14 +413,22 @@ static unsigned long msm_cpp_queue_buffer_info(struct cpp_device *cpp_dev,
pr_err("error allocating memory\n");
goto error;
}
- buff->map_info.buff_info = *buffer_info;
+ buff->map_info.buff_info = *buffer_info;
buff->map_info.buf_fd = buffer_info->fd;
- rc = cam_smmu_get_phy_addr(cpp_dev->iommu_hdl, buffer_info->fd,
- CAM_SMMU_MAP_RW, &buff->map_info.phy_addr,
- (size_t *)&buff->map_info.len);
+
+ if (buff_queue->security_mode == SECURE_MODE)
+ rc = cam_smmu_get_stage2_phy_addr(cpp_dev->iommu_hdl,
+ buffer_info->fd, CAM_SMMU_MAP_RW,
+ cpp_dev->ion_client, &buff->map_info.phy_addr,
+ (size_t *)&buff->map_info.len);
+ else
+ rc = cam_smmu_get_phy_addr(cpp_dev->iommu_hdl,
+ buffer_info->fd, CAM_SMMU_MAP_RW,
+ &buff->map_info.phy_addr,
+ (size_t *)&buff->map_info.len);
if (rc < 0) {
- pr_err("ION mmap failed\n");
+ pr_err("ION mmap for CPP buffer failed\n");
kzfree(buff);
goto error;
}
@@ -430,10 +442,17 @@ error:
}
static void msm_cpp_dequeue_buffer_info(struct cpp_device *cpp_dev,
+ struct msm_cpp_buff_queue_info_t *buff_queue,
struct msm_cpp_buffer_map_list_t *buff)
{
int ret = -1;
- ret = cam_smmu_put_phy_addr(cpp_dev->iommu_hdl, buff->map_info.buf_fd);
+
+ if (buff_queue->security_mode == SECURE_MODE)
+ ret = cam_smmu_put_stage2_phy_addr(cpp_dev->iommu_hdl,
+ buff->map_info.buf_fd);
+ else
+ ret = cam_smmu_put_phy_addr(cpp_dev->iommu_hdl,
+ buff->map_info.buf_fd);
if (ret < 0)
pr_err("Error: cannot put the iommu handle back to ion fd\n");
@@ -466,6 +485,7 @@ static unsigned long msm_cpp_fetch_buffer_info(struct cpp_device *cpp_dev,
buffer_info);
*fd = buffer_info->fd;
}
+
return phy_addr;
}
@@ -477,12 +497,12 @@ static int32_t msm_cpp_dequeue_buff_info_list(struct cpp_device *cpp_dev,
buff_head = &buff_queue_info->native_buff_head;
list_for_each_entry_safe(buff, save, buff_head, entry) {
- msm_cpp_dequeue_buffer_info(cpp_dev, buff);
+ msm_cpp_dequeue_buffer_info(cpp_dev, buff_queue_info, buff);
}
buff_head = &buff_queue_info->vb2_buff_head;
list_for_each_entry_safe(buff, save, buff_head, entry) {
- msm_cpp_dequeue_buffer_info(cpp_dev, buff);
+ msm_cpp_dequeue_buffer_info(cpp_dev, buff_queue_info, buff);
}
return 0;
@@ -502,7 +522,8 @@ static int32_t msm_cpp_dequeue_buff(struct cpp_device *cpp_dev,
list_for_each_entry_safe(buff, save, buff_head, entry) {
if (buff->map_info.buff_info.index == buff_index) {
- msm_cpp_dequeue_buffer_info(cpp_dev, buff);
+ msm_cpp_dequeue_buffer_info(cpp_dev, buff_queue_info,
+ buff);
break;
}
}
@@ -522,6 +543,8 @@ static int32_t msm_cpp_add_buff_queue_entry(struct cpp_device *cpp_dev,
buff_queue_info->used = 1;
buff_queue_info->session_id = session_id;
buff_queue_info->stream_id = stream_id;
+ buff_queue_info->security_mode =
+ cpp_dev->security_mode;
INIT_LIST_HEAD(&buff_queue_info->vb2_buff_head);
INIT_LIST_HEAD(&buff_queue_info->native_buff_head);
return 0;
@@ -548,6 +571,7 @@ static int32_t msm_cpp_free_buff_queue_entry(struct cpp_device *cpp_dev,
buff_queue_info->used = 0;
buff_queue_info->session_id = 0;
buff_queue_info->stream_id = 0;
+ buff_queue_info->security_mode = NON_SECURE_MODE;
INIT_LIST_HEAD(&buff_queue_info->vb2_buff_head);
INIT_LIST_HEAD(&buff_queue_info->native_buff_head);
return 0;
@@ -557,6 +581,7 @@ static int32_t msm_cpp_create_buff_queue(struct cpp_device *cpp_dev,
uint32_t num_buffq)
{
struct msm_cpp_buff_queue_info_t *buff_queue;
+
buff_queue = kzalloc(
sizeof(struct msm_cpp_buff_queue_info_t) * num_buffq,
GFP_KERNEL);
@@ -602,6 +627,7 @@ static int32_t msm_cpp_poll(void __iomem *cpp_base, u32 val)
{
uint32_t tmp, retry = 0;
int32_t rc = 0;
+
do {
tmp = msm_cpp_read(cpp_base);
if (tmp != 0xDEADBEEF)
@@ -796,6 +822,7 @@ static irqreturn_t msm_cpp_irq(int irq_num, void *data)
uint32_t tx_fifo[MSM_CPP_TX_FIFO_LEVEL];
struct cpp_device *cpp_dev = data;
struct msm_cpp_tasklet_queue_cmd *queue_cmd;
+
irq_status = msm_camera_io_r(cpp_dev->base + MSM_CPP_MICRO_IRQGEN_STAT);
if (irq_status & 0x8) {
@@ -1028,6 +1055,7 @@ reg_enable_failed:
static void cpp_release_hardware(struct cpp_device *cpp_dev)
{
int32_t rc;
+
if (cpp_dev->state != CPP_STATE_BOOT) {
msm_camera_unregister_irq(cpp_dev->pdev, cpp_dev->irq, cpp_dev);
tasklet_kill(&cpp_dev->cpp_tasklet);
@@ -1061,7 +1089,7 @@ static int32_t cpp_load_fw(struct cpp_device *cpp_dev, char *fw_name_bin)
goto end;
}
pr_debug("%s:%d] FW file: %s\n", __func__, __LINE__, fw_name_bin);
- if (NULL == cpp_dev->fw) {
+ if (cpp_dev->fw == NULL) {
pr_err("%s:%d] fw NULL", __func__, __LINE__);
rc = -EINVAL;
goto end;
@@ -1192,7 +1220,8 @@ static int cpp_open_node(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
int rc;
uint32_t i;
struct cpp_device *cpp_dev = NULL;
- CPP_DBG("E\n");
+
+ CPP_DBG("E");
if (!sd || !fh) {
pr_err("Wrong input parameters sd %pK fh %pK!",
@@ -1246,6 +1275,14 @@ static int cpp_open_node(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
return rc;
}
cpp_dev->state = CPP_STATE_IDLE;
+
+ CPP_DBG("Invoking msm_ion_client_create()\n");
+ cpp_dev->ion_client = msm_ion_client_create("cpp");
+ if (cpp_dev->ion_client == NULL) {
+ pr_err("msm_ion_client_create() failed\n");
+ mutex_unlock(&cpp_dev->mutex);
+ rc = -ENOMEM;
+ }
}
mutex_unlock(&cpp_dev->mutex);
return 0;
@@ -1338,6 +1375,12 @@ static int cpp_close_node(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
msm_cpp_empty_list(processing_q, list_frame);
msm_cpp_empty_list(eventData_q, list_eventdata);
cpp_dev->state = CPP_STATE_OFF;
+
+ if (cpp_dev->ion_client) {
+ CPP_DBG("Invoking ion_client_destroy()\n");
+ ion_client_destroy(cpp_dev->ion_client);
+ cpp_dev->ion_client = NULL;
+ }
}
mutex_unlock(&cpp_dev->mutex);
@@ -1415,7 +1458,8 @@ static int msm_cpp_notify_frame_done(struct cpp_device *cpp_dev,
SWAP_IDENTITY_FOR_BATCH_ON_PREVIEW(processed_frame,
iden, processed_frame->duplicate_identity);
- memset(&buff_mgr_info, 0 ,
+
+ memset(&buff_mgr_info, 0,
sizeof(struct msm_buf_mngr_info));
buff_mgr_info.session_id = ((iden >> 16) & 0xFFFF);
@@ -1460,7 +1504,7 @@ static int msm_cpp_notify_frame_done(struct cpp_device *cpp_dev,
SWAP_IDENTITY_FOR_BATCH_ON_PREVIEW(processed_frame,
iden, processed_frame->identity);
- memset(&buff_mgr_info, 0 ,
+ memset(&buff_mgr_info, 0,
sizeof(struct msm_buf_mngr_info));
buff_mgr_info.session_id = ((iden >> 16) & 0xFFFF);
@@ -1500,6 +1544,7 @@ static int msm_cpp_dump_frame_cmd(struct msm_cpp_frame_info_t *frame_info)
{
int i, i1, i2;
struct cpp_device *cpp_dev = cpp_timer.data.cpp_dev;
+
CPP_DBG("-- start: cpp frame cmd for identity=0x%x, frame_id=%d --\n",
frame_info->identity, frame_info->frame_id);
@@ -1935,6 +1980,7 @@ static int msm_cpp_check_buf_type(struct msm_buf_mngr_info *buff_mgr_info,
{
int32_t num_output_bufs = 0;
uint32_t i = 0;
+
if (buff_mgr_info->type == MSM_CAMERA_BUF_MNGR_BUF_USER) {
new_frame->batch_info.cont_idx =
buff_mgr_info->index;
@@ -2009,7 +2055,7 @@ static void msm_cpp_update_frame_msg_phy_address(struct cpp_device *cpp_dev,
dup_we_mmu_pf_ptr_off = cpp_dev->payload_params.dup_we_mmu_pf_ptr_off;
ref_we_mmu_pf_ptr_off = cpp_dev->payload_params.ref_we_mmu_pf_ptr_off;
- pr_debug("%s: feature_mask 0x%x\n", __func__, new_frame->feature_mask);
+ pr_debug("feature_mask 0x%x\n", new_frame->feature_mask);
/* Update individual module status from feature mask */
tnr_enabled = ((new_frame->feature_mask & TNR_MASK) >> 2);
@@ -2460,6 +2506,7 @@ static int msm_cpp_cfg_frame(struct cpp_device *cpp_dev,
/* get buffer for duplicate output */
if (new_frame->duplicate_output) {
int32_t iden = new_frame->duplicate_identity;
+
CPP_DBG("duplication enabled, dup_id=0x%x",
new_frame->duplicate_identity);
@@ -2599,7 +2646,7 @@ static int msm_cpp_cfg(struct cpp_device *cpp_dev,
int32_t rc = 0;
int32_t i = 0;
int32_t num_buff = sizeof(k_frame_info.output_buffer_info)/
- sizeof(struct msm_cpp_buffer_info_t);
+ sizeof(struct msm_cpp_buffer_info_t);
if (copy_from_user(&k_frame_info,
(void __user *)ioctl_ptr->ioctl_ptr,
sizeof(k_frame_info)))
@@ -2660,6 +2707,7 @@ static int msm_cpp_copy_from_ioctl_ptr(void *dst_ptr,
struct msm_camera_v4l2_ioctl_t *ioctl_ptr)
{
int ret;
+
if ((ioctl_ptr->ioctl_ptr == NULL) || (ioctl_ptr->len == 0)) {
pr_err("%s: Wrong ioctl_ptr %pK / len %zu\n", __func__,
ioctl_ptr, ioctl_ptr->len);
@@ -2683,6 +2731,7 @@ static int msm_cpp_copy_from_ioctl_ptr(void *dst_ptr,
struct msm_camera_v4l2_ioctl_t *ioctl_ptr)
{
int ret;
+
if ((ioctl_ptr->ioctl_ptr == NULL) || (ioctl_ptr->len == 0)) {
pr_err("%s: Wrong ioctl_ptr %pK / len %zu\n", __func__,
ioctl_ptr, ioctl_ptr->len);
@@ -2758,14 +2807,15 @@ static int msm_cpp_validate_input(unsigned int cmd, void *arg,
break;
default: {
if (ioctl_ptr == NULL) {
- pr_err("Wrong ioctl_ptr for cmd %u\n", cmd);
+ pr_err("Wrong ioctl_ptr %pK for cmd %u\n",
+ ioctl_ptr, cmd);
return -EINVAL;
}
*ioctl_ptr = arg;
if ((*ioctl_ptr == NULL) ||
- (*ioctl_ptr)->ioctl_ptr == NULL) {
- pr_err("Error invalid ioctl argument cmd %u", cmd);
+ ((*ioctl_ptr)->ioctl_ptr == NULL)) {
+ pr_err("Wrong arg %pK for cmd %u\n", arg, cmd);
return -EINVAL;
}
break;
@@ -3007,7 +3057,7 @@ long msm_cpp_subdev_ioctl(struct v4l2_subdev *sd,
mutex_unlock(&cpp_dev->mutex);
return -EINVAL;
}
- if (VIDIOC_MSM_CPP_DELETE_STREAM_BUFF == cmd) {
+ if (cmd == VIDIOC_MSM_CPP_DELETE_STREAM_BUFF) {
for (j = 0; j < k_stream_buff_info.num_buffs; j++) {
msm_cpp_dequeue_buff(cpp_dev, buff_queue_info,
k_stream_buff_info.buffer_info[j].index,
@@ -3030,9 +3080,9 @@ STREAM_BUFF_END:
case VIDIOC_MSM_CPP_DEQUEUE_STREAM_BUFF_INFO: {
uint32_t identity;
struct msm_cpp_buff_queue_info_t *buff_queue_info;
+
CPP_DBG("VIDIOC_MSM_CPP_DEQUEUE_STREAM_BUFF_INFO\n");
- if ((ioctl_ptr->len == 0) ||
- (ioctl_ptr->len > sizeof(uint32_t))) {
+ if (ioctl_ptr->len != sizeof(uint32_t)) {
mutex_unlock(&cpp_dev->mutex);
return -EINVAL;
}
@@ -3079,6 +3129,7 @@ STREAM_BUFF_END:
struct msm_device_queue *queue = &cpp_dev->eventData_q;
struct msm_queue_cmd *event_qcmd;
struct msm_cpp_frame_info_t *process_frame;
+
CPP_DBG("VIDIOC_MSM_CPP_GET_EVENTPAYLOAD\n");
event_qcmd = msm_dequeue(queue, list_eventdata, POP_FRONT);
if (!event_qcmd) {
@@ -3107,6 +3158,7 @@ STREAM_BUFF_END:
uint32_t msm_cpp_core_clk_idx;
struct msm_cpp_clock_settings_t clock_settings;
unsigned long clock_rate = 0;
+
CPP_DBG("VIDIOC_MSM_CPP_SET_CLOCK\n");
if (ioctl_ptr->len == 0) {
pr_err("ioctl_ptr->len is 0\n");
@@ -3185,6 +3237,7 @@ STREAM_BUFF_END:
break;
case VIDIOC_MSM_CPP_QUEUE_BUF: {
struct msm_pproc_queue_buf_info queue_buf_info;
+
CPP_DBG("VIDIOC_MSM_CPP_QUEUE_BUF\n");
if (ioctl_ptr->len != sizeof(struct msm_pproc_queue_buf_info)) {
@@ -3267,9 +3320,27 @@ STREAM_BUFF_END:
break;
case VIDIOC_MSM_CPP_IOMMU_ATTACH: {
if (cpp_dev->iommu_state == CPP_IOMMU_STATE_DETACHED) {
- rc = cam_smmu_ops(cpp_dev->iommu_hdl, CAM_SMMU_ATTACH);
+ struct msm_camera_smmu_attach_type cpp_attach_info;
+
+ memset(&cpp_attach_info, 0, sizeof(cpp_attach_info));
+ rc = msm_cpp_copy_from_ioctl_ptr(&cpp_attach_info,
+ ioctl_ptr);
if (rc < 0) {
- pr_err("%s:%dError iommu_attach_device failed\n",
+ ERR_COPY_FROM_USER();
+ return -EINVAL;
+ }
+
+ cpp_dev->security_mode = cpp_attach_info.attach;
+
+ if (cpp_dev->security_mode == SECURE_MODE) {
+ rc = cam_smmu_ops(cpp_dev->iommu_hdl,
+ CAM_SMMU_ATTACH_SEC_CPP);
+ } else {
+ rc = cam_smmu_ops(cpp_dev->iommu_hdl,
+ CAM_SMMU_ATTACH);
+ }
+ if (rc < 0) {
+ pr_err("%s:%diommu_attach_device failed\n",
__func__, __LINE__);
rc = -EINVAL;
break;
@@ -3285,10 +3356,28 @@ STREAM_BUFF_END:
case VIDIOC_MSM_CPP_IOMMU_DETACH: {
if ((cpp_dev->iommu_state == CPP_IOMMU_STATE_ATTACHED) &&
(cpp_dev->stream_cnt == 0)) {
- rc = cam_smmu_ops(cpp_dev->iommu_hdl, CAM_SMMU_DETACH);
+
+ struct msm_camera_smmu_attach_type cpp_attach_info;
+
+ memset(&cpp_attach_info, 0, sizeof(cpp_attach_info));
+ rc = msm_cpp_copy_from_ioctl_ptr(&cpp_attach_info,
+ ioctl_ptr);
if (rc < 0) {
- pr_err("%s:%dError iommu atach failed\n",
- __func__, __LINE__);
+ ERR_COPY_FROM_USER();
+ return -EINVAL;
+ }
+
+ cpp_dev->security_mode = cpp_attach_info.attach;
+
+ if (cpp_dev->security_mode == SECURE_MODE)
+ rc = cam_smmu_ops(cpp_dev->iommu_hdl,
+ CAM_SMMU_DETACH_SEC_CPP);
+ else
+ rc = cam_smmu_ops(cpp_dev->iommu_hdl,
+ CAM_SMMU_DETACH);
+ if (rc < 0) {
+ pr_err("%s:%diommu detach failed\n", __func__,
+ __LINE__);
rc = -EINVAL;
break;
}
@@ -3368,6 +3457,7 @@ static long msm_cpp_subdev_do_ioctl(
struct cpp_device *cpp_dev = v4l2_get_subdevdata(sd);
struct msm_camera_v4l2_ioctl_t *ioctl_ptr = arg;
struct msm_cpp_frame_info_t inst_info;
+
memset(&inst_info, 0, sizeof(struct msm_cpp_frame_info_t));
for (i = 0; i < MAX_ACTIVE_CPP_INSTANCE; i++) {
if (cpp_dev->cpp_subscribe_list[i].vfh == vfh) {
@@ -3736,6 +3826,7 @@ static long msm_cpp_subdev_fops_compat_ioctl(struct file *file,
struct msm_cpp_frame_info32_t inst_info;
struct v4l2_fh *vfh = NULL;
uint32_t i;
+
vfh = file->private_data;
memset(&inst_info, 0, sizeof(struct msm_cpp_frame_info32_t));
for (i = 0; i < MAX_ACTIVE_CPP_INSTANCE; i++) {
@@ -3979,6 +4070,7 @@ static int msm_cpp_update_gdscr_status(struct cpp_device *cpp_dev,
{
int rc = 0;
int value = 0;
+
if (!cpp_dev) {
pr_err("%s: cpp device invalid\n", __func__);
rc = -EINVAL;
@@ -4081,6 +4173,7 @@ static int cpp_probe(struct platform_device *pdev)
struct cpp_device *cpp_dev;
int rc = 0;
int i = 0;
+
CPP_DBG("E");
cpp_dev = kzalloc(sizeof(struct cpp_device), GFP_KERNEL);
@@ -4252,6 +4345,8 @@ static int cpp_probe(struct platform_device *pdev)
cpp_timer_callback, (unsigned long)&cpp_timer);
cpp_dev->fw_name_bin = NULL;
cpp_dev->max_timeout_trial_cnt = MSM_CPP_MAX_TIMEOUT_TRIAL;
+
+
if (rc == 0)
CPP_DBG("SUCCESS.");
else
@@ -4294,6 +4389,7 @@ static int cpp_device_remove(struct platform_device *dev)
{
struct v4l2_subdev *sd = platform_get_drvdata(dev);
struct cpp_device *cpp_dev;
+
if (!sd) {
pr_err("%s: Subdevice is NULL\n", __func__);
return 0;
@@ -4304,6 +4400,7 @@ static int cpp_device_remove(struct platform_device *dev)
pr_err("%s: cpp device is NULL\n", __func__);
return 0;
}
+
if (cpp_dev->fw) {
release_firmware(cpp_dev->fw);
cpp_dev->fw = NULL;
@@ -4367,6 +4464,7 @@ DEFINE_SIMPLE_ATTRIBUTE(cpp_debugfs_error, NULL,
static int msm_cpp_enable_debugfs(struct cpp_device *cpp_dev)
{
struct dentry *debugfs_base;
+
debugfs_base = debugfs_create_dir("msm_cpp", NULL);
if (!debugfs_base)
return -ENOMEM;
diff --git a/drivers/media/platform/msm/camera_v2/pproc/cpp/msm_cpp.h b/drivers/media/platform/msm/camera_v2/pproc/cpp/msm_cpp.h
index d5abe0202717..f46cc10cef46 100644
--- a/drivers/media/platform/msm/camera_v2/pproc/cpp/msm_cpp.h
+++ b/drivers/media/platform/msm/camera_v2/pproc/cpp/msm_cpp.h
@@ -169,6 +169,7 @@ struct msm_cpp_buff_queue_info_t {
uint32_t used;
uint16_t session_id;
uint16_t stream_id;
+ enum smmu_attach_mode security_mode;
struct list_head vb2_buff_head;
struct list_head native_buff_head;
};
@@ -234,6 +235,8 @@ struct cpp_device {
uint32_t min_clk_rate;
int iommu_hdl;
+ struct ion_client *ion_client;
+ enum smmu_attach_mode security_mode;
/* Reusing proven tasklet from msm isp */
atomic_t irq_cnt;
uint8_t taskletq_idx;
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 b1c23823c122..f113bdc5de01 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
@@ -115,15 +115,16 @@ static int32_t msm_cci_set_clk_param(struct cci_device *cci_dev,
enum cci_i2c_master_t master = c_ctrl->cci_info->cci_i2c_master;
enum i2c_freq_mode_t i2c_freq_mode = c_ctrl->cci_info->i2c_freq_mode;
- clk_params = &cci_dev->cci_clk_params[i2c_freq_mode];
-
if ((i2c_freq_mode >= I2C_MAX_MODES) || (i2c_freq_mode < 0)) {
pr_err("%s:%d invalid i2c_freq_mode = %d",
__func__, __LINE__, i2c_freq_mode);
return -EINVAL;
}
+
if (cci_dev->i2c_freq_mode[master] == i2c_freq_mode)
return 0;
+
+ clk_params = &cci_dev->cci_clk_params[i2c_freq_mode];
if (MASTER_0 == master) {
msm_camera_io_w_mb(clk_params->hw_thigh << 16 |
clk_params->hw_tlow,
@@ -1196,6 +1197,13 @@ static uint32_t *msm_cci_get_clk_rates(struct cci_device *cci_dev,
struct msm_cci_clk_params_t *clk_params = NULL;
enum i2c_freq_mode_t i2c_freq_mode = c_ctrl->cci_info->i2c_freq_mode;
struct device_node *of_node = cci_dev->pdev->dev.of_node;
+
+ if ((i2c_freq_mode >= I2C_MAX_MODES) || (i2c_freq_mode < 0)) {
+ pr_err("%s:%d invalid i2c_freq_mode %d\n",
+ __func__, __LINE__, i2c_freq_mode);
+ return NULL;
+ }
+
clk_params = &cci_dev->cci_clk_params[i2c_freq_mode];
cci_clk_src = clk_params->cci_clk_src;
diff --git a/drivers/media/platform/msm/sde/rotator/sde_rotator_core.c b/drivers/media/platform/msm/sde/rotator/sde_rotator_core.c
index 0d8c6cb8f3f3..dc5a5a0dc851 100644
--- a/drivers/media/platform/msm/sde/rotator/sde_rotator_core.c
+++ b/drivers/media/platform/msm/sde/rotator/sde_rotator_core.c
@@ -237,7 +237,7 @@ static void sde_rotator_set_clk_rate(struct sde_rot_mgr *mgr,
clk_rate = clk_round_rate(clk, rate);
if (IS_ERR_VALUE(clk_rate)) {
SDEROT_ERR("unable to round rate err=%ld\n", clk_rate);
- } else if (clk_rate != clk_get_rate(clk)) {
+ } else {
ret = clk_set_rate(clk, clk_rate);
if (IS_ERR_VALUE(ret))
SDEROT_ERR("clk_set_rate failed, err:%d\n",
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 4e86a3ff820d..eaf35733b38a 100644
--- a/drivers/media/platform/msm/sde/rotator/sde_rotator_r3.c
+++ b/drivers/media/platform/msm/sde/rotator/sde_rotator_r3.c
@@ -2013,15 +2013,18 @@ static int sde_hw_rotator_validate_entry(struct sde_rot_mgr *mgr,
}
}
- fmt = sde_get_format_params(item->output.format);
- /* Tiled format downscale support not applied to AYUV tiled */
- if (sde_mdp_is_tilea5x_format(fmt) && (entry->dnsc_factor_h > 4)) {
- SDEROT_DBG("max downscale for tiled format is 4\n");
+ fmt = sde_get_format_params(item->input.format);
+ /*
+ * Rotator downscale support max 4 times for UBWC format and
+ * max 2 times for TP10/TP10_UBWC format
+ */
+ if (sde_mdp_is_ubwc_format(fmt) && (entry->dnsc_factor_h > 4)) {
+ SDEROT_DBG("max downscale for UBWC format is 4\n");
ret = -EINVAL;
goto dnsc_err;
}
- if (sde_mdp_is_ubwc_format(fmt) && (entry->dnsc_factor_h > 2)) {
- SDEROT_DBG("downscale with ubwc cannot be more than 2\n");
+ if (sde_mdp_is_tp10_format(fmt) && (entry->dnsc_factor_h > 2)) {
+ SDEROT_DBG("downscale with TP10 cannot be more than 2\n");
ret = -EINVAL;
}
goto dnsc_err;
@@ -2076,6 +2079,7 @@ static ssize_t sde_hw_rotator_show_caps(struct sde_rot_mgr *mgr,
struct device_attribute *attr, char *buf, ssize_t len)
{
struct sde_hw_rotator *hw_data;
+ struct sde_rot_data_type *mdata = sde_rot_get_mdata();
int cnt = 0;
if (!mgr || !buf)
@@ -2087,6 +2091,10 @@ static ssize_t sde_hw_rotator_show_caps(struct sde_rot_mgr *mgr,
(cnt += scnprintf(buf + cnt, len - cnt, fmt, ##__VA_ARGS__))
/* insert capabilities here */
+ if (test_bit(SDE_CAPS_R3_1P5_DOWNSCALE, mdata->sde_caps_map))
+ SPRINT("min_downscale=1.5\n");
+ else
+ SPRINT("min_downscale=2.0\n");
#undef SPRINT
return cnt;
diff --git a/drivers/media/platform/msm/vidc/governors/msm_vidc_table_gov.c b/drivers/media/platform/msm/vidc/governors/msm_vidc_table_gov.c
index dded8a25961a..98d9eb733371 100644
--- a/drivers/media/platform/msm/vidc/governors/msm_vidc_table_gov.c
+++ b/drivers/media/platform/msm/vidc/governors/msm_vidc_table_gov.c
@@ -24,6 +24,7 @@ enum bus_profile {
VIDC_BUS_PROFILE_NORMAL = BIT(0),
VIDC_BUS_PROFILE_LOW = BIT(1),
VIDC_BUS_PROFILE_UBWC = BIT(2),
+ VIDC_BUS_PROFILE_UBWC_10_BIT = BIT(3),
};
struct bus_profile_entry {
@@ -53,7 +54,7 @@ static int __get_bus_freq(struct msm_vidc_bus_table_gov *gov,
load = NUM_MBS_PER_SEC(data->width, data->height, data->fps);
sess_type = VIDC_VOTE_DATA_SESSION_VAL(data->codec, data->domain);
- /* check if ubwc bus profile is present */
+ /* check if appropriate bus profile is present */
for (i = 0; i < gov->count; i++) {
entry = &gov->bus_prof_entries[i];
if (!entry->bus_table || !entry->bus_table_size)
@@ -119,18 +120,23 @@ static int msm_vidc_table_get_target_freq(struct devfreq *dev,
}
profile = VIDC_BUS_PROFILE_NORMAL;
- if (data->color_formats[0] == HAL_COLOR_FORMAT_NV12_TP10_UBWC ||
- data->color_formats[0] == HAL_COLOR_FORMAT_NV12_UBWC)
+ if (data->color_formats[0] == HAL_COLOR_FORMAT_NV12_UBWC)
profile = VIDC_BUS_PROFILE_UBWC;
+ else if (data->color_formats[0] ==
+ HAL_COLOR_FORMAT_NV12_TP10_UBWC)
+ profile = VIDC_BUS_PROFILE_UBWC_10_BIT;
freq = __get_bus_freq(gov, data, profile);
/*
* chose frequency from normal profile
* if specific profile frequency was not found.
*/
- if (!freq)
+ if (!freq) {
+ dprintk(VIDC_WARN,
+ "appropriate bus table not found, voting with Normal Profile\n");
freq = __get_bus_freq(gov, data,
VIDC_BUS_PROFILE_NORMAL);
+ }
*frequency += (unsigned long)freq;
@@ -260,6 +266,8 @@ static int msm_vidc_load_bus_table(struct platform_device *pdev,
entry->profile = VIDC_BUS_PROFILE_LOW;
else if (of_find_property(child_node, "qcom,ubwc-mode", NULL))
entry->profile = VIDC_BUS_PROFILE_UBWC;
+ else if (of_find_property(child_node, "qcom,ubwc-10bit", NULL))
+ entry->profile = VIDC_BUS_PROFILE_UBWC_10_BIT;
else
entry->profile = VIDC_BUS_PROFILE_NORMAL;
diff --git a/drivers/media/platform/msm/vidc/msm_vidc.c b/drivers/media/platform/msm/vidc/msm_vidc.c
index c4d06b658b30..7bc1fe1af26d 100644
--- a/drivers/media/platform/msm/vidc/msm_vidc.c
+++ b/drivers/media/platform/msm/vidc/msm_vidc.c
@@ -1320,11 +1320,6 @@ int msm_vidc_destroy(struct msm_vidc_inst *inst)
msm_comm_ctrl_deinit(inst);
- mutex_destroy(&inst->sync_lock);
- mutex_destroy(&inst->bufq[CAPTURE_PORT].lock);
- mutex_destroy(&inst->bufq[OUTPUT_PORT].lock);
- mutex_destroy(&inst->lock);
-
DEINIT_MSM_VIDC_LIST(&inst->pendingq);
DEINIT_MSM_VIDC_LIST(&inst->scratchbufs);
DEINIT_MSM_VIDC_LIST(&inst->persistbufs);
@@ -1338,6 +1333,11 @@ int msm_vidc_destroy(struct msm_vidc_inst *inst)
for (i = 0; i < MAX_PORT_NUM; i++)
vb2_queue_release(&inst->bufq[i].vb2_bufq);
+ mutex_destroy(&inst->sync_lock);
+ mutex_destroy(&inst->bufq[CAPTURE_PORT].lock);
+ mutex_destroy(&inst->bufq[OUTPUT_PORT].lock);
+ mutex_destroy(&inst->lock);
+
pr_info(VIDC_DBG_TAG "Closed video instance: %pK\n",
VIDC_MSG_PRIO2STRING(VIDC_INFO), inst);
kfree(inst);
diff --git a/drivers/media/platform/msm/vidc/msm_vidc_common.c b/drivers/media/platform/msm/vidc/msm_vidc_common.c
index fa2ad1754e77..73c52841fd34 100644
--- a/drivers/media/platform/msm/vidc/msm_vidc_common.c
+++ b/drivers/media/platform/msm/vidc/msm_vidc_common.c
@@ -298,6 +298,11 @@ static int msm_comm_get_mbs_per_sec(struct msm_vidc_inst *inst)
rc = msm_comm_g_ctrl(inst, &ctrl);
if (!rc && ctrl.value) {
fps = (ctrl.value >> 16) ? ctrl.value >> 16 : 1;
+ /*
+ * Check if operating rate is less than fps.
+ * If Yes, then use fps to scale clocks
+ */
+ fps = fps > inst->prop.fps ? fps : inst->prop.fps;
return max(output_port_mbs, capture_port_mbs) * fps;
} else
return max(output_port_mbs, capture_port_mbs) * inst->prop.fps;
@@ -1666,7 +1671,7 @@ static void handle_sys_error(enum hal_command_response cmd, void *data)
*/
mutex_lock(&core->lock);
- inst = list_first_entry(&core->instances,
+ inst = list_first_entry_or_null(&core->instances,
struct msm_vidc_inst, list);
mutex_unlock(&core->lock);
@@ -5359,10 +5364,10 @@ static void msm_comm_print_debug_info(struct msm_vidc_inst *inst)
dprintk(VIDC_ERR, "Venus core frequency = %lu",
msm_comm_get_clock_rate(core));
+ mutex_lock(&core->lock);
dprintk(VIDC_ERR, "Printing instance info that caused Error\n");
msm_comm_print_inst_info(inst);
dprintk(VIDC_ERR, "Printing remaining instances info\n");
- mutex_lock(&core->lock);
list_for_each_entry(temp, &core->instances, list) {
/* inst already printed above. Hence don't repeat.*/
if (temp == inst)
diff --git a/drivers/media/platform/msm/vidc/venus_hfi.c b/drivers/media/platform/msm/vidc/venus_hfi.c
index 787ee43ccbd2..0055e22b40b4 100644
--- a/drivers/media/platform/msm/vidc/venus_hfi.c
+++ b/drivers/media/platform/msm/vidc/venus_hfi.c
@@ -75,7 +75,7 @@ const struct msm_vidc_gov_data DEFAULT_BUS_VOTE = {
.imem_size = 0,
};
-const int max_packets = 250;
+const int max_packets = 1000;
static void venus_hfi_pm_handler(struct work_struct *work);
static DECLARE_DELAYED_WORK(venus_hfi_pm_work, venus_hfi_pm_handler);
@@ -3576,6 +3576,7 @@ static void venus_hfi_core_work_handler(struct work_struct *work)
struct venus_hfi_device *device = list_first_entry(
&hal_ctxt.dev_head, struct venus_hfi_device, list);
int num_responses = 0, i = 0;
+ u32 intr_status;
mutex_lock(&device->lock);
@@ -3601,10 +3602,9 @@ static void venus_hfi_core_work_handler(struct work_struct *work)
num_responses = __response_handler(device);
err_no_work:
- /* We need re-enable the irq which was disabled in ISR handler */
- if (!(device->intr_status & VIDC_WRAPPER_INTR_STATUS_A2HWD_BMSK))
- enable_irq(device->hal_data->irq);
+ /* Keep the interrupt status before releasing device lock */
+ intr_status = device->intr_status;
mutex_unlock(&device->lock);
/*
@@ -3619,6 +3619,10 @@ err_no_work:
device->callback(r->response_type, &r->response);
}
+ /* We need re-enable the irq which was disabled in ISR handler */
+ if (!(intr_status & VIDC_WRAPPER_INTR_STATUS_A2HWD_BMSK))
+ enable_irq(device->hal_data->irq);
+
/*
* XXX: Don't add any code beyond here. Reacquiring locks after release
* it above doesn't guarantee the atomicity that we're aiming for.
@@ -4548,7 +4552,7 @@ static struct venus_hfi_device *__add_device(u32 device_id,
}
hdevice->response_pkt = kmalloc_array(max_packets,
- sizeof(*hdevice->response_pkt), GFP_TEMPORARY);
+ sizeof(*hdevice->response_pkt), GFP_KERNEL);
if (!hdevice->response_pkt) {
dprintk(VIDC_ERR, "failed to allocate response_pkt\n");
goto err_cleanup;
diff --git a/drivers/media/tuners/tuner-xc2028.c b/drivers/media/tuners/tuner-xc2028.c
index 4e941f00b600..082ff5608455 100644
--- a/drivers/media/tuners/tuner-xc2028.c
+++ b/drivers/media/tuners/tuner-xc2028.c
@@ -1403,11 +1403,12 @@ static int xc2028_set_config(struct dvb_frontend *fe, void *priv_cfg)
* in order to avoid troubles during device release.
*/
kfree(priv->ctrl.fname);
+ priv->ctrl.fname = NULL;
memcpy(&priv->ctrl, p, sizeof(priv->ctrl));
if (p->fname) {
priv->ctrl.fname = kstrdup(p->fname, GFP_KERNEL);
if (priv->ctrl.fname == NULL)
- rc = -ENOMEM;
+ return -ENOMEM;
}
/*
diff --git a/drivers/misc/hdcp.c b/drivers/misc/hdcp.c
index 56ddf8467d16..011d5bd88d90 100644
--- a/drivers/misc/hdcp.c
+++ b/drivers/misc/hdcp.c
@@ -65,7 +65,8 @@
#define REPEATER_AUTH_SEND_ACK_MESSAGE_ID 15
#define REPEATER_AUTH_STREAM_MANAGE_MESSAGE_ID 16
#define REPEATER_AUTH_STREAM_READY_MESSAGE_ID 17
-#define HDCP2P2_MAX_MESSAGES 18
+#define SKE_SEND_TYPE_ID 18
+#define HDCP2P2_MAX_MESSAGES 19
#define HDCP1_SET_KEY_MESSAGE_ID 202
#define HDCP1_SET_ENC_MESSAGE_ID 205
@@ -94,7 +95,7 @@
* minimum wait as per standard is 200 ms. keep it 300 ms
* to be on safe side.
*/
-#define SLEEP_SET_HW_KEY_MS 300
+#define SLEEP_SET_HW_KEY_MS 220
#define QSEECOM_ALIGN_SIZE 0x40
#define QSEECOM_ALIGN_MASK (QSEECOM_ALIGN_SIZE - 1)
@@ -187,6 +188,9 @@ static const struct hdcp_msg_data hdcp_msg_lookup[HDCP2P2_MAX_MESSAGES] = {
[SKE_SEND_EKS_MESSAGE_ID] = { 2,
{ {"Edkey_ks", 0x69318, 16}, {"riv", 0x69328, 8} },
0 },
+ [SKE_SEND_TYPE_ID] = { 1,
+ { {"type", 0x69494, 1} },
+ 0 },
[REPEATER_AUTH_SEND_RECEIVERID_LIST_MESSAGE_ID] = { 4,
{ {"RxInfo", 0x69330, 2}, {"seq_num_V", 0x69332, 3},
{"V'", 0x69335, 16}, {"ridlist", 0x69345, 155} },
@@ -499,8 +503,10 @@ struct hdcp_lib_handle {
uint32_t tz_ctxhandle;
uint32_t hdcp_timeout;
uint32_t timeout_left;
+ uint32_t wait_timeout;
bool no_stored_km_flag;
bool feature_supported;
+ bool authenticated;
void *client_ctx;
struct hdcp_client_ops *client_ops;
struct mutex msg_lock;
@@ -521,7 +527,7 @@ struct hdcp_lib_handle {
enum hdcp_device_type device_type;
struct task_struct *thread;
- struct completion topo_wait;
+ struct completion poll_wait;
struct kthread_worker worker;
struct kthread_work wk_init;
@@ -529,7 +535,7 @@ struct hdcp_lib_handle {
struct kthread_work wk_msg_recvd;
struct kthread_work wk_timeout;
struct kthread_work wk_clean;
- struct kthread_work wk_topology;
+ struct kthread_work wk_wait;
struct kthread_work wk_stream;
int (*hdcp_app_init)(struct hdcp_lib_handle *handle);
@@ -574,6 +580,7 @@ static const char *hdcp_lib_message_name(int msg_id)
{15, "REPEATER_AUTH_SEND_ACK"},
{16, "REPEATER_AUTH_STREAM_MANAGE"},
{17, "REPEATER_AUTH_STREAM_READY"},
+ {18, "SKE_SEND_TYPE_ID"},
};
int i;
@@ -612,8 +619,14 @@ static int hdcp_lib_get_next_message(struct hdcp_lib_handle *handle,
case LC_SEND_L_PRIME_MESSAGE_ID:
return SKE_SEND_EKS_MESSAGE_ID;
case SKE_SEND_EKS_MESSAGE_ID:
+ if (!handle->repeater_flag)
+ return SKE_SEND_TYPE_ID;
+ case SKE_SEND_TYPE_ID:
case REPEATER_AUTH_STREAM_READY_MESSAGE_ID:
case REPEATER_AUTH_SEND_ACK_MESSAGE_ID:
+ if (!handle->repeater_flag)
+ return INVALID_MESSAGE_ID;
+
if (data->cmd == HDMI_HDCP_WKUP_CMD_SEND_MESSAGE)
return REPEATER_AUTH_STREAM_MANAGE_MESSAGE_ID;
else
@@ -628,6 +641,33 @@ static int hdcp_lib_get_next_message(struct hdcp_lib_handle *handle,
}
}
+static void hdcp_lib_wait_for_response(struct hdcp_lib_handle *handle,
+ struct hdmi_hdcp_wakeup_data *data)
+{
+ switch (handle->last_msg) {
+ case AKE_SEND_H_PRIME_MESSAGE_ID:
+ if (handle->no_stored_km_flag)
+ handle->wait_timeout = HZ;
+ else
+ handle->wait_timeout = HZ / 4;
+ break;
+ case AKE_SEND_PAIRING_INFO_MESSAGE_ID:
+ handle->wait_timeout = HZ / 4;
+ break;
+ case REPEATER_AUTH_SEND_RECEIVERID_LIST_MESSAGE_ID:
+ if (!handle->authenticated)
+ handle->wait_timeout = HZ * 3;
+ else
+ handle->wait_timeout = 0;
+ break;
+ default:
+ handle->wait_timeout = 0;
+ }
+
+ if (handle->wait_timeout)
+ queue_kthread_work(&handle->worker, &handle->wk_wait);
+}
+
static void hdcp_lib_wakeup_client(struct hdcp_lib_handle *handle,
struct hdmi_hdcp_wakeup_data *data)
{
@@ -639,43 +679,42 @@ static void hdcp_lib_wakeup_client(struct hdcp_lib_handle *handle,
data->abort_mask = REAUTH_REQ | LINK_INTEGRITY_FAILURE;
- if (data->cmd == HDMI_HDCP_WKUP_CMD_SEND_MESSAGE ||
- data->cmd == HDMI_HDCP_WKUP_CMD_RECV_MESSAGE ||
- data->cmd == HDMI_HDCP_WKUP_CMD_LINK_POLL) {
+ if (data->cmd == HDMI_HDCP_WKUP_CMD_RECV_MESSAGE ||
+ data->cmd == HDMI_HDCP_WKUP_CMD_LINK_POLL)
handle->last_msg = hdcp_lib_get_next_message(handle, data);
+ if (handle->last_msg != INVALID_MESSAGE_ID &&
+ data->cmd != HDMI_HDCP_WKUP_CMD_STATUS_SUCCESS &&
+ data->cmd != HDMI_HDCP_WKUP_CMD_STATUS_FAILED) {
+ u32 msg_num, rx_status;
+ const struct hdcp_msg_part *msg;
+
pr_debug("lib->client: %s (%s)\n",
hdmi_hdcp_cmd_to_str(data->cmd),
hdcp_lib_message_name(handle->last_msg));
- if (handle->last_msg > INVALID_MESSAGE_ID &&
- handle->last_msg < HDCP2P2_MAX_MESSAGES) {
- u32 msg_num, rx_status;
- const struct hdcp_msg_part *msg;
-
- data->message_data = &hdcp_msg_lookup[handle->last_msg];
+ data->message_data = &hdcp_msg_lookup[handle->last_msg];
- msg_num = data->message_data->num_messages;
- msg = data->message_data->messages;
- rx_status = data->message_data->rx_status;
+ msg_num = data->message_data->num_messages;
+ msg = data->message_data->messages;
+ rx_status = data->message_data->rx_status;
- pr_debug("rxstatus 0x%x\n", rx_status);
- pr_debug("%10s | %6s | %4s\n", "name", "offset", "len");
+ pr_debug("%10s | %6s | %4s\n", "name", "offset", "len");
- for (i = 0; i < msg_num; i++)
- pr_debug("%10s | %6x | %4d\n",
- msg[i].name, msg[i].offset,
- msg[i].length);
- }
+ for (i = 0; i < msg_num; i++)
+ pr_debug("%10s | %6x | %4d\n",
+ msg[i].name, msg[i].offset,
+ msg[i].length);
} else {
- pr_debug("lib->client: %s\n",
- hdmi_hdcp_cmd_to_str(data->cmd));
+ pr_debug("lib->client: %s\n", hdmi_hdcp_cmd_to_str(data->cmd));
}
rc = handle->client_ops->wakeup(data);
if (rc)
pr_err("error sending %s to client\n",
hdmi_hdcp_cmd_to_str(data->cmd));
+
+ hdcp_lib_wait_for_response(handle, data);
}
static inline void hdcp_lib_send_message(struct hdcp_lib_handle *handle)
@@ -1286,6 +1325,8 @@ static int hdcp_lib_txmtr_init_legacy(struct hdcp_lib_handle *handle)
hdcp_lib_message_name((int)rsp_buf->message[0]),
jiffies_to_msecs(jiffies));
+ handle->last_msg = (int)rsp_buf->message[0];
+
/* send the response to HDMI driver */
memset(handle->listener_buf, 0, MAX_TX_MESSAGE_SIZE);
memcpy(handle->listener_buf, (unsigned char *)rsp_buf->message,
@@ -1404,6 +1445,8 @@ static int hdcp_lib_start_auth(struct hdcp_lib_handle *handle)
hdcp_lib_message_name((int)rsp_buf->message[0]),
jiffies_to_msecs(jiffies));
+ handle->last_msg = (int)rsp_buf->message[0];
+
/* send the response to HDMI driver */
memset(handle->listener_buf, 0, MAX_TX_MESSAGE_SIZE);
memcpy(handle->listener_buf, (unsigned char *)rsp_buf->message,
@@ -1470,6 +1513,8 @@ static void hdcp_lib_stream(struct hdcp_lib_handle *handle)
pr_debug("message received from TZ: %s\n",
hdcp_lib_message_name((int)rsp_buf->msg[0]));
+ handle->last_msg = (int)rsp_buf->msg[0];
+
memset(handle->listener_buf, 0, MAX_TX_MESSAGE_SIZE);
memcpy(handle->listener_buf, (unsigned char *)rsp_buf->msg,
rsp_buf->msglen);
@@ -1550,11 +1595,11 @@ static void hdcp_lib_check_worker_status(struct hdcp_lib_handle *handle)
if (handle->worker.current_work == &handle->wk_clean)
pr_debug("clean work executing\n");
- if (!list_empty(&handle->wk_topology.node))
- pr_debug("topology work queued\n");
+ if (!list_empty(&handle->wk_wait.node))
+ pr_debug("wait work queued\n");
- if (handle->worker.current_work == &handle->wk_topology)
- pr_debug("topology work executing\n");
+ if (handle->worker.current_work == &handle->wk_wait)
+ pr_debug("wait work executing\n");
if (!list_empty(&handle->wk_stream.node))
pr_debug("stream work queued\n");
@@ -1613,7 +1658,7 @@ static void hdcp_lib_update_exec_type(void *ctx, bool tethered)
mutex_unlock(&handle->wakeup_mutex);
}
-static int hdcp_lib_wakeup(struct hdcp_lib_wakeup_data *data)
+static int hdcp_lib_wakeup_thread(struct hdcp_lib_wakeup_data *data)
{
struct hdcp_lib_handle *handle;
int rc = 0;
@@ -1630,8 +1675,9 @@ static int hdcp_lib_wakeup(struct hdcp_lib_wakeup_data *data)
handle->wakeup_cmd = data->cmd;
handle->timeout_left = data->timeout;
- pr_debug("client->lib: %s\n",
- hdcp_lib_cmd_to_str(handle->wakeup_cmd));
+ pr_debug("client->lib: %s (%s)\n",
+ hdcp_lib_cmd_to_str(data->cmd),
+ hdcp_lib_message_name(handle->last_msg));
rc = hdcp_lib_check_valid_state(handle);
if (rc)
@@ -1655,8 +1701,8 @@ static int hdcp_lib_wakeup(struct hdcp_lib_wakeup_data *data)
}
mutex_unlock(&handle->msg_lock);
- if (!completion_done(&handle->topo_wait))
- complete_all(&handle->topo_wait);
+ if (!completion_done(&handle->poll_wait))
+ complete_all(&handle->poll_wait);
switch (handle->wakeup_cmd) {
case HDCP_LIB_WKUP_CMD_START:
@@ -1719,22 +1765,30 @@ static void hdcp_lib_msg_sent(struct hdcp_lib_handle *handle)
cdata.context = handle->client_ctx;
switch (handle->last_msg_sent) {
- case SKE_SEND_EKS_MESSAGE_ID:
- if (handle->repeater_flag) {
- if (!atomic_read(&handle->hdcp_off))
- queue_kthread_work(&handle->worker,
- &handle->wk_topology);
- }
-
+ case SKE_SEND_TYPE_ID:
if (!hdcp_lib_enable_encryption(handle)) {
+ handle->authenticated = true;
+
cdata.cmd = HDMI_HDCP_WKUP_CMD_STATUS_SUCCESS;
hdcp_lib_wakeup_client(handle, &cdata);
+ }
+ /* poll for link check */
+ cdata.cmd = HDMI_HDCP_WKUP_CMD_LINK_POLL;
+ break;
+ case SKE_SEND_EKS_MESSAGE_ID:
+ if (handle->repeater_flag) {
/* poll for link check */
cdata.cmd = HDMI_HDCP_WKUP_CMD_LINK_POLL;
} else {
- if (!atomic_read(&handle->hdcp_off))
- HDCP_LIB_EXECUTE(clean);
+ memset(handle->listener_buf, 0, MAX_TX_MESSAGE_SIZE);
+ handle->listener_buf[0] = SKE_SEND_TYPE_ID;
+ handle->msglen = 2;
+ cdata.cmd = HDMI_HDCP_WKUP_CMD_SEND_MESSAGE;
+ cdata.send_msg_buf = handle->listener_buf;
+ cdata.send_msg_len = handle->msglen;
+ handle->last_msg = hdcp_lib_get_next_message(handle,
+ &cdata);
}
break;
case REPEATER_AUTH_SEND_ACK_MESSAGE_ID:
@@ -1915,6 +1969,8 @@ static void hdcp_lib_clean(struct hdcp_lib_handle *handle)
return;
}
+ handle->authenticated = false;
+
hdcp_lib_txmtr_deinit(handle);
if (!handle->legacy_app)
hdcp_lib_session_deinit(handle);
@@ -2040,6 +2096,13 @@ static void hdcp_lib_msg_recvd(struct hdcp_lib_handle *handle)
(rc == 0) && (rsp_buf->status == 0)) {
pr_debug("Got Auth_Stream_Ready, nothing sent to rx\n");
+ if (!hdcp_lib_enable_encryption(handle)) {
+ handle->authenticated = true;
+
+ cdata.cmd = HDMI_HDCP_WKUP_CMD_STATUS_SUCCESS;
+ hdcp_lib_wakeup_client(handle, &cdata);
+ }
+
cdata.cmd = HDMI_HDCP_WKUP_CMD_LINK_POLL;
goto exit;
}
@@ -2057,6 +2120,8 @@ static void hdcp_lib_msg_recvd(struct hdcp_lib_handle *handle)
hdcp_lib_message_name((int)rsp_buf->msg[0]),
jiffies_to_msecs(jiffies));
+ handle->last_msg = (int)rsp_buf->msg[0];
+
/* set the flag if response is AKE_No_Stored_km */
if (((int)rsp_buf->msg[0] == AKE_NO_STORED_KM_MESSAGE_ID)) {
pr_debug("Setting no_stored_km_flag\n");
@@ -2101,12 +2166,11 @@ static void hdcp_lib_msg_recvd_work(struct kthread_work *work)
hdcp_lib_msg_recvd(handle);
}
-static void hdcp_lib_topology_work(struct kthread_work *work)
+static void hdcp_lib_wait_work(struct kthread_work *work)
{
u32 timeout;
struct hdcp_lib_handle *handle = container_of(work,
- struct hdcp_lib_handle,
- wk_topology);
+ struct hdcp_lib_handle, wk_wait);
if (!handle) {
pr_err("invalid input\n");
@@ -2123,14 +2187,17 @@ static void hdcp_lib_topology_work(struct kthread_work *work)
return;
}
- reinit_completion(&handle->topo_wait);
- timeout = wait_for_completion_timeout(&handle->topo_wait, HZ * 3);
+ reinit_completion(&handle->poll_wait);
+ timeout = wait_for_completion_timeout(&handle->poll_wait,
+ handle->wait_timeout);
if (!timeout) {
- pr_err("topology receiver id list timeout\n");
+ pr_err("wait timeout\n");
if (!atomic_read(&handle->hdcp_off))
HDCP_LIB_EXECUTE(clean);
}
+
+ handle->wait_timeout = 0;
}
bool hdcp1_check_if_supported_load_app(void)
@@ -2266,7 +2333,7 @@ int hdcp_library_register(struct hdcp_register_data *data)
/* populate ops to be called by client */
data->txmtr_ops->feature_supported = hdcp_lib_client_feature_supported;
- data->txmtr_ops->wakeup = hdcp_lib_wakeup;
+ data->txmtr_ops->wakeup = hdcp_lib_wakeup_thread;
data->txmtr_ops->update_exec_type = hdcp_lib_update_exec_type;
handle = kzalloc(sizeof(*handle), GFP_KERNEL);
@@ -2296,10 +2363,10 @@ int hdcp_library_register(struct hdcp_register_data *data)
init_kthread_work(&handle->wk_msg_recvd, hdcp_lib_msg_recvd_work);
init_kthread_work(&handle->wk_timeout, hdcp_lib_manage_timeout_work);
init_kthread_work(&handle->wk_clean, hdcp_lib_cleanup_work);
- init_kthread_work(&handle->wk_topology, hdcp_lib_topology_work);
+ init_kthread_work(&handle->wk_wait, hdcp_lib_wait_work);
init_kthread_work(&handle->wk_stream, hdcp_lib_query_stream_work);
- init_completion(&handle->topo_wait);
+ init_completion(&handle->poll_wait);
handle->listener_buf = kzalloc(MAX_TX_MESSAGE_SIZE, GFP_KERNEL);
if (!(handle->listener_buf)) {
diff --git a/drivers/misc/qcom/qdsp6v2/Makefile b/drivers/misc/qcom/qdsp6v2/Makefile
index 7006ff4a272f..90a123adbb7f 100644
--- a/drivers/misc/qcom/qdsp6v2/Makefile
+++ b/drivers/misc/qcom/qdsp6v2/Makefile
@@ -1,5 +1,6 @@
-obj-$(CONFIG_MSM_QDSP6V2_CODECS) += aac_in.o qcelp_in.o evrc_in.o amrnb_in.o audio_utils.o
+obj-$(CONFIG_MSM_QDSP6V2_CODECS) += aac_in.o qcelp_in.o evrc_in.o amrnb_in.o g711mlaw_in.o g711alaw_in.o audio_utils.o
obj-$(CONFIG_MSM_QDSP6V2_CODECS) += audio_wma.o audio_wmapro.o audio_aac.o audio_multi_aac.o audio_alac.o audio_ape.o audio_utils_aio.o
obj-$(CONFIG_MSM_QDSP6V2_CODECS) += q6audio_v2.o q6audio_v2_aio.o
+obj-$(CONFIG_MSM_QDSP6V2_CODECS) += audio_g711mlaw.o audio_g711alaw.o
obj-$(CONFIG_MSM_QDSP6V2_CODECS) += audio_mp3.o audio_amrnb.o audio_amrwb.o audio_amrwbplus.o audio_evrc.o audio_qcelp.o amrwb_in.o audio_hwacc_effects.o
obj-$(CONFIG_MSM_ULTRASOUND) += ultrasound/
diff --git a/drivers/misc/qcom/qdsp6v2/audio_amrnb.c b/drivers/misc/qcom/qdsp6v2/audio_amrnb.c
index 78bcdb74af0e..9e4f74bfacd9 100644
--- a/drivers/misc/qcom/qdsp6v2/audio_amrnb.c
+++ b/drivers/misc/qcom/qdsp6v2/audio_amrnb.c
@@ -14,6 +14,9 @@
* GNU General Public License for more details.
*
*/
+
+#include <linux/types.h>
+#include <linux/compat.h>
#include "audio_utils_aio.h"
static struct miscdevice audio_amrnb_misc;
@@ -68,6 +71,52 @@ static long audio_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
return rc;
}
+static long audio_compat_ioctl(struct file *file, unsigned int cmd,
+ unsigned long arg)
+{
+ struct q6audio_aio *audio = file->private_data;
+ int rc = 0;
+
+ switch (cmd) {
+ case AUDIO_START: {
+ pr_debug("%s[%pK]: AUDIO_START session_id[%d]\n", __func__,
+ audio, audio->ac->session);
+ if (audio->feedback == NON_TUNNEL_MODE) {
+ /* Configure PCM output block */
+ rc = q6asm_enc_cfg_blk_pcm(audio->ac,
+ audio->pcm_cfg.sample_rate,
+ audio->pcm_cfg.channel_count);
+ if (rc < 0) {
+ pr_err("%s: pcm output block config failed rc=%d\n",
+ __func__, rc);
+ break;
+ }
+ }
+
+ rc = audio_aio_enable(audio);
+ audio->eos_rsp = 0;
+ audio->eos_flag = 0;
+ if (!rc) {
+ audio->enabled = 1;
+ } else {
+ audio->enabled = 0;
+ pr_err("%s: Audio Start procedure failed rc=%d\n",
+ __func__, rc);
+ break;
+ }
+ pr_debug("AUDIO_START success enable[%d]\n", audio->enabled);
+ if (audio->stopped == 1)
+ audio->stopped = 0;
+ break;
+ }
+ default:
+ pr_debug("%s[%pK]: Calling compat ioctl\n", __func__, audio);
+ rc = audio->codec_compat_ioctl(file, cmd, arg);
+ }
+ return rc;
+}
+
+
static int audio_open(struct inode *inode, struct file *file)
{
struct q6audio_aio *audio = NULL;
@@ -155,6 +204,7 @@ static const struct file_operations audio_amrnb_fops = {
.release = audio_aio_release,
.unlocked_ioctl = audio_ioctl,
.fsync = audio_aio_fsync,
+ .compat_ioctl = audio_compat_ioctl,
};
static struct miscdevice audio_amrnb_misc = {
diff --git a/drivers/misc/qcom/qdsp6v2/audio_amrwb.c b/drivers/misc/qcom/qdsp6v2/audio_amrwb.c
index 2283cf26bda9..2403dbbe426b 100644
--- a/drivers/misc/qcom/qdsp6v2/audio_amrwb.c
+++ b/drivers/misc/qcom/qdsp6v2/audio_amrwb.c
@@ -15,6 +15,8 @@
*
*/
+#include <linux/compat.h>
+#include <linux/types.h>
#include "audio_utils_aio.h"
static struct miscdevice audio_amrwb_misc;
@@ -71,6 +73,53 @@ static long audio_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
return rc;
}
+static long audio_compat_ioctl(struct file *file, unsigned int cmd,
+ unsigned long arg)
+{
+ struct q6audio_aio *audio = file->private_data;
+ int rc = 0;
+
+ switch (cmd) {
+ case AUDIO_START: {
+ pr_debug("%s[%pK]: AUDIO_START session_id[%d]\n", __func__,
+ audio, audio->ac->session);
+ if (audio->feedback == NON_TUNNEL_MODE) {
+ /* Configure PCM output block */
+ rc = q6asm_enc_cfg_blk_pcm(audio->ac,
+ audio->pcm_cfg.sample_rate,
+ audio->pcm_cfg.channel_count);
+ if (rc < 0) {
+ pr_err("%s: pcm output block config failed rc=%d\n",
+ __func__, rc);
+ break;
+ }
+ }
+
+ rc = audio_aio_enable(audio);
+ audio->eos_rsp = 0;
+ audio->eos_flag = 0;
+ if (!rc) {
+ audio->enabled = 1;
+ } else {
+ audio->enabled = 0;
+ pr_err("%s: Audio Start procedure failed rc=%d\n",
+ __func__, rc);
+ break;
+ }
+ pr_debug("%s: AUDIO_START sessionid[%d]enable[%d]\n", __func__,
+ audio->ac->session,
+ audio->enabled);
+ if (audio->stopped == 1)
+ audio->stopped = 0;
+ break;
+ }
+ default:
+ pr_debug("%s[%pK]: Calling compat ioctl\n", __func__, audio);
+ rc = audio->codec_compat_ioctl(file, cmd, arg);
+ }
+ return rc;
+}
+
static int audio_open(struct inode *inode, struct file *file)
{
struct q6audio_aio *audio = NULL;
@@ -159,6 +208,7 @@ static const struct file_operations audio_amrwb_fops = {
.release = audio_aio_release,
.unlocked_ioctl = audio_ioctl,
.fsync = audio_aio_fsync,
+ .compat_ioctl = audio_compat_ioctl,
};
static struct miscdevice audio_amrwb_misc = {
diff --git a/drivers/misc/qcom/qdsp6v2/audio_g711alaw.c b/drivers/misc/qcom/qdsp6v2/audio_g711alaw.c
new file mode 100644
index 000000000000..6f02654d3d4c
--- /dev/null
+++ b/drivers/misc/qcom/qdsp6v2/audio_g711alaw.c
@@ -0,0 +1,396 @@
+/* Copyright (c) 2016, The Linux Foundation. All rights reserved.
+*
+* This program is free software; you can redistribute it and/or modify
+* it under the terms of the GNU General Public License version 2 and
+* 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/types.h>
+#include <linux/msm_audio_g711_dec.h>
+#include <linux/compat.h>
+#include "audio_utils_aio.h"
+
+static struct miscdevice audio_g711alaw_misc;
+static struct ws_mgr audio_g711_ws_mgr;
+
+static const struct file_operations audio_g711_debug_fops = {
+ .read = audio_aio_debug_read,
+ .open = audio_aio_debug_open,
+};
+
+static struct dentry *config_debugfs_create_file(const char *name, void *data)
+{
+ return debugfs_create_file(name, S_IFREG | S_IRUGO,
+ NULL, (void *)data, &audio_g711_debug_fops);
+}
+
+static int g711_channel_map(u8 *channel_mapping, uint32_t channels);
+
+static long audio_ioctl_shared(struct file *file, unsigned int cmd,
+ void *arg)
+{
+ struct q6audio_aio *audio = file->private_data;
+ int rc = 0;
+
+ switch (cmd) {
+ case AUDIO_START: {
+ struct asm_g711_dec_cfg g711_dec_cfg;
+ struct msm_audio_g711_dec_config *g711_dec_config;
+ u8 channel_mapping[PCM_FORMAT_MAX_NUM_CHANNEL];
+
+ memset(channel_mapping, 0, PCM_FORMAT_MAX_NUM_CHANNEL);
+ memset(&g711_dec_cfg, 0, sizeof(g711_dec_cfg));
+
+ if (g711_channel_map(channel_mapping,
+ audio->pcm_cfg.channel_count)) {
+ pr_err("%s: setting channel map failed %d\n",
+ __func__, audio->pcm_cfg.channel_count);
+ }
+
+ pr_debug("%s[%pK]: AUDIO_START session_id[%d]\n", __func__,
+ audio, audio->ac->session);
+ if (audio->feedback == NON_TUNNEL_MODE) {
+ /* Configure PCM output block */
+ rc = q6asm_enc_cfg_blk_pcm_v2(audio->ac,
+ audio->pcm_cfg.sample_rate,
+ audio->pcm_cfg.channel_count,
+ 16, /*bits per sample*/
+ false, false, channel_mapping);
+ if (rc < 0) {
+ pr_err("%s: pcm output block config failed rc=%d\n",
+ __func__, rc);
+ break;
+ }
+ }
+ g711_dec_config =
+ (struct msm_audio_g711_dec_config *)audio->codec_cfg;
+ g711_dec_cfg.sample_rate = g711_dec_config->sample_rate;
+ /* Configure Media format block */
+ rc = q6asm_media_format_block_g711(audio->ac, &g711_dec_cfg,
+ audio->ac->stream_id);
+ if (rc < 0) {
+ pr_err("%s: cmd media format block failed rc=%d\n",
+ __func__, rc);
+ break;
+ }
+ rc = audio_aio_enable(audio);
+ audio->eos_rsp = 0;
+ audio->eos_flag = 0;
+ if (!rc) {
+ audio->enabled = 1;
+ } else {
+ audio->enabled = 0;
+ pr_err("%s: Audio Start procedure failed rc=%d\n",
+ __func__, rc);
+ break;
+ }
+ pr_debug("%s: AUDIO_START success enable[%d]\n",
+ __func__, audio->enabled);
+ if (audio->stopped == 1)
+ audio->stopped = 0;
+ break;
+ }
+ default:
+ pr_debug("%s: Unknown ioctl cmd = %d", __func__, cmd);
+ break;
+ }
+ return rc;
+}
+
+static long audio_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
+{
+ struct q6audio_aio *audio = file->private_data;
+ int rc = 0;
+
+ switch (cmd) {
+ case AUDIO_START: {
+ rc = audio_ioctl_shared(file, cmd, (void *)arg);
+ break;
+ }
+ case AUDIO_GET_G711_DEC_CONFIG: {
+ if (copy_to_user((void *)arg, audio->codec_cfg,
+ sizeof(struct msm_audio_g711_dec_config))) {
+ pr_err("%s: copy_to_user for AUDIO_GET_G711_DEC_CONFIG failed\n",
+ __func__);
+ rc = -EFAULT;
+ }
+ break;
+ }
+ case AUDIO_SET_G711_DEC_CONFIG: {
+ if (copy_from_user(audio->codec_cfg, (void *)arg,
+ sizeof(struct msm_audio_g711_dec_config))) {
+ pr_err("%s: copy_from_user for AUDIO_SET_G711_DEC_CONFIG failed\n",
+ __func__);
+ rc = -EFAULT;
+ }
+ break;
+ }
+ default: {
+ rc = audio->codec_ioctl(file, cmd, arg);
+ if (rc)
+ pr_err("%s: Failed in audio_aio_ioctl: %d cmd=%d\n",
+ __func__, rc, cmd);
+ break;
+ }
+ }
+ return rc;
+}
+
+#ifdef CONFIG_COMPAT
+struct msm_audio_g711_dec_config_32 {
+ u32 sample_rate;
+};
+
+enum {
+ AUDIO_SET_G711_DEC_CONFIG_32 = _IOW(AUDIO_IOCTL_MAGIC,
+ (AUDIO_MAX_COMMON_IOCTL_NUM+0), struct msm_audio_g711_dec_config_32),
+ AUDIO_GET_G711_DEC_CONFIG_32 = _IOR(AUDIO_IOCTL_MAGIC,
+ (AUDIO_MAX_COMMON_IOCTL_NUM+1), struct msm_audio_g711_dec_config_32)
+};
+
+static long audio_compat_ioctl(struct file *file, unsigned int cmd,
+ unsigned long arg)
+{
+ struct q6audio_aio *audio = file->private_data;
+ int rc = 0;
+
+ switch (cmd) {
+ case AUDIO_START: {
+ rc = audio_ioctl_shared(file, cmd, (void *)arg);
+ break;
+ }
+ case AUDIO_GET_G711_DEC_CONFIG_32: {
+ struct msm_audio_g711_dec_config *g711_dec_config;
+ struct msm_audio_g711_dec_config_32 g711_dec_config_32;
+
+ memset(&g711_dec_config_32, 0, sizeof(g711_dec_config_32));
+
+ g711_dec_config =
+ (struct msm_audio_g711_dec_config *)audio->codec_cfg;
+ g711_dec_config_32.sample_rate = g711_dec_config->sample_rate;
+
+ if (copy_to_user((void *)arg, &g711_dec_config_32,
+ sizeof(g711_dec_config_32))) {
+ pr_err("%s: copy_to_user for AUDIO_GET_G711_DEC_CONFIG_32 failed\n",
+ __func__);
+ rc = -EFAULT;
+ }
+ break;
+ }
+ case AUDIO_SET_G711_DEC_CONFIG_32: {
+ struct msm_audio_g711_dec_config *g711_dec_config;
+ struct msm_audio_g711_dec_config_32 g711_dec_config_32;
+
+ memset(&g711_dec_config_32, 0, sizeof(g711_dec_config_32));
+
+ if (copy_from_user(&g711_dec_config_32, (void *)arg,
+ sizeof(g711_dec_config_32))) {
+ pr_err("%s: copy_from_user for AUDIO_SET_G711_DEC_CONFIG_32 failed\n",
+ __func__);
+ rc = -EFAULT;
+ break;
+ }
+
+ g711_dec_config =
+ (struct msm_audio_g711_dec_config *)audio->codec_cfg;
+ g711_dec_config->sample_rate = g711_dec_config_32.sample_rate;
+
+ break;
+ }
+ default: {
+ rc = audio->codec_compat_ioctl(file, cmd, arg);
+ if (rc)
+ pr_err("%s: Failed in audio_aio_compat_ioctl: %d cmd=%d\n",
+ __func__, rc, cmd);
+ break;
+ }
+ }
+ return rc;
+}
+#else
+#define audio_compat_ioctl NULL
+#endif
+
+static int audio_open(struct inode *inode, struct file *file)
+{
+ struct q6audio_aio *audio = NULL;
+ int rc = 0;
+ /* 4 bytes represents decoder number, 1 byte for terminate string */
+ char name[sizeof "msm_g711_" + 5];
+
+ audio = kzalloc(sizeof(struct q6audio_aio), GFP_KERNEL);
+
+ if (!audio)
+ return -ENOMEM;
+ audio->codec_cfg = kzalloc(sizeof(struct msm_audio_g711_dec_config),
+ GFP_KERNEL);
+ if (!audio->codec_cfg) {
+ kfree(audio);
+ return -ENOMEM;
+ }
+
+ audio->pcm_cfg.buffer_size = PCM_BUFSZ_MIN;
+ audio->miscdevice = &audio_g711alaw_misc;
+ audio->wakelock_voted = false;
+ audio->audio_ws_mgr = &audio_g711_ws_mgr;
+
+ init_waitqueue_head(&audio->event_wait);
+
+ audio->ac = q6asm_audio_client_alloc((app_cb) q6_audio_cb,
+ (void *)audio);
+
+ if (!audio->ac) {
+ pr_err("%s: Could not allocate memory for audio client\n",
+ __func__);
+ kfree(audio->codec_cfg);
+ kfree(audio);
+ return -ENOMEM;
+ }
+ rc = audio_aio_open(audio, file);
+ if (rc < 0) {
+ pr_err("%s: audio_aio_open rc=%d\n",
+ __func__, rc);
+ goto fail;
+ }
+ /* open in T/NT mode */ /*foramt:G711_ALAW*/
+ if ((file->f_mode & FMODE_WRITE) && (file->f_mode & FMODE_READ)) {
+ rc = q6asm_open_read_write(audio->ac, FORMAT_LINEAR_PCM,
+ FORMAT_G711_ALAW_FS);
+ if (rc < 0) {
+ pr_err("%s: NT mode Open failed rc=%d\n", __func__, rc);
+ goto fail;
+ }
+ audio->feedback = NON_TUNNEL_MODE;
+ /* open G711 decoder, expected frames is always 1*/
+ audio->buf_cfg.frames_per_buf = 0x01;
+ audio->buf_cfg.meta_info_enable = 0x01;
+ } else if ((file->f_mode & FMODE_WRITE) &&
+ !(file->f_mode & FMODE_READ)) {
+ rc = q6asm_open_write(audio->ac, FORMAT_G711_ALAW_FS);
+ if (rc < 0) {
+ pr_err("%s: T mode Open failed rc=%d\n", __func__, rc);
+ goto fail;
+ }
+ audio->feedback = TUNNEL_MODE;
+ audio->buf_cfg.meta_info_enable = 0x00;
+ } else {
+ pr_err("%s: %d mode is not supported mode\n",
+ __func__, file->f_mode);
+ rc = -EACCES;
+ goto fail;
+ }
+
+ snprintf(name, sizeof(name), "msm_g711_%04x", audio->ac->session);
+ audio->dentry = config_debugfs_create_file(name, (void *)audio);
+
+ if (IS_ERR_OR_NULL(audio->dentry))
+ pr_debug("%s: debugfs_create_file failed\n", __func__);
+ pr_debug("%s: g711dec success mode[%d]session[%d]\n", __func__,
+ audio->feedback,
+ audio->ac->session);
+ return rc;
+fail:
+ q6asm_audio_client_free(audio->ac);
+ kfree(audio->codec_cfg);
+ kfree(audio);
+ return rc;
+}
+
+static int g711_channel_map(u8 *channel_mapping, uint32_t channels)
+{
+ u8 *lchannel_mapping;
+
+ lchannel_mapping = channel_mapping;
+ pr_debug("%s: channels passed: %d\n", __func__, channels);
+ if (channels == 1) {
+ lchannel_mapping[0] = PCM_CHANNEL_FC;
+ } else if (channels == 2) {
+ lchannel_mapping[0] = PCM_CHANNEL_FL;
+ lchannel_mapping[1] = PCM_CHANNEL_FR;
+ } else if (channels == 3) {
+ lchannel_mapping[0] = PCM_CHANNEL_FC;
+ lchannel_mapping[1] = PCM_CHANNEL_FL;
+ lchannel_mapping[2] = PCM_CHANNEL_FR;
+ } else if (channels == 4) {
+ lchannel_mapping[0] = PCM_CHANNEL_FC;
+ lchannel_mapping[1] = PCM_CHANNEL_FL;
+ lchannel_mapping[2] = PCM_CHANNEL_FR;
+ lchannel_mapping[3] = PCM_CHANNEL_CS;
+ } else if (channels == 5) {
+ lchannel_mapping[0] = PCM_CHANNEL_FC;
+ lchannel_mapping[1] = PCM_CHANNEL_FL;
+ lchannel_mapping[2] = PCM_CHANNEL_FR;
+ lchannel_mapping[3] = PCM_CHANNEL_LS;
+ lchannel_mapping[4] = PCM_CHANNEL_RS;
+ } else if (channels == 6) {
+ lchannel_mapping[0] = PCM_CHANNEL_FC;
+ lchannel_mapping[1] = PCM_CHANNEL_FL;
+ lchannel_mapping[2] = PCM_CHANNEL_FR;
+ lchannel_mapping[3] = PCM_CHANNEL_LS;
+ lchannel_mapping[4] = PCM_CHANNEL_RS;
+ lchannel_mapping[5] = PCM_CHANNEL_LFE;
+ } else if (channels == 7) {
+ lchannel_mapping[0] = PCM_CHANNEL_FC;
+ lchannel_mapping[1] = PCM_CHANNEL_FL;
+ lchannel_mapping[2] = PCM_CHANNEL_FR;
+ lchannel_mapping[3] = PCM_CHANNEL_LS;
+ lchannel_mapping[4] = PCM_CHANNEL_RS;
+ lchannel_mapping[5] = PCM_CHANNEL_CS;
+ lchannel_mapping[6] = PCM_CHANNEL_LFE;
+ } else if (channels == 8) {
+ lchannel_mapping[0] = PCM_CHANNEL_FC;
+ lchannel_mapping[1] = PCM_CHANNEL_FLC;
+ lchannel_mapping[2] = PCM_CHANNEL_FRC;
+ lchannel_mapping[3] = PCM_CHANNEL_FL;
+ lchannel_mapping[4] = PCM_CHANNEL_FR;
+ lchannel_mapping[5] = PCM_CHANNEL_LS;
+ lchannel_mapping[6] = PCM_CHANNEL_RS;
+ lchannel_mapping[7] = PCM_CHANNEL_LFE;
+ } else {
+ pr_err("%s: ERROR.unsupported num_ch = %u\n",
+ __func__, channels);
+ return -EINVAL;
+ }
+ return 0;
+}
+
+static const struct file_operations audio_g711_fops = {
+ .owner = THIS_MODULE,
+ .open = audio_open,
+ .release = audio_aio_release,
+ .unlocked_ioctl = audio_ioctl,
+ .compat_ioctl = audio_compat_ioctl,
+ .fsync = audio_aio_fsync,
+};
+
+static struct miscdevice audio_g711alaw_misc = {
+ .minor = MISC_DYNAMIC_MINOR,
+ .name = "msm_g711alaw",
+ .fops = &audio_g711_fops,
+};
+
+static int __init audio_g711alaw_init(void)
+{
+ int ret = misc_register(&audio_g711alaw_misc);
+
+ if (ret == 0)
+ device_init_wakeup(audio_g711alaw_misc.this_device, true);
+ audio_g711_ws_mgr.ref_cnt = 0;
+ mutex_init(&audio_g711_ws_mgr.ws_lock);
+
+ return ret;
+}
+static void __exit audio_g711alaw_exit(void)
+{
+ misc_deregister(&audio_g711alaw_misc);
+ mutex_destroy(&audio_g711_ws_mgr.ws_lock);
+}
+
+device_initcall(audio_g711alaw_init);
+__exitcall(audio_g711alaw_exit);
diff --git a/drivers/misc/qcom/qdsp6v2/audio_g711mlaw.c b/drivers/misc/qcom/qdsp6v2/audio_g711mlaw.c
new file mode 100644
index 000000000000..cae2490feb7a
--- /dev/null
+++ b/drivers/misc/qcom/qdsp6v2/audio_g711mlaw.c
@@ -0,0 +1,396 @@
+/* Copyright (c) 2016, The Linux Foundation. All rights reserved.
+*
+* This program is free software; you can redistribute it and/or modify
+* it under the terms of the GNU General Public License version 2 and
+* 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/types.h>
+#include <linux/msm_audio_g711_dec.h>
+#include <linux/compat.h>
+#include "audio_utils_aio.h"
+
+static struct miscdevice audio_g711mlaw_misc;
+static struct ws_mgr audio_g711_ws_mgr;
+
+static const struct file_operations audio_g711_debug_fops = {
+ .read = audio_aio_debug_read,
+ .open = audio_aio_debug_open,
+};
+
+static struct dentry *config_debugfs_create_file(const char *name, void *data)
+{
+ return debugfs_create_file(name, S_IFREG | S_IRUGO,
+ NULL, (void *)data, &audio_g711_debug_fops);
+}
+
+static int g711_channel_map(u8 *channel_mapping, uint32_t channels);
+
+static long audio_ioctl_shared(struct file *file, unsigned int cmd,
+ void *arg)
+{
+ struct q6audio_aio *audio = file->private_data;
+ int rc = 0;
+
+ switch (cmd) {
+ case AUDIO_START: {
+ struct asm_g711_dec_cfg g711_dec_cfg;
+ struct msm_audio_g711_dec_config *g711_dec_config;
+ u8 channel_mapping[PCM_FORMAT_MAX_NUM_CHANNEL];
+
+ memset(channel_mapping, 0, PCM_FORMAT_MAX_NUM_CHANNEL);
+ memset(&g711_dec_cfg, 0, sizeof(g711_dec_cfg));
+
+ if (g711_channel_map(channel_mapping,
+ audio->pcm_cfg.channel_count)) {
+ pr_err("%s: setting channel map failed %d\n",
+ __func__, audio->pcm_cfg.channel_count);
+ }
+
+ pr_debug("%s[%pK]: AUDIO_START session_id[%d]\n", __func__,
+ audio, audio->ac->session);
+ if (audio->feedback == NON_TUNNEL_MODE) {
+ /* Configure PCM output block */
+ rc = q6asm_enc_cfg_blk_pcm_v2(audio->ac,
+ audio->pcm_cfg.sample_rate,
+ audio->pcm_cfg.channel_count,
+ 16, /*bits per sample*/
+ false, false, channel_mapping);
+ if (rc < 0) {
+ pr_err("%s: pcm output block config failed rc=%d\n",
+ __func__, rc);
+ break;
+ }
+ }
+ g711_dec_config =
+ (struct msm_audio_g711_dec_config *)audio->codec_cfg;
+ g711_dec_cfg.sample_rate = g711_dec_config->sample_rate;
+ /* Configure Media format block */
+ rc = q6asm_media_format_block_g711(audio->ac, &g711_dec_cfg,
+ audio->ac->stream_id);
+ if (rc < 0) {
+ pr_err("%s: cmd media format block failed rc=%d\n",
+ __func__, rc);
+ break;
+ }
+ rc = audio_aio_enable(audio);
+ audio->eos_rsp = 0;
+ audio->eos_flag = 0;
+ if (!rc) {
+ audio->enabled = 1;
+ } else {
+ audio->enabled = 0;
+ pr_err("%s: Audio Start procedure failed rc=%d\n",
+ __func__, rc);
+ break;
+ }
+ pr_debug("%s: AUDIO_START success enable[%d]\n",
+ __func__, audio->enabled);
+ if (audio->stopped == 1)
+ audio->stopped = 0;
+ break;
+ }
+ default:
+ pr_debug("%s: Unknown ioctl cmd = %d", __func__, cmd);
+ break;
+ }
+ return rc;
+}
+
+static long audio_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
+{
+ struct q6audio_aio *audio = file->private_data;
+ int rc = 0;
+
+ switch (cmd) {
+ case AUDIO_START: {
+ rc = audio_ioctl_shared(file, cmd, (void *)arg);
+ break;
+ }
+ case AUDIO_GET_G711_DEC_CONFIG: {
+ if (copy_to_user((void *)arg, audio->codec_cfg,
+ sizeof(struct msm_audio_g711_dec_config))) {
+ pr_err("%s: AUDIO_GET_G711_DEC_CONFIG failed\n",
+ __func__);
+ rc = -EFAULT;
+ }
+ break;
+ }
+ case AUDIO_SET_G711_DEC_CONFIG: {
+ if (copy_from_user(audio->codec_cfg, (void *)arg,
+ sizeof(struct msm_audio_g711_dec_config))) {
+ pr_err("%s: AUDIO_SET_G711_DEC_CONFIG failed\n",
+ __func__);
+ rc = -EFAULT;
+ }
+ break;
+ }
+ default: {
+ rc = audio->codec_ioctl(file, cmd, arg);
+ if (rc)
+ pr_err("%s: Failed in audio_aio_ioctl: %d cmd=%d\n",
+ __func__, rc, cmd);
+ break;
+ }
+ }
+ return rc;
+}
+
+#ifdef CONFIG_COMPAT
+struct msm_audio_g711_dec_config_32 {
+ u32 sample_rate;
+};
+
+enum {
+ AUDIO_SET_G711_DEC_CONFIG_32 = _IOW(AUDIO_IOCTL_MAGIC,
+ (AUDIO_MAX_COMMON_IOCTL_NUM+0), struct msm_audio_g711_dec_config_32),
+ AUDIO_GET_G711_DEC_CONFIG_32 = _IOR(AUDIO_IOCTL_MAGIC,
+ (AUDIO_MAX_COMMON_IOCTL_NUM+1), struct msm_audio_g711_dec_config_32)
+};
+
+static long audio_compat_ioctl(struct file *file, unsigned int cmd,
+ unsigned long arg)
+{
+ struct q6audio_aio *audio = file->private_data;
+ int rc = 0;
+
+ switch (cmd) {
+ case AUDIO_START: {
+ rc = audio_ioctl_shared(file, cmd, (void *)arg);
+ break;
+ }
+ case AUDIO_GET_G711_DEC_CONFIG_32: {
+ struct msm_audio_g711_dec_config *g711_dec_config;
+ struct msm_audio_g711_dec_config_32 g711_dec_config_32;
+
+ memset(&g711_dec_config_32, 0, sizeof(g711_dec_config_32));
+
+ g711_dec_config =
+ (struct msm_audio_g711_dec_config *)audio->codec_cfg;
+ g711_dec_config_32.sample_rate = g711_dec_config->sample_rate;
+
+ if (copy_to_user((void *)arg, &g711_dec_config_32,
+ sizeof(g711_dec_config_32))) {
+ pr_err("%s: copy_to_user for AUDIO_GET_G711_DEC_CONFIG failed\n",
+ __func__);
+ rc = -EFAULT;
+ }
+ break;
+ }
+ case AUDIO_SET_G711_DEC_CONFIG_32: {
+ struct msm_audio_g711_dec_config *g711_dec_config;
+ struct msm_audio_g711_dec_config_32 g711_dec_config_32;
+
+ memset(&g711_dec_config_32, 0, sizeof(g711_dec_config_32));
+
+ if (copy_from_user(&g711_dec_config_32, (void *)arg,
+ sizeof(g711_dec_config_32))) {
+ pr_err("%s: copy_from_user for AUDIO_SET_G711_DEC_CONFIG failed\n",
+ __func__);
+ rc = -EFAULT;
+ break;
+ }
+ g711_dec_config =
+ (struct msm_audio_g711_dec_config *)audio->codec_cfg;
+ g711_dec_config->sample_rate = g711_dec_config_32.sample_rate;
+
+ break;
+ }
+ default: {
+ rc = audio->codec_compat_ioctl(file, cmd, arg);
+ if (rc)
+ pr_err("%s: Failed in audio_aio_compat_ioctl: %d cmd=%d\n",
+ __func__, rc, cmd);
+ break;
+ }
+ }
+ return rc;
+}
+#else
+#define audio_compat_ioctl NULL
+#endif
+
+static int audio_open(struct inode *inode, struct file *file)
+{
+ struct q6audio_aio *audio = NULL;
+ int rc = 0;
+ /* 4 bytes represents decoder number, 1 byte for terminate string */
+ char name[sizeof "msm_g711_" + 5];
+
+ audio = kzalloc(sizeof(struct q6audio_aio), GFP_KERNEL);
+
+ if (!audio)
+ return -ENOMEM;
+ audio->codec_cfg = kzalloc(sizeof(struct msm_audio_g711_dec_config),
+ GFP_KERNEL);
+ if (!audio->codec_cfg) {
+ kfree(audio);
+ return -ENOMEM;
+ }
+
+ audio->pcm_cfg.buffer_size = PCM_BUFSZ_MIN;
+ audio->miscdevice = &audio_g711mlaw_misc;
+ audio->wakelock_voted = false;
+ audio->audio_ws_mgr = &audio_g711_ws_mgr;
+
+ init_waitqueue_head(&audio->event_wait);
+
+ audio->ac = q6asm_audio_client_alloc((app_cb) q6_audio_cb,
+ (void *)audio);
+
+ if (!audio->ac) {
+ pr_err("%s: Could not allocate memory for audio client\n",
+ __func__);
+ kfree(audio->codec_cfg);
+ kfree(audio);
+ return -ENOMEM;
+ }
+ rc = audio_aio_open(audio, file);
+ if (rc < 0) {
+ pr_err("%s: audio_aio_open rc=%d\n",
+ __func__, rc);
+ goto fail;
+ }
+ /* open in T/NT mode */ /*foramt:G711_ALAW*/
+ if ((file->f_mode & FMODE_WRITE) && (file->f_mode & FMODE_READ)) {
+ rc = q6asm_open_read_write(audio->ac, FORMAT_LINEAR_PCM,
+ FORMAT_G711_MLAW_FS);
+ if (rc < 0) {
+ pr_err("%s: NT mode Open failed rc=%d\n", __func__, rc);
+ goto fail;
+ }
+ audio->feedback = NON_TUNNEL_MODE;
+ /* open G711 decoder, expected frames is always 1*/
+ audio->buf_cfg.frames_per_buf = 0x01;
+ audio->buf_cfg.meta_info_enable = 0x01;
+ } else if ((file->f_mode & FMODE_WRITE) &&
+ !(file->f_mode & FMODE_READ)) {
+ rc = q6asm_open_write(audio->ac, FORMAT_G711_MLAW_FS);
+ if (rc < 0) {
+ pr_err("%s: T mode Open failed rc=%d\n", __func__, rc);
+ goto fail;
+ }
+ audio->feedback = TUNNEL_MODE;
+ audio->buf_cfg.meta_info_enable = 0x00;
+ } else {
+ pr_err("%s: %d mode is not supported\n", __func__,
+ file->f_mode);
+ rc = -EACCES;
+ goto fail;
+ }
+
+ snprintf(name, sizeof(name), "msm_g711_%04x", audio->ac->session);
+ audio->dentry = config_debugfs_create_file(name, (void *)audio);
+
+ if (IS_ERR_OR_NULL(audio->dentry))
+ pr_debug("%s: debugfs_create_file failed\n", __func__);
+ pr_debug("%s: g711dec success mode[%d]session[%d]\n", __func__,
+ audio->feedback,
+ audio->ac->session);
+ return rc;
+fail:
+ q6asm_audio_client_free(audio->ac);
+ kfree(audio->codec_cfg);
+ kfree(audio);
+ return rc;
+}
+
+static int g711_channel_map(u8 *channel_mapping, uint32_t channels)
+{
+ u8 *lchannel_mapping;
+
+ lchannel_mapping = channel_mapping;
+ pr_debug("%s: channels passed: %d\n", __func__, channels);
+ if (channels == 1) {
+ lchannel_mapping[0] = PCM_CHANNEL_FC;
+ } else if (channels == 2) {
+ lchannel_mapping[0] = PCM_CHANNEL_FL;
+ lchannel_mapping[1] = PCM_CHANNEL_FR;
+ } else if (channels == 3) {
+ lchannel_mapping[0] = PCM_CHANNEL_FC;
+ lchannel_mapping[1] = PCM_CHANNEL_FL;
+ lchannel_mapping[2] = PCM_CHANNEL_FR;
+ } else if (channels == 4) {
+ lchannel_mapping[0] = PCM_CHANNEL_FC;
+ lchannel_mapping[1] = PCM_CHANNEL_FL;
+ lchannel_mapping[2] = PCM_CHANNEL_FR;
+ lchannel_mapping[3] = PCM_CHANNEL_CS;
+ } else if (channels == 5) {
+ lchannel_mapping[0] = PCM_CHANNEL_FC;
+ lchannel_mapping[1] = PCM_CHANNEL_FL;
+ lchannel_mapping[2] = PCM_CHANNEL_FR;
+ lchannel_mapping[3] = PCM_CHANNEL_LS;
+ lchannel_mapping[4] = PCM_CHANNEL_RS;
+ } else if (channels == 6) {
+ lchannel_mapping[0] = PCM_CHANNEL_FC;
+ lchannel_mapping[1] = PCM_CHANNEL_FL;
+ lchannel_mapping[2] = PCM_CHANNEL_FR;
+ lchannel_mapping[3] = PCM_CHANNEL_LS;
+ lchannel_mapping[4] = PCM_CHANNEL_RS;
+ lchannel_mapping[5] = PCM_CHANNEL_LFE;
+ } else if (channels == 7) {
+ lchannel_mapping[0] = PCM_CHANNEL_FC;
+ lchannel_mapping[1] = PCM_CHANNEL_FL;
+ lchannel_mapping[2] = PCM_CHANNEL_FR;
+ lchannel_mapping[3] = PCM_CHANNEL_LS;
+ lchannel_mapping[4] = PCM_CHANNEL_RS;
+ lchannel_mapping[5] = PCM_CHANNEL_CS;
+ lchannel_mapping[6] = PCM_CHANNEL_LFE;
+ } else if (channels == 8) {
+ lchannel_mapping[0] = PCM_CHANNEL_FC;
+ lchannel_mapping[1] = PCM_CHANNEL_FLC;
+ lchannel_mapping[2] = PCM_CHANNEL_FRC;
+ lchannel_mapping[3] = PCM_CHANNEL_FL;
+ lchannel_mapping[4] = PCM_CHANNEL_FR;
+ lchannel_mapping[5] = PCM_CHANNEL_LS;
+ lchannel_mapping[6] = PCM_CHANNEL_RS;
+ lchannel_mapping[7] = PCM_CHANNEL_LFE;
+ } else {
+ pr_err("%s: ERROR.unsupported num_ch = %u\n",
+ __func__, channels);
+ return -EINVAL;
+ }
+ return 0;
+}
+
+static const struct file_operations audio_g711_fops = {
+ .owner = THIS_MODULE,
+ .open = audio_open,
+ .release = audio_aio_release,
+ .unlocked_ioctl = audio_ioctl,
+ .compat_ioctl = audio_compat_ioctl,
+ .fsync = audio_aio_fsync,
+};
+
+static struct miscdevice audio_g711mlaw_misc = {
+ .minor = MISC_DYNAMIC_MINOR,
+ .name = "msm_g711mlaw",
+ .fops = &audio_g711_fops,
+};
+
+static int __init audio_g711mlaw_init(void)
+{
+ int ret = misc_register(&audio_g711mlaw_misc);
+
+ if (ret == 0)
+ device_init_wakeup(audio_g711mlaw_misc.this_device, true);
+ audio_g711_ws_mgr.ref_cnt = 0;
+ mutex_init(&audio_g711_ws_mgr.ws_lock);
+
+ return ret;
+}
+
+static void __exit audio_g711mlaw_exit(void)
+{
+ misc_deregister(&audio_g711mlaw_misc);
+ mutex_destroy(&audio_g711_ws_mgr.ws_lock);
+}
+
+device_initcall(audio_g711mlaw_init);
+__exitcall(audio_g711mlaw_exit);
diff --git a/drivers/misc/qcom/qdsp6v2/g711alaw_in.c b/drivers/misc/qcom/qdsp6v2/g711alaw_in.c
new file mode 100644
index 000000000000..ac720b53ff5b
--- /dev/null
+++ b/drivers/misc/qcom/qdsp6v2/g711alaw_in.c
@@ -0,0 +1,382 @@
+/* Copyright (c) 2010-2016, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+*/
+
+#include <linux/module.h>
+#include <linux/fs.h>
+#include <linux/miscdevice.h>
+#include <linux/uaccess.h>
+#include <linux/sched.h>
+#include <linux/wait.h>
+#include <linux/dma-mapping.h>
+#include <linux/slab.h>
+#include <linux/msm_audio_g711.h>
+#include <linux/atomic.h>
+#include <linux/compat.h>
+#include <asm/ioctls.h>
+#include "audio_utils.h"
+
+/* Buffer with meta*/
+#define PCM_BUF_SIZE (4096 + sizeof(struct meta_in))
+
+/* Maximum 10 frames in buffer with meta */
+#define FRAME_SIZE (1 + ((320+sizeof(struct meta_out_dsp)) * 10))
+static long g711_in_ioctl_shared(struct file *file,
+ unsigned int cmd, unsigned long arg)
+{
+ struct q6audio_in *audio = file->private_data;
+ int rc = 0;
+ int cnt = 0;
+
+ switch (cmd) {
+ case AUDIO_START: {
+ struct msm_audio_g711_enc_config *enc_cfg;
+
+ enc_cfg = (struct msm_audio_g711_enc_config *)audio->enc_cfg;
+ pr_debug("%s:session id %d: default buf alloc[%d]\n", __func__,
+ audio->ac->session, audio->buf_alloc);
+ if (audio->enabled == 1) {
+ rc = 0;
+ break;
+ }
+ rc = audio_in_buf_alloc(audio);
+ if (rc < 0) {
+ pr_err("%s:session id %d: buffer allocation failed rc=%d\n",
+ __func__, audio->ac->session, rc);
+ break;
+ }
+ pr_debug("%s: sample rate %d", __func__, enc_cfg->sample_rate);
+ rc = q6asm_enc_cfg_blk_g711(audio->ac,
+ audio->buf_cfg.frames_per_buf,
+ enc_cfg->sample_rate);
+
+ if (rc < 0) {
+ pr_err("%s:session id %d: cmd g711 media format block failed rc=%d\n",
+ __func__, audio->ac->session, rc);
+ break;
+ }
+ if (audio->feedback == NON_TUNNEL_MODE) {
+ rc = q6asm_media_format_block_pcm(audio->ac,
+ audio->pcm_cfg.sample_rate,
+ audio->pcm_cfg.channel_count);
+
+ if (rc < 0) {
+ pr_err("%s:session id %d: media format block failed rc=%d\n",
+ __func__, audio->ac->session, rc);
+ break;
+ }
+ }
+ pr_debug("%s:session id %d: AUDIO_START enable[%d]\n", __func__,
+ audio->ac->session, audio->enabled);
+ rc = audio_in_enable(audio);
+ if (!rc) {
+ audio->enabled = 1;
+ } else {
+ audio->enabled = 0;
+ pr_err("%s:session id %d: Audio Start procedure failed rc=%d\n",
+ __func__, audio->ac->session, rc);
+ break;
+ }
+ while (cnt++ < audio->str_cfg.buffer_count)
+ q6asm_read(audio->ac); /* Push buffer to DSP */
+ rc = 0;
+ pr_debug("%s:session id %d: AUDIO_START success enable[%d]\n",
+ __func__, audio->ac->session, audio->enabled);
+ break;
+ }
+ case AUDIO_STOP: {
+ pr_debug("%s:session id %d: AUDIO_STOP\n", __func__,
+ audio->ac->session);
+ rc = audio_in_disable(audio);
+ if (rc < 0) {
+ pr_err("%s:session id %d: Audio Stop procedure failed rc=%d\n",
+ __func__, audio->ac->session,
+ rc);
+ break;
+ }
+ break;
+ }
+ case AUDIO_SET_G711_ENC_CONFIG: {
+ struct msm_audio_g711_enc_config *cfg;
+ struct msm_audio_g711_enc_config *enc_cfg;
+
+ enc_cfg = (struct msm_audio_g711_enc_config *)audio->enc_cfg;
+
+ cfg = (struct msm_audio_g711_enc_config *)arg;
+ if (cfg == NULL) {
+ pr_err("%s: NULL config pointer\n", __func__);
+ rc = -EINVAL;
+ break;
+ }
+ if (cfg->sample_rate != 8000 &&
+ cfg->sample_rate != 16000) {
+ pr_err("%s:session id %d: invalid sample rate\n",
+ __func__, audio->ac->session);
+ rc = -EINVAL;
+ break;
+ }
+ enc_cfg->sample_rate = cfg->sample_rate;
+ pr_debug("%s:session id %d: sample_rate= 0x%x",
+ __func__,
+ audio->ac->session, enc_cfg->sample_rate);
+ break;
+ }
+ default:
+ pr_err("%s: Unknown ioctl cmd = %d", __func__, cmd);
+ rc = -ENOIOCTLCMD;
+ }
+ return rc;
+}
+
+static long g711_in_ioctl(struct file *file,
+ unsigned int cmd, unsigned long arg)
+{
+ struct q6audio_in *audio = file->private_data;
+ int rc = 0;
+
+ switch (cmd) {
+ case AUDIO_START:
+ case AUDIO_STOP: {
+ rc = g711_in_ioctl_shared(file, cmd, arg);
+ break;
+ }
+ case AUDIO_GET_G711_ENC_CONFIG: {
+ if (copy_to_user((void *)arg, audio->enc_cfg,
+ sizeof(struct msm_audio_g711_enc_config))) {
+ pr_err(
+ "%s: copy_to_user for AUDIO_GET_g711_ENC_CONFIG failed",
+ __func__);
+ rc = -EFAULT;
+ }
+ break;
+ }
+ case AUDIO_SET_G711_ENC_CONFIG: {
+ struct msm_audio_g711_enc_config cfg;
+
+ if (copy_from_user(&cfg, (void *) arg,
+ sizeof(cfg))) {
+ pr_err(
+ "%s: copy_from_user for AUDIO_GET_G711_ENC_CONFIG failed",
+ __func__);
+ rc = -EFAULT;
+ break;
+ }
+ rc = g711_in_ioctl_shared(file, cmd, (unsigned long)&cfg);
+ if (rc)
+ pr_err("%s:AUDIO_GET_G711_ENC_CONFIG failed. Rc= %d\n",
+ __func__, rc);
+ break;
+ }
+ default:
+ pr_err("%s: Unknown ioctl cmd = %d", __func__, cmd);
+ rc = -ENOIOCTLCMD;
+ }
+ return rc;
+}
+
+#ifdef CONFIG_COMPAT
+struct msm_audio_g711_enc_config32 {
+ uint32_t sample_rate;
+};
+
+enum {
+ AUDIO_SET_G711_ENC_CONFIG_32 = _IOW(AUDIO_IOCTL_MAGIC,
+ (AUDIO_MAX_COMMON_IOCTL_NUM+0), struct msm_audio_g711_enc_config32),
+ AUDIO_GET_G711_ENC_CONFIG_32 = _IOR(AUDIO_IOCTL_MAGIC,
+ (AUDIO_MAX_COMMON_IOCTL_NUM+1), struct msm_audio_g711_enc_config32)
+};
+
+static long g711_in_compat_ioctl(struct file *file,
+ unsigned int cmd, unsigned long arg)
+{
+ struct q6audio_in *audio = file->private_data;
+ int rc = 0;
+
+ switch (cmd) {
+ case AUDIO_START:
+ case AUDIO_STOP: {
+ rc = g711_in_ioctl_shared(file, cmd, arg);
+ break;
+ }
+ case AUDIO_GET_G711_ENC_CONFIG_32: {
+ struct msm_audio_g711_enc_config32 cfg_32;
+ struct msm_audio_g711_enc_config32 *enc_cfg;
+
+ enc_cfg = (struct msm_audio_g711_enc_config32 *)audio->enc_cfg;
+ cfg_32.sample_rate = enc_cfg->sample_rate;
+ if (copy_to_user((void *)arg, &cfg_32,
+ sizeof(cfg_32))) {
+ pr_err("%s: copy_to_user for AUDIO_GET_G711_ENC_CONFIG_32 failed\n",
+ __func__);
+ rc = -EFAULT;
+ }
+ break;
+ }
+ case AUDIO_SET_G711_ENC_CONFIG_32: {
+ struct msm_audio_g711_enc_config32 cfg_32;
+ struct msm_audio_g711_enc_config32 cfg;
+
+ if (copy_from_user(&cfg_32, (void *) arg,
+ sizeof(cfg_32))) {
+ pr_err("%s: copy_from_user for AUDIO_SET_G711_ENC_CONFIG_32 failed\n",
+ __func__);
+ rc = -EFAULT;
+ break;
+ }
+ cfg.sample_rate = cfg_32.sample_rate;
+ cmd = AUDIO_SET_G711_ENC_CONFIG;
+ rc = g711_in_ioctl_shared(file, cmd, (unsigned long)&cfg);
+ if (rc)
+ pr_err("%s:AUDIO_SET_G711_ENC_CONFIG failed. rc= %d\n",
+ __func__, rc);
+ break;
+ }
+ default:
+ pr_err("%s: Unknown ioctl cmd = %d", __func__, cmd);
+ rc = -ENOIOCTLCMD;
+ }
+ return rc;
+}
+#else
+#define g711_in_compat_ioctl NULL
+#endif
+
+static int g711_in_open(struct inode *inode, struct file *file)
+{
+ struct q6audio_in *audio = NULL;
+ struct msm_audio_g711_enc_config *enc_cfg;
+ int rc = 0;
+
+ audio = kzalloc(sizeof(struct q6audio_in), GFP_KERNEL);
+
+ if (audio == NULL)
+ return -ENOMEM;
+ /* Allocate memory for encoder config param */
+ audio->enc_cfg = kzalloc(sizeof(struct msm_audio_g711_enc_config),
+ GFP_KERNEL);
+ if (audio->enc_cfg == NULL) {
+ kfree(audio);
+ return -ENOMEM;
+ }
+ enc_cfg = audio->enc_cfg;
+
+ mutex_init(&audio->lock);
+ mutex_init(&audio->read_lock);
+ mutex_init(&audio->write_lock);
+ spin_lock_init(&audio->dsp_lock);
+ init_waitqueue_head(&audio->read_wait);
+ init_waitqueue_head(&audio->write_wait);
+
+ /*
+ * Settings will be re-config at AUDIO_SET_CONFIG,
+ * but at least we need to have initial config
+ */
+ audio->str_cfg.buffer_size = FRAME_SIZE;
+ audio->str_cfg.buffer_count = FRAME_NUM;
+ audio->min_frame_size = 320;
+ audio->max_frames_per_buf = 10;
+ audio->pcm_cfg.buffer_size = PCM_BUF_SIZE;
+ audio->pcm_cfg.buffer_count = PCM_BUF_COUNT;
+ enc_cfg->sample_rate = 8000;
+ audio->pcm_cfg.channel_count = 1;
+ audio->pcm_cfg.sample_rate = 8000;
+ audio->buf_cfg.meta_info_enable = 0x01;
+ audio->buf_cfg.frames_per_buf = 0x01;
+ audio->event_abort = 0;
+
+ audio->ac = q6asm_audio_client_alloc((app_cb)q6asm_in_cb,
+ (void *)audio);
+
+ if (!audio->ac) {
+ kfree(audio->enc_cfg);
+ kfree(audio);
+ return -ENOMEM;
+ }
+
+ /* open g711 encoder in T/NT mode */
+ if ((file->f_mode & FMODE_WRITE) &&
+ (file->f_mode & FMODE_READ)) {
+ audio->feedback = NON_TUNNEL_MODE;
+ rc = q6asm_open_read_write(audio->ac, FORMAT_G711_ALAW_FS,
+ FORMAT_LINEAR_PCM);
+ if (rc < 0) {
+ pr_err("%s:session id %d: NT mode Open failed rc=%d\n",
+ __func__, audio->ac->session, rc);
+ rc = -ENODEV;
+ goto fail;
+ }
+ } else if (!(file->f_mode & FMODE_WRITE) &&
+ (file->f_mode & FMODE_READ)) {
+ audio->feedback = TUNNEL_MODE;
+ rc = q6asm_open_read(audio->ac, FORMAT_G711_ALAW_FS);
+ if (rc < 0) {
+ pr_err("%s:session id %d: T mode Open failed rc=%d\n",
+ __func__, audio->ac->session, rc);
+ rc = -ENODEV;
+ goto fail;
+ }
+ /* register for tx overflow (valid for tunnel mode only) */
+ rc = q6asm_reg_tx_overflow(audio->ac, 0x01);
+ if (rc < 0) {
+ pr_err("%s:session id %d: TX Overflow registration failed rc=%d\n",
+ __func__, audio->ac->session, rc);
+ rc = -ENODEV;
+ goto fail;
+ }
+ } else {
+ pr_err("%s:session id %d: Unexpected mode\n", __func__,
+ audio->ac->session);
+ rc = -EACCES;
+ goto fail;
+ }
+
+ audio->opened = 1;
+ audio->reset_event = false;
+ atomic_set(&audio->in_count, PCM_BUF_COUNT);
+ atomic_set(&audio->out_count, 0x00);
+ audio->enc_compat_ioctl = g711_in_compat_ioctl;
+ audio->enc_ioctl = g711_in_ioctl;
+ file->private_data = audio;
+
+ pr_info("%s:session id %d: success\n", __func__, audio->ac->session);
+ return 0;
+fail:
+ q6asm_audio_client_free(audio->ac);
+ kfree(audio->enc_cfg);
+ kfree(audio);
+ return rc;
+}
+
+static const struct file_operations audio_in_fops = {
+ .owner = THIS_MODULE,
+ .open = g711_in_open,
+ .release = audio_in_release,
+ .read = audio_in_read,
+ .write = audio_in_write,
+ .unlocked_ioctl = audio_in_ioctl,
+#ifdef CONFIG_COMPAT
+ .compat_ioctl = audio_in_compat_ioctl,
+#endif
+};
+
+struct miscdevice audio_g711alaw_in_misc = {
+ .minor = MISC_DYNAMIC_MINOR,
+ .name = "msm_g711alaw_in",
+ .fops = &audio_in_fops,
+};
+
+static int __init g711alaw_in_init(void)
+{
+ return misc_register(&audio_g711alaw_in_misc);
+}
+
+device_initcall(g711alaw_in_init);
diff --git a/drivers/misc/qcom/qdsp6v2/g711mlaw_in.c b/drivers/misc/qcom/qdsp6v2/g711mlaw_in.c
new file mode 100644
index 000000000000..6660f83683f8
--- /dev/null
+++ b/drivers/misc/qcom/qdsp6v2/g711mlaw_in.c
@@ -0,0 +1,385 @@
+/* Copyright (c) 2010-2016, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+*/
+
+#include <linux/module.h>
+#include <linux/fs.h>
+#include <linux/miscdevice.h>
+#include <linux/uaccess.h>
+#include <linux/sched.h>
+#include <linux/wait.h>
+#include <linux/dma-mapping.h>
+#include <linux/slab.h>
+#include <linux/msm_audio_g711.h>
+#include <linux/atomic.h>
+#include <linux/compat.h>
+#include <asm/ioctls.h>
+#include "audio_utils.h"
+
+#ifdef CONFIG_COMPAT
+#undef PROC_ADD
+#endif
+/* Buffer with meta*/
+#define PCM_BUF_SIZE (4096 + sizeof(struct meta_in))
+
+/* Maximum 10 frames in buffer with meta */
+#define FRAME_SIZE (1 + ((320+sizeof(struct meta_out_dsp)) * 10))
+static long g711_in_ioctl_shared(struct file *file,
+ unsigned int cmd, unsigned long arg)
+{
+ struct q6audio_in *audio = file->private_data;
+ int rc = 0;
+ int cnt = 0;
+
+ switch (cmd) {
+ case AUDIO_START: {
+ struct msm_audio_g711_enc_config *enc_cfg;
+
+ enc_cfg = (struct msm_audio_g711_enc_config *)audio->enc_cfg;
+ pr_debug("%s:session id %d: default buf alloc[%d]\n", __func__,
+ audio->ac->session, audio->buf_alloc);
+ if (audio->enabled == 1) {
+ rc = 0;
+ break;
+ }
+ rc = audio_in_buf_alloc(audio);
+ if (rc < 0) {
+ pr_err("%s:session id %d: buffer allocation failed rc=%d\n",
+ __func__, audio->ac->session, rc);
+ break;
+ }
+ pr_debug("%s: sample rate %d", __func__, enc_cfg->sample_rate);
+ rc = q6asm_enc_cfg_blk_g711(audio->ac,
+ audio->buf_cfg.frames_per_buf,
+ enc_cfg->sample_rate);
+
+ if (rc < 0) {
+ pr_err("%s:session id %d: cmd g711 media format block failed rc=%d\n",
+ __func__, audio->ac->session, rc);
+ break;
+ }
+ if (audio->feedback == NON_TUNNEL_MODE) {
+ rc = q6asm_media_format_block_pcm(audio->ac,
+ audio->pcm_cfg.sample_rate,
+ audio->pcm_cfg.channel_count);
+
+ if (rc < 0) {
+ pr_err("%s:session id %d: media format block failed rc=%d\n",
+ __func__, audio->ac->session, rc);
+ break;
+ }
+ }
+ pr_debug("%s:session id %d: AUDIO_START enable[%d]\n", __func__,
+ audio->ac->session, audio->enabled);
+ rc = audio_in_enable(audio);
+ if (!rc) {
+ audio->enabled = 1;
+ } else {
+ audio->enabled = 0;
+ pr_err("%s:session id %d: Audio Start procedure failed rc=%d\n",
+ __func__, audio->ac->session, rc);
+ break;
+ }
+ while (cnt++ < audio->str_cfg.buffer_count)
+ q6asm_read(audio->ac); /* Push buffer to DSP */
+ rc = 0;
+ pr_debug("%s:session id %d: AUDIO_START success enable[%d]\n",
+ __func__, audio->ac->session, audio->enabled);
+ break;
+ }
+ case AUDIO_STOP: {
+ pr_debug("%s:session id %d: AUDIO_STOP\n", __func__,
+ audio->ac->session);
+ rc = audio_in_disable(audio);
+ if (rc < 0) {
+ pr_err("%s:session id %d: Audio Stop procedure failed rc=%d\n",
+ __func__, audio->ac->session,
+ rc);
+ break;
+ }
+ break;
+ }
+ case AUDIO_SET_G711_ENC_CONFIG: {
+ struct msm_audio_g711_enc_config *cfg;
+ struct msm_audio_g711_enc_config *enc_cfg;
+
+ enc_cfg = (struct msm_audio_g711_enc_config *)audio->enc_cfg;
+
+ cfg = (struct msm_audio_g711_enc_config *)arg;
+ if (cfg == NULL) {
+ pr_err("%s: NULL config pointer\n", __func__);
+ rc = -EINVAL;
+ break;
+ }
+ if (cfg->sample_rate != 8000 &&
+ cfg->sample_rate != 16000) {
+ pr_err("%s:session id %d: invalid sample rate\n",
+ __func__, audio->ac->session);
+ rc = -EINVAL;
+ break;
+ }
+ enc_cfg->sample_rate = cfg->sample_rate;
+ pr_debug("%s:session id %d: sample_rate= 0x%x",
+ __func__,
+ audio->ac->session, enc_cfg->sample_rate);
+ break;
+ }
+ default:
+ pr_err("%s: Unknown ioctl cmd = %d", __func__, cmd);
+ rc = -ENOIOCTLCMD;
+ }
+ return rc;
+}
+
+static long g711_in_ioctl(struct file *file,
+ unsigned int cmd, unsigned long arg)
+{
+ struct q6audio_in *audio = file->private_data;
+ int rc = 0;
+
+ switch (cmd) {
+ case AUDIO_START:
+ case AUDIO_STOP: {
+ rc = g711_in_ioctl_shared(file, cmd, arg);
+ break;
+ }
+ case AUDIO_GET_G711_ENC_CONFIG: {
+ if (copy_to_user((void *)arg, audio->enc_cfg,
+ sizeof(struct msm_audio_g711_enc_config))) {
+ pr_err(
+ "%s: copy_to_user for AUDIO_GET_g711_ENC_CONFIG failed",
+ __func__);
+ rc = -EFAULT;
+ }
+ break;
+ }
+ case AUDIO_SET_G711_ENC_CONFIG: {
+ struct msm_audio_g711_enc_config cfg;
+
+ if (copy_from_user(&cfg, (void *) arg,
+ sizeof(cfg))) {
+ pr_err(
+ "%s: copy_from_user for AUDIO_GET_G711_ENC_CONFIG failed",
+ __func__);
+ rc = -EFAULT;
+ break;
+ }
+ rc = g711_in_ioctl_shared(file, cmd, (unsigned long)&cfg);
+ if (rc)
+ pr_err("%s:AUDIO_GET_G711_ENC_CONFIG failed. Rc= %d\n",
+ __func__, rc);
+ break;
+ }
+ default:
+ pr_err("%s: Unknown ioctl cmd = %d", __func__, cmd);
+ rc = -ENOIOCTLCMD;
+ }
+ return rc;
+}
+
+#ifdef CONFIG_COMPAT
+struct msm_audio_g711_enc_config32 {
+ uint32_t sample_rate;
+};
+
+enum {
+ AUDIO_SET_G711_ENC_CONFIG_32 = _IOW(AUDIO_IOCTL_MAGIC,
+ (AUDIO_MAX_COMMON_IOCTL_NUM+0), struct msm_audio_g711_enc_config32),
+ AUDIO_GET_G711_ENC_CONFIG_32 = _IOR(AUDIO_IOCTL_MAGIC,
+ (AUDIO_MAX_COMMON_IOCTL_NUM+1), struct msm_audio_g711_enc_config32)
+};
+
+static long g711_in_compat_ioctl(struct file *file,
+ unsigned int cmd, unsigned long arg)
+{
+ struct q6audio_in *audio = file->private_data;
+ int rc = 0;
+
+ switch (cmd) {
+ case AUDIO_START:
+ case AUDIO_STOP: {
+ rc = g711_in_ioctl_shared(file, cmd, arg);
+ break;
+ }
+ case AUDIO_GET_G711_ENC_CONFIG_32: {
+ struct msm_audio_g711_enc_config32 cfg_32;
+ struct msm_audio_g711_enc_config32 *enc_cfg;
+
+ enc_cfg = (struct msm_audio_g711_enc_config32 *)audio->enc_cfg;
+ cfg_32.sample_rate = enc_cfg->sample_rate;
+ if (copy_to_user((void *)arg, &cfg_32,
+ sizeof(cfg_32))) {
+ pr_err("%s: copy_to_user for AUDIO_GET_G711_ENC_CONFIG_32 failed\n",
+ __func__);
+ rc = -EFAULT;
+ }
+ break;
+ }
+ case AUDIO_SET_G711_ENC_CONFIG_32: {
+ struct msm_audio_g711_enc_config32 cfg_32;
+ struct msm_audio_g711_enc_config32 cfg;
+
+ if (copy_from_user(&cfg_32, (void *) arg,
+ sizeof(cfg_32))) {
+ pr_err("%s: copy_from_user for AUDIO_SET_G711_ENC_CONFIG_32 failed\n",
+ __func__);
+ rc = -EFAULT;
+ break;
+ }
+ cfg.sample_rate = cfg_32.sample_rate;
+ cmd = AUDIO_SET_G711_ENC_CONFIG;
+ rc = g711_in_ioctl_shared(file, cmd, (unsigned long)&cfg);
+ if (rc)
+ pr_err("%s:AUDIO_SET_G711_ENC_CONFIG failed. rc= %d\n",
+ __func__, rc);
+ break;
+ }
+ default:
+ pr_err("%s: Unknown ioctl cmd = %d", __func__, cmd);
+ rc = -ENOIOCTLCMD;
+ }
+ return rc;
+}
+#else
+#define g711_in_compat_ioctl NULL
+#endif
+
+static int g711_in_open(struct inode *inode, struct file *file)
+{
+ struct q6audio_in *audio = NULL;
+ struct msm_audio_g711_enc_config *enc_cfg;
+ int rc = 0;
+
+ audio = kzalloc(sizeof(struct q6audio_in), GFP_KERNEL);
+
+ if (audio == NULL)
+ return -ENOMEM;
+ /* Allocate memory for encoder config param */
+ audio->enc_cfg = kzalloc(sizeof(struct msm_audio_g711_enc_config),
+ GFP_KERNEL);
+ if (audio->enc_cfg == NULL) {
+ kfree(audio);
+ return -ENOMEM;
+ }
+ enc_cfg = audio->enc_cfg;
+
+ mutex_init(&audio->lock);
+ mutex_init(&audio->read_lock);
+ mutex_init(&audio->write_lock);
+ spin_lock_init(&audio->dsp_lock);
+ init_waitqueue_head(&audio->read_wait);
+ init_waitqueue_head(&audio->write_wait);
+
+ /*
+ * Settings will be re-config at AUDIO_SET_CONFIG,
+ * but at least we need to have initial config
+ */
+ audio->str_cfg.buffer_size = FRAME_SIZE;
+ audio->str_cfg.buffer_count = FRAME_NUM;
+ audio->min_frame_size = 320;
+ audio->max_frames_per_buf = 10;
+ audio->pcm_cfg.buffer_size = PCM_BUF_SIZE;
+ audio->pcm_cfg.buffer_count = PCM_BUF_COUNT;
+ enc_cfg->sample_rate = 8000;
+ audio->pcm_cfg.channel_count = 1;
+ audio->pcm_cfg.sample_rate = 8000;
+ audio->buf_cfg.meta_info_enable = 0x01;
+ audio->buf_cfg.frames_per_buf = 0x01;
+ audio->event_abort = 0;
+
+ audio->ac = q6asm_audio_client_alloc((app_cb)q6asm_in_cb,
+ (void *)audio);
+
+ if (!audio->ac) {
+ kfree(audio->enc_cfg);
+ kfree(audio);
+ return -ENOMEM;
+ }
+
+ /* open g711 encoder in T/NT mode */
+ if ((file->f_mode & FMODE_WRITE) &&
+ (file->f_mode & FMODE_READ)) {
+ audio->feedback = NON_TUNNEL_MODE;
+ rc = q6asm_open_read_write(audio->ac, FORMAT_G711_MLAW_FS,
+ FORMAT_LINEAR_PCM);
+ if (rc < 0) {
+ pr_err("%s:session id %d: NT mode Open failed rc=%d\n",
+ __func__, audio->ac->session, rc);
+ rc = -ENODEV;
+ goto fail;
+ }
+ } else if (!(file->f_mode & FMODE_WRITE) &&
+ (file->f_mode & FMODE_READ)) {
+ audio->feedback = TUNNEL_MODE;
+ rc = q6asm_open_read(audio->ac, FORMAT_G711_MLAW_FS);
+ if (rc < 0) {
+ pr_err("%s:session id %d: T mode Open failed rc=%d\n",
+ __func__, audio->ac->session, rc);
+ rc = -ENODEV;
+ goto fail;
+ }
+ /* register for tx overflow (valid for tunnel mode only) */
+ rc = q6asm_reg_tx_overflow(audio->ac, 0x01);
+ if (rc < 0) {
+ pr_err("%s:session id %d: TX Overflow registration failed rc=%d\n",
+ __func__, audio->ac->session, rc);
+ rc = -ENODEV;
+ goto fail;
+ }
+ } else {
+ pr_err("%s:session id %d: Unexpected mode\n", __func__,
+ audio->ac->session);
+ rc = -EACCES;
+ goto fail;
+ }
+
+ audio->opened = 1;
+ audio->reset_event = false;
+ atomic_set(&audio->in_count, PCM_BUF_COUNT);
+ atomic_set(&audio->out_count, 0x00);
+ audio->enc_compat_ioctl = g711_in_compat_ioctl;
+ audio->enc_ioctl = g711_in_ioctl;
+ file->private_data = audio;
+
+ pr_info("%s:session id %d: success\n", __func__, audio->ac->session);
+ return 0;
+fail:
+ q6asm_audio_client_free(audio->ac);
+ kfree(audio->enc_cfg);
+ kfree(audio);
+ return rc;
+}
+
+static const struct file_operations audio_in_fops = {
+ .owner = THIS_MODULE,
+ .open = g711_in_open,
+ .release = audio_in_release,
+ .read = audio_in_read,
+ .write = audio_in_write,
+ .unlocked_ioctl = audio_in_ioctl,
+#ifdef CONFIG_COMPAT
+ .compat_ioctl = audio_in_compat_ioctl,
+#endif
+};
+
+struct miscdevice audio_g711mlaw_in_misc = {
+ .minor = MISC_DYNAMIC_MINOR,
+ .name = "msm_g711mlaw_in",
+ .fops = &audio_in_fops,
+};
+
+static int __init g711mlaw_in_init(void)
+{
+ return misc_register(&audio_g711mlaw_in_misc);
+}
+
+device_initcall(g711mlaw_in_init);
diff --git a/drivers/misc/qseecom.c b/drivers/misc/qseecom.c
index 457629ee4bf5..4fd845ab4086 100644
--- a/drivers/misc/qseecom.c
+++ b/drivers/misc/qseecom.c
@@ -1293,9 +1293,11 @@ static int __qseecom_set_msm_bus_request(uint32_t mode)
pr_err("Bandwidth req failed(%d) MODE (%d)\n",
ret, mode);
if (qclk->ce_core_src_clk != NULL) {
- if (mode == INACTIVE)
- __qseecom_enable_clk(CLK_QSEE);
- else
+ if (mode == INACTIVE) {
+ ret = __qseecom_enable_clk(CLK_QSEE);
+ if (ret)
+ pr_err("CLK enable failed\n");
+ } else
__qseecom_disable_clk(CLK_QSEE);
}
}
@@ -1603,12 +1605,21 @@ static int __qseecom_qseos_fail_return_resp_tz(struct qseecom_dev_handle *data,
if (ptr_svc)
pr_warn("listener_id:%x, lstnr: %x\n",
ptr_svc->svc.listener_id, lstnr);
- if (ptr_svc && ptr_svc->ihandle)
- msm_ion_do_cache_op(qseecom.ion_clnt, ptr_svc->ihandle,
+ if (ptr_svc && ptr_svc->ihandle) {
+ ret = msm_ion_do_cache_op(qseecom.ion_clnt, ptr_svc->ihandle,
ptr_svc->sb_virt, ptr_svc->sb_length,
ION_IOC_CLEAN_INV_CACHES);
- if (lstnr == RPMB_SERVICE)
- __qseecom_enable_clk(CLK_QSEE);
+ if (ret) {
+ pr_err("cache operation failed %d\n", ret);
+ return ret;
+ }
+ }
+
+ if (lstnr == RPMB_SERVICE) {
+ ret = __qseecom_enable_clk(CLK_QSEE);
+ if (ret)
+ return ret;
+ }
ret = qseecom_scm_call(SCM_SVC_TZSCHEDULER, 1, send_data_rsp,
sizeof(send_data_rsp), resp, sizeof(*resp));
if (ret) {
@@ -1764,13 +1775,22 @@ static int __qseecom_process_incomplete_cmd(struct qseecom_dev_handle *data,
else
*(uint32_t *)cmd_buf =
QSEOS_LISTENER_DATA_RSP_COMMAND_WHITELIST;
- if (ptr_svc)
- msm_ion_do_cache_op(qseecom.ion_clnt, ptr_svc->ihandle,
+ if (ptr_svc) {
+ ret = msm_ion_do_cache_op(qseecom.ion_clnt,
+ ptr_svc->ihandle,
ptr_svc->sb_virt, ptr_svc->sb_length,
- ION_IOC_CLEAN_INV_CACHES);
+ ION_IOC_CLEAN_INV_CACHES);
+ if (ret) {
+ pr_err("cache operation failed %d\n", ret);
+ return ret;
+ }
+ }
- if ((lstnr == RPMB_SERVICE) || (lstnr == SSD_SERVICE))
- __qseecom_enable_clk(CLK_QSEE);
+ if ((lstnr == RPMB_SERVICE) || (lstnr == SSD_SERVICE)) {
+ ret = __qseecom_enable_clk(CLK_QSEE);
+ if (ret)
+ return ret;
+ }
ret = qseecom_scm_call(SCM_SVC_TZSCHEDULER, 1,
cmd_buf, cmd_len, resp, sizeof(*resp));
@@ -2005,13 +2025,21 @@ static int __qseecom_reentrancy_process_incomplete_cmd(
else
*(uint32_t *)cmd_buf =
QSEOS_LISTENER_DATA_RSP_COMMAND_WHITELIST;
- if (ptr_svc)
- msm_ion_do_cache_op(qseecom.ion_clnt, ptr_svc->ihandle,
+ if (ptr_svc) {
+ ret = msm_ion_do_cache_op(qseecom.ion_clnt,
+ ptr_svc->ihandle,
ptr_svc->sb_virt, ptr_svc->sb_length,
- ION_IOC_CLEAN_INV_CACHES);
-
- if (lstnr == RPMB_SERVICE)
- __qseecom_enable_clk(CLK_QSEE);
+ ION_IOC_CLEAN_INV_CACHES);
+ if (ret) {
+ pr_err("cache operation failed %d\n", ret);
+ return ret;
+ }
+ }
+ if (lstnr == RPMB_SERVICE) {
+ ret = __qseecom_enable_clk(CLK_QSEE);
+ if (ret)
+ return ret;
+ }
ret = qseecom_scm_call(SCM_SVC_TZSCHEDULER, 1,
cmd_buf, cmd_len, resp, sizeof(*resp));
@@ -2297,8 +2325,12 @@ static int qseecom_load_app(struct qseecom_dev_handle *data, void __user *argp)
cmd_len = sizeof(struct qseecom_load_app_64bit_ireq);
}
- msm_ion_do_cache_op(qseecom.ion_clnt, ihandle, NULL, len,
+ ret = msm_ion_do_cache_op(qseecom.ion_clnt, ihandle, NULL, len,
ION_IOC_CLEAN_INV_CACHES);
+ if (ret) {
+ pr_err("cache operation failed %d\n", ret);
+ goto loadapp_err;
+ }
/* SCM_CALL to load the app and get the app_id back */
ret = qseecom_scm_call(SCM_SVC_TZSCHEDULER, 1, cmd_buf,
@@ -2776,15 +2808,16 @@ static int qseecom_send_service_cmd(struct qseecom_dev_handle *data,
}
}
- msm_ion_do_cache_op(qseecom.ion_clnt, data->client.ihandle,
+ ret = msm_ion_do_cache_op(qseecom.ion_clnt, data->client.ihandle,
data->client.sb_virt, data->client.sb_length,
ION_IOC_CLEAN_INV_CACHES);
+ if (ret) {
+ pr_err("cache operation failed %d\n", ret);
+ goto exit;
+ }
ret = qseecom_scm_call(SCM_SVC_TZSCHEDULER, 1,
(const void *)send_req_ptr,
req_buf_size, &resp, sizeof(resp));
- msm_ion_do_cache_op(qseecom.ion_clnt, data->client.ihandle,
- data->client.sb_virt, data->client.sb_length,
- ION_IOC_INV_CACHES);
if (ret) {
pr_err("qseecom_scm_call failed with err: %d\n", ret);
if (!qseecom.support_bus_scaling) {
@@ -2796,7 +2829,13 @@ static int qseecom_send_service_cmd(struct qseecom_dev_handle *data,
}
goto exit;
}
-
+ ret = msm_ion_do_cache_op(qseecom.ion_clnt, data->client.ihandle,
+ data->client.sb_virt, data->client.sb_length,
+ ION_IOC_INV_CACHES);
+ if (ret) {
+ pr_err("cache operation failed %d\n", ret);
+ goto exit;
+ }
switch (resp.result) {
case QSEOS_RESULT_SUCCESS:
break;
@@ -3029,10 +3068,14 @@ static int __qseecom_send_cmd(struct qseecom_dev_handle *data,
else
*(uint32_t *)cmd_buf = QSEOS_CLIENT_SEND_DATA_COMMAND_WHITELIST;
- msm_ion_do_cache_op(qseecom.ion_clnt, data->client.ihandle,
+ ret = msm_ion_do_cache_op(qseecom.ion_clnt, data->client.ihandle,
data->client.sb_virt,
reqd_len_sb_in,
ION_IOC_CLEAN_INV_CACHES);
+ if (ret) {
+ pr_err("cache operation failed %d\n", ret);
+ return ret;
+ }
__qseecom_reentrancy_check_if_this_app_blocked(ptr_app);
@@ -3063,9 +3106,11 @@ static int __qseecom_send_cmd(struct qseecom_dev_handle *data,
}
}
}
- msm_ion_do_cache_op(qseecom.ion_clnt, data->client.ihandle,
+ ret = msm_ion_do_cache_op(qseecom.ion_clnt, data->client.ihandle,
data->client.sb_virt, data->client.sb_length,
ION_IOC_INV_CACHES);
+ if (ret)
+ pr_err("cache operation failed %d\n", ret);
return ret;
}
@@ -3177,7 +3222,7 @@ static int __qseecom_update_cmd_buf(void *msg, bool cleanup,
}
/* Populate the cmd data structure with the phys_addr */
sg_ptr = ion_sg_table(qseecom.ion_clnt, ihandle);
- if (sg_ptr == NULL) {
+ if (IS_ERR_OR_NULL(sg_ptr)) {
pr_err("IOn client could not retrieve sg table\n");
goto err;
}
@@ -3285,13 +3330,21 @@ static int __qseecom_update_cmd_buf(void *msg, bool cleanup,
}
if (cleanup) {
- msm_ion_do_cache_op(qseecom.ion_clnt,
+ ret = msm_ion_do_cache_op(qseecom.ion_clnt,
ihandle, NULL, len,
ION_IOC_INV_CACHES);
+ if (ret) {
+ pr_err("cache operation failed %d\n", ret);
+ goto err;
+ }
} else {
- msm_ion_do_cache_op(qseecom.ion_clnt,
+ ret = msm_ion_do_cache_op(qseecom.ion_clnt,
ihandle, NULL, len,
ION_IOC_CLEAN_INV_CACHES);
+ if (ret) {
+ pr_err("cache operation failed %d\n", ret);
+ goto err;
+ }
if (data->type == QSEECOM_CLIENT_APP) {
offset = req->ifd_data[i].cmd_buf_offset;
data->sglistinfo_ptr[i].indexAndFlags =
@@ -3432,7 +3485,7 @@ static int __qseecom_update_cmd_buf_64(void *msg, bool cleanup,
}
/* Populate the cmd data structure with the phys_addr */
sg_ptr = ion_sg_table(qseecom.ion_clnt, ihandle);
- if (sg_ptr == NULL) {
+ if (IS_ERR_OR_NULL(sg_ptr)) {
pr_err("IOn client could not retrieve sg table\n");
goto err;
}
@@ -3515,13 +3568,21 @@ static int __qseecom_update_cmd_buf_64(void *msg, bool cleanup,
}
cleanup:
if (cleanup) {
- msm_ion_do_cache_op(qseecom.ion_clnt,
+ ret = msm_ion_do_cache_op(qseecom.ion_clnt,
ihandle, NULL, len,
ION_IOC_INV_CACHES);
+ if (ret) {
+ pr_err("cache operation failed %d\n", ret);
+ goto err;
+ }
} else {
- msm_ion_do_cache_op(qseecom.ion_clnt,
+ ret = msm_ion_do_cache_op(qseecom.ion_clnt,
ihandle, NULL, len,
ION_IOC_CLEAN_INV_CACHES);
+ if (ret) {
+ pr_err("cache operation failed %d\n", ret);
+ goto err;
+ }
if (data->type == QSEECOM_CLIENT_APP) {
offset = req->ifd_data[i].cmd_buf_offset;
data->sglistinfo_ptr[i].indexAndFlags =
@@ -4010,9 +4071,13 @@ static int __qseecom_load_fw(struct qseecom_dev_handle *data, char *appname)
goto exit_unregister_bus_bw_need;
}
- msm_ion_do_cache_op(qseecom.ion_clnt, ihandle,
+ ret = msm_ion_do_cache_op(qseecom.ion_clnt, ihandle,
img_data, fw_size,
ION_IOC_CLEAN_INV_CACHES);
+ if (ret) {
+ pr_err("cache operation failed %d\n", ret);
+ goto exit_disable_clk_vote;
+ }
/* SCM_CALL to load the image */
ret = qseecom_scm_call(SCM_SVC_TZSCHEDULER, 1, cmd_buf, cmd_len,
@@ -4126,9 +4191,13 @@ static int qseecom_load_commonlib_image(struct qseecom_dev_handle *data,
goto exit_unregister_bus_bw_need;
}
- msm_ion_do_cache_op(qseecom.ion_clnt, qseecom.cmnlib_ion_handle,
+ ret = msm_ion_do_cache_op(qseecom.ion_clnt, qseecom.cmnlib_ion_handle,
img_data, fw_size,
ION_IOC_CLEAN_INV_CACHES);
+ if (ret) {
+ pr_err("cache operation failed %d\n", ret);
+ goto exit_disable_clk_vote;
+ }
/* SCM_CALL to load the image */
ret = qseecom_scm_call(SCM_SVC_TZSCHEDULER, 1, cmd_buf, cmd_len,
@@ -4694,9 +4763,10 @@ static int __qseecom_enable_clk(enum qseecom_ce_hw_instance ce)
}
mutex_lock(&clk_access_lock);
- if (qclk->clk_access_cnt == ULONG_MAX)
+ if (qclk->clk_access_cnt == ULONG_MAX) {
+ pr_err("clk_access_cnt beyond limitation\n");
goto err;
-
+ }
if (qclk->clk_access_cnt > 0) {
qclk->clk_access_cnt++;
mutex_unlock(&clk_access_lock);
@@ -5009,9 +5079,12 @@ static int qseecom_load_external_elf(struct qseecom_dev_handle *data,
ret = -EIO;
goto exit_register_bus_bandwidth_needs;
}
- msm_ion_do_cache_op(qseecom.ion_clnt, ihandle, NULL, len,
+ ret = msm_ion_do_cache_op(qseecom.ion_clnt, ihandle, NULL, len,
ION_IOC_CLEAN_INV_CACHES);
-
+ if (ret) {
+ pr_err("cache operation failed %d\n", ret);
+ goto exit_disable_clock;
+ }
/* SCM_CALL to load the external elf */
ret = qseecom_scm_call(SCM_SVC_TZSCHEDULER, 1, cmd_buf, cmd_len,
&resp, sizeof(resp));
@@ -5257,7 +5330,9 @@ static int __qseecom_generate_and_save_key(struct qseecom_dev_handle *data,
pr_err("Error:: unsupported usage %d\n", usage);
return -EFAULT;
}
- __qseecom_enable_clk(CLK_QSEE);
+ ret = __qseecom_enable_clk(CLK_QSEE);
+ if (ret)
+ return ret;
ret = qseecom_scm_call(SCM_SVC_TZSCHEDULER, 1,
ireq, sizeof(struct qseecom_key_generate_ireq),
@@ -5315,7 +5390,9 @@ static int __qseecom_delete_saved_key(struct qseecom_dev_handle *data,
pr_err("Error:: unsupported usage %d\n", usage);
return -EFAULT;
}
- __qseecom_enable_clk(CLK_QSEE);
+ ret = __qseecom_enable_clk(CLK_QSEE);
+ if (ret)
+ return ret;
ret = qseecom_scm_call(SCM_SVC_TZSCHEDULER, 1,
ireq, sizeof(struct qseecom_key_delete_ireq),
@@ -5374,10 +5451,15 @@ static int __qseecom_set_clear_ce_key(struct qseecom_dev_handle *data,
pr_err("Error:: unsupported usage %d\n", usage);
return -EFAULT;
}
+ ret = __qseecom_enable_clk(CLK_QSEE);
+ if (ret)
+ return ret;
- __qseecom_enable_clk(CLK_QSEE);
- if (qseecom.qsee.instance != qseecom.ce_drv.instance)
- __qseecom_enable_clk(CLK_CE_DRV);
+ if (qseecom.qsee.instance != qseecom.ce_drv.instance) {
+ ret = __qseecom_enable_clk(CLK_CE_DRV);
+ if (ret)
+ return ret;
+ }
ret = qseecom_scm_call(SCM_SVC_TZSCHEDULER, 1,
ireq, sizeof(struct qseecom_key_select_ireq),
@@ -5452,8 +5534,9 @@ static int __qseecom_update_current_key_user_info(
pr_err("Error:: unsupported usage %d\n", usage);
return -EFAULT;
}
-
- __qseecom_enable_clk(CLK_QSEE);
+ ret = __qseecom_enable_clk(CLK_QSEE);
+ if (ret)
+ return ret;
ret = qseecom_scm_call(SCM_SVC_TZSCHEDULER, 1,
ireq, sizeof(struct qseecom_key_userinfo_update_ireq),
@@ -5994,7 +6077,9 @@ static int qseecom_mdtp_cipher_dip(void __user *argp)
desc.args[3] = req.out_buf_size;
desc.args[4] = req.direction;
- __qseecom_enable_clk(CLK_QSEE);
+ ret = __qseecom_enable_clk(CLK_QSEE);
+ if (ret)
+ break;
ret = scm_call2(TZ_MDTP_CIPHER_DIP_ID, &desc);
@@ -6181,7 +6266,7 @@ static int __qseecom_update_qteec_req_buf(struct qseecom_qteec_modfd_req *req,
}
/* Populate the cmd data structure with the phys_addr */
sg_ptr = ion_sg_table(qseecom.ion_clnt, ihandle);
- if (sg_ptr == NULL) {
+ if (IS_ERR_OR_NULL(sg_ptr)) {
pr_err("IOn client could not retrieve sg table\n");
goto err;
}
@@ -6237,13 +6322,21 @@ static int __qseecom_update_qteec_req_buf(struct qseecom_qteec_modfd_req *req,
}
clean:
if (cleanup) {
- msm_ion_do_cache_op(qseecom.ion_clnt,
+ ret = msm_ion_do_cache_op(qseecom.ion_clnt,
ihandle, NULL, sg->length,
ION_IOC_INV_CACHES);
+ if (ret) {
+ pr_err("cache operation failed %d\n", ret);
+ goto err;
+ }
} else {
- msm_ion_do_cache_op(qseecom.ion_clnt,
+ ret = msm_ion_do_cache_op(qseecom.ion_clnt,
ihandle, NULL, sg->length,
ION_IOC_CLEAN_INV_CACHES);
+ if (ret) {
+ pr_err("cache operation failed %d\n", ret);
+ goto err;
+ }
data->sglistinfo_ptr[i].indexAndFlags =
SGLISTINFO_SET_INDEX_FLAG(
(sg_ptr->nents == 1), 0,
@@ -6356,10 +6449,14 @@ static int __qseecom_qteec_issue_cmd(struct qseecom_dev_handle *data,
*(uint32_t *)cmd_buf = cmd_id;
reqd_len_sb_in = req->req_len + req->resp_len;
- msm_ion_do_cache_op(qseecom.ion_clnt, data->client.ihandle,
+ ret = msm_ion_do_cache_op(qseecom.ion_clnt, data->client.ihandle,
data->client.sb_virt,
reqd_len_sb_in,
ION_IOC_CLEAN_INV_CACHES);
+ if (ret) {
+ pr_err("cache operation failed %d\n", ret);
+ return ret;
+ }
__qseecom_reentrancy_check_if_this_app_blocked(ptr_app);
@@ -6390,9 +6487,13 @@ static int __qseecom_qteec_issue_cmd(struct qseecom_dev_handle *data,
}
}
}
- msm_ion_do_cache_op(qseecom.ion_clnt, data->client.ihandle,
+ ret = msm_ion_do_cache_op(qseecom.ion_clnt, data->client.ihandle,
data->client.sb_virt, data->client.sb_length,
ION_IOC_INV_CACHES);
+ if (ret) {
+ pr_err("cache operation failed %d\n", ret);
+ return ret;
+ }
if ((cmd_id == QSEOS_TEE_OPEN_SESSION) ||
(cmd_id == QSEOS_TEE_REQUEST_CANCELLATION)) {
@@ -6536,10 +6637,14 @@ static int qseecom_qteec_invoke_modfd_cmd(struct qseecom_dev_handle *data,
else
*(uint32_t *)cmd_buf = QSEOS_TEE_INVOKE_COMMAND;
- msm_ion_do_cache_op(qseecom.ion_clnt, data->client.ihandle,
+ ret = msm_ion_do_cache_op(qseecom.ion_clnt, data->client.ihandle,
data->client.sb_virt,
reqd_len_sb_in,
ION_IOC_CLEAN_INV_CACHES);
+ if (ret) {
+ pr_err("cache operation failed %d\n", ret);
+ return ret;
+ }
__qseecom_reentrancy_check_if_this_app_blocked(ptr_app);
@@ -6574,9 +6679,13 @@ static int qseecom_qteec_invoke_modfd_cmd(struct qseecom_dev_handle *data,
if (ret)
return ret;
- msm_ion_do_cache_op(qseecom.ion_clnt, data->client.ihandle,
+ ret = msm_ion_do_cache_op(qseecom.ion_clnt, data->client.ihandle,
data->client.sb_virt, data->client.sb_length,
ION_IOC_INV_CACHES);
+ if (ret) {
+ pr_err("cache operation failed %d\n", ret);
+ return ret;
+ }
return 0;
}
diff --git a/drivers/mmc/card/block.c b/drivers/mmc/card/block.c
index 6eee4aa0e574..39cb46a5ce11 100644
--- a/drivers/mmc/card/block.c
+++ b/drivers/mmc/card/block.c
@@ -3456,7 +3456,8 @@ static void mmc_blk_cmdq_err(struct mmc_queue *mq)
struct mmc_request *mrq = host->err_mrq;
struct mmc_cmdq_context_info *ctx_info = &host->cmdq_ctx;
struct request_queue *q;
- int err;
+ int err, ret;
+ u32 status = 0;
mmc_host_clk_hold(host);
host->cmdq_ops->dumpstate(host);
@@ -3475,8 +3476,14 @@ static void mmc_blk_cmdq_err(struct mmc_queue *mq)
/* RED error - Fatal: requires reset */
if (mrq->cmdq_req->resp_err) {
err = mrq->cmdq_req->resp_err;
- pr_crit("%s: Response error detected: Device in bad state\n",
- mmc_hostname(host));
+ if (mmc_host_halt(host) || mmc_host_cq_disable(host)) {
+ ret = get_card_status(host->card, &status, 0);
+ if (ret)
+ pr_err("%s: CMD13 failed with err %d\n",
+ mmc_hostname(host), ret);
+ }
+ pr_err("%s: Response error detected with device status 0x%08x\n",
+ mmc_hostname(host), status);
goto reset;
}
diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c
index 828d2b85f6e4..6ad91042409e 100644
--- a/drivers/mmc/core/core.c
+++ b/drivers/mmc/core/core.c
@@ -1552,6 +1552,12 @@ int mmc_cmdq_halt(struct mmc_host *host, bool halt)
{
int err = 0;
+ if (mmc_host_cq_disable(host)) {
+ pr_debug("%s: %s: CQE is already disabled\n",
+ mmc_hostname(host), __func__);
+ return 0;
+ }
+
if ((halt && mmc_host_halt(host)) ||
(!halt && !mmc_host_halt(host))) {
pr_debug("%s: %s: CQE is already %s\n", mmc_hostname(host),
diff --git a/drivers/mmc/host/cmdq_hci.c b/drivers/mmc/host/cmdq_hci.c
index 0e0a018f39be..52427815722b 100644
--- a/drivers/mmc/host/cmdq_hci.c
+++ b/drivers/mmc/host/cmdq_hci.c
@@ -863,8 +863,16 @@ skip_cqterri:
* If CQE halt fails then, disable CQE
* from processing any further requests
*/
- if (ret)
+ if (ret) {
cmdq_disable_nosync(mmc, true);
+ /*
+ * Enable legacy interrupts as CQE halt has failed.
+ * This is needed to send legacy commands like status
+ * cmd as part of error handling work.
+ */
+ if (cq_host->ops->clear_set_irqs)
+ cq_host->ops->clear_set_irqs(mmc, false);
+ }
/*
* CQE detected a reponse error from device
diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c
index 0542ba51445f..886229317fea 100644
--- a/drivers/mmc/host/sdhci.c
+++ b/drivers/mmc/host/sdhci.c
@@ -3157,7 +3157,7 @@ static irqreturn_t sdhci_irq(int irq, void *dev_id)
do {
if (host->mmc->card && mmc_card_cmdq(host->mmc->card) &&
- !mmc_host_halt(host->mmc)) {
+ !mmc_host_halt(host->mmc) && !mmc_host_cq_disable(host->mmc)) {
pr_debug("*** %s: cmdq intr: 0x%08x\n",
mmc_hostname(host->mmc),
intmask);
diff --git a/drivers/net/wireless/ath/wil6210/ftm.c b/drivers/net/wireless/ath/wil6210/ftm.c
index 5cf07343a33c..6891a38d7a59 100644
--- a/drivers/net/wireless/ath/wil6210/ftm.c
+++ b/drivers/net/wireless/ath/wil6210/ftm.c
@@ -52,6 +52,7 @@ nla_policy wil_nl80211_loc_policy[QCA_WLAN_VENDOR_ATTR_LOC_MAX + 1] = {
[QCA_WLAN_VENDOR_ATTR_FTM_INITIAL_TOKEN] = { .type = NLA_U8 },
[QCA_WLAN_VENDOR_ATTR_AOA_TYPE] = { .type = NLA_U32 },
[QCA_WLAN_VENDOR_ATTR_LOC_ANTENNA_ARRAY_MASK] = { .type = NLA_U32 },
+ [QCA_WLAN_VENDOR_ATTR_FREQ] = { .type = NLA_U32 },
};
static const struct
@@ -61,6 +62,7 @@ nla_policy wil_nl80211_ftm_peer_policy[
[QCA_WLAN_VENDOR_ATTR_FTM_PEER_MEAS_FLAGS] = { .type = NLA_U32 },
[QCA_WLAN_VENDOR_ATTR_FTM_PEER_MEAS_PARAMS] = { .type = NLA_NESTED },
[QCA_WLAN_VENDOR_ATTR_FTM_PEER_SECURE_TOKEN_ID] = { .type = NLA_U8 },
+ [QCA_WLAN_VENDOR_ATTR_FTM_PEER_FREQ] = { .type = NLA_U32 },
};
static const struct
@@ -72,6 +74,37 @@ nla_policy wil_nl80211_ftm_meas_param_policy[
[QCA_WLAN_VENDOR_ATTR_FTM_PARAM_BURST_PERIOD] = { .type = NLA_U16 },
};
+static u8 wil_ftm_get_channel(struct wil6210_priv *wil,
+ const u8 *mac_addr, u32 freq)
+{
+ struct wiphy *wiphy = wil_to_wiphy(wil);
+ struct cfg80211_bss *bss;
+ struct ieee80211_channel *chan;
+ u8 channel;
+
+ if (freq) {
+ chan = ieee80211_get_channel(wiphy, freq);
+ if (!chan) {
+ wil_err(wil, "invalid freq: %d\n", freq);
+ return 0;
+ }
+ channel = chan->hw_value;
+ } else {
+ bss = cfg80211_get_bss(wiphy, NULL, mac_addr,
+ NULL, 0, IEEE80211_BSS_TYPE_ANY,
+ IEEE80211_PRIVACY_ANY);
+ if (!bss) {
+ wil_err(wil, "Unable to find BSS\n");
+ return 0;
+ }
+ channel = bss->channel->hw_value;
+ cfg80211_put_bss(wiphy, bss);
+ }
+
+ wil_dbg_misc(wil, "target %pM at channel %d\n", mac_addr, channel);
+ return channel;
+}
+
static int wil_ftm_parse_meas_params(struct wil6210_priv *wil,
struct nlattr *attr,
struct wil_ftm_meas_params *params)
@@ -273,7 +306,7 @@ wil_ftm_cfg80211_start_session(struct wil6210_priv *wil,
{
int rc = 0;
bool has_lci = false, has_lcr = false;
- u8 max_meas = 0, *ptr;
+ u8 max_meas = 0, channel, *ptr;
u32 i, cmd_len;
struct wmi_tof_session_start_cmd *cmd;
@@ -283,12 +316,6 @@ wil_ftm_cfg80211_start_session(struct wil6210_priv *wil,
rc = -EAGAIN;
goto out;
}
- /* for now allow measurement to associated AP only */
- if (!test_bit(wil_status_fwconnected, wil->status)) {
- wil_err(wil, "must be associated\n");
- rc = -ENOTSUPP;
- goto out;
- }
for (i = 0; i < request->n_peers; i++) {
if (request->peers[i].flags &
@@ -333,7 +360,14 @@ wil_ftm_cfg80211_start_session(struct wil6210_priv *wil,
for (i = 0; i < request->n_peers; i++) {
ether_addr_copy(cmd->ftm_dest_info[i].dst_mac,
request->peers[i].mac_addr);
- cmd->ftm_dest_info[i].channel = request->peers[i].channel;
+ channel = wil_ftm_get_channel(wil, request->peers[i].mac_addr,
+ request->peers[i].freq);
+ if (!channel) {
+ wil_err(wil, "can't find FTM target at index %d\n", i);
+ rc = -EINVAL;
+ goto out_cmd;
+ }
+ cmd->ftm_dest_info[i].channel = channel - 1;
if (request->peers[i].flags &
QCA_WLAN_VENDOR_ATTR_FTM_PEER_MEAS_FLAG_SECURE) {
cmd->ftm_dest_info[i].flags |=
@@ -367,14 +401,13 @@ wil_ftm_cfg80211_start_session(struct wil6210_priv *wil,
}
rc = wmi_send(wil, WMI_TOF_SESSION_START_CMDID, cmd, cmd_len);
- kfree(cmd);
-
- if (rc)
- goto out_ftm_res;
-
- wil->ftm.session_cookie = request->session_cookie;
- wil->ftm.session_started = 1;
+ if (!rc) {
+ wil->ftm.session_cookie = request->session_cookie;
+ wil->ftm.session_started = 1;
+ }
+out_cmd:
+ kfree(cmd);
out_ftm_res:
if (rc) {
kfree(wil->ftm.ftm_res);
@@ -444,8 +477,8 @@ wil_aoa_cfg80211_start_measurement(struct wil6210_priv *wil,
struct wil_aoa_meas_request *request)
{
int rc = 0;
- struct cfg80211_bss *bss;
struct wmi_aoa_meas_cmd cmd;
+ u8 channel;
mutex_lock(&wil->ftm.lock);
@@ -460,30 +493,25 @@ wil_aoa_cfg80211_start_measurement(struct wil6210_priv *wil,
goto out;
}
- bss = cfg80211_get_bss(wil_to_wiphy(wil), NULL, request->mac_addr,
- NULL, 0,
- IEEE80211_BSS_TYPE_ANY, IEEE80211_PRIVACY_ANY);
- if (!bss) {
- wil_err(wil, "Unable to find BSS\n");
- rc = -ENOENT;
+ channel = wil_ftm_get_channel(wil, request->mac_addr, request->freq);
+ if (!channel) {
+ rc = -EINVAL;
goto out;
}
memset(&cmd, 0, sizeof(cmd));
ether_addr_copy(cmd.mac_addr, request->mac_addr);
- cmd.channel = bss->channel->hw_value - 1;
+ cmd.channel = channel - 1;
cmd.aoa_meas_type = request->type;
rc = wmi_send(wil, WMI_AOA_MEAS_CMDID, &cmd, sizeof(cmd));
if (rc)
- goto out_bss;
+ goto out;
ether_addr_copy(wil->ftm.aoa_peer_mac_addr, request->mac_addr);
mod_timer(&wil->ftm.aoa_timer,
jiffies + msecs_to_jiffies(WIL_AOA_MEASUREMENT_TIMEOUT));
wil->ftm.aoa_started = 1;
-out_bss:
- cfg80211_put_bss(wil_to_wiphy(wil), bss);
out:
mutex_unlock(&wil->ftm.lock);
return rc;
@@ -721,7 +749,6 @@ int wil_ftm_start_session(struct wiphy *wiphy, struct wireless_dev *wdev,
struct nlattr *tb2[QCA_WLAN_VENDOR_ATTR_FTM_PEER_MAX + 1];
struct nlattr *peer;
int rc, n_peers = 0, index = 0, tmp;
- struct cfg80211_bss *bss;
if (!test_bit(WMI_FW_CAPABILITY_FTM, wil->fw_capabilities))
return -ENOTSUPP;
@@ -785,17 +812,9 @@ int wil_ftm_start_session(struct wiphy *wiphy, struct wireless_dev *wdev,
memcpy(request->peers[index].mac_addr,
nla_data(tb2[QCA_WLAN_VENDOR_ATTR_FTM_PEER_MAC_ADDR]),
ETH_ALEN);
- bss = cfg80211_get_bss(wiphy, NULL,
- request->peers[index].mac_addr, NULL, 0,
- IEEE80211_BSS_TYPE_ANY,
- IEEE80211_PRIVACY_ANY);
- if (!bss) {
- wil_err(wil, "invalid bss at index %d\n", index);
- rc = -ENOENT;
- goto out;
- }
- request->peers[index].channel = bss->channel->hw_value - 1;
- cfg80211_put_bss(wiphy, bss);
+ if (tb2[QCA_WLAN_VENDOR_ATTR_FTM_PEER_FREQ])
+ request->peers[index].freq = nla_get_u32(
+ tb2[QCA_WLAN_VENDOR_ATTR_FTM_PEER_FREQ]);
if (tb2[QCA_WLAN_VENDOR_ATTR_FTM_PEER_MEAS_FLAGS])
request->peers[index].flags = nla_get_u32(
tb2[QCA_WLAN_VENDOR_ATTR_FTM_PEER_MEAS_FLAGS]);
@@ -868,6 +887,8 @@ int wil_aoa_start_measurement(struct wiphy *wiphy, struct wireless_dev *wdev,
ether_addr_copy(request.mac_addr,
nla_data(tb[QCA_WLAN_VENDOR_ATTR_MAC_ADDR]));
request.type = nla_get_u32(tb[QCA_WLAN_VENDOR_ATTR_AOA_TYPE]);
+ if (tb[QCA_WLAN_VENDOR_ATTR_FREQ])
+ request.freq = nla_get_u32(tb[QCA_WLAN_VENDOR_ATTR_FREQ]);
rc = wil_aoa_cfg80211_start_measurement(wil, &request);
return rc;
diff --git a/drivers/net/wireless/ath/wil6210/ftm.h b/drivers/net/wireless/ath/wil6210/ftm.h
index 9721344579aa..ea186d641d59 100644
--- a/drivers/net/wireless/ath/wil6210/ftm.h
+++ b/drivers/net/wireless/ath/wil6210/ftm.h
@@ -77,6 +77,8 @@
* %QCA_WLAN_VENDOR_ATTR_AOA_TYPE_TOP_CIR_PHASE_AMP: array of 2 U16
* values, phase and amplitude of the strongest CIR path for each
* antenna in the measured array(s)
+ * @QCA_WLAN_VENDOR_ATTR_FREQ: Frequency where peer is listening, in MHz.
+ * Unsigned 32 bit value.
*/
enum qca_wlan_vendor_attr_loc {
/* we reuse these attributes */
@@ -94,6 +96,7 @@ enum qca_wlan_vendor_attr_loc {
QCA_WLAN_VENDOR_ATTR_AOA_TYPE = 23,
QCA_WLAN_VENDOR_ATTR_LOC_ANTENNA_ARRAY_MASK = 24,
QCA_WLAN_VENDOR_ATTR_AOA_MEAS_RESULT = 25,
+ QCA_WLAN_VENDOR_ATTR_FREQ = 26,
/* keep last */
QCA_WLAN_VENDOR_ATTR_LOC_AFTER_LAST,
QCA_WLAN_VENDOR_ATTR_LOC_MAX = QCA_WLAN_VENDOR_ATTR_LOC_AFTER_LAST - 1,
@@ -176,6 +179,9 @@ enum qca_wlan_vendor_attr_loc_capa_flags {
* @QCA_WLAN_VENDOR_ATTR_FTM_PEER_AOA_BURST_PERIOD: Request AOA
* measurement every _value_ bursts. If 0 or not specified,
* AOA measurements will be disabled for this peer.
+ * @QCA_WLAN_VENDOR_ATTR_FTM_PEER_FREQ: Frequency in MHz where
+ * peer is listening. Optional; if not specified, use the
+ * entry from the kernel scan results cache.
*/
enum qca_wlan_vendor_attr_ftm_peer_info {
QCA_WLAN_VENDOR_ATTR_FTM_PEER_INVALID,
@@ -184,6 +190,7 @@ enum qca_wlan_vendor_attr_ftm_peer_info {
QCA_WLAN_VENDOR_ATTR_FTM_PEER_MEAS_PARAMS,
QCA_WLAN_VENDOR_ATTR_FTM_PEER_SECURE_TOKEN_ID,
QCA_WLAN_VENDOR_ATTR_FTM_PEER_AOA_BURST_PERIOD,
+ QCA_WLAN_VENDOR_ATTR_FTM_PEER_FREQ,
/* keep last */
QCA_WLAN_VENDOR_ATTR_FTM_PEER_AFTER_LAST,
QCA_WLAN_VENDOR_ATTR_FTM_PEER_MAX =
@@ -426,7 +433,7 @@ struct wil_ftm_meas_params {
/* measurement request for a single peer */
struct wil_ftm_meas_peer_info {
u8 mac_addr[ETH_ALEN];
- u8 channel;
+ u32 freq;
u32 flags; /* enum qca_wlan_vendor_attr_ftm_peer_meas_flags */
struct wil_ftm_meas_params params;
u8 secure_token_id;
@@ -465,6 +472,7 @@ struct wil_ftm_peer_meas_res {
/* standalone AOA measurement request */
struct wil_aoa_meas_request {
u8 mac_addr[ETH_ALEN];
+ u32 freq;
u32 type;
};
diff --git a/drivers/pinctrl/qcom/pinctrl-msm8998.c b/drivers/pinctrl/qcom/pinctrl-msm8998.c
index e983bcc8e47d..c4882f244d3f 100644
--- a/drivers/pinctrl/qcom/pinctrl-msm8998.c
+++ b/drivers/pinctrl/qcom/pinctrl-msm8998.c
@@ -92,6 +92,31 @@
.intr_detection_bit = -1, \
.intr_detection_width = -1, \
}
+
+#define UFS_RESET(pg_name, offset) \
+ { \
+ .name = #pg_name, \
+ .pins = pg_name##_pins, \
+ .npins = (unsigned)ARRAY_SIZE(pg_name##_pins), \
+ .ctl_reg = offset, \
+ .io_reg = offset + 0x4, \
+ .intr_cfg_reg = 0, \
+ .intr_status_reg = 0, \
+ .intr_target_reg = 0, \
+ .mux_bit = -1, \
+ .pull_bit = 3, \
+ .drv_bit = 0, \
+ .oe_bit = -1, \
+ .in_bit = -1, \
+ .out_bit = 0, \
+ .intr_enable_bit = -1, \
+ .intr_status_bit = -1, \
+ .intr_target_bit = -1, \
+ .intr_raw_status_bit = -1, \
+ .intr_polarity_bit = -1, \
+ .intr_detection_bit = -1, \
+ .intr_detection_width = -1, \
+ }
static const struct pinctrl_pin_desc msm8998_pins[] = {
PINCTRL_PIN(0, "GPIO_0"),
PINCTRL_PIN(1, "GPIO_1"),
@@ -246,6 +271,7 @@ static const struct pinctrl_pin_desc msm8998_pins[] = {
PINCTRL_PIN(150, "SDC2_CLK"),
PINCTRL_PIN(151, "SDC2_CMD"),
PINCTRL_PIN(152, "SDC2_DATA"),
+ PINCTRL_PIN(153, "UFS_RESET"),
};
#define DECLARE_MSM_GPIO_PINS(pin) \
@@ -404,6 +430,7 @@ DECLARE_MSM_GPIO_PINS(149);
static const unsigned int sdc2_clk_pins[] = { 150 };
static const unsigned int sdc2_cmd_pins[] = { 151 };
static const unsigned int sdc2_data_pins[] = { 152 };
+static const unsigned int ufs_reset_pins[] = { 153 };
enum msm8998_functions {
msm_mux_blsp_spi1,
@@ -1856,6 +1883,7 @@ static const struct msm_pingroup msm8998_groups[] = {
SDC_QDSD_PINGROUP(sdc2_clk, 0x999000, 14, 6),
SDC_QDSD_PINGROUP(sdc2_cmd, 0x999000, 11, 3),
SDC_QDSD_PINGROUP(sdc2_data, 0x999000, 9, 0),
+ UFS_RESET(ufs_reset, 0x19d000),
};
static const struct msm_pinctrl_soc_data msm8998_pinctrl = {
diff --git a/drivers/platform/msm/gsi/gsi.c b/drivers/platform/msm/gsi/gsi.c
index df3901093006..a617c9e8e11f 100644
--- a/drivers/platform/msm/gsi/gsi.c
+++ b/drivers/platform/msm/gsi/gsi.c
@@ -105,6 +105,8 @@ static void gsi_handle_ch_ctrl(int ee)
ch = gsi_readl(gsi_ctx->base +
GSI_EE_n_CNTXT_SRC_GSI_CH_IRQ_OFFS(ee));
+ gsi_writel(ch, gsi_ctx->base +
+ GSI_EE_n_CNTXT_SRC_GSI_CH_IRQ_CLR_OFFS(ee));
GSIDBG("ch %x\n", ch);
for (i = 0; i < 32; i++) {
if ((1 << i) & ch) {
@@ -124,9 +126,6 @@ static void gsi_handle_ch_ctrl(int ee)
gsi_ctx->ch_dbg[i].cmd_completed++;
}
}
-
- gsi_writel(ch, gsi_ctx->base +
- GSI_EE_n_CNTXT_SRC_GSI_CH_IRQ_CLR_OFFS(ee));
}
static void gsi_handle_ev_ctrl(int ee)
@@ -138,6 +137,8 @@ static void gsi_handle_ev_ctrl(int ee)
ch = gsi_readl(gsi_ctx->base +
GSI_EE_n_CNTXT_SRC_EV_CH_IRQ_OFFS(ee));
+ gsi_writel(ch, gsi_ctx->base +
+ GSI_EE_n_CNTXT_SRC_EV_CH_IRQ_CLR_OFFS(ee));
GSIDBG("ev %x\n", ch);
for (i = 0; i < 32; i++) {
if ((1 << i) & ch) {
@@ -156,9 +157,6 @@ static void gsi_handle_ev_ctrl(int ee)
complete(&ctx->compl);
}
}
-
- gsi_writel(ch, gsi_ctx->base +
- GSI_EE_n_CNTXT_SRC_EV_CH_IRQ_CLR_OFFS(ee));
}
static void gsi_handle_glob_err(uint32_t err)
@@ -439,9 +437,16 @@ static void gsi_handle_ieob(int ee)
GSI_EE_n_CNTXT_SRC_IEOB_IRQ_OFFS(ee));
msk = gsi_readl(gsi_ctx->base +
GSI_EE_n_CNTXT_SRC_IEOB_IRQ_MSK_OFFS(ee));
+ gsi_writel(ch & msk, gsi_ctx->base +
+ GSI_EE_n_CNTXT_SRC_IEOB_IRQ_CLR_OFFS(ee));
for (i = 0; i < 32; i++) {
if ((1 << i) & ch & msk) {
+ if (i >= gsi_ctx->max_ev || i >= GSI_EVT_RING_MAX) {
+ GSIERR("invalid event %d\n", i);
+ break;
+ }
+
ctx = &gsi_ctx->evtr[i];
BUG_ON(ctx->props.intf != GSI_EVT_CHTYPE_GPI_EV);
spin_lock_irqsave(&ctx->ring.slock, flags);
@@ -467,9 +472,6 @@ check_again:
spin_unlock_irqrestore(&ctx->ring.slock, flags);
}
}
-
- gsi_writel(ch & msk, gsi_ctx->base +
- GSI_EE_n_CNTXT_SRC_IEOB_IRQ_CLR_OFFS(ee));
}
static void gsi_handle_inter_ee_ch_ctrl(int ee)
@@ -479,15 +481,14 @@ static void gsi_handle_inter_ee_ch_ctrl(int ee)
ch = gsi_readl(gsi_ctx->base +
GSI_INTER_EE_n_SRC_GSI_CH_IRQ_OFFS(ee));
+ gsi_writel(ch, gsi_ctx->base +
+ GSI_INTER_EE_n_SRC_GSI_CH_IRQ_CLR_OFFS(ee));
for (i = 0; i < 32; i++) {
if ((1 << i) & ch) {
/* not currently expected */
GSIERR("ch %u was inter-EE changed\n", i);
}
}
-
- gsi_writel(ch, gsi_ctx->base +
- GSI_INTER_EE_n_SRC_GSI_CH_IRQ_CLR_OFFS(ee));
}
static void gsi_handle_inter_ee_ev_ctrl(int ee)
@@ -497,15 +498,14 @@ static void gsi_handle_inter_ee_ev_ctrl(int ee)
ch = gsi_readl(gsi_ctx->base +
GSI_INTER_EE_n_SRC_EV_CH_IRQ_OFFS(ee));
+ gsi_writel(ch, gsi_ctx->base +
+ GSI_INTER_EE_n_SRC_EV_CH_IRQ_CLR_OFFS(ee));
for (i = 0; i < 32; i++) {
if ((1 << i) & ch) {
/* not currently expected */
GSIERR("evt %u was inter-EE changed\n", i);
}
}
-
- gsi_writel(ch, gsi_ctx->base +
- GSI_INTER_EE_n_SRC_EV_CH_IRQ_CLR_OFFS(ee));
}
static void gsi_handle_general(int ee)
diff --git a/drivers/platform/msm/ipa/ipa_api.c b/drivers/platform/msm/ipa/ipa_api.c
index 75b193def36e..159452c6e3bd 100644
--- a/drivers/platform/msm/ipa/ipa_api.c
+++ b/drivers/platform/msm/ipa/ipa_api.c
@@ -2907,6 +2907,22 @@ int ipa_tear_down_uc_offload_pipes(int ipa_ep_idx_ul,
return ret;
}
+/**
+ * ipa_get_pdev() - return a pointer to IPA dev struct
+ *
+ * Return value: a pointer to IPA dev struct
+ *
+ */
+struct device *ipa_get_pdev(void)
+{
+ struct device *ret;
+
+ IPA_API_DISPATCH_RETURN_PTR(ipa_get_pdev);
+
+ return ret;
+}
+EXPORT_SYMBOL(ipa_get_pdev);
+
static const struct dev_pm_ops ipa_pm_ops = {
.suspend_noirq = ipa_ap_suspend,
.resume_noirq = ipa_ap_resume,
diff --git a/drivers/platform/msm/ipa/ipa_api.h b/drivers/platform/msm/ipa/ipa_api.h
index eab048323bd5..78fcdeb4b7a0 100644
--- a/drivers/platform/msm/ipa/ipa_api.h
+++ b/drivers/platform/msm/ipa/ipa_api.h
@@ -369,6 +369,8 @@ struct ipa_api_controller {
int (*ipa_tear_down_uc_offload_pipes)(int ipa_ep_idx_ul,
int ipa_ep_idx_dl);
+
+ struct device *(*ipa_get_pdev)(void);
};
#ifdef CONFIG_IPA
diff --git a/drivers/platform/msm/ipa/ipa_v2/ipa_i.h b/drivers/platform/msm/ipa/ipa_v2/ipa_i.h
index 866170d3324d..fd61435db5e2 100644
--- a/drivers/platform/msm/ipa/ipa_v2/ipa_i.h
+++ b/drivers/platform/msm/ipa/ipa_v2/ipa_i.h
@@ -1847,4 +1847,5 @@ int ipa_ntn_init(void);
int ipa2_get_ntn_stats(struct IpaHwStatsNTNInfoData_t *stats);
int ipa2_register_ipa_ready_cb(void (*ipa_ready_cb)(void *),
void *user_data);
+struct device *ipa2_get_pdev(void);
#endif /* _IPA_I_H_ */
diff --git a/drivers/platform/msm/ipa/ipa_v2/ipa_utils.c b/drivers/platform/msm/ipa/ipa_v2/ipa_utils.c
index b627cd1fc833..9813fa417c3a 100644
--- a/drivers/platform/msm/ipa/ipa_v2/ipa_utils.c
+++ b/drivers/platform/msm/ipa/ipa_v2/ipa_utils.c
@@ -5102,6 +5102,7 @@ int ipa2_bind_api_controller(enum ipa_hw_type ipa_hw_type,
api_ctrl->ipa_setup_uc_ntn_pipes = ipa2_setup_uc_ntn_pipes;
api_ctrl->ipa_tear_down_uc_offload_pipes =
ipa2_tear_down_uc_offload_pipes;
+ api_ctrl->ipa_get_pdev = ipa2_get_pdev;
return 0;
}
@@ -5181,3 +5182,17 @@ void ipa_suspend_apps_pipes(bool suspend)
}
}
}
+
+/**
+ * ipa2_get_pdev() - return a pointer to IPA dev struct
+ *
+ * Return value: a pointer to IPA dev struct
+ *
+ */
+struct device *ipa2_get_pdev(void)
+{
+ if (!ipa_ctx)
+ return NULL;
+
+ return ipa_ctx->pdev;
+}
diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa.c b/drivers/platform/msm/ipa/ipa_v3/ipa.c
index 8676b35914e2..2101147e7d24 100644
--- a/drivers/platform/msm/ipa/ipa_v3/ipa.c
+++ b/drivers/platform/msm/ipa/ipa_v3/ipa.c
@@ -624,16 +624,16 @@ static long ipa3_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
IPADBG("cmd=%x nr=%d\n", cmd, _IOC_NR(cmd));
- if (!ipa3_is_ready()) {
- IPAERR("IPA not ready, waiting for init completion\n");
- wait_for_completion(&ipa3_ctx->init_completion_obj);
- }
-
if (_IOC_TYPE(cmd) != IPA_IOC_MAGIC)
return -ENOTTY;
if (_IOC_NR(cmd) >= IPA_IOCTL_MAX)
return -ENOTTY;
+ if (!ipa3_is_ready()) {
+ IPAERR("IPA not ready, waiting for init completion\n");
+ wait_for_completion(&ipa3_ctx->init_completion_obj);
+ }
+
IPA_ACTIVE_CLIENTS_INC_SIMPLE();
switch (cmd) {
diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_i.h b/drivers/platform/msm/ipa/ipa_v3/ipa_i.h
index 1b78835cda6b..3a666419385e 100644
--- a/drivers/platform/msm/ipa/ipa_v3/ipa_i.h
+++ b/drivers/platform/msm/ipa/ipa_v3/ipa_i.h
@@ -2027,4 +2027,5 @@ int ipa3_ntn_init(void);
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);
#endif /* _IPA3_I_H_ */
diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_utils.c b/drivers/platform/msm/ipa/ipa_v3/ipa_utils.c
index 4ea68ae1e95c..db60829bce69 100644
--- a/drivers/platform/msm/ipa/ipa_v3/ipa_utils.c
+++ b/drivers/platform/msm/ipa/ipa_v3/ipa_utils.c
@@ -3199,6 +3199,7 @@ int ipa3_bind_api_controller(enum ipa_hw_type ipa_hw_type,
api_ctrl->ipa_setup_uc_ntn_pipes = ipa3_setup_uc_ntn_pipes;
api_ctrl->ipa_tear_down_uc_offload_pipes =
ipa3_tear_down_uc_offload_pipes;
+ api_ctrl->ipa_get_pdev = ipa3_get_pdev;
return 0;
}
@@ -3637,3 +3638,17 @@ bool ipa3_is_msm_device(void)
return false;
}
+
+/**
+ * ipa3_get_pdev() - return a pointer to IPA dev struct
+ *
+ * Return value: a pointer to IPA dev struct
+ *
+ */
+struct device *ipa3_get_pdev(void)
+{
+ if (!ipa3_ctx)
+ return NULL;
+
+ return ipa3_ctx->pdev;
+}
diff --git a/drivers/power/qcom-charger/fg-core.h b/drivers/power/qcom-charger/fg-core.h
index d612016b1b79..f0de532f196c 100644
--- a/drivers/power/qcom-charger/fg-core.h
+++ b/drivers/power/qcom-charger/fg-core.h
@@ -151,6 +151,7 @@ enum fg_sram_param_id {
FG_SRAM_CHG_TERM_CURR,
FG_SRAM_DELTA_SOC_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_MAX,
@@ -198,6 +199,7 @@ struct fg_dt_props {
int sys_term_curr_ma;
int delta_soc_thr;
int recharge_soc_thr;
+ int recharge_volt_thr_mv;
int rsense_sel;
int jeita_thresholds[NUM_JEITA_LEVELS];
int esr_timer_charging;
diff --git a/drivers/power/qcom-charger/qpnp-fg-gen3.c b/drivers/power/qcom-charger/qpnp-fg-gen3.c
index 6ff0e9e45b00..4d2cfc84d455 100644
--- a/drivers/power/qcom-charger/qpnp-fg-gen3.c
+++ b/drivers/power/qcom-charger/qpnp-fg-gen3.c
@@ -112,6 +112,8 @@
#define EMPTY_VOLT_v2_OFFSET 3
#define VBATT_LOW_v2_WORD 16
#define VBATT_LOW_v2_OFFSET 0
+#define RECHARGE_VBATT_THR_v2_WORD 16
+#define RECHARGE_VBATT_THR_v2_OFFSET 1
#define FLOAT_VOLT_v2_WORD 16
#define FLOAT_VOLT_v2_OFFSET 2
@@ -236,6 +238,9 @@ static struct fg_sram_param pmi8998_v2_sram_params[] = {
PARAM(RECHARGE_SOC_THR, RECHARGE_SOC_THR_v2_WORD,
RECHARGE_SOC_THR_v2_OFFSET, 1, 256, 100, 0, fg_encode_default,
NULL),
+ PARAM(RECHARGE_VBATT_THR, RECHARGE_VBATT_THR_v2_WORD,
+ RECHARGE_VBATT_THR_v2_OFFSET, 1, 1000, 15625, -2000,
+ fg_encode_voltage, NULL),
PARAM(ESR_TIMER_DISCHG_MAX, ESR_TIMER_DISCHG_MAX_WORD,
ESR_TIMER_DISCHG_MAX_OFFSET, 2, 1, 1, 0, fg_encode_default,
NULL),
@@ -2395,8 +2400,8 @@ static int fg_hw_init(struct fg_chip *chip)
return rc;
}
- /* This SRAM register is only present in v2.0 */
- if (chip->pmic_rev_id->rev4 == PMI8998_V2P0_REV4 &&
+ /* This SRAM register is only present in v2.0 and above */
+ if (chip->pmic_rev_id->rev4 >= PMI8998_V2P0_REV4 &&
chip->bp.float_volt_uv > 0) {
fg_encode(chip->sp, FG_SRAM_FLOAT_VOLT,
chip->bp.float_volt_uv / 1000, buf);
@@ -2476,6 +2481,23 @@ static int fg_hw_init(struct fg_chip *chip)
}
}
+ /* This configuration is available only for pmicobalt v2.0 and above */
+ if (chip->pmic_rev_id->rev4 >= PMI8998_V2P0_REV4 &&
+ chip->dt.recharge_volt_thr_mv > 0) {
+ fg_encode(chip->sp, FG_SRAM_RECHARGE_VBATT_THR,
+ chip->dt.recharge_volt_thr_mv, buf);
+ rc = fg_sram_write(chip,
+ chip->sp[FG_SRAM_RECHARGE_VBATT_THR].addr_word,
+ chip->sp[FG_SRAM_RECHARGE_VBATT_THR].addr_byte,
+ buf, chip->sp[FG_SRAM_RECHARGE_VBATT_THR].len,
+ FG_IMA_DEFAULT);
+ if (rc < 0) {
+ pr_err("Error in writing recharge_vbatt_thr, rc=%d\n",
+ rc);
+ return rc;
+ }
+ }
+
if (chip->dt.rsense_sel >= SRC_SEL_BATFET &&
chip->dt.rsense_sel < SRC_SEL_RESERVED) {
rc = fg_masked_write(chip, BATT_INFO_IBATT_SENSING_CFG(chip),
@@ -2935,6 +2957,7 @@ static int fg_parse_ki_coefficients(struct fg_chip *chip)
#define DEFAULT_CUTOFF_VOLT_MV 3200
#define DEFAULT_EMPTY_VOLT_MV 2800
+#define DEFAULT_RECHARGE_VOLT_MV 4250
#define DEFAULT_CHG_TERM_CURR_MA 100
#define DEFAULT_SYS_TERM_CURR_MA -125
#define DEFAULT_DELTA_SOC_THR 1
@@ -3096,6 +3119,12 @@ static int fg_parse_dt(struct fg_chip *chip)
else
chip->dt.recharge_soc_thr = temp;
+ rc = of_property_read_u32(node, "qcom,fg-recharge-voltage", &temp);
+ if (rc < 0)
+ chip->dt.recharge_volt_thr_mv = DEFAULT_RECHARGE_VOLT_MV;
+ else
+ chip->dt.recharge_volt_thr_mv = temp;
+
rc = of_property_read_u32(node, "qcom,fg-rsense-sel", &temp);
if (rc < 0)
chip->dt.rsense_sel = SRC_SEL_BATFET_SMB;
diff --git a/drivers/power/qcom-charger/qpnp-smb2.c b/drivers/power/qcom-charger/qpnp-smb2.c
index 7accaa3a1673..f7a54f71a28a 100644
--- a/drivers/power/qcom-charger/qpnp-smb2.c
+++ b/drivers/power/qcom-charger/qpnp-smb2.c
@@ -214,7 +214,6 @@ static struct smb_params v1_params = {
#define STEP_CHARGING_MAX_STEPS 5
struct smb_dt_props {
- bool no_battery;
int fcc_ua;
int usb_icl_ua;
int otg_cl_ua;
@@ -226,7 +225,9 @@ struct smb_dt_props {
struct device_node *revid_dev_node;
int float_option;
int chg_inhibit_thr_mv;
+ bool no_battery;
bool hvdcp_disable;
+ bool auto_recharge_soc;
};
struct smb2 {
@@ -344,6 +345,8 @@ static int smb2_parse_dt(struct smb2 *chip)
return -EINVAL;
}
+ chip->dt.auto_recharge_soc = of_property_read_bool(node,
+ "qcom,auto-recharge-soc");
return 0;
}
@@ -1169,12 +1172,14 @@ static int smb2_init_hw(struct smb2 *chip)
return rc;
}
- /* disable Type-C factory mode */
+ /*
+ * disable Type-C factory mode and stay in Attached.SRC state when VCONN
+ * over-current happens
+ */
rc = smblib_masked_write(chg, TYPE_C_CFG_REG,
- FACTORY_MODE_DETECTION_EN_BIT, 0);
+ FACTORY_MODE_DETECTION_EN_BIT | VCONN_OC_CFG_BIT, 0);
if (rc < 0) {
- dev_err(chg->dev,
- "Couldn't disable Type-C factory mode rc=%d\n", rc);
+ dev_err(chg->dev, "Couldn't configure Type-C rc=%d\n", rc);
return rc;
}
@@ -1295,6 +1300,28 @@ static int smb2_init_hw(struct smb2 *chip)
return rc;
}
+ if (chip->dt.auto_recharge_soc) {
+ rc = smblib_masked_write(chg, FG_UPDATE_CFG_2_SEL_REG,
+ SOC_LT_CHG_RECHARGE_THRESH_SEL_BIT |
+ VBT_LT_CHG_RECHARGE_THRESH_SEL_BIT,
+ VBT_LT_CHG_RECHARGE_THRESH_SEL_BIT);
+ if (rc < 0) {
+ dev_err(chg->dev, "Couldn't configure FG_UPDATE_CFG2_SEL_REG rc=%d\n",
+ rc);
+ return rc;
+ }
+ } else {
+ rc = smblib_masked_write(chg, FG_UPDATE_CFG_2_SEL_REG,
+ SOC_LT_CHG_RECHARGE_THRESH_SEL_BIT |
+ VBT_LT_CHG_RECHARGE_THRESH_SEL_BIT,
+ SOC_LT_CHG_RECHARGE_THRESH_SEL_BIT);
+ if (rc < 0) {
+ dev_err(chg->dev, "Couldn't configure FG_UPDATE_CFG2_SEL_REG rc=%d\n",
+ rc);
+ return rc;
+ }
+ }
+
return rc;
}
@@ -1837,8 +1864,13 @@ static void smb2_shutdown(struct platform_device *pdev)
struct smb2 *chip = platform_get_drvdata(pdev);
struct smb_charger *chg = &chip->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);
+
+ /* force HVDCP to 5V */
smblib_masked_write(chg, USBIN_OPTIONS_1_CFG_REG,
- HVDCP_AUTONOMOUS_MODE_EN_CFG_BIT, 0);
+ HVDCP_AUTONOMOUS_MODE_EN_CFG_BIT, 0);
smblib_write(chg, CMD_HVDCP_2_REG, FORCE_5V_BIT);
}
diff --git a/drivers/power/qcom-charger/smb-lib.c b/drivers/power/qcom-charger/smb-lib.c
index 3403474565be..0faf8aee8aa0 100644
--- a/drivers/power/qcom-charger/smb-lib.c
+++ b/drivers/power/qcom-charger/smb-lib.c
@@ -505,15 +505,14 @@ static int try_rerun_apsd_for_hvdcp(struct smb_charger *chg)
static const struct apsd_result *smblib_update_usb_type(struct smb_charger *chg)
{
- const struct apsd_result *apsd_result;
+ const struct apsd_result *apsd_result = smblib_get_apsd_result(chg);
/* if PD is active, APSD is disabled so won't have a valid result */
if (chg->pd_active) {
chg->usb_psy_desc.type = POWER_SUPPLY_TYPE_USB_PD;
- return 0;
+ return apsd_result;
}
- apsd_result = smblib_get_apsd_result(chg);
chg->usb_psy_desc.type = apsd_result->pst;
return apsd_result;
}
@@ -2866,39 +2865,39 @@ 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;
int rc;
- u8 stat;
+ u8 stat4, stat5;
bool debounce_done, sink_attached, legacy_cable;
/* 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, &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);
return IRQ_HANDLED;
}
- smblib_dbg(chg, PR_REGISTER, "TYPE_C_STATUS_4 = 0x%02x\n", stat);
- debounce_done = (bool)(stat & TYPEC_DEBOUNCE_DONE_STATUS_BIT);
- sink_attached = (bool)(stat & UFP_DFP_MODE_STATUS_BIT);
- 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 rc=%d\n", rc);
return IRQ_HANDLED;
}
- smblib_dbg(chg, PR_REGISTER, "TYPE_C_STATUS_5 = 0x%02x\n", stat);
- legacy_cable = (bool)(stat & TYPEC_LEGACY_CABLE_STATUS_BIT);
+
+ 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);
smblib_handle_typec_debounce_done(chg,
debounce_done, sink_attached, legacy_cable);
- power_supply_changed(chg->usb_psy);
-
- if (stat & TYPEC_VBUS_ERROR_STATUS_BIT)
+ if (stat4 & TYPEC_VBUS_ERROR_STATUS_BIT)
smblib_dbg(chg, PR_INTERRUPT, "IRQ: %s vbus-error\n",
irq_data->name);
+ 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);
return IRQ_HANDLED;
}
diff --git a/drivers/regulator/cpr3-regulator.h b/drivers/regulator/cpr3-regulator.h
index ac571271b0d5..3c652ca8d489 100644
--- a/drivers/regulator/cpr3-regulator.h
+++ b/drivers/regulator/cpr3-regulator.h
@@ -565,6 +565,11 @@ struct cpr3_panic_regs_info {
* @mem_acc_corner_map: mem-acc regulator corners mapping to low and high
* voltage mem-acc settings for the memories powered by
* this CPR3 controller and its associated CPR3 regulators
+ * @mem_acc_crossover_volt: Voltage in microvolts corresponding to the voltage
+ * that the VDD supply must be set to while a MEM ACC
+ * switch is in progress. This element must be initialized
+ * for CPRh controllers when a MEM ACC threshold voltage is
+ * defined.
* @core_clk: Pointer to the CPR3 controller core clock
* @iface_clk: Pointer to the CPR3 interface clock (platform specific)
* @bus_clk: Pointer to the CPR3 bus clock (platform specific)
@@ -744,6 +749,7 @@ struct cpr3_controller {
int system_supply_max_volt;
int mem_acc_threshold_volt;
int mem_acc_corner_map[CPR3_MEM_ACC_CORNERS];
+ int mem_acc_crossover_volt;
struct clk *core_clk;
struct clk *iface_clk;
struct clk *bus_clk;
@@ -876,6 +882,7 @@ int cpr4_parse_core_count_temp_voltage_adj(struct cpr3_regulator *vreg,
int cpr3_apm_init(struct cpr3_controller *ctrl);
int cpr3_mem_acc_init(struct cpr3_regulator *vreg);
void cprh_adjust_voltages_for_apm(struct cpr3_regulator *vreg);
+void cprh_adjust_voltages_for_mem_acc(struct cpr3_regulator *vreg);
#else
@@ -1052,6 +1059,10 @@ static inline void cprh_adjust_voltages_for_apm(struct cpr3_regulator *vreg)
{
}
+static inline void cprh_adjust_voltages_for_mem_acc(struct cpr3_regulator *vreg)
+{
+}
+
#endif /* CONFIG_REGULATOR_CPR3 */
#endif /* __REGULATOR_CPR_REGULATOR_H__ */
diff --git a/drivers/regulator/cpr3-util.c b/drivers/regulator/cpr3-util.c
index c377a65a6393..60fe825ca013 100644
--- a/drivers/regulator/cpr3-util.c
+++ b/drivers/regulator/cpr3-util.c
@@ -680,12 +680,13 @@ int cpr3_parse_common_corner_data(struct cpr3_regulator *vreg)
}
/*
- * In CPRh compliant controllers an additional corner is
- * allocated to correspond to the APM crossover voltage
+ * For CPRh compliant controllers two additional corners are
+ * allocated to correspond to the APM crossover voltage and the MEM ACC
+ * crossover voltage.
*/
vreg->corner = devm_kcalloc(ctrl->dev, ctrl->ctrl_type ==
CPR_CTRL_TYPE_CPRH ?
- vreg->corner_count + 1 :
+ vreg->corner_count + 2 :
vreg->corner_count,
sizeof(*vreg->corner), GFP_KERNEL);
temp = kcalloc(vreg->corner_count, sizeof(*temp), GFP_KERNEL);
@@ -2083,3 +2084,66 @@ void cprh_adjust_voltages_for_apm(struct cpr3_regulator *vreg)
corner->ceiling_volt, corner->open_loop_volt);
}
}
+
+/**
+ * cprh_adjust_voltages_for_mem_acc() - adjust per-corner floor and ceiling
+ * voltages so that they do not intersect the MEM ACC threshold
+ * voltage
+ * @vreg: Pointer to the CPR3 regulator
+ *
+ * The following algorithm is applied:
+ * if floor < threshold <= ceiling:
+ * if open_loop >= threshold, then floor = threshold
+ * else ceiling = threshold - step
+ * where:
+ * step = voltage in microvolts of a single step of the VDD supply
+ *
+ * The open-loop voltage is also bounded by the new floor or ceiling value as
+ * needed.
+ *
+ * Return: none
+ */
+void cprh_adjust_voltages_for_mem_acc(struct cpr3_regulator *vreg)
+{
+ struct cpr3_controller *ctrl = vreg->thread->ctrl;
+ struct cpr3_corner *corner;
+ int i, threshold, prev_ceiling, prev_floor, prev_open_loop;
+
+ if (!ctrl->mem_acc_threshold_volt) {
+ /* MEM ACC not being used. */
+ return;
+ }
+
+ ctrl->mem_acc_threshold_volt = CPR3_ROUND(ctrl->mem_acc_threshold_volt,
+ ctrl->step_volt);
+
+ threshold = ctrl->mem_acc_threshold_volt;
+
+ for (i = 0; i < vreg->corner_count; i++) {
+ corner = &vreg->corner[i];
+
+ if (threshold <= corner->floor_volt
+ || threshold > corner->ceiling_volt)
+ continue;
+
+ prev_floor = corner->floor_volt;
+ prev_ceiling = corner->ceiling_volt;
+ prev_open_loop = corner->open_loop_volt;
+
+ if (corner->open_loop_volt >= threshold) {
+ corner->floor_volt = max(corner->floor_volt, threshold);
+ if (corner->open_loop_volt < corner->floor_volt)
+ corner->open_loop_volt = corner->floor_volt;
+ } else {
+ corner->ceiling_volt = threshold - ctrl->step_volt;
+ }
+
+ if (corner->floor_volt != prev_floor
+ || corner->ceiling_volt != prev_ceiling
+ || corner->open_loop_volt != prev_open_loop)
+ cpr3_debug(vreg, "MEM ACC threshold=%d changed corner %d voltages; prev: floor=%d, ceiling=%d, open-loop=%d; new: floor=%d, ceiling=%d, open-loop=%d\n",
+ threshold, i, prev_floor, prev_ceiling,
+ prev_open_loop, corner->floor_volt,
+ corner->ceiling_volt, corner->open_loop_volt);
+ }
+}
diff --git a/drivers/regulator/cprh-kbss-regulator.c b/drivers/regulator/cprh-kbss-regulator.c
index 2608cc4a430a..9cbd1ee18ec3 100644
--- a/drivers/regulator/cprh-kbss-regulator.c
+++ b/drivers/regulator/cprh-kbss-regulator.c
@@ -73,8 +73,10 @@ struct cprh_msm8998_kbss_fuses {
/*
* Fuse combos 0 - 7 map to CPR fusing revision 0 - 7 with speed bin fuse = 0.
* Fuse combos 8 - 15 map to CPR fusing revision 0 - 7 with speed bin fuse = 1.
+ * Fuse combos 16 - 23 map to CPR fusing revision 0 - 7 with speed bin fuse = 2.
+ * Fuse combos 24 - 31 map to CPR fusing revision 0 - 7 with speed bin fuse = 3.
*/
-#define CPRH_MSM8998_KBSS_FUSE_COMBO_COUNT 16
+#define CPRH_MSM8998_KBSS_FUSE_COMBO_COUNT 32
/*
* Constants which define the name of each fuse corner.
@@ -866,6 +868,44 @@ static int cprh_kbss_apm_crossover_as_corner(struct cpr3_regulator *vreg)
}
/**
+ * cprh_kbss_mem_acc_crossover_as_corner() - introduce a corner whose floor,
+ * open-loop, and ceiling voltages correspond to the MEM ACC
+ * crossover voltage.
+ * @vreg: Pointer to the CPR3 regulator
+ *
+ * The MEM ACC corner is utilized as a crossover corner by OSM and CPRh
+ * hardware to set the VDD supply voltage during the MEM ACC switch
+ * routine.
+ *
+ * Return: 0 on success, errno on failure
+ */
+static int cprh_kbss_mem_acc_crossover_as_corner(struct cpr3_regulator *vreg)
+{
+ struct cpr3_controller *ctrl = vreg->thread->ctrl;
+ struct cpr3_corner *corner;
+
+ if (!ctrl->mem_acc_crossover_volt) {
+ /* MEM ACC voltage crossover corner not required. */
+ return 0;
+ }
+
+ corner = &vreg->corner[vreg->corner_count];
+ /*
+ * 0 MHz indicates this corner is not to be
+ * used as active DCVS set point.
+ */
+ corner->proc_freq = 0;
+ corner->floor_volt = ctrl->mem_acc_crossover_volt;
+ corner->ceiling_volt = ctrl->mem_acc_crossover_volt;
+ corner->open_loop_volt = ctrl->mem_acc_crossover_volt;
+ corner->abs_ceiling_volt = ctrl->mem_acc_crossover_volt;
+ corner->use_open_loop = true;
+ vreg->corner_count++;
+
+ return 0;
+}
+
+/**
* cprh_msm8998_kbss_set_no_interpolation_quotients() - use the fused target
* quotient values for lower frequencies.
* @vreg: Pointer to the CPR3 regulator
@@ -1196,6 +1236,7 @@ static int cprh_kbss_init_regulator(struct cpr3_regulator *vreg)
}
cprh_adjust_voltages_for_apm(vreg);
+ cprh_adjust_voltages_for_mem_acc(vreg);
cpr3_open_loop_voltage_as_ceiling(vreg);
@@ -1248,6 +1289,13 @@ static int cprh_kbss_init_regulator(struct cpr3_regulator *vreg)
return rc;
}
+ rc = cprh_kbss_mem_acc_crossover_as_corner(vreg);
+ if (rc) {
+ cpr3_err(vreg, "unable to introduce MEM ACC voltage crossover corner, rc=%d\n",
+ rc);
+ return rc;
+ }
+
cprh_kbss_print_settings(vreg);
return 0;
@@ -1420,6 +1468,25 @@ static int cprh_kbss_init_controller(struct cpr3_controller *ctrl)
ctrl->saw_use_unit_mV = of_property_read_bool(ctrl->dev->of_node,
"qcom,cpr-saw-use-unit-mV");
+ rc = of_property_read_u32(ctrl->dev->of_node,
+ "qcom,mem-acc-threshold-voltage",
+ &ctrl->mem_acc_threshold_volt);
+ if (!rc) {
+ ctrl->mem_acc_threshold_volt
+ = CPR3_ROUND(ctrl->mem_acc_threshold_volt, ctrl->step_volt);
+
+ rc = of_property_read_u32(ctrl->dev->of_node,
+ "qcom,mem-acc-crossover-voltage",
+ &ctrl->mem_acc_crossover_volt);
+ if (rc) {
+ cpr3_err(ctrl, "error reading property qcom,mem-acc-crossover-voltage, rc=%d\n",
+ rc);
+ return rc;
+ }
+ ctrl->mem_acc_crossover_volt
+ = CPR3_ROUND(ctrl->mem_acc_crossover_volt, ctrl->step_volt);
+ }
+
/*
* Use fixed step quotient if specified otherwise use dynamically
* calculated per RO step quotient
@@ -1475,6 +1542,14 @@ static int cprh_kbss_populate_opp_table(struct cpr3_controller *ctrl)
for (i = 0; i < vreg->corner_count; i++) {
corner = &vreg->corner[i];
+ if (!corner->proc_freq) {
+ /*
+ * 0 MHz indicates this corner is not to be
+ * used as active DCVS set point. Don't add it
+ * to the OPP table.
+ */
+ continue;
+ }
rc = dev_pm_opp_add(dev, corner->proc_freq, i + 1);
if (rc) {
cpr3_err(ctrl, "could not add OPP for corner %d with frequency %u MHz, rc=%d\n",
diff --git a/drivers/scsi/ufs/ufs-qcom.c b/drivers/scsi/ufs/ufs-qcom.c
index 603cbe65825b..1e200370deea 100644
--- a/drivers/scsi/ufs/ufs-qcom.c
+++ b/drivers/scsi/ufs/ufs-qcom.c
@@ -791,8 +791,12 @@ static int ufs_qcom_full_reset(struct ufs_hba *hba)
goto out;
}
- /* Very small delay, per the documented requirement */
- usleep_range(1, 2);
+ /*
+ * The hardware requirement for delay between assert/deassert
+ * is at least 3-4 sleep clock (32.7KHz) cycles, which comes to
+ * ~125us (4/32768). To be on the safe side add 200us delay.
+ */
+ usleep_range(200, 210);
ret = reset_control_deassert(hba->core_reset);
if (ret)
diff --git a/drivers/scsi/ufs/ufshcd-pltfrm.c b/drivers/scsi/ufs/ufshcd-pltfrm.c
index 5a9564326099..41684dca6baa 100644
--- a/drivers/scsi/ufs/ufshcd-pltfrm.c
+++ b/drivers/scsi/ufs/ufshcd-pltfrm.c
@@ -250,6 +250,20 @@ static void ufshcd_parse_pm_levels(struct ufs_hba *hba)
}
}
+static int ufshcd_parse_pinctrl_info(struct ufs_hba *hba)
+{
+ int ret = 0;
+
+ /* Try to obtain pinctrl handle */
+ hba->pctrl = devm_pinctrl_get(hba->dev);
+ if (IS_ERR(hba->pctrl)) {
+ ret = PTR_ERR(hba->pctrl);
+ hba->pctrl = NULL;
+ }
+
+ return ret;
+}
+
#ifdef CONFIG_SMP
/**
* ufshcd_pltfrm_suspend - suspend power management function
@@ -361,6 +375,13 @@ int ufshcd_pltfrm_init(struct platform_device *pdev,
goto dealloc_host;
}
+ err = ufshcd_parse_pinctrl_info(hba);
+ if (err) {
+ dev_dbg(&pdev->dev, "%s: unable to parse pinctrl data %d\n",
+ __func__, err);
+ /* let's not fail the probe */
+ }
+
ufshcd_parse_pm_levels(hba);
if (!dev->dma_mask)
diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
index 67e1636c25ec..06defae6d5ba 100644
--- a/drivers/scsi/ufs/ufshcd.c
+++ b/drivers/scsi/ufs/ufshcd.c
@@ -446,6 +446,63 @@ void ufshcd_scsi_block_requests(struct ufs_hba *hba)
}
EXPORT_SYMBOL(ufshcd_scsi_block_requests);
+static int ufshcd_device_reset_ctrl(struct ufs_hba *hba, bool ctrl)
+{
+ int ret = 0;
+
+ if (!hba->pctrl)
+ return 0;
+
+ /* Assert reset if ctrl == true */
+ if (ctrl)
+ ret = pinctrl_select_state(hba->pctrl,
+ pinctrl_lookup_state(hba->pctrl, "dev-reset-assert"));
+ else
+ ret = pinctrl_select_state(hba->pctrl,
+ pinctrl_lookup_state(hba->pctrl, "dev-reset-deassert"));
+
+ if (ret < 0)
+ dev_err(hba->dev, "%s: %s failed with err %d\n",
+ __func__, ctrl ? "Assert" : "Deassert", ret);
+
+ return ret;
+}
+
+static inline int ufshcd_assert_device_reset(struct ufs_hba *hba)
+{
+ return ufshcd_device_reset_ctrl(hba, true);
+}
+
+static inline int ufshcd_deassert_device_reset(struct ufs_hba *hba)
+{
+ return ufshcd_device_reset_ctrl(hba, false);
+}
+
+static int ufshcd_reset_device(struct ufs_hba *hba)
+{
+ int ret;
+
+ /* reset the connected UFS device */
+ ret = ufshcd_assert_device_reset(hba);
+ if (ret)
+ goto out;
+ /*
+ * The reset signal is active low.
+ * The UFS device shall detect more than or equal to 1us of positive
+ * or negative RST_n pulse width.
+ * To be on safe side, keep the reset low for atleast 10us.
+ */
+ usleep_range(10, 15);
+
+ ret = ufshcd_deassert_device_reset(hba);
+ if (ret)
+ goto out;
+ /* same as assert, wait for atleast 10us after deassert */
+ usleep_range(10, 15);
+out:
+ return ret;
+}
+
/* replace non-printable or non-ASCII characters with spaces */
static inline void ufshcd_remove_non_printable(char *val)
{
@@ -6520,6 +6577,11 @@ static int ufshcd_reset_and_restore(struct ufs_hba *hba)
dev_warn(hba->dev, "%s: full reset returned %d\n",
__func__, err);
+ err = ufshcd_reset_device(hba);
+ if (err)
+ dev_warn(hba->dev, "%s: device reset failed. err %d\n",
+ __func__, err);
+
err = ufshcd_host_reset_and_restore(hba);
} while (err && --retries);
@@ -8220,13 +8282,6 @@ static int ufshcd_suspend(struct ufs_hba *hba, enum ufs_pm_op pm_op)
hba->clk_gating.is_suspended = true;
hba->hibern8_on_idle.is_suspended = true;
- /*
- * Disable auto hibern8 to prevent unnecessary hibern8 enter/exit
- * during suspend path
- */
- if (ufshcd_is_auto_hibern8_supported(hba))
- ufshcd_set_auto_hibern8_timer(hba, 0);
-
if (hba->clk_scaling.is_allowed) {
cancel_work_sync(&hba->clk_scaling.suspend_work);
cancel_work_sync(&hba->clk_scaling.resume_work);
@@ -8334,10 +8389,6 @@ enable_gating:
ufshcd_resume_clkscaling(hba);
hba->hibern8_on_idle.is_suspended = false;
hba->clk_gating.is_suspended = false;
- /* Re-enable auto hibern8 in case of suspend failure */
- if (ufshcd_is_auto_hibern8_supported(hba))
- ufshcd_set_auto_hibern8_timer(hba,
- hba->hibern8_on_idle.delay_ms);
ufshcd_release_all(hba);
out:
hba->pm_op_in_progress = 0;
@@ -8431,13 +8482,6 @@ static int ufshcd_resume(struct ufs_hba *hba, enum ufs_pm_op pm_op)
if (hba->clk_scaling.is_allowed)
ufshcd_resume_clkscaling(hba);
- /*
- * Enable auto hibern8 after successful resume to prevent
- * unnecessary hibern8 enter/exit during resume path
- */
- if (ufshcd_is_auto_hibern8_supported(hba))
- ufshcd_set_auto_hibern8_timer(hba,
- hba->hibern8_on_idle.delay_ms);
/* Schedule clock gating in case of no access to UFS device yet */
ufshcd_release_all(hba);
goto out;
@@ -9419,6 +9463,15 @@ int ufshcd_init(struct ufs_hba *hba, void __iomem *mmio_base, unsigned int irq)
goto exit_gating;
}
+ /* Reset controller to power on reset (POR) state */
+ ufshcd_vops_full_reset(hba);
+
+ /* reset connected UFS device */
+ err = ufshcd_reset_device(hba);
+ if (err)
+ dev_warn(hba->dev, "%s: device reset failed. err %d\n",
+ __func__, err);
+
/* Host controller enable */
err = ufshcd_hba_enable(hba);
if (err) {
diff --git a/drivers/scsi/ufs/ufshcd.h b/drivers/scsi/ufs/ufshcd.h
index 9f2b04c8ff82..c5eb21d8a0fe 100644
--- a/drivers/scsi/ufs/ufshcd.h
+++ b/drivers/scsi/ufs/ufshcd.h
@@ -907,6 +907,7 @@ struct ufs_hba {
int scsi_block_reqs_cnt;
bool full_init_linereset;
+ struct pinctrl *pctrl;
};
static inline void ufshcd_mark_shutdown_ongoing(struct ufs_hba *hba)
diff --git a/drivers/soc/qcom/Kconfig b/drivers/soc/qcom/Kconfig
index d3f967319d21..21733633cb6c 100644
--- a/drivers/soc/qcom/Kconfig
+++ b/drivers/soc/qcom/Kconfig
@@ -628,12 +628,10 @@ config MSM_PERFORMANCE
config MSM_PERFORMANCE_HOTPLUG_ON
bool "Hotplug functionality through msm_performance turned on"
depends on MSM_PERFORMANCE
- default y
help
- If some other core-control driver is present turn off the core-control
- capability of msm_performance driver. Setting this flag to false will
- compile out the nodes needed for core-control functionality through
- msm_performance.
+ Setting this flag to true will enable the nodes needed for core-control
+ functionality of hot plugging cores through msm_performance if there is
+ no default core-control driver available.
endif # ARCH_QCOM
diff --git a/drivers/soc/qcom/gladiator_erp_v2.c b/drivers/soc/qcom/gladiator_erp_v2.c
index 25c7bd77ae96..91b5d39be242 100644
--- a/drivers/soc/qcom/gladiator_erp_v2.c
+++ b/drivers/soc/qcom/gladiator_erp_v2.c
@@ -628,9 +628,11 @@ static irqreturn_t msm_gladiator_isr(int irq, void *dev_id)
msm_gld_data->gladiator_virt_base +
get_gld_offset(err_log));
}
- pr_alert("Main log register data:\n%08x %08x %08x %08x\n%08x %08x %08x %08x\n%08x %08x %08x\n",
- err_buf[0], err_buf[1], err_buf[2], err_buf[3], err_buf[4], err_buf[5], err_buf[6],
- err_buf[7], err_buf[8], err_buf[9], err_buf[10]);
+ pr_alert("Main log register data:\n%08x %08x %08x %08x\n"
+ "%08x %08x %08x %08x\n%08x %08x %08x %08x\n",
+ err_buf[2], err_buf[3], err_buf[4], err_buf[5],
+ err_buf[6], err_buf[7], err_buf[8], err_buf[9],
+ err_buf[10], err_buf[11], err_buf[12], err_buf[13]);
}
if (obsrv_err_valid) {
diff --git a/drivers/soc/qcom/msm_bus/msm_bus_arb_adhoc.c b/drivers/soc/qcom/msm_bus/msm_bus_arb_adhoc.c
index deb7231a4ed1..10fb4cc8ebff 100644
--- a/drivers/soc/qcom/msm_bus/msm_bus_arb_adhoc.c
+++ b/drivers/soc/qcom/msm_bus/msm_bus_arb_adhoc.c
@@ -869,7 +869,7 @@ static void unregister_client_adhoc(uint32_t cl)
}
curr = client->curr;
- if (curr >= pdata->num_usecases) {
+ if ((curr < 0) || (curr >= pdata->num_usecases)) {
MSM_BUS_ERR("Invalid index Defaulting curr to 0");
curr = 0;
}
diff --git a/drivers/soc/qcom/rpm-smd.c b/drivers/soc/qcom/rpm-smd.c
index 242071f52811..20f406b9a2f7 100644
--- a/drivers/soc/qcom/rpm-smd.c
+++ b/drivers/soc/qcom/rpm-smd.c
@@ -83,7 +83,7 @@ static struct glink_apps_rpm_data *glink_data;
#define DEFAULT_BUFFER_SIZE 256
#define DEBUG_PRINT_BUFFER_SIZE 512
#define MAX_SLEEP_BUFFER 128
-#define GFP_FLAG(noirq) (noirq ? GFP_ATOMIC : GFP_NOFS)
+#define GFP_FLAG(noirq) (noirq ? GFP_ATOMIC : GFP_NOIO)
#define INV_RSC "resource does not exist"
#define ERR "err\0"
#define MAX_ERR_BUFFER_SIZE 128
diff --git a/drivers/soc/qcom/scm.c b/drivers/soc/qcom/scm.c
index b4713ac1b68b..f2216f968319 100644
--- a/drivers/soc/qcom/scm.c
+++ b/drivers/soc/qcom/scm.c
@@ -665,10 +665,6 @@ int scm_call2(u32 fn_id, struct scm_desc *desc)
desc->ret[0] = desc->ret[1] = desc->ret[2] = 0;
- pr_debug("scm_call: func id %#llx, args: %#x, %#llx, %#llx, %#llx, %#llx\n",
- x0, desc->arginfo, desc->args[0], desc->args[1],
- desc->args[2], desc->x5);
-
trace_scm_call_start(x0, desc);
if (scm_version == SCM_ARMV8_64)
@@ -698,10 +694,8 @@ int scm_call2(u32 fn_id, struct scm_desc *desc)
} while (ret == SCM_V2_EBUSY && (retry_count++ < SCM_EBUSY_MAX_RETRY));
if (ret < 0)
- pr_err("scm_call failed: func id %#llx, arginfo: %#x, args: %#llx, %#llx, %#llx, %#llx, ret: %d, syscall returns: %#llx, %#llx, %#llx\n",
- x0, desc->arginfo, desc->args[0], desc->args[1],
- desc->args[2], desc->x5, ret, desc->ret[0],
- desc->ret[1], desc->ret[2]);
+ pr_err("scm_call failed: func id %#llx, ret: %d, syscall returns: %#llx, %#llx, %#llx\n",
+ x0, ret, desc->ret[0], desc->ret[1], desc->ret[2]);
if (arglen > N_REGISTER_ARGS)
kfree(desc->extra_arg_buf);
diff --git a/drivers/soc/qcom/socinfo.c b/drivers/soc/qcom/socinfo.c
index 826a22355429..f93ee29123fe 100644
--- a/drivers/soc/qcom/socinfo.c
+++ b/drivers/soc/qcom/socinfo.c
@@ -42,8 +42,8 @@
#define SMEM_IMAGE_VERSION_NAME_SIZE 75
#define SMEM_IMAGE_VERSION_VARIANT_SIZE 20
#define SMEM_IMAGE_VERSION_VARIANT_OFFSET 75
-#define SMEM_IMAGE_VERSION_OEM_SIZE 32
-#define SMEM_IMAGE_VERSION_OEM_OFFSET 96
+#define SMEM_IMAGE_VERSION_OEM_SIZE 33
+#define SMEM_IMAGE_VERSION_OEM_OFFSET 95
#define SMEM_IMAGE_VERSION_PARTITION_APPS 10
enum {
@@ -974,7 +974,7 @@ msm_get_image_crm_version(struct device *dev,
}
string_address += current_image * SMEM_IMAGE_VERSION_SINGLE_BLOCK_SIZE;
string_address += SMEM_IMAGE_VERSION_OEM_OFFSET;
- return snprintf(buf, SMEM_IMAGE_VERSION_OEM_SIZE, "%-.32s\n",
+ return snprintf(buf, SMEM_IMAGE_VERSION_OEM_SIZE, "%-.33s\n",
string_address);
}
@@ -995,7 +995,7 @@ msm_set_image_crm_version(struct device *dev,
}
store_address += current_image * SMEM_IMAGE_VERSION_SINGLE_BLOCK_SIZE;
store_address += SMEM_IMAGE_VERSION_OEM_OFFSET;
- snprintf(store_address, SMEM_IMAGE_VERSION_OEM_SIZE, "%-.32s", buf);
+ snprintf(store_address, SMEM_IMAGE_VERSION_OEM_SIZE, "%-.33s", buf);
return count;
}
@@ -1049,7 +1049,8 @@ msm_get_images(struct device *dev,
image_address);
pos += snprintf(buf + pos, PAGE_SIZE - pos, "\tVariant:\t%-.20s\n",
image_address + SMEM_IMAGE_VERSION_VARIANT_OFFSET);
- pos += snprintf(buf + pos, PAGE_SIZE - pos, "\tVersion:\t%-.32s\n\n",
+ pos += snprintf(buf + pos, PAGE_SIZE - pos,
+ "\tVersion:\t%-.33s\n",
image_address + SMEM_IMAGE_VERSION_OEM_OFFSET);
image_address += SMEM_IMAGE_VERSION_SINGLE_BLOCK_SIZE;
diff --git a/drivers/staging/android/ion/ion_cma_heap.c b/drivers/staging/android/ion/ion_cma_heap.c
index b2e1a4c1b170..b5905fc81147 100644
--- a/drivers/staging/android/ion/ion_cma_heap.c
+++ b/drivers/staging/android/ion/ion_cma_heap.c
@@ -274,11 +274,16 @@ static int ion_secure_cma_allocate(struct ion_heap *heap,
source_vm = VMID_HLOS;
dest_vm = get_secure_vmid(flags);
+
if (dest_vm < 0) {
pr_err("%s: Failed to get secure vmid\n", __func__);
return -EINVAL;
}
- dest_perms = PERM_READ | PERM_WRITE;
+
+ if (dest_vm == VMID_CP_SEC_DISPLAY)
+ dest_perms = PERM_READ;
+ else
+ dest_perms = PERM_READ | PERM_WRITE;
ret = ion_cma_allocate(heap, buffer, len, align, flags);
if (ret) {
diff --git a/drivers/tty/tty_ldisc.c b/drivers/tty/tty_ldisc.c
index 629e3c865072..9bee25cfa0be 100644
--- a/drivers/tty/tty_ldisc.c
+++ b/drivers/tty/tty_ldisc.c
@@ -417,6 +417,10 @@ EXPORT_SYMBOL_GPL(tty_ldisc_flush);
* they are not on hot paths so a little discipline won't do
* any harm.
*
+ * The line discipline-related tty_struct fields are reset to
+ * prevent the ldisc driver from re-using stale information for
+ * the new ldisc instance.
+ *
* Locking: takes termios_rwsem
*/
@@ -425,6 +429,9 @@ static void tty_set_termios_ldisc(struct tty_struct *tty, int num)
down_write(&tty->termios_rwsem);
tty->termios.c_line = num;
up_write(&tty->termios_rwsem);
+
+ tty->disc_data = NULL;
+ tty->receive_room = 0;
}
/**
diff --git a/drivers/usb/dwc3/dwc3-msm.c b/drivers/usb/dwc3/dwc3-msm.c
index add035269ae7..a21f6735808b 100644
--- a/drivers/usb/dwc3/dwc3-msm.c
+++ b/drivers/usb/dwc3/dwc3-msm.c
@@ -1465,11 +1465,10 @@ static void dwc3_restart_usb_work(struct work_struct *w)
pm_runtime_suspend(mdwc->dev);
}
+ mdwc->in_restart = false;
/* Force reconnect only if cable is still connected */
- if (mdwc->vbus_active) {
- mdwc->in_restart = false;
+ if (mdwc->vbus_active)
dwc3_resume_work(&mdwc->resume_work);
- }
dwc->err_evt_seen = false;
flush_delayed_work(&mdwc->sm_work);
@@ -1781,7 +1780,7 @@ static int dwc3_msm_prepare_suspend(struct dwc3_msm *mdwc)
u32 reg = 0;
if ((mdwc->in_host_mode || mdwc->vbus_active)
- && dwc3_msm_is_superspeed(mdwc)) {
+ && dwc3_msm_is_superspeed(mdwc) && !mdwc->in_restart) {
if (!atomic_read(&mdwc->in_p3)) {
dev_err(mdwc->dev, "Not in P3,aborting LPM sequence\n");
return -EBUSY;
@@ -1967,7 +1966,7 @@ static int dwc3_msm_suspend(struct dwc3_msm *mdwc)
clk_disable_unprepare(mdwc->xo_clk);
/* Perform controller power collapse */
- if (!mdwc->in_host_mode && !mdwc->vbus_active) {
+ if (!mdwc->in_host_mode && (!mdwc->vbus_active || mdwc->in_restart)) {
mdwc->lpm_flags |= MDWC3_POWER_COLLAPSE;
dev_dbg(mdwc->dev, "%s: power collapse\n", __func__);
dwc3_msm_config_gdsc(mdwc, 0);
diff --git a/drivers/usb/gadget/Kconfig b/drivers/usb/gadget/Kconfig
index 9ef57e5d7d64..9d9eed2d5d68 100644
--- a/drivers/usb/gadget/Kconfig
+++ b/drivers/usb/gadget/Kconfig
@@ -178,6 +178,9 @@ config USB_F_RNDIS
config USB_F_QCRNDIS
tristate
+config USB_F_RMNET_BAM
+ tristate
+
config USB_F_MASS_STORAGE
tristate
@@ -345,6 +348,12 @@ config USB_CONFIGFS_RNDIS
XP, you'll need to download drivers from Microsoft's website; a URL
is given in comments found in that info file.
+config USB_CONFIGFS_RMNET_BAM
+ bool "RMNET"
+ depends on USB_CONFIGFS
+ depends on IPA
+ select USB_F_RMNET_BAM
+
config USB_CONFIGFS_EEM
bool "Ethernet Emulation Model (EEM)"
depends on USB_CONFIGFS
diff --git a/drivers/usb/gadget/function/Makefile b/drivers/usb/gadget/function/Makefile
index a213cd4c8377..511909fb78f6 100644
--- a/drivers/usb/gadget/function/Makefile
+++ b/drivers/usb/gadget/function/Makefile
@@ -62,3 +62,5 @@ usb_f_qdss-y := f_qdss.o u_qdss.o
obj-$(CONFIG_USB_F_QDSS) += usb_f_qdss.o
usb_f_qcrndis-y := f_qc_rndis.o u_data_ipa.o
obj-$(CONFIG_USB_F_QCRNDIS) += usb_f_qcrndis.o
+usb_f_rmnet_bam-y := f_rmnet.o u_ctrl_qti.o
+obj-$(CONFIG_USB_F_RMNET_BAM) += usb_f_rmnet_bam.o
diff --git a/drivers/usb/gadget/function/f_fs.c b/drivers/usb/gadget/function/f_fs.c
index eb2409dda50d..19d6a997ee6c 100644
--- a/drivers/usb/gadget/function/f_fs.c
+++ b/drivers/usb/gadget/function/f_fs.c
@@ -760,8 +760,8 @@ static ssize_t ffs_epfile_io(struct file *file, struct ffs_io_data *io_data)
ssize_t ret, data_len = -EINVAL;
int halt;
- ffs_log("enter: epfile name %s epfile err %d", epfile->name,
- atomic_read(&epfile->error));
+ ffs_log("enter: epfile name %s epfile err %d (%s)", epfile->name,
+ atomic_read(&epfile->error), io_data->read ? "READ" : "WRITE");
smp_mb__before_atomic();
if (atomic_read(&epfile->error))
@@ -781,6 +781,12 @@ static ssize_t ffs_epfile_io(struct file *file, struct ffs_io_data *io_data)
goto error;
}
+ /* Don't wait on write if device is offline */
+ if (!io_data->read) {
+ ret = -EINTR;
+ goto error;
+ }
+
/*
* If ep is disabled, this fails all current IOs
* and wait for next epfile open to happen.
diff --git a/drivers/usb/gadget/function/f_gsi.c b/drivers/usb/gadget/function/f_gsi.c
index 738f20d935d6..af20033b621f 100644
--- a/drivers/usb/gadget/function/f_gsi.c
+++ b/drivers/usb/gadget/function/f_gsi.c
@@ -1984,6 +1984,10 @@ static int gsi_set_alt(struct usb_function *f, unsigned intf, unsigned alt)
atomic_set(&gsi->connected, 1);
+ /* send 0 len pkt to qti to notify state change */
+ if (gsi->prot_id == IPA_USB_DIAG)
+ gsi_ctrl_send_cpkt_tomodem(gsi, NULL, 0);
+
return 0;
notify_ep_disable:
diff --git a/drivers/usb/gadget/function/f_qdss.h b/drivers/usb/gadget/function/f_qdss.h
index c4af5ac839cd..e3fe8ae03775 100644
--- a/drivers/usb/gadget/function/f_qdss.h
+++ b/drivers/usb/gadget/function/f_qdss.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2012-2015, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2012-2016, The Linux Foundation. All rights reserved.
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -21,6 +21,8 @@
#include <linux/usb/composite.h>
#include <linux/usb/usb_qdss.h>
+#include "u_rmnet.h"
+
struct usb_qdss_bam_connect_info {
u32 usb_bam_pipe_idx;
u32 peer_pipe_idx;
@@ -33,8 +35,8 @@ struct gqdss {
struct usb_ep *ctrl_out;
struct usb_ep *ctrl_in;
struct usb_ep *data;
- int (*send_encap_cmd)(u8 port_num, void *buf, size_t len);
- void (*notify_modem)(void *g, u8 port_num, int cbits);
+ int (*send_encap_cmd)(enum qti_port_type qport, void *buf, size_t len);
+ void (*notify_modem)(void *g, enum qti_port_type qport, int cbits);
};
/* struct f_qdss - USB qdss function driver private structure */
diff --git a/drivers/usb/gadget/function/f_rmnet.c b/drivers/usb/gadget/function/f_rmnet.c
index d84b55cef666..0fd7e213ef99 100644
--- a/drivers/usb/gadget/function/f_rmnet.c
+++ b/drivers/usb/gadget/function/f_rmnet.c
@@ -17,16 +17,11 @@
#include <linux/netdevice.h>
#include <linux/spinlock.h>
#include <linux/usb_bam.h>
+#include <linux/module.h>
-#include "usb_gadget_xport.h"
-#include "u_ether.h"
#include "u_rmnet.h"
-#include "gadget_chips.h"
-
-static unsigned int rmnet_dl_max_pkt_per_xfer = 7;
-module_param(rmnet_dl_max_pkt_per_xfer, uint, S_IRUGO | S_IWUSR);
-MODULE_PARM_DESC(rmnet_dl_max_pkt_per_xfer,
- "Maximum packets per transfer for DL aggregation");
+#include "u_data_ipa.h"
+#include "configfs.h"
#define RMNET_NOTIFY_INTERVAL 5
#define RMNET_MAX_NOTIFY_SIZE sizeof(struct usb_cdc_notification)
@@ -38,10 +33,9 @@ MODULE_PARM_DESC(rmnet_dl_max_pkt_per_xfer,
* control paths
*/
struct f_rmnet {
- struct gether gether_port;
+ struct usb_function func;
struct grmnet port;
int ifc_id;
- u8 port_num;
atomic_t online;
atomic_t ctrl_online;
struct usb_composite_dev *cdev;
@@ -53,30 +47,11 @@ struct f_rmnet {
struct usb_request *notify_req;
/* control info */
+ struct gadget_ipa_port ipa_port;
struct list_head cpkt_resp_q;
unsigned long notify_count;
unsigned long cpkts_len;
- const struct usb_endpoint_descriptor *in_ep_desc_backup;
- const struct usb_endpoint_descriptor *out_ep_desc_backup;
-};
-
-static unsigned int nr_rmnet_ports;
-static unsigned int no_ctrl_smd_ports;
-static unsigned int no_ctrl_qti_ports;
-static unsigned int no_ctrl_hsic_ports;
-static unsigned int no_ctrl_hsuart_ports;
-static unsigned int no_data_bam_ports;
-static unsigned int no_data_bam2bam_ports;
-static unsigned int no_data_hsic_ports;
-static unsigned int no_data_hsuart_ports;
-static struct rmnet_ports {
- enum transport_type data_xport;
- enum transport_type ctrl_xport;
- unsigned data_xport_num;
- unsigned ctrl_xport_num;
- unsigned port_num;
- struct f_rmnet *port;
-} rmnet_ports[NR_RMNET_PORTS];
+} *rmnet_port;
static struct usb_interface_descriptor rmnet_interface_desc = {
.bLength = USB_DT_INTERFACE_SIZE,
@@ -244,7 +219,7 @@ static void frmnet_ctrl_response_available(struct f_rmnet *dev);
static inline struct f_rmnet *func_to_rmnet(struct usb_function *f)
{
- return container_of(f, struct f_rmnet, gether_port.func);
+ return container_of(f, struct f_rmnet, func);
}
static inline struct f_rmnet *port_to_rmnet(struct grmnet *r)
@@ -253,8 +228,7 @@ static inline struct f_rmnet *port_to_rmnet(struct grmnet *r)
}
static struct usb_request *
-frmnet_alloc_req(struct usb_ep *ep, unsigned len, size_t extra_buf_alloc,
- gfp_t flags)
+frmnet_alloc_req(struct usb_ep *ep, unsigned len, gfp_t flags)
{
struct usb_request *req;
@@ -262,7 +236,7 @@ frmnet_alloc_req(struct usb_ep *ep, unsigned len, size_t extra_buf_alloc,
if (!req)
return ERR_PTR(-ENOMEM);
- req->buf = kmalloc(len + extra_buf_alloc, flags);
+ req->buf = kmalloc(len, flags);
if (!req->buf) {
usb_ep_free_request(ep, req);
return ERR_PTR(-ENOMEM);
@@ -305,198 +279,42 @@ static void rmnet_free_ctrl_pkt(struct rmnet_ctrl_pkt *pkt)
/* -------------------------------------------*/
-static int rmnet_gport_setup(void)
-{
- int ret;
- int port_idx;
- int i;
- u8 base;
-
- pr_debug("%s: bam ports:%u bam2bam ports:%u data hsic ports:%u\n",
- __func__, no_data_bam_ports, no_data_bam2bam_ports,
- no_data_hsic_ports);
-
- pr_debug("%s: data hsuart ports:%u smd ports:%u ctrl hsic ports:%u\n",
- __func__, no_data_hsuart_ports, no_ctrl_smd_ports,
- no_ctrl_hsic_ports);
-
- pr_debug("%s: ctrl hsuart ports:%u nr_rmnet_ports:%u\n",
- __func__, no_ctrl_hsuart_ports, nr_rmnet_ports);
-
- if (no_data_bam_ports) {
- ret = gbam_setup(no_data_bam_ports);
- if (ret < 0)
- return ret;
- }
-
- if (no_data_bam2bam_ports) {
- ret = gbam2bam_setup(no_data_bam2bam_ports);
- if (ret < 0)
- return ret;
- }
-
- if (no_ctrl_smd_ports) {
- ret = gsmd_ctrl_setup(FRMNET_CTRL_CLIENT,
- no_ctrl_smd_ports, &base);
- if (ret)
- return ret;
- for (i = 0; i < nr_rmnet_ports; i++)
- if (rmnet_ports[i].port)
- rmnet_ports[i].port->port_num += base;
- }
-
- if (no_data_hsic_ports) {
- port_idx = ghsic_data_setup(no_data_hsic_ports,
- USB_GADGET_RMNET);
- if (port_idx < 0)
- return port_idx;
- for (i = 0; i < nr_rmnet_ports; i++) {
- if (rmnet_ports[i].data_xport ==
- USB_GADGET_XPORT_HSIC) {
- rmnet_ports[i].data_xport_num = port_idx;
- port_idx++;
- }
- }
- }
-
- if (no_ctrl_hsic_ports) {
- port_idx = ghsic_ctrl_setup(no_ctrl_hsic_ports,
- USB_GADGET_RMNET);
- if (port_idx < 0)
- return port_idx;
- for (i = 0; i < nr_rmnet_ports; i++) {
- if (rmnet_ports[i].ctrl_xport ==
- USB_GADGET_XPORT_HSIC) {
- rmnet_ports[i].ctrl_xport_num = port_idx;
- port_idx++;
- }
- }
- }
-
- return 0;
-}
-
static int gport_rmnet_connect(struct f_rmnet *dev, unsigned intf)
{
int ret;
- unsigned port_num;
- enum transport_type cxport = rmnet_ports[dev->port_num].ctrl_xport;
- enum transport_type dxport = rmnet_ports[dev->port_num].data_xport;
int src_connection_idx = 0, dst_connection_idx = 0;
struct usb_gadget *gadget = dev->cdev->gadget;
enum usb_ctrl usb_bam_type;
- void *net;
-
- pr_debug("%s: ctrl xport: %s data xport: %s dev: %p portno: %d\n",
- __func__, xport_to_str(cxport), xport_to_str(dxport),
- dev, dev->port_num);
- port_num = rmnet_ports[dev->port_num].ctrl_xport_num;
- switch (cxport) {
- case USB_GADGET_XPORT_SMD:
- ret = gsmd_ctrl_connect(&dev->port, port_num);
- if (ret) {
- pr_err("%s: gsmd_ctrl_connect failed: err:%d\n",
- __func__, ret);
- return ret;
- }
- break;
- case USB_GADGET_XPORT_QTI:
- ret = gqti_ctrl_connect(&dev->port, port_num, dev->ifc_id,
- dxport, USB_GADGET_RMNET);
- if (ret) {
- pr_err("%s: gqti_ctrl_connect failed: err:%d\n",
- __func__, ret);
- return ret;
- }
- break;
- case USB_GADGET_XPORT_HSIC:
- ret = ghsic_ctrl_connect(&dev->port, port_num);
- if (ret) {
- pr_err("%s: ghsic_ctrl_connect failed: err:%d\n",
- __func__, ret);
- return ret;
- }
- break;
- case USB_GADGET_XPORT_NONE:
- break;
- default:
- pr_err("%s: Un-supported transport: %s\n", __func__,
- xport_to_str(cxport));
- return -ENODEV;
+ ret = gqti_ctrl_connect(&dev->port, QTI_PORT_RMNET, dev->ifc_id);
+ if (ret) {
+ pr_err("%s: gqti_ctrl_connect failed: err:%d\n",
+ __func__, ret);
+ return ret;
}
- port_num = rmnet_ports[dev->port_num].data_xport_num;
-
- switch (dxport) {
- case USB_GADGET_XPORT_BAM_DMUX:
- ret = gbam_connect(&dev->port, port_num,
- dxport, src_connection_idx, dst_connection_idx);
- if (ret) {
- pr_err("%s: gbam_connect failed: err:%d\n",
- __func__, ret);
- gsmd_ctrl_disconnect(&dev->port, port_num);
- return ret;
- }
- break;
- case USB_GADGET_XPORT_BAM2BAM_IPA:
- usb_bam_type = usb_bam_get_bam_type(gadget->name);
- src_connection_idx = usb_bam_get_connection_idx(usb_bam_type,
- IPA_P_BAM, USB_TO_PEER_PERIPHERAL, USB_BAM_DEVICE,
- port_num);
- dst_connection_idx = usb_bam_get_connection_idx(usb_bam_type,
- IPA_P_BAM, PEER_PERIPHERAL_TO_USB, USB_BAM_DEVICE,
- port_num);
- if (dst_connection_idx < 0 || src_connection_idx < 0) {
- pr_err("%s: usb_bam_get_connection_idx failed\n",
- __func__);
- gsmd_ctrl_disconnect(&dev->port, port_num);
- return -EINVAL;
- }
- ret = gbam_connect(&dev->port, port_num,
- dxport, src_connection_idx, dst_connection_idx);
- if (ret) {
- pr_err("%s: gbam_connect failed: err:%d\n",
- __func__, ret);
- if (cxport == USB_GADGET_XPORT_QTI)
- gqti_ctrl_disconnect(&dev->port, port_num);
- else
- gsmd_ctrl_disconnect(&dev->port, port_num);
- return ret;
- }
- break;
- case USB_GADGET_XPORT_HSIC:
- ret = ghsic_data_connect(&dev->port, port_num);
- if (ret) {
- pr_err("%s: ghsic_data_connect failed: err:%d\n",
- __func__, ret);
- ghsic_ctrl_disconnect(&dev->port, port_num);
- return ret;
- }
- break;
- case USB_GADGET_XPORT_ETHER:
- gether_enable_sg(&dev->gether_port, true);
- net = gether_connect(&dev->gether_port);
- if (IS_ERR(net)) {
- pr_err("%s: gether_connect failed: err:%ld\n",
- __func__, PTR_ERR(net));
- if (cxport == USB_GADGET_XPORT_QTI)
- gqti_ctrl_disconnect(&dev->port, port_num);
- else
- gsmd_ctrl_disconnect(&dev->port, port_num);
-
- return PTR_ERR(net);
- }
- gether_update_dl_max_pkts_per_xfer(&dev->gether_port,
- rmnet_dl_max_pkt_per_xfer);
- gether_update_dl_max_xfer_size(&dev->gether_port, 16384);
- break;
- case USB_GADGET_XPORT_NONE:
- break;
- default:
- pr_err("%s: Un-supported transport: %s\n", __func__,
- xport_to_str(dxport));
- return -ENODEV;
+ dev->ipa_port.cdev = dev->cdev;
+ ipa_data_port_select(USB_IPA_FUNC_RMNET);
+ usb_bam_type = usb_bam_get_bam_type(gadget->name);
+ src_connection_idx = usb_bam_get_connection_idx(usb_bam_type,
+ IPA_P_BAM, USB_TO_PEER_PERIPHERAL, USB_BAM_DEVICE,
+ QTI_PORT_RMNET);
+ dst_connection_idx = usb_bam_get_connection_idx(usb_bam_type,
+ IPA_P_BAM, PEER_PERIPHERAL_TO_USB, USB_BAM_DEVICE,
+ QTI_PORT_RMNET);
+ if (dst_connection_idx < 0 || src_connection_idx < 0) {
+ pr_err("%s: usb_bam_get_connection_idx failed\n",
+ __func__);
+ gqti_ctrl_disconnect(&dev->port, QTI_PORT_RMNET);
+ return -EINVAL;
+ }
+ ret = ipa_data_connect(&dev->ipa_port, USB_IPA_FUNC_RMNET,
+ src_connection_idx, dst_connection_idx);
+ if (ret) {
+ pr_err("%s: ipa_data_connect failed: err:%d\n",
+ __func__, ret);
+ gqti_ctrl_disconnect(&dev->port, QTI_PORT_RMNET);
+ return ret;
}
return 0;
@@ -504,61 +322,26 @@ static int gport_rmnet_connect(struct f_rmnet *dev, unsigned intf)
static int gport_rmnet_disconnect(struct f_rmnet *dev)
{
- unsigned port_num;
- enum transport_type cxport = rmnet_ports[dev->port_num].ctrl_xport;
- enum transport_type dxport = rmnet_ports[dev->port_num].data_xport;
-
- pr_debug("%s: ctrl xport: %s data xport: %s dev: %p portno: %d\n",
- __func__, xport_to_str(cxport), xport_to_str(dxport),
- dev, dev->port_num);
-
- port_num = rmnet_ports[dev->port_num].ctrl_xport_num;
- switch (cxport) {
- case USB_GADGET_XPORT_SMD:
- gsmd_ctrl_disconnect(&dev->port, port_num);
- break;
- case USB_GADGET_XPORT_QTI:
- gqti_ctrl_disconnect(&dev->port, port_num);
- break;
- case USB_GADGET_XPORT_HSIC:
- ghsic_ctrl_disconnect(&dev->port, port_num);
- break;
- case USB_GADGET_XPORT_NONE:
- break;
- default:
- pr_err("%s: Un-supported transport: %s\n", __func__,
- xport_to_str(cxport));
- return -ENODEV;
- }
+ gqti_ctrl_disconnect(&dev->port, QTI_PORT_RMNET);
+ ipa_data_disconnect(&dev->ipa_port, USB_IPA_FUNC_RMNET);
+ return 0;
+}
- port_num = rmnet_ports[dev->port_num].data_xport_num;
- switch (dxport) {
- case USB_GADGET_XPORT_BAM_DMUX:
- case USB_GADGET_XPORT_BAM2BAM_IPA:
- gbam_disconnect(&dev->port, port_num, dxport);
- break;
- case USB_GADGET_XPORT_HSIC:
- ghsic_data_disconnect(&dev->port, port_num);
- break;
- case USB_GADGET_XPORT_ETHER:
- gether_disconnect(&dev->gether_port);
- break;
- case USB_GADGET_XPORT_NONE:
- break;
- default:
- pr_err("%s: Un-supported transport: %s\n", __func__,
- xport_to_str(dxport));
- return -ENODEV;
- }
+static void frmnet_free(struct usb_function *f)
+{
+ struct f_rmnet_opts *opts;
- return 0;
+ opts = container_of(f->fi, struct f_rmnet_opts, func_inst);
+ opts->refcnt--;
+ kfree(rmnet_port);
+ rmnet_port = NULL;
}
static void frmnet_unbind(struct usb_configuration *c, struct usb_function *f)
{
struct f_rmnet *dev = func_to_rmnet(f);
- pr_debug("%s: portno:%d\n", __func__, dev->port_num);
+ pr_debug("%s: start unbinding\n", __func__);
if (gadget_is_superspeed(c->cdev->gadget))
usb_free_descriptors(f->ss_descriptors);
if (gadget_is_dualspeed(c->cdev->gadget))
@@ -575,8 +358,7 @@ static void frmnet_purge_responses(struct f_rmnet *dev)
unsigned long flags;
struct rmnet_ctrl_pkt *cpkt;
- pr_debug("%s: port#%d\n", __func__, dev->port_num);
-
+ pr_debug("%s: Purging responses\n", __func__);
spin_lock_irqsave(&dev->lock, flags);
while (!list_empty(&dev->cpkt_resp_q)) {
cpkt = list_first_entry(&dev->cpkt_resp_q,
@@ -591,117 +373,46 @@ static void frmnet_purge_responses(struct f_rmnet *dev)
static void frmnet_suspend(struct usb_function *f)
{
- struct f_rmnet *dev = func_to_rmnet(f);
- unsigned port_num;
- enum transport_type dxport = rmnet_ports[dev->port_num].data_xport;
- bool remote_wakeup_allowed;
+ struct f_rmnet *dev = func_to_rmnet(f);
+ bool remote_wakeup_allowed;
if (f->config->cdev->gadget->speed == USB_SPEED_SUPER)
remote_wakeup_allowed = f->func_wakeup_allowed;
else
remote_wakeup_allowed = f->config->cdev->gadget->remote_wakeup;
- pr_debug("%s: data xport: %s dev: %p portno: %d remote_wakeup: %d\n",
- __func__, xport_to_str(dxport),
- dev, dev->port_num, remote_wakeup_allowed);
+ pr_debug("%s: dev: %p remote_wakeup: %d\n",
+ __func__, dev, remote_wakeup_allowed);
usb_ep_fifo_flush(dev->notify);
frmnet_purge_responses(dev);
- port_num = rmnet_ports[dev->port_num].data_xport_num;
- switch (dxport) {
- case USB_GADGET_XPORT_BAM_DMUX:
- break;
- case USB_GADGET_XPORT_BAM2BAM_IPA:
- if (remote_wakeup_allowed) {
- gbam_suspend(&dev->port, port_num, dxport);
- } else {
- /*
- * When remote wakeup is disabled, IPA is disconnected
- * because it cannot send new data until the USB bus is
- * resumed. Endpoint descriptors info is saved before it
- * gets reset by the BAM disconnect API. This lets us
- * restore this info when the USB bus is resumed.
- */
- dev->in_ep_desc_backup = dev->port.in->desc;
- dev->out_ep_desc_backup = dev->port.out->desc;
- pr_debug("in_ep_desc_bkup = %p, out_ep_desc_bkup = %p",
- dev->in_ep_desc_backup, dev->out_ep_desc_backup);
- pr_debug("%s(): Disconnecting\n", __func__);
- gport_rmnet_disconnect(dev);
- }
- break;
- case USB_GADGET_XPORT_HSIC:
- break;
- case USB_GADGET_XPORT_HSUART:
- break;
- case USB_GADGET_XPORT_ETHER:
- break;
- case USB_GADGET_XPORT_NONE:
- break;
- default:
- pr_err("%s: Un-supported transport: %s\n", __func__,
- xport_to_str(dxport));
- }
+ ipa_data_suspend(&dev->ipa_port, USB_IPA_FUNC_RMNET,
+ remote_wakeup_allowed);
}
static void frmnet_resume(struct usb_function *f)
{
- struct f_rmnet *dev = func_to_rmnet(f);
- unsigned port_num;
- enum transport_type dxport = rmnet_ports[dev->port_num].data_xport;
- int ret;
- bool remote_wakeup_allowed;
+ struct f_rmnet *dev = func_to_rmnet(f);
+ bool remote_wakeup_allowed;
if (f->config->cdev->gadget->speed == USB_SPEED_SUPER)
remote_wakeup_allowed = f->func_wakeup_allowed;
else
remote_wakeup_allowed = f->config->cdev->gadget->remote_wakeup;
- pr_debug("%s: data xport: %s dev: %p portno: %d remote_wakeup: %d\n",
- __func__, xport_to_str(dxport),
- dev, dev->port_num, remote_wakeup_allowed);
+ pr_debug("%s: dev: %p remote_wakeup: %d\n",
+ __func__, dev, remote_wakeup_allowed);
- port_num = rmnet_ports[dev->port_num].data_xport_num;
- switch (dxport) {
- case USB_GADGET_XPORT_BAM_DMUX:
- break;
- case USB_GADGET_XPORT_BAM2BAM_IPA:
- if (remote_wakeup_allowed) {
- gbam_resume(&dev->port, port_num, dxport);
- } else {
- dev->port.in->desc = dev->in_ep_desc_backup;
- dev->port.out->desc = dev->out_ep_desc_backup;
- pr_debug("%s(): Connecting\n", __func__);
- ret = gport_rmnet_connect(dev, dev->ifc_id);
- if (ret) {
- pr_err("%s: gport_rmnet_connect failed: err:%d\n",
- __func__, ret);
- }
- }
- break;
- case USB_GADGET_XPORT_HSIC:
- break;
- case USB_GADGET_XPORT_HSUART:
- break;
- case USB_GADGET_XPORT_ETHER:
- break;
- case USB_GADGET_XPORT_NONE:
- break;
- default:
- pr_err("%s: Un-supported transport: %s\n", __func__,
- xport_to_str(dxport));
- }
+ ipa_data_resume(&dev->ipa_port, USB_IPA_FUNC_RMNET,
+ remote_wakeup_allowed);
}
static void frmnet_disable(struct usb_function *f)
{
- struct f_rmnet *dev = func_to_rmnet(f);
- enum transport_type dxport = rmnet_ports[dev->port_num].data_xport;
- struct usb_composite_dev *cdev = dev->cdev;
-
- pr_debug("%s: port#%d\n", __func__, dev->port_num);
+ struct f_rmnet *dev = func_to_rmnet(f);
+ pr_debug("%s: Disabling\n", __func__);
usb_ep_disable(dev->notify);
dev->notify->driver_data = NULL;
@@ -709,11 +420,8 @@ static void frmnet_disable(struct usb_function *f)
frmnet_purge_responses(dev);
- if (dxport == USB_GADGET_XPORT_BAM2BAM_IPA &&
- gadget_is_dwc3(cdev->gadget)) {
- msm_ep_unconfig(dev->port.out);
- msm_ep_unconfig(dev->port.in);
- }
+ msm_ep_unconfig(dev->ipa_port.out);
+ msm_ep_unconfig(dev->ipa_port.in);
gport_rmnet_disconnect(dev);
}
@@ -721,14 +429,14 @@ static int
frmnet_set_alt(struct usb_function *f, unsigned intf, unsigned alt)
{
struct f_rmnet *dev = func_to_rmnet(f);
- struct usb_composite_dev *cdev = dev->cdev;
+ struct usb_composite_dev *cdev = f->config->cdev;
int ret;
- struct list_head *cpkt;
-
- pr_debug("%s:dev:%p port#%d\n", __func__, dev, dev->port_num);
+ struct list_head *cpkt;
+ pr_debug("%s: dev: %p\n", __func__, dev);
+ dev->cdev = cdev;
if (dev->notify->driver_data) {
- pr_debug("%s: reset port:%d\n", __func__, dev->port_num);
+ pr_debug("%s: reset port\n", __func__);
usb_ep_disable(dev->notify);
}
@@ -749,14 +457,14 @@ frmnet_set_alt(struct usb_function *f, unsigned intf, unsigned alt)
}
dev->notify->driver_data = dev;
- if (!dev->port.in->desc || !dev->port.out->desc) {
- if (config_ep_by_speed(cdev->gadget, f, dev->port.in) ||
- config_ep_by_speed(cdev->gadget, f, dev->port.out)) {
+ if (!dev->ipa_port.in->desc || !dev->ipa_port.out->desc) {
+ if (config_ep_by_speed(cdev->gadget, f, dev->ipa_port.in) ||
+ config_ep_by_speed(cdev->gadget, f, dev->ipa_port.out)) {
pr_err("%s(): config_ep_by_speed failed.\n", __func__);
ret = -EINVAL;
goto err_disable_ep;
}
- dev->port.gadget = dev->cdev->gadget;
+ dev->ipa_port.cdev = dev->cdev;
}
ret = gport_rmnet_connect(dev, intf);
@@ -777,8 +485,8 @@ frmnet_set_alt(struct usb_function *f, unsigned intf, unsigned alt)
return ret;
err_disable_ep:
- dev->port.in->desc = NULL;
- dev->port.out->desc = NULL;
+ dev->ipa_port.in->desc = NULL;
+ dev->ipa_port.out->desc = NULL;
usb_ep_disable(dev->notify);
return ret;
@@ -790,10 +498,9 @@ static void frmnet_ctrl_response_available(struct f_rmnet *dev)
struct usb_cdc_notification *event;
unsigned long flags;
int ret;
- struct rmnet_ctrl_pkt *cpkt;
-
- pr_debug("%s:dev:%p portno#%d\n", __func__, dev, dev->port_num);
+ struct rmnet_ctrl_pkt *cpkt;
+ pr_debug("%s: dev: %p\n", __func__, dev);
spin_lock_irqsave(&dev->lock, flags);
if (!atomic_read(&dev->online) || !req || !req->buf) {
spin_unlock_irqrestore(&dev->lock, flags);
@@ -913,8 +620,7 @@ frmnet_send_cpkt_response(void *gr, void *buf, size_t len)
dev = port_to_rmnet(gr);
- pr_debug("%s: dev:%p port#%d\n", __func__, dev, dev->port_num);
-
+ pr_debug("%s: dev: %p\n", __func__, dev);
if (!atomic_read(&dev->online) || !atomic_read(&dev->ctrl_online)) {
rmnet_free_ctrl_pkt(cpkt);
return 0;
@@ -934,32 +640,27 @@ frmnet_cmd_complete(struct usb_ep *ep, struct usb_request *req)
{
struct f_rmnet *dev = req->context;
struct usb_composite_dev *cdev;
- unsigned port_num;
if (!dev) {
pr_err("%s: rmnet dev is null\n", __func__);
return;
}
-
- pr_debug("%s: dev:%p port#%d\n", __func__, dev, dev->port_num);
-
+ pr_debug("%s: dev: %p\n", __func__, dev);
cdev = dev->cdev;
if (dev->port.send_encap_cmd) {
- port_num = rmnet_ports[dev->port_num].ctrl_xport_num;
- dev->port.send_encap_cmd(port_num, req->buf, req->actual);
+ dev->port.send_encap_cmd(QTI_PORT_RMNET, req->buf, req->actual);
}
}
static void frmnet_notify_complete(struct usb_ep *ep, struct usb_request *req)
{
- struct f_rmnet *dev = req->context;
- int status = req->status;
+ struct f_rmnet *dev = req->context;
+ int status = req->status;
unsigned long flags;
struct rmnet_ctrl_pkt *cpkt;
- pr_debug("%s: dev:%p port#%d\n", __func__, dev, dev->port_num);
-
+ pr_debug("%s: dev: %p\n", __func__, dev);
switch (status) {
case -ECONNRESET:
case -ESHUTDOWN:
@@ -1021,14 +722,12 @@ frmnet_setup(struct usb_function *f, const struct usb_ctrlrequest *ctrl)
struct f_rmnet *dev = func_to_rmnet(f);
struct usb_composite_dev *cdev = dev->cdev;
struct usb_request *req = cdev->req;
- unsigned port_num;
u16 w_index = le16_to_cpu(ctrl->wIndex);
u16 w_value = le16_to_cpu(ctrl->wValue);
u16 w_length = le16_to_cpu(ctrl->wLength);
int ret = -EOPNOTSUPP;
- pr_debug("%s:dev:%p port#%d\n", __func__, dev, dev->port_num);
-
+ pr_debug("%s: dev: %p\n", __func__, dev);
if (!atomic_read(&dev->online)) {
pr_warn("%s: usb cable is not connected\n", __func__);
return -ENOTCONN;
@@ -1085,8 +784,8 @@ frmnet_setup(struct usb_function *f, const struct usb_ctrlrequest *ctrl)
pr_debug("%s: USB_CDC_REQ_SET_CONTROL_LINE_STATE: DTR:%d\n",
__func__, w_value & ACM_CTRL_DTR ? 1 : 0);
if (dev->port.notify_modem) {
- port_num = rmnet_ports[dev->port_num].ctrl_xport_num;
- dev->port.notify_modem(&dev->port, port_num, w_value);
+ dev->port.notify_modem(&dev->port,
+ QTI_PORT_RMNET, w_value);
}
ret = 0;
@@ -1121,6 +820,16 @@ static int frmnet_bind(struct usb_configuration *c, struct usb_function *f)
struct usb_composite_dev *cdev = c->cdev;
int ret = -ENODEV;
+ if (rmnet_string_defs[0].id == 0) {
+ ret = usb_string_id(c->cdev);
+ if (ret < 0) {
+ pr_err("%s: failed to get string id, err:%d\n",
+ __func__, ret);
+ return ret;
+ }
+ rmnet_string_defs[0].id = ret;
+ }
+
pr_debug("%s: start binding\n", __func__);
dev->ifc_id = usb_interface_id(c, f);
if (dev->ifc_id < 0) {
@@ -1135,9 +844,7 @@ static int frmnet_bind(struct usb_configuration *c, struct usb_function *f)
pr_err("%s: usb epin autoconfig failed\n", __func__);
return -ENODEV;
}
- dev->port.in = ep;
- /* Update same for u_ether which uses gether port struct */
- dev->gether_port.in_ep = ep;
+ dev->ipa_port.in = ep;
ep->driver_data = cdev;
ep = usb_ep_autoconfig(cdev->gadget, &rmnet_fs_out_desc);
@@ -1146,9 +853,7 @@ static int frmnet_bind(struct usb_configuration *c, struct usb_function *f)
ret = -ENODEV;
goto ep_auto_out_fail;
}
- dev->port.out = ep;
- /* Update same for u_ether which uses gether port struct */
- dev->gether_port.out_ep = ep;
+ dev->ipa_port.out = ep;
ep->driver_data = cdev;
ep = usb_ep_autoconfig(cdev->gadget, &rmnet_fs_notify_desc);
@@ -1162,7 +867,6 @@ static int frmnet_bind(struct usb_configuration *c, struct usb_function *f)
dev->notify_req = frmnet_alloc_req(ep,
sizeof(struct usb_cdc_notification),
- cdev->gadget->extra_buf_alloc,
GFP_KERNEL);
if (IS_ERR(dev->notify_req)) {
pr_err("%s: unable to allocate memory for notify req\n",
@@ -1218,10 +922,9 @@ static int frmnet_bind(struct usb_configuration *c, struct usb_function *f)
}
}
- pr_debug("%s: RmNet(%d) %s Speed, IN:%s OUT:%s\n",
- __func__, dev->port_num,
- gadget_is_dualspeed(cdev->gadget) ? "dual" : "full",
- dev->port.in->name, dev->port.out->name);
+ pr_debug("%s: RmNet %s Speed, IN:%s OUT:%s\n",
+ __func__, gadget_is_dualspeed(cdev->gadget) ? "dual" : "full",
+ dev->ipa_port.in->name, dev->ipa_port.out->name);
return 0;
@@ -1238,67 +941,35 @@ ep_notify_alloc_fail:
dev->notify->driver_data = NULL;
dev->notify = NULL;
ep_auto_notify_fail:
- dev->port.out->driver_data = NULL;
- dev->port.out = NULL;
+ dev->ipa_port.out->driver_data = NULL;
+ dev->ipa_port.out = NULL;
ep_auto_out_fail:
- dev->port.in->driver_data = NULL;
- dev->port.in = NULL;
+ dev->ipa_port.in->driver_data = NULL;
+ dev->ipa_port.in = NULL;
return ret;
}
-static int frmnet_bind_config(struct usb_configuration *c, unsigned portno)
+static struct usb_function *frmnet_bind_config(struct usb_function_instance *fi)
{
+ struct f_rmnet_opts *opts;
int status;
struct f_rmnet *dev;
struct usb_function *f;
unsigned long flags;
- pr_debug("%s: usb config:%p\n", __func__, c);
-
- if (portno >= nr_rmnet_ports) {
- pr_err("%s: supporting ports#%u port_id:%u\n", __func__,
- nr_rmnet_ports, portno);
- return -ENODEV;
- }
-
- dev = rmnet_ports[portno].port;
-
- if (rmnet_ports[portno].data_xport == USB_GADGET_XPORT_ETHER) {
- struct net_device *net = gether_setup_name_default("usb_rmnet");
-
- if (IS_ERR(net)) {
- pr_err("%s: gether_setup failed\n", __func__);
- return PTR_ERR(net);
- }
- dev->gether_port.ioport = netdev_priv(net);
- gether_set_gadget(net, c->cdev->gadget);
- status = gether_register_netdev(net);
- if (status < 0) {
- pr_err("%s: gether_register_netdev failed\n", __func__);
- free_netdev(net);
- return status;
- }
- }
-
- if (rmnet_string_defs[0].id == 0) {
- status = usb_string_id(c->cdev);
- if (status < 0) {
- pr_err("%s: failed to get string id, err:%d\n",
- __func__, status);
- return status;
- }
- rmnet_string_defs[0].id = status;
- }
-
+ /* allocate and initialize one new instance */
+ status = -ENOMEM;
+ opts = container_of(fi, struct f_rmnet_opts, func_inst);
+ opts->refcnt++;
+ dev = opts->dev;
spin_lock_irqsave(&dev->lock, flags);
- dev->cdev = c->cdev;
- f = &dev->gether_port.func;
- f->name = kasprintf(GFP_ATOMIC, "rmnet%d", portno);
+ f = &dev->func;
+ f->name = kasprintf(GFP_ATOMIC, "rmnet%d", 0);
spin_unlock_irqrestore(&dev->lock, flags);
if (!f->name) {
pr_err("%s: cannot allocate memory for name\n", __func__);
- return -ENOMEM;
+ return ERR_PTR(-ENOMEM);
}
f->strings = rmnet_strings;
@@ -1309,166 +980,123 @@ static int frmnet_bind_config(struct usb_configuration *c, unsigned portno)
f->setup = frmnet_setup;
f->suspend = frmnet_suspend;
f->resume = frmnet_resume;
+ f->free_func = frmnet_free;
dev->port.send_cpkt_response = frmnet_send_cpkt_response;
dev->port.disconnect = frmnet_disconnect;
dev->port.connect = frmnet_connect;
- dev->gether_port.cdc_filter = 0;
-
- status = usb_add_function(c, f);
- if (status) {
- pr_err("%s: usb add function failed: %d\n",
- __func__, status);
- kfree(f->name);
- return status;
- }
pr_debug("%s: complete\n", __func__);
- return status;
+ return f;
}
-static void frmnet_unbind_config(void)
+static int rmnet_init(void)
{
- int i;
+ return gqti_ctrl_init();
+}
- for (i = 0; i < nr_rmnet_ports; i++)
- if (rmnet_ports[i].data_xport == USB_GADGET_XPORT_ETHER) {
- gether_cleanup(rmnet_ports[i].port->gether_port.ioport);
- rmnet_ports[i].port->gether_port.ioport = NULL;
- }
+static void frmnet_cleanup(void)
+{
+ gqti_ctrl_cleanup();
}
-static int rmnet_init(void)
+static void rmnet_free_inst(struct usb_function_instance *f)
{
- return gqti_ctrl_init();
+ struct f_rmnet_opts *opts = container_of(f, struct f_rmnet_opts,
+ func_inst);
+ ipa_data_free(USB_IPA_FUNC_RMNET);
+ kfree(opts);
}
-static void frmnet_cleanup(void)
+static int rmnet_set_inst_name(struct usb_function_instance *fi,
+ const char *name)
{
- int i;
+ int name_len;
+ int ret;
- gqti_ctrl_cleanup();
+ name_len = strlen(name) + 1;
+ if (name_len > MAX_INST_NAME_LEN)
+ return -ENAMETOOLONG;
- for (i = 0; i < nr_rmnet_ports; i++)
- kfree(rmnet_ports[i].port);
-
- gbam_cleanup();
- nr_rmnet_ports = 0;
- no_ctrl_smd_ports = 0;
- no_ctrl_qti_ports = 0;
- no_data_bam_ports = 0;
- no_data_bam2bam_ports = 0;
- no_ctrl_hsic_ports = 0;
- no_data_hsic_ports = 0;
- no_ctrl_hsuart_ports = 0;
- no_data_hsuart_ports = 0;
+ ret = ipa_data_setup(USB_IPA_FUNC_RMNET);
+ return ret;
}
-static int frmnet_init_port(const char *ctrl_name, const char *data_name,
- const char *port_name)
+static inline struct f_rmnet_opts *to_f_rmnet_opts(struct config_item *item)
{
- struct f_rmnet *dev;
- struct rmnet_ports *rmnet_port;
- int ret;
- int i;
+ return container_of(to_config_group(item), struct f_rmnet_opts,
+ func_inst.group);
+}
- if (nr_rmnet_ports >= NR_RMNET_PORTS) {
- pr_err("%s: Max-%d instances supported\n",
- __func__, NR_RMNET_PORTS);
- return -EINVAL;
- }
+static void rmnet_opts_release(struct config_item *item)
+{
+ struct f_rmnet_opts *opts = to_f_rmnet_opts(item);
- pr_debug("%s: port#:%d, ctrl port: %s data port: %s\n",
- __func__, nr_rmnet_ports, ctrl_name, data_name);
+ usb_put_function_instance(&opts->func_inst);
+};
- dev = kzalloc(sizeof(struct f_rmnet), GFP_KERNEL);
- if (!dev)
- return -ENOMEM;
+static struct configfs_item_operations rmnet_item_ops = {
+ .release = rmnet_opts_release,
+};
- dev->port_num = nr_rmnet_ports;
- spin_lock_init(&dev->lock);
- INIT_LIST_HEAD(&dev->cpkt_resp_q);
+static struct config_item_type rmnet_func_type = {
+ .ct_item_ops = &rmnet_item_ops,
+ .ct_owner = THIS_MODULE,
+};
- rmnet_port = &rmnet_ports[nr_rmnet_ports];
- rmnet_port->port = dev;
- rmnet_port->port_num = nr_rmnet_ports;
- rmnet_port->ctrl_xport = str_to_xport(ctrl_name);
- rmnet_port->data_xport = str_to_xport(data_name);
+static struct usb_function_instance *rmnet_alloc_inst(void)
+{
+ struct f_rmnet_opts *opts;
- switch (rmnet_port->ctrl_xport) {
- case USB_GADGET_XPORT_SMD:
- rmnet_port->ctrl_xport_num = no_ctrl_smd_ports;
- no_ctrl_smd_ports++;
- break;
- case USB_GADGET_XPORT_QTI:
- rmnet_port->ctrl_xport_num = no_ctrl_qti_ports;
- no_ctrl_qti_ports++;
- break;
- case USB_GADGET_XPORT_HSIC:
- ghsic_ctrl_set_port_name(port_name, ctrl_name);
- rmnet_port->ctrl_xport_num = no_ctrl_hsic_ports;
- no_ctrl_hsic_ports++;
- break;
- case USB_GADGET_XPORT_HSUART:
- rmnet_port->ctrl_xport_num = no_ctrl_hsuart_ports;
- no_ctrl_hsuart_ports++;
- break;
- case USB_GADGET_XPORT_NONE:
- break;
- default:
- pr_err("%s: Un-supported transport: %u\n", __func__,
- rmnet_port->ctrl_xport);
- ret = -ENODEV;
- goto fail_probe;
- }
+ opts = kzalloc(sizeof(*opts), GFP_KERNEL);
+ if (!opts)
+ return ERR_PTR(-ENOMEM);
- switch (rmnet_port->data_xport) {
- case USB_GADGET_XPORT_BAM2BAM:
- /* Override BAM2BAM to BAM_DMUX for old ABI compatibility */
- rmnet_port->data_xport = USB_GADGET_XPORT_BAM_DMUX;
- /* fall-through */
- case USB_GADGET_XPORT_BAM_DMUX:
- rmnet_port->data_xport_num = no_data_bam_ports;
- no_data_bam_ports++;
- break;
- case USB_GADGET_XPORT_BAM2BAM_IPA:
- rmnet_port->data_xport_num = no_data_bam2bam_ports;
- no_data_bam2bam_ports++;
- break;
- case USB_GADGET_XPORT_HSIC:
- ghsic_data_set_port_name(port_name, data_name);
- rmnet_port->data_xport_num = no_data_hsic_ports;
- no_data_hsic_ports++;
- break;
- case USB_GADGET_XPORT_HSUART:
- rmnet_port->data_xport_num = no_data_hsuart_ports;
- no_data_hsuart_ports++;
- break;
- case USB_GADGET_XPORT_ETHER:
- case USB_GADGET_XPORT_NONE:
- break;
- default:
- pr_err("%s: Un-supported transport: %u\n", __func__,
- rmnet_port->data_xport);
- ret = -ENODEV;
- goto fail_probe;
- }
- nr_rmnet_ports++;
+ opts->func_inst.set_inst_name = rmnet_set_inst_name;
+ opts->func_inst.free_func_inst = rmnet_free_inst;
- return 0;
+ config_group_init_type_name(&opts->func_inst.group, "",
+ &rmnet_func_type);
+ return &opts->func_inst;
+}
+
+static struct usb_function *rmnet_alloc(struct usb_function_instance *fi)
+{
+ struct f_rmnet_opts *opts = container_of(fi,
+ struct f_rmnet_opts, func_inst);
+ rmnet_port = kzalloc(sizeof(struct f_rmnet), GFP_KERNEL);
+ if (!rmnet_port)
+ return ERR_PTR(-ENOMEM);
+ opts->dev = rmnet_port;
+ spin_lock_init(&rmnet_port->lock);
+ INIT_LIST_HEAD(&rmnet_port->cpkt_resp_q);
+ return frmnet_bind_config(fi);
+}
-fail_probe:
- for (i = 0; i < nr_rmnet_ports; i++)
- kfree(rmnet_ports[i].port);
+DECLARE_USB_FUNCTION(rmnet_bam, rmnet_alloc_inst, rmnet_alloc);
- nr_rmnet_ports = 0;
- no_ctrl_smd_ports = 0;
- no_ctrl_qti_ports = 0;
- no_data_bam_ports = 0;
- no_ctrl_hsic_ports = 0;
- no_data_hsic_ports = 0;
- no_ctrl_hsuart_ports = 0;
- no_data_hsuart_ports = 0;
+static int __init usb_rmnet_init(void)
+{
+ int ret;
+ ret = rmnet_init();
+ if (!ret) {
+ ret = usb_function_register(&rmnet_bamusb_func);
+ if (ret) {
+ pr_err("%s: failed to register rmnet %d\n",
+ __func__, ret);
+ return ret;
+ }
+ }
return ret;
}
+
+static void __exit usb_rmnet_exit(void)
+{
+ usb_function_unregister(&rmnet_bamusb_func);
+ frmnet_cleanup();
+}
+
+module_init(usb_rmnet_init);
+module_exit(usb_rmnet_exit);
+MODULE_DESCRIPTION("USB RMNET Function Driver");
diff --git a/drivers/usb/gadget/function/u_ctrl_qti.c b/drivers/usb/gadget/function/u_ctrl_qti.c
index 7ef56eca20b8..c0650b0abf8c 100644
--- a/drivers/usb/gadget/function/u_ctrl_qti.c
+++ b/drivers/usb/gadget/function/u_ctrl_qti.c
@@ -14,11 +14,11 @@
#include <linux/wait.h>
#include <linux/poll.h>
#include <linux/usb/usb_ctrl_qti.h>
-
-#include <soc/qcom/bam_dmux.h>
+#include <linux/miscdevice.h>
+#include <linux/debugfs.h>
#include "u_rmnet.h"
-#include "usb_gadget_xport.h"
+#include "f_qdss.h"
#define RMNET_CTRL_QTI_NAME "rmnet_ctrl"
#define DPL_CTRL_QTI_NAME "dpl_ctrl"
@@ -54,18 +54,18 @@ struct qti_ctrl_port {
struct list_head cpkt_req_q;
spinlock_t lock;
- enum gadget_type gtype;
+ enum qti_port_type port_type;
unsigned host_to_modem;
unsigned copied_to_modem;
unsigned copied_from_modem;
unsigned modem_to_host;
unsigned drp_cpkt_cnt;
};
-static struct qti_ctrl_port *ctrl_port[NR_QTI_PORTS];
+static struct qti_ctrl_port *ctrl_port[QTI_NUM_PORTS];
static inline int qti_ctrl_lock(atomic_t *excl)
{
- if (atomic_inc_return(excl) == 1) {
+ if (atomic_inc_return(excl) == 1)
return 0;
atomic_dec(excl);
return -EBUSY;
@@ -76,6 +76,32 @@ static inline void qti_ctrl_unlock(atomic_t *excl)
atomic_dec(excl);
}
+static struct rmnet_ctrl_pkt *alloc_rmnet_ctrl_pkt(unsigned len, gfp_t flags)
+{
+ struct rmnet_ctrl_pkt *pkt;
+
+ pkt = kzalloc(sizeof(struct rmnet_ctrl_pkt), flags);
+ if (!pkt)
+ return ERR_PTR(-ENOMEM);
+
+ pkt->buf = kmalloc(len, flags);
+ if (!pkt->buf) {
+ kfree(pkt);
+ return ERR_PTR(-ENOMEM);
+ }
+
+ pkt->len = len;
+
+ return pkt;
+}
+
+static void free_rmnet_ctrl_pkt(struct rmnet_ctrl_pkt *pkt)
+{
+ kfree(pkt->buf);
+ kfree(pkt);
+}
+
+
static void qti_ctrl_queue_notify(struct qti_ctrl_port *port)
{
unsigned long flags;
@@ -106,7 +132,8 @@ static void qti_ctrl_queue_notify(struct qti_ctrl_port *port)
wake_up(&port->read_wq);
}
-static int gqti_ctrl_send_cpkt_tomodem(u8 portno, void *buf, size_t len)
+static int gqti_ctrl_send_cpkt_tomodem(enum qti_port_type qport,
+ void *buf, size_t len)
{
unsigned long flags;
struct qti_ctrl_port *port;
@@ -118,12 +145,11 @@ static int gqti_ctrl_send_cpkt_tomodem(u8 portno, void *buf, size_t len)
return -EINVAL;
}
- if (portno >= NR_QTI_PORTS) {
- pr_err("%s: Invalid QTI port %d\n", __func__, portno);
+ if (qport >= QTI_NUM_PORTS) {
+ pr_err("%s: Invalid QTI port %d\n", __func__, qport);
return -ENODEV;
}
- port = ctrl_port[portno];
-
+ port = ctrl_port[qport];
cpkt = alloc_rmnet_ctrl_pkt(len, GFP_ATOMIC);
if (IS_ERR(cpkt)) {
pr_err("%s: Unable to allocate ctrl pkt\n", __func__);
@@ -133,8 +159,8 @@ static int gqti_ctrl_send_cpkt_tomodem(u8 portno, void *buf, size_t len)
memcpy(cpkt->buf, buf, len);
cpkt->len = len;
- pr_debug("%s: gtype:%d: Add to cpkt_req_q packet with len = %zu\n",
- __func__, port->gtype, len);
+ pr_debug("%s: port type:%d: Add to cpkt_req_q packet with len = %zu\n",
+ __func__, port->port_type, len);
spin_lock_irqsave(&port->lock, flags);
/* drop cpkt if port is not open */
@@ -159,71 +185,51 @@ static int gqti_ctrl_send_cpkt_tomodem(u8 portno, void *buf, size_t len)
}
static void
-gqti_ctrl_notify_modem(void *gptr, u8 portno, int val)
+gqti_ctrl_notify_modem(void *gptr, enum qti_port_type qport, int val)
{
struct qti_ctrl_port *port;
- if (portno >= NR_QTI_PORTS) {
- pr_err("%s: Invalid QTI port %d\n", __func__, portno);
+ if (qport >= QTI_NUM_PORTS) {
+ pr_err("%s: Invalid QTI port %d\n", __func__, qport);
return;
}
- port = ctrl_port[portno];
-
+ port = ctrl_port[qport];
atomic_set(&port->line_state, val);
/* send 0 len pkt to qti to notify state change */
qti_ctrl_queue_notify(port);
}
-int gqti_ctrl_connect(void *gr, u8 port_num, unsigned intf,
- enum transport_type dxport, enum gadget_type gtype)
+int gqti_ctrl_connect(void *gr, enum qti_port_type qport, unsigned intf)
{
struct qti_ctrl_port *port;
struct grmnet *g_rmnet = NULL;
struct gqdss *g_dpl = NULL;
unsigned long flags;
- pr_debug("%s: gtype:%d gadget:%p\n", __func__, gtype, gr);
- if (port_num >= NR_QTI_PORTS) {
- pr_err("%s: Invalid QTI port %d\n", __func__, port_num);
+ pr_debug("%s: port type:%d gadget:%p\n", __func__, qport, gr);
+ if (qport >= QTI_NUM_PORTS) {
+ pr_err("%s: Invalid QTI port %d\n", __func__, qport);
return -ENODEV;
}
- port = ctrl_port[port_num];
+ port = ctrl_port[qport];
if (!port) {
pr_err("%s: gadget port is null\n", __func__);
return -ENODEV;
}
spin_lock_irqsave(&port->lock, flags);
- port->gtype = gtype;
- if (dxport == USB_GADGET_XPORT_BAM_DMUX) {
- /*
- * BAM-DMUX data transport is used for RMNET and DPL
- * on some targets where IPA is not available.
- * Set endpoint type as BAM-DMUX and interface
- * id as channel number. This information is
- * sent to user space via EP_LOOKUP ioctl.
- *
- */
-
- port->ep_type = DATA_EP_TYPE_BAM_DMUX;
- port->intf = (gtype == USB_GADGET_RMNET) ?
- BAM_DMUX_USB_RMNET_0 :
- BAM_DMUX_USB_DPL;
- port->ipa_prod_idx = 0;
- port->ipa_cons_idx = 0;
- } else {
- port->ep_type = DATA_EP_TYPE_HSUSB;
- port->intf = intf;
- }
+ port->port_type = qport;
+ port->ep_type = DATA_EP_TYPE_HSUSB;
+ port->intf = intf;
- if (gr && port->gtype == USB_GADGET_RMNET) {
+ if (gr && port->port_type == QTI_PORT_RMNET) {
port->port_usb = gr;
g_rmnet = (struct grmnet *)gr;
g_rmnet->send_encap_cmd = gqti_ctrl_send_cpkt_tomodem;
g_rmnet->notify_modem = gqti_ctrl_notify_modem;
- } else if (gr && port->gtype == USB_GADGET_DPL) {
+ } else if (gr && port->port_type == QTI_PORT_DPL) {
port->port_usb = gr;
g_dpl = (struct gqdss *)gr;
g_dpl->send_encap_cmd = gqti_ctrl_send_cpkt_tomodem;
@@ -231,7 +237,7 @@ int gqti_ctrl_connect(void *gr, u8 port_num, unsigned intf,
atomic_set(&port->line_state, 1);
} else {
spin_unlock_irqrestore(&port->lock, flags);
- pr_err("%s(): Port is used without gtype.\n", __func__);
+ pr_err("%s(): Port is used without port type.\n", __func__);
return -ENODEV;
}
@@ -251,7 +257,7 @@ int gqti_ctrl_connect(void *gr, u8 port_num, unsigned intf,
return 0;
}
-void gqti_ctrl_disconnect(void *gr, u8 port_num)
+void gqti_ctrl_disconnect(void *gr, enum qti_port_type qport)
{
struct qti_ctrl_port *port;
unsigned long flags;
@@ -261,13 +267,12 @@ void gqti_ctrl_disconnect(void *gr, u8 port_num)
pr_debug("%s: gadget:%p\n", __func__, gr);
- if (port_num >= NR_QTI_PORTS) {
- pr_err("%s: Invalid QTI port %d\n", __func__, port_num);
+ if (qport >= QTI_NUM_PORTS) {
+ pr_err("%s: Invalid QTI port %d\n", __func__, qport);
return;
}
- port = ctrl_port[port_num];
-
+ port = ctrl_port[qport];
if (!port) {
pr_err("%s: gadget port is null\n", __func__);
return;
@@ -282,17 +287,17 @@ void gqti_ctrl_disconnect(void *gr, u8 port_num)
port->ipa_cons_idx = -1;
port->port_usb = NULL;
- if (gr && port->gtype == USB_GADGET_RMNET) {
+ if (gr && port->port_type == QTI_PORT_RMNET) {
g_rmnet = (struct grmnet *)gr;
g_rmnet->send_encap_cmd = NULL;
g_rmnet->notify_modem = NULL;
- } else if (gr && port->gtype == USB_GADGET_DPL) {
+ } else if (gr && port->port_type == QTI_PORT_DPL) {
g_dpl = (struct gqdss *)gr;
g_dpl->send_encap_cmd = NULL;
g_dpl->notify_modem = NULL;
} else {
pr_err("%s(): unrecognized gadget type(%d).\n",
- __func__, port->gtype);
+ __func__, port->port_type);
}
while (!list_empty(&port->cpkt_req_q)) {
@@ -309,18 +314,17 @@ void gqti_ctrl_disconnect(void *gr, u8 port_num)
qti_ctrl_queue_notify(port);
}
-void gqti_ctrl_update_ipa_pipes(void *gr, u8 port_num, u32 ipa_prod,
- u32 ipa_cons)
+void gqti_ctrl_update_ipa_pipes(void *gr, enum qti_port_type qport,
+ u32 ipa_prod, u32 ipa_cons)
{
struct qti_ctrl_port *port;
- if (port_num >= NR_QTI_PORTS) {
- pr_err("%s: Invalid QTI port %d\n", __func__, port_num);
+ if (qport >= QTI_NUM_PORTS) {
+ pr_err("%s: Invalid QTI port %d\n", __func__, qport);
return;
}
- port = ctrl_port[port_num];
-
+ port = ctrl_port[qport];
port->ipa_prod_idx = ipa_prod;
port->ipa_cons_idx = ipa_cons;
@@ -492,12 +496,12 @@ qti_ctrl_write(struct file *fp, const char __user *buf, size_t count,
spin_lock_irqsave(&port->lock, flags);
if (port && port->port_usb) {
- if (port->gtype == USB_GADGET_RMNET) {
+ if (port->port_type == QTI_PORT_RMNET) {
g_rmnet = (struct grmnet *)port->port_usb;
} else {
spin_unlock_irqrestore(&port->lock, flags);
pr_err("%s(): unrecognized gadget type(%d).\n",
- __func__, port->gtype);
+ __func__, port->port_type);
return -EINVAL;
}
@@ -530,15 +534,15 @@ static long qti_ctrl_ioctl(struct file *fp, unsigned cmd, unsigned long arg)
struct ep_info info;
int val, ret = 0;
- pr_debug("%s: Received command %d for gtype:%d\n",
- __func__, cmd, port->gtype);
+ pr_debug("%s: Received command %d for port type:%d\n",
+ __func__, cmd, port->port_type);
if (qti_ctrl_lock(&port->ioctl_excl))
return -EBUSY;
switch (cmd) {
case QTI_CTRL_MODEM_OFFLINE:
- if (port && (port->gtype == USB_GADGET_DPL)) {
+ if (port && (port->port_type == QTI_PORT_DPL)) {
pr_err("%s(): Modem Offline not handled\n", __func__);
goto exit_ioctl;
}
@@ -550,7 +554,7 @@ static long qti_ctrl_ioctl(struct file *fp, unsigned cmd, unsigned long arg)
gr->disconnect(gr);
break;
case QTI_CTRL_MODEM_ONLINE:
- if (port && (port->gtype == USB_GADGET_DPL)) {
+ if (port && (port->port_type == QTI_PORT_DPL)) {
pr_err("%s(): Modem Online not handled\n", __func__);
goto exit_ioctl;
}
@@ -568,13 +572,13 @@ static long qti_ctrl_ioctl(struct file *fp, unsigned cmd, unsigned long arg)
pr_err("copying to user space failed");
ret = -EFAULT;
}
- pr_debug("%s: Sent line_state: %d for gtype:%d\n", __func__,
- atomic_read(&port->line_state), port->gtype);
+ pr_debug("%s: Sent line_state: %d for port type:%d\n", __func__,
+ atomic_read(&port->line_state), port->port_type);
break;
case QTI_CTRL_EP_LOOKUP:
- pr_debug("%s(): EP_LOOKUP for gtype:%d\n", __func__,
- port->gtype);
+ pr_debug("%s(): EP_LOOKUP for port type:%d\n", __func__,
+ port->port_type);
val = atomic_read(&port->connected);
if (!val) {
pr_err_ratelimited("EP_LOOKUP failed: not connected\n");
@@ -593,9 +597,9 @@ static long qti_ctrl_ioctl(struct file *fp, unsigned cmd, unsigned long arg)
info.ipa_ep_pair.cons_pipe_num = port->ipa_cons_idx;
info.ipa_ep_pair.prod_pipe_num = port->ipa_prod_idx;
- pr_debug("%s(): gtype:%d ep_type:%d intf:%d\n",
- __func__, port->gtype, info.ph_ep_info.ep_type,
- info.ph_ep_info.peripheral_iface_id);
+ pr_debug("%s(): port type:%d ep_type:%d intf:%d\n",
+ __func__, port->port_type, info.ph_ep_info.ep_type,
+ info.ph_ep_info.peripheral_iface_id);
pr_debug("%s(): ipa_cons_idx:%d ipa_prod_idx:%d\n",
__func__, info.ipa_ep_pair.cons_pipe_num,
@@ -650,7 +654,7 @@ static int qti_ctrl_read_stats(struct seq_file *s, void *unused)
unsigned long flags;
int i;
- for (i = 0; i < NR_QTI_PORTS; i++) {
+ for (i = 0; i < QTI_NUM_PORTS; i++) {
port = ctrl_port[i];
if (!port)
continue;
@@ -687,7 +691,7 @@ static ssize_t qti_ctrl_reset_stats(struct file *file,
int i;
unsigned long flags;
- for (i = 0; i < NR_QTI_PORTS; i++) {
+ for (i = 0; i < QTI_NUM_PORTS; i++) {
port = ctrl_port[i];
if (!port)
continue;
@@ -762,10 +766,9 @@ int gqti_ctrl_init(void)
int ret, i, sz = QTI_CTRL_NAME_LEN;
struct qti_ctrl_port *port = NULL;
- for (i = 0; i < NR_QTI_PORTS; i++) {
+ for (i = 0; i < QTI_NUM_PORTS; i++) {
port = kzalloc(sizeof(struct qti_ctrl_port), GFP_KERNEL);
if (!port) {
- pr_err("Failed to allocate rmnet control device\n");
ret = -ENOMEM;
goto fail_init;
}
@@ -787,16 +790,16 @@ int gqti_ctrl_init(void)
port->ipa_prod_idx = -1;
port->ipa_cons_idx = -1;
- if (i == 0)
+ if (i == QTI_PORT_RMNET)
strlcat(port->name, RMNET_CTRL_QTI_NAME, sz);
- else if (i == DPL_QTI_CTRL_PORT_NO)
+ else if (i == QTI_PORT_DPL)
strlcat(port->name, DPL_CTRL_QTI_NAME, sz);
else
snprintf(port->name, sz, "%s%d",
- RMNET_CTRL_QTI_NAME, i);
+ RMNET_CTRL_QTI_NAME, i);
port->ctrl_device.name = port->name;
- if (i == DPL_QTI_CTRL_PORT_NO)
+ if (i == QTI_PORT_DPL)
port->ctrl_device.fops = &dpl_qti_ctrl_fops;
else
port->ctrl_device.fops = &qti_ctrl_fops;
@@ -809,7 +812,6 @@ int gqti_ctrl_init(void)
}
}
qti_ctrl_debugfs_init();
-
return ret;
fail_init:
@@ -825,7 +827,7 @@ void gqti_ctrl_cleanup(void)
{
int i;
- for (i = 0; i < NR_QTI_PORTS; i++) {
+ for (i = 0; i < QTI_NUM_PORTS; i++) {
misc_deregister(&ctrl_port[i]->ctrl_device);
kfree(ctrl_port[i]);
ctrl_port[i] = NULL;
diff --git a/drivers/usb/gadget/function/u_data_ipa.c b/drivers/usb/gadget/function/u_data_ipa.c
index 56e7dea427ec..2da0c59fdfc2 100644
--- a/drivers/usb/gadget/function/u_data_ipa.c
+++ b/drivers/usb/gadget/function/u_data_ipa.c
@@ -23,6 +23,7 @@
#include <linux/usb_bam.h>
#include "u_data_ipa.h"
+#include "u_rmnet.h"
struct ipa_data_ch_info {
struct usb_request *rx_req;
@@ -564,6 +565,11 @@ static void ipa_data_connect_work(struct work_struct *w)
atomic_set(&port->pipe_connect_notified, 1);
}
+ if (port->func_type == USB_IPA_FUNC_RMNET) {
+ gqti_ctrl_update_ipa_pipes(port->port_usb, QTI_PORT_RMNET,
+ gport->ipa_producer_ep, gport->ipa_consumer_ep);
+ }
+
pr_debug("ipa_producer_ep:%d ipa_consumer_ep:%d\n",
gport->ipa_producer_ep,
gport->ipa_consumer_ep);
@@ -1135,7 +1141,7 @@ int ipa_data_setup(enum ipa_func_type func)
}
if (ipa_data_wq) {
pr_debug("ipa_data_wq is already setup.");
- goto free_rndis_data;
+ return 0;
}
ipa_data_wq = alloc_workqueue("k_usb_ipa_data",
diff --git a/drivers/usb/gadget/function/u_data_ipa.h b/drivers/usb/gadget/function/u_data_ipa.h
index a1c1055bd8ef..14411575af22 100644
--- a/drivers/usb/gadget/function/u_data_ipa.h
+++ b/drivers/usb/gadget/function/u_data_ipa.h
@@ -20,6 +20,8 @@
#include <linux/ipa_usb.h>
#include <linux/usb_bam.h>
+#include "u_rmnet.h"
+
enum ipa_func_type {
USB_IPA_FUNC_ECM,
USB_IPA_FUNC_MBIM,
@@ -57,6 +59,12 @@ struct f_rndis_qc_opts {
int refcnt;
};
+struct f_rmnet_opts {
+ struct usb_function_instance func_inst;
+ struct f_rmnet *dev;
+ int refcnt;
+};
+
void ipa_data_port_select(enum ipa_func_type func);
void ipa_data_disconnect(struct gadget_ipa_port *gp, enum ipa_func_type func);
int ipa_data_connect(struct gadget_ipa_port *gp, enum ipa_func_type func,
@@ -87,4 +95,6 @@ void *rndis_qc_get_ipa_rx_cb(void);
bool rndis_qc_get_skip_ep_config(void);
void *rndis_qc_get_ipa_tx_cb(void);
void rndis_ipa_reset_trigger(void);
+void gqti_ctrl_update_ipa_pipes(void *gr, enum qti_port_type qport,
+ u32 ipa_prod, u32 ipa_cons);
#endif
diff --git a/drivers/usb/gadget/function/u_rmnet.h b/drivers/usb/gadget/function/u_rmnet.h
index 4336dbf26274..e0843794b594 100644
--- a/drivers/usb/gadget/function/u_rmnet.h
+++ b/drivers/usb/gadget/function/u_rmnet.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011-2015, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2011-2016, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -19,18 +19,19 @@
#include <linux/workqueue.h>
struct rmnet_ctrl_pkt {
- void *buf;
- int len;
+ void *buf;
+ int len;
struct list_head list;
};
-struct grmnet {
- struct usb_function func;
+enum qti_port_type {
+ QTI_PORT_RMNET,
+ QTI_PORT_DPL,
+ QTI_NUM_PORTS
+};
- struct usb_gadget *gadget;
- struct usb_ep *in;
- struct usb_ep *out;
+struct grmnet {
/* to usb host, aka laptop, windows pc etc. Will
* be filled by usb driver of rmnet functionality
*/
@@ -39,18 +40,13 @@ struct grmnet {
/* to modem, and to be filled by driver implementing
* control function
*/
- int (*send_encap_cmd)(u8 port_num, void *buf, size_t len);
-
- void (*notify_modem)(void *g, u8 port_num, int cbits);
+ int (*send_encap_cmd)(enum qti_port_type qport, void *buf, size_t len);
+ void (*notify_modem)(void *g, enum qti_port_type qport, int cbits);
void (*disconnect)(struct grmnet *g);
void (*connect)(struct grmnet *g);
};
-#define NR_QTI_PORTS (NR_RMNET_PORTS + NR_DPL_PORTS)
-#define NR_RMNET_PORTS 4
-#define NR_DPL_PORTS 1
-
enum ctrl_client {
FRMNET_CTRL_CLIENT,
GPS_CTRL_CLIENT,
@@ -58,22 +54,8 @@ enum ctrl_client {
NR_CTRL_CLIENTS
};
-int gbam_setup(unsigned int no_bam_port);
-int gbam2bam_setup(unsigned int no_bam2bam_port);
-void gbam_cleanup(void);
-int gbam_connect(struct grmnet *gr, u8 port_num,
- enum transport_type trans, u8 src_connection_idx,
- u8 dst_connection_idx);
-void gbam_disconnect(struct grmnet *gr, u8 port_num,
- enum transport_type trans);
-void gbam_suspend(struct grmnet *gr, u8 port_num, enum transport_type trans);
-void gbam_resume(struct grmnet *gr, u8 port_num, enum transport_type trans);
-int gbam_mbim_setup(void);
-int gbam_mbim_connect(struct usb_gadget *g, struct usb_ep *in,
- struct usb_ep *out);
-void gbam_mbim_disconnect(void);
-int gsmd_ctrl_connect(struct grmnet *gr, int port_num);
-void gsmd_ctrl_disconnect(struct grmnet *gr, u8 port_num);
-int gsmd_ctrl_setup(enum ctrl_client client_num, unsigned int count,
- u8 *first_port_idx);
+int gqti_ctrl_connect(void *gr, enum qti_port_type qport, unsigned intf);
+void gqti_ctrl_disconnect(void *gr, enum qti_port_type qport);
+int gqti_ctrl_init(void);
+void gqti_ctrl_cleanup(void);
#endif /* __U_RMNET_H*/
diff --git a/drivers/usb/pd/Kconfig b/drivers/usb/pd/Kconfig
index dd2813000dec..cc88df495f6e 100644
--- a/drivers/usb/pd/Kconfig
+++ b/drivers/usb/pd/Kconfig
@@ -9,6 +9,7 @@ config USB_PD
config USB_PD_POLICY
tristate "USB Power Delivery Protocol and Policy Engine"
depends on EXTCON
+ depends on DUAL_ROLE_USB_INTF
select USB_PD
help
Say Y here to enable USB PD protocol and policy engine.
diff --git a/drivers/usb/pd/policy_engine.c b/drivers/usb/pd/policy_engine.c
index aa2e1d9f3c70..2fbe4c8faa79 100644
--- a/drivers/usb/pd/policy_engine.c
+++ b/drivers/usb/pd/policy_engine.c
@@ -10,6 +10,7 @@
* GNU General Public License for more details.
*/
+#include <linux/completion.h>
#include <linux/delay.h>
#include <linux/hrtimer.h>
#include <linux/ipc_logging.h>
@@ -24,6 +25,7 @@
#include <linux/spinlock.h>
#include <linux/workqueue.h>
#include <linux/extcon.h>
+#include <linux/usb/class-dual-role.h>
#include <linux/usb/usbpd.h>
#include "usbpd.h"
@@ -163,11 +165,11 @@ static void *usbpd_ipc_log;
/* Timeouts (in ms) */
#define ERROR_RECOVERY_TIME 25
#define SENDER_RESPONSE_TIME 26
-#define SINK_WAIT_CAP_TIME 620
+#define SINK_WAIT_CAP_TIME 500
#define PS_TRANSITION_TIME 450
#define SRC_CAP_TIME 120
#define SRC_TRANSITION_TIME 25
-#define SRC_RECOVER_TIME 660
+#define SRC_RECOVER_TIME 750
#define PS_HARD_RESET_TIME 25
#define PS_SOURCE_ON 400
#define PS_SOURCE_OFF 750
@@ -175,8 +177,11 @@ static void *usbpd_ipc_log;
#define VDM_BUSY_TIME 50
#define VCONN_ON_TIME 100
-/* tPSHardReset + tSafe0V + tSrcRecover + tSrcTurnOn */
-#define SNK_HARD_RESET_RECOVER_TIME (35 + 650 + 1000 + 275)
+/* tPSHardReset + tSafe0V */
+#define SNK_HARD_RESET_VBUS_OFF_TIME (35 + 650)
+
+/* tSrcRecover + tSrcTurnOn */
+#define SNK_HARD_RESET_VBUS_ON_TIME (1000 + 275)
#define PD_CAPS_COUNT 50
@@ -308,15 +313,23 @@ struct usbpd {
enum power_supply_typec_mode typec_mode;
enum power_supply_type psy_type;
+ enum power_supply_typec_power_role forced_pr;
bool vbus_present;
enum data_role current_dr;
enum power_role current_pr;
bool in_pr_swap;
bool pd_phy_opened;
+ struct completion swap_complete;
+
+ struct dual_role_phy_instance *dual_role;
+ struct dual_role_phy_desc dr_desc;
+ bool send_pr_swap;
+ bool send_dr_swap;
struct regulator *vbus;
struct regulator *vconn;
+ bool vbus_enabled;
bool vconn_enabled;
bool vconn_is_external;
@@ -409,6 +422,17 @@ static struct usbpd_svid_handler *find_svid_handler(struct usbpd *pd, u16 svid)
return NULL;
}
+/* Reset protocol layer */
+static inline void pd_reset_protocol(struct usbpd *pd)
+{
+ /*
+ * first Rx ID should be 0; set this to a sentinel of -1 so that in
+ * phy_msg_received() we can check if we had seen it before.
+ */
+ pd->rx_msgid = -1;
+ pd->tx_msgid = 0;
+}
+
static int pd_send_msg(struct usbpd *pd, u8 hdr_type, const u32 *data,
size_t num_data, enum pd_msg_type type)
{
@@ -423,7 +447,9 @@ static int pd_send_msg(struct usbpd *pd, u8 hdr_type, const u32 *data,
/* MessageID incremented regardless of Tx error */
pd->tx_msgid = (pd->tx_msgid + 1) & PD_MAX_MSG_ID;
- if (ret != num_data * sizeof(u32))
+ if (ret < 0)
+ return ret;
+ else if (ret != num_data * sizeof(u32))
return -EIO;
return 0;
}
@@ -631,6 +657,7 @@ static void usbpd_set_state(struct usbpd *pd, enum usbpd_state next_state)
switch (next_state) {
case PE_ERROR_RECOVERY: /* perform hard disconnect/reconnect */
pd->in_pr_swap = false;
+ pd->current_pr = PR_NONE;
set_power_role(pd, PR_NONE);
pd->typec_mode = POWER_SUPPLY_TYPEC_NONE;
kick_sm(pd, 0);
@@ -646,12 +673,14 @@ static void usbpd_set_state(struct usbpd *pd, enum usbpd_state next_state)
*/
}
+ dual_role_instance_changed(pd->dual_role);
+
/* Set CC back to DRP toggle for the next disconnect */
val.intval = POWER_SUPPLY_TYPEC_PR_DUAL;
power_supply_set_property(pd->usb_psy,
POWER_SUPPLY_PROP_TYPEC_POWER_ROLE, &val);
- pd->rx_msgid = -1;
+ pd_reset_protocol(pd);
if (!pd->in_pr_swap) {
if (pd->pd_phy_opened) {
@@ -677,6 +706,7 @@ static void usbpd_set_state(struct usbpd *pd, enum usbpd_state next_state)
pd->current_state = PE_SRC_SEND_CAPABILITIES;
if (pd->in_pr_swap) {
kick_sm(pd, SWAP_SOURCE_START_TIME);
+ pd->in_pr_swap = false;
break;
}
@@ -758,6 +788,8 @@ static void usbpd_set_state(struct usbpd *pd, enum usbpd_state next_state)
}
kobject_uevent(&pd->dev.kobj, KOBJ_CHANGE);
+ complete(&pd->swap_complete);
+ dual_role_instance_changed(pd->dual_role);
break;
case PE_SRC_HARD_RESET:
@@ -768,9 +800,7 @@ static void usbpd_set_state(struct usbpd *pd, enum usbpd_state next_state)
case PE_SRC_SEND_SOFT_RESET:
case PE_SNK_SEND_SOFT_RESET:
- /* Reset protocol layer */
- pd->tx_msgid = 0;
- pd->rx_msgid = -1;
+ pd_reset_protocol(pd);
ret = pd_send_msg(pd, MSG_SOFT_RESET, NULL, 0, SOP_MSG);
if (ret) {
@@ -801,6 +831,8 @@ static void usbpd_set_state(struct usbpd *pd, enum usbpd_state next_state)
}
}
+ dual_role_instance_changed(pd->dual_role);
+
ret = power_supply_get_property(pd->usb_psy,
POWER_SUPPLY_PROP_PD_ALLOWED, &val);
if (ret) {
@@ -812,9 +844,7 @@ static void usbpd_set_state(struct usbpd *pd, enum usbpd_state next_state)
if (!val.intval)
break;
- /* Reset protocol layer */
- pd->tx_msgid = 0;
- pd->rx_msgid = -1;
+ pd_reset_protocol(pd);
if (!pd->in_pr_swap) {
if (pd->pd_phy_opened) {
@@ -837,7 +867,17 @@ static void usbpd_set_state(struct usbpd *pd, enum usbpd_state next_state)
pd->pd_phy_opened = true;
}
- pd->current_voltage = 5000000;
+ pd->current_voltage = pd->requested_voltage = 5000000;
+ val.intval = pd->requested_voltage; /* set max range to 5V */
+ power_supply_set_property(pd->usb_psy,
+ POWER_SUPPLY_PROP_VOLTAGE_MAX, &val);
+
+ if (!pd->vbus_present) {
+ pd->current_state = PE_SNK_DISCOVERY;
+ /* max time for hard reset to turn vbus back on */
+ kick_sm(pd, SNK_HARD_RESET_VBUS_ON_TIME);
+ break;
+ }
pd->current_state = PE_SNK_WAIT_FOR_CAPABILITIES;
/* fall-through */
@@ -882,6 +922,8 @@ static void usbpd_set_state(struct usbpd *pd, enum usbpd_state next_state)
case PE_SNK_READY:
pd->in_explicit_contract = true;
kobject_uevent(&pd->dev.kobj, KOBJ_CHANGE);
+ complete(&pd->swap_complete);
+ dual_role_instance_changed(pd->dual_role);
break;
case PE_SNK_TRANSITION_TO_DEFAULT:
@@ -901,13 +943,8 @@ static void usbpd_set_state(struct usbpd *pd, enum usbpd_state next_state)
pd->vconn_enabled = false;
}
- val.intval = pd->requested_voltage; /* set range back to 5V */
- power_supply_set_property(pd->usb_psy,
- POWER_SUPPLY_PROP_VOLTAGE_MAX, &val);
- pd->current_voltage = pd->requested_voltage;
-
- /* max time for hard reset to toggle vbus off/on */
- kick_sm(pd, SNK_HARD_RESET_RECOVER_TIME);
+ /* max time for hard reset to turn vbus off */
+ kick_sm(pd, SNK_HARD_RESET_VBUS_OFF_TIME);
break;
case PE_PRS_SNK_SRC_TRANSITION_TO_OFF:
@@ -996,7 +1033,7 @@ int usbpd_send_vdm(struct usbpd *pd, u32 vdm_hdr, const u32 *vdos, int num_vdos)
pd->vdm_tx = vdm_tx;
/* slight delay before queuing to prioritize handling of incoming VDM */
- kick_sm(pd, 5);
+ kick_sm(pd, 2);
return 0;
}
@@ -1214,21 +1251,32 @@ static void handle_vdm_rx(struct usbpd *pd, struct rx_msg *rx_msg)
static void handle_vdm_tx(struct usbpd *pd)
{
int ret;
+ unsigned long flags;
/* only send one VDM at a time */
if (pd->vdm_tx) {
u32 vdm_hdr = pd->vdm_tx->data[0];
+ /* bail out and try again later if a message just arrived */
+ spin_lock_irqsave(&pd->rx_lock, flags);
+ if (!list_empty(&pd->rx_q)) {
+ spin_unlock_irqrestore(&pd->rx_lock, flags);
+ return;
+ }
+ spin_unlock_irqrestore(&pd->rx_lock, flags);
+
ret = pd_send_msg(pd, MSG_VDM, pd->vdm_tx->data,
pd->vdm_tx->size, SOP_MSG);
if (ret) {
- usbpd_err(&pd->dev, "Error sending VDM command %d\n",
- SVDM_HDR_CMD(pd->vdm_tx->data[0]));
- usbpd_set_state(pd, pd->current_pr == PR_SRC ?
+ usbpd_err(&pd->dev, "Error (%d) sending VDM command %d\n",
+ ret, SVDM_HDR_CMD(pd->vdm_tx->data[0]));
+
+ /* retry when hitting PE_SRC/SNK_Ready again */
+ if (ret != -EBUSY)
+ usbpd_set_state(pd, pd->current_pr == PR_SRC ?
PE_SRC_SEND_SOFT_RESET :
PE_SNK_SEND_SOFT_RESET);
- /* retry when hitting PE_SRC/SNK_Ready again */
return;
}
@@ -1240,7 +1288,7 @@ static void handle_vdm_tx(struct usbpd *pd)
SVDM_HDR_CMD_TYPE(vdm_hdr) == SVDM_CMD_TYPE_INITIATOR &&
SVDM_HDR_CMD(vdm_hdr) <= USBPD_SVDM_DISCOVER_SVIDS) {
if (pd->vdm_tx_retry) {
- usbpd_err(&pd->dev, "Previous Discover VDM command %d not ACKed/NAKed\n",
+ usbpd_dbg(&pd->dev, "Previous Discover VDM command %d not ACKed/NAKed\n",
SVDM_HDR_CMD(
pd->vdm_tx_retry->data[0]));
kfree(pd->vdm_tx_retry);
@@ -1319,6 +1367,13 @@ static void vconn_swap(struct usbpd *pd)
pd->vconn_enabled = true;
+ /*
+ * Small delay to ensure Vconn has ramped up. This is well
+ * below tVCONNSourceOn (100ms) so we still send PS_RDY within
+ * the allowed time.
+ */
+ usleep_range(5000, 10000);
+
ret = pd_send_msg(pd, MSG_PS_RDY, NULL, 0, SOP_MSG);
if (ret) {
usbpd_err(&pd->dev, "Error sending PS_RDY\n");
@@ -1366,7 +1421,7 @@ static void usbpd_sm(struct work_struct *w)
spin_unlock_irqrestore(&pd->rx_lock, flags);
/* Disconnect? */
- if (pd->typec_mode == POWER_SUPPLY_TYPEC_NONE && !pd->in_pr_swap) {
+ if (pd->current_pr == PR_NONE) {
if (pd->current_state == PE_UNKNOWN)
goto sm_done;
@@ -1400,8 +1455,10 @@ static void usbpd_sm(struct work_struct *w)
power_supply_set_property(pd->usb_psy,
POWER_SUPPLY_PROP_PD_ACTIVE, &val);
- if (pd->current_pr == PR_SRC)
+ if (pd->vbus_enabled) {
regulator_disable(pd->vbus);
+ pd->vbus_enabled = false;
+ }
if (pd->vconn_enabled) {
regulator_disable(pd->vconn);
@@ -1423,13 +1480,22 @@ static void usbpd_sm(struct work_struct *w)
usleep_range(ERROR_RECOVERY_TIME * USEC_PER_MSEC,
(ERROR_RECOVERY_TIME + 5) * USEC_PER_MSEC);
- /* Set CC back to DRP toggle */
- val.intval = POWER_SUPPLY_TYPEC_PR_DUAL;
+ /* set due to dual_role class "mode" change */
+ if (pd->forced_pr != POWER_SUPPLY_TYPEC_PR_NONE)
+ val.intval = pd->forced_pr;
+ else
+ /* Set CC back to DRP toggle */
+ val.intval = POWER_SUPPLY_TYPEC_PR_DUAL;
+
power_supply_set_property(pd->usb_psy,
POWER_SUPPLY_PROP_TYPEC_POWER_ROLE, &val);
+ pd->forced_pr = POWER_SUPPLY_TYPEC_PR_NONE;
pd->current_state = PE_UNKNOWN;
+ kobject_uevent(&pd->dev.kobj, KOBJ_CHANGE);
+ dual_role_instance_changed(pd->dual_role);
+
goto sm_done;
}
@@ -1473,6 +1539,8 @@ static void usbpd_sm(struct work_struct *w)
ret = regulator_enable(pd->vbus);
if (ret)
usbpd_err(&pd->dev, "Unable to enable vbus\n");
+ else
+ pd->vbus_enabled = true;
if (!pd->vconn_enabled &&
pd->typec_mode ==
@@ -1521,10 +1589,6 @@ static void usbpd_sm(struct work_struct *w)
break;
}
- val.intval = 1;
- power_supply_set_property(pd->usb_psy,
- POWER_SUPPLY_PROP_PD_ACTIVE, &val);
-
/* transmit was successful if GoodCRC was received */
pd->caps_count = 0;
pd->hard_reset_count = 0;
@@ -1533,6 +1597,10 @@ static void usbpd_sm(struct work_struct *w)
/* wait for REQUEST */
pd->current_state = PE_SRC_SEND_CAPABILITIES_WAIT;
kick_sm(pd, SENDER_RESPONSE_TIME);
+
+ val.intval = 1;
+ power_supply_set_property(pd->usb_psy,
+ POWER_SUPPLY_PROP_PD_ACTIVE, &val);
break;
case PE_SRC_SEND_CAPABILITIES_WAIT:
@@ -1582,7 +1650,6 @@ static void usbpd_sm(struct work_struct *w)
}
dr_swap(pd);
- kobject_uevent(&pd->dev.kobj, KOBJ_CHANGE);
} else if (IS_CTRL(rx_msg, MSG_PR_SWAP)) {
/* lock in current mode */
set_power_role(pd, pd->current_pr);
@@ -1607,18 +1674,40 @@ static void usbpd_sm(struct work_struct *w)
}
vconn_swap(pd);
+ } else if (IS_DATA(rx_msg, MSG_VDM)) {
+ handle_vdm_rx(pd, rx_msg);
+ } else if (pd->send_pr_swap) {
+ pd->send_pr_swap = false;
+ ret = pd_send_msg(pd, MSG_PR_SWAP, NULL, 0, SOP_MSG);
+ if (ret) {
+ dev_err(&pd->dev, "Error sending PR Swap\n");
+ usbpd_set_state(pd, PE_SRC_SEND_SOFT_RESET);
+ break;
+ }
+
+ pd->current_state = PE_PRS_SRC_SNK_SEND_SWAP;
+ kick_sm(pd, SENDER_RESPONSE_TIME);
+ } else if (pd->send_dr_swap) {
+ pd->send_dr_swap = false;
+ ret = pd_send_msg(pd, MSG_DR_SWAP, NULL, 0, SOP_MSG);
+ if (ret) {
+ dev_err(&pd->dev, "Error sending DR Swap\n");
+ usbpd_set_state(pd, PE_SRC_SEND_SOFT_RESET);
+ break;
+ }
+
+ pd->current_state = PE_DRS_SEND_DR_SWAP;
+ kick_sm(pd, SENDER_RESPONSE_TIME);
} else {
- if (IS_DATA(rx_msg, MSG_VDM))
- handle_vdm_rx(pd, rx_msg);
- else
- handle_vdm_tx(pd);
+ handle_vdm_tx(pd);
}
break;
case PE_SRC_TRANSITION_TO_DEFAULT:
if (pd->vconn_enabled)
regulator_disable(pd->vconn);
- regulator_disable(pd->vbus);
+ if (pd->vbus_enabled)
+ regulator_disable(pd->vbus);
if (pd->current_dr != DR_DFP) {
extcon_set_cable_state_(pd->extcon, EXTCON_USB, 0);
@@ -1628,9 +1717,12 @@ static void usbpd_sm(struct work_struct *w)
msleep(SRC_RECOVER_TIME);
+ pd->vbus_enabled = false;
ret = regulator_enable(pd->vbus);
if (ret)
usbpd_err(&pd->dev, "Unable to enable vbus\n");
+ else
+ pd->vbus_enabled = true;
if (pd->vconn_enabled) {
ret = regulator_enable(pd->vconn);
@@ -1665,23 +1757,48 @@ static void usbpd_sm(struct work_struct *w)
usbpd_set_state(pd, PE_SNK_STARTUP);
break;
+ case PE_SNK_DISCOVERY:
+ if (!rx_msg) {
+ if (pd->vbus_present)
+ usbpd_set_state(pd,
+ PE_SNK_WAIT_FOR_CAPABILITIES);
+
+ /*
+ * Handle disconnection in the middle of PR_Swap.
+ * Since in psy_changed() if pd->in_pr_swap is true
+ * we ignore the typec_mode==NONE change since that is
+ * expected to happen. However if the cable really did
+ * get disconnected we need to check for it here after
+ * waiting for VBUS presence times out.
+ */
+ if (!pd->typec_mode) {
+ pd->current_pr = PR_NONE;
+ kick_sm(pd, 0);
+ }
+
+ break;
+ }
+ /* else fall-through */
+
case PE_SNK_WAIT_FOR_CAPABILITIES:
+ pd->in_pr_swap = false;
+
if (IS_DATA(rx_msg, MSG_SOURCE_CAPABILITIES)) {
val.intval = 0;
power_supply_set_property(pd->usb_psy,
POWER_SUPPLY_PROP_PD_IN_HARD_RESET,
&val);
- val.intval = 1;
- power_supply_set_property(pd->usb_psy,
- POWER_SUPPLY_PROP_PD_ACTIVE, &val);
-
/* save the PDOs so userspace can further evaluate */
memcpy(&pd->received_pdos, rx_msg->payload,
sizeof(pd->received_pdos));
pd->src_cap_id++;
usbpd_set_state(pd, PE_SNK_EVALUATE_CAPABILITY);
+
+ val.intval = 1;
+ power_supply_set_property(pd->usb_psy,
+ POWER_SUPPLY_PROP_PD_ACTIVE, &val);
} else if (pd->hard_reset_count < 3) {
usbpd_set_state(pd, PE_SNK_HARD_RESET);
} else if (pd->pd_connected) {
@@ -1821,7 +1938,6 @@ static void usbpd_sm(struct work_struct *w)
}
dr_swap(pd);
- kobject_uevent(&pd->dev.kobj, KOBJ_CHANGE);
} else if (IS_CTRL(rx_msg, MSG_PR_SWAP)) {
/* lock in current mode */
set_power_role(pd, pd->current_pr);
@@ -1863,37 +1979,42 @@ static void usbpd_sm(struct work_struct *w)
}
vconn_swap(pd);
+ } else if (IS_DATA(rx_msg, MSG_VDM)) {
+ handle_vdm_rx(pd, rx_msg);
+ } else if (pd->send_pr_swap) {
+ pd->send_pr_swap = false;
+ ret = pd_send_msg(pd, MSG_PR_SWAP, NULL, 0, SOP_MSG);
+ if (ret) {
+ dev_err(&pd->dev, "Error sending PR Swap\n");
+ usbpd_set_state(pd, PE_SNK_SEND_SOFT_RESET);
+ break;
+ }
+
+ pd->current_state = PE_PRS_SNK_SRC_SEND_SWAP;
+ kick_sm(pd, SENDER_RESPONSE_TIME);
+ } else if (pd->send_dr_swap) {
+ pd->send_dr_swap = false;
+ ret = pd_send_msg(pd, MSG_DR_SWAP, NULL, 0, SOP_MSG);
+ if (ret) {
+ dev_err(&pd->dev, "Error sending DR Swap\n");
+ usbpd_set_state(pd, PE_SNK_SEND_SOFT_RESET);
+ break;
+ }
+
+ pd->current_state = PE_DRS_SEND_DR_SWAP;
+ kick_sm(pd, SENDER_RESPONSE_TIME);
} else {
- if (IS_DATA(rx_msg, MSG_VDM))
- handle_vdm_rx(pd, rx_msg);
- else
- handle_vdm_tx(pd);
+ handle_vdm_tx(pd);
}
break;
case PE_SNK_TRANSITION_TO_DEFAULT:
- val.intval = 0;
- power_supply_set_property(pd->usb_psy,
- POWER_SUPPLY_PROP_PD_IN_HARD_RESET, &val);
-
- if (pd->vbus_present) {
- usbpd_set_state(pd, PE_SNK_STARTUP);
- } else {
- /* Hard reset and VBUS didn't come back? */
- power_supply_get_property(pd->usb_psy,
- POWER_SUPPLY_PROP_TYPEC_MODE, &val);
- if (val.intval == POWER_SUPPLY_TYPEC_NONE) {
- pd->typec_mode = POWER_SUPPLY_TYPEC_NONE;
- kick_sm(pd, 0);
- }
- }
+ usbpd_set_state(pd, PE_SNK_STARTUP);
break;
case PE_SRC_SOFT_RESET:
case PE_SNK_SOFT_RESET:
- /* Reset protocol layer */
- pd->tx_msgid = 0;
- pd->rx_msgid = -1;
+ pd_reset_protocol(pd);
ret = pd_send_msg(pd, MSG_ACCEPT, NULL, 0, SOP_MSG);
if (ret) {
@@ -1969,7 +2090,10 @@ static void usbpd_sm(struct work_struct *w)
pd->in_pr_swap = true;
pd->in_explicit_contract = false;
- regulator_disable(pd->vbus);
+ if (pd->vbus_enabled) {
+ regulator_disable(pd->vbus);
+ pd->vbus_enabled = false;
+ }
/* PE_PRS_SRC_SNK_Assert_Rd */
pd->current_pr = PR_SINK;
@@ -2024,6 +2148,8 @@ static void usbpd_sm(struct work_struct *w)
ret = regulator_enable(pd->vbus);
if (ret)
usbpd_err(&pd->dev, "Unable to enable vbus\n");
+ else
+ pd->vbus_enabled = true;
msleep(200); /* allow time VBUS ramp-up, must be < tNewSrc */
@@ -2134,6 +2260,21 @@ static int psy_changed(struct notifier_block *nb, unsigned long evt, void *ptr)
pd->psy_type = val.intval;
+ /*
+ * For sink hard reset, state machine needs to know when VBUS changes
+ * - when in PE_SNK_TRANSITION_TO_DEFAULT, notify when VBUS falls
+ * - when in PE_SNK_DISCOVERY, notify when VBUS rises
+ */
+ if (typec_mode && ((!pd->vbus_present &&
+ pd->current_state == PE_SNK_TRANSITION_TO_DEFAULT) ||
+ (pd->vbus_present && pd->current_state == PE_SNK_DISCOVERY))) {
+ usbpd_dbg(&pd->dev, "hard reset: typec mode:%d present:%d\n",
+ typec_mode, pd->vbus_present);
+ pd->typec_mode = typec_mode;
+ kick_sm(pd, 0);
+ return 0;
+ }
+
if (pd->typec_mode == typec_mode)
return 0;
@@ -2151,32 +2292,7 @@ static int psy_changed(struct notifier_block *nb, unsigned long evt, void *ptr)
return 0;
}
- /*
- * Workaround for PMIC HW bug.
- *
- * During hard reset when VBUS goes to 0 the CC logic
- * will report this as a disconnection. In those cases
- * it can be ignored, however the downside is that
- * we can also happen to be in the SNK_Transition_to_default
- * state due to a hard reset attempt even with a non-PD
- * capable source, in which a physical disconnect may get
- * masked. In that case, allow for the common case of
- * disconnecting from an SDP.
- *
- * The less common case is a PD-capable SDP which will
- * result in a hard reset getting treated like a
- * disconnect. We can live with this until the HW bug
- * is fixed: in which disconnection won't be reported
- * on VBUS loss alone unless pullup is also removed
- * from CC.
- */
- if (pd->psy_type != POWER_SUPPLY_TYPE_USB &&
- pd->current_state ==
- PE_SNK_TRANSITION_TO_DEFAULT) {
- usbpd_dbg(&pd->dev, "Ignoring disconnect due to hard reset\n");
- return 0;
- }
-
+ pd->current_pr = PR_NONE;
break;
/* Sink states */
@@ -2185,8 +2301,11 @@ static int psy_changed(struct notifier_block *nb, unsigned long evt, void *ptr)
case POWER_SUPPLY_TYPEC_SOURCE_HIGH:
usbpd_info(&pd->dev, "Type-C Source (%s) connected\n",
src_current(typec_mode));
+
+ if (pd->current_pr == PR_SINK)
+ return 0;
+
pd->current_pr = PR_SINK;
- pd->in_pr_swap = false;
break;
/* Source states */
@@ -2195,8 +2314,11 @@ static int psy_changed(struct notifier_block *nb, unsigned long evt, void *ptr)
usbpd_info(&pd->dev, "Type-C Sink%s connected\n",
typec_mode == POWER_SUPPLY_TYPEC_SINK ?
"" : " (powered)");
+
+ if (pd->current_pr == PR_SRC)
+ return 0;
+
pd->current_pr = PR_SRC;
- pd->in_pr_swap = false;
break;
case POWER_SUPPLY_TYPEC_SINK_DEBUG_ACCESSORY:
@@ -2216,6 +2338,198 @@ static int psy_changed(struct notifier_block *nb, unsigned long evt, void *ptr)
return 0;
}
+static enum dual_role_property usbpd_dr_properties[] = {
+ DUAL_ROLE_PROP_SUPPORTED_MODES,
+ DUAL_ROLE_PROP_MODE,
+ DUAL_ROLE_PROP_PR,
+ DUAL_ROLE_PROP_DR,
+};
+
+static int usbpd_dr_get_property(struct dual_role_phy_instance *dual_role,
+ enum dual_role_property prop, unsigned int *val)
+{
+ struct usbpd *pd = dual_role_get_drvdata(dual_role);
+
+ if (!pd)
+ return -ENODEV;
+
+ switch (prop) {
+ case DUAL_ROLE_PROP_MODE:
+ /* For now associate UFP/DFP with data role only */
+ if (pd->current_dr == DR_UFP)
+ *val = DUAL_ROLE_PROP_MODE_UFP;
+ else if (pd->current_dr == DR_DFP)
+ *val = DUAL_ROLE_PROP_MODE_DFP;
+ else
+ *val = DUAL_ROLE_PROP_MODE_NONE;
+ break;
+ case DUAL_ROLE_PROP_PR:
+ if (pd->current_pr == PR_SRC)
+ *val = DUAL_ROLE_PROP_PR_SRC;
+ else if (pd->current_pr == PR_SINK)
+ *val = DUAL_ROLE_PROP_PR_SNK;
+ else
+ *val = DUAL_ROLE_PROP_PR_NONE;
+ break;
+ case DUAL_ROLE_PROP_DR:
+ if (pd->current_dr == DR_UFP)
+ *val = DUAL_ROLE_PROP_DR_DEVICE;
+ else if (pd->current_dr == DR_DFP)
+ *val = DUAL_ROLE_PROP_DR_HOST;
+ else
+ *val = DUAL_ROLE_PROP_DR_NONE;
+ break;
+ default:
+ usbpd_warn(&pd->dev, "unsupported property %d\n", prop);
+ return -ENODATA;
+ }
+
+ return 0;
+}
+
+static int usbpd_dr_set_property(struct dual_role_phy_instance *dual_role,
+ enum dual_role_property prop, const unsigned int *val)
+{
+ struct usbpd *pd = dual_role_get_drvdata(dual_role);
+ bool do_swap = false;
+
+ if (!pd)
+ return -ENODEV;
+
+ switch (prop) {
+ case DUAL_ROLE_PROP_MODE:
+ usbpd_dbg(&pd->dev, "Setting mode to %d\n", *val);
+
+ /*
+ * Forces disconnect on CC and re-establishes connection.
+ * This does not use PD-based PR/DR swap
+ */
+ if (*val == DUAL_ROLE_PROP_MODE_UFP)
+ pd->forced_pr = POWER_SUPPLY_TYPEC_PR_SINK;
+ else if (*val == DUAL_ROLE_PROP_MODE_DFP)
+ pd->forced_pr = POWER_SUPPLY_TYPEC_PR_SOURCE;
+
+ /* new mode will be applied in disconnect handler */
+ set_power_role(pd, PR_NONE);
+
+ /* wait until it takes effect */
+ while (pd->forced_pr != POWER_SUPPLY_TYPEC_PR_NONE)
+ msleep(20);
+
+ break;
+
+ case DUAL_ROLE_PROP_DR:
+ usbpd_dbg(&pd->dev, "Setting data_role to %d\n", *val);
+
+ if (*val == DUAL_ROLE_PROP_DR_HOST) {
+ if (pd->current_dr == DR_UFP)
+ do_swap = true;
+ } else if (*val == DUAL_ROLE_PROP_DR_DEVICE) {
+ if (pd->current_dr == DR_DFP)
+ do_swap = true;
+ } else {
+ usbpd_warn(&pd->dev, "setting data_role to 'none' unsupported\n");
+ return -ENOTSUPP;
+ }
+
+ if (do_swap) {
+ if (pd->current_state != PE_SRC_READY &&
+ pd->current_state != PE_SNK_READY) {
+ usbpd_err(&pd->dev, "data_role swap not allowed: PD not in Ready state\n");
+ return -EAGAIN;
+ }
+
+ reinit_completion(&pd->swap_complete);
+ pd->send_dr_swap = true;
+ kick_sm(pd, 0);
+
+ /* wait for operation to complete */
+ if (!wait_for_completion_timeout(&pd->swap_complete,
+ msecs_to_jiffies(100))) {
+ usbpd_err(&pd->dev, "data_role swap timed out\n");
+ return -ETIMEDOUT;
+ }
+
+ if ((*val == DUAL_ROLE_PROP_DR_HOST &&
+ pd->current_dr != DR_DFP) ||
+ (*val == DUAL_ROLE_PROP_DR_DEVICE &&
+ pd->current_dr != DR_UFP)) {
+ usbpd_err(&pd->dev, "incorrect state (%s) after data_role swap\n",
+ pd->current_dr == DR_DFP ?
+ "dfp" : "ufp");
+ return -EPROTO;
+ }
+ }
+
+ break;
+
+ case DUAL_ROLE_PROP_PR:
+ usbpd_dbg(&pd->dev, "Setting power_role to %d\n", *val);
+
+ if (*val == DUAL_ROLE_PROP_PR_SRC) {
+ if (pd->current_pr == PR_SINK)
+ do_swap = true;
+ } else if (*val == DUAL_ROLE_PROP_PR_SNK) {
+ if (pd->current_pr == PR_SRC)
+ do_swap = true;
+ } else {
+ usbpd_warn(&pd->dev, "setting power_role to 'none' unsupported\n");
+ return -ENOTSUPP;
+ }
+
+ if (do_swap) {
+ if (pd->current_state != PE_SRC_READY &&
+ pd->current_state != PE_SNK_READY) {
+ usbpd_err(&pd->dev, "power_role swap not allowed: PD not in Ready state\n");
+ return -EAGAIN;
+ }
+
+ reinit_completion(&pd->swap_complete);
+ pd->send_pr_swap = true;
+ kick_sm(pd, 0);
+
+ /* wait for operation to complete */
+ if (!wait_for_completion_timeout(&pd->swap_complete,
+ msecs_to_jiffies(2000))) {
+ usbpd_err(&pd->dev, "power_role swap timed out\n");
+ return -ETIMEDOUT;
+ }
+
+ if ((*val == DUAL_ROLE_PROP_PR_SRC &&
+ pd->current_pr != PR_SRC) ||
+ (*val == DUAL_ROLE_PROP_PR_SNK &&
+ pd->current_pr != PR_SINK)) {
+ usbpd_err(&pd->dev, "incorrect state (%s) after power_role swap\n",
+ pd->current_pr == PR_SRC ?
+ "source" : "sink");
+ return -EPROTO;
+ }
+ }
+ break;
+
+ default:
+ usbpd_warn(&pd->dev, "unsupported property %d\n", prop);
+ return -ENOTSUPP;
+ }
+
+ return 0;
+}
+
+static int usbpd_dr_prop_writeable(struct dual_role_phy_instance *dual_role,
+ enum dual_role_property prop)
+{
+ switch (prop) {
+ case DUAL_ROLE_PROP_MODE:
+ case DUAL_ROLE_PROP_DR:
+ case DUAL_ROLE_PROP_PR:
+ return 1;
+ default:
+ break;
+ }
+
+ return 0;
+}
+
static int usbpd_uevent(struct device *dev, struct kobj_uevent_env *env)
{
struct usbpd *pd = dev_get_drvdata(dev);
@@ -2698,6 +3012,30 @@ struct usbpd *usbpd_create(struct device *parent)
pd->vconn_is_external = device_property_present(parent,
"qcom,vconn-uses-external-source");
+ /*
+ * Register the Android dual-role class (/sys/class/dual_role_usb/).
+ * The first instance should be named "otg_default" as that's what
+ * Android expects.
+ * Note this is different than the /sys/class/usbpd/ created above.
+ */
+ pd->dr_desc.name = (num_pd_instances == 1) ?
+ "otg_default" : dev_name(&pd->dev);
+ pd->dr_desc.supported_modes = DUAL_ROLE_SUPPORTED_MODES_DFP_AND_UFP;
+ pd->dr_desc.properties = usbpd_dr_properties;
+ pd->dr_desc.num_properties = ARRAY_SIZE(usbpd_dr_properties);
+ pd->dr_desc.get_property = usbpd_dr_get_property;
+ pd->dr_desc.set_property = usbpd_dr_set_property;
+ pd->dr_desc.property_is_writeable = usbpd_dr_prop_writeable;
+
+ pd->dual_role = devm_dual_role_instance_register(&pd->dev,
+ &pd->dr_desc);
+ if (IS_ERR(pd->dual_role)) {
+ usbpd_err(&pd->dev, "could not register dual_role instance\n");
+ goto unreg_psy;
+ } else {
+ pd->dual_role->drv_data = pd;
+ }
+
pd->current_pr = PR_NONE;
pd->current_dr = DR_NONE;
list_add_tail(&pd->instance, &_usbpd);
@@ -2705,6 +3043,7 @@ struct usbpd *usbpd_create(struct device *parent)
spin_lock_init(&pd->rx_lock);
INIT_LIST_HEAD(&pd->rx_q);
INIT_LIST_HEAD(&pd->svid_handlers);
+ init_completion(&pd->swap_complete);
/* force read initial power_supply values */
psy_changed(&pd->psy_nb, PSY_EVENT_PROP_CHANGED, pd->usb_psy);
diff --git a/drivers/usb/pd/qpnp-pdphy.c b/drivers/usb/pd/qpnp-pdphy.c
index 0b9b60c3ca45..1a03b0d71a18 100644
--- a/drivers/usb/pd/qpnp-pdphy.c
+++ b/drivers/usb/pd/qpnp-pdphy.c
@@ -71,6 +71,9 @@
#define USB_PDPHY_RX_BUFFER 0x80
+#define USB_PDPHY_SEC_ACCESS 0xD0
+#define USB_PDPHY_TRIM_3 0xF3
+
/* VDD regulator */
#define VDD_PDPHY_VOL_MIN 3088000 /* uV */
#define VDD_PDPHY_VOL_MAX 3088000 /* uV */
@@ -673,6 +676,9 @@ static irqreturn_t pdphy_msg_rx_irq_thread(int irq, void *data)
if (ret)
goto done;
+ /* ack to change ownership of rx buffer back to PDPHY RX HW */
+ pdphy_reg_write(pdphy, USB_PDPHY_RX_ACKNOWLEDGE, 0);
+
if (((buf[0] & 0xf) == PD_MSG_BIST) && size >= 5) { /* BIST */
u8 mode = buf[5] >> 4; /* [31:28] of 1st data object */
@@ -689,9 +695,6 @@ static irqreturn_t pdphy_msg_rx_irq_thread(int irq, void *data)
if (pdphy->msg_rx_cb)
pdphy->msg_rx_cb(pdphy->usbpd, frame_type, buf, size + 1);
- /* ack to change ownership of rx buffer back to PDPHY RX HW */
- pdphy_reg_write(pdphy, USB_PDPHY_RX_ACKNOWLEDGE, 0);
-
print_hex_dump_debug("rx msg:", DUMP_PREFIX_NONE, 32, 4, buf, size + 1,
false);
pdphy->rx_bytes += size + 1;
@@ -806,6 +809,14 @@ static int pdphy_probe(struct platform_device *pdev)
if (ret < 0)
return ret;
+ ret = pdphy_reg_write(pdphy, USB_PDPHY_SEC_ACCESS, 0xA5);
+ if (ret)
+ return ret;
+
+ ret = pdphy_reg_write(pdphy, USB_PDPHY_TRIM_3, 0x2);
+ if (ret)
+ return ret;
+
/* usbpd_create() could call back to us, so have __pdphy ready */
__pdphy = pdphy;
diff --git a/drivers/video/fbdev/msm/mdp3_ctrl.c b/drivers/video/fbdev/msm/mdp3_ctrl.c
index 31c0cd86df4b..da6c68d43b53 100644
--- a/drivers/video/fbdev/msm/mdp3_ctrl.c
+++ b/drivers/video/fbdev/msm/mdp3_ctrl.c
@@ -1603,10 +1603,6 @@ int mdp3_validate_scale_config(struct mdp_bl_scale_data *data)
pr_err("%s invalid bl_scale\n", __func__);
return -EINVAL;
}
- if (data->min_lvl > MDP_HISTOGRAM_BL_LEVEL_MAX) {
- pr_err("%s invalid bl_min_lvl\n", __func__);
- return -EINVAL;
- }
return 0;
}
@@ -1810,9 +1806,7 @@ static int mdp3_bl_scale_config(struct msm_fb_data_type *mfd,
mutex_lock(&mfd->bl_lock);
curr_bl = mfd->bl_level;
mfd->bl_scale = data->scale;
- mfd->bl_min_lvl = data->min_lvl;
- pr_debug("update scale = %d, min_lvl = %d\n", mfd->bl_scale,
- mfd->bl_min_lvl);
+ pr_debug("update scale = %d\n", mfd->bl_scale);
/* update current backlight to use new scaling*/
mdss_fb_set_backlight(mfd, curr_bl);
diff --git a/drivers/video/fbdev/msm/mdss.h b/drivers/video/fbdev/msm/mdss.h
index 5a24a1995af9..5a6d7bc3ff78 100644
--- a/drivers/video/fbdev/msm/mdss.h
+++ b/drivers/video/fbdev/msm/mdss.h
@@ -164,6 +164,7 @@ enum mdss_hw_quirk {
MDSS_QUIRK_NEED_SECURE_MAP,
MDSS_QUIRK_SRC_SPLIT_ALWAYS,
MDSS_QUIRK_MMSS_GDSC_COLLAPSE,
+ MDSS_QUIRK_MDP_CLK_SET_RATE,
MDSS_QUIRK_MAX,
};
@@ -289,6 +290,7 @@ struct mdss_data_type {
bool en_svs_high;
u32 max_mdp_clk_rate;
struct mdss_util_intf *mdss_util;
+ unsigned long mdp_clk_rate;
struct platform_device *pdev;
struct dss_io_data mdss_io;
diff --git a/drivers/video/fbdev/msm/mdss_compat_utils.c b/drivers/video/fbdev/msm/mdss_compat_utils.c
index 5ad51dd23f3b..d3eb3db48eb7 100644
--- a/drivers/video/fbdev/msm/mdss_compat_utils.c
+++ b/drivers/video/fbdev/msm/mdss_compat_utils.c
@@ -197,7 +197,7 @@ static struct mdp_input_layer *__create_layer_list(
struct mdp_input_layer32 *layer_list32,
u32 layer_count)
{
- int i, ret;
+ int i, ret = 0;
u32 buffer_size;
struct mdp_input_layer *layer, *layer_list;
struct mdp_input_layer32 *layer32;
diff --git a/drivers/video/fbdev/msm/mdss_dba_utils.c b/drivers/video/fbdev/msm/mdss_dba_utils.c
index fa78bd0166ea..76671b539aa7 100644
--- a/drivers/video/fbdev/msm/mdss_dba_utils.c
+++ b/drivers/video/fbdev/msm/mdss_dba_utils.c
@@ -323,7 +323,9 @@ static void mdss_dba_utils_dba_cb(void *data, enum msm_dba_callback_event event)
if (!ret) {
hdmi_edid_parser(udata->edid_data);
hdmi_edid_get_audio_blk(udata->edid_data, &blk);
- udata->ops.set_audio_block(udata->dba_data,
+ if (udata->ops.set_audio_block)
+ udata->ops.set_audio_block(
+ udata->dba_data,
sizeof(blk), &blk);
} else {
pr_err("failed to get edid%d\n", ret);
diff --git a/drivers/video/fbdev/msm/mdss_debug.c b/drivers/video/fbdev/msm/mdss_debug.c
index 8663797f1730..6b455e0f1e6f 100644
--- a/drivers/video/fbdev/msm/mdss_debug.c
+++ b/drivers/video/fbdev/msm/mdss_debug.c
@@ -244,23 +244,19 @@ static ssize_t panel_debug_base_reg_read(struct file *file,
mdss_dsi_panel_cmd_read(ctrl_pdata, panel_reg[0], panel_reg[1],
NULL, rx_buf, dbg->cnt);
- len = snprintf(panel_reg_buf, reg_buf_len, "0x%02zx: ", dbg->off);
- if (len < 0)
- goto read_reg_fail;
+ len = scnprintf(panel_reg_buf, reg_buf_len, "0x%02zx: ", dbg->off);
for (i = 0; (len < reg_buf_len) && (i < ctrl_pdata->rx_len); i++)
len += scnprintf(panel_reg_buf + len, reg_buf_len - len,
"0x%02x ", rx_buf[i]);
- panel_reg_buf[len - 1] = '\n';
+ if (len)
+ panel_reg_buf[len - 1] = '\n';
if (mdata->debug_inf.debug_enable_clock)
mdata->debug_inf.debug_enable_clock(0);
- if (len < 0 || len >= sizeof(panel_reg_buf))
- return 0;
-
- if ((count < sizeof(panel_reg_buf))
+ if ((count < reg_buf_len)
|| (copy_to_user(user_buf, panel_reg_buf, len)))
goto read_reg_fail;
diff --git a/drivers/video/fbdev/msm/mdss_dp.c b/drivers/video/fbdev/msm/mdss_dp.c
index b7561e49955b..132dc0e028ae 100644
--- a/drivers/video/fbdev/msm/mdss_dp.c
+++ b/drivers/video/fbdev/msm/mdss_dp.c
@@ -45,6 +45,8 @@
#define VDDA_UA_ON_LOAD 100000 /* uA units */
#define VDDA_UA_OFF_LOAD 100 /* uA units */
+#define DP_CRYPTO_CLK_RATE_KHZ 337500
+
struct mdss_dp_attention_node {
u32 vdo;
struct list_head list;
@@ -208,9 +210,9 @@ static int mdss_dp_get_dt_clk_data(struct device *dev,
&ctrl_power_data->clk_config[ctrl_clk_index];
strlcpy(clk->clk_name, clk_name, sizeof(clk->clk_name));
ctrl_clk_index++;
- if (!strcmp(clk_name, "ctrl_link_clk"))
- clk->type = DSS_CLK_PCLK;
- else if (!strcmp(clk_name, "ctrl_pixel_clk"))
+ if (!strcmp(clk_name, "ctrl_link_clk") ||
+ !strcmp(clk_name, "ctrl_pixel_clk") ||
+ !strcmp(clk_name, "ctrl_crypto_clk"))
clk->type = DSS_CLK_PCLK;
else
clk->type = DSS_CLK_AHB;
@@ -1089,6 +1091,23 @@ exit:
return ret;
}
+static void mdss_dp_set_clock_rate(struct mdss_dp_drv_pdata *dp,
+ char *name, u32 rate)
+{
+ u32 num = dp->power_data[DP_CTRL_PM].num_clk;
+ struct dss_clk *cfg = dp->power_data[DP_CTRL_PM].clk_config;
+
+ while (num && strcmp(cfg->clk_name, name)) {
+ num--;
+ cfg++;
+ }
+
+ if (num)
+ cfg->rate = rate;
+ else
+ pr_err("%s clock could not be set with rate %d\n", name, rate);
+}
+
/**
* mdss_dp_enable_mainlink_clocks() - enables Display Port main link clocks
* @dp: Display Port Driver data
@@ -1099,12 +1118,14 @@ static int mdss_dp_enable_mainlink_clocks(struct mdss_dp_drv_pdata *dp)
{
int ret = 0;
- dp->power_data[DP_CTRL_PM].clk_config[0].rate =
- ((dp->link_rate * DP_LINK_RATE_MULTIPLIER) / 1000);/* KHz */
+ mdss_dp_set_clock_rate(dp, "ctrl_link_clk",
+ (dp->link_rate * DP_LINK_RATE_MULTIPLIER) / DP_KHZ_TO_HZ);
+
+ mdss_dp_set_clock_rate(dp, "ctrl_crypto_clk", DP_CRYPTO_CLK_RATE_KHZ);
dp->pixel_rate = dp->panel_data.panel_info.clk_rate;
- dp->power_data[DP_CTRL_PM].clk_config[3].rate =
- (dp->pixel_rate / 1000);/* KHz */
+ mdss_dp_set_clock_rate(dp, "ctrl_pixel_clk",
+ (dp->pixel_rate / DP_KHZ_TO_HZ));
ret = mdss_dp_clk_ctrl(dp, DP_CTRL_PM, true);
if (ret) {
@@ -1286,12 +1307,8 @@ int mdss_dp_on_hpd(struct mdss_dp_drv_pdata *dp_drv)
link_training:
dp_drv->power_on = true;
- if (-EAGAIN == mdss_dp_train_main_link(dp_drv)) {
- mutex_unlock(&dp_drv->train_mutex);
-
- mdss_dp_link_retraining(dp_drv);
- return 0;
- }
+ while (-EAGAIN == mdss_dp_train_main_link(dp_drv))
+ pr_debug("MAIN LINK TRAINING RETRY\n");
dp_drv->cont_splash = 0;
@@ -1622,13 +1639,27 @@ static void mdss_dp_hdcp_cb_work(struct work_struct *work)
struct mdss_dp_drv_pdata *dp;
struct delayed_work *dw = to_delayed_work(work);
struct hdcp_ops *ops;
+ unsigned char *base;
int rc = 0;
+ u32 hdcp_auth_state;
dp = container_of(dw, struct mdss_dp_drv_pdata, hdcp_cb_work);
+ base = dp->base;
+
+ hdcp_auth_state = (dp_read(base + DP_HDCP_STATUS) >> 20) & 0x3;
+
+ pr_debug("hdcp auth state %d\n", hdcp_auth_state);
ops = dp->hdcp.ops;
switch (dp->hdcp_status) {
+ case HDCP_STATE_AUTHENTICATING:
+ pr_debug("start authenticaton\n");
+
+ if (dp->hdcp.ops && dp->hdcp.ops->authenticate)
+ rc = dp->hdcp.ops->authenticate(dp->hdcp.data);
+
+ break;
case HDCP_STATE_AUTHENTICATED:
pr_debug("hdcp authenticated\n");
dp->hdcp.auth_state = true;
@@ -1636,7 +1667,7 @@ static void mdss_dp_hdcp_cb_work(struct work_struct *work)
case HDCP_STATE_AUTH_FAIL:
dp->hdcp.auth_state = false;
- if (dp->power_on) {
+ if (dp->alt_mode.dp_status.hpd_high && dp->power_on) {
pr_debug("Reauthenticating\n");
if (ops && ops->reauthenticate) {
rc = ops->reauthenticate(dp->hdcp.data);
@@ -1664,7 +1695,8 @@ static void mdss_dp_hdcp_cb(void *ptr, enum hdcp_states status)
dp->hdcp_status = status;
- queue_delayed_work(dp->workq, &dp->hdcp_cb_work, HZ/4);
+ if (dp->alt_mode.dp_status.hpd_high)
+ queue_delayed_work(dp->workq, &dp->hdcp_cb_work, HZ/4);
}
static int mdss_dp_hdcp_init(struct mdss_panel_data *pdata)
@@ -1927,20 +1959,28 @@ static int mdss_dp_event_handler(struct mdss_panel_data *pdata,
rc = mdss_dp_on(pdata);
break;
case MDSS_EVENT_PANEL_ON:
+ mdss_dp_ack_state(dp, true);
+
mdss_dp_update_hdcp_info(dp);
- if (dp->hdcp.ops && dp->hdcp.ops->authenticate)
- rc = dp->hdcp.ops->authenticate(dp->hdcp.data);
+ if (dp_is_hdcp_enabled(dp)) {
+ cancel_delayed_work(&dp->hdcp_cb_work);
- mdss_dp_ack_state(dp, true);
+ dp->hdcp_status = HDCP_STATE_AUTHENTICATING;
+ queue_delayed_work(dp->workq,
+ &dp->hdcp_cb_work, HZ / 2);
+ }
break;
case MDSS_EVENT_PANEL_OFF:
rc = mdss_dp_off(pdata);
break;
case MDSS_EVENT_BLANK:
- if (dp_is_hdcp_enabled(dp) && dp->hdcp.ops->off) {
- flush_delayed_work(&dp->hdcp_cb_work);
- dp->hdcp.ops->off(dp->hdcp.data);
+ if (dp_is_hdcp_enabled(dp)) {
+ dp->hdcp_status = HDCP_STATE_INACTIVE;
+
+ cancel_delayed_work(&dp->hdcp_cb_work);
+ if (dp->hdcp.ops->off)
+ dp->hdcp.ops->off(dp->hdcp.data);
}
mdss_dp_mainlink_push_idle(pdata);
@@ -2152,8 +2192,9 @@ static void mdss_dp_event_work(struct work_struct *work)
SVDM_CMD_TYPE_INITIATOR, 0x1, 0x0, 0x0);
break;
case EV_USBPD_DP_STATUS:
+ config = 0x1; /* DFP_D connected */
usbpd_send_svdm(dp->pd, USB_C_DP_SID, DP_VDM_STATUS,
- SVDM_CMD_TYPE_INITIATOR, 0x1, 0x0, 0x0);
+ SVDM_CMD_TYPE_INITIATOR, 0x1, &config, 0x1);
break;
case EV_USBPD_DP_CONFIGURE:
config = mdss_dp_usbpd_gen_config_pkt(dp);
@@ -2188,9 +2229,6 @@ irqreturn_t dp_isr(int irq, void *ptr)
isr1 &= ~mask1; /* remove masks bit */
- pr_debug("isr=%x mask=%x isr2=%x\n",
- isr1, mask1, isr2);
-
ack = isr1 & EDP_INTR_STATUS1;
ack <<= 1; /* ack bits */
ack |= mask1;
@@ -2552,7 +2590,8 @@ static void usbpd_response_callback(struct usbpd_svid_handler *hdlr, u8 cmd,
dp_drv->alt_mode.dp_cap.response = *vdos;
mdss_dp_usbpd_ext_capabilities(&dp_drv->alt_mode.dp_cap);
dp_drv->alt_mode.current_state |= DISCOVER_MODES_DONE;
- dp_send_events(dp_drv, EV_USBPD_ENTER_MODE);
+ if (dp_drv->alt_mode.dp_cap.s_port & BIT(0))
+ dp_send_events(dp_drv, EV_USBPD_ENTER_MODE);
break;
case USBPD_SVDM_ENTER_MODE:
dp_drv->alt_mode.current_state |= ENTER_MODE_DONE;
@@ -2574,7 +2613,8 @@ static void usbpd_response_callback(struct usbpd_svid_handler *hdlr, u8 cmd,
if (!(dp_drv->alt_mode.current_state & DP_CONFIGURE_DONE)) {
dp_drv->alt_mode.current_state |= DP_STATUS_DONE;
- dp_send_events(dp_drv, EV_USBPD_DP_CONFIGURE);
+ if (dp_drv->alt_mode.dp_status.c_port & BIT(1))
+ dp_send_events(dp_drv, EV_USBPD_DP_CONFIGURE);
}
break;
case DP_VDM_CONFIGURE:
@@ -2598,9 +2638,10 @@ static void mdss_dp_process_attention(struct mdss_dp_drv_pdata *dp_drv)
if (dp_drv->alt_mode.dp_status.hpd_irq) {
pr_debug("Attention: hpd_irq high\n");
- if (dp_drv->power_on && dp_drv->hdcp.ops &&
- dp_drv->hdcp.ops->cp_irq)
- dp_drv->hdcp.ops->cp_irq(dp_drv->hdcp.data);
+ if (dp_drv->hdcp.ops && dp_drv->hdcp.ops->cp_irq) {
+ if (!dp_drv->hdcp.ops->cp_irq(dp_drv->hdcp.data))
+ return;
+ }
if (!mdss_dp_process_hpd_irq_high(dp_drv))
return;
@@ -2611,6 +2652,12 @@ static void mdss_dp_process_attention(struct mdss_dp_drv_pdata *dp_drv)
if (!dp_drv->alt_mode.dp_status.hpd_high) {
pr_debug("Attention: HPD low\n");
+
+ if (dp_is_hdcp_enabled(dp_drv) && dp_drv->hdcp.ops->off) {
+ cancel_delayed_work(&dp_drv->hdcp_cb_work);
+ dp_drv->hdcp.ops->off(dp_drv->hdcp.data);
+ }
+
mdss_dp_update_cable_status(dp_drv, false);
mdss_dp_notify_clients(dp_drv, false);
pr_debug("Attention: Notified clients\n");
diff --git a/drivers/video/fbdev/msm/mdss_dp.h b/drivers/video/fbdev/msm/mdss_dp.h
index 04abe9221acc..dc84694f2238 100644
--- a/drivers/video/fbdev/msm/mdss_dp.h
+++ b/drivers/video/fbdev/msm/mdss_dp.h
@@ -228,6 +228,7 @@ struct dp_alt_mode {
#define DP_LINK_RATE_MAX DP_LINK_RATE_540
#define DP_LINK_RATE_MULTIPLIER 27000000
+#define DP_KHZ_TO_HZ 1000
#define DP_MAX_PIXEL_CLK_KHZ 675000
struct downstream_port_config {
/* Byte 02205h */
diff --git a/drivers/video/fbdev/msm/mdss_dp_hdcp2p2.c b/drivers/video/fbdev/msm/mdss_dp_hdcp2p2.c
index 79cd94cfbe88..73b9ad65482f 100644
--- a/drivers/video/fbdev/msm/mdss_dp_hdcp2p2.c
+++ b/drivers/video/fbdev/msm/mdss_dp_hdcp2p2.c
@@ -23,6 +23,8 @@
#include "mdss_hdcp.h"
#include "mdss_dp_util.h"
+struct dp_hdcp2p2_ctrl;
+
enum dp_hdcp2p2_sink_status {
SINK_DISCONNECTED,
SINK_CONNECTED
@@ -33,9 +35,21 @@ enum dp_auth_status {
DP_HDCP_AUTH_STATUS_SUCCESS
};
+struct dp_hdcp2p2_int_set {
+ u32 interrupt;
+ char *name;
+ void (*func)(struct dp_hdcp2p2_ctrl *ctrl);
+};
+
+struct dp_hdcp2p2_interrupts {
+ u32 reg;
+ struct dp_hdcp2p2_int_set *int_set;
+};
+
struct dp_hdcp2p2_ctrl {
atomic_t auth_state;
enum dp_hdcp2p2_sink_status sink_status; /* Is sink connected */
+ struct dp_hdcp2p2_interrupts *intr;
struct hdcp_init_data init_data;
struct mutex mutex; /* mutex to protect access to ctrl */
struct mutex msg_lock; /* mutex to protect access to msg buffer */
@@ -172,7 +186,10 @@ static int dp_hdcp2p2_wakeup(struct hdmi_hdcp_wakeup_data *data)
queue_kthread_work(&ctrl->worker, &ctrl->status);
break;
case HDMI_HDCP_WKUP_CMD_LINK_POLL:
- ctrl->polling = true;
+ if (ctrl->cp_irq_done)
+ queue_kthread_work(&ctrl->worker, &ctrl->recv_msg);
+ else
+ ctrl->polling = true;
break;
case HDMI_HDCP_WKUP_CMD_AUTHENTICATE:
queue_kthread_work(&ctrl->worker, &ctrl->auth);
@@ -211,6 +228,31 @@ static void dp_hdcp2p2_reset(struct dp_hdcp2p2_ctrl *ctrl)
atomic_set(&ctrl->auth_state, HDCP_STATE_INACTIVE);
}
+static void dp_hdcp2p2_set_interrupts(struct dp_hdcp2p2_ctrl *ctrl, bool enable)
+{
+ unsigned char *base = ctrl->init_data.core_io->base;
+ struct dp_hdcp2p2_interrupts *intr = ctrl->intr;
+
+ while (intr && intr->reg) {
+ struct dp_hdcp2p2_int_set *int_set = intr->int_set;
+ u32 interrupts = 0;
+
+ while (int_set && int_set->interrupt) {
+ interrupts |= int_set->interrupt;
+ int_set++;
+ }
+
+ if (enable)
+ dp_write(base + intr->reg,
+ dp_read(base + intr->reg) | interrupts);
+ else
+ dp_write(base + intr->reg,
+ dp_read(base + intr->reg) & ~interrupts);
+
+ intr++;
+ }
+}
+
static void dp_hdcp2p2_off(void *input)
{
struct dp_hdcp2p2_ctrl *ctrl = (struct dp_hdcp2p2_ctrl *)input;
@@ -221,6 +263,13 @@ static void dp_hdcp2p2_off(void *input)
return;
}
+ if (atomic_read(&ctrl->auth_state) == HDCP_STATE_INACTIVE) {
+ pr_err("hdcp is off\n");
+ return;
+ }
+
+ dp_hdcp2p2_set_interrupts(ctrl, false);
+
dp_hdcp2p2_reset(ctrl);
flush_kthread_worker(&ctrl->worker);
@@ -237,6 +286,8 @@ static int dp_hdcp2p2_authenticate(void *input)
flush_kthread_worker(&ctrl->worker);
+ dp_hdcp2p2_set_interrupts(ctrl, true);
+
ctrl->sink_status = SINK_CONNECTED;
atomic_set(&ctrl->auth_state, HDCP_STATE_AUTHENTICATING);
@@ -317,6 +368,8 @@ static void dp_hdcp2p2_auth_failed(struct dp_hdcp2p2_ctrl *ctrl)
return;
}
+ dp_hdcp2p2_set_interrupts(ctrl, false);
+
/* notify DP about HDCP failure */
ctrl->init_data.notify_status(ctrl->init_data.cb_data,
HDCP_STATE_AUTH_FAIL);
@@ -574,18 +627,6 @@ static void dp_hdcp2p2_link_work(struct kthread_work *work)
cdata.context = ctrl->lib_ctx;
- ctrl->sink_rx_status = 0;
- rc = mdss_dp_aux_read_rx_status(ctrl->init_data.cb_data,
- &ctrl->sink_rx_status);
-
- if (rc) {
- pr_err("failed to read rx status\n");
-
- cdata.cmd = HDCP_LIB_WKUP_CMD_LINK_FAILED;
- atomic_set(&ctrl->auth_state, HDCP_STATE_AUTH_FAIL);
- goto exit;
- }
-
if (ctrl->sink_rx_status & ctrl->abort_mask) {
if (ctrl->sink_rx_status & BIT(3))
pr_err("reauth_req set by sink\n");
@@ -636,6 +677,7 @@ static void dp_hdcp2p2_auth_work(struct kthread_work *work)
static int dp_hdcp2p2_cp_irq(void *input)
{
+ int rc = 0;
struct dp_hdcp2p2_ctrl *ctrl = input;
if (!ctrl) {
@@ -643,9 +685,67 @@ static int dp_hdcp2p2_cp_irq(void *input)
return -EINVAL;
}
+ ctrl->sink_rx_status = 0;
+ rc = mdss_dp_aux_read_rx_status(ctrl->init_data.cb_data,
+ &ctrl->sink_rx_status);
+ if (rc) {
+ pr_err("failed to read rx status\n");
+ goto error;
+ }
+
+ pr_debug("sink_rx_status=0x%x\n", ctrl->sink_rx_status);
+
+ if (!ctrl->sink_rx_status) {
+ pr_debug("not a hdcp 2.2 irq\n");
+ rc = -EINVAL;
+ goto error;
+ }
+
queue_kthread_work(&ctrl->worker, &ctrl->link);
return 0;
+error:
+ return rc;
+}
+
+static int dp_hdcp2p2_isr(void *input)
+{
+ struct dp_hdcp2p2_ctrl *ctrl = (struct dp_hdcp2p2_ctrl *)input;
+ int rc = 0;
+ struct dss_io_data *io;
+ struct dp_hdcp2p2_interrupts *intr;
+ u32 hdcp_int_val;
+
+ if (!ctrl || !ctrl->init_data.core_io) {
+ pr_err("invalid input\n");
+ rc = -EINVAL;
+ goto end;
+ }
+
+ io = ctrl->init_data.core_io;
+ intr = ctrl->intr;
+
+ while (intr && intr->reg) {
+ struct dp_hdcp2p2_int_set *int_set = intr->int_set;
+
+ hdcp_int_val = dp_read(io->base + intr->reg);
+
+ while (int_set && int_set->interrupt) {
+ if (hdcp_int_val & (int_set->interrupt >> 2)) {
+ pr_debug("%s\n", int_set->name);
+
+ if (int_set->func)
+ int_set->func(ctrl);
+
+ dp_write(io->base + intr->reg, hdcp_int_val |
+ (int_set->interrupt >> 1));
+ }
+ int_set++;
+ }
+ intr++;
+ }
+end:
+ return rc;
}
void dp_hdcp2p2_deinit(void *input)
@@ -679,6 +779,7 @@ void *dp_hdcp2p2_init(struct hdcp_init_data *init_data)
int rc;
struct dp_hdcp2p2_ctrl *ctrl;
static struct hdcp_ops ops = {
+ .isr = dp_hdcp2p2_isr,
.reauthenticate = dp_hdcp2p2_reauthenticate,
.authenticate = dp_hdcp2p2_authenticate,
.feature_supported = dp_hdcp2p2_feature_supported,
@@ -689,7 +790,22 @@ void *dp_hdcp2p2_init(struct hdcp_init_data *init_data)
static struct hdcp_client_ops client_ops = {
.wakeup = dp_hdcp2p2_wakeup,
};
-
+ static struct dp_hdcp2p2_int_set int_set1[] = {
+ {BIT(17), "authentication successful", 0},
+ {BIT(20), "authentication failed", 0},
+ {BIT(24), "encryption enabled", 0},
+ {BIT(27), "encryption disabled", 0},
+ {0},
+ };
+ static struct dp_hdcp2p2_int_set int_set2[] = {
+ {BIT(2), "key fifo underflow", 0},
+ {0},
+ };
+ static struct dp_hdcp2p2_interrupts intr[] = {
+ {DP_INTR_STATUS2, int_set1},
+ {DP_INTR_STATUS3, int_set2},
+ {0}
+ };
static struct hdcp_txmtr_ops txmtr_ops;
struct hdcp_register_data register_data = {0};
@@ -714,6 +830,7 @@ void *dp_hdcp2p2_init(struct hdcp_init_data *init_data)
}
ctrl->sink_status = SINK_DISCONNECTED;
+ ctrl->intr = intr;
atomic_set(&ctrl->auth_state, HDCP_STATE_INACTIVE);
diff --git a/drivers/video/fbdev/msm/mdss_dp_util.c b/drivers/video/fbdev/msm/mdss_dp_util.c
index 86edc4492599..10962548c3c5 100644
--- a/drivers/video/fbdev/msm/mdss_dp_util.c
+++ b/drivers/video/fbdev/msm/mdss_dp_util.c
@@ -266,8 +266,7 @@ void mdss_dp_sw_config_msa(struct dss_io_data *ctrl_io,
mvid = (pixel_m & 0xFFFF) * 5;
nvid = (0xFFFF & (~pixel_n)) + (pixel_m & 0xFFFF);
- if (lrate == DP_LINK_RATE_540)
- nvid = nvid * 2;
+
pr_debug("mvid=0x%x, nvid=0x%x\n", mvid, nvid);
writel_relaxed(mvid, ctrl_io->base + DP_SOFTWARE_MVID);
writel_relaxed(nvid, ctrl_io->base + DP_SOFTWARE_NVID);
diff --git a/drivers/video/fbdev/msm/mdss_dp_util.h b/drivers/video/fbdev/msm/mdss_dp_util.h
index 4b28d98177be..82e9f9417662 100644
--- a/drivers/video/fbdev/msm/mdss_dp_util.h
+++ b/drivers/video/fbdev/msm/mdss_dp_util.h
@@ -185,6 +185,7 @@
#define DP_HDCP_RCVPORT_DATA6 (0x0C4)
#define HDCP_SEC_DP_TZ_HV_HLOS_HDCP_SHA_CTRL (0x024)
+#define HDCP_SEC_DP_TZ_HV_HLOS_HDCP_SHA_DATA (0x028)
#define HDCP_SEC_DP_TZ_HV_HLOS_HDCP_RCVPORT_DATA0 (0x004)
#define HDCP_SEC_DP_TZ_HV_HLOS_HDCP_RCVPORT_DATA1 (0x008)
#define HDCP_SEC_DP_TZ_HV_HLOS_HDCP_RCVPORT_DATA7 (0x00C)
diff --git a/drivers/video/fbdev/msm/mdss_dsi.c b/drivers/video/fbdev/msm/mdss_dsi.c
index 8dccab8a81be..423a15d82679 100644
--- a/drivers/video/fbdev/msm/mdss_dsi.c
+++ b/drivers/video/fbdev/msm/mdss_dsi.c
@@ -1283,7 +1283,11 @@ int mdss_dsi_switch_mode(struct mdss_panel_data *pdata, int mode)
MDSS_DSI_ALL_CLKS, MDSS_DSI_CLK_ON);
if (dsi_ctrl_setup_needed)
mdss_dsi_ctrl_setup(ctrl_pdata);
+
+ ATRACE_BEGIN("switch_cmds");
ctrl_pdata->switch_mode(pdata, mode);
+ ATRACE_END("switch_cmds");
+
mdss_dsi_clk_ctrl(ctrl_pdata, ctrl_pdata->dsi_clk_handle,
MDSS_DSI_ALL_CLKS, MDSS_DSI_CLK_OFF);
@@ -1733,6 +1737,38 @@ int mdss_dsi_cont_splash_on(struct mdss_panel_data *pdata)
return ret;
}
+static void __mdss_dsi_mask_dfps_errors(struct mdss_dsi_ctrl_pdata *ctrl,
+ bool mask)
+{
+ u32 data = 0;
+
+ /*
+ * Assumption is that the DSI clocks will be enabled
+ * when this API is called from dfps thread
+ */
+ if (mask) {
+ /* mask FIFO underflow and PLL unlock bits */
+ mdss_dsi_set_reg(ctrl, 0x10c, 0x7c000000, 0x7c000000);
+ } else {
+ data = MIPI_INP((ctrl->ctrl_base) + 0x0120);
+ if (data & BIT(16)) {
+ pr_debug("pll unlocked: 0x%x\n", data);
+ /* clear PLL unlock bit */
+ MIPI_OUTP((ctrl->ctrl_base) + 0x120, BIT(16));
+ }
+
+ data = MIPI_INP((ctrl->ctrl_base) + 0x00c);
+ if (data & 0x88880000) {
+ pr_debug("dsi fifo underflow: 0x%x\n", data);
+ /* clear DSI FIFO underflow and empty */
+ MIPI_OUTP((ctrl->ctrl_base) + 0x00c, 0x99990000);
+ }
+
+ /* restore FIFO underflow and PLL unlock bits */
+ mdss_dsi_set_reg(ctrl, 0x10c, 0x7c000000, 0x0);
+ }
+}
+
static void __mdss_dsi_update_video_mode_total(struct mdss_panel_data *pdata,
int new_fps)
{
@@ -1935,7 +1971,6 @@ static int __mdss_dsi_dfps_update_clks(struct mdss_panel_data *pdata,
struct mdss_dsi_ctrl_pdata *sctrl_pdata = NULL;
struct mdss_panel_info *pinfo, *spinfo;
int rc = 0;
- u32 data;
if (pdata == NULL) {
pr_err("%s Invalid pdata\n", __func__);
@@ -2055,12 +2090,9 @@ static int __mdss_dsi_dfps_update_clks(struct mdss_panel_data *pdata,
MIPI_OUTP((sctrl_pdata->ctrl_base) + DSI_DYNAMIC_REFRESH_CTRL,
0x00);
- data = MIPI_INP((ctrl_pdata->ctrl_base) + 0x0120);
- if (data & BIT(16)) {
- pr_debug("pll unlocked: 0x%x\n", data);
- /* clear PLL unlock bit */
- MIPI_OUTP((ctrl_pdata->ctrl_base) + 0x120, BIT(16));
- }
+ __mdss_dsi_mask_dfps_errors(ctrl_pdata, false);
+ if (sctrl_pdata)
+ __mdss_dsi_mask_dfps_errors(sctrl_pdata, false);
/* Move the mux clocks to main byte and pixel clocks */
rc = clk_set_parent(ctrl_pdata->mux_byte_clk,
@@ -2188,6 +2220,9 @@ static int mdss_dsi_dfps_config(struct mdss_panel_data *pdata, int new_fps)
__mdss_dsi_update_video_mode_total(pdata, new_fps);
} else if (pinfo->dfps_update == DFPS_IMMEDIATE_CLK_UPDATE_MODE) {
/* Clock update method */
+
+ __mdss_dsi_mask_dfps_errors(ctrl_pdata, true);
+
if (phy_rev == DSI_PHY_REV_20) {
rc = mdss_dsi_phy_calc_timing_param(pinfo, phy_rev,
new_fps);
diff --git a/drivers/video/fbdev/msm/mdss_dsi.h b/drivers/video/fbdev/msm/mdss_dsi.h
index 3a347681f434..6c840c8459ae 100644
--- a/drivers/video/fbdev/msm/mdss_dsi.h
+++ b/drivers/video/fbdev/msm/mdss_dsi.h
@@ -692,6 +692,8 @@ void mdss_dsi_dsc_config(struct mdss_dsi_ctrl_pdata *ctrl,
struct dsc_desc *dsc);
void mdss_dsi_dfps_config_8996(struct mdss_dsi_ctrl_pdata *ctrl);
void mdss_dsi_set_burst_mode(struct mdss_dsi_ctrl_pdata *ctrl);
+void mdss_dsi_set_reg(struct mdss_dsi_ctrl_pdata *ctrl, int off,
+ u32 mask, u32 val);
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 5f8b45413e32..d445f95924ef 100644
--- a/drivers/video/fbdev/msm/mdss_dsi_host.c
+++ b/drivers/video/fbdev/msm/mdss_dsi_host.c
@@ -134,7 +134,7 @@ void mdss_dsi_ctrl_init(struct device *ctrl_dev,
}
}
-static void mdss_dsi_set_reg(struct mdss_dsi_ctrl_pdata *ctrl, int off,
+void mdss_dsi_set_reg(struct mdss_dsi_ctrl_pdata *ctrl, int off,
u32 mask, u32 val)
{
u32 data;
@@ -2978,7 +2978,7 @@ bool mdss_dsi_dln0_phy_err(struct mdss_dsi_ctrl_pdata *ctrl, bool print_en)
static bool mdss_dsi_fifo_status(struct mdss_dsi_ctrl_pdata *ctrl)
{
- u32 status, isr;
+ u32 status;
unsigned char *base;
bool ret = false;
@@ -2990,17 +2990,7 @@ static bool mdss_dsi_fifo_status(struct mdss_dsi_ctrl_pdata *ctrl)
if (status & 0xcccc4409) {
MIPI_OUTP(base + 0x000c, status);
- /*
- * When dynamic refresh operation is under progress, it is
- * expected to have FIFO underflow error sometimes. In such
- * cases, do not trigger the underflow recovery process and
- * avoid printing the error status on console.
- */
- isr = MIPI_INP(ctrl->ctrl_base + 0x0110);
- if (isr & DSI_INTR_DYNAMIC_REFRESH_MASK)
- status &= ~(0x88880000);
- else
- pr_err("%s: status=%x\n", __func__, status);
+ pr_err("%s: status=%x\n", __func__, status);
if (status & 0x44440000) {/* DLNx_HS_FIFO_OVERFLOW */
dsi_send_events(ctrl, DSI_EV_DLNx_FIFO_OVERFLOW, 0);
@@ -3048,6 +3038,10 @@ static bool mdss_dsi_clk_status(struct mdss_dsi_ctrl_pdata *ctrl)
if (status & 0x10000) { /* DSI_CLK_PLL_UNLOCKED */
MIPI_OUTP(base + 0x0120, status);
+ /* If PLL unlock is masked, do not report error */
+ if (MIPI_INP(base + 0x10c) & BIT(28))
+ return false;
+
dsi_send_events(ctrl, DSI_EV_PLL_UNLOCKED, 0);
pr_err("%s: status=%x\n", __func__, status);
ret = true;
@@ -3134,6 +3128,11 @@ irqreturn_t mdss_dsi_isr(int irq, void *ptr)
pr_debug("%s: ndx=%d isr=%x\n", __func__, ctrl->ndx, isr);
+ if (isr & DSI_INTR_ERROR) {
+ MDSS_XLOG(ctrl->ndx, ctrl->mdp_busy, isr, 0x97);
+ mdss_dsi_error(ctrl);
+ }
+
if (isr & DSI_INTR_BTA_DONE) {
MDSS_XLOG(ctrl->ndx, ctrl->mdp_busy, isr, 0x96);
spin_lock(&ctrl->mdp_lock);
@@ -3158,11 +3157,6 @@ irqreturn_t mdss_dsi_isr(int irq, void *ptr)
spin_unlock(&ctrl->mdp_lock);
}
- if (isr & DSI_INTR_ERROR) {
- MDSS_XLOG(ctrl->ndx, ctrl->mdp_busy, isr, 0x97);
- mdss_dsi_error(ctrl);
- }
-
if (isr & DSI_INTR_VIDEO_DONE) {
spin_lock(&ctrl->mdp_lock);
mdss_dsi_disable_irq_nosync(ctrl, DSI_VIDEO_TERM);
diff --git a/drivers/video/fbdev/msm/mdss_dsi_panel.c b/drivers/video/fbdev/msm/mdss_dsi_panel.c
index 7c36bb627043..8fbf2544f487 100644
--- a/drivers/video/fbdev/msm/mdss_dsi_panel.c
+++ b/drivers/video/fbdev/msm/mdss_dsi_panel.c
@@ -1960,6 +1960,9 @@ static int mdss_dsi_parse_panel_features(struct device_node *np,
pinfo->panel_ack_disabled = pinfo->sim_panel_mode ?
1 : of_property_read_bool(np, "qcom,panel-ack-disabled");
+ pinfo->allow_phy_power_off = of_property_read_bool(np,
+ "qcom,panel-allow-phy-poweroff");
+
mdss_dsi_parse_esd_params(np, ctrl);
if (pinfo->panel_ack_disabled && pinfo->esd_check_enabled) {
diff --git a/drivers/video/fbdev/msm/mdss_fb.c b/drivers/video/fbdev/msm/mdss_fb.c
index d528305af798..98ca6c3da20b 100644
--- a/drivers/video/fbdev/msm/mdss_fb.c
+++ b/drivers/video/fbdev/msm/mdss_fb.c
@@ -1134,10 +1134,10 @@ static int mdss_fb_probe(struct platform_device *pdev)
mfd->bl_level = 0;
mfd->bl_scale = 1024;
- mfd->bl_min_lvl = 30;
mfd->ad_bl_level = 0;
mfd->fb_imgType = MDP_RGBA_8888;
mfd->calib_mode_bl = 0;
+ mfd->unset_bl_level = U32_MAX;
mfd->pdev = pdev;
@@ -1511,27 +1511,22 @@ static void mdss_fb_scale_bl(struct msm_fb_data_type *mfd, u32 *bl_lvl)
u32 temp = *bl_lvl;
pr_debug("input = %d, scale = %d\n", temp, mfd->bl_scale);
- if (temp >= mfd->bl_min_lvl) {
- if (temp > mfd->panel_info->bl_max) {
- pr_warn("%s: invalid bl level\n",
+ if (temp > mfd->panel_info->bl_max) {
+ pr_warn("%s: invalid bl level\n",
__func__);
- temp = mfd->panel_info->bl_max;
- }
- if (mfd->bl_scale > 1024) {
- pr_warn("%s: invalid bl scale\n",
+ temp = mfd->panel_info->bl_max;
+ }
+ if (mfd->bl_scale > 1024) {
+ pr_warn("%s: invalid bl scale\n",
__func__);
- mfd->bl_scale = 1024;
- }
- /*
- * bl_scale is the numerator of
- * scaling fraction (x/1024)
- */
- temp = (temp * mfd->bl_scale) / 1024;
-
- /*if less than minimum level, use min level*/
- if (temp < mfd->bl_min_lvl)
- temp = mfd->bl_min_lvl;
+ mfd->bl_scale = 1024;
}
+ /*
+ * bl_scale is the numerator of
+ * scaling fraction (x/1024)
+ */
+ temp = (temp * mfd->bl_scale) / 1024;
+
pr_debug("output = %d\n", temp);
(*bl_lvl) = temp;
@@ -1553,7 +1548,7 @@ void mdss_fb_set_backlight(struct msm_fb_data_type *mfd, u32 bkl_lvl)
} else if (mdss_fb_is_power_on(mfd) && mfd->panel_info->panel_dead) {
mfd->unset_bl_level = mfd->bl_level;
} else {
- mfd->unset_bl_level = 0;
+ mfd->unset_bl_level = U32_MAX;
}
pdata = dev_get_platdata(&mfd->pdev->dev);
@@ -1597,7 +1592,7 @@ void mdss_fb_update_backlight(struct msm_fb_data_type *mfd)
u32 temp;
bool bl_notify = false;
- if (!mfd->unset_bl_level)
+ if (mfd->unset_bl_level == U32_MAX)
return;
mutex_lock(&mfd->bl_lock);
if (!mfd->allow_bl_update) {
@@ -1808,7 +1803,8 @@ static int mdss_fb_blank_unblank(struct msm_fb_data_type *mfd)
*/
if (IS_CALIB_MODE_BL(mfd))
mdss_fb_set_backlight(mfd, mfd->calib_mode_bl);
- else if (!mfd->panel_info->mipi.post_init_delay)
+ else if ((!mfd->panel_info->mipi.post_init_delay) &&
+ (mfd->unset_bl_level != U32_MAX))
mdss_fb_set_backlight(mfd, mfd->unset_bl_level);
/*
diff --git a/drivers/video/fbdev/msm/mdss_fb.h b/drivers/video/fbdev/msm/mdss_fb.h
index 56997e40d244..2eb6c6456f29 100644
--- a/drivers/video/fbdev/msm/mdss_fb.h
+++ b/drivers/video/fbdev/msm/mdss_fb.h
@@ -299,7 +299,6 @@ struct msm_fb_data_type {
u32 ad_bl_level;
u32 bl_level;
u32 bl_scale;
- u32 bl_min_lvl;
u32 unset_bl_level;
bool allow_bl_update;
u32 bl_level_scaled;
diff --git a/drivers/video/fbdev/msm/mdss_hdcp_1x.c b/drivers/video/fbdev/msm/mdss_hdcp_1x.c
index a8182c2f0e76..44a3ad993909 100644
--- a/drivers/video/fbdev/msm/mdss_hdcp_1x.c
+++ b/drivers/video/fbdev/msm/mdss_hdcp_1x.c
@@ -10,13 +10,14 @@
* GNU General Public License for more details.
*/
+#define pr_fmt(fmt) "%s: " fmt, __func__
+
#include <linux/io.h>
#include <linux/types.h>
#include <linux/delay.h>
#include <linux/slab.h>
#include <linux/stat.h>
#include <linux/iopoll.h>
-#include <soc/qcom/scm.h>
#include <linux/hdcp_qseecom.h>
#include "mdss_hdcp.h"
#include "mdss_fb.h"
@@ -51,10 +52,6 @@
#define HDCP_POLL_SLEEP_US (20 * 1000)
#define HDCP_POLL_TIMEOUT_US (HDCP_POLL_SLEEP_US * 100)
-#define reg_set_data(x) \
- (hdcp_ctrl->init_data.sec_access ? reg_set->sec_data##x : \
- reg_set->data##x)
-
struct hdcp_sink_addr {
char *name;
u32 addr;
@@ -72,6 +69,7 @@ struct hdcp_sink_addr_map {
struct hdcp_sink_addr bksv;
struct hdcp_sink_addr r0;
struct hdcp_sink_addr bstatus;
+ struct hdcp_sink_addr cp_irq_status;
struct hdcp_sink_addr ksv_fifo;
struct hdcp_sink_addr v_h0;
struct hdcp_sink_addr v_h1;
@@ -82,7 +80,6 @@ struct hdcp_sink_addr_map {
/* addresses to write to sink */
struct hdcp_sink_addr an;
struct hdcp_sink_addr aksv;
- struct hdcp_sink_addr rep;
};
struct hdcp_int_set {
@@ -125,23 +122,15 @@ struct hdcp_reg_set {
u32 aksv_msb;
u32 entropy_ctrl0;
u32 entropy_ctrl1;
- u32 sha_ctrl;
u32 sec_sha_ctrl;
+ u32 sec_sha_data;
u32 sha_status;
- u32 data0;
- u32 data1;
u32 data2_0;
u32 data3;
u32 data4;
u32 data5;
u32 data6;
- u32 data7;
- u32 data8;
- u32 data9;
- u32 data10;
- u32 data11;
- u32 data12;
u32 sec_data0;
u32 sec_data1;
@@ -154,20 +143,19 @@ struct hdcp_reg_set {
u32 reset;
u32 reset_bit;
+
+ u32 repeater;
};
#define HDCP_REG_SET_CLIENT_HDMI \
{HDMI_HDCP_LINK0_STATUS, 28, 24, 20, HDMI_HDCP_CTRL, \
HDMI_HDCP_SW_LOWER_AKSV, HDMI_HDCP_SW_UPPER_AKSV, \
HDMI_HDCP_ENTROPY_CTRL0, HDMI_HDCP_ENTROPY_CTRL1, \
- HDMI_HDCP_SHA_CTRL, HDCP_SEC_TZ_HV_HLOS_HDCP_SHA_CTRL, \
- HDMI_HDCP_SHA_STATUS, HDMI_HDCP_RCVPORT_DATA0, \
- HDMI_HDCP_RCVPORT_DATA1, HDMI_HDCP_RCVPORT_DATA2_0, \
+ HDCP_SEC_TZ_HV_HLOS_HDCP_SHA_CTRL, \
+ HDCP_SEC_TZ_HV_HLOS_HDCP_SHA_DATA, \
+ HDMI_HDCP_SHA_STATUS, HDMI_HDCP_RCVPORT_DATA2_0, \
HDMI_HDCP_RCVPORT_DATA3, HDMI_HDCP_RCVPORT_DATA4, \
HDMI_HDCP_RCVPORT_DATA5, HDMI_HDCP_RCVPORT_DATA6, \
- HDMI_HDCP_RCVPORT_DATA7, HDMI_HDCP_RCVPORT_DATA8, \
- HDMI_HDCP_RCVPORT_DATA9, HDMI_HDCP_RCVPORT_DATA10, \
- HDMI_HDCP_RCVPORT_DATA11, HDMI_HDCP_RCVPORT_DATA12, \
HDCP_SEC_TZ_HV_HLOS_HDCP_RCVPORT_DATA0, \
HDCP_SEC_TZ_HV_HLOS_HDCP_RCVPORT_DATA1, \
HDCP_SEC_TZ_HV_HLOS_HDCP_RCVPORT_DATA7, \
@@ -176,17 +164,17 @@ struct hdcp_reg_set {
HDCP_SEC_TZ_HV_HLOS_HDCP_RCVPORT_DATA10, \
HDCP_SEC_TZ_HV_HLOS_HDCP_RCVPORT_DATA11, \
HDCP_SEC_TZ_HV_HLOS_HDCP_RCVPORT_DATA12, \
- HDMI_HDCP_RESET, BIT(0)}
+ HDMI_HDCP_RESET, BIT(0), BIT(6)}
#define HDCP_REG_SET_CLIENT_DP \
{DP_HDCP_STATUS, 16, 14, 13, DP_HDCP_CTRL, \
DP_HDCP_SW_LOWER_AKSV, DP_HDCP_SW_UPPER_AKSV, \
DP_HDCP_ENTROPY_CTRL0, DP_HDCP_ENTROPY_CTRL1, \
- 0, HDCP_SEC_DP_TZ_HV_HLOS_HDCP_SHA_CTRL, \
- DP_HDCP_SHA_STATUS, 0, 0, DP_HDCP_RCVPORT_DATA2_0, \
+ HDCP_SEC_DP_TZ_HV_HLOS_HDCP_SHA_CTRL, \
+ HDCP_SEC_DP_TZ_HV_HLOS_HDCP_SHA_DATA, \
+ DP_HDCP_SHA_STATUS, DP_HDCP_RCVPORT_DATA2_0, \
DP_HDCP_RCVPORT_DATA3, DP_HDCP_RCVPORT_DATA4, \
DP_HDCP_RCVPORT_DATA5, DP_HDCP_RCVPORT_DATA6, \
- 0, 0, 0, 0, 0, 0, \
HDCP_SEC_DP_TZ_HV_HLOS_HDCP_RCVPORT_DATA0, \
HDCP_SEC_DP_TZ_HV_HLOS_HDCP_RCVPORT_DATA1, \
HDCP_SEC_DP_TZ_HV_HLOS_HDCP_RCVPORT_DATA7, \
@@ -195,21 +183,21 @@ struct hdcp_reg_set {
HDCP_SEC_DP_TZ_HV_HLOS_HDCP_RCVPORT_DATA10, \
HDCP_SEC_DP_TZ_HV_HLOS_HDCP_RCVPORT_DATA11, \
HDCP_SEC_DP_TZ_HV_HLOS_HDCP_RCVPORT_DATA12, \
- DP_SW_RESET, BIT(1)}
+ DP_SW_RESET, BIT(1), BIT(1)}
#define HDCP_HDMI_SINK_ADDR_MAP \
{{"bcaps", 0x40, 1}, {"bksv", 0x00, 5}, {"r0'", 0x08, 2}, \
- {"bstatus", 0x41, 2}, {"ksv-fifo", 0x43, 0}, {"v_h0", 0x20, 4}, \
- {"v_h1", 0x24, 4}, {"v_h2", 0x28, 4}, {"v_h3", 0x2c, 4}, \
- {"v_h4", 0x30, 4}, {"an", 0x18, 8}, {"aksv", 0x10, 5}, \
- {"repeater", 0x00, 0} }
+ {"bstatus", 0x41, 2}, {"??", 0x0, 0}, {"ksv-fifo", 0x43, 0}, \
+ {"v_h0", 0x20, 4}, {"v_h1", 0x24, 4}, {"v_h2", 0x28, 4}, \
+ {"v_h3", 0x2c, 4}, {"v_h4", 0x30, 4}, {"an", 0x18, 8}, \
+ {"aksv", 0x10, 5} }
#define HDCP_DP_SINK_ADDR_MAP \
{{"bcaps", 0x68028, 1}, {"bksv", 0x68000, 5}, {"r0'", 0x68005, 2}, \
- {"bstatus", 0x6802A, 2}, {"ksv-fifo", 0x6802A, 0}, \
- {"v_h0", 0x68014, 4}, {"v_h1", 0x68018, 4}, {"v_h2", 0x6801C, 4}, \
- {"v_h3", 0x68020, 4}, {"v_h4", 0x68024, 4}, {"an", 0x6800C, 8}, \
- {"aksv", 0x68007, 5}, {"repeater", 0x68028, 1} }
+ {"binfo", 0x6802A, 2}, {"cp_irq_status", 0x68029, 2}, \
+ {"ksv-fifo", 0x6802C, 0}, {"v_h0", 0x68014, 4}, {"v_h1", 0x68018, 4}, \
+ {"v_h2", 0x6801C, 4}, {"v_h3", 0x68020, 4}, {"v_h4", 0x68024, 4}, \
+ {"an", 0x6800C, 8}, {"aksv", 0x68007, 5} }
#define HDCP_HDMI_INT_SET \
{HDMI_HDCP_INT_CTRL, \
@@ -226,18 +214,22 @@ struct hdcp_reg_set {
struct hdcp_1x_ctrl {
u32 auth_retries;
u32 tp_msgid;
- u32 tz_hdcp;
+ bool sink_r0_ready;
+ bool reauth;
enum hdcp_states hdcp_state;
struct HDCP_V2V1_MSG_TOPOLOGY cached_tp;
struct HDCP_V2V1_MSG_TOPOLOGY current_tp;
struct delayed_work hdcp_auth_work;
struct work_struct hdcp_int_work;
struct completion r0_checked;
+ struct completion sink_r0_available;
+ struct completion sink_rep_ready;
struct hdcp_init_data init_data;
struct hdcp_ops *ops;
struct hdcp_reg_set reg_set;
struct hdcp_int_set int_set;
struct hdcp_sink_addr_map sink_addr;
+ struct workqueue_struct *workq;
};
const char *hdcp_state_name(enum hdcp_states hdcp_state)
@@ -269,7 +261,7 @@ static void reset_hdcp_ddc_failures(struct hdcp_1x_ctrl *hdcp_ctrl)
struct dss_io_data *io;
if (!hdcp_ctrl || !hdcp_ctrl->init_data.core_io) {
- DEV_ERR("%s: invalid input\n", __func__);
+ pr_err("invalid input\n");
return;
}
@@ -279,8 +271,8 @@ static void reset_hdcp_ddc_failures(struct hdcp_1x_ctrl *hdcp_ctrl)
hdcp_ddc_status = DSS_REG_R(io, HDMI_HDCP_DDC_STATUS);
failure = (hdcp_ddc_status >> 16) & 0x1;
nack0 = (hdcp_ddc_status >> 14) & 0x1;
- DEV_DBG("%s: %s: On Entry: HDCP_DDC_STATUS=0x%x, FAIL=%d, NACK0=%d\n",
- __func__, HDCP_STATE_NAME, hdcp_ddc_status, failure, nack0);
+ pr_debug("%s: On Entry: HDCP_DDC_STATUS=0x%x, FAIL=%d, NACK0=%d\n",
+ HDCP_STATE_NAME, hdcp_ddc_status, failure, nack0);
if (failure == 0x1) {
/*
@@ -290,8 +282,8 @@ static void reset_hdcp_ddc_failures(struct hdcp_1x_ctrl *hdcp_ctrl)
* matches HDCP_DDC_RETRY_CNT.
* Failure occured, let's clear it.
*/
- DEV_DBG("%s: %s: DDC failure detected.HDCP_DDC_STATUS=0x%08x\n",
- __func__, HDCP_STATE_NAME, hdcp_ddc_status);
+ pr_debug("%s: DDC failure detected.HDCP_DDC_STATUS=0x%08x\n",
+ HDCP_STATE_NAME, hdcp_ddc_status);
/* First, Disable DDC */
DSS_REG_W(io, HDMI_HDCP_DDC_CTRL_0, BIT(0));
@@ -305,18 +297,18 @@ static void reset_hdcp_ddc_failures(struct hdcp_1x_ctrl *hdcp_ctrl)
hdcp_ddc_status = DSS_REG_R(io, HDMI_HDCP_DDC_STATUS);
hdcp_ddc_status = (hdcp_ddc_status >> 16) & BIT(0);
if (hdcp_ddc_status == 0x0)
- DEV_DBG("%s: %s: HDCP DDC Failure cleared\n", __func__,
+ pr_debug("%s: HDCP DDC Failure cleared\n",
HDCP_STATE_NAME);
else
- DEV_WARN("%s: %s: Unable to clear HDCP DDC Failure",
- __func__, HDCP_STATE_NAME);
+ pr_debug("%s: Unable to clear HDCP DDC Failure",
+ HDCP_STATE_NAME);
/* Re-Enable HDCP DDC */
DSS_REG_W(io, HDMI_HDCP_DDC_CTRL_0, 0);
}
if (nack0 == 0x1) {
- DEV_DBG("%s: %s: Before: HDMI_DDC_SW_STATUS=0x%08x\n", __func__,
+ pr_debug("%s: Before: HDMI_DDC_SW_STATUS=0x%08x\n",
HDCP_STATE_NAME, DSS_REG_R(io, HDMI_DDC_SW_STATUS));
/* Reset HDMI DDC software status */
DSS_REG_W_ND(io, HDMI_DDC_CTRL,
@@ -331,7 +323,7 @@ static void reset_hdcp_ddc_failures(struct hdcp_1x_ctrl *hdcp_ctrl)
msleep(20);
DSS_REG_W_ND(io, HDMI_DDC_CTRL,
DSS_REG_R(io, HDMI_DDC_CTRL) & ~BIT(1));
- DEV_DBG("%s: %s: After: HDMI_DDC_SW_STATUS=0x%08x\n", __func__,
+ pr_debug("%s: After: HDMI_DDC_SW_STATUS=0x%08x\n",
HDCP_STATE_NAME, DSS_REG_R(io, HDMI_DDC_SW_STATUS));
}
@@ -339,8 +331,8 @@ static void reset_hdcp_ddc_failures(struct hdcp_1x_ctrl *hdcp_ctrl)
failure = (hdcp_ddc_status >> 16) & BIT(0);
nack0 = (hdcp_ddc_status >> 14) & BIT(0);
- DEV_DBG("%s: %s: On Exit: HDCP_DDC_STATUS=0x%x, FAIL=%d, NACK0=%d\n",
- __func__, HDCP_STATE_NAME, hdcp_ddc_status, failure, nack0);
+ pr_debug("%s: On Exit: HDCP_DDC_STATUS=0x%x, FAIL=%d, NACK0=%d\n",
+ HDCP_STATE_NAME, hdcp_ddc_status, failure, nack0);
} /* reset_hdcp_ddc_failures */
static void hdcp_1x_hw_ddc_clean(struct hdcp_1x_ctrl *hdcp_ctrl)
@@ -353,14 +345,14 @@ static void hdcp_1x_hw_ddc_clean(struct hdcp_1x_ctrl *hdcp_ctrl)
u32 timeout_count;
if (!hdcp_ctrl || !hdcp_ctrl->init_data.core_io) {
- DEV_ERR("%s: invalid input\n", __func__);
+ pr_err("invalid input\n");
return;
}
io = hdcp_ctrl->init_data.core_io;
if (!io->base) {
- DEV_ERR("%s: core io not inititalized\n", __func__);
- return;
+ pr_err("core io not inititalized\n");
+ return;
}
/* Wait to be clean on DDC HW engine */
@@ -382,49 +374,16 @@ static void hdcp_1x_hw_ddc_clean(struct hdcp_1x_ctrl *hdcp_ctrl)
ddc_hw_not_ready = xfer_not_done || hw_not_done;
- DEV_DBG("%s: %s: timeout count(%d): ddc hw%sready\n",
- __func__, HDCP_STATE_NAME, timeout_count,
+ pr_debug("%s: timeout count(%d): ddc hw%sready\n",
+ HDCP_STATE_NAME, timeout_count,
ddc_hw_not_ready ? " not " : " ");
- DEV_DBG("hdcp_ddc_status[0x%x], ddc_hw_status[0x%x]\n",
+ pr_debug("hdcp_ddc_status[0x%x], ddc_hw_status[0x%x]\n",
hdcp_ddc_status, ddc_hw_status);
if (ddc_hw_not_ready)
msleep(20);
} while (ddc_hw_not_ready && --timeout_count);
} /* hdcp_1x_hw_ddc_clean */
-static int hdcp_scm_call(struct scm_hdcp_req *req, u32 *resp)
-{
- int ret = 0;
-
- if (!is_scm_armv8()) {
- ret = scm_call(SCM_SVC_HDCP, SCM_CMD_HDCP, (void *) req,
- SCM_HDCP_MAX_REG * sizeof(struct scm_hdcp_req),
- &resp, sizeof(*resp));
- } else {
- struct scm_desc desc;
-
- desc.args[0] = req[0].addr;
- desc.args[1] = req[0].val;
- desc.args[2] = req[1].addr;
- desc.args[3] = req[1].val;
- desc.args[4] = req[2].addr;
- desc.args[5] = req[2].val;
- desc.args[6] = req[3].addr;
- desc.args[7] = req[3].val;
- desc.args[8] = req[4].addr;
- desc.args[9] = req[4].val;
- desc.arginfo = SCM_ARGS(10);
-
- ret = scm_call2(SCM_SIP_FNID(SCM_SVC_HDCP, SCM_CMD_HDCP),
- &desc);
- *resp = desc.ret[0];
- if (ret)
- return ret;
- }
-
- return ret;
-}
-
static int hdcp_1x_load_keys(void *input)
{
int rc = 0;
@@ -440,14 +399,14 @@ static int hdcp_1x_load_keys(void *input)
if (!hdcp_ctrl || !hdcp_ctrl->init_data.core_io ||
!hdcp_ctrl->init_data.qfprom_io) {
- DEV_ERR("%s: invalid input\n", __func__);
+ pr_err("invalid input\n");
rc = -EINVAL;
goto end;
}
if ((HDCP_STATE_INACTIVE != hdcp_ctrl->hdcp_state) &&
(HDCP_STATE_AUTH_FAIL != hdcp_ctrl->hdcp_state)) {
- DEV_ERR("%s: %s: invalid state. returning\n", __func__,
+ pr_err("%s: invalid state. returning\n",
HDCP_STATE_NAME);
rc = -EINVAL;
goto end;
@@ -470,7 +429,7 @@ static int hdcp_1x_load_keys(void *input)
if (use_sw_keys) {
if (hdcp1_set_keys(&aksv_msb, &aksv_lsb)) {
- pr_err("%s: setting hdcp SW keys failed\n", __func__);
+ pr_err("setting hdcp SW keys failed\n");
rc = -EINVAL;
goto end;
}
@@ -488,7 +447,7 @@ static int hdcp_1x_load_keys(void *input)
aksv_msb = DSS_REG_R(qfprom_io, ksv_msb_addr);
}
- DEV_DBG("%s: %s: AKSV=%02x%08x\n", __func__, HDCP_STATE_NAME,
+ pr_debug("%s: AKSV=%02x%08x\n", HDCP_STATE_NAME,
aksv_msb, aksv_lsb);
aksv[0] = aksv_lsb & 0xFF;
@@ -499,7 +458,7 @@ static int hdcp_1x_load_keys(void *input)
/* check there are 20 ones in AKSV */
if (hdcp_1x_count_one(aksv, 5) != 20) {
- DEV_ERR("%s: AKSV bit count failed\n", __func__);
+ pr_err("AKSV bit count failed\n");
rc = -EINVAL;
goto end;
}
@@ -527,6 +486,7 @@ static int hdcp_1x_read(struct hdcp_1x_ctrl *hdcp_ctrl,
u8 *buf, bool realign)
{
u32 rc = 0;
+ int const max_size = 15, edid_read_delay_us = 20;
struct hdmi_tx_ddc_data ddc_data;
if (hdcp_ctrl->init_data.client_id == HDCP_CLIENT_HDMI) {
@@ -546,21 +506,34 @@ static int hdcp_1x_read(struct hdcp_1x_ctrl *hdcp_ctrl,
rc = hdmi_ddc_read(hdcp_ctrl->init_data.ddc_ctrl);
if (rc)
- DEV_ERR("%s: %s: %s read failed\n", __func__,
+ pr_err("%s: %s read failed\n",
HDCP_STATE_NAME, sink->name);
} else if (IS_ENABLED(CONFIG_FB_MSM_MDSS_DP_PANEL) &&
hdcp_ctrl->init_data.client_id == HDCP_CLIENT_DP) {
- struct edp_cmd cmd = {0};
+ int size = sink->len;
- cmd.read = 1;
- cmd.addr = sink->addr;
- cmd.out_buf = buf;
- cmd.len = sink->len;
+ do {
+ struct edp_cmd cmd = {0};
+ int read_size;
- rc = dp_aux_read(hdcp_ctrl->init_data.cb_data, &cmd);
- if (rc)
- DEV_ERR("%s: %s: %s read failed\n", __func__,
- HDCP_STATE_NAME, sink->name);
+ read_size = min(size, max_size);
+
+ cmd.read = 1;
+ cmd.addr = sink->addr;
+ cmd.len = read_size;
+ cmd.out_buf = buf;
+
+ rc = dp_aux_read(hdcp_ctrl->init_data.cb_data, &cmd);
+ if (rc) {
+ pr_err("Aux read failed\n");
+ break;
+ }
+
+ /* give sink/repeater time to ready edid */
+ msleep(edid_read_delay_us);
+ buf += read_size;
+ size -= read_size;
+ } while (size > 0);
}
return rc;
@@ -584,7 +557,7 @@ static int hdcp_1x_write(struct hdcp_1x_ctrl *hdcp_ctrl,
rc = hdmi_ddc_write(hdcp_ctrl->init_data.ddc_ctrl);
if (rc)
- DEV_ERR("%s: %s: %s write failed\n", __func__,
+ pr_err("%s: %s write failed\n",
HDCP_STATE_NAME, sink->name);
} else if (IS_ENABLED(CONFIG_FB_MSM_MDSS_DP_PANEL) &&
hdcp_ctrl->init_data.client_id == HDCP_CLIENT_DP) {
@@ -596,7 +569,7 @@ static int hdcp_1x_write(struct hdcp_1x_ctrl *hdcp_ctrl,
rc = dp_aux_write(hdcp_ctrl->init_data.cb_data, &cmd);
if (rc)
- DEV_ERR("%s: %s: %s read failed\n", __func__,
+ pr_err("%s: %s read failed\n",
HDCP_STATE_NAME, sink->name);
}
@@ -621,28 +594,26 @@ static void hdcp_1x_enable_interrupts(struct hdcp_1x_ctrl *hdcp_ctrl)
static int hdcp_1x_authentication_part1(struct hdcp_1x_ctrl *hdcp_ctrl)
{
- int rc;
+ int rc, r0_retry = 3;
+ u32 const r0_read_delay_us = 1;
+ u32 const r0_read_timeout_us = r0_read_delay_us * 10;
u32 link0_aksv_0, link0_aksv_1;
u32 link0_bksv_0, link0_bksv_1;
u32 link0_an_0, link0_an_1;
u32 timeout_count;
- bool is_match;
struct dss_io_data *io;
struct dss_io_data *hdcp_io;
struct hdcp_reg_set *reg_set;
u8 aksv[5], *bksv = NULL;
u8 an[8];
u8 bcaps = 0;
- u32 link0_status;
+ u32 link0_status = 0;
u8 buf[0xFF];
- struct scm_hdcp_req scm_buf[SCM_HDCP_MAX_REG];
u32 phy_addr;
- u32 ret = 0;
- u32 resp = 0;
if (!hdcp_ctrl || !hdcp_ctrl->init_data.core_io ||
!hdcp_ctrl->init_data.qfprom_io) {
- DEV_ERR("%s: invalid input\n", __func__);
+ pr_err("invalid input\n");
rc = -EINVAL;
goto error;
}
@@ -654,7 +625,7 @@ static int hdcp_1x_authentication_part1(struct hdcp_1x_ctrl *hdcp_ctrl)
reg_set = &hdcp_ctrl->reg_set;
if (HDCP_STATE_AUTHENTICATING != hdcp_ctrl->hdcp_state) {
- DEV_ERR("%s: %s: invalid state. returning\n", __func__,
+ pr_err("%s: invalid state. returning\n",
HDCP_STATE_NAME);
rc = -EINVAL;
goto error;
@@ -663,35 +634,17 @@ static int hdcp_1x_authentication_part1(struct hdcp_1x_ctrl *hdcp_ctrl)
rc = hdcp_1x_read(hdcp_ctrl, &hdcp_ctrl->sink_addr.bcaps,
&bcaps, false);
if (IS_ERR_VALUE(rc)) {
- DEV_ERR("%s: error reading bcaps\n", __func__);
+ pr_err("error reading bcaps\n");
goto error;
}
hdcp_1x_enable_interrupts(hdcp_ctrl);
- /* receiver (0), repeater (1) */
- hdcp_ctrl->current_tp.ds_type =
- (bcaps & BIT(6)) >> 6 ? DS_REPEATER : DS_RECEIVER;
+ hdcp_ctrl->current_tp.ds_type = bcaps & reg_set->repeater ?
+ DS_REPEATER : DS_RECEIVER;
/* Write BCAPS to the hardware */
- if (hdcp_ctrl->tz_hdcp) {
- memset(scm_buf, 0x00, sizeof(scm_buf));
-
- scm_buf[0].addr = phy_addr + reg_set->data12;
- scm_buf[0].val = bcaps;
-
- ret = hdcp_scm_call(scm_buf, &resp);
- if (ret || resp) {
- DEV_ERR("%s: error: scm_call ret = %d, resp = %d\n",
- __func__, ret, resp);
- rc = -EINVAL;
- goto error;
- }
- } else if (hdcp_ctrl->init_data.sec_access) {
- DSS_REG_W(hdcp_io, reg_set->sec_data12, bcaps);
- } else {
- DSS_REG_W(io, reg_set->data12, bcaps);
- }
+ DSS_REG_W(hdcp_io, reg_set->sec_data12, bcaps);
/* Wait for HDCP keys to be checked and validated */
rc = readl_poll_timeout(io->base + reg_set->status, link0_status,
@@ -699,7 +652,7 @@ static int hdcp_1x_authentication_part1(struct hdcp_1x_ctrl *hdcp_ctrl)
== HDCP_KEYS_STATE_VALID,
HDCP_POLL_SLEEP_US, HDCP_POLL_TIMEOUT_US);
if (IS_ERR_VALUE(rc)) {
- DEV_ERR("%s: key not ready\n", __func__);
+ pr_err("key not ready\n");
goto error;
}
@@ -714,7 +667,7 @@ static int hdcp_1x_authentication_part1(struct hdcp_1x_ctrl *hdcp_ctrl)
(link0_status & (BIT(8) | BIT(9))),
HDCP_POLL_SLEEP_US, HDCP_POLL_TIMEOUT_US);
if (IS_ERR_VALUE(rc)) {
- DEV_ERR("%s: An not ready\n", __func__);
+ pr_err("An not ready\n");
goto error;
}
@@ -757,30 +710,18 @@ static int hdcp_1x_authentication_part1(struct hdcp_1x_ctrl *hdcp_ctrl)
an[6] = (link0_an_1 >> 16) & 0xFF;
an[7] = (link0_an_1 >> 24) & 0xFF;
- rc = hdcp_1x_write(hdcp_ctrl, &hdcp_ctrl->sink_addr.an, an);
- if (IS_ERR_VALUE(rc)) {
- DEV_ERR("%s: error writing an to sink\n", __func__);
- goto error;
- }
-
- rc = hdcp_1x_write(hdcp_ctrl, &hdcp_ctrl->sink_addr.aksv, aksv);
- if (IS_ERR_VALUE(rc)) {
- DEV_ERR("%s: error writing aksv to sink\n", __func__);
- goto error;
- }
-
rc = hdcp_1x_read(hdcp_ctrl, &hdcp_ctrl->sink_addr.bksv, bksv, false);
if (IS_ERR_VALUE(rc)) {
- DEV_ERR("%s: error reading bksv from sink\n", __func__);
+ pr_err("error reading bksv from sink\n");
goto error;
}
/* check there are 20 ones in BKSV */
if (hdcp_1x_count_one(bksv, 5) != 20) {
- DEV_ERR("%s: %s: BKSV doesn't have 20 1's and 20 0's\n",
- __func__, HDCP_STATE_NAME);
- DEV_ERR("%s: %s: BKSV chk fail. BKSV=%02x%02x%02x%02x%02x\n",
- __func__, HDCP_STATE_NAME, bksv[4], bksv[3], bksv[2],
+ pr_err("%s: BKSV doesn't have 20 1's and 20 0's\n",
+ HDCP_STATE_NAME);
+ pr_err("%s: BKSV chk fail. BKSV=%02x%02x%02x%02x%02x\n",
+ HDCP_STATE_NAME, bksv[4], bksv[3], bksv[2],
bksv[1], bksv[0]);
rc = -EINVAL;
goto error;
@@ -791,90 +732,87 @@ static int hdcp_1x_authentication_part1(struct hdcp_1x_ctrl *hdcp_ctrl)
link0_bksv_0 = (link0_bksv_0 << 8) | bksv[1];
link0_bksv_0 = (link0_bksv_0 << 8) | bksv[0];
link0_bksv_1 = bksv[4];
- DEV_DBG("%s: %s: BKSV=%02x%08x\n", __func__, HDCP_STATE_NAME,
+ pr_debug("%s: BKSV=%02x%08x\n", HDCP_STATE_NAME,
link0_bksv_1, link0_bksv_0);
- if (hdcp_ctrl->tz_hdcp) {
- memset(scm_buf, 0x00, sizeof(scm_buf));
+ DSS_REG_W(hdcp_io, reg_set->sec_data0, link0_bksv_0);
+ DSS_REG_W(hdcp_io, reg_set->sec_data1, link0_bksv_1);
- scm_buf[0].addr = phy_addr + reg_set->data0;
- scm_buf[0].val = link0_bksv_0;
- scm_buf[1].addr = phy_addr + reg_set->data1;
- scm_buf[1].val = link0_bksv_1;
+ /* Wait for HDCP R0 computation to be completed */
+ rc = readl_poll_timeout(io->base + reg_set->status, link0_status,
+ link0_status & BIT(reg_set->r0_offset),
+ HDCP_POLL_SLEEP_US, HDCP_POLL_TIMEOUT_US);
+ if (IS_ERR_VALUE(rc)) {
+ pr_err("R0 not ready\n");
+ goto error;
+ }
- ret = hdcp_scm_call(scm_buf, &resp);
+ rc = hdcp_1x_write(hdcp_ctrl, &hdcp_ctrl->sink_addr.an, an);
+ if (IS_ERR_VALUE(rc)) {
+ pr_err("error writing an to sink\n");
+ goto error;
+ }
- if (ret || resp) {
- DEV_ERR("%s: error: scm_call ret = %d, resp = %d\n",
- __func__, ret, resp);
- rc = -EINVAL;
- goto error;
- }
- } else if (hdcp_ctrl->init_data.sec_access) {
- DSS_REG_W(hdcp_io, reg_set->sec_data0, link0_bksv_0);
- DSS_REG_W(hdcp_io, reg_set->sec_data1, link0_bksv_1);
- } else {
- DSS_REG_W(io, reg_set->data0, link0_bksv_0);
- DSS_REG_W(io, reg_set->data1, link0_bksv_1);
+ rc = hdcp_1x_write(hdcp_ctrl, &hdcp_ctrl->sink_addr.aksv, aksv);
+ if (IS_ERR_VALUE(rc)) {
+ pr_err("error writing aksv to sink\n");
+ goto error;
}
/*
* HDCP Compliace Test case 1A-01:
* Wait here at least 100ms before reading R0'
*/
- msleep(125);
+ if (hdcp_ctrl->init_data.client_id == HDCP_CLIENT_HDMI) {
+ msleep(125);
+ } else {
+ if (!hdcp_ctrl->sink_r0_ready) {
+ reinit_completion(&hdcp_ctrl->sink_r0_available);
+ timeout_count = wait_for_completion_timeout(
+ &hdcp_ctrl->sink_r0_available, HZ / 2);
- /* Wait for HDCP R0 computation to be completed */
- rc = readl_poll_timeout(io->base + reg_set->status, link0_status,
- link0_status & BIT(reg_set->r0_offset),
- HDCP_POLL_SLEEP_US, HDCP_POLL_TIMEOUT_US);
- if (IS_ERR_VALUE(rc)) {
- DEV_ERR("%s: R0 not ready\n", __func__);
- goto error;
+ if (!timeout_count || hdcp_ctrl->reauth) {
+ pr_err("sink R0 not ready\n");
+ rc = -EINVAL;
+ goto error;
+ }
+ }
}
-
+r0_read_retry:
memset(buf, 0, sizeof(buf));
rc = hdcp_1x_read(hdcp_ctrl, &hdcp_ctrl->sink_addr.r0, buf, false);
if (IS_ERR_VALUE(rc)) {
- DEV_ERR("%s: error reading R0' from sink\n", __func__);
+ pr_err("error reading R0' from sink\n");
goto error;
}
- DEV_DBG("%s: %s: R0'=%02x%02x\n", __func__, HDCP_STATE_NAME,
+ pr_debug("%s: R0'=%02x%02x\n", HDCP_STATE_NAME,
buf[1], buf[0]);
/* Write R0' to HDCP registers and check to see if it is a match */
- reinit_completion(&hdcp_ctrl->r0_checked);
DSS_REG_W(io, reg_set->data2_0, (((u32)buf[1]) << 8) | buf[0]);
- timeout_count = wait_for_completion_timeout(
- &hdcp_ctrl->r0_checked, HZ*2);
- link0_status = DSS_REG_R(io, reg_set->status);
- is_match = link0_status & BIT(12);
- if (!is_match) {
- DEV_DBG("%s: %s: Link0_Status=0x%08x\n", __func__,
- HDCP_STATE_NAME, link0_status);
- if (!timeout_count) {
- DEV_ERR("%s: %s: Timeout. No R0 mtch. R0'=%02x%02x\n",
- __func__, HDCP_STATE_NAME, buf[1], buf[0]);
- rc = -ETIMEDOUT;
- goto error;
- } else {
- DEV_ERR("%s: %s: R0 mismatch. R0'=%02x%02x\n", __func__,
- HDCP_STATE_NAME, buf[1], buf[0]);
- rc = -EINVAL;
- goto error;
- }
- } else {
- DEV_DBG("%s: %s: R0 matches\n", __func__, HDCP_STATE_NAME);
+ rc = readl_poll_timeout(io->base + reg_set->status, link0_status,
+ link0_status & BIT(12),
+ r0_read_delay_us, r0_read_timeout_us);
+ if (IS_ERR_VALUE(rc)) {
+ pr_err("R0 mismatch\n");
+ if (--r0_retry)
+ goto r0_read_retry;
+
+ goto error;
}
+ hdcp1_set_enc(true);
+
+ pr_debug("%s: Authentication Part I successful\n",
+ hdcp_ctrl ? HDCP_STATE_NAME : "???");
+
+ return 0;
+
error:
- if (rc)
- DEV_ERR("%s: %s: Authentication Part I failed\n", __func__,
- hdcp_ctrl ? HDCP_STATE_NAME : "???");
- else
- DEV_INFO("%s: %s: Authentication Part I successful\n",
- __func__, HDCP_STATE_NAME);
+ pr_err("%s: Authentication Part I failed\n",
+ hdcp_ctrl ? HDCP_STATE_NAME : "???");
+
return rc;
} /* hdcp_1x_authentication_part1 */
@@ -884,24 +822,16 @@ static int hdcp_1x_set_v_h(struct hdcp_1x_ctrl *hdcp_ctrl,
int rc;
struct dss_io_data *io;
- if (!hdcp_ctrl->tz_hdcp && hdcp_ctrl->init_data.sec_access)
- io = hdcp_ctrl->init_data.hdcp_io;
- else
- io = hdcp_ctrl->init_data.core_io;
+ io = hdcp_ctrl->init_data.hdcp_io;
rc = hdcp_1x_read(hdcp_ctrl, rd->sink, buf, false);
if (IS_ERR_VALUE(rc)) {
- DEV_ERR("%s: error reading %s\n", __func__, rd->sink->name);
+ pr_err("error reading %s\n", rd->sink->name);
goto end;
}
- DEV_DBG("%s: %s: %s: buf[0]=%x, buf[1]=%x, buf[2]=%x, buf[3]=%x\n",
- __func__, HDCP_STATE_NAME, rd->sink->name, buf[0], buf[1],
- buf[2], buf[3]);
-
- if (!hdcp_ctrl->tz_hdcp)
- DSS_REG_W(io, rd->reg_id,
- (buf[3] << 24 | buf[2] << 16 | buf[1] << 8 | buf[0]));
+ DSS_REG_W(io, rd->reg_id,
+ (buf[3] << 24 | buf[2] << 16 | buf[1] << 8 | buf[0]));
end:
return rc;
}
@@ -910,46 +840,27 @@ static int hdcp_1x_transfer_v_h(struct hdcp_1x_ctrl *hdcp_ctrl)
{
int rc = 0;
u8 buf[4];
- struct scm_hdcp_req scm_buf[SCM_HDCP_MAX_REG];
u32 phy_addr;
struct hdcp_reg_set *reg_set = &hdcp_ctrl->reg_set;
struct hdcp_1x_reg_data reg_data[] = {
- {reg_set_data(7), &hdcp_ctrl->sink_addr.v_h0},
- {reg_set_data(8), &hdcp_ctrl->sink_addr.v_h1},
- {reg_set_data(9), &hdcp_ctrl->sink_addr.v_h2},
- {reg_set_data(10), &hdcp_ctrl->sink_addr.v_h3},
- {reg_set_data(11), &hdcp_ctrl->sink_addr.v_h4},
+ {reg_set->sec_data7, &hdcp_ctrl->sink_addr.v_h0},
+ {reg_set->sec_data8, &hdcp_ctrl->sink_addr.v_h1},
+ {reg_set->sec_data9, &hdcp_ctrl->sink_addr.v_h2},
+ {reg_set->sec_data10, &hdcp_ctrl->sink_addr.v_h3},
+ {reg_set->sec_data11, &hdcp_ctrl->sink_addr.v_h4},
};
u32 size = ARRAY_SIZE(reg_data);
- u32 iter = 0, ret = 0, resp = 0;
+ u32 iter = 0;
phy_addr = hdcp_ctrl->init_data.phy_addr;
- memset(scm_buf, 0x00, sizeof(scm_buf));
-
for (iter = 0; iter < size; iter++) {
struct hdcp_1x_reg_data *rd = reg_data + iter;
memset(buf, 0, sizeof(buf));
hdcp_1x_set_v_h(hdcp_ctrl, rd, buf);
-
- if (hdcp_ctrl->tz_hdcp) {
- u32 reg_val = buf[3] << 24 | buf[2] << 16 |
- buf[1] << 8 | buf[0];
-
- scm_buf[iter].addr = phy_addr + reg_data[iter].reg_id;
- scm_buf[iter].val = reg_val;
-
- ret = hdcp_scm_call(scm_buf, &resp);
- if (ret || resp) {
- DEV_ERR("%s: scm err: ret=%d, resp=%d\n",
- __func__, ret, resp);
- rc = -EINVAL;
- goto error;
- }
- }
}
-error:
+
return rc;
}
@@ -966,14 +877,12 @@ static int hdcp_1x_authentication_part2(struct hdcp_1x_ctrl *hdcp_ctrl)
u32 ksv_bytes;
struct dss_io_data *io;
struct hdcp_reg_set *reg_set;
- struct scm_hdcp_req scm_buf[SCM_HDCP_MAX_REG];
u32 phy_addr;
- u32 ret = 0;
- u32 resp = 0;
u32 ksv_read_retry = 20;
+ int v_retry = 3;
if (!hdcp_ctrl || !hdcp_ctrl->init_data.core_io) {
- DEV_ERR("%s: invalid input\n", __func__);
+ pr_err("invalid input\n");
rc = -EINVAL;
goto error;
}
@@ -982,7 +891,7 @@ static int hdcp_1x_authentication_part2(struct hdcp_1x_ctrl *hdcp_ctrl)
reg_set = &hdcp_ctrl->reg_set;
if (HDCP_STATE_AUTHENTICATING != hdcp_ctrl->hdcp_state) {
- DEV_DBG("%s: %s: invalid state. returning\n", __func__,
+ pr_debug("%s: invalid state. returning\n",
HDCP_STATE_NAME);
rc = -EINVAL;
goto error;
@@ -999,64 +908,53 @@ static int hdcp_1x_authentication_part2(struct hdcp_1x_ctrl *hdcp_ctrl)
* Wait until READY bit is set in BCAPS, as per HDCP specifications
* maximum permitted time to check for READY bit is five seconds.
*/
- timeout_count = 50;
- do {
- rc = hdcp_1x_read(hdcp_ctrl, &hdcp_ctrl->sink_addr.bcaps,
- &bcaps, true);
- if (IS_ERR_VALUE(rc)) {
- DEV_ERR("%s: error reading bcaps\n", __func__);
- goto error;
- }
- msleep(100);
- } while (!(bcaps & BIT(5)) && --timeout_count);
-
- rc = hdcp_1x_read(hdcp_ctrl, &hdcp_ctrl->sink_addr.bstatus,
- buf, true);
+ rc = hdcp_1x_read(hdcp_ctrl, &hdcp_ctrl->sink_addr.bcaps, &bcaps, true);
if (IS_ERR_VALUE(rc)) {
- DEV_ERR("%s: error reading bstatus\n", __func__);
+ pr_err("error reading bcaps\n");
goto error;
}
- bstatus = buf[1];
- bstatus = (bstatus << 8) | buf[0];
-
- if (hdcp_ctrl->tz_hdcp) {
- memset(scm_buf, 0x00, sizeof(scm_buf));
+ if (hdcp_ctrl->init_data.client_id == HDCP_CLIENT_HDMI) {
+ timeout_count = 50;
- /* Write BSTATUS and BCAPS to HDCP registers */
- scm_buf[0].addr = phy_addr + reg_set->data12;
- scm_buf[0].val = bcaps | (bstatus << 8);
+ while (!(bcaps & BIT(5)) && --timeout_count) {
+ rc = hdcp_1x_read(hdcp_ctrl,
+ &hdcp_ctrl->sink_addr.bcaps, &bcaps, true);
+ if (IS_ERR_VALUE(rc)) {
+ pr_err("error reading bcaps\n");
+ goto error;
+ }
+ msleep(100);
+ }
+ } else {
+ reinit_completion(&hdcp_ctrl->sink_rep_ready);
+ timeout_count = wait_for_completion_timeout(
+ &hdcp_ctrl->sink_rep_ready, HZ * 5);
- ret = hdcp_scm_call(scm_buf, &resp);
- if (ret || resp) {
- DEV_ERR("%s: error: scm_call ret = %d, resp = %d\n",
- __func__, ret, resp);
+ if (!timeout_count || hdcp_ctrl->reauth) {
+ pr_err("sink not ready with DS KSV list\n");
rc = -EINVAL;
goto error;
}
- } else if (hdcp_ctrl->init_data.sec_access) {
- DSS_REG_W(hdcp_ctrl->init_data.hdcp_io,
- reg_set->sec_data12,
- bcaps | (bstatus << 8));
- } else {
- DSS_REG_W(io, reg_set->data12, bcaps | (bstatus << 8));
}
- down_stream_devices = bstatus & 0x7F;
- if (down_stream_devices == 0) {
- /*
- * If no downstream devices are attached to the repeater
- * then part II fails.
- * todo: The other approach would be to continue PART II.
- */
- DEV_ERR("%s: %s: No downstream devices\n", __func__,
- HDCP_STATE_NAME);
- rc = -EINVAL;
+ rc = hdcp_1x_read(hdcp_ctrl, &hdcp_ctrl->sink_addr.bstatus,
+ buf, true);
+ if (IS_ERR_VALUE(rc)) {
+ pr_err("error reading bstatus\n");
goto error;
}
+ bstatus = buf[1];
+ bstatus = (bstatus << 8) | buf[0];
+
+ down_stream_devices = bstatus & 0x7F;
+
+ pr_debug("DEVICE_COUNT %d\n", down_stream_devices);
+
/* Cascaded repeater depth */
repeater_cascade_depth = (bstatus >> 8) & 0x7;
+ pr_debug("DEPTH %d\n", repeater_cascade_depth);
/*
* HDCP Compliance 1B-05:
@@ -1064,9 +962,10 @@ static int hdcp_1x_authentication_part2(struct hdcp_1x_ctrl *hdcp_ctrl)
* exceed max_devices_connected from bit 7 of Bstatus.
*/
max_devs_exceeded = (bstatus & BIT(7)) >> 7;
+ pr_debug("MAX_DEVS_EXCEEDED %d\n", max_devs_exceeded);
if (max_devs_exceeded == 0x01) {
- DEV_ERR("%s: %s: no. of devs connected exceeds max allowed",
- __func__, HDCP_STATE_NAME);
+ pr_err("%s: no. of devs connected exceeds max allowed",
+ HDCP_STATE_NAME);
rc = -EINVAL;
goto error;
}
@@ -1077,9 +976,11 @@ static int hdcp_1x_authentication_part2(struct hdcp_1x_ctrl *hdcp_ctrl)
* exceed max_cascade_connected from bit 11 of Bstatus.
*/
max_cascade_exceeded = (bstatus & BIT(11)) >> 11;
+ pr_debug("MAX CASCADE_EXCEEDED %d\n",
+ max_cascade_exceeded);
if (max_cascade_exceeded == 0x01) {
- DEV_ERR("%s: %s: no. of cascade conn exceeds max allowed",
- __func__, HDCP_STATE_NAME);
+ pr_err("%s: no. of cascade conn exceeds max allowed",
+ HDCP_STATE_NAME);
rc = -EINVAL;
goto error;
}
@@ -1096,31 +997,39 @@ static int hdcp_1x_authentication_part2(struct hdcp_1x_ctrl *hdcp_ctrl)
ksv_bytes = 5 * down_stream_devices;
hdcp_ctrl->sink_addr.ksv_fifo.len = ksv_bytes;
- do {
+ while (ksv_bytes && --ksv_read_retry) {
rc = hdcp_1x_read(hdcp_ctrl, &hdcp_ctrl->sink_addr.ksv_fifo,
ksv_fifo, false);
if (IS_ERR_VALUE(rc)) {
- DEV_DBG("%s: could not read ksv fifo (%d)\n",
- __func__, ksv_read_retry);
+ pr_debug("could not read ksv fifo (%d)\n",
+ ksv_read_retry);
/*
* HDCP Compliace Test case 1B-01:
* Wait here until all the ksv bytes have been
* read from the KSV FIFO register.
*/
msleep(25);
-
+ } else {
+ break;
}
- } while (rc && --ksv_read_retry);
+ }
if (rc) {
- DEV_ERR("%s: error reading ksv_fifo\n", __func__);
+ pr_err("error reading ksv_fifo\n");
goto error;
}
+ DSS_REG_W(hdcp_ctrl->init_data.hdcp_io,
+ reg_set->sec_data12, bcaps | (bstatus << 8));
+v_read_retry:
rc = hdcp_1x_transfer_v_h(hdcp_ctrl);
if (rc)
goto error;
+ /* do not proceed further if no downstream device connected */
+ if (!ksv_bytes)
+ goto error;
+
/*
* Write KSV FIFO to HDCP_SHA_DATA.
* This is done 1 byte at time starting with the LSB.
@@ -1129,55 +1038,15 @@ static int hdcp_1x_authentication_part2(struct hdcp_1x_ctrl *hdcp_ctrl)
/* First, reset SHA engine */
/* Next, enable SHA engine, SEL=DIGA_HDCP */
- if (hdcp_ctrl->tz_hdcp) {
- memset(scm_buf, 0x00, sizeof(scm_buf));
-
- scm_buf[0].addr = phy_addr + reg_set->sha_ctrl;
- scm_buf[0].val = HDCP_REG_ENABLE;
- scm_buf[1].addr = phy_addr + reg_set->sha_ctrl;
- scm_buf[1].val = HDCP_REG_DISABLE;
-
- ret = hdcp_scm_call(scm_buf, &resp);
- if (ret || resp) {
- DEV_ERR("%s: error: scm_call ret = %d, resp = %d\n",
- __func__, ret, resp);
- rc = -EINVAL;
- goto error;
- }
- } else if (hdcp_ctrl->init_data.sec_access) {
- DSS_REG_W(hdcp_ctrl->init_data.hdcp_io,
- reg_set->sec_sha_ctrl,
- HDCP_REG_ENABLE);
- DSS_REG_W(hdcp_ctrl->init_data.hdcp_io,
- reg_set->sec_sha_ctrl,
- HDCP_REG_DISABLE);
- } else {
- DSS_REG_W(io, reg_set->sha_ctrl, HDCP_REG_ENABLE);
- DSS_REG_W(io, reg_set->sha_ctrl, HDCP_REG_DISABLE);
- }
+ DSS_REG_W(hdcp_ctrl->init_data.hdcp_io,
+ reg_set->sec_sha_ctrl, HDCP_REG_ENABLE);
+ DSS_REG_W(hdcp_ctrl->init_data.hdcp_io,
+ reg_set->sec_sha_ctrl, HDCP_REG_DISABLE);
for (i = 0; i < ksv_bytes - 1; i++) {
/* Write KSV byte and do not set DONE bit[0] */
- if (hdcp_ctrl->tz_hdcp) {
- memset(scm_buf, 0x00, sizeof(scm_buf));
-
- scm_buf[0].addr = phy_addr + reg_set->sha_ctrl;
- scm_buf[0].val = ksv_fifo[i] << 16;
-
- ret = hdcp_scm_call(scm_buf, &resp);
- if (ret || resp) {
- DEV_ERR("%s: scm_call ret = %d, resp = %d\n",
- __func__, ret, resp);
- rc = -EINVAL;
- goto error;
- }
- } else if (hdcp_ctrl->init_data.sec_access) {
- DSS_REG_W_ND(hdcp_ctrl->init_data.hdcp_io,
- reg_set->sec_sha_ctrl,
- ksv_fifo[i] << 16);
- } else {
- DSS_REG_W_ND(io, reg_set->sha_ctrl, ksv_fifo[i] << 16);
- }
+ DSS_REG_W_ND(hdcp_ctrl->init_data.hdcp_io,
+ reg_set->sec_sha_data, ksv_fifo[i] << 16);
/*
* Once 64 bytes have been written, we need to poll for
@@ -1189,41 +1058,22 @@ static int hdcp_1x_authentication_part2(struct hdcp_1x_ctrl *hdcp_ctrl)
HDCP_POLL_SLEEP_US,
HDCP_POLL_TIMEOUT_US);
if (IS_ERR_VALUE(rc)) {
- DEV_ERR("%s: block not done\n", __func__);
+ pr_err("block not done\n");
goto error;
}
}
}
/* Write l to DONE bit[0] */
- if (hdcp_ctrl->tz_hdcp) {
- memset(scm_buf, 0x00, sizeof(scm_buf));
-
- scm_buf[0].addr = phy_addr + reg_set->sha_ctrl;
- scm_buf[0].val = (ksv_fifo[ksv_bytes - 1] << 16) | 0x1;
-
- ret = hdcp_scm_call(scm_buf, &resp);
- if (ret || resp) {
- DEV_ERR("%s: error: scm_call ret = %d, resp = %d\n",
- __func__, ret, resp);
- rc = -EINVAL;
- goto error;
- }
- } else if (hdcp_ctrl->init_data.sec_access) {
- DSS_REG_W_ND(hdcp_ctrl->init_data.hdcp_io,
- reg_set->sec_sha_ctrl,
- (ksv_fifo[ksv_bytes - 1] << 16) | 0x1);
- } else {
- DSS_REG_W_ND(io, reg_set->sha_ctrl,
- (ksv_fifo[ksv_bytes - 1] << 16) | 0x1);
- }
+ DSS_REG_W_ND(hdcp_ctrl->init_data.hdcp_io,
+ reg_set->sec_sha_data, (ksv_fifo[ksv_bytes - 1] << 16) | 0x1);
/* Now wait for HDCP_SHA_COMP_DONE */
rc = readl_poll_timeout(io->base + reg_set->sha_status, sha_status,
sha_status & BIT(4),
HDCP_POLL_SLEEP_US, HDCP_POLL_TIMEOUT_US);
if (IS_ERR_VALUE(rc)) {
- DEV_ERR("%s: comp not done\n", __func__);
+ pr_err("V computation not done\n");
goto error;
}
@@ -1232,20 +1082,20 @@ static int hdcp_1x_authentication_part2(struct hdcp_1x_ctrl *hdcp_ctrl)
status & BIT(reg_set->v_offset),
HDCP_POLL_SLEEP_US, HDCP_POLL_TIMEOUT_US);
if (IS_ERR_VALUE(rc)) {
- DEV_ERR("%s: V not ready\n", __func__);
- goto error;
+ pr_err("V mismatch\n");
+ if (--v_retry)
+ goto v_read_retry;
}
error:
if (rc)
- DEV_ERR("%s: %s: Authentication Part II failed\n", __func__,
+ pr_err("%s: Authentication Part II failed\n",
hdcp_ctrl ? HDCP_STATE_NAME : "???");
else
- DEV_INFO("%s: %s: Authentication Part II successful\n",
- __func__, HDCP_STATE_NAME);
+ pr_debug("%s: Authentication Part II successful\n",
+ HDCP_STATE_NAME);
if (!hdcp_ctrl) {
- DEV_ERR("%s: hdcp_ctrl null. Topology not updated\n",
- __func__);
+ pr_err("hdcp_ctrl null. Topology not updated\n");
return rc;
}
/* Update topology information */
@@ -1260,7 +1110,7 @@ error:
static void hdcp_1x_cache_topology(struct hdcp_1x_ctrl *hdcp_ctrl)
{
if (!hdcp_ctrl || !hdcp_ctrl->init_data.core_io) {
- DEV_ERR("%s: invalid input\n", __func__);
+ pr_err("invalid input\n");
return;
}
@@ -1283,7 +1133,7 @@ static void hdcp_1x_notify_topology(struct hdcp_1x_ctrl *hdcp_ctrl)
snprintf(envp[2], 16, "%d", (int)HDCP_V1_TX);
kobject_uevent_env(hdcp_ctrl->init_data.sysfs_kobj, KOBJ_CHANGE, envp);
- DEV_DBG("%s Event Sent: %s msgID = %s srcID = %s\n", __func__,
+ pr_debug("Event Sent: %s msgID = %s srcID = %s\n",
envp[0], envp[1], envp[2]);
}
@@ -1293,7 +1143,7 @@ static void hdcp_1x_int_work(struct work_struct *work)
struct hdcp_1x_ctrl, hdcp_int_work);
if (!hdcp_ctrl) {
- DEV_ERR("%s: invalid input\n", __func__);
+ pr_err("invalid input\n");
return;
}
@@ -1320,16 +1170,19 @@ static void hdcp_1x_auth_work(struct work_struct *work)
struct dss_io_data *io;
if (!hdcp_ctrl) {
- DEV_ERR("%s: invalid input\n", __func__);
+ pr_err("invalid input\n");
return;
}
if (HDCP_STATE_AUTHENTICATING != hdcp_ctrl->hdcp_state) {
- DEV_DBG("%s: %s: invalid state. returning\n", __func__,
+ pr_debug("%s: invalid state. returning\n",
HDCP_STATE_NAME);
return;
}
+ hdcp_ctrl->sink_r0_ready = false;
+ hdcp_ctrl->reauth = false;
+
io = hdcp_ctrl->init_data.core_io;
/* Enabling Software DDC for HDMI and REF timer for DP */
if (hdcp_ctrl->init_data.client_id == HDCP_CLIENT_HDMI)
@@ -1340,7 +1193,7 @@ static void hdcp_1x_auth_work(struct work_struct *work)
rc = hdcp_1x_authentication_part1(hdcp_ctrl);
if (rc) {
- DEV_DBG("%s: %s: HDCP Auth Part I failed\n", __func__,
+ pr_debug("%s: HDCP Auth Part I failed\n",
HDCP_STATE_NAME);
goto error;
}
@@ -1348,12 +1201,12 @@ static void hdcp_1x_auth_work(struct work_struct *work)
if (hdcp_ctrl->current_tp.ds_type == DS_REPEATER) {
rc = hdcp_1x_authentication_part2(hdcp_ctrl);
if (rc) {
- DEV_DBG("%s: %s: HDCP Auth Part II failed\n", __func__,
+ pr_debug("%s: HDCP Auth Part II failed\n",
HDCP_STATE_NAME);
goto error;
}
} else {
- DEV_INFO("%s: Downstream device is not a repeater\n", __func__);
+ pr_debug("Downstream device is not a repeater\n");
}
/* Disabling software DDC before going into part3 to make sure
* there is no Arbitration between software and hardware for DDC */
@@ -1381,18 +1234,16 @@ error:
mutex_unlock(hdcp_ctrl->init_data.mutex);
/* Notify HDMI Tx controller of the result */
- DEV_DBG("%s: %s: Notifying HDMI Tx of auth result\n",
- __func__, HDCP_STATE_NAME);
+ pr_debug("%s: Notifying HDMI Tx of auth result\n",
+ HDCP_STATE_NAME);
if (hdcp_ctrl->init_data.notify_status) {
hdcp_ctrl->init_data.notify_status(
hdcp_ctrl->init_data.cb_data,
hdcp_ctrl->hdcp_state);
}
-
- hdcp1_set_enc(true);
} else {
- DEV_DBG("%s: %s: HDCP state changed during authentication\n",
- __func__, HDCP_STATE_NAME);
+ pr_debug("%s: HDCP state changed during authentication\n",
+ HDCP_STATE_NAME);
mutex_unlock(hdcp_ctrl->init_data.mutex);
}
return;
@@ -1403,28 +1254,28 @@ int hdcp_1x_authenticate(void *input)
struct hdcp_1x_ctrl *hdcp_ctrl = (struct hdcp_1x_ctrl *)input;
if (!hdcp_ctrl) {
- DEV_ERR("%s: invalid input\n", __func__);
+ pr_err("invalid input\n");
return -EINVAL;
}
if (HDCP_STATE_INACTIVE != hdcp_ctrl->hdcp_state) {
- DEV_DBG("%s: %s: already active or activating. returning\n",
- __func__, HDCP_STATE_NAME);
+ pr_debug("%s: already active or activating. returning\n",
+ HDCP_STATE_NAME);
return 0;
}
- DEV_DBG("%s: %s: Queuing work to start HDCP authentication", __func__,
+ pr_debug("%s: Queuing work to start HDCP authentication",
HDCP_STATE_NAME);
if (!hdcp_1x_load_keys(input)) {
flush_delayed_work(&hdcp_ctrl->hdcp_auth_work);
- queue_delayed_work(hdcp_ctrl->init_data.workq,
+ queue_delayed_work(hdcp_ctrl->workq,
&hdcp_ctrl->hdcp_auth_work, HZ/2);
} else {
flush_work(&hdcp_ctrl->hdcp_int_work);
- queue_work(hdcp_ctrl->init_data.workq,
+ queue_work(hdcp_ctrl->workq,
&hdcp_ctrl->hdcp_int_work);
}
@@ -1441,7 +1292,7 @@ int hdcp_1x_reauthenticate(void *input)
u32 ret = 0, reg;
if (!hdcp_ctrl || !hdcp_ctrl->init_data.core_io) {
- DEV_ERR("%s: invalid input\n", __func__);
+ pr_err("invalid input\n");
return -EINVAL;
}
@@ -1450,7 +1301,7 @@ int hdcp_1x_reauthenticate(void *input)
isr = &hdcp_ctrl->int_set;
if (HDCP_STATE_AUTH_FAIL != hdcp_ctrl->hdcp_state) {
- DEV_DBG("%s: %s: invalid state. returning\n", __func__,
+ pr_debug("%s: invalid state. returning\n",
HDCP_STATE_NAME);
return 0;
}
@@ -1478,10 +1329,10 @@ int hdcp_1x_reauthenticate(void *input)
DSS_REG_W(io, reg_set->reset, reg & ~reg_set->reset_bit);
if (!hdcp_1x_load_keys(input))
- queue_delayed_work(hdcp_ctrl->init_data.workq,
+ queue_delayed_work(hdcp_ctrl->workq,
&hdcp_ctrl->hdcp_auth_work, HZ);
else
- queue_work(hdcp_ctrl->init_data.workq,
+ queue_work(hdcp_ctrl->workq,
&hdcp_ctrl->hdcp_int_work);
return ret;
@@ -1497,7 +1348,7 @@ void hdcp_1x_off(void *input)
u32 reg;
if (!hdcp_ctrl || !hdcp_ctrl->init_data.core_io) {
- DEV_ERR("%s: invalid input\n", __func__);
+ pr_err("invalid input\n");
return;
}
@@ -1506,7 +1357,7 @@ void hdcp_1x_off(void *input)
isr = &hdcp_ctrl->int_set;
if (HDCP_STATE_INACTIVE == hdcp_ctrl->hdcp_state) {
- DEV_DBG("%s: %s: inactive. returning\n", __func__,
+ pr_debug("%s: inactive. returning\n",
HDCP_STATE_NAME);
return;
}
@@ -1531,13 +1382,13 @@ void hdcp_1x_off(void *input)
* No more reauthentiaction attempts will be scheduled since we
* set the currect state to inactive.
*/
- rc = cancel_delayed_work_sync(&hdcp_ctrl->hdcp_auth_work);
+ rc = cancel_delayed_work(&hdcp_ctrl->hdcp_auth_work);
if (rc)
- DEV_DBG("%s: %s: Deleted hdcp auth work\n", __func__,
+ pr_debug("%s: Deleted hdcp auth work\n",
HDCP_STATE_NAME);
rc = cancel_work_sync(&hdcp_ctrl->hdcp_int_work);
if (rc)
- DEV_DBG("%s: %s: Deleted hdcp int work\n", __func__,
+ pr_debug("%s: Deleted hdcp int work\n",
HDCP_STATE_NAME);
@@ -1549,7 +1400,9 @@ void hdcp_1x_off(void *input)
DSS_REG_W(io, reg_set->reset, reg & ~reg_set->reset_bit);
- DEV_DBG("%s: %s: HDCP: Off\n", __func__, HDCP_STATE_NAME);
+ hdcp_ctrl->sink_r0_ready = false;
+
+ pr_debug("%s: HDCP: Off\n", HDCP_STATE_NAME);
} /* hdcp_1x_off */
int hdcp_1x_isr(void *input)
@@ -1562,7 +1415,7 @@ int hdcp_1x_isr(void *input)
struct hdcp_int_set *isr;
if (!hdcp_ctrl || !hdcp_ctrl->init_data.core_io) {
- DEV_ERR("%s: invalid input\n", __func__);
+ pr_err("invalid input\n");
rc = -EINVAL;
goto error;
}
@@ -1583,7 +1436,7 @@ int hdcp_1x_isr(void *input)
/* AUTH_SUCCESS_INT */
DSS_REG_W(io, isr->int_reg,
(hdcp_int_val | isr->auth_success_ack));
- DEV_INFO("%s: %s: AUTH_SUCCESS_INT received\n", __func__,
+ pr_debug("%s: AUTH_SUCCESS_INT received\n",
HDCP_STATE_NAME);
if (HDCP_STATE_AUTHENTICATING == hdcp_ctrl->hdcp_state)
complete_all(&hdcp_ctrl->r0_checked);
@@ -1595,11 +1448,11 @@ int hdcp_1x_isr(void *input)
DSS_REG_W(io, isr->int_reg,
(hdcp_int_val | isr->auth_fail_ack));
- DEV_INFO("%s: %s: AUTH_FAIL_INT rcvd, LINK0_STATUS=0x%08x\n",
- __func__, HDCP_STATE_NAME, link_status);
+ pr_debug("%s: AUTH_FAIL_INT rcvd, LINK0_STATUS=0x%08x\n",
+ HDCP_STATE_NAME, link_status);
if (HDCP_STATE_AUTHENTICATED == hdcp_ctrl->hdcp_state) {
/* Inform HDMI Tx of the failure */
- queue_work(hdcp_ctrl->init_data.workq,
+ queue_work(hdcp_ctrl->workq,
&hdcp_ctrl->hdcp_int_work);
/* todo: print debug log with auth fail reason */
} else if (HDCP_STATE_AUTHENTICATING == hdcp_ctrl->hdcp_state) {
@@ -1615,7 +1468,7 @@ int hdcp_1x_isr(void *input)
/* DDC_XFER_REQ_INT */
DSS_REG_W(io, isr->int_reg,
(hdcp_int_val | isr->tx_req_ack));
- DEV_INFO("%s: %s: DDC_XFER_REQ_INT received\n", __func__,
+ pr_debug("%s: DDC_XFER_REQ_INT received\n",
HDCP_STATE_NAME);
}
@@ -1623,7 +1476,7 @@ int hdcp_1x_isr(void *input)
/* DDC_XFER_DONE_INT */
DSS_REG_W(io, isr->int_reg,
(hdcp_int_val | isr->tx_req_done_ack));
- DEV_INFO("%s: %s: DDC_XFER_DONE received\n", __func__,
+ pr_debug("%s: DDC_XFER_DONE received\n",
HDCP_STATE_NAME);
}
@@ -1631,7 +1484,7 @@ int hdcp_1x_isr(void *input)
/* Encryption enabled */
DSS_REG_W(io, isr->int_reg,
(hdcp_int_val | isr->encryption_ready_ack));
- DEV_INFO("%s: %s: encryption ready received\n", __func__,
+ pr_debug("%s: encryption ready received\n",
HDCP_STATE_NAME);
}
@@ -1639,7 +1492,7 @@ int hdcp_1x_isr(void *input)
/* Encryption enabled */
DSS_REG_W(io, isr->int_reg,
(hdcp_int_val | isr->encryption_not_ready_ack));
- DEV_INFO("%s: %s: encryption not ready received\n", __func__,
+ pr_debug("%s: encryption not ready received\n",
HDCP_STATE_NAME);
}
@@ -1688,13 +1541,13 @@ static ssize_t hdcp_1x_sysfs_rda_status(struct device *dev,
struct hdcp_1x_ctrl *hdcp_ctrl = hdcp_1x_get_ctrl(dev);
if (!hdcp_ctrl) {
- DEV_ERR("%s: invalid input\n", __func__);
+ pr_err("invalid input\n");
return -EINVAL;
}
mutex_lock(hdcp_ctrl->init_data.mutex);
ret = snprintf(buf, PAGE_SIZE, "%d\n", hdcp_ctrl->hdcp_state);
- DEV_DBG("%s: '%d'\n", __func__, hdcp_ctrl->hdcp_state);
+ pr_debug("'%d'\n", hdcp_ctrl->hdcp_state);
mutex_unlock(hdcp_ctrl->init_data.mutex);
return ret;
@@ -1707,7 +1560,7 @@ static ssize_t hdcp_1x_sysfs_rda_tp(struct device *dev,
struct hdcp_1x_ctrl *hdcp_ctrl = hdcp_1x_get_ctrl(dev);
if (!hdcp_ctrl) {
- DEV_ERR("%s: invalid input\n", __func__);
+ pr_err("invalid input\n");
return -EINVAL;
}
@@ -1741,7 +1594,7 @@ static ssize_t hdcp_1x_sysfs_wta_tp(struct device *dev,
struct hdcp_1x_ctrl *hdcp_ctrl = hdcp_1x_get_ctrl(dev);
if (!hdcp_ctrl || !buf) {
- DEV_ERR("%s: invalid input\n", __func__);
+ pr_err("invalid input\n");
return -EINVAL;
}
@@ -1781,10 +1634,13 @@ void hdcp_1x_deinit(void *input)
struct hdcp_1x_ctrl *hdcp_ctrl = (struct hdcp_1x_ctrl *)input;
if (!hdcp_ctrl) {
- DEV_ERR("%s: invalid input\n", __func__);
+ pr_err("invalid input\n");
return;
}
+ if (hdcp_ctrl->workq)
+ destroy_workqueue(hdcp_ctrl->workq);
+
sysfs_remove_group(hdcp_ctrl->init_data.sysfs_kobj,
&hdcp_1x_fs_attr_group);
@@ -1812,12 +1668,67 @@ static void hdcp_1x_update_client_reg_set(struct hdcp_1x_ctrl *hdcp_ctrl)
}
}
+static int hdcp_1x_cp_irq(void *input)
+{
+ struct hdcp_1x_ctrl *hdcp_ctrl = (struct hdcp_1x_ctrl *)input;
+ u8 buf = 0;
+ int ret = -EINVAL;
+
+ if (!hdcp_ctrl) {
+ pr_err("invalid input\n");
+ goto end;
+ }
+
+ ret = hdcp_1x_read(hdcp_ctrl, &hdcp_ctrl->sink_addr.cp_irq_status,
+ &buf, false);
+ if (IS_ERR_VALUE(ret)) {
+ pr_err("error reading cp_irq_status\n");
+ goto end;
+ }
+
+ if (!buf) {
+ pr_debug("not a hdcp 1.x irq\n");
+ ret = -EINVAL;
+ goto end;
+ }
+
+ if ((buf & BIT(2)) || (buf & BIT(3))) {
+ pr_err("%s\n",
+ buf & BIT(2) ? "LINK_INTEGRITY_FAILURE" :
+ "REAUTHENTICATION_REQUEST");
+
+ hdcp_ctrl->reauth = true;
+
+ complete_all(&hdcp_ctrl->sink_rep_ready);
+ complete_all(&hdcp_ctrl->sink_r0_available);
+
+ queue_work(hdcp_ctrl->workq, &hdcp_ctrl->hdcp_int_work);
+ goto end;
+ }
+
+ if (buf & BIT(1)) {
+ pr_debug("R0' AVAILABLE\n");
+ hdcp_ctrl->sink_r0_ready = true;
+ complete_all(&hdcp_ctrl->sink_r0_available);
+ goto end;
+ }
+
+ if (buf & BIT(0)) {
+ pr_debug("KSVs READY\n");
+ complete_all(&hdcp_ctrl->sink_rep_ready);
+ goto end;
+ }
+end:
+ return ret;
+}
+
void *hdcp_1x_init(struct hdcp_init_data *init_data)
{
struct hdcp_1x_ctrl *hdcp_ctrl = NULL;
- int ret;
+ char name[20];
static struct hdcp_ops ops = {
.isr = hdcp_1x_isr,
+ .cp_irq = hdcp_1x_cp_irq,
.reauthenticate = hdcp_1x_reauthenticate,
.authenticate = hdcp_1x_authenticate,
.off = hdcp_1x_off
@@ -1826,29 +1737,36 @@ void *hdcp_1x_init(struct hdcp_init_data *init_data)
if (!init_data || !init_data->core_io || !init_data->qfprom_io ||
!init_data->mutex || !init_data->notify_status ||
!init_data->workq || !init_data->cb_data) {
- DEV_ERR("%s: invalid input\n", __func__);
+ pr_err("invalid input\n");
goto error;
}
if (init_data->sec_access && !init_data->hdcp_io) {
- DEV_ERR("%s: hdcp_io required\n", __func__);
+ pr_err("hdcp_io required\n");
goto error;
}
hdcp_ctrl = kzalloc(sizeof(*hdcp_ctrl), GFP_KERNEL);
- if (!hdcp_ctrl) {
- DEV_ERR("%s: Out of memory\n", __func__);
+ if (!hdcp_ctrl)
goto error;
- }
hdcp_ctrl->init_data = *init_data;
hdcp_ctrl->ops = &ops;
+ snprintf(name, sizeof(name), "hdcp_1x_%d",
+ hdcp_ctrl->init_data.client_id);
+
+ hdcp_ctrl->workq = create_workqueue(name);
+ if (!hdcp_ctrl->workq) {
+ pr_err("Error creating workqueue\n");
+ goto error;
+ }
+
hdcp_1x_update_client_reg_set(hdcp_ctrl);
if (sysfs_create_group(init_data->sysfs_kobj,
&hdcp_1x_fs_attr_group)) {
- DEV_ERR("%s: hdcp sysfs group creation failed\n", __func__);
+ pr_err("hdcp sysfs group creation failed\n");
goto error;
}
@@ -1857,19 +1775,10 @@ void *hdcp_1x_init(struct hdcp_init_data *init_data)
hdcp_ctrl->hdcp_state = HDCP_STATE_INACTIVE;
init_completion(&hdcp_ctrl->r0_checked);
+ init_completion(&hdcp_ctrl->sink_r0_available);
+ init_completion(&hdcp_ctrl->sink_rep_ready);
- if (!hdcp_ctrl->init_data.sec_access) {
- ret = scm_is_call_available(SCM_SVC_HDCP, SCM_CMD_HDCP);
- if (ret <= 0) {
- DEV_ERR("%s: secure hdcp service unavailable, ret = %d",
- __func__, ret);
- } else {
- DEV_DBG("%s: tz_hdcp = 1\n", __func__);
- hdcp_ctrl->tz_hdcp = 1;
- }
- }
-
- DEV_DBG("%s: HDCP module initialized. HDCP_STATE=%s", __func__,
+ pr_debug("HDCP module initialized. HDCP_STATE=%s\n",
HDCP_STATE_NAME);
error:
diff --git a/drivers/video/fbdev/msm/mdss_hdmi_edid.c b/drivers/video/fbdev/msm/mdss_hdmi_edid.c
index b90ac82049c6..0a316fa19909 100644
--- a/drivers/video/fbdev/msm/mdss_hdmi_edid.c
+++ b/drivers/video/fbdev/msm/mdss_hdmi_edid.c
@@ -134,6 +134,7 @@ struct hdmi_edid_ctrl {
u8 it_scan_info;
u8 ce_scan_info;
u8 cea_blks;
+ /* DC: MSB -> LSB: Y420_48|Y420_36|Y420_30|RGB48|RGB36|RGB30|Y444 */
u8 deep_color;
u16 physical_address;
u32 video_resolution; /* selected by user */
@@ -858,6 +859,43 @@ static const u8 *hdmi_edid_find_block(const u8 *in_buf, u32 start_offset,
return NULL;
} /* hdmi_edid_find_block */
+static const u8 *hdmi_edid_find_hfvsdb(const u8 *in_buf)
+{
+ u8 len = 0, i = 0;
+ const u8 *vsd = NULL;
+ u32 vsd_offset = DBC_START_OFFSET;
+ u32 hf_ieee_oui = 0;
+
+ /* Find HF-VSDB with HF-OUI */
+ do {
+ vsd = hdmi_edid_find_block(in_buf, vsd_offset,
+ VENDOR_SPECIFIC_DATA_BLOCK, &len);
+
+ if (!vsd || !len || len > MAX_DATA_BLOCK_SIZE) {
+ if (i == 0)
+ pr_debug("%s: VSDB not found\n", __func__);
+ else
+ pr_debug("%s: no more VSDB found\n", __func__);
+
+ return NULL;
+ }
+
+ hf_ieee_oui = (vsd[1] << 16) | (vsd[2] << 8) | vsd[3];
+
+ if (hf_ieee_oui == HDMI_FORUM_IEEE_OUI) {
+ pr_debug("%s: found HF-VSDB\n", __func__);
+ break;
+ }
+
+ pr_debug("%s: Not a HF OUI 0x%x\n", __func__, hf_ieee_oui);
+
+ i++;
+ vsd_offset = vsd - in_buf + len + 1;
+ } while (1);
+
+ return vsd;
+}
+
static void hdmi_edid_set_y420_support(struct hdmi_edid_ctrl *edid_ctrl,
u32 video_format)
{
@@ -1251,62 +1289,32 @@ static void hdmi_edid_extract_speaker_allocation_data(
static void hdmi_edid_extract_sink_caps(struct hdmi_edid_ctrl *edid_ctrl,
const u8 *in_buf)
{
- u8 len = 0, i = 0;
const u8 *vsd = NULL;
- u32 vsd_offset = DBC_START_OFFSET;
- u32 hf_ieee_oui = 0;
if (!edid_ctrl) {
- DEV_ERR("%s: invalid input\n", __func__);
+ pr_err("%s: invalid input\n", __func__);
return;
}
- /* Find HF-VSDB with HF-OUI */
- do {
- vsd = hdmi_edid_find_block(in_buf, vsd_offset,
- VENDOR_SPECIFIC_DATA_BLOCK, &len);
-
- if (!vsd || !len || len > MAX_DATA_BLOCK_SIZE) {
- if (i == 0)
- DEV_ERR("%s: VSDB not found\n", __func__);
- else
- DEV_DBG("%s: no more VSDB found\n", __func__);
- break;
- }
-
- hf_ieee_oui = (vsd[1] << 16) | (vsd[2] << 8) | vsd[3];
-
- if (hf_ieee_oui == HDMI_FORUM_IEEE_OUI) {
- DEV_DBG("%s: found HF-VSDB\n", __func__);
- break;
- }
-
- DEV_DBG("%s: Not a HF OUI 0x%x\n", __func__, hf_ieee_oui);
-
- i++;
- vsd_offset = vsd - in_buf + len + 1;
- } while (1);
-
- if (!vsd) {
- DEV_DBG("%s: HF-VSDB not found\n", __func__);
- return;
+ vsd = hdmi_edid_find_hfvsdb(in_buf);
+
+ if (vsd) {
+ /* Max pixel clock is in multiples of 5Mhz. */
+ edid_ctrl->sink_caps.max_pclk_in_hz =
+ vsd[5]*5000000;
+ edid_ctrl->sink_caps.scdc_present =
+ (vsd[6] & 0x80) ? true : false;
+ edid_ctrl->sink_caps.scramble_support =
+ (vsd[6] & 0x08) ? true : false;
+ edid_ctrl->sink_caps.read_req_support =
+ (vsd[6] & 0x40) ? true : false;
+ edid_ctrl->sink_caps.osd_disparity =
+ (vsd[6] & 0x01) ? true : false;
+ edid_ctrl->sink_caps.dual_view_support =
+ (vsd[6] & 0x02) ? true : false;
+ edid_ctrl->sink_caps.ind_view_support =
+ (vsd[6] & 0x04) ? true : false;
}
-
- /* Max pixel clock is in multiples of 5Mhz. */
- edid_ctrl->sink_caps.max_pclk_in_hz =
- vsd[5]*5000000;
- edid_ctrl->sink_caps.scdc_present =
- (vsd[6] & 0x80) ? true : false;
- edid_ctrl->sink_caps.scramble_support =
- (vsd[6] & 0x08) ? true : false;
- edid_ctrl->sink_caps.read_req_support =
- (vsd[6] & 0x40) ? true : false;
- edid_ctrl->sink_caps.osd_disparity =
- (vsd[6] & 0x01) ? true : false;
- edid_ctrl->sink_caps.dual_view_support =
- (vsd[6] & 0x02) ? true : false;
- edid_ctrl->sink_caps.ind_view_support =
- (vsd[6] & 0x04) ? true : false;
}
static void hdmi_edid_extract_latency_fields(struct hdmi_edid_ctrl *edid_ctrl,
@@ -1404,12 +1412,19 @@ static void hdmi_edid_extract_dc(struct hdmi_edid_ctrl *edid_ctrl,
edid_ctrl->deep_color = (vsd[6] >> 0x3) & 0xF;
- DEV_DBG("%s: deep color: Y444|RGB30|RGB36|RGB48: (%d|%d|%d|%d)\n",
- __func__,
+ vsd = hdmi_edid_find_hfvsdb(in_buf);
+
+ if (vsd)
+ edid_ctrl->deep_color |= (vsd[7] & 0x07) << 4;
+
+ pr_debug("deep color: Y444|RGB30|RGB36|RGB48|Y420_30|Y420_36|Y420_48: (%d|%d|%d|%d|%d|%d|%d)\n",
(int) (edid_ctrl->deep_color & BIT(0)) >> 0,
(int) (edid_ctrl->deep_color & BIT(1)) >> 1,
(int) (edid_ctrl->deep_color & BIT(2)) >> 2,
- (int) (edid_ctrl->deep_color & BIT(3)) >> 3);
+ (int) (edid_ctrl->deep_color & BIT(3)) >> 3,
+ (int) (edid_ctrl->deep_color & BIT(4)) >> 4,
+ (int) (edid_ctrl->deep_color & BIT(5)) >> 5,
+ (int) (edid_ctrl->deep_color & BIT(6)) >> 6);
}
static u32 hdmi_edid_check_header(const u8 *edid_buf)
@@ -2398,8 +2413,8 @@ u32 hdmi_edid_get_sink_mode(void *input)
*
* This API returns deep color for different formats supported by sink.
* Deep color support for Y444 (BIT(0)), RGB30 (BIT(1)), RGB36 (BIT(2),
- * RGB 48 (BIT(3)) is provided in a 8 bit integer. The MSB 8 bits are
- * not used.
+ * RGB 48 (BIT(3)), Y420_30 (BIT(4)), Y420_36 (BIT(5)), Y420_48 (BIT(6))
+ * is provided in a 8 bit integer. The MSB 8 bits are not used.
*
* Return: deep color data.
*/
@@ -2416,6 +2431,25 @@ u8 hdmi_edid_get_deep_color(void *input)
}
/**
+ * hdmi_edid_get_max_pclk() - get max pclk supported. Sink side's limitation
+ * should be concerned as well.
+ * @input: edid parser data
+ *
+ * Return: max pclk rate
+ */
+u32 hdmi_edid_get_max_pclk(void *input)
+{
+ struct hdmi_edid_ctrl *edid_ctrl = (struct hdmi_edid_ctrl *)input;
+
+ if (!edid_ctrl) {
+ DEV_ERR("%s: invalid input\n", __func__);
+ return 0;
+ }
+
+ return edid_ctrl->init_data.max_pclk_khz;
+}
+
+/**
* hdmi_edid_get_hdr_data() - get the HDR capabiliies of the sink
* @input: edid parser data
*
diff --git a/drivers/video/fbdev/msm/mdss_hdmi_edid.h b/drivers/video/fbdev/msm/mdss_hdmi_edid.h
index ce6cecbb2e03..43e1adb1f139 100644
--- a/drivers/video/fbdev/msm/mdss_hdmi_edid.h
+++ b/drivers/video/fbdev/msm/mdss_hdmi_edid.h
@@ -60,6 +60,7 @@ void *hdmi_edid_init(struct hdmi_edid_init_data *init_data);
bool hdmi_edid_is_s3d_mode_supported(void *input,
u32 video_mode, u32 s3d_mode);
u8 hdmi_edid_get_deep_color(void *edid_ctrl);
+u32 hdmi_edid_get_max_pclk(void *edid_ctrl);
void hdmi_edid_get_hdr_data(void *edid_ctrl,
struct hdmi_edid_hdr_data **hdr_data);
diff --git a/drivers/video/fbdev/msm/mdss_hdmi_hdcp2p2.c b/drivers/video/fbdev/msm/mdss_hdmi_hdcp2p2.c
index 481fc118c7ad..7934e4cf3bc4 100644
--- a/drivers/video/fbdev/msm/mdss_hdmi_hdcp2p2.c
+++ b/drivers/video/fbdev/msm/mdss_hdmi_hdcp2p2.c
@@ -666,7 +666,7 @@ static void hdmi_hdcp2p2_link_cb(void *data)
static void hdmi_hdcp2p2_recv_msg(struct hdmi_hdcp2p2_ctrl *ctrl)
{
- int rc, timeout_hsync;
+ int rc = 0, timeout_hsync;
char *recvd_msg_buf = NULL;
struct hdmi_tx_hdcp2p2_ddc_data *ddc_data;
struct hdmi_tx_ddc_ctrl *ddc_ctrl;
@@ -689,6 +689,7 @@ static void hdmi_hdcp2p2_recv_msg(struct hdmi_hdcp2p2_ctrl *ctrl)
if (atomic_read(&ctrl->auth_state) == HDCP_STATE_INACTIVE) {
pr_err("hdcp is off\n");
+ rc = -EINVAL;
goto exit;
}
hdmi_ddc_config(ddc_ctrl);
diff --git a/drivers/video/fbdev/msm/mdss_hdmi_panel.c b/drivers/video/fbdev/msm/mdss_hdmi_panel.c
index 522debfba8ce..a8a56e3a8745 100644
--- a/drivers/video/fbdev/msm/mdss_hdmi_panel.c
+++ b/drivers/video/fbdev/msm/mdss_hdmi_panel.c
@@ -602,14 +602,51 @@ end:
return rc;
}
+static int hdmi_panel_setup_dc(struct hdmi_panel *panel)
+{
+ u32 hdmi_ctrl_reg;
+ u32 vbi_pkt_reg;
+ int rc = 0;
+
+ pr_debug("Deep Color: %s\n", panel->data->dc_enable ? "ON" : "OFF");
+
+ /* enable deep color if supported */
+ if (panel->data->dc_enable) {
+ hdmi_ctrl_reg = DSS_REG_R(panel->io, HDMI_CTRL);
+
+ /* GC CD override */
+ hdmi_ctrl_reg |= BIT(27);
+
+ /* enable deep color for RGB888 30 bits */
+ hdmi_ctrl_reg |= BIT(24);
+ DSS_REG_W(panel->io, HDMI_CTRL, hdmi_ctrl_reg);
+
+ /* Enable GC_CONT and GC_SEND in General Control Packet
+ * (GCP) register so that deep color data is
+ * transmitted to the sink on every frame, allowing
+ * the sink to decode the data correctly.
+ *
+ * GC_CONT: 0x1 - Send GCP on every frame
+ * GC_SEND: 0x1 - Enable GCP Transmission
+ */
+ vbi_pkt_reg = DSS_REG_R(panel->io, HDMI_VBI_PKT_CTRL);
+ vbi_pkt_reg |= BIT(5) | BIT(4);
+ DSS_REG_W(panel->io, HDMI_VBI_PKT_CTRL, vbi_pkt_reg);
+ }
+
+ return rc;
+}
+
static int hdmi_panel_setup_scrambler(struct hdmi_panel *panel)
{
int rc = 0;
int timeout_hsync;
u32 reg_val = 0;
u32 tmds_clock_ratio = 0;
+ u32 tmds_clock = 0;
bool scrambler_on = false;
struct msm_hdmi_mode_timing_info *timing = NULL;
+ struct mdss_panel_info *pinfo = NULL;
if (!panel) {
pr_err("invalid input\n");
@@ -622,13 +659,22 @@ static int hdmi_panel_setup_scrambler(struct hdmi_panel *panel)
return -EINVAL;
}
+ pinfo = panel->data->pinfo;
+ if (!pinfo) {
+ pr_err("invalid panel data\n");
+ return -EINVAL;
+ }
+
/* Scrambling is supported from HDMI TX 4.0 */
if (panel->version < HDMI_TX_SCRAMBLER_MIN_TX_VERSION) {
pr_debug("scrambling not supported by tx\n");
return 0;
}
- if (timing->pixel_freq > HDMI_TX_SCRAMBLER_THRESHOLD_RATE_KHZ) {
+ tmds_clock = hdmi_tx_setup_tmds_clk_rate(timing->pixel_freq,
+ pinfo->out_format, panel->data->dc_enable);
+
+ if (tmds_clock > HDMI_TX_SCRAMBLER_THRESHOLD_RATE_KHZ) {
scrambler_on = true;
tmds_clock_ratio = 1;
} else {
@@ -798,6 +844,12 @@ static int hdmi_panel_power_on(void *input)
pr_err("scrambler setup failed. rc=%d\n", rc);
goto err;
}
+
+ rc = hdmi_panel_setup_dc(panel);
+ if (rc) {
+ pr_err("Deep Color setup failed. rc=%d\n", rc);
+ goto err;
+ }
end:
panel->on = true;
diff --git a/drivers/video/fbdev/msm/mdss_hdmi_panel.h b/drivers/video/fbdev/msm/mdss_hdmi_panel.h
index 6fa9af13d46e..cb40f0cad55e 100644
--- a/drivers/video/fbdev/msm/mdss_hdmi_panel.h
+++ b/drivers/video/fbdev/msm/mdss_hdmi_panel.h
@@ -28,6 +28,7 @@
* @infoframe: set to true if infoframes should be sent to sink
* @is_it_content: set to true if content is IT
* @scrambler: set to true if scrambler needs to be enabled
+ * @dc_enable: set to true if deep color is enabled
*/
struct hdmi_panel_data {
struct mdss_panel_info *pinfo;
@@ -39,6 +40,7 @@ struct hdmi_panel_data {
bool infoframe;
bool is_it_content;
bool scrambler;
+ bool dc_enable;
};
/**
diff --git a/drivers/video/fbdev/msm/mdss_hdmi_tx.c b/drivers/video/fbdev/msm/mdss_hdmi_tx.c
index d01d163af5fa..e9ae30bb6914 100644
--- a/drivers/video/fbdev/msm/mdss_hdmi_tx.c
+++ b/drivers/video/fbdev/msm/mdss_hdmi_tx.c
@@ -35,6 +35,7 @@
#include "mdss.h"
#include "mdss_panel.h"
#include "mdss_hdmi_mhl.h"
+#include "mdss_hdmi_util.h"
#define DRV_NAME "hdmi-tx"
#define COMPATIBLE_NAME "qcom,hdmi-tx"
@@ -58,13 +59,6 @@
#define AUDIO_POLL_SLEEP_US (5 * 1000)
#define AUDIO_POLL_TIMEOUT_US (AUDIO_POLL_SLEEP_US * 1000)
-#define HDMI_TX_YUV420_24BPP_PCLK_TMDS_CH_RATE_RATIO 2
-#define HDMI_TX_YUV422_24BPP_PCLK_TMDS_CH_RATE_RATIO 1
-#define HDMI_TX_RGB_24BPP_PCLK_TMDS_CH_RATE_RATIO 1
-
-#define HDMI_TX_SCRAMBLER_THRESHOLD_RATE_KHZ 340000
-#define HDMI_TX_SCRAMBLER_TIMEOUT_MSEC 200
-
/* Maximum pixel clock rates for hdmi tx */
#define HDMI_DEFAULT_MAX_PCLK_RATE 148500
#define HDMI_TX_3_MAX_PCLK_RATE 297000
@@ -77,6 +71,7 @@
#define HDMI_TX_MIN_FPS 20000
#define HDMI_TX_MAX_FPS 120000
+#define HDMI_KHZ_TO_HZ 1000
#define HDMI_TX_VERSION_403 0x40000003 /* msm8998 */
#define HDMI_GET_MSB(x) (x >> 8)
@@ -111,7 +106,6 @@ static irqreturn_t hdmi_tx_isr(int irq, void *data);
static void hdmi_tx_hpd_off(struct hdmi_tx_ctrl *hdmi_ctrl);
static int hdmi_tx_enable_power(struct hdmi_tx_ctrl *hdmi_ctrl,
enum hdmi_tx_power_module_type module, int enable);
-static int hdmi_tx_setup_tmds_clk_rate(struct hdmi_tx_ctrl *hdmi_ctrl);
static void hdmi_tx_fps_work(struct work_struct *work);
static int hdmi_tx_pinctrl_set_state(struct hdmi_tx_ctrl *hdmi_ctrl,
enum hdmi_tx_power_module_type module, bool active);
@@ -121,6 +115,7 @@ static int hdmi_tx_audio_info_setup(struct platform_device *pdev,
static int hdmi_tx_get_audio_edid_blk(struct platform_device *pdev,
struct msm_ext_disp_audio_edid_blk *blk);
static int hdmi_tx_get_cable_status(struct platform_device *pdev, u32 vote);
+static int hdmi_tx_update_ppm(struct hdmi_tx_ctrl *hdmi_ctrl, s32 ppm);
static struct mdss_hw hdmi_tx_hw = {
.hw_ndx = MDSS_HW_HDMI,
@@ -318,11 +313,29 @@ static inline bool hdmi_tx_metadata_type_one(struct hdmi_tx_ctrl *hdmi_ctrl)
return hdr_data->metadata_type_one;
}
+static inline bool hdmix_tx_sink_dc_support(struct hdmi_tx_ctrl *hdmi_ctrl)
+{
+ void *edid_fd = hdmi_tx_get_fd(HDMI_TX_FEAT_EDID);
+
+ if (hdmi_ctrl->panel_data.panel_info.out_format == MDP_Y_CBCR_H2V2)
+ return (hdmi_edid_get_deep_color(edid_fd) & BIT(4));
+ else
+ return (hdmi_edid_get_deep_color(edid_fd) & BIT(1));
+}
+
static inline bool hdmi_tx_dc_support(struct hdmi_tx_ctrl *hdmi_ctrl)
{
- return hdmi_ctrl->dc_feature_on && hdmi_ctrl->dc_support &&
- (hdmi_edid_get_deep_color(
- hdmi_tx_get_fd(HDMI_TX_FEAT_EDID)) & BIT(1));
+ /* actual pixel clock if deep color is enabled */
+ void *edid_fd = hdmi_tx_get_fd(HDMI_TX_FEAT_EDID);
+ u32 tmds_clk_with_dc = hdmi_tx_setup_tmds_clk_rate(
+ hdmi_ctrl->timing.pixel_freq,
+ hdmi_ctrl->panel.pinfo->out_format,
+ true);
+
+ return hdmi_ctrl->dc_feature_on &&
+ hdmi_ctrl->dc_support &&
+ hdmix_tx_sink_dc_support(hdmi_ctrl) &&
+ (tmds_clk_with_dc <= hdmi_edid_get_max_pclk(edid_fd));
}
static const char *hdmi_tx_pm_name(enum hdmi_tx_power_module_type module)
@@ -349,7 +362,10 @@ static const char *hdmi_tx_io_name(u32 type)
static void hdmi_tx_audio_setup(struct hdmi_tx_ctrl *hdmi_ctrl)
{
if (hdmi_ctrl && hdmi_ctrl->audio_ops.on) {
- u32 pclk = hdmi_tx_setup_tmds_clk_rate(hdmi_ctrl);
+ u32 pclk = hdmi_tx_setup_tmds_clk_rate(
+ hdmi_ctrl->timing.pixel_freq,
+ hdmi_ctrl->panel.pinfo->out_format,
+ hdmi_ctrl->panel.dc_enable);
hdmi_ctrl->audio_ops.on(hdmi_ctrl->audio_data,
pclk, &hdmi_ctrl->audio_params);
@@ -369,9 +385,14 @@ static inline bool hdmi_tx_is_panel_on(struct hdmi_tx_ctrl *hdmi_ctrl)
static inline bool hdmi_tx_is_cec_wakeup_en(struct hdmi_tx_ctrl *hdmi_ctrl)
{
- void *fd = hdmi_tx_get_fd(HDMI_TX_FEAT_CEC_HW);
+ void *fd = NULL;
- if (!hdmi_ctrl || !fd)
+ if (!hdmi_ctrl)
+ return false;
+
+ fd = hdmi_tx_get_fd(HDMI_TX_FEAT_CEC_HW);
+
+ if (!fd)
return false;
return hdmi_cec_is_wakeup_en(fd);
@@ -379,9 +400,14 @@ static inline bool hdmi_tx_is_cec_wakeup_en(struct hdmi_tx_ctrl *hdmi_ctrl)
static inline void hdmi_tx_cec_device_suspend(struct hdmi_tx_ctrl *hdmi_ctrl)
{
- void *fd = hdmi_tx_get_fd(HDMI_TX_FEAT_CEC_HW);
+ void *fd = NULL;
+
+ if (!hdmi_ctrl)
+ return;
+
+ fd = hdmi_tx_get_fd(HDMI_TX_FEAT_CEC_HW);
- if (!hdmi_ctrl || !fd)
+ if (!fd)
return;
hdmi_cec_device_suspend(fd, hdmi_ctrl->panel_suspend);
@@ -399,7 +425,8 @@ static inline void hdmi_tx_send_cable_notification(
static inline void hdmi_tx_set_audio_switch_node(
struct hdmi_tx_ctrl *hdmi_ctrl, int val)
{
- if (hdmi_ctrl && hdmi_ctrl->ext_audio_data.intf_ops.notify)
+ if (hdmi_ctrl && hdmi_ctrl->ext_audio_data.intf_ops.notify &&
+ !hdmi_tx_is_dvi_mode(hdmi_ctrl))
hdmi_ctrl->ext_audio_data.intf_ops.notify(hdmi_ctrl->ext_pdev,
val);
}
@@ -634,10 +661,11 @@ static int hdmi_tx_update_pixel_clk(struct hdmi_tx_ctrl *hdmi_ctrl)
{
struct dss_module_power *power_data = NULL;
struct mdss_panel_info *pinfo;
+ u32 new_clk_rate = 0;
int rc = 0;
if (!hdmi_ctrl) {
- DEV_ERR("%s: invalid input\n", __func__);
+ pr_err("invalid input\n");
rc = -EINVAL;
goto end;
}
@@ -646,21 +674,25 @@ static int hdmi_tx_update_pixel_clk(struct hdmi_tx_ctrl *hdmi_ctrl)
power_data = &hdmi_ctrl->pdata.power_data[HDMI_TX_CORE_PM];
if (!power_data) {
- DEV_ERR("%s: Error: invalid power data\n", __func__);
+ pr_err("Error: invalid power data\n");
rc = -EINVAL;
goto end;
}
- if (power_data->clk_config->rate == pinfo->clk_rate) {
- rc = -EINVAL;
+ new_clk_rate = hdmi_tx_setup_tmds_clk_rate(pinfo->clk_rate,
+ pinfo->out_format, hdmi_ctrl->panel.dc_enable);
+
+ if (power_data->clk_config->rate == new_clk_rate)
goto end;
- }
- power_data->clk_config->rate = pinfo->clk_rate;
+ power_data->clk_config->rate = new_clk_rate;
- DEV_DBG("%s: rate %ld\n", __func__, power_data->clk_config->rate);
+ pr_debug("rate %ld\n", power_data->clk_config->rate);
- msm_dss_clk_set_rate(power_data->clk_config, power_data->num_clk);
+ rc = msm_dss_clk_set_rate(power_data->clk_config, power_data->num_clk);
+ if (rc < 0)
+ pr_err("failed to set clock rate %lu\n",
+ power_data->clk_config->rate);
end:
return rc;
}
@@ -1212,11 +1244,23 @@ static ssize_t hdmi_tx_sysfs_wta_5v(struct device *dev,
hdmi_ctrl = hdmi_tx_get_drvdata_from_sysfs_dev(dev);
if (!hdmi_ctrl) {
DEV_ERR("%s: invalid input\n", __func__);
- ret = -EINVAL;
- goto end;
+ return -EINVAL;
+ }
+
+ pd = &hdmi_ctrl->pdata.power_data[HDMI_TX_HPD_PM];
+
+ if (!pd || !pd->gpio_config) {
+ DEV_ERR("%s: Error: invalid power data\n", __func__);
+ return -EINVAL;
}
mutex_lock(&hdmi_ctrl->tx_lock);
+ pd = &hdmi_ctrl->pdata.power_data[HDMI_TX_HPD_PM];
+ if (!pd || !pd->gpio_config) {
+ DEV_ERR("%s: Error: invalid power data\n", __func__);
+ ret = -EINVAL;
+ goto end;
+ }
ret = kstrtoint(buf, 10, &read);
if (ret) {
@@ -1302,6 +1346,35 @@ end:
return ret;
}
+static ssize_t hdmi_tx_sysfs_wta_hdmi_ppm(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t count)
+{
+ int ret, ppm;
+ struct hdmi_tx_ctrl *hdmi_ctrl
+ = hdmi_tx_get_drvdata_from_sysfs_dev(dev);
+
+ if (!hdmi_ctrl) {
+ pr_err("invalid input\n");
+ return -EINVAL;
+ }
+
+ mutex_lock(&hdmi_ctrl->tx_lock);
+
+ ret = kstrtoint(buf, 10, &ppm);
+ if (ret) {
+ pr_err("kstrtoint failed. rc=%d\n", ret);
+ goto end;
+ }
+
+ hdmi_tx_update_ppm(hdmi_ctrl, ppm);
+
+ ret = strnlen(buf, PAGE_SIZE);
+ pr_debug("write ppm %d\n", ppm);
+end:
+ mutex_unlock(&hdmi_ctrl->tx_lock);
+ return ret;
+}
+
static DEVICE_ATTR(connected, S_IRUGO, hdmi_tx_sysfs_rda_connected, NULL);
static DEVICE_ATTR(hot_plug, S_IWUSR, NULL, hdmi_tx_sysfs_wta_hot_plug);
static DEVICE_ATTR(sim_mode, S_IRUGO | S_IWUSR, hdmi_tx_sysfs_rda_sim_mode,
@@ -1322,6 +1395,8 @@ static DEVICE_ATTR(s3d_mode, S_IRUGO | S_IWUSR, hdmi_tx_sysfs_rda_s3d_mode,
hdmi_tx_sysfs_wta_s3d_mode);
static DEVICE_ATTR(5v, S_IWUSR, NULL, hdmi_tx_sysfs_wta_5v);
static DEVICE_ATTR(hdr_stream, S_IWUSR, NULL, hdmi_tx_sysfs_wta_hdr_stream);
+static DEVICE_ATTR(hdmi_ppm, S_IRUGO | S_IWUSR, NULL,
+ hdmi_tx_sysfs_wta_hdmi_ppm);
static struct attribute *hdmi_tx_fs_attrs[] = {
&dev_attr_connected.attr,
@@ -1337,6 +1412,7 @@ static struct attribute *hdmi_tx_fs_attrs[] = {
&dev_attr_s3d_mode.attr,
&dev_attr_5v.attr,
&dev_attr_hdr_stream.attr,
+ &dev_attr_hdmi_ppm.attr,
NULL,
};
static struct attribute_group hdmi_tx_fs_attrs_group = {
@@ -2100,6 +2176,7 @@ static int hdmi_tx_init_panel_info(struct hdmi_tx_ctrl *hdmi_ctrl)
pinfo->type = DTV_PANEL;
pinfo->pdest = DISPLAY_3;
pinfo->wait_cycle = 0;
+ pinfo->out_format = MDP_RGB_888;
pinfo->bpp = 24;
pinfo->fb_num = 1;
@@ -2345,7 +2422,6 @@ static void hdmi_tx_set_mode(struct hdmi_tx_ctrl *hdmi_ctrl, u32 power_on)
struct dss_io_data *io = NULL;
/* Defaults: Disable block, HDMI mode */
u32 hdmi_ctrl_reg = BIT(1);
- u32 vbi_pkt_reg;
if (!hdmi_ctrl) {
DEV_ERR("%s: invalid input\n", __func__);
@@ -2383,27 +2459,6 @@ static void hdmi_tx_set_mode(struct hdmi_tx_ctrl *hdmi_ctrl, u32 power_on)
* longer be used
*/
hdmi_ctrl_reg |= BIT(31);
-
- /* enable deep color if supported */
- if (hdmi_tx_dc_support(hdmi_ctrl)) {
- /* GC CD override */
- hdmi_ctrl_reg |= BIT(27);
-
- /* enable deep color for RGB888 30 bits */
- hdmi_ctrl_reg |= BIT(24);
-
- /* Enable GC_CONT and GC_SEND in General Control Packet
- * (GCP) register so that deep color data is
- * transmitted to the sink on every frame, allowing
- * the sink to decode the data correctly.
- *
- * GC_CONT: 0x1 - Send GCP on every frame
- * GC_SEND: 0x1 - Enable GCP Transmission
- */
- vbi_pkt_reg = DSS_REG_R(io, HDMI_VBI_PKT_CTRL);
- vbi_pkt_reg |= BIT(5) | BIT(4);
- DSS_REG_W(io, HDMI_VBI_PKT_CTRL, vbi_pkt_reg);
- }
}
DSS_REG_W(io, HDMI_CTRL, hdmi_ctrl_reg);
@@ -2973,44 +3028,6 @@ static int hdmi_tx_get_cable_status(struct platform_device *pdev, u32 vote)
return hpd;
}
-static int hdmi_tx_setup_tmds_clk_rate(struct hdmi_tx_ctrl *hdmi_ctrl)
-{
- u32 rate = 0;
- struct msm_hdmi_mode_timing_info *timing = NULL;
- u32 rate_ratio;
-
- if (!hdmi_ctrl) {
- DEV_ERR("%s: Bad input parameters\n", __func__);
- goto end;
- }
-
- timing = &hdmi_ctrl->timing;
- if (!timing) {
- DEV_ERR("%s: Invalid timing info\n", __func__);
- goto end;
- }
-
- switch (hdmi_ctrl->panel_data.panel_info.out_format) {
- case MDP_Y_CBCR_H2V2:
- rate_ratio = HDMI_TX_YUV420_24BPP_PCLK_TMDS_CH_RATE_RATIO;
- break;
- case MDP_Y_CBCR_H2V1:
- rate_ratio = HDMI_TX_YUV422_24BPP_PCLK_TMDS_CH_RATE_RATIO;
- break;
- default:
- rate_ratio = HDMI_TX_RGB_24BPP_PCLK_TMDS_CH_RATE_RATIO;
- break;
- }
-
- rate = timing->pixel_freq / rate_ratio;
-
- if (hdmi_tx_dc_support(hdmi_ctrl))
- rate += rate >> 2;
-
-end:
- return rate;
-}
-
static inline bool hdmi_tx_hw_is_cable_connected(struct hdmi_tx_ctrl *hdmi_ctrl)
{
return DSS_REG_R(&hdmi_ctrl->pdata.io[HDMI_TX_CORE_IO],
@@ -3059,7 +3076,12 @@ static void hdmi_tx_hpd_polarity_setup(struct hdmi_tx_ctrl *hdmi_ctrl,
static inline void hdmi_tx_audio_off(struct hdmi_tx_ctrl *hdmi_ctrl)
{
- if (hdmi_ctrl && hdmi_ctrl->audio_ops.off)
+ if (!hdmi_ctrl) {
+ DEV_ERR("%s: invalid input\n", __func__);
+ return;
+ }
+
+ if (hdmi_ctrl->audio_ops.off)
hdmi_ctrl->audio_ops.off(hdmi_ctrl->audio_data);
memset(&hdmi_ctrl->audio_params, 0,
@@ -3069,13 +3091,19 @@ static inline void hdmi_tx_audio_off(struct hdmi_tx_ctrl *hdmi_ctrl)
static int hdmi_tx_power_off(struct hdmi_tx_ctrl *hdmi_ctrl)
{
struct dss_io_data *io = NULL;
- void *pdata = hdmi_tx_get_fd(HDMI_TX_FEAT_PANEL);
+ void *pdata = NULL;
if (!hdmi_ctrl) {
DEV_ERR("%s: invalid input\n", __func__);
return -EINVAL;
}
+ pdata = hdmi_tx_get_fd(HDMI_TX_FEAT_PANEL);
+ if (!pdata) {
+ DEV_ERR("%s: invalid panel data\n", __func__);
+ return -EINVAL;
+ }
+
io = &hdmi_ctrl->pdata.io[HDMI_TX_CORE_IO];
if (!io->base) {
DEV_ERR("%s: Core io is not initialized\n", __func__);
@@ -3117,7 +3145,7 @@ static int hdmi_tx_power_on(struct hdmi_tx_ctrl *hdmi_ctrl)
void *pdata = hdmi_tx_get_fd(HDMI_TX_FEAT_PANEL);
void *edata = hdmi_tx_get_fd(HDMI_TX_FEAT_EDID);
- hdmi_panel_get_vic(&panel_data->panel_info,
+ hdmi_ctrl->vic = hdmi_panel_get_vic(&panel_data->panel_info,
&hdmi_ctrl->ds_data);
if (hdmi_ctrl->vic <= 0) {
@@ -3144,16 +3172,14 @@ static int hdmi_tx_power_on(struct hdmi_tx_ctrl *hdmi_ctrl)
hdmi_ctrl->vic);
hdmi_ctrl->panel.scrambler = hdmi_edid_get_sink_scrambler_support(
edata);
+ hdmi_ctrl->panel.dc_enable = hdmi_tx_dc_support(hdmi_ctrl);
if (hdmi_ctrl->panel_ops.on)
hdmi_ctrl->panel_ops.on(pdata);
- pixel_clk = hdmi_ctrl->timing.pixel_freq * 1000;
-
- if (panel_data->panel_info.out_format == MDP_Y_CBCR_H2V2)
- pixel_clk >>= 1;
- else if (hdmi_tx_dc_support(hdmi_ctrl))
- pixel_clk += pixel_clk >> 2;
+ pixel_clk = hdmi_tx_setup_tmds_clk_rate(hdmi_ctrl->timing.pixel_freq,
+ hdmi_ctrl->panel.pinfo->out_format,
+ hdmi_ctrl->panel.dc_enable) * 1000;
DEV_DBG("%s: setting pixel clk %d\n", __func__, pixel_clk);
@@ -3215,7 +3241,7 @@ static void hdmi_tx_hpd_off(struct hdmi_tx_ctrl *hdmi_ctrl)
hdmi_ctrl->mdss_util->disable_irq(&hdmi_tx_hw);
hdmi_tx_set_mode(hdmi_ctrl, false);
}
-
+ hdmi_tx_config_5v(hdmi_ctrl, false);
rc = hdmi_tx_enable_power(hdmi_ctrl, HDMI_TX_HPD_PM, 0);
if (rc)
DEV_INFO("%s: Failed to disable hpd power. Error=%d\n",
@@ -3568,7 +3594,7 @@ static int hdmi_tx_hdcp_off(struct hdmi_tx_ctrl *hdmi_ctrl)
static void hdmi_tx_update_fps(struct hdmi_tx_ctrl *hdmi_ctrl)
{
- void *pdata = pdata = hdmi_tx_get_fd(HDMI_TX_FEAT_PANEL);
+ void *pdata = NULL;
struct mdss_panel_info *pinfo;
if (!hdmi_ctrl) {
@@ -3576,8 +3602,15 @@ static void hdmi_tx_update_fps(struct hdmi_tx_ctrl *hdmi_ctrl)
return;
}
- pinfo = &hdmi_ctrl->panel_data.panel_info;
+ pdata = hdmi_tx_get_fd(HDMI_TX_FEAT_PANEL);
+ pdata = hdmi_tx_get_fd(HDMI_TX_FEAT_PANEL);
+ if (!pdata) {
+ DEV_ERR("%s: invalid panel data\n", __func__);
+ return;
+ }
+
+ pinfo = &hdmi_ctrl->panel_data.panel_info;
if (!pinfo->dynamic_fps) {
DEV_DBG("%s: Dynamic fps not enabled\n", __func__);
return;
@@ -3614,6 +3647,80 @@ static void hdmi_tx_fps_work(struct work_struct *work)
hdmi_tx_update_fps(hdmi_ctrl);
}
+static u64 hdmi_tx_clip_valid_pclk(struct hdmi_tx_ctrl *hdmi_ctrl, u64 pclk_in)
+{
+ struct msm_hdmi_mode_timing_info timing = {0};
+ u32 pclk_delta, pclk;
+ u64 pclk_clip = pclk_in;
+
+ hdmi_get_supported_mode(&timing,
+ &hdmi_ctrl->ds_data, hdmi_ctrl->vic);
+
+ /* as per standard, 0.5% of deviation is allowed */
+ pclk = timing.pixel_freq * HDMI_KHZ_TO_HZ;
+ pclk_delta = pclk * 5 / 1000;
+
+ if (pclk_in < (pclk - pclk_delta))
+ pclk_clip = pclk - pclk_delta;
+ else if (pclk_in > (pclk + pclk_delta))
+ pclk_clip = pclk + pclk_delta;
+
+ if (pclk_in != pclk_clip)
+ pr_debug("the deviation is too big, so clip pclk from %lld to %lld\n",
+ pclk_in, pclk_clip);
+
+ return pclk_clip;
+}
+
+/**
+ * hdmi_tx_update_ppm() - Update the HDMI pixel clock as per the input ppm
+ *
+ * @ppm: ppm is parts per million multiplied by 1000.
+ * return: 0 on success, non-zero in case of failure.
+ */
+static int hdmi_tx_update_ppm(struct hdmi_tx_ctrl *hdmi_ctrl, s32 ppm)
+{
+ struct mdss_panel_info *pinfo = NULL;
+ u64 cur_pclk, dst_pclk;
+ u64 clip_pclk;
+ int rc = 0;
+
+ if (!hdmi_ctrl) {
+ pr_err("invalid hdmi_ctrl\n");
+ return -EINVAL;
+ }
+
+ pinfo = &hdmi_ctrl->panel_data.panel_info;
+
+ /* only available in case HDMI is up */
+ if (!hdmi_tx_is_panel_on(hdmi_ctrl)) {
+ pr_err("hdmi is not on\n");
+ return -EINVAL;
+ }
+
+ /* get current pclk */
+ cur_pclk = pinfo->clk_rate;
+ /* get desired pclk */
+ dst_pclk = cur_pclk * (1000000000 + ppm);
+ do_div(dst_pclk, 1000000000);
+
+ clip_pclk = hdmi_tx_clip_valid_pclk(hdmi_ctrl, dst_pclk);
+
+ /* update pclk */
+ if (clip_pclk != cur_pclk) {
+ pr_debug("pclk changes from %llu to %llu when ppm is %d\n",
+ cur_pclk, clip_pclk, ppm);
+ pinfo->clk_rate = clip_pclk;
+ rc = hdmi_tx_update_pixel_clk(hdmi_ctrl);
+ if (rc < 0) {
+ pr_err("PPM update failed, reset clock rate\n");
+ pinfo->clk_rate = cur_pclk;
+ }
+ }
+
+ return rc;
+}
+
static int hdmi_tx_evt_handle_register(struct hdmi_tx_ctrl *hdmi_ctrl)
{
int rc = 0;
@@ -3844,6 +3951,13 @@ static int hdmi_tx_evt_handle_deep_color(struct hdmi_tx_ctrl *hdmi_ctrl)
return 0;
}
+static int hdmi_tx_evt_handle_hdmi_ppm(struct hdmi_tx_ctrl *hdmi_ctrl)
+{
+ s32 ppm = (s32) (unsigned long)hdmi_ctrl->evt_arg;
+
+ return hdmi_tx_update_ppm(hdmi_ctrl, ppm);
+}
+
static int hdmi_tx_event_handler(struct mdss_panel_data *panel_data,
int event, void *arg)
{
@@ -4545,6 +4659,7 @@ static int hdmi_tx_init_event_handler(struct hdmi_tx_ctrl *hdmi_ctrl)
handler[MDSS_EVENT_PANEL_OFF] = hdmi_tx_evt_handle_panel_off;
handler[MDSS_EVENT_CLOSE] = hdmi_tx_evt_handle_close;
handler[MDSS_EVENT_DEEP_COLOR] = hdmi_tx_evt_handle_deep_color;
+ handler[MDSS_EVENT_UPDATE_PANEL_PPM] = hdmi_tx_evt_handle_hdmi_ppm;
return 0;
}
diff --git a/drivers/video/fbdev/msm/mdss_hdmi_util.c b/drivers/video/fbdev/msm/mdss_hdmi_util.c
index c9fc8ba8bfdb..89890bcf68df 100644
--- a/drivers/video/fbdev/msm/mdss_hdmi_util.c
+++ b/drivers/video/fbdev/msm/mdss_hdmi_util.c
@@ -15,6 +15,7 @@
#include <linux/io.h>
#include <linux/delay.h>
+#include <linux/msm_mdp.h>
#include "mdss_hdmi_util.h"
#define RESOLUTION_NAME_STR_LEN 30
@@ -26,6 +27,10 @@
#define HDMI_SCDC_UNKNOWN_REGISTER "Unknown register"
+#define HDMI_TX_YUV420_24BPP_PCLK_TMDS_CH_RATE_RATIO 2
+#define HDMI_TX_YUV422_24BPP_PCLK_TMDS_CH_RATE_RATIO 1
+#define HDMI_TX_RGB_24BPP_PCLK_TMDS_CH_RATE_RATIO 1
+
static char res_buf[RESOLUTION_NAME_STR_LEN];
enum trigger_mode {
@@ -738,6 +743,30 @@ ssize_t hdmi_get_video_3d_fmt_2string(u32 format, char *buf, u32 size)
return len;
} /* hdmi_get_video_3d_fmt_2string */
+int hdmi_tx_setup_tmds_clk_rate(u32 pixel_freq, u32 out_format, bool dc_enable)
+{
+ u32 rate_ratio;
+
+ switch (out_format) {
+ case MDP_Y_CBCR_H2V2:
+ rate_ratio = HDMI_TX_YUV420_24BPP_PCLK_TMDS_CH_RATE_RATIO;
+ break;
+ case MDP_Y_CBCR_H2V1:
+ rate_ratio = HDMI_TX_YUV422_24BPP_PCLK_TMDS_CH_RATE_RATIO;
+ break;
+ default:
+ rate_ratio = HDMI_TX_RGB_24BPP_PCLK_TMDS_CH_RATE_RATIO;
+ break;
+ }
+
+ pixel_freq /= rate_ratio;
+
+ if (dc_enable)
+ pixel_freq += pixel_freq >> 2;
+
+ return pixel_freq;
+}
+
static void hdmi_ddc_trigger(struct hdmi_tx_ddc_ctrl *ddc_ctrl,
enum trigger_mode mode, bool seg)
{
diff --git a/drivers/video/fbdev/msm/mdss_hdmi_util.h b/drivers/video/fbdev/msm/mdss_hdmi_util.h
index 8a7e4d1ebafc..4fd659616bcc 100644
--- a/drivers/video/fbdev/msm/mdss_hdmi_util.h
+++ b/drivers/video/fbdev/msm/mdss_hdmi_util.h
@@ -16,6 +16,7 @@
#include "video/msm_hdmi_modes.h"
#include "mdss_panel.h"
+#include "mdss_hdmi_panel.h"
/* HDMI_TX Registers */
#define HDMI_CTRL (0x00000000)
@@ -495,6 +496,7 @@ bool hdmi_is_valid_resv_timing(int mode);
void hdmi_reset_resv_timing_info(void);
int hdmi_panel_get_vic(struct mdss_panel_info *pinfo,
struct hdmi_util_ds_data *ds_data);
+int hdmi_tx_setup_tmds_clk_rate(u32 pixel_freq, u32 out_format, bool dc_enable);
/* todo: Fix this. Right now this is defined in mdss_hdmi_tx.c */
void *hdmi_get_featuredata_from_sysfs_dev(struct device *device, u32 type);
diff --git a/drivers/video/fbdev/msm/mdss_mdp.c b/drivers/video/fbdev/msm/mdss_mdp.c
index 1dae41391795..58e0d9676736 100644
--- a/drivers/video/fbdev/msm/mdss_mdp.c
+++ b/drivers/video/fbdev/msm/mdss_mdp.c
@@ -1139,12 +1139,31 @@ static int mdss_mdp_clk_update(u32 clk_idx, u32 enable)
{
int ret = -ENODEV;
struct clk *clk = mdss_mdp_get_clk(clk_idx);
+ struct mdss_data_type *mdata = mdss_res;
if (clk) {
pr_debug("clk=%d en=%d\n", clk_idx, enable);
if (enable) {
if (clk_idx == MDSS_CLK_MDP_VSYNC)
clk_set_rate(clk, 19200000);
+ if (mdss_has_quirk(mdata, MDSS_QUIRK_MDP_CLK_SET_RATE)
+ && (clk_idx == MDSS_CLK_MDP_CORE)) {
+
+ if (WARN_ON(!mdata->mdp_clk_rate)) {
+ /*
+ * rate should have been set in probe
+ * or during clk scaling; but if this
+ * is not the case, set max clk rate.
+ */
+ pr_warn("set max mdp clk rate:%u\n",
+ mdata->max_mdp_clk_rate);
+ mdss_mdp_set_clk_rate(
+ mdata->max_mdp_clk_rate, true);
+ } else {
+ clk_set_rate(clk, mdata->mdp_clk_rate);
+ }
+ }
+
ret = clk_prepare_enable(clk);
} else {
clk_disable_unprepare(clk);
@@ -1172,7 +1191,7 @@ int mdss_mdp_vsync_clk_enable(int enable, bool locked)
return ret;
}
-void mdss_mdp_set_clk_rate(unsigned long rate)
+void mdss_mdp_set_clk_rate(unsigned long rate, bool locked)
{
struct mdss_data_type *mdata = mdss_res;
unsigned long clk_rate;
@@ -1182,7 +1201,9 @@ void mdss_mdp_set_clk_rate(unsigned long rate)
min_clk_rate = max(rate, mdata->perf_tune.min_mdp_clk);
if (clk) {
- mutex_lock(&mdp_clk_lock);
+
+ if (!locked)
+ mutex_lock(&mdp_clk_lock);
if (min_clk_rate < mdata->max_mdp_clk_rate)
clk_rate = clk_round_rate(clk, min_clk_rate);
else
@@ -1190,12 +1211,15 @@ void mdss_mdp_set_clk_rate(unsigned long rate)
if (IS_ERR_VALUE(clk_rate)) {
pr_err("unable to round rate err=%ld\n", clk_rate);
} else if (clk_rate != clk_get_rate(clk)) {
+
+ mdata->mdp_clk_rate = clk_rate;
if (IS_ERR_VALUE(clk_set_rate(clk, clk_rate)))
pr_err("clk_set_rate failed\n");
else
pr_debug("mdp clk rate=%lu\n", clk_rate);
}
- mutex_unlock(&mdp_clk_lock);
+ if (!locked)
+ mutex_unlock(&mdp_clk_lock);
} else {
pr_err("mdp src clk not setup properly\n");
}
@@ -1779,7 +1803,7 @@ static int mdss_mdp_irq_clk_setup(struct mdss_data_type *mdata)
mdss_mdp_irq_clk_register(mdata, "mnoc_clk", MDSS_CLK_MNOC_AHB);
/* Setting the default clock rate to the max supported.*/
- mdss_mdp_set_clk_rate(mdata->max_mdp_clk_rate);
+ mdss_mdp_set_clk_rate(mdata->max_mdp_clk_rate, false);
pr_debug("mdp clk rate=%ld\n",
mdss_mdp_get_clk_rate(MDSS_CLK_MDP_CORE, false));
@@ -1816,8 +1840,10 @@ static int mdss_mdp_debug_init(struct platform_device *pdev,
mdss_debug_register_dump_range(pdev, dbg_blk, "qcom,regs-dump-mdp",
"qcom,regs-dump-names-mdp", "qcom,regs-dump-xin-id-mdp");
- mdss_debug_register_io("vbif", &mdata->vbif_io, NULL);
- mdss_debug_register_io("vbif_nrt", &mdata->vbif_nrt_io, NULL);
+ if (mdata->vbif_io.base)
+ mdss_debug_register_io("vbif", &mdata->vbif_io, NULL);
+ if (mdata->vbif_nrt_io.base)
+ mdss_debug_register_io("vbif_nrt", &mdata->vbif_nrt_io, NULL);
return 0;
}
@@ -2020,6 +2046,7 @@ static void mdss_mdp_hw_rev_caps_init(struct mdss_data_type *mdata)
mdss_set_quirk(mdata, MDSS_QUIRK_DSC_RIGHT_ONLY_PU);
mdss_set_quirk(mdata, MDSS_QUIRK_DSC_2SLICE_PU_THRPUT);
mdss_set_quirk(mdata, MDSS_QUIRK_MMSS_GDSC_COLLAPSE);
+ mdss_set_quirk(mdata, MDSS_QUIRK_MDP_CLK_SET_RATE);
mdata->has_wb_ubwc = true;
set_bit(MDSS_CAPS_10_BIT_SUPPORTED, mdata->mdss_caps_map);
set_bit(MDSS_CAPS_AVR_SUPPORTED, mdata->mdss_caps_map);
@@ -2409,12 +2436,12 @@ static void __update_sspp_info(struct mdss_mdp_pipe *pipe,
#define SPRINT(fmt, ...) \
(*cnt += scnprintf(buf + *cnt, len - *cnt, fmt, ##__VA_ARGS__))
- for (i = 0; i < pipe_cnt; i++) {
+ for (i = 0; i < pipe_cnt && pipe; i++) {
SPRINT("pipe_num:%d pipe_type:%s pipe_ndx:%d rects:%d pipe_is_handoff:%d display_id:%d ",
pipe->num, type, pipe->ndx, pipe->multirect.max_rects,
pipe->is_handed_off, mdss_mdp_get_display_id(pipe));
SPRINT("fmts_supported:");
- for (j = 0; j < num_bytes && pipe; j++)
+ for (j = 0; j < num_bytes; j++)
SPRINT("%d,", pipe->supported_formats[j]);
SPRINT("\n");
pipe += pipe->multirect.max_rects;
@@ -3391,15 +3418,18 @@ static int mdss_mdp_parse_dt_pipe(struct platform_device *pdev)
mdss_mdp_parse_dt_handler(pdev, "qcom,mdss-pipe-sw-reset-off",
&sw_reset_offset, 1);
if (sw_reset_offset) {
- mdss_mdp_parse_dt_pipe_sw_reset(pdev, sw_reset_offset,
- "qcom,mdss-pipe-vig-sw-reset-map", mdata->vig_pipes,
- mdata->nvig_pipes);
- mdss_mdp_parse_dt_pipe_sw_reset(pdev, sw_reset_offset,
- "qcom,mdss-pipe-rgb-sw-reset-map", mdata->rgb_pipes,
- mdata->nrgb_pipes);
- mdss_mdp_parse_dt_pipe_sw_reset(pdev, sw_reset_offset,
- "qcom,mdss-pipe-dma-sw-reset-map", mdata->dma_pipes,
- mdata->ndma_pipes);
+ if (mdata->vig_pipes)
+ mdss_mdp_parse_dt_pipe_sw_reset(pdev, sw_reset_offset,
+ "qcom,mdss-pipe-vig-sw-reset-map",
+ mdata->vig_pipes, mdata->nvig_pipes);
+ if (mdata->rgb_pipes)
+ mdss_mdp_parse_dt_pipe_sw_reset(pdev, sw_reset_offset,
+ "qcom,mdss-pipe-rgb-sw-reset-map",
+ mdata->rgb_pipes, mdata->nrgb_pipes);
+ if (mdata->dma_pipes)
+ mdss_mdp_parse_dt_pipe_sw_reset(pdev, sw_reset_offset,
+ "qcom,mdss-pipe-dma-sw-reset-map",
+ mdata->dma_pipes, mdata->ndma_pipes);
}
mdata->has_panic_ctrl = of_property_read_bool(pdev->dev.of_node,
@@ -3584,6 +3614,7 @@ static int mdss_mdp_cdm_addr_setup(struct mdss_data_type *mdata,
head[i].base = (mdata->mdss_io.base) + cdm_offsets[i];
atomic_set(&head[i].kref.refcount, 0);
mutex_init(&head[i].lock);
+ init_completion(&head[i].free_comp);
pr_debug("%s: cdm off (%d) = %pK\n", __func__, i, head[i].base);
}
diff --git a/drivers/video/fbdev/msm/mdss_mdp.h b/drivers/video/fbdev/msm/mdss_mdp.h
index e1c3841c82de..20aeabfdf9a4 100644
--- a/drivers/video/fbdev/msm/mdss_mdp.h
+++ b/drivers/video/fbdev/msm/mdss_mdp.h
@@ -22,6 +22,7 @@
#include <linux/notifier.h>
#include <linux/irqreturn.h>
#include <linux/kref.h>
+#include <linux/kthread.h>
#include "mdss.h"
#include "mdss_mdp_hwio.h"
@@ -465,6 +466,9 @@ struct mdss_mdp_ctl {
u32 vsync_cnt;
u32 underrun_cnt;
+ struct work_struct cpu_pm_work;
+ int autorefresh_frame_cnt;
+
u16 width;
u16 height;
u16 border_x_off;
@@ -473,6 +477,7 @@ struct mdss_mdp_ctl {
/* used for WFD */
u32 dst_format;
+ enum mdss_mdp_csc_type csc_type;
struct mult_factor dst_comp_ratio;
u32 clk_rate;
@@ -546,6 +551,7 @@ struct mdss_mdp_ctl {
/* dynamic resolution switch during cont-splash handoff */
bool switch_with_handoff;
struct mdss_mdp_avr_info avr_info;
+ bool commit_in_progress;
};
struct mdss_mdp_mixer {
@@ -927,7 +933,6 @@ struct mdss_overlay_private {
struct sw_sync_timeline *vsync_timeline;
struct mdss_mdp_vsync_handler vsync_retire_handler;
- struct work_struct retire_work;
int retire_cnt;
bool kickoff_released;
u32 cursor_ndx[2];
@@ -939,6 +944,11 @@ struct mdss_overlay_private {
struct mdss_mdp_cwb cwb;
wait_queue_head_t wb_waitq;
atomic_t wb_busy;
+ bool allow_kickoff;
+
+ struct kthread_worker worker;
+ struct kthread_work vsync_work;
+ struct task_struct *thread;
};
struct mdss_mdp_set_ot_params {
@@ -1586,7 +1596,7 @@ u32 mdss_mdp_get_irq_mask(u32 intr_type, u32 intf_num);
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);
+void mdss_mdp_set_clk_rate(unsigned long min_clk_rate, bool locked);
unsigned long mdss_mdp_get_clk_rate(u32 clk_idx, bool locked);
int mdss_mdp_vsync_clk_enable(int enable, bool locked);
void mdss_mdp_clk_ctrl(int enable);
@@ -1910,6 +1920,7 @@ int mdss_mdp_ctl_cmd_set_autorefresh(struct mdss_mdp_ctl *ctl, int frame_cnt);
int mdss_mdp_ctl_cmd_get_autorefresh(struct mdss_mdp_ctl *ctl);
int mdss_mdp_enable_panel_disable_mode(struct msm_fb_data_type *mfd,
bool disable_panel);
+void mdss_mdp_ctl_event_timer(void *data);
int mdss_mdp_pp_get_version(struct mdp_pp_feature_version *version);
int mdss_mdp_layer_pre_commit_cwb(struct msm_fb_data_type *mfd,
struct mdp_layer_commit_v1 *commit);
diff --git a/drivers/video/fbdev/msm/mdss_mdp_cdm.c b/drivers/video/fbdev/msm/mdss_mdp_cdm.c
index e0bf1cdf1361..f1d1bdd301e3 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-2015, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2014-2016, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -26,6 +26,8 @@ static u32 cdm_cdwn2_offsite_h_coeff[] = {0x000b0005, 0x01db01eb, 0x00e40046};
static u32 cdm_cdwn2_cosite_v_coeff[] = {0x00080004};
static u32 cdm_cdwn2_offsite_v_coeff[] = {0x00060002};
+#define VSYNC_TIMEOUT_US 16000
+
/**
* @mdss_mdp_cdm_alloc() - Allocates a cdm block by parsing the list of
* available cdm blocks.
@@ -66,6 +68,7 @@ static void mdss_mdp_cdm_free(struct kref *kref)
if (!cdm)
return;
+ complete_all(&cdm->free_comp);
pr_debug("free cdm_num = %d\n", cdm->num);
}
@@ -84,6 +87,28 @@ struct mdss_mdp_cdm *mdss_mdp_cdm_init(struct mdss_mdp_ctl *ctl, u32 intf_type)
cdm = mdss_mdp_cdm_alloc(mdata);
+ /**
+ * give hdmi interface priority to alloc the cdm block. It will wait
+ * for one vsync cycle to allow wfd to finish its job and try to reserve
+ * the block the again.
+ */
+ if (!cdm && (intf_type == MDP_CDM_CDWN_OUTPUT_HDMI)) {
+ /* always wait for first cdm block */
+ cdm = mdata->cdm_off;
+ if (cdm) {
+ reinit_completion(&cdm->free_comp);
+ /*
+ * no need to check the return status of completion
+ * timeout. Next cdm_alloc call will try to reserve
+ * the cdm block and returns failure if allocation
+ * fails.
+ */
+ wait_for_completion_timeout(&cdm->free_comp,
+ usecs_to_jiffies(VSYNC_TIMEOUT_US));
+ cdm = mdss_mdp_cdm_alloc(mdata);
+ }
+ }
+
if (!cdm) {
pr_err("%s: Unable to allocate cdm\n", __func__);
return ERR_PTR(-EBUSY);
@@ -110,7 +135,9 @@ static int mdss_mdp_cdm_csc_setup(struct mdss_mdp_cdm *cdm,
mdss_mdp_csc_setup(MDSS_MDP_BLOCK_CDM, cdm->num, data->csc_type);
- if (data->csc_type == MDSS_MDP_CSC_RGB2YUV_601L) {
+ if ((data->csc_type == MDSS_MDP_CSC_RGB2YUV_601L) ||
+ (data->csc_type == MDSS_MDP_CSC_RGB2YUV_601FR) ||
+ (data->csc_type == MDSS_MDP_CSC_RGB2YUV_709L)) {
op_mode |= BIT(2); /* DST_DATA_FORMAT = YUV */
op_mode &= ~BIT(1); /* SRC_DATA_FORMAT = RGB */
op_mode |= BIT(0); /* EN = 1 */
@@ -350,17 +377,6 @@ 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_cdm.h b/drivers/video/fbdev/msm/mdss_mdp_cdm.h
index 4515628da0e7..3b7fdced6623 100644
--- a/drivers/video/fbdev/msm/mdss_mdp_cdm.h
+++ b/drivers/video/fbdev/msm/mdss_mdp_cdm.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2014, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2014,2016, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -59,6 +59,7 @@ struct mdss_mdp_cdm {
u32 out_intf;
bool is_bypassed;
struct mdp_cdm_cfg setup;
+ struct completion free_comp;
};
struct mdss_mdp_cdm *mdss_mdp_cdm_init(struct mdss_mdp_ctl *ctl,
diff --git a/drivers/video/fbdev/msm/mdss_mdp_ctl.c b/drivers/video/fbdev/msm/mdss_mdp_ctl.c
index 6b71025229a0..c80d8f47bbb7 100644
--- a/drivers/video/fbdev/msm/mdss_mdp_ctl.c
+++ b/drivers/video/fbdev/msm/mdss_mdp_ctl.c
@@ -22,6 +22,7 @@
#include <linux/clk.h>
#include <linux/bitmap.h>
+#include <soc/qcom/event_timer.h>
#include "mdss_fb.h"
#include "mdss_mdp.h"
#include "mdss_mdp_trace.h"
@@ -2374,7 +2375,7 @@ static void mdss_mdp_ctl_perf_update(struct mdss_mdp_ctl *ctl,
*/
if (update_clk) {
ATRACE_INT("mdp_clk", clk_rate);
- mdss_mdp_set_clk_rate(clk_rate);
+ mdss_mdp_set_clk_rate(clk_rate, false);
pr_debug("update clk rate = %d HZ\n", clk_rate);
}
@@ -2681,12 +2682,122 @@ int mdss_mdp_block_mixer_destroy(struct mdss_mdp_mixer *mixer)
return 0;
}
+int mdss_mdp_display_wakeup_time(struct mdss_mdp_ctl *ctl,
+ ktime_t *wakeup_time)
+{
+ struct mdss_panel_info *pinfo;
+ u64 clk_rate;
+ u32 clk_period;
+ u32 current_line, total_line;
+ u32 time_of_line, time_to_vsync, adjust_line_ns;
+
+ ktime_t current_time = ktime_get();
+
+ if (!ctl->ops.read_line_cnt_fnc)
+ return -EINVAL;
+
+ pinfo = &ctl->panel_data->panel_info;
+ if (!pinfo)
+ return -ENODEV;
+
+ clk_rate = mdss_mdp_get_pclk_rate(ctl);
+
+ clk_rate = DIV_ROUND_UP_ULL(clk_rate, 1000); /* in kHz */
+ if (!clk_rate)
+ return -EINVAL;
+
+ /*
+ * calculate clk_period as pico second to maintain good
+ * accuracy with high pclk rate and this number is in 17 bit
+ * range.
+ */
+ clk_period = DIV_ROUND_UP_ULL(1000000000, clk_rate);
+ if (!clk_period)
+ return -EINVAL;
+
+ time_of_line = (pinfo->lcdc.h_back_porch +
+ pinfo->lcdc.h_front_porch +
+ pinfo->lcdc.h_pulse_width +
+ pinfo->xres) * clk_period;
+
+ time_of_line /= 1000; /* in nano second */
+ if (!time_of_line)
+ return -EINVAL;
+
+ current_line = ctl->ops.read_line_cnt_fnc(ctl);
+
+ total_line = pinfo->lcdc.v_back_porch +
+ pinfo->lcdc.v_front_porch +
+ pinfo->lcdc.v_pulse_width +
+ pinfo->yres;
+
+ if (current_line >= total_line)
+ time_to_vsync = time_of_line * total_line;
+ else
+ time_to_vsync = time_of_line * (total_line - current_line);
+
+ if (pinfo->adjust_timer_delay_ms) {
+ adjust_line_ns = pinfo->adjust_timer_delay_ms
+ * 1000000; /* convert to ns */
+
+ /* Ignore large values of adjust_line_ns\ */
+ if (time_to_vsync > adjust_line_ns)
+ time_to_vsync -= adjust_line_ns;
+ }
+
+ if (!time_to_vsync)
+ return -EINVAL;
+
+ *wakeup_time = ktime_add_ns(current_time, time_to_vsync);
+
+ pr_debug("clk_rate=%lldkHz clk_period=%d cur_line=%d tot_line=%d\n",
+ clk_rate, clk_period, current_line, total_line);
+ pr_debug("time_to_vsync=%d current_time=%d wakeup_time=%d\n",
+ time_to_vsync, (int)ktime_to_ms(current_time),
+ (int)ktime_to_ms(*wakeup_time));
+
+ return 0;
+}
+
+static void __cpu_pm_work_handler(struct work_struct *work)
+{
+ struct mdss_mdp_ctl *ctl =
+ container_of(work, typeof(*ctl), cpu_pm_work);
+ ktime_t wakeup_time;
+ struct mdss_overlay_private *mdp5_data;
+
+ if (!ctl)
+ return;
+
+ if (mdss_mdp_display_wakeup_time(ctl, &wakeup_time))
+ return;
+
+ mdp5_data = mfd_to_mdp5_data(ctl->mfd);
+ activate_event_timer(mdp5_data->cpu_pm_hdl, wakeup_time);
+}
+
+void mdss_mdp_ctl_event_timer(void *data)
+{
+ struct mdss_overlay_private *mdp5_data =
+ (struct mdss_overlay_private *)data;
+ struct mdss_mdp_ctl *ctl = mdp5_data->ctl;
+
+ if (mdp5_data->cpu_pm_hdl && ctl && ctl->autorefresh_frame_cnt)
+ schedule_work(&ctl->cpu_pm_work);
+}
+
int mdss_mdp_ctl_cmd_set_autorefresh(struct mdss_mdp_ctl *ctl, int frame_cnt)
{
int ret = 0;
+ struct mdss_overlay_private *mdp5_data = mfd_to_mdp5_data(ctl->mfd);
if (ctl->panel_data->panel_info.type == MIPI_CMD_PANEL) {
ret = mdss_mdp_cmd_set_autorefresh_mode(ctl, frame_cnt);
+ if (!ret) {
+ ctl->autorefresh_frame_cnt = frame_cnt;
+ if (frame_cnt)
+ mdss_mdp_ctl_event_timer(mdp5_data);
+ }
} else {
pr_err("Mode not supported for this panel\n");
ret = -EINVAL;
@@ -3824,6 +3935,7 @@ struct mdss_mdp_ctl *mdss_mdp_ctl_init(struct mdss_panel_data *pdata,
ctl->intf_type = MDSS_INTF_DSI;
ctl->opmode = MDSS_MDP_CTL_OP_CMD_MODE;
ctl->ops.start_fnc = mdss_mdp_cmd_start;
+ INIT_WORK(&ctl->cpu_pm_work, __cpu_pm_work_handler);
break;
case DTV_PANEL:
ctl->is_video_mode = true;
@@ -5383,8 +5495,13 @@ int mdss_mdp_ctl_update_fps(struct mdss_mdp_ctl *ctl)
(pinfo->dfps_update == DFPS_IMMEDIATE_PORCH_UPDATE_MODE_HFP) ||
(pinfo->dfps_update ==
DFPS_IMMEDIATE_MULTI_UPDATE_MODE_CLK_HFP) ||
+ (pinfo->dfps_update ==
+ DFPS_IMMEDIATE_MULTI_MODE_HFP_CALC_CLK) ||
pinfo->dfps_update == DFPS_IMMEDIATE_CLK_UPDATE_MODE) {
- new_fps = mdss_panel_get_framerate(pinfo);
+ if (pinfo->type == DTV_PANEL)
+ new_fps = pinfo->lcdc.frame_rate;
+ else
+ new_fps = mdss_panel_get_framerate(pinfo);
} else {
new_fps = pinfo->new_fps;
}
@@ -5410,83 +5527,6 @@ exit:
return ret;
}
-int mdss_mdp_display_wakeup_time(struct mdss_mdp_ctl *ctl,
- ktime_t *wakeup_time)
-{
- struct mdss_panel_info *pinfo;
- u64 clk_rate;
- u32 clk_period;
- u32 current_line, total_line;
- u32 time_of_line, time_to_vsync, adjust_line_ns;
-
- ktime_t current_time = ktime_get();
-
- if (!ctl->ops.read_line_cnt_fnc)
- return -ENOSYS;
-
- pinfo = &ctl->panel_data->panel_info;
- if (!pinfo)
- return -ENODEV;
-
- clk_rate = mdss_mdp_get_pclk_rate(ctl);
-
- clk_rate = DIV_ROUND_UP_ULL(clk_rate, 1000); /* in kHz */
- if (!clk_rate)
- return -EINVAL;
-
- /*
- * calculate clk_period as pico second to maintain good
- * accuracy with high pclk rate and this number is in 17 bit
- * range.
- */
- clk_period = DIV_ROUND_UP_ULL(1000000000, clk_rate);
- if (!clk_period)
- return -EINVAL;
-
- time_of_line = (pinfo->lcdc.h_back_porch +
- pinfo->lcdc.h_front_porch +
- pinfo->lcdc.h_pulse_width +
- pinfo->xres) * clk_period;
-
- time_of_line /= 1000; /* in nano second */
- if (!time_of_line)
- return -EINVAL;
-
- current_line = ctl->ops.read_line_cnt_fnc(ctl);
-
- total_line = pinfo->lcdc.v_back_porch +
- pinfo->lcdc.v_front_porch +
- pinfo->lcdc.v_pulse_width +
- pinfo->yres;
-
- if (current_line > total_line)
- return -EINVAL;
-
- time_to_vsync = time_of_line * (total_line - current_line);
-
- if (pinfo->adjust_timer_delay_ms) {
- adjust_line_ns = pinfo->adjust_timer_delay_ms
- * 1000000; /* convert to ns */
-
- /* Ignore large values of adjust_line_ns\ */
- if (time_to_vsync > adjust_line_ns)
- time_to_vsync -= adjust_line_ns;
- }
-
- if (!time_to_vsync)
- return -EINVAL;
-
- *wakeup_time = ktime_add_ns(current_time, time_to_vsync);
-
- pr_debug("clk_rate=%lldkHz clk_period=%d cur_line=%d tot_line=%d\n",
- clk_rate, clk_period, current_line, total_line);
- pr_debug("time_to_vsync=%d current_time=%d wakeup_time=%d\n",
- time_to_vsync, (int)ktime_to_ms(current_time),
- (int)ktime_to_ms(*wakeup_time));
-
- return 0;
-}
-
int mdss_mdp_display_wait4comp(struct mdss_mdp_ctl *ctl)
{
int ret;
@@ -5748,7 +5788,9 @@ int mdss_mdp_display_commit(struct mdss_mdp_ctl *ctl, void *arg,
} else {
sctl_flush_bits = sctl->flush_bits;
}
+ sctl->commit_in_progress = true;
}
+ ctl->commit_in_progress = true;
ctl_flush_bits = ctl->flush_bits;
ATRACE_END("postproc_programming");
@@ -5876,11 +5918,16 @@ int mdss_mdp_display_commit(struct mdss_mdp_ctl *ctl, void *arg,
ATRACE_BEGIN("flush_kickoff");
mdss_mdp_ctl_write(ctl, MDSS_MDP_REG_CTL_FLUSH, ctl_flush_bits);
- if (sctl && sctl_flush_bits) {
- mdss_mdp_ctl_write(sctl, MDSS_MDP_REG_CTL_FLUSH,
- sctl_flush_bits);
- sctl->flush_bits = 0;
+ if (sctl) {
+ if (sctl_flush_bits) {
+ mdss_mdp_ctl_write(sctl, MDSS_MDP_REG_CTL_FLUSH,
+ sctl_flush_bits);
+ sctl->flush_bits = 0;
+ }
+ sctl->commit_in_progress = false;
}
+ ctl->commit_in_progress = false;
+
MDSS_XLOG(ctl->intf_num, ctl_flush_bits, sctl_flush_bits,
split_lm_valid);
wmb();
diff --git a/drivers/video/fbdev/msm/mdss_mdp_intf_cmd.c b/drivers/video/fbdev/msm/mdss_mdp_intf_cmd.c
index a71c7254de7c..4852fc73f040 100644
--- a/drivers/video/fbdev/msm/mdss_mdp_intf_cmd.c
+++ b/drivers/video/fbdev/msm/mdss_mdp_intf_cmd.c
@@ -1267,7 +1267,8 @@ static void mdss_mdp_cmd_pingpong_done(void *arg)
atomic_read(&ctx->koff_cnt));
if (sync_ppdone) {
atomic_inc(&ctx->pp_done_cnt);
- schedule_work(&ctx->pp_done_work);
+ if (!ctl->commit_in_progress)
+ schedule_work(&ctx->pp_done_work);
mdss_mdp_resource_control(ctl,
MDP_RSRC_CTL_EVENT_PP_DONE);
diff --git a/drivers/video/fbdev/msm/mdss_mdp_intf_video.c b/drivers/video/fbdev/msm/mdss_mdp_intf_video.c
index 70b36a08d5ca..5d5515a91572 100644
--- a/drivers/video/fbdev/msm/mdss_mdp_intf_video.c
+++ b/drivers/video/fbdev/msm/mdss_mdp_intf_video.c
@@ -1424,7 +1424,9 @@ static int mdss_mdp_video_config_fps(struct mdss_mdp_ctl *ctl, int new_fps)
pdata->panel_info.dfps_update
== DFPS_IMMEDIATE_PORCH_UPDATE_MODE_HFP ||
pdata->panel_info.dfps_update
- == DFPS_IMMEDIATE_MULTI_UPDATE_MODE_CLK_HFP) {
+ == DFPS_IMMEDIATE_MULTI_UPDATE_MODE_CLK_HFP ||
+ pdata->panel_info.dfps_update
+ == DFPS_IMMEDIATE_MULTI_MODE_HFP_CALC_CLK) {
unsigned long flags;
if (!ctx->timegen_en) {
pr_err("TG is OFF. DFPS mode invalid\n");
@@ -1793,21 +1795,12 @@ static inline bool mdss_mdp_video_need_pixel_drop(u32 vic)
}
static int mdss_mdp_video_cdm_setup(struct mdss_mdp_cdm *cdm,
- struct mdss_panel_info *pinfo)
+ struct mdss_panel_info *pinfo, struct mdss_mdp_format_params *fmt)
{
- struct mdss_mdp_format_params *fmt;
struct mdp_cdm_cfg setup;
- fmt = mdss_mdp_get_format_params(pinfo->out_format);
-
- if (!fmt) {
- pr_err("%s: format %d not supported\n", __func__,
- pinfo->out_format);
- return -EINVAL;
- }
- setup.out_format = pinfo->out_format;
if (fmt->is_yuv)
- setup.csc_type = MDSS_MDP_CSC_RGB2YUV_601L;
+ setup.csc_type = MDSS_MDP_CSC_RGB2YUV_601FR;
else
setup.csc_type = MDSS_MDP_CSC_RGB2RGB;
@@ -1835,6 +1828,7 @@ static int mdss_mdp_video_cdm_setup(struct mdss_mdp_cdm *cdm,
return -EINVAL;
}
+ setup.out_format = pinfo->out_format;
setup.mdp_csc_bit_depth = MDP_CDM_CSC_8BIT;
setup.output_width = pinfo->xres + pinfo->lcdc.xres_pad;
setup.output_height = pinfo->yres + pinfo->lcdc.yres_pad;
@@ -1868,6 +1862,7 @@ static int mdss_mdp_video_ctx_setup(struct mdss_mdp_ctl *ctl,
{
struct intf_timing_params *itp = &ctx->itp;
u32 dst_bpp;
+ struct mdss_mdp_format_params *fmt;
struct mdss_data_type *mdata = ctl->mdata;
struct dsc_desc *dsc = NULL;
u32 hdmi_dp_core;
@@ -1902,17 +1897,32 @@ static int mdss_mdp_video_ctx_setup(struct mdss_mdp_ctl *ctl,
}
if (mdss_mdp_is_cdm_supported(mdata, ctl->intf_type, 0)) {
- ctl->cdm = mdss_mdp_cdm_init(ctl, MDP_CDM_CDWN_OUTPUT_HDMI);
- if (!IS_ERR_OR_NULL(ctl->cdm)) {
- if (mdss_mdp_video_cdm_setup(ctl->cdm, pinfo)) {
- pr_err("%s: setting up cdm failed\n",
- __func__);
+
+ fmt = mdss_mdp_get_format_params(pinfo->out_format);
+ if (!fmt) {
+ pr_err("%s: format %d not supported\n", __func__,
+ pinfo->out_format);
+ return -EINVAL;
+ }
+ if (fmt->is_yuv) {
+ ctl->cdm =
+ mdss_mdp_cdm_init(ctl, MDP_CDM_CDWN_OUTPUT_HDMI);
+ if (!IS_ERR_OR_NULL(ctl->cdm)) {
+ if (mdss_mdp_video_cdm_setup(ctl->cdm,
+ pinfo, fmt)) {
+ pr_err("%s: setting up cdm failed\n",
+ __func__);
+ return -EINVAL;
+ }
+ ctl->flush_bits |= BIT(26);
+ } else {
+ pr_err("%s: failed to initialize cdm\n",
+ __func__);
return -EINVAL;
}
- ctl->flush_bits |= BIT(26);
} else {
- pr_err("%s: failed to initialize cdm\n", __func__);
- return -EINVAL;
+ pr_debug("%s: Format is not YUV,cdm not required\n",
+ __func__);
}
} else {
pr_debug("%s: cdm not supported\n", __func__);
diff --git a/drivers/video/fbdev/msm/mdss_mdp_intf_writeback.c b/drivers/video/fbdev/msm/mdss_mdp_intf_writeback.c
index e6e03e7d54b2..80549908beb6 100644
--- a/drivers/video/fbdev/msm/mdss_mdp_intf_writeback.c
+++ b/drivers/video/fbdev/msm/mdss_mdp_intf_writeback.c
@@ -57,6 +57,7 @@ struct mdss_mdp_writeback_ctx {
u16 width;
u16 height;
u16 frame_rate;
+ enum mdss_mdp_csc_type csc_type;
struct mdss_rect dst_rect;
u32 dnsc_factor_w;
@@ -202,17 +203,10 @@ static int mdss_mdp_writeback_addr_setup(struct mdss_mdp_writeback_ctx *ctx,
}
static int mdss_mdp_writeback_cdm_setup(struct mdss_mdp_writeback_ctx *ctx,
- struct mdss_mdp_cdm *cdm, u32 format)
+ struct mdss_mdp_cdm *cdm, struct mdss_mdp_format_params *fmt)
{
- struct mdss_mdp_format_params *fmt;
struct mdp_cdm_cfg setup;
- fmt = mdss_mdp_get_format_params(format);
- if (!fmt) {
- pr_err("%s: format %d not supported\n", __func__, format);
- return -EINVAL;
- }
-
if (fmt->is_yuv)
setup.csc_type = MDSS_MDP_CSC_RGB2YUV_601L;
else
@@ -237,10 +231,11 @@ static int mdss_mdp_writeback_cdm_setup(struct mdss_mdp_writeback_ctx *ctx,
return -EINVAL;
}
- setup.out_format = format;
+ setup.out_format = fmt->format;
setup.mdp_csc_bit_depth = MDP_CDM_CSC_8BIT;
setup.output_width = ctx->width;
setup.output_height = ctx->height;
+ setup.csc_type = ctx->csc_type;
return mdss_mdp_cdm_setup(cdm, &setup);
}
@@ -260,10 +255,19 @@ static void mdss_mdp_writeback_cwb_overflow(void *arg)
mdp5_data->cwb.valid = 0;
mdss_mdp_irq_disable_nosync(ctx->intr_type, ctx->intf_num);
+ mdss_mdp_set_intr_callback_nosync(ctx->intr_type, ctx->intf_num,
+ NULL, NULL);
+
mdss_mdp_irq_disable_nosync(MDSS_MDP_IRQ_TYPE_CWB_OVERFLOW, CWB_PPB_0);
- if (mdss_mdp_get_split_ctl(ctl))
+ mdss_mdp_set_intr_callback_nosync(MDSS_MDP_IRQ_TYPE_CWB_OVERFLOW,
+ CWB_PPB_0, NULL, NULL);
+
+ if (mdss_mdp_get_split_ctl(ctl)) {
mdss_mdp_irq_disable_nosync(MDSS_MDP_IRQ_TYPE_CWB_OVERFLOW,
- CWB_PPB_1);
+ CWB_PPB_1);
+ mdss_mdp_set_intr_callback_nosync(
+ MDSS_MDP_IRQ_TYPE_CWB_OVERFLOW, CWB_PPB_1, NULL, NULL);
+ }
if (!atomic_add_unless(&mdp5_data->wb_busy, -1, 0))
pr_err("Invalid state for WB\n");
@@ -285,10 +289,20 @@ static void mdss_mdp_writeback_cwb_intr_done(void *arg)
mdp5_data->cwb.valid = 0;
mdss_mdp_irq_disable_nosync(ctx->intr_type, ctx->intf_num);
- mdss_mdp_irq_disable_nosync(MDSS_MDP_IRQ_TYPE_CWB_OVERFLOW, CWB_PPB_0);
- if (mdss_mdp_get_split_ctl(ctl))
+ mdss_mdp_set_intr_callback_nosync(ctx->intr_type, ctx->intf_num,
+ NULL, NULL);
+
+ mdss_mdp_irq_disable_nosync(MDSS_MDP_IRQ_TYPE_CWB_OVERFLOW,
+ CWB_PPB_0);
+ mdss_mdp_set_intr_callback_nosync(MDSS_MDP_IRQ_TYPE_CWB_OVERFLOW,
+ CWB_PPB_0, NULL, NULL);
+
+ if (mdss_mdp_get_split_ctl(ctl)) {
mdss_mdp_irq_disable_nosync(MDSS_MDP_IRQ_TYPE_CWB_OVERFLOW,
- CWB_PPB_1);
+ CWB_PPB_1);
+ mdss_mdp_set_intr_callback_nosync(
+ MDSS_MDP_IRQ_TYPE_CWB_OVERFLOW, CWB_PPB_1, NULL, NULL);
+ }
queue_work(mdp5_data->cwb.cwb_work_queue, &mdp5_data->cwb.cwb_work);
@@ -353,10 +367,9 @@ static int mdss_mdp_writeback_format_setup(struct mdss_mdp_writeback_ctx *ctx,
chroma_samp = fmt->chroma_sample;
if (ctl->cdm) {
-
- rc = mdss_mdp_writeback_cdm_setup(ctx, ctl->cdm, format);
+ rc = mdss_mdp_writeback_cdm_setup(ctx, ctl->cdm, fmt);
if (rc) {
- pr_err("%s: CDM configuration failed with error %d\n",
+ pr_err("%s: CDM config failed with error %d\n",
__func__, rc);
return rc;
}
@@ -495,21 +508,20 @@ int mdss_mdp_writeback_prepare_cwb(struct mdss_mdp_ctl *ctl,
pr_err("cwb writeback data setup error\n");
return ret;
}
- mdss_mdp_irq_enable(ctx->intr_type, ctx->intf_num);
mdss_mdp_set_intr_callback(ctx->intr_type, ctx->intf_num,
mdss_mdp_writeback_cwb_intr_done, ctl);
+ mdss_mdp_irq_enable(ctx->intr_type, ctx->intf_num);
- mdss_mdp_irq_enable(MDSS_MDP_IRQ_TYPE_CWB_OVERFLOW, ctl->intf_num);
mdss_mdp_set_intr_callback(MDSS_MDP_IRQ_TYPE_CWB_OVERFLOW,
- ctl->intf_num,
- mdss_mdp_writeback_cwb_overflow, ctl);
+ CWB_PPB_0, mdss_mdp_writeback_cwb_overflow, ctl);
+ mdss_mdp_irq_enable(MDSS_MDP_IRQ_TYPE_CWB_OVERFLOW, CWB_PPB_0);
+
sctl = mdss_mdp_get_split_ctl(ctl);
if (sctl) {
- mdss_mdp_irq_enable(MDSS_MDP_IRQ_TYPE_CWB_OVERFLOW,
- sctl->intf_num);
mdss_mdp_set_intr_callback(MDSS_MDP_IRQ_TYPE_CWB_OVERFLOW,
- sctl->intf_num,
- mdss_mdp_writeback_cwb_overflow, sctl);
+ CWB_PPB_1, mdss_mdp_writeback_cwb_overflow,
+ sctl);
+ mdss_mdp_irq_enable(MDSS_MDP_IRQ_TYPE_CWB_OVERFLOW, CWB_PPB_1);
}
if (test_bit(MDSS_QOS_WB2_WRITE_GATHER_EN, ctl->mdata->mdss_qos_map))
@@ -544,6 +556,7 @@ static int mdss_mdp_writeback_prepare_wfd(struct mdss_mdp_ctl *ctl, void *arg)
ctx->width = ctl->width;
ctx->height = ctl->height;
ctx->frame_rate = ctl->frame_rate;
+ ctx->csc_type = ctl->csc_type;
ctx->dst_rect.x = 0;
ctx->dst_rect.y = 0;
ctx->dst_rect.w = ctx->width;
@@ -1014,6 +1027,7 @@ int mdss_mdp_writeback_start(struct mdss_mdp_ctl *ctl)
struct mdss_mdp_writeback_ctx *ctx;
struct mdss_mdp_writeback *wb;
u32 mixer_type = MDSS_MDP_MIXER_TYPE_UNUSED;
+ struct mdss_mdp_format_params *fmt = NULL;
bool is_rot;
pr_debug("start ctl=%d\n", ctl->num);
@@ -1037,6 +1051,10 @@ int mdss_mdp_writeback_start(struct mdss_mdp_ctl *ctl)
return -EINVAL;
}
+ fmt = mdss_mdp_get_format_params(ctl->dst_format);
+ if (!fmt)
+ return -EINVAL;
+
is_rot = (ctx->type == MDSS_MDP_WRITEBACK_TYPE_ROTATOR) ? true : false;
if (ctl->mixer_left) {
@@ -1050,15 +1068,13 @@ int mdss_mdp_writeback_start(struct mdss_mdp_ctl *ctl)
}
if (mdss_mdp_is_cdm_supported(ctl->mdata, ctl->intf_type,
- mixer_type)) {
+ mixer_type) && fmt->is_yuv) {
ctl->cdm = mdss_mdp_cdm_init(ctl, MDP_CDM_CDWN_OUTPUT_WB);
if (IS_ERR_OR_NULL(ctl->cdm)) {
- pr_err("%s failed to init cdm\n", __func__);
+ pr_err("cdm block already in use\n");
+ ctl->cdm = NULL;
return -EBUSY;
}
- } else {
- ctl->cdm = NULL;
- pr_debug("%s: cdm not supported\n", __func__);
}
ctl->priv_data = ctx;
ctx->wb_num = wb->num;
diff --git a/drivers/video/fbdev/msm/mdss_mdp_layer.c b/drivers/video/fbdev/msm/mdss_mdp_layer.c
index 73350b3a5a6f..3fc8e3883250 100644
--- a/drivers/video/fbdev/msm/mdss_mdp_layer.c
+++ b/drivers/video/fbdev/msm/mdss_mdp_layer.c
@@ -71,6 +71,7 @@ static void mdss_mdp_disable_destination_scaler_setup(struct mdss_mdp_ctl *ctl)
{
struct mdss_data_type *mdata = ctl->mdata;
struct mdss_panel_info *pinfo = &ctl->panel_data->panel_info;
+ struct mdss_mdp_ctl *split_ctl;
if (test_bit(MDSS_CAPS_DEST_SCALER, mdata->mdss_caps_map)) {
if (ctl->mixer_left && ctl->mixer_right &&
@@ -80,9 +81,11 @@ static void mdss_mdp_disable_destination_scaler_setup(struct mdss_mdp_ctl *ctl)
/*
* DUAL mode disable
*/
+ split_ctl = mdss_mdp_get_split_ctl(ctl);
ctl->mixer_left->width = get_panel_width(ctl);
ctl->mixer_left->height = get_panel_yres(pinfo);
- ctl->mixer_left->width /= 2;
+ if (!split_ctl)
+ ctl->mixer_left->width /= 2;
ctl->mixer_right->width = ctl->mixer_left->width;
ctl->mixer_right->height = ctl->mixer_left->height;
ctl->mixer_left->roi = (struct mdss_rect) { 0, 0,
@@ -2136,7 +2139,7 @@ static int __validate_multirect(struct msm_fb_data_type *mfd,
static int __validate_layers(struct msm_fb_data_type *mfd,
struct file *file, struct mdp_layer_commit_v1 *commit)
{
- int ret, i;
+ int ret, i = 0;
int rec_ndx[MDSS_MDP_PIPE_MAX_RECTS] = { 0 };
int rec_release_ndx[MDSS_MDP_PIPE_MAX_RECTS] = { 0 };
int rec_destroy_ndx[MDSS_MDP_PIPE_MAX_RECTS] = { 0 };
@@ -2660,13 +2663,22 @@ int mdss_mdp_layer_pre_commit(struct msm_fb_data_type *mfd,
if (mdp5_data->cwb.valid) {
struct sync_fence *retire_fence = NULL;
+ if (!commit->output_layer) {
+ pr_err("cwb request without setting output layer\n");
+ goto map_err;
+ }
+
retire_fence = __create_fence(mfd,
&mdp5_data->cwb.cwb_sync_pt_data,
MDSS_MDP_CWB_RETIRE_FENCE,
&commit->output_layer->buffer.fence, 0);
if (IS_ERR_OR_NULL(retire_fence)) {
pr_err("failed to handle cwb fence");
+ goto map_err;
}
+
+ sync_fence_install(retire_fence,
+ commit->output_layer->buffer.fence);
}
map_err:
diff --git a/drivers/video/fbdev/msm/mdss_mdp_overlay.c b/drivers/video/fbdev/msm/mdss_mdp_overlay.c
index 298b8743f0a6..bf8130b35a57 100644
--- a/drivers/video/fbdev/msm/mdss_mdp_overlay.c
+++ b/drivers/video/fbdev/msm/mdss_mdp_overlay.c
@@ -1404,14 +1404,6 @@ int mdss_mdp_overlay_start(struct msm_fb_data_type *mfd)
mdss_iommu_ctrl(0);
}
- /* Restore any previously configured PP features by resetting the dirty
- * bits for enabled features. The dirty bits will be consumed during the
- * first display commit when the PP hardware blocks are updated
- */
- rc = mdss_mdp_pp_resume(mfd);
- if (rc && (rc != -EPERM) && (rc != -ENODEV))
- pr_err("PP resume err %d\n", rc);
-
/*
* Increment the overlay active count prior to calling ctl_start.
* This is needed to ensure that if idle power collapse kicks in
@@ -1427,6 +1419,14 @@ int mdss_mdp_overlay_start(struct msm_fb_data_type *mfd)
goto ctl_error;
}
+ /* Restore any previously configured PP features by resetting the dirty
+ * bits for enabled features. The dirty bits will be consumed during the
+ * first display commit when the PP hardware blocks are updated
+ */
+ rc = mdss_mdp_pp_resume(mfd);
+ if (rc && (rc != -EPERM) && (rc != -ENODEV))
+ pr_err("PP resume err %d\n", rc);
+
rc = mdss_mdp_splash_cleanup(mfd, true);
if (!rc)
goto end;
@@ -1453,6 +1453,21 @@ static void mdss_mdp_overlay_update_pm(struct mdss_overlay_private *mdp5_data)
activate_event_timer(mdp5_data->cpu_pm_hdl, wakeup_time);
}
+static void __unstage_pipe_and_clean_buf(struct msm_fb_data_type *mfd,
+ struct mdss_mdp_pipe *pipe, struct mdss_mdp_data *buf)
+{
+
+ pr_debug("unstaging pipe:%d rect:%d buf:%d\n",
+ pipe->num, pipe->multirect.num, !buf);
+ MDSS_XLOG(pipe->num, pipe->multirect.num, !buf);
+ mdss_mdp_mixer_pipe_unstage(pipe, pipe->mixer_left);
+ mdss_mdp_mixer_pipe_unstage(pipe, pipe->mixer_right);
+ pipe->dirty = true;
+
+ if (buf)
+ __pipe_buf_mark_cleanup(mfd, buf);
+}
+
static int __overlay_queue_pipes(struct msm_fb_data_type *mfd)
{
struct mdss_overlay_private *mdp5_data = mfd_to_mdp5_data(mfd);
@@ -1573,14 +1588,36 @@ static int __overlay_queue_pipes(struct msm_fb_data_type *mfd)
ret = mdss_mdp_pipe_queue_data(pipe, buf);
if (IS_ERR_VALUE(ret)) {
- pr_warn("Unable to queue data for pnum=%d\n",
- pipe->num);
- mdss_mdp_mixer_pipe_unstage(pipe, pipe->mixer_left);
- mdss_mdp_mixer_pipe_unstage(pipe, pipe->mixer_right);
- pipe->dirty = true;
+ pr_warn("Unable to queue data for pnum=%d rect=%d\n",
+ pipe->num, pipe->multirect.num);
- if (buf)
- __pipe_buf_mark_cleanup(mfd, buf);
+ /*
+ * If we fail for a multi-rect pipe, unstage both rects
+ * so we don't leave the pipe configured in multi-rect
+ * mode with only one rectangle staged.
+ */
+ if (pipe->multirect.mode !=
+ MDSS_MDP_PIPE_MULTIRECT_NONE) {
+ struct mdss_mdp_pipe *next_pipe =
+ (struct mdss_mdp_pipe *)
+ pipe->multirect.next;
+
+ if (next_pipe) {
+ struct mdss_mdp_data *next_buf =
+ list_first_entry_or_null(
+ &next_pipe->buf_queue,
+ struct mdss_mdp_data,
+ pipe_list);
+
+ __unstage_pipe_and_clean_buf(mfd,
+ next_pipe, next_buf);
+ } else {
+ pr_warn("cannot find rect pnum=%d\n",
+ pipe->num);
+ }
+ }
+
+ __unstage_pipe_and_clean_buf(mfd, pipe, buf);
}
}
@@ -1886,6 +1923,8 @@ static void __restore_pipe(struct mdss_mdp_pipe *pipe)
pipe->dst.y = pipe->layer.dst_rect.y;
pipe->dst.w = pipe->layer.dst_rect.w;
pipe->dst.h = pipe->layer.dst_rect.h;
+
+ pipe->restore_roi = false;
}
/**
@@ -1909,7 +1948,6 @@ static int __crop_adjust_pipe_rect(struct mdss_mdp_pipe *pipe,
u32 roi_y_pos;
int ret = 0;
- pipe->restore_roi = false;
if (mdss_rect_overlap_check(&pipe->dst, &dual_roi->first_roi)) {
mdss_mdp_crop_rect(&pipe->src, &pipe->dst,
&dual_roi->first_roi, false);
@@ -2055,6 +2093,13 @@ static void __validate_and_set_roi(struct msm_fb_data_type *mfd,
}
list_for_each_entry(pipe, &mdp5_data->pipes_used, list) {
+ /*
+ * Restore the pipe src/dst ROI if it was altered
+ * in the previous kickoff.
+ */
+ if (pipe->restore_roi)
+ __restore_pipe(pipe);
+
pr_debug("pipe:%d src:{%d,%d,%d,%d} dst:{%d,%d,%d,%d}\n",
pipe->num, pipe->src.x, pipe->src.y,
pipe->src.w, pipe->src.h, pipe->dst.x,
@@ -3027,16 +3072,23 @@ static void cache_initial_timings(struct mdss_panel_data *pdata)
* This value will change dynamically once the
* actual dfps update happen in hw.
*/
- pdata->panel_info.current_fps =
- mdss_panel_get_framerate(&pdata->panel_info);
-
+ if (pdata->panel_info.type == DTV_PANEL)
+ pdata->panel_info.current_fps =
+ pdata->panel_info.lcdc.frame_rate;
+ else
+ pdata->panel_info.current_fps =
+ mdss_panel_get_framerate(&pdata->panel_info);
/*
* Keep the initial fps and porch values for this panel before
* any dfps update happen, this is to prevent losing precision
* in further calculations.
*/
- pdata->panel_info.default_fps =
- mdss_panel_get_framerate(&pdata->panel_info);
+ if (pdata->panel_info.type == DTV_PANEL)
+ pdata->panel_info.default_fps =
+ pdata->panel_info.lcdc.frame_rate;
+ else
+ pdata->panel_info.default_fps =
+ mdss_panel_get_framerate(&pdata->panel_info);
if (pdata->panel_info.dfps_update ==
DFPS_IMMEDIATE_PORCH_UPDATE_MODE_VFP) {
@@ -3048,7 +3100,9 @@ static void cache_initial_timings(struct mdss_panel_data *pdata)
} else if (pdata->panel_info.dfps_update ==
DFPS_IMMEDIATE_PORCH_UPDATE_MODE_HFP ||
pdata->panel_info.dfps_update ==
- DFPS_IMMEDIATE_MULTI_UPDATE_MODE_CLK_HFP) {
+ DFPS_IMMEDIATE_MULTI_UPDATE_MODE_CLK_HFP ||
+ pdata->panel_info.dfps_update ==
+ DFPS_IMMEDIATE_MULTI_MODE_HFP_CALC_CLK) {
pdata->panel_info.saved_total =
mdss_panel_get_htotal(&pdata->panel_info, true);
pdata->panel_info.saved_fporch =
@@ -3117,8 +3171,25 @@ static void dfps_update_panel_params(struct mdss_panel_data *pdata,
pdata->panel_info.lcdc.h_pulse_width = data->hpw;
pdata->panel_info.clk_rate = data->clk_rate;
+ if (pdata->panel_info.type == DTV_PANEL)
+ pdata->panel_info.clk_rate *= 1000;
dfps_update_fps(&pdata->panel_info, new_fps);
+ } else if (pdata->panel_info.dfps_update ==
+ DFPS_IMMEDIATE_MULTI_MODE_HFP_CALC_CLK) {
+
+ pr_debug("hfp=%d, hbp=%d, hpw=%d, clk=%d, fps=%d\n",
+ data->hfp, data->hbp, data->hpw,
+ data->clk_rate, data->fps);
+
+ pdata->panel_info.lcdc.h_front_porch = data->hfp;
+ pdata->panel_info.lcdc.h_back_porch = data->hbp;
+ pdata->panel_info.lcdc.h_pulse_width = data->hpw;
+
+ pdata->panel_info.clk_rate = data->clk_rate;
+
+ dfps_update_fps(&pdata->panel_info, new_fps);
+ mdss_panel_update_clk_rate(&pdata->panel_info, new_fps);
} else {
dfps_update_fps(&pdata->panel_info, new_fps);
mdss_panel_update_clk_rate(&pdata->panel_info, new_fps);
@@ -3193,7 +3264,9 @@ static ssize_t dynamic_fps_sysfs_wta_dfps(struct device *dev,
}
if (pdata->panel_info.dfps_update ==
- DFPS_IMMEDIATE_MULTI_UPDATE_MODE_CLK_HFP) {
+ DFPS_IMMEDIATE_MULTI_UPDATE_MODE_CLK_HFP ||
+ pdata->panel_info.dfps_update ==
+ DFPS_IMMEDIATE_MULTI_MODE_HFP_CALC_CLK) {
if (sscanf(buf, "%u %u %u %u %u",
&data.hfp, &data.hbp, &data.hpw,
&data.clk_rate, &data.fps) != 5) {
@@ -3208,7 +3281,10 @@ static ssize_t dynamic_fps_sysfs_wta_dfps(struct device *dev,
}
}
- panel_fps = mdss_panel_get_framerate(&pdata->panel_info);
+ if (pdata->panel_info.type == DTV_PANEL)
+ panel_fps = pdata->panel_info.lcdc.frame_rate;
+ else
+ panel_fps = mdss_panel_get_framerate(&pdata->panel_info);
if (data.fps == panel_fps) {
pr_debug("%s: FPS is already %d\n",
@@ -3271,7 +3347,7 @@ static ssize_t mdss_mdp_lineptr_show_event(struct device *dev,
if (!mdp5_data->ctl ||
(!mdp5_data->ctl->panel_data->panel_info.cont_splash_enabled
&& !mdss_mdp_ctl_is_power_on(mdp5_data->ctl)))
- return -EAGAIN;
+ return -EPERM;
lineptr_ticks = ktime_to_ns(mdp5_data->lineptr_time);
@@ -3292,7 +3368,7 @@ static ssize_t mdss_mdp_lineptr_show_value(struct device *dev,
if (!mdp5_data->ctl ||
(!mdp5_data->ctl->panel_data->panel_info.cont_splash_enabled
&& !mdss_mdp_ctl_is_power_on(mdp5_data->ctl)))
- return -EAGAIN;
+ return -EPERM;
lineptr_val = mfd->panel_info->te.wr_ptr_irq;
@@ -3728,6 +3804,9 @@ static ssize_t mdss_mdp_misr_store(struct device *dev,
return rc;
}
+ req.block_id = DISPLAY_MISR_MAX;
+ sreq.block_id = DISPLAY_MISR_MAX;
+
pr_debug("intf_type:%d enable:%d\n", ctl->intf_type, enable_misr);
if (ctl->intf_type == MDSS_INTF_DSI) {
@@ -4365,9 +4444,7 @@ static int mdss_bl_scale_config(struct msm_fb_data_type *mfd,
mutex_lock(&mfd->bl_lock);
curr_bl = mfd->bl_level;
mfd->bl_scale = data->scale;
- mfd->bl_min_lvl = data->min_lvl;
- pr_debug("update scale = %d, min_lvl = %d\n", mfd->bl_scale,
- mfd->bl_min_lvl);
+ pr_debug("update scale = %d\n", mfd->bl_scale);
/* update current backlight to use new scaling*/
mdss_fb_set_backlight(mfd, curr_bl);
@@ -4577,6 +4654,20 @@ static int mdss_fb_set_metadata(struct msm_fb_data_type *mfd,
return ret;
}
+static int mdss_fb_set_panel_ppm(struct msm_fb_data_type *mfd, s32 ppm)
+{
+ struct mdss_mdp_ctl *ctl = mfd_to_ctl(mfd);
+ int ret = 0;
+
+ if (!ctl)
+ return -EPERM;
+
+ ret = mdss_mdp_ctl_intf_event(ctl, MDSS_EVENT_UPDATE_PANEL_PPM,
+ (void *) (unsigned long) ppm,
+ CTL_INTF_EVENT_FLAG_DEFAULT);
+ return ret;
+}
+
static int mdss_fb_get_hw_caps(struct msm_fb_data_type *mfd,
struct mdss_hw_caps *caps)
{
@@ -5123,6 +5214,16 @@ static int mdss_mdp_overlay_ioctl_handler(struct msm_fb_data_type *mfd,
}
ret = mdss_mdp_set_cfg(mfd, &cfg);
break;
+ case MSMFB_MDP_SET_PANEL_PPM:
+ ret = copy_from_user(&val, argp, sizeof(val));
+ if (ret) {
+ pr_err("copy failed MSMFB_MDP_SET_PANEL_PPM ret %d\n",
+ ret);
+ ret = -EFAULT;
+ break;
+ }
+ ret = mdss_fb_set_panel_ppm(mfd, val);
+ break;
default:
break;
@@ -5487,7 +5588,7 @@ ctl_stop:
* retire_signal api checks for retire_cnt with sync_mutex lock.
*/
- flush_work(&mdp5_data->retire_work);
+ flush_kthread_work(&mdp5_data->vsync_work);
}
mutex_lock(&mdp5_data->ov_lock);
@@ -5690,13 +5791,13 @@ static void __vsync_retire_handle_vsync(struct mdss_mdp_ctl *ctl, ktime_t t)
}
mdp5_data = mfd_to_mdp5_data(mfd);
- schedule_work(&mdp5_data->retire_work);
+ queue_kthread_work(&mdp5_data->worker, &mdp5_data->vsync_work);
}
-static void __vsync_retire_work_handler(struct work_struct *work)
+static void __vsync_retire_work_handler(struct kthread_work *work)
{
struct mdss_overlay_private *mdp5_data =
- container_of(work, typeof(*mdp5_data), retire_work);
+ container_of(work, typeof(*mdp5_data), vsync_work);
if (!mdp5_data->ctl || !mdp5_data->ctl->mfd)
return;
@@ -5796,6 +5897,7 @@ static int __vsync_retire_setup(struct msm_fb_data_type *mfd)
{
struct mdss_overlay_private *mdp5_data = mfd_to_mdp5_data(mfd);
char name[24];
+ struct sched_param param = { .sched_priority = 5 };
snprintf(name, sizeof(name), "mdss_fb%d_retire", mfd->index);
mdp5_data->vsync_timeline = sw_sync_timeline_create(name);
@@ -5803,12 +5905,26 @@ static int __vsync_retire_setup(struct msm_fb_data_type *mfd)
pr_err("cannot vsync create time line");
return -ENOMEM;
}
+
+ init_kthread_worker(&mdp5_data->worker);
+ init_kthread_work(&mdp5_data->vsync_work, __vsync_retire_work_handler);
+
+ mdp5_data->thread = kthread_run(kthread_worker_fn,
+ &mdp5_data->worker, "vsync_retire_work");
+
+ if (IS_ERR(mdp5_data->thread)) {
+ pr_err("unable to start vsync thread\n");
+ mdp5_data->thread = NULL;
+ return -ENOMEM;
+ }
+
+ sched_setscheduler(mdp5_data->thread, SCHED_FIFO, &param);
+
mfd->mdp_sync_pt_data.get_retire_fence = __vsync_retire_get_fence;
mdp5_data->vsync_retire_handler.vsync_handler =
__vsync_retire_handle_vsync;
mdp5_data->vsync_retire_handler.cmd_post_flush = false;
- INIT_WORK(&mdp5_data->retire_work, __vsync_retire_work_handler);
return 0;
}
@@ -6111,8 +6227,8 @@ int mdss_mdp_overlay_init(struct msm_fb_data_type *mfd)
/* Adding event timer only for primary panel */
if ((mfd->index == 0) && (mfd->panel_info->type != WRITEBACK_PANEL)) {
- mdp5_data->cpu_pm_hdl = add_event_timer(mdss_irq->irq, NULL,
- (void *)mdp5_data);
+ mdp5_data->cpu_pm_hdl = add_event_timer(mdss_irq->irq,
+ mdss_mdp_ctl_event_timer, (void *)mdp5_data);
if (!mdp5_data->cpu_pm_hdl)
pr_warn("%s: unable to add event timer\n", __func__);
}
diff --git a/drivers/video/fbdev/msm/mdss_mdp_pipe.c b/drivers/video/fbdev/msm/mdss_mdp_pipe.c
index bcf5309993b9..4d42e42035c3 100644
--- a/drivers/video/fbdev/msm/mdss_mdp_pipe.c
+++ b/drivers/video/fbdev/msm/mdss_mdp_pipe.c
@@ -1114,6 +1114,7 @@ static void mdss_mdp_init_pipe_params(struct mdss_mdp_pipe *pipe)
pipe->is_right_blend = false;
pipe->src_split_req = false;
pipe->bwc_mode = 0;
+ pipe->restore_roi = false;
pipe->mfd = NULL;
pipe->mixer_left = pipe->mixer_right = NULL;
@@ -2599,7 +2600,8 @@ static int mdss_mdp_set_ts_pipe(struct mdss_mdp_pipe *pipe)
__get_ordered_rects(pipe, &low_pipe, &high_pipe);
ts_count_low = __get_ts_count(low_pipe, mixer, true);
- ts_count_high = __get_ts_count(high_pipe, mixer, false);
+ if (high_pipe != NULL)
+ ts_count_high = __get_ts_count(high_pipe, mixer, false);
ts_bytes = __get_ts_bytes(pipe, mixer);
if (low_pipe->multirect.num == MDSS_MDP_PIPE_RECT0) {
@@ -2702,8 +2704,8 @@ int mdss_mdp_pipe_queue_data(struct mdss_mdp_pipe *pipe,
if (ret) {
pr_err("pipe pp setup error for pnum=%d\n", pipe->num);
- MDSS_XLOG(pipe->num, pipe->mixer_left->num,
- pipe->play_cnt, 0xbad);
+ MDSS_XLOG(pipe->num, pipe->multirect.num,
+ pipe->mixer_left->num, pipe->play_cnt, 0xbad);
goto done;
}
@@ -2714,13 +2716,14 @@ int mdss_mdp_pipe_queue_data(struct mdss_mdp_pipe *pipe,
pipe->params_changed = 0;
mdss_mdp_pipe_solidfill_setup(pipe);
- MDSS_XLOG(pipe->num, pipe->mixer_left->num, pipe->play_cnt,
- 0x111);
+ MDSS_XLOG(pipe->num, pipe->multirect.num, pipe->mixer_left->num,
+ pipe->play_cnt, 0x111);
goto update_nobuf;
}
- MDSS_XLOG(pipe->num, pipe->mixer_left->num, pipe->play_cnt, 0x222);
+ 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_mdp_pp.c b/drivers/video/fbdev/msm/mdss_mdp_pp.c
index 248492b28ce2..5a8438caba4b 100644
--- a/drivers/video/fbdev/msm/mdss_mdp_pp.c
+++ b/drivers/video/fbdev/msm/mdss_mdp_pp.c
@@ -2519,7 +2519,9 @@ static int pp_dspp_setup(u32 disp_num, struct mdss_mdp_mixer *mixer)
DSPP);
}
- pp_dspp_opmode_config(ctl, dspp_num, pp_sts, mdata->mdp_rev, &opmode);
+ if (pp_sts != NULL)
+ pp_dspp_opmode_config(ctl, dspp_num, pp_sts, mdata->mdp_rev,
+ &opmode);
if (ad_hw) {
mutex_lock(&ad->lock);
@@ -6984,9 +6986,6 @@ static int is_valid_calib_addr(void *addr, u32 operation)
int ret = 0;
char __iomem *ptr = addr;
char __iomem *mixer_base = mdss_res->mixer_intf->base;
- char __iomem *rgb_base = mdss_res->rgb_pipes->base;
- char __iomem *dma_base = mdss_res->dma_pipes->base;
- char __iomem *vig_base = mdss_res->vig_pipes->base;
char __iomem *ctl_base = mdss_res->ctl_off->base;
char __iomem *dspp_base = mdss_res->mixer_intf->dspp_base;
@@ -7018,17 +7017,20 @@ static int is_valid_calib_addr(void *addr, u32 operation)
if (ret)
goto valid_addr;
}
- if (ptr >= vig_base) {
+ if (mdss_res->vig_pipes &&
+ ptr >= mdss_res->vig_pipes->base) {
ret = is_valid_calib_vig_addr(ptr);
if (ret)
goto valid_addr;
}
- if (ptr >= rgb_base) {
+ if (mdss_res->rgb_pipes &&
+ ptr >= mdss_res->rgb_pipes->base) {
ret = is_valid_calib_rgb_addr(ptr);
if (ret)
goto valid_addr;
}
- if (ptr >= dma_base) {
+ if (mdss_res->dma_pipes &&
+ ptr >= mdss_res->dma_pipes->base) {
ret = is_valid_calib_dma_addr(ptr);
if (ret)
goto valid_addr;
diff --git a/drivers/video/fbdev/msm/mdss_mdp_util.c b/drivers/video/fbdev/msm/mdss_mdp_util.c
index 199c2b66d90e..c14840ffd08d 100644
--- a/drivers/video/fbdev/msm/mdss_mdp_util.c
+++ b/drivers/video/fbdev/msm/mdss_mdp_util.c
@@ -573,13 +573,6 @@ int mdss_mdp_get_plane_sizes(struct mdss_mdp_format_params *fmt, u32 w, u32 h,
chroma_samp = fmt->chroma_sample;
- if (rotation) {
- if (chroma_samp == MDSS_MDP_CHROMA_H2V1)
- chroma_samp = MDSS_MDP_CHROMA_H1V2;
- else if (chroma_samp == MDSS_MDP_CHROMA_H1V2)
- chroma_samp = MDSS_MDP_CHROMA_H2V1;
- }
-
mdss_mdp_get_v_h_subsample_rate(chroma_samp,
&v_subsample, &h_subsample);
@@ -1027,7 +1020,7 @@ static int mdss_mdp_get_img(struct msmfb_data *img,
} else if (iclient) {
if (mdss_mdp_is_map_needed(mdata, data)) {
data->srcp_dma_buf = dma_buf_get(img->memory_id);
- if (IS_ERR(data->srcp_dma_buf)) {
+ if (IS_ERR_OR_NULL(data->srcp_dma_buf)) {
pr_err("error on ion_import_fd\n");
ret = PTR_ERR(data->srcp_dma_buf);
data->srcp_dma_buf = NULL;
diff --git a/drivers/video/fbdev/msm/mdss_mdp_wfd.c b/drivers/video/fbdev/msm/mdss_mdp_wfd.c
index f04450e9974c..71a07f6b7d39 100644
--- a/drivers/video/fbdev/msm/mdss_mdp_wfd.c
+++ b/drivers/video/fbdev/msm/mdss_mdp_wfd.c
@@ -152,6 +152,7 @@ int mdss_mdp_wfd_setup(struct mdss_mdp_wfd *wfd,
u32 wb_idx = layer->writeback_ndx;
struct mdss_mdp_ctl *ctl = wfd->ctl;
struct mdss_mdp_writeback *wb = NULL;
+ struct mdss_mdp_format_params *fmt = NULL;
int ret = 0;
u32 width, height, max_mixer_width;
@@ -192,6 +193,32 @@ int mdss_mdp_wfd_setup(struct mdss_mdp_wfd *wfd,
ctl->roi = (struct mdss_rect) {0, 0, width, height};
ctl->is_secure = (layer->flags & MDP_LAYER_SECURE_SESSION);
+ fmt = mdss_mdp_get_format_params(layer->buffer.format);
+
+ if (fmt == NULL) {
+ pr_err("invalid buffer format\n");
+ ret = -EINVAL;
+ goto wfd_setup_error;
+ }
+
+ /* only 3 csc type supported */
+ if (fmt->is_yuv) {
+ switch (layer->color_space) {
+ case MDP_CSC_ITU_R_601:
+ ctl->csc_type = MDSS_MDP_CSC_RGB2YUV_601L;
+ break;
+ case MDP_CSC_ITU_R_709:
+ ctl->csc_type = MDSS_MDP_CSC_RGB2YUV_709L;
+ break;
+ case MDP_CSC_ITU_R_601_FR:
+ default:
+ ctl->csc_type = MDSS_MDP_CSC_RGB2YUV_601FR;
+ break;
+ }
+ } else {
+ ctl->csc_type = MDSS_MDP_CSC_RGB2RGB;
+ }
+
if (ctl->mdata->wfd_mode == MDSS_MDP_WFD_INTERFACE) {
ctl->mixer_left = mdss_mdp_mixer_alloc(ctl,
MDSS_MDP_MIXER_TYPE_INTF, (width > max_mixer_width), 0);
diff --git a/drivers/video/fbdev/msm/mdss_panel.h b/drivers/video/fbdev/msm/mdss_panel.h
index 0483e3d42873..16bb48e22bee 100644
--- a/drivers/video/fbdev/msm/mdss_panel.h
+++ b/drivers/video/fbdev/msm/mdss_panel.h
@@ -255,6 +255,8 @@ struct mdss_intf_recovery {
* Argument provided is new panel timing.
* @MDSS_EVENT_DEEP_COLOR: Set deep color.
* Argument provided is bits per pixel (8/10/12)
+ * @MDSS_EVENT_UPDATE_PANEL_PPM: update pixel clock by input PPM.
+ * Argument provided is parts per million.
*/
enum mdss_intf_events {
MDSS_EVENT_RESET = 1,
@@ -287,6 +289,7 @@ enum mdss_intf_events {
MDSS_EVENT_PANEL_TIMING_SWITCH,
MDSS_EVENT_DEEP_COLOR,
MDSS_EVENT_DISABLE_PANEL,
+ MDSS_EVENT_UPDATE_PANEL_PPM,
MDSS_EVENT_MAX,
};
@@ -537,7 +540,10 @@ struct dynamic_fps_data {
* @DFPS_IMMEDIATE_PORCH_UPDATE_MODE_VFP: update fps using vertical timings
* @DFPS_IMMEDIATE_PORCH_UPDATE_MODE_HFP: update fps using horizontal timings
* @DFPS_IMMEDIATE_MULTI_UPDATE_MODE_CLK_HFP: update fps using both horizontal
- * timings and clock.
+ * timings and clock.
+ * @DFPS_IMMEDIATE_MULTI_MODE_HFP_CALC_CLK: update fps using both
+ * horizontal timings, clock need to be caculate base on new clock and
+ * porches.
* @DFPS_MODE_MAX: defines maximum limit of supported modes.
*/
enum dynamic_fps_update {
@@ -546,6 +552,7 @@ enum dynamic_fps_update {
DFPS_IMMEDIATE_PORCH_UPDATE_MODE_VFP,
DFPS_IMMEDIATE_PORCH_UPDATE_MODE_HFP,
DFPS_IMMEDIATE_MULTI_UPDATE_MODE_CLK_HFP,
+ DFPS_IMMEDIATE_MULTI_MODE_HFP_CALC_CLK,
DFPS_MODE_MAX
};
@@ -761,6 +768,7 @@ struct mdss_panel_info {
bool ulps_suspend_enabled;
bool panel_ack_disabled;
bool esd_check_enabled;
+ bool allow_phy_power_off;
char dfps_update;
/* new requested fps before it is updated in hw */
int new_fps;
@@ -974,7 +982,9 @@ static inline u32 mdss_panel_get_framerate(struct mdss_panel_info *panel_info)
break;
case DTV_PANEL:
if (panel_info->dynamic_fps) {
- frame_rate = panel_info->lcdc.frame_rate;
+ frame_rate = panel_info->lcdc.frame_rate / 1000;
+ if (panel_info->lcdc.frame_rate % 1000)
+ frame_rate += 1;
break;
}
default:
diff --git a/drivers/video/fbdev/msm/msm_mdss_io_8974.c b/drivers/video/fbdev/msm/msm_mdss_io_8974.c
index 0c43a2642ede..fdd888edc2fb 100644
--- a/drivers/video/fbdev/msm/msm_mdss_io_8974.c
+++ b/drivers/video/fbdev/msm/msm_mdss_io_8974.c
@@ -960,13 +960,22 @@ static void mdss_dsi_8996_phy_power_off(
static void mdss_dsi_phy_power_off(
struct mdss_dsi_ctrl_pdata *ctrl)
{
+ struct mdss_panel_info *pinfo;
+
if (ctrl->phy_power_off)
return;
- /* supported for phy rev 2.0 */
- if (ctrl->shared_data->phy_rev != DSI_PHY_REV_20)
+ pinfo = &ctrl->panel_data.panel_info;
+
+ if ((ctrl->shared_data->phy_rev != DSI_PHY_REV_20) ||
+ !pinfo->allow_phy_power_off) {
+ pr_debug("%s: ctrl%d phy rev:%d panel support for phy off:%d\n",
+ __func__, ctrl->ndx, ctrl->shared_data->phy_rev,
+ pinfo->allow_phy_power_off);
return;
+ }
+ /* supported for phy rev 2.0 and if panel allows it*/
mdss_dsi_8996_phy_power_off(ctrl);
ctrl->phy_power_off = true;
@@ -1003,7 +1012,7 @@ static void mdss_dsi_8996_phy_power_on(
static void mdss_dsi_phy_power_on(
struct mdss_dsi_ctrl_pdata *ctrl, bool mmss_clamp)
{
- if (mmss_clamp && (ctrl->shared_data->phy_rev != DSI_PHY_REV_20))
+ if (mmss_clamp && !ctrl->phy_power_off)
mdss_dsi_phy_init(ctrl);
else if ((ctrl->shared_data->phy_rev == DSI_PHY_REV_20) &&
ctrl->phy_power_off)
diff --git a/fs/proc/array.c b/fs/proc/array.c
index b6c00ce0e29e..d5c6f5b38617 100644
--- a/fs/proc/array.c
+++ b/fs/proc/array.c
@@ -171,15 +171,15 @@ static inline void task_state(struct seq_file *m, struct pid_namespace *ns,
seq_printf(m,
"State:\t%s\n"
"Tgid:\t%d\n"
- "Ngid:\t%d\n"
"Pid:\t%d\n"
"PPid:\t%d\n"
"TracerPid:\t%d\n"
"Uid:\t%d\t%d\t%d\t%d\n"
"Gid:\t%d\t%d\t%d\t%d\n"
+ "Ngid:\t%d\n"
"FDSize:\t%d\nGroups:\t",
get_task_state(p),
- tgid, ngid, pid_nr_ns(pid, ns), ppid, tpid,
+ tgid, pid_nr_ns(pid, ns), ppid, tpid,
from_kuid_munged(user_ns, cred->uid),
from_kuid_munged(user_ns, cred->euid),
from_kuid_munged(user_ns, cred->suid),
@@ -188,7 +188,7 @@ static inline void task_state(struct seq_file *m, struct pid_namespace *ns,
from_kgid_munged(user_ns, cred->egid),
from_kgid_munged(user_ns, cred->sgid),
from_kgid_munged(user_ns, cred->fsgid),
- max_fds);
+ ngid, max_fds);
group_info = cred->group_info;
for (g = 0; g < group_info->ngroups; g++)
diff --git a/include/dt-bindings/clock/audio-ext-clk.h b/include/dt-bindings/clock/audio-ext-clk.h
index 6e4932342751..c9a8286d7c7f 100644
--- a/include/dt-bindings/clock/audio-ext-clk.h
+++ b/include/dt-bindings/clock/audio-ext-clk.h
@@ -14,9 +14,19 @@
#define __AUDIO_EXT_CLK_H
/* Audio External Clocks */
+#ifdef CONFIG_COMMON_CLK_QCOM
+#define AUDIO_PMI_CLK 0
+#define AUDIO_PMIC_LNBB_CLK 1
+#define AUDIO_AP_CLK 2
+#define AUDIO_AP_CLK2 3
+#define AUDIO_LPASS_MCLK 4
+#define AUDIO_LPASS_MCLK2 5
+#else
#define clk_audio_ap_clk 0x9b5727cb
#define clk_audio_pmi_clk 0xcbfe416d
#define clk_audio_ap_clk2 0x454d1e91
#define clk_audio_lpass_mclk 0xf0f2a284
#define clk_audio_pmi_lnbb_clk 0x57312343
#endif
+
+#endif
diff --git a/include/dt-bindings/clock/qcom,mmcc-msmfalcon.h b/include/dt-bindings/clock/qcom,mmcc-msmfalcon.h
index ffb80a128dd6..7a6ec2bf2418 100644
--- a/include/dt-bindings/clock/qcom,mmcc-msmfalcon.h
+++ b/include/dt-bindings/clock/qcom,mmcc-msmfalcon.h
@@ -159,46 +159,47 @@
#define MMSS_MDSS_AXI_CLK 142
#define MMSS_MDSS_BYTE0_CLK 143
#define MMSS_MDSS_BYTE0_INTF_CLK 144
-#define MMSS_MDSS_BYTE1_CLK 145
-#define MMSS_MDSS_BYTE1_INTF_CLK 146
-#define MMSS_MDSS_DP_AUX_CLK 147
-#define MMSS_MDSS_DP_CRYPTO_CLK 148
-#define MMSS_MDSS_DP_GTC_CLK 149
-#define MMSS_MDSS_DP_LINK_CLK 150
-#define MMSS_MDSS_DP_LINK_INTF_CLK 151
-#define MMSS_MDSS_DP_PIXEL_CLK 152
-#define MMSS_MDSS_ESC0_CLK 153
-#define MMSS_MDSS_ESC1_CLK 154
-#define MMSS_MDSS_HDMI_DP_AHB_CLK 155
-#define MMSS_MDSS_MDP_CLK 156
-#define MMSS_MDSS_PCLK0_CLK 157
-#define MMSS_MDSS_PCLK1_CLK 158
-#define MMSS_MDSS_ROT_CLK 159
-#define MMSS_MDSS_VSYNC_CLK 160
-#define MMSS_MISC_AHB_CLK 161
-#define MMSS_MISC_CXO_CLK 162
-#define MMSS_MNOC_AHB_CLK 163
-#define MMSS_SNOC_DVM_AXI_CLK 164
-#define MMSS_THROTTLE_CAMSS_AHB_CLK 165
-#define MMSS_THROTTLE_CAMSS_AXI_CLK 166
-#define MMSS_THROTTLE_CAMSS_CXO_CLK 167
-#define MMSS_THROTTLE_MDSS_AHB_CLK 168
-#define MMSS_THROTTLE_MDSS_AXI_CLK 169
-#define MMSS_THROTTLE_MDSS_CXO_CLK 170
-#define MMSS_THROTTLE_VIDEO_AHB_CLK 171
-#define MMSS_THROTTLE_VIDEO_AXI_CLK 172
-#define MMSS_THROTTLE_VIDEO_CXO_CLK 173
-#define MMSS_VIDEO_AHB_CLK 174
-#define MMSS_VIDEO_AXI_CLK 175
-#define MMSS_VIDEO_CORE_CLK 176
-#define MMSS_VIDEO_SUBCORE0_CLK 177
-#define PCLK0_CLK_SRC 178
-#define PCLK1_CLK_SRC 179
-#define ROT_CLK_SRC 180
-#define VFE0_CLK_SRC 181
-#define VFE1_CLK_SRC 182
-#define VIDEO_CORE_CLK_SRC 183
-#define VSYNC_CLK_SRC 184
+#define MMSS_MDSS_BYTE0_INTF_DIV_CLK 145
+#define MMSS_MDSS_BYTE1_CLK 146
+#define MMSS_MDSS_BYTE1_INTF_CLK 147
+#define MMSS_MDSS_DP_AUX_CLK 148
+#define MMSS_MDSS_DP_CRYPTO_CLK 149
+#define MMSS_MDSS_DP_GTC_CLK 150
+#define MMSS_MDSS_DP_LINK_CLK 151
+#define MMSS_MDSS_DP_LINK_INTF_CLK 152
+#define MMSS_MDSS_DP_PIXEL_CLK 153
+#define MMSS_MDSS_ESC0_CLK 154
+#define MMSS_MDSS_ESC1_CLK 155
+#define MMSS_MDSS_HDMI_DP_AHB_CLK 156
+#define MMSS_MDSS_MDP_CLK 157
+#define MMSS_MDSS_PCLK0_CLK 158
+#define MMSS_MDSS_PCLK1_CLK 159
+#define MMSS_MDSS_ROT_CLK 160
+#define MMSS_MDSS_VSYNC_CLK 161
+#define MMSS_MISC_AHB_CLK 162
+#define MMSS_MISC_CXO_CLK 163
+#define MMSS_MNOC_AHB_CLK 164
+#define MMSS_SNOC_DVM_AXI_CLK 165
+#define MMSS_THROTTLE_CAMSS_AHB_CLK 166
+#define MMSS_THROTTLE_CAMSS_AXI_CLK 167
+#define MMSS_THROTTLE_CAMSS_CXO_CLK 168
+#define MMSS_THROTTLE_MDSS_AHB_CLK 169
+#define MMSS_THROTTLE_MDSS_AXI_CLK 170
+#define MMSS_THROTTLE_MDSS_CXO_CLK 171
+#define MMSS_THROTTLE_VIDEO_AHB_CLK 172
+#define MMSS_THROTTLE_VIDEO_AXI_CLK 173
+#define MMSS_THROTTLE_VIDEO_CXO_CLK 174
+#define MMSS_VIDEO_AHB_CLK 175
+#define MMSS_VIDEO_AXI_CLK 176
+#define MMSS_VIDEO_CORE_CLK 177
+#define MMSS_VIDEO_SUBCORE0_CLK 178
+#define PCLK0_CLK_SRC 179
+#define PCLK1_CLK_SRC 180
+#define ROT_CLK_SRC 181
+#define VFE0_CLK_SRC 182
+#define VFE1_CLK_SRC 183
+#define VIDEO_CORE_CLK_SRC 184
+#define VSYNC_CLK_SRC 185
#define BIMC_SMMU_GDSC 0
#define CAMSS_CPP_GDSC 1
@@ -209,5 +210,6 @@
#define VIDEO_SUBCORE0_GDSC 6
#define VIDEO_TOP_GDSC 7
+#define CAMSS_MICRO_BCR 0
#endif
diff --git a/include/linux/clk-provider.h b/include/linux/clk-provider.h
index fd2eb059b991..aed90a4902c7 100644
--- a/include/linux/clk-provider.h
+++ b/include/linux/clk-provider.h
@@ -32,6 +32,7 @@
#define CLK_SET_RATE_NO_REPARENT BIT(7) /* don't re-parent on rate change */
#define CLK_GET_ACCURACY_NOCACHE BIT(8) /* do not use the cached clk accuracy */
#define CLK_RECALC_NEW_RATES BIT(9) /* recalc rates after notifications */
+#define CLK_IS_CRITICAL BIT(11) /* do not gate, ever */
struct clk;
struct clk_hw;
@@ -787,7 +788,8 @@ int of_clk_get_parent_count(struct device_node *np);
int of_clk_parent_fill(struct device_node *np, const char **parents,
unsigned int size);
const char *of_clk_get_parent_name(struct device_node *np, int index);
-
+int of_clk_detect_critical(struct device_node *np, int index,
+ unsigned long *flags);
void of_clk_init(const struct of_device_id *matches);
#else /* !CONFIG_OF */
@@ -825,6 +827,13 @@ static inline const char *of_clk_get_parent_name(struct device_node *np,
{
return NULL;
}
+
+static inline int of_clk_detect_critical(struct device_node *np, int index,
+ unsigned long *flags)
+{
+ return 0;
+}
+
#define of_clk_init(matches) \
{ while (0); }
#endif /* CONFIG_OF */
diff --git a/include/linux/clk/msm-clk-provider.h b/include/linux/clk/msm-clk-provider.h
index a09ce5c3b156..2fa8916ad356 100644
--- a/include/linux/clk/msm-clk-provider.h
+++ b/include/linux/clk/msm-clk-provider.h
@@ -1,6 +1,6 @@
/*
* Copyright (C) 2007 Google, Inc.
- * Copyright (c) 2007-2015, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2007-2016, The Linux Foundation. All rights reserved.
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
@@ -29,6 +29,7 @@
#include <linux/seq_file.h>
#include <linux/clk/msm-clk.h>
+#if defined(CONFIG_COMMON_CLK_MSM)
/*
* Bit manipulation macros
*/
@@ -265,4 +266,5 @@ static inline const char *clk_name(struct clk *c)
return "(null)";
return c->dbg_name;
};
+#endif /* CONFIG_COMMON_CLK_MSM */
#endif
diff --git a/include/linux/clk/msm-clk.h b/include/linux/clk/msm-clk.h
index 964909d25021..8455fd776246 100644
--- a/include/linux/clk/msm-clk.h
+++ b/include/linux/clk/msm-clk.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2009, 2012-2015 The Linux Foundation. All rights reserved.
+/* Copyright (c) 2009, 2012-2016, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -23,6 +23,9 @@ enum branch_mem_flags {
CLKFLAG_PERIPH_OFF_SET,
CLKFLAG_PERIPH_OFF_CLEAR,
};
+
+#include <linux/clk.h>
+
#elif defined(CONFIG_COMMON_CLK_MSM)
#define CLKFLAG_INVERT 0x00000001
#define CLKFLAG_NOINVERT 0x00000002
@@ -42,7 +45,6 @@ enum branch_mem_flags {
#define CLKFLAG_EPROBE_DEFER 0x00010000
#define CLKFLAG_PERIPH_OFF_SET 0x00020000
#define CLKFLAG_PERIPH_OFF_CLEAR 0x00040000
-#endif
struct clk_lookup;
struct clk;
@@ -132,4 +134,5 @@ int msm_clk_notif_register(struct clk *clk, struct notifier_block *nb);
int msm_clk_notif_unregister(struct clk *clk, struct notifier_block *nb);
+#endif /* CONFIG_COMMON_CLK_MSM */
#endif
diff --git a/include/linux/sched.h b/include/linux/sched.h
index 4f6711f31939..9c3be2d56ac5 100644
--- a/include/linux/sched.h
+++ b/include/linux/sched.h
@@ -2401,6 +2401,8 @@ struct cpu_cycle_counter_cb {
u64 (*get_cpu_cycle_counter)(int cpu);
};
+#define MAX_NUM_CGROUP_COLOC_ID 20
+
#ifdef CONFIG_SCHED_HMP
extern void free_task_load_ptrs(struct task_struct *p);
extern int sched_set_window(u64 window_start, unsigned int window_size);
diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h
index b89c9c2f7f6e..cc1e8d6b3454 100644
--- a/include/net/cfg80211.h
+++ b/include/net/cfg80211.h
@@ -796,19 +796,15 @@ struct cfg80211_csa_settings {
* @iftype_num: array with the number of interfaces of each interface
* type. The index is the interface type as specified in &enum
* nl80211_iftype.
- * @beacon_int_gcd: a value specifying GCD of all beaconing interfaces,
- * the GCD of a single value is considered the value itself, so for
- * a single interface this should be set to that interface's beacon
- * interval
- * @beacon_int_different: a flag indicating whether or not all beacon
- * intervals (of beaconing interfaces) are different or not.
+ * @new_beacon_int: set this to the beacon interval of a new interface
+ * that's not operating yet, if such is to be checked as part of
+ * the verification
*/
struct iface_combination_params {
int num_different_channels;
u8 radar_detect;
int iftype_num[NUM_NL80211_IFTYPES];
- u32 beacon_int_gcd;
- bool beacon_int_different;
+ u32 new_beacon_int;
};
/**
@@ -3219,6 +3215,9 @@ struct wiphy_iftype_ext_capab {
* @vht_capa_mod_mask: Specify what VHT capabilities can be over-ridden.
* If null, then none can be over-ridden.
*
+ * @wdev_list: the list of associated (virtual) interfaces; this list must
+ * not be modified by the driver, but can be read with RTNL/RCU protection.
+ *
* @max_acl_mac_addrs: Maximum number of MAC addresses that the device
* supports for ACL.
*
@@ -3363,6 +3362,8 @@ struct wiphy {
const struct ieee80211_ht_cap *ht_capa_mod_mask;
const struct ieee80211_vht_cap *vht_capa_mod_mask;
+ struct list_head wdev_list;
+
/* the network namespace this phy lives in currently */
possible_net_t _net;
diff --git a/include/net/sock.h b/include/net/sock.h
index fca6e414f844..0e49452f5c48 100644
--- a/include/net/sock.h
+++ b/include/net/sock.h
@@ -457,6 +457,7 @@ struct sock {
int (*sk_backlog_rcv)(struct sock *sk,
struct sk_buff *skb);
void (*sk_destruct)(struct sock *sk);
+ struct rcu_head sk_rcu;
};
#define __sk_user_data(sk) ((*((void __rcu **)&(sk)->sk_user_data)))
@@ -739,6 +740,7 @@ enum sock_flags {
*/
SOCK_FILTER_LOCKED, /* Filter cannot be changed anymore */
SOCK_SELECT_ERR_QUEUE, /* Wake select on error queue */
+ SOCK_RCU_FREE, /* wait rcu grace period in sk_destruct() */
};
#define SK_FLAGS_TIMESTAMP ((1UL << SOCK_TIMESTAMP) | (1UL << SOCK_TIMESTAMPING_RX_SOFTWARE))
diff --git a/include/net/tcp.h b/include/net/tcp.h
index 213601d620e0..52402ab90c57 100644
--- a/include/net/tcp.h
+++ b/include/net/tcp.h
@@ -1528,6 +1528,8 @@ static inline void tcp_check_send_head(struct sock *sk, struct sk_buff *skb_unli
{
if (sk->sk_send_head == skb_unlinked)
sk->sk_send_head = NULL;
+ if (tcp_sk(sk)->highest_sack == skb_unlinked)
+ tcp_sk(sk)->highest_sack = NULL;
}
static inline void tcp_init_send_head(struct sock *sk)
diff --git a/include/sound/apr_audio-v2.h b/include/sound/apr_audio-v2.h
index e713641cc3ec..e01e16e5cebe 100644
--- a/include/sound/apr_audio-v2.h
+++ b/include/sound/apr_audio-v2.h
@@ -3609,6 +3609,10 @@ struct asm_alac_cfg {
u32 channel_layout_tag;
};
+struct asm_g711_dec_cfg {
+ u32 sample_rate;
+};
+
struct asm_vorbis_cfg {
u32 bit_stream_fmt;
};
@@ -4220,6 +4224,22 @@ struct asm_aac_enc_cfg_v2 {
} __packed;
+#define ASM_MEDIA_FMT_G711_ALAW_FS 0x00010BF7
+#define ASM_MEDIA_FMT_G711_MLAW_FS 0x00010C2E
+
+struct asm_g711_enc_cfg_v2 {
+ struct apr_hdr hdr;
+ struct asm_stream_cmd_set_encdec_param encdec;
+ struct asm_enc_cfg_blk_param_v2 encblk;
+
+ u32 sample_rate;
+/*
+ * Number of samples per second.
+ * Supported values: 8000, 16000 Hz
+ */
+
+} __packed;
+
struct asm_vorbis_fmt_blk_v2 {
struct apr_hdr hdr;
struct asm_data_cmd_media_fmt_update_v2 fmtblk;
@@ -4321,6 +4341,12 @@ struct asm_alac_fmt_blk_v2 {
} __packed;
+struct asm_g711_dec_fmt_blk_v2 {
+ struct apr_hdr hdr;
+ struct asm_data_cmd_media_fmt_update_v2 fmtblk;
+ u32 sample_rate;
+} __packed;
+
struct asm_ape_fmt_blk_v2 {
struct apr_hdr hdr;
struct asm_data_cmd_media_fmt_update_v2 fmtblk;
@@ -8811,6 +8837,7 @@ struct afe_param_id_clip_bank_sel {
/* Supported OSR clock values */
#define Q6AFE_LPASS_OSR_CLK_12_P288_MHZ 0xBB8000
+#define Q6AFE_LPASS_OSR_CLK_11_P2896_MHZ 0xAC4400
#define Q6AFE_LPASS_OSR_CLK_9_P600_MHZ 0x927C00
#define Q6AFE_LPASS_OSR_CLK_8_P192_MHZ 0x7D0000
#define Q6AFE_LPASS_OSR_CLK_6_P144_MHZ 0x5DC000
diff --git a/include/sound/q6asm-v2.h b/include/sound/q6asm-v2.h
index f08bd73edb59..efa5af8e661c 100644
--- a/include/sound/q6asm-v2.h
+++ b/include/sound/q6asm-v2.h
@@ -73,6 +73,11 @@
/* bit 4 represents META enable of encoded data buffer */
#define BUFFER_META_ENABLE 0x0010
+/* bit 5 represents timestamp */
+/* bit 5 - 0 -- ASM_DATA_EVENT_READ_DONE will have relative time-stamp*/
+/* bit 5 - 1 -- ASM_DATA_EVENT_READ_DONE will have absolute time-stamp*/
+#define ABSOLUTE_TIMESTAMP_ENABLE 0x0020
+
/* Enable Sample_Rate/Channel_Mode notification event from Decoder */
#define SR_CM_NOTIFY_ENABLE 0x0004
@@ -175,6 +180,7 @@ struct audio_aio_read_param {
phys_addr_t paddr;
uint32_t len;
uint32_t uid;
+ uint32_t flags;/*meta data flags*/
};
struct audio_port_data {
@@ -382,6 +388,10 @@ int q6asm_enc_cfg_blk_aac(struct audio_client *ac,
uint32_t bit_rate,
uint32_t mode, uint32_t format);
+int q6asm_enc_cfg_blk_g711(struct audio_client *ac,
+ uint32_t frames_per_buf,
+ uint32_t sample_rate);
+
int q6asm_enc_cfg_blk_pcm(struct audio_client *ac,
uint32_t rate, uint32_t channels);
@@ -530,6 +540,9 @@ int q6asm_stream_media_format_block_flac(struct audio_client *ac,
int q6asm_media_format_block_alac(struct audio_client *ac,
struct asm_alac_cfg *cfg, int stream_id);
+int q6asm_media_format_block_g711(struct audio_client *ac,
+ struct asm_g711_dec_cfg *cfg, int stream_id);
+
int q6asm_stream_media_format_block_vorbis(struct audio_client *ac,
struct asm_vorbis_cfg *cfg, int stream_id);
diff --git a/include/uapi/linux/Kbuild b/include/uapi/linux/Kbuild
index 14bd1e806ad7..748b7c277a3c 100644
--- a/include/uapi/linux/Kbuild
+++ b/include/uapi/linux/Kbuild
@@ -302,6 +302,8 @@ header-y += msm_audio_wma.h
header-y += msm_audio_wmapro.h
header-y += msm_audio_alac.h
header-y += msm_audio_ape.h
+header-y += msm_audio_g711.h
+header-y += msm_audio_g711_dec.h
header-y += msm_ion.h
header-y += msm_kgsl.h
header-y += msm_pft.h
diff --git a/include/uapi/linux/msm_audio_g711.h b/include/uapi/linux/msm_audio_g711.h
new file mode 100644
index 000000000000..48ebd6a1131e
--- /dev/null
+++ b/include/uapi/linux/msm_audio_g711.h
@@ -0,0 +1,17 @@
+#ifndef _UAPI_MSM_AUDIO_G711_H
+#define _UAPI_MSM_AUDIO_G711_H
+
+#include <linux/msm_audio.h>
+
+struct msm_audio_g711_enc_config {
+ uint32_t sample_rate;
+};
+
+#define AUDIO_SET_G711_ENC_CONFIG _IOW(AUDIO_IOCTL_MAGIC, \
+ (AUDIO_MAX_COMMON_IOCTL_NUM+0), struct msm_audio_g711_enc_config)
+
+#define AUDIO_GET_G711_ENC_CONFIG _IOR(AUDIO_IOCTL_MAGIC, \
+ (AUDIO_MAX_COMMON_IOCTL_NUM+1), struct msm_audio_g711_enc_config)
+
+
+#endif /* _UAPI_MSM_AUDIO_G711_H */
diff --git a/include/uapi/linux/msm_audio_g711_dec.h b/include/uapi/linux/msm_audio_g711_dec.h
new file mode 100644
index 000000000000..ff7e4ce39fd5
--- /dev/null
+++ b/include/uapi/linux/msm_audio_g711_dec.h
@@ -0,0 +1,16 @@
+#ifndef _UAPI_MSM_AUDIO_G711_H
+#define _UAPI_MSM_AUDIO_G711_H
+
+#include <linux/msm_audio.h>
+
+struct msm_audio_g711_dec_config {
+ uint32_t sample_rate;
+};
+
+#define AUDIO_SET_G711_DEC_CONFIG _IOW(AUDIO_IOCTL_MAGIC, \
+ (AUDIO_MAX_COMMON_IOCTL_NUM+0), struct msm_audio_g711_dec_config)
+
+#define AUDIO_GET_G711_DEC_CONFIG _IOR(AUDIO_IOCTL_MAGIC, \
+ (AUDIO_MAX_COMMON_IOCTL_NUM+1), struct msm_audio_g711_dec_config)
+
+#endif /* _UAPI_MSM_AUDIO_G711_H */
diff --git a/include/uapi/linux/msm_mdp_ext.h b/include/uapi/linux/msm_mdp_ext.h
index 1a71e860ba48..24f1e7c7b742 100644
--- a/include/uapi/linux/msm_mdp_ext.h
+++ b/include/uapi/linux/msm_mdp_ext.h
@@ -31,6 +31,12 @@
struct mdp_set_cfg)
/*
+ * Ioctl for setting the PLL PPM.
+ * PLL PPM is passed by the user space using this IOCTL.
+ */
+#define MSMFB_MDP_SET_PANEL_PPM _IOW(MDP_IOCTL_MAGIC, 131, int)
+
+/*
* To allow proper structure padding for 64bit/32bit target
*/
#ifdef __LP64
@@ -165,6 +171,8 @@ VALIDATE/COMMIT FLAG CONFIGURATION
#define MDP_COMMIT_VERSION_1_0 0x00010000
+#define OUT_LAYER_COLOR_SPACE
+
/**********************************************************************
Configuration structures
All parameters are input to driver unless mentioned output parameter
@@ -357,8 +365,11 @@ struct mdp_output_layer {
/* Buffer attached with output layer. Device uses it for commit call */
struct mdp_layer_buffer buffer;
+ /* color space of the destination */
+ enum mdp_color_space color_space;
+
/* 32bits reserved value for future usage. */
- uint32_t reserved[6];
+ uint32_t reserved[5];
};
/*
diff --git a/include/uapi/media/msm_media_info.h b/include/uapi/media/msm_media_info.h
index e9b5501c697b..50b8fc32b129 100644
--- a/include/uapi/media/msm_media_info.h
+++ b/include/uapi/media/msm_media_info.h
@@ -2,7 +2,9 @@
#define __MEDIA_INFO_H__
#ifndef MSM_MEDIA_ALIGN
-#define MSM_MEDIA_ALIGN(__sz, __align) (((__sz) + (__align-1)) & (~(__align-1)))
+#define MSM_MEDIA_ALIGN(__sz, __align) (((__align) & ((__align) - 1)) ?\
+ ((((__sz) + (__align) - 1) / (__align)) * (__align)) :\
+ (((__sz) + (__align) - 1) & (~((__align) - 1))))
#endif
#ifndef MSM_MEDIA_ROUNDUP
@@ -399,8 +401,195 @@ enum color_fmts {
* Extradata, 4096)
*/
COLOR_FMT_RGBA8888_UBWC,
+ /* Venus RGBA1010102 UBWC format:
+ * Contains 2 planes in the following order -
+ * (A) Meta plane
+ * (B) RGBA plane
+ *
+ * <--- RGB_Meta_Stride ---->
+ * <-------- Width ------>
+ * M M M M M M M M M M M M . . ^ ^
+ * M M M M M M M M M M M M . . | |
+ * M M M M M M M M M M M M . . Height |
+ * M M M M M M M M M M M M . . | Meta_RGB_Scanlines
+ * M M M M M M M M M M M M . . | |
+ * M M M M M M M M M M M M . . | |
+ * M M M M M M M M M M M M . . | |
+ * M M M M M M M M M M M M . . V |
+ * . . . . . . . . . . . . . . |
+ * . . . . . . . . . . . . . . |
+ * . . . . . . . . . . . . . . -------> Buffer size aligned to 4k
+ * . . . . . . . . . . . . . . V
+ * <-------- RGB_Stride -------->
+ * <------- Width ------->
+ * R R R R R R R R R R R R . . . . ^ ^
+ * R R R R R R R R R R R R . . . . | |
+ * R R R R R R R R R R R R . . . . Height |
+ * R R R R R R R R R R R R . . . . | RGB_Scanlines
+ * R R R R R R R R R R R R . . . . | |
+ * R R R R R R R R R R R R . . . . | |
+ * R R R R R R R R R R R R . . . . | |
+ * R R R R R R R R R R R R . . . . V |
+ * . . . . . . . . . . . . . . . . |
+ * . . . . . . . . . . . . . . . . |
+ * . . . . . . . . . . . . . . . . -------> Buffer size aligned to 4k
+ * . . . . . . . . . . . . . . . . V
+ *
+ * RGB_Stride = align(Width * 4, 256)
+ * RGB_Scanlines = align(Height, 16)
+ * RGB_Plane_size = align(RGB_Stride * RGB_Scanlines, 4096)
+ * RGB_Meta_Stride = align(roundup(Width, RGB_TileWidth), 64)
+ * RGB_Meta_Scanline = align(roundup(Height, RGB_TileHeight), 16)
+ * RGB_Meta_Plane_size = align(RGB_Meta_Stride *
+ * RGB_Meta_Scanlines, 4096)
+ * Extradata = 8k
+ *
+ * Total size = align(RGB_Meta_Plane_size + RGB_Plane_size +
+ * Extradata, 4096)
+ */
+ COLOR_FMT_RGBA1010102_UBWC,
+ /* Venus RGB565 UBWC format:
+ * Contains 2 planes in the following order -
+ * (A) Meta plane
+ * (B) RGB plane
+ *
+ * <--- RGB_Meta_Stride ---->
+ * <-------- Width ------>
+ * M M M M M M M M M M M M . . ^ ^
+ * M M M M M M M M M M M M . . | |
+ * M M M M M M M M M M M M . . Height |
+ * M M M M M M M M M M M M . . | Meta_RGB_Scanlines
+ * M M M M M M M M M M M M . . | |
+ * M M M M M M M M M M M M . . | |
+ * M M M M M M M M M M M M . . | |
+ * M M M M M M M M M M M M . . V |
+ * . . . . . . . . . . . . . . |
+ * . . . . . . . . . . . . . . |
+ * . . . . . . . . . . . . . . -------> Buffer size aligned to 4k
+ * . . . . . . . . . . . . . . V
+ * <-------- RGB_Stride -------->
+ * <------- Width ------->
+ * R R R R R R R R R R R R . . . . ^ ^
+ * R R R R R R R R R R R R . . . . | |
+ * R R R R R R R R R R R R . . . . Height |
+ * R R R R R R R R R R R R . . . . | RGB_Scanlines
+ * R R R R R R R R R R R R . . . . | |
+ * R R R R R R R R R R R R . . . . | |
+ * R R R R R R R R R R R R . . . . | |
+ * R R R R R R R R R R R R . . . . V |
+ * . . . . . . . . . . . . . . . . |
+ * . . . . . . . . . . . . . . . . |
+ * . . . . . . . . . . . . . . . . -------> Buffer size aligned to 4k
+ * . . . . . . . . . . . . . . . . V
+ *
+ * RGB_Stride = align(Width * 2, 128)
+ * RGB_Scanlines = align(Height, 16)
+ * RGB_Plane_size = align(RGB_Stride * RGB_Scanlines, 4096)
+ * RGB_Meta_Stride = align(roundup(Width, RGB_TileWidth), 64)
+ * RGB_Meta_Scanline = align(roundup(Height, RGB_TileHeight), 16)
+ * RGB_Meta_Plane_size = align(RGB_Meta_Stride *
+ * RGB_Meta_Scanlines, 4096)
+ * Extradata = 8k
+ *
+ * Total size = align(RGB_Meta_Plane_size + RGB_Plane_size +
+ * Extradata, 4096)
+ */
+ COLOR_FMT_RGB565_UBWC,
+ /* P010 UBWC:
+ * Compressed Macro-tile format for NV12.
+ * Contains 4 planes in the following order -
+ * (A) Y_Meta_Plane
+ * (B) Y_UBWC_Plane
+ * (C) UV_Meta_Plane
+ * (D) UV_UBWC_Plane
+ *
+ * Y_Meta_Plane consists of meta information to decode compressed
+ * tile data in Y_UBWC_Plane.
+ * Y_UBWC_Plane consists of Y data in compressed macro-tile format.
+ * UBWC decoder block will use the Y_Meta_Plane data together with
+ * Y_UBWC_Plane data to produce loss-less uncompressed 10 bit Y samples.
+ *
+ * UV_Meta_Plane consists of meta information to decode compressed
+ * tile data in UV_UBWC_Plane.
+ * UV_UBWC_Plane consists of UV data in compressed macro-tile format.
+ * UBWC decoder block will use UV_Meta_Plane data together with
+ * UV_UBWC_Plane data to produce loss-less uncompressed 10 bit 2x2
+ * subsampled color difference samples.
+ *
+ * Each tile in Y_UBWC_Plane/UV_UBWC_Plane is independently decodable
+ * and randomly accessible. There is no dependency between tiles.
+ *
+ * <----- Y_Meta_Stride ----->
+ * <-------- Width ------>
+ * M M M M M M M M M M M M . . ^ ^
+ * M M M M M M M M M M M M . . | |
+ * M M M M M M M M M M M M . . Height |
+ * M M M M M M M M M M M M . . | Meta_Y_Scanlines
+ * M M M M M M M M M M M M . . | |
+ * M M M M M M M M M M M M . . | |
+ * M M M M M M M M M M M M . . | |
+ * M M M M M M M M M M M M . . V |
+ * . . . . . . . . . . . . . . |
+ * . . . . . . . . . . . . . . |
+ * . . . . . . . . . . . . . . -------> Buffer size aligned to 4k
+ * . . . . . . . . . . . . . . V
+ * <--Compressed tile Y Stride--->
+ * <------- Width ------->
+ * Y* Y* Y* Y* Y* Y* Y* Y* . . . . ^ ^
+ * Y* Y* Y* Y* Y* Y* Y* Y* . . . . | |
+ * Y* Y* Y* Y* Y* Y* Y* Y* . . . . Height |
+ * Y* Y* Y* Y* Y* Y* Y* Y* . . . . | Macro_tile_Y_Scanlines
+ * Y* Y* Y* Y* Y* Y* Y* Y* . . . . | |
+ * Y* Y* Y* Y* Y* Y* Y* Y* . . . . | |
+ * Y* Y* Y* Y* Y* Y* Y* Y* . . . . | |
+ * Y* Y* Y* Y* Y* Y* Y* Y* . . . . V |
+ * . . . . . . . . . . . . . . . . |
+ * . . . . . . . . . . . . . . . . |
+ * . . . . . . . . . . . . . . . . -------> Buffer size aligned to 4k
+ * . . . . . . . . . . . . . . . . V
+ * <----- UV_Meta_Stride ---->
+ * M M M M M M M M M M M M . . ^
+ * M M M M M M M M M M M M . . |
+ * M M M M M M M M M M M M . . |
+ * M M M M M M M M M M M M . . M_UV_Scanlines
+ * . . . . . . . . . . . . . . |
+ * . . . . . . . . . . . . . . V
+ * . . . . . . . . . . . . . . -------> Buffer size aligned to 4k
+ * <--Compressed tile UV Stride--->
+ * U* V* U* V* U* V* U* V* . . . . ^
+ * U* V* U* V* U* V* U* V* . . . . |
+ * U* V* U* V* U* V* U* V* . . . . |
+ * U* V* U* V* U* V* U* V* . . . . UV_Scanlines
+ * . . . . . . . . . . . . . . . . |
+ * . . . . . . . . . . . . . . . . V
+ * . . . . . . . . . . . . . . . . -------> Buffer size aligned to 4k
+ *
+ *
+ * Y_Stride = align(Width * 2, 256)
+ * UV_Stride = align(Width * 2, 256)
+ * Y_Scanlines = align(Height, 16)
+ * UV_Scanlines = align(Height/2, 16)
+ * Y_UBWC_Plane_Size = align(Y_Stride * Y_Scanlines, 4096)
+ * UV_UBWC_Plane_Size = align(UV_Stride * UV_Scanlines, 4096)
+ * Y_Meta_Stride = align(roundup(Width, Y_TileWidth), 64)
+ * Y_Meta_Scanlines = align(roundup(Height, Y_TileHeight), 16)
+ * Y_Meta_Plane_size = align(Y_Meta_Stride * Y_Meta_Scanlines, 4096)
+ * UV_Meta_Stride = align(roundup(Width, UV_TileWidth), 64)
+ * UV_Meta_Scanlines = align(roundup(Height, UV_TileHeight), 16)
+ * UV_Meta_Plane_size = align(UV_Meta_Stride * UV_Meta_Scanlines, 4096)
+ * Extradata = 8k
+ *
+ * Total size = align(Y_UBWC_Plane_size + UV_UBWC_Plane_size +
+ * Y_Meta_Plane_size + UV_Meta_Plane_size
+ * + max(Extradata, Y_Stride * 48), 4096)
+ */
+ COLOR_FMT_P010_UBWC,
};
+#define COLOR_FMT_RGBA1010102_UBWC COLOR_FMT_RGBA1010102_UBWC
+#define COLOR_FMT_RGB565_UBWC COLOR_FMT_RGB565_UBWC
+#define COLOR_FMT_P010_UBWC COLOR_FMT_P010_UBWC
+
static inline unsigned int VENUS_EXTRADATA_SIZE(int width, int height)
{
(void)height;
@@ -433,6 +622,10 @@ static inline unsigned int VENUS_Y_STRIDE(int color_fmt, int width)
stride = MSM_MEDIA_ALIGN(width, 192);
stride = MSM_MEDIA_ALIGN(stride * 4/3, alignment);
break;
+ case COLOR_FMT_P010_UBWC:
+ alignment = 256;
+ stride = MSM_MEDIA_ALIGN(width * 2, alignment);
+ break;
default:
break;
}
@@ -460,6 +653,10 @@ static inline unsigned int VENUS_UV_STRIDE(int color_fmt, int width)
stride = MSM_MEDIA_ALIGN(width, 192);
stride = MSM_MEDIA_ALIGN(stride * 4/3, alignment);
break;
+ case COLOR_FMT_P010_UBWC:
+ alignment = 256;
+ stride = MSM_MEDIA_ALIGN(width * 2, alignment);
+ break;
default:
break;
}
@@ -482,6 +679,7 @@ static inline unsigned int VENUS_Y_SCANLINES(int color_fmt, int height)
alignment = 32;
break;
case COLOR_FMT_NV12_BPP10_UBWC:
+ case COLOR_FMT_P010_UBWC:
alignment = 16;
break;
default:
@@ -504,6 +702,7 @@ static inline unsigned int VENUS_UV_SCANLINES(int color_fmt, int height)
case COLOR_FMT_NV12:
case COLOR_FMT_NV12_MVTB:
case COLOR_FMT_NV12_BPP10_UBWC:
+ case COLOR_FMT_P010_UBWC:
alignment = 16;
break;
case COLOR_FMT_NV12_UBWC:
@@ -528,6 +727,7 @@ static inline unsigned int VENUS_Y_META_STRIDE(int color_fmt, int width)
switch (color_fmt) {
case COLOR_FMT_NV12_UBWC:
+ case COLOR_FMT_P010_UBWC:
y_tile_width = 32;
break;
case COLOR_FMT_NV12_BPP10_UBWC:
@@ -556,6 +756,7 @@ static inline unsigned int VENUS_Y_META_SCANLINES(int color_fmt, int height)
y_tile_height = 8;
break;
case COLOR_FMT_NV12_BPP10_UBWC:
+ case COLOR_FMT_P010_UBWC:
y_tile_height = 4;
break;
default:
@@ -578,6 +779,7 @@ static inline unsigned int VENUS_UV_META_STRIDE(int color_fmt, int width)
switch (color_fmt) {
case COLOR_FMT_NV12_UBWC:
+ case COLOR_FMT_P010_UBWC:
uv_tile_width = 16;
break;
case COLOR_FMT_NV12_BPP10_UBWC:
@@ -606,6 +808,7 @@ static inline unsigned int VENUS_UV_META_SCANLINES(int color_fmt, int height)
uv_tile_height = 8;
break;
case COLOR_FMT_NV12_BPP10_UBWC:
+ case COLOR_FMT_P010_UBWC:
uv_tile_height = 4;
break;
default:
@@ -621,7 +824,7 @@ invalid_input:
static inline unsigned int VENUS_RGB_STRIDE(int color_fmt, int width)
{
- unsigned int alignment = 0, stride = 0;
+ unsigned int alignment = 0, stride = 0, bpp = 4;
if (!width)
goto invalid_input;
@@ -630,14 +833,19 @@ static inline unsigned int VENUS_RGB_STRIDE(int color_fmt, int width)
case COLOR_FMT_RGBA8888:
alignment = 128;
break;
+ case COLOR_FMT_RGB565_UBWC:
+ alignment = 128;
+ bpp = 2;
+ break;
case COLOR_FMT_RGBA8888_UBWC:
+ case COLOR_FMT_RGBA1010102_UBWC:
alignment = 256;
break;
default:
goto invalid_input;
}
- stride = MSM_MEDIA_ALIGN(width * 4, alignment);
+ stride = MSM_MEDIA_ALIGN(width * bpp, alignment);
invalid_input:
return stride;
@@ -655,6 +863,8 @@ static inline unsigned int VENUS_RGB_SCANLINES(int color_fmt, int height)
alignment = 32;
break;
case COLOR_FMT_RGBA8888_UBWC:
+ case COLOR_FMT_RGBA1010102_UBWC:
+ case COLOR_FMT_RGB565_UBWC:
alignment = 16;
break;
default:
@@ -676,6 +886,8 @@ static inline unsigned int VENUS_RGB_META_STRIDE(int color_fmt, int width)
switch (color_fmt) {
case COLOR_FMT_RGBA8888_UBWC:
+ case COLOR_FMT_RGBA1010102_UBWC:
+ case COLOR_FMT_RGB565_UBWC:
rgb_tile_width = 16;
break;
default:
@@ -698,6 +910,8 @@ static inline unsigned int VENUS_RGB_META_SCANLINES(int color_fmt, int height)
switch (color_fmt) {
case COLOR_FMT_RGBA8888_UBWC:
+ case COLOR_FMT_RGBA1010102_UBWC:
+ case COLOR_FMT_RGB565_UBWC:
rgb_tile_height = 4;
break;
default:
diff --git a/include/uapi/media/msmb_isp.h b/include/uapi/media/msmb_isp.h
index cdb85170919a..e4d41d4072c5 100644
--- a/include/uapi/media/msmb_isp.h
+++ b/include/uapi/media/msmb_isp.h
@@ -261,6 +261,26 @@ struct msm_vfe_fetch_eng_start {
uint32_t frame_id;
};
+enum msm_vfe_fetch_eng_pass {
+ OFFLINE_FIRST_PASS,
+ OFFLINE_SECOND_PASS,
+ OFFLINE_MAX_PASS,
+};
+
+struct msm_vfe_fetch_eng_multi_pass_start {
+ uint32_t session_id;
+ uint32_t stream_id;
+ uint32_t buf_idx;
+ uint8_t offline_mode;
+ uint32_t fd;
+ uint32_t buf_addr;
+ uint32_t frame_id;
+ uint32_t output_buf_idx;
+ uint32_t input_buf_offset;
+ enum msm_vfe_fetch_eng_pass offline_pass;
+ uint32_t output_stream_id;
+};
+
struct msm_vfe_axi_plane_cfg {
uint32_t output_width; /*Include padding*/
uint32_t output_height;
@@ -328,6 +348,7 @@ enum msm_vfe_axi_stream_update_type {
UPDATE_STREAM_REMOVE_BUFQ,
UPDATE_STREAM_SW_FRAME_DROP,
UPDATE_STREAM_REQUEST_FRAMES_VER2,
+ UPDATE_STREAM_OFFLINE_AXI_CONFIG,
};
#define UPDATE_STREAM_REQUEST_FRAMES_VER2 UPDATE_STREAM_REQUEST_FRAMES_VER2
@@ -853,6 +874,8 @@ enum msm_isp_ioctl_cmd_code {
MSM_ISP_SET_DUAL_HW_MASTER_SLAVE,
MSM_ISP_MAP_BUF_START_FE,
MSM_ISP_UNMAP_BUF,
+ MSM_ISP_FETCH_ENG_MULTI_PASS_START,
+ MSM_ISP_MAP_BUF_START_MULTI_PASS_FE,
};
#define VIDIOC_MSM_VFE_REG_CFG \
@@ -958,4 +981,11 @@ enum msm_isp_ioctl_cmd_code {
#define VIDIOC_MSM_ISP_AHB_CLK_CFG \
_IOWR('V', BASE_VIDIOC_PRIVATE+25, struct msm_isp_ahb_clk_cfg)
+#define VIDIOC_MSM_ISP_FETCH_ENG_MULTI_PASS_START \
+ _IOWR('V', MSM_ISP_FETCH_ENG_MULTI_PASS_START, \
+ struct msm_vfe_fetch_eng_multi_pass_start)
+
+#define VIDIOC_MSM_ISP_MAP_BUF_START_MULTI_PASS_FE \
+ _IOWR('V', MSM_ISP_MAP_BUF_START_MULTI_PASS_FE, \
+ struct msm_vfe_fetch_eng_multi_pass_start)
#endif /* __MSMB_ISP__ */
diff --git a/include/uapi/sound/compress_params.h b/include/uapi/sound/compress_params.h
index 47367c663011..ef96966b2bbe 100644
--- a/include/uapi/sound/compress_params.h
+++ b/include/uapi/sound/compress_params.h
@@ -70,6 +70,11 @@
#define Q6_DTS 0x00010D88
#define Q6_DTS_LBR 0x00010DBB
+/* Timestamp flsg */
+/* Bit-0 - 1 : Enable Timestamp mode */
+/* Bit-0 - 0 : Disable Timestamp mode */
+#define COMPRESSED_TIMESTAMP_FLAG 0x0001
+
/* Codecs are listed linearly to allow for extensibility */
#define SND_AUDIOCODEC_PCM ((__u32) 0x00000001)
#define SND_AUDIOCODEC_MP3 ((__u32) 0x00000002)
@@ -480,7 +485,24 @@ struct snd_codec {
__u32 align;
__u32 compr_passthr;
union snd_codec_options options;
- __u32 reserved[3];
+ __u32 flags;
+ __u32 reserved[2];
} __attribute__((packed, aligned(4)));
+
+/** struct snd_codec_metadata
+ * @length: Length of the encoded buffer.
+ * @offset: Offset from the buffer address to the first byte of the first
+ * encoded frame. All encoded frames are consecutive starting
+ * from this offset.
+ * @timestamp: Session time in microseconds of the first sample in the buffer.
+ * @reserved: Reserved for future use.
+ */
+struct snd_codec_metadata {
+ __u32 length;
+ __u32 offset;
+ __u64 timestamp;
+ __u32 reserved[4];
+};
+
#endif
diff --git a/kernel/auditsc.c b/kernel/auditsc.c
index b86cc04959de..48f45987dc6c 100644
--- a/kernel/auditsc.c
+++ b/kernel/auditsc.c
@@ -73,6 +73,7 @@
#include <linux/compat.h>
#include <linux/ctype.h>
#include <linux/string.h>
+#include <linux/uaccess.h>
#include <uapi/linux/limits.h>
#include "audit.h"
@@ -82,7 +83,8 @@
#define AUDITSC_SUCCESS 1
#define AUDITSC_FAILURE 2
-/* no execve audit message should be longer than this (userspace limits) */
+/* no execve audit message should be longer than this (userspace limits),
+ * see the note near the top of audit_log_execve_info() about this value */
#define MAX_EXECVE_AUDIT_LEN 7500
/* max length to print of cmdline/proctitle value during audit */
@@ -988,184 +990,178 @@ static int audit_log_pid_context(struct audit_context *context, pid_t pid,
return rc;
}
-/*
- * to_send and len_sent accounting are very loose estimates. We aren't
- * really worried about a hard cap to MAX_EXECVE_AUDIT_LEN so much as being
- * within about 500 bytes (next page boundary)
- *
- * why snprintf? an int is up to 12 digits long. if we just assumed when
- * logging that a[%d]= was going to be 16 characters long we would be wasting
- * space in every audit message. In one 7500 byte message we can log up to
- * about 1000 min size arguments. That comes down to about 50% waste of space
- * if we didn't do the snprintf to find out how long arg_num_len was.
- */
-static int audit_log_single_execve_arg(struct audit_context *context,
- struct audit_buffer **ab,
- int arg_num,
- size_t *len_sent,
- const char __user *p,
- char *buf)
+static void audit_log_execve_info(struct audit_context *context,
+ struct audit_buffer **ab)
{
- char arg_num_len_buf[12];
- const char __user *tmp_p = p;
- /* how many digits are in arg_num? 5 is the length of ' a=""' */
- size_t arg_num_len = snprintf(arg_num_len_buf, 12, "%d", arg_num) + 5;
- size_t len, len_left, to_send;
- size_t max_execve_audit_len = MAX_EXECVE_AUDIT_LEN;
- unsigned int i, has_cntl = 0, too_long = 0;
- int ret;
-
- /* strnlen_user includes the null we don't want to send */
- len_left = len = strnlen_user(p, MAX_ARG_STRLEN) - 1;
-
- /*
- * We just created this mm, if we can't find the strings
- * we just copied into it something is _very_ wrong. Similar
- * for strings that are too long, we should not have created
- * any.
- */
- if (WARN_ON_ONCE(len < 0 || len > MAX_ARG_STRLEN - 1)) {
- send_sig(SIGKILL, current, 0);
- return -1;
+ long len_max;
+ long len_rem;
+ long len_full;
+ long len_buf;
+ long len_abuf;
+ long len_tmp;
+ bool require_data;
+ bool encode;
+ unsigned int iter;
+ unsigned int arg;
+ char *buf_head;
+ char *buf;
+ const char __user *p = (const char __user *)current->mm->arg_start;
+
+ /* NOTE: this buffer needs to be large enough to hold all the non-arg
+ * data we put in the audit record for this argument (see the
+ * code below) ... at this point in time 96 is plenty */
+ char abuf[96];
+
+ /* NOTE: we set MAX_EXECVE_AUDIT_LEN to a rather arbitrary limit, the
+ * current value of 7500 is not as important as the fact that it
+ * is less than 8k, a setting of 7500 gives us plenty of wiggle
+ * room if we go over a little bit in the logging below */
+ WARN_ON_ONCE(MAX_EXECVE_AUDIT_LEN > 7500);
+ len_max = MAX_EXECVE_AUDIT_LEN;
+
+ /* scratch buffer to hold the userspace args */
+ buf_head = kmalloc(MAX_EXECVE_AUDIT_LEN + 1, GFP_KERNEL);
+ if (!buf_head) {
+ audit_panic("out of memory for argv string");
+ return;
}
+ buf = buf_head;
- /* walk the whole argument looking for non-ascii chars */
+ audit_log_format(*ab, "argc=%d", context->execve.argc);
+
+ len_rem = len_max;
+ len_buf = 0;
+ len_full = 0;
+ require_data = true;
+ encode = false;
+ iter = 0;
+ arg = 0;
do {
- if (len_left > MAX_EXECVE_AUDIT_LEN)
- to_send = MAX_EXECVE_AUDIT_LEN;
- else
- to_send = len_left;
- ret = copy_from_user(buf, tmp_p, to_send);
- /*
- * There is no reason for this copy to be short. We just
- * copied them here, and the mm hasn't been exposed to user-
- * space yet.
- */
- if (ret) {
- WARN_ON(1);
- send_sig(SIGKILL, current, 0);
- return -1;
- }
- buf[to_send] = '\0';
- has_cntl = audit_string_contains_control(buf, to_send);
- if (has_cntl) {
- /*
- * hex messages get logged as 2 bytes, so we can only
- * send half as much in each message
- */
- max_execve_audit_len = MAX_EXECVE_AUDIT_LEN / 2;
- break;
- }
- len_left -= to_send;
- tmp_p += to_send;
- } while (len_left > 0);
-
- len_left = len;
-
- if (len > max_execve_audit_len)
- too_long = 1;
-
- /* rewalk the argument actually logging the message */
- for (i = 0; len_left > 0; i++) {
- int room_left;
-
- if (len_left > max_execve_audit_len)
- to_send = max_execve_audit_len;
- else
- to_send = len_left;
-
- /* do we have space left to send this argument in this ab? */
- room_left = MAX_EXECVE_AUDIT_LEN - arg_num_len - *len_sent;
- if (has_cntl)
- room_left -= (to_send * 2);
- else
- room_left -= to_send;
- if (room_left < 0) {
- *len_sent = 0;
- audit_log_end(*ab);
- *ab = audit_log_start(context, GFP_KERNEL, AUDIT_EXECVE);
- if (!*ab)
- return 0;
- }
+ /* NOTE: we don't ever want to trust this value for anything
+ * serious, but the audit record format insists we
+ * provide an argument length for really long arguments,
+ * e.g. > MAX_EXECVE_AUDIT_LEN, so we have no choice but
+ * to use strncpy_from_user() to obtain this value for
+ * recording in the log, although we don't use it
+ * anywhere here to avoid a double-fetch problem */
+ if (len_full == 0)
+ len_full = strnlen_user(p, MAX_ARG_STRLEN) - 1;
+
+ /* read more data from userspace */
+ if (require_data) {
+ /* can we make more room in the buffer? */
+ if (buf != buf_head) {
+ memmove(buf_head, buf, len_buf);
+ buf = buf_head;
+ }
+
+ /* fetch as much as we can of the argument */
+ len_tmp = strncpy_from_user(&buf_head[len_buf], p,
+ len_max - len_buf);
+ if (len_tmp == -EFAULT) {
+ /* unable to copy from userspace */
+ send_sig(SIGKILL, current, 0);
+ goto out;
+ } else if (len_tmp == (len_max - len_buf)) {
+ /* buffer is not large enough */
+ require_data = true;
+ /* NOTE: if we are going to span multiple
+ * buffers force the encoding so we stand
+ * a chance at a sane len_full value and
+ * consistent record encoding */
+ encode = true;
+ len_full = len_full * 2;
+ p += len_tmp;
+ } else {
+ require_data = false;
+ if (!encode)
+ encode = audit_string_contains_control(
+ buf, len_tmp);
+ /* try to use a trusted value for len_full */
+ if (len_full < len_max)
+ len_full = (encode ?
+ len_tmp * 2 : len_tmp);
+ p += len_tmp + 1;
+ }
+ len_buf += len_tmp;
+ buf_head[len_buf] = '\0';
- /*
- * first record needs to say how long the original string was
- * so we can be sure nothing was lost.
- */
- if ((i == 0) && (too_long))
- audit_log_format(*ab, " a%d_len=%zu", arg_num,
- has_cntl ? 2*len : len);
-
- /*
- * normally arguments are small enough to fit and we already
- * filled buf above when we checked for control characters
- * so don't bother with another copy_from_user
- */
- if (len >= max_execve_audit_len)
- ret = copy_from_user(buf, p, to_send);
- else
- ret = 0;
- if (ret) {
- WARN_ON(1);
- send_sig(SIGKILL, current, 0);
- return -1;
+ /* length of the buffer in the audit record? */
+ len_abuf = (encode ? len_buf * 2 : len_buf + 2);
}
- buf[to_send] = '\0';
-
- /* actually log it */
- audit_log_format(*ab, " a%d", arg_num);
- if (too_long)
- audit_log_format(*ab, "[%d]", i);
- audit_log_format(*ab, "=");
- if (has_cntl)
- audit_log_n_hex(*ab, buf, to_send);
- else
- audit_log_string(*ab, buf);
-
- p += to_send;
- len_left -= to_send;
- *len_sent += arg_num_len;
- if (has_cntl)
- *len_sent += to_send * 2;
- else
- *len_sent += to_send;
- }
- /* include the null we didn't log */
- return len + 1;
-}
-static void audit_log_execve_info(struct audit_context *context,
- struct audit_buffer **ab)
-{
- int i, len;
- size_t len_sent = 0;
- const char __user *p;
- char *buf;
+ /* write as much as we can to the audit log */
+ if (len_buf > 0) {
+ /* NOTE: some magic numbers here - basically if we
+ * can't fit a reasonable amount of data into the
+ * existing audit buffer, flush it and start with
+ * a new buffer */
+ if ((sizeof(abuf) + 8) > len_rem) {
+ len_rem = len_max;
+ audit_log_end(*ab);
+ *ab = audit_log_start(context,
+ GFP_KERNEL, AUDIT_EXECVE);
+ if (!*ab)
+ goto out;
+ }
- p = (const char __user *)current->mm->arg_start;
+ /* create the non-arg portion of the arg record */
+ len_tmp = 0;
+ if (require_data || (iter > 0) ||
+ ((len_abuf + sizeof(abuf)) > len_rem)) {
+ if (iter == 0) {
+ len_tmp += snprintf(&abuf[len_tmp],
+ sizeof(abuf) - len_tmp,
+ " a%d_len=%lu",
+ arg, len_full);
+ }
+ len_tmp += snprintf(&abuf[len_tmp],
+ sizeof(abuf) - len_tmp,
+ " a%d[%d]=", arg, iter++);
+ } else
+ len_tmp += snprintf(&abuf[len_tmp],
+ sizeof(abuf) - len_tmp,
+ " a%d=", arg);
+ WARN_ON(len_tmp >= sizeof(abuf));
+ abuf[sizeof(abuf) - 1] = '\0';
+
+ /* log the arg in the audit record */
+ audit_log_format(*ab, "%s", abuf);
+ len_rem -= len_tmp;
+ len_tmp = len_buf;
+ if (encode) {
+ if (len_abuf > len_rem)
+ len_tmp = len_rem / 2; /* encoding */
+ audit_log_n_hex(*ab, buf, len_tmp);
+ len_rem -= len_tmp * 2;
+ len_abuf -= len_tmp * 2;
+ } else {
+ if (len_abuf > len_rem)
+ len_tmp = len_rem - 2; /* quotes */
+ audit_log_n_string(*ab, buf, len_tmp);
+ len_rem -= len_tmp + 2;
+ /* don't subtract the "2" because we still need
+ * to add quotes to the remaining string */
+ len_abuf -= len_tmp;
+ }
+ len_buf -= len_tmp;
+ buf += len_tmp;
+ }
- audit_log_format(*ab, "argc=%d", context->execve.argc);
+ /* ready to move to the next argument? */
+ if ((len_buf == 0) && !require_data) {
+ arg++;
+ iter = 0;
+ len_full = 0;
+ require_data = true;
+ encode = false;
+ }
+ } while (arg < context->execve.argc);
- /*
- * we need some kernel buffer to hold the userspace args. Just
- * allocate one big one rather than allocating one of the right size
- * for every single argument inside audit_log_single_execve_arg()
- * should be <8k allocation so should be pretty safe.
- */
- buf = kmalloc(MAX_EXECVE_AUDIT_LEN + 1, GFP_KERNEL);
- if (!buf) {
- audit_panic("out of memory for argv string");
- return;
- }
+ /* NOTE: the caller handles the final audit_log_end() call */
- for (i = 0; i < context->execve.argc; i++) {
- len = audit_log_single_execve_arg(context, ab, i,
- &len_sent, p, buf);
- if (len <= 0)
- break;
- p += len;
- }
- kfree(buf);
+out:
+ kfree(buf_head);
}
static void show_special(struct audit_context *context, int *call_panic)
diff --git a/kernel/cgroup.c b/kernel/cgroup.c
index ae83d9602aa0..8c9823947c7a 100644
--- a/kernel/cgroup.c
+++ b/kernel/cgroup.c
@@ -6002,7 +6002,7 @@ static int cgroup_css_links_read(struct seq_file *seq, void *v)
struct task_struct *task;
int count = 0;
- seq_printf(seq, "css_set %p\n", cset);
+ seq_printf(seq, "css_set %pK\n", cset);
list_for_each_entry(task, &cset->tasks, cg_list) {
if (count++ > MAX_TASKS_SHOWN_PER_CSS)
diff --git a/kernel/power/qos.c b/kernel/power/qos.c
index 69c32c42080f..582b66e882ce 100644
--- a/kernel/power/qos.c
+++ b/kernel/power/qos.c
@@ -358,7 +358,11 @@ int pm_qos_update_target(struct pm_qos_constraints *c,
spin_unlock_irqrestore(&pm_qos_lock, flags);
trace_pm_qos_update_target(action, prev_value, curr_value);
- if (prev_value != curr_value) {
+ /*
+ * if cpu mask bits are set, call the notifier call chain
+ * to update the new qos restriction for the cores
+ */
+ if (!cpumask_empty(&cpus)) {
ret = 1;
if (c->notifiers)
blocking_notifier_call_chain(c->notifiers,
@@ -592,7 +596,6 @@ void pm_qos_add_request(struct pm_qos_request *req,
#ifdef CONFIG_SMP
case PM_QOS_REQ_AFFINE_IRQ:
if (irq_can_set_affinity(req->irq)) {
- int ret = 0;
struct irq_desc *desc = irq_to_desc(req->irq);
struct cpumask *mask = desc->irq_data.common->affinity;
@@ -602,13 +605,6 @@ void pm_qos_add_request(struct pm_qos_request *req,
req->irq_notify.notify = pm_qos_irq_notify;
req->irq_notify.release = pm_qos_irq_release;
- ret = irq_set_affinity_notifier(req->irq,
- &req->irq_notify);
- if (ret) {
- WARN(1, KERN_ERR "IRQ affinity notify set failed\n");
- req->type = PM_QOS_REQ_ALL_CORES;
- cpumask_setall(&req->cpus_affine);
- }
} else {
req->type = PM_QOS_REQ_ALL_CORES;
cpumask_setall(&req->cpus_affine);
@@ -630,6 +626,24 @@ void pm_qos_add_request(struct pm_qos_request *req,
trace_pm_qos_add_request(pm_qos_class, value);
pm_qos_update_target(pm_qos_array[pm_qos_class]->constraints,
req, PM_QOS_ADD_REQ, value);
+
+#ifdef CONFIG_SMP
+ if (req->type == PM_QOS_REQ_AFFINE_IRQ &&
+ irq_can_set_affinity(req->irq)) {
+ int ret = 0;
+
+ ret = irq_set_affinity_notifier(req->irq,
+ &req->irq_notify);
+ if (ret) {
+ WARN(1, "IRQ affinity notify set failed\n");
+ req->type = PM_QOS_REQ_ALL_CORES;
+ cpumask_setall(&req->cpus_affine);
+ pm_qos_update_target(
+ pm_qos_array[pm_qos_class]->constraints,
+ req, PM_QOS_UPDATE_REQ, value);
+ }
+ }
+#endif
}
EXPORT_SYMBOL_GPL(pm_qos_add_request);
diff --git a/kernel/sched/core.c b/kernel/sched/core.c
index a5d101e8a5f2..d7846edd7a79 100644
--- a/kernel/sched/core.c
+++ b/kernel/sched/core.c
@@ -5600,7 +5600,6 @@ int do_isolation_work_cpu_stop(void *data)
*/
nohz_balance_clear_nohz_mask(cpu);
- clear_hmp_request(cpu);
local_irq_enable();
return 0;
}
@@ -5682,7 +5681,7 @@ int sched_isolate_cpu(int cpu)
if (trace_sched_isolate_enabled())
start_time = sched_clock();
- lock_device_hotplug();
+ cpu_maps_update_begin();
cpumask_andnot(&avail_cpus, cpu_online_mask, cpu_isolated_mask);
@@ -5725,13 +5724,14 @@ int sched_isolate_cpu(int cpu)
migrate_sync_cpu(cpu, cpumask_first(&avail_cpus));
stop_cpus(cpumask_of(cpu), do_isolation_work_cpu_stop, 0);
+ clear_hmp_request(cpu);
calc_load_migrate(rq);
update_max_interval();
sched_update_group_capacities(cpu);
out:
- unlock_device_hotplug();
+ cpu_maps_update_done();
trace_sched_isolate(cpu, cpumask_bits(cpu_isolated_mask)[0],
start_time, 1);
return ret_code;
@@ -5752,8 +5752,6 @@ int sched_unisolate_cpu_unlocked(int cpu)
if (trace_sched_isolate_enabled())
start_time = sched_clock();
- lock_device_hotplug_assert();
-
if (!cpu_isolation_vote[cpu]) {
ret_code = -EINVAL;
goto out;
@@ -5792,9 +5790,9 @@ int sched_unisolate_cpu(int cpu)
{
int ret_code;
- lock_device_hotplug();
+ cpu_maps_update_begin();
ret_code = sched_unisolate_cpu_unlocked(cpu);
- unlock_device_hotplug();
+ cpu_maps_update_done();
return ret_code;
}
@@ -8073,6 +8071,9 @@ void __init sched_init(void)
atomic_set(&rq->nr_iowait, 0);
}
+ i = alloc_related_thread_groups();
+ BUG_ON(i);
+
set_hmp_defaults();
set_load_weight(&init_task);
diff --git a/kernel/sched/core_ctl.c b/kernel/sched/core_ctl.c
index 9b21a09ec4ba..aac12bfc2ae6 100644
--- a/kernel/sched/core_ctl.c
+++ b/kernel/sched/core_ctl.c
@@ -893,14 +893,10 @@ static int __ref cpu_callback(struct notifier_block *nfb,
unsigned int need;
int ret = NOTIFY_OK;
- /* Don't affect suspend resume */
- if (action & CPU_TASKS_FROZEN)
- return NOTIFY_OK;
-
if (unlikely(!cluster || !cluster->inited))
return NOTIFY_OK;
- switch (action) {
+ switch (action & ~CPU_TASKS_FROZEN) {
case CPU_UP_PREPARE:
/* If online state of CPU somehow got out of sync, fix it. */
@@ -1095,7 +1091,7 @@ static int __init core_ctl_init(void)
cpufreq_register_notifier(&cpufreq_pol_nb, CPUFREQ_POLICY_NOTIFIER);
cpufreq_register_notifier(&cpufreq_gov_nb, CPUFREQ_GOVINFO_NOTIFIER);
- lock_device_hotplug();
+ cpu_maps_update_begin();
for_each_online_cpu(cpu) {
struct cpufreq_policy *policy;
int ret;
@@ -1109,7 +1105,7 @@ static int __init core_ctl_init(void)
cpufreq_cpu_put(policy);
}
}
- unlock_device_hotplug();
+ cpu_maps_update_done();
initialized = true;
return 0;
}
diff --git a/kernel/sched/hmp.c b/kernel/sched/hmp.c
index 968a41e0e81e..6304c5030137 100644
--- a/kernel/sched/hmp.c
+++ b/kernel/sched/hmp.c
@@ -641,14 +641,18 @@ void clear_hmp_request(int cpu)
clear_boost_kick(cpu);
clear_reserved(cpu);
if (rq->push_task) {
+ struct task_struct *push_task = NULL;
+
raw_spin_lock_irqsave(&rq->lock, flags);
if (rq->push_task) {
clear_reserved(rq->push_cpu);
- put_task_struct(rq->push_task);
+ push_task = rq->push_task;
rq->push_task = NULL;
}
rq->active_balance = 0;
raw_spin_unlock_irqrestore(&rq->lock, flags);
+ if (push_task)
+ put_task_struct(push_task);
}
}
@@ -784,11 +788,12 @@ __read_mostly unsigned int sched_major_task_runtime = 10000000;
static unsigned int sync_cpu;
-static LIST_HEAD(related_thread_groups);
+struct related_thread_group *related_thread_groups[MAX_NUM_CGROUP_COLOC_ID];
+static LIST_HEAD(active_related_thread_groups);
static DEFINE_RWLOCK(related_thread_group_lock);
#define for_each_related_thread_group(grp) \
- list_for_each_entry(grp, &related_thread_groups, list)
+ list_for_each_entry(grp, &active_related_thread_groups, list)
/*
* Task load is categorized into buckets for the purpose of top task tracking.
@@ -1767,20 +1772,20 @@ static int send_notification(struct rq *rq, int check_pred, int check_groups)
if (freq_required < cur_freq + sysctl_sched_pred_alert_freq)
return 0;
} else {
- read_lock(&related_thread_group_lock);
+ read_lock_irqsave(&related_thread_group_lock, flags);
/*
* Protect from concurrent update of rq->prev_runnable_sum and
* group cpu load
*/
- raw_spin_lock_irqsave(&rq->lock, flags);
+ raw_spin_lock(&rq->lock);
if (check_groups)
_group_load_in_cpu(cpu_of(rq), &group_load, NULL);
new_load = rq->prev_runnable_sum + group_load;
new_load = freq_policy_load(rq, new_load);
- raw_spin_unlock_irqrestore(&rq->lock, flags);
- read_unlock(&related_thread_group_lock);
+ raw_spin_unlock(&rq->lock);
+ read_unlock_irqrestore(&related_thread_group_lock, flags);
cur_freq = load_to_freq(rq, rq->old_busy_time);
freq_required = load_to_freq(rq, new_load);
@@ -3052,7 +3057,7 @@ void reset_all_window_stats(u64 window_start, unsigned int window_size)
read_unlock(&tasklist_lock);
- list_for_each_entry(grp, &related_thread_groups, list) {
+ list_for_each_entry(grp, &active_related_thread_groups, list) {
int j;
for_each_possible_cpu(j) {
@@ -3202,14 +3207,16 @@ void sched_get_cpus_busy(struct sched_load *busy,
if (unlikely(cpus == 0))
return;
+ local_irq_save(flags);
+
+ read_lock(&related_thread_group_lock);
+
/*
* This function could be called in timer context, and the
* current task may have been executing for a long time. Ensure
* that the window stats are current by doing an update.
*/
- read_lock(&related_thread_group_lock);
- local_irq_save(flags);
for_each_cpu(cpu, query_cpus)
raw_spin_lock(&cpu_rq(cpu)->lock);
@@ -3309,10 +3316,11 @@ skip_early:
for_each_cpu(cpu, query_cpus)
raw_spin_unlock(&(cpu_rq(cpu))->lock);
- local_irq_restore(flags);
read_unlock(&related_thread_group_lock);
+ local_irq_restore(flags);
+
i = 0;
for_each_cpu(cpu, query_cpus) {
rq = cpu_rq(cpu);
@@ -3965,47 +3973,54 @@ _group_cpu_time(struct related_thread_group *grp, int cpu)
return grp ? per_cpu_ptr(grp->cpu_time, cpu) : NULL;
}
-struct related_thread_group *alloc_related_thread_group(int group_id)
+static inline struct related_thread_group*
+lookup_related_thread_group(unsigned int group_id)
{
- struct related_thread_group *grp;
-
- grp = kzalloc(sizeof(*grp), GFP_ATOMIC);
- if (!grp)
- return ERR_PTR(-ENOMEM);
-
- if (alloc_group_cputime(grp)) {
- kfree(grp);
- return ERR_PTR(-ENOMEM);
- }
-
- grp->id = group_id;
- INIT_LIST_HEAD(&grp->tasks);
- INIT_LIST_HEAD(&grp->list);
- raw_spin_lock_init(&grp->lock);
-
- return grp;
+ return related_thread_groups[group_id];
}
-struct related_thread_group *lookup_related_thread_group(unsigned int group_id)
+int alloc_related_thread_groups(void)
{
+ int i, ret;
struct related_thread_group *grp;
- list_for_each_entry(grp, &related_thread_groups, list) {
- if (grp->id == group_id)
- return grp;
+ /* groupd_id = 0 is invalid as it's special id to remove group. */
+ for (i = 1; i < MAX_NUM_CGROUP_COLOC_ID; i++) {
+ grp = kzalloc(sizeof(*grp), GFP_NOWAIT);
+ if (!grp) {
+ ret = -ENOMEM;
+ goto err;
+ }
+
+ if (alloc_group_cputime(grp)) {
+ kfree(grp);
+ ret = -ENOMEM;
+ goto err;
+ }
+
+ grp->id = i;
+ INIT_LIST_HEAD(&grp->tasks);
+ INIT_LIST_HEAD(&grp->list);
+ raw_spin_lock_init(&grp->lock);
+
+ related_thread_groups[i] = grp;
}
- return NULL;
-}
+ return 0;
-/* See comments before preferred_cluster() */
-static void free_related_thread_group(struct rcu_head *rcu)
-{
- struct related_thread_group *grp = container_of(rcu, struct
- related_thread_group, rcu);
+err:
+ for (i = 1; i < MAX_NUM_CGROUP_COLOC_ID; i++) {
+ grp = lookup_related_thread_group(i);
+ if (grp) {
+ free_group_cputime(grp);
+ kfree(grp);
+ related_thread_groups[i] = NULL;
+ } else {
+ break;
+ }
+ }
- free_group_cputime(grp);
- kfree(grp);
+ return ret;
}
static void remove_task_from_group(struct task_struct *p)
@@ -4030,10 +4045,12 @@ static void remove_task_from_group(struct task_struct *p)
raw_spin_unlock(&grp->lock);
/* Reserved groups cannot be destroyed */
- if (empty_group && grp->id != DEFAULT_CGROUP_COLOC_ID) {
- list_del(&grp->list);
- call_rcu(&grp->rcu, free_related_thread_group);
- }
+ if (empty_group && grp->id != DEFAULT_CGROUP_COLOC_ID)
+ /*
+ * We test whether grp->list is attached with list_empty()
+ * hence re-init the list after deletion.
+ */
+ list_del_init(&grp->list);
}
static int
@@ -4105,53 +4122,15 @@ void add_new_task_to_grp(struct task_struct *new)
write_unlock_irqrestore(&related_thread_group_lock, flags);
}
-#if defined(CONFIG_SCHED_TUNE) && defined(CONFIG_CGROUP_SCHEDTUNE)
-/*
- * We create a default colocation group at boot. There is no need to
- * synchronize tasks between cgroups at creation time because the
- * correct cgroup hierarchy is not available at boot. Therefore cgroup
- * colocation is turned off by default even though the colocation group
- * itself has been allocated. Furthermore this colocation group cannot
- * be destroyted once it has been created. All of this has been as part
- * of runtime optimizations.
- *
- * The job of synchronizing tasks to the colocation group is done when
- * the colocation flag in the cgroup is turned on.
- */
-static int __init create_default_coloc_group(void)
-{
- struct related_thread_group *grp = NULL;
- unsigned long flags;
-
- grp = alloc_related_thread_group(DEFAULT_CGROUP_COLOC_ID);
- if (IS_ERR(grp)) {
- WARN_ON(1);
- return -ENOMEM;
- }
-
- write_lock_irqsave(&related_thread_group_lock, flags);
- list_add(&grp->list, &related_thread_groups);
- write_unlock_irqrestore(&related_thread_group_lock, flags);
-
- update_freq_aggregate_threshold(MAX_FREQ_AGGR_THRESH);
- return 0;
-}
-late_initcall(create_default_coloc_group);
-
-int sync_cgroup_colocation(struct task_struct *p, bool insert)
-{
- unsigned int grp_id = insert ? DEFAULT_CGROUP_COLOC_ID : 0;
-
- return sched_set_group_id(p, grp_id);
-}
-#endif
-
-int sched_set_group_id(struct task_struct *p, unsigned int group_id)
+static int __sched_set_group_id(struct task_struct *p, unsigned int group_id)
{
int rc = 0;
unsigned long flags;
struct related_thread_group *grp = NULL;
+ if (group_id >= MAX_NUM_CGROUP_COLOC_ID)
+ return -EINVAL;
+
raw_spin_lock_irqsave(&p->pi_lock, flags);
write_lock(&related_thread_group_lock);
@@ -4167,29 +4146,26 @@ int sched_set_group_id(struct task_struct *p, unsigned int group_id)
}
grp = lookup_related_thread_group(group_id);
- if (!grp) {
- /* This is a reserved id */
- if (group_id == DEFAULT_CGROUP_COLOC_ID) {
- rc = -EINVAL;
- goto done;
- }
-
- grp = alloc_related_thread_group(group_id);
- if (IS_ERR(grp)) {
- rc = -ENOMEM;
- goto done;
- }
-
- list_add(&grp->list, &related_thread_groups);
- }
+ if (list_empty(&grp->list))
+ list_add(&grp->list, &active_related_thread_groups);
rc = add_task_to_group(p, grp);
done:
write_unlock(&related_thread_group_lock);
raw_spin_unlock_irqrestore(&p->pi_lock, flags);
+
return rc;
}
+int sched_set_group_id(struct task_struct *p, unsigned int group_id)
+{
+ /* DEFAULT_CGROUP_COLOC_ID is a reserved id */
+ if (group_id == DEFAULT_CGROUP_COLOC_ID)
+ return -EINVAL;
+
+ return __sched_set_group_id(p, group_id);
+}
+
unsigned int sched_get_group_id(struct task_struct *p)
{
unsigned int group_id;
@@ -4203,6 +4179,42 @@ unsigned int sched_get_group_id(struct task_struct *p)
return group_id;
}
+#if defined(CONFIG_SCHED_TUNE) && defined(CONFIG_CGROUP_SCHEDTUNE)
+/*
+ * We create a default colocation group at boot. There is no need to
+ * synchronize tasks between cgroups at creation time because the
+ * correct cgroup hierarchy is not available at boot. Therefore cgroup
+ * colocation is turned off by default even though the colocation group
+ * itself has been allocated. Furthermore this colocation group cannot
+ * be destroyted once it has been created. All of this has been as part
+ * of runtime optimizations.
+ *
+ * The job of synchronizing tasks to the colocation group is done when
+ * the colocation flag in the cgroup is turned on.
+ */
+static int __init create_default_coloc_group(void)
+{
+ struct related_thread_group *grp = NULL;
+ unsigned long flags;
+
+ grp = lookup_related_thread_group(DEFAULT_CGROUP_COLOC_ID);
+ write_lock_irqsave(&related_thread_group_lock, flags);
+ list_add(&grp->list, &active_related_thread_groups);
+ write_unlock_irqrestore(&related_thread_group_lock, flags);
+
+ update_freq_aggregate_threshold(MAX_FREQ_AGGR_THRESH);
+ return 0;
+}
+late_initcall(create_default_coloc_group);
+
+int sync_cgroup_colocation(struct task_struct *p, bool insert)
+{
+ unsigned int grp_id = insert ? DEFAULT_CGROUP_COLOC_ID : 0;
+
+ return __sched_set_group_id(p, grp_id);
+}
+#endif
+
static void update_cpu_cluster_capacity(const cpumask_t *cpus)
{
int i;
diff --git a/kernel/sched/sched.h b/kernel/sched/sched.h
index 30838bb9b442..f569c6fe3cbb 100644
--- a/kernel/sched/sched.h
+++ b/kernel/sched/sched.h
@@ -1448,6 +1448,8 @@ static inline void update_cgroup_boost_settings(void) { }
static inline void restore_cgroup_boost_settings(void) { }
#endif
+extern int alloc_related_thread_groups(void);
+
#else /* CONFIG_SCHED_HMP */
struct hmp_sched_stats;
@@ -1638,6 +1640,7 @@ static inline void set_hmp_defaults(void) { }
static inline void clear_reserved(int cpu) { }
static inline void sched_boost_parse_dt(void) {}
+static inline int alloc_related_thread_groups(void) { return 0; }
#define trace_sched_cpu_load(...)
#define trace_sched_cpu_load_lb(...)
diff --git a/mm/page_isolation.c b/mm/page_isolation.c
index 00c96462cc36..3ecd3807c2c2 100644
--- a/mm/page_isolation.c
+++ b/mm/page_isolation.c
@@ -7,6 +7,7 @@
#include <linux/pageblock-flags.h>
#include <linux/memory.h>
#include <linux/hugetlb.h>
+#include <linux/kasan.h>
#include "internal.h"
static int set_migratetype_isolate(struct page *page,
@@ -105,6 +106,8 @@ static void unset_migratetype_isolate(struct page *page, unsigned migratetype)
if (pfn_valid_within(page_to_pfn(buddy)) &&
!is_migrate_isolate_page(buddy)) {
__isolate_free_page(page, order);
+ kasan_alloc_pages(page, order);
+ arch_alloc_page(page, order);
kernel_map_pages(page, (1 << order), 1);
set_page_refcounted(page);
isolated_page = page;
diff --git a/net/core/sock.c b/net/core/sock.c
index 0d91f7dca751..fed6f3462c95 100644
--- a/net/core/sock.c
+++ b/net/core/sock.c
@@ -1439,8 +1439,12 @@ struct sock *sk_alloc(struct net *net, int family, gfp_t priority,
}
EXPORT_SYMBOL(sk_alloc);
-void sk_destruct(struct sock *sk)
+/* Sockets having SOCK_RCU_FREE will call this function after one RCU
+ * grace period. This is the case for UDP sockets and TCP listeners.
+ */
+static void __sk_destruct(struct rcu_head *head)
{
+ struct sock *sk = container_of(head, struct sock, sk_rcu);
struct sk_filter *filter;
if (sk->sk_destruct)
@@ -1467,6 +1471,14 @@ void sk_destruct(struct sock *sk)
sk_prot_free(sk->sk_prot_creator, sk);
}
+void sk_destruct(struct sock *sk)
+{
+ if (sock_flag(sk, SOCK_RCU_FREE))
+ call_rcu(&sk->sk_rcu, __sk_destruct);
+ else
+ __sk_destruct(&sk->sk_rcu);
+}
+
static void __sk_free(struct sock *sk)
{
if (unlikely(sock_diag_has_destroy_listeners(sk) && sk->sk_net_refcnt))
diff --git a/net/netfilter/nfnetlink.c b/net/netfilter/nfnetlink.c
index 77afe913d03d..9adedba78eea 100644
--- a/net/netfilter/nfnetlink.c
+++ b/net/netfilter/nfnetlink.c
@@ -326,10 +326,12 @@ replay:
nlh = nlmsg_hdr(skb);
err = 0;
- if (nlmsg_len(nlh) < sizeof(struct nfgenmsg) ||
- skb->len < nlh->nlmsg_len) {
- err = -EINVAL;
- goto ack;
+ if (nlh->nlmsg_len < NLMSG_HDRLEN ||
+ skb->len < nlh->nlmsg_len ||
+ nlmsg_len(nlh) < sizeof(struct nfgenmsg)) {
+ nfnl_err_reset(&err_list);
+ status |= NFNL_BATCH_FAILURE;
+ goto done;
}
/* Only requests are handled by the kernel */
diff --git a/net/netlink/af_netlink.c b/net/netlink/af_netlink.c
index 7a5fa0c98377..2b67ae1c53e4 100644
--- a/net/netlink/af_netlink.c
+++ b/net/netlink/af_netlink.c
@@ -926,16 +926,6 @@ static void netlink_skb_set_owner_r(struct sk_buff *skb, struct sock *sk)
static void netlink_sock_destruct(struct sock *sk)
{
- struct netlink_sock *nlk = nlk_sk(sk);
-
- if (nlk->cb_running) {
- if (nlk->cb.done)
- nlk->cb.done(&nlk->cb);
-
- module_put(nlk->cb.module);
- kfree_skb(nlk->cb.skb);
- }
-
skb_queue_purge(&sk->sk_receive_queue);
#ifdef CONFIG_NETLINK_MMAP
if (1) {
@@ -1070,8 +1060,9 @@ static struct sock *netlink_lookup(struct net *net, int protocol, u32 portid)
rcu_read_lock();
sk = __netlink_lookup(table, portid, net);
- if (sk)
- sock_hold(sk);
+ if (sk && !atomic_inc_not_zero(&sk->sk_refcnt))
+ sk = NULL;
+
rcu_read_unlock();
return sk;
@@ -1198,6 +1189,7 @@ static int __netlink_create(struct net *net, struct socket *sock,
mutex_init(&nlk->pg_vec_lock);
#endif
+ sock_set_flag(sk, SOCK_RCU_FREE);
sk->sk_destruct = netlink_sock_destruct;
sk->sk_protocol = protocol;
return 0;
@@ -1262,13 +1254,6 @@ out_module:
goto out;
}
-static void deferred_put_nlk_sk(struct rcu_head *head)
-{
- struct netlink_sock *nlk = container_of(head, struct netlink_sock, rcu);
-
- sock_put(&nlk->sk);
-}
-
static int netlink_release(struct socket *sock)
{
struct sock *sk = sock->sk;
@@ -1341,7 +1326,19 @@ static int netlink_release(struct socket *sock)
local_bh_disable();
sock_prot_inuse_add(sock_net(sk), &netlink_proto, -1);
local_bh_enable();
- call_rcu(&nlk->rcu, deferred_put_nlk_sk);
+ if (nlk->cb_running) {
+ mutex_lock(nlk->cb_mutex);
+ if (nlk->cb_running) {
+ if (nlk->cb.done)
+ nlk->cb.done(&nlk->cb);
+
+ module_put(nlk->cb.module);
+ kfree_skb(nlk->cb.skb);
+ nlk->cb_running = false;
+ }
+ mutex_unlock(nlk->cb_mutex);
+ }
+ sock_put(sk);
return 0;
}
diff --git a/net/netlink/af_netlink.h b/net/netlink/af_netlink.h
index 14437d9b1965..6acee01a419f 100644
--- a/net/netlink/af_netlink.h
+++ b/net/netlink/af_netlink.h
@@ -52,7 +52,6 @@ struct netlink_sock {
#endif /* CONFIG_NETLINK_MMAP */
struct rhash_head node;
- struct rcu_head rcu;
};
static inline struct netlink_sock *nlk_sk(struct sock *sk)
diff --git a/net/rmnet_data/rmnet_data_handlers.c b/net/rmnet_data/rmnet_data_handlers.c
index 185b609e637f..35b94e9da0d9 100644
--- a/net/rmnet_data/rmnet_data_handlers.c
+++ b/net/rmnet_data/rmnet_data_handlers.c
@@ -505,6 +505,7 @@ static int rmnet_map_egress_handler(struct sk_buff *skb,
if (pskb_expand_head(skb, required_headroom, 0, GFP_KERNEL)) {
LOGD("Failed to add headroom of %d bytes",
required_headroom);
+ kfree_skb(skb);
return 1;
}
}
@@ -528,6 +529,7 @@ static int rmnet_map_egress_handler(struct sk_buff *skb,
if (!map_header) {
LOGD("%s", "Failed to add MAP header to egress packet");
+ kfree_skb(skb);
return 1;
}
diff --git a/net/wireless/chan.c b/net/wireless/chan.c
index cf14c7e22fb3..d5ccaeaa76e0 100644
--- a/net/wireless/chan.c
+++ b/net/wireless/chan.c
@@ -749,7 +749,7 @@ static bool cfg80211_ir_permissive_chan(struct wiphy *wiphy,
* and thus fail the GO instantiation, consider only the interfaces of
* the current registered device.
*/
- list_for_each_entry(wdev, &rdev->wdev_list, list) {
+ list_for_each_entry(wdev, &rdev->wiphy.wdev_list, list) {
struct ieee80211_channel *other_chan = NULL;
int r1, r2;
diff --git a/net/wireless/core.c b/net/wireless/core.c
index 6d3402434a63..16043faba52c 100644
--- a/net/wireless/core.c
+++ b/net/wireless/core.c
@@ -3,6 +3,7 @@
*
* Copyright 2006-2010 Johannes Berg <johannes@sipsolutions.net>
* Copyright 2013-2014 Intel Mobile Communications GmbH
+ * Copyright 2015 Intel Deutschland GmbH
*/
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
@@ -157,7 +158,7 @@ int cfg80211_switch_netns(struct cfg80211_registered_device *rdev,
if (!(rdev->wiphy.flags & WIPHY_FLAG_NETNS_OK))
return -EOPNOTSUPP;
- list_for_each_entry(wdev, &rdev->wdev_list, list) {
+ list_for_each_entry(wdev, &rdev->wiphy.wdev_list, list) {
if (!wdev->netdev)
continue;
wdev->netdev->features &= ~NETIF_F_NETNS_LOCAL;
@@ -171,7 +172,8 @@ int cfg80211_switch_netns(struct cfg80211_registered_device *rdev,
/* failed -- clean up to old netns */
net = wiphy_net(&rdev->wiphy);
- list_for_each_entry_continue_reverse(wdev, &rdev->wdev_list,
+ list_for_each_entry_continue_reverse(wdev,
+ &rdev->wiphy.wdev_list,
list) {
if (!wdev->netdev)
continue;
@@ -230,7 +232,7 @@ void cfg80211_shutdown_all_interfaces(struct wiphy *wiphy)
ASSERT_RTNL();
- list_for_each_entry(wdev, &rdev->wdev_list, list) {
+ list_for_each_entry(wdev, &rdev->wiphy.wdev_list, list) {
if (wdev->netdev) {
dev_close(wdev->netdev);
continue;
@@ -298,7 +300,8 @@ void cfg80211_destroy_ifaces(struct cfg80211_registered_device *rdev)
kfree(item);
spin_unlock_irq(&rdev->destroy_list_lock);
- list_for_each_entry_safe(wdev, tmp, &rdev->wdev_list, list) {
+ list_for_each_entry_safe(wdev, tmp,
+ &rdev->wiphy.wdev_list, list) {
if (nlportid == wdev->owner_nlportid)
rdev_del_virtual_intf(rdev, wdev);
}
@@ -400,7 +403,7 @@ use_default_name:
dev_set_name(&rdev->wiphy.dev, PHY_NAME "%d", rdev->wiphy_idx);
}
- INIT_LIST_HEAD(&rdev->wdev_list);
+ INIT_LIST_HEAD(&rdev->wiphy.wdev_list);
INIT_LIST_HEAD(&rdev->beacon_registrations);
spin_lock_init(&rdev->beacon_registrations_lock);
spin_lock_init(&rdev->bss_lock);
@@ -812,7 +815,7 @@ void wiphy_unregister(struct wiphy *wiphy)
nl80211_notify_wiphy(rdev, NL80211_CMD_DEL_WIPHY);
rdev->wiphy.registered = false;
- WARN_ON(!list_empty(&rdev->wdev_list));
+ WARN_ON(!list_empty(&rdev->wiphy.wdev_list));
/*
* First remove the hardware from everywhere, this makes
@@ -949,7 +952,7 @@ static int cfg80211_netdev_notifier_call(struct notifier_block *nb,
spin_lock_init(&wdev->mgmt_registrations_lock);
wdev->identifier = ++rdev->wdev_id;
- list_add_rcu(&wdev->list, &rdev->wdev_list);
+ list_add_rcu(&wdev->list, &rdev->wiphy.wdev_list);
rdev->devlist_generation++;
/* can only change netns with wiphy */
dev->features |= NETIF_F_NETNS_LOCAL;
diff --git a/net/wireless/core.h b/net/wireless/core.h
index fcd59e76a8e5..a06a1056f726 100644
--- a/net/wireless/core.h
+++ b/net/wireless/core.h
@@ -50,8 +50,7 @@ struct cfg80211_registered_device {
/* wiphy index, internal only */
int wiphy_idx;
- /* associated wireless interfaces, protected by rtnl or RCU */
- struct list_head wdev_list;
+ /* protected by RTNL */
int devlist_generation, wdev_id;
int opencount; /* also protected by devlist_mtx */
wait_queue_head_t dev_wait;
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index 40299f19c09b..375d6c1732fa 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -103,7 +103,7 @@ __cfg80211_wdev_from_attrs(struct net *netns, struct nlattr **attrs)
if (have_wdev_id && rdev->wiphy_idx != wiphy_idx)
continue;
- list_for_each_entry(wdev, &rdev->wdev_list, list) {
+ list_for_each_entry(wdev, &rdev->wiphy.wdev_list, list) {
if (have_ifidx && wdev->netdev &&
wdev->netdev->ifindex == ifidx) {
result = wdev;
@@ -149,7 +149,7 @@ __cfg80211_rdev_from_attrs(struct net *netns, struct nlattr **attrs)
tmp = cfg80211_rdev_by_wiphy_idx(wdev_id >> 32);
if (tmp) {
/* make sure wdev exists */
- list_for_each_entry(wdev, &tmp->wdev_list, list) {
+ list_for_each_entry(wdev, &tmp->wiphy.wdev_list, list) {
if (wdev->identifier != (u32)wdev_id)
continue;
found = true;
@@ -524,7 +524,7 @@ static int nl80211_prepare_wdev_dump(struct sk_buff *skb,
*rdev = wiphy_to_rdev(wiphy);
*wdev = NULL;
- list_for_each_entry(tmp, &(*rdev)->wdev_list, list) {
+ list_for_each_entry(tmp, &(*rdev)->wiphy.wdev_list, list) {
if (tmp->identifier == cb->args[1]) {
*wdev = tmp;
break;
@@ -2504,7 +2504,7 @@ static int nl80211_dump_interface(struct sk_buff *skb, struct netlink_callback *
}
if_idx = 0;
- list_for_each_entry(wdev, &rdev->wdev_list, list) {
+ list_for_each_entry(wdev, &rdev->wiphy.wdev_list, list) {
if (if_idx < if_start) {
if_idx++;
continue;
@@ -2776,7 +2776,7 @@ static int nl80211_new_interface(struct sk_buff *skb, struct genl_info *info)
spin_lock_init(&wdev->mgmt_registrations_lock);
wdev->identifier = ++rdev->wdev_id;
- list_add_rcu(&wdev->list, &rdev->wdev_list);
+ list_add_rcu(&wdev->list, &rdev->wiphy.wdev_list);
rdev->devlist_generation++;
break;
default:
@@ -3585,7 +3585,7 @@ static bool nl80211_get_ap_channel(struct cfg80211_registered_device *rdev,
struct wireless_dev *wdev;
bool ret = false;
- list_for_each_entry(wdev, &rdev->wdev_list, list) {
+ list_for_each_entry(wdev, &rdev->wiphy.wdev_list, list) {
if (wdev->iftype != NL80211_IFTYPE_AP &&
wdev->iftype != NL80211_IFTYPE_P2P_GO)
continue;
@@ -7770,12 +7770,14 @@ static int nl80211_join_ibss(struct sk_buff *skb, struct genl_info *info)
ibss.beacon_interval = 100;
- if (info->attrs[NL80211_ATTR_BEACON_INTERVAL]) {
+ if (info->attrs[NL80211_ATTR_BEACON_INTERVAL])
ibss.beacon_interval =
nla_get_u32(info->attrs[NL80211_ATTR_BEACON_INTERVAL]);
- if (ibss.beacon_interval < 1 || ibss.beacon_interval > 10000)
- return -EINVAL;
- }
+
+ err = cfg80211_validate_beacon_int(rdev, NL80211_IFTYPE_ADHOC,
+ ibss.beacon_interval);
+ if (err)
+ return err;
if (!rdev->ops->join_ibss)
return -EOPNOTSUPP;
@@ -9013,9 +9015,12 @@ static int nl80211_join_mesh(struct sk_buff *skb, struct genl_info *info)
if (info->attrs[NL80211_ATTR_BEACON_INTERVAL]) {
setup.beacon_interval =
nla_get_u32(info->attrs[NL80211_ATTR_BEACON_INTERVAL]);
- if (setup.beacon_interval < 10 ||
- setup.beacon_interval > 10000)
- return -EINVAL;
+
+ err = cfg80211_validate_beacon_int(rdev,
+ NL80211_IFTYPE_MESH_POINT,
+ setup.beacon_interval);
+ if (err)
+ return err;
}
if (info->attrs[NL80211_ATTR_DTIM_PERIOD]) {
@@ -10328,7 +10333,7 @@ static int nl80211_prepare_vendor_dump(struct sk_buff *skb,
*wdev = NULL;
if (cb->args[1]) {
- list_for_each_entry(tmp, &(*rdev)->wdev_list, list) {
+ list_for_each_entry(tmp, &wiphy->wdev_list, list) {
if (tmp->identifier == cb->args[1] - 1) {
*wdev = tmp;
break;
@@ -13339,7 +13344,7 @@ static int nl80211_netlink_notify(struct notifier_block * nb,
sched_scan_req->owner_nlportid == notify->portid)
schedule_scan_stop = true;
- list_for_each_entry_rcu(wdev, &rdev->wdev_list, list) {
+ list_for_each_entry_rcu(wdev, &rdev->wiphy.wdev_list, list) {
cfg80211_mlme_unregister_socket(wdev, notify->portid);
if (wdev->owner_nlportid == notify->portid)
diff --git a/net/wireless/reg.c b/net/wireless/reg.c
index 2fed05f2edf8..050d7948dd68 100644
--- a/net/wireless/reg.c
+++ b/net/wireless/reg.c
@@ -1685,7 +1685,7 @@ static void reg_leave_invalid_chans(struct wiphy *wiphy)
struct cfg80211_sched_scan_request *sched_scan_req;
ASSERT_RTNL();
- list_for_each_entry(wdev, &rdev->wdev_list, list)
+ list_for_each_entry(wdev, &rdev->wiphy.wdev_list, list)
if (!reg_wdev_chan_valid(wiphy, wdev)) {
dev = wdev->netdev;
switch (wdev->iftype) {
diff --git a/net/wireless/sme.c b/net/wireless/sme.c
index 37d8ab3a71be..e5b962d2ffe7 100644
--- a/net/wireless/sme.c
+++ b/net/wireless/sme.c
@@ -54,7 +54,7 @@ static bool cfg80211_is_all_countryie_ignore(void)
bool is_all_countryie_ignore = true;
list_for_each_entry(rdev, &cfg80211_rdev_list, list) {
- list_for_each_entry(wdev, &rdev->wdev_list, list) {
+ list_for_each_entry(wdev, &rdev->wiphy.wdev_list, list) {
wdev_lock(wdev);
if (!(wdev->wiphy->regulatory_flags &
REGULATORY_COUNTRY_IE_IGNORE)) {
@@ -246,7 +246,7 @@ void cfg80211_conn_work(struct work_struct *work)
rtnl_lock();
- list_for_each_entry(wdev, &rdev->wdev_list, list) {
+ list_for_each_entry(wdev, &rdev->wiphy.wdev_list, list) {
if (!wdev->netdev)
continue;
@@ -630,7 +630,7 @@ static bool cfg80211_is_all_idle(void)
* count as new regulatory hints.
*/
list_for_each_entry(rdev, &cfg80211_rdev_list, list) {
- list_for_each_entry(wdev, &rdev->wdev_list, list) {
+ list_for_each_entry(wdev, &rdev->wiphy.wdev_list, list) {
wdev_lock(wdev);
if (wdev->conn || wdev->current_bss)
is_all_idle = false;
diff --git a/net/wireless/util.c b/net/wireless/util.c
index acff02fcc281..ef394e8a42bc 100644
--- a/net/wireless/util.c
+++ b/net/wireless/util.c
@@ -13,6 +13,7 @@
#include <net/dsfield.h>
#include <linux/if_vlan.h>
#include <linux/mpls.h>
+#include <linux/gcd.h>
#include "core.h"
#include "rdev-ops.h"
@@ -910,7 +911,7 @@ void cfg80211_process_rdev_events(struct cfg80211_registered_device *rdev)
ASSERT_RTNL();
- list_for_each_entry(wdev, &rdev->wdev_list, list)
+ list_for_each_entry(wdev, &rdev->wiphy.wdev_list, list)
cfg80211_process_wdev_events(wdev);
}
@@ -1482,47 +1483,53 @@ bool ieee80211_chandef_to_operating_class(struct cfg80211_chan_def *chandef,
}
EXPORT_SYMBOL(ieee80211_chandef_to_operating_class);
-int cfg80211_validate_beacon_int(struct cfg80211_registered_device *rdev,
- enum nl80211_iftype iftype, u32 beacon_int)
+static void cfg80211_calculate_bi_data(struct wiphy *wiphy, u32 new_beacon_int,
+ u32 *beacon_int_gcd,
+ bool *beacon_int_different)
{
struct wireless_dev *wdev;
- struct iface_combination_params params = {
- .beacon_int_gcd = beacon_int, /* GCD(n) = n */
- };
- if (!beacon_int)
- return -EINVAL;
+ *beacon_int_gcd = 0;
+ *beacon_int_different = false;
- params.iftype_num[iftype] = 1;
- list_for_each_entry(wdev, &rdev->wdev_list, list) {
+ list_for_each_entry(wdev, &wiphy->wdev_list, list) {
if (!wdev->beacon_interval)
continue;
- params.iftype_num[wdev->iftype]++;
- }
-
- list_for_each_entry(wdev, &rdev->wdev_list, list) {
- u32 bi_prev = wdev->beacon_interval;
-
- if (!wdev->beacon_interval)
+ if (!*beacon_int_gcd) {
+ *beacon_int_gcd = wdev->beacon_interval;
continue;
+ }
- /* slight optimisation - skip identical BIs */
- if (wdev->beacon_interval == beacon_int)
+ if (wdev->beacon_interval == *beacon_int_gcd)
continue;
- params.beacon_int_different = true;
-
- /* Get the GCD */
- while (bi_prev != 0) {
- u32 tmp_bi = bi_prev;
+ *beacon_int_different = true;
+ *beacon_int_gcd = gcd(*beacon_int_gcd, wdev->beacon_interval);
+ }
- bi_prev = params.beacon_int_gcd % bi_prev;
- params.beacon_int_gcd = tmp_bi;
- }
+ if (new_beacon_int && *beacon_int_gcd != new_beacon_int) {
+ if (*beacon_int_gcd)
+ *beacon_int_different = true;
+ *beacon_int_gcd = gcd(*beacon_int_gcd, new_beacon_int);
}
+}
- return cfg80211_check_combinations(&rdev->wiphy, &params);
+int cfg80211_validate_beacon_int(struct cfg80211_registered_device *rdev,
+ enum nl80211_iftype iftype, u32 beacon_int)
+{
+ /*
+ * This is just a basic pre-condition check; if interface combinations
+ * are possible the driver must already be checking those with a call
+ * to cfg80211_check_combinations(), in which case we'll validate more
+ * through the cfg80211_calculate_bi_data() call and code in
+ * cfg80211_iter_combinations().
+ */
+
+ if (beacon_int < 10 || beacon_int > 10000)
+ return -EINVAL;
+
+ return 0;
}
int cfg80211_iter_combinations(struct wiphy *wiphy,
@@ -1536,6 +1543,21 @@ int cfg80211_iter_combinations(struct wiphy *wiphy,
int i, j, iftype;
int num_interfaces = 0;
u32 used_iftypes = 0;
+ u32 beacon_int_gcd;
+ bool beacon_int_different;
+
+ /*
+ * This is a bit strange, since the iteration used to rely only on
+ * the data given by the driver, but here it now relies on context,
+ * in form of the currently operating interfaces.
+ * This is OK for all current users, and saves us from having to
+ * push the GCD calculations into all the drivers.
+ * In the future, this should probably rely more on data that's in
+ * cfg80211 already - the only thing not would appear to be any new
+ * interfaces (while being brought up) and channel/radar data.
+ */
+ cfg80211_calculate_bi_data(wiphy, params->new_beacon_int,
+ &beacon_int_gcd, &beacon_int_different);
if (params->radar_detect) {
rcu_read_lock();
@@ -1598,14 +1620,11 @@ int cfg80211_iter_combinations(struct wiphy *wiphy,
if ((all_iftypes & used_iftypes) != used_iftypes)
goto cont;
- if (params->beacon_int_gcd) {
+ if (beacon_int_gcd) {
if (c->beacon_int_min_gcd &&
- params->beacon_int_gcd < c->beacon_int_min_gcd) {
- kfree(limits);
- return -EINVAL;
- }
- if (!c->beacon_int_min_gcd &&
- params->beacon_int_different)
+ beacon_int_gcd < c->beacon_int_min_gcd)
+ goto cont;
+ if (!c->beacon_int_min_gcd && beacon_int_different)
goto cont;
}
@@ -1701,7 +1720,7 @@ int cfg80211_can_use_iftype_chan(struct cfg80211_registered_device *rdev,
break;
}
- list_for_each_entry(wdev_iter, &rdev->wdev_list, list) {
+ list_for_each_entry(wdev_iter, &rdev->wiphy.wdev_list, list) {
if (wdev_iter == wdev)
continue;
if (wdev_iter->iftype == NL80211_IFTYPE_P2P_DEVICE) {
diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile
index f580a1048d65..5f21eb37eae4 100644
--- a/sound/soc/codecs/Makefile
+++ b/sound/soc/codecs/Makefile
@@ -139,6 +139,10 @@ snd-soc-wcd9xxx-v2-objs := wcd9xxx-common-v2.o wcd9xxx-resmgr-v2.o
ifeq ($(CONFIG_COMMON_CLK_MSM), y)
audio-ext-clock-objs := audio-ext-clk.o
endif
+
+ifeq ($(CONFIG_COMMON_CLK_QCOM), y)
+ audio-ext-clock-up-objs := audio-ext-clk-up.o
+endif
snd-soc-wcd-cpe-objs := wcd_cpe_services.o wcd_cpe_core.o
snd-soc-wsa881x-objs := wsa881x.o wsa881x-tables.o wsa881x-regmap.o wsa881x-temp-sensor.o
snd-soc-wcd-mbhc-objs := wcd-mbhc-v2.o
@@ -349,6 +353,9 @@ obj-$(CONFIG_SND_SOC_WCD934X) += wcd934x/
ifeq ($(CONFIG_COMMON_CLK_MSM), y)
obj-$(CONFIG_AUDIO_EXT_CLK) += audio-ext-clock.o
endif
+ifeq ($(CONFIG_COMMON_CLK_QCOM), y)
+ obj-$(CONFIG_AUDIO_EXT_CLK) += audio-ext-clock-up.o
+endif
obj-$(CONFIG_SND_SOC_WCD9XXX) += snd-soc-wcd9xxx.o
obj-$(CONFIG_SND_SOC_WCD9XXX_V2) += snd-soc-wcd9xxx-v2.o
obj-$(CONFIG_SND_SOC_WCD_CPE) += snd-soc-wcd-cpe.o
diff --git a/sound/soc/codecs/audio-ext-clk-up.c b/sound/soc/codecs/audio-ext-clk-up.c
new file mode 100644
index 000000000000..f989498e9c32
--- /dev/null
+++ b/sound/soc/codecs/audio-ext-clk-up.c
@@ -0,0 +1,577 @@
+/* Copyright (c) 2015-2016, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * 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/kernel.h>
+#include <linux/init.h>
+#include <linux/err.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/clk.h>
+#include <linux/clk-provider.h>
+#include "../../../drivers/clk/qcom/common.h"
+#include <linux/platform_device.h>
+#include <linux/gpio.h>
+#include <linux/of_gpio.h>
+#include <dt-bindings/clock/audio-ext-clk.h>
+#include <sound/q6afe-v2.h>
+
+enum audio_clk_mux {
+ AP_CLK2,
+ LPASS_MCLK,
+ LPASS_MCLK2,
+};
+
+struct pinctrl_info {
+ struct pinctrl *pinctrl;
+ struct pinctrl_state *sleep;
+ struct pinctrl_state *active;
+};
+
+struct audio_ext_ap_clk {
+ bool enabled;
+ int gpio;
+ struct clk_fixed_factor fact;
+};
+
+struct audio_ext_pmi_clk {
+ int gpio;
+ struct clk_fixed_factor fact;
+};
+
+struct audio_ext_ap_clk2 {
+ bool enabled;
+ struct pinctrl_info pnctrl_info;
+ struct clk_fixed_factor fact;
+};
+
+struct audio_ext_lpass_mclk {
+ struct pinctrl_info pnctrl_info;
+ struct clk_fixed_factor fact;
+};
+
+static struct afe_clk_set clk2_config = {
+ Q6AFE_LPASS_CLK_CONFIG_API_VERSION,
+ Q6AFE_LPASS_CLK_ID_SPEAKER_I2S_OSR,
+ Q6AFE_LPASS_IBIT_CLK_11_P2896_MHZ,
+ Q6AFE_LPASS_CLK_ATTRIBUTE_COUPLE_NO,
+ Q6AFE_LPASS_CLK_ROOT_DEFAULT,
+ 0,
+};
+
+static struct afe_clk_set lpass_default = {
+ Q6AFE_LPASS_CLK_CONFIG_API_VERSION,
+ Q6AFE_LPASS_CLK_ID_SPEAKER_I2S_OSR,
+ Q6AFE_LPASS_IBIT_CLK_11_P2896_MHZ,
+ Q6AFE_LPASS_CLK_ATTRIBUTE_COUPLE_NO,
+ Q6AFE_LPASS_CLK_ROOT_DEFAULT,
+ 0,
+};
+
+static struct afe_clk_set lpass_mclk = {
+ Q6AFE_LPASS_CLK_CONFIG_API_VERSION,
+ Q6AFE_LPASS_CLK_ID_MCLK_1,
+ Q6AFE_LPASS_OSR_CLK_11_P2896_MHZ,
+ Q6AFE_LPASS_CLK_ATTRIBUTE_COUPLE_NO,
+ Q6AFE_LPASS_CLK_ROOT_DEFAULT,
+ 0,
+};
+
+static inline struct audio_ext_ap_clk *to_audio_ap_clk(struct clk_hw *hw)
+{
+ return container_of(hw, struct audio_ext_ap_clk, fact.hw);
+}
+
+static int audio_ext_clk_prepare(struct clk_hw *hw)
+{
+ struct audio_ext_ap_clk *audio_clk = to_audio_ap_clk(hw);
+
+ pr_debug("%s: gpio: %d\n", __func__, audio_clk->gpio);
+ if (gpio_is_valid(audio_clk->gpio))
+ return gpio_direction_output(audio_clk->gpio, 1);
+ return 0;
+}
+
+static void audio_ext_clk_unprepare(struct clk_hw *hw)
+{
+ struct audio_ext_ap_clk *audio_clk = to_audio_ap_clk(hw);
+
+ pr_debug("%s: gpio: %d\n", __func__, audio_clk->gpio);
+ if (gpio_is_valid(audio_clk->gpio))
+ gpio_direction_output(audio_clk->gpio, 0);
+}
+
+static inline struct audio_ext_ap_clk2 *to_audio_ap_clk2(struct clk_hw *hw)
+{
+ return container_of(hw, struct audio_ext_ap_clk2, fact.hw);
+}
+
+static int audio_ext_clk2_prepare(struct clk_hw *hw)
+{
+ struct audio_ext_ap_clk2 *audio_clk2 = to_audio_ap_clk2(hw);
+ struct pinctrl_info *pnctrl_info = &audio_clk2->pnctrl_info;
+ int ret;
+
+
+ if (!pnctrl_info->pinctrl || !pnctrl_info->active)
+ return 0;
+
+ ret = pinctrl_select_state(pnctrl_info->pinctrl,
+ pnctrl_info->active);
+ if (ret) {
+ pr_err("%s: active state select failed with %d\n",
+ __func__, ret);
+ return -EIO;
+ }
+
+ clk2_config.enable = 1;
+ ret = afe_set_lpass_clk_cfg(IDX_RSVD_3, &clk2_config);
+ if (ret < 0) {
+ pr_err("%s: failed to set clock, ret = %d\n", __func__, ret);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static void audio_ext_clk2_unprepare(struct clk_hw *hw)
+{
+ struct audio_ext_ap_clk2 *audio_clk2 = to_audio_ap_clk2(hw);
+ struct pinctrl_info *pnctrl_info = &audio_clk2->pnctrl_info;
+ int ret;
+
+ if (!pnctrl_info->pinctrl || !pnctrl_info->sleep)
+ return;
+
+ ret = pinctrl_select_state(pnctrl_info->pinctrl,
+ pnctrl_info->sleep);
+ if (ret)
+ pr_err("%s: sleep state select failed with %d\n",
+ __func__, ret);
+
+ clk2_config.enable = 0;
+ ret = afe_set_lpass_clk_cfg(IDX_RSVD_3, &clk2_config);
+ if (ret < 0)
+ pr_err("%s: failed to reset clock, ret = %d\n", __func__, ret);
+}
+
+static inline struct audio_ext_lpass_mclk *to_audio_lpass_mclk(
+ struct clk_hw *hw)
+{
+ return container_of(hw, struct audio_ext_lpass_mclk, fact.hw);
+}
+
+static int audio_ext_lpass_mclk_prepare(struct clk_hw *hw)
+{
+ struct audio_ext_lpass_mclk *audio_lpass_mclk = to_audio_lpass_mclk(hw);
+ struct pinctrl_info *pnctrl_info = &audio_lpass_mclk->pnctrl_info;
+ int ret;
+
+ if (pnctrl_info->pinctrl) {
+ ret = pinctrl_select_state(pnctrl_info->pinctrl,
+ pnctrl_info->active);
+ if (ret) {
+ pr_err("%s: active state select failed with %d\n",
+ __func__, ret);
+ return -EIO;
+ }
+ }
+
+ lpass_mclk.enable = 1;
+ ret = afe_set_lpass_clock_v2(AFE_PORT_ID_PRIMARY_MI2S_RX,
+ &lpass_mclk);
+ if (ret < 0) {
+ pr_err("%s afe_set_digital_codec_core_clock failed\n",
+ __func__);
+ return ret;
+ }
+
+ return 0;
+}
+
+static void audio_ext_lpass_mclk_unprepare(struct clk_hw *hw)
+{
+ struct audio_ext_lpass_mclk *audio_lpass_mclk = to_audio_lpass_mclk(hw);
+ struct pinctrl_info *pnctrl_info = &audio_lpass_mclk->pnctrl_info;
+ int ret;
+
+ if (pnctrl_info->pinctrl) {
+ ret = pinctrl_select_state(pnctrl_info->pinctrl,
+ pnctrl_info->sleep);
+ if (ret) {
+ pr_err("%s: active state select failed with %d\n",
+ __func__, ret);
+ return;
+ }
+ }
+
+ lpass_mclk.enable = 0;
+ ret = afe_set_lpass_clock_v2(AFE_PORT_ID_PRIMARY_MI2S_RX,
+ &lpass_mclk);
+ if (ret < 0)
+ pr_err("%s: afe_set_digital_codec_core_clock failed, ret = %d\n",
+ __func__, ret);
+}
+
+static int audio_ext_lpass_mclk2_prepare(struct clk_hw *hw)
+{
+ struct audio_ext_lpass_mclk *audio_lpass_mclk2 =
+ to_audio_lpass_mclk(hw);
+ struct pinctrl_info *pnctrl_info = &audio_lpass_mclk2->pnctrl_info;
+ int ret;
+
+ if (pnctrl_info->pinctrl) {
+ ret = pinctrl_select_state(pnctrl_info->pinctrl,
+ pnctrl_info->active);
+ if (ret) {
+ pr_err("%s: active state select failed with %d\n",
+ __func__, ret);
+ return -EIO;
+ }
+ }
+
+ lpass_default.enable = 1;
+ ret = afe_set_lpass_clk_cfg(IDX_RSVD_3, &lpass_default);
+ if (ret < 0) {
+ pr_err("%s: failed to set clock, ret = %d\n", __func__, ret);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static void audio_ext_lpass_mclk2_unprepare(struct clk_hw *hw)
+{
+ struct audio_ext_lpass_mclk *audio_lpass_mclk2 =
+ to_audio_lpass_mclk(hw);
+ struct pinctrl_info *pnctrl_info = &audio_lpass_mclk2->pnctrl_info;
+ int ret;
+
+ if (pnctrl_info->pinctrl) {
+ ret = pinctrl_select_state(pnctrl_info->pinctrl,
+ pnctrl_info->sleep);
+ if (ret)
+ pr_err("%s: sleep state select failed with %d\n",
+ __func__, ret);
+ }
+
+ lpass_default.enable = 0;
+ ret = afe_set_lpass_clk_cfg(IDX_RSVD_3, &lpass_default);
+ if (ret < 0)
+ pr_err("%s: failed to reset clock, ret = %d\n", __func__, ret);
+}
+
+static struct clk_ops audio_ext_ap_clk_ops = {
+ .prepare = audio_ext_clk_prepare,
+ .unprepare = audio_ext_clk_unprepare,
+};
+
+static struct clk_ops audio_ext_ap_clk2_ops = {
+ .prepare = audio_ext_clk2_prepare,
+ .unprepare = audio_ext_clk2_unprepare,
+};
+
+static struct clk_ops audio_ext_lpass_mclk_ops = {
+ .prepare = audio_ext_lpass_mclk_prepare,
+ .unprepare = audio_ext_lpass_mclk_unprepare,
+};
+
+static struct clk_ops audio_ext_lpass_mclk2_ops = {
+ .prepare = audio_ext_lpass_mclk2_prepare,
+ .unprepare = audio_ext_lpass_mclk2_unprepare,
+};
+
+static struct audio_ext_pmi_clk audio_pmi_clk = {
+ .gpio = -EINVAL,
+ .fact = {
+ .mult = 1,
+ .div = 1,
+ .hw.init = &(struct clk_init_data){
+ .name = "audio_ext_pmi_clk",
+ .ops = &clk_dummy_ops,
+ },
+ },
+};
+
+static struct audio_ext_pmi_clk audio_pmi_lnbb_clk = {
+ .gpio = -EINVAL,
+ .fact = {
+ .mult = 1,
+ .div = 1,
+ .hw.init = &(struct clk_init_data){
+ .name = "audio_ext_pmi_lnbb_clk",
+ .ops = &clk_dummy_ops,
+ },
+ },
+};
+
+static struct audio_ext_ap_clk audio_ap_clk = {
+ .gpio = -EINVAL,
+ .fact = {
+ .mult = 1,
+ .div = 1,
+ .hw.init = &(struct clk_init_data){
+ .name = "audio_ap_clk",
+ .ops = &audio_ext_ap_clk_ops,
+ },
+ },
+};
+
+static struct audio_ext_ap_clk2 audio_ap_clk2 = {
+ .enabled = false,
+ .pnctrl_info = {NULL},
+ .fact = {
+ .mult = 1,
+ .div = 1,
+ .hw.init = &(struct clk_init_data){
+ .name = "audio_ap_clk2",
+ .ops = &audio_ext_ap_clk2_ops,
+ },
+ },
+};
+
+static struct audio_ext_lpass_mclk audio_lpass_mclk = {
+ .pnctrl_info = {NULL},
+ .fact = {
+ .mult = 1,
+ .div = 1,
+ .hw.init = &(struct clk_init_data){
+ .name = "audio_lpass_mclk",
+ .ops = &audio_ext_lpass_mclk_ops,
+ },
+ },
+};
+
+static struct audio_ext_lpass_mclk audio_lpass_mclk2 = {
+ .pnctrl_info = {NULL},
+ .fact = {
+ .mult = 1,
+ .div = 1,
+ .hw.init = &(struct clk_init_data){
+ .name = "audio_lpass_mclk2",
+ .ops = &audio_ext_lpass_mclk2_ops,
+ },
+ },
+};
+
+static struct clk_hw *audio_msm_hws[] = {
+ &audio_pmi_clk.fact.hw,
+ &audio_pmi_lnbb_clk.fact.hw,
+ &audio_ap_clk.fact.hw,
+ &audio_ap_clk2.fact.hw,
+ &audio_lpass_mclk.fact.hw,
+ &audio_lpass_mclk2.fact.hw,
+};
+
+static int audio_get_pinctrl(struct platform_device *pdev,
+ enum audio_clk_mux mux)
+{
+ struct pinctrl_info *pnctrl_info;
+ struct pinctrl *pinctrl;
+ int ret;
+
+ switch (mux) {
+ case AP_CLK2:
+ pnctrl_info = &audio_ap_clk2.pnctrl_info;
+ break;
+ case LPASS_MCLK:
+ pnctrl_info = &audio_lpass_mclk.pnctrl_info;
+ break;
+ case LPASS_MCLK2:
+ pnctrl_info = &audio_lpass_mclk2.pnctrl_info;
+ break;
+ default:
+ dev_err(&pdev->dev, "%s Not a valid MUX ID: %d\n",
+ __func__, mux);
+ return -EINVAL;
+ }
+ pnctrl_info = &audio_ap_clk2.pnctrl_info;
+
+ if (pnctrl_info->pinctrl) {
+ dev_dbg(&pdev->dev, "%s: already requested before\n",
+ __func__);
+ return -EINVAL;
+ }
+
+ pinctrl = devm_pinctrl_get(&pdev->dev);
+ if (IS_ERR_OR_NULL(pinctrl)) {
+ dev_dbg(&pdev->dev, "%s: Unable to get pinctrl handle\n",
+ __func__);
+ return -EINVAL;
+ }
+ pnctrl_info->pinctrl = pinctrl;
+ /* get all state handles from Device Tree */
+ pnctrl_info->sleep = pinctrl_lookup_state(pinctrl, "sleep");
+ if (IS_ERR(pnctrl_info->sleep)) {
+ dev_err(&pdev->dev, "%s: could not get sleep pinstate\n",
+ __func__);
+ goto err;
+ }
+ pnctrl_info->active = pinctrl_lookup_state(pinctrl, "active");
+ if (IS_ERR(pnctrl_info->active)) {
+ dev_err(&pdev->dev, "%s: could not get active pinstate\n",
+ __func__);
+ goto err;
+ }
+ /* Reset the TLMM pins to a default state */
+ ret = pinctrl_select_state(pnctrl_info->pinctrl,
+ pnctrl_info->sleep);
+ if (ret) {
+ dev_err(&pdev->dev, "%s: Disable TLMM pins failed with %d\n",
+ __func__, ret);
+ goto err;
+ }
+ return 0;
+
+err:
+ devm_pinctrl_put(pnctrl_info->pinctrl);
+ return -EINVAL;
+}
+
+static int audio_ref_clk_probe(struct platform_device *pdev)
+{
+ int clk_gpio;
+ int ret;
+ u32 mclk_freq;
+ struct clk *audio_clk;
+ struct device *dev = &pdev->dev;
+ int i;
+ struct clk_onecell_data *clk_data;
+
+ ret = of_property_read_u32(pdev->dev.of_node,
+ "qcom,codec-mclk-clk-freq",
+ &mclk_freq);
+ if (!ret) {
+ lpass_mclk.clk_freq_in_hz = mclk_freq;
+
+ ret = audio_get_pinctrl(pdev, LPASS_MCLK);
+ if (ret)
+ dev_err(&pdev->dev, "%s: Parsing pinctrl %s failed\n",
+ __func__, "LPASS_MCLK");
+ ret = audio_get_pinctrl(pdev, LPASS_MCLK2);
+ if (ret)
+ dev_dbg(&pdev->dev, "%s: Parsing pinctrl %s failed\n",
+ __func__, "LPASS_MCLK2");
+ }
+
+ clk_gpio = of_get_named_gpio(pdev->dev.of_node,
+ "qcom,audio-ref-clk-gpio", 0);
+ if (clk_gpio > 0) {
+ ret = gpio_request(clk_gpio, "EXT_CLK");
+ if (ret) {
+ dev_err(&pdev->dev,
+ "Request ext clk gpio failed %d, err:%d\n",
+ clk_gpio, ret);
+ goto err;
+ }
+ if (of_property_read_bool(pdev->dev.of_node,
+ "qcom,node_has_rpm_clock")) {
+ audio_pmi_clk.gpio = clk_gpio;
+ } else
+ audio_ap_clk.gpio = clk_gpio;
+
+ }
+
+ ret = audio_get_pinctrl(pdev, AP_CLK2);
+ if (ret)
+ dev_dbg(&pdev->dev, "%s: Parsing pinctrl failed\n",
+ __func__);
+
+ clk_data = devm_kzalloc(&pdev->dev, sizeof(*clk_data), GFP_KERNEL);
+ if (!clk_data)
+ goto err_gpio;
+
+ clk_data->clk_num = ARRAY_SIZE(audio_msm_hws);
+ clk_data->clks = devm_kzalloc(&pdev->dev,
+ clk_data->clk_num * sizeof(struct clk *),
+ GFP_KERNEL);
+ if (!clk_data->clks)
+ goto err_clk;
+
+ for (i = 0; i < ARRAY_SIZE(audio_msm_hws); i++) {
+ audio_clk = devm_clk_register(dev, audio_msm_hws[i]);
+ if (IS_ERR(audio_clk)) {
+ dev_err(&pdev->dev,
+ "%s: audio ref clock i = %d register failed\n",
+ __func__, i);
+ return PTR_ERR(audio_clk);
+ }
+ clk_data->clks[i] = audio_clk;
+ }
+
+ ret = of_clk_add_provider(pdev->dev.of_node,
+ of_clk_src_onecell_get, clk_data);
+ if (ret) {
+ dev_err(&pdev->dev, "%s: audio ref clock register failed\n",
+ __func__);
+ goto err_gpio;
+ }
+
+ return 0;
+
+err_clk:
+ if (clk_data)
+ devm_kfree(&pdev->dev, clk_data->clks);
+ devm_kfree(&pdev->dev, clk_data);
+err_gpio:
+ gpio_free(clk_gpio);
+
+err:
+ return ret;
+}
+
+static int audio_ref_clk_remove(struct platform_device *pdev)
+{
+ struct pinctrl_info *pnctrl_info = &audio_ap_clk2.pnctrl_info;
+
+ if (audio_pmi_clk.gpio > 0)
+ gpio_free(audio_pmi_clk.gpio);
+ else if (audio_ap_clk.gpio > 0)
+ gpio_free(audio_ap_clk.gpio);
+
+ if (pnctrl_info->pinctrl) {
+ devm_pinctrl_put(pnctrl_info->pinctrl);
+ pnctrl_info->pinctrl = NULL;
+ }
+
+ return 0;
+}
+
+static const struct of_device_id audio_ref_clk_match[] = {
+ {.compatible = "qcom,audio-ref-clk"},
+ {}
+};
+MODULE_DEVICE_TABLE(of, audio_ref_clk_match);
+
+static struct platform_driver audio_ref_clk_driver = {
+ .driver = {
+ .name = "audio-ref-clk",
+ .owner = THIS_MODULE,
+ .of_match_table = audio_ref_clk_match,
+ },
+ .probe = audio_ref_clk_probe,
+ .remove = audio_ref_clk_remove,
+};
+
+static int __init audio_ref_clk_platform_init(void)
+{
+ return platform_driver_register(&audio_ref_clk_driver);
+}
+module_init(audio_ref_clk_platform_init);
+
+static void __exit audio_ref_clk_platform_exit(void)
+{
+ platform_driver_unregister(&audio_ref_clk_driver);
+}
+module_exit(audio_ref_clk_platform_exit);
+
+MODULE_DESCRIPTION("Audio Ref Up Clock module platform driver");
+MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/codecs/wcd9335.c b/sound/soc/codecs/wcd9335.c
index 06e00fdfe6a1..71858e268232 100644
--- a/sound/soc/codecs/wcd9335.c
+++ b/sound/soc/codecs/wcd9335.c
@@ -13681,6 +13681,7 @@ static int tasha_codec_probe(struct snd_soc_codec *codec)
snd_soc_dapm_ignore_suspend(dapm, "AIF Mix Playback");
snd_soc_dapm_ignore_suspend(dapm, "AIF4 MAD TX");
snd_soc_dapm_ignore_suspend(dapm, "VIfeed");
+ snd_soc_dapm_ignore_suspend(dapm, "AIF5 CPE TX");
}
snd_soc_dapm_sync(dapm);
diff --git a/sound/soc/codecs/wcd934x/wcd934x.c b/sound/soc/codecs/wcd934x/wcd934x.c
index b0bb89c8d9c2..1fdf81a3a45f 100644
--- a/sound/soc/codecs/wcd934x/wcd934x.c
+++ b/sound/soc/codecs/wcd934x/wcd934x.c
@@ -1879,6 +1879,7 @@ static void tavil_codec_override(struct snd_soc_codec *codec, int mode,
{
if (mode == CLS_AB || mode == CLS_AB_HIFI) {
switch (event) {
+ case SND_SOC_DAPM_PRE_PMU:
case SND_SOC_DAPM_POST_PMU:
if (!(snd_soc_read(codec,
WCD934X_CDC_RX2_RX_PATH_CTL) & 0x10) &&
@@ -2088,6 +2089,9 @@ static int tavil_codec_enable_lineout_pa(struct snd_soc_dapm_widget *w,
}
switch (event) {
+ case SND_SOC_DAPM_PRE_PMU:
+ tavil_codec_override(codec, CLS_AB, event);
+ break;
case SND_SOC_DAPM_POST_PMU:
/*
* 5ms sleep is required after PA is enabled as per
@@ -2102,6 +2106,13 @@ static int tavil_codec_enable_lineout_pa(struct snd_soc_dapm_widget *w,
lineout_mix_vol_reg,
0x10, 0x00);
break;
+ case SND_SOC_DAPM_POST_PMD:
+ /*
+ * 5ms sleep is required after PA is disabled as per
+ * HW requirement
+ */
+ usleep_range(5000, 5500);
+ tavil_codec_override(codec, CLS_AB, event);
default:
break;
};
@@ -7039,10 +7050,12 @@ static const struct snd_soc_dapm_widget tavil_dapm_widgets[] = {
SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD),
SND_SOC_DAPM_PGA_E("LINEOUT1 PA", WCD934X_ANA_LO_1_2, 7, 0, NULL, 0,
tavil_codec_enable_lineout_pa,
- SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+ SND_SOC_DAPM_POST_PMD),
SND_SOC_DAPM_PGA_E("LINEOUT2 PA", WCD934X_ANA_LO_1_2, 6, 0, NULL, 0,
tavil_codec_enable_lineout_pa,
- SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+ SND_SOC_DAPM_POST_PMD),
SND_SOC_DAPM_PGA_E("ANC EAR PA", WCD934X_ANA_EAR, 7, 0, NULL, 0,
tavil_codec_enable_ear_pa, SND_SOC_DAPM_POST_PMU |
SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD),
@@ -8156,6 +8169,8 @@ static const struct tavil_reg_mask_val tavil_codec_reg_defaults[] = {
{WCD934X_CDC_RX0_RX_PATH_DSMDEM_CTL, 0x01, 0x01},
{WCD934X_CDC_RX1_RX_PATH_DSMDEM_CTL, 0x01, 0x01},
{WCD934X_CDC_RX2_RX_PATH_DSMDEM_CTL, 0x01, 0x01},
+ {WCD934X_CDC_RX3_RX_PATH_DSMDEM_CTL, 0x01, 0x01},
+ {WCD934X_CDC_RX4_RX_PATH_DSMDEM_CTL, 0x01, 0x01},
{WCD934X_CDC_RX7_RX_PATH_DSMDEM_CTL, 0x01, 0x01},
{WCD934X_CDC_RX8_RX_PATH_DSMDEM_CTL, 0x01, 0x01},
{WCD934X_CDC_COMPANDER8_CTL7, 0x1E, 0x18},
@@ -8189,6 +8204,8 @@ static const struct tavil_reg_mask_val tavil_codec_reg_init_1_1_val[] = {
{WCD934X_CDC_COMPANDER2_CTL7, 0x1E, 0x06},
{WCD934X_HPH_NEW_INT_RDAC_HD2_CTL_L, 0xFF, 0x84},
{WCD934X_HPH_NEW_INT_RDAC_HD2_CTL_R, 0xFF, 0x84},
+ {WCD934X_CDC_RX3_RX_PATH_SEC0, 0xFC, 0xF4},
+ {WCD934X_CDC_RX4_RX_PATH_SEC0, 0xFC, 0xF4},
};
static const struct tavil_cpr_reg_defaults cpr_defaults[] = {
diff --git a/sound/soc/msm/msm-dai-fe.c b/sound/soc/msm/msm-dai-fe.c
index aa036d352f40..9c720acf8ef8 100644
--- a/sound/soc/msm/msm-dai-fe.c
+++ b/sound/soc/msm/msm-dai-fe.c
@@ -2449,6 +2449,63 @@ static struct snd_soc_dai_driver msm_fe_dais[] = {
.name = "VoiceMMode2",
.probe = fe_dai_probe,
},
+ {
+ .capture = {
+ .stream_name = "MultiMedia17 Capture",
+ .aif_name = "MM_UL17",
+ .rates = (SNDRV_PCM_RATE_8000_48000|
+ SNDRV_PCM_RATE_KNOT),
+ .formats = (SNDRV_PCM_FMTBIT_S16_LE |
+ SNDRV_PCM_FMTBIT_S24_LE |
+ SNDRV_PCM_FMTBIT_S24_3LE),
+ .channels_min = 1,
+ .channels_max = 8,
+ .rate_min = 8000,
+ .rate_max = 48000,
+ },
+ .ops = &msm_fe_Multimedia_dai_ops,
+ .compress_new = snd_soc_new_compress,
+ .name = "MultiMedia17",
+ .probe = fe_dai_probe,
+ },
+ {
+ .capture = {
+ .stream_name = "MultiMedia18 Capture",
+ .aif_name = "MM_UL18",
+ .rates = (SNDRV_PCM_RATE_8000_48000|
+ SNDRV_PCM_RATE_KNOT),
+ .formats = (SNDRV_PCM_FMTBIT_S16_LE |
+ SNDRV_PCM_FMTBIT_S24_LE |
+ SNDRV_PCM_FMTBIT_S24_3LE),
+ .channels_min = 1,
+ .channels_max = 8,
+ .rate_min = 8000,
+ .rate_max = 48000,
+ },
+ .ops = &msm_fe_Multimedia_dai_ops,
+ .compress_new = snd_soc_new_compress,
+ .name = "MultiMedia18",
+ .probe = fe_dai_probe,
+ },
+ {
+ .capture = {
+ .stream_name = "MultiMedia19 Capture",
+ .aif_name = "MM_UL19",
+ .rates = (SNDRV_PCM_RATE_8000_48000|
+ SNDRV_PCM_RATE_KNOT),
+ .formats = (SNDRV_PCM_FMTBIT_S16_LE |
+ SNDRV_PCM_FMTBIT_S24_LE |
+ SNDRV_PCM_FMTBIT_S24_3LE),
+ .channels_min = 1,
+ .channels_max = 8,
+ .rate_min = 8000,
+ .rate_max = 48000,
+ },
+ .ops = &msm_fe_Multimedia_dai_ops,
+ .compress_new = snd_soc_new_compress,
+ .name = "MultiMedia19",
+ .probe = fe_dai_probe,
+ },
};
static int msm_fe_dai_dev_probe(struct platform_device *pdev)
diff --git a/sound/soc/msm/qdsp6v2/msm-compress-q6-v2.c b/sound/soc/msm/qdsp6v2/msm-compress-q6-v2.c
index a2cd6c6f98db..d3c0850d8de2 100644
--- a/sound/soc/msm/qdsp6v2/msm-compress-q6-v2.c
+++ b/sound/soc/msm/qdsp6v2/msm-compress-q6-v2.c
@@ -55,6 +55,10 @@
#define DSP_NUM_OUTPUT_FRAME_BUFFERED 2
#define FLAC_BLK_SIZE_LIMIT 65535
+/* Timestamp mode payload offsets */
+#define TS_LSW_OFFSET 6
+#define TS_MSW_OFFSET 7
+
/* decoder parameter length */
#define DDP_DEC_MAX_NUM_PARAM 18
@@ -127,6 +131,13 @@ struct msm_compr_audio {
uint64_t bytes_received; /* from userspace */
uint64_t bytes_sent; /* to DSP */
+ uint64_t received_total; /* bytes received from DSP */
+ uint64_t bytes_copied; /* to userspace */
+ uint64_t bytes_read; /* from DSP */
+ uint32_t bytes_read_offset; /* bytes read offset */
+
+ uint32_t ts_header_offset; /* holds the timestamp header offset */
+
int32_t first_buffer;
int32_t last_buffer;
int32_t partial_drain_delay;
@@ -362,6 +373,53 @@ static int msm_compr_send_buffer(struct msm_compr_audio *prtd)
return 0;
}
+static int msm_compr_read_buffer(struct msm_compr_audio *prtd)
+{
+ int buffer_length;
+ uint64_t bytes_available;
+ uint64_t buffer_sent;
+ struct audio_aio_read_param param;
+ int ret;
+
+ if (!atomic_read(&prtd->start)) {
+ pr_err("%s: stream is not in started state\n", __func__);
+ return -EINVAL;
+ }
+
+ buffer_length = prtd->codec_param.buffer.fragment_size -
+ prtd->ts_header_offset;
+ bytes_available = prtd->received_total - prtd->bytes_copied;
+ buffer_sent = prtd->bytes_read - prtd->bytes_copied;
+ if (buffer_sent + buffer_length + prtd->ts_header_offset
+ > prtd->buffer_size) {
+ pr_debug(" %s : Buffer is Full bytes_available: %llu\n",
+ __func__, bytes_available);
+ return 0;
+ }
+
+ memset(&param, 0x0, sizeof(struct audio_aio_read_param));
+ param.paddr = prtd->buffer_paddr + prtd->bytes_read_offset +
+ prtd->ts_header_offset;
+ param.len = buffer_length;
+ param.uid = buffer_length;
+ param.flags = prtd->codec_param.codec.flags;
+
+ pr_debug("%s: reading %d bytes from DSP byte_offset = %llu\n",
+ __func__, buffer_length, prtd->bytes_read);
+ ret = q6asm_async_read(prtd->audio_client, &param);
+ if (ret < 0) {
+ pr_err("%s: q6asm_async_read failed - %d\n",
+ __func__, ret);
+ return ret;
+ }
+ prtd->bytes_read += buffer_length;
+ prtd->bytes_read_offset += buffer_length;
+ if (prtd->bytes_read_offset >= prtd->buffer_size)
+ prtd->bytes_read_offset -= prtd->buffer_size;
+
+ return 0;
+}
+
static void compr_event_handler(uint32_t opcode,
uint32_t token, uint32_t *payload, void *priv)
{
@@ -374,6 +432,8 @@ static void compr_event_handler(uint32_t opcode,
int stream_id;
uint32_t stream_index;
unsigned long flags;
+ uint64_t read_size;
+ uint32_t *buff_addr;
if (!prtd) {
pr_err("%s: prtd is NULL\n", __func__);
@@ -459,6 +519,49 @@ static void compr_event_handler(uint32_t opcode,
spin_unlock_irqrestore(&prtd->lock, flags);
break;
+
+ case ASM_DATA_EVENT_READ_DONE_V2:
+ spin_lock_irqsave(&prtd->lock, flags);
+
+ pr_debug("ASM_DATA_EVENT_READ_DONE_V2 offset %d, length %d\n",
+ prtd->byte_offset, payload[4]);
+
+ if (prtd->ts_header_offset) {
+ /* Update the header for received buffer */
+ buff_addr = prtd->buffer + prtd->byte_offset;
+ /* Write the length of the buffer */
+ *buff_addr = prtd->codec_param.buffer.fragment_size
+ - prtd->ts_header_offset;
+ buff_addr++;
+ /* Write the offset */
+ *buff_addr = prtd->ts_header_offset;
+ buff_addr++;
+ /* Write the TS LSW */
+ *buff_addr = payload[TS_LSW_OFFSET];
+ buff_addr++;
+ /* Write the TS MSW */
+ *buff_addr = payload[TS_MSW_OFFSET];
+ }
+ /* Always assume read_size is same as fragment_size */
+ read_size = prtd->codec_param.buffer.fragment_size;
+ prtd->byte_offset += read_size;
+ prtd->received_total += read_size;
+ if (prtd->byte_offset >= prtd->buffer_size)
+ prtd->byte_offset -= prtd->buffer_size;
+
+ snd_compr_fragment_elapsed(cstream);
+
+ if (!atomic_read(&prtd->start)) {
+ pr_debug("read_done received while not started, treat as xrun");
+ atomic_set(&prtd->xrun, 1);
+ spin_unlock_irqrestore(&prtd->lock, flags);
+ break;
+ }
+ msm_compr_read_buffer(prtd);
+
+ spin_unlock_irqrestore(&prtd->lock, flags);
+ break;
+
case ASM_DATA_EVENT_RENDERED_EOS:
spin_lock_irqsave(&prtd->lock, flags);
pr_debug("%s: ASM_DATA_CMDRSP_EOS token 0x%x,stream id %d\n",
@@ -511,6 +614,14 @@ static void compr_event_handler(uint32_t opcode,
/* FIXME: A state is a better way, dealing with this*/
spin_lock_irqsave(&prtd->lock, flags);
+
+ if (cstream->direction == SND_COMPRESS_CAPTURE) {
+ atomic_set(&prtd->start, 1);
+ msm_compr_read_buffer(prtd);
+ spin_unlock_irqrestore(&prtd->lock, flags);
+ break;
+ }
+
if (!prtd->bytes_sent) {
bytes_available = prtd->bytes_received - prtd->copied_total;
if (bytes_available < cstream->runtime->fragment_size) {
@@ -958,7 +1069,8 @@ static int msm_compr_init_pp_params(struct snd_compr_stream *cstream,
return ret;
}
-static int msm_compr_configure_dsp(struct snd_compr_stream *cstream)
+static int msm_compr_configure_dsp_for_playback
+ (struct snd_compr_stream *cstream)
{
struct snd_compr_runtime *runtime = cstream->runtime;
struct msm_compr_audio *prtd = runtime->private_data;
@@ -1096,7 +1208,108 @@ static int msm_compr_configure_dsp(struct snd_compr_stream *cstream)
return ret;
}
-static int msm_compr_open(struct snd_compr_stream *cstream)
+static int msm_compr_configure_dsp_for_capture(struct snd_compr_stream *cstream)
+{
+ struct snd_compr_runtime *runtime = cstream->runtime;
+ struct msm_compr_audio *prtd = runtime->private_data;
+ struct snd_soc_pcm_runtime *soc_prtd = cstream->private_data;
+ uint16_t bits_per_sample;
+ uint16_t sample_word_size;
+ int dir = OUT, ret = 0;
+ struct audio_client *ac = prtd->audio_client;
+ uint32_t stream_index;
+
+ switch (prtd->codec_param.codec.format) {
+ case SNDRV_PCM_FORMAT_S24_LE:
+ bits_per_sample = 24;
+ sample_word_size = 32;
+ break;
+ case SNDRV_PCM_FORMAT_S24_3LE:
+ bits_per_sample = 24;
+ sample_word_size = 24;
+ break;
+ case SNDRV_PCM_FORMAT_S32_LE:
+ bits_per_sample = 32;
+ sample_word_size = 32;
+ break;
+ case SNDRV_PCM_FORMAT_S16_LE:
+ default:
+ bits_per_sample = 16;
+ sample_word_size = 16;
+ break;
+ }
+
+ pr_debug("%s: stream_id %d bits_per_sample %d\n",
+ __func__, ac->stream_id, bits_per_sample);
+
+ ret = q6asm_open_read_v4(prtd->audio_client, FORMAT_LINEAR_PCM,
+ bits_per_sample);
+ if (ret < 0) {
+ pr_err("%s: q6asm_open_read failed:%d\n", __func__, ret);
+ return ret;
+ }
+
+ ret = msm_pcm_routing_reg_phy_stream(soc_prtd->dai_link->be_id,
+ ac->perf_mode,
+ prtd->session_id,
+ SNDRV_PCM_STREAM_CAPTURE);
+ if (ret) {
+ pr_err("%s: stream reg failed:%d\n", __func__, ret);
+ return ret;
+ }
+
+ ret = q6asm_set_io_mode(ac, (COMPRESSED_STREAM_IO | ASYNC_IO_MODE));
+ if (ret < 0) {
+ pr_err("%s: Set IO mode failed\n", __func__);
+ return -EINVAL;
+ }
+
+ stream_index = STREAM_ARRAY_INDEX(ac->stream_id);
+ if (stream_index >= MAX_NUMBER_OF_STREAMS || stream_index < 0) {
+ pr_err("%s: Invalid stream index:%d", __func__, stream_index);
+ return -EINVAL;
+ }
+
+ runtime->fragments = prtd->codec_param.buffer.fragments;
+ runtime->fragment_size = prtd->codec_param.buffer.fragment_size;
+ pr_debug("%s: allocate %d buffers each of size %d\n",
+ __func__, runtime->fragments,
+ runtime->fragment_size);
+ ret = q6asm_audio_client_buf_alloc_contiguous(dir, ac,
+ runtime->fragment_size,
+ runtime->fragments);
+ if (ret < 0) {
+ pr_err("Audio Start: Buffer Allocation failed rc = %d\n", ret);
+ return -ENOMEM;
+ }
+
+ prtd->byte_offset = 0;
+ prtd->received_total = 0;
+ prtd->app_pointer = 0;
+ prtd->bytes_copied = 0;
+ prtd->bytes_read = 0;
+ prtd->bytes_read_offset = 0;
+ prtd->buffer = ac->port[dir].buf[0].data;
+ prtd->buffer_paddr = ac->port[dir].buf[0].phys;
+ prtd->buffer_size = runtime->fragments * runtime->fragment_size;
+
+ /* Bit-0 of flags represent timestamp mode */
+ if (prtd->codec_param.codec.flags & COMPRESSED_TIMESTAMP_FLAG)
+ prtd->ts_header_offset = sizeof(struct snd_codec_metadata);
+ else
+ prtd->ts_header_offset = 0;
+
+ pr_debug("%s: sample_rate = %d channels = %d bps = %d sample_word_size = %d\n",
+ __func__, prtd->sample_rate, prtd->num_channels,
+ bits_per_sample, sample_word_size);
+ ret = q6asm_enc_cfg_blk_pcm_format_support_v3(prtd->audio_client,
+ prtd->sample_rate, prtd->num_channels,
+ bits_per_sample, sample_word_size);
+
+ return ret;
+}
+
+static int msm_compr_playback_open(struct snd_compr_stream *cstream)
{
struct snd_compr_runtime *runtime = cstream->runtime;
struct snd_soc_pcm_runtime *rtd = cstream->private_data;
@@ -1181,15 +1394,80 @@ static int msm_compr_open(struct snd_compr_stream *cstream)
kfree(prtd);
return -ENOMEM;
}
+ pr_debug("%s: session ID %d\n", __func__, prtd->audio_client->session);
+ prtd->audio_client->perf_mode = false;
+ prtd->session_id = prtd->audio_client->session;
+ return 0;
+}
+
+static int msm_compr_capture_open(struct snd_compr_stream *cstream)
+{
+ struct snd_compr_runtime *runtime = cstream->runtime;
+ struct snd_soc_pcm_runtime *rtd = cstream->private_data;
+ struct msm_compr_audio *prtd;
+ struct msm_compr_pdata *pdata =
+ snd_soc_platform_get_drvdata(rtd->platform);
+
+ pr_debug("%s\n", __func__);
+ prtd = kzalloc(sizeof(struct msm_compr_audio), GFP_KERNEL);
+ if (prtd == NULL) {
+ pr_err("Failed to allocate memory for msm_compr_audio\n");
+ return -ENOMEM;
+ }
+
+ runtime->private_data = NULL;
+ prtd->cstream = cstream;
+ pdata->cstream[rtd->dai_link->be_id] = cstream;
+
+ prtd->audio_client = q6asm_audio_client_alloc(
+ (app_cb)compr_event_handler, prtd);
+ if (!prtd->audio_client) {
+ pr_err("%s: Could not allocate memory for client\n", __func__);
+ pdata->cstream[rtd->dai_link->be_id] = NULL;
+ kfree(prtd);
+ return -ENOMEM;
+ }
pr_debug("%s: session ID %d\n", __func__, prtd->audio_client->session);
prtd->audio_client->perf_mode = false;
prtd->session_id = prtd->audio_client->session;
+ prtd->codec = FORMAT_LINEAR_PCM;
+ prtd->bytes_copied = 0;
+ prtd->bytes_read = 0;
+ prtd->bytes_read_offset = 0;
+ prtd->received_total = 0;
+ prtd->byte_offset = 0;
+ prtd->sample_rate = 48000;
+ prtd->num_channels = 2;
+ prtd->first_buffer = 0;
+
+ spin_lock_init(&prtd->lock);
+
+ atomic_set(&prtd->eos, 0);
+ atomic_set(&prtd->start, 0);
+ atomic_set(&prtd->drain, 0);
+ atomic_set(&prtd->xrun, 0);
+ atomic_set(&prtd->close, 0);
+ atomic_set(&prtd->wait_on_close, 0);
+ atomic_set(&prtd->error, 0);
+
+ runtime->private_data = prtd;
return 0;
}
-static int msm_compr_free(struct snd_compr_stream *cstream)
+static int msm_compr_open(struct snd_compr_stream *cstream)
+{
+ int ret = 0;
+
+ if (cstream->direction == SND_COMPRESS_PLAYBACK)
+ ret = msm_compr_playback_open(cstream);
+ else if (cstream->direction == SND_COMPRESS_CAPTURE)
+ ret = msm_compr_capture_open(cstream);
+ return ret;
+}
+
+static int msm_compr_playback_free(struct snd_compr_stream *cstream)
{
struct snd_compr_runtime *runtime;
struct msm_compr_audio *prtd;
@@ -1284,6 +1562,76 @@ static int msm_compr_free(struct snd_compr_stream *cstream)
return 0;
}
+static int msm_compr_capture_free(struct snd_compr_stream *cstream)
+{
+ struct snd_compr_runtime *runtime;
+ struct msm_compr_audio *prtd;
+ struct snd_soc_pcm_runtime *soc_prtd;
+ struct msm_compr_pdata *pdata;
+ struct audio_client *ac;
+ int dir = OUT, stream_id;
+ unsigned long flags;
+ uint32_t stream_index;
+
+ if (!cstream) {
+ pr_err("%s cstream is null\n", __func__);
+ return 0;
+ }
+ runtime = cstream->runtime;
+ soc_prtd = cstream->private_data;
+ if (!runtime || !soc_prtd || !(soc_prtd->platform)) {
+ pr_err("%s runtime or soc_prtd or platform is null\n",
+ __func__);
+ return 0;
+ }
+ prtd = runtime->private_data;
+ if (!prtd) {
+ pr_err("%s prtd is null\n", __func__);
+ return 0;
+ }
+ pdata = snd_soc_platform_get_drvdata(soc_prtd->platform);
+ ac = prtd->audio_client;
+ if (!pdata || !ac) {
+ pr_err("%s pdata or ac is null\n", __func__);
+ return 0;
+ }
+
+ spin_lock_irqsave(&prtd->lock, flags);
+ stream_id = ac->stream_id;
+
+ stream_index = STREAM_ARRAY_INDEX(stream_id);
+ if ((stream_index < MAX_NUMBER_OF_STREAMS && stream_index >= 0)) {
+ spin_unlock_irqrestore(&prtd->lock, flags);
+ pr_debug("close stream %d", stream_id);
+ q6asm_stream_cmd(ac, CMD_CLOSE, stream_id);
+ spin_lock_irqsave(&prtd->lock, flags);
+ }
+ spin_unlock_irqrestore(&prtd->lock, flags);
+
+ pdata->cstream[soc_prtd->dai_link->be_id] = NULL;
+ msm_pcm_routing_dereg_phy_stream(soc_prtd->dai_link->be_id,
+ SNDRV_PCM_STREAM_CAPTURE);
+
+ q6asm_audio_client_buf_free_contiguous(dir, ac);
+
+ q6asm_audio_client_free(ac);
+
+ kfree(prtd);
+
+ return 0;
+}
+
+static int msm_compr_free(struct snd_compr_stream *cstream)
+{
+ int ret = 0;
+
+ if (cstream->direction == SND_COMPRESS_PLAYBACK)
+ ret = msm_compr_playback_free(cstream);
+ else if (cstream->direction == SND_COMPRESS_CAPTURE)
+ ret = msm_compr_capture_free(cstream);
+ return ret;
+}
+
static bool msm_compr_validate_codec_compr(__u32 codec_id)
{
int32_t i;
@@ -1449,7 +1797,10 @@ static int msm_compr_set_params(struct snd_compr_stream *cstream,
prtd->partial_drain_delay =
msm_compr_get_partial_drain_delay(frame_sz, prtd->sample_rate);
- ret = msm_compr_configure_dsp(cstream);
+ if (cstream->direction == SND_COMPRESS_PLAYBACK)
+ ret = msm_compr_configure_dsp_for_playback(cstream);
+ else if (cstream->direction == SND_COMPRESS_CAPTURE)
+ ret = msm_compr_configure_dsp_for_capture(cstream);
return ret;
}
@@ -1539,11 +1890,6 @@ static int msm_compr_trigger(struct snd_compr_stream *cstream, int cmd)
uint32_t stream_index;
uint16_t bits_per_sample = 16;
- if (cstream->direction != SND_COMPRESS_PLAYBACK) {
- pr_err("%s: Unsupported stream type\n", __func__);
- return -EINVAL;
- }
-
spin_lock_irqsave(&prtd->lock, flags);
if (atomic_read(&prtd->error)) {
pr_err("%s Got RESET EVENTS notification, return immediately",
@@ -1566,7 +1912,8 @@ static int msm_compr_trigger(struct snd_compr_stream *cstream, int cmd)
* compress passthrough volume is controlled in
* ADM by adm_send_compressed_device_mute()
*/
- if (prtd->compr_passthr == LEGACY_PCM) {
+ if (prtd->compr_passthr == LEGACY_PCM &&
+ cstream->direction == SND_COMPRESS_PLAYBACK) {
/* set volume for the stream before RUN */
rc = msm_compr_set_volume(cstream,
volume[0], volume[1]);
@@ -1578,8 +1925,9 @@ static int msm_compr_trigger(struct snd_compr_stream *cstream, int cmd)
if (rc)
pr_err("%s : init PP params failed : %d\n",
__func__, rc);
+ } else {
+ msm_compr_read_buffer(prtd);
}
-
/* issue RUN command for the stream */
q6asm_run_nowait(prtd->audio_client, 0, 0, 0);
break;
@@ -1589,6 +1937,18 @@ static int msm_compr_trigger(struct snd_compr_stream *cstream, int cmd)
prtd->gapless_state.gapless_transition);
stream_id = ac->stream_id;
atomic_set(&prtd->start, 0);
+ if (cstream->direction == SND_COMPRESS_CAPTURE) {
+ q6asm_cmd_nowait(prtd->audio_client, CMD_PAUSE);
+ atomic_set(&prtd->xrun, 0);
+ prtd->received_total = 0;
+ prtd->bytes_copied = 0;
+ prtd->bytes_read = 0;
+ prtd->bytes_read_offset = 0;
+ prtd->byte_offset = 0;
+ prtd->app_pointer = 0;
+ spin_unlock_irqrestore(&prtd->lock, flags);
+ break;
+ }
if (prtd->next_stream) {
pr_debug("%s: interrupt next track wait queues\n",
__func__);
@@ -1979,7 +2339,7 @@ static int msm_compr_trigger(struct snd_compr_stream *cstream, int cmd)
}
static int msm_compr_pointer(struct snd_compr_stream *cstream,
- struct snd_compr_tstamp *arg)
+ struct snd_compr_tstamp *arg)
{
struct snd_compr_runtime *runtime = cstream->runtime;
struct snd_soc_pcm_runtime *rtd = cstream->private_data;
@@ -1998,7 +2358,10 @@ static int msm_compr_pointer(struct snd_compr_stream *cstream,
spin_lock_irqsave(&prtd->lock, flags);
tstamp.sampling_rate = prtd->sample_rate;
tstamp.byte_offset = prtd->byte_offset;
- tstamp.copied_total = prtd->copied_total;
+ if (cstream->direction == SND_COMPRESS_PLAYBACK)
+ tstamp.copied_total = prtd->copied_total;
+ else if (cstream->direction == SND_COMPRESS_CAPTURE)
+ tstamp.copied_total = prtd->received_total;
first_buffer = prtd->first_buffer;
if (atomic_read(&prtd->error)) {
pr_err("%s Got RESET EVENTS notification, return error\n",
@@ -2012,37 +2375,39 @@ static int msm_compr_pointer(struct snd_compr_stream *cstream,
spin_unlock_irqrestore(&prtd->lock, flags);
return -ENETRESET;
}
+ if (cstream->direction == SND_COMPRESS_PLAYBACK) {
- gapless_transition = prtd->gapless_state.gapless_transition;
- spin_unlock_irqrestore(&prtd->lock, flags);
-
- if (gapless_transition)
- pr_debug("%s session time in gapless transition",
- __func__);
-
- /*
- - Do not query if no buffer has been given.
- - Do not query on a gapless transition.
- Playback for the 2nd stream can start (thus returning time
- starting from 0) before the driver knows about EOS of first stream.
- */
-
- if (!first_buffer && !gapless_transition) {
- if (pdata->use_legacy_api)
- rc = q6asm_get_session_time_legacy(prtd->audio_client,
- &prtd->marker_timestamp);
- else
- rc = q6asm_get_session_time(prtd->audio_client,
- &prtd->marker_timestamp);
+ gapless_transition = prtd->gapless_state.gapless_transition;
+ spin_unlock_irqrestore(&prtd->lock, flags);
+ if (gapless_transition)
+ pr_debug("%s session time in gapless transition",
+ __func__);
+ /*
+ *- Do not query if no buffer has been given.
+ *- Do not query on a gapless transition.
+ * Playback for the 2nd stream can start (thus returning time
+ * starting from 0) before the driver knows about EOS of first
+ * stream.
+ */
+ if (!first_buffer || gapless_transition) {
- if (rc < 0) {
- pr_err("%s: Get Session Time return value =%lld\n",
- __func__, timestamp);
- if (atomic_read(&prtd->error))
- return -ENETRESET;
+ if (pdata->use_legacy_api)
+ rc = q6asm_get_session_time_legacy(
+ prtd->audio_client, &prtd->marker_timestamp);
else
- return -EAGAIN;
+ rc = q6asm_get_session_time(
+ prtd->audio_client, &prtd->marker_timestamp);
+ if (rc < 0) {
+ pr_err("%s: Get Session Time return =%lld\n",
+ __func__, timestamp);
+ if (atomic_read(&prtd->error))
+ return -ENETRESET;
+ else
+ return -EAGAIN;
+ }
}
+ } else {
+ spin_unlock_irqrestore(&prtd->lock, flags);
}
timestamp = prtd->marker_timestamp;
@@ -2103,8 +2468,8 @@ static int msm_compr_ack(struct snd_compr_stream *cstream,
return 0;
}
-static int msm_compr_copy(struct snd_compr_stream *cstream,
- char __user *buf, size_t count)
+static int msm_compr_playback_copy(struct snd_compr_stream *cstream,
+ char __user *buf, size_t count)
{
struct snd_compr_runtime *runtime = cstream->runtime;
struct msm_compr_audio *prtd = runtime->private_data;
@@ -2166,6 +2531,60 @@ static int msm_compr_copy(struct snd_compr_stream *cstream,
return count;
}
+static int msm_compr_capture_copy(struct snd_compr_stream *cstream,
+ char __user *buf, size_t count)
+{
+ struct snd_compr_runtime *runtime = cstream->runtime;
+ struct msm_compr_audio *prtd = runtime->private_data;
+ void *source;
+ unsigned long flags;
+
+ pr_debug("%s: count = %zd\n", __func__, count);
+ if (!prtd->buffer) {
+ pr_err("%s: Buffer is not allocated yet ??", __func__);
+ return 0;
+ }
+
+ spin_lock_irqsave(&prtd->lock, flags);
+ if (atomic_read(&prtd->error)) {
+ pr_err("%s Got RESET EVENTS notification", __func__);
+ spin_unlock_irqrestore(&prtd->lock, flags);
+ return -ENETRESET;
+ }
+
+ source = prtd->buffer + prtd->app_pointer;
+ /* check if we have requested amount of data to copy to user*/
+ if (count <= prtd->received_total - prtd->bytes_copied) {
+ spin_unlock_irqrestore(&prtd->lock, flags);
+ if (copy_to_user(buf, source, count)) {
+ pr_err("copy_to_user failed");
+ return -EFAULT;
+ }
+ spin_lock_irqsave(&prtd->lock, flags);
+ prtd->app_pointer += count;
+ if (prtd->app_pointer >= prtd->buffer_size)
+ prtd->app_pointer -= prtd->buffer_size;
+ prtd->bytes_copied += count;
+ }
+ msm_compr_read_buffer(prtd);
+
+ spin_unlock_irqrestore(&prtd->lock, flags);
+ return count;
+}
+
+static int msm_compr_copy(struct snd_compr_stream *cstream,
+ char __user *buf, size_t count)
+{
+ int ret = 0;
+
+ pr_debug(" In %s\n", __func__);
+ if (cstream->direction == SND_COMPRESS_PLAYBACK)
+ ret = msm_compr_playback_copy(cstream, buf, count);
+ else if (cstream->direction == SND_COMPRESS_CAPTURE)
+ ret = msm_compr_capture_copy(cstream, buf, count);
+ return ret;
+}
+
static int msm_compr_get_caps(struct snd_compr_stream *cstream,
struct snd_compr_caps *arg)
{
@@ -2760,7 +3179,7 @@ static int msm_compr_dec_params_get(struct snd_kcontrol *kcontrol,
return 0;
}
-static int msm_compr_app_type_cfg_put(struct snd_kcontrol *kcontrol,
+static int msm_compr_playback_app_type_cfg_put(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
u64 fe_id = kcontrol->private_value;
@@ -2787,7 +3206,7 @@ static int msm_compr_app_type_cfg_put(struct snd_kcontrol *kcontrol,
return 0;
}
-static int msm_compr_app_type_cfg_get(struct snd_kcontrol *kcontrol,
+static int msm_compr_playback_app_type_cfg_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
u64 fe_id = kcontrol->private_value;
@@ -2822,6 +3241,68 @@ done:
return ret;
}
+static int msm_compr_capture_app_type_cfg_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ u64 fe_id = kcontrol->private_value;
+ int app_type;
+ int acdb_dev_id;
+ int sample_rate = 48000;
+
+ pr_debug("%s: fe_id- %llu\n", __func__, fe_id);
+ if (fe_id >= MSM_FRONTEND_DAI_MAX) {
+ pr_err("%s Received out of bounds fe_id %llu\n",
+ __func__, fe_id);
+ return -EINVAL;
+ }
+
+ app_type = ucontrol->value.integer.value[0];
+ acdb_dev_id = ucontrol->value.integer.value[1];
+ if (ucontrol->value.integer.value[2] != 0)
+ sample_rate = ucontrol->value.integer.value[2];
+ pr_debug("%s: app_type- %d acdb_dev_id- %d sample_rate- %d session_type- %d\n",
+ __func__, app_type, acdb_dev_id, sample_rate, SESSION_TYPE_TX);
+ msm_pcm_routing_reg_stream_app_type_cfg(fe_id, app_type,
+ acdb_dev_id, sample_rate, SESSION_TYPE_TX);
+
+ return 0;
+}
+
+static int msm_compr_capture_app_type_cfg_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ u64 fe_id = kcontrol->private_value;
+ int ret = 0;
+ int app_type;
+ int acdb_dev_id;
+ int sample_rate;
+
+ pr_debug("%s: fe_id- %llu\n", __func__, fe_id);
+ if (fe_id >= MSM_FRONTEND_DAI_MAX) {
+ pr_err("%s Received out of bounds fe_id %llu\n",
+ __func__, fe_id);
+ ret = -EINVAL;
+ goto done;
+ }
+
+ ret = msm_pcm_routing_get_stream_app_type_cfg(fe_id, SESSION_TYPE_TX,
+ &app_type, &acdb_dev_id, &sample_rate);
+ if (ret < 0) {
+ pr_err("%s: msm_pcm_routing_get_stream_app_type_cfg failed returned %d\n",
+ __func__, ret);
+ goto done;
+ }
+
+ ucontrol->value.integer.value[0] = app_type;
+ ucontrol->value.integer.value[1] = acdb_dev_id;
+ ucontrol->value.integer.value[2] = sample_rate;
+ pr_debug("%s: fedai_id %llu, session_type %d, app_type %d, acdb_dev_id %d, sample_rate %d\n",
+ __func__, fe_id, SESSION_TYPE_TX,
+ app_type, acdb_dev_id, sample_rate);
+done:
+ return ret;
+}
+
static int msm_compr_channel_map_put(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
@@ -3209,7 +3690,8 @@ static int msm_compr_add_dec_runtime_params_control(
static int msm_compr_add_app_type_cfg_control(struct snd_soc_pcm_runtime *rtd)
{
- const char *mixer_ctl_name = "Audio Stream";
+ const char *playback_mixer_ctl_name = "Audio Stream";
+ const char *capture_mixer_ctl_name = "Audio Stream Capture";
const char *deviceNo = "NN";
const char *suffix = "App Type Cfg";
char *mixer_str = NULL;
@@ -3220,8 +3702,8 @@ static int msm_compr_add_app_type_cfg_control(struct snd_soc_pcm_runtime *rtd)
.name = "?",
.access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
.info = msm_compr_app_type_cfg_info,
- .put = msm_compr_app_type_cfg_put,
- .get = msm_compr_app_type_cfg_get,
+ .put = msm_compr_playback_app_type_cfg_put,
+ .get = msm_compr_playback_app_type_cfg_get,
.private_value = 0,
}
};
@@ -3232,11 +3714,15 @@ static int msm_compr_add_app_type_cfg_control(struct snd_soc_pcm_runtime *rtd)
}
pr_debug("%s: added new compr FE ctl with name %s, id %d, cpu dai %s, device no %d\n",
- __func__, rtd->dai_link->name, rtd->dai_link->be_id,
- rtd->dai_link->cpu_dai_name, rtd->pcm->device);
+ __func__, rtd->dai_link->name, rtd->dai_link->be_id,
+ rtd->dai_link->cpu_dai_name, rtd->pcm->device);
+ if (rtd->compr->direction == SND_COMPRESS_PLAYBACK)
+ ctl_len = strlen(playback_mixer_ctl_name) + 1 + strlen(deviceNo)
+ + 1 + strlen(suffix) + 1;
+ else
+ ctl_len = strlen(capture_mixer_ctl_name) + 1 + strlen(deviceNo)
+ + 1 + strlen(suffix) + 1;
- ctl_len = strlen(mixer_ctl_name) + 1 + strlen(deviceNo) + 1 +
- strlen(suffix) + 1;
mixer_str = kzalloc(ctl_len, GFP_KERNEL);
if (!mixer_str) {
@@ -3244,14 +3730,31 @@ static int msm_compr_add_app_type_cfg_control(struct snd_soc_pcm_runtime *rtd)
return 0;
}
- snprintf(mixer_str, ctl_len, "%s %d %s", mixer_ctl_name,
- rtd->pcm->device, suffix);
+ if (rtd->compr->direction == SND_COMPRESS_PLAYBACK)
+ snprintf(mixer_str, ctl_len, "%s %d %s",
+ playback_mixer_ctl_name, rtd->pcm->device, suffix);
+ else
+ snprintf(mixer_str, ctl_len, "%s %d %s",
+ capture_mixer_ctl_name, rtd->pcm->device, suffix);
+
fe_app_type_cfg_control[0].name = mixer_str;
fe_app_type_cfg_control[0].private_value = rtd->dai_link->be_id;
+
+ if (rtd->compr->direction == SND_COMPRESS_PLAYBACK) {
+ fe_app_type_cfg_control[0].put =
+ msm_compr_playback_app_type_cfg_put;
+ fe_app_type_cfg_control[0].get =
+ msm_compr_playback_app_type_cfg_get;
+ } else {
+ fe_app_type_cfg_control[0].put =
+ msm_compr_capture_app_type_cfg_put;
+ fe_app_type_cfg_control[0].get =
+ msm_compr_capture_app_type_cfg_get;
+ }
pr_debug("Registering new mixer ctl %s", mixer_str);
snd_soc_add_platform_controls(rtd->platform,
- fe_app_type_cfg_control,
- ARRAY_SIZE(fe_app_type_cfg_control));
+ fe_app_type_cfg_control,
+ ARRAY_SIZE(fe_app_type_cfg_control));
kfree(mixer_str);
return 0;
}
diff --git a/sound/soc/msm/qdsp6v2/msm-dai-q6-v2.c b/sound/soc/msm/qdsp6v2/msm-dai-q6-v2.c
index 718f7017342b..f1f2fd908eca 100644
--- a/sound/soc/msm/qdsp6v2/msm-dai-q6-v2.c
+++ b/sound/soc/msm/qdsp6v2/msm-dai-q6-v2.c
@@ -2645,8 +2645,10 @@ static struct snd_soc_dai_driver msm_dai_q6_usb_rx_dai = {
.rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_11025 |
SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_22050 |
SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 |
- SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_96000 |
- SNDRV_PCM_RATE_192000 | SNDRV_PCM_RATE_384000,
+ SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_88200 |
+ SNDRV_PCM_RATE_96000 | SNDRV_PCM_RATE_176400 |
+ SNDRV_PCM_RATE_192000 | SNDRV_PCM_RATE_352800 |
+ SNDRV_PCM_RATE_384000,
.formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE |
SNDRV_PCM_FMTBIT_S24_3LE | SNDRV_PCM_FMTBIT_S32_LE,
.channels_min = 1,
@@ -2667,8 +2669,10 @@ static struct snd_soc_dai_driver msm_dai_q6_usb_tx_dai = {
.rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_11025 |
SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_22050 |
SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 |
- SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_96000 |
- SNDRV_PCM_RATE_192000 | SNDRV_PCM_RATE_384000,
+ SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_88200 |
+ SNDRV_PCM_RATE_96000 | SNDRV_PCM_RATE_176400 |
+ SNDRV_PCM_RATE_192000 | SNDRV_PCM_RATE_352800 |
+ SNDRV_PCM_RATE_384000,
.formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE |
SNDRV_PCM_FMTBIT_S24_3LE | SNDRV_PCM_FMTBIT_S32_LE,
.channels_min = 1,
diff --git a/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c b/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c
index 9164475386ff..a456cc2ab857 100644
--- a/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c
+++ b/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c
@@ -548,6 +548,15 @@ static struct msm_pcm_routing_fdai_data
/* MULTIMEDIA16 */
{{0, INVALID_SESSION, LEGACY_PCM_MODE, {NULL, NULL} },
{0, INVALID_SESSION, LEGACY_PCM_MODE, {NULL, NULL} } },
+ /* MULTIMEDIA17 */
+ {{0, INVALID_SESSION, LEGACY_PCM_MODE, {NULL, NULL} },
+ {0, INVALID_SESSION, LEGACY_PCM_MODE, {NULL, NULL} } },
+ /* MULTIMEDIA18 */
+ {{0, INVALID_SESSION, LEGACY_PCM_MODE, {NULL, NULL} },
+ {0, INVALID_SESSION, LEGACY_PCM_MODE, {NULL, NULL} } },
+ /* MULTIMEDIA19 */
+ {{0, INVALID_SESSION, LEGACY_PCM_MODE, {NULL, NULL} },
+ {0, INVALID_SESSION, LEGACY_PCM_MODE, {NULL, NULL} } },
};
static unsigned long session_copp_map[MSM_FRONTEND_DAI_MM_SIZE][2]
@@ -2288,6 +2297,21 @@ static const struct snd_kcontrol_new ext_ec_ref_mux_ul9 =
msm_route_ec_ref_rx_enum[0],
msm_routing_ec_ref_rx_get, msm_routing_ec_ref_rx_put);
+static const struct snd_kcontrol_new ext_ec_ref_mux_ul17 =
+ SOC_DAPM_ENUM_EXT("AUDIO_REF_EC_UL17 MUX Mux",
+ msm_route_ec_ref_rx_enum[0],
+ msm_routing_ec_ref_rx_get, msm_routing_ec_ref_rx_put);
+
+static const struct snd_kcontrol_new ext_ec_ref_mux_ul18 =
+ SOC_DAPM_ENUM_EXT("AUDIO_REF_EC_UL18 MUX Mux",
+ msm_route_ec_ref_rx_enum[0],
+ msm_routing_ec_ref_rx_get, msm_routing_ec_ref_rx_put);
+
+static const struct snd_kcontrol_new ext_ec_ref_mux_ul19 =
+ SOC_DAPM_ENUM_EXT("AUDIO_REF_EC_UL19 MUX Mux",
+ msm_route_ec_ref_rx_enum[0],
+ msm_routing_ec_ref_rx_get, msm_routing_ec_ref_rx_put);
+
static int msm_routing_ext_ec_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
@@ -2417,6 +2441,15 @@ static const struct snd_kcontrol_new pri_i2s_rx_mixer_controls[] = {
SOC_SINGLE_EXT("MultiMedia16", MSM_BACKEND_DAI_PRI_I2S_RX,
MSM_FRONTEND_DAI_MULTIMEDIA16, 1, 0, msm_routing_get_audio_mixer,
msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia17", MSM_BACKEND_DAI_PRI_I2S_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA17, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia18", MSM_BACKEND_DAI_PRI_I2S_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA18, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia19", MSM_BACKEND_DAI_PRI_I2S_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA19, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
};
static const struct snd_kcontrol_new sec_i2s_rx_mixer_controls[] = {
@@ -2468,6 +2501,15 @@ static const struct snd_kcontrol_new sec_i2s_rx_mixer_controls[] = {
SOC_SINGLE_EXT("MultiMedia16", MSM_BACKEND_DAI_SEC_I2S_RX,
MSM_FRONTEND_DAI_MULTIMEDIA16, 1, 0, msm_routing_get_audio_mixer,
msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia17", MSM_BACKEND_DAI_SEC_I2S_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA17, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia18", MSM_BACKEND_DAI_SEC_I2S_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA18, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia19", MSM_BACKEND_DAI_SEC_I2S_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA19, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
};
static const struct snd_kcontrol_new spdif_rx_mixer_controls[] = {
@@ -2519,6 +2561,16 @@ static const struct snd_kcontrol_new spdif_rx_mixer_controls[] = {
SOC_SINGLE_EXT("MultiMedia16", MSM_BACKEND_DAI_SPDIF_RX,
MSM_FRONTEND_DAI_MULTIMEDIA16, 1, 0, msm_routing_get_audio_mixer,
msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia17", MSM_BACKEND_DAI_SPDIF_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA17, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia18", MSM_BACKEND_DAI_SPDIF_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA18, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia19", MSM_BACKEND_DAI_SPDIF_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA19, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+
};
static const struct snd_kcontrol_new slimbus_2_rx_mixer_controls[] = {
@@ -2621,6 +2673,15 @@ static const struct snd_kcontrol_new slimbus_5_rx_mixer_controls[] = {
SOC_SINGLE_EXT("MultiMedia16", MSM_BACKEND_DAI_SLIMBUS_5_RX,
MSM_FRONTEND_DAI_MULTIMEDIA16, 1, 0, msm_routing_get_audio_mixer,
msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia17", MSM_BACKEND_DAI_SLIMBUS_5_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA17, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia18", MSM_BACKEND_DAI_SLIMBUS_5_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA18, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia19", MSM_BACKEND_DAI_SLIMBUS_5_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA19, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
};
static const struct snd_kcontrol_new slimbus_rx_mixer_controls[] = {
@@ -2672,6 +2733,15 @@ static const struct snd_kcontrol_new slimbus_rx_mixer_controls[] = {
SOC_SINGLE_EXT("MultiMedia16", MSM_BACKEND_DAI_SLIMBUS_0_RX,
MSM_FRONTEND_DAI_MULTIMEDIA16, 1, 0, msm_routing_get_audio_mixer,
msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia17", MSM_BACKEND_DAI_SLIMBUS_0_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA17, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia18", MSM_BACKEND_DAI_SLIMBUS_0_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA18, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia19", MSM_BACKEND_DAI_SLIMBUS_0_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA19, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
};
static const struct snd_kcontrol_new mi2s_rx_mixer_controls[] = {
@@ -2723,6 +2793,15 @@ static const struct snd_kcontrol_new mi2s_rx_mixer_controls[] = {
SOC_SINGLE_EXT("MultiMedia16", MSM_BACKEND_DAI_MI2S_RX,
MSM_FRONTEND_DAI_MULTIMEDIA16, 1, 0, msm_routing_get_audio_mixer,
msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia17", MSM_BACKEND_DAI_MI2S_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA17, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia18", MSM_BACKEND_DAI_MI2S_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA18, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia19", MSM_BACKEND_DAI_MI2S_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA19, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
};
static const struct snd_kcontrol_new quaternary_mi2s_rx_mixer_controls[] = {
@@ -2774,6 +2853,15 @@ static const struct snd_kcontrol_new quaternary_mi2s_rx_mixer_controls[] = {
SOC_SINGLE_EXT("MultiMedia16", MSM_BACKEND_DAI_QUATERNARY_MI2S_RX,
MSM_FRONTEND_DAI_MULTIMEDIA16, 1, 0, msm_routing_get_audio_mixer,
msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia17", MSM_BACKEND_DAI_QUATERNARY_MI2S_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA17, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia18", MSM_BACKEND_DAI_QUATERNARY_MI2S_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA18, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia19", MSM_BACKEND_DAI_QUATERNARY_MI2S_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA19, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
};
static const struct snd_kcontrol_new quinary_mi2s_rx_mixer_controls[] = {
@@ -2825,6 +2913,15 @@ static const struct snd_kcontrol_new quinary_mi2s_rx_mixer_controls[] = {
SOC_SINGLE_EXT("MultiMedia16", MSM_BACKEND_DAI_QUINARY_MI2S_RX,
MSM_FRONTEND_DAI_MULTIMEDIA16, 1, 0, msm_routing_get_audio_mixer,
msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia17", MSM_BACKEND_DAI_QUINARY_MI2S_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA17, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia18", MSM_BACKEND_DAI_QUINARY_MI2S_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA18, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia19", MSM_BACKEND_DAI_QUINARY_MI2S_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA19, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
};
static const struct snd_kcontrol_new tertiary_mi2s_rx_mixer_controls[] = {
@@ -2870,6 +2967,15 @@ static const struct snd_kcontrol_new tertiary_mi2s_rx_mixer_controls[] = {
SOC_SINGLE_EXT("MultiMedia16", MSM_BACKEND_DAI_TERTIARY_MI2S_RX,
MSM_FRONTEND_DAI_MULTIMEDIA16, 1, 0, msm_routing_get_audio_mixer,
msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia17", MSM_BACKEND_DAI_TERTIARY_MI2S_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA17, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia18", MSM_BACKEND_DAI_TERTIARY_MI2S_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA18, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia19", MSM_BACKEND_DAI_TERTIARY_MI2S_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA19, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
};
static const struct snd_kcontrol_new secondary_mi2s_rx2_mixer_controls[] = {
@@ -2927,6 +3033,15 @@ static const struct snd_kcontrol_new secondary_mi2s_rx_mixer_controls[] = {
SOC_SINGLE_EXT("MultiMedia16", MSM_BACKEND_DAI_SECONDARY_MI2S_RX,
MSM_FRONTEND_DAI_MULTIMEDIA16, 1, 0, msm_routing_get_audio_mixer,
msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia17", MSM_BACKEND_DAI_SECONDARY_MI2S_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA17, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia18", MSM_BACKEND_DAI_SECONDARY_MI2S_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA18, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia19", MSM_BACKEND_DAI_SECONDARY_MI2S_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA19, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
};
static const struct snd_kcontrol_new primary_mi2s_rx_mixer_controls[] = {
@@ -2978,6 +3093,15 @@ static const struct snd_kcontrol_new primary_mi2s_rx_mixer_controls[] = {
SOC_SINGLE_EXT("MultiMedia16", MSM_BACKEND_DAI_PRI_MI2S_RX,
MSM_FRONTEND_DAI_MULTIMEDIA16, 1, 0, msm_routing_get_audio_mixer,
msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia17", MSM_BACKEND_DAI_PRI_MI2S_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA17, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia18", MSM_BACKEND_DAI_PRI_MI2S_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA18, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia19", MSM_BACKEND_DAI_PRI_MI2S_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA19, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
};
static const struct snd_kcontrol_new int0_mi2s_rx_mixer_controls[] = {
@@ -3131,6 +3255,15 @@ static const struct snd_kcontrol_new hdmi_mixer_controls[] = {
SOC_SINGLE_EXT("MultiMedia16", MSM_BACKEND_DAI_HDMI_RX,
MSM_FRONTEND_DAI_MULTIMEDIA16, 1, 0, msm_routing_get_audio_mixer,
msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia17", MSM_BACKEND_DAI_HDMI_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA17, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia18", MSM_BACKEND_DAI_HDMI_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA18, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia19", MSM_BACKEND_DAI_HDMI_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA19, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
};
static const struct snd_kcontrol_new display_port_mixer_controls[] = {
@@ -3432,6 +3565,15 @@ static const struct snd_kcontrol_new int_bt_sco_rx_mixer_controls[] = {
SOC_SINGLE_EXT("MultiMedia16", MSM_BACKEND_DAI_INT_BT_SCO_RX,
MSM_FRONTEND_DAI_MULTIMEDIA16, 1, 0, msm_routing_get_audio_mixer,
msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia17", MSM_BACKEND_DAI_INT_BT_SCO_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA17, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia18", MSM_BACKEND_DAI_INT_BT_SCO_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA18, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia19", MSM_BACKEND_DAI_INT_BT_SCO_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA19, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
};
static const struct snd_kcontrol_new int_bt_a2dp_rx_mixer_controls[] = {
@@ -3534,6 +3676,15 @@ static const struct snd_kcontrol_new int_fm_rx_mixer_controls[] = {
SOC_SINGLE_EXT("MultiMedia16", MSM_BACKEND_DAI_INT_FM_RX,
MSM_FRONTEND_DAI_MULTIMEDIA16, 1, 0, msm_routing_get_audio_mixer,
msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia17", MSM_BACKEND_DAI_INT_FM_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA17, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia18", MSM_BACKEND_DAI_INT_FM_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA18, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia19", MSM_BACKEND_DAI_INT_FM_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA19, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
};
static const struct snd_kcontrol_new afe_pcm_rx_mixer_controls[] = {
@@ -3585,6 +3736,15 @@ static const struct snd_kcontrol_new afe_pcm_rx_mixer_controls[] = {
SOC_SINGLE_EXT("MultiMedia16", MSM_BACKEND_DAI_AFE_PCM_RX,
MSM_FRONTEND_DAI_MULTIMEDIA16, 1, 0, msm_routing_get_audio_mixer,
msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia17", MSM_BACKEND_DAI_AFE_PCM_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA17, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia18", MSM_BACKEND_DAI_AFE_PCM_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA18, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia19", MSM_BACKEND_DAI_AFE_PCM_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA19, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
};
static const struct snd_kcontrol_new auxpcm_rx_mixer_controls[] = {
@@ -3636,6 +3796,15 @@ static const struct snd_kcontrol_new auxpcm_rx_mixer_controls[] = {
SOC_SINGLE_EXT("MultiMedia16", MSM_BACKEND_DAI_AUXPCM_RX,
MSM_FRONTEND_DAI_MULTIMEDIA16, 1, 0, msm_routing_get_audio_mixer,
msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia17", MSM_BACKEND_DAI_AUXPCM_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA17, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia18", MSM_BACKEND_DAI_AUXPCM_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA18, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia19", MSM_BACKEND_DAI_AUXPCM_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA19, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
};
static const struct snd_kcontrol_new sec_auxpcm_rx_mixer_controls[] = {
@@ -3687,6 +3856,15 @@ static const struct snd_kcontrol_new sec_auxpcm_rx_mixer_controls[] = {
SOC_SINGLE_EXT("MultiMedia16", MSM_BACKEND_DAI_SEC_AUXPCM_RX,
MSM_FRONTEND_DAI_MULTIMEDIA16, 1, 0, msm_routing_get_audio_mixer,
msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia17", MSM_BACKEND_DAI_SEC_AUXPCM_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA17, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia18", MSM_BACKEND_DAI_SEC_AUXPCM_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA18, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia19", MSM_BACKEND_DAI_SEC_AUXPCM_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA19, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
};
static const struct snd_kcontrol_new tert_auxpcm_rx_mixer_controls[] = {
@@ -5018,6 +5196,77 @@ static const struct snd_kcontrol_new mmul8_mixer_controls[] = {
msm_routing_put_audio_mixer),
};
+static const struct snd_kcontrol_new mmul17_mixer_controls[] = {
+ SOC_SINGLE_EXT("SLIM_0_TX", MSM_BACKEND_DAI_SLIMBUS_0_TX,
+ MSM_FRONTEND_DAI_MULTIMEDIA17, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("PRI_MI2S_TX", MSM_BACKEND_DAI_PRI_MI2S_TX,
+ MSM_FRONTEND_DAI_MULTIMEDIA17, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("INTERNAL_FM_TX", MSM_BACKEND_DAI_INT_FM_TX,
+ MSM_FRONTEND_DAI_MULTIMEDIA17, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("INTERNAL_BT_SCO_TX", MSM_BACKEND_DAI_INT_BT_SCO_TX,
+ MSM_FRONTEND_DAI_MULTIMEDIA17, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("AFE_PCM_TX", MSM_BACKEND_DAI_AFE_PCM_TX,
+ MSM_FRONTEND_DAI_MULTIMEDIA17, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("VOC_REC_DL", MSM_BACKEND_DAI_INCALL_RECORD_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA17, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("VOC_REC_UL", MSM_BACKEND_DAI_INCALL_RECORD_TX,
+ MSM_FRONTEND_DAI_MULTIMEDIA17, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+};
+
+static const struct snd_kcontrol_new mmul18_mixer_controls[] = {
+ SOC_SINGLE_EXT("SLIM_0_TX", MSM_BACKEND_DAI_SLIMBUS_0_TX,
+ MSM_FRONTEND_DAI_MULTIMEDIA18, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("PRI_MI2S_TX", MSM_BACKEND_DAI_PRI_MI2S_TX,
+ MSM_FRONTEND_DAI_MULTIMEDIA18, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("INTERNAL_FM_TX", MSM_BACKEND_DAI_INT_FM_TX,
+ MSM_FRONTEND_DAI_MULTIMEDIA18, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("INTERNAL_BT_SCO_TX", MSM_BACKEND_DAI_INT_BT_SCO_TX,
+ MSM_FRONTEND_DAI_MULTIMEDIA18, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("AFE_PCM_TX", MSM_BACKEND_DAI_AFE_PCM_TX,
+ MSM_FRONTEND_DAI_MULTIMEDIA18, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("VOC_REC_DL", MSM_BACKEND_DAI_INCALL_RECORD_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA18, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("VOC_REC_UL", MSM_BACKEND_DAI_INCALL_RECORD_TX,
+ MSM_FRONTEND_DAI_MULTIMEDIA18, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+};
+
+static const struct snd_kcontrol_new mmul19_mixer_controls[] = {
+ SOC_SINGLE_EXT("SLIM_0_TX", MSM_BACKEND_DAI_SLIMBUS_0_TX,
+ MSM_FRONTEND_DAI_MULTIMEDIA19, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("PRI_MI2S_TX", MSM_BACKEND_DAI_PRI_MI2S_TX,
+ MSM_FRONTEND_DAI_MULTIMEDIA19, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("INTERNAL_FM_TX", MSM_BACKEND_DAI_INT_FM_TX,
+ MSM_FRONTEND_DAI_MULTIMEDIA19, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("INTERNAL_BT_SCO_TX", MSM_BACKEND_DAI_INT_BT_SCO_TX,
+ MSM_FRONTEND_DAI_MULTIMEDIA19, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("AFE_PCM_TX", MSM_BACKEND_DAI_AFE_PCM_TX,
+ MSM_FRONTEND_DAI_MULTIMEDIA19, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("VOC_REC_DL", MSM_BACKEND_DAI_INCALL_RECORD_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA19, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("VOC_REC_UL", MSM_BACKEND_DAI_INCALL_RECORD_TX,
+ MSM_FRONTEND_DAI_MULTIMEDIA19, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+};
static const struct snd_kcontrol_new pri_rx_voice_mixer_controls[] = {
SOC_SINGLE_EXT("CSVoice", MSM_BACKEND_DAI_PRI_I2S_RX,
MSM_FRONTEND_DAI_CS_VOICE, 1, 0, msm_routing_get_voice_mixer,
@@ -8098,6 +8347,9 @@ static const struct snd_soc_dapm_widget msm_qdsp6_widgets[] = {
SND_SOC_DAPM_AIF_OUT("MM_UL6", "MultiMedia6 Capture", 0, 0, 0, 0),
SND_SOC_DAPM_AIF_OUT("MM_UL8", "MultiMedia8 Capture", 0, 0, 0, 0),
SND_SOC_DAPM_AIF_OUT("MM_UL9", "MultiMedia9 Capture", 0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_OUT("MM_UL17", "MultiMedia17 Capture", 0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_OUT("MM_UL18", "MultiMedia18 Capture", 0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_OUT("MM_UL19", "MultiMedia19 Capture", 0, 0, 0, 0),
SND_SOC_DAPM_AIF_IN("CS-VOICE_DL1", "CS-VOICE Playback", 0, 0, 0, 0),
SND_SOC_DAPM_AIF_OUT("CS-VOICE_UL1", "CS-VOICE Capture", 0, 0, 0, 0),
SND_SOC_DAPM_AIF_IN("VOICE2_DL", "Voice2 Playback", 0, 0, 0, 0),
@@ -8796,6 +9048,12 @@ static const struct snd_soc_dapm_widget msm_qdsp6_widgets[] = {
mmul6_mixer_controls, ARRAY_SIZE(mmul6_mixer_controls)),
SND_SOC_DAPM_MIXER("MultiMedia8 Mixer", SND_SOC_NOPM, 0, 0,
mmul8_mixer_controls, ARRAY_SIZE(mmul8_mixer_controls)),
+ SND_SOC_DAPM_MIXER("MultiMedia17 Mixer", SND_SOC_NOPM, 0, 0,
+ mmul17_mixer_controls, ARRAY_SIZE(mmul17_mixer_controls)),
+ SND_SOC_DAPM_MIXER("MultiMedia18 Mixer", SND_SOC_NOPM, 0, 0,
+ mmul18_mixer_controls, ARRAY_SIZE(mmul18_mixer_controls)),
+ SND_SOC_DAPM_MIXER("MultiMedia19 Mixer", SND_SOC_NOPM, 0, 0,
+ mmul19_mixer_controls, ARRAY_SIZE(mmul19_mixer_controls)),
SND_SOC_DAPM_MIXER("AUX_PCM_RX Audio Mixer", SND_SOC_NOPM, 0, 0,
auxpcm_rx_mixer_controls, ARRAY_SIZE(auxpcm_rx_mixer_controls)),
SND_SOC_DAPM_MIXER("SEC_AUX_PCM_RX Audio Mixer", SND_SOC_NOPM, 0, 0,
@@ -9060,6 +9318,12 @@ static const struct snd_soc_dapm_widget msm_qdsp6_widgets[] = {
&ext_ec_ref_mux_ul8),
SND_SOC_DAPM_MUX("AUDIO_REF_EC_UL9 MUX", SND_SOC_NOPM, 0, 0,
&ext_ec_ref_mux_ul9),
+ SND_SOC_DAPM_MUX("AUDIO_REF_EC_UL17 MUX", SND_SOC_NOPM, 0, 0,
+ &ext_ec_ref_mux_ul17),
+ SND_SOC_DAPM_MUX("AUDIO_REF_EC_UL18 MUX", SND_SOC_NOPM, 0, 0,
+ &ext_ec_ref_mux_ul18),
+ SND_SOC_DAPM_MUX("AUDIO_REF_EC_UL19 MUX", SND_SOC_NOPM, 0, 0,
+ &ext_ec_ref_mux_ul19),
};
static const struct snd_soc_dapm_route intercon[] = {
@@ -9287,9 +9551,15 @@ static const struct snd_soc_dapm_route intercon[] = {
{"MultiMedia8 Mixer", "SLIM_6_TX", "SLIMBUS_6_TX"},
{"MultiMedia8 Mixer", "SLIM_7_TX", "SLIMBUS_7_TX"},
{"MultiMedia4 Mixer", "SLIM_0_TX", "SLIMBUS_0_TX"},
+ {"MultiMedia17 Mixer", "SLIM_0_TX", "SLIMBUS_0_TX"},
+ {"MultiMedia18 Mixer", "SLIM_0_TX", "SLIMBUS_0_TX"},
+ {"MultiMedia19 Mixer", "SLIM_0_TX", "SLIMBUS_0_TX"},
{"MultiMedia8 Mixer", "SLIM_0_TX", "SLIMBUS_0_TX"},
{"MultiMedia2 Mixer", "PRI_MI2S_TX", "PRI_MI2S_TX"},
{"MultiMedia4 Mixer", "PRI_MI2S_TX", "PRI_MI2S_TX"},
+ {"MultiMedia17 Mixer", "PRI_MI2S_TX", "PRI_MI2S_TX"},
+ {"MultiMedia18 Mixer", "PRI_MI2S_TX", "PRI_MI2S_TX"},
+ {"MultiMedia19 Mixer", "PRI_MI2S_TX", "PRI_MI2S_TX"},
{"MultiMedia8 Mixer", "PRI_MI2S_TX", "PRI_MI2S_TX"},
{"MultiMedia3 Mixer", "SLIM_0_TX", "SLIMBUS_0_TX"},
{"MultiMedia5 Mixer", "SLIM_0_TX", "SLIMBUS_0_TX"},
@@ -9884,10 +10154,16 @@ static const struct snd_soc_dapm_route intercon[] = {
{"MultiMedia1 Mixer", "INTERNAL_BT_SCO_TX", "INT_BT_SCO_TX"},
{"MultiMedia3 Mixer", "INTERNAL_BT_SCO_TX", "INT_BT_SCO_TX"},
{"MultiMedia4 Mixer", "INTERNAL_BT_SCO_TX", "INT_BT_SCO_TX"},
+ {"MultiMedia17 Mixer", "INTERNAL_BT_SCO_TX", "INT_BT_SCO_TX"},
+ {"MultiMedia18 Mixer", "INTERNAL_BT_SCO_TX", "INT_BT_SCO_TX"},
+ {"MultiMedia19 Mixer", "INTERNAL_BT_SCO_TX", "INT_BT_SCO_TX"},
{"MultiMedia5 Mixer", "INTERNAL_BT_SCO_TX", "INT_BT_SCO_TX"},
{"MultiMedia8 Mixer", "INTERNAL_BT_SCO_TX", "INT_BT_SCO_TX"},
{"MultiMedia1 Mixer", "INTERNAL_FM_TX", "INT_FM_TX"},
{"MultiMedia4 Mixer", "INTERNAL_FM_TX", "INT_FM_TX"},
+ {"MultiMedia17 Mixer", "INTERNAL_FM_TX", "INT_FM_TX"},
+ {"MultiMedia18 Mixer", "INTERNAL_FM_TX", "INT_FM_TX"},
+ {"MultiMedia19 Mixer", "INTERNAL_FM_TX", "INT_FM_TX"},
{"MultiMedia5 Mixer", "INTERNAL_FM_TX", "INT_FM_TX"},
{"MultiMedia6 Mixer", "INTERNAL_FM_TX", "INT_FM_TX"},
{"MultiMedia8 Mixer", "INTERNAL_FM_TX", "INT_FM_TX"},
@@ -9895,6 +10171,9 @@ static const struct snd_soc_dapm_route intercon[] = {
{"MultiMedia1 Mixer", "AFE_PCM_TX", "PCM_TX"},
{"MultiMedia3 Mixer", "AFE_PCM_TX", "PCM_TX"},
{"MultiMedia4 Mixer", "AFE_PCM_TX", "PCM_TX"},
+ {"MultiMedia17 Mixer", "AFE_PCM_TX", "PCM_TX"},
+ {"MultiMedia18 Mixer", "AFE_PCM_TX", "PCM_TX"},
+ {"MultiMedia19 Mixer", "AFE_PCM_TX", "PCM_TX"},
{"MultiMedia5 Mixer", "AFE_PCM_TX", "PCM_TX"},
{"MultiMedia8 Mixer", "AFE_PCM_TX", "PCM_TX"},
{"MM_UL1", NULL, "MultiMedia1 Mixer"},
@@ -9905,6 +10184,9 @@ static const struct snd_soc_dapm_route intercon[] = {
{"MM_UL5", NULL, "MultiMedia5 Mixer"},
{"MM_UL6", NULL, "MultiMedia6 Mixer"},
{"MM_UL8", NULL, "MultiMedia8 Mixer"},
+ {"MM_UL17", NULL, "MultiMedia17 Mixer"},
+ {"MM_UL18", NULL, "MultiMedia18 Mixer"},
+ {"MM_UL19", NULL, "MultiMedia19 Mixer"},
{"AUX_PCM_RX Audio Mixer", "MultiMedia1", "MM_DL1"},
{"AUX_PCM_RX Audio Mixer", "MultiMedia2", "MM_DL2"},
@@ -10284,6 +10566,21 @@ static const struct snd_soc_dapm_route intercon[] = {
{"AUDIO_REF_EC_UL9 MUX", "TERT_MI2S_TX" , "TERT_MI2S_TX"},
{"AUDIO_REF_EC_UL9 MUX", "QUAT_MI2S_TX" , "QUAT_MI2S_TX"},
+ {"AUDIO_REF_EC_UL17 MUX", "PRI_MI2S_TX", "PRI_MI2S_TX"},
+ {"AUDIO_REF_EC_UL17 MUX", "SEC_MI2S_TX", "SEC_MI2S_TX"},
+ {"AUDIO_REF_EC_UL17 MUX", "TERT_MI2S_TX", "TERT_MI2S_TX"},
+ {"AUDIO_REF_EC_UL17 MUX", "QUAT_MI2S_TX", "QUAT_MI2S_TX"},
+
+ {"AUDIO_REF_EC_UL18 MUX", "PRI_MI2S_TX", "PRI_MI2S_TX"},
+ {"AUDIO_REF_EC_UL18 MUX", "SEC_MI2S_TX", "SEC_MI2S_TX"},
+ {"AUDIO_REF_EC_UL18 MUX", "TERT_MI2S_TX", "TERT_MI2S_TX"},
+ {"AUDIO_REF_EC_UL18 MUX", "QUAT_MI2S_TX", "QUAT_MI2S_TX"},
+
+ {"AUDIO_REF_EC_UL19 MUX", "PRI_MI2S_TX", "PRI_MI2S_TX"},
+ {"AUDIO_REF_EC_UL19 MUX", "SEC_MI2S_TX", "SEC_MI2S_TX"},
+ {"AUDIO_REF_EC_UL19 MUX", "TERT_MI2S_TX", "TERT_MI2S_TX"},
+ {"AUDIO_REF_EC_UL19 MUX", "QUAT_MI2S_TX", "QUAT_MI2S_TX"},
+
{"MM_UL1", NULL, "AUDIO_REF_EC_UL1 MUX"},
{"MM_UL2", NULL, "AUDIO_REF_EC_UL2 MUX"},
{"MM_UL3", NULL, "AUDIO_REF_EC_UL3 MUX"},
@@ -10292,6 +10589,9 @@ static const struct snd_soc_dapm_route intercon[] = {
{"MM_UL6", NULL, "AUDIO_REF_EC_UL6 MUX"},
{"MM_UL8", NULL, "AUDIO_REF_EC_UL8 MUX"},
{"MM_UL9", NULL, "AUDIO_REF_EC_UL9 MUX"},
+ {"MM_UL17", NULL, "AUDIO_REF_EC_UL17 MUX"},
+ {"MM_UL18", NULL, "AUDIO_REF_EC_UL18 MUX"},
+ {"MM_UL19", NULL, "AUDIO_REF_EC_UL19 MUX"},
{"Voice_Tx Mixer", "PRI_TX_Voice", "PRI_I2S_TX"},
{"Voice_Tx Mixer", "PRI_MI2S_TX_Voice", "PRI_MI2S_TX"},
diff --git a/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.h b/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.h
index 4fdfd6bb936d..d64fd640618e 100644
--- a/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.h
+++ b/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.h
@@ -182,6 +182,9 @@ enum {
MSM_FRONTEND_DAI_MULTIMEDIA14,
MSM_FRONTEND_DAI_MULTIMEDIA15,
MSM_FRONTEND_DAI_MULTIMEDIA16,
+ MSM_FRONTEND_DAI_MULTIMEDIA17,
+ MSM_FRONTEND_DAI_MULTIMEDIA18,
+ MSM_FRONTEND_DAI_MULTIMEDIA19,
MSM_FRONTEND_DAI_CS_VOICE,
MSM_FRONTEND_DAI_VOIP,
MSM_FRONTEND_DAI_AFE_RX,
@@ -207,8 +210,8 @@ enum {
MSM_FRONTEND_DAI_MAX,
};
-#define MSM_FRONTEND_DAI_MM_SIZE (MSM_FRONTEND_DAI_MULTIMEDIA16 + 1)
-#define MSM_FRONTEND_DAI_MM_MAX_ID MSM_FRONTEND_DAI_MULTIMEDIA16
+#define MSM_FRONTEND_DAI_MM_SIZE (MSM_FRONTEND_DAI_MULTIMEDIA19 + 1)
+#define MSM_FRONTEND_DAI_MM_MAX_ID MSM_FRONTEND_DAI_MULTIMEDIA19
enum {
MSM_BACKEND_DAI_PRI_I2S_RX = 0,
diff --git a/sound/soc/msm/qdsp6v2/q6asm.c b/sound/soc/msm/qdsp6v2/q6asm.c
index e3545405f61d..38c51eb32f4d 100644
--- a/sound/soc/msm/qdsp6v2/q6asm.c
+++ b/sound/soc/msm/qdsp6v2/q6asm.c
@@ -1639,7 +1639,7 @@ static int32_t q6asm_callback(struct apr_client_data *data, void *priv)
asm_token.token = data->token;
if (q6asm_get_flag_from_token(&asm_token, ASM_CMD_NO_WAIT_OFFSET)) {
pr_debug("%s: No wait command opcode[0x%x] cmd_opcode:%x\n",
- __func__, data->opcode, payload[0]);
+ __func__, data->opcode, payload ? payload[0] : 0);
wakeup_flag = 0;
}
@@ -1673,9 +1673,14 @@ static int32_t q6asm_callback(struct apr_client_data *data, void *priv)
data->dest_port);
if ((data->opcode != ASM_DATA_EVENT_RENDERED_EOS) &&
(data->opcode != ASM_DATA_EVENT_EOS) &&
- (data->opcode != ASM_SESSION_EVENT_RX_UNDERFLOW))
+ (data->opcode != ASM_SESSION_EVENT_RX_UNDERFLOW)) {
+ if (payload == NULL) {
+ pr_err("%s: payload is null\n", __func__);
+ return -EINVAL;
+ }
dev_vdbg(ac->dev, "%s: Payload = [0x%x] status[0x%x] opcode 0x%x\n",
__func__, payload[0], payload[1], data->opcode);
+ }
if (data->opcode == APR_BASIC_RSP_RESULT) {
switch (payload[0]) {
case ASM_STREAM_CMD_SET_PP_PARAMS_V2:
@@ -2285,7 +2290,8 @@ static void q6asm_add_mmaphdr(struct audio_client *ac, struct apr_hdr *hdr,
static int __q6asm_open_read(struct audio_client *ac,
uint32_t format, uint16_t bits_per_sample,
- uint32_t pcm_format_block_ver)
+ uint32_t pcm_format_block_ver,
+ bool ts_mode)
{
int rc = 0x00;
struct asm_stream_cmd_open_read_v3 open;
@@ -2329,11 +2335,21 @@ static int __q6asm_open_read(struct audio_client *ac,
case FORMAT_LINEAR_PCM:
open.mode_flags |= 0x00;
open.enc_cfg_id = q6asm_get_pcm_format_id(pcm_format_block_ver);
+ if (ts_mode)
+ open.mode_flags |= ABSOLUTE_TIMESTAMP_ENABLE;
break;
case FORMAT_MPEG4_AAC:
open.mode_flags |= BUFFER_META_ENABLE;
open.enc_cfg_id = ASM_MEDIA_FMT_AAC_V2;
break;
+ case FORMAT_G711_ALAW_FS:
+ open.mode_flags |= BUFFER_META_ENABLE;
+ open.enc_cfg_id = ASM_MEDIA_FMT_G711_ALAW_FS;
+ break;
+ case FORMAT_G711_MLAW_FS:
+ open.mode_flags |= BUFFER_META_ENABLE;
+ open.enc_cfg_id = ASM_MEDIA_FMT_G711_MLAW_FS;
+ break;
case FORMAT_V13K:
open.mode_flags |= BUFFER_META_ENABLE;
open.enc_cfg_id = ASM_MEDIA_FMT_V13K_FS;
@@ -2391,14 +2407,16 @@ int q6asm_open_read(struct audio_client *ac,
uint32_t format)
{
return __q6asm_open_read(ac, format, 16,
- PCM_MEDIA_FORMAT_V2 /*media fmt block ver*/);
+ PCM_MEDIA_FORMAT_V2 /*media fmt block ver*/,
+ false/*ts_mode*/);
}
int q6asm_open_read_v2(struct audio_client *ac, uint32_t format,
uint16_t bits_per_sample)
{
return __q6asm_open_read(ac, format, bits_per_sample,
- PCM_MEDIA_FORMAT_V2 /*media fmt block ver*/);
+ PCM_MEDIA_FORMAT_V2 /*media fmt block ver*/,
+ false/*ts_mode*/);
}
/*
@@ -2412,7 +2430,8 @@ int q6asm_open_read_v3(struct audio_client *ac, uint32_t format,
uint16_t bits_per_sample)
{
return __q6asm_open_read(ac, format, bits_per_sample,
- PCM_MEDIA_FORMAT_V3/*media fmt block ver*/);
+ PCM_MEDIA_FORMAT_V3/*media fmt block ver*/,
+ false/*ts_mode*/);
}
EXPORT_SYMBOL(q6asm_open_read_v3);
@@ -2427,7 +2446,8 @@ int q6asm_open_read_v4(struct audio_client *ac, uint32_t format,
uint16_t bits_per_sample)
{
return __q6asm_open_read(ac, format, bits_per_sample,
- PCM_MEDIA_FORMAT_V4 /*media fmt block ver*/);
+ PCM_MEDIA_FORMAT_V4 /*media fmt block ver*/,
+ true/*ts_mode*/);
}
EXPORT_SYMBOL(q6asm_open_read_v4);
@@ -2857,6 +2877,11 @@ static int __q6asm_open_read_write(struct audio_client *ac, uint32_t rd_format,
break;
case FORMAT_DSD:
open.dec_fmt_id = ASM_MEDIA_FMT_DSD;
+ case FORMAT_G711_ALAW_FS:
+ open.dec_fmt_id = ASM_MEDIA_FMT_G711_ALAW_FS;
+ break;
+ case FORMAT_G711_MLAW_FS:
+ open.dec_fmt_id = ASM_MEDIA_FMT_G711_MLAW_FS;
break;
default:
pr_err("%s: Invalid format 0x%x\n",
@@ -2873,6 +2898,12 @@ static int __q6asm_open_read_write(struct audio_client *ac, uint32_t rd_format,
case FORMAT_MPEG4_AAC:
open.enc_cfg_id = ASM_MEDIA_FMT_AAC_V2;
break;
+ case FORMAT_G711_ALAW_FS:
+ open.enc_cfg_id = ASM_MEDIA_FMT_G711_ALAW_FS;
+ break;
+ case FORMAT_G711_MLAW_FS:
+ open.enc_cfg_id = ASM_MEDIA_FMT_G711_MLAW_FS;
+ break;
case FORMAT_V13K:
open.enc_cfg_id = ASM_MEDIA_FMT_V13K_FS;
break;
@@ -3540,6 +3571,57 @@ fail_cmd:
return rc;
}
+int q6asm_enc_cfg_blk_g711(struct audio_client *ac,
+ uint32_t frames_per_buf,
+ uint32_t sample_rate)
+{
+ struct asm_g711_enc_cfg_v2 enc_cfg;
+ int rc = 0;
+
+ pr_debug("%s: session[%d]frames[%d]SR[%d]\n",
+ __func__, ac->session, frames_per_buf,
+ sample_rate);
+
+ q6asm_add_hdr(ac, &enc_cfg.hdr, sizeof(enc_cfg), TRUE);
+ atomic_set(&ac->cmd_state, -1);
+
+ enc_cfg.hdr.opcode = ASM_STREAM_CMD_SET_ENCDEC_PARAM;
+ enc_cfg.encdec.param_id = ASM_PARAM_ID_ENCDEC_ENC_CFG_BLK_V2;
+ enc_cfg.encdec.param_size = sizeof(struct asm_g711_enc_cfg_v2) -
+ sizeof(struct asm_stream_cmd_set_encdec_param);
+ enc_cfg.encblk.frames_per_buf = frames_per_buf;
+ enc_cfg.encblk.enc_cfg_blk_size = enc_cfg.encdec.param_size -
+ sizeof(struct asm_enc_cfg_blk_param_v2);
+ enc_cfg.sample_rate = sample_rate;
+
+ rc = apr_send_pkt(ac->apr, (uint32_t *) &enc_cfg);
+ if (rc < 0) {
+ pr_err("%s: Comamnd %d failed %d\n",
+ __func__, ASM_STREAM_CMD_SET_ENCDEC_PARAM, rc);
+ rc = -EINVAL;
+ goto fail_cmd;
+ }
+ rc = wait_event_timeout(ac->cmd_wait,
+ (atomic_read(&ac->cmd_state) >= 0), 5*HZ);
+ if (!rc) {
+ pr_err("%s: timeout. waited for FORMAT_UPDATE\n",
+ __func__);
+ rc = -ETIMEDOUT;
+ goto fail_cmd;
+ }
+ if (atomic_read(&ac->cmd_state) > 0) {
+ pr_err("%s: DSP returned error[%s]\n",
+ __func__, adsp_err_get_err_str(
+ atomic_read(&ac->cmd_state)));
+ rc = adsp_err_get_lnx_err_code(
+ atomic_read(&ac->cmd_state));
+ goto fail_cmd;
+ }
+ return 0;
+fail_cmd:
+ return rc;
+}
+
int q6asm_set_encdec_chan_map(struct audio_client *ac,
uint32_t num_channels)
{
@@ -5424,6 +5506,75 @@ fail_cmd:
return rc;
}
+/*
+ * q6asm_media_format_block_g711 - sends g711 decoder configuration
+ * parameters
+ * @ac: Client session handle
+ * @cfg: Audio stream manager configuration parameters
+ * @stream_id: Stream id
+ */
+int q6asm_media_format_block_g711(struct audio_client *ac,
+ struct asm_g711_dec_cfg *cfg, int stream_id)
+{
+ struct asm_g711_dec_fmt_blk_v2 fmt;
+ int rc = 0;
+
+ if (!ac) {
+ pr_err("%s: audio client is null\n", __func__);
+ return -EINVAL;
+ }
+ if (!cfg) {
+ pr_err("%s: Invalid ASM config\n", __func__);
+ return -EINVAL;
+ }
+
+ if (stream_id <= 0) {
+ pr_err("%s: Invalid stream id\n", __func__);
+ return -EINVAL;
+ }
+
+ pr_debug("%s :session[%d]rate[%d]\n", __func__,
+ ac->session, cfg->sample_rate);
+
+ memset(&fmt, 0, sizeof(struct asm_g711_dec_fmt_blk_v2));
+
+ q6asm_stream_add_hdr(ac, &fmt.hdr, sizeof(fmt), TRUE, stream_id);
+ atomic_set(&ac->cmd_state, -1);
+
+ fmt.hdr.opcode = ASM_DATA_CMD_MEDIA_FMT_UPDATE_V2;
+ fmt.fmtblk.fmt_blk_size = sizeof(fmt) - sizeof(fmt.hdr) -
+ sizeof(fmt.fmtblk);
+
+ fmt.sample_rate = cfg->sample_rate;
+
+ rc = apr_send_pkt(ac->apr, (uint32_t *) &fmt);
+ if (rc < 0) {
+ pr_err("%s :Command media format update failed %d\n",
+ __func__, rc);
+ goto fail_cmd;
+ }
+ rc = wait_event_timeout(ac->cmd_wait,
+ (atomic_read(&ac->cmd_state) >= 0), 5*HZ);
+ if (!rc) {
+ pr_err("%s :timeout. waited for FORMAT_UPDATE\n", __func__);
+ rc = -ETIMEDOUT;
+ goto fail_cmd;
+ }
+
+ if (atomic_read(&ac->cmd_state) > 0) {
+ pr_err("%s: DSP returned error[%s]\n",
+ __func__, adsp_err_get_err_str(
+ atomic_read(&ac->cmd_state)));
+ rc = adsp_err_get_lnx_err_code(
+ atomic_read(&ac->cmd_state));
+ goto fail_cmd;
+ }
+ return 0;
+fail_cmd:
+ return rc;
+}
+EXPORT_SYMBOL(q6asm_media_format_block_g711);
+
int q6asm_stream_media_format_block_vorbis(struct audio_client *ac,
struct asm_vorbis_cfg *cfg, int stream_id)
{
@@ -7150,7 +7301,11 @@ int q6asm_async_read(struct audio_client *ac,
lbuf_phys_addr = (param->paddr - 64);
dir = OUT;
} else {
- lbuf_phys_addr = param->paddr;
+ if (param->flags & COMPRESSED_TIMESTAMP_FLAG)
+ lbuf_phys_addr = param->paddr -
+ sizeof(struct snd_codec_metadata);
+ else
+ lbuf_phys_addr = param->paddr;
dir = OUT;
}
diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c
index 4c66eeaeeb03..b1980df07dce 100644
--- a/sound/soc/soc-dapm.c
+++ b/sound/soc/soc-dapm.c
@@ -2623,8 +2623,7 @@ static int snd_soc_dapm_add_path(struct snd_soc_dapm_context *dapm,
dapm_mark_dirty(widgets[dir], "Route added");
}
- if (dapm->card->instantiated && path->connect)
- dapm_path_invalidate(path);
+ dapm_path_invalidate(path);
return 0;
err: