summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Documentation/devicetree/bindings/arm/msm/adv7481.txt54
-rw-r--r--Documentation/devicetree/bindings/display/msm/cec.txt2
-rw-r--r--Documentation/devicetree/bindings/fb/mdss-dsi.txt4
-rw-r--r--Documentation/devicetree/bindings/fb/mdss-pll.txt7
-rw-r--r--Documentation/devicetree/bindings/regulator/rpm-smd-regulator.txt6
-rw-r--r--arch/arm/boot/dts/qcom/msm-arm-smmu-660.dtsi1
-rw-r--r--arch/arm/boot/dts/qcom/msm8998-mdss-panels.dtsi4
-rw-r--r--arch/arm/boot/dts/qcom/msm8998-mdss.dtsi4
-rw-r--r--arch/arm/boot/dts/qcom/msm8998-qrd-skuk-hdk.dtsi10
-rw-r--r--arch/arm/boot/dts/qcom/msm8998-qrd-vr1.dtsi10
-rw-r--r--arch/arm/boot/dts/qcom/msm8998-regulator.dtsi8
-rw-r--r--arch/arm/boot/dts/qcom/msm8998-sde-display.dtsi34
-rw-r--r--arch/arm/boot/dts/qcom/msm8998-sde.dtsi4
-rw-r--r--arch/arm/boot/dts/qcom/sdm630-camera.dtsi1
-rw-r--r--arch/arm/boot/dts/qcom/sdm660-common.dtsi2
-rw-r--r--arch/arm64/configs/msmcortex_mediabox-perf_defconfig1
-rw-r--r--arch/arm64/configs/msmcortex_mediabox_defconfig1
-rw-r--r--drivers/bluetooth/bluetooth-power.c4
-rw-r--r--drivers/bluetooth/btfm_slim_codec.c4
-rw-r--r--drivers/char/diag/diag_masks.c75
-rw-r--r--drivers/char/diag/diag_memorydevice.c4
-rw-r--r--drivers/char/diag/diagchar.h5
-rw-r--r--drivers/char/diag/diagchar_core.c24
-rw-r--r--drivers/clk/msm/clock-osm.c6
-rw-r--r--drivers/clk/msm/mdss/mdss-hdmi-pll-8998.c240
-rw-r--r--drivers/clk/msm/mdss/mdss-hdmi-pll.h16
-rw-r--r--drivers/clk/msm/mdss/mdss-pll.c14
-rw-r--r--drivers/clk/msm/mdss/mdss-pll.h5
-rw-r--r--drivers/gpio/gpiolib-acpi.c2
-rw-r--r--drivers/gpu/drm/drm_mm.c248
-rw-r--r--drivers/gpu/drm/msm/Kconfig2
-rw-r--r--drivers/gpu/drm/msm/hdmi-staging/sde_hdmi.c47
-rw-r--r--drivers/gpu/drm/msm/hdmi-staging/sde_hdmi.h3
-rw-r--r--drivers/gpu/drm/msm/hdmi-staging/sde_hdmi_bridge.c2
-rw-r--r--drivers/gpu/drm/msm/msm_drv.c32
-rw-r--r--drivers/gpu/drm/msm/msm_drv.h19
-rw-r--r--drivers/gpu/drm/msm/msm_gem.c477
-rw-r--r--drivers/gpu/drm/msm/msm_gem.h29
-rw-r--r--drivers/gpu/drm/msm/msm_gem_submit.c12
-rw-r--r--drivers/gpu/drm/msm/msm_gem_vma.c58
-rw-r--r--drivers/leds/leds-qpnp-flash-v2.c3
-rw-r--r--drivers/md/dm-android-verity.c2
-rw-r--r--drivers/md/dm.c5
-rw-r--r--drivers/media/Kconfig4
-rw-r--r--drivers/media/Makefile4
-rw-r--r--drivers/media/cec-notifier.c129
-rw-r--r--drivers/media/cec/cec-core.c22
-rw-r--r--drivers/media/i2c/adv7481.c1619
-rw-r--r--drivers/media/i2c/adv7481_reg.h702
-rw-r--r--drivers/media/platform/msm/ais/isp/msm_buf_mgr.c26
-rw-r--r--drivers/media/platform/msm/camera_v2/common/cam_smmu_api.c3
-rw-r--r--drivers/media/platform/msm/camera_v2/isp/msm_buf_mgr.c5
-rw-r--r--drivers/media/platform/msm/camera_v2/isp/msm_isp_axi_util.c4
-rw-r--r--drivers/media/platform/msm/camera_v2/ispif/msm_ispif.c2
-rw-r--r--drivers/media/platform/msm/sde/Kconfig1
-rw-r--r--drivers/media/platform/msm/sde/cec/sde_hdmi_cec.c40
-rw-r--r--drivers/media/platform/msm/sde/rotator/sde_rotator_r1.c4
-rw-r--r--drivers/mmc/card/block.c2
-rw-r--r--drivers/mmc/core/core.c42
-rw-r--r--drivers/mmc/host/sdhci-msm.c10
-rw-r--r--drivers/net/wireless/ath/regd.c18
-rw-r--r--drivers/net/wireless/ath/wil6210/pm.c13
-rw-r--r--drivers/net/wireless/ath/wil6210/txrx.c5
-rw-r--r--drivers/platform/msm/mhi/mhi_bhi.c117
-rw-r--r--drivers/platform/msm/mhi/mhi_bhi.h1
-rw-r--r--drivers/platform/msm/mhi/mhi_pm.c105
-rw-r--r--drivers/platform/msm/mhi/mhi_states.c5
-rw-r--r--drivers/power/qcom/debug_core.c6
-rw-r--r--drivers/power/supply/qcom/qpnp-fg-gen3.c16
-rw-r--r--drivers/regulator/cpr3-hmss-regulator.c4
-rw-r--r--drivers/regulator/cpr3-regulator.c3
-rw-r--r--drivers/regulator/cprh-kbss-regulator.c2
-rw-r--r--drivers/regulator/rpm-smd-regulator.c59
-rw-r--r--drivers/regulator/spm-regulator.c309
-rw-r--r--drivers/scsi/ufs/ufshcd.c6
-rw-r--r--drivers/soc/qcom/glink_smem_native_xprt.c2
-rw-r--r--drivers/soc/qcom/msm_bus/msm_bus_rules.c2
-rw-r--r--drivers/soc/qcom/subsys-pil-tz.c1
-rw-r--r--drivers/soundwire/swr-wcd-ctrl.c2
-rw-r--r--drivers/staging/android/lowmemorykiller.c2
-rw-r--r--drivers/thermal/msm-tsens.c2
-rw-r--r--drivers/usb/host/xhci-hub.c12
-rw-r--r--drivers/usb/pd/policy_engine.c65
-rw-r--r--drivers/usb/pd/qpnp-pdphy.c19
-rw-r--r--drivers/video/fbdev/core/fbmem.c7
-rw-r--r--drivers/video/fbdev/msm/mdss_dba_utils.c3
-rw-r--r--drivers/video/fbdev/msm/mdss_dp_util.c2
-rw-r--r--drivers/video/fbdev/msm/mdss_dsi.c11
-rw-r--r--drivers/video/fbdev/msm/mdss_dsi.h2
-rw-r--r--drivers/video/fbdev/msm/mdss_dsi_host.c2
-rw-r--r--drivers/video/fbdev/msm/mdss_dsi_panel.c35
-rw-r--r--drivers/video/fbdev/msm/mdss_fb.c10
-rw-r--r--drivers/video/fbdev/msm/mdss_hdmi_edid.c33
-rw-r--r--drivers/video/fbdev/msm/mdss_hdmi_edid.h6
-rw-r--r--drivers/video/fbdev/msm/mdss_hdmi_tx.c21
-rw-r--r--drivers/video/fbdev/msm/mdss_hdmi_util.c4
-rw-r--r--drivers/video/fbdev/msm/mdss_mdp.c1
-rw-r--r--drivers/video/fbdev/msm/mdss_mdp.h4
-rw-r--r--drivers/video/fbdev/msm/mdss_mdp_ctl.c20
-rw-r--r--drivers/video/fbdev/msm/mdss_mdp_intf_video.c14
-rw-r--r--drivers/video/fbdev/msm/mdss_mdp_layer.c9
-rw-r--r--drivers/video/fbdev/msm/mdss_mdp_util.c4
-rw-r--r--drivers/video/fbdev/msm/mdss_panel.h3
-rw-r--r--drivers/video/fbdev/msm/mdss_rotator.c2
-rw-r--r--include/drm/drm_mm.h15
-rw-r--r--include/linux/mmc/host.h2
-rw-r--r--include/linux/msm_mhi.h2
-rw-r--r--include/media/cec-notifier.h111
-rw-r--r--include/media/cec.h10
-rw-r--r--include/uapi/drm/msm_drm.h12
-rw-r--r--kernel/irq/msi.c2
-rw-r--r--kernel/time/hrtimer.c49
-rw-r--r--kernel/time/posix-cpu-timers.c2
-rw-r--r--net/netfilter/xt_HARDIDLETIMER.c4
-rw-r--r--net/netfilter/xt_IDLETIMER.c2
-rw-r--r--net/unix/af_unix.c2
116 files changed, 4099 insertions, 1193 deletions
diff --git a/Documentation/devicetree/bindings/arm/msm/adv7481.txt b/Documentation/devicetree/bindings/arm/msm/adv7481.txt
new file mode 100644
index 000000000000..974c0877ac30
--- /dev/null
+++ b/Documentation/devicetree/bindings/arm/msm/adv7481.txt
@@ -0,0 +1,54 @@
+ADV7481 chip driver (VIDEO_ADV7481)
+
+VIDEO_ADV7481 is a kernel platform driver that is used for video decoder
+and dual mode HDMI/MHL receiver.
+
+The devicetree representation of the VIDEO_ADV7481 block should be:
+
+Required properties
+
+- compatible: "qcom,adv7481"
+- reg: The i2c slave address of adv7481 device.
+- qcom,cci-master: The i2c master id to be used for adv7481 driver.
+- gpios: The GPIOs required to be configured for the driver. It should
+ be in the order I2C data line, i2c clock line, reset line,
+ interrupt 1, interrupt 2 and interrupt 3.
+- cam_vdig-supply: Should contain regulator to be used for the digital
+ vdd.
+- cam_vio-supply: Should contain regulator to be used for the IO vdd.
+- cam_vana-supply: Should contain regulator from which analog voltage
+ is supplied.
+- qcom,cam-vreg-name: Should specify array of regulator names required
+ for the device.
+- qcom,cam-vreg-min-voltage: Should specify array of minimum voltage
+ level in uV for the regulators specified in the property
+ "qcom,cam-vreg-name".
+- qcom,cam-vreg-max-voltage: Should specify array of maximum voltage
+ level in uV for the regulators specified in the property
+ "qcom,cam-vreg-name".
+- qcom,cam-vreg-op-mode: Should specify array of current level in uA
+ for the regulators specified in the property "qcom,cam-vreg-name".
+
+Example:
+
+ qcom,adv7481@70 {
+ compatible = "qcom,adv7481";
+ reg = <0x70 0xff>;
+ cam_vdig-supply = <&vph_pwr_vreg>;
+ /* Cameras powered by PMIC: */
+ cam_vio-supply = <&pm8994_lvs1>;
+ cam_vana-supply = <&pm8994_l17>;
+ /* Self-powered cameras: */
+ qcom,cam-vreg-name = "cam_vdig", "cam_vio", "cam_vana";
+ qcom,cam-vreg-min-voltage = <1300000 0 2500000>;
+ qcom,cam-vreg-max-voltage = <1300000 0 2500000>;
+ qcom,cam-vreg-op-mode = <105000 0 80000>;
+ qcom,cci-master = <0>;
+ qcom,slave-addr = <0x70>;
+ gpios = <&tlmm 17 0>, /* I2C SDA */
+ <&tlmm 18 0>, /* I2C SCL */
+ <&pm8994_gpios 4 0>, /* RST */
+ <&pm8994_gpios 5 0>, /* INT1 */
+ <&pm8994_gpios 6 0>, /* INT2 */
+ <&pm8994_gpios 7 0>; /* INT3 */
+ };
diff --git a/Documentation/devicetree/bindings/display/msm/cec.txt b/Documentation/devicetree/bindings/display/msm/cec.txt
index ba51b0d1dd18..e5282f1f5e9e 100644
--- a/Documentation/devicetree/bindings/display/msm/cec.txt
+++ b/Documentation/devicetree/bindings/display/msm/cec.txt
@@ -5,6 +5,7 @@ various audiovisual products in a user environment.
Required properties:
- compatible: Must be "qcom,hdmi-cec".
+- qcom,hdmi-dev: Phandle for the hdmi device node.
- interrupt-parent: Must be the hdmi interrupt controller.
- interrupts: Interrupt associated with cec.
- reg: Physical base address and length of the controller's registers.
@@ -41,6 +42,7 @@ Example:
sde_hdmi_cec: qcom,hdmi-cec@c9a0000 {
compatible = "qcom,hdmi-cec";
label = "sde_hdmi_cec";
+ qcom,hdmi-dev = <&sde_hdmi>;
interrupt-parent = <&sde_hdmi_tx>;
interrupts = <1 0>;
diff --git a/Documentation/devicetree/bindings/fb/mdss-dsi.txt b/Documentation/devicetree/bindings/fb/mdss-dsi.txt
index 0d55389f3790..f28de379f84c 100644
--- a/Documentation/devicetree/bindings/fb/mdss-dsi.txt
+++ b/Documentation/devicetree/bindings/fb/mdss-dsi.txt
@@ -105,7 +105,9 @@ Optional properties:
- qcom,platform-reset-gpio: Specifies the panel reset gpio.
- qcom,platform-te-gpio: Specifies the gpio used for TE.
- qcom,platform-bklight-en-gpio: Specifies the gpio used to enable display back-light
-- qcom,platform-bklight-en-gpio-invert: Invert the gpio used to enable display back-light
+- qcom,platform-bklight-en-gpio-invert: Boolean to invert the gpio used to enable display back-light
+- qcom,platform-avdd-en-gpio: Specifies the gpio used to enable AMOLED AVDD
+- qcom,platform-avdd-en-gpio-invert: Boolean to invert the gpio used to enable AMOLED AVDD
- qcom,panel-mode-gpio: Specifies the GPIO to select video/command/single-port/dual-port
mode of panel through gpio when it supports these modes.
- pinctrl-names: List of names to assign mdss pin states defined in pinctrl device node
diff --git a/Documentation/devicetree/bindings/fb/mdss-pll.txt b/Documentation/devicetree/bindings/fb/mdss-pll.txt
index 2e9d2dae51a2..4ba9060222c2 100644
--- a/Documentation/devicetree/bindings/fb/mdss-pll.txt
+++ b/Documentation/devicetree/bindings/fb/mdss-pll.txt
@@ -15,9 +15,10 @@ Required properties:
"qcom,mdss_hdmi_pll_8996_v2", "qcom,mdss_dsi_pll_8996_v2",
"qcom,mdss_hdmi_pll_8996_v3", "qcom,mdss_hdmi_pll_8996_v3_1p8",
"qcom,mdss_dsi_pll_8998", "qcom,mdss_dp_pll_8998",
- "qcom,mdss_hdmi_pll_8998", "qcom,mdss_dsi_pll_sdm660",
- "qcom,mdss_dp_pll_sdm660", "qcom,mdss_dsi_pll_sdm630",
- "qcom,mdss_dp_pll_sdm630"
+ "qcom,mdss_hdmi_pll_8998", "qcom,mdss_hdmi_pll_8998_1p8",
+ "qcom,mdss_dsi_pll_sdm660", "qcom,mdss_dp_pll_sdm660",
+ "qcom,mdss_dsi_pll_sdm630", "qcom,mdss_dp_pll_sdm630"
+
- cell-index: Specifies the controller used
- reg: offset and length of the register set for the device.
- reg-names : names to refer to register sets related to this device
diff --git a/Documentation/devicetree/bindings/regulator/rpm-smd-regulator.txt b/Documentation/devicetree/bindings/regulator/rpm-smd-regulator.txt
index 1eb27f4c1c56..559ee5b6fc08 100644
--- a/Documentation/devicetree/bindings/regulator/rpm-smd-regulator.txt
+++ b/Documentation/devicetree/bindings/regulator/rpm-smd-regulator.txt
@@ -104,6 +104,12 @@ Optional properties:
parameter. Only one pin may be specified per
regulator. This property only applies to BoB
type regulators.
+- qcom,pwm-threshold-current: Minimum current in mA which requires regulator
+ to be in PWM mode. Load currents below this
+ threshold use AUTO mode. This property only
+ applies to BoB and SMPS type regulators.
+ If this property is not specified, then the
+ hardware default mode will be used all the time.
- qcom,always-send-voltage: Flag which indicates that updates to the
voltage, voltage corner or voltage level set
point should always be sent immediately to the
diff --git a/arch/arm/boot/dts/qcom/msm-arm-smmu-660.dtsi b/arch/arm/boot/dts/qcom/msm-arm-smmu-660.dtsi
index 33bd86654363..06935e80e07b 100644
--- a/arch/arm/boot/dts/qcom/msm-arm-smmu-660.dtsi
+++ b/arch/arm/boot/dts/qcom/msm-arm-smmu-660.dtsi
@@ -157,6 +157,7 @@
<GIC_SPI 117 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 349 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 350 IRQ_TYPE_LEVEL_HIGH>;
+ qcom,deferred-regulator-disable-delay = <80>;
vdd-supply = <&gdsc_gpu_cx>;
clocks = <&clock_gcc GCC_GPU_CFG_AHB_CLK>,
<&clock_gcc GCC_BIMC_GFX_CLK>,
diff --git a/arch/arm/boot/dts/qcom/msm8998-mdss-panels.dtsi b/arch/arm/boot/dts/qcom/msm8998-mdss-panels.dtsi
index 7de4fbbbf9ff..b53ff87d5092 100644
--- a/arch/arm/boot/dts/qcom/msm8998-mdss-panels.dtsi
+++ b/arch/arm/boot/dts/qcom/msm8998-mdss-panels.dtsi
@@ -152,6 +152,10 @@
qcom,mdss-dsi-panel-timings = [00 35 0a 0c 15 1b 09 0d 0a 03 04 00];
qcom,mdss-dsi-t-clk-post = <0x0d>;
qcom,mdss-dsi-t-clk-pre = <0x26>;
+ qcom,mdss-dsi-min-refresh-rate = <55>;
+ qcom,mdss-dsi-max-refresh-rate = <60>;
+ qcom,mdss-dsi-pan-enable-dynamic-fps;
+ qcom,mdss-dsi-pan-fps-update = "dfps_immediate_porch_mode_vfp";
};
&dsi_sharp_4k_dsc_cmd {
diff --git a/arch/arm/boot/dts/qcom/msm8998-mdss.dtsi b/arch/arm/boot/dts/qcom/msm8998-mdss.dtsi
index b7651aee5a67..5708fce44378 100644
--- a/arch/arm/boot/dts/qcom/msm8998-mdss.dtsi
+++ b/arch/arm/boot/dts/qcom/msm8998-mdss.dtsi
@@ -387,6 +387,8 @@
qcom,mdss-mdp = <&mdss_mdp>;
qcom,mdss-fb-map = <&mdss_fb0>;
+ qcom,null-insertion-enabled;
+
clocks = <&clock_mmss clk_mmss_mdss_byte0_clk>,
<&clock_mmss clk_mmss_mdss_pclk0_clk>,
<&clock_mmss clk_mmss_mdss_esc0_clk>,
@@ -425,6 +427,8 @@
qcom,mdss-mdp = <&mdss_mdp>;
qcom,mdss-fb-map = <&mdss_fb0>;
+ qcom,null-insertion-enabled;
+
clocks = <&clock_mmss clk_mmss_mdss_byte1_clk>,
<&clock_mmss clk_mmss_mdss_pclk1_clk>,
<&clock_mmss clk_mmss_mdss_esc1_clk>,
diff --git a/arch/arm/boot/dts/qcom/msm8998-qrd-skuk-hdk.dtsi b/arch/arm/boot/dts/qcom/msm8998-qrd-skuk-hdk.dtsi
index 3c76519acdcf..7809b81fcefd 100644
--- a/arch/arm/boot/dts/qcom/msm8998-qrd-skuk-hdk.dtsi
+++ b/arch/arm/boot/dts/qcom/msm8998-qrd-skuk-hdk.dtsi
@@ -87,8 +87,8 @@
qcom,platform-te-gpio = <&tlmm 10 0>;
qcom,platform-enable-gpio = <&tlmm 52 0>;
qcom,platform-reset-gpio = <&tlmm 94 0>;
- qcom,platform-bklight-en-gpio = <&pmi8998_gpios 1 0>;
- qcom,platform-bklight-en-gpio-invert;
+ qcom,platform-avdd-en-gpio = <&pmi8998_gpios 1 0>;
+ qcom,platform-avdd-en-gpio-invert;
};
&mdss_dsi1 {
@@ -99,8 +99,8 @@
qcom,platform-te-gpio = <&tlmm 10 0>;
qcom,platform-enable-gpio = <&tlmm 52 0>;
qcom,platform-reset-gpio = <&tlmm 94 0>;
- qcom,platform-bklight-en-gpio = <&pmi8998_gpios 1 0>;
- qcom,platform-bklight-en-gpio-invert;
+ qcom,platform-avdd-en-gpio = <&pmi8998_gpios 1 0>;
+ qcom,platform-avdd-en-gpio-invert;
};
&pmi8998_wled {
@@ -114,7 +114,7 @@
};
&pmi8998_gpios {
- /* GPIO 1 for WLED power enable */
+ /* GPIO 1 for AVDD power enable */
gpio@c000 {
qcom,mode = <1>;
qcom,output-type = <0>;
diff --git a/arch/arm/boot/dts/qcom/msm8998-qrd-vr1.dtsi b/arch/arm/boot/dts/qcom/msm8998-qrd-vr1.dtsi
index 0d0c66d7f26e..9b1145242cc0 100644
--- a/arch/arm/boot/dts/qcom/msm8998-qrd-vr1.dtsi
+++ b/arch/arm/boot/dts/qcom/msm8998-qrd-vr1.dtsi
@@ -420,8 +420,8 @@
qcom,platform-te-gpio = <&tlmm 10 0>;
qcom,platform-enable-gpio = <&tlmm 52 0>;
qcom,platform-reset-gpio = <&tlmm 94 0>;
- qcom,platform-bklight-en-gpio = <&pmi8998_gpios 1 0>;
- qcom,platform-bklight-en-gpio-invert;
+ qcom,platform-avdd-en-gpio = <&pmi8998_gpios 1 0>;
+ qcom,platform-avdd-en-gpio-invert;
};
&mdss_dsi1 {
@@ -432,8 +432,8 @@
qcom,platform-te-gpio = <&tlmm 10 0>;
qcom,platform-enable-gpio = <&tlmm 52 0>;
qcom,platform-reset-gpio = <&tlmm 94 0>;
- qcom,platform-bklight-en-gpio = <&pmi8998_gpios 1 0>;
- qcom,platform-bklight-en-gpio-invert;
+ qcom,platform-avdd-en-gpio = <&pmi8998_gpios 1 0>;
+ qcom,platform-avdd-en-gpio-invert;
};
&pmi8998_wled {
@@ -447,7 +447,7 @@
};
&pmi8998_gpios {
- /* GPIO 1 for WLED power enable */
+ /* GPIO 1 for AVDD power enable */
gpio@c000 {
qcom,mode = <1>;
qcom,output-type = <0>;
diff --git a/arch/arm/boot/dts/qcom/msm8998-regulator.dtsi b/arch/arm/boot/dts/qcom/msm8998-regulator.dtsi
index be70f129e272..bfd2a035d2a4 100644
--- a/arch/arm/boot/dts/qcom/msm8998-regulator.dtsi
+++ b/arch/arm/boot/dts/qcom/msm8998-regulator.dtsi
@@ -502,6 +502,8 @@
pmi8998_bob: regulator-bob {
regulator-min-microvolt = <3312000>;
regulator-max-microvolt = <3600000>;
+ qcom,pwm-threshold-current = <2000000>;
+ qcom,init-bob-mode = <2>;
status = "okay";
};
pmi8998_bob_pin1: regulator-bob-pin1 {
@@ -510,6 +512,8 @@
qcom,set = <3>;
regulator-min-microvolt = <3312000>;
regulator-max-microvolt = <3600000>;
+ qcom,pwm-threshold-current = <2000000>;
+ qcom,init-bob-mode = <2>;
qcom,use-pin-ctrl-voltage1;
};
pmi8998_bob_pin2: regulator-bob-pin2 {
@@ -518,6 +522,8 @@
qcom,set = <3>;
regulator-min-microvolt = <3312000>;
regulator-max-microvolt = <3600000>;
+ qcom,pwm-threshold-current = <2000000>;
+ qcom,init-bob-mode = <2>;
qcom,use-pin-ctrl-voltage2;
};
pmi8998_bob_pin3: regulator-bob-pin3 {
@@ -526,6 +532,8 @@
qcom,set = <3>;
regulator-min-microvolt = <3312000>;
regulator-max-microvolt = <3600000>;
+ qcom,pwm-threshold-current = <2000000>;
+ qcom,init-bob-mode = <2>;
qcom,use-pin-ctrl-voltage3;
};
};
diff --git a/arch/arm/boot/dts/qcom/msm8998-sde-display.dtsi b/arch/arm/boot/dts/qcom/msm8998-sde-display.dtsi
index 6098a96db206..6e19c77995c1 100644
--- a/arch/arm/boot/dts/qcom/msm8998-sde-display.dtsi
+++ b/arch/arm/boot/dts/qcom/msm8998-sde-display.dtsi
@@ -34,6 +34,40 @@
qcom,msm_ext_disp = <&msm_ext_disp>;
};
+ sde_hdmi_cec: qcom,hdmi-cec@c9a0000 {
+ compatible = "qcom,hdmi-cec";
+ label = "sde_hdmi_cec";
+ qcom,hdmi-dev = <&sde_hdmi>;
+ interrupt-parent = <&sde_hdmi_tx>;
+ interrupts = <1 0>;
+
+ reg = <0xc9a0000 0x50c>;
+ reg-names = "hdmi_cec";
+
+ clocks = <&clock_mmss clk_mmss_mnoc_ahb_clk>,
+ <&clock_mmss clk_mmss_mdss_ahb_clk>,
+ <&clock_mmss clk_mmss_mdss_hdmi_clk>;
+ clock-names = "cec_mnoc_clk", "cec_iface_clk", "cec_core_clk";
+
+ pinctrl-names = "cec_active", "cec_sleep";
+ pinctrl-0 = <&mdss_hdmi_cec_active>;
+ pinctrl-1 = <&mdss_hdmi_cec_suspend>;
+
+ cec-gdsc-supply = <&gdsc_mdss>;
+ qcom,platform-supply-entries {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ qcom,platform-supply-entry@0 {
+ reg = <0>;
+ qcom,supply-name = "cec-gdsc";
+ qcom,supply-min-voltage = <0>;
+ qcom,supply-max-voltage = <0>;
+ qcom,supply-enable-load = <0>;
+ qcom,supply-disable-load = <0>;
+ };
+ };
+ };
};
&sde_kms {
diff --git a/arch/arm/boot/dts/qcom/msm8998-sde.dtsi b/arch/arm/boot/dts/qcom/msm8998-sde.dtsi
index f7dbda515643..795635d8d13d 100644
--- a/arch/arm/boot/dts/qcom/msm8998-sde.dtsi
+++ b/arch/arm/boot/dts/qcom/msm8998-sde.dtsi
@@ -175,6 +175,8 @@
reg-names = "core_physical", "qfprom_physical", "hdcp_physical";
interrupt-parent = <&sde_kms>;
interrupts = <8 0>;
+ interrupt-controller;
+ #interrupt-cells = <1>;
qcom,hdmi-tx-ddc-clk-gpio = <&tlmm 32 0>;
qcom,hdmi-tx-ddc-data-gpio = <&tlmm 33 0>;
qcom,hdmi-tx-hpd-gpio = <&tlmm 34 0>;
@@ -182,11 +184,9 @@
pinctrl-names = "default", "sleep";
pinctrl-0 = <&mdss_hdmi_hpd_active
&mdss_hdmi_ddc_active
- &mdss_hdmi_cec_active
&mdss_hdmi_5v_active>;
pinctrl-1 = <&mdss_hdmi_hpd_suspend
&mdss_hdmi_ddc_suspend
- &mdss_hdmi_cec_suspend
&mdss_hdmi_5v_suspend>;
hpd-gdsc-supply = <&gdsc_mdss>;
qcom,supply-names = "hpd-gdsc";
diff --git a/arch/arm/boot/dts/qcom/sdm630-camera.dtsi b/arch/arm/boot/dts/qcom/sdm630-camera.dtsi
index 75b30791ffdc..834a5706a525 100644
--- a/arch/arm/boot/dts/qcom/sdm630-camera.dtsi
+++ b/arch/arm/boot/dts/qcom/sdm630-camera.dtsi
@@ -395,6 +395,7 @@
reset-names = "micro_iface_reset";
qcom,src-clock-rates = <120000000 256000000 384000000
480000000 540000000 576000000>;
+ qcom,micro-reset;
qcom,cpp-fw-payload-info {
qcom,stripe-base = <790>;
qcom,plane-base = <715>;
diff --git a/arch/arm/boot/dts/qcom/sdm660-common.dtsi b/arch/arm/boot/dts/qcom/sdm660-common.dtsi
index baced7758c9f..f75794ba942f 100644
--- a/arch/arm/boot/dts/qcom/sdm660-common.dtsi
+++ b/arch/arm/boot/dts/qcom/sdm660-common.dtsi
@@ -267,8 +267,10 @@
qusb_phy0: qusb@c012000 {
compatible = "qcom,qusb2phy";
reg = <0x0c012000 0x180>,
+ <0x01fcb24c 0x4>,
<0x00188018 0x4>;
reg-names = "qusb_phy_base",
+ "tcsr_clamp_dig_n_1p8",
"ref_clk_addr";
vdd-supply = <&pm660l_l1>;
vdda18-supply = <&pm660_l10>;
diff --git a/arch/arm64/configs/msmcortex_mediabox-perf_defconfig b/arch/arm64/configs/msmcortex_mediabox-perf_defconfig
index 953d700c20cc..b359c78a0d29 100644
--- a/arch/arm64/configs/msmcortex_mediabox-perf_defconfig
+++ b/arch/arm64/configs/msmcortex_mediabox-perf_defconfig
@@ -405,6 +405,7 @@ CONFIG_MSM_VIDC_VMEM=y
CONFIG_MSM_VIDC_GOVERNORS=y
CONFIG_MSM_SDE_ROTATOR=y
CONFIG_MSM_SDE_ROTATOR_EVTLOG_DEBUG=y
+CONFIG_MSM_SDE_HDMI_CEC=y
CONFIG_DVB_MPQ=m
CONFIG_DVB_MPQ_DEMUX=m
CONFIG_DVB_MPQ_MEDIA_BOX_DEMUX=y
diff --git a/arch/arm64/configs/msmcortex_mediabox_defconfig b/arch/arm64/configs/msmcortex_mediabox_defconfig
index d81c10d11318..994b0f230968 100644
--- a/arch/arm64/configs/msmcortex_mediabox_defconfig
+++ b/arch/arm64/configs/msmcortex_mediabox_defconfig
@@ -407,6 +407,7 @@ CONFIG_MSM_VIDC_VMEM=y
CONFIG_MSM_VIDC_GOVERNORS=y
CONFIG_MSM_SDE_ROTATOR=y
CONFIG_MSM_SDE_ROTATOR_EVTLOG_DEBUG=y
+CONFIG_MSM_SDE_HDMI_CEC=y
CONFIG_DVB_MPQ=m
CONFIG_DVB_MPQ_DEMUX=m
CONFIG_DVB_MPQ_MEDIA_BOX_DEMUX=y
diff --git a/drivers/bluetooth/bluetooth-power.c b/drivers/bluetooth/bluetooth-power.c
index 59245ba320f6..99c18e3d66d7 100644
--- a/drivers/bluetooth/bluetooth-power.c
+++ b/drivers/bluetooth/bluetooth-power.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2009-2010, 2013-2016 The Linux Foundation. All rights reserved.
+/* Copyright (c) 2009-2010, 2013-2017 The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -682,7 +682,7 @@ int bt_register_slimdev(struct device *dev)
static long bt_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{
- int ret, pwr_cntrl = 0;
+ int ret = 0, pwr_cntrl = 0;
switch (cmd) {
case BT_CMD_SLIM_TEST:
diff --git a/drivers/bluetooth/btfm_slim_codec.c b/drivers/bluetooth/btfm_slim_codec.c
index 05da1fb1f975..1faebb1759e2 100644
--- a/drivers/bluetooth/btfm_slim_codec.c
+++ b/drivers/bluetooth/btfm_slim_codec.c
@@ -296,9 +296,9 @@ static int btfm_slim_dai_get_channel_map(struct snd_soc_dai *dai,
unsigned int *tx_num, unsigned int *tx_slot,
unsigned int *rx_num, unsigned int *rx_slot)
{
- int i, ret = -EINVAL, *slot, j = 0, num = 1;
+ int i, ret = -EINVAL, *slot = NULL, j = 0, num = 1;
struct btfmslim *btfmslim = dai->dev->platform_data;
- struct btfmslim_ch *ch;
+ struct btfmslim_ch *ch = NULL;
if (!btfmslim)
return ret;
diff --git a/drivers/char/diag/diag_masks.c b/drivers/char/diag/diag_masks.c
index 382717bad828..21994d53db91 100644
--- a/drivers/char/diag/diag_masks.c
+++ b/drivers/char/diag/diag_masks.c
@@ -28,7 +28,8 @@
#define DIAG_SET_FEATURE_MASK(x) (feature_bytes[(x)/8] |= (1 << (x & 0x7)))
#define diag_check_update(x) \
- (!info || (info && (info->peripheral_mask & MD_PERIPHERAL_MASK(x)))) \
+ (!info || (info && (info->peripheral_mask & MD_PERIPHERAL_MASK(x))) \
+ || (info && (info->peripheral_mask & MD_PERIPHERAL_PD_MASK(x)))) \
struct diag_mask_info msg_mask;
struct diag_mask_info msg_bt_mask;
@@ -89,7 +90,7 @@ static void diag_send_log_mask_update(uint8_t peripheral, int equip_id)
int err = 0;
int send_once = 0;
int header_len = sizeof(struct diag_ctrl_log_mask);
- uint8_t *buf = NULL;
+ uint8_t *buf = NULL, upd = 0;
uint8_t *temp = NULL;
uint32_t mask_size = 0;
struct diag_ctrl_log_mask ctrl_pkt;
@@ -106,11 +107,25 @@ static void diag_send_log_mask_update(uint8_t peripheral, int equip_id)
return;
}
- if (driver->md_session_mask != 0 &&
- driver->md_session_mask & MD_PERIPHERAL_MASK(peripheral))
- mask_info = driver->md_session_map[peripheral]->log_mask;
- else
+ if (driver->md_session_mask != 0) {
+ if (driver->md_session_mask & MD_PERIPHERAL_MASK(peripheral)) {
+ if (driver->md_session_map[peripheral])
+ mask_info =
+ driver->md_session_map[peripheral]->log_mask;
+ } else if (driver->md_session_mask &
+ MD_PERIPHERAL_PD_MASK(peripheral)) {
+ upd = diag_mask_to_pd_value(driver->md_session_mask);
+ if (upd && driver->md_session_map[upd])
+ mask_info =
+ driver->md_session_map[upd]->log_mask;
+ } else {
+ DIAG_LOG(DIAG_DEBUG_MASKS,
+ "asking for mask update with unknown session mask\n");
+ return;
+ }
+ } else {
mask_info = &log_mask;
+ }
if (!mask_info || !mask_info->ptr || !mask_info->update_buf)
return;
@@ -195,7 +210,7 @@ static void diag_send_log_mask_update(uint8_t peripheral, int equip_id)
static void diag_send_event_mask_update(uint8_t peripheral)
{
- uint8_t *buf = NULL;
+ uint8_t *buf = NULL, upd = 0;
uint8_t *temp = NULL;
struct diag_ctrl_event_mask header;
struct diag_mask_info *mask_info = NULL;
@@ -220,11 +235,25 @@ static void diag_send_event_mask_update(uint8_t peripheral)
return;
}
- if (driver->md_session_mask != 0 &&
- (driver->md_session_mask & MD_PERIPHERAL_MASK(peripheral)))
- mask_info = driver->md_session_map[peripheral]->event_mask;
- else
+ if (driver->md_session_mask != 0) {
+ if (driver->md_session_mask & MD_PERIPHERAL_MASK(peripheral)) {
+ if (driver->md_session_map[peripheral])
+ mask_info =
+ driver->md_session_map[peripheral]->event_mask;
+ } else if (driver->md_session_mask &
+ MD_PERIPHERAL_PD_MASK(peripheral)) {
+ upd = diag_mask_to_pd_value(driver->md_session_mask);
+ if (upd && driver->md_session_map[upd])
+ mask_info =
+ driver->md_session_map[upd]->event_mask;
+ } else {
+ DIAG_LOG(DIAG_DEBUG_MASKS,
+ "asking for mask update with unknown session mask\n");
+ return;
+ }
+ } else {
mask_info = &event_mask;
+ }
if (!mask_info || !mask_info->ptr || !mask_info->update_buf)
return;
@@ -284,7 +313,7 @@ static void diag_send_msg_mask_update(uint8_t peripheral, int first, int last)
int err = 0;
int header_len = sizeof(struct diag_ctrl_msg_mask);
int temp_len = 0;
- uint8_t *buf = NULL;
+ uint8_t *buf = NULL, upd = 0;
uint8_t *temp = NULL;
uint32_t mask_size = 0;
struct diag_mask_info *mask_info = NULL;
@@ -301,11 +330,25 @@ static void diag_send_msg_mask_update(uint8_t peripheral, int first, int last)
return;
}
- if (driver->md_session_mask != 0 &&
- (driver->md_session_mask & MD_PERIPHERAL_MASK(peripheral)))
- mask_info = driver->md_session_map[peripheral]->msg_mask;
- else
+ if (driver->md_session_mask != 0) {
+ if (driver->md_session_mask & MD_PERIPHERAL_MASK(peripheral)) {
+ if (driver->md_session_map[peripheral])
+ mask_info =
+ driver->md_session_map[peripheral]->msg_mask;
+ } else if (driver->md_session_mask &
+ MD_PERIPHERAL_PD_MASK(peripheral)) {
+ upd = diag_mask_to_pd_value(driver->md_session_mask);
+ if (upd && driver->md_session_map[upd])
+ mask_info =
+ driver->md_session_map[upd]->msg_mask;
+ } else {
+ DIAG_LOG(DIAG_DEBUG_MASKS,
+ "asking for mask update with unknown session mask\n");
+ return;
+ }
+ } else {
mask_info = &msg_mask;
+ }
if (!mask_info || !mask_info->ptr || !mask_info->update_buf)
return;
diff --git a/drivers/char/diag/diag_memorydevice.c b/drivers/char/diag/diag_memorydevice.c
index a5d92c51cc0b..7b414bd7d808 100644
--- a/drivers/char/diag/diag_memorydevice.c
+++ b/drivers/char/diag/diag_memorydevice.c
@@ -360,10 +360,6 @@ drop_data:
err = copy_to_user(buf + sizeof(int),
(void *)&num_data,
sizeof(int));
- } else {
- DIAG_LOG(DIAG_DEBUG_PERIPHERALS,
- "diag: md_session_map[%d] with pid = %d Exited..\n",
- peripheral, driver->md_session_map[peripheral]->pid);
}
diag_ws_on_copy_complete(DIAG_WS_MUX);
if (drain_again)
diff --git a/drivers/char/diag/diagchar.h b/drivers/char/diag/diagchar.h
index 73296b573436..a7d7fd176302 100644
--- a/drivers/char/diag/diagchar.h
+++ b/drivers/char/diag/diagchar.h
@@ -235,6 +235,10 @@
#define MD_PERIPHERAL_MASK(x) (1 << x)
+#define MD_PERIPHERAL_PD_MASK(x) \
+ ((x == PERIPHERAL_MODEM) ? (1 << UPD_WLAN) : \
+ ((x == PERIPHERAL_LPASS) ? (1 << UPD_AUDIO | 1 << UPD_SENSORS) : 0))\
+
/*
* Number of stm processors includes all the peripherals and
* apps.Added 1 below to indicate apps
@@ -675,6 +679,7 @@ void diag_cmd_remove_reg_by_proc(int proc);
int diag_cmd_chk_polling(struct diag_cmd_reg_entry_t *entry);
int diag_mask_param(void);
void diag_clear_masks(struct diag_md_session_t *info);
+uint8_t diag_mask_to_pd_value(uint32_t peripheral_mask);
void diag_record_stats(int type, int flag);
diff --git a/drivers/char/diag/diagchar_core.c b/drivers/char/diag/diagchar_core.c
index 5c1094b48e92..6be7c48f75a8 100644
--- a/drivers/char/diag/diagchar_core.c
+++ b/drivers/char/diag/diagchar_core.c
@@ -403,6 +403,30 @@ static uint32_t diag_translate_kernel_to_user_mask(uint32_t peripheral_mask)
ret |= DIAG_CON_UPD_SENSORS;
return ret;
}
+
+uint8_t diag_mask_to_pd_value(uint32_t peripheral_mask)
+{
+ uint8_t upd = 0;
+ uint32_t pd_mask = 0;
+
+ pd_mask = diag_translate_kernel_to_user_mask(peripheral_mask);
+ switch (pd_mask) {
+ case DIAG_CON_UPD_WLAN:
+ upd = UPD_WLAN;
+ break;
+ case DIAG_CON_UPD_AUDIO:
+ upd = UPD_AUDIO;
+ break;
+ case DIAG_CON_UPD_SENSORS:
+ upd = UPD_SENSORS;
+ break;
+ default:
+ DIAG_LOG(DIAG_DEBUG_MASKS,
+ "asking for mask update with no pd mask set\n");
+ }
+ return upd;
+}
+
int diag_mask_param(void)
{
return diag_mask_clear_param;
diff --git a/drivers/clk/msm/clock-osm.c b/drivers/clk/msm/clock-osm.c
index 9d9aa61c480a..7cc1c56a2090 100644
--- a/drivers/clk/msm/clock-osm.c
+++ b/drivers/clk/msm/clock-osm.c
@@ -1541,8 +1541,8 @@ static int clk_osm_setup_hw_table(struct clk_osm *c)
{
struct osm_entry *entry = c->osm_table;
int i;
- u32 freq_val, volt_val, override_val, spare_val;
- u32 table_entry_offset, last_spare, last_virtual_corner = 0;
+ u32 freq_val = 0, volt_val = 0, override_val = 0, spare_val = 0;
+ u32 table_entry_offset = 0, last_spare = 0, last_virtual_corner = 0;
for (i = 0; i < OSM_TABLE_SIZE; i++) {
if (i < c->num_entries) {
@@ -2758,7 +2758,7 @@ static ssize_t debugfs_trace_method_get(struct file *file, char __user *buf,
size_t count, loff_t *ppos)
{
struct clk_osm *c = file->private_data;
- int len, rc;
+ int len = 0, rc;
if (IS_ERR(file) || file == NULL) {
pr_err("input error %ld\n", PTR_ERR(file));
diff --git a/drivers/clk/msm/mdss/mdss-hdmi-pll-8998.c b/drivers/clk/msm/mdss/mdss-hdmi-pll-8998.c
index c60c4864442f..c4215f30acce 100644
--- a/drivers/clk/msm/mdss/mdss-hdmi-pll-8998.c
+++ b/drivers/clk/msm/mdss/mdss-hdmi-pll-8998.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2016, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2016-2017, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -29,6 +29,10 @@
#define _W(x, y, z) MDSS_PLL_REG_W(x, y, z)
#define _R(x, y) MDSS_PLL_REG_R(x, y)
+/* CONSTANTS */
+#define HDMI_VERSION_8998_3_3 1
+#define HDMI_VERSION_8998_1_8 2
+
/* PLL REGISTERS */
#define FREQ_UPDATE (0x008)
#define BIAS_EN_CLKBUFLR_EN (0x034)
@@ -277,7 +281,7 @@ find_optimal_index:
}
static int hdmi_8998_config_phy(unsigned long rate,
- struct hdmi_8998_reg_cfg *cfg)
+ struct hdmi_8998_reg_cfg *cfg, u32 ver)
{
u64 const high_freq_bit_clk_threshold = 3400000000UL;
u64 const dig_freq_bit_clk_threshold = 1500000000UL;
@@ -359,6 +363,7 @@ static int hdmi_8998_config_phy(unsigned long rate,
pr_debug("INTEGLOOP_GAIN = %llu\n", integloop_gain);
pr_debug("CMP_RNG = %llu\n", cmp_rng);
pr_debug("PLL_CMP = %llu\n", pll_cmp);
+ pr_debug("VER=%d\n", ver);
cfg->svs_mode_clk_sel = (digclk_divsel & 0xFF);
cfg->hsclk_sel = (0x20 | hsclk_sel);
@@ -382,82 +387,105 @@ static int hdmi_8998_config_phy(unsigned long rate,
cfg->core_clk_en = 0x2C;
cfg->coreclk_div_mode0 = 0x5;
cfg->phy_mode = (tmds_bclk_ratio ? 0x5 : 0x4);
+ /* V1P8_SEL */
+ if (ver == HDMI_VERSION_8998_1_8)
+ cfg->phy_mode |= 1 << 4;
cfg->ssc_en_center = 0x0;
- if (bclk > high_freq_bit_clk_threshold) {
- cfg->l0_tx_drv_lvl = 0xA;
- cfg->l0_tx_emp_post1_lvl = 0x3;
- cfg->l1_tx_drv_lvl = 0xA;
- cfg->l1_tx_emp_post1_lvl = 0x3;
- cfg->l2_tx_drv_lvl = 0xA;
- cfg->l2_tx_emp_post1_lvl = 0x3;
- cfg->l3_tx_drv_lvl = 0x8;
- cfg->l3_tx_emp_post1_lvl = 0x3;
- cfg->l0_pre_driver_1 = 0x0;
- cfg->l0_pre_driver_2 = 0x1C;
- cfg->l1_pre_driver_1 = 0x0;
- cfg->l1_pre_driver_2 = 0x1C;
- cfg->l2_pre_driver_1 = 0x0;
- cfg->l2_pre_driver_2 = 0x1C;
- cfg->l3_pre_driver_1 = 0x0;
- cfg->l3_pre_driver_2 = 0x0;
- } else if (bclk > dig_freq_bit_clk_threshold) {
- cfg->l0_tx_drv_lvl = 0x9;
- cfg->l0_tx_emp_post1_lvl = 0x3;
- cfg->l1_tx_drv_lvl = 0x9;
- cfg->l1_tx_emp_post1_lvl = 0x3;
- cfg->l2_tx_drv_lvl = 0x9;
- cfg->l2_tx_emp_post1_lvl = 0x3;
- cfg->l3_tx_drv_lvl = 0x8;
- cfg->l3_tx_emp_post1_lvl = 0x3;
- cfg->l0_pre_driver_1 = 0x0;
- cfg->l0_pre_driver_2 = 0x16;
- cfg->l1_pre_driver_1 = 0x0;
- cfg->l1_pre_driver_2 = 0x16;
- cfg->l2_pre_driver_1 = 0x0;
- cfg->l2_pre_driver_2 = 0x16;
- cfg->l3_pre_driver_1 = 0x0;
- cfg->l3_pre_driver_2 = 0x0;
- } else if (bclk > mid_freq_bit_clk_threshold) {
- cfg->l0_tx_drv_lvl = 0x9;
- cfg->l0_tx_emp_post1_lvl = 0x3;
- cfg->l1_tx_drv_lvl = 0x9;
- cfg->l1_tx_emp_post1_lvl = 0x3;
- cfg->l2_tx_drv_lvl = 0x9;
- cfg->l2_tx_emp_post1_lvl = 0x3;
- cfg->l3_tx_drv_lvl = 0x8;
- cfg->l3_tx_emp_post1_lvl = 0x3;
- cfg->l0_pre_driver_1 = 0x0;
- cfg->l0_pre_driver_2 = 0x0E;
- cfg->l1_pre_driver_1 = 0x0;
- cfg->l1_pre_driver_2 = 0x0E;
- cfg->l2_pre_driver_1 = 0x0;
- cfg->l2_pre_driver_2 = 0x0E;
- cfg->l3_pre_driver_1 = 0x0;
- cfg->l3_pre_driver_2 = 0x0;
+ if (ver == HDMI_VERSION_8998_3_3) {
+ if (bclk > high_freq_bit_clk_threshold) {
+ cfg->l0_tx_drv_lvl = 0xA;
+ cfg->l0_tx_emp_post1_lvl = 0x3;
+ cfg->l1_tx_drv_lvl = 0xA;
+ cfg->l1_tx_emp_post1_lvl = 0x3;
+ cfg->l2_tx_drv_lvl = 0xA;
+ cfg->l2_tx_emp_post1_lvl = 0x3;
+ cfg->l3_tx_drv_lvl = 0x8;
+ cfg->l3_tx_emp_post1_lvl = 0x3;
+ cfg->l0_pre_driver_1 = 0x0;
+ cfg->l0_pre_driver_2 = 0x1C;
+ cfg->l1_pre_driver_1 = 0x0;
+ cfg->l1_pre_driver_2 = 0x1C;
+ cfg->l2_pre_driver_1 = 0x0;
+ cfg->l2_pre_driver_2 = 0x1C;
+ cfg->l3_pre_driver_1 = 0x0;
+ cfg->l3_pre_driver_2 = 0x0;
+ } else if (bclk > dig_freq_bit_clk_threshold) {
+ cfg->l0_tx_drv_lvl = 0x9;
+ cfg->l0_tx_emp_post1_lvl = 0x3;
+ cfg->l1_tx_drv_lvl = 0x9;
+ cfg->l1_tx_emp_post1_lvl = 0x3;
+ cfg->l2_tx_drv_lvl = 0x9;
+ cfg->l2_tx_emp_post1_lvl = 0x3;
+ cfg->l3_tx_drv_lvl = 0x8;
+ cfg->l3_tx_emp_post1_lvl = 0x3;
+ cfg->l0_pre_driver_1 = 0x0;
+ cfg->l0_pre_driver_2 = 0x16;
+ cfg->l1_pre_driver_1 = 0x0;
+ cfg->l1_pre_driver_2 = 0x16;
+ cfg->l2_pre_driver_1 = 0x0;
+ cfg->l2_pre_driver_2 = 0x16;
+ cfg->l3_pre_driver_1 = 0x0;
+ cfg->l3_pre_driver_2 = 0x0;
+ } else if (bclk > mid_freq_bit_clk_threshold) {
+ cfg->l0_tx_drv_lvl = 0x9;
+ cfg->l0_tx_emp_post1_lvl = 0x3;
+ cfg->l1_tx_drv_lvl = 0x9;
+ cfg->l1_tx_emp_post1_lvl = 0x3;
+ cfg->l2_tx_drv_lvl = 0x9;
+ cfg->l2_tx_emp_post1_lvl = 0x3;
+ cfg->l3_tx_drv_lvl = 0x8;
+ cfg->l3_tx_emp_post1_lvl = 0x3;
+ cfg->l0_pre_driver_1 = 0x0;
+ cfg->l0_pre_driver_2 = 0x0E;
+ cfg->l1_pre_driver_1 = 0x0;
+ cfg->l1_pre_driver_2 = 0x0E;
+ cfg->l2_pre_driver_1 = 0x0;
+ cfg->l2_pre_driver_2 = 0x0E;
+ cfg->l3_pre_driver_1 = 0x0;
+ cfg->l3_pre_driver_2 = 0x0;
+ } else {
+ cfg->l0_tx_drv_lvl = 0x0;
+ cfg->l0_tx_emp_post1_lvl = 0x0;
+ cfg->l1_tx_drv_lvl = 0x0;
+ cfg->l1_tx_emp_post1_lvl = 0x0;
+ cfg->l2_tx_drv_lvl = 0x0;
+ cfg->l2_tx_emp_post1_lvl = 0x0;
+ cfg->l3_tx_drv_lvl = 0x0;
+ cfg->l3_tx_emp_post1_lvl = 0x0;
+ cfg->l0_pre_driver_1 = 0x0;
+ cfg->l0_pre_driver_2 = 0x01;
+ cfg->l1_pre_driver_1 = 0x0;
+ cfg->l1_pre_driver_2 = 0x01;
+ cfg->l2_pre_driver_1 = 0x0;
+ cfg->l2_pre_driver_2 = 0x01;
+ cfg->l3_pre_driver_1 = 0x0;
+ cfg->l3_pre_driver_2 = 0x0;
+ }
} else {
- cfg->l0_tx_drv_lvl = 0x0;
- cfg->l0_tx_emp_post1_lvl = 0x0;
- cfg->l1_tx_drv_lvl = 0x0;
- cfg->l1_tx_emp_post1_lvl = 0x0;
- cfg->l2_tx_drv_lvl = 0x0;
- cfg->l2_tx_emp_post1_lvl = 0x0;
- cfg->l3_tx_drv_lvl = 0x0;
+ cfg->l0_tx_drv_lvl = 0xF;
+ cfg->l0_tx_emp_post1_lvl = 0x5;
+ cfg->l1_tx_drv_lvl = 0xF;
+ cfg->l1_tx_emp_post1_lvl = 0x2;
+ cfg->l2_tx_drv_lvl = 0xF;
+ cfg->l2_tx_emp_post1_lvl = 0x2;
+ cfg->l3_tx_drv_lvl = 0xF;
cfg->l3_tx_emp_post1_lvl = 0x0;
cfg->l0_pre_driver_1 = 0x0;
- cfg->l0_pre_driver_2 = 0x01;
+ cfg->l0_pre_driver_2 = 0x1E;
cfg->l1_pre_driver_1 = 0x0;
- cfg->l1_pre_driver_2 = 0x01;
+ cfg->l1_pre_driver_2 = 0x1E;
cfg->l2_pre_driver_1 = 0x0;
- cfg->l2_pre_driver_2 = 0x01;
+ cfg->l2_pre_driver_2 = 0x1E;
cfg->l3_pre_driver_1 = 0x0;
- cfg->l3_pre_driver_2 = 0x0;
+ cfg->l3_pre_driver_2 = 0x10;
}
return rc;
}
-static int hdmi_8998_pll_set_clk_rate(struct clk *c, unsigned long rate)
+static int hdmi_8998_pll_set_clk_rate(struct clk *c, unsigned long rate,
+ u32 ver)
{
int rc = 0;
struct hdmi_pll_vco_clk *vco = to_hdmi_vco_clk(c);
@@ -465,7 +493,7 @@ static int hdmi_8998_pll_set_clk_rate(struct clk *c, unsigned long rate)
struct hdmi_8998_reg_cfg cfg = {0};
void __iomem *phy = io->phy_base, *pll = io->pll_base;
- rc = hdmi_8998_config_phy(rate, &cfg);
+ rc = hdmi_8998_config_phy(rate, &cfg, ver);
if (rc) {
pr_err("rate calculation failed\n, rc=%d", rc);
return rc;
@@ -699,7 +727,7 @@ static int hdmi_8998_vco_get_lock_range(struct clk *c,
}
static int hdmi_8998_vco_rate_atomic_update(struct clk *c,
- unsigned long rate)
+ unsigned long rate, u32 ver)
{
struct hdmi_pll_vco_clk *vco = to_hdmi_vco_clk(c);
struct mdss_pll_resources *io = vco->priv;
@@ -707,7 +735,7 @@ static int hdmi_8998_vco_rate_atomic_update(struct clk *c,
struct hdmi_8998_reg_cfg cfg = {0};
int rc = 0;
- rc = hdmi_8998_config_phy(rate, &cfg);
+ rc = hdmi_8998_config_phy(rate, &cfg, ver);
if (rc) {
pr_err("rate calculation failed\n, rc=%d", rc);
goto end;
@@ -728,7 +756,7 @@ end:
return rc;
}
-static int hdmi_8998_vco_set_rate(struct clk *c, unsigned long rate)
+static int hdmi_8998_vco_set_rate(struct clk *c, unsigned long rate, u32 ver)
{
struct hdmi_pll_vco_clk *vco = to_hdmi_vco_clk(c);
struct mdss_pll_resources *io = vco->priv;
@@ -767,9 +795,9 @@ static int hdmi_8998_vco_set_rate(struct clk *c, unsigned long rate)
set_power_dwn = 1;
if (atomic_update)
- rc = hdmi_8998_vco_rate_atomic_update(c, rate);
+ rc = hdmi_8998_vco_rate_atomic_update(c, rate, ver);
else
- rc = hdmi_8998_pll_set_clk_rate(c, rate);
+ rc = hdmi_8998_pll_set_clk_rate(c, rate, ver);
if (rc) {
pr_err("failed to set clk rate\n");
@@ -806,7 +834,7 @@ static long hdmi_8998_vco_round_rate(struct clk *c, unsigned long rate)
return rrate;
}
-static int hdmi_8998_vco_prepare(struct clk *c)
+static int hdmi_8998_vco_prepare(struct clk *c, u32 ver)
{
struct hdmi_pll_vco_clk *vco = to_hdmi_vco_clk(c);
struct mdss_pll_resources *io = vco->priv;
@@ -824,7 +852,7 @@ static int hdmi_8998_vco_prepare(struct clk *c)
}
if (!vco->rate_set && vco->rate) {
- rc = hdmi_8998_pll_set_clk_rate(c, vco->rate);
+ rc = hdmi_8998_pll_set_clk_rate(c, vco->rate, ver);
if (rc) {
pr_err("set rate failed, rc=%d\n", rc);
goto error;
@@ -902,10 +930,38 @@ static enum handoff hdmi_8998_vco_handoff(struct clk *c)
return ret;
}
-static struct clk_ops hdmi_8998_vco_clk_ops = {
- .set_rate = hdmi_8998_vco_set_rate,
+static int hdmi_8998_3p3_vco_set_rate(struct clk *c, unsigned long rate)
+{
+ return hdmi_8998_vco_set_rate(c, rate, HDMI_VERSION_8998_3_3);
+}
+
+static int hdmi_8998_1p8_vco_set_rate(struct clk *c, unsigned long rate)
+{
+ return hdmi_8998_vco_set_rate(c, rate, HDMI_VERSION_8998_1_8);
+}
+
+static int hdmi_8998_3p3_vco_prepare(struct clk *c)
+{
+ return hdmi_8998_vco_prepare(c, HDMI_VERSION_8998_3_3);
+}
+
+static int hdmi_8998_1p8_vco_prepare(struct clk *c)
+{
+ return hdmi_8998_vco_prepare(c, HDMI_VERSION_8998_1_8);
+}
+
+static struct clk_ops hdmi_8998_3p3_vco_clk_ops = {
+ .set_rate = hdmi_8998_3p3_vco_set_rate,
+ .round_rate = hdmi_8998_vco_round_rate,
+ .prepare = hdmi_8998_3p3_vco_prepare,
+ .unprepare = hdmi_8998_vco_unprepare,
+ .handoff = hdmi_8998_vco_handoff,
+};
+
+static struct clk_ops hdmi_8998_1p8_vco_clk_ops = {
+ .set_rate = hdmi_8998_1p8_vco_set_rate,
.round_rate = hdmi_8998_vco_round_rate,
- .prepare = hdmi_8998_vco_prepare,
+ .prepare = hdmi_8998_1p8_vco_prepare,
.unprepare = hdmi_8998_vco_unprepare,
.handoff = hdmi_8998_vco_handoff,
};
@@ -915,7 +971,7 @@ static struct hdmi_pll_vco_clk hdmi_vco_clk = {
.max_rate = HDMI_VCO_MAX_RATE_HZ,
.c = {
.dbg_name = "hdmi_8998_vco_clk",
- .ops = &hdmi_8998_vco_clk_ops,
+ .ops = &hdmi_8998_3p3_vco_clk_ops,
CLK_INIT(hdmi_vco_clk.c),
},
};
@@ -925,7 +981,7 @@ static struct clk_lookup hdmipllcc_8998[] = {
};
int hdmi_8998_pll_clock_register(struct platform_device *pdev,
- struct mdss_pll_resources *pll_res)
+ struct mdss_pll_resources *pll_res, u32 ver)
{
int rc = 0;
@@ -936,8 +992,20 @@ int hdmi_8998_pll_clock_register(struct platform_device *pdev,
hdmi_vco_clk.priv = pll_res;
+ switch (ver) {
+ case HDMI_VERSION_8998_3_3:
+ hdmi_vco_clk.c.ops = &hdmi_8998_3p3_vco_clk_ops;
+ break;
+ case HDMI_VERSION_8998_1_8:
+ hdmi_vco_clk.c.ops = &hdmi_8998_1p8_vco_clk_ops;
+ break;
+ default:
+ hdmi_vco_clk.c.ops = &hdmi_8998_3p3_vco_clk_ops;
+ break;
+ };
+
rc = of_msm_clock_register(pdev->dev.of_node, hdmipllcc_8998,
- ARRAY_SIZE(hdmipllcc_8998));
+ ARRAY_SIZE(hdmipllcc_8998));
if (rc) {
pr_err("clock register failed, rc=%d\n", rc);
return rc;
@@ -945,3 +1013,17 @@ int hdmi_8998_pll_clock_register(struct platform_device *pdev,
return rc;
}
+
+int hdmi_8998_3p3_pll_clock_register(struct platform_device *pdev,
+ struct mdss_pll_resources *pll_res)
+{
+ return hdmi_8998_pll_clock_register(pdev, pll_res,
+ HDMI_VERSION_8998_3_3);
+}
+
+int hdmi_8998_1p8_pll_clock_register(struct platform_device *pdev,
+ struct mdss_pll_resources *pll_res)
+{
+ return hdmi_8998_pll_clock_register(pdev, pll_res,
+ HDMI_VERSION_8998_1_8);
+}
diff --git a/drivers/clk/msm/mdss/mdss-hdmi-pll.h b/drivers/clk/msm/mdss/mdss-hdmi-pll.h
index 19f9b925644a..9e6a39481286 100644
--- a/drivers/clk/msm/mdss/mdss-hdmi-pll.h
+++ b/drivers/clk/msm/mdss/mdss-hdmi-pll.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012-2016, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-2017, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -45,17 +45,19 @@ int hdmi_20nm_pll_clock_register(struct platform_device *pdev,
struct mdss_pll_resources *pll_res);
int hdmi_8996_v1_pll_clock_register(struct platform_device *pdev,
- struct mdss_pll_resources *pll_res);
+ struct mdss_pll_resources *pll_res);
int hdmi_8996_v2_pll_clock_register(struct platform_device *pdev,
- struct mdss_pll_resources *pll_res);
+ struct mdss_pll_resources *pll_res);
int hdmi_8996_v3_pll_clock_register(struct platform_device *pdev,
- struct mdss_pll_resources *pll_res);
+ struct mdss_pll_resources *pll_res);
int hdmi_8996_v3_1p8_pll_clock_register(struct platform_device *pdev,
- struct mdss_pll_resources *pll_res);
+ struct mdss_pll_resources *pll_res);
-int hdmi_8998_pll_clock_register(struct platform_device *pdev,
- struct mdss_pll_resources *pll_res);
+int hdmi_8998_3p3_pll_clock_register(struct platform_device *pdev,
+ struct mdss_pll_resources *pll_res);
+int hdmi_8998_1p8_pll_clock_register(struct platform_device *pdev,
+ struct mdss_pll_resources *pll_res);
#endif
diff --git a/drivers/clk/msm/mdss/mdss-pll.c b/drivers/clk/msm/mdss/mdss-pll.c
index 01ce2b1817f2..b5c98774ba92 100644
--- a/drivers/clk/msm/mdss/mdss-pll.c
+++ b/drivers/clk/msm/mdss/mdss-pll.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2013-2016, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2013-2017, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -149,7 +149,9 @@ static int mdss_pll_resource_parse(struct platform_device *pdev,
"qcom,mdss_hdmi_pll_8996_v3_1p8")) {
pll_res->pll_interface_type = MDSS_HDMI_PLL_8996_V3_1_8;
} else if (!strcmp(compatible_stream, "qcom,mdss_hdmi_pll_8998")) {
- pll_res->pll_interface_type = MDSS_HDMI_PLL_8998;
+ pll_res->pll_interface_type = MDSS_HDMI_PLL_8998_3_3;
+ } else if (!strcmp(compatible_stream, "qcom,mdss_hdmi_pll_8998_1p8")) {
+ pll_res->pll_interface_type = MDSS_HDMI_PLL_8998_1_8;
} else {
goto err;
}
@@ -193,8 +195,11 @@ static int mdss_pll_clock_register(struct platform_device *pdev,
case MDSS_HDMI_PLL_8996_V3_1_8:
rc = hdmi_8996_v3_1p8_pll_clock_register(pdev, pll_res);
break;
- case MDSS_HDMI_PLL_8998:
- rc = hdmi_8998_pll_clock_register(pdev, pll_res);
+ case MDSS_HDMI_PLL_8998_3_3:
+ rc = hdmi_8998_3p3_pll_clock_register(pdev, pll_res);
+ break;
+ case MDSS_HDMI_PLL_8998_1_8:
+ rc = hdmi_8998_1p8_pll_clock_register(pdev, pll_res);
break;
case MDSS_UNKNOWN_PLL:
default:
@@ -401,6 +406,7 @@ static const struct of_device_id mdss_pll_dt_match[] = {
{.compatible = "qcom,mdss_hdmi_pll_8996_v3_1p8"},
{.compatible = "qcom,mdss_dp_pll_8998"},
{.compatible = "qcom,mdss_hdmi_pll_8998"},
+ {.compatible = "qcom,mdss_hdmi_pll_8998_1p8"},
{}
};
diff --git a/drivers/clk/msm/mdss/mdss-pll.h b/drivers/clk/msm/mdss/mdss-pll.h
index 8fffaf30d4ec..0120d71f0daf 100644
--- a/drivers/clk/msm/mdss/mdss-pll.h
+++ b/drivers/clk/msm/mdss/mdss-pll.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2013-2016, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2013-2017, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -37,7 +37,8 @@ enum {
MDSS_HDMI_PLL_8996_V2,
MDSS_HDMI_PLL_8996_V3,
MDSS_HDMI_PLL_8996_V3_1_8,
- MDSS_HDMI_PLL_8998,
+ MDSS_HDMI_PLL_8998_3_3,
+ MDSS_HDMI_PLL_8998_1_8,
MDSS_UNKNOWN_PLL,
};
diff --git a/drivers/gpio/gpiolib-acpi.c b/drivers/gpio/gpiolib-acpi.c
index 16a7b6816744..8decab2a9cce 100644
--- a/drivers/gpio/gpiolib-acpi.c
+++ b/drivers/gpio/gpiolib-acpi.c
@@ -597,7 +597,7 @@ int acpi_dev_gpio_irq_get(struct acpi_device *adev, int index)
int idx, i;
for (i = 0, idx = 0; idx <= index; i++) {
- struct acpi_gpio_info info;
+ struct acpi_gpio_info info = {0, 0};
struct gpio_desc *desc;
desc = acpi_get_gpiod_by_index(adev, NULL, i, &info);
diff --git a/drivers/gpu/drm/drm_mm.c b/drivers/gpu/drm/drm_mm.c
index 04de6fd88f8c..6e4dd62d4ed9 100644
--- a/drivers/gpu/drm/drm_mm.c
+++ b/drivers/gpu/drm/drm_mm.c
@@ -46,6 +46,8 @@
#include <linux/slab.h>
#include <linux/seq_file.h>
#include <linux/export.h>
+#include <linux/interval_tree_generic.h>
+#include <linux/rbtree.h>
/**
* DOC: Overview
@@ -73,7 +75,8 @@
* allocations and avoiding too much fragmentation. This means free space
* searches are O(num_holes). Given that all the fancy features drm_mm supports
* something better would be fairly complex and since gfx thrashing is a fairly
- * steep cliff not a real concern. Removing a node again is O(1).
+ * steep cliff not a real concern. Removing a node again is O(1). With the
+ * rbtree to track free holes, free hole search becomes O(log(num_holes)).
*
* drm_mm supports a few features: Alignment and range restrictions can be
* supplied. Further more every &drm_mm_node has a color value (which is just an
@@ -103,6 +106,98 @@ static struct drm_mm_node *drm_mm_search_free_in_range_generic(const struct drm_
u64 end,
enum drm_mm_search_flags flags);
+#define START(node) ((node)->start)
+#define LAST(node) ((node)->start + (node)->size - 1)
+
+INTERVAL_TREE_DEFINE(struct drm_mm_node, rb,
+ u64, __subtree_last,
+ START, LAST, static inline, drm_mm_interval_tree)
+
+struct drm_mm_node *
+drm_mm_interval_first(struct drm_mm *mm, u64 start, u64 last)
+{
+ return drm_mm_interval_tree_iter_first(&mm->interval_tree,
+ start, last);
+}
+EXPORT_SYMBOL(drm_mm_interval_first);
+
+struct drm_mm_node *
+drm_mm_interval_next(struct drm_mm_node *node, u64 start, u64 last)
+{
+ return drm_mm_interval_tree_iter_next(node, start, last);
+}
+EXPORT_SYMBOL(drm_mm_interval_next);
+
+static void drm_mm_interval_tree_add_node(struct drm_mm_node *hole_node,
+ struct drm_mm_node *node)
+{
+ struct drm_mm *mm = hole_node->mm;
+ struct rb_node **link, *rb;
+ struct drm_mm_node *parent;
+
+ node->__subtree_last = LAST(node);
+
+ if (hole_node->allocated) {
+ rb = &hole_node->rb;
+ while (rb) {
+ parent = rb_entry(rb, struct drm_mm_node, rb);
+ if (parent->__subtree_last >= node->__subtree_last)
+ break;
+
+ parent->__subtree_last = node->__subtree_last;
+ rb = rb_parent(rb);
+ }
+
+ rb = &hole_node->rb;
+ link = &hole_node->rb.rb_right;
+ } else {
+ rb = NULL;
+ link = &mm->interval_tree.rb_node;
+ }
+
+ while (*link) {
+ rb = *link;
+ parent = rb_entry(rb, struct drm_mm_node, rb);
+ if (parent->__subtree_last < node->__subtree_last)
+ parent->__subtree_last = node->__subtree_last;
+ if (node->start < parent->start)
+ link = &parent->rb.rb_left;
+ else
+ link = &parent->rb.rb_right;
+ }
+
+ rb_link_node(&node->rb, rb, link);
+ rb_insert_augmented(&node->rb,
+ &mm->interval_tree,
+ &drm_mm_interval_tree_augment);
+}
+
+static void
+rb_insert_hole_node(struct drm_mm_node *hole_node, struct drm_mm *mm)
+{
+ struct rb_node **new = &(mm->holes_tree.rb_node);
+ struct rb_node *parent = NULL;
+ struct drm_mm_node *cur;
+
+ while (*new) {
+ parent = *new;
+ cur = rb_entry(parent, struct drm_mm_node, hole_node);
+
+ if (__drm_mm_hole_node_start(hole_node)
+ < __drm_mm_hole_node_start(cur))
+ new = &parent->rb_left;
+ else
+ new = &parent->rb_right;
+ }
+ rb_link_node(&hole_node->hole_node, parent, new);
+ rb_insert_color(&hole_node->hole_node, &mm->holes_tree);
+}
+
+static void rb_erase_hole_node(struct drm_mm_node *hole_node, struct drm_mm *mm)
+{
+ rb_erase(&hole_node->hole_node, &mm->holes_tree);
+}
+
static void drm_mm_insert_helper(struct drm_mm_node *hole_node,
struct drm_mm_node *node,
u64 size, unsigned alignment,
@@ -142,6 +237,7 @@ static void drm_mm_insert_helper(struct drm_mm_node *hole_node,
if (adj_start == hole_start) {
hole_node->hole_follows = 0;
list_del(&hole_node->hole_stack);
+ rb_erase_hole_node(hole_node, mm);
}
node->start = adj_start;
@@ -150,14 +246,16 @@ static void drm_mm_insert_helper(struct drm_mm_node *hole_node,
node->color = color;
node->allocated = 1;
- INIT_LIST_HEAD(&node->hole_stack);
list_add(&node->node_list, &hole_node->node_list);
+ drm_mm_interval_tree_add_node(hole_node, node);
+
BUG_ON(node->start + node->size > adj_end);
node->hole_follows = 0;
if (__drm_mm_hole_node_start(node) < hole_end) {
list_add(&node->hole_stack, &mm->hole_stack);
+ rb_insert_hole_node(node, mm);
node->hole_follows = 1;
}
}
@@ -178,39 +276,54 @@ static void drm_mm_insert_helper(struct drm_mm_node *hole_node,
*/
int drm_mm_reserve_node(struct drm_mm *mm, struct drm_mm_node *node)
{
- struct drm_mm_node *hole;
u64 end = node->start + node->size;
- u64 hole_start;
- u64 hole_end;
+ struct drm_mm_node *hole;
+ u64 hole_start, hole_end;
- BUG_ON(node == NULL);
+ if (WARN_ON(node->size == 0))
+ return -EINVAL;
/* Find the relevant hole to add our node to */
- drm_mm_for_each_hole(hole, mm, hole_start, hole_end) {
- if (hole_start > node->start || hole_end < end)
- continue;
+ hole = drm_mm_interval_tree_iter_first(&mm->interval_tree,
+ node->start, ~(u64)0);
+ if (hole) {
+ if (hole->start < end)
+ return -ENOSPC;
+ } else {
+ hole = list_entry(&mm->head_node.node_list,
+ typeof(*hole), node_list);
+ }
- node->mm = mm;
- node->allocated = 1;
+ hole = list_last_entry(&hole->node_list, typeof(*hole), node_list);
+ if (!hole->hole_follows)
+ return -ENOSPC;
- INIT_LIST_HEAD(&node->hole_stack);
- list_add(&node->node_list, &hole->node_list);
+ hole_start = __drm_mm_hole_node_start(hole);
+ hole_end = __drm_mm_hole_node_end(hole);
+ if (hole_start > node->start || hole_end < end)
+ return -ENOSPC;
- if (node->start == hole_start) {
- hole->hole_follows = 0;
- list_del_init(&hole->hole_stack);
- }
+ node->mm = mm;
+ node->allocated = 1;
- node->hole_follows = 0;
- if (end != hole_end) {
- list_add(&node->hole_stack, &mm->hole_stack);
- node->hole_follows = 1;
- }
+ list_add(&node->node_list, &hole->node_list);
- return 0;
+ drm_mm_interval_tree_add_node(hole, node);
+
+ if (node->start == hole_start) {
+ hole->hole_follows = 0;
+ list_del(&hole->hole_stack);
+ rb_erase_hole_node(hole, mm);
}
- return -ENOSPC;
+ node->hole_follows = 0;
+ if (end != hole_end) {
+ list_add(&node->hole_stack, &mm->hole_stack);
+ rb_insert_hole_node(node, mm);
+ node->hole_follows = 1;
+ }
+
+ return 0;
}
EXPORT_SYMBOL(drm_mm_reserve_node);
@@ -237,6 +350,9 @@ int drm_mm_insert_node_generic(struct drm_mm *mm, struct drm_mm_node *node,
{
struct drm_mm_node *hole_node;
+ if (WARN_ON(size == 0))
+ return -EINVAL;
+
hole_node = drm_mm_search_free_generic(mm, size, alignment,
color, sflags);
if (!hole_node)
@@ -289,6 +405,7 @@ static void drm_mm_insert_helper_range(struct drm_mm_node *hole_node,
if (adj_start == hole_start) {
hole_node->hole_follows = 0;
list_del(&hole_node->hole_stack);
+ rb_erase_hole_node(hole_node, mm);
}
node->start = adj_start;
@@ -297,9 +414,10 @@ static void drm_mm_insert_helper_range(struct drm_mm_node *hole_node,
node->color = color;
node->allocated = 1;
- INIT_LIST_HEAD(&node->hole_stack);
list_add(&node->node_list, &hole_node->node_list);
+ drm_mm_interval_tree_add_node(hole_node, node);
+
BUG_ON(node->start < start);
BUG_ON(node->start < adj_start);
BUG_ON(node->start + node->size > adj_end);
@@ -308,6 +426,7 @@ static void drm_mm_insert_helper_range(struct drm_mm_node *hole_node,
node->hole_follows = 0;
if (__drm_mm_hole_node_start(node) < hole_end) {
list_add(&node->hole_stack, &mm->hole_stack);
+ rb_insert_hole_node(node, mm);
node->hole_follows = 1;
}
}
@@ -338,6 +457,9 @@ int drm_mm_insert_node_in_range_generic(struct drm_mm *mm, struct drm_mm_node *n
{
struct drm_mm_node *hole_node;
+ if (WARN_ON(size == 0))
+ return -EINVAL;
+
hole_node = drm_mm_search_free_in_range_generic(mm,
size, alignment, color,
start, end, sflags);
@@ -377,6 +499,7 @@ void drm_mm_remove_node(struct drm_mm_node *node)
BUG_ON(__drm_mm_hole_node_start(node) ==
__drm_mm_hole_node_end(node));
list_del(&node->hole_stack);
+ rb_erase_hole_node(node, mm);
} else
BUG_ON(__drm_mm_hole_node_start(node) !=
__drm_mm_hole_node_end(node));
@@ -385,9 +508,11 @@ void drm_mm_remove_node(struct drm_mm_node *node)
if (!prev_node->hole_follows) {
prev_node->hole_follows = 1;
list_add(&prev_node->hole_stack, &mm->hole_stack);
+ rb_insert_hole_node(prev_node, mm);
} else
list_move(&prev_node->hole_stack, &mm->hole_stack);
+ drm_mm_interval_tree_remove(node, &mm->interval_tree);
list_del(&node->node_list);
node->allocated = 0;
}
@@ -410,6 +535,46 @@ static int check_free_hole(u64 start, u64 end, u64 size, unsigned alignment)
return end >= start + size;
}
+static struct drm_mm_node *get_first_hole(const struct drm_mm *mm,
+ enum drm_mm_search_flags flags)
+{
+ if (flags & DRM_MM_SEARCH_BOTTOM_UP) {
+ struct rb_node *node = rb_first(&mm->holes_tree);
+
+ return rb_entry(node, struct drm_mm_node, hole_node);
+ } else if (flags & DRM_MM_SEARCH_BELOW) {
+ return list_entry((mm)->hole_stack.prev,
+ struct drm_mm_node, hole_stack);
+ } else {
+ return list_entry((mm)->hole_stack.next,
+ struct drm_mm_node, hole_stack);
+ }
+}
+
+static struct drm_mm_node *get_next_hole(struct drm_mm_node *entry,
+ enum drm_mm_search_flags flags)
+{
+ if (flags & DRM_MM_SEARCH_BOTTOM_UP) {
+ return rb_entry(rb_next(&entry->hole_node),
+ struct drm_mm_node, hole_node);
+ } else if (flags & DRM_MM_SEARCH_BELOW) {
+ return list_entry(entry->hole_stack.prev,
+ struct drm_mm_node, hole_stack);
+ } else {
+ return list_entry(entry->hole_stack.next,
+ struct drm_mm_node, hole_stack);
+ }
+}
+
+static bool drm_mm_hole_traversal_condition(const struct drm_mm *mm,
+ struct drm_mm_node *entry, enum drm_mm_search_flags flags)
+{
+ if (flags & DRM_MM_SEARCH_BOTTOM_UP)
+ return entry ? 1 : 0;
+ else
+ return (&entry->hole_stack != &(mm)->hole_stack) ? 1 : 0;
+}
+
static struct drm_mm_node *drm_mm_search_free_generic(const struct drm_mm *mm,
u64 size,
unsigned alignment,
@@ -427,9 +592,14 @@ static struct drm_mm_node *drm_mm_search_free_generic(const struct drm_mm *mm,
best = NULL;
best_size = ~0UL;
- __drm_mm_for_each_hole(entry, mm, adj_start, adj_end,
- flags & DRM_MM_SEARCH_BELOW) {
- u64 hole_size = adj_end - adj_start;
+ for (entry = get_first_hole(mm, flags);
+ drm_mm_hole_traversal_condition(mm, entry, flags);
+ entry = get_next_hole(entry, flags)) {
+ u64 hole_size;
+
+ adj_start = drm_mm_hole_node_start(entry);
+ adj_end = drm_mm_hole_node_end(entry);
+ hole_size = adj_end - adj_start;
if (mm->color_adjust) {
mm->color_adjust(entry, color, &adj_start, &adj_end);
@@ -471,9 +641,14 @@ static struct drm_mm_node *drm_mm_search_free_in_range_generic(const struct drm_
best = NULL;
best_size = ~0UL;
- __drm_mm_for_each_hole(entry, mm, adj_start, adj_end,
- flags & DRM_MM_SEARCH_BELOW) {
- u64 hole_size = adj_end - adj_start;
+ for (entry = get_first_hole(mm, flags);
+ drm_mm_hole_traversal_condition(mm, entry, flags);
+ entry = get_next_hole(entry, flags)) {
+ u64 hole_size;
+
+ adj_start = drm_mm_hole_node_start(entry);
+ adj_end = drm_mm_hole_node_end(entry);
+ hole_size = adj_end - adj_start;
if (adj_start < start)
adj_start = start;
@@ -514,14 +689,21 @@ void drm_mm_replace_node(struct drm_mm_node *old, struct drm_mm_node *new)
{
list_replace(&old->node_list, &new->node_list);
list_replace(&old->hole_stack, &new->hole_stack);
+ rb_replace_node(&old->rb, &new->rb, &old->mm->interval_tree);
new->hole_follows = old->hole_follows;
new->mm = old->mm;
new->start = old->start;
new->size = old->size;
new->color = old->color;
+ new->__subtree_last = old->__subtree_last;
old->allocated = 0;
new->allocated = 1;
+
+ if (old->hole_follows)
+ rb_replace_node(&old->hole_node, &new->hole_node,
+ &old->mm->holes_tree);
+
}
EXPORT_SYMBOL(drm_mm_replace_node);
@@ -746,7 +928,6 @@ void drm_mm_init(struct drm_mm * mm, u64 start, u64 size)
/* Clever trick to avoid a special case in the free hole tracking. */
INIT_LIST_HEAD(&mm->head_node.node_list);
- INIT_LIST_HEAD(&mm->head_node.hole_stack);
mm->head_node.hole_follows = 1;
mm->head_node.scanned_block = 0;
mm->head_node.scanned_prev_free = 0;
@@ -756,7 +937,10 @@ void drm_mm_init(struct drm_mm * mm, u64 start, u64 size)
mm->head_node.size = start - mm->head_node.start;
list_add_tail(&mm->head_node.hole_stack, &mm->hole_stack);
+ mm->interval_tree = RB_ROOT;
mm->color_adjust = NULL;
+ mm->holes_tree = RB_ROOT;
+ rb_insert_hole_node(&mm->head_node, mm);
}
EXPORT_SYMBOL(drm_mm_init);
diff --git a/drivers/gpu/drm/msm/Kconfig b/drivers/gpu/drm/msm/Kconfig
index 5838545468f8..dbc198b00792 100644
--- a/drivers/gpu/drm/msm/Kconfig
+++ b/drivers/gpu/drm/msm/Kconfig
@@ -12,6 +12,8 @@ config DRM_MSM
select QCOM_SCM
select BACKLIGHT_CLASS_DEVICE
select MSM_EXT_DISPLAY
+ select MMU_NOTIFIER
+ select INTERVAL_TREE
default y
help
DRM/KMS driver for MSM/snapdragon.
diff --git a/drivers/gpu/drm/msm/hdmi-staging/sde_hdmi.c b/drivers/gpu/drm/msm/hdmi-staging/sde_hdmi.c
index 4c70472bd338..acc417737558 100644
--- a/drivers/gpu/drm/msm/hdmi-staging/sde_hdmi.c
+++ b/drivers/gpu/drm/msm/hdmi-staging/sde_hdmi.c
@@ -907,6 +907,17 @@ static void _sde_hdmi_hdp_disable(struct sde_hdmi *sde_hdmi)
}
}
+static void _sde_hdmi_cec_update_phys_addr(struct sde_hdmi *display)
+{
+ struct edid *edid = display->edid_ctrl->edid;
+
+ if (edid)
+ cec_notifier_set_phys_addr_from_edid(display->notifier, edid);
+ else
+ cec_notifier_set_phys_addr(display->notifier,
+ CEC_PHYS_ADDR_INVALID);
+}
+
static void _sde_hdmi_hotplug_work(struct work_struct *work)
{
struct sde_hdmi *sde_hdmi =
@@ -936,6 +947,7 @@ static void _sde_hdmi_hotplug_work(struct work_struct *work)
sde_free_edid((void **)&sde_hdmi->edid_ctrl);
drm_helper_hpd_irq_event(connector->dev);
+ _sde_hdmi_cec_update_phys_addr(sde_hdmi);
}
static void _sde_hdmi_connector_irq(struct sde_hdmi *sde_hdmi)
@@ -1673,10 +1685,28 @@ int sde_hdmi_dev_deinit(struct sde_hdmi *display)
SDE_ERROR("Invalid params\n");
return -EINVAL;
}
+ return 0;
+}
+
+static int _sde_hdmi_cec_init(struct sde_hdmi *display)
+{
+ struct platform_device *pdev = display->pdev;
+
+ display->notifier = cec_notifier_get(&pdev->dev);
+ if (!display->notifier) {
+ SDE_ERROR("CEC notifier get failed\n");
+ return -ENOMEM;
+ }
return 0;
}
+static void _sde_hdmi_cec_deinit(struct sde_hdmi *display)
+{
+ cec_notifier_set_phys_addr(display->notifier, CEC_PHYS_ADDR_INVALID);
+ cec_notifier_put(display->notifier);
+}
+
static int sde_hdmi_bind(struct device *dev, struct device *master, void *data)
{
int rc = 0;
@@ -1715,7 +1745,14 @@ static int sde_hdmi_bind(struct device *dev, struct device *master, void *data)
if (rc) {
SDE_ERROR("[%s]Ext Disp init failed, rc=%d\n",
display->name, rc);
- goto error;
+ goto ext_error;
+ }
+
+ rc = _sde_hdmi_cec_init(display);
+ if (rc) {
+ SDE_ERROR("[%s]CEC init failed, rc=%d\n",
+ display->name, rc);
+ goto ext_error;
}
display->edid_ctrl = sde_edid_init();
@@ -1723,7 +1760,7 @@ static int sde_hdmi_bind(struct device *dev, struct device *master, void *data)
SDE_ERROR("[%s]sde edid init failed\n",
display->name);
rc = -ENOMEM;
- goto error;
+ goto cec_error;
}
display_ctrl = &display->ctrl;
@@ -1732,7 +1769,10 @@ static int sde_hdmi_bind(struct device *dev, struct device *master, void *data)
mutex_unlock(&display->display_lock);
return rc;
-error:
+
+cec_error:
+ (void)_sde_hdmi_cec_deinit(display);
+ext_error:
(void)_sde_hdmi_debugfs_deinit(display);
debug_error:
mutex_unlock(&display->display_lock);
@@ -1758,6 +1798,7 @@ static void sde_hdmi_unbind(struct device *dev, struct device *master,
mutex_lock(&display->display_lock);
(void)_sde_hdmi_debugfs_deinit(display);
(void)sde_edid_deinit((void **)&display->edid_ctrl);
+ (void)_sde_hdmi_cec_deinit(display);
display->drm_dev = NULL;
mutex_unlock(&display->display_lock);
}
diff --git a/drivers/gpu/drm/msm/hdmi-staging/sde_hdmi.h b/drivers/gpu/drm/msm/hdmi-staging/sde_hdmi.h
index 54506da4f9b0..dff245dec764 100644
--- a/drivers/gpu/drm/msm/hdmi-staging/sde_hdmi.h
+++ b/drivers/gpu/drm/msm/hdmi-staging/sde_hdmi.h
@@ -23,6 +23,7 @@
#include <drm/drmP.h>
#include <drm/drm_crtc.h>
+#include <media/cec-notifier.h>
#include "hdmi.h"
#include "sde_edid_parser.h"
@@ -87,6 +88,7 @@ struct sde_hdmi_ctrl {
* @codec_ready: If audio codec is ready.
* @client_notify_pending: If there is client notification pending.
* @irq_domain: IRQ domain structure.
+ * @notifier: CEC notifider to convey physical address information.
* @root: Debug fs root entry.
*/
struct sde_hdmi {
@@ -116,6 +118,7 @@ struct sde_hdmi {
bool client_notify_pending;
struct irq_domain *irq_domain;
+ struct cec_notifier *notifier;
/* DEBUG FS */
struct dentry *root;
diff --git a/drivers/gpu/drm/msm/hdmi-staging/sde_hdmi_bridge.c b/drivers/gpu/drm/msm/hdmi-staging/sde_hdmi_bridge.c
index 34268aaedfc0..26a0638f7792 100644
--- a/drivers/gpu/drm/msm/hdmi-staging/sde_hdmi_bridge.c
+++ b/drivers/gpu/drm/msm/hdmi-staging/sde_hdmi_bridge.c
@@ -328,7 +328,6 @@ static int _sde_hdmi_bridge_setup_scrambler(struct hdmi *hdmi,
}
reg_val = hdmi_read(hdmi, REG_HDMI_CTRL);
- reg_val |= BIT(31); /* Enable Update DATAPATH_MODE */
reg_val |= BIT(28); /* Set SCRAMBLER_EN bit */
hdmi_write(hdmi, REG_HDMI_CTRL, reg_val);
@@ -360,7 +359,6 @@ static int _sde_hdmi_bridge_setup_scrambler(struct hdmi *hdmi,
} else {
sde_hdmi_scdc_write(hdmi, HDMI_TX_SCDC_SCRAMBLING_ENABLE, 0x0);
reg_val = hdmi_read(hdmi, REG_HDMI_CTRL);
- reg_val &= ~BIT(31); /* Disable Update DATAPATH_MODE */
reg_val &= ~BIT(28); /* Unset SCRAMBLER_EN bit */
hdmi_write(hdmi, REG_HDMI_CTRL, reg_val);
}
diff --git a/drivers/gpu/drm/msm/msm_drv.c b/drivers/gpu/drm/msm/msm_drv.c
index b9503564cdd6..74f298d7328d 100644
--- a/drivers/gpu/drm/msm/msm_drv.c
+++ b/drivers/gpu/drm/msm/msm_drv.c
@@ -391,6 +391,8 @@ static int msm_load(struct drm_device *dev, unsigned long flags)
INIT_LIST_HEAD(&priv->vblank_ctrl.event_list);
init_kthread_work(&priv->vblank_ctrl.work, vblank_ctrl_worker);
spin_lock_init(&priv->vblank_ctrl.lock);
+ hash_init(priv->mn_hash);
+ mutex_init(&priv->mn_lock);
drm_mode_config_init(dev);
@@ -559,7 +561,8 @@ static struct msm_file_private *setup_pagetable(struct msm_drm_private *priv)
return ERR_PTR(-ENOMEM);
ctx->aspace = msm_gem_address_space_create_instance(
- priv->gpu->aspace->mmu, "gpu", 0x100000000, 0x1ffffffff);
+ priv->gpu->aspace->mmu, "gpu", 0x100000000ULL,
+ TASK_SIZE_64 - 1);
if (IS_ERR(ctx->aspace)) {
int ret = PTR_ERR(ctx->aspace);
@@ -1141,6 +1144,20 @@ static int msm_ioctl_gem_new(struct drm_device *dev, void *data,
args->flags, &args->handle);
}
+static int msm_ioctl_gem_svm_new(struct drm_device *dev, void *data,
+ struct drm_file *file)
+{
+ struct drm_msm_gem_svm_new *args = data;
+
+ if (args->flags & ~MSM_BO_FLAGS) {
+ DRM_ERROR("invalid flags: %08x\n", args->flags);
+ return -EINVAL;
+ }
+
+ return msm_gem_svm_new_handle(dev, file, args->hostptr, args->size,
+ args->flags, &args->handle);
+}
+
static inline ktime_t to_ktime(struct drm_msm_timespec timeout)
{
return ktime_set(timeout.tv_sec, timeout.tv_nsec);
@@ -1193,6 +1210,7 @@ static int msm_ioctl_gem_info(struct drm_device *dev, void *data,
{
struct drm_msm_gem_info *args = data;
struct drm_gem_object *obj;
+ struct msm_gem_object *msm_obj;
struct msm_file_private *ctx = file->driver_priv;
int ret = 0;
@@ -1203,10 +1221,10 @@ static int msm_ioctl_gem_info(struct drm_device *dev, void *data,
if (!obj)
return -ENOENT;
+ msm_obj = to_msm_bo(obj);
if (args->flags & MSM_INFO_IOVA) {
struct msm_gem_address_space *aspace = NULL;
struct msm_drm_private *priv = dev->dev_private;
- struct msm_gem_object *msm_obj = to_msm_bo(obj);
uint64_t iova;
if (msm_obj->flags & MSM_BO_SECURE && priv->gpu)
@@ -1223,6 +1241,14 @@ static int msm_ioctl_gem_info(struct drm_device *dev, void *data,
if (!ret)
args->offset = iova;
} else {
+ if (msm_obj->flags & MSM_BO_SVM) {
+ /*
+ * Offset for an SVM object is not needed as they are
+ * already mmap'ed before the SVM ioctl is invoked.
+ */
+ ret = -EACCES;
+ goto out;
+ }
args->offset = msm_gem_mmap_offset(obj);
}
@@ -1700,6 +1726,8 @@ static const struct drm_ioctl_desc msm_ioctls[] = {
DRM_AUTH|DRM_RENDER_ALLOW),
DRM_IOCTL_DEF_DRV(MSM_GEM_SYNC, msm_ioctl_gem_sync,
DRM_AUTH|DRM_RENDER_ALLOW),
+ DRM_IOCTL_DEF_DRV(MSM_GEM_SVM_NEW, msm_ioctl_gem_svm_new,
+ DRM_AUTH|DRM_RENDER_ALLOW),
};
static const struct vm_operations_struct vm_ops = {
diff --git a/drivers/gpu/drm/msm/msm_drv.h b/drivers/gpu/drm/msm/msm_drv.h
index 54a3568ca11f..4083e990b2c8 100644
--- a/drivers/gpu/drm/msm/msm_drv.h
+++ b/drivers/gpu/drm/msm/msm_drv.h
@@ -34,6 +34,7 @@
#include <linux/of_graph.h>
#include <linux/of_device.h>
#include <linux/sde_io_util.h>
+#include <linux/hashtable.h>
#include <asm/sizes.h>
#include <linux/kthread.h>
@@ -325,6 +326,11 @@ struct msm_drm_private {
unsigned int num_connectors;
struct drm_connector *connectors[MAX_CONNECTORS];
+ /* hash to store mm_struct to msm_mmu_notifier mappings */
+ DECLARE_HASHTABLE(mn_hash, 7);
+ /* protects mn_hash and the msm_mmu_notifier for the process */
+ struct mutex mn_lock;
+
/* Properties */
struct drm_property *plane_property[PLANE_PROP_COUNT];
struct drm_property *crtc_property[CRTC_PROP_COUNT];
@@ -404,10 +410,15 @@ void msm_update_fence(struct drm_device *dev, uint32_t fence);
void msm_gem_unmap_vma(struct msm_gem_address_space *aspace,
struct msm_gem_vma *vma, struct sg_table *sgt,
- void *priv);
+ void *priv, bool invalidated);
int msm_gem_map_vma(struct msm_gem_address_space *aspace,
struct msm_gem_vma *vma, struct sg_table *sgt,
void *priv, unsigned int flags);
+int msm_gem_reserve_iova(struct msm_gem_address_space *aspace,
+ struct msm_gem_vma *domain,
+ uint64_t hostptr, uint64_t size);
+void msm_gem_release_iova(struct msm_gem_address_space *aspace,
+ struct msm_gem_vma *vma);
void msm_gem_address_space_put(struct msm_gem_address_space *aspace);
@@ -471,6 +482,12 @@ struct drm_gem_object *msm_gem_new_locked(struct drm_device *dev,
struct drm_gem_object *msm_gem_import(struct drm_device *dev,
uint32_t size, struct sg_table *sgt, u32 flags);
void msm_gem_sync(struct drm_gem_object *obj, u32 op);
+int msm_gem_svm_new_handle(struct drm_device *dev, struct drm_file *file,
+ uint64_t hostptr, uint64_t size,
+ uint32_t flags, uint32_t *handle);
+struct drm_gem_object *msm_gem_svm_new(struct drm_device *dev,
+ struct drm_file *file, uint64_t hostptr,
+ uint64_t size, uint32_t flags);
int msm_framebuffer_prepare(struct drm_framebuffer *fb,
struct msm_gem_address_space *aspace);
diff --git a/drivers/gpu/drm/msm/msm_gem.c b/drivers/gpu/drm/msm/msm_gem.c
index 4b1a586d474d..6bb29c62378d 100644
--- a/drivers/gpu/drm/msm/msm_gem.c
+++ b/drivers/gpu/drm/msm/msm_gem.c
@@ -25,6 +25,129 @@
#include "msm_gpu.h"
#include "msm_mmu.h"
+static void msm_gem_mn_free(struct kref *refcount)
+{
+ struct msm_mmu_notifier *msm_mn = container_of(refcount,
+ struct msm_mmu_notifier, refcount);
+
+ mmu_notifier_unregister(&msm_mn->mn, msm_mn->mm);
+ hash_del(&msm_mn->node);
+
+ kfree(msm_mn);
+}
+
+static int msm_gem_mn_get(struct msm_mmu_notifier *msm_mn)
+{
+ if (msm_mn)
+ return kref_get_unless_zero(&msm_mn->refcount);
+ return 0;
+}
+
+static void msm_gem_mn_put(struct msm_mmu_notifier *msm_mn)
+{
+ if (msm_mn) {
+ struct msm_drm_private *msm_dev = msm_mn->msm_dev;
+
+ mutex_lock(&msm_dev->mn_lock);
+ kref_put(&msm_mn->refcount, msm_gem_mn_free);
+ mutex_unlock(&msm_dev->mn_lock);
+ }
+}
+
+void msm_mn_invalidate_range_start(struct mmu_notifier *mn,
+ struct mm_struct *mm, unsigned long start, unsigned long end);
+
+static const struct mmu_notifier_ops msm_mn_ops = {
+ .invalidate_range_start = msm_mn_invalidate_range_start,
+};
+
+static struct msm_mmu_notifier *
+msm_gem_mn_find(struct msm_drm_private *msm_dev, struct mm_struct *mm,
+ struct msm_gem_address_space *aspace)
+{
+ struct msm_mmu_notifier *msm_mn;
+ int ret = 0;
+
+ mutex_lock(&msm_dev->mn_lock);
+ hash_for_each_possible(msm_dev->mn_hash, msm_mn, node,
+ (unsigned long) mm) {
+ if (msm_mn->mm == mm) {
+ if (!msm_gem_mn_get(msm_mn)) {
+ ret = -EINVAL;
+ goto fail;
+ }
+ mutex_unlock(&msm_dev->mn_lock);
+ return msm_mn;
+ }
+ }
+
+ msm_mn = kzalloc(sizeof(*msm_mn), GFP_KERNEL);
+ if (!msm_mn) {
+ ret = -ENOMEM;
+ goto fail;
+ }
+
+ msm_mn->mm = current->mm;
+ msm_mn->mn.ops = &msm_mn_ops;
+ ret = mmu_notifier_register(&msm_mn->mn, msm_mn->mm);
+ if (ret) {
+ kfree(msm_mn);
+ goto fail;
+ }
+
+ msm_mn->svm_tree = RB_ROOT;
+ spin_lock_init(&msm_mn->svm_tree_lock);
+ kref_init(&msm_mn->refcount);
+ msm_mn->msm_dev = msm_dev;
+
+ /* Insert the msm_mn into the hash */
+ hash_add(msm_dev->mn_hash, &msm_mn->node, (unsigned long) msm_mn->mm);
+ mutex_unlock(&msm_dev->mn_lock);
+
+ return msm_mn;
+
+fail:
+ mutex_unlock(&msm_dev->mn_lock);
+ return ERR_PTR(ret);
+}
+
+static int msm_gem_mn_register(struct msm_gem_svm_object *msm_svm_obj,
+ struct msm_gem_address_space *aspace)
+{
+ struct drm_gem_object *obj = &msm_svm_obj->msm_obj_base.base;
+ struct msm_drm_private *msm_dev = obj->dev->dev_private;
+ struct msm_mmu_notifier *msm_mn;
+
+ msm_svm_obj->mm = current->mm;
+ msm_svm_obj->svm_node.start = msm_svm_obj->hostptr;
+ msm_svm_obj->svm_node.last = msm_svm_obj->hostptr + obj->size - 1;
+
+ msm_mn = msm_gem_mn_find(msm_dev, msm_svm_obj->mm, aspace);
+ if (IS_ERR(msm_mn))
+ return PTR_ERR(msm_mn);
+
+ msm_svm_obj->msm_mn = msm_mn;
+
+ spin_lock(&msm_mn->svm_tree_lock);
+ interval_tree_insert(&msm_svm_obj->svm_node, &msm_mn->svm_tree);
+ spin_unlock(&msm_mn->svm_tree_lock);
+
+ return 0;
+}
+
+static void msm_gem_mn_unregister(struct msm_gem_svm_object *msm_svm_obj)
+{
+ struct msm_mmu_notifier *msm_mn = msm_svm_obj->msm_mn;
+
+ /* invalid: bo already unregistered */
+ if (!msm_mn || msm_svm_obj->invalid)
+ return;
+
+ spin_lock(&msm_mn->svm_tree_lock);
+ interval_tree_remove(&msm_svm_obj->svm_node, &msm_mn->svm_tree);
+ spin_unlock(&msm_mn->svm_tree_lock);
+}
+
static int protect_pages(struct msm_gem_object *msm_obj)
{
int perm = PERM_READ | PERM_WRITE;
@@ -175,10 +298,19 @@ static void put_pages(struct drm_gem_object *obj)
sg_free_table(msm_obj->sgt);
kfree(msm_obj->sgt);
- if (use_pages(obj))
- drm_gem_put_pages(obj, msm_obj->pages, true, false);
- else
+ if (use_pages(obj)) {
+ if (msm_obj->flags & MSM_BO_SVM) {
+ int npages = obj->size >> PAGE_SHIFT;
+
+ release_pages(msm_obj->pages, npages, 0);
+ kfree(msm_obj->pages);
+ } else {
+ drm_gem_put_pages(obj, msm_obj->pages,
+ true, false);
+ }
+ } else {
put_pages_vram(obj);
+ }
msm_obj->pages = NULL;
}
@@ -205,8 +337,8 @@ int msm_gem_mmap_obj(struct drm_gem_object *obj,
{
struct msm_gem_object *msm_obj = to_msm_bo(obj);
- /* We can't mmap secure objects */
- if (msm_obj->flags & MSM_BO_SECURE) {
+ /* We can't mmap secure objects or SVM objects */
+ if (msm_obj->flags & (MSM_BO_SECURE | MSM_BO_SVM)) {
drm_gem_vm_close(vma);
return -EACCES;
}
@@ -348,14 +480,21 @@ static void
put_iova(struct drm_gem_object *obj)
{
struct msm_gem_object *msm_obj = to_msm_bo(obj);
+ struct msm_gem_svm_object *msm_svm_obj;
struct msm_gem_vma *domain, *tmp;
+ bool invalid = false;
WARN_ON(!mutex_is_locked(&msm_obj->lock));
+ if (msm_obj->flags & MSM_BO_SVM) {
+ msm_svm_obj = to_msm_svm_obj(msm_obj);
+ invalid = msm_svm_obj->invalid;
+ }
+
list_for_each_entry_safe(domain, tmp, &msm_obj->domains, list) {
if (iommu_present(&platform_bus_type)) {
msm_gem_unmap_vma(domain->aspace, domain,
- msm_obj->sgt, get_dmabuf_ptr(obj));
+ msm_obj->sgt, get_dmabuf_ptr(obj), invalid);
}
obj_remove_domain(domain);
@@ -658,15 +797,26 @@ void msm_gem_free_object(struct drm_gem_object *obj)
{
struct drm_device *dev = obj->dev;
struct msm_gem_object *msm_obj = to_msm_bo(obj);
+ struct msm_gem_svm_object *msm_svm_obj = NULL;
WARN_ON(!mutex_is_locked(&dev->struct_mutex));
/* object should not be on active list: */
WARN_ON(is_active(msm_obj));
+
+ if (msm_obj->flags & MSM_BO_SVM)
+ msm_svm_obj = to_msm_svm_obj(msm_obj);
+
list_del(&msm_obj->mm_list);
- mutex_lock(&msm_obj->lock);
+ /* Unregister SVM object from mmu notifications */
+ if (msm_obj->flags & MSM_BO_SVM) {
+ msm_gem_mn_unregister(msm_svm_obj);
+ msm_gem_mn_put(msm_svm_obj->msm_mn);
+ msm_svm_obj->msm_mn = NULL;
+ }
+ mutex_lock(&msm_obj->lock);
put_iova(obj);
if (obj->import_attach) {
@@ -691,7 +841,10 @@ void msm_gem_free_object(struct drm_gem_object *obj)
drm_gem_object_release(obj);
mutex_unlock(&msm_obj->lock);
- kfree(msm_obj);
+ if (msm_obj->flags & MSM_BO_SVM)
+ kfree(msm_svm_obj);
+ else
+ kfree(msm_obj);
}
/* convenience method to construct a GEM buffer object, and userspace handle */
@@ -714,26 +867,32 @@ int msm_gem_new_handle(struct drm_device *dev, struct drm_file *file,
return ret;
}
-static inline void msm_gem_add_to_inactive_list(struct msm_gem_object *msm_obj,
- struct drm_device *dev, bool struct_mutex_locked)
+/* convenience method to construct an SVM buffer object, and userspace handle */
+int msm_gem_svm_new_handle(struct drm_device *dev, struct drm_file *file,
+ uint64_t hostptr, uint64_t size,
+ uint32_t flags, uint32_t *handle)
{
- struct msm_drm_private *priv = dev->dev_private;
+ struct drm_gem_object *obj;
+ int ret;
- if (struct_mutex_locked) {
- list_add_tail(&msm_obj->mm_list, &priv->inactive_list);
- } else {
- mutex_lock(&dev->struct_mutex);
- list_add_tail(&msm_obj->mm_list, &priv->inactive_list);
- mutex_unlock(&dev->struct_mutex);
- }
+ obj = msm_gem_svm_new(dev, file, hostptr, size, flags);
+
+ if (IS_ERR(obj))
+ return PTR_ERR(obj);
+
+ ret = drm_gem_handle_create(file, obj, handle);
+
+ /* drop reference from allocate - handle holds it now */
+ drm_gem_object_unreference_unlocked(obj);
+
+ return ret;
}
-static int msm_gem_new_impl(struct drm_device *dev,
- uint32_t size, uint32_t flags, struct drm_gem_object **obj,
- bool struct_mutex_locked)
+static int msm_gem_obj_init(struct drm_device *dev,
+ uint32_t size, uint32_t flags,
+ struct msm_gem_object *msm_obj, bool struct_mutex_locked)
{
struct msm_drm_private *priv = dev->dev_private;
- struct msm_gem_object *msm_obj;
bool use_vram = false;
switch (flags & MSM_BO_CACHE_MASK) {
@@ -755,10 +914,6 @@ static int msm_gem_new_impl(struct drm_device *dev,
if (WARN_ON(use_vram && !priv->vram.size))
return -EINVAL;
- msm_obj = kzalloc(sizeof(*msm_obj), GFP_KERNEL);
- if (!msm_obj)
- return -ENOMEM;
-
mutex_init(&msm_obj->lock);
if (use_vram) {
@@ -773,20 +928,44 @@ static int msm_gem_new_impl(struct drm_device *dev,
msm_obj->resv = &msm_obj->_resv;
reservation_object_init(msm_obj->resv);
+ INIT_LIST_HEAD(&msm_obj->mm_list);
INIT_LIST_HEAD(&msm_obj->submit_entry);
INIT_LIST_HEAD(&msm_obj->domains);
- msm_gem_add_to_inactive_list(msm_obj, dev, struct_mutex_locked);
-
- *obj = &msm_obj->base;
+ if (struct_mutex_locked) {
+ list_add_tail(&msm_obj->mm_list, &priv->inactive_list);
+ } else {
+ mutex_lock(&dev->struct_mutex);
+ list_add_tail(&msm_obj->mm_list, &priv->inactive_list);
+ mutex_unlock(&dev->struct_mutex);
+ }
return 0;
}
+static struct drm_gem_object *msm_gem_new_impl(struct drm_device *dev,
+ uint32_t size, uint32_t flags, bool struct_mutex_locked)
+{
+ struct msm_gem_object *msm_obj;
+ int ret;
+
+ msm_obj = kzalloc(sizeof(*msm_obj), GFP_KERNEL);
+ if (!msm_obj)
+ return ERR_PTR(-ENOMEM);
+
+ ret = msm_gem_obj_init(dev, size, flags, msm_obj, struct_mutex_locked);
+ if (ret) {
+ kfree(msm_obj);
+ return ERR_PTR(ret);
+ }
+
+ return &msm_obj->base;
+}
+
static struct drm_gem_object *_msm_gem_new(struct drm_device *dev,
uint32_t size, uint32_t flags, bool struct_mutex_locked)
{
- struct drm_gem_object *obj = NULL;
+ struct drm_gem_object *obj;
int ret;
size = PAGE_ALIGN(size);
@@ -798,9 +977,9 @@ static struct drm_gem_object *_msm_gem_new(struct drm_device *dev,
if (!size)
return ERR_PTR(-EINVAL);
- ret = msm_gem_new_impl(dev, size, flags, &obj, struct_mutex_locked);
- if (ret)
- goto fail;
+ obj = msm_gem_new_impl(dev, size, flags, struct_mutex_locked);
+ if (IS_ERR(obj))
+ return obj;
if (use_pages(obj)) {
ret = drm_gem_object_init(dev, obj, size);
@@ -813,8 +992,7 @@ static struct drm_gem_object *_msm_gem_new(struct drm_device *dev,
return obj;
fail:
- if (obj)
- drm_gem_object_unreference_unlocked(obj);
+ drm_gem_object_unreference_unlocked(obj);
return ERR_PTR(ret);
}
@@ -831,6 +1009,143 @@ struct drm_gem_object *msm_gem_new(struct drm_device *dev,
return _msm_gem_new(dev, size, flags, false);
}
+static struct drm_gem_object *msm_svm_gem_new_impl(struct drm_device *dev,
+ uint32_t size, uint32_t flags)
+{
+ struct msm_gem_svm_object *msm_svm_obj;
+ struct msm_gem_object *msm_obj;
+ int ret;
+
+ msm_svm_obj = kzalloc(sizeof(*msm_svm_obj), GFP_KERNEL);
+ if (!msm_svm_obj)
+ return ERR_PTR(-ENOMEM);
+
+ msm_obj = &msm_svm_obj->msm_obj_base;
+
+ ret = msm_gem_obj_init(dev, size, flags | MSM_BO_SVM, msm_obj, false);
+ if (ret) {
+ kfree(msm_svm_obj);
+ return ERR_PTR(ret);
+ }
+
+ return &msm_obj->base;
+}
+
+/* convenience method to construct an SVM GEM bo, and userspace handle */
+struct drm_gem_object *msm_gem_svm_new(struct drm_device *dev,
+ struct drm_file *file, uint64_t hostptr,
+ uint64_t size, uint32_t flags)
+{
+ struct drm_gem_object *obj;
+ struct msm_file_private *ctx = file->driver_priv;
+ struct msm_gem_address_space *aspace = ctx->aspace;
+ struct msm_gem_object *msm_obj;
+ struct msm_gem_svm_object *msm_svm_obj;
+ struct msm_gem_vma *domain = NULL;
+ struct page **p;
+ int npages;
+ int num_pinned = 0;
+ int write;
+ int ret;
+
+ /* if we don't have IOMMU, don't bother pretending we can import: */
+ if (!iommu_present(&platform_bus_type)) {
+ dev_err_once(dev->dev, "cannot import without IOMMU\n");
+ return ERR_PTR(-EINVAL);
+ }
+
+ /* hostptr and size must be page-aligned */
+ if (offset_in_page(hostptr | size))
+ return ERR_PTR(-EINVAL);
+
+ /* Only CPU cached SVM objects are allowed */
+ if ((flags & MSM_BO_CACHE_MASK) != MSM_BO_CACHED)
+ return ERR_PTR(-EINVAL);
+
+ /* Allocate and initialize a new msm_gem_object */
+ obj = msm_svm_gem_new_impl(dev, size, flags);
+ if (IS_ERR(obj))
+ return obj;
+
+ drm_gem_private_object_init(dev, obj, size);
+
+ msm_obj = to_msm_bo(obj);
+ domain = obj_add_domain(&msm_obj->base, aspace);
+ if (IS_ERR(domain)) {
+ drm_gem_object_unreference_unlocked(obj);
+ return ERR_CAST(domain);
+ }
+
+ /* Reserve iova if not already in use, else fail */
+ ret = msm_gem_reserve_iova(aspace, domain, hostptr, size);
+ if (ret) {
+ obj_remove_domain(domain);
+ drm_gem_object_unreference_unlocked(obj);
+ return ERR_PTR(ret);
+ }
+
+ msm_svm_obj = to_msm_svm_obj(msm_obj);
+ msm_svm_obj->hostptr = hostptr;
+ msm_svm_obj->invalid = false;
+
+ ret = msm_gem_mn_register(msm_svm_obj, aspace);
+ if (ret)
+ goto fail;
+
+ /*
+ * Get physical pages and map into smmu in the ioctl itself.
+ * The driver handles iova allocation, physical page allocation and
+ * SMMU map all in one go. If we break this, then we have to maintain
+ * state to tell if physical pages allocation/map needs to happen.
+ * For SVM, iova reservation needs to happen in the ioctl itself,
+ * so do the rest right here as well.
+ */
+ npages = size >> PAGE_SHIFT;
+ p = kcalloc(npages, sizeof(struct page *), GFP_KERNEL);
+ if (!p) {
+ ret = -ENOMEM;
+ goto fail;
+ }
+
+ write = (msm_obj->flags & MSM_BO_GPU_READONLY) ? 0 : 1;
+ /* This may hold mm->mmap_sem */
+ num_pinned = get_user_pages_fast(hostptr, npages, write, p);
+ if (num_pinned != npages) {
+ ret = -EINVAL;
+ goto free_pages;
+ }
+
+ msm_obj->sgt = drm_prime_pages_to_sg(p, npages);
+ if (IS_ERR(msm_obj->sgt)) {
+ ret = PTR_ERR(msm_obj->sgt);
+ goto free_pages;
+ }
+
+ msm_obj->pages = p;
+
+ ret = aspace->mmu->funcs->map(aspace->mmu, domain->iova,
+ msm_obj->sgt, msm_obj->flags, get_dmabuf_ptr(obj));
+ if (ret)
+ goto free_pages;
+
+ kref_get(&aspace->kref);
+
+ return obj;
+
+free_pages:
+ release_pages(p, num_pinned, 0);
+ kfree(p);
+
+fail:
+ if (domain)
+ msm_gem_release_iova(aspace, domain);
+
+ obj_remove_domain(domain);
+ drm_gem_object_unreference_unlocked(obj);
+
+ return ERR_PTR(ret);
+}
+
struct drm_gem_object *msm_gem_import(struct drm_device *dev,
uint32_t size, struct sg_table *sgt, u32 flags)
{
@@ -846,10 +1161,9 @@ struct drm_gem_object *msm_gem_import(struct drm_device *dev,
size = PAGE_ALIGN(size);
- ret = msm_gem_new_impl(dev, size, MSM_BO_WC, &obj, false);
-
- if (ret)
- goto fail;
+ obj = msm_gem_new_impl(dev, size, MSM_BO_WC, false);
+ if (IS_ERR(obj))
+ return obj;
drm_gem_private_object_init(dev, obj, size);
@@ -868,7 +1182,8 @@ struct drm_gem_object *msm_gem_import(struct drm_device *dev,
/* OR the passed in flags */
msm_obj->flags |= flags;
- ret = drm_prime_sg_to_page_addr_arrays(sgt, msm_obj->pages, NULL, npages);
+ ret = drm_prime_sg_to_page_addr_arrays(sgt, msm_obj->pages,
+ NULL, npages);
if (ret) {
mutex_unlock(&msm_obj->lock);
goto fail;
@@ -879,8 +1194,86 @@ struct drm_gem_object *msm_gem_import(struct drm_device *dev,
return obj;
fail:
- if (obj)
- drm_gem_object_unreference_unlocked(obj);
+ drm_gem_object_unreference_unlocked(obj);
return ERR_PTR(ret);
}
+
+/* Timeout in ms, long enough so we are sure the GPU is hung */
+#define SVM_OBJ_WAIT_TIMEOUT 10000
+static void invalidate_svm_object(struct msm_gem_svm_object *msm_svm_obj)
+{
+ struct msm_gem_object *msm_obj = &msm_svm_obj->msm_obj_base;
+ struct drm_device *dev = msm_obj->base.dev;
+ struct msm_gem_vma *domain, *tmp;
+ uint32_t fence;
+ int ret;
+
+ if (is_active(msm_obj)) {
+ ktime_t timeout = ktime_add_ms(ktime_get(),
+ SVM_OBJ_WAIT_TIMEOUT);
+
+ /* Get the most recent fence that touches the object */
+ fence = msm_gem_fence(msm_obj, MSM_PREP_READ | MSM_PREP_WRITE);
+
+ /* Wait for the fence to retire */
+ ret = msm_wait_fence(dev, fence, &timeout, true);
+ if (ret)
+ /* The GPU could be hung! Not much we can do */
+ dev_err(dev->dev, "drm: Error (%d) waiting for svm object: 0x%llx",
+ ret, msm_svm_obj->hostptr);
+ }
+
+ /* GPU is done, unmap object from SMMU */
+ mutex_lock(&msm_obj->lock);
+ list_for_each_entry_safe(domain, tmp, &msm_obj->domains, list) {
+ struct msm_gem_address_space *aspace = domain->aspace;
+
+ if (domain->iova)
+ aspace->mmu->funcs->unmap(aspace->mmu,
+ domain->iova, msm_obj->sgt,
+ get_dmabuf_ptr(&msm_obj->base));
+ }
+ /* Let go of the physical pages */
+ put_pages(&msm_obj->base);
+ mutex_unlock(&msm_obj->lock);
+}
+
+void msm_mn_invalidate_range_start(struct mmu_notifier *mn,
+ struct mm_struct *mm, unsigned long start, unsigned long end)
+{
+ struct msm_mmu_notifier *msm_mn =
+ container_of(mn, struct msm_mmu_notifier, mn);
+ struct interval_tree_node *itn = NULL;
+ struct msm_gem_svm_object *msm_svm_obj;
+ struct drm_gem_object *obj;
+ LIST_HEAD(inv_list);
+
+ if (!msm_gem_mn_get(msm_mn))
+ return;
+
+ spin_lock(&msm_mn->svm_tree_lock);
+ itn = interval_tree_iter_first(&msm_mn->svm_tree, start, end - 1);
+ while (itn) {
+ msm_svm_obj = container_of(itn,
+ struct msm_gem_svm_object, svm_node);
+ obj = &msm_svm_obj->msm_obj_base.base;
+
+ if (kref_get_unless_zero(&obj->refcount))
+ list_add(&msm_svm_obj->lnode, &inv_list);
+
+ itn = interval_tree_iter_next(itn, start, end - 1);
+ }
+ spin_unlock(&msm_mn->svm_tree_lock);
+
+ list_for_each_entry(msm_svm_obj, &inv_list, lnode) {
+ obj = &msm_svm_obj->msm_obj_base.base;
+ /* Unregister SVM object from mmu notifications */
+ msm_gem_mn_unregister(msm_svm_obj);
+ msm_svm_obj->invalid = true;
+ invalidate_svm_object(msm_svm_obj);
+ drm_gem_object_unreference_unlocked(obj);
+ }
+
+ msm_gem_mn_put(msm_mn);
+}
diff --git a/drivers/gpu/drm/msm/msm_gem.h b/drivers/gpu/drm/msm/msm_gem.h
index eb850952f1f5..04e6c658b5f3 100644
--- a/drivers/gpu/drm/msm/msm_gem.h
+++ b/drivers/gpu/drm/msm/msm_gem.h
@@ -20,11 +20,14 @@
#include <linux/kref.h>
#include <linux/reservation.h>
+#include <linux/mmu_notifier.h>
+#include <linux/interval_tree.h>
#include "msm_drv.h"
/* Additional internal-use only BO flags: */
#define MSM_BO_STOLEN 0x10000000 /* try to use stolen/splash memory */
#define MSM_BO_LOCKED 0x20000000 /* Pages have been securely locked */
+#define MSM_BO_SVM 0x40000000 /* bo is SVM */
struct msm_gem_address_space {
const char *name;
@@ -85,6 +88,32 @@ struct msm_gem_object {
};
#define to_msm_bo(x) container_of(x, struct msm_gem_object, base)
+struct msm_mmu_notifier {
+ struct mmu_notifier mn;
+ struct mm_struct *mm; /* mm_struct owning the mmu notifier mn */
+ struct hlist_node node;
+ struct rb_root svm_tree; /* interval tree holding all svm bos */
+ spinlock_t svm_tree_lock; /* Protects svm_tree*/
+ struct msm_drm_private *msm_dev;
+ struct kref refcount;
+};
+
+struct msm_gem_svm_object {
+ struct msm_gem_object msm_obj_base;
+ uint64_t hostptr;
+ struct mm_struct *mm; /* mm_struct the svm bo belongs to */
+ struct interval_tree_node svm_node;
+ struct msm_mmu_notifier *msm_mn;
+ struct list_head lnode;
+ /* bo has been unmapped on CPU, cannot be part of GPU submits */
+ bool invalid;
+};
+
+#define to_msm_svm_obj(x) \
+ ((struct msm_gem_svm_object *) \
+ container_of(x, struct msm_gem_svm_object, msm_obj_base))
+
+
static inline bool is_active(struct msm_gem_object *msm_obj)
{
return msm_obj->gpu != NULL;
diff --git a/drivers/gpu/drm/msm/msm_gem_submit.c b/drivers/gpu/drm/msm/msm_gem_submit.c
index c9b3151180dc..c861bfd77537 100644
--- a/drivers/gpu/drm/msm/msm_gem_submit.c
+++ b/drivers/gpu/drm/msm/msm_gem_submit.c
@@ -217,6 +217,18 @@ retry:
submit->bos[i].flags |= BO_LOCKED;
}
+ /*
+ * An invalid SVM object is part of
+ * this submit's buffer list, fail.
+ */
+ if (msm_obj->flags & MSM_BO_SVM) {
+ struct msm_gem_svm_object *msm_svm_obj =
+ to_msm_svm_obj(msm_obj);
+ if (msm_svm_obj->invalid) {
+ ret = -EINVAL;
+ goto fail;
+ }
+ }
/* if locking succeeded, pin bo: */
ret = msm_gem_get_iova(&msm_obj->base, aspace, &iova);
diff --git a/drivers/gpu/drm/msm/msm_gem_vma.c b/drivers/gpu/drm/msm/msm_gem_vma.c
index 12e3c0f7c101..f399d24019e4 100644
--- a/drivers/gpu/drm/msm/msm_gem_vma.c
+++ b/drivers/gpu/drm/msm/msm_gem_vma.c
@@ -88,7 +88,7 @@ static int allocate_iova(struct msm_gem_address_space *aspace,
return 0;
}
ret = drm_mm_insert_node(&aspace->mm, &vma->node,
- size >> PAGE_SHIFT, 0, DRM_MM_SEARCH_DEFAULT);
+ size >> PAGE_SHIFT, 0, DRM_MM_SEARCH_BOTTOM_UP);
spin_unlock(&aspace->lock);
@@ -98,6 +98,45 @@ static int allocate_iova(struct msm_gem_address_space *aspace,
return ret;
}
+int msm_gem_reserve_iova(struct msm_gem_address_space *aspace,
+ struct msm_gem_vma *vma,
+ uint64_t hostptr, uint64_t size)
+{
+ struct drm_mm *mm = &aspace->mm;
+ uint64_t start = hostptr >> PAGE_SHIFT;
+ uint64_t last = (hostptr + size - 1) >> PAGE_SHIFT;
+ int ret;
+
+ spin_lock(&aspace->lock);
+
+ if (drm_mm_interval_first(mm, start, last)) {
+ /* iova already in use, fail */
+ spin_unlock(&aspace->lock);
+ return -EADDRINUSE;
+ }
+
+ vma->node.start = hostptr >> PAGE_SHIFT;
+ vma->node.size = size >> PAGE_SHIFT;
+ vma->node.color = 0;
+
+ ret = drm_mm_reserve_node(mm, &vma->node);
+ if (!ret)
+ vma->iova = hostptr;
+
+ spin_unlock(&aspace->lock);
+
+ return ret;
+}
+
+void msm_gem_release_iova(struct msm_gem_address_space *aspace,
+ struct msm_gem_vma *vma)
+{
+ spin_lock(&aspace->lock);
+ if (drm_mm_node_allocated(&vma->node))
+ drm_mm_remove_node(&vma->node);
+ spin_unlock(&aspace->lock);
+}
+
int msm_gem_map_vma(struct msm_gem_address_space *aspace,
struct msm_gem_vma *vma, struct sg_table *sgt,
void *priv, unsigned int flags)
@@ -116,11 +155,7 @@ int msm_gem_map_vma(struct msm_gem_address_space *aspace,
flags, priv);
if (ret) {
- spin_lock(&aspace->lock);
- if (drm_mm_node_allocated(&vma->node))
- drm_mm_remove_node(&vma->node);
- spin_unlock(&aspace->lock);
-
+ msm_gem_release_iova(aspace, vma);
return ret;
}
@@ -131,17 +166,16 @@ int msm_gem_map_vma(struct msm_gem_address_space *aspace,
}
void msm_gem_unmap_vma(struct msm_gem_address_space *aspace,
- struct msm_gem_vma *vma, struct sg_table *sgt, void *priv)
+ struct msm_gem_vma *vma, struct sg_table *sgt,
+ void *priv, bool invalidated)
{
if (!aspace || !vma->iova)
return;
- aspace->mmu->funcs->unmap(aspace->mmu, vma->iova, sgt, priv);
+ if (!invalidated)
+ aspace->mmu->funcs->unmap(aspace->mmu, vma->iova, sgt, priv);
- spin_lock(&aspace->lock);
- if (drm_mm_node_allocated(&vma->node))
- drm_mm_remove_node(&vma->node);
- spin_unlock(&aspace->lock);
+ msm_gem_release_iova(aspace, vma);
vma->iova = 0;
diff --git a/drivers/leds/leds-qpnp-flash-v2.c b/drivers/leds/leds-qpnp-flash-v2.c
index a89a92d253ac..564d20079715 100644
--- a/drivers/leds/leds-qpnp-flash-v2.c
+++ b/drivers/leds/leds-qpnp-flash-v2.c
@@ -721,7 +721,8 @@ static int qpnp_flash_led_get_voltage_headroom(struct qpnp_flash_led *led)
#define VIN_FLASH_MIN_UV 3300000LL
static int qpnp_flash_led_calc_max_current(struct qpnp_flash_led *led)
{
- int ocv_uv, rbatt_uohm, ibat_now, voltage_hdrm_mv, rc;
+ int ocv_uv = 0, rbatt_uohm = 0, ibat_now = 0, voltage_hdrm_mv = 0;
+ int rc = 0;
int64_t ibat_flash_ua, avail_flash_ua, avail_flash_power_fw;
int64_t ibat_safe_ua, vin_flash_uv, vph_flash_uv, vph_flash_vdip;
diff --git a/drivers/md/dm-android-verity.c b/drivers/md/dm-android-verity.c
index 7cef735a01a7..4f6086970131 100644
--- a/drivers/md/dm-android-verity.c
+++ b/drivers/md/dm-android-verity.c
@@ -691,7 +691,7 @@ static int android_verity_ctr(struct dm_target *ti, unsigned argc, char **argv)
dev_t uninitialized_var(dev);
struct android_metadata *metadata = NULL;
int err = 0, i, mode;
- char *key_id, *table_ptr, dummy, *target_device,
+ char *key_id = NULL, *table_ptr, dummy, *target_device,
*verity_table_args[VERITY_TABLE_ARGS + 2 + VERITY_TABLE_OPT_FEC_ARGS];
/* One for specifying number of opt args and one for mode */
sector_t data_sectors;
diff --git a/drivers/md/dm.c b/drivers/md/dm.c
index 5d42d8f09421..1a7b11d57256 100644
--- a/drivers/md/dm.c
+++ b/drivers/md/dm.c
@@ -2191,8 +2191,11 @@ static void dm_request_fn(struct request_queue *q)
tio = tio_from_request(rq);
/* Establish tio->ti before queuing work (map_tio_request) */
tio->ti = ti;
- queue_kthread_work(&md->kworker, &tio->work);
+ spin_unlock(q->queue_lock);
+ if (map_request(tio, rq, md) == DM_MAPIO_REQUEUE)
+ dm_requeue_original_request(md, rq);
BUG_ON(!irqs_disabled());
+ spin_lock(q->queue_lock);
}
goto out;
diff --git a/drivers/media/Kconfig b/drivers/media/Kconfig
index 0b219a81e8a2..c1b999c6cff2 100644
--- a/drivers/media/Kconfig
+++ b/drivers/media/Kconfig
@@ -99,6 +99,10 @@ config MEDIA_CEC_DEBUG
config MEDIA_CEC_EDID
bool
+config MEDIA_CEC_NOTIFIER
+ bool
+ select MEDIA_CEC_EDID
+
#
# Media controller
# Selectable only for webcam/grabbers, as other drivers don't use it
diff --git a/drivers/media/Makefile b/drivers/media/Makefile
index ba516dcbc6aa..6c7801919b98 100644
--- a/drivers/media/Makefile
+++ b/drivers/media/Makefile
@@ -10,6 +10,10 @@ ifeq ($(CONFIG_MEDIA_CEC_SUPPORT),y)
obj-$(CONFIG_MEDIA_SUPPORT) += cec/
endif
+ifeq ($(CONFIG_MEDIA_CEC_NOTIFIER),y)
+ obj-$(CONFIG_MEDIA_SUPPORT) += cec-notifier.o
+endif
+
media-objs := media-device.o media-devnode.o media-entity.o
#
diff --git a/drivers/media/cec-notifier.c b/drivers/media/cec-notifier.c
new file mode 100644
index 000000000000..5f5209a73665
--- /dev/null
+++ b/drivers/media/cec-notifier.c
@@ -0,0 +1,129 @@
+/*
+ * cec-notifier.c - notify CEC drivers of physical address changes
+ *
+ * Copyright 2016 Russell King <rmk+kernel@arm.linux.org.uk>
+ * Copyright 2016-2017 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
+ *
+ * This program is free software; you may redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include <linux/export.h>
+#include <linux/string.h>
+#include <linux/slab.h>
+#include <linux/list.h>
+#include <linux/kref.h>
+
+#include <media/cec-notifier.h>
+#include <drm/drm_edid.h>
+
+struct cec_notifier {
+ struct mutex lock;
+ struct list_head head;
+ struct kref kref;
+ struct device *dev;
+ struct cec_adapter *cec_adap;
+ void (*callback)(struct cec_adapter *adap, u16 pa);
+
+ u16 phys_addr;
+};
+
+static LIST_HEAD(cec_notifiers);
+static DEFINE_MUTEX(cec_notifiers_lock);
+
+struct cec_notifier *cec_notifier_get(struct device *dev)
+{
+ struct cec_notifier *n;
+
+ mutex_lock(&cec_notifiers_lock);
+ list_for_each_entry(n, &cec_notifiers, head) {
+ if (n->dev == dev) {
+ kref_get(&n->kref);
+ mutex_unlock(&cec_notifiers_lock);
+ return n;
+ }
+ }
+ n = kzalloc(sizeof(*n), GFP_KERNEL);
+ if (!n)
+ goto unlock;
+ n->dev = dev;
+ n->phys_addr = CEC_PHYS_ADDR_INVALID;
+ mutex_init(&n->lock);
+ kref_init(&n->kref);
+ list_add_tail(&n->head, &cec_notifiers);
+unlock:
+ mutex_unlock(&cec_notifiers_lock);
+ return n;
+}
+EXPORT_SYMBOL_GPL(cec_notifier_get);
+
+static void cec_notifier_release(struct kref *kref)
+{
+ struct cec_notifier *n =
+ container_of(kref, struct cec_notifier, kref);
+
+ list_del(&n->head);
+ kfree(n);
+}
+
+void cec_notifier_put(struct cec_notifier *n)
+{
+ mutex_lock(&cec_notifiers_lock);
+ kref_put(&n->kref, cec_notifier_release);
+ mutex_unlock(&cec_notifiers_lock);
+}
+EXPORT_SYMBOL_GPL(cec_notifier_put);
+
+void cec_notifier_set_phys_addr(struct cec_notifier *n, u16 pa)
+{
+ mutex_lock(&n->lock);
+ n->phys_addr = pa;
+ if (n->callback)
+ n->callback(n->cec_adap, n->phys_addr);
+ mutex_unlock(&n->lock);
+}
+EXPORT_SYMBOL_GPL(cec_notifier_set_phys_addr);
+
+void cec_notifier_set_phys_addr_from_edid(struct cec_notifier *n,
+ const struct edid *edid)
+{
+ u16 pa = CEC_PHYS_ADDR_INVALID;
+
+ if (edid && edid->extensions)
+ pa = cec_get_edid_phys_addr((const u8 *)edid,
+ EDID_LENGTH * (edid->extensions + 1), NULL);
+ cec_notifier_set_phys_addr(n, pa);
+}
+EXPORT_SYMBOL_GPL(cec_notifier_set_phys_addr_from_edid);
+
+void cec_notifier_register(struct cec_notifier *n,
+ struct cec_adapter *adap,
+ void (*callback)(struct cec_adapter *adap, u16 pa))
+{
+ kref_get(&n->kref);
+ mutex_lock(&n->lock);
+ n->cec_adap = adap;
+ n->callback = callback;
+ n->callback(adap, n->phys_addr);
+ mutex_unlock(&n->lock);
+}
+EXPORT_SYMBOL_GPL(cec_notifier_register);
+
+void cec_notifier_unregister(struct cec_notifier *n)
+{
+ mutex_lock(&n->lock);
+ n->callback = NULL;
+ mutex_unlock(&n->lock);
+ cec_notifier_put(n);
+}
+EXPORT_SYMBOL_GPL(cec_notifier_unregister);
diff --git a/drivers/media/cec/cec-core.c b/drivers/media/cec/cec-core.c
index aca3ab83a8a1..61adc28ec8ec 100644
--- a/drivers/media/cec/cec-core.c
+++ b/drivers/media/cec/cec-core.c
@@ -195,6 +195,24 @@ static void cec_devnode_unregister(struct cec_devnode *devnode)
put_device(&devnode->dev);
}
+#ifdef CONFIG_MEDIA_CEC_NOTIFIER
+static void cec_cec_notify(struct cec_adapter *adap, u16 pa)
+{
+ cec_s_phys_addr(adap, pa, false);
+}
+
+void cec_register_cec_notifier(struct cec_adapter *adap,
+ struct cec_notifier *notifier)
+{
+ if (WARN_ON(!adap->devnode.registered))
+ return;
+
+ adap->notifier = notifier;
+ cec_notifier_register(adap->notifier, adap, cec_cec_notify);
+}
+EXPORT_SYMBOL_GPL(cec_register_cec_notifier);
+#endif
+
struct cec_adapter *cec_allocate_adapter(const struct cec_adap_ops *ops,
void *priv, const char *name, u32 caps,
u8 available_las)
@@ -344,6 +362,10 @@ void cec_unregister_adapter(struct cec_adapter *adap)
adap->rc = NULL;
#endif
debugfs_remove_recursive(adap->cec_dir);
+#ifdef CONFIG_MEDIA_CEC_NOTIFIER
+ if (adap->notifier)
+ cec_notifier_unregister(adap->notifier);
+#endif
cec_devnode_unregister(&adap->devnode);
}
EXPORT_SYMBOL_GPL(cec_unregister_adapter);
diff --git a/drivers/media/i2c/adv7481.c b/drivers/media/i2c/adv7481.c
index 359a860fdabb..b382a1d83d92 100644
--- a/drivers/media/i2c/adv7481.c
+++ b/drivers/media/i2c/adv7481.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2014-2015, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2014-2017, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -27,29 +27,68 @@
#include <media/v4l2-ctrls.h>
#include <linux/mutex.h>
#include <linux/delay.h>
+
+#include <linux/platform_device.h>
+#include <linux/of_platform.h>
+#include <linux/of_gpio.h>
+
#include <media/adv7481.h>
#include <media/msm_ba.h>
#include "adv7481_reg.h"
+#include "msm_cci.h"
+#include "msm_camera_i2c.h"
+#include "msm_camera_io_util.h"
+#include "msm_camera_dt_util.h"
+
#define DRIVER_NAME "adv7481"
-#define I2C_RW_DELAY 100
-#define I2C_SW_RST_DELAY 10000
-#define GPIO_HW_DELAY_LOW 100000
-#define GPIO_HW_DELAY_HI 10000
+#define I2C_RW_DELAY 1
+#define I2C_SW_RST_DELAY 5000
+#define GPIO_HW_RST_DELAY_HI 10000
+#define GPIO_HW_RST_DELAY_LOW 10000
#define SDP_MIN_SLEEP 5000
#define SDP_MAX_SLEEP 6000
#define SDP_NUM_TRIES 30
#define LOCK_MIN_SLEEP 5000
#define LOCK_MAX_SLEEP 6000
-#define LOCK_NUM_TRIES 20
+#define LOCK_NUM_TRIES 200
+
+#define MAX_DEFAULT_WIDTH 1280
+#define MAX_DEFAULT_HEIGHT 720
+#define MAX_DEFAULT_FRAME_RATE 60
+#define MAX_DEFAULT_PIX_CLK_HZ 74240000
#define ONE_MHZ_TO_HZ 1000000
+#define I2C_BLOCK_WRITE_SIZE 1024
+
+enum adv7481_gpio_t {
+
+ CCI_I2C_SDA = 0,
+ CCI_I2C_SCL,
+
+ ADV7481_GPIO_RST,
+
+ ADV7481_GPIO_INT1,
+ ADV7481_GPIO_INT2,
+ ADV7481_GPIO_INT3,
+
+ ADV7481_GPIO_MAX,
+};
struct adv7481_state {
- /* Platform Data */
- struct adv7481_platform_data pdata;
+ struct device *dev;
+
+ /* VREG */
+ struct camera_vreg_t *cci_vreg;
+ struct regulator *cci_reg_ptr[MAX_REGULATOR];
+ int32_t regulator_count;
+
+ /* I2C */
+ struct msm_camera_i2c_client i2c_client;
+ u32 cci_master;
+ u32 i2c_slave_addr;
/* V4L2 Data */
struct v4l2_subdev sd;
@@ -63,19 +102,25 @@ struct adv7481_state {
struct workqueue_struct *work_queues;
struct mutex mutex;
- struct i2c_client *client;
- struct i2c_client *i2c_csi_txa;
- struct i2c_client *i2c_csi_txb;
- struct i2c_client *i2c_hdmi;
- struct i2c_client *i2c_edid;
- struct i2c_client *i2c_cp;
- struct i2c_client *i2c_sdp;
- struct i2c_client *i2c_rep;
+ uint8_t i2c_io_addr;
+ uint8_t i2c_csi_txa_addr;
+ uint8_t i2c_csi_txb_addr;
+ uint8_t i2c_hdmi_addr;
+ uint8_t i2c_edid_addr;
+ uint8_t i2c_cp_addr;
+ uint8_t i2c_sdp_addr;
+ uint8_t i2c_rep_addr;
+ uint8_t i2c_cbus_addr;
/* device status and Flags */
int irq;
int device_num;
int powerup;
+ int cec_detected;
+ int clocks_requested;
+
+ /* GPIOs */
+ struct gpio gpio_array[ADV7481_GPIO_MAX];
/* routing configuration data */
int csia_src;
@@ -196,6 +241,9 @@ const uint8_t adv7481_default_edid_data[] = {
#define ADV7481_EDID_SIZE ARRAY_SIZE(adv7481_default_edid_data)
+static u32 adv7481_inp_to_ba(u32 adv_input);
+static bool adv7481_is_timing_locked(struct adv7481_state *state);
+
static inline struct v4l2_subdev *to_sd(struct v4l2_ctrl *ctrl)
{
return &(container_of(ctrl->handler,
@@ -208,56 +256,151 @@ static inline struct adv7481_state *to_state(struct v4l2_subdev *sd)
}
/* I2C Rd/Rw Functions */
-static int adv7481_wr_byte(struct i2c_client *i2c_client, unsigned int reg,
- unsigned int value)
+static int32_t adv7481_cci_i2c_write(struct msm_camera_i2c_client *i2c_client,
+ uint8_t reg, uint16_t *data,
+ enum msm_camera_i2c_data_type data_type)
{
- int ret;
+ return i2c_client->i2c_func_tbl->i2c_write(i2c_client, reg,
+ *data, data_type);
+}
- ret = i2c_smbus_write_byte_data(i2c_client, reg & 0xFF, value);
- usleep_range(I2C_RW_DELAY, 2*I2C_RW_DELAY);
+static int32_t adv7481_cci_i2c_write_seq(
+ struct msm_camera_i2c_client *i2c_client,
+ uint8_t reg, const uint8_t *data, uint32_t size)
+{
+ return i2c_client->i2c_func_tbl->i2c_write_seq(i2c_client, reg,
+ (uint8_t *)data, size);
+}
+
+static int32_t adv7481_cci_i2c_read(struct msm_camera_i2c_client *i2c_client,
+ uint8_t reg, uint16_t *data,
+ enum msm_camera_i2c_data_type data_type)
+{
+ return i2c_client->i2c_func_tbl->i2c_read(i2c_client, reg,
+ data, data_type);
+}
+
+static int32_t adv7481_wr_byte(struct msm_camera_i2c_client *c_i2c_client,
+ uint8_t sid, uint8_t reg, uint8_t data)
+{
+ uint16_t write_data = data;
+ int ret = 0;
+
+ c_i2c_client->cci_client->sid = sid;
+
+ ret = adv7481_cci_i2c_write(c_i2c_client, reg, &write_data,
+ MSM_CAMERA_I2C_BYTE_DATA);
+ if (ret < 0)
+ pr_err("Error %d writing cci i2c\n", ret);
return ret;
}
-static int adv7481_rd_byte(struct i2c_client *i2c_client, unsigned int reg)
+static int32_t adv7481_wr_block(struct msm_camera_i2c_client *c_i2c_client,
+ uint8_t sid, uint8_t reg, const uint8_t *data, uint32_t size)
{
- int ret;
+ int ret = 0;
- ret = i2c_smbus_read_byte_data(i2c_client, reg & 0xFF);
- usleep_range(I2C_RW_DELAY, 2*I2C_RW_DELAY);
+ c_i2c_client->cci_client->sid = sid;
+
+ ret = adv7481_cci_i2c_write_seq(c_i2c_client, reg, data, size);
+ if (ret < 0)
+ pr_err("Error %d writing cci i2c block data\n", ret);
return ret;
}
+static uint8_t adv7481_rd_byte(struct msm_camera_i2c_client *c_i2c_client,
+ uint8_t sid, uint8_t reg)
+{
+ uint16_t data = 0;
+ int ret = 0;
+
+ c_i2c_client->cci_client->sid = sid;
+ ret = adv7481_cci_i2c_read(c_i2c_client, reg, &data,
+ MSM_CAMERA_I2C_BYTE_DATA);
+ if (ret < 0) {
+ pr_err("Error %d reading cci i2c\n", ret);
+ return ret;
+ }
+
+ return (uint8_t)(data & 0xFF);
+}
+
+static uint16_t adv7481_rd_word(struct msm_camera_i2c_client *c_i2c_client,
+ uint8_t sid, uint8_t reg)
+{
+ uint16_t data = 0;
+ int ret;
+
+ c_i2c_client->cci_client->sid = sid;
+ ret = adv7481_cci_i2c_read(c_i2c_client, reg, &data,
+ MSM_CAMERA_I2C_WORD_DATA);
+ if (ret < 0) {
+ pr_err("Error %d reading cci i2c\n", ret);
+ return ret;
+ }
+
+ return data;
+}
+
static int adv7481_set_irq(struct adv7481_state *state)
{
int ret = 0;
- ret = adv7481_wr_byte(state->client, IO_REG_PAD_CTRL_1_ADDR,
+ ret = adv7481_wr_byte(&state->i2c_client, state->i2c_io_addr,
+ IO_REG_PAD_CTRL_1_ADDR,
ADV_REG_SETFIELD(1, IO_PDN_INT2) |
ADV_REG_SETFIELD(1, IO_PDN_INT3) |
ADV_REG_SETFIELD(1, IO_INV_LLC) |
ADV_REG_SETFIELD(AD_MID_DRIVE_STRNGTH, IO_DRV_LLC_PAD));
- ret |= adv7481_wr_byte(state->client, IO_REG_INT1_CONF_ADDR,
+ ret |= adv7481_wr_byte(&state->i2c_client, state->i2c_io_addr,
+ IO_REG_INT1_CONF_ADDR,
ADV_REG_SETFIELD(AD_ACTIVE_UNTIL_CLR,
IO_INTRQ_DUR_SEL) |
ADV_REG_SETFIELD(AD_OP_DRIVE_LOW, IO_INTRQ_OP_SEL));
- ret |= adv7481_wr_byte(state->client, IO_REG_INT2_CONF_ADDR,
+ ret |= adv7481_wr_byte(&state->i2c_client, state->i2c_io_addr,
+ IO_REG_INT2_CONF_ADDR,
ADV_REG_SETFIELD(1, IO_CP_LOCK_UNLOCK_EDGE_SEL));
- ret |= adv7481_wr_byte(state->client, IO_REG_DATAPATH_INT_MASKB_ADDR,
+ ret |= adv7481_wr_byte(&state->i2c_client, state->i2c_io_addr,
+ IO_REG_DATAPATH_INT_MASKB_ADDR,
ADV_REG_SETFIELD(1, IO_CP_LOCK_CP_MB1) |
ADV_REG_SETFIELD(1, IO_CP_UNLOCK_CP_MB1) |
ADV_REG_SETFIELD(1, IO_VMUTE_REQUEST_HDMI_MB1) |
ADV_REG_SETFIELD(1, IO_INT_SD_MB1));
- /* Set hpa */
- ret |= adv7481_wr_byte(state->client, IO_HDMI_LVL_INT_MASKB_3_ADDR,
- ADV_REG_SETFIELD(1, IO_CABLE_DET_A_MB1));
+ /* Set cable detect */
+ ret |= adv7481_wr_byte(&state->i2c_client, state->i2c_io_addr,
+ IO_HDMI_LVL_INT_MASKB_3_ADDR,
+ ADV_REG_SETFIELD(1, IO_CABLE_DET_A_MB1) |
+ ADV_REG_SETFIELD(1, IO_V_LOCKED_MB1) |
+ ADV_REG_SETFIELD(1, IO_DE_REGEN_LCK_MB1));
+
+ /* set CVBS lock/unlock interrupts */
+ /* Select SDP MAP 1 */
+ adv7481_wr_byte(&state->i2c_client, state->i2c_sdp_addr,
+ SDP_RW_MAP_REG, 0x20);
+ adv7481_wr_byte(&state->i2c_client, state->i2c_sdp_addr,
+ SDP_RW_LOCK_UNLOCK_MASK_ADDR, 0x03);
+ adv7481_wr_byte(&state->i2c_client, state->i2c_sdp_addr,
+ SDP_RW_MAP_REG, 0x00);
if (ret)
pr_err("%s: Failed %d to setup interrupt regs\n",
__func__, ret);
- else
- enable_irq(state->irq);
+
+ return ret;
+}
+
+static int adv7481_reset_irq(struct adv7481_state *state)
+{
+ int ret = 0;
+
+ disable_irq(state->irq);
+
+ ret = adv7481_wr_byte(&state->i2c_client, state->i2c_io_addr,
+ IO_REG_DATAPATH_INT_MASKB_ADDR, 0x00);
+ ret |= adv7481_wr_byte(&state->i2c_client, state->i2c_io_addr,
+ IO_HDMI_LVL_INT_MASKB_3_ADDR, 0x00);
return ret;
}
@@ -267,27 +410,42 @@ static int adv7481_set_edid(struct adv7481_state *state)
int i;
int ret = 0;
uint8_t edid_state;
+ uint32_t data_left = 0;
+ uint32_t start_pos;
/* Enable Manual Control of EDID on Port A */
- ret |= adv7481_wr_byte(state->i2c_rep, 0x74, 0x01);
+ ret |= adv7481_wr_byte(&state->i2c_client, state->i2c_rep_addr, 0x74,
+ 0x01);
/* Disable Auto Enable of EDID */
- ret |= adv7481_wr_byte(state->i2c_rep, 0x7A, 0x08);
+ ret |= adv7481_wr_byte(&state->i2c_client, state->i2c_rep_addr, 0x7A,
+ 0x08);
/* Set Primary EDID Size to 256 Bytes */
- ret |= adv7481_wr_byte(state->i2c_rep, 0x70, 0x20);
+ ret |= adv7481_wr_byte(&state->i2c_client, state->i2c_rep_addr, 0x70,
+ 0x20);
/*
* Readback EDID enable state after a combination of manual
* and automatic functions
*/
- edid_state = adv7481_rd_byte(state->i2c_rep,
+ edid_state = adv7481_rd_byte(&state->i2c_client, state->i2c_rep_addr,
HDMI_REG_RO_EDID_DEBUG_2_ADDR);
pr_debug("%s: Readback EDID enable state: 0x%x\n", __func__,
edid_state);
- for (i = 0; i < ADV7481_EDID_SIZE; i++) {
- ret |= adv7481_wr_byte(state->i2c_edid, i,
- adv7481_default_edid_data[i]);
- }
+ for (i = 0; i < ADV7481_EDID_SIZE && !ret; i += I2C_BLOCK_WRITE_SIZE)
+ ret |= adv7481_wr_block(&state->i2c_client,
+ state->i2c_edid_addr,
+ i, &adv7481_default_edid_data[i],
+ I2C_BLOCK_WRITE_SIZE);
+
+ data_left = ADV7481_EDID_SIZE % I2C_BLOCK_WRITE_SIZE;
+ start_pos = ADV7481_EDID_SIZE - data_left;
+ if (data_left && !ret)
+ ret |= adv7481_wr_block(&state->i2c_client,
+ state->i2c_edid_addr,
+ start_pos,
+ &adv7481_default_edid_data[start_pos],
+ data_left);
return ret;
}
@@ -301,47 +459,232 @@ static irqreturn_t adv7481_irq(int irq, void *dev)
return IRQ_HANDLED;
}
+/* Request CCI clocks for adv7481 register access */
+static int adv7481_request_cci_clks(struct adv7481_state *state)
+{
+ int ret = 0;
+
+ if (state->clocks_requested == TRUE)
+ return ret;
+
+ ret = state->i2c_client.i2c_func_tbl->i2c_util(
+ &state->i2c_client, MSM_CCI_INIT);
+ if (ret < 0)
+ pr_err("%s - cci_init failed\n", __func__);
+ else
+ state->clocks_requested = TRUE;
+
+ /* enable camera voltage regulator */
+ ret = msm_camera_enable_vreg(state->dev, state->cci_vreg,
+ state->regulator_count, NULL, 0,
+ &state->cci_reg_ptr[0], 1);
+ if (ret < 0)
+ pr_err("%s:cci enable_vreg failed\n", __func__);
+ else
+ pr_debug("%s - VREG Initialized...\n", __func__);
+
+ return ret;
+}
+
+static int adv7481_release_cci_clks(struct adv7481_state *state)
+{
+ int ret = 0;
+
+ if (state->clocks_requested == FALSE)
+ return ret;
+
+ ret = state->i2c_client.i2c_func_tbl->i2c_util(
+ &state->i2c_client, MSM_CCI_RELEASE);
+ if (ret < 0)
+ pr_err("%s - cci_release failed\n", __func__);
+ else
+ state->clocks_requested = FALSE;
+
+ /* disable camera voltage regulator */
+ ret = msm_camera_enable_vreg(state->dev, state->cci_vreg,
+ state->regulator_count, NULL, 0,
+ &state->cci_reg_ptr[0], 0);
+ if (ret < 0)
+ pr_err("%s:cci disable vreg failed\n", __func__);
+ else
+ pr_debug("%s - VREG Initialized...\n", __func__);
+
+ return ret;
+}
+
static void adv7481_irq_delay_work(struct work_struct *work)
{
struct adv7481_state *state;
- uint8_t status;
+ uint8_t int_raw_status;
+ uint8_t int_status;
+ uint8_t raw_status;
state = container_of(work, struct adv7481_state,
irq_delayed_work.work);
mutex_lock(&state->mutex);
- /* workaround for irq trigger */
- status = adv7481_rd_byte(state->client,
+ /* Read raw irq status register */
+ int_raw_status = adv7481_rd_byte(&state->i2c_client, state->i2c_io_addr,
IO_REG_INT_RAW_STATUS_ADDR);
pr_debug("%s: dev: %d got int raw status: 0x%x\n", __func__,
- state->device_num, status);
+ state->device_num, int_raw_status);
+ state->cec_detected = ADV_REG_GETFIELD(int_raw_status, IO_INT_CEC_ST);
+
+ while (int_raw_status) {
+ if (ADV_REG_GETFIELD(int_raw_status, IO_INTRQ1_RAW)) {
+ int lock_status = -1;
+ struct v4l2_event event = {0};
+ int *ptr = (int *)event.u.data;
+
+ pr_debug("%s: dev: %d got intrq1_raw\n", __func__,
+ state->device_num);
+ int_status = adv7481_rd_byte(&state->i2c_client,
+ state->i2c_io_addr,
+ IO_REG_DATAPATH_INT_STATUS_ADDR);
+
+ raw_status = adv7481_rd_byte(&state->i2c_client,
+ state->i2c_io_addr,
+ IO_REG_DATAPATH_RAW_STATUS_ADDR);
+
+ adv7481_wr_byte(&state->i2c_client, state->i2c_io_addr,
+ IO_REG_DATAPATH_INT_CLEAR_ADDR, int_status);
+
+ pr_debug("%s: dev: %d got datapath int status: 0x%x\n",
+ __func__, state->device_num, int_status);
+
+ pr_debug("%s: dev: %d got datapath raw status: 0x%x\n",
+ __func__, state->device_num, raw_status);
+
+ if (ADV_REG_GETFIELD(int_status, IO_INT_SD_ST) &&
+ ADV_REG_GETFIELD(raw_status, IO_INT_SD_RAW)) {
+ uint8_t sdp_sts = 0;
+
+ adv7481_wr_byte(&state->i2c_client,
+ state->i2c_sdp_addr, SDP_RW_MAP_REG,
+ 0x01);
+ sdp_sts = adv7481_rd_byte(&state->i2c_client,
+ state->i2c_sdp_addr,
+ SDP_RO_MAIN_STATUS1_ADDR);
+ pr_debug("%s: dev: %d got sdp status: 0x%x\n",
+ __func__, state->device_num, sdp_sts);
+ adv7481_wr_byte(&state->i2c_client,
+ state->i2c_sdp_addr, SDP_RW_MAP_REG,
+ 0x00);
+ if (ADV_REG_GETFIELD(sdp_sts,
+ SDP_RO_MAIN_IN_LOCK)) {
+ lock_status = 0;
+ pr_debug(
+ "%s: set lock_status SDP_IN_LOCK:0x%x\n",
+ __func__, lock_status);
+ } else {
+ lock_status = 1;
+ pr_debug(
+ "%s: set lock_status SDP_UNLOCK:0x%x\n",
+ __func__, lock_status);
+ }
+ adv7481_wr_byte(&state->i2c_client,
+ state->i2c_sdp_addr, SDP_RW_MAP_REG,
+ 0x20);
+ adv7481_wr_byte(&state->i2c_client,
+ state->i2c_sdp_addr,
+ SDP_RW_LOCK_UNLOCK_CLR_ADDR, sdp_sts);
+ adv7481_wr_byte(&state->i2c_client,
+ state->i2c_sdp_addr, SDP_RW_MAP_REG,
+ 0x00);
+ } else {
+ if (ADV_REG_GETFIELD(int_status,
+ IO_CP_LOCK_CP_ST) &&
+ ADV_REG_GETFIELD(raw_status,
+ IO_CP_LOCK_CP_RAW)) {
+ lock_status = 0;
+ pr_debug(
+ "%s: set lock_status IO_CP_LOCK_CP_RAW:0x%x\n",
+ __func__, lock_status);
+ }
+ if (ADV_REG_GETFIELD(int_status,
+ IO_CP_UNLOCK_CP_ST) &&
+ ADV_REG_GETFIELD(raw_status,
+ IO_CP_UNLOCK_CP_RAW)) {
+ lock_status = 1;
+ pr_debug(
+ "%s: set lock_status IO_CP_UNLOCK_CP_RAW:0x%x\n",
+ __func__, lock_status);
+ }
+ }
+
+ if (lock_status >= 0) {
+ ptr[0] = adv7481_inp_to_ba(state->mode);
+ ptr[1] = lock_status;
+ event.type = lock_status ?
+ V4L2_EVENT_MSM_BA_SIGNAL_LOST_LOCK :
+ V4L2_EVENT_MSM_BA_SIGNAL_IN_LOCK;
+ v4l2_subdev_notify(&state->sd,
+ event.type, &event);
+ }
+ }
- status = adv7481_rd_byte(state->client,
- IO_REG_DATAPATH_INT_STATUS_ADDR);
+ if (ADV_REG_GETFIELD(int_raw_status, IO_INT_HDMI_ST)) {
+ int cable_detected = 0;
+ struct v4l2_event event = {0};
+ int *ptr = (int *)event.u.data;
- pr_debug("%s: dev: %d got datapath int status: 0x%x\n", __func__,
- state->device_num, status);
+ ptr[0] = adv7481_inp_to_ba(state->mode);
- adv7481_wr_byte(state->client,
- IO_REG_DATAPATH_INT_CLEAR_ADDR, status);
+ pr_debug("%s: dev: %d got int_hdmi_st\n", __func__,
+ state->device_num);
- status = adv7481_rd_byte(state->client,
- IO_REG_DATAPATH_RAW_STATUS_ADDR);
+ int_status = adv7481_rd_byte(&state->i2c_client,
+ state->i2c_io_addr,
+ IO_HDMI_LVL_INT_STATUS_3_ADDR);
- pr_debug("%s: dev: %d got datapath rawstatus: 0x%x\n", __func__,
- state->device_num, status);
+ raw_status = adv7481_rd_byte(&state->i2c_client,
+ state->i2c_io_addr,
+ IO_HDMI_LVL_RAW_STATUS_3_ADDR);
- status = adv7481_rd_byte(state->client,
- IO_HDMI_LVL_INT_STATUS_3_ADDR);
+ adv7481_wr_byte(&state->i2c_client, state->i2c_io_addr,
+ IO_HDMI_LVL_INT_CLEAR_3_ADDR, int_status);
- pr_debug("%s: dev: %d got hdmi lvl int status 3: 0x%x\n", __func__,
- state->device_num, status);
+ pr_debug("%s: dev: %d got hdmi lvl int status 3: 0x%x\n",
+ __func__, state->device_num, int_status);
+ pr_debug("%s: dev: %d got hdmi lvl raw status 3: 0x%x\n",
+ __func__, state->device_num, raw_status);
- adv7481_wr_byte(state->client,
- IO_HDMI_LVL_INT_CLEAR_3_ADDR, status);
+ if (ADV_REG_GETFIELD(int_status, IO_CABLE_DET_A_ST)) {
+ cable_detected = ADV_REG_GETFIELD(raw_status,
+ IO_CABLE_DET_A_RAW);
+ pr_debug("%s: set cable_detected: 0x%x\n",
+ __func__, cable_detected);
+ ptr[1] = cable_detected;
+ event.type = V4L2_EVENT_MSM_BA_CABLE_DETECT;
+ v4l2_subdev_notify(&state->sd,
+ event.type, &event);
+ }
+ /* Assumption is that vertical sync int
+ * is the last one to come
+ */
+ if (ADV_REG_GETFIELD(int_status, IO_V_LOCKED_ST)) {
+ if (ADV_REG_GETFIELD(raw_status,
+ IO_TMDSPLL_LCK_A_RAW) &&
+ ADV_REG_GETFIELD(raw_status,
+ IO_V_LOCKED_RAW) &&
+ ADV_REG_GETFIELD(raw_status,
+ IO_DE_REGEN_LCK_RAW)) {
+ pr_debug("%s: port settings changed\n",
+ __func__);
+ event.type =
+ V4L2_EVENT_MSM_BA_PORT_SETTINGS_CHANGED;
+ v4l2_subdev_notify(&state->sd,
+ event.type, &event);
+ }
+ }
+ }
+ int_raw_status = adv7481_rd_byte(&state->i2c_client,
+ state->i2c_io_addr,
+ IO_REG_INT_RAW_STATUS_ADDR);
+ }
mutex_unlock(&state->mutex);
}
@@ -350,110 +693,100 @@ static int adv7481_cec_wakeup(struct adv7481_state *state, bool enable)
uint8_t val;
int ret = 0;
- val = adv7481_rd_byte(state->client,
+ val = adv7481_rd_byte(&state->i2c_client, state->i2c_io_addr,
IO_REG_PWR_DN2_XTAL_HIGH_ADDR);
val = ADV_REG_GETFIELD(val, IO_PROG_XTAL_FREQ_HIGH);
if (enable) {
/* CEC wake up enabled in power-down mode */
val |= ADV_REG_SETFIELD(1, IO_CTRL_CEC_WAKE_UP_PWRDN2B) |
ADV_REG_SETFIELD(0, IO_CTRL_CEC_WAKE_UP_PWRDNB);
- ret = adv7481_wr_byte(state->client,
+ ret = adv7481_wr_byte(&state->i2c_client, state->i2c_io_addr,
IO_REG_PWR_DN2_XTAL_HIGH_ADDR, val);
} else {
/* CEC wake up disabled in power-down mode */
val |= ADV_REG_SETFIELD(0, IO_CTRL_CEC_WAKE_UP_PWRDN2B) |
ADV_REG_SETFIELD(1, IO_CTRL_CEC_WAKE_UP_PWRDNB);
- ret = adv7481_wr_byte(state->client,
+ ret = adv7481_wr_byte(&state->i2c_client, state->i2c_io_addr,
IO_REG_PWR_DN2_XTAL_HIGH_ADDR, val);
}
return ret;
}
/* Initialize adv7481 I2C Settings */
-static int adv7481_dev_init(struct adv7481_state *state,
- struct i2c_client *client)
+static int adv7481_dev_init(struct adv7481_state *state)
{
+ uint16_t chip_rev_id;
int ret;
mutex_lock(&state->mutex);
/* Soft reset */
- ret = adv7481_wr_byte(state->client,
- IO_REG_MAIN_RST_ADDR, IO_REG_MAIN_RST_VALUE);
+ ret = adv7481_wr_byte(&state->i2c_client, state->i2c_io_addr,
+ IO_REG_MAIN_RST_ADDR, IO_REG_MAIN_RST_VALUE);
/* Delay required following I2C reset and I2C transactions */
- usleep_range(I2C_SW_RST_DELAY, I2C_SW_RST_DELAY+1000);
+ udelay(I2C_SW_RST_DELAY);
+
+ chip_rev_id = adv7481_rd_word(&state->i2c_client, state->i2c_io_addr,
+ IO_REG_CHIP_REV_ID_1_ADDR);
+ pr_debug("%s: ADV7481 chip rev id: 0x%x", __func__, chip_rev_id);
/* Disable CEC wake up in power-down mode */
ret |= adv7481_cec_wakeup(state, 0);
/* Setting Vid_Std to 720x480p60 */
- ret |= adv7481_wr_byte(state->client,
- IO_REG_CP_VID_STD_ADDR, 0x4A);
+ ret |= adv7481_wr_byte(&state->i2c_client, state->i2c_io_addr,
+ IO_REG_CP_VID_STD_ADDR, 0x4A);
/* Configure I2C Maps and I2C Communication Settings */
/* io_reg_f2 I2C Auto Increment */
- ret |= adv7481_wr_byte(state->client, IO_REG_I2C_CFG_ADDR,
- IO_REG_I2C_AUTOINC_EN_REG_VALUE);
+ ret |= adv7481_wr_byte(&state->i2c_client, state->i2c_io_addr,
+ IO_REG_I2C_CFG_ADDR, IO_REG_I2C_AUTOINC_EN_REG_VALUE);
/* DPLL Map Address */
- ret |= adv7481_wr_byte(state->client, IO_REG_DPLL_ADDR,
- IO_REG_DPLL_SADDR);
+ ret |= adv7481_wr_byte(&state->i2c_client, state->i2c_io_addr,
+ IO_REG_DPLL_ADDR, IO_REG_DPLL_SADDR);
/* CP Map Address */
- ret |= adv7481_wr_byte(state->client, IO_REG_CP_ADDR,
- IO_REG_CP_SADDR);
+ ret |= adv7481_wr_byte(&state->i2c_client, state->i2c_io_addr,
+ IO_REG_CP_ADDR, IO_REG_CP_SADDR);
/* HDMI RX Map Address */
- ret |= adv7481_wr_byte(state->client, IO_REG_HDMI_ADDR,
- IO_REG_HDMI_SADDR);
+ ret |= adv7481_wr_byte(&state->i2c_client, state->i2c_io_addr,
+ IO_REG_HDMI_ADDR, IO_REG_HDMI_SADDR);
/* EDID Map Address */
- ret |= adv7481_wr_byte(state->client, IO_REG_EDID_ADDR,
- IO_REG_EDID_SADDR);
+ ret |= adv7481_wr_byte(&state->i2c_client, state->i2c_io_addr,
+ IO_REG_EDID_ADDR, IO_REG_EDID_SADDR);
/* HDMI RX Repeater Map Address */
- ret |= adv7481_wr_byte(state->client, IO_REG_HDMI_REP_ADDR,
- IO_REG_HDMI_REP_SADDR);
+ ret |= adv7481_wr_byte(&state->i2c_client, state->i2c_io_addr,
+ IO_REG_HDMI_REP_ADDR, IO_REG_HDMI_REP_SADDR);
/* HDMI RX Info-frame Map Address */
- ret |= adv7481_wr_byte(state->client, IO_REG_HDMI_INF_ADDR,
- IO_REG_HDMI_INF_SADDR);
+ ret |= adv7481_wr_byte(&state->i2c_client, state->i2c_io_addr,
+ IO_REG_HDMI_INF_ADDR, IO_REG_HDMI_INF_SADDR);
/* CBUS Map Address */
- ret |= adv7481_wr_byte(state->client, IO_REG_CBUS_ADDR,
- IO_REG_CBUS_SADDR);
+ ret |= adv7481_wr_byte(&state->i2c_client, state->i2c_io_addr,
+ IO_REG_CBUS_ADDR, IO_REG_CBUS_SADDR);
/* CEC Map Address */
- ret |= adv7481_wr_byte(state->client, IO_REG_CEC_ADDR,
- IO_REG_CEC_SADDR);
+ ret |= adv7481_wr_byte(&state->i2c_client, state->i2c_io_addr,
+ IO_REG_CEC_ADDR, IO_REG_CEC_SADDR);
/* SDP Main Map Address */
- ret |= adv7481_wr_byte(state->client, IO_REG_SDP_ADDR,
- IO_REG_SDP_SADDR);
+ ret |= adv7481_wr_byte(&state->i2c_client, state->i2c_io_addr,
+ IO_REG_SDP_ADDR, IO_REG_SDP_SADDR);
/* CSI-TXB Map Address */
- ret |= adv7481_wr_byte(state->client, IO_REG_CSI_TXB_ADDR,
- IO_REG_CSI_TXB_SADDR);
+ ret |= adv7481_wr_byte(&state->i2c_client, state->i2c_io_addr,
+ IO_REG_CSI_TXB_ADDR, IO_REG_CSI_TXB_SADDR);
/* CSI-TXA Map Address */
- ret |= adv7481_wr_byte(state->client, IO_REG_CSI_TXA_ADDR,
- IO_REG_CSI_TXA_SADDR);
+ ret |= adv7481_wr_byte(&state->i2c_client, state->i2c_io_addr,
+ IO_REG_CSI_TXA_ADDR, IO_REG_CSI_TXA_SADDR);
if (ret) {
pr_err("%s: Failed dev init %d\n", __func__, ret);
goto err_exit;
}
/* Configure i2c clients */
- state->i2c_csi_txa = i2c_new_dummy(client->adapter,
- IO_REG_CSI_TXA_SADDR >> 1);
- state->i2c_csi_txb = i2c_new_dummy(client->adapter,
- IO_REG_CSI_TXB_SADDR >> 1);
- state->i2c_cp = i2c_new_dummy(client->adapter,
- IO_REG_CP_SADDR >> 1);
- state->i2c_hdmi = i2c_new_dummy(client->adapter,
- IO_REG_HDMI_SADDR >> 1);
- state->i2c_edid = i2c_new_dummy(client->adapter,
- IO_REG_EDID_SADDR >> 1);
- state->i2c_sdp = i2c_new_dummy(client->adapter,
- IO_REG_SDP_SADDR >> 1);
- state->i2c_rep = i2c_new_dummy(client->adapter,
- IO_REG_HDMI_REP_SADDR >> 1);
-
- if (!state->i2c_csi_txa || !state->i2c_csi_txb || !state->i2c_cp ||
- !state->i2c_sdp || !state->i2c_hdmi || !state->i2c_edid ||
- !state->i2c_rep) {
- pr_err("%s: Additional I2C Client Fail\n", __func__);
- ret = -EFAULT;
- goto err_exit;
- }
+ state->i2c_csi_txa_addr = IO_REG_CSI_TXA_SADDR >> 1;
+ state->i2c_csi_txb_addr = IO_REG_CSI_TXB_SADDR >> 1;
+ state->i2c_cp_addr = IO_REG_CP_SADDR >> 1;
+ state->i2c_hdmi_addr = IO_REG_HDMI_SADDR >> 1;
+ state->i2c_edid_addr = IO_REG_EDID_SADDR >> 1;
+ state->i2c_sdp_addr = IO_REG_SDP_SADDR >> 1;
+ state->i2c_rep_addr = IO_REG_HDMI_REP_SADDR >> 1;
+ state->i2c_cbus_addr = IO_REG_CBUS_SADDR >> 1;
ret = adv7481_set_edid(state);
ret |= adv7481_set_irq(state);
@@ -465,28 +798,25 @@ err_exit:
}
/* Initialize adv7481 hardware */
-static int adv7481_hw_init(struct adv7481_platform_data *pdata,
- struct adv7481_state *state)
+static int adv7481_hw_init(struct adv7481_state *state)
{
int ret = 0;
- if (!pdata) {
- pr_err("%s: PDATA is NULL\n", __func__);
- return -EFAULT;
- }
-
mutex_lock(&state->mutex);
- if (gpio_is_valid(pdata->rstb_gpio)) {
- ret = gpio_request(pdata->rstb_gpio, "rstb_gpio");
- if (ret) {
- pr_err("%s: Request GPIO Fail %d\n", __func__, ret);
- goto err_exit;
- }
- ret = gpio_direction_output(pdata->rstb_gpio, 0);
- usleep_range(GPIO_HW_DELAY_LOW, GPIO_HW_DELAY_LOW+1000);
- ret = gpio_direction_output(pdata->rstb_gpio, 1);
- usleep_range(GPIO_HW_DELAY_HI, GPIO_HW_DELAY_HI+1000);
+ /* Bring ADV7481 out of reset */
+ ret = gpio_request_array(&state->gpio_array[ADV7481_GPIO_RST], 1);
+ if (ret < 0) {
+ pr_err("%s: Failed to request reset GPIO %d\n", __func__, ret);
+ goto err_exit;
+ }
+ if (gpio_is_valid(state->gpio_array[ADV7481_GPIO_RST].gpio)) {
+ ret |= gpio_direction_output(
+ state->gpio_array[ADV7481_GPIO_RST].gpio, 0);
+ udelay(GPIO_HW_RST_DELAY_LOW);
+ ret |= gpio_direction_output(
+ state->gpio_array[ADV7481_GPIO_RST].gpio, 1);
+ udelay(GPIO_HW_RST_DELAY_HI);
if (ret) {
pr_err("%s: Set GPIO Fail %d\n", __func__, ret);
goto err_exit;
@@ -494,22 +824,21 @@ static int adv7481_hw_init(struct adv7481_platform_data *pdata,
}
/* Only setup IRQ1 for now... */
- if (gpio_is_valid(pdata->irq1_gpio)) {
- ret = gpio_request(pdata->irq1_gpio, "irq_gpio");
- if (ret) {
- pr_err("%s: Failed to request irq_gpio %d\n",
- __func__, ret);
- goto err_exit;
- }
-
- ret = gpio_direction_input(pdata->irq1_gpio);
+ ret = gpio_request_array(&state->gpio_array[ADV7481_GPIO_INT1], 1);
+ if (ret < 0) {
+ pr_err("%s: Failed to request irq_gpio %d\n", __func__, ret);
+ goto err_exit;
+ }
+ if (gpio_is_valid(state->gpio_array[ADV7481_GPIO_INT1].gpio)) {
+ ret |= gpio_direction_input(
+ state->gpio_array[ADV7481_GPIO_INT1].gpio);
if (ret) {
pr_err("%s: Failed gpio_direction irq %d\n",
__func__, ret);
goto err_exit;
}
-
- state->irq = gpio_to_irq(pdata->irq1_gpio);
+ state->irq = gpio_to_irq(
+ state->gpio_array[ADV7481_GPIO_INT1].gpio);
if (state->irq) {
ret = request_irq(state->irq, adv7481_irq,
IRQF_ONESHOT | IRQF_TRIGGER_FALLING,
@@ -519,18 +848,16 @@ static int adv7481_hw_init(struct adv7481_platform_data *pdata,
__func__, ret);
goto err_exit;
}
+ /* disable irq until chip interrupts are programmed */
+ disable_irq(state->irq);
} else {
pr_err("%s: Failed gpio_to_irq %d\n", __func__, ret);
ret = -EINVAL;
goto err_exit;
}
-
- /* disable irq until chip interrupts are programmed */
- disable_irq(state->irq);
-
- INIT_DELAYED_WORK(&state->irq_delayed_work,
- adv7481_irq_delay_work);
}
+ INIT_DELAYED_WORK(&state->irq_delayed_work,
+ adv7481_irq_delay_work);
err_exit:
mutex_unlock(&state->mutex);
@@ -548,31 +875,40 @@ static int adv7481_s_ctrl(struct v4l2_ctrl *ctrl)
pr_debug("Enter %s: id = 0x%x\n", __func__, ctrl->id);
switch (ctrl->id) {
case V4L2_CID_BRIGHTNESS:
- temp = adv7481_rd_byte(state->client, CP_REG_VID_ADJ);
+ temp = adv7481_rd_byte(&state->i2c_client, state->i2c_io_addr,
+ CP_REG_VID_ADJ);
temp |= CP_CTR_VID_ADJ_EN;
- ret = adv7481_wr_byte(state->client, CP_REG_VID_ADJ, temp);
- ret |= adv7481_wr_byte(state->client,
- CP_REG_BRIGHTNESS, ctrl->val);
+ ret = adv7481_wr_byte(&state->i2c_client, state->i2c_io_addr,
+ CP_REG_VID_ADJ, temp);
+ ret |= adv7481_wr_byte(&state->i2c_client, state->i2c_io_addr,
+ CP_REG_BRIGHTNESS, ctrl->val);
break;
case V4L2_CID_CONTRAST:
- temp = adv7481_rd_byte(state->client, CP_REG_VID_ADJ);
+ temp = adv7481_rd_byte(&state->i2c_client, state->i2c_io_addr,
+ CP_REG_VID_ADJ);
temp |= CP_CTR_VID_ADJ_EN;
- ret = adv7481_wr_byte(state->client, CP_REG_VID_ADJ, temp);
- ret |= adv7481_wr_byte(state->client,
- CP_REG_CONTRAST, ctrl->val);
+ ret = adv7481_wr_byte(&state->i2c_client, state->i2c_io_addr,
+ CP_REG_VID_ADJ, temp);
+ ret |= adv7481_wr_byte(&state->i2c_client, state->i2c_io_addr,
+ CP_REG_CONTRAST, ctrl->val);
break;
case V4L2_CID_SATURATION:
- temp = adv7481_rd_byte(state->client, CP_REG_VID_ADJ);
+ temp = adv7481_rd_byte(&state->i2c_client, state->i2c_io_addr,
+ CP_REG_VID_ADJ);
temp |= CP_CTR_VID_ADJ_EN;
- ret = adv7481_wr_byte(state->client, CP_REG_VID_ADJ, temp);
- ret |= adv7481_wr_byte(state->client,
- CP_REG_SATURATION, ctrl->val);
+ ret = adv7481_wr_byte(&state->i2c_client, state->i2c_io_addr,
+ CP_REG_VID_ADJ, temp);
+ ret |= adv7481_wr_byte(&state->i2c_client, state->i2c_io_addr,
+ CP_REG_SATURATION, ctrl->val);
break;
case V4L2_CID_HUE:
- temp = adv7481_rd_byte(state->client, CP_REG_VID_ADJ);
+ temp = adv7481_rd_byte(&state->i2c_client, state->i2c_io_addr,
+ CP_REG_VID_ADJ);
temp |= CP_CTR_VID_ADJ_EN;
- ret = adv7481_wr_byte(state->client, CP_REG_VID_ADJ, temp);
- ret |= adv7481_wr_byte(state->client, CP_REG_HUE, ctrl->val);
+ ret = adv7481_wr_byte(&state->i2c_client, state->i2c_io_addr,
+ CP_REG_VID_ADJ, temp);
+ ret |= adv7481_wr_byte(&state->i2c_client, state->i2c_io_addr,
+ CP_REG_HUE, ctrl->val);
break;
default:
break;
@@ -611,6 +947,108 @@ static int adv7481_s_power(struct v4l2_subdev *sd, int on)
return ret;
}
+static int adv7481_set_cec_logical_addr(struct adv7481_state *state, int *la)
+{
+ int rc = 0;
+ uint8_t val;
+
+ if (!la) {
+ pr_err("%s: NULL pointer provided\n", __func__);
+ return -EINVAL;
+ }
+
+ val = adv7481_rd_byte(&state->i2c_client, state->i2c_io_addr,
+ CEC_REG_LOG_ADDR_MASK_ADDR);
+ if (ADV_REG_GETFIELD(val, CEC_REG_LOG_ADDR_MASK0)) {
+ val = adv7481_rd_byte(&state->i2c_client, state->i2c_io_addr,
+ CEC_REG_LOGICAL_ADDRESS0_1_ADDR);
+ val = ADV_REG_RSTFIELD(val, CEC_REG_LOGICAL_ADDRESS0);
+ val |= ADV_REG_SETFIELD(*la, CEC_REG_LOGICAL_ADDRESS0);
+ rc = adv7481_wr_byte(&state->i2c_client, state->i2c_io_addr,
+ CEC_REG_LOGICAL_ADDRESS0_1_ADDR, val);
+ } else if (ADV_REG_GETFIELD(val, CEC_REG_LOG_ADDR_MASK1)) {
+ val = adv7481_rd_byte(&state->i2c_client, state->i2c_io_addr,
+ CEC_REG_LOGICAL_ADDRESS0_1_ADDR);
+ val = ADV_REG_RSTFIELD(val, CEC_REG_LOGICAL_ADDRESS1);
+ val |= ADV_REG_SETFIELD(*la, CEC_REG_LOGICAL_ADDRESS1);
+ rc = adv7481_wr_byte(&state->i2c_client, state->i2c_io_addr,
+ CEC_REG_LOGICAL_ADDRESS0_1_ADDR, val);
+ } else if (ADV_REG_GETFIELD(val, CEC_REG_LOG_ADDR_MASK2)) {
+ val = ADV_REG_SETFIELD(*la, CEC_REG_LOGICAL_ADDRESS2);
+ rc = adv7481_wr_byte(&state->i2c_client, state->i2c_io_addr,
+ CEC_REG_LOGICAL_ADDRESS2_ADDR, val);
+ } else {
+ pr_err("No cec logical address mask set\n");
+ }
+
+ return rc;
+}
+
+static int adv7481_cec_powerup(struct adv7481_state *state, int *powerup)
+{
+ int rc = 0;
+ uint8_t val = 0;
+
+ if (!powerup) {
+ pr_err("%s: NULL pointer provided\n", __func__);
+ return -EINVAL;
+ }
+
+ pr_debug("%s: set power %d\n", __func__, *powerup);
+
+ val = ADV_REG_SETFIELD(*powerup, CEC_REG_CEC_POWER_UP);
+ rc = adv7481_wr_byte(&state->i2c_client, state->i2c_io_addr,
+ CEC_REG_CEC_POWER_UP_ADDR, val);
+
+ return rc;
+}
+
+static long adv7481_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg)
+{
+ struct adv7481_state *state = to_state(sd);
+ int *ret_val = arg;
+ long ret = 0;
+ int param = 0;
+
+ pr_debug("Enter %s with command: 0x%x", __func__, cmd);
+
+ if (!sd)
+ return -EINVAL;
+
+ switch (cmd) {
+ case VIDIOC_HDMI_RX_CEC_S_LOGICAL:
+ ret = adv7481_set_cec_logical_addr(state, arg);
+ break;
+ case VIDIOC_HDMI_RX_CEC_CLEAR_LOGICAL:
+ ret = adv7481_set_cec_logical_addr(state, &param);
+ break;
+ case VIDIOC_HDMI_RX_CEC_G_PHYSICAL:
+ if (ret_val) {
+ *ret_val = 0;
+ } else {
+ pr_err("%s: NULL pointer provided\n", __func__);
+ ret = -EINVAL;
+ }
+ break;
+ case VIDIOC_HDMI_RX_CEC_G_CONNECTED:
+ if (ret_val) {
+ *ret_val = state->cec_detected;
+ } else {
+ pr_err("%s: NULL pointer provided\n", __func__);
+ ret = -EINVAL;
+ }
+ break;
+ case VIDIOC_HDMI_RX_CEC_S_ENABLE:
+ ret = adv7481_cec_powerup(state, arg);
+ break;
+ default:
+ pr_err("Not a typewriter! Command: 0x%x", cmd);
+ ret = -ENOTTY;
+ break;
+ }
+ return ret;
+}
+
static int adv7481_get_sd_timings(struct adv7481_state *state, int *sd_standard)
{
int ret = 0;
@@ -620,18 +1058,22 @@ static int adv7481_get_sd_timings(struct adv7481_state *state, int *sd_standard)
if (sd_standard == NULL)
return -EINVAL;
+ /* Select SDP read-only main Map */
+ adv7481_wr_byte(&state->i2c_client, state->i2c_sdp_addr,
+ SDP_RW_MAP_REG, 0x01);
do {
- sdp_stat = adv7481_rd_byte(state->i2c_sdp,
- SDP_RO_MAIN_STATUS1_ADDR);
+ sdp_stat = adv7481_rd_byte(&state->i2c_client,
+ state->i2c_sdp_addr, SDP_RO_MAIN_STATUS1_ADDR);
usleep_range(SDP_MIN_SLEEP, SDP_MAX_SLEEP);
timeout++;
- sdp_stat2 = adv7481_rd_byte(state->i2c_sdp,
- SDP_RO_MAIN_STATUS1_ADDR);
+ sdp_stat2 = adv7481_rd_byte(&state->i2c_client,
+ state->i2c_sdp_addr, SDP_RO_MAIN_STATUS1_ADDR);
} while ((sdp_stat != sdp_stat2) && (timeout < SDP_NUM_TRIES));
+ adv7481_wr_byte(&state->i2c_client, state->i2c_sdp_addr,
+ SDP_RW_MAP_REG, 0x00);
if (sdp_stat != sdp_stat2) {
- pr_err("%s(%d), adv7481 SDP status unstable: 1\n",
- __func__, __LINE__);
+ pr_err("%s, adv7481 SDP status unstable: 1\n", __func__);
return -ETIMEDOUT;
}
@@ -681,22 +1123,50 @@ static int adv7481_set_cvbs_mode(struct adv7481_state *state)
pr_debug("Enter %s\n", __func__);
state->mode = ADV7481_IP_CVBS_1;
/* cvbs video settings ntsc etc */
- ret = adv7481_wr_byte(state->client, 0x00, 0x30);
- ret |= adv7481_wr_byte(state->i2c_sdp, 0x0f, 0x00);
- ret |= adv7481_wr_byte(state->i2c_sdp, 0x00, 0x00);
- ret |= adv7481_wr_byte(state->i2c_sdp, 0x03, 0x42);
- ret |= adv7481_wr_byte(state->i2c_sdp, 0x04, 0x07);
- ret |= adv7481_wr_byte(state->i2c_sdp, 0x13, 0x00);
- ret |= adv7481_wr_byte(state->i2c_sdp, 0x17, 0x41);
- ret |= adv7481_wr_byte(state->i2c_sdp, 0x31, 0x12);
- ret |= adv7481_wr_byte(state->i2c_sdp, 0x52, 0xcd);
- ret |= adv7481_wr_byte(state->i2c_sdp, 0x0e, 0xff);
- val = adv7481_rd_byte(state->client, IO_REG_CSI_PIX_EN_SEL_ADDR);
+ ret = adv7481_wr_byte(&state->i2c_client, state->i2c_io_addr,
+ 0x00, 0x30);
+ ret = adv7481_wr_byte(&state->i2c_client, state->i2c_io_addr,
+ 0x0e, 0xff);
+ ret |= adv7481_wr_byte(&state->i2c_client, state->i2c_sdp_addr,
+ 0x0f, 0x00);
+ ret |= adv7481_wr_byte(&state->i2c_client, state->i2c_sdp_addr,
+ 0x52, 0xcd);
+ ret |= adv7481_wr_byte(&state->i2c_client, state->i2c_sdp_addr,
+ 0x00, 0x00);
+ ret |= adv7481_wr_byte(&state->i2c_client, state->i2c_sdp_addr,
+ SDP_RW_MAP_REG, 0x80);
+ ret |= adv7481_wr_byte(&state->i2c_client, state->i2c_sdp_addr,
+ 0x9c, 0x00);
+ ret |= adv7481_wr_byte(&state->i2c_client, state->i2c_sdp_addr,
+ 0x9c, 0xff);
+ ret |= adv7481_wr_byte(&state->i2c_client, state->i2c_sdp_addr,
+ SDP_RW_MAP_REG, 0x00);
+ ret |= adv7481_wr_byte(&state->i2c_client, state->i2c_sdp_addr,
+ 0x80, 0x51);
+ ret |= adv7481_wr_byte(&state->i2c_client, state->i2c_sdp_addr,
+ 0x81, 0x51);
+ ret |= adv7481_wr_byte(&state->i2c_client, state->i2c_sdp_addr,
+ 0x82, 0x68);
+ ret |= adv7481_wr_byte(&state->i2c_client, state->i2c_sdp_addr,
+ 0x03, 0x42);
+ ret |= adv7481_wr_byte(&state->i2c_client, state->i2c_sdp_addr,
+ 0x04, 0x07);
+ ret |= adv7481_wr_byte(&state->i2c_client, state->i2c_sdp_addr,
+ 0x13, 0x00);
+ ret |= adv7481_wr_byte(&state->i2c_client, state->i2c_sdp_addr,
+ 0x17, 0x41);
+ ret |= adv7481_wr_byte(&state->i2c_client, state->i2c_sdp_addr,
+ 0x31, 0x12);
+
+ val = adv7481_rd_byte(&state->i2c_client, state->i2c_io_addr,
+ IO_REG_CSI_PIX_EN_SEL_ADDR);
/* Output of SD core routed to MIPI CSI 4-lane Tx */
- val |= ADV_REG_SETFIELD(0x10, IO_CTRL_CSI4_IN_SEL);
- ret |= adv7481_wr_byte(state->client, IO_REG_CSI_PIX_EN_SEL_ADDR, val);
- /* Enable autodetect */
- ret |= adv7481_wr_byte(state->i2c_sdp, 0x0e, 0x81);
+ val = ADV_REG_SETFIELD(1, IO_CTRL_CSI4_EN) |
+ ADV_REG_SETFIELD(1, IO_CTRL_PIX_OUT_EN) |
+ ADV_REG_SETFIELD(0x2, IO_CTRL_CSI4_IN_SEL);
+
+ ret |= adv7481_wr_byte(&state->i2c_client, state->i2c_io_addr,
+ IO_REG_CSI_PIX_EN_SEL_ADDR, val);
return ret;
}
@@ -713,69 +1183,101 @@ static int adv7481_set_hdmi_mode(struct adv7481_state *state)
* YUV 422 out via TxA CSI: 4-Lane
*/
/* Disable chip powerdown & Enable HDMI Rx block */
- temp = adv7481_rd_byte(state->client, IO_REG_PWR_DOWN_CTRL_ADDR);
+ temp = adv7481_rd_byte(&state->i2c_client, state->i2c_io_addr,
+ IO_REG_PWR_DOWN_CTRL_ADDR);
val = ADV_REG_SETFIELD(1, IO_CTRL_RX_EN) |
ADV_REG_SETFIELD(0, IO_CTRL_RX_PWDN) |
ADV_REG_SETFIELD(0, IO_CTRL_XTAL_PWDN) |
ADV_REG_SETFIELD(0, IO_CTRL_CORE_PWDN) |
ADV_REG_SETFIELD(0, IO_CTRL_MASTER_PWDN);
- ret = adv7481_wr_byte(state->client, IO_REG_PWR_DOWN_CTRL_ADDR, val);
+ ret = adv7481_wr_byte(&state->i2c_client, state->i2c_io_addr,
+ IO_REG_PWR_DOWN_CTRL_ADDR, val);
/* SDR mode */
- ret |= adv7481_wr_byte(state->client, 0x11, 0x48);
+ ret |= adv7481_wr_byte(&state->i2c_client, state->i2c_io_addr,
+ 0x11, 0x48);
/* Set CP core to YUV out */
- ret |= adv7481_wr_byte(state->client, 0x04, 0x00);
+ ret |= adv7481_wr_byte(&state->i2c_client, state->i2c_io_addr,
+ 0x04, 0x00);
/* Set CP core to SDR 422 */
- ret |= adv7481_wr_byte(state->client, 0x12, 0xF2);
+ ret |= adv7481_wr_byte(&state->i2c_client, state->i2c_io_addr,
+ 0x12, 0xF2);
/* Saturate both Luma and Chroma values to 254 */
- ret |= adv7481_wr_byte(state->client, 0x17, 0x80);
+ ret |= adv7481_wr_byte(&state->i2c_client, state->i2c_io_addr,
+ 0x17, 0x80);
/* Set CP core to enable AV codes */
- ret |= adv7481_wr_byte(state->client, 0x03, 0x86);
+ ret |= adv7481_wr_byte(&state->i2c_client, state->i2c_io_addr,
+ 0x03, 0x86);
/* ADI RS CP Core: */
- ret |= adv7481_wr_byte(state->i2c_cp, 0x7C, 0x00);
+ ret |= adv7481_wr_byte(&state->i2c_client, state->i2c_cp_addr,
+ 0x7C, 0x00);
/* Set CP core Phase Adjustment */
- ret |= adv7481_wr_byte(state->client, 0x0C, 0xE0);
+ ret |= adv7481_wr_byte(&state->i2c_client, state->i2c_io_addr,
+ 0x0C, 0xE0);
/* LLC/PIX/SPI PINS TRISTATED AUD Outputs Enabled */
- ret |= adv7481_wr_byte(state->client, IO_PAD_CTRLS_ADDR, 0xDD);
+ ret |= adv7481_wr_byte(&state->i2c_client, state->i2c_io_addr,
+ IO_PAD_CTRLS_ADDR, 0xDD);
/* Enable Tx A CSI 4-Lane & data from CP core */
val = ADV_REG_SETFIELD(1, IO_CTRL_CSI4_EN) |
ADV_REG_SETFIELD(1, IO_CTRL_PIX_OUT_EN) |
ADV_REG_SETFIELD(0, IO_CTRL_CSI4_IN_SEL);
- ret |= adv7481_wr_byte(state->client, IO_REG_CSI_PIX_EN_SEL_ADDR,
- val);
+ ret |= adv7481_wr_byte(&state->i2c_client, state->i2c_io_addr,
+ IO_REG_CSI_PIX_EN_SEL_ADDR, val);
/* start to configure HDMI Rx once io-map is configured */
/* Enable HDCP 1.1 */
- ret |= adv7481_wr_byte(state->i2c_rep, 0x40, 0x83);
+ ret |= adv7481_wr_byte(&state->i2c_client, state->i2c_rep_addr,
+ 0x40, 0x83);
/* Foreground Channel = A */
- ret |= adv7481_wr_byte(state->i2c_hdmi, 0x00, 0x08);
+ ret |= adv7481_wr_byte(&state->i2c_client, state->i2c_hdmi_addr,
+ 0x00, 0x08);
/* ADI Required Write */
- ret |= adv7481_wr_byte(state->i2c_hdmi, 0x98, 0xFF);
- ret |= adv7481_wr_byte(state->i2c_hdmi, 0x99, 0xA3);
- ret |= adv7481_wr_byte(state->i2c_hdmi, 0x9A, 0x00);
- ret |= adv7481_wr_byte(state->i2c_hdmi, 0x9B, 0x0A);
- ret |= adv7481_wr_byte(state->i2c_hdmi, 0x9D, 0x40);
- ret |= adv7481_wr_byte(state->i2c_hdmi, 0xCB, 0x09);
+ ret |= adv7481_wr_byte(&state->i2c_client, state->i2c_hdmi_addr,
+ 0x98, 0xFF);
+ ret |= adv7481_wr_byte(&state->i2c_client, state->i2c_hdmi_addr,
+ 0x99, 0xA3);
+ ret |= adv7481_wr_byte(&state->i2c_client, state->i2c_hdmi_addr,
+ 0x9A, 0x00);
+ ret |= adv7481_wr_byte(&state->i2c_client, state->i2c_hdmi_addr,
+ 0x9B, 0x0A);
+ ret |= adv7481_wr_byte(&state->i2c_client, state->i2c_hdmi_addr,
+ 0x9D, 0x40);
+ ret |= adv7481_wr_byte(&state->i2c_client, state->i2c_hdmi_addr,
+ 0xCB, 0x09);
/* ADI RS */
- ret |= adv7481_wr_byte(state->i2c_hdmi, 0x3D, 0x10);
- ret |= adv7481_wr_byte(state->i2c_hdmi, 0x3E, 0x7B);
- ret |= adv7481_wr_byte(state->i2c_hdmi, 0x3F, 0x5E);
- ret |= adv7481_wr_byte(state->i2c_hdmi, 0x4E, 0xFE);
- ret |= adv7481_wr_byte(state->i2c_hdmi, 0x4F, 0x18);
- ret |= adv7481_wr_byte(state->i2c_hdmi, 0x57, 0xA3);
- ret |= adv7481_wr_byte(state->i2c_hdmi, 0x58, 0x04);
- ret |= adv7481_wr_byte(state->i2c_hdmi, 0x85, 0x10);
+ ret |= adv7481_wr_byte(&state->i2c_client, state->i2c_hdmi_addr,
+ 0x3D, 0x10);
+ ret |= adv7481_wr_byte(&state->i2c_client, state->i2c_hdmi_addr,
+ 0x3E, 0x7B);
+ ret |= adv7481_wr_byte(&state->i2c_client, state->i2c_hdmi_addr,
+ 0x3F, 0x5E);
+ ret |= adv7481_wr_byte(&state->i2c_client, state->i2c_hdmi_addr,
+ 0x4E, 0xFE);
+ ret |= adv7481_wr_byte(&state->i2c_client, state->i2c_hdmi_addr,
+ 0x4F, 0x18);
+ ret |= adv7481_wr_byte(&state->i2c_client, state->i2c_hdmi_addr,
+ 0x57, 0xA3);
+ ret |= adv7481_wr_byte(&state->i2c_client, state->i2c_hdmi_addr,
+ 0x58, 0x04);
+ ret |= adv7481_wr_byte(&state->i2c_client, state->i2c_hdmi_addr,
+ 0x85, 0x10);
/* Enable All Terminations */
- ret |= adv7481_wr_byte(state->i2c_hdmi, 0x83, 0x00);
+ ret |= adv7481_wr_byte(&state->i2c_client, state->i2c_hdmi_addr,
+ 0x83, 0x00);
/* ADI RS */
- ret |= adv7481_wr_byte(state->i2c_hdmi, 0xA3, 0x01);
- ret |= adv7481_wr_byte(state->i2c_hdmi, 0xBE, 0x00);
+ ret |= adv7481_wr_byte(&state->i2c_client, state->i2c_hdmi_addr,
+ 0xA3, 0x01);
+ ret |= adv7481_wr_byte(&state->i2c_client, state->i2c_hdmi_addr,
+ 0xBE, 0x00);
/* HPA Manual Enable */
- ret |= adv7481_wr_byte(state->i2c_hdmi, 0x6C, 0x01);
+ ret |= adv7481_wr_byte(&state->i2c_client, state->i2c_hdmi_addr,
+ 0x6C, 0x01);
/* HPA Asserted */
- ret |= adv7481_wr_byte(state->i2c_hdmi, 0xF8, 0x01);
+ ret |= adv7481_wr_byte(&state->i2c_client, state->i2c_hdmi_addr,
+ 0xF8, 0x01);
/* Audio Mute Speed Set to Fastest (Smallest Step Size) */
- ret |= adv7481_wr_byte(state->i2c_hdmi, 0x0F, 0x00);
+ ret |= adv7481_wr_byte(&state->i2c_client, state->i2c_hdmi_addr,
+ 0x0F, 0x00);
return ret;
}
@@ -860,7 +1362,7 @@ static int adv7481_set_ip_mode(struct adv7481_state *state, int input)
}
static int adv7481_set_op_src(struct adv7481_state *state,
- int output, int input)
+ int output, int input)
{
int ret = 0;
int temp = 0;
@@ -897,10 +1399,11 @@ static int adv7481_set_op_src(struct adv7481_state *state,
default:
ret = -EINVAL;
}
- temp = adv7481_rd_byte(state->client,
+ temp = adv7481_rd_byte(&state->i2c_client, state->i2c_io_addr,
IO_REG_PWR_DOWN_CTRL_ADDR);
temp |= val;
- adv7481_wr_byte(state->client, IO_REG_PWR_DOWN_CTRL_ADDR, temp);
+ adv7481_wr_byte(&state->i2c_client, state->i2c_io_addr,
+ IO_REG_PWR_DOWN_CTRL_ADDR, temp);
state->csia_src = input;
break;
case ADV7481_OP_CSIB:
@@ -915,11 +1418,11 @@ static int adv7481_set_op_src(struct adv7481_state *state,
return ret;
}
-static u32 ba_inp_to_adv7481(u32 input)
+static u32 ba_inp_to_adv7481(u32 ba_input)
{
u32 adv_input = ADV7481_IP_HDMI;
- switch (input) {
+ switch (ba_input) {
case BA_IP_CVBS_0:
adv_input = ADV7481_IP_CVBS_1;
break;
@@ -954,6 +1457,42 @@ static u32 ba_inp_to_adv7481(u32 input)
return adv_input;
}
+static u32 adv7481_inp_to_ba(u32 adv_input)
+{
+ u32 ba_input = BA_IP_HDMI_1;
+
+ switch (adv_input) {
+ case ADV7481_IP_CVBS_1:
+ ba_input = BA_IP_CVBS_0;
+ break;
+ case ADV7481_IP_CVBS_2:
+ ba_input = BA_IP_CVBS_1;
+ break;
+ case ADV7481_IP_CVBS_3:
+ ba_input = BA_IP_CVBS_2;
+ break;
+ case ADV7481_IP_CVBS_4:
+ ba_input = BA_IP_CVBS_3;
+ break;
+ case ADV7481_IP_CVBS_5:
+ ba_input = BA_IP_CVBS_4;
+ break;
+ case ADV7481_IP_CVBS_6:
+ ba_input = BA_IP_CVBS_5;
+ break;
+ case ADV7481_IP_HDMI:
+ ba_input = BA_IP_HDMI_1;
+ break;
+ case ADV7481_IP_TTL:
+ ba_input = BA_IP_TTL;
+ break;
+ default:
+ ba_input = BA_IP_HDMI_1;
+ break;
+ }
+ return ba_input;
+}
+
static int adv7481_s_routing(struct v4l2_subdev *sd, u32 input,
u32 output, u32 config)
{
@@ -971,14 +1510,11 @@ static int adv7481_s_routing(struct v4l2_subdev *sd, u32 input,
goto unlock_exit;
}
- if (state->mode != adv_input) {
- ret = adv7481_set_ip_mode(state, adv_input);
- if (ret)
- pr_err("%s: Set input mode failed: %d\n",
- __func__, ret);
- else
- state->mode = adv_input;
- }
+ ret = adv7481_set_ip_mode(state, adv_input);
+ if (ret)
+ pr_err("%s: Set input mode failed: %d\n", __func__, ret);
+ else
+ state->mode = adv_input;
unlock_exit:
mutex_unlock(&state->mutex);
@@ -986,6 +1522,27 @@ unlock_exit:
return ret;
}
+static bool adv7481_is_timing_locked(struct adv7481_state *state)
+{
+ bool ret = false;
+ int val1 = 0;
+ int val2 = 0;
+
+ /* Check Timing Lock IO Map Status3:0x71[0] && 0x71[1] && 0x71[7] */
+ val1 = adv7481_rd_byte(&state->i2c_client, state->i2c_io_addr,
+ IO_HDMI_LVL_RAW_STATUS_3_ADDR);
+ val2 = adv7481_rd_byte(&state->i2c_client, state->i2c_cp_addr,
+ CP_REG_STDI_CH_ADDR);
+
+ if (ADV_REG_GETFIELD(val1, IO_DE_REGEN_LCK_RAW) &&
+ ADV_REG_GETFIELD(val1, IO_V_LOCKED_RAW) &&
+ ADV_REG_GETFIELD(val1, IO_TMDSPLL_LCK_A_RAW) &&
+ ADV_REG_GETFIELD(val2, CP_STDI_DVALID_CH1))
+ ret = true;
+
+ return ret;
+}
+
static int adv7481_get_hdmi_timings(struct adv7481_state *state,
struct adv7481_vid_params *vid_params,
struct adv7481_hdmi_params *hdmi_params)
@@ -998,13 +1555,15 @@ static int adv7481_get_hdmi_timings(struct adv7481_state *state,
pr_debug("Enter %s\n", __func__);
/* Check TMDS PLL Lock and Frequency */
- temp1 = adv7481_rd_byte(state->i2c_hdmi, HDMI_REG_HDMI_PARAM4_ADDR);
+ temp1 = adv7481_rd_byte(&state->i2c_client, state->i2c_hdmi_addr,
+ HDMI_REG_HDMI_PARAM4_ADDR);
hdmi_params->pll_lock = ADV_REG_GETFIELD(temp1,
HDMI_REG_TMDS_PLL_LOCKED);
if (hdmi_params->pll_lock) {
- temp1 = adv7481_rd_byte(state->i2c_hdmi,
- HDMI_REG_TMDS_FREQ_ADDR);
- temp2 = adv7481_rd_byte(state->i2c_hdmi,
+ temp1 = adv7481_rd_byte(&state->i2c_client,
+ state->i2c_hdmi_addr, HDMI_REG_TMDS_FREQ_ADDR);
+ temp2 = adv7481_rd_byte(&state->i2c_client,
+ state->i2c_hdmi_addr,
HDMI_REG_TMDS_FREQ_FRAC_ADDR);
hdmi_params->tmds_freq = ADV_REG_GETFIELD(temp1,
HDMI_REG_TMDS_FREQ);
@@ -1015,34 +1574,29 @@ static int adv7481_get_hdmi_timings(struct adv7481_state *state,
hdmi_params->tmds_freq += ADV_REG_GETFIELD(temp2,
HDMI_REG_TMDS_FREQ_FRAC)*ONE_MHZ_TO_HZ/128;
} else {
- pr_err("%s: PLL not locked return EBUSY\n", __func__);
- return -EBUSY;
+ pr_err("%s(%d): PLL not locked return EBUSY\n",
+ __func__, __LINE__);
+ ret = -EBUSY;
+ goto set_default;
}
- /* Check Timing Lock IO Map Status3:0x71[0] && 0x71[1] && 0x71[7] */
+ /* Check Timing Lock */
do {
- temp1 = adv7481_rd_byte(state->client,
- IO_HDMI_LVL_RAW_STATUS_3_ADDR);
- temp2 = adv7481_rd_byte(state->i2c_cp,
- CP_REG_STDI_CH_ADDR);
-
- if (ADV_REG_GETFIELD(temp1, IO_DE_REGEN_LCK_RAW) &&
- ADV_REG_GETFIELD(temp1, IO_V_LOCKED_RAW) &&
- ADV_REG_GETFIELD(temp1, IO_TMDSPLL_LCK_A_RAW) &&
- ADV_REG_GETFIELD(temp2, CP_STDI_DVALID_CH1))
+ if (adv7481_is_timing_locked(state))
break;
count++;
usleep_range(LOCK_MIN_SLEEP, LOCK_MAX_SLEEP);
} while (count < LOCK_NUM_TRIES);
if (count >= LOCK_NUM_TRIES) {
- pr_err("%s(%d), adv7481 HDMI DE regeneration block NOT Locked: 0x%x",
- __func__, __LINE__, temp1);
+ pr_err("%s(%d), HDMI DE regeneration block NOT Locked\n",
+ __func__, __LINE__);
}
/* Check Timing Lock HDMI Map V:0x07[7], H:0x7[5] */
do {
- temp1 = adv7481_rd_byte(state->i2c_hdmi,
+ temp1 = adv7481_rd_byte(&state->i2c_client,
+ state->i2c_hdmi_addr,
HDMI_REG_LINE_WIDTH_1_ADDR);
if (ADV_REG_GETFIELD(temp1, HDMI_VERT_FILTER_LOCKED) &&
@@ -1059,7 +1613,8 @@ static int adv7481_get_hdmi_timings(struct adv7481_state *state,
}
/* Check HDMI Parameters */
- temp1 = adv7481_rd_byte(state->i2c_hdmi, HDMI_REG_FIELD1_HEIGHT1_ADDR);
+ temp1 = adv7481_rd_byte(&state->i2c_client, state->i2c_hdmi_addr,
+ HDMI_REG_FIELD1_HEIGHT1_ADDR);
hdmi_params->color_depth = ADV_REG_GETFIELD(temp1,
HDMI_REG_DEEP_COLOR_MODE);
@@ -1068,22 +1623,25 @@ static int adv7481_get_hdmi_timings(struct adv7481_state *state,
HDMI_REG_HDMI_INTERLACED);
fieldfactor = (vid_params->intrlcd == 1) ? 2 : 1;
- temp1 = adv7481_rd_byte(state->i2c_hdmi, HDMI_REG_HDMI_PARAM5_ADDR);
+ temp1 = adv7481_rd_byte(&state->i2c_client, state->i2c_hdmi_addr,
+ HDMI_REG_HDMI_PARAM5_ADDR);
hdmi_params->pix_rep = ADV_REG_GETFIELD(temp1,
HDMI_REG_PIXEL_REPETITION);
/* Get Active Timing Data HDMI Map H:0x07[4:0] + 0x08[7:0] */
- temp1 = adv7481_rd_byte(state->i2c_hdmi, HDMI_REG_LINE_WIDTH_1_ADDR);
- temp2 = adv7481_rd_byte(state->i2c_hdmi, HDMI_REG_LINE_WIDTH_2_ADDR);
+ temp1 = adv7481_rd_byte(&state->i2c_client, state->i2c_hdmi_addr,
+ HDMI_REG_LINE_WIDTH_1_ADDR);
+ temp2 = adv7481_rd_byte(&state->i2c_client, state->i2c_hdmi_addr,
+ HDMI_REG_LINE_WIDTH_2_ADDR);
vid_params->act_pix = (((ADV_REG_GETFIELD(temp1,
HDMI_REG_LINE_WIDTH_1) << 8) & 0x1F00) |
ADV_REG_GETFIELD(temp2,
HDMI_REG_LINE_WIDTH_2));
/* Get Total Timing Data HDMI Map H:0x1E[5:0] + 0x1F[7:0] */
- temp1 = adv7481_rd_byte(state->i2c_hdmi,
+ temp1 = adv7481_rd_byte(&state->i2c_client, state->i2c_hdmi_addr,
HDMI_REG_TOTAL_LINE_WIDTH_1_ADDR);
- temp2 = adv7481_rd_byte(state->i2c_hdmi,
+ temp2 = adv7481_rd_byte(&state->i2c_client, state->i2c_hdmi_addr,
HDMI_REG_TOTAL_LINE_WIDTH_2_ADDR);
vid_params->tot_pix = (((ADV_REG_GETFIELD(temp1,
HDMI_REG_TOTAL_LINE_WIDTH_1) << 8) & 0x3F00) |
@@ -1091,9 +1649,9 @@ static int adv7481_get_hdmi_timings(struct adv7481_state *state,
HDMI_REG_TOTAL_LINE_WIDTH_2));
/* Get Active Timing Data HDMI Map V:0x09[4:0] + 0x0A[7:0] */
- temp1 = adv7481_rd_byte(state->i2c_hdmi,
+ temp1 = adv7481_rd_byte(&state->i2c_client, state->i2c_hdmi_addr,
HDMI_REG_FIELD0_HEIGHT_1_ADDR);
- temp2 = adv7481_rd_byte(state->i2c_hdmi,
+ temp2 = adv7481_rd_byte(&state->i2c_client, state->i2c_hdmi_addr,
HDMI_REG_FIELD0_HEIGHT_2_ADDR);
vid_params->act_lines = (((ADV_REG_GETFIELD(temp1,
HDMI_REG_FIELD0_HEIGHT_1) << 8) & 0x1F00) |
@@ -1101,9 +1659,9 @@ static int adv7481_get_hdmi_timings(struct adv7481_state *state,
HDMI_REG_FIELD0_HEIGHT_2));
/* Get Total Timing Data HDMI Map V:0x26[5:0] + 0x27[7:0] */
- temp1 = adv7481_rd_byte(state->i2c_hdmi,
+ temp1 = adv7481_rd_byte(&state->i2c_client, state->i2c_hdmi_addr,
HDMI_REG_FIELD0_TOTAL_HEIGHT_1_ADDR);
- temp2 = adv7481_rd_byte(state->i2c_hdmi,
+ temp2 = adv7481_rd_byte(&state->i2c_client, state->i2c_hdmi_addr,
HDMI_REG_FIELD0_TOTAL_HEIGHT_2_ADDR);
vid_params->tot_lines = (((ADV_REG_GETFIELD(temp1,
HDMI_REG_FIELD0_TOT_HEIGHT_1) << 8) & 0x3F00) |
@@ -1139,6 +1697,18 @@ static int adv7481_get_hdmi_timings(struct adv7481_state *state,
(hdmi_params->pix_rep + 1));
}
+set_default:
+ if (ret) {
+ pr_debug("%s(%d), error %d resort to default fmt\n",
+ __func__, __LINE__, ret);
+ vid_params->act_pix = MAX_DEFAULT_WIDTH;
+ vid_params->act_lines = MAX_DEFAULT_HEIGHT;
+ vid_params->fr_rate = MAX_DEFAULT_FRAME_RATE;
+ vid_params->pix_clk = MAX_DEFAULT_PIX_CLK_HZ;
+ vid_params->intrlcd = 0;
+ ret = 0;
+ }
+
pr_debug("%s(%d), adv7481 TMDS Resolution: %d x %d @ %d fps\n",
__func__, __LINE__,
vid_params->act_pix, vid_params->act_lines,
@@ -1170,15 +1740,22 @@ static int adv7481_query_dv_timings(struct v4l2_subdev *sd,
switch (state->mode) {
case ADV7481_IP_HDMI:
case ADV7481_IP_CVBS_1_HDMI_SIM:
- adv7481_get_hdmi_timings(state, &vid_params, &hdmi_params);
- timings->type = V4L2_DV_BT_656_1120;
- bt_timings->width = vid_params.act_pix;
- bt_timings->height = vid_params.act_lines;
- bt_timings->pixelclock = vid_params.pix_clk;
- bt_timings->interlaced = vid_params.intrlcd ?
+ ret = adv7481_get_hdmi_timings(state, &vid_params,
+ &hdmi_params);
+ if (!ret) {
+ timings->type = V4L2_DV_BT_656_1120;
+ bt_timings->width = vid_params.act_pix;
+ bt_timings->height = vid_params.act_lines;
+ bt_timings->pixelclock = vid_params.pix_clk;
+ bt_timings->interlaced = vid_params.intrlcd ?
V4L2_DV_INTERLACED : V4L2_DV_PROGRESSIVE;
- if (bt_timings->interlaced == V4L2_DV_INTERLACED)
- bt_timings->height /= 2;
+ if (bt_timings->interlaced == V4L2_DV_INTERLACED)
+ bt_timings->height /= 2;
+ } else {
+ pr_err(
+ "%s: Error in adv7481_get_hdmi_timings. ret %d\n",
+ __func__, ret);
+ }
break;
default:
return -EINVAL;
@@ -1193,10 +1770,24 @@ static int adv7481_query_sd_std(struct v4l2_subdev *sd, v4l2_std_id *std)
int temp = 0;
struct adv7481_state *state = to_state(sd);
uint8_t tStatus = 0x0;
+ uint32_t count = 0;
pr_debug("Enter %s\n", __func__);
- tStatus = adv7481_rd_byte(state->i2c_sdp, SDP_RO_MAIN_STATUS1_ADDR);
- if (!ADV_REG_GETFIELD(tStatus, SDP_RO_MAIN_IN_LOCK))
+ /* Select SDP read-only main Map */
+ adv7481_wr_byte(&state->i2c_client, state->i2c_sdp_addr,
+ SDP_RW_MAP_REG, 0x01);
+ do {
+ tStatus = adv7481_rd_byte(&state->i2c_client,
+ state->i2c_sdp_addr, SDP_RO_MAIN_STATUS1_ADDR);
+ if (ADV_REG_GETFIELD(tStatus, SDP_RO_MAIN_IN_LOCK))
+ break;
+ count++;
+ usleep_range(LOCK_MIN_SLEEP, LOCK_MAX_SLEEP);
+ } while (count < LOCK_NUM_TRIES);
+
+ adv7481_wr_byte(&state->i2c_client, state->i2c_sdp_addr,
+ SDP_RW_MAP_REG, 0x00);
+ if (count >= LOCK_NUM_TRIES)
pr_err("%s(%d), adv7481 SD Input NOT Locked: 0x%x\n",
__func__, __LINE__, tStatus);
@@ -1245,13 +1836,15 @@ static int adv7481_g_frame_interval(struct v4l2_subdev *sd,
return 0;
}
-static int adv7481_g_mbus_fmt(struct v4l2_subdev *sd,
- struct v4l2_mbus_framefmt *fmt)
+static int adv7481_get_fmt(struct v4l2_subdev *sd,
+ struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_format *format)
{
int ret;
struct adv7481_vid_params vid_params;
struct adv7481_hdmi_params hdmi_params;
struct adv7481_state *state = to_state(sd);
+ struct v4l2_mbus_framefmt *fmt = &format->format;
if (!fmt)
return -EINVAL;
@@ -1267,17 +1860,29 @@ static int adv7481_g_mbus_fmt(struct v4l2_subdev *sd,
switch (state->mode) {
case ADV7481_IP_HDMI:
case ADV7481_IP_CVBS_1_HDMI_SIM:
- adv7481_get_hdmi_timings(state, &vid_params, &hdmi_params);
- fmt->width = vid_params.act_pix;
- fmt->height = vid_params.act_lines;
- if (vid_params.intrlcd)
- fmt->height /= 2;
+ ret = adv7481_get_hdmi_timings(state, &vid_params,
+ &hdmi_params);
+ if (!ret) {
+ fmt->width = vid_params.act_pix;
+ fmt->height = vid_params.act_lines;
+ if (vid_params.intrlcd)
+ fmt->height /= 2;
+ } else {
+ pr_err("%s: Error %d in adv7481_get_hdmi_timings\n",
+ __func__, ret);
+ }
+ break;
+ case ADV7481_IP_CVBS_1:
+ fmt->code = MEDIA_BUS_FMT_UYVY8_2X8;
+ fmt->colorspace = V4L2_COLORSPACE_SMPTE170M;
+ fmt->width = 720;
+ fmt->height = 576;
break;
default:
return -EINVAL;
}
mutex_unlock(&state->mutex);
- fmt->code = V4L2_MBUS_FMT_UYVY8_2X8;
+ fmt->code = MEDIA_BUS_FMT_UYVY8_2X8;
fmt->colorspace = V4L2_COLORSPACE_SMPTE170M;
return ret;
}
@@ -1290,17 +1895,17 @@ static int adv7481_set_audio_spdif(struct adv7481_state *state,
if (on) {
/* Configure I2S_SDATA output pin as an SPDIF output 0x6E[3] */
- val = adv7481_rd_byte(state->i2c_hdmi,
+ val = adv7481_rd_byte(&state->i2c_client, state->i2c_hdmi_addr,
HDMI_REG_MUX_SPDIF_TO_I2S_ADDR);
val |= ADV_REG_SETFIELD(1, HDMI_MUX_SPDIF_TO_I2S_EN);
- ret = adv7481_wr_byte(state->i2c_hdmi,
+ ret = adv7481_wr_byte(&state->i2c_client, state->i2c_hdmi_addr,
HDMI_REG_MUX_SPDIF_TO_I2S_ADDR, val);
} else {
/* Configure I2S_SDATA output pin as an I2S output 0x6E[3] */
- val = adv7481_rd_byte(state->i2c_hdmi,
+ val = adv7481_rd_byte(&state->i2c_client, state->i2c_hdmi_addr,
HDMI_REG_MUX_SPDIF_TO_I2S_ADDR);
val &= ~ADV_REG_SETFIELD(1, HDMI_MUX_SPDIF_TO_I2S_EN);
- ret = adv7481_wr_byte(state->i2c_hdmi,
+ ret = adv7481_wr_byte(&state->i2c_client, state->i2c_hdmi_addr,
HDMI_REG_MUX_SPDIF_TO_I2S_ADDR, val);
}
return ret;
@@ -1310,40 +1915,42 @@ static int adv7481_csi_powerdown(struct adv7481_state *state,
enum adv7481_output output)
{
int ret;
- struct i2c_client *csi_map;
+ uint8_t csi_map;
uint8_t val = 0;
pr_debug("Enter %s for output: %d\n", __func__, output);
/* Select CSI TX to configure data */
if (output == ADV7481_OP_CSIA) {
- csi_map = state->i2c_csi_txa;
+ csi_map = state->i2c_csi_txa_addr;
} else if (output == ADV7481_OP_CSIB) {
- csi_map = state->i2c_csi_txb;
+ csi_map = state->i2c_csi_txb_addr;
} else if (output == ADV7481_OP_TTL) {
/* For now use TxA */
- csi_map = state->i2c_csi_txa;
+ csi_map = state->i2c_csi_txa_addr;
} else {
/* Default to TxA */
- csi_map = state->i2c_csi_txa;
+ csi_map = state->i2c_csi_txa_addr;
}
/* CSI Tx: power down DPHY */
- ret = adv7481_wr_byte(csi_map, CSI_REG_TX_DPHY_PWDN_ADDR,
+ ret = adv7481_wr_byte(&state->i2c_client, csi_map,
+ CSI_REG_TX_DPHY_PWDN_ADDR,
ADV_REG_SETFIELD(1, CSI_CTRL_DPHY_PWDN));
/* ADI Required Write */
- ret |= adv7481_wr_byte(csi_map, 0x31, 0x82);
- ret |= adv7481_wr_byte(csi_map, 0x1e, 0x00);
+ ret |= adv7481_wr_byte(&state->i2c_client, csi_map, 0x31, 0x82);
+ ret |= adv7481_wr_byte(&state->i2c_client, csi_map, 0x1e, 0x00);
/* CSI TxA: # Lane : Power Off */
val = ADV_REG_SETFIELD(1, CSI_CTRL_TX_PWRDN) |
ADV_REG_SETFIELD(state->tx_lanes, CSI_CTRL_NUM_LANES);
- ret |= adv7481_wr_byte(csi_map, CSI_REG_TX_CFG1_ADDR, val);
+ ret |= adv7481_wr_byte(&state->i2c_client, csi_map,
+ CSI_REG_TX_CFG1_ADDR, val);
/*
* ADI Recommended power down sequence
* DPHY and CSI Tx A Power down Sequence
* CSI TxA: MIPI PLL DIS
*/
- ret |= adv7481_wr_byte(csi_map, 0xda, 0x00);
+ ret |= adv7481_wr_byte(&state->i2c_client, csi_map, 0xda, 0x00);
/* ADI Required Write */
- ret |= adv7481_wr_byte(csi_map, 0xc1, 0x3b);
+ ret |= adv7481_wr_byte(&state->i2c_client, csi_map, 0xc1, 0x3b);
pr_debug("Exit %s, ret: %d\n", __func__, ret);
@@ -1354,17 +1961,23 @@ static int adv7481_csi_powerup(struct adv7481_state *state,
enum adv7481_output output)
{
int ret;
- struct i2c_client *csi_map;
+ uint8_t csi_map;
uint8_t val = 0;
uint8_t csi_sel = 0;
pr_debug("Enter %s for output: %d\n", __func__, output);
/* Select CSI TX to configure data */
if (output == ADV7481_OP_CSIA) {
- csi_sel = ADV_REG_SETFIELD(1, IO_CTRL_CSI4_EN) |
- ADV_REG_SETFIELD(1, IO_CTRL_PIX_OUT_EN) |
- ADV_REG_SETFIELD(0, IO_CTRL_CSI4_IN_SEL);
- csi_map = state->i2c_csi_txa;
+ if (state->csia_src == ADV7481_IP_HDMI) {
+ csi_sel = ADV_REG_SETFIELD(1, IO_CTRL_CSI4_EN) |
+ ADV_REG_SETFIELD(1, IO_CTRL_PIX_OUT_EN) |
+ ADV_REG_SETFIELD(0, IO_CTRL_CSI4_IN_SEL);
+ } else {
+ csi_sel = ADV_REG_SETFIELD(1, IO_CTRL_CSI4_EN) |
+ ADV_REG_SETFIELD(1, IO_CTRL_PIX_OUT_EN) |
+ ADV_REG_SETFIELD(0x2, IO_CTRL_CSI4_IN_SEL);
+ }
+ csi_map = state->i2c_csi_txa_addr;
} else if (output == ADV7481_OP_CSIB) {
/* Enable 1-Lane MIPI Tx, enable pixel output and
* route SD through Pixel port
@@ -1373,54 +1986,57 @@ static int adv7481_csi_powerup(struct adv7481_state *state,
ADV_REG_SETFIELD(1, IO_CTRL_PIX_OUT_EN) |
ADV_REG_SETFIELD(1, IO_CTRL_SD_THRU_PIX_OUT) |
ADV_REG_SETFIELD(0, IO_CTRL_CSI4_IN_SEL);
- csi_map = state->i2c_csi_txb;
+ csi_map = state->i2c_csi_txb_addr;
} else if (output == ADV7481_OP_TTL) {
/* For now use TxA */
- csi_map = state->i2c_csi_txa;
+ csi_map = state->i2c_csi_txa_addr;
} else {
/* Default to TxA */
- csi_map = state->i2c_csi_txa;
+ csi_map = state->i2c_csi_txa_addr;
}
/* Enable Tx A/B CSI #-lane */
- ret = adv7481_wr_byte(state->client,
+ ret = adv7481_wr_byte(&state->i2c_client, state->i2c_io_addr,
IO_REG_CSI_PIX_EN_SEL_ADDR, csi_sel);
/* TXA MIPI lane settings for CSI */
/* CSI TxA: # Lane : Power Off */
val = ADV_REG_SETFIELD(1, CSI_CTRL_TX_PWRDN) |
ADV_REG_SETFIELD(state->tx_lanes, CSI_CTRL_NUM_LANES);
- ret |= adv7481_wr_byte(csi_map, CSI_REG_TX_CFG1_ADDR, val);
+ ret |= adv7481_wr_byte(&state->i2c_client, csi_map,
+ CSI_REG_TX_CFG1_ADDR, val);
/* CSI TxA: Auto D-PHY Timing */
val |= ADV_REG_SETFIELD(1, CSI_CTRL_AUTO_PARAMS);
- ret |= adv7481_wr_byte(csi_map, CSI_REG_TX_CFG1_ADDR, val);
+ ret |= adv7481_wr_byte(&state->i2c_client, csi_map,
+ CSI_REG_TX_CFG1_ADDR, val);
/* DPHY and CSI Tx A */
- ret |= adv7481_wr_byte(csi_map, 0xdb, 0x10);
- ret |= adv7481_wr_byte(csi_map, 0xd6, 0x07);
- ret |= adv7481_wr_byte(csi_map, 0xc4, 0x0a);
- ret |= adv7481_wr_byte(csi_map, 0x71, 0x33);
- ret |= adv7481_wr_byte(csi_map, 0x72, 0x11);
+ ret |= adv7481_wr_byte(&state->i2c_client, csi_map, 0xdb, 0x10);
+ ret |= adv7481_wr_byte(&state->i2c_client, csi_map, 0xd6, 0x07);
+ ret |= adv7481_wr_byte(&state->i2c_client, csi_map, 0xc4, 0x0a);
+ ret |= adv7481_wr_byte(&state->i2c_client, csi_map, 0x71, 0x33);
+ ret |= adv7481_wr_byte(&state->i2c_client, csi_map, 0x72, 0x11);
/* CSI TxA: power up DPHY */
- ret |= adv7481_wr_byte(csi_map, 0xf0, 0x00);
+ ret |= adv7481_wr_byte(&state->i2c_client, csi_map, 0xf0, 0x00);
/* ADI Required Write */
- ret |= adv7481_wr_byte(csi_map, 0x31, 0x82);
- ret |= adv7481_wr_byte(csi_map, 0x1e, 0x40);
+ ret |= adv7481_wr_byte(&state->i2c_client, csi_map, 0x31, 0x82);
+ ret |= adv7481_wr_byte(&state->i2c_client, csi_map, 0x1e, 0x40);
/* adi Recommended power up sequence */
/* DPHY and CSI Tx A Power up Sequence */
/* CSI TxA: MIPI PLL EN */
- ret |= adv7481_wr_byte(csi_map, 0xda, 0x01);
+ ret |= adv7481_wr_byte(&state->i2c_client, csi_map, 0xda, 0x01);
msleep(200);
/* CSI TxA: # MIPI Lane : Power ON */
val = ADV_REG_SETFIELD(0, CSI_CTRL_TX_PWRDN) |
ADV_REG_SETFIELD(1, CSI_CTRL_AUTO_PARAMS) |
ADV_REG_SETFIELD(state->tx_lanes, CSI_CTRL_NUM_LANES);
- ret |= adv7481_wr_byte(csi_map, CSI_REG_TX_CFG1_ADDR, val);
+ ret |= adv7481_wr_byte(&state->i2c_client, csi_map,
+ CSI_REG_TX_CFG1_ADDR, val);
msleep(100);
/* ADI Required Write */
- ret |= adv7481_wr_byte(csi_map, 0xc1, 0x2b);
+ ret |= adv7481_wr_byte(&state->i2c_client, csi_map, 0xc1, 0x2b);
msleep(100);
/* ADI Required Write */
- ret |= adv7481_wr_byte(csi_map, 0x31, 0x80);
+ ret |= adv7481_wr_byte(&state->i2c_client, csi_map, 0x31, 0x80);
pr_debug("Exit %s, ret: %d\n", __func__, ret);
@@ -1476,42 +2092,43 @@ static int adv7481_g_input_status(struct v4l2_subdev *sd, u32 *status)
{
int ret = 0;
struct adv7481_state *state = to_state(sd);
- uint8_t val1 = 0;
- uint8_t val2 = 0;
+ uint8_t val = 0;
uint32_t count = 0;
+ *status = 0;
pr_debug("Enter %s\n", __func__);
if (ADV7481_IP_HDMI == state->mode) {
- /*
- * Check Timing Lock IO Map Status3:0x71[0] &&
- * 0x71[1] && 0x71[7]
- */
+ /* Check Timing Lock */
do {
- val1 = adv7481_rd_byte(state->client,
- IO_HDMI_LVL_RAW_STATUS_3_ADDR);
- val2 = adv7481_rd_byte(state->i2c_cp,
- CP_REG_STDI_CH_ADDR);
-
- if (ADV_REG_GETFIELD(val1, IO_DE_REGEN_LCK_RAW) &&
- ADV_REG_GETFIELD(val1, IO_V_LOCKED_RAW) &&
- ADV_REG_GETFIELD(val1, IO_TMDSPLL_LCK_A_RAW) &&
- ADV_REG_GETFIELD(val2, CP_STDI_DVALID_CH1))
+ if (adv7481_is_timing_locked(state))
break;
count++;
usleep_range(LOCK_MIN_SLEEP, LOCK_MAX_SLEEP);
} while (count < LOCK_NUM_TRIES);
if (count >= LOCK_NUM_TRIES) {
- pr_err("%s(%d), HDMI DE regeneration block NOT Locked: 0x%x, 0x%x",
- __func__, __LINE__, val1, val2);
+ pr_err("%s(%d), HDMI DE regeneration block NOT Locked\n",
+ __func__, __LINE__);
*status |= V4L2_IN_ST_NO_SIGNAL;
}
} else {
- val1 = adv7481_rd_byte(state->i2c_sdp,
- SDP_RO_MAIN_STATUS1_ADDR);
- if (!ADV_REG_GETFIELD(val1, SDP_RO_MAIN_IN_LOCK)) {
+ /* Select SDP read-only main Map */
+ adv7481_wr_byte(&state->i2c_client, state->i2c_sdp_addr,
+ SDP_RW_MAP_REG, 0x01);
+ do {
+ val = adv7481_rd_byte(&state->i2c_client,
+ state->i2c_sdp_addr, SDP_RO_MAIN_STATUS1_ADDR);
+ if (ADV_REG_GETFIELD(val, SDP_RO_MAIN_IN_LOCK))
+ break;
+ count++;
+ usleep_range(LOCK_MIN_SLEEP, LOCK_MAX_SLEEP);
+ } while (count < LOCK_NUM_TRIES);
+
+ adv7481_wr_byte(&state->i2c_client, state->i2c_sdp_addr,
+ SDP_RW_MAP_REG, 0x00);
+ if (count >= LOCK_NUM_TRIES) {
pr_err("%s(%d), SD Input NOT Locked: 0x%x\n",
- __func__, __LINE__, val1);
+ __func__, __LINE__, val);
*status |= V4L2_IN_ST_NO_SIGNAL;
}
}
@@ -1530,7 +2147,6 @@ static int adv7481_s_stream(struct v4l2_subdev *sd, int on)
static const struct v4l2_subdev_video_ops adv7481_video_ops = {
.s_routing = adv7481_s_routing,
.g_frame_interval = adv7481_g_frame_interval,
- .g_mbus_fmt = adv7481_g_mbus_fmt,
.querystd = adv7481_query_sd_std,
.g_dv_timings = adv7481_query_dv_timings,
.g_input_status = adv7481_g_input_status,
@@ -1539,6 +2155,11 @@ static const struct v4l2_subdev_video_ops adv7481_video_ops = {
static const struct v4l2_subdev_core_ops adv7481_core_ops = {
.s_power = adv7481_s_power,
+ .ioctl = adv7481_ioctl,
+};
+
+static const struct v4l2_subdev_pad_ops adv7481_pad_ops = {
+ .get_fmt = adv7481_get_fmt,
};
static const struct v4l2_ctrl_ops adv7481_ctrl_ops = {
@@ -1548,10 +2169,13 @@ static const struct v4l2_ctrl_ops adv7481_ctrl_ops = {
static const struct v4l2_subdev_ops adv7481_ops = {
.core = &adv7481_core_ops,
.video = &adv7481_video_ops,
+ .pad = &adv7481_pad_ops,
};
static int adv7481_init_v4l2_controls(struct adv7481_state *state)
{
+ int ret = 0;
+
v4l2_ctrl_handler_init(&state->ctrl_hdl, 4);
v4l2_ctrl_new_std(&state->ctrl_hdl, &adv7481_ctrl_ops,
@@ -1565,59 +2189,195 @@ static int adv7481_init_v4l2_controls(struct adv7481_state *state)
state->sd.ctrl_handler = &state->ctrl_hdl;
if (state->ctrl_hdl.error) {
- int err = state->ctrl_hdl.error;
+ ret = state->ctrl_hdl.error;
v4l2_ctrl_handler_free(&state->ctrl_hdl);
- return err;
+ } else {
+ v4l2_ctrl_handler_setup(&state->ctrl_hdl);
}
- v4l2_ctrl_handler_setup(&state->ctrl_hdl);
- return 0;
+ pr_err("%s: Exit with ret: %d\n", __func__, ret);
+ return ret;
+}
+
+static struct msm_camera_i2c_fn_t msm_sensor_cci_func_tbl = {
+ .i2c_read = msm_camera_cci_i2c_read,
+ .i2c_read_seq = msm_camera_cci_i2c_read_seq,
+ .i2c_write = msm_camera_cci_i2c_write,
+ .i2c_write_seq = msm_camera_cci_i2c_write_seq,
+ .i2c_write_table = msm_camera_cci_i2c_write_table,
+ .i2c_write_seq_table = msm_camera_cci_i2c_write_seq_table,
+ .i2c_write_table_w_microdelay =
+ msm_camera_cci_i2c_write_table_w_microdelay,
+ .i2c_util = msm_sensor_cci_i2c_util,
+ .i2c_poll = msm_camera_cci_i2c_poll,
+};
+
+static int adv7481_cci_init(struct adv7481_state *state)
+{
+ struct msm_camera_cci_client *cci_client = NULL;
+ int ret = 0;
+
+ pr_err("%s: Enter\n", __func__);
+
+ state->i2c_client.i2c_func_tbl = &msm_sensor_cci_func_tbl;
+ state->i2c_client.addr_type = MSM_CAMERA_I2C_BYTE_ADDR;
+ state->i2c_client.cci_client = kzalloc(sizeof(
+ struct msm_camera_cci_client), GFP_KERNEL);
+ cci_client = state->i2c_client.cci_client;
+ if (!cci_client) {
+ ret = -ENOMEM;
+ goto err_cci_init;
+ }
+ cci_client->cci_subdev = msm_cci_get_subdev();
+ pr_debug("%s cci_subdev: %p\n", __func__, cci_client->cci_subdev);
+ if (!cci_client->cci_subdev) {
+ ret = -EPROBE_DEFER;
+ goto err_cci_init;
+ }
+ cci_client->cci_i2c_master = state->cci_master;
+ cci_client->sid = state->i2c_slave_addr;
+ cci_client->retries = 3;
+ cci_client->id_map = 0;
+ cci_client->i2c_freq_mode = I2C_CUSTOM_MODE;
+ ret = state->i2c_client.i2c_func_tbl->i2c_util(
+ &state->i2c_client, MSM_CCI_INIT);
+ if (ret < 0)
+ pr_err("%s - cci_init failed\n", __func__);
+ else
+ state->clocks_requested = TRUE;
+
+ pr_debug("%s i2c_client.client: %p\n", __func__,
+ state->i2c_client.client);
+
+err_cci_init:
+ return ret;
}
-static int adv7481_probe(struct i2c_client *client,
- const struct i2c_device_id *id)
+static int adv7481_parse_dt(struct platform_device *pdev,
+ struct adv7481_state *state)
+{
+ struct device_node *np = state->dev->of_node;
+ uint32_t i = 0;
+ int gpio_count = 0;
+ struct resource *adv_addr_res = NULL;
+ int ret = 0;
+
+ /* config CCI */
+ ret = of_property_read_u32(np, "qcom,cci-master",
+ &state->cci_master);
+ if (ret < 0 || state->cci_master >= MASTER_MAX) {
+ pr_err("%s: failed to read cci master . ret %d\n",
+ __func__, ret);
+ goto exit;
+ }
+ pr_debug("%s: cci_master: 0x%x\n", __func__, state->cci_master);
+ adv_addr_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!adv_addr_res) {
+ pr_err("%s: failed to read adv7481 resource.\n", __func__);
+ goto exit;
+ }
+ state->i2c_slave_addr = adv_addr_res->start;
+ pr_debug("%s: i2c_slave_addr: 0x%x\n", __func__, state->i2c_slave_addr);
+ state->i2c_io_addr = (uint8_t)state->i2c_slave_addr;
+
+ gpio_count = of_gpio_count(np);
+ if (gpio_count != ADV7481_GPIO_MAX) {
+ ret = -EFAULT;
+ pr_err("%s: dt gpio count %d doesn't match required. ret %d\n",
+ __func__, gpio_count, ret);
+ goto exit;
+ }
+ for (i = 0; i < ADV7481_GPIO_MAX; i++) {
+ state->gpio_array[i].gpio = of_get_gpio_flags(np, i,
+ (enum of_gpio_flags *)&state->gpio_array[i].flags);
+ if (!gpio_is_valid(state->gpio_array[i].gpio)) {
+ pr_err("invalid gpio setting for index %d\n", i);
+ ret = -EFAULT;
+ goto exit;
+ }
+ pr_debug("%s: gpio_array[%d] = %d flag = %ld\n", __func__, i,
+ state->gpio_array[i].gpio, state->gpio_array[i].flags);
+ }
+
+exit:
+ return ret;
+}
+
+static const struct of_device_id adv7481_id[] = {
+ { .compatible = "qcom,adv7481", },
+ { /* end of list */ },
+};
+MODULE_DEVICE_TABLE(of, adv7481_id);
+
+static int adv7481_probe(struct platform_device *pdev)
{
struct adv7481_state *state;
- struct adv7481_platform_data *pdata = NULL;
+ const struct of_device_id *device_id;
struct v4l2_subdev *sd;
- struct v4l2_ctrl_handler *hdl;
int ret;
- pr_debug("Attempting to probe...\n");
- /* Check if the adapter supports the needed features */
- if (!i2c_check_functionality(client->adapter,
- I2C_FUNC_SMBUS_BYTE_DATA)) {
- pr_err("%s %s Check i2c Functionality Fail\n",
- __func__, client->name);
- ret = -EIO;
+ device_id = of_match_device(adv7481_id, &pdev->dev);
+ if (!device_id) {
+ pr_err("%s: device_id is NULL\n", __func__);
+ ret = -ENODEV;
goto err;
}
- v4l_info(client, "chip found @ 0x%02x (%s)\n",
- client->addr, client->adapter->name);
/* Create 7481 State */
- state = devm_kzalloc(&client->dev,
- sizeof(struct adv7481_state), GFP_KERNEL);
+ state = devm_kzalloc(&pdev->dev,
+ sizeof(struct adv7481_state), GFP_KERNEL);
if (state == NULL) {
ret = -ENOMEM;
- pr_err("Check Kzalloc Fail\n");
- goto err_mem;
+ goto err;
}
- state->client = client;
+ platform_set_drvdata(pdev, state);
+ state->dev = &pdev->dev;
+
mutex_init(&state->mutex);
+ ret = adv7481_parse_dt(pdev, state);
+ if (ret < 0) {
+ pr_err("Error parsing dt tree\n");
+ goto err_mem_free;
+ }
- /* Get and Check Platform Data */
- pdata = (struct adv7481_platform_data *) client->dev.platform_data;
- if (!pdata) {
- ret = -ENOMEM;
- pr_err("Getting Platform data failed\n");
- goto err_mem;
+ ret = adv7481_cci_init(state);
+ if (ret < 0) {
+ pr_err("%s: failed adv7481_cci_init ret %d\n", __func__, ret);
+ goto err_mem_free;
+ }
+
+ /* config VREG */
+ ret = msm_camera_get_dt_vreg_data(pdev->dev.of_node,
+ &(state->cci_vreg), &(state->regulator_count));
+ if (ret < 0) {
+ pr_err("%s:cci get_dt_vreg failed\n", __func__);
+ goto err_mem_free;
+ }
+
+ ret = msm_camera_config_vreg(&pdev->dev, state->cci_vreg,
+ state->regulator_count, NULL, 0,
+ &state->cci_reg_ptr[0], 1);
+ if (ret < 0) {
+ pr_err("%s:cci config_vreg failed\n", __func__);
+ goto err_mem_free;
+ }
+
+ ret = msm_camera_enable_vreg(&pdev->dev, state->cci_vreg,
+ state->regulator_count, NULL, 0,
+ &state->cci_reg_ptr[0], 1);
+ if (ret < 0) {
+ pr_err("%s:cci enable_vreg failed\n", __func__);
+ goto err_mem_free;
}
+ pr_debug("%s - VREG Initialized...\n", __func__);
- /* Configure and Register V4L2 I2C Sub-device */
+ /* Configure and Register V4L2 Sub-device */
sd = &state->sd;
- v4l2_i2c_subdev_init(sd, client, &adv7481_ops);
+ v4l2_subdev_init(sd, &adv7481_ops);
+ sd->owner = pdev->dev.driver->owner;
+ v4l2_set_subdevdata(sd, state);
+ strlcpy(sd->name, DRIVER_NAME, sizeof(sd->name));
state->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
state->sd.flags |= V4L2_SUBDEV_FL_HAS_EVENTS;
@@ -1627,103 +2387,136 @@ static int adv7481_probe(struct i2c_client *client,
ret = media_entity_init(&state->sd.entity, 1, &state->pad, 0);
if (ret) {
ret = -EIO;
- pr_err("Media entity init failed\n");
+ pr_err("%s(%d): Media entity init failed\n",
+ __func__, __LINE__);
goto err_media_entity;
}
/* Initialize HW Config */
- ret = adv7481_hw_init(pdata, state);
+ ret = adv7481_hw_init(state);
if (ret) {
ret = -EIO;
- pr_err("HW Initialisation Failed\n");
+ pr_err("%s: HW Initialisation Failed\n", __func__);
goto err_media_entity;
}
/* Register V4l2 Control Functions */
- hdl = &state->ctrl_hdl;
- v4l2_ctrl_handler_init(hdl, 4);
- adv7481_init_v4l2_controls(state);
+ ret = adv7481_init_v4l2_controls(state);
+ if (ret) {
+ pr_err("%s: V4L2 Controls Initialisation Failed %d\n",
+ __func__, ret);
+ }
- /* Initials ADV7481 State Settings */
+ /* Initial ADV7481 State Settings */
state->tx_auto_params = ADV7481_AUTO_PARAMS;
- state->tx_lanes = ADV7481_MIPI_2LANE;
/* Initialize SW Init Settings and I2C sub maps 7481 */
- ret = adv7481_dev_init(state, client);
+ ret = adv7481_dev_init(state);
if (ret) {
ret = -EIO;
- pr_err("SW Initialisation Failed\n");
+ pr_err("%s(%d): SW Initialisation Failed\n",
+ __func__, __LINE__);
goto err_media_entity;
}
- /* Set hdmi settings */
- ret = adv7481_set_hdmi_mode(state);
-
/* BA registration */
- ret |= msm_ba_register_subdev_node(sd);
+ ret = msm_ba_register_subdev_node(sd);
if (ret) {
ret = -EIO;
- pr_err("BA INIT FAILED\n");
+ pr_err("%s: BA init failed\n", __func__);
goto err_media_entity;
}
+ enable_irq(state->irq);
pr_debug("Probe successful!\n");
return ret;
err_media_entity:
media_entity_cleanup(&sd->entity);
-err_mem:
- kfree(state);
+
+err_mem_free:
+ adv7481_release_cci_clks(state);
+ devm_kfree(&pdev->dev, state);
+
err:
- if (!ret)
- ret = 1;
return ret;
}
-static int adv7481_remove(struct i2c_client *client)
+static int adv7481_remove(struct platform_device *pdev)
{
- struct v4l2_subdev *sd = i2c_get_clientdata(client);
- struct adv7481_state *state = to_state(sd);
+ struct adv7481_state *state = platform_get_drvdata(pdev);
- msm_ba_unregister_subdev_node(sd);
- v4l2_device_unregister_subdev(sd);
- media_entity_cleanup(&sd->entity);
+ msm_ba_unregister_subdev_node(&state->sd);
+ v4l2_device_unregister_subdev(&state->sd);
+ media_entity_cleanup(&state->sd.entity);
v4l2_ctrl_handler_free(&state->ctrl_hdl);
+ adv7481_reset_irq(state);
if (state->irq > 0)
free_irq(state->irq, state);
- i2c_unregister_device(state->i2c_csi_txa);
- i2c_unregister_device(state->i2c_csi_txb);
- i2c_unregister_device(state->i2c_hdmi);
- i2c_unregister_device(state->i2c_edid);
- i2c_unregister_device(state->i2c_cp);
- i2c_unregister_device(state->i2c_sdp);
- i2c_unregister_device(state->i2c_rep);
+ cancel_delayed_work(&state->irq_delayed_work);
mutex_destroy(&state->mutex);
- kfree(state);
+ devm_kfree(&pdev->dev, state);
return 0;
}
-static const struct i2c_device_id adv7481_id[] = {
- { DRIVER_NAME, 0 },
- {},
-};
-MODULE_DEVICE_TABLE(i2c, adv7481_id);
+#ifdef CONFIG_PM_SLEEP
+static int adv7481_suspend(struct device *dev)
+{
+ struct adv7481_state *state;
+ int ret;
+
+ state = (struct adv7481_state *)dev_get_drvdata(dev);
+
+ /* release CCI clocks */
+ ret = adv7481_release_cci_clks(state);
+ if (ret)
+ pr_err("%s: adv7481 release cci clocks failed\n", __func__);
+ else
+ pr_debug("released cci clocks in suspend");
+
+ return 0;
+}
+
+static int adv7481_resume(struct device *dev)
+{
+ struct adv7481_state *state;
+ int ret;
+
+ state = (struct adv7481_state *)dev_get_drvdata(dev);
+
+ /* Request CCI clocks */
+ ret = adv7481_request_cci_clks(state);
+ if (ret)
+ pr_err("%s: adv7481 request cci clocks failed\n", __func__);
+ else
+ pr_debug("requested cci clocks in resume");
+
+ return 0;
+}
+
+static SIMPLE_DEV_PM_OPS(adv7481_pm_ops, adv7481_suspend, adv7481_resume);
+#define ADV7481_PM_OPS (&adv7481_pm_ops)
+#else
+#define ADV7481_PM_OPS NULL
+#endif
-static struct i2c_driver adv7481_driver = {
+static struct platform_driver adv7481_driver = {
.driver = {
.owner = THIS_MODULE,
.name = KBUILD_MODNAME,
+ .of_match_table = adv7481_id,
+ .pm = ADV7481_PM_OPS,
},
.probe = adv7481_probe,
.remove = adv7481_remove,
- .id_table = adv7481_id,
};
-module_i2c_driver(adv7481_driver);
+module_driver(adv7481_driver, platform_driver_register,
+ platform_driver_unregister);
MODULE_DESCRIPTION("ADI ADV7481 HDMI/MHL/SD video receiver");
diff --git a/drivers/media/i2c/adv7481_reg.h b/drivers/media/i2c/adv7481_reg.h
index a4e14fa18e0a..60b1301abbe6 100644
--- a/drivers/media/i2c/adv7481_reg.h
+++ b/drivers/media/i2c/adv7481_reg.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2014-2015, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2014-2016, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -19,329 +19,451 @@
#define ADV_REG_GETFIELD(val, field) \
(((val) & (field##_BMSK)) >> (field##_SHFT))
+#define ADV_REG_RSTFIELD(val, field) \
+ ((val) & ~((field##_BMSK) << (field##_SHFT)))
+
/* IO Map Registers */
-#define IO_REG_MAIN_RST_ADDR 0xFF
-#define IO_REG_MAIN_RST_VALUE 0xFF
-
-#define IO_REG_PWR_DOWN_CTRL_ADDR 0x00
-#define IO_CTRL_RX_EN_BMSK 0x0040
-#define IO_CTRL_RX_EN_SHFT 6
-#define IO_CTRL_RX_PWDN_BMSK 0x0020
-#define IO_CTRL_RX_PWDN_SHFT 5
-#define IO_CTRL_XTAL_PWDN_BMSK 0x0004
-#define IO_CTRL_XTAL_PWDN_SHFT 2
-#define IO_CTRL_CORE_PWDN_BMSK 0x0002
-#define IO_CTRL_CORE_PWDN_SHFT 1
-#define IO_CTRL_MASTER_PWDN_BMSK 0x0001
-#define IO_CTRL_MASTER_PWDN_SHFT 0
-
-#define IO_REG_PWR_DN2_XTAL_HIGH_ADDR 0x01
-#define IO_CTRL_CEC_WAKE_UP_PWRDN2B_BMSK 0x0080
-#define IO_CTRL_CEC_WAKE_UP_PWRDN2B_SHFT 7
-#define IO_CTRL_CEC_WAKE_UP_PWRDNB_BMSK 0x0040
-#define IO_CTRL_CEC_WAKE_UP_PWRDNB_SHFT 6
-#define IO_PROG_XTAL_FREQ_HIGH_BMSK 0x003F
-#define IO_PROG_XTAL_FREQ_HIGH_SHFT 0
-
-#define IO_REG_XTAL_FREQ_LOW_ADDR 0x02
-#define IO_PROG_XTAL_FREQ_LOW_BMSK 0x00FF
-#define IO_PROG_XTAL_FREQ_LOW_SHFT 0
-
-#define IO_REG_CP_VID_STD_ADDR 0x05
-
-#define IO_REG_CSI_PIX_EN_SEL_ADDR 0x10
-#define IO_CTRL_CSI4_EN_BMSK 0x0080
-#define IO_CTRL_CSI4_EN_SHFT 7
-#define IO_CTRL_CSI1_EN_BMSK 0x0040
-#define IO_CTRL_CSI1_EN_SHFT 6
-#define IO_CTRL_PIX_OUT_EN_BMSK 0x0020
-#define IO_CTRL_PIX_OUT_EN_SHFT 5
-#define IO_CTRL_SD_THRU_PIX_OUT_BMSK 0x0010
-#define IO_CTRL_SD_THRU_PIX_OUT_SHFT 4
-#define IO_CTRL_CSI4_IN_SEL_BMSK 0x000C
-#define IO_CTRL_CSI4_IN_SEL_SHFT 2
-
-#define IO_PAD_CTRLS_ADDR 0x0E
-
-#define IO_REG_I2C_CFG_ADDR 0xF2
-#define IO_REG_I2C_AUTOINC_EN_REG_VALUE 0x01
-
-#define IO_CTRL_MASTER_PWDN_REG_VALUE 0x01
-
-#define IO_HDMI_LVL_RAW_STATUS_3_ADDR 0x71
-#define IO_TMDSPLL_LCK_A_RAW_BMSK 0x0080
-#define IO_TMDSPLL_LCK_A_RAW_SHFT 7
-#define IO_CABLE_DET_A_RAW_BMSK 0x0040
-#define IO_CABLE_DET_A_RAW_SHFT 6
-#define IO_V_LOCKED_RAW_BMSK 0x0002
-#define IO_V_LOCKED_RAW_SHFT 1
-#define IO_DE_REGEN_LCK_RAW_BMSK 0x0001
-#define IO_DE_REGEN_LCK_RAW_SHFT 0
+#define IO_REG_MAIN_RST_ADDR 0xFF
+#define IO_REG_MAIN_RST_VALUE 0xFF
+
+#define IO_REG_PWR_DOWN_CTRL_ADDR 0x00
+#define IO_CTRL_RX_EN_BMSK 0x0040
+#define IO_CTRL_RX_EN_SHFT 6
+#define IO_CTRL_RX_PWDN_BMSK 0x0020
+#define IO_CTRL_RX_PWDN_SHFT 5
+#define IO_CTRL_XTAL_PWDN_BMSK 0x0004
+#define IO_CTRL_XTAL_PWDN_SHFT 2
+#define IO_CTRL_CORE_PWDN_BMSK 0x0002
+#define IO_CTRL_CORE_PWDN_SHFT 1
+#define IO_CTRL_MASTER_PWDN_BMSK 0x0001
+#define IO_CTRL_MASTER_PWDN_SHFT 0
+
+#define IO_REG_PWR_DN2_XTAL_HIGH_ADDR 0x01
+#define IO_CTRL_CEC_WAKE_UP_PWRDN2B_BMSK 0x0080
+#define IO_CTRL_CEC_WAKE_UP_PWRDN2B_SHFT 7
+#define IO_CTRL_CEC_WAKE_UP_PWRDNB_BMSK 0x0040
+#define IO_CTRL_CEC_WAKE_UP_PWRDNB_SHFT 6
+#define IO_PROG_XTAL_FREQ_HIGH_BMSK 0x003F
+#define IO_PROG_XTAL_FREQ_HIGH_SHFT 0
+
+#define IO_REG_XTAL_FREQ_LOW_ADDR 0x02
+#define IO_PROG_XTAL_FREQ_LOW_BMSK 0x00FF
+#define IO_PROG_XTAL_FREQ_LOW_SHFT 0
+
+#define IO_REG_CP_VID_STD_ADDR 0x05
+
+#define IO_REG_CSI_PIX_EN_SEL_ADDR 0x10
+#define IO_CTRL_CSI4_EN_BMSK 0x0080
+#define IO_CTRL_CSI4_EN_SHFT 7
+#define IO_CTRL_CSI1_EN_BMSK 0x0040
+#define IO_CTRL_CSI1_EN_SHFT 6
+#define IO_CTRL_PIX_OUT_EN_BMSK 0x0020
+#define IO_CTRL_PIX_OUT_EN_SHFT 5
+#define IO_CTRL_SD_THRU_PIX_OUT_BMSK 0x0010
+#define IO_CTRL_SD_THRU_PIX_OUT_SHFT 4
+#define IO_CTRL_CSI4_IN_SEL_BMSK 0x000C
+#define IO_CTRL_CSI4_IN_SEL_SHFT 2
+
+#define IO_PAD_CTRLS_ADDR 0x0E
+#define IO_PAD_FILTER_CTRLS_ADDR 0x0F
+
+#define IO_REG_I2C_CFG_ADDR 0xF2
+#define IO_REG_I2C_AUTOINC_EN_REG_VALUE 0x01
+
+#define IO_CTRL_MASTER_PWDN_REG_VALUE 0x01
/* Interrupts */
-#define IO_HDMI_LVL_INT_STATUS_3_ADDR 0x72
-#define IO_CABLE_DET_A_ST_BMSK 0x0040
-#define IO_CABLE_DET_A_ST_SHFT 6
-
-#define IO_HDMI_LVL_INT_CLEAR_3_ADDR 0x73
-#define IO_CABLE_DET_A_CLR_BMSK 0x0040
-#define IO_CABLE_DET_A_CLR_SHFT 6
-
-#define IO_HDMI_LVL_INT2_MASKB_3_ADDR 0x74
-#define IO_CABLE_DET_A_MB2_BMSK 0x0040
-#define IO_CABLE_DET_A_MB2_SHFT 6
-
-#define IO_HDMI_LVL_INT_MASKB_3_ADDR 0x75
-#define IO_CABLE_DET_A_MB1_BMSK 0x0040
-#define IO_CABLE_DET_A_MB1_SHFT 6
-
-#define IO_REG_PAD_CTRL_1_ADDR 0x1D
-#define IO_PDN_INT1_BMSK 0x0080
-#define IO_PDN_INT1_SHFT 7
-#define IO_PDN_INT2_BMSK 0x0040
-#define IO_PDN_INT2_SHFT 6
-#define IO_PDN_INT3_BMSK 0x0020
-#define IO_PDN_INT3_SHFT 5
-#define IO_INV_LLC_BMSK 0x0010
-#define IO_INV_LLC_SHFT 4
-#define IO_DRV_LLC_PAD_BMSK 0x000C
-#define IO_DRV_LLC_PAD_SHFT 2
-
-#define IO_REG_INT_RAW_STATUS_ADDR 0x3F
-
-#define IO_REG_INT1_CONF_ADDR 0x40
-#define IO_INTRQ_DUR_SEL_BMSK 0x00C0
-#define IO_INTRQ_DUR_SEL_SHFT 6
-#define IO_INTRQ_OP_SEL_BMSK 0x0003
-#define IO_INTRQ_OP_SEL_SHFT 0
-
-#define IO_REG_INT2_CONF_ADDR 0x41
-#define IO_INTRQ2_DUR_SEL_BMSK 0x00C0
-#define IO_INTRQ2_DUR_SEL_SHFT 6
-#define IO_CP_LOCK_UNLOCK_EDGE_SEL_BMSK 0x0020
-#define IO_CP_LOCK_UNLOCK_EDGE_SEL_SHFT 5
-#define IO_EN_UMASK_RAW_INTRQ2_BMSK 0x0008
-#define IO_EN_UMASK_RAW_INTRQ2_SHFT 3
-#define IO_INT2_EN_BMSK 0x0004
-#define IO_INT2_EN_SHFT 2
-#define IO_INTRQ2_OP_SEL_BMSK 0x0003
-#define IO_INTRQ2_OP_SEL_SHFT 0
-
-#define IO_REG_DATAPATH_RAW_STATUS_ADDR 0x43
-#define IO_REG_DATAPATH_INT_STATUS_ADDR 0x44
-#define IO_REG_DATAPATH_INT_CLEAR_ADDR 0x45
-
-#define IO_REG_DATAPATH_INT_MASKB_ADDR 0x47
-#define IO_CP_LOCK_CP_MB1_BMSK 0x0080
-#define IO_CP_LOCK_CP_MB1_SHFT 7
-#define IO_CP_UNLOCK_CP_MB1_BMSK 0x0040
-#define IO_CP_UNLOCK_CP_MB1_SHFT 6
-#define IO_VMUTE_REQUEST_HDMI_MB1_BMSK 0x0020
-#define IO_VMUTE_REQUEST_HDMI_MB1_SHFT 5
-#define IO_MPU_STIM_INTRQ_MB1_BMSK 0x0002
-#define IO_MPU_STIM_INTRQ_MB1_SHFT 1
-#define IO_INT_SD_MB1_BMSK 0x0001
-#define IO_INT_SD_MB1_SHFT 0
+#define IO_HDMI_LVL_INT_CLEAR_1_ADDR 0x69
+
+#define IO_HDMI_LVL_INT_MASKB_1_ADDR 0x6B
+#define IO_AVI_INFO_MB1_BMSK 0x0001
+#define IO_AVI_INFO_MB1_SHFT 0
+
+#define IO_HDMI_LVL_INT_CLEAR_2_ADDR 0x6E
+
+#define IO_HDMI_LVL_RAW_STATUS_3_ADDR 0x71
+#define IO_TMDSPLL_LCK_A_RAW_BMSK 0x0080
+#define IO_TMDSPLL_LCK_A_RAW_SHFT 7
+#define IO_CABLE_DET_A_RAW_BMSK 0x0040
+#define IO_CABLE_DET_A_RAW_SHFT 6
+#define IO_V_LOCKED_RAW_BMSK 0x0002
+#define IO_V_LOCKED_RAW_SHFT 1
+#define IO_DE_REGEN_LCK_RAW_BMSK 0x0001
+#define IO_DE_REGEN_LCK_RAW_SHFT 0
+
+#define IO_HDMI_LVL_INT_STATUS_3_ADDR 0x72
+#define IO_CABLE_DET_A_ST_BMSK 0x0040
+#define IO_CABLE_DET_A_ST_SHFT 6
+#define IO_V_LOCKED_ST_BMSK 0x0002
+#define IO_V_LOCKED_ST_SHFT 1
+#define IO_DE_REGEN_LCK_ST_BMSK 0x0001
+#define IO_DE_REGEN_LCK_ST_SHFT 0
+
+#define IO_HDMI_LVL_INT_CLEAR_3_ADDR 0x73
+#define IO_CABLE_DET_A_CLR_BMSK 0x0040
+#define IO_CABLE_DET_A_CLR_SHFT 6
+
+#define IO_HDMI_LVL_INT2_MASKB_3_ADDR 0x74
+#define IO_CABLE_DET_A_MB2_BMSK 0x0040
+#define IO_CABLE_DET_A_MB2_SHFT 6
+
+#define IO_HDMI_LVL_INT_MASKB_3_ADDR 0x75
+#define IO_CABLE_DET_A_MB1_BMSK 0x0040
+#define IO_CABLE_DET_A_MB1_SHFT 6
+#define IO_V_LOCKED_MB1_BMSK 0x0002
+#define IO_V_LOCKED_MB1_SHFT 1
+#define IO_DE_REGEN_LCK_MB1_BMSK 0x0001
+#define IO_DE_REGEN_LCK_MB1_SHFT 0
+
+#define IO_HDMI_EDG_RAW_STATUS_1_ADDR 0x80
+#define IO_NEW_AVI_INFO_RAW_BMSK 0x0001
+#define IO_NEW_AVI_INFO_RAW_SHFT 0
+
+#define IO_HDMI_EDG_INT_STATUS_1_ADDR 0x81
+#define IO_NEW_AVI_INFO_ST_BMSK 0x0001
+#define IO_NEW_AVI_INFO_ST_SHFT 0
+
+#define IO_HDMI_EDG_INT_CLEAR_1_ADDR 0x82
+#define IO_NEW_AVI_INFO_CLR_BMSK 0x0001
+#define IO_NEW_AVI_INFO_CLR_SHFT 0
+
+#define IO_HDMI_EDG_INT2_MASKB_1_ADDR 0x83
+#define IO_NEW_AVI_INFO_MB2_BMSK 0x0001
+#define IO_NEW_AVI_INFO_MB2_SHFT 0
+
+#define IO_HDMI_EDG_INT_MASKB_1_ADDR 0x84
+#define IO_NEW_AVI_INFO_MB1_BMSK 0x0001
+#define IO_NEW_AVI_INFO_MB1_SHFT 0
+
+#define IO_HDMI_EDG_INT_CLEAR_2_ADDR 0x87
+#define IO_HDMI_EDG_INT_CLEAR_3_ADDR 0x8C
+
+#define IO_REG_PAD_CTRL_1_ADDR 0x1D
+#define IO_PDN_INT1_BMSK 0x0080
+#define IO_PDN_INT1_SHFT 7
+#define IO_PDN_INT2_BMSK 0x0040
+#define IO_PDN_INT2_SHFT 6
+#define IO_PDN_INT3_BMSK 0x0020
+#define IO_PDN_INT3_SHFT 5
+#define IO_INV_LLC_BMSK 0x0010
+#define IO_INV_LLC_SHFT 4
+#define IO_DRV_LLC_PAD_BMSK 0x000C
+#define IO_DRV_LLC_PAD_SHFT 2
+
+#define IO_REG_INT_RAW_STATUS_ADDR 0x3F
+#define IO_INT_CEC_ST_BMSK 0x0010
+#define IO_INT_CEC_ST_SHFT 4
+#define IO_INT_HDMI_ST_BMSK 0x0008
+#define IO_INT_HDMI_ST_SHFT 3
+#define IO_INTRQ3_RAW_BMSK 0x0004
+#define IO_INTRQ3_RAW_SHFT 2
+#define IO_INTRQ2_RAW_BMSK 0x0002
+#define IO_INTRQ2_RAW_SHFT 1
+#define IO_INTRQ1_RAW_BMSK 0x0001
+#define IO_INTRQ1_RAW_SHFT 0
+
+#define IO_REG_INT1_CONF_ADDR 0x40
+#define IO_INTRQ_DUR_SEL_BMSK 0x00C0
+#define IO_INTRQ_DUR_SEL_SHFT 6
+#define IO_INTRQ_OP_SEL_BMSK 0x0003
+#define IO_INTRQ_OP_SEL_SHFT 0
+
+#define IO_REG_INT2_CONF_ADDR 0x41
+#define IO_INTRQ2_DUR_SEL_BMSK 0x00C0
+#define IO_INTRQ2_DUR_SEL_SHFT 6
+#define IO_CP_LOCK_UNLOCK_EDGE_SEL_BMSK 0x0020
+#define IO_CP_LOCK_UNLOCK_EDGE_SEL_SHFT 5
+#define IO_EN_UMASK_RAW_INTRQ2_BMSK 0x0008
+#define IO_EN_UMASK_RAW_INTRQ2_SHFT 3
+#define IO_INT2_EN_BMSK 0x0004
+#define IO_INT2_EN_SHFT 2
+#define IO_INTRQ2_OP_SEL_BMSK 0x0003
+#define IO_INTRQ2_OP_SEL_SHFT 0
+
+#define IO_REG_DATAPATH_RAW_STATUS_ADDR 0x43
+#define IO_CP_LOCK_CP_RAW_BMSK 0x0080
+#define IO_CP_LOCK_CP_RAW_SHFT 7
+#define IO_CP_UNLOCK_CP_RAW_BMSK 0x0040
+#define IO_CP_UNLOCK_CP_RAW_SHFT 6
+#define IO_VMUTE_REQUEST_HDMI_RAW_BMSK 0x0020
+#define IO_VMUTE_REQUEST_HDMI_RAW_SHFT 5
+#define IO_MPU_STIM_INTRQ_RAW_BMSK 0x0002
+#define IO_MPU_STIM_INTRQ_RAW_SHFT 1
+#define IO_INT_SD_RAW_BMSK 0x0001
+#define IO_INT_SD_RAW_SHFT 0
+
+#define IO_REG_DATAPATH_INT_STATUS_ADDR 0x44
+#define IO_CP_LOCK_CP_ST_BMSK 0x0080
+#define IO_CP_LOCK_CP_ST_SHFT 7
+#define IO_CP_UNLOCK_CP_ST_BMSK 0x0040
+#define IO_CP_UNLOCK_CP_ST_SHFT 6
+#define IO_VMUTE_REQUEST_HDMI_ST_BMSK 0x0020
+#define IO_VMUTE_REQUEST_HDMI_ST_SHFT 5
+#define IO_MPU_STIM_INTRQ_ST_BMSK 0x0002
+#define IO_MPU_STIM_INTRQ_ST_SHFT 1
+#define IO_INT_SD_ST_BMSK 0x0001
+#define IO_INT_SD_ST_SHFT 0
+
+#define IO_REG_DATAPATH_INT_CLEAR_ADDR 0x45
+
+#define IO_REG_DATAPATH_INT_MASKB_ADDR 0x47
+#define IO_CP_LOCK_CP_MB1_BMSK 0x0080
+#define IO_CP_LOCK_CP_MB1_SHFT 7
+#define IO_CP_UNLOCK_CP_MB1_BMSK 0x0040
+#define IO_CP_UNLOCK_CP_MB1_SHFT 6
+#define IO_VMUTE_REQUEST_HDMI_MB1_BMSK 0x0020
+#define IO_VMUTE_REQUEST_HDMI_MB1_SHFT 5
+#define IO_MPU_STIM_INTRQ_MB1_BMSK 0x0002
+#define IO_MPU_STIM_INTRQ_MB1_SHFT 1
+#define IO_INT_SD_MB1_BMSK 0x0001
+#define IO_INT_SD_MB1_SHFT 0
+
+#define IO_REG_CHIP_REV_ID_1_ADDR 0xDF
+#define IO_REG_CHIP_REV_ID_2_ADDR 0xE0
/* Offsets */
-#define IO_REG_DPLL_ADDR 0xF3
-#define IO_REG_CP_ADDR 0xF4
-#define IO_REG_HDMI_ADDR 0xF5
-#define IO_REG_EDID_ADDR 0xF6
-#define IO_REG_HDMI_REP_ADDR 0xF7
-#define IO_REG_HDMI_INF_ADDR 0xF8
-#define IO_REG_CBUS_ADDR 0xF9
-#define IO_REG_CEC_ADDR 0xFA
-#define IO_REG_SDP_ADDR 0xFB
-#define IO_REG_CSI_TXB_ADDR 0xFC
-#define IO_REG_CSI_TXA_ADDR 0xFD
+#define IO_REG_DPLL_ADDR 0xF3
+#define IO_REG_CP_ADDR 0xF4
+#define IO_REG_HDMI_ADDR 0xF5
+#define IO_REG_EDID_ADDR 0xF6
+#define IO_REG_HDMI_REP_ADDR 0xF7
+#define IO_REG_HDMI_INF_ADDR 0xF8
+#define IO_REG_CBUS_ADDR 0xF9
+#define IO_REG_CEC_ADDR 0xFA
+#define IO_REG_SDP_ADDR 0xFB
+#define IO_REG_CSI_TXB_ADDR 0xFC
+#define IO_REG_CSI_TXA_ADDR 0xFD
/* Sub Address Map Locations */
-#define IO_REG_DPLL_SADDR 0x4C
-#define IO_REG_CP_SADDR 0x44
-#define IO_REG_HDMI_SADDR 0x74
-#define IO_REG_EDID_SADDR 0x78
-#define IO_REG_HDMI_REP_SADDR 0x64
-#define IO_REG_HDMI_INF_SADDR 0x62
-#define IO_REG_CBUS_SADDR 0xF0
-#define IO_REG_CEC_SADDR 0x82
-#define IO_REG_SDP_SADDR 0xF2
-#define IO_REG_CSI_TXB_SADDR 0x90
-#define IO_REG_CSI_TXA_SADDR 0x94
+#define IO_REG_DPLL_SADDR 0x4C
+#define IO_REG_CP_SADDR 0x44
+#define IO_REG_HDMI_SADDR 0x74
+#define IO_REG_EDID_SADDR 0x78
+#define IO_REG_HDMI_REP_SADDR 0x64
+#define IO_REG_HDMI_INF_SADDR 0x62
+#define IO_REG_CBUS_SADDR 0xF0
+#define IO_REG_CEC_SADDR 0x82
+#define IO_REG_SDP_SADDR 0xF2
+#define IO_REG_CSI_TXB_SADDR 0x90
+#define IO_REG_CSI_TXA_SADDR 0x94
/* HDMI Map Registers */
-#define HDMI_REG_HDMI_PARAM4_ADDR 0x04
-#define HDMI_REG_AV_MUTE_BMSK 0x0040
-#define HDMI_REG_AV_MUTE_SHFT 6
-#define HDMI_REG_TMDS_PLL_LOCKED_BMSK 0x0002
-#define HDMI_REG_TMDS_PLL_LOCKED_SHFT 1
-#define HDMI_REG_AUDIO_PLL_LOCKED_BMSK 0x0001
-#define HDMI_REG_AUDIO_PLL_LOCKED_SHFT 0
-
-#define HDMI_REG_HDMI_PARAM5_ADDR 0x05
-#define HDMI_REG_HDMI_MODE_BMSK 0x0080
-#define HDMI_REG_TMDS_FREQ_0_SHFT 7
-#define HDMI_REG_HDMI_CONT_ENCRYPT_BMSK 0x0040
-#define HDMI_REG_HDMI_CONT_ENCRYPT_SHFT 6
-#define HDMI_REG_DVI_HSYNC_POLARITY_BMSK 0x0020
-#define HDMI_REG_DVI_HSYNC_POLARITY_SHFT 5
-#define HDMI_REG_DVI_VSYNC_POLARITY_BMSK 0x0010
-#define HDMI_REG_DVI_VSYNC_POLARITY_SHFT 4
-#define HDMI_REG_PIXEL_REPETITION_BMSK 0x000F
-#define HDMI_REG_PIXEL_REPETITION_SHFT 0
-
-#define HDMI_REG_LINE_WIDTH_1_ADDR 0x07
-#define HDMI_VERT_FILTER_LOCKED_BMSK 0x0080
-#define HDMI_VERT_FILTER_LOCKED_SHFT 7
-#define HDMI_AUDIO_CHANNEL_MODE_BMSK 0x0040
-#define HDMI_AUDIO_CHANNEL_MODE_SHFT 6
-#define HDMI_DE_REGEN_FILTER_LCK_BMSK 0x0020
-#define HDMI_DE_REGEN_FILTER_LCK_SHFT 5
-#define HDMI_REG_LINE_WIDTH_1_BMSK 0x001F
-#define HDMI_REG_LINE_WIDTH_1_SHFT 0
-
-#define HDMI_REG_LINE_WIDTH_2_ADDR 0x08
-#define HDMI_REG_LINE_WIDTH_2_BMSK 0x00FF
-#define HDMI_REG_LINE_WIDTH_2_SHFT 0
-
-#define HDMI_REG_FIELD0_HEIGHT_1_ADDR 0x09
-#define HDMI_REG_FIELD0_HEIGHT_1_BMSK 0x001F
-#define HDMI_REG_FIELD0_HEIGHT_1_SHFT 0
-#define HDMI_REG_FIELD0_HEIGHT_2_ADDR 0x0A
-#define HDMI_REG_FIELD0_HEIGHT_2_BMSK 0x00FF
-#define HDMI_REG_FIELD0_HEIGHT_2_SHFT 0
-
-#define HDMI_REG_FIELD1_HEIGHT1_ADDR 0x0B
-#define HDMI_REG_DEEP_COLOR_MODE_BMSK 0x00C0
-#define HDMI_REG_DEEP_COLOR_MODE_SHFT 6
-#define HDMI_REG_HDMI_INTERLACED_BMSK 0x0020
-#define HDMI_REG_HDMI_INTERLACED_SHFT 5
-
-#define HDMI_REG_TOTAL_LINE_WIDTH_1_ADDR 0x1E
-#define HDMI_REG_TOTAL_LINE_WIDTH_1_BMSK 0x003F
-#define HDMI_REG_TOTAL_LINE_WIDTH_1_SHFT 0
-
-#define HDMI_REG_TOTAL_LINE_WIDTH_2_ADDR 0x1F
-#define HDMI_REG_TOTAL_LINE_WIDTH_2_BMSK 0x00FF
-#define HDMI_REG_TOTAL_LINE_WIDTH_2_SHFT 0
-
-#define HDMI_REG_FIELD0_TOTAL_HEIGHT_1_ADDR 0x26
-#define HDMI_REG_FIELD0_TOT_HEIGHT_1_BMSK 0x003F
-#define HDMI_REG_FIELD0_TOT_HEIGHT_1_SHFT 0
-
-#define HDMI_REG_FIELD0_TOTAL_HEIGHT_2_ADDR 0x27
-#define HDMI_REG_FIELD0_TOT_HEIGHT_2_BMSK 0x00FF
-#define HDMI_REG_FIELD0_TOT_HEIGHT_2_SHFT 0
-
-#define HDMI_REG_DIS_CABLE_DET_RST_ADDR 0x48
-#define HDMI_DIS_CABLE_DET_RST_BMSK 0x0040
-#define HDMI_DIS_CABLE_DET_RST_SHFT 6
-
-#define HDMI_REG_TMDS_FREQ_ADDR 0x51
-#define HDMI_REG_TMDS_FREQ_BMSK 0x00FF
-#define HDMI_REG_TMDS_FREQ_SHFT 0
-
-#define HDMI_REG_TMDS_FREQ_FRAC_ADDR 0x52
-#define HDMI_REG_TMDS_FREQ_0_BMSK 0x0080
-#define HDMI_REG_TMDS_FREQ_0_SHFT 7
-#define HDMI_REG_TMDS_FREQ_FRAC_BMSK 0x007F
-#define HDMI_REG_TMDS_FREQ_FRAC_SHFT 0
-
-#define HDMI_REG_RST_CTRLS_ADDR 0x5A
-#define HDMI_HDCP_REPT_EDID_RST_BMSK 0x0008
-#define HDMI_HDCP_REPT_EDID_RST_SHFT 3
-
-#define HDMI_REG_MUX_SPDIF_TO_I2S_ADDR 0x6E
-#define HDMI_MUX_SPDIF_TO_I2S_EN_BMSK 0x0008
-#define HDMI_MUX_SPDIF_TO_I2S_EN_SHFT 3
+#define HDMI_REG_HDMI_PARAM4_ADDR 0x04
+#define HDMI_REG_AV_MUTE_BMSK 0x0040
+#define HDMI_REG_AV_MUTE_SHFT 6
+#define HDMI_REG_TMDS_PLL_LOCKED_BMSK 0x0002
+#define HDMI_REG_TMDS_PLL_LOCKED_SHFT 1
+#define HDMI_REG_AUDIO_PLL_LOCKED_BMSK 0x0001
+#define HDMI_REG_AUDIO_PLL_LOCKED_SHFT 0
+
+#define HDMI_REG_HDMI_PARAM5_ADDR 0x05
+#define HDMI_REG_HDMI_MODE_BMSK 0x0080
+#define HDMI_REG_TMDS_FREQ_0_SHFT 7
+#define HDMI_REG_HDMI_CONT_ENCRYPT_BMSK 0x0040
+#define HDMI_REG_HDMI_CONT_ENCRYPT_SHFT 6
+#define HDMI_REG_DVI_HSYNC_POLARITY_BMSK 0x0020
+#define HDMI_REG_DVI_HSYNC_POLARITY_SHFT 5
+#define HDMI_REG_DVI_VSYNC_POLARITY_BMSK 0x0010
+#define HDMI_REG_DVI_VSYNC_POLARITY_SHFT 4
+#define HDMI_REG_PIXEL_REPETITION_BMSK 0x000F
+#define HDMI_REG_PIXEL_REPETITION_SHFT 0
+
+#define HDMI_REG_LINE_WIDTH_1_ADDR 0x07
+#define HDMI_VERT_FILTER_LOCKED_BMSK 0x0080
+#define HDMI_VERT_FILTER_LOCKED_SHFT 7
+#define HDMI_AUDIO_CHANNEL_MODE_BMSK 0x0040
+#define HDMI_AUDIO_CHANNEL_MODE_SHFT 6
+#define HDMI_DE_REGEN_FILTER_LCK_BMSK 0x0020
+#define HDMI_DE_REGEN_FILTER_LCK_SHFT 5
+#define HDMI_REG_LINE_WIDTH_1_BMSK 0x001F
+#define HDMI_REG_LINE_WIDTH_1_SHFT 0
+
+#define HDMI_REG_LINE_WIDTH_2_ADDR 0x08
+#define HDMI_REG_LINE_WIDTH_2_BMSK 0x00FF
+#define HDMI_REG_LINE_WIDTH_2_SHFT 0
+
+#define HDMI_REG_FIELD0_HEIGHT_1_ADDR 0x09
+#define HDMI_REG_FIELD0_HEIGHT_1_BMSK 0x001F
+#define HDMI_REG_FIELD0_HEIGHT_1_SHFT 0
+#define HDMI_REG_FIELD0_HEIGHT_2_ADDR 0x0A
+#define HDMI_REG_FIELD0_HEIGHT_2_BMSK 0x00FF
+#define HDMI_REG_FIELD0_HEIGHT_2_SHFT 0
+
+#define HDMI_REG_FIELD1_HEIGHT1_ADDR 0x0B
+#define HDMI_REG_DEEP_COLOR_MODE_BMSK 0x00C0
+#define HDMI_REG_DEEP_COLOR_MODE_SHFT 6
+#define HDMI_REG_HDMI_INTERLACED_BMSK 0x0020
+#define HDMI_REG_HDMI_INTERLACED_SHFT 5
+
+#define HDMI_REG_TOTAL_LINE_WIDTH_1_ADDR 0x1E
+#define HDMI_REG_TOTAL_LINE_WIDTH_1_BMSK 0x003F
+#define HDMI_REG_TOTAL_LINE_WIDTH_1_SHFT 0
+
+#define HDMI_REG_TOTAL_LINE_WIDTH_2_ADDR 0x1F
+#define HDMI_REG_TOTAL_LINE_WIDTH_2_BMSK 0x00FF
+#define HDMI_REG_TOTAL_LINE_WIDTH_2_SHFT 0
+
+#define HDMI_REG_FIELD0_TOTAL_HEIGHT_1_ADDR 0x26
+#define HDMI_REG_FIELD0_TOT_HEIGHT_1_BMSK 0x003F
+#define HDMI_REG_FIELD0_TOT_HEIGHT_1_SHFT 0
+
+#define HDMI_REG_FIELD0_TOTAL_HEIGHT_2_ADDR 0x27
+#define HDMI_REG_FIELD0_TOT_HEIGHT_2_BMSK 0x00FF
+#define HDMI_REG_FIELD0_TOT_HEIGHT_2_SHFT 0
+
+#define HDMI_REG_DIS_CABLE_DET_RST_ADDR 0x48
+#define HDMI_DIS_CABLE_DET_RST_BMSK 0x0040
+#define HDMI_DIS_CABLE_DET_RST_SHFT 6
+
+#define HDMI_REG_TMDS_FREQ_ADDR 0x51
+#define HDMI_REG_TMDS_FREQ_BMSK 0x00FF
+#define HDMI_REG_TMDS_FREQ_SHFT 0
+
+#define HDMI_REG_TMDS_FREQ_FRAC_ADDR 0x52
+#define HDMI_REG_TMDS_FREQ_0_BMSK 0x0080
+#define HDMI_REG_TMDS_FREQ_0_SHFT 7
+#define HDMI_REG_TMDS_FREQ_FRAC_BMSK 0x007F
+#define HDMI_REG_TMDS_FREQ_FRAC_SHFT 0
+
+#define HDMI_REG_RST_CTRLS_ADDR 0x5A
+#define HDMI_HDCP_REPT_EDID_RST_BMSK 0x0008
+#define HDMI_HDCP_REPT_EDID_RST_SHFT 3
+
+#define HDMI_REG_MUX_SPDIF_TO_I2S_ADDR 0x6E
+#define HDMI_MUX_SPDIF_TO_I2S_EN_BMSK 0x0008
+#define HDMI_MUX_SPDIF_TO_I2S_EN_SHFT 3
/* HDMI Repeater Map Registers */
-#define HDMI_REG_HDCP_EDID_CTRLS_ADDR 0x74
-#define HDMI_MAN_EDID_A_ENABLE_BMSK 0x0001
-#define HDMI_MAN_EDID_A_ENABLE_SHFT 0
+#define HDMI_REG_HDCP_EDID_CTRLS_ADDR 0x74
+#define HDMI_MAN_EDID_A_ENABLE_BMSK 0x0001
+#define HDMI_MAN_EDID_A_ENABLE_SHFT 0
+
+#define HDMI_REG_RO_EDID_DEBUG_2_ADDR 0x76
+#define HDMI_EDID_A_ENABLE_BMSK 0x0001
+#define HDMI_EDID_A_ENABLE_SHFT 0
+
+/* CEC Map Registers */
+#define CEC_REG_LOG_ADDR_MASK_ADDR 0x27
+#define CEC_REG_LOG_ADDR_MASK2_BMSK 0x0040
+#define CEC_REG_LOG_ADDR_MASK2_SHFT 6
+#define CEC_REG_LOG_ADDR_MASK1_BMSK 0x0020
+#define CEC_REG_LOG_ADDR_MASK1_SHFT 5
+#define CEC_REG_LOG_ADDR_MASK0_BMSK 0x0010
+#define CEC_REG_LOG_ADDR_MASK0_SHFT 4
+#define CEC_REG_ERROR_REPORT_MODE_BMSK 0x0008
+#define CEC_REG_ERROR_REPORT_MODE_SHFT 3
+#define CEC_REG_ERROR_REPORT_DET_BMSK 0x0004
+#define CEC_REG_ERROR_REPORT_DET_SHFT 2
+#define CEC_REG_FORCE_NACK_BMSK 0x0002
+#define CEC_REG_FORCE_NACK_SHFT 1
+#define CEC_REG_FORCE_IGNORE_BMSK 0x0001
+#define CEC_REG_FORCE_IGNORE_SHFT 0
+
+#define CEC_REG_LOGICAL_ADDRESS0_1_ADDR 0x28
+#define CEC_REG_LOGICAL_ADDRESS1_BMSK 0x00F0
+#define CEC_REG_LOGICAL_ADDRESS1_SHFT 4
+#define CEC_REG_LOGICAL_ADDRESS0_BMSK 0x000F
+#define CEC_REG_LOGICAL_ADDRESS0_SHFT 0
+
+#define CEC_REG_LOGICAL_ADDRESS2_ADDR 0x29
+#define CEC_REG_LOGICAL_ADDRESS2_BMSK 0x000F
+#define CEC_REG_LOGICAL_ADDRESS2_SHFT 0
+
+#define CEC_REG_CEC_POWER_UP_ADDR 0x2A
+#define CEC_REG_CEC_POWER_UP_BMSK 0x0001
+#define CEC_REG_CEC_POWER_UP_SHFT 0
+
+#define CEC_REG_CLR_RX_RDY_SFT_RST_ADDR 0x2C
+#define CEC_REG_CEC_SOFT_RESET_BMSK 0x0001
+#define CEC_REG_CEC_SOFT_RESET_SHFT 0
-#define HDMI_REG_RO_EDID_DEBUG_2_ADDR 0x76
-#define HDMI_EDID_A_ENABLE_BMSK 0x0001
-#define HDMI_EDID_A_ENABLE_SHFT 0
/* CP Map Registers */
-#define CP_REG_CONTRAST 0x3A
-#define CP_REG_SATURATION 0x3B
-#define CP_REG_BRIGHTNESS 0x3C
-#define CP_REG_HUE 0x3D
-#define CP_REG_VID_ADJ 0x3E
-#define CP_CTR_VID_ADJ_EN 0x80
-#define CP_REG_STDI_CH_ADDR 0xB1
-#define CP_STDI_DVALID_CH1_BMSK 0x0080
-#define CP_STDI_DVALID_CH1_SHFT 7
+#define CP_REG_CONTRAST 0x3A
+#define CP_REG_SATURATION 0x3B
+#define CP_REG_BRIGHTNESS 0x3C
+#define CP_REG_HUE 0x3D
+#define CP_REG_VID_ADJ 0x3E
+#define CP_CTR_VID_ADJ_EN 0x80
+#define CP_REG_STDI_CH_ADDR 0xB1
+#define CP_STDI_DVALID_CH1_BMSK 0x0080
+#define CP_STDI_DVALID_CH1_SHFT 7
+
+/* SDP Main Map */
+#define SDP_RW_MAP_REG 0x0e
+
+/* SDP MAP 1 Registers */
+#define SDP_RW_LOCK_UNLOCK_CLR_ADDR 0x43
+#define SDP_RW_LOCK_UNLOCK_MASK_ADDR 0x44
/* SDP R/O Main Map Registers */
-#define SDP_RO_MAIN_STATUS1_ADDR 0x10
-#define SDP_RO_MAIN_COL_KILL_BMSK 0x0080
-#define SDP_RO_MAIN_COL_KILL_SHFT 7
-#define SDP_RO_MAIN_AD_RESULT_BMSK 0x0070
-#define SDP_RO_MAIN_AD_RESULT_SHFT 4
-#define SDP_RO_MAIN_FOLLOW_PW_BMSK 0x0008
-#define SDP_RO_MAIN_FOLLOW_PW_SHFT 3
-#define SDP_RO_MAIN_FSC_LOCK_BMSK 0x0004
-#define SDP_RO_MAIN_FSC_LOCK_SHFT 2
-#define SDP_RO_MAIN_LOST_LOCK_BMSK 0x0002
-#define SDP_RO_MAIN_LOST_LOCK_SHFT 1
-#define SDP_RO_MAIN_IN_LOCK_BMSK 0x0001
-#define SDP_RO_MAIN_IN_LOCK_SHFT 0
+#define SDP_RO_MAIN_STATUS1_ADDR 0x10
+#define SDP_RO_MAIN_COL_KILL_BMSK 0x0080
+#define SDP_RO_MAIN_COL_KILL_SHFT 7
+#define SDP_RO_MAIN_AD_RESULT_BMSK 0x0070
+#define SDP_RO_MAIN_AD_RESULT_SHFT 4
+#define SDP_RO_MAIN_FOLLOW_PW_BMSK 0x0008
+#define SDP_RO_MAIN_FOLLOW_PW_SHFT 3
+#define SDP_RO_MAIN_FSC_LOCK_BMSK 0x0004
+#define SDP_RO_MAIN_FSC_LOCK_SHFT 2
+#define SDP_RO_MAIN_LOST_LOCK_BMSK 0x0002
+#define SDP_RO_MAIN_LOST_LOCK_SHFT 1
+#define SDP_RO_MAIN_IN_LOCK_BMSK 0x0001
+#define SDP_RO_MAIN_IN_LOCK_SHFT 0
+
/*
* CSI Map Registers
*/
-#define CSI_REG_TX_CFG1_ADDR 0x00
-#define CSI_CTRL_TX_PWRDN_BMSK 0x0080
-#define CSI_CTRL_TX_PWRDN_SHFT 7
-#define CSI_CTRL_AUTO_PARAMS_BMSK 0x0020
-#define CSI_CTRL_AUTO_PARAMS_SHFT 5
-#define CSI_CTRL_NUM_LANES_BMSK 0x0007
-#define CSI_CTRL_NUM_LANES_SHFT 0
-
-#define CSI_REG_TX_DPHY_PWDN_ADDR 0xF0
-#define CSI_CTRL_DPHY_PWDN_BMSK 0x0001
-#define CSI_CTRL_DPHY_PWDN_SHFT 0
+#define CSI_REG_TX_CFG1_ADDR 0x00
+#define CSI_CTRL_TX_PWRDN_BMSK 0x0080
+#define CSI_CTRL_TX_PWRDN_SHFT 7
+#define CSI_CTRL_AUTO_PARAMS_BMSK 0x0020
+#define CSI_CTRL_AUTO_PARAMS_SHFT 5
+#define CSI_CTRL_NUM_LANES_BMSK 0x0007
+#define CSI_CTRL_NUM_LANES_SHFT 0
+
+#define CSI_REG_TX_DPHY_PWDN_ADDR 0xF0
+#define CSI_CTRL_DPHY_PWDN_BMSK 0x0001
+#define CSI_CTRL_DPHY_PWDN_SHFT 0
enum adv7481_adresult {
- AD_NTSM_M_J = 0x0,
- AD_NTSC_4_43 = 0x1,
- AD_PAL_M = 0x2,
- AD_PAL_60 = 0x3,
- AD_PAL_B_G = 0x4,
- AD_SECAM = 0x5,
- AD_PAL_COMB_N = 0x6,
- AD_SECAM_525 = 0x7,
+ AD_NTSM_M_J = 0x0,
+ AD_NTSC_4_43 = 0x1,
+ AD_PAL_M = 0x2,
+ AD_PAL_60 = 0x3,
+ AD_PAL_B_G = 0x4,
+ AD_SECAM = 0x5,
+ AD_PAL_COMB_N = 0x6,
+ AD_SECAM_525 = 0x7,
};
enum adv7481_color_depth {
- CD_8BIT = 0x0,
- CD_10BIT = 0x1,
- CD_12BIT = 0x2,
- CD_16BIT = 0x3,
+ CD_8BIT = 0x0,
+ CD_10BIT = 0x1,
+ CD_12BIT = 0x2,
+ CD_16BIT = 0x3,
};
enum adv7481_intrq_dur_sel {
- AD_4_XTAL_PER = 0x0,
- AD_16_XTAL_PER = 0x1,
- AD_64_XTAL_PER = 0x2,
- AD_ACTIVE_UNTIL_CLR = 0x3,
+ AD_4_XTAL_PER = 0x0,
+ AD_16_XTAL_PER = 0x1,
+ AD_64_XTAL_PER = 0x2,
+ AD_ACTIVE_UNTIL_CLR = 0x3,
};
enum adv7481_intrq_op_sel {
- AD_OP_OPEN_DRAIN = 0x0,
- AD_OP_DRIVE_LOW = 0x1,
- AD_OP_DRIVE_HIGH = 0x2,
- AD_OP_DISABLED = 0x3,
+ AD_OP_OPEN_DRAIN = 0x0,
+ AD_OP_DRIVE_LOW = 0x1,
+ AD_OP_DRIVE_HIGH = 0x2,
+ AD_OP_DISABLED = 0x3,
};
enum adv7481_drv_llc_pad {
- AD_LLC_PAD_NOT_USED = 0x0,
- AD_MIN_DRIVE_STRNGTH = 0x1,
- AD_MID_DRIVE_STRNGTH = 0x2,
- AD_MAX_DRIVE_STRNGTH = 0x3,
+ AD_LLC_PAD_NOT_USED = 0x0,
+ AD_MIN_DRIVE_STRNGTH = 0x1,
+ AD_MID_DRIVE_STRNGTH = 0x2,
+ AD_MAX_DRIVE_STRNGTH = 0x3,
};
#endif
diff --git a/drivers/media/platform/msm/ais/isp/msm_buf_mgr.c b/drivers/media/platform/msm/ais/isp/msm_buf_mgr.c
index fcd803d4b138..2133f9391433 100644
--- a/drivers/media/platform/msm/ais/isp/msm_buf_mgr.c
+++ b/drivers/media/platform/msm/ais/isp/msm_buf_mgr.c
@@ -212,8 +212,8 @@ static int msm_isp_prepare_v4l2_buf(struct msm_isp_buf_mgr *buf_mgr,
mapped_info->paddr += accu_length;
accu_length += qbuf_buf->planes[i].length;
- CDBG("%s: plane: %d addr:%lu\n",
- __func__, i, (unsigned long)mapped_info->paddr);
+ CDBG("%s: plane: %d addr:%pK\n",
+ __func__, i, (void *)mapped_info->paddr);
}
buf_info->num_planes = qbuf_buf->num_planes;
@@ -275,8 +275,8 @@ static int msm_isp_map_buf(struct msm_isp_buf_mgr *buf_mgr,
pr_err_ratelimited("%s: cannot map address", __func__);
goto smmu_map_error;
}
- CDBG("%s: addr:%lu\n",
- __func__, (unsigned long)mapped_info->paddr);
+ CDBG("%s: addr:%pK\n",
+ __func__, (void *)mapped_info->paddr);
return rc;
smmu_map_error:
@@ -1367,14 +1367,15 @@ static int msm_isp_buf_mgr_debug(struct msm_isp_buf_mgr *buf_mgr,
struct msm_isp_buffer *bufs = NULL;
uint32_t i = 0, j = 0, k = 0, rc = 0;
char *print_buf = NULL, temp_buf[100];
- uint32_t start_addr = 0, end_addr = 0, print_buf_size = 2000;
+ uint32_t print_buf_size = 2000;
+ unsigned long start_addr = 0, end_addr = 0;
int buf_addr_delta = -1;
int temp_delta = 0;
uint32_t debug_output_id = 0;
uint32_t debug_buf_idx = 0;
uint32_t debug_buf_plane = 0;
- uint32_t debug_start_addr = 0;
- uint32_t debug_end_addr = 0;
+ unsigned long debug_start_addr = 0;
+ unsigned long debug_end_addr = 0;
uint32_t debug_frame_id = 0;
enum msm_isp_buffer_state debug_state = MSM_ISP_BUFFER_STATE_UNUSED;
unsigned long flags;
@@ -1433,8 +1434,8 @@ static int msm_isp_buf_mgr_debug(struct msm_isp_buf_mgr *buf_mgr,
debug_output_id, debug_frame_id);
pr_err("%s: nearby buf index %d, plane %d, state %d\n", __func__,
debug_buf_idx, debug_buf_plane, debug_state);
- pr_err("%s: buf address 0x%x -- 0x%x\n", __func__,
- debug_start_addr, debug_end_addr);
+ pr_err("%s: buf address %pK -- %pK\n", __func__,
+ (void *)debug_start_addr, (void *)debug_end_addr);
if (BUF_DEBUG_FULL) {
print_buf = kzalloc(print_buf_size, GFP_ATOMIC);
@@ -1469,9 +1470,10 @@ static int msm_isp_buf_mgr_debug(struct msm_isp_buf_mgr *buf_mgr,
mapped_info[k].len;
snprintf(temp_buf,
sizeof(temp_buf),
- " buf %d plane %d start_addr %x end_addr %x\n",
- j, k, start_addr,
- end_addr);
+ " buf %d plane %d start_addr %pK end_addr %pK\n",
+ j, k,
+ (void *)start_addr,
+ (void *)end_addr);
strlcat(print_buf, temp_buf,
print_buf_size);
}
diff --git a/drivers/media/platform/msm/camera_v2/common/cam_smmu_api.c b/drivers/media/platform/msm/camera_v2/common/cam_smmu_api.c
index 2030755d59d0..7d9edde62c1b 100644
--- a/drivers/media/platform/msm/camera_v2/common/cam_smmu_api.c
+++ b/drivers/media/platform/msm/camera_v2/common/cam_smmu_api.c
@@ -1360,11 +1360,12 @@ int cam_smmu_set_attr(int handle, uint32_t flags, int32_t *data)
/* set attributes */
ret = iommu_domain_set_attr(domain, cb->attr, (void *)data);
if (ret < 0) {
+ mutex_unlock(&iommu_cb_set.cb_info[idx].lock);
pr_err("Error: set attr\n");
return -ENODEV;
}
} else {
- return -EINVAL;
+ ret = -EINVAL;
}
mutex_unlock(&iommu_cb_set.cb_info[idx].lock);
return ret;
diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_buf_mgr.c b/drivers/media/platform/msm/camera_v2/isp/msm_buf_mgr.c
index 5dbed80f5b85..8f3cffb4c3da 100644
--- a/drivers/media/platform/msm/camera_v2/isp/msm_buf_mgr.c
+++ b/drivers/media/platform/msm/camera_v2/isp/msm_buf_mgr.c
@@ -1166,10 +1166,15 @@ int msm_isp_smmu_attach(struct msm_isp_buf_mgr *buf_mgr,
{
struct msm_vfe_smmu_attach_cmd *cmd = arg;
int rc = 0;
+ int32_t stall_disable = 1;
pr_debug("%s: cmd->security_mode : %d\n", __func__, cmd->security_mode);
+
mutex_lock(&buf_mgr->lock);
if (cmd->iommu_attach_mode == IOMMU_ATTACH) {
+ /* disable smmu stall on fault */
+ cam_smmu_set_attr(buf_mgr->iommu_hdl,
+ DOMAIN_ATTR_CB_STALL_DISABLE, &stall_disable);
/*
* Call hypervisor thru scm call to notify secure or
* non-secure mode
diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp_axi_util.c b/drivers/media/platform/msm/camera_v2/isp/msm_isp_axi_util.c
index 08a8135ea9f4..7e74f2f10c8c 100644
--- a/drivers/media/platform/msm/camera_v2/isp/msm_isp_axi_util.c
+++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp_axi_util.c
@@ -1259,7 +1259,7 @@ void msm_isp_get_avtimer_ts(
int msm_isp_request_axi_stream(struct vfe_device *vfe_dev, void *arg)
{
- int rc = 0, i;
+ int rc = 0, i = 0;
uint32_t io_format = 0;
struct msm_vfe_axi_stream_request_cmd *stream_cfg_cmd = arg;
struct msm_vfe_axi_stream *stream_info;
@@ -1395,7 +1395,7 @@ done:
int msm_isp_release_axi_stream(struct vfe_device *vfe_dev, void *arg)
{
- int rc = 0, i;
+ int rc = 0, i = 0;
struct msm_vfe_axi_stream_release_cmd *stream_release_cmd = arg;
struct msm_vfe_axi_stream *stream_info;
struct msm_vfe_axi_stream_cfg_cmd stream_cfg;
diff --git a/drivers/media/platform/msm/camera_v2/ispif/msm_ispif.c b/drivers/media/platform/msm/camera_v2/ispif/msm_ispif.c
index 24e3223a79d0..ab7d4e86dcac 100644
--- a/drivers/media/platform/msm/camera_v2/ispif/msm_ispif.c
+++ b/drivers/media/platform/msm/camera_v2/ispif/msm_ispif.c
@@ -621,7 +621,7 @@ static int msm_ispif_reset(struct ispif_device *ispif)
ispif->base + ISPIF_VFE_m_INTF_CMD_0(i));
msm_camera_io_w(ISPIF_STOP_INTF_IMMEDIATELY,
ispif->base + ISPIF_VFE_m_INTF_CMD_1(i));
- pr_debug("%s: base %lx", __func__, (unsigned long)ispif->base);
+ pr_debug("%s: base %pK", __func__, ispif->base);
msm_camera_io_w(0, ispif->base +
ISPIF_VFE_m_PIX_INTF_n_CID_MASK(i, 0));
msm_camera_io_w(0, ispif->base +
diff --git a/drivers/media/platform/msm/sde/Kconfig b/drivers/media/platform/msm/sde/Kconfig
index c0e73813ab06..d2c2e90f9de9 100644
--- a/drivers/media/platform/msm/sde/Kconfig
+++ b/drivers/media/platform/msm/sde/Kconfig
@@ -21,6 +21,7 @@ config MSM_SDE_HDMI_CEC
depends on DRM_SDE_HDMI
select MEDIA_CEC_SUPPORT
select MEDIA_CEC_EDID
+ select MEDIA_CEC_NOTIFIER
---help---
The HDMI CEC driver provides support to enable HDMI CEC features
which allows various audiovisual products to communicate using HDMI
diff --git a/drivers/media/platform/msm/sde/cec/sde_hdmi_cec.c b/drivers/media/platform/msm/sde/cec/sde_hdmi_cec.c
index 0fed19a01d5b..b3798e8a9d24 100644
--- a/drivers/media/platform/msm/sde/cec/sde_hdmi_cec.c
+++ b/drivers/media/platform/msm/sde/cec/sde_hdmi_cec.c
@@ -18,11 +18,14 @@
#include <linux/mfd/syscon.h>
#include <linux/module.h>
#include <linux/of.h>
+#include <linux/of_platform.h>
#include <linux/of_irq.h>
#include <linux/platform_device.h>
#include <linux/pm_runtime.h>
#include <linux/cec.h>
#include <media/cec.h>
+#include <media/cec-edid.h>
+#include <media/cec-notifier.h>
#include "sde_hdmi_cec_util.h"
@@ -63,6 +66,7 @@ struct sde_hdmi_cec {
struct cec_hw_resource hw_res;
int irq;
enum cec_irq_status irq_status;
+ struct cec_notifier *notifier;
};
static int sde_hdmi_cec_adap_enable(struct cec_adapter *adap, bool enable)
@@ -287,6 +291,8 @@ static int sde_hdmi_cec_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct sde_hdmi_cec *cec;
+ struct device_node *np;
+ struct platform_device *hdmi_dev;
int ret;
cec = devm_kzalloc(dev, sizeof(*cec), GFP_KERNEL);
@@ -295,6 +301,15 @@ static int sde_hdmi_cec_probe(struct platform_device *pdev)
cec->dev = dev;
+ np = of_parse_phandle(pdev->dev.of_node, "qcom,hdmi-dev", 0);
+ if (!np) {
+ pr_err("failed to find hdmi node in device tree\n");
+ return -ENODEV;
+ }
+ hdmi_dev = of_find_device_by_node(np);
+ if (hdmi_dev == NULL)
+ return -EPROBE_DEFER;
+
cec->irq = of_irq_get(dev->of_node, 0);
if (cec->irq < 0) {
pr_err("failed to get irq\n");
@@ -314,24 +329,38 @@ static int sde_hdmi_cec_probe(struct platform_device *pdev)
cec->adap = cec_allocate_adapter(&sde_hdmi_cec_adap_ops, cec,
CEC_NAME,
CEC_CAP_LOG_ADDRS | CEC_CAP_PASSTHROUGH |
- CEC_CAP_PHYS_ADDR | CEC_CAP_TRANSMIT, 1);
+ CEC_CAP_TRANSMIT, 1);
ret = PTR_ERR_OR_ZERO(cec->adap);
if (ret)
return ret;
ret = cec_register_adapter(cec->adap, &pdev->dev);
- if (ret) {
- cec_delete_adapter(cec->adap);
- return ret;
+ if (ret)
+ goto err_del_adap;
+
+ cec->notifier = cec_notifier_get(&hdmi_dev->dev);
+ if (!cec->notifier) {
+ pr_err("failed to get cec notifier\n");
+ goto err_del_adap;
}
platform_set_drvdata(pdev, cec);
pm_runtime_enable(dev);
+ /*
+ * cec_register_cec_notifier has to be later than pm_runtime_enable
+ * because it calls adap_enable.
+ */
+ cec_register_cec_notifier(cec->adap, cec->notifier);
+
pr_debug("probe done\n");
- return 0;
+ return ret;
+
+err_del_adap:
+ cec_delete_adapter(cec->adap);
+ return ret;
}
static int sde_hdmi_cec_remove(struct platform_device *pdev)
@@ -341,6 +370,7 @@ static int sde_hdmi_cec_remove(struct platform_device *pdev)
pm_runtime_disable(&pdev->dev);
cec_unregister_adapter(cec->adap);
+ cec_notifier_put(cec->notifier);
devm_free_irq(&pdev->dev, cec->irq, cec);
sde_hdmi_cec_deinit_resource(pdev, &cec->hw_res);
diff --git a/drivers/media/platform/msm/sde/rotator/sde_rotator_r1.c b/drivers/media/platform/msm/sde/rotator/sde_rotator_r1.c
index 5b574ed9fabc..9e3d7d806a0c 100644
--- a/drivers/media/platform/msm/sde/rotator/sde_rotator_r1.c
+++ b/drivers/media/platform/msm/sde/rotator/sde_rotator_r1.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2015-2016, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2015-2017, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -145,7 +145,7 @@ static struct sde_mdp_hw_resource *sde_rotator_hw_alloc(
struct sde_mdp_hw_resource *mdp_hw;
struct sde_rot_data_type *mdata = sde_rot_get_mdata();
int pipe_ndx, offset = ctl_id;
- int ret;
+ int ret = 0;
mdp_hw = devm_kzalloc(&mgr->pdev->dev,
sizeof(struct sde_mdp_hw_resource), GFP_KERNEL);
diff --git a/drivers/mmc/card/block.c b/drivers/mmc/card/block.c
index 69e51cc96303..29c57d13744e 100644
--- a/drivers/mmc/card/block.c
+++ b/drivers/mmc/card/block.c
@@ -1017,7 +1017,7 @@ static int mmc_blk_ioctl_rpmb_cmd(struct block_device *bdev,
{
struct mmc_blk_ioc_rpmb_data *idata;
struct mmc_blk_data *md;
- struct mmc_card *card;
+ struct mmc_card *card = NULL;
struct mmc_command cmd = {0};
struct mmc_data data = {0};
struct mmc_request mrq = {NULL};
diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c
index 63f7bf87843f..2cb0ea03a338 100644
--- a/drivers/mmc/core/core.c
+++ b/drivers/mmc/core/core.c
@@ -616,17 +616,39 @@ static int mmc_devfreq_create_freq_table(struct mmc_host *host)
host->card->clk_scaling_lowest,
host->card->clk_scaling_highest);
+ /*
+ * Create the frequency table and initialize it with default values.
+ * Initialize it with platform specific frequencies if the frequency
+ * table supplied by platform driver is present, otherwise initialize
+ * it with min and max frequencies supported by the card.
+ */
if (!clk_scaling->freq_table) {
- pr_debug("%s: no frequency table defined - setting default\n",
- mmc_hostname(host));
+ if (clk_scaling->pltfm_freq_table_sz)
+ clk_scaling->freq_table_sz =
+ clk_scaling->pltfm_freq_table_sz;
+ else
+ clk_scaling->freq_table_sz = 2;
+
clk_scaling->freq_table = kzalloc(
- 2*sizeof(*(clk_scaling->freq_table)), GFP_KERNEL);
+ (clk_scaling->freq_table_sz *
+ sizeof(*(clk_scaling->freq_table))), GFP_KERNEL);
if (!clk_scaling->freq_table)
return -ENOMEM;
- clk_scaling->freq_table[0] = host->card->clk_scaling_lowest;
- clk_scaling->freq_table[1] = host->card->clk_scaling_highest;
- clk_scaling->freq_table_sz = 2;
- goto out;
+
+ if (clk_scaling->pltfm_freq_table) {
+ memcpy(clk_scaling->freq_table,
+ clk_scaling->pltfm_freq_table,
+ (clk_scaling->pltfm_freq_table_sz *
+ sizeof(*(clk_scaling->pltfm_freq_table))));
+ } else {
+ pr_debug("%s: no frequency table defined - setting default\n",
+ mmc_hostname(host));
+ clk_scaling->freq_table[0] =
+ host->card->clk_scaling_lowest;
+ clk_scaling->freq_table[1] =
+ host->card->clk_scaling_highest;
+ goto out;
+ }
}
if (host->card->clk_scaling_lowest >
@@ -835,7 +857,7 @@ int mmc_resume_clk_scaling(struct mmc_host *host)
devfreq_min_clk = host->clk_scaling.freq_table[0];
host->clk_scaling.curr_freq = devfreq_max_clk;
- if (host->ios.clock < host->card->clk_scaling_highest)
+ if (host->ios.clock < host->clk_scaling.freq_table[max_clk_idx])
host->clk_scaling.curr_freq = devfreq_min_clk;
host->clk_scaling.clk_scaling_in_progress = false;
@@ -895,6 +917,10 @@ int mmc_exit_clk_scaling(struct mmc_host *host)
host->clk_scaling.devfreq = NULL;
atomic_set(&host->clk_scaling.devfreq_abort, 1);
+
+ kfree(host->clk_scaling.freq_table);
+ host->clk_scaling.freq_table = NULL;
+
pr_debug("%s: devfreq was removed\n", mmc_hostname(host));
return 0;
diff --git a/drivers/mmc/host/sdhci-msm.c b/drivers/mmc/host/sdhci-msm.c
index ca72ebfd55a3..1eeab7db9722 100644
--- a/drivers/mmc/host/sdhci-msm.c
+++ b/drivers/mmc/host/sdhci-msm.c
@@ -1837,13 +1837,13 @@ struct sdhci_msm_pltfm_data *sdhci_msm_populate_pdata(struct device *dev,
}
if (sdhci_msm_dt_get_array(dev, "qcom,devfreq,freq-table",
- &msm_host->mmc->clk_scaling.freq_table,
- &msm_host->mmc->clk_scaling.freq_table_sz, 0))
+ &msm_host->mmc->clk_scaling.pltfm_freq_table,
+ &msm_host->mmc->clk_scaling.pltfm_freq_table_sz, 0))
pr_debug("%s: no clock scaling frequencies were supplied\n",
dev_name(dev));
- else if (!msm_host->mmc->clk_scaling.freq_table ||
- !msm_host->mmc->clk_scaling.freq_table_sz)
- dev_err(dev, "bad dts clock scaling frequencies\n");
+ else if (!msm_host->mmc->clk_scaling.pltfm_freq_table ||
+ !msm_host->mmc->clk_scaling.pltfm_freq_table_sz)
+ dev_err(dev, "bad dts clock scaling frequencies\n");
/*
* Few hosts can support DDR52 mode at the same lower
diff --git a/drivers/net/wireless/ath/regd.c b/drivers/net/wireless/ath/regd.c
index 06ea6cc9e30a..096818610d40 100644
--- a/drivers/net/wireless/ath/regd.c
+++ b/drivers/net/wireless/ath/regd.c
@@ -38,28 +38,28 @@ static int __ath_regd_init(struct ath_regulatory *reg);
/* We enable active scan on these a case by case basis by regulatory domain */
#define ATH9K_2GHZ_CH12_13 REG_RULE(2467-10, 2472+10, 40, 0, 20,\
NL80211_RRF_NO_IR)
-#define ATH9K_2GHZ_CH14 REG_RULE(2484-10, 2484+10, 40, 0, 20,\
+#define ATH9K_2GHZ_CH14 REG_RULE(2484 - 10, 2484 + 10, 20, 0, 20,\
NL80211_RRF_NO_IR | \
NL80211_RRF_NO_OFDM)
/* We allow IBSS on these on a case by case basis by regulatory domain */
-#define ATH9K_5GHZ_5150_5350 REG_RULE(5150-10, 5350+10, 80, 0, 30,\
+#define ATH9K_5GHZ_5180_5320 REG_RULE(5180 - 10, 5320 + 10, 160, 0, 20,\
NL80211_RRF_NO_IR)
-#define ATH9K_5GHZ_5470_5850 REG_RULE(5470-10, 5850+10, 80, 0, 30,\
+#define ATH9K_5GHZ_5500_5825 REG_RULE(5500 - 10, 5825 + 10, 80, 0, 20,\
NL80211_RRF_NO_IR)
-#define ATH9K_5GHZ_5725_5850 REG_RULE(5725-10, 5850+10, 80, 0, 30,\
+#define ATH9K_5GHZ_5745_5825 REG_RULE(5745 - 10, 5825 + 10, 80, 0, 20,\
NL80211_RRF_NO_IR)
#define ATH9K_2GHZ_ALL ATH9K_2GHZ_CH01_11, \
ATH9K_2GHZ_CH12_13, \
ATH9K_2GHZ_CH14
-#define ATH9K_5GHZ_ALL ATH9K_5GHZ_5150_5350, \
- ATH9K_5GHZ_5470_5850
+#define ATH9K_5GHZ_ALL ATH9K_5GHZ_5180_5320, \
+ ATH9K_5GHZ_5500_5825
/* This one skips what we call "mid band" */
-#define ATH9K_5GHZ_NO_MIDBAND ATH9K_5GHZ_5150_5350, \
- ATH9K_5GHZ_5725_5850
+#define ATH9K_5GHZ_NO_MIDBAND ATH9K_5GHZ_5180_5320, \
+ ATH9K_5GHZ_5745_5825
/* Can be used for:
* 0x60, 0x61, 0x62 */
@@ -256,7 +256,7 @@ EXPORT_SYMBOL(ath_is_49ghz_allowed);
/* Frequency is one where radar detection is required */
static bool ath_is_radar_freq(u16 center_freq)
{
- return (center_freq >= 5260 && center_freq <= 5700);
+ return (center_freq >= 5260 && center_freq <= 5720);
}
static void ath_force_clear_no_ir_chan(struct wiphy *wiphy,
diff --git a/drivers/net/wireless/ath/wil6210/pm.c b/drivers/net/wireless/ath/wil6210/pm.c
index b4faf8212348..ce1f384e7f8e 100644
--- a/drivers/net/wireless/ath/wil6210/pm.c
+++ b/drivers/net/wireless/ath/wil6210/pm.c
@@ -98,6 +98,10 @@ static int wil_resume_keep_radio_on(struct wil6210_priv *wil)
}
}
+ /* Wake all queues */
+ if (test_bit(wil_status_fwconnected, wil->status))
+ wil_update_net_queues_bh(wil, NULL, false);
+
out:
if (rc)
set_bit(wil_status_suspended, wil->status);
@@ -113,6 +117,7 @@ static int wil_suspend_keep_radio_on(struct wil6210_priv *wil)
/* Prevent handling of new tx and wmi commands */
set_bit(wil_status_suspending, wil->status);
+ wil_update_net_queues_bh(wil, NULL, true);
if (!wil_is_tx_idle(wil)) {
wil_dbg_pm(wil, "Pending TX data, reject suspend\n");
@@ -201,13 +206,17 @@ resume_after_fail:
clear_bit(wil_status_suspending, wil->status);
rc = wmi_resume(wil);
/* if resume succeeded, reject the suspend */
- if (!rc)
+ if (!rc) {
rc = -EBUSY;
-
+ if (test_bit(wil_status_fwconnected, wil->status))
+ wil_update_net_queues_bh(wil, NULL, false);
+ }
return rc;
reject_suspend:
clear_bit(wil_status_suspending, wil->status);
+ if (test_bit(wil_status_fwconnected, wil->status))
+ wil_update_net_queues_bh(wil, NULL, false);
return -EBUSY;
}
diff --git a/drivers/net/wireless/ath/wil6210/txrx.c b/drivers/net/wireless/ath/wil6210/txrx.c
index 439fe30936b6..8f1e79b425cf 100644
--- a/drivers/net/wireless/ath/wil6210/txrx.c
+++ b/drivers/net/wireless/ath/wil6210/txrx.c
@@ -1930,6 +1930,11 @@ static inline void __wil_update_net_queues(struct wil6210_priv *wil,
return;
}
+ /* Do not wake the queues in suspend flow */
+ if (test_bit(wil_status_suspending, wil->status) ||
+ test_bit(wil_status_suspended, wil->status))
+ return;
+
/* check wake */
for (i = 0; i < WIL6210_MAX_TX_RINGS; i++) {
struct vring *cur_vring = &wil->vring_tx[i];
diff --git a/drivers/platform/msm/mhi/mhi_bhi.c b/drivers/platform/msm/mhi/mhi_bhi.c
index e1c50e1273ac..4354b2600472 100644
--- a/drivers/platform/msm/mhi/mhi_bhi.c
+++ b/drivers/platform/msm/mhi/mhi_bhi.c
@@ -249,6 +249,13 @@ int bhi_rddm(struct mhi_device_ctxt *mhi_dev_ctxt, bool in_panic)
{
struct bhi_ctxt_t *bhi_ctxt = &mhi_dev_ctxt->bhi_ctxt;
struct bhie_vec_table *rddm_table = &bhi_ctxt->rddm_table;
+ struct bhie_mem_info *bhie_mem_info;
+ u32 rx_sequence, val, current_seq;
+ u32 timeout = (bhi_ctxt->poll_timeout * 1000) / BHIE_RDDM_DELAY_TIME_US;
+ int i;
+ u32 cur_exec, prev_exec = 0;
+ u32 state, prev_state = 0;
+ u32 rx_status, prev_status = 0;
if (!rddm_table->bhie_mem_info) {
mhi_log(mhi_dev_ctxt, MHI_MSG_INFO, "RDDM table == NULL\n");
@@ -258,9 +265,93 @@ int bhi_rddm(struct mhi_device_ctxt *mhi_dev_ctxt, bool in_panic)
if (!in_panic)
return bhi_rddm_graceful(mhi_dev_ctxt);
- mhi_log(mhi_dev_ctxt, MHI_MSG_ERROR,
- "RDDM collection in panic not yet supported\n");
- return -EINVAL;
+ /*
+ * Below code should only be executed during kernel panic,
+ * we expect other cores to be shutting down while we're
+ * executing rddm transfer. After returning from this function,
+ * we expect device to reset.
+ */
+
+ /* Trigger device into RDDM */
+ mhi_log(mhi_dev_ctxt, MHI_MSG_INFO, "pm_state:0x%x mhi_state:%s\n",
+ mhi_dev_ctxt->mhi_pm_state,
+ TO_MHI_STATE_STR(mhi_dev_ctxt->mhi_state));
+ if (!MHI_REG_ACCESS_VALID(mhi_dev_ctxt->mhi_pm_state)) {
+ mhi_log(mhi_dev_ctxt, MHI_MSG_ERROR,
+ "Register access not allowed\n");
+ return -EIO;
+ }
+
+ /*
+ * Normally we only set mhi_pm_state after grabbing pm_xfer_lock as a
+ * write, by function mhi_tryset_pm_state. Since we're in a kernel
+ * panic, we will set pm state w/o grabbing xfer lock. We're setting
+ * pm_state to LD as a safety precautions. If another core in middle
+ * of register access this should deter it. However, there is no
+ * no gurantee change will take effect.
+ */
+ mhi_dev_ctxt->mhi_pm_state = MHI_PM_LD_ERR_FATAL_DETECT;
+ /* change should take effect immediately */
+ smp_wmb();
+
+ bhie_mem_info = &rddm_table->
+ bhie_mem_info[rddm_table->segment_count - 1];
+ rx_sequence = rddm_table->sequence++;
+
+ /* program the vector table */
+ mhi_log(mhi_dev_ctxt, MHI_MSG_INFO, "Programming RXVEC table\n");
+ val = HIGH_WORD(bhie_mem_info->phys_addr);
+ mhi_reg_write(mhi_dev_ctxt, bhi_ctxt->bhi_base,
+ BHIE_RXVECADDR_HIGH_OFFS, val);
+ val = LOW_WORD(bhie_mem_info->phys_addr);
+ mhi_reg_write(mhi_dev_ctxt, bhi_ctxt->bhi_base, BHIE_RXVECADDR_LOW_OFFS,
+ val);
+ val = (u32)bhie_mem_info->size;
+ mhi_reg_write(mhi_dev_ctxt, bhi_ctxt->bhi_base, BHIE_RXVECSIZE_OFFS,
+ val);
+ mhi_reg_write_field(mhi_dev_ctxt, bhi_ctxt->bhi_base, BHIE_RXVECDB_OFFS,
+ BHIE_TXVECDB_SEQNUM_BMSK, BHIE_TXVECDB_SEQNUM_SHFT,
+ rx_sequence);
+
+ /* trigger device into rddm */
+ mhi_log(mhi_dev_ctxt, MHI_MSG_INFO,
+ "Triggering Device into RDDM mode\n");
+ mhi_set_m_state(mhi_dev_ctxt, MHI_STATE_SYS_ERR);
+ i = 0;
+
+ while (timeout--) {
+ cur_exec = mhi_reg_read(bhi_ctxt->bhi_base, BHI_EXECENV);
+ state = mhi_get_m_state(mhi_dev_ctxt);
+ rx_status = mhi_reg_read(bhi_ctxt->bhi_base,
+ BHIE_RXVECSTATUS_OFFS);
+ /* if reg. values changed or each sec (udelay(1000)) log it */
+ if (cur_exec != prev_exec || state != prev_state ||
+ rx_status != prev_status || !(i & (SZ_1K - 1))) {
+ mhi_log(mhi_dev_ctxt, MHI_MSG_INFO,
+ "EXECENV:0x%x MHISTATE:0x%x RXSTATUS:0x%x\n",
+ cur_exec, state, rx_status);
+ prev_exec = cur_exec;
+ prev_state = state;
+ prev_status = rx_status;
+ };
+ current_seq = (rx_status & BHIE_TXVECSTATUS_SEQNUM_BMSK) >>
+ BHIE_TXVECSTATUS_SEQNUM_SHFT;
+ rx_status = (rx_status & BHIE_TXVECSTATUS_STATUS_BMSK) >>
+ BHIE_TXVECSTATUS_STATUS_SHFT;
+
+ if ((rx_status == BHIE_TXVECSTATUS_STATUS_XFER_COMPL) &&
+ (current_seq == rx_sequence)) {
+ mhi_log(mhi_dev_ctxt, MHI_MSG_INFO,
+ "rddm transfer completed\n");
+ return 0;
+ }
+ udelay(BHIE_RDDM_DELAY_TIME_US);
+ i++;
+ }
+
+ mhi_log(mhi_dev_ctxt, MHI_MSG_ERROR, "rddm transfer timeout\n");
+
+ return -EIO;
}
static int bhi_load_firmware(struct mhi_device_ctxt *mhi_dev_ctxt,
@@ -439,7 +530,6 @@ void bhi_firmware_download(struct work_struct *work)
struct bhi_ctxt_t *bhi_ctxt;
struct bhie_mem_info mem_info;
int ret;
- long timeout;
mhi_dev_ctxt = container_of(work, struct mhi_device_ctxt,
bhi_ctxt.fw_load_work);
@@ -448,7 +538,14 @@ void bhi_firmware_download(struct work_struct *work)
mhi_log(mhi_dev_ctxt, MHI_MSG_INFO, "Enter\n");
wait_event_interruptible(*mhi_dev_ctxt->mhi_ev_wq.bhi_event,
- mhi_dev_ctxt->mhi_state == MHI_STATE_BHI);
+ mhi_dev_ctxt->mhi_state == MHI_STATE_BHI ||
+ mhi_dev_ctxt->mhi_pm_state == MHI_PM_LD_ERR_FATAL_DETECT);
+ if (mhi_dev_ctxt->mhi_pm_state == MHI_PM_LD_ERR_FATAL_DETECT ||
+ mhi_dev_ctxt->mhi_state != MHI_STATE_BHI) {
+ mhi_log(mhi_dev_ctxt, MHI_MSG_ERROR,
+ "MHI is not in valid state for firmware download\n");
+ return;
+ }
/* PBL image is the first segment in firmware vector table */
mem_info = *bhi_ctxt->fw_table.bhie_mem_info;
@@ -462,10 +559,12 @@ void bhi_firmware_download(struct work_struct *work)
mhi_init_state_transition(mhi_dev_ctxt,
STATE_TRANSITION_RESET);
- timeout = wait_event_timeout(*mhi_dev_ctxt->mhi_ev_wq.bhi_event,
- mhi_dev_ctxt->dev_exec_env == MHI_EXEC_ENV_BHIE,
- msecs_to_jiffies(bhi_ctxt->poll_timeout));
- if (!timeout) {
+ wait_event_timeout(*mhi_dev_ctxt->mhi_ev_wq.bhi_event,
+ mhi_dev_ctxt->dev_exec_env == MHI_EXEC_ENV_BHIE ||
+ mhi_dev_ctxt->mhi_pm_state == MHI_PM_LD_ERR_FATAL_DETECT,
+ msecs_to_jiffies(bhi_ctxt->poll_timeout));
+ if (mhi_dev_ctxt->mhi_pm_state == MHI_PM_LD_ERR_FATAL_DETECT ||
+ mhi_dev_ctxt->dev_exec_env != MHI_EXEC_ENV_BHIE) {
mhi_log(mhi_dev_ctxt, MHI_MSG_ERROR,
"Failed to Enter EXEC_ENV_BHIE\n");
return;
diff --git a/drivers/platform/msm/mhi/mhi_bhi.h b/drivers/platform/msm/mhi/mhi_bhi.h
index 8f7b3d69347c..8f9bc52bbbe0 100644
--- a/drivers/platform/msm/mhi/mhi_bhi.h
+++ b/drivers/platform/msm/mhi/mhi_bhi.h
@@ -87,6 +87,7 @@
#define BHI_POLL_SLEEP_TIME_MS 100
#define BHI_POLL_TIMEOUT_MS 2000
+#define BHIE_RDDM_DELAY_TIME_US (1000)
int bhi_probe(struct mhi_device_ctxt *mhi_dev_ctxt);
void bhi_firmware_download(struct work_struct *work);
diff --git a/drivers/platform/msm/mhi/mhi_pm.c b/drivers/platform/msm/mhi/mhi_pm.c
index caa34eadf8ea..ad9a6fd6b278 100644
--- a/drivers/platform/msm/mhi/mhi_pm.c
+++ b/drivers/platform/msm/mhi/mhi_pm.c
@@ -22,6 +22,22 @@
#include "mhi_hwio.h"
#include "mhi_bhi.h"
+static const char *const mhi_dev_ctrl_str[MHI_DEV_CTRL_MAXCMD] = {
+ [MHI_DEV_CTRL_INIT] = "INIT",
+ [MHI_DEV_CTRL_DE_INIT] = "DE-INIT",
+ [MHI_DEV_CTRL_SUSPEND] = "SUSPEND",
+ [MHI_DEV_CTRL_RESUME] = "RESUME",
+ [MHI_DEV_CTRL_POWER_OFF] = "OFF",
+ [MHI_DEV_CTRL_POWER_ON] = "ON",
+ [MHI_DEV_CTRL_TRIGGER_RDDM] = "TRIGGER RDDM",
+ [MHI_DEV_CTRL_RDDM] = "RDDM",
+ [MHI_DEV_CTRL_RDDM_KERNEL_PANIC] = "RDDM IN PANIC",
+ [MHI_DEV_CTRL_NOTIFY_LINK_ERROR] = "LD",
+};
+
+#define TO_MHI_DEV_CTRL_STR(cmd) ((cmd >= MHI_DEV_CTRL_MAXCMD) ? "INVALID" : \
+ mhi_dev_ctrl_str[cmd])
+
/* Write only sysfs attributes */
static DEVICE_ATTR(MHI_M0, S_IWUSR, NULL, sysfs_init_m0);
static DEVICE_ATTR(MHI_M3, S_IWUSR, NULL, sysfs_init_m3);
@@ -97,12 +113,14 @@ static int mhi_pm_initiate_m3(struct mhi_device_ctxt *mhi_dev_ctxt,
mhi_dev_ctxt->assert_wake(mhi_dev_ctxt, false);
read_unlock_bh(&mhi_dev_ctxt->pm_xfer_lock);
r = wait_event_timeout(*mhi_dev_ctxt->mhi_ev_wq.m0_event,
- mhi_dev_ctxt->mhi_state == MHI_STATE_M0 ||
- mhi_dev_ctxt->mhi_state == MHI_STATE_M1,
- msecs_to_jiffies(MHI_MAX_RESUME_TIMEOUT));
- if (!r) {
+ mhi_dev_ctxt->mhi_state == MHI_STATE_M0 ||
+ mhi_dev_ctxt->mhi_state == MHI_STATE_M1 ||
+ mhi_dev_ctxt->mhi_pm_state == MHI_PM_LD_ERR_FATAL_DETECT,
+ msecs_to_jiffies(MHI_MAX_RESUME_TIMEOUT));
+ if (!r || mhi_dev_ctxt->mhi_pm_state == MHI_PM_LD_ERR_FATAL_DETECT) {
mhi_log(mhi_dev_ctxt, MHI_MSG_ERROR,
- "Failed to get M0||M1 event, timeout, current state:%s\n",
+ "Failed to get M0||M1 event or LD pm_state:0x%x state:%s\n",
+ mhi_dev_ctxt->mhi_pm_state,
TO_MHI_STATE_STR(mhi_dev_ctxt->mhi_state));
return -EIO;
}
@@ -122,9 +140,10 @@ static int mhi_pm_initiate_m3(struct mhi_device_ctxt *mhi_dev_ctxt,
write_unlock_irq(&mhi_dev_ctxt->pm_xfer_lock);
mhi_log(mhi_dev_ctxt, MHI_MSG_INFO, "Waiting for M3 completion.\n");
r = wait_event_timeout(*mhi_dev_ctxt->mhi_ev_wq.m3_event,
- mhi_dev_ctxt->mhi_state == MHI_STATE_M3,
- msecs_to_jiffies(MHI_MAX_SUSPEND_TIMEOUT));
- if (!r) {
+ mhi_dev_ctxt->mhi_state == MHI_STATE_M3 ||
+ mhi_dev_ctxt->mhi_pm_state == MHI_PM_LD_ERR_FATAL_DETECT,
+ msecs_to_jiffies(MHI_MAX_SUSPEND_TIMEOUT));
+ if (!r || mhi_dev_ctxt->mhi_pm_state == MHI_PM_LD_ERR_FATAL_DETECT) {
mhi_log(mhi_dev_ctxt, MHI_MSG_ERROR,
"Failed to get M3 event, timeout, current state:%s\n",
TO_MHI_STATE_STR(mhi_dev_ctxt->mhi_state));
@@ -158,12 +177,13 @@ static int mhi_pm_initiate_m0(struct mhi_device_ctxt *mhi_dev_ctxt)
mhi_set_m_state(mhi_dev_ctxt, MHI_STATE_M0);
write_unlock_irq(&mhi_dev_ctxt->pm_xfer_lock);
r = wait_event_timeout(*mhi_dev_ctxt->mhi_ev_wq.m0_event,
- mhi_dev_ctxt->mhi_state == MHI_STATE_M0 ||
- mhi_dev_ctxt->mhi_state == MHI_STATE_M1,
- msecs_to_jiffies(MHI_MAX_RESUME_TIMEOUT));
- if (!r) {
+ mhi_dev_ctxt->mhi_state == MHI_STATE_M0 ||
+ mhi_dev_ctxt->mhi_state == MHI_STATE_M1 ||
+ mhi_dev_ctxt->mhi_pm_state == MHI_PM_LD_ERR_FATAL_DETECT,
+ msecs_to_jiffies(MHI_MAX_RESUME_TIMEOUT));
+ if (!r || mhi_dev_ctxt->mhi_pm_state == MHI_PM_LD_ERR_FATAL_DETECT) {
mhi_log(mhi_dev_ctxt, MHI_MSG_ERROR,
- "Failed to get M0 event, timeout\n");
+ "Failed to get M0 event, timeout or LD\n");
r = -EIO;
} else
r = 0;
@@ -295,13 +315,16 @@ static int mhi_pm_slave_mode_power_on(struct mhi_device_ctxt *mhi_dev_ctxt)
mhi_dev_ctxt->assert_wake(mhi_dev_ctxt, false);
read_unlock_irq(&mhi_dev_ctxt->pm_xfer_lock);
- ret_val = wait_for_completion_timeout(&mhi_dev_ctxt->cmd_complete,
- msecs_to_jiffies(timeout));
- if (!ret_val || mhi_dev_ctxt->dev_exec_env != MHI_EXEC_ENV_AMSS)
+ wait_for_completion_timeout(&mhi_dev_ctxt->cmd_complete,
+ msecs_to_jiffies(timeout));
+ if (mhi_dev_ctxt->dev_exec_env != MHI_EXEC_ENV_AMSS)
ret_val = -EIO;
else
ret_val = 0;
+ /* wait for firmware download to complete */
+ flush_work(&mhi_dev_ctxt->bhi_ctxt.fw_load_work);
+
if (ret_val) {
read_lock_irq(&mhi_dev_ctxt->pm_xfer_lock);
mhi_dev_ctxt->deassert_wake(mhi_dev_ctxt);
@@ -537,16 +560,16 @@ void mhi_link_state_cb(struct msm_pcie_notify *notify)
}
}
-int mhi_pm_control_device(struct mhi_device *mhi_device,
- enum mhi_dev_ctrl ctrl)
+int mhi_pm_control_device(struct mhi_device *mhi_device, enum mhi_dev_ctrl ctrl)
{
struct mhi_device_ctxt *mhi_dev_ctxt = mhi_device->mhi_dev_ctxt;
+ unsigned long flags;
if (!mhi_dev_ctxt)
return -EINVAL;
- mhi_log(mhi_dev_ctxt, MHI_MSG_INFO,
- "Entered with cmd:%d\n", ctrl);
+ mhi_log(mhi_dev_ctxt, MHI_MSG_INFO, "Entered with cmd:%s\n",
+ TO_MHI_DEV_CTRL_STR(ctrl));
switch (ctrl) {
case MHI_DEV_CTRL_INIT:
@@ -560,12 +583,46 @@ int mhi_pm_control_device(struct mhi_device *mhi_device,
case MHI_DEV_CTRL_POWER_OFF:
mhi_pm_slave_mode_power_off(mhi_dev_ctxt);
break;
+ case MHI_DEV_CTRL_TRIGGER_RDDM:
+ write_lock_irqsave(&mhi_dev_ctxt->pm_xfer_lock, flags);
+ if (!MHI_REG_ACCESS_VALID(mhi_dev_ctxt->mhi_pm_state)) {
+ write_unlock_irqrestore(&mhi_dev_ctxt->pm_xfer_lock,
+ flags);
+ mhi_log(mhi_dev_ctxt, MHI_MSG_INFO,
+ "failed to trigger rddm, no register access in state:0x%x\n",
+ mhi_dev_ctxt->mhi_pm_state);
+ return -EIO;
+ }
+ mhi_set_m_state(mhi_dev_ctxt, MHI_STATE_SYS_ERR);
+ write_unlock_irqrestore(&mhi_dev_ctxt->pm_xfer_lock, flags);
+ break;
case MHI_DEV_CTRL_RDDM:
return bhi_rddm(mhi_dev_ctxt, false);
+ case MHI_DEV_CTRL_RDDM_KERNEL_PANIC:
+ return bhi_rddm(mhi_dev_ctxt, true);
case MHI_DEV_CTRL_DE_INIT:
- if (mhi_dev_ctxt->mhi_pm_state != MHI_PM_DISABLE)
+ if (mhi_dev_ctxt->mhi_pm_state != MHI_PM_DISABLE) {
+ enum MHI_PM_STATE cur_state;
+ /*
+ * If bus master calls DE_INIT before calling POWER_OFF
+ * means a critical failure occurred during POWER_ON
+ * state transition and external PCIe device may not
+ * respond to host. Force PM state to PCIe linkdown
+ * state prior to starting shutdown process to avoid
+ * accessing PCIe link.
+ */
+ write_lock_irq(&mhi_dev_ctxt->pm_xfer_lock);
+ cur_state = mhi_tryset_pm_state(mhi_dev_ctxt,
+ MHI_PM_LD_ERR_FATAL_DETECT);
+ write_unlock_irq(&mhi_dev_ctxt->pm_xfer_lock);
+ if (unlikely(cur_state != MHI_PM_LD_ERR_FATAL_DETECT)) {
+ mhi_log(mhi_dev_ctxt, MHI_MSG_ERROR,
+ "Failed to transition to state 0x%x from 0x%x\n",
+ MHI_PM_LD_ERR_FATAL_DETECT, cur_state);
+ }
process_disable_transition(MHI_PM_SHUTDOWN_PROCESS,
mhi_dev_ctxt);
+ }
bhi_exit(mhi_dev_ctxt);
break;
case MHI_DEV_CTRL_NOTIFY_LINK_ERROR:
@@ -580,6 +637,12 @@ int mhi_pm_control_device(struct mhi_device *mhi_device,
mhi_log(mhi_dev_ctxt, MHI_MSG_INFO,
"Failed to transition to state 0x%x from 0x%x\n",
MHI_PM_LD_ERR_FATAL_DETECT, cur_state);
+
+ /* wake up all threads that's waiting for state change events */
+ complete(&mhi_dev_ctxt->cmd_complete);
+ wake_up_interruptible(mhi_dev_ctxt->mhi_ev_wq.bhi_event);
+ wake_up(mhi_dev_ctxt->mhi_ev_wq.m0_event);
+ wake_up(mhi_dev_ctxt->mhi_ev_wq.m3_event);
break;
}
default:
diff --git a/drivers/platform/msm/mhi/mhi_states.c b/drivers/platform/msm/mhi/mhi_states.c
index 2906393cbd5c..ea2a91bd2d06 100644
--- a/drivers/platform/msm/mhi/mhi_states.c
+++ b/drivers/platform/msm/mhi/mhi_states.c
@@ -147,7 +147,8 @@ void mhi_set_m_state(struct mhi_device_ctxt *mhi_dev_ctxt,
* M1 -> M3_ENTER --> M3
* L1: SYS_ERR_DETECT -> SYS_ERR_PROCESS --> POR
* L2: SHUTDOWN_PROCESS -> DISABLE -> SSR_PENDING (via SSR Notification only)
- * L3: LD_ERR_FATAL_DETECT -> SHUTDOWN_PROCESS
+ * L3: LD_ERR_FATAL_DETECT <--> LD_ERR_FATAL_DETECT
+ * LD_ERR_FATAL_DETECT -> SHUTDOWN_PROCESS
*/
static const struct mhi_pm_transitions const mhi_state_transitions[] = {
/* L0 States */
@@ -216,7 +217,7 @@ static const struct mhi_pm_transitions const mhi_state_transitions[] = {
/* L3 States */
{
MHI_PM_LD_ERR_FATAL_DETECT,
- MHI_PM_SHUTDOWN_PROCESS
+ MHI_PM_LD_ERR_FATAL_DETECT | MHI_PM_SHUTDOWN_PROCESS
},
/* From SSR notification only */
{
diff --git a/drivers/power/qcom/debug_core.c b/drivers/power/qcom/debug_core.c
index ccef04ae9eb2..51b6d63fe994 100644
--- a/drivers/power/qcom/debug_core.c
+++ b/drivers/power/qcom/debug_core.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2014-2016, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2014-2017, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -288,8 +288,8 @@ static const struct file_operations msm_core_ptable_ops = {
int msm_core_debug_init(void)
{
- struct dentry *dir;
- struct dentry *file;
+ struct dentry *dir = NULL;
+ struct dentry *file = NULL;
int i;
msm_core_data = get_cpu_pwr_stats();
diff --git a/drivers/power/supply/qcom/qpnp-fg-gen3.c b/drivers/power/supply/qcom/qpnp-fg-gen3.c
index 36ac1960a176..bd7231705319 100644
--- a/drivers/power/supply/qcom/qpnp-fg-gen3.c
+++ b/drivers/power/supply/qcom/qpnp-fg-gen3.c
@@ -491,7 +491,7 @@ static void fg_encode_default(struct fg_sram_param *sp,
int i, mask = 0xff;
int64_t temp;
- temp = DIV_ROUND_CLOSEST(val * sp[id].numrtr, sp[id].denmtr);
+ temp = (int64_t)div_s64((s64)val * sp[id].numrtr, sp[id].denmtr);
pr_debug("temp: %llx id: %d, val: %d, buf: [ ", temp, id, val);
for (i = 0; i < sp[id].len; i++) {
buf[i] = temp & mask;
@@ -1320,9 +1320,16 @@ static int fg_cap_learning_process_full_data(struct fg_chip *chip)
return rc;
}
- cc_soc_delta_pct = DIV_ROUND_CLOSEST(
- abs(cc_soc_sw - chip->cl.init_cc_soc_sw) * 100,
- CC_SOC_30BIT);
+ cc_soc_delta_pct =
+ div64_s64((int64_t)(cc_soc_sw - chip->cl.init_cc_soc_sw) * 100,
+ CC_SOC_30BIT);
+
+ /* If the delta is < 50%, then skip processing full data */
+ if (cc_soc_delta_pct < 50) {
+ pr_err("cc_soc_delta_pct: %d\n", cc_soc_delta_pct);
+ return -ERANGE;
+ }
+
delta_cc_uah = div64_s64(chip->cl.learned_cc_uah * cc_soc_delta_pct,
100);
chip->cl.final_cc_uah = chip->cl.init_cc_uah + delta_cc_uah;
@@ -1392,7 +1399,6 @@ out:
return rc;
}
-#define FULL_SOC_RAW 255
static void fg_cap_learning_update(struct fg_chip *chip)
{
int rc, batt_soc, batt_soc_msb;
diff --git a/drivers/regulator/cpr3-hmss-regulator.c b/drivers/regulator/cpr3-hmss-regulator.c
index 9a20b6925877..21381d1ad7fa 100644
--- a/drivers/regulator/cpr3-hmss-regulator.c
+++ b/drivers/regulator/cpr3-hmss-regulator.c
@@ -1505,7 +1505,7 @@ static int cpr3_hmss_init_regulator(struct cpr3_regulator *vreg)
static int cpr3_hmss_init_aging(struct cpr3_controller *ctrl)
{
struct cpr3_msm8996_hmss_fuses *fuse = NULL;
- struct cpr3_regulator *vreg;
+ struct cpr3_regulator *vreg = NULL;
u32 aging_ro_scale;
int i, j, rc;
@@ -1710,7 +1710,7 @@ static int cpr3_hmss_regulator_probe(struct platform_device *pdev)
struct device *dev = &pdev->dev;
const struct of_device_id *match;
struct cpr3_controller *ctrl;
- struct cpr3_regulator *vreg;
+ struct cpr3_regulator *vreg = NULL;
int i, j, rc;
if (!dev->of_node) {
diff --git a/drivers/regulator/cpr3-regulator.c b/drivers/regulator/cpr3-regulator.c
index d131a8ea4144..3adbd41ede88 100644
--- a/drivers/regulator/cpr3-regulator.c
+++ b/drivers/regulator/cpr3-regulator.c
@@ -3117,7 +3117,8 @@ static int _cpr3_regulator_update_ctrl_state(struct cpr3_controller *ctrl)
struct cpr4_sdelta *sdelta;
bool valid = false;
bool thread_valid;
- int i, j, rc, new_volt, vdd_volt, dynamic_floor_volt, last_corner_volt;
+ int i, j, rc;
+ int new_volt, vdd_volt, dynamic_floor_volt, last_corner_volt = 0;
u32 reg_last_measurement = 0, sdelta_size;
int *sdelta_table, *boost_table;
diff --git a/drivers/regulator/cprh-kbss-regulator.c b/drivers/regulator/cprh-kbss-regulator.c
index 2307da9497dc..ecf7885a4bff 100644
--- a/drivers/regulator/cprh-kbss-regulator.c
+++ b/drivers/regulator/cprh-kbss-regulator.c
@@ -1975,7 +1975,7 @@ static int cprh_kbss_init_regulator(struct cpr3_regulator *vreg)
static int cprh_kbss_init_aging(struct cpr3_controller *ctrl)
{
struct cprh_kbss_fuses *fuse = NULL;
- struct cpr3_regulator *vreg;
+ struct cpr3_regulator *vreg = NULL;
u32 aging_ro_scale;
int i, j, rc = 0;
diff --git a/drivers/regulator/rpm-smd-regulator.c b/drivers/regulator/rpm-smd-regulator.c
index d26fd3bea788..a5dc1b983bcb 100644
--- a/drivers/regulator/rpm-smd-regulator.c
+++ b/drivers/regulator/rpm-smd-regulator.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012-2016, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-2017, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -207,6 +207,7 @@ struct rpm_regulator {
bool use_pin_ctrl_for_enable;
struct rpm_vreg_request req;
int system_load;
+ int hpm_threshold_current;
int min_uV;
int max_uV;
u32 pin_ctrl_mask[RPM_VREG_PIN_CTRL_STATE_COUNT];
@@ -1030,6 +1031,34 @@ static unsigned int rpm_vreg_get_bob_mode(struct regulator_dev *rdev)
return mode;
}
+static unsigned int rpm_vreg_get_optimum_mode(struct regulator_dev *rdev,
+ int input_uV, int output_uV, int load_uA)
+{
+ struct rpm_regulator *reg = rdev_get_drvdata(rdev);
+ u32 mode = REGULATOR_MODE_NORMAL;
+
+ if (reg->hpm_threshold_current > 0) {
+ if (load_uA >= reg->hpm_threshold_current) {
+ /* PWM mode */
+ mode = (reg->rpm_vreg->regulator_type
+ == RPM_REGULATOR_TYPE_BOB)
+ ? REGULATOR_MODE_FAST
+ : REGULATOR_MODE_NORMAL;
+ } else {
+ /* AUTO mode */
+ mode = (reg->rpm_vreg->regulator_type
+ == RPM_REGULATOR_TYPE_BOB)
+ ? REGULATOR_MODE_NORMAL
+ : REGULATOR_MODE_IDLE;
+ }
+ } else {
+ /* Default to the current mode if no threshold is present. */
+ mode = reg->rdesc.ops->get_mode(rdev);
+ }
+
+ return mode;
+}
+
static int rpm_vreg_enable_time(struct regulator_dev *rdev)
{
struct rpm_regulator *reg = rdev_get_drvdata(rdev);
@@ -1402,6 +1431,18 @@ static struct regulator_ops smps_ops = {
.enable_time = rpm_vreg_enable_time,
};
+static struct regulator_ops smps_optimum_mode_ops = {
+ .enable = rpm_vreg_enable,
+ .disable = rpm_vreg_disable,
+ .is_enabled = rpm_vreg_is_enabled,
+ .set_voltage = rpm_vreg_set_voltage,
+ .get_voltage = rpm_vreg_get_voltage,
+ .set_mode = rpm_vreg_set_mode,
+ .get_mode = rpm_vreg_get_mode,
+ .get_optimum_mode = rpm_vreg_get_optimum_mode,
+ .enable_time = rpm_vreg_enable_time,
+};
+
static struct regulator_ops switch_ops = {
.enable = rpm_vreg_enable,
.disable = rpm_vreg_disable,
@@ -1426,6 +1467,7 @@ static struct regulator_ops bob_ops = {
.get_voltage = rpm_vreg_get_voltage,
.set_mode = rpm_vreg_set_bob_mode,
.get_mode = rpm_vreg_get_bob_mode,
+ .get_optimum_mode = rpm_vreg_get_optimum_mode,
.enable_time = rpm_vreg_enable_time,
};
@@ -1676,6 +1718,12 @@ static int rpm_vreg_device_probe(struct platform_device *pdev)
if (of_get_property(node, "parent-supply", NULL))
init_data->supply_regulator = "parent";
+ of_property_read_u32(node, "qcom,pwm-threshold-current",
+ &reg->hpm_threshold_current);
+ if (reg->hpm_threshold_current > 0
+ && regulator_type == RPM_REGULATOR_TYPE_SMPS)
+ reg->rdesc.ops = &smps_optimum_mode_ops;
+
/*
* Fill in ops and mode masks based on callbacks specified for
* this type of regulator.
@@ -1689,8 +1737,13 @@ static int rpm_vreg_device_probe(struct platform_device *pdev)
if (reg->rdesc.ops->get_mode) {
init_data->constraints.valid_ops_mask
|= REGULATOR_CHANGE_MODE | REGULATOR_CHANGE_DRMS;
- init_data->constraints.valid_modes_mask
- |= REGULATOR_MODE_NORMAL | REGULATOR_MODE_IDLE;
+
+ if (regulator_type == RPM_REGULATOR_TYPE_BOB)
+ init_data->constraints.valid_modes_mask
+ = REGULATOR_MODE_FAST | REGULATOR_MODE_NORMAL;
+ else
+ init_data->constraints.valid_modes_mask
+ |= REGULATOR_MODE_NORMAL | REGULATOR_MODE_IDLE;
}
reg->rdesc.name = init_data->constraints.name;
diff --git a/drivers/regulator/spm-regulator.c b/drivers/regulator/spm-regulator.c
index 484f0412addf..d469463a0b00 100644
--- a/drivers/regulator/spm-regulator.c
+++ b/drivers/regulator/spm-regulator.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2013-2016, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2013-2017, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -49,6 +49,7 @@ enum qpnp_regulator_uniq_type {
QPNP_TYPE_HF,
QPNP_TYPE_FTS2,
QPNP_TYPE_FTS2p5,
+ QPNP_TYPE_FTS426,
QPNP_TYPE_ULT_HF,
};
@@ -56,6 +57,7 @@ enum qpnp_regulator_type {
QPNP_HF_TYPE = 0x03,
QPNP_FTS2_TYPE = 0x1C,
QPNP_FTS2p5_TYPE = 0x1C,
+ QPNP_FTS426_TYPE = 0x1C,
QPNP_ULT_HF_TYPE = 0x22,
};
@@ -63,15 +65,22 @@ enum qpnp_regulator_subtype {
QPNP_FTS2_SUBTYPE = 0x08,
QPNP_HF_SUBTYPE = 0x08,
QPNP_FTS2p5_SUBTYPE = 0x09,
+ QPNP_FTS426_SUBTYPE = 0x0A,
QPNP_ULT_HF_SUBTYPE = 0x0D,
};
+enum qpnp_logical_mode {
+ QPNP_LOGICAL_MODE_AUTO,
+ QPNP_LOGICAL_MODE_PWM,
+};
+
static const struct voltage_range fts2_range0 = {0, 350000, 1275000, 5000};
static const struct voltage_range fts2_range1 = {0, 700000, 2040000, 10000};
static const struct voltage_range fts2p5_range0
= { 80000, 350000, 1355000, 5000};
static const struct voltage_range fts2p5_range1
= {160000, 700000, 2200000, 10000};
+static const struct voltage_range fts426_range = {0, 320000, 1352000, 4000};
static const struct voltage_range ult_hf_range0 = {375000, 375000, 1562500,
12500};
static const struct voltage_range ult_hf_range1 = {750000, 750000, 1525000,
@@ -86,17 +95,45 @@ static const struct voltage_range hf_range1 = {1550000, 1550000, 3125000,
#define QPNP_SMPS_REG_VOLTAGE_SETPOINT 0x41
#define QPNP_SMPS_REG_MODE 0x45
#define QPNP_SMPS_REG_STEP_CTRL 0x61
+#define QPNP_SMPS_REG_UL_LL_CTRL 0x68
+
+/* FTS426 voltage control registers */
+#define QPNP_FTS426_REG_VOLTAGE_LB 0x40
+#define QPNP_FTS426_REG_VOLTAGE_UB 0x41
+#define QPNP_FTS426_REG_VOLTAGE_VALID_LB 0x42
+#define QPNP_FTS426_REG_VOLTAGE_VALID_UB 0x43
+
+/* HF voltage limit registers */
+#define QPNP_HF_REG_VOLTAGE_ULS 0x69
+#define QPNP_HF_REG_VOLTAGE_LLS 0x6B
+
+/* FTS voltage limit registers */
+#define QPNP_FTS_REG_VOLTAGE_ULS_VALID 0x6A
+#define QPNP_FTS_REG_VOLTAGE_LLS_VALID 0x6C
+
+/* FTS426 voltage limit registers */
+#define QPNP_FTS426_REG_VOLTAGE_ULS_LB 0x68
+#define QPNP_FTS426_REG_VOLTAGE_ULS_UB 0x69
+
+/* Common regulator UL & LL limits control register layout */
+#define QPNP_COMMON_UL_EN_MASK 0x80
+#define QPNP_COMMON_LL_EN_MASK 0x40
#define QPNP_SMPS_MODE_PWM 0x80
#define QPNP_SMPS_MODE_AUTO 0x40
+#define QPNP_FTS426_MODE_PWM 0x07
+#define QPNP_FTS426_MODE_AUTO 0x06
#define QPNP_SMPS_STEP_CTRL_STEP_MASK 0x18
#define QPNP_SMPS_STEP_CTRL_STEP_SHIFT 3
#define QPNP_SMPS_STEP_CTRL_DELAY_MASK 0x07
#define QPNP_SMPS_STEP_CTRL_DELAY_SHIFT 0
+#define QPNP_FTS426_STEP_CTRL_DELAY_MASK 0x03
+#define QPNP_FTS426_STEP_CTRL_DELAY_SHIFT 0
/* Clock rate in kHz of the FTS2 regulator reference clock. */
#define QPNP_SMPS_CLOCK_RATE 19200
+#define QPNP_FTS426_CLOCK_RATE 4800
/* Time to delay in us to ensure that a mode change has completed. */
#define QPNP_FTS2_MODE_CHANGE_DELAY 50
@@ -107,6 +144,7 @@ static const struct voltage_range hf_range1 = {1550000, 1550000, 3125000,
/* Minimum voltage stepper delay for each step. */
#define QPNP_FTS2_STEP_DELAY 8
#define QPNP_HF_STEP_DELAY 20
+#define QPNP_FTS426_STEP_DELAY 2
/* Arbitrarily large max step size used to avoid possible numerical overflow */
#define SPM_REGULATOR_MAX_STEP_UV 10000000
@@ -117,6 +155,8 @@ static const struct voltage_range hf_range1 = {1550000, 1550000, 3125000,
*/
#define QPNP_FTS2_STEP_MARGIN_NUM 4
#define QPNP_FTS2_STEP_MARGIN_DEN 5
+#define QPNP_FTS426_STEP_MARGIN_NUM 10
+#define QPNP_FTS426_STEP_MARGIN_DEN 11
/*
* Settling delay for FTS2.5
@@ -140,8 +180,8 @@ struct spm_vreg {
u32 max_step_uV;
bool online;
u16 spmi_base_addr;
- u8 init_mode;
- u8 mode;
+ enum qpnp_logical_mode init_mode;
+ enum qpnp_logical_mode mode;
int step_rate;
enum qpnp_regulator_uniq_type regulator_type;
u32 cpu_num;
@@ -163,6 +203,9 @@ static int spm_regulator_uv_to_vlevel(struct spm_vreg *vreg, int uV)
{
int vlevel;
+ if (vreg->regulator_type == QPNP_TYPE_FTS426)
+ return roundup(uV, vreg->range->step_uV) / 1000;
+
vlevel = DIV_ROUND_UP(uV - vreg->range->min_uV, vreg->range->step_uV);
/* Fix VSET for ULT HF Buck */
@@ -177,6 +220,8 @@ static int spm_regulator_uv_to_vlevel(struct spm_vreg *vreg, int uV)
static int spm_regulator_vlevel_to_uv(struct spm_vreg *vreg, int vlevel)
{
+ if (vreg->regulator_type == QPNP_TYPE_FTS426)
+ return vlevel * 1000;
/*
* Calculate ULT HF buck VSET based on range:
* In case of range 0: VSET is a 7 bit value.
@@ -204,32 +249,91 @@ static unsigned spm_regulator_vlevel_to_selector(struct spm_vreg *vreg,
static int qpnp_smps_read_voltage(struct spm_vreg *vreg)
{
int rc;
- u8 reg = 0;
- uint val;
+ u8 val[2] = {0};
- rc = regmap_read(vreg->regmap,
- vreg->spmi_base_addr + QPNP_SMPS_REG_VOLTAGE_SETPOINT,
- &val);
- if (rc) {
- dev_err(&vreg->pdev->dev,
- "%s: could not read voltage setpoint register, rc=%d\n",
- __func__, rc);
- return rc;
+ if (vreg->regulator_type == QPNP_TYPE_FTS426) {
+ rc = regmap_bulk_read(vreg->regmap,
+ vreg->spmi_base_addr + QPNP_FTS426_REG_VOLTAGE_VALID_LB,
+ val, 2);
+ if (rc) {
+ dev_err(&vreg->pdev->dev, "%s: could not read voltage setpoint registers, rc=%d\n",
+ __func__, rc);
+ return rc;
+ }
+
+ vreg->last_set_vlevel = ((unsigned)val[1] << 8) | val[0];
+ } else {
+ rc = regmap_bulk_read(vreg->regmap,
+ vreg->spmi_base_addr + QPNP_SMPS_REG_VOLTAGE_SETPOINT,
+ val, 1);
+ if (rc) {
+ dev_err(&vreg->pdev->dev, "%s: could not read voltage setpoint register, rc=%d\n",
+ __func__, rc);
+ return rc;
+ }
+ vreg->last_set_vlevel = val[0];
}
- reg = (u8)val;
- vreg->last_set_vlevel = reg;
- vreg->last_set_uV = spm_regulator_vlevel_to_uv(vreg, reg);
+ vreg->last_set_uV = spm_regulator_vlevel_to_uv(vreg,
+ vreg->last_set_vlevel);
+ return rc;
+}
+
+static int qpnp_smps_write_voltage(struct spm_vreg *vreg, unsigned vlevel)
+{
+ int rc = 0;
+ u8 reg[2];
+
+ /* Set voltage control registers via SPMI. */
+ reg[0] = vlevel & 0xFF;
+ reg[1] = (vlevel >> 8) & 0xFF;
+
+ if (vreg->regulator_type == QPNP_TYPE_FTS426) {
+ rc = regmap_bulk_write(vreg->regmap,
+ vreg->spmi_base_addr + QPNP_FTS426_REG_VOLTAGE_LB,
+ reg, 2);
+ } else {
+ rc = regmap_write(vreg->regmap,
+ vreg->spmi_base_addr + QPNP_SMPS_REG_VOLTAGE_SETPOINT,
+ reg[0]);
+ }
+
+ if (rc)
+ pr_err("%s: regmap_write failed, rc=%d\n",
+ vreg->rdesc.name, rc);
return rc;
}
+static inline enum qpnp_logical_mode qpnp_regval_to_mode(struct spm_vreg *vreg,
+ u8 regval)
+{
+ if (vreg->regulator_type == QPNP_TYPE_FTS426)
+ return (regval == QPNP_FTS426_MODE_PWM)
+ ? QPNP_LOGICAL_MODE_PWM : QPNP_LOGICAL_MODE_AUTO;
+ else
+ return (regval & QPNP_SMPS_MODE_PWM)
+ ? QPNP_LOGICAL_MODE_PWM : QPNP_LOGICAL_MODE_AUTO;
+}
+
+static inline u8 qpnp_mode_to_regval(struct spm_vreg *vreg,
+ enum qpnp_logical_mode mode)
+{
+ if (vreg->regulator_type == QPNP_TYPE_FTS426)
+ return (mode == QPNP_LOGICAL_MODE_PWM)
+ ? QPNP_FTS426_MODE_PWM : QPNP_FTS426_MODE_AUTO;
+ else
+ return (mode == QPNP_LOGICAL_MODE_PWM)
+ ? QPNP_SMPS_MODE_PWM : QPNP_SMPS_MODE_AUTO;
+}
+
static int qpnp_smps_set_mode(struct spm_vreg *vreg, u8 mode)
{
int rc;
rc = regmap_write(vreg->regmap,
- vreg->spmi_base_addr + QPNP_SMPS_REG_MODE, mode);
+ vreg->spmi_base_addr + QPNP_SMPS_REG_MODE,
+ qpnp_mode_to_regval(vreg, mode));
if (rc)
dev_err(&vreg->pdev->dev,
"%s: could not write to mode register, rc=%d\n",
@@ -275,7 +379,6 @@ static int spm_regulator_write_voltage(struct spm_vreg *vreg, int uV)
bool spm_failed = false;
int rc = 0;
u32 slew_delay;
- u8 reg;
if (likely(!vreg->bypass_spm)) {
/* Set voltage control register via SPM. */
@@ -288,13 +391,9 @@ static int spm_regulator_write_voltage(struct spm_vreg *vreg, int uV)
}
if (unlikely(vreg->bypass_spm || spm_failed)) {
- /* Set voltage control register via SPMI. */
- reg = vlevel;
- rc = regmap_write(vreg->regmap,
- vreg->spmi_base_addr + QPNP_SMPS_REG_VOLTAGE_SETPOINT,
- reg);
+ rc = qpnp_smps_write_voltage(vreg, vlevel);
if (rc) {
- pr_err("%s: regmap_write failed, rc=%d\n",
+ pr_err("%s: voltage write failed, rc=%d\n",
vreg->rdesc.name, rc);
return rc;
}
@@ -351,12 +450,12 @@ static int _spm_regulator_set_voltage(struct regulator_dev *rdev)
return 0;
pwm_required = (vreg->regulator_type == QPNP_TYPE_FTS2)
- && !(vreg->init_mode & QPNP_SMPS_MODE_PWM)
+ && (vreg->init_mode != QPNP_LOGICAL_MODE_PWM)
&& vreg->uV > vreg->last_set_uV;
if (pwm_required) {
/* Switch to PWM mode so that voltage ramping is fast. */
- rc = qpnp_smps_set_mode(vreg, QPNP_SMPS_MODE_PWM);
+ rc = qpnp_smps_set_mode(vreg, QPNP_LOGICAL_MODE_PWM);
if (rc)
return rc;
}
@@ -375,7 +474,7 @@ static int _spm_regulator_set_voltage(struct regulator_dev *rdev)
/* Wait for mode transition to complete. */
udelay(QPNP_FTS2_MODE_CHANGE_DELAY - QPNP_SPMI_WRITE_MIN_DELAY);
/* Switch to AUTO mode so that power consumption is lowered. */
- rc = qpnp_smps_set_mode(vreg, QPNP_SMPS_MODE_AUTO);
+ rc = qpnp_smps_set_mode(vreg, QPNP_LOGICAL_MODE_AUTO);
if (rc)
return rc;
}
@@ -466,7 +565,7 @@ static unsigned int spm_regulator_get_mode(struct regulator_dev *rdev)
{
struct spm_vreg *vreg = rdev_get_drvdata(rdev);
- return vreg->mode == QPNP_SMPS_MODE_PWM
+ return vreg->mode == QPNP_LOGICAL_MODE_PWM
? REGULATOR_MODE_NORMAL : REGULATOR_MODE_IDLE;
}
@@ -480,8 +579,8 @@ static int spm_regulator_set_mode(struct regulator_dev *rdev, unsigned int mode)
* in the case that qcom,mode has been specified as "pwm" in device
* tree.
*/
- vreg->mode
- = mode == REGULATOR_MODE_NORMAL ? QPNP_SMPS_MODE_PWM : vreg->init_mode;
+ vreg->mode = (mode == REGULATOR_MODE_NORMAL) ? QPNP_LOGICAL_MODE_PWM
+ : vreg->init_mode;
return qpnp_smps_set_mode(vreg, vreg->mode);
}
@@ -538,7 +637,7 @@ static int spm_regulator_avs_set_voltage(struct regulator_dev *rdev, int min_uV,
return -EINVAL;
}
- vlevel_max = (uV - range->min_uV) / range->step_uV;
+ vlevel_max = spm_regulator_uv_to_vlevel(vreg, uV);
avs_max_uV = spm_regulator_vlevel_to_uv(vreg, vlevel_max);
if (avs_max_uV < min_uV) {
@@ -646,6 +745,9 @@ static int qpnp_smps_check_type(struct spm_vreg *vreg)
} else if (type[0] == QPNP_FTS2p5_TYPE
&& type[1] == QPNP_FTS2p5_SUBTYPE) {
vreg->regulator_type = QPNP_TYPE_FTS2p5;
+ } else if (type[0] == QPNP_FTS426_TYPE
+ && type[1] == QPNP_FTS426_SUBTYPE) {
+ vreg->regulator_type = QPNP_TYPE_FTS426;
} else if (type[0] == QPNP_ULT_HF_TYPE
&& type[1] == QPNP_ULT_HF_SUBTYPE) {
vreg->regulator_type = QPNP_TYPE_ULT_HF;
@@ -750,10 +852,10 @@ static int qpnp_smps_init_mode(struct spm_vreg *vreg)
&mode_name);
if (!rc) {
if (strcmp("pwm", mode_name) == 0) {
- vreg->init_mode = QPNP_SMPS_MODE_PWM;
+ vreg->init_mode = QPNP_LOGICAL_MODE_PWM;
} else if ((strcmp("auto", mode_name) == 0) &&
(vreg->regulator_type != QPNP_TYPE_ULT_HF)) {
- vreg->init_mode = QPNP_SMPS_MODE_AUTO;
+ vreg->init_mode = QPNP_LOGICAL_MODE_AUTO;
} else {
dev_err(&vreg->pdev->dev,
"%s: unknown regulator mode: %s\n",
@@ -761,13 +863,9 @@ static int qpnp_smps_init_mode(struct spm_vreg *vreg)
return -EINVAL;
}
- rc = regmap_write(vreg->regmap,
- vreg->spmi_base_addr + QPNP_SMPS_REG_MODE,
- *&vreg->init_mode);
+ rc = qpnp_smps_set_mode(vreg, vreg->init_mode);
if (rc)
- dev_err(&vreg->pdev->dev,
- "%s: could not write mode register, rc=%d\n",
- __func__, rc);
+ return rc;
} else {
rc = regmap_read(vreg->regmap,
vreg->spmi_base_addr + QPNP_SMPS_REG_MODE,
@@ -776,7 +874,7 @@ static int qpnp_smps_init_mode(struct spm_vreg *vreg)
dev_err(&vreg->pdev->dev,
"%s: could not read mode register, rc=%d\n",
__func__, rc);
- vreg->init_mode = (u8)val;
+ vreg->init_mode = qpnp_regval_to_mode(vreg, val);
}
vreg->mode = vreg->init_mode;
@@ -801,26 +899,41 @@ static int qpnp_smps_init_step_rate(struct spm_vreg *vreg)
}
reg = (u8)val;
- /* ULT buck does not support steps */
- if (vreg->regulator_type != QPNP_TYPE_ULT_HF)
+ /* ULT and FTS426 bucks do not support steps */
+ if (vreg->regulator_type != QPNP_TYPE_ULT_HF && vreg->regulator_type !=
+ QPNP_TYPE_FTS426)
step = (reg & QPNP_SMPS_STEP_CTRL_STEP_MASK)
>> QPNP_SMPS_STEP_CTRL_STEP_SHIFT;
- delay = (reg & QPNP_SMPS_STEP_CTRL_DELAY_MASK)
- >> QPNP_SMPS_STEP_CTRL_DELAY_SHIFT;
+ if (vreg->regulator_type == QPNP_TYPE_FTS426) {
+ delay = (reg & QPNP_FTS426_STEP_CTRL_DELAY_MASK)
+ >> QPNP_FTS426_STEP_CTRL_DELAY_SHIFT;
- /* step_rate has units of uV/us. */
- vreg->step_rate = QPNP_SMPS_CLOCK_RATE * vreg->range->step_uV
- * (1 << step);
+ /* step_rate has units of uV/us. */
+ vreg->step_rate = QPNP_FTS426_CLOCK_RATE * vreg->range->step_uV;
+ } else {
+ delay = (reg & QPNP_SMPS_STEP_CTRL_DELAY_MASK)
+ >> QPNP_SMPS_STEP_CTRL_DELAY_SHIFT;
+
+ /* step_rate has units of uV/us. */
+ vreg->step_rate = QPNP_SMPS_CLOCK_RATE * vreg->range->step_uV
+ * (1 << step);
+ }
if ((vreg->regulator_type == QPNP_TYPE_ULT_HF)
|| (vreg->regulator_type == QPNP_TYPE_HF))
vreg->step_rate /= 1000 * (QPNP_HF_STEP_DELAY << delay);
+ else if (vreg->regulator_type == QPNP_TYPE_FTS426)
+ vreg->step_rate /= 1000 * (QPNP_FTS426_STEP_DELAY << delay);
else
vreg->step_rate /= 1000 * (QPNP_FTS2_STEP_DELAY << delay);
- vreg->step_rate = vreg->step_rate * QPNP_FTS2_STEP_MARGIN_NUM
- / QPNP_FTS2_STEP_MARGIN_DEN;
+ if (vreg->regulator_type == QPNP_TYPE_FTS426)
+ vreg->step_rate = vreg->step_rate * QPNP_FTS426_STEP_MARGIN_NUM
+ / QPNP_FTS426_STEP_MARGIN_DEN;
+ else
+ vreg->step_rate = vreg->step_rate * QPNP_FTS2_STEP_MARGIN_NUM
+ / QPNP_FTS2_STEP_MARGIN_DEN;
/* Ensure that the stepping rate is greater than 0. */
vreg->step_rate = max(vreg->step_rate, 1);
@@ -828,10 +941,93 @@ static int qpnp_smps_init_step_rate(struct spm_vreg *vreg)
return rc;
}
+static int qpnp_smps_check_constraints(struct spm_vreg *vreg,
+ struct regulator_init_data *init_data)
+{
+ int rc = 0, limit_min_uV, limit_max_uV;
+ u16 ul_reg, ll_reg;
+ u8 reg[2];
+
+ limit_min_uV = 0;
+ limit_max_uV = INT_MAX;
+
+ ul_reg = QPNP_FTS_REG_VOLTAGE_ULS_VALID;
+ ll_reg = QPNP_FTS_REG_VOLTAGE_LLS_VALID;
+
+ switch (vreg->regulator_type) {
+ case QPNP_TYPE_HF:
+ ul_reg = QPNP_HF_REG_VOLTAGE_ULS;
+ ll_reg = QPNP_HF_REG_VOLTAGE_LLS;
+ case QPNP_TYPE_FTS2:
+ case QPNP_TYPE_FTS2p5:
+ rc = regmap_bulk_read(vreg->regmap, vreg->spmi_base_addr
+ + QPNP_SMPS_REG_UL_LL_CTRL, reg, 1);
+ if (rc) {
+ dev_err(&vreg->pdev->dev, "%s: UL_LL register read failed, rc=%d\n",
+ __func__, rc);
+ return rc;
+ }
+
+ if (reg[0] & QPNP_COMMON_UL_EN_MASK) {
+ rc = regmap_bulk_read(vreg->regmap, vreg->spmi_base_addr
+ + ul_reg, &reg[1], 1);
+ if (rc) {
+ dev_err(&vreg->pdev->dev, "%s: ULS register read failed, rc=%d\n",
+ __func__, rc);
+ return rc;
+ }
+
+ limit_max_uV = spm_regulator_vlevel_to_uv(vreg, reg[1]);
+ }
+
+ if (reg[0] & QPNP_COMMON_LL_EN_MASK) {
+ rc = regmap_bulk_read(vreg->regmap, vreg->spmi_base_addr
+ + ll_reg, &reg[1], 1);
+ if (rc) {
+ dev_err(&vreg->pdev->dev, "%s: LLS register read failed, rc=%d\n",
+ __func__, rc);
+ return rc;
+ }
+
+ limit_min_uV = spm_regulator_vlevel_to_uv(vreg, reg[1]);
+ }
+
+ break;
+ case QPNP_TYPE_FTS426:
+ rc = regmap_bulk_read(vreg->regmap, vreg->spmi_base_addr
+ + QPNP_FTS426_REG_VOLTAGE_ULS_LB,
+ reg, 2);
+ if (rc) {
+ dev_err(&vreg->pdev->dev, "%s: could not read voltage limit registers, rc=%d\n",
+ __func__, rc);
+ return rc;
+ }
+
+ limit_max_uV = spm_regulator_vlevel_to_uv(vreg,
+ ((unsigned)reg[1] << 8) | reg[0]);
+ break;
+ case QPNP_TYPE_ULT_HF:
+ /* no HW voltage limit configuration */
+ break;
+ }
+
+ if (init_data->constraints.min_uV < limit_min_uV
+ || init_data->constraints.max_uV > limit_max_uV) {
+ dev_err(&vreg->pdev->dev, "regulator min/max(%d/%d) constraints do not fit within HW configured min/max(%d/%d) constraints\n",
+ init_data->constraints.min_uV,
+ init_data->constraints.max_uV, limit_min_uV,
+ limit_max_uV);
+ return -EINVAL;
+ }
+
+ return rc;
+}
+
static bool spm_regulator_using_range0(struct spm_vreg *vreg)
{
return vreg->range == &fts2_range0 || vreg->range == &fts2p5_range0
- || vreg->range == &ult_hf_range0 || vreg->range == &hf_range0;
+ || vreg->range == &ult_hf_range0 || vreg->range == &hf_range0
+ || vreg->range == &fts426_range;
}
/* Register a regulator to enable/disable AVS and set AVS min/max limits. */
@@ -969,6 +1165,8 @@ static int spm_regulator_probe(struct platform_device *pdev)
rc = qpnp_smps_init_range(vreg, &fts2_range0, &fts2_range1);
else if (vreg->regulator_type == QPNP_TYPE_FTS2p5)
rc = qpnp_smps_init_range(vreg, &fts2p5_range0, &fts2p5_range1);
+ else if (vreg->regulator_type == QPNP_TYPE_FTS426)
+ vreg->range = &fts426_range;
else if (vreg->regulator_type == QPNP_TYPE_HF)
rc = qpnp_smps_init_range(vreg, &hf_range0, &hf_range1);
else if (vreg->regulator_type == QPNP_TYPE_ULT_HF)
@@ -1006,6 +1204,13 @@ static int spm_regulator_probe(struct platform_device *pdev)
return -EINVAL;
}
+ rc = qpnp_smps_check_constraints(vreg, init_data);
+ if (rc) {
+ dev_err(&pdev->dev, "%s: regulator constraints check failed, rc=%d\n",
+ __func__, rc);
+ return rc;
+ }
+
vreg->rdesc.name = init_data->constraints.name;
vreg->rdesc.type = REGULATOR_VOLTAGE;
vreg->rdesc.owner = THIS_MODULE;
@@ -1050,8 +1255,8 @@ static int spm_regulator_probe(struct platform_device *pdev)
vreg->rdesc.name,
spm_regulator_using_range0(vreg) ? "LV" : "MV",
vreg->uV,
- vreg->init_mode & QPNP_SMPS_MODE_PWM ? "PWM" :
- (vreg->init_mode & QPNP_SMPS_MODE_AUTO ? "AUTO" : "PFM"),
+ vreg->init_mode == QPNP_LOGICAL_MODE_PWM ? "PWM" :
+ (vreg->init_mode == QPNP_LOGICAL_MODE_AUTO ? "AUTO" : "PFM"),
vreg->step_rate);
return rc;
diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
index a90c51a113d2..b8dc7e834cf3 100644
--- a/drivers/scsi/ufs/ufshcd.c
+++ b/drivers/scsi/ufs/ufshcd.c
@@ -3285,8 +3285,10 @@ static int ufshcd_exec_dev_cmd(struct ufs_hba *hba,
/*
* May get invoked from shutdown and IOCTL contexts.
* In shutdown context, it comes in with lock acquired.
+ * In error recovery context, it may come with lock acquired.
*/
- if (!ufshcd_is_shutdown_ongoing(hba))
+
+ if (!ufshcd_is_shutdown_ongoing(hba) && !ufshcd_eh_in_progress(hba))
down_read(&hba->lock);
/*
@@ -3320,7 +3322,7 @@ static int ufshcd_exec_dev_cmd(struct ufs_hba *hba,
out_put_tag:
ufshcd_put_dev_cmd_tag(hba, tag);
wake_up(&hba->dev_cmd.tag_wq);
- if (!ufshcd_is_shutdown_ongoing(hba))
+ if (!ufshcd_is_shutdown_ongoing(hba) && !ufshcd_eh_in_progress(hba))
up_read(&hba->lock);
return err;
}
diff --git a/drivers/soc/qcom/glink_smem_native_xprt.c b/drivers/soc/qcom/glink_smem_native_xprt.c
index 168db46084df..8385987e8888 100644
--- a/drivers/soc/qcom/glink_smem_native_xprt.c
+++ b/drivers/soc/qcom/glink_smem_native_xprt.c
@@ -849,7 +849,7 @@ static void __rx_worker(struct edge_info *einfo, bool atomic_ctx)
rcu_id = srcu_read_lock(&einfo->use_ref);
- if (unlikely(!einfo->rx_fifo)) {
+ if (unlikely(!einfo->rx_fifo) && atomic_ctx) {
if (!get_rx_fifo(einfo)) {
srcu_read_unlock(&einfo->use_ref, rcu_id);
return;
diff --git a/drivers/soc/qcom/msm_bus/msm_bus_rules.c b/drivers/soc/qcom/msm_bus/msm_bus_rules.c
index ea29e303bbde..43a892bbd27c 100644
--- a/drivers/soc/qcom/msm_bus/msm_bus_rules.c
+++ b/drivers/soc/qcom/msm_bus/msm_bus_rules.c
@@ -597,7 +597,7 @@ void msm_rule_register(int num_rules, struct bus_rule_type *rule,
static bool __rule_unregister(int num_rules, struct bus_rule_type *rule,
struct notifier_block *nb)
{
- int i;
+ int i = 0;
struct rule_node_info *node = NULL;
struct rule_node_info *node_tmp = NULL;
struct rules_def *node_rule;
diff --git a/drivers/soc/qcom/subsys-pil-tz.c b/drivers/soc/qcom/subsys-pil-tz.c
index 991bce363740..f85c4ba06b47 100644
--- a/drivers/soc/qcom/subsys-pil-tz.c
+++ b/drivers/soc/qcom/subsys-pil-tz.c
@@ -1113,6 +1113,7 @@ static int pil_tz_driver_probe(struct platform_device *pdev)
rc = PTR_ERR(d->subsys);
goto err_subsys;
}
+ d->desc.subsys_dev = d->subsys;
return 0;
err_subsys:
diff --git a/drivers/soundwire/swr-wcd-ctrl.c b/drivers/soundwire/swr-wcd-ctrl.c
index e72663bd2138..14c13db991a1 100644
--- a/drivers/soundwire/swr-wcd-ctrl.c
+++ b/drivers/soundwire/swr-wcd-ctrl.c
@@ -540,7 +540,7 @@ static int swrm_read(struct swr_master *master, u8 dev_num, u16 reg_addr,
{
struct swr_mstr_ctrl *swrm = swr_get_ctrl_data(master);
int ret = 0;
- int val;
+ int val = 0;
u8 *reg_val = (u8 *)buf;
if (!swrm) {
diff --git a/drivers/staging/android/lowmemorykiller.c b/drivers/staging/android/lowmemorykiller.c
index 205af6627b80..1de3dddfd0f4 100644
--- a/drivers/staging/android/lowmemorykiller.c
+++ b/drivers/staging/android/lowmemorykiller.c
@@ -146,7 +146,7 @@ int adjust_minadj(short *min_score_adj)
static int lmk_vmpressure_notifier(struct notifier_block *nb,
unsigned long action, void *data)
{
- int other_free, other_file;
+ int other_free = 0, other_file = 0;
unsigned long pressure = action;
int array_size = ARRAY_SIZE(lowmem_adj);
diff --git a/drivers/thermal/msm-tsens.c b/drivers/thermal/msm-tsens.c
index d59b9736c570..5f955af4671a 100644
--- a/drivers/thermal/msm-tsens.c
+++ b/drivers/thermal/msm-tsens.c
@@ -2119,7 +2119,7 @@ static int get_device_tree_data(struct platform_device *pdev,
{
struct device_node *of_node = pdev->dev.of_node;
struct resource *res_mem = NULL;
- u32 *tsens_slope_data, *sensor_id, *client_id;
+ u32 *tsens_slope_data = NULL, *sensor_id, *client_id;
u32 *temp1_calib_offset_factor, *temp2_calib_offset_factor;
u32 rc = 0, i, tsens_num_sensors = 0;
u32 cycle_monitor = 0, wd_bark = 0;
diff --git a/drivers/usb/host/xhci-hub.c b/drivers/usb/host/xhci-hub.c
index d885033d3322..9dbd7595a7a3 100644
--- a/drivers/usb/host/xhci-hub.c
+++ b/drivers/usb/host/xhci-hub.c
@@ -376,10 +376,6 @@ static int xhci_stop_device(struct xhci_hcd *xhci, int slot_id, int suspend)
int i;
ret = 0;
- virt_dev = xhci->devs[slot_id];
- if (!virt_dev)
- return -ENODEV;
-
cmd = xhci_alloc_command(xhci, false, true, GFP_NOIO);
if (!cmd) {
xhci_dbg(xhci, "Couldn't allocate command structure.\n");
@@ -387,6 +383,13 @@ static int xhci_stop_device(struct xhci_hcd *xhci, int slot_id, int suspend)
}
spin_lock_irqsave(&xhci->lock, flags);
+ virt_dev = xhci->devs[slot_id];
+ if (!virt_dev) {
+ spin_unlock_irqrestore(&xhci->lock, flags);
+ xhci_free_command(xhci, cmd);
+ return -ENODEV;
+ }
+
for (i = LAST_EP_INDEX; i > 0; i--) {
if (virt_dev->eps[i].ring && virt_dev->eps[i].ring->dequeue) {
struct xhci_command *command;
@@ -403,6 +406,7 @@ static int xhci_stop_device(struct xhci_hcd *xhci, int slot_id, int suspend)
i, suspend);
if (ret) {
spin_unlock_irqrestore(&xhci->lock, flags);
+ xhci_free_command(xhci, command);
goto err_cmd_queue;
}
}
diff --git a/drivers/usb/pd/policy_engine.c b/drivers/usb/pd/policy_engine.c
index d46e21bd2c68..7a250c31f44d 100644
--- a/drivers/usb/pd/policy_engine.c
+++ b/drivers/usb/pd/policy_engine.c
@@ -29,6 +29,11 @@
#include <linux/usb/usbpd.h>
#include "usbpd.h"
+/* To start USB stack for USB3.1 complaince testing */
+static bool usb_compliance_mode;
+module_param(usb_compliance_mode, bool, S_IRUGO|S_IWUSR);
+MODULE_PARM_DESC(usb_compliance_mode, "Start USB stack for USB3.1 compliance testing");
+
enum usbpd_state {
PE_UNKNOWN,
PE_ERROR_RECOVERY,
@@ -483,13 +488,12 @@ static int pd_send_msg(struct usbpd *pd, u8 hdr_type, const u32 *data,
ret = pd_phy_write(hdr, (u8 *)data, num_data * sizeof(u32), type, 15);
/* TODO figure out timeout. based on tReceive=1.1ms x nRetryCount? */
- /* MessageID incremented regardless of Tx error */
- pd->tx_msgid = (pd->tx_msgid + 1) & PD_MAX_MSG_ID;
-
if (ret < 0)
return ret;
else if (ret != num_data * sizeof(u32))
return -EIO;
+
+ pd->tx_msgid = (pd->tx_msgid + 1) & PD_MAX_MSG_ID;
return 0;
}
@@ -581,6 +585,8 @@ static int pd_eval_src_caps(struct usbpd *pd)
static void pd_send_hard_reset(struct usbpd *pd)
{
+ union power_supply_propval val = {0};
+
usbpd_dbg(&pd->dev, "send hard reset");
/* Force CC logic to source/sink to keep Rp/Rd unchanged */
@@ -588,6 +594,7 @@ static void pd_send_hard_reset(struct usbpd *pd)
pd->hard_reset_count++;
pd_phy_signal(HARD_RESET_SIG, 5); /* tHardResetComplete */
pd->in_pr_swap = false;
+ power_supply_set_property(pd->usb_psy, POWER_SUPPLY_PROP_PR_SWAP, &val);
}
static void kick_sm(struct usbpd *pd, int ms)
@@ -603,6 +610,8 @@ static void kick_sm(struct usbpd *pd, int ms)
static void phy_sig_received(struct usbpd *pd, enum pd_sig_type type)
{
+ union power_supply_propval val = {1};
+
if (type != HARD_RESET_SIG) {
usbpd_err(&pd->dev, "invalid signal (%d) received\n", type);
return;
@@ -613,6 +622,9 @@ static void phy_sig_received(struct usbpd *pd, enum pd_sig_type type)
/* Force CC logic to source/sink to keep Rp/Rd unchanged */
set_power_role(pd, pd->current_pr);
pd->hard_reset_recvd = true;
+ power_supply_set_property(pd->usb_psy,
+ POWER_SUPPLY_PROP_PD_IN_HARD_RESET, &val);
+
kick_sm(pd, 0);
}
@@ -778,6 +790,9 @@ static void usbpd_set_state(struct usbpd *pd, enum usbpd_state next_state)
if (pd->in_pr_swap) {
kick_sm(pd, SWAP_SOURCE_START_TIME);
pd->in_pr_swap = false;
+ val.intval = 0;
+ power_supply_set_property(pd->usb_psy,
+ POWER_SUPPLY_PROP_PR_SWAP, &val);
break;
}
@@ -890,7 +905,8 @@ static void usbpd_set_state(struct usbpd *pd, enum usbpd_state next_state)
pd->current_dr = DR_UFP;
if (pd->psy_type == POWER_SUPPLY_TYPE_USB ||
- pd->psy_type == POWER_SUPPLY_TYPE_USB_CDP)
+ pd->psy_type == POWER_SUPPLY_TYPE_USB_CDP ||
+ usb_compliance_mode)
start_usb_peripheral(pd);
}
@@ -1566,7 +1582,6 @@ static void usbpd_sm(struct work_struct *w)
memset(&pd->received_pdos, 0, sizeof(pd->received_pdos));
rx_msg_cleanup(pd);
- val.intval = 0;
power_supply_set_property(pd->usb_psy,
POWER_SUPPLY_PROP_PD_IN_HARD_RESET, &val);
@@ -1597,6 +1612,10 @@ static void usbpd_sm(struct work_struct *w)
usleep_range(ERROR_RECOVERY_TIME * USEC_PER_MSEC,
(ERROR_RECOVERY_TIME + 5) * USEC_PER_MSEC);
+ val.intval = 0;
+ power_supply_set_property(pd->usb_psy,
+ POWER_SUPPLY_PROP_PR_SWAP, &val);
+
/* set due to dual_role class "mode" change */
if (pd->forced_pr != POWER_SUPPLY_TYPEC_PR_NONE)
val.intval = pd->forced_pr;
@@ -1620,11 +1639,22 @@ static void usbpd_sm(struct work_struct *w)
if (pd->hard_reset_recvd) {
pd->hard_reset_recvd = false;
- val.intval = 1;
+ if (pd->requested_current) {
+ val.intval = pd->requested_current = 0;
+ power_supply_set_property(pd->usb_psy,
+ POWER_SUPPLY_PROP_PD_CURRENT_MAX, &val);
+ }
+
+ pd->requested_voltage = 5000000;
+ val.intval = pd->requested_voltage;
power_supply_set_property(pd->usb_psy,
- POWER_SUPPLY_PROP_PD_IN_HARD_RESET, &val);
+ POWER_SUPPLY_PROP_VOLTAGE_MIN, &val);
pd->in_pr_swap = false;
+ val.intval = 0;
+ power_supply_set_property(pd->usb_psy,
+ POWER_SUPPLY_PROP_PR_SWAP, &val);
+
pd->in_explicit_contract = false;
pd->selected_pdo = pd->requested_pdo = 0;
pd->rdo = 0;
@@ -1885,6 +1915,9 @@ static void usbpd_sm(struct work_struct *w)
case PE_SNK_WAIT_FOR_CAPABILITIES:
pd->in_pr_swap = false;
+ val.intval = 0;
+ power_supply_set_property(pd->usb_psy,
+ POWER_SUPPLY_PROP_PR_SWAP, &val);
if (IS_DATA(rx_msg, MSG_SOURCE_CAPABILITIES)) {
val.intval = 0;
@@ -1904,15 +1937,6 @@ static void usbpd_sm(struct work_struct *w)
POWER_SUPPLY_PROP_PD_ACTIVE, &val);
} else if (pd->hard_reset_count < 3) {
usbpd_set_state(pd, PE_SNK_HARD_RESET);
- } else if (pd->pd_connected) {
- usbpd_info(&pd->dev, "Sink hard reset count exceeded, forcing reconnect\n");
-
- val.intval = 0;
- power_supply_set_property(pd->usb_psy,
- POWER_SUPPLY_PROP_PD_IN_HARD_RESET,
- &val);
-
- usbpd_set_state(pd, PE_ERROR_RECOVERY);
} else {
usbpd_dbg(&pd->dev, "Sink hard reset count exceeded, disabling PD\n");
@@ -2063,6 +2087,9 @@ static void usbpd_sm(struct work_struct *w)
}
pd->in_pr_swap = true;
+ val.intval = 1;
+ power_supply_set_property(pd->usb_psy,
+ POWER_SUPPLY_PROP_PR_SWAP, &val);
usbpd_set_state(pd, PE_PRS_SNK_SRC_TRANSITION_TO_OFF);
break;
} else if (IS_CTRL(rx_msg, MSG_VCONN_SWAP)) {
@@ -2206,6 +2233,9 @@ static void usbpd_sm(struct work_struct *w)
case PE_PRS_SRC_SNK_TRANSITION_TO_OFF:
pd->in_pr_swap = true;
+ val.intval = 1;
+ power_supply_set_property(pd->usb_psy,
+ POWER_SUPPLY_PROP_PR_SWAP, &val);
pd->in_explicit_contract = false;
if (pd->vbus_enabled) {
@@ -2246,6 +2276,9 @@ static void usbpd_sm(struct work_struct *w)
}
pd->in_pr_swap = true;
+ val.intval = 1;
+ power_supply_set_property(pd->usb_psy,
+ POWER_SUPPLY_PROP_PR_SWAP, &val);
usbpd_set_state(pd, PE_PRS_SNK_SRC_TRANSITION_TO_OFF);
break;
diff --git a/drivers/usb/pd/qpnp-pdphy.c b/drivers/usb/pd/qpnp-pdphy.c
index fa3b71d6ce08..e200c25bc23a 100644
--- a/drivers/usb/pd/qpnp-pdphy.c
+++ b/drivers/usb/pd/qpnp-pdphy.c
@@ -108,6 +108,7 @@ struct usb_pdphy {
int tx_status;
u8 frame_filter_val;
bool in_test_data_mode;
+ bool rx_busy;
enum data_role data_role;
enum power_role power_role;
@@ -485,6 +486,12 @@ int pd_phy_write(u16 hdr, const u8 *data, size_t data_len,
return -EINVAL;
}
+ ret = pdphy_reg_read(pdphy, &val, USB_PDPHY_RX_ACKNOWLEDGE, 1);
+ if (ret || val || pdphy->rx_busy) {
+ dev_err(pdphy->dev, "%s: RX message pending\n", __func__);
+ return -EBUSY;
+ }
+
pdphy->tx_status = -EINPROGRESS;
/* write 2 byte SOP message header */
@@ -657,6 +664,15 @@ static int pd_phy_bist_mode(u8 bist_mode)
BIST_MODE_MASK | BIST_ENABLE, bist_mode | BIST_ENABLE);
}
+static irqreturn_t pdphy_msg_rx_irq(int irq, void *data)
+{
+ struct usb_pdphy *pdphy = data;
+
+ pdphy->rx_busy = true;
+
+ return IRQ_WAKE_THREAD;
+}
+
static irqreturn_t pdphy_msg_rx_irq_thread(int irq, void *data)
{
u8 size, rx_status, frame_type;
@@ -713,6 +729,7 @@ static irqreturn_t pdphy_msg_rx_irq_thread(int irq, void *data)
false);
pdphy->rx_bytes += size + 1;
done:
+ pdphy->rx_busy = false;
return IRQ_HANDLED;
}
@@ -798,7 +815,7 @@ static int pdphy_probe(struct platform_device *pdev)
return ret;
ret = pdphy_request_irq(pdphy, pdev->dev.of_node,
- &pdphy->msg_rx_irq, "msg-rx", NULL,
+ &pdphy->msg_rx_irq, "msg-rx", pdphy_msg_rx_irq,
pdphy_msg_rx_irq_thread, (IRQF_TRIGGER_RISING | IRQF_ONESHOT));
if (ret < 0)
return ret;
diff --git a/drivers/video/fbdev/core/fbmem.c b/drivers/video/fbdev/core/fbmem.c
index c082ae8e50ce..2a708dd2ecee 100644
--- a/drivers/video/fbdev/core/fbmem.c
+++ b/drivers/video/fbdev/core/fbmem.c
@@ -1097,6 +1097,13 @@ static long do_fb_ioctl(struct fb_info *info, unsigned int cmd,
void __user *argp = (void __user *)arg;
long ret = 0;
+ memset(&var, 0, sizeof(var));
+ memset(&fix, 0, sizeof(fix));
+ memset(&con2fb, 0, sizeof(con2fb));
+ memset(&cmap_from, 0, sizeof(cmap_from));
+ memset(&cmap, 0, sizeof(cmap));
+ memset(&event, 0, sizeof(event));
+
switch (cmd) {
case FBIOGET_VSCREENINFO:
if (!lock_fb_info(info))
diff --git a/drivers/video/fbdev/msm/mdss_dba_utils.c b/drivers/video/fbdev/msm/mdss_dba_utils.c
index 3330f8f62b78..c6ff92ed1686 100644
--- a/drivers/video/fbdev/msm/mdss_dba_utils.c
+++ b/drivers/video/fbdev/msm/mdss_dba_utils.c
@@ -576,7 +576,6 @@ int mdss_dba_utils_video_on(void *data, struct mdss_panel_info *pinfo)
video_cfg.h_pulse_width = pinfo->lcdc.h_pulse_width;
video_cfg.v_pulse_width = pinfo->lcdc.v_pulse_width;
video_cfg.pclk_khz = (unsigned long)pinfo->clk_rate / 1000;
- video_cfg.hdmi_mode = !hdmi_edid_is_dvi_mode(ud->edid_data);
/* Calculate number of DSI lanes configured */
video_cfg.num_of_input_lanes = 0;
@@ -592,6 +591,8 @@ int mdss_dba_utils_video_on(void *data, struct mdss_panel_info *pinfo)
/* Get scan information from EDID */
video_cfg.vic = mdss_dba_get_vic_panel_info(ud, pinfo);
ud->current_vic = video_cfg.vic;
+ video_cfg.hdmi_mode = hdmi_edid_get_sink_mode(ud->edid_data,
+ video_cfg.vic);
video_cfg.scaninfo = hdmi_edid_get_sink_scaninfo(ud->edid_data,
video_cfg.vic);
if (ud->ops.video_on)
diff --git a/drivers/video/fbdev/msm/mdss_dp_util.c b/drivers/video/fbdev/msm/mdss_dp_util.c
index 0d9cf7b72b4d..e8c3fe9f4957 100644
--- a/drivers/video/fbdev/msm/mdss_dp_util.c
+++ b/drivers/video/fbdev/msm/mdss_dp_util.c
@@ -311,7 +311,7 @@ static void mdss_dp_calc_tu_parameters(u8 link_rate, u8 ln_cnt,
bool n_err_neg, nn_err_neg;
u8 hblank_margin = 16;
- u8 tu_size, tu_size_desired, tu_size_minus1;
+ u8 tu_size, tu_size_desired = 0, tu_size_minus1;
int valid_boundary_link;
u64 resulting_valid;
u64 total_valid;
diff --git a/drivers/video/fbdev/msm/mdss_dsi.c b/drivers/video/fbdev/msm/mdss_dsi.c
index d5caf0e6bb1c..4f1333426113 100644
--- a/drivers/video/fbdev/msm/mdss_dsi.c
+++ b/drivers/video/fbdev/msm/mdss_dsi.c
@@ -2091,7 +2091,7 @@ static int __mdss_dsi_dfps_update_clks(struct mdss_panel_data *pdata,
{
struct mdss_dsi_ctrl_pdata *ctrl_pdata = NULL;
struct mdss_dsi_ctrl_pdata *sctrl_pdata = NULL;
- struct mdss_panel_info *pinfo, *spinfo;
+ struct mdss_panel_info *pinfo, *spinfo = NULL;
int rc = 0;
if (pdata == NULL) {
@@ -4301,6 +4301,15 @@ static int mdss_dsi_parse_gpio_params(struct platform_device *ctrl_pdev,
of_property_read_bool(ctrl_pdev->dev.of_node,
"qcom,platform-bklight-en-gpio-invert");
+ ctrl_pdata->avdd_en_gpio = of_get_named_gpio(ctrl_pdev->dev.of_node,
+ "qcom,platform-avdd-en-gpio", 0);
+ if (!gpio_is_valid(ctrl_pdata->avdd_en_gpio))
+ pr_info("%s: avdd_en gpio not specified\n", __func__);
+
+ ctrl_pdata->avdd_en_gpio_invert =
+ of_property_read_bool(ctrl_pdev->dev.of_node,
+ "qcom,platform-avdd-en-gpio-invert");
+
ctrl_pdata->rst_gpio = of_get_named_gpio(ctrl_pdev->dev.of_node,
"qcom,platform-reset-gpio", 0);
if (!gpio_is_valid(ctrl_pdata->rst_gpio))
diff --git a/drivers/video/fbdev/msm/mdss_dsi.h b/drivers/video/fbdev/msm/mdss_dsi.h
index 62d88f0af652..7fabd4944cbd 100644
--- a/drivers/video/fbdev/msm/mdss_dsi.h
+++ b/drivers/video/fbdev/msm/mdss_dsi.h
@@ -455,6 +455,8 @@ struct mdss_dsi_ctrl_pdata {
int bklt_en_gpio;
bool bklt_en_gpio_invert;
bool bklt_en_gpio_state;
+ int avdd_en_gpio;
+ bool avdd_en_gpio_invert;
int lcd_mode_sel_gpio;
int bklt_ctrl; /* backlight ctrl */
bool pwm_pmi;
diff --git a/drivers/video/fbdev/msm/mdss_dsi_host.c b/drivers/video/fbdev/msm/mdss_dsi_host.c
index f0fb791a7b8d..b448153df1df 100644
--- a/drivers/video/fbdev/msm/mdss_dsi_host.c
+++ b/drivers/video/fbdev/msm/mdss_dsi_host.c
@@ -1161,6 +1161,8 @@ static int mdss_dsi_read_status(struct mdss_dsi_ctrl_pdata *ctrl)
rc = mdss_dsi_cmdlist_put(ctrl, &cmdreq);
if (rc <= 0) {
+ if (!mdss_dsi_sync_wait_enable(ctrl) ||
+ mdss_dsi_sync_wait_trigger(ctrl))
pr_err("%s: get status: fail\n", __func__);
return rc;
}
diff --git a/drivers/video/fbdev/msm/mdss_dsi_panel.c b/drivers/video/fbdev/msm/mdss_dsi_panel.c
index 60012c71449c..695dbfa95e29 100644
--- a/drivers/video/fbdev/msm/mdss_dsi_panel.c
+++ b/drivers/video/fbdev/msm/mdss_dsi_panel.c
@@ -260,6 +260,15 @@ static int mdss_dsi_request_gpios(struct mdss_dsi_ctrl_pdata *ctrl_pdata)
rc);
goto rst_gpio_err;
}
+ if (gpio_is_valid(ctrl_pdata->avdd_en_gpio)) {
+ rc = gpio_request(ctrl_pdata->avdd_en_gpio,
+ "avdd_enable");
+ if (rc) {
+ pr_err("request avdd_en gpio failed, rc=%d\n",
+ rc);
+ goto avdd_en_gpio_err;
+ }
+ }
if (gpio_is_valid(ctrl_pdata->lcd_mode_sel_gpio)) {
rc = gpio_request(ctrl_pdata->lcd_mode_sel_gpio, "mode_sel");
if (rc) {
@@ -272,6 +281,9 @@ static int mdss_dsi_request_gpios(struct mdss_dsi_ctrl_pdata *ctrl_pdata)
return rc;
lcd_mode_sel_gpio_err:
+ if (gpio_is_valid(ctrl_pdata->avdd_en_gpio))
+ gpio_free(ctrl_pdata->avdd_en_gpio);
+avdd_en_gpio_err:
gpio_free(ctrl_pdata->rst_gpio);
rst_gpio_err:
if (gpio_is_valid(ctrl_pdata->disp_en_gpio))
@@ -424,6 +436,21 @@ int mdss_dsi_panel_reset(struct mdss_panel_data *pdata, int enable)
if (pdata->panel_info.rst_seq[++i])
usleep_range(pinfo->rst_seq[i] * 1000, pinfo->rst_seq[i] * 1000);
}
+
+ if (gpio_is_valid(ctrl_pdata->avdd_en_gpio)) {
+ if (ctrl_pdata->avdd_en_gpio_invert) {
+ rc = gpio_direction_output(
+ ctrl_pdata->avdd_en_gpio, 0);
+ } else {
+ rc = gpio_direction_output(
+ ctrl_pdata->avdd_en_gpio, 1);
+ }
+ if (rc) {
+ pr_err("%s: unable to set dir for avdd_en gpio\n",
+ __func__);
+ goto exit;
+ }
+ }
}
if (gpio_is_valid(ctrl_pdata->lcd_mode_sel_gpio)) {
@@ -452,6 +479,14 @@ int mdss_dsi_panel_reset(struct mdss_panel_data *pdata, int enable)
pr_debug("%s: Reset panel done\n", __func__);
}
} else {
+ if (gpio_is_valid(ctrl_pdata->avdd_en_gpio)) {
+ if (ctrl_pdata->avdd_en_gpio_invert)
+ gpio_set_value((ctrl_pdata->avdd_en_gpio), 1);
+ else
+ gpio_set_value((ctrl_pdata->avdd_en_gpio), 0);
+
+ gpio_free(ctrl_pdata->avdd_en_gpio);
+ }
if (gpio_is_valid(ctrl_pdata->disp_en_gpio)) {
gpio_set_value((ctrl_pdata->disp_en_gpio), 0);
gpio_free(ctrl_pdata->disp_en_gpio);
diff --git a/drivers/video/fbdev/msm/mdss_fb.c b/drivers/video/fbdev/msm/mdss_fb.c
index 40a79c4af38e..31cba148ad28 100644
--- a/drivers/video/fbdev/msm/mdss_fb.c
+++ b/drivers/video/fbdev/msm/mdss_fb.c
@@ -3607,6 +3607,16 @@ static void mdss_fb_var_to_panelinfo(struct fb_var_screeninfo *var,
*/
if (pinfo->is_dba_panel)
pinfo->mipi.dsi_pclk_rate = pinfo->clk_rate;
+
+ if (var->sync & FB_SYNC_HOR_HIGH_ACT)
+ pinfo->lcdc.h_polarity = 0;
+ else
+ pinfo->lcdc.h_polarity = 1;
+
+ if (var->sync & FB_SYNC_VERT_HIGH_ACT)
+ pinfo->lcdc.v_polarity = 0;
+ else
+ pinfo->lcdc.v_polarity = 1;
}
void mdss_panelinfo_to_fb_var(struct mdss_panel_info *pinfo,
diff --git a/drivers/video/fbdev/msm/mdss_hdmi_edid.c b/drivers/video/fbdev/msm/mdss_hdmi_edid.c
index 102c22cba7dd..ddc5edbe010d 100644
--- a/drivers/video/fbdev/msm/mdss_hdmi_edid.c
+++ b/drivers/video/fbdev/msm/mdss_hdmi_edid.c
@@ -62,11 +62,6 @@
#define EDID_VENDOR_ID_SIZE 4
#define EDID_IEEE_REG_ID 0x0c03
-enum edid_sink_mode {
- SINK_MODE_DVI,
- SINK_MODE_HDMI
-};
-
enum luminance_value {
NO_LUMINANCE_DATA = 3,
MAXIMUM_LUMINANCE = 4,
@@ -2406,7 +2401,7 @@ end:
return scaninfo;
} /* hdmi_edid_get_sink_scaninfo */
-static u32 hdmi_edid_get_sink_mode(void *input)
+u32 hdmi_edid_get_sink_mode(void *input, u32 mode)
{
struct hdmi_edid_ctrl *edid_ctrl = (struct hdmi_edid_ctrl *)input;
bool sink_mode;
@@ -2419,8 +2414,13 @@ static u32 hdmi_edid_get_sink_mode(void *input)
if (edid_ctrl->edid_override &&
(edid_ctrl->override_data.sink_mode != -1))
sink_mode = edid_ctrl->override_data.sink_mode;
- else
- sink_mode = edid_ctrl->sink_mode;
+ else {
+ if (edid_ctrl->sink_mode &&
+ (mode > 0 && mode <= HDMI_EVFRMT_END))
+ sink_mode = SINK_MODE_HDMI;
+ else
+ sink_mode = SINK_MODE_DVI;
+ }
return sink_mode;
} /* hdmi_edid_get_sink_mode */
@@ -2435,10 +2435,21 @@ static u32 hdmi_edid_get_sink_mode(void *input)
*/
bool hdmi_edid_is_dvi_mode(void *input)
{
- if (hdmi_edid_get_sink_mode(input))
- return false;
- else
+ struct hdmi_edid_ctrl *edid_ctrl = (struct hdmi_edid_ctrl *)input;
+ int sink_mode;
+
+ if (!edid_ctrl) {
+ DEV_ERR("%s: invalid input\n", __func__);
return true;
+ }
+
+ if (edid_ctrl->edid_override &&
+ (edid_ctrl->override_data.sink_mode != -1))
+ sink_mode = edid_ctrl->override_data.sink_mode;
+ else
+ sink_mode = edid_ctrl->sink_mode;
+
+ return (sink_mode == SINK_MODE_DVI);
}
/**
diff --git a/drivers/video/fbdev/msm/mdss_hdmi_edid.h b/drivers/video/fbdev/msm/mdss_hdmi_edid.h
index af802bb45f89..c604d0fbf7b2 100644
--- a/drivers/video/fbdev/msm/mdss_hdmi_edid.h
+++ b/drivers/video/fbdev/msm/mdss_hdmi_edid.h
@@ -58,10 +58,16 @@ struct hdmi_edid_override_data {
int vic;
};
+enum edid_sink_mode {
+ SINK_MODE_DVI,
+ SINK_MODE_HDMI
+};
+
int hdmi_edid_parser(void *edid_ctrl);
u32 hdmi_edid_get_raw_data(void *edid_ctrl, u8 *buf, u32 size);
u8 hdmi_edid_get_sink_scaninfo(void *edid_ctrl, u32 resolution);
bool hdmi_edid_is_dvi_mode(void *input);
+u32 hdmi_edid_get_sink_mode(void *edid_ctrl, u32 mode);
bool hdmi_edid_sink_scramble_override(void *input);
bool hdmi_edid_get_sink_scrambler_support(void *input);
bool hdmi_edid_get_scdc_support(void *input);
diff --git a/drivers/video/fbdev/msm/mdss_hdmi_tx.c b/drivers/video/fbdev/msm/mdss_hdmi_tx.c
index 07592fa26a49..a9ab970fb4bc 100644
--- a/drivers/video/fbdev/msm/mdss_hdmi_tx.c
+++ b/drivers/video/fbdev/msm/mdss_hdmi_tx.c
@@ -66,7 +66,7 @@
#define HDMI_TX_4_MAX_PCLK_RATE 600000
#define hdmi_tx_get_fd(x) ((x && (ffs(x) > 0)) ? \
- hdmi_ctrl->feature_data[ffs(x) - 1] : 0)
+ hdmi_ctrl->feature_data[ffs(x) - 1] : NULL)
#define hdmi_tx_set_fd(x, y) {if (x && (ffs(x) > 0)) \
hdmi_ctrl->feature_data[ffs(x) - 1] = y; }
@@ -375,9 +375,12 @@ static void hdmi_tx_audio_setup(struct hdmi_tx_ctrl *hdmi_ctrl)
}
}
-static inline u32 hdmi_tx_is_dvi_mode(struct hdmi_tx_ctrl *hdmi_ctrl)
+static inline bool hdmi_tx_is_dvi_mode(struct hdmi_tx_ctrl *hdmi_ctrl)
{
- return hdmi_edid_is_dvi_mode(hdmi_tx_get_fd(HDMI_TX_FEAT_EDID));
+ void *data = hdmi_tx_get_fd(HDMI_TX_FEAT_EDID);
+
+ return (hdmi_edid_get_sink_mode(data,
+ hdmi_ctrl->vic) == SINK_MODE_DVI);
} /* hdmi_tx_is_dvi_mode */
static inline u32 hdmi_tx_is_in_splash(struct hdmi_tx_ctrl *hdmi_ctrl)
@@ -2156,6 +2159,8 @@ static int hdmi_tx_init_panel_info(struct hdmi_tx_ctrl *hdmi_ctrl)
pinfo->lcdc.v_front_porch = timing.front_porch_v;
pinfo->lcdc.v_pulse_width = timing.pulse_width_v;
pinfo->lcdc.frame_rate = timing.refresh_rate;
+ pinfo->lcdc.h_polarity = timing.active_low_h;
+ pinfo->lcdc.v_polarity = timing.active_low_v;
pinfo->type = DTV_PANEL;
pinfo->pdest = DISPLAY_3;
@@ -2442,6 +2447,7 @@ static void hdmi_tx_set_mode(struct hdmi_tx_ctrl *hdmi_ctrl, u32 power_on)
struct dss_io_data *io = NULL;
/* Defaults: Disable block, HDMI mode */
u32 hdmi_ctrl_reg = BIT(1);
+ void *data = hdmi_tx_get_fd(HDMI_TX_FEAT_EDID);
if (!hdmi_ctrl) {
DEV_ERR("%s: invalid input\n", __func__);
@@ -2470,7 +2476,8 @@ static void hdmi_tx_set_mode(struct hdmi_tx_ctrl *hdmi_ctrl, u32 power_on)
hdmi_ctrl_reg |= BIT(2);
/* Set transmission mode to DVI based in EDID info */
- if (hdmi_edid_is_dvi_mode(hdmi_tx_get_fd(HDMI_TX_FEAT_EDID)))
+ if (hdmi_edid_get_sink_mode(data,
+ hdmi_ctrl->vic) == SINK_MODE_DVI)
hdmi_ctrl_reg &= ~BIT(1); /* DVI mode */
/*
@@ -2929,7 +2936,6 @@ static int hdmi_tx_audio_info_setup(struct platform_device *pdev,
{
int rc = 0;
struct hdmi_tx_ctrl *hdmi_ctrl = platform_get_drvdata(pdev);
- u32 is_mode_dvi;
if (!hdmi_ctrl || !params) {
DEV_ERR("%s: invalid input\n", __func__);
@@ -2938,9 +2944,8 @@ static int hdmi_tx_audio_info_setup(struct platform_device *pdev,
mutex_lock(&hdmi_ctrl->tx_lock);
- is_mode_dvi = hdmi_tx_is_dvi_mode(hdmi_ctrl);
-
- if (!is_mode_dvi && hdmi_tx_is_panel_on(hdmi_ctrl)) {
+ if (!hdmi_tx_is_dvi_mode(hdmi_ctrl) &&
+ hdmi_tx_is_panel_on(hdmi_ctrl)) {
memcpy(&hdmi_ctrl->audio_params, params,
sizeof(struct msm_ext_disp_audio_setup_params));
diff --git a/drivers/video/fbdev/msm/mdss_hdmi_util.c b/drivers/video/fbdev/msm/mdss_hdmi_util.c
index 102c2f994646..827013d06412 100644
--- a/drivers/video/fbdev/msm/mdss_hdmi_util.c
+++ b/drivers/video/fbdev/msm/mdss_hdmi_util.c
@@ -857,7 +857,7 @@ static int hdmi_ddc_read_retry(struct hdmi_tx_ddc_ctrl *ddc_ctrl)
u32 reg_val, ndx, time_out_count, wait_time;
struct hdmi_tx_ddc_data *ddc_data;
int status;
- int busy_wait_us;
+ int busy_wait_us = 0;
if (!ddc_ctrl || !ddc_ctrl->io) {
pr_err("invalid input\n");
@@ -1335,7 +1335,7 @@ int hdmi_ddc_write(struct hdmi_tx_ddc_ctrl *ddc_ctrl)
u32 time_out_count;
struct hdmi_tx_ddc_data *ddc_data;
u32 wait_time;
- int busy_wait_us;
+ int busy_wait_us = 0;
if (!ddc_ctrl || !ddc_ctrl->io) {
pr_err("invalid input\n");
diff --git a/drivers/video/fbdev/msm/mdss_mdp.c b/drivers/video/fbdev/msm/mdss_mdp.c
index d88d87bd2092..6936c4c1f3cc 100644
--- a/drivers/video/fbdev/msm/mdss_mdp.c
+++ b/drivers/video/fbdev/msm/mdss_mdp.c
@@ -2180,7 +2180,6 @@ static void mdss_mdp_hw_rev_caps_init(struct mdss_data_type *mdata)
mdss_set_quirk(mdata, MDSS_QUIRK_MDP_CLK_SET_RATE);
mdata->has_wb_ubwc = true;
set_bit(MDSS_CAPS_10_BIT_SUPPORTED, mdata->mdss_caps_map);
- set_bit(MDSS_CAPS_AVR_SUPPORTED, mdata->mdss_caps_map);
set_bit(MDSS_CAPS_SEC_DETACH_SMMU, mdata->mdss_caps_map);
mdss_set_quirk(mdata, MDSS_QUIRK_HDR_SUPPORT_ENABLED);
break;
diff --git a/drivers/video/fbdev/msm/mdss_mdp.h b/drivers/video/fbdev/msm/mdss_mdp.h
index cd403f19c088..5a15b557e5c7 100644
--- a/drivers/video/fbdev/msm/mdss_mdp.h
+++ b/drivers/video/fbdev/msm/mdss_mdp.h
@@ -1107,9 +1107,9 @@ static inline enum mdss_mdp_pu_type mdss_mdp_get_pu_type(
if (!is_split_lm(mctl->mfd) || mdss_mdp_is_both_lm_valid(mctl))
pu_type = MDSS_MDP_DEFAULT_UPDATE;
- else if (mctl->mixer_left->valid_roi)
+ else if (mctl->mixer_left && mctl->mixer_left->valid_roi)
pu_type = MDSS_MDP_LEFT_ONLY_UPDATE;
- else if (mctl->mixer_right->valid_roi)
+ else if (mctl->mixer_right && mctl->mixer_right->valid_roi)
pu_type = MDSS_MDP_RIGHT_ONLY_UPDATE;
else
pr_err("%s: invalid pu_type\n", __func__);
diff --git a/drivers/video/fbdev/msm/mdss_mdp_ctl.c b/drivers/video/fbdev/msm/mdss_mdp_ctl.c
index 929eeb270f32..0da462394ab8 100644
--- a/drivers/video/fbdev/msm/mdss_mdp_ctl.c
+++ b/drivers/video/fbdev/msm/mdss_mdp_ctl.c
@@ -571,6 +571,9 @@ static u32 __calc_qseed3_mdp_clk_rate(struct mdss_mdp_pipe *pipe,
u64 ver_dwnscale;
u64 active_line;
u64 backfill_line;
+ struct mdss_mdp_ctl *ctl = pipe->mixer_left->ctl;
+ u64 pclk_rate;
+ struct mdss_panel_info *pinfo = &ctl->panel_data->panel_info;
ver_dwnscale = (u64)src_h << PHASE_STEP_SHIFT;
do_div(ver_dwnscale, dst.h);
@@ -596,12 +599,26 @@ static u32 __calc_qseed3_mdp_clk_rate(struct mdss_mdp_pipe *pipe,
total_cycle = active_line_cycle + backfill_cycle;
+ /*
+ * MDP clkrate = total_cycle * PixelClock / Dest-width
+ * if pixelClock not available:
+ * = total_cycle * fps * v_total
+ */
+ if ((pinfo->type == MIPI_CMD_PANEL) && dst.w) {
+ pclk_rate = (u64)mdss_panel_get_htotal(pinfo, false) *
+ v_total * fps;
+ do_div(pclk_rate, pinfo->xres);
+ total_cycle *= pclk_rate;
+ } else {
+ total_cycle *= (fps * v_total);
+ }
+
pr_debug("line: active=%lld backfill=%lld vds=%lld\n",
active_line, backfill_line, ver_dwnscale);
pr_debug("cycle: total=%lld active=%lld backfill=%lld\n",
total_cycle, active_line_cycle, backfill_cycle);
- return (u32)total_cycle * (fps * v_total);
+ return (u32)total_cycle;
}
static inline bool __is_vert_downscaling(u32 src_h,
@@ -659,6 +676,7 @@ static u32 get_pipe_mdp_clk_rate(struct mdss_mdp_pipe *pipe,
if (flags & PERF_CALC_PIPE_APPLY_CLK_FUDGE)
rate = mdss_mdp_clk_fudge_factor(mixer, rate);
+ rate = min(mdata->max_mdp_clk_rate, rate);
return rate;
}
diff --git a/drivers/video/fbdev/msm/mdss_mdp_intf_video.c b/drivers/video/fbdev/msm/mdss_mdp_intf_video.c
index 587150bbc9fa..d9aaac4526ea 100644
--- a/drivers/video/fbdev/msm/mdss_mdp_intf_video.c
+++ b/drivers/video/fbdev/msm/mdss_mdp_intf_video.c
@@ -58,6 +58,8 @@ struct intf_timing_params {
u32 v_front_porch;
u32 hsync_pulse_width;
u32 vsync_pulse_width;
+ u32 h_polarity;
+ u32 v_polarity;
u32 border_clr;
u32 underflow_clr;
@@ -641,13 +643,8 @@ static int mdss_mdp_video_timegen_setup(struct mdss_mdp_ctl *ctl,
display_hctl = (hsync_end_x << 16) | hsync_start_x;
den_polarity = 0;
- if (MDSS_INTF_HDMI == ctx->intf_type) {
- hsync_polarity = p->yres >= 720 ? 0 : 1;
- vsync_polarity = p->yres >= 720 ? 0 : 1;
- } else {
- hsync_polarity = 0;
- vsync_polarity = 0;
- }
+ hsync_polarity = p->h_polarity;
+ vsync_polarity = p->v_polarity;
polarity_ctl = (den_polarity << 2) | /* DEN Polarity */
(vsync_polarity << 1) | /* VSYNC Polarity */
(hsync_polarity << 0); /* HSYNC Polarity */
@@ -2178,7 +2175,8 @@ static int mdss_mdp_video_ctx_setup(struct mdss_mdp_ctl *ctl,
itp->width = dsc->pclk_per_line;
itp->xres = dsc->pclk_per_line;
}
-
+ itp->h_polarity = pinfo->lcdc.h_polarity;
+ itp->v_polarity = pinfo->lcdc.v_polarity;
itp->h_back_porch = pinfo->lcdc.h_back_porch;
itp->h_front_porch = pinfo->lcdc.h_front_porch;
itp->v_back_porch = pinfo->lcdc.v_back_porch;
diff --git a/drivers/video/fbdev/msm/mdss_mdp_layer.c b/drivers/video/fbdev/msm/mdss_mdp_layer.c
index 472f1e8e8e3b..a1d79a89b463 100644
--- a/drivers/video/fbdev/msm/mdss_mdp_layer.c
+++ b/drivers/video/fbdev/msm/mdss_mdp_layer.c
@@ -1812,13 +1812,16 @@ static int __validate_secure_session(struct mdss_overlay_private *mdp5_data)
pr_debug("pipe count:: secure display:%d non-secure:%d secure-vid:%d,secure-cam:%d\n",
sd_pipes, nonsd_pipes, secure_vid_pipes, secure_cam_pipes);
+ MDSS_XLOG(mdss_get_sd_client_cnt(), sd_pipes, nonsd_pipes,
+ secure_vid_pipes, secure_cam_pipes);
if (mdss_get_sd_client_cnt() && !mdp5_data->sd_enabled) {
pr_err("Secure session already enabled for other client\n");
return -EINVAL;
}
- if ((sd_pipes) &&
+ if (((sd_pipes) || (mdp5_data->ctl->is_video_mode &&
+ mdss_get_sd_client_cnt())) &&
(nonsd_pipes || secure_vid_pipes ||
secure_cam_pipes)) {
pr_err("non-secure layer validation request during secure display session\n");
@@ -2410,14 +2413,14 @@ static int __validate_layers(struct msm_fb_data_type *mfd,
int layer_count = commit->input_layer_cnt;
u32 ds_mode = 0;
- struct mdss_mdp_pipe *pipe, *tmp, *left_blend_pipe;
+ struct mdss_mdp_pipe *pipe = NULL, *tmp, *left_blend_pipe;
struct mdss_mdp_pipe *right_plist[MAX_PIPES_PER_LM] = {0};
struct mdss_mdp_pipe *left_plist[MAX_PIPES_PER_LM] = {0};
struct mdss_overlay_private *mdp5_data = mfd_to_mdp5_data(mfd);
struct mdss_data_type *mdata = mfd_to_mdata(mfd);
struct mdss_mdp_mixer *mixer = NULL;
- struct mdp_input_layer *layer, *layer_list;
+ struct mdp_input_layer *layer = NULL, *layer_list;
struct mdss_mdp_validate_info_t *validate_info_list = NULL;
bool is_single_layer = false, force_validate;
enum layer_pipe_q pipe_q_type;
diff --git a/drivers/video/fbdev/msm/mdss_mdp_util.c b/drivers/video/fbdev/msm/mdss_mdp_util.c
index 22656175edf8..1ae3d0ba4ec6 100644
--- a/drivers/video/fbdev/msm/mdss_mdp_util.c
+++ b/drivers/video/fbdev/msm/mdss_mdp_util.c
@@ -428,8 +428,8 @@ static int mdss_mdp_get_ubwc_plane_size(struct mdss_mdp_format_params *fmt,
if (fmt->format == MDP_Y_CBCR_H2V2_UBWC ||
fmt->format == MDP_Y_CBCR_H2V2_TP10_UBWC) {
- uint32_t y_stride_alignment, uv_stride_alignment;
- uint32_t y_height_alignment, uv_height_alignment;
+ uint32_t y_stride_alignment = 0, uv_stride_alignment = 0;
+ uint32_t y_height_alignment = 0, uv_height_alignment = 0;
uint32_t y_tile_width = fmt_ubwc->micro.tile_width;
uint32_t y_tile_height = fmt_ubwc->micro.tile_height;
uint32_t uv_tile_width = y_tile_width / 2;
diff --git a/drivers/video/fbdev/msm/mdss_panel.h b/drivers/video/fbdev/msm/mdss_panel.h
index 37b0ca7aa44b..e8255ff45726 100644
--- a/drivers/video/fbdev/msm/mdss_panel.h
+++ b/drivers/video/fbdev/msm/mdss_panel.h
@@ -406,9 +406,10 @@ struct lcd_panel_info {
/* Pad height */
u32 yres_pad;
u32 frame_rate;
+ u32 h_polarity;
+ u32 v_polarity;
};
-
/* DSI PHY configuration */
struct mdss_dsi_phy_ctrl {
char regulator[7]; /* 8996, 1 * 5 */
diff --git a/drivers/video/fbdev/msm/mdss_rotator.c b/drivers/video/fbdev/msm/mdss_rotator.c
index 399a12e3dcc8..61b0518d3ee6 100644
--- a/drivers/video/fbdev/msm/mdss_rotator.c
+++ b/drivers/video/fbdev/msm/mdss_rotator.c
@@ -687,7 +687,7 @@ static struct mdss_rot_hw_resource *mdss_rotator_hw_alloc(
struct mdss_rot_hw_resource *hw;
struct mdss_data_type *mdata = mdss_mdp_get_mdata();
u32 pipe_ndx, offset = mdss_mdp_get_wb_ctl_support(mdata, true);
- int ret;
+ int ret = 0;
hw = devm_kzalloc(&mgr->pdev->dev, sizeof(struct mdss_rot_hw_resource),
GFP_KERNEL);
diff --git a/include/drm/drm_mm.h b/include/drm/drm_mm.h
index 0de6290df4da..6649b6d8c437 100644
--- a/include/drm/drm_mm.h
+++ b/include/drm/drm_mm.h
@@ -37,6 +37,7 @@
* Generic range manager structs
*/
#include <linux/bug.h>
+#include <linux/rbtree.h>
#include <linux/kernel.h>
#include <linux/list.h>
#include <linux/spinlock.h>
@@ -48,6 +49,7 @@ enum drm_mm_search_flags {
DRM_MM_SEARCH_DEFAULT = 0,
DRM_MM_SEARCH_BEST = 1 << 0,
DRM_MM_SEARCH_BELOW = 1 << 1,
+ DRM_MM_SEARCH_BOTTOM_UP = 1 << 2,
};
enum drm_mm_allocator_flags {
@@ -61,6 +63,8 @@ enum drm_mm_allocator_flags {
struct drm_mm_node {
struct list_head node_list;
struct list_head hole_stack;
+ struct rb_node rb;
+ struct rb_node hole_node;
unsigned hole_follows : 1;
unsigned scanned_block : 1;
unsigned scanned_prev_free : 1;
@@ -70,6 +74,7 @@ struct drm_mm_node {
unsigned long color;
u64 start;
u64 size;
+ u64 __subtree_last;
struct drm_mm *mm;
};
@@ -79,6 +84,10 @@ struct drm_mm {
/* head_node.node_list is the list of all memory nodes, ordered
* according to the (increasing) start address of the memory node. */
struct drm_mm_node head_node;
+ /* Keep an interval_tree for fast lookup of drm_mm_nodes by address. */
+ struct rb_root interval_tree;
+ struct rb_root holes_tree;
+
unsigned int scan_check_range : 1;
unsigned scan_alignment;
unsigned long scan_color;
@@ -301,6 +310,12 @@ void drm_mm_init(struct drm_mm *mm,
void drm_mm_takedown(struct drm_mm *mm);
bool drm_mm_clean(struct drm_mm *mm);
+struct drm_mm_node *
+drm_mm_interval_first(struct drm_mm *mm, u64 start, u64 last);
+
+struct drm_mm_node *
+drm_mm_interval_next(struct drm_mm_node *node, u64 start, u64 last);
+
void drm_mm_init_scan(struct drm_mm *mm,
u64 size,
unsigned alignment,
diff --git a/include/linux/mmc/host.h b/include/linux/mmc/host.h
index d9e12c1b1748..279411c42ded 100644
--- a/include/linux/mmc/host.h
+++ b/include/linux/mmc/host.h
@@ -330,7 +330,9 @@ struct mmc_devfeq_clk_scaling {
atomic_t devfreq_abort;
bool skip_clk_scale_freq_update;
int freq_table_sz;
+ int pltfm_freq_table_sz;
u32 *freq_table;
+ u32 *pltfm_freq_table;
unsigned long total_busy_time_us;
unsigned long target_freq;
unsigned long curr_freq;
diff --git a/include/linux/msm_mhi.h b/include/linux/msm_mhi.h
index 01fe2e78b9d5..1704cb93e6a3 100644
--- a/include/linux/msm_mhi.h
+++ b/include/linux/msm_mhi.h
@@ -160,9 +160,11 @@ enum mhi_dev_ctrl {
MHI_DEV_CTRL_RESUME,
MHI_DEV_CTRL_POWER_OFF,
MHI_DEV_CTRL_POWER_ON,
+ MHI_DEV_CTRL_TRIGGER_RDDM,
MHI_DEV_CTRL_RDDM,
MHI_DEV_CTRL_RDDM_KERNEL_PANIC,
MHI_DEV_CTRL_NOTIFY_LINK_ERROR,
+ MHI_DEV_CTRL_MAXCMD,
};
enum mhi_rddm_segment {
diff --git a/include/media/cec-notifier.h b/include/media/cec-notifier.h
new file mode 100644
index 000000000000..035712e0993d
--- /dev/null
+++ b/include/media/cec-notifier.h
@@ -0,0 +1,111 @@
+/*
+ * cec-notifier.h - notify CEC drivers of physical address changes
+ *
+ * Copyright 2016 Russell King <rmk+kernel@arm.linux.org.uk>
+ * Copyright 2016-2017 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
+ *
+ * This program is free software; you may redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#ifndef LINUX_CEC_NOTIFIER_H
+#define LINUX_CEC_NOTIFIER_H
+
+#include <linux/types.h>
+#include <media/cec-edid.h>
+
+struct device;
+struct edid;
+struct cec_adapter;
+struct cec_notifier;
+
+#ifdef CONFIG_MEDIA_CEC_NOTIFIER
+
+/**
+ * cec_notifier_get - find or create a new cec_notifier for the given device.
+ * @dev: device that sends the events.
+ *
+ * If a notifier for device @dev already exists, then increase the refcount
+ * and return that notifier.
+ *
+ * If it doesn't exist, then allocate a new notifier struct and return a
+ * pointer to that new struct.
+ *
+ * Return NULL if the memory could not be allocated.
+ */
+struct cec_notifier *cec_notifier_get(struct device *dev);
+
+/**
+ * cec_notifier_put - decrease refcount and delete when the refcount reaches 0.
+ * @n: notifier
+ */
+void cec_notifier_put(struct cec_notifier *n);
+
+/**
+ * cec_notifier_set_phys_addr - set a new physical address.
+ * @n: the CEC notifier
+ * @pa: the CEC physical address
+ *
+ * Set a new CEC physical address.
+ */
+void cec_notifier_set_phys_addr(struct cec_notifier *n, u16 pa);
+
+/**
+ * cec_notifier_set_phys_addr_from_edid - set parse the PA from the EDID.
+ * @n: the CEC notifier
+ * @edid: the struct edid pointer
+ *
+ * Parses the EDID to obtain the new CEC physical address and set it.
+ */
+void cec_notifier_set_phys_addr_from_edid(struct cec_notifier *n,
+ const struct edid *edid);
+
+/**
+ * cec_notifier_register - register a callback with the notifier
+ * @n: the CEC notifier
+ * @adap: the CEC adapter, passed as argument to the callback function
+ * @callback: the callback function
+ */
+void cec_notifier_register(struct cec_notifier *n,
+ struct cec_adapter *adap,
+ void (*callback)(struct cec_adapter *adap, u16 pa));
+
+/**
+ * cec_notifier_unregister - unregister the callback from the notifier.
+ * @n: the CEC notifier
+ */
+void cec_notifier_unregister(struct cec_notifier *n);
+
+#else
+static inline struct cec_notifier *cec_notifier_get(struct device *dev)
+{
+ /* A non-NULL pointer is expected on success */
+ return (struct cec_notifier *)0xdeadfeed;
+}
+
+static inline void cec_notifier_put(struct cec_notifier *n)
+{
+}
+
+static inline void cec_notifier_set_phys_addr(struct cec_notifier *n, u16 pa)
+{
+}
+
+static inline void cec_notifier_set_phys_addr_from_edid(struct cec_notifier *n,
+ const struct edid *edid)
+{
+}
+
+#endif
+
+#endif
diff --git a/include/media/cec.h b/include/media/cec.h
index 96a0aa770d61..307f5dcaf034 100644
--- a/include/media/cec.h
+++ b/include/media/cec.h
@@ -30,6 +30,7 @@
#include <linux/cec-funcs.h>
#include <media/rc-core.h>
#include <media/cec-edid.h>
+#include <media/cec-notifier.h>
/**
* struct cec_devnode - cec device node
@@ -173,6 +174,10 @@ struct cec_adapter {
bool passthrough;
struct cec_log_addrs log_addrs;
+#ifdef CONFIG_MEDIA_CEC_NOTIFIER
+ struct cec_notifier *notifier;
+#endif
+
struct dentry *cec_dir;
struct dentry *status_file;
@@ -213,6 +218,11 @@ void cec_transmit_done(struct cec_adapter *adap, u8 status, u8 arb_lost_cnt,
u8 nack_cnt, u8 low_drive_cnt, u8 error_cnt);
void cec_received_msg(struct cec_adapter *adap, struct cec_msg *msg);
+#ifdef CONFIG_MEDIA_CEC_NOTIFIER
+void cec_register_cec_notifier(struct cec_adapter *adap,
+ struct cec_notifier *notifier);
+#endif
+
#else
static inline int cec_register_adapter(struct cec_adapter *adap,
diff --git a/include/uapi/drm/msm_drm.h b/include/uapi/drm/msm_drm.h
index 7aa6496c7608..cc6d4fb42d9f 100644
--- a/include/uapi/drm/msm_drm.h
+++ b/include/uapi/drm/msm_drm.h
@@ -102,6 +102,13 @@ struct drm_msm_gem_new {
__u32 handle; /* out */
};
+struct drm_msm_gem_svm_new {
+ __u64 hostptr; /* in, must be page-aligned */
+ __u64 size; /* in, must be page-aligned */
+ __u32 flags; /* in, mask of MSM_BO_x */
+ __u32 handle; /* out */
+};
+
#define MSM_INFO_IOVA 0x01
#define MSM_INFO_FLAGS (MSM_INFO_IOVA)
@@ -356,6 +363,8 @@ struct drm_msm_gem_sync {
#define DRM_MSM_GEM_CPU_FINI 0x05
#define DRM_MSM_GEM_SUBMIT 0x06
#define DRM_MSM_WAIT_FENCE 0x07
+/* Gap for upstream DRM_MSM_GEM_MADVISE */
+#define DRM_MSM_GEM_SVM_NEW 0x09
#define DRM_SDE_WB_CONFIG 0x40
#define DRM_MSM_REGISTER_EVENT 0x41
@@ -395,6 +404,9 @@ struct drm_msm_gem_sync {
struct drm_msm_counter_read)
#define DRM_IOCTL_MSM_GEM_SYNC DRM_IOW(DRM_COMMAND_BASE + DRM_MSM_GEM_SYNC,\
struct drm_msm_gem_sync)
+#define DRM_IOCTL_MSM_GEM_SVM_NEW \
+ DRM_IOWR(DRM_COMMAND_BASE + DRM_MSM_GEM_SVM_NEW, \
+ struct drm_msm_gem_svm_new)
#if defined(__cplusplus)
}
diff --git a/kernel/irq/msi.c b/kernel/irq/msi.c
index cd6009006510..41b40f310c28 100644
--- a/kernel/irq/msi.c
+++ b/kernel/irq/msi.c
@@ -268,7 +268,7 @@ int msi_domain_alloc_irqs(struct irq_domain *domain, struct device *dev,
struct msi_domain_ops *ops = info->ops;
msi_alloc_info_t arg;
struct msi_desc *desc;
- int i, ret, virq;
+ int i, ret, virq = 0;
ret = ops->msi_check(domain, info, dev);
if (ret == 0)
diff --git a/kernel/time/hrtimer.c b/kernel/time/hrtimer.c
index 01a49614e942..e7c2392666cb 100644
--- a/kernel/time/hrtimer.c
+++ b/kernel/time/hrtimer.c
@@ -49,7 +49,6 @@
#include <linux/sched/deadline.h>
#include <linux/timer.h>
#include <linux/freezer.h>
-#include <linux/delay.h>
#include <asm/uaccess.h>
@@ -1593,42 +1592,22 @@ static void init_hrtimers_cpu(int cpu)
}
#if defined(CONFIG_HOTPLUG_CPU)
-static void migrate_hrtimer_list(struct hrtimer_cpu_base *old_base,
- struct hrtimer_cpu_base *new_base,
- unsigned int i,
- bool wait,
+static void migrate_hrtimer_list(struct hrtimer_clock_base *old_base,
+ struct hrtimer_clock_base *new_base,
bool remove_pinned)
{
struct hrtimer *timer;
struct timerqueue_node *node;
struct timerqueue_head pinned;
int is_pinned;
- struct hrtimer_clock_base *old_c_base = &old_base->clock_base[i];
- struct hrtimer_clock_base *new_c_base = &new_base->clock_base[i];
+ bool is_hotplug = !cpu_online(old_base->cpu_base->cpu);
timerqueue_init_head(&pinned);
- while ((node = timerqueue_getnext(&old_c_base->active))) {
+ while ((node = timerqueue_getnext(&old_base->active))) {
timer = container_of(node, struct hrtimer, node);
- if (wait) {
- /* Ensure timers are done running before continuing */
- while (hrtimer_callback_running(timer)) {
- raw_spin_unlock(&old_base->lock);
- raw_spin_unlock(&new_base->lock);
- cpu_relax();
- /*
- * cpu_relax may just be a barrier. Grant the
- * run_hrtimer_list code some time to obtain the
- * spinlock.
- */
- udelay(2);
- raw_spin_lock(&new_base->lock);
- raw_spin_lock_nested(&old_base->lock,
- SINGLE_DEPTH_NESTING);
- }
- } else {
+ if (is_hotplug)
BUG_ON(hrtimer_callback_running(timer));
- }
debug_deactivate(timer);
/*
@@ -1636,7 +1615,7 @@ static void migrate_hrtimer_list(struct hrtimer_cpu_base *old_base,
* timer could be seen as !active and just vanish away
* under us on another CPU
*/
- __remove_hrtimer(timer, old_c_base, HRTIMER_STATE_ENQUEUED, 0);
+ __remove_hrtimer(timer, old_base, HRTIMER_STATE_ENQUEUED, 0);
is_pinned = timer->state & HRTIMER_STATE_PINNED;
if (!remove_pinned && is_pinned) {
@@ -1644,7 +1623,7 @@ static void migrate_hrtimer_list(struct hrtimer_cpu_base *old_base,
continue;
}
- timer->base = new_c_base;
+ timer->base = new_base;
/*
* Enqueue the timers on the new cpu. This does not
* reprogram the event device in case the timer
@@ -1653,7 +1632,7 @@ static void migrate_hrtimer_list(struct hrtimer_cpu_base *old_base,
* sort out already expired timers and reprogram the
* event device.
*/
- enqueue_hrtimer(timer, new_c_base);
+ enqueue_hrtimer(timer, new_base);
}
/* Re-queue pinned timers for non-hotplug usecase */
@@ -1661,11 +1640,11 @@ static void migrate_hrtimer_list(struct hrtimer_cpu_base *old_base,
timer = container_of(node, struct hrtimer, node);
timerqueue_del(&pinned, &timer->node);
- enqueue_hrtimer(timer, old_c_base);
+ enqueue_hrtimer(timer, old_base);
}
}
-static void __migrate_hrtimers(int scpu, bool wait, bool remove_pinned)
+static void __migrate_hrtimers(int scpu, bool remove_pinned)
{
struct hrtimer_cpu_base *old_base, *new_base;
unsigned long flags;
@@ -1682,8 +1661,8 @@ static void __migrate_hrtimers(int scpu, bool wait, bool remove_pinned)
raw_spin_lock_nested(&old_base->lock, SINGLE_DEPTH_NESTING);
for (i = 0; i < HRTIMER_MAX_CLOCK_BASES; i++) {
- migrate_hrtimer_list(old_base, new_base, i, wait,
- remove_pinned);
+ migrate_hrtimer_list(&old_base->clock_base[i],
+ &new_base->clock_base[i], remove_pinned);
}
raw_spin_unlock(&old_base->lock);
@@ -1699,12 +1678,12 @@ static void migrate_hrtimers(int scpu)
BUG_ON(cpu_online(scpu));
tick_cancel_sched_timer(scpu);
- __migrate_hrtimers(scpu, false, true);
+ __migrate_hrtimers(scpu, true);
}
void hrtimer_quiesce_cpu(void *cpup)
{
- __migrate_hrtimers(*(int *)cpup, true, false);
+ __migrate_hrtimers(*(int *)cpup, false);
}
#endif /* CONFIG_HOTPLUG_CPU */
diff --git a/kernel/time/posix-cpu-timers.c b/kernel/time/posix-cpu-timers.c
index 80016b329d94..051544aec37c 100644
--- a/kernel/time/posix-cpu-timers.c
+++ b/kernel/time/posix-cpu-timers.c
@@ -1250,7 +1250,7 @@ void run_posix_cpu_timers(struct task_struct *tsk)
void set_process_cpu_timer(struct task_struct *tsk, unsigned int clock_idx,
cputime_t *newval, cputime_t *oldval)
{
- unsigned long long now;
+ unsigned long long now = 0;
WARN_ON_ONCE(clock_idx == CPUCLOCK_SCHED);
cpu_timer_sample_group(clock_idx, tsk, &now);
diff --git a/net/netfilter/xt_HARDIDLETIMER.c b/net/netfilter/xt_HARDIDLETIMER.c
index 06322e4de632..ecb4a7fb6bf8 100644
--- a/net/netfilter/xt_HARDIDLETIMER.c
+++ b/net/netfilter/xt_HARDIDLETIMER.c
@@ -4,7 +4,7 @@
* Netfilter module to trigger a timer when packet matches.
* After timer expires a kevent will be sent.
*
- * Copyright (c) 2014-2015, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2014-2015, 2017 The Linux Foundation. All rights reserved.
*
* Copyright (C) 2004, 2010 Nokia Corporation
*
@@ -187,6 +187,8 @@ static int hardidletimer_tg_create(struct hardidletimer_tg_info *info)
pr_debug("couldn't add file to sysfs");
goto out_free_attr;
}
+ /* notify userspace */
+ kobject_uevent(hardidletimer_tg_kobj, KOBJ_ADD);
list_add(&info->timer->entry, &hardidletimer_tg_list);
diff --git a/net/netfilter/xt_IDLETIMER.c b/net/netfilter/xt_IDLETIMER.c
index 80b32de1d99c..f9eb8641dc3a 100644
--- a/net/netfilter/xt_IDLETIMER.c
+++ b/net/netfilter/xt_IDLETIMER.c
@@ -307,6 +307,8 @@ static int idletimer_tg_create(struct idletimer_tg_info *info)
pr_debug("couldn't add file to sysfs");
goto out_free_attr;
}
+ /* notify userspace */
+ kobject_uevent(idletimer_tg_kobj, KOBJ_ADD);
list_add(&info->timer->entry, &idletimer_tg_list);
diff --git a/net/unix/af_unix.c b/net/unix/af_unix.c
index b2e934ff2448..1f5d18d80fba 100644
--- a/net/unix/af_unix.c
+++ b/net/unix/af_unix.c
@@ -991,7 +991,7 @@ static int unix_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len)
struct sockaddr_un *sunaddr = (struct sockaddr_un *)uaddr;
char *sun_path = sunaddr->sun_path;
int err;
- unsigned int hash;
+ unsigned int hash = 0;
struct unix_address *addr;
struct hlist_head *list;
struct path path = { NULL, NULL };