Merge "usb: Add support to handle USB SMMU S1 address"
diff --git a/Documentation/devicetree/bindings/display/msm/sde.txt b/Documentation/devicetree/bindings/display/msm/sde.txt
index c8cffb5..b570448 100644
--- a/Documentation/devicetree/bindings/display/msm/sde.txt
+++ b/Documentation/devicetree/bindings/display/msm/sde.txt
@@ -135,6 +135,18 @@
power collapse feature available or not.
- qcom,sde-has-mixer-gc: Boolean property to indicate if mixer has gamma correction
feature available or not.
+- qcom,sde-has-dest-scaler: Boolean property to indicate if destination scaler
+ feature is available or not.
+- qcom,sde-max-dest-scaler-input-linewidth: A u32 value indicates the
+ maximum input line width to destination scaler.
+- qcom,sde-max-dest-scaler-output-linewidth: A u32 value indicates the
+ maximum output line width of destination scaler.
+- qcom,sde-dest-scaler-top-off: A u32 value provides the
+ offset from mdp base to destination scaler block.
+- qcom,sde-dest-scaler-top-size: A u32 value indicates the address range for ds top
+- qcom,sde-dest-scaler-off: Array of u32 offsets indicate the qseed3 scaler blocks
+ offset from destination scaler top offset.
+- qcom,sde-dest-scaler-size: A u32 value indicates the address range for each scaler block
- qcom,sde-sspp-clk-ctrl: Array of offsets describing clk control
offsets for dynamic clock gating. 1st value
in the array represents offset of the control
@@ -444,6 +456,8 @@
qcom,sde-dspp-off = <0x00055000 0x00057000>;
qcom,sde-dspp-ad-off = <0x24000 0x22800>;
qcom,sde-dspp-ad-version = <0x00030000>;
+ qcom,sde-dest-scaler-top-off = <0x00061000>;
+ qcom,sde-dest-scaler-off = <0x800 0x1000>;
qcom,sde-wb-off = <0x00066000>;
qcom,sde-wb-xin-id = <6>;
qcom,sde-intf-off = <0x0006b000 0x0006b800
@@ -505,6 +519,8 @@
qcom,sde-cdm-size = <0x100>;
qcom,sde-pp-size = <0x100>;
qcom,sde-wb-size = <0x100>;
+ qcom,sde-dest-scaler-top-size = <0xc>;
+ qcom,sde-dest-scaler-size = <0x800>;
qcom,sde-len = <0x100>;
qcom,sde-wb-linewidth = <2560>;
qcom,sde-sspp-scale-size = <0x100>;
@@ -514,6 +530,9 @@
qcom,sde-highest-bank-bit = <15>;
qcom,sde-has-mixer-gc;
qcom,sde-has-idle-pc;
+ qcom,sde-has-dest-scaler;
+ qcom,sde-max-dest-scaler-input-linewidth = <2048>;
+ qcom,sde-max-dest-scaler-output-linewidth = <2560>;
qcom,sde-sspp-max-rects = <1 1 1 1
1 1 1 1
1 1
diff --git a/Documentation/devicetree/bindings/iommu/arm,smmu.txt b/Documentation/devicetree/bindings/iommu/arm,smmu.txt
index 8fcdd82..d2e635a 100644
--- a/Documentation/devicetree/bindings/iommu/arm,smmu.txt
+++ b/Documentation/devicetree/bindings/iommu/arm,smmu.txt
@@ -100,6 +100,10 @@
Some hardware may not have full support for atos debugging
in tandem with other features like power collapse.
+- qcom,mmu500-errata-1:
+ An array of <sid mask>.
+ Indicates the SIDs for which the workaround is required.
+
- qcom,deferred-regulator-disable-delay : The time delay for deferred regulator
disable in ms. In case of unmap call, regulator is
enabled/disabled. This may introduce additional delay. For
diff --git a/Documentation/devicetree/bindings/media/video/msm-cam-eeprom.txt b/Documentation/devicetree/bindings/media/video/msm-cam-eeprom.txt
index 933ad85..83a58df 100644
--- a/Documentation/devicetree/bindings/media/video/msm-cam-eeprom.txt
+++ b/Documentation/devicetree/bindings/media/video/msm-cam-eeprom.txt
@@ -278,6 +278,46 @@
Value type: <u32>
Definition: should specify the power on sequence delay time in ms.
+- spiop-read
+ Usage: required
+ Value type: <u32>
+ Definition: this array provides SPI read operation related data.
+
+- spiop-readseq
+ Usage: required
+ Value type: <u32>
+ Definition: this array provides SPI read sequence operation realted data.
+
+- spiop-queryid
+ Usage: required
+ Value type: <u32>
+ Definition: this array provides SPI query eeprom id operation related data.
+
+- spiop-pprog:
+ Usage: required
+ Value type: <u32>
+ Definition: this array provides SPI page program operation related data.
+
+- spiop-wenable
+ Usage: required
+ Value type: <u32>
+ Definition: this array provides SPI write enable operation related data.
+
+- spiop-readst
+ Usage: required
+ Value type: <u32>
+ Definition: this array provides SPI read destination operation related data.
+
+- spiop-erase
+ Usage: required
+ Value type: <u32>
+ Definition: this array provides SPI erase operation related data.
+
+- eeprom-idx
+ Usage: required
+ Value type: <u32>
+ Definition: this array provides eeprom id realted data.
+
- xxxx-supply
Usage: required
Value type: <phandle>
@@ -385,6 +425,10 @@
cell-index = <0>;
reg = <0x0>;
qcom,eeprom-name = "msm_eeprom";
+ eeprom-id0 = <0xF8 0x15>;
+ eeprom-id1 = <0xEF 0x15>;
+ eeprom-id2 = <0xC2 0x36>;
+ eeprom-id3 = <0xC8 0x15>;
compatible = "qcom,eeprom";
qcom,slave-addr = <0x60>;
qcom,num-blocks = <2>;
@@ -400,6 +444,13 @@
qcom,cmm-data-compressed;
qcom,cmm-data-offset = <0>;
qcom,cmm-data-size = <0>;
+ spiop-read = <0x03 3 0 0 0>;
+ spiop-readseq = <0x03 3 0 0 0>;
+ spiop-queryid = <0x90 3 0 0 0>;
+ spiop-pprog = <0x02 3 0 3 100>;
+ spiop-wenable = <0x06 0 0 0 0>;
+ spiop-readst = <0x05 0 0 0 0>;
+ spiop-erase = <0x20 3 0 10 100>;
qcom,cam-power-seq-type = "sensor_vreg",
"sensor_vreg", "sensor_clk",
"sensor_gpio", "sensor_gpio";
diff --git a/Documentation/devicetree/bindings/media/video/msm-cam-smmu.txt b/Documentation/devicetree/bindings/media/video/msm-cam-smmu.txt
index 72e2ab4..728c5f9 100644
--- a/Documentation/devicetree/bindings/media/video/msm-cam-smmu.txt
+++ b/Documentation/devicetree/bindings/media/video/msm-cam-smmu.txt
@@ -56,6 +56,11 @@
Value type: <string>
Definition: Should specify a string label to identify the context bank.
+- qcom,secure-cb
+ Usage: optional
+ Value type: boolean
+ Definition: Specifies if the context bank is a secure context bank.
+
=============================================
Third Level Node - CAM SMMU memory map device
=============================================
diff --git a/Documentation/devicetree/bindings/pinctrl/qcom,msm8953-pinctrl.txt b/Documentation/devicetree/bindings/pinctrl/qcom,msm8953-pinctrl.txt
new file mode 100644
index 0000000..d4bf1ce
--- /dev/null
+++ b/Documentation/devicetree/bindings/pinctrl/qcom,msm8953-pinctrl.txt
@@ -0,0 +1,210 @@
+Qualcomm MSM8953 TLMM block
+
+This binding describes the Top Level Mode Multiplexer block found in the
+MSM8953 platform.
+
+- compatible:
+ Usage: required
+ Value type: <string>
+ Definition: must be "qcom,msm8953-pinctrl"
+
+- reg:
+ Usage: required
+ Value type: <prop-encoded-array>
+ Definition: the base address and size of the TLMM register space.
+
+- interrupts:
+ Usage: required
+ Value type: <prop-encoded-array>
+ Definition: should specify the TLMM summary IRQ.
+
+- interrupt-controller:
+ Usage: required
+ Value type: <none>
+ Definition: identifies this node as an interrupt controller
+
+- #interrupt-cells:
+ Usage: required
+ Value type: <u32>
+ Definition: must be 2. Specifying the pin number and flags, as defined
+ in <dt-bindings/interrupt-controller/irq.h>
+
+- gpio-controller:
+ Usage: required
+ Value type: <none>
+ Definition: identifies this node as a gpio controller
+
+- #gpio-cells:
+ Usage: required
+ Value type: <u32>
+ Definition: must be 2. Specifying the pin number and flags, as defined
+ in <dt-bindings/gpio/gpio.h>
+
+Please refer to ../gpio/gpio.txt and ../interrupt-controller/interrupts.txt for
+a general description of GPIO and interrupt bindings.
+
+Please refer to pinctrl-bindings.txt in this directory for details of the
+common pinctrl bindings used by client devices, including the meaning of the
+phrase "pin configuration node".
+
+The pin configuration nodes act as a container for an arbitrary number of
+subnodes. Each of these subnodes represents some desired configuration for a
+pin, a group, or a list of pins or groups. This configuration can include the
+mux function to select on those pin(s)/group(s), and various pin configuration
+parameters, such as pull-up, drive strength, etc.
+
+
+PIN CONFIGURATION NODES:
+
+The name of each subnode is not important; all subnodes should be enumerated
+and processed purely based on their content.
+
+Each subnode only affects those parameters that are explicitly listed. In
+other words, a subnode that lists a mux function but no pin configuration
+parameters implies no information about any pin configuration parameters.
+Similarly, a pin subnode that describes a pullup parameter implies no
+information about e.g. the mux function.
+
+
+The following generic properties as defined in pinctrl-bindings.txt are valid
+to specify in a pin configuration subnode:
+
+- pins:
+ Usage: required
+ Value type: <string-array>
+ Definition: List of gpio pins affected by the properties specified in
+ this subnode.
+ Valid pins are:
+ gpio0-gpio141,
+ sdc1_clk,
+ sdc1_cmd,
+ sdc1_data,
+ sdc1_rclk,
+ sdc2_clk,
+ sdc2_cmd,
+ sdc2_data,
+ qdsd_cmd,
+ qdsd_data0,
+ qdsd_data1,
+ qdsd_data2,
+ qdsd_data3
+
+- function:
+ Usage: required
+ Value type: <string>
+ Definition: Specify the alternative function to be configured for the
+ specified pins. Functions are only valid for gpio pins.
+ Valid values are:
+ gpio, blsp_spi1, smb_int, adsp_ext, prng_rosc, blsp_i2c1,
+ qdss_cti_trig_out_b0, qdss_cti_trig_out_a1, blsp_spi2, blsp_uart2,
+ ldo_update, dac_calib0, ldo_en, blsp_i2c2, gcc_gp1_clk_b,
+ atest_gpsadc_dtest0_native, blsp_spi3, qdss_tracedata_b,
+ pwr_modem_enabled_b, blsp_i2c3, gcc_gp2_clk_b, gcc_gp3_clk_b, hall_int,
+ blsp_spi4, blsp_uart4, pwr_nav_enabled_b, dac_calib1, cap_int,
+ pwr_crypto_enabled_b, dac_calib2, blsp_i2c4, nfc_disable, blsp_spi5,
+ blsp_uart5, qdss_traceclk_a, atest_bbrx1, nfc_irq, m_voc,
+ qdss_cti_trig_in_a0, atest_bbrx0, blsp_i2c5, qdss_tracectl_a,
+ atest_gpsadc_dtest1_native, qdss_tracedata_a, blsp_spi6, blsp_uart6,
+ qdss_tracectl_b, dac_calib15, qdss_cti_trig_in_b0, dac_calib16, blsp_i2c6,
+ qdss_traceclk_b, atest_wlan0, atest_wlan1, mdp_vsync, pri_mi2s_mclk_a,
+ sec_mi2s_mclk_a, qdss_cti_trig_out_b1, cam_mclk, dac_calib3, cci_i2c,
+ pwr_modem_enabled_a, dac_calib4, dac_calib19, flash_strobe, cci_timer0,
+ cci_timer1, cam_irq, cci_timer2, blsp1_spi, pwr_nav_enabled_a, ois_sync,
+ cci_timer3, cci_timer4, blsp3_spi, qdss_cti_trig_out_a0, dac_calib7,
+ accel_int, gcc_gp1_clk_a, dac_calib8, alsp_int, gcc_gp2_clk_a, dac_calib9,
+ mag_int, gcc_gp3_clk_a, pwr_crypto_enabled_a, cci_async, cam1_standby,
+ dac_calib5, cam1_rst, dac_calib6, dac_calib10, gyro_int, dac_calib11,
+ pressure_int, dac_calib12, blsp6_spi, dac_calib13, fp_int,
+ qdss_cti_trig_in_b1, dac_calib14, uim_batt, cam0_ldo, sd_write, uim1_data,
+ uim1_clk, uim1_reset, uim1_present, uim2_data, uim2_clk, uim2_reset,
+ uim2_present, ts_xvdd, mipi_dsi0, nfc_dwl, us_euro, atest_char3, dbg_out,
+ bimc_dte0, ts_resout, ts_sample, sec_mi2s_mclk_b, pri_mi2s, codec_reset,
+ cdc_pdm0, atest_char1, ebi_cdc, dac_calib17, us_emitter, atest_char0,
+ pri_mi2s_mclk_b, lpass_slimbus, lpass_slimbus0, lpass_slimbus1, codec_int1,
+ codec_int2, wcss_bt, atest_char2, ebi_ch0, wcss_wlan2, wcss_wlan1,
+ wcss_wlan0, wcss_wlan, wcss_fm, ext_lpass, mss_lte, key_volp, pbs0,
+ cri_trng0, key_snapshot, pbs1, cri_trng1, key_focus, pbs2, cri_trng,
+ gcc_tlmm, key_home, pwr_down, dmic0_clk, blsp7_spi, hdmi_int, dmic0_data,
+ qdss_cti_trig_in_a1, pri_mi2s_ws, wsa_io, wsa_en, blsp_spi8, wsa_irq,
+ blsp_i2c8, gcc_plltest, nav_pps_in_a, pa_indicator, nav_pps_in_b, nav_pps,
+ modem_tsync, nav_tsync, ssbi_wtr1, gsm1_tx, dac_calib18, gsm0_tx,
+ atest_char, atest_tsens, bimc_dte1, dac_calib20, cam2_rst, ddr_bist,
+ dac_calib21, cam2_standby, dac_calib22, cam3_rst, dac_calib23,
+ cam3_standby, dac_calib24, sdcard_det, dac_calib25, cam1_ldo, sec_mi2s,
+ blsp_spi7, blsp_i2c7, ss_switch, tsens_max
+
+- bias-disable:
+ Usage: optional
+ Value type: <none>
+ Definition: The specified pins should be configued as no pull.
+
+- bias-pull-down:
+ Usage: optional
+ Value type: <none>
+ Definition: The specified pins should be configued as pull down.
+
+- bias-pull-up:
+ Usage: optional
+ Value type: <none>
+ Definition: The specified pins should be configued as pull up.
+
+- output-high:
+ Usage: optional
+ Value type: <none>
+ Definition: The specified pins are configured in output mode, driven
+ high.
+ Not valid for sdc pins.
+
+- output-low:
+ Usage: optional
+ Value type: <none>
+ Definition: The specified pins are configured in output mode, driven
+ low.
+ Not valid for sdc pins.
+
+- drive-strength:
+ Usage: optional
+ Value type: <u32>
+ Definition: Selects the drive strength for the specified pins, in mA.
+ Valid values are: 2, 4, 6, 8, 10, 12, 14 and 16
+
+Example:
+
+ tlmm: pinctrl@1000000 {
+ compatible = "qcom,msm8953-pinctrl";
+ reg = <0x1000000 0x300000>;
+ interrupts = <0 208 0>;
+ gpio-controller;
+ #gpio-cells = <2>;
+ interrupt-controller;
+ #interrupt-cells = <2>;
+
+ pmx-uartconsole {
+ uart_console_active: uart_console_active {
+ mux {
+ pins = "gpio4", "gpio5";
+ function = "blsp_uart2";
+ };
+
+ config {
+ pins = "gpio4", "gpio5";
+ drive-strength = <2>;
+ bias-disable;
+ };
+ };
+
+ uart_console_sleep: uart_console_sleep {
+ mux {
+ pins = "gpio4", "gpio5";
+ function = "blsp_uart2";
+ };
+
+ config {
+ pins = "gpio4", "gpio5";
+ drive-strength = <2>;
+ bias-pull-down;
+ };
+ };
+
+ };
+ };
diff --git a/Documentation/devicetree/bindings/power/supply/qcom/qpnp-fg-gen3.txt b/Documentation/devicetree/bindings/power/supply/qcom/qpnp-fg-gen3.txt
index a3fd951..d205b0b 100644
--- a/Documentation/devicetree/bindings/power/supply/qcom/qpnp-fg-gen3.txt
+++ b/Documentation/devicetree/bindings/power/supply/qcom/qpnp-fg-gen3.txt
@@ -309,6 +309,13 @@
is specified to make it fully functional. Value has no
unit. Allowed range is 0 to 62200 in micro units.
+- qcom,ki-coeff-full-dischg
+ Usage: optional
+ Value type: <u32>
+ Definition: Ki coefficient full SOC value that will be applied during
+ discharging. If not specified, a value of 0 will be set.
+ Allowed range is from 245 to 62256.
+
- qcom,fg-rconn-mohms
Usage: optional
Value type: <u32>
diff --git a/Documentation/devicetree/bindings/sound/qcom-audio-dev.txt b/Documentation/devicetree/bindings/sound/qcom-audio-dev.txt
index 4d05e50..57a227e 100644
--- a/Documentation/devicetree/bindings/sound/qcom-audio-dev.txt
+++ b/Documentation/devicetree/bindings/sound/qcom-audio-dev.txt
@@ -2459,6 +2459,10 @@
6-pole-jack : Jack on the hardware is 6-pole.
- clock-names : clock name defined for external clock.
- clocks : external clock defined for codec clock.
+- qcom,msm-mbhc-hs-mic-max-threshold-mv : headset detection threshold. When micbias is
+ not set to 2.7v, need scale in driver.
+- qcom,msm-mbhc-hs-mic-min-threshold-mv : headhpone detection threshold. When micbias is
+ not set to 2.7v, need scale in driver.
- qcom,hph-en1-gpio : GPIO to enable HiFi amplifiers.
- qcom,hph-en0-gpio : GPIO to enable HiFi audio route to headset.
- qcom,wsa-max-devs : Maximum number of WSA881x devices present in the target
@@ -2516,6 +2520,8 @@
qcom,msm-mbhc-hphl-swh = <0>;
qcom,msm-mbhc-gnd-swh = <0>;
+ qcom,msm-mbhc-hs-mic-max-threshold-mv = <1700>;
+ qcom,msm-mbhc-hs-mic-min-threshold-mv = <50>;
qcom,hph-en0-gpio = <&tavil_hph_en0>;
qcom,hph-en1-gpio = <&tavil_hph_en1>;
qcom,tavil-mclk-clk-freq = <9600000>;
diff --git a/Makefile b/Makefile
index a8d289a..665104d 100644
--- a/Makefile
+++ b/Makefile
@@ -1,6 +1,6 @@
VERSION = 4
PATCHLEVEL = 9
-SUBLEVEL = 48
+SUBLEVEL = 51
EXTRAVERSION =
NAME = Roaring Lionus
diff --git a/arch/arm/mm/fault.c b/arch/arm/mm/fault.c
index aec74bf..a9ef54d 100644
--- a/arch/arm/mm/fault.c
+++ b/arch/arm/mm/fault.c
@@ -314,8 +314,11 @@
* signal first. We do not need to release the mmap_sem because
* it would already be released in __lock_page_or_retry in
* mm/filemap.c. */
- if ((fault & VM_FAULT_RETRY) && fatal_signal_pending(current))
+ if ((fault & VM_FAULT_RETRY) && fatal_signal_pending(current)) {
+ if (!user_mode(regs))
+ goto no_context;
return 0;
+ }
/*
* Major/minor page fault accounting is only done on the
diff --git a/arch/arm64/Kconfig.platforms b/arch/arm64/Kconfig.platforms
index f96fba6..e1454fb 100644
--- a/arch/arm64/Kconfig.platforms
+++ b/arch/arm64/Kconfig.platforms
@@ -139,6 +139,15 @@
This enables support for the SDM670 chipset. If you do not
wish to build a kernel that runs on this chipset, say 'N' here.
+config ARCH_MSM8953
+ bool "Enable Support for Qualcomm Technologies Inc. MSM8953"
+ depends on ARCH_QCOM
+ select COMMON_CLK_QCOM
+ select QCOM_GDSC
+ help
+ This enables support for the MSM8953 chipset. If you do not
+ wish to build a kernel that runs on this chipset, say 'N' here.
+
config ARCH_ROCKCHIP
bool "Rockchip Platforms"
select ARCH_HAS_RESET_CONTROLLER
diff --git a/arch/arm64/boot/dts/marvell/armada-37xx.dtsi b/arch/arm64/boot/dts/marvell/armada-37xx.dtsi
index 49a5d8c..68e6f88 100644
--- a/arch/arm64/boot/dts/marvell/armada-37xx.dtsi
+++ b/arch/arm64/boot/dts/marvell/armada-37xx.dtsi
@@ -170,6 +170,7 @@
interrupt-controller;
reg = <0x1d00000 0x10000>, /* GICD */
<0x1d40000 0x40000>; /* GICR */
+ interrupts = <GIC_PPI 9 IRQ_TYPE_LEVEL_HIGH>;
};
};
diff --git a/arch/arm64/boot/dts/qcom/dsi-panel-nt35597-truly-dsc-wqxga-cmd.dtsi b/arch/arm64/boot/dts/qcom/dsi-panel-nt35597-truly-dsc-wqxga-cmd.dtsi
index 0ca1175..0e60a0c 100644
--- a/arch/arm64/boot/dts/qcom/dsi-panel-nt35597-truly-dsc-wqxga-cmd.dtsi
+++ b/arch/arm64/boot/dts/qcom/dsi-panel-nt35597-truly-dsc-wqxga-cmd.dtsi
@@ -88,7 +88,7 @@
15 01 00 00 00 00 02 5d 81
15 01 00 00 00 00 02 5e 00
15 01 00 00 00 00 02 5f 01
- 15 01 00 00 00 00 02 72 31
+ 15 01 00 00 00 00 02 72 11
15 01 00 00 00 00 02 68 03
/* CMD2_P4 */
15 01 00 00 00 00 02 ff 24
diff --git a/arch/arm64/boot/dts/qcom/dsi-panel-nt35597-truly-dsc-wqxga-video.dtsi b/arch/arm64/boot/dts/qcom/dsi-panel-nt35597-truly-dsc-wqxga-video.dtsi
index ac8a956..2c54504 100644
--- a/arch/arm64/boot/dts/qcom/dsi-panel-nt35597-truly-dsc-wqxga-video.dtsi
+++ b/arch/arm64/boot/dts/qcom/dsi-panel-nt35597-truly-dsc-wqxga-video.dtsi
@@ -74,7 +74,7 @@
15 01 00 00 00 00 02 5d 81
15 01 00 00 00 00 02 5e 00
15 01 00 00 00 00 02 5f 01
- 15 01 00 00 00 00 02 72 31
+ 15 01 00 00 00 00 02 72 11
15 01 00 00 00 00 02 68 03
/* CMD2_P4 */
15 01 00 00 00 00 02 ff 24
diff --git a/arch/arm64/boot/dts/qcom/dsi-panel-nt35597-truly-dualmipi-wqxga-cmd.dtsi b/arch/arm64/boot/dts/qcom/dsi-panel-nt35597-truly-dualmipi-wqxga-cmd.dtsi
index 87cabae..5b5fbb8 100644
--- a/arch/arm64/boot/dts/qcom/dsi-panel-nt35597-truly-dualmipi-wqxga-cmd.dtsi
+++ b/arch/arm64/boot/dts/qcom/dsi-panel-nt35597-truly-dualmipi-wqxga-cmd.dtsi
@@ -89,7 +89,7 @@
15 01 00 00 00 00 02 5D 81
15 01 00 00 00 00 02 5E 00
15 01 00 00 00 00 02 5F 01
- 15 01 00 00 00 00 02 72 31
+ 15 01 00 00 00 00 02 72 11
15 01 00 00 00 00 02 68 03
/* CMD2_P4 */
15 01 00 00 00 00 02 ff 24
diff --git a/arch/arm64/boot/dts/qcom/dsi-panel-nt35597-truly-dualmipi-wqxga-video.dtsi b/arch/arm64/boot/dts/qcom/dsi-panel-nt35597-truly-dualmipi-wqxga-video.dtsi
index c83fd87..95e0e5a 100644
--- a/arch/arm64/boot/dts/qcom/dsi-panel-nt35597-truly-dualmipi-wqxga-video.dtsi
+++ b/arch/arm64/boot/dts/qcom/dsi-panel-nt35597-truly-dualmipi-wqxga-video.dtsi
@@ -75,7 +75,7 @@
15 01 00 00 00 00 02 5D 81
15 01 00 00 00 00 02 5E 00
15 01 00 00 00 00 02 5F 01
- 15 01 00 00 00 00 02 72 31
+ 15 01 00 00 00 00 02 72 11
15 01 00 00 00 00 02 68 03
/* CMD2_P4 */
15 01 00 00 00 00 02 FF 24
diff --git a/arch/arm64/boot/dts/qcom/msm-arm-smmu-sdm845.dtsi b/arch/arm64/boot/dts/qcom/msm-arm-smmu-sdm845.dtsi
index 2156a5d..a48fba0 100644
--- a/arch/arm64/boot/dts/qcom/msm-arm-smmu-sdm845.dtsi
+++ b/arch/arm64/boot/dts/qcom/msm-arm-smmu-sdm845.dtsi
@@ -355,4 +355,7 @@
<0x1400 0x3ff 0x3>,
<0x1800 0x3ff 0x3>,
<0x1c00 0x3ff 0x3>;
+
+ qcom,mmu500-errata-1 = <0x800 0x3ff>,
+ <0xc00 0x3ff>;
};
diff --git a/arch/arm64/boot/dts/qcom/msm-audio-lpass.dtsi b/arch/arm64/boot/dts/qcom/msm-audio-lpass.dtsi
index 0d2f9e8..2fd1bc4 100644
--- a/arch/arm64/boot/dts/qcom/msm-audio-lpass.dtsi
+++ b/arch/arm64/boot/dts/qcom/msm-audio-lpass.dtsi
@@ -353,6 +353,20 @@
qcom,msm-cpudai-afe-clk-ver = <2>;
};
+ dai_quin_auxpcm: qcom,msm-quin-auxpcm {
+ compatible = "qcom,msm-auxpcm-dev";
+ qcom,msm-cpudai-auxpcm-mode = <0>, <0>;
+ qcom,msm-cpudai-auxpcm-sync = <1>, <1>;
+ qcom,msm-cpudai-auxpcm-frame = <5>, <4>;
+ qcom,msm-cpudai-auxpcm-quant = <2>, <2>;
+ qcom,msm-cpudai-auxpcm-num-slots = <1>, <1>;
+ qcom,msm-cpudai-auxpcm-slot-mapping = <1>, <1>;
+ qcom,msm-cpudai-auxpcm-data = <0>, <0>;
+ qcom,msm-cpudai-auxpcm-pcm-clk-rate = <2048000>, <2048000>;
+ qcom,msm-auxpcm-interface = "quinary";
+ qcom,msm-cpudai-afe-clk-ver = <2>;
+ };
+
hdmi_dba: qcom,msm-hdmi-dba-codec-rx {
compatible = "qcom,msm-hdmi-dba-codec-rx";
qcom,dba-bridge-chip = "adv7533";
@@ -522,4 +536,42 @@
qcom,msm-cpudai-tdm-data-align = <0>;
};
};
+
+ qcom,msm-dai-tdm-quin-rx {
+ compatible = "qcom,msm-dai-tdm";
+ qcom,msm-cpudai-tdm-group-id = <37184>;
+ qcom,msm-cpudai-tdm-group-num-ports = <1>;
+ qcom,msm-cpudai-tdm-group-port-id = <36928>;
+ qcom,msm-cpudai-tdm-clk-rate = <1536000>;
+ qcom,msm-cpudai-tdm-clk-internal = <1>;
+ qcom,msm-cpudai-tdm-sync-mode = <1>;
+ qcom,msm-cpudai-tdm-sync-src = <1>;
+ qcom,msm-cpudai-tdm-data-out = <0>;
+ qcom,msm-cpudai-tdm-invert-sync = <1>;
+ qcom,msm-cpudai-tdm-data-delay = <1>;
+ dai_quin_tdm_rx_0: qcom,msm-dai-q6-tdm-quin-rx-0 {
+ compatible = "qcom,msm-dai-q6-tdm";
+ qcom,msm-cpudai-tdm-dev-id = <36928>;
+ qcom,msm-cpudai-tdm-data-align = <0>;
+ };
+ };
+
+ qcom,msm-dai-tdm-quin-tx {
+ compatible = "qcom,msm-dai-tdm";
+ qcom,msm-cpudai-tdm-group-id = <37185>;
+ qcom,msm-cpudai-tdm-group-num-ports = <1>;
+ qcom,msm-cpudai-tdm-group-port-id = <36929>;
+ qcom,msm-cpudai-tdm-clk-rate = <1536000>;
+ qcom,msm-cpudai-tdm-clk-internal = <1>;
+ qcom,msm-cpudai-tdm-sync-mode = <1>;
+ qcom,msm-cpudai-tdm-sync-src = <1>;
+ qcom,msm-cpudai-tdm-data-out = <0>;
+ qcom,msm-cpudai-tdm-invert-sync = <1>;
+ qcom,msm-cpudai-tdm-data-delay = <1>;
+ dai_quin_tdm_tx_0: qcom,msm-dai-q6-tdm-quin-tx-0 {
+ compatible = "qcom,msm-dai-q6-tdm";
+ qcom,msm-cpudai-tdm-dev-id = <36929>;
+ qcom,msm-cpudai-tdm-data-align = <0>;
+ };
+ };
};
diff --git a/arch/arm64/boot/dts/qcom/pm8998.dtsi b/arch/arm64/boot/dts/qcom/pm8998.dtsi
index 450295e..013ac48 100644
--- a/arch/arm64/boot/dts/qcom/pm8998.dtsi
+++ b/arch/arm64/boot/dts/qcom/pm8998.dtsi
@@ -192,6 +192,33 @@
qcom,fast-avg-setup = <0>;
#thermal-sensor-cells = <1>;
};
+
+ pm8998_div_clk1: qcom,clkdiv@5b00 {
+ compatible = "qcom,qpnp-clkdiv";
+ reg = <0x5b00 0x100>;
+ #clock-cells = <1>;
+ qcom,cxo-freq = <19200000>;
+ qcom,clkdiv-id = <1>;
+ qcom,clkdiv-init-freq = <19200000>;
+ };
+
+ pm8998_div_clk2: qcom,clkdiv@5c00 {
+ compatible = "qcom,qpnp-clkdiv";
+ reg = <0x5c00 0x100>;
+ #clock-cells = <1>;
+ qcom,cxo-freq = <19200000>;
+ qcom,clkdiv-id = <2>;
+ qcom,clkdiv-init-freq = <19200000>;
+ };
+
+ pm8998_div_clk3: qcom,clkdiv@5d00 {
+ compatible = "qcom,qpnp-clkdiv";
+ reg = <0x5d00 0x100>;
+ #clock-cells = <1>;
+ qcom,cxo-freq = <19200000>;
+ qcom,clkdiv-id = <3>;
+ qcom,clkdiv-init-freq = <19200000>;
+ };
};
qcom,pm8998@1 {
diff --git a/arch/arm64/boot/dts/qcom/sdm670-audio-overlay.dtsi b/arch/arm64/boot/dts/qcom/sdm670-audio-overlay.dtsi
new file mode 100644
index 0000000..dfb8142
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/sdm670-audio-overlay.dtsi
@@ -0,0 +1,362 @@
+/*
+ * Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+#include "sdm670-wcd.dtsi"
+#include "sdm670-wsa881x.dtsi"
+#include <dt-bindings/clock/qcom,audio-ext-clk.h>
+
+&tavil_snd {
+ qcom,msm-mi2s-master = <1>, <1>, <1>, <1>, <1>;
+ qcom,audio-routing =
+ "AIF4 VI", "MCLK",
+ "RX_BIAS", "MCLK",
+ "MADINPUT", "MCLK",
+ "hifi amp", "LINEOUT1",
+ "hifi amp", "LINEOUT2",
+ "AMIC2", "MIC BIAS2",
+ "MIC BIAS2", "Headset Mic",
+ "AMIC3", "MIC BIAS2",
+ "MIC BIAS2", "ANCRight Headset Mic",
+ "AMIC4", "MIC BIAS2",
+ "MIC BIAS2", "ANCLeft Headset Mic",
+ "AMIC5", "MIC BIAS3",
+ "MIC BIAS3", "Handset Mic",
+ "DMIC0", "MIC BIAS1",
+ "MIC BIAS1", "Digital Mic0",
+ "DMIC1", "MIC BIAS1",
+ "MIC BIAS1", "Digital Mic1",
+ "DMIC2", "MIC BIAS3",
+ "MIC BIAS3", "Digital Mic2",
+ "DMIC3", "MIC BIAS3",
+ "MIC BIAS3", "Digital Mic3",
+ "DMIC4", "MIC BIAS4",
+ "MIC BIAS4", "Digital Mic4",
+ "DMIC5", "MIC BIAS4",
+ "MIC BIAS4", "Digital Mic5",
+ "SpkrLeft IN", "SPK1 OUT",
+ "SpkrRight IN", "SPK2 OUT";
+
+ qcom,msm-mbhc-hphl-swh = <1>;
+ qcom,msm-mbhc-gnd-swh = <1>;
+ qcom,hph-en0-gpio = <&tavil_hph_en0>;
+ qcom,hph-en1-gpio = <&tavil_hph_en1>;
+ qcom,msm-mclk-freq = <9600000>;
+ asoc-codec = <&stub_codec>;
+ asoc-codec-names = "msm-stub-codec.1";
+ qcom,wsa-max-devs = <2>;
+ qcom,wsa-devs = <&wsa881x_0211>, <&wsa881x_0212>,
+ <&wsa881x_0213>, <&wsa881x_0214>;
+ qcom,wsa-aux-dev-prefix = "SpkrLeft", "SpkrRight",
+ "SpkrLeft", "SpkrRight";
+};
+
+&int_codec {
+ qcom,audio-routing =
+ "RX_BIAS", "INT_MCLK0",
+ "SPK_RX_BIAS", "INT_MCLK0",
+ "INT_LDO_H", "INT_MCLK0",
+ "MIC BIAS External", "Handset Mic",
+ "MIC BIAS External2", "Headset Mic",
+ "MIC BIAS External", "Secondary Mic",
+ "AMIC1", "MIC BIAS External",
+ "AMIC2", "MIC BIAS External2",
+ "AMIC3", "MIC BIAS External",
+ "DMIC1", "MIC BIAS External",
+ "MIC BIAS External", "Digital Mic1",
+ "DMIC2", "MIC BIAS External",
+ "MIC BIAS External", "Digital Mic2",
+ "DMIC3", "MIC BIAS External",
+ "MIC BIAS External", "Digital Mic3",
+ "DMIC4", "MIC BIAS External",
+ "MIC BIAS External", "Digital Mic4",
+ "SpkrLeft IN", "SPK1 OUT",
+ "SpkrRight IN", "SPK2 OUT",
+ "PDM_IN_RX1", "PDM_OUT_RX1",
+ "PDM_IN_RX2", "PDM_OUT_RX2",
+ "PDM_IN_RX3", "PDM_OUT_RX3",
+ "ADC1_IN", "ADC1_OUT",
+ "ADC2_IN", "ADC2_OUT",
+ "ADC3_IN", "ADC3_OUT";
+
+ qcom,msm-mi2s-master = <1>, <1>, <1>, <1>, <1>;
+ qcom,msm-mclk-freq = <9600000>;
+ qcom,msm-mbhc-hphl-swh = <1>;
+ qcom,msm-mbhc-gnd-swh = <1>;
+ qcom,msm-micbias2-ext-cap;
+ qcom,msm-hs-micbias-type = "external";
+ qcom,cdc-pdm-gpios = <&cdc_pdm_gpios>;
+ qcom,cdc-comp-gpios = <&cdc_comp_gpios>;
+ qcom,cdc-dmic-gpios = <&cdc_dmic_gpios>;
+
+ asoc-codec = <&stub_codec>, <&msm_digital_codec>,
+ <&pmic_analog_codec>, <&msm_sdw_codec>;
+ asoc-codec-names = "msm-stub-codec.1", "msm-dig-codec",
+ "analog-codec", "msm_sdw_codec";
+
+ qcom,wsa-max-devs = <2>;
+ qcom,wsa-devs = <&wsa881x_211_en>, <&wsa881x_212_en>,
+ <&wsa881x_213_en>, <&wsa881x_214_en>;
+ qcom,wsa-aux-dev-prefix = "SpkrLeft", "SpkrRight",
+ "SpkrLeft", "SpkrRight";
+};
+
+&soc {
+ wcd_usbc_analog_en1_gpio: msm_cdc_pinctrl_usbc_audio_en1 {
+ compatible = "qcom,msm-cdc-pinctrl";
+ pinctrl-names = "aud_active", "aud_sleep";
+ pinctrl-0 = <&wcd_usbc_analog_en1_active>;
+ pinctrl-1 = <&wcd_usbc_analog_en1_idle>;
+ };
+
+ cdc_pdm_gpios: cdc_pdm_pinctrl {
+ compatible = "qcom,msm-cdc-pinctrl";
+ pinctrl-names = "aud_active", "aud_sleep";
+ pinctrl-0 = <&cdc_pdm_clk_active &cdc_pdm_sync_active
+ &cdc_pdm_rx0_active &cdc_pdm_rx1_2_active
+ &cdc_pdm_2_gpios_active>;
+ pinctrl-1 = <&cdc_pdm_clk_sleep &cdc_pdm_sync_sleep
+ &cdc_pdm_rx0_sleep &cdc_pdm_rx1_2_sleep
+ &cdc_pdm_2_gpios_sleep>;
+ qcom,lpi-gpios;
+ };
+
+ cdc_comp_gpios: cdc_comp_pinctrl {
+ compatible = "qcom,msm-cdc-pinctrl";
+ pinctrl-names = "aud_active", "aud_sleep";
+ pinctrl-0 = <&cdc_rx0_comp_active &cdc_rx1_comp_active>;
+ pinctrl-1 = <&cdc_rx0_comp_sleep &cdc_rx1_comp_sleep>;
+ qcom,lpi-gpios;
+ };
+
+ cdc_dmic_gpios: cdc_dmic_pinctrl {
+ compatible = "qcom,msm-cdc-pinctrl";
+ pinctrl-names = "aud_active", "aud_sleep";
+ pinctrl-0 = <&cdc_dmic12_gpios_active
+ &cdc_dmic34_gpios_active>;
+ pinctrl-1 = <&cdc_dmic12_gpios_sleep
+ &cdc_dmic34_gpios_sleep>;
+ qcom,lpi-gpios;
+ };
+
+ cdc_sdw_gpios: sdw_clk_data_pinctrl {
+ compatible = "qcom,msm-cdc-pinctrl";
+ pinctrl-names = "aud_active", "aud_sleep";
+ pinctrl-0 = <&sdw_clk_active &sdw_data_active>;
+ pinctrl-1 = <&sdw_clk_sleep &sdw_data_sleep>;
+ };
+
+ wsa_spkr_en1: wsa_spkr_en1_pinctrl {
+ compatible = "qcom,msm-cdc-pinctrl";
+ pinctrl-names = "aud_active", "aud_sleep";
+ pinctrl-0 = <&spkr_1_sd_n_active>;
+ pinctrl-1 = <&spkr_1_sd_n_sleep>;
+ };
+
+ wsa_spkr_en2: wsa_spkr_en2_pinctrl {
+ compatible = "qcom,msm-cdc-pinctrl";
+ pinctrl-names = "aud_active", "aud_sleep";
+ pinctrl-0 = <&spkr_2_sd_n_active>;
+ pinctrl-1 = <&spkr_2_sd_n_sleep>;
+ };
+
+ msm_sdw_codec: msm-sdw-codec@62ec1000 {
+ status = "okay";
+ compatible = "qcom,msm-sdw-codec";
+ reg = <0x62ec1000 0x0>;
+ interrupts = <0 88 0>;
+ interrupt-names = "swr_master_irq";
+ qcom,cdc-sdw-gpios = <&cdc_sdw_gpios>;
+
+ swr_master {
+ compatible = "qcom,swr-wcd";
+ #address-cells = <2>;
+ #size-cells = <0>;
+
+ wsa881x_211_en: wsa881x_en@20170211 {
+ compatible = "qcom,wsa881x";
+ reg = <0x0 0x20170211>;
+ qcom,spkr-sd-n-node = <&wsa_spkr_en1>;
+ };
+
+ wsa881x_212_en: wsa881x_en@20170212 {
+ compatible = "qcom,wsa881x";
+ reg = <0x0 0x20170212>;
+ qcom,spkr-sd-n-node = <&wsa_spkr_en2>;
+ };
+
+ wsa881x_213_en: wsa881x_en@21170213 {
+ compatible = "qcom,wsa881x";
+ reg = <0x0 0x21170213>;
+ qcom,spkr-sd-n-node = <&wsa_spkr_en1>;
+ };
+
+ wsa881x_214_en: wsa881x_en@21170214 {
+ compatible = "qcom,wsa881x";
+ reg = <0x0 0x21170214>;
+ qcom,spkr-sd-n-node = <&wsa_spkr_en2>;
+ };
+ };
+ };
+
+ wcd9xxx_intc: wcd9xxx-irq {
+ status = "disabled";
+ compatible = "qcom,wcd9xxx-irq";
+ interrupt-controller;
+ #interrupt-cells = <1>;
+ interrupt-parent = <&tlmm>;
+ qcom,gpio-connect = <&tlmm 80 0>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&wcd_intr_default>;
+ };
+
+ clock_audio_lnbb: audio_ext_clk_lnbb {
+ status = "disabled";
+ compatible = "qcom,audio-ref-clk";
+ clock-names = "osr_clk";
+ clocks = <&clock_rpmh RPMH_LN_BB_CLK2>;
+ qcom,node_has_rpm_clock;
+ #clock-cells = <1>;
+ };
+
+ wcd_rst_gpio: msm_cdc_pinctrl@64 {
+ status = "disabled";
+ compatible = "qcom,msm-cdc-pinctrl";
+ pinctrl-names = "aud_active", "aud_sleep";
+ pinctrl-0 = <&lpi_cdc_reset_active>;
+ pinctrl-1 = <&lpi_cdc_reset_sleep>;
+ qcom,lpi-gpios;
+ };
+
+ wdsp_mgr: qcom,wcd-dsp-mgr {
+ compatible = "qcom,wcd-dsp-mgr";
+ qcom,wdsp-components = <&wcd934x_cdc 0>,
+ <&wcd_spi_0 1>,
+ <&glink_spi_xprt_wdsp 2>;
+ qcom,img-filename = "cpe_9340";
+ };
+
+ wdsp_glink: qcom,wcd-dsp-glink {
+ compatible = "qcom,wcd-dsp-glink";
+ };
+};
+
+&slim_aud {
+ wcd934x_cdc: tavil_codec {
+ status = "disabled";
+ compatible = "qcom,tavil-slim-pgd";
+ elemental-addr = [00 01 50 02 17 02];
+
+ interrupt-parent = <&wcd9xxx_intc>;
+ interrupts = <0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
+ 17 18 19 20 21 22 23 24 25 26 27 28 29
+ 30 31>;
+
+ qcom,wcd-rst-gpio-node = <&wcd_rst_gpio>;
+
+ clock-names = "wcd_clk";
+ clocks = <&clock_audio_lnbb AUDIO_PMIC_LNBB_CLK>;
+
+ cdc-vdd-mic-bias-supply = <&pm660l_bob>;
+ qcom,cdc-vdd-mic-bias-voltage = <3312000 3312000>;
+ qcom,cdc-vdd-mic-bias-current = <30400>;
+
+ qcom,cdc-static-supplies = "cdc-vdd-mic-bias";
+
+ qcom,cdc-micbias1-mv = <1800>;
+ qcom,cdc-micbias2-mv = <1800>;
+ qcom,cdc-micbias3-mv = <1800>;
+ qcom,cdc-micbias4-mv = <1800>;
+
+ qcom,cdc-mclk-clk-rate = <9600000>;
+ qcom,cdc-slim-ifd = "tavil-slim-ifd";
+ qcom,cdc-slim-ifd-elemental-addr = [00 00 50 02 17 02];
+ qcom,cdc-dmic-sample-rate = <4800000>;
+ qcom,cdc-mad-dmic-rate = <600000>;
+
+ qcom,wdsp-cmpnt-dev-name = "tavil_codec";
+
+ wcd_spi_0: wcd_spi {
+ compatible = "qcom,wcd-spi-v2";
+ qcom,master-bus-num = <0>;
+ qcom,chip-select = <0>;
+ qcom,max-frequency = <24000000>;
+ qcom,mem-base-addr = <0x100000>;
+ };
+ };
+};
+
+&pm660l_3 {
+ pmic_analog_codec: analog-codec@f000 {
+ status = "okay";
+ compatible = "qcom,pmic-analog-codec";
+ reg = <0xf000 0x200>;
+ #address-cells = <2>;
+ #size-cells = <0>;
+ interrupt-parent = <&spmi_bus>;
+ interrupts = <0x3 0xf0 0x0 IRQ_TYPE_NONE>,
+ <0x3 0xf0 0x1 IRQ_TYPE_NONE>,
+ <0x3 0xf0 0x2 IRQ_TYPE_NONE>,
+ <0x3 0xf0 0x3 IRQ_TYPE_NONE>,
+ <0x3 0xf0 0x4 IRQ_TYPE_NONE>,
+ <0x3 0xf0 0x5 IRQ_TYPE_NONE>,
+ <0x3 0xf0 0x6 IRQ_TYPE_NONE>,
+ <0x3 0xf0 0x7 IRQ_TYPE_NONE>,
+ <0x3 0xf1 0x0 IRQ_TYPE_NONE>,
+ <0x3 0xf1 0x1 IRQ_TYPE_NONE>,
+ <0x3 0xf1 0x2 IRQ_TYPE_NONE>,
+ <0x3 0xf1 0x3 IRQ_TYPE_NONE>,
+ <0x3 0xf1 0x4 IRQ_TYPE_NONE>,
+ <0x3 0xf1 0x5 IRQ_TYPE_NONE>;
+ interrupt-names = "spk_cnp_int",
+ "spk_clip_int",
+ "spk_ocp_int",
+ "ins_rem_det1",
+ "but_rel_det",
+ "but_press_det",
+ "ins_rem_det",
+ "mbhc_int",
+ "ear_ocp_int",
+ "hphr_ocp_int",
+ "hphl_ocp_det",
+ "ear_cnp_int",
+ "hphr_cnp_int",
+ "hphl_cnp_int";
+
+ cdc-vdda-cp-supply = <&pm660_s4>;
+ qcom,cdc-vdda-cp-voltage = <1900000 2050000>;
+ qcom,cdc-vdda-cp-current = <50000>;
+
+ cdc-vdd-pa-supply = <&pm660_s4>;
+ qcom,cdc-vdd-pa-voltage = <2040000 2040000>;
+ qcom,cdc-vdd-pa-current = <260000>;
+
+ cdc-vdd-mic-bias-supply = <&pm660l_l7>;
+ qcom,cdc-vdd-mic-bias-voltage = <3088000 3088000>;
+ qcom,cdc-vdd-mic-bias-current = <5000>;
+
+ qcom,cdc-mclk-clk-rate = <9600000>;
+
+ qcom,cdc-static-supplies = "cdc-vdda-cp",
+ "cdc-vdd-pa";
+
+ qcom,cdc-on-demand-supplies = "cdc-vdd-mic-bias";
+
+ /*
+ * Not marking address @ as driver searches this child
+ * with name msm-dig-codec
+ */
+ msm_digital_codec: msm-dig-codec {
+ compatible = "qcom,msm-digital-codec";
+ reg = <0x62ec0000 0x0>;
+ };
+ };
+};
diff --git a/arch/arm64/boot/dts/qcom/sdm670-audio.dtsi b/arch/arm64/boot/dts/qcom/sdm670-audio.dtsi
index 3bd0350..ef92cdd 100644
--- a/arch/arm64/boot/dts/qcom/sdm670-audio.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm670-audio.dtsi
@@ -39,42 +39,6 @@
qcom,wcn-btfm;
qcom,mi2s-audio-intf;
qcom,auxpcm-audio-intf;
- qcom,msm-mi2s-master = <1>, <1>, <1>, <1>;
- qcom,audio-routing =
- "AIF4 VI", "MCLK",
- "RX_BIAS", "MCLK",
- "MADINPUT", "MCLK",
- "hifi amp", "LINEOUT1",
- "hifi amp", "LINEOUT2",
- "AMIC2", "MIC BIAS2",
- "MIC BIAS2", "Headset Mic",
- "AMIC3", "MIC BIAS2",
- "MIC BIAS2", "ANCRight Headset Mic",
- "AMIC4", "MIC BIAS2",
- "MIC BIAS2", "ANCLeft Headset Mic",
- "AMIC5", "MIC BIAS3",
- "MIC BIAS3", "Handset Mic",
- "DMIC0", "MIC BIAS1",
- "MIC BIAS1", "Digital Mic0",
- "DMIC1", "MIC BIAS1",
- "MIC BIAS1", "Digital Mic1",
- "DMIC2", "MIC BIAS3",
- "MIC BIAS3", "Digital Mic2",
- "DMIC3", "MIC BIAS3",
- "MIC BIAS3", "Digital Mic3",
- "DMIC4", "MIC BIAS4",
- "MIC BIAS4", "Digital Mic4",
- "DMIC5", "MIC BIAS4",
- "MIC BIAS4", "Digital Mic5",
- "SpkrLeft IN", "SPK1 OUT",
- "SpkrRight IN", "SPK2 OUT";
-
- qcom,msm-mbhc-hphl-swh = <1>;
- qcom,msm-mbhc-gnd-swh = <1>;
- qcom,hph-en0-gpio = <&tavil_hph_en0>;
- qcom,hph-en1-gpio = <&tavil_hph_en1>;
- qcom,msm-mclk-freq = <9600000>;
- qcom,usbc-analog-en1_gpio = <&wcd_usbc_analog_en1_gpio>;
asoc-platform = <&pcm0>, <&pcm1>, <&pcm2>, <&voip>, <&voice>,
<&loopback>, <&compress>, <&hostless>,
<&afe>, <&lsm>, <&routing>, <&cpe>, <&compr>,
@@ -87,9 +51,10 @@
"msm-pcm-routing", "msm-cpe-lsm",
"msm-compr-dsp", "msm-pcm-dsp-noirq";
asoc-cpu = <&dai_mi2s0>, <&dai_mi2s1>,
- <&dai_mi2s2>, <&dai_mi2s3>,
+ <&dai_mi2s2>, <&dai_mi2s3>, <&dai_mi2s4>,
<&dai_pri_auxpcm>, <&dai_sec_auxpcm>,
<&dai_tert_auxpcm>, <&dai_quat_auxpcm>,
+ <&dai_quin_auxpcm>,
<&sb_0_rx>, <&sb_0_tx>, <&sb_1_rx>, <&sb_1_tx>,
<&sb_2_rx>, <&sb_2_tx>, <&sb_3_rx>, <&sb_3_tx>,
<&sb_4_rx>, <&sb_4_tx>, <&sb_5_rx>, <&sb_5_tx>,
@@ -103,11 +68,14 @@
<&dai_pri_tdm_rx_0>, <&dai_pri_tdm_tx_0>,
<&dai_sec_tdm_rx_0>, <&dai_sec_tdm_tx_0>,
<&dai_tert_tdm_rx_0>, <&dai_tert_tdm_tx_0>,
- <&dai_quat_tdm_rx_0>, <&dai_quat_tdm_tx_0>;
+ <&dai_quat_tdm_rx_0>, <&dai_quat_tdm_tx_0>,
+ <&dai_quin_tdm_rx_0>, <&dai_quin_tdm_tx_0>;
asoc-cpu-names = "msm-dai-q6-mi2s.0", "msm-dai-q6-mi2s.1",
"msm-dai-q6-mi2s.2", "msm-dai-q6-mi2s.3",
+ "msm-dai-q6-mi2s.5",
"msm-dai-q6-auxpcm.1", "msm-dai-q6-auxpcm.2",
"msm-dai-q6-auxpcm.3", "msm-dai-q6-auxpcm.4",
+ "msm-dai-q6-auxpcm.5",
"msm-dai-q6-dev.16384", "msm-dai-q6-dev.16385",
"msm-dai-q6-dev.16386", "msm-dai-q6-dev.16387",
"msm-dai-q6-dev.16388", "msm-dai-q6-dev.16389",
@@ -125,59 +93,17 @@
"msm-dai-q6-tdm.36864", "msm-dai-q6-tdm.36865",
"msm-dai-q6-tdm.36880", "msm-dai-q6-tdm.36881",
"msm-dai-q6-tdm.36896", "msm-dai-q6-tdm.36897",
- "msm-dai-q6-tdm.36912", "msm-dai-q6-tdm.36913";
- asoc-codec = <&stub_codec>;
- asoc-codec-names = "msm-stub-codec.1";
- qcom,wsa-max-devs = <2>;
- qcom,wsa-devs = <&wsa881x_0211>, <&wsa881x_0212>,
- <&wsa881x_0213>, <&wsa881x_0214>;
- qcom,wsa-aux-dev-prefix = "SpkrLeft", "SpkrRight",
- "SpkrLeft", "SpkrRight";
+ "msm-dai-q6-tdm.36912", "msm-dai-q6-tdm.36913",
+ "msm-dai-q6-tdm.36928", "msm-dai-q6-tdm.36929";
};
-int_codec: sound {
+ int_codec: sound {
status = "okay";
compatible = "qcom,sdm670-asoc-snd";
- qcom,model = "sdm670-snd-card";
+ qcom,model = "sdm670-snd-card-mtp";
qcom,wcn-btfm;
qcom,mi2s-audio-intf;
qcom,auxpcm-audio-intf;
- qcom,msm-mi2s-master = <1>, <1>, <1>, <1>;
- qcom,msm-mclk-freq = <9600000>;
- qcom,msm-mbhc-hphl-swh = <1>;
- qcom,msm-mbhc-gnd-swh = <1>;
- qcom,msm-micbias2-ext-cap;
- qcom,msm-hs-micbias-type = "external";
- qcom,cdc-pdm-gpios = <&cdc_pdm_gpios>;
- qcom,cdc-comp-gpios = <&cdc_comp_gpios>;
- qcom,cdc-dmic-gpios = <&cdc_dmic_gpios>;
- qcom,audio-routing =
- "RX_BIAS", "INT_MCLK0",
- "SPK_RX_BIAS", "INT_MCLK0",
- "INT_LDO_H", "INT_MCLK0",
- "MIC BIAS External", "Handset Mic",
- "MIC BIAS External2", "Headset Mic",
- "MIC BIAS External", "Secondary Mic",
- "AMIC1", "MIC BIAS External",
- "AMIC2", "MIC BIAS External2",
- "AMIC3", "MIC BIAS External",
- "DMIC1", "MIC BIAS External",
- "MIC BIAS External", "Digital Mic1",
- "DMIC2", "MIC BIAS External",
- "MIC BIAS External", "Digital Mic2",
- "DMIC3", "MIC BIAS External",
- "MIC BIAS External", "Digital Mic3",
- "DMIC4", "MIC BIAS External",
- "MIC BIAS External", "Digital Mic4",
- "SpkrLeft IN", "SPK1 OUT",
- "SpkrRight IN", "SPK2 OUT",
- "PDM_IN_RX1", "PDM_OUT_RX1",
- "PDM_IN_RX2", "PDM_OUT_RX2",
- "PDM_IN_RX3", "PDM_OUT_RX3",
- "ADC1_IN", "ADC1_OUT",
- "ADC2_IN", "ADC2_OUT",
- "ADC3_IN", "ADC3_OUT";
-
asoc-platform = <&pcm0>, <&pcm1>, <&pcm2>, <&voip>, <&voice>,
<&loopback>, <&compress>, <&hostless>,
<&afe>, <&lsm>, <&routing>, <&compr>,
@@ -190,12 +116,13 @@
"msm-pcm-routing", "msm-compr-dsp",
"msm-pcm-dsp-noirq";
asoc-cpu = <&dai_mi2s0>, <&dai_mi2s1>,
- <&dai_mi2s2>, <&dai_mi2s3>,
+ <&dai_mi2s2>, <&dai_mi2s3>, <&dai_mi2s4>,
<&dai_int_mi2s0>, <&dai_int_mi2s1>,
<&dai_int_mi2s2>, <&dai_int_mi2s3>,
<&dai_int_mi2s4>, <&dai_int_mi2s5>,
<&dai_pri_auxpcm>, <&dai_sec_auxpcm>,
<&dai_tert_auxpcm>, <&dai_quat_auxpcm>,
+ <&dai_quin_auxpcm>,
<&afe_pcm_rx>, <&afe_pcm_tx>, <&afe_proxy_rx>,
<&afe_proxy_tx>, <&incall_record_rx>,
<&incall_record_tx>, <&incall_music_rx>,
@@ -205,14 +132,17 @@
<&dai_pri_tdm_rx_0>, <&dai_pri_tdm_tx_0>,
<&dai_sec_tdm_rx_0>, <&dai_sec_tdm_tx_0>,
<&dai_tert_tdm_rx_0>, <&dai_tert_tdm_tx_0>,
- <&dai_quat_tdm_rx_0>, <&dai_quat_tdm_tx_0>;
+ <&dai_quat_tdm_rx_0>, <&dai_quat_tdm_tx_0>,
+ <&dai_quin_tdm_rx_0>, <&dai_quin_tdm_tx_0>;
asoc-cpu-names = "msm-dai-q6-mi2s.0", "msm-dai-q6-mi2s.1",
"msm-dai-q6-mi2s.2", "msm-dai-q6-mi2s.3",
+ "msm-dai-q6-mi2s.5",
"msm-dai-q6-mi2s.7", "msm-dai-q6-mi2s.8",
"msm-dai-q6-mi2s.9", "msm-dai-q6-mi2s.10",
"msm-dai-q6-mi2s.11", "msm-dai-q6-mi2s.12",
"msm-dai-q6-auxpcm.1", "msm-dai-q6-auxpcm.2",
"msm-dai-q6-auxpcm.3", "msm-dai-q6-auxpcm.4",
+ "msm-dai-q6-auxpcm.5",
"msm-dai-q6-dev.224", "msm-dai-q6-dev.225",
"msm-dai-q6-dev.241", "msm-dai-q6-dev.240",
"msm-dai-q6-dev.32771", "msm-dai-q6-dev.32772",
@@ -223,136 +153,8 @@
"msm-dai-q6-tdm.36864", "msm-dai-q6-tdm.36865",
"msm-dai-q6-tdm.36880", "msm-dai-q6-tdm.36881",
"msm-dai-q6-tdm.36896", "msm-dai-q6-tdm.36897",
- "msm-dai-q6-tdm.36912", "msm-dai-q6-tdm.36913";
- asoc-codec = <&stub_codec>, <&msm_digital_codec>,
- <&pmic_analog_codec>, <&msm_sdw_codec>;
- asoc-codec-names = "msm-stub-codec.1", "msm-dig-codec",
- "analog-codec", "msm_sdw_codec";
-
- qcom,wsa-max-devs = <2>;
- qcom,wsa-devs = <&wsa881x_211_en>, <&wsa881x_212_en>,
- <&wsa881x_213_en>, <&wsa881x_214_en>;
- qcom,wsa-aux-dev-prefix = "SpkrLeft", "SpkrRight",
- "SpkrLeft", "SpkrRight";
- };
-
- cdc_pdm_gpios: cdc_pdm_pinctrl {
- compatible = "qcom,msm-cdc-pinctrl";
- pinctrl-names = "aud_active", "aud_sleep";
- pinctrl-0 = <&cdc_pdm_clk_active &cdc_pdm_sync_active
- &cdc_pdm_rx0_active &cdc_pdm_rx1_2_active
- &cdc_pdm_2_gpios_active>;
- pinctrl-1 = <&cdc_pdm_clk_sleep &cdc_pdm_sync_sleep
- &cdc_pdm_rx0_sleep &cdc_pdm_rx1_2_sleep
- &cdc_pdm_2_gpios_sleep>;
- qcom,lpi-gpios;
- };
-
- cdc_comp_gpios: cdc_comp_pinctrl {
- compatible = "qcom,msm-cdc-pinctrl";
- pinctrl-names = "aud_active", "aud_sleep";
- pinctrl-0 = <&cdc_rx0_comp_active &cdc_rx1_comp_active>;
- pinctrl-1 = <&cdc_rx0_comp_sleep &cdc_rx1_comp_sleep>;
- qcom,lpi-gpios;
- };
-
- cdc_dmic_gpios: cdc_dmic_pinctrl {
- compatible = "qcom,msm-cdc-pinctrl";
- pinctrl-names = "aud_active", "aud_sleep";
- pinctrl-0 = <&cdc_dmic12_gpios_active
- &cdc_dmic34_gpios_active>;
- pinctrl-1 = <&cdc_dmic12_gpios_sleep
- &cdc_dmic34_gpios_sleep>;
- qcom,lpi-gpios;
- };
-
- cdc_sdw_gpios: sdw_clk_data_pinctrl {
- compatible = "qcom,msm-cdc-pinctrl";
- pinctrl-names = "aud_active", "aud_sleep";
- pinctrl-0 = <&sdw_clk_active &sdw_data_active>;
- pinctrl-1 = <&sdw_clk_sleep &sdw_data_sleep>;
- };
-
- wsa_spkr_en1: wsa_spkr_en1_pinctrl {
- compatible = "qcom,msm-cdc-pinctrl";
- pinctrl-names = "aud_active", "aud_sleep";
- pinctrl-0 = <&spkr_1_sd_n_active>;
- pinctrl-1 = <&spkr_1_sd_n_sleep>;
- };
-
- wsa_spkr_en2: wsa_spkr_en2_pinctrl {
- compatible = "qcom,msm-cdc-pinctrl";
- pinctrl-names = "aud_active", "aud_sleep";
- pinctrl-0 = <&spkr_2_sd_n_active>;
- pinctrl-1 = <&spkr_2_sd_n_sleep>;
- };
-
- msm_sdw_codec: msm-sdw-codec@62ec1000 {
- status = "okay";
- compatible = "qcom,msm-sdw-codec";
- reg = <0x62ec1000 0x0>;
- interrupts = <0 161 0>;
- interrupt-names = "swr_master_irq";
- qcom,cdc-sdw-gpios = <&cdc_sdw_gpios>;
-
- swr_master {
- compatible = "qcom,swr-wcd";
- #address-cells = <2>;
- #size-cells = <0>;
-
- wsa881x_211_en: wsa881x_en@20170211 {
- compatible = "qcom,wsa881x";
- reg = <0x0 0x20170211>;
- qcom,spkr-sd-n-node = <&wsa_spkr_en1>;
- };
-
- wsa881x_212_en: wsa881x_en@20170212 {
- compatible = "qcom,wsa881x";
- reg = <0x0 0x20170212>;
- qcom,spkr-sd-n-node = <&wsa_spkr_en2>;
- };
-
- wsa881x_213_en: wsa881x_en@21170213 {
- compatible = "qcom,wsa881x";
- reg = <0x0 0x21170213>;
- qcom,spkr-sd-n-node = <&wsa_spkr_en1>;
- };
-
- wsa881x_214_en: wsa881x_en@21170214 {
- compatible = "qcom,wsa881x";
- reg = <0x0 0x21170214>;
- qcom,spkr-sd-n-node = <&wsa_spkr_en2>;
- };
- };
- };
-
- wcd9xxx_intc: wcd9xxx-irq {
- status = "disabled";
- compatible = "qcom,wcd9xxx-irq";
- interrupt-controller;
- #interrupt-cells = <1>;
- interrupt-parent = <&tlmm>;
- qcom,gpio-connect = <&tlmm 80 0>;
- pinctrl-names = "default";
- pinctrl-0 = <&wcd_intr_default>;
- };
-
- clock_audio_lnbb: audio_ext_clk_lnbb {
- status = "disabled";
- compatible = "qcom,audio-ref-clk";
- clock-names = "osr_clk";
- clocks = <&clock_rpmh RPMH_LN_BB_CLK2>;
- qcom,node_has_rpm_clock;
- #clock-cells = <1>;
- };
-
- wcd_rst_gpio: msm_cdc_pinctrl@64 {
- status = "disabled";
- compatible = "qcom,msm-cdc-pinctrl";
- pinctrl-names = "aud_active", "aud_sleep";
- pinctrl-0 = <&lpi_cdc_reset_active>;
- pinctrl-1 = <&lpi_cdc_reset_sleep>;
- qcom,lpi-gpios;
+ "msm-dai-q6-tdm.36912", "msm-dai-q6-tdm.36913",
+ "msm-dai-q6-tdm.36928", "msm-dai-q6-tdm.36929";
};
cpe: qcom,msm-cpe-lsm {
@@ -363,18 +165,6 @@
compatible = "qcom,msm-cpe-lsm";
qcom,msm-cpe-lsm-id = <3>;
};
-
- wdsp_mgr: qcom,wcd-dsp-mgr {
- compatible = "qcom,wcd-dsp-mgr";
- qcom,wdsp-components = <&wcd934x_cdc 0>,
- <&wcd_spi_0 1>,
- <&glink_spi_xprt_wdsp 2>;
- qcom,img-filename = "cpe_9340";
- };
-
- wdsp_glink: qcom,wcd-dsp-glink {
- compatible = "qcom,wcd-dsp-glink";
- };
};
&slim_aud {
@@ -384,56 +174,6 @@
compatible = "qcom,msm-dai-slim";
elemental-addr = [ff ff ff fe 17 02];
};
-
- wcd934x_cdc: tavil_codec {
- status = "disabled";
- compatible = "qcom,tavil-slim-pgd";
- elemental-addr = [00 01 50 02 17 02];
-
- interrupt-parent = <&wcd9xxx_intc>;
- interrupts = <0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
- 17 18 19 20 21 22 23 24 25 26 27 28 29
- 30 31>;
-
- qcom,wcd-rst-gpio-node = <&wcd_rst_gpio>;
-
- clock-names = "wcd_clk";
- clocks = <&clock_audio_lnbb AUDIO_PMIC_LNBB_CLK>;
-
- cdc-vdd-mic-bias-supply = <&pm660l_bob>;
- qcom,cdc-vdd-mic-bias-voltage = <3300000 3300000>;
- qcom,cdc-vdd-mic-bias-current = <30400>;
-
- qcom,cdc-static-supplies = "cdc-vdd-mic-bias";
-
- qcom,cdc-micbias1-mv = <1800>;
- qcom,cdc-micbias2-mv = <1800>;
- qcom,cdc-micbias3-mv = <1800>;
- qcom,cdc-micbias4-mv = <1800>;
-
- qcom,cdc-mclk-clk-rate = <9600000>;
- qcom,cdc-slim-ifd = "tavil-slim-ifd";
- qcom,cdc-slim-ifd-elemental-addr = [00 00 50 02 17 02];
- qcom,cdc-dmic-sample-rate = <4800000>;
- qcom,cdc-mad-dmic-rate = <600000>;
-
- qcom,wdsp-cmpnt-dev-name = "tavil_codec";
-
- wcd_spi_0: wcd_spi {
- compatible = "qcom,wcd-spi-v2";
- qcom,master-bus-num = <8>;
- qcom,chip-select = <0>;
- qcom,max-frequency = <24000000>;
- qcom,mem-base-addr = <0x100000>;
- };
-
- wcd_usbc_analog_en1_gpio: msm_cdc_pinctrl_usbc_audio_en1 {
- compatible = "qcom,msm-cdc-pinctrl";
- pinctrl-names = "aud_active", "aud_sleep";
- pinctrl-0 = <&wcd_usbc_analog_en1_active>;
- pinctrl-1 = <&wcd_usbc_analog_en1_idle>;
- };
- };
};
&msm_dai_mi2s {
@@ -486,83 +226,3 @@
qcom,msm-mi2s-tx-lines = <3>;
};
};
-
-&pm660l_3 {
- pmic_analog_codec: analog-codec@f000 {
- status = "okay";
- compatible = "qcom,pmic-analog-codec";
- reg = <0xf000 0x200>;
- #address-cells = <2>;
- #size-cells = <0>;
- interrupt-parent = <&spmi_bus>;
- interrupts = <0x3 0xf0 0x0 IRQ_TYPE_NONE>,
- <0x3 0xf0 0x1 IRQ_TYPE_NONE>,
- <0x3 0xf0 0x2 IRQ_TYPE_NONE>,
- <0x3 0xf0 0x3 IRQ_TYPE_NONE>,
- <0x3 0xf0 0x4 IRQ_TYPE_NONE>,
- <0x3 0xf0 0x5 IRQ_TYPE_NONE>,
- <0x3 0xf0 0x6 IRQ_TYPE_NONE>,
- <0x3 0xf0 0x7 IRQ_TYPE_NONE>,
- <0x3 0xf1 0x0 IRQ_TYPE_NONE>,
- <0x3 0xf1 0x1 IRQ_TYPE_NONE>,
- <0x3 0xf1 0x2 IRQ_TYPE_NONE>,
- <0x3 0xf1 0x3 IRQ_TYPE_NONE>,
- <0x3 0xf1 0x4 IRQ_TYPE_NONE>,
- <0x3 0xf1 0x5 IRQ_TYPE_NONE>;
- interrupt-names = "spk_cnp_int",
- "spk_clip_int",
- "spk_ocp_int",
- "ins_rem_det1",
- "but_rel_det",
- "but_press_det",
- "ins_rem_det",
- "mbhc_int",
- "ear_ocp_int",
- "hphr_ocp_int",
- "hphl_ocp_det",
- "ear_cnp_int",
- "hphr_cnp_int",
- "hphl_cnp_int";
-
-
- cdc-vdda-cp-supply = <&pm660_s4>;
- qcom,cdc-vdda-cp-voltage = <1900000 2050000>;
- qcom,cdc-vdda-cp-current = <50000>;
-
- cdc-vdd-pa-supply = <&pm660_s4>;
- qcom,cdc-vdd-pa-voltage = <2040000 2040000>;
- qcom,cdc-vdd-pa-current = <260000>;
-
- cdc-vdd-mic-bias-supply = <&pm660l_l7>;
- qcom,cdc-vdd-mic-bias-voltage = <3088000 3088000>;
- qcom,cdc-vdd-mic-bias-current = <5000>;
-
- qcom,cdc-mclk-clk-rate = <9600000>;
-
- qcom,cdc-static-supplies = "cdc-vdda-cp",
- "cdc-vdd-pa";
-
- qcom,cdc-on-demand-supplies = "cdc-vdd-mic-bias";
-
- /*
- * Not marking address @ as driver searches this child
- * with name msm-dig-codec
- */
- msm_digital_codec: msm-dig-codec {
- compatible = "qcom,msm-digital-codec";
- reg = <0x62ec0000 0x0>;
- };
- };
-};
-
-&pm660_gpios {
- gpio@c200 {
- status = "ok";
- qcom,mode = <1>;
- qcom,pull = <4>;
- qcom,vin-sel = <0>;
- qcom,src-sel = <2>;
- qcom,master-en = <1>;
- qcom,out-strength = <2>;
- };
-};
diff --git a/arch/arm64/boot/dts/qcom/sdm670-bus.dtsi b/arch/arm64/boot/dts/qcom/sdm670-bus.dtsi
new file mode 100644
index 0000000..8749145
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/sdm670-bus.dtsi
@@ -0,0 +1,1873 @@
+/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <dt-bindings/msm/msm-bus-ids.h>
+#include <dt-bindings/soc/qcom,tcs-mbox.h>
+
+&soc {
+ ad_hoc_bus: ad-hoc-bus {
+ compatible = "qcom,msm-bus-device";
+ reg = <0x016E0000 0x40000>,
+ <0x1700000 0x40000>,
+ <0x1500000 0x40000>,
+ <0x14E0000 0x40000>,
+ <0x17900000 0x40000>,
+ <0x1380000 0x40000>,
+ <0x1380000 0x40000>,
+ <0x1740000 0x40000>,
+ <0x1620000 0x40000>,
+ <0x1620000 0x40000>,
+ <0x1620000 0x40000>;
+
+ reg-names = "aggre1_noc-base", "aggre2_noc-base",
+ "config_noc-base", "dc_noc-base",
+ "gladiator_noc-base", "mc_virt-base", "mem_noc-base",
+ "mmss_noc-base", "system_noc-base", "ipa_virt-base",
+ "camnoc_virt-base";
+
+ mbox-names = "apps_rsc", "disp_rsc";
+ mboxes = <&apps_rsc 0 &disp_rsc 0>;
+
+ /*RSCs*/
+ rsc_apps: rsc-apps {
+ cell-id = <MSM_BUS_RSC_APPS>;
+ label = "apps_rsc";
+ qcom,rsc-dev;
+ qcom,req_state = <2>;
+ };
+
+ rsc_disp: rsc-disp {
+ cell-id = <MSM_BUS_RSC_DISP>;
+ label = "disp_rsc";
+ qcom,rsc-dev;
+ qcom,req_state = <3>;
+ };
+
+ /*BCMs*/
+ bcm_acv: bcm-acv {
+ cell-id = <MSM_BUS_BCM_ACV>;
+ label = "ACV";
+ qcom,bcm-name = "ACV";
+ qcom,rscs = <&rsc_apps>;
+ qcom,bcm-dev;
+ };
+
+ bcm_alc: bcm-alc {
+ cell-id = <MSM_BUS_BCM_ALC>;
+ label = "ALC";
+ qcom,bcm-name = "ALC";
+ qcom,rscs = <&rsc_apps>;
+ qcom,bcm-dev;
+ };
+
+ bcm_mc0: bcm-mc0 {
+ cell-id = <MSM_BUS_BCM_MC0>;
+ label = "MC0";
+ qcom,bcm-name = "MC0";
+ qcom,rscs = <&rsc_apps>;
+ qcom,bcm-dev;
+ };
+
+ bcm_sh0: bcm-sh0 {
+ cell-id = <MSM_BUS_BCM_SH0>;
+ label = "SH0";
+ qcom,bcm-name = "SH0";
+ qcom,rscs = <&rsc_apps>;
+ qcom,bcm-dev;
+ };
+
+ bcm_mm0: bcm-mm0 {
+ cell-id = <MSM_BUS_BCM_MM0>;
+ label = "MM0";
+ qcom,bcm-name = "MM0";
+ qcom,rscs = <&rsc_apps>;
+ qcom,bcm-dev;
+ };
+
+ bcm_sh1: bcm-sh1 {
+ cell-id = <MSM_BUS_BCM_SH1>;
+ label = "SH1";
+ qcom,bcm-name = "SH1";
+ qcom,rscs = <&rsc_apps>;
+ qcom,bcm-dev;
+ };
+
+ bcm_mm1: bcm-mm1 {
+ cell-id = <MSM_BUS_BCM_MM1>;
+ label = "MM1";
+ qcom,bcm-name = "MM1";
+ qcom,rscs = <&rsc_apps>;
+ qcom,bcm-dev;
+ };
+
+ bcm_sh2: bcm-sh2 {
+ cell-id = <MSM_BUS_BCM_SH2>;
+ label = "SH2";
+ qcom,bcm-name = "SH2";
+ qcom,rscs = <&rsc_apps>;
+ qcom,bcm-dev;
+ };
+
+ bcm_mm2: bcm-mm2 {
+ cell-id = <MSM_BUS_BCM_MM2>;
+ label = "MM2";
+ qcom,bcm-name = "MM2";
+ qcom,rscs = <&rsc_apps>;
+ qcom,bcm-dev;
+ };
+
+ bcm_sh3: bcm-sh3 {
+ cell-id = <MSM_BUS_BCM_SH3>;
+ label = "SH3";
+ qcom,bcm-name = "SH3";
+ qcom,rscs = <&rsc_apps>;
+ qcom,bcm-dev;
+ };
+
+ bcm_mm3: bcm-mm3 {
+ cell-id = <MSM_BUS_BCM_MM3>;
+ label = "MM3";
+ qcom,bcm-name = "MM3";
+ qcom,rscs = <&rsc_apps>;
+ qcom,bcm-dev;
+ };
+
+ bcm_sh5: bcm-sh5 {
+ cell-id = <MSM_BUS_BCM_SH5>;
+ label = "SH5";
+ qcom,bcm-name = "SH5";
+ qcom,rscs = <&rsc_apps>;
+ qcom,bcm-dev;
+ };
+
+ bcm_sn0: bcm-sn0 {
+ cell-id = <MSM_BUS_BCM_SN0>;
+ label = "SN0";
+ qcom,bcm-name = "SN0";
+ qcom,rscs = <&rsc_apps>;
+ qcom,bcm-dev;
+ };
+
+ bcm_ce0: bcm-ce0 {
+ cell-id = <MSM_BUS_BCM_CE0>;
+ label = "CE0";
+ qcom,bcm-name = "CE0";
+ qcom,rscs = <&rsc_apps>;
+ qcom,bcm-dev;
+ };
+
+ bcm_ip0: bcm-ip0 {
+ cell-id = <MSM_BUS_BCM_IP0>;
+ label = "IP0";
+ qcom,bcm-name = "IP0";
+ qcom,rscs = <&rsc_apps>;
+ qcom,bcm-dev;
+ };
+
+ bcm_cn0: bcm-cn0 {
+ cell-id = <MSM_BUS_BCM_CN0>;
+ label = "CN0";
+ qcom,bcm-name = "CN0";
+ qcom,rscs = <&rsc_apps>;
+ qcom,bcm-dev;
+ };
+
+ bcm_qup0: bcm-qup0 {
+ cell-id = <MSM_BUS_BCM_QUP0>;
+ label = "QUP0";
+ qcom,bcm-name = "QUP0";
+ qcom,rscs = <&rsc_apps>;
+ qcom,bcm-dev;
+ };
+
+ bcm_sn1: bcm-sn1 {
+ cell-id = <MSM_BUS_BCM_SN1>;
+ label = "SN1";
+ qcom,bcm-name = "SN1";
+ qcom,rscs = <&rsc_apps>;
+ qcom,bcm-dev;
+ };
+
+ bcm_sn2: bcm-sn2 {
+ cell-id = <MSM_BUS_BCM_SN2>;
+ label = "SN2";
+ qcom,bcm-name = "SN2";
+ qcom,rscs = <&rsc_apps>;
+ qcom,bcm-dev;
+ };
+
+ bcm_sn3: bcm-sn3 {
+ cell-id = <MSM_BUS_BCM_SN3>;
+ label = "SN3";
+ qcom,bcm-name = "SN3";
+ qcom,rscs = <&rsc_apps>;
+ qcom,bcm-dev;
+ };
+
+ bcm_sn4: bcm-sn4 {
+ cell-id = <MSM_BUS_BCM_SN4>;
+ label = "SN4";
+ qcom,bcm-name = "SN4";
+ qcom,rscs = <&rsc_apps>;
+ qcom,bcm-dev;
+ };
+
+ bcm_sn5: bcm-sn5 {
+ cell-id = <MSM_BUS_BCM_SN5>;
+ label = "SN5";
+ qcom,bcm-name = "SN5";
+ qcom,rscs = <&rsc_apps>;
+ qcom,bcm-dev;
+ };
+
+ bcm_sn8: bcm-sn8 {
+ cell-id = <MSM_BUS_BCM_SN8>;
+ label = "SN8";
+ qcom,bcm-name = "SN8";
+ qcom,rscs = <&rsc_apps>;
+ qcom,bcm-dev;
+ };
+
+ bcm_sn10: bcm-sn10 {
+ cell-id = <MSM_BUS_BCM_SN10>;
+ label = "SN10";
+ qcom,bcm-name = "SN10";
+ qcom,rscs = <&rsc_apps>;
+ qcom,bcm-dev;
+ };
+
+ bcm_sn11: bcm-sn11 {
+ cell-id = <MSM_BUS_BCM_SN11>;
+ label = "SN11";
+ qcom,bcm-name = "SN11";
+ qcom,rscs = <&rsc_apps>;
+ qcom,bcm-dev;
+ };
+
+ bcm_sn13: bcm-sn13 {
+ cell-id = <MSM_BUS_BCM_SN13>;
+ label = "SN13";
+ qcom,bcm-name = "SN13";
+ qcom,rscs = <&rsc_apps>;
+ qcom,bcm-dev;
+ };
+
+ bcm_mc0_display: bcm-mc0_display {
+ cell-id = <MSM_BUS_BCM_MC0_DISPLAY>;
+ label = "MC0_DISPLAY";
+ qcom,bcm-name = "MC0";
+ qcom,rscs = <&rsc_disp>;
+ qcom,bcm-dev;
+ };
+
+ bcm_sh0_display: bcm-sh0_display {
+ cell-id = <MSM_BUS_BCM_SH0_DISPLAY>;
+ label = "SH0_DISPLAY";
+ qcom,bcm-name = "SH0";
+ qcom,rscs = <&rsc_disp>;
+ qcom,bcm-dev;
+ };
+
+ bcm_mm0_display: bcm-mm0_display {
+ cell-id = <MSM_BUS_BCM_MM0_DISPLAY>;
+ label = "MM0_DISPLAY";
+ qcom,bcm-name = "MM0";
+ qcom,rscs = <&rsc_disp>;
+ qcom,bcm-dev;
+ };
+
+ bcm_mm1_display: bcm-mm1_display {
+ cell-id = <MSM_BUS_BCM_MM1_DISPLAY>;
+ label = "MM1_DISPLAY";
+ qcom,bcm-name = "MM1";
+ qcom,rscs = <&rsc_disp>;
+ qcom,bcm-dev;
+ };
+
+ bcm_mm2_display: bcm-mm2_display {
+ cell-id = <MSM_BUS_BCM_MM2_DISPLAY>;
+ label = "MM2_DISPLAY";
+ qcom,bcm-name = "MM2";
+ qcom,rscs = <&rsc_disp>;
+ qcom,bcm-dev;
+ };
+
+ bcm_mm3_display: bcm-mm3_display {
+ cell-id = <MSM_BUS_BCM_MM3_DISPLAY>;
+ label = "MM3_DISPLAY";
+ qcom,bcm-name = "MM3";
+ qcom,rscs = <&rsc_disp>;
+ qcom,bcm-dev;
+ };
+
+
+ /*Buses*/
+ fab_aggre1_noc: fab-aggre1_noc {
+ cell-id = <MSM_BUS_FAB_A1_NOC>;
+ label = "fab-aggre1_noc";
+ qcom,fab-dev;
+ qcom,base-name = "aggre1_noc-base";
+ qcom,qos-off = <4096>;
+ qcom,base-offset = <16384>;
+ qcom,bypass-qos-prg;
+ qcom,bus-type = <1>;
+ clocks = <>;
+ };
+
+ fab_aggre2_noc: fab-aggre2_noc {
+ cell-id = <MSM_BUS_FAB_A2_NOC>;
+ label = "fab-aggre2_noc";
+ qcom,fab-dev;
+ qcom,base-name = "aggre2_noc-base";
+ qcom,qos-off = <2048>;
+ qcom,base-offset = <12288>;
+ qcom,bypass-qos-prg;
+ qcom,bus-type = <1>;
+ clocks = <>;
+ };
+
+ fab_camnoc_virt: fab-camnoc_virt {
+ cell-id = <MSM_BUS_FAB_CAMNOC_VIRT>;
+ label = "fab-camnoc_virt";
+ qcom,fab-dev;
+ qcom,base-name = "camnoc_virt-base";
+ qcom,qos-off = <0>;
+ qcom,base-offset = <0>;
+ qcom,bypass-qos-prg;
+ clocks = <>;
+ };
+
+ fab_config_noc: fab-config_noc {
+ cell-id = <MSM_BUS_FAB_CONFIG_NOC>;
+ label = "fab-config_noc";
+ qcom,fab-dev;
+ qcom,base-name = "config_noc-base";
+ qcom,qos-off = <0>;
+ qcom,base-offset = <0>;
+ qcom,bypass-qos-prg;
+ qcom,bus-type = <1>;
+ clocks = <>;
+ };
+
+ fab_dc_noc: fab-dc_noc {
+ cell-id = <MSM_BUS_FAB_DC_NOC>;
+ label = "fab-dc_noc";
+ qcom,fab-dev;
+ qcom,base-name = "dc_noc-base";
+ qcom,qos-off = <0>;
+ qcom,base-offset = <0>;
+ qcom,bypass-qos-prg;
+ qcom,bus-type = <1>;
+ clocks = <>;
+ };
+
+ fab_gladiator_noc: fab-gladiator_noc {
+ cell-id = <MSM_BUS_FAB_GNOC>;
+ label = "fab-gladiator_noc";
+ qcom,fab-dev;
+ qcom,base-name = "gladiator_noc-base";
+ qcom,qos-off = <0>;
+ qcom,base-offset = <0>;
+ qcom,bypass-qos-prg;
+ qcom,bus-type = <1>;
+ clocks = <>;
+ };
+
+ fab_ipa_virt: fab-ipa_virt {
+ cell-id = <MSM_BUS_FAB_IPA_VIRT>;
+ label = "fab-ipa_virt";
+ qcom,fab-dev;
+ qcom,base-name = "ipa_virt-base";
+ qcom,qos-off = <0>;
+ qcom,base-offset = <0>;
+ qcom,bypass-qos-prg;
+ clocks = <>;
+ };
+
+ fab_mc_virt: fab-mc_virt {
+ cell-id = <MSM_BUS_FAB_MC_VIRT>;
+ label = "fab-mc_virt";
+ qcom,fab-dev;
+ qcom,base-name = "mc_virt-base";
+ qcom,qos-off = <0>;
+ qcom,base-offset = <0>;
+ qcom,bypass-qos-prg;
+ clocks = <>;
+ };
+
+ fab_mem_noc: fab-mem_noc {
+ cell-id = <MSM_BUS_FAB_MEM_NOC>;
+ label = "fab-mem_noc";
+ qcom,fab-dev;
+ qcom,base-name = "mem_noc-base";
+ qcom,qos-off = <4096>;
+ qcom,base-offset = <65536>;
+ qcom,bypass-qos-prg;
+ qcom,bus-type = <1>;
+ clocks = <>;
+ };
+
+ fab_mmss_noc: fab-mmss_noc {
+ cell-id = <MSM_BUS_FAB_MMSS_NOC>;
+ label = "fab-mmss_noc";
+ qcom,fab-dev;
+ qcom,base-name = "mmss_noc-base";
+ qcom,qos-off = <4096>;
+ qcom,base-offset = <36864>;
+ qcom,bypass-qos-prg;
+ qcom,bus-type = <1>;
+ clocks = <>;
+ };
+
+ fab_system_noc: fab-system_noc {
+ cell-id = <MSM_BUS_FAB_SYS_NOC>;
+ label = "fab-system_noc";
+ qcom,fab-dev;
+ qcom,base-name = "system_noc-base";
+ qcom,qos-off = <4096>;
+ qcom,base-offset = <36864>;
+ qcom,bypass-qos-prg;
+ qcom,bus-type = <1>;
+ clocks = <>;
+ };
+
+ fab_mc_virt_display: fab-mc_virt_display {
+ cell-id = <MSM_BUS_FAB_MC_VIRT_DISPLAY>;
+ label = "fab-mc_virt_display";
+ qcom,fab-dev;
+ qcom,base-name = "mc_virt-base";
+ qcom,qos-off = <0>;
+ qcom,base-offset = <0>;
+ qcom,bypass-qos-prg;
+ clocks = <>;
+ };
+
+ fab_mem_noc_display: fab-mem_noc_display {
+ cell-id = <MSM_BUS_FAB_MEM_NOC_DISPLAY>;
+ label = "fab-mem_noc_display";
+ qcom,fab-dev;
+ qcom,base-name = "mem_noc-base";
+ qcom,qos-off = <4096>;
+ qcom,base-offset = <65536>;
+ qcom,bypass-qos-prg;
+ qcom,bus-type = <1>;
+ clocks = <>;
+ };
+
+ fab_mmss_noc_display: fab-mmss_noc_display {
+ cell-id = <MSM_BUS_FAB_MMSS_NOC_DISPLAY>;
+ label = "fab-mmss_noc_display";
+ qcom,fab-dev;
+ qcom,base-name = "mmss_noc-base";
+ qcom,qos-off = <4096>;
+ qcom,base-offset = <36864>;
+ qcom,bypass-qos-prg;
+ qcom,bus-type = <1>;
+ clocks = <>;
+ };
+
+
+ /*Masters*/
+
+ mas_qhm_a1noc_cfg: mas-qhm-a1noc-cfg {
+ cell-id = <MSM_BUS_MASTER_A1NOC_CFG>;
+ label = "mas-qhm-a1noc-cfg";
+ qcom,buswidth = <4>;
+ qcom,agg-ports = <1>;
+ qcom,connections = <&slv_srvc_aggre1_noc>;
+ qcom,bus-dev = <&fab_aggre1_noc>;
+ };
+
+ mas_qhm_qup1: mas-qhm-qup1 {
+ cell-id = <MSM_BUS_MASTER_BLSP_1>;
+ label = "mas-qhm-qup1";
+ qcom,buswidth = <4>;
+ qcom,agg-ports = <1>;
+ qcom,qport = <16>;
+ qcom,connections = <&slv_qns_a1noc_snoc>;
+ qcom,bus-dev = <&fab_aggre1_noc>;
+ qcom,bcms = <&bcm_qup0>;
+ qcom,ap-owned;
+ qcom,prio = <0>;
+ };
+
+ mas_qhm_tsif: mas-qhm-tsif {
+ cell-id = <MSM_BUS_MASTER_TSIF>;
+ label = "mas-qhm-tsif";
+ qcom,buswidth = <4>;
+ qcom,agg-ports = <1>;
+ qcom,connections = <&slv_qns_a1noc_snoc>;
+ qcom,bus-dev = <&fab_aggre1_noc>;
+ };
+
+ mas_xm_emmc: mas-xm-emmc {
+ cell-id = <MSM_BUS_MASTER_EMMC>;
+ label = "mas-xm-emmc";
+ qcom,buswidth = <8>;
+ qcom,agg-ports = <1>;
+ qcom,qport = <3>;
+ qcom,connections = <&slv_qns_a1noc_snoc>;
+ qcom,bus-dev = <&fab_aggre1_noc>;
+ qcom,ap-owned;
+ qcom,prio = <0>;
+ };
+
+ mas_xm_sdc2: mas-xm-sdc2 {
+ cell-id = <MSM_BUS_MASTER_SDCC_2>;
+ label = "mas-xm-sdc2";
+ qcom,buswidth = <8>;
+ qcom,agg-ports = <1>;
+ qcom,qport = <1>;
+ qcom,connections = <&slv_qns_a1noc_snoc>;
+ qcom,bus-dev = <&fab_aggre1_noc>;
+ qcom,ap-owned;
+ qcom,prio = <1>;
+ };
+
+ mas_xm_sdc4: mas-xm-sdc4 {
+ cell-id = <MSM_BUS_MASTER_SDCC_4>;
+ label = "mas-xm-sdc4";
+ qcom,buswidth = <8>;
+ qcom,agg-ports = <1>;
+ qcom,qport = <2>;
+ qcom,connections = <&slv_qns_a1noc_snoc>;
+ qcom,bus-dev = <&fab_aggre1_noc>;
+ qcom,ap-owned;
+ qcom,prio = <1>;
+ };
+
+ mas_xm_ufs_mem: mas-xm-ufs-mem {
+ cell-id = <MSM_BUS_MASTER_UFS_MEM>;
+ label = "mas-xm-ufs-mem";
+ qcom,buswidth = <8>;
+ qcom,agg-ports = <1>;
+ qcom,qport = <4>;
+ qcom,connections = <&slv_qns_a1noc_snoc>;
+ qcom,bus-dev = <&fab_aggre1_noc>;
+ qcom,ap-owned;
+ qcom,prio = <2>;
+ };
+
+ mas_qhm_a2noc_cfg: mas-qhm-a2noc-cfg {
+ cell-id = <MSM_BUS_MASTER_A2NOC_CFG>;
+ label = "mas-qhm-a2noc-cfg";
+ qcom,buswidth = <4>;
+ qcom,agg-ports = <1>;
+ qcom,connections = <&slv_srvc_aggre2_noc>;
+ qcom,bus-dev = <&fab_aggre2_noc>;
+ };
+
+ mas_qhm_qdss_bam: mas-qhm-qdss-bam {
+ cell-id = <MSM_BUS_MASTER_QDSS_BAM>;
+ label = "mas-qhm-qdss-bam";
+ qcom,buswidth = <4>;
+ qcom,agg-ports = <1>;
+ qcom,qport = <17>;
+ qcom,connections = <&slv_qns_a2noc_snoc>;
+ qcom,bus-dev = <&fab_aggre2_noc>;
+ qcom,ap-owned;
+ qcom,prio = <0>;
+ };
+
+ mas_qhm_qup2: mas-qhm-qup2 {
+ cell-id = <MSM_BUS_MASTER_BLSP_2>;
+ label = "mas-qhm-qup2";
+ qcom,buswidth = <4>;
+ qcom,agg-ports = <1>;
+ qcom,qport = <0>;
+ qcom,connections = <&slv_qns_a2noc_snoc>;
+ qcom,bus-dev = <&fab_aggre2_noc>;
+ qcom,bcms = <&bcm_qup0>;
+ qcom,ap-owned;
+ qcom,prio = <0>;
+ };
+
+ mas_qnm_cnoc: mas-qnm-cnoc {
+ cell-id = <MSM_BUS_MASTER_CNOC_A2NOC>;
+ label = "mas-qnm-cnoc";
+ qcom,buswidth = <8>;
+ qcom,agg-ports = <1>;
+ qcom,qport = <2>;
+ qcom,connections = <&slv_qns_a2noc_snoc>;
+ qcom,bus-dev = <&fab_aggre2_noc>;
+ qcom,ap-owned;
+ qcom,prio = <1>;
+ };
+
+ mas_qxm_crypto: mas-qxm-crypto {
+ cell-id = <MSM_BUS_MASTER_CRYPTO_CORE_0>;
+ label = "mas-qxm-crypto";
+ qcom,buswidth = <8>;
+ qcom,agg-ports = <1>;
+ qcom,qport = <4>;
+ qcom,connections = <&slv_qns_a2noc_snoc>;
+ qcom,bus-dev = <&fab_aggre2_noc>;
+ qcom,bcms = <&bcm_ce0>;
+ qcom,ap-owned;
+ qcom,prio = <2>;
+ };
+
+ mas_qxm_ipa: mas-qxm-ipa {
+ cell-id = <MSM_BUS_MASTER_IPA>;
+ label = "mas-qxm-ipa";
+ qcom,buswidth = <8>;
+ qcom,agg-ports = <1>;
+ qcom,qport = <6>;
+ qcom,connections = <&slv_qns_a2noc_snoc>;
+ qcom,bus-dev = <&fab_aggre2_noc>;
+ qcom,ap-owned;
+ qcom,prio = <2>;
+ };
+
+ mas_xm_qdss_etr: mas-xm-qdss-etr {
+ cell-id = <MSM_BUS_MASTER_QDSS_ETR>;
+ label = "mas-xm-qdss-etr";
+ qcom,buswidth = <8>;
+ qcom,agg-ports = <1>;
+ qcom,qport = <16>;
+ qcom,connections = <&slv_qns_a2noc_snoc>;
+ qcom,bus-dev = <&fab_aggre2_noc>;
+ qcom,ap-owned;
+ qcom,prio = <2>;
+ };
+
+ mas_xm_usb3_0: mas-xm-usb3-0 {
+ cell-id = <MSM_BUS_MASTER_USB3>;
+ label = "mas-xm-usb3-0";
+ qcom,buswidth = <8>;
+ qcom,agg-ports = <1>;
+ qcom,qport = <22>;
+ qcom,connections = <&slv_qns_a2noc_snoc>;
+ qcom,bus-dev = <&fab_aggre2_noc>;
+ qcom,ap-owned;
+ qcom,prio = <2>;
+ };
+
+ mas_qxm_camnoc_hf0_uncomp: mas-qxm-camnoc-hf0-uncomp {
+ cell-id = <MSM_BUS_MASTER_CAMNOC_HF0_UNCOMP>;
+ label = "mas-qxm-camnoc-hf0-uncomp";
+ qcom,buswidth = <32>;
+ qcom,agg-ports = <1>;
+ qcom,connections = <&slv_qns_camnoc_uncomp>;
+ qcom,bus-dev = <&fab_camnoc_virt>;
+ qcom,bcms = <&bcm_mm1>;
+ };
+
+ mas_qxm_camnoc_hf1_uncomp: mas-qxm-camnoc-hf1-uncomp {
+ cell-id = <MSM_BUS_MASTER_CAMNOC_HF1_UNCOMP>;
+ label = "mas-qxm-camnoc-hf1-uncomp";
+ qcom,buswidth = <32>;
+ qcom,agg-ports = <1>;
+ qcom,connections = <&slv_qns_camnoc_uncomp>;
+ qcom,bus-dev = <&fab_camnoc_virt>;
+ qcom,bcms = <&bcm_mm1>;
+ };
+
+ mas_qxm_camnoc_sf_uncomp: mas-qxm-camnoc-sf-uncomp {
+ cell-id = <MSM_BUS_MASTER_CAMNOC_SF_UNCOMP>;
+ label = "mas-qxm-camnoc-sf-uncomp";
+ qcom,buswidth = <32>;
+ qcom,agg-ports = <1>;
+ qcom,connections = <&slv_qns_camnoc_uncomp>;
+ qcom,bus-dev = <&fab_camnoc_virt>;
+ qcom,bcms = <&bcm_mm1>;
+ };
+
+ mas_qhm_spdm: mas-qhm-spdm {
+ cell-id = <MSM_BUS_MASTER_SPDM>;
+ label = "mas-qhm-spdm";
+ qcom,buswidth = <4>;
+ qcom,agg-ports = <1>;
+ qcom,connections = <&slv_qns_cnoc_a2noc>;
+ qcom,bus-dev = <&fab_config_noc>;
+ qcom,bcms = <&bcm_cn0>;
+ };
+
+ mas_qhm_tic: mas-qhm-tic {
+ cell-id = <MSM_BUS_MASTER_TIC>;
+ label = "mas-qhm-tic";
+ qcom,buswidth = <4>;
+ qcom,agg-ports = <1>;
+ qcom,connections = <&slv_qhs_tlmm_south
+ &slv_qhs_camera_cfg &slv_qhs_sdc4
+ &slv_qhs_sdc2 &slv_qhs_mnoc_cfg
+ &slv_qhs_ufs_mem_cfg &slv_qhs_glm
+ &slv_qhs_pdm &slv_qhs_a2_noc_cfg
+ &slv_qhs_qdss_cfg &slv_qhs_display_cfg
+ &slv_qhs_tcsr &slv_qhs_dcc_cfg
+ &slv_qhs_ddrss_cfg &slv_qns_cnoc_a2noc
+ &slv_qhs_snoc_cfg &slv_qhs_phy_refgen_south
+ &slv_qhs_gpuss_cfg &slv_qhs_venus_cfg
+ &slv_qhs_tsif &slv_qhs_compute_dsp_cfg
+ &slv_qhs_aop &slv_qhs_qupv3_north
+ &slv_srvc_cnoc &slv_qhs_usb3_0
+ &slv_qhs_ipa &slv_qhs_cpr_cx
+ &slv_qhs_a1_noc_cfg &slv_qhs_aoss
+ &slv_qhs_prng &slv_qhs_vsense_ctrl_cfg
+ &slv_qhs_qupv3_south &slv_qhs_spdm
+ &slv_qhs_crypto0_cfg &slv_qhs_pimem_cfg
+ &slv_qhs_tlmm_north &slv_qhs_clk_ctl
+ &slv_qhs_imem_cfg>;
+ qcom,bus-dev = <&fab_config_noc>;
+ qcom,bcms = <&bcm_cn0>;
+ };
+
+ mas_qnm_snoc: mas-qnm-snoc {
+ cell-id = <MSM_BUS_SNOC_CNOC_MAS>;
+ label = "mas-qnm-snoc";
+ qcom,buswidth = <8>;
+ qcom,agg-ports = <1>;
+ qcom,connections = <&slv_qhs_tlmm_south
+ &slv_qhs_camera_cfg &slv_qhs_sdc4
+ &slv_qhs_sdc2 &slv_qhs_mnoc_cfg
+ &slv_qhs_ufs_mem_cfg &slv_qhs_glm
+ &slv_qhs_pdm &slv_qhs_a2_noc_cfg
+ &slv_qhs_qdss_cfg &slv_qhs_display_cfg
+ &slv_qhs_tcsr &slv_qhs_dcc_cfg
+ &slv_qhs_ddrss_cfg &slv_qhs_snoc_cfg
+ &slv_qhs_phy_refgen_south &slv_qhs_gpuss_cfg
+ &slv_qhs_venus_cfg &slv_qhs_tsif
+ &slv_qhs_compute_dsp_cfg &slv_qhs_aop
+ &slv_qhs_qupv3_north &slv_srvc_cnoc
+ &slv_qhs_usb3_0 &slv_qhs_ipa
+ &slv_qhs_cpr_cx &slv_qhs_a1_noc_cfg
+ &slv_qhs_aoss &slv_qhs_prng
+ &slv_qhs_vsense_ctrl_cfg &slv_qhs_qupv3_south
+ &slv_qhs_spdm &slv_qhs_crypto0_cfg
+ &slv_qhs_pimem_cfg &slv_qhs_tlmm_north
+ &slv_qhs_clk_ctl &slv_qhs_imem_cfg>;
+ qcom,bus-dev = <&fab_config_noc>;
+ qcom,bcms = <&bcm_cn0>;
+ };
+
+ mas_xm_qdss_dap: mas-xm-qdss-dap {
+ cell-id = <MSM_BUS_MASTER_QDSS_DAP>;
+ label = "mas-xm-qdss-dap";
+ qcom,buswidth = <8>;
+ qcom,agg-ports = <1>;
+ qcom,connections = <&slv_qhs_tlmm_south
+ &slv_qhs_camera_cfg
+ &slv_qhs_sdc4
+ &slv_qhs_sdc2 &slv_qhs_mnoc_cfg
+ &slv_qhs_ufs_mem_cfg &slv_qhs_glm
+ &slv_qhs_pdm &slv_qhs_a2_noc_cfg
+ &slv_qhs_qdss_cfg &slv_qhs_display_cfg
+ &slv_qhs_tcsr &slv_qhs_dcc_cfg
+ &slv_qhs_ddrss_cfg &slv_qns_cnoc_a2noc
+ &slv_qhs_snoc_cfg &slv_qhs_phy_refgen_south
+ &slv_qhs_gpuss_cfg &slv_qhs_venus_cfg
+ &slv_qhs_tsif &slv_qhs_compute_dsp_cfg
+ &slv_qhs_aop &slv_qhs_qupv3_north
+ &slv_srvc_cnoc &slv_qhs_usb3_0
+ &slv_qhs_ipa &slv_qhs_cpr_cx
+ &slv_qhs_a1_noc_cfg &slv_qhs_aoss
+ &slv_qhs_prng &slv_qhs_vsense_ctrl_cfg
+ &slv_qhs_qupv3_south &slv_qhs_spdm
+ &slv_qhs_crypto0_cfg &slv_qhs_pimem_cfg
+ &slv_qhs_tlmm_north &slv_qhs_clk_ctl
+ &slv_qhs_imem_cfg>;
+ qcom,bus-dev = <&fab_config_noc>;
+ qcom,bcms = <&bcm_cn0>;
+ };
+
+ mas_qhm_cnoc: mas-qhm-cnoc {
+ cell-id = <MSM_BUS_MASTER_CNOC_DC_NOC>;
+ label = "mas-qhm-cnoc";
+ qcom,buswidth = <4>;
+ qcom,agg-ports = <1>;
+ qcom,connections = <&slv_qhs_memnoc &slv_qhs_llcc>;
+ qcom,bus-dev = <&fab_dc_noc>;
+ };
+
+ mas_acm_l3: mas-acm-l3 {
+ cell-id = <MSM_BUS_MASTER_AMPSS_M0>;
+ label = "mas-acm-l3";
+ qcom,buswidth = <16>;
+ qcom,agg-ports = <1>;
+ qcom,connections = <&slv_srvc_gnoc
+ &slv_qns_gladiator_sodv &slv_qns_gnoc_memnoc>;
+ qcom,bus-dev = <&fab_gladiator_noc>;
+ };
+
+ mas_pm_gnoc_cfg: mas-pm-gnoc-cfg {
+ cell-id = <MSM_BUS_MASTER_GNOC_CFG>;
+ label = "mas-pm-gnoc-cfg";
+ qcom,buswidth = <4>;
+ qcom,agg-ports = <1>;
+ qcom,connections = <&slv_srvc_gnoc>;
+ qcom,bus-dev = <&fab_gladiator_noc>;
+ };
+
+ mas_ipa_core_master: mas-ipa-core-master {
+ cell-id = <MSM_BUS_MASTER_IPA_CORE>;
+ label = "mas-ipa-core-master";
+ qcom,buswidth = <8>;
+ qcom,agg-ports = <1>;
+ qcom,connections = <&slv_ipa_core_slave>;
+ qcom,bus-dev = <&fab_ipa_virt>;
+ };
+
+ mas_llcc_mc: mas-llcc-mc {
+ cell-id = <MSM_BUS_MASTER_LLCC>;
+ label = "mas-llcc-mc";
+ qcom,buswidth = <4>;
+ qcom,agg-ports = <2>;
+ qcom,connections = <&slv_ebi>;
+ qcom,bus-dev = <&fab_mc_virt>;
+ };
+
+ mas_acm_tcu: mas-acm-tcu {
+ cell-id = <MSM_BUS_MASTER_TCU_0>;
+ label = "mas-acm-tcu";
+ qcom,buswidth = <8>;
+ qcom,agg-ports = <1>;
+ qcom,qport = <0>;
+ qcom,connections = <&slv_qns_apps_io &slv_qns_llcc
+ &slv_qns_memnoc_snoc>;
+ qcom,bus-dev = <&fab_mem_noc>;
+ qcom,bcms = <&bcm_sh3>;
+ qcom,ap-owned;
+ qcom,prio = <6>;
+ };
+
+ mas_qhm_memnoc_cfg: mas-qhm-memnoc-cfg {
+ cell-id = <MSM_BUS_MASTER_MEM_NOC_CFG>;
+ label = "mas-qhm-memnoc-cfg";
+ qcom,buswidth = <4>;
+ qcom,agg-ports = <1>;
+ qcom,connections = <&slv_srvc_memnoc
+ &slv_qhs_mdsp_ms_mpu_cfg>;
+ qcom,bus-dev = <&fab_mem_noc>;
+ };
+
+ mas_qnm_apps: mas-qnm-apps {
+ cell-id = <MSM_BUS_MASTER_GNOC_MEM_NOC>;
+ label = "mas-qnm-apps";
+ qcom,buswidth = <32>;
+ qcom,agg-ports = <2>;
+ qcom,qport = <2 3>;
+ qcom,connections = <&slv_qns_llcc>;
+ qcom,bus-dev = <&fab_mem_noc>;
+ qcom,bcms = <&bcm_sh5>;
+ qcom,ap-owned;
+ qcom,prio = <0>;
+ };
+
+ mas_qnm_mnoc_hf: mas-qnm-mnoc-hf {
+ cell-id = <MSM_BUS_MASTER_MNOC_HF_MEM_NOC>;
+ label = "mas-qnm-mnoc-hf";
+ qcom,buswidth = <32>;
+ qcom,agg-ports = <2>;
+ qcom,qport = <4 5>;
+ qcom,connections = <&slv_qns_llcc>;
+ qcom,bus-dev = <&fab_mem_noc>;
+ qcom,ap-owned;
+ qcom,prio = <0>;
+ qcom,forwarding;
+ };
+
+ mas_qnm_mnoc_sf: mas-qnm-mnoc-sf {
+ cell-id = <MSM_BUS_MASTER_MNOC_SF_MEM_NOC>;
+ label = "mas-qnm-mnoc-sf";
+ qcom,buswidth = <32>;
+ qcom,agg-ports = <1>;
+ qcom,qport = <7>;
+ qcom,connections = <&slv_qns_apps_io
+ &slv_qns_llcc &slv_qns_memnoc_snoc>;
+ qcom,bus-dev = <&fab_mem_noc>;
+ qcom,ap-owned;
+ qcom,prio = <0>;
+ qcom,forwarding;
+ };
+
+ mas_qnm_snoc_gc: mas-qnm-snoc-gc {
+ cell-id = <MSM_BUS_MASTER_SNOC_GC_MEM_NOC>;
+ label = "mas-qnm-snoc-gc";
+ qcom,buswidth = <8>;
+ qcom,agg-ports = <1>;
+ qcom,qport = <8>;
+ qcom,connections = <&slv_qns_llcc>;
+ qcom,bus-dev = <&fab_mem_noc>;
+ qcom,ap-owned;
+ qcom,prio = <0>;
+ qcom,forwarding;
+ };
+
+ mas_qnm_snoc_sf: mas-qnm-snoc-sf {
+ cell-id = <MSM_BUS_MASTER_SNOC_SF_MEM_NOC>;
+ label = "mas-qnm-snoc-sf";
+ qcom,buswidth = <16>;
+ qcom,agg-ports = <1>;
+ qcom,qport = <9>;
+ qcom,connections = <&slv_qns_apps_io &slv_qns_llcc>;
+ qcom,bus-dev = <&fab_mem_noc>;
+ qcom,ap-owned;
+ qcom,prio = <0>;
+ qcom,forwarding;
+ };
+
+ mas_qxm_gpu: mas-qxm-gpu {
+ cell-id = <MSM_BUS_MASTER_GRAPHICS_3D>;
+ label = "mas-qxm-gpu";
+ qcom,buswidth = <32>;
+ qcom,agg-ports = <2>;
+ qcom,qport = <10 11>;
+ qcom,connections = <&slv_qns_apps_io
+ &slv_qns_llcc &slv_qns_memnoc_snoc>;
+ qcom,bus-dev = <&fab_mem_noc>;
+ qcom,ap-owned;
+ qcom,prio = <0>;
+ };
+
+ mas_qhm_mnoc_cfg: mas-qhm-mnoc-cfg {
+ cell-id = <MSM_BUS_MASTER_CNOC_MNOC_CFG>;
+ label = "mas-qhm-mnoc-cfg";
+ qcom,buswidth = <4>;
+ qcom,agg-ports = <1>;
+ qcom,connections = <&slv_srvc_mnoc>;
+ qcom,bus-dev = <&fab_mmss_noc>;
+ };
+
+ mas_qxm_camnoc_hf0: mas-qxm-camnoc-hf0 {
+ cell-id = <MSM_BUS_MASTER_CAMNOC_HF0>;
+ label = "mas-qxm-camnoc-hf0";
+ qcom,buswidth = <32>;
+ qcom,agg-ports = <1>;
+ qcom,qport = <1>;
+ qcom,connections = <&slv_qns_mem_noc_hf>;
+ qcom,bus-dev = <&fab_mmss_noc>;
+ qcom,bcms = <&bcm_mm1>;
+ qcom,ap-owned;
+ qcom,prio = <0>;
+ qcom,forwarding;
+ };
+
+ mas_qxm_camnoc_hf1: mas-qxm-camnoc-hf1 {
+ cell-id = <MSM_BUS_MASTER_CAMNOC_HF1>;
+ label = "mas-qxm-camnoc-hf1";
+ qcom,buswidth = <32>;
+ qcom,agg-ports = <1>;
+ qcom,qport = <2>;
+ qcom,connections = <&slv_qns_mem_noc_hf>;
+ qcom,bus-dev = <&fab_mmss_noc>;
+ qcom,bcms = <&bcm_mm1>;
+ qcom,ap-owned;
+ qcom,prio = <0>;
+ qcom,forwarding;
+ };
+
+ mas_qxm_camnoc_sf: mas-qxm-camnoc-sf {
+ cell-id = <MSM_BUS_MASTER_CAMNOC_SF>;
+ label = "mas-qxm-camnoc-sf";
+ qcom,buswidth = <32>;
+ qcom,agg-ports = <1>;
+ qcom,qport = <0>;
+ qcom,connections = <&slv_qns2_mem_noc>;
+ qcom,bus-dev = <&fab_mmss_noc>;
+ qcom,bcms = <&bcm_mm3>;
+ qcom,ap-owned;
+ qcom,prio = <0>;
+ qcom,forwarding;
+ };
+
+ mas_qxm_mdp0: mas-qxm-mdp0 {
+ cell-id = <MSM_BUS_MASTER_MDP_PORT0>;
+ label = "mas-qxm-mdp0";
+ qcom,buswidth = <32>;
+ qcom,agg-ports = <1>;
+ qcom,qport = <3>;
+ qcom,connections = <&slv_qns_mem_noc_hf>;
+ qcom,bus-dev = <&fab_mmss_noc>;
+ qcom,bcms = <&bcm_mm1>;
+ qcom,ap-owned;
+ qcom,prio = <0>;
+ qcom,forwarding;
+ };
+
+ mas_qxm_mdp1: mas-qxm-mdp1 {
+ cell-id = <MSM_BUS_MASTER_MDP_PORT1>;
+ label = "mas-qxm-mdp1";
+ qcom,buswidth = <32>;
+ qcom,agg-ports = <1>;
+ qcom,qport = <4>;
+ qcom,connections = <&slv_qns_mem_noc_hf>;
+ qcom,bus-dev = <&fab_mmss_noc>;
+ qcom,bcms = <&bcm_mm1>;
+ qcom,ap-owned;
+ qcom,prio = <0>;
+ qcom,forwarding;
+ };
+
+ mas_qxm_rot: mas-qxm-rot {
+ cell-id = <MSM_BUS_MASTER_ROTATOR>;
+ label = "mas-qxm-rot";
+ qcom,buswidth = <32>;
+ qcom,agg-ports = <1>;
+ qcom,qport = <5>;
+ qcom,connections = <&slv_qns2_mem_noc>;
+ qcom,bus-dev = <&fab_mmss_noc>;
+ qcom,bcms = <&bcm_mm3>;
+ qcom,ap-owned;
+ qcom,prio = <0>;
+ qcom,forwarding;
+ };
+
+ mas_qxm_venus0: mas-qxm-venus0 {
+ cell-id = <MSM_BUS_MASTER_VIDEO_P0>;
+ label = "mas-qxm-venus0";
+ qcom,buswidth = <32>;
+ qcom,agg-ports = <1>;
+ qcom,qport = <6>;
+ qcom,connections = <&slv_qns2_mem_noc>;
+ qcom,bus-dev = <&fab_mmss_noc>;
+ qcom,bcms = <&bcm_mm3>;
+ qcom,ap-owned;
+ qcom,prio = <0>;
+ qcom,forwarding;
+ };
+
+ mas_qxm_venus1: mas-qxm-venus1 {
+ cell-id = <MSM_BUS_MASTER_VIDEO_P1>;
+ label = "mas-qxm-venus1";
+ qcom,buswidth = <32>;
+ qcom,agg-ports = <1>;
+ qcom,qport = <7>;
+ qcom,connections = <&slv_qns2_mem_noc>;
+ qcom,bus-dev = <&fab_mmss_noc>;
+ qcom,bcms = <&bcm_mm3>;
+ qcom,ap-owned;
+ qcom,prio = <0>;
+ qcom,forwarding;
+ };
+
+ mas_qxm_venus_arm9: mas-qxm-venus-arm9 {
+ cell-id = <MSM_BUS_MASTER_VIDEO_PROC>;
+ label = "mas-qxm-venus-arm9";
+ qcom,buswidth = <8>;
+ qcom,agg-ports = <1>;
+ qcom,qport = <8>;
+ qcom,connections = <&slv_qns2_mem_noc>;
+ qcom,bus-dev = <&fab_mmss_noc>;
+ qcom,bcms = <&bcm_mm3>;
+ qcom,ap-owned;
+ qcom,prio = <0>;
+ qcom,forwarding;
+ };
+
+ mas_qhm_snoc_cfg: mas-qhm-snoc-cfg {
+ cell-id = <MSM_BUS_MASTER_SNOC_CFG>;
+ label = "mas-qhm-snoc-cfg";
+ qcom,buswidth = <4>;
+ qcom,agg-ports = <1>;
+ qcom,connections = <&slv_srvc_snoc>;
+ qcom,bus-dev = <&fab_system_noc>;
+ };
+
+ mas_qnm_aggre1_noc: mas-qnm-aggre1-noc {
+ cell-id = <MSM_BUS_A1NOC_SNOC_MAS>;
+ label = "mas-qnm-aggre1-noc";
+ qcom,buswidth = <16>;
+ qcom,agg-ports = <1>;
+ qcom,connections = <&slv_qxs_pimem
+ &slv_qns_memnoc_sf &slv_qxs_imem
+ &slv_qhs_apss &slv_qns_cnoc
+ &slv_xs_qdss_stm>;
+ qcom,bus-dev = <&fab_system_noc>;
+ qcom,bcms = <&bcm_sn8>;
+ };
+
+ mas_qnm_aggre2_noc: mas-qnm-aggre2-noc {
+ cell-id = <MSM_BUS_A2NOC_SNOC_MAS>;
+ label = "mas-qnm-aggre2-noc";
+ qcom,buswidth = <16>;
+ qcom,agg-ports = <1>;
+ qcom,connections = <&slv_qxs_pimem
+ &slv_qns_memnoc_sf &slv_qxs_imem
+ &slv_qhs_apss &slv_qns_cnoc
+ &slv_xs_sys_tcu_cfg &slv_xs_qdss_stm>;
+ qcom,bus-dev = <&fab_system_noc>;
+ qcom,bcms = <&bcm_sn10>;
+ };
+
+ mas_qnm_gladiator_sodv: mas-qnm-gladiator-sodv {
+ cell-id = <MSM_BUS_MASTER_GNOC_SNOC>;
+ label = "mas-qnm-gladiator-sodv";
+ qcom,buswidth = <8>;
+ qcom,agg-ports = <1>;
+ qcom,connections = <&slv_qxs_pimem
+ &slv_qxs_imem &slv_qhs_apss
+ &slv_qns_cnoc &slv_xs_sys_tcu_cfg
+ &slv_xs_qdss_stm>;
+ qcom,bus-dev = <&fab_system_noc>;
+ qcom,bcms = <&bcm_sn11>;
+ };
+
+ mas_qnm_memnoc: mas-qnm-memnoc {
+ cell-id = <MSM_BUS_MASTER_MEM_NOC_SNOC>;
+ label = "mas-qnm-memnoc";
+ qcom,buswidth = <8>;
+ qcom,agg-ports = <1>;
+ qcom,connections = <&slv_qxs_imem
+ &slv_qhs_apss &slv_qxs_pimem
+ &slv_qns_cnoc &slv_xs_qdss_stm>;
+ qcom,bus-dev = <&fab_system_noc>;
+ qcom,bcms = <&bcm_sn13>;
+ };
+
+ mas_qxm_pimem: mas-qxm-pimem {
+ cell-id = <MSM_BUS_MASTER_PIMEM>;
+ label = "mas-qxm-pimem";
+ qcom,buswidth = <8>;
+ qcom,agg-ports = <1>;
+ qcom,qport = <3>;
+ qcom,connections = <&slv_qxs_imem &slv_qns_memnoc_gc>;
+ qcom,bus-dev = <&fab_system_noc>;
+ qcom,bcms = <&bcm_sn4>;
+ qcom,ap-owned;
+ qcom,prio = <2>;
+ };
+
+ mas_xm_gic: mas-xm-gic {
+ cell-id = <MSM_BUS_MASTER_GIC>;
+ label = "mas-xm-gic";
+ qcom,buswidth = <8>;
+ qcom,agg-ports = <1>;
+ qcom,qport = <0>;
+ qcom,connections = <&slv_qxs_imem &slv_qns_memnoc_gc>;
+ qcom,bus-dev = <&fab_system_noc>;
+ qcom,bcms = <&bcm_sn11>;
+ qcom,ap-owned;
+ qcom,prio = <1>;
+ };
+
+ mas_alc: mas-alc {
+ cell-id = <MSM_BUS_MASTER_ALC>;
+ label = "mas-alc";
+ qcom,buswidth = <1>;
+ qcom,agg-ports = <1>;
+ qcom,bus-dev = <&fab_mc_virt>;
+ qcom,bcms = <&bcm_alc>;
+ };
+
+ mas_llcc_mc_display: mas-llcc-mc_display {
+ cell-id = <MSM_BUS_MASTER_LLCC_DISPLAY>;
+ label = "mas-llcc-mc_display";
+ qcom,buswidth = <4>;
+ qcom,agg-ports = <2>;
+ qcom,connections = <&slv_ebi_display>;
+ qcom,bus-dev = <&fab_mc_virt_display>;
+ };
+
+ mas_qnm_mnoc_hf_display: mas-qnm-mnoc-hf_display {
+ cell-id = <MSM_BUS_MASTER_MNOC_HF_MEM_NOC_DISPLAY>;
+ label = "mas-qnm-mnoc-hf_display";
+ qcom,buswidth = <32>;
+ qcom,agg-ports = <2>;
+ qcom,qport = <4 5>;
+ qcom,connections = <&slv_qns_llcc_display>;
+ qcom,bus-dev = <&fab_mem_noc_display>;
+ };
+
+ mas_qnm_mnoc_sf_display: mas-qnm-mnoc-sf_display {
+ cell-id = <MSM_BUS_MASTER_MNOC_SF_MEM_NOC_DISPLAY>;
+ label = "mas-qnm-mnoc-sf_display";
+ qcom,buswidth = <32>;
+ qcom,agg-ports = <1>;
+ qcom,qport = <7>;
+ qcom,connections = <&slv_qns_llcc_display>;
+ qcom,bus-dev = <&fab_mem_noc_display>;
+ };
+
+ mas_qxm_mdp0_display: mas-qxm-mdp0_display {
+ cell-id = <MSM_BUS_MASTER_MDP_PORT0_DISPLAY>;
+ label = "mas-qxm-mdp0_display";
+ qcom,buswidth = <32>;
+ qcom,agg-ports = <1>;
+ qcom,qport = <3>;
+ qcom,connections = <&slv_qns_mem_noc_hf_display>;
+ qcom,bus-dev = <&fab_mmss_noc_display>;
+ qcom,bcms = <&bcm_mm1_display>;
+ };
+
+ mas_qxm_mdp1_display: mas-qxm-mdp1_display {
+ cell-id = <MSM_BUS_MASTER_MDP_PORT1_DISPLAY>;
+ label = "mas-qxm-mdp1_display";
+ qcom,buswidth = <32>;
+ qcom,agg-ports = <1>;
+ qcom,qport = <4>;
+ qcom,connections = <&slv_qns_mem_noc_hf_display>;
+ qcom,bus-dev = <&fab_mmss_noc_display>;
+ qcom,bcms = <&bcm_mm1_display>;
+ };
+
+ mas_qxm_rot_display: mas-qxm-rot_display {
+ cell-id = <MSM_BUS_MASTER_ROTATOR_DISPLAY>;
+ label = "mas-qxm-rot_display";
+ qcom,buswidth = <32>;
+ qcom,agg-ports = <1>;
+ qcom,qport = <5>;
+ qcom,connections = <&slv_qns2_mem_noc_display>;
+ qcom,bus-dev = <&fab_mmss_noc_display>;
+ qcom,bcms = <&bcm_mm3_display>;
+ };
+
+ /*Internal nodes*/
+
+ /*Slaves*/
+
+ slv_qns_a1noc_snoc:slv-qns-a1noc-snoc {
+ cell-id = <MSM_BUS_A1NOC_SNOC_SLV>;
+ label = "slv-qns-a1noc-snoc";
+ qcom,buswidth = <16>;
+ qcom,agg-ports = <1>;
+ qcom,bus-dev = <&fab_aggre1_noc>;
+ qcom,connections = <&mas_qnm_aggre1_noc>;
+ };
+
+ slv_srvc_aggre1_noc:slv-srvc-aggre1-noc {
+ cell-id = <MSM_BUS_SLAVE_SERVICE_A1NOC>;
+ label = "slv-srvc-aggre1-noc";
+ qcom,buswidth = <4>;
+ qcom,agg-ports = <1>;
+ qcom,bus-dev = <&fab_aggre1_noc>;
+ qcom,bcms = <&bcm_sn8>;
+ };
+
+ slv_qns_a2noc_snoc:slv-qns-a2noc-snoc {
+ cell-id = <MSM_BUS_A2NOC_SNOC_SLV>;
+ label = "slv-qns-a2noc-snoc";
+ qcom,buswidth = <16>;
+ qcom,agg-ports = <1>;
+ qcom,bus-dev = <&fab_aggre2_noc>;
+ qcom,connections = <&mas_qnm_aggre2_noc>;
+ };
+
+ slv_srvc_aggre2_noc:slv-srvc-aggre2-noc {
+ cell-id = <MSM_BUS_SLAVE_SERVICE_A2NOC>;
+ label = "slv-srvc-aggre2-noc";
+ qcom,buswidth = <4>;
+ qcom,agg-ports = <1>;
+ qcom,bus-dev = <&fab_aggre2_noc>;
+ qcom,bcms = <&bcm_sn10>;
+ };
+
+ slv_qns_camnoc_uncomp:slv-qns-camnoc-uncomp {
+ cell-id = <MSM_BUS_SLAVE_CAMNOC_UNCOMP>;
+ label = "slv-qns-camnoc-uncomp";
+ qcom,buswidth = <32>;
+ qcom,agg-ports = <1>;
+ qcom,bus-dev = <&fab_camnoc_virt>;
+ };
+
+ slv_qhs_a1_noc_cfg:slv-qhs-a1-noc-cfg {
+ cell-id = <MSM_BUS_SLAVE_A1NOC_CFG>;
+ label = "slv-qhs-a1-noc-cfg";
+ qcom,buswidth = <4>;
+ qcom,agg-ports = <1>;
+ qcom,bus-dev = <&fab_config_noc>;
+ qcom,connections = <&mas_qhm_a1noc_cfg>;
+ qcom,bcms = <&bcm_cn0>;
+ };
+
+ slv_qhs_a2_noc_cfg:slv-qhs-a2-noc-cfg {
+ cell-id = <MSM_BUS_SLAVE_A2NOC_CFG>;
+ label = "slv-qhs-a2-noc-cfg";
+ qcom,buswidth = <4>;
+ qcom,agg-ports = <1>;
+ qcom,bus-dev = <&fab_config_noc>;
+ qcom,connections = <&mas_qhm_a2noc_cfg>;
+ qcom,bcms = <&bcm_cn0>;
+ };
+
+ slv_qhs_aop:slv-qhs-aop {
+ cell-id = <MSM_BUS_SLAVE_AOP>;
+ label = "slv-qhs-aop";
+ qcom,buswidth = <4>;
+ qcom,agg-ports = <1>;
+ qcom,bus-dev = <&fab_config_noc>;
+ qcom,bcms = <&bcm_cn0>;
+ };
+
+ slv_qhs_aoss:slv-qhs-aoss {
+ cell-id = <MSM_BUS_SLAVE_AOSS>;
+ label = "slv-qhs-aoss";
+ qcom,buswidth = <4>;
+ qcom,agg-ports = <1>;
+ qcom,bus-dev = <&fab_config_noc>;
+ qcom,bcms = <&bcm_cn0>;
+ };
+
+ slv_qhs_camera_cfg:slv-qhs-camera-cfg {
+ cell-id = <MSM_BUS_SLAVE_CAMERA_CFG>;
+ label = "slv-qhs-camera-cfg";
+ qcom,buswidth = <4>;
+ qcom,agg-ports = <1>;
+ qcom,bus-dev = <&fab_config_noc>;
+ qcom,bcms = <&bcm_cn0>;
+ };
+
+ slv_qhs_clk_ctl:slv-qhs-clk-ctl {
+ cell-id = <MSM_BUS_SLAVE_CLK_CTL>;
+ label = "slv-qhs-clk-ctl";
+ qcom,buswidth = <4>;
+ qcom,agg-ports = <1>;
+ qcom,bus-dev = <&fab_config_noc>;
+ qcom,bcms = <&bcm_cn0>;
+ };
+
+ slv_qhs_compute_dsp_cfg:slv-qhs-compute-dsp-cfg {
+ cell-id = <MSM_BUS_SLAVE_CDSP_CFG>;
+ label = "slv-qhs-compute-dsp-cfg";
+ qcom,buswidth = <4>;
+ qcom,agg-ports = <1>;
+ qcom,bus-dev = <&fab_config_noc>;
+ qcom,bcms = <&bcm_cn0>;
+ };
+
+ slv_qhs_cpr_cx:slv-qhs-cpr-cx {
+ cell-id = <MSM_BUS_SLAVE_RBCPR_CX_CFG>;
+ label = "slv-qhs-cpr-cx";
+ qcom,buswidth = <4>;
+ qcom,agg-ports = <1>;
+ qcom,bus-dev = <&fab_config_noc>;
+ qcom,bcms = <&bcm_cn0>;
+ };
+
+ slv_qhs_crypto0_cfg:slv-qhs-crypto0-cfg {
+ cell-id = <MSM_BUS_SLAVE_CRYPTO_0_CFG>;
+ label = "slv-qhs-crypto0-cfg";
+ qcom,buswidth = <4>;
+ qcom,agg-ports = <1>;
+ qcom,bus-dev = <&fab_config_noc>;
+ qcom,bcms = <&bcm_cn0>;
+ };
+
+ slv_qhs_dcc_cfg:slv-qhs-dcc-cfg {
+ cell-id = <MSM_BUS_SLAVE_DCC_CFG>;
+ label = "slv-qhs-dcc-cfg";
+ qcom,buswidth = <4>;
+ qcom,agg-ports = <1>;
+ qcom,bus-dev = <&fab_config_noc>;
+ qcom,connections = <&mas_qhm_cnoc>;
+ qcom,bcms = <&bcm_cn0>;
+ };
+
+ slv_qhs_ddrss_cfg:slv-qhs-ddrss-cfg {
+ cell-id = <MSM_BUS_SLAVE_CNOC_DDRSS>;
+ label = "slv-qhs-ddrss-cfg";
+ qcom,buswidth = <4>;
+ qcom,agg-ports = <1>;
+ qcom,bus-dev = <&fab_config_noc>;
+ qcom,bcms = <&bcm_cn0>;
+ };
+
+ slv_qhs_display_cfg:slv-qhs-display-cfg {
+ cell-id = <MSM_BUS_SLAVE_DISPLAY_CFG>;
+ label = "slv-qhs-display-cfg";
+ qcom,buswidth = <4>;
+ qcom,agg-ports = <1>;
+ qcom,bus-dev = <&fab_config_noc>;
+ qcom,bcms = <&bcm_cn0>;
+ };
+
+ slv_qhs_glm:slv-qhs-glm {
+ cell-id = <MSM_BUS_SLAVE_GLM>;
+ label = "slv-qhs-glm";
+ qcom,buswidth = <4>;
+ qcom,agg-ports = <1>;
+ qcom,bus-dev = <&fab_config_noc>;
+ qcom,bcms = <&bcm_cn0>;
+ };
+
+ slv_qhs_gpuss_cfg:slv-qhs-gpuss-cfg {
+ cell-id = <MSM_BUS_SLAVE_GRAPHICS_3D_CFG>;
+ label = "slv-qhs-gpuss-cfg";
+ qcom,buswidth = <8>;
+ qcom,agg-ports = <1>;
+ qcom,bus-dev = <&fab_config_noc>;
+ qcom,bcms = <&bcm_cn0>;
+ };
+
+ slv_qhs_imem_cfg:slv-qhs-imem-cfg {
+ cell-id = <MSM_BUS_SLAVE_IMEM_CFG>;
+ label = "slv-qhs-imem-cfg";
+ qcom,buswidth = <4>;
+ qcom,agg-ports = <1>;
+ qcom,bus-dev = <&fab_config_noc>;
+ qcom,bcms = <&bcm_cn0>;
+ };
+
+ slv_qhs_ipa:slv-qhs-ipa {
+ cell-id = <MSM_BUS_SLAVE_IPA_CFG>;
+ label = "slv-qhs-ipa";
+ qcom,buswidth = <4>;
+ qcom,agg-ports = <1>;
+ qcom,bus-dev = <&fab_config_noc>;
+ qcom,bcms = <&bcm_cn0>;
+ };
+
+ slv_qhs_mnoc_cfg:slv-qhs-mnoc-cfg {
+ cell-id = <MSM_BUS_SLAVE_CNOC_MNOC_CFG>;
+ label = "slv-qhs-mnoc-cfg";
+ qcom,buswidth = <4>;
+ qcom,agg-ports = <1>;
+ qcom,bus-dev = <&fab_config_noc>;
+ qcom,connections = <&mas_qhm_mnoc_cfg>;
+ qcom,bcms = <&bcm_cn0>;
+ };
+
+ slv_qhs_pdm:slv-qhs-pdm {
+ cell-id = <MSM_BUS_SLAVE_PDM>;
+ label = "slv-qhs-pdm";
+ qcom,buswidth = <4>;
+ qcom,agg-ports = <1>;
+ qcom,bus-dev = <&fab_config_noc>;
+ qcom,bcms = <&bcm_cn0>;
+ };
+
+ slv_qhs_phy_refgen_south:slv-qhs-phy-refgen-south {
+ cell-id = <MSM_BUS_SLAVE_SOUTH_PHY_CFG>;
+ label = "slv-qhs-phy-refgen-south";
+ qcom,buswidth = <4>;
+ qcom,agg-ports = <1>;
+ qcom,bus-dev = <&fab_config_noc>;
+ qcom,bcms = <&bcm_cn0>;
+ };
+
+ slv_qhs_pimem_cfg:slv-qhs-pimem-cfg {
+ cell-id = <MSM_BUS_SLAVE_PIMEM_CFG>;
+ label = "slv-qhs-pimem-cfg";
+ qcom,buswidth = <4>;
+ qcom,agg-ports = <1>;
+ qcom,bus-dev = <&fab_config_noc>;
+ qcom,bcms = <&bcm_cn0>;
+ };
+
+ slv_qhs_prng:slv-qhs-prng {
+ cell-id = <MSM_BUS_SLAVE_PRNG>;
+ label = "slv-qhs-prng";
+ qcom,buswidth = <4>;
+ qcom,agg-ports = <1>;
+ qcom,bus-dev = <&fab_config_noc>;
+ qcom,bcms = <&bcm_cn0>;
+ };
+
+ slv_qhs_qdss_cfg:slv-qhs-qdss-cfg {
+ cell-id = <MSM_BUS_SLAVE_QDSS_CFG>;
+ label = "slv-qhs-qdss-cfg";
+ qcom,buswidth = <4>;
+ qcom,agg-ports = <1>;
+ qcom,bus-dev = <&fab_config_noc>;
+ qcom,bcms = <&bcm_cn0>;
+ };
+
+ slv_qhs_qupv3_north:slv-qhs-qupv3-north {
+ cell-id = <MSM_BUS_SLAVE_BLSP_2>;
+ label = "slv-qhs-qupv3-north";
+ qcom,buswidth = <4>;
+ qcom,agg-ports = <1>;
+ qcom,bus-dev = <&fab_config_noc>;
+ qcom,bcms = <&bcm_cn0>;
+ };
+
+ slv_qhs_qupv3_south:slv-qhs-qupv3-south {
+ cell-id = <MSM_BUS_SLAVE_BLSP_1>;
+ label = "slv-qhs-qupv3-south";
+ qcom,buswidth = <4>;
+ qcom,agg-ports = <1>;
+ qcom,bus-dev = <&fab_config_noc>;
+ qcom,bcms = <&bcm_cn0>;
+ };
+
+ slv_qhs_sdc2:slv-qhs-sdc2 {
+ cell-id = <MSM_BUS_SLAVE_SDCC_2>;
+ label = "slv-qhs-sdc2";
+ qcom,buswidth = <4>;
+ qcom,agg-ports = <1>;
+ qcom,bus-dev = <&fab_config_noc>;
+ qcom,bcms = <&bcm_cn0>;
+ };
+
+ slv_qhs_sdc4:slv-qhs-sdc4 {
+ cell-id = <MSM_BUS_SLAVE_SDCC_4>;
+ label = "slv-qhs-sdc4";
+ qcom,buswidth = <4>;
+ qcom,agg-ports = <1>;
+ qcom,bus-dev = <&fab_config_noc>;
+ qcom,bcms = <&bcm_cn0>;
+ };
+
+ slv_qhs_snoc_cfg:slv-qhs-snoc-cfg {
+ cell-id = <MSM_BUS_SLAVE_SNOC_CFG>;
+ label = "slv-qhs-snoc-cfg";
+ qcom,buswidth = <4>;
+ qcom,agg-ports = <1>;
+ qcom,bus-dev = <&fab_config_noc>;
+ qcom,connections = <&mas_qhm_snoc_cfg>;
+ qcom,bcms = <&bcm_cn0>;
+ };
+
+ slv_qhs_spdm:slv-qhs-spdm {
+ cell-id = <MSM_BUS_SLAVE_SPDM_WRAPPER>;
+ label = "slv-qhs-spdm";
+ qcom,buswidth = <4>;
+ qcom,agg-ports = <1>;
+ qcom,bus-dev = <&fab_config_noc>;
+ qcom,bcms = <&bcm_cn0>;
+ };
+
+ slv_qhs_tcsr:slv-qhs-tcsr {
+ cell-id = <MSM_BUS_SLAVE_TCSR>;
+ label = "slv-qhs-tcsr";
+ qcom,buswidth = <4>;
+ qcom,agg-ports = <1>;
+ qcom,bus-dev = <&fab_config_noc>;
+ qcom,bcms = <&bcm_cn0>;
+ };
+
+ slv_qhs_tlmm_north:slv-qhs-tlmm-north {
+ cell-id = <MSM_BUS_SLAVE_TLMM_NORTH>;
+ label = "slv-qhs-tlmm-north";
+ qcom,buswidth = <4>;
+ qcom,agg-ports = <1>;
+ qcom,bus-dev = <&fab_config_noc>;
+ qcom,bcms = <&bcm_cn0>;
+ };
+
+ slv_qhs_tlmm_south:slv-qhs-tlmm-south {
+ cell-id = <MSM_BUS_SLAVE_TLMM_SOUTH>;
+ label = "slv-qhs-tlmm-south";
+ qcom,buswidth = <4>;
+ qcom,agg-ports = <1>;
+ qcom,bus-dev = <&fab_config_noc>;
+ qcom,bcms = <&bcm_cn0>;
+ };
+
+ slv_qhs_tsif:slv-qhs-tsif {
+ cell-id = <MSM_BUS_SLAVE_TSIF>;
+ label = "slv-qhs-tsif";
+ qcom,buswidth = <4>;
+ qcom,agg-ports = <1>;
+ qcom,bus-dev = <&fab_config_noc>;
+ qcom,bcms = <&bcm_cn0>;
+ };
+
+ slv_qhs_ufs_mem_cfg:slv-qhs-ufs-mem-cfg {
+ cell-id = <MSM_BUS_SLAVE_UFS_MEM_CFG>;
+ label = "slv-qhs-ufs-mem-cfg";
+ qcom,buswidth = <4>;
+ qcom,agg-ports = <1>;
+ qcom,bus-dev = <&fab_config_noc>;
+ qcom,bcms = <&bcm_cn0>;
+ };
+
+ slv_qhs_usb3_0:slv-qhs-usb3-0 {
+ cell-id = <MSM_BUS_SLAVE_USB3>;
+ label = "slv-qhs-usb3-0";
+ qcom,buswidth = <4>;
+ qcom,agg-ports = <1>;
+ qcom,bus-dev = <&fab_config_noc>;
+ qcom,bcms = <&bcm_cn0>;
+ };
+
+ slv_qhs_venus_cfg:slv-qhs-venus-cfg {
+ cell-id = <MSM_BUS_SLAVE_VENUS_CFG>;
+ label = "slv-qhs-venus-cfg";
+ qcom,buswidth = <4>;
+ qcom,agg-ports = <1>;
+ qcom,bus-dev = <&fab_config_noc>;
+ qcom,bcms = <&bcm_cn0>;
+ };
+
+ slv_qhs_vsense_ctrl_cfg:slv-qhs-vsense-ctrl-cfg {
+ cell-id = <MSM_BUS_SLAVE_VSENSE_CTRL_CFG>;
+ label = "slv-qhs-vsense-ctrl-cfg";
+ qcom,buswidth = <4>;
+ qcom,agg-ports = <1>;
+ qcom,bus-dev = <&fab_config_noc>;
+ qcom,bcms = <&bcm_cn0>;
+ };
+
+ slv_qns_cnoc_a2noc:slv-qns-cnoc-a2noc {
+ cell-id = <MSM_BUS_SLAVE_CNOC_A2NOC>;
+ label = "slv-qns-cnoc-a2noc";
+ qcom,buswidth = <8>;
+ qcom,agg-ports = <1>;
+ qcom,bus-dev = <&fab_config_noc>;
+ qcom,connections = <&mas_qnm_cnoc>;
+ qcom,bcms = <&bcm_cn0>;
+ };
+
+ slv_srvc_cnoc:slv-srvc-cnoc {
+ cell-id = <MSM_BUS_SLAVE_SERVICE_CNOC>;
+ label = "slv-srvc-cnoc";
+ qcom,buswidth = <4>;
+ qcom,agg-ports = <1>;
+ qcom,bus-dev = <&fab_config_noc>;
+ qcom,bcms = <&bcm_cn0>;
+ };
+
+ slv_qhs_llcc:slv-qhs-llcc {
+ cell-id = <MSM_BUS_SLAVE_LLCC_CFG>;
+ label = "slv-qhs-llcc";
+ qcom,buswidth = <4>;
+ qcom,agg-ports = <1>;
+ qcom,bus-dev = <&fab_dc_noc>;
+ };
+
+ slv_qhs_memnoc:slv-qhs-memnoc {
+ cell-id = <MSM_BUS_SLAVE_MEM_NOC_CFG>;
+ label = "slv-qhs-memnoc";
+ qcom,buswidth = <4>;
+ qcom,agg-ports = <1>;
+ qcom,bus-dev = <&fab_dc_noc>;
+ qcom,connections = <&mas_qhm_memnoc_cfg>;
+ };
+
+ slv_qns_gladiator_sodv:slv-qns-gladiator-sodv {
+ cell-id = <MSM_BUS_SLAVE_GNOC_SNOC>;
+ label = "slv-qns-gladiator-sodv";
+ qcom,buswidth = <8>;
+ qcom,agg-ports = <1>;
+ qcom,bus-dev = <&fab_gladiator_noc>;
+ qcom,connections = <&mas_qnm_gladiator_sodv>;
+ };
+
+ slv_qns_gnoc_memnoc:slv-qns-gnoc-memnoc {
+ cell-id = <MSM_BUS_SLAVE_GNOC_MEM_NOC>;
+ label = "slv-qns-gnoc-memnoc";
+ qcom,buswidth = <32>;
+ qcom,agg-ports = <2>;
+ qcom,bus-dev = <&fab_gladiator_noc>;
+ qcom,connections = <&mas_qnm_apps>;
+ };
+
+ slv_srvc_gnoc:slv-srvc-gnoc {
+ cell-id = <MSM_BUS_SLAVE_SERVICE_GNOC>;
+ label = "slv-srvc-gnoc";
+ qcom,buswidth = <4>;
+ qcom,agg-ports = <1>;
+ qcom,bus-dev = <&fab_gladiator_noc>;
+ };
+
+ slv_ipa_core_slave:slv-ipa-core-slave {
+ cell-id = <MSM_BUS_SLAVE_IPA_CORE>;
+ label = "slv-ipa-core-slave";
+ qcom,buswidth = <8>;
+ qcom,agg-ports = <1>;
+ qcom,bus-dev = <&fab_ipa_virt>;
+ qcom,bcms = <&bcm_ip0>;
+ };
+
+ slv_ebi:slv-ebi {
+ cell-id = <MSM_BUS_SLAVE_EBI_CH0>;
+ label = "slv-ebi";
+ qcom,buswidth = <4>;
+ qcom,agg-ports = <2>;
+ qcom,bus-dev = <&fab_mc_virt>;
+ qcom,bcms = <&bcm_mc0>, <&bcm_acv>;
+ };
+
+ slv_qhs_mdsp_ms_mpu_cfg:slv-qhs-mdsp-ms-mpu-cfg {
+ cell-id = <MSM_BUS_SLAVE_MSS_PROC_MS_MPU_CFG>;
+ label = "slv-qhs-mdsp-ms-mpu-cfg";
+ qcom,buswidth = <4>;
+ qcom,agg-ports = <1>;
+ qcom,bus-dev = <&fab_mem_noc>;
+ };
+
+ slv_qns_apps_io:slv-qns-apps-io {
+ cell-id = <MSM_BUS_SLAVE_MEM_NOC_GNOC>;
+ label = "slv-qns-apps-io";
+ qcom,buswidth = <32>;
+ qcom,agg-ports = <1>;
+ qcom,bus-dev = <&fab_mem_noc>;
+ qcom,bcms = <&bcm_sh1>;
+ };
+
+ slv_qns_llcc:slv-qns-llcc {
+ cell-id = <MSM_BUS_SLAVE_LLCC>;
+ label = "slv-qns-llcc";
+ qcom,buswidth = <16>;
+ qcom,agg-ports = <2>;
+ qcom,bus-dev = <&fab_mem_noc>;
+ qcom,connections = <&mas_llcc_mc>;
+ qcom,bcms = <&bcm_sh0>;
+ };
+
+ slv_qns_memnoc_snoc:slv-qns-memnoc-snoc {
+ cell-id = <MSM_BUS_SLAVE_MEM_NOC_SNOC>;
+ label = "slv-qns-memnoc-snoc";
+ qcom,buswidth = <8>;
+ qcom,agg-ports = <1>;
+ qcom,bus-dev = <&fab_mem_noc>;
+ qcom,connections = <&mas_qnm_memnoc>;
+ qcom,bcms = <&bcm_sh2>;
+ };
+
+ slv_srvc_memnoc:slv-srvc-memnoc {
+ cell-id = <MSM_BUS_SLAVE_SERVICE_MEM_NOC>;
+ label = "slv-srvc-memnoc";
+ qcom,buswidth = <4>;
+ qcom,agg-ports = <1>;
+ qcom,bus-dev = <&fab_mem_noc>;
+ };
+
+ slv_qns2_mem_noc:slv-qns2-mem-noc {
+ cell-id = <MSM_BUS_SLAVE_MNOC_SF_MEM_NOC>;
+ label = "slv-qns2-mem-noc";
+ qcom,buswidth = <32>;
+ qcom,agg-ports = <1>;
+ qcom,bus-dev = <&fab_mmss_noc>;
+ qcom,connections = <&mas_qnm_mnoc_sf>;
+ qcom,bcms = <&bcm_mm2>;
+ };
+
+ slv_qns_mem_noc_hf:slv-qns-mem-noc-hf {
+ cell-id = <MSM_BUS_SLAVE_MNOC_HF_MEM_NOC>;
+ label = "slv-qns-mem-noc-hf";
+ qcom,buswidth = <32>;
+ qcom,agg-ports = <2>;
+ qcom,bus-dev = <&fab_mmss_noc>;
+ qcom,connections = <&mas_qnm_mnoc_hf>;
+ qcom,bcms = <&bcm_mm0>;
+ };
+
+ slv_srvc_mnoc:slv-srvc-mnoc {
+ cell-id = <MSM_BUS_SLAVE_SERVICE_MNOC>;
+ label = "slv-srvc-mnoc";
+ qcom,buswidth = <4>;
+ qcom,agg-ports = <1>;
+ qcom,bus-dev = <&fab_mmss_noc>;
+ };
+
+ slv_qhs_apss:slv-qhs-apss {
+ cell-id = <MSM_BUS_SLAVE_APPSS>;
+ label = "slv-qhs-apss";
+ qcom,buswidth = <8>;
+ qcom,agg-ports = <1>;
+ qcom,bus-dev = <&fab_system_noc>;
+ };
+
+ slv_qns_cnoc:slv-qns-cnoc {
+ cell-id = <MSM_BUS_SNOC_CNOC_SLV>;
+ label = "slv-qns-cnoc";
+ qcom,buswidth = <8>;
+ qcom,agg-ports = <1>;
+ qcom,bus-dev = <&fab_system_noc>;
+ qcom,connections = <&mas_qnm_snoc>;
+ qcom,bcms = <&bcm_sn3>;
+ };
+
+ slv_qns_memnoc_gc:slv-qns-memnoc-gc {
+ cell-id = <MSM_BUS_SLAVE_SNOC_MEM_NOC_GC>;
+ label = "slv-qns-memnoc-gc";
+ qcom,buswidth = <8>;
+ qcom,agg-ports = <1>;
+ qcom,bus-dev = <&fab_system_noc>;
+ qcom,connections = <&mas_qnm_snoc_gc>;
+ qcom,bcms = <&bcm_sn2>;
+ };
+
+ slv_qns_memnoc_sf:slv-qns-memnoc-sf {
+ cell-id = <MSM_BUS_SLAVE_SNOC_MEM_NOC_SF>;
+ label = "slv-qns-memnoc-sf";
+ qcom,buswidth = <16>;
+ qcom,agg-ports = <1>;
+ qcom,bus-dev = <&fab_system_noc>;
+ qcom,connections = <&mas_qnm_snoc_sf>;
+ qcom,bcms = <&bcm_sn0>;
+ };
+
+ slv_qxs_imem:slv-qxs-imem {
+ cell-id = <MSM_BUS_SLAVE_OCIMEM>;
+ label = "slv-qxs-imem";
+ qcom,buswidth = <8>;
+ qcom,agg-ports = <1>;
+ qcom,bus-dev = <&fab_system_noc>;
+ qcom,bcms = <&bcm_sn1>;
+ };
+
+ slv_qxs_pimem:slv-qxs-pimem {
+ cell-id = <MSM_BUS_SLAVE_PIMEM>;
+ label = "slv-qxs-pimem";
+ qcom,buswidth = <8>;
+ qcom,agg-ports = <1>;
+ qcom,bus-dev = <&fab_system_noc>;
+ qcom,bcms = <&bcm_sn4>;
+ };
+
+ slv_srvc_snoc:slv-srvc-snoc {
+ cell-id = <MSM_BUS_SLAVE_SERVICE_SNOC>;
+ label = "slv-srvc-snoc";
+ qcom,buswidth = <4>;
+ qcom,agg-ports = <1>;
+ qcom,bus-dev = <&fab_system_noc>;
+ };
+
+ slv_xs_qdss_stm:slv-xs-qdss-stm {
+ cell-id = <MSM_BUS_SLAVE_QDSS_STM>;
+ label = "slv-xs-qdss-stm";
+ qcom,buswidth = <4>;
+ qcom,agg-ports = <1>;
+ qcom,bus-dev = <&fab_system_noc>;
+ qcom,bcms = <&bcm_sn5>;
+ };
+
+ slv_xs_sys_tcu_cfg:slv-xs-sys-tcu-cfg {
+ cell-id = <MSM_BUS_SLAVE_TCU>;
+ label = "slv-xs-sys-tcu-cfg";
+ qcom,buswidth = <8>;
+ qcom,agg-ports = <1>;
+ qcom,bus-dev = <&fab_system_noc>;
+ };
+
+ slv_ebi_display:slv-ebi_display {
+ cell-id = <MSM_BUS_SLAVE_EBI_CH0_DISPLAY>;
+ label = "slv-ebi_display";
+ qcom,buswidth = <4>;
+ qcom,agg-ports = <2>;
+ qcom,bus-dev = <&fab_mc_virt_display>;
+ qcom,bcms = <&bcm_mc0_display>;
+ };
+
+ slv_qns_llcc_display:slv-qns-llcc_display {
+ cell-id = <MSM_BUS_SLAVE_LLCC_DISPLAY>;
+ label = "slv-qns-llcc_display";
+ qcom,buswidth = <16>;
+ qcom,agg-ports = <2>;
+ qcom,bus-dev = <&fab_mem_noc_display>;
+ qcom,connections = <&mas_llcc_mc_display>;
+ qcom,bcms = <&bcm_sh0_display>;
+ };
+
+ slv_qns2_mem_noc_display:slv-qns2-mem-noc_display {
+ cell-id = <MSM_BUS_SLAVE_MNOC_SF_MEM_NOC_DISPLAY>;
+ label = "slv-qns2-mem-noc_display";
+ qcom,buswidth = <32>;
+ qcom,agg-ports = <1>;
+ qcom,bus-dev = <&fab_mmss_noc_display>;
+ qcom,connections = <&mas_qnm_mnoc_sf_display>;
+ qcom,bcms = <&bcm_mm2_display>;
+ };
+
+ slv_qns_mem_noc_hf_display:slv-qns-mem-noc-hf_display {
+ cell-id = <MSM_BUS_SLAVE_MNOC_HF_MEM_NOC_DISPLAY>;
+ label = "slv-qns-mem-noc-hf_display";
+ qcom,buswidth = <32>;
+ qcom,agg-ports = <2>;
+ qcom,bus-dev = <&fab_mmss_noc_display>;
+ qcom,connections = <&mas_qnm_mnoc_hf_display>;
+ qcom,bcms = <&bcm_mm0_display>;
+ };
+ };
+};
diff --git a/arch/arm64/boot/dts/qcom/sdm670-cdp-overlay.dts b/arch/arm64/boot/dts/qcom/sdm670-cdp-overlay.dts
index 9feb5b4..2b5ed1a 100644
--- a/arch/arm64/boot/dts/qcom/sdm670-cdp-overlay.dts
+++ b/arch/arm64/boot/dts/qcom/sdm670-cdp-overlay.dts
@@ -20,6 +20,7 @@
#include <dt-bindings/interrupt-controller/arm-gic.h>
#include "sdm670-cdp.dtsi"
+#include "sdm670-audio-overlay.dtsi"
/ {
model = "Qualcomm Technologies, Inc. SDM670 PM660 + PM660L CDP";
diff --git a/arch/arm64/boot/dts/qcom/sdm670-cdp.dts b/arch/arm64/boot/dts/qcom/sdm670-cdp.dts
index 27882dd..5a1b945 100644
--- a/arch/arm64/boot/dts/qcom/sdm670-cdp.dts
+++ b/arch/arm64/boot/dts/qcom/sdm670-cdp.dts
@@ -15,6 +15,7 @@
#include "sdm670.dtsi"
#include "sdm670-cdp.dtsi"
+#include "sdm670-audio-overlay.dtsi"
/ {
model = "Qualcomm Technologies, Inc. SDM670 PM660 + PM660L CDP";
diff --git a/arch/arm64/boot/dts/qcom/sdm670-cdp.dtsi b/arch/arm64/boot/dts/qcom/sdm670-cdp.dtsi
index 00f454c..257698a 100644
--- a/arch/arm64/boot/dts/qcom/sdm670-cdp.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm670-cdp.dtsi
@@ -10,7 +10,9 @@
* GNU General Public License for more details.
*/
+#include <dt-bindings/gpio/gpio.h>
#include "sdm670-pmic-overlay.dtsi"
+#include "sdm670-sde-display.dtsi"
&ufsphy_mem {
compatible = "qcom,ufs-phy-qmp-v3";
@@ -106,7 +108,8 @@
pinctrl-names = "default";
pinctrl-0 = <&key_cam_snapshot_default
- &key_cam_focus_default>;
+ &key_cam_focus_default
+ &key_vol_up_default>;
cam_snapshot {
label = "cam_snapshot";
@@ -127,5 +130,106 @@
debounce-interval = <15>;
linux,can-disable;
};
+
+ vol_up {
+ label = "volume_up";
+ gpios = <&pm660l_gpios 7 GPIO_ACTIVE_LOW>;
+ linux,input-type = <1>;
+ linux,code = <115>;
+ gpio-key,wakeup;
+ debounce-interval = <15>;
+ linux,can-disable;
+ };
};
};
+
+&dsi_dual_nt35597_truly_video {
+ qcom,panel-supply-entries = <&dsi_panel_pwr_supply>;
+ qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_wled";
+ qcom,mdss-dsi-bl-min-level = <1>;
+ qcom,mdss-dsi-bl-max-level = <4095>;
+ qcom,mdss-dsi-mode-sel-gpio-state = "dual_port";
+ qcom,panel-mode-gpio = <&tlmm 76 0>;
+ qcom,platform-reset-gpio = <&tlmm 75 0>;
+};
+
+&dsi_dual_nt35597_truly_cmd {
+ qcom,panel-supply-entries = <&dsi_panel_pwr_supply>;
+ qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_wled";
+ qcom,mdss-dsi-bl-min-level = <1>;
+ qcom,mdss-dsi-bl-max-level = <4095>;
+ qcom,mdss-dsi-mode-sel-gpio-state = "dual_port";
+ qcom,panel-mode-gpio = <&tlmm 76 0>;
+ qcom,platform-reset-gpio = <&tlmm 75 0>;
+ qcom,platform-te-gpio = <&tlmm 10 0>;
+};
+
+&dsi_nt35597_truly_dsc_video {
+ qcom,panel-supply-entries = <&dsi_panel_pwr_supply>;
+ qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_wled";
+ qcom,mdss-dsi-bl-min-level = <1>;
+ qcom,mdss-dsi-bl-max-level = <4095>;
+ qcom,mdss-dsi-mode-sel-gpio-state = "single_port";
+ qcom,panel-mode-gpio = <&tlmm 76 0>;
+ qcom,platform-reset-gpio = <&tlmm 75 0>;
+};
+
+&dsi_nt35597_truly_dsc_cmd {
+ qcom,panel-supply-entries = <&dsi_panel_pwr_supply>;
+ qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_wled";
+ qcom,mdss-dsi-bl-min-level = <1>;
+ qcom,mdss-dsi-bl-max-level = <4095>;
+ qcom,mdss-dsi-mode-sel-gpio-state = "single_port";
+ qcom,panel-mode-gpio = <&tlmm 76 0>;
+ qcom,platform-reset-gpio = <&tlmm 75 0>;
+ qcom,platform-te-gpio = <&tlmm 10 0>;
+};
+
+&dsi_sim_vid {
+ qcom,panel-supply-entries = <&dsi_panel_pwr_supply>;
+ qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_wled";
+ qcom,platform-reset-gpio = <&tlmm 75 0>;
+};
+
+&dsi_dual_sim_vid {
+ qcom,panel-supply-entries = <&dsi_panel_pwr_supply>;
+ qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_wled";
+ qcom,platform-reset-gpio = <&tlmm 75 0>;
+};
+
+&dsi_sim_cmd {
+ qcom,panel-supply-entries = <&dsi_panel_pwr_supply>;
+ qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_wled";
+ qcom,platform-reset-gpio = <&tlmm 75 0>;
+};
+
+&dsi_dual_sim_cmd {
+ qcom,panel-supply-entries = <&dsi_panel_pwr_supply>;
+ qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_wled";
+ qcom,platform-reset-gpio = <&tlmm 75 0>;
+};
+
+&dsi_sim_dsc_375_cmd {
+ qcom,panel-supply-entries = <&dsi_panel_pwr_supply>;
+ qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_wled";
+ qcom,platform-reset-gpio = <&tlmm 75 0>;
+};
+
+&dsi_dual_sim_dsc_375_cmd {
+ qcom,panel-supply-entries = <&dsi_panel_pwr_supply>;
+ qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_wled";
+ qcom,platform-reset-gpio = <&tlmm 75 0>;
+};
+
+&dsi_dual_nt35597_truly_video {
+ qcom,dsi-display-active;
+};
+
+&pm660l_wled {
+ status = "okay";
+ qcom,led-strings-list = [01 02];
+};
+
+&mdss_mdp {
+ #cooling-cells = <2>;
+};
diff --git a/arch/arm64/boot/dts/qcom/sdm670-coresight.dtsi b/arch/arm64/boot/dts/qcom/sdm670-coresight.dtsi
index 6cbfb57..8b79d8b 100644
--- a/arch/arm64/boot/dts/qcom/sdm670-coresight.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm670-coresight.dtsi
@@ -746,6 +746,7 @@
arm,primecell-periphid = <0x0003b968>;
reg = <0x6860000 0x1000>;
reg-names = "tpdm-base";
+ status = "disabled";
coresight-name = "coresight-tpdm-turing";
diff --git a/arch/arm64/boot/dts/qcom/sdm670-ext-cdc-usbc-audio.dtsi b/arch/arm64/boot/dts/qcom/sdm670-ext-cdc-usbc-audio.dtsi
new file mode 100644
index 0000000..cd113b3
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/sdm670-ext-cdc-usbc-audio.dtsi
@@ -0,0 +1,17 @@
+/*
+ * Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+&tavil_snd {
+ qcom,msm-mbhc-usbc-audio-supported = <1>;
+ qcom,usbc-analog-en1-gpio = <&wcd_usbc_analog_en1_gpio>;
+};
diff --git a/arch/arm64/boot/dts/qcom/sdm670-ext-codec-audio-overlay.dtsi b/arch/arm64/boot/dts/qcom/sdm670-ext-codec-audio-overlay.dtsi
new file mode 100644
index 0000000..775cf48
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/sdm670-ext-codec-audio-overlay.dtsi
@@ -0,0 +1,96 @@
+/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+#include "sdm670-audio-overlay.dtsi"
+
+&pmic_analog_codec {
+ status = "disabled";
+};
+
+&msm_sdw_codec {
+ status = "disabled";
+};
+
+&cdc_pdm_gpios {
+ status = "disabled";
+};
+
+&cdc_comp_gpios {
+ status = "disabled";
+};
+
+&cdc_dmic_gpios {
+ status = "disabled";
+};
+
+&cdc_sdw_gpios {
+ status = "disabled";
+};
+
+&wsa_spkr_en1 {
+ status = "disabled";
+};
+
+&wsa_spkr_en2 {
+ status = "disabled";
+};
+
+&qupv3_se8_spi {
+ status = "okay";
+};
+
+&soc {
+ wcd_buck_vreg_gpio: msm_cdc_pinctrl@94 {
+ status = "okay";
+ compatible = "qcom,msm-cdc-pinctrl";
+ pinctrl-names = "aud_active", "aud_sleep";
+ pinctrl-0 = <&wcd_buck_vsel_default>;
+ pinctrl-1 = <&wcd_buck_vsel_default>;
+ };
+};
+
+&wcd9xxx_intc {
+ status = "okay";
+};
+
+&wdsp_mgr {
+ status = "okay";
+};
+
+&wdsp_glink {
+ status = "okay";
+};
+
+&slim_aud {
+ status = "okay";
+};
+
+&dai_slim {
+ status = "okay";
+};
+
+&wcd934x_cdc {
+ status = "okay";
+ qcom,has-buck-vsel-gpio;
+ qcom,buck-vsel-gpio-node = <&wcd_buck_vreg_gpio>;
+};
+
+&clock_audio_lnbb {
+ status = "okay";
+};
+
+&wcd_rst_gpio {
+ status = "okay";
+};
+
+&wcd9xxx_intc {
+ status = "okay";
+};
diff --git a/arch/arm64/boot/dts/qcom/sdm670-external-codec.dtsi b/arch/arm64/boot/dts/qcom/sdm670-external-codec.dtsi
index 6ea92ee..dbcc6bd 100644
--- a/arch/arm64/boot/dts/qcom/sdm670-external-codec.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm670-external-codec.dtsi
@@ -9,3 +9,21 @@
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
+
+#include "sdm670-ext-codec-audio-overlay.dtsi"
+
+&int_codec {
+ status = "disabled";
+};
+
+&tavil_snd {
+ status = "okay";
+};
+
+&slim_aud {
+ status = "okay";
+};
+
+&dai_slim {
+ status = "okay";
+};
diff --git a/arch/arm64/boot/dts/qcom/sdm670-int-cdc-usbc-audio-overlay.dtsi b/arch/arm64/boot/dts/qcom/sdm670-int-cdc-usbc-audio-overlay.dtsi
new file mode 100644
index 0000000..df10e7d
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/sdm670-int-cdc-usbc-audio-overlay.dtsi
@@ -0,0 +1,17 @@
+/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+#include "sdm670-audio-overlay.dtsi"
+
+&int_codec {
+ qcom,msm-mbhc-usbc-audio-supported = <1>;
+ qcom,usbc-analog-en1-gpio = <&wcd_usbc_analog_en1_gpio>;
+};
diff --git a/arch/arm64/boot/dts/qcom/sdm670-mtp-overlay.dts b/arch/arm64/boot/dts/qcom/sdm670-mtp-overlay.dts
index 65c16c1..ac254fd 100644
--- a/arch/arm64/boot/dts/qcom/sdm670-mtp-overlay.dts
+++ b/arch/arm64/boot/dts/qcom/sdm670-mtp-overlay.dts
@@ -20,6 +20,7 @@
#include <dt-bindings/interrupt-controller/arm-gic.h>
#include "sdm670-mtp.dtsi"
+#include "sdm670-audio-overlay.dtsi"
/ {
model = "Qualcomm Technologies, Inc. SDM670 PM660 + PM660L MTP";
diff --git a/arch/arm64/boot/dts/qcom/sdm670-mtp.dts b/arch/arm64/boot/dts/qcom/sdm670-mtp.dts
index 38a9fae..1241a20 100644
--- a/arch/arm64/boot/dts/qcom/sdm670-mtp.dts
+++ b/arch/arm64/boot/dts/qcom/sdm670-mtp.dts
@@ -15,6 +15,7 @@
#include "sdm670.dtsi"
#include "sdm670-mtp.dtsi"
+#include "sdm670-audio-overlay.dtsi"
/ {
model = "Qualcomm Technologies, Inc. SDM670 PM660 + PM660L MTP";
diff --git a/arch/arm64/boot/dts/qcom/sdm670-mtp.dtsi b/arch/arm64/boot/dts/qcom/sdm670-mtp.dtsi
index 320a1f2..fa76a2e 100644
--- a/arch/arm64/boot/dts/qcom/sdm670-mtp.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm670-mtp.dtsi
@@ -10,7 +10,9 @@
* GNU General Public License for more details.
*/
+#include <dt-bindings/gpio/gpio.h>
#include "sdm670-pmic-overlay.dtsi"
+#include "sdm670-sde-display.dtsi"
&ufsphy_mem {
compatible = "qcom,ufs-phy-qmp-v3";
@@ -115,7 +117,8 @@
pinctrl-names = "default";
pinctrl-0 = <&key_cam_snapshot_default
- &key_cam_focus_default>;
+ &key_cam_focus_default
+ &key_vol_up_default>;
cam_snapshot {
label = "cam_snapshot";
@@ -136,5 +139,106 @@
debounce-interval = <15>;
linux,can-disable;
};
+
+ vol_up {
+ label = "volume_up";
+ gpios = <&pm660l_gpios 7 GPIO_ACTIVE_LOW>;
+ linux,input-type = <1>;
+ linux,code = <115>;
+ gpio-key,wakeup;
+ debounce-interval = <15>;
+ linux,can-disable;
+ };
};
};
+
+&dsi_dual_nt35597_truly_video {
+ qcom,panel-supply-entries = <&dsi_panel_pwr_supply>;
+ qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_wled";
+ qcom,mdss-dsi-bl-min-level = <1>;
+ qcom,mdss-dsi-bl-max-level = <4095>;
+ qcom,mdss-dsi-mode-sel-gpio-state = "dual_port";
+ qcom,panel-mode-gpio = <&tlmm 76 0>;
+ qcom,platform-reset-gpio = <&tlmm 75 0>;
+};
+
+&dsi_dual_nt35597_truly_cmd {
+ qcom,panel-supply-entries = <&dsi_panel_pwr_supply>;
+ qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_wled";
+ qcom,mdss-dsi-bl-min-level = <1>;
+ qcom,mdss-dsi-bl-max-level = <4095>;
+ qcom,mdss-dsi-mode-sel-gpio-state = "dual_port";
+ qcom,panel-mode-gpio = <&tlmm 76 0>;
+ qcom,platform-reset-gpio = <&tlmm 75 0>;
+ qcom,platform-te-gpio = <&tlmm 10 0>;
+};
+
+&dsi_nt35597_truly_dsc_video {
+ qcom,panel-supply-entries = <&dsi_panel_pwr_supply>;
+ qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_wled";
+ qcom,mdss-dsi-bl-min-level = <1>;
+ qcom,mdss-dsi-bl-max-level = <4095>;
+ qcom,mdss-dsi-mode-sel-gpio-state = "single_port";
+ qcom,panel-mode-gpio = <&tlmm 76 0>;
+ qcom,platform-reset-gpio = <&tlmm 75 0>;
+};
+
+&dsi_nt35597_truly_dsc_cmd {
+ qcom,panel-supply-entries = <&dsi_panel_pwr_supply>;
+ qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_wled";
+ qcom,mdss-dsi-bl-min-level = <1>;
+ qcom,mdss-dsi-bl-max-level = <4095>;
+ qcom,mdss-dsi-mode-sel-gpio-state = "single_port";
+ qcom,panel-mode-gpio = <&tlmm 76 0>;
+ qcom,platform-reset-gpio = <&tlmm 75 0>;
+ qcom,platform-te-gpio = <&tlmm 10 0>;
+};
+
+&dsi_sim_vid {
+ qcom,panel-supply-entries = <&dsi_panel_pwr_supply>;
+ qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_wled";
+ qcom,platform-reset-gpio = <&tlmm 75 0>;
+};
+
+&dsi_dual_sim_vid {
+ qcom,panel-supply-entries = <&dsi_panel_pwr_supply>;
+ qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_wled";
+ qcom,platform-reset-gpio = <&tlmm 75 0>;
+};
+
+&dsi_sim_cmd {
+ qcom,panel-supply-entries = <&dsi_panel_pwr_supply>;
+ qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_wled";
+ qcom,platform-reset-gpio = <&tlmm 75 0>;
+};
+
+&dsi_dual_sim_cmd {
+ qcom,panel-supply-entries = <&dsi_panel_pwr_supply>;
+ qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_wled";
+ qcom,platform-reset-gpio = <&tlmm 75 0>;
+};
+
+&dsi_sim_dsc_375_cmd {
+ qcom,panel-supply-entries = <&dsi_panel_pwr_supply>;
+ qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_wled";
+ qcom,platform-reset-gpio = <&tlmm 75 0>;
+};
+
+&dsi_dual_sim_dsc_375_cmd {
+ qcom,panel-supply-entries = <&dsi_panel_pwr_supply>;
+ qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_wled";
+ qcom,platform-reset-gpio = <&tlmm 75 0>;
+};
+
+&dsi_dual_nt35597_truly_video {
+ qcom,dsi-display-active;
+};
+
+&pm660l_wled {
+ status = "okay";
+ qcom,led-strings-list = [01 02];
+};
+
+&mdss_mdp {
+ #cooling-cells = <2>;
+};
diff --git a/arch/arm64/boot/dts/qcom/sdm670-pinctrl.dtsi b/arch/arm64/boot/dts/qcom/sdm670-pinctrl.dtsi
index 2a2b6d8..e747185 100644
--- a/arch/arm64/boot/dts/qcom/sdm670-pinctrl.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm670-pinctrl.dtsi
@@ -1406,6 +1406,22 @@
};
};
+ wcd_buck_vsel {
+ wcd_buck_vsel_default: wcd_buck_vsel_default{
+ mux {
+ pins = "gpio94";
+ function = "gpio";
+ };
+
+ config {
+ pins = "gpio94";
+ drive-strength = <8>; /* 8 mA */
+ bias-pull-down; /* pull down */
+ output-high;
+ };
+ };
+ };
+
wcd_gnd_mic_swap {
wcd_gnd_mic_swap_idle: wcd_gnd_mic_swap_idle {
mux {
@@ -1473,5 +1489,123 @@
};
};
+ pmx_sde: pmx_sde {
+ sde_dsi_active: sde_dsi_active {
+ mux {
+ pins = "gpio75", "gpio76";
+ function = "gpio";
+ };
+
+ config {
+ pins = "gpio75", "gpio76";
+ drive-strength = <8>; /* 8 mA */
+ bias-disable = <0>; /* no pull */
+ };
+ };
+ sde_dsi_suspend: sde_dsi_suspend {
+ mux {
+ pins = "gpio75", "gpio76";
+ function = "gpio";
+ };
+
+ config {
+ pins = "gpio75", "gpio76";
+ drive-strength = <2>; /* 2 mA */
+ bias-pull-down; /* PULL DOWN */
+ };
+ };
+ };
+
+ pmx_sde_te {
+ sde_te_active: sde_te_active {
+ mux {
+ pins = "gpio10";
+ function = "mdp_vsync";
+ };
+
+ config {
+ pins = "gpio10";
+ drive-strength = <2>; /* 2 mA */
+ bias-pull-down; /* PULL DOWN */
+ };
+ };
+
+ sde_te_suspend: sde_te_suspend {
+ mux {
+ pins = "gpio10";
+ function = "mdp_vsync";
+ };
+
+ config {
+ pins = "gpio10";
+ drive-strength = <2>; /* 2 mA */
+ bias-pull-down; /* PULL DOWN */
+ };
+ };
+ };
+
+ sde_dp_aux_active: sde_dp_aux_active {
+ mux {
+ pins = "gpio40", "gpio50";
+ function = "gpio";
+ };
+
+ config {
+ pins = "gpio40", "gpio50";
+ bias-disable = <0>; /* no pull */
+ drive-strength = <8>;
+ };
+ };
+
+ sde_dp_aux_suspend: sde_dp_aux_suspend {
+ mux {
+ pins = "gpio40", "gpio50";
+ function = "gpio";
+ };
+
+ config {
+ pins = "gpio40", "gpio50";
+ bias-pull-down;
+ drive-strength = <2>;
+ };
+ };
+
+ sde_dp_usbplug_cc_active: sde_dp_usbplug_cc_active {
+ mux {
+ pins = "gpio38";
+ function = "gpio";
+ };
+
+ config {
+ pins = "gpio38";
+ bias-disable;
+ drive-strength = <16>;
+ };
+ };
+
+ sde_dp_usbplug_cc_suspend: sde_dp_usbplug_cc_suspend {
+ mux {
+ pins = "gpio38";
+ function = "gpio";
+ };
+
+ config {
+ pins = "gpio38";
+ bias-pull-down;
+ drive-strength = <2>;
+ };
+ };
+ };
+};
+
+&pm660l_gpios {
+ key_vol_up {
+ key_vol_up_default: key_vol_up_default {
+ pins = "gpio7";
+ function = "normal";
+ input-enable;
+ bias-pull-up;
+ power-source = <0>;
+ };
};
};
diff --git a/arch/arm64/boot/dts/qcom/sdm670-pm660a-cdp-overlay.dts b/arch/arm64/boot/dts/qcom/sdm670-pm660a-cdp-overlay.dts
index b3d2357..5b67765 100644
--- a/arch/arm64/boot/dts/qcom/sdm670-pm660a-cdp-overlay.dts
+++ b/arch/arm64/boot/dts/qcom/sdm670-pm660a-cdp-overlay.dts
@@ -21,6 +21,7 @@
#include "sdm670-cdp.dtsi"
#include "pm660a.dtsi"
+#include "sdm670-audio-overlay.dtsi"
/ {
model = "Qualcomm Technologies, Inc. SDM670 PM660 + PM660A CDP";
diff --git a/arch/arm64/boot/dts/qcom/sdm670-pm660a-cdp.dts b/arch/arm64/boot/dts/qcom/sdm670-pm660a-cdp.dts
index 5cf3513..26f5e78 100644
--- a/arch/arm64/boot/dts/qcom/sdm670-pm660a-cdp.dts
+++ b/arch/arm64/boot/dts/qcom/sdm670-pm660a-cdp.dts
@@ -16,6 +16,7 @@
#include "sdm670.dtsi"
#include "sdm670-cdp.dtsi"
#include "pm660a.dtsi"
+#include "sdm670-audio-overlay.dtsi"
/ {
model = "Qualcomm Technologies, Inc. SDM670 PM660 + PM660A CDP";
diff --git a/arch/arm64/boot/dts/qcom/sdm670-pm660a-mtp-overlay.dts b/arch/arm64/boot/dts/qcom/sdm670-pm660a-mtp-overlay.dts
index ff3270d..1550661 100644
--- a/arch/arm64/boot/dts/qcom/sdm670-pm660a-mtp-overlay.dts
+++ b/arch/arm64/boot/dts/qcom/sdm670-pm660a-mtp-overlay.dts
@@ -21,6 +21,7 @@
#include "sdm670-mtp.dtsi"
#include "pm660a.dtsi"
+#include "sdm670-audio-overlay.dtsi"
/ {
model = "Qualcomm Technologies, Inc. SDM670 PM660 + PM660A MTP";
diff --git a/arch/arm64/boot/dts/qcom/sdm670-pm660a-mtp.dts b/arch/arm64/boot/dts/qcom/sdm670-pm660a-mtp.dts
index febd5d9..14f48a0 100644
--- a/arch/arm64/boot/dts/qcom/sdm670-pm660a-mtp.dts
+++ b/arch/arm64/boot/dts/qcom/sdm670-pm660a-mtp.dts
@@ -16,6 +16,7 @@
#include "sdm670.dtsi"
#include "sdm670-mtp.dtsi"
#include "pm660a.dtsi"
+#include "sdm670-audio-overlay.dtsi"
/ {
model = "Qualcomm Technologies, Inc. SDM670 PM660 + PM660A MTP";
diff --git a/arch/arm64/boot/dts/qcom/sdm670-rumi.dts b/arch/arm64/boot/dts/qcom/sdm670-rumi.dts
index 6201488..e137705 100644
--- a/arch/arm64/boot/dts/qcom/sdm670-rumi.dts
+++ b/arch/arm64/boot/dts/qcom/sdm670-rumi.dts
@@ -16,6 +16,7 @@
#include "sdm670.dtsi"
#include "sdm670-rumi.dtsi"
+#include "sdm670-audio-overlay.dtsi"
/ {
model = "Qualcomm Technologies, Inc. SDM670 RUMI";
compatible = "qcom,sdm670-rumi", "qcom,sdm670", "qcom,rumi";
diff --git a/arch/arm64/boot/dts/qcom/sdm670-sde-display.dtsi b/arch/arm64/boot/dts/qcom/sdm670-sde-display.dtsi
new file mode 100644
index 0000000..3e9d967
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/sdm670-sde-display.dtsi
@@ -0,0 +1,597 @@
+/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include "dsi-panel-sim-video.dtsi"
+#include "dsi-panel-sim-cmd.dtsi"
+#include "dsi-panel-sim-dsc375-cmd.dtsi"
+#include "dsi-panel-sim-dualmipi-video.dtsi"
+#include "dsi-panel-sim-dualmipi-cmd.dtsi"
+#include "dsi-panel-sim-dualmipi-dsc375-cmd.dtsi"
+#include "dsi-panel-nt35597-truly-dualmipi-wqxga-video.dtsi"
+#include "dsi-panel-nt35597-truly-dualmipi-wqxga-cmd.dtsi"
+#include "dsi-panel-nt35597-truly-dsc-wqxga-cmd.dtsi"
+#include "dsi-panel-nt35597-truly-dsc-wqxga-video.dtsi"
+#include <dt-bindings/clock/mdss-10nm-pll-clk.h>
+
+&soc {
+ dsi_panel_pwr_supply: dsi_panel_pwr_supply {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ qcom,panel-supply-entry@0 {
+ reg = <0>;
+ qcom,supply-name = "vddio";
+ qcom,supply-min-voltage = <1800000>;
+ qcom,supply-max-voltage = <1800000>;
+ qcom,supply-enable-load = <62000>;
+ qcom,supply-disable-load = <80>;
+ qcom,supply-post-on-sleep = <20>;
+ };
+
+ qcom,panel-supply-entry@1 {
+ reg = <1>;
+ qcom,supply-name = "lab";
+ qcom,supply-min-voltage = <4600000>;
+ qcom,supply-max-voltage = <6000000>;
+ qcom,supply-enable-load = <100000>;
+ qcom,supply-disable-load = <100>;
+ };
+
+ qcom,panel-supply-entry@2 {
+ reg = <2>;
+ qcom,supply-name = "ibb";
+ qcom,supply-min-voltage = <4600000>;
+ qcom,supply-max-voltage = <6000000>;
+ qcom,supply-enable-load = <100000>;
+ qcom,supply-disable-load = <100>;
+ qcom,supply-post-on-sleep = <20>;
+ };
+ };
+
+ dsi_panel_pwr_supply_no_labibb: dsi_panel_pwr_supply_no_labibb {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ qcom,panel-supply-entry@0 {
+ reg = <0>;
+ qcom,supply-name = "vddio";
+ qcom,supply-min-voltage = <1800000>;
+ qcom,supply-max-voltage = <1800000>;
+ qcom,supply-enable-load = <62000>;
+ qcom,supply-disable-load = <80>;
+ qcom,supply-post-on-sleep = <20>;
+ };
+ };
+
+ dsi_panel_pwr_supply_vdd_no_labibb: dsi_panel_pwr_supply_vdd_no_labibb {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ qcom,panel-supply-entry@0 {
+ reg = <0>;
+ qcom,supply-name = "vddio";
+ qcom,supply-min-voltage = <1800000>;
+ qcom,supply-max-voltage = <1800000>;
+ qcom,supply-enable-load = <62000>;
+ qcom,supply-disable-load = <80>;
+ qcom,supply-post-on-sleep = <20>;
+ };
+
+ qcom,panel-supply-entry@1 {
+ reg = <1>;
+ qcom,supply-name = "vdd";
+ qcom,supply-min-voltage = <3000000>;
+ qcom,supply-max-voltage = <3000000>;
+ qcom,supply-enable-load = <857000>;
+ qcom,supply-disable-load = <0>;
+ qcom,supply-post-on-sleep = <0>;
+ };
+ };
+
+ dsi_dual_nt35597_truly_video_display: qcom,dsi-display@0 {
+ compatible = "qcom,dsi-display";
+ label = "dsi_dual_nt35597_truly_video_display";
+ qcom,display-type = "primary";
+
+ qcom,dsi-ctrl = <&mdss_dsi0 &mdss_dsi1>;
+ qcom,dsi-phy = <&mdss_dsi_phy0 &mdss_dsi_phy1>;
+ clocks = <&mdss_dsi0_pll BYTECLK_MUX_0_CLK>,
+ <&mdss_dsi0_pll PCLK_MUX_0_CLK>;
+ clock-names = "src_byte_clk", "src_pixel_clk";
+
+ pinctrl-names = "panel_active", "panel_suspend";
+ pinctrl-0 = <&sde_dsi_active &sde_te_active>;
+ pinctrl-1 = <&sde_dsi_suspend &sde_te_suspend>;
+ qcom,platform-reset-gpio = <&tlmm 75 0>;
+ qcom,panel-mode-gpio = <&tlmm 76 0>;
+
+ qcom,dsi-panel = <&dsi_dual_nt35597_truly_video>;
+ vddio-supply = <&pm660_l11>;
+ lab-supply = <&lcdb_ldo_vreg>;
+ ibb-supply = <&lcdb_ncp_vreg>;
+ };
+
+ dsi_dual_nt35597_truly_cmd_display: qcom,dsi-display@1 {
+ compatible = "qcom,dsi-display";
+ label = "dsi_dual_nt35597_truly_cmd_display";
+ qcom,display-type = "primary";
+
+ qcom,dsi-ctrl = <&mdss_dsi0 &mdss_dsi1>;
+ qcom,dsi-phy = <&mdss_dsi_phy0 &mdss_dsi_phy1>;
+ clocks = <&mdss_dsi0_pll BYTECLK_MUX_0_CLK>,
+ <&mdss_dsi0_pll PCLK_MUX_0_CLK>;
+ clock-names = "src_byte_clk", "src_pixel_clk";
+
+ pinctrl-names = "panel_active", "panel_suspend";
+ pinctrl-0 = <&sde_dsi_active &sde_te_active>;
+ pinctrl-1 = <&sde_dsi_suspend &sde_te_suspend>;
+ qcom,platform-te-gpio = <&tlmm 10 0>;
+ qcom,platform-reset-gpio = <&tlmm 75 0>;
+ qcom,panel-mode-gpio = <&tlmm 76 0>;
+
+ qcom,dsi-panel = <&dsi_dual_nt35597_truly_cmd>;
+ vddio-supply = <&pm660_l11>;
+ lab-supply = <&lcdb_ldo_vreg>;
+ ibb-supply = <&lcdb_ncp_vreg>;
+ };
+
+ dsi_nt35597_truly_dsc_cmd_display: qcom,dsi-display@2 {
+ compatible = "qcom,dsi-display";
+ label = "dsi_nt35597_truly_dsc_cmd_display";
+ qcom,display-type = "primary";
+
+ qcom,dsi-ctrl = <&mdss_dsi1>;
+ qcom,dsi-phy = <&mdss_dsi_phy1>;
+ clocks = <&mdss_dsi1_pll BYTECLK_MUX_1_CLK>,
+ <&mdss_dsi1_pll PCLK_MUX_1_CLK>;
+ clock-names = "src_byte_clk", "src_pixel_clk";
+
+ pinctrl-names = "panel_active", "panel_suspend";
+ pinctrl-0 = <&sde_dsi_active &sde_te_active>;
+ pinctrl-1 = <&sde_dsi_suspend &sde_te_suspend>;
+ qcom,platform-te-gpio = <&tlmm 10 0>;
+ qcom,platform-reset-gpio = <&tlmm 75 0>;
+ qcom,panel-mode-gpio = <&tlmm 76 0>;
+
+ qcom,dsi-panel = <&dsi_nt35597_truly_dsc_cmd>;
+ vddio-supply = <&pm660_l11>;
+ lab-supply = <&lcdb_ldo_vreg>;
+ ibb-supply = <&lcdb_ncp_vreg>;
+ };
+
+ dsi_nt35597_truly_dsc_video_display: qcom,dsi-display@3 {
+ compatible = "qcom,dsi-display";
+ label = "dsi_nt35597_truly_dsc_video_display";
+ qcom,display-type = "primary";
+
+ qcom,dsi-ctrl = <&mdss_dsi1>;
+ qcom,dsi-phy = <&mdss_dsi_phy1>;
+ clocks = <&mdss_dsi1_pll BYTECLK_MUX_1_CLK>,
+ <&mdss_dsi1_pll PCLK_MUX_1_CLK>;
+ clock-names = "src_byte_clk", "src_pixel_clk";
+
+ pinctrl-names = "panel_active", "panel_suspend";
+ pinctrl-0 = <&sde_dsi_active &sde_te_active>;
+ pinctrl-1 = <&sde_dsi_suspend &sde_te_suspend>;
+ qcom,platform-te-gpio = <&tlmm 10 0>;
+ qcom,platform-reset-gpio = <&tlmm 75 0>;
+ qcom,panel-mode-gpio = <&tlmm 76 0>;
+
+ qcom,dsi-panel = <&dsi_nt35597_truly_dsc_video>;
+ vddio-supply = <&pm660_l11>;
+ lab-supply = <&lcdb_ldo_vreg>;
+ ibb-supply = <&lcdb_ncp_vreg>;
+ };
+
+ dsi_sim_vid_display: qcom,dsi-display@4 {
+ compatible = "qcom,dsi-display";
+ label = "dsi_sim_vid_display";
+ qcom,display-type = "primary";
+
+ qcom,dsi-ctrl = <&mdss_dsi0>;
+ qcom,dsi-phy = <&mdss_dsi_phy0>;
+ clocks = <&mdss_dsi0_pll BYTECLK_MUX_0_CLK>,
+ <&mdss_dsi0_pll PCLK_MUX_0_CLK>;
+ clock-names = "src_byte_clk", "src_pixel_clk";
+
+ pinctrl-names = "panel_active", "panel_suspend";
+ pinctrl-0 = <&sde_dsi_active &sde_te_active>;
+ pinctrl-1 = <&sde_dsi_suspend &sde_te_suspend>;
+
+ qcom,dsi-panel = <&dsi_sim_vid>;
+ };
+
+ dsi_dual_sim_vid_display: qcom,dsi-display@5 {
+ compatible = "qcom,dsi-display";
+ label = "dsi_dual_sim_vid_display";
+ qcom,display-type = "primary";
+
+ qcom,dsi-ctrl = <&mdss_dsi0 &mdss_dsi1>;
+ qcom,dsi-phy = <&mdss_dsi_phy0 &mdss_dsi_phy1>;
+ clocks = <&mdss_dsi0_pll BYTECLK_MUX_0_CLK>,
+ <&mdss_dsi0_pll PCLK_MUX_0_CLK>;
+ clock-names = "src_byte_clk", "src_pixel_clk";
+
+ pinctrl-names = "panel_active", "panel_suspend";
+ pinctrl-0 = <&sde_dsi_active &sde_te_active>;
+ pinctrl-1 = <&sde_dsi_suspend &sde_te_suspend>;
+
+ qcom,dsi-panel = <&dsi_dual_sim_vid>;
+ };
+
+ dsi_sim_cmd_display: qcom,dsi-display@6 {
+ compatible = "qcom,dsi-display";
+ label = "dsi_sim_cmd_display";
+ qcom,display-type = "primary";
+
+ qcom,dsi-ctrl = <&mdss_dsi0>;
+ qcom,dsi-phy = <&mdss_dsi_phy0>;
+ clocks = <&mdss_dsi0_pll BYTECLK_MUX_0_CLK>,
+ <&mdss_dsi0_pll PCLK_MUX_0_CLK>;
+ clock-names = "src_byte_clk", "src_pixel_clk";
+
+ pinctrl-names = "panel_active", "panel_suspend";
+ pinctrl-0 = <&sde_dsi_active &sde_te_active>;
+ pinctrl-1 = <&sde_dsi_suspend &sde_te_suspend>;
+
+ qcom,dsi-panel = <&dsi_sim_cmd>;
+ };
+
+ dsi_dual_sim_cmd_display: qcom,dsi-display@7 {
+ compatible = "qcom,dsi-display";
+ label = "dsi_dual_sim_cmd_display";
+ qcom,display-type = "primary";
+
+ qcom,dsi-ctrl = <&mdss_dsi0 &mdss_dsi1>;
+ qcom,dsi-phy = <&mdss_dsi_phy0 &mdss_dsi_phy1>;
+ clocks = <&mdss_dsi0_pll BYTECLK_MUX_0_CLK>,
+ <&mdss_dsi0_pll PCLK_MUX_0_CLK>;
+ clock-names = "src_byte_clk", "src_pixel_clk";
+
+ pinctrl-names = "panel_active", "panel_suspend";
+ pinctrl-0 = <&sde_dsi_active &sde_te_active>;
+ pinctrl-1 = <&sde_dsi_suspend &sde_te_suspend>;
+
+ qcom,dsi-panel = <&dsi_dual_sim_cmd>;
+ };
+
+ dsi_sim_dsc_375_cmd_display: qcom,dsi-display@8 {
+ compatible = "qcom,dsi-display";
+ label = "dsi_sim_dsc_375_cmd_display";
+ qcom,display-type = "primary";
+
+ qcom,dsi-ctrl = <&mdss_dsi0>;
+ qcom,dsi-phy = <&mdss_dsi_phy0>;
+ clocks = <&mdss_dsi0_pll BYTECLK_MUX_0_CLK>,
+ <&mdss_dsi0_pll PCLK_MUX_0_CLK>;
+ clock-names = "src_byte_clk", "src_pixel_clk";
+
+ pinctrl-names = "panel_active", "panel_suspend";
+ pinctrl-0 = <&sde_dsi_active &sde_te_active>;
+ pinctrl-1 = <&sde_dsi_suspend &sde_te_suspend>;
+
+ qcom,dsi-panel = <&dsi_sim_dsc_375_cmd>;
+ };
+
+ dsi_dual_sim_dsc_375_cmd_display: qcom,dsi-display@9 {
+ compatible = "qcom,dsi-display";
+ label = "dsi_dual_sim_dsc_375_cmd_display";
+ qcom,display-type = "primary";
+
+ qcom,dsi-ctrl = <&mdss_dsi0 &mdss_dsi1>;
+ qcom,dsi-phy = <&mdss_dsi_phy0 &mdss_dsi_phy1>;
+ clocks = <&mdss_dsi0_pll BYTECLK_MUX_0_CLK>,
+ <&mdss_dsi0_pll PCLK_MUX_0_CLK>;
+ clock-names = "src_byte_clk", "src_pixel_clk";
+
+ pinctrl-names = "panel_active", "panel_suspend";
+ pinctrl-0 = <&sde_dsi_active &sde_te_active>;
+ pinctrl-1 = <&sde_dsi_suspend &sde_te_suspend>;
+
+ qcom,dsi-panel = <&dsi_dual_sim_dsc_375_cmd>;
+ };
+
+ sde_wb: qcom,wb-display@0 {
+ compatible = "qcom,wb-display";
+ cell-index = <0>;
+ label = "wb_display";
+ };
+
+ ext_disp: qcom,msm-ext-disp {
+ compatible = "qcom,msm-ext-disp";
+ status = "disabled";
+
+ ext_disp_audio_codec: qcom,msm-ext-disp-audio-codec-rx {
+ compatible = "qcom,msm-ext-disp-audio-codec-rx";
+ };
+ };
+
+ sde_dp: qcom,dp_display@0{
+ cell-index = <0>;
+ compatible = "qcom,dp-display";
+ status = "disabled";
+
+ gdsc-supply = <&mdss_core_gdsc>;
+ vdda-1p2-supply = <&pm660_l1>;
+ vdda-0p9-supply = <&pm660l_l1>;
+
+ reg = <0xae90000 0xa84>,
+ <0x88eaa00 0x200>,
+ <0x88ea200 0x200>,
+ <0x88ea600 0x200>,
+ <0xaf02000 0x1a0>,
+ <0x780000 0x621c>,
+ <0x88ea030 0x10>,
+ <0x0aee1000 0x034>;
+ reg-names = "dp_ctrl", "dp_phy", "dp_ln_tx0", "dp_ln_tx1",
+ "dp_mmss_cc", "qfprom_physical", "dp_pll",
+ "hdcp_physical";
+
+ interrupt-parent = <&mdss_mdp>;
+ interrupts = <12 0>;
+
+ clocks = <&clock_dispcc DISP_CC_MDSS_DP_AUX_CLK>,
+ <&clock_rpmh RPMH_CXO_CLK>,
+ <&clock_gcc GCC_USB3_PRIM_CLKREF_CLK>,
+ <&clock_gcc GCC_USB_PHY_CFG_AHB2PHY_CLK>,
+ <&clock_gcc GCC_USB3_PRIM_PHY_PIPE_CLK>,
+ <&clock_dispcc DISP_CC_MDSS_DP_LINK_CLK>,
+ <&clock_dispcc DISP_CC_MDSS_DP_LINK_INTF_CLK>,
+ <&clock_dispcc DISP_CC_MDSS_DP_PIXEL_CLK>,
+ <&clock_dispcc DISP_CC_MDSS_DP_CRYPTO_CLK>,
+ <&clock_dispcc DISP_CC_MDSS_DP_PIXEL_CLK_SRC>,
+ <&mdss_dp_pll DP_VCO_DIVIDED_CLK_SRC_MUX>;
+ clock-names = "core_aux_clk", "core_usb_ref_clk_src",
+ "core_usb_ref_clk", "core_usb_cfg_ahb_clk",
+ "core_usb_pipe_clk", "ctrl_link_clk",
+ "ctrl_link_iface_clk", "ctrl_pixel_clk",
+ "crypto_clk", "pixel_clk_rcg", "pixel_parent";
+
+ qcom,dp-usbpd-detection = <&pm660_pdphy>;
+ qcom,ext-disp = <&ext_disp>;
+
+ qcom,aux-cfg0-settings = [20 00];
+ qcom,aux-cfg1-settings = [24 13 23 1d];
+ qcom,aux-cfg2-settings = [28 24];
+ qcom,aux-cfg3-settings = [2c 00];
+ qcom,aux-cfg4-settings = [30 0a];
+ qcom,aux-cfg5-settings = [34 26];
+ qcom,aux-cfg6-settings = [38 0a];
+ qcom,aux-cfg7-settings = [3c 03];
+ qcom,aux-cfg8-settings = [40 bb];
+ qcom,aux-cfg9-settings = [44 03];
+
+ qcom,max-pclk-frequency-khz = <675000>;
+
+ qcom,core-supply-entries {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ qcom,core-supply-entry@0 {
+ reg = <0>;
+ qcom,supply-name = "gdsc";
+ qcom,supply-min-voltage = <0>;
+ qcom,supply-max-voltage = <0>;
+ qcom,supply-enable-load = <0>;
+ qcom,supply-disable-load = <0>;
+ };
+ };
+
+ qcom,ctrl-supply-entries {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ qcom,ctrl-supply-entry@0 {
+ reg = <0>;
+ qcom,supply-name = "vdda-1p2";
+ qcom,supply-min-voltage = <1200000>;
+ qcom,supply-max-voltage = <1200000>;
+ qcom,supply-enable-load = <21800>;
+ qcom,supply-disable-load = <4>;
+ };
+ };
+
+ qcom,phy-supply-entries {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ qcom,phy-supply-entry@0 {
+ reg = <0>;
+ qcom,supply-name = "vdda-0p9";
+ qcom,supply-min-voltage = <880000>;
+ qcom,supply-max-voltage = <880000>;
+ qcom,supply-enable-load = <36000>;
+ qcom,supply-disable-load = <32>;
+ };
+ };
+ };
+};
+
+&sde_dp {
+ status = "disabled";
+ pinctrl-names = "mdss_dp_active", "mdss_dp_sleep";
+ pinctrl-0 = <&sde_dp_aux_active &sde_dp_usbplug_cc_active>;
+ pinctrl-1 = <&sde_dp_aux_suspend &sde_dp_usbplug_cc_suspend>;
+ qcom,aux-en-gpio = <&tlmm 50 0>;
+ qcom,aux-sel-gpio = <&tlmm 40 0>;
+ qcom,usbplug-cc-gpio = <&tlmm 38 0>;
+};
+
+&mdss_mdp {
+ connectors = <&sde_rscc &sde_wb>;
+};
+
+&dsi_dual_nt35597_truly_video {
+ qcom,mdss-dsi-t-clk-post = <0x0D>;
+ qcom,mdss-dsi-t-clk-pre = <0x2D>;
+ qcom,mdss-dsi-display-timings {
+ timing@0{
+ qcom,mdss-dsi-panel-phy-timings = [00 1c 07 07 23 21 07
+ 07 05 03 04 00];
+ qcom,display-topology = <2 0 2>,
+ <1 0 2>;
+ qcom,default-topology-index = <0>;
+ };
+ };
+};
+
+&dsi_dual_nt35597_truly_cmd {
+ qcom,mdss-dsi-t-clk-post = <0x0D>;
+ qcom,mdss-dsi-t-clk-pre = <0x2D>;
+ qcom,mdss-dsi-display-timings {
+ timing@0{
+ qcom,mdss-dsi-panel-phy-timings = [00 1c 07 07 23 21 07
+ 07 05 03 04 00];
+ qcom,display-topology = <2 0 2>,
+ <1 0 2>;
+ qcom,default-topology-index = <0>;
+ };
+ };
+};
+
+&dsi_nt35597_truly_dsc_cmd {
+ qcom,mdss-dsi-t-clk-post = <0x0b>;
+ qcom,mdss-dsi-t-clk-pre = <0x23>;
+ qcom,mdss-dsi-display-timings {
+ timing@0{
+ qcom,mdss-dsi-panel-phy-timings = [00 15 05 05 20 1f 05
+ 05 03 03 04 00];
+ qcom,display-topology = <1 1 1>,
+ <2 2 1>, /* dsc merge */
+ <2 1 1>; /* 3d mux */
+ qcom,default-topology-index = <1>;
+ };
+ };
+};
+
+&dsi_nt35597_truly_dsc_video {
+ qcom,mdss-dsi-t-clk-post = <0x0b>;
+ qcom,mdss-dsi-t-clk-pre = <0x23>;
+ qcom,mdss-dsi-display-timings {
+ timing@0{
+ qcom,mdss-dsi-panel-phy-timings = [00 15 05 05 20 1f 05
+ 04 03 03 04 00];
+ qcom,display-topology = <1 1 1>,
+ <2 2 1>, /* dsc merge */
+ <2 1 1>; /* 3d mux */
+ qcom,default-topology-index = <1>;
+ };
+ };
+};
+
+&dsi_sim_vid {
+ qcom,mdss-dsi-t-clk-post = <0x0d>;
+ qcom,mdss-dsi-t-clk-pre = <0x2d>;
+ qcom,mdss-dsi-display-timings {
+ timing@0{
+ qcom,mdss-dsi-panel-phy-timings = [00 1c 07 07 23 21 07
+ 07 05 03 04 00];
+ qcom,display-topology = <1 0 1>,
+ <2 0 1>;
+ qcom,default-topology-index = <0>;
+ };
+ };
+};
+
+&dsi_dual_sim_vid {
+ qcom,mdss-dsi-t-clk-post = <0x0d>;
+ qcom,mdss-dsi-t-clk-pre = <0x2d>;
+ qcom,mdss-dsi-display-timings {
+ timing@0{
+ qcom,mdss-dsi-panel-phy-timings = [00 1c 07 07 23 21 07
+ 07 05 03 04 00];
+ qcom,display-topology = <2 0 2>,
+ <1 0 2>;
+ qcom,default-topology-index = <0>;
+ };
+ };
+};
+
+&dsi_sim_cmd {
+ qcom,mdss-dsi-t-clk-post = <0x0d>;
+ qcom,mdss-dsi-t-clk-pre = <0x2d>;
+ qcom,mdss-dsi-display-timings {
+ timing@0{
+ qcom,mdss-dsi-panel-phy-timings = [00 1c 07 07 23 21 07
+ 07 05 03 04 00];
+ qcom,display-topology = <1 0 1>,
+ <2 0 1>;
+ qcom,default-topology-index = <0>;
+ };
+ };
+};
+
+&dsi_dual_sim_cmd {
+ qcom,mdss-dsi-t-clk-post = <0x0d>;
+ qcom,mdss-dsi-t-clk-pre = <0x2d>;
+ qcom,mdss-dsi-display-timings {
+ timing@0{
+ qcom,mdss-dsi-panel-phy-timings = [00 24 09 09 26 24 09
+ 09 06 03 04 00];
+ qcom,display-topology = <2 0 2>;
+ qcom,default-topology-index = <0>;
+ };
+ timing@1{
+ qcom,mdss-dsi-panel-phy-timings = [00 1c 07 07 23 21 07
+ 07 05 03 04 00];
+ qcom,display-topology = <2 0 2>,
+ <1 0 2>;
+ qcom,default-topology-index = <0>;
+ };
+ timing@2{
+ qcom,mdss-dsi-panel-phy-timings = [00 18 06 06 21 20 06
+ 06 04 03 04 00];
+ qcom,display-topology = <2 0 2>;
+ qcom,default-topology-index = <0>;
+ };
+ };
+};
+
+&dsi_sim_dsc_375_cmd {
+ qcom,mdss-dsi-t-clk-post = <0x0d>;
+ qcom,mdss-dsi-t-clk-pre = <0x2d>;
+ qcom,mdss-dsi-display-timings {
+ timing@0 { /* 1080p */
+ qcom,mdss-dsi-panel-phy-timings = [00 1A 06 06 22 20 07
+ 07 04 03 04 00];
+ qcom,display-topology = <1 1 1>;
+ qcom,default-topology-index = <0>;
+ };
+ timing@1 { /* qhd */
+ qcom,mdss-dsi-panel-phy-timings = [00 15 05 05 20 1f 05
+ 05 03 03 04 00];
+ qcom,display-topology = <1 1 1>,
+ <2 2 1>, /* dsc merge */
+ <2 1 1>; /* 3d mux */
+ qcom,default-topology-index = <0>;
+ };
+ };
+};
+
+&dsi_dual_sim_dsc_375_cmd {
+ qcom,mdss-dsi-t-clk-post = <0x0d>;
+ qcom,mdss-dsi-t-clk-pre = <0x2d>;
+ qcom,mdss-dsi-display-timings {
+ timing@0 { /* qhd */
+ qcom,mdss-dsi-panel-phy-timings = [00 1c 07 07 23 21 07
+ 07 05 03 04 00];
+ qcom,display-topology = <2 2 2>;
+ qcom,default-topology-index = <0>;
+ };
+ timing@1 { /* 4k */
+ qcom,mdss-dsi-panel-phy-timings = [00 18 06 06 21 20 06
+ 06 04 03 04 00];
+ qcom,display-topology = <2 2 2>;
+ qcom,default-topology-index = <0>;
+ };
+ };
+};
diff --git a/arch/arm64/boot/dts/qcom/sdm670-sde-pll.dtsi b/arch/arm64/boot/dts/qcom/sdm670-sde-pll.dtsi
new file mode 100644
index 0000000..78e5d94
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/sdm670-sde-pll.dtsi
@@ -0,0 +1,110 @@
+/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+&soc {
+ mdss_dsi0_pll: qcom,mdss_dsi_pll@ae94a00 {
+ compatible = "qcom,mdss_dsi_pll_10nm";
+ label = "MDSS DSI 0 PLL";
+ cell-index = <0>;
+ #clock-cells = <1>;
+ reg = <0xae94a00 0x1e0>,
+ <0xae94400 0x800>,
+ <0xaf03000 0x8>;
+ reg-names = "pll_base", "phy_base", "gdsc_base";
+ clocks = <&clock_dispcc DISP_CC_MDSS_AHB_CLK>;
+ clock-names = "iface_clk";
+ clock-rate = <0>;
+ gdsc-supply = <&mdss_core_gdsc>;
+ qcom,platform-supply-entries {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ qcom,platform-supply-entry@0 {
+ reg = <0>;
+ qcom,supply-name = "gdsc";
+ qcom,supply-min-voltage = <0>;
+ qcom,supply-max-voltage = <0>;
+ qcom,supply-enable-load = <0>;
+ qcom,supply-disable-load = <0>;
+ };
+ };
+ };
+
+ mdss_dsi1_pll: qcom,mdss_dsi_pll@ae96a00 {
+ compatible = "qcom,mdss_dsi_pll_10nm";
+ label = "MDSS DSI 1 PLL";
+ cell-index = <1>;
+ #clock-cells = <1>;
+ reg = <0xae96a00 0x1e0>,
+ <0xae96400 0x800>,
+ <0xaf03000 0x8>;
+ reg-names = "pll_base", "phy_base", "gdsc_base";
+ clocks = <&clock_dispcc DISP_CC_MDSS_AHB_CLK>;
+ clock-names = "iface_clk";
+ clock-rate = <0>;
+ gdsc-supply = <&mdss_core_gdsc>;
+ qcom,platform-supply-entries {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ qcom,platform-supply-entry@0 {
+ reg = <0>;
+ qcom,supply-name = "gdsc";
+ qcom,supply-min-voltage = <0>;
+ qcom,supply-max-voltage = <0>;
+ qcom,supply-enable-load = <0>;
+ qcom,supply-disable-load = <0>;
+ };
+ };
+ };
+
+ mdss_dp_pll: qcom,mdss_dp_pll@88ea000 {
+ compatible = "qcom,mdss_dp_pll_10nm";
+ status = "disabled";
+ label = "MDSS DP PLL";
+ cell-index = <0>;
+ #clock-cells = <1>;
+
+ reg = <0x088ea000 0x200>,
+ <0x088eaa00 0x200>,
+ <0x088ea200 0x200>,
+ <0x088ea600 0x200>,
+ <0xaf03000 0x8>;
+ reg-names = "pll_base", "phy_base", "ln_tx0_base",
+ "ln_tx1_base", "gdsc_base";
+
+ gdsc-supply = <&mdss_core_gdsc>;
+
+ clocks = <&clock_dispcc DISP_CC_MDSS_AHB_CLK>,
+ <&clock_rpmh RPMH_CXO_CLK>,
+ <&clock_gcc GCC_USB3_PRIM_CLKREF_CLK>,
+ <&clock_gcc GCC_USB_PHY_CFG_AHB2PHY_CLK>,
+ <&clock_gcc GCC_USB3_PRIM_PHY_PIPE_CLK>;
+ clock-names = "iface_clk", "ref_clk_src", "ref_clk",
+ "cfg_ahb_clk", "pipe_clk";
+ clock-rate = <0>;
+
+ qcom,platform-supply-entries {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ qcom,platform-supply-entry@0 {
+ reg = <0>;
+ qcom,supply-name = "gdsc";
+ qcom,supply-min-voltage = <0>;
+ qcom,supply-max-voltage = <0>;
+ qcom,supply-enable-load = <0>;
+ qcom,supply-disable-load = <0>;
+ };
+
+ };
+ };
+
+};
diff --git a/arch/arm64/boot/dts/qcom/sdm670-sde.dtsi b/arch/arm64/boot/dts/qcom/sdm670-sde.dtsi
new file mode 100644
index 0000000..bb30a20
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/sdm670-sde.dtsi
@@ -0,0 +1,532 @@
+/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+&soc {
+ mdss_mdp: qcom,mdss_mdp@ae00000 {
+ compatible = "qcom,sde-kms";
+ reg = <0x0ae00000 0x81d40>,
+ <0x0aeb0000 0x2008>,
+ <0x0aeac000 0xf0>;
+ reg-names = "mdp_phys",
+ "vbif_phys",
+ "regdma_phys";
+
+ clocks =
+ <&clock_gcc GCC_DISP_AHB_CLK>,
+ <&clock_gcc GCC_DISP_AXI_CLK>,
+ <&clock_dispcc DISP_CC_MDSS_AHB_CLK>,
+ <&clock_dispcc DISP_CC_MDSS_AXI_CLK>,
+ <&clock_dispcc DISP_CC_MDSS_MDP_CLK>,
+ <&clock_dispcc DISP_CC_MDSS_VSYNC_CLK>;
+ clock-names = "gcc_iface", "gcc_bus", "iface_clk",
+ "bus_clk", "core_clk", "vsync_clk";
+ clock-rate = <0 0 0 0 300000000 19200000 0>;
+ clock-max-rate = <0 0 0 0 412500000 19200000 0>;
+
+ sde-vdd-supply = <&mdss_core_gdsc>;
+
+ /* interrupt config */
+ interrupt-parent = <&pdc>;
+ interrupts = <0 83 0>;
+ interrupt-controller;
+ #interrupt-cells = <1>;
+ iommus = <&apps_smmu 0x880 0x8>,
+ <&apps_smmu 0xc80 0x8>;
+
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ /* hw blocks */
+ qcom,sde-off = <0x1000>;
+ qcom,sde-len = <0x45C>;
+
+ qcom,sde-ctl-off = <0x2000 0x2200 0x2400
+ 0x2600 0x2800>;
+ qcom,sde-ctl-size = <0xE4>;
+
+ qcom,sde-mixer-off = <0x45000 0x46000 0x47000
+ 0x48000 0x49000 0x4a000>;
+ qcom,sde-mixer-size = <0x320>;
+
+ qcom,sde-dspp-top-off = <0x1300>;
+ qcom,sde-dspp-top-size = <0xc>;
+
+ qcom,sde-dspp-off = <0x55000 0x57000>;
+ qcom,sde-dspp-size = <0x17e0>;
+
+ qcom,sde-wb-off = <0x66000>;
+ qcom,sde-wb-size = <0x2c8>;
+ qcom,sde-wb-xin-id = <6>;
+ qcom,sde-wb-id = <2>;
+ qcom,sde-wb-clk-ctrl = <0x3b8 24>;
+
+ qcom,sde-intf-off = <0x6b000 0x6b800
+ 0x6c000 0x6c800>;
+ qcom,sde-intf-size = <0x280>;
+
+ qcom,sde-intf-type = "dp", "dsi", "dsi", "dp";
+ qcom,sde-pp-off = <0x71000 0x71800
+ 0x72000 0x72800 0x73000>;
+ qcom,sde-pp-slave = <0x0 0x0 0x0 0x0 0x1>;
+ qcom,sde-pp-size = <0xd4>;
+
+ qcom,sde-te2-off = <0x2000 0x2000 0x0 0x0 0x0>;
+ qcom,sde-cdm-off = <0x7a200>;
+ qcom,sde-cdm-size = <0x224>;
+
+ qcom,sde-dsc-off = <0x81000 0x81400>;
+ qcom,sde-dsc-size = <0x140>;
+
+ qcom,sde-dither-off = <0x30e0 0x30e0 0x30e0 0x30e0 0x0>;
+ qcom,sde-dither-version = <0x00010000>;
+ qcom,sde-dither-size = <0x20>;
+
+ qcom,sde-sspp-type = "vig", "vig",
+ "dma", "dma", "dma";
+
+ qcom,sde-sspp-off = <0x5000 0x7000 0x25000 0x27000 0x29000>;
+ qcom,sde-sspp-src-size = <0x1c8>;
+
+ qcom,sde-sspp-xin-id = <0 4 1 5 9>;
+ qcom,sde-sspp-excl-rect = <1 1 1 1 1>;
+ qcom,sde-sspp-smart-dma-priority = <4 5 1 2 3>;
+ qcom,sde-smart-dma-rev = "smart_dma_v2";
+
+ qcom,sde-mixer-pair-mask = <2 1 6 0 0 3>;
+
+ qcom,sde-mixer-blend-op-off = <0x20 0x38 0x50 0x68 0x80 0x98
+ 0xb0 0xc8 0xe0 0xf8 0x110>;
+
+ /* offsets are relative to "mdp_phys + qcom,sde-off */
+ qcom,sde-sspp-clk-ctrl =
+ <0x2ac 0>, <0x2b4 0>,
+ <0x2ac 8>, <0x2b4 8>, <0x2bc 8>;
+ qcom,sde-sspp-csc-off = <0x1a00>;
+ qcom,sde-csc-type = "csc-10bit";
+ qcom,sde-qseed-type = "qseedv3";
+ qcom,sde-sspp-qseed-off = <0xa00>;
+ qcom,sde-mixer-linewidth = <2560>;
+ qcom,sde-sspp-linewidth = <2560>;
+ qcom,sde-wb-linewidth = <4096>;
+ qcom,sde-mixer-blendstages = <0xb>;
+ qcom,sde-highest-bank-bit = <0x1>;
+ qcom,sde-ubwc-version = <0x200>;
+ qcom,sde-panic-per-pipe;
+ qcom,sde-has-cdp;
+ qcom,sde-has-src-split;
+ qcom,sde-has-dim-layer;
+ qcom,sde-has-idle-pc;
+ qcom,sde-max-bw-low-kbps = <9600000>;
+ qcom,sde-max-bw-high-kbps = <9600000>;
+ qcom,sde-dram-channels = <2>;
+ qcom,sde-num-nrt-paths = <0>;
+ qcom,sde-dspp-ad-version = <0x00040000>;
+ qcom,sde-dspp-ad-off = <0x28000 0x27000>;
+
+ qcom,sde-vbif-off = <0>;
+ qcom,sde-vbif-size = <0x1040>;
+ qcom,sde-vbif-id = <0>;
+ qcom,sde-vbif-memtype-0 = <3 3 3 3 3 3 3 3>;
+ qcom,sde-vbif-memtype-1 = <3 3 3 3 3 3>;
+
+ qcom,sde-vbif-qos-rt-remap = <3 3 4 4 5 5 6 6>;
+ qcom,sde-vbif-qos-nrt-remap = <3 3 3 3 3 3 3 3>;
+
+ qcom,sde-danger-lut = <0x0000000f 0x0000ffff 0x00000000
+ 0x00000000>;
+ qcom,sde-safe-lut = <0xfffc 0xff00 0xffff 0xffff>;
+ qcom,sde-qos-lut-linear =
+ <4 0x00000000 0x00000357>,
+ <5 0x00000000 0x00003357>,
+ <6 0x00000000 0x00023357>,
+ <7 0x00000000 0x00223357>,
+ <8 0x00000000 0x02223357>,
+ <9 0x00000000 0x22223357>,
+ <10 0x00000002 0x22223357>,
+ <11 0x00000022 0x22223357>,
+ <12 0x00000222 0x22223357>,
+ <13 0x00002222 0x22223357>,
+ <14 0x00012222 0x22223357>,
+ <0 0x00112222 0x22223357>;
+ qcom,sde-qos-lut-macrotile =
+ <10 0x00000003 0x44556677>,
+ <11 0x00000033 0x44556677>,
+ <12 0x00000233 0x44556677>,
+ <13 0x00002233 0x44556677>,
+ <14 0x00012233 0x44556677>,
+ <0 0x00112233 0x44556677>;
+ qcom,sde-qos-lut-nrt =
+ <0 0x00000000 0x00000000>;
+ qcom,sde-qos-lut-cwb =
+ <0 0x75300000 0x00000000>;
+
+ qcom,sde-cdp-setting = <1 1>, <1 0>;
+
+ qcom,sde-inline-rotator = <&mdss_rotator 0>;
+ qcom,sde-inline-rot-xin = <10 11>;
+ qcom,sde-inline-rot-xin-type = "sspp", "wb";
+
+ /* offsets are relative to "mdp_phys + qcom,sde-off */
+ qcom,sde-inline-rot-clk-ctrl = <0x2bc 0x8>, <0x2bc 0xc>;
+
+ qcom,sde-reg-dma-off = <0>;
+ qcom,sde-reg-dma-version = <0x1>;
+ qcom,sde-reg-dma-trigger-off = <0x119c>;
+
+ qcom,sde-sspp-vig-blocks {
+ qcom,sde-vig-csc-off = <0x1a00>;
+ qcom,sde-vig-qseed-off = <0xa00>;
+ qcom,sde-vig-qseed-size = <0xa0>;
+ };
+
+ qcom,sde-dspp-blocks {
+ qcom,sde-dspp-igc = <0x0 0x00030001>;
+ qcom,sde-dspp-vlut = <0xa00 0x00010008>;
+ qcom,sde-dspp-gamut = <0x1000 0x00040000>;
+ qcom,sde-dspp-pcc = <0x1700 0x00040000>;
+ qcom,sde-dspp-gc = <0x17c0 0x00010008>;
+ };
+
+ qcom,platform-supply-entries {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ qcom,platform-supply-entry@0 {
+ reg = <0>;
+ qcom,supply-name = "sde-vdd";
+ qcom,supply-min-voltage = <0>;
+ qcom,supply-max-voltage = <0>;
+ qcom,supply-enable-load = <0>;
+ qcom,supply-disable-load = <0>;
+ };
+ };
+
+ smmu_sde_sec: qcom,smmu_sde_sec_cb {
+ compatible = "qcom,smmu_sde_sec";
+ iommus = <&apps_smmu 0x881 0x8>,
+ <&apps_smmu 0xc81 0x8>;
+ };
+
+ /* data and reg bus scale settings */
+ qcom,sde-data-bus {
+ qcom,msm-bus,name = "mdss_sde_mnoc";
+ qcom,msm-bus,num-cases = <3>;
+ qcom,msm-bus,num-paths = <2>;
+ qcom,msm-bus,vectors-KBps =
+ <22 773 0 0>, <23 773 0 0>,
+ <22 773 0 6400000>, <23 773 0 6400000>,
+ <22 773 0 6400000>, <23 773 0 6400000>;
+ };
+
+ qcom,sde-llcc-bus {
+ qcom,msm-bus,name = "mdss_sde_llcc";
+ qcom,msm-bus,num-cases = <3>;
+ qcom,msm-bus,num-paths = <1>;
+ qcom,msm-bus,vectors-KBps =
+ <132 770 0 0>,
+ <132 770 0 6400000>,
+ <132 770 0 6400000>;
+ };
+
+ qcom,sde-ebi-bus {
+ qcom,msm-bus,name = "mdss_sde_ebi";
+ qcom,msm-bus,num-cases = <3>;
+ qcom,msm-bus,num-paths = <1>;
+ qcom,msm-bus,vectors-KBps =
+ <129 512 0 0>,
+ <129 512 0 6400000>,
+ <129 512 0 6400000>;
+ };
+
+ qcom,sde-reg-bus {
+ qcom,msm-bus,name = "mdss_reg";
+ qcom,msm-bus,num-cases = <4>;
+ qcom,msm-bus,num-paths = <1>;
+ qcom,msm-bus,active-only;
+ qcom,msm-bus,vectors-KBps =
+ <1 590 0 0>,
+ <1 590 0 76800>,
+ <1 590 0 150000>,
+ <1 590 0 300000>;
+ };
+ };
+
+ sde_rscc: qcom,sde_rscc@af20000 {
+ cell-index = <0>;
+ compatible = "qcom,sde-rsc";
+ reg = <0xaf20000 0x1c44>,
+ <0xaf30000 0x3fd4>;
+ reg-names = "drv", "wrapper";
+ qcom,sde-rsc-version = <1>;
+
+ vdd-supply = <&mdss_core_gdsc>;
+ clocks = <&clock_dispcc DISP_CC_MDSS_RSCC_VSYNC_CLK>,
+ <&clock_dispcc DISP_CC_MDSS_RSCC_AHB_CLK>;
+ clock-names = "vsync_clk", "iface_clk";
+ clock-rate = <0 0>;
+
+ qcom,sde-dram-channels = <2>;
+
+ mboxes = <&disp_rsc 0>;
+ mbox-names = "disp_rsc";
+
+ /* data and reg bus scale settings */
+ qcom,sde-data-bus {
+ qcom,msm-bus,name = "disp_rsc_mnoc";
+ qcom,msm-bus,active-only;
+ qcom,msm-bus,num-cases = <3>;
+ qcom,msm-bus,num-paths = <2>;
+ qcom,msm-bus,vectors-KBps =
+ <20003 20515 0 0>, <20004 20515 0 0>,
+ <20003 20515 0 6400000>, <20004 20515 0 6400000>,
+ <20003 20515 0 6400000>, <20004 20515 0 6400000>;
+ };
+
+ qcom,sde-llcc-bus {
+ qcom,msm-bus,name = "disp_rsc_llcc";
+ qcom,msm-bus,active-only;
+ qcom,msm-bus,num-cases = <3>;
+ qcom,msm-bus,num-paths = <1>;
+ qcom,msm-bus,vectors-KBps =
+ <20001 20513 0 0>,
+ <20001 20513 0 6400000>,
+ <20001 20513 0 6400000>;
+ };
+
+ qcom,sde-ebi-bus {
+ qcom,msm-bus,name = "disp_rsc_ebi";
+ qcom,msm-bus,active-only;
+ qcom,msm-bus,num-cases = <3>;
+ qcom,msm-bus,num-paths = <1>;
+ qcom,msm-bus,vectors-KBps =
+ <20000 20512 0 0>,
+ <20000 20512 0 6400000>,
+ <20000 20512 0 6400000>;
+ };
+ };
+
+ mdss_rotator: qcom,mdss_rotator@ae00000 {
+ compatible = "qcom,sde_rotator";
+ reg = <0x0ae00000 0xac000>,
+ <0x0aeb8000 0x3000>;
+ reg-names = "mdp_phys",
+ "rot_vbif_phys";
+
+ #list-cells = <1>;
+
+ qcom,mdss-rot-mode = <1>;
+ qcom,mdss-highest-bank-bit = <0x1>;
+
+ /* Bus Scale Settings */
+ qcom,msm-bus,name = "mdss_rotator";
+ qcom,msm-bus,num-cases = <3>;
+ qcom,msm-bus,num-paths = <1>;
+ qcom,msm-bus,vectors-KBps =
+ <25 512 0 0>,
+ <25 512 0 6400000>,
+ <25 512 0 6400000>;
+
+ rot-vdd-supply = <&mdss_core_gdsc>;
+ qcom,supply-names = "rot-vdd";
+
+ clocks =
+ <&clock_gcc GCC_DISP_AHB_CLK>,
+ <&clock_gcc GCC_DISP_AXI_CLK>,
+ <&clock_dispcc DISP_CC_MDSS_AHB_CLK>,
+ <&clock_dispcc DISP_CC_MDSS_ROT_CLK>,
+ <&clock_dispcc DISP_CC_MDSS_AXI_CLK>;
+ clock-names = "gcc_iface", "gcc_bus",
+ "iface_clk", "rot_clk", "axi_clk";
+
+ interrupt-parent = <&mdss_mdp>;
+ interrupts = <2 0>;
+
+ /* Offline rotator QoS setting */
+ qcom,mdss-rot-vbif-qos-setting = <3 3 3 3 3 3 3 3>;
+ qcom,mdss-rot-vbif-memtype = <3 3>;
+ qcom,mdss-rot-cdp-setting = <1 1>;
+ qcom,mdss-rot-qos-lut = <0x0 0x0 0x0 0x0>;
+ qcom,mdss-rot-danger-lut = <0x0 0x0>;
+ qcom,mdss-rot-safe-lut = <0x0000ffff 0x0000ffff>;
+
+ /* Inline rotator QoS Setting */
+ /* setting default register values for RD - qos/danger/safe */
+ qcom,mdss-inline-rot-qos-lut = <0x44556677 0x00112233
+ 0x44556677 0x00112233>;
+ qcom,mdss-inline-rot-danger-lut = <0x0055aaff 0x0000ffff>;
+ qcom,mdss-inline-rot-safe-lut = <0x0000f000 0x0000ff00>;
+
+ qcom,mdss-default-ot-rd-limit = <32>;
+ qcom,mdss-default-ot-wr-limit = <32>;
+
+ qcom,mdss-sbuf-headroom = <20>;
+
+ cache-slice-names = "rotator";
+ cache-slices = <&llcc 4>;
+
+ /* reg bus scale settings */
+ rot_reg: qcom,rot-reg-bus {
+ qcom,msm-bus,name = "mdss_rot_reg";
+ qcom,msm-bus,num-cases = <2>;
+ qcom,msm-bus,num-paths = <1>;
+ qcom,msm-bus,active-only;
+ qcom,msm-bus,vectors-KBps =
+ <1 590 0 0>,
+ <1 590 0 76800>;
+ };
+
+ smmu_rot_unsec: qcom,smmu_rot_unsec_cb {
+ compatible = "qcom,smmu_sde_rot_unsec";
+ iommus = <&apps_smmu 0x1090 0x0>;
+ };
+
+ smmu_rot_sec: qcom,smmu_rot_sec_cb {
+ compatible = "qcom,smmu_sde_rot_sec";
+ iommus = <&apps_smmu 0x1091 0x0>;
+ };
+ };
+
+ mdss_dsi0: qcom,mdss_dsi_ctrl0@ae94000 {
+ compatible = "qcom,dsi-ctrl-hw-v2.2";
+ label = "dsi-ctrl-0";
+ cell-index = <0>;
+ reg = <0xae94000 0x400>,
+ <0xaf08000 0x4>;
+ reg-names = "dsi_ctrl", "disp_cc_base";
+ interrupt-parent = <&mdss_mdp>;
+ interrupts = <4 0>;
+ vdda-1p2-supply = <&pm660_l1>;
+ clocks = <&clock_dispcc DISP_CC_MDSS_BYTE0_CLK>,
+ <&clock_dispcc DISP_CC_MDSS_BYTE0_CLK_SRC>,
+ <&clock_dispcc DISP_CC_MDSS_BYTE0_INTF_CLK>,
+ <&clock_dispcc DISP_CC_MDSS_PCLK0_CLK>,
+ <&clock_dispcc DISP_CC_MDSS_PCLK0_CLK_SRC>,
+ <&clock_dispcc DISP_CC_MDSS_ESC0_CLK>;
+ clock-names = "byte_clk", "byte_clk_rcg", "byte_intf_clk",
+ "pixel_clk", "pixel_clk_rcg",
+ "esc_clk";
+
+ qcom,ctrl-supply-entries {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ qcom,ctrl-supply-entry@0 {
+ reg = <0>;
+ qcom,supply-name = "vdda-1p2";
+ qcom,supply-min-voltage = <1200000>;
+ qcom,supply-max-voltage = <1200000>;
+ qcom,supply-enable-load = <21800>;
+ qcom,supply-disable-load = <4>;
+ };
+ };
+ };
+
+ mdss_dsi1: qcom,mdss_dsi_ctrl1@ae96000 {
+ compatible = "qcom,dsi-ctrl-hw-v2.2";
+ label = "dsi-ctrl-1";
+ cell-index = <1>;
+ reg = <0xae96000 0x400>,
+ <0xaf08000 0x4>;
+ reg-names = "dsi_ctrl", "disp_cc_base";
+ interrupt-parent = <&mdss_mdp>;
+ interrupts = <5 0>;
+ vdda-1p2-supply = <&pm660_l1>;
+ clocks = <&clock_dispcc DISP_CC_MDSS_BYTE1_CLK>,
+ <&clock_dispcc DISP_CC_MDSS_BYTE1_CLK_SRC>,
+ <&clock_dispcc DISP_CC_MDSS_BYTE1_INTF_CLK>,
+ <&clock_dispcc DISP_CC_MDSS_PCLK1_CLK>,
+ <&clock_dispcc DISP_CC_MDSS_PCLK1_CLK_SRC>,
+ <&clock_dispcc DISP_CC_MDSS_ESC1_CLK>;
+ clock-names = "byte_clk", "byte_clk_rcg", "byte_intf_clk",
+ "pixel_clk", "pixel_clk_rcg", "esc_clk";
+ qcom,ctrl-supply-entries {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ qcom,ctrl-supply-entry@0 {
+ reg = <0>;
+ qcom,supply-name = "vdda-1p2";
+ qcom,supply-min-voltage = <1200000>;
+ qcom,supply-max-voltage = <1200000>;
+ qcom,supply-enable-load = <21800>;
+ qcom,supply-disable-load = <4>;
+ };
+ };
+ };
+
+ mdss_dsi_phy0: qcom,mdss_dsi_phy0@ae94400 {
+ compatible = "qcom,dsi-phy-v3.0";
+ label = "dsi-phy-0";
+ cell-index = <0>;
+ reg = <0xae94400 0x7c0>;
+ reg-names = "dsi_phy";
+ gdsc-supply = <&mdss_core_gdsc>;
+ vdda-0p9-supply = <&pm660l_l1>;
+ qcom,platform-strength-ctrl = [55 03
+ 55 03
+ 55 03
+ 55 03
+ 55 00];
+ qcom,platform-lane-config = [00 00 00 00
+ 00 00 00 00
+ 00 00 00 00
+ 00 00 00 00
+ 00 00 00 80];
+ qcom,platform-regulator-settings = [1d 1d 1d 1d 1d];
+ qcom,phy-supply-entries {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ qcom,phy-supply-entry@0 {
+ reg = <0>;
+ qcom,supply-name = "vdda-0p9";
+ qcom,supply-min-voltage = <880000>;
+ qcom,supply-max-voltage = <880000>;
+ qcom,supply-enable-load = <36000>;
+ qcom,supply-disable-load = <32>;
+ };
+ };
+ };
+
+ mdss_dsi_phy1: qcom,mdss_dsi_phy0@ae96400 {
+ compatible = "qcom,dsi-phy-v3.0";
+ label = "dsi-phy-1";
+ cell-index = <1>;
+ reg = <0xae96400 0x7c0>;
+ reg-names = "dsi_phy";
+ gdsc-supply = <&mdss_core_gdsc>;
+ vdda-0p9-supply = <&pm660l_l1>;
+ qcom,platform-strength-ctrl = [55 03
+ 55 03
+ 55 03
+ 55 03
+ 55 00];
+ qcom,platform-regulator-settings = [1d 1d 1d 1d 1d];
+ qcom,platform-lane-config = [00 00 00 00
+ 00 00 00 00
+ 00 00 00 00
+ 00 00 00 00
+ 00 00 00 80];
+ qcom,phy-supply-entries {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ qcom,phy-supply-entry@0 {
+ reg = <0>;
+ qcom,supply-name = "vdda-0p9";
+ qcom,supply-min-voltage = <880000>;
+ qcom,supply-max-voltage = <880000>;
+ qcom,supply-enable-load = <36000>;
+ qcom,supply-disable-load = <32>;
+ };
+ };
+ };
+
+};
diff --git a/arch/arm64/boot/dts/qcom/sdm670-usbc-cdp-overlay.dts b/arch/arm64/boot/dts/qcom/sdm670-usbc-cdp-overlay.dts
index 190b32f..e4e1db5 100644
--- a/arch/arm64/boot/dts/qcom/sdm670-usbc-cdp-overlay.dts
+++ b/arch/arm64/boot/dts/qcom/sdm670-usbc-cdp-overlay.dts
@@ -20,6 +20,7 @@
#include <dt-bindings/interrupt-controller/arm-gic.h>
#include "sdm670-cdp.dtsi"
+#include "sdm670-int-cdc-usbc-audio-overlay.dtsi"
/ {
model = "Qualcomm Technologies, Inc. SDM670 PM660 + PM660L, USB-C Audio, CDP";
diff --git a/arch/arm64/boot/dts/qcom/sdm670-usbc-cdp.dts b/arch/arm64/boot/dts/qcom/sdm670-usbc-cdp.dts
index 45ff83f..80a8423 100644
--- a/arch/arm64/boot/dts/qcom/sdm670-usbc-cdp.dts
+++ b/arch/arm64/boot/dts/qcom/sdm670-usbc-cdp.dts
@@ -15,7 +15,7 @@
#include "sdm670.dtsi"
#include "sdm670-cdp.dtsi"
-
+#include "sdm670-int-cdc-usbc-audio-overlay.dtsi"
/ {
model = "Qualcomm Technologies, Inc. SDM670 PM660 + PM660L, USB-C Audio, CDP";
compatible = "qcom,sdm670-cdp", "qcom,sdm670", "qcom,cdp";
diff --git a/arch/arm64/boot/dts/qcom/sdm670-usbc-external-codec-cdp-overlay.dts b/arch/arm64/boot/dts/qcom/sdm670-usbc-external-codec-cdp-overlay.dts
index 226c2ae..c5bab55 100644
--- a/arch/arm64/boot/dts/qcom/sdm670-usbc-external-codec-cdp-overlay.dts
+++ b/arch/arm64/boot/dts/qcom/sdm670-usbc-external-codec-cdp-overlay.dts
@@ -21,6 +21,7 @@
#include "sdm670-cdp.dtsi"
#include "sdm670-external-codec.dtsi"
+#include "sdm670-ext-cdc-usbc-audio.dtsi"
/ {
model = "Qualcomm Technologies, Inc. SDM670 PM660+PM660L, USB-C Audio, Ext. Audio Codec CDP";
diff --git a/arch/arm64/boot/dts/qcom/sdm670-usbc-external-codec-cdp.dts b/arch/arm64/boot/dts/qcom/sdm670-usbc-external-codec-cdp.dts
index 8928f80..2c53334 100644
--- a/arch/arm64/boot/dts/qcom/sdm670-usbc-external-codec-cdp.dts
+++ b/arch/arm64/boot/dts/qcom/sdm670-usbc-external-codec-cdp.dts
@@ -16,6 +16,7 @@
#include "sdm670.dtsi"
#include "sdm670-cdp.dtsi"
#include "sdm670-external-codec.dtsi"
+#include "sdm670-ext-cdc-usbc-audio.dtsi"
/ {
model = "Qualcomm Technologies, Inc. SDM 670 PM660+PM660L, USB-C Audio, Ext. Audio Codec CDP";
diff --git a/arch/arm64/boot/dts/qcom/sdm670-usbc-external-codec-mtp-overlay.dts b/arch/arm64/boot/dts/qcom/sdm670-usbc-external-codec-mtp-overlay.dts
index 78d1dfa..09ba184 100644
--- a/arch/arm64/boot/dts/qcom/sdm670-usbc-external-codec-mtp-overlay.dts
+++ b/arch/arm64/boot/dts/qcom/sdm670-usbc-external-codec-mtp-overlay.dts
@@ -21,7 +21,7 @@
#include "sdm670-mtp.dtsi"
#include "sdm670-external-codec.dtsi"
-
+#include "sdm670-ext-cdc-usbc-audio.dtsi"
/ {
model = "Qualcomm Technologies, Inc. SDM670 PM660+PM660L, USB-C Audio, Ext. Audio Codec MTP";
compatible = "qcom,sdm670-mtp", "qcom,sdm670", "qcom,mtp";
diff --git a/arch/arm64/boot/dts/qcom/sdm670-usbc-external-codec-mtp.dts b/arch/arm64/boot/dts/qcom/sdm670-usbc-external-codec-mtp.dts
index 5628e92..7a19819 100644
--- a/arch/arm64/boot/dts/qcom/sdm670-usbc-external-codec-mtp.dts
+++ b/arch/arm64/boot/dts/qcom/sdm670-usbc-external-codec-mtp.dts
@@ -16,6 +16,7 @@
#include "sdm670.dtsi"
#include "sdm670-mtp.dtsi"
#include "sdm670-external-codec.dtsi"
+#include "sdm670-ext-cdc-usbc-audio.dtsi"
/ {
model = "Qualcomm Technologies, Inc. SDM 670 PM660+PM660L, USB-C Audio, Ext. Audio Codec MTP";
diff --git a/arch/arm64/boot/dts/qcom/sdm670-usbc-external-codec-pm660a-cdp-overlay.dts b/arch/arm64/boot/dts/qcom/sdm670-usbc-external-codec-pm660a-cdp-overlay.dts
index c1891a4..71db0f7 100644
--- a/arch/arm64/boot/dts/qcom/sdm670-usbc-external-codec-pm660a-cdp-overlay.dts
+++ b/arch/arm64/boot/dts/qcom/sdm670-usbc-external-codec-pm660a-cdp-overlay.dts
@@ -22,6 +22,7 @@
#include "sdm670-cdp.dtsi"
#include "pm660a.dtsi"
#include "sdm670-external-codec.dtsi"
+#include "sdm670-ext-cdc-usbc-audio.dtsi"
/ {
model = "Qualcomm Technologies, Inc. SDM670 PM660+PM660A, USB-C Audio, Ext. Audio Codec CDP";
diff --git a/arch/arm64/boot/dts/qcom/sdm670-usbc-external-codec-pm660a-cdp.dts b/arch/arm64/boot/dts/qcom/sdm670-usbc-external-codec-pm660a-cdp.dts
index c059113..ff641e6 100644
--- a/arch/arm64/boot/dts/qcom/sdm670-usbc-external-codec-pm660a-cdp.dts
+++ b/arch/arm64/boot/dts/qcom/sdm670-usbc-external-codec-pm660a-cdp.dts
@@ -17,6 +17,7 @@
#include "sdm670-cdp.dtsi"
#include "pm660a.dtsi"
#include "sdm670-external-codec.dtsi"
+#include "sdm670-ext-cdc-usbc-audio.dtsi"
/ {
model = "Qualcomm Technologies, Inc. SDM 670 PM660+PM660A, USB-C Audio, Ext. Audio Codec CDP";
diff --git a/arch/arm64/boot/dts/qcom/sdm670-usbc-external-codec-pm660a-mtp-overlay.dts b/arch/arm64/boot/dts/qcom/sdm670-usbc-external-codec-pm660a-mtp-overlay.dts
index c54e299..c2e6f58 100644
--- a/arch/arm64/boot/dts/qcom/sdm670-usbc-external-codec-pm660a-mtp-overlay.dts
+++ b/arch/arm64/boot/dts/qcom/sdm670-usbc-external-codec-pm660a-mtp-overlay.dts
@@ -22,6 +22,7 @@
#include "sdm670-mtp.dtsi"
#include "pm660a.dtsi"
#include "sdm670-external-codec.dtsi"
+#include "sdm670-ext-cdc-usbc-audio.dtsi"
/ {
model = "Qualcomm Technologies, Inc. SDM670 PM660+PM660A, USB-C Audio, Ext. Audio Codec MTP";
diff --git a/arch/arm64/boot/dts/qcom/sdm670-usbc-external-codec-pm660a-mtp.dts b/arch/arm64/boot/dts/qcom/sdm670-usbc-external-codec-pm660a-mtp.dts
index d09b5e5..2cd68f1 100644
--- a/arch/arm64/boot/dts/qcom/sdm670-usbc-external-codec-pm660a-mtp.dts
+++ b/arch/arm64/boot/dts/qcom/sdm670-usbc-external-codec-pm660a-mtp.dts
@@ -17,6 +17,7 @@
#include "sdm670-mtp.dtsi"
#include "pm660a.dtsi"
#include "sdm670-external-codec.dtsi"
+#include "sdm670-ext-cdc-usbc-audio.dtsi"
/ {
model = "Qualcomm Technologies, Inc. SDM 670 PM660+PM660A, USB-C Audio, Ext. Audio Codec MTP";
diff --git a/arch/arm64/boot/dts/qcom/sdm670-usbc-mtp-overlay.dts b/arch/arm64/boot/dts/qcom/sdm670-usbc-mtp-overlay.dts
index d8c4102..3d5c04e 100644
--- a/arch/arm64/boot/dts/qcom/sdm670-usbc-mtp-overlay.dts
+++ b/arch/arm64/boot/dts/qcom/sdm670-usbc-mtp-overlay.dts
@@ -20,6 +20,7 @@
#include <dt-bindings/interrupt-controller/arm-gic.h>
#include "sdm670-mtp.dtsi"
+#include "sdm670-int-cdc-usbc-audio-overlay.dtsi"
/ {
model = "Qualcomm Technologies, Inc. SDM670 PM660 + PM660L, USB-C Audio, MTP";
diff --git a/arch/arm64/boot/dts/qcom/sdm670-usbc-mtp.dts b/arch/arm64/boot/dts/qcom/sdm670-usbc-mtp.dts
index b9bb3ef..8449625 100644
--- a/arch/arm64/boot/dts/qcom/sdm670-usbc-mtp.dts
+++ b/arch/arm64/boot/dts/qcom/sdm670-usbc-mtp.dts
@@ -15,6 +15,7 @@
#include "sdm670.dtsi"
#include "sdm670-mtp.dtsi"
+#include "sdm670-int-cdc-usbc-audio-overlay.dtsi"
/ {
model = "Qualcomm Technologies, Inc. SDM670 PM660 + PM660L, USB-C Audio, MTP";
diff --git a/arch/arm64/boot/dts/qcom/sdm670-usbc-pm660a-cdp-overlay.dts b/arch/arm64/boot/dts/qcom/sdm670-usbc-pm660a-cdp-overlay.dts
index 95df620..6a26d95 100644
--- a/arch/arm64/boot/dts/qcom/sdm670-usbc-pm660a-cdp-overlay.dts
+++ b/arch/arm64/boot/dts/qcom/sdm670-usbc-pm660a-cdp-overlay.dts
@@ -21,6 +21,7 @@
#include "sdm670-cdp.dtsi"
#include "pm660a.dtsi"
+#include "sdm670-int-cdc-usbc-audio-overlay.dtsi"
/ {
model = "Qualcomm Technologies, Inc. SDM670 PM660 + PM660A, USB-C Audio, CDP";
diff --git a/arch/arm64/boot/dts/qcom/sdm670-usbc-pm660a-cdp.dts b/arch/arm64/boot/dts/qcom/sdm670-usbc-pm660a-cdp.dts
index 5e33308..1871b45 100644
--- a/arch/arm64/boot/dts/qcom/sdm670-usbc-pm660a-cdp.dts
+++ b/arch/arm64/boot/dts/qcom/sdm670-usbc-pm660a-cdp.dts
@@ -16,6 +16,7 @@
#include "sdm670.dtsi"
#include "sdm670-cdp.dtsi"
#include "pm660a.dtsi"
+#include "sdm670-int-cdc-usbc-audio-overlay.dtsi"
/ {
model = "Qualcomm Technologies, Inc. SDM670 PM660 + PM660A, USB-C Audio, CDP";
diff --git a/arch/arm64/boot/dts/qcom/sdm670-usbc-pm660a-mtp-overlay.dts b/arch/arm64/boot/dts/qcom/sdm670-usbc-pm660a-mtp-overlay.dts
index 226a46b..d565cdd 100644
--- a/arch/arm64/boot/dts/qcom/sdm670-usbc-pm660a-mtp-overlay.dts
+++ b/arch/arm64/boot/dts/qcom/sdm670-usbc-pm660a-mtp-overlay.dts
@@ -21,6 +21,7 @@
#include "sdm670-mtp.dtsi"
#include "pm660a.dtsi"
+#include "sdm670-int-cdc-usbc-audio-overlay.dtsi"
/ {
model = "Qualcomm Technologies, Inc. SDM670 PM660 + PM660A, USB-C Audio, MTP";
diff --git a/arch/arm64/boot/dts/qcom/sdm670-usbc-pm660a-mtp.dts b/arch/arm64/boot/dts/qcom/sdm670-usbc-pm660a-mtp.dts
index ca99736..b288569 100644
--- a/arch/arm64/boot/dts/qcom/sdm670-usbc-pm660a-mtp.dts
+++ b/arch/arm64/boot/dts/qcom/sdm670-usbc-pm660a-mtp.dts
@@ -16,6 +16,7 @@
#include "sdm670.dtsi"
#include "sdm670-mtp.dtsi"
#include "pm660a.dtsi"
+#include "sdm670-int-cdc-usbc-audio-overlay.dtsi"
/ {
model = "Qualcomm Technologies, Inc. SDM670 PM660 + PM660A, USB-C Audio, MTP";
diff --git a/arch/arm64/boot/dts/qcom/sdm670.dtsi b/arch/arm64/boot/dts/qcom/sdm670.dtsi
index 4a2861a..c2fb7b3 100644
--- a/arch/arm64/boot/dts/qcom/sdm670.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm670.dtsi
@@ -23,6 +23,8 @@
#include <dt-bindings/regulator/qcom,rpmh-regulator.h>
#include <dt-bindings/clock/qcom,aop-qmp.h>
+#define MHZ_TO_MBPS(mhz, w) ((mhz * 1000000 * w) / (1024 * 1024))
+
/ {
model = "Qualcomm Technologies, Inc. SDM670";
compatible = "qcom,sdm670";
@@ -536,24 +538,6 @@
reg = <0 0x93d00000 0 0x1e00000>;
};
- pil_ipa_fw_mem: pil_ipa_fw_region@95b00000 {
- compatible = "removed-dma-pool";
- no-map;
- reg = <0 0x95b00000 0 0x10000>;
- };
-
- pil_ipa_gsi_mem: pil_ipa_gsi_region@95b10000 {
- compatible = "removed-dma-pool";
- no-map;
- reg = <0 0x95b10000 0 0x5000>;
- };
-
- pil_gpu_mem: pil_gpu_region@95b15000 {
- compatible = "removed-dma-pool";
- no-map;
- reg = <0 0x95b15000 0 0x1000>;
- };
-
adsp_mem: adsp_region {
compatible = "shared-dma-pool";
alloc-ranges = <0 0x00000000 0 0xffffffff>;
@@ -614,6 +598,10 @@
#include "sdm670-vidc.dtsi"
+#include "sdm670-sde-pll.dtsi"
+
+#include "sdm670-sde.dtsi"
+
&soc {
#address-cells = <1>;
#size-cells = <1>;
@@ -646,6 +634,14 @@
qcom,pipe-attr-ee;
};
+ qcom,qbt1000 {
+ compatible = "qcom,qbt1000";
+ clock-names = "core", "iface";
+ clock-frequency = <25000000>;
+ qcom,ipc-gpio = <&tlmm 121 0>;
+ qcom,finger-detect-gpio = <&tlmm 122 0>;
+ };
+
thermal_zones: thermal-zones {};
tsens0: tsens@c222000 {
@@ -793,6 +789,7 @@
reg-names = "cc_base";
vdd_cx-supply = <&pm660l_s3_level>;
vdd_mx-supply = <&pm660l_s1_level>;
+ qcom,gpu_cc_gmu_clk_src-opp-handle = <&gmu>;
#clock-cells = <1>;
#reset-cells = <1>;
};
@@ -802,6 +799,7 @@
reg = <0x5090000 0x9000>;
reg-names = "cc_base";
vdd_gfx-supply = <&pm660l_s2_level>;
+ qcom,gpu_cc_gx_gfx3d_clk_src-opp-handle = <&msm_gpu>;
#clock-cells = <1>;
#reset-cells = <1>;
};
@@ -2079,12 +2077,12 @@
<MSM_BUS_MASTER_AMPSS_M0 MSM_BUS_SLAVE_LLCC>;
qcom,active-only;
qcom,bw-tbl =
- < 1144 /* 150 MHz */ >,
- < 2288 /* 300 MHz */ >,
- < 3555 /* 466 MHz */ >,
- < 4577 /* 600 MHz */ >,
- < 6149 /* 806 MHz */ >,
- < 7118 /* 933 MHz */ >;
+ < MHZ_TO_MBPS(150, 16) >, /* 2288 MB/s */
+ < MHZ_TO_MBPS(300, 16) >, /* 4577 MB/s */
+ < MHZ_TO_MBPS(466, 16) >, /* 7110 MB/s */
+ < MHZ_TO_MBPS(600, 16) >, /* 9155 MB/s */
+ < MHZ_TO_MBPS(806, 16) >, /* 12298 MB/s */
+ < MHZ_TO_MBPS(933, 16) >; /* 14236 MB/s */
};
bwmon: qcom,cpu-bwmon {
@@ -2104,17 +2102,17 @@
<MSM_BUS_MASTER_LLCC MSM_BUS_SLAVE_EBI_CH0>;
qcom,active-only;
qcom,bw-tbl =
- < 381 /* 100 MHz */ >,
- < 762 /* 200 MHz */ >,
- < 1144 /* 300 MHz */ >,
- < 1720 /* 451 MHz */ >,
- < 2086 /* 547 MHz */ >,
- < 2597 /* 681 MHz */ >,
- < 2929 /* 768 MHz */ >,
- < 3879 /* 1017 MHz */ >,
- < 5161 /* 1353 MHz */ >,
- < 5931 /* 1555 MHz */ >,
- < 6881 /* 1804 MHz */ >;
+ < MHZ_TO_MBPS( 100, 4) >, /* 381 MB/s */
+ < MHZ_TO_MBPS( 200, 4) >, /* 762 MB/s */
+ < MHZ_TO_MBPS( 300, 4) >, /* 1144 MB/s */
+ < MHZ_TO_MBPS( 451, 4) >, /* 1720 MB/s */
+ < MHZ_TO_MBPS( 547, 4) >, /* 2086 MB/s */
+ < MHZ_TO_MBPS( 681, 4) >, /* 2597 MB/s */
+ < MHZ_TO_MBPS( 768, 4) >, /* 2929 MB/s */
+ < MHZ_TO_MBPS(1017, 4) >, /* 3879 MB/s */
+ < MHZ_TO_MBPS(1353, 4) >, /* 5161 MB/s */
+ < MHZ_TO_MBPS(1555, 4) >, /* 5931 MB/s */
+ < MHZ_TO_MBPS(1804, 4) >; /* 6881 MB/s */
};
llcc_bwmon: qcom,llcc-bwmon {
@@ -2135,17 +2133,17 @@
qcom,src-dst-ports = <1 512>;
qcom,active-only;
qcom,bw-tbl =
- < 381 /* 100 MHz */ >,
- < 762 /* 200 MHz */ >,
- < 1144 /* 300 MHz */ >,
- < 1720 /* 451 MHz */ >,
- < 2086 /* 547 MHz */ >,
- < 2597 /* 681 MHz */ >,
- < 2929 /* 768 MHz */ >,
- < 3879 /* 1017 MHz */ >,
- < 5161 /* 1353 MHz */ >,
- < 5931 /* 1555 MHz */ >,
- < 6881 /* 1804 MHz */ >;
+ < MHZ_TO_MBPS( 100, 4) >, /* 381 MB/s */
+ < MHZ_TO_MBPS( 200, 4) >, /* 762 MB/s */
+ < MHZ_TO_MBPS( 300, 4) >, /* 1144 MB/s */
+ < MHZ_TO_MBPS( 451, 4) >, /* 1720 MB/s */
+ < MHZ_TO_MBPS( 547, 4) >, /* 2086 MB/s */
+ < MHZ_TO_MBPS( 681, 4) >, /* 2597 MB/s */
+ < MHZ_TO_MBPS( 768, 4) >, /* 2929 MB/s */
+ < MHZ_TO_MBPS(1017, 4) >, /* 3879 MB/s */
+ < MHZ_TO_MBPS(1353, 4) >, /* 5161 MB/s */
+ < MHZ_TO_MBPS(1555, 4) >, /* 5931 MB/s */
+ < MHZ_TO_MBPS(1804, 4) >; /* 6881 MB/s */
};
memlat_cpu4: qcom,memlat-cpu4 {
@@ -2155,17 +2153,17 @@
qcom,active-only;
status = "ok";
qcom,bw-tbl =
- < 381 /* 100 MHz */ >,
- < 762 /* 200 MHz */ >,
- < 1144 /* 300 MHz */ >,
- < 1720 /* 451 MHz */ >,
- < 2086 /* 547 MHz */ >,
- < 2597 /* 681 MHz */ >,
- < 2929 /* 768 MHz */ >,
- < 3879 /* 1017 MHz */ >,
- < 5161 /* 1353 MHz */ >,
- < 5931 /* 1555 MHz */ >,
- < 6881 /* 1804 MHz */ >;
+ < MHZ_TO_MBPS( 100, 4) >, /* 381 MB/s */
+ < MHZ_TO_MBPS( 200, 4) >, /* 762 MB/s */
+ < MHZ_TO_MBPS( 300, 4) >, /* 1144 MB/s */
+ < MHZ_TO_MBPS( 451, 4) >, /* 1720 MB/s */
+ < MHZ_TO_MBPS( 547, 4) >, /* 2086 MB/s */
+ < MHZ_TO_MBPS( 681, 4) >, /* 2597 MB/s */
+ < MHZ_TO_MBPS( 768, 4) >, /* 2929 MB/s */
+ < MHZ_TO_MBPS(1017, 4) >, /* 3879 MB/s */
+ < MHZ_TO_MBPS(1353, 4) >, /* 5161 MB/s */
+ < MHZ_TO_MBPS(1555, 4) >, /* 5931 MB/s */
+ < MHZ_TO_MBPS(1804, 4) >; /* 6881 MB/s */
};
devfreq_memlat_0: qcom,cpu0-memlat-mon {
@@ -2174,11 +2172,11 @@
qcom,target-dev = <&memlat_cpu0>;
qcom,cachemiss-ev = <0x24>;
qcom,core-dev-table =
- < 748800 1144 >,
- < 998400 1720 >,
- < 1209600 2086 >,
- < 1497600 2929 >,
- < 1728000 3879 >;
+ < 748800 MHZ_TO_MBPS( 300, 4) >,
+ < 998400 MHZ_TO_MBPS( 451, 4) >,
+ < 1209600 MHZ_TO_MBPS( 547, 4) >,
+ < 1497600 MHZ_TO_MBPS( 768, 4) >,
+ < 1728000 MHZ_TO_MBPS(1017, 4) >;
};
devfreq_memlat_4: qcom,cpu4-memlat-mon {
@@ -2187,11 +2185,11 @@
qcom,target-dev = <&memlat_cpu4>;
qcom,cachemiss-ev = <0x24>;
qcom,core-dev-table =
- < 787200 1144 >,
- < 1113600 2086 >,
- < 1344000 3879 >,
- < 1900800 5931 >,
- < 2438400 6881 >;
+ < 787200 MHZ_TO_MBPS( 300, 4) >,
+ < 1113600 MHZ_TO_MBPS( 547, 4) >,
+ < 1344000 MHZ_TO_MBPS(1017, 4) >,
+ < 1900800 MHZ_TO_MBPS(1555, 4) >,
+ < 2438400 MHZ_TO_MBPS(1804, 4) >;
};
l3_cpu0: qcom,l3-cpu0 {
@@ -2241,37 +2239,50 @@
qcom,src-dst-ports = <1 512>;
qcom,active-only;
qcom,bw-tbl =
- < 381 /* 100 MHz */ >,
- < 762 /* 200 MHz */ >,
- < 1144 /* 300 MHz */ >,
- < 1720 /* 451 MHz */ >,
- < 2086 /* 547 MHz */ >,
- < 2597 /* 681 MHz */ >,
- < 2929 /* 768 MHz */ >,
- < 3879 /* 1017 MHz */ >,
- < 5161 /* 1353 MHz */ >,
- < 5931 /* 1555 MHz */ >,
- < 6881 /* 1804 MHz */ >;
+ < MHZ_TO_MBPS( 100, 4) >, /* 381 MB/s */
+ < MHZ_TO_MBPS( 200, 4) >, /* 762 MB/s */
+ < MHZ_TO_MBPS( 300, 4) >, /* 1144 MB/s */
+ < MHZ_TO_MBPS( 451, 4) >, /* 1720 MB/s */
+ < MHZ_TO_MBPS( 547, 4) >, /* 2086 MB/s */
+ < MHZ_TO_MBPS( 681, 4) >, /* 2597 MB/s */
+ < MHZ_TO_MBPS( 768, 4) >, /* 2929 MB/s */
+ < MHZ_TO_MBPS(1017, 4) >, /* 3879 MB/s */
+ < MHZ_TO_MBPS(1353, 4) >, /* 5161 MB/s */
+ < MHZ_TO_MBPS(1555, 4) >, /* 5931 MB/s */
+ < MHZ_TO_MBPS(1804, 4) >; /* 6881 MB/s */
};
devfreq-cpufreq {
mincpubw-cpufreq {
target-dev = <&mincpubw>;
cpu-to-dev-map-0 =
- < 748800 1144 >,
- < 1209600 1720 >,
- < 1612000 2086 >,
- < 1728000 2929 >;
+ < 748800 MHZ_TO_MBPS( 300, 4) >,
+ < 1209600 MHZ_TO_MBPS( 451, 4) >,
+ < 1612000 MHZ_TO_MBPS( 547, 4) >,
+ < 1728000 MHZ_TO_MBPS( 768, 4) >;
cpu-to-dev-map-4 =
- < 1113600 1144 >,
- < 1344000 2086 >,
- < 1728000 2929 >,
- < 1900800 3879 >,
- < 2438400 6881 >;
+ < 1113600 MHZ_TO_MBPS( 300, 4) >,
+ < 1344000 MHZ_TO_MBPS( 547, 4) >,
+ < 1728000 MHZ_TO_MBPS( 768, 4) >,
+ < 1900800 MHZ_TO_MBPS(1017, 4) >,
+ < 2438400 MHZ_TO_MBPS(1804, 4) >;
};
};
+
+ gpu_gx_domain_addr: syscon@0x5091508 {
+ compatible = "syscon";
+ reg = <0x5091508 0x4>;
+ };
+
+ gpu_gx_sw_reset: syscon@0x5091008 {
+ compatible = "syscon";
+ reg = <0x5091008 0x4>;
+ };
};
+#include "pm660.dtsi"
+#include "pm660l.dtsi"
+#include "sdm670-regulator.dtsi"
#include "sdm670-pinctrl.dtsi"
#include "msm-arm-smmu-sdm670.dtsi"
#include "msm-gdsc-sdm845.dtsi"
@@ -2346,6 +2357,9 @@
clocks = <&clock_gfx GPU_CC_GX_GFX3D_CLK_SRC>;
qcom,force-enable-root-clk;
parent-supply = <&pm660l_s2_level>;
+ domain-addr = <&gpu_gx_domain_addr>;
+ sw-reset = <&gpu_gx_sw_reset>;
+ qcom,reset-aon-logic;
status = "ok";
};
@@ -2363,10 +2377,8 @@
status = "ok";
};
-#include "pm660.dtsi"
-#include "pm660l.dtsi"
-#include "sdm670-regulator.dtsi"
#include "sdm670-audio.dtsi"
#include "sdm670-usb.dtsi"
#include "sdm670-gpu.dtsi"
#include "sdm670-thermal.dtsi"
+#include "sdm670-bus.dtsi"
diff --git a/arch/arm64/boot/dts/qcom/sdm845-audio-overlay.dtsi b/arch/arm64/boot/dts/qcom/sdm845-audio-overlay.dtsi
index cb11a9e..9d485b5 100644
--- a/arch/arm64/boot/dts/qcom/sdm845-audio-overlay.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm845-audio-overlay.dtsi
@@ -47,6 +47,8 @@
qcom,msm-mbhc-hphl-swh = <1>;
qcom,msm-mbhc-gnd-swh = <1>;
+ qcom,msm-mbhc-hs-mic-max-threshold-mv = <1700>;
+ qcom,msm-mbhc-hs-mic-min-threshold-mv = <50>;
qcom,hph-en0-gpio = <&tavil_hph_en0>;
qcom,hph-en1-gpio = <&tavil_hph_en1>;
qcom,tavil-mclk-clk-freq = <9600000>;
diff --git a/arch/arm64/boot/dts/qcom/sdm845-camera-sensor-cdp.dtsi b/arch/arm64/boot/dts/qcom/sdm845-camera-sensor-cdp.dtsi
index 9d799cb..9a1f055 100644
--- a/arch/arm64/boot/dts/qcom/sdm845-camera-sensor-cdp.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm845-camera-sensor-cdp.dtsi
@@ -111,7 +111,7 @@
rgltr-min-voltage = <2800000>;
rgltr-max-voltage = <2800000>;
rgltr-load-current = <0>;
- status = "disabled";
+ status = "ok";
};
eeprom_rear: qcom,eeprom@0 {
diff --git a/arch/arm64/boot/dts/qcom/sdm845-camera-sensor-mtp.dtsi b/arch/arm64/boot/dts/qcom/sdm845-camera-sensor-mtp.dtsi
index f18137c..2702ca1 100644
--- a/arch/arm64/boot/dts/qcom/sdm845-camera-sensor-mtp.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm845-camera-sensor-mtp.dtsi
@@ -111,7 +111,7 @@
rgltr-min-voltage = <2800000>;
rgltr-max-voltage = <2800000>;
rgltr-load-current = <0>;
- status = "disabled";
+ status = "ok";
};
eeprom_rear: qcom,eeprom@0 {
diff --git a/arch/arm64/boot/dts/qcom/sdm845-camera.dtsi b/arch/arm64/boot/dts/qcom/sdm845-camera.dtsi
index 8df879a..e4f768f 100644
--- a/arch/arm64/boot/dts/qcom/sdm845-camera.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm845-camera.dtsi
@@ -325,18 +325,8 @@
msm_cam_smmu_secure {
compatible = "qcom,msm-cam-smmu-cb";
- iommus = <&apps_smmu 0x1001 0x0>;
label = "cam-secure";
- cam_secure_iova_mem_map: iova-mem-map {
- /* Secure IO region is approximately 3.4 GB */
- iova-mem-region-io {
- iova-region-name = "io";
- iova-region-start = <0x7400000>;
- iova-region-len = <0xd8c00000>;
- iova-region-id = <0x3>;
- status = "ok";
- };
- };
+ qcom,secure-cb;
};
msm_cam_smmu_fd {
diff --git a/arch/arm64/boot/dts/qcom/sdm845-coresight.dtsi b/arch/arm64/boot/dts/qcom/sdm845-coresight.dtsi
index 568213b..5fca6a3 100644
--- a/arch/arm64/boot/dts/qcom/sdm845-coresight.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm845-coresight.dtsi
@@ -12,6 +12,16 @@
&soc {
+ csr: csr@6001000 {
+ compatible = "qcom,coresight-csr";
+ reg = <0x6001000 0x1000>;
+ reg-names = "csr-base";
+
+ coresight-name = "coresight-csr";
+
+ qcom,blk-size = <1>;
+ };
+
replicator_qdss: replicator@6046000 {
compatible = "arm,primecell";
arm,primecell-periphid = <0x0003b909>;
@@ -271,6 +281,9 @@
clocks = <&clock_aop QDSS_CLK>;
clock-names = "apb_pclk";
+ interrupts = <GIC_SPI 270 IRQ_TYPE_EDGE_RISING>;
+ interrupt-names = "byte-cntr-irq";
+
port {
tmc_etr_in_replicator: endpoint {
slave-mode;
@@ -397,16 +410,6 @@
clock-names = "apb_pclk";
};
- csr: csr@6001000 {
- compatible = "qcom,coresight-csr";
- reg = <0x6001000 0x1000>;
- reg-names = "csr-base";
-
- coresight-name = "coresight-csr";
-
- qcom,blk-size = <1>;
- };
-
funnel_in0: funnel@0x6041000 {
compatible = "arm,primecell";
arm,primecell-periphid = <0x0003b908>;
@@ -1553,7 +1556,7 @@
reg = <0x69e1000 0x1000>;
reg-names = "cti-base";
- coresight-name = "coresight-cti0-ddr0";
+ coresight-name = "coresight-cti-DDR_DL_0_CTI";
clocks = <&clock_aop QDSS_CLK>;
clock-names = "apb_pclk";
@@ -1565,7 +1568,7 @@
reg = <0x69e4000 0x1000>;
reg-names = "cti-base";
- coresight-name = "coresight-cti0-ddr1";
+ coresight-name = "coresight-cti-DDR_DL_1_CTI0";
clocks = <&clock_aop QDSS_CLK>;
clock-names = "apb_pclk";
@@ -1577,7 +1580,7 @@
reg = <0x69e5000 0x1000>;
reg-names = "cti-base";
- coresight-name = "coresight-cti1-ddr1";
+ coresight-name = "coresight-cti-DDR_DL_1_CTI1";
clocks = <&clock_aop QDSS_CLK>;
clock-names = "apb_pclk";
@@ -1589,7 +1592,7 @@
reg = <0x6c09000 0x1000>;
reg-names = "cti-base";
- coresight-name = "coresight-cti0-dlmm";
+ coresight-name = "coresight-cti-DLMM_CTI0";
clocks = <&clock_aop QDSS_CLK>;
clock-names = "apb_pclk";
@@ -1601,7 +1604,7 @@
reg = <0x6c0a000 0x1000>;
reg-names = "cti-base";
- coresight-name = "coresight-cti1-dlmm";
+ coresight-name = "coresight-cti-DLMM_CTI1";
clocks = <&clock_aop QDSS_CLK>;
clock-names = "apb_pclk";
@@ -1929,7 +1932,7 @@
reg = <0x6b04000 0x1000>;
reg-names = "cti-base";
- coresight-name = "coresight-cti0-swao";
+ coresight-name = "coresight-cti-SWAO_CTI0";
clocks = <&clock_aop QDSS_CLK>;
clock-names = "apb_pclk";
diff --git a/arch/arm64/boot/dts/qcom/sdm845-interposer-sdm670-audio-overlay.dtsi b/arch/arm64/boot/dts/qcom/sdm845-interposer-sdm670-audio-overlay.dtsi
new file mode 100644
index 0000000..54bd5201
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/sdm845-interposer-sdm670-audio-overlay.dtsi
@@ -0,0 +1,53 @@
+/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+#include "sdm670-audio-overlay.dtsi"
+
+&pm660l_3 {
+ /delete-node/analog-codec;
+};
+
+&soc {
+ /delete-node/msm-sdw-codec@62ec1000;
+ /delete-node/cdc_pdm_pinctrl;
+ /delete-node/wsa_spkr_en1_pinctrl;
+ /delete-node/wsa_spkr_en2_pinctrl;
+ /delete-node/sdw_clk_data_pinctrl;
+};
+
+&qupv3_se8_spi {
+ status = "okay";
+};
+
+&wcd9xxx_intc {
+ status = "okay";
+ qcom,gpio-connect = <&tlmm 54 0>;
+};
+
+&wdsp_mgr {
+ status = "okay";
+};
+
+&wdsp_glink {
+ status = "okay";
+};
+
+&wcd934x_cdc {
+ status = "okay";
+};
+
+&clock_audio_lnbb {
+ status = "okay";
+};
+
+&wcd_rst_gpio {
+ status = "okay";
+};
diff --git a/arch/arm64/boot/dts/qcom/sdm845-interposer-sdm670-audio.dtsi b/arch/arm64/boot/dts/qcom/sdm845-interposer-sdm670-audio.dtsi
index f861ca3..88892d7 100644
--- a/arch/arm64/boot/dts/qcom/sdm845-interposer-sdm670-audio.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm845-interposer-sdm670-audio.dtsi
@@ -10,44 +10,17 @@
* GNU General Public License for more details.
*/
-#include "sdm670-audio.dtsi"
&msm_audio_ion {
iommus = <&apps_smmu 0x1821 0x0>;
qcom,smmu-sid-mask = /bits/ 64 <0xf>;
};
-&qupv3_se8_spi {
- status = "okay";
-};
-
-&pm660l_3 {
- /delete-node/analog-codec;
-};
-
&soc {
- /delete-node/msm-sdw-codec@62ec1000;
/delete-node/sound;
- /delete-node/cdc_pdm_pinctrl;
- /delete-node/wsa_spkr_en1_pinctrl;
- /delete-node/wsa_spkr_en2_pinctrl;
- /delete-node/sdw_clk_data_pinctrl;
};
-&msm_audio_ion {
- iommus = <&apps_smmu 0x1821 0x0>;
-};
-
-&wcd9xxx_intc {
- status = "okay";
- qcom,gpio-connect = <&tlmm 54 0>;
-};
-
-&wdsp_mgr {
- status = "okay";
-};
-
-&wdsp_glink {
+&tavil_snd {
status = "okay";
};
@@ -58,24 +31,3 @@
&dai_slim {
status = "okay";
};
-
-&wcd934x_cdc {
- status = "okay";
-};
-
-&clock_audio_lnbb {
- status = "okay";
-};
-
-&wcd_rst_gpio {
- status = "okay";
-};
-
-&wcd9xxx_intc {
- status = "okay";
-};
-
-&tavil_snd {
- status = "okay";
-};
-
diff --git a/arch/arm64/boot/dts/qcom/sdm845-interposer-sdm670-cdp-overlay.dts b/arch/arm64/boot/dts/qcom/sdm845-interposer-sdm670-cdp-overlay.dts
index da59bcf..9d61324 100644
--- a/arch/arm64/boot/dts/qcom/sdm845-interposer-sdm670-cdp-overlay.dts
+++ b/arch/arm64/boot/dts/qcom/sdm845-interposer-sdm670-cdp-overlay.dts
@@ -21,7 +21,7 @@
#include "sdm845-sde-display.dtsi"
#include "sdm845-interposer-sdm670-cdp.dtsi"
-
+#include "sdm845-interposer-sdm670-audio-overlay.dtsi"
/ {
model = "Qualcomm Technologies, Inc. SDM845 v1 Interposer SDM670 CDP";
compatible = "qcom,sdm845-cdp", "qcom,sdm845", "qcom,cdp";
diff --git a/arch/arm64/boot/dts/qcom/sdm845-interposer-sdm670-cdp.dts b/arch/arm64/boot/dts/qcom/sdm845-interposer-sdm670-cdp.dts
index ebb5e8f..597773e 100644
--- a/arch/arm64/boot/dts/qcom/sdm845-interposer-sdm670-cdp.dts
+++ b/arch/arm64/boot/dts/qcom/sdm845-interposer-sdm670-cdp.dts
@@ -16,6 +16,8 @@
#include "sdm845-interposer-sdm670.dtsi"
#include "sdm845-sde-display.dtsi"
#include "sdm845-interposer-sdm670-cdp.dtsi"
+#include "sdm670-audio.dtsi"
+#include "sdm845-interposer-sdm670-audio.dtsi"
/ {
model = "Qualcomm Technologies, Inc. MSM sdm845 v1 Interposer SDM670 CDP";
diff --git a/arch/arm64/boot/dts/qcom/sdm845-interposer-sdm670-cdp.dtsi b/arch/arm64/boot/dts/qcom/sdm845-interposer-sdm670-cdp.dtsi
index e435cdd..1265d2a 100644
--- a/arch/arm64/boot/dts/qcom/sdm845-interposer-sdm670-cdp.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm845-interposer-sdm670-cdp.dtsi
@@ -12,7 +12,6 @@
#include "sdm845-cdp.dtsi"
#include "sdm845-interposer-pm660.dtsi"
-#include "sdm845-interposer-sdm670-audio.dtsi"
&soc {
/delete-node/ ssusb@a800000;
diff --git a/arch/arm64/boot/dts/qcom/sdm845-interposer-sdm670-mtp-overlay.dts b/arch/arm64/boot/dts/qcom/sdm845-interposer-sdm670-mtp-overlay.dts
index 3ca15b9..1690174 100644
--- a/arch/arm64/boot/dts/qcom/sdm845-interposer-sdm670-mtp-overlay.dts
+++ b/arch/arm64/boot/dts/qcom/sdm845-interposer-sdm670-mtp-overlay.dts
@@ -21,7 +21,7 @@
#include "sdm845-sde-display.dtsi"
#include "sdm845-interposer-sdm670-mtp.dtsi"
-
+#include "sdm845-interposer-sdm670-audio-overlay.dtsi"
/ {
model = "Qualcomm Technologies, Inc. SDM845 v1 Interposer SDM670 MTP";
compatible = "qcom,sdm845-mtp", "qcom,sdm845", "qcom,mtp";
diff --git a/arch/arm64/boot/dts/qcom/sdm845-interposer-sdm670-mtp.dts b/arch/arm64/boot/dts/qcom/sdm845-interposer-sdm670-mtp.dts
index 39664f1..52869da 100644
--- a/arch/arm64/boot/dts/qcom/sdm845-interposer-sdm670-mtp.dts
+++ b/arch/arm64/boot/dts/qcom/sdm845-interposer-sdm670-mtp.dts
@@ -16,6 +16,8 @@
#include "sdm845-interposer-sdm670.dtsi"
#include "sdm845-sde-display.dtsi"
#include "sdm845-interposer-sdm670-mtp.dtsi"
+#include "sdm670-audio.dtsi"
+#include "sdm845-interposer-sdm670-audio.dtsi"
/ {
model = "Qualcomm Technologies, Inc. MSM sdm845 v1 Interposer SDM670 MTP";
diff --git a/arch/arm64/boot/dts/qcom/sdm845-interposer-sdm670-mtp.dtsi b/arch/arm64/boot/dts/qcom/sdm845-interposer-sdm670-mtp.dtsi
index 4b24b0d..9d722df 100644
--- a/arch/arm64/boot/dts/qcom/sdm845-interposer-sdm670-mtp.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm845-interposer-sdm670-mtp.dtsi
@@ -12,7 +12,6 @@
#include "sdm845-mtp.dtsi"
#include "sdm845-interposer-pm660.dtsi"
-#include "sdm845-interposer-sdm670-audio.dtsi"
&qupv3_se10_i2c {
/delete-node/ qcom,smb1355@8;
diff --git a/arch/arm64/boot/dts/qcom/sdm845-qupv3.dtsi b/arch/arm64/boot/dts/qcom/sdm845-qupv3.dtsi
index 1fa6e26..a805e2e 100644
--- a/arch/arm64/boot/dts/qcom/sdm845-qupv3.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm845-qupv3.dtsi
@@ -221,6 +221,9 @@
interrupts = <GIC_SPI 601 0>;
spi-max-frequency = <50000000>;
qcom,wrapper-core = <&qupv3_0>;
+ dmas = <&gpi_dma0 0 0 1 64 0>,
+ <&gpi_dma0 1 0 1 64 0>;
+ dma-names = "tx", "rx";
status = "disabled";
};
@@ -240,6 +243,9 @@
interrupts = <GIC_SPI 602 0>;
spi-max-frequency = <50000000>;
qcom,wrapper-core = <&qupv3_0>;
+ dmas = <&gpi_dma0 0 1 1 64 0>,
+ <&gpi_dma0 1 1 1 64 0>;
+ dma-names = "tx", "rx";
status = "disabled";
};
@@ -259,6 +265,9 @@
interrupts = <GIC_SPI 603 0>;
spi-max-frequency = <50000000>;
qcom,wrapper-core = <&qupv3_0>;
+ dmas = <&gpi_dma0 0 2 1 64 0>,
+ <&gpi_dma0 1 2 1 64 0>;
+ dma-names = "tx", "rx";
status = "disabled";
};
@@ -278,6 +287,9 @@
interrupts = <GIC_SPI 604 0>;
spi-max-frequency = <50000000>;
qcom,wrapper-core = <&qupv3_0>;
+ dmas = <&gpi_dma0 0 3 1 64 0>,
+ <&gpi_dma0 1 3 1 64 0>;
+ dma-names = "tx", "rx";
status = "disabled";
};
@@ -297,6 +309,9 @@
interrupts = <GIC_SPI 605 0>;
spi-max-frequency = <50000000>;
qcom,wrapper-core = <&qupv3_0>;
+ dmas = <&gpi_dma0 0 4 1 64 0>,
+ <&gpi_dma0 1 4 1 64 0>;
+ dma-names = "tx", "rx";
status = "disabled";
};
@@ -316,6 +331,9 @@
interrupts = <GIC_SPI 606 0>;
spi-max-frequency = <50000000>;
qcom,wrapper-core = <&qupv3_0>;
+ dmas = <&gpi_dma0 0 5 1 64 0>,
+ <&gpi_dma0 1 5 1 64 0>;
+ dma-names = "tx", "rx";
status = "disabled";
};
@@ -335,6 +353,9 @@
interrupts = <GIC_SPI 607 0>;
spi-max-frequency = <50000000>;
qcom,wrapper-core = <&qupv3_0>;
+ dmas = <&gpi_dma0 0 6 1 64 0>,
+ <&gpi_dma0 1 6 1 64 0>;
+ dma-names = "tx", "rx";
status = "disabled";
};
@@ -354,6 +375,9 @@
interrupts = <GIC_SPI 608 0>;
spi-max-frequency = <50000000>;
qcom,wrapper-core = <&qupv3_0>;
+ dmas = <&gpi_dma0 0 7 1 64 0>,
+ <&gpi_dma0 1 7 1 64 0>;
+ dma-names = "tx", "rx";
status = "disabled";
};
@@ -561,6 +585,9 @@
interrupts = <GIC_SPI 353 0>;
spi-max-frequency = <50000000>;
qcom,wrapper-core = <&qupv3_1>;
+ dmas = <&gpi_dma1 0 0 1 64 0>,
+ <&gpi_dma1 1 0 1 64 0>;
+ dma-names = "tx", "rx";
status = "disabled";
};
@@ -580,6 +607,9 @@
interrupts = <GIC_SPI 354 0>;
spi-max-frequency = <50000000>;
qcom,wrapper-core = <&qupv3_1>;
+ dmas = <&gpi_dma1 0 1 1 64 0>,
+ <&gpi_dma1 1 1 1 64 0>;
+ dma-names = "tx", "rx";
status = "disabled";
};
@@ -599,6 +629,9 @@
interrupts = <GIC_SPI 355 0>;
spi-max-frequency = <50000000>;
qcom,wrapper-core = <&qupv3_1>;
+ dmas = <&gpi_dma1 0 2 1 64 0>,
+ <&gpi_dma1 1 2 1 64 0>;
+ dma-names = "tx", "rx";
status = "disabled";
};
@@ -618,6 +651,9 @@
interrupts = <GIC_SPI 356 0>;
spi-max-frequency = <50000000>;
qcom,wrapper-core = <&qupv3_1>;
+ dmas = <&gpi_dma1 0 3 1 64 0>,
+ <&gpi_dma1 1 3 1 64 0>;
+ dma-names = "tx", "rx";
status = "disabled";
};
@@ -637,6 +673,9 @@
interrupts = <GIC_SPI 357 0>;
spi-max-frequency = <50000000>;
qcom,wrapper-core = <&qupv3_1>;
+ dmas = <&gpi_dma1 0 4 1 64 0>,
+ <&gpi_dma1 1 4 1 64 0>;
+ dma-names = "tx", "rx";
status = "disabled";
};
@@ -656,6 +695,9 @@
interrupts = <GIC_SPI 358 0>;
spi-max-frequency = <50000000>;
qcom,wrapper-core = <&qupv3_1>;
+ dmas = <&gpi_dma1 0 5 1 64 0>,
+ <&gpi_dma1 1 5 1 64 0>;
+ dma-names = "tx", "rx";
status = "disabled";
};
@@ -675,6 +717,9 @@
interrupts = <GIC_SPI 359 0>;
spi-max-frequency = <50000000>;
qcom,wrapper-core = <&qupv3_1>;
+ dmas = <&gpi_dma1 0 6 1 64 0>,
+ <&gpi_dma1 1 6 1 64 0>;
+ dma-names = "tx", "rx";
status = "disabled";
};
@@ -694,6 +739,9 @@
interrupts = <GIC_SPI 360 0>;
spi-max-frequency = <50000000>;
qcom,wrapper-core = <&qupv3_1>;
+ dmas = <&gpi_dma1 0 7 1 64 0>,
+ <&gpi_dma1 1 7 1 64 0>;
+ dma-names = "tx", "rx";
status = "disabled";
};
};
diff --git a/arch/arm64/boot/dts/qcom/sdm845-qvr.dtsi b/arch/arm64/boot/dts/qcom/sdm845-qvr.dtsi
index 7bc4d89..d89722f 100644
--- a/arch/arm64/boot/dts/qcom/sdm845-qvr.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm845-qvr.dtsi
@@ -12,11 +12,69 @@
#include "sdm845-pmic-overlay.dtsi"
#include "sdm845-pinctrl-overlay.dtsi"
+#include "smb1355.dtsi"
&pmi8998_pdphy {
vbus-supply = <&smb2_vbus>;
};
+&pmi8998_fg {
+ qcom,fg-bmd-en-delay-ms = <300>;
+};
+
+&qupv3_se10_i2c {
+ status = "ok";
+};
+
+&smb1355_charger_0 {
+ status = "ok";
+};
+
+&smb1355_charger_1 {
+ status = "ok";
+};
+
+&soc {
+ qcom,qbt1000 {
+ status = "disabled";
+ };
+
+ gpio_keys {
+ compatible = "gpio-keys";
+ label = "gpio-keys";
+ pinctrl-names = "default";
+ pinctrl-0 = <&key_vol_up_default
+ &key_home_default>;
+
+ vol_up {
+ label = "volume_up";
+ gpios = <&pm8998_gpios 6 GPIO_ACTIVE_LOW>;
+ linux,input-type = <1>;
+ linux,code = <115>;
+ gpio-key,wakeup;
+ debounce-interval = <15>;
+ linux,can-disable;
+ };
+
+ home {
+ label = "home";
+ gpios = <&pm8998_gpios 5 GPIO_ACTIVE_LOW>;
+ linux,input-type = <1>;
+ linux,code = <102>;
+ gpio-key,wakeup;
+ debounce-interval = <15>;
+ linux,can-disable;
+ };
+ };
+};
+
+&pmi8998_haptics {
+ qcom,vmax-mv = <1800>;
+ qcom,wave-play-rate-us = <4255>;
+ qcom,lra-auto-mode;
+ status = "okay";
+};
+
&ufsphy_mem {
compatible = "qcom,ufs-phy-qmp-v3";
@@ -41,3 +99,21 @@
status = "ok";
};
+
+&sdhc_2 {
+ vdd-supply = <&pm8998_l21>;
+ qcom,vdd-voltage-level = <2950000 2960000>;
+ qcom,vdd-current-level = <200 800000>;
+
+ vdd-io-supply = <&pm8998_l13>;
+ qcom,vdd-io-voltage-level = <1808000 2960000>;
+ qcom,vdd-io-current-level = <200 22000>;
+
+ pinctrl-names = "active", "sleep";
+ pinctrl-0 = <&sdc2_clk_on &sdc2_cmd_on &storage_cd>;
+ pinctrl-1 = <&sdc2_clk_off &sdc2_cmd_off &storage_cd>;
+
+ cd-gpios = <&tlmm 126 GPIO_ACTIVE_HIGH>;
+
+ status = "ok";
+};
diff --git a/arch/arm64/boot/dts/qcom/sdm845-sde-display.dtsi b/arch/arm64/boot/dts/qcom/sdm845-sde-display.dtsi
index 03b40b3..04edfa9 100644
--- a/arch/arm64/boot/dts/qcom/sdm845-sde-display.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm845-sde-display.dtsi
@@ -414,109 +414,12 @@
compatible = "qcom,msm-ext-disp-audio-codec-rx";
};
};
-
- sde_dp: qcom,dp_display@0{
- cell-index = <0>;
- compatible = "qcom,dp-display";
-
- gdsc-supply = <&mdss_core_gdsc>;
- vdda-1p2-supply = <&pm8998_l26>;
- vdda-0p9-supply = <&pm8998_l1>;
-
- reg = <0xae90000 0xa84>,
- <0x88eaa00 0x200>,
- <0x88ea200 0x200>,
- <0x88ea600 0x200>,
- <0xaf02000 0x1a0>,
- <0x780000 0x621c>,
- <0x88ea030 0x10>,
- <0x88e8000 0x20>,
- <0x0aee1000 0x034>;
- reg-names = "dp_ctrl", "dp_phy", "dp_ln_tx0", "dp_ln_tx1",
- "dp_mmss_cc", "qfprom_physical", "dp_pll",
- "usb3_dp_com", "hdcp_physical";
-
- interrupt-parent = <&mdss_mdp>;
- interrupts = <12 0>;
-
- clocks = <&clock_dispcc DISP_CC_MDSS_DP_AUX_CLK>,
- <&clock_rpmh RPMH_CXO_CLK>,
- <&clock_gcc GCC_USB3_PRIM_CLKREF_CLK>,
- <&clock_gcc GCC_USB_PHY_CFG_AHB2PHY_CLK>,
- <&clock_gcc GCC_USB3_PRIM_PHY_PIPE_CLK>,
- <&clock_dispcc DISP_CC_MDSS_DP_LINK_CLK>,
- <&clock_dispcc DISP_CC_MDSS_DP_LINK_INTF_CLK>,
- <&clock_dispcc DISP_CC_MDSS_DP_PIXEL_CLK>,
- <&clock_dispcc DISP_CC_MDSS_DP_CRYPTO_CLK>,
- <&clock_dispcc DISP_CC_MDSS_DP_PIXEL_CLK_SRC>,
- <&mdss_dp_pll DP_VCO_DIVIDED_CLK_SRC_MUX>;
- clock-names = "core_aux_clk", "core_usb_ref_clk_src",
- "core_usb_ref_clk", "core_usb_cfg_ahb_clk",
- "core_usb_pipe_clk", "ctrl_link_clk",
- "ctrl_link_iface_clk", "ctrl_pixel_clk",
- "crypto_clk", "pixel_clk_rcg", "pixel_parent";
-
- qcom,dp-usbpd-detection = <&pmi8998_pdphy>;
- qcom,ext-disp = <&ext_disp>;
-
- qcom,aux-cfg0-settings = [20 00];
- qcom,aux-cfg1-settings = [24 13 23 1d];
- qcom,aux-cfg2-settings = [28 24];
- qcom,aux-cfg3-settings = [2c 00];
- qcom,aux-cfg4-settings = [30 0a];
- qcom,aux-cfg5-settings = [34 26];
- qcom,aux-cfg6-settings = [38 0a];
- qcom,aux-cfg7-settings = [3c 03];
- qcom,aux-cfg8-settings = [40 bb];
- qcom,aux-cfg9-settings = [44 03];
-
- qcom,max-pclk-frequency-khz = <576000>;
-
- qcom,core-supply-entries {
- #address-cells = <1>;
- #size-cells = <0>;
-
- qcom,core-supply-entry@0 {
- reg = <0>;
- qcom,supply-name = "gdsc";
- qcom,supply-min-voltage = <0>;
- qcom,supply-max-voltage = <0>;
- qcom,supply-enable-load = <0>;
- qcom,supply-disable-load = <0>;
- };
- };
-
- qcom,ctrl-supply-entries {
- #address-cells = <1>;
- #size-cells = <0>;
-
- qcom,ctrl-supply-entry@0 {
- reg = <0>;
- qcom,supply-name = "vdda-1p2";
- qcom,supply-min-voltage = <1200000>;
- qcom,supply-max-voltage = <1200000>;
- qcom,supply-enable-load = <21800>;
- qcom,supply-disable-load = <4>;
- };
- };
-
- qcom,phy-supply-entries {
- #address-cells = <1>;
- #size-cells = <0>;
-
- qcom,phy-supply-entry@0 {
- reg = <0>;
- qcom,supply-name = "vdda-0p9";
- qcom,supply-min-voltage = <880000>;
- qcom,supply-max-voltage = <880000>;
- qcom,supply-enable-load = <36000>;
- qcom,supply-disable-load = <32>;
- };
- };
- };
};
&sde_dp {
+ qcom,dp-usbpd-detection = <&pmi8998_pdphy>;
+ qcom,ext-disp = <&ext_disp>;
+
pinctrl-names = "mdss_dp_active", "mdss_dp_sleep";
pinctrl-0 = <&sde_dp_aux_active &sde_dp_usbplug_cc_active>;
pinctrl-1 = <&sde_dp_aux_suspend &sde_dp_usbplug_cc_suspend>;
diff --git a/arch/arm64/boot/dts/qcom/sdm845-sde.dtsi b/arch/arm64/boot/dts/qcom/sdm845-sde.dtsi
index 6051106..3f255ac 100644
--- a/arch/arm64/boot/dts/qcom/sdm845-sde.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm845-sde.dtsi
@@ -9,6 +9,7 @@
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
+#include <dt-bindings/clock/mdss-10nm-pll-clk.h>
&soc {
mdss_mdp: qcom,mdss_mdp@ae00000 {
@@ -63,6 +64,11 @@
qcom,sde-dspp-off = <0x55000 0x57000 0x59000 0x5b000>;
qcom,sde-dspp-size = <0x17e0>;
+ qcom,sde-dest-scaler-top-off = <0x00061000>;
+ qcom,sde-dest-scaler-top-size = <0xc>;
+ qcom,sde-dest-scaler-off = <0x800 0x1000>;
+ qcom,sde-dest-scaler-size = <0x800>;
+
qcom,sde-wb-off = <0x66000>;
qcom,sde-wb-size = <0x2c8>;
qcom,sde-wb-xin-id = <6>;
@@ -128,6 +134,9 @@
qcom,sde-has-src-split;
qcom,sde-has-dim-layer;
qcom,sde-has-idle-pc;
+ qcom,sde-has-dest-scaler;
+ qcom,sde-max-dest-scaler-input-linewidth = <2048>;
+ qcom,sde-max-dest-scaler-output-linewidth = <2560>;
qcom,sde-max-bw-low-kbps = <9600000>;
qcom,sde-max-bw-high-kbps = <9600000>;
qcom,sde-min-core-ib-kbps = <2400000>;
@@ -535,4 +544,86 @@
};
};
+ sde_dp: qcom,dp_display@0{
+ cell-index = <0>;
+ compatible = "qcom,dp-display";
+
+ gdsc-supply = <&mdss_core_gdsc>;
+ vdda-1p2-supply = <&pm8998_l26>;
+ vdda-0p9-supply = <&pm8998_l1>;
+
+ reg = <0xae90000 0xa84>,
+ <0x88eaa00 0x200>,
+ <0x88ea200 0x200>,
+ <0x88ea600 0x200>,
+ <0xaf02000 0x1a0>,
+ <0x780000 0x621c>,
+ <0x88ea030 0x10>,
+ <0x88e8000 0x20>,
+ <0x0aee1000 0x034>;
+ reg-names = "dp_ctrl", "dp_phy", "dp_ln_tx0", "dp_ln_tx1",
+ "dp_mmss_cc", "qfprom_physical", "dp_pll",
+ "usb3_dp_com", "hdcp_physical";
+
+ interrupt-parent = <&mdss_mdp>;
+ interrupts = <12 0>;
+
+ clocks = <&clock_dispcc DISP_CC_MDSS_DP_AUX_CLK>,
+ <&clock_rpmh RPMH_CXO_CLK>,
+ <&clock_gcc GCC_USB3_PRIM_CLKREF_CLK>,
+ <&clock_gcc GCC_USB_PHY_CFG_AHB2PHY_CLK>,
+ <&clock_gcc GCC_USB3_PRIM_PHY_PIPE_CLK>,
+ <&clock_dispcc DISP_CC_MDSS_DP_LINK_CLK>,
+ <&clock_dispcc DISP_CC_MDSS_DP_LINK_INTF_CLK>,
+ <&clock_dispcc DISP_CC_MDSS_DP_PIXEL_CLK>,
+ <&clock_dispcc DISP_CC_MDSS_DP_CRYPTO_CLK>,
+ <&clock_dispcc DISP_CC_MDSS_DP_PIXEL_CLK_SRC>,
+ <&mdss_dp_pll DP_VCO_DIVIDED_CLK_SRC_MUX>;
+ clock-names = "core_aux_clk", "core_usb_ref_clk_src",
+ "core_usb_ref_clk", "core_usb_cfg_ahb_clk",
+ "core_usb_pipe_clk", "ctrl_link_clk",
+ "ctrl_link_iface_clk", "ctrl_pixel_clk",
+ "crypto_clk", "pixel_clk_rcg", "pixel_parent";
+
+ qcom,aux-cfg0-settings = [20 00];
+ qcom,aux-cfg1-settings = [24 13 23 1d];
+ qcom,aux-cfg2-settings = [28 24];
+ qcom,aux-cfg3-settings = [2c 00];
+ qcom,aux-cfg4-settings = [30 0a];
+ qcom,aux-cfg5-settings = [34 26];
+ qcom,aux-cfg6-settings = [38 0a];
+ qcom,aux-cfg7-settings = [3c 03];
+ qcom,aux-cfg8-settings = [40 bb];
+ qcom,aux-cfg9-settings = [44 03];
+
+ qcom,max-pclk-frequency-khz = <675000>;
+
+ qcom,ctrl-supply-entries {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ qcom,ctrl-supply-entry@0 {
+ reg = <0>;
+ qcom,supply-name = "vdda-1p2";
+ qcom,supply-min-voltage = <1200000>;
+ qcom,supply-max-voltage = <1200000>;
+ qcom,supply-enable-load = <21800>;
+ qcom,supply-disable-load = <4>;
+ };
+ };
+
+ qcom,phy-supply-entries {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ qcom,phy-supply-entry@0 {
+ reg = <0>;
+ qcom,supply-name = "vdda-0p9";
+ qcom,supply-min-voltage = <880000>;
+ qcom,supply-max-voltage = <880000>;
+ qcom,supply-enable-load = <36000>;
+ qcom,supply-disable-load = <32>;
+ };
+ };
+ };
};
diff --git a/arch/arm64/boot/dts/qcom/sdm845-v2-camera.dtsi b/arch/arm64/boot/dts/qcom/sdm845-v2-camera.dtsi
index c42a7be..c070ed6 100644
--- a/arch/arm64/boot/dts/qcom/sdm845-v2-camera.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm845-v2-camera.dtsi
@@ -243,18 +243,8 @@
msm_cam_smmu_secure {
compatible = "qcom,msm-cam-smmu-cb";
- iommus = <&apps_smmu 0x1001 0x0>;
label = "cam-secure";
- cam_secure_iova_mem_map: iova-mem-map {
- /* Secure IO region is approximately 3.4 GB */
- iova-mem-region-io {
- iova-region-name = "io";
- iova-region-start = <0x7400000>;
- iova-region-len = <0xd8c00000>;
- iova-region-id = <0x3>;
- status = "ok";
- };
- };
+ qcom,secure-cb;
};
};
diff --git a/arch/arm64/boot/dts/qcom/sdm845-v2.dtsi b/arch/arm64/boot/dts/qcom/sdm845-v2.dtsi
index 80ef35f..138b750 100644
--- a/arch/arm64/boot/dts/qcom/sdm845-v2.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm845-v2.dtsi
@@ -1207,6 +1207,54 @@
qcom,sde-min-core-ib-kbps = <4800000>;
};
+&mdss_dsi0 {
+ qcom,core-supply-entries {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ qcom,core-supply-entry@0 {
+ reg = <0>;
+ qcom,supply-name = "refgen";
+ qcom,supply-min-voltage = <0>;
+ qcom,supply-max-voltage = <0>;
+ qcom,supply-enable-load = <0>;
+ qcom,supply-disable-load = <0>;
+ };
+ };
+};
+
+&mdss_dsi1 {
+ qcom,core-supply-entries {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ qcom,core-supply-entry@0 {
+ reg = <0>;
+ qcom,supply-name = "refgen";
+ qcom,supply-min-voltage = <0>;
+ qcom,supply-max-voltage = <0>;
+ qcom,supply-enable-load = <0>;
+ qcom,supply-disable-load = <0>;
+ };
+ };
+};
+
+&sde_dp {
+ qcom,core-supply-entries {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ qcom,core-supply-entry@0 {
+ reg = <0>;
+ qcom,supply-name = "refgen";
+ qcom,supply-min-voltage = <0>;
+ qcom,supply-max-voltage = <0>;
+ qcom,supply-enable-load = <0>;
+ qcom,supply-disable-load = <0>;
+ };
+ };
+};
+
&energy_costs {
CPU_COST_0: core-cost0 {
busy-cost-data = <
@@ -1435,3 +1483,26 @@
};
};
};
+
+&qusb_phy0 {
+ qcom,qusb-phy-init-seq =
+ /* <value reg_offset> */
+ <0x23 0x210 /* PWR_CTRL1 */
+ 0x03 0x04 /* PLL_ANALOG_CONTROLS_TWO */
+ 0x7c 0x18c /* PLL_CLOCK_INVERTERS */
+ 0x80 0x2c /* PLL_CMODE */
+ 0x0a 0x184 /* PLL_LOCK_DELAY */
+ 0x19 0xb4 /* PLL_DIGITAL_TIMERS_TWO */
+ 0x40 0x194 /* PLL_BIAS_CONTROL_1 */
+ 0x20 0x198 /* PLL_BIAS_CONTROL_2 */
+ 0x21 0x214 /* PWR_CTRL2 */
+ 0x00 0x220 /* IMP_CTRL1 */
+ 0x58 0x224 /* IMP_CTRL2 */
+ 0x45 0x240 /* TUNE1 */
+ 0x29 0x244 /* TUNE2 */
+ 0xca 0x248 /* TUNE3 */
+ 0x04 0x24c /* TUNE4 */
+ 0x03 0x250 /* TUNE5 */
+ 0x00 0x23c /* CHG_CTRL2 */
+ 0x22 0x210>; /* PWR_CTRL1 */
+};
diff --git a/arch/arm64/boot/dts/qcom/sdm845.dtsi b/arch/arm64/boot/dts/qcom/sdm845.dtsi
index ff092ea..71c3a23 100644
--- a/arch/arm64/boot/dts/qcom/sdm845.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm845.dtsi
@@ -1740,6 +1740,7 @@
qcom,sysmon-id = <0>;
qcom,ssctl-instance-id = <0x12>;
qcom,override-acc;
+ qcom,signal-aop;
qcom,qdsp6v65-1-0;
qcom,mss_pdc_offset = <8>;
status = "ok";
@@ -1755,6 +1756,9 @@
/* GPIO output to mss */
qcom,gpio-force-stop = <&smp2pgpio_ssr_smp2p_1_out 0 0>;
+
+ mboxes = <&qmp_aop 0>;
+ mbox-names = "mss-pil";
qcom,mba-mem@0 {
compatible = "qcom,pil-mba-mem";
memory-region = <&pil_mba_mem>;
@@ -1781,6 +1785,7 @@
status = "ok";
qcom,ssctl-instance-id = <0x14>;
qcom,firmware-name = "adsp";
+ qcom,signal-aop;
memory-region = <&pil_adsp_mem>;
/* GPIO inputs from lpass */
@@ -1791,6 +1796,9 @@
/* GPIO output to lpass */
qcom,gpio-force-stop = <&smp2pgpio_ssr_smp2p_2_out 0 0>;
+
+ mboxes = <&qmp_aop 0>;
+ mbox-names = "adsp-pil";
};
qcom,ssc@5c00000 {
@@ -1812,6 +1820,7 @@
qcom,smem-id = <424>;
qcom,sysmon-id = <3>;
qcom,ssctl-instance-id = <0x16>;
+ qcom,signal-aop;
qcom,firmware-name = "slpi";
status = "ok";
memory-region = <&pil_slpi_mem>;
@@ -1824,6 +1833,9 @@
/* GPIO output to ssc */
qcom,gpio-force-stop = <&smp2pgpio_ssr_smp2p_3_out 0 0>;
+
+ mboxes = <&qmp_aop 0>;
+ mbox-names = "slpi-pil";
};
slim_aud: slim@171c0000 {
@@ -1906,9 +1918,13 @@
qcom,pas-id = <14>;
qcom,proxy-timeout-ms = <10000>;
+ qcom,signal-aop;
qcom,firmware-name = "spss";
memory-region = <&pil_spss_mem>;
qcom,spss-scsr-bits = <24 25>;
+
+ mboxes = <&qmp_aop 0>;
+ mbox-names = "spss-pil";
};
wdog: qcom,wdt@17980000{
@@ -1941,6 +1957,7 @@
qcom,sysmon-id = <7>;
qcom,ssctl-instance-id = <0x17>;
qcom,firmware-name = "cdsp";
+ qcom,signal-aop;
memory-region = <&pil_cdsp_mem>;
/* GPIO inputs from turing */
@@ -1952,6 +1969,9 @@
/* GPIO output to turing*/
qcom,gpio-force-stop = <&smp2pgpio_ssr_smp2p_5_out 0 0>;
status = "ok";
+
+ mboxes = <&qmp_aop 0>;
+ mbox-names = "cdsp-pil";
};
qcom,msm-rtb {
@@ -2278,19 +2298,19 @@
};
LLCC_1: llcc_1_dcache {
- qcom,dump-size = <0x114100>;
+ qcom,dump-size = <0x1141c0>;
};
LLCC_2: llcc_2_dcache {
- qcom,dump-size = <0x114100>;
+ qcom,dump-size = <0x1141c0>;
};
LLCC_3: llcc_3_dcache {
- qcom,dump-size = <0x114100>;
+ qcom,dump-size = <0x1141c0>;
};
LLCC_4: llcc_4_dcache {
- qcom,dump-size = <0x114100>;
+ qcom,dump-size = <0x1141c0>;
};
};
@@ -2543,7 +2563,7 @@
qcom,qsee_ipc_irq_bridge {
compatible = "qcom,qsee-ipc-irq-bridge";
- qcom,qsee-ipq-irq-spss {
+ qcom,qsee-ipc-irq-spss {
qcom,rx-irq-clr = <0x1888008 0x4>;
qcom,rx-irq-clr-mask = <0x1>;
qcom,dev-name = "qsee_ipc_irq_spss";
@@ -2949,6 +2969,7 @@
compatible = "qcom,pil-tz-generic";
qcom,pas-id = <0xf>;
qcom,firmware-name = "ipa_fws";
+ qcom,pil-force-shutdown;
};
qcom,chd_sliver {
@@ -3704,6 +3725,10 @@
<&clock_rpmh RPMH_RF_CLK3_A>;
clock-names = "rf_clk3_clk", "rf_clk3_pin_clk";
qcom,smmu-support;
+ qcom,smmu-mapping = <0x20000000 0xe0000000>;
+ qcom,smmu-s1-en;
+ qcom,smmu-fast-map;
+ qcom,smmu-coherent;
qcom,keep-radio-on-during-sleep;
status = "disabled";
};
diff --git a/arch/arm64/configs/msm8953-perf_defconfig b/arch/arm64/configs/msm8953-perf_defconfig
new file mode 100644
index 0000000..4e7fe31
--- /dev/null
+++ b/arch/arm64/configs/msm8953-perf_defconfig
@@ -0,0 +1,473 @@
+CONFIG_LOCALVERSION="-perf"
+# CONFIG_LOCALVERSION_AUTO is not set
+# CONFIG_FHANDLE is not set
+CONFIG_AUDIT=y
+# CONFIG_AUDITSYSCALL is not set
+CONFIG_NO_HZ=y
+CONFIG_HIGH_RES_TIMERS=y
+CONFIG_IRQ_TIME_ACCOUNTING=y
+CONFIG_SCHED_WALT=y
+CONFIG_RCU_EXPERT=y
+CONFIG_RCU_FAST_NO_HZ=y
+CONFIG_RCU_NOCB_CPU=y
+CONFIG_RCU_NOCB_CPU_ALL=y
+CONFIG_IKCONFIG=y
+CONFIG_IKCONFIG_PROC=y
+CONFIG_LOG_CPU_MAX_BUF_SHIFT=17
+CONFIG_CGROUP_FREEZER=y
+CONFIG_CPUSETS=y
+CONFIG_CGROUP_CPUACCT=y
+CONFIG_CGROUP_SCHEDTUNE=y
+CONFIG_RT_GROUP_SCHED=y
+CONFIG_CGROUP_BPF=y
+CONFIG_SCHED_CORE_CTL=y
+CONFIG_NAMESPACES=y
+# CONFIG_UTS_NS is not set
+# CONFIG_PID_NS is not set
+CONFIG_SCHED_AUTOGROUP=y
+CONFIG_SCHED_TUNE=y
+CONFIG_BLK_DEV_INITRD=y
+# CONFIG_RD_XZ is not set
+# CONFIG_RD_LZO is not set
+# CONFIG_RD_LZ4 is not set
+CONFIG_KALLSYMS_ALL=y
+CONFIG_BPF_SYSCALL=y
+# CONFIG_AIO is not set
+# CONFIG_MEMBARRIER is not set
+CONFIG_EMBEDDED=y
+# CONFIG_COMPAT_BRK is not set
+CONFIG_PROFILING=y
+CONFIG_CC_STACKPROTECTOR_STRONG=y
+CONFIG_ARCH_MMAP_RND_COMPAT_BITS=16
+CONFIG_MODULES=y
+CONFIG_MODULE_UNLOAD=y
+CONFIG_MODULE_FORCE_UNLOAD=y
+CONFIG_MODVERSIONS=y
+CONFIG_MODULE_SIG=y
+CONFIG_MODULE_SIG_FORCE=y
+CONFIG_MODULE_SIG_SHA512=y
+# CONFIG_BLK_DEV_BSG is not set
+CONFIG_PARTITION_ADVANCED=y
+# CONFIG_IOSCHED_DEADLINE is not set
+CONFIG_ARCH_QCOM=y
+CONFIG_ARCH_MSM8953=y
+CONFIG_SCHED_MC=y
+CONFIG_NR_CPUS=8
+CONFIG_PREEMPT=y
+CONFIG_HZ_100=y
+CONFIG_CMA=y
+CONFIG_ZSMALLOC=y
+CONFIG_BALANCE_ANON_FILE_RECLAIM=y
+CONFIG_SECCOMP=y
+CONFIG_ARMV8_DEPRECATED=y
+CONFIG_SWP_EMULATION=y
+CONFIG_CP15_BARRIER_EMULATION=y
+CONFIG_SETEND_EMULATION=y
+# CONFIG_ARM64_VHE is not set
+CONFIG_BUILD_ARM64_APPENDED_DTB_IMAGE=y
+# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set
+CONFIG_COMPAT=y
+CONFIG_PM_AUTOSLEEP=y
+CONFIG_PM_WAKELOCKS=y
+CONFIG_PM_WAKELOCKS_LIMIT=0
+# CONFIG_PM_WAKELOCKS_GC is not set
+CONFIG_CPU_IDLE=y
+CONFIG_CPU_FREQ=y
+CONFIG_CPU_FREQ_GOV_POWERSAVE=y
+CONFIG_CPU_FREQ_GOV_USERSPACE=y
+CONFIG_CPU_FREQ_GOV_ONDEMAND=y
+CONFIG_CPU_FREQ_GOV_CONSERVATIVE=y
+CONFIG_CPU_BOOST=y
+CONFIG_CPU_FREQ_GOV_SCHEDUTIL=y
+CONFIG_NET=y
+CONFIG_PACKET=y
+CONFIG_UNIX=y
+CONFIG_XFRM_USER=y
+CONFIG_XFRM_STATISTICS=y
+CONFIG_NET_KEY=y
+CONFIG_INET=y
+CONFIG_IP_MULTICAST=y
+CONFIG_IP_ADVANCED_ROUTER=y
+CONFIG_IP_MULTIPLE_TABLES=y
+CONFIG_IP_ROUTE_VERBOSE=y
+CONFIG_IP_PNP=y
+CONFIG_IP_PNP_DHCP=y
+CONFIG_INET_AH=y
+CONFIG_INET_ESP=y
+CONFIG_INET_IPCOMP=y
+CONFIG_INET_DIAG_DESTROY=y
+CONFIG_IPV6_ROUTER_PREF=y
+CONFIG_IPV6_ROUTE_INFO=y
+CONFIG_IPV6_OPTIMISTIC_DAD=y
+CONFIG_INET6_AH=y
+CONFIG_INET6_ESP=y
+CONFIG_INET6_IPCOMP=y
+CONFIG_IPV6_MIP6=y
+CONFIG_IPV6_MULTIPLE_TABLES=y
+CONFIG_IPV6_SUBTREES=y
+CONFIG_NETFILTER=y
+CONFIG_NF_CONNTRACK=y
+CONFIG_NF_CONNTRACK_SECMARK=y
+CONFIG_NF_CONNTRACK_EVENTS=y
+CONFIG_NF_CT_PROTO_DCCP=y
+CONFIG_NF_CT_PROTO_SCTP=y
+CONFIG_NF_CT_PROTO_UDPLITE=y
+CONFIG_NF_CONNTRACK_AMANDA=y
+CONFIG_NF_CONNTRACK_FTP=y
+CONFIG_NF_CONNTRACK_H323=y
+CONFIG_NF_CONNTRACK_IRC=y
+CONFIG_NF_CONNTRACK_NETBIOS_NS=y
+CONFIG_NF_CONNTRACK_PPTP=y
+CONFIG_NF_CONNTRACK_SANE=y
+CONFIG_NF_CONNTRACK_TFTP=y
+CONFIG_NF_CT_NETLINK=y
+CONFIG_NETFILTER_XT_TARGET_CLASSIFY=y
+CONFIG_NETFILTER_XT_TARGET_CONNMARK=y
+CONFIG_NETFILTER_XT_TARGET_CONNSECMARK=y
+CONFIG_NETFILTER_XT_TARGET_IDLETIMER=y
+CONFIG_NETFILTER_XT_TARGET_HARDIDLETIMER=y
+CONFIG_NETFILTER_XT_TARGET_LOG=y
+CONFIG_NETFILTER_XT_TARGET_MARK=y
+CONFIG_NETFILTER_XT_TARGET_NFLOG=y
+CONFIG_NETFILTER_XT_TARGET_NFQUEUE=y
+CONFIG_NETFILTER_XT_TARGET_NOTRACK=y
+CONFIG_NETFILTER_XT_TARGET_TEE=y
+CONFIG_NETFILTER_XT_TARGET_TPROXY=y
+CONFIG_NETFILTER_XT_TARGET_TRACE=y
+CONFIG_NETFILTER_XT_TARGET_SECMARK=y
+CONFIG_NETFILTER_XT_TARGET_TCPMSS=y
+CONFIG_NETFILTER_XT_MATCH_COMMENT=y
+CONFIG_NETFILTER_XT_MATCH_CONNLIMIT=y
+CONFIG_NETFILTER_XT_MATCH_CONNMARK=y
+CONFIG_NETFILTER_XT_MATCH_CONNTRACK=y
+CONFIG_NETFILTER_XT_MATCH_DSCP=y
+CONFIG_NETFILTER_XT_MATCH_ESP=y
+CONFIG_NETFILTER_XT_MATCH_HASHLIMIT=y
+CONFIG_NETFILTER_XT_MATCH_HELPER=y
+CONFIG_NETFILTER_XT_MATCH_IPRANGE=y
+# CONFIG_NETFILTER_XT_MATCH_L2TP is not set
+CONFIG_NETFILTER_XT_MATCH_LENGTH=y
+CONFIG_NETFILTER_XT_MATCH_LIMIT=y
+CONFIG_NETFILTER_XT_MATCH_MAC=y
+CONFIG_NETFILTER_XT_MATCH_MARK=y
+CONFIG_NETFILTER_XT_MATCH_MULTIPORT=y
+CONFIG_NETFILTER_XT_MATCH_POLICY=y
+CONFIG_NETFILTER_XT_MATCH_PKTTYPE=y
+CONFIG_NETFILTER_XT_MATCH_QTAGUID=y
+CONFIG_NETFILTER_XT_MATCH_QUOTA=y
+CONFIG_NETFILTER_XT_MATCH_QUOTA2=y
+CONFIG_NETFILTER_XT_MATCH_SOCKET=y
+CONFIG_NETFILTER_XT_MATCH_STATE=y
+CONFIG_NETFILTER_XT_MATCH_STATISTIC=y
+CONFIG_NETFILTER_XT_MATCH_STRING=y
+CONFIG_NETFILTER_XT_MATCH_TIME=y
+CONFIG_NETFILTER_XT_MATCH_U32=y
+CONFIG_NF_CONNTRACK_IPV4=y
+CONFIG_IP_NF_IPTABLES=y
+CONFIG_IP_NF_MATCH_AH=y
+CONFIG_IP_NF_MATCH_ECN=y
+CONFIG_IP_NF_MATCH_RPFILTER=y
+CONFIG_IP_NF_MATCH_TTL=y
+CONFIG_IP_NF_FILTER=y
+CONFIG_IP_NF_TARGET_REJECT=y
+CONFIG_IP_NF_NAT=y
+CONFIG_IP_NF_TARGET_MASQUERADE=y
+CONFIG_IP_NF_TARGET_NETMAP=y
+CONFIG_IP_NF_TARGET_REDIRECT=y
+CONFIG_IP_NF_MANGLE=y
+CONFIG_IP_NF_RAW=y
+CONFIG_IP_NF_SECURITY=y
+CONFIG_IP_NF_ARPTABLES=y
+CONFIG_IP_NF_ARPFILTER=y
+CONFIG_IP_NF_ARP_MANGLE=y
+CONFIG_NF_CONNTRACK_IPV6=y
+CONFIG_IP6_NF_IPTABLES=y
+CONFIG_IP6_NF_MATCH_RPFILTER=y
+CONFIG_IP6_NF_FILTER=y
+CONFIG_IP6_NF_TARGET_REJECT=y
+CONFIG_IP6_NF_MANGLE=y
+CONFIG_IP6_NF_RAW=y
+CONFIG_BRIDGE_NF_EBTABLES=y
+CONFIG_BRIDGE_EBT_BROUTE=y
+CONFIG_L2TP=y
+CONFIG_L2TP_V3=y
+CONFIG_L2TP_IP=y
+CONFIG_L2TP_ETH=y
+CONFIG_BRIDGE=y
+CONFIG_NET_SCHED=y
+CONFIG_NET_SCH_HTB=y
+CONFIG_NET_SCH_PRIO=y
+CONFIG_NET_SCH_MULTIQ=y
+CONFIG_NET_SCH_INGRESS=y
+CONFIG_NET_CLS_FW=y
+CONFIG_NET_CLS_U32=y
+CONFIG_CLS_U32_MARK=y
+CONFIG_NET_CLS_FLOW=y
+CONFIG_NET_EMATCH=y
+CONFIG_NET_EMATCH_CMP=y
+CONFIG_NET_EMATCH_NBYTE=y
+CONFIG_NET_EMATCH_U32=y
+CONFIG_NET_EMATCH_META=y
+CONFIG_NET_EMATCH_TEXT=y
+CONFIG_NET_CLS_ACT=y
+CONFIG_NET_ACT_GACT=y
+CONFIG_NET_ACT_MIRRED=y
+CONFIG_NET_ACT_SKBEDIT=y
+CONFIG_RMNET_DATA=y
+CONFIG_RMNET_DATA_FC=y
+CONFIG_RMNET_DATA_DEBUG_PKT=y
+CONFIG_BT=y
+CONFIG_MSM_BT_POWER=y
+CONFIG_CFG80211=y
+CONFIG_CFG80211_INTERNAL_REGDB=y
+# CONFIG_CFG80211_CRDA_SUPPORT is not set
+CONFIG_RFKILL=y
+CONFIG_NFC_NQ=y
+CONFIG_IPC_ROUTER=y
+CONFIG_IPC_ROUTER_SECURITY=y
+CONFIG_FW_LOADER_USER_HELPER_FALLBACK=y
+CONFIG_DMA_CMA=y
+CONFIG_ZRAM=y
+CONFIG_BLK_DEV_LOOP=y
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_SIZE=8192
+CONFIG_QSEECOM=y
+CONFIG_MEMORY_STATE_TIME=y
+CONFIG_SCSI=y
+CONFIG_BLK_DEV_SD=y
+CONFIG_CHR_DEV_SG=y
+CONFIG_CHR_DEV_SCH=y
+CONFIG_SCSI_CONSTANTS=y
+CONFIG_SCSI_LOGGING=y
+CONFIG_SCSI_SCAN_ASYNC=y
+CONFIG_SCSI_UFSHCD=y
+CONFIG_SCSI_UFSHCD_PLATFORM=y
+CONFIG_SCSI_UFS_QCOM=y
+CONFIG_SCSI_UFS_QCOM_ICE=y
+CONFIG_SCSI_UFSHCD_CMD_LOGGING=y
+CONFIG_MD=y
+CONFIG_BLK_DEV_DM=y
+CONFIG_DM_DEBUG=y
+CONFIG_DM_CRYPT=y
+CONFIG_DM_REQ_CRYPT=y
+CONFIG_DM_UEVENT=y
+CONFIG_DM_VERITY=y
+CONFIG_DM_VERITY_FEC=y
+CONFIG_NETDEVICES=y
+CONFIG_DUMMY=y
+CONFIG_TUN=y
+CONFIG_PPP=y
+CONFIG_PPP_BSDCOMP=y
+CONFIG_PPP_DEFLATE=y
+CONFIG_PPP_FILTER=y
+CONFIG_PPP_MPPE=y
+CONFIG_PPP_MULTILINK=y
+CONFIG_PPPOE=y
+CONFIG_PPPOL2TP=y
+CONFIG_PPPOLAC=y
+CONFIG_PPPOPNS=y
+CONFIG_PPP_ASYNC=y
+CONFIG_PPP_SYNC_TTY=y
+CONFIG_WCNSS_MEM_PRE_ALLOC=y
+CONFIG_CLD_LL_CORE=y
+CONFIG_INPUT_EVDEV=y
+CONFIG_KEYBOARD_GPIO=y
+# CONFIG_INPUT_MOUSE is not set
+CONFIG_INPUT_JOYSTICK=y
+CONFIG_INPUT_TOUCHSCREEN=y
+CONFIG_INPUT_MISC=y
+CONFIG_INPUT_HBTP_INPUT=y
+CONFIG_INPUT_UINPUT=y
+# CONFIG_SERIO_SERPORT is not set
+# CONFIG_VT is not set
+# CONFIG_LEGACY_PTYS is not set
+CONFIG_SERIAL_MSM=y
+CONFIG_SERIAL_MSM_CONSOLE=y
+CONFIG_HW_RANDOM=y
+CONFIG_HW_RANDOM_MSM_LEGACY=y
+CONFIG_MSM_ADSPRPC=y
+CONFIG_MSM_RDBG=m
+CONFIG_I2C_CHARDEV=y
+CONFIG_SPI=y
+CONFIG_SPI_QUP=y
+CONFIG_SPI_SPIDEV=y
+CONFIG_SLIMBUS_MSM_NGD=y
+CONFIG_SPMI=y
+CONFIG_SPMI_MSM_PMIC_ARB_DEBUG=y
+CONFIG_PINCTRL_MSM8953=y
+CONFIG_PINCTRL_QCOM_SPMI_PMIC=y
+CONFIG_GPIOLIB=y
+CONFIG_GPIO_SYSFS=y
+CONFIG_POWER_RESET_QCOM=y
+CONFIG_QCOM_DLOAD_MODE=y
+CONFIG_POWER_RESET_XGENE=y
+CONFIG_POWER_RESET_SYSCON=y
+CONFIG_SENSORS_QPNP_ADC_VOLTAGE=y
+CONFIG_THERMAL=y
+CONFIG_THERMAL_QPNP=y
+CONFIG_THERMAL_QPNP_ADC_TM=y
+CONFIG_THERMAL_TSENS=y
+CONFIG_MSM_BCL_PERIPHERAL_CTL=y
+CONFIG_QTI_THERMAL_LIMITS_DCVS=y
+CONFIG_REGULATOR_FIXED_VOLTAGE=y
+CONFIG_REGULATOR_CPRH_KBSS=y
+CONFIG_REGULATOR_QPNP_LABIBB=y
+CONFIG_REGULATOR_QPNP=y
+CONFIG_REGULATOR_STUB=y
+CONFIG_MEDIA_SUPPORT=y
+CONFIG_MEDIA_CAMERA_SUPPORT=y
+CONFIG_MEDIA_CONTROLLER=y
+CONFIG_VIDEO_V4L2_SUBDEV_API=y
+CONFIG_V4L_PLATFORM_DRIVERS=y
+CONFIG_MSM_VIDC_V4L2=y
+CONFIG_MSM_VIDC_GOVERNORS=y
+CONFIG_MSM_SDE_ROTATOR=y
+CONFIG_MSM_SDE_ROTATOR_EVTLOG_DEBUG=y
+CONFIG_QCOM_KGSL=y
+CONFIG_DRM=y
+CONFIG_DRM_SDE_EVTLOG_DEBUG=y
+CONFIG_DRM_SDE_RSC=y
+CONFIG_BACKLIGHT_LCD_SUPPORT=y
+CONFIG_BACKLIGHT_CLASS_DEVICE=y
+CONFIG_LOGO=y
+# CONFIG_LOGO_LINUX_MONO is not set
+# CONFIG_LOGO_LINUX_VGA16 is not set
+CONFIG_SOUND=y
+CONFIG_SND=y
+CONFIG_SND_DYNAMIC_MINORS=y
+CONFIG_SND_SOC=y
+CONFIG_UHID=y
+CONFIG_HID_APPLE=y
+CONFIG_HID_ELECOM=y
+CONFIG_HID_MAGICMOUSE=y
+CONFIG_HID_MICROSOFT=y
+CONFIG_HID_MULTITOUCH=y
+CONFIG_USB_DWC3=y
+CONFIG_NOP_USB_XCEIV=y
+CONFIG_DUAL_ROLE_USB_INTF=y
+CONFIG_USB_MSM_SSPHY_QMP=y
+CONFIG_MSM_QUSB_PHY=y
+CONFIG_USB_GADGET=y
+CONFIG_USB_GADGET_DEBUG_FILES=y
+CONFIG_USB_GADGET_DEBUG_FS=y
+CONFIG_USB_GADGET_VBUS_DRAW=500
+CONFIG_MMC=y
+CONFIG_MMC_PERF_PROFILING=y
+CONFIG_MMC_PARANOID_SD_INIT=y
+CONFIG_MMC_CLKGATE=y
+CONFIG_MMC_BLOCK_MINORS=32
+CONFIG_MMC_BLOCK_DEFERRED_RESUME=y
+CONFIG_MMC_TEST=y
+CONFIG_MMC_SDHCI=y
+CONFIG_MMC_SDHCI_PLTFM=y
+CONFIG_MMC_SDHCI_MSM=y
+CONFIG_NEW_LEDS=y
+CONFIG_LEDS_CLASS=y
+CONFIG_LEDS_QPNP=y
+CONFIG_LEDS_QPNP_WLED=y
+CONFIG_LEDS_TRIGGERS=y
+CONFIG_EDAC=y
+CONFIG_EDAC_MM_EDAC=y
+CONFIG_RTC_CLASS=y
+CONFIG_RTC_DRV_QPNP=y
+CONFIG_DMADEVICES=y
+CONFIG_QCOM_SPS_DMA=y
+CONFIG_UIO=y
+CONFIG_UIO_MSM_SHAREDMEM=y
+CONFIG_STAGING=y
+CONFIG_ASHMEM=y
+CONFIG_ANDROID_LOW_MEMORY_KILLER=y
+CONFIG_ION=y
+CONFIG_ION_MSM=y
+CONFIG_GSI=y
+CONFIG_IPA3=y
+CONFIG_RMNET_IPA3=y
+CONFIG_RNDIS_IPA=y
+CONFIG_IPA_UT=y
+CONFIG_SPS=y
+CONFIG_SPS_SUPPORT_NDP_BAM=y
+CONFIG_QPNP_COINCELL=y
+CONFIG_QPNP_REVID=y
+CONFIG_USB_BAM=y
+CONFIG_QCOM_MDSS_PLL=y
+CONFIG_REMOTE_SPINLOCK_MSM=y
+CONFIG_MAILBOX=y
+CONFIG_ARM_SMMU=y
+CONFIG_MSM_BOOT_STATS=y
+CONFIG_QCOM_EUD=y
+CONFIG_QCOM_WATCHDOG_V2=y
+CONFIG_QCOM_MEMORY_DUMP_V2=y
+CONFIG_QCOM_SECURE_BUFFER=y
+CONFIG_QCOM_EARLY_RANDOM=y
+CONFIG_MSM_SMEM=y
+CONFIG_MSM_GLINK=y
+CONFIG_MSM_GLINK_LOOPBACK_SERVER=y
+CONFIG_MSM_GLINK_SMEM_NATIVE_XPRT=y
+CONFIG_MSM_GLINK_SPI_XPRT=y
+CONFIG_MSM_SMP2P=y
+CONFIG_MSM_SMP2P_TEST=y
+CONFIG_MSM_IPC_ROUTER_GLINK_XPRT=y
+CONFIG_MSM_QMI_INTERFACE=y
+CONFIG_MSM_GLINK_PKT=y
+CONFIG_MSM_SUBSYSTEM_RESTART=y
+CONFIG_MSM_PIL=y
+CONFIG_MSM_PIL_SSR_GENERIC=y
+CONFIG_MSM_PIL_MSS_QDSP6V5=y
+CONFIG_ICNSS=y
+CONFIG_MSM_PERFORMANCE=y
+CONFIG_MSM_EVENT_TIMER=y
+CONFIG_MSM_PM=y
+CONFIG_QTI_RPM_STATS_LOG=y
+CONFIG_QCOM_FORCE_WDOG_BITE_ON_PANIC=y
+CONFIG_PWM=y
+CONFIG_PWM_QPNP=y
+CONFIG_ARM_GIC_V3_ACL=y
+CONFIG_ANDROID=y
+CONFIG_ANDROID_BINDER_IPC=y
+CONFIG_SENSORS_SSC=y
+CONFIG_MSM_TZ_LOG=y
+CONFIG_QUOTA=y
+CONFIG_QUOTA_NETLINK_INTERFACE=y
+CONFIG_FUSE_FS=y
+CONFIG_VFAT_FS=y
+CONFIG_TMPFS_POSIX_ACL=y
+CONFIG_ECRYPT_FS=y
+CONFIG_ECRYPT_FS_MESSAGING=y
+# CONFIG_NETWORK_FILESYSTEMS is not set
+CONFIG_NLS_CODEPAGE_437=y
+CONFIG_NLS_ISO8859_1=y
+CONFIG_PRINTK_TIME=y
+CONFIG_DEBUG_INFO=y
+CONFIG_MAGIC_SYSRQ=y
+CONFIG_PANIC_TIMEOUT=5
+CONFIG_SCHEDSTATS=y
+# CONFIG_DEBUG_PREEMPT is not set
+CONFIG_IPC_LOGGING=y
+CONFIG_CPU_FREQ_SWITCH_PROFILER=y
+CONFIG_DEBUG_ALIGN_RODATA=y
+CONFIG_CORESIGHT=y
+CONFIG_CORESIGHT_STM=y
+CONFIG_CORESIGHT_EVENT=y
+CONFIG_SECURITY_PERF_EVENTS_RESTRICT=y
+CONFIG_SECURITY=y
+CONFIG_HARDENED_USERCOPY=y
+CONFIG_SECURITY_SELINUX=y
+CONFIG_SECURITY_SMACK=y
+CONFIG_CRYPTO_CTR=y
+CONFIG_CRYPTO_XCBC=y
+CONFIG_CRYPTO_MD4=y
+CONFIG_CRYPTO_TWOFISH=y
+CONFIG_CRYPTO_ANSI_CPRNG=y
+CONFIG_CRYPTO_DEV_QCOM_MSM_QCE=y
+CONFIG_CRYPTO_DEV_QCRYPTO=y
+CONFIG_CRYPTO_DEV_QCEDEV=y
+CONFIG_CRYPTO_DEV_QCOM_ICE=y
+CONFIG_ARM64_CRYPTO=y
+CONFIG_CRYPTO_SHA1_ARM64_CE=y
+CONFIG_CRYPTO_SHA2_ARM64_CE=y
+CONFIG_CRYPTO_GHASH_ARM64_CE=y
+CONFIG_CRYPTO_AES_ARM64_CE_CCM=y
+CONFIG_CRYPTO_AES_ARM64_CE_BLK=y
+CONFIG_CRYPTO_AES_ARM64_NEON_BLK=y
+CONFIG_CRYPTO_CRC32_ARM64=y
+CONFIG_QMI_ENCDEC=y
diff --git a/arch/arm64/configs/msm8953_defconfig b/arch/arm64/configs/msm8953_defconfig
new file mode 100644
index 0000000..6951086
--- /dev/null
+++ b/arch/arm64/configs/msm8953_defconfig
@@ -0,0 +1,543 @@
+# CONFIG_LOCALVERSION_AUTO is not set
+# CONFIG_FHANDLE is not set
+CONFIG_AUDIT=y
+# CONFIG_AUDITSYSCALL is not set
+CONFIG_NO_HZ=y
+CONFIG_HIGH_RES_TIMERS=y
+CONFIG_IRQ_TIME_ACCOUNTING=y
+CONFIG_SCHED_WALT=y
+CONFIG_TASKSTATS=y
+CONFIG_TASK_DELAY_ACCT=y
+CONFIG_TASK_XACCT=y
+CONFIG_TASK_IO_ACCOUNTING=y
+CONFIG_RCU_EXPERT=y
+CONFIG_RCU_FAST_NO_HZ=y
+CONFIG_RCU_NOCB_CPU=y
+CONFIG_RCU_NOCB_CPU_ALL=y
+CONFIG_IKCONFIG=y
+CONFIG_IKCONFIG_PROC=y
+CONFIG_LOG_CPU_MAX_BUF_SHIFT=17
+CONFIG_CGROUP_DEBUG=y
+CONFIG_CGROUP_FREEZER=y
+CONFIG_CPUSETS=y
+CONFIG_CGROUP_CPUACCT=y
+CONFIG_CGROUP_SCHEDTUNE=y
+CONFIG_RT_GROUP_SCHED=y
+CONFIG_CGROUP_BPF=y
+CONFIG_SCHED_CORE_CTL=y
+CONFIG_NAMESPACES=y
+# CONFIG_UTS_NS is not set
+# CONFIG_PID_NS is not set
+CONFIG_SCHED_AUTOGROUP=y
+CONFIG_SCHED_TUNE=y
+CONFIG_BLK_DEV_INITRD=y
+# CONFIG_RD_XZ is not set
+# CONFIG_RD_LZO is not set
+# CONFIG_RD_LZ4 is not set
+CONFIG_KALLSYMS_ALL=y
+CONFIG_BPF_SYSCALL=y
+# CONFIG_AIO is not set
+# CONFIG_MEMBARRIER is not set
+CONFIG_EMBEDDED=y
+# CONFIG_COMPAT_BRK is not set
+CONFIG_PROFILING=y
+CONFIG_CC_STACKPROTECTOR_STRONG=y
+CONFIG_ARCH_MMAP_RND_COMPAT_BITS=16
+CONFIG_MODULES=y
+CONFIG_MODULE_UNLOAD=y
+CONFIG_MODULE_FORCE_UNLOAD=y
+CONFIG_MODVERSIONS=y
+CONFIG_MODULE_SIG=y
+CONFIG_MODULE_SIG_FORCE=y
+CONFIG_MODULE_SIG_SHA512=y
+# CONFIG_BLK_DEV_BSG is not set
+CONFIG_PARTITION_ADVANCED=y
+# CONFIG_IOSCHED_DEADLINE is not set
+CONFIG_ARCH_QCOM=y
+CONFIG_ARCH_MSM8953=y
+CONFIG_SCHED_MC=y
+CONFIG_NR_CPUS=8
+CONFIG_PREEMPT=y
+CONFIG_HZ_100=y
+CONFIG_CLEANCACHE=y
+CONFIG_CMA=y
+CONFIG_CMA_DEBUGFS=y
+CONFIG_ZSMALLOC=y
+CONFIG_BALANCE_ANON_FILE_RECLAIM=y
+CONFIG_SECCOMP=y
+CONFIG_ARMV8_DEPRECATED=y
+CONFIG_SWP_EMULATION=y
+CONFIG_CP15_BARRIER_EMULATION=y
+CONFIG_SETEND_EMULATION=y
+# CONFIG_ARM64_VHE is not set
+CONFIG_BUILD_ARM64_APPENDED_DTB_IMAGE=y
+# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set
+CONFIG_COMPAT=y
+CONFIG_PM_AUTOSLEEP=y
+CONFIG_PM_WAKELOCKS=y
+CONFIG_PM_WAKELOCKS_LIMIT=0
+# CONFIG_PM_WAKELOCKS_GC is not set
+CONFIG_PM_DEBUG=y
+CONFIG_CPU_IDLE=y
+CONFIG_CPU_FREQ=y
+CONFIG_CPU_FREQ_GOV_POWERSAVE=y
+CONFIG_CPU_FREQ_GOV_USERSPACE=y
+CONFIG_CPU_FREQ_GOV_ONDEMAND=y
+CONFIG_CPU_FREQ_GOV_CONSERVATIVE=y
+CONFIG_CPU_BOOST=y
+CONFIG_CPU_FREQ_GOV_SCHEDUTIL=y
+CONFIG_NET=y
+CONFIG_PACKET=y
+CONFIG_UNIX=y
+CONFIG_XFRM_USER=y
+CONFIG_XFRM_STATISTICS=y
+CONFIG_NET_KEY=y
+CONFIG_INET=y
+CONFIG_IP_MULTICAST=y
+CONFIG_IP_ADVANCED_ROUTER=y
+CONFIG_IP_MULTIPLE_TABLES=y
+CONFIG_IP_ROUTE_VERBOSE=y
+CONFIG_IP_PNP=y
+CONFIG_IP_PNP_DHCP=y
+CONFIG_INET_AH=y
+CONFIG_INET_ESP=y
+CONFIG_INET_IPCOMP=y
+CONFIG_INET_DIAG_DESTROY=y
+CONFIG_IPV6_ROUTER_PREF=y
+CONFIG_IPV6_ROUTE_INFO=y
+CONFIG_IPV6_OPTIMISTIC_DAD=y
+CONFIG_INET6_AH=y
+CONFIG_INET6_ESP=y
+CONFIG_INET6_IPCOMP=y
+CONFIG_IPV6_MIP6=y
+CONFIG_IPV6_MULTIPLE_TABLES=y
+CONFIG_IPV6_SUBTREES=y
+CONFIG_NETFILTER=y
+CONFIG_NF_CONNTRACK=y
+CONFIG_NF_CONNTRACK_SECMARK=y
+CONFIG_NF_CONNTRACK_EVENTS=y
+CONFIG_NF_CT_PROTO_DCCP=y
+CONFIG_NF_CT_PROTO_SCTP=y
+CONFIG_NF_CT_PROTO_UDPLITE=y
+CONFIG_NF_CONNTRACK_AMANDA=y
+CONFIG_NF_CONNTRACK_FTP=y
+CONFIG_NF_CONNTRACK_H323=y
+CONFIG_NF_CONNTRACK_IRC=y
+CONFIG_NF_CONNTRACK_NETBIOS_NS=y
+CONFIG_NF_CONNTRACK_PPTP=y
+CONFIG_NF_CONNTRACK_SANE=y
+CONFIG_NF_CONNTRACK_TFTP=y
+CONFIG_NF_CT_NETLINK=y
+CONFIG_NETFILTER_XT_TARGET_CLASSIFY=y
+CONFIG_NETFILTER_XT_TARGET_CONNMARK=y
+CONFIG_NETFILTER_XT_TARGET_CONNSECMARK=y
+CONFIG_NETFILTER_XT_TARGET_IDLETIMER=y
+CONFIG_NETFILTER_XT_TARGET_HARDIDLETIMER=y
+CONFIG_NETFILTER_XT_TARGET_LOG=y
+CONFIG_NETFILTER_XT_TARGET_MARK=y
+CONFIG_NETFILTER_XT_TARGET_NFLOG=y
+CONFIG_NETFILTER_XT_TARGET_NFQUEUE=y
+CONFIG_NETFILTER_XT_TARGET_NOTRACK=y
+CONFIG_NETFILTER_XT_TARGET_TEE=y
+CONFIG_NETFILTER_XT_TARGET_TPROXY=y
+CONFIG_NETFILTER_XT_TARGET_TRACE=y
+CONFIG_NETFILTER_XT_TARGET_SECMARK=y
+CONFIG_NETFILTER_XT_TARGET_TCPMSS=y
+CONFIG_NETFILTER_XT_MATCH_COMMENT=y
+CONFIG_NETFILTER_XT_MATCH_CONNLIMIT=y
+CONFIG_NETFILTER_XT_MATCH_CONNMARK=y
+CONFIG_NETFILTER_XT_MATCH_CONNTRACK=y
+CONFIG_NETFILTER_XT_MATCH_DSCP=y
+CONFIG_NETFILTER_XT_MATCH_ESP=y
+CONFIG_NETFILTER_XT_MATCH_HASHLIMIT=y
+CONFIG_NETFILTER_XT_MATCH_HELPER=y
+CONFIG_NETFILTER_XT_MATCH_IPRANGE=y
+# CONFIG_NETFILTER_XT_MATCH_L2TP is not set
+CONFIG_NETFILTER_XT_MATCH_LENGTH=y
+CONFIG_NETFILTER_XT_MATCH_LIMIT=y
+CONFIG_NETFILTER_XT_MATCH_MAC=y
+CONFIG_NETFILTER_XT_MATCH_MARK=y
+CONFIG_NETFILTER_XT_MATCH_MULTIPORT=y
+CONFIG_NETFILTER_XT_MATCH_POLICY=y
+CONFIG_NETFILTER_XT_MATCH_PKTTYPE=y
+CONFIG_NETFILTER_XT_MATCH_QTAGUID=y
+CONFIG_NETFILTER_XT_MATCH_QUOTA=y
+CONFIG_NETFILTER_XT_MATCH_QUOTA2=y
+CONFIG_NETFILTER_XT_MATCH_SOCKET=y
+CONFIG_NETFILTER_XT_MATCH_STATE=y
+CONFIG_NETFILTER_XT_MATCH_STATISTIC=y
+CONFIG_NETFILTER_XT_MATCH_STRING=y
+CONFIG_NETFILTER_XT_MATCH_TIME=y
+CONFIG_NETFILTER_XT_MATCH_U32=y
+CONFIG_NF_CONNTRACK_IPV4=y
+CONFIG_IP_NF_IPTABLES=y
+CONFIG_IP_NF_MATCH_AH=y
+CONFIG_IP_NF_MATCH_ECN=y
+CONFIG_IP_NF_MATCH_RPFILTER=y
+CONFIG_IP_NF_MATCH_TTL=y
+CONFIG_IP_NF_FILTER=y
+CONFIG_IP_NF_TARGET_REJECT=y
+CONFIG_IP_NF_NAT=y
+CONFIG_IP_NF_TARGET_MASQUERADE=y
+CONFIG_IP_NF_TARGET_NETMAP=y
+CONFIG_IP_NF_TARGET_REDIRECT=y
+CONFIG_IP_NF_MANGLE=y
+CONFIG_IP_NF_RAW=y
+CONFIG_IP_NF_SECURITY=y
+CONFIG_IP_NF_ARPTABLES=y
+CONFIG_IP_NF_ARPFILTER=y
+CONFIG_IP_NF_ARP_MANGLE=y
+CONFIG_NF_CONNTRACK_IPV6=y
+CONFIG_IP6_NF_IPTABLES=y
+CONFIG_IP6_NF_MATCH_RPFILTER=y
+CONFIG_IP6_NF_FILTER=y
+CONFIG_IP6_NF_TARGET_REJECT=y
+CONFIG_IP6_NF_MANGLE=y
+CONFIG_IP6_NF_RAW=y
+CONFIG_BRIDGE_NF_EBTABLES=y
+CONFIG_BRIDGE_EBT_BROUTE=y
+CONFIG_L2TP=y
+CONFIG_L2TP_DEBUGFS=y
+CONFIG_L2TP_V3=y
+CONFIG_L2TP_IP=y
+CONFIG_L2TP_ETH=y
+CONFIG_BRIDGE=y
+CONFIG_NET_SCHED=y
+CONFIG_NET_SCH_HTB=y
+CONFIG_NET_SCH_PRIO=y
+CONFIG_NET_SCH_MULTIQ=y
+CONFIG_NET_SCH_INGRESS=y
+CONFIG_NET_CLS_FW=y
+CONFIG_NET_CLS_U32=y
+CONFIG_CLS_U32_MARK=y
+CONFIG_NET_CLS_FLOW=y
+CONFIG_NET_EMATCH=y
+CONFIG_NET_EMATCH_CMP=y
+CONFIG_NET_EMATCH_NBYTE=y
+CONFIG_NET_EMATCH_U32=y
+CONFIG_NET_EMATCH_META=y
+CONFIG_NET_EMATCH_TEXT=y
+CONFIG_NET_CLS_ACT=y
+CONFIG_NET_ACT_GACT=y
+CONFIG_NET_ACT_MIRRED=y
+CONFIG_NET_ACT_SKBEDIT=y
+CONFIG_DNS_RESOLVER=y
+CONFIG_RMNET_DATA=y
+CONFIG_RMNET_DATA_FC=y
+CONFIG_RMNET_DATA_DEBUG_PKT=y
+CONFIG_BT=y
+CONFIG_MSM_BT_POWER=y
+CONFIG_CFG80211=y
+CONFIG_CFG80211_INTERNAL_REGDB=y
+# CONFIG_CFG80211_CRDA_SUPPORT is not set
+CONFIG_RFKILL=y
+CONFIG_NFC_NQ=y
+CONFIG_IPC_ROUTER=y
+CONFIG_IPC_ROUTER_SECURITY=y
+CONFIG_FW_LOADER_USER_HELPER_FALLBACK=y
+CONFIG_DMA_CMA=y
+CONFIG_ZRAM=y
+CONFIG_BLK_DEV_LOOP=y
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_SIZE=8192
+CONFIG_QSEECOM=y
+CONFIG_UID_SYS_STATS=y
+CONFIG_MEMORY_STATE_TIME=y
+CONFIG_SCSI=y
+CONFIG_BLK_DEV_SD=y
+CONFIG_CHR_DEV_SG=y
+CONFIG_CHR_DEV_SCH=y
+CONFIG_SCSI_CONSTANTS=y
+CONFIG_SCSI_LOGGING=y
+CONFIG_SCSI_SCAN_ASYNC=y
+CONFIG_SCSI_UFSHCD=y
+CONFIG_SCSI_UFSHCD_PLATFORM=y
+CONFIG_SCSI_UFS_QCOM=y
+CONFIG_SCSI_UFS_QCOM_ICE=y
+CONFIG_SCSI_UFSHCD_CMD_LOGGING=y
+CONFIG_MD=y
+CONFIG_BLK_DEV_DM=y
+CONFIG_DM_DEBUG=y
+CONFIG_DM_CRYPT=y
+CONFIG_DM_REQ_CRYPT=y
+CONFIG_DM_UEVENT=y
+CONFIG_DM_VERITY=y
+CONFIG_DM_VERITY_FEC=y
+CONFIG_NETDEVICES=y
+CONFIG_DUMMY=y
+CONFIG_TUN=y
+CONFIG_PPP=y
+CONFIG_PPP_BSDCOMP=y
+CONFIG_PPP_DEFLATE=y
+CONFIG_PPP_FILTER=y
+CONFIG_PPP_MPPE=y
+CONFIG_PPP_MULTILINK=y
+CONFIG_PPPOE=y
+CONFIG_PPPOL2TP=y
+CONFIG_PPPOLAC=y
+CONFIG_PPPOPNS=y
+CONFIG_PPP_ASYNC=y
+CONFIG_PPP_SYNC_TTY=y
+CONFIG_WCNSS_MEM_PRE_ALLOC=y
+CONFIG_CLD_LL_CORE=y
+CONFIG_INPUT_EVDEV=y
+CONFIG_KEYBOARD_GPIO=y
+# CONFIG_INPUT_MOUSE is not set
+CONFIG_INPUT_JOYSTICK=y
+CONFIG_INPUT_TOUCHSCREEN=y
+CONFIG_INPUT_MISC=y
+CONFIG_INPUT_HBTP_INPUT=y
+CONFIG_INPUT_UINPUT=y
+# CONFIG_SERIO_SERPORT is not set
+# CONFIG_VT is not set
+# CONFIG_LEGACY_PTYS is not set
+CONFIG_SERIAL_MSM=y
+CONFIG_SERIAL_MSM_CONSOLE=y
+CONFIG_HW_RANDOM=y
+CONFIG_HW_RANDOM_MSM_LEGACY=y
+CONFIG_MSM_ADSPRPC=y
+CONFIG_MSM_RDBG=m
+CONFIG_I2C_CHARDEV=y
+CONFIG_SPI=y
+CONFIG_SPI_QUP=y
+CONFIG_SPI_SPIDEV=y
+CONFIG_SLIMBUS_MSM_NGD=y
+CONFIG_SPMI=y
+CONFIG_SPMI_MSM_PMIC_ARB_DEBUG=y
+CONFIG_PINCTRL_MSM8953=y
+CONFIG_PINCTRL_QCOM_SPMI_PMIC=y
+CONFIG_GPIOLIB=y
+CONFIG_GPIO_SYSFS=y
+CONFIG_POWER_RESET_QCOM=y
+CONFIG_QCOM_DLOAD_MODE=y
+CONFIG_POWER_RESET_XGENE=y
+CONFIG_POWER_RESET_SYSCON=y
+CONFIG_SENSORS_QPNP_ADC_VOLTAGE=y
+CONFIG_THERMAL=y
+CONFIG_THERMAL_QPNP=y
+CONFIG_THERMAL_QPNP_ADC_TM=y
+CONFIG_THERMAL_TSENS=y
+CONFIG_MSM_BCL_PERIPHERAL_CTL=y
+CONFIG_QTI_THERMAL_LIMITS_DCVS=y
+CONFIG_REGULATOR_FIXED_VOLTAGE=y
+CONFIG_REGULATOR_CPRH_KBSS=y
+CONFIG_REGULATOR_QPNP_LABIBB=y
+CONFIG_REGULATOR_QPNP=y
+CONFIG_REGULATOR_STUB=y
+CONFIG_MEDIA_SUPPORT=y
+CONFIG_MEDIA_CAMERA_SUPPORT=y
+CONFIG_MEDIA_CONTROLLER=y
+CONFIG_VIDEO_V4L2_SUBDEV_API=y
+CONFIG_V4L_PLATFORM_DRIVERS=y
+CONFIG_MSM_VIDC_V4L2=y
+CONFIG_MSM_VIDC_GOVERNORS=y
+CONFIG_MSM_SDE_ROTATOR=y
+CONFIG_MSM_SDE_ROTATOR_EVTLOG_DEBUG=y
+CONFIG_QCOM_KGSL=y
+CONFIG_DRM=y
+CONFIG_DRM_SDE_EVTLOG_DEBUG=y
+CONFIG_DRM_SDE_RSC=y
+CONFIG_FB_VIRTUAL=y
+CONFIG_BACKLIGHT_LCD_SUPPORT=y
+CONFIG_BACKLIGHT_CLASS_DEVICE=y
+CONFIG_LOGO=y
+# CONFIG_LOGO_LINUX_MONO is not set
+# CONFIG_LOGO_LINUX_VGA16 is not set
+CONFIG_SOUND=y
+CONFIG_SND=y
+CONFIG_SND_DYNAMIC_MINORS=y
+CONFIG_SND_SOC=y
+CONFIG_UHID=y
+CONFIG_HID_APPLE=y
+CONFIG_HID_ELECOM=y
+CONFIG_HID_MAGICMOUSE=y
+CONFIG_HID_MICROSOFT=y
+CONFIG_HID_MULTITOUCH=y
+CONFIG_USB_DWC3=y
+CONFIG_NOP_USB_XCEIV=y
+CONFIG_DUAL_ROLE_USB_INTF=y
+CONFIG_USB_MSM_SSPHY_QMP=y
+CONFIG_MSM_QUSB_PHY=y
+CONFIG_USB_GADGET=y
+CONFIG_USB_GADGET_DEBUG_FILES=y
+CONFIG_USB_GADGET_DEBUG_FS=y
+CONFIG_USB_GADGET_VBUS_DRAW=500
+CONFIG_MMC=y
+CONFIG_MMC_PERF_PROFILING=y
+CONFIG_MMC_RING_BUFFER=y
+CONFIG_MMC_PARANOID_SD_INIT=y
+CONFIG_MMC_CLKGATE=y
+CONFIG_MMC_BLOCK_MINORS=32
+CONFIG_MMC_BLOCK_DEFERRED_RESUME=y
+CONFIG_MMC_TEST=y
+CONFIG_MMC_SDHCI=y
+CONFIG_MMC_SDHCI_PLTFM=y
+CONFIG_MMC_SDHCI_MSM=y
+CONFIG_NEW_LEDS=y
+CONFIG_LEDS_CLASS=y
+CONFIG_LEDS_QPNP=y
+CONFIG_LEDS_QPNP_WLED=y
+CONFIG_LEDS_TRIGGERS=y
+CONFIG_EDAC=y
+CONFIG_EDAC_MM_EDAC=y
+CONFIG_RTC_CLASS=y
+CONFIG_RTC_DRV_QPNP=y
+CONFIG_DMADEVICES=y
+CONFIG_QCOM_SPS_DMA=y
+CONFIG_UIO=y
+CONFIG_UIO_MSM_SHAREDMEM=y
+CONFIG_STAGING=y
+CONFIG_ASHMEM=y
+CONFIG_ANDROID_LOW_MEMORY_KILLER=y
+CONFIG_ION=y
+CONFIG_ION_MSM=y
+CONFIG_GSI=y
+CONFIG_IPA3=y
+CONFIG_RMNET_IPA3=y
+CONFIG_RNDIS_IPA=y
+CONFIG_SPS=y
+CONFIG_SPS_SUPPORT_NDP_BAM=y
+CONFIG_QPNP_COINCELL=y
+CONFIG_QPNP_REVID=y
+CONFIG_USB_BAM=y
+CONFIG_QCOM_MDSS_PLL=y
+CONFIG_REMOTE_SPINLOCK_MSM=y
+CONFIG_MAILBOX=y
+CONFIG_ARM_SMMU=y
+CONFIG_IOMMU_DEBUG=y
+CONFIG_IOMMU_DEBUG_TRACKING=y
+CONFIG_IOMMU_TESTS=y
+CONFIG_MSM_BOOT_STATS=y
+CONFIG_MSM_CORE_HANG_DETECT=y
+CONFIG_MSM_GLADIATOR_HANG_DETECT=y
+CONFIG_QCOM_EUD=y
+CONFIG_QCOM_WATCHDOG_V2=y
+CONFIG_QCOM_MEMORY_DUMP_V2=y
+CONFIG_QCOM_SECURE_BUFFER=y
+CONFIG_QCOM_EARLY_RANDOM=y
+CONFIG_MSM_SMEM=y
+CONFIG_MSM_GLINK=y
+CONFIG_MSM_GLINK_LOOPBACK_SERVER=y
+CONFIG_MSM_GLINK_SMEM_NATIVE_XPRT=y
+CONFIG_MSM_GLINK_SPI_XPRT=y
+CONFIG_TRACER_PKT=y
+CONFIG_MSM_SMP2P=y
+CONFIG_MSM_SMP2P_TEST=y
+CONFIG_MSM_IPC_ROUTER_GLINK_XPRT=y
+CONFIG_MSM_QMI_INTERFACE=y
+CONFIG_MSM_GLINK_PKT=y
+CONFIG_MSM_SUBSYSTEM_RESTART=y
+CONFIG_MSM_PIL=y
+CONFIG_MSM_PIL_SSR_GENERIC=y
+CONFIG_MSM_PIL_MSS_QDSP6V5=y
+CONFIG_ICNSS=y
+CONFIG_MSM_PERFORMANCE=y
+CONFIG_MSM_EVENT_TIMER=y
+CONFIG_MSM_PM=y
+CONFIG_QTI_RPM_STATS_LOG=y
+CONFIG_QCOM_FORCE_WDOG_BITE_ON_PANIC=y
+CONFIG_PWM=y
+CONFIG_PWM_QPNP=y
+CONFIG_ARM_GIC_V3_ACL=y
+CONFIG_ANDROID=y
+CONFIG_ANDROID_BINDER_IPC=y
+CONFIG_SENSORS_SSC=y
+CONFIG_MSM_TZ_LOG=y
+CONFIG_EXT2_FS=y
+CONFIG_EXT2_FS_XATTR=y
+CONFIG_EXT3_FS=y
+CONFIG_EXT4_FS_SECURITY=y
+CONFIG_QUOTA=y
+CONFIG_QUOTA_NETLINK_INTERFACE=y
+CONFIG_FUSE_FS=y
+CONFIG_MSDOS_FS=y
+CONFIG_VFAT_FS=y
+CONFIG_TMPFS_POSIX_ACL=y
+CONFIG_ECRYPT_FS=y
+CONFIG_ECRYPT_FS_MESSAGING=y
+# CONFIG_NETWORK_FILESYSTEMS is not set
+CONFIG_NLS_CODEPAGE_437=y
+CONFIG_NLS_ISO8859_1=y
+CONFIG_PRINTK_TIME=y
+CONFIG_DYNAMIC_DEBUG=y
+CONFIG_DEBUG_INFO=y
+CONFIG_PAGE_OWNER=y
+CONFIG_PAGE_OWNER_ENABLE_DEFAULT=y
+CONFIG_MAGIC_SYSRQ=y
+CONFIG_DEBUG_PAGEALLOC=y
+CONFIG_SLUB_DEBUG_PANIC_ON=y
+CONFIG_DEBUG_PAGEALLOC_ENABLE_DEFAULT=y
+CONFIG_PAGE_POISONING=y
+CONFIG_DEBUG_OBJECTS=y
+CONFIG_DEBUG_OBJECTS_FREE=y
+CONFIG_DEBUG_OBJECTS_TIMERS=y
+CONFIG_DEBUG_OBJECTS_WORK=y
+CONFIG_DEBUG_OBJECTS_RCU_HEAD=y
+CONFIG_DEBUG_OBJECTS_PERCPU_COUNTER=y
+CONFIG_SLUB_DEBUG_ON=y
+CONFIG_DEBUG_KMEMLEAK=y
+CONFIG_DEBUG_KMEMLEAK_EARLY_LOG_SIZE=4000
+CONFIG_DEBUG_KMEMLEAK_DEFAULT_OFF=y
+CONFIG_DEBUG_STACK_USAGE=y
+CONFIG_DEBUG_MEMORY_INIT=y
+CONFIG_LOCKUP_DETECTOR=y
+CONFIG_WQ_WATCHDOG=y
+CONFIG_PANIC_TIMEOUT=5
+CONFIG_PANIC_ON_SCHED_BUG=y
+CONFIG_PANIC_ON_RT_THROTTLING=y
+CONFIG_SCHEDSTATS=y
+CONFIG_SCHED_STACK_END_CHECK=y
+# CONFIG_DEBUG_PREEMPT is not set
+CONFIG_DEBUG_SPINLOCK=y
+CONFIG_DEBUG_MUTEXES=y
+CONFIG_DEBUG_ATOMIC_SLEEP=y
+CONFIG_DEBUG_LIST=y
+CONFIG_FAULT_INJECTION=y
+CONFIG_FAIL_PAGE_ALLOC=y
+CONFIG_FAULT_INJECTION_DEBUG_FS=y
+CONFIG_FAULT_INJECTION_STACKTRACE_FILTER=y
+CONFIG_IPC_LOGGING=y
+CONFIG_QCOM_RTB=y
+CONFIG_QCOM_RTB_SEPARATE_CPUS=y
+CONFIG_FUNCTION_TRACER=y
+CONFIG_IRQSOFF_TRACER=y
+CONFIG_PREEMPT_TRACER=y
+CONFIG_BLK_DEV_IO_TRACE=y
+CONFIG_CPU_FREQ_SWITCH_PROFILER=y
+CONFIG_LKDTM=y
+CONFIG_MEMTEST=y
+CONFIG_PANIC_ON_DATA_CORRUPTION=y
+CONFIG_ARM64_PTDUMP=y
+CONFIG_PID_IN_CONTEXTIDR=y
+CONFIG_CORESIGHT=y
+CONFIG_CORESIGHT_REMOTE_ETM=y
+CONFIG_CORESIGHT_REMOTE_ETM_DEFAULT_ENABLE=0
+CONFIG_CORESIGHT_STM=y
+CONFIG_CORESIGHT_TPDA=y
+CONFIG_CORESIGHT_TPDM=y
+CONFIG_CORESIGHT_CTI=y
+CONFIG_CORESIGHT_EVENT=y
+CONFIG_CORESIGHT_HWEVENT=y
+CONFIG_SECURITY_PERF_EVENTS_RESTRICT=y
+CONFIG_SECURITY=y
+CONFIG_HARDENED_USERCOPY=y
+CONFIG_SECURITY_SELINUX=y
+CONFIG_SECURITY_SMACK=y
+CONFIG_CRYPTO_CTR=y
+CONFIG_CRYPTO_XCBC=y
+CONFIG_CRYPTO_MD4=y
+CONFIG_CRYPTO_TWOFISH=y
+CONFIG_CRYPTO_ANSI_CPRNG=y
+CONFIG_CRYPTO_DEV_QCOM_MSM_QCE=y
+CONFIG_CRYPTO_DEV_QCRYPTO=y
+CONFIG_CRYPTO_DEV_QCEDEV=y
+CONFIG_CRYPTO_DEV_QCOM_ICE=y
+CONFIG_ARM64_CRYPTO=y
+CONFIG_CRYPTO_SHA1_ARM64_CE=y
+CONFIG_CRYPTO_SHA2_ARM64_CE=y
+CONFIG_CRYPTO_GHASH_ARM64_CE=y
+CONFIG_CRYPTO_AES_ARM64_CE_CCM=y
+CONFIG_CRYPTO_AES_ARM64_CE_BLK=y
+CONFIG_CRYPTO_AES_ARM64_NEON_BLK=y
+CONFIG_CRYPTO_CRC32_ARM64=y
+CONFIG_QMI_ENCDEC=y
diff --git a/arch/arm64/configs/sdm670-perf_defconfig b/arch/arm64/configs/sdm670-perf_defconfig
index cd393c2..cc7f169 100644
--- a/arch/arm64/configs/sdm670-perf_defconfig
+++ b/arch/arm64/configs/sdm670-perf_defconfig
@@ -486,6 +486,8 @@
CONFIG_QCOM_WATCHDOG_V2=y
CONFIG_QPNP_PBS=y
CONFIG_QCOM_MEMORY_DUMP_V2=y
+CONFIG_QCOM_BUS_SCALING=y
+CONFIG_QCOM_BUS_CONFIG_RPMH=y
CONFIG_QCOM_SECURE_BUFFER=y
CONFIG_QCOM_EARLY_RANDOM=y
CONFIG_MSM_SMEM=y
diff --git a/arch/arm64/configs/sdm670_defconfig b/arch/arm64/configs/sdm670_defconfig
index 17231c7..b47850c 100644
--- a/arch/arm64/configs/sdm670_defconfig
+++ b/arch/arm64/configs/sdm670_defconfig
@@ -23,6 +23,7 @@
CONFIG_CGROUP_CPUACCT=y
CONFIG_CGROUP_SCHEDTUNE=y
CONFIG_RT_GROUP_SCHED=y
+CONFIG_CGROUP_BPF=y
CONFIG_SCHED_CORE_CTL=y
CONFIG_NAMESPACES=y
# CONFIG_UTS_NS is not set
@@ -35,12 +36,13 @@
# CONFIG_RD_LZO is not set
# CONFIG_RD_LZ4 is not set
CONFIG_KALLSYMS_ALL=y
+CONFIG_BPF_SYSCALL=y
# CONFIG_AIO is not set
# CONFIG_MEMBARRIER is not set
CONFIG_EMBEDDED=y
# CONFIG_COMPAT_BRK is not set
CONFIG_PROFILING=y
-CONFIG_CC_STACKPROTECTOR_REGULAR=y
+CONFIG_CC_STACKPROTECTOR_STRONG=y
CONFIG_ARCH_MMAP_RND_COMPAT_BITS=16
CONFIG_MODULES=y
CONFIG_MODULE_UNLOAD=y
@@ -133,6 +135,7 @@
CONFIG_NETFILTER_XT_TARGET_CONNMARK=y
CONFIG_NETFILTER_XT_TARGET_CONNSECMARK=y
CONFIG_NETFILTER_XT_TARGET_IDLETIMER=y
+CONFIG_NETFILTER_XT_TARGET_HARDIDLETIMER=y
CONFIG_NETFILTER_XT_TARGET_LOG=y
CONFIG_NETFILTER_XT_TARGET_MARK=y
CONFIG_NETFILTER_XT_TARGET_NFLOG=y
@@ -160,6 +163,7 @@
CONFIG_NETFILTER_XT_MATCH_MULTIPORT=y
CONFIG_NETFILTER_XT_MATCH_POLICY=y
CONFIG_NETFILTER_XT_MATCH_PKTTYPE=y
+CONFIG_NETFILTER_XT_MATCH_QTAGUID=y
CONFIG_NETFILTER_XT_MATCH_QUOTA=y
CONFIG_NETFILTER_XT_MATCH_QUOTA2=y
CONFIG_NETFILTER_XT_MATCH_QUOTA2_LOG=y
@@ -270,9 +274,15 @@
CONFIG_PPP=y
CONFIG_PPP_BSDCOMP=y
CONFIG_PPP_DEFLATE=y
+CONFIG_PPP_FILTER=y
CONFIG_PPP_MPPE=y
+CONFIG_PPP_MULTILINK=y
+CONFIG_PPPOE=y
+CONFIG_PPPOL2TP=y
CONFIG_PPPOLAC=y
CONFIG_PPPOPNS=y
+CONFIG_PPP_ASYNC=y
+CONFIG_PPP_SYNC_TTY=y
CONFIG_USB_USBNET=y
CONFIG_WIL6210=m
CONFIG_WCNSS_MEM_PRE_ALLOC=y
@@ -495,6 +505,8 @@
CONFIG_QCOM_WATCHDOG_V2=y
CONFIG_QPNP_PBS=y
CONFIG_QCOM_MEMORY_DUMP_V2=y
+CONFIG_QCOM_BUS_SCALING=y
+CONFIG_QCOM_BUS_CONFIG_RPMH=y
CONFIG_QCOM_SECURE_BUFFER=y
CONFIG_QCOM_EARLY_RANDOM=y
CONFIG_MSM_SMEM=y
@@ -513,6 +525,7 @@
CONFIG_MSM_GLINK_PKT=y
CONFIG_MSM_SUBSYSTEM_RESTART=y
CONFIG_MSM_PIL=y
+CONFIG_MSM_SYSMON_GLINK_COMM=y
CONFIG_MSM_PIL_SSR_GENERIC=y
CONFIG_MSM_PIL_MSS_QDSP6V5=y
CONFIG_ICNSS=y
@@ -520,13 +533,16 @@
CONFIG_QCOM_COMMAND_DB=y
CONFIG_MSM_PERFORMANCE=y
CONFIG_MSM_CDSP_LOADER=y
+CONFIG_QCOM_SMCINVOKE=y
CONFIG_MSM_EVENT_TIMER=y
CONFIG_MSM_PM=y
CONFIG_MSM_QBT1000=y
+CONFIG_APSS_CORE_EA=y
CONFIG_QCOM_DCC_V2=y
CONFIG_QTI_RPM_STATS_LOG=y
CONFIG_QCOM_FORCE_WDOG_BITE_ON_PANIC=y
CONFIG_QMP_DEBUGFS_CLIENT=y
+CONFIG_MSM_REMOTEQDSS=y
CONFIG_QCOM_BIMC_BWMON=y
CONFIG_ARM_MEMLAT_MON=y
CONFIG_QCOMCCI_HWMON=y
@@ -624,13 +640,16 @@
CONFIG_CORESIGHT_TPDA=y
CONFIG_CORESIGHT_TPDM=y
CONFIG_CORESIGHT_CTI=y
+CONFIG_CORESIGHT_EVENT=y
CONFIG_CORESIGHT_HWEVENT=y
CONFIG_CORESIGHT_DUMMY=y
CONFIG_SECURITY_PERF_EVENTS_RESTRICT=y
CONFIG_SECURITY=y
CONFIG_HARDENED_USERCOPY=y
+CONFIG_FORTIFY_SOURCE=y
CONFIG_SECURITY_SELINUX=y
CONFIG_SECURITY_SMACK=y
+CONFIG_CRYPTO_CTR=y
CONFIG_CRYPTO_XCBC=y
CONFIG_CRYPTO_MD4=y
CONFIG_CRYPTO_TWOFISH=y
diff --git a/arch/arm64/configs/sdm845-perf_defconfig b/arch/arm64/configs/sdm845-perf_defconfig
index a04d0f4..fd96708 100644
--- a/arch/arm64/configs/sdm845-perf_defconfig
+++ b/arch/arm64/configs/sdm845-perf_defconfig
@@ -7,6 +7,9 @@
CONFIG_HIGH_RES_TIMERS=y
CONFIG_IRQ_TIME_ACCOUNTING=y
CONFIG_SCHED_WALT=y
+CONFIG_TASKSTATS=y
+CONFIG_TASK_XACCT=y
+CONFIG_TASK_IO_ACCOUNTING=y
CONFIG_RCU_EXPERT=y
CONFIG_RCU_FAST_NO_HZ=y
CONFIG_RCU_NOCB_CPU=y
@@ -234,6 +237,7 @@
CONFIG_BLK_DEV_RAM=y
CONFIG_BLK_DEV_RAM_SIZE=8192
CONFIG_QSEECOM=y
+CONFIG_UID_SYS_STATS=y
CONFIG_MEMORY_STATE_TIME=y
CONFIG_SCSI=y
CONFIG_BLK_DEV_SD=y
@@ -296,6 +300,7 @@
CONFIG_DIAG_CHAR=y
CONFIG_HW_RANDOM=y
CONFIG_HW_RANDOM_MSM_LEGACY=y
+# CONFIG_DEVPORT is not set
CONFIG_MSM_ADSPRPC=y
CONFIG_MSM_RDBG=m
CONFIG_I2C_CHARDEV=y
diff --git a/arch/arm64/configs/sdm845_defconfig b/arch/arm64/configs/sdm845_defconfig
index 7655c91..0d89dc7 100644
--- a/arch/arm64/configs/sdm845_defconfig
+++ b/arch/arm64/configs/sdm845_defconfig
@@ -304,6 +304,7 @@
CONFIG_DIAG_CHAR=y
CONFIG_HW_RANDOM=y
CONFIG_HW_RANDOM_MSM_LEGACY=y
+# CONFIG_DEVPORT is not set
CONFIG_MSM_ADSPRPC=y
CONFIG_MSM_RDBG=m
CONFIG_I2C_CHARDEV=y
@@ -455,9 +456,6 @@
CONFIG_EDAC_KRYO3XX_ARM64=y
CONFIG_EDAC_KRYO3XX_ARM64_PANIC_ON_CE=y
CONFIG_EDAC_KRYO3XX_ARM64_PANIC_ON_UE=y
-CONFIG_EDAC_QCOM_LLCC=y
-CONFIG_EDAC_QCOM_LLCC_PANIC_ON_CE=y
-CONFIG_EDAC_QCOM_LLCC_PANIC_ON_UE=y
CONFIG_RTC_CLASS=y
CONFIG_RTC_DRV_QPNP=y
CONFIG_DMADEVICES=y
diff --git a/arch/arm64/include/asm/arch_gicv3.h b/arch/arm64/include/asm/arch_gicv3.h
index 6ebd2c3..f1ace59 100644
--- a/arch/arm64/include/asm/arch_gicv3.h
+++ b/arch/arm64/include/asm/arch_gicv3.h
@@ -21,6 +21,7 @@
#include <asm/sysreg.h>
#define ICC_EOIR1_EL1 sys_reg(3, 0, 12, 12, 1)
+#define ICC_HPPIR1_EL1 sys_reg(3, 0, 12, 12, 2)
#define ICC_DIR_EL1 sys_reg(3, 0, 12, 11, 1)
#define ICC_IAR1_EL1 sys_reg(3, 0, 12, 12, 0)
#define ICC_SGI1R_EL1 sys_reg(3, 0, 12, 11, 5)
diff --git a/arch/arm64/include/asm/memory.h b/arch/arm64/include/asm/memory.h
index 5edb6ed..f3a142e 100644
--- a/arch/arm64/include/asm/memory.h
+++ b/arch/arm64/include/asm/memory.h
@@ -165,6 +165,11 @@
/* the offset between the kernel virtual and physical mappings */
extern u64 kimage_voffset;
+static inline unsigned long kaslr_offset(void)
+{
+ return kimage_vaddr - KIMAGE_VADDR;
+}
+
/*
* Allow all memory at the discovery stage. We will clip it later.
*/
diff --git a/arch/arm64/kernel/setup.c b/arch/arm64/kernel/setup.c
index ba29095..a58fb92 100644
--- a/arch/arm64/kernel/setup.c
+++ b/arch/arm64/kernel/setup.c
@@ -356,11 +356,11 @@
static int dump_kernel_offset(struct notifier_block *self, unsigned long v,
void *p)
{
- u64 const kaslr_offset = kimage_vaddr - KIMAGE_VADDR;
+ const unsigned long offset = kaslr_offset();
- if (IS_ENABLED(CONFIG_RANDOMIZE_BASE) && kaslr_offset > 0) {
- pr_emerg("Kernel Offset: 0x%llx from 0x%lx\n",
- kaslr_offset, KIMAGE_VADDR);
+ if (IS_ENABLED(CONFIG_RANDOMIZE_BASE) && offset > 0) {
+ pr_emerg("Kernel Offset: 0x%lx from 0x%lx\n",
+ offset, KIMAGE_VADDR);
} else {
pr_emerg("Kernel Offset: disabled\n");
}
diff --git a/arch/s390/include/asm/pgtable.h b/arch/s390/include/asm/pgtable.h
index 0cea702..d33f245 100644
--- a/arch/s390/include/asm/pgtable.h
+++ b/arch/s390/include/asm/pgtable.h
@@ -480,7 +480,7 @@
* In the case that a guest uses storage keys
* faults should no longer be backed by zero pages
*/
-#define mm_forbids_zeropage mm_use_skey
+#define mm_forbids_zeropage mm_has_pgste
static inline int mm_use_skey(struct mm_struct *mm)
{
#ifdef CONFIG_PGSTE
diff --git a/arch/s390/mm/gmap.c b/arch/s390/mm/gmap.c
index 3ba6227..cb2cd04 100644
--- a/arch/s390/mm/gmap.c
+++ b/arch/s390/mm/gmap.c
@@ -2125,6 +2125,37 @@
}
/*
+ * Remove all empty zero pages from the mapping for lazy refaulting
+ * - This must be called after mm->context.has_pgste is set, to avoid
+ * future creation of zero pages
+ * - This must be called after THP was enabled
+ */
+static int __zap_zero_pages(pmd_t *pmd, unsigned long start,
+ unsigned long end, struct mm_walk *walk)
+{
+ unsigned long addr;
+
+ for (addr = start; addr != end; addr += PAGE_SIZE) {
+ pte_t *ptep;
+ spinlock_t *ptl;
+
+ ptep = pte_offset_map_lock(walk->mm, pmd, addr, &ptl);
+ if (is_zero_pfn(pte_pfn(*ptep)))
+ ptep_xchg_direct(walk->mm, addr, ptep, __pte(_PAGE_INVALID));
+ pte_unmap_unlock(ptep, ptl);
+ }
+ return 0;
+}
+
+static inline void zap_zero_pages(struct mm_struct *mm)
+{
+ struct mm_walk walk = { .pmd_entry = __zap_zero_pages };
+
+ walk.mm = mm;
+ walk_page_range(0, TASK_SIZE, &walk);
+}
+
+/*
* switch on pgstes for its userspace process (for kvm)
*/
int s390_enable_sie(void)
@@ -2141,6 +2172,7 @@
mm->context.has_pgste = 1;
/* split thp mappings and disable thp for future mappings */
thp_split_mm(mm);
+ zap_zero_pages(mm);
up_write(&mm->mmap_sem);
return 0;
}
@@ -2153,13 +2185,6 @@
static int __s390_enable_skey(pte_t *pte, unsigned long addr,
unsigned long next, struct mm_walk *walk)
{
- /*
- * Remove all zero page mappings,
- * after establishing a policy to forbid zero page mappings
- * following faults for that page will get fresh anonymous pages
- */
- if (is_zero_pfn(pte_pfn(*pte)))
- ptep_xchg_direct(walk->mm, addr, pte, __pte(_PAGE_INVALID));
/* Clear storage key */
ptep_zap_key(walk->mm, addr, pte);
return 0;
diff --git a/arch/x86/include/asm/elf.h b/arch/x86/include/asm/elf.h
index b31761e..7bcd138 100644
--- a/arch/x86/include/asm/elf.h
+++ b/arch/x86/include/asm/elf.h
@@ -204,6 +204,7 @@
#define ELF_CORE_COPY_REGS(pr_reg, regs) \
do { \
+ unsigned long base; \
unsigned v; \
(pr_reg)[0] = (regs)->r15; \
(pr_reg)[1] = (regs)->r14; \
@@ -226,8 +227,8 @@
(pr_reg)[18] = (regs)->flags; \
(pr_reg)[19] = (regs)->sp; \
(pr_reg)[20] = (regs)->ss; \
- (pr_reg)[21] = current->thread.fsbase; \
- (pr_reg)[22] = current->thread.gsbase; \
+ rdmsrl(MSR_FS_BASE, base); (pr_reg)[21] = base; \
+ rdmsrl(MSR_KERNEL_GS_BASE, base); (pr_reg)[22] = base; \
asm("movl %%ds,%0" : "=r" (v)); (pr_reg)[23] = v; \
asm("movl %%es,%0" : "=r" (v)); (pr_reg)[24] = v; \
asm("movl %%fs,%0" : "=r" (v)); (pr_reg)[25] = v; \
diff --git a/arch/x86/kernel/process_64.c b/arch/x86/kernel/process_64.c
index b3760b3..0887d2a 100644
--- a/arch/x86/kernel/process_64.c
+++ b/arch/x86/kernel/process_64.c
@@ -136,6 +136,123 @@
}
}
+enum which_selector {
+ FS,
+ GS
+};
+
+/*
+ * Saves the FS or GS base for an outgoing thread if FSGSBASE extensions are
+ * not available. The goal is to be reasonably fast on non-FSGSBASE systems.
+ * It's forcibly inlined because it'll generate better code and this function
+ * is hot.
+ */
+static __always_inline void save_base_legacy(struct task_struct *prev_p,
+ unsigned short selector,
+ enum which_selector which)
+{
+ if (likely(selector == 0)) {
+ /*
+ * On Intel (without X86_BUG_NULL_SEG), the segment base could
+ * be the pre-existing saved base or it could be zero. On AMD
+ * (with X86_BUG_NULL_SEG), the segment base could be almost
+ * anything.
+ *
+ * This branch is very hot (it's hit twice on almost every
+ * context switch between 64-bit programs), and avoiding
+ * the RDMSR helps a lot, so we just assume that whatever
+ * value is already saved is correct. This matches historical
+ * Linux behavior, so it won't break existing applications.
+ *
+ * To avoid leaking state, on non-X86_BUG_NULL_SEG CPUs, if we
+ * report that the base is zero, it needs to actually be zero:
+ * see the corresponding logic in load_seg_legacy.
+ */
+ } else {
+ /*
+ * If the selector is 1, 2, or 3, then the base is zero on
+ * !X86_BUG_NULL_SEG CPUs and could be anything on
+ * X86_BUG_NULL_SEG CPUs. In the latter case, Linux
+ * has never attempted to preserve the base across context
+ * switches.
+ *
+ * If selector > 3, then it refers to a real segment, and
+ * saving the base isn't necessary.
+ */
+ if (which == FS)
+ prev_p->thread.fsbase = 0;
+ else
+ prev_p->thread.gsbase = 0;
+ }
+}
+
+static __always_inline void save_fsgs(struct task_struct *task)
+{
+ savesegment(fs, task->thread.fsindex);
+ savesegment(gs, task->thread.gsindex);
+ save_base_legacy(task, task->thread.fsindex, FS);
+ save_base_legacy(task, task->thread.gsindex, GS);
+}
+
+static __always_inline void loadseg(enum which_selector which,
+ unsigned short sel)
+{
+ if (which == FS)
+ loadsegment(fs, sel);
+ else
+ load_gs_index(sel);
+}
+
+static __always_inline void load_seg_legacy(unsigned short prev_index,
+ unsigned long prev_base,
+ unsigned short next_index,
+ unsigned long next_base,
+ enum which_selector which)
+{
+ if (likely(next_index <= 3)) {
+ /*
+ * The next task is using 64-bit TLS, is not using this
+ * segment at all, or is having fun with arcane CPU features.
+ */
+ if (next_base == 0) {
+ /*
+ * Nasty case: on AMD CPUs, we need to forcibly zero
+ * the base.
+ */
+ if (static_cpu_has_bug(X86_BUG_NULL_SEG)) {
+ loadseg(which, __USER_DS);
+ loadseg(which, next_index);
+ } else {
+ /*
+ * We could try to exhaustively detect cases
+ * under which we can skip the segment load,
+ * but there's really only one case that matters
+ * for performance: if both the previous and
+ * next states are fully zeroed, we can skip
+ * the load.
+ *
+ * (This assumes that prev_base == 0 has no
+ * false positives. This is the case on
+ * Intel-style CPUs.)
+ */
+ if (likely(prev_index | next_index | prev_base))
+ loadseg(which, next_index);
+ }
+ } else {
+ if (prev_index != next_index)
+ loadseg(which, next_index);
+ wrmsrl(which == FS ? MSR_FS_BASE : MSR_KERNEL_GS_BASE,
+ next_base);
+ }
+ } else {
+ /*
+ * The next task is using a real segment. Loading the selector
+ * is sufficient.
+ */
+ loadseg(which, next_index);
+ }
+}
+
int copy_thread_tls(unsigned long clone_flags, unsigned long sp,
unsigned long arg, struct task_struct *p, unsigned long tls)
{
@@ -216,10 +333,19 @@
unsigned long new_sp,
unsigned int _cs, unsigned int _ss, unsigned int _ds)
{
+ WARN_ON_ONCE(regs != current_pt_regs());
+
+ if (static_cpu_has(X86_BUG_NULL_SEG)) {
+ /* Loading zero below won't clear the base. */
+ loadsegment(fs, __USER_DS);
+ load_gs_index(__USER_DS);
+ }
+
loadsegment(fs, 0);
loadsegment(es, _ds);
loadsegment(ds, _ds);
load_gs_index(0);
+
regs->ip = new_ip;
regs->sp = new_sp;
regs->cs = _cs;
@@ -264,7 +390,6 @@
struct fpu *next_fpu = &next->fpu;
int cpu = smp_processor_id();
struct tss_struct *tss = &per_cpu(cpu_tss, cpu);
- unsigned prev_fsindex, prev_gsindex;
fpu_switch_t fpu_switch;
fpu_switch = switch_fpu_prepare(prev_fpu, next_fpu, cpu);
@@ -274,8 +399,7 @@
*
* (e.g. xen_load_tls())
*/
- savesegment(fs, prev_fsindex);
- savesegment(gs, prev_gsindex);
+ save_fsgs(prev_p);
/*
* Load TLS before restoring any segments so that segment loads
@@ -314,108 +438,10 @@
if (unlikely(next->ds | prev->ds))
loadsegment(ds, next->ds);
- /*
- * Switch FS and GS.
- *
- * These are even more complicated than DS and ES: they have
- * 64-bit bases are that controlled by arch_prctl. The bases
- * don't necessarily match the selectors, as user code can do
- * any number of things to cause them to be inconsistent.
- *
- * We don't promise to preserve the bases if the selectors are
- * nonzero. We also don't promise to preserve the base if the
- * selector is zero and the base doesn't match whatever was
- * most recently passed to ARCH_SET_FS/GS. (If/when the
- * FSGSBASE instructions are enabled, we'll need to offer
- * stronger guarantees.)
- *
- * As an invariant,
- * (fsbase != 0 && fsindex != 0) || (gsbase != 0 && gsindex != 0) is
- * impossible.
- */
- if (next->fsindex) {
- /* Loading a nonzero value into FS sets the index and base. */
- loadsegment(fs, next->fsindex);
- } else {
- if (next->fsbase) {
- /* Next index is zero but next base is nonzero. */
- if (prev_fsindex)
- loadsegment(fs, 0);
- wrmsrl(MSR_FS_BASE, next->fsbase);
- } else {
- /* Next base and index are both zero. */
- if (static_cpu_has_bug(X86_BUG_NULL_SEG)) {
- /*
- * We don't know the previous base and can't
- * find out without RDMSR. Forcibly clear it.
- */
- loadsegment(fs, __USER_DS);
- loadsegment(fs, 0);
- } else {
- /*
- * If the previous index is zero and ARCH_SET_FS
- * didn't change the base, then the base is
- * also zero and we don't need to do anything.
- */
- if (prev->fsbase || prev_fsindex)
- loadsegment(fs, 0);
- }
- }
- }
- /*
- * Save the old state and preserve the invariant.
- * NB: if prev_fsindex == 0, then we can't reliably learn the base
- * without RDMSR because Intel user code can zero it without telling
- * us and AMD user code can program any 32-bit value without telling
- * us.
- */
- if (prev_fsindex)
- prev->fsbase = 0;
- prev->fsindex = prev_fsindex;
-
- if (next->gsindex) {
- /* Loading a nonzero value into GS sets the index and base. */
- load_gs_index(next->gsindex);
- } else {
- if (next->gsbase) {
- /* Next index is zero but next base is nonzero. */
- if (prev_gsindex)
- load_gs_index(0);
- wrmsrl(MSR_KERNEL_GS_BASE, next->gsbase);
- } else {
- /* Next base and index are both zero. */
- if (static_cpu_has_bug(X86_BUG_NULL_SEG)) {
- /*
- * We don't know the previous base and can't
- * find out without RDMSR. Forcibly clear it.
- *
- * This contains a pointless SWAPGS pair.
- * Fixing it would involve an explicit check
- * for Xen or a new pvop.
- */
- load_gs_index(__USER_DS);
- load_gs_index(0);
- } else {
- /*
- * If the previous index is zero and ARCH_SET_GS
- * didn't change the base, then the base is
- * also zero and we don't need to do anything.
- */
- if (prev->gsbase || prev_gsindex)
- load_gs_index(0);
- }
- }
- }
- /*
- * Save the old state and preserve the invariant.
- * NB: if prev_gsindex == 0, then we can't reliably learn the base
- * without RDMSR because Intel user code can zero it without telling
- * us and AMD user code can program any 32-bit value without telling
- * us.
- */
- if (prev_gsindex)
- prev->gsbase = 0;
- prev->gsindex = prev_gsindex;
+ load_seg_legacy(prev->fsindex, prev->fsbase,
+ next->fsindex, next->fsbase, FS);
+ load_seg_legacy(prev->gsindex, prev->gsbase,
+ next->gsindex, next->gsbase, GS);
switch_fpu_finish(next_fpu, fpu_switch);
diff --git a/drivers/ata/pata_amd.c b/drivers/ata/pata_amd.c
index 8d4d959..8706533 100644
--- a/drivers/ata/pata_amd.c
+++ b/drivers/ata/pata_amd.c
@@ -616,6 +616,7 @@
{ PCI_VDEVICE(NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP73_IDE), 8 },
{ PCI_VDEVICE(NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP77_IDE), 8 },
{ PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_CS5536_IDE), 9 },
+ { PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_CS5536_DEV_IDE), 9 },
{ },
};
diff --git a/drivers/ata/pata_cs5536.c b/drivers/ata/pata_cs5536.c
index 6c15a55..dc12552 100644
--- a/drivers/ata/pata_cs5536.c
+++ b/drivers/ata/pata_cs5536.c
@@ -289,6 +289,7 @@
static const struct pci_device_id cs5536[] = {
{ PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_CS5536_IDE), },
+ { PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_CS5536_DEV_IDE), },
{ },
};
diff --git a/drivers/base/bus.c b/drivers/base/bus.c
index 6470eb8..e32a74e 100644
--- a/drivers/base/bus.c
+++ b/drivers/base/bus.c
@@ -736,7 +736,7 @@
out_unregister:
kobject_put(&priv->kobj);
- kfree(drv->p);
+ /* drv->p is freed in driver_release() */
drv->p = NULL;
out_put_bus:
bus_put(bus);
diff --git a/drivers/base/core.c b/drivers/base/core.c
index ac43d6f..35ab4d5 100644
--- a/drivers/base/core.c
+++ b/drivers/base/core.c
@@ -1116,7 +1116,13 @@
error = dpm_sysfs_add(dev);
if (error)
goto DPMError;
- device_pm_add(dev);
+ if ((dev->pm_domain) || (dev->type && dev->type->pm)
+ || (dev->class && (dev->class->pm || dev->class->resume))
+ || (dev->bus && (dev->bus->pm || dev->bus->resume)) ||
+ (dev->driver && dev->driver->pm)) {
+ device_pm_add(dev);
+ }
+
if (MAJOR(dev->devt)) {
error = device_create_file(dev, &dev_attr_dev);
diff --git a/drivers/base/firmware_class.c b/drivers/base/firmware_class.c
index b0beb52..914433f 100644
--- a/drivers/base/firmware_class.c
+++ b/drivers/base/firmware_class.c
@@ -958,7 +958,7 @@
timeout = MAX_JIFFY_OFFSET;
}
- timeout = wait_for_completion_interruptible_timeout(&buf->completion,
+ timeout = wait_for_completion_killable_timeout(&buf->completion,
timeout);
if (timeout == -ERESTARTSYS || !timeout) {
retval = timeout;
diff --git a/drivers/base/power/main.c b/drivers/base/power/main.c
index 4f99101..c1e56c3 100644
--- a/drivers/base/power/main.c
+++ b/drivers/base/power/main.c
@@ -162,6 +162,12 @@
pr_debug("PM: Moving %s:%s before %s:%s\n",
deva->bus ? deva->bus->name : "No Bus", dev_name(deva),
devb->bus ? devb->bus->name : "No Bus", dev_name(devb));
+ if (!((devb->pm_domain) || (devb->type && devb->type->pm)
+ || (devb->class && (devb->class->pm || devb->class->resume))
+ || (devb->bus && (devb->bus->pm || devb->bus->resume)) ||
+ (devb->driver && devb->driver->pm))) {
+ device_pm_add(devb);
+ }
/* Delete deva from dpm_list and reinsert before devb. */
list_move_tail(&deva->power.entry, &devb->power.entry);
}
@@ -176,6 +182,12 @@
pr_debug("PM: Moving %s:%s after %s:%s\n",
deva->bus ? deva->bus->name : "No Bus", dev_name(deva),
devb->bus ? devb->bus->name : "No Bus", dev_name(devb));
+ if (!((devb->pm_domain) || (devb->type && devb->type->pm)
+ || (devb->class && (devb->class->pm || devb->class->resume))
+ || (devb->bus && (devb->bus->pm || devb->bus->resume)) ||
+ (devb->driver && devb->driver->pm))) {
+ device_pm_add(devb);
+ }
/* Delete deva from dpm_list and reinsert after devb. */
list_move(&deva->power.entry, &devb->power.entry);
}
diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c
index dd220fa..74e677a 100644
--- a/drivers/bluetooth/btusb.c
+++ b/drivers/bluetooth/btusb.c
@@ -342,6 +342,7 @@
{ USB_DEVICE(0x13d3, 0x3410), .driver_info = BTUSB_REALTEK },
{ USB_DEVICE(0x13d3, 0x3416), .driver_info = BTUSB_REALTEK },
{ USB_DEVICE(0x13d3, 0x3459), .driver_info = BTUSB_REALTEK },
+ { USB_DEVICE(0x13d3, 0x3494), .driver_info = BTUSB_REALTEK },
/* Additional Realtek 8821AE Bluetooth devices */
{ USB_DEVICE(0x0b05, 0x17dc), .driver_info = BTUSB_REALTEK },
diff --git a/drivers/char/adsprpc.c b/drivers/char/adsprpc.c
index 874639f..89bf7c6 100644
--- a/drivers/char/adsprpc.c
+++ b/drivers/char/adsprpc.c
@@ -1822,18 +1822,62 @@
{
}
+static int fastrpc_search_ctx(uint64_t rctx)
+{
+ struct fastrpc_apps *me = &gfa;
+ struct fastrpc_file *fl;
+ struct hlist_node *n, *m;
+ struct smq_invoke_ctx *ictx = NULL;
+ struct smq_invoke_ctx *ctx;
+ int bfound = 0;
+
+ ctx = (struct smq_invoke_ctx *)(uint64_to_ptr(rctx));
+ if (!ctx)
+ return bfound;
+
+ spin_lock(&me->hlock);
+ hlist_for_each_entry_safe(fl, n, &me->drivers, hn) {
+ if (ctx->fl != fl)
+ continue;
+ spin_lock(&fl->hlock);
+ hlist_for_each_entry_safe(ictx, m, &fl->clst.pending, hn) {
+ if (ptr_to_uint64(ictx) == rctx) {
+ bfound = 1;
+ break;
+ }
+ }
+ hlist_for_each_entry_safe(ictx, m, &fl->clst.interrupted, hn) {
+ if (ptr_to_uint64(ictx) == rctx) {
+ bfound = 1;
+ break;
+ }
+ }
+ spin_unlock(&fl->hlock);
+ if (bfound)
+ break;
+ }
+ spin_unlock(&me->hlock);
+ return bfound;
+}
+
void fastrpc_glink_notify_rx(void *handle, const void *priv,
const void *pkt_priv, const void *ptr, size_t size)
{
struct smq_invoke_rsp *rsp = (struct smq_invoke_rsp *)ptr;
- int len = size;
+ int bfound = 0;
- while (len >= sizeof(*rsp) && rsp) {
- rsp->ctx = rsp->ctx & ~1;
- context_notify_user(uint64_to_ptr(rsp->ctx), rsp->retval);
- rsp++;
- len = len - sizeof(*rsp);
+ if (!rsp || (size < sizeof(*rsp)))
+ goto bail;
+
+ bfound = fastrpc_search_ctx((uint64_t)(rsp->ctx & ~1));
+ if (!bfound) {
+ pr_err("adsprpc: invalid context %pK\n", (void *)rsp->ctx);
+ goto bail;
}
+
+ rsp->ctx = rsp->ctx & ~1;
+ context_notify_user(uint64_to_ptr(rsp->ctx), rsp->retval);
+bail:
glink_rx_done(handle, ptr, true);
}
@@ -1899,6 +1943,8 @@
return 0;
cid = fl->cid;
+ (void)fastrpc_release_current_dsp_process(fl);
+
spin_lock(&fl->apps->hlock);
hlist_del_init(&fl->hn);
spin_unlock(&fl->apps->hlock);
@@ -1907,7 +1953,6 @@
kfree(fl);
return 0;
}
- (void)fastrpc_release_current_dsp_process(fl);
spin_lock(&fl->hlock);
fl->file_close = 1;
spin_unlock(&fl->hlock);
diff --git a/drivers/char/diag/diag_masks.c b/drivers/char/diag/diag_masks.c
index d734e29..ee76d39 100644
--- a/drivers/char/diag/diag_masks.c
+++ b/drivers/char/diag/diag_masks.c
@@ -1982,7 +1982,8 @@
void diag_send_updates_peripheral(uint8_t peripheral)
{
- diag_send_feature_mask_update(peripheral);
+ if (!driver->feature[peripheral].sent_feature_mask)
+ diag_send_feature_mask_update(peripheral);
/*
* Masks (F3, logs and events) will be sent to
* peripheral immediately following feature mask update only
diff --git a/drivers/char/diag/diagfwd_cntl.c b/drivers/char/diag/diagfwd_cntl.c
index 354c6a0..710271e 100644
--- a/drivers/char/diag/diagfwd_cntl.c
+++ b/drivers/char/diag/diagfwd_cntl.c
@@ -765,21 +765,17 @@
fwd_info_data->diagid_root = ctrl_pkt.diag_id;
} else {
i = fwd_info_cmd->num_pd - 2;
- if (i >= 0)
+ if (i >= 0 && i < MAX_PERIPHERAL_UPD)
fwd_info_cmd->diagid_user[i] =
ctrl_pkt.diag_id;
i = fwd_info_data->num_pd - 2;
- if (i >= 0)
+ if (i >= 0 && i < MAX_PERIPHERAL_UPD)
fwd_info_data->diagid_user[i] =
ctrl_pkt.diag_id;
}
}
- if (root_str)
- driver->diag_id_sent[peripheral] = 0;
-
-
DIAG_LOG(DIAG_DEBUG_PERIPHERALS,
"diag: peripheral = %d: diag_id string = %s,diag_id = %d\n",
peripheral, process_name, ctrl_pkt.diag_id);
@@ -796,22 +792,24 @@
pr_err("diag: Unable to send diag id ctrl packet to peripheral %d, err: %d\n",
peripheral, err);
} else {
- /*
- * Masks (F3, logs and events) will be sent to
- * peripheral immediately following feature mask update only
- * if diag_id support is not present or
- * diag_id support is present and diag_id has been sent to
- * peripheral.
- * With diag_id being sent now, mask will be updated
- * to peripherals.
- */
- driver->diag_id_sent[peripheral] = 1;
+ /*
+ * Masks (F3, logs and events) will be sent to
+ * peripheral immediately following feature mask update only
+ * if diag_id support is not present or
+ * diag_id support is present and diag_id has been sent to
+ * peripheral.
+ * With diag_id being sent now, mask will be updated
+ * to peripherals.
+ */
+ if (root_str) {
+ driver->diag_id_sent[peripheral] = 1;
+ diag_send_updates_peripheral(peripheral);
+ }
+ diagfwd_buffers_init(fwd_info_data);
DIAG_LOG(DIAG_DEBUG_PERIPHERALS,
"diag: diag_id sent = %d to peripheral = %d with diag_id = %d for %s :\n",
driver->diag_id_sent[peripheral], peripheral,
ctrl_pkt.diag_id, process_name);
- diag_send_updates_peripheral(peripheral);
- diagfwd_buffers_init(fwd_info_data);
}
}
diff --git a/drivers/char/diag/diagfwd_peripheral.c b/drivers/char/diag/diagfwd_peripheral.c
index 9f7f699..e00a61d 100644
--- a/drivers/char/diag/diagfwd_peripheral.c
+++ b/drivers/char/diag/diagfwd_peripheral.c
@@ -497,6 +497,19 @@
fwd_info->upd_len[i][1] = 0;
}
}
+
+ if (flag_buf_1) {
+ fwd_info->cpd_len_1 = len_cpd;
+ for (i = 0; i <= (fwd_info->num_pd - 2); i++)
+ if (fwd_info->type == TYPE_DATA)
+ fwd_info->upd_len[i][0] = len_upd[i];
+ } else if (flag_buf_2) {
+ fwd_info->cpd_len_2 = len_cpd;
+ for (i = 0; i <= (fwd_info->num_pd - 2); i++)
+ if (fwd_info->type == TYPE_DATA)
+ fwd_info->upd_len[i][1] = len_upd[i];
+ }
+
if (len_cpd) {
if (flag_buf_1)
fwd_info->cpd_len_1 = len_cpd;
@@ -1281,7 +1294,7 @@
void diagfwd_write_done(uint8_t peripheral, uint8_t type, int ctxt)
{
- int i = 0;
+ int i = 0, upd_valid_len = 0;
struct diagfwd_info *fwd_info = NULL;
if (peripheral >= NUM_PERIPHERALS || type >= NUM_TYPES)
@@ -1293,12 +1306,26 @@
if (ctxt == 1 && fwd_info->buf_1) {
/* Buffer 1 for core PD is freed */
- atomic_set(&fwd_info->buf_1->in_busy, 0);
fwd_info->cpd_len_1 = 0;
+ for (i = 0; i <= (fwd_info->num_pd - 2); i++) {
+ if (fwd_info->upd_len[i][0]) {
+ upd_valid_len = 1;
+ break;
+ }
+ }
+ if (!upd_valid_len)
+ atomic_set(&fwd_info->buf_1->in_busy, 0);
} else if (ctxt == 2 && fwd_info->buf_2) {
/* Buffer 2 for core PD is freed */
- atomic_set(&fwd_info->buf_2->in_busy, 0);
fwd_info->cpd_len_2 = 0;
+ for (i = 0; i <= (fwd_info->num_pd - 2); i++) {
+ if (fwd_info->upd_len[i][1]) {
+ upd_valid_len = 1;
+ break;
+ }
+ }
+ if (!upd_valid_len)
+ atomic_set(&fwd_info->buf_2->in_busy, 0);
} else if (ctxt >= 3 && (ctxt % 2)) {
for (i = 0; i <= (fwd_info->num_pd - 2); i++) {
if (fwd_info->buf_upd[i][0]) {
diff --git a/drivers/clk/clk.c b/drivers/clk/clk.c
index 5638333..4f2fb77 100644
--- a/drivers/clk/clk.c
+++ b/drivers/clk/clk.c
@@ -2712,9 +2712,10 @@
struct clk_core *core;
int cnt = 0;
- clock_debug_output(s, 0, "Enabled clocks:\n");
+ if (!mutex_trylock(&clk_debug_lock))
+ return;
- mutex_lock(&clk_debug_lock);
+ clock_debug_output(s, 0, "Enabled clocks:\n");
hlist_for_each_entry(core, &clk_debug_list, debug_node)
cnt += clock_debug_print_clock(core, s);
@@ -3037,14 +3038,19 @@
/*
* Print the names of all enabled clocks and their parents if
- * debug_suspend is set from debugfs.
+ * debug_suspend is set from debugfs along with print_parent flag set to 1.
+ * Otherwise if print_parent set to 0, print only enabled clocks
+ *
*/
-void clock_debug_print_enabled(void)
+void clock_debug_print_enabled(bool print_parent)
{
if (likely(!debug_suspend))
return;
- clock_debug_print_enabled_debug_suspend(NULL);
+ if (print_parent)
+ clock_debug_print_enabled_clocks(NULL);
+ else
+ clock_debug_print_enabled_debug_suspend(NULL);
}
EXPORT_SYMBOL_GPL(clock_debug_print_enabled);
diff --git a/drivers/clk/clk.h b/drivers/clk/clk.h
index b52aa25..a7d0981 100644
--- a/drivers/clk/clk.h
+++ b/drivers/clk/clk.h
@@ -23,7 +23,7 @@
void __clk_free_clk(struct clk *clk);
/* Debugfs API to print the enabled clocks */
-void clock_debug_print_enabled(void);
+void clock_debug_print_enabled(bool print_parent);
void clk_debug_print_hw(struct clk_core *clk, struct seq_file *f);
#else
diff --git a/drivers/clk/qcom/camcc-sdm845.c b/drivers/clk/qcom/camcc-sdm845.c
index 3819959..62ae8c5 100644
--- a/drivers/clk/qcom/camcc-sdm845.c
+++ b/drivers/clk/qcom/camcc-sdm845.c
@@ -442,7 +442,7 @@
.mnd_width = 0,
.hid_width = 5,
.parent_map = cam_cc_parent_map_0,
- .freq_tbl = NULL,
+ .freq_tbl = ftbl_cam_cc_csi0phytimer_clk_src,
.clkr.hw.init = &(struct clk_init_data){
.name = "cam_cc_csi3phytimer_clk_src",
.parent_names = cam_cc_parent_names_0,
diff --git a/drivers/clk/qcom/clk-rcg.h b/drivers/clk/qcom/clk-rcg.h
index 7f56fb6..60758b4 100644
--- a/drivers/clk/qcom/clk-rcg.h
+++ b/drivers/clk/qcom/clk-rcg.h
@@ -23,8 +23,6 @@
u8 pre_div;
u16 m;
u16 n;
- unsigned long src_freq;
-#define FIXED_FREQ_SRC 0
};
/**
diff --git a/drivers/clk/qcom/clk-rcg2.c b/drivers/clk/qcom/clk-rcg2.c
index 7382cfa..8d5e527 100644
--- a/drivers/clk/qcom/clk-rcg2.c
+++ b/drivers/clk/qcom/clk-rcg2.c
@@ -281,10 +281,9 @@
const struct freq_tbl *f, struct clk_rate_request *req)
{
unsigned long clk_flags, rate = req->rate;
- struct clk_rate_request parent_req = { };
struct clk_hw *p;
struct clk_rcg2 *rcg = to_clk_rcg2(hw);
- int index, ret = 0;
+ int index;
f = qcom_find_freq(f, rate);
if (!f)
@@ -315,21 +314,6 @@
req->best_parent_rate = rate;
req->rate = f->freq;
- if (f->src_freq != FIXED_FREQ_SRC) {
- rate = parent_req.rate = f->src_freq;
- parent_req.best_parent_hw = p;
- ret = __clk_determine_rate(p, &parent_req);
- if (ret)
- return ret;
-
- ret = clk_set_rate(p->clk, parent_req.rate);
- if (ret) {
- pr_err("Failed set rate(%lu) on parent for non-fixed source\n",
- parent_req.rate);
- return ret;
- }
- }
-
return 0;
}
diff --git a/drivers/clk/qcom/debugcc-sdm845.c b/drivers/clk/qcom/debugcc-sdm845.c
index ef1da5c..be84b46 100644
--- a/drivers/clk/qcom/debugcc-sdm845.c
+++ b/drivers/clk/qcom/debugcc-sdm845.c
@@ -117,6 +117,7 @@
"gcc_aggre_ufs_phy_axi_clk",
"gcc_aggre_usb3_prim_axi_clk",
"gcc_aggre_usb3_sec_axi_clk",
+ "gcc_apc_vs_clk",
"gcc_boot_rom_ahb_clk",
"gcc_camera_ahb_clk",
"gcc_camera_axi_clk",
@@ -144,12 +145,14 @@
"gcc_gpu_gpll0_div_clk_src",
"gcc_gpu_memnoc_gfx_clk",
"gcc_gpu_snoc_dvm_gfx_clk",
+ "gcc_gpu_vs_clk",
"gcc_mss_axis2_clk",
"gcc_mss_cfg_ahb_clk",
"gcc_mss_gpll0_div_clk_src",
"gcc_mss_mfab_axis_clk",
"gcc_mss_q6_memnoc_axi_clk",
"gcc_mss_snoc_axi_clk",
+ "gcc_mss_vs_clk",
"gcc_pcie_0_aux_clk",
"gcc_pcie_0_cfg_ahb_clk",
"gcc_pcie_0_mstr_axi_clk",
@@ -232,9 +235,14 @@
"gcc_usb3_sec_phy_com_aux_clk",
"gcc_usb3_sec_phy_pipe_clk",
"gcc_usb_phy_cfg_ahb2phy_clk",
+ "gcc_vdda_vs_clk",
+ "gcc_vddcx_vs_clk",
+ "gcc_vddmx_vs_clk",
"gcc_video_ahb_clk",
"gcc_video_axi_clk",
"gcc_video_xo_clk",
+ "gcc_vs_ctrl_ahb_clk",
+ "gcc_vs_ctrl_clk",
"gcc_sdcc1_ahb_clk",
"gcc_sdcc1_apps_clk",
"gcc_sdcc1_ice_core_clk",
@@ -452,6 +460,8 @@
0x11B, 0x3FF, 0, 0xF, 0, 4, 0x62008, 0x62000, 0x62004 },
{ "gcc_aggre_usb3_sec_axi_clk", 0x11C, 4, GCC,
0x11C, 0x3FF, 0, 0xF, 0, 4, 0x62008, 0x62000, 0x62004 },
+ { "gcc_apc_vs_clk", 0x113, 4, GCC,
+ 0x113, 0x3FF, 0, 0xF, 0, 4, 0x62008, 0x62000, 0x62004 },
{ "gcc_boot_rom_ahb_clk", 0x94, 4, GCC,
0x94, 0x3FF, 0, 0xF, 0, 4, 0x62008, 0x62000, 0x62004 },
{ "gcc_camera_ahb_clk", 0x3A, 4, GCC,
@@ -506,6 +516,8 @@
0x145, 0x3FF, 0, 0xF, 0, 4, 0x62008, 0x62000, 0x62004 },
{ "gcc_gpu_snoc_dvm_gfx_clk", 0x147, 4, GCC,
0x147, 0x3FF, 0, 0xF, 0, 4, 0x62008, 0x62000, 0x62004 },
+ { "gcc_gpu_vs_clk", 0x112, 4, GCC,
+ 0x112, 0x3FF, 0, 0xF, 0, 4, 0x62008, 0x62000, 0x62004 },
{ "gcc_mss_axis2_clk", 0x12F, 4, GCC,
0x12F, 0x3FF, 0, 0xF, 0, 4, 0x62008, 0x62000, 0x62004 },
{ "gcc_mss_cfg_ahb_clk", 0x12D, 4, GCC,
@@ -518,6 +530,8 @@
0x135, 0x3FF, 0, 0xF, 0, 4, 0x62008, 0x62000, 0x62004 },
{ "gcc_mss_snoc_axi_clk", 0x134, 4, GCC,
0x134, 0x3FF, 0, 0xF, 0, 4, 0x62008, 0x62000, 0x62004 },
+ { "gcc_mss_vs_clk", 0x111, 4, GCC,
+ 0x111, 0x3FF, 0, 0xF, 0, 4, 0x62008, 0x62000, 0x62004 },
{ "gcc_pcie_0_aux_clk", 0xE5, 4, GCC,
0xE5, 0x3FF, 0, 0xF, 0, 4, 0x62008, 0x62000, 0x62004 },
{ "gcc_pcie_0_cfg_ahb_clk", 0xE4, 4, GCC,
@@ -682,12 +696,22 @@
0x6A, 0x3FF, 0, 0xF, 0, 4, 0x62008, 0x62000, 0x62004 },
{ "gcc_usb_phy_cfg_ahb2phy_clk", 0x6F, 4, GCC,
0x6F, 0x3FF, 0, 0xF, 0, 4, 0x62008, 0x62000, 0x62004 },
+ { "gcc_vdda_vs_clk", 0x10E, 4, GCC,
+ 0x10E, 0x3FF, 0, 0xF, 0, 4, 0x62008, 0x62000, 0x62004 },
+ { "gcc_vddcx_vs_clk", 0x10C, 4, GCC,
+ 0x10C, 0x3FF, 0, 0xF, 0, 4, 0x62008, 0x62000, 0x62004 },
+ { "gcc_vddmx_vs_clk", 0x10D, 4, GCC,
+ 0x10D, 0x3FF, 0, 0xF, 0, 4, 0x62008, 0x62000, 0x62004 },
{ "gcc_video_ahb_clk", 0x39, 4, GCC,
0x39, 0x3FF, 0, 0xF, 0, 4, 0x62008, 0x62000, 0x62004 },
{ "gcc_video_axi_clk", 0x3F, 4, GCC,
0x3F, 0x3FF, 0, 0xF, 0, 4, 0x62008, 0x62000, 0x62004 },
{ "gcc_video_xo_clk", 0x42, 4, GCC,
0x42, 0x3FF, 0, 0xF, 0, 4, 0x62008, 0x62000, 0x62004 },
+ { "gcc_vs_ctrl_ahb_clk", 0x110, 4, GCC,
+ 0x110, 0x3FF, 0, 0xF, 0, 4, 0x62008, 0x62000, 0x62004 },
+ { "gcc_vs_ctrl_clk", 0x10F, 4, GCC,
+ 0x10F, 0x3FF, 0, 0xF, 0, 4, 0x62008, 0x62000, 0x62004 },
{ "gcc_sdcc1_ahb_clk", 0x15C, 4, GCC,
0x42, 0x3FF, 0, 0xF, 0, 4, 0x62008, 0x62000, 0x62004 },
{ "gcc_sdcc1_apps_clk", 0x15B, 4, GCC,
diff --git a/drivers/clk/qcom/dispcc-sdm845.c b/drivers/clk/qcom/dispcc-sdm845.c
index 7a2969a..b256157 100644
--- a/drivers/clk/qcom/dispcc-sdm845.c
+++ b/drivers/clk/qcom/dispcc-sdm845.c
@@ -40,8 +40,6 @@
#define DISP_CC_MISC_CMD 0x8000
#define F(f, s, h, m, n) { (f), (s), (2 * (h) - 1), (m), (n) }
-#define F_SLEW(f, s, h, m, n, src_freq) { (f), (s), (2 * (h) - 1), (m), (n), \
- (src_freq) }
static DEFINE_VDD_REGULATORS(vdd_cx, VDD_CX_NUM, 1, vdd_corner);
diff --git a/drivers/clk/qcom/videocc-sdm845.c b/drivers/clk/qcom/videocc-sdm845.c
index 3311e9f..f8fdf3f 100644
--- a/drivers/clk/qcom/videocc-sdm845.c
+++ b/drivers/clk/qcom/videocc-sdm845.c
@@ -114,6 +114,17 @@
{ }
};
+static const struct freq_tbl ftbl_video_cc_venus_clk_src_sdm670[] = {
+ F(100000000, P_VIDEO_PLL0_OUT_MAIN, 4, 0, 0),
+ F(200000000, P_VIDEO_PLL0_OUT_MAIN, 2, 0, 0),
+ F(330000000, P_VIDEO_PLL0_OUT_MAIN, 2, 0, 0),
+ F(364800000, P_VIDEO_PLL0_OUT_MAIN, 2, 0, 0),
+ F(404000000, P_VIDEO_PLL0_OUT_MAIN, 1, 0, 0),
+ F(444000000, P_VIDEO_PLL0_OUT_MAIN, 1, 0, 0),
+ F(533000000, P_VIDEO_PLL0_OUT_MAIN, 1, 0, 0),
+ { }
+};
+
static struct clk_rcg2 video_cc_venus_clk_src = {
.cmd_rcgr = 0x7f0,
.mnd_width = 0,
@@ -343,8 +354,10 @@
static void video_cc_sdm845_fixup_sdm670(void)
{
- video_cc_sdm845_fixup_sdm845v2();
-
+ video_cc_venus_clk_src.freq_tbl = ftbl_video_cc_venus_clk_src_sdm670;
+ video_cc_venus_clk_src.clkr.hw.init->rate_max[VDD_CX_LOW] = 330000000;
+ video_cc_venus_clk_src.clkr.hw.init->rate_max[VDD_CX_LOW_L1] =
+ 404000000;
}
static int video_cc_sdm845_fixup(struct platform_device *pdev)
diff --git a/drivers/cpuidle/lpm-levels.c b/drivers/cpuidle/lpm-levels.c
index 5d2e918..746cdc0 100644
--- a/drivers/cpuidle/lpm-levels.c
+++ b/drivers/cpuidle/lpm-levels.c
@@ -1606,7 +1606,7 @@
* clocks that are enabled and preventing the system level
* LPMs(XO and Vmin).
*/
- clock_debug_print_enabled();
+ clock_debug_print_enabled(true);
psci_enter_sleep(lpm_cpu, idx, false);
diff --git a/drivers/crypto/msm/ice.c b/drivers/crypto/msm/ice.c
index 6ed82ef..6fa91ae 100644
--- a/drivers/crypto/msm/ice.c
+++ b/drivers/crypto/msm/ice.c
@@ -888,7 +888,7 @@
static int qcom_ice_init_clocks(struct ice_device *ice)
{
int ret = -EINVAL;
- struct ice_clk_info *clki;
+ struct ice_clk_info *clki = NULL;
struct device *dev = ice->pdev;
struct list_head *head = &ice->clk_list_head;
@@ -932,7 +932,7 @@
static int qcom_ice_enable_clocks(struct ice_device *ice, bool enable)
{
int ret = 0;
- struct ice_clk_info *clki;
+ struct ice_clk_info *clki = NULL;
struct device *dev = ice->pdev;
struct list_head *head = &ice->clk_list_head;
@@ -1608,12 +1608,14 @@
if (ice_dev->pdev->of_node == node) {
pr_info("%s: found ice device %pK\n", __func__,
ice_dev);
+ ice_pdev = to_platform_device(ice_dev->pdev);
break;
}
}
- ice_pdev = to_platform_device(ice_dev->pdev);
- pr_info("%s: matching platform device %pK\n", __func__, ice_pdev);
+ if (ice_pdev)
+ pr_info("%s: matching platform device %pK\n", __func__,
+ ice_pdev);
out:
return ice_pdev;
}
@@ -1632,11 +1634,11 @@
list_for_each_entry(ice_dev, &ice_devices, list) {
if (!strcmp(ice_dev->ice_instance_type, storage_type)) {
pr_info("%s: found ice device %p\n", __func__, ice_dev);
- break;
+ return ice_dev;
}
}
out:
- return ice_dev;
+ return NULL;
}
static int enable_ice_setup(struct ice_device *ice_dev)
diff --git a/drivers/crypto/msm/qcedev.c b/drivers/crypto/msm/qcedev.c
index 2cf303e..94b3c17 100644
--- a/drivers/crypto/msm/qcedev.c
+++ b/drivers/crypto/msm/qcedev.c
@@ -340,8 +340,6 @@
if (authdata) {
handle->sha_ctxt.auth_data[0] = auth32[0];
handle->sha_ctxt.auth_data[1] = auth32[1];
- handle->sha_ctxt.auth_data[2] = auth32[2];
- handle->sha_ctxt.auth_data[3] = auth32[3];
}
tasklet_schedule(&pdev->done_tasklet);
diff --git a/drivers/devfreq/arm-memlat-mon.c b/drivers/devfreq/arm-memlat-mon.c
index 5802c21..4e04100 100644
--- a/drivers/devfreq/arm-memlat-mon.c
+++ b/drivers/devfreq/arm-memlat-mon.c
@@ -97,13 +97,8 @@
u64 total, enabled, running;
total = perf_event_read_value(event->pevent, &enabled, &running);
- if (total >= event->prev_count)
- ev_count = total - event->prev_count;
- else
- ev_count = (MAX_COUNT_LIM - event->prev_count) + total;
-
+ ev_count = total - event->prev_count;
event->prev_count = total;
-
return ev_count;
}
diff --git a/drivers/dma-buf/sync_file.c b/drivers/dma-buf/sync_file.c
index 5a9166a..2f34a01 100644
--- a/drivers/dma-buf/sync_file.c
+++ b/drivers/dma-buf/sync_file.c
@@ -285,7 +285,7 @@
struct sync_file *sync_file = container_of(kref, struct sync_file,
kref);
- if (test_bit(POLL_ENABLED, &sync_file->fence->flags))
+ if (test_bit(POLL_ENABLED, &sync_file->flags))
fence_remove_callback(sync_file->fence, &sync_file->cb);
fence_put(sync_file->fence);
kfree(sync_file);
@@ -305,7 +305,7 @@
poll_wait(file, &sync_file->wq, wait);
- if (!test_and_set_bit(POLL_ENABLED, &sync_file->fence->flags)) {
+ if (!test_and_set_bit(POLL_ENABLED, &sync_file->flags)) {
if (fence_add_callback(sync_file->fence, &sync_file->cb,
fence_check_cb_func) < 0)
wake_up_all(&sync_file->wq);
diff --git a/drivers/gpu/drm/bridge/adv7511/adv7511.h b/drivers/gpu/drm/bridge/adv7511/adv7511.h
index 161c923..3e74e1a 100644
--- a/drivers/gpu/drm/bridge/adv7511/adv7511.h
+++ b/drivers/gpu/drm/bridge/adv7511/adv7511.h
@@ -315,6 +315,8 @@
bool edid_read;
wait_queue_head_t wq;
+ struct work_struct hpd_work;
+
struct drm_bridge bridge;
struct drm_connector connector;
diff --git a/drivers/gpu/drm/bridge/adv7511/adv7511_drv.c b/drivers/gpu/drm/bridge/adv7511/adv7511_drv.c
index 8ed3906..213d892 100644
--- a/drivers/gpu/drm/bridge/adv7511/adv7511_drv.c
+++ b/drivers/gpu/drm/bridge/adv7511/adv7511_drv.c
@@ -402,6 +402,27 @@
return false;
}
+static void adv7511_hpd_work(struct work_struct *work)
+{
+ struct adv7511 *adv7511 = container_of(work, struct adv7511, hpd_work);
+ enum drm_connector_status status;
+ unsigned int val;
+ int ret;
+
+ ret = regmap_read(adv7511->regmap, ADV7511_REG_STATUS, &val);
+ if (ret < 0)
+ status = connector_status_disconnected;
+ else if (val & ADV7511_STATUS_HPD)
+ status = connector_status_connected;
+ else
+ status = connector_status_disconnected;
+
+ if (adv7511->connector.status != status) {
+ adv7511->connector.status = status;
+ drm_kms_helper_hotplug_event(adv7511->connector.dev);
+ }
+}
+
static int adv7511_irq_process(struct adv7511 *adv7511, bool process_hpd)
{
unsigned int irq0, irq1;
@@ -419,7 +440,7 @@
regmap_write(adv7511->regmap, ADV7511_REG_INT(1), irq1);
if (process_hpd && irq0 & ADV7511_INT0_HPD && adv7511->bridge.encoder)
- drm_helper_hpd_irq_event(adv7511->connector.dev);
+ schedule_work(&adv7511->hpd_work);
if (irq0 & ADV7511_INT0_EDID_READY || irq1 & ADV7511_INT1_DDC_ERROR) {
adv7511->edid_read = true;
@@ -1006,6 +1027,8 @@
goto err_i2c_unregister_edid;
}
+ INIT_WORK(&adv7511->hpd_work, adv7511_hpd_work);
+
if (i2c->irq) {
init_waitqueue_head(&adv7511->wq);
diff --git a/drivers/gpu/drm/msm/Makefile b/drivers/gpu/drm/msm/Makefile
index 4015832..c81832a 100644
--- a/drivers/gpu/drm/msm/Makefile
+++ b/drivers/gpu/drm/msm/Makefile
@@ -161,7 +161,8 @@
sde/sde_hw_color_processing_v1_7.o \
sde/sde_reg_dma.o \
sde/sde_hw_reg_dma_v1.o \
- sde/sde_hw_dsc.o
+ sde/sde_hw_dsc.o \
+ sde/sde_hw_ds.o
msm_drm-$(CONFIG_DRM_SDE_WB) += sde/sde_wb.o \
sde/sde_encoder_phys_wb.o
diff --git a/drivers/gpu/drm/msm/dp/dp_audio.c b/drivers/gpu/drm/msm/dp/dp_audio.c
index 67b6072..c4a60dc 100644
--- a/drivers/gpu/drm/msm/dp/dp_audio.c
+++ b/drivers/gpu/drm/msm/dp/dp_audio.c
@@ -771,8 +771,10 @@
dp_audio->off = dp_audio_off;
rc = dp_audio_init_ext_disp(audio);
- if (rc)
+ if (rc) {
+ devm_kfree(&pdev->dev, audio);
goto error;
+ }
catalog->init(catalog);
@@ -790,5 +792,5 @@
audio = container_of(dp_audio, struct dp_audio_private, dp_audio);
- kzfree(audio);
+ devm_kfree(&audio->pdev->dev, audio);
}
diff --git a/drivers/gpu/drm/msm/dp/dp_aux.c b/drivers/gpu/drm/msm/dp/dp_aux.c
index 9106027..7426fc4 100644
--- a/drivers/gpu/drm/msm/dp/dp_aux.c
+++ b/drivers/gpu/drm/msm/dp/dp_aux.c
@@ -38,6 +38,10 @@
bool cmd_busy;
bool native;
bool read;
+ bool no_send_addr;
+ bool no_send_stop;
+ u32 offset;
+ u32 segment;
struct drm_dp_aux drm_aux;
};
@@ -102,9 +106,18 @@
aux->catalog->write_data(aux->catalog);
}
+ aux->catalog->clear_trans(aux->catalog, false);
+
reg = 0; /* Transaction number == 1 */
- if (!aux->native) /* i2c */
- reg |= (BIT(8) | BIT(10) | BIT(11));
+ if (!aux->native) { /* i2c */
+ reg |= BIT(8);
+
+ if (aux->no_send_addr)
+ reg |= BIT(10);
+
+ if (aux->no_send_stop)
+ reg |= BIT(11);
+ }
reg |= BIT(9);
aux->catalog->data = reg;
@@ -150,9 +163,11 @@
{
u32 data;
u8 *dp;
- u32 i;
+ u32 i, actual_i;
u32 len = msg->size;
+ aux->catalog->clear_trans(aux->catalog, true);
+
data = 0;
data |= DP_AUX_DATA_INDEX_WRITE; /* INDEX_WRITE */
data |= BIT(0); /* read */
@@ -168,6 +183,11 @@
for (i = 0; i < len; i++) {
data = aux->catalog->read_data(aux->catalog);
*dp++ = (u8)((data >> 8) & 0xff);
+
+ actual_i = (data >> 16) & 0xFF;
+ if (i != actual_i)
+ pr_warn("Index mismatch: expected %d, found %d\n",
+ i, actual_i);
}
}
@@ -250,6 +270,87 @@
aux->catalog->reset(aux->catalog);
}
+static void dp_aux_update_offset_and_segment(struct dp_aux_private *aux,
+ struct drm_dp_aux_msg *input_msg)
+{
+ u32 const edid_address = 0x50;
+ u32 const segment_address = 0x30;
+ bool i2c_read = input_msg->request &
+ (DP_AUX_I2C_READ & DP_AUX_NATIVE_READ);
+ u8 *data = NULL;
+
+ if (aux->native || i2c_read || ((input_msg->address != edid_address) &&
+ (input_msg->address != segment_address)))
+ return;
+
+
+ data = input_msg->buffer;
+ if (input_msg->address == segment_address)
+ aux->segment = *data;
+ else
+ aux->offset = *data;
+}
+
+/**
+ * dp_aux_transfer_helper() - helper function for EDID read transactions
+ *
+ * @aux: DP AUX private structure
+ * @input_msg: input message from DRM upstream APIs
+ *
+ * return: void
+ *
+ * This helper function is used to fix EDID reads for non-compliant
+ * sinks that do not handle the i2c middle-of-transaction flag correctly.
+ */
+static void dp_aux_transfer_helper(struct dp_aux_private *aux,
+ struct drm_dp_aux_msg *input_msg)
+{
+ struct drm_dp_aux_msg helper_msg;
+ u32 const message_size = 0x10;
+ u32 const segment_address = 0x30;
+ bool i2c_mot = input_msg->request & DP_AUX_I2C_MOT;
+ bool i2c_read = input_msg->request &
+ (DP_AUX_I2C_READ & DP_AUX_NATIVE_READ);
+
+ if (!i2c_mot || !i2c_read || (input_msg->size == 0))
+ return;
+
+ aux->read = false;
+ aux->cmd_busy = true;
+ aux->no_send_addr = true;
+ aux->no_send_stop = true;
+
+ /*
+ * Send the segment address for every i2c read in which the
+ * middle-of-tranaction flag is set. This is required to support EDID
+ * reads of more than 2 blocks as the segment address is reset to 0
+ * since we are overriding the middle-of-transaction flag for read
+ * transactions.
+ */
+ memset(&helper_msg, 0, sizeof(helper_msg));
+ helper_msg.address = segment_address;
+ helper_msg.buffer = &aux->segment;
+ helper_msg.size = 1;
+ dp_aux_cmd_fifo_tx(aux, &helper_msg);
+
+ /*
+ * Send the offset address for every i2c read in which the
+ * middle-of-transaction flag is set. This will ensure that the sink
+ * will update its read pointer and return the correct portion of the
+ * EDID buffer in the subsequent i2c read trasntion triggered in the
+ * native AUX transfer function.
+ */
+ memset(&helper_msg, 0, sizeof(helper_msg));
+ helper_msg.address = input_msg->address;
+ helper_msg.buffer = &aux->offset;
+ helper_msg.size = 1;
+ dp_aux_cmd_fifo_tx(aux, &helper_msg);
+ aux->offset += message_size;
+
+ if (aux->offset == 0x80 || aux->offset == 0x100)
+ aux->segment = 0x0; /* reset segment at end of block */
+}
+
/*
* This function does the real job to process an AUX transaction.
* It will call aux_reset() function to reset the AUX channel,
@@ -268,8 +369,6 @@
mutex_lock(&aux->mutex);
aux->native = msg->request & (DP_AUX_NATIVE_WRITE & DP_AUX_NATIVE_READ);
- aux->read = msg->request & (DP_AUX_I2C_READ & DP_AUX_NATIVE_READ);
- aux->cmd_busy = true;
/* Ignore address only message */
if ((msg->size == 0) || (msg->buffer == NULL)) {
@@ -288,6 +387,20 @@
goto unlock_exit;
}
+ dp_aux_update_offset_and_segment(aux, msg);
+ dp_aux_transfer_helper(aux, msg);
+
+ aux->read = msg->request & (DP_AUX_I2C_READ & DP_AUX_NATIVE_READ);
+ aux->cmd_busy = true;
+
+ if (aux->read) {
+ aux->no_send_addr = true;
+ aux->no_send_stop = false;
+ } else {
+ aux->no_send_addr = true;
+ aux->no_send_stop = true;
+ }
+
ret = dp_aux_cmd_fifo_tx(aux, msg);
if ((ret < 0) && aux->native) {
aux->retry_cnt++;
@@ -451,5 +564,7 @@
aux = container_of(dp_aux, struct dp_aux_private, dp_aux);
+ mutex_destroy(&aux->mutex);
+
devm_kfree(aux->dev, aux);
}
diff --git a/drivers/gpu/drm/msm/dp/dp_catalog.c b/drivers/gpu/drm/msm/dp/dp_catalog.c
index 9327ddc..8b17aed 100644
--- a/drivers/gpu/drm/msm/dp/dp_catalog.c
+++ b/drivers/gpu/drm/msm/dp/dp_catalog.c
@@ -131,6 +131,33 @@
return rc;
}
+static int dp_catalog_aux_clear_trans(struct dp_catalog_aux *aux, bool read)
+{
+ int rc = 0;
+ u32 data = 0;
+ struct dp_catalog_private *catalog;
+ void __iomem *base;
+
+ if (!aux) {
+ pr_err("invalid input\n");
+ rc = -EINVAL;
+ goto end;
+ }
+
+ dp_catalog_get_priv(aux);
+ base = catalog->io->ctrl_io.base;
+
+ if (read) {
+ data = dp_read(base + DP_AUX_TRANS_CTRL);
+ data &= ~BIT(9);
+ dp_write(base + DP_AUX_TRANS_CTRL, data);
+ } else {
+ dp_write(base + DP_AUX_TRANS_CTRL, 0);
+ }
+end:
+ return rc;
+}
+
static void dp_catalog_aux_reset(struct dp_catalog_aux *aux)
{
u32 aux_ctrl;
@@ -219,13 +246,12 @@
dp_catalog_get_priv(aux);
- dp_write(catalog->io->phy_io.base + DP_PHY_PD_CTL, 0x02);
+ dp_write(catalog->io->phy_io.base + DP_PHY_PD_CTL, 0x65);
wmb(); /* make sure PD programming happened */
- dp_write(catalog->io->phy_io.base + DP_PHY_PD_CTL, 0x7d);
/* Turn on BIAS current for PHY/PLL */
dp_write(catalog->io->dp_pll_io.base +
- QSERDES_COM_BIAS_EN_CLKBUFLR_EN, 0x3f);
+ QSERDES_COM_BIAS_EN_CLKBUFLR_EN, 0x1b);
/* DP AUX CFG register programming */
for (i = 0; i < PHY_AUX_CFG_MAX; i++) {
@@ -253,9 +279,6 @@
dp_catalog_get_priv(aux);
base = catalog->io->ctrl_io.base;
- if (cmd_busy)
- dp_write(base + DP_AUX_TRANS_CTRL, 0x0);
-
aux->isr = dp_read(base + DP_INTR_STATUS);
aux->isr &= ~DP_INTR_MASK1;
ack = aux->isr & DP_INTERRUPT_STATUS1;
@@ -1213,6 +1236,7 @@
.read_data = dp_catalog_aux_read_data,
.write_data = dp_catalog_aux_write_data,
.write_trans = dp_catalog_aux_write_trans,
+ .clear_trans = dp_catalog_aux_clear_trans,
.reset = dp_catalog_aux_reset,
.update_aux_cfg = dp_catalog_aux_update_cfg,
.enable = dp_catalog_aux_enable,
diff --git a/drivers/gpu/drm/msm/dp/dp_catalog.h b/drivers/gpu/drm/msm/dp/dp_catalog.h
index 39c5c6d..c1b7a7e 100644
--- a/drivers/gpu/drm/msm/dp/dp_catalog.h
+++ b/drivers/gpu/drm/msm/dp/dp_catalog.h
@@ -67,6 +67,7 @@
u32 (*read_data)(struct dp_catalog_aux *aux);
int (*write_data)(struct dp_catalog_aux *aux);
int (*write_trans)(struct dp_catalog_aux *aux);
+ int (*clear_trans)(struct dp_catalog_aux *aux, bool read);
void (*reset)(struct dp_catalog_aux *aux);
void (*enable)(struct dp_catalog_aux *aux, bool enable);
void (*update_aux_cfg)(struct dp_catalog_aux *aux,
diff --git a/drivers/gpu/drm/msm/dp/dp_ctrl.c b/drivers/gpu/drm/msm/dp/dp_ctrl.c
index dcdcc6f..13ca6b2 100644
--- a/drivers/gpu/drm/msm/dp/dp_ctrl.c
+++ b/drivers/gpu/drm/msm/dp/dp_ctrl.c
@@ -69,7 +69,6 @@
struct completion idle_comp;
struct completion video_comp;
- bool psm_enabled;
bool orientation;
atomic_t aborted;
@@ -992,7 +991,10 @@
ctrl->catalog->mainlink_ctrl(ctrl->catalog, true);
- drm_dp_link_power_up(ctrl->aux->drm_aux, &ctrl->panel->link_info);
+ ret = ctrl->link->psm_config(ctrl->link,
+ &ctrl->panel->link_info, false);
+ if (ret)
+ goto end;
if (ctrl->link->sink_request & DP_TEST_LINK_PHY_TEST_PATTERN)
goto end;
diff --git a/drivers/gpu/drm/msm/dp/dp_ctrl.h b/drivers/gpu/drm/msm/dp/dp_ctrl.h
index 69cf6b6..d6d10ed 100644
--- a/drivers/gpu/drm/msm/dp/dp_ctrl.h
+++ b/drivers/gpu/drm/msm/dp/dp_ctrl.h
@@ -23,7 +23,6 @@
#include "dp_catalog.h"
struct dp_ctrl {
-
int (*init)(struct dp_ctrl *dp_ctrl, bool flip);
void (*deinit)(struct dp_ctrl *dp_ctrl);
int (*on)(struct dp_ctrl *dp_ctrl);
diff --git a/drivers/gpu/drm/msm/dp/dp_debug.c b/drivers/gpu/drm/msm/dp/dp_debug.c
index cc9e623..d0512e6 100644
--- a/drivers/gpu/drm/msm/dp/dp_debug.c
+++ b/drivers/gpu/drm/msm/dp/dp_debug.c
@@ -463,7 +463,11 @@
dp_debug->hdisplay = 0;
dp_debug->vrefresh = 0;
- dp_debug_init(dp_debug);
+ rc = dp_debug_init(dp_debug);
+ if (rc) {
+ devm_kfree(dev, debug);
+ goto error;
+ }
return dp_debug;
error:
@@ -495,5 +499,5 @@
dp_debug_deinit(dp_debug);
- kzfree(debug);
+ devm_kfree(debug->dev, debug);
}
diff --git a/drivers/gpu/drm/msm/dp/dp_display.c b/drivers/gpu/drm/msm/dp/dp_display.c
index 3fa376b..a0b6cef 100644
--- a/drivers/gpu/drm/msm/dp/dp_display.c
+++ b/drivers/gpu/drm/msm/dp/dp_display.c
@@ -37,6 +37,7 @@
#include "dp_debug.h"
static struct dp_display *g_dp_display;
+#define HPD_STRING_SIZE 30
struct dp_hdcp {
void *data;
@@ -434,19 +435,68 @@
(dp->link->sink_count.count == 0);
}
+static void dp_display_send_hpd_event(struct dp_display *dp_display)
+{
+ struct drm_device *dev = NULL;
+ struct dp_display_private *dp;
+ struct drm_connector *connector;
+ char name[HPD_STRING_SIZE], status[HPD_STRING_SIZE],
+ bpp[HPD_STRING_SIZE], pattern[HPD_STRING_SIZE];
+ char *envp[5];
+
+ if (!dp_display) {
+ pr_err("invalid input\n");
+ return;
+ }
+
+ dp = container_of(dp_display, struct dp_display_private, dp_display);
+ if (!dp) {
+ pr_err("invalid params\n");
+ return;
+ }
+ connector = dp->dp_display.connector;
+ dev = dp_display->connector->dev;
+
+ connector->status = connector->funcs->detect(connector, false);
+ pr_debug("[%s] status updated to %s\n",
+ connector->name,
+ drm_get_connector_status_name(connector->status));
+ snprintf(name, HPD_STRING_SIZE, "name=%s", connector->name);
+ snprintf(status, HPD_STRING_SIZE, "status=%s",
+ drm_get_connector_status_name(connector->status));
+ snprintf(bpp, HPD_STRING_SIZE, "bpp=%d",
+ dp_link_bit_depth_to_bpp(
+ dp->link->test_video.test_bit_depth));
+ snprintf(pattern, HPD_STRING_SIZE, "pattern=%d",
+ dp->link->test_video.test_video_pattern);
+
+ pr_debug("generating hotplug event [%s]:[%s] [%s] [%s]\n",
+ name, status, bpp, pattern);
+ envp[0] = name;
+ envp[1] = status;
+ envp[2] = bpp;
+ envp[3] = pattern;
+ envp[4] = NULL;
+ kobject_uevent_env(&dev->primary->kdev->kobj, KOBJ_CHANGE,
+ envp);
+}
+
static int dp_display_send_hpd_notification(struct dp_display_private *dp,
bool hpd)
{
-
if ((hpd && dp->dp_display.is_connected) ||
(!hpd && !dp->dp_display.is_connected)) {
pr_info("HPD already %s\n", (hpd ? "on" : "off"));
return 0;
}
+ /* reset video pattern flag on disconnect */
+ if (!hpd)
+ dp->panel->video_test = false;
+
dp->dp_display.is_connected = hpd;
reinit_completion(&dp->notification_comp);
- drm_helper_hpd_irq_event(dp->dp_display.connector->dev);
+ dp_display_send_hpd_event(&dp->dp_display);
if (!wait_for_completion_timeout(&dp->notification_comp, HZ * 2)) {
pr_warn("%s timeout\n", hpd ? "connect" : "disconnect");
@@ -456,25 +506,20 @@
return 0;
}
-static void dp_display_handle_test_edid(struct dp_display_private *dp)
-{
- if (dp->link->sink_request & DP_TEST_LINK_EDID_READ) {
- drm_dp_dpcd_write(dp->aux->drm_aux, DP_TEST_EDID_CHECKSUM,
- &dp->panel->edid_ctrl->edid->checksum, 1);
- drm_dp_dpcd_write(dp->aux->drm_aux, DP_TEST_RESPONSE,
- &dp->link->test_response, 1);
- }
-}
-
static int dp_display_process_hpd_high(struct dp_display_private *dp)
{
int rc = 0;
u32 max_pclk_from_edid = 0;
struct edid *edid;
+ dp->aux->init(dp->aux, dp->parser->aux_cfg);
+
+ if (dp->link->psm_enabled)
+ goto notify;
+
rc = dp->panel->read_sink_caps(dp->panel, dp->dp_display.connector);
if (rc)
- return rc;
+ goto notify;
dp->link->process_request(dp->link);
@@ -488,13 +533,14 @@
dp->audio_supported = drm_detect_monitor_audio(edid);
- dp_display_handle_test_edid(dp);
+ dp->panel->handle_sink_request(dp->panel);
max_pclk_from_edid = dp->panel->get_max_pclk(dp->panel);
dp->dp_display.max_pclk_khz = min(max_pclk_from_edid,
dp->parser->max_pclk_khz);
+notify:
dp_display_send_hpd_notification(dp, true);
end:
@@ -515,7 +561,6 @@
dp->power->init(dp->power, flip);
dp->ctrl->init(dp->ctrl, flip);
- dp->aux->init(dp->aux, dp->parser->aux_cfg);
enable_irq(dp->irq);
dp->core_initialized = true;
}
@@ -527,7 +572,6 @@
return;
}
- dp->aux->deinit(dp->aux);
dp->ctrl->deinit(dp->ctrl);
dp->power->deinit(dp->power);
disable_irq(dp->irq);
@@ -548,6 +592,8 @@
dp->audio->off(dp->audio);
dp_display_send_hpd_notification(dp, false);
+
+ dp->aux->deinit(dp->aux);
}
static int dp_display_usbpd_configure_cb(struct device *dev)
@@ -616,6 +662,10 @@
rc = dp_display_send_hpd_notification(dp, false);
+ /* if cable is disconnected, reset psm_enabled flag */
+ if (!dp->usbpd->alt_mode_cfg_done)
+ dp->link->psm_enabled = false;
+
if ((rc < 0) && dp->power_on)
dp_display_clean(dp);
@@ -624,6 +674,17 @@
return rc;
}
+static void dp_display_handle_video_request(struct dp_display_private *dp)
+{
+ if (dp->link->sink_request & DP_TEST_LINK_VIDEO_PATTERN) {
+ /* force disconnect followed by connect */
+ dp->usbpd->connect(dp->usbpd, false);
+ dp->panel->video_test = true;
+ dp->usbpd->connect(dp->usbpd, true);
+ dp->link->send_test_response(dp->link);
+ }
+}
+
static int dp_display_handle_hpd_irq(struct dp_display_private *dp)
{
if (dp->link->sink_request & DS_PORT_STATUS_CHANGED) {
@@ -639,6 +700,8 @@
dp->ctrl->handle_sink_request(dp->ctrl);
+ dp_display_handle_video_request(dp);
+
return 0;
}
@@ -686,6 +749,20 @@
return rc;
}
+static void dp_display_deinit_sub_modules(struct dp_display_private *dp)
+{
+ dp_audio_put(dp->audio);
+ dp_ctrl_put(dp->ctrl);
+ dp_link_put(dp->link);
+ dp_panel_put(dp->panel);
+ dp_aux_put(dp->aux);
+ dp_power_put(dp->power);
+ dp_catalog_put(dp->catalog);
+ dp_parser_put(dp->parser);
+ dp_usbpd_put(dp->usbpd);
+ dp_debug_put(dp->debug);
+}
+
static int dp_init_sub_modules(struct dp_display_private *dp)
{
int rc = 0;
@@ -694,6 +771,9 @@
struct dp_ctrl_in ctrl_in = {
.dev = dev,
};
+ struct dp_panel_in panel_in = {
+ .dev = dev,
+ };
cb->configure = dp_display_usbpd_configure_cb;
cb->disconnect = dp_display_usbpd_disconnect_cb;
@@ -703,49 +783,60 @@
if (IS_ERR(dp->usbpd)) {
rc = PTR_ERR(dp->usbpd);
pr_err("failed to initialize usbpd, rc = %d\n", rc);
- goto err;
+ dp->usbpd = NULL;
+ goto error;
}
dp->parser = dp_parser_get(dp->pdev);
if (IS_ERR(dp->parser)) {
rc = PTR_ERR(dp->parser);
pr_err("failed to initialize parser, rc = %d\n", rc);
- goto err;
+ dp->parser = NULL;
+ goto error_parser;
}
dp->catalog = dp_catalog_get(dev, &dp->parser->io);
if (IS_ERR(dp->catalog)) {
rc = PTR_ERR(dp->catalog);
pr_err("failed to initialize catalog, rc = %d\n", rc);
- goto err;
+ dp->catalog = NULL;
+ goto error_catalog;
}
dp->power = dp_power_get(dp->parser);
if (IS_ERR(dp->power)) {
rc = PTR_ERR(dp->power);
pr_err("failed to initialize power, rc = %d\n", rc);
- goto err;
+ dp->power = NULL;
+ goto error_power;
}
dp->aux = dp_aux_get(dev, &dp->catalog->aux, dp->parser->aux_cfg);
if (IS_ERR(dp->aux)) {
rc = PTR_ERR(dp->aux);
pr_err("failed to initialize aux, rc = %d\n", rc);
- goto err;
- }
-
- dp->panel = dp_panel_get(dev, dp->aux, &dp->catalog->panel);
- if (IS_ERR(dp->panel)) {
- rc = PTR_ERR(dp->panel);
- pr_err("failed to initialize panel, rc = %d\n", rc);
- goto err;
+ dp->aux = NULL;
+ goto error_aux;
}
dp->link = dp_link_get(dev, dp->aux);
if (IS_ERR(dp->link)) {
rc = PTR_ERR(dp->link);
pr_err("failed to initialize link, rc = %d\n", rc);
- goto err;
+ dp->link = NULL;
+ goto error_link;
+ }
+
+ panel_in.aux = dp->aux;
+ panel_in.catalog = &dp->catalog->panel;
+ panel_in.link = dp->link;
+
+ dp->panel = dp_panel_get(&panel_in);
+ if (IS_ERR(dp->panel)) {
+ rc = PTR_ERR(dp->panel);
+ pr_err("failed to initialize panel, rc = %d\n", rc);
+ dp->panel = NULL;
+ goto error_panel;
}
ctrl_in.link = dp->link;
@@ -759,13 +850,16 @@
if (IS_ERR(dp->ctrl)) {
rc = PTR_ERR(dp->ctrl);
pr_err("failed to initialize ctrl, rc = %d\n", rc);
- goto err;
+ dp->ctrl = NULL;
+ goto error_ctrl;
}
dp->audio = dp_audio_get(dp->pdev, dp->panel, &dp->catalog->audio);
if (IS_ERR(dp->audio)) {
rc = PTR_ERR(dp->audio);
pr_err("failed to initialize audio, rc = %d\n", rc);
+ dp->audio = NULL;
+ goto error_audio;
}
dp->debug = dp_debug_get(dev, dp->panel, dp->usbpd,
@@ -773,9 +867,30 @@
if (IS_ERR(dp->debug)) {
rc = PTR_ERR(dp->debug);
pr_err("failed to initialize debug, rc = %d\n", rc);
- goto err;
+ dp->debug = NULL;
+ goto error_debug;
}
-err:
+
+ return rc;
+error_debug:
+ dp_audio_put(dp->audio);
+error_audio:
+ dp_ctrl_put(dp->ctrl);
+error_ctrl:
+ dp_panel_put(dp->panel);
+error_panel:
+ dp_link_put(dp->link);
+error_link:
+ dp_aux_put(dp->aux);
+error_aux:
+ dp_power_put(dp->power);
+error_power:
+ dp_catalog_put(dp->catalog);
+error_catalog:
+ dp_parser_put(dp->parser);
+error_parser:
+ dp_usbpd_put(dp->usbpd);
+error:
return rc;
}
@@ -883,6 +998,10 @@
dp->hdcp.ops->off(dp->hdcp.data);
}
+ if (dp->usbpd->alt_mode_cfg_done && (dp->usbpd->hpd_high ||
+ dp->usbpd->forced_disconnect))
+ dp->link->psm_config(dp->link, &dp->panel->link_info, true);
+
dp->ctrl->push_idle(dp->ctrl);
error:
return rc;
@@ -969,19 +1088,58 @@
return 0;
}
-static int dp_display_get_modes(struct dp_display *dp)
+static int dp_display_get_modes(struct dp_display *dp,
+ struct dp_display_mode *dp_mode)
{
- int ret = 0;
struct dp_display_private *dp_display;
+ int ret = 0;
+
+ if (!dp) {
+ pr_err("invalid params\n");
+ return 0;
+ }
dp_display = container_of(dp, struct dp_display_private, dp_display);
- ret = _sde_edid_update_modes(dp->connector,
- dp_display->panel->edid_ctrl);
-
+ ret = dp_display->panel->get_modes(dp_display->panel,
+ dp->connector, dp_mode);
+ if (dp_mode->timing.pixel_clk_khz)
+ dp->max_pclk_khz = dp_mode->timing.pixel_clk_khz;
return ret;
}
+static bool dp_display_check_video_test(struct dp_display *dp)
+{
+ struct dp_display_private *dp_display;
+
+ if (!dp) {
+ pr_err("invalid params\n");
+ return false;
+ }
+
+ dp_display = container_of(dp, struct dp_display_private, dp_display);
+
+ if (dp_display->panel->video_test)
+ return true;
+
+ return false;
+}
+
+static int dp_display_get_test_bpp(struct dp_display *dp)
+{
+ struct dp_display_private *dp_display;
+
+ if (!dp) {
+ pr_err("invalid params\n");
+ return 0;
+ }
+
+ dp_display = container_of(dp, struct dp_display_private, dp_display);
+
+ return dp_link_bit_depth_to_bpp(
+ dp_display->link->test_video.test_bit_depth);
+}
+
static int dp_display_probe(struct platform_device *pdev)
{
int rc = 0;
@@ -1022,10 +1180,16 @@
g_dp_display->unprepare = dp_display_unprepare;
g_dp_display->request_irq = dp_request_irq;
g_dp_display->get_debug = dp_get_debug;
+ g_dp_display->send_hpd_event = dp_display_send_hpd_event;
+ g_dp_display->is_video_test = dp_display_check_video_test;
+ g_dp_display->get_test_bpp = dp_display_get_test_bpp;
rc = component_add(&pdev->dev, &dp_display_comp_ops);
- if (rc)
+ if (rc) {
pr_err("component add failed, rc=%d\n", rc);
+ dp_display_deinit_sub_modules(dp);
+ devm_kfree(&pdev->dev, dp);
+ }
return rc;
}
@@ -1051,20 +1215,6 @@
return 1;
}
-static void dp_display_deinit_sub_modules(struct dp_display_private *dp)
-{
- dp_audio_put(dp->audio);
- dp_ctrl_put(dp->ctrl);
- dp_link_put(dp->link);
- dp_panel_put(dp->panel);
- dp_aux_put(dp->aux);
- dp_power_put(dp->power);
- dp_catalog_put(dp->catalog);
- dp_parser_put(dp->parser);
- dp_usbpd_put(dp->usbpd);
- dp_debug_put(dp->debug);
-}
-
static int dp_display_remove(struct platform_device *pdev)
{
struct dp_display_private *dp;
diff --git a/drivers/gpu/drm/msm/dp/dp_display.h b/drivers/gpu/drm/msm/dp/dp_display.h
index 5943629..5539d61 100644
--- a/drivers/gpu/drm/msm/dp/dp_display.h
+++ b/drivers/gpu/drm/msm/dp/dp_display.h
@@ -19,11 +19,6 @@
#include "dp_panel.h"
-struct dp_display_mode {
- struct dp_panel_info timing;
- u32 capabilities;
-};
-
struct dp_display {
struct drm_device *drm_dev;
struct dp_bridge *bridge;
@@ -41,11 +36,15 @@
struct dp_display_mode *mode);
int (*validate_mode)(struct dp_display *dp_display,
struct dp_display_mode *mode);
- int (*get_modes)(struct dp_display *dp_display);
+ int (*get_modes)(struct dp_display *dp_display,
+ struct dp_display_mode *dp_mode);
int (*prepare)(struct dp_display *dp_display);
int (*unprepare)(struct dp_display *dp_display);
int (*request_irq)(struct dp_display *dp_display);
struct dp_debug *(*get_debug)(struct dp_display *dp_display);
+ void (*send_hpd_event)(struct dp_display *dp_display);
+ bool (*is_video_test)(struct dp_display *dp_display);
+ int (*get_test_bpp)(struct dp_display *dp_display);
};
int dp_display_get_num_of_displays(void);
diff --git a/drivers/gpu/drm/msm/dp/dp_drm.c b/drivers/gpu/drm/msm/dp/dp_drm.c
index 802f295..06f8558 100644
--- a/drivers/gpu/drm/msm/dp/dp_drm.c
+++ b/drivers/gpu/drm/msm/dp/dp_drm.c
@@ -48,7 +48,15 @@
dp_mode->timing.v_front_porch = drm_mode->vsync_start -
drm_mode->vdisplay;
- dp_mode->timing.bpp = dp->connector->display_info.bpc * num_components;
+
+ if (dp->is_video_test(dp))
+ dp_mode->timing.bpp = dp->get_test_bpp(dp);
+ else
+ dp_mode->timing.bpp = dp->connector->display_info.bpc *
+ num_components;
+
+ if (!dp_mode->timing.bpp)
+ dp_mode->timing.bpp = 24;
dp_mode->timing.refresh_rate = drm_mode->vrefresh;
@@ -375,26 +383,65 @@
return status;
}
+void dp_connector_send_hpd_event(void *display)
+{
+ struct dp_display *dp;
+
+ if (!display) {
+ pr_err("invalid input\n");
+ return;
+ }
+
+ dp = display;
+
+ if (dp->send_hpd_event)
+ dp->send_hpd_event(dp);
+}
+
int dp_connector_get_modes(struct drm_connector *connector,
void *display)
{
int rc = 0;
struct dp_display *dp;
+ struct dp_display_mode *dp_mode = NULL;
+ struct drm_display_mode *m, drm_mode;
if (!connector || !display)
- return -EINVAL;
+ return 0;
dp = display;
+
+ dp_mode = kzalloc(sizeof(*dp_mode), GFP_KERNEL);
+ if (!dp_mode)
+ return 0;
+
/* pluggable case assumes EDID is read when HPD */
if (dp->is_connected) {
- rc = dp->get_modes(dp);
+ rc = dp->get_modes(dp, dp_mode);
if (!rc)
pr_err("failed to get DP sink modes, rc=%d\n", rc);
+
+ if (dp_mode->timing.pixel_clk_khz) { /* valid DP mode */
+ memset(&drm_mode, 0x0, sizeof(drm_mode));
+ convert_to_drm_mode(dp_mode, &drm_mode);
+ m = drm_mode_duplicate(connector->dev, &drm_mode);
+ if (!m) {
+ pr_err("failed to add mode %ux%u\n",
+ drm_mode.hdisplay,
+ drm_mode.vdisplay);
+ kfree(dp_mode);
+ return 0;
+ }
+ m->width_mm = connector->display_info.width_mm;
+ m->height_mm = connector->display_info.height_mm;
+ drm_mode_probed_add(connector, m);
+ }
} else {
pr_err("No sink connected\n");
}
+ kfree(dp_mode);
- return 0;
+ return rc;
}
int dp_drm_bridge_init(void *data, struct drm_encoder *encoder)
@@ -476,6 +523,13 @@
else
return MODE_ERROR;
} else {
+ if (mode->vrefresh == 0) {
+ int vrefresh = (mode->clock * 1000) /
+ (mode->vtotal * mode->htotal);
+ if (vrefresh > 60)
+ return MODE_BAD;
+ }
+
if (mode->clock > dp_disp->max_pclk_khz)
return MODE_BAD;
else
diff --git a/drivers/gpu/drm/msm/dp/dp_drm.h b/drivers/gpu/drm/msm/dp/dp_drm.h
index 5918df1..53570f5 100644
--- a/drivers/gpu/drm/msm/dp/dp_drm.h
+++ b/drivers/gpu/drm/msm/dp/dp_drm.h
@@ -86,6 +86,8 @@
int dp_connector_get_info(struct msm_display_info *info, void *display);
+void dp_connector_send_hpd_event(void *display);
+
int dp_drm_bridge_init(void *display,
struct drm_encoder *encoder);
diff --git a/drivers/gpu/drm/msm/dp/dp_link.c b/drivers/gpu/drm/msm/dp/dp_link.c
index b62c1e9..0cf488d 100644
--- a/drivers/gpu/drm/msm/dp/dp_link.c
+++ b/drivers/gpu/drm/msm/dp/dp_link.c
@@ -17,12 +17,6 @@
#include "dp_link.h"
#include "dp_panel.h"
-enum dp_lane_count {
- DP_LANE_COUNT_1 = 1,
- DP_LANE_COUNT_2 = 2,
- DP_LANE_COUNT_4 = 4,
-};
-
enum dynamic_range {
DP_DYNAMIC_RANGE_RGB_VESA = 0x00,
DP_DYNAMIC_RANGE_RGB_CEA = 0x01,
@@ -60,42 +54,6 @@
u8 link_status[DP_LINK_STATUS_SIZE];
};
-/**
- * mdss_dp_test_bit_depth_to_bpp() - convert test bit depth to bpp
- * @tbd: test bit depth
- *
- * Returns the bits per pixel (bpp) to be used corresponding to the
- * git bit depth value. This function assumes that bit depth has
- * already been validated.
- */
-static inline u32 dp_link_bit_depth_to_bpp(u32 tbd)
-{
- u32 bpp;
-
- /*
- * Few simplistic rules and assumptions made here:
- * 1. Bit depth is per color component
- * 2. If bit depth is unknown return 0
- * 3. Assume 3 color components
- */
- switch (tbd) {
- case DP_TEST_BIT_DEPTH_6:
- bpp = 18;
- break;
- case DP_TEST_BIT_DEPTH_8:
- bpp = 24;
- break;
- case DP_TEST_BIT_DEPTH_10:
- bpp = 30;
- break;
- case DP_TEST_BIT_DEPTH_UNKNOWN:
- default:
- bpp = 0;
- }
-
- return bpp;
-}
-
static char *dp_link_get_audio_test_pattern(u32 pattern)
{
switch (pattern) {
@@ -659,33 +617,6 @@
}
/**
- * dp_link_is_link_rate_valid() - validates the link rate
- * @lane_rate: link rate requested by the sink
- *
- * Returns true if the requested link rate is supported.
- */
-static bool dp_link_is_link_rate_valid(u32 bw_code)
-{
- return ((bw_code == DP_LINK_BW_1_62) ||
- (bw_code == DP_LINK_BW_2_7) ||
- (bw_code == DP_LINK_BW_5_4) ||
- (bw_code == DP_LINK_BW_8_1));
-}
-
-/**
- * dp_link_is_lane_count_valid() - validates the lane count
- * @lane_count: lane count requested by the sink
- *
- * Returns true if the requested lane count is supported.
- */
-static bool dp_link_is_lane_count_valid(u32 lane_count)
-{
- return (lane_count == DP_LANE_COUNT_1) ||
- (lane_count == DP_LANE_COUNT_2) ||
- (lane_count == DP_LANE_COUNT_4);
-}
-
-/**
* dp_link_parse_link_training_params() - parses link training parameters from
* DPCD
* @link: Display Port Driver data
@@ -710,7 +641,7 @@
}
data = bp;
- if (!dp_link_is_link_rate_valid(data)) {
+ if (!is_link_rate_valid(data)) {
pr_err("invalid link rate = 0x%x\n", data);
ret = -EINVAL;
goto exit;
@@ -729,7 +660,7 @@
data = bp;
data &= 0x1F;
- if (!dp_link_is_lane_count_valid(data)) {
+ if (!is_lane_count_valid(data)) {
pr_err("invalid lane count = 0x%x\n", data);
ret = -EINVAL;
goto exit;
@@ -1021,7 +952,6 @@
static void dp_link_send_test_response(struct dp_link *dp_link)
{
struct dp_link_private *link = NULL;
- u32 const test_response_addr = 0x260;
u32 const response_len = 0x1;
if (!dp_link) {
@@ -1031,10 +961,52 @@
link = container_of(dp_link, struct dp_link_private, dp_link);
- drm_dp_dpcd_write(link->aux->drm_aux, test_response_addr,
+ drm_dp_dpcd_write(link->aux->drm_aux, DP_TEST_RESPONSE,
&dp_link->test_response, response_len);
}
+static int dp_link_psm_config(struct dp_link *dp_link,
+ struct drm_dp_link *link_info, bool enable)
+{
+ struct dp_link_private *link = NULL;
+ int ret = 0;
+
+ if (!dp_link) {
+ pr_err("invalid params\n");
+ return -EINVAL;
+ }
+
+ link = container_of(dp_link, struct dp_link_private, dp_link);
+
+ if (enable)
+ ret = drm_dp_link_power_down(link->aux->drm_aux, link_info);
+ else
+ ret = drm_dp_link_power_up(link->aux->drm_aux, link_info);
+
+ if (ret)
+ pr_err("Failed to %s low power mode\n",
+ (enable ? "enter" : "exit"));
+ else
+ dp_link->psm_enabled = enable;
+
+ return ret;
+}
+
+static void dp_link_send_edid_checksum(struct dp_link *dp_link, u8 checksum)
+{
+ struct dp_link_private *link = NULL;
+ u32 const response_len = 0x1;
+
+ if (!dp_link) {
+ pr_err("invalid input\n");
+ return;
+ }
+
+ link = container_of(dp_link, struct dp_link_private, dp_link);
+
+ drm_dp_dpcd_write(link->aux->drm_aux, DP_TEST_EDID_CHECKSUM,
+ &checksum, response_len);
+}
static int dp_link_parse_vx_px(struct dp_link_private *link)
{
@@ -1131,8 +1103,8 @@
test_link_rate = link->request.test_link_rate;
test_lane_count = link->request.test_lane_count;
- if (!dp_link_is_link_rate_valid(test_link_rate) ||
- !dp_link_is_lane_count_valid(test_lane_count)) {
+ if (!is_link_rate_valid(test_link_rate) ||
+ !is_lane_count_valid(test_lane_count)) {
pr_err("Invalid params: link rate = 0x%x, lane count = 0x%x\n",
test_link_rate, test_lane_count);
return -EINVAL;
@@ -1555,6 +1527,8 @@
dp_link->adjust_levels = dp_link_adjust_levels;
dp_link->send_psm_request = dp_link_send_psm_request;
dp_link->send_test_response = dp_link_send_test_response;
+ dp_link->psm_config = dp_link_psm_config;
+ dp_link->send_edid_checksum = dp_link_send_edid_checksum;
return dp_link;
error:
diff --git a/drivers/gpu/drm/msm/dp/dp_link.h b/drivers/gpu/drm/msm/dp/dp_link.h
index 9a5b75a..b1d9249 100644
--- a/drivers/gpu/drm/msm/dp/dp_link.h
+++ b/drivers/gpu/drm/msm/dp/dp_link.h
@@ -86,6 +86,7 @@
struct dp_link {
u32 sink_request;
u32 test_response;
+ bool psm_enabled;
struct dp_link_sink_count sink_count;
struct dp_link_test_video test_video;
@@ -99,6 +100,9 @@
int (*adjust_levels)(struct dp_link *dp_link, u8 *link_status);
int (*send_psm_request)(struct dp_link *dp_link, bool req);
void (*send_test_response)(struct dp_link *dp_link);
+ int (*psm_config)(struct dp_link *dp_link,
+ struct drm_dp_link *link_info, bool enable);
+ void (*send_edid_checksum)(struct dp_link *dp_link, u8 checksum);
};
static inline char *dp_link_get_phy_test_pattern(u32 phy_test_pattern_sel)
@@ -126,6 +130,42 @@
}
/**
+ * mdss_dp_test_bit_depth_to_bpp() - convert test bit depth to bpp
+ * @tbd: test bit depth
+ *
+ * Returns the bits per pixel (bpp) to be used corresponding to the
+ * git bit depth value. This function assumes that bit depth has
+ * already been validated.
+ */
+static inline u32 dp_link_bit_depth_to_bpp(u32 tbd)
+{
+ u32 bpp;
+
+ /*
+ * Few simplistic rules and assumptions made here:
+ * 1. Bit depth is per color component
+ * 2. If bit depth is unknown return 0
+ * 3. Assume 3 color components
+ */
+ switch (tbd) {
+ case DP_TEST_BIT_DEPTH_6:
+ bpp = 18;
+ break;
+ case DP_TEST_BIT_DEPTH_8:
+ bpp = 24;
+ break;
+ case DP_TEST_BIT_DEPTH_10:
+ bpp = 30;
+ break;
+ case DP_TEST_BIT_DEPTH_UNKNOWN:
+ default:
+ bpp = 0;
+ }
+
+ return bpp;
+}
+
+/**
* dp_link_get() - get the functionalities of dp test module
*
*
diff --git a/drivers/gpu/drm/msm/dp/dp_panel.c b/drivers/gpu/drm/msm/dp/dp_panel.c
index 56b2d37..2b27b3e 100644
--- a/drivers/gpu/drm/msm/dp/dp_panel.c
+++ b/drivers/gpu/drm/msm/dp/dp_panel.c
@@ -27,10 +27,28 @@
struct device *dev;
struct dp_panel dp_panel;
struct dp_aux *aux;
+ struct dp_link *link;
struct dp_catalog_panel *catalog;
bool aux_cfg_update_done;
};
+static const struct dp_panel_info fail_safe = {
+ .h_active = 640,
+ .v_active = 480,
+ .h_back_porch = 48,
+ .h_front_porch = 16,
+ .h_sync_width = 96,
+ .h_active_low = 0,
+ .v_back_porch = 33,
+ .v_front_porch = 10,
+ .v_sync_width = 2,
+ .v_active_low = 0,
+ .h_skew = 0,
+ .refresh_rate = 60,
+ .pixel_clk_khz = 25200,
+ .bpp = 24,
+};
+
static int dp_panel_read_dpcd(struct dp_panel *dp_panel)
{
int rlen, rc = 0;
@@ -100,6 +118,23 @@
return rc;
}
+static int dp_panel_set_default_link_params(struct dp_panel *dp_panel)
+{
+ struct drm_dp_link *link_info;
+ const int default_bw_code = 162000;
+ const int default_num_lanes = 1;
+
+ if (!dp_panel) {
+ pr_err("invalid input\n");
+ return -EINVAL;
+ }
+ link_info = &dp_panel->link_info;
+ link_info->rate = default_bw_code;
+ link_info->num_lanes = default_num_lanes;
+ pr_debug("link_rate=%d num_lanes=%d\n",
+ link_info->rate, link_info->num_lanes);
+ return 0;
+}
static int dp_panel_read_edid(struct dp_panel *dp_panel,
struct drm_connector *connector)
@@ -145,14 +180,16 @@
panel = container_of(dp_panel, struct dp_panel_private, dp_panel);
rc = dp_panel_read_dpcd(dp_panel);
- if (rc) {
- pr_err("panel dpcd read failed\n");
- return rc;
+ if (rc || !is_link_rate_valid(drm_dp_link_rate_to_bw_code(
+ dp_panel->link_info.rate)) || !is_lane_count_valid(
+ dp_panel->link_info.num_lanes)) {
+ pr_err("panel dpcd read failed/incorrect, set default params\n");
+ dp_panel_set_default_link_params(dp_panel);
}
rc = dp_panel_read_edid(dp_panel, connector);
if (rc) {
- pr_err("panel edid read failed\n");
+ pr_err("panel edid read failed, set failsafe mode\n");
return rc;
}
@@ -193,6 +230,94 @@
return max_pclk_rate_khz;
}
+static void dp_panel_set_test_mode(struct dp_panel_private *panel,
+ struct dp_display_mode *mode)
+{
+ struct dp_panel_info *pinfo = NULL;
+ struct dp_link_test_video *test_info = NULL;
+
+ if (!panel) {
+ pr_err("invalid params\n");
+ return;
+ }
+
+ pinfo = &mode->timing;
+ test_info = &panel->link->test_video;
+
+ pinfo->h_active = test_info->test_h_width;
+ pinfo->h_sync_width = test_info->test_hsync_width;
+ pinfo->h_back_porch = test_info->test_h_start -
+ test_info->test_hsync_width;
+ pinfo->h_front_porch = test_info->test_h_total -
+ (test_info->test_h_start + test_info->test_h_width);
+
+ pinfo->v_active = test_info->test_v_height;
+ pinfo->v_sync_width = test_info->test_vsync_width;
+ pinfo->v_back_porch = test_info->test_v_start -
+ test_info->test_vsync_width;
+ pinfo->v_front_porch = test_info->test_v_total -
+ (test_info->test_v_start + test_info->test_v_height);
+
+ pinfo->bpp = dp_link_bit_depth_to_bpp(test_info->test_bit_depth);
+ pinfo->h_active_low = test_info->test_hsync_pol;
+ pinfo->v_active_low = test_info->test_vsync_pol;
+
+ pinfo->refresh_rate = test_info->test_rr_n;
+ pinfo->pixel_clk_khz = test_info->test_h_total *
+ test_info->test_v_total * pinfo->refresh_rate;
+
+ if (test_info->test_rr_d == 0)
+ pinfo->pixel_clk_khz /= 1000;
+ else
+ pinfo->pixel_clk_khz /= 1001;
+
+ if (test_info->test_h_width == 640)
+ pinfo->pixel_clk_khz = 25170;
+}
+
+static int dp_panel_get_modes(struct dp_panel *dp_panel,
+ struct drm_connector *connector, struct dp_display_mode *mode)
+{
+ struct dp_panel_private *panel;
+
+ if (!dp_panel) {
+ pr_err("invalid input\n");
+ return -EINVAL;
+ }
+
+ panel = container_of(dp_panel, struct dp_panel_private, dp_panel);
+
+ if (dp_panel->video_test) {
+ dp_panel_set_test_mode(panel, mode);
+ return 1;
+ } else if (dp_panel->edid_ctrl->edid) {
+ return _sde_edid_update_modes(connector, dp_panel->edid_ctrl);
+ } else { /* fail-safe mode */
+ memcpy(&mode->timing, &fail_safe,
+ sizeof(fail_safe));
+ return 1;
+ }
+}
+
+static void dp_panel_handle_sink_request(struct dp_panel *dp_panel)
+{
+ struct dp_panel_private *panel;
+
+ if (!dp_panel) {
+ pr_err("invalid input\n");
+ return;
+ }
+
+ panel = container_of(dp_panel, struct dp_panel_private, dp_panel);
+
+ if (panel->link->sink_request & DP_TEST_LINK_EDID_READ) {
+ u8 checksum = sde_get_edid_checksum(dp_panel->edid_ctrl);
+
+ panel->link->send_edid_checksum(panel->link, checksum);
+ panel->link->send_test_response(panel->link);
+ }
+}
+
static int dp_panel_timing_cfg(struct dp_panel *dp_panel)
{
int rc = 0;
@@ -351,28 +476,28 @@
return min_link_rate_khz;
}
-struct dp_panel *dp_panel_get(struct device *dev, struct dp_aux *aux,
- struct dp_catalog_panel *catalog)
+struct dp_panel *dp_panel_get(struct dp_panel_in *in)
{
int rc = 0;
struct dp_panel_private *panel;
struct dp_panel *dp_panel;
- if (!dev || !aux || !catalog) {
+ if (!in->dev || !in->catalog || !in->aux || !in->link) {
pr_err("invalid input\n");
rc = -EINVAL;
goto error;
}
- panel = devm_kzalloc(dev, sizeof(*panel), GFP_KERNEL);
+ panel = devm_kzalloc(in->dev, sizeof(*panel), GFP_KERNEL);
if (!panel) {
rc = -ENOMEM;
goto error;
}
- panel->dev = dev;
- panel->aux = aux;
- panel->catalog = catalog;
+ panel->dev = in->dev;
+ panel->aux = in->aux;
+ panel->catalog = in->catalog;
+ panel->link = in->link;
dp_panel = &panel->dp_panel;
panel->aux_cfg_update_done = false;
@@ -384,6 +509,8 @@
dp_panel->read_sink_caps = dp_panel_read_sink_caps;
dp_panel->get_min_req_link_rate = dp_panel_get_min_req_link_rate;
dp_panel->get_max_pclk = dp_panel_get_max_pclk;
+ dp_panel->get_modes = dp_panel_get_modes;
+ dp_panel->handle_sink_request = dp_panel_handle_sink_request;
return dp_panel;
error:
diff --git a/drivers/gpu/drm/msm/dp/dp_panel.h b/drivers/gpu/drm/msm/dp/dp_panel.h
index a94f4b8..4486a84 100644
--- a/drivers/gpu/drm/msm/dp/dp_panel.h
+++ b/drivers/gpu/drm/msm/dp/dp_panel.h
@@ -16,8 +16,16 @@
#define _DP_PANEL_H_
#include "dp_aux.h"
+#include "dp_link.h"
+#include "dp_usbpd.h"
#include "sde_edid_parser.h"
+enum dp_lane_count {
+ DP_LANE_COUNT_1 = 1,
+ DP_LANE_COUNT_2 = 2,
+ DP_LANE_COUNT_4 = 4,
+};
+
#define DP_MAX_DOWNSTREAM_PORTS 0x10
struct dp_panel_info {
@@ -37,6 +45,18 @@
u32 bpp;
};
+struct dp_display_mode {
+ struct dp_panel_info timing;
+ u32 capabilities;
+};
+
+struct dp_panel_in {
+ struct device *dev;
+ struct dp_aux *aux;
+ struct dp_link *link;
+ struct dp_catalog_panel *catalog;
+};
+
struct dp_panel {
/* dpcd raw data */
u8 dpcd[DP_RECEIVER_CAP_SIZE];
@@ -46,6 +66,7 @@
struct sde_edid_ctrl *edid_ctrl;
struct drm_connector *connector;
struct dp_panel_info pinfo;
+ bool video_test;
u32 vic;
u32 max_pclk_khz;
@@ -58,9 +79,38 @@
struct drm_connector *connector);
u32 (*get_min_req_link_rate)(struct dp_panel *dp_panel);
u32 (*get_max_pclk)(struct dp_panel *dp_panel);
+ int (*get_modes)(struct dp_panel *dp_panel,
+ struct drm_connector *connector, struct dp_display_mode *mode);
+ void (*handle_sink_request)(struct dp_panel *dp_panel);
};
-struct dp_panel *dp_panel_get(struct device *dev, struct dp_aux *aux,
- struct dp_catalog_panel *catalog);
+/**
+ * is_link_rate_valid() - validates the link rate
+ * @lane_rate: link rate requested by the sink
+ *
+ * Returns true if the requested link rate is supported.
+ */
+static inline bool is_link_rate_valid(u32 bw_code)
+{
+ return ((bw_code == DP_LINK_BW_1_62) ||
+ (bw_code == DP_LINK_BW_2_7) ||
+ (bw_code == DP_LINK_BW_5_4) ||
+ (bw_code == DP_LINK_BW_8_1));
+}
+
+/**
+ * dp_link_is_lane_count_valid() - validates the lane count
+ * @lane_count: lane count requested by the sink
+ *
+ * Returns true if the requested lane count is supported.
+ */
+static inline bool is_lane_count_valid(u32 lane_count)
+{
+ return (lane_count == DP_LANE_COUNT_1) ||
+ (lane_count == DP_LANE_COUNT_2) ||
+ (lane_count == DP_LANE_COUNT_4);
+}
+
+struct dp_panel *dp_panel_get(struct dp_panel_in *in);
void dp_panel_put(struct dp_panel *dp_panel);
#endif /* _DP_PANEL_H_ */
diff --git a/drivers/gpu/drm/msm/dp/dp_power.c b/drivers/gpu/drm/msm/dp/dp_power.c
index 60c8966..eb787fa 100644
--- a/drivers/gpu/drm/msm/dp/dp_power.c
+++ b/drivers/gpu/drm/msm/dp/dp_power.c
@@ -612,8 +612,12 @@
void dp_power_put(struct dp_power *dp_power)
{
- struct dp_power_private *power = container_of(dp_power,
- struct dp_power_private, dp_power);
+ struct dp_power_private *power = NULL;
+
+ if (!dp_power)
+ return;
+
+ power = container_of(dp_power, struct dp_power_private, dp_power);
devm_kfree(&power->pdev->dev, power);
}
diff --git a/drivers/gpu/drm/msm/dp/dp_usbpd.c b/drivers/gpu/drm/msm/dp/dp_usbpd.c
index c0bcdda..98781abb 100644
--- a/drivers/gpu/drm/msm/dp/dp_usbpd.c
+++ b/drivers/gpu/drm/msm/dp/dp_usbpd.c
@@ -73,8 +73,6 @@
struct dp_usbpd dp_usbpd;
enum dp_usbpd_alt_mode alt_mode;
u32 dp_usbpd_config;
-
- bool forced_disconnect;
};
static const char *dp_usbpd_pin_name(u8 pin)
@@ -347,7 +345,7 @@
dp_usbpd_send_event(pd, DP_USBPD_EVT_STATUS);
break;
case USBPD_SVDM_ATTENTION:
- if (pd->forced_disconnect)
+ if (pd->dp_usbpd.forced_disconnect)
break;
pd->vdo = *vdos;
@@ -412,7 +410,7 @@
pd = container_of(dp_usbpd, struct dp_usbpd_private, dp_usbpd);
dp_usbpd->hpd_high = hpd;
- pd->forced_disconnect = !hpd;
+ dp_usbpd->forced_disconnect = !hpd;
if (hpd)
pd->dp_cb->configure(pd->dev);
@@ -466,7 +464,7 @@
if (rc) {
pr_err("pd registration failed\n");
rc = -ENODEV;
- kfree(usbpd);
+ devm_kfree(dev, usbpd);
goto error;
}
@@ -487,5 +485,7 @@
usbpd = container_of(dp_usbpd, struct dp_usbpd_private, dp_usbpd);
- kfree(usbpd);
+ usbpd_unregister_svid(usbpd->pd, &usbpd->svid_handler);
+
+ devm_kfree(usbpd->dev, usbpd);
}
diff --git a/drivers/gpu/drm/msm/dp/dp_usbpd.h b/drivers/gpu/drm/msm/dp/dp_usbpd.h
index 2682e98..5b392f5 100644
--- a/drivers/gpu/drm/msm/dp/dp_usbpd.h
+++ b/drivers/gpu/drm/msm/dp/dp_usbpd.h
@@ -63,6 +63,7 @@
bool hpd_irq;
bool alt_mode_cfg_done;
bool debug_en;
+ bool forced_disconnect;
int (*connect)(struct dp_usbpd *dp_usbpd, bool hpd);
};
diff --git a/drivers/gpu/drm/msm/dsi-staging/dsi_catalog.c b/drivers/gpu/drm/msm/dsi-staging/dsi_catalog.c
index e9dabb1..38a6e47 100644
--- a/drivers/gpu/drm/msm/dsi-staging/dsi_catalog.c
+++ b/drivers/gpu/drm/msm/dsi-staging/dsi_catalog.c
@@ -28,6 +28,7 @@
ctrl->ops.video_engine_en = dsi_ctrl_hw_cmn_video_engine_en;
ctrl->ops.video_engine_setup = dsi_ctrl_hw_cmn_video_engine_setup;
ctrl->ops.set_video_timing = dsi_ctrl_hw_cmn_set_video_timing;
+ ctrl->ops.set_timing_db = dsi_ctrl_hw_cmn_set_timing_db;
ctrl->ops.cmd_engine_setup = dsi_ctrl_hw_cmn_cmd_engine_setup;
ctrl->ops.setup_cmd_stream = dsi_ctrl_hw_cmn_setup_cmd_stream;
ctrl->ops.ctrl_en = dsi_ctrl_hw_cmn_ctrl_en;
@@ -58,6 +59,7 @@
ctrl->ops.phy_reset_config = dsi_ctrl_hw_cmn_phy_reset_config;
ctrl->ops.setup_misr = dsi_ctrl_hw_cmn_setup_misr;
ctrl->ops.collect_misr = dsi_ctrl_hw_cmn_collect_misr;
+ ctrl->ops.debug_bus = dsi_ctrl_hw_cmn_debug_bus;
switch (version) {
case DSI_CTRL_VERSION_1_4:
diff --git a/drivers/gpu/drm/msm/dsi-staging/dsi_catalog.h b/drivers/gpu/drm/msm/dsi-staging/dsi_catalog.h
index e8d594c..84448ec 100644
--- a/drivers/gpu/drm/msm/dsi-staging/dsi_catalog.h
+++ b/drivers/gpu/drm/msm/dsi-staging/dsi_catalog.h
@@ -104,6 +104,7 @@
/* DSI controller common ops */
u32 dsi_ctrl_hw_cmn_get_interrupt_status(struct dsi_ctrl_hw *ctrl);
+void dsi_ctrl_hw_cmn_debug_bus(struct dsi_ctrl_hw *ctrl);
void dsi_ctrl_hw_cmn_clear_interrupt_status(struct dsi_ctrl_hw *ctrl, u32 ints);
void dsi_ctrl_hw_cmn_enable_status_interrupts(struct dsi_ctrl_hw *ctrl,
u32 ints);
@@ -132,7 +133,8 @@
struct dsi_video_engine_cfg *cfg);
void dsi_ctrl_hw_cmn_set_video_timing(struct dsi_ctrl_hw *ctrl,
struct dsi_mode_info *mode);
-
+void dsi_ctrl_hw_cmn_set_timing_db(struct dsi_ctrl_hw *ctrl,
+ bool enable);
void dsi_ctrl_hw_cmn_cmd_engine_setup(struct dsi_ctrl_hw *ctrl,
struct dsi_host_common_cfg *common_cfg,
struct dsi_cmd_engine_cfg *cfg);
diff --git a/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl.c b/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl.c
index 4756bf6..0db99f4 100644
--- a/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl.c
+++ b/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl.c
@@ -38,6 +38,8 @@
#define DSI_CTRL_TX_TO_MS 200
#define TO_ON_OFF(x) ((x) ? "ON" : "OFF")
+
+#define CEIL(x, y) (((x) + ((y)-1)) / (y))
/**
* enum dsi_ctrl_driver_ops - controller driver ops
*/
@@ -890,6 +892,38 @@
return rc;
}
+static void dsi_ctrl_wait_for_video_done(struct dsi_ctrl *dsi_ctrl)
+{
+ u32 v_total = 0, v_blank = 0, sleep_ms = 0, fps = 0, ret;
+ struct dsi_mode_info *timing;
+
+ if (dsi_ctrl->host_config.panel_mode != DSI_OP_VIDEO_MODE)
+ return;
+
+ dsi_ctrl->hw.ops.clear_interrupt_status(&dsi_ctrl->hw,
+ DSI_VIDEO_MODE_FRAME_DONE);
+
+ dsi_ctrl_enable_status_interrupt(dsi_ctrl,
+ DSI_SINT_VIDEO_MODE_FRAME_DONE, NULL);
+ reinit_completion(&dsi_ctrl->irq_info.vid_frame_done);
+ ret = wait_for_completion_timeout(
+ &dsi_ctrl->irq_info.vid_frame_done,
+ msecs_to_jiffies(DSI_CTRL_TX_TO_MS));
+ if (ret <= 0)
+ pr_debug("wait for video done failed\n");
+ dsi_ctrl_disable_status_interrupt(dsi_ctrl,
+ DSI_SINT_VIDEO_MODE_FRAME_DONE);
+
+ timing = &(dsi_ctrl->host_config.video_timing);
+ v_total = timing->v_sync_width + timing->v_back_porch +
+ timing->v_front_porch + timing->v_active;
+ v_blank = timing->v_sync_width + timing->v_back_porch;
+ fps = timing->refresh_rate;
+
+ sleep_ms = CEIL((v_blank * 1000), (v_total * fps)) + 1;
+ udelay(sleep_ms * 1000);
+}
+
static int dsi_message_tx(struct dsi_ctrl *dsi_ctrl,
const struct mipi_dsi_msg *msg,
u32 flags)
@@ -971,6 +1005,7 @@
}
if (!(flags & DSI_CTRL_CMD_DEFER_TRIGGER)) {
+ dsi_ctrl_wait_for_video_done(dsi_ctrl);
dsi_ctrl_enable_status_interrupt(dsi_ctrl,
DSI_SINT_CMD_MODE_DMA_DONE, NULL);
reinit_completion(&dsi_ctrl->irq_info.cmd_dma_done);
@@ -1431,6 +1466,26 @@
},
};
+#if defined(CONFIG_DEBUG_FS)
+
+void dsi_ctrl_debug_dump(void)
+{
+ struct list_head *pos, *tmp;
+ struct dsi_ctrl *ctrl = NULL;
+
+ mutex_lock(&dsi_ctrl_list_lock);
+ list_for_each_safe(pos, tmp, &dsi_ctrl_list) {
+ struct dsi_ctrl_list_item *n;
+
+ n = list_entry(pos, struct dsi_ctrl_list_item, list);
+ ctrl = n->ctrl;
+ pr_err("dsi ctrl:%d\n", ctrl->cell_index);
+ ctrl->hw.ops.debug_bus(&ctrl->hw);
+ }
+ mutex_unlock(&dsi_ctrl_list_lock);
+}
+
+#endif
/**
* dsi_ctrl_get() - get a dsi_ctrl handle from an of_node
* @of_node: of_node of the DSI controller.
@@ -1647,7 +1702,7 @@
host_mode = &dsi_ctrl->host_config.video_timing;
memcpy(host_mode, timing, sizeof(*host_mode));
-
+ dsi_ctrl->hw.ops.set_timing_db(&dsi_ctrl->hw, true);
dsi_ctrl->hw.ops.set_video_timing(&dsi_ctrl->hw, host_mode);
exit:
@@ -1655,6 +1710,53 @@
return rc;
}
+/**
+ * dsi_ctrl_timing_db_update() - update only controller Timing DB
+ * @dsi_ctrl: DSI controller handle.
+ * @enable: Enable/disable Timing DB register
+ *
+ * Update timing db register value during dfps usecases
+ *
+ * Return: error code.
+ */
+int dsi_ctrl_timing_db_update(struct dsi_ctrl *dsi_ctrl,
+ bool enable)
+{
+ int rc = 0;
+
+ if (!dsi_ctrl) {
+ pr_err("Invalid dsi_ctrl\n");
+ return -EINVAL;
+ }
+
+ mutex_lock(&dsi_ctrl->ctrl_lock);
+
+ rc = dsi_ctrl_check_state(dsi_ctrl, DSI_CTRL_OP_ASYNC_TIMING,
+ DSI_CTRL_ENGINE_ON);
+ if (rc) {
+ pr_err("[DSI_%d] Controller state check failed, rc=%d\n",
+ dsi_ctrl->cell_index, rc);
+ goto exit;
+ }
+
+ /*
+ * Add HW recommended delay for dfps feature.
+ * When prefetch is enabled, MDSS HW works on 2 vsync
+ * boundaries i.e. mdp_vsync and panel_vsync.
+ * In the current implementation we are only waiting
+ * for mdp_vsync. We need to make sure that interface
+ * flush is after panel_vsync. So, added the recommended
+ * delays after dfps update.
+ */
+ usleep_range(2000, 2010);
+
+ dsi_ctrl->hw.ops.set_timing_db(&dsi_ctrl->hw, enable);
+
+exit:
+ mutex_unlock(&dsi_ctrl->ctrl_lock);
+ return rc;
+}
+
int dsi_ctrl_setup(struct dsi_ctrl *dsi_ctrl)
{
int rc = 0;
@@ -2148,7 +2250,7 @@
goto error;
}
- if (!(flags & DSI_MODE_FLAG_SEAMLESS)) {
+ if (!(flags & (DSI_MODE_FLAG_SEAMLESS | DSI_MODE_FLAG_VRR))) {
rc = dsi_ctrl_update_link_freqs(ctrl, config, clk_handle);
if (rc) {
pr_err("[%s] failed to update link frequencies, rc=%d\n",
diff --git a/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl.h b/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl.h
index f10c7a6..4781299 100644
--- a/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl.h
+++ b/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl.h
@@ -311,6 +311,18 @@
int flags, void *clk_handle);
/**
+ * dsi_ctrl_timing_db_update() - update only controller Timing DB
+ * @dsi_ctrl: DSI controller handle.
+ * @enable: Enable/disable Timing DB register
+ *
+ * Update timing db register value during dfps usecases
+ *
+ * Return: error code.
+ */
+int dsi_ctrl_timing_db_update(struct dsi_ctrl *dsi_ctrl,
+ bool enable);
+
+/**
* dsi_ctrl_async_timing_update() - update only controller timing
* @dsi_ctrl: DSI controller handle.
* @timing: New DSI timing info
diff --git a/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl_hw.h b/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl_hw.h
index 57f9bcd..57bccfb 100644
--- a/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl_hw.h
+++ b/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl_hw.h
@@ -445,6 +445,12 @@
void (*phy_sw_reset)(struct dsi_ctrl_hw *ctrl);
/**
+ * debug_bus() - get dsi debug bus status.
+ * @ctrl: Pointer to the controller host hardware.
+ */
+ void (*debug_bus)(struct dsi_ctrl_hw *ctrl);
+
+ /**
* soft_reset() - perform a soft reset on DSI controller
* @ctrl: Pointer to the controller host hardware.
*
@@ -695,6 +701,15 @@
u32 (*collect_misr)(struct dsi_ctrl_hw *ctrl,
enum dsi_op_mode panel_mode);
+ /**
+ * set_timing_db() - enable/disable Timing DB register
+ * @ctrl: Pointer to controller host hardware.
+ * @enable: Enable/Disable flag.
+ *
+ * Enable or Disabe the Timing DB register.
+ */
+ void (*set_timing_db)(struct dsi_ctrl_hw *ctrl,
+ bool enable);
};
/*
diff --git a/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl_hw_cmn.c b/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl_hw_cmn.c
index cd21413..8278ada 100644
--- a/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl_hw_cmn.c
+++ b/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl_hw_cmn.c
@@ -21,6 +21,7 @@
#include "dsi_hw.h"
#include "dsi_panel.h"
#include "dsi_catalog.h"
+#include "sde_dbg.h"
#define MMSS_MISC_CLAMP_REG_OFF 0x0014
#define DSI_CTRL_DYNAMIC_FORCE_ON (0x23F|BIT(8)|BIT(9)|BIT(11)|BIT(21))
@@ -218,6 +219,27 @@
}
/**
+* set_timing_db() - enable/disable Timing DB register
+* @ctrl: Pointer to controller host hardware.
+* @enable: Enable/Disable flag.
+*
+* Enable or Disabe the Timing DB register.
+*/
+void dsi_ctrl_hw_cmn_set_timing_db(struct dsi_ctrl_hw *ctrl,
+ bool enable)
+{
+ if (enable)
+ DSI_W32(ctrl, DSI_DSI_TIMING_DB_MODE, 0x1);
+ else
+ DSI_W32(ctrl, DSI_DSI_TIMING_DB_MODE, 0x0);
+
+ wmb(); /* make sure timing db registers are set */
+ pr_debug("[DSI_%d] ctrl timing DB set:%d\n", ctrl->index,
+ enable);
+ SDE_EVT32(ctrl->index, enable);
+}
+
+/**
* set_video_timing() - set up the timing for video frame
* @ctrl: Pointer to controller host hardware.
* @mode: Video mode information.
@@ -290,6 +312,7 @@
DSI_W32(ctrl, DSI_MISR_VIDEO_CTRL, 0x10100);
DSI_W32(ctrl, DSI_DSI_TIMING_FLUSH, 0x1);
pr_debug("[DSI_%d] ctrl video parameters updated\n", ctrl->index);
+ SDE_EVT32(v_total, h_total);
}
/**
@@ -424,6 +447,18 @@
pr_debug("[DSI_%d] Video engine setup done\n", ctrl->index);
}
+void dsi_ctrl_hw_cmn_debug_bus(struct dsi_ctrl_hw *ctrl)
+{
+ u32 reg = 0;
+
+ DSI_W32(ctrl, DSI_DEBUG_BUS_CTL, 0x181);
+
+ /* make sure that debug test point is enabled */
+ wmb();
+ reg = DSI_R32(ctrl, DSI_DEBUG_BUS_STATUS);
+
+ pr_err("[DSI_%d] debug bus status:0x%x\n", ctrl->index, reg);
+}
/**
* cmd_engine_setup() - setup dsi host controller for command mode
* @ctrl: Pointer to the controller host hardware.
diff --git a/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl_reg.h b/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl_reg.h
index f8f7e13..39ac021 100644
--- a/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl_reg.h
+++ b/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl_reg.h
@@ -82,6 +82,8 @@
#define DSI_SOFT_RESET (0x0118)
#define DSI_CLK_CTRL (0x011C)
#define DSI_CLK_STATUS (0x0120)
+#define DSI_DEBUG_BUS_CTL (0x0124)
+#define DSI_DEBUG_BUS_STATUS (0x0128)
#define DSI_PHY_SW_RESET (0x012C)
#define DSI_AXI2AHB_CTRL (0x0130)
#define DSI_MISR_CMD_MDP0_32BIT (0x0134)
diff --git a/drivers/gpu/drm/msm/dsi-staging/dsi_defs.h b/drivers/gpu/drm/msm/dsi-staging/dsi_defs.h
index fcc59ef..96ed47e 100644
--- a/drivers/gpu/drm/msm/dsi-staging/dsi_defs.h
+++ b/drivers/gpu/drm/msm/dsi-staging/dsi_defs.h
@@ -77,12 +77,15 @@
* @DSI_MODE_FLAG_DFPS: Seamless transition is DynamicFPS
* @DSI_MODE_FLAG_VBLANK_PRE_MODESET: Transition needs VBLANK before Modeset
* @DSI_MODE_FLAG_DMS: Seamless transition is dynamic mode switch
+ * @DSI_MODE_FLAG_VRR: Seamless transition is DynamicFPS.
+ * New timing values are sent from DAL.
*/
enum dsi_mode_flags {
DSI_MODE_FLAG_SEAMLESS = BIT(0),
DSI_MODE_FLAG_DFPS = BIT(1),
DSI_MODE_FLAG_VBLANK_PRE_MODESET = BIT(2),
DSI_MODE_FLAG_DMS = BIT(3),
+ DSI_MODE_FLAG_VRR = BIT(4),
};
/**
diff --git a/drivers/gpu/drm/msm/dsi-staging/dsi_display.c b/drivers/gpu/drm/msm/dsi-staging/dsi_display.c
index 5c22e65..117fdc1 100644
--- a/drivers/gpu/drm/msm/dsi-staging/dsi_display.c
+++ b/drivers/gpu/drm/msm/dsi-staging/dsi_display.c
@@ -28,6 +28,7 @@
#include "dsi_drm.h"
#include "dsi_clk.h"
#include "dsi_pwr.h"
+#include "sde_dbg.h"
#define to_dsi_display(x) container_of(x, struct dsi_display, host)
#define INT_BASE_10 10
@@ -2557,7 +2558,7 @@
}
static int dsi_display_dfps_calc_front_porch(
- u64 clk_hz,
+ u32 old_fps,
u32 new_fps,
u32 a_total,
u32 b_total,
@@ -2565,6 +2566,7 @@
u32 *b_fp_out)
{
s32 b_fp_new;
+ int add_porches, diff;
if (!b_fp_out) {
pr_err("Invalid params");
@@ -2576,15 +2578,22 @@
return -EINVAL;
}
- /**
+ /*
* Keep clock, other porches constant, use new fps, calc front porch
- * clk = (hor * ver * fps)
- * hfront = clk / (vtotal * fps)) - hactive - hback - hsync
+ * new_vtotal = old_vtotal * (old_fps / new_fps )
+ * new_vfp - old_vfp = new_vtotal - old_vtotal
+ * new_vfp = old_vfp + old_vtotal * ((old_fps - new_fps)/ new_fps)
*/
- b_fp_new = (clk_hz / (a_total * new_fps)) - (b_total - b_fp);
+ diff = abs(old_fps - new_fps);
+ add_porches = mult_frac(b_total, diff, new_fps);
- pr_debug("clk %llu fps %u a %u b %u b_fp %u new_fp %d\n",
- clk_hz, new_fps, a_total, b_total, b_fp, b_fp_new);
+ if (old_fps > new_fps)
+ b_fp_new = b_fp + add_porches;
+ else
+ b_fp_new = b_fp - add_porches;
+
+ pr_debug("fps %u a %u b %u b_fp %u new_fp %d\n",
+ new_fps, a_total, b_total, b_fp, b_fp_new);
if (b_fp_new < 0) {
pr_err("Invalid new_hfp calcluated%d\n", b_fp_new);
@@ -2600,14 +2609,25 @@
return 0;
}
+/**
+ * dsi_display_get_dfps_timing() - Get the new dfps values.
+ * @display: DSI display handle.
+ * @adj_mode: Mode value structure to be changed.
+ * It contains old timing values and latest fps value.
+ * New timing values are updated based on new fps.
+ * @curr_refresh_rate: Current fps rate.
+ * If zero , current fps rate is taken from
+ * display->panel->cur_mode.
+ * Return: error code.
+ */
static int dsi_display_get_dfps_timing(struct dsi_display *display,
- struct dsi_display_mode *adj_mode)
+ struct dsi_display_mode *adj_mode,
+ u32 curr_refresh_rate)
{
struct dsi_dfps_capabilities dfps_caps;
struct dsi_display_mode per_ctrl_mode;
struct dsi_mode_info *timing;
struct dsi_ctrl *m_ctrl;
- u64 clk_hz;
int rc = 0;
@@ -2626,20 +2646,27 @@
per_ctrl_mode = *adj_mode;
adjust_timing_by_ctrl_count(display, &per_ctrl_mode);
- if (!dsi_display_is_seamless_dfps_possible(display,
- &per_ctrl_mode, dfps_caps.type)) {
- pr_err("seamless dynamic fps not supported for mode\n");
- return -EINVAL;
+ if (!curr_refresh_rate) {
+ if (!dsi_display_is_seamless_dfps_possible(display,
+ &per_ctrl_mode, dfps_caps.type)) {
+ pr_err("seamless dynamic fps not supported for mode\n");
+ return -EINVAL;
+ }
+ if (display->panel->cur_mode) {
+ curr_refresh_rate =
+ display->panel->cur_mode->timing.refresh_rate;
+ } else {
+ pr_err("cur_mode is not initialized\n");
+ return -EINVAL;
+ }
}
-
/* TODO: Remove this direct reference to the dsi_ctrl */
- clk_hz = m_ctrl->clk_freq.pix_clk_rate;
timing = &per_ctrl_mode.timing;
switch (dfps_caps.type) {
case DSI_DFPS_IMMEDIATE_VFP:
rc = dsi_display_dfps_calc_front_porch(
- clk_hz,
+ curr_refresh_rate,
timing->refresh_rate,
DSI_H_TOTAL(timing),
DSI_V_TOTAL(timing),
@@ -2649,7 +2676,7 @@
case DSI_DFPS_IMMEDIATE_HFP:
rc = dsi_display_dfps_calc_front_porch(
- clk_hz,
+ curr_refresh_rate,
timing->refresh_rate,
DSI_V_TOTAL(timing),
DSI_H_TOTAL(timing),
@@ -2678,7 +2705,7 @@
}
/* Currently the only seamless transition is dynamic fps */
- rc = dsi_display_get_dfps_timing(display, adj_mode);
+ rc = dsi_display_get_dfps_timing(display, adj_mode, 0);
if (rc) {
pr_debug("Dynamic FPS not supported for seamless\n");
} else {
@@ -2718,7 +2745,8 @@
memcpy(&display->config.lane_map, &display->lane_map,
sizeof(display->lane_map));
- if (mode->dsi_mode_flags & DSI_MODE_FLAG_DFPS) {
+ if (mode->dsi_mode_flags &
+ (DSI_MODE_FLAG_DFPS | DSI_MODE_FLAG_VRR)) {
rc = dsi_display_dfps_update(display, mode);
if (rc) {
pr_err("[%s]DSI dfps update failed, rc=%d\n",
@@ -3496,6 +3524,7 @@
for (i = 0; i < num_dfps_rates; i++) {
struct dsi_display_mode *sub_mode = &modes[array_idx];
+ u32 curr_refresh_rate;
if (!sub_mode) {
pr_err("invalid mode data\n");
@@ -3505,9 +3534,15 @@
memcpy(sub_mode, &panel_mode, sizeof(panel_mode));
if (dfps_caps.dfps_support) {
+ curr_refresh_rate =
+ sub_mode->timing.refresh_rate;
sub_mode->timing.refresh_rate =
dfps_caps.min_refresh_rate +
(i % num_dfps_rates);
+
+ dsi_display_get_dfps_timing(display,
+ sub_mode, curr_refresh_rate);
+
sub_mode->pixel_clk_khz =
(DSI_H_TOTAL(&sub_mode->timing) *
DSI_V_TOTAL(&sub_mode->timing) *
@@ -3522,6 +3557,102 @@
return rc;
}
+/**
+ * dsi_display_validate_mode_vrr() - Validate if varaible refresh case.
+ * @display: DSI display handle.
+ * @cur_dsi_mode: Current DSI mode.
+ * @mode: Mode value structure to be validated.
+ * MSM_MODE_FLAG_SEAMLESS_VRR flag is set if there
+ * is change in fps but vactive and hactive are same.
+ * Return: error code.
+ */
+int dsi_display_validate_mode_vrr(struct dsi_display *display,
+ struct dsi_display_mode *cur_dsi_mode,
+ struct dsi_display_mode *mode)
+{
+ int rc = 0;
+ struct dsi_display_mode adj_mode, cur_mode;
+ struct dsi_dfps_capabilities dfps_caps;
+ u32 curr_refresh_rate;
+
+ if (!display || !mode) {
+ pr_err("Invalid params\n");
+ return -EINVAL;
+ }
+
+ if (!display->panel || !display->panel->cur_mode) {
+ pr_debug("Current panel mode not set\n");
+ return rc;
+ }
+
+ mutex_lock(&display->display_lock);
+
+ adj_mode = *mode;
+ cur_mode = *cur_dsi_mode;
+
+ if ((cur_mode.timing.refresh_rate != adj_mode.timing.refresh_rate) &&
+ (cur_mode.timing.v_active == adj_mode.timing.v_active) &&
+ (cur_mode.timing.h_active == adj_mode.timing.h_active)) {
+
+ curr_refresh_rate = cur_mode.timing.refresh_rate;
+ rc = dsi_panel_get_dfps_caps(display->panel, &dfps_caps);
+ if (rc) {
+ pr_err("[%s] failed to get dfps caps from panel\n",
+ display->name);
+ goto error;
+ }
+
+ cur_mode.timing.refresh_rate =
+ adj_mode.timing.refresh_rate;
+
+ rc = dsi_display_get_dfps_timing(display,
+ &cur_mode, curr_refresh_rate);
+ if (rc) {
+ pr_err("[%s] seamless vrr not possible rc=%d\n",
+ display->name, rc);
+ goto error;
+ }
+ switch (dfps_caps.type) {
+ /*
+ * Ignore any round off factors in porch calculation.
+ * Worse case is set to 5.
+ */
+ case DSI_DFPS_IMMEDIATE_VFP:
+ if (abs(DSI_V_TOTAL(&cur_mode.timing) -
+ DSI_V_TOTAL(&adj_mode.timing)) > 5)
+ pr_err("Mismatch vfp fps:%d new:%d given:%d\n",
+ adj_mode.timing.refresh_rate,
+ cur_mode.timing.v_front_porch,
+ adj_mode.timing.v_front_porch);
+ break;
+
+ case DSI_DFPS_IMMEDIATE_HFP:
+ if (abs(DSI_H_TOTAL(&cur_mode.timing) -
+ DSI_H_TOTAL(&adj_mode.timing)) > 5)
+ pr_err("Mismatch hfp fps:%d new:%d given:%d\n",
+ adj_mode.timing.refresh_rate,
+ cur_mode.timing.h_front_porch,
+ adj_mode.timing.h_front_porch);
+ break;
+
+ default:
+ pr_err("Unsupported DFPS mode %d\n",
+ dfps_caps.type);
+ rc = -ENOTSUPP;
+ }
+
+ pr_debug("Mode switch is seamless variable refresh\n");
+ mode->dsi_mode_flags |= DSI_MODE_FLAG_VRR;
+ SDE_EVT32(curr_refresh_rate, adj_mode.timing.refresh_rate,
+ cur_mode.timing.h_front_porch,
+ adj_mode.timing.h_front_porch);
+ }
+
+error:
+ mutex_unlock(&display->display_lock);
+ return rc;
+}
+
int dsi_display_validate_mode(struct dsi_display *display,
struct dsi_display_mode *mode,
u32 flags)
diff --git a/drivers/gpu/drm/msm/dsi-staging/dsi_display.h b/drivers/gpu/drm/msm/dsi-staging/dsi_display.h
index 1c30b9c..4d7a0b8 100644
--- a/drivers/gpu/drm/msm/dsi-staging/dsi_display.h
+++ b/drivers/gpu/drm/msm/dsi-staging/dsi_display.h
@@ -324,6 +324,17 @@
u32 flags);
/**
+ * dsi_display_validate_mode_vrr() - validates mode if variable refresh case
+ * @display: Handle to display.
+ * @mode: Mode to be validated..
+ *
+ * Return: 0 if error code.
+ */
+int dsi_display_validate_mode_vrr(struct dsi_display *display,
+ struct dsi_display_mode *cur_dsi_mode,
+ struct dsi_display_mode *mode);
+
+/**
* dsi_display_set_mode() - Set mode on the display.
* @display: Handle to display.
* @mode: mode to be set.
diff --git a/drivers/gpu/drm/msm/dsi-staging/dsi_drm.c b/drivers/gpu/drm/msm/dsi-staging/dsi_drm.c
index 30e5f02..af721eb 100644
--- a/drivers/gpu/drm/msm/dsi-staging/dsi_drm.c
+++ b/drivers/gpu/drm/msm/dsi-staging/dsi_drm.c
@@ -61,6 +61,8 @@
dsi_mode->dsi_mode_flags |= DSI_MODE_FLAG_VBLANK_PRE_MODESET;
if (msm_is_mode_seamless_dms(drm_mode))
dsi_mode->dsi_mode_flags |= DSI_MODE_FLAG_DMS;
+ if (msm_is_mode_seamless_vrr(drm_mode))
+ dsi_mode->dsi_mode_flags |= DSI_MODE_FLAG_VRR;
}
static void convert_to_drm_mode(const struct dsi_display_mode *dsi_mode,
@@ -96,6 +98,8 @@
drm_mode->private_flags |= MSM_MODE_FLAG_VBLANK_PRE_MODESET;
if (dsi_mode->dsi_mode_flags & DSI_MODE_FLAG_DMS)
drm_mode->private_flags |= MSM_MODE_FLAG_SEAMLESS_DMS;
+ if (dsi_mode->dsi_mode_flags & DSI_MODE_FLAG_VRR)
+ drm_mode->private_flags |= MSM_MODE_FLAG_SEAMLESS_VRR;
drm_mode_set_name(drm_mode);
}
@@ -134,7 +138,8 @@
return;
}
- if (c_bridge->dsi_mode.dsi_mode_flags & DSI_MODE_FLAG_SEAMLESS) {
+ if (c_bridge->dsi_mode.dsi_mode_flags &
+ (DSI_MODE_FLAG_SEAMLESS | DSI_MODE_FLAG_VRR)) {
pr_debug("[%d] seamless pre-enable\n", c_bridge->id);
return;
}
@@ -169,7 +174,8 @@
return;
}
- if (c_bridge->dsi_mode.dsi_mode_flags & DSI_MODE_FLAG_SEAMLESS) {
+ if (c_bridge->dsi_mode.dsi_mode_flags &
+ (DSI_MODE_FLAG_SEAMLESS | DSI_MODE_FLAG_VRR)) {
pr_debug("[%d] seamless enable\n", c_bridge->id);
return;
}
@@ -249,7 +255,7 @@
{
int rc = 0;
struct dsi_bridge *c_bridge = to_dsi_bridge(bridge);
- struct dsi_display_mode dsi_mode;
+ struct dsi_display_mode dsi_mode, cur_dsi_mode;
struct drm_display_mode cur_mode;
if (!bridge || !mode || !adjusted_mode) {
@@ -267,9 +273,20 @@
}
if (bridge->encoder && bridge->encoder->crtc) {
+
+ convert_to_dsi_mode(&bridge->encoder->crtc->mode,
+ &cur_dsi_mode);
+ rc = dsi_display_validate_mode_vrr(c_bridge->display,
+ &cur_dsi_mode, &dsi_mode);
+ if (rc)
+ pr_debug("[%s] vrr mode mismatch failure rc=%d\n",
+ c_bridge->display->name, rc);
+
cur_mode = bridge->encoder->crtc->mode;
- if (!drm_mode_equal(&cur_mode, adjusted_mode))
+ if (!drm_mode_equal(&cur_mode, adjusted_mode) &&
+ (!(dsi_mode.dsi_mode_flags &
+ DSI_MODE_FLAG_VRR)))
dsi_mode.dsi_mode_flags |= DSI_MODE_FLAG_DMS;
}
@@ -383,6 +400,13 @@
sde_kms_info_add_keystr(info, "dfps support",
panel->dfps_caps.dfps_support ? "true" : "false");
+ if (panel->dfps_caps.dfps_support) {
+ sde_kms_info_add_keyint(info, "min_fps",
+ panel->dfps_caps.min_refresh_rate);
+ sde_kms_info_add_keyint(info, "max_fps",
+ panel->dfps_caps.max_refresh_rate);
+ }
+
switch (panel->phy_props.rotation) {
case DSI_PANEL_ROTATE_NONE:
sde_kms_info_add_keystr(info, "panel orientation", "none");
@@ -598,6 +622,52 @@
dsi_display_enable_event(display, event_idx, &event_info, enable);
}
+int dsi_conn_post_kickoff(struct drm_connector *connector)
+{
+ struct drm_encoder *encoder;
+ struct dsi_bridge *c_bridge;
+ struct dsi_display_mode adj_mode;
+ struct dsi_display *display;
+ struct dsi_display_ctrl *m_ctrl, *ctrl;
+ int i, rc = 0;
+
+ if (!connector || !connector->state->best_encoder)
+ return -EINVAL;
+
+ encoder = connector->state->best_encoder;
+ c_bridge = to_dsi_bridge(encoder->bridge);
+ adj_mode = c_bridge->dsi_mode;
+ display = c_bridge->display;
+
+ if (adj_mode.dsi_mode_flags & DSI_MODE_FLAG_VRR) {
+ m_ctrl = &display->ctrl[display->clk_master_idx];
+ rc = dsi_ctrl_timing_db_update(m_ctrl->ctrl, false);
+ if (rc) {
+ pr_err("[%s] failed to dfps update rc=%d\n",
+ display->name, rc);
+ return -EINVAL;
+ }
+
+ /* Update the rest of the controllers */
+ for (i = 0; i < display->ctrl_count; i++) {
+ ctrl = &display->ctrl[i];
+ if (!ctrl->ctrl || (ctrl == m_ctrl))
+ continue;
+
+ rc = dsi_ctrl_timing_db_update(ctrl->ctrl, false);
+ if (rc) {
+ pr_err("[%s] failed to dfps update rc=%d\n",
+ display->name, rc);
+ return -EINVAL;
+ }
+ }
+
+ c_bridge->dsi_mode.dsi_mode_flags &= ~DSI_MODE_FLAG_VRR;
+ }
+
+ return 0;
+}
+
struct dsi_bridge *dsi_drm_bridge_init(struct dsi_display *display,
struct drm_device *dev,
struct drm_encoder *encoder)
diff --git a/drivers/gpu/drm/msm/dsi-staging/dsi_drm.h b/drivers/gpu/drm/msm/dsi-staging/dsi_drm.h
index 793f8f1..9700e68 100644
--- a/drivers/gpu/drm/msm/dsi-staging/dsi_drm.h
+++ b/drivers/gpu/drm/msm/dsi-staging/dsi_drm.h
@@ -119,4 +119,11 @@
void *display,
struct msm_display_kickoff_params *params);
+/**
+ * dsi_display_post_kickoff - program post kickoff-time features
+ * @connector: Pointer to drm connector structure
+ * Returns: Zero on success
+ */
+int dsi_conn_post_kickoff(struct drm_connector *connector);
+
#endif /* _DSI_DRM_H_ */
diff --git a/drivers/gpu/drm/msm/msm_atomic.c b/drivers/gpu/drm/msm/msm_atomic.c
index e0617ee..cbcf580 100644
--- a/drivers/gpu/drm/msm/msm_atomic.c
+++ b/drivers/gpu/drm/msm/msm_atomic.c
@@ -130,11 +130,13 @@
continue;
if (msm_is_mode_seamless(
- &connector->encoder->crtc->state->mode))
+ &connector->encoder->crtc->state->mode) ||
+ msm_is_mode_seamless_vrr(
+ &connector->encoder->crtc->state->adjusted_mode))
continue;
if (msm_is_mode_seamless_dms(
- &connector->encoder->crtc->state->adjusted_mode))
+ &connector->encoder->crtc->state->adjusted_mode))
continue;
funcs = encoder->helper_private;
@@ -169,7 +171,8 @@
if (!old_crtc_state->active)
continue;
- if (msm_is_mode_seamless(&crtc->state->mode))
+ if (msm_is_mode_seamless(&crtc->state->mode) ||
+ msm_is_mode_seamless_vrr(&crtc->state->adjusted_mode))
continue;
if (msm_is_mode_seamless_dms(&crtc->state->adjusted_mode))
@@ -309,7 +312,8 @@
if (!crtc->state->active)
continue;
- if (msm_is_mode_seamless(&crtc->state->mode))
+ if (msm_is_mode_seamless(&crtc->state->mode) ||
+ msm_is_mode_seamless_vrr(&crtc->state->adjusted_mode))
continue;
funcs = crtc->helper_private;
diff --git a/drivers/gpu/drm/msm/msm_drv.c b/drivers/gpu/drm/msm/msm_drv.c
index 5e47daf..0f48db6 100644
--- a/drivers/gpu/drm/msm/msm_drv.c
+++ b/drivers/gpu/drm/msm/msm_drv.c
@@ -58,51 +58,6 @@
#define MSM_VERSION_PATCHLEVEL 0
#define TEARDOWN_DEADLOCK_RETRY_MAX 5
-#define HPD_STRING_SIZE 30
-
-static void msm_drm_helper_hotplug_event(struct drm_device *dev)
-{
- struct drm_connector *connector;
- char name[HPD_STRING_SIZE], status[HPD_STRING_SIZE];
- char const *connector_name;
- char *envp[3];
-
- if (!dev) {
- DRM_ERROR("hotplug_event failed, invalid input\n");
- return;
- }
-
- if (!dev->mode_config.poll_enabled)
- return;
-
- mutex_lock(&dev->mode_config.mutex);
- drm_for_each_connector(connector, dev) {
- /* Only handle HPD capable connectors. */
- if (!(connector->polled & DRM_CONNECTOR_POLL_HPD))
- continue;
-
- connector->status = connector->funcs->detect(connector, false);
-
- if (connector->name)
- connector_name = connector->name;
- else
- connector_name = "unknown";
-
- snprintf(name, HPD_STRING_SIZE, "name=%s", connector_name);
-
- snprintf(status, HPD_STRING_SIZE, "status=%s",
- drm_get_connector_status_name(connector->status));
-
- DRM_DEBUG("generating hotplug event [%s]: [%s]\n",
- name, status);
- envp[0] = name;
- envp[1] = status;
- envp[2] = NULL;
- kobject_uevent_env(&dev->primary->kdev->kobj, KOBJ_CHANGE,
- envp);
- }
- mutex_unlock(&dev->mode_config.mutex);
-}
static void msm_fb_output_poll_changed(struct drm_device *dev)
{
@@ -117,8 +72,6 @@
if (priv->fbdev)
drm_fb_helper_hotplug_event(priv->fbdev);
- else
- msm_drm_helper_hotplug_event(dev);
}
/**
diff --git a/drivers/gpu/drm/msm/msm_drv.h b/drivers/gpu/drm/msm/msm_drv.h
index 12d2d15..a5cc6474 100644
--- a/drivers/gpu/drm/msm/msm_drv.h
+++ b/drivers/gpu/drm/msm/msm_drv.h
@@ -127,6 +127,9 @@
enum msm_mdp_crtc_property {
CRTC_PROP_INFO,
+ CRTC_PROP_DEST_SCALER_LUT_ED,
+ CRTC_PROP_DEST_SCALER_LUT_CIR,
+ CRTC_PROP_DEST_SCALER_LUT_SEP,
/* # of blob properties */
CRTC_PROP_BLOBCOUNT,
@@ -148,6 +151,7 @@
CRTC_PROP_ROI_V1,
CRTC_PROP_SECURITY_LEVEL,
CRTC_PROP_IDLE_TIMEOUT,
+ CRTC_PROP_DEST_SCALER,
/* total # of properties */
CRTC_PROP_COUNT
diff --git a/drivers/gpu/drm/msm/msm_kms.h b/drivers/gpu/drm/msm/msm_kms.h
index 76523c7..304faa6 100644
--- a/drivers/gpu/drm/msm/msm_kms.h
+++ b/drivers/gpu/drm/msm/msm_kms.h
@@ -36,6 +36,8 @@
#define MSM_MODE_FLAG_VBLANK_PRE_MODESET (1<<1)
/* Request to switch the connector mode */
#define MSM_MODE_FLAG_SEAMLESS_DMS (1<<2)
+/* Request to switch the fps */
+#define MSM_MODE_FLAG_SEAMLESS_VRR (1<<3)
/* As there are different display controller blocks depending on the
* snapdragon version, the kms support is split out and the appropriate
@@ -163,6 +165,12 @@
(mode->private_flags & MSM_MODE_FLAG_SEAMLESS_DYNAMIC_FPS));
}
+static inline bool msm_is_mode_seamless_vrr(const struct drm_display_mode *mode)
+{
+ return mode ? (mode->private_flags & MSM_MODE_FLAG_SEAMLESS_VRR)
+ : false;
+}
+
static inline bool msm_needs_vblank_pre_modeset(
const struct drm_display_mode *mode)
{
diff --git a/drivers/gpu/drm/msm/msm_prop.c b/drivers/gpu/drm/msm/msm_prop.c
index d1991a4..033be6e 100644
--- a/drivers/gpu/drm/msm/msm_prop.c
+++ b/drivers/gpu/drm/msm/msm_prop.c
@@ -269,9 +269,16 @@
info->property_data[property_idx].default_value = 0;
info->property_data[property_idx].force_dirty = false;
+ /* select first defined value for enums */
+ if (!is_bitmask)
+ info->property_data[property_idx].default_value =
+ values->type;
+
/* always attach property, if created */
if (*prop) {
- drm_object_attach_property(info->base, *prop, 0);
+ drm_object_attach_property(info->base, *prop,
+ info->property_data
+ [property_idx].default_value);
++info->install_count;
}
}
diff --git a/drivers/gpu/drm/msm/sde/sde_connector.h b/drivers/gpu/drm/msm/sde/sde_connector.h
index ceeafc2..24b547b 100644
--- a/drivers/gpu/drm/msm/sde/sde_connector.h
+++ b/drivers/gpu/drm/msm/sde/sde_connector.h
@@ -199,6 +199,19 @@
* Returns: dst_format of display
*/
enum dsi_pixel_format (*get_dst_format)(void *display);
+
+ /**
+ * post_kickoff - display to program post kickoff-time features
+ * @connector: Pointer to drm connector structure
+ * Returns: Zero on success
+ */
+ int (*post_kickoff)(struct drm_connector *connector);
+
+ /**
+ * send_hpd_event - send HPD uevent notification to userspace
+ * @display: Pointer to private display structure
+ */
+ void (*send_hpd_event)(void *display);
};
/**
diff --git a/drivers/gpu/drm/msm/sde/sde_crtc.c b/drivers/gpu/drm/msm/sde/sde_crtc.c
index efbbd24..7b0e1b5 100644
--- a/drivers/gpu/drm/msm/sde/sde_crtc.c
+++ b/drivers/gpu/drm/msm/sde/sde_crtc.c
@@ -611,6 +611,18 @@
return;
}
+/**
+ * sde_crtc_destroy_dest_scaler - free memory allocated for scaler lut
+ * @sde_crtc: Pointer to sde crtc
+ */
+static void _sde_crtc_destroy_dest_scaler(struct sde_crtc *sde_crtc)
+{
+ if (!sde_crtc)
+ return;
+
+ kfree(sde_crtc->scl3_lut_cfg);
+}
+
static void sde_crtc_destroy(struct drm_crtc *crtc)
{
struct sde_crtc *sde_crtc = to_sde_crtc(crtc);
@@ -624,6 +636,7 @@
drm_property_unreference_blob(sde_crtc->blob_info);
msm_property_destroy(&sde_crtc->property_info);
sde_cp_crtc_destroy_properties(crtc);
+ _sde_crtc_destroy_dest_scaler(sde_crtc);
sde_fence_deinit(&sde_crtc->output_fence);
_sde_crtc_deinit_events(sde_crtc);
@@ -639,8 +652,9 @@
{
SDE_DEBUG("\n");
- if (msm_is_mode_seamless(adjusted_mode) &&
- (!crtc->enabled || crtc->state->active_changed)) {
+ if ((msm_is_mode_seamless(adjusted_mode) ||
+ msm_is_mode_seamless_vrr(adjusted_mode)) &&
+ (!crtc->enabled)) {
SDE_ERROR("crtc state prevents seamless transition\n");
return false;
}
@@ -790,7 +804,7 @@
}
static int _sde_crtc_set_roi_v1(struct drm_crtc_state *state,
- void *usr_ptr)
+ void __user *usr_ptr)
{
struct drm_crtc *crtc;
struct sde_crtc_state *cstate;
@@ -912,23 +926,6 @@
sde_kms_rect_merge_rectangles(&crtc_state->user_roi_list, crtc_roi);
- /*
- * for 3dmux dsc, make sure is full ROI, since current driver doesn't
- * support partial update for this configuration.
- */
- if (!sde_kms_rect_is_null(crtc_roi) &&
- _sde_crtc_setup_is_3dmux_dsc(state)) {
- struct drm_display_mode *adj_mode = &state->adjusted_mode;
-
- if (crtc_roi->w != adj_mode->hdisplay ||
- crtc_roi->h != adj_mode->vdisplay) {
- SDE_ERROR("%s: unsupported top roi[%d %d] wxh[%d %d]\n",
- sde_crtc->name, crtc_roi->w, crtc_roi->h,
- adj_mode->hdisplay, adj_mode->vdisplay);
- return -EINVAL;
- }
- }
-
SDE_DEBUG("%s: crtc roi (%d,%d,%d,%d)\n", sde_crtc->name,
crtc_roi->x, crtc_roi->y, crtc_roi->w, crtc_roi->h);
@@ -999,6 +996,18 @@
SDE_DEBUG("%s: lm%d roi (%d,%d,%d,%d)\n", sde_crtc->name, lm_idx,
lm_roi->x, lm_roi->y, lm_roi->w, lm_roi->h);
+ /*
+ * partial update is not supported with 3dmux dsc or dest scaler.
+ * hence, crtc roi must match the mixer dimensions.
+ */
+ if (crtc_state->num_ds_enabled ||
+ _sde_crtc_setup_is_3dmux_dsc(state)) {
+ if (memcmp(lm_roi, lm_bounds, sizeof(struct sde_rect))) {
+ SDE_ERROR("Unsupported: Dest scaler/3d mux DSC + PU\n");
+ return -EINVAL;
+ }
+ }
+
/* if any dimension is zero, clear all dimensions for clarity */
if (sde_kms_rect_is_null(lm_roi))
memset(lm_roi, 0, sizeof(*lm_roi));
@@ -1658,8 +1667,6 @@
smmu_state->transition_type = post_commit ?
POST_COMMIT : PRE_COMMIT;
ops |= SDE_KMS_OPS_CRTC_SECURE_STATE_CHANGE;
- if (translation_mode == SDE_DRM_FB_SEC)
- ops |= SDE_KMS_OPS_PREPARE_PLANE_FB;
if (old_valid_fb)
ops |= SDE_KMS_OPS_WAIT_FOR_TX_DONE;
} else if ((smmu_state->state == DETACHED) ||
@@ -1667,8 +1674,7 @@
smmu_state->state = ATTACH_ALL_REQ;
smmu_state->transition_type = post_commit ?
POST_COMMIT : PRE_COMMIT;
- ops |= SDE_KMS_OPS_CRTC_SECURE_STATE_CHANGE |
- SDE_KMS_OPS_PREPARE_PLANE_FB;
+ ops |= SDE_KMS_OPS_CRTC_SECURE_STATE_CHANGE;
if (old_valid_fb)
ops |= (SDE_KMS_OPS_WAIT_FOR_TX_DONE |
SDE_KMS_OPS_CLEANUP_PLANE_FB);
@@ -1731,6 +1737,64 @@
}
/**
+ * _sde_crtc_setup_scaler3_lut - Set up scaler lut
+ * LUTs are configured only once during boot
+ * @sde_crtc: Pointer to sde crtc
+ * @cstate: Pointer to sde crtc state
+ */
+static int _sde_crtc_set_dest_scaler_lut(struct sde_crtc *sde_crtc,
+ struct sde_crtc_state *cstate, uint32_t lut_idx)
+{
+ struct sde_hw_scaler3_lut_cfg *cfg;
+ u32 *lut_data = NULL;
+ size_t len = 0;
+ int ret = 0;
+
+ if (!sde_crtc || !cstate || !sde_crtc->scl3_lut_cfg) {
+ SDE_ERROR("invalid args\n");
+ return -EINVAL;
+ }
+
+ if (sde_crtc->scl3_lut_cfg->is_configured) {
+ SDE_DEBUG("lut already configured\n");
+ return 0;
+ }
+
+ lut_data = msm_property_get_blob(&sde_crtc->property_info,
+ &cstate->property_state, &len, lut_idx);
+ if (!lut_data || !len) {
+ SDE_ERROR("lut(%d): no data, len(%zu)\n", lut_idx, len);
+ return -ENODATA;
+ }
+
+ cfg = sde_crtc->scl3_lut_cfg;
+
+ switch (lut_idx) {
+ case CRTC_PROP_DEST_SCALER_LUT_ED:
+ cfg->dir_lut = lut_data;
+ cfg->dir_len = len;
+ break;
+ case CRTC_PROP_DEST_SCALER_LUT_CIR:
+ cfg->cir_lut = lut_data;
+ cfg->cir_len = len;
+ break;
+ case CRTC_PROP_DEST_SCALER_LUT_SEP:
+ cfg->sep_lut = lut_data;
+ cfg->sep_len = len;
+ break;
+ default:
+ ret = -EINVAL;
+ SDE_ERROR("invalid LUT index = %d", lut_idx);
+ break;
+ }
+
+ if (cfg->dir_lut && cfg->cir_lut && cfg->sep_lut)
+ cfg->is_configured = true;
+
+ return ret;
+}
+
+/**
* sde_crtc_secure_ctrl - Initiates the operations to swtich between secure
* and non-secure mode
* @crtc: Pointer to crtc
@@ -1848,6 +1912,105 @@
return ret;
}
+/**
+ * _sde_crtc_dest_scaler_setup - Set up dest scaler block
+ * @crtc: Pointer to drm crtc
+ */
+static void _sde_crtc_dest_scaler_setup(struct drm_crtc *crtc)
+{
+ struct sde_crtc *sde_crtc;
+ struct sde_crtc_state *cstate;
+ struct sde_hw_mixer *hw_lm;
+ struct sde_hw_ctl *hw_ctl;
+ struct sde_hw_ds *hw_ds;
+ struct sde_hw_ds_cfg *cfg;
+ struct sde_kms *kms;
+ u32 flush_mask = 0, op_mode = 0;
+ u32 lm_idx = 0, num_mixers = 0;
+ int i, count = 0;
+
+ if (!crtc)
+ return;
+
+ sde_crtc = to_sde_crtc(crtc);
+ cstate = to_sde_crtc_state(crtc->state);
+ kms = _sde_crtc_get_kms(crtc);
+ num_mixers = sde_crtc->num_mixers;
+
+ SDE_DEBUG("crtc%d\n", crtc->base.id);
+
+ if (!cstate->ds_dirty) {
+ SDE_DEBUG("no change in settings, skip commit\n");
+ } else if (!kms || !kms->catalog) {
+ SDE_ERROR("invalid parameters\n");
+ } else if (!kms->catalog->mdp[0].has_dest_scaler) {
+ SDE_DEBUG("dest scaler feature not supported\n");
+ } else if (num_mixers > CRTC_DUAL_MIXERS) {
+ SDE_ERROR("invalid number mixers: %d\n", num_mixers);
+ } else if (!sde_crtc->scl3_lut_cfg->is_configured) {
+ SDE_DEBUG("no LUT data available\n");
+ } else {
+ count = cstate->num_ds_enabled ? cstate->num_ds : num_mixers;
+
+ for (i = 0; i < count; i++) {
+ cfg = &cstate->ds_cfg[i];
+
+ if (!cfg->flags)
+ continue;
+
+ lm_idx = cfg->ndx;
+ hw_lm = sde_crtc->mixers[lm_idx].hw_lm;
+ hw_ctl = sde_crtc->mixers[lm_idx].hw_ctl;
+ hw_ds = sde_crtc->mixers[lm_idx].hw_ds;
+
+ /* Setup op mode - Dual/single */
+ if (cfg->flags & SDE_DRM_DESTSCALER_ENABLE)
+ op_mode |= BIT(hw_ds->idx - DS_0);
+
+ if ((i == count-1) && hw_ds->ops.setup_opmode) {
+ op_mode |= (cstate->num_ds_enabled ==
+ CRTC_DUAL_MIXERS) ?
+ SDE_DS_OP_MODE_DUAL : 0;
+ hw_ds->ops.setup_opmode(hw_ds, op_mode);
+ SDE_EVT32(DRMID(crtc), op_mode);
+ }
+
+ /* Setup scaler */
+ if ((cfg->flags & SDE_DRM_DESTSCALER_SCALE_UPDATE) ||
+ (cfg->flags &
+ SDE_DRM_DESTSCALER_ENHANCER_UPDATE)) {
+ if (hw_ds->ops.setup_scaler)
+ hw_ds->ops.setup_scaler(hw_ds,
+ cfg->scl3_cfg,
+ sde_crtc->scl3_lut_cfg);
+
+ /**
+ * Clear the flags as the block doesn't have to
+ * be programmed in each commit if no updates
+ */
+ cfg->flags &= ~SDE_DRM_DESTSCALER_SCALE_UPDATE;
+ cfg->flags &=
+ ~SDE_DRM_DESTSCALER_ENHANCER_UPDATE;
+ }
+
+ /*
+ * Dest scaler shares the flush bit of the LM in control
+ */
+ if (cfg->set_lm_flush && hw_lm && hw_ctl &&
+ hw_ctl->ops.get_bitmask_mixer) {
+ flush_mask = hw_ctl->ops.get_bitmask_mixer(
+ hw_ctl, hw_lm->idx);
+ SDE_DEBUG("Set lm[%d] flush = %d",
+ hw_lm->idx, flush_mask);
+ hw_ctl->ops.update_pending_flush(hw_ctl,
+ flush_mask);
+ }
+ cfg->set_lm_flush = false;
+ }
+ cstate->ds_dirty = false;
+ }
+}
+
void sde_crtc_prepare_commit(struct drm_crtc *crtc,
struct drm_crtc_state *old_state)
{
@@ -2254,7 +2417,7 @@
* @user_ptr: User ptr for sde_drm_dim_layer_v1 struct
*/
static void _sde_crtc_set_dim_layer_v1(struct sde_crtc_state *cstate,
- void *usr_ptr)
+ void __user *usr_ptr)
{
struct sde_drm_dim_layer_v1 dim_layer_v1;
struct sde_drm_dim_layer_cfg *user_cfg;
@@ -2316,6 +2479,363 @@
}
/**
+ * _sde_crtc_dest_scaler_init - allocate memory for scaler lut
+ * @sde_crtc : Pointer to sde crtc
+ * @catalog : Pointer to mdss catalog info
+ */
+static void _sde_crtc_dest_scaler_init(struct sde_crtc *sde_crtc,
+ struct sde_mdss_cfg *catalog)
+{
+ if (!sde_crtc || !catalog)
+ return;
+
+ if (!catalog->mdp[0].has_dest_scaler) {
+ SDE_DEBUG("dest scaler feature not supported\n");
+ return;
+ }
+
+ sde_crtc->scl3_lut_cfg = kzalloc(sizeof(struct sde_hw_scaler3_lut_cfg),
+ GFP_KERNEL);
+ if (!sde_crtc->scl3_lut_cfg)
+ SDE_ERROR("failed to create scale LUT for dest scaler");
+}
+
+/**
+ * _sde_crtc_set_dest_scaler - copy dest scaler settings from userspace
+ * @sde_crtc : Pointer to sde crtc
+ * @cstate : Pointer to sde crtc state
+ * @usr_ptr: User ptr for sde_drm_dest_scaler_data struct
+ */
+static int _sde_crtc_set_dest_scaler(struct sde_crtc *sde_crtc,
+ struct sde_crtc_state *cstate,
+ void __user *usr_ptr)
+{
+ struct sde_drm_dest_scaler_data ds_data;
+ struct sde_drm_dest_scaler_cfg *ds_cfg_usr;
+ struct sde_drm_scaler_v2 scaler_v2;
+ void __user *scaler_v2_usr;
+ int i, count, ret = 0;
+
+ if (!sde_crtc || !cstate) {
+ SDE_ERROR("invalid sde_crtc/state\n");
+ return -EINVAL;
+ }
+
+ SDE_DEBUG("crtc %s\n", sde_crtc->name);
+
+ cstate->num_ds = 0;
+ cstate->ds_dirty = false;
+ if (!usr_ptr) {
+ SDE_DEBUG("ds data removed\n");
+ return 0;
+ }
+
+ if (copy_from_user(&ds_data, usr_ptr, sizeof(ds_data))) {
+ SDE_ERROR("failed to copy dest scaler data from user\n");
+ return -EINVAL;
+ }
+
+ count = ds_data.num_dest_scaler;
+ if (!sde_crtc->num_mixers || count > sde_crtc->num_mixers ||
+ (count && (count != sde_crtc->num_mixers) &&
+ !(ds_data.ds_cfg[0].flags & SDE_DRM_DESTSCALER_PU_ENABLE))) {
+ SDE_ERROR("invalid config:num ds(%d), mixers(%d),flags(%d)\n",
+ count, sde_crtc->num_mixers, ds_data.ds_cfg[0].flags);
+ return -EINVAL;
+ }
+
+ /* Populate from user space */
+ for (i = 0; i < count; i++) {
+ ds_cfg_usr = &ds_data.ds_cfg[i];
+
+ cstate->ds_cfg[i].ndx = ds_cfg_usr->index;
+ cstate->ds_cfg[i].flags = ds_cfg_usr->flags;
+ cstate->ds_cfg[i].lm_width = ds_cfg_usr->lm_width;
+ cstate->ds_cfg[i].lm_height = ds_cfg_usr->lm_height;
+ cstate->ds_cfg[i].scl3_cfg = NULL;
+
+ if (ds_cfg_usr->scaler_cfg) {
+ scaler_v2_usr =
+ (void __user *)((uintptr_t)ds_cfg_usr->scaler_cfg);
+
+ memset(&scaler_v2, 0, sizeof(scaler_v2));
+
+ cstate->ds_cfg[i].scl3_cfg =
+ kzalloc(sizeof(struct sde_hw_scaler3_cfg),
+ GFP_KERNEL);
+
+ if (!cstate->ds_cfg[i].scl3_cfg) {
+ ret = -ENOMEM;
+ goto err;
+ }
+
+ if (copy_from_user(&scaler_v2, scaler_v2_usr,
+ sizeof(scaler_v2))) {
+ SDE_ERROR("scale data:copy from user failed\n");
+ ret = -EINVAL;
+ goto err;
+ }
+
+ sde_set_scaler_v2(cstate->ds_cfg[i].scl3_cfg,
+ &scaler_v2);
+
+ SDE_DEBUG("en(%d)dir(%d)de(%d) src(%dx%d) dst(%dx%d)\n",
+ scaler_v2.enable, scaler_v2.dir_en,
+ scaler_v2.de.enable, scaler_v2.src_width[0],
+ scaler_v2.src_height[0], scaler_v2.dst_width,
+ scaler_v2.dst_height);
+ SDE_EVT32_VERBOSE(DRMID(&sde_crtc->base),
+ scaler_v2.enable, scaler_v2.dir_en,
+ scaler_v2.de.enable, scaler_v2.src_width[0],
+ scaler_v2.src_height[0], scaler_v2.dst_width,
+ scaler_v2.dst_height);
+ }
+
+ SDE_DEBUG("ds cfg[%d]-ndx(%d) flags(%d) lm(%dx%d)\n",
+ i, ds_cfg_usr->index, ds_cfg_usr->flags,
+ ds_cfg_usr->lm_width, ds_cfg_usr->lm_height);
+ SDE_EVT32_VERBOSE(DRMID(&sde_crtc->base), i, ds_cfg_usr->index,
+ ds_cfg_usr->flags, ds_cfg_usr->lm_width,
+ ds_cfg_usr->lm_height);
+ }
+
+ cstate->num_ds = count;
+ cstate->ds_dirty = true;
+ return 0;
+
+err:
+ for (; i >= 0; i--)
+ kfree(cstate->ds_cfg[i].scl3_cfg);
+
+ return ret;
+}
+
+/**
+ * _sde_crtc_check_dest_scaler_data - validate the dest scaler data
+ * @crtc : Pointer to drm crtc
+ * @state : Pointer to drm crtc state
+ */
+static int _sde_crtc_check_dest_scaler_data(struct drm_crtc *crtc,
+ struct drm_crtc_state *state)
+{
+ struct sde_crtc *sde_crtc;
+ struct sde_crtc_state *cstate;
+ struct drm_display_mode *mode;
+ struct sde_kms *kms;
+ struct sde_hw_ds *hw_ds;
+ struct sde_hw_ds_cfg *cfg;
+ u32 i, ret = 0, lm_idx;
+ u32 num_ds_enable = 0;
+ u32 max_in_width = 0, max_out_width = 0;
+ u32 prev_lm_width = 0, prev_lm_height = 0;
+
+ if (!crtc || !state)
+ return -EINVAL;
+
+ sde_crtc = to_sde_crtc(crtc);
+ cstate = to_sde_crtc_state(state);
+ kms = _sde_crtc_get_kms(crtc);
+ mode = &state->adjusted_mode;
+
+ SDE_DEBUG("crtc%d\n", crtc->base.id);
+
+ if (!cstate->ds_dirty && !cstate->num_ds_enabled) {
+ SDE_DEBUG("dest scaler property not set, skip validation\n");
+ return 0;
+ }
+
+ if (!kms || !kms->catalog) {
+ SDE_ERROR("invalid parameters\n");
+ return -EINVAL;
+ }
+
+ if (!kms->catalog->mdp[0].has_dest_scaler) {
+ SDE_DEBUG("dest scaler feature not supported\n");
+ return 0;
+ }
+
+ if (!sde_crtc->num_mixers) {
+ SDE_ERROR("mixers not allocated\n");
+ return -EINVAL;
+ }
+
+ /**
+ * Check if sufficient hw resources are
+ * available as per target caps & topology
+ */
+ if (sde_crtc->num_mixers > CRTC_DUAL_MIXERS) {
+ SDE_ERROR("invalid config: mixers(%d) max(%d)\n",
+ sde_crtc->num_mixers, CRTC_DUAL_MIXERS);
+ ret = -EINVAL;
+ goto err;
+ }
+
+ for (i = 0; i < sde_crtc->num_mixers; i++) {
+ if (!sde_crtc->mixers[i].hw_lm || !sde_crtc->mixers[i].hw_ds) {
+ SDE_ERROR("insufficient HW resources allocated\n");
+ ret = -EINVAL;
+ goto err;
+ }
+ }
+
+ /**
+ * Check if DS needs to be enabled or disabled
+ * In case of enable, validate the data
+ */
+ if (!cstate->ds_dirty || !cstate->num_ds ||
+ !(cstate->ds_cfg[0].flags & SDE_DRM_DESTSCALER_ENABLE)) {
+ SDE_DEBUG("disable dest scaler,dirty(%d)num(%d)flags(%d)\n",
+ cstate->ds_dirty, cstate->num_ds,
+ cstate->ds_cfg[0].flags);
+ goto disable;
+ }
+
+ /**
+ * No of dest scalers shouldn't exceed hw ds block count and
+ * also, match the num of mixers unless it is partial update
+ * left only/right only use case - currently PU + DS is not supported
+ */
+ if (cstate->num_ds > kms->catalog->ds_count ||
+ ((cstate->num_ds != sde_crtc->num_mixers) &&
+ !(cstate->ds_cfg[0].flags & SDE_DRM_DESTSCALER_PU_ENABLE))) {
+ SDE_ERROR("invalid cfg: num_ds(%d), hw_ds_cnt(%d) flags(%d)\n",
+ cstate->num_ds, kms->catalog->ds_count,
+ cstate->ds_cfg[0].flags);
+ ret = -EINVAL;
+ goto err;
+ }
+
+ /* Validate the DS data */
+ for (i = 0; i < cstate->num_ds; i++) {
+ cfg = &cstate->ds_cfg[i];
+ lm_idx = cfg->ndx;
+
+ /**
+ * Validate against topology
+ * No of dest scalers should match the num of mixers
+ * unless it is partial update left only/right only use case
+ */
+ if (lm_idx >= sde_crtc->num_mixers || (i != lm_idx &&
+ !(cfg->flags & SDE_DRM_DESTSCALER_PU_ENABLE))) {
+ SDE_ERROR("invalid user data(%d):idx(%d), flags(%d)\n",
+ i, lm_idx, cfg->flags);
+ ret = -EINVAL;
+ goto err;
+ }
+
+ hw_ds = sde_crtc->mixers[lm_idx].hw_ds;
+
+ if (!max_in_width && !max_out_width) {
+ max_in_width = hw_ds->scl->top->maxinputwidth;
+ max_out_width = hw_ds->scl->top->maxoutputwidth;
+
+ if (cstate->num_ds == CRTC_DUAL_MIXERS)
+ max_in_width -= SDE_DS_OVERFETCH_SIZE;
+
+ SDE_DEBUG("max DS width [%d,%d] for num_ds = %d\n",
+ max_in_width, max_out_width, cstate->num_ds);
+ }
+
+ /* Check LM width and height */
+ if (cfg->lm_width > (mode->hdisplay/sde_crtc->num_mixers) ||
+ cfg->lm_height > mode->vdisplay ||
+ !cfg->lm_width || !cfg->lm_height) {
+ SDE_ERROR("invalid lm size[%d,%d] display [%d,%d]\n",
+ cfg->lm_width,
+ cfg->lm_height,
+ mode->hdisplay/sde_crtc->num_mixers,
+ mode->vdisplay);
+ ret = -E2BIG;
+ goto err;
+ }
+
+ if (!prev_lm_width && !prev_lm_height) {
+ prev_lm_width = cfg->lm_width;
+ prev_lm_height = cfg->lm_height;
+ } else {
+ if (cfg->lm_width != prev_lm_width ||
+ cfg->lm_height != prev_lm_height) {
+ SDE_ERROR("lm size:left[%d,%d], right[%d %d]\n",
+ cfg->lm_width, cfg->lm_height,
+ prev_lm_width, prev_lm_height);
+ ret = -EINVAL;
+ goto err;
+ }
+ }
+
+ /* Check scaler data */
+ if (cfg->flags & SDE_DRM_DESTSCALER_SCALE_UPDATE ||
+ cfg->flags & SDE_DRM_DESTSCALER_ENHANCER_UPDATE) {
+ if (!cfg->scl3_cfg) {
+ ret = -EINVAL;
+ SDE_ERROR("null scale data\n");
+ goto err;
+ }
+ if (cfg->scl3_cfg->src_width[0] > max_in_width ||
+ cfg->scl3_cfg->dst_width > max_out_width ||
+ !cfg->scl3_cfg->src_width[0] ||
+ !cfg->scl3_cfg->dst_width) {
+ SDE_ERROR("scale width(%d %d) for ds-%d:\n",
+ cfg->scl3_cfg->src_width[0],
+ cfg->scl3_cfg->dst_width,
+ hw_ds->idx - DS_0);
+ SDE_ERROR("scale_en = %d, DE_en =%d\n",
+ cfg->scl3_cfg->enable,
+ cfg->scl3_cfg->de.enable);
+
+ cfg->flags &=
+ ~SDE_DRM_DESTSCALER_SCALE_UPDATE;
+ cfg->flags &=
+ ~SDE_DRM_DESTSCALER_ENHANCER_UPDATE;
+
+ ret = -EINVAL;
+ goto err;
+ }
+ }
+
+ if (cfg->flags & SDE_DRM_DESTSCALER_ENABLE)
+ num_ds_enable++;
+
+ /**
+ * Validation successful, indicator for flush to be issued
+ */
+ cfg->set_lm_flush = true;
+
+ SDE_DEBUG("ds[%d]: flags = 0x%X\n",
+ hw_ds->idx - DS_0, cfg->flags);
+ }
+
+disable:
+ SDE_DEBUG("dest scaler enable status, old = %d, new = %d",
+ cstate->num_ds_enabled, num_ds_enable);
+ SDE_EVT32(DRMID(crtc), cstate->num_ds_enabled, num_ds_enable,
+ cstate->ds_dirty);
+
+ if (cstate->num_ds_enabled != num_ds_enable) {
+ /* Disabling destination scaler */
+ if (!num_ds_enable) {
+ for (i = 0; i < sde_crtc->num_mixers; i++) {
+ cfg = &cstate->ds_cfg[i];
+ cfg->ndx = i;
+ /* Update scaler settings in disable case */
+ cfg->flags = SDE_DRM_DESTSCALER_SCALE_UPDATE;
+ cfg->scl3_cfg->enable = 0;
+ cfg->scl3_cfg->de.enable = 0;
+ cfg->set_lm_flush = true;
+ }
+ }
+ cstate->num_ds_enabled = num_ds_enable;
+ cstate->ds_dirty = true;
+ }
+
+ return 0;
+
+err:
+ cstate->ds_dirty = false;
+ return ret;
+}
+
+/**
* _sde_crtc_wait_for_fences - wait for incoming framebuffer sync fences
* @crtc: Pointer to CRTC object
*/
@@ -2372,11 +2892,12 @@
struct sde_crtc_mixer *mixer;
struct sde_hw_ctl *last_valid_ctl = NULL;
int i;
- struct sde_rm_hw_iter lm_iter, ctl_iter, dspp_iter;
+ struct sde_rm_hw_iter lm_iter, ctl_iter, dspp_iter, ds_iter;
sde_rm_init_hw_iter(&lm_iter, enc->base.id, SDE_HW_BLK_LM);
sde_rm_init_hw_iter(&ctl_iter, enc->base.id, SDE_HW_BLK_CTL);
sde_rm_init_hw_iter(&dspp_iter, enc->base.id, SDE_HW_BLK_DSPP);
+ sde_rm_init_hw_iter(&ds_iter, enc->base.id, SDE_HW_BLK_DS);
/* Set up all the mixers and ctls reserved by this encoder */
for (i = sde_crtc->num_mixers; i < ARRAY_SIZE(sde_crtc->mixers); i++) {
@@ -2407,6 +2928,10 @@
(void) sde_rm_get_hw(rm, &dspp_iter);
mixer->hw_dspp = (struct sde_hw_dspp *)dspp_iter.hw;
+ /* DS may be null */
+ (void) sde_rm_get_hw(rm, &ds_iter);
+ mixer->hw_ds = (struct sde_hw_ds *)ds_iter.hw;
+
mixer->encoder = enc;
sde_crtc->num_mixers++;
@@ -2414,6 +2939,9 @@
i, mixer->hw_lm->idx - LM_0);
SDE_DEBUG("setup mixer %d: ctl %d\n",
i, mixer->hw_ctl->idx - CTL_0);
+ if (mixer->hw_ds)
+ SDE_DEBUG("setup mixer %d: ds %d\n",
+ i, mixer->hw_ds->idx - DS_0);
}
}
@@ -2423,6 +2951,7 @@
struct drm_encoder *enc;
sde_crtc->num_mixers = 0;
+ sde_crtc->mixers_swapped = false;
memset(sde_crtc->mixers, 0, sizeof(sde_crtc->mixers));
mutex_lock(&sde_crtc->crtc_lock);
@@ -2472,13 +3001,14 @@
cstate = to_sde_crtc_state(state);
adj_mode = &state->adjusted_mode;
- crtc_split_width = sde_crtc_mixer_width(sde_crtc, adj_mode);
+ crtc_split_width = sde_crtc_get_mixer_width(sde_crtc, cstate, adj_mode);
for (i = 0; i < sde_crtc->num_mixers; i++) {
cstate->lm_bounds[i].x = crtc_split_width * i;
cstate->lm_bounds[i].y = 0;
cstate->lm_bounds[i].w = crtc_split_width;
- cstate->lm_bounds[i].h = adj_mode->vdisplay;
+ cstate->lm_bounds[i].h =
+ sde_crtc_get_mixer_height(sde_crtc, cstate, adj_mode);
memcpy(&cstate->lm_roi[i], &cstate->lm_bounds[i],
sizeof(cstate->lm_roi[i]));
SDE_EVT32_VERBOSE(DRMID(crtc), i,
@@ -2549,6 +3079,7 @@
return;
_sde_crtc_blend_setup(crtc);
+ _sde_crtc_dest_scaler_setup(crtc);
/*
* Since CP properties use AXI buffer to program the
@@ -3299,6 +3830,7 @@
memset(sde_crtc->mixers, 0, sizeof(sde_crtc->mixers));
sde_crtc->num_mixers = 0;
+ sde_crtc->mixers_swapped = false;
/* disable clk & bw control until clk & bw properties are set */
cstate->bw_control = false;
@@ -3581,7 +4113,14 @@
memset(pipe_staged, 0, sizeof(pipe_staged));
- mixer_width = sde_crtc_mixer_width(sde_crtc, mode);
+ rc = _sde_crtc_check_dest_scaler_data(crtc, state);
+ if (rc) {
+ SDE_ERROR("crtc%d failed dest scaler check %d\n",
+ crtc->base.id, rc);
+ goto end;
+ }
+
+ mixer_width = sde_crtc_get_mixer_width(sde_crtc, cstate, mode);
_sde_crtc_setup_is_ppsplit(state);
_sde_crtc_setup_lm_bounds(crtc, state);
@@ -3976,6 +4515,39 @@
"smart_dma_rev", "smart_dma_v2");
}
+ if (catalog->mdp[0].has_dest_scaler) {
+ sde_kms_info_add_keyint(info, "has_dest_scaler",
+ catalog->mdp[0].has_dest_scaler);
+ sde_kms_info_add_keyint(info, "dest_scaler_count",
+ catalog->ds_count);
+
+ if (catalog->ds[0].top) {
+ sde_kms_info_add_keyint(info,
+ "max_dest_scaler_input_width",
+ catalog->ds[0].top->maxinputwidth);
+ sde_kms_info_add_keyint(info,
+ "max_dest_scaler_output_width",
+ catalog->ds[0].top->maxinputwidth);
+ sde_kms_info_add_keyint(info, "max_dest_scale_up",
+ catalog->ds[0].top->maxupscale);
+ }
+
+ if (catalog->ds[0].features & BIT(SDE_SSPP_SCALER_QSEED3)) {
+ msm_property_install_volatile_range(
+ &sde_crtc->property_info, "dest_scaler",
+ 0x0, 0, ~0, 0, CRTC_PROP_DEST_SCALER);
+ msm_property_install_blob(&sde_crtc->property_info,
+ "ds_lut_ed", 0,
+ CRTC_PROP_DEST_SCALER_LUT_ED);
+ msm_property_install_blob(&sde_crtc->property_info,
+ "ds_lut_cir", 0,
+ CRTC_PROP_DEST_SCALER_LUT_CIR);
+ msm_property_install_blob(&sde_crtc->property_info,
+ "ds_lut_sep", 0,
+ CRTC_PROP_DEST_SCALER_LUT_SEP);
+ }
+ }
+
sde_kms_info_add_keyint(info, "has_src_split", catalog->has_src_split);
if (catalog->perf.max_bw_low)
sde_kms_info_add_keyint(info, "max_bandwidth_low",
@@ -4060,10 +4632,22 @@
_sde_crtc_set_input_fence_timeout(cstate);
break;
case CRTC_PROP_DIM_LAYER_V1:
- _sde_crtc_set_dim_layer_v1(cstate, (void *)val);
+ _sde_crtc_set_dim_layer_v1(cstate,
+ (void __user *)val);
break;
case CRTC_PROP_ROI_V1:
- ret = _sde_crtc_set_roi_v1(state, (void *)val);
+ ret = _sde_crtc_set_roi_v1(state,
+ (void __user *)val);
+ break;
+ case CRTC_PROP_DEST_SCALER:
+ ret = _sde_crtc_set_dest_scaler(sde_crtc,
+ cstate, (void __user *)val);
+ break;
+ case CRTC_PROP_DEST_SCALER_LUT_ED:
+ case CRTC_PROP_DEST_SCALER_LUT_CIR:
+ case CRTC_PROP_DEST_SCALER_LUT_SEP:
+ ret = _sde_crtc_set_dest_scaler_lut(sde_crtc,
+ cstate, idx);
break;
case CRTC_PROP_CORE_CLK:
case CRTC_PROP_CORE_AB:
@@ -4211,7 +4795,7 @@
mutex_lock(&sde_crtc->crtc_lock);
mode = &crtc->state->adjusted_mode;
- out_width = sde_crtc_mixer_width(sde_crtc, mode);
+ out_width = sde_crtc_get_mixer_width(sde_crtc, cstate, mode);
seq_printf(s, "crtc:%d width:%d height:%d\n", crtc->base.id,
mode->hdisplay, mode->vdisplay);
@@ -4746,6 +5330,9 @@
sde_crtc_install_properties(crtc, kms->catalog);
+ /* Init dest scaler */
+ _sde_crtc_dest_scaler_init(sde_crtc, kms->catalog);
+
/* Install color processing properties */
sde_cp_crtc_init(crtc);
sde_cp_crtc_install_properties(crtc);
diff --git a/drivers/gpu/drm/msm/sde/sde_crtc.h b/drivers/gpu/drm/msm/sde/sde_crtc.h
index 0783f11..dd18b63 100644
--- a/drivers/gpu/drm/msm/sde/sde_crtc.h
+++ b/drivers/gpu/drm/msm/sde/sde_crtc.h
@@ -26,6 +26,7 @@
#include "sde_kms.h"
#include "sde_core_perf.h"
#include "sde_hw_blk.h"
+#include "sde_hw_ds.h"
#define SDE_CRTC_NAME_SIZE 12
@@ -106,14 +107,16 @@
* @hw_lm: LM HW Driver context
* @hw_ctl: CTL Path HW driver context
* @hw_dspp: DSPP HW driver context
+ * @hw_ds: DS HW driver context
* @encoder: Encoder attached to this lm & ctl
- * @mixer_op_mode: mixer blending operation mode
+ * @mixer_op_mode: mixer blending operation mode
* @flush_mask: mixer flush mask for ctl, mixer and pipe
*/
struct sde_crtc_mixer {
struct sde_hw_mixer *hw_lm;
struct sde_hw_ctl *hw_ctl;
- struct sde_hw_dspp *hw_dspp;
+ struct sde_hw_dspp *hw_dspp;
+ struct sde_hw_ds *hw_ds;
struct drm_encoder *encoder;
u32 mixer_op_mode;
u32 flush_mask;
@@ -210,6 +213,7 @@
* @cur_perf : current performance committed to clock/bandwidth driver
* @rp_lock : serialization lock for resource pool
* @rp_head : list of active resource pool
+ * @scl3_cfg_lut : qseed3 lut config
*/
struct sde_crtc {
struct drm_crtc base;
@@ -220,6 +224,7 @@
u32 num_mixers;
bool mixers_swapped;
struct sde_crtc_mixer mixers[CRTC_DUAL_MIXERS];
+ struct sde_hw_scaler3_lut_cfg *scl3_lut_cfg;
struct drm_pending_vblank_event *event;
u32 vsync_count;
@@ -342,7 +347,6 @@
* @base: Base drm crtc state structure
* @connectors : Currently associated drm connectors
* @num_connectors: Number of associated drm connectors
- * @intf_mode : Interface mode of the primary connector
* @rsc_client : sde rsc client when mode is valid
* @is_ppsplit : Whether current topology requires PPSplit special handling
* @bw_control : true if bw/clk controlled by core bw/clk properties
@@ -359,6 +363,10 @@
* @input_fence_timeout_ns : Cached input fence timeout, in ns
* @num_dim_layers: Number of dim layers
* @dim_layer: Dim layer configs
+ * @num_ds: Number of destination scalers to be configured
+ * @num_ds_enabled: Number of destination scalers enabled
+ * @ds_dirty: Boolean to indicate if dirty or not
+ * @ds_cfg: Destination scaler config
* @new_perf: new performance state being requested
* @sbuf_cfg: stream buffer configuration
* @sbuf_prefill_line: number of line for inline rotator prefetch
@@ -368,7 +376,6 @@
struct drm_connector *connectors[MAX_CONNECTORS];
int num_connectors;
- enum sde_intf_mode intf_mode;
struct sde_rsc_client *rsc_client;
bool rsc_update;
bool bw_control;
@@ -385,6 +392,10 @@
uint64_t input_fence_timeout_ns;
uint32_t num_dim_layers;
struct sde_hw_dim_layer dim_layer[SDE_MAX_DIM_LAYERS];
+ uint32_t num_ds;
+ uint32_t num_ds_enabled;
+ bool ds_dirty;
+ struct sde_hw_ds_cfg ds_cfg[SDE_MAX_DS_COUNT];
struct sde_core_perf_params new_perf;
struct sde_ctl_sbuf_cfg sbuf_cfg;
@@ -405,14 +416,41 @@
#define sde_crtc_get_property(S, X) \
((S) && ((X) < CRTC_PROP_COUNT) ? ((S)->property_values[(X)].value) : 0)
-static inline int sde_crtc_mixer_width(struct sde_crtc *sde_crtc,
- struct drm_display_mode *mode)
+/**
+ * sde_crtc_get_mixer_width - get the mixer width
+ * Mixer width will be same as panel width(/2 for split)
+ * unless destination scaler feature is enabled
+ */
+static inline int sde_crtc_get_mixer_width(struct sde_crtc *sde_crtc,
+ struct sde_crtc_state *cstate, struct drm_display_mode *mode)
{
- if (!sde_crtc || !mode)
+ u32 mixer_width;
+
+ if (!sde_crtc || !cstate || !mode)
return 0;
- return sde_crtc->num_mixers == CRTC_DUAL_MIXERS ?
- mode->hdisplay / CRTC_DUAL_MIXERS : mode->hdisplay;
+ if (cstate->num_ds_enabled)
+ mixer_width = cstate->ds_cfg[0].lm_width;
+ else
+ mixer_width = (sde_crtc->num_mixers == CRTC_DUAL_MIXERS ?
+ mode->hdisplay / CRTC_DUAL_MIXERS : mode->hdisplay);
+
+ return mixer_width;
+}
+
+/**
+ * sde_crtc_get_mixer_height - get the mixer height
+ * Mixer height will be same as panel height unless
+ * destination scaler feature is enabled
+ */
+static inline int sde_crtc_get_mixer_height(struct sde_crtc *sde_crtc,
+ struct sde_crtc_state *cstate, struct drm_display_mode *mode)
+{
+ if (!sde_crtc || !cstate || !mode)
+ return 0;
+
+ return (cstate->num_ds_enabled ?
+ cstate->ds_cfg[0].lm_height : mode->vdisplay);
}
/**
@@ -503,8 +541,8 @@
if (!cstate)
return NRT_CLIENT;
- return cstate->rsc_client ? RT_RSC_CLIENT :
- (cstate->intf_mode == INTF_MODE_WB_LINE ? NRT_CLIENT : RT_CLIENT);
+ return sde_crtc_get_intf_mode(crtc) == INTF_MODE_WB_LINE ? NRT_CLIENT :
+ (cstate->rsc_client ? RT_RSC_CLIENT : RT_CLIENT);
}
/**
diff --git a/drivers/gpu/drm/msm/sde/sde_encoder.c b/drivers/gpu/drm/msm/sde/sde_encoder.c
index 270e677..c92753f 100644
--- a/drivers/gpu/drm/msm/sde/sde_encoder.c
+++ b/drivers/gpu/drm/msm/sde/sde_encoder.c
@@ -179,6 +179,7 @@
* @crtc_frame_event_cb_data: callback handler private data
* @frame_done_timeout: frame done timeout in Hz
* @frame_done_timer: watchdog timer for frame done event
+ * @vsync_event_timer: vsync timer
* @rsc_client: rsc client pointer
* @rsc_state_init: boolean to indicate rsc config init
* @disp_info: local copy of msm_display_info struct
@@ -191,6 +192,7 @@
* @rc_state: resource controller state
* @delayed_off_work: delayed worker to schedule disabling of
* clks and resources after IDLE_TIMEOUT time.
+ * @vsync_event_work: worker to handle vsync event for autorefresh
* @topology: topology of the display
* @mode_set_complete: flag to indicate modeset completion
* @rsc_config: rsc configuration for display vtotal, fps, etc.
@@ -224,6 +226,7 @@
atomic_t frame_done_timeout;
struct timer_list frame_done_timer;
+ struct timer_list vsync_event_timer;
struct sde_rsc_client *rsc_client;
bool rsc_state_init;
@@ -236,6 +239,7 @@
struct mutex rc_lock;
enum sde_enc_rc_states rc_state;
struct kthread_delayed_work delayed_off_work;
+ struct kthread_work vsync_event_work;
struct msm_display_topology topology;
bool mode_set_complete;
@@ -438,7 +442,7 @@
irq = &phys_enc->irq[intr_idx];
if (irq->irq_idx >= 0) {
- SDE_ERROR_PHYS(phys_enc,
+ SDE_DEBUG_PHYS(phys_enc,
"skipping already registered irq %s type %d\n",
irq->name, irq->intr_type);
return 0;
@@ -1291,7 +1295,7 @@
}
break;
default:
- SDE_ERROR_ENC(sde_enc, "Unexpected topology:%d\n", topology);
+ SDE_DEBUG_ENC(sde_enc, "Unexpected topology:%d\n", topology);
return -EINVAL;
};
@@ -1502,29 +1506,31 @@
{
struct sde_encoder_virt *sde_enc = to_sde_encoder_virt(drm_enc);
struct sde_encoder_rsc_config rsc_cfg = { 0 };
+ int i;
if (enable) {
rsc_cfg.inline_rotate_prefill =
sde_crtc_get_inline_prefill(drm_enc->crtc);
- /* connect the TE source to actual TE GPIO to drive RSC */
- _sde_encoder_update_vsync_source(sde_enc, &sde_enc->disp_info,
- false);
-
_sde_encoder_update_rsc_client(drm_enc, &rsc_cfg, true);
} else {
_sde_encoder_update_rsc_client(drm_enc, NULL, false);
/**
- * disconnect the TE source from the actual TE GPIO for RSC
- *
- * this call is for hardware workaround on sdm845 and should
- * not be removed without considering the design changes for
- * sde rsc + command mode concurrency. It may lead to pp
- * timeout due to vsync from panel for command mode panel.
+ * disable the vsync source after updating the rsc state. rsc
+ * state update might have vsync wait and vsync source must be
+ * disabled after it. It will avoid generating any vsync from
+ * this point till mode-2 entry. It is SW workaround for
+ * HW limitation and should not be removed without checking the
+ * updated design.
*/
- _sde_encoder_update_vsync_source(sde_enc, &sde_enc->disp_info,
- true);
+ for (i = 0; i < sde_enc->num_phys_encs; i++) {
+ struct sde_encoder_phys *phys = sde_enc->phys_encs[i];
+
+ if (phys && phys->ops.prepare_idle_pc)
+ phys->ops.prepare_idle_pc(phys);
+ }
+
}
}
@@ -2842,6 +2848,165 @@
phys->hw_pp->ops.setup_dither(phys->hw_pp, dither_cfg, len);
}
+static u32 _sde_encoder_calculate_linetime(struct sde_encoder_virt *sde_enc,
+ struct drm_display_mode *mode)
+{
+ u64 pclk_rate;
+ u32 pclk_period;
+ u32 line_time;
+
+ /*
+ * For linetime calculation, only operate on master encoder.
+ */
+ if (!sde_enc->cur_master)
+ return 0;
+
+ if (!sde_enc->cur_master->ops.get_line_count) {
+ SDE_ERROR("get_line_count function not defined\n");
+ return 0;
+ }
+
+ pclk_rate = mode->clock; /* pixel clock in kHz */
+ if (pclk_rate == 0) {
+ SDE_ERROR("pclk is 0, cannot calculate line time\n");
+ return 0;
+ }
+
+ pclk_period = DIV_ROUND_UP_ULL(1000000000ull, pclk_rate);
+ if (pclk_period == 0) {
+ SDE_ERROR("pclk period is 0\n");
+ return 0;
+ }
+
+ /*
+ * Line time calculation based on Pixel clock and HTOTAL.
+ * Final unit is in ns.
+ */
+ line_time = (pclk_period * mode->htotal) / 1000;
+ if (line_time == 0) {
+ SDE_ERROR("line time calculation is 0\n");
+ return 0;
+ }
+
+ SDE_DEBUG_ENC(sde_enc,
+ "clk_rate=%lldkHz, clk_period=%d, linetime=%dns\n",
+ pclk_rate, pclk_period, line_time);
+
+ return line_time;
+}
+
+static int _sde_encoder_wakeup_time(struct drm_encoder *drm_enc,
+ ktime_t *wakeup_time)
+{
+ struct drm_display_mode *mode;
+ struct sde_encoder_virt *sde_enc;
+ u32 cur_line;
+ u32 line_time;
+ u32 vtotal, time_to_vsync;
+ ktime_t cur_time;
+
+ sde_enc = to_sde_encoder_virt(drm_enc);
+
+ if (!drm_enc->crtc || !drm_enc->crtc->state) {
+ SDE_ERROR("crtc/crtc state object is NULL\n");
+ return -EINVAL;
+ }
+ mode = &drm_enc->crtc->state->adjusted_mode;
+
+ line_time = _sde_encoder_calculate_linetime(sde_enc, mode);
+ if (!line_time)
+ return -EINVAL;
+
+ cur_line = sde_enc->cur_master->ops.get_line_count(sde_enc->cur_master);
+
+ vtotal = mode->vtotal;
+ if (cur_line >= vtotal)
+ time_to_vsync = line_time * vtotal;
+ else
+ time_to_vsync = line_time * (vtotal - cur_line);
+
+ if (time_to_vsync == 0) {
+ SDE_ERROR("time to vsync should not be zero, vtotal=%d\n",
+ vtotal);
+ return -EINVAL;
+ }
+
+ cur_time = ktime_get();
+ *wakeup_time = ktime_add_ns(cur_time, time_to_vsync);
+
+ SDE_DEBUG_ENC(sde_enc,
+ "cur_line=%u vtotal=%u time_to_vsync=%u, cur_time=%lld, wakeup_time=%lld\n",
+ cur_line, vtotal, time_to_vsync,
+ ktime_to_ms(cur_time),
+ ktime_to_ms(*wakeup_time));
+ return 0;
+}
+
+static void sde_encoder_vsync_event_handler(unsigned long data)
+{
+ struct drm_encoder *drm_enc = (struct drm_encoder *) data;
+ struct sde_encoder_virt *sde_enc;
+ struct msm_drm_private *priv;
+ struct msm_drm_thread *event_thread;
+ bool autorefresh_enabled = false;
+
+ if (!drm_enc || !drm_enc->dev || !drm_enc->dev->dev_private ||
+ !drm_enc->crtc) {
+ SDE_ERROR("invalid parameters\n");
+ return;
+ }
+
+ sde_enc = to_sde_encoder_virt(drm_enc);
+ priv = drm_enc->dev->dev_private;
+
+ if (drm_enc->crtc->index >= ARRAY_SIZE(priv->event_thread)) {
+ SDE_ERROR("invalid crtc index\n");
+ return;
+ }
+ event_thread = &priv->event_thread[drm_enc->crtc->index];
+ if (!event_thread) {
+ SDE_ERROR("event_thread not found for crtc:%d\n",
+ drm_enc->crtc->index);
+ return;
+ }
+
+ if (sde_enc->cur_master &&
+ sde_enc->cur_master->ops.is_autorefresh_enabled)
+ autorefresh_enabled =
+ sde_enc->cur_master->ops.is_autorefresh_enabled(
+ sde_enc->cur_master);
+
+ /*
+ * Queue work to update the vsync event timer
+ * if autorefresh is enabled.
+ */
+ SDE_EVT32_VERBOSE(autorefresh_enabled);
+ if (autorefresh_enabled)
+ kthread_queue_work(&event_thread->worker,
+ &sde_enc->vsync_event_work);
+ else
+ del_timer(&sde_enc->vsync_event_timer);
+}
+
+static void sde_encoder_vsync_event_work_handler(struct kthread_work *work)
+{
+ struct sde_encoder_virt *sde_enc = container_of(work,
+ struct sde_encoder_virt, vsync_event_work);
+ ktime_t wakeup_time;
+
+ if (!sde_enc) {
+ SDE_ERROR("invalid sde encoder\n");
+ return;
+ }
+
+ if (_sde_encoder_wakeup_time(&sde_enc->base, &wakeup_time))
+ return;
+
+ SDE_EVT32_VERBOSE(ktime_to_ms(wakeup_time));
+ mod_timer(&sde_enc->vsync_event_timer,
+ nsecs_to_jiffies(ktime_to_ns(wakeup_time)));
+}
+
void sde_encoder_prepare_for_kickoff(struct drm_encoder *drm_enc,
struct sde_encoder_kickoff_params *params)
{
@@ -2909,6 +3074,7 @@
{
struct sde_encoder_virt *sde_enc;
struct sde_encoder_phys *phys;
+ ktime_t wakeup_time;
unsigned int i;
if (!drm_enc) {
@@ -2935,6 +3101,14 @@
if (phys && phys->ops.handle_post_kickoff)
phys->ops.handle_post_kickoff(phys);
}
+
+ if (sde_enc->disp_info.intf_type == DRM_MODE_CONNECTOR_DSI &&
+ !_sde_encoder_wakeup_time(drm_enc, &wakeup_time)) {
+ SDE_EVT32_VERBOSE(ktime_to_ms(wakeup_time));
+ mod_timer(&sde_enc->vsync_event_timer,
+ nsecs_to_jiffies(ktime_to_ns(wakeup_time)));
+ }
+
SDE_ATRACE_END("encoder_kickoff");
}
@@ -3553,6 +3727,12 @@
setup_timer(&sde_enc->frame_done_timer, sde_encoder_frame_done_timeout,
(unsigned long) sde_enc);
+ if ((disp_info->intf_type == DRM_MODE_CONNECTOR_DSI) &&
+ disp_info->is_primary)
+ setup_timer(&sde_enc->vsync_event_timer,
+ sde_encoder_vsync_event_handler,
+ (unsigned long)sde_enc);
+
snprintf(name, SDE_NAME_SIZE, "rsc_enc%u", drm_enc->base.id);
sde_enc->rsc_client = sde_rsc_client_create(SDE_RSC_INDEX, name,
disp_info->is_primary);
@@ -3566,6 +3746,10 @@
kthread_init_delayed_work(&sde_enc->delayed_off_work,
sde_encoder_off_work);
sde_enc->idle_timeout = IDLE_TIMEOUT;
+
+ kthread_init_work(&sde_enc->vsync_event_work,
+ sde_encoder_vsync_event_work_handler);
+
memcpy(&sde_enc->disp_info, disp_info, sizeof(*disp_info));
SDE_DEBUG_ENC(sde_enc, "created\n");
diff --git a/drivers/gpu/drm/msm/sde/sde_encoder_phys.h b/drivers/gpu/drm/msm/sde/sde_encoder_phys.h
index 5a78e4d..e90074b 100644
--- a/drivers/gpu/drm/msm/sde/sde_encoder_phys.h
+++ b/drivers/gpu/drm/msm/sde/sde_encoder_phys.h
@@ -125,9 +125,12 @@
* SDE_ENC_ERR_NEEDS_HW_RESET state
* @irq_control: Handler to enable/disable all the encoder IRQs
* @update_split_role: Update the split role of the phys enc
+ * @prepare_idle_pc: phys encoder can update the vsync_enable status
+ * on idle power collapse prepare
* @restore: Restore all the encoder configs.
* @is_autorefresh_enabled: provides the autorefresh current
* enable/disable state.
+ * @get_line_count: Obtain current vertical line count
*/
struct sde_encoder_phys_ops {
@@ -167,8 +170,10 @@
void (*irq_control)(struct sde_encoder_phys *phys, bool enable);
void (*update_split_role)(struct sde_encoder_phys *phys_enc,
enum sde_enc_split_role role);
+ void (*prepare_idle_pc)(struct sde_encoder_phys *phys_enc);
void (*restore)(struct sde_encoder_phys *phys);
bool (*is_autorefresh_enabled)(struct sde_encoder_phys *phys);
+ int (*get_line_count)(struct sde_encoder_phys *phys);
};
/**
diff --git a/drivers/gpu/drm/msm/sde/sde_encoder_phys_cmd.c b/drivers/gpu/drm/msm/sde/sde_encoder_phys_cmd.c
index 70a25dd..4291098 100644
--- a/drivers/gpu/drm/msm/sde/sde_encoder_phys_cmd.c
+++ b/drivers/gpu/drm/msm/sde/sde_encoder_phys_cmd.c
@@ -34,9 +34,6 @@
#define PP_TIMEOUT_MAX_TRIALS 10
-/* wait for 2 vyncs only */
-#define CTL_START_TIMEOUT_MS 32
-
/*
* Tearcheck sync start and continue thresholds are empirically found
* based on common panels In the future, may want to allow panels to override
@@ -897,6 +894,30 @@
phys_enc->hw_pp->ops.connect_external_te(phys_enc->hw_pp, enable);
}
+static void sde_encoder_phys_cmd_prepare_idle_pc(
+ struct sde_encoder_phys *phys_enc)
+{
+ _sde_encoder_phys_cmd_connect_te(phys_enc, false);
+}
+
+static int sde_encoder_phys_cmd_get_line_count(
+ struct sde_encoder_phys *phys_enc)
+{
+ struct sde_hw_pingpong *hw_pp;
+
+ if (!phys_enc || !phys_enc->hw_pp)
+ return -EINVAL;
+
+ if (!sde_encoder_phys_cmd_is_master(phys_enc))
+ return -EINVAL;
+
+ hw_pp = phys_enc->hw_pp;
+ if (!hw_pp->ops.get_line_count)
+ return -EINVAL;
+
+ return hw_pp->ops.get_line_count(hw_pp);
+}
+
static void sde_encoder_phys_cmd_disable(struct sde_encoder_phys *phys_enc)
{
struct sde_encoder_phys_cmd *cmd_enc =
@@ -1007,7 +1028,7 @@
wait_info.wq = &phys_enc->pending_kickoff_wq;
wait_info.atomic_cnt = &phys_enc->pending_ctlstart_cnt;
- wait_info.timeout_ms = CTL_START_TIMEOUT_MS;
+ wait_info.timeout_ms = KICKOFF_TIMEOUT_MS;
/* slave encoder doesn't enable for ppsplit */
if (_sde_encoder_phys_is_ppsplit_slave(phys_enc))
@@ -1239,9 +1260,11 @@
ops->irq_control = sde_encoder_phys_cmd_irq_control;
ops->update_split_role = sde_encoder_phys_cmd_update_split_role;
ops->restore = sde_encoder_phys_cmd_enable_helper;
+ ops->prepare_idle_pc = sde_encoder_phys_cmd_prepare_idle_pc;
ops->is_autorefresh_enabled =
sde_encoder_phys_cmd_is_autorefresh_enabled;
ops->handle_post_kickoff = sde_encoder_phys_cmd_handle_post_kickoff;
+ ops->get_line_count = sde_encoder_phys_cmd_get_line_count;
}
struct sde_encoder_phys *sde_encoder_phys_cmd_init(
diff --git a/drivers/gpu/drm/msm/sde/sde_encoder_phys_vid.c b/drivers/gpu/drm/msm/sde/sde_encoder_phys_vid.c
index 3158fe2..6a4348ba 100644
--- a/drivers/gpu/drm/msm/sde/sde_encoder_phys_vid.c
+++ b/drivers/gpu/drm/msm/sde/sde_encoder_phys_vid.c
@@ -483,13 +483,19 @@
{
struct sde_encoder_irq *irq;
+ /*
+ * Initialize irq->hw_idx only when irq is not registered.
+ * Prevent invalidating irq->irq_idx as modeset may be
+ * called many times during dfps.
+ */
+
irq = &phys_enc->irq[INTR_IDX_VSYNC];
- irq->hw_idx = phys_enc->intf_idx;
- irq->irq_idx = -EINVAL;
+ if (irq->irq_idx < 0)
+ irq->hw_idx = phys_enc->intf_idx;
irq = &phys_enc->irq[INTR_IDX_UNDERRUN];
- irq->hw_idx = phys_enc->intf_idx;
- irq->irq_idx = -EINVAL;
+ if (irq->irq_idx < 0)
+ irq->hw_idx = phys_enc->intf_idx;
}
static void sde_encoder_phys_vid_mode_set(
@@ -899,6 +905,24 @@
vid_enc->hw_intf->ops.collect_misr(vid_enc->hw_intf) : 0;
}
+static int sde_encoder_phys_vid_get_line_count(
+ struct sde_encoder_phys *phys_enc)
+{
+ struct sde_encoder_phys_vid *vid_enc;
+
+ if (!phys_enc)
+ return -EINVAL;
+
+ if (!sde_encoder_phys_vid_is_master(phys_enc))
+ return -EINVAL;
+
+ vid_enc = to_sde_encoder_phys_vid(phys_enc);
+ if (!vid_enc->hw_intf || !vid_enc->hw_intf->ops.get_line_count)
+ return -EINVAL;
+
+ return vid_enc->hw_intf->ops.get_line_count(vid_enc->hw_intf);
+}
+
static void sde_encoder_phys_vid_init_ops(struct sde_encoder_phys_ops *ops)
{
ops->is_master = sde_encoder_phys_vid_is_master;
@@ -919,6 +943,7 @@
ops->setup_misr = sde_encoder_phys_vid_setup_misr;
ops->collect_misr = sde_encoder_phys_vid_collect_misr;
ops->hw_reset = sde_encoder_helper_hw_reset;
+ ops->get_line_count = sde_encoder_phys_vid_get_line_count;
}
struct sde_encoder_phys *sde_encoder_phys_vid_init(
diff --git a/drivers/gpu/drm/msm/sde/sde_fence.c b/drivers/gpu/drm/msm/sde/sde_fence.c
index 5732aae6..c013fef 100644
--- a/drivers/gpu/drm/msm/sde/sde_fence.c
+++ b/drivers/gpu/drm/msm/sde/sde_fence.c
@@ -305,6 +305,7 @@
spin_unlock_irqrestore(&ctx->lock, flags);
if (is_signaled) {
+ list_del_init(&fc->fence_list);
fence_put(&fc->base);
kref_put(&ctx->kref, sde_fence_destroy);
} else {
diff --git a/drivers/gpu/drm/msm/sde/sde_hw_catalog.c b/drivers/gpu/drm/msm/sde/sde_hw_catalog.c
index f35e999..aea2c6b 100644
--- a/drivers/gpu/drm/msm/sde/sde_hw_catalog.c
+++ b/drivers/gpu/drm/msm/sde/sde_hw_catalog.c
@@ -36,9 +36,12 @@
/* each entry will have register address and bit offset in that register */
#define MAX_BIT_OFFSET 2
-/* default line width for sspp */
+/* default line width for sspp, mixer, ds (input), wb */
#define DEFAULT_SDE_LINE_WIDTH 2048
+/* default output line width for ds */
+#define DEFAULT_SDE_OUTPUT_LINE_WIDTH 2560
+
/* max mixer blend stages */
#define DEFAULT_SDE_MIXER_BLENDSTAGES 7
@@ -60,8 +63,8 @@
/* total number of intf - dp, dsi, hdmi */
#define INTF_COUNT 3
-#define MAX_SSPP_UPSCALE 20
-#define MAX_SSPP_DOWNSCALE 4
+#define MAX_UPSCALE_RATIO 20
+#define MAX_DOWNSCALE_RATIO 4
#define SSPP_UNITY_SCALE 1
#define MAX_HORZ_DECIMATION 4
@@ -140,6 +143,7 @@
DIM_LAYER,
SMART_DMA_REV,
IDLE_PC,
+ DEST_SCALER,
SDE_PROP_MAX,
};
@@ -233,6 +237,20 @@
};
enum {
+ DS_TOP_OFF,
+ DS_TOP_LEN,
+ DS_TOP_INPUT_LINEWIDTH,
+ DS_TOP_OUTPUT_LINEWIDTH,
+ DS_TOP_PROP_MAX,
+};
+
+enum {
+ DS_OFF,
+ DS_LEN,
+ DS_PROP_MAX,
+};
+
+enum {
DSPP_TOP_OFF,
DSPP_TOP_SIZE,
DSPP_TOP_PROP_MAX,
@@ -374,6 +392,7 @@
{DIM_LAYER, "qcom,sde-has-dim-layer", false, PROP_TYPE_BOOL},
{SMART_DMA_REV, "qcom,sde-smart-dma-rev", false, PROP_TYPE_STRING},
{IDLE_PC, "qcom,sde-has-idle-pc", false, PROP_TYPE_BOOL},
+ {DEST_SCALER, "qcom,sde-has-dest-scaler", false, PROP_TYPE_BOOL},
};
static struct sde_prop_type sde_perf_prop[] = {
@@ -506,6 +525,20 @@
{AD_VERSION, "qcom,sde-dspp-ad-version", false, PROP_TYPE_U32},
};
+static struct sde_prop_type ds_top_prop[] = {
+ {DS_TOP_OFF, "qcom,sde-dest-scaler-top-off", false, PROP_TYPE_U32},
+ {DS_TOP_LEN, "qcom,sde-dest-scaler-top-size", false, PROP_TYPE_U32},
+ {DS_TOP_INPUT_LINEWIDTH, "qcom,sde-max-dest-scaler-input-linewidth",
+ false, PROP_TYPE_U32},
+ {DS_TOP_OUTPUT_LINEWIDTH, "qcom,sde-max-dest-scaler-output-linewidth",
+ false, PROP_TYPE_U32},
+};
+
+static struct sde_prop_type ds_prop[] = {
+ {DS_OFF, "qcom,sde-dest-scaler-off", false, PROP_TYPE_U32_ARRAY},
+ {DS_LEN, "qcom,sde-dest-scaler-size", false, PROP_TYPE_U32},
+};
+
static struct sde_prop_type pp_prop[] = {
{PP_OFF, "qcom,sde-pp-off", true, PROP_TYPE_U32_ARRAY},
{PP_LEN, "qcom,sde-pp-size", false, PROP_TYPE_U32},
@@ -863,8 +896,8 @@
struct sde_sspp_cfg *sspp, struct sde_sspp_sub_blks *sblk,
bool *prop_exists, struct sde_prop_value *prop_value, u32 *vig_count)
{
- sblk->maxupscale = MAX_SSPP_UPSCALE;
- sblk->maxdwnscale = MAX_SSPP_DOWNSCALE;
+ sblk->maxupscale = MAX_UPSCALE_RATIO;
+ sblk->maxdwnscale = MAX_DOWNSCALE_RATIO;
sspp->id = SSPP_VIG0 + *vig_count;
snprintf(sspp->name, SDE_HW_BLK_NAME_LEN, "sspp_%u",
sspp->id - SSPP_VIG0);
@@ -958,8 +991,8 @@
struct sde_sspp_cfg *sspp, struct sde_sspp_sub_blks *sblk,
bool *prop_exists, struct sde_prop_value *prop_value, u32 *rgb_count)
{
- sblk->maxupscale = MAX_SSPP_UPSCALE;
- sblk->maxdwnscale = MAX_SSPP_DOWNSCALE;
+ sblk->maxupscale = MAX_UPSCALE_RATIO;
+ sblk->maxdwnscale = MAX_DOWNSCALE_RATIO;
sspp->id = SSPP_RGB0 + *rgb_count;
snprintf(sspp->name, SDE_HW_BLK_NAME_LEN, "sspp_%u",
sspp->id - SSPP_VIG0);
@@ -1293,8 +1326,8 @@
u32 off_count, blend_off_count, max_blendstages, lm_pair_mask;
struct sde_lm_cfg *mixer;
struct sde_lm_sub_blks *sblk;
- int pp_count, dspp_count;
- u32 pp_idx, dspp_idx;
+ int pp_count, dspp_count, ds_count;
+ u32 pp_idx, dspp_idx, ds_idx;
struct device_node *snp = NULL;
if (!sde_cfg) {
@@ -1325,6 +1358,7 @@
pp_count = sde_cfg->pingpong_count;
dspp_count = sde_cfg->dspp_count;
+ ds_count = sde_cfg->ds_count;
/* get mixer feature dt properties if they exist */
snp = of_get_child_by_name(np, mixer_prop[MIXER_BLOCKS].prop_name);
@@ -1364,7 +1398,7 @@
if (rc)
goto end;
- for (i = 0, pp_idx = 0, dspp_idx = 0; i < off_count; i++) {
+ for (i = 0, pp_idx = 0, dspp_idx = 0, ds_idx = 0; i < off_count; i++) {
mixer = sde_cfg->mixer + i;
sblk = kzalloc(sizeof(*sblk), GFP_KERNEL);
if (!sblk) {
@@ -1406,13 +1440,17 @@
: PINGPONG_MAX;
mixer->dspp = dspp_count > 0 ? dspp_idx + DSPP_0
: DSPP_MAX;
+ mixer->ds = ds_count > 0 ? ds_idx + DS_0 : DS_MAX;
pp_count--;
dspp_count--;
+ ds_count--;
pp_idx++;
dspp_idx++;
+ ds_idx++;
} else {
mixer->pingpong = PINGPONG_MAX;
mixer->dspp = DSPP_MAX;
+ mixer->ds = DS_MAX;
}
sblk->gc.id = SDE_MIXER_GC;
@@ -2044,6 +2082,116 @@
return rc;
}
+static int sde_ds_parse_dt(struct device_node *np,
+ struct sde_mdss_cfg *sde_cfg)
+{
+ int rc, prop_count[DS_PROP_MAX], top_prop_count[DS_TOP_PROP_MAX], i;
+ struct sde_prop_value *prop_value = NULL, *top_prop_value = NULL;
+ bool prop_exists[DS_PROP_MAX], top_prop_exists[DS_TOP_PROP_MAX];
+ u32 off_count = 0, top_off_count = 0;
+ struct sde_ds_cfg *ds;
+ struct sde_ds_top_cfg *ds_top = NULL;
+
+ if (!sde_cfg) {
+ SDE_ERROR("invalid argument\n");
+ rc = -EINVAL;
+ goto end;
+ }
+
+ if (!sde_cfg->mdp[0].has_dest_scaler) {
+ SDE_DEBUG("dest scaler feature not supported\n");
+ rc = 0;
+ goto end;
+ }
+
+ /* Parse the dest scaler top register offset and capabilities */
+ top_prop_value = kzalloc(DS_TOP_PROP_MAX *
+ sizeof(struct sde_prop_value), GFP_KERNEL);
+ if (!top_prop_value) {
+ rc = -ENOMEM;
+ goto end;
+ }
+
+ rc = _validate_dt_entry(np, ds_top_prop,
+ ARRAY_SIZE(ds_top_prop),
+ top_prop_count, &top_off_count);
+ if (rc)
+ goto end;
+
+ rc = _read_dt_entry(np, ds_top_prop,
+ ARRAY_SIZE(ds_top_prop), top_prop_count,
+ top_prop_exists, top_prop_value);
+ if (rc)
+ goto end;
+
+ /* Parse the offset of each dest scaler block */
+ prop_value = kzalloc(DS_PROP_MAX *
+ sizeof(struct sde_prop_value), GFP_KERNEL);
+ if (!prop_value) {
+ rc = -ENOMEM;
+ goto end;
+ }
+
+ rc = _validate_dt_entry(np, ds_prop, ARRAY_SIZE(ds_prop), prop_count,
+ &off_count);
+ if (rc)
+ goto end;
+
+ sde_cfg->ds_count = off_count;
+
+ rc = _read_dt_entry(np, ds_prop, ARRAY_SIZE(ds_prop), prop_count,
+ prop_exists, prop_value);
+ if (rc)
+ goto end;
+
+ if (!off_count)
+ goto end;
+
+ ds_top = kzalloc(sizeof(struct sde_ds_top_cfg), GFP_KERNEL);
+ if (!ds_top) {
+ rc = -ENOMEM;
+ goto end;
+ }
+
+ ds_top->id = DS_TOP;
+ snprintf(ds_top->name, SDE_HW_BLK_NAME_LEN, "ds_top_%u",
+ ds_top->id - DS_TOP);
+ ds_top->base = PROP_VALUE_ACCESS(top_prop_value, DS_TOP_OFF, 0);
+ ds_top->len = PROP_VALUE_ACCESS(top_prop_value, DS_TOP_LEN, 0);
+ ds_top->maxupscale = MAX_UPSCALE_RATIO;
+
+ ds_top->maxinputwidth = PROP_VALUE_ACCESS(top_prop_value,
+ DS_TOP_INPUT_LINEWIDTH, 0);
+ if (!top_prop_exists[DS_TOP_INPUT_LINEWIDTH])
+ ds_top->maxinputwidth = DEFAULT_SDE_LINE_WIDTH;
+
+ ds_top->maxoutputwidth = PROP_VALUE_ACCESS(top_prop_value,
+ DS_TOP_OUTPUT_LINEWIDTH, 0);
+ if (!top_prop_exists[DS_TOP_OUTPUT_LINEWIDTH])
+ ds_top->maxoutputwidth = DEFAULT_SDE_OUTPUT_LINE_WIDTH;
+
+ for (i = 0; i < off_count; i++) {
+ ds = sde_cfg->ds + i;
+ ds->top = ds_top;
+ ds->base = PROP_VALUE_ACCESS(prop_value, DS_OFF, i);
+ ds->id = DS_0 + i;
+ ds->len = PROP_VALUE_ACCESS(prop_value, DS_LEN, 0);
+ snprintf(ds->name, SDE_HW_BLK_NAME_LEN, "ds_%u",
+ ds->id - DS_0);
+
+ if (!prop_exists[DS_LEN])
+ ds->len = DEFAULT_SDE_HW_BLOCK_LEN;
+
+ if (sde_cfg->qseed_type == SDE_SSPP_SCALER_QSEED3)
+ set_bit(SDE_SSPP_SCALER_QSEED3, &ds->features);
+ }
+
+end:
+ kfree(top_prop_value);
+ kfree(prop_value);
+ return rc;
+};
+
static int sde_dsc_parse_dt(struct device_node *np,
struct sde_mdss_cfg *sde_cfg)
{
@@ -2548,6 +2696,9 @@
if (!prop_exists[UBWC_SWIZZLE])
cfg->mdp[0].ubwc_swizzle = DEFAULT_SDE_UBWC_SWIZZLE;
+ cfg->mdp[0].has_dest_scaler =
+ PROP_VALUE_ACCESS(prop_value, DEST_SCALER, 0);
+
rc = of_property_read_string(np, sde_prop[QSEED_TYPE].prop_name, &type);
if (!rc && !strcmp(type, "qseedv3")) {
cfg->qseed_type = SDE_SSPP_SCALER_QSEED3;
@@ -3007,6 +3158,9 @@
for (i = 0; i < sde_cfg->dspp_count; i++)
kfree(sde_cfg->dspp[i].sblk);
+ if (sde_cfg->ds_count)
+ kfree(sde_cfg->ds[0].top);
+
for (i = 0; i < sde_cfg->pingpong_count; i++)
kfree(sde_cfg->pingpong[i].sblk);
@@ -3075,6 +3229,10 @@
if (rc)
goto end;
+ rc = sde_ds_parse_dt(np, sde_cfg);
+ if (rc)
+ goto end;
+
rc = sde_dsc_parse_dt(np, sde_cfg);
if (rc)
goto end;
@@ -3083,7 +3241,9 @@
if (rc)
goto end;
- /* mixer parsing should be done after dspp and pp for mapping setup */
+ /* mixer parsing should be done after dspp,
+ * ds and pp for mapping setup
+ */
rc = sde_mixer_parse_dt(np, sde_cfg);
if (rc)
goto end;
diff --git a/drivers/gpu/drm/msm/sde/sde_hw_catalog.h b/drivers/gpu/drm/msm/sde/sde_hw_catalog.h
index 7c43988..e60b5ca 100644
--- a/drivers/gpu/drm/msm/sde/sde_hw_catalog.h
+++ b/drivers/gpu/drm/msm/sde/sde_hw_catalog.h
@@ -519,6 +519,7 @@
* @highest_bank_bit: UBWC parameter
* @ubwc_static: ubwc static configuration
* @ubwc_swizzle: ubwc default swizzle setting
+ * @has_dest_scaler: indicates support of destination scaler
* @clk_ctrls clock control register definition
*/
struct sde_mdp_cfg {
@@ -526,6 +527,7 @@
u32 highest_bank_bit;
u32 ubwc_static;
u32 ubwc_swizzle;
+ bool has_dest_scaler;
struct sde_clk_ctrl_reg clk_ctrls[SDE_CLK_CTRL_MAX];
};
@@ -564,6 +566,7 @@
* @sblk: LM Sub-blocks information
* @dspp: ID of connected DSPP, DSPP_MAX if unsupported
* @pingpong: ID of connected PingPong, PINGPONG_MAX if unsupported
+ * @ds: ID of connected DS, DS_MAX if unsupported
* @lm_pair_mask: Bitmask of LMs that can be controlled by same CTL
*/
struct sde_lm_cfg {
@@ -571,6 +574,7 @@
const struct sde_lm_sub_blks *sblk;
u32 dspp;
u32 pingpong;
+ u32 ds;
unsigned long lm_pair_mask;
};
@@ -599,6 +603,38 @@
};
/**
+ * struct sde_ds_top_cfg - information of dest scaler top
+ * @id enum identifying this block
+ * @base register offset of this block
+ * @features bit mask identifying features
+ * @version hw version of dest scaler
+ * @maxinputwidth maximum input line width
+ * @maxoutputwidth maximum output line width
+ * @maxupscale maximum upscale ratio
+ */
+struct sde_ds_top_cfg {
+ SDE_HW_BLK_INFO;
+ u32 version;
+ u32 maxinputwidth;
+ u32 maxoutputwidth;
+ u32 maxupscale;
+};
+
+/**
+ * struct sde_ds_cfg - information of dest scaler blocks
+ * @id enum identifying this block
+ * @base register offset wrt DS top offset
+ * @features bit mask identifying features
+ * @version hw version of the qseed block
+ * @top DS top information
+ */
+struct sde_ds_cfg {
+ SDE_HW_BLK_INFO;
+ u32 version;
+ const struct sde_ds_top_cfg *top;
+};
+
+/**
* struct sde_pingpong_cfg - information of PING-PONG blocks
* @id enum identifying this block
* @base register offset of this block
@@ -921,6 +957,9 @@
u32 dspp_count;
struct sde_dspp_cfg dspp[MAX_BLOCKS];
+ u32 ds_count;
+ struct sde_ds_cfg ds[MAX_BLOCKS];
+
u32 pingpong_count;
struct sde_pingpong_cfg pingpong[MAX_BLOCKS];
@@ -973,6 +1012,7 @@
#define BLK_CURSOR(s) ((s)->cursor)
#define BLK_MIXER(s) ((s)->mixer)
#define BLK_DSPP(s) ((s)->dspp)
+#define BLK_DS(s) ((s)->ds)
#define BLK_PINGPONG(s) ((s)->pingpong)
#define BLK_CDM(s) ((s)->cdm)
#define BLK_INTF(s) ((s)->intf)
diff --git a/drivers/gpu/drm/msm/sde/sde_hw_ds.c b/drivers/gpu/drm/msm/sde/sde_hw_ds.c
new file mode 100644
index 0000000..e37a7d6
--- /dev/null
+++ b/drivers/gpu/drm/msm/sde/sde_hw_ds.c
@@ -0,0 +1,149 @@
+/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include "sde_hw_ds.h"
+#include "sde_formats.h"
+#include "sde_dbg.h"
+#include "sde_kms.h"
+
+/* Destination scaler TOP registers */
+#define DEST_SCALER_OP_MODE 0x00
+#define DEST_SCALER_HW_VERSION 0x10
+
+static void sde_hw_ds_setup_opmode(struct sde_hw_ds *hw_ds,
+ u32 op_mode)
+{
+ struct sde_hw_blk_reg_map *hw = &hw_ds->hw;
+
+ SDE_REG_WRITE(hw, DEST_SCALER_OP_MODE, op_mode);
+}
+
+static void sde_hw_ds_setup_scaler3(struct sde_hw_ds *hw_ds,
+ void *scaler_cfg, void *scaler_lut_cfg)
+{
+ struct sde_hw_scaler3_cfg *scl3_cfg = scaler_cfg;
+ struct sde_hw_scaler3_lut_cfg *scl3_lut_cfg = scaler_lut_cfg;
+
+ if (!hw_ds || !hw_ds->scl || !scl3_cfg || !scl3_lut_cfg)
+ return;
+
+ /*
+ * copy LUT values to scaler structure
+ */
+ if (scl3_lut_cfg->is_configured) {
+ scl3_cfg->dir_lut = scl3_lut_cfg->dir_lut;
+ scl3_cfg->dir_len = scl3_lut_cfg->dir_len;
+ scl3_cfg->cir_lut = scl3_lut_cfg->cir_lut;
+ scl3_cfg->cir_len = scl3_lut_cfg->cir_len;
+ scl3_cfg->sep_lut = scl3_lut_cfg->sep_lut;
+ scl3_cfg->sep_len = scl3_lut_cfg->sep_len;
+ }
+
+ sde_hw_setup_scaler3(&hw_ds->hw, scl3_cfg,
+ hw_ds->scl->base,
+ hw_ds->scl->version,
+ sde_get_sde_format(DRM_FORMAT_XBGR2101010));
+}
+
+static void _setup_ds_ops(struct sde_hw_ds_ops *ops, unsigned long features)
+{
+ ops->setup_opmode = sde_hw_ds_setup_opmode;
+
+ if (test_bit(SDE_SSPP_SCALER_QSEED3, &features))
+ ops->setup_scaler = sde_hw_ds_setup_scaler3;
+}
+
+static struct sde_ds_cfg *_ds_offset(enum sde_ds ds,
+ struct sde_mdss_cfg *m,
+ void __iomem *addr,
+ struct sde_hw_blk_reg_map *b)
+{
+ int i;
+
+ if (!m || !addr || !b)
+ return ERR_PTR(-EINVAL);
+
+ for (i = 0; i < m->ds_count; i++) {
+ if ((ds == m->ds[i].id) &&
+ (m->ds[i].top)) {
+ b->base_off = addr;
+ b->blk_off = m->ds[i].top->base;
+ b->length = m->ds[i].top->len;
+ b->hwversion = m->hwversion;
+ b->log_mask = SDE_DBG_MASK_DS;
+ return &m->ds[i];
+ }
+ }
+
+ return ERR_PTR(-EINVAL);
+}
+
+static struct sde_hw_blk_ops sde_hw_ops = {
+ .start = NULL,
+ .stop = NULL,
+};
+
+struct sde_hw_ds *sde_hw_ds_init(enum sde_ds idx,
+ void __iomem *addr,
+ struct sde_mdss_cfg *m)
+{
+ struct sde_hw_ds *hw_ds;
+ struct sde_ds_cfg *cfg;
+ int rc;
+
+ if (!addr || !m)
+ return ERR_PTR(-EINVAL);
+
+ hw_ds = kzalloc(sizeof(*hw_ds), GFP_KERNEL);
+ if (!hw_ds)
+ return ERR_PTR(-ENOMEM);
+
+ cfg = _ds_offset(idx, m, addr, &hw_ds->hw);
+ if (IS_ERR_OR_NULL(cfg)) {
+ SDE_ERROR("failed to get ds cfg\n");
+ kfree(hw_ds);
+ return ERR_PTR(-EINVAL);
+ }
+
+ /* Assign ops */
+ hw_ds->idx = idx;
+ hw_ds->scl = cfg;
+ _setup_ds_ops(&hw_ds->ops, hw_ds->scl->features);
+
+ rc = sde_hw_blk_init(&hw_ds->base, SDE_HW_BLK_DS, idx, &sde_hw_ops);
+ if (rc) {
+ SDE_ERROR("failed to init hw blk %d\n", rc);
+ goto blk_init_error;
+ }
+
+ if (cfg->len) {
+ sde_dbg_reg_register_dump_range(SDE_DBG_NAME, cfg->name,
+ hw_ds->hw.blk_off + cfg->base,
+ hw_ds->hw.blk_off + cfg->base + cfg->len,
+ hw_ds->hw.xin_id);
+ }
+
+ return hw_ds;
+
+blk_init_error:
+ kzfree(hw_ds);
+
+ return ERR_PTR(rc);
+
+}
+
+void sde_hw_ds_destroy(struct sde_hw_ds *hw_ds)
+{
+ if (hw_ds)
+ sde_hw_blk_destroy(&hw_ds->base);
+ kfree(hw_ds);
+}
diff --git a/drivers/gpu/drm/msm/sde/sde_hw_ds.h b/drivers/gpu/drm/msm/sde/sde_hw_ds.h
new file mode 100644
index 0000000..d81cfaf
--- /dev/null
+++ b/drivers/gpu/drm/msm/sde/sde_hw_ds.h
@@ -0,0 +1,111 @@
+/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef _SDE_HW_DS_H
+#define _SDE_HW_DS_H
+
+#include "sde_hw_mdss.h"
+#include "sde_hw_util.h"
+#include "sde_hw_catalog.h"
+#include "sde_hw_blk.h"
+
+struct sde_hw_ds;
+
+/* Destination Scaler DUAL mode overfetch pixel count */
+#define SDE_DS_OVERFETCH_SIZE 5
+
+/* Destination scaler DUAL mode operation bit */
+#define SDE_DS_OP_MODE_DUAL BIT(16)
+
+/* struct sde_hw_ds_cfg - destination scaler config
+ * @ndx : DS selection index
+ * @flags : Flag to switch between mode for DS
+ * @lm_width : Layer mixer width configuration
+ * @lm_heigh : Layer mixer height configuration
+ * @set_lm_flush : LM flush bit
+ * @scl3_cfg : Pointer to sde_hw_scaler3_cfg.
+ */
+struct sde_hw_ds_cfg {
+ u32 ndx;
+ int flags;
+ u32 lm_width;
+ u32 lm_height;
+ bool set_lm_flush;
+ struct sde_hw_scaler3_cfg *scl3_cfg;
+};
+
+/**
+ * struct sde_hw_ds_ops - interface to the destination scaler
+ * hardware driver functions
+ * Caller must call the init function to get the ds context for each ds
+ * Assumption is these functions will be called after clocks are enabled
+ */
+struct sde_hw_ds_ops {
+ /**
+ * setup_opmode - destination scaler op mode setup
+ * @hw_ds : Pointer to ds context
+ * @op_mode : Op mode configuration
+ */
+ void (*setup_opmode)(struct sde_hw_ds *hw_ds,
+ u32 op_mode);
+
+ /**
+ * setup_scaler - destination scaler block setup
+ * @hw_ds : Pointer to ds context
+ * @scaler_cfg : Pointer to scaler data
+ * @scaler_lut_cfg : Pointer to scaler lut
+ */
+ void (*setup_scaler)(struct sde_hw_ds *hw_ds,
+ void *scaler_cfg,
+ void *scaler_lut_cfg);
+
+};
+
+/**
+ * struct sde_hw_ds - destination scaler description
+ * @base : Hardware block base structure
+ * @hw : Block hardware details
+ * @idx : Destination scaler index
+ * @scl : Pointer to
+ * - scaler offset relative to top offset
+ * - capabilities
+ * @ops : Pointer to operations for this DS
+ */
+struct sde_hw_ds {
+ struct sde_hw_blk base;
+ struct sde_hw_blk_reg_map hw;
+ enum sde_ds idx;
+ const struct sde_ds_cfg *scl;
+ struct sde_hw_ds_ops ops;
+};
+
+/**
+ * sde_hw_ds_init - initializes the destination scaler
+ * hw driver object and should be called once before
+ * accessing every destination scaler
+ * @idx : DS index for which driver object is required
+ * @addr: Mapped register io address of MDP
+ * @m : MDSS catalog information
+ * @Return: pointer to structure or ERR_PTR
+ */
+struct sde_hw_ds *sde_hw_ds_init(enum sde_ds idx,
+ void __iomem *addr,
+ struct sde_mdss_cfg *m);
+
+/**
+ * sde_hw_ds_destroy - destroys destination scaler
+ * driver context
+ * @hw_ds: Pointer to DS context
+ */
+void sde_hw_ds_destroy(struct sde_hw_ds *hw_ds);
+
+#endif /*_SDE_HW_DS_H */
diff --git a/drivers/gpu/drm/msm/sde/sde_hw_intf.c b/drivers/gpu/drm/msm/sde/sde_hw_intf.c
index 35f1800..fd06c12 100644
--- a/drivers/gpu/drm/msm/sde/sde_hw_intf.c
+++ b/drivers/gpu/drm/msm/sde/sde_hw_intf.c
@@ -289,6 +289,18 @@
return SDE_REG_READ(c, INTF_MISR_SIGNATURE);
}
+static u32 sde_hw_intf_get_line_count(struct sde_hw_intf *intf)
+{
+ struct sde_hw_blk_reg_map *c;
+
+ if (!intf)
+ return 0;
+
+ c = &intf->hw;
+
+ return SDE_REG_READ(c, INTF_LINE_COUNT);
+}
+
static void _setup_intf_ops(struct sde_hw_intf_ops *ops,
unsigned long cap)
{
@@ -298,6 +310,7 @@
ops->enable_timing = sde_hw_intf_enable_timing_engine;
ops->setup_misr = sde_hw_intf_setup_misr;
ops->collect_misr = sde_hw_intf_collect_misr;
+ ops->get_line_count = sde_hw_intf_get_line_count;
if (cap & BIT(SDE_INTF_ROT_START))
ops->setup_rot_start = sde_hw_intf_setup_rot_start;
}
diff --git a/drivers/gpu/drm/msm/sde/sde_hw_intf.h b/drivers/gpu/drm/msm/sde/sde_hw_intf.h
index 83e206d..89068bc 100644
--- a/drivers/gpu/drm/msm/sde/sde_hw_intf.h
+++ b/drivers/gpu/drm/msm/sde/sde_hw_intf.h
@@ -62,6 +62,7 @@
* @ get_status: returns if timing engine is enabled or not
* @ setup_misr: enables/disables MISR in HW register
* @ collect_misr: reads and stores MISR data from HW register
+ * @ get_line_count: reads current vertical line counter
*/
struct sde_hw_intf_ops {
void (*setup_timing_gen)(struct sde_hw_intf *intf,
@@ -84,6 +85,8 @@
bool enable, u32 frame_count);
u32 (*collect_misr)(struct sde_hw_intf *intf);
+
+ u32 (*get_line_count)(struct sde_hw_intf *intf);
};
struct sde_hw_intf {
diff --git a/drivers/gpu/drm/msm/sde/sde_hw_mdss.h b/drivers/gpu/drm/msm/sde/sde_hw_mdss.h
index f07f5ed..952ee8f 100644
--- a/drivers/gpu/drm/msm/sde/sde_hw_mdss.h
+++ b/drivers/gpu/drm/msm/sde/sde_hw_mdss.h
@@ -100,6 +100,7 @@
SDE_HW_BLK_SSPP,
SDE_HW_BLK_LM,
SDE_HW_BLK_DSPP,
+ SDE_HW_BLK_DS,
SDE_HW_BLK_CTL,
SDE_HW_BLK_CDM,
SDE_HW_BLK_PINGPONG,
@@ -176,6 +177,13 @@
DSPP_MAX
};
+enum sde_ds {
+ DS_TOP,
+ DS_0,
+ DS_1,
+ DS_MAX
+};
+
enum sde_ctl {
CTL_0 = 1,
CTL_1,
@@ -489,6 +497,7 @@
#define SDE_DBG_MASK_VBIF (1 << 10)
#define SDE_DBG_MASK_DSC (1 << 11)
#define SDE_DBG_MASK_ROT (1 << 12)
+#define SDE_DBG_MASK_DS (1 << 13)
/**
* struct sde_hw_cp_cfg: hardware dspp/lm feature payload.
diff --git a/drivers/gpu/drm/msm/sde/sde_hw_pingpong.c b/drivers/gpu/drm/msm/sde/sde_hw_pingpong.c
index d65e8d0..d8f79f1 100644
--- a/drivers/gpu/drm/msm/sde/sde_hw_pingpong.c
+++ b/drivers/gpu/drm/msm/sde/sde_hw_pingpong.c
@@ -302,6 +302,33 @@
return 0;
}
+static u32 sde_hw_pp_get_line_count(struct sde_hw_pingpong *pp)
+{
+ struct sde_hw_blk_reg_map *c = &pp->hw;
+ u32 height, init;
+ u32 line = 0xFFFF;
+
+ if (!pp)
+ return 0;
+ c = &pp->hw;
+
+ init = SDE_REG_READ(c, PP_VSYNC_INIT_VAL) & 0xFFFF;
+ height = SDE_REG_READ(c, PP_SYNC_CONFIG_HEIGHT) & 0xFFFF;
+
+ if (height < init)
+ goto line_count_exit;
+
+ line = SDE_REG_READ(c, PP_INT_COUNT_VAL) & 0xFFFF;
+
+ if (line < init)
+ line += (0xFFFF - init);
+ else
+ line -= init;
+
+line_count_exit:
+ return line;
+}
+
static void _setup_pingpong_ops(struct sde_hw_pingpong_ops *ops,
const struct sde_pingpong_cfg *hw_cap)
{
@@ -317,6 +344,7 @@
ops->disable_dsc = sde_hw_pp_dsc_disable;
ops->get_autorefresh = sde_hw_pp_get_autorefresh_config;
ops->poll_timeout_wr_ptr = sde_hw_pp_poll_timeout_wr_ptr;
+ ops->get_line_count = sde_hw_pp_get_line_count;
version = SDE_COLOR_PROCESS_MAJOR(hw_cap->sblk->dither.version);
switch (version) {
diff --git a/drivers/gpu/drm/msm/sde/sde_hw_pingpong.h b/drivers/gpu/drm/msm/sde/sde_hw_pingpong.h
index f0a2054..389b2d2 100644
--- a/drivers/gpu/drm/msm/sde/sde_hw_pingpong.h
+++ b/drivers/gpu/drm/msm/sde/sde_hw_pingpong.h
@@ -64,6 +64,7 @@
* @enable_dsc : enables DSC encoder
* @disable_dsc : disables DSC encoder
* @setup_dither : function to program the dither hw block
+ * @get_line_count: obtain current vertical line counter
*/
struct sde_hw_pingpong_ops {
/**
@@ -130,6 +131,11 @@
* Program the dither hw block
*/
int (*setup_dither)(struct sde_hw_pingpong *pp, void *cfg, size_t len);
+
+ /**
+ * Obtain current vertical line counter
+ */
+ u32 (*get_line_count)(struct sde_hw_pingpong *pp);
};
struct sde_hw_pingpong {
diff --git a/drivers/gpu/drm/msm/sde/sde_hw_reg_dma_v1.c b/drivers/gpu/drm/msm/sde/sde_hw_reg_dma_v1.c
index 93637a4..d7b7625 100644
--- a/drivers/gpu/drm/msm/sde/sde_hw_reg_dma_v1.c
+++ b/drivers/gpu/drm/msm/sde/sde_hw_reg_dma_v1.c
@@ -699,7 +699,9 @@
msm_gem_address_space_unregister_cb(aspace,
sde_reg_dma_aspace_cb_locked, dma_buf);
free_gem:
+ mutex_lock(®_dma->drm_dev->struct_mutex);
msm_gem_free_object(dma_buf->buf);
+ mutex_unlock(®_dma->drm_dev->struct_mutex);
fail:
kfree(dma_buf);
return ERR_PTR(rc);
diff --git a/drivers/gpu/drm/msm/sde/sde_irq.c b/drivers/gpu/drm/msm/sde/sde_irq.c
index eeb7a00..7864b9f 100644
--- a/drivers/gpu/drm/msm/sde/sde_irq.c
+++ b/drivers/gpu/drm/msm/sde/sde_irq.c
@@ -19,6 +19,8 @@
#include "sde_irq.h"
#include "sde_core_irq.h"
+static uint32_t g_sde_irq_status;
+
irqreturn_t sde_irq(struct msm_kms *kms)
{
struct sde_kms *sde_kms = to_sde_kms(kms);
@@ -27,6 +29,9 @@
sde_kms->hw_intr->ops.get_interrupt_sources(sde_kms->hw_intr,
&interrupts);
+ /* store irq status in case of irq-storm debugging */
+ g_sde_irq_status = interrupts;
+
/*
* Taking care of MDP interrupt
*/
@@ -40,13 +45,30 @@
*/
while (interrupts) {
irq_hw_number_t hwirq = fls(interrupts) - 1;
+ unsigned int mapping;
+ int rc;
- generic_handle_irq(irq_find_mapping(
- sde_kms->irq_controller.domain, hwirq));
+ mapping = irq_find_mapping(sde_kms->irq_controller.domain,
+ hwirq);
+ if (mapping == 0) {
+ SDE_EVT32(hwirq, SDE_EVTLOG_ERROR);
+ goto error;
+ }
+
+ rc = generic_handle_irq(mapping);
+ if (rc < 0) {
+ SDE_EVT32(hwirq, mapping, rc, SDE_EVTLOG_ERROR);
+ goto error;
+ }
+
interrupts &= ~(1 << hwirq);
}
return IRQ_HANDLED;
+
+error:
+ /* bad situation, inform irq system, it may disable overall MDSS irq */
+ return IRQ_NONE;
}
void sde_irq_preinstall(struct msm_kms *kms)
diff --git a/drivers/gpu/drm/msm/sde/sde_kms.c b/drivers/gpu/drm/msm/sde/sde_kms.c
index 1a6585a..ec8c346 100644
--- a/drivers/gpu/drm/msm/sde/sde_kms.c
+++ b/drivers/gpu/drm/msm/sde/sde_kms.c
@@ -545,7 +545,9 @@
struct msm_drm_private *priv;
struct drm_crtc *crtc;
struct drm_crtc_state *old_crtc_state;
- int i;
+ struct drm_connector *connector;
+ struct drm_connector_state *old_conn_state;
+ int i, rc = 0;
if (!kms || !old_state)
return;
@@ -558,6 +560,19 @@
for_each_crtc_in_state(old_state, crtc, old_crtc_state, i)
sde_crtc_complete_commit(crtc, old_crtc_state);
+ for_each_connector_in_state(old_state, connector, old_conn_state, i) {
+ struct sde_connector *c_conn;
+
+ c_conn = to_sde_connector(connector);
+ if (!c_conn->ops.post_kickoff)
+ continue;
+ rc = c_conn->ops.post_kickoff(connector);
+ if (rc) {
+ pr_err("Connector Post kickoff failed rc=%d\n",
+ rc);
+ }
+ }
+
sde_power_resource_enable(&priv->phandle, sde_kms->core_client, false);
SDE_EVT32_VERBOSE(SDE_EVTLOG_FUNC_EXIT);
@@ -758,6 +773,7 @@
.set_power = dsi_display_set_power,
.get_mode_info = dsi_conn_get_mode_info,
.get_dst_format = dsi_display_get_dst_format,
+ .post_kickoff = dsi_conn_post_kickoff
};
static const struct sde_connector_ops wb_ops = {
.post_init = sde_wb_connector_post_init,
@@ -776,6 +792,7 @@
.mode_valid = dp_connector_mode_valid,
.get_info = dp_connector_get_info,
.get_mode_info = dp_connector_get_mode_info,
+ .send_hpd_event = dp_connector_send_hpd_event,
};
struct msm_display_info info;
struct drm_encoder *encoder;
@@ -1685,6 +1702,8 @@
{
struct drm_device *dev = NULL;
struct sde_kms *sde_kms = NULL;
+ struct drm_connector *connector = NULL;
+ struct sde_connector *sde_conn = NULL;
if (!kms) {
SDE_ERROR("invalid kms\n");
@@ -1699,8 +1718,22 @@
return;
}
- if (dev->mode_config.funcs->output_poll_changed)
- dev->mode_config.funcs->output_poll_changed(dev);
+ if (!dev->mode_config.poll_enabled)
+ return;
+
+ mutex_lock(&dev->mode_config.mutex);
+ drm_for_each_connector(connector, dev) {
+ /* Only handle HPD capable connectors. */
+ if (!(connector->polled & DRM_CONNECTOR_POLL_HPD))
+ continue;
+
+ sde_conn = to_sde_connector(connector);
+
+ if (sde_conn->ops.send_hpd_event)
+ sde_conn->ops.send_hpd_event(sde_conn->display);
+ }
+ mutex_unlock(&dev->mode_config.mutex);
+
}
static int sde_kms_pm_suspend(struct device *dev)
diff --git a/drivers/gpu/drm/msm/sde/sde_plane.c b/drivers/gpu/drm/msm/sde/sde_plane.c
index edd1611..f85f2c6 100644
--- a/drivers/gpu/drm/msm/sde/sde_plane.c
+++ b/drivers/gpu/drm/msm/sde/sde_plane.c
@@ -916,6 +916,22 @@
return;
}
+ /*
+ * framebuffer prepare is deferred for prepare_fb calls that
+ * happen during the transition from secure to non-secure.
+ * Handle the prepare at this point for such cases. This can be
+ * expected for one or two frames during the transition.
+ */
+ if (aspace && pstate->defer_prepare_fb) {
+ ret = msm_framebuffer_prepare(fb, pstate->aspace);
+ if (ret) {
+ SDE_ERROR_PLANE(psde,
+ "failed to prepare framebuffer %d\n", ret);
+ return;
+ }
+ pstate->defer_prepare_fb = false;
+ }
+
ret = sde_format_populate_layout(aspace, fb, &pipe_cfg->layout);
if (ret == -EAGAIN)
SDE_DEBUG_PLANE(psde, "not updating same src addrs\n");
@@ -2117,6 +2133,13 @@
}
}
+ if (new_pstate->defer_prepare_fb) {
+ SDE_DEBUG(
+ "plane%d, domain not attached, prepare fb handled later\n",
+ plane->base.id);
+ return 0;
+ }
+
/* prepare rotator input buffer */
ret = msm_framebuffer_prepare(new_state->fb, new_pstate->aspace);
if (ret) {
@@ -2386,6 +2409,7 @@
struct drm_plane_state *state;
struct sde_plane_state *pstate;
struct sde_plane_rot_state *rstate;
+ int ret = 0;
if (!plane || !plane->state) {
SDE_ERROR("invalid plane/state\n");
@@ -2407,7 +2431,40 @@
if (!rstate->out_sbuf || !rstate->rot_hw)
return;
+ /*
+ * framebuffer prepare is deferred for prepare_fb calls that
+ * happen during the transition from secure to non-secure.
+ * Handle the prepare at this point for rotator in such cases.
+ * This can be expected for one or two frames during the transition.
+ */
+ if (pstate->aspace && pstate->defer_prepare_fb) {
+ /* prepare rotator input buffer */
+ ret = msm_framebuffer_prepare(state->fb, pstate->aspace);
+ if (ret) {
+ SDE_ERROR("p%d failed to prepare input fb %d\n",
+ plane->base.id, ret);
+ return;
+ }
+
+ /* prepare rotator output buffer */
+ if (sde_plane_enabled(state) && rstate->out_fb) {
+ ret = msm_framebuffer_prepare(rstate->out_fb,
+ pstate->aspace);
+ if (ret) {
+ SDE_ERROR(
+ "p%d failed to prepare inline fb %d\n",
+ plane->base.id, ret);
+ goto error_prepare_output_buffer;
+ }
+ }
+ }
+
sde_plane_rot_submit_command(plane, state, SDE_HW_ROT_CMD_COMMIT);
+
+ return;
+
+error_prepare_output_buffer:
+ msm_framebuffer_cleanup(state->fb, pstate->aspace);
}
void sde_plane_kickoff(struct drm_plane *plane)
@@ -2765,29 +2822,33 @@
return ret;
}
- /*cache aspace */
+ /* cache aspace */
pstate->aspace = aspace;
+
+ /*
+ * when transitioning from secure to non-secure,
+ * plane->prepare_fb happens before the commit. In such case,
+ * defer the prepare_fb and handled it late, during the commit
+ * after attaching the domains as part of the transition
+ */
+ pstate->defer_prepare_fb = (aspace && !aspace->domain_attached) ?
+ true : false;
+
ret = sde_plane_rot_prepare_fb(plane, new_state);
if (ret) {
SDE_ERROR("failed to prepare rot framebuffer\n");
return ret;
}
+ if (pstate->defer_prepare_fb) {
+ SDE_DEBUG_PLANE(psde,
+ "domain not attached, prepare_fb handled later\n");
+ return 0;
+ }
+
new_rstate = &to_sde_plane_state(new_state)->rot;
if (pstate->aspace) {
- /*
- * when transitioning from secure to non-secure,
- * plane->prepare_fb happens before the commit. In such case,
- * return early, as prepare_fb would be handled as part
- * of the transition after attaching the domains,
- * during the commit
- */
- if (!pstate->aspace->domain_attached) {
- SDE_DEBUG_PLANE(psde,
- "domain not attached, prepare_fb handled later\n");
- return 0;
- }
ret = msm_framebuffer_prepare(new_rstate->out_fb,
pstate->aspace);
if (ret) {
diff --git a/drivers/gpu/drm/msm/sde/sde_plane.h b/drivers/gpu/drm/msm/sde/sde_plane.h
index c956345..2e8adfe 100644
--- a/drivers/gpu/drm/msm/sde/sde_plane.h
+++ b/drivers/gpu/drm/msm/sde/sde_plane.h
@@ -129,6 +129,7 @@
* @multirect_index: index of the rectangle of SSPP
* @multirect_mode: parallel or time multiplex multirect mode
* @pending: whether the current update is still pending
+ * @defer_prepare_fb: indicate if prepare_fb call was deferred
* @scaler3_cfg: configuration data for scaler3
* @pixel_ext: configuration data for pixel extensions
* @scaler_check_state: indicates status of user provided pixel extension data
@@ -146,6 +147,7 @@
uint32_t multirect_index;
uint32_t multirect_mode;
bool pending;
+ bool defer_prepare_fb;
/* scaler configuration */
struct sde_hw_scaler3_cfg scaler3_cfg;
diff --git a/drivers/gpu/drm/msm/sde/sde_rm.c b/drivers/gpu/drm/msm/sde/sde_rm.c
index be3a8af..ebcf9e0 100644
--- a/drivers/gpu/drm/msm/sde/sde_rm.c
+++ b/drivers/gpu/drm/msm/sde/sde_rm.c
@@ -18,6 +18,7 @@
#include "sde_hw_ctl.h"
#include "sde_hw_cdm.h"
#include "sde_hw_dspp.h"
+#include "sde_hw_ds.h"
#include "sde_hw_pingpong.h"
#include "sde_hw_intf.h"
#include "sde_hw_wb.h"
@@ -32,6 +33,7 @@
#define RM_RQ_LOCK(r) ((r)->top_ctrl & BIT(SDE_RM_TOPCTL_RESERVE_LOCK))
#define RM_RQ_CLEAR(r) ((r)->top_ctrl & BIT(SDE_RM_TOPCTL_RESERVE_CLEAR))
#define RM_RQ_DSPP(r) ((r)->top_ctrl & BIT(SDE_RM_TOPCTL_DSPP))
+#define RM_RQ_DS(r) ((r)->top_ctrl & BIT(SDE_RM_TOPCTL_DS))
#define RM_IS_TOPOLOGY_MATCH(t, r) ((t).num_lm == (r).num_lm && \
(t).num_comp_enc == (r).num_enc && \
(t).num_intf == (r).num_intf)
@@ -234,6 +236,9 @@
case SDE_HW_BLK_DSPP:
sde_hw_dspp_destroy(hw);
break;
+ case SDE_HW_BLK_DS:
+ sde_hw_ds_destroy(hw);
+ break;
case SDE_HW_BLK_CTL:
sde_hw_ctl_destroy(hw);
break;
@@ -304,7 +309,7 @@
static int _sde_rm_hw_blk_create(
struct sde_rm *rm,
struct sde_mdss_cfg *cat,
- void *mmio,
+ void __iomem *mmio,
enum sde_hw_blk_type type,
uint32_t id,
void *hw_catalog_info)
@@ -322,6 +327,9 @@
case SDE_HW_BLK_DSPP:
hw = sde_hw_dspp_init(id, mmio, cat);
break;
+ case SDE_HW_BLK_DS:
+ hw = sde_hw_ds_init(id, mmio, cat);
+ break;
case SDE_HW_BLK_CTL:
hw = sde_hw_ctl_init(id, mmio, cat);
break;
@@ -375,7 +383,7 @@
int sde_rm_init(struct sde_rm *rm,
struct sde_mdss_cfg *cat,
- void *mmio,
+ void __iomem *mmio,
struct drm_device *dev)
{
int rc, i;
@@ -444,6 +452,17 @@
}
}
+ if (cat->mdp[0].has_dest_scaler) {
+ for (i = 0; i < cat->ds_count; i++) {
+ rc = _sde_rm_hw_blk_create(rm, cat, mmio, SDE_HW_BLK_DS,
+ cat->ds[i].id, &cat->ds[i]);
+ if (rc) {
+ SDE_ERROR("failed: ds hw not available\n");
+ goto fail;
+ }
+ }
+ }
+
for (i = 0; i < cat->pingpong_count; i++) {
rc = _sde_rm_hw_blk_create(rm, cat, mmio, SDE_HW_BLK_PINGPONG,
cat->pingpong[i].id, &cat->pingpong[i]);
@@ -543,18 +562,22 @@
struct sde_rm_requirements *reqs,
struct sde_rm_hw_blk *lm,
struct sde_rm_hw_blk **dspp,
+ struct sde_rm_hw_blk **ds,
struct sde_rm_hw_blk **pp,
struct sde_rm_hw_blk *primary_lm)
{
const struct sde_lm_cfg *lm_cfg = to_sde_hw_mixer(lm->hw)->cap;
const struct sde_pingpong_cfg *pp_cfg;
struct sde_rm_hw_iter iter;
+ bool is_valid_dspp, is_valid_ds, ret;
*dspp = NULL;
+ *ds = NULL;
*pp = NULL;
- SDE_DEBUG("check lm %d: dspp %d pp %d\n", lm_cfg->id, lm_cfg->dspp,
- lm_cfg->pingpong);
+ SDE_DEBUG("check lm %d: dspp %d ds %d pp %d\n",
+ lm_cfg->id, lm_cfg->dspp,
+ lm_cfg->ds, lm_cfg->pingpong);
/* Check if this layer mixer is a peer of the proposed primary LM */
if (primary_lm) {
@@ -568,13 +591,28 @@
}
}
- /* Matches user requirements? */
- if ((RM_RQ_DSPP(reqs) && lm_cfg->dspp == DSPP_MAX) ||
- (!RM_RQ_DSPP(reqs) && lm_cfg->dspp != DSPP_MAX)) {
- SDE_DEBUG("dspp req mismatch lm %d reqdspp %d, lm->dspp %d\n",
- lm_cfg->id, (bool)(RM_RQ_DSPP(reqs)),
- lm_cfg->dspp);
- return false;
+ is_valid_dspp = (lm_cfg->dspp != DSPP_MAX) ? true : false;
+ is_valid_ds = (lm_cfg->ds != DS_MAX) ? true : false;
+
+ /**
+ * RM_RQ_X: specification of which LMs to choose
+ * is_valid_X: indicates whether LM is tied with block X
+ * ret: true if given LM matches the user requirement, false otherwise
+ */
+ if (RM_RQ_DSPP(reqs) && RM_RQ_DS(reqs))
+ ret = (is_valid_dspp && is_valid_ds);
+ else if (RM_RQ_DSPP(reqs))
+ ret = is_valid_dspp;
+ else if (RM_RQ_DS(reqs))
+ ret = is_valid_ds;
+ else
+ ret = !(is_valid_dspp || is_valid_ds);
+
+ if (!ret) {
+ SDE_DEBUG("fail:lm(%d)req_dspp(%d)dspp(%d)req_ds(%d)ds(%d)\n",
+ lm_cfg->id, (bool)(RM_RQ_DSPP(reqs)), lm_cfg->dspp,
+ (bool)(RM_RQ_DS(reqs)), lm_cfg->ds);
+ return ret;
}
/* Already reserved? */
@@ -605,6 +643,28 @@
}
}
+ if (lm_cfg->ds != DS_MAX) {
+ sde_rm_init_hw_iter(&iter, 0, SDE_HW_BLK_DS);
+ while (_sde_rm_get_hw_locked(rm, &iter)) {
+ if (iter.blk->id == lm_cfg->ds) {
+ *ds = iter.blk;
+ break;
+ }
+ }
+
+ if (!*ds) {
+ SDE_DEBUG("lm %d failed to retrieve ds %d\n", lm->id,
+ lm_cfg->ds);
+ return false;
+ }
+
+ if (RESERVED_BY_OTHER(*ds, rsvp)) {
+ SDE_DEBUG("lm %d ds %d already reserved\n",
+ lm->id, (*ds)->id);
+ return false;
+ }
+ }
+
sde_rm_init_hw_iter(&iter, 0, SDE_HW_BLK_PINGPONG);
while (_sde_rm_get_hw_locked(rm, &iter)) {
if (iter.blk->id == lm_cfg->pingpong) {
@@ -622,6 +682,7 @@
SDE_DEBUG("lm %d pp %d already reserved\n", lm->id,
(*pp)->id);
*dspp = NULL;
+ *ds = NULL;
return false;
}
@@ -630,6 +691,7 @@
!(test_bit(SDE_PINGPONG_SPLIT, &pp_cfg->features))) {
SDE_DEBUG("pp %d doesn't support ppsplit\n", pp_cfg->id);
*dspp = NULL;
+ *ds = NULL;
return false;
}
@@ -644,6 +706,7 @@
{
struct sde_rm_hw_blk *lm[MAX_BLOCKS];
struct sde_rm_hw_blk *dspp[MAX_BLOCKS];
+ struct sde_rm_hw_blk *ds[MAX_BLOCKS];
struct sde_rm_hw_blk *pp[MAX_BLOCKS];
struct sde_rm_hw_iter iter_i, iter_j;
int lm_count = 0;
@@ -660,14 +723,16 @@
_sde_rm_get_hw_locked(rm, &iter_i)) {
memset(&lm, 0, sizeof(lm));
memset(&dspp, 0, sizeof(dspp));
+ memset(&ds, 0, sizeof(ds));
memset(&pp, 0, sizeof(pp));
lm_count = 0;
lm[lm_count] = iter_i.blk;
- if (!_sde_rm_check_lm_and_get_connected_blks(rm, rsvp, reqs,
- lm[lm_count], &dspp[lm_count], &pp[lm_count],
- NULL))
+ if (!_sde_rm_check_lm_and_get_connected_blks(
+ rm, rsvp, reqs, lm[lm_count],
+ &dspp[lm_count], &ds[lm_count],
+ &pp[lm_count], NULL))
continue;
++lm_count;
@@ -680,8 +745,9 @@
if (iter_i.blk == iter_j.blk)
continue;
- if (!_sde_rm_check_lm_and_get_connected_blks(rm, rsvp,
- reqs, iter_j.blk, &dspp[lm_count],
+ if (!_sde_rm_check_lm_and_get_connected_blks(
+ rm, rsvp, reqs, iter_j.blk,
+ &dspp[lm_count], &ds[lm_count],
&pp[lm_count], iter_i.blk))
continue;
@@ -704,8 +770,12 @@
if (dspp[i])
dspp[i]->rsvp_nxt = rsvp;
+ if (ds[i])
+ ds[i]->rsvp_nxt = rsvp;
+
SDE_EVT32(lm[i]->type, rsvp->enc_id, lm[i]->id, pp[i]->id,
- dspp[i] ? dspp[i]->id : 0);
+ dspp[i] ? dspp[i]->id : 0,
+ ds[i] ? ds[i]->id : 0);
}
if (reqs->topology->top_name == SDE_RM_TOPOLOGY_PPSPLIT) {
@@ -1018,6 +1088,15 @@
if (reqs->topology->num_comp_enc)
reqs->top_ctrl |= BIT(SDE_RM_TOPCTL_DSPP);
+ /**
+ * Set the requirement based on caps if not set from user space
+ * This will ensure to select LM tied with DS blocks
+ * Currently, DS blocks are tied with LM 0 and LM 1 (primary display)
+ */
+ if (!RM_RQ_DS(reqs) && rm->hw_mdp->caps->has_dest_scaler &&
+ conn_state->connector->connector_type == DRM_MODE_CONNECTOR_DSI)
+ reqs->top_ctrl |= BIT(SDE_RM_TOPCTL_DS);
+
SDE_DEBUG("top_ctrl: 0x%llX num_h_tiles: %d\n", reqs->top_ctrl,
reqs->hw_res.display_num_of_h_tiles);
SDE_DEBUG("num_lm: %d num_ctl: %d topology: %d split_display: %d\n",
diff --git a/drivers/gpu/drm/msm/sde/sde_rm.h b/drivers/gpu/drm/msm/sde/sde_rm.h
index b4a801a..1e48855 100644
--- a/drivers/gpu/drm/msm/sde/sde_rm.h
+++ b/drivers/gpu/drm/msm/sde/sde_rm.h
@@ -56,11 +56,13 @@
* Normal behavior would not impact the
* reservation list during the AtomicTest phase.
* @SDE_RM_TOPCTL_DSPP: Require layer mixers with DSPP capabilities
+ * @SDE_RM_TOPCTL_DS : Require layer mixers with DS capabilities
*/
enum sde_rm_topology_control {
SDE_RM_TOPCTL_RESERVE_LOCK,
SDE_RM_TOPCTL_RESERVE_CLEAR,
SDE_RM_TOPCTL_DSPP,
+ SDE_RM_TOPCTL_DS,
};
/**
diff --git a/drivers/gpu/drm/msm/sde_dbg.c b/drivers/gpu/drm/msm/sde_dbg.c
index 7143a8b..b8fbcf7 100644
--- a/drivers/gpu/drm/msm/sde_dbg.c
+++ b/drivers/gpu/drm/msm/sde_dbg.c
@@ -44,6 +44,7 @@
/* offsets from sde top address for the debug buses */
#define DBGBUS_SSPP0 0x188
+#define DBGBUS_AXI_INTF 0x194
#define DBGBUS_SSPP1 0x298
#define DBGBUS_DSPP 0x348
#define DBGBUS_PERIPH 0x418
@@ -66,6 +67,7 @@
/* print debug ranges in groups of 4 u32s */
#define REG_DUMP_ALIGN 16
+#define RSC_DEBUG_MUX_SEL_SDM845 9
/**
* struct sde_dbg_reg_offset - tracking for start and end of region
* @start: start offset
@@ -128,7 +130,8 @@
u32 wr_addr;
u32 block_id;
u32 test_id;
- void (*analyzer)(struct sde_debug_bus_entry *entry, u32 val);
+ void (*analyzer)(void __iomem *mem_base,
+ struct sde_debug_bus_entry *entry, u32 val);
};
struct vbif_debug_bus_entry {
@@ -174,6 +177,7 @@
* @dbgbus_sde: debug bus structure for the sde
* @dbgbus_vbif_rt: debug bus structure for the realtime vbif
* @dump_all: dump all entries in register dump
+ * @dsi_dbg_bus: dump dsi debug bus register
*/
static struct sde_dbg_base {
struct sde_dbg_evtlog *evtlog;
@@ -191,20 +195,21 @@
struct sde_dbg_sde_debug_bus dbgbus_sde;
struct sde_dbg_vbif_debug_bus dbgbus_vbif_rt;
bool dump_all;
+ bool dsi_dbg_bus;
} sde_dbg_base;
/* sde_dbg_base_evtlog - global pointer to main sde event log for macro use */
struct sde_dbg_evtlog *sde_dbg_base_evtlog;
-static void _sde_debug_bus_xbar_dump(struct sde_debug_bus_entry *entry,
- u32 val)
+static void _sde_debug_bus_xbar_dump(void __iomem *mem_base,
+ struct sde_debug_bus_entry *entry, u32 val)
{
dev_err(sde_dbg_base.dev, "xbar 0x%x %d %d 0x%x\n",
entry->wr_addr, entry->block_id, entry->test_id, val);
}
-static void _sde_debug_bus_lm_dump(struct sde_debug_bus_entry *entry,
- u32 val)
+static void _sde_debug_bus_lm_dump(void __iomem *mem_base,
+ struct sde_debug_bus_entry *entry, u32 val)
{
if (!(val & 0xFFF000))
return;
@@ -213,8 +218,8 @@
entry->wr_addr, entry->block_id, entry->test_id, val);
}
-static void _sde_debug_bus_ppb0_dump(struct sde_debug_bus_entry *entry,
- u32 val)
+static void _sde_debug_bus_ppb0_dump(void __iomem *mem_base,
+ struct sde_debug_bus_entry *entry, u32 val)
{
if (!(val & BIT(15)))
return;
@@ -223,8 +228,8 @@
entry->wr_addr, entry->block_id, entry->test_id, val);
}
-static void _sde_debug_bus_ppb1_dump(struct sde_debug_bus_entry *entry,
- u32 val)
+static void _sde_debug_bus_ppb1_dump(void __iomem *mem_base,
+ struct sde_debug_bus_entry *entry, u32 val)
{
if (!(val & BIT(15)))
return;
@@ -233,6 +238,29 @@
entry->wr_addr, entry->block_id, entry->test_id, val);
}
+static void _sde_debug_bus_axi_dump_sdm845(void __iomem *mem_base,
+ struct sde_debug_bus_entry *entry, u32 val)
+{
+ u32 status, i;
+
+ if (!mem_base || !entry)
+ return;
+
+ for (i = 0; i <= RSC_DEBUG_MUX_SEL_SDM845; i++) {
+ sde_rsc_debug_dump(i);
+
+ /* make sure that mux_sel updated */
+ wmb();
+
+ /* read status again after rsc routes the debug bus */
+ status = readl_relaxed(mem_base + DBGBUS_DSPP_STATUS);
+
+ dev_err(sde_dbg_base.dev, "rsc mux_sel:%d 0x%x %d %d 0x%x\n",
+ i, entry->wr_addr, entry->block_id,
+ entry->test_id, status);
+ }
+}
+
static struct sde_debug_bus_entry dbg_bus_sde_8998[] = {
/* Unpack 0 sspp 0*/
@@ -1986,6 +2014,9 @@
{ DBGBUS_PERIPH, 71, 3},
{ DBGBUS_PERIPH, 71, 4},
{ DBGBUS_PERIPH, 71, 5},
+
+ /* axi - should be last entry */
+ { DBGBUS_AXI_INTF, 62, 0, _sde_debug_bus_axi_dump_sdm845},
};
static struct vbif_debug_bus_entry vbif_dbg_bus_msm8998[] = {
@@ -2332,7 +2363,7 @@
}
if (head->analyzer)
- head->analyzer(head, status);
+ head->analyzer(mem_base, head, status);
/* Disable debug bus once we are done */
writel_relaxed(0, mem_base + head->wr_addr);
@@ -2541,6 +2572,9 @@
if (dump_dbgbus_vbif_rt)
_sde_dbg_dump_vbif_dbg_bus(&sde_dbg_base.dbgbus_vbif_rt);
+ if (sde_dbg_base.dsi_dbg_bus || dump_all)
+ dsi_ctrl_debug_dump();
+
if (do_panic && sde_dbg_base.panic_on_err)
panic(name);
}
@@ -2615,6 +2649,9 @@
if (!strcmp(blk_name, "vbif_dbg_bus"))
dump_dbgbus_vbif_rt = true;
+ if (!strcmp(blk_name, "dsi_dbg_bus"))
+ sde_dbg_base.dsi_dbg_bus = true;
+
if (!strcmp(blk_name, "panic"))
do_panic = true;
}
diff --git a/drivers/gpu/drm/msm/sde_dbg.h b/drivers/gpu/drm/msm/sde_dbg.h
index a266574..786451c3 100644
--- a/drivers/gpu/drm/msm/sde_dbg.h
+++ b/drivers/gpu/drm/msm/sde_dbg.h
@@ -315,6 +315,17 @@
int sde_evtlog_get_filter(struct sde_dbg_evtlog *evtlog, int index,
char *buf, size_t bufsz);
+/**
+ * sde_rsc_debug_dump - sde rsc debug dump status
+ * @mux_sel: select mux on rsc debug bus
+ */
+void sde_rsc_debug_dump(u32 mux_sel);
+
+/**
+ * dsi_ctrl_debug_dump - dump dsi debug dump status
+ */
+void dsi_ctrl_debug_dump(void);
+
#else
static inline struct sde_dbg_evtlog *sde_evtlog_init(void)
{
@@ -396,6 +407,14 @@
return -EINVAL;
}
+static inline void sde_rsc_debug_dump(u32 mux_sel)
+{
+}
+
+static inline void dsi_ctrl_debug_dump(void)
+{
+}
+
#endif /* defined(CONFIG_DEBUG_FS) */
diff --git a/drivers/gpu/drm/msm/sde_edid_parser.c b/drivers/gpu/drm/msm/sde_edid_parser.c
index 3d6c2ea..791a6ca 100644
--- a/drivers/gpu/drm/msm/sde_edid_parser.c
+++ b/drivers/gpu/drm/msm/sde_edid_parser.c
@@ -605,6 +605,30 @@
}
}
+u8 sde_get_edid_checksum(void *input)
+{
+ struct sde_edid_ctrl *edid_ctrl = (struct sde_edid_ctrl *)(input);
+ struct edid *edid = NULL, *last_block = NULL;
+ u8 *raw_edid = NULL;
+
+ if (!edid_ctrl || !edid_ctrl->edid) {
+ SDE_ERROR("invalid edid input\n");
+ return 0;
+ }
+
+ edid = edid_ctrl->edid;
+
+ raw_edid = (u8 *)edid;
+ raw_edid += (edid->extensions * EDID_LENGTH);
+ last_block = (struct edid *)raw_edid;
+
+ if (last_block)
+ return last_block->checksum;
+
+ SDE_ERROR("Invalid block, no checksum\n");
+ return 0;
+}
+
bool sde_detect_hdmi_monitor(void *input)
{
struct sde_edid_ctrl *edid_ctrl = (struct sde_edid_ctrl *)(input);
diff --git a/drivers/gpu/drm/msm/sde_edid_parser.h b/drivers/gpu/drm/msm/sde_edid_parser.h
index b58b322..07bdf50 100644
--- a/drivers/gpu/drm/msm/sde_edid_parser.h
+++ b/drivers/gpu/drm/msm/sde_edid_parser.h
@@ -146,6 +146,14 @@
u32 sde_get_sink_bpc(void *edid_ctrl);
/**
+ * sde_get_edid_checksum() - return the checksum of last block of EDID.
+ * @input: Handle to the edid_ctrl structure.
+ *
+ * Return: checksum of the last EDID block.
+ */
+u8 sde_get_edid_checksum(void *input);
+
+/**
* _sde_edid_update_modes() - populate EDID modes.
* @edid_ctrl: Handle to the edid_ctrl structure.
*
diff --git a/drivers/gpu/drm/msm/sde_rsc.c b/drivers/gpu/drm/msm/sde_rsc.c
index b654b26..82b1199 100644
--- a/drivers/gpu/drm/msm/sde_rsc.c
+++ b/drivers/gpu/drm/msm/sde_rsc.c
@@ -456,7 +456,7 @@
} else if (rsc->hw_ops.state_update) {
rc = rsc->hw_ops.state_update(rsc, SDE_RSC_IDLE_STATE);
if (!rc)
- rpmh_mode_solver_set(rsc->disp_rsc, false);
+ rpmh_mode_solver_set(rsc->disp_rsc, true);
}
return rc;
@@ -837,6 +837,21 @@
}
EXPORT_SYMBOL(sde_rsc_client_vote);
+#if defined(CONFIG_DEBUG_FS)
+void sde_rsc_debug_dump(u32 mux_sel)
+{
+ struct sde_rsc_priv *rsc;
+
+ rsc = rsc_prv_list[SDE_RSC_INDEX];
+ if (!rsc)
+ return;
+
+ /* this must be called with rsc clocks enabled */
+ if (rsc->hw_ops.debug_dump)
+ rsc->hw_ops.debug_dump(rsc, mux_sel);
+}
+#endif /* defined(CONFIG_DEBUG_FS) */
+
static int _sde_debugfs_status_show(struct seq_file *s, void *data)
{
struct sde_rsc_priv *rsc;
diff --git a/drivers/gpu/drm/msm/sde_rsc_hw.c b/drivers/gpu/drm/msm/sde_rsc_hw.c
index b474d21..e957779 100644
--- a/drivers/gpu/drm/msm/sde_rsc_hw.c
+++ b/drivers/gpu/drm/msm/sde_rsc_hw.c
@@ -515,7 +515,7 @@
reg = dss_reg_r(&rsc->wrapper_io,
SDE_RSCC_WRAPPER_OVERRIDE_CTRL, rsc->debug_mode);
reg |= (BIT(0) | BIT(8));
- reg &= ~(BIT(1) | BIT(2) | BIT(3) | BIT(6) | BIT(7));
+ reg &= ~(BIT(1) | BIT(2) | BIT(3) | BIT(6) | BIT(7) | BIT(9));
dss_reg_w(&rsc->wrapper_io, SDE_RSCC_WRAPPER_OVERRIDE_CTRL,
reg, rsc->debug_mode);
/* make sure that solver is enabled */
@@ -746,6 +746,12 @@
return blen;
}
+static void rsc_hw_debug_dump(struct sde_rsc_priv *rsc, u32 mux_sel)
+{
+ dss_reg_w(&rsc->wrapper_io, SDE_RSCC_WRAPPER_DEBUG_BUS,
+ ((mux_sel & 0xf) << 1) | BIT(0), rsc->debug_mode);
+}
+
bool rsc_hw_is_amc_mode(struct sde_rsc_priv *rsc)
{
return dss_reg_r(&rsc->drv_io, SDE_RSCC_TCS_DRV0_CONTROL,
@@ -806,6 +812,7 @@
rsc->hw_ops.state_update = sde_rsc_state_update;
rsc->hw_ops.debug_show = sde_rsc_debug_show;
rsc->hw_ops.mode_ctrl = rsc_hw_mode_ctrl;
+ rsc->hw_ops.debug_dump = rsc_hw_debug_dump;
return 0;
}
diff --git a/drivers/gpu/drm/msm/sde_rsc_priv.h b/drivers/gpu/drm/msm/sde_rsc_priv.h
index c96ce75..64b0216 100644
--- a/drivers/gpu/drm/msm/sde_rsc_priv.h
+++ b/drivers/gpu/drm/msm/sde_rsc_priv.h
@@ -73,6 +73,7 @@
* @hw_vsync: Enables the vsync on RSC block.
* @tcs_use_ok: set TCS set to high to allow RSC to use it.
* @is_amc_mode: Check current amc mode status
+ * @debug_dump: dump debug bus registers or enable debug bus
* @state_update: Enable/override the solver based on rsc state
* status (command/video)
* @mode_show: shows current mode status, mode0/1/2
@@ -87,6 +88,7 @@
char *buffer, int buffer_size, u32 mode);
int (*tcs_use_ok)(struct sde_rsc_priv *rsc);
bool (*is_amc_mode)(struct sde_rsc_priv *rsc);
+ void (*debug_dump)(struct sde_rsc_priv *rsc, u32 mux_sel);
int (*state_update)(struct sde_rsc_priv *rsc, enum sde_rsc_state state);
int (*debug_show)(struct seq_file *s, struct sde_rsc_priv *rsc);
int (*mode_ctrl)(struct sde_rsc_priv *rsc, enum rsc_mode_req request,
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/pci/base.c b/drivers/gpu/drm/nouveau/nvkm/subdev/pci/base.c
index eb9b278..a4cb824 100644
--- a/drivers/gpu/drm/nouveau/nvkm/subdev/pci/base.c
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/pci/base.c
@@ -192,6 +192,10 @@
}
}
+#ifdef __BIG_ENDIAN
+ pci->msi = false;
+#endif
+
pci->msi = nvkm_boolopt(device->cfgopt, "NvMSI", pci->msi);
if (pci->msi && func->msi_rearm) {
pci->msi = pci_enable_msi(pci->pdev) == 0;
diff --git a/drivers/gpu/msm/a6xx_reg.h b/drivers/gpu/msm/a6xx_reg.h
index e112fd1..c2eb9ea 100644
--- a/drivers/gpu/msm/a6xx_reg.h
+++ b/drivers/gpu/msm/a6xx_reg.h
@@ -764,6 +764,29 @@
#define A6XX_VBIF_PERF_PWR_CNT_HIGH1 0x3119
#define A6XX_VBIF_PERF_PWR_CNT_HIGH2 0x311a
+/* GBIF registers */
+#define A6XX_GBIF_HALT 0x3c45
+#define A6XX_GBIF_HALT_ACK 0x3c46
+#define A6XX_GBIF_HALT_MASK 0x1
+
+#define A6XX_GBIF_PERF_PWR_CNT_EN 0x3cc0
+#define A6XX_GBIF_PERF_CNT_SEL 0x3cc2
+#define A6XX_GBIF_PERF_CNT_LOW0 0x3cc4
+#define A6XX_GBIF_PERF_CNT_LOW1 0x3cc5
+#define A6XX_GBIF_PERF_CNT_LOW2 0x3cc6
+#define A6XX_GBIF_PERF_CNT_LOW3 0x3cc7
+#define A6XX_GBIF_PERF_CNT_HIGH0 0x3cc8
+#define A6XX_GBIF_PERF_CNT_HIGH1 0x3cc9
+#define A6XX_GBIF_PERF_CNT_HIGH2 0x3cca
+#define A6XX_GBIF_PERF_CNT_HIGH3 0x3ccb
+#define A6XX_GBIF_PWR_CNT_LOW0 0x3ccc
+#define A6XX_GBIF_PWR_CNT_LOW1 0x3ccd
+#define A6XX_GBIF_PWR_CNT_LOW2 0x3cce
+#define A6XX_GBIF_PWR_CNT_HIGH0 0x3ccf
+#define A6XX_GBIF_PWR_CNT_HIGH1 0x3cd0
+#define A6XX_GBIF_PWR_CNT_HIGH2 0x3cd1
+
+
/* CX_DBGC_CFG registers */
#define A6XX_CX_DBGC_CFG_DBGBUS_SEL_A 0x18400
#define A6XX_CX_DBGC_CFG_DBGBUS_SEL_B 0x18401
@@ -935,6 +958,7 @@
#define A6XX_GMU_AO_SPARE_CNTL 0x23B16
/* GMU RSC control registers */
+#define A6XX_GPU_RSCC_RSC_STATUS0_DRV0 0x23404
#define A6XX_GMU_RSCC_CONTROL_REQ 0x23B07
#define A6XX_GMU_RSCC_CONTROL_ACK 0x23B08
diff --git a/drivers/gpu/msm/adreno.c b/drivers/gpu/msm/adreno.c
index 506f6ad..7943745 100644
--- a/drivers/gpu/msm/adreno.c
+++ b/drivers/gpu/msm/adreno.c
@@ -2870,7 +2870,7 @@
gpu_busy += adj;
}
- if (kgsl_gmu_isenabled(device)) {
+ if (adreno_is_a6xx(adreno_dev)) {
/* clock sourced from XO */
stats->busy_time = gpu_busy * 10 / 192;
} else {
diff --git a/drivers/gpu/msm/adreno.h b/drivers/gpu/msm/adreno.h
index d7d2cf9..342a85a 100644
--- a/drivers/gpu/msm/adreno.h
+++ b/drivers/gpu/msm/adreno.h
@@ -621,6 +621,8 @@
ADRENO_REG_RBBM_RBBM_CTL,
ADRENO_REG_UCHE_INVALIDATE0,
ADRENO_REG_UCHE_INVALIDATE1,
+ ADRENO_REG_RBBM_PERFCTR_RBBM_0_LO,
+ ADRENO_REG_RBBM_PERFCTR_RBBM_0_HI,
ADRENO_REG_RBBM_PERFCTR_LOAD_VALUE_LO,
ADRENO_REG_RBBM_PERFCTR_LOAD_VALUE_HI,
ADRENO_REG_RBBM_SECVID_TRUST_CONTROL,
@@ -634,6 +636,8 @@
ADRENO_REG_VBIF_XIN_HALT_CTRL0,
ADRENO_REG_VBIF_XIN_HALT_CTRL1,
ADRENO_REG_VBIF_VERSION,
+ ADRENO_REG_GBIF_HALT,
+ ADRENO_REG_GBIF_HALT_ACK,
ADRENO_REG_GMU_AO_INTERRUPT_EN,
ADRENO_REG_GMU_AO_HOST_INTERRUPT_CLR,
ADRENO_REG_GMU_AO_HOST_INTERRUPT_STATUS,
@@ -1170,6 +1174,12 @@
(ADRENO_CHIPID_PATCH(adreno_dev->chipid) == 0);
}
+static inline int adreno_is_a630v2(struct adreno_device *adreno_dev)
+{
+ return (ADRENO_GPUREV(adreno_dev) == ADRENO_REV_A630) &&
+ (ADRENO_CHIPID_PATCH(adreno_dev->chipid) == 1);
+}
+
/*
* adreno_checkreg_off() - Checks the validity of a register enum
* @adreno_dev: Pointer to adreno device
@@ -1701,21 +1711,60 @@
spin_unlock_irqrestore(&rb->preempt_lock, flags);
}
+static inline bool is_power_counter_overflow(struct adreno_device *adreno_dev,
+ unsigned int reg, unsigned int prev_val, unsigned int *perfctr_pwr_hi)
+{
+ unsigned int val;
+ bool ret = false;
+
+ /*
+ * If prev_val is zero, it is first read after perf counter reset.
+ * So set perfctr_pwr_hi register to zero.
+ */
+ if (prev_val == 0) {
+ *perfctr_pwr_hi = 0;
+ return ret;
+ }
+ adreno_readreg(adreno_dev, ADRENO_REG_RBBM_PERFCTR_RBBM_0_HI, &val);
+ if (val != *perfctr_pwr_hi) {
+ *perfctr_pwr_hi = val;
+ ret = true;
+ }
+ return ret;
+}
+
static inline unsigned int counter_delta(struct kgsl_device *device,
unsigned int reg, unsigned int *counter)
{
+ struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
unsigned int val;
unsigned int ret = 0;
+ bool overflow = true;
+ static unsigned int perfctr_pwr_hi;
/* Read the value */
kgsl_regread(device, reg, &val);
+ if (adreno_is_a5xx(adreno_dev) && reg == adreno_getreg
+ (adreno_dev, ADRENO_REG_RBBM_PERFCTR_RBBM_0_LO))
+ overflow = is_power_counter_overflow(adreno_dev, reg,
+ *counter, &perfctr_pwr_hi);
+
/* Return 0 for the first read */
if (*counter != 0) {
- if (val < *counter)
- ret = (0xFFFFFFFF - *counter) + val;
- else
+ if (val >= *counter) {
ret = val - *counter;
+ } else if (overflow == true) {
+ ret = (0xFFFFFFFF - *counter) + val;
+ } else {
+ /*
+ * Since KGSL got abnormal value from the counter,
+ * We will drop the value from being accumulated.
+ */
+ pr_warn_once("KGSL: Abnormal value :0x%x (0x%x) from perf counter : 0x%x\n",
+ val, *counter, reg);
+ return 0;
+ }
}
*counter = val;
@@ -1754,6 +1803,47 @@
kgsl_active_count_put(KGSL_DEVICE(adreno_dev));
}
+static inline bool adreno_has_gbif(struct adreno_device *adreno_dev)
+{
+ if (adreno_is_a615(adreno_dev))
+ return true;
+ else
+ return false;
+}
+
+/**
+ * adreno_wait_for_vbif_halt_ack() - wait for VBIF acknowledgment
+ * for given HALT request.
+ * @ack_reg: register offset to wait for acknowledge
+ */
+static inline int adreno_wait_for_vbif_halt_ack(struct kgsl_device *device,
+ int ack_reg)
+{
+ struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
+ struct adreno_gpudev *gpudev = ADRENO_GPU_DEVICE(adreno_dev);
+ unsigned long wait_for_vbif;
+ unsigned int mask = gpudev->vbif_xin_halt_ctrl0_mask;
+ unsigned int val;
+ int ret = 0;
+
+ /* wait for the transactions to clear */
+ wait_for_vbif = jiffies + msecs_to_jiffies(100);
+ while (1) {
+ adreno_readreg(adreno_dev, ack_reg,
+ &val);
+ if ((val & mask) == mask)
+ break;
+ if (time_after(jiffies, wait_for_vbif)) {
+ KGSL_DRV_ERR(device,
+ "Wait limit reached for VBIF XIN Halt\n");
+ ret = -ETIMEDOUT;
+ break;
+ }
+ }
+
+ return ret;
+}
+
/**
* adreno_vbif_clear_pending_transactions() - Clear transactions in VBIF pipe
* @device: Pointer to the device whose VBIF pipe is to be cleared
@@ -1764,26 +1854,20 @@
struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
struct adreno_gpudev *gpudev = ADRENO_GPU_DEVICE(adreno_dev);
unsigned int mask = gpudev->vbif_xin_halt_ctrl0_mask;
- unsigned int val;
- unsigned long wait_for_vbif;
int ret = 0;
- adreno_writereg(adreno_dev, ADRENO_REG_VBIF_XIN_HALT_CTRL0, mask);
- /* wait for the transactions to clear */
- wait_for_vbif = jiffies + msecs_to_jiffies(100);
- while (1) {
- adreno_readreg(adreno_dev,
- ADRENO_REG_VBIF_XIN_HALT_CTRL1, &val);
- if ((val & mask) == mask)
- break;
- if (time_after(jiffies, wait_for_vbif)) {
- KGSL_DRV_ERR(device,
- "Wait limit reached for VBIF XIN Halt\n");
- ret = -ETIMEDOUT;
- break;
- }
+ if (adreno_has_gbif(adreno_dev)) {
+ adreno_writereg(adreno_dev, ADRENO_REG_GBIF_HALT, mask);
+ ret = adreno_wait_for_vbif_halt_ack(device,
+ ADRENO_REG_GBIF_HALT_ACK);
+ adreno_writereg(adreno_dev, ADRENO_REG_GBIF_HALT, 0);
+ } else {
+ adreno_writereg(adreno_dev, ADRENO_REG_VBIF_XIN_HALT_CTRL0,
+ mask);
+ ret = adreno_wait_for_vbif_halt_ack(device,
+ ADRENO_REG_VBIF_XIN_HALT_CTRL1);
+ adreno_writereg(adreno_dev, ADRENO_REG_VBIF_XIN_HALT_CTRL0, 0);
}
- adreno_writereg(adreno_dev, ADRENO_REG_VBIF_XIN_HALT_CTRL0, 0);
return ret;
}
diff --git a/drivers/gpu/msm/adreno_a3xx.c b/drivers/gpu/msm/adreno_a3xx.c
index 356d7c2..b2cdf56 100644
--- a/drivers/gpu/msm/adreno_a3xx.c
+++ b/drivers/gpu/msm/adreno_a3xx.c
@@ -1533,6 +1533,10 @@
A3XX_UCHE_CACHE_INVALIDATE0_REG),
ADRENO_REG_DEFINE(ADRENO_REG_UCHE_INVALIDATE1,
A3XX_UCHE_CACHE_INVALIDATE1_REG),
+ ADRENO_REG_DEFINE(ADRENO_REG_RBBM_PERFCTR_RBBM_0_LO,
+ A3XX_RBBM_PERFCTR_RBBM_0_LO),
+ ADRENO_REG_DEFINE(ADRENO_REG_RBBM_PERFCTR_RBBM_0_HI,
+ A3XX_RBBM_PERFCTR_RBBM_0_HI),
ADRENO_REG_DEFINE(ADRENO_REG_RBBM_PERFCTR_LOAD_VALUE_LO,
A3XX_RBBM_PERFCTR_LOAD_VALUE_LO),
ADRENO_REG_DEFINE(ADRENO_REG_RBBM_PERFCTR_LOAD_VALUE_HI,
diff --git a/drivers/gpu/msm/adreno_a4xx.c b/drivers/gpu/msm/adreno_a4xx.c
index 0cf909e..80ceabd 100644
--- a/drivers/gpu/msm/adreno_a4xx.c
+++ b/drivers/gpu/msm/adreno_a4xx.c
@@ -808,6 +808,10 @@
ADRENO_REG_DEFINE(ADRENO_REG_RBBM_SW_RESET_CMD, A4XX_RBBM_SW_RESET_CMD),
ADRENO_REG_DEFINE(ADRENO_REG_UCHE_INVALIDATE0, A4XX_UCHE_INVALIDATE0),
ADRENO_REG_DEFINE(ADRENO_REG_UCHE_INVALIDATE1, A4XX_UCHE_INVALIDATE1),
+ ADRENO_REG_DEFINE(ADRENO_REG_RBBM_PERFCTR_RBBM_0_LO,
+ A4XX_RBBM_PERFCTR_RBBM_0_LO),
+ ADRENO_REG_DEFINE(ADRENO_REG_RBBM_PERFCTR_RBBM_0_HI,
+ A4XX_RBBM_PERFCTR_RBBM_0_HI),
ADRENO_REG_DEFINE(ADRENO_REG_RBBM_PERFCTR_LOAD_VALUE_LO,
A4XX_RBBM_PERFCTR_LOAD_VALUE_LO),
ADRENO_REG_DEFINE(ADRENO_REG_RBBM_PERFCTR_LOAD_VALUE_HI,
diff --git a/drivers/gpu/msm/adreno_a5xx.c b/drivers/gpu/msm/adreno_a5xx.c
index 6cddd08..2d078ba 100644
--- a/drivers/gpu/msm/adreno_a5xx.c
+++ b/drivers/gpu/msm/adreno_a5xx.c
@@ -2998,6 +2998,10 @@
ADRENO_REG_DEFINE(ADRENO_REG_RBBM_BLOCK_SW_RESET_CMD2,
A5XX_RBBM_BLOCK_SW_RESET_CMD2),
ADRENO_REG_DEFINE(ADRENO_REG_UCHE_INVALIDATE0, A5XX_UCHE_INVALIDATE0),
+ ADRENO_REG_DEFINE(ADRENO_REG_RBBM_PERFCTR_RBBM_0_LO,
+ A5XX_RBBM_PERFCTR_RBBM_0_LO),
+ ADRENO_REG_DEFINE(ADRENO_REG_RBBM_PERFCTR_RBBM_0_HI,
+ A5XX_RBBM_PERFCTR_RBBM_0_HI),
ADRENO_REG_DEFINE(ADRENO_REG_RBBM_PERFCTR_LOAD_VALUE_LO,
A5XX_RBBM_PERFCTR_LOAD_VALUE_LO),
ADRENO_REG_DEFINE(ADRENO_REG_RBBM_PERFCTR_LOAD_VALUE_HI,
diff --git a/drivers/gpu/msm/adreno_a5xx_snapshot.c b/drivers/gpu/msm/adreno_a5xx_snapshot.c
index 78b56bc..6dc62866 100644
--- a/drivers/gpu/msm/adreno_a5xx_snapshot.c
+++ b/drivers/gpu/msm/adreno_a5xx_snapshot.c
@@ -767,6 +767,8 @@
crash_dump_valid = false;
+ if (!device->snapshot_crashdumper)
+ return;
if (capturescript.gpuaddr == 0 || registers.gpuaddr == 0)
return;
@@ -872,8 +874,7 @@
ARRAY_SIZE(a5xx_vbif_snapshot_registers));
/* Try to run the crash dumper */
- if (device->snapshot_crashdumper)
- _a5xx_do_crashdump(device);
+ _a5xx_do_crashdump(device);
kgsl_snapshot_add_section(device, KGSL_SNAPSHOT_SECTION_REGS,
snapshot, a5xx_snapshot_registers, NULL);
diff --git a/drivers/gpu/msm/adreno_a6xx.c b/drivers/gpu/msm/adreno_a6xx.c
index 88c15eb..301a4f8 100644
--- a/drivers/gpu/msm/adreno_a6xx.c
+++ b/drivers/gpu/msm/adreno_a6xx.c
@@ -50,10 +50,15 @@
{0, 0},
};
-static const struct adreno_vbif_platform a6xx_vbif_platforms[] = {
- { adreno_is_a630, a630_vbif },
+static const struct adreno_vbif_data a615_gbif[] = {
+ {A6XX_RBBM_VBIF_CLIENT_QOS_CNTL, 0x3},
+ {0, 0},
};
+static const struct adreno_vbif_platform a6xx_vbif_platforms[] = {
+ { adreno_is_a630, a630_vbif },
+ { adreno_is_a615, a615_gbif },
+};
struct kgsl_hwcg_reg {
unsigned int off;
@@ -244,18 +249,6 @@
{ A6XX_RB_CONTEXT_SWITCH_GMEM_SAVE_RESTORE, 0x0 },
};
-static void a6xx_platform_setup(struct adreno_device *adreno_dev)
-{
- uint64_t addr;
- struct adreno_gpudev *gpudev = ADRENO_GPU_DEVICE(adreno_dev);
-
- /* Calculate SP local and private mem addresses */
- addr = ALIGN(ADRENO_UCHE_GMEM_BASE + adreno_dev->gmem_size, SZ_64K);
- adreno_dev->sp_local_gpuaddr = addr;
- adreno_dev->sp_pvt_gpuaddr = addr + SZ_64K;
- gpudev->vbif_xin_halt_ctrl0_mask = A6XX_VBIF_XIN_HALT_CTRL0_MASK;
-}
-
static void _update_always_on_regs(struct adreno_device *adreno_dev)
{
struct adreno_gpudev *gpudev = ADRENO_GPU_DEVICE(adreno_dev);
@@ -369,14 +362,33 @@
kgsl_regwrite(device, A6XX_RBBM_SECVID_TSB_ADDR_MODE_CNTL, 0x1);
}
+#define RBBM_CLOCK_CNTL_ON 0x8AA8AA02
static void a6xx_hwcg_set(struct adreno_device *adreno_dev, bool on)
{
struct kgsl_device *device = KGSL_DEVICE(adreno_dev);
const struct kgsl_hwcg_reg *regs;
+ unsigned int value;
int i, j;
if (!test_bit(ADRENO_HWCG_CTRL, &adreno_dev->pwrctrl_flag))
+ on = false;
+
+ if (kgsl_gmu_isenabled(device)) {
+ kgsl_gmu_regwrite(device, A6XX_GPU_GMU_AO_GMU_CGC_MODE_CNTL,
+ on ? 0x00020222 : 0);
+ kgsl_gmu_regwrite(device, A6XX_GPU_GMU_AO_GMU_CGC_DELAY_CNTL,
+ on ? 0x00010111 : 0);
+ kgsl_gmu_regwrite(device, A6XX_GPU_GMU_AO_GMU_CGC_HYST_CNTL,
+ on ? 0x00050555 : 0);
+ }
+
+ kgsl_regread(device, A6XX_RBBM_CLOCK_CNTL, &value);
+
+ if (value == RBBM_CLOCK_CNTL_ON && on)
+ return;
+
+ if (value == 0 && !on)
return;
for (i = 0; i < ARRAY_SIZE(a6xx_hwcg_registers); i++) {
@@ -395,19 +407,12 @@
for (j = 0; j < a6xx_hwcg_registers[i].count; j++)
kgsl_regwrite(device, regs[j].off, on ? regs[j].val : 0);
- if (kgsl_gmu_isenabled(device)) {
- kgsl_gmu_regwrite(device, A6XX_GPU_GMU_AO_GMU_CGC_MODE_CNTL,
- 0x00020222);
- kgsl_gmu_regwrite(device, A6XX_GPU_GMU_AO_GMU_CGC_DELAY_CNTL,
- 0x00010111);
- kgsl_gmu_regwrite(device, A6XX_GPU_GMU_AO_GMU_CGC_HYST_CNTL,
- 0x00050555);
- }
/* Enable SP clock */
kgsl_gmu_regrmw(device, A6XX_GPU_GMU_GX_SPTPRAC_CLOCK_CONTROL, 0, 1);
/* enable top level HWCG */
- kgsl_regwrite(device, A6XX_RBBM_CLOCK_CNTL, on ? 0x8AA8AA02 : 0);
+ kgsl_regwrite(device, A6XX_RBBM_CLOCK_CNTL,
+ on ? RBBM_CLOCK_CNTL_ON : 0);
}
#define LM_DEFAULT_LIMIT 6000
@@ -888,8 +893,12 @@
*/
static void _load_gmu_rpmh_ucode(struct kgsl_device *device)
{
+ struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
struct gmu_device *gmu = &device->gmu;
+ /* Disable SDE clock gating */
+ kgsl_gmu_regwrite(device, A6XX_GPU_RSCC_RSC_STATUS0_DRV0, BIT(24));
+
/* Setup RSC PDC handshake for sleep and wakeup */
kgsl_gmu_regwrite(device, A6XX_RSCC_PDC_SLAVE_ID_DRV0, 1);
kgsl_gmu_regwrite(device, A6XX_RSCC_HIDDEN_TCS_CMD0_DATA, 0);
@@ -909,8 +918,9 @@
kgsl_gmu_regwrite(device, A6XX_RSCC_PDC_MATCH_VALUE_LO, 0x4510);
kgsl_gmu_regwrite(device, A6XX_RSCC_PDC_MATCH_VALUE_HI, 0x4514);
- /* Enable timestamp event */
- kgsl_gmu_regwrite(device, A6XX_RSCC_TIMESTAMP_UNIT1_EN_DRV0, 1);
+ /* Enable timestamp event for v1 only */
+ if (adreno_is_a630v1(adreno_dev))
+ kgsl_gmu_regwrite(device, A6XX_RSCC_TIMESTAMP_UNIT1_EN_DRV0, 1);
/* Load RSC sequencer uCode for sleep and wakeup */
kgsl_gmu_regwrite(device, A6XX_RSCC_SEQ_MEM_0_DRV0, 0xA7A506A0);
@@ -920,11 +930,11 @@
kgsl_gmu_regwrite(device, A6XX_RSCC_SEQ_MEM_0_DRV0 + 4, 0x0020E8A8);
/* Load PDC sequencer uCode for power up and power down sequence */
- _regwrite(gmu->pdc_reg_virt, PDC_GPU_SEQ_MEM_0, 0xFFBFA1E1);
- _regwrite(gmu->pdc_reg_virt, PDC_GPU_SEQ_MEM_0 + 1, 0xE0A4A3A2);
- _regwrite(gmu->pdc_reg_virt, PDC_GPU_SEQ_MEM_0 + 2, 0xE2848382);
- _regwrite(gmu->pdc_reg_virt, PDC_GPU_SEQ_MEM_0 + 3, 0xFDBDE4E3);
- _regwrite(gmu->pdc_reg_virt, PDC_GPU_SEQ_MEM_0 + 4, 0x00002081);
+ _regwrite(gmu->pdc_reg_virt, PDC_GPU_SEQ_MEM_0, 0xFEBEA1E1);
+ _regwrite(gmu->pdc_reg_virt, PDC_GPU_SEQ_MEM_0 + 1, 0xA5A4A3A2);
+ _regwrite(gmu->pdc_reg_virt, PDC_GPU_SEQ_MEM_0 + 2, 0x8382A6E0);
+ _regwrite(gmu->pdc_reg_virt, PDC_GPU_SEQ_MEM_0 + 3, 0xBCE3E284);
+ _regwrite(gmu->pdc_reg_virt, PDC_GPU_SEQ_MEM_0 + 4, 0x002081FC);
/* Set TCS commands used by PDC sequence for low power modes */
_regwrite(gmu->pdc_reg_virt, PDC_GPU_TCS0_CMD_ENABLE_BANK, 7);
@@ -1007,6 +1017,11 @@
cond_resched();
} while (!time_after(jiffies, t));
+ /* Double check one last time */
+ kgsl_gmu_regread(device, offset, &value);
+ if ((value & mask) == expected_ret)
+ return 0;
+
return -EINVAL;
}
@@ -1430,36 +1445,50 @@
static int a6xx_rpmh_power_off_gpu(struct kgsl_device *device)
{
struct gmu_device *gmu = &device->gmu;
- const struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
- int val;
+ struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
+ int ret;
- /* RSC sleep sequence */
- kgsl_gmu_regwrite(device, A6XX_RSCC_TIMESTAMP_UNIT1_EN_DRV0, 1);
+ /* RSC sleep sequence is different on v1 */
+ if (adreno_is_a630v1(adreno_dev))
+ kgsl_gmu_regwrite(device, A6XX_RSCC_TIMESTAMP_UNIT1_EN_DRV0, 1);
+
kgsl_gmu_regwrite(device, A6XX_GMU_RSCC_CONTROL_REQ, 1);
wmb();
- if (timed_poll_check(device,
- A6XX_RSCC_TIMESTAMP_UNIT1_OUTPUT_DRV0,
- BIT(0),
- GPU_START_TIMEOUT,
- BIT(0))) {
+ if (adreno_is_a630v1(adreno_dev))
+ ret = timed_poll_check(device,
+ A6XX_RSCC_TIMESTAMP_UNIT1_OUTPUT_DRV0,
+ BIT(0),
+ GPU_START_TIMEOUT,
+ BIT(0));
+ else
+ ret = timed_poll_check(device,
+ A6XX_GPU_RSCC_RSC_STATUS0_DRV0,
+ BIT(16),
+ GPU_START_TIMEOUT,
+ BIT(16));
+
+ if (ret) {
dev_err(&gmu->pdev->dev, "GPU RSC power off fail\n");
- return -EINVAL;
+ return -ETIMEDOUT;
}
- /* Read to clear the timestamp */
- kgsl_gmu_regread(device, A6XX_RSCC_TIMESTAMP_UNIT0_TIMESTAMP_L_DRV0,
- &val);
- kgsl_gmu_regread(device, A6XX_RSCC_TIMESTAMP_UNIT0_TIMESTAMP_H_DRV0,
- &val);
+ /* Read to clear the timestamp valid signal. Don't care what we read. */
+ if (adreno_is_a630v1(adreno_dev)) {
+ kgsl_gmu_regread(device,
+ A6XX_RSCC_TIMESTAMP_UNIT0_TIMESTAMP_L_DRV0,
+ &ret);
+ kgsl_gmu_regread(device,
+ A6XX_RSCC_TIMESTAMP_UNIT0_TIMESTAMP_H_DRV0,
+ &ret);
+ }
+
kgsl_gmu_regwrite(device, A6XX_GMU_RSCC_CONTROL_REQ, 0);
if (ADRENO_FEATURE(adreno_dev, ADRENO_LM) &&
- test_bit(ADRENO_LM_CTRL, &adreno_dev->pwrctrl_flag))
+ test_bit(ADRENO_LM_CTRL, &adreno_dev->pwrctrl_flag))
kgsl_gmu_regwrite(device, A6XX_GMU_AO_SPARE_CNTL, 0);
- /* FIXME: v2 has different procedure to trigger sequence */
-
return 0;
}
@@ -2685,6 +2714,27 @@
A6XX_VBIF_PERF_PWR_CNT_HIGH2, -1, A6XX_VBIF_PERF_PWR_CNT_EN2 },
};
+
+static struct adreno_perfcount_register a6xx_perfcounters_gbif[] = {
+ { KGSL_PERFCOUNTER_NOT_USED, 0, 0, A6XX_GBIF_PERF_CNT_LOW0,
+ A6XX_GBIF_PERF_CNT_HIGH0, -1, A6XX_GBIF_PERF_CNT_SEL },
+ { KGSL_PERFCOUNTER_NOT_USED, 0, 0, A6XX_GBIF_PERF_CNT_LOW1,
+ A6XX_GBIF_PERF_CNT_HIGH1, -1, A6XX_GBIF_PERF_CNT_SEL },
+ { KGSL_PERFCOUNTER_NOT_USED, 0, 0, A6XX_GBIF_PERF_CNT_LOW2,
+ A6XX_GBIF_PERF_CNT_HIGH2, -1, A6XX_GBIF_PERF_CNT_SEL },
+ { KGSL_PERFCOUNTER_NOT_USED, 0, 0, A6XX_GBIF_PERF_CNT_LOW3,
+ A6XX_GBIF_PERF_CNT_HIGH3, -1, A6XX_GBIF_PERF_CNT_SEL },
+};
+
+static struct adreno_perfcount_register a6xx_perfcounters_gbif_pwr[] = {
+ { KGSL_PERFCOUNTER_NOT_USED, 0, 0, A6XX_GBIF_PWR_CNT_LOW0,
+ A6XX_GBIF_PWR_CNT_HIGH0, -1, A6XX_GBIF_PERF_PWR_CNT_EN },
+ { KGSL_PERFCOUNTER_NOT_USED, 0, 0, A6XX_GBIF_PWR_CNT_LOW1,
+ A6XX_GBIF_PWR_CNT_HIGH1, -1, A6XX_GBIF_PERF_PWR_CNT_EN },
+ { KGSL_PERFCOUNTER_NOT_USED, 0, 0, A6XX_GBIF_PWR_CNT_LOW2,
+ A6XX_GBIF_PWR_CNT_HIGH2, -1, A6XX_GBIF_PERF_PWR_CNT_EN },
+};
+
static struct adreno_perfcount_register a6xx_perfcounters_pwr[] = {
{ KGSL_PERFCOUNTER_BROKEN, 0, 0, 0, 0, -1, 0 },
{ KGSL_PERFCOUNTER_NOT_USED, 0, 0,
@@ -2795,6 +2845,35 @@
return 0;
}
+static void a6xx_platform_setup(struct adreno_device *adreno_dev)
+{
+ uint64_t addr;
+ struct adreno_gpudev *gpudev = ADRENO_GPU_DEVICE(adreno_dev);
+
+ /* Calculate SP local and private mem addresses */
+ addr = ALIGN(ADRENO_UCHE_GMEM_BASE + adreno_dev->gmem_size, SZ_64K);
+ adreno_dev->sp_local_gpuaddr = addr;
+ adreno_dev->sp_pvt_gpuaddr = addr + SZ_64K;
+
+ if (adreno_has_gbif(adreno_dev)) {
+ a6xx_perfcounter_groups[KGSL_PERFCOUNTER_GROUP_VBIF].regs =
+ a6xx_perfcounters_gbif;
+ a6xx_perfcounter_groups[KGSL_PERFCOUNTER_GROUP_VBIF].reg_count
+ = ARRAY_SIZE(a6xx_perfcounters_gbif);
+
+ a6xx_perfcounter_groups[KGSL_PERFCOUNTER_GROUP_VBIF_PWR].regs =
+ a6xx_perfcounters_gbif_pwr;
+ a6xx_perfcounter_groups[KGSL_PERFCOUNTER_GROUP_VBIF].reg_count
+ = ARRAY_SIZE(a6xx_perfcounters_gbif_pwr);
+
+ gpudev->vbif_xin_halt_ctrl0_mask =
+ A6XX_GBIF_HALT_MASK;
+ } else
+ gpudev->vbif_xin_halt_ctrl0_mask =
+ A6XX_VBIF_XIN_HALT_CTRL0_MASK;
+}
+
+
/* Register offset defines for A6XX, in order of enum adreno_regs */
static unsigned int a6xx_register_offsets[ADRENO_REG_REGISTER_MAX] = {
@@ -2854,6 +2933,8 @@
A6XX_VBIF_XIN_HALT_CTRL0),
ADRENO_REG_DEFINE(ADRENO_REG_VBIF_XIN_HALT_CTRL1,
A6XX_VBIF_XIN_HALT_CTRL1),
+ ADRENO_REG_DEFINE(ADRENO_REG_GBIF_HALT, A6XX_GBIF_HALT),
+ ADRENO_REG_DEFINE(ADRENO_REG_GBIF_HALT_ACK, A6XX_GBIF_HALT_ACK),
ADRENO_REG_DEFINE(ADRENO_REG_RBBM_ALWAYSON_COUNTER_LO,
A6XX_GMU_ALWAYS_ON_COUNTER_L),
ADRENO_REG_DEFINE(ADRENO_REG_RBBM_ALWAYSON_COUNTER_HI,
diff --git a/drivers/gpu/msm/adreno_a6xx_snapshot.c b/drivers/gpu/msm/adreno_a6xx_snapshot.c
index f63e824d..755fc7f 100644
--- a/drivers/gpu/msm/adreno_a6xx_snapshot.c
+++ b/drivers/gpu/msm/adreno_a6xx_snapshot.c
@@ -569,38 +569,33 @@
(((_a)[(2 * (_i)) + 1] - (_a)[2 * (_i)]) + 1)
static size_t a6xx_legacy_snapshot_registers(struct kgsl_device *device,
- u8 *buf, size_t remain)
+ u8 *buf, size_t remain, struct reg_list *regs)
{
- unsigned int i;
- size_t used = 0;
+ struct kgsl_snapshot_registers snapshot_regs = {
+ .regs = regs->regs,
+ .count = regs->count,
+ };
- for (i = 0; i < ARRAY_SIZE(a6xx_reg_list); i++) {
- struct reg_list *regs = &a6xx_reg_list[i];
- struct kgsl_snapshot_registers snapshot_regs = {
- .regs = regs->regs,
- .count = regs->count,
- };
+ if (regs->sel)
+ kgsl_regwrite(device, regs->sel->host_reg, regs->sel->val);
- if (regs->sel)
- kgsl_regwrite(device, regs->sel->host_reg,
- regs->sel->val);
- used += kgsl_snapshot_dump_registers(device, buf + used,
- remain - used, &snapshot_regs);
- }
- return used;
+ return kgsl_snapshot_dump_registers(device, buf, remain,
+ &snapshot_regs);
}
static size_t a6xx_snapshot_registers(struct kgsl_device *device, u8 *buf,
size_t remain, void *priv)
{
struct kgsl_snapshot_regs *header = (struct kgsl_snapshot_regs *)buf;
+ struct reg_list *regs = (struct reg_list *)priv;
unsigned int *data = (unsigned int *)(buf + sizeof(*header));
unsigned int *src = (unsigned int *)a6xx_crashdump_registers.hostptr;
- unsigned int i, j, k;
+ unsigned int j, k;
unsigned int count = 0;
if (crash_dump_valid == false)
- return a6xx_legacy_snapshot_registers(device, buf, remain);
+ return a6xx_legacy_snapshot_registers(device, buf, remain,
+ regs);
if (remain < sizeof(*header)) {
SNAPSHOT_ERR_NOMEM(device, "REGISTERS");
@@ -609,24 +604,20 @@
remain -= sizeof(*header);
- for (i = 0; i < ARRAY_SIZE(a6xx_reg_list); i++) {
- struct reg_list *regs = &a6xx_reg_list[i];
+ for (j = 0; j < regs->count; j++) {
+ unsigned int start = regs->regs[2 * j];
+ unsigned int end = regs->regs[(2 * j) + 1];
- for (j = 0; j < regs->count; j++) {
- unsigned int start = regs->regs[2 * j];
- unsigned int end = regs->regs[(2 * j) + 1];
+ if (remain < ((end - start) + 1) * 8) {
+ SNAPSHOT_ERR_NOMEM(device, "REGISTERS");
+ goto out;
+ }
- if (remain < ((end - start) + 1) * 8) {
- SNAPSHOT_ERR_NOMEM(device, "REGISTERS");
- goto out;
- }
+ remain -= ((end - start) + 1) * 8;
- remain -= ((end - start) + 1) * 8;
-
- for (k = start; k <= end; k++, count++) {
- *data++ = k;
- *data++ = *src++;
- }
+ for (k = start; k <= end; k++, count++) {
+ *data++ = k;
+ *data++ = *src++;
}
}
@@ -1366,6 +1357,7 @@
struct kgsl_snapshot *snapshot)
{
int i;
+ struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
kgsl_regwrite(device, A6XX_DBGC_CFG_DBGBUS_CNTLT,
(0xf << A6XX_DBGC_CFG_DBGBUS_CNTLT_SEGT_SHIFT) |
@@ -1456,9 +1448,12 @@
(void *) &a6xx_dbgc_debugbus_blocks[i]);
}
- kgsl_snapshot_add_section(device, KGSL_SNAPSHOT_SECTION_DEBUGBUS,
- snapshot, a6xx_snapshot_vbif_debugbus_block,
- (void *) &a6xx_vbif_debugbus_blocks);
+ /* Skip if GPU has GBIF */
+ if (!adreno_has_gbif(adreno_dev))
+ kgsl_snapshot_add_section(device,
+ KGSL_SNAPSHOT_SECTION_DEBUGBUS,
+ snapshot, a6xx_snapshot_vbif_debugbus_block,
+ (void *) &a6xx_vbif_debugbus_blocks);
if (a6xx_cx_dbgc) {
for (i = 0; i < ARRAY_SIZE(a6xx_cx_dbgc_debugbus_blocks); i++) {
@@ -1527,6 +1522,8 @@
crash_dump_valid = false;
+ if (!device->snapshot_crashdumper)
+ return;
if (a6xx_capturescript.gpuaddr == 0 ||
a6xx_crashdump_registers.gpuaddr == 0)
return;
@@ -1578,6 +1575,7 @@
struct adreno_gpudev *gpudev = ADRENO_GPU_DEVICE(adreno_dev);
struct adreno_snapshot_data *snap_data = gpudev->snapshot_data;
bool sptprac_on;
+ unsigned int i;
sptprac_on = gpudev->sptprac_is_on(adreno_dev);
@@ -1590,16 +1588,19 @@
snapshot, a6xx_snapshot_pre_crashdump_regs, NULL);
/* Dump vbif registers as well which get affected by crash dumper */
- adreno_snapshot_vbif_registers(device, snapshot,
- a6xx_vbif_snapshot_registers,
- ARRAY_SIZE(a6xx_vbif_snapshot_registers));
+ if (!adreno_has_gbif(adreno_dev))
+ adreno_snapshot_vbif_registers(device, snapshot,
+ a6xx_vbif_snapshot_registers,
+ ARRAY_SIZE(a6xx_vbif_snapshot_registers));
/* Try to run the crash dumper */
if (sptprac_on)
_a6xx_do_crashdump(device);
- kgsl_snapshot_add_section(device, KGSL_SNAPSHOT_SECTION_REGS,
- snapshot, a6xx_snapshot_registers, NULL);
+ for (i = 0; i < ARRAY_SIZE(a6xx_reg_list); i++) {
+ kgsl_snapshot_add_section(device, KGSL_SNAPSHOT_SECTION_REGS,
+ snapshot, a6xx_snapshot_registers, &a6xx_reg_list[i]);
+ }
/* CP_SQE indexed registers */
kgsl_snapshot_indexed_registers(device, snapshot,
diff --git a/drivers/gpu/msm/adreno_dispatch.c b/drivers/gpu/msm/adreno_dispatch.c
index 6bdc486..cb42a70 100644
--- a/drivers/gpu/msm/adreno_dispatch.c
+++ b/drivers/gpu/msm/adreno_dispatch.c
@@ -2079,7 +2079,7 @@
struct adreno_ringbuffer *rb;
struct adreno_ringbuffer *hung_rb = NULL;
unsigned int reg;
- uint64_t base;
+ uint64_t base = 0;
struct kgsl_drawobj_cmd *cmdobj = NULL;
int ret, i;
int fault;
diff --git a/drivers/gpu/msm/adreno_perfcounter.c b/drivers/gpu/msm/adreno_perfcounter.c
index 0da4da9..dfce3eb 100644
--- a/drivers/gpu/msm/adreno_perfcounter.c
+++ b/drivers/gpu/msm/adreno_perfcounter.c
@@ -28,6 +28,20 @@
/* offset of enable register from select register */
#define VBIF2_PERF_EN_REG_SEL_OFF 16
+/* offset of clear register from select register for GBIF */
+#define GBIF_PERF_CLR_REG_SEL_OFF 1
+
+/* offset of enable register from select register for GBIF*/
+#define GBIF_PERF_EN_REG_SEL_OFF 2
+
+/* offset of clear register from the power enable register for GBIF*/
+#define GBIF_PWR_CLR_REG_EN_OFF 1
+
+/* */
+#define GBIF_PERF_RMW_MASK 0xFF
+/* */
+#define GBIF_PWR_RMW_MASK 0x10000
+
/* offset of clear register from the enable register */
#define VBIF2_PERF_PWR_CLR_REG_EN_OFF 8
@@ -612,14 +626,41 @@
{
struct kgsl_device *device = KGSL_DEVICE(adreno_dev);
struct adreno_perfcount_register *reg;
+ unsigned int shift = counter << 3;
reg = &counters->groups[KGSL_PERFCOUNTER_GROUP_VBIF].regs[counter];
- /* Write 1, followed by 0 to CLR register for clearing the counter */
- kgsl_regwrite(device, reg->select - VBIF2_PERF_CLR_REG_SEL_OFF, 1);
- kgsl_regwrite(device, reg->select - VBIF2_PERF_CLR_REG_SEL_OFF, 0);
- kgsl_regwrite(device, reg->select, countable & VBIF2_PERF_CNT_SEL_MASK);
- /* enable reg is 8 DWORDS before select reg */
- kgsl_regwrite(device, reg->select - VBIF2_PERF_EN_REG_SEL_OFF, 1);
+
+ if (adreno_has_gbif(adreno_dev)) {
+ /*
+ * Write 1, followed by 0 to CLR register for
+ * clearing the counter
+ */
+ kgsl_regrmw(device, reg->select - GBIF_PERF_CLR_REG_SEL_OFF,
+ 1 << counter, 1);
+ kgsl_regrmw(device, reg->select - GBIF_PERF_CLR_REG_SEL_OFF,
+ 1 << counter, 0);
+ /* select the desired countable */
+ kgsl_regrmw(device, reg->select,
+ GBIF_PERF_RMW_MASK << shift, countable << shift);
+ /* enable counter */
+ kgsl_regrmw(device, reg->select - GBIF_PERF_EN_REG_SEL_OFF,
+ 1 << counter, 1);
+
+ } else {
+ /*
+ * Write 1, followed by 0 to CLR register for
+ * clearing the counter
+ */
+ kgsl_regwrite(device,
+ reg->select - VBIF2_PERF_CLR_REG_SEL_OFF, 1);
+ kgsl_regwrite(device,
+ reg->select - VBIF2_PERF_CLR_REG_SEL_OFF, 0);
+ kgsl_regwrite(device,
+ reg->select, countable & VBIF2_PERF_CNT_SEL_MASK);
+ /* enable reg is 8 DWORDS before select reg */
+ kgsl_regwrite(device,
+ reg->select - VBIF2_PERF_EN_REG_SEL_OFF, 1);
+ }
reg->value = 0;
}
@@ -630,10 +671,30 @@
struct adreno_perfcount_register *reg;
reg = &counters->groups[KGSL_PERFCOUNTER_GROUP_VBIF_PWR].regs[counter];
- /* Write 1, followed by 0 to CLR register for clearing the counter */
- kgsl_regwrite(device, reg->select + VBIF2_PERF_PWR_CLR_REG_EN_OFF, 1);
- kgsl_regwrite(device, reg->select + VBIF2_PERF_PWR_CLR_REG_EN_OFF, 0);
- kgsl_regwrite(device, reg->select, 1);
+
+ if (adreno_has_gbif(adreno_dev)) {
+ /*
+ * Write 1, followed by 0 to CLR register for
+ * clearing the counter
+ */
+ kgsl_regrmw(device, reg->select + GBIF_PWR_CLR_REG_EN_OFF,
+ GBIF_PWR_RMW_MASK << counter, 1);
+ kgsl_regrmw(device, reg->select + GBIF_PWR_CLR_REG_EN_OFF,
+ GBIF_PWR_RMW_MASK << counter, 0);
+ /* Enable the counter */
+ kgsl_regrmw(device, reg->select,
+ GBIF_PWR_RMW_MASK << counter, 1);
+ } else {
+ /*
+ * Write 1, followed by 0 to CLR register for
+ * clearing the counter
+ */
+ kgsl_regwrite(device, reg->select +
+ VBIF2_PERF_PWR_CLR_REG_EN_OFF, 1);
+ kgsl_regwrite(device, reg->select +
+ VBIF2_PERF_PWR_CLR_REG_EN_OFF, 0);
+ kgsl_regwrite(device, reg->select, 1);
+ }
reg->value = 0;
}
diff --git a/drivers/gpu/msm/kgsl_gmu.c b/drivers/gpu/msm/kgsl_gmu.c
index 7ea2255..82f0c11 100644
--- a/drivers/gpu/msm/kgsl_gmu.c
+++ b/drivers/gpu/msm/kgsl_gmu.c
@@ -1149,7 +1149,6 @@
goto error;
gmu->num_gpupwrlevels = pwr->num_pwrlevels;
- gmu->wakeup_pwrlevel = pwr->default_pwrlevel;
for (i = 0; i < gmu->num_gpupwrlevels; i++) {
int j = gmu->num_gpupwrlevels - 1 - i;
@@ -1411,11 +1410,8 @@
if (ret)
goto error_gmu;
- /* Send default DCVS level */
- ret = gmu_dcvs_set(gmu, pwr->default_pwrlevel,
- pwr->pwrlevels[pwr->default_pwrlevel].bus_freq);
- if (ret)
- goto error_gmu;
+ /* Request default DCVS level */
+ kgsl_pwrctrl_pwrlevel_change(device, pwr->default_pwrlevel);
msm_bus_scale_client_update_request(gmu->pcl, 0);
break;
@@ -1435,12 +1431,7 @@
if (ret)
goto error_gmu;
- ret = gmu_dcvs_set(gmu, gmu->wakeup_pwrlevel,
- pwr->pwrlevels[gmu->wakeup_pwrlevel].bus_freq);
- if (ret)
- goto error_gmu;
-
- gmu->wakeup_pwrlevel = pwr->default_pwrlevel;
+ kgsl_pwrctrl_pwrlevel_change(device, pwr->default_pwrlevel);
break;
case KGSL_STATE_RESET:
@@ -1462,11 +1453,8 @@
goto error_gmu;
/* Send DCVS level prior to reset*/
- ret = gmu_dcvs_set(gmu, pwr->active_pwrlevel,
- pwr->pwrlevels[pwr->active_pwrlevel]
- .bus_freq);
- if (ret)
- goto error_gmu;
+ kgsl_pwrctrl_pwrlevel_change(device,
+ pwr->default_pwrlevel);
ret = gpudev->oob_set(adreno_dev,
OOB_CPINIT_SET_MASK,
@@ -1519,6 +1507,14 @@
cond_resched();
}
+ /* Double check one last time */
+ if (idle == false) {
+ adreno_read_gmureg(ADRENO_DEVICE(device),
+ ADRENO_REG_GMU_RPMH_POWER_STATE, ®);
+ if (reg == device->gmu.idle_level)
+ idle = true;
+ }
+
gpudev->rpmh_gpu_pwrctrl(adreno_dev, GMU_NOTIFY_SLUMBER, 0, 0);
if (!idle || (gpudev->wait_for_gmu_idle &&
diff --git a/drivers/gpu/msm/kgsl_gmu.h b/drivers/gpu/msm/kgsl_gmu.h
index ff65f66..a5dc692 100644
--- a/drivers/gpu/msm/kgsl_gmu.h
+++ b/drivers/gpu/msm/kgsl_gmu.h
@@ -82,7 +82,8 @@
GMU_BOOT_INIT_DONE = 0,
GMU_CLK_ON = 1,
GMU_HFI_ON = 2,
- GMU_FAULT = 3
+ GMU_FAULT = 3,
+ GMU_DCVS_REPLAY = 4,
};
/**
diff --git a/drivers/gpu/msm/kgsl_pwrctrl.c b/drivers/gpu/msm/kgsl_pwrctrl.c
index 007121c..97e5c22 100644
--- a/drivers/gpu/msm/kgsl_pwrctrl.c
+++ b/drivers/gpu/msm/kgsl_pwrctrl.c
@@ -244,12 +244,9 @@
/* GMU scales GPU freq */
if (kgsl_gmu_isenabled(device)) {
/* If GMU has not been started, save it */
- if (!(gmu->flags & GMU_HFI_ON)) {
- /* In slumber the clock is off so we are done */
- if (pwrlevel == (gmu->num_gpupwrlevels - 1))
- return 0;
-
- gmu->wakeup_pwrlevel = pwrlevel;
+ if (!test_bit(GMU_HFI_ON, &gmu->flags)) {
+ /* store clock change request */
+ set_bit(GMU_DCVS_REPLAY, &gmu->flags);
return 0;
}
@@ -259,6 +256,8 @@
return -EINVAL;
}
ret = gmu_dcvs_set(gmu, pwrlevel, INVALID_DCVS_IDX);
+ /* indicate actual clock change */
+ clear_bit(GMU_DCVS_REPLAY, &gmu->flags);
} else
/* Linux clock driver scales GPU freq */
ret = clk_set_rate(pwr->grp_clks[0], pl->gpu_freq);
@@ -412,7 +411,8 @@
*/
kgsl_pwrctrl_set_thermal_cycle(pwr, new_level);
- if (new_level == old_level)
+ if (new_level == old_level &&
+ !test_bit(GMU_DCVS_REPLAY, &device->gmu.flags))
return;
kgsl_pwrscale_update_stats(device);
@@ -2485,6 +2485,9 @@
static void kgsl_pwrctrl_disable(struct kgsl_device *device)
{
if (kgsl_gmu_isenabled(device)) {
+ struct kgsl_pwrctrl *pwr = &device->pwrctrl;
+
+ pwr->active_pwrlevel = pwr->num_pwrlevels - 1;
kgsl_pwrctrl_axi(device, KGSL_PWRFLAGS_OFF);
return gmu_stop(device);
}
diff --git a/drivers/hwtracing/coresight/Makefile b/drivers/hwtracing/coresight/Makefile
index 44e55ff..cb47ecd 100644
--- a/drivers/hwtracing/coresight/Makefile
+++ b/drivers/hwtracing/coresight/Makefile
@@ -5,7 +5,8 @@
obj-$(CONFIG_OF) += of_coresight.o
obj-$(CONFIG_CORESIGHT_LINK_AND_SINK_TMC) += coresight-tmc.o \
coresight-tmc-etf.o \
- coresight-tmc-etr.o
+ coresight-tmc-etr.o \
+ coresight-byte-cntr.o
obj-$(CONFIG_CORESIGHT_SINK_TPIU) += coresight-tpiu.o
obj-$(CONFIG_CORESIGHT_SINK_ETBV10) += coresight-etb10.o
obj-$(CONFIG_CORESIGHT_LINKS_AND_SINKS) += coresight-funnel.o \
diff --git a/drivers/hwtracing/coresight/coresight-byte-cntr.c b/drivers/hwtracing/coresight/coresight-byte-cntr.c
new file mode 100644
index 0000000..496738c
--- /dev/null
+++ b/drivers/hwtracing/coresight/coresight-byte-cntr.c
@@ -0,0 +1,374 @@
+/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+#include <linux/interrupt.h>
+#include <linux/dma-mapping.h>
+#include <linux/fs.h>
+#include <linux/of_irq.h>
+#include <linux/moduleparam.h>
+#include <linux/delay.h>
+
+#include "coresight-byte-cntr.h"
+#include "coresight-priv.h"
+#include "coresight-tmc.h"
+
+static struct tmc_drvdata *tmcdrvdata;
+
+static void tmc_etr_read_bytes(struct byte_cntr *byte_cntr_data, loff_t *ppos,
+ size_t bytes, size_t *len)
+{
+ if (*len >= bytes) {
+ atomic_dec(&byte_cntr_data->irq_cnt);
+ *len = bytes;
+ } else {
+ if (((uint32_t)*ppos % bytes) + *len > bytes)
+ *len = bytes - ((uint32_t)*ppos % bytes);
+ if ((*len + (uint32_t)*ppos) % bytes == 0)
+ atomic_dec(&byte_cntr_data->irq_cnt);
+ }
+}
+
+static void tmc_etr_sg_read_pos(loff_t *ppos,
+ size_t bytes, bool noirq, size_t *len,
+ char **bufpp)
+{
+ uint32_t rwp, i = 0;
+ uint32_t blk_num, sg_tbl_num, blk_num_loc, read_off;
+ uint32_t *virt_pte, *virt_st_tbl;
+ void *virt_blk;
+ phys_addr_t phys_pte;
+ int total_ents = DIV_ROUND_UP(tmcdrvdata->size, PAGE_SIZE);
+ int ents_per_pg = PAGE_SIZE/sizeof(uint32_t);
+
+ if (*len == 0)
+ return;
+
+ blk_num = *ppos / PAGE_SIZE;
+ read_off = *ppos % PAGE_SIZE;
+
+ virt_st_tbl = (uint32_t *)tmcdrvdata->vaddr;
+
+ /* Compute table index and block entry index within that table */
+ if (blk_num && (blk_num == (total_ents - 1)) &&
+ !(blk_num % (ents_per_pg - 1))) {
+ sg_tbl_num = blk_num / ents_per_pg;
+ blk_num_loc = ents_per_pg - 1;
+ } else {
+ sg_tbl_num = blk_num / (ents_per_pg - 1);
+ blk_num_loc = blk_num % (ents_per_pg - 1);
+ }
+
+ for (i = 0; i < sg_tbl_num; i++) {
+ virt_pte = virt_st_tbl + (ents_per_pg - 1);
+ phys_pte = TMC_ETR_SG_ENT_TO_BLK(*virt_pte);
+ virt_st_tbl = (uint32_t *)phys_to_virt(phys_pte);
+ }
+
+ virt_pte = virt_st_tbl + blk_num_loc;
+ phys_pte = TMC_ETR_SG_ENT_TO_BLK(*virt_pte);
+ virt_blk = phys_to_virt(phys_pte);
+
+ *bufpp = (char *)(virt_blk + read_off);
+
+ if (noirq) {
+ rwp = readl_relaxed(tmcdrvdata->base + TMC_RWP);
+ tmc_etr_sg_rwp_pos(tmcdrvdata, rwp);
+ if (tmcdrvdata->sg_blk_num == blk_num &&
+ rwp >= (phys_pte + read_off))
+ *len = rwp - phys_pte - read_off;
+ else if (tmcdrvdata->sg_blk_num > blk_num)
+ *len = PAGE_SIZE - read_off;
+ else
+ *len = bytes;
+ } else {
+
+ if (*len > (PAGE_SIZE - read_off))
+ *len = PAGE_SIZE - read_off;
+
+ if (*len >= (bytes - ((uint32_t)*ppos % bytes)))
+ *len = bytes - ((uint32_t)*ppos % bytes);
+
+ if ((*len + (uint32_t)*ppos) % bytes == 0)
+ atomic_dec(&tmcdrvdata->byte_cntr->irq_cnt);
+ }
+
+ /*
+ * Invalidate cache range before reading. This will make sure that CPU
+ * reads latest contents from DDR
+ */
+ dmac_inv_range((void *)(*bufpp), (void *)(*bufpp) + *len);
+}
+
+static irqreturn_t etr_handler(int irq, void *data)
+{
+ struct byte_cntr *byte_cntr_data = data;
+
+ atomic_inc(&byte_cntr_data->irq_cnt);
+
+ wake_up(&byte_cntr_data->wq);
+
+ return IRQ_HANDLED;
+}
+
+static void tmc_etr_flush_bytes(loff_t *ppos, size_t bytes, size_t *len)
+{
+ uint32_t rwp = 0;
+
+ rwp = readl_relaxed(tmcdrvdata->base + TMC_RWP);
+
+ if (rwp >= (tmcdrvdata->paddr + *ppos)) {
+ if (bytes > (rwp - tmcdrvdata->paddr - *ppos))
+ *len = rwp - tmcdrvdata->paddr - *ppos;
+ }
+}
+
+static ssize_t tmc_etr_byte_cntr_read(struct file *fp, char __user *data,
+ size_t len, loff_t *ppos)
+{
+ struct byte_cntr *byte_cntr_data = fp->private_data;
+ char *bufp;
+
+ if (!data)
+ return -EINVAL;
+
+ mutex_lock(&byte_cntr_data->byte_cntr_lock);
+ if (!byte_cntr_data->read_active)
+ goto err0;
+
+ if (byte_cntr_data->enable) {
+ if (!atomic_read(&byte_cntr_data->irq_cnt)) {
+ mutex_unlock(&byte_cntr_data->byte_cntr_lock);
+ if (wait_event_interruptible(byte_cntr_data->wq,
+ atomic_read(&byte_cntr_data->irq_cnt) > 0))
+ return -ERESTARTSYS;
+ mutex_lock(&byte_cntr_data->byte_cntr_lock);
+ if (!byte_cntr_data->read_active)
+ goto err0;
+ }
+ bufp = (char *)(tmcdrvdata->vaddr + *ppos);
+
+ if (tmcdrvdata->mem_type == TMC_ETR_MEM_TYPE_CONTIG)
+ tmc_etr_read_bytes(byte_cntr_data, ppos,
+ byte_cntr_data->block_size, &len);
+ else
+ tmc_etr_sg_read_pos(ppos, byte_cntr_data->block_size, 0,
+ &len, &bufp);
+
+ } else {
+ if (!atomic_read(&byte_cntr_data->irq_cnt)) {
+ if (tmcdrvdata->mem_type == TMC_ETR_MEM_TYPE_CONTIG)
+ tmc_etr_flush_bytes(ppos,
+ byte_cntr_data->block_size,
+ &len);
+ else
+ tmc_etr_sg_read_pos(ppos,
+ byte_cntr_data->block_size,
+ 1,
+ &len, &bufp);
+ if (!len)
+ goto err0;
+ } else {
+ if (tmcdrvdata->mem_type == TMC_ETR_MEM_TYPE_CONTIG)
+ tmc_etr_read_bytes(byte_cntr_data, ppos,
+ byte_cntr_data->block_size,
+ &len);
+ else
+ tmc_etr_sg_read_pos(ppos,
+ byte_cntr_data->block_size,
+ 1,
+ &len, &bufp);
+ }
+ }
+
+ if (copy_to_user(data, bufp, len)) {
+ mutex_unlock(&byte_cntr_data->byte_cntr_lock);
+ dev_dbg(tmcdrvdata->dev, "%s: copy_to_user failed\n", __func__);
+ return -EFAULT;
+ }
+
+ if (*ppos + len >= tmcdrvdata->size)
+ *ppos = 0;
+ else
+ *ppos += len;
+err0:
+ mutex_unlock(&byte_cntr_data->byte_cntr_lock);
+
+ return len;
+}
+
+void tmc_etr_byte_cntr_start(struct byte_cntr *byte_cntr_data)
+{
+ if (!byte_cntr_data)
+ return;
+
+ mutex_lock(&byte_cntr_data->byte_cntr_lock);
+
+ if (byte_cntr_data->block_size == 0) {
+ mutex_unlock(&byte_cntr_data->byte_cntr_lock);
+ return;
+ }
+
+ atomic_set(&byte_cntr_data->irq_cnt, 0);
+ byte_cntr_data->enable = true;
+ mutex_unlock(&byte_cntr_data->byte_cntr_lock);
+}
+EXPORT_SYMBOL(tmc_etr_byte_cntr_start);
+
+void tmc_etr_byte_cntr_stop(struct byte_cntr *byte_cntr_data)
+{
+ if (!byte_cntr_data)
+ return;
+
+ mutex_lock(&byte_cntr_data->byte_cntr_lock);
+ byte_cntr_data->enable = false;
+ coresight_csr_set_byte_cntr(0);
+ mutex_unlock(&byte_cntr_data->byte_cntr_lock);
+
+}
+EXPORT_SYMBOL(tmc_etr_byte_cntr_stop);
+
+
+static int tmc_etr_byte_cntr_release(struct inode *in, struct file *fp)
+{
+ struct byte_cntr *byte_cntr_data = fp->private_data;
+
+ mutex_lock(&byte_cntr_data->byte_cntr_lock);
+ byte_cntr_data->read_active = false;
+
+ coresight_csr_set_byte_cntr(0);
+ mutex_unlock(&byte_cntr_data->byte_cntr_lock);
+
+ return 0;
+}
+
+static int tmc_etr_byte_cntr_open(struct inode *in, struct file *fp)
+{
+ struct byte_cntr *byte_cntr_data =
+ container_of(in->i_cdev, struct byte_cntr, dev);
+
+ mutex_lock(&byte_cntr_data->byte_cntr_lock);
+
+ if (!tmcdrvdata->enable || !byte_cntr_data->block_size) {
+ mutex_unlock(&byte_cntr_data->byte_cntr_lock);
+ return -EINVAL;
+ }
+
+ coresight_csr_set_byte_cntr(byte_cntr_data->block_size);
+ fp->private_data = byte_cntr_data;
+ nonseekable_open(in, fp);
+ byte_cntr_data->enable = true;
+ byte_cntr_data->read_active = true;
+ mutex_unlock(&byte_cntr_data->byte_cntr_lock);
+
+ return 0;
+}
+
+static const struct file_operations byte_cntr_fops = {
+ .owner = THIS_MODULE,
+ .open = tmc_etr_byte_cntr_open,
+ .read = tmc_etr_byte_cntr_read,
+ .release = tmc_etr_byte_cntr_release,
+ .llseek = no_llseek,
+};
+
+static int byte_cntr_register_chardev(struct byte_cntr *byte_cntr_data)
+{
+ int ret;
+ unsigned int baseminor = 0;
+ unsigned int count = 1;
+ struct device *device;
+ dev_t dev;
+
+ ret = alloc_chrdev_region(&dev, baseminor, count, "byte-cntr");
+ if (ret < 0) {
+ pr_err("alloc_chrdev_region failed %d\n", ret);
+ return ret;
+ }
+ cdev_init(&byte_cntr_data->dev, &byte_cntr_fops);
+
+ byte_cntr_data->dev.owner = THIS_MODULE;
+ byte_cntr_data->dev.ops = &byte_cntr_fops;
+
+ ret = cdev_add(&byte_cntr_data->dev, dev, 1);
+ if (ret)
+ goto exit_unreg_chrdev_region;
+
+ byte_cntr_data->driver_class = class_create(THIS_MODULE,
+ "coresight-tmc-etr-stream");
+ if (IS_ERR(byte_cntr_data->driver_class)) {
+ ret = -ENOMEM;
+ pr_err("class_create failed %d\n", ret);
+ goto exit_unreg_chrdev_region;
+ }
+
+ device = device_create(byte_cntr_data->driver_class, NULL,
+ byte_cntr_data->dev.dev, byte_cntr_data,
+ "byte-cntr");
+
+ if (IS_ERR(device)) {
+ pr_err("class_device_create failed %d\n", ret);
+ ret = -ENOMEM;
+ goto exit_destroy_class;
+ }
+
+ return 0;
+
+exit_destroy_class:
+ class_destroy(byte_cntr_data->driver_class);
+exit_unreg_chrdev_region:
+ unregister_chrdev_region(byte_cntr_data->dev.dev, 1);
+ return ret;
+}
+
+struct byte_cntr *byte_cntr_init(struct amba_device *adev,
+ struct tmc_drvdata *drvdata)
+{
+ struct device *dev = &adev->dev;
+ struct device_node *np = adev->dev.of_node;
+ int byte_cntr_irq;
+ int ret;
+ struct byte_cntr *byte_cntr_data;
+
+ byte_cntr_irq = of_irq_get_byname(np, "byte-cntr-irq");
+ if (byte_cntr_irq < 0)
+ return NULL;
+
+ byte_cntr_data = devm_kmalloc(dev, sizeof(*byte_cntr_data), GFP_KERNEL);
+ if (!byte_cntr_data)
+ return NULL;
+
+ ret = devm_request_irq(dev, byte_cntr_irq, etr_handler,
+ IRQF_TRIGGER_RISING | IRQF_SHARED,
+ "tmc-etr", byte_cntr_data);
+ if (ret) {
+ devm_kfree(dev, byte_cntr_data);
+ dev_err(dev, "Byte_cntr interrupt registration failed\n");
+ return NULL;
+ }
+
+ ret = byte_cntr_register_chardev(byte_cntr_data);
+ if (ret) {
+ devm_free_irq(dev, byte_cntr_irq, byte_cntr_data);
+ devm_kfree(dev, byte_cntr_data);
+ dev_err(dev, "Byte_cntr char dev registration failed\n");
+ return NULL;
+ }
+
+ tmcdrvdata = drvdata;
+ byte_cntr_data->block_size = 0;
+ byte_cntr_data->byte_cntr_irq = byte_cntr_irq;
+ atomic_set(&byte_cntr_data->irq_cnt, 0);
+ init_waitqueue_head(&byte_cntr_data->wq);
+ mutex_init(&byte_cntr_data->byte_cntr_lock);
+
+ return byte_cntr_data;
+}
+EXPORT_SYMBOL(byte_cntr_init);
diff --git a/drivers/hwtracing/coresight/coresight-byte-cntr.h b/drivers/hwtracing/coresight/coresight-byte-cntr.h
new file mode 100644
index 0000000..94e9089
--- /dev/null
+++ b/drivers/hwtracing/coresight/coresight-byte-cntr.h
@@ -0,0 +1,24 @@
+#ifndef _CORESIGHT_BYTE_CNTR_H
+#define _CORESIGHT_BYTE_CNTR_H
+#include <linux/cdev.h>
+#include <linux/amba/bus.h>
+#include <linux/wait.h>
+#include <linux/mutex.h>
+
+struct byte_cntr {
+ struct cdev dev;
+ struct class *driver_class;
+ bool enable;
+ bool read_active;
+ uint32_t byte_cntr_value;
+ uint32_t block_size;
+ int byte_cntr_irq;
+ atomic_t irq_cnt;
+ wait_queue_head_t wq;
+ struct mutex byte_cntr_lock;
+};
+
+extern void tmc_etr_byte_cntr_start(struct byte_cntr *byte_cntr_data);
+extern void tmc_etr_byte_cntr_stop(struct byte_cntr *byte_cntr_data);
+
+#endif
diff --git a/drivers/hwtracing/coresight/coresight-priv.h b/drivers/hwtracing/coresight/coresight-priv.h
index 3af358a..afe9f3d 100644
--- a/drivers/hwtracing/coresight/coresight-priv.h
+++ b/drivers/hwtracing/coresight/coresight-priv.h
@@ -153,12 +153,14 @@
extern void msm_qdss_csr_disable_bam_to_usb(void);
extern void msm_qdss_csr_disable_flush(void);
extern int coresight_csr_hwctrl_set(uint64_t addr, uint32_t val);
+extern void coresight_csr_set_byte_cntr(uint32_t count);
#else
static inline void msm_qdss_csr_enable_bam_to_usb(void) {}
static inline void msm_qdss_csr_disable_bam_to_usb(void) {}
static inline void msm_qdss_csr_disable_flush(void) {}
-static inline int coresight_csr_hwctrl_set(uint64_t addr, 95
+static inline int coresight_csr_hwctrl_set(uint64_t addr,
uint32_t val) { return -EINVAL; }
+static inline void coresight_csr_set_byte_cntr(uint32_t count) {}
#endif
#endif
diff --git a/drivers/hwtracing/coresight/coresight-tmc-etr.c b/drivers/hwtracing/coresight/coresight-tmc-etr.c
index 2a5a1bd..9e024ce 100644
--- a/drivers/hwtracing/coresight/coresight-tmc-etr.c
+++ b/drivers/hwtracing/coresight/coresight-tmc-etr.c
@@ -351,7 +351,7 @@
tmc_etr_sg_tbl_flush(vaddr, size);
}
-static void tmc_etr_sg_rwp_pos(struct tmc_drvdata *drvdata, uint32_t rwp)
+void tmc_etr_sg_rwp_pos(struct tmc_drvdata *drvdata, uint32_t rwp)
{
uint32_t i = 0, pte_n = 0, last_pte;
uint32_t *virt_st_tbl, *virt_pte;
@@ -403,6 +403,7 @@
break;
}
}
+EXPORT_SYMBOL(tmc_etr_sg_rwp_pos);
static void tmc_etr_mem_reset(struct tmc_drvdata *drvdata)
{
@@ -831,6 +832,8 @@
drvdata->sticky_enable = true;
out:
spin_unlock_irqrestore(&drvdata->spinlock, flags);
+ if (drvdata->out_mode == TMC_ETR_OUT_MODE_MEM)
+ tmc_etr_byte_cntr_start(drvdata->byte_cntr);
mutex_unlock(&drvdata->mem_lock);
if (!ret)
@@ -919,6 +922,7 @@
if (drvdata->out_mode == TMC_ETR_OUT_MODE_MEM) {
coresight_cti_unmap_trigin(drvdata->cti_reset, 2, 0);
coresight_cti_unmap_trigout(drvdata->cti_flush, 3, 0);
+ tmc_etr_byte_cntr_stop(drvdata->byte_cntr);
}
out:
mutex_unlock(&drvdata->mem_lock);
@@ -990,6 +994,11 @@
goto out;
}
+ if (!drvdata->byte_cntr || drvdata->byte_cntr->enable) {
+ ret = -EINVAL;
+ goto out;
+ }
+
/* Disable the TMC if need be */
if (val == CS_MODE_SYSFS)
tmc_etr_disable_hw(drvdata);
diff --git a/drivers/hwtracing/coresight/coresight-tmc.c b/drivers/hwtracing/coresight/coresight-tmc.c
index b97ebb8..6f13eb3 100644
--- a/drivers/hwtracing/coresight/coresight-tmc.c
+++ b/drivers/hwtracing/coresight/coresight-tmc.c
@@ -459,6 +459,42 @@
}
static DEVICE_ATTR_RW(mem_type);
+static ssize_t block_size_show(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct tmc_drvdata *drvdata = dev_get_drvdata(dev->parent);
+ uint32_t val = 0;
+
+ if (drvdata->byte_cntr)
+ val = drvdata->byte_cntr->block_size;
+
+ return scnprintf(buf, PAGE_SIZE, "%d\n",
+ val);
+}
+
+static ssize_t block_size_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf,
+ size_t size)
+{
+ struct tmc_drvdata *drvdata = dev_get_drvdata(dev->parent);
+ unsigned long val;
+
+ if (kstrtoul(buf, 0, &val))
+ return -EINVAL;
+
+ if (!drvdata->byte_cntr)
+ return -EINVAL;
+
+ mutex_lock(&drvdata->byte_cntr->byte_cntr_lock);
+ drvdata->byte_cntr->block_size = val * 8;
+ mutex_unlock(&drvdata->byte_cntr->byte_cntr_lock);
+
+ return size;
+}
+static DEVICE_ATTR_RW(block_size);
+
static struct attribute *coresight_tmc_etf_attrs[] = {
&dev_attr_trigger_cntr.attr,
NULL,
@@ -470,6 +506,7 @@
&dev_attr_trigger_cntr.attr,
&dev_attr_out_mode.attr,
&dev_attr_available_out_modes.attr,
+ &dev_attr_block_size.attr,
NULL,
};
@@ -587,6 +624,8 @@
desc.groups = coresight_tmc_etr_groups;
desc.subtype.sink_subtype = CORESIGHT_DEV_SUBTYPE_SINK_BUFFER;
+ drvdata->byte_cntr = byte_cntr_init(adev, drvdata);
+
ret = tmc_etr_bam_init(adev, drvdata);
if (ret)
goto out;
diff --git a/drivers/hwtracing/coresight/coresight-tmc.h b/drivers/hwtracing/coresight/coresight-tmc.h
index 6643adc..fe6bc76 100644
--- a/drivers/hwtracing/coresight/coresight-tmc.h
+++ b/drivers/hwtracing/coresight/coresight-tmc.h
@@ -27,6 +27,8 @@
#include <linux/usb/usb_qdss.h>
#include <linux/coresight-cti.h>
+#include "coresight-byte-cntr.h"
+
#define TMC_RSZ 0x004
#define TMC_STS 0x00c
#define TMC_RRD 0x010
@@ -167,7 +169,7 @@
bool enable;
char *buf;
dma_addr_t paddr;
- void __iomem *vaddr;
+ void *vaddr;
u32 size;
u32 len;
local_t mode;
@@ -187,6 +189,7 @@
bool sticky_enable;
struct coresight_cti *cti_flush;
struct coresight_cti *cti_reset;
+ struct byte_cntr *byte_cntr;
};
/* Generic functions */
@@ -214,5 +217,9 @@
struct usb_qdss_ch *ch);
int tmc_etr_bam_init(struct amba_device *adev,
struct tmc_drvdata *drvdata);
+extern struct byte_cntr *byte_cntr_init(struct amba_device *adev,
+ struct tmc_drvdata *drvdata);
+extern void tmc_etr_sg_rwp_pos(struct tmc_drvdata *drvdata, uint32_t rwp);
+
extern const struct coresight_ops tmc_etr_cs_ops;
#endif
diff --git a/drivers/hwtracing/intel_th/pci.c b/drivers/hwtracing/intel_th/pci.c
index 0bba384..63b5db4 100644
--- a/drivers/hwtracing/intel_th/pci.c
+++ b/drivers/hwtracing/intel_th/pci.c
@@ -85,6 +85,16 @@
PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0xa2a6),
.driver_data = (kernel_ulong_t)0,
},
+ {
+ /* Cannon Lake H */
+ PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0xa326),
+ .driver_data = (kernel_ulong_t)0,
+ },
+ {
+ /* Cannon Lake LP */
+ PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x9da6),
+ .driver_data = (kernel_ulong_t)0,
+ },
{ 0 },
};
diff --git a/drivers/i2c/busses/i2c-qcom-geni.c b/drivers/i2c/busses/i2c-qcom-geni.c
index 7264381..7e9999b 100644
--- a/drivers/i2c/busses/i2c-qcom-geni.c
+++ b/drivers/i2c/busses/i2c-qcom-geni.c
@@ -448,8 +448,8 @@
int stretch = (i < (num - 1));
dma_cookie_t tx_cookie, rx_cookie;
struct msm_gpi_tre *go_t = &gi2c->go_t;
- struct device *rx_dev = gi2c->dev;
- struct device *tx_dev = gi2c->dev;
+ struct device *rx_dev = gi2c->wrapper_dev;
+ struct device *tx_dev = gi2c->wrapper_dev;
gi2c->cur = &msgs[i];
if (!gi2c->cfg_sent) {
@@ -480,9 +480,8 @@
if (msgs[i].flags & I2C_M_RD) {
sg_init_table(&gi2c->rx_sg, 1);
- gi2c->rx_ph = dma_map_single(rx_dev, msgs[i].buf,
- msgs[i].len,
- DMA_FROM_DEVICE);
+ geni_se_iommu_map_buf(rx_dev, &gi2c->rx_ph, msgs[i].buf,
+ msgs[i].len, DMA_FROM_DEVICE);
gi2c->rx_t.dword[0] =
MSM_GPI_DMA_W_BUFFER_TRE_DWORD0(gi2c->rx_ph);
gi2c->rx_t.dword[1] =
@@ -512,9 +511,8 @@
rx_cookie = dmaengine_submit(gi2c->rx_desc);
dma_async_issue_pending(gi2c->rx_c);
} else {
- gi2c->tx_ph = dma_map_single(tx_dev, msgs[i].buf,
- msgs[i].len,
- DMA_TO_DEVICE);
+ geni_se_iommu_map_buf(tx_dev, &gi2c->tx_ph, msgs[i].buf,
+ msgs[i].len, DMA_TO_DEVICE);
gi2c->tx_t.dword[0] =
MSM_GPI_DMA_W_BUFFER_TRE_DWORD0(gi2c->tx_ph);
gi2c->tx_t.dword[1] =
@@ -547,11 +545,11 @@
timeout = wait_for_completion_timeout(&gi2c->xfer, HZ);
if (msgs[i].flags & I2C_M_RD)
- dma_unmap_single(rx_dev, gi2c->rx_ph, msgs[i].len,
- DMA_FROM_DEVICE);
+ geni_se_iommu_unmap_buf(rx_dev, &gi2c->rx_ph,
+ msgs[i].len, DMA_FROM_DEVICE);
else
- dma_unmap_single(tx_dev, gi2c->tx_ph, msgs[i].len,
- DMA_TO_DEVICE);
+ geni_se_iommu_unmap_buf(tx_dev, &gi2c->tx_ph,
+ msgs[i].len, DMA_TO_DEVICE);
if (!timeout) {
GENI_SE_ERR(gi2c->ipcl, true, gi2c->dev,
diff --git a/drivers/iio/adc/ti-ads1015.c b/drivers/iio/adc/ti-ads1015.c
index cde6f13..472641f 100644
--- a/drivers/iio/adc/ti-ads1015.c
+++ b/drivers/iio/adc/ti-ads1015.c
@@ -80,18 +80,12 @@
8, 16, 32, 64, 128, 250, 475, 860
};
-static const struct {
- int scale;
- int uscale;
-} ads1015_scale[] = {
- {3, 0},
- {2, 0},
- {1, 0},
- {0, 500000},
- {0, 250000},
- {0, 125000},
- {0, 125000},
- {0, 125000},
+/*
+ * Translation from PGA bits to full-scale positive and negative input voltage
+ * range in mV
+ */
+static int ads1015_fullscale_range[] = {
+ 6144, 4096, 2048, 1024, 512, 256, 256, 256
};
#define ADS1015_V_CHAN(_chan, _addr) { \
@@ -182,6 +176,12 @@
struct ads1015_channel_data channel_data[ADS1015_CHANNELS];
unsigned int *data_rate;
+ /*
+ * Set to true when the ADC is switched to the continuous-conversion
+ * mode and exits from a power-down state. This flag is used to avoid
+ * getting the stale result from the conversion register.
+ */
+ bool conv_invalid;
};
static bool ads1015_is_writeable_reg(struct device *dev, unsigned int reg)
@@ -234,33 +234,43 @@
ret = pm_runtime_put_autosuspend(dev);
}
- return ret;
+ return ret < 0 ? ret : 0;
}
static
int ads1015_get_adc_result(struct ads1015_data *data, int chan, int *val)
{
int ret, pga, dr, conv_time;
- bool change;
+ unsigned int old, mask, cfg;
if (chan < 0 || chan >= ADS1015_CHANNELS)
return -EINVAL;
- pga = data->channel_data[chan].pga;
- dr = data->channel_data[chan].data_rate;
-
- ret = regmap_update_bits_check(data->regmap, ADS1015_CFG_REG,
- ADS1015_CFG_MUX_MASK |
- ADS1015_CFG_PGA_MASK,
- chan << ADS1015_CFG_MUX_SHIFT |
- pga << ADS1015_CFG_PGA_SHIFT,
- &change);
- if (ret < 0)
+ ret = regmap_read(data->regmap, ADS1015_CFG_REG, &old);
+ if (ret)
return ret;
- if (change) {
- conv_time = DIV_ROUND_UP(USEC_PER_SEC, data->data_rate[dr]);
+ pga = data->channel_data[chan].pga;
+ dr = data->channel_data[chan].data_rate;
+ mask = ADS1015_CFG_MUX_MASK | ADS1015_CFG_PGA_MASK |
+ ADS1015_CFG_DR_MASK;
+ cfg = chan << ADS1015_CFG_MUX_SHIFT | pga << ADS1015_CFG_PGA_SHIFT |
+ dr << ADS1015_CFG_DR_SHIFT;
+
+ cfg = (old & ~mask) | (cfg & mask);
+
+ ret = regmap_write(data->regmap, ADS1015_CFG_REG, cfg);
+ if (ret)
+ return ret;
+
+ if (old != cfg || data->conv_invalid) {
+ int dr_old = (old & ADS1015_CFG_DR_MASK) >>
+ ADS1015_CFG_DR_SHIFT;
+
+ conv_time = DIV_ROUND_UP(USEC_PER_SEC, data->data_rate[dr_old]);
+ conv_time += DIV_ROUND_UP(USEC_PER_SEC, data->data_rate[dr]);
usleep_range(conv_time, conv_time + 1);
+ data->conv_invalid = false;
}
return regmap_read(data->regmap, ADS1015_CONV_REG, val);
@@ -297,17 +307,20 @@
return IRQ_HANDLED;
}
-static int ads1015_set_scale(struct ads1015_data *data, int chan,
+static int ads1015_set_scale(struct ads1015_data *data,
+ struct iio_chan_spec const *chan,
int scale, int uscale)
{
int i, ret, rindex = -1;
+ int fullscale = div_s64((scale * 1000000LL + uscale) <<
+ (chan->scan_type.realbits - 1), 1000000);
- for (i = 0; i < ARRAY_SIZE(ads1015_scale); i++)
- if (ads1015_scale[i].scale == scale &&
- ads1015_scale[i].uscale == uscale) {
+ for (i = 0; i < ARRAY_SIZE(ads1015_fullscale_range); i++) {
+ if (ads1015_fullscale_range[i] == fullscale) {
rindex = i;
break;
}
+ }
if (rindex < 0)
return -EINVAL;
@@ -317,32 +330,23 @@
if (ret < 0)
return ret;
- data->channel_data[chan].pga = rindex;
+ data->channel_data[chan->address].pga = rindex;
return 0;
}
static int ads1015_set_data_rate(struct ads1015_data *data, int chan, int rate)
{
- int i, ret, rindex = -1;
+ int i;
- for (i = 0; i < ARRAY_SIZE(ads1015_data_rate); i++)
+ for (i = 0; i < ARRAY_SIZE(ads1015_data_rate); i++) {
if (data->data_rate[i] == rate) {
- rindex = i;
- break;
+ data->channel_data[chan].data_rate = i;
+ return 0;
}
- if (rindex < 0)
- return -EINVAL;
+ }
- ret = regmap_update_bits(data->regmap, ADS1015_CFG_REG,
- ADS1015_CFG_DR_MASK,
- rindex << ADS1015_CFG_DR_SHIFT);
- if (ret < 0)
- return ret;
-
- data->channel_data[chan].data_rate = rindex;
-
- return 0;
+ return -EINVAL;
}
static int ads1015_read_raw(struct iio_dev *indio_dev,
@@ -384,9 +388,9 @@
}
case IIO_CHAN_INFO_SCALE:
idx = data->channel_data[chan->address].pga;
- *val = ads1015_scale[idx].scale;
- *val2 = ads1015_scale[idx].uscale;
- ret = IIO_VAL_INT_PLUS_MICRO;
+ *val = ads1015_fullscale_range[idx];
+ *val2 = chan->scan_type.realbits - 1;
+ ret = IIO_VAL_FRACTIONAL_LOG2;
break;
case IIO_CHAN_INFO_SAMP_FREQ:
idx = data->channel_data[chan->address].data_rate;
@@ -413,7 +417,7 @@
mutex_lock(&data->lock);
switch (mask) {
case IIO_CHAN_INFO_SCALE:
- ret = ads1015_set_scale(data, chan->address, val, val2);
+ ret = ads1015_set_scale(data, chan, val, val2);
break;
case IIO_CHAN_INFO_SAMP_FREQ:
ret = ads1015_set_data_rate(data, chan->address, val);
@@ -445,7 +449,10 @@
.validate_scan_mask = &iio_validate_scan_mask_onehot,
};
-static IIO_CONST_ATTR(scale_available, "3 2 1 0.5 0.25 0.125");
+static IIO_CONST_ATTR_NAMED(ads1015_scale_available, scale_available,
+ "3 2 1 0.5 0.25 0.125");
+static IIO_CONST_ATTR_NAMED(ads1115_scale_available, scale_available,
+ "0.1875 0.125 0.0625 0.03125 0.015625 0.007813");
static IIO_CONST_ATTR_NAMED(ads1015_sampling_frequency_available,
sampling_frequency_available, "128 250 490 920 1600 2400 3300");
@@ -453,7 +460,7 @@
sampling_frequency_available, "8 16 32 64 128 250 475 860");
static struct attribute *ads1015_attributes[] = {
- &iio_const_attr_scale_available.dev_attr.attr,
+ &iio_const_attr_ads1015_scale_available.dev_attr.attr,
&iio_const_attr_ads1015_sampling_frequency_available.dev_attr.attr,
NULL,
};
@@ -463,7 +470,7 @@
};
static struct attribute *ads1115_attributes[] = {
- &iio_const_attr_scale_available.dev_attr.attr,
+ &iio_const_attr_ads1115_scale_available.dev_attr.attr,
&iio_const_attr_ads1115_sampling_frequency_available.dev_attr.attr,
NULL,
};
@@ -624,6 +631,15 @@
dev_err(&client->dev, "iio triggered buffer setup failed\n");
return ret;
}
+
+ ret = regmap_update_bits(data->regmap, ADS1015_CFG_REG,
+ ADS1015_CFG_MOD_MASK,
+ ADS1015_CONTINUOUS << ADS1015_CFG_MOD_SHIFT);
+ if (ret)
+ return ret;
+
+ data->conv_invalid = true;
+
ret = pm_runtime_set_active(&client->dev);
if (ret)
goto err_buffer_cleanup;
@@ -679,10 +695,15 @@
{
struct iio_dev *indio_dev = i2c_get_clientdata(to_i2c_client(dev));
struct ads1015_data *data = iio_priv(indio_dev);
+ int ret;
- return regmap_update_bits(data->regmap, ADS1015_CFG_REG,
+ ret = regmap_update_bits(data->regmap, ADS1015_CFG_REG,
ADS1015_CFG_MOD_MASK,
ADS1015_CONTINUOUS << ADS1015_CFG_MOD_SHIFT);
+ if (!ret)
+ data->conv_invalid = true;
+
+ return ret;
}
#endif
diff --git a/drivers/input/mouse/trackpoint.c b/drivers/input/mouse/trackpoint.c
index ce6ff9b..7e2dc5e 100644
--- a/drivers/input/mouse/trackpoint.c
+++ b/drivers/input/mouse/trackpoint.c
@@ -381,8 +381,8 @@
return 0;
if (trackpoint_read(&psmouse->ps2dev, TP_EXT_BTN, &button_info)) {
- psmouse_warn(psmouse, "failed to get extended button data\n");
- button_info = 0;
+ psmouse_warn(psmouse, "failed to get extended button data, assuming 3 buttons\n");
+ button_info = 0x33;
}
psmouse->private = kzalloc(sizeof(struct trackpoint_data), GFP_KERNEL);
diff --git a/drivers/iommu/arm-smmu.c b/drivers/iommu/arm-smmu.c
index d49fd55..a0e1f59 100644
--- a/drivers/iommu/arm-smmu.c
+++ b/drivers/iommu/arm-smmu.c
@@ -51,6 +51,9 @@
#include <linux/of_platform.h>
#include <linux/msm-bus.h>
#include <dt-bindings/msm/msm-bus-ids.h>
+#include <linux/remote_spinlock.h>
+#include <linux/ktime.h>
+#include <trace/events/iommu.h>
#include <linux/amba/bus.h>
@@ -428,6 +431,7 @@
#define ARM_SMMU_OPT_3LVL_TABLES (1 << 4)
#define ARM_SMMU_OPT_NO_ASID_RETENTION (1 << 5)
#define ARM_SMMU_OPT_DISABLE_ATOS (1 << 6)
+#define ARM_SMMU_OPT_QCOM_MMU500_ERRATA1 (1 << 7)
u32 options;
enum arm_smmu_arch_version version;
enum arm_smmu_implementation model;
@@ -527,6 +531,9 @@
struct mutex assign_lock;
struct list_head secure_pool_list;
struct iommu_domain domain;
+
+ bool qsmmuv500_errata1_init;
+ bool qsmmuv500_errata1_client;
};
static DEFINE_SPINLOCK(arm_smmu_devices_lock);
@@ -549,6 +556,7 @@
{ ARM_SMMU_OPT_3LVL_TABLES, "qcom,use-3-lvl-tables" },
{ ARM_SMMU_OPT_NO_ASID_RETENTION, "qcom,no-asid-retention" },
{ ARM_SMMU_OPT_DISABLE_ATOS, "qcom,disable-atos" },
+ { ARM_SMMU_OPT_QCOM_MMU500_ERRATA1, "qcom,mmu500-errata-1" },
{ 0, NULL},
};
@@ -574,6 +582,7 @@
static int arm_smmu_alloc_cb(struct iommu_domain *domain,
struct arm_smmu_device *smmu,
struct device *dev);
+static struct iommu_gather_ops qsmmuv500_errata1_smmu_gather_ops;
static struct arm_smmu_domain *to_smmu_domain(struct iommu_domain *dom)
{
@@ -1228,11 +1237,12 @@
{
struct arm_smmu_domain *smmu_domain = to_smmu_domain(domain);
struct arm_smmu_device *smmu = smmu_domain->smmu;
+ const struct iommu_gather_ops *tlb = smmu_domain->pgtbl_cfg.tlb;
phys_addr_t phys;
phys_addr_t phys_post_tlbiall;
phys = arm_smmu_iova_to_phys_hard(domain, iova);
- arm_smmu_tlb_inv_context(smmu_domain);
+ tlb->tlb_flush_all(smmu_domain);
phys_post_tlbiall = arm_smmu_iova_to_phys_hard(domain, iova);
if (phys != phys_post_tlbiall) {
@@ -1588,6 +1598,7 @@
bool is_fast = smmu_domain->attributes & (1 << DOMAIN_ATTR_FAST);
unsigned long quirks = 0;
bool dynamic;
+ const struct iommu_gather_ops *tlb;
mutex_lock(&smmu_domain->init_mutex);
if (smmu_domain->smmu)
@@ -1702,6 +1713,13 @@
quirks |= IO_PGTABLE_QUIRK_QCOM_USE_UPSTREAM_HINT;
if (is_iommu_pt_coherent(smmu_domain))
quirks |= IO_PGTABLE_QUIRK_PAGE_TABLE_COHERENT;
+ if ((quirks & IO_PGTABLE_QUIRK_QCOM_USE_UPSTREAM_HINT) &&
+ (smmu->model == QCOM_SMMUV500))
+ quirks |= IO_PGTABLE_QUIRK_QSMMUV500_NON_SHAREABLE;
+
+ tlb = &arm_smmu_gather_ops;
+ if (smmu->options & ARM_SMMU_OPT_QCOM_MMU500_ERRATA1)
+ tlb = &qsmmuv500_errata1_smmu_gather_ops;
ret = arm_smmu_alloc_cb(domain, smmu, dev);
if (ret < 0)
@@ -1720,7 +1738,7 @@
.pgsize_bitmap = smmu->pgsize_bitmap,
.ias = ias,
.oas = oas,
- .tlb = &arm_smmu_gather_ops,
+ .tlb = tlb,
.iommu_dev = smmu->dev,
};
@@ -2378,6 +2396,8 @@
if (ret)
return ret;
+ arm_smmu_secure_domain_lock(smmu_domain);
+
__saved_iova_start = iova;
idx_start = idx_end = 0;
sg_start = sg_end = sg;
@@ -2415,6 +2435,7 @@
arm_smmu_unmap(domain, __saved_iova_start, size_to_unmap);
iova = __saved_iova_start;
}
+ arm_smmu_secure_domain_unlock(smmu_domain);
arm_smmu_domain_power_off(domain, smmu_domain->smmu);
return iova - __saved_iova_start;
}
@@ -3138,7 +3159,10 @@
static void arm_smmu_tlbi_domain(struct iommu_domain *domain)
{
- arm_smmu_tlb_inv_context(to_smmu_domain(domain));
+ struct arm_smmu_domain *smmu_domain = to_smmu_domain(domain);
+ const struct iommu_gather_ops *tlb = smmu_domain->pgtbl_cfg.tlb;
+
+ tlb->tlb_flush_all(smmu_domain);
}
static int arm_smmu_enable_config_clocks(struct iommu_domain *domain)
@@ -4300,6 +4324,14 @@
struct list_head tbus;
void __iomem *tcu_base;
u32 version;
+
+ struct actlr_setting *actlrs;
+ u32 actlr_tbl_size;
+
+ struct arm_smmu_smr *errata1_clients;
+ u32 num_errata1_clients;
+ remote_spinlock_t errata1_lock;
+ ktime_t last_tlbi_ktime;
};
#define get_qsmmuv500_archdata(smmu) \
((struct qsmmuv500_archdata *)(smmu->archdata))
@@ -4320,6 +4352,118 @@
u32 halt_count;
};
+static bool arm_smmu_domain_match_smr(struct arm_smmu_domain *smmu_domain,
+ struct arm_smmu_smr *smr)
+{
+ struct arm_smmu_smr *smr2;
+ int i, idx;
+
+ for_each_cfg_sme(smmu_domain->dev->iommu_fwspec, i, idx) {
+ smr2 = &smmu_domain->smmu->smrs[idx];
+ /* Continue if table entry does not match */
+ if ((smr->id ^ smr2->id) & ~(smr->mask | smr2->mask))
+ continue;
+ return true;
+ }
+ return false;
+}
+
+#define ERRATA1_REMOTE_SPINLOCK "S:6"
+#define ERRATA1_TLBI_INTERVAL_US 10
+static bool
+qsmmuv500_errata1_required(struct arm_smmu_domain *smmu_domain,
+ struct qsmmuv500_archdata *data)
+{
+ bool ret = false;
+ int j;
+ struct arm_smmu_smr *smr;
+
+ if (smmu_domain->qsmmuv500_errata1_init)
+ return smmu_domain->qsmmuv500_errata1_client;
+
+ for (j = 0; j < data->num_errata1_clients; j++) {
+ smr = &data->errata1_clients[j];
+ if (arm_smmu_domain_match_smr(smmu_domain, smr)) {
+ ret = true;
+ break;
+ }
+ }
+
+ smmu_domain->qsmmuv500_errata1_init = true;
+ smmu_domain->qsmmuv500_errata1_client = ret;
+ return ret;
+}
+
+static void __qsmmuv500_errata1_tlbiall(struct arm_smmu_domain *smmu_domain)
+{
+ struct arm_smmu_device *smmu = smmu_domain->smmu;
+ struct device *dev = smmu_domain->dev;
+ struct arm_smmu_cfg *cfg = &smmu_domain->cfg;
+ void __iomem *base;
+ ktime_t cur;
+ u32 val;
+
+ base = ARM_SMMU_CB_BASE(smmu) + ARM_SMMU_CB(smmu, cfg->cbndx);
+ writel_relaxed(0, base + ARM_SMMU_CB_S1_TLBIALL);
+ writel_relaxed(0, base + ARM_SMMU_CB_TLBSYNC);
+ if (readl_poll_timeout_atomic(base + ARM_SMMU_CB_TLBSTATUS, val,
+ !(val & TLBSTATUS_SACTIVE), 0, 100)) {
+ cur = ktime_get();
+ trace_errata_throttle_start(dev, 0);
+
+ msm_bus_noc_throttle_wa(true);
+ if (readl_poll_timeout_atomic(base + ARM_SMMU_CB_TLBSTATUS, val,
+ !(val & TLBSTATUS_SACTIVE), 0, 10000)) {
+ dev_err(smmu->dev, "ERRATA1 TLBSYNC timeout");
+ trace_errata_failed(dev, 0);
+ }
+
+ msm_bus_noc_throttle_wa(false);
+
+ trace_errata_throttle_end(
+ dev, ktime_us_delta(ktime_get(), cur));
+ }
+}
+
+/* Must be called with clocks/regulators enabled */
+static void qsmmuv500_errata1_tlb_inv_context(void *cookie)
+{
+ struct arm_smmu_domain *smmu_domain = cookie;
+ struct device *dev = smmu_domain->dev;
+ struct qsmmuv500_archdata *data =
+ get_qsmmuv500_archdata(smmu_domain->smmu);
+ ktime_t cur;
+ bool errata;
+
+ cur = ktime_get();
+ trace_errata_tlbi_start(dev, 0);
+
+ errata = qsmmuv500_errata1_required(smmu_domain, data);
+ remote_spin_lock(&data->errata1_lock);
+ if (errata) {
+ s64 delta;
+
+ delta = ktime_us_delta(ktime_get(), data->last_tlbi_ktime);
+ if (delta < ERRATA1_TLBI_INTERVAL_US)
+ udelay(ERRATA1_TLBI_INTERVAL_US - delta);
+
+ __qsmmuv500_errata1_tlbiall(smmu_domain);
+
+ data->last_tlbi_ktime = ktime_get();
+ } else {
+ __qsmmuv500_errata1_tlbiall(smmu_domain);
+ }
+ remote_spin_unlock(&data->errata1_lock);
+
+ trace_errata_tlbi_end(dev, ktime_us_delta(ktime_get(), cur));
+}
+
+static struct iommu_gather_ops qsmmuv500_errata1_smmu_gather_ops = {
+ .tlb_flush_all = qsmmuv500_errata1_tlb_inv_context,
+ .alloc_pages_exact = arm_smmu_alloc_pages_exact,
+ .free_pages_exact = arm_smmu_free_pages_exact,
+};
+
static int qsmmuv500_tbu_halt(struct qsmmuv500_tbu_device *tbu)
{
unsigned long flags;
@@ -4592,6 +4736,38 @@
return 0;
}
+static int qsmmuv500_parse_errata1(struct arm_smmu_device *smmu)
+{
+ int len, i;
+ struct device *dev = smmu->dev;
+ struct qsmmuv500_archdata *data = get_qsmmuv500_archdata(smmu);
+ struct arm_smmu_smr *smrs;
+ const __be32 *cell;
+
+ cell = of_get_property(dev->of_node, "qcom,mmu500-errata-1", NULL);
+ if (!cell)
+ return 0;
+
+ remote_spin_lock_init(&data->errata1_lock, ERRATA1_REMOTE_SPINLOCK);
+ len = of_property_count_elems_of_size(
+ dev->of_node, "qcom,mmu500-errata-1", sizeof(u32) * 2);
+ if (len < 0)
+ return 0;
+
+ smrs = devm_kzalloc(dev, sizeof(*smrs) * len, GFP_KERNEL);
+ if (!smrs)
+ return -ENOMEM;
+
+ for (i = 0; i < len; i++) {
+ smrs[i].id = of_read_number(cell++, 1);
+ smrs[i].mask = of_read_number(cell++, 1);
+ }
+
+ data->errata1_clients = smrs;
+ data->num_errata1_clients = len;
+ return 0;
+}
+
static int qsmmuv500_arch_init(struct arm_smmu_device *smmu)
{
struct resource *res;
@@ -4615,6 +4791,10 @@
data->version = readl_relaxed(data->tcu_base + TCU_HW_VERSION_HLOS1);
smmu->archdata = data;
+ ret = qsmmuv500_parse_errata1(smmu);
+ if (ret)
+ return ret;
+
ret = of_platform_populate(dev->of_node, NULL, NULL, dev);
if (ret)
return ret;
diff --git a/drivers/iommu/io-pgtable-arm.c b/drivers/iommu/io-pgtable-arm.c
index dde2876..a3594d2 100644
--- a/drivers/iommu/io-pgtable-arm.c
+++ b/drivers/iommu/io-pgtable-arm.c
@@ -1011,6 +1011,11 @@
reg = (ARM_LPAE_TCR_SH_OS << ARM_LPAE_TCR_SH0_SHIFT) |
(ARM_LPAE_TCR_RGN_WBWA << ARM_LPAE_TCR_IRGN0_SHIFT) |
(ARM_LPAE_TCR_RGN_WBWA << ARM_LPAE_TCR_ORGN0_SHIFT);
+ else if ((cfg->quirks & IO_PGTABLE_QUIRK_QCOM_USE_UPSTREAM_HINT) &&
+ (cfg->quirks & IO_PGTABLE_QUIRK_QSMMUV500_NON_SHAREABLE))
+ reg = (ARM_LPAE_TCR_SH_NS << ARM_LPAE_TCR_SH0_SHIFT) |
+ (ARM_LPAE_TCR_RGN_NC << ARM_LPAE_TCR_IRGN0_SHIFT) |
+ (ARM_LPAE_TCR_RGN_WBWA << ARM_LPAE_TCR_ORGN0_SHIFT);
else if (cfg->quirks & IO_PGTABLE_QUIRK_QCOM_USE_UPSTREAM_HINT)
reg = (ARM_LPAE_TCR_SH_OS << ARM_LPAE_TCR_SH0_SHIFT) |
(ARM_LPAE_TCR_RGN_NC << ARM_LPAE_TCR_IRGN0_SHIFT) |
diff --git a/drivers/iommu/io-pgtable.h b/drivers/iommu/io-pgtable.h
index a686ad0..b35016e 100644
--- a/drivers/iommu/io-pgtable.h
+++ b/drivers/iommu/io-pgtable.h
@@ -81,6 +81,12 @@
*
* IO_PGTABLE_QUIRK_PAGE_TABLE_COHERENT: Set the page table as
* coherent.
+ *
+ * IO_PGTABLE_QUIRK_QSMMUV500_NON_SHAREABLE:
+ * Having page tables which are non coherent, but cached in a
+ * system cache requires SH=Non-Shareable. This applies to the
+ * qsmmuv500 model. For data buffers SH=Non-Shareable is not
+ * required.
*/
#define IO_PGTABLE_QUIRK_ARM_NS BIT(0)
#define IO_PGTABLE_QUIRK_NO_PERMS BIT(1)
@@ -88,6 +94,7 @@
#define IO_PGTABLE_QUIRK_ARM_MTK_4GB BIT(3)
#define IO_PGTABLE_QUIRK_QCOM_USE_UPSTREAM_HINT BIT(4)
#define IO_PGTABLE_QUIRK_PAGE_TABLE_COHERENT BIT(5)
+ #define IO_PGTABLE_QUIRK_QSMMUV500_NON_SHAREABLE BIT(6)
unsigned long quirks;
unsigned long pgsize_bitmap;
unsigned int ias;
diff --git a/drivers/irqchip/irq-gic-v3.c b/drivers/irqchip/irq-gic-v3.c
index 779001e..01f9435 100644
--- a/drivers/irqchip/irq-gic-v3.c
+++ b/drivers/irqchip/irq-gic-v3.c
@@ -132,6 +132,45 @@
}
#endif
+/*
+ * gic_show_pending_irq - Shows the pending interrupts
+ * Note: Interrupts should be disabled on the cpu from which
+ * this is called to get accurate list of pending interrupts.
+ */
+void gic_show_pending_irqs(void)
+{
+ void __iomem *base;
+ u32 pending[32], enabled;
+ unsigned int j;
+
+ base = gic_data.dist_base;
+ for (j = 0; j * 32 < gic_data.irq_nr; j++) {
+ enabled = readl_relaxed(base +
+ GICD_ISENABLER + j * 4);
+ pending[j] = readl_relaxed(base +
+ GICD_ISPENDR + j * 4);
+ pending[j] &= enabled;
+ pr_err("Pending irqs[%d] %x\n", j, pending[j]);
+ }
+}
+
+/*
+ * get_gic_highpri_irq - Returns next high priority interrupt on current CPU
+ */
+unsigned int get_gic_highpri_irq(void)
+{
+ unsigned long flags;
+ unsigned int val = 0;
+
+ local_irq_save(flags);
+ val = read_gicreg(ICC_HPPIR1_EL1);
+ local_irq_restore(flags);
+
+ if (val >= 1020)
+ return 0;
+ return val;
+}
+
static void gic_enable_redist(bool enable)
{
void __iomem *rbase;
diff --git a/drivers/leds/leds-qpnp.c b/drivers/leds/leds-qpnp.c
index ab0e4f9..e3cfffb 100644
--- a/drivers/leds/leds-qpnp.c
+++ b/drivers/leds/leds-qpnp.c
@@ -875,6 +875,14 @@
}
if (led->mpp_cfg->pwm_mode == PWM_MODE) {
/*config pwm for brightness scaling*/
+ rc = pwm_change_mode(led->mpp_cfg->pwm_cfg->pwm_dev,
+ PM_PWM_MODE_PWM);
+ if (rc < 0) {
+ dev_err(&led->pdev->dev,
+ "Failed to set PWM mode, rc = %d\n",
+ rc);
+ return rc;
+ }
period_us = led->mpp_cfg->pwm_cfg->pwm_period_us;
if (period_us > INT_MAX / NSEC_PER_USEC) {
duty_us = (period_us * led->cdev.brightness) /
@@ -1581,6 +1589,14 @@
}
if (led->kpdbl_cfg->pwm_cfg->mode == PWM_MODE) {
+ rc = pwm_change_mode(led->kpdbl_cfg->pwm_cfg->pwm_dev,
+ PM_PWM_MODE_PWM);
+ if (rc < 0) {
+ dev_err(&led->pdev->dev,
+ "Failed to set PWM mode, rc = %d\n",
+ rc);
+ return rc;
+ }
period_us = led->kpdbl_cfg->pwm_cfg->pwm_period_us;
if (period_us > INT_MAX / NSEC_PER_USEC) {
duty_us = (period_us * led->cdev.brightness) /
@@ -1702,6 +1718,14 @@
led->rgb_cfg->pwm_cfg->mode =
led->rgb_cfg->pwm_cfg->default_mode;
if (led->rgb_cfg->pwm_cfg->mode == PWM_MODE) {
+ rc = pwm_change_mode(led->rgb_cfg->pwm_cfg->pwm_dev,
+ PM_PWM_MODE_PWM);
+ if (rc < 0) {
+ dev_err(&led->pdev->dev,
+ "Failed to set PWM mode, rc = %d\n",
+ rc);
+ return rc;
+ }
period_us = led->rgb_cfg->pwm_cfg->pwm_period_us;
if (period_us > INT_MAX / NSEC_PER_USEC) {
duty_us = (period_us * led->cdev.brightness) /
@@ -2136,6 +2160,11 @@
dev_err(&pdev->dev, "Failed to configure pwm LUT\n");
return rc;
}
+ rc = pwm_change_mode(pwm_cfg->pwm_dev, PM_PWM_MODE_LPG);
+ if (rc < 0) {
+ dev_err(&pdev->dev, "Failed to set LPG mode\n");
+ return rc;
+ }
}
} else {
dev_err(&pdev->dev, "Invalid PWM device\n");
diff --git a/drivers/mailbox/msm_qmp.c b/drivers/mailbox/msm_qmp.c
index f0bb0bc..3b07c47 100644
--- a/drivers/mailbox/msm_qmp.c
+++ b/drivers/mailbox/msm_qmp.c
@@ -27,7 +27,7 @@
#define QMP_VERSION 0x1
#define QMP_FEATURES 0x0
#define QMP_TOUT_MS 5000
-#define QMP_TX_TOUT_MS 2000
+#define QMP_TX_TOUT_MS 1000
#define QMP_MBOX_LINK_DOWN 0xFFFF0000
#define QMP_MBOX_LINK_UP 0x0000FFFF
@@ -229,7 +229,7 @@
}
/**
- * qmp_notify_timeout() - Notify client of tx timeout with -EIO
+ * qmp_notify_timeout() - Notify client of tx timeout with -ETIME
* @work: Structure for work that was scheduled.
*/
static void qmp_notify_timeout(struct work_struct *work)
@@ -237,7 +237,7 @@
struct delayed_work *dwork = to_delayed_work(work);
struct qmp_mbox *mbox = container_of(dwork, struct qmp_mbox, dwork);
struct mbox_chan *chan = &mbox->ctrl.chans[mbox->idx_in_flight];
- int err = -EIO;
+ int err = -ETIME;
unsigned long flags;
spin_lock_irqsave(&mbox->tx_lock, flags);
@@ -246,6 +246,7 @@
return;
}
pr_err("%s: qmp tx timeout for %d\n", __func__, mbox->idx_in_flight);
+ iowrite32(0, mbox->mdev->msgram + mbox->mcore_mbox_offset);
mbox->tx_sent = false;
spin_unlock_irqrestore(&mbox->tx_lock, flags);
mbox_chan_txdone(chan, err);
diff --git a/drivers/mcb/mcb-lpc.c b/drivers/mcb/mcb-lpc.c
index d072c08..945091a 100644
--- a/drivers/mcb/mcb-lpc.c
+++ b/drivers/mcb/mcb-lpc.c
@@ -114,6 +114,12 @@
.flags = IORESOURCE_MEM,
};
+static struct resource sc31_fpga_resource = {
+ .start = 0xf000e000,
+ .end = 0xf000e000 + CHAM_HEADER_SIZE,
+ .flags = IORESOURCE_MEM,
+};
+
static struct platform_driver mcb_lpc_driver = {
.driver = {
.name = "mcb-lpc",
@@ -132,6 +138,15 @@
.driver_data = (void *)&sc24_fpga_resource,
.callback = mcb_lpc_create_platform_device,
},
+ {
+ .ident = "SC31",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "MEN"),
+ DMI_MATCH(DMI_PRODUCT_VERSION, "14SC31"),
+ },
+ .driver_data = (void *)&sc31_fpga_resource,
+ .callback = mcb_lpc_create_platform_device,
+ },
{}
};
MODULE_DEVICE_TABLE(dmi, mcb_lpc_dmi_table);
diff --git a/drivers/md/raid5.c b/drivers/md/raid5.c
index 383f19c..549b4af 100644
--- a/drivers/md/raid5.c
+++ b/drivers/md/raid5.c
@@ -5844,6 +5844,8 @@
spin_unlock_irq(&conf->device_lock);
+ r5l_flush_stripe_to_raid(conf->log);
+
async_tx_issue_pending_all();
blk_finish_plug(&plug);
diff --git a/drivers/media/platform/msm/camera/cam_core/cam_node.c b/drivers/media/platform/msm/camera/cam_core/cam_node.c
index 043f44d..3a78b5e 100644
--- a/drivers/media/platform/msm/camera/cam_core/cam_node.c
+++ b/drivers/media/platform/msm/camera/cam_core/cam_node.c
@@ -256,7 +256,7 @@
return -EINVAL;
}
- trace_cam_apply_req("Node", apply);
+ trace_cam_apply_req("Node", apply->request_id);
return cam_context_handle_crm_apply_req(ctx, apply);
}
diff --git a/drivers/media/platform/msm/camera/cam_cpas/cpas_top/cam_cpastop_hw.c b/drivers/media/platform/msm/camera/cam_cpas/cpas_top/cam_cpastop_hw.c
index d9133b9..e3d46df 100644
--- a/drivers/media/platform/msm/camera/cam_cpas/cpas_top/cam_cpastop_hw.c
+++ b/drivers/media/platform/msm/camera/cam_cpas/cpas_top/cam_cpastop_hw.c
@@ -402,9 +402,10 @@
CAM_CPAS_POLL_RETRY_CNT,
CAM_CPAS_POLL_MIN_USECS, CAM_CPAS_POLL_MAX_USECS);
if (rc) {
- CAM_ERR(CAM_CPAS,
+ CAM_DBG(CAM_CPAS,
"camnoc flush slave pending trans failed");
/* Do not return error, passthrough */
+ rc = 0;
}
}
diff --git a/drivers/media/platform/msm/camera/cam_cpas/cpas_top/cpastop_v170_110.h b/drivers/media/platform/msm/camera/cam_cpas/cpas_top/cpastop_v170_110.h
index f4d0e36..918258d 100644
--- a/drivers/media/platform/msm/camera/cam_cpas/cpas_top/cpastop_v170_110.h
+++ b/drivers/media/platform/msm/camera/cam_cpas/cpas_top/cpastop_v170_110.h
@@ -515,7 +515,7 @@
static struct cam_cpas_hw_errata_wa_list cam170_cpas110_errata_wa_list = {
.camnoc_flush_slave_pending_trans = {
- .enable = true,
+ .enable = false,
.data.reg_info = {
.access_type = CAM_REG_TYPE_READ,
.offset = 0x2100, /* SidebandManager_SenseIn0_Low */
diff --git a/drivers/media/platform/msm/camera/cam_fd/cam_fd_context.c b/drivers/media/platform/msm/camera/cam_fd/cam_fd_context.c
index 4c29ffd..f23c4c1 100644
--- a/drivers/media/platform/msm/camera/cam_fd/cam_fd_context.c
+++ b/drivers/media/platform/msm/camera/cam_fd/cam_fd_context.c
@@ -15,6 +15,7 @@
#include "cam_debug_util.h"
#include "cam_fd_context.h"
+#include "cam_trace.h"
/* Functions in Available state */
static int __cam_fd_ctx_acquire_dev_in_available(struct cam_context *ctx,
@@ -29,6 +30,7 @@
}
ctx->state = CAM_CTX_ACQUIRED;
+ trace_cam_context_state("FD", ctx);
return rc;
}
@@ -46,6 +48,7 @@
}
ctx->state = CAM_CTX_AVAILABLE;
+ trace_cam_context_state("FD", ctx);
return rc;
}
@@ -76,6 +79,7 @@
}
ctx->state = CAM_CTX_ACTIVATED;
+ trace_cam_context_state("FD", ctx);
return rc;
}
@@ -93,6 +97,7 @@
}
ctx->state = CAM_CTX_ACQUIRED;
+ trace_cam_context_state("FD", ctx);
return rc;
}
diff --git a/drivers/media/platform/msm/camera/cam_fd/fd_hw_mgr/cam_fd_hw_mgr.c b/drivers/media/platform/msm/camera/cam_fd/fd_hw_mgr/cam_fd_hw_mgr.c
index d226e17..37e6954 100644
--- a/drivers/media/platform/msm/camera/cam_fd/fd_hw_mgr/cam_fd_hw_mgr.c
+++ b/drivers/media/platform/msm/camera/cam_fd/fd_hw_mgr/cam_fd_hw_mgr.c
@@ -26,6 +26,7 @@
#include "cam_fd_hw_soc.h"
#include "cam_fd_hw_mgr_intf.h"
#include "cam_fd_hw_mgr.h"
+#include "cam_trace.h"
static struct cam_fd_hw_mgr g_fd_hw_mgr;
@@ -334,7 +335,7 @@
/* Update required info in hw context */
hw_ctx->device_index = i;
- CAM_DBG(CAM_FD, "ctx index=%d, hw_ctx=%d", hw_ctx->ctx_index,
+ CAM_DBG(CAM_FD, "ctx index=%d, device_index=%d", hw_ctx->ctx_index,
hw_ctx->device_index);
return 0;
@@ -480,6 +481,53 @@
return rc;
}
+static int cam_fd_mgr_util_get_buf_map_requirement(uint32_t direction,
+ uint32_t resource_type, bool *need_io_map, bool *need_cpu_map)
+{
+ if (!need_io_map || !need_cpu_map) {
+ CAM_ERR(CAM_FD, "Invalid input pointers %pK %pK", need_io_map,
+ need_cpu_map);
+ return -EINVAL;
+ }
+
+ if (direction == CAM_BUF_INPUT) {
+ switch (resource_type) {
+ case CAM_FD_INPUT_PORT_ID_IMAGE:
+ *need_io_map = true;
+ *need_cpu_map = false;
+ break;
+ default:
+ CAM_WARN(CAM_FD, "Invalid port: dir %d, id %d",
+ direction, resource_type);
+ return -EINVAL;
+ }
+ } else if (direction == CAM_BUF_OUTPUT) {
+ switch (resource_type) {
+ case CAM_FD_OUTPUT_PORT_ID_RESULTS:
+ *need_io_map = true;
+ *need_cpu_map = true;
+ break;
+ case CAM_FD_OUTPUT_PORT_ID_RAW_RESULTS:
+ *need_io_map = true;
+ *need_cpu_map = true;
+ break;
+ case CAM_FD_OUTPUT_PORT_ID_WORK_BUFFER:
+ *need_io_map = true;
+ *need_cpu_map = false;
+ break;
+ default:
+ CAM_WARN(CAM_FD, "Invalid port: dir %d, id %d",
+ direction, resource_type);
+ return -EINVAL;
+ }
+ } else {
+ CAM_WARN(CAM_FD, "Invalid direction %d", direction);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
static int cam_fd_mgr_util_prepare_io_buf_info(int32_t iommu_hdl,
struct cam_hw_prepare_update_args *prepare,
struct cam_fd_hw_io_buffer *input_buf,
@@ -491,6 +539,7 @@
uint64_t io_addr[CAM_PACKET_MAX_PLANES];
uint64_t cpu_addr[CAM_PACKET_MAX_PLANES];
size_t size;
+ bool need_io_map, need_cpu_map;
/* Get IO Buf information */
num_out_buf = 0;
@@ -512,32 +561,55 @@
return -EINVAL;
}
+ rc = cam_fd_mgr_util_get_buf_map_requirement(
+ io_cfg[i].direction, io_cfg[i].resource_type,
+ &need_io_map, &need_cpu_map);
+ if (rc) {
+ CAM_WARN(CAM_FD, "Invalid io buff [%d] : %d %d %d",
+ i, io_cfg[i].direction,
+ io_cfg[i].resource_type, rc);
+ continue;
+ }
+
memset(io_addr, 0x0, sizeof(io_addr));
for (plane = 0; plane < CAM_PACKET_MAX_PLANES; plane++) {
if (!io_cfg[i].mem_handle[plane])
break;
- rc = cam_mem_get_io_buf(io_cfg[i].mem_handle[plane],
- iommu_hdl, &io_addr[plane], &size);
- if ((rc) || (io_addr[plane] >> 32)) {
- CAM_ERR(CAM_FD, "Invalid io addr for %d %d",
- plane, rc);
- return -ENOMEM;
+ io_addr[plane] = 0x0;
+ cpu_addr[plane] = 0x0;
+
+ if (need_io_map) {
+ rc = cam_mem_get_io_buf(
+ io_cfg[i].mem_handle[plane],
+ iommu_hdl, &io_addr[plane], &size);
+ if ((rc) || (io_addr[plane] >> 32)) {
+ CAM_ERR(CAM_FD,
+ "Invalid io buf %d %d %d %d",
+ io_cfg[i].direction,
+ io_cfg[i].resource_type, plane,
+ rc);
+ return -ENOMEM;
+ }
+
+ io_addr[plane] += io_cfg[i].offsets[plane];
}
- /*
- * Buffers may be accessed by CPU as well, we do not
- * know at this point, so get both and send to HW layer
- */
- rc = cam_mem_get_cpu_buf(io_cfg[i].mem_handle[plane],
- &cpu_addr[plane], &size);
- if (rc) {
- CAM_ERR(CAM_FD, "unable to get buf address");
- return rc;
- }
+ if (need_cpu_map) {
+ rc = cam_mem_get_cpu_buf(
+ io_cfg[i].mem_handle[plane],
+ &cpu_addr[plane], &size);
+ if (rc) {
+ CAM_ERR(CAM_FD,
+ "Invalid cpu buf %d %d %d %d",
+ io_cfg[i].direction,
+ io_cfg[i].resource_type, plane,
+ rc);
+ return rc;
+ }
- io_addr[plane] += io_cfg[i].offsets[plane];
- cpu_addr[plane] += io_cfg[i].offsets[plane];
+ cpu_addr[plane] += io_cfg[i].offsets[plane];
+ }
CAM_DBG(CAM_FD, "IO Address[%d][%d] : %pK, %pK",
io_cfg[i].direction, plane, io_addr[plane],
@@ -764,6 +836,8 @@
return -EBUSY;
}
+ trace_cam_submit_to_hw("FD", frame_req->request_id);
+
list_del_init(&frame_req->list);
mutex_unlock(&hw_mgr->frame_req_mutex);
@@ -924,6 +998,8 @@
frame_abort = false;
}
+ trace_cam_irq_handled("FD", irq_type);
+
notify_context:
/* Do a callback to inform frame done or stop done */
if (frame_req->hw_ctx->event_cb) {
@@ -1158,7 +1234,7 @@
return -EPERM;
}
- CAM_DBG(CAM_FD, "ctx index=%d, hw_ctx=%d", hw_ctx->ctx_index,
+ CAM_DBG(CAM_FD, "ctx index=%d, device_index=%d", hw_ctx->ctx_index,
hw_ctx->device_index);
rc = cam_fd_mgr_util_get_device(hw_mgr, hw_ctx, &hw_device);
@@ -1300,7 +1376,7 @@
/* We do not expect any patching, but just do it anyway */
rc = cam_packet_util_process_patches(prepare->packet,
- hw_mgr->device_iommu.non_secure);
+ hw_mgr->device_iommu.non_secure, -1);
if (rc) {
CAM_ERR(CAM_FD, "Patch FD packet failed, rc=%d", rc);
return rc;
@@ -1389,6 +1465,8 @@
}
frame_req = config->priv;
+
+ trace_cam_apply_req("FD", frame_req->request_id);
CAM_DBG(CAM_FD, "FrameHWConfig : Frame[%lld]", frame_req->request_id);
frame_req->num_hw_update_entries = config->num_hw_update_entries;
diff --git a/drivers/media/platform/msm/camera/cam_fd/fd_hw_mgr/fd_hw/cam_fd_hw_core.c b/drivers/media/platform/msm/camera/cam_fd/fd_hw_mgr/fd_hw/cam_fd_hw_core.c
index 51fcdcaa..11a81d6 100644
--- a/drivers/media/platform/msm/camera/cam_fd/fd_hw_mgr/fd_hw/cam_fd_hw_core.c
+++ b/drivers/media/platform/msm/camera/cam_fd/fd_hw_mgr/fd_hw/cam_fd_hw_core.c
@@ -12,6 +12,7 @@
#include "cam_fd_hw_core.h"
#include "cam_fd_hw_soc.h"
+#include "cam_trace.h"
#define CAM_FD_REG_VAL_PAIR_SIZE 256
@@ -30,6 +31,7 @@
static void cam_fd_hw_util_cdm_callback(uint32_t handle, void *userdata,
enum cam_cdm_cb_status status, uint32_t cookie)
{
+ trace_cam_cdm_cb("FD", status);
CAM_DBG(CAM_FD, "CDM hdl=%x, udata=%pK, status=%d, cookie=%d",
handle, userdata, status, cookie);
}
@@ -110,9 +112,6 @@
/* Before triggering reset to HW, clear the reset complete */
reinit_completion(&fd_core->reset_complete);
- cam_fd_soc_register_write(soc_info, CAM_FD_REG_CORE,
- hw_static_info->core_regs.control, 0x1);
-
if (hw_static_info->enable_errata_wa.single_irq_only) {
cam_fd_soc_register_write(soc_info, CAM_FD_REG_WRAPPER,
hw_static_info->wrapper_regs.irq_mask,
@@ -124,13 +123,11 @@
time_left = wait_for_completion_timeout(&fd_core->reset_complete,
msecs_to_jiffies(CAM_FD_HW_HALT_RESET_TIMEOUT));
- if (time_left <= 0) {
- CAM_ERR(CAM_FD, "HW reset wait failed time_left=%d", time_left);
- return -EPERM;
- }
+ if (time_left <= 0)
+ CAM_WARN(CAM_FD, "HW reset timeout time_left=%d", time_left);
cam_fd_soc_register_write(soc_info, CAM_FD_REG_CORE,
- hw_static_info->core_regs.control, 0x0);
+ hw_static_info->core_regs.control, 0x1);
CAM_DBG(CAM_FD, "FD Wrapper SW Sync Reset complete");
@@ -148,9 +145,6 @@
/* Before triggering halt to HW, clear halt complete */
reinit_completion(&fd_core->halt_complete);
- cam_fd_soc_register_write(soc_info, CAM_FD_REG_CORE,
- hw_static_info->core_regs.control, 0x1);
-
if (hw_static_info->enable_errata_wa.single_irq_only) {
cam_fd_soc_register_write(soc_info, CAM_FD_REG_WRAPPER,
hw_static_info->wrapper_regs.irq_mask,
@@ -162,13 +156,8 @@
time_left = wait_for_completion_timeout(&fd_core->halt_complete,
msecs_to_jiffies(CAM_FD_HW_HALT_RESET_TIMEOUT));
- if (time_left <= 0) {
- CAM_ERR(CAM_FD, "HW halt wait failed time_left=%d", time_left);
- return -EPERM;
- }
-
- cam_fd_soc_register_write(soc_info, CAM_FD_REG_CORE,
- hw_static_info->core_regs.control, 0x0);
+ if (time_left <= 0)
+ CAM_WARN(CAM_FD, "HW halt timeout time_left=%d", time_left);
CAM_DBG(CAM_FD, "FD Wrapper Halt complete");
@@ -397,12 +386,22 @@
prestart_args->pre_config_buf_size =
prestart_args->size - available_size;
- /*
- * Currently, no post config commands, we trigger HW start directly
- * from start(). Start trigger command can be inserted into CDM
- * as post config commands.
- */
- prestart_args->post_config_buf_size = 0;
+ /* Insert start trigger command into CDM as post config commands. */
+ num_cmds = cam_fd_cdm_write_reg_val_pair(reg_val_pair, 0,
+ hw_static_info->core_regs.control, 0x2);
+ size = ctx_hw_private->cdm_ops->cdm_required_size_reg_random(
+ num_cmds/2);
+ if ((size * 4) > available_size) {
+ CAM_ERR(CAM_FD, "Insufficient size:%d , expected size:%d",
+ available_size, size);
+ return -ENOMEM;
+ }
+ ctx_hw_private->cdm_ops->cdm_write_regrandom(cmd_buf_addr, num_cmds/2,
+ reg_val_pair);
+ cmd_buf_addr += size;
+ available_size -= (size * 4);
+
+ prestart_args->post_config_buf_size = size * 4;
CAM_DBG(CAM_FD, "PreConfig [%pK %d], PostConfig[%pK %d]",
prestart_args->cmd_buf_addr, prestart_args->pre_config_buf_size,
@@ -573,6 +572,8 @@
return -EINVAL;
}
+ trace_cam_irq_activated("FD", irq_type);
+
cam_fd_soc_register_write(soc_info, CAM_FD_REG_WRAPPER,
hw_static_info->wrapper_regs.irq_clear,
hw_static_info->irq_mask);
@@ -795,6 +796,12 @@
fd_core->core_state = CAM_FD_CORE_STATE_RESET_PROGRESS;
spin_unlock(&fd_core->spin_lock);
+ rc = cam_fd_hw_util_fdwrapper_halt(fd_hw);
+ if (rc) {
+ CAM_ERR(CAM_FD, "Failed in HALT rc=%d", rc);
+ return rc;
+ }
+
rc = cam_fd_hw_util_fdwrapper_sync_reset(fd_hw);
if (rc) {
CAM_ERR(CAM_FD, "Failed in RESET rc=%d", rc);
@@ -893,9 +900,6 @@
goto error;
}
- cam_fd_soc_register_write(&fd_hw->soc_info, CAM_FD_REG_CORE,
- hw_static_info->core_regs.control, 0x2);
-
return 0;
error:
spin_lock(&fd_core->spin_lock);
diff --git a/drivers/media/platform/msm/camera/cam_fd/fd_hw_mgr/fd_hw/cam_fd_hw_core.h b/drivers/media/platform/msm/camera/cam_fd/fd_hw_mgr/fd_hw/cam_fd_hw_core.h
index 35bf6b6..bdd72af 100644
--- a/drivers/media/platform/msm/camera/cam_fd/fd_hw_mgr/fd_hw/cam_fd_hw_core.h
+++ b/drivers/media/platform/msm/camera/cam_fd/fd_hw_mgr/fd_hw/cam_fd_hw_core.h
@@ -30,7 +30,7 @@
#define CAM_FD_IRQ_TO_MASK(irq) (1 << (irq))
#define CAM_FD_MASK_TO_IRQ(mask, irq) ((mask) >> (irq))
-#define CAM_FD_HW_HALT_RESET_TIMEOUT 3000
+#define CAM_FD_HW_HALT_RESET_TIMEOUT 100
/**
* enum cam_fd_core_state - FD Core internal states
diff --git a/drivers/media/platform/msm/camera/cam_icp/cam_icp_subdev.c b/drivers/media/platform/msm/camera/cam_icp/cam_icp_subdev.c
index bbdff27..8a0d5f7 100644
--- a/drivers/media/platform/msm/camera/cam_icp/cam_icp_subdev.c
+++ b/drivers/media/platform/msm/camera/cam_icp/cam_icp_subdev.c
@@ -41,8 +41,8 @@
struct cam_icp_subdev {
struct cam_subdev sd;
struct cam_node *node;
- struct cam_context ctx[CAM_CTX_MAX];
- struct cam_icp_context ctx_icp[CAM_CTX_MAX];
+ struct cam_context ctx[CAM_ICP_CTX_MAX];
+ struct cam_icp_context ctx_icp[CAM_ICP_CTX_MAX];
struct mutex icp_lock;
int32_t open_cnt;
int32_t reserved;
@@ -164,7 +164,7 @@
goto hw_init_fail;
}
- for (i = 0; i < CAM_CTX_MAX; i++) {
+ for (i = 0; i < CAM_ICP_CTX_MAX; i++) {
g_icp_dev.ctx_icp[i].base = &g_icp_dev.ctx[i];
rc = cam_icp_context_init(&g_icp_dev.ctx_icp[i],
hw_mgr_intf);
@@ -175,7 +175,7 @@
}
rc = cam_node_init(node, hw_mgr_intf, g_icp_dev.ctx,
- CAM_CTX_MAX, CAM_ICP_DEV_NAME);
+ CAM_ICP_CTX_MAX, CAM_ICP_DEV_NAME);
if (rc) {
CAM_ERR(CAM_ICP, "ICP node init failed");
goto ctx_fail;
@@ -220,7 +220,7 @@
return -ENODEV;
}
- for (i = 0; i < CAM_CTX_MAX; i++)
+ for (i = 0; i < CAM_ICP_CTX_MAX; i++)
cam_icp_context_deinit(&g_icp_dev.ctx_icp[i]);
cam_node_deinit(g_icp_dev.node);
cam_subdev_remove(&g_icp_dev.sd);
diff --git a/drivers/media/platform/msm/camera/cam_icp/icp_hw/icp_hw_mgr/cam_icp_hw_mgr.c b/drivers/media/platform/msm/camera/cam_icp/icp_hw/icp_hw_mgr/cam_icp_hw_mgr.c
index 7c5b405..3354e2c 100644
--- a/drivers/media/platform/msm/camera/cam_icp/icp_hw/icp_hw_mgr/cam_icp_hw_mgr.c
+++ b/drivers/media/platform/msm/camera/cam_icp/icp_hw/icp_hw_mgr/cam_icp_hw_mgr.c
@@ -880,6 +880,12 @@
buf_data.request_id = hfi_frame_process->request_id[idx];
ctx_data->ctxt_event_cb(ctx_data->context_priv, flag, &buf_data);
hfi_frame_process->request_id[idx] = 0;
+ if (ctx_data->hfi_frame_process.in_resource[idx] > 0) {
+ CAM_DBG(CAM_ICP, "Delete merged sync in object: %d",
+ ctx_data->hfi_frame_process.in_resource[idx]);
+ cam_sync_destroy(ctx_data->hfi_frame_process.in_resource[idx]);
+ ctx_data->hfi_frame_process.in_resource[idx] = 0;
+ }
clear_bit(idx, ctx_data->hfi_frame_process.bitmap);
hfi_frame_process->fw_process_flag[idx] = false;
mutex_unlock(&ctx_data->ctx_mutex);
@@ -1550,6 +1556,7 @@
cam_icp_mgr_device_deinit(hw_mgr);
cam_icp_free_hfi_mem();
hw_mgr->fw_download = false;
+ hw_mgr->secure_mode = CAM_SECURE_MODE_NON_SECURE;
mutex_unlock(&hw_mgr->hw_mgr_mutex);
return rc;
@@ -1973,13 +1980,16 @@
return rc;
}
-static void cam_icp_mgr_process_io_cfg(struct cam_icp_hw_mgr *hw_mgr,
+static int cam_icp_mgr_process_io_cfg(struct cam_icp_hw_mgr *hw_mgr,
struct cam_icp_hw_ctx_data *ctx_data,
struct cam_packet *packet,
- struct cam_hw_prepare_update_args *prepare_args)
+ struct cam_hw_prepare_update_args *prepare_args,
+ int32_t index)
{
- int i, j, k;
+ int i, j, k, rc = 0;
struct cam_buf_io_cfg *io_cfg_ptr = NULL;
+ int32_t sync_in_obj[CAM_MAX_OUT_RES];
+ int32_t merged_sync_in_obj;
io_cfg_ptr = (struct cam_buf_io_cfg *) ((uint32_t *) &packet->payload +
packet->io_configs_offset/4);
@@ -1988,8 +1998,7 @@
for (i = 0, j = 0, k = 0; i < packet->num_io_configs; i++) {
if (io_cfg_ptr[i].direction == CAM_BUF_INPUT) {
- prepare_args->in_map_entries[j++].sync_id =
- io_cfg_ptr[i].fence;
+ sync_in_obj[j++] = io_cfg_ptr[i].fence;
prepare_args->num_in_map_entries++;
} else {
prepare_args->out_map_entries[k++].sync_id =
@@ -1999,6 +2008,33 @@
CAM_DBG(CAM_ICP, "dir[%d]: %u, fence: %u",
i, io_cfg_ptr[i].direction, io_cfg_ptr[i].fence);
}
+
+ if (prepare_args->num_in_map_entries > 1) {
+ rc = cam_sync_merge(&sync_in_obj[0],
+ prepare_args->num_in_map_entries, &merged_sync_in_obj);
+ if (rc) {
+ prepare_args->num_out_map_entries = 0;
+ prepare_args->num_in_map_entries = 0;
+ return rc;
+ }
+
+ ctx_data->hfi_frame_process.in_resource[index] =
+ merged_sync_in_obj;
+ prepare_args->in_map_entries[0].sync_id = merged_sync_in_obj;
+ prepare_args->num_in_map_entries = 1;
+ CAM_DBG(CAM_ICP, "Merged Sync obj = %d", merged_sync_in_obj);
+ } else if (prepare_args->num_in_map_entries == 1) {
+ prepare_args->in_map_entries[0].sync_id = sync_in_obj[0];
+ prepare_args->num_in_map_entries = 1;
+ ctx_data->hfi_frame_process.in_resource[index] = 0;
+ } else {
+ CAM_ERR(CAM_ICP, "No input fences");
+ prepare_args->num_in_map_entries = 0;
+ ctx_data->hfi_frame_process.in_resource[index] = 0;
+ rc = -EINVAL;
+ }
+
+ return rc;
}
static int cam_icp_packet_generic_blob_handler(void *user_data,
@@ -2146,21 +2182,28 @@
}
/* Update Buffer Address from handles and patch information */
- rc = cam_packet_util_process_patches(packet, hw_mgr->iommu_hdl);
+ rc = cam_packet_util_process_patches(packet, hw_mgr->iommu_hdl,
+ hw_mgr->iommu_sec_hdl);
if (rc) {
mutex_unlock(&ctx_data->ctx_mutex);
return rc;
}
- cam_icp_mgr_process_io_cfg(hw_mgr, ctx_data,
- packet, prepare_args);
-
rc = cam_icp_mgr_update_hfi_frame_process(ctx_data, packet,
prepare_args, &idx);
if (rc) {
- if (prepare_args->in_map_entries[0].sync_id > 0)
+ mutex_unlock(&ctx_data->ctx_mutex);
+ return rc;
+ }
+
+ rc = cam_icp_mgr_process_io_cfg(hw_mgr, ctx_data,
+ packet, prepare_args, idx);
+ if (rc) {
+ if (ctx_data->hfi_frame_process.in_resource[idx] > 0)
cam_sync_destroy(
- prepare_args->in_map_entries[0].sync_id);
+ ctx_data->hfi_frame_process.in_resource[idx]);
+ clear_bit(idx, ctx_data->hfi_frame_process.bitmap);
+ ctx_data->hfi_frame_process.request_id[idx] = -1;
mutex_unlock(&ctx_data->ctx_mutex);
return rc;
}
@@ -2195,6 +2238,13 @@
/* now release memory for hfi frame process command */
hfi_frame_process->request_id[idx] = 0;
+ if (ctx_data->hfi_frame_process.in_resource[idx] > 0) {
+ CAM_DBG(CAM_ICP, "Delete merged sync in object: %d",
+ ctx_data->hfi_frame_process.in_resource[idx]);
+ cam_sync_destroy(
+ ctx_data->hfi_frame_process.in_resource[idx]);
+ ctx_data->hfi_frame_process.in_resource[idx] = 0;
+ }
clear_bit(idx, ctx_data->hfi_frame_process.bitmap);
}
mutex_unlock(&ctx_data->ctx_mutex);
@@ -2239,6 +2289,7 @@
NULL, 0);
cam_icp_mgr_hw_close(hw_mgr, NULL);
cam_icp_hw_mgr_reset_clk_info(hw_mgr);
+ hw_mgr->secure_mode = CAM_SECURE_MODE_NON_SECURE;
}
return rc;
@@ -2384,6 +2435,12 @@
sizeof(struct cam_icp_acquire_dev_info)))
return -EFAULT;
+ if (icp_dev_acquire_info.secure_mode > CAM_SECURE_MODE_SECURE) {
+ CAM_ERR(CAM_ICP, "Invalid mode:%d",
+ icp_dev_acquire_info.secure_mode);
+ return -EINVAL;
+ }
+
if (icp_dev_acquire_info.num_out_res > ICP_MAX_OUTPUT_SUPPORTED) {
CAM_ERR(CAM_ICP, "num of out resources exceeding : %u",
icp_dev_acquire_info.num_out_res);
@@ -2396,28 +2453,46 @@
return -EFAULT;
}
+ if (!hw_mgr->ctxt_cnt) {
+ hw_mgr->secure_mode = icp_dev_acquire_info.secure_mode;
+ } else {
+ if (hw_mgr->secure_mode != icp_dev_acquire_info.secure_mode) {
+ CAM_ERR(CAM_ICP,
+ "secure mode mismatch driver:%d, context:%d",
+ hw_mgr->secure_mode,
+ icp_dev_acquire_info.secure_mode);
+ return -EINVAL;
+ }
+ }
+
acquire_size = sizeof(struct cam_icp_acquire_dev_info) +
(icp_dev_acquire_info.num_out_res *
sizeof(struct cam_icp_res_info));
ctx_data->icp_dev_acquire_info = kzalloc(acquire_size, GFP_KERNEL);
- if (!ctx_data->icp_dev_acquire_info)
+ if (!ctx_data->icp_dev_acquire_info) {
+ if (!hw_mgr->ctxt_cnt)
+ hw_mgr->secure_mode = CAM_SECURE_MODE_NON_SECURE;
return -ENOMEM;
+ }
if (copy_from_user(ctx_data->icp_dev_acquire_info,
(void __user *)args->acquire_info, acquire_size)) {
+ if (!hw_mgr->ctxt_cnt)
+ hw_mgr->secure_mode = CAM_SECURE_MODE_NON_SECURE;
kfree(ctx_data->icp_dev_acquire_info);
ctx_data->icp_dev_acquire_info = NULL;
return -EFAULT;
}
- CAM_DBG(CAM_ICP, "%x %x %x %x %x %x %x",
+ CAM_DBG(CAM_ICP, "%x %x %x %x %x %x %x %u",
ctx_data->icp_dev_acquire_info->dev_type,
ctx_data->icp_dev_acquire_info->in_res.format,
ctx_data->icp_dev_acquire_info->in_res.width,
ctx_data->icp_dev_acquire_info->in_res.height,
ctx_data->icp_dev_acquire_info->in_res.fps,
ctx_data->icp_dev_acquire_info->num_out_res,
- ctx_data->icp_dev_acquire_info->scratch_mem_size);
+ ctx_data->icp_dev_acquire_info->scratch_mem_size,
+ hw_mgr->secure_mode);
p_icp_out = ctx_data->icp_dev_acquire_info->out_res;
for (i = 0; i < icp_dev_acquire_info.num_out_res; i++)
@@ -2470,18 +2545,10 @@
goto acquire_info_failed;
icp_dev_acquire_info = ctx_data->icp_dev_acquire_info;
- /* Get IOCONFIG command info */
- if (icp_dev_acquire_info->secure_mode)
- rc = cam_mem_get_io_buf(
- icp_dev_acquire_info->io_config_cmd_handle,
- hw_mgr->iommu_sec_hdl,
- &io_buf_addr, &io_buf_size);
- else
- rc = cam_mem_get_io_buf(
- icp_dev_acquire_info->io_config_cmd_handle,
- hw_mgr->iommu_hdl,
- &io_buf_addr, &io_buf_size);
-
+ rc = cam_mem_get_io_buf(
+ icp_dev_acquire_info->io_config_cmd_handle,
+ hw_mgr->iommu_hdl,
+ &io_buf_addr, &io_buf_size);
if (rc) {
CAM_ERR(CAM_ICP, "unable to get src buf info from io desc");
goto get_io_buf_failed;
@@ -2808,6 +2875,7 @@
hw_mgr_intf->download_fw = cam_icp_mgr_download_fw;
hw_mgr_intf->hw_close = cam_icp_mgr_hw_close;
+ icp_hw_mgr.secure_mode = CAM_SECURE_MODE_NON_SECURE;
mutex_init(&icp_hw_mgr.hw_mgr_mutex);
spin_lock_init(&icp_hw_mgr.hw_mgr_lock);
@@ -2820,7 +2888,7 @@
rc = cam_smmu_get_handle("icp", &icp_hw_mgr.iommu_hdl);
if (rc) {
- CAM_ERR(CAM_ICP, "icp get iommu handle failed: %d", rc);
+ CAM_ERR(CAM_ICP, "get mmu handle failed: %d", rc);
goto icp_get_hdl_failed;
}
@@ -2830,6 +2898,12 @@
goto icp_attach_failed;
}
+ rc = cam_smmu_get_handle("cam-secure", &icp_hw_mgr.iommu_sec_hdl);
+ if (rc) {
+ CAM_ERR(CAM_ICP, "get secure mmu handle failed: %d", rc);
+ goto secure_hdl_failed;
+ }
+
rc = cam_icp_mgr_create_wq();
if (rc)
goto icp_wq_create_failed;
@@ -2839,6 +2913,9 @@
return rc;
icp_wq_create_failed:
+ cam_smmu_destroy_handle(icp_hw_mgr.iommu_sec_hdl);
+ icp_hw_mgr.iommu_sec_hdl = -1;
+secure_hdl_failed:
cam_smmu_ops(icp_hw_mgr.iommu_hdl, CAM_SMMU_DETACH);
icp_attach_failed:
cam_smmu_destroy_handle(icp_hw_mgr.iommu_hdl);
diff --git a/drivers/media/platform/msm/camera/cam_icp/icp_hw/icp_hw_mgr/cam_icp_hw_mgr.h b/drivers/media/platform/msm/camera/cam_icp/icp_hw/icp_hw_mgr/cam_icp_hw_mgr.h
index d4f5482..d1793e6 100644
--- a/drivers/media/platform/msm/camera/cam_icp/icp_hw/icp_hw_mgr/cam_icp_hw_mgr.h
+++ b/drivers/media/platform/msm/camera/cam_icp/icp_hw/icp_hw_mgr/cam_icp_hw_mgr.h
@@ -114,6 +114,7 @@
uint64_t request_id[CAM_FRAME_CMD_MAX];
uint32_t num_out_resources[CAM_FRAME_CMD_MAX];
uint32_t out_resource[CAM_FRAME_CMD_MAX][CAM_MAX_OUT_RES];
+ uint32_t in_resource[CAM_FRAME_CMD_MAX];
uint32_t fw_process_flag[CAM_FRAME_CMD_MAX];
struct cam_icp_clk_bw_request clk_info[CAM_FRAME_CMD_MAX];
};
@@ -226,6 +227,7 @@
* @icp_debug_clk: Set clock based on debug value
* @icp_default_clk: Set this clok if user doesn't supply
* @clk_info: Clock info of hardware
+ * @secure_mode: Flag to enable/disable secure camera
*/
struct cam_icp_hw_mgr {
struct mutex hw_mgr_mutex;
@@ -255,6 +257,7 @@
uint64_t icp_debug_clk;
uint64_t icp_default_clk;
struct cam_icp_clk_info clk_info[ICP_CLK_HW_MAX];
+ bool secure_mode;
};
static int cam_icp_mgr_hw_close(void *hw_priv, void *hw_close_args);
diff --git a/drivers/media/platform/msm/camera/cam_icp/icp_hw/icp_hw_mgr/include/cam_icp_hw_intf.h b/drivers/media/platform/msm/camera/cam_icp/icp_hw/icp_hw_mgr/include/cam_icp_hw_intf.h
index 9300ea8..6915ad5 100644
--- a/drivers/media/platform/msm/camera/cam_icp/icp_hw/icp_hw_mgr/include/cam_icp_hw_intf.h
+++ b/drivers/media/platform/msm/camera/cam_icp/icp_hw/icp_hw_mgr/include/cam_icp_hw_intf.h
@@ -13,8 +13,6 @@
#ifndef CAM_ICP_HW_INTF_H
#define CAM_ICP_HW_INTF_H
-#define CAM_ICP_CTX_MAX 8
-
#define CAM_ICP_CMD_BUF_MAX_SIZE 128
#define CAM_ICP_MSG_BUF_MAX_SIZE CAM_ICP_CMD_BUF_MAX_SIZE
diff --git a/drivers/media/platform/msm/camera/cam_icp/icp_hw/include/cam_icp_hw_mgr_intf.h b/drivers/media/platform/msm/camera/cam_icp/icp_hw/include/cam_icp_hw_mgr_intf.h
index d99a878..4f6fce8 100644
--- a/drivers/media/platform/msm/camera/cam_icp/icp_hw/include/cam_icp_hw_mgr_intf.h
+++ b/drivers/media/platform/msm/camera/cam_icp/icp_hw/include/cam_icp_hw_mgr_intf.h
@@ -20,6 +20,7 @@
#define ICP_TURBO_VOTE 600000000
#define ICP_SVS_VOTE 400000000
+#define CAM_ICP_CTX_MAX 36
int cam_icp_hw_mgr_init(struct device_node *of_node,
uint64_t *hw_mgr_hdl);
diff --git a/drivers/media/platform/msm/camera/cam_isp/cam_isp_context.c b/drivers/media/platform/msm/camera/cam_isp/cam_isp_context.c
index 0ee368d..4ecb36e 100644
--- a/drivers/media/platform/msm/camera/cam_isp/cam_isp_context.c
+++ b/drivers/media/platform/msm/camera/cam_isp/cam_isp_context.c
@@ -24,6 +24,46 @@
#include "cam_trace.h"
#include "cam_debug_util.h"
+static int __cam_isp_ctx_enqueue_request_in_order(
+ struct cam_context *ctx, struct cam_ctx_request *req)
+{
+ struct cam_ctx_request *req_current;
+ struct cam_ctx_request *req_prev;
+ struct list_head temp_list;
+
+ INIT_LIST_HEAD(&temp_list);
+ spin_lock_bh(&ctx->lock);
+ if (list_empty(&ctx->pending_req_list)) {
+ list_add_tail(&req->list, &ctx->pending_req_list);
+ } else {
+ list_for_each_entry_safe_reverse(
+ req_current, req_prev, &ctx->pending_req_list, list) {
+ if (req->request_id < req_current->request_id) {
+ list_del_init(&req_current->list);
+ list_add(&req_current->list, &temp_list);
+ continue;
+ } else if (req->request_id == req_current->request_id) {
+ CAM_WARN(CAM_ISP,
+ "Received duplicated request %lld",
+ req->request_id);
+ }
+ break;
+ }
+ list_add_tail(&req->list, &ctx->pending_req_list);
+
+ if (!list_empty(&temp_list)) {
+ list_for_each_entry_safe(
+ req_current, req_prev, &temp_list, list) {
+ list_del_init(&req_current->list);
+ list_add_tail(&req_current->list,
+ &ctx->pending_req_list);
+ }
+ }
+ }
+ spin_unlock_bh(&ctx->lock);
+ return 0;
+}
+
static uint64_t __cam_isp_ctx_get_event_ts(uint32_t evt_id, void *evt_data)
{
uint64_t ts = 0;
@@ -256,7 +296,7 @@
__cam_isp_ctx_send_sof_timestamp(ctx_isp, request_id,
CAM_REQ_MGR_SOF_EVENT_SUCCESS);
} else {
- CAM_ERR(CAM_ISP, "Can not notify SOF to CRM");
+ CAM_ERR_RATE_LIMIT(CAM_ISP, "Can not notify SOF to CRM");
rc = -EFAULT;
}
@@ -574,7 +614,8 @@
*/
if (list_empty(&ctx->active_req_list)) {
- CAM_ERR(CAM_ISP, "handling error with no active request");
+ CAM_ERR_RATE_LIMIT(CAM_ISP,
+ "handling error with no active request");
rc = -EINVAL;
goto end;
}
@@ -588,10 +629,10 @@
notify.req_id = req->request_id;
ctx->ctx_crm_intf->notify_err(¬ify);
- CAM_ERR(CAM_ISP, "Notify CRM about ERROR frame %lld",
+ CAM_ERR_RATE_LIMIT(CAM_ISP, "Notify CRM about ERROR frame %lld",
ctx_isp->frame_id);
} else {
- CAM_ERR(CAM_ISP, "Can not notify ERRROR to CRM");
+ CAM_ERR_RATE_LIMIT(CAM_ISP, "Can not notify ERRROR to CRM");
rc = -EFAULT;
}
@@ -724,7 +765,7 @@
rc = ctx->hw_mgr_intf->hw_config(ctx->hw_mgr_intf->hw_mgr_priv, &cfg);
if (rc) {
- CAM_ERR(CAM_ISP, "Can not apply the configuration");
+ CAM_ERR_RATE_LIMIT(CAM_ISP, "Can not apply the configuration");
} else {
spin_lock_bh(&ctx->lock);
ctx_isp->substate_activated = next_state;
@@ -964,7 +1005,7 @@
__cam_isp_ctx_send_sof_timestamp(ctx_isp, request_id,
CAM_REQ_MGR_SOF_EVENT_SUCCESS);
} else {
- CAM_ERR(CAM_ISP, "Can not notify SOF to CRM");
+ CAM_ERR_RATE_LIMIT(CAM_ISP, "Can not notify SOF to CRM");
}
if (list_empty(&ctx->active_req_list))
@@ -1477,9 +1518,7 @@
CAM_DBG(CAM_ISP, "Packet request id 0x%llx",
packet->header.request_id);
- spin_lock_bh(&ctx->lock);
- list_add_tail(&req->list, &ctx->pending_req_list);
- spin_unlock_bh(&ctx->lock);
+ __cam_isp_ctx_enqueue_request_in_order(ctx, req);
CAM_DBG(CAM_ISP, "Preprocessing Config %lld successful",
req->request_id);
@@ -1875,7 +1914,7 @@
struct cam_isp_context *ctx_isp =
(struct cam_isp_context *) ctx->ctx_priv;
- trace_cam_apply_req("ISP", apply);
+ trace_cam_apply_req("ISP", apply->request_id);
CAM_DBG(CAM_ISP, "Enter: apply req in Substate %d request _id:%lld",
ctx_isp->substate_activated, apply->request_id);
if (ctx_isp->substate_machine[ctx_isp->substate_activated].
@@ -1883,14 +1922,16 @@
rc = ctx_isp->substate_machine[ctx_isp->substate_activated].
crm_ops.apply_req(ctx, apply);
} else {
- CAM_ERR(CAM_ISP, "No handle function in activated substate %d",
- ctx_isp->substate_activated);
+ CAM_ERR_RATE_LIMIT(CAM_ISP,
+ "No handle function in activated substate %d",
+ ctx_isp->substate_activated);
rc = -EFAULT;
}
if (rc)
- CAM_ERR(CAM_ISP, "Apply failed in active substate %d",
- ctx_isp->substate_activated);
+ CAM_ERR_RATE_LIMIT(CAM_ISP,
+ "Apply failed in active substate %d",
+ ctx_isp->substate_activated);
return rc;
}
diff --git a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c
index d0b0751..d84be30 100644
--- a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c
+++ b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c
@@ -64,7 +64,7 @@
sizeof(struct cam_isp_query_cap_cmd)))
rc = -EFAULT;
- CAM_DBG(CAM_ISP, "exit rc :%d !", rc);
+ CAM_DBG(CAM_ISP, "exit rc :%d", rc);
return rc;
}
@@ -111,7 +111,7 @@
return 0;
err:
- CAM_ERR(CAM_ISP, "INIT HW res failed! (type:%d, id:%d)",
+ CAM_ERR(CAM_ISP, "INIT HW res failed: (type:%d, id:%d)",
isp_hw_res->res_type, isp_hw_res->res_id);
return rc;
}
@@ -132,7 +132,7 @@
isp_hw_res->hw_res[i],
sizeof(struct cam_isp_resource_node));
if (rc) {
- CAM_ERR(CAM_ISP, "Can not start HW resources!");
+ CAM_ERR(CAM_ISP, "Can not start HW resources");
goto err;
}
} else {
@@ -143,7 +143,7 @@
return 0;
err:
- CAM_ERR(CAM_ISP, "Start hw res failed! (type:%d, id:%d)",
+ CAM_ERR(CAM_ISP, "Start hw res failed (type:%d, id:%d)",
isp_hw_res->res_type, isp_hw_res->res_id);
return rc;
}
@@ -210,7 +210,7 @@
struct cam_ife_hw_mgr_res, list);
list_del_init(&res_ptr->list);
} else {
- CAM_ERR(CAM_ISP, "No more free ife hw mgr ctx!");
+ CAM_ERR(CAM_ISP, "No more free ife hw mgr ctx");
rc = -1;
}
*res = res_ptr;
@@ -235,7 +235,7 @@
sizeof(struct cam_isp_resource_node));
if (rc)
CAM_ERR(CAM_ISP,
- "Release hw resrouce id %d failed!",
+ "Release hw resrouce id %d failed",
isp_hw_res->res_id);
isp_hw_res->hw_res[i] = NULL;
} else
@@ -362,7 +362,7 @@
struct cam_ife_hw_mgr_ctx, list);
list_del_init(&ctx_ptr->list);
} else {
- CAM_ERR(CAM_ISP, "No more free ife hw mgr ctx!");
+ CAM_ERR(CAM_ISP, "No more free ife hw mgr ctx");
rc = -1;
}
*ife_ctx = ctx_ptr;
@@ -417,7 +417,7 @@
uint32_t i;
if (list_empty(&ctx->res_list_ife_src)) {
- CAM_ERR(CAM_ISP, "Error! Mux List empty");
+ CAM_ERR(CAM_ISP, "Mux List empty");
return -ENODEV;
}
@@ -474,6 +474,8 @@
CAM_ERR(CAM_ISP, "invalid resource type");
goto err;
}
+ CAM_DBG(CAM_ISP, "vfe_in_res_id = %d, vfe_out_red_id = %d",
+ vfe_in_res_id, vfe_out_res_id);
vfe_acquire.rsrc_type = CAM_ISP_RESOURCE_VFE_OUT;
vfe_acquire.tasklet = ife_ctx->common.tasklet_info;
@@ -482,6 +484,9 @@
for (i = 0; i < in_port->num_out_res; i++) {
out_port = &in_port->data[i];
+ CAM_DBG(CAM_ISP, "i = %d, vfe_out_res_id = %d, out_port: %d",
+ i, vfe_out_res_id, out_port->res_type);
+
if (vfe_out_res_id != out_port->res_type)
continue;
@@ -503,7 +508,9 @@
}
if (i == in_port->num_out_res) {
- CAM_ERR(CAM_ISP, "Can not acquire out resource");
+ CAM_ERR(CAM_ISP,
+ "Cannot acquire out resource, i=%d, num_out_res=%d",
+ i, in_port->num_out_res);
goto err;
}
@@ -511,6 +518,7 @@
ife_out_res->is_dual_vfe = 0;
ife_out_res->res_id = vfe_out_res_id;
ife_out_res->res_type = CAM_ISP_RESOURCE_VFE_OUT;
+ ife_src_res->child[ife_src_res->num_children++] = ife_out_res;
return 0;
err:
@@ -633,7 +641,8 @@
ife_src_res, in_port);
break;
default:
- CAM_ERR(CAM_ISP, "Fatal: Unknown IFE SRC resource!");
+ CAM_ERR(CAM_ISP, "Unknown IFE SRC resource: %d",
+ ife_src_res->res_id);
break;
}
if (rc)
@@ -667,7 +676,7 @@
rc = cam_ife_hw_mgr_get_res(&ife_ctx->free_res_list,
&ife_src_res);
if (rc) {
- CAM_ERR(CAM_ISP, "No more free hw mgr resource!");
+ CAM_ERR(CAM_ISP, "No more free hw mgr resource");
goto err;
}
cam_ife_hw_mgr_put_res(&ife_ctx->res_list_ife_src,
@@ -706,7 +715,7 @@
vfe_acquire.vfe_in.sync_mode = CAM_ISP_HW_SYNC_NONE;
break;
default:
- CAM_ERR(CAM_ISP, "Wrong IFE CSID Resource Node!");
+ CAM_ERR(CAM_ISP, "Wrong IFE CSID Resource Node");
goto err;
}
ife_src_res->res_type = vfe_acquire.rsrc_type;
@@ -748,9 +757,11 @@
* csid resource and ife source resource
*/
csid_res->child[0] = ife_src_res;
- csid_res->num_children = 1;
ife_src_res->parent = csid_res;
csid_res->child[csid_res->num_children++] = ife_src_res;
+ CAM_DBG(CAM_ISP, "csid_res=%d num_children=%d ife_src_res=%d",
+ csid_res->res_id, csid_res->num_children,
+ ife_src_res->res_id);
}
return 0;
@@ -776,7 +787,7 @@
rc = cam_ife_hw_mgr_get_res(&ife_ctx->free_res_list, &csid_res);
if (rc) {
- CAM_ERR(CAM_ISP, "No more free hw mgr resource!");
+ CAM_ERR(CAM_ISP, "No more free hw mgr resource");
goto err;
}
cam_ife_hw_mgr_put_res(&ife_ctx->res_list_ife_csid, &csid_res);
@@ -808,11 +819,11 @@
}
if (i == CAM_IFE_CSID_HW_NUM_MAX) {
- CAM_ERR(CAM_ISP, "Can not acquire ife csid ipp resrouce!");
+ CAM_ERR(CAM_ISP, "Can not acquire ife csid ipp resource");
goto err;
}
- CAM_DBG(CAM_ISP, "acquired csid(%d) left ipp resrouce successfully!",
+ CAM_DBG(CAM_ISP, "acquired csid(%d) left ipp resource successfully",
i);
csid_res->res_type = CAM_ISP_RESOURCE_PIX_PATH;
@@ -839,18 +850,17 @@
if (j == CAM_IFE_CSID_HW_NUM_MAX) {
CAM_ERR(CAM_ISP,
- "Can not acquire ife csid rdi resrouce!");
+ "Can not acquire ife csid rdi resrouce");
goto err;
}
csid_res->hw_res[1] = csid_acquire.node_res;
CAM_DBG(CAM_ISP,
- "acquired csid(%d)right ipp resrouce successfully!", j);
+ "acquired csid(%d)right ipp resrouce successfully", j);
}
csid_res->parent = &ife_ctx->res_list_ife_in;
- ife_ctx->res_list_ife_in.child[
- ife_ctx->res_list_ife_in.num_children++] = csid_res;
+ CAM_DBG(CAM_ISP, "acquire res %d", csid_acquire.res_id);
return 0;
err:
@@ -862,7 +872,6 @@
uint32_t out_port_type)
{
enum cam_ife_pix_path_res_id path_id;
-
switch (out_port_type) {
case CAM_ISP_IFE_OUT_RES_RDI_0:
path_id = CAM_IFE_PIX_PATH_RES_RDI_0;
@@ -882,6 +891,8 @@
break;
}
+ CAM_DBG(CAM_ISP, "out_port %d path_id %d", out_port_type, path_id);
+
return path_id;
}
@@ -909,7 +920,7 @@
rc = cam_ife_hw_mgr_get_res(&ife_ctx->free_res_list,
&csid_res);
if (rc) {
- CAM_ERR(CAM_ISP, "No more free hw mgr resource!",
+ CAM_ERR(CAM_ISP, "No more free hw mgr resource",
__func__);
goto err;
}
@@ -945,7 +956,7 @@
if (j == CAM_IFE_CSID_HW_NUM_MAX) {
CAM_ERR(CAM_ISP,
- "Can not acquire ife csid rdi resrouce!");
+ "Can not acquire ife csid rdi resource");
goto err;
}
@@ -954,10 +965,8 @@
csid_res->is_dual_vfe = 0;
csid_res->hw_res[0] = csid_acquire.node_res;
csid_res->hw_res[1] = NULL;
-
+ CAM_DBG(CAM_ISP, "acquire res %d", csid_acquire.res_id);
csid_res->parent = &ife_ctx->res_list_ife_in;
- ife_ctx->res_list_ife_in.child[
- ife_ctx->res_list_ife_in.num_children++] = csid_res;
}
return 0;
@@ -978,7 +987,7 @@
ife_ctx->res_list_ife_in.res_id = in_port->res_type;
ife_ctx->res_list_ife_in.is_dual_vfe = in_port->usage_type;
} else if (ife_ctx->res_list_ife_in.res_id != in_port->res_type) {
- CAM_ERR(CAM_ISP, "No Free resource for this context!");
+ CAM_ERR(CAM_ISP, "No Free resource for this context");
goto err;
} else {
/* else do nothing */
@@ -1032,7 +1041,7 @@
/* no dual vfe for TPG */
if ((in_port->res_type == CAM_ISP_IFE_IN_RES_TPG) &&
(in_port->usage_type != 0)) {
- CAM_ERR(CAM_ISP, "No Dual VFE on TPG input!");
+ CAM_ERR(CAM_ISP, "No Dual VFE on TPG input");
goto err;
}
@@ -1040,7 +1049,7 @@
rc = cam_ife_hw_mgr_get_res(&ife_ctx->free_res_list, &cid_res);
if (rc) {
- CAM_ERR(CAM_ISP, "No more free hw mgr resource!");
+ CAM_ERR(CAM_ISP, "No more free hw mgr resource");
goto err;
}
cam_ife_hw_mgr_put_res(&ife_ctx->res_list_ife_cid, &cid_res);
@@ -1062,7 +1071,7 @@
}
if (i == CAM_IFE_CSID_HW_NUM_MAX || !csid_acquire.node_res) {
- CAM_ERR(CAM_ISP, "Can not acquire ife csid rdi resrouce!");
+ CAM_ERR(CAM_ISP, "Can not acquire ife csid rdi resource");
goto err;
}
@@ -1093,7 +1102,7 @@
if (j == CAM_IFE_CSID_HW_NUM_MAX) {
CAM_ERR(CAM_ISP,
- "Can not acquire ife csid rdi resrouce!");
+ "Can not acquire ife csid rdi resource");
goto err;
}
cid_res->hw_res[1] = csid_acquire.node_res;
@@ -1123,14 +1132,14 @@
/* get root node resource */
rc = cam_ife_hw_mgr_acquire_res_root(ife_ctx, in_port);
if (rc) {
- CAM_ERR(CAM_ISP, "Can not acquire csid rx resource!");
+ CAM_ERR(CAM_ISP, "Can not acquire csid rx resource");
goto err;
}
/* get cid resource */
rc = cam_ife_mgr_acquire_cid_res(ife_ctx, in_port, &cid_res_id);
if (rc) {
- CAM_ERR(CAM_ISP, "Acquire IFE CID resource Failed!");
+ CAM_ERR(CAM_ISP, "Acquire IFE CID resource Failed");
goto err;
}
@@ -1138,7 +1147,7 @@
&pixel_count, &rdi_count);
if (!pixel_count && !rdi_count) {
- CAM_ERR(CAM_ISP, "Error! no PIX or RDI resource");
+ CAM_ERR(CAM_ISP, "No PIX or RDI resource");
return -EINVAL;
}
@@ -1148,7 +1157,7 @@
cid_res_id);
if (rc) {
CAM_ERR(CAM_ISP,
- "Acquire IFE CSID IPP resource Failed!");
+ "Acquire IFE CSID IPP resource Failed");
goto err;
}
}
@@ -1159,7 +1168,7 @@
cid_res_id);
if (rc) {
CAM_ERR(CAM_ISP,
- "Acquire IFE CSID RDI resource Failed!");
+ "Acquire IFE CSID RDI resource Failed");
goto err;
}
}
@@ -1167,13 +1176,13 @@
/* get ife src resource */
rc = cam_ife_hw_mgr_acquire_res_ife_src(ife_ctx, in_port);
if (rc) {
- CAM_ERR(CAM_ISP, "Acquire IFE SRC resource Failed!");
+ CAM_ERR(CAM_ISP, "Acquire IFE SRC resource Failed");
goto err;
}
rc = cam_ife_hw_mgr_acquire_res_ife_out(ife_ctx, in_port);
if (rc) {
- CAM_ERR(CAM_ISP, "Acquire IFE OUT resource Failed!");
+ CAM_ERR(CAM_ISP, "Acquire IFE OUT resource Failed");
goto err;
}
@@ -1206,8 +1215,10 @@
struct cam_isp_in_port_info *in_port = NULL;
struct cam_isp_resource *isp_resource = NULL;
struct cam_cdm_acquire_data cdm_acquire;
- uint32_t num_pix_port = 0;
- uint32_t num_rdi_port = 0;
+ uint32_t num_pix_port_per_in = 0;
+ uint32_t num_rdi_port_per_in = 0;
+ uint32_t total_pix_port = 0;
+ uint32_t total_rdi_port = 0;
CAM_DBG(CAM_ISP, "Enter...");
@@ -1219,7 +1230,7 @@
/* get the ife ctx */
rc = cam_ife_hw_mgr_get_ctx(&ife_hw_mgr->free_ctx_list, &ife_ctx);
if (rc || !ife_ctx) {
- CAM_ERR(CAM_ISP, "Get ife hw context failed!");
+ CAM_ERR(CAM_ISP, "Get ife hw context failed");
goto err;
}
@@ -1271,7 +1282,10 @@
isp_resource[i].length);
if (in_port > 0) {
rc = cam_ife_mgr_acquire_hw_for_ctx(ife_ctx, in_port,
- &num_pix_port, &num_rdi_port);
+ &num_pix_port_per_in, &num_rdi_port_per_in);
+ total_pix_port += num_pix_port_per_in;
+ total_rdi_port += num_rdi_port_per_in;
+
kfree(in_port);
if (rc) {
CAM_ERR(CAM_ISP, "can not acquire resource");
@@ -1279,7 +1293,7 @@
}
} else {
CAM_ERR(CAM_ISP,
- "copy from user failed with in_port = %pK",
+ "Copy from user failed with in_port = %pK",
in_port);
rc = -EFAULT;
goto free_res;
@@ -1287,7 +1301,7 @@
}
/* Check whether context has only RDI resource */
- if (!num_pix_port) {
+ if (!total_pix_port) {
ife_ctx->is_rdi_only_context = 1;
CAM_DBG(CAM_ISP, "RDI only context");
}
@@ -1295,7 +1309,7 @@
/* Process base info */
rc = cam_ife_mgr_process_base_info(ife_ctx);
if (rc) {
- CAM_ERR(CAM_ISP, "Error process) base info!");
+ CAM_ERR(CAM_ISP, "Process base info failed");
return -EINVAL;
}
@@ -1304,14 +1318,14 @@
cam_ife_hw_mgr_put_ctx(&ife_hw_mgr->used_ctx_list, &ife_ctx);
- CAM_DBG(CAM_ISP, "Exit...(success)!");
+ CAM_DBG(CAM_ISP, "Exit...(success)");
return 0;
free_res:
cam_ife_hw_mgr_release_hw_for_ctx(ife_ctx);
cam_ife_hw_mgr_put_ctx(&ife_hw_mgr->free_ctx_list, &ife_ctx);
err:
- CAM_DBG(CAM_ISP, "Exit...(rc=%d)!", rc);
+ CAM_DBG(CAM_ISP, "Exit...(rc=%d)", rc);
return rc;
}
@@ -1334,12 +1348,12 @@
cfg = config_hw_args;
ctx = (struct cam_ife_hw_mgr_ctx *)cfg->ctxt_to_hw_map;
if (!ctx) {
- CAM_ERR(CAM_ISP, "Fatal: Invalid context is used!");
+ CAM_ERR(CAM_ISP, "Invalid context is used");
return -EPERM;
}
if (!ctx->ctx_in_use || !ctx->cdm_cmd) {
- CAM_ERR(CAM_ISP, "Invalid context parameters !");
+ CAM_ERR(CAM_ISP, "Invalid context parameters");
return -EPERM;
}
@@ -1388,7 +1402,7 @@
}
ctx = (struct cam_ife_hw_mgr_ctx *)stop_args->ctxt_to_hw_map;
if (!ctx || !ctx->ctx_in_use) {
- CAM_ERR(CAM_ISP, "Fatal: Invalid context is used!");
+ CAM_ERR(CAM_ISP, "Invalid context is used");
return -EPERM;
}
@@ -1397,7 +1411,7 @@
/* stop resource will remove the irq mask from the hardware */
if (!ctx->num_base) {
- CAM_ERR(CAM_ISP, "error number of bases are zero");
+ CAM_ERR(CAM_ISP, "Number of bases are zero");
return -EINVAL;
}
@@ -1474,7 +1488,7 @@
}
ctx = (struct cam_ife_hw_mgr_ctx *)stop_args->ctxt_to_hw_map;
if (!ctx || !ctx->ctx_in_use) {
- CAM_ERR(CAM_ISP, "Fatal: Invalid context is used!");
+ CAM_ERR(CAM_ISP, "Invalid context is used");
return -EPERM;
}
@@ -1484,7 +1498,7 @@
/* Note:stop resource will remove the irq mask from the hardware */
if (!ctx->num_base) {
- CAM_ERR(CAM_ISP, "error number of bases are zero");
+ CAM_ERR(CAM_ISP, "number of bases are zero");
return -EINVAL;
}
@@ -1628,7 +1642,7 @@
ctx = (struct cam_ife_hw_mgr_ctx *)start_args->ctxt_to_hw_map;
if (!ctx || !ctx->ctx_in_use) {
- CAM_ERR(CAM_ISP, "Invalid context is used!");
+ CAM_ERR(CAM_ISP, "Invalid context is used");
return -EPERM;
}
@@ -1639,7 +1653,7 @@
for (i = 0; i < CAM_IFE_HW_OUT_RES_MAX; i++) {
rc = cam_ife_hw_mgr_start_hw_res(&ctx->res_list_ife_out[i]);
if (rc) {
- CAM_ERR(CAM_ISP, "Can not start IFE OUT (%d)!", i);
+ CAM_ERR(CAM_ISP, "Can not start IFE OUT (%d)", i);
goto err;
}
}
@@ -1649,7 +1663,7 @@
list_for_each_entry(hw_mgr_res, &ctx->res_list_ife_src, list) {
rc = cam_ife_hw_mgr_start_hw_res(hw_mgr_res);
if (rc) {
- CAM_ERR(CAM_ISP, "Can not start IFE MUX (%d)!",
+ CAM_ERR(CAM_ISP, "Can not start IFE MUX (%d)",
hw_mgr_res->res_id);
goto err;
}
@@ -1660,7 +1674,7 @@
list_for_each_entry(hw_mgr_res, &ctx->res_list_ife_csid, list) {
rc = cam_ife_hw_mgr_start_hw_res(hw_mgr_res);
if (rc) {
- CAM_ERR(CAM_ISP, "Can not start IFE CSID (%d)!",
+ CAM_ERR(CAM_ISP, "Can not start IFE CSID (%d)",
hw_mgr_res->res_id);
goto err;
}
@@ -1671,7 +1685,7 @@
list_for_each_entry(hw_mgr_res, &ctx->res_list_ife_cid, list) {
rc = cam_ife_hw_mgr_start_hw_res(hw_mgr_res);
if (rc) {
- CAM_ERR(CAM_ISP, "Can not start IFE CSID (%d)!",
+ CAM_ERR(CAM_ISP, "Can not start IFE CSID (%d)",
hw_mgr_res->res_id);
goto err;
}
@@ -1702,7 +1716,7 @@
ctx = (struct cam_ife_hw_mgr_ctx *)start_args->ctxt_to_hw_map;
if (!ctx || !ctx->ctx_in_use) {
- CAM_ERR(CAM_ISP, "Invalid context is used!");
+ CAM_ERR(CAM_ISP, "Invalid context is used");
return -EPERM;
}
@@ -1721,7 +1735,7 @@
list_for_each_entry(hw_mgr_res, &ctx->res_list_ife_cid, list) {
rc = cam_ife_hw_mgr_init_hw_res(hw_mgr_res);
if (rc) {
- CAM_ERR(CAM_ISP, "Can not INIT IFE CID.(id :%d)!",
+ CAM_ERR(CAM_ISP, "Can not INIT IFE CID(id :%d)",
hw_mgr_res->res_id);
goto err;
}
@@ -1735,7 +1749,7 @@
list_for_each_entry(hw_mgr_res, &ctx->res_list_ife_csid, list) {
rc = cam_ife_hw_mgr_init_hw_res(hw_mgr_res);
if (rc) {
- CAM_ERR(CAM_ISP, "Can not INIT IFE CSID.(id :%d)!",
+ CAM_ERR(CAM_ISP, "Can not INIT IFE CSID(id :%d)",
hw_mgr_res->res_id);
goto err;
}
@@ -1747,7 +1761,7 @@
list_for_each_entry(hw_mgr_res, &ctx->res_list_ife_src, list) {
rc = cam_ife_hw_mgr_init_hw_res(hw_mgr_res);
if (rc) {
- CAM_ERR(CAM_ISP, "Can not INIT IFE SRC (%d)!",
+ CAM_ERR(CAM_ISP, "Can not INIT IFE SRC (%d)",
hw_mgr_res->res_id);
goto err;
}
@@ -1760,7 +1774,7 @@
for (i = 0; i < CAM_IFE_HW_OUT_RES_MAX; i++) {
rc = cam_ife_hw_mgr_init_hw_res(&ctx->res_list_ife_out[i]);
if (rc) {
- CAM_ERR(CAM_ISP, "Can not INIT IFE OUT (%d)!",
+ CAM_ERR(CAM_ISP, "Can not INIT IFE OUT (%d)",
ctx->res_list_ife_out[i].res_id);
goto err;
}
@@ -1769,7 +1783,7 @@
CAM_DBG(CAM_ISP, "start cdm interface");
rc = cam_cdm_stream_on(ctx->cdm_handle);
if (rc) {
- CAM_ERR(CAM_ISP, "Can not start cdm (%d)!",
+ CAM_ERR(CAM_ISP, "Can not start cdm (%d)",
ctx->cdm_handle);
goto err;
}
@@ -1788,7 +1802,7 @@
for (i = 0; i < CAM_IFE_HW_OUT_RES_MAX; i++) {
rc = cam_ife_hw_mgr_start_hw_res(&ctx->res_list_ife_out[i]);
if (rc) {
- CAM_ERR(CAM_ISP, "Can not start IFE OUT (%d)!",
+ CAM_ERR(CAM_ISP, "Can not start IFE OUT (%d)",
i);
goto err;
}
@@ -1800,7 +1814,7 @@
list_for_each_entry(hw_mgr_res, &ctx->res_list_ife_src, list) {
rc = cam_ife_hw_mgr_start_hw_res(hw_mgr_res);
if (rc) {
- CAM_ERR(CAM_ISP, "Can not start IFE MUX (%d)!",
+ CAM_ERR(CAM_ISP, "Can not start IFE MUX (%d)",
hw_mgr_res->res_id);
goto err;
}
@@ -1812,7 +1826,7 @@
list_for_each_entry(hw_mgr_res, &ctx->res_list_ife_csid, list) {
rc = cam_ife_hw_mgr_start_hw_res(hw_mgr_res);
if (rc) {
- CAM_ERR(CAM_ISP, "Can not start IFE CSID (%d)!",
+ CAM_ERR(CAM_ISP, "Can not start IFE CSID (%d)",
hw_mgr_res->res_id);
goto err;
}
@@ -1824,7 +1838,7 @@
list_for_each_entry(hw_mgr_res, &ctx->res_list_ife_cid, list) {
rc = cam_ife_hw_mgr_start_hw_res(hw_mgr_res);
if (rc) {
- CAM_ERR(CAM_ISP, "Can not start IFE CSID (%d)!",
+ CAM_ERR(CAM_ISP, "Can not start IFE CSID (%d)",
hw_mgr_res->res_id);
goto err;
}
@@ -1864,7 +1878,7 @@
ctx = (struct cam_ife_hw_mgr_ctx *)release_args->ctxt_to_hw_map;
if (!ctx || !ctx->ctx_in_use) {
- CAM_ERR(CAM_ISP, "Fatal: Invalid context is used!");
+ CAM_ERR(CAM_ISP, "Invalid context is used");
return -EPERM;
}
@@ -1923,7 +1937,8 @@
return rc;
rc = cam_packet_util_process_patches(prepare->packet,
- hw_mgr->mgr_common.cmd_iommu_hdl);
+ hw_mgr->mgr_common.cmd_iommu_hdl,
+ hw_mgr->mgr_common.cmd_iommu_hdl_secure);
if (rc) {
CAM_ERR(CAM_ISP, "Patch ISP packet failed.");
return rc;
@@ -1982,6 +1997,7 @@
/* get IO buffers */
rc = cam_isp_add_io_buffers(hw_mgr->mgr_common.img_iommu_hdl,
+ hw_mgr->mgr_common.img_iommu_hdl_secure,
prepare, ctx->base[i].idx,
&kmd_buf, ctx->res_list_ife_out,
CAM_IFE_HW_OUT_RES_MAX, fill_fence);
@@ -2049,7 +2065,7 @@
ctx = (struct cam_ife_hw_mgr_ctx *)hw_cmd_args->ctxt_to_hw_map;
if (!ctx || !ctx->ctx_in_use) {
- CAM_ERR(CAM_ISP, "Fatal: Invalid context is used!");
+ CAM_ERR(CAM_ISP, "Fatal: Invalid context is used");
return -EPERM;
}
@@ -2117,7 +2133,7 @@
}
end:
if (rc)
- CAM_ERR(CAM_ISP, "error in getting sof time stamp");
+ CAM_ERR(CAM_ISP, "Getting sof time stamp failed");
return rc;
}
@@ -2135,7 +2151,7 @@
struct cam_ife_hw_mgr_ctx *ctx = NULL;
/* Here recovery is performed */
- CAM_DBG(CAM_ISP, "Enter: ErrorType = %d", error_type);
+ CAM_DBG(CAM_ISP, "ErrorType = %d", error_type);
switch (error_type) {
case CAM_ISP_HW_ERROR_OVERFLOW:
@@ -2757,7 +2773,7 @@
break;
}
- CAM_DBG(CAM_ISP, "Exit (sof_status = %d)!", sof_status);
+ CAM_DBG(CAM_ISP, "Exit (sof_status = %d)", sof_status);
return 0;
}
@@ -2949,7 +2965,7 @@
}
}
- CAM_DBG(CAM_ISP, "Exit (eof_status = %d)!", eof_status);
+ CAM_DBG(CAM_ISP, "Exit (eof_status = %d)", eof_status);
return 0;
}
@@ -3080,7 +3096,7 @@
* for the first phase, we are going to reset entire HW.
*/
- CAM_DBG(CAM_ISP, "Exit (buf_done_status (Error) = %d)!",
+ CAM_DBG(CAM_ISP, "Exit buf_done_status Error = %d",
buf_done_status);
return rc;
}
@@ -3212,8 +3228,8 @@
mutex_init(&g_ife_hw_mgr.ctx_mutex);
if (CAM_IFE_HW_NUM_MAX != CAM_IFE_CSID_HW_NUM_MAX) {
- CAM_ERR(CAM_ISP, "Fatal, CSID num is different then IFE num!");
- goto end;
+ CAM_ERR(CAM_ISP, "CSID num is different then IFE num");
+ return -EINVAL;
}
/* fill ife hw intf information */
@@ -3237,8 +3253,8 @@
}
}
if (j == 0) {
- CAM_ERR(CAM_ISP, "no valid IFE HW!");
- goto end;
+ CAM_ERR(CAM_ISP, "no valid IFE HW");
+ return -EINVAL;
}
/* fill csid hw intf information */
@@ -3248,8 +3264,8 @@
j++;
}
if (!j) {
- CAM_ERR(CAM_ISP, "no valid IFE CSID HW!");
- goto end;
+ CAM_ERR(CAM_ISP, "no valid IFE CSID HW");
+ return -EINVAL;
}
cam_ife_hw_mgr_sort_dev_with_caps(&g_ife_hw_mgr);
@@ -3267,19 +3283,25 @@
*/
if (cam_smmu_get_handle("ife",
&g_ife_hw_mgr.mgr_common.img_iommu_hdl)) {
- CAM_ERR(CAM_ISP, "Can not get iommu handle.");
- goto end;
+ CAM_ERR(CAM_ISP, "Can not get iommu handle");
+ return -EINVAL;
}
if (cam_smmu_ops(g_ife_hw_mgr.mgr_common.img_iommu_hdl,
CAM_SMMU_ATTACH)) {
CAM_ERR(CAM_ISP, "Attach iommu handle failed.");
- goto end;
+ goto attach_fail;
}
- CAM_DBG(CAM_ISP, "got iommu_handle=%d",
- g_ife_hw_mgr.mgr_common.img_iommu_hdl);
- g_ife_hw_mgr.mgr_common.img_iommu_hdl_secure = -1;
+ if (cam_smmu_get_handle("cam-secure",
+ &g_ife_hw_mgr.mgr_common.img_iommu_hdl_secure)) {
+ CAM_ERR(CAM_ISP, "Failed to get secure iommu handle");
+ goto secure_fail;
+ }
+
+ CAM_DBG(CAM_ISP, "iommu_handles: non-secure[0x%x], secure[0x%x]",
+ g_ife_hw_mgr.mgr_common.img_iommu_hdl,
+ g_ife_hw_mgr.mgr_common.img_iommu_hdl_secure);
if (!cam_cdm_get_iommu_handle("ife", &cdm_handles)) {
CAM_DBG(CAM_ISP, "Successfully acquired the CDM iommu handles");
@@ -3341,7 +3363,6 @@
/* Create Worker for ife_hw_mgr with 10 tasks */
rc = cam_req_mgr_workq_create("cam_ife_worker", 10,
&g_ife_hw_mgr.workq, CRM_WORKQ_USAGE_NON_IRQ);
-
if (rc < 0) {
CAM_ERR(CAM_ISP, "Unable to create worker");
goto end;
@@ -3359,14 +3380,28 @@
hw_mgr_intf->hw_prepare_update = cam_ife_mgr_prepare_hw_update;
hw_mgr_intf->hw_config = cam_ife_mgr_config_hw;
hw_mgr_intf->hw_cmd = cam_ife_mgr_cmd;
-
CAM_DBG(CAM_ISP, "Exit");
+
return 0;
end:
if (rc) {
- for (i = 0; i < CAM_CTX_MAX; i++)
+ for (i = 0; i < CAM_CTX_MAX; i++) {
+ cam_tasklet_deinit(
+ &g_ife_hw_mgr.mgr_common.tasklet_pool[i]);
kfree(g_ife_hw_mgr.ctx_pool[i].cdm_cmd);
+ g_ife_hw_mgr.ctx_pool[i].cdm_cmd = NULL;
+ g_ife_hw_mgr.ctx_pool[i].common.tasklet_info = NULL;
+ }
}
+ cam_smmu_destroy_handle(
+ g_ife_hw_mgr.mgr_common.img_iommu_hdl_secure);
+ g_ife_hw_mgr.mgr_common.img_iommu_hdl_secure = -1;
+secure_fail:
+ cam_smmu_ops(g_ife_hw_mgr.mgr_common.img_iommu_hdl,
+ CAM_SMMU_DETACH);
+attach_fail:
+ cam_smmu_destroy_handle(g_ife_hw_mgr.mgr_common.img_iommu_hdl);
+ g_ife_hw_mgr.mgr_common.img_iommu_hdl = -1;
return rc;
}
diff --git a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/hw_utils/cam_isp_packet_parser.c b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/hw_utils/cam_isp_packet_parser.c
index 698a4c8..c58578e 100644
--- a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/hw_utils/cam_isp_packet_parser.c
+++ b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/hw_utils/cam_isp_packet_parser.c
@@ -408,6 +408,7 @@
int cam_isp_add_io_buffers(
int iommu_hdl,
+ int sec_iommu_hdl,
struct cam_hw_prepare_update_args *prepare,
uint32_t base_idx,
struct cam_kmd_buf_info *kmd_buf_info,
@@ -425,7 +426,10 @@
uint32_t i, j, num_out_buf, num_in_buf;
uint32_t res_id_out, res_id_in, plane_id;
uint32_t io_cfg_used_bytes, num_ent;
- size_t size;
+ size_t size;
+ int32_t hdl;
+ int mmu_hdl;
+ bool mode, is_buf_secure;
io_cfg = (struct cam_buf_io_cfg *) ((uint8_t *)
&prepare->packet->payload +
@@ -536,9 +540,31 @@
if (!io_cfg[i].mem_handle[plane_id])
break;
+ hdl = io_cfg[i].mem_handle[plane_id];
+ if (res->process_cmd(res,
+ CAM_VFE_HW_CMD_GET_SECURE_MODE,
+ &mode,
+ sizeof(bool)))
+ return -EINVAL;
+
+ is_buf_secure = cam_mem_is_secure_buf(hdl);
+ if ((mode == CAM_SECURE_MODE_SECURE) &&
+ is_buf_secure) {
+ mmu_hdl = sec_iommu_hdl;
+ } else if (
+ (mode == CAM_SECURE_MODE_NON_SECURE) &&
+ (!is_buf_secure)) {
+ mmu_hdl = iommu_hdl;
+ } else {
+ CAM_ERR_RATE_LIMIT(CAM_ISP,
+ "Invalid hdl: port mode[%u], buf mode[%u]",
+ mode, is_buf_secure);
+ return -EINVAL;
+ }
+
rc = cam_mem_get_io_buf(
io_cfg[i].mem_handle[plane_id],
- iommu_hdl, &io_addr[plane_id], &size);
+ mmu_hdl, &io_addr[plane_id], &size);
if (rc) {
CAM_ERR(CAM_ISP,
"no io addr for plane%d",
diff --git a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/hw_utils/include/cam_isp_packet_parser.h b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/hw_utils/include/cam_isp_packet_parser.h
index 187e5bc..24b532e 100644
--- a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/hw_utils/include/cam_isp_packet_parser.h
+++ b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/hw_utils/include/cam_isp_packet_parser.h
@@ -69,6 +69,8 @@
* index and update the HW entries list
*
* @iommu_hdl: Iommu handle to get the IO buf from memory manager
+ * @sec_iommu_hdl: Secure iommu handle to get the IO buf from
+ * memory manager
* @prepare: Contain the packet and HW update variables
* @base_idx: Base or dev index of the IFE/VFE HW instance
* @kmd_buf_info: Kmd buffer to store the change base command
@@ -79,7 +81,9 @@
* @return: 0 for success
* -EINVAL for Fail
*/
-int cam_isp_add_io_buffers(int iommu_hdl,
+int cam_isp_add_io_buffers(
+ int iommu_hdl,
+ int sec_iommu_hdl,
struct cam_hw_prepare_update_args *prepare,
uint32_t base_idx,
struct cam_kmd_buf_info *kmd_buf_info,
diff --git a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/hw_utils/irq_controller/cam_irq_controller.c b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/hw_utils/irq_controller/cam_irq_controller.c
index 2341b38..dcbea8d 100644
--- a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/hw_utils/irq_controller/cam_irq_controller.c
+++ b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/hw_utils/irq_controller/cam_irq_controller.c
@@ -329,6 +329,111 @@
return rc;
}
+int cam_irq_controller_enable_irq(void *irq_controller, uint32_t handle)
+{
+ struct cam_irq_controller *controller = irq_controller;
+ struct cam_irq_evt_handler *evt_handler = NULL;
+ struct cam_irq_evt_handler *evt_handler_temp;
+ unsigned long flags;
+ unsigned int i;
+ uint32_t irq_mask;
+ uint32_t found = 0;
+ int rc = -EINVAL;
+
+ if (!controller)
+ return rc;
+
+ list_for_each_entry_safe(evt_handler, evt_handler_temp,
+ &controller->evt_handler_list_head, list_node) {
+ if (evt_handler->index == handle) {
+ CAM_DBG(CAM_ISP, "enable item %d", handle);
+ found = 1;
+ rc = 0;
+ break;
+ }
+ }
+
+ if (!found)
+ return rc;
+
+ write_lock_irqsave(&controller->rw_lock, flags);
+ for (i = 0; i < controller->num_registers; i++) {
+ controller->irq_register_arr[i].
+ top_half_enable_mask[evt_handler->priority] |=
+ evt_handler->evt_bit_mask_arr[i];
+
+ irq_mask = cam_io_r_mb(controller->mem_base +
+ controller->irq_register_arr[i].
+ mask_reg_offset);
+ irq_mask |= evt_handler->evt_bit_mask_arr[i];
+
+ cam_io_w_mb(irq_mask, controller->mem_base +
+ controller->irq_register_arr[i].mask_reg_offset);
+ }
+ write_unlock_irqrestore(&controller->rw_lock, flags);
+
+ return rc;
+}
+
+int cam_irq_controller_disable_irq(void *irq_controller, uint32_t handle)
+{
+ struct cam_irq_controller *controller = irq_controller;
+ struct cam_irq_evt_handler *evt_handler = NULL;
+ struct cam_irq_evt_handler *evt_handler_temp;
+ unsigned long flags;
+ unsigned int i;
+ uint32_t irq_mask;
+ uint32_t found = 0;
+ int rc = -EINVAL;
+
+ if (!controller)
+ return rc;
+
+ list_for_each_entry_safe(evt_handler, evt_handler_temp,
+ &controller->evt_handler_list_head, list_node) {
+ if (evt_handler->index == handle) {
+ CAM_DBG(CAM_ISP, "disable item %d", handle);
+ found = 1;
+ rc = 0;
+ break;
+ }
+ }
+
+ if (!found)
+ return rc;
+
+ write_lock_irqsave(&controller->rw_lock, flags);
+ for (i = 0; i < controller->num_registers; i++) {
+ controller->irq_register_arr[i].
+ top_half_enable_mask[evt_handler->priority] &=
+ ~(evt_handler->evt_bit_mask_arr[i]);
+
+ irq_mask = cam_io_r_mb(controller->mem_base +
+ controller->irq_register_arr[i].
+ mask_reg_offset);
+ irq_mask &= ~(evt_handler->evt_bit_mask_arr[i]);
+
+ cam_io_w_mb(irq_mask, controller->mem_base +
+ controller->irq_register_arr[i].
+ mask_reg_offset);
+
+ /* Clear the IRQ bits of this handler */
+ cam_io_w_mb(evt_handler->evt_bit_mask_arr[i],
+ controller->mem_base +
+ controller->irq_register_arr[i].
+ clear_reg_offset);
+
+ if (controller->global_clear_offset)
+ cam_io_w_mb(
+ controller->global_clear_bitmask,
+ controller->mem_base +
+ controller->global_clear_offset);
+ }
+ write_unlock_irqrestore(&controller->rw_lock, flags);
+
+ return rc;
+}
+
int cam_irq_controller_unsubscribe_irq(void *irq_controller,
uint32_t handle)
{
diff --git a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/hw_utils/irq_controller/cam_irq_controller.h b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/hw_utils/irq_controller/cam_irq_controller.h
index 1990c51..7e307b5 100644
--- a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/hw_utils/irq_controller/cam_irq_controller.h
+++ b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/hw_utils/irq_controller/cam_irq_controller.h
@@ -214,4 +214,40 @@
*/
irqreturn_t cam_irq_controller_handle_irq(int irq_num, void *priv);
+/*
+ * cam_irq_controller_disable_irq()
+ *
+ * @brief: Disable the interrupts on given controller.
+ * Unsubscribe will disable the IRQ by default, so this is
+ * only needed if between subscribe/unsubscribe there is
+ * need to disable IRQ again
+ *
+ * @irq_controller: Pointer to IRQ Controller that controls the registered
+ * events to it.
+ * @handle: Handle returned on successful subscribe, used to
+ * identify the handler object
+ *
+ * @return: 0: events found and disabled
+ * Negative: events not registered on this controller
+ */
+int cam_irq_controller_disable_irq(void *irq_controller, uint32_t handle);
+
+/*
+ * cam_irq_controller_enable_irq()
+ *
+ * @brief: Enable the interrupts on given controller.
+ * Subscribe will enable the IRQ by default, so this is
+ * only needed if between subscribe/unsubscribe there is
+ * need to enable IRQ again
+ *
+ * @irq_controller: Pointer to IRQ Controller that controls the registered
+ * events to it.
+ * @handle: Handle returned on successful subscribe, used to
+ * identify the handler object
+ *
+ * @return: 0: events found and enabled
+ * Negative: events not registered on this controller
+ */
+int cam_irq_controller_enable_irq(void *irq_controller, uint32_t handle);
+
#endif /* _CAM_IRQ_CONTROLLER_H_ */
diff --git a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_soc.c b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_soc.c
index 22c11d3..020599d 100644
--- a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_soc.c
+++ b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_soc.c
@@ -129,8 +129,8 @@
ahb_vote.type = CAM_VOTE_ABSOLUTE;
ahb_vote.vote.level = CAM_SVS_VOTE;
- axi_vote.compressed_bw = 640000000;
- axi_vote.uncompressed_bw = 640000000;
+ axi_vote.compressed_bw = CAM_CPAS_DEFAULT_AXI_BW;
+ axi_vote.uncompressed_bw = CAM_CPAS_DEFAULT_AXI_BW;
CAM_DBG(CAM_ISP, "csid vote compressed_bw:%lld uncompressed_bw:%lld",
axi_vote.compressed_bw, axi_vote.uncompressed_bw);
diff --git a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/include/cam_vfe_hw_intf.h b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/include/cam_vfe_hw_intf.h
index a08248d..a64379c 100644
--- a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/include/cam_vfe_hw_intf.h
+++ b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/include/cam_vfe_hw_intf.h
@@ -49,6 +49,7 @@
CAM_VFE_HW_CMD_GET_BUF_UPDATE,
CAM_VFE_HW_CMD_GET_REG_UPDATE,
CAM_VFE_HW_CMD_GET_HFR_UPDATE,
+ CAM_VFE_HW_CMD_GET_SECURE_MODE,
CAM_VFE_HW_CMD_MAX,
};
diff --git a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_ver2.c b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_ver2.c
index b015452..1472e09 100644
--- a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_ver2.c
+++ b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_ver2.c
@@ -94,6 +94,9 @@
struct cam_vfe_bus_irq_evt_payload evt_payload[
CAM_VFE_BUS_VER2_PAYLOAD_MAX];
struct list_head free_payload_list;
+ struct mutex bus_mutex;
+ uint32_t secure_mode;
+ uint32_t num_sec_out;
};
struct cam_vfe_bus_ver2_wm_resource_data {
@@ -168,6 +171,7 @@
uint32_t max_width;
uint32_t max_height;
struct cam_cdm_utils_ops *cdm_util_ops;
+ uint32_t secure_mode;
};
struct cam_vfe_bus_ver2_priv {
@@ -184,6 +188,10 @@
uint32_t irq_handle;
};
+static int cam_vfe_bus_process_cmd(
+ struct cam_isp_resource_node *priv,
+ uint32_t cmd_type, void *cmd_args, uint32_t arg_size);
+
static int cam_vfe_bus_get_evt_payload(
struct cam_vfe_bus_ver2_common_data *common_data,
struct cam_vfe_bus_irq_evt_payload **evt_payload)
@@ -328,6 +336,34 @@
return rc;
}
+static bool cam_vfe_bus_can_be_secure(uint32_t out_type)
+{
+ switch (out_type) {
+ case CAM_VFE_BUS_VER2_VFE_OUT_FULL:
+ case CAM_VFE_BUS_VER2_VFE_OUT_DS4:
+ case CAM_VFE_BUS_VER2_VFE_OUT_DS16:
+ case CAM_VFE_BUS_VER2_VFE_OUT_FD:
+ case CAM_VFE_BUS_VER2_VFE_OUT_RAW_DUMP:
+ case CAM_VFE_BUS_VER2_VFE_OUT_RDI0:
+ case CAM_VFE_BUS_VER2_VFE_OUT_RDI1:
+ case CAM_VFE_BUS_VER2_VFE_OUT_RDI2:
+ return true;
+
+ case CAM_VFE_BUS_VER2_VFE_OUT_PDAF:
+ case CAM_VFE_BUS_VER2_VFE_OUT_STATS_HDR_BE:
+ case CAM_VFE_BUS_VER2_VFE_OUT_STATS_HDR_BHIST:
+ case CAM_VFE_BUS_VER2_VFE_OUT_STATS_TL_BG:
+ case CAM_VFE_BUS_VER2_VFE_OUT_STATS_BF:
+ case CAM_VFE_BUS_VER2_VFE_OUT_STATS_AWB_BG:
+ case CAM_VFE_BUS_VER2_VFE_OUT_STATS_BHIST:
+ case CAM_VFE_BUS_VER2_VFE_OUT_STATS_RS:
+ case CAM_VFE_BUS_VER2_VFE_OUT_STATS_CS:
+ case CAM_VFE_BUS_VER2_VFE_OUT_STATS_IHIST:
+ default:
+ return false;
+ }
+}
+
static enum cam_vfe_bus_ver2_vfe_out_type
cam_vfe_bus_get_out_res_id(uint32_t res_type)
{
@@ -720,6 +756,8 @@
case CAM_FORMAT_UBWC_TP10:
case CAM_FORMAT_TP10:
return PACKER_FMT_TP_10;
+ case CAM_FORMAT_ARGB_14:
+ return PACKER_FMT_ARGB_14;
default:
return PACKER_FMT_MAX;
}
@@ -844,7 +882,7 @@
case PLANE_Y:
break;
default:
- CAM_ERR(CAM_ISP, "Invalid plane %d\n", plane);
+ CAM_ERR(CAM_ISP, "Invalid plane %d", plane);
return -EINVAL;
}
break;
@@ -860,7 +898,7 @@
case PLANE_Y:
break;
default:
- CAM_ERR(CAM_ISP, "Invalid plane %d\n", plane);
+ CAM_ERR(CAM_ISP, "Invalid plane %d", plane);
return -EINVAL;
}
break;
@@ -875,7 +913,7 @@
case PLANE_Y:
break;
default:
- CAM_ERR(CAM_ISP, "Invalid plane %d\n", plane);
+ CAM_ERR(CAM_ISP, "Invalid plane %d", plane);
return -EINVAL;
}
break;
@@ -889,12 +927,12 @@
case PLANE_Y:
break;
default:
- CAM_ERR(CAM_ISP, "Invalid plane %d\n", plane);
+ CAM_ERR(CAM_ISP, "Invalid plane %d", plane);
return -EINVAL;
}
break;
default:
- CAM_ERR(CAM_ISP, "Invalid format %d\n",
+ CAM_ERR(CAM_ISP, "Invalid format %d",
rsrc_data->format);
return -EINVAL;
}
@@ -905,8 +943,13 @@
rsrc_data->height = 0;
rsrc_data->stride = 1;
rsrc_data->en_cfg = 0x3;
- } else {
- /* Write master 5-6 DS ports , 9 - Raw dump , 10 PDAF */
+ } else if (rsrc_data->index == 9) {
+ /* Write master 9 - Raw dump */
+ rsrc_data->width = rsrc_data->width * 2;
+ rsrc_data->stride = rsrc_data->width;
+ rsrc_data->en_cfg = 0x1;
+ } else {
+ /* Write master 5-6 DS ports, 10 PDAF */
rsrc_data->width = rsrc_data->width * 4;
rsrc_data->height = rsrc_data->height / 2;
rsrc_data->en_cfg = 0x1;
@@ -1061,7 +1104,7 @@
wm_res = th_payload->handler_priv;
if (!wm_res) {
- CAM_ERR_RATE_LIMIT(CAM_ISP, "Error! No resource\n");
+ CAM_ERR_RATE_LIMIT(CAM_ISP, "Error: No resource");
return -ENODEV;
}
@@ -1073,7 +1116,7 @@
rc = cam_vfe_bus_get_evt_payload(rsrc_data->common_data, &evt_payload);
if (rc) {
CAM_ERR_RATE_LIMIT(CAM_ISP,
- "No tasklet_cmd is free in queue\n");
+ "No tasklet_cmd is free in queue");
return rc;
}
@@ -1170,10 +1213,8 @@
rsrc_data = wm_res->res_priv;
wm_res->res_priv = NULL;
- if (!rsrc_data) {
- CAM_ERR(CAM_ISP, "Error! WM res priv is NULL");
+ if (!rsrc_data)
return -ENOMEM;
- }
kfree(rsrc_data);
return 0;
@@ -1465,7 +1506,7 @@
comp_grp = th_payload->handler_priv;
if (!comp_grp) {
- CAM_ERR_RATE_LIMIT(CAM_ISP, "Error! No resource\n");
+ CAM_ERR_RATE_LIMIT(CAM_ISP, "No resource");
return -ENODEV;
}
@@ -1477,7 +1518,7 @@
rc = cam_vfe_bus_get_evt_payload(rsrc_data->common_data, &evt_payload);
if (rc) {
CAM_ERR_RATE_LIMIT(CAM_ISP,
- "No tasklet_cmd is free in queue\n");
+ "No tasklet_cmd is free in queue");
return rc;
}
@@ -1604,7 +1645,7 @@
break;
default:
rc = CAM_VFE_IRQ_STATUS_ERR;
- CAM_ERR(CAM_ISP, "Error! Invalid comp_grp_type %u",
+ CAM_ERR(CAM_ISP, "Invalid comp_grp_type %u",
rsrc_data->comp_grp_type);
break;
}
@@ -1625,10 +1666,9 @@
rsrc_data = kzalloc(sizeof(struct cam_vfe_bus_ver2_comp_grp_data),
GFP_KERNEL);
- if (!rsrc_data) {
- CAM_DBG(CAM_ISP, "Failed to alloc for comp_grp_priv");
+ if (!rsrc_data)
return -ENOMEM;
- }
+
comp_grp->res_priv = rsrc_data;
comp_grp->res_state = CAM_ISP_RESOURCE_STATE_AVAILABLE;
@@ -1675,7 +1715,7 @@
comp_grp->res_priv = NULL;
if (!rsrc_data) {
- CAM_ERR(CAM_ISP, "Error! comp_grp_priv is NULL");
+ CAM_ERR(CAM_ISP, "comp_grp_priv is NULL");
return -ENODEV;
}
kfree(rsrc_data);
@@ -1683,6 +1723,22 @@
return 0;
}
+static int cam_vfe_bus_get_secure_mode(void *priv, void *cmd_args,
+ uint32_t arg_size)
+{
+ bool *mode = cmd_args;
+ struct cam_isp_resource_node *res =
+ (struct cam_isp_resource_node *) priv;
+ struct cam_vfe_bus_ver2_vfe_out_data *rsrc_data =
+ (struct cam_vfe_bus_ver2_vfe_out_data *)res->res_priv;
+
+ *mode =
+ (rsrc_data->secure_mode == CAM_SECURE_MODE_SECURE) ?
+ true : false;
+
+ return 0;
+}
+
static int cam_vfe_bus_acquire_vfe_out(void *bus_priv, void *acquire_args,
uint32_t args_size)
{
@@ -1690,7 +1746,7 @@
int i;
enum cam_vfe_bus_ver2_vfe_out_type vfe_out_res_id;
uint32_t format;
- uint32_t num_wm;
+ int num_wm;
uint32_t subscribe_irq;
uint32_t client_done_mask;
struct cam_vfe_bus_ver2_priv *ver2_bus_priv = bus_priv;
@@ -1698,6 +1754,7 @@
struct cam_vfe_hw_vfe_out_acquire_args *out_acquire_args;
struct cam_isp_resource_node *rsrc_node = NULL;
struct cam_vfe_bus_ver2_vfe_out_data *rsrc_data = NULL;
+ uint32_t secure_caps = 0, mode;
if (!bus_priv || !acquire_args) {
CAM_ERR(CAM_ISP, "Invalid Param");
@@ -1727,6 +1784,33 @@
}
rsrc_data = rsrc_node->res_priv;
+ secure_caps = cam_vfe_bus_can_be_secure(
+ rsrc_data->out_type);
+ mode = out_acquire_args->out_port_info->secure_mode;
+ mutex_lock(&rsrc_data->common_data->bus_mutex);
+ if (secure_caps) {
+ if (!rsrc_data->common_data->num_sec_out) {
+ rsrc_data->secure_mode = mode;
+ rsrc_data->common_data->secure_mode = mode;
+ } else {
+ if (mode == rsrc_data->common_data->secure_mode) {
+ rsrc_data->secure_mode =
+ rsrc_data->common_data->secure_mode;
+ } else {
+ rc = -EINVAL;
+ CAM_ERR_RATE_LIMIT(CAM_ISP,
+ "Mismatch: Acquire mode[%d], drvr mode[%d]",
+ rsrc_data->common_data->secure_mode,
+ mode);
+ mutex_unlock(
+ &rsrc_data->common_data->bus_mutex);
+ return -EINVAL;
+ }
+ }
+ rsrc_data->common_data->num_sec_out++;
+ }
+ mutex_unlock(&rsrc_data->common_data->bus_mutex);
+
rsrc_data->num_wm = num_wm;
rsrc_node->res_id = out_acquire_args->out_port_info->res_type;
rsrc_node->tasklet_info = acq_args->tasklet;
@@ -1807,6 +1891,7 @@
uint32_t i;
struct cam_isp_resource_node *vfe_out = NULL;
struct cam_vfe_bus_ver2_vfe_out_data *rsrc_data = NULL;
+ uint32_t secure_caps = 0;
if (!bus_priv || !release_args) {
CAM_ERR(CAM_ISP, "Invalid input bus_priv %pK release_args %pK",
@@ -1818,7 +1903,7 @@
rsrc_data = vfe_out->res_priv;
if (vfe_out->res_state != CAM_ISP_RESOURCE_STATE_RESERVED) {
- CAM_ERR(CAM_ISP, "Error! Invalid resource state:%d",
+ CAM_ERR(CAM_ISP, "Invalid resource state:%d",
vfe_out->res_state);
}
@@ -1834,6 +1919,32 @@
vfe_out->cdm_ops = NULL;
rsrc_data->cdm_util_ops = NULL;
+ secure_caps = cam_vfe_bus_can_be_secure(rsrc_data->out_type);
+ mutex_lock(&rsrc_data->common_data->bus_mutex);
+ if (secure_caps) {
+ if (rsrc_data->secure_mode ==
+ rsrc_data->common_data->secure_mode) {
+ rsrc_data->common_data->num_sec_out--;
+ rsrc_data->secure_mode =
+ CAM_SECURE_MODE_NON_SECURE;
+ } else {
+ /*
+ * The validity of the mode is properly
+ * checked while acquiring the output port.
+ * not expected to reach here, unless there is
+ * some corruption.
+ */
+ CAM_ERR(CAM_ISP, "driver[%d],resource[%d] mismatch",
+ rsrc_data->common_data->secure_mode,
+ rsrc_data->secure_mode);
+ }
+
+ if (!rsrc_data->common_data->num_sec_out)
+ rsrc_data->common_data->secure_mode =
+ CAM_SECURE_MODE_NON_SECURE;
+ }
+ mutex_unlock(&rsrc_data->common_data->bus_mutex);
+
if (vfe_out->res_state == CAM_ISP_RESOURCE_STATE_RESERVED)
vfe_out->res_state = CAM_ISP_RESOURCE_STATE_AVAILABLE;
@@ -1858,7 +1969,7 @@
CAM_DBG(CAM_ISP, "Start resource index %d", rsrc_data->out_type);
if (vfe_out->res_state != CAM_ISP_RESOURCE_STATE_RESERVED) {
- CAM_ERR(CAM_ISP, "Error! Invalid resource state:%d",
+ CAM_ERR(CAM_ISP, "Invalid resource state:%d",
vfe_out->res_state);
return -EACCES;
}
@@ -1965,7 +2076,6 @@
rsrc_data = kzalloc(sizeof(struct cam_vfe_bus_ver2_vfe_out_data),
GFP_KERNEL);
if (!rsrc_data) {
- CAM_DBG(CAM_ISP, "Error! Failed to alloc for vfe out priv");
rc = -ENOMEM;
return rc;
}
@@ -1981,12 +2091,14 @@
ver2_hw_info->vfe_out_hw_info[index].max_width;
rsrc_data->max_height =
ver2_hw_info->vfe_out_hw_info[index].max_height;
+ rsrc_data->secure_mode = CAM_SECURE_MODE_NON_SECURE;
vfe_out->start = cam_vfe_bus_start_vfe_out;
vfe_out->stop = cam_vfe_bus_stop_vfe_out;
vfe_out->top_half_handler = cam_vfe_bus_handle_vfe_out_done_top_half;
vfe_out->bottom_half_handler =
cam_vfe_bus_handle_vfe_out_done_bottom_half;
+ vfe_out->process_cmd = cam_vfe_bus_process_cmd;
vfe_out->hw_intf = ver2_bus_priv->common_data.hw_intf;
return 0;
@@ -2007,10 +2119,8 @@
INIT_LIST_HEAD(&vfe_out->list);
vfe_out->res_priv = NULL;
- if (!rsrc_data) {
- CAM_ERR(CAM_ISP, "Error! vfe out priv is NULL");
+ if (!rsrc_data)
return -ENOMEM;
- }
kfree(rsrc_data);
return 0;
@@ -2387,7 +2497,7 @@
uint32_t top_irq_reg_mask[2] = {0};
if (!bus_priv) {
- CAM_ERR(CAM_ISP, "Error! Invalid args");
+ CAM_ERR(CAM_ISP, "Invalid args");
return -EINVAL;
}
@@ -2418,7 +2528,7 @@
int rc;
if (!bus_priv || (bus_priv->irq_handle <= 0)) {
- CAM_ERR(CAM_ISP, "Error! Invalid args");
+ CAM_ERR(CAM_ISP, "Error: Invalid args");
return -EINVAL;
}
@@ -2431,13 +2541,20 @@
return rc;
}
-static int cam_vfe_bus_process_cmd(void *priv,
+static int __cam_vfe_bus_process_cmd(void *priv,
+ uint32_t cmd_type, void *cmd_args, uint32_t arg_size)
+{
+ return cam_vfe_bus_process_cmd(priv, cmd_type, cmd_args, arg_size);
+}
+
+static int cam_vfe_bus_process_cmd(
+ struct cam_isp_resource_node *priv,
uint32_t cmd_type, void *cmd_args, uint32_t arg_size)
{
int rc = -EINVAL;
if (!priv || !cmd_args) {
- CAM_ERR_RATE_LIMIT(CAM_ISP, "Error! Invalid input arguments\n");
+ CAM_ERR_RATE_LIMIT(CAM_ISP, "Invalid input arguments");
return -EINVAL;
}
@@ -2448,8 +2565,11 @@
case CAM_VFE_HW_CMD_GET_HFR_UPDATE:
rc = cam_vfe_bus_update_hfr(priv, cmd_args, arg_size);
break;
+ case CAM_VFE_HW_CMD_GET_SECURE_MODE:
+ rc = cam_vfe_bus_get_secure_mode(priv, cmd_args, arg_size);
+ break;
default:
- CAM_ERR_RATE_LIMIT(CAM_ISP, "Inval camif process command:%d\n",
+ CAM_ERR_RATE_LIMIT(CAM_ISP, "Invalid camif process command:%d",
cmd_type);
break;
}
@@ -2496,18 +2616,21 @@
}
vfe_bus_local->bus_priv = bus_priv;
+ bus_priv->common_data.num_sec_out = 0;
+ bus_priv->common_data.secure_mode = CAM_SECURE_MODE_NON_SECURE;
bus_priv->common_data.core_index = soc_info->index;
bus_priv->common_data.mem_base =
CAM_SOC_GET_REG_MAP_START(soc_info, VFE_CORE_BASE_IDX);
bus_priv->common_data.hw_intf = hw_intf;
bus_priv->common_data.vfe_irq_controller = vfe_irq_controller;
bus_priv->common_data.common_reg = &ver2_hw_info->common_reg;
+ mutex_init(&bus_priv->common_data.bus_mutex);
rc = cam_irq_controller_init(drv_name, bus_priv->common_data.mem_base,
&ver2_hw_info->common_reg.irq_reg_info,
&bus_priv->common_data.bus_irq_controller);
if (rc) {
- CAM_ERR(CAM_ISP, "Error! cam_irq_controller_init failed");
+ CAM_ERR(CAM_ISP, "cam_irq_controller_init failed");
goto free_bus_priv;
}
@@ -2519,7 +2642,7 @@
rc = cam_vfe_bus_init_wm_resource(i, bus_priv, bus_hw_info,
&bus_priv->bus_client[i]);
if (rc < 0) {
- CAM_ERR(CAM_ISP, "Error! Init WM failed rc=%d", rc);
+ CAM_ERR(CAM_ISP, "Init WM failed rc=%d", rc);
goto deinit_wm;
}
}
@@ -2557,7 +2680,7 @@
vfe_bus_local->hw_ops.deinit = cam_vfe_bus_deinit_hw;
vfe_bus_local->top_half_handler = cam_vfe_bus_ver2_handle_irq;
vfe_bus_local->bottom_half_handler = NULL;
- vfe_bus_local->hw_ops.process_cmd = cam_vfe_bus_process_cmd;
+ vfe_bus_local->hw_ops.process_cmd = __cam_vfe_bus_process_cmd;
*vfe_bus = vfe_bus_local;
@@ -2600,14 +2723,14 @@
struct cam_vfe_bus *vfe_bus_local;
if (!vfe_bus || !*vfe_bus) {
- CAM_ERR(CAM_ISP, "Error! Invalid input");
+ CAM_ERR(CAM_ISP, "Invalid input");
return -EINVAL;
}
vfe_bus_local = *vfe_bus;
bus_priv = vfe_bus_local->bus_priv;
if (!bus_priv) {
- CAM_ERR(CAM_ISP, "Error! bus_priv is NULL");
+ CAM_ERR(CAM_ISP, "bus_priv is NULL");
rc = -ENODEV;
goto free_bus_local;
}
@@ -2620,21 +2743,21 @@
rc = cam_vfe_bus_deinit_wm_resource(&bus_priv->bus_client[i]);
if (rc < 0)
CAM_ERR(CAM_ISP,
- "Error! Deinit WM failed rc=%d", rc);
+ "Deinit WM failed rc=%d", rc);
}
for (i = 0; i < CAM_VFE_BUS_VER2_COMP_GRP_MAX; i++) {
rc = cam_vfe_bus_deinit_comp_grp(&bus_priv->comp_grp[i]);
if (rc < 0)
CAM_ERR(CAM_ISP,
- "Error! Deinit Comp Grp failed rc=%d", rc);
+ "Deinit Comp Grp failed rc=%d", rc);
}
for (i = 0; i < CAM_VFE_BUS_VER2_VFE_OUT_MAX; i++) {
rc = cam_vfe_bus_deinit_vfe_out_resource(&bus_priv->vfe_out[i]);
if (rc < 0)
CAM_ERR(CAM_ISP,
- "Error! Deinit VFE Out failed rc=%d", rc);
+ "Deinit VFE Out failed rc=%d", rc);
}
INIT_LIST_HEAD(&bus_priv->free_comp_grp);
@@ -2645,8 +2768,9 @@
&bus_priv->common_data.bus_irq_controller);
if (rc)
CAM_ERR(CAM_ISP,
- "Error! Deinit IRQ Controller failed rc=%d", rc);
+ "Deinit IRQ Controller failed rc=%d", rc);
+ mutex_destroy(&bus_priv->common_data.bus_mutex);
kfree(vfe_bus_local->bus_priv);
free_bus_local:
diff --git a/drivers/media/platform/msm/camera/cam_jpeg/jpeg_hw/cam_jpeg_hw_mgr.c b/drivers/media/platform/msm/camera/cam_jpeg/jpeg_hw/cam_jpeg_hw_mgr.c
index b06b5c4..2cd6b04 100644
--- a/drivers/media/platform/msm/camera/cam_jpeg/jpeg_hw/cam_jpeg_hw_mgr.c
+++ b/drivers/media/platform/msm/camera/cam_jpeg/jpeg_hw/cam_jpeg_hw_mgr.c
@@ -214,22 +214,22 @@
static int cam_jpeg_mgr_release_ctx(
- struct cam_jpeg_hw_mgr *hw_mgr, int ctx_id)
+ struct cam_jpeg_hw_mgr *hw_mgr, struct cam_jpeg_hw_ctx_data *ctx_data)
{
- if (ctx_id >= CAM_JPEG_CTX_MAX) {
- CAM_ERR(CAM_JPEG, "ctx_id is wrong: %d", ctx_id);
+ if (!ctx_data) {
+ CAM_ERR(CAM_JPEG, "invalid ctx_data %pK", ctx_data);
return -EINVAL;
}
- mutex_lock(&hw_mgr->ctx_data[ctx_id].ctx_mutex);
- if (!hw_mgr->ctx_data[ctx_id].in_use) {
- CAM_ERR(CAM_JPEG, "ctx is already in use: %d", ctx_id);
- mutex_unlock(&hw_mgr->ctx_data[ctx_id].ctx_mutex);
+ mutex_lock(&ctx_data->ctx_mutex);
+ if (!ctx_data->in_use) {
+ CAM_ERR(CAM_JPEG, "ctx is already un-used: %pK", ctx_data);
+ mutex_unlock(&ctx_data->ctx_mutex);
return -EINVAL;
}
- hw_mgr->ctx_data[ctx_id].in_use = 0;
- mutex_unlock(&hw_mgr->ctx_data[ctx_id].ctx_mutex);
+ ctx_data->in_use = false;
+ mutex_unlock(&ctx_data->ctx_mutex);
return 0;
}
@@ -280,7 +280,8 @@
hw_mgr->dev_hw_cfg_args[p_cfg_req->dev_type][0] = p_cfg_req;
list_del_init(&p_cfg_req->list);
} else {
- CAM_ERR(CAM_JPEG, "NOT dequeing, just return");
+ CAM_DBG(CAM_JPEG, "Not dequeing, just return");
+ mutex_unlock(&hw_mgr->hw_mgr_mutex);
rc = -EFAULT;
goto end;
}
@@ -289,7 +290,7 @@
config_args = (struct cam_hw_config_args *)&p_cfg_req->hw_cfg_args;
request_id = task_data->request_id;
if (request_id != (uint64_t)config_args->priv) {
- CAM_WARN(CAM_JPEG, "not a recent req %d %d",
+ CAM_DBG(CAM_JPEG, "not a recent req %lld %lld",
request_id, (uint64_t)config_args->priv);
}
@@ -475,8 +476,8 @@
request_id = (uint64_t)config_args->priv;
hw_update_entries = config_args->hw_update_entries;
- CAM_DBG(CAM_JPEG, "ctx_data = %pK req_id = %d %pK",
- ctx_data, request_id, config_args->priv);
+ CAM_DBG(CAM_JPEG, "ctx_data = %pK req_id = %lld %lld",
+ ctx_data, request_id, (uint64_t)config_args->priv);
task = cam_req_mgr_workq_get_task(g_jpeg_hw_mgr.work_process_frame);
if (!task) {
CAM_ERR(CAM_JPEG, "no empty task");
@@ -578,7 +579,7 @@
(void *)packet, (void *)cmd_desc,
sizeof(struct cam_cmd_buf_desc));
- rc = cam_packet_util_process_patches(packet, hw_mgr->iommu_hdl);
+ rc = cam_packet_util_process_patches(packet, hw_mgr->iommu_hdl, -1);
if (rc) {
CAM_ERR(CAM_JPEG, "Patch processing failed %d", rc);
return rc;
@@ -631,13 +632,12 @@
static int cam_jpeg_mgr_release_hw(void *hw_mgr_priv, void *release_hw_args)
{
int rc;
- int ctx_id = 0;
struct cam_hw_release_args *release_hw = release_hw_args;
struct cam_jpeg_hw_mgr *hw_mgr = hw_mgr_priv;
struct cam_jpeg_hw_ctx_data *ctx_data = NULL;
uint32_t dev_type;
- if (!release_hw || !hw_mgr) {
+ if (!hw_mgr || !release_hw || !release_hw->ctxt_to_hw_map) {
CAM_ERR(CAM_JPEG, "Invalid args");
return -EINVAL;
}
@@ -671,7 +671,7 @@
}
mutex_unlock(&hw_mgr->hw_mgr_mutex);
- rc = cam_jpeg_mgr_release_ctx(hw_mgr, ctx_id);
+ rc = cam_jpeg_mgr_release_ctx(hw_mgr, ctx_data);
if (rc) {
mutex_unlock(&hw_mgr->hw_mgr_mutex);
return -EINVAL;
@@ -838,7 +838,7 @@
cam_cdm_release(hw_mgr->cdm_info[dev_type][0].cdm_handle);
acq_cdm_hdl_failed:
kfree(ctx_data->cdm_cmd);
- cam_jpeg_mgr_release_ctx(hw_mgr, ctx_id);
+ cam_jpeg_mgr_release_ctx(hw_mgr, ctx_data);
mutex_unlock(&hw_mgr->hw_mgr_mutex);
return rc;
diff --git a/drivers/media/platform/msm/camera/cam_jpeg/jpeg_hw/jpeg_dma_hw/jpeg_dma_core.c b/drivers/media/platform/msm/camera/cam_jpeg/jpeg_hw/jpeg_dma_hw/jpeg_dma_core.c
index 05c1a95..0a15f71 100644
--- a/drivers/media/platform/msm/camera/cam_jpeg/jpeg_hw/jpeg_dma_hw/jpeg_dma_core.c
+++ b/drivers/media/platform/msm/camera/cam_jpeg/jpeg_hw/jpeg_dma_hw/jpeg_dma_core.c
@@ -57,6 +57,13 @@
return -EINVAL;
}
+
+ mutex_lock(&core_info->core_mutex);
+ if (++core_info->ref_count > 1) {
+ mutex_unlock(&core_info->core_mutex);
+ return 0;
+ }
+
cpas_vote.ahb_vote.type = CAM_VOTE_ABSOLUTE;
cpas_vote.ahb_vote.vote.level = CAM_SVS_VOTE;
cpas_vote.axi_vote.compressed_bw = JPEG_TURBO_VOTE;
@@ -64,15 +71,26 @@
rc = cam_cpas_start(core_info->cpas_handle,
&cpas_vote.ahb_vote, &cpas_vote.axi_vote);
- if (rc)
+ if (rc) {
CAM_ERR(CAM_JPEG, "cpass start failed: %d", rc);
+ goto cpas_failed;
+ }
rc = cam_jpeg_dma_enable_soc_resources(soc_info);
if (rc) {
CAM_ERR(CAM_JPEG, "soc enable is failed %d", rc);
- cam_cpas_stop(core_info->cpas_handle);
+ goto soc_failed;
}
+ mutex_unlock(&core_info->core_mutex);
+
+ return 0;
+
+soc_failed:
+ cam_cpas_stop(core_info->cpas_handle);
+cpas_failed:
+ --core_info->ref_count;
+ mutex_unlock(&core_info->core_mutex);
return rc;
}
@@ -98,6 +116,19 @@
return -EINVAL;
}
+ mutex_lock(&core_info->core_mutex);
+ if (--core_info->ref_count > 0) {
+ mutex_unlock(&core_info->core_mutex);
+ return 0;
+ }
+
+ if (core_info->ref_count < 0) {
+ CAM_ERR(CAM_JPEG, "ref cnt %d", core_info->ref_count);
+ core_info->ref_count = 0;
+ mutex_unlock(&core_info->core_mutex);
+ return -EFAULT;
+ }
+
rc = cam_jpeg_dma_disable_soc_resources(soc_info);
if (rc)
CAM_ERR(CAM_JPEG, "soc enable failed %d", rc);
@@ -106,6 +137,8 @@
if (rc)
CAM_ERR(CAM_JPEG, "cpas stop failed: %d", rc);
+ mutex_unlock(&core_info->core_mutex);
+
return 0;
}
diff --git a/drivers/media/platform/msm/camera/cam_jpeg/jpeg_hw/jpeg_dma_hw/jpeg_dma_core.h b/drivers/media/platform/msm/camera/cam_jpeg/jpeg_hw/jpeg_dma_hw/jpeg_dma_core.h
index bb4e34a..1e0c2e2 100644
--- a/drivers/media/platform/msm/camera/cam_jpeg/jpeg_hw/jpeg_dma_hw/jpeg_dma_core.h
+++ b/drivers/media/platform/msm/camera/cam_jpeg/jpeg_hw/jpeg_dma_hw/jpeg_dma_core.h
@@ -41,6 +41,8 @@
struct cam_jpeg_dma_device_hw_info *jpeg_dma_hw_info;
uint32_t cpas_handle;
struct cam_jpeg_dma_set_irq_cb irq_cb;
+ int32_t ref_count;
+ struct mutex core_mutex;
};
int cam_jpeg_dma_init_hw(void *device_priv,
diff --git a/drivers/media/platform/msm/camera/cam_jpeg/jpeg_hw/jpeg_dma_hw/jpeg_dma_dev.c b/drivers/media/platform/msm/camera/cam_jpeg/jpeg_hw/jpeg_dma_hw/jpeg_dma_dev.c
index 55a344d..ed58b41 100644
--- a/drivers/media/platform/msm/camera/cam_jpeg/jpeg_hw/jpeg_dma_hw/jpeg_dma_dev.c
+++ b/drivers/media/platform/msm/camera/cam_jpeg/jpeg_hw/jpeg_dma_hw/jpeg_dma_dev.c
@@ -99,6 +99,7 @@
if (rc)
CAM_ERR(CAM_JPEG, " unreg failed to reg cpas %d", rc);
+ mutex_destroy(&core_info->core_mutex);
kfree(core_info);
deinit_soc:
@@ -165,13 +166,14 @@
hw_info = (struct cam_jpeg_dma_device_hw_info *)match_dev->data;
core_info->jpeg_dma_hw_info = hw_info;
core_info->core_state = CAM_JPEG_DMA_CORE_NOT_READY;
+ mutex_init(&core_info->core_mutex);
rc = cam_jpeg_dma_init_soc_resources(&jpeg_dma_dev->soc_info,
cam_jpeg_dma_irq,
jpeg_dma_dev);
if (rc) {
CAM_ERR(CAM_JPEG, "%failed to init_soc %d", rc);
- goto error_match_dev;
+ goto error_init_soc;
}
rc = cam_jpeg_dma_register_cpas(&jpeg_dma_dev->soc_info,
@@ -191,6 +193,8 @@
error_reg_cpas:
rc = cam_soc_util_release_platform_resource(&jpeg_dma_dev->soc_info);
+error_init_soc:
+ mutex_destroy(&core_info->core_mutex);
error_match_dev:
kfree(jpeg_dma_dev->core_info);
error_alloc_core:
diff --git a/drivers/media/platform/msm/camera/cam_jpeg/jpeg_hw/jpeg_dma_hw/jpeg_dma_soc.c b/drivers/media/platform/msm/camera/cam_jpeg/jpeg_hw/jpeg_dma_hw/jpeg_dma_soc.c
index efc161b..63d54fd 100644
--- a/drivers/media/platform/msm/camera/cam_jpeg/jpeg_hw/jpeg_dma_hw/jpeg_dma_soc.c
+++ b/drivers/media/platform/msm/camera/cam_jpeg/jpeg_hw/jpeg_dma_hw/jpeg_dma_soc.c
@@ -55,7 +55,7 @@
{
int rc;
- rc = cam_soc_util_disable_platform_resource(soc_info, true, false);
+ rc = cam_soc_util_disable_platform_resource(soc_info, true, true);
if (rc)
CAM_ERR(CAM_JPEG, "disable platform failed %d", rc);
diff --git a/drivers/media/platform/msm/camera/cam_jpeg/jpeg_hw/jpeg_enc_hw/jpeg_enc_core.c b/drivers/media/platform/msm/camera/cam_jpeg/jpeg_hw/jpeg_enc_hw/jpeg_enc_core.c
index 25405cf..06ad260 100644
--- a/drivers/media/platform/msm/camera/cam_jpeg/jpeg_hw/jpeg_enc_hw/jpeg_enc_core.c
+++ b/drivers/media/platform/msm/camera/cam_jpeg/jpeg_hw/jpeg_enc_hw/jpeg_enc_core.c
@@ -100,6 +100,13 @@
return -EINVAL;
}
+
+ mutex_lock(&core_info->core_mutex);
+ if (++core_info->ref_count > 1) {
+ mutex_unlock(&core_info->core_mutex);
+ return 0;
+ }
+
cpas_vote.ahb_vote.type = CAM_VOTE_ABSOLUTE;
cpas_vote.ahb_vote.vote.level = CAM_SVS_VOTE;
cpas_vote.axi_vote.compressed_bw = JPEG_TURBO_VOTE;
@@ -107,15 +114,26 @@
rc = cam_cpas_start(core_info->cpas_handle,
&cpas_vote.ahb_vote, &cpas_vote.axi_vote);
- if (rc)
+ if (rc) {
CAM_ERR(CAM_JPEG, "cpass start failed: %d", rc);
+ goto cpas_failed;
+ }
rc = cam_jpeg_enc_enable_soc_resources(soc_info);
if (rc) {
CAM_ERR(CAM_JPEG, "soc enable is failed %d", rc);
- cam_cpas_stop(core_info->cpas_handle);
+ goto soc_failed;
}
+ mutex_unlock(&core_info->core_mutex);
+
+ return 0;
+
+soc_failed:
+ cam_cpas_stop(core_info->cpas_handle);
+cpas_failed:
+ --core_info->ref_count;
+ mutex_unlock(&core_info->core_mutex);
return rc;
}
@@ -141,6 +159,19 @@
return -EINVAL;
}
+ mutex_lock(&core_info->core_mutex);
+ if (--core_info->ref_count > 0) {
+ mutex_unlock(&core_info->core_mutex);
+ return 0;
+ }
+
+ if (core_info->ref_count < 0) {
+ CAM_ERR(CAM_JPEG, "ref cnt %d", core_info->ref_count);
+ core_info->ref_count = 0;
+ mutex_unlock(&core_info->core_mutex);
+ return -EFAULT;
+ }
+
rc = cam_jpeg_enc_disable_soc_resources(soc_info);
if (rc)
CAM_ERR(CAM_JPEG, "soc enable failed %d", rc);
@@ -149,6 +180,8 @@
if (rc)
CAM_ERR(CAM_JPEG, "cpas stop failed: %d", rc);
+ mutex_unlock(&core_info->core_mutex);
+
return 0;
}
diff --git a/drivers/media/platform/msm/camera/cam_jpeg/jpeg_hw/jpeg_enc_hw/jpeg_enc_core.h b/drivers/media/platform/msm/camera/cam_jpeg/jpeg_hw/jpeg_enc_hw/jpeg_enc_core.h
index 6ae4cdc..eb5caef 100644
--- a/drivers/media/platform/msm/camera/cam_jpeg/jpeg_hw/jpeg_enc_hw/jpeg_enc_core.h
+++ b/drivers/media/platform/msm/camera/cam_jpeg/jpeg_hw/jpeg_enc_hw/jpeg_enc_core.h
@@ -45,6 +45,8 @@
struct cam_jpeg_enc_device_hw_info *jpeg_enc_hw_info;
uint32_t cpas_handle;
struct cam_jpeg_enc_set_irq_cb irq_cb;
+ int32_t ref_count;
+ struct mutex core_mutex;
};
int cam_jpeg_enc_init_hw(void *device_priv,
diff --git a/drivers/media/platform/msm/camera/cam_jpeg/jpeg_hw/jpeg_enc_hw/jpeg_enc_dev.c b/drivers/media/platform/msm/camera/cam_jpeg/jpeg_hw/jpeg_enc_hw/jpeg_enc_dev.c
index a8f309a..570d9f9 100644
--- a/drivers/media/platform/msm/camera/cam_jpeg/jpeg_hw/jpeg_enc_hw/jpeg_enc_dev.c
+++ b/drivers/media/platform/msm/camera/cam_jpeg/jpeg_hw/jpeg_enc_hw/jpeg_enc_dev.c
@@ -103,6 +103,7 @@
if (rc)
CAM_ERR(CAM_JPEG, " unreg failed to reg cpas %d", rc);
+ mutex_destroy(&core_info->core_mutex);
kfree(core_info);
deinit_soc:
@@ -171,13 +172,14 @@
hw_info = (struct cam_jpeg_enc_device_hw_info *)match_dev->data;
core_info->jpeg_enc_hw_info = hw_info;
core_info->core_state = CAM_JPEG_ENC_CORE_NOT_READY;
+ mutex_init(&core_info->core_mutex);
rc = cam_jpeg_enc_init_soc_resources(&jpeg_enc_dev->soc_info,
cam_jpeg_enc_irq,
jpeg_enc_dev);
if (rc) {
CAM_ERR(CAM_JPEG, " failed to init_soc %d", rc);
- goto error_match_dev;
+ goto error_init_soc;
}
rc = cam_jpeg_enc_register_cpas(&jpeg_enc_dev->soc_info,
@@ -195,6 +197,8 @@
error_reg_cpas:
cam_soc_util_release_platform_resource(&jpeg_enc_dev->soc_info);
+error_init_soc:
+ mutex_destroy(&core_info->core_mutex);
error_match_dev:
kfree(jpeg_enc_dev->core_info);
error_alloc_core:
diff --git a/drivers/media/platform/msm/camera/cam_jpeg/jpeg_hw/jpeg_enc_hw/jpeg_enc_soc.c b/drivers/media/platform/msm/camera/cam_jpeg/jpeg_hw/jpeg_enc_hw/jpeg_enc_soc.c
index 3f450cd..ddf2465 100644
--- a/drivers/media/platform/msm/camera/cam_jpeg/jpeg_hw/jpeg_enc_hw/jpeg_enc_soc.c
+++ b/drivers/media/platform/msm/camera/cam_jpeg/jpeg_hw/jpeg_enc_hw/jpeg_enc_soc.c
@@ -55,7 +55,7 @@
{
int rc;
- rc = cam_soc_util_disable_platform_resource(soc_info, true, false);
+ rc = cam_soc_util_disable_platform_resource(soc_info, true, true);
if (rc)
CAM_ERR(CAM_JPEG, "disable platform failed %d", rc);
diff --git a/drivers/media/platform/msm/camera/cam_req_mgr/cam_mem_mgr.c b/drivers/media/platform/msm/camera/cam_req_mgr/cam_mem_mgr.c
index c150244..9d454e9 100644
--- a/drivers/media/platform/msm/camera/cam_req_mgr/cam_mem_mgr.c
+++ b/drivers/media/platform/msm/camera/cam_req_mgr/cam_mem_mgr.c
@@ -52,6 +52,8 @@
rc = DMA_FROM_DEVICE;
else if (flags & CAM_MEM_FLAG_HW_READ_WRITE)
rc = DMA_BIDIRECTIONAL;
+ else if (flags & CAM_MEM_FLAG_PROTECTED_MODE)
+ rc = DMA_BIDIRECTIONAL;
return rc;
}
@@ -211,10 +213,16 @@
goto handle_mismatch;
}
- rc = cam_smmu_get_iova(mmu_handle,
- tbl.bufq[idx].fd,
- iova_ptr,
- len_ptr);
+ if (CAM_MEM_MGR_IS_SECURE_HDL(buf_handle))
+ rc = cam_smmu_get_stage2_iova(mmu_handle,
+ tbl.bufq[idx].fd,
+ iova_ptr,
+ len_ptr);
+ else
+ rc = cam_smmu_get_iova(mmu_handle,
+ tbl.bufq[idx].fd,
+ iova_ptr,
+ len_ptr);
if (rc < 0)
CAM_ERR(CAM_CRM, "fail to get buf hdl :%d", buf_handle);
@@ -376,10 +384,12 @@
uint32_t ion_flag = 0;
int rc;
- if (cmd->flags & CAM_MEM_FLAG_PROTECTED_MODE)
+ if (cmd->flags & CAM_MEM_FLAG_PROTECTED_MODE) {
heap_id = ION_HEAP(ION_SECURE_DISPLAY_HEAP_ID);
- else
+ ion_flag |= ION_FLAG_SECURE | ION_FLAG_CP_CAMERA;
+ } else {
heap_id = ION_HEAP(ION_SYSTEM_HEAP_ID);
+ }
if (cmd->flags & CAM_MEM_FLAG_CACHE)
ion_flag |= ION_FLAG_CACHED;
@@ -466,10 +476,11 @@
if (flags & CAM_MEM_FLAG_PROTECTED_MODE) {
for (i = 0; i < num_hdls; i++) {
- rc = cam_smmu_map_sec_iova(mmu_hdls[i],
+ rc = cam_smmu_map_stage2_iova(mmu_hdls[i],
fd,
dir,
- (dma_addr_t *)hw_vaddr,
+ tbl.client,
+ (ion_phys_addr_t *)hw_vaddr,
len);
if (rc < 0) {
@@ -498,7 +509,7 @@
multi_map_fail:
if (flags & CAM_MEM_FLAG_PROTECTED_MODE)
for (--i; i > 0; i--)
- cam_smmu_unmap_sec_iova(mmu_hdls[i], fd);
+ cam_smmu_unmap_stage2_iova(mmu_hdls[i], fd);
else
for (--i; i > 0; i--)
cam_smmu_unmap_iova(mmu_hdls[i],
@@ -543,8 +554,9 @@
goto slot_fail;
}
- if (cmd->flags & CAM_MEM_FLAG_HW_READ_WRITE ||
- cmd->flags & CAM_MEM_FLAG_HW_SHARED_ACCESS) {
+ if ((cmd->flags & CAM_MEM_FLAG_HW_READ_WRITE) ||
+ (cmd->flags & CAM_MEM_FLAG_HW_SHARED_ACCESS) ||
+ (cmd->flags & CAM_MEM_FLAG_PROTECTED_MODE)) {
enum cam_smmu_region_id region;
@@ -570,6 +582,8 @@
tbl.bufq[idx].fd = ion_fd;
tbl.bufq[idx].flags = cmd->flags;
tbl.bufq[idx].buf_handle = GET_MEM_HANDLE(idx, ion_fd);
+ if (cmd->flags & CAM_MEM_FLAG_PROTECTED_MODE)
+ CAM_MEM_MGR_SET_SECURE_HDL(tbl.bufq[idx].buf_handle, true);
tbl.bufq[idx].kmdvaddr = 0;
if (cmd->num_hdl > 0)
@@ -630,7 +644,8 @@
return -EINVAL;
}
- if (cmd->flags & CAM_MEM_FLAG_HW_READ_WRITE) {
+ if ((cmd->flags & CAM_MEM_FLAG_HW_READ_WRITE) ||
+ (cmd->flags & CAM_MEM_FLAG_PROTECTED_MODE)) {
rc = cam_mem_util_map_hw_va(cmd->flags,
cmd->mmu_hdls,
cmd->num_hdl,
@@ -652,6 +667,8 @@
tbl.bufq[idx].fd = cmd->fd;
tbl.bufq[idx].flags = cmd->flags;
tbl.bufq[idx].buf_handle = GET_MEM_HANDLE(idx, cmd->fd);
+ if (cmd->flags & CAM_MEM_FLAG_PROTECTED_MODE)
+ CAM_MEM_MGR_SET_SECURE_HDL(tbl.bufq[idx].buf_handle, true);
tbl.bufq[idx].kmdvaddr = 0;
if (cmd->num_hdl > 0)
@@ -699,7 +716,7 @@
if (flags & CAM_MEM_FLAG_PROTECTED_MODE) {
for (i = 0; i < num_hdls; i++) {
- rc = cam_smmu_unmap_sec_iova(mmu_hdls[i], fd);
+ rc = cam_smmu_unmap_stage2_iova(mmu_hdls[i], fd);
if (rc < 0)
goto unmap_end;
}
@@ -741,8 +758,9 @@
region = CAM_SMMU_REGION_IO;
}
- if (tbl.bufq[idx].flags & CAM_MEM_FLAG_HW_READ_WRITE ||
- tbl.bufq[idx].flags & CAM_MEM_FLAG_HW_SHARED_ACCESS)
+ if ((tbl.bufq[idx].flags & CAM_MEM_FLAG_HW_READ_WRITE) ||
+ (tbl.bufq[idx].flags & CAM_MEM_FLAG_HW_SHARED_ACCESS) ||
+ (tbl.bufq[idx].flags & CAM_MEM_FLAG_PROTECTED_MODE))
rc = cam_mem_util_unmap_hw_va(idx, region);
diff --git a/drivers/media/platform/msm/camera/cam_req_mgr/cam_mem_mgr_api.h b/drivers/media/platform/msm/camera/cam_req_mgr/cam_mem_mgr_api.h
index 0858b8a..af7962a 100644
--- a/drivers/media/platform/msm/camera/cam_req_mgr/cam_mem_mgr_api.h
+++ b/drivers/media/platform/msm/camera/cam_req_mgr/cam_mem_mgr_api.h
@@ -95,4 +95,9 @@
int cam_mem_get_cpu_buf(int32_t buf_handle, uint64_t *vaddr_ptr,
size_t *len);
+static inline bool cam_mem_is_secure_buf(int32_t buf_handle)
+{
+ return CAM_MEM_MGR_IS_SECURE_HDL(buf_handle);
+}
+
#endif /* _CAM_MEM_MGR_API_H_ */
diff --git a/drivers/media/platform/msm/camera/cam_req_mgr/cam_req_mgr_core.c b/drivers/media/platform/msm/camera/cam_req_mgr/cam_req_mgr_core.c
index 96d5b6e..681504d 100644
--- a/drivers/media/platform/msm/camera/cam_req_mgr/cam_req_mgr_core.c
+++ b/drivers/media/platform/msm/camera/cam_req_mgr/cam_req_mgr_core.c
@@ -414,7 +414,7 @@
}
}
if (rc < 0) {
- CAM_ERR(CAM_CRM, "APPLY FAILED pd %d req_id %lld",
+ CAM_ERR_RATE_LIMIT(CAM_CRM, "APPLY FAILED pd %d req_id %lld",
dev->dev_info.p_delay, apply_req.request_id);
/* Apply req failed notify already applied devs */
for (; i >= 0; i--) {
@@ -525,7 +525,8 @@
if (trigger == CAM_TRIGGER_POINT_SOF) {
if (link->trigger_mask) {
- CAM_ERR(CAM_CRM, "Applying for last EOF fails");
+ CAM_ERR_RATE_LIMIT(CAM_CRM,
+ "Applying for last EOF fails");
return -EINVAL;
}
rc = __cam_req_mgr_check_link_is_ready(link, slot->idx);
@@ -542,7 +543,7 @@
* ready, don't expect to enter here.
* @TODO: gracefully handle if recovery fails.
*/
- CAM_ERR(CAM_CRM,
+ CAM_ERR_RATE_LIMIT(CAM_CRM,
"FATAL recovery cant finish idx %d status %d",
in_q->rd_idx,
in_q->slot[in_q->rd_idx].status);
@@ -553,7 +554,7 @@
}
if (trigger == CAM_TRIGGER_POINT_EOF &&
(!(link->trigger_mask & CAM_TRIGGER_POINT_SOF))) {
- CAM_ERR(CAM_CRM, "Applying for last SOF fails");
+ CAM_DBG(CAM_CRM, "Applying for last SOF fails");
return -EINVAL;
}
@@ -902,7 +903,13 @@
CAM_ERR(CAM_CRM, "failed to create link, no mem");
return NULL;
}
- in_q = &session->in_q;
+ in_q = (struct cam_req_mgr_req_queue *)
+ kzalloc(sizeof(struct cam_req_mgr_req_queue), GFP_KERNEL);
+ if (!in_q) {
+ CAM_ERR(CAM_CRM, "failed to create input queue, no mem");
+ kfree(link);
+ return NULL;
+ }
mutex_init(&link->lock);
mutex_lock(&link->lock);
@@ -928,7 +935,7 @@
}
/**
- * __cam_req_mgr_reserve_link()
+ * __cam_req_mgr_unreserve_link()
*
* @brief : Reserves one link data struct within session
* @session: session identifier
@@ -960,6 +967,8 @@
CAM_DBG(CAM_CRM, "Active session links (%d)",
session->num_links);
}
+ kfree((*link)->req.in_q);
+ (*link)->req.in_q = NULL;
kfree(*link);
*link = NULL;
mutex_unlock(&session->lock);
@@ -1178,7 +1187,7 @@
}
}
if (!tbl) {
- CAM_ERR(CAM_CRM, "dev_hdl not found %x, %x %x",
+ CAM_ERR_RATE_LIMIT(CAM_CRM, "dev_hdl not found %x, %x %x",
add_req->dev_hdl,
link->l_dev[0].dev_hdl,
link->l_dev[1].dev_hdl);
@@ -1267,8 +1276,9 @@
if (err_info->error == CRM_KMD_ERR_BUBBLE) {
idx = __cam_req_mgr_find_slot_for_req(in_q, err_info->req_id);
if (idx < 0) {
- CAM_ERR(CAM_CRM, "req_id %lld not found in input queue",
- err_info->req_id);
+ CAM_ERR_RATE_LIMIT(CAM_CRM,
+ "req_id %lld not found in input queue",
+ err_info->req_id);
} else {
CAM_DBG(CAM_CRM, "req_id %lld found at idx %d",
err_info->req_id, idx);
@@ -1430,7 +1440,7 @@
task = cam_req_mgr_workq_get_task(link->workq);
if (!task) {
- CAM_ERR(CAM_CRM, "no empty task dev %x req %lld",
+ CAM_ERR_RATE_LIMIT(CAM_CRM, "no empty task dev %x req %lld",
add_req->dev_hdl, add_req->req_id);
rc = -EBUSY;
goto end;
@@ -1902,10 +1912,7 @@
cam_destroy_device_hdl(link->link_hdl);
link_info->link_hdl = 0;
link_hdl_fail:
- mutex_lock(&link->lock);
- link->state = CAM_CRM_LINK_STATE_AVAILABLE;
- mutex_unlock(&link->lock);
-
+ __cam_req_mgr_unreserve_link(cam_session, &link);
mutex_unlock(&g_crm_core_dev->crm_lock);
return rc;
}
diff --git a/drivers/media/platform/msm/camera/cam_req_mgr/cam_req_mgr_core.h b/drivers/media/platform/msm/camera/cam_req_mgr/cam_req_mgr_core.h
index 98a2a4f..e45d634 100644
--- a/drivers/media/platform/msm/camera/cam_req_mgr/cam_req_mgr_core.h
+++ b/drivers/media/platform/msm/camera/cam_req_mgr/cam_req_mgr_core.h
@@ -315,7 +315,6 @@
int32_t session_hdl;
uint32_t num_links;
struct cam_req_mgr_core_link *links[MAX_LINKS_PER_SESSION];
- struct cam_req_mgr_req_queue in_q;
struct list_head entry;
struct mutex lock;
int32_t force_err_recovery;
diff --git a/drivers/media/platform/msm/camera/cam_req_mgr/cam_req_mgr_dev.c b/drivers/media/platform/msm/camera/cam_req_mgr/cam_req_mgr_dev.c
index 7a2bc09..e4bc98f 100644
--- a/drivers/media/platform/msm/camera/cam_req_mgr/cam_req_mgr_dev.c
+++ b/drivers/media/platform/msm/camera/cam_req_mgr/cam_req_mgr_dev.c
@@ -500,6 +500,12 @@
g_dev.video = NULL;
}
+void cam_register_subdev_fops(struct v4l2_file_operations *fops)
+{
+ *fops = v4l2_subdev_fops;
+}
+EXPORT_SYMBOL(cam_register_subdev_fops);
+
int cam_register_subdev(struct cam_subdev *csd)
{
struct v4l2_subdev *sd;
diff --git a/drivers/media/platform/msm/camera/cam_req_mgr/cam_req_mgr_util.c b/drivers/media/platform/msm/camera/cam_req_mgr/cam_req_mgr_util.c
index a9134fb..1d2169b 100644
--- a/drivers/media/platform/msm/camera/cam_req_mgr/cam_req_mgr_util.c
+++ b/drivers/media/platform/msm/camera/cam_req_mgr/cam_req_mgr_util.c
@@ -203,29 +203,29 @@
spin_lock_bh(&hdl_tbl_lock);
if (!hdl_tbl) {
- CAM_ERR(CAM_CRM, "Hdl tbl is NULL");
+ CAM_ERR_RATE_LIMIT(CAM_CRM, "Hdl tbl is NULL");
goto device_priv_fail;
}
idx = CAM_REQ_MGR_GET_HDL_IDX(dev_hdl);
if (idx >= CAM_REQ_MGR_MAX_HANDLES) {
- CAM_ERR(CAM_CRM, "Invalid idx");
+ CAM_ERR_RATE_LIMIT(CAM_CRM, "Invalid idx");
goto device_priv_fail;
}
if (hdl_tbl->hdl[idx].state != HDL_ACTIVE) {
- CAM_ERR(CAM_CRM, "Invalid state");
+ CAM_ERR_RATE_LIMIT(CAM_CRM, "Invalid state");
goto device_priv_fail;
}
type = CAM_REQ_MGR_GET_HDL_TYPE(dev_hdl);
if (HDL_TYPE_DEV != type && HDL_TYPE_SESSION != type) {
- CAM_ERR(CAM_CRM, "Invalid type");
+ CAM_ERR_RATE_LIMIT(CAM_CRM, "Invalid type");
goto device_priv_fail;
}
if (hdl_tbl->hdl[idx].hdl_value != dev_hdl) {
- CAM_ERR(CAM_CRM, "Invalid hdl");
+ CAM_ERR_RATE_LIMIT(CAM_CRM, "Invalid hdl");
goto device_priv_fail;
}
diff --git a/drivers/media/platform/msm/camera/cam_req_mgr/cam_subdev.h b/drivers/media/platform/msm/camera/cam_req_mgr/cam_subdev.h
index 78f2223..8cd3214 100644
--- a/drivers/media/platform/msm/camera/cam_req_mgr/cam_subdev.h
+++ b/drivers/media/platform/msm/camera/cam_req_mgr/cam_subdev.h
@@ -82,6 +82,15 @@
int cam_subdev_remove(struct cam_subdev *sd);
/**
+ * cam_register_subdev_fops()
+ *
+ * @brief: This common utility function assigns subdev ops
+ *
+ * @fops: v4l file operations
+ */
+void cam_register_subdev_fops(struct v4l2_file_operations *fops);
+
+/**
* cam_register_subdev()
*
* @brief: This is the common utility function to be called by each camera
diff --git a/drivers/media/platform/msm/camera/cam_sensor_module/cam_actuator/cam_actuator_core.c b/drivers/media/platform/msm/camera/cam_sensor_module/cam_actuator/cam_actuator_core.c
index bcf4133..8ffa0ff 100644
--- a/drivers/media/platform/msm/camera/cam_sensor_module/cam_actuator/cam_actuator_core.c
+++ b/drivers/media/platform/msm/camera/cam_sensor_module/cam_actuator/cam_actuator_core.c
@@ -161,7 +161,7 @@
}
request_id = apply->request_id % MAX_PER_FRAME_ARRAY;
- trace_cam_apply_req("Actuator", apply);
+ trace_cam_apply_req("Actuator", apply->request_id);
CAM_DBG(CAM_ACTUATOR, "Request Id: %lld", apply->request_id);
diff --git a/drivers/media/platform/msm/camera/cam_sensor_module/cam_actuator/cam_actuator_dev.c b/drivers/media/platform/msm/camera/cam_sensor_module/cam_actuator/cam_actuator_dev.c
index e58f737..b58f5d8 100644
--- a/drivers/media/platform/msm/camera/cam_sensor_module/cam_actuator/cam_actuator_dev.c
+++ b/drivers/media/platform/msm/camera/cam_sensor_module/cam_actuator/cam_actuator_dev.c
@@ -286,6 +286,7 @@
}
/* Fill platform device id*/
+ a_ctrl->id = a_ctrl->soc_info.index;
pdev->id = a_ctrl->id;
rc = cam_actuator_init_subdev(a_ctrl);
diff --git a/drivers/media/platform/msm/camera/cam_sensor_module/cam_cci/cam_cci_dev.c b/drivers/media/platform/msm/camera/cam_sensor_module/cam_cci/cam_cci_dev.c
index 6aa7586..6cfb965 100644
--- a/drivers/media/platform/msm/camera/cam_sensor_module/cam_cci/cam_cci_dev.c
+++ b/drivers/media/platform/msm/camera/cam_sensor_module/cam_cci/cam_cci_dev.c
@@ -30,6 +30,11 @@
{
int32_t rc = 0;
+ if (arg == NULL) {
+ CAM_ERR(CAM_CCI, "Invalid Args");
+ return rc;
+ }
+
switch (cmd) {
case VIDIOC_MSM_CCI_CFG:
rc = cam_cci_core_cfg(sd, arg);
@@ -44,6 +49,14 @@
return rc;
}
+#ifdef CONFIG_COMPAT
+static long cam_cci_subdev_compat_ioctl(struct v4l2_subdev *sd,
+ unsigned int cmd, unsigned long arg)
+{
+ return cam_cci_subdev_ioctl(sd, cmd, NULL);
+}
+#endif
+
irqreturn_t cam_cci_irq(int irq_num, void *data)
{
uint32_t irq;
@@ -162,6 +175,9 @@
static struct v4l2_subdev_core_ops cci_subdev_core_ops = {
.ioctl = cam_cci_subdev_ioctl,
+#ifdef CONFIG_COMPAT
+ .compat_ioctl32 = cam_cci_subdev_compat_ioctl,
+#endif
.interrupt_service_routine = cam_cci_irq_routine,
};
@@ -171,6 +187,34 @@
static const struct v4l2_subdev_internal_ops cci_subdev_intern_ops;
+static struct v4l2_file_operations cci_v4l2_subdev_fops;
+
+static long cam_cci_subdev_do_ioctl(
+ struct file *file, unsigned int cmd, void *arg)
+{
+ struct video_device *vdev = video_devdata(file);
+ struct v4l2_subdev *sd = vdev_to_v4l2_subdev(vdev);
+
+ return cam_cci_subdev_ioctl(sd, cmd, NULL);
+}
+
+static long cam_cci_subdev_fops_ioctl(struct file *file, unsigned int cmd,
+ unsigned long arg)
+{
+ return video_usercopy(file, cmd, arg, cam_cci_subdev_do_ioctl);
+}
+
+#ifdef CONFIG_COMPAT
+static long cam_cci_subdev_fops_compat_ioctl(struct file *file,
+ unsigned int cmd, unsigned long arg)
+{
+ struct video_device *vdev = video_devdata(file);
+ struct v4l2_subdev *sd = vdev_to_v4l2_subdev(vdev);
+
+ return v4l2_subdev_call(sd, core, ioctl, cmd, NULL);
+}
+#endif
+
static int cam_cci_platform_probe(struct platform_device *pdev)
{
struct cam_cpas_register_params cpas_parms;
@@ -222,6 +266,13 @@
v4l2_set_subdevdata(&new_cci_dev->v4l2_dev_str.sd, new_cci_dev);
g_cci_subdev = &new_cci_dev->v4l2_dev_str.sd;
+ cam_register_subdev_fops(&cci_v4l2_subdev_fops);
+ cci_v4l2_subdev_fops.unlocked_ioctl = cam_cci_subdev_fops_ioctl;
+#ifdef CONFIG_COMPAT
+ cci_v4l2_subdev_fops.compat_ioctl32 =
+ cam_cci_subdev_fops_compat_ioctl;
+#endif
+
cpas_parms.cam_cpas_client_cb = NULL;
cpas_parms.cell_index = 0;
cpas_parms.dev = &pdev->dev;
@@ -271,6 +322,26 @@
},
};
+static int cam_cci_assign_fops(void)
+{
+ struct v4l2_subdev *sd;
+
+ sd = g_cci_subdev;
+ if (!sd || !(sd->devnode)) {
+ CAM_ERR(CAM_CRM,
+ "Invalid args sd node: %pK", sd);
+ return -EINVAL;
+ }
+ sd->devnode->fops = &cci_v4l2_subdev_fops;
+
+ return 0;
+}
+
+static int __init cam_cci_late_init(void)
+{
+ return cam_cci_assign_fops();
+}
+
static int __init cam_cci_init_module(void)
{
return platform_driver_register(&cci_driver);
@@ -282,6 +353,7 @@
}
module_init(cam_cci_init_module);
+late_initcall(cam_cci_late_init);
module_exit(cam_cci_exit_module);
MODULE_DESCRIPTION("MSM CCI driver");
MODULE_LICENSE("GPL v2");
diff --git a/drivers/media/platform/msm/camera/cam_sensor_module/cam_csiphy/cam_csiphy_core.c b/drivers/media/platform/msm/camera/cam_sensor_module/cam_csiphy/cam_csiphy_core.c
index bdd3e72..1a3f947 100644
--- a/drivers/media/platform/msm/camera/cam_sensor_module/cam_csiphy/cam_csiphy_core.c
+++ b/drivers/media/platform/msm/camera/cam_sensor_module/cam_csiphy/cam_csiphy_core.c
@@ -14,10 +14,32 @@
#include "cam_csiphy_core.h"
#include "cam_csiphy_dev.h"
#include "cam_csiphy_soc.h"
+
+#include <soc/qcom/scm.h>
#include <cam_mem_mgr.h>
static int cam_csiphy_mem_dmp_param;
module_param(cam_csiphy_mem_dmp_param, int, 0644);
+#define SCM_SVC_CAMERASS 0x18
+#define SECURE_SYSCALL_ID 0x6
+
+static int cam_csiphy_notify_secure_mode(int phy, bool protect)
+{
+ struct scm_desc desc = {0};
+
+ desc.arginfo = SCM_ARGS(2, SCM_VAL, SCM_VAL);
+ desc.args[0] = protect;
+ desc.args[1] = phy;
+
+ CAM_DBG(CAM_CSIPHY, "phy : %d, protect : %d", phy, protect);
+ if (scm_call2(SCM_SIP_FNID(SCM_SVC_CAMERASS, SECURE_SYSCALL_ID),
+ &desc)) {
+ CAM_ERR(CAM_CSIPHY, "scm call to hypervisor failed");
+ return -EINVAL;
+ }
+
+ return 0;
+}
void cam_csiphy_query_cap(struct csiphy_device *csiphy_dev,
struct cam_csiphy_query_cap *csiphy_cap)
@@ -70,17 +92,10 @@
return -EINVAL;
}
- csiphy_dev->csiphy_info =
- kzalloc(sizeof(struct cam_csiphy_info), GFP_KERNEL);
- if (!csiphy_dev->csiphy_info)
- return -ENOMEM;
-
rc = cam_mem_get_cpu_buf((int32_t) cfg_dev->packet_handle,
(uint64_t *)&generic_ptr, &len);
if (rc < 0) {
CAM_ERR(CAM_CSIPHY, "Failed to get packet Mem address: %d", rc);
- kfree(csiphy_dev->csiphy_info);
- csiphy_dev->csiphy_info = NULL;
return rc;
}
@@ -88,8 +103,6 @@
CAM_ERR(CAM_CSIPHY,
"offset is out of bounds: offset: %lld len: %zu",
cfg_dev->offset, len);
- kfree(csiphy_dev->csiphy_info);
- csiphy_dev->csiphy_info = NULL;
return -EINVAL;
}
@@ -104,8 +117,6 @@
if (rc < 0) {
CAM_ERR(CAM_CSIPHY,
"Failed to get cmd buf Mem address : %d", rc);
- kfree(csiphy_dev->csiphy_info);
- csiphy_dev->csiphy_info = NULL;
return rc;
}
@@ -113,13 +124,26 @@
cmd_buf += cmd_desc->offset / 4;
cam_cmd_csiphy_info = (struct cam_csiphy_info *)cmd_buf;
- csiphy_dev->csiphy_info->lane_cnt = cam_cmd_csiphy_info->lane_cnt;
- csiphy_dev->csiphy_info->lane_mask = cam_cmd_csiphy_info->lane_mask;
- csiphy_dev->csiphy_info->csiphy_3phase =
+ csiphy_dev->config_count++;
+ csiphy_dev->csiphy_info.lane_cnt += cam_cmd_csiphy_info->lane_cnt;
+ csiphy_dev->csiphy_info.lane_mask |= cam_cmd_csiphy_info->lane_mask;
+ csiphy_dev->csiphy_info.csiphy_3phase =
cam_cmd_csiphy_info->csiphy_3phase;
- csiphy_dev->csiphy_info->combo_mode = cam_cmd_csiphy_info->combo_mode;
- csiphy_dev->csiphy_info->settle_time = cam_cmd_csiphy_info->settle_time;
- csiphy_dev->csiphy_info->data_rate = cam_cmd_csiphy_info->data_rate;
+ csiphy_dev->csiphy_info.combo_mode |= cam_cmd_csiphy_info->combo_mode;
+ if (cam_cmd_csiphy_info->combo_mode == 1)
+ csiphy_dev->csiphy_info.settle_time_combo_sensor =
+ cam_cmd_csiphy_info->settle_time;
+ else
+ csiphy_dev->csiphy_info.settle_time =
+ cam_cmd_csiphy_info->settle_time;
+ csiphy_dev->csiphy_info.data_rate = cam_cmd_csiphy_info->data_rate;
+ csiphy_dev->csiphy_info.secure_mode = cam_cmd_csiphy_info->secure_mode;
+
+ if (csiphy_dev->csiphy_info.secure_mode &&
+ (csiphy_dev->config_count == 1))
+ rc = cam_csiphy_notify_secure_mode(
+ csiphy_dev->soc_info.index,
+ CAM_SECURE_MODE_SECURE);
return rc;
}
@@ -205,14 +229,8 @@
void __iomem *csiphybase;
struct csiphy_reg_t (*reg_array)[MAX_SETTINGS_PER_LANE];
- if (csiphy_dev->csiphy_info == NULL) {
- CAM_ERR(CAM_CSIPHY, "csiphy_info is NULL, No/Fail CONFIG_DEV?");
- return -EINVAL;
- }
-
- lane_cnt = csiphy_dev->csiphy_info->lane_cnt;
- lane_mask = csiphy_dev->csiphy_info->lane_mask & 0x1f;
- settle_cnt = (csiphy_dev->csiphy_info->settle_time / 200000000);
+ lane_cnt = csiphy_dev->csiphy_info.lane_cnt;
+ lane_mask = csiphy_dev->csiphy_info.lane_mask & 0x1f;
csiphybase = csiphy_dev->soc_info.reg_map[0].mem_base;
if (!csiphybase) {
@@ -231,8 +249,8 @@
mask <<= 1;
}
- if (!csiphy_dev->csiphy_info->csiphy_3phase) {
- if (csiphy_dev->csiphy_info->combo_mode == 1)
+ if (!csiphy_dev->csiphy_info.csiphy_3phase) {
+ if (csiphy_dev->csiphy_info.combo_mode == 1)
reg_array =
csiphy_dev->ctrl_reg->csiphy_2ph_combo_mode_reg;
else
@@ -242,7 +260,7 @@
cfg_size = csiphy_dev->ctrl_reg->csiphy_reg.
csiphy_2ph_config_array_size;
} else {
- if (csiphy_dev->csiphy_info->combo_mode == 1)
+ if (csiphy_dev->csiphy_info.combo_mode == 1)
reg_array =
csiphy_dev->ctrl_reg->csiphy_2ph_3ph_mode_reg;
else
@@ -283,6 +301,12 @@
continue;
}
+ settle_cnt = (csiphy_dev->csiphy_info.settle_time / 200000000);
+ if (csiphy_dev->csiphy_info.combo_mode == 1 &&
+ (lane_pos >= 3))
+ settle_cnt =
+ (csiphy_dev->csiphy_info.
+ settle_time_combo_sensor / 200000000);
for (i = 0; i < cfg_size; i++) {
switch (reg_array[lane_pos][i].csiphy_param_type) {
case CSIPHY_LANE_ENABLE:
@@ -353,6 +377,14 @@
csiphy_acq_params.combo_mode = 0;
+ if (copy_from_user(&csiphy_acq_params,
+ (void __user *)csiphy_acq_dev.info_handle,
+ sizeof(csiphy_acq_params))) {
+ CAM_ERR(CAM_CSIPHY,
+ "Failed copying from User");
+ goto release_mutex;
+ }
+
if (csiphy_dev->acquire_count == 2) {
CAM_ERR(CAM_CSIPHY,
"CSIPHY device do not allow more than 2 acquires");
@@ -360,6 +392,27 @@
goto release_mutex;
}
+ if ((csiphy_acq_params.combo_mode == 1) &&
+ (csiphy_dev->is_acquired_dev_combo_mode == 1)) {
+ CAM_ERR(CAM_CSIPHY,
+ "Multiple Combo Acq are not allowed: cm: %d, acm: %d",
+ csiphy_acq_params.combo_mode,
+ csiphy_dev->is_acquired_dev_combo_mode);
+ rc = -EINVAL;
+ goto release_mutex;
+ }
+
+ if ((csiphy_acq_params.combo_mode != 1) &&
+ (csiphy_dev->is_acquired_dev_combo_mode != 1) &&
+ (csiphy_dev->acquire_count == 1)) {
+ CAM_ERR(CAM_CSIPHY,
+ "Multiple Acquires are not allowed cm: %d acm: %d",
+ csiphy_acq_params.combo_mode,
+ csiphy_dev->is_acquired_dev_combo_mode);
+ rc = -EINVAL;
+ goto release_mutex;
+ }
+
bridge_params.ops = NULL;
bridge_params.session_hdl = csiphy_acq_dev.session_handle;
bridge_params.v4l2_sub_dev_flag = 0;
@@ -384,7 +437,9 @@
}
if (csiphy_acq_params.combo_mode == 1)
csiphy_dev->is_acquired_dev_combo_mode = 1;
+
csiphy_dev->acquire_count++;
+ csiphy_dev->csiphy_state = CAM_CSIPHY_ACQUIRE;
}
break;
case CAM_QUERY_CAP: {
@@ -400,6 +455,19 @@
}
break;
case CAM_STOP_DEV: {
+ if (csiphy_dev->csiphy_state !=
+ CAM_CSIPHY_START) {
+ CAM_ERR(CAM_CSIPHY, "Not in right state to stop : %d",
+ csiphy_dev->csiphy_state);
+ goto release_mutex;
+ }
+
+ if (--csiphy_dev->start_dev_count) {
+ CAM_DBG(CAM_CSIPHY, "Stop Dev ref Cnt: %d",
+ csiphy_dev->start_dev_count);
+ goto release_mutex;
+ }
+
rc = cam_csiphy_disable_hw(csiphy_dev);
if (rc < 0) {
CAM_ERR(CAM_CSIPHY, "Failed in csiphy release");
@@ -411,6 +479,8 @@
CAM_ERR(CAM_CSIPHY, "de-voting CPAS: %d", rc);
goto release_mutex;
}
+ csiphy_dev->csiphy_info.combo_mode = 0;
+ csiphy_dev->csiphy_state = CAM_CSIPHY_STOP;
}
break;
case CAM_RELEASE_DEV: {
@@ -441,8 +511,22 @@
csiphy_dev->bridge_intf.link_hdl[1] = -1;
csiphy_dev->bridge_intf.
session_hdl[1] = -1;
+ csiphy_dev->is_acquired_dev_combo_mode = 0;
}
+
+ csiphy_dev->config_count--;
csiphy_dev->acquire_count--;
+ if (csiphy_dev->acquire_count == 0)
+ csiphy_dev->csiphy_state = CAM_CSIPHY_RELEASE;
+
+ if (csiphy_dev->csiphy_info.secure_mode &&
+ (!csiphy_dev->config_count)) {
+ csiphy_dev->csiphy_info.secure_mode =
+ CAM_SECURE_MODE_NON_SECURE;
+ rc = cam_csiphy_notify_secure_mode(
+ csiphy_dev->soc_info.index,
+ CAM_SECURE_MODE_NON_SECURE);
+ }
}
break;
case CAM_CONFIG_DEV: {
@@ -464,6 +548,11 @@
struct cam_ahb_vote ahb_vote;
struct cam_axi_vote axi_vote;
+ csiphy_dev->start_dev_count++;
+
+ if (csiphy_dev->csiphy_state == CAM_CSIPHY_START)
+ goto release_mutex;
+
ahb_vote.type = CAM_VOTE_ABSOLUTE;
ahb_vote.vote.level = CAM_SVS_VOTE;
axi_vote.compressed_bw = CAM_CPAS_DEFAULT_AXI_BW;
@@ -491,6 +580,7 @@
cam_cpas_stop(csiphy_dev->cpas_handle);
goto release_mutex;
}
+ csiphy_dev->csiphy_state = CAM_CSIPHY_START;
}
break;
case CAM_SD_SHUTDOWN:
diff --git a/drivers/media/platform/msm/camera/cam_sensor_module/cam_csiphy/cam_csiphy_dev.c b/drivers/media/platform/msm/camera/cam_sensor_module/cam_csiphy/cam_csiphy_dev.c
index 6e74344..a136fa7 100644
--- a/drivers/media/platform/msm/camera/cam_sensor_module/cam_csiphy/cam_csiphy_dev.c
+++ b/drivers/media/platform/msm/camera/cam_sensor_module/cam_csiphy/cam_csiphy_dev.c
@@ -157,6 +157,7 @@
NULL;
new_csiphy_dev->acquire_count = 0;
+ new_csiphy_dev->start_dev_count = 0;
new_csiphy_dev->is_acquired_dev_combo_mode = 0;
cpas_parms.cam_cpas_client_cb = NULL;
diff --git a/drivers/media/platform/msm/camera/cam_sensor_module/cam_csiphy/cam_csiphy_dev.h b/drivers/media/platform/msm/camera/cam_sensor_module/cam_csiphy/cam_csiphy_dev.h
index 8ed5ba4..25891c5 100644
--- a/drivers/media/platform/msm/camera/cam_sensor_module/cam_csiphy/cam_csiphy_dev.h
+++ b/drivers/media/platform/msm/camera/cam_sensor_module/cam_csiphy/cam_csiphy_dev.h
@@ -67,6 +67,13 @@
#define CDBG(fmt, args...) pr_debug(fmt, ##args)
#endif
+enum cam_csiphy_state {
+ CAM_CSIPHY_ACQUIRE,
+ CAM_CSIPHY_RELEASE,
+ CAM_CSIPHY_START,
+ CAM_CSIPHY_STOP,
+};
+
/**
* struct csiphy_reg_parms_t
* @mipi_csiphy_glbl_irq_cmd_addr: CSIPhy irq addr
@@ -150,6 +157,32 @@
};
/**
+ * cam_csiphy_param: Provides cmdbuffer structre
+ * @lane_mask : Lane mask details
+ * @lane_assign : Lane sensor will be using
+ * @csiphy_3phase : Mentions DPHY or CPHY
+ * @combo_mode : Info regarding combo_mode is enable / disable
+ * @lane_cnt : Total number of lanes
+ * @reserved
+ * @3phase : Details whether 3Phase / 2Phase operation
+ * @settle_time : Settling time in ms
+ * @settle_time_combo_sensor : Settling time in ms
+ * @data_rate : Data rate in mbps
+ *
+ */
+struct cam_csiphy_param {
+ uint16_t lane_mask;
+ uint16_t lane_assign;
+ uint8_t csiphy_3phase;
+ uint8_t combo_mode;
+ uint8_t lane_cnt;
+ uint8_t secure_mode;
+ uint64_t settle_time;
+ uint64_t settle_time_combo_sensor;
+ uint64_t data_rate;
+};
+
+/**
* struct csiphy_device
* @pdev: Platform device
* @irq: Interrupt structure
@@ -171,6 +204,7 @@
* @ref_count: Reference count
* @clk_lane: Clock lane
* @acquire_count: Acquire device count
+ * @start_dev_count: Start count
* @is_acquired_dev_combo_mode:
* Flag that mentions whether already acquired
* device is for combo mode
@@ -178,7 +212,7 @@
struct csiphy_device {
struct mutex mutex;
uint32_t hw_version;
- uint32_t csiphy_state;
+ enum cam_csiphy_state csiphy_state;
struct csiphy_ctrl_t *ctrl_reg;
uint32_t csiphy_max_clk;
struct msm_cam_clk_info csiphy_3p_clk_info[2];
@@ -190,14 +224,16 @@
uint8_t is_csiphy_3phase_hw;
uint8_t num_irq_registers;
struct cam_subdev v4l2_dev_str;
- struct cam_csiphy_info *csiphy_info;
+ struct cam_csiphy_param csiphy_info;
struct intf_params bridge_intf;
uint32_t clk_lane;
uint32_t acquire_count;
+ uint32_t start_dev_count;
char device_name[20];
uint32_t is_acquired_dev_combo_mode;
struct cam_hw_soc_info soc_info;
uint32_t cpas_handle;
+ uint32_t config_count;
};
#endif /* _CAM_CSIPHY_DEV_H_ */
diff --git a/drivers/media/platform/msm/camera/cam_sensor_module/cam_eeprom/cam_eeprom_core.c b/drivers/media/platform/msm/camera/cam_sensor_module/cam_eeprom/cam_eeprom_core.c
index 02b2c51..6eab59a 100644
--- a/drivers/media/platform/msm/camera/cam_sensor_module/cam_eeprom/cam_eeprom_core.c
+++ b/drivers/media/platform/msm/camera/cam_sensor_module/cam_eeprom/cam_eeprom_core.c
@@ -243,7 +243,8 @@
struct camera_io_master *client = &e_ctrl->io_master_info;
uint8_t id[2];
- rc = cam_spi_query_id(client, 0, &id[0], 2);
+ rc = cam_spi_query_id(client, 0, CAMERA_SENSOR_I2C_TYPE_WORD,
+ &id[0], 2);
if (rc)
return rc;
CAM_DBG(CAM_EEPROM, "read 0x%x 0x%x, check 0x%x 0x%x",
@@ -310,6 +311,8 @@
data_mem_free:
kfree(e_ctrl->cal_data.mapdata);
kfree(e_ctrl->cal_data.map);
+ e_ctrl->cal_data.num_data = 0;
+ e_ctrl->cal_data.num_map = 0;
return rc;
}
@@ -483,7 +486,7 @@
uint16_t cmd_length_in_bytes = 0;
struct cam_cmd_i2c_info *i2c_info = NULL;
int num_map = -1;
- struct cam_eeprom_memory_map_t *map;
+ struct cam_eeprom_memory_map_t *map = NULL;
struct cam_eeprom_soc_private *soc_private =
(struct cam_eeprom_soc_private *)e_ctrl->soc_info.soc_private;
struct cam_sensor_power_ctrl_t *power_info = &soc_private->power_info;
@@ -664,53 +667,60 @@
switch (csl_packet->header.op_code & 0xFFFFFF) {
case CAM_EEPROM_PACKET_OPCODE_INIT:
if (e_ctrl->userspace_probe == false) {
- rc = cam_eeprom_get_cal_data(e_ctrl, csl_packet);
- CAM_ERR(CAM_EEPROM,
- "Eeprom already probed at kernel boot");
- rc = -EINVAL;
- break;
- }
- if (e_ctrl->cal_data.num_data == 0) {
- rc = cam_eeprom_init_pkt_parser(e_ctrl, csl_packet);
- if (rc) {
- CAM_ERR(CAM_EEPROM,
- "Failed in parsing the pkt");
+ rc = cam_eeprom_parse_read_memory_map(
+ e_ctrl->pdev->dev.of_node, e_ctrl);
+ if (rc < 0) {
+ CAM_ERR(CAM_EEPROM, "Failed: rc : %d", rc);
return rc;
}
-
- e_ctrl->cal_data.mapdata =
- kzalloc(e_ctrl->cal_data.num_data, GFP_KERNEL);
- if (!e_ctrl->cal_data.mapdata) {
- rc = -ENOMEM;
- CAM_ERR(CAM_EEPROM, "failed");
- goto error;
- }
-
- rc = cam_eeprom_power_up(e_ctrl,
- &soc_private->power_info);
- if (rc) {
- CAM_ERR(CAM_EEPROM, "failed rc %d", rc);
- goto memdata_free;
- }
-
- rc = cam_eeprom_read_memory(e_ctrl, &e_ctrl->cal_data);
- if (rc) {
- CAM_ERR(CAM_EEPROM,
- "read_eeprom_memory failed");
- goto power_down;
- }
-
rc = cam_eeprom_get_cal_data(e_ctrl, csl_packet);
- rc = cam_eeprom_power_down(e_ctrl);
- } else {
- CAM_DBG(CAM_EEPROM, "Already read eeprom");
+ kfree(e_ctrl->cal_data.mapdata);
+ kfree(e_ctrl->cal_data.map);
+ e_ctrl->cal_data.num_data = 0;
+ e_ctrl->cal_data.num_map = 0;
+ CAM_DBG(CAM_EEPROM,
+ "Returning the data using kernel probe");
+ break;
}
+ rc = cam_eeprom_init_pkt_parser(e_ctrl, csl_packet);
+ if (rc) {
+ CAM_ERR(CAM_EEPROM,
+ "Failed in parsing the pkt");
+ return rc;
+ }
+
+ e_ctrl->cal_data.mapdata =
+ kzalloc(e_ctrl->cal_data.num_data, GFP_KERNEL);
+ if (!e_ctrl->cal_data.mapdata) {
+ rc = -ENOMEM;
+ CAM_ERR(CAM_EEPROM, "failed");
+ goto error;
+ }
+
+ rc = cam_eeprom_power_up(e_ctrl,
+ &soc_private->power_info);
+ if (rc) {
+ CAM_ERR(CAM_EEPROM, "failed rc %d", rc);
+ goto memdata_free;
+ }
+
+ rc = cam_eeprom_read_memory(e_ctrl, &e_ctrl->cal_data);
+ if (rc) {
+ CAM_ERR(CAM_EEPROM,
+ "read_eeprom_memory failed");
+ goto power_down;
+ }
+
+ rc = cam_eeprom_get_cal_data(e_ctrl, csl_packet);
+ rc = cam_eeprom_power_down(e_ctrl);
+ kfree(e_ctrl->cal_data.mapdata);
+ kfree(e_ctrl->cal_data.map);
+ e_ctrl->cal_data.num_data = 0;
+ e_ctrl->cal_data.num_map = 0;
break;
default:
break;
}
- kfree(e_ctrl->cal_data.mapdata);
- kfree(e_ctrl->cal_data.map);
return rc;
power_down:
rc = cam_eeprom_power_down(e_ctrl);
@@ -718,6 +728,8 @@
kfree(e_ctrl->cal_data.mapdata);
error:
kfree(e_ctrl->cal_data.map);
+ e_ctrl->cal_data.num_data = 0;
+ e_ctrl->cal_data.num_map = 0;
return rc;
}
@@ -764,6 +776,23 @@
goto release_mutex;
}
break;
+ case CAM_RELEASE_DEV:
+ if (e_ctrl->bridge_intf.device_hdl == -1) {
+ CAM_ERR(CAM_EEPROM,
+ "Invalid Handles: link hdl: %d device hdl: %d",
+ e_ctrl->bridge_intf.device_hdl,
+ e_ctrl->bridge_intf.link_hdl);
+ rc = -EINVAL;
+ goto release_mutex;
+ }
+ rc = cam_destroy_device_hdl(e_ctrl->bridge_intf.device_hdl);
+ if (rc < 0)
+ CAM_ERR(CAM_EEPROM,
+ "failed in destroying the device hdl");
+ e_ctrl->bridge_intf.device_hdl = -1;
+ e_ctrl->bridge_intf.link_hdl = -1;
+ e_ctrl->bridge_intf.session_hdl = -1;
+ break;
case CAM_CONFIG_DEV:
rc = cam_eeprom_pkt_parse(e_ctrl, arg);
if (rc) {
diff --git a/drivers/media/platform/msm/camera/cam_sensor_module/cam_eeprom/cam_eeprom_dev.c b/drivers/media/platform/msm/camera/cam_sensor_module/cam_eeprom/cam_eeprom_dev.c
index 9bbc6df..88d7665 100644
--- a/drivers/media/platform/msm/camera/cam_sensor_module/cam_eeprom/cam_eeprom_dev.c
+++ b/drivers/media/platform/msm/camera/cam_sensor_module/cam_eeprom/cam_eeprom_dev.c
@@ -152,6 +152,12 @@
goto probe_failure;
}
+ soc_private = kzalloc(sizeof(*soc_private), GFP_KERNEL);
+ if (!soc_private)
+ goto ectrl_free;
+
+ e_ctrl->soc_info.soc_private = soc_private;
+
i2c_set_clientdata(client, e_ctrl);
mutex_init(&(e_ctrl->eeprom_mutex));
@@ -175,15 +181,6 @@
goto free_soc;
}
- if (e_ctrl->userspace_probe == false) {
- rc = cam_eeprom_parse_read_memory_map(soc_info->dev->of_node,
- e_ctrl);
- if (rc) {
- CAM_ERR(CAM_EEPROM, "failed: read mem map rc %d", rc);
- goto free_soc;
- }
- }
-
soc_private = (struct cam_eeprom_soc_private *)(id->driver_data);
if (!soc_private) {
CAM_ERR(CAM_EEPROM, "board info NULL");
@@ -242,8 +239,6 @@
return -EINVAL;
}
- kfree(e_ctrl->cal_data.mapdata);
- kfree(e_ctrl->cal_data.map);
if (soc_private) {
kfree(soc_private->power_info.gpio_num_info);
kfree(soc_private);
@@ -307,13 +302,10 @@
goto board_free;
}
- if (e_ctrl->userspace_probe == false) {
- rc = cam_eeprom_parse_read_memory_map(soc_info->dev->of_node,
- e_ctrl);
- if (rc) {
- CAM_ERR(CAM_EEPROM, "failed: read mem map rc %d", rc);
- goto board_free;
- }
+ rc = cam_eeprom_spi_parse_of(spi_client);
+ if (rc) {
+ CAM_ERR(CAM_EEPROM, "Device tree parsing error");
+ goto board_free;
}
rc = cam_eeprom_init_subdev(e_ctrl);
@@ -369,8 +361,6 @@
}
kfree(e_ctrl->io_master_info.spi_client);
- kfree(e_ctrl->cal_data.mapdata);
- kfree(e_ctrl->cal_data.map);
soc_private =
(struct cam_eeprom_soc_private *)e_ctrl->soc_info.soc_private;
if (soc_private) {
@@ -428,15 +418,6 @@
goto free_soc;
}
- if (e_ctrl->userspace_probe == false) {
- rc = cam_eeprom_parse_read_memory_map(pdev->dev.of_node,
- e_ctrl);
- if (rc) {
- CAM_ERR(CAM_EEPROM, "failed: read mem map rc %d", rc);
- goto free_soc;
- }
- }
-
rc = cam_eeprom_init_subdev(e_ctrl);
if (rc)
goto free_soc;
diff --git a/drivers/media/platform/msm/camera/cam_sensor_module/cam_eeprom/cam_eeprom_soc.c b/drivers/media/platform/msm/camera/cam_sensor_module/cam_eeprom/cam_eeprom_soc.c
index 5e12f4a..70c40fd 100644
--- a/drivers/media/platform/msm/camera/cam_sensor_module/cam_eeprom/cam_eeprom_soc.c
+++ b/drivers/media/platform/msm/camera/cam_sensor_module/cam_eeprom/cam_eeprom_soc.c
@@ -20,6 +20,96 @@
#include "cam_eeprom_soc.h"
#include "cam_debug_util.h"
+#define cam_eeprom_spi_parse_cmd(spi_dev, name, out) \
+ { \
+ spi_dev->cmd_tbl.name.opcode = out[0]; \
+ spi_dev->cmd_tbl.name.addr_len = out[1]; \
+ spi_dev->cmd_tbl.name.dummy_len = out[2]; \
+ spi_dev->cmd_tbl.name.delay_intv = out[3]; \
+ spi_dev->cmd_tbl.name.delay_count = out[4]; \
+ }
+
+int cam_eeprom_spi_parse_of(struct cam_sensor_spi_client *spi_dev)
+{
+ int rc = -EFAULT;
+ uint32_t tmp[5];
+
+ rc = of_property_read_u32_array(spi_dev->spi_master->dev.of_node,
+ "spiop-read", tmp, 5);
+ if (!rc) {
+ cam_eeprom_spi_parse_cmd(spi_dev, read, tmp);
+ } else {
+ CAM_ERR(CAM_EEPROM, "Failed to get read data");
+ return -EFAULT;
+ }
+
+ rc = of_property_read_u32_array(spi_dev->spi_master->dev.of_node,
+ "spiop-readseq", tmp, 5);
+ if (!rc) {
+ cam_eeprom_spi_parse_cmd(spi_dev, read_seq, tmp);
+ } else {
+ CAM_ERR(CAM_EEPROM, "Failed to get readseq data");
+ return -EFAULT;
+ }
+
+ rc = of_property_read_u32_array(spi_dev->spi_master->dev.of_node,
+ "spiop-queryid", tmp, 5);
+ if (!rc) {
+ cam_eeprom_spi_parse_cmd(spi_dev, query_id, tmp);
+ } else {
+ CAM_ERR(CAM_EEPROM, "Failed to get queryid data");
+ return -EFAULT;
+ }
+
+ rc = of_property_read_u32_array(spi_dev->spi_master->dev.of_node,
+ "spiop-pprog", tmp, 5);
+ if (!rc) {
+ cam_eeprom_spi_parse_cmd(spi_dev, page_program, tmp);
+ } else {
+ CAM_ERR(CAM_EEPROM, "Failed to get page program data");
+ return -EFAULT;
+ }
+
+ rc = of_property_read_u32_array(spi_dev->spi_master->dev.of_node,
+ "spiop-wenable", tmp, 5);
+ if (!rc) {
+ cam_eeprom_spi_parse_cmd(spi_dev, write_enable, tmp);
+ } else {
+ CAM_ERR(CAM_EEPROM, "Failed to get write enable data");
+ return rc;
+ }
+
+ rc = of_property_read_u32_array(spi_dev->spi_master->dev.of_node,
+ "spiop-readst", tmp, 5);
+ if (!rc) {
+ cam_eeprom_spi_parse_cmd(spi_dev, read_status, tmp);
+ } else {
+ CAM_ERR(CAM_EEPROM, "Failed to get readdst data");
+ return rc;
+ }
+
+ rc = of_property_read_u32_array(spi_dev->spi_master->dev.of_node,
+ "spiop-erase", tmp, 5);
+ if (!rc) {
+ cam_eeprom_spi_parse_cmd(spi_dev, erase, tmp);
+ } else {
+ CAM_ERR(CAM_EEPROM, "Failed to get erase data");
+ return rc;
+ }
+
+ rc = of_property_read_u32_array(spi_dev->spi_master->dev.of_node,
+ "eeprom-id", tmp, 2);
+ if (rc) {
+ CAM_ERR(CAM_EEPROM, "Failed to get eeprom id");
+ return rc;
+ }
+
+ spi_dev->mfr_id0 = tmp[0];
+ spi_dev->device_id0 = tmp[1];
+
+ return 0;
+}
+
/*
* cam_eeprom_parse_memory_map() - parse memory map in device node
* @of: device node
diff --git a/drivers/media/platform/msm/camera/cam_sensor_module/cam_eeprom/cam_eeprom_soc.h b/drivers/media/platform/msm/camera/cam_sensor_module/cam_eeprom/cam_eeprom_soc.h
index 08c436c..d311549 100644
--- a/drivers/media/platform/msm/camera/cam_sensor_module/cam_eeprom/cam_eeprom_soc.h
+++ b/drivers/media/platform/msm/camera/cam_sensor_module/cam_eeprom/cam_eeprom_soc.h
@@ -14,6 +14,8 @@
#include "cam_eeprom_dev.h"
+int cam_eeprom_spi_parse_of(struct cam_sensor_spi_client *client);
+
int cam_eeprom_parse_dt_memory_map(struct device_node *of,
struct cam_eeprom_memory_block_t *data);
diff --git a/drivers/media/platform/msm/camera/cam_sensor_module/cam_flash/cam_flash_core.c b/drivers/media/platform/msm/camera/cam_sensor_module/cam_flash/cam_flash_core.c
index 0aaf8b0c..f455715 100644
--- a/drivers/media/platform/msm/camera/cam_sensor_module/cam_flash/cam_flash_core.c
+++ b/drivers/media/platform/msm/camera/cam_sensor_module/cam_flash/cam_flash_core.c
@@ -334,7 +334,8 @@
flash_data = &fctrl->per_frame[frame_offset];
if ((flash_data->opcode == CAMERA_SENSOR_FLASH_OP_FIREHIGH) &&
- (flash_data->cmn_attr.is_settings_valid)) {
+ (flash_data->cmn_attr.is_settings_valid) &&
+ (flash_data->cmn_attr.request_id == req_id)) {
/* Turn On Flash */
if (fctrl->flash_state == CAM_FLASH_STATE_INIT) {
rc = cam_flash_high(fctrl, flash_data);
@@ -348,7 +349,8 @@
}
} else if ((flash_data->opcode ==
CAMERA_SENSOR_FLASH_OP_FIRELOW) &&
- (flash_data->cmn_attr.is_settings_valid)) {
+ (flash_data->cmn_attr.is_settings_valid) &&
+ (flash_data->cmn_attr.request_id == req_id)) {
/* Turn On Torch */
if (fctrl->flash_state == CAM_FLASH_STATE_INIT) {
rc = cam_flash_low(fctrl, flash_data);
@@ -361,7 +363,8 @@
fctrl->flash_state = CAM_FLASH_STATE_LOW;
}
} else if ((flash_data->opcode == CAMERA_SENSOR_FLASH_OP_OFF) &&
- (flash_data->cmn_attr.is_settings_valid)) {
+ (flash_data->cmn_attr.is_settings_valid) &&
+ (flash_data->cmn_attr.request_id == req_id)) {
if ((fctrl->flash_state != CAM_FLASH_STATE_RELEASE) ||
(fctrl->flash_state != CAM_FLASH_STATE_INIT)) {
rc = cam_flash_off(fctrl);
@@ -374,10 +377,7 @@
}
}
} else {
- CAM_ERR(CAM_FLASH, "Wrong opcode : %d",
- flash_data->opcode);
- rc = -EINVAL;
- goto apply_setting_err;
+ CAM_DBG(CAM_FLASH, "NOP opcode: req_id: %u", req_id);
}
}
@@ -470,6 +470,19 @@
csl_packet->cmd_buf_offset);
frame_offset = csl_packet->header.request_id %
MAX_PER_FRAME_ARRAY;
+ if (fctrl->per_frame[frame_offset].cmn_attr.is_settings_valid
+ == true) {
+ fctrl->per_frame[frame_offset].cmn_attr.request_id = 0;
+ fctrl->per_frame[frame_offset].
+ cmn_attr.is_settings_valid = false;
+ for (i = 0;
+ i < fctrl->per_frame[frame_offset].cmn_attr.count;
+ i++) {
+ fctrl->per_frame[frame_offset].
+ led_current_ma[i] = 0;
+ }
+ }
+
fctrl->per_frame[frame_offset].cmn_attr.request_id =
csl_packet->header.request_id;
fctrl->per_frame[frame_offset].cmn_attr.is_settings_valid =
@@ -479,6 +492,10 @@
(uint64_t *)&generic_ptr, &len_of_buffer);
cmd_buf = (uint32_t *)((uint8_t *)generic_ptr +
cmd_desc->offset);
+
+ if (!cmd_buf)
+ return -EINVAL;
+
cmn_hdr = (struct common_header *)cmd_buf;
switch (cmn_hdr->cmd_type) {
@@ -487,6 +504,11 @@
"CAMERA_FLASH_CMD_TYPE_OPS case called");
flash_operation_info =
(struct cam_flash_set_on_off *) cmd_buf;
+ if (!flash_operation_info) {
+ CAM_ERR(CAM_FLASH, "flash_operation_info Null");
+ return -EINVAL;
+ }
+
fctrl->per_frame[frame_offset].opcode =
flash_operation_info->opcode;
fctrl->per_frame[frame_offset].cmn_attr.count =
@@ -502,7 +524,6 @@
cmn_hdr->cmd_type);
return -EINVAL;
}
-
break;
}
case CAM_FLASH_PACKET_OPCODE_NON_REALTIME_SET_OPS: {
@@ -596,6 +617,8 @@
break;
}
case CAM_PKT_NOP_OPCODE: {
+ CAM_DBG(CAM_FLASH, "NOP Packet is Received: req_id: %u",
+ csl_packet->header.request_id);
goto update_req_mgr;
}
default:
diff --git a/drivers/media/platform/msm/camera/cam_sensor_module/cam_flash/cam_flash_dev.c b/drivers/media/platform/msm/camera/cam_sensor_module/cam_flash/cam_flash_dev.c
index 7040ba2..d743cf0 100644
--- a/drivers/media/platform/msm/camera/cam_sensor_module/cam_flash/cam_flash_dev.c
+++ b/drivers/media/platform/msm/camera/cam_sensor_module/cam_flash/cam_flash_dev.c
@@ -93,7 +93,7 @@
break;
}
case CAM_QUERY_CAP: {
- struct cam_flash_query_cap_info flash_cap;
+ struct cam_flash_query_cap_info flash_cap = {0};
CAM_DBG(CAM_FLASH, "CAM_QUERY_CAP");
flash_cap.slot_info = fctrl->soc_info.index;
diff --git a/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor/cam_sensor_core.c b/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor/cam_sensor_core.c
index edbb335..f0c1bca 100644
--- a/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor/cam_sensor_core.c
+++ b/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor/cam_sensor_core.c
@@ -813,29 +813,27 @@
return rc;
}
}
- del_req_id = (req_id +
- MAX_PER_FRAME_ARRAY -
- MAX_SYSTEM_PIPELINE_DELAY) %
- MAX_PER_FRAME_ARRAY;
- CAM_DBG(CAM_SENSOR, "Deleting the Request: %d",
- del_req_id);
- if (req_id >
- s_ctrl->i2c_data.per_frame[del_req_id].
- request_id) {
- s_ctrl->i2c_data.per_frame[del_req_id].
- request_id = 0;
- rc = delete_request(
- &(s_ctrl->i2c_data.
- per_frame[del_req_id]));
- if (rc < 0)
- CAM_ERR(CAM_SENSOR,
- "Delete request Fail:%d rc:%d",
- del_req_id, rc);
- }
} else {
CAM_DBG(CAM_SENSOR,
"Invalid/NOP request to apply: %lld", req_id);
}
+
+ del_req_id = (req_id + MAX_PER_FRAME_ARRAY -
+ MAX_SYSTEM_PIPELINE_DELAY) % MAX_PER_FRAME_ARRAY;
+ CAM_DBG(CAM_SENSOR, "Deleting the Request: %d", del_req_id);
+
+ if ((req_id >
+ s_ctrl->i2c_data.per_frame[del_req_id].request_id) &&
+ (s_ctrl->i2c_data.per_frame[del_req_id].
+ is_settings_valid == 1)) {
+ s_ctrl->i2c_data.per_frame[del_req_id].request_id = 0;
+ rc = delete_request(
+ &(s_ctrl->i2c_data.per_frame[del_req_id]));
+ if (rc < 0)
+ CAM_ERR(CAM_SENSOR,
+ "Delete request Fail:%d rc:%d",
+ del_req_id, rc);
+ }
}
return rc;
}
@@ -855,7 +853,7 @@
return -EINVAL;
}
CAM_DBG(CAM_SENSOR, " Req Id: %lld", apply->request_id);
- trace_cam_apply_req("Sensor", apply);
+ trace_cam_apply_req("Sensor", apply->request_id);
rc = cam_sensor_apply_settings(s_ctrl, apply->request_id);
return rc;
}
diff --git a/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor_io/cam_sensor_cci_i2c.c b/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor_io/cam_sensor_cci_i2c.c
index 3257703..2c1f520 100644
--- a/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor_io/cam_sensor_cci_i2c.c
+++ b/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor_io/cam_sensor_cci_i2c.c
@@ -38,7 +38,7 @@
rc = v4l2_subdev_call(cci_client->cci_subdev,
core, ioctl, VIDIOC_MSM_CCI_CFG, &cci_ctrl);
if (rc < 0) {
- CAM_ERR(CAM_SENSOR, "line %d rc = %d", rc);
+ CAM_ERR(CAM_SENSOR, "rc = %d", rc);
return rc;
}
diff --git a/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor_io/cam_sensor_io.c b/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor_io/cam_sensor_io.c
index c9cf088..6e169cf 100644
--- a/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor_io/cam_sensor_io.c
+++ b/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor_io/cam_sensor_io.c
@@ -58,7 +58,7 @@
addr, data, addr_type, data_type);
} else if (io_master_info->master_type == SPI_MASTER) {
return cam_spi_read(io_master_info,
- addr, data, addr_type);
+ addr, data, addr_type, data_type);
} else {
CAM_ERR(CAM_SENSOR, "Invalid Comm. Master:%d",
io_master_info->master_type);
@@ -78,8 +78,8 @@
return cam_qup_i2c_read_seq(io_master_info->client,
addr, data, addr_type, num_bytes);
} else if (io_master_info->master_type == SPI_MASTER) {
- return cam_spi_read(io_master_info,
- addr, (uint32_t *)data, addr_type);
+ return cam_spi_read_seq(io_master_info,
+ addr, data, addr_type, num_bytes);
} else {
CAM_ERR(CAM_SENSOR, "Invalid Comm. Master:%d",
io_master_info->master_type);
@@ -153,6 +153,9 @@
cam_cci_get_subdev();
return cam_sensor_cci_i2c_util(io_master_info->cci_client,
MSM_CCI_INIT);
+ } else if ((io_master_info->master_type == I2C_MASTER) ||
+ (io_master_info->master_type == SPI_MASTER)) {
+ return 0;
} else {
CAM_ERR(CAM_SENSOR, "Invalid Comm. Master:%d",
io_master_info->master_type);
diff --git a/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor_io/cam_sensor_spi.c b/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor_io/cam_sensor_spi.c
index 4011aa0..131b0ae 100644
--- a/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor_io/cam_sensor_spi.c
+++ b/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor_io/cam_sensor_spi.c
@@ -59,25 +59,27 @@
* instruction and the data length.
*/
static void cam_set_addr(uint32_t addr, uint8_t addr_len,
- enum camera_sensor_i2c_type type,
+ enum camera_sensor_i2c_type addr_type,
char *str)
{
- int i, len;
-
if (!addr_len)
return;
- if (addr_len < type)
- CAM_DBG(CAM_EEPROM, "omitting higher bits in address");
-
- /* only support transfer MSB first for now */
- len = addr_len - type;
- for (i = len; i < addr_len; i++) {
- if (i >= 0)
- str[i] = (addr >> (BITS_PER_BYTE * (addr_len - i - 1)))
- & 0xFF;
+ if (addr_type == CAMERA_SENSOR_I2C_TYPE_BYTE) {
+ str[0] = addr;
+ } else if (addr_type == CAMERA_SENSOR_I2C_TYPE_WORD) {
+ str[0] = addr >> 8;
+ str[1] = addr;
+ } else if (addr_type == CAMERA_SENSOR_I2C_TYPE_3B) {
+ str[0] = addr >> 16;
+ str[1] = addr >> 8;
+ str[2] = addr;
+ } else {
+ str[0] = addr >> 24;
+ str[1] = addr >> 16;
+ str[2] = addr >> 8;
+ str[3] = addr;
}
-
}
/**
@@ -105,6 +107,7 @@
*/
static int32_t cam_spi_tx_helper(struct camera_io_master *client,
struct cam_camera_spi_inst *inst, uint32_t addr, uint8_t *data,
+ enum camera_sensor_i2c_type addr_type,
uint32_t num_byte, char *tx, char *rx)
{
int32_t rc = -EINVAL;
@@ -112,10 +115,6 @@
char *ctx = NULL, *crx = NULL;
uint32_t len, hlen;
uint8_t retries = client->spi_client->retries;
- enum camera_sensor_i2c_type addr_type = CAMERA_SENSOR_I2C_TYPE_WORD;
-
- if (addr_type >= CAMERA_SENSOR_I2C_TYPE_MAX)
- return rc;
hlen = cam_camera_spi_get_hlen(inst);
len = hlen + num_byte;
@@ -166,6 +165,7 @@
static int32_t cam_spi_tx_read(struct camera_io_master *client,
struct cam_camera_spi_inst *inst, uint32_t addr, uint8_t *data,
+ enum camera_sensor_i2c_type addr_type,
uint32_t num_byte, char *tx, char *rx)
{
int32_t rc = -EINVAL;
@@ -173,12 +173,6 @@
char *ctx = NULL, *crx = NULL;
uint32_t hlen;
uint8_t retries = client->spi_client->retries;
- enum camera_sensor_i2c_type addr_type = CAMERA_SENSOR_I2C_TYPE_WORD;
-
- if ((addr_type != CAMERA_SENSOR_I2C_TYPE_WORD)
- && (addr_type != CAMERA_SENSOR_I2C_TYPE_BYTE)
- && (addr_type != CAMERA_SENSOR_I2C_TYPE_3B))
- return rc;
hlen = cam_camera_spi_get_hlen(inst);
if (tx) {
@@ -204,14 +198,8 @@
}
ctx[0] = inst->opcode;
- if (addr_type == CAMERA_SENSOR_I2C_TYPE_3B) {
- cam_set_addr(addr, inst->addr_len, addr_type,
- ctx + 1);
- } else {
- ctx[1] = (addr >> BITS_PER_BYTE) & 0xFF;
- ctx[2] = (addr & 0xFF);
- ctx[3] = 0;
- }
+ cam_set_addr(addr, inst->addr_len, addr_type, ctx + 1);
+
CAM_DBG(CAM_EEPROM, "tx(%u): %02x %02x %02x %02x", hlen, ctx[0],
ctx[1], ctx[2], ctx[3]);
while ((rc = cam_spi_txfr_read(spi, ctx, crx, hlen, num_byte))
@@ -235,18 +223,23 @@
int cam_spi_read(struct camera_io_master *client,
uint32_t addr, uint32_t *data,
+ enum camera_sensor_i2c_type addr_type,
enum camera_sensor_i2c_type data_type)
{
int rc = -EINVAL;
uint8_t temp[CAMERA_SENSOR_I2C_TYPE_MAX];
- if ((data_type <= CAMERA_SENSOR_I2C_TYPE_INVALID)
- || (data_type >= CAMERA_SENSOR_I2C_TYPE_MAX))
+ if (addr_type <= CAMERA_SENSOR_I2C_TYPE_INVALID
+ || addr_type >= CAMERA_SENSOR_I2C_TYPE_MAX
+ || data_type <= CAMERA_SENSOR_I2C_TYPE_INVALID
+ || data_type >= CAMERA_SENSOR_I2C_TYPE_MAX) {
+ CAM_ERR(CAM_SENSOR, "Failed with addr/data_type verification");
return rc;
+ }
rc = cam_spi_tx_read(client,
&client->spi_client->cmd_tbl.read, addr, &temp[0],
- data_type, NULL, NULL);
+ addr_type, data_type, NULL, NULL);
if (rc < 0) {
CAM_ERR(CAM_SENSOR, "failed %d", rc);
return rc;
@@ -254,23 +247,50 @@
if (data_type == CAMERA_SENSOR_I2C_TYPE_BYTE)
*data = temp[0];
- else
+ else if (data_type == CAMERA_SENSOR_I2C_TYPE_WORD)
*data = (temp[0] << BITS_PER_BYTE) | temp[1];
+ else if (data_type == CAMERA_SENSOR_I2C_TYPE_3B)
+ *data = (temp[0] << 16 | temp[1] << 8 | temp[2]);
+ else
+ *data = (temp[0] << 24 | temp[1] << 16 | temp[2] << 8 |
+ temp[3]);
CAM_DBG(CAM_SENSOR, "addr 0x%x, data %u", addr, *data);
return rc;
}
+int32_t cam_spi_read_seq(struct camera_io_master *client,
+ uint32_t addr, uint8_t *data,
+ enum camera_sensor_i2c_type addr_type, int32_t num_bytes)
+{
+ if ((addr_type <= CAMERA_SENSOR_I2C_TYPE_INVALID)
+ || (addr_type >= CAMERA_SENSOR_I2C_TYPE_MAX)) {
+ CAM_ERR(CAM_SENSOR, "Failed with addr_type verification");
+ return -EINVAL;
+ }
+
+ if (num_bytes == 0) {
+ CAM_ERR(CAM_SENSOR, "num_byte: 0x%x", num_bytes);
+ return -EINVAL;
+ }
+
+ return cam_spi_tx_helper(client,
+ &client->spi_client->cmd_tbl.read_seq, addr, data,
+ addr_type, num_bytes, NULL, NULL);
+}
+
int cam_spi_query_id(struct camera_io_master *client,
- uint32_t addr, uint8_t *data, uint32_t num_byte)
+ uint32_t addr, enum camera_sensor_i2c_type addr_type,
+ uint8_t *data, uint32_t num_byte)
{
return cam_spi_tx_helper(client,
- &client->spi_client->cmd_tbl.query_id, addr, data, num_byte,
- NULL, NULL);
+ &client->spi_client->cmd_tbl.query_id,
+ addr, data, addr_type, num_byte, NULL, NULL);
}
static int32_t cam_spi_read_status_reg(
- struct camera_io_master *client, uint8_t *status)
+ struct camera_io_master *client, uint8_t *status,
+ enum camera_sensor_i2c_type addr_type)
{
struct cam_camera_spi_inst *rs =
&client->spi_client->cmd_tbl.read_status;
@@ -279,16 +299,17 @@
CAM_ERR(CAM_SENSOR, "not implemented yet");
return -ENXIO;
}
- return cam_spi_tx_helper(client, rs, 0, status, 1, NULL, NULL);
+ return cam_spi_tx_helper(client, rs, 0, status,
+ addr_type, 1, NULL, NULL);
}
static int32_t cam_spi_device_busy(struct camera_io_master *client,
- uint8_t *busy)
+ uint8_t *busy, enum camera_sensor_i2c_type addr_type)
{
int rc;
uint8_t st = 0;
- rc = cam_spi_read_status_reg(client, &st);
+ rc = cam_spi_read_status_reg(client, &st, addr_type);
if (rc < 0) {
CAM_ERR(CAM_SENSOR, "failed to read status reg");
return rc;
@@ -298,14 +319,15 @@
}
static int32_t cam_spi_wait(struct camera_io_master *client,
- struct cam_camera_spi_inst *inst)
+ struct cam_camera_spi_inst *inst,
+ enum camera_sensor_i2c_type addr_type)
{
uint8_t busy;
int i, rc;
CAM_DBG(CAM_SENSOR, "op 0x%x wait start", inst->opcode);
for (i = 0; i < inst->delay_count; i++) {
- rc = cam_spi_device_busy(client, &busy);
+ rc = cam_spi_device_busy(client, &busy, addr_type);
if (rc < 0)
return rc;
if (!busy)
@@ -321,8 +343,8 @@
return 0;
}
-static int32_t cam_spi_write_enable(
- struct camera_io_master *client)
+static int32_t cam_spi_write_enable(struct camera_io_master *client,
+ enum camera_sensor_i2c_type addr_type)
{
struct cam_camera_spi_inst *we =
&client->spi_client->cmd_tbl.write_enable;
@@ -334,7 +356,8 @@
CAM_ERR(CAM_SENSOR, "not implemented yet");
return -EINVAL;
}
- rc = cam_spi_tx_helper(client, we, 0, NULL, 0, NULL, NULL);
+ rc = cam_spi_tx_helper(client, we, 0, NULL, addr_type,
+ 0, NULL, NULL);
if (rc < 0)
CAM_ERR(CAM_SENSOR, "write enable failed");
return rc;
@@ -354,7 +377,9 @@
* used outside cam_spi_write_seq().
*/
static int32_t cam_spi_page_program(struct camera_io_master *client,
- uint32_t addr, uint8_t *data, uint16_t len, uint8_t *tx)
+ uint32_t addr, uint8_t *data,
+ enum camera_sensor_i2c_type addr_type,
+ uint16_t len, uint8_t *tx)
{
int rc;
struct cam_camera_spi_inst *pg =
@@ -362,10 +387,9 @@
struct spi_device *spi = client->spi_client->spi_master;
uint8_t retries = client->spi_client->retries;
uint8_t header_len = sizeof(pg->opcode) + pg->addr_len + pg->dummy_len;
- enum camera_sensor_i2c_type addr_type = CAMERA_SENSOR_I2C_TYPE_WORD;
CAM_DBG(CAM_SENSOR, "addr 0x%x, size 0x%x", addr, len);
- rc = cam_spi_write_enable(client);
+ rc = cam_spi_write_enable(client, addr_type);
if (rc < 0)
return rc;
memset(tx, 0, header_len);
@@ -375,7 +399,7 @@
CAM_DBG(CAM_SENSOR, "tx(%u): %02x %02x %02x %02x",
len, tx[0], tx[1], tx[2], tx[3]);
while ((rc = spi_write(spi, tx, len + header_len)) && retries) {
- rc = cam_spi_wait(client, pg);
+ rc = cam_spi_wait(client, pg, addr_type);
msleep(client->spi_client->retry_delay);
retries--;
}
@@ -383,41 +407,54 @@
CAM_ERR(CAM_SENSOR, "failed %d", rc);
return rc;
}
- rc = cam_spi_wait(client, pg);
+ rc = cam_spi_wait(client, pg, addr_type);
return rc;
}
int cam_spi_write(struct camera_io_master *client,
- uint32_t addr, uint16_t data,
+ uint32_t addr, uint32_t data,
+ enum camera_sensor_i2c_type addr_type,
enum camera_sensor_i2c_type data_type)
{
struct cam_camera_spi_inst *pg =
&client->spi_client->cmd_tbl.page_program;
uint8_t header_len = sizeof(pg->opcode) + pg->addr_len + pg->dummy_len;
uint16_t len = 0;
- char buf[2];
+ char buf[CAMERA_SENSOR_I2C_TYPE_MAX];
char *tx;
int rc = -EINVAL;
- enum camera_sensor_i2c_type addr_type = CAMERA_SENSOR_I2C_TYPE_WORD;
- if ((addr_type >= CAMERA_SENSOR_I2C_TYPE_MAX)
- || (data_type != CAMERA_SENSOR_I2C_TYPE_BYTE
- && data_type != CAMERA_SENSOR_I2C_TYPE_WORD))
+ if ((addr_type <= CAMERA_SENSOR_I2C_TYPE_INVALID)
+ || (addr_type >= CAMERA_SENSOR_I2C_TYPE_MAX)
+ || (data_type <= CAMERA_SENSOR_I2C_TYPE_INVALID)
+ || (data_type != CAMERA_SENSOR_I2C_TYPE_MAX))
return rc;
+
CAM_DBG(CAM_EEPROM, "Data: 0x%x", data);
len = header_len + (uint8_t)data_type;
tx = kmalloc(len, GFP_KERNEL | GFP_DMA);
if (!tx)
goto NOMEM;
+
if (data_type == CAMERA_SENSOR_I2C_TYPE_BYTE) {
buf[0] = data;
CAM_DBG(CAM_EEPROM, "Byte %d: 0x%x", len, buf[0]);
} else if (data_type == CAMERA_SENSOR_I2C_TYPE_WORD) {
buf[0] = (data >> BITS_PER_BYTE) & 0x00FF;
buf[1] = (data & 0x00FF);
+ } else if (data_type == CAMERA_SENSOR_I2C_TYPE_3B) {
+ buf[0] = (data >> 16) & 0x00FF;
+ buf[1] = (data >> 8) & 0x00FF;
+ buf[2] = (data & 0x00FF);
+ } else {
+ buf[0] = (data >> 24) & 0x00FF;
+ buf[1] = (data >> 16) & 0x00FF;
+ buf[2] = (data >> 8) & 0x00FF;
+ buf[3] = (data & 0x00FF);
}
+
rc = cam_spi_page_program(client, addr, buf,
- (uint16_t)data_type, tx);
+ addr_type, data_type, tx);
if (rc < 0)
goto ERROR;
goto OUT;
@@ -442,18 +479,22 @@
if (!client || !write_setting)
return rc;
- if (write_setting->addr_type >= CAMERA_SENSOR_I2C_TYPE_MAX
- || (write_setting->data_type != CAMERA_SENSOR_I2C_TYPE_BYTE
- && write_setting->data_type != CAMERA_SENSOR_I2C_TYPE_WORD))
+
+ if ((write_setting->addr_type <= CAMERA_SENSOR_I2C_TYPE_INVALID)
+ || (write_setting->addr_type >= CAMERA_SENSOR_I2C_TYPE_MAX)
+ || (write_setting->data_type <= CAMERA_SENSOR_I2C_TYPE_INVALID)
+ || (write_setting->data_type >= CAMERA_SENSOR_I2C_TYPE_MAX))
return rc;
+
reg_setting = write_setting->reg_setting;
- client_addr_type = addr_type;
+ client_addr_type = write_setting->addr_type;
addr_type = write_setting->addr_type;
for (i = 0; i < write_setting->size; i++) {
CAM_DBG(CAM_SENSOR, "addr %x data %x",
reg_setting->reg_addr, reg_setting->reg_data);
- rc = cam_spi_write(client, reg_setting->reg_addr,
- reg_setting->reg_data, write_setting->data_type);
+ rc = cam_spi_write(client,
+ reg_setting->reg_addr, reg_setting->reg_data,
+ write_setting->addr_type, write_setting->data_type);
if (rc < 0)
break;
reg_setting++;
diff --git a/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor_io/cam_sensor_spi.h b/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor_io/cam_sensor_spi.h
index a497491..ec1bede 100644
--- a/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor_io/cam_sensor_spi.h
+++ b/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor_io/cam_sensor_spi.h
@@ -78,13 +78,22 @@
int cam_spi_read(struct camera_io_master *client,
uint32_t addr, uint32_t *data,
+ enum camera_sensor_i2c_type addr_type,
enum camera_sensor_i2c_type data_type);
+int cam_spi_read_seq(struct camera_io_master *client,
+ uint32_t addr, uint8_t *data,
+ enum camera_sensor_i2c_type addr_type,
+ int32_t num_bytes);
+
int cam_spi_query_id(struct camera_io_master *client,
- uint32_t addr, uint8_t *data, uint32_t num_byte);
+ uint32_t addr,
+ enum camera_sensor_i2c_type addr_type,
+ uint8_t *data, uint32_t num_byte);
int cam_spi_write(struct camera_io_master *client,
- uint32_t addr, uint16_t data,
+ uint32_t addr, uint32_t data,
+ enum camera_sensor_i2c_type addr_type,
enum camera_sensor_i2c_type data_type);
int cam_spi_write_table(struct camera_io_master *client,
diff --git a/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor_utils/cam_sensor_util.c b/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor_utils/cam_sensor_util.c
index f5df775..bcdaf6d 100644
--- a/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor_utils/cam_sensor_util.c
+++ b/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor_utils/cam_sensor_util.c
@@ -217,9 +217,19 @@
sizeof(cam_cmd_i2c_continuous_wr->reg_addr) +
sizeof(struct cam_cmd_read) *
(cam_cmd_i2c_continuous_wr->header.count));
- i2c_list->op_code = cam_cmd_i2c_continuous_wr->header.op_code;
+ if (cam_cmd_i2c_continuous_wr->header.op_code ==
+ CAMERA_SENSOR_I2C_OP_CONT_WR_BRST)
+ i2c_list->op_code = CAM_SENSOR_I2C_WRITE_BURST;
+ else if (cam_cmd_i2c_continuous_wr->header.op_code ==
+ CAMERA_SENSOR_I2C_OP_CONT_WR_SEQN)
+ i2c_list->op_code = CAM_SENSOR_I2C_WRITE_SEQ;
+ else
+ return -EINVAL;
+
i2c_list->i2c_settings.addr_type =
cam_cmd_i2c_continuous_wr->header.addr_type;
+ i2c_list->i2c_settings.data_type =
+ cam_cmd_i2c_continuous_wr->header.data_type;
for (cnt = 0; cnt < (cam_cmd_i2c_continuous_wr->header.count);
cnt++) {
@@ -388,7 +398,7 @@
uint16_t power_setting_size)
{
int32_t rc = 0, j = 0, i = 0;
- uint32_t num_vreg;
+ int num_vreg;
/* Validate input parameters */
if (!soc_info || !power_setting) {
@@ -399,7 +409,7 @@
num_vreg = soc_info->num_rgltr;
- if (num_vreg <= 0) {
+ if ((num_vreg <= 0) || (num_vreg > CAM_SOC_MAX_REGULATOR)) {
CAM_ERR(CAM_SENSOR, "failed: num_vreg %d", num_vreg);
return -EINVAL;
}
@@ -1210,8 +1220,8 @@
gpio_num_info = ctrl->gpio_num_info;
num_vreg = soc_info->num_rgltr;
- if ((num_vreg == 0) || (num_vreg > CAM_SOC_MAX_REGULATOR)) {
- CAM_ERR(CAM_SENSOR, "Regulators are not initialized");
+ if ((num_vreg <= 0) || (num_vreg > CAM_SOC_MAX_REGULATOR)) {
+ CAM_ERR(CAM_SENSOR, "failed: num_vreg %d", num_vreg);
return -EINVAL;
}
@@ -1556,6 +1566,11 @@
gpio_num_info = ctrl->gpio_num_info;
num_vreg = soc_info->num_rgltr;
+ if ((num_vreg <= 0) || (num_vreg > CAM_SOC_MAX_REGULATOR)) {
+ CAM_ERR(CAM_SENSOR, "failed: num_vreg %d", num_vreg);
+ return -EINVAL;
+ }
+
for (index = 0; index < ctrl->power_down_setting_size; index++) {
CAM_DBG(CAM_SENSOR, "index %d", index);
pd = &ctrl->power_down_setting[index];
diff --git a/drivers/media/platform/msm/camera/cam_smmu/cam_smmu_api.c b/drivers/media/platform/msm/camera/cam_smmu/cam_smmu_api.c
index ff7a0e5..cbf54f7 100644
--- a/drivers/media/platform/msm/camera/cam_smmu/cam_smmu_api.c
+++ b/drivers/media/platform/msm/camera/cam_smmu/cam_smmu_api.c
@@ -21,7 +21,8 @@
#include <linux/msm_dma_iommu_mapping.h>
#include <linux/workqueue.h>
#include <linux/genalloc.h>
-
+#include <soc/qcom/scm.h>
+#include <soc/qcom/secure_buffer.h>
#include "cam_smmu_api.h"
#include "cam_debug_util.h"
@@ -118,6 +119,7 @@
int, void*);
void *token[CAM_SMMU_CB_MAX];
int cb_count;
+ int secure_count;
};
struct cam_iommu_cb_set {
@@ -151,6 +153,17 @@
size_t phys_len;
};
+struct cam_sec_buff_info {
+ struct ion_handle *i_hdl;
+ struct ion_client *i_client;
+ enum dma_data_direction dir;
+ int ref_count;
+ dma_addr_t paddr;
+ struct list_head list;
+ int ion_fd;
+ size_t len;
+};
+
static struct cam_iommu_cb_set iommu_cb_set;
static enum dma_data_direction cam_smmu_translate_dir(
@@ -166,6 +179,9 @@
static struct cam_dma_buff_info *cam_smmu_find_mapping_by_ion_index(int idx,
int ion_fd);
+static struct cam_sec_buff_info *cam_smmu_find_mapping_by_sec_buf_idx(int idx,
+ int ion_fd);
+
static int cam_smmu_init_scratch_map(struct scratch_mapping *scratch_map,
dma_addr_t base, size_t size,
int order);
@@ -544,7 +560,15 @@
"Error: %s already got handle 0x%x",
name,
iommu_cb_set.cb_info[i].handle);
+
+ if (iommu_cb_set.cb_info[i].is_secure)
+ iommu_cb_set.cb_info[i].secure_count++;
+
mutex_unlock(&iommu_cb_set.cb_info[i].lock);
+ if (iommu_cb_set.cb_info[i].is_secure) {
+ *hdl = iommu_cb_set.cb_info[i].handle;
+ return 0;
+ }
return -EINVAL;
}
@@ -556,6 +580,8 @@
/* put handle in the table */
iommu_cb_set.cb_info[i].handle = handle;
iommu_cb_set.cb_info[i].cb_count = 0;
+ if (iommu_cb_set.cb_info[i].is_secure)
+ iommu_cb_set.cb_info[i].secure_count++;
*hdl = handle;
CAM_DBG(CAM_SMMU, "%s creates handle 0x%x",
name, handle);
@@ -693,6 +719,24 @@
CAM_ERR(CAM_SMMU, "Error: Cannot find fd %d by index %d",
ion_fd, idx);
+
+ return NULL;
+}
+
+static struct cam_sec_buff_info *cam_smmu_find_mapping_by_sec_buf_idx(int idx,
+ int ion_fd)
+{
+ struct cam_sec_buff_info *mapping;
+
+ list_for_each_entry(mapping, &iommu_cb_set.cb_info[idx].smmu_buf_list,
+ list) {
+ if (mapping->ion_fd == ion_fd) {
+ CAM_DBG(CAM_SMMU, "find ion_fd %d", ion_fd);
+ return mapping;
+ }
+ }
+ CAM_ERR(CAM_SMMU, "Error: Cannot find fd %d by index %d",
+ ion_fd, idx);
return NULL;
}
@@ -1339,6 +1383,25 @@
return CAM_SMMU_BUFF_NOT_EXIST;
}
+static enum cam_smmu_buf_state cam_smmu_check_secure_fd_in_list(int idx,
+ int ion_fd, dma_addr_t *paddr_ptr,
+ size_t *len_ptr)
+{
+ struct cam_sec_buff_info *mapping;
+
+ list_for_each_entry(mapping,
+ &iommu_cb_set.cb_info[idx].smmu_buf_list,
+ list) {
+ if (mapping->ion_fd == ion_fd) {
+ *paddr_ptr = mapping->paddr;
+ *len_ptr = mapping->len;
+ return CAM_SMMU_BUFF_EXIST;
+ }
+ }
+
+ return CAM_SMMU_BUFF_NOT_EXIST;
+}
+
int cam_smmu_get_handle(char *identifier, int *handle_ptr)
{
int ret = 0;
@@ -1722,14 +1785,200 @@
return rc;
}
-int cam_smmu_map_sec_iova(int handle, int ion_fd,
- enum cam_smmu_map_dir dir, dma_addr_t *paddr_ptr,
- size_t *len_ptr)
+static int cam_smmu_map_stage2_buffer_and_add_to_list(int idx, int ion_fd,
+ enum dma_data_direction dma_dir, struct ion_client *client,
+ dma_addr_t *paddr_ptr,
+ size_t *len_ptr)
{
- /* not implemented yet */
- return -EPERM;
+ int rc = 0;
+ struct ion_handle *i_handle = NULL;
+ struct cam_sec_buff_info *mapping_info;
+
+ /* clean the content from clients */
+ *paddr_ptr = (dma_addr_t)NULL;
+ *len_ptr = (size_t)0;
+
+ i_handle = ion_import_dma_buf_fd(client, ion_fd);
+ if (IS_ERR_OR_NULL((void *)(i_handle))) {
+ CAM_ERR(CAM_SMMU, "ion import dma buffer failed");
+ return -EINVAL;
+ }
+
+ /* return addr and len to client */
+ rc = ion_phys(client, i_handle, paddr_ptr, len_ptr);
+ if (rc) {
+ CAM_ERR(CAM_SMMU, "ION Get Physical failed, rc: %d",
+ rc);
+ return rc;
+ }
+
+ /* fill up mapping_info */
+ mapping_info = kzalloc(sizeof(struct cam_sec_buff_info), GFP_KERNEL);
+ if (!mapping_info)
+ return -ENOMEM;
+
+ mapping_info->ion_fd = ion_fd;
+ mapping_info->paddr = *paddr_ptr;
+ mapping_info->len = *len_ptr;
+ mapping_info->dir = dma_dir;
+ mapping_info->ref_count = 1;
+ mapping_info->i_hdl = i_handle;
+ mapping_info->i_client = client;
+
+ CAM_DBG(CAM_SMMU, "ion_fd = %d, dev = %pK, paddr= %pK, len = %u",
+ ion_fd,
+ (void *)iommu_cb_set.cb_info[idx].dev,
+ (void *)*paddr_ptr, (unsigned int)*len_ptr);
+
+ /* add to the list */
+ list_add(&mapping_info->list, &iommu_cb_set.cb_info[idx].smmu_buf_list);
+
+ return rc;
}
-EXPORT_SYMBOL(cam_smmu_map_sec_iova);
+
+int cam_smmu_map_stage2_iova(int handle,
+ int ion_fd, enum cam_smmu_map_dir dir,
+ struct ion_client *client, ion_phys_addr_t *paddr_ptr,
+ size_t *len_ptr)
+{
+ int idx, rc;
+ enum dma_data_direction dma_dir;
+ enum cam_smmu_buf_state buf_state;
+
+ if (!paddr_ptr || !len_ptr) {
+ CAM_ERR(CAM_SMMU,
+ "Error: Invalid inputs, paddr_ptr:%pK, len_ptr: %pK",
+ paddr_ptr, len_ptr);
+ return -EINVAL;
+ }
+ /* clean the content from clients */
+ *paddr_ptr = (dma_addr_t)NULL;
+ *len_ptr = (size_t)0;
+
+ dma_dir = cam_smmu_translate_dir(dir);
+ if (dma_dir == DMA_NONE) {
+ CAM_ERR(CAM_SMMU,
+ "Error: translate direction failed. dir = %d", dir);
+ return -EINVAL;
+ }
+
+ idx = GET_SMMU_TABLE_IDX(handle);
+ if ((handle == HANDLE_INIT) ||
+ (idx < 0) ||
+ (idx >= iommu_cb_set.cb_num)) {
+ CAM_ERR(CAM_SMMU,
+ "Error: handle or index invalid. idx = %d hdl = %x",
+ idx, handle);
+ return -EINVAL;
+ }
+
+ if (!iommu_cb_set.cb_info[idx].is_secure) {
+ CAM_ERR(CAM_SMMU,
+ "Error: can't map secure mem to non secure cb");
+ return -EINVAL;
+ }
+
+ mutex_lock(&iommu_cb_set.cb_info[idx].lock);
+ if (iommu_cb_set.cb_info[idx].handle != handle) {
+ CAM_ERR(CAM_SMMU,
+ "Error: hdl is not valid, table_hdl = %x, hdl = %x",
+ iommu_cb_set.cb_info[idx].handle, handle);
+ rc = -EINVAL;
+ goto get_addr_end;
+ }
+
+ buf_state = cam_smmu_check_secure_fd_in_list(idx, ion_fd, paddr_ptr,
+ len_ptr);
+ if (buf_state == CAM_SMMU_BUFF_EXIST) {
+ CAM_DBG(CAM_SMMU, "fd:%d already in list, give same addr back",
+ ion_fd);
+ rc = 0;
+ goto get_addr_end;
+ }
+ rc = cam_smmu_map_stage2_buffer_and_add_to_list(idx, ion_fd, dma_dir,
+ client, paddr_ptr, len_ptr);
+ if (rc < 0) {
+ CAM_ERR(CAM_SMMU, "Error: mapping or add list fail");
+ goto get_addr_end;
+ }
+
+get_addr_end:
+ mutex_unlock(&iommu_cb_set.cb_info[idx].lock);
+ return rc;
+}
+EXPORT_SYMBOL(cam_smmu_map_stage2_iova);
+
+static int cam_smmu_secure_unmap_buf_and_remove_from_list(
+ struct cam_sec_buff_info *mapping_info,
+ int idx)
+{
+ if (!mapping_info) {
+ CAM_ERR(CAM_SMMU, "Error: List doesn't exist");
+ return -EINVAL;
+ }
+ ion_free(mapping_info->i_client, mapping_info->i_hdl);
+ list_del_init(&mapping_info->list);
+
+ CAM_DBG(CAM_SMMU, "unmap fd: %d, idx : %d", mapping_info->ion_fd, idx);
+
+ /* free one buffer */
+ kfree(mapping_info);
+ return 0;
+}
+
+int cam_smmu_unmap_stage2_iova(int handle, int ion_fd)
+{
+ int idx, rc;
+ struct cam_sec_buff_info *mapping_info;
+
+ /* find index in the iommu_cb_set.cb_info */
+ idx = GET_SMMU_TABLE_IDX(handle);
+ if ((handle == HANDLE_INIT) ||
+ (idx < 0) ||
+ (idx >= iommu_cb_set.cb_num)) {
+ CAM_ERR(CAM_SMMU,
+ "Error: handle or index invalid. idx = %d hdl = %x",
+ idx, handle);
+ return -EINVAL;
+ }
+
+ if (!iommu_cb_set.cb_info[idx].is_secure) {
+ CAM_ERR(CAM_SMMU,
+ "Error: can't unmap secure mem from non secure cb");
+ return -EINVAL;
+ }
+
+ mutex_lock(&iommu_cb_set.cb_info[idx].lock);
+ if (iommu_cb_set.cb_info[idx].handle != handle) {
+ CAM_ERR(CAM_SMMU,
+ "Error: hdl is not valid, table_hdl = %x, hdl = %x",
+ iommu_cb_set.cb_info[idx].handle, handle);
+ rc = -EINVAL;
+ goto put_addr_end;
+ }
+
+ /* based on ion fd and index, we can find mapping info of buffer */
+ mapping_info = cam_smmu_find_mapping_by_sec_buf_idx(idx, ion_fd);
+ if (!mapping_info) {
+ CAM_ERR(CAM_SMMU,
+ "Error: Invalid params! idx = %d, fd = %d",
+ idx, ion_fd);
+ rc = -EINVAL;
+ goto put_addr_end;
+ }
+
+ /* unmapping one buffer from device */
+ rc = cam_smmu_secure_unmap_buf_and_remove_from_list(mapping_info, idx);
+ if (rc) {
+ CAM_ERR(CAM_SMMU, "Error: unmap or remove list fail");
+ goto put_addr_end;
+ }
+
+put_addr_end:
+ mutex_unlock(&iommu_cb_set.cb_info[idx].lock);
+ return rc;
+}
+EXPORT_SYMBOL(cam_smmu_unmap_stage2_iova);
int cam_smmu_map_iova(int handle, int ion_fd,
enum cam_smmu_map_dir dir, dma_addr_t *paddr_ptr,
@@ -1767,6 +2016,12 @@
return -EINVAL;
}
+ if (iommu_cb_set.cb_info[idx].is_secure) {
+ CAM_ERR(CAM_SMMU,
+ "Error: can't map non-secure mem to secure cb");
+ return -EINVAL;
+ }
+
mutex_lock(&iommu_cb_set.cb_info[idx].lock);
if (iommu_cb_set.cb_info[idx].handle != handle) {
CAM_ERR(CAM_SMMU, "hdl is not valid, table_hdl = %x, hdl = %x",
@@ -1786,9 +2041,7 @@
buf_state = cam_smmu_check_fd_in_list(idx, ion_fd, paddr_ptr,
len_ptr);
if (buf_state == CAM_SMMU_BUFF_EXIST) {
- CAM_ERR(CAM_SMMU,
- "ion_fd:%d already in the list, give same addr back",
- ion_fd);
+ CAM_ERR(CAM_SMMU, "ion_fd:%d already in the list", ion_fd);
rc = -EALREADY;
goto get_addr_end;
}
@@ -1832,6 +2085,12 @@
return -EINVAL;
}
+ if (iommu_cb_set.cb_info[idx].is_secure) {
+ CAM_ERR(CAM_SMMU,
+ "Error: can't get non-secure mem from secure cb");
+ return -EINVAL;
+ }
+
mutex_lock(&iommu_cb_set.cb_info[idx].lock);
if (iommu_cb_set.cb_info[idx].handle != handle) {
CAM_ERR(CAM_SMMU,
@@ -1854,12 +2113,65 @@
}
EXPORT_SYMBOL(cam_smmu_get_iova);
-int cam_smmu_unmap_sec_iova(int handle, int ion_fd)
+int cam_smmu_get_stage2_iova(int handle, int ion_fd,
+ dma_addr_t *paddr_ptr, size_t *len_ptr)
{
- /* not implemented yet */
- return -EPERM;
+ int idx, rc = 0;
+ enum cam_smmu_buf_state buf_state;
+
+ if (!paddr_ptr || !len_ptr) {
+ CAM_ERR(CAM_SMMU, "Error: Input pointers are invalid");
+ return -EINVAL;
+ }
+
+ if (handle == HANDLE_INIT) {
+ CAM_ERR(CAM_SMMU, "Error: Invalid handle");
+ return -EINVAL;
+ }
+
+ /* clean the content from clients */
+ *paddr_ptr = (dma_addr_t)NULL;
+ *len_ptr = (size_t)0;
+
+ idx = GET_SMMU_TABLE_IDX(handle);
+ if (idx < 0 || idx >= iommu_cb_set.cb_num) {
+ CAM_ERR(CAM_SMMU,
+ "Error: handle or index invalid. idx = %d hdl = %x",
+ idx, handle);
+ return -EINVAL;
+ }
+
+ if (!iommu_cb_set.cb_info[idx].is_secure) {
+ CAM_ERR(CAM_SMMU,
+ "Error: can't get secure mem from non secure cb");
+ return -EINVAL;
+ }
+
+ mutex_lock(&iommu_cb_set.cb_info[idx].lock);
+ if (iommu_cb_set.cb_info[idx].handle != handle) {
+ CAM_ERR(CAM_SMMU,
+ "Error: hdl is not valid, table_hdl = %x, hdl = %x",
+ iommu_cb_set.cb_info[idx].handle, handle);
+ rc = -EINVAL;
+ goto get_addr_end;
+ }
+
+ buf_state = cam_smmu_check_secure_fd_in_list(idx,
+ ion_fd,
+ paddr_ptr,
+ len_ptr);
+
+ if (buf_state == CAM_SMMU_BUFF_NOT_EXIST) {
+ CAM_ERR(CAM_SMMU, "ion_fd:%d not in the mapped list", ion_fd);
+ rc = -EINVAL;
+ goto get_addr_end;
+ }
+
+get_addr_end:
+ mutex_unlock(&iommu_cb_set.cb_info[idx].lock);
+ return rc;
}
-EXPORT_SYMBOL(cam_smmu_unmap_sec_iova);
+EXPORT_SYMBOL(cam_smmu_get_stage2_iova);
int cam_smmu_unmap_iova(int handle,
int ion_fd,
@@ -1882,6 +2194,12 @@
return -EINVAL;
}
+ if (iommu_cb_set.cb_info[idx].is_secure) {
+ CAM_ERR(CAM_SMMU,
+ "Error: can't unmap non-secure mem from secure cb");
+ return -EINVAL;
+ }
+
mutex_lock(&iommu_cb_set.cb_info[idx].lock);
if (iommu_cb_set.cb_info[idx].handle != handle) {
CAM_ERR(CAM_SMMU,
@@ -1989,6 +2307,22 @@
cam_smmu_clean_buffer_list(idx);
}
+ if (&iommu_cb_set.cb_info[idx].is_secure) {
+ if (iommu_cb_set.cb_info[idx].secure_count == 0) {
+ mutex_unlock(&iommu_cb_set.cb_info[idx].lock);
+ return -EPERM;
+ }
+
+ iommu_cb_set.cb_info[idx].secure_count--;
+ if (iommu_cb_set.cb_info[idx].secure_count == 0) {
+ iommu_cb_set.cb_info[idx].cb_count = 0;
+ iommu_cb_set.cb_info[idx].handle = HANDLE_INIT;
+ }
+
+ mutex_unlock(&iommu_cb_set.cb_info[idx].lock);
+ return 0;
+ }
+
iommu_cb_set.cb_info[idx].cb_count = 0;
iommu_cb_set.cb_info[idx].handle = HANDLE_INIT;
mutex_unlock(&iommu_cb_set.cb_info[idx].lock);
@@ -2168,7 +2502,15 @@
}
mem_map_node = of_get_child_by_name(of_node, "iova-mem-map");
+ cb->is_secure = of_property_read_bool(of_node, "qcom,secure-cb");
+
+ /*
+ * We always expect a memory map node, except when it is a secure
+ * context bank.
+ */
if (!mem_map_node) {
+ if (cb->is_secure)
+ return 0;
CAM_ERR(CAM_SMMU, "iova-mem-map not present");
return -EINVAL;
}
@@ -2292,6 +2634,12 @@
return rc;
}
+ if (cb->is_secure) {
+ /* increment count to next bank */
+ iommu_cb_set.cb_init_count++;
+ return 0;
+ }
+
/* set up the iommu mapping for the context bank */
if (type == CAM_QSMMU) {
CAM_ERR(CAM_SMMU, "Error: QSMMU ctx not supported for : %s",
diff --git a/drivers/media/platform/msm/camera/cam_smmu/cam_smmu_api.h b/drivers/media/platform/msm/camera/cam_smmu/cam_smmu_api.h
index 20445f3..4cb6efb 100644
--- a/drivers/media/platform/msm/camera/cam_smmu/cam_smmu_api.h
+++ b/drivers/media/platform/msm/camera/cam_smmu/cam_smmu_api.h
@@ -204,6 +204,19 @@
*/
int cam_smmu_get_iova(int handle, int ion_fd,
dma_addr_t *paddr_ptr, size_t *len_ptr);
+
+/**
+ * @brief Maps memory from an ION fd into IOVA space
+ *
+ * @param handle: SMMU handle identifying the secure context bank to map to
+ * @param ion_fd: ION fd of memory to map to
+ * @param paddr_ptr: Pointer IOVA address that will be returned
+ * @param len_ptr: Length of memory mapped
+ *
+ * @return Status of operation. Negative in case of error. Zero otherwise.
+ */
+int cam_smmu_get_stage2_iova(int handle, int ion_fd,
+ dma_addr_t *paddr_ptr, size_t *len_ptr);
/**
* @brief Unmaps memory from context bank
*
@@ -217,27 +230,28 @@
/**
* @brief Maps secure memory for SMMU handle
*
- * @param handle: SMMU handle identifying context bank
+ * @param handle: SMMU handle identifying secure context bank
* @param ion_fd: ION fd to map securely
* @param dir: DMA Direction for the mapping
+ * @param client: Ion client passed by caller
* @param dma_addr: Returned IOVA address after mapping
* @param len_ptr: Length of memory mapped
*
* @return Status of operation. Negative in case of error. Zero otherwise.
*/
-int cam_smmu_map_sec_iova(int handle,
- int ion_fd, enum cam_smmu_map_dir dir,
- dma_addr_t *dma_addr, size_t *len_ptr);
+int cam_smmu_map_stage2_iova(int handle,
+ int ion_fd, enum cam_smmu_map_dir dir, struct ion_client *client,
+ ion_phys_addr_t *dma_addr, size_t *len_ptr);
/**
* @brief Unmaps secure memopry for SMMU handle
*
- * @param handle: SMMU handle identifying context bank
+ * @param handle: SMMU handle identifying secure context bank
* @param ion_fd: ION fd to unmap
*
* @return Status of operation. Negative in case of error. Zero otherwise.
*/
-int cam_smmu_unmap_sec_iova(int handle, int ion_fd);
+int cam_smmu_unmap_stage2_iova(int handle, int ion_fd);
/**
diff --git a/drivers/media/platform/msm/camera/cam_utils/cam_packet_util.c b/drivers/media/platform/msm/camera/cam_utils/cam_packet_util.c
index 4323358..44d5d48 100644
--- a/drivers/media/platform/msm/camera/cam_utils/cam_packet_util.c
+++ b/drivers/media/platform/msm/camera/cam_utils/cam_packet_util.c
@@ -124,7 +124,7 @@
}
int cam_packet_util_process_patches(struct cam_packet *packet,
- int32_t iommu_hdl)
+ int32_t iommu_hdl, int32_t sec_mmu_hdl)
{
struct cam_patch_desc *patch_desc = NULL;
uint64_t iova_addr;
@@ -136,6 +136,7 @@
size_t src_buf_size;
int i;
int rc = 0;
+ int32_t hdl;
/* process patch descriptor */
patch_desc = (struct cam_patch_desc *)
@@ -146,8 +147,11 @@
sizeof(struct cam_patch_desc));
for (i = 0; i < packet->num_patches; i++) {
+
+ hdl = cam_mem_is_secure_buf(patch_desc[i].src_buf_hdl) ?
+ sec_mmu_hdl : iommu_hdl;
rc = cam_mem_get_io_buf(patch_desc[i].src_buf_hdl,
- iommu_hdl, &iova_addr, &src_buf_size);
+ hdl, &iova_addr, &src_buf_size);
if (rc < 0) {
CAM_ERR(CAM_UTIL, "unable to get src buf address");
return rc;
diff --git a/drivers/media/platform/msm/camera/cam_utils/cam_packet_util.h b/drivers/media/platform/msm/camera/cam_utils/cam_packet_util.h
index 2fa7585..323a75a 100644
--- a/drivers/media/platform/msm/camera/cam_utils/cam_packet_util.h
+++ b/drivers/media/platform/msm/camera/cam_utils/cam_packet_util.h
@@ -83,12 +83,14 @@
*
* @packet: Input packet containing Command Buffers and Patches
* @iommu_hdl: IOMMU handle of the HW Device that received the packet
+ * @sec_iommu_hdl: Secure IOMMU handle of the HW Device that
+ * received the packet
*
* @return: 0: Success
* Negative: Failure
*/
int cam_packet_util_process_patches(struct cam_packet *packet,
- int32_t iommu_hdl);
+ int32_t iommu_hdl, int32_t sec_mmu_hdl);
/**
* cam_packet_util_process_generic_cmd_buffer()
diff --git a/drivers/media/platform/msm/camera/cam_utils/cam_trace.h b/drivers/media/platform/msm/camera/cam_utils/cam_trace.h
index 2e9e61f..f4f85e4 100644
--- a/drivers/media/platform/msm/camera/cam_utils/cam_trace.h
+++ b/drivers/media/platform/msm/camera/cam_utils/cam_trace.h
@@ -92,15 +92,15 @@
);
TRACE_EVENT(cam_apply_req,
- TP_PROTO(const char *entity, struct cam_req_mgr_apply_request *req),
- TP_ARGS(entity, req),
+ TP_PROTO(const char *entity, uint64_t req_id),
+ TP_ARGS(entity, req_id),
TP_STRUCT__entry(
__string(entity, entity)
__field(uint64_t, req_id)
),
TP_fast_assign(
__assign_str(entity, entity);
- __entry->req_id = req->request_id;
+ __entry->req_id = req_id;
),
TP_printk(
"%8s: ApplyRequest request=%llu",
@@ -217,6 +217,75 @@
__entry->devicemap, __entry->link, __entry->session
)
);
+
+TRACE_EVENT(cam_submit_to_hw,
+ TP_PROTO(const char *entity, uint64_t req_id),
+ TP_ARGS(entity, req_id),
+ TP_STRUCT__entry(
+ __string(entity, entity)
+ __field(uint64_t, req_id)
+ ),
+ TP_fast_assign(
+ __assign_str(entity, entity);
+ __entry->req_id = req_id;
+ ),
+ TP_printk(
+ "%8s: submit request=%llu",
+ __get_str(entity), __entry->req_id
+ )
+);
+
+TRACE_EVENT(cam_irq_activated,
+ TP_PROTO(const char *entity, uint32_t irq_type),
+ TP_ARGS(entity, irq_type),
+ TP_STRUCT__entry(
+ __string(entity, entity)
+ __field(uint32_t, irq_type)
+ ),
+ TP_fast_assign(
+ __assign_str(entity, entity);
+ __entry->irq_type = irq_type;
+ ),
+ TP_printk(
+ "%8s: got irq type=%d",
+ __get_str(entity), __entry->irq_type
+ )
+);
+
+TRACE_EVENT(cam_irq_handled,
+ TP_PROTO(const char *entity, uint32_t irq_type),
+ TP_ARGS(entity, irq_type),
+ TP_STRUCT__entry(
+ __string(entity, entity)
+ __field(uint32_t, irq_type)
+ ),
+ TP_fast_assign(
+ __assign_str(entity, entity);
+ __entry->irq_type = irq_type;
+ ),
+ TP_printk(
+ "%8s: handled irq type=%d",
+ __get_str(entity), __entry->irq_type
+ )
+);
+
+TRACE_EVENT(cam_cdm_cb,
+ TP_PROTO(const char *entity, uint32_t status),
+ TP_ARGS(entity, status),
+ TP_STRUCT__entry(
+ __string(entity, entity)
+ __field(uint32_t, status)
+ ),
+ TP_fast_assign(
+ __assign_str(entity, entity);
+ __entry->status = status;
+ ),
+ TP_printk(
+ "%8s: cdm cb status=%d",
+ __get_str(entity), __entry->status
+ )
+);
+
#endif /* _CAM_TRACE_H */
/* This part must be outside protection */
diff --git a/drivers/media/platform/msm/sde/rotator/sde_rotator_core.c b/drivers/media/platform/msm/sde/rotator/sde_rotator_core.c
index 03d4840..d749384 100644
--- a/drivers/media/platform/msm/sde/rotator/sde_rotator_core.c
+++ b/drivers/media/platform/msm/sde/rotator/sde_rotator_core.c
@@ -65,6 +65,9 @@
#define ROT_OVERHEAD_NUMERATOR 27
#define ROT_OVERHEAD_DENOMINATOR 10000
+/* Minimum Rotator Clock value */
+#define ROT_MIN_ROT_CLK 20000000
+
/* default minimum bandwidth vote */
#define ROT_ENABLE_BW_VOTE 64000
/*
@@ -1378,6 +1381,9 @@
if (rot_dev->min_rot_clk > perf->clk_rate)
perf->clk_rate = rot_dev->min_rot_clk;
+ if (mgr->min_rot_clk > perf->clk_rate)
+ perf->clk_rate = mgr->min_rot_clk;
+
read_bw = sde_rotator_calc_buf_bw(in_fmt, config->input.width,
config->input.height, max_fps);
@@ -2383,7 +2389,7 @@
}
SDEROT_DBG(
- "reconfig session id=%u in{%u,%u}f:%u out{%u,%u}f:%u fps:%d clk:%lu, bw:%llu\n",
+ "reconfig session id=%u in{%u,%u}f:%x out{%u,%u}f:%x fps:%d clk:%lu bw:%llu\n",
config->session_id, config->input.width, config->input.height,
config->input.format, config->output.width,
config->output.height, config->output.format,
@@ -3084,6 +3090,7 @@
IS_SDE_MAJOR_MINOR_SAME(mdata->mdss_version,
SDE_MDP_HW_REV_410)) {
mgr->ops_hw_init = sde_rotator_r3_init;
+ mgr->min_rot_clk = ROT_MIN_ROT_CLK;
} else {
ret = -ENODEV;
SDEROT_ERR("unsupported sde version %x\n",
@@ -3398,3 +3405,38 @@
return sde_rotator_config_session(mgr, private, config);
}
+
+/*
+ * sde_rotator_session_validate - validate session
+ */
+int sde_rotator_session_validate(struct sde_rot_mgr *mgr,
+ struct sde_rot_file_private *private,
+ struct sde_rotation_config *config)
+{
+ int ret;
+
+ if (!mgr || !private || !config) {
+ SDEROT_ERR("null parameters\n");
+ return -EINVAL;
+ }
+
+ SDEROT_DBG(
+ "validate session id=%u in{%u,%u}f:%x out{%u,%u}f:%x fps:%d\n",
+ config->session_id, config->input.width, config->input.height,
+ config->input.format, config->output.width,
+ config->output.height, config->output.format,
+ config->frame_rate);
+
+ ret = sde_rotator_verify_config_all(mgr, config);
+ if (ret) {
+ SDEROT_WARN("rotator verify format failed %d\n", ret);
+ return ret;
+ }
+
+ if (config->output.sbuf && mgr->sbuf_ctx != private && mgr->sbuf_ctx) {
+ SDEROT_WARN("too many sbuf sessions\n");
+ return -EBUSY;
+ }
+
+ return 0;
+}
diff --git a/drivers/media/platform/msm/sde/rotator/sde_rotator_core.h b/drivers/media/platform/msm/sde/rotator/sde_rotator_core.h
index eb8cb88..e2f5465 100644
--- a/drivers/media/platform/msm/sde/rotator/sde_rotator_core.h
+++ b/drivers/media/platform/msm/sde/rotator/sde_rotator_core.h
@@ -396,6 +396,7 @@
* @pixel_per_clk: rotator hardware performance in pixel for clock
* @fudge_factor: fudge factor for clock calculation
* @overhead: software overhead for offline rotation in msec
+ * @min_rot_clk: minimum rotator clock rate
* @sbuf_ctx: pointer to sbuf session context
* @ops_xxx: function pointers of rotator HAL layer
* @hw_data: private handle of rotator HAL layer
@@ -443,6 +444,7 @@
struct sde_mult_factor pixel_per_clk;
struct sde_mult_factor fudge_factor;
struct sde_mult_factor overhead;
+ unsigned long min_rot_clk;
struct sde_rot_file_private *sbuf_ctx;
@@ -602,6 +604,17 @@
struct sde_rotation_config *config);
/*
+ * sde_rotator_session_validate - validate session configuration
+ * @mgr: Pointer to rotator manager
+ * @private: Pointer to per file session
+ * @config: Pointer to rotator configuration
+ * return: 0 if success; error code otherwise
+ */
+int sde_rotator_session_validate(struct sde_rot_mgr *mgr,
+ struct sde_rot_file_private *private,
+ struct sde_rotation_config *config);
+
+/*
* sde_rotator_req_init - allocate a new request and initialzie with given
* array of rotation items
* @rot_dev: Pointer to rotator device
diff --git a/drivers/media/platform/msm/sde/rotator/sde_rotator_dev.c b/drivers/media/platform/msm/sde/rotator/sde_rotator_dev.c
index a838128..76c9367 100644
--- a/drivers/media/platform/msm/sde/rotator/sde_rotator_dev.c
+++ b/drivers/media/platform/msm/sde/rotator/sde_rotator_dev.c
@@ -1460,9 +1460,10 @@
struct sde_rotator_device *rot_dev;
struct sde_rotator_request *request = NULL;
struct sde_rot_entry_container *req = NULL;
+ struct sde_rotation_config rotcfg;
ktime_t *ts;
u32 flags = 0;
- int i, ret;
+ int i, ret = 0;
if (!handle || !cmd) {
SDEROT_ERR("invalid rotator handle/cmd\n");
@@ -1584,11 +1585,8 @@
ret = -ENOMEM;
goto error_init_request;
}
- }
- if (cmd_type == SDE_ROTATOR_INLINE_CMD_VALIDATE) {
- struct sde_rotation_config rotcfg;
-
+ /* initialize session configuration */
memset(&rotcfg, 0, sizeof(struct sde_rotation_config));
rotcfg.flags = flags;
rotcfg.frame_rate = cmd->fps;
@@ -1606,25 +1604,16 @@
rotcfg.output.comp_ratio.numer = 1;
rotcfg.output.comp_ratio.denom = 1;
rotcfg.output.sbuf = true;
+ }
- if (memcmp(&rotcfg, &ctx->rotcfg, sizeof(rotcfg))) {
- ret = sde_rotator_session_config(rot_dev->mgr,
- ctx->private, &rotcfg);
- if (ret) {
- SDEROT_WARN("fail session config s:%d\n",
- ctx->session_id);
- goto error_session_config;
- }
+ if (cmd_type == SDE_ROTATOR_INLINE_CMD_VALIDATE) {
- ctx->rotcfg = rotcfg;
- }
-
- ret = sde_rotator_validate_request(rot_dev->mgr, ctx->private,
- req);
+ ret = sde_rotator_session_validate(rot_dev->mgr,
+ ctx->private, &rotcfg);
if (ret) {
- SDEROT_WARN("fail validate request s:%d\n",
+ SDEROT_WARN("fail session validation s:%d\n",
ctx->session_id);
- goto error_validate_request;
+ goto error_session_validate;
}
devm_kfree(rot_dev->dev, req);
@@ -1632,6 +1621,18 @@
} else if (cmd_type == SDE_ROTATOR_INLINE_CMD_COMMIT) {
+ if (memcmp(&rotcfg, &ctx->rotcfg, sizeof(rotcfg))) {
+ ret = sde_rotator_session_config(rot_dev->mgr,
+ ctx->private, &rotcfg);
+ if (ret) {
+ SDEROT_ERR("fail session config s:%d\n",
+ ctx->session_id);
+ goto error_session_config;
+ }
+
+ ctx->rotcfg = rotcfg;
+ }
+
request = list_first_entry_or_null(&ctx->retired_list,
struct sde_rotator_request, list);
if (!request) {
@@ -1745,7 +1746,7 @@
sde_rotator_update_retire_sequence(request);
sde_rotator_retire_request(request);
error_retired_list:
-error_validate_request:
+error_session_validate:
error_session_config:
devm_kfree(rot_dev->dev, req);
error_invalid_handle:
@@ -2614,13 +2615,6 @@
}
/**
- * Loose any reference to sync fence once we pass
- * it to user. Driver does not clean up user
- * unclosed fence descriptors.
- */
- vbinfo->fence = NULL;
-
- /**
* Cache fence descriptor in case user calls this
* ioctl multiple times. Cached value would be stale
* if user duplicated and closed old descriptor.
diff --git a/drivers/media/platform/msm/vidc/venus_hfi.c b/drivers/media/platform/msm/vidc/venus_hfi.c
index 0fbc96e..5d2ed29 100644
--- a/drivers/media/platform/msm/vidc/venus_hfi.c
+++ b/drivers/media/platform/msm/vidc/venus_hfi.c
@@ -1751,9 +1751,8 @@
if (rc || __iface_cmdq_write(dev, &version_pkt))
dprintk(VIDC_WARN, "Failed to send image version pkt to f/w\n");
- rc = __enable_subcaches(device);
- if (!rc)
- __set_subcaches(device);
+ __enable_subcaches(device);
+ __set_subcaches(device);
if (dev->res->pm_qos_latency_us) {
#ifdef CONFIG_SMP
@@ -3790,8 +3789,9 @@
venus_hfi_for_each_subcache(device, sinfo) {
rc = llcc_slice_activate(sinfo->subcache);
if (rc) {
- dprintk(VIDC_ERR, "Failed to activate %s: %d\n",
+ dprintk(VIDC_WARN, "Failed to activate %s: %d\n",
sinfo->name, rc);
+ msm_vidc_res_handle_fatal_hw_error(device->res, true);
goto err_activate_fail;
}
sinfo->isactive = true;
@@ -3806,7 +3806,7 @@
err_activate_fail:
__release_subcaches(device);
__disable_subcaches(device);
- return -EINVAL;
+ return 0;
}
static int __set_subcaches(struct venus_hfi_device *device)
@@ -3848,25 +3848,25 @@
rc = __core_set_resource(device, &rhdr, (void *)sc_res_info);
if (rc) {
- dprintk(VIDC_ERR, "Failed to set subcaches %d\n", rc);
+ dprintk(VIDC_WARN, "Failed to set subcaches %d\n", rc);
goto err_fail_set_subacaches;
}
- }
- venus_hfi_for_each_subcache(device, sinfo) {
- if (sinfo->isactive == true)
- sinfo->isset = true;
- }
+ venus_hfi_for_each_subcache(device, sinfo) {
+ if (sinfo->isactive == true)
+ sinfo->isset = true;
+ }
- dprintk(VIDC_DBG, "Set Subcaches done to Venus\n");
- device->res->sys_cache_res_set = true;
+ dprintk(VIDC_DBG, "Set Subcaches done to Venus\n");
+ device->res->sys_cache_res_set = true;
+ }
return 0;
err_fail_set_subacaches:
__disable_subcaches(device);
- return rc;
+ return 0;
}
static int __release_subcaches(struct venus_hfi_device *device)
@@ -3905,13 +3905,13 @@
rc = __core_release_resource(device, &rhdr);
if (rc)
- dprintk(VIDC_ERR,
+ dprintk(VIDC_WARN,
"Failed to release %d subcaches\n", c);
}
device->res->sys_cache_res_set = false;
- return rc;
+ return 0;
}
static int __disable_subcaches(struct venus_hfi_device *device)
@@ -3929,7 +3929,7 @@
sinfo->name);
rc = llcc_slice_deactivate(sinfo->subcache);
if (rc) {
- dprintk(VIDC_ERR,
+ dprintk(VIDC_WARN,
"Failed to de-activate %s: %d\n",
sinfo->name, rc);
}
@@ -3937,7 +3937,7 @@
}
}
- return rc;
+ return 0;
}
static int __venus_power_on(struct venus_hfi_device *device)
@@ -4111,9 +4111,8 @@
__sys_set_debug(device, msm_vidc_fw_debug);
- rc = __enable_subcaches(device);
- if (!rc)
- __set_subcaches(device);
+ __enable_subcaches(device);
+ __set_subcaches(device);
dprintk(VIDC_PROF, "Resumed from power collapse\n");
exit:
diff --git a/drivers/mmc/card/block.c b/drivers/mmc/card/block.c
index 120fd54..af409aa 100644
--- a/drivers/mmc/card/block.c
+++ b/drivers/mmc/card/block.c
@@ -3518,15 +3518,23 @@
/* RED error - Fatal: requires reset */
if (mrq->cmdq_req->resp_err) {
err = mrq->cmdq_req->resp_err;
+ goto reset;
+ }
+
+ /*
+ * TIMEOUT errrors can happen because of execution error
+ * in the last command. So send cmd 13 to get device status
+ */
+ if ((mrq->cmd && (mrq->cmd->error == -ETIMEDOUT)) ||
+ (mrq->data && (mrq->data->error == -ETIMEDOUT))) {
if (mmc_host_halt(host) || mmc_host_cq_disable(host)) {
ret = get_card_status(host->card, &status, 0);
if (ret)
pr_err("%s: CMD13 failed with err %d\n",
mmc_hostname(host), ret);
}
- pr_err("%s: Response error detected with device status 0x%08x\n",
+ pr_err("%s: Timeout error detected with device status 0x%08x\n",
mmc_hostname(host), status);
- goto reset;
}
/*
@@ -3572,7 +3580,7 @@
else if (mrq->data && mrq->data->error)
err = mrq->data->error;
- if (err || cmdq_req->resp_err) {
+ if ((err || cmdq_req->resp_err) && !cmdq_req->skip_err_handling) {
pr_err("%s: %s: txfr error(%d)/resp_err(%d)\n",
mmc_hostname(mrq->host), __func__, err,
cmdq_req->resp_err);
@@ -3609,6 +3617,17 @@
blk_end_request_all(rq, err);
goto out;
}
+ /*
+ * In case of error, cmdq_req->data.bytes_xfered is set to 0.
+ * If we call blk_end_request() with nr_bytes as 0 then the request
+ * never gets completed. So in case of error, to complete a request
+ * with error we should use blk_end_request_all().
+ */
+ if (err && cmdq_req->skip_err_handling) {
+ cmdq_req->skip_err_handling = false;
+ blk_end_request_all(rq, err);
+ goto out;
+ }
blk_end_request(rq, err, cmdq_req->data.bytes_xfered);
diff --git a/drivers/mmc/host/sdhci-msm.c b/drivers/mmc/host/sdhci-msm.c
index 60e8ca0..55d9cf5 100644
--- a/drivers/mmc/host/sdhci-msm.c
+++ b/drivers/mmc/host/sdhci-msm.c
@@ -1902,8 +1902,16 @@
dev_err(dev, "Invalid clock table\n");
goto out;
}
+ if (ice_clk_table_len != 2) {
+ dev_err(dev, "Need max and min frequencies in the table\n");
+ goto out;
+ }
pdata->sup_ice_clk_table = ice_clk_table;
pdata->sup_ice_clk_cnt = ice_clk_table_len;
+ pdata->ice_clk_max = pdata->sup_ice_clk_table[0];
+ pdata->ice_clk_min = pdata->sup_ice_clk_table[1];
+ dev_dbg(dev, "supported ICE clock rates (Hz): max: %u min: %u\n",
+ pdata->ice_clk_max, pdata->ice_clk_min);
}
pdata->vreg_data = devm_kzalloc(dev, sizeof(struct
@@ -4115,6 +4123,32 @@
return max_curr;
}
+static int sdhci_msm_notify_load(struct sdhci_host *host, enum mmc_load state)
+{
+ struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
+ struct sdhci_msm_host *msm_host = pltfm_host->priv;
+ int ret = 0;
+ u32 clk_rate = 0;
+
+ if (!IS_ERR(msm_host->ice_clk)) {
+ clk_rate = (state == MMC_LOAD_LOW) ?
+ msm_host->pdata->ice_clk_min :
+ msm_host->pdata->ice_clk_max;
+ if (msm_host->ice_clk_rate == clk_rate)
+ return 0;
+ pr_debug("%s: changing ICE clk rate to %u\n",
+ mmc_hostname(host->mmc), clk_rate);
+ ret = clk_set_rate(msm_host->ice_clk, clk_rate);
+ if (ret) {
+ pr_err("%s: ICE_CLK rate set failed (%d) for %u\n",
+ mmc_hostname(host->mmc), ret, clk_rate);
+ return ret;
+ }
+ msm_host->ice_clk_rate = clk_rate;
+ }
+ return 0;
+}
+
static struct sdhci_ops sdhci_msm_ops = {
.crypto_engine_cfg = sdhci_msm_ice_cfg,
.crypto_engine_cmdq_cfg = sdhci_msm_ice_cmdq_cfg,
@@ -4142,6 +4176,7 @@
.pre_req = sdhci_msm_pre_req,
.post_req = sdhci_msm_post_req,
.get_current_limit = sdhci_msm_get_current_limit,
+ .notify_load = sdhci_msm_notify_load,
};
static void sdhci_set_default_hw_caps(struct sdhci_msm_host *msm_host,
@@ -4439,11 +4474,11 @@
if (!IS_ERR(msm_host->ice_clk)) {
/* ICE core has only one clock frequency for now */
ret = clk_set_rate(msm_host->ice_clk,
- msm_host->pdata->sup_ice_clk_table[0]);
+ msm_host->pdata->ice_clk_max);
if (ret) {
dev_err(&pdev->dev, "ICE_CLK rate set failed (%d) for %u\n",
ret,
- msm_host->pdata->sup_ice_clk_table[0]);
+ msm_host->pdata->ice_clk_max);
goto pclk_disable;
}
ret = clk_prepare_enable(msm_host->ice_clk);
@@ -4451,7 +4486,7 @@
goto pclk_disable;
msm_host->ice_clk_rate =
- msm_host->pdata->sup_clk_table[0];
+ msm_host->pdata->ice_clk_max;
}
}
diff --git a/drivers/mmc/host/sdhci-msm.h b/drivers/mmc/host/sdhci-msm.h
index cdbaaa9..7c0b873 100644
--- a/drivers/mmc/host/sdhci-msm.h
+++ b/drivers/mmc/host/sdhci-msm.h
@@ -151,6 +151,8 @@
unsigned char sup_ice_clk_cnt;
struct sdhci_msm_pm_qos_data pm_qos_data;
bool sdr104_wa;
+ u32 ice_clk_max;
+ u32 ice_clk_min;
};
struct sdhci_msm_bus_vote {
diff --git a/drivers/mtd/nand/mxc_nand.c b/drivers/mtd/nand/mxc_nand.c
index d7f724b..0c84ee8 100644
--- a/drivers/mtd/nand/mxc_nand.c
+++ b/drivers/mtd/nand/mxc_nand.c
@@ -877,6 +877,8 @@
}
}
+#define MXC_V1_ECCBYTES 5
+
static int mxc_v1_ooblayout_ecc(struct mtd_info *mtd, int section,
struct mtd_oob_region *oobregion)
{
@@ -886,7 +888,7 @@
return -ERANGE;
oobregion->offset = (section * 16) + 6;
- oobregion->length = nand_chip->ecc.bytes;
+ oobregion->length = MXC_V1_ECCBYTES;
return 0;
}
@@ -908,8 +910,7 @@
oobregion->length = 4;
}
} else {
- oobregion->offset = ((section - 1) * 16) +
- nand_chip->ecc.bytes + 6;
+ oobregion->offset = ((section - 1) * 16) + MXC_V1_ECCBYTES + 6;
if (section < nand_chip->ecc.steps)
oobregion->length = (section * 16) + 6 -
oobregion->offset;
diff --git a/drivers/mtd/nand/qcom_nandc.c b/drivers/mtd/nand/qcom_nandc.c
index 57d483a..6f0fd15 100644
--- a/drivers/mtd/nand/qcom_nandc.c
+++ b/drivers/mtd/nand/qcom_nandc.c
@@ -109,7 +109,11 @@
#define READ_ADDR 0
/* NAND_DEV_CMD_VLD bits */
-#define READ_START_VLD 0
+#define READ_START_VLD BIT(0)
+#define READ_STOP_VLD BIT(1)
+#define WRITE_START_VLD BIT(2)
+#define ERASE_START_VLD BIT(3)
+#define SEQ_READ_START_VLD BIT(4)
/* NAND_EBI2_ECC_BUF_CFG bits */
#define NUM_STEPS 0
@@ -148,6 +152,10 @@
#define FETCH_ID 0xb
#define RESET_DEVICE 0xd
+/* Default Value for NAND_DEV_CMD_VLD */
+#define NAND_DEV_CMD_VLD_VAL (READ_START_VLD | WRITE_START_VLD | \
+ ERASE_START_VLD | SEQ_READ_START_VLD)
+
/*
* the NAND controller performs reads/writes with ECC in 516 byte chunks.
* the driver calls the chunks 'step' or 'codeword' interchangeably
@@ -672,8 +680,7 @@
/* configure CMD1 and VLD for ONFI param probing */
nandc_set_reg(nandc, NAND_DEV_CMD_VLD,
- (nandc->vld & ~(1 << READ_START_VLD))
- | 0 << READ_START_VLD);
+ (nandc->vld & ~READ_START_VLD));
nandc_set_reg(nandc, NAND_DEV_CMD1,
(nandc->cmd1 & ~(0xFF << READ_ADDR))
| NAND_CMD_PARAM << READ_ADDR);
@@ -1893,7 +1900,7 @@
| wide_bus << WIDE_FLASH
| 1 << DEV0_CFG1_ECC_DISABLE;
- host->ecc_bch_cfg = host->bch_enabled << ECC_CFG_ECC_DISABLE
+ host->ecc_bch_cfg = !host->bch_enabled << ECC_CFG_ECC_DISABLE
| 0 << ECC_SW_RESET
| host->cw_data << ECC_NUM_DATA_BYTES
| 1 << ECC_FORCE_CLK_OPEN
@@ -1972,13 +1979,14 @@
{
/* kill onenand */
nandc_write(nandc, SFLASHC_BURST_CFG, 0);
+ nandc_write(nandc, NAND_DEV_CMD_VLD, NAND_DEV_CMD_VLD_VAL);
/* enable ADM DMA */
nandc_write(nandc, NAND_FLASH_CHIP_SELECT, DM_EN);
/* save the original values of these registers */
nandc->cmd1 = nandc_read(nandc, NAND_DEV_CMD1);
- nandc->vld = nandc_read(nandc, NAND_DEV_CMD_VLD);
+ nandc->vld = NAND_DEV_CMD_VLD_VAL;
return 0;
}
diff --git a/drivers/net/ethernet/chelsio/cxgb4/t4_hw.c b/drivers/net/ethernet/chelsio/cxgb4/t4_hw.c
index e813951..9e073fb 100644
--- a/drivers/net/ethernet/chelsio/cxgb4/t4_hw.c
+++ b/drivers/net/ethernet/chelsio/cxgb4/t4_hw.c
@@ -317,12 +317,12 @@
if (v != MBOX_OWNER_DRV) {
ret = (v == MBOX_OWNER_FW) ? -EBUSY : -ETIMEDOUT;
- t4_record_mbox(adap, cmd, MBOX_LEN, access, ret);
+ t4_record_mbox(adap, cmd, size, access, ret);
return ret;
}
/* Copy in the new mailbox command and send it on its way ... */
- t4_record_mbox(adap, cmd, MBOX_LEN, access, 0);
+ t4_record_mbox(adap, cmd, size, access, 0);
for (i = 0; i < size; i += 8)
t4_write_reg64(adap, data_reg + i, be64_to_cpu(*p++));
@@ -371,7 +371,7 @@
}
ret = (pcie_fw & PCIE_FW_ERR_F) ? -ENXIO : -ETIMEDOUT;
- t4_record_mbox(adap, cmd, MBOX_LEN, access, ret);
+ t4_record_mbox(adap, cmd, size, access, ret);
dev_err(adap->pdev_dev, "command %#x in mailbox %d timed out\n",
*(const u8 *)cmd, mbox);
t4_report_fw_error(adap);
diff --git a/drivers/net/ethernet/freescale/fman/mac.c b/drivers/net/ethernet/freescale/fman/mac.c
index 736db9d..81021f8 100644
--- a/drivers/net/ethernet/freescale/fman/mac.c
+++ b/drivers/net/ethernet/freescale/fman/mac.c
@@ -622,6 +622,9 @@
goto no_mem;
}
+ pdev->dev.of_node = node;
+ pdev->dev.parent = priv->dev;
+
ret = platform_device_add_data(pdev, &data, sizeof(data));
if (ret)
goto err;
diff --git a/drivers/net/ethernet/freescale/gianfar.c b/drivers/net/ethernet/freescale/gianfar.c
index 3f4e711..fd20688 100644
--- a/drivers/net/ethernet/freescale/gianfar.c
+++ b/drivers/net/ethernet/freescale/gianfar.c
@@ -3690,7 +3690,7 @@
u32 tempval1 = gfar_read(®s->maccfg1);
u32 tempval = gfar_read(®s->maccfg2);
u32 ecntrl = gfar_read(®s->ecntrl);
- u32 tx_flow_oldval = (tempval & MACCFG1_TX_FLOW);
+ u32 tx_flow_oldval = (tempval1 & MACCFG1_TX_FLOW);
if (phydev->duplex != priv->oldduplex) {
if (!(phydev->duplex))
diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum.c
index f902c4d..1806b1f 100644
--- a/drivers/net/ethernet/mellanox/mlxsw/spectrum.c
+++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum.c
@@ -4172,6 +4172,8 @@
return -EINVAL;
if (!info->linking)
break;
+ if (netdev_has_any_upper_dev(upper_dev))
+ return -EINVAL;
/* HW limitation forbids to put ports to multiple bridges. */
if (netif_is_bridge_master(upper_dev) &&
!mlxsw_sp_master_bridge_check(mlxsw_sp, upper_dev))
@@ -4185,6 +4187,10 @@
if (netif_is_lag_port(dev) && is_vlan_dev(upper_dev) &&
!netif_is_lag_master(vlan_dev_real_dev(upper_dev)))
return -EINVAL;
+ if (!info->linking)
+ break;
+ if (netdev_has_any_upper_dev(upper_dev))
+ return -EINVAL;
break;
case NETDEV_CHANGEUPPER:
upper_dev = info->upper_dev;
diff --git a/drivers/net/ethernet/qlogic/qlge/qlge_dbg.c b/drivers/net/ethernet/qlogic/qlge/qlge_dbg.c
index 829be21..be258d9 100644
--- a/drivers/net/ethernet/qlogic/qlge/qlge_dbg.c
+++ b/drivers/net/ethernet/qlogic/qlge/qlge_dbg.c
@@ -724,7 +724,7 @@
seg_hdr->cookie = MPI_COREDUMP_COOKIE;
seg_hdr->segNum = seg_number;
seg_hdr->segSize = seg_size;
- memcpy(seg_hdr->description, desc, (sizeof(seg_hdr->description)) - 1);
+ strncpy(seg_hdr->description, desc, (sizeof(seg_hdr->description)) - 1);
}
/*
diff --git a/drivers/net/hyperv/netvsc_drv.c b/drivers/net/hyperv/netvsc_drv.c
index ff038e5..36a04e1 100644
--- a/drivers/net/hyperv/netvsc_drv.c
+++ b/drivers/net/hyperv/netvsc_drv.c
@@ -1084,7 +1084,12 @@
bool notify = false, reschedule = false;
unsigned long flags, next_reconfig, delay;
- rtnl_lock();
+ /* if changes are happening, comeback later */
+ if (!rtnl_trylock()) {
+ schedule_delayed_work(&ndev_ctx->dwork, LINKCHANGE_INT);
+ return;
+ }
+
if (ndev_ctx->start_remove)
goto out_unlock;
diff --git a/drivers/net/macsec.c b/drivers/net/macsec.c
index a5d66e2..2caac0c 100644
--- a/drivers/net/macsec.c
+++ b/drivers/net/macsec.c
@@ -3510,6 +3510,7 @@
module_exit(macsec_exit);
MODULE_ALIAS_RTNL_LINK("macsec");
+MODULE_ALIAS_GENL_FAMILY("macsec");
MODULE_DESCRIPTION("MACsec IEEE 802.1AE");
MODULE_LICENSE("GPL v2");
diff --git a/drivers/net/phy/phy.c b/drivers/net/phy/phy.c
index 775a6e1..6e12401 100644
--- a/drivers/net/phy/phy.c
+++ b/drivers/net/phy/phy.c
@@ -674,9 +674,6 @@
if (phydev->state > PHY_UP && phydev->state != PHY_HALTED)
phydev->state = PHY_UP;
mutex_unlock(&phydev->lock);
-
- /* Now we can run the state machine synchronously */
- phy_state_machine(&phydev->state_queue.work);
}
/**
diff --git a/drivers/net/wireless/ath/ath10k/core.c b/drivers/net/wireless/ath/ath10k/core.c
index 972b5e2..366d3dc 100644
--- a/drivers/net/wireless/ath/ath10k/core.c
+++ b/drivers/net/wireless/ath/ath10k/core.c
@@ -1852,6 +1852,12 @@
goto err_wmi_detach;
}
+ /* If firmware indicates Full Rx Reorder support it must be used in a
+ * slightly different manner. Let HTT code know.
+ */
+ ar->htt.rx_ring.in_ord_rx = !!(test_bit(WMI_SERVICE_RX_FULL_REORDER,
+ ar->wmi.svc_map));
+
status = ath10k_htt_rx_alloc(&ar->htt);
if (status) {
ath10k_err(ar, "failed to alloc htt rx: %d\n", status);
@@ -1964,12 +1970,6 @@
}
}
- /* If firmware indicates Full Rx Reorder support it must be used in a
- * slightly different manner. Let HTT code know.
- */
- ar->htt.rx_ring.in_ord_rx = !!(test_bit(WMI_SERVICE_RX_FULL_REORDER,
- ar->wmi.svc_map));
-
status = ath10k_htt_rx_ring_refill(ar);
if (status) {
ath10k_err(ar, "failed to refill htt rx ring: %d\n", status);
diff --git a/drivers/net/wireless/ath/wil6210/cfg80211.c b/drivers/net/wireless/ath/wil6210/cfg80211.c
index 9552d2a..e2a459e 100644
--- a/drivers/net/wireless/ath/wil6210/cfg80211.c
+++ b/drivers/net/wireless/ath/wil6210/cfg80211.c
@@ -1802,9 +1802,13 @@
wil_dbg_pm(wil, "suspending\n");
+ mutex_lock(&wil->mutex);
wil_p2p_stop_discovery(wil);
+ mutex_lock(&wil->p2p_wdev_mutex);
wil_abort_scan(wil, true);
+ mutex_unlock(&wil->p2p_wdev_mutex);
+ mutex_unlock(&wil->mutex);
out:
return rc;
diff --git a/drivers/net/wireless/ath/wil6210/debugfs.c b/drivers/net/wireless/ath/wil6210/debugfs.c
index 45a8081..831780a 100644
--- a/drivers/net/wireless/ath/wil6210/debugfs.c
+++ b/drivers/net/wireless/ath/wil6210/debugfs.c
@@ -242,12 +242,19 @@
static int wil_mbox_debugfs_show(struct seq_file *s, void *data)
{
struct wil6210_priv *wil = s->private;
+ int ret;
+
+ ret = wil_pm_runtime_get(wil);
+ if (ret < 0)
+ return ret;
wil_print_ring(s, "tx", wil->csr + HOST_MBOX +
offsetof(struct wil6210_mbox_ctl, tx));
wil_print_ring(s, "rx", wil->csr + HOST_MBOX +
offsetof(struct wil6210_mbox_ctl, rx));
+ wil_pm_runtime_put(wil);
+
return 0;
}
@@ -265,15 +272,38 @@
static int wil_debugfs_iomem_x32_set(void *data, u64 val)
{
- writel(val, (void __iomem *)data);
+ struct wil_debugfs_iomem_data *d = (struct
+ wil_debugfs_iomem_data *)data;
+ struct wil6210_priv *wil = d->wil;
+ int ret;
+
+ ret = wil_pm_runtime_get(wil);
+ if (ret < 0)
+ return ret;
+
+ writel_relaxed(val, (void __iomem *)d->offset);
+
wmb(); /* make sure write propagated to HW */
+ wil_pm_runtime_put(wil);
+
return 0;
}
static int wil_debugfs_iomem_x32_get(void *data, u64 *val)
{
- *val = readl((void __iomem *)data);
+ struct wil_debugfs_iomem_data *d = (struct
+ wil_debugfs_iomem_data *)data;
+ struct wil6210_priv *wil = d->wil;
+ int ret;
+
+ ret = wil_pm_runtime_get(wil);
+ if (ret < 0)
+ return ret;
+
+ *val = readl_relaxed((void __iomem *)d->offset);
+
+ wil_pm_runtime_put(wil);
return 0;
}
@@ -284,10 +314,21 @@
static struct dentry *wil_debugfs_create_iomem_x32(const char *name,
umode_t mode,
struct dentry *parent,
- void *value)
+ void *value,
+ struct wil6210_priv *wil)
{
- return debugfs_create_file(name, mode, parent, value,
- &fops_iomem_x32);
+ struct dentry *file;
+ struct wil_debugfs_iomem_data *data = &wil->dbg_data.data_arr[
+ wil->dbg_data.iomem_data_count];
+
+ data->wil = wil;
+ data->offset = value;
+
+ file = debugfs_create_file(name, mode, parent, data, &fops_iomem_x32);
+ if (!IS_ERR_OR_NULL(file))
+ wil->dbg_data.iomem_data_count++;
+
+ return file;
}
static int wil_debugfs_ulong_set(void *data, u64 val)
@@ -346,7 +387,8 @@
case doff_io32:
f = wil_debugfs_create_iomem_x32(tbl[i].name,
tbl[i].mode, dbg,
- base + tbl[i].off);
+ base + tbl[i].off,
+ wil);
break;
case doff_u8:
f = debugfs_create_u8(tbl[i].name, tbl[i].mode, dbg,
@@ -475,13 +517,22 @@
static int wil_memread_debugfs_show(struct seq_file *s, void *data)
{
struct wil6210_priv *wil = s->private;
- void __iomem *a = wmi_buffer(wil, cpu_to_le32(mem_addr));
+ void __iomem *a;
+ int ret;
+
+ ret = wil_pm_runtime_get(wil);
+ if (ret < 0)
+ return ret;
+
+ a = wmi_buffer(wil, cpu_to_le32(mem_addr));
if (a)
seq_printf(s, "[0x%08x] = 0x%08x\n", mem_addr, readl(a));
else
seq_printf(s, "[0x%08x] = INVALID\n", mem_addr);
+ wil_pm_runtime_put(wil);
+
return 0;
}
@@ -502,10 +553,12 @@
{
enum { max_count = 4096 };
struct wil_blob_wrapper *wil_blob = file->private_data;
+ struct wil6210_priv *wil = wil_blob->wil;
loff_t pos = *ppos;
size_t available = wil_blob->blob.size;
void *buf;
size_t ret;
+ int rc;
if (test_bit(wil_status_suspending, wil_blob->wil->status) ||
test_bit(wil_status_suspended, wil_blob->wil->status))
@@ -526,10 +579,19 @@
if (!buf)
return -ENOMEM;
+ rc = wil_pm_runtime_get(wil);
+ if (rc < 0) {
+ kfree(buf);
+ return rc;
+ }
+
wil_memcpy_fromio_32(buf, (const void __iomem *)
wil_blob->blob.data + pos, count);
ret = copy_to_user(user_buf, buf, count);
+
+ wil_pm_runtime_put(wil);
+
kfree(buf);
if (ret == count)
return -EFAULT;
@@ -1786,6 +1848,13 @@
{},
};
+static const int dbg_off_count = 4 * (ARRAY_SIZE(isr_off) - 1) +
+ ARRAY_SIZE(dbg_wil_regs) - 1 +
+ ARRAY_SIZE(pseudo_isr_off) - 1 +
+ ARRAY_SIZE(lgc_itr_cnt_off) - 1 +
+ ARRAY_SIZE(tx_itr_cnt_off) - 1 +
+ ARRAY_SIZE(rx_itr_cnt_off) - 1;
+
int wil6210_debugfs_init(struct wil6210_priv *wil)
{
struct dentry *dbg = wil->debug = debugfs_create_dir(WIL_NAME,
@@ -1794,6 +1863,17 @@
if (IS_ERR_OR_NULL(dbg))
return -ENODEV;
+ wil->dbg_data.data_arr = kcalloc(dbg_off_count,
+ sizeof(struct wil_debugfs_iomem_data),
+ GFP_KERNEL);
+ if (!wil->dbg_data.data_arr) {
+ debugfs_remove_recursive(dbg);
+ wil->debug = NULL;
+ return -ENOMEM;
+ }
+
+ wil->dbg_data.iomem_data_count = 0;
+
wil_pmc_init(wil);
wil6210_debugfs_init_files(wil, dbg);
@@ -1818,6 +1898,8 @@
debugfs_remove_recursive(wil->debug);
wil->debug = NULL;
+ kfree(wil->dbg_data.data_arr);
+
/* free pmc memory without sending command to fw, as it will
* be reset on the way down anyway
*/
diff --git a/drivers/net/wireless/ath/wil6210/ethtool.c b/drivers/net/wireless/ath/wil6210/ethtool.c
index adcfef4..66200f6 100644
--- a/drivers/net/wireless/ath/wil6210/ethtool.c
+++ b/drivers/net/wireless/ath/wil6210/ethtool.c
@@ -47,9 +47,14 @@
struct wil6210_priv *wil = ndev_to_wil(ndev);
u32 tx_itr_en, tx_itr_val = 0;
u32 rx_itr_en, rx_itr_val = 0;
+ int ret;
wil_dbg_misc(wil, "ethtoolops_get_coalesce\n");
+ ret = wil_pm_runtime_get(wil);
+ if (ret < 0)
+ return ret;
+
tx_itr_en = wil_r(wil, RGF_DMA_ITR_TX_CNT_CTL);
if (tx_itr_en & BIT_DMA_ITR_TX_CNT_CTL_EN)
tx_itr_val = wil_r(wil, RGF_DMA_ITR_TX_CNT_TRSH);
@@ -58,6 +63,8 @@
if (rx_itr_en & BIT_DMA_ITR_RX_CNT_CTL_EN)
rx_itr_val = wil_r(wil, RGF_DMA_ITR_RX_CNT_TRSH);
+ wil_pm_runtime_put(wil);
+
cp->tx_coalesce_usecs = tx_itr_val;
cp->rx_coalesce_usecs = rx_itr_val;
return 0;
@@ -67,6 +74,7 @@
struct ethtool_coalesce *cp)
{
struct wil6210_priv *wil = ndev_to_wil(ndev);
+ int ret;
wil_dbg_misc(wil, "ethtoolops_set_coalesce: rx %d usec, tx %d usec\n",
cp->rx_coalesce_usecs, cp->tx_coalesce_usecs);
@@ -86,8 +94,15 @@
wil->tx_max_burst_duration = cp->tx_coalesce_usecs;
wil->rx_max_burst_duration = cp->rx_coalesce_usecs;
+
+ ret = wil_pm_runtime_get(wil);
+ if (ret < 0)
+ return ret;
+
wil_configure_interrupt_moderation(wil);
+ wil_pm_runtime_put(wil);
+
return 0;
out_bad:
diff --git a/drivers/net/wireless/ath/wil6210/ioctl.c b/drivers/net/wireless/ath/wil6210/ioctl.c
index f8d2c20..25bc439 100644
--- a/drivers/net/wireless/ath/wil6210/ioctl.c
+++ b/drivers/net/wireless/ath/wil6210/ioctl.c
@@ -221,6 +221,10 @@
{
int ret;
+ ret = wil_pm_runtime_get(wil);
+ if (ret < 0)
+ return ret;
+
switch (cmd) {
case WIL_IOCTL_MEMIO:
ret = wil_ioc_memio_dword(wil, data);
@@ -233,9 +237,12 @@
break;
default:
wil_dbg_ioctl(wil, "Unsupported IOCTL 0x%04x\n", cmd);
+ wil_pm_runtime_put(wil);
return -ENOIOCTLCMD;
}
+ wil_pm_runtime_put(wil);
+
wil_dbg_ioctl(wil, "ioctl(0x%04x) -> %d\n", cmd, ret);
return ret;
}
diff --git a/drivers/net/wireless/ath/wil6210/netdev.c b/drivers/net/wireless/ath/wil6210/netdev.c
index d80e7f4..40cd32a 100644
--- a/drivers/net/wireless/ath/wil6210/netdev.c
+++ b/drivers/net/wireless/ath/wil6210/netdev.c
@@ -26,6 +26,7 @@
static int wil_open(struct net_device *ndev)
{
struct wil6210_priv *wil = ndev_to_wil(ndev);
+ int rc;
wil_dbg_misc(wil, "open\n");
@@ -35,16 +36,29 @@
return -EINVAL;
}
- return wil_up(wil);
+ rc = wil_pm_runtime_get(wil);
+ if (rc < 0)
+ return rc;
+
+ rc = wil_up(wil);
+ if (rc)
+ wil_pm_runtime_put(wil);
+
+ return rc;
}
static int wil_stop(struct net_device *ndev)
{
struct wil6210_priv *wil = ndev_to_wil(ndev);
+ int rc;
wil_dbg_misc(wil, "stop\n");
- return wil_down(wil);
+ rc = wil_down(wil);
+ if (!rc)
+ wil_pm_runtime_put(wil);
+
+ return rc;
}
static int wil_change_mtu(struct net_device *ndev, int new_mtu)
diff --git a/drivers/net/wireless/ath/wil6210/pcie_bus.c b/drivers/net/wireless/ath/wil6210/pcie_bus.c
index 5432b31..663e163 100644
--- a/drivers/net/wireless/ath/wil6210/pcie_bus.c
+++ b/drivers/net/wireless/ath/wil6210/pcie_bus.c
@@ -21,6 +21,7 @@
#include <linux/suspend.h>
#include "wil6210.h"
#include <linux/rtnetlink.h>
+#include <linux/pm_runtime.h>
static bool use_msi = true;
module_param(use_msi, bool, 0444);
@@ -316,6 +317,8 @@
wil6210_debugfs_init(wil);
wil6210_sysfs_init(wil);
+ wil_pm_runtime_allow(wil);
+
return 0;
bus_disable:
@@ -348,6 +351,8 @@
#endif /* CONFIG_PM_SLEEP */
#endif /* CONFIG_PM */
+ wil_pm_runtime_forbid(wil);
+
wil6210_sysfs_remove(wil);
wil6210_debugfs_remove(wil);
rtnl_lock();
@@ -477,10 +482,40 @@
}
#endif /* CONFIG_PM_SLEEP */
+static int wil6210_pm_runtime_idle(struct device *dev)
+{
+ struct pci_dev *pdev = to_pci_dev(dev);
+ struct wil6210_priv *wil = pci_get_drvdata(pdev);
+
+ wil_dbg_pm(wil, "Runtime idle\n");
+
+ return wil_can_suspend(wil, true);
+}
+
+static int wil6210_pm_runtime_resume(struct device *dev)
+{
+ return wil6210_resume(dev, true);
+}
+
+static int wil6210_pm_runtime_suspend(struct device *dev)
+{
+ struct pci_dev *pdev = to_pci_dev(dev);
+ struct wil6210_priv *wil = pci_get_drvdata(pdev);
+
+ if (test_bit(wil_status_suspended, wil->status)) {
+ wil_dbg_pm(wil, "trying to suspend while suspended\n");
+ return 1;
+ }
+
+ return wil6210_suspend(dev, true);
+}
#endif /* CONFIG_PM */
static const struct dev_pm_ops wil6210_pm_ops = {
SET_SYSTEM_SLEEP_PM_OPS(wil6210_pm_suspend, wil6210_pm_resume)
+ SET_RUNTIME_PM_OPS(wil6210_pm_runtime_suspend,
+ wil6210_pm_runtime_resume,
+ wil6210_pm_runtime_idle)
};
static struct pci_driver wil6210_driver = {
diff --git a/drivers/net/wireless/ath/wil6210/pm.c b/drivers/net/wireless/ath/wil6210/pm.c
index 8f5d1b44..2ef2f34 100644
--- a/drivers/net/wireless/ath/wil6210/pm.c
+++ b/drivers/net/wireless/ath/wil6210/pm.c
@@ -16,15 +16,26 @@
#include "wil6210.h"
#include <linux/jiffies.h>
+#include <linux/pm_runtime.h>
+
+#define WIL6210_AUTOSUSPEND_DELAY_MS (1000)
int wil_can_suspend(struct wil6210_priv *wil, bool is_runtime)
{
int rc = 0;
struct wireless_dev *wdev = wil->wdev;
struct net_device *ndev = wil_to_ndev(wil);
+ bool wmi_only = test_bit(WMI_FW_CAPABILITY_WMI_ONLY,
+ wil->fw_capabilities);
wil_dbg_pm(wil, "can_suspend: %s\n", is_runtime ? "runtime" : "system");
+ if (wmi_only || debug_fw) {
+ wil_dbg_pm(wil, "Deny any suspend - %s mode\n",
+ wmi_only ? "wmi_only" : "debug_fw");
+ rc = -EPERM;
+ goto out;
+ }
if (!(ndev->flags & IFF_UP)) {
/* can always sleep when down */
wil_dbg_pm(wil, "Interface is down\n");
@@ -44,6 +55,10 @@
/* interface is running */
switch (wdev->iftype) {
case NL80211_IFTYPE_MONITOR:
+ wil_dbg_pm(wil, "Sniffer\n");
+ rc = -EBUSY;
+ goto out;
+ /* for STA-like interface, don't runtime suspend */
case NL80211_IFTYPE_STATION:
case NL80211_IFTYPE_P2P_CLIENT:
if (test_bit(wil_status_fwconnecting, wil->status)) {
@@ -51,6 +66,12 @@
rc = -EBUSY;
goto out;
}
+ /* Runtime pm not supported in case the interface is up */
+ if (is_runtime) {
+ wil_dbg_pm(wil, "STA-like interface\n");
+ rc = -EBUSY;
+ goto out;
+ }
break;
/* AP-like interface - can't suspend */
default:
@@ -348,3 +369,44 @@
is_runtime ? "runtime" : "system", rc, suspend_time_usec);
return rc;
}
+
+void wil_pm_runtime_allow(struct wil6210_priv *wil)
+{
+ struct device *dev = wil_to_dev(wil);
+
+ pm_runtime_put_noidle(dev);
+ pm_runtime_set_autosuspend_delay(dev, WIL6210_AUTOSUSPEND_DELAY_MS);
+ pm_runtime_use_autosuspend(dev);
+ pm_runtime_allow(dev);
+}
+
+void wil_pm_runtime_forbid(struct wil6210_priv *wil)
+{
+ struct device *dev = wil_to_dev(wil);
+
+ pm_runtime_forbid(dev);
+ pm_runtime_get_noresume(dev);
+}
+
+int wil_pm_runtime_get(struct wil6210_priv *wil)
+{
+ int rc;
+ struct device *dev = wil_to_dev(wil);
+
+ rc = pm_runtime_get_sync(dev);
+ if (rc < 0) {
+ wil_err(wil, "pm_runtime_get_sync() failed, rc = %d\n", rc);
+ pm_runtime_put_noidle(dev);
+ return rc;
+ }
+
+ return 0;
+}
+
+void wil_pm_runtime_put(struct wil6210_priv *wil)
+{
+ struct device *dev = wil_to_dev(wil);
+
+ pm_runtime_mark_last_busy(dev);
+ pm_runtime_put_autosuspend(dev);
+}
diff --git a/drivers/net/wireless/ath/wil6210/wil6210.h b/drivers/net/wireless/ath/wil6210/wil6210.h
index 1c13b0b..8616f86 100644
--- a/drivers/net/wireless/ath/wil6210/wil6210.h
+++ b/drivers/net/wireless/ath/wil6210/wil6210.h
@@ -621,6 +621,16 @@
u32 off_ms;
};
+struct wil_debugfs_iomem_data {
+ void *offset;
+ struct wil6210_priv *wil;
+};
+
+struct wil_debugfs_data {
+ struct wil_debugfs_iomem_data *data_arr;
+ int iomem_data_count;
+};
+
extern struct blink_on_off_time led_blink_time[WIL_LED_TIME_LAST];
extern u8 led_id;
extern u8 led_polarity;
@@ -713,6 +723,7 @@
u8 abft_len;
u8 wakeup_trigger;
struct wil_suspend_stats suspend_stats;
+ struct wil_debugfs_data dbg_data;
void *platform_handle;
struct wil_platform_ops platform_ops;
@@ -1015,6 +1026,11 @@
bool load);
bool wil_fw_verify_file_exists(struct wil6210_priv *wil, const char *name);
+void wil_pm_runtime_allow(struct wil6210_priv *wil);
+void wil_pm_runtime_forbid(struct wil6210_priv *wil);
+int wil_pm_runtime_get(struct wil6210_priv *wil);
+void wil_pm_runtime_put(struct wil6210_priv *wil);
+
int wil_can_suspend(struct wil6210_priv *wil, bool is_runtime);
int wil_suspend(struct wil6210_priv *wil, bool is_runtime);
int wil_resume(struct wil6210_priv *wil, bool is_runtime);
diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/drv.c b/drivers/net/wireless/intel/iwlwifi/pcie/drv.c
index 2f8134b..177fd5b 100644
--- a/drivers/net/wireless/intel/iwlwifi/pcie/drv.c
+++ b/drivers/net/wireless/intel/iwlwifi/pcie/drv.c
@@ -429,6 +429,7 @@
{IWL_PCI_DEVICE(0x095B, 0x520A, iwl7265_2ac_cfg)},
{IWL_PCI_DEVICE(0x095A, 0x9000, iwl7265_2ac_cfg)},
{IWL_PCI_DEVICE(0x095A, 0x9400, iwl7265_2ac_cfg)},
+ {IWL_PCI_DEVICE(0x095A, 0x9E10, iwl7265_2ac_cfg)},
/* 8000 Series */
{IWL_PCI_DEVICE(0x24F3, 0x0010, iwl8260_2ac_cfg)},
diff --git a/drivers/net/wireless/marvell/mwifiex/cfg80211.c b/drivers/net/wireless/marvell/mwifiex/cfg80211.c
index afdbbf5..8677a53 100644
--- a/drivers/net/wireless/marvell/mwifiex/cfg80211.c
+++ b/drivers/net/wireless/marvell/mwifiex/cfg80211.c
@@ -4188,7 +4188,7 @@
if (adapter->config_bands & BAND_A)
n_channels_a = mwifiex_band_5ghz.n_channels;
- adapter->num_in_chan_stats = max_t(u32, n_channels_bg, n_channels_a);
+ adapter->num_in_chan_stats = n_channels_bg + n_channels_a;
adapter->chan_stats = vmalloc(sizeof(*adapter->chan_stats) *
adapter->num_in_chan_stats);
diff --git a/drivers/net/wireless/marvell/mwifiex/scan.c b/drivers/net/wireless/marvell/mwifiex/scan.c
index 97c9765..78d59a6 100644
--- a/drivers/net/wireless/marvell/mwifiex/scan.c
+++ b/drivers/net/wireless/marvell/mwifiex/scan.c
@@ -2479,6 +2479,12 @@
sizeof(struct mwifiex_chan_stats);
for (i = 0 ; i < num_chan; i++) {
+ if (adapter->survey_idx >= adapter->num_in_chan_stats) {
+ mwifiex_dbg(adapter, WARN,
+ "FW reported too many channel results (max %d)\n",
+ adapter->num_in_chan_stats);
+ return;
+ }
chan_stats.chan_num = fw_chan_stats->chan_num;
chan_stats.bandcfg = fw_chan_stats->bandcfg;
chan_stats.flags = fw_chan_stats->flags;
diff --git a/drivers/net/wireless/realtek/rtlwifi/pci.c b/drivers/net/wireless/realtek/rtlwifi/pci.c
index 5be4fc9..75ffeaa 100644
--- a/drivers/net/wireless/realtek/rtlwifi/pci.c
+++ b/drivers/net/wireless/realtek/rtlwifi/pci.c
@@ -2269,7 +2269,7 @@
/* find adapter */
if (!_rtl_pci_find_adapter(pdev, hw)) {
err = -ENODEV;
- goto fail3;
+ goto fail2;
}
/* Init IO handler */
@@ -2339,10 +2339,10 @@
pci_set_drvdata(pdev, NULL);
rtl_deinit_core(hw);
+fail2:
if (rtlpriv->io.pci_mem_start != 0)
pci_iounmap(pdev, (void __iomem *)rtlpriv->io.pci_mem_start);
-fail2:
pci_release_regions(pdev);
complete(&rtlpriv->firmware_loading_complete);
diff --git a/drivers/nvme/host/fabrics.c b/drivers/nvme/host/fabrics.c
index 5a3f008..eef1a68 100644
--- a/drivers/nvme/host/fabrics.c
+++ b/drivers/nvme/host/fabrics.c
@@ -77,7 +77,7 @@
kref_init(&host->ref);
uuid_be_gen(&host->id);
snprintf(host->nqn, NVMF_NQN_SIZE,
- "nqn.2014-08.org.nvmexpress:NVMf:uuid:%pUb", &host->id);
+ "nqn.2014-08.org.nvmexpress:uuid:%pUb", &host->id);
mutex_lock(&nvmf_hosts_mutex);
list_add_tail(&host->list, &nvmf_hosts);
diff --git a/drivers/pinctrl/qcom/Kconfig b/drivers/pinctrl/qcom/Kconfig
index 8da8571..d39a17f 100644
--- a/drivers/pinctrl/qcom/Kconfig
+++ b/drivers/pinctrl/qcom/Kconfig
@@ -79,6 +79,16 @@
This is the pinctrl, pinmux, pinconf and gpiolib driver for the
Qualcomm TLMM block found on the Qualcomm 8916 platform.
+config PINCTRL_MSM8953
+ tristate "Qualcomm Technologies Inc MSM8953 pin controller driver"
+ depends on GPIOLIB && OF
+ select PINCTRL_MSM
+ help
+ This is the pinctrl, pinmux, pinconf and gpiolib driver for the
+ Qualcomm Technologies Inc TLMM block found on the Qualcomm
+ Technologies Inc MSM8953 platform.
+ If unsure say N.
+
config PINCTRL_SDM845
tristate "Qualcomm Technologies Inc SDM845 pin controller driver"
depends on GPIOLIB && OF
diff --git a/drivers/pinctrl/qcom/Makefile b/drivers/pinctrl/qcom/Makefile
index 392ed2a..c9f5c11 100644
--- a/drivers/pinctrl/qcom/Makefile
+++ b/drivers/pinctrl/qcom/Makefile
@@ -11,6 +11,7 @@
obj-$(CONFIG_PINCTRL_MSM8996) += pinctrl-msm8996.o
obj-$(CONFIG_PINCTRL_QDF2XXX) += pinctrl-qdf2xxx.o
obj-$(CONFIG_PINCTRL_MDM9615) += pinctrl-mdm9615.o
+obj-$(CONFIG_PINCTRL_MSM8953) += pinctrl-msm8953.o
obj-$(CONFIG_PINCTRL_QCOM_SPMI_PMIC) += pinctrl-spmi-gpio.o
obj-$(CONFIG_PINCTRL_QCOM_SPMI_PMIC) += pinctrl-spmi-mpp.o
obj-$(CONFIG_PINCTRL_QCOM_SSBI_PMIC) += pinctrl-ssbi-gpio.o
diff --git a/drivers/pinctrl/qcom/pinctrl-msm8953.c b/drivers/pinctrl/qcom/pinctrl-msm8953.c
new file mode 100644
index 0000000..ba1cad0
--- /dev/null
+++ b/drivers/pinctrl/qcom/pinctrl-msm8953.c
@@ -0,0 +1,1686 @@
+/*
+ * Copyright (c) 2015-2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/pinctrl/pinctrl.h>
+
+#include "pinctrl-msm.h"
+
+#define FUNCTION(fname) \
+ [msm_mux_##fname] = { \
+ .name = #fname, \
+ .groups = fname##_groups, \
+ .ngroups = ARRAY_SIZE(fname##_groups), \
+ }
+
+#define REG_SIZE 0x1000
+#define PINGROUP(id, f1, f2, f3, f4, f5, f6, f7, f8, f9) \
+ { \
+ .name = "gpio" #id, \
+ .pins = gpio##id##_pins, \
+ .npins = (unsigned int)ARRAY_SIZE(gpio##id##_pins), \
+ .funcs = (int[]){ \
+ msm_mux_gpio, /* gpio mode */ \
+ msm_mux_##f1, \
+ msm_mux_##f2, \
+ msm_mux_##f3, \
+ msm_mux_##f4, \
+ msm_mux_##f5, \
+ msm_mux_##f6, \
+ msm_mux_##f7, \
+ msm_mux_##f8, \
+ msm_mux_##f9 \
+ }, \
+ .nfuncs = 10, \
+ .ctl_reg = REG_SIZE * id, \
+ .io_reg = 0x4 + REG_SIZE * id, \
+ .intr_cfg_reg = 0x8 + REG_SIZE * id, \
+ .intr_status_reg = 0xc + REG_SIZE * id, \
+ .intr_target_reg = 0x8 + REG_SIZE * id, \
+ .mux_bit = 2, \
+ .pull_bit = 0, \
+ .drv_bit = 6, \
+ .oe_bit = 9, \
+ .in_bit = 0, \
+ .out_bit = 1, \
+ .intr_enable_bit = 0, \
+ .intr_status_bit = 0, \
+ .intr_target_bit = 5, \
+ .intr_target_kpss_val = 4, \
+ .intr_raw_status_bit = 4, \
+ .intr_polarity_bit = 1, \
+ .intr_detection_bit = 2, \
+ .intr_detection_width = 2, \
+ }
+
+#define SDC_QDSD_PINGROUP(pg_name, ctl, pull, drv) \
+ { \
+ .name = #pg_name, \
+ .pins = pg_name##_pins, \
+ .npins = (unsigned int)ARRAY_SIZE(pg_name##_pins), \
+ .ctl_reg = ctl, \
+ .io_reg = 0, \
+ .intr_cfg_reg = 0, \
+ .intr_status_reg = 0, \
+ .intr_target_reg = 0, \
+ .mux_bit = -1, \
+ .pull_bit = pull, \
+ .drv_bit = drv, \
+ .oe_bit = -1, \
+ .in_bit = -1, \
+ .out_bit = -1, \
+ .intr_enable_bit = -1, \
+ .intr_status_bit = -1, \
+ .intr_target_bit = -1, \
+ .intr_raw_status_bit = -1, \
+ .intr_polarity_bit = -1, \
+ .intr_detection_bit = -1, \
+ .intr_detection_width = -1, \
+ }
+static const struct pinctrl_pin_desc msm8953_pins[] = {
+ PINCTRL_PIN(0, "GPIO_0"),
+ PINCTRL_PIN(1, "GPIO_1"),
+ PINCTRL_PIN(2, "GPIO_2"),
+ PINCTRL_PIN(3, "GPIO_3"),
+ PINCTRL_PIN(4, "GPIO_4"),
+ PINCTRL_PIN(5, "GPIO_5"),
+ PINCTRL_PIN(6, "GPIO_6"),
+ PINCTRL_PIN(7, "GPIO_7"),
+ PINCTRL_PIN(8, "GPIO_8"),
+ PINCTRL_PIN(9, "GPIO_9"),
+ PINCTRL_PIN(10, "GPIO_10"),
+ PINCTRL_PIN(11, "GPIO_11"),
+ PINCTRL_PIN(12, "GPIO_12"),
+ PINCTRL_PIN(13, "GPIO_13"),
+ PINCTRL_PIN(14, "GPIO_14"),
+ PINCTRL_PIN(15, "GPIO_15"),
+ PINCTRL_PIN(16, "GPIO_16"),
+ PINCTRL_PIN(17, "GPIO_17"),
+ PINCTRL_PIN(18, "GPIO_18"),
+ PINCTRL_PIN(19, "GPIO_19"),
+ PINCTRL_PIN(20, "GPIO_20"),
+ PINCTRL_PIN(21, "GPIO_21"),
+ PINCTRL_PIN(22, "GPIO_22"),
+ PINCTRL_PIN(23, "GPIO_23"),
+ PINCTRL_PIN(24, "GPIO_24"),
+ PINCTRL_PIN(25, "GPIO_25"),
+ PINCTRL_PIN(26, "GPIO_26"),
+ PINCTRL_PIN(27, "GPIO_27"),
+ PINCTRL_PIN(28, "GPIO_28"),
+ PINCTRL_PIN(29, "GPIO_29"),
+ PINCTRL_PIN(30, "GPIO_30"),
+ PINCTRL_PIN(31, "GPIO_31"),
+ PINCTRL_PIN(32, "GPIO_32"),
+ PINCTRL_PIN(33, "GPIO_33"),
+ PINCTRL_PIN(34, "GPIO_34"),
+ PINCTRL_PIN(35, "GPIO_35"),
+ PINCTRL_PIN(36, "GPIO_36"),
+ PINCTRL_PIN(37, "GPIO_37"),
+ PINCTRL_PIN(38, "GPIO_38"),
+ PINCTRL_PIN(39, "GPIO_39"),
+ PINCTRL_PIN(40, "GPIO_40"),
+ PINCTRL_PIN(41, "GPIO_41"),
+ PINCTRL_PIN(42, "GPIO_42"),
+ PINCTRL_PIN(43, "GPIO_43"),
+ PINCTRL_PIN(44, "GPIO_44"),
+ PINCTRL_PIN(45, "GPIO_45"),
+ PINCTRL_PIN(46, "GPIO_46"),
+ PINCTRL_PIN(47, "GPIO_47"),
+ PINCTRL_PIN(48, "GPIO_48"),
+ PINCTRL_PIN(49, "GPIO_49"),
+ PINCTRL_PIN(50, "GPIO_50"),
+ PINCTRL_PIN(51, "GPIO_51"),
+ PINCTRL_PIN(52, "GPIO_52"),
+ PINCTRL_PIN(53, "GPIO_53"),
+ PINCTRL_PIN(54, "GPIO_54"),
+ PINCTRL_PIN(55, "GPIO_55"),
+ PINCTRL_PIN(56, "GPIO_56"),
+ PINCTRL_PIN(57, "GPIO_57"),
+ PINCTRL_PIN(58, "GPIO_58"),
+ PINCTRL_PIN(59, "GPIO_59"),
+ PINCTRL_PIN(60, "GPIO_60"),
+ PINCTRL_PIN(61, "GPIO_61"),
+ PINCTRL_PIN(62, "GPIO_62"),
+ PINCTRL_PIN(63, "GPIO_63"),
+ PINCTRL_PIN(64, "GPIO_64"),
+ PINCTRL_PIN(65, "GPIO_65"),
+ PINCTRL_PIN(66, "GPIO_66"),
+ PINCTRL_PIN(67, "GPIO_67"),
+ PINCTRL_PIN(68, "GPIO_68"),
+ PINCTRL_PIN(69, "GPIO_69"),
+ PINCTRL_PIN(70, "GPIO_70"),
+ PINCTRL_PIN(71, "GPIO_71"),
+ PINCTRL_PIN(72, "GPIO_72"),
+ PINCTRL_PIN(73, "GPIO_73"),
+ PINCTRL_PIN(74, "GPIO_74"),
+ PINCTRL_PIN(75, "GPIO_75"),
+ PINCTRL_PIN(76, "GPIO_76"),
+ PINCTRL_PIN(77, "GPIO_77"),
+ PINCTRL_PIN(78, "GPIO_78"),
+ PINCTRL_PIN(79, "GPIO_79"),
+ PINCTRL_PIN(80, "GPIO_80"),
+ PINCTRL_PIN(81, "GPIO_81"),
+ PINCTRL_PIN(82, "GPIO_82"),
+ PINCTRL_PIN(83, "GPIO_83"),
+ PINCTRL_PIN(84, "GPIO_84"),
+ PINCTRL_PIN(85, "GPIO_85"),
+ PINCTRL_PIN(86, "GPIO_86"),
+ PINCTRL_PIN(87, "GPIO_87"),
+ PINCTRL_PIN(88, "GPIO_88"),
+ PINCTRL_PIN(89, "GPIO_89"),
+ PINCTRL_PIN(90, "GPIO_90"),
+ PINCTRL_PIN(91, "GPIO_91"),
+ PINCTRL_PIN(92, "GPIO_92"),
+ PINCTRL_PIN(93, "GPIO_93"),
+ PINCTRL_PIN(94, "GPIO_94"),
+ PINCTRL_PIN(95, "GPIO_95"),
+ PINCTRL_PIN(96, "GPIO_96"),
+ PINCTRL_PIN(97, "GPIO_97"),
+ PINCTRL_PIN(98, "GPIO_98"),
+ PINCTRL_PIN(99, "GPIO_99"),
+ PINCTRL_PIN(100, "GPIO_100"),
+ PINCTRL_PIN(101, "GPIO_101"),
+ PINCTRL_PIN(102, "GPIO_102"),
+ PINCTRL_PIN(103, "GPIO_103"),
+ PINCTRL_PIN(104, "GPIO_104"),
+ PINCTRL_PIN(105, "GPIO_105"),
+ PINCTRL_PIN(106, "GPIO_106"),
+ PINCTRL_PIN(107, "GPIO_107"),
+ PINCTRL_PIN(108, "GPIO_108"),
+ PINCTRL_PIN(109, "GPIO_109"),
+ PINCTRL_PIN(110, "GPIO_110"),
+ PINCTRL_PIN(111, "GPIO_111"),
+ PINCTRL_PIN(112, "GPIO_112"),
+ PINCTRL_PIN(113, "GPIO_113"),
+ PINCTRL_PIN(114, "GPIO_114"),
+ PINCTRL_PIN(115, "GPIO_115"),
+ PINCTRL_PIN(116, "GPIO_116"),
+ PINCTRL_PIN(117, "GPIO_117"),
+ PINCTRL_PIN(118, "GPIO_118"),
+ PINCTRL_PIN(119, "GPIO_119"),
+ PINCTRL_PIN(120, "GPIO_120"),
+ PINCTRL_PIN(121, "GPIO_121"),
+ PINCTRL_PIN(122, "GPIO_122"),
+ PINCTRL_PIN(123, "GPIO_123"),
+ PINCTRL_PIN(124, "GPIO_124"),
+ PINCTRL_PIN(125, "GPIO_125"),
+ PINCTRL_PIN(126, "GPIO_126"),
+ PINCTRL_PIN(127, "GPIO_127"),
+ PINCTRL_PIN(128, "GPIO_128"),
+ PINCTRL_PIN(129, "GPIO_129"),
+ PINCTRL_PIN(130, "GPIO_130"),
+ PINCTRL_PIN(131, "GPIO_131"),
+ PINCTRL_PIN(132, "GPIO_132"),
+ PINCTRL_PIN(133, "GPIO_133"),
+ PINCTRL_PIN(134, "GPIO_134"),
+ PINCTRL_PIN(135, "GPIO_135"),
+ PINCTRL_PIN(136, "GPIO_136"),
+ PINCTRL_PIN(137, "GPIO_137"),
+ PINCTRL_PIN(138, "GPIO_138"),
+ PINCTRL_PIN(139, "GPIO_139"),
+ PINCTRL_PIN(140, "GPIO_140"),
+ PINCTRL_PIN(141, "GPIO_141"),
+ PINCTRL_PIN(142, "SDC1_CLK"),
+ PINCTRL_PIN(143, "SDC1_CMD"),
+ PINCTRL_PIN(144, "SDC1_DATA"),
+ PINCTRL_PIN(145, "SDC1_RCLK"),
+ PINCTRL_PIN(146, "SDC2_CLK"),
+ PINCTRL_PIN(147, "SDC2_CMD"),
+ PINCTRL_PIN(148, "SDC2_DATA"),
+ PINCTRL_PIN(149, "QDSD_CLK"),
+ PINCTRL_PIN(150, "QDSD_CMD"),
+ PINCTRL_PIN(151, "QDSD_DATA0"),
+ PINCTRL_PIN(152, "QDSD_DATA1"),
+ PINCTRL_PIN(153, "QDSD_DATA2"),
+ PINCTRL_PIN(154, "QDSD_DATA3"),
+};
+
+#define DECLARE_MSM_GPIO_PINS(pin) \
+ static const unsigned int gpio##pin##_pins[] = { pin }
+DECLARE_MSM_GPIO_PINS(0);
+DECLARE_MSM_GPIO_PINS(1);
+DECLARE_MSM_GPIO_PINS(2);
+DECLARE_MSM_GPIO_PINS(3);
+DECLARE_MSM_GPIO_PINS(4);
+DECLARE_MSM_GPIO_PINS(5);
+DECLARE_MSM_GPIO_PINS(6);
+DECLARE_MSM_GPIO_PINS(7);
+DECLARE_MSM_GPIO_PINS(8);
+DECLARE_MSM_GPIO_PINS(9);
+DECLARE_MSM_GPIO_PINS(10);
+DECLARE_MSM_GPIO_PINS(11);
+DECLARE_MSM_GPIO_PINS(12);
+DECLARE_MSM_GPIO_PINS(13);
+DECLARE_MSM_GPIO_PINS(14);
+DECLARE_MSM_GPIO_PINS(15);
+DECLARE_MSM_GPIO_PINS(16);
+DECLARE_MSM_GPIO_PINS(17);
+DECLARE_MSM_GPIO_PINS(18);
+DECLARE_MSM_GPIO_PINS(19);
+DECLARE_MSM_GPIO_PINS(20);
+DECLARE_MSM_GPIO_PINS(21);
+DECLARE_MSM_GPIO_PINS(22);
+DECLARE_MSM_GPIO_PINS(23);
+DECLARE_MSM_GPIO_PINS(24);
+DECLARE_MSM_GPIO_PINS(25);
+DECLARE_MSM_GPIO_PINS(26);
+DECLARE_MSM_GPIO_PINS(27);
+DECLARE_MSM_GPIO_PINS(28);
+DECLARE_MSM_GPIO_PINS(29);
+DECLARE_MSM_GPIO_PINS(30);
+DECLARE_MSM_GPIO_PINS(31);
+DECLARE_MSM_GPIO_PINS(32);
+DECLARE_MSM_GPIO_PINS(33);
+DECLARE_MSM_GPIO_PINS(34);
+DECLARE_MSM_GPIO_PINS(35);
+DECLARE_MSM_GPIO_PINS(36);
+DECLARE_MSM_GPIO_PINS(37);
+DECLARE_MSM_GPIO_PINS(38);
+DECLARE_MSM_GPIO_PINS(39);
+DECLARE_MSM_GPIO_PINS(40);
+DECLARE_MSM_GPIO_PINS(41);
+DECLARE_MSM_GPIO_PINS(42);
+DECLARE_MSM_GPIO_PINS(43);
+DECLARE_MSM_GPIO_PINS(44);
+DECLARE_MSM_GPIO_PINS(45);
+DECLARE_MSM_GPIO_PINS(46);
+DECLARE_MSM_GPIO_PINS(47);
+DECLARE_MSM_GPIO_PINS(48);
+DECLARE_MSM_GPIO_PINS(49);
+DECLARE_MSM_GPIO_PINS(50);
+DECLARE_MSM_GPIO_PINS(51);
+DECLARE_MSM_GPIO_PINS(52);
+DECLARE_MSM_GPIO_PINS(53);
+DECLARE_MSM_GPIO_PINS(54);
+DECLARE_MSM_GPIO_PINS(55);
+DECLARE_MSM_GPIO_PINS(56);
+DECLARE_MSM_GPIO_PINS(57);
+DECLARE_MSM_GPIO_PINS(58);
+DECLARE_MSM_GPIO_PINS(59);
+DECLARE_MSM_GPIO_PINS(60);
+DECLARE_MSM_GPIO_PINS(61);
+DECLARE_MSM_GPIO_PINS(62);
+DECLARE_MSM_GPIO_PINS(63);
+DECLARE_MSM_GPIO_PINS(64);
+DECLARE_MSM_GPIO_PINS(65);
+DECLARE_MSM_GPIO_PINS(66);
+DECLARE_MSM_GPIO_PINS(67);
+DECLARE_MSM_GPIO_PINS(68);
+DECLARE_MSM_GPIO_PINS(69);
+DECLARE_MSM_GPIO_PINS(70);
+DECLARE_MSM_GPIO_PINS(71);
+DECLARE_MSM_GPIO_PINS(72);
+DECLARE_MSM_GPIO_PINS(73);
+DECLARE_MSM_GPIO_PINS(74);
+DECLARE_MSM_GPIO_PINS(75);
+DECLARE_MSM_GPIO_PINS(76);
+DECLARE_MSM_GPIO_PINS(77);
+DECLARE_MSM_GPIO_PINS(78);
+DECLARE_MSM_GPIO_PINS(79);
+DECLARE_MSM_GPIO_PINS(80);
+DECLARE_MSM_GPIO_PINS(81);
+DECLARE_MSM_GPIO_PINS(82);
+DECLARE_MSM_GPIO_PINS(83);
+DECLARE_MSM_GPIO_PINS(84);
+DECLARE_MSM_GPIO_PINS(85);
+DECLARE_MSM_GPIO_PINS(86);
+DECLARE_MSM_GPIO_PINS(87);
+DECLARE_MSM_GPIO_PINS(88);
+DECLARE_MSM_GPIO_PINS(89);
+DECLARE_MSM_GPIO_PINS(90);
+DECLARE_MSM_GPIO_PINS(91);
+DECLARE_MSM_GPIO_PINS(92);
+DECLARE_MSM_GPIO_PINS(93);
+DECLARE_MSM_GPIO_PINS(94);
+DECLARE_MSM_GPIO_PINS(95);
+DECLARE_MSM_GPIO_PINS(96);
+DECLARE_MSM_GPIO_PINS(97);
+DECLARE_MSM_GPIO_PINS(98);
+DECLARE_MSM_GPIO_PINS(99);
+DECLARE_MSM_GPIO_PINS(100);
+DECLARE_MSM_GPIO_PINS(101);
+DECLARE_MSM_GPIO_PINS(102);
+DECLARE_MSM_GPIO_PINS(103);
+DECLARE_MSM_GPIO_PINS(104);
+DECLARE_MSM_GPIO_PINS(105);
+DECLARE_MSM_GPIO_PINS(106);
+DECLARE_MSM_GPIO_PINS(107);
+DECLARE_MSM_GPIO_PINS(108);
+DECLARE_MSM_GPIO_PINS(109);
+DECLARE_MSM_GPIO_PINS(110);
+DECLARE_MSM_GPIO_PINS(111);
+DECLARE_MSM_GPIO_PINS(112);
+DECLARE_MSM_GPIO_PINS(113);
+DECLARE_MSM_GPIO_PINS(114);
+DECLARE_MSM_GPIO_PINS(115);
+DECLARE_MSM_GPIO_PINS(116);
+DECLARE_MSM_GPIO_PINS(117);
+DECLARE_MSM_GPIO_PINS(118);
+DECLARE_MSM_GPIO_PINS(119);
+DECLARE_MSM_GPIO_PINS(120);
+DECLARE_MSM_GPIO_PINS(121);
+DECLARE_MSM_GPIO_PINS(122);
+DECLARE_MSM_GPIO_PINS(123);
+DECLARE_MSM_GPIO_PINS(124);
+DECLARE_MSM_GPIO_PINS(125);
+DECLARE_MSM_GPIO_PINS(126);
+DECLARE_MSM_GPIO_PINS(127);
+DECLARE_MSM_GPIO_PINS(128);
+DECLARE_MSM_GPIO_PINS(129);
+DECLARE_MSM_GPIO_PINS(130);
+DECLARE_MSM_GPIO_PINS(131);
+DECLARE_MSM_GPIO_PINS(132);
+DECLARE_MSM_GPIO_PINS(133);
+DECLARE_MSM_GPIO_PINS(134);
+DECLARE_MSM_GPIO_PINS(135);
+DECLARE_MSM_GPIO_PINS(136);
+DECLARE_MSM_GPIO_PINS(137);
+DECLARE_MSM_GPIO_PINS(138);
+DECLARE_MSM_GPIO_PINS(139);
+DECLARE_MSM_GPIO_PINS(140);
+DECLARE_MSM_GPIO_PINS(141);
+
+static const unsigned int sdc1_clk_pins[] = { 142 };
+static const unsigned int sdc1_cmd_pins[] = { 143 };
+static const unsigned int sdc1_data_pins[] = { 144 };
+static const unsigned int sdc1_rclk_pins[] = { 145 };
+static const unsigned int sdc2_clk_pins[] = { 146 };
+static const unsigned int sdc2_cmd_pins[] = { 147 };
+static const unsigned int sdc2_data_pins[] = { 148 };
+static const unsigned int qdsd_clk_pins[] = { 149 };
+static const unsigned int qdsd_cmd_pins[] = { 150 };
+static const unsigned int qdsd_data0_pins[] = { 151 };
+static const unsigned int qdsd_data1_pins[] = { 152 };
+static const unsigned int qdsd_data2_pins[] = { 153 };
+static const unsigned int qdsd_data3_pins[] = { 154 };
+
+enum msm8953_functions {
+ msm_mux_gpio,
+ msm_mux_blsp_spi1,
+ msm_mux_smb_int,
+ msm_mux_adsp_ext,
+ msm_mux_prng_rosc,
+ msm_mux_blsp_i2c1,
+ msm_mux_qdss_cti_trig_out_b0,
+ msm_mux_qdss_cti_trig_out_a1,
+ msm_mux_blsp_spi2,
+ msm_mux_blsp_uart2,
+ msm_mux_ldo_update,
+ msm_mux_dac_calib0,
+ msm_mux_ldo_en,
+ msm_mux_blsp_i2c2,
+ msm_mux_gcc_gp1_clk_b,
+ msm_mux_atest_gpsadc_dtest0_native,
+ msm_mux_blsp_spi3,
+ msm_mux_qdss_tracedata_b,
+ msm_mux_pwr_modem_enabled_b,
+ msm_mux_blsp_i2c3,
+ msm_mux_gcc_gp2_clk_b,
+ msm_mux_gcc_gp3_clk_b,
+ msm_mux_hall_int,
+ msm_mux_blsp_spi4,
+ msm_mux_blsp_uart4,
+ msm_mux_pwr_nav_enabled_b,
+ msm_mux_dac_calib1,
+ msm_mux_cap_int,
+ msm_mux_pwr_crypto_enabled_b,
+ msm_mux_dac_calib2,
+ msm_mux_blsp_i2c4,
+ msm_mux_nfc_disable,
+ msm_mux_blsp_spi5,
+ msm_mux_blsp_uart5,
+ msm_mux_qdss_traceclk_a,
+ msm_mux_atest_bbrx1,
+ msm_mux_nfc_irq,
+ msm_mux_m_voc,
+ msm_mux_qdss_cti_trig_in_a0,
+ msm_mux_atest_bbrx0,
+ msm_mux_blsp_i2c5,
+ msm_mux_qdss_tracectl_a,
+ msm_mux_atest_gpsadc_dtest1_native,
+ msm_mux_qdss_tracedata_a,
+ msm_mux_blsp_spi6,
+ msm_mux_blsp_uart6,
+ msm_mux_qdss_tracectl_b,
+ msm_mux_dac_calib15,
+ msm_mux_qdss_cti_trig_in_b0,
+ msm_mux_dac_calib16,
+ msm_mux_blsp_i2c6,
+ msm_mux_qdss_traceclk_b,
+ msm_mux_atest_wlan0,
+ msm_mux_atest_wlan1,
+ msm_mux_mdp_vsync,
+ msm_mux_pri_mi2s_mclk_a,
+ msm_mux_sec_mi2s_mclk_a,
+ msm_mux_qdss_cti_trig_out_b1,
+ msm_mux_cam_mclk,
+ msm_mux_dac_calib3,
+ msm_mux_cci_i2c,
+ msm_mux_pwr_modem_enabled_a,
+ msm_mux_dac_calib4,
+ msm_mux_dac_calib19,
+ msm_mux_flash_strobe,
+ msm_mux_cci_timer0,
+ msm_mux_cci_timer1,
+ msm_mux_cam_irq,
+ msm_mux_cci_timer2,
+ msm_mux_blsp1_spi,
+ msm_mux_pwr_nav_enabled_a,
+ msm_mux_ois_sync,
+ msm_mux_cci_timer3,
+ msm_mux_cci_timer4,
+ msm_mux_blsp3_spi,
+ msm_mux_qdss_cti_trig_out_a0,
+ msm_mux_dac_calib7,
+ msm_mux_accel_int,
+ msm_mux_gcc_gp1_clk_a,
+ msm_mux_dac_calib8,
+ msm_mux_alsp_int,
+ msm_mux_gcc_gp2_clk_a,
+ msm_mux_dac_calib9,
+ msm_mux_mag_int,
+ msm_mux_gcc_gp3_clk_a,
+ msm_mux_pwr_crypto_enabled_a,
+ msm_mux_cci_async,
+ msm_mux_cam1_standby,
+ msm_mux_dac_calib5,
+ msm_mux_cam1_rst,
+ msm_mux_dac_calib6,
+ msm_mux_dac_calib10,
+ msm_mux_gyro_int,
+ msm_mux_dac_calib11,
+ msm_mux_pressure_int,
+ msm_mux_dac_calib12,
+ msm_mux_blsp6_spi,
+ msm_mux_dac_calib13,
+ msm_mux_fp_int,
+ msm_mux_qdss_cti_trig_in_b1,
+ msm_mux_dac_calib14,
+ msm_mux_uim_batt,
+ msm_mux_cam0_ldo,
+ msm_mux_sd_write,
+ msm_mux_uim1_data,
+ msm_mux_uim1_clk,
+ msm_mux_uim1_reset,
+ msm_mux_uim1_present,
+ msm_mux_uim2_data,
+ msm_mux_uim2_clk,
+ msm_mux_uim2_reset,
+ msm_mux_uim2_present,
+ msm_mux_ts_xvdd,
+ msm_mux_mipi_dsi0,
+ msm_mux_nfc_dwl,
+ msm_mux_us_euro,
+ msm_mux_atest_char3,
+ msm_mux_dbg_out,
+ msm_mux_bimc_dte0,
+ msm_mux_ts_resout,
+ msm_mux_ts_sample,
+ msm_mux_sec_mi2s_mclk_b,
+ msm_mux_pri_mi2s,
+ msm_mux_codec_reset,
+ msm_mux_cdc_pdm0,
+ msm_mux_atest_char1,
+ msm_mux_ebi_cdc,
+ msm_mux_dac_calib17,
+ msm_mux_us_emitter,
+ msm_mux_atest_char0,
+ msm_mux_pri_mi2s_mclk_b,
+ msm_mux_lpass_slimbus,
+ msm_mux_lpass_slimbus0,
+ msm_mux_lpass_slimbus1,
+ msm_mux_codec_int1,
+ msm_mux_codec_int2,
+ msm_mux_wcss_bt,
+ msm_mux_atest_char2,
+ msm_mux_ebi_ch0,
+ msm_mux_wcss_wlan2,
+ msm_mux_wcss_wlan1,
+ msm_mux_wcss_wlan0,
+ msm_mux_wcss_wlan,
+ msm_mux_wcss_fm,
+ msm_mux_ext_lpass,
+ msm_mux_mss_lte,
+ msm_mux_key_volp,
+ msm_mux_pbs0,
+ msm_mux_cri_trng0,
+ msm_mux_key_snapshot,
+ msm_mux_pbs1,
+ msm_mux_cri_trng1,
+ msm_mux_key_focus,
+ msm_mux_pbs2,
+ msm_mux_cri_trng,
+ msm_mux_gcc_tlmm,
+ msm_mux_key_home,
+ msm_mux_pwr_down,
+ msm_mux_dmic0_clk,
+ msm_mux_blsp7_spi,
+ msm_mux_hdmi_int,
+ msm_mux_dmic0_data,
+ msm_mux_qdss_cti_trig_in_a1,
+ msm_mux_pri_mi2s_ws,
+ msm_mux_wsa_io,
+ msm_mux_wsa_en,
+ msm_mux_blsp_spi8,
+ msm_mux_wsa_irq,
+ msm_mux_blsp_i2c8,
+ msm_mux_gcc_plltest,
+ msm_mux_nav_pps_in_a,
+ msm_mux_pa_indicator,
+ msm_mux_nav_pps_in_b,
+ msm_mux_nav_pps,
+ msm_mux_modem_tsync,
+ msm_mux_nav_tsync,
+ msm_mux_ssbi_wtr1,
+ msm_mux_gsm1_tx,
+ msm_mux_dac_calib18,
+ msm_mux_gsm0_tx,
+ msm_mux_atest_char,
+ msm_mux_atest_tsens,
+ msm_mux_bimc_dte1,
+ msm_mux_dac_calib20,
+ msm_mux_cam2_rst,
+ msm_mux_ddr_bist,
+ msm_mux_dac_calib21,
+ msm_mux_cam2_standby,
+ msm_mux_dac_calib22,
+ msm_mux_cam3_rst,
+ msm_mux_dac_calib23,
+ msm_mux_cam3_standby,
+ msm_mux_dac_calib24,
+ msm_mux_sdcard_det,
+ msm_mux_dac_calib25,
+ msm_mux_cam1_ldo,
+ msm_mux_sec_mi2s,
+ msm_mux_blsp_spi7,
+ msm_mux_blsp_i2c7,
+ msm_mux_ss_switch,
+ msm_mux_tsens_max,
+ msm_mux_NA,
+};
+
+static const char * const gpio_groups[] = {
+ "gpio0", "gpio1", "gpio2", "gpio3", "gpio4", "gpio5", "gpio6", "gpio7",
+ "gpio8", "gpio9", "gpio10", "gpio11", "gpio12", "gpio13", "gpio14",
+ "gpio15", "gpio16", "gpio17", "gpio18", "gpio19", "gpio20", "gpio21",
+ "gpio22", "gpio23", "gpio24", "gpio25", "gpio26", "gpio27", "gpio28",
+ "gpio29", "gpio30", "gpio31", "gpio32", "gpio33", "gpio34", "gpio35",
+ "gpio36", "gpio37", "gpio38", "gpio39", "gpio40", "gpio41", "gpio42",
+ "gpio43", "gpio44", "gpio45", "gpio46", "gpio47", "gpio48", "gpio49",
+ "gpio50", "gpio51", "gpio52", "gpio53", "gpio54", "gpio55", "gpio56",
+ "gpio57", "gpio58", "gpio59", "gpio60", "gpio61", "gpio62", "gpio63",
+ "gpio64", "gpio65", "gpio66", "gpio67", "gpio68", "gpio69", "gpio70",
+ "gpio71", "gpio72", "gpio73", "gpio74", "gpio75", "gpio76", "gpio77",
+ "gpio78", "gpio79", "gpio80", "gpio81", "gpio82", "gpio83", "gpio84",
+ "gpio85", "gpio86", "gpio87", "gpio88", "gpio89", "gpio90", "gpio91",
+ "gpio92", "gpio93", "gpio94", "gpio95", "gpio96", "gpio97", "gpio98",
+ "gpio99", "gpio100", "gpio101", "gpio102", "gpio103", "gpio104",
+ "gpio105", "gpio106", "gpio107", "gpio108", "gpio109", "gpio110",
+ "gpio111", "gpio112", "gpio113", "gpio114", "gpio115", "gpio116",
+ "gpio117", "gpio118", "gpio119", "gpio120", "gpio121", "gpio122",
+ "gpio123", "gpio124", "gpio125", "gpio126", "gpio127", "gpio128",
+ "gpio129", "gpio130", "gpio131", "gpio132", "gpio133", "gpio134",
+ "gpio135", "gpio136", "gpio137", "gpio138", "gpio139", "gpio140",
+ "gpio141",
+};
+static const char * const blsp_spi1_groups[] = {
+ "gpio0", "gpio1", "gpio2", "gpio3",
+};
+static const char * const smb_int_groups[] = {
+ "gpio1",
+};
+static const char * const adsp_ext_groups[] = {
+ "gpio1",
+};
+static const char * const prng_rosc_groups[] = {
+ "gpio2",
+};
+static const char * const blsp_i2c1_groups[] = {
+ "gpio2", "gpio3",
+};
+static const char * const qdss_cti_trig_out_b0_groups[] = {
+ "gpio2",
+};
+static const char * const qdss_cti_trig_out_a1_groups[] = {
+ "gpio3",
+};
+static const char * const blsp_spi2_groups[] = {
+ "gpio4", "gpio5", "gpio6", "gpio7",
+};
+static const char * const blsp_uart2_groups[] = {
+ "gpio4", "gpio5", "gpio6", "gpio7",
+};
+static const char * const ldo_update_groups[] = {
+ "gpio4",
+};
+static const char * const dac_calib0_groups[] = {
+ "gpio4",
+};
+static const char * const ldo_en_groups[] = {
+ "gpio5",
+};
+static const char * const blsp_i2c2_groups[] = {
+ "gpio6", "gpio7",
+};
+static const char * const gcc_gp1_clk_b_groups[] = {
+ "gpio6", "gpio41",
+};
+static const char * const atest_gpsadc_dtest0_native_groups[] = {
+ "gpio7",
+};
+static const char * const blsp_spi3_groups[] = {
+ "gpio8", "gpio9", "gpio10", "gpio11",
+};
+static const char * const qdss_tracedata_b_groups[] = {
+ "gpio8", "gpio9", "gpio12", "gpio13", "gpio23", "gpio42", "gpio43",
+ "gpio44", "gpio45", "gpio46", "gpio47", "gpio66", "gpio86", "gpio87",
+ "gpio88", "gpio92",
+};
+static const char * const pwr_modem_enabled_b_groups[] = {
+ "gpio9",
+};
+static const char * const blsp_i2c3_groups[] = {
+ "gpio10", "gpio11",
+};
+static const char * const gcc_gp2_clk_b_groups[] = {
+ "gpio10",
+};
+static const char * const gcc_gp3_clk_b_groups[] = {
+ "gpio11",
+};
+static const char * const hall_int_groups[] = {
+ "gpio12",
+};
+static const char * const blsp_spi4_groups[] = {
+ "gpio12", "gpio13", "gpio14", "gpio15",
+};
+static const char * const blsp_uart4_groups[] = {
+ "gpio12", "gpio13", "gpio14", "gpio15",
+};
+static const char * const pwr_nav_enabled_b_groups[] = {
+ "gpio12",
+};
+static const char * const dac_calib1_groups[] = {
+ "gpio12",
+};
+static const char * const cap_int_groups[] = {
+ "gpio13",
+};
+static const char * const pwr_crypto_enabled_b_groups[] = {
+ "gpio13",
+};
+static const char * const dac_calib2_groups[] = {
+ "gpio13",
+};
+static const char * const blsp_i2c4_groups[] = {
+ "gpio14", "gpio15",
+};
+static const char * const nfc_disable_groups[] = {
+ "gpio16",
+};
+static const char * const blsp_spi5_groups[] = {
+ "gpio16", "gpio17", "gpio18", "gpio19",
+};
+static const char * const blsp_uart5_groups[] = {
+ "gpio16", "gpio17", "gpio18", "gpio19",
+};
+static const char * const qdss_traceclk_a_groups[] = {
+ "gpio16",
+};
+static const char * const atest_bbrx1_groups[] = {
+ "gpio16",
+};
+static const char * const nfc_irq_groups[] = {
+ "gpio17",
+};
+static const char * const m_voc_groups[] = {
+ "gpio17", "gpio21",
+};
+static const char * const qdss_cti_trig_in_a0_groups[] = {
+ "gpio17",
+};
+static const char * const atest_bbrx0_groups[] = {
+ "gpio17",
+};
+static const char * const blsp_i2c5_groups[] = {
+ "gpio18", "gpio19",
+};
+static const char * const qdss_tracectl_a_groups[] = {
+ "gpio18",
+};
+static const char * const atest_gpsadc_dtest1_native_groups[] = {
+ "gpio18",
+};
+static const char * const qdss_tracedata_a_groups[] = {
+ "gpio19", "gpio26", "gpio27", "gpio28", "gpio29", "gpio30", "gpio31",
+ "gpio32", "gpio33", "gpio34", "gpio35", "gpio36", "gpio38", "gpio39",
+ "gpio40", "gpio50",
+};
+static const char * const blsp_spi6_groups[] = {
+ "gpio20", "gpio21", "gpio22", "gpio23",
+};
+static const char * const blsp_uart6_groups[] = {
+ "gpio20", "gpio21", "gpio22", "gpio23",
+};
+static const char * const qdss_tracectl_b_groups[] = {
+ "gpio20",
+};
+static const char * const dac_calib15_groups[] = {
+ "gpio20",
+};
+static const char * const qdss_cti_trig_in_b0_groups[] = {
+ "gpio21",
+};
+static const char * const dac_calib16_groups[] = {
+ "gpio21",
+};
+static const char * const blsp_i2c6_groups[] = {
+ "gpio22", "gpio23",
+};
+static const char * const qdss_traceclk_b_groups[] = {
+ "gpio22",
+};
+static const char * const atest_wlan0_groups[] = {
+ "gpio22",
+};
+static const char * const atest_wlan1_groups[] = {
+ "gpio23",
+};
+static const char * const mdp_vsync_groups[] = {
+ "gpio24", "gpio25",
+};
+static const char * const pri_mi2s_mclk_a_groups[] = {
+ "gpio25",
+};
+static const char * const sec_mi2s_mclk_a_groups[] = {
+ "gpio25",
+};
+static const char * const qdss_cti_trig_out_b1_groups[] = {
+ "gpio25",
+};
+static const char * const cam_mclk_groups[] = {
+ "gpio26", "gpio27", "gpio28", "gpio128",
+};
+static const char * const dac_calib3_groups[] = {
+ "gpio28",
+};
+static const char * const cci_i2c_groups[] = {
+ "gpio29", "gpio30", "gpio31", "gpio32",
+};
+static const char * const pwr_modem_enabled_a_groups[] = {
+ "gpio29",
+};
+static const char * const dac_calib4_groups[] = {
+ "gpio29",
+};
+static const char * const dac_calib19_groups[] = {
+ "gpio30",
+};
+static const char * const flash_strobe_groups[] = {
+ "gpio33", "gpio34",
+};
+static const char * const cci_timer0_groups[] = {
+ "gpio33",
+};
+static const char * const cci_timer1_groups[] = {
+ "gpio34",
+};
+static const char * const cam_irq_groups[] = {
+ "gpio35",
+};
+static const char * const cci_timer2_groups[] = {
+ "gpio35",
+};
+static const char * const blsp1_spi_groups[] = {
+ "gpio35", "gpio36",
+};
+static const char * const pwr_nav_enabled_a_groups[] = {
+ "gpio35",
+};
+static const char * const ois_sync_groups[] = {
+ "gpio36",
+};
+static const char * const cci_timer3_groups[] = {
+ "gpio36",
+};
+static const char * const cci_timer4_groups[] = {
+ "gpio41",
+};
+static const char * const blsp3_spi_groups[] = {
+ "gpio41", "gpio50",
+};
+static const char * const qdss_cti_trig_out_a0_groups[] = {
+ "gpio41",
+};
+static const char * const dac_calib7_groups[] = {
+ "gpio41",
+};
+static const char * const accel_int_groups[] = {
+ "gpio42",
+};
+static const char * const gcc_gp1_clk_a_groups[] = {
+ "gpio42",
+};
+static const char * const dac_calib8_groups[] = {
+ "gpio42",
+};
+static const char * const alsp_int_groups[] = {
+ "gpio43",
+};
+static const char * const gcc_gp2_clk_a_groups[] = {
+ "gpio43",
+};
+static const char * const dac_calib9_groups[] = {
+ "gpio43",
+};
+static const char * const mag_int_groups[] = {
+ "gpio44",
+};
+static const char * const gcc_gp3_clk_a_groups[] = {
+ "gpio44",
+};
+static const char * const pwr_crypto_enabled_a_groups[] = {
+ "gpio36",
+};
+static const char * const cci_async_groups[] = {
+ "gpio38",
+};
+static const char * const cam1_standby_groups[] = {
+ "gpio39",
+};
+static const char * const dac_calib5_groups[] = {
+ "gpio39",
+};
+static const char * const cam1_rst_groups[] = {
+ "gpio40",
+};
+static const char * const dac_calib6_groups[] = {
+ "gpio40",
+};
+static const char * const dac_calib10_groups[] = {
+ "gpio44",
+};
+static const char * const gyro_int_groups[] = {
+ "gpio45",
+};
+static const char * const dac_calib11_groups[] = {
+ "gpio45",
+};
+static const char * const pressure_int_groups[] = {
+ "gpio46",
+};
+static const char * const dac_calib12_groups[] = {
+ "gpio46",
+};
+static const char * const blsp6_spi_groups[] = {
+ "gpio47", "gpio48",
+};
+static const char * const dac_calib13_groups[] = {
+ "gpio47",
+};
+static const char * const fp_int_groups[] = {
+ "gpio48",
+};
+static const char * const qdss_cti_trig_in_b1_groups[] = {
+ "gpio48",
+};
+static const char * const dac_calib14_groups[] = {
+ "gpio48",
+};
+static const char * const uim_batt_groups[] = {
+ "gpio49",
+};
+static const char * const cam0_ldo_groups[] = {
+ "gpio50",
+};
+static const char * const sd_write_groups[] = {
+ "gpio50",
+};
+static const char * const uim1_data_groups[] = {
+ "gpio51",
+};
+static const char * const uim1_clk_groups[] = {
+ "gpio52",
+};
+static const char * const uim1_reset_groups[] = {
+ "gpio53",
+};
+static const char * const uim1_present_groups[] = {
+ "gpio54",
+};
+static const char * const uim2_data_groups[] = {
+ "gpio55",
+};
+static const char * const uim2_clk_groups[] = {
+ "gpio56",
+};
+static const char * const uim2_reset_groups[] = {
+ "gpio57",
+};
+static const char * const uim2_present_groups[] = {
+ "gpio58",
+};
+static const char * const ts_xvdd_groups[] = {
+ "gpio60",
+};
+static const char * const mipi_dsi0_groups[] = {
+ "gpio61",
+};
+static const char * const nfc_dwl_groups[] = {
+ "gpio62",
+};
+static const char * const us_euro_groups[] = {
+ "gpio63",
+};
+static const char * const atest_char3_groups[] = {
+ "gpio63",
+};
+static const char * const dbg_out_groups[] = {
+ "gpio63",
+};
+static const char * const bimc_dte0_groups[] = {
+ "gpio63", "gpio65",
+};
+static const char * const ts_resout_groups[] = {
+ "gpio64",
+};
+static const char * const ts_sample_groups[] = {
+ "gpio65",
+};
+static const char * const sec_mi2s_mclk_b_groups[] = {
+ "gpio66",
+};
+static const char * const pri_mi2s_groups[] = {
+ "gpio66", "gpio88", "gpio91", "gpio93", "gpio94", "gpio95",
+};
+static const char * const codec_reset_groups[] = {
+ "gpio67",
+};
+static const char * const cdc_pdm0_groups[] = {
+ "gpio67", "gpio68", "gpio69", "gpio70", "gpio71", "gpio72", "gpio73",
+ "gpio74",
+};
+static const char * const atest_char1_groups[] = {
+ "gpio67",
+};
+static const char * const ebi_cdc_groups[] = {
+ "gpio67", "gpio69", "gpio118", "gpio119", "gpio120", "gpio123",
+};
+static const char * const dac_calib17_groups[] = {
+ "gpio67",
+};
+static const char * const us_emitter_groups[] = {
+ "gpio68",
+};
+static const char * const atest_char0_groups[] = {
+ "gpio68",
+};
+static const char * const pri_mi2s_mclk_b_groups[] = {
+ "gpio69",
+};
+static const char * const lpass_slimbus_groups[] = {
+ "gpio70",
+};
+static const char * const lpass_slimbus0_groups[] = {
+ "gpio71",
+};
+static const char * const lpass_slimbus1_groups[] = {
+ "gpio72",
+};
+static const char * const codec_int1_groups[] = {
+ "gpio73",
+};
+static const char * const codec_int2_groups[] = {
+ "gpio74",
+};
+static const char * const wcss_bt_groups[] = {
+ "gpio75", "gpio83", "gpio84",
+};
+static const char * const atest_char2_groups[] = {
+ "gpio75",
+};
+static const char * const ebi_ch0_groups[] = {
+ "gpio75",
+};
+static const char * const wcss_wlan2_groups[] = {
+ "gpio76",
+};
+static const char * const wcss_wlan1_groups[] = {
+ "gpio77",
+};
+static const char * const wcss_wlan0_groups[] = {
+ "gpio78",
+};
+static const char * const wcss_wlan_groups[] = {
+ "gpio79", "gpio80",
+};
+static const char * const wcss_fm_groups[] = {
+ "gpio81", "gpio82",
+};
+static const char * const ext_lpass_groups[] = {
+ "gpio81",
+};
+static const char * const mss_lte_groups[] = {
+ "gpio82", "gpio83",
+};
+static const char * const key_volp_groups[] = {
+ "gpio85",
+};
+static const char * const pbs0_groups[] = {
+ "gpio85",
+};
+static const char * const cri_trng0_groups[] = {
+ "gpio85",
+};
+static const char * const key_snapshot_groups[] = {
+ "gpio86",
+};
+static const char * const pbs1_groups[] = {
+ "gpio86",
+};
+static const char * const cri_trng1_groups[] = {
+ "gpio86",
+};
+static const char * const key_focus_groups[] = {
+ "gpio87",
+};
+static const char * const pbs2_groups[] = {
+ "gpio87",
+};
+static const char * const cri_trng_groups[] = {
+ "gpio87",
+};
+static const char * const gcc_tlmm_groups[] = {
+ "gpio87",
+};
+static const char * const key_home_groups[] = {
+ "gpio88",
+};
+static const char * const pwr_down_groups[] = {
+ "gpio89",
+};
+static const char * const dmic0_clk_groups[] = {
+ "gpio89",
+};
+static const char * const blsp7_spi_groups[] = {
+ "gpio89", "gpio90",
+};
+static const char * const hdmi_int_groups[] = {
+ "gpio90",
+};
+static const char * const dmic0_data_groups[] = {
+ "gpio90",
+};
+static const char * const qdss_cti_trig_in_a1_groups[] = {
+ "gpio91",
+};
+static const char * const pri_mi2s_ws_groups[] = {
+ "gpio92",
+};
+static const char * const wsa_io_groups[] = {
+ "gpio94", "gpio95",
+};
+static const char * const wsa_en_groups[] = {
+ "gpio96",
+};
+static const char * const blsp_spi8_groups[] = {
+ "gpio96", "gpio97", "gpio98", "gpio99",
+};
+static const char * const wsa_irq_groups[] = {
+ "gpio97",
+};
+static const char * const blsp_i2c8_groups[] = {
+ "gpio98", "gpio99",
+};
+static const char * const gcc_plltest_groups[] = {
+ "gpio98", "gpio99",
+};
+static const char * const nav_pps_in_a_groups[] = {
+ "gpio111",
+};
+static const char * const pa_indicator_groups[] = {
+ "gpio112",
+};
+static const char * const nav_pps_in_b_groups[] = {
+ "gpio113",
+};
+static const char * const nav_pps_groups[] = {
+ "gpio113",
+};
+static const char * const modem_tsync_groups[] = {
+ "gpio113",
+};
+static const char * const nav_tsync_groups[] = {
+ "gpio113",
+};
+static const char * const ssbi_wtr1_groups[] = {
+ "gpio114", "gpio123",
+};
+static const char * const gsm1_tx_groups[] = {
+ "gpio115",
+};
+static const char * const dac_calib18_groups[] = {
+ "gpio115",
+};
+static const char * const gsm0_tx_groups[] = {
+ "gpio117",
+};
+static const char * const atest_char_groups[] = {
+ "gpio120",
+};
+static const char * const atest_tsens_groups[] = {
+ "gpio120",
+};
+static const char * const bimc_dte1_groups[] = {
+ "gpio121", "gpio122",
+};
+static const char * const dac_calib20_groups[] = {
+ "gpio128",
+};
+static const char * const cam2_rst_groups[] = {
+ "gpio129",
+};
+static const char * const ddr_bist_groups[] = {
+ "gpio129", "gpio130", "gpio131", "gpio132",
+};
+static const char * const dac_calib21_groups[] = {
+ "gpio129",
+};
+static const char * const cam2_standby_groups[] = {
+ "gpio130",
+};
+static const char * const dac_calib22_groups[] = {
+ "gpio130",
+};
+static const char * const cam3_rst_groups[] = {
+ "gpio131",
+};
+static const char * const dac_calib23_groups[] = {
+ "gpio131",
+};
+static const char * const cam3_standby_groups[] = {
+ "gpio132",
+};
+static const char * const dac_calib24_groups[] = {
+ "gpio132",
+};
+static const char * const sdcard_det_groups[] = {
+ "gpio133",
+};
+static const char * const dac_calib25_groups[] = {
+ "gpio133",
+};
+static const char * const cam1_ldo_groups[] = {
+ "gpio134",
+};
+static const char * const sec_mi2s_groups[] = {
+ "gpio135", "gpio136", "gpio137", "gpio138",
+};
+static const char * const blsp_spi7_groups[] = {
+ "gpio135", "gpio136", "gpio137", "gpio138",
+};
+static const char * const blsp_i2c7_groups[] = {
+ "gpio135", "gpio136",
+};
+static const char * const ss_switch_groups[] = {
+ "gpio139",
+};
+static const char * const tsens_max_groups[] = {
+ "gpio139",
+};
+
+static const struct msm_function msm8953_functions[] = {
+ FUNCTION(gpio),
+ FUNCTION(blsp_spi1),
+ FUNCTION(smb_int),
+ FUNCTION(adsp_ext),
+ FUNCTION(prng_rosc),
+ FUNCTION(blsp_i2c1),
+ FUNCTION(qdss_cti_trig_out_b0),
+ FUNCTION(qdss_cti_trig_out_a1),
+ FUNCTION(blsp_spi2),
+ FUNCTION(blsp_uart2),
+ FUNCTION(ldo_update),
+ FUNCTION(dac_calib0),
+ FUNCTION(ldo_en),
+ FUNCTION(blsp_i2c2),
+ FUNCTION(gcc_gp1_clk_b),
+ FUNCTION(atest_gpsadc_dtest0_native),
+ FUNCTION(blsp_spi3),
+ FUNCTION(qdss_tracedata_b),
+ FUNCTION(pwr_modem_enabled_b),
+ FUNCTION(blsp_i2c3),
+ FUNCTION(gcc_gp2_clk_b),
+ FUNCTION(gcc_gp3_clk_b),
+ FUNCTION(hall_int),
+ FUNCTION(blsp_spi4),
+ FUNCTION(blsp_uart4),
+ FUNCTION(pwr_nav_enabled_b),
+ FUNCTION(dac_calib1),
+ FUNCTION(cap_int),
+ FUNCTION(pwr_crypto_enabled_b),
+ FUNCTION(dac_calib2),
+ FUNCTION(blsp_i2c4),
+ FUNCTION(nfc_disable),
+ FUNCTION(blsp_spi5),
+ FUNCTION(blsp_uart5),
+ FUNCTION(qdss_traceclk_a),
+ FUNCTION(atest_bbrx1),
+ FUNCTION(nfc_irq),
+ FUNCTION(m_voc),
+ FUNCTION(qdss_cti_trig_in_a0),
+ FUNCTION(atest_bbrx0),
+ FUNCTION(blsp_i2c5),
+ FUNCTION(qdss_tracectl_a),
+ FUNCTION(atest_gpsadc_dtest1_native),
+ FUNCTION(qdss_tracedata_a),
+ FUNCTION(blsp_spi6),
+ FUNCTION(blsp_uart6),
+ FUNCTION(qdss_tracectl_b),
+ FUNCTION(dac_calib15),
+ FUNCTION(qdss_cti_trig_in_b0),
+ FUNCTION(dac_calib16),
+ FUNCTION(blsp_i2c6),
+ FUNCTION(qdss_traceclk_b),
+ FUNCTION(atest_wlan0),
+ FUNCTION(atest_wlan1),
+ FUNCTION(mdp_vsync),
+ FUNCTION(pri_mi2s_mclk_a),
+ FUNCTION(sec_mi2s_mclk_a),
+ FUNCTION(qdss_cti_trig_out_b1),
+ FUNCTION(cam_mclk),
+ FUNCTION(dac_calib3),
+ FUNCTION(cci_i2c),
+ FUNCTION(pwr_modem_enabled_a),
+ FUNCTION(dac_calib4),
+ FUNCTION(dac_calib19),
+ FUNCTION(flash_strobe),
+ FUNCTION(cci_timer0),
+ FUNCTION(cci_timer1),
+ FUNCTION(cam_irq),
+ FUNCTION(cci_timer2),
+ FUNCTION(blsp1_spi),
+ FUNCTION(pwr_nav_enabled_a),
+ FUNCTION(ois_sync),
+ FUNCTION(cci_timer3),
+ FUNCTION(cci_timer4),
+ FUNCTION(blsp3_spi),
+ FUNCTION(qdss_cti_trig_out_a0),
+ FUNCTION(dac_calib7),
+ FUNCTION(accel_int),
+ FUNCTION(gcc_gp1_clk_a),
+ FUNCTION(dac_calib8),
+ FUNCTION(alsp_int),
+ FUNCTION(gcc_gp2_clk_a),
+ FUNCTION(dac_calib9),
+ FUNCTION(mag_int),
+ FUNCTION(gcc_gp3_clk_a),
+ FUNCTION(pwr_crypto_enabled_a),
+ FUNCTION(cci_async),
+ FUNCTION(cam1_standby),
+ FUNCTION(dac_calib5),
+ FUNCTION(cam1_rst),
+ FUNCTION(dac_calib6),
+ FUNCTION(dac_calib10),
+ FUNCTION(gyro_int),
+ FUNCTION(dac_calib11),
+ FUNCTION(pressure_int),
+ FUNCTION(dac_calib12),
+ FUNCTION(blsp6_spi),
+ FUNCTION(dac_calib13),
+ FUNCTION(fp_int),
+ FUNCTION(qdss_cti_trig_in_b1),
+ FUNCTION(dac_calib14),
+ FUNCTION(uim_batt),
+ FUNCTION(cam0_ldo),
+ FUNCTION(sd_write),
+ FUNCTION(uim1_data),
+ FUNCTION(uim1_clk),
+ FUNCTION(uim1_reset),
+ FUNCTION(uim1_present),
+ FUNCTION(uim2_data),
+ FUNCTION(uim2_clk),
+ FUNCTION(uim2_reset),
+ FUNCTION(uim2_present),
+ FUNCTION(ts_xvdd),
+ FUNCTION(mipi_dsi0),
+ FUNCTION(nfc_dwl),
+ FUNCTION(us_euro),
+ FUNCTION(atest_char3),
+ FUNCTION(dbg_out),
+ FUNCTION(bimc_dte0),
+ FUNCTION(ts_resout),
+ FUNCTION(ts_sample),
+ FUNCTION(sec_mi2s_mclk_b),
+ FUNCTION(pri_mi2s),
+ FUNCTION(codec_reset),
+ FUNCTION(cdc_pdm0),
+ FUNCTION(atest_char1),
+ FUNCTION(ebi_cdc),
+ FUNCTION(dac_calib17),
+ FUNCTION(us_emitter),
+ FUNCTION(atest_char0),
+ FUNCTION(pri_mi2s_mclk_b),
+ FUNCTION(lpass_slimbus),
+ FUNCTION(lpass_slimbus0),
+ FUNCTION(lpass_slimbus1),
+ FUNCTION(codec_int1),
+ FUNCTION(codec_int2),
+ FUNCTION(wcss_bt),
+ FUNCTION(atest_char2),
+ FUNCTION(ebi_ch0),
+ FUNCTION(wcss_wlan2),
+ FUNCTION(wcss_wlan1),
+ FUNCTION(wcss_wlan0),
+ FUNCTION(wcss_wlan),
+ FUNCTION(wcss_fm),
+ FUNCTION(ext_lpass),
+ FUNCTION(mss_lte),
+ FUNCTION(key_volp),
+ FUNCTION(pbs0),
+ FUNCTION(cri_trng0),
+ FUNCTION(key_snapshot),
+ FUNCTION(pbs1),
+ FUNCTION(cri_trng1),
+ FUNCTION(key_focus),
+ FUNCTION(pbs2),
+ FUNCTION(cri_trng),
+ FUNCTION(gcc_tlmm),
+ FUNCTION(key_home),
+ FUNCTION(pwr_down),
+ FUNCTION(dmic0_clk),
+ FUNCTION(blsp7_spi),
+ FUNCTION(hdmi_int),
+ FUNCTION(dmic0_data),
+ FUNCTION(qdss_cti_trig_in_a1),
+ FUNCTION(pri_mi2s_ws),
+ FUNCTION(wsa_io),
+ FUNCTION(wsa_en),
+ FUNCTION(blsp_spi8),
+ FUNCTION(wsa_irq),
+ FUNCTION(blsp_i2c8),
+ FUNCTION(gcc_plltest),
+ FUNCTION(nav_pps_in_a),
+ FUNCTION(pa_indicator),
+ FUNCTION(nav_pps_in_b),
+ FUNCTION(nav_pps),
+ FUNCTION(modem_tsync),
+ FUNCTION(nav_tsync),
+ FUNCTION(ssbi_wtr1),
+ FUNCTION(gsm1_tx),
+ FUNCTION(dac_calib18),
+ FUNCTION(gsm0_tx),
+ FUNCTION(atest_char),
+ FUNCTION(atest_tsens),
+ FUNCTION(bimc_dte1),
+ FUNCTION(dac_calib20),
+ FUNCTION(cam2_rst),
+ FUNCTION(ddr_bist),
+ FUNCTION(dac_calib21),
+ FUNCTION(cam2_standby),
+ FUNCTION(dac_calib22),
+ FUNCTION(cam3_rst),
+ FUNCTION(dac_calib23),
+ FUNCTION(cam3_standby),
+ FUNCTION(dac_calib24),
+ FUNCTION(sdcard_det),
+ FUNCTION(dac_calib25),
+ FUNCTION(cam1_ldo),
+ FUNCTION(sec_mi2s),
+ FUNCTION(blsp_spi7),
+ FUNCTION(blsp_i2c7),
+ FUNCTION(ss_switch),
+ FUNCTION(tsens_max),
+};
+
+static const struct msm_pingroup msm8953_groups[] = {
+ PINGROUP(0, blsp_spi1, NA, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(1, blsp_spi1, adsp_ext, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(2, blsp_spi1, blsp_i2c1, prng_rosc, NA, NA, NA,
+ qdss_cti_trig_out_b0, NA, NA),
+ PINGROUP(3, blsp_spi1, blsp_i2c1, NA, NA, NA, qdss_cti_trig_out_a1, NA,
+ NA, NA),
+ PINGROUP(4, blsp_spi2, blsp_uart2, ldo_update, NA, dac_calib0, NA, NA,
+ NA, NA),
+ PINGROUP(5, blsp_spi2, blsp_uart2, ldo_en, NA, NA, NA, NA, NA, NA),
+ PINGROUP(6, blsp_spi2, blsp_uart2, blsp_i2c2, gcc_gp1_clk_b, NA, NA,
+ NA, NA, NA),
+ PINGROUP(7, blsp_spi2, blsp_uart2, blsp_i2c2, NA,
+ atest_gpsadc_dtest0_native, NA, NA, NA, NA),
+ PINGROUP(8, blsp_spi3, NA, NA, qdss_tracedata_b, NA, NA, NA, NA, NA),
+ PINGROUP(9, blsp_spi3, pwr_modem_enabled_b, NA, NA, qdss_tracedata_b,
+ NA, NA, NA, NA),
+ PINGROUP(10, blsp_spi3, blsp_i2c3, gcc_gp2_clk_b, NA, NA, NA, NA, NA,
+ NA),
+ PINGROUP(11, blsp_spi3, blsp_i2c3, gcc_gp3_clk_b, NA, NA, NA, NA, NA,
+ NA),
+ PINGROUP(12, blsp_spi4, blsp_uart4, pwr_nav_enabled_b, NA, NA,
+ qdss_tracedata_b, NA, dac_calib1, NA),
+ PINGROUP(13, blsp_spi4, blsp_uart4, pwr_crypto_enabled_b, NA, NA, NA,
+ qdss_tracedata_b, NA, dac_calib2),
+ PINGROUP(14, blsp_spi4, blsp_uart4, blsp_i2c4, NA, NA, NA, NA, NA, NA),
+ PINGROUP(15, blsp_spi4, blsp_uart4, blsp_i2c4, NA, NA, NA, NA, NA, NA),
+ PINGROUP(16, blsp_spi5, blsp_uart5, NA, NA, qdss_traceclk_a, NA,
+ atest_bbrx1, NA, NA),
+ PINGROUP(17, blsp_spi5, blsp_uart5, m_voc, qdss_cti_trig_in_a0, NA,
+ atest_bbrx0, NA, NA, NA),
+ PINGROUP(18, blsp_spi5, blsp_uart5, blsp_i2c5, qdss_tracectl_a, NA,
+ atest_gpsadc_dtest1_native, NA, NA, NA),
+ PINGROUP(19, blsp_spi5, blsp_uart5, blsp_i2c5, qdss_tracedata_a, NA,
+ NA, NA, NA, NA),
+ PINGROUP(20, blsp_spi6, blsp_uart6, NA, NA, NA, qdss_tracectl_b, NA,
+ dac_calib15, NA),
+ PINGROUP(21, blsp_spi6, blsp_uart6, m_voc, NA, NA, NA,
+ qdss_cti_trig_in_b0, NA, dac_calib16),
+ PINGROUP(22, blsp_spi6, blsp_uart6, blsp_i2c6, qdss_traceclk_b, NA,
+ atest_wlan0, NA, NA, NA),
+ PINGROUP(23, blsp_spi6, blsp_uart6, blsp_i2c6, qdss_tracedata_b, NA,
+ atest_wlan1, NA, NA, NA),
+ PINGROUP(24, mdp_vsync, NA, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(25, mdp_vsync, pri_mi2s_mclk_a, sec_mi2s_mclk_a,
+ qdss_cti_trig_out_b1, NA, NA, NA, NA, NA),
+ PINGROUP(26, cam_mclk, NA, NA, NA, qdss_tracedata_a, NA, NA, NA, NA),
+ PINGROUP(27, cam_mclk, NA, NA, NA, qdss_tracedata_a, NA, NA, NA, NA),
+ PINGROUP(28, cam_mclk, NA, NA, NA, qdss_tracedata_a, NA, dac_calib3,
+ NA, NA),
+ PINGROUP(29, cci_i2c, pwr_modem_enabled_a, NA, NA, NA,
+ qdss_tracedata_a, NA, dac_calib4, NA),
+ PINGROUP(30, cci_i2c, NA, NA, NA, qdss_tracedata_a, NA, dac_calib19,
+ NA, NA),
+ PINGROUP(31, cci_i2c, NA, NA, NA, qdss_tracedata_a, NA, NA, NA, NA),
+ PINGROUP(32, cci_i2c, NA, NA, NA, qdss_tracedata_a, NA, NA, NA, NA),
+ PINGROUP(33, cci_timer0, NA, NA, NA, NA, qdss_tracedata_a, NA, NA, NA),
+ PINGROUP(34, cci_timer1, NA, NA, NA, NA, qdss_tracedata_a, NA, NA, NA),
+ PINGROUP(35, cci_timer2, blsp1_spi, pwr_nav_enabled_a, NA, NA, NA,
+ qdss_tracedata_a, NA, NA),
+ PINGROUP(36, cci_timer3, blsp1_spi, NA, pwr_crypto_enabled_a, NA, NA,
+ NA, qdss_tracedata_a, NA),
+ PINGROUP(37, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(38, cci_async, NA, qdss_tracedata_a, NA, NA, NA, NA, NA, NA),
+ PINGROUP(39, NA, NA, NA, qdss_tracedata_a, NA, dac_calib5, NA, NA, NA),
+ PINGROUP(40, NA, NA, qdss_tracedata_a, NA, dac_calib6, NA, NA, NA, NA),
+ PINGROUP(41, cci_timer4, blsp3_spi, gcc_gp1_clk_b, NA, NA,
+ qdss_cti_trig_out_a0, NA, dac_calib7, NA),
+ PINGROUP(42, gcc_gp1_clk_a, qdss_tracedata_b, NA, dac_calib8, NA, NA,
+ NA, NA, NA),
+ PINGROUP(43, gcc_gp2_clk_a, qdss_tracedata_b, NA, dac_calib9, NA, NA,
+ NA, NA, NA),
+ PINGROUP(44, gcc_gp3_clk_a, qdss_tracedata_b, NA, dac_calib10, NA, NA,
+ NA, NA, NA),
+ PINGROUP(45, NA, qdss_tracedata_b, NA, dac_calib11, NA, NA, NA, NA, NA),
+ PINGROUP(46, qdss_tracedata_b, NA, dac_calib12, NA, NA, NA, NA, NA, NA),
+ PINGROUP(47, blsp6_spi, qdss_tracedata_b, NA, dac_calib13, NA, NA, NA,
+ NA, NA),
+ PINGROUP(48, blsp6_spi, NA, qdss_cti_trig_in_b1, NA, dac_calib14, NA,
+ NA, NA, NA),
+ PINGROUP(49, uim_batt, NA, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(50, blsp3_spi, sd_write, NA, NA, NA, qdss_tracedata_a, NA, NA,
+ NA),
+ PINGROUP(51, uim1_data, NA, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(52, uim1_clk, NA, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(53, uim1_reset, NA, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(54, uim1_present, NA, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(55, uim2_data, NA, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(56, uim2_clk, NA, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(57, uim2_reset, NA, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(58, uim2_present, NA, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(59, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(60, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(61, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(62, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(63, atest_char3, dbg_out, bimc_dte0, NA, NA, NA, NA, NA, NA),
+ PINGROUP(64, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(65, bimc_dte0, NA, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(66, sec_mi2s_mclk_b, pri_mi2s, NA, qdss_tracedata_b, NA, NA,
+ NA, NA, NA),
+ PINGROUP(67, cdc_pdm0, atest_char1, ebi_cdc, NA, dac_calib17, NA, NA,
+ NA, NA),
+ PINGROUP(68, cdc_pdm0, atest_char0, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(69, cdc_pdm0, pri_mi2s_mclk_b, ebi_cdc, NA, NA, NA, NA, NA,
+ NA),
+ PINGROUP(70, lpass_slimbus, cdc_pdm0, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(71, lpass_slimbus0, cdc_pdm0, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(72, lpass_slimbus1, cdc_pdm0, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(73, cdc_pdm0, NA, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(74, cdc_pdm0, NA, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(75, wcss_bt, atest_char2, NA, ebi_ch0, NA, NA, NA, NA, NA),
+ PINGROUP(76, wcss_wlan2, NA, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(77, wcss_wlan1, NA, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(78, wcss_wlan0, NA, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(79, wcss_wlan, NA, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(80, wcss_wlan, NA, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(81, wcss_fm, ext_lpass, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(82, wcss_fm, mss_lte, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(83, wcss_bt, mss_lte, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(84, wcss_bt, NA, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(85, pbs0, cri_trng0, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(86, pbs1, cri_trng1, qdss_tracedata_b, NA, NA, NA, NA, NA, NA),
+ PINGROUP(87, pbs2, cri_trng, qdss_tracedata_b, gcc_tlmm, NA, NA, NA,
+ NA, NA),
+ PINGROUP(88, pri_mi2s, NA, NA, NA, qdss_tracedata_b, NA, NA, NA, NA),
+ PINGROUP(89, dmic0_clk, blsp7_spi, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(90, dmic0_data, blsp7_spi, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(91, pri_mi2s, NA, NA, NA, qdss_cti_trig_in_a1, NA, NA, NA, NA),
+ PINGROUP(92, pri_mi2s_ws, NA, NA, NA, qdss_tracedata_b, NA, NA, NA, NA),
+ PINGROUP(93, pri_mi2s, NA, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(94, wsa_io, pri_mi2s, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(95, wsa_io, pri_mi2s, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(96, blsp_spi8, NA, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(97, blsp_spi8, NA, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(98, blsp_i2c8, blsp_spi8, gcc_plltest, NA, NA, NA, NA, NA, NA),
+ PINGROUP(99, blsp_i2c8, blsp_spi8, gcc_plltest, NA, NA, NA, NA, NA, NA),
+ PINGROUP(100, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(101, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(102, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(103, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(104, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(105, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(106, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(107, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(108, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(109, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(110, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(111, NA, NA, nav_pps_in_a, NA, NA, NA, NA, NA, NA),
+ PINGROUP(112, NA, pa_indicator, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(113, NA, nav_pps_in_b, nav_pps, modem_tsync, nav_tsync, NA,
+ NA, NA, NA),
+ PINGROUP(114, NA, ssbi_wtr1, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(115, NA, gsm1_tx, NA, dac_calib18, NA, NA, NA, NA, NA),
+ PINGROUP(116, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(117, gsm0_tx, NA, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(118, NA, ebi_cdc, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(119, NA, ebi_cdc, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(120, NA, atest_char, ebi_cdc, NA, atest_tsens, NA, NA, NA, NA),
+ PINGROUP(121, NA, NA, NA, bimc_dte1, NA, NA, NA, NA, NA),
+ PINGROUP(122, NA, NA, NA, bimc_dte1, NA, NA, NA, NA, NA),
+ PINGROUP(123, NA, ssbi_wtr1, ebi_cdc, NA, NA, NA, NA, NA, NA),
+ PINGROUP(124, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(125, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(126, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(127, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(128, cam_mclk, NA, dac_calib20, NA, NA, NA, NA, NA, NA),
+ PINGROUP(129, ddr_bist, NA, dac_calib21, NA, NA, NA, NA, NA, NA),
+ PINGROUP(130, ddr_bist, NA, dac_calib22, NA, NA, NA, NA, NA, NA),
+ PINGROUP(131, ddr_bist, NA, dac_calib23, NA, NA, NA, NA, NA, NA),
+ PINGROUP(132, ddr_bist, NA, dac_calib24, NA, NA, NA, NA, NA, NA),
+ PINGROUP(133, NA, dac_calib25, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(134, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(135, sec_mi2s, blsp_spi7, blsp_i2c7, NA, NA, NA, NA, NA, NA),
+ PINGROUP(136, sec_mi2s, blsp_spi7, blsp_i2c7, NA, NA, NA, NA, NA, NA),
+ PINGROUP(137, sec_mi2s, blsp_spi7, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(138, sec_mi2s, blsp_spi7, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(139, tsens_max, NA, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(140, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(141, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+ SDC_QDSD_PINGROUP(sdc1_clk, 0x10a000, 13, 6),
+ SDC_QDSD_PINGROUP(sdc1_cmd, 0x10a000, 11, 3),
+ SDC_QDSD_PINGROUP(sdc1_data, 0x10a000, 9, 0),
+ SDC_QDSD_PINGROUP(sdc1_rclk, 0x10a000, 15, 0),
+ SDC_QDSD_PINGROUP(sdc2_clk, 0x109000, 14, 6),
+ SDC_QDSD_PINGROUP(sdc2_cmd, 0x109000, 11, 3),
+ SDC_QDSD_PINGROUP(sdc2_data, 0x109000, 9, 0),
+ SDC_QDSD_PINGROUP(qdsd_clk, 0x19c000, 3, 0),
+ SDC_QDSD_PINGROUP(qdsd_cmd, 0x19c000, 8, 5),
+ SDC_QDSD_PINGROUP(qdsd_data0, 0x19c000, 13, 10),
+ SDC_QDSD_PINGROUP(qdsd_data1, 0x19c000, 18, 15),
+ SDC_QDSD_PINGROUP(qdsd_data2, 0x19c000, 23, 20),
+ SDC_QDSD_PINGROUP(qdsd_data3, 0x19c000, 28, 25),
+};
+
+static const struct msm_pinctrl_soc_data msm8953_pinctrl = {
+ .pins = msm8953_pins,
+ .npins = ARRAY_SIZE(msm8953_pins),
+ .functions = msm8953_functions,
+ .nfunctions = ARRAY_SIZE(msm8953_functions),
+ .groups = msm8953_groups,
+ .ngroups = ARRAY_SIZE(msm8953_groups),
+ .ngpios = 142,
+};
+
+static int msm8953_pinctrl_probe(struct platform_device *pdev)
+{
+ return msm_pinctrl_probe(pdev, &msm8953_pinctrl);
+}
+
+static const struct of_device_id msm8953_pinctrl_of_match[] = {
+ { .compatible = "qcom,msm8953-pinctrl", },
+ { },
+};
+
+static struct platform_driver msm8953_pinctrl_driver = {
+ .driver = {
+ .name = "msm8953-pinctrl",
+ .owner = THIS_MODULE,
+ .of_match_table = msm8953_pinctrl_of_match,
+ },
+ .probe = msm8953_pinctrl_probe,
+ .remove = msm_pinctrl_remove,
+};
+
+static int __init msm8953_pinctrl_init(void)
+{
+ return platform_driver_register(&msm8953_pinctrl_driver);
+}
+arch_initcall(msm8953_pinctrl_init);
+
+static void __exit msm8953_pinctrl_exit(void)
+{
+ platform_driver_unregister(&msm8953_pinctrl_driver);
+}
+module_exit(msm8953_pinctrl_exit);
+
+MODULE_DESCRIPTION("QTI msm8953 pinctrl driver");
+MODULE_LICENSE("GPL v2");
+MODULE_DEVICE_TABLE(of, msm8953_pinctrl_of_match);
diff --git a/drivers/platform/msm/ipa/ipa_clients/ecm_ipa.c b/drivers/platform/msm/ipa/ipa_clients/ecm_ipa.c
index 105294a..2975192 100644
--- a/drivers/platform/msm/ipa/ipa_clients/ecm_ipa.c
+++ b/drivers/platform/msm/ipa/ipa_clients/ecm_ipa.c
@@ -19,6 +19,8 @@
#include <linux/sched.h>
#include <linux/atomic.h>
#include <linux/ecm_ipa.h>
+#include "../ipa_common_i.h"
+#include "../ipa_v3/ipa_pm.h"
#define DRIVER_NAME "ecm_ipa"
#define ECM_IPA_IPV4_HDR_NAME "ecm_eth_ipv4"
@@ -120,6 +122,7 @@
* @usb_to_ipa_client: producer client
* @ipa_rm_resource_name_prod: IPA resource manager producer resource
* @ipa_rm_resource_name_cons: IPA resource manager consumer resource
+ * @pm_hdl: handle for IPA PM
*/
struct ecm_ipa_dev {
struct net_device *net;
@@ -137,6 +140,7 @@
enum ipa_client_type usb_to_ipa_client;
enum ipa_rm_resource_name ipa_rm_resource_name_prod;
enum ipa_rm_resource_name ipa_rm_resource_name_cons;
+ u32 pm_hdl;
};
static int ecm_ipa_open(struct net_device *net);
@@ -158,6 +162,8 @@
static struct net_device_stats *ecm_ipa_get_stats(struct net_device *net);
static int ecm_ipa_create_rm_resource(struct ecm_ipa_dev *ecm_ipa_ctx);
static void ecm_ipa_destroy_rm_resource(struct ecm_ipa_dev *ecm_ipa_ctx);
+static int ecm_ipa_register_pm_client(struct ecm_ipa_dev *ecm_ipa_ctx);
+static void ecm_ipa_deregister_pm_client(struct ecm_ipa_dev *ecm_ipa_ctx);
static int resource_request(struct ecm_ipa_dev *ecm_ipa_ctx);
static void resource_release(struct ecm_ipa_dev *ecm_ipa_ctx);
static netdev_tx_t ecm_ipa_start_xmit
@@ -403,27 +409,34 @@
ECM_IPA_DEBUG("usb_to_ipa_client = %d\n",
ecm_ipa_ctx->usb_to_ipa_client);
- ecm_ipa_ctx->ipa_rm_resource_name_cons =
- ipa_get_rm_resource_from_ep(ipa_to_usb_hdl);
- if (ecm_ipa_ctx->ipa_rm_resource_name_cons < 0) {
- ECM_IPA_ERROR("Error getting CONS RM resource from handle %d\n",
+ if (ipa_pm_is_used()) {
+ retval = ecm_ipa_register_pm_client(ecm_ipa_ctx);
+ } else {
+ ecm_ipa_ctx->ipa_rm_resource_name_cons =
+ ipa_get_rm_resource_from_ep(ipa_to_usb_hdl);
+ if (ecm_ipa_ctx->ipa_rm_resource_name_cons < 0) {
+ ECM_IPA_ERROR(
+ "Error getting CONS RM resource from handle %d\n",
+ ecm_ipa_ctx->ipa_rm_resource_name_cons);
+ return -EINVAL;
+ }
+ ECM_IPA_DEBUG("ipa_rm_resource_name_cons = %d\n",
ecm_ipa_ctx->ipa_rm_resource_name_cons);
- return -EINVAL;
- }
- ECM_IPA_DEBUG("ipa_rm_resource_name_cons = %d\n",
- ecm_ipa_ctx->ipa_rm_resource_name_cons);
- ecm_ipa_ctx->ipa_rm_resource_name_prod =
- ipa_get_rm_resource_from_ep(usb_to_ipa_hdl);
- if (ecm_ipa_ctx->ipa_rm_resource_name_prod < 0) {
- ECM_IPA_ERROR("Error getting PROD RM resource from handle %d\n",
+ ecm_ipa_ctx->ipa_rm_resource_name_prod =
+ ipa_get_rm_resource_from_ep(usb_to_ipa_hdl);
+ if (ecm_ipa_ctx->ipa_rm_resource_name_prod < 0) {
+ ECM_IPA_ERROR(
+ "Error getting PROD RM resource from handle %d\n",
+ ecm_ipa_ctx->ipa_rm_resource_name_prod);
+ return -EINVAL;
+ }
+ ECM_IPA_DEBUG("ipa_rm_resource_name_prod = %d\n",
ecm_ipa_ctx->ipa_rm_resource_name_prod);
- return -EINVAL;
- }
- ECM_IPA_DEBUG("ipa_rm_resource_name_prod = %d\n",
- ecm_ipa_ctx->ipa_rm_resource_name_prod);
- retval = ecm_ipa_create_rm_resource(ecm_ipa_ctx);
+ retval = ecm_ipa_create_rm_resource(ecm_ipa_ctx);
+ }
+
if (retval) {
ECM_IPA_ERROR("fail on RM create\n");
goto fail_create_rm;
@@ -488,7 +501,10 @@
fail:
ecm_ipa_deregister_properties();
fail_create_rm:
- ecm_ipa_destroy_rm_resource(ecm_ipa_ctx);
+ if (ipa_pm_is_used())
+ ecm_ipa_deregister_pm_client(ecm_ipa_ctx);
+ else
+ ecm_ipa_destroy_rm_resource(ecm_ipa_ctx);
return retval;
}
EXPORT_SYMBOL(ecm_ipa_connect);
@@ -746,7 +762,10 @@
netif_stop_queue(ecm_ipa_ctx->net);
ECM_IPA_DEBUG("queue stopped\n");
- ecm_ipa_destroy_rm_resource(ecm_ipa_ctx);
+ if (ipa_pm_is_used())
+ ecm_ipa_deregister_pm_client(ecm_ipa_ctx);
+ else
+ ecm_ipa_destroy_rm_resource(ecm_ipa_ctx);
outstanding_dropped_pkts =
atomic_read(&ecm_ipa_ctx->outstanding_pkts);
@@ -1117,15 +1136,65 @@
ECM_IPA_LOG_EXIT();
}
+static void ecm_ipa_pm_cb(void *p, enum ipa_pm_cb_event event)
+{
+ struct ecm_ipa_dev *ecm_ipa_ctx = p;
+
+ ECM_IPA_LOG_ENTRY();
+ if (event != IPA_PM_CLIENT_ACTIVATED) {
+ ECM_IPA_ERROR("unexpected event %d\n", event);
+ WARN_ON(1);
+ return;
+ }
+
+ if (netif_queue_stopped(ecm_ipa_ctx->net)) {
+ ECM_IPA_DEBUG("Resource Granted - starting queue\n");
+ netif_start_queue(ecm_ipa_ctx->net);
+ }
+ ECM_IPA_LOG_EXIT();
+}
+
+static int ecm_ipa_register_pm_client(struct ecm_ipa_dev *ecm_ipa_ctx)
+{
+ int result;
+ struct ipa_pm_register_params pm_reg;
+
+ memset(&pm_reg, 0, sizeof(pm_reg));
+ pm_reg.name = ecm_ipa_ctx->net->name;
+ pm_reg.user_data = ecm_ipa_ctx;
+ pm_reg.callback = ecm_ipa_pm_cb;
+ pm_reg.group = IPA_PM_GROUP_APPS;
+ result = ipa_pm_register(&pm_reg, &ecm_ipa_ctx->pm_hdl);
+ if (result) {
+ ECM_IPA_ERROR("failed to create IPA PM client %d\n", result);
+ return result;
+ }
+ return 0;
+}
+
+static void ecm_ipa_deregister_pm_client(struct ecm_ipa_dev *ecm_ipa_ctx)
+{
+ ipa_pm_deactivate_sync(ecm_ipa_ctx->pm_hdl);
+ ipa_pm_deregister(ecm_ipa_ctx->pm_hdl);
+ ecm_ipa_ctx->pm_hdl = ~0;
+}
+
static int resource_request(struct ecm_ipa_dev *ecm_ipa_ctx)
{
+ if (ipa_pm_is_used())
+ return ipa_pm_activate(ecm_ipa_ctx->pm_hdl);
+
return ipa_rm_inactivity_timer_request_resource(
IPA_RM_RESOURCE_STD_ECM_PROD);
}
static void resource_release(struct ecm_ipa_dev *ecm_ipa_ctx)
{
- ipa_rm_inactivity_timer_release_resource(IPA_RM_RESOURCE_STD_ECM_PROD);
+ if (ipa_pm_is_used())
+ ipa_pm_deferred_deactivate(ecm_ipa_ctx->pm_hdl);
+ else
+ ipa_rm_inactivity_timer_release_resource(
+ IPA_RM_RESOURCE_STD_ECM_PROD);
}
/**
diff --git a/drivers/platform/msm/ipa/ipa_clients/ipa_mhi_client.c b/drivers/platform/msm/ipa/ipa_clients/ipa_mhi_client.c
index 9b3b53d..4d3113f 100644
--- a/drivers/platform/msm/ipa/ipa_clients/ipa_mhi_client.c
+++ b/drivers/platform/msm/ipa/ipa_clients/ipa_mhi_client.c
@@ -19,6 +19,7 @@
#include <linux/ipa_qmi_service_v01.h>
#include <linux/ipa_mhi.h>
#include "../ipa_common_i.h"
+#include "../ipa_v3/ipa_pm.h"
#define IPA_MHI_DRV_NAME "ipa_mhi_client"
#define IPA_MHI_DBG(fmt, args...) \
@@ -136,6 +137,8 @@
u32 use_ipadma;
bool assert_bit40;
bool test_mode;
+ u32 pm_hdl;
+ u32 modem_pm_hdl;
};
static struct ipa_mhi_client_ctx *ipa_mhi_client_ctx;
@@ -834,25 +837,38 @@
IPA_MHI_DBG("event_context_array_addr 0x%llx\n",
ipa_mhi_client_ctx->event_context_array_addr);
- /* Add MHI <-> Q6 dependencies to IPA RM */
- res = ipa_rm_add_dependency(IPA_RM_RESOURCE_MHI_PROD,
- IPA_RM_RESOURCE_Q6_CONS);
- if (res && res != -EINPROGRESS) {
- IPA_MHI_ERR("failed to add dependency %d\n", res);
- goto fail_add_mhi_q6_dep;
- }
+ if (ipa_pm_is_used()) {
+ res = ipa_pm_activate_sync(ipa_mhi_client_ctx->pm_hdl);
+ if (res) {
+ IPA_MHI_ERR("failed activate client %d\n", res);
+ goto fail_pm_activate;
+ }
+ res = ipa_pm_activate_sync(ipa_mhi_client_ctx->modem_pm_hdl);
+ if (res) {
+ IPA_MHI_ERR("failed activate modem client %d\n", res);
+ goto fail_pm_activate_modem;
+ }
+ } else {
+ /* Add MHI <-> Q6 dependencies to IPA RM */
+ res = ipa_rm_add_dependency(IPA_RM_RESOURCE_MHI_PROD,
+ IPA_RM_RESOURCE_Q6_CONS);
+ if (res && res != -EINPROGRESS) {
+ IPA_MHI_ERR("failed to add dependency %d\n", res);
+ goto fail_add_mhi_q6_dep;
+ }
- res = ipa_rm_add_dependency(IPA_RM_RESOURCE_Q6_PROD,
- IPA_RM_RESOURCE_MHI_CONS);
- if (res && res != -EINPROGRESS) {
- IPA_MHI_ERR("failed to add dependency %d\n", res);
- goto fail_add_q6_mhi_dep;
- }
+ res = ipa_rm_add_dependency(IPA_RM_RESOURCE_Q6_PROD,
+ IPA_RM_RESOURCE_MHI_CONS);
+ if (res && res != -EINPROGRESS) {
+ IPA_MHI_ERR("failed to add dependency %d\n", res);
+ goto fail_add_q6_mhi_dep;
+ }
- res = ipa_mhi_request_prod();
- if (res) {
- IPA_MHI_ERR("failed request prod %d\n", res);
- goto fail_request_prod;
+ res = ipa_mhi_request_prod();
+ if (res) {
+ IPA_MHI_ERR("failed request prod %d\n", res);
+ goto fail_request_prod;
+ }
}
/* gsi params */
@@ -880,14 +896,23 @@
return 0;
fail_init_engine:
- ipa_mhi_release_prod();
+ if (!ipa_pm_is_used())
+ ipa_mhi_release_prod();
fail_request_prod:
- ipa_rm_delete_dependency(IPA_RM_RESOURCE_Q6_PROD,
- IPA_RM_RESOURCE_MHI_CONS);
+ if (!ipa_pm_is_used())
+ ipa_rm_delete_dependency(IPA_RM_RESOURCE_Q6_PROD,
+ IPA_RM_RESOURCE_MHI_CONS);
fail_add_q6_mhi_dep:
- ipa_rm_delete_dependency(IPA_RM_RESOURCE_MHI_PROD,
- IPA_RM_RESOURCE_Q6_CONS);
+ if (!ipa_pm_is_used())
+ ipa_rm_delete_dependency(IPA_RM_RESOURCE_MHI_PROD,
+ IPA_RM_RESOURCE_Q6_CONS);
fail_add_mhi_q6_dep:
+ if (ipa_pm_is_used())
+ ipa_pm_deactivate_sync(ipa_mhi_client_ctx->modem_pm_hdl);
+fail_pm_activate_modem:
+ if (ipa_pm_is_used())
+ ipa_pm_deactivate_sync(ipa_mhi_client_ctx->pm_hdl);
+fail_pm_activate:
ipa_mhi_set_state(IPA_MHI_STATE_INITIALIZED);
return res;
}
@@ -2095,20 +2120,32 @@
*/
IPA_ACTIVE_CLIENTS_INC_SIMPLE();
- IPA_MHI_DBG("release prod\n");
- res = ipa_mhi_release_prod();
- if (res) {
- IPA_MHI_ERR("ipa_mhi_release_prod failed %d\n", res);
- goto fail_release_prod;
- }
+ if (ipa_pm_is_used()) {
+ res = ipa_pm_deactivate_sync(ipa_mhi_client_ctx->pm_hdl);
+ if (res) {
+ IPA_MHI_ERR("fail to deactivate client %d\n", res);
+ goto fail_deactivate_pm;
+ }
+ res = ipa_pm_deactivate_sync(ipa_mhi_client_ctx->modem_pm_hdl);
+ if (res) {
+ IPA_MHI_ERR("fail to deactivate client %d\n", res);
+ goto fail_deactivate_modem_pm;
+ }
+ } else {
+ IPA_MHI_DBG("release prod\n");
+ res = ipa_mhi_release_prod();
+ if (res) {
+ IPA_MHI_ERR("ipa_mhi_release_prod failed %d\n", res);
+ goto fail_release_prod;
+ }
- IPA_MHI_DBG("wait for cons release\n");
- res = ipa_mhi_wait_for_cons_release();
- if (res) {
- IPA_MHI_ERR("ipa_mhi_wait_for_cons_release failed %d\n", res);
- goto fail_release_cons;
+ IPA_MHI_DBG("wait for cons release\n");
+ res = ipa_mhi_wait_for_cons_release();
+ if (res) {
+ IPA_MHI_ERR("ipa_mhi_wait_for_cons_release failed\n");
+ goto fail_release_cons;
+ }
}
-
usleep_range(IPA_MHI_SUSPEND_SLEEP_MIN, IPA_MHI_SUSPEND_SLEEP_MAX);
res = ipa_mhi_suspend_dl(force);
@@ -2132,8 +2169,15 @@
fail_suspend_dl_channel:
fail_release_cons:
+ if (!ipa_pm_is_used())
ipa_mhi_request_prod();
fail_release_prod:
+ if (ipa_pm_is_used())
+ ipa_pm_deactivate_sync(ipa_mhi_client_ctx->modem_pm_hdl);
+fail_deactivate_modem_pm:
+ if (ipa_pm_is_used())
+ ipa_pm_deactivate_sync(ipa_mhi_client_ctx->pm_hdl);
+fail_deactivate_pm:
IPA_ACTIVE_CLIENTS_DEC_SIMPLE();
fail_suspend_ul_channel:
ipa_mhi_resume_channels(true, ipa_mhi_client_ctx->ul_channels);
@@ -2193,10 +2237,23 @@
ipa_mhi_client_ctx->rm_cons_state = IPA_MHI_RM_STATE_GRANTED;
}
- res = ipa_mhi_request_prod();
- if (res) {
- IPA_MHI_ERR("ipa_mhi_request_prod failed %d\n", res);
- goto fail_request_prod;
+ if (ipa_pm_is_used()) {
+ res = ipa_pm_activate_sync(ipa_mhi_client_ctx->pm_hdl);
+ if (res) {
+ IPA_MHI_ERR("fail to activate client %d\n", res);
+ goto fail_pm_activate;
+ }
+ ipa_pm_activate_sync(ipa_mhi_client_ctx->modem_pm_hdl);
+ if (res) {
+ IPA_MHI_ERR("fail to activate client %d\n", res);
+ goto fail_pm_activate_modem;
+ }
+ } else {
+ res = ipa_mhi_request_prod();
+ if (res) {
+ IPA_MHI_ERR("ipa_mhi_request_prod failed %d\n", res);
+ goto fail_request_prod;
+ }
}
/* resume all UL channels */
@@ -2234,8 +2291,15 @@
fail_resume_dl_channels2:
ipa_mhi_suspend_channels(ipa_mhi_client_ctx->ul_channels);
fail_resume_ul_channels:
- ipa_mhi_release_prod();
+ if (!ipa_pm_is_used())
+ ipa_mhi_release_prod();
fail_request_prod:
+ if (ipa_pm_is_used())
+ ipa_pm_deactivate_sync(ipa_mhi_client_ctx->modem_pm_hdl);
+fail_pm_activate_modem:
+ if (ipa_pm_is_used())
+ ipa_pm_deactivate_sync(ipa_mhi_client_ctx->pm_hdl);
+fail_pm_activate:
ipa_mhi_suspend_channels(ipa_mhi_client_ctx->dl_channels);
fail_resume_dl_channels:
ipa_mhi_set_state(IPA_MHI_STATE_SUSPENDED);
@@ -2319,6 +2383,85 @@
debugfs_remove_recursive(dent);
}
+static void ipa_mhi_delete_rm_resources(void)
+{
+ int res;
+
+ if (ipa_mhi_client_ctx->state != IPA_MHI_STATE_INITIALIZED &&
+ ipa_mhi_client_ctx->state != IPA_MHI_STATE_READY) {
+
+ IPA_MHI_DBG("release prod\n");
+ res = ipa_mhi_release_prod();
+ if (res) {
+ IPA_MHI_ERR("ipa_mhi_release_prod failed %d\n",
+ res);
+ goto fail;
+ }
+ IPA_MHI_DBG("wait for cons release\n");
+ res = ipa_mhi_wait_for_cons_release();
+ if (res) {
+ IPA_MHI_ERR("ipa_mhi_wait_for_cons_release%d\n",
+ res);
+ goto fail;
+ }
+
+ usleep_range(IPA_MHI_SUSPEND_SLEEP_MIN,
+ IPA_MHI_SUSPEND_SLEEP_MAX);
+
+ IPA_MHI_DBG("deleate dependency Q6_PROD->MHI_CONS\n");
+ res = ipa_rm_delete_dependency(IPA_RM_RESOURCE_Q6_PROD,
+ IPA_RM_RESOURCE_MHI_CONS);
+ if (res) {
+ IPA_MHI_ERR(
+ "Error deleting dependency %d->%d, res=%d\n",
+ IPA_RM_RESOURCE_Q6_PROD,
+ IPA_RM_RESOURCE_MHI_CONS,
+ res);
+ goto fail;
+ }
+ IPA_MHI_DBG("deleate dependency MHI_PROD->Q6_CONS\n");
+ res = ipa_rm_delete_dependency(IPA_RM_RESOURCE_MHI_PROD,
+ IPA_RM_RESOURCE_Q6_CONS);
+ if (res) {
+ IPA_MHI_ERR(
+ "Error deleting dependency %d->%d, res=%d\n",
+ IPA_RM_RESOURCE_MHI_PROD,
+ IPA_RM_RESOURCE_Q6_CONS,
+ res);
+ goto fail;
+ }
+ }
+
+ res = ipa_rm_delete_resource(IPA_RM_RESOURCE_MHI_PROD);
+ if (res) {
+ IPA_MHI_ERR("Error deleting resource %d, res=%d\n",
+ IPA_RM_RESOURCE_MHI_PROD, res);
+ goto fail;
+ }
+
+ res = ipa_rm_delete_resource(IPA_RM_RESOURCE_MHI_CONS);
+ if (res) {
+ IPA_MHI_ERR("Error deleting resource %d, res=%d\n",
+ IPA_RM_RESOURCE_MHI_CONS, res);
+ goto fail;
+ }
+
+ return;
+fail:
+ ipa_assert();
+}
+
+static void ipa_mhi_deregister_pm(void)
+{
+ ipa_pm_deactivate_sync(ipa_mhi_client_ctx->pm_hdl);
+ ipa_pm_deregister(ipa_mhi_client_ctx->pm_hdl);
+ ipa_mhi_client_ctx->pm_hdl = ~0;
+
+ ipa_pm_deactivate_sync(ipa_mhi_client_ctx->modem_pm_hdl);
+ ipa_pm_deregister(ipa_mhi_client_ctx->modem_pm_hdl);
+ ipa_mhi_client_ctx->modem_pm_hdl = ~0;
+}
+
/**
* ipa_mhi_destroy() - Destroy MHI IPA
*
@@ -2351,62 +2494,10 @@
ipa_uc_mhi_cleanup();
}
-
- if (ipa_mhi_client_ctx->state != IPA_MHI_STATE_INITIALIZED &&
- ipa_mhi_client_ctx->state != IPA_MHI_STATE_READY) {
- IPA_MHI_DBG("release prod\n");
- res = ipa_mhi_release_prod();
- if (res) {
- IPA_MHI_ERR("ipa_mhi_release_prod failed %d\n", res);
- goto fail;
- }
- IPA_MHI_DBG("wait for cons release\n");
- res = ipa_mhi_wait_for_cons_release();
- if (res) {
- IPA_MHI_ERR("ipa_mhi_wait_for_cons_release failed %d\n",
- res);
- goto fail;
- }
- usleep_range(IPA_MHI_SUSPEND_SLEEP_MIN,
- IPA_MHI_SUSPEND_SLEEP_MAX);
-
- IPA_MHI_DBG("deleate dependency Q6_PROD->MHI_CONS\n");
- res = ipa_rm_delete_dependency(IPA_RM_RESOURCE_Q6_PROD,
- IPA_RM_RESOURCE_MHI_CONS);
- if (res) {
- IPA_MHI_ERR(
- "Error deleting dependency %d->%d, res=%d\n"
- , IPA_RM_RESOURCE_Q6_PROD,
- IPA_RM_RESOURCE_MHI_CONS,
- res);
- goto fail;
- }
- IPA_MHI_DBG("deleate dependency MHI_PROD->Q6_CONS\n");
- res = ipa_rm_delete_dependency(IPA_RM_RESOURCE_MHI_PROD,
- IPA_RM_RESOURCE_Q6_CONS);
- if (res) {
- IPA_MHI_ERR(
- "Error deleting dependency %d->%d, res=%d\n",
- IPA_RM_RESOURCE_MHI_PROD,
- IPA_RM_RESOURCE_Q6_CONS,
- res);
- goto fail;
- }
- }
-
- res = ipa_rm_delete_resource(IPA_RM_RESOURCE_MHI_PROD);
- if (res) {
- IPA_MHI_ERR("Error deleting resource %d, res=%d\n",
- IPA_RM_RESOURCE_MHI_PROD, res);
- goto fail;
- }
-
- res = ipa_rm_delete_resource(IPA_RM_RESOURCE_MHI_CONS);
- if (res) {
- IPA_MHI_ERR("Error deleting resource %d, res=%d\n",
- IPA_RM_RESOURCE_MHI_CONS, res);
- goto fail;
- }
+ if (ipa_pm_is_used())
+ ipa_mhi_deregister_pm();
+ else
+ ipa_mhi_delete_rm_resources();
ipa_mhi_debugfs_destroy();
destroy_workqueue(ipa_mhi_client_ctx->wq);
@@ -2420,6 +2511,132 @@
ipa_assert();
}
+static void ipa_mhi_pm_cb(void *p, enum ipa_pm_cb_event event)
+{
+ unsigned long flags;
+
+ IPA_MHI_FUNC_ENTRY();
+
+ if (event != IPA_PM_REQUEST_WAKEUP) {
+ IPA_MHI_ERR("Unexpected event %d\n", event);
+ WARN_ON(1);
+ return;
+ }
+
+ IPA_MHI_DBG("%s\n", MHI_STATE_STR(ipa_mhi_client_ctx->state));
+ spin_lock_irqsave(&ipa_mhi_client_ctx->state_lock, flags);
+ if (ipa_mhi_client_ctx->state == IPA_MHI_STATE_SUSPENDED) {
+ ipa_mhi_notify_wakeup();
+ } else if (ipa_mhi_client_ctx->state ==
+ IPA_MHI_STATE_SUSPEND_IN_PROGRESS) {
+ /* wakeup event will be trigger after suspend finishes */
+ ipa_mhi_client_ctx->trigger_wakeup = true;
+ }
+ spin_unlock_irqrestore(&ipa_mhi_client_ctx->state_lock, flags);
+ IPA_MHI_DBG("EXIT");
+}
+
+static int ipa_mhi_register_pm(void)
+{
+ int res;
+ struct ipa_pm_register_params params;
+
+ memset(¶ms, 0, sizeof(params));
+ params.name = "MHI";
+ params.callback = ipa_mhi_pm_cb;
+ params.group = IPA_PM_GROUP_DEFAULT;
+ res = ipa_pm_register(¶ms, &ipa_mhi_client_ctx->pm_hdl);
+ if (res) {
+ IPA_MHI_ERR("fail to register with PM %d\n", res);
+ return res;
+ }
+
+ res = ipa_pm_associate_ipa_cons_to_client(ipa_mhi_client_ctx->pm_hdl,
+ IPA_CLIENT_MHI_CONS);
+ if (res) {
+ IPA_MHI_ERR("fail to associate cons with PM %d\n", res);
+ goto fail_pm_cons;
+ }
+
+ res = ipa_pm_set_perf_profile(ipa_mhi_client_ctx->pm_hdl, 1000);
+ if (res) {
+ IPA_MHI_ERR("fail to set perf profile to PM %d\n", res);
+ goto fail_pm_cons;
+ }
+
+ /* create a modem client for clock scaling */
+ memset(¶ms, 0, sizeof(params));
+ params.name = "MODEM (MHI)";
+ params.group = IPA_PM_GROUP_MODEM;
+ params.skip_clk_vote = true;
+ res = ipa_pm_register(¶ms, &ipa_mhi_client_ctx->modem_pm_hdl);
+ if (res) {
+ IPA_MHI_ERR("fail to register with PM %d\n", res);
+ goto fail_pm_cons;
+ }
+
+ return 0;
+
+fail_pm_cons:
+ ipa_pm_deregister(ipa_mhi_client_ctx->pm_hdl);
+ ipa_mhi_client_ctx->pm_hdl = ~0;
+ return res;
+}
+
+static int ipa_mhi_create_rm_resources(void)
+{
+ int res;
+ struct ipa_rm_create_params mhi_prod_params;
+ struct ipa_rm_create_params mhi_cons_params;
+ struct ipa_rm_perf_profile profile;
+
+ /* Create PROD in IPA RM */
+ memset(&mhi_prod_params, 0, sizeof(mhi_prod_params));
+ mhi_prod_params.name = IPA_RM_RESOURCE_MHI_PROD;
+ mhi_prod_params.floor_voltage = IPA_VOLTAGE_SVS;
+ mhi_prod_params.reg_params.notify_cb = ipa_mhi_rm_prod_notify;
+ res = ipa_rm_create_resource(&mhi_prod_params);
+ if (res) {
+ IPA_MHI_ERR("fail to create IPA_RM_RESOURCE_MHI_PROD\n");
+ goto fail_create_rm_prod;
+ }
+
+ memset(&profile, 0, sizeof(profile));
+ profile.max_supported_bandwidth_mbps = 1000;
+ res = ipa_rm_set_perf_profile(IPA_RM_RESOURCE_MHI_PROD, &profile);
+ if (res) {
+ IPA_MHI_ERR("fail to set profile to MHI_PROD\n");
+ goto fail_perf_rm_prod;
+ }
+
+ /* Create CONS in IPA RM */
+ memset(&mhi_cons_params, 0, sizeof(mhi_cons_params));
+ mhi_cons_params.name = IPA_RM_RESOURCE_MHI_CONS;
+ mhi_cons_params.floor_voltage = IPA_VOLTAGE_SVS;
+ mhi_cons_params.request_resource = ipa_mhi_rm_cons_request;
+ mhi_cons_params.release_resource = ipa_mhi_rm_cons_release;
+ res = ipa_rm_create_resource(&mhi_cons_params);
+ if (res) {
+ IPA_MHI_ERR("fail to create IPA_RM_RESOURCE_MHI_CONS\n");
+ goto fail_create_rm_cons;
+ }
+
+ memset(&profile, 0, sizeof(profile));
+ profile.max_supported_bandwidth_mbps = 1000;
+ res = ipa_rm_set_perf_profile(IPA_RM_RESOURCE_MHI_CONS, &profile);
+ if (res) {
+ IPA_MHI_ERR("fail to set profile to MHI_CONS\n");
+ goto fail_perf_rm_cons;
+ }
+fail_perf_rm_cons:
+ ipa_rm_delete_resource(IPA_RM_RESOURCE_MHI_CONS);
+fail_create_rm_cons:
+fail_perf_rm_prod:
+ ipa_rm_delete_resource(IPA_RM_RESOURCE_MHI_PROD);
+fail_create_rm_prod:
+ return res;
+}
+
/**
* ipa_mhi_init() - Initialize IPA MHI driver
* @params: initialization params
@@ -2437,9 +2654,6 @@
int ipa_mhi_init(struct ipa_mhi_init_params *params)
{
int res;
- struct ipa_rm_create_params mhi_prod_params;
- struct ipa_rm_create_params mhi_cons_params;
- struct ipa_rm_perf_profile profile;
IPA_MHI_FUNC_ENTRY();
@@ -2500,43 +2714,14 @@
goto fail_create_wq;
}
- /* Create PROD in IPA RM */
- memset(&mhi_prod_params, 0, sizeof(mhi_prod_params));
- mhi_prod_params.name = IPA_RM_RESOURCE_MHI_PROD;
- mhi_prod_params.floor_voltage = IPA_VOLTAGE_SVS;
- mhi_prod_params.reg_params.notify_cb = ipa_mhi_rm_prod_notify;
- res = ipa_rm_create_resource(&mhi_prod_params);
+ if (ipa_pm_is_used())
+ res = ipa_mhi_register_pm();
+ else
+ res = ipa_mhi_create_rm_resources();
if (res) {
- IPA_MHI_ERR("fail to create IPA_RM_RESOURCE_MHI_PROD\n");
- goto fail_create_rm_prod;
- }
-
- memset(&profile, 0, sizeof(profile));
- profile.max_supported_bandwidth_mbps = 1000;
- res = ipa_rm_set_perf_profile(IPA_RM_RESOURCE_MHI_PROD, &profile);
- if (res) {
- IPA_MHI_ERR("fail to set profile to MHI_PROD\n");
- goto fail_perf_rm_prod;
- }
-
- /* Create CONS in IPA RM */
- memset(&mhi_cons_params, 0, sizeof(mhi_cons_params));
- mhi_cons_params.name = IPA_RM_RESOURCE_MHI_CONS;
- mhi_cons_params.floor_voltage = IPA_VOLTAGE_SVS;
- mhi_cons_params.request_resource = ipa_mhi_rm_cons_request;
- mhi_cons_params.release_resource = ipa_mhi_rm_cons_release;
- res = ipa_rm_create_resource(&mhi_cons_params);
- if (res) {
- IPA_MHI_ERR("fail to create IPA_RM_RESOURCE_MHI_CONS\n");
- goto fail_create_rm_cons;
- }
-
- memset(&profile, 0, sizeof(profile));
- profile.max_supported_bandwidth_mbps = 1000;
- res = ipa_rm_set_perf_profile(IPA_RM_RESOURCE_MHI_CONS, &profile);
- if (res) {
- IPA_MHI_ERR("fail to set profile to MHI_CONS\n");
- goto fail_perf_rm_cons;
+ IPA_MHI_ERR("failed to create RM resources\n");
+ res = -EFAULT;
+ goto fail_rm;
}
/* Initialize uC interface */
@@ -2551,12 +2736,7 @@
IPA_MHI_FUNC_EXIT();
return 0;
-fail_perf_rm_cons:
- ipa_rm_delete_resource(IPA_RM_RESOURCE_MHI_CONS);
-fail_create_rm_cons:
-fail_perf_rm_prod:
- ipa_rm_delete_resource(IPA_RM_RESOURCE_MHI_PROD);
-fail_create_rm_prod:
+fail_rm:
destroy_workqueue(ipa_mhi_client_ctx->wq);
fail_create_wq:
kfree(ipa_mhi_client_ctx);
diff --git a/drivers/platform/msm/ipa/ipa_clients/ipa_uc_offload.c b/drivers/platform/msm/ipa/ipa_clients/ipa_uc_offload.c
index a15a9d8..e19d297 100644
--- a/drivers/platform/msm/ipa/ipa_clients/ipa_uc_offload.c
+++ b/drivers/platform/msm/ipa/ipa_clients/ipa_uc_offload.c
@@ -13,6 +13,7 @@
#include <linux/ipa_uc_offload.h>
#include <linux/msm_ipa.h>
#include "../ipa_common_i.h"
+#include "../ipa_v3/ipa_pm.h"
#define IPA_NTN_DMA_POOL_ALIGNMENT 8
#define OFFLOAD_DRV_NAME "ipa_uc_offload"
@@ -69,6 +70,7 @@
char netdev_name[IPA_RESOURCE_NAME_MAX];
ipa_notify_cb notify;
struct completion ntn_completion;
+ u32 pm_hdl;
};
static struct ipa_uc_offload_ctx *ipa_uc_offload_ctx[IPA_UC_MAX_PROT_SIZE];
@@ -113,22 +115,53 @@
return 0;
}
-static int ipa_uc_offload_ntn_reg_intf(
- struct ipa_uc_offload_intf_params *inp,
- struct ipa_uc_offload_out_params *outp,
+static void ipa_uc_offload_ntn_pm_cb(void *p, enum ipa_pm_cb_event event)
+{
+ /* suspend/resume is not supported */
+ IPA_UC_OFFLOAD_DBG("event = %d\n", event);
+}
+
+static int ipa_uc_offload_ntn_register_pm_client(
struct ipa_uc_offload_ctx *ntn_ctx)
{
- struct ipa_ioc_add_hdr *hdr = NULL;
- struct ipa_tx_intf tx;
- struct ipa_rx_intf rx;
- struct ipa_ioc_tx_intf_prop tx_prop[2];
- struct ipa_ioc_rx_intf_prop rx_prop[2];
- struct ipa_rm_create_params param;
- u32 len;
- int ret = 0;
+ int res;
+ struct ipa_pm_register_params params;
- IPA_UC_OFFLOAD_DBG("register interface for netdev %s\n",
- inp->netdev_name);
+ memset(¶ms, 0, sizeof(params));
+ params.name = "ETH";
+ params.callback = ipa_uc_offload_ntn_pm_cb;
+ params.user_data = ntn_ctx;
+ params.group = IPA_PM_GROUP_DEFAULT;
+ res = ipa_pm_register(¶ms, &ntn_ctx->pm_hdl);
+ if (res) {
+ IPA_UC_OFFLOAD_ERR("fail to register with PM %d\n", res);
+ return res;
+ }
+
+ res = ipa_pm_associate_ipa_cons_to_client(ntn_ctx->pm_hdl,
+ IPA_CLIENT_ETHERNET_CONS);
+ if (res) {
+ IPA_UC_OFFLOAD_ERR("fail to associate cons with PM %d\n", res);
+ ipa_pm_deregister(ntn_ctx->pm_hdl);
+ ntn_ctx->pm_hdl = ~0;
+ return res;
+ }
+
+ return 0;
+}
+
+static void ipa_uc_offload_ntn_deregister_pm_client(
+ struct ipa_uc_offload_ctx *ntn_ctx)
+{
+ ipa_pm_deactivate_sync(ntn_ctx->pm_hdl);
+ ipa_pm_deregister(ntn_ctx->pm_hdl);
+}
+static int ipa_uc_offload_ntn_create_rm_resources(
+ struct ipa_uc_offload_ctx *ntn_ctx)
+{
+ int ret;
+ struct ipa_rm_create_params param;
+
memset(¶m, 0, sizeof(param));
param.name = IPA_RM_RESOURCE_ETHERNET_PROD;
param.reg_params.user_data = ntn_ctx;
@@ -147,9 +180,37 @@
ret = ipa_rm_create_resource(¶m);
if (ret) {
IPA_UC_OFFLOAD_ERR("fail to create ETHERNET_CONS resource\n");
- goto fail_create_rm_cons;
+ ipa_rm_delete_resource(IPA_RM_RESOURCE_ETHERNET_PROD);
+ return -EFAULT;
}
+ return 0;
+}
+
+static int ipa_uc_offload_ntn_reg_intf(
+ struct ipa_uc_offload_intf_params *inp,
+ struct ipa_uc_offload_out_params *outp,
+ struct ipa_uc_offload_ctx *ntn_ctx)
+{
+ struct ipa_ioc_add_hdr *hdr = NULL;
+ struct ipa_tx_intf tx;
+ struct ipa_rx_intf rx;
+ struct ipa_ioc_tx_intf_prop tx_prop[2];
+ struct ipa_ioc_rx_intf_prop rx_prop[2];
+ int ret = 0;
+ u32 len;
+
+
+ IPA_UC_OFFLOAD_DBG("register interface for netdev %s\n",
+ inp->netdev_name);
+ if (ipa_pm_is_used())
+ ret = ipa_uc_offload_ntn_register_pm_client(ntn_ctx);
+ else
+ ret = ipa_uc_offload_ntn_create_rm_resources(ntn_ctx);
+ if (ret) {
+ IPA_UC_OFFLOAD_ERR("fail to create rm resource\n");
+ return -EFAULT;
+ }
memcpy(ntn_ctx->netdev_name, inp->netdev_name, IPA_RESOURCE_NAME_MAX);
ntn_ctx->hdr_len = inp->hdr_info[0].hdr_len;
ntn_ctx->notify = inp->notify;
@@ -228,9 +289,12 @@
fail:
kfree(hdr);
fail_alloc:
- ipa_rm_delete_resource(IPA_RM_RESOURCE_ETHERNET_CONS);
-fail_create_rm_cons:
- ipa_rm_delete_resource(IPA_RM_RESOURCE_ETHERNET_PROD);
+ if (ipa_pm_is_used()) {
+ ipa_uc_offload_ntn_deregister_pm_client(ntn_ctx);
+ } else {
+ ipa_rm_delete_resource(IPA_RM_RESOURCE_ETHERNET_CONS);
+ ipa_rm_delete_resource(IPA_RM_RESOURCE_ETHERNET_PROD);
+ }
return ret;
}
@@ -348,25 +412,34 @@
return -EINVAL;
}
- result = ipa_rm_add_dependency(IPA_RM_RESOURCE_ETHERNET_PROD,
- IPA_RM_RESOURCE_APPS_CONS);
- if (result) {
- IPA_UC_OFFLOAD_ERR("fail to add rm dependency: %d\n", result);
- return result;
- }
+ if (ipa_pm_is_used()) {
+ result = ipa_pm_activate_sync(ntn_ctx->pm_hdl);
+ if (result) {
+ IPA_UC_OFFLOAD_ERR("fail to activate: %d\n", result);
+ return result;
+ }
+ } else {
+ result = ipa_rm_add_dependency(IPA_RM_RESOURCE_ETHERNET_PROD,
+ IPA_RM_RESOURCE_APPS_CONS);
+ if (result) {
+ IPA_UC_OFFLOAD_ERR("fail to add rm dependency: %d\n",
+ result);
+ return result;
+ }
- result = ipa_rm_request_resource(IPA_RM_RESOURCE_ETHERNET_PROD);
- if (result == -EINPROGRESS) {
- if (wait_for_completion_timeout(&ntn_ctx->ntn_completion,
- 10*HZ) == 0) {
- IPA_UC_OFFLOAD_ERR("ETH_PROD resource req time out\n");
+ result = ipa_rm_request_resource(IPA_RM_RESOURCE_ETHERNET_PROD);
+ if (result == -EINPROGRESS) {
+ if (wait_for_completion_timeout(&ntn_ctx->ntn_completion
+ , 10*HZ) == 0) {
+ IPA_UC_OFFLOAD_ERR("ETH_PROD req timeout\n");
+ result = -EFAULT;
+ goto fail;
+ }
+ } else if (result != 0) {
+ IPA_UC_OFFLOAD_ERR("fail to request resource\n");
result = -EFAULT;
goto fail;
}
- } else if (result != 0) {
- IPA_UC_OFFLOAD_ERR("fail to request resource\n");
- result = -EFAULT;
- goto fail;
}
ntn_ctx->state = IPA_UC_OFFLOAD_STATE_UP;
@@ -383,8 +456,9 @@
return 0;
fail:
- ipa_rm_delete_dependency(IPA_RM_RESOURCE_ETHERNET_PROD,
- IPA_RM_RESOURCE_APPS_CONS);
+ if (!ipa_pm_is_used())
+ ipa_rm_delete_dependency(IPA_RM_RESOURCE_ETHERNET_PROD,
+ IPA_RM_RESOURCE_APPS_CONS);
return result;
}
@@ -455,6 +529,11 @@
return -EINVAL;
}
+ if (ipa_pm_is_used())
+ return ipa_pm_set_perf_profile(
+ ipa_uc_offload_ctx[IPA_UC_NTN]->pm_hdl,
+ profile->max_supported_bw_mbps);
+
if (ipa_rm_set_perf_profile(resource_name, &rm_profile)) {
IPA_UC_OFFLOAD_ERR("fail to setup rm perf profile\n");
return -EFAULT;
@@ -471,18 +550,27 @@
ntn_ctx->state = IPA_UC_OFFLOAD_STATE_INITIALIZED;
- ret = ipa_rm_release_resource(IPA_RM_RESOURCE_ETHERNET_PROD);
- if (ret) {
- IPA_UC_OFFLOAD_ERR("fail to release ETHERNET_PROD res: %d\n",
- ret);
- return -EFAULT;
- }
+ if (ipa_pm_is_used()) {
+ ret = ipa_pm_deactivate_sync(ntn_ctx->pm_hdl);
+ if (ret) {
+ IPA_UC_OFFLOAD_ERR("fail to deactivate res: %d\n",
+ ret);
+ return -EFAULT;
+ }
+ } else {
+ ret = ipa_rm_release_resource(IPA_RM_RESOURCE_ETHERNET_PROD);
+ if (ret) {
+ IPA_UC_OFFLOAD_ERR("fail release ETHERNET_PROD: %d\n",
+ ret);
+ return -EFAULT;
+ }
- ret = ipa_rm_delete_dependency(IPA_RM_RESOURCE_ETHERNET_PROD,
- IPA_RM_RESOURCE_APPS_CONS);
- if (ret) {
- IPA_UC_OFFLOAD_ERR("fail to del dep ETH_PROD->APPS, %d\n", ret);
- return -EFAULT;
+ ret = ipa_rm_delete_dependency(IPA_RM_RESOURCE_ETHERNET_PROD,
+ IPA_RM_RESOURCE_APPS_CONS);
+ if (ret) {
+ IPA_UC_OFFLOAD_ERR("fail del dep ETH->APPS, %d\n", ret);
+ return -EFAULT;
+ }
}
ipa_ep_idx_ul = ipa_get_ep_mapping(IPA_CLIENT_ETHERNET_PROD);
@@ -539,14 +627,18 @@
int len, result = 0;
struct ipa_ioc_del_hdr *hdr;
- if (ipa_rm_delete_resource(IPA_RM_RESOURCE_ETHERNET_PROD)) {
- IPA_UC_OFFLOAD_ERR("fail to delete ETHERNET_PROD resource\n");
- return -EFAULT;
- }
+ if (ipa_pm_is_used()) {
+ ipa_uc_offload_ntn_deregister_pm_client(ntn_ctx);
+ } else {
+ if (ipa_rm_delete_resource(IPA_RM_RESOURCE_ETHERNET_PROD)) {
+ IPA_UC_OFFLOAD_ERR("fail to delete ETHERNET_PROD\n");
+ return -EFAULT;
+ }
- if (ipa_rm_delete_resource(IPA_RM_RESOURCE_ETHERNET_CONS)) {
- IPA_UC_OFFLOAD_ERR("fail to delete ETHERNET_CONS resource\n");
- return -EFAULT;
+ if (ipa_rm_delete_resource(IPA_RM_RESOURCE_ETHERNET_CONS)) {
+ IPA_UC_OFFLOAD_ERR("fail to delete ETHERNET_CONS\n");
+ return -EFAULT;
+ }
}
len = sizeof(struct ipa_ioc_del_hdr) + 2 * sizeof(struct ipa_hdr_del);
diff --git a/drivers/platform/msm/ipa/ipa_clients/ipa_usb.c b/drivers/platform/msm/ipa/ipa_clients/ipa_usb.c
index f5d8d61..745e429 100644
--- a/drivers/platform/msm/ipa/ipa_clients/ipa_usb.c
+++ b/drivers/platform/msm/ipa/ipa_clients/ipa_usb.c
@@ -119,6 +119,12 @@
bool cons_requested_released;
};
+struct ipa3_usb_pm_context {
+ struct ipa_pm_register_params reg_params;
+ struct work_struct *remote_wakeup_work;
+ u32 hdl;
+};
+
enum ipa3_usb_state {
IPA_USB_INVALID,
IPA_USB_INITIALIZED,
@@ -157,6 +163,7 @@
*/
struct ipa3_usb_transport_type_ctx {
struct ipa3_usb_rm_context rm_ctx;
+ struct ipa3_usb_pm_context pm_ctx;
int (*ipa_usb_notify_cb)(enum ipa_usb_notify_event, void *user_data);
void *user_data;
enum ipa3_usb_state state;
@@ -362,7 +369,8 @@
ipa3_usb_state_to_string(new_state));
}
- if (state_legal && (new_state == IPA_USB_CONNECTED)) {
+ if (!ipa_pm_is_used() &&
+ state_legal && (new_state == IPA_USB_CONNECTED)) {
rm_ctx = &ipa3_usb_ctx->ttype_ctx[ttype].rm_ctx;
if ((rm_ctx->cons_state == IPA_USB_CONS_GRANTED) ||
rm_ctx->cons_requested_released) {
@@ -656,6 +664,30 @@
return ipa3_usb_cons_release_resource_cb_do(IPA_USB_TRANSPORT_DPL);
}
+static void ipa3_usb_pm_cb(void *p, enum ipa_pm_cb_event event)
+{
+ struct ipa3_usb_transport_type_ctx *ttype_ctx =
+ (struct ipa3_usb_transport_type_ctx *)p;
+ unsigned long flags;
+
+ IPA_USB_DBG_LOW("entry\n");
+
+ if (event != IPA_PM_REQUEST_WAKEUP) {
+ IPA_USB_ERR("Unexpected event %d\n", event);
+ WARN_ON(1);
+ return;
+ }
+
+ spin_lock_irqsave(&ipa3_usb_ctx->state_lock, flags);
+ IPA_USB_DBG("state is %s\n",
+ ipa3_usb_state_to_string(ttype_ctx->state));
+ if (ttype_ctx->state == IPA_USB_SUSPENDED)
+ queue_work(ipa3_usb_ctx->wq,
+ ttype_ctx->pm_ctx.remote_wakeup_work);
+ spin_unlock_irqrestore(&ipa3_usb_ctx->state_lock, flags);
+ IPA_USB_DBG_LOW("exit\n");
+}
+
static char *ipa3_usb_teth_prot_to_string(enum ipa_usb_teth_prot teth_prot)
{
switch (teth_prot) {
@@ -703,6 +735,59 @@
return 0;
}
+static int ipa3_usb_register_pm(enum ipa3_usb_transport_type ttype)
+{
+ struct ipa3_usb_transport_type_ctx *ttype_ctx =
+ &ipa3_usb_ctx->ttype_ctx[ttype];
+ int result;
+
+ memset(&ttype_ctx->pm_ctx.reg_params, 0,
+ sizeof(ttype_ctx->pm_ctx.reg_params));
+ ttype_ctx->pm_ctx.reg_params.name = (ttype == IPA_USB_TRANSPORT_DPL) ?
+ "USB DPL" : "USB";
+ ttype_ctx->pm_ctx.reg_params.callback = ipa3_usb_pm_cb;
+ ttype_ctx->pm_ctx.reg_params.user_data = ttype_ctx;
+ ttype_ctx->pm_ctx.reg_params.group = IPA_PM_GROUP_DEFAULT;
+
+ result = ipa_pm_register(&ttype_ctx->pm_ctx.reg_params,
+ &ttype_ctx->pm_ctx.hdl);
+ if (result) {
+ IPA_USB_ERR("fail to register with PM %d\n", result);
+ goto fail_pm_reg;
+ }
+
+ result = ipa_pm_associate_ipa_cons_to_client(ttype_ctx->pm_ctx.hdl,
+ (ttype == IPA_USB_TRANSPORT_DPL) ?
+ IPA_CLIENT_USB_DPL_CONS : IPA_CLIENT_USB_CONS);
+ if (result) {
+ IPA_USB_ERR("fail to associate cons with PM %d\n", result);
+ goto fail_pm_cons;
+ }
+
+ return 0;
+
+fail_pm_cons:
+ ipa_pm_deregister(ttype_ctx->pm_ctx.hdl);
+fail_pm_reg:
+ memset(&ttype_ctx->pm_ctx.reg_params, 0,
+ sizeof(ttype_ctx->pm_ctx.reg_params));
+ return result;
+}
+
+static int ipa3_usb_deregister_pm(enum ipa3_usb_transport_type ttype)
+{
+ struct ipa3_usb_pm_context *pm_ctx =
+ &ipa3_usb_ctx->ttype_ctx[ttype].pm_ctx;
+ int result;
+
+ result = ipa_pm_deregister(pm_ctx->hdl);
+ if (result)
+ return result;
+
+ memset(&pm_ctx->reg_params, 0, sizeof(pm_ctx->reg_params));
+ return 0;
+}
+
static int ipa3_usb_create_rm_resources(enum ipa3_usb_transport_type ttype)
{
struct ipa3_usb_rm_context *rm_ctx;
@@ -802,7 +887,10 @@
}
/* Create IPA RM USB resources */
- result = ipa3_usb_create_rm_resources(ttype);
+ if (ipa_pm_is_used())
+ result = ipa3_usb_register_pm(ttype);
+ else
+ result = ipa3_usb_create_rm_resources(ttype);
if (result) {
IPA_USB_ERR("Failed creating IPA RM USB resources\n");
goto bad_params;
@@ -934,12 +1022,18 @@
teth_prot_init_fail:
if ((IPA3_USB_IS_TTYPE_DPL(ttype))
|| (ipa3_usb_ctx->num_init_prot == 0)) {
- ipa3_usb_ctx->ttype_ctx[ttype].rm_ctx.prod_valid = false;
- ipa3_usb_ctx->ttype_ctx[ttype].rm_ctx.cons_valid = false;
- ipa_rm_delete_resource(
+ if (ipa_pm_is_used()) {
+ ipa3_usb_deregister_pm(ttype);
+ } else {
+ ipa3_usb_ctx->ttype_ctx[ttype].rm_ctx.prod_valid =
+ false;
+ ipa3_usb_ctx->ttype_ctx[ttype].rm_ctx.cons_valid =
+ false;
+ ipa_rm_delete_resource(
ipa3_usb_ctx->ttype_ctx[ttype].rm_ctx.prod_params.name);
- ipa_rm_delete_resource(
+ ipa_rm_delete_resource(
ipa3_usb_ctx->ttype_ctx[ttype].rm_ctx.cons_params.name);
+ }
}
bad_params:
mutex_unlock(&ipa3_usb_ctx->general_mutex);
@@ -1393,6 +1487,9 @@
{
int res = 0;
+ if (ipa_pm_is_used())
+ return 0;
+
/*
* Add DPL dependency to RM dependency graph, first add_dependency call
* is sync in order to make sure the IPA clocks are up before we
@@ -1572,6 +1669,9 @@
{
int res;
+ if (ipa_pm_is_used())
+ return 0;
+
/* Remove DPL RM dependency */
res = ipa_rm_delete_dependency(IPA_RM_RESOURCE_USB_DPL_DUMMY_PROD,
IPA_RM_RESOURCE_Q6_CONS);
@@ -1699,32 +1799,51 @@
return result;
}
- /* Set RM PROD & CONS perf profile */
- profile.max_supported_bandwidth_mbps =
- params->max_supported_bandwidth_mbps;
- result = ipa_rm_set_perf_profile(
- ipa3_usb_ctx->ttype_ctx[ttype].rm_ctx.prod_params.name,
- &profile);
- if (result) {
- IPA_USB_ERR("failed to set %s perf profile\n",
- ipa_rm_resource_str(ipa3_usb_ctx->ttype_ctx[ttype].
- rm_ctx.prod_params.name));
- return result;
- }
- result = ipa_rm_set_perf_profile(
- ipa3_usb_ctx->ttype_ctx[ttype].rm_ctx.cons_params.name,
- &profile);
- if (result) {
- IPA_USB_ERR("failed to set %s perf profile\n",
- ipa_rm_resource_str(ipa3_usb_ctx->ttype_ctx[ttype].
- rm_ctx.cons_params.name));
- return result;
- }
+ if (ipa_pm_is_used()) {
+ result = ipa_pm_set_perf_profile(
+ ipa3_usb_ctx->ttype_ctx[ttype].pm_ctx.hdl,
+ params->max_supported_bandwidth_mbps);
+ if (result) {
+ IPA_USB_ERR("failed to set perf profile\n");
+ return result;
+ }
- /* Request PROD */
- result = ipa3_usb_request_prod(ttype);
- if (result)
- return result;
+ result = ipa_pm_activate_sync(
+ ipa3_usb_ctx->ttype_ctx[ttype].pm_ctx.hdl);
+ if (result) {
+ IPA_USB_ERR("failed to activate pm\n");
+ return result;
+ }
+ } else {
+ /* Set RM PROD & CONS perf profile */
+ profile.max_supported_bandwidth_mbps =
+ params->max_supported_bandwidth_mbps;
+ result = ipa_rm_set_perf_profile(
+ ipa3_usb_ctx->ttype_ctx[ttype].rm_ctx.prod_params.name,
+ &profile);
+ if (result) {
+ IPA_USB_ERR("failed to set %s perf profile\n",
+ ipa_rm_resource_str(ipa3_usb_ctx->
+ ttype_ctx[ttype].
+ rm_ctx.prod_params.name));
+ return result;
+ }
+ result = ipa_rm_set_perf_profile(
+ ipa3_usb_ctx->ttype_ctx[ttype].rm_ctx.cons_params.name,
+ &profile);
+ if (result) {
+ IPA_USB_ERR("failed to set %s perf profile\n",
+ ipa_rm_resource_str(ipa3_usb_ctx->
+ ttype_ctx[ttype].
+ rm_ctx.cons_params.name));
+ return result;
+ }
+
+ /* Request PROD */
+ result = ipa3_usb_request_prod(ttype);
+ if (result)
+ return result;
+ }
if (params->teth_prot != IPA_USB_DIAG) {
/* Start UL channel */
@@ -1775,7 +1894,11 @@
ipa3_reset_gsi_event_ring(params->usb_to_ipa_clnt_hdl);
}
connect_ul_fail:
- ipa3_usb_release_prod(ttype);
+ if (ipa_pm_is_used())
+ ipa_pm_deactivate_sync(
+ ipa3_usb_ctx->ttype_ctx[ttype].pm_ctx.hdl);
+ else
+ ipa3_usb_release_prod(ttype);
return result;
}
@@ -2224,7 +2347,11 @@
goto bad_params;
if (orig_state != IPA_USB_SUSPENDED) {
- result = ipa3_usb_release_prod(ttype);
+ if (ipa_pm_is_used())
+ result = ipa_pm_deactivate_sync(
+ ipa3_usb_ctx->ttype_ctx[ttype].pm_ctx.hdl);
+ else
+ result = ipa3_usb_release_prod(ttype);
if (result) {
IPA_USB_ERR("failed to release PROD.\n");
goto bad_params;
@@ -2334,13 +2461,19 @@
(ipa3_usb_ctx->num_init_prot == 0)) {
if (!ipa3_usb_set_state(IPA_USB_INVALID, false, ttype))
IPA_USB_ERR("failed to change state to invalid\n");
- ipa_rm_delete_resource(
+ if (ipa_pm_is_used()) {
+ ipa3_usb_deregister_pm(ttype);
+ } else {
+ ipa_rm_delete_resource(
ipa3_usb_ctx->ttype_ctx[ttype].rm_ctx.prod_params.name);
- ipa3_usb_ctx->ttype_ctx[ttype].rm_ctx.prod_valid = false;
- ipa_rm_delete_resource(
+ ipa3_usb_ctx->ttype_ctx[ttype].rm_ctx.prod_valid =
+ false;
+ ipa_rm_delete_resource(
ipa3_usb_ctx->ttype_ctx[ttype].rm_ctx.cons_params.name);
- ipa3_usb_ctx->ttype_ctx[ttype].rm_ctx.cons_valid = false;
- ipa3_usb_ctx->ttype_ctx[ttype].ipa_usb_notify_cb = NULL;
+ ipa3_usb_ctx->ttype_ctx[ttype].rm_ctx.cons_valid =
+ false;
+ ipa3_usb_ctx->ttype_ctx[ttype].ipa_usb_notify_cb = NULL;
+ }
}
IPA_USB_DBG_LOW("exit\n");
@@ -2400,7 +2533,11 @@
if (result)
goto start_ul;
- result = ipa3_usb_release_prod(ttype);
+ if (ipa_pm_is_used())
+ result = ipa_pm_deactivate_sync(
+ ipa3_usb_ctx->ttype_ctx[ttype].pm_ctx.hdl);
+ else
+ result = ipa3_usb_release_prod(ttype);
if (result) {
IPA_USB_ERR("failed to release PROD.\n");
goto connect_teth;
@@ -2477,7 +2614,11 @@
}
ipa3_usb_ctx->qmi_req_id++;
- result = ipa3_usb_release_prod(ttype);
+ if (ipa_pm_is_used())
+ result = ipa_pm_deactivate_sync(
+ ipa3_usb_ctx->ttype_ctx[ttype].pm_ctx.hdl);
+ else
+ result = ipa3_usb_release_prod(ttype);
if (result) {
IPA_USB_ERR("failed to release PROD\n");
goto release_prod_fail;
@@ -2543,7 +2684,11 @@
"DPL channel":"Data Tethering channels");
/* Request USB_PROD */
- result = ipa3_usb_request_prod(ttype);
+ if (ipa_pm_is_used())
+ result = ipa_pm_activate_sync(
+ ipa3_usb_ctx->ttype_ctx[ttype].pm_ctx.hdl);
+ else
+ result = ipa3_usb_request_prod(ttype);
if (result)
goto fail_exit;
@@ -2590,7 +2735,11 @@
disconn_teth:
(void)ipa3_usb_disconnect_teth_prot(teth_prot);
release_prod:
- (void)ipa3_usb_release_prod(ttype);
+ if (ipa_pm_is_used())
+ (void)ipa_pm_deactivate_sync(
+ ipa3_usb_ctx->ttype_ctx[ttype].pm_ctx.hdl);
+ else
+ (void)ipa3_usb_release_prod(ttype);
fail_exit:
return result;
}
@@ -2642,7 +2791,11 @@
}
/* Request USB_PROD */
- result = ipa3_usb_request_prod(ttype);
+ if (ipa_pm_is_used())
+ result = ipa_pm_activate_sync(
+ ipa3_usb_ctx->ttype_ctx[ttype].pm_ctx.hdl);
+ else
+ result = ipa3_usb_request_prod(ttype);
if (result)
goto prod_req_fail;
@@ -2685,7 +2838,11 @@
IPA_USB_ERR("Error stopping UL channel: %d\n", result);
}
start_ul_fail:
- ipa3_usb_release_prod(ttype);
+ if (ipa_pm_is_used())
+ ipa_pm_deactivate_sync(
+ ipa3_usb_ctx->ttype_ctx[ttype].pm_ctx.hdl);
+ else
+ ipa3_usb_release_prod(ttype);
prod_req_fail:
/* Change state back to prev_state */
if (!ipa3_usb_set_state(prev_state, true, ttype))
@@ -2722,6 +2879,20 @@
ipa3_usb_ctx->dl_data_pending = false;
mutex_init(&ipa3_usb_ctx->general_mutex);
+ if (ipa_pm_is_used()) {
+ struct ipa3_usb_pm_context *pm_ctx;
+
+ pm_ctx =
+ &ipa3_usb_ctx->ttype_ctx[IPA_USB_TRANSPORT_TETH].pm_ctx;
+ pm_ctx->hdl = ~0;
+ pm_ctx->remote_wakeup_work =
+ &ipa3_usb_notify_remote_wakeup_work;
+ pm_ctx = &ipa3_usb_ctx->ttype_ctx[IPA_USB_TRANSPORT_DPL].pm_ctx;
+ pm_ctx->hdl = ~0;
+ pm_ctx->remote_wakeup_work =
+ &ipa3_usb_dpl_notify_remote_wakeup_work;
+ }
+
for (i = 0; i < IPA_USB_TRANSPORT_MAX; i++) {
ipa3_usb_ctx->ttype_ctx[i].rm_ctx.prod_valid = false;
ipa3_usb_ctx->ttype_ctx[i].rm_ctx.cons_valid = false;
diff --git a/drivers/platform/msm/ipa/ipa_clients/odu_bridge.c b/drivers/platform/msm/ipa/ipa_clients/odu_bridge.c
index a623d0b..f0d1102 100644
--- a/drivers/platform/msm/ipa/ipa_clients/odu_bridge.c
+++ b/drivers/platform/msm/ipa/ipa_clients/odu_bridge.c
@@ -27,6 +27,7 @@
#include <linux/cdev.h>
#include <linux/ipa_odu_bridge.h>
#include "../ipa_common_i.h"
+#include "../ipa_v3/ipa_pm.h"
#define ODU_BRIDGE_DRV_NAME "odu_ipa_bridge"
@@ -152,6 +153,7 @@
void *logbuf_low;
struct completion rm_comp;
void (*wakeup_request)(void *);
+ u32 pm_hdl;
};
static struct odu_bridge_ctx *odu_bridge_ctx;
@@ -273,20 +275,22 @@
memset(&odu_prod_params, 0, sizeof(odu_prod_params));
memset(&odu_emb_cons_params, 0, sizeof(odu_emb_cons_params));
- /* Build IPA Resource manager dependency graph */
- ODU_BRIDGE_DBG_LOW("build dependency graph\n");
- res = ipa_rm_add_dependency(IPA_RM_RESOURCE_ODU_ADAPT_PROD,
+ if (!ipa_pm_is_used()) {
+ /* Build IPA Resource manager dependency graph */
+ ODU_BRIDGE_DBG_LOW("build dependency graph\n");
+ res = ipa_rm_add_dependency(IPA_RM_RESOURCE_ODU_ADAPT_PROD,
IPA_RM_RESOURCE_Q6_CONS);
- if (res && res != -EINPROGRESS) {
- ODU_BRIDGE_ERR("ipa_rm_add_dependency() failed\n");
- goto fail_add_dependency_1;
- }
+ if (res && res != -EINPROGRESS) {
+ ODU_BRIDGE_ERR("ipa_rm_add_dependency() failed\n");
+ goto fail_add_dependency_1;
+ }
- res = ipa_rm_add_dependency(IPA_RM_RESOURCE_Q6_PROD,
+ res = ipa_rm_add_dependency(IPA_RM_RESOURCE_Q6_PROD,
IPA_RM_RESOURCE_ODU_ADAPT_CONS);
- if (res && res != -EINPROGRESS) {
- ODU_BRIDGE_ERR("ipa_rm_add_dependency() failed\n");
- goto fail_add_dependency_2;
+ if (res && res != -EINPROGRESS) {
+ ODU_BRIDGE_ERR("ipa_rm_add_dependency() failed\n");
+ goto fail_add_dependency_2;
+ }
}
/* configure RX (ODU->IPA) EP */
@@ -346,10 +350,12 @@
ipa_teardown_sys_pipe(odu_bridge_ctx->odu_prod_hdl);
odu_bridge_ctx->odu_prod_hdl = 0;
fail_odu_prod:
- ipa_rm_delete_dependency(IPA_RM_RESOURCE_Q6_PROD,
+ if (!ipa_pm_is_used())
+ ipa_rm_delete_dependency(IPA_RM_RESOURCE_Q6_PROD,
IPA_RM_RESOURCE_ODU_ADAPT_CONS);
fail_add_dependency_2:
- ipa_rm_delete_dependency(IPA_RM_RESOURCE_ODU_ADAPT_PROD,
+ if (!ipa_pm_is_used())
+ ipa_rm_delete_dependency(IPA_RM_RESOURCE_ODU_ADAPT_PROD,
IPA_RM_RESOURCE_Q6_CONS);
fail_add_dependency_1:
return res;
@@ -397,17 +403,19 @@
ODU_BRIDGE_ERR("teardown ODU EMB CONS failed\n");
odu_bridge_ctx->odu_emb_cons_hdl = 0;
- /* Delete IPA Resource manager dependency graph */
- ODU_BRIDGE_DBG("deleting dependency graph\n");
- res = ipa_rm_delete_dependency(IPA_RM_RESOURCE_ODU_ADAPT_PROD,
- IPA_RM_RESOURCE_Q6_CONS);
- if (res && res != -EINPROGRESS)
- ODU_BRIDGE_ERR("ipa_rm_delete_dependency() failed\n");
+ if (!ipa_pm_is_used()) {
+ /* Delete IPA Resource manager dependency graph */
+ ODU_BRIDGE_DBG("deleting dependency graph\n");
+ res = ipa_rm_delete_dependency(IPA_RM_RESOURCE_ODU_ADAPT_PROD,
+ IPA_RM_RESOURCE_Q6_CONS);
+ if (res && res != -EINPROGRESS)
+ ODU_BRIDGE_ERR("ipa_rm_delete_dependency() failed\n");
- res = ipa_rm_delete_dependency(IPA_RM_RESOURCE_Q6_PROD,
- IPA_RM_RESOURCE_ODU_ADAPT_CONS);
- if (res && res != -EINPROGRESS)
- ODU_BRIDGE_ERR("ipa_rm_delete_dependency() failed\n");
+ res = ipa_rm_delete_dependency(IPA_RM_RESOURCE_Q6_PROD,
+ IPA_RM_RESOURCE_ODU_ADAPT_CONS);
+ if (res && res != -EINPROGRESS)
+ ODU_BRIDGE_ERR("ipa_rm_delete_dependency() failed\n");
+ }
return 0;
}
@@ -1319,24 +1327,58 @@
return 0;
}
-/* IPA Bridge API is the new API which will replaces old odu_bridge API */
-int ipa_bridge_init(struct ipa_bridge_init_params *params, u32 *hdl)
+static void ipa_br_pm_cb(void *p, enum ipa_pm_cb_event event)
+{
+ ODU_BRIDGE_FUNC_ENTRY();
+ if (event != IPA_PM_REQUEST_WAKEUP) {
+ ODU_BRIDGE_ERR("Unexpected event %d\n", event);
+ WARN_ON(1);
+ return;
+ }
+
+ if (odu_bridge_ctx->is_suspended)
+ odu_bridge_ctx->wakeup_request(odu_bridge_ctx->priv);
+ ODU_BRIDGE_FUNC_EXIT();
+}
+
+static int ipa_br_register_pm(void)
+{
+ struct ipa_pm_register_params reg_params;
+ int ret;
+
+ memset(®_params, 0, sizeof(reg_params));
+ reg_params.name = "ODU Bridge";
+ reg_params.callback = ipa_br_pm_cb;
+ reg_params.group = IPA_PM_GROUP_DEFAULT;
+
+ ret = ipa_pm_register(®_params,
+ &odu_bridge_ctx->pm_hdl);
+ if (ret) {
+ ODU_BRIDGE_ERR("fail to register with PM %d\n", ret);
+ goto fail_pm_reg;
+ }
+
+ ret = ipa_pm_associate_ipa_cons_to_client(odu_bridge_ctx->pm_hdl,
+ IPA_CLIENT_ODU_EMB_CONS);
+ if (ret) {
+ ODU_BRIDGE_ERR("fail to associate cons with PM %d\n", ret);
+ goto fail_pm_cons;
+ }
+
+ return 0;
+
+fail_pm_cons:
+ ipa_pm_deregister(odu_bridge_ctx->pm_hdl);
+ odu_bridge_ctx->pm_hdl = ~0;
+fail_pm_reg:
+ return ret;
+}
+
+static int ipa_br_create_rm_resources(void)
{
int ret;
struct ipa_rm_create_params create_params;
- if (!params || !params->wakeup_request || !hdl) {
- ODU_BRIDGE_ERR("NULL arg\n");
- return -EINVAL;
- }
-
-
- ret = odu_bridge_init(¶ms->info);
- if (ret)
- return ret;
-
- odu_bridge_ctx->wakeup_request = params->wakeup_request;
-
/* create IPA RM resources for power management */
init_completion(&odu_bridge_ctx->rm_comp);
memset(&create_params, 0, sizeof(create_params));
@@ -1368,9 +1410,6 @@
goto fail_rm_cons;
}
- /* handle is ignored for now */
- *hdl = 0;
-
return 0;
fail_rm_cons:
@@ -1379,6 +1418,41 @@
fail_add_dep:
ipa_rm_delete_resource(IPA_RM_RESOURCE_ODU_ADAPT_PROD);
fail_rm_prod:
+ return ret;
+}
+
+/* IPA Bridge API is the new API which will replaces old odu_bridge API */
+int ipa_bridge_init(struct ipa_bridge_init_params *params, u32 *hdl)
+{
+ int ret;
+
+ if (!params || !params->wakeup_request || !hdl) {
+ ODU_BRIDGE_ERR("NULL arg\n");
+ return -EINVAL;
+ }
+
+
+ ret = odu_bridge_init(¶ms->info);
+ if (ret)
+ return ret;
+
+ odu_bridge_ctx->wakeup_request = params->wakeup_request;
+
+ if (ipa_pm_is_used())
+ ret = ipa_br_register_pm();
+ else
+ ret = ipa_br_create_rm_resources();
+ if (ret) {
+ ODU_BRIDGE_ERR("fail to register woth RM/PM %d\n", ret);
+ goto fail_pm;
+ }
+
+ /* handle is ignored for now */
+ *hdl = 0;
+
+ return 0;
+
+fail_pm:
odu_bridge_cleanup();
return ret;
}
@@ -1398,7 +1472,10 @@
return -EFAULT;
}
- ret = ipa_br_request_prod();
+ if (ipa_pm_is_used())
+ ret = ipa_pm_activate_sync(odu_bridge_ctx->pm_hdl);
+ else
+ ret = ipa_br_request_prod();
if (ret)
return ret;
@@ -1411,6 +1488,10 @@
struct ipa_rm_perf_profile profile = {0};
int ret;
+ if (ipa_pm_is_used())
+ return ipa_pm_set_perf_profile(odu_bridge_ctx->pm_hdl,
+ bandwidth);
+
profile.max_supported_bandwidth_mbps = bandwidth;
ret = ipa_rm_set_perf_profile(IPA_RM_RESOURCE_ODU_ADAPT_PROD, &profile);
if (ret) {
@@ -1436,7 +1517,10 @@
if (ret)
return ret;
- ret = ipa_br_release_prod();
+ if (ipa_pm_is_used())
+ ret = ipa_pm_deactivate_sync(odu_bridge_ctx->pm_hdl);
+ else
+ ret = ipa_br_release_prod();
if (ret)
return ret;
@@ -1470,7 +1554,10 @@
return ret;
}
- ret = ipa_br_release_prod();
+ if (ipa_pm_is_used())
+ ret = ipa_pm_deactivate_sync(odu_bridge_ctx->pm_hdl);
+ else
+ ret = ipa_br_release_prod();
if (ret) {
ODU_BRIDGE_ERR("failed to release prod %d\n", ret);
ipa_start_gsi_channel(odu_bridge_ctx->odu_emb_cons_hdl);
@@ -1501,7 +1588,10 @@
return -EFAULT;
}
- ret = ipa_br_request_prod();
+ if (ipa_pm_is_used())
+ ret = ipa_pm_activate_sync(odu_bridge_ctx->pm_hdl);
+ else
+ ret = ipa_br_request_prod();
if (ret)
return ret;
@@ -1523,12 +1613,27 @@
}
EXPORT_SYMBOL(ipa_bridge_tx_dp);
-int ipa_bridge_cleanup(u32 hdl)
+static void ipa_br_delete_rm_resources(void)
{
ipa_rm_delete_dependency(IPA_RM_RESOURCE_ODU_ADAPT_PROD,
IPA_RM_RESOURCE_APPS_CONS);
ipa_rm_delete_resource(IPA_RM_RESOURCE_ODU_ADAPT_PROD);
ipa_rm_delete_resource(IPA_RM_RESOURCE_ODU_ADAPT_CONS);
+}
+
+static void ipa_br_deregister_pm(void)
+{
+ ipa_pm_deactivate_sync(odu_bridge_ctx->pm_hdl);
+ ipa_pm_deregister(odu_bridge_ctx->pm_hdl);
+ odu_bridge_ctx->pm_hdl = ~0;
+}
+
+int ipa_bridge_cleanup(u32 hdl)
+{
+ if (ipa_pm_is_used())
+ ipa_br_deregister_pm();
+ else
+ ipa_br_delete_rm_resources();
return odu_bridge_cleanup();
}
EXPORT_SYMBOL(ipa_bridge_cleanup);
diff --git a/drivers/platform/msm/ipa/ipa_clients/rndis_ipa.c b/drivers/platform/msm/ipa/ipa_clients/rndis_ipa.c
index f62cb27..1c47e69 100644
--- a/drivers/platform/msm/ipa/ipa_clients/rndis_ipa.c
+++ b/drivers/platform/msm/ipa/ipa_clients/rndis_ipa.c
@@ -9,7 +9,6 @@
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
-
#include <linux/atomic.h>
#include <linux/errno.h>
#include <linux/etherdevice.h>
@@ -27,6 +26,8 @@
#include <linux/random.h>
#include <linux/rndis_ipa.h>
#include <linux/workqueue.h>
+#include "../ipa_common_i.h"
+#include "../ipa_v3/ipa_pm.h"
#define CREATE_TRACE_POINTS
#include "rndis_ipa_trace.h"
@@ -160,6 +161,7 @@
* state is changed to RNDIS_IPA_CONNECTED_AND_UP
* @xmit_error_delayed_work: work item for cases where IPA driver Tx fails
* @state_lock: used to protect the state variable.
+ * @pm_hdl: handle for IPA PM framework
*/
struct rndis_ipa_dev {
struct net_device *net;
@@ -188,6 +190,7 @@
void (*device_ready_notify)(void);
struct delayed_work xmit_error_delayed_work;
spinlock_t state_lock; /* Spinlock for the state variable.*/
+ u32 pm_hdl;
};
/**
@@ -233,6 +236,8 @@
unsigned long data);
static int rndis_ipa_create_rm_resource(struct rndis_ipa_dev *rndis_ipa_ctx);
static int rndis_ipa_destroy_rm_resource(struct rndis_ipa_dev *rndis_ipa_ctx);
+static int rndis_ipa_register_pm_client(struct rndis_ipa_dev *rndis_ipa_ctx);
+static int rndis_ipa_deregister_pm_client(struct rndis_ipa_dev *rndis_ipa_ctx);
static bool rx_filter(struct sk_buff *skb);
static bool tx_filter(struct sk_buff *skb);
static bool rm_enabled(struct rndis_ipa_dev *rndis_ipa_ctx);
@@ -701,7 +706,10 @@
return -EINVAL;
}
- result = rndis_ipa_create_rm_resource(rndis_ipa_ctx);
+ if (ipa_pm_is_used())
+ result = rndis_ipa_register_pm_client(rndis_ipa_ctx);
+ else
+ result = rndis_ipa_create_rm_resource(rndis_ipa_ctx);
if (result) {
RNDIS_IPA_ERROR("fail on RM create\n");
goto fail_create_rm;
@@ -763,7 +771,10 @@
return 0;
fail:
- rndis_ipa_destroy_rm_resource(rndis_ipa_ctx);
+ if (ipa_pm_is_used())
+ rndis_ipa_deregister_pm_client(rndis_ipa_ctx);
+ else
+ rndis_ipa_destroy_rm_resource(rndis_ipa_ctx);
fail_create_rm:
return result;
}
@@ -1235,7 +1246,10 @@
rndis_ipa_ctx->net->stats.tx_dropped += outstanding_dropped_pkts;
atomic_set(&rndis_ipa_ctx->outstanding_pkts, 0);
- retval = rndis_ipa_destroy_rm_resource(rndis_ipa_ctx);
+ if (ipa_pm_is_used())
+ retval = rndis_ipa_deregister_pm_client(rndis_ipa_ctx);
+ else
+ retval = rndis_ipa_destroy_rm_resource(rndis_ipa_ctx);
if (retval) {
RNDIS_IPA_ERROR("Fail to clean RM\n");
return retval;
@@ -1772,6 +1786,29 @@
return result;
}
+static void rndis_ipa_pm_cb(void *p, enum ipa_pm_cb_event event)
+{
+ struct rndis_ipa_dev *rndis_ipa_ctx = p;
+
+ RNDIS_IPA_LOG_ENTRY();
+
+ if (event != IPA_PM_CLIENT_ACTIVATED) {
+ RNDIS_IPA_ERROR("unexpected event %d\n", event);
+ WARN_ON(1);
+ return;
+ }
+ RNDIS_IPA_DEBUG("Resource Granted\n");
+
+ if (netif_queue_stopped(rndis_ipa_ctx->net)) {
+ RNDIS_IPA_DEBUG("starting queue\n");
+ netif_start_queue(rndis_ipa_ctx->net);
+ } else {
+ RNDIS_IPA_DEBUG("queue already awake\n");
+ }
+
+ RNDIS_IPA_LOG_EXIT();
+}
+
/**
* rndis_ipa_destroy_rm_resource() - delete the dependency and destroy
* the resource done on rndis_ipa_create_rm_resource()
@@ -1831,6 +1868,33 @@
return result;
}
+static int rndis_ipa_register_pm_client(struct rndis_ipa_dev *rndis_ipa_ctx)
+{
+ int result;
+ struct ipa_pm_register_params pm_reg;
+
+ memset(&pm_reg, 0, sizeof(pm_reg));
+
+ pm_reg.name = rndis_ipa_ctx->net->name;
+ pm_reg.user_data = rndis_ipa_ctx;
+ pm_reg.callback = rndis_ipa_pm_cb;
+ pm_reg.group = IPA_PM_GROUP_APPS;
+ result = ipa_pm_register(&pm_reg, &rndis_ipa_ctx->pm_hdl);
+ if (result) {
+ RNDIS_IPA_ERROR("failed to create IPA PM client %d\n", result);
+ return result;
+ }
+ return 0;
+}
+
+static int rndis_ipa_deregister_pm_client(struct rndis_ipa_dev *rndis_ipa_ctx)
+{
+ ipa_pm_deactivate_sync(rndis_ipa_ctx->pm_hdl);
+ ipa_pm_deregister(rndis_ipa_ctx->pm_hdl);
+ rndis_ipa_ctx->pm_hdl = ~0;
+ return 0;
+}
+
/**
* resource_request() - request for the Netdev resource
* @rndis_ipa_ctx: main driver context
@@ -1849,11 +1913,14 @@
int result = 0;
if (!rm_enabled(rndis_ipa_ctx))
- goto out;
- result = ipa_rm_inactivity_timer_request_resource(
+ return result;
+
+ if (ipa_pm_is_used())
+ return ipa_pm_activate(rndis_ipa_ctx->pm_hdl);
+
+ return ipa_rm_inactivity_timer_request_resource(
DRV_RESOURCE_ID);
-out:
- return result;
+
}
/**
@@ -1868,9 +1935,12 @@
static void resource_release(struct rndis_ipa_dev *rndis_ipa_ctx)
{
if (!rm_enabled(rndis_ipa_ctx))
- goto out;
- ipa_rm_inactivity_timer_release_resource(DRV_RESOURCE_ID);
-out:
+ return;
+ if (ipa_pm_is_used())
+ ipa_pm_deferred_deactivate(rndis_ipa_ctx->pm_hdl);
+ else
+ ipa_rm_inactivity_timer_release_resource(DRV_RESOURCE_ID);
+
return;
}
diff --git a/drivers/platform/msm/ipa/ipa_common_i.h b/drivers/platform/msm/ipa/ipa_common_i.h
index 32c8b25..a487bf4 100644
--- a/drivers/platform/msm/ipa/ipa_common_i.h
+++ b/drivers/platform/msm/ipa/ipa_common_i.h
@@ -386,4 +386,6 @@
const char *ipa_get_version_string(enum ipa_hw_type ver);
int ipa_start_gsi_channel(u32 clnt_hdl);
+bool ipa_pm_is_used(void);
+
#endif /* _IPA_COMMON_I_H_ */
diff --git a/drivers/platform/msm/ipa/ipa_v2/ipa_debugfs.c b/drivers/platform/msm/ipa/ipa_v2/ipa_debugfs.c
index 2b517a1..7aa7ffd 100644
--- a/drivers/platform/msm/ipa/ipa_v2/ipa_debugfs.c
+++ b/drivers/platform/msm/ipa/ipa_v2/ipa_debugfs.c
@@ -811,10 +811,11 @@
eq = true;
} else {
rt_tbl = ipa_id_find(entry->rule.rt_tbl_hdl);
- if (rt_tbl)
- rt_tbl_idx = rt_tbl->idx;
+ if (rt_tbl == NULL ||
+ rt_tbl->cookie != IPA_RT_TBL_COOKIE)
+ rt_tbl_idx = ~0;
else
- rt_tbl_idx = ~0;
+ rt_tbl_idx = rt_tbl->idx;
bitmap = entry->rule.attrib.attrib_mask;
eq = false;
}
@@ -841,10 +842,11 @@
eq = true;
} else {
rt_tbl = ipa_id_find(entry->rule.rt_tbl_hdl);
- if (rt_tbl)
- rt_tbl_idx = rt_tbl->idx;
- else
+ if (rt_tbl == NULL ||
+ rt_tbl->cookie != IPA_RT_TBL_COOKIE)
rt_tbl_idx = ~0;
+ else
+ rt_tbl_idx = rt_tbl->idx;
bitmap = entry->rule.attrib.attrib_mask;
eq = false;
}
diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa.c b/drivers/platform/msm/ipa/ipa_v3/ipa.c
index 55dd899..097eec8 100644
--- a/drivers/platform/msm/ipa/ipa_v3/ipa.c
+++ b/drivers/platform/msm/ipa/ipa_v3/ipa.c
@@ -1466,6 +1466,10 @@
}
break;
case IPA_IOC_RM_ADD_DEPENDENCY:
+ /* deprecate if IPA PM is used */
+ if (ipa3_ctx->use_ipa_pm)
+ return 0;
+
if (copy_from_user((u8 *)&rm_depend, (u8 *)arg,
sizeof(struct ipa_ioc_rm_dependency))) {
retval = -EFAULT;
@@ -1475,6 +1479,10 @@
rm_depend.resource_name, rm_depend.depends_on_name);
break;
case IPA_IOC_RM_DEL_DEPENDENCY:
+ /* deprecate if IPA PM is used */
+ if (ipa3_ctx->use_ipa_pm)
+ return 0;
+
if (copy_from_user((u8 *)&rm_depend, (u8 *)arg,
sizeof(struct ipa_ioc_rm_dependency))) {
retval = -EFAULT;
@@ -3831,14 +3839,19 @@
u32 i = 0;
int res;
struct ipa_ep_cfg_holb holb_cfg;
+ u32 pipe_bitmask = 0;
IPADBG("interrupt=%d, interrupt_data=%u\n",
interrupt, suspend_data);
memset(&holb_cfg, 0, sizeof(holb_cfg));
holb_cfg.tmr_val = 0;
- for (i = 0; i < ipa3_ctx->ipa_num_pipes; i++) {
+ for (i = 0; i < ipa3_ctx->ipa_num_pipes; i++, bmsk = bmsk << 1) {
if ((suspend_data & bmsk) && (ipa3_ctx->ep[i].valid)) {
+ if (ipa3_ctx->use_ipa_pm) {
+ pipe_bitmask |= bmsk;
+ continue;
+ }
if (IPA_CLIENT_IS_APPS_CONS(ipa3_ctx->ep[i].client)) {
/*
* pipe will be unsuspended as part of
@@ -3877,7 +3890,13 @@
}
}
}
- bmsk = bmsk << 1;
+ }
+ if (ipa3_ctx->use_ipa_pm) {
+ res = ipa_pm_handle_suspend(pipe_bitmask);
+ if (res) {
+ IPAERR("ipa_pm_handle_suspend failed %d\n", res);
+ return;
+ }
}
}
@@ -4408,6 +4427,8 @@
if (IS_ERR_OR_NULL(subsystem_get_retval)) {
IPAERR("Unable to trigger PIL process for FW loading\n");
return -EINVAL;
+ } else {
+ subsystem_put(subsystem_get_retval);
}
IPADBG("PIL FW loading process is complete\n");
@@ -4638,6 +4659,7 @@
ipa3_ctx->ee = resource_p->ee;
ipa3_ctx->apply_rg10_wa = resource_p->apply_rg10_wa;
ipa3_ctx->gsi_ch20_wa = resource_p->gsi_ch20_wa;
+ ipa3_ctx->use_ipa_pm = resource_p->use_ipa_pm;
ipa3_ctx->ipa3_active_clients_logging.log_rdy = false;
if (resource_p->ipa_tz_unlock_reg) {
ipa3_ctx->ipa_tz_unlock_reg_num =
@@ -4951,20 +4973,30 @@
wakeup_source_init(&ipa3_ctx->w_lock, "IPA_WS");
spin_lock_init(&ipa3_ctx->wakelock_ref_cnt.spinlock);
- /* Initialize IPA RM (resource manager) */
- result = ipa_rm_initialize();
- if (result) {
- IPAERR("RM initialization failed (%d)\n", -result);
- result = -ENODEV;
- goto fail_ipa_rm_init;
- }
- IPADBG("IPA resource manager initialized");
+ /* Initialize Power Management framework */
+ if (ipa3_ctx->use_ipa_pm) {
+ result = ipa_pm_init(&ipa3_res.pm_init);
+ if (result) {
+ IPAERR("IPA PM initialization failed (%d)\n", -result);
+ result = -ENODEV;
+ goto fail_ipa_rm_init;
+ }
+ IPADBG("IPA resource manager initialized");
+ } else {
+ result = ipa_rm_initialize();
+ if (result) {
+ IPAERR("RM initialization failed (%d)\n", -result);
+ result = -ENODEV;
+ goto fail_ipa_rm_init;
+ }
+ IPADBG("IPA resource manager initialized");
- result = ipa3_create_apps_resource();
- if (result) {
- IPAERR("Failed to create APPS_CONS resource\n");
- result = -ENODEV;
- goto fail_create_apps_resource;
+ result = ipa3_create_apps_resource();
+ if (result) {
+ IPAERR("Failed to create APPS_CONS resource\n");
+ result = -ENODEV;
+ goto fail_create_apps_resource;
+ }
}
result = ipa3_alloc_pkt_init();
@@ -5015,9 +5047,11 @@
fail_cdev_add:
fail_ipa_init_interrupts:
- ipa_rm_delete_resource(IPA_RM_RESOURCE_APPS_CONS);
+ if (!ipa3_ctx->use_ipa_pm)
+ ipa_rm_delete_resource(IPA_RM_RESOURCE_APPS_CONS);
fail_create_apps_resource:
- ipa_rm_exit();
+ if (!ipa3_ctx->use_ipa_pm)
+ ipa_rm_exit();
fail_ipa_rm_init:
fail_nat_dev_add:
device_destroy(ipa3_ctx->class, ipa3_ctx->dev_num);
@@ -5086,6 +5120,101 @@
return result;
}
+bool ipa_pm_is_used(void)
+{
+ return (ipa3_ctx) ? ipa3_ctx->use_ipa_pm : false;
+}
+
+static int get_ipa_dts_pm_info(struct platform_device *pdev,
+ struct ipa3_plat_drv_res *ipa_drv_res)
+{
+ int result;
+ int i, j;
+
+ ipa_drv_res->use_ipa_pm = of_property_read_bool(pdev->dev.of_node,
+ "qcom,use-ipa-pm");
+ IPADBG("use_ipa_pm=%d\n", ipa_drv_res->use_ipa_pm);
+ if (!ipa_drv_res->use_ipa_pm)
+ return 0;
+
+ result = of_property_read_u32(pdev->dev.of_node,
+ "qcom,msm-bus,num-cases",
+ &ipa_drv_res->pm_init.threshold_size);
+ /* No vote is ignored */
+ ipa_drv_res->pm_init.threshold_size -= 2;
+ if (result || ipa_drv_res->pm_init.threshold_size >
+ IPA_PM_THRESHOLD_MAX) {
+ IPAERR("invalid property qcom,msm-bus,num-cases %d\n",
+ ipa_drv_res->pm_init.threshold_size);
+ return -EFAULT;
+ }
+
+ result = of_property_read_u32_array(pdev->dev.of_node,
+ "qcom,throughput-threshold",
+ ipa_drv_res->pm_init.default_threshold,
+ ipa_drv_res->pm_init.threshold_size);
+ if (result) {
+ IPAERR("failed to read qcom,throughput-thresholds\n");
+ return -EFAULT;
+ }
+
+ result = of_property_count_strings(pdev->dev.of_node,
+ "qcom,scaling-exceptions");
+ if (result < 0) {
+ IPADBG("no exception list for ipa pm\n");
+ result = 0;
+ }
+
+ if (result % (ipa_drv_res->pm_init.threshold_size + 1)) {
+ IPAERR("failed to read qcom,scaling-exceptions\n");
+ return -EFAULT;
+ }
+
+ ipa_drv_res->pm_init.exception_size = result /
+ (ipa_drv_res->pm_init.threshold_size + 1);
+ if (ipa_drv_res->pm_init.exception_size >=
+ IPA_PM_EXCEPTION_MAX) {
+ IPAERR("exception list larger then max %d\n",
+ ipa_drv_res->pm_init.exception_size);
+ return -EFAULT;
+ }
+
+ for (i = 0; i < ipa_drv_res->pm_init.exception_size; i++) {
+ struct ipa_pm_exception *ex = ipa_drv_res->pm_init.exceptions;
+
+ result = of_property_read_string_index(pdev->dev.of_node,
+ "qcom,scaling-exceptions",
+ i * ipa_drv_res->pm_init.threshold_size,
+ &ex[i].usecase);
+ if (result) {
+ IPAERR("failed to read qcom,scaling-exceptions");
+ return -EFAULT;
+ }
+
+ for (j = 0; j < ipa_drv_res->pm_init.threshold_size; j++) {
+ const char *str;
+
+ result = of_property_read_string_index(
+ pdev->dev.of_node,
+ "qcom,scaling-exceptions",
+ i * ipa_drv_res->pm_init.threshold_size + j + 1,
+ &str);
+ if (result) {
+ IPAERR("failed to read qcom,scaling-exceptions"
+ );
+ return -EFAULT;
+ }
+
+ if (kstrtou32(str, 0, &ex[i].threshold[j])) {
+ IPAERR("error str=%s\n", str);
+ return -EFAULT;
+ }
+ }
+ }
+
+ return 0;
+}
+
static int get_ipa_dts_configuration(struct platform_device *pdev,
struct ipa3_plat_drv_res *ipa_drv_res)
{
@@ -5324,6 +5453,14 @@
}
kfree(ipa_tz_unlock_reg);
}
+
+ /* get IPA PM related information */
+ result = get_ipa_dts_pm_info(pdev, ipa_drv_res);
+ if (result) {
+ IPAERR("failed to get pm info from dts %d\n", result);
+ return result;
+ }
+
return 0;
}
@@ -5861,11 +5998,16 @@
}
}
- /*
- * Release transport IPA resource without waiting for inactivity timer
- */
- atomic_set(&ipa3_ctx->transport_pm.eot_activity, 0);
- ipa3_transport_release_resource(NULL);
+ if (ipa3_ctx->use_ipa_pm) {
+ ipa_pm_deactivate_all_deferred();
+ } else {
+ /*
+ * Release transport IPA resource without waiting
+ * for inactivity timer
+ */
+ atomic_set(&ipa3_ctx->transport_pm.eot_activity, 0);
+ ipa3_transport_release_resource(NULL);
+ }
IPADBG("Exit\n");
return 0;
diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_debugfs.c b/drivers/platform/msm/ipa/ipa_v3/ipa_debugfs.c
index 153548b..f72f41c 100644
--- a/drivers/platform/msm/ipa/ipa_v3/ipa_debugfs.c
+++ b/drivers/platform/msm/ipa/ipa_v3/ipa_debugfs.c
@@ -910,10 +910,11 @@
eq = true;
} else {
rt_tbl = ipa3_id_find(entry->rule.rt_tbl_hdl);
- if (rt_tbl)
- rt_tbl_idx = rt_tbl->idx;
+ if (rt_tbl == NULL ||
+ rt_tbl->cookie != IPA_RT_TBL_COOKIE)
+ rt_tbl_idx = ~0;
else
- rt_tbl_idx = ~0;
+ rt_tbl_idx = rt_tbl->idx;
bitmap = entry->rule.attrib.attrib_mask;
eq = false;
}
@@ -1705,6 +1706,10 @@
{
int result, nbytes, cnt = 0;
+ /* deprecate if IPA PM is used */
+ if (ipa3_ctx->use_ipa_pm)
+ return 0;
+
result = ipa_rm_stat(dbg_buff, IPA_MAX_MSG_LEN);
if (result < 0) {
nbytes = scnprintf(dbg_buff, IPA_MAX_MSG_LEN,
@@ -1716,6 +1721,45 @@
return simple_read_from_buffer(ubuf, count, ppos, dbg_buff, cnt);
}
+static ssize_t ipa3_pm_read_stats(struct file *file, char __user *ubuf,
+ size_t count, loff_t *ppos)
+{
+ int result, nbytes, cnt = 0;
+
+ if (!ipa3_ctx->use_ipa_pm)
+ return 0;
+
+ result = ipa_pm_stat(dbg_buff, IPA_MAX_MSG_LEN);
+ if (result < 0) {
+ nbytes = scnprintf(dbg_buff, IPA_MAX_MSG_LEN,
+ "Error in printing PM stat %d\n", result);
+ cnt += nbytes;
+ } else
+ cnt += result;
+
+ return simple_read_from_buffer(ubuf, count, ppos, dbg_buff, cnt);
+}
+
+static ssize_t ipa3_pm_ex_read_stats(struct file *file, char __user *ubuf,
+ size_t count, loff_t *ppos)
+{
+ int result, nbytes, cnt = 0;
+
+ if (!ipa3_ctx->use_ipa_pm)
+ return 0;
+
+ result = ipa_pm_exceptions_stat(dbg_buff, IPA_MAX_MSG_LEN);
+ if (result < 0) {
+ nbytes = scnprintf(dbg_buff, IPA_MAX_MSG_LEN,
+ "Error in printing PM stat %d\n", result);
+ cnt += nbytes;
+ } else
+ cnt += result;
+
+ return simple_read_from_buffer(ubuf, count, ppos, dbg_buff, cnt);
+}
+
+
static void ipa_dump_status(struct ipahal_pkt_status *status)
{
IPA_DUMP_STATUS_FIELD(status_opcode);
@@ -1940,6 +1984,15 @@
.read = ipa3_rm_read_stats,
};
+static const struct file_operations ipa3_pm_stats = {
+ .read = ipa3_pm_read_stats,
+};
+
+
+static const struct file_operations ipa3_pm_ex_stats = {
+ .read = ipa3_pm_ex_read_stats,
+};
+
const struct file_operations ipa3_active_clients = {
.read = ipa3_print_active_clients_log,
.write = ipa3_clear_active_clients_log,
@@ -2131,11 +2184,27 @@
goto fail;
}
- dfile_rm_stats = debugfs_create_file("rm_stats",
- read_only_mode, dent, 0, &ipa3_rm_stats);
- if (!dfile_rm_stats || IS_ERR(dfile_rm_stats)) {
- IPAERR("fail to create file for debug_fs rm_stats\n");
- goto fail;
+ if (ipa3_ctx->use_ipa_pm) {
+ file = dfile_rm_stats = debugfs_create_file("pm_stats",
+ read_only_mode, dent, NULL, &ipa3_pm_stats);
+ if (!file || IS_ERR(file)) {
+ IPAERR("fail to create file for debug_fs pm_stats\n");
+ goto fail;
+ }
+
+ file = dfile_rm_stats = debugfs_create_file("pm_ex_stats",
+ read_only_mode, dent, NULL, &ipa3_pm_ex_stats);
+ if (!file || IS_ERR(file)) {
+ IPAERR("fail to create file for debugfs pm_ex_stats\n");
+ goto fail;
+ }
+ } else {
+ dfile_rm_stats = debugfs_create_file("rm_stats",
+ read_only_mode, dent, NULL, &ipa3_rm_stats);
+ if (!dfile_rm_stats || IS_ERR(dfile_rm_stats)) {
+ IPAERR("fail to create file for debug_fs rm_stats\n");
+ goto fail;
+ }
}
dfile_status_stats = debugfs_create_file("status_stats",
diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_dp.c b/drivers/platform/msm/ipa/ipa_v3/ipa_dp.c
index 26d5f5e..7f30a10 100644
--- a/drivers/platform/msm/ipa/ipa_v3/ipa_dp.c
+++ b/drivers/platform/msm/ipa/ipa_v3/ipa_dp.c
@@ -73,6 +73,8 @@
#define IPA_TX_SEND_COMPL_NOP_DELAY_NS (2 * 1000 * 1000)
+#define IPA_APPS_BW_FOR_PM 700
+
static struct sk_buff *ipa3_get_skb_ipa_rx(unsigned int len, gfp_t flags);
static void ipa3_replenish_wlan_rx_cache(struct ipa3_sys_context *sys);
static void ipa3_replenish_rx_cache(struct ipa3_sys_context *sys);
@@ -748,7 +750,10 @@
int inactive_cycles = 0;
int cnt;
- IPA_ACTIVE_CLIENTS_INC_SIMPLE();
+ if (ipa3_ctx->use_ipa_pm)
+ ipa_pm_activate_sync(sys->pm_hdl);
+ else
+ IPA_ACTIVE_CLIENTS_INC_SIMPLE();
do {
cnt = ipa3_handle_rx_core(sys, true, true);
if (cnt == 0)
@@ -772,7 +777,10 @@
trace_poll_to_intr3(sys->ep->client);
ipa3_rx_switch_to_intr_mode(sys);
- IPA_ACTIVE_CLIENTS_DEC_SIMPLE();
+ if (ipa3_ctx->use_ipa_pm)
+ ipa_pm_deferred_deactivate(sys->pm_hdl);
+ else
+ IPA_ACTIVE_CLIENTS_DEC_SIMPLE();
}
static void ipa3_switch_to_intr_rx_work_func(struct work_struct *work)
@@ -799,6 +807,32 @@
return HRTIMER_NORESTART;
}
+static void ipa_pm_sys_pipe_cb(void *p, enum ipa_pm_cb_event event)
+{
+ struct ipa3_sys_context *sys = (struct ipa3_sys_context *)p;
+
+ switch (event) {
+ case IPA_PM_CLIENT_ACTIVATED:
+ /*
+ * this event is ignored as the sync version of activation
+ * will be used.
+ */
+ break;
+ case IPA_PM_REQUEST_WAKEUP:
+ /*
+ * pipe will be unsuspended as part of
+ * enabling IPA clocks
+ */
+ ipa_pm_activate_sync(sys->pm_hdl);
+ ipa_pm_deferred_deactivate(sys->pm_hdl);
+ break;
+ default:
+ IPAERR("Unexpected event %d\n", event);
+ WARN_ON(1);
+ return;
+ }
+}
+
/**
* ipa3_setup_sys_pipe() - Setup an IPA GPI pipe and perform
* IPA EP configuration
@@ -846,6 +880,9 @@
memset(ep, 0, offsetof(struct ipa3_ep_context, sys));
if (!ep->sys) {
+ struct ipa_pm_register_params pm_reg;
+
+ memset(&pm_reg, 0, sizeof(pm_reg));
ep->sys = kzalloc(sizeof(struct ipa3_sys_context), GFP_KERNEL);
if (!ep->sys) {
IPAERR("failed to sys ctx for client %d\n",
@@ -884,6 +921,35 @@
hrtimer_init(&ep->sys->db_timer, CLOCK_MONOTONIC,
HRTIMER_MODE_REL);
ep->sys->db_timer.function = ipa3_ring_doorbell_timer_fn;
+
+ /* create IPA PM resources for handling polling mode */
+ if (ipa3_ctx->use_ipa_pm &&
+ IPA_CLIENT_IS_CONS(sys_in->client)) {
+ pm_reg.name = ipa_clients_strings[sys_in->client];
+ pm_reg.callback = ipa_pm_sys_pipe_cb;
+ pm_reg.user_data = ep->sys;
+ pm_reg.group = IPA_PM_GROUP_APPS;
+ result = ipa_pm_register(&pm_reg, &ep->sys->pm_hdl);
+ if (result) {
+ IPAERR("failed to create IPA PM client %d\n",
+ result);
+ goto fail_pm;
+ }
+
+ result = ipa_pm_associate_ipa_cons_to_client(
+ ep->sys->pm_hdl, sys_in->client);
+ if (result) {
+ IPAERR("failed to associate IPA PM client\n");
+ goto fail_gen2;
+ }
+
+ result = ipa_pm_set_perf_profile(ep->sys->pm_hdl,
+ IPA_APPS_BW_FOR_PM);
+ if (result) {
+ IPAERR("failed to set profile IPA PM client\n");
+ goto fail_gen2;
+ }
+ }
} else {
memset(ep->sys, 0, offsetof(struct ipa3_sys_context, ep));
}
@@ -984,6 +1050,9 @@
return 0;
fail_gen2:
+ if (ipa3_ctx->use_ipa_pm)
+ ipa_pm_deregister(ep->sys->pm_hdl);
+fail_pm:
destroy_workqueue(ep->sys->repl_wq);
fail_wq2:
destroy_workqueue(ep->sys->wq);
@@ -1402,7 +1471,8 @@
sys = container_of(work, struct ipa3_sys_context, work);
if (sys->ep->napi_enabled) {
- IPA_ACTIVE_CLIENTS_INC_SPECIAL("NAPI");
+ if (!ipa3_ctx->use_ipa_pm)
+ IPA_ACTIVE_CLIENTS_INC_SPECIAL("NAPI");
sys->ep->client_notify(sys->ep->priv,
IPA_CLIENT_START_POLL, 0);
} else
@@ -3283,11 +3353,48 @@
}
}
+void __ipa_gsi_irq_rx_scedule_poll(struct ipa3_sys_context *sys)
+{
+ bool clk_off;
+
+ atomic_set(&sys->curr_polling_state, 1);
+ ipa3_inc_acquire_wakelock();
+
+ /*
+ * pm deactivate is done in wq context
+ * or after NAPI poll
+ */
+ if (ipa3_ctx->use_ipa_pm) {
+ clk_off = ipa_pm_activate(sys->pm_hdl);
+ if (!clk_off && sys->ep->napi_enabled) {
+ sys->ep->client_notify(sys->ep->priv,
+ IPA_CLIENT_START_POLL, 0);
+ return;
+ }
+ queue_work(sys->wq, &sys->work);
+ return;
+ }
+
+ if (sys->ep->napi_enabled) {
+ struct ipa_active_client_logging_info log;
+
+ IPA_ACTIVE_CLIENTS_PREP_SPECIAL(log, "NAPI");
+ clk_off = ipa3_inc_client_enable_clks_no_block(
+ &log);
+ if (!clk_off) {
+ sys->ep->client_notify(sys->ep->priv,
+ IPA_CLIENT_START_POLL, 0);
+ return;
+ }
+ }
+
+ queue_work(sys->wq, &sys->work);
+}
+
static void ipa_gsi_irq_rx_notify_cb(struct gsi_chan_xfer_notify *notify)
{
struct ipa3_sys_context *sys;
struct ipa3_rx_pkt_wrapper *rx_pkt_expected, *rx_pkt_rcvd;
- int clk_off;
if (!notify) {
IPAERR("gsi notify is NULL.\n");
@@ -3317,22 +3424,7 @@
/* put the gsi channel into polling mode */
gsi_config_channel_mode(sys->ep->gsi_chan_hdl,
GSI_CHAN_MODE_POLL);
- ipa3_inc_acquire_wakelock();
- atomic_set(&sys->curr_polling_state, 1);
- if (sys->ep->napi_enabled) {
- struct ipa_active_client_logging_info log;
-
- IPA_ACTIVE_CLIENTS_PREP_SPECIAL(log, "NAPI");
- clk_off = ipa3_inc_client_enable_clks_no_block(
- &log);
- if (!clk_off)
- sys->ep->client_notify(sys->ep->priv,
- IPA_CLIENT_START_POLL, 0);
- else
- queue_work(sys->wq, &sys->work);
- } else {
- queue_work(sys->wq, &sys->work);
- }
+ __ipa_gsi_irq_rx_scedule_poll(sys);
}
break;
default:
@@ -3734,7 +3826,10 @@
if (cnt < weight) {
ep->client_notify(ep->priv, IPA_CLIENT_COMP_NAPI, 0);
ipa3_rx_switch_to_intr_mode(ep->sys);
- ipa3_dec_client_disable_clks_no_block(&log);
+ if (ipa3_ctx->use_ipa_pm)
+ ipa_pm_deferred_deactivate(ep->sys->pm_hdl);
+ else
+ ipa3_dec_client_disable_clks_no_block(&log);
}
return cnt;
diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_flt.c b/drivers/platform/msm/ipa/ipa_v3/ipa_flt.c
index beca549..0883e6f 100644
--- a/drivers/platform/msm/ipa/ipa_v3/ipa_flt.c
+++ b/drivers/platform/msm/ipa/ipa_v3/ipa_flt.c
@@ -1170,6 +1170,13 @@
goto bail;
}
+ if (entry->cookie != IPA_FLT_COOKIE) {
+ IPAERR_RL("Invalid cookie value = %u flt hdl id = %d\n",
+ entry->cookie, rules->add_after_hdl);
+ result = -EINVAL;
+ goto bail;
+ }
+
if (entry->tbl != tbl) {
IPAERR_RL("given entry does not match the table\n");
result = -EINVAL;
diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_i.h b/drivers/platform/msm/ipa/ipa_v3/ipa_i.h
index 89b2fdf..3e1d188 100644
--- a/drivers/platform/msm/ipa/ipa_v3/ipa_i.h
+++ b/drivers/platform/msm/ipa/ipa_v3/ipa_i.h
@@ -36,6 +36,7 @@
#include "ipahal/ipahal_hw_stats.h"
#include "../ipa_common_i.h"
#include "ipa_uc_offload_i.h"
+#include "ipa_pm.h"
#define DRV_NAME "ipa"
#define NAT_DEV_NAME "ipaNatTable"
@@ -647,6 +648,7 @@
struct workqueue_struct *wq;
struct workqueue_struct *repl_wq;
struct ipa3_status_stats *status_stat;
+ u32 pm_hdl;
/* ordering is important - other immutable fields go below */
};
@@ -1315,6 +1317,7 @@
struct ipa_cne_evt ipa_cne_evt_req_cache[IPA_MAX_NUM_REQ_CACHE];
int num_ipa_cne_evt_req;
struct mutex ipa_cne_evt_lock;
+ bool use_ipa_pm;
};
struct ipa3_plat_drv_res {
@@ -1342,6 +1345,8 @@
bool tethered_flow_control;
u32 ipa_tz_unlock_reg_num;
struct ipa_tz_unlock_reg_info *ipa_tz_unlock_reg;
+ bool use_ipa_pm;
+ struct ipa_pm_init_params pm_init;
};
/**
@@ -2228,4 +2233,5 @@
int ipa3_allocate_dma_task_for_gsi(void);
void ipa3_free_dma_task_for_gsi(void);
int ipa3_set_clock_plan_from_pm(int idx);
+void __ipa_gsi_irq_rx_scedule_poll(struct ipa3_sys_context *sys);
#endif /* _IPA3_I_H_ */
diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_pm.c b/drivers/platform/msm/ipa/ipa_v3/ipa_pm.c
index 66c712c..11c1737 100644
--- a/drivers/platform/msm/ipa/ipa_v3/ipa_pm.c
+++ b/drivers/platform/msm/ipa/ipa_v3/ipa_pm.c
@@ -1164,8 +1164,8 @@
mutex_unlock(&ipa_pm_ctx->client_mutex);
spin_lock_irqsave(&client->state_lock, flags);
- if (IPA_PM_STATE_ACTIVE(client->state || (client->group !=
- IPA_PM_GROUP_DEFAULT))) {
+ if (IPA_PM_STATE_ACTIVE(client->state) || (client->group !=
+ IPA_PM_GROUP_DEFAULT)) {
spin_unlock_irqrestore(&client->state_lock, flags);
do_clk_scaling();
return 0;
diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_qmi_service.c b/drivers/platform/msm/ipa/ipa_v3/ipa_qmi_service.c
index 61bccc6..4e8c233 100644
--- a/drivers/platform/msm/ipa/ipa_v3/ipa_qmi_service.c
+++ b/drivers/platform/msm/ipa/ipa_v3/ipa_qmi_service.c
@@ -1214,7 +1214,6 @@
/* voting for bus BW to ipa_rm*/
int ipa3_vote_for_bus_bw(uint32_t *bw_mbps)
{
- struct ipa_rm_perf_profile profile;
int ret;
if (bw_mbps == NULL) {
@@ -1222,16 +1221,13 @@
return -EINVAL;
}
- memset(&profile, 0, sizeof(profile));
- profile.max_supported_bandwidth_mbps = *bw_mbps;
- ret = ipa_rm_set_perf_profile(IPA_RM_RESOURCE_Q6_PROD,
- &profile);
+ ret = ipa3_wwan_set_modem_perf_profile(*bw_mbps);
if (ret)
IPAWANERR("Failed to set perf profile to BW %u\n",
- profile.max_supported_bandwidth_mbps);
+ *bw_mbps);
else
IPAWANDBG("Succeeded to set perf profile to BW %u\n",
- profile.max_supported_bandwidth_mbps);
+ *bw_mbps);
return ret;
}
diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_qmi_service.h b/drivers/platform/msm/ipa/ipa_v3/ipa_qmi_service.h
index d5d8503..d3a4ba0 100644
--- a/drivers/platform/msm/ipa/ipa_v3/ipa_qmi_service.h
+++ b/drivers/platform/msm/ipa/ipa_v3/ipa_qmi_service.h
@@ -207,6 +207,10 @@
void ipa3_q6_handshake_complete(bool ssr_bootup);
+int ipa3_wwan_set_modem_perf_profile(int throughput);
+
+int ipa3_wwan_set_modem_state(struct wan_ioctl_notify_wan_state *state);
+
void ipa3_qmi_init(void);
void ipa3_qmi_cleanup(void);
@@ -323,6 +327,11 @@
static inline void ipa3_q6_handshake_complete(bool ssr_bootup) { }
+static inline int ipa3_wwan_set_modem_perf_profile(int throughput)
+{
+ return -EPERM;
+}
+
static inline void ipa3_qmi_init(void)
{
}
diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_rt.c b/drivers/platform/msm/ipa/ipa_v3/ipa_rt.c
index dd691f1..8bd7d30 100644
--- a/drivers/platform/msm/ipa/ipa_v3/ipa_rt.c
+++ b/drivers/platform/msm/ipa/ipa_v3/ipa_rt.c
@@ -1149,6 +1149,13 @@
goto bail;
}
+ if (entry->cookie != IPA_RT_RULE_COOKIE) {
+ IPAERR_RL("Invalid cookie value = %u rule %d in rt tbls\n",
+ entry->cookie, rules->add_after_hdl);
+ ret = -EINVAL;
+ goto bail;
+ }
+
if (entry->tbl != tbl) {
IPAERR_RL("given rt rule does not match the table\n");
ret = -EINVAL;
diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_utils.c b/drivers/platform/msm/ipa/ipa_v3/ipa_utils.c
index 5206337..f717264 100644
--- a/drivers/platform/msm/ipa/ipa_v3/ipa_utils.c
+++ b/drivers/platform/msm/ipa/ipa_v3/ipa_utils.c
@@ -4855,11 +4855,8 @@
IPADBG("ch %ld not empty\n", ep->gsi_chan_hdl);
/* queue a work to start polling if don't have one */
atomic_set(&ipa3_ctx->transport_pm.eot_activity, 1);
- if (!atomic_read(&ep->sys->curr_polling_state)) {
- ipa3_inc_acquire_wakelock();
- atomic_set(&ep->sys->curr_polling_state, 1);
- queue_work(ep->sys->wq, &ep->sys->work);
- }
+ if (!atomic_read(&ep->sys->curr_polling_state))
+ __ipa_gsi_irq_rx_scedule_poll(ep->sys);
}
}
diff --git a/drivers/platform/msm/ipa/ipa_v3/ipahal/ipahal.c b/drivers/platform/msm/ipa/ipa_v3/ipahal/ipahal.c
index 56fed2a..a8d5342 100644
--- a/drivers/platform/msm/ipa/ipa_v3/ipahal/ipahal.c
+++ b/drivers/platform/msm/ipa/ipa_v3/ipahal/ipahal.c
@@ -595,6 +595,15 @@
return pyld;
}
+static struct ipahal_imm_cmd_pyld *ipa_imm_cmd_construct_dummy(
+ enum ipahal_imm_cmd_name cmd, const void *params, bool is_atomic_ctx)
+{
+ IPAHAL_ERR("no construct function for IMM_CMD=%s, IPA ver %d\n",
+ ipahal_imm_cmd_name_str(cmd), ipahal_ctx->hw_type);
+ WARN_ON(1);
+ return NULL;
+}
+
/*
* struct ipahal_imm_cmd_obj - immediate command H/W information for
* specific IPA version
@@ -668,8 +677,8 @@
12},
/* NAT_DMA was renamed to TABLE_DMA for IPAv4 */
[IPA_HW_v4_0][IPA_IMM_CMD_NAT_DMA] = {
- NULL,
- -1 },
+ ipa_imm_cmd_construct_dummy,
+ -1},
[IPA_HW_v4_0][IPA_IMM_CMD_TABLE_DMA] = {
ipa_imm_cmd_construct_table_dma_ipav4,
14},
diff --git a/drivers/platform/msm/ipa/ipa_v3/rmnet_ipa.c b/drivers/platform/msm/ipa/ipa_v3/rmnet_ipa.c
index 5095e1f..f08e1e3 100644
--- a/drivers/platform/msm/ipa/ipa_v3/rmnet_ipa.c
+++ b/drivers/platform/msm/ipa/ipa_v3/rmnet_ipa.c
@@ -142,6 +142,9 @@
u32 ipa3_to_apps_hdl;
struct mutex pipe_handle_guard;
struct mutex add_mux_channel_lock;
+ u32 pm_hdl;
+ u32 q6_pm_hdl;
+ u32 q6_teth_pm_hdl;
};
static struct rmnet_ipa3_context *rmnet_ipa3_ctx;
@@ -1134,8 +1137,14 @@
send:
/* IPA_RM checking start */
- ret = ipa_rm_inactivity_timer_request_resource(
- IPA_RM_RESOURCE_WWAN_0_PROD);
+ if (ipa3_ctx->use_ipa_pm) {
+ /* activate the modem pm for clock scaling */
+ ipa_pm_activate(rmnet_ipa3_ctx->q6_pm_hdl);
+ ret = ipa_pm_activate(rmnet_ipa3_ctx->pm_hdl);
+ } else {
+ ret = ipa_rm_inactivity_timer_request_resource(
+ IPA_RM_RESOURCE_WWAN_0_PROD);
+ }
if (ret == -EINPROGRESS) {
netif_stop_queue(dev);
return NETDEV_TX_BUSY;
@@ -1164,9 +1173,15 @@
dev->stats.tx_bytes += skb->len;
ret = NETDEV_TX_OK;
out:
- if (atomic_read(&wwan_ptr->outstanding_pkts) == 0)
- ipa_rm_inactivity_timer_release_resource(
- IPA_RM_RESOURCE_WWAN_0_PROD);
+ if (atomic_read(&wwan_ptr->outstanding_pkts) == 0) {
+ if (ipa3_ctx->use_ipa_pm) {
+ ipa_pm_deferred_deactivate(rmnet_ipa3_ctx->pm_hdl);
+ ipa_pm_deferred_deactivate(rmnet_ipa3_ctx->q6_pm_hdl);
+ } else {
+ ipa_rm_inactivity_timer_release_resource(
+ IPA_RM_RESOURCE_WWAN_0_PROD);
+ }
+ }
return ret;
}
@@ -1218,9 +1233,15 @@
netif_wake_queue(wwan_ptr->net);
}
- if (atomic_read(&wwan_ptr->outstanding_pkts) == 0)
- ipa_rm_inactivity_timer_release_resource(
+ if (atomic_read(&wwan_ptr->outstanding_pkts) == 0) {
+ if (ipa3_ctx->use_ipa_pm) {
+ ipa_pm_deferred_deactivate(rmnet_ipa3_ctx->pm_hdl);
+ ipa_pm_deferred_deactivate(rmnet_ipa3_ctx->q6_pm_hdl);
+ } else {
+ ipa_rm_inactivity_timer_release_resource(
IPA_RM_RESOURCE_WWAN_0_PROD);
+ }
+ }
__netif_tx_unlock_bh(netdev_get_tx_queue(dev, 0));
dev_kfree_skb_any(skb);
}
@@ -1858,6 +1879,91 @@
return;
}
}
+
+int ipa3_wwan_set_modem_state(struct wan_ioctl_notify_wan_state *state)
+{
+ if (!state)
+ return -EINVAL;
+
+ if (!ipa_pm_is_used())
+ return 0;
+
+ if (state->up)
+ return ipa_pm_activate_sync(rmnet_ipa3_ctx->q6_teth_pm_hdl);
+ else
+ return ipa_pm_deactivate_sync(rmnet_ipa3_ctx->q6_teth_pm_hdl);
+}
+
+/**
+ * ipa3_q6_register_pm - Register modem clients for PM
+ *
+ * This function will register 2 client with IPA PM to represent modem
+ * in clock scaling calculation:
+ * - "EMB MODEM" - this client will be activated with embedded traffic
+ - "TETH MODEM" - this client we be activated by IPACM on offload to
+ modem.
+*/
+static int ipa3_q6_register_pm(void)
+{
+ int result;
+ struct ipa_pm_register_params pm_reg;
+
+ memset(&pm_reg, 0, sizeof(pm_reg));
+ pm_reg.name = "EMB MODEM";
+ pm_reg.group = IPA_PM_GROUP_MODEM;
+ pm_reg.skip_clk_vote = true;
+ result = ipa_pm_register(&pm_reg, &rmnet_ipa3_ctx->q6_pm_hdl);
+ if (result) {
+ IPAERR("failed to create IPA PM client %d\n", result);
+ return result;
+ }
+
+ pm_reg.name = "TETH MODEM";
+ pm_reg.group = IPA_PM_GROUP_MODEM;
+ pm_reg.skip_clk_vote = true;
+ result = ipa_pm_register(&pm_reg, &rmnet_ipa3_ctx->q6_teth_pm_hdl);
+ if (result) {
+ IPAERR("failed to create IPA PM client %d\n", result);
+ return result;
+ }
+
+ return 0;
+}
+
+static void ipa3_q6_deregister_pm(void)
+{
+ ipa_pm_deactivate_sync(rmnet_ipa3_ctx->q6_pm_hdl);
+ ipa_pm_deregister(rmnet_ipa3_ctx->q6_pm_hdl);
+}
+
+int ipa3_wwan_set_modem_perf_profile(int throughput)
+{
+ struct ipa_rm_perf_profile profile;
+ int ret;
+
+ ret = ipa_pm_set_perf_profile(rmnet_ipa3_ctx->q6_pm_hdl, throughput);
+ if (ret)
+ return ret;
+ return ipa_pm_set_perf_profile(rmnet_ipa3_ctx->q6_teth_pm_hdl,
+ throughput);
+
+ if (ipa3_ctx->use_ipa_pm) {
+ ret = ipa_pm_set_perf_profile(rmnet_ipa3_ctx->q6_pm_hdl,
+ throughput);
+ if (ret)
+ return ret;
+ ret = ipa_pm_set_perf_profile(rmnet_ipa3_ctx->q6_teth_pm_hdl,
+ throughput);
+ } else {
+ memset(&profile, 0, sizeof(profile));
+ profile.max_supported_bandwidth_mbps = throughput;
+ ret = ipa_rm_set_perf_profile(IPA_RM_RESOURCE_Q6_PROD,
+ &profile);
+ }
+
+ return ret;
+}
+
static int ipa3_q6_initialize_rm(void)
{
struct ipa_rm_create_params create_params;
@@ -2075,6 +2181,120 @@
schedule_work(&ipa3_scheduled_probe);
}
+static void ipa_pm_wwan_pm_cb(void *p, enum ipa_pm_cb_event event)
+{
+ struct net_device *dev = (struct net_device *)p;
+ struct ipa3_wwan_private *wwan_ptr = netdev_priv(dev);
+
+ IPAWANDBG_LOW("event %d\n", event);
+ switch (event) {
+ case IPA_PM_CLIENT_ACTIVATED:
+ if (wwan_ptr->device_status == WWAN_DEVICE_INACTIVE) {
+ complete_all(&wwan_ptr->resource_granted_completion);
+ break;
+ }
+ ipa3_rm_resource_granted(dev);
+ break;
+ default:
+ pr_err("%s: unknown event %d\n", __func__, event);
+ break;
+ }
+}
+
+static int ipa3_wwan_register_netdev_pm_client(struct net_device *dev)
+{
+ int result;
+ struct ipa_pm_register_params pm_reg;
+
+ memset(&pm_reg, 0, sizeof(pm_reg));
+ pm_reg.name = IPA_NETDEV()->name;
+ pm_reg.user_data = dev;
+ pm_reg.callback = ipa_pm_wwan_pm_cb;
+ pm_reg.group = IPA_PM_GROUP_APPS;
+ result = ipa_pm_register(&pm_reg, &rmnet_ipa3_ctx->pm_hdl);
+ if (result) {
+ IPAERR("failed to create IPA PM client %d\n", result);
+ return result;
+ }
+ return 0;
+}
+
+static void ipa3_wwan_deregister_netdev_pm_client(void)
+{
+ ipa_pm_deactivate_sync(rmnet_ipa3_ctx->pm_hdl);
+ ipa_pm_deregister(rmnet_ipa3_ctx->pm_hdl);
+}
+
+static int ipa3_wwan_create_wwan_rm_resource(struct net_device *dev)
+{
+ struct ipa_rm_create_params ipa_rm_params;
+ struct ipa_rm_perf_profile profile;
+ int ret;
+
+ memset(&ipa_rm_params, 0, sizeof(struct ipa_rm_create_params));
+ ipa_rm_params.name = IPA_RM_RESOURCE_WWAN_0_PROD;
+ ipa_rm_params.reg_params.user_data = dev;
+ ipa_rm_params.reg_params.notify_cb = ipa3_rm_notify;
+ ret = ipa_rm_create_resource(&ipa_rm_params);
+ if (ret) {
+ pr_err("%s: unable to create resourse %d in IPA RM\n",
+ __func__, IPA_RM_RESOURCE_WWAN_0_PROD);
+ return ret;
+ }
+ ret = ipa_rm_inactivity_timer_init(IPA_RM_RESOURCE_WWAN_0_PROD,
+ IPA_RM_INACTIVITY_TIMER);
+ if (ret) {
+ pr_err("%s: ipa rm timer init failed %d on resourse %d\n",
+ __func__, ret, IPA_RM_RESOURCE_WWAN_0_PROD);
+ goto timer_init_err;
+ }
+ /* add dependency */
+ ret = ipa_rm_add_dependency(IPA_RM_RESOURCE_WWAN_0_PROD,
+ IPA_RM_RESOURCE_Q6_CONS);
+ if (ret)
+ goto add_dpnd_err;
+ /* setup Performance profile */
+ memset(&profile, 0, sizeof(profile));
+ profile.max_supported_bandwidth_mbps = IPA_APPS_MAX_BW_IN_MBPS;
+ ret = ipa_rm_set_perf_profile(IPA_RM_RESOURCE_WWAN_0_PROD,
+ &profile);
+ if (ret)
+ goto set_perf_err;
+
+ return 0;
+
+set_perf_err:
+ ipa_rm_delete_dependency(IPA_RM_RESOURCE_WWAN_0_PROD,
+ IPA_RM_RESOURCE_Q6_CONS);
+add_dpnd_err:
+ ipa_rm_inactivity_timer_destroy(
+ IPA_RM_RESOURCE_WWAN_0_PROD); /* IPA_RM */
+timer_init_err:
+ ipa_rm_delete_resource(IPA_RM_RESOURCE_WWAN_0_PROD);
+ return ret;
+}
+
+static void ipa3_wwan_delete_wwan_rm_resource(void)
+{
+ int ret;
+
+ ret = ipa_rm_delete_dependency(IPA_RM_RESOURCE_WWAN_0_PROD,
+ IPA_RM_RESOURCE_Q6_CONS);
+ if (ret < 0)
+ IPAWANERR("Error deleting dependency %d->%d, ret=%d\n",
+ IPA_RM_RESOURCE_WWAN_0_PROD, IPA_RM_RESOURCE_Q6_CONS,
+ ret);
+ ret = ipa_rm_inactivity_timer_destroy(IPA_RM_RESOURCE_WWAN_0_PROD);
+ if (ret < 0)
+ IPAWANERR(
+ "Error ipa_rm_inactivity_timer_destroy resource %d, ret=%d\n",
+ IPA_RM_RESOURCE_WWAN_0_PROD, ret);
+ ret = ipa_rm_delete_resource(IPA_RM_RESOURCE_WWAN_0_PROD);
+ if (ret < 0)
+ IPAWANERR("Error deleting resource %d, ret=%d\n",
+ IPA_RM_RESOURCE_WWAN_0_PROD, ret);
+}
+
/**
* ipa3_wwan_probe() - Initialized the module and registers as a
* network interface to the network stack
@@ -2092,8 +2312,6 @@
{
int ret, i;
struct net_device *dev;
- struct ipa_rm_create_params ipa_rm_params; /* IPA_RM */
- struct ipa_rm_perf_profile profile; /* IPA_RM */
pr_info("rmnet_ipa3 started initialization\n");
@@ -2187,7 +2405,10 @@
if (!atomic_read(&rmnet_ipa3_ctx->is_ssr)) {
/* IPA_RM configuration starts */
- ret = ipa3_q6_initialize_rm();
+ if (ipa3_ctx->use_ipa_pm)
+ ret = ipa3_q6_register_pm();
+ else
+ ret = ipa3_q6_initialize_rm();
if (ret) {
IPAWANERR("%s: ipa3_q6_initialize_rm failed, ret: %d\n",
__func__, ret);
@@ -2195,36 +2416,14 @@
}
}
- memset(&ipa_rm_params, 0, sizeof(struct ipa_rm_create_params));
- ipa_rm_params.name = IPA_RM_RESOURCE_WWAN_0_PROD;
- ipa_rm_params.reg_params.user_data = dev;
- ipa_rm_params.reg_params.notify_cb = ipa3_rm_notify;
- ret = ipa_rm_create_resource(&ipa_rm_params);
+ if (ipa3_ctx->use_ipa_pm)
+ ret = ipa3_wwan_register_netdev_pm_client(dev);
+ else
+ ret = ipa3_wwan_create_wwan_rm_resource(dev);
if (ret) {
- pr_err("%s: unable to create resourse %d in IPA RM\n",
- __func__, IPA_RM_RESOURCE_WWAN_0_PROD);
- goto create_rsrc_err;
+ IPAWANERR("fail to create/register pm resources\n");
+ goto fail_pm;
}
- ret = ipa_rm_inactivity_timer_init(IPA_RM_RESOURCE_WWAN_0_PROD,
- IPA_RM_INACTIVITY_TIMER);
- if (ret) {
- pr_err("%s: ipa rm timer init failed %d on resourse %d\n",
- __func__, ret, IPA_RM_RESOURCE_WWAN_0_PROD);
- goto timer_init_err;
- }
- /* add dependency */
- ret = ipa_rm_add_dependency(IPA_RM_RESOURCE_WWAN_0_PROD,
- IPA_RM_RESOURCE_Q6_CONS);
- if (ret)
- goto add_dpnd_err;
- /* setup Performance profile */
- memset(&profile, 0, sizeof(profile));
- profile.max_supported_bandwidth_mbps = IPA_APPS_MAX_BW_IN_MBPS;
- ret = ipa_rm_set_perf_profile(IPA_RM_RESOURCE_WWAN_0_PROD,
- &profile);
- if (ret)
- goto set_perf_err;
- /* IPA_RM configuration ends */
/* Enable SG support in netdevice. */
if (ipa3_rmnet_res.ipa_advertise_sg_support)
@@ -2260,28 +2459,18 @@
netif_napi_del(&(rmnet_ipa3_ctx->wwan_priv->napi));
unregister_netdev(dev);
set_perf_err:
- ret = ipa_rm_delete_dependency(IPA_RM_RESOURCE_WWAN_0_PROD,
- IPA_RM_RESOURCE_Q6_CONS);
- if (ret)
- IPAWANERR("Error deleting dependency %d->%d, ret=%d\n",
- IPA_RM_RESOURCE_WWAN_0_PROD, IPA_RM_RESOURCE_Q6_CONS,
- ret);
-add_dpnd_err:
- ret = ipa_rm_inactivity_timer_destroy(
- IPA_RM_RESOURCE_WWAN_0_PROD); /* IPA_RM */
- if (ret)
- IPAWANERR("Error ipa_rm_inactivity_timer_destroy %d, ret=%d\n",
- IPA_RM_RESOURCE_WWAN_0_PROD, ret);
-timer_init_err:
- ret = ipa_rm_delete_resource(IPA_RM_RESOURCE_WWAN_0_PROD);
- if (ret)
- IPAWANERR("Error deleting resource %d, ret=%d\n",
- IPA_RM_RESOURCE_WWAN_0_PROD, ret);
-create_rsrc_err:
-
- if (!atomic_read(&rmnet_ipa3_ctx->is_ssr))
- ipa3_q6_deinitialize_rm();
-
+ if (ipa3_ctx->use_ipa_pm)
+ ipa3_wwan_deregister_netdev_pm_client();
+ else
+ ipa3_wwan_delete_wwan_rm_resource();
+fail_pm:
+ if (ipa3_ctx->use_ipa_pm) {
+ if (!atomic_read(&rmnet_ipa3_ctx->is_ssr))
+ ipa3_q6_deregister_pm();
+ } else {
+ if (!atomic_read(&rmnet_ipa3_ctx->is_ssr))
+ ipa3_q6_deinitialize_rm();
+ }
q6_init_err:
free_netdev(dev);
rmnet_ipa3_ctx->wwan_priv = NULL;
@@ -2317,21 +2506,10 @@
netif_napi_del(&(rmnet_ipa3_ctx->wwan_priv->napi));
mutex_unlock(&rmnet_ipa3_ctx->pipe_handle_guard);
unregister_netdev(IPA_NETDEV());
- ret = ipa_rm_delete_dependency(IPA_RM_RESOURCE_WWAN_0_PROD,
- IPA_RM_RESOURCE_Q6_CONS);
- if (ret < 0)
- IPAWANERR("Error deleting dependency %d->%d, ret=%d\n",
- IPA_RM_RESOURCE_WWAN_0_PROD, IPA_RM_RESOURCE_Q6_CONS,
- ret);
- ret = ipa_rm_inactivity_timer_destroy(IPA_RM_RESOURCE_WWAN_0_PROD);
- if (ret < 0)
- IPAWANERR(
- "Error ipa_rm_inactivity_timer_destroy resource %d, ret=%d\n",
- IPA_RM_RESOURCE_WWAN_0_PROD, ret);
- ret = ipa_rm_delete_resource(IPA_RM_RESOURCE_WWAN_0_PROD);
- if (ret < 0)
- IPAWANERR("Error deleting resource %d, ret=%d\n",
- IPA_RM_RESOURCE_WWAN_0_PROD, ret);
+ if (ipa3_ctx->use_ipa_pm)
+ ipa3_wwan_deregister_netdev_pm_client();
+ else
+ ipa3_wwan_delete_wwan_rm_resource();
cancel_work_sync(&ipa3_tx_wakequeue_work);
cancel_delayed_work(&ipa_tether_stats_poll_wakequeue_work);
if (IPA_NETDEV())
@@ -2385,23 +2563,26 @@
if (wwan_ptr == NULL) {
IPAWANERR("wwan_ptr is NULL.\n");
ret = 0;
- goto unlock_and_bail;
+ netif_tx_unlock_bh(netdev);
+ goto bail;
}
/* Do not allow A7 to suspend in case there are oustanding packets */
if (atomic_read(&wwan_ptr->outstanding_pkts) != 0) {
IPAWANDBG("Outstanding packets, postponing AP suspend.\n");
ret = -EAGAIN;
- goto unlock_and_bail;
+ netif_tx_unlock_bh(netdev);
+ goto bail;
}
/* Make sure that there is no Tx operation ongoing */
netif_stop_queue(netdev);
- ipa_rm_release_resource(IPA_RM_RESOURCE_WWAN_0_PROD);
- ret = 0;
-
-unlock_and_bail:
netif_tx_unlock_bh(netdev);
+ if (ipa3_ctx->use_ipa_pm)
+ ipa_pm_deactivate_sync(rmnet_ipa3_ctx->pm_hdl);
+ else
+ ipa_rm_release_resource(IPA_RM_RESOURCE_WWAN_0_PROD);
+ ret = 0;
bail:
IPAWANDBG("Exit with %d\n", ret);
return ret;
diff --git a/drivers/platform/msm/ipa/ipa_v3/rmnet_ipa_fd_ioctl.c b/drivers/platform/msm/ipa/ipa_v3/rmnet_ipa_fd_ioctl.c
index c7a6186..2e43abf 100644
--- a/drivers/platform/msm/ipa/ipa_v3/rmnet_ipa_fd_ioctl.c
+++ b/drivers/platform/msm/ipa/ipa_v3/rmnet_ipa_fd_ioctl.c
@@ -50,6 +50,9 @@
#define WAN_IOC_QUERY_TETHER_STATS_ALL32 _IOWR(WAN_IOC_MAGIC, \
WAN_IOCTL_QUERY_TETHER_STATS_ALL, \
compat_uptr_t)
+#define WAN_IOC_NOTIFY_WAN_STATE32 _IOWR(WAN_IOC_MAGIC, \
+ WAN_IOCTL_NOTIFY_WAN_STATE, \
+ compat_uptr_t)
#endif
static unsigned int dev_num = 1;
@@ -316,6 +319,27 @@
}
break;
+ case WAN_IOC_NOTIFY_WAN_STATE:
+ IPAWANDBG_LOW("device %s got WAN_IOC_NOTIFY_WAN_STATE :>>>\n",
+ DRIVER_NAME);
+ pyld_sz = sizeof(struct wan_ioctl_notify_wan_state);
+ param = kzalloc(pyld_sz, GFP_KERNEL);
+ if (!param) {
+ retval = -ENOMEM;
+ break;
+ }
+ if (copy_from_user(param, (u8 __user *)arg, pyld_sz)) {
+ retval = -EFAULT;
+ break;
+ }
+
+ if (ipa3_wwan_set_modem_state(
+ (struct wan_ioctl_notify_wan_state *)param)) {
+ IPAWANERR("WAN_IOC_NOTIFY_WAN_STATE failed\n");
+ retval = -EFAULT;
+ break;
+ }
+ break;
default:
retval = -ENOTTY;
}
diff --git a/drivers/platform/msm/ipa/ipa_v3/teth_bridge.c b/drivers/platform/msm/ipa/ipa_v3/teth_bridge.c
index 297f932..7496f28 100644
--- a/drivers/platform/msm/ipa/ipa_v3/teth_bridge.c
+++ b/drivers/platform/msm/ipa/ipa_v3/teth_bridge.c
@@ -50,6 +50,7 @@
dev_t dev_num;
struct device *dev;
struct cdev cdev;
+ u32 modem_pm_hdl;
};
static struct ipa3_teth_bridge_ctx *ipa3_teth_ctx;
@@ -118,14 +119,25 @@
*/
int ipa3_teth_bridge_disconnect(enum ipa_client_type client)
{
+ int res = 0;
+
TETH_DBG_FUNC_ENTRY();
- ipa_rm_delete_dependency(IPA_RM_RESOURCE_USB_PROD,
- IPA_RM_RESOURCE_Q6_CONS);
- ipa_rm_delete_dependency(IPA_RM_RESOURCE_Q6_PROD,
- IPA_RM_RESOURCE_USB_CONS);
+ if (ipa_pm_is_used()) {
+ res = ipa_pm_deactivate_sync(ipa3_teth_ctx->modem_pm_hdl);
+ if (res) {
+ TETH_ERR("fail to deactivate modem %d\n", res);
+ return res;
+ }
+ res = ipa_pm_destroy();
+ } else {
+ ipa_rm_delete_dependency(IPA_RM_RESOURCE_USB_PROD,
+ IPA_RM_RESOURCE_Q6_CONS);
+ ipa_rm_delete_dependency(IPA_RM_RESOURCE_Q6_PROD,
+ IPA_RM_RESOURCE_USB_CONS);
+ }
TETH_DBG_FUNC_EXIT();
- return 0;
+ return res;
}
/**
@@ -140,9 +152,27 @@
int ipa3_teth_bridge_connect(struct teth_bridge_connect_params *connect_params)
{
int res = 0;
+ struct ipa_pm_register_params reg_params;
+
+ memset(®_params, 0, sizeof(reg_params));
TETH_DBG_FUNC_ENTRY();
+ if (ipa_pm_is_used()) {
+ reg_params.name = "MODEM (USB RMNET)";
+ reg_params.group = IPA_PM_GROUP_MODEM;
+ reg_params.skip_clk_vote = true;
+ res = ipa_pm_register(®_params,
+ &ipa3_teth_ctx->modem_pm_hdl);
+ if (res) {
+ TETH_ERR("fail to register with PM %d\n", res);
+ return res;
+ }
+
+ res = ipa_pm_activate_sync(ipa3_teth_ctx->modem_pm_hdl);
+ goto bail;
+ }
+
/* Build the dependency graph, first add_dependency call is sync
* in order to make sure the IPA clocks are up before we continue
* and notify the USB driver it may continue.
@@ -234,6 +264,8 @@
res = -ENODEV;
goto fail_cdev_add;
}
+
+ ipa3_teth_ctx->modem_pm_hdl = ~0;
TETH_DBG("Tethering bridge driver init OK\n");
return 0;
diff --git a/drivers/power/supply/qcom/battery.c b/drivers/power/supply/qcom/battery.c
index f6e81d8..0cba866 100644
--- a/drivers/power/supply/qcom/battery.c
+++ b/drivers/power/supply/qcom/battery.c
@@ -26,12 +26,14 @@
#include <linux/pm_wakeup.h>
#include <linux/slab.h>
#include <linux/pmic-voter.h>
+#include <linux/workqueue.h>
#include "battery.h"
#define DRV_MAJOR_VERSION 1
#define DRV_MINOR_VERSION 0
#define CHG_STATE_VOTER "CHG_STATE_VOTER"
+#define TAPER_STEPPER_VOTER "TAPER_STEPPER_VOTER"
#define TAPER_END_VOTER "TAPER_END_VOTER"
#define PL_TAPER_EARLY_BAD_VOTER "PL_TAPER_EARLY_BAD_VOTER"
#define PARALLEL_PSY_VOTER "PARALLEL_PSY_VOTER"
@@ -46,7 +48,6 @@
struct pl_data {
int pl_mode;
int slave_pct;
- int taper_pct;
int slave_fcc_ua;
int restricted_current;
bool restricted_charging_enabled;
@@ -59,7 +60,8 @@
struct votable *pl_enable_votable_indirect;
struct delayed_work status_change_work;
struct work_struct pl_disable_forever_work;
- struct delayed_work pl_taper_work;
+ struct work_struct pl_taper_work;
+ bool taper_work_running;
struct power_supply *main_psy;
struct power_supply *pl_psy;
struct power_supply *batt_psy;
@@ -342,67 +344,61 @@
*master_ua = max(0, total_ua);
else
*master_ua = max(0, total_ua - *slave_ua);
-
- /* further reduce slave's share in accordance with taper reductions */
- *slave_ua = (*slave_ua * chip->taper_pct) / 100;
}
#define MINIMUM_PARALLEL_FCC_UA 500000
#define PL_TAPER_WORK_DELAY_MS 500
#define TAPER_RESIDUAL_PCT 90
+#define TAPER_REDUCTION_UA 200000
static void pl_taper_work(struct work_struct *work)
{
struct pl_data *chip = container_of(work, struct pl_data,
- pl_taper_work.work);
+ pl_taper_work);
union power_supply_propval pval = {0, };
- int total_fcc_ua, master_fcc_ua, slave_fcc_ua;
int rc;
+ int eff_fcc_ua;
- /* exit immediately if parallel is disabled */
- if (get_effective_result(chip->pl_disable_votable)) {
- pl_dbg(chip, PR_PARALLEL, "terminating parallel not in progress\n");
- goto done;
+ chip->taper_work_running = true;
+ while (true) {
+ /* exit immediately if parallel is disabled */
+ if (get_effective_result(chip->pl_disable_votable)) {
+ pl_dbg(chip, PR_PARALLEL, "terminating parallel not in progress\n");
+ goto done;
+ }
+
+ rc = power_supply_get_property(chip->batt_psy,
+ POWER_SUPPLY_PROP_CHARGE_TYPE, &pval);
+ if (rc < 0) {
+ pr_err("Couldn't get batt charge type rc=%d\n", rc);
+ goto done;
+ }
+
+ chip->charge_type = pval.intval;
+ if (pval.intval == POWER_SUPPLY_CHARGE_TYPE_TAPER) {
+ eff_fcc_ua = get_effective_result(chip->fcc_votable);
+ if (eff_fcc_ua < 0) {
+ pr_err("Couldn't get fcc, exiting taper work\n");
+ goto done;
+ }
+ eff_fcc_ua = eff_fcc_ua - TAPER_REDUCTION_UA;
+ if (eff_fcc_ua < 0) {
+ pr_err("Can't reduce FCC any more\n");
+ goto done;
+ }
+
+ pl_dbg(chip, PR_PARALLEL, "master is taper charging; reducing FCC to %dua\n",
+ eff_fcc_ua);
+ vote(chip->fcc_votable, TAPER_STEPPER_VOTER,
+ true, eff_fcc_ua);
+ } else {
+ pl_dbg(chip, PR_PARALLEL, "master is fast charging; waiting for next taper\n");
+ }
+ /* wait for the charger state to deglitch after FCC change */
+ msleep(PL_TAPER_WORK_DELAY_MS);
}
-
- total_fcc_ua = get_effective_result_locked(chip->fcc_votable);
- get_fcc_split(chip, total_fcc_ua, &master_fcc_ua, &slave_fcc_ua);
- if (slave_fcc_ua < MINIMUM_PARALLEL_FCC_UA) {
- pl_dbg(chip, PR_PARALLEL, "terminating parallel's share lower than 500mA\n");
- vote(chip->pl_disable_votable, TAPER_END_VOTER, true, 0);
- goto done;
- }
-
- pl_dbg(chip, PR_PARALLEL, "entering parallel taper work slave_fcc = %d\n",
- slave_fcc_ua);
-
- rc = power_supply_get_property(chip->batt_psy,
- POWER_SUPPLY_PROP_CHARGE_TYPE, &pval);
- if (rc < 0) {
- pr_err("Couldn't get batt charge type rc=%d\n", rc);
- goto done;
- }
-
- chip->charge_type = pval.intval;
- if (pval.intval == POWER_SUPPLY_CHARGE_TYPE_TAPER) {
- pl_dbg(chip, PR_PARALLEL, "master is taper charging; reducing slave FCC\n");
-
- vote(chip->pl_awake_votable, TAPER_END_VOTER, true, 0);
- /* Reduce the taper percent by 10 percent */
- chip->taper_pct = chip->taper_pct * TAPER_RESIDUAL_PCT / 100;
- rerun_election(chip->fcc_votable);
- pl_dbg(chip, PR_PARALLEL, "taper entry scheduling work after %d ms\n",
- PL_TAPER_WORK_DELAY_MS);
- schedule_delayed_work(&chip->pl_taper_work,
- msecs_to_jiffies(PL_TAPER_WORK_DELAY_MS));
- return;
- }
-
- /*
- * Master back to Fast Charge, get out of this round of taper reduction
- */
- pl_dbg(chip, PR_PARALLEL, "master is fast charging; waiting for next taper\n");
-
done:
+ chip->taper_work_running = false;
+ vote(chip->fcc_votable, TAPER_STEPPER_VOTER, false, 0);
vote(chip->pl_awake_votable, TAPER_END_VOTER, false, 0);
}
@@ -422,7 +418,7 @@
get_fcc_split(chip, total_fcc_ua, &master_fcc_ua,
&slave_fcc_ua);
- if (slave_fcc_ua > 500000) {
+ if (slave_fcc_ua > MINIMUM_PARALLEL_FCC_UA) {
chip->slave_fcc_ua = slave_fcc_ua;
vote(chip->pl_disable_votable, FCC_CHANGE_VOTER,
false, 0);
@@ -435,11 +431,6 @@
rerun_election(chip->pl_disable_votable);
- pl_dbg(chip, PR_PARALLEL, "master_fcc=%d slave_fcc=%d distribution=(%d/%d)\n",
- master_fcc_ua, slave_fcc_ua,
- (master_fcc_ua * 100) / total_fcc_ua,
- (slave_fcc_ua * 100) / total_fcc_ua);
-
return 0;
}
@@ -652,12 +643,21 @@
if (rc < 0) {
pr_err("Couldn't get batt charge type rc=%d\n", rc);
} else {
- if (pval.intval == POWER_SUPPLY_CHARGE_TYPE_TAPER) {
+ if (pval.intval == POWER_SUPPLY_CHARGE_TYPE_TAPER
+ && !chip->taper_work_running) {
pl_dbg(chip, PR_PARALLEL,
"pl enabled in Taper scheduing work\n");
- schedule_delayed_work(&chip->pl_taper_work, 0);
+ vote(chip->pl_awake_votable, TAPER_END_VOTER,
+ true, 0);
+ queue_work(system_long_wq,
+ &chip->pl_taper_work);
}
}
+
+ pl_dbg(chip, PR_PARALLEL, "master_fcc=%d slave_fcc=%d distribution=(%d/%d)\n",
+ master_fcc_ua, slave_fcc_ua,
+ (master_fcc_ua * 100) / total_fcc_ua,
+ (slave_fcc_ua * 100) / total_fcc_ua);
} else {
if ((chip->pl_mode == POWER_SUPPLY_PL_USBIN_USBIN)
|| (chip->pl_mode == POWER_SUPPLY_PL_USBIN_USBIN_EXT))
@@ -788,7 +788,6 @@
if ((pval.intval != POWER_SUPPLY_CHARGE_TYPE_FAST)
&& (pval.intval != POWER_SUPPLY_CHARGE_TYPE_TAPER)) {
vote(chip->pl_disable_votable, CHG_STATE_VOTER, true, 0);
- chip->taper_pct = 100;
vote(chip->pl_disable_votable, TAPER_END_VOTER, false, 0);
vote(chip->pl_disable_votable, PL_TAPER_EARLY_BAD_VOTER,
false, 0);
@@ -800,8 +799,11 @@
if (chip->charge_type == POWER_SUPPLY_CHARGE_TYPE_FAST
&& (pval.intval == POWER_SUPPLY_CHARGE_TYPE_TAPER)) {
chip->charge_type = pval.intval;
- pl_dbg(chip, PR_PARALLEL, "taper entry scheduling work\n");
- schedule_delayed_work(&chip->pl_taper_work, 0);
+ if (!chip->taper_work_running) {
+ pl_dbg(chip, PR_PARALLEL, "taper entry scheduling work\n");
+ vote(chip->pl_awake_votable, TAPER_END_VOTER, true, 0);
+ queue_work(system_long_wq, &chip->pl_taper_work);
+ }
return;
}
@@ -1057,7 +1059,7 @@
vote(chip->pl_disable_votable, PL_INDIRECT_VOTER, true, 0);
INIT_DELAYED_WORK(&chip->status_change_work, status_change_work);
- INIT_DELAYED_WORK(&chip->pl_taper_work, pl_taper_work);
+ INIT_WORK(&chip->pl_taper_work, pl_taper_work);
INIT_WORK(&chip->pl_disable_forever_work, pl_disable_forever_work);
rc = pl_register_notifier(chip);
@@ -1082,8 +1084,6 @@
goto unreg_notifier;
}
- chip->taper_pct = 100;
-
the_chip = chip;
return 0;
@@ -1112,7 +1112,7 @@
return;
cancel_delayed_work_sync(&chip->status_change_work);
- cancel_delayed_work_sync(&chip->pl_taper_work);
+ cancel_work_sync(&chip->pl_taper_work);
cancel_work_sync(&chip->pl_disable_forever_work);
power_supply_unreg_notifier(&chip->nb);
diff --git a/drivers/power/supply/qcom/fg-core.h b/drivers/power/supply/qcom/fg-core.h
index 271c523..4303960 100644
--- a/drivers/power/supply/qcom/fg-core.h
+++ b/drivers/power/supply/qcom/fg-core.h
@@ -287,6 +287,7 @@
int esr_pulse_thresh_ma;
int esr_meas_curr_ma;
int bmd_en_delay_ms;
+ int ki_coeff_full_soc_dischg;
int jeita_thresholds[NUM_JEITA_LEVELS];
int ki_coeff_soc[KI_COEFF_SOC_LEVELS];
int ki_coeff_med_dischg[KI_COEFF_SOC_LEVELS];
@@ -416,6 +417,7 @@
struct mutex bus_lock;
struct mutex sram_rw_lock;
struct mutex charge_full_lock;
+ struct mutex qnovo_esr_ctrl_lock;
u32 batt_soc_base;
u32 batt_info_base;
u32 mem_if_base;
@@ -424,7 +426,6 @@
int batt_id_ohms;
int ki_coeff_full_soc;
int charge_status;
- int prev_charge_status;
int charge_done;
int charge_type;
int online_status;
@@ -450,6 +451,7 @@
bool slope_limit_en;
bool use_ima_single_mode;
bool use_dma;
+ bool qnovo_enable;
struct completion soc_update;
struct completion soc_ready;
struct completion mem_grant;
diff --git a/drivers/power/supply/qcom/qpnp-fg-gen3.c b/drivers/power/supply/qcom/qpnp-fg-gen3.c
index 7f220c3..b02c860 100644
--- a/drivers/power/supply/qcom/qpnp-fg-gen3.c
+++ b/drivers/power/supply/qcom/qpnp-fg-gen3.c
@@ -1631,6 +1631,8 @@
if (batt_temp < 0)
ki_coeff_full_soc = 0;
+ else if (chip->charge_status == POWER_SUPPLY_STATUS_DISCHARGING)
+ ki_coeff_full_soc = chip->dt.ki_coeff_full_soc_dischg;
else
ki_coeff_full_soc = KI_COEFF_FULL_SOC_DEFAULT;
@@ -1748,12 +1750,12 @@
/* We need 2 most significant bytes here */
bsoc = (u32)bsoc >> 16;
- rc = fg_get_msoc(chip, &msoc);
+ rc = fg_get_msoc_raw(chip, &msoc_raw);
if (rc < 0) {
- pr_err("Error in getting msoc, rc=%d\n", rc);
+ pr_err("Error in getting msoc_raw, rc=%d\n", rc);
goto out;
}
- msoc_raw = DIV_ROUND_CLOSEST(msoc * FULL_SOC_RAW, FULL_CAPACITY);
+ msoc = DIV_ROUND_CLOSEST(msoc_raw * FULL_CAPACITY, FULL_SOC_RAW);
fg_dbg(chip, FG_STATUS, "msoc: %d bsoc: %x health: %d status: %d full: %d\n",
msoc, bsoc, chip->health, chip->charge_status,
@@ -2507,7 +2509,6 @@
goto out;
}
- chip->prev_charge_status = chip->charge_status;
chip->charge_status = prop.intval;
rc = power_supply_get_property(chip->batt_psy,
POWER_SUPPLY_PROP_CHARGE_TYPE, &prop);
@@ -3300,20 +3301,21 @@
int rc;
int esr_uohms;
+ mutex_lock(&chip->qnovo_esr_ctrl_lock);
/* force esr extraction enable */
rc = fg_sram_masked_write(chip, ESR_EXTRACTION_ENABLE_WORD,
ESR_EXTRACTION_ENABLE_OFFSET, BIT(0), BIT(0),
FG_IMA_DEFAULT);
if (rc < 0) {
pr_err("failed to enable esr extn rc=%d\n", rc);
- return rc;
+ goto out;
}
rc = fg_masked_write(chip, BATT_INFO_QNOVO_CFG(chip),
LD_REG_CTRL_BIT, 0);
if (rc < 0) {
pr_err("Error in configuring qnovo_cfg rc=%d\n", rc);
- return rc;
+ goto out;
}
rc = fg_masked_write(chip, BATT_INFO_TM_MISC1(chip),
@@ -3321,24 +3323,36 @@
ESR_REQ_CTL_BIT | ESR_REQ_CTL_EN_BIT);
if (rc < 0) {
pr_err("Error in configuring force ESR rc=%d\n", rc);
- return rc;
+ goto out;
}
+ /*
+ * Release and grab the lock again after 1.5 seconds so that prepare
+ * callback can succeed if the request comes in between.
+ */
+ mutex_unlock(&chip->qnovo_esr_ctrl_lock);
+
/* wait 1.5 seconds for hw to measure ESR */
msleep(1500);
+
+ mutex_lock(&chip->qnovo_esr_ctrl_lock);
rc = fg_masked_write(chip, BATT_INFO_TM_MISC1(chip),
ESR_REQ_CTL_BIT | ESR_REQ_CTL_EN_BIT,
0);
if (rc < 0) {
pr_err("Error in restoring force ESR rc=%d\n", rc);
- return rc;
+ goto out;
}
+ /* If qnovo is disabled, then leave ESR extraction enabled */
+ if (!chip->qnovo_enable)
+ goto done;
+
rc = fg_masked_write(chip, BATT_INFO_QNOVO_CFG(chip),
LD_REG_CTRL_BIT, LD_REG_CTRL_BIT);
if (rc < 0) {
pr_err("Error in restoring qnovo_cfg rc=%d\n", rc);
- return rc;
+ goto out;
}
/* force esr extraction disable */
@@ -3347,36 +3361,46 @@
FG_IMA_DEFAULT);
if (rc < 0) {
pr_err("failed to disable esr extn rc=%d\n", rc);
- return rc;
+ goto out;
}
+done:
fg_get_battery_resistance(chip, &esr_uohms);
fg_dbg(chip, FG_STATUS, "ESR uohms = %d\n", esr_uohms);
-
+out:
+ mutex_unlock(&chip->qnovo_esr_ctrl_lock);
return rc;
}
static int fg_prepare_for_qnovo(struct fg_chip *chip, int qnovo_enable)
{
- int rc;
+ int rc = 0;
+ mutex_lock(&chip->qnovo_esr_ctrl_lock);
/* force esr extraction disable when qnovo enables */
rc = fg_sram_masked_write(chip, ESR_EXTRACTION_ENABLE_WORD,
ESR_EXTRACTION_ENABLE_OFFSET,
BIT(0), qnovo_enable ? 0 : BIT(0),
FG_IMA_DEFAULT);
- if (rc < 0)
+ if (rc < 0) {
pr_err("Error in configuring esr extraction rc=%d\n", rc);
+ goto out;
+ }
rc = fg_masked_write(chip, BATT_INFO_QNOVO_CFG(chip),
LD_REG_CTRL_BIT,
qnovo_enable ? LD_REG_CTRL_BIT : 0);
if (rc < 0) {
pr_err("Error in configuring qnovo_cfg rc=%d\n", rc);
- return rc;
+ goto out;
}
- fg_dbg(chip, FG_STATUS, "Prepared for Qnovo\n");
- return 0;
+
+ fg_dbg(chip, FG_STATUS, "%s for Qnovo\n",
+ qnovo_enable ? "Prepared" : "Unprepared");
+ chip->qnovo_enable = qnovo_enable;
+out:
+ mutex_unlock(&chip->qnovo_esr_ctrl_lock);
+ return rc;
}
static void ttf_work(struct work_struct *work)
@@ -4503,7 +4527,11 @@
static int fg_parse_ki_coefficients(struct fg_chip *chip)
{
struct device_node *node = chip->dev->of_node;
- int rc, i;
+ int rc, i, temp;
+
+ rc = of_property_read_u32(node, "qcom,ki-coeff-full-dischg", &temp);
+ if (!rc)
+ chip->dt.ki_coeff_full_soc_dischg = temp;
rc = fg_parse_dt_property_u32_array(node, "qcom,ki-coeff-soc-dischg",
chip->dt.ki_coeff_soc, KI_COEFF_SOC_LEVELS);
@@ -4972,7 +5000,6 @@
chip->debug_mask = &fg_gen3_debug_mask;
chip->irqs = fg_irqs;
chip->charge_status = -EINVAL;
- chip->prev_charge_status = -EINVAL;
chip->ki_coeff_full_soc = -EINVAL;
chip->online_status = -EINVAL;
chip->regmap = dev_get_regmap(chip->dev->parent, NULL);
@@ -5045,6 +5072,7 @@
mutex_init(&chip->cl.lock);
mutex_init(&chip->ttf.lock);
mutex_init(&chip->charge_full_lock);
+ mutex_init(&chip->qnovo_esr_ctrl_lock);
init_completion(&chip->soc_update);
init_completion(&chip->soc_ready);
init_completion(&chip->mem_grant);
diff --git a/drivers/power/supply/qcom/qpnp-smb2.c b/drivers/power/supply/qcom/qpnp-smb2.c
index 6abbaeb..d7fcfc4 100644
--- a/drivers/power/supply/qcom/qpnp-smb2.c
+++ b/drivers/power/supply/qcom/qpnp-smb2.c
@@ -188,6 +188,11 @@
module_param_named(
weak_chg_icl_ua, __weak_chg_icl_ua, int, 0600);
+static int __try_sink_enabled = 1;
+module_param_named(
+ try_sink_enabled, __try_sink_enabled, int, 0600
+);
+
#define MICRO_1P5A 1500000
#define MICRO_P1A 100000
#define OTG_DEFAULT_DEGLITCH_TIME_MS 50
@@ -1037,7 +1042,10 @@
val->intval = 0;
break;
case POWER_SUPPLY_PROP_DIE_HEALTH:
- rc = smblib_get_prop_die_health(chg, val);
+ if (chg->die_health == -EINVAL)
+ rc = smblib_get_prop_die_health(chg, val);
+ else
+ val->intval = chg->die_health;
break;
case POWER_SUPPLY_PROP_DP_DM:
val->intval = chg->pulse_cnt;
@@ -1145,6 +1153,10 @@
case POWER_SUPPLY_PROP_INPUT_CURRENT_LIMITED:
rc = smblib_set_prop_input_current_limited(chg, val);
break;
+ case POWER_SUPPLY_PROP_DIE_HEALTH:
+ chg->die_health = val->intval;
+ power_supply_changed(chg->batt_psy);
+ break;
default:
rc = -EINVAL;
}
@@ -1166,6 +1178,7 @@
case POWER_SUPPLY_PROP_INPUT_CURRENT_LIMITED:
case POWER_SUPPLY_PROP_STEP_CHARGING_ENABLED:
case POWER_SUPPLY_PROP_SW_JEITA_ENABLED:
+ case POWER_SUPPLY_PROP_DIE_HEALTH:
return 1;
default:
break;
@@ -1647,15 +1660,6 @@
return rc;
}
- /* disable SW STAT override */
- rc = smblib_masked_write(chg, STAT_CFG_REG,
- STAT_SW_OVERRIDE_CFG_BIT, 0);
- if (rc < 0) {
- dev_err(chg->dev, "Couldn't disable SW STAT override rc=%d\n",
- rc);
- return rc;
- }
-
/* disable h/w autonomous parallel charging control */
rc = smblib_masked_write(chg, MISC_CFG_REG,
STAT_PARALLEL_1400MA_EN_CFG_BIT, 0);
@@ -2244,9 +2248,11 @@
chg->dev = &pdev->dev;
chg->param = v1_params;
chg->debug_mask = &__debug_mask;
+ chg->try_sink_enabled = &__try_sink_enabled;
chg->weak_chg_icl_ua = &__weak_chg_icl_ua;
chg->mode = PARALLEL_MASTER;
chg->irq_info = smb2_irqs;
+ chg->die_health = -EINVAL;
chg->name = "PMI";
chg->regmap = dev_get_regmap(chg->dev->parent, NULL);
diff --git a/drivers/power/supply/qcom/smb-lib.c b/drivers/power/supply/qcom/smb-lib.c
index 1b890d5..e69e8f2 100644
--- a/drivers/power/supply/qcom/smb-lib.c
+++ b/drivers/power/supply/qcom/smb-lib.c
@@ -143,6 +143,23 @@
return rc;
}
+int smblib_stat_sw_override_cfg(struct smb_charger *chg, bool override)
+{
+ int rc;
+
+ /* override = 1, SW STAT override; override = 0, HW auto mode */
+ rc = smblib_masked_write(chg, STAT_CFG_REG,
+ STAT_SW_OVERRIDE_CFG_BIT,
+ override ? STAT_SW_OVERRIDE_CFG_BIT : 0);
+ if (rc < 0) {
+ dev_err(chg->dev, "Couldn't configure SW STAT override rc=%d\n",
+ rc);
+ return rc;
+ }
+
+ return rc;
+}
+
/********************
* REGISTER GETTERS *
********************/
@@ -584,8 +601,10 @@
schedule_work(&chg->bms_update_work);
}
- if (!chg->pl.psy && !strcmp(psy->desc->name, "parallel"))
+ if (!chg->pl.psy && !strcmp(psy->desc->name, "parallel")) {
chg->pl.psy = psy;
+ schedule_work(&chg->pl_update_work);
+ }
return NOTIFY_OK;
}
@@ -2250,12 +2269,6 @@
int smblib_get_prop_usb_voltage_now(struct smb_charger *chg,
union power_supply_propval *val)
{
- int rc = 0;
-
- rc = smblib_get_prop_usb_present(chg, val);
- if (rc < 0 || !val->intval)
- return rc;
-
if (!chg->iio.usbin_v_chan ||
PTR_ERR(chg->iio.usbin_v_chan) == -EPROBE_DEFER)
chg->iio.usbin_v_chan = iio_channel_get(chg->dev, "usbin_v");
@@ -2798,7 +2811,7 @@
hvdcp = stat & QC_CHARGER_BIT;
vote(chg->apsd_disable_votable, PD_VOTER, false, 0);
vote(chg->pd_allowed_votable, PD_VOTER, true, 0);
- vote(chg->usb_irq_enable_votable, PD_VOTER, true, 0);
+ vote(chg->usb_irq_enable_votable, PD_VOTER, false, 0);
vote(chg->hvdcp_disable_votable_indirect, PD_INACTIVE_VOTER,
false, 0);
@@ -3779,8 +3792,165 @@
return IRQ_HANDLED;
}
+static int typec_try_sink(struct smb_charger *chg)
+{
+ union power_supply_propval val;
+ bool debounce_done, vbus_detected, sink;
+ u8 stat;
+ int exit_mode = ATTACHED_SRC, rc;
+
+ /* ignore typec interrupt while try.snk WIP */
+ chg->try_sink_active = true;
+
+ /* force SNK mode */
+ val.intval = POWER_SUPPLY_TYPEC_PR_SINK;
+ rc = smblib_set_prop_typec_power_role(chg, &val);
+ if (rc < 0) {
+ smblib_err(chg, "Couldn't set UFP mode rc=%d\n", rc);
+ goto try_sink_exit;
+ }
+
+ /* reduce Tccdebounce time to ~20ms */
+ rc = smblib_masked_write(chg, MISC_CFG_REG,
+ TCC_DEBOUNCE_20MS_BIT, TCC_DEBOUNCE_20MS_BIT);
+ if (rc < 0) {
+ smblib_err(chg, "Couldn't set MISC_CFG_REG rc=%d\n", rc);
+ goto try_sink_exit;
+ }
+
+ /*
+ * give opportunity to the other side to be a SRC,
+ * for tDRPTRY + Tccdebounce time
+ */
+ msleep(100);
+
+ rc = smblib_read(chg, TYPE_C_STATUS_4_REG, &stat);
+ if (rc < 0) {
+ smblib_err(chg, "Couldn't read TYPE_C_STATUS_4 rc=%d\n",
+ rc);
+ goto try_sink_exit;
+ }
+
+ debounce_done = stat & TYPEC_DEBOUNCE_DONE_STATUS_BIT;
+
+ if (!debounce_done)
+ /*
+ * The other side didn't switch to source, either it
+ * is an adamant sink or is removed go back to showing Rp
+ */
+ goto try_wait_src;
+
+ /*
+ * We are in force sink mode and the other side has switched to
+ * showing Rp. Config DRP in case the other side removes Rp so we
+ * can quickly (20ms) switch to showing our Rp. Note that the spec
+ * needs us to show Rp for 80mS while the drp DFP residency is just
+ * 54mS. But 54mS is plenty time for us to react and force Rp for
+ * the remaining 26mS.
+ */
+ val.intval = POWER_SUPPLY_TYPEC_PR_DUAL;
+ rc = smblib_set_prop_typec_power_role(chg, &val);
+ if (rc < 0) {
+ smblib_err(chg, "Couldn't set DFP mode rc=%d\n",
+ rc);
+ goto try_sink_exit;
+ }
+
+ /*
+ * while other side is Rp, wait for VBUS from it; exit if other side
+ * removes Rp
+ */
+ do {
+ rc = smblib_read(chg, TYPE_C_STATUS_4_REG, &stat);
+ if (rc < 0) {
+ smblib_err(chg, "Couldn't read TYPE_C_STATUS_4 rc=%d\n",
+ rc);
+ goto try_sink_exit;
+ }
+
+ debounce_done = stat & TYPEC_DEBOUNCE_DONE_STATUS_BIT;
+ vbus_detected = stat & TYPEC_VBUS_STATUS_BIT;
+
+ /* Successfully transitioned to ATTACHED.SNK */
+ if (vbus_detected && debounce_done) {
+ exit_mode = ATTACHED_SINK;
+ goto try_sink_exit;
+ }
+
+ /*
+ * Ensure sink since drp may put us in source if other
+ * side switches back to Rd
+ */
+ sink = !(stat & UFP_DFP_MODE_STATUS_BIT);
+
+ usleep_range(1000, 2000);
+ } while (debounce_done && sink);
+
+try_wait_src:
+ /*
+ * Transition to trywait.SRC state. check if other side still wants
+ * to be SNK or has been removed.
+ */
+ val.intval = POWER_SUPPLY_TYPEC_PR_SOURCE;
+ rc = smblib_set_prop_typec_power_role(chg, &val);
+ if (rc < 0) {
+ smblib_err(chg, "Couldn't set UFP mode rc=%d\n", rc);
+ goto try_sink_exit;
+ }
+
+ /* Need to be in this state for tDRPTRY time, 75ms~150ms */
+ msleep(80);
+
+ rc = smblib_read(chg, TYPE_C_STATUS_4_REG, &stat);
+ if (rc < 0) {
+ smblib_err(chg, "Couldn't read TYPE_C_STATUS_4 rc=%d\n", rc);
+ goto try_sink_exit;
+ }
+
+ debounce_done = stat & TYPEC_DEBOUNCE_DONE_STATUS_BIT;
+
+ if (debounce_done)
+ /* the other side wants to be a sink */
+ exit_mode = ATTACHED_SRC;
+ else
+ /* the other side is detached */
+ exit_mode = UNATTACHED_SINK;
+
+try_sink_exit:
+ /* release forcing of SRC/SNK mode */
+ val.intval = POWER_SUPPLY_TYPEC_PR_DUAL;
+ rc = smblib_set_prop_typec_power_role(chg, &val);
+ if (rc < 0)
+ smblib_err(chg, "Couldn't set DFP mode rc=%d\n", rc);
+
+ /* revert Tccdebounce time back to ~120ms */
+ rc = smblib_masked_write(chg, MISC_CFG_REG, TCC_DEBOUNCE_20MS_BIT, 0);
+ if (rc < 0)
+ smblib_err(chg, "Couldn't set MISC_CFG_REG rc=%d\n", rc);
+
+ chg->try_sink_active = false;
+
+ return exit_mode;
+}
+
static void typec_sink_insertion(struct smb_charger *chg)
{
+ int exit_mode;
+
+ /*
+ * Try.SNK entry status - ATTACHWAIT.SRC state and detected Rd-open
+ * or RD-Ra for TccDebounce time.
+ */
+
+ if (*chg->try_sink_enabled) {
+ exit_mode = typec_try_sink(chg);
+
+ if (exit_mode != ATTACHED_SRC) {
+ smblib_usb_typec_change(chg);
+ return;
+ }
+ }
+
/* when a sink is inserted we should not wait on hvdcp timeout to
* enable pd
*/
@@ -4047,7 +4217,7 @@
smblib_typec_mode_name[chg->typec_mode]);
}
-static void smblib_usb_typec_change(struct smb_charger *chg)
+void smblib_usb_typec_change(struct smb_charger *chg)
{
int rc;
@@ -4083,7 +4253,8 @@
return IRQ_HANDLED;
}
- if (chg->cc2_detach_wa_active || chg->typec_en_dis_active) {
+ if (chg->cc2_detach_wa_active || chg->typec_en_dis_active ||
+ chg->try_sink_active) {
smblib_dbg(chg, PR_INTERRUPT, "Ignoring since %s active\n",
chg->cc2_detach_wa_active ?
"cc2_detach_wa" : "typec_en_dis");
@@ -4117,6 +4288,14 @@
struct smb_charger *chg = irq_data->parent_data;
chg->is_hdc = true;
+ /*
+ * Disable usb IRQs after the flag set and re-enable IRQs after
+ * the flag cleared in the delayed work queue, to avoid any IRQ
+ * storming during the delays
+ */
+ if (chg->irq_info[HIGH_DUTY_CYCLE_IRQ].irq)
+ disable_irq_nosync(chg->irq_info[HIGH_DUTY_CYCLE_IRQ].irq);
+
schedule_delayed_work(&chg->clear_hdc_work, msecs_to_jiffies(60));
return IRQ_HANDLED;
@@ -4288,12 +4467,22 @@
power_supply_changed(chg->batt_psy);
}
+static void pl_update_work(struct work_struct *work)
+{
+ struct smb_charger *chg = container_of(work, struct smb_charger,
+ pl_update_work);
+
+ smblib_stat_sw_override_cfg(chg, false);
+}
+
static void clear_hdc_work(struct work_struct *work)
{
struct smb_charger *chg = container_of(work, struct smb_charger,
clear_hdc_work.work);
chg->is_hdc = 0;
+ if (chg->irq_info[HIGH_DUTY_CYCLE_IRQ].irq)
+ enable_irq(chg->irq_info[HIGH_DUTY_CYCLE_IRQ].irq);
}
static void rdstd_cc2_detach_work(struct work_struct *work)
@@ -4818,6 +5007,7 @@
mutex_init(&chg->otg_oc_lock);
mutex_init(&chg->vconn_oc_lock);
INIT_WORK(&chg->bms_update_work, bms_update_work);
+ INIT_WORK(&chg->pl_update_work, pl_update_work);
INIT_WORK(&chg->rdstd_cc2_detach_work, rdstd_cc2_detach_work);
INIT_DELAYED_WORK(&chg->hvdcp_detect_work, smblib_hvdcp_detect_work);
INIT_DELAYED_WORK(&chg->clear_hdc_work, clear_hdc_work);
@@ -4866,6 +5056,14 @@
chg->bms_psy = power_supply_get_by_name("bms");
chg->pl.psy = power_supply_get_by_name("parallel");
+ if (chg->pl.psy) {
+ rc = smblib_stat_sw_override_cfg(chg, false);
+ if (rc < 0) {
+ smblib_err(chg,
+ "Couldn't config stat sw rc=%d\n", rc);
+ return rc;
+ }
+ }
break;
case PARALLEL_SLAVE:
break;
@@ -4882,6 +5080,7 @@
switch (chg->mode) {
case PARALLEL_MASTER:
cancel_work_sync(&chg->bms_update_work);
+ cancel_work_sync(&chg->pl_update_work);
cancel_work_sync(&chg->rdstd_cc2_detach_work);
cancel_delayed_work_sync(&chg->hvdcp_detect_work);
cancel_delayed_work_sync(&chg->clear_hdc_work);
diff --git a/drivers/power/supply/qcom/smb-lib.h b/drivers/power/supply/qcom/smb-lib.h
index 80f5bca..d31428b 100644
--- a/drivers/power/supply/qcom/smb-lib.h
+++ b/drivers/power/supply/qcom/smb-lib.h
@@ -130,6 +130,12 @@
SMB_IRQ_MAX,
};
+enum try_sink_exit_mode {
+ ATTACHED_SRC = 0,
+ ATTACHED_SINK,
+ UNATTACHED_SINK,
+};
+
struct smb_irq_info {
const char *name;
const irq_handler_t handler;
@@ -232,6 +238,7 @@
struct smb_params param;
struct smb_iio iio;
int *debug_mask;
+ int *try_sink_enabled;
enum smb_mode mode;
struct smb_chg_freq chg_freq;
int smb_version;
@@ -287,6 +294,7 @@
/* work */
struct work_struct bms_update_work;
+ struct work_struct pl_update_work;
struct work_struct rdstd_cc2_detach_work;
struct delayed_work hvdcp_detect_work;
struct delayed_work ps_change_timeout_work;
@@ -342,6 +350,7 @@
u32 wa_flags;
bool cc2_detach_wa_active;
bool typec_en_dis_active;
+ bool try_sink_active;
int boost_current_ua;
int temp_speed_reading_count;
@@ -355,6 +364,8 @@
/* qnovo */
int usb_icl_delta_ua;
int pulse_cnt;
+
+ int die_health;
};
int smblib_read(struct smb_charger *chg, u16 addr, u8 *val);
@@ -523,6 +534,8 @@
union power_supply_propval *val);
int smblib_set_prop_pr_swap_in_progress(struct smb_charger *chg,
const union power_supply_propval *val);
+int smblib_stat_sw_override_cfg(struct smb_charger *chg, bool override);
+void smblib_usb_typec_change(struct smb_charger *chg);
int smblib_init(struct smb_charger *chg);
int smblib_deinit(struct smb_charger *chg);
diff --git a/drivers/power/supply/qcom/smb1351-charger.c b/drivers/power/supply/qcom/smb1351-charger.c
index a464a81..4b2e9c8 100644
--- a/drivers/power/supply/qcom/smb1351-charger.c
+++ b/drivers/power/supply/qcom/smb1351-charger.c
@@ -861,7 +861,7 @@
return (reg & CMD_OTG_EN_BIT) ? 1 : 0;
}
-struct regulator_ops smb1351_chg_otg_reg_ops = {
+static struct regulator_ops smb1351_chg_otg_reg_ops = {
.enable = smb1351_chg_otg_regulator_enable,
.disable = smb1351_chg_otg_regulator_disable,
.is_enabled = smb1351_chg_otg_regulator_is_enable,
diff --git a/drivers/power/supply/qcom/smb1355-charger.c b/drivers/power/supply/qcom/smb1355-charger.c
index 4e1bb17..4b42420 100644
--- a/drivers/power/supply/qcom/smb1355-charger.c
+++ b/drivers/power/supply/qcom/smb1355-charger.c
@@ -146,6 +146,8 @@
struct power_supply *parallel_psy;
struct pmic_revid_data *pmic_rev_id;
+
+ int c_health;
};
static bool is_secure(struct smb1355 *chip, int addr)
@@ -434,7 +436,10 @@
val->intval = POWER_SUPPLY_PL_USBMID_USBMID;
break;
case POWER_SUPPLY_PROP_CONNECTOR_HEALTH:
- val->intval = smb1355_get_prop_connector_health(chip);
+ if (chip->c_health == -EINVAL)
+ val->intval = smb1355_get_prop_connector_health(chip);
+ else
+ val->intval = chip->c_health;
break;
default:
pr_err_ratelimited("parallel psy get prop %d not supported\n",
@@ -497,6 +502,10 @@
rc = smb1355_set_charge_param(chip, &chip->param.fcc,
val->intval);
break;
+ case POWER_SUPPLY_PROP_CONNECTOR_HEALTH:
+ chip->c_health = val->intval;
+ power_supply_changed(chip->parallel_psy);
+ break;
default:
pr_debug("parallel power supply set prop %d not supported\n",
prop);
@@ -509,6 +518,13 @@
static int smb1355_parallel_prop_is_writeable(struct power_supply *psy,
enum power_supply_property prop)
{
+ switch (prop) {
+ case POWER_SUPPLY_PROP_CONNECTOR_HEALTH:
+ return 1;
+ default:
+ break;
+ }
+
return 0;
}
@@ -613,6 +629,7 @@
[0] = {
.name = "wdog-bark",
.handler = smb1355_handle_wdog_bark,
+ .wake = true,
},
[1] = {
.name = "chg-state-change",
@@ -713,6 +730,7 @@
chip->dev = &pdev->dev;
chip->param = v1_params;
+ chip->c_health = -EINVAL;
chip->name = "smb1355";
mutex_init(&chip->write_lock);
@@ -762,14 +780,26 @@
return 0;
}
+static void smb1355_shutdown(struct platform_device *pdev)
+{
+ struct smb1355 *chip = platform_get_drvdata(pdev);
+ int rc;
+
+ /* disable parallel charging path */
+ rc = smb1355_set_parallel_charging(chip, true);
+ if (rc < 0)
+ pr_err("Couldn't disable parallel path rc=%d\n", rc);
+}
+
static struct platform_driver smb1355_driver = {
.driver = {
.name = "qcom,smb1355-charger",
.owner = THIS_MODULE,
.of_match_table = match_table,
},
- .probe = smb1355_probe,
- .remove = smb1355_remove,
+ .probe = smb1355_probe,
+ .remove = smb1355_remove,
+ .shutdown = smb1355_shutdown,
};
module_platform_driver(smb1355_driver);
diff --git a/drivers/power/supply/qcom/smb135x-charger.c b/drivers/power/supply/qcom/smb135x-charger.c
index 803dd6e..edc0998 100644
--- a/drivers/power/supply/qcom/smb135x-charger.c
+++ b/drivers/power/supply/qcom/smb135x-charger.c
@@ -2218,7 +2218,7 @@
return (reg & OTG_EN) ? 1 : 0;
}
-struct regulator_ops smb135x_chg_otg_reg_ops = {
+static struct regulator_ops smb135x_chg_otg_reg_ops = {
.enable = smb135x_chg_otg_regulator_enable,
.disable = smb135x_chg_otg_regulator_disable,
.is_enabled = smb135x_chg_otg_regulator_is_enable,
diff --git a/drivers/pwm/pwm-qpnp.c b/drivers/pwm/pwm-qpnp.c
index 86f08d2..e7267de 100644
--- a/drivers/pwm/pwm-qpnp.c
+++ b/drivers/pwm/pwm-qpnp.c
@@ -317,6 +317,7 @@
struct pwm_period_config period;
int supported_sizes;
int force_pwm_size;
+ bool update_period;
};
/* Public facing structure */
@@ -327,6 +328,7 @@
bool enabled;
struct _qpnp_pwm_config pwm_config;
struct qpnp_lpg_config lpg_config;
+ enum pm_pwm_mode pwm_mode;
spinlock_t lpg_lock;
enum qpnp_lpg_revision revision;
u8 sub_type;
@@ -1211,28 +1213,32 @@
rc = qpnp_lpg_save_pwm_value(chip);
if (rc)
goto out;
- rc = qpnp_lpg_configure_pwm(chip);
- if (rc)
- goto out;
- rc = qpnp_configure_pwm_control(chip);
- if (rc)
- goto out;
- if (!rc && chip->enabled) {
- rc = qpnp_lpg_configure_pwm_state(chip, QPNP_PWM_ENABLE);
- if (rc) {
- pr_err("Error in configuring pwm state, rc=%d\n", rc);
- return rc;
- }
+ if (pwm_config->update_period) {
+ rc = qpnp_lpg_configure_pwm(chip);
+ if (rc)
+ goto out;
+ rc = qpnp_configure_pwm_control(chip);
+ if (rc)
+ goto out;
+ if (!rc && chip->enabled) {
+ rc = qpnp_lpg_configure_pwm_state(chip,
+ QPNP_PWM_ENABLE);
+ if (rc) {
+ pr_err("Error in configuring pwm state, rc=%d\n",
+ rc);
+ return rc;
+ }
- /* Enable the glitch removal after PWM is enabled */
- rc = qpnp_lpg_glitch_removal(chip, true);
- if (rc) {
- pr_err("Error in enabling glitch control, rc=%d\n", rc);
- return rc;
+ /* Enable the glitch removal after PWM is enabled */
+ rc = qpnp_lpg_glitch_removal(chip, true);
+ if (rc) {
+ pr_err("Error in enabling glitch control, rc=%d\n",
+ rc);
+ return rc;
+ }
}
}
-
pr_debug("duty/period=%u/%u %s: pwm_value=%d (of %d)\n",
(unsigned int)duty_value, (unsigned int)period_value,
(tm_lvl == LVL_USEC) ? "usec" : "nsec",
@@ -1309,12 +1315,10 @@
return rc;
}
+/* lpg_lock should be held while calling _pwm_enable() */
static int _pwm_enable(struct qpnp_pwm_chip *chip)
{
int rc = 0;
- unsigned long flags;
-
- spin_lock_irqsave(&chip->lpg_lock, flags);
if (QPNP_IS_PWM_CONFIG_SELECTED(
chip->qpnp_lpg_registers[QPNP_ENABLE_CONTROL]) ||
@@ -1327,8 +1331,21 @@
if (!rc)
chip->enabled = true;
- spin_unlock_irqrestore(&chip->lpg_lock, flags);
+ return rc;
+}
+/* lpg_lock should be held while calling _pwm_change_mode() */
+static int _pwm_change_mode(struct qpnp_pwm_chip *chip, enum pm_pwm_mode mode)
+{
+ int rc;
+
+ if (mode == PM_PWM_MODE_LPG)
+ rc = qpnp_configure_lpg_control(chip);
+ else
+ rc = qpnp_configure_pwm_control(chip);
+
+ if (rc)
+ pr_err("Failed to change the mode\n");
return rc;
}
@@ -1375,12 +1392,14 @@
spin_lock_irqsave(&chip->lpg_lock, flags);
+ chip->pwm_config.update_period = false;
if (prev_period_us > INT_MAX / NSEC_PER_USEC ||
prev_period_us * NSEC_PER_USEC != period_ns) {
qpnp_lpg_calc_period(LVL_NSEC, period_ns, chip);
qpnp_lpg_save_period(chip);
pwm->state.period = period_ns;
chip->pwm_config.pwm_period = period_ns / NSEC_PER_USEC;
+ chip->pwm_config.update_period = true;
}
rc = _pwm_config(chip, LVL_NSEC, duty_ns, period_ns);
@@ -1403,11 +1422,15 @@
{
int rc;
struct qpnp_pwm_chip *chip = qpnp_pwm_from_pwm_chip(pwm_chip);
+ unsigned long flags;
+ spin_lock_irqsave(&chip->lpg_lock, flags);
rc = _pwm_enable(chip);
if (rc)
pr_err("Failed to enable PWM channel: %d\n", chip->channel_id);
+ spin_unlock_irqrestore(&chip->lpg_lock, flags);
+
return rc;
}
@@ -1445,20 +1468,6 @@
chip->channel_id);
}
-static int _pwm_change_mode(struct qpnp_pwm_chip *chip, enum pm_pwm_mode mode)
-{
- int rc;
-
- if (mode)
- rc = qpnp_configure_lpg_control(chip);
- else
- rc = qpnp_configure_pwm_control(chip);
-
- if (rc)
- pr_err("Failed to change the mode\n");
- return rc;
-}
-
/**
* pwm_change_mode - Change the PWM mode configuration
* @pwm: the PWM device
@@ -1466,7 +1475,7 @@
*/
int pwm_change_mode(struct pwm_device *pwm, enum pm_pwm_mode mode)
{
- int rc;
+ int rc = 0;
unsigned long flags;
struct qpnp_pwm_chip *chip;
@@ -1483,7 +1492,22 @@
chip = qpnp_pwm_from_pwm_dev(pwm);
spin_lock_irqsave(&chip->lpg_lock, flags);
- rc = _pwm_change_mode(chip, mode);
+ if (chip->pwm_mode != mode) {
+ rc = _pwm_change_mode(chip, mode);
+ if (rc) {
+ pr_err("Failed to change mode: %d, rc=%d\n", mode, rc);
+ goto unlock;
+ }
+ chip->pwm_mode = mode;
+ if (chip->enabled) {
+ rc = _pwm_enable(chip);
+ if (rc) {
+ pr_err("Failed to enable PWM, rc=%d\n", rc);
+ goto unlock;
+ }
+ }
+ }
+unlock:
spin_unlock_irqrestore(&chip->lpg_lock, flags);
return rc;
@@ -1619,6 +1643,7 @@
spin_lock_irqsave(&chip->lpg_lock, flags);
+ chip->pwm_config.update_period = false;
if (chip->pwm_config.pwm_period != period_us) {
qpnp_lpg_calc_period(LVL_USEC, period_us, chip);
qpnp_lpg_save_period(chip);
@@ -1629,6 +1654,7 @@
else
pwm->state.period
= (unsigned int)period_us * NSEC_PER_USEC;
+ chip->pwm_config.update_period = true;
}
rc = _pwm_config(chip, LVL_USEC, duty_us, period_us);
@@ -1735,6 +1761,7 @@
qpnp_lpg_calc_period(LVL_USEC, period, chip);
qpnp_lpg_save_period(chip);
chip->pwm_config.pwm_period = period;
+ chip->pwm_config.update_period = true;
rc = _pwm_config(chip, LVL_USEC, chip->pwm_config.pwm_duty, period);
@@ -1885,7 +1912,7 @@
static int qpnp_parse_dt_config(struct platform_device *pdev,
struct qpnp_pwm_chip *chip)
{
- int rc, enable, lut_entry_size, list_size, i;
+ int rc, mode, lut_entry_size, list_size, i;
const char *label;
const __be32 *prop;
u32 size;
@@ -2069,18 +2096,20 @@
}
}
- rc = of_property_read_u32(of_node, "qcom,mode-select", &enable);
+ rc = of_property_read_u32(of_node, "qcom,mode-select", &mode);
if (rc)
goto read_opt_props;
- if ((enable == PM_PWM_MODE_PWM && found_pwm_subnode == 0) ||
- (enable == PM_PWM_MODE_LPG && found_lpg_subnode == 0)) {
+ if (mode > PM_PWM_MODE_LPG ||
+ (mode == PM_PWM_MODE_PWM && found_pwm_subnode == 0) ||
+ (mode == PM_PWM_MODE_LPG && found_lpg_subnode == 0)) {
dev_err(&pdev->dev, "%s: Invalid mode select\n", __func__);
rc = -EINVAL;
goto out;
}
- _pwm_change_mode(chip, enable);
+ chip->pwm_mode = mode;
+ _pwm_change_mode(chip, mode);
_pwm_enable(chip);
read_opt_props:
diff --git a/drivers/scsi/sg.c b/drivers/scsi/sg.c
index ecc6aad..4bd6fd4 100644
--- a/drivers/scsi/sg.c
+++ b/drivers/scsi/sg.c
@@ -500,7 +500,7 @@
old_hdr->result = EIO;
break;
case DID_ERROR:
- old_hdr->result = (srp->sense_b[0] == 0 &&
+ old_hdr->result = (srp->sense_b[0] == 0 &&
hp->masked_status == GOOD) ? 0 : EIO;
break;
default:
@@ -859,8 +859,10 @@
return -ENXIO;
if (!access_ok(VERIFY_WRITE, p, SZ_SG_IO_HDR))
return -EFAULT;
+ mutex_lock(&sfp->parentdp->open_rel_lock);
result = sg_new_write(sfp, filp, p, SZ_SG_IO_HDR,
1, read_only, 1, &srp);
+ mutex_unlock(&sfp->parentdp->open_rel_lock);
if (result < 0)
return result;
result = wait_event_interruptible(sfp->read_wait,
@@ -901,8 +903,10 @@
sfp->low_dma = 1;
if ((0 == sfp->low_dma) && !sfp->res_in_use) {
val = (int) sfp->reserve.bufflen;
+ mutex_lock(&sfp->parentdp->open_rel_lock);
sg_remove_scat(sfp, &sfp->reserve);
sg_build_reserve(sfp, val);
+ mutex_unlock(&sfp->parentdp->open_rel_lock);
}
} else {
if (atomic_read(&sdp->detaching))
@@ -970,8 +974,8 @@
result = get_user(val, ip);
if (result)
return result;
- if (val < 0)
- return -EINVAL;
+ if (val < 0)
+ return -EINVAL;
val = min_t(int, val,
max_sectors_bytes(sdp->device->request_queue));
mutex_lock(&sfp->f_mutex);
@@ -981,9 +985,10 @@
mutex_unlock(&sfp->f_mutex);
return -EBUSY;
}
-
+ mutex_lock(&sfp->parentdp->open_rel_lock);
sg_remove_scat(sfp, &sfp->reserve);
sg_build_reserve(sfp, val);
+ mutex_unlock(&sfp->parentdp->open_rel_lock);
}
mutex_unlock(&sfp->f_mutex);
return 0;
@@ -1039,8 +1044,8 @@
if (srp) {
rinfo[val].req_state = srp->done + 1;
rinfo[val].problem =
- srp->header.masked_status &
- srp->header.host_status &
+ srp->header.masked_status &
+ srp->header.host_status &
srp->header.driver_status;
if (srp->done)
rinfo[val].duration =
@@ -1061,7 +1066,7 @@
}
}
read_unlock_irqrestore(&sfp->rq_list_lock, iflags);
- result = __copy_to_user(p, rinfo,
+ result = __copy_to_user(p, rinfo,
SZ_SG_REQ_INFO * SG_MAX_QUEUE);
result = result ? -EFAULT : 0;
kfree(rinfo);
@@ -1137,14 +1142,14 @@
return -ENXIO;
sdev = sdp->device;
- if (sdev->host->hostt->compat_ioctl) {
+ if (sdev->host->hostt->compat_ioctl) {
int ret;
ret = sdev->host->hostt->compat_ioctl(sdev, cmd_in, (void __user *)arg);
return ret;
}
-
+
return -ENOIOCTLCMD;
}
#endif
@@ -1248,6 +1253,7 @@
unsigned long req_sz, len, sa;
Sg_scatter_hold *rsv_schp;
int k, length;
+ int ret = 0;
if ((!filp) || (!vma) || (!(sfp = (Sg_fd *) filp->private_data)))
return -ENXIO;
@@ -1258,8 +1264,11 @@
if (vma->vm_pgoff)
return -EINVAL; /* want no offset */
rsv_schp = &sfp->reserve;
- if (req_sz > rsv_schp->bufflen)
- return -ENOMEM; /* cannot map more than reserved buffer */
+ mutex_lock(&sfp->f_mutex);
+ if (req_sz > rsv_schp->bufflen) {
+ ret = -ENOMEM; /* cannot map more than reserved buffer */
+ goto out;
+ }
sa = vma->vm_start;
length = 1 << (PAGE_SHIFT + rsv_schp->page_order);
@@ -1273,7 +1282,9 @@
vma->vm_flags |= VM_IO | VM_DONTEXPAND | VM_DONTDUMP;
vma->vm_private_data = sfp;
vma->vm_ops = &sg_mmap_vm_ops;
- return 0;
+out:
+ mutex_unlock(&sfp->f_mutex);
+ return ret;
}
static void
@@ -1628,7 +1639,7 @@
else
def_reserved_size = sg_big_buff;
- rc = register_chrdev_region(MKDEV(SCSI_GENERIC_MAJOR, 0),
+ rc = register_chrdev_region(MKDEV(SCSI_GENERIC_MAJOR, 0),
SG_MAX_DEVS, "sg");
if (rc)
return rc;
@@ -1742,9 +1753,12 @@
!sfp->res_in_use) {
sfp->res_in_use = 1;
sg_link_reserve(sfp, srp, dxfer_len);
- } else if ((hp->flags & SG_FLAG_MMAP_IO) && sfp->res_in_use) {
+ } else if (hp->flags & SG_FLAG_MMAP_IO) {
+ res = -EBUSY; /* sfp->res_in_use == 1 */
+ if (dxfer_len > rsv_schp->bufflen)
+ res = -ENOMEM;
mutex_unlock(&sfp->f_mutex);
- return -EBUSY;
+ return res;
} else {
res = sg_build_indirect(req_schp, sfp, dxfer_len);
if (res) {
@@ -2306,7 +2320,7 @@
};
static int sg_proc_single_open_dressz(struct inode *inode, struct file *file);
-static ssize_t sg_proc_write_dressz(struct file *filp,
+static ssize_t sg_proc_write_dressz(struct file *filp,
const char __user *buffer, size_t count, loff_t *off);
static const struct file_operations dressz_fops = {
.owner = THIS_MODULE,
@@ -2446,7 +2460,7 @@
return single_open(file, sg_proc_seq_show_int, &sg_allow_dio);
}
-static ssize_t
+static ssize_t
sg_proc_write_adio(struct file *filp, const char __user *buffer,
size_t count, loff_t *off)
{
@@ -2467,7 +2481,7 @@
return single_open(file, sg_proc_seq_show_int, &sg_big_buff);
}
-static ssize_t
+static ssize_t
sg_proc_write_dressz(struct file *filp, const char __user *buffer,
size_t count, loff_t *off)
{
@@ -2627,7 +2641,7 @@
hp = &srp->header;
new_interface = (hp->interface_id == '\0') ? 0 : 1;
if (srp->res_used) {
- if (new_interface &&
+ if (new_interface &&
(SG_FLAG_MMAP_IO & hp->flags))
cp = " mmap>> ";
else
diff --git a/drivers/scsi/ufs/ufs-debugfs.c b/drivers/scsi/ufs/ufs-debugfs.c
index 557ca19..11e11e4 100644
--- a/drivers/scsi/ufs/ufs-debugfs.c
+++ b/drivers/scsi/ufs/ufs-debugfs.c
@@ -950,6 +950,10 @@
seq_printf(file, "hba->saved_err = 0x%x\n", hba->saved_err);
seq_printf(file, "hba->saved_uic_err = 0x%x\n", hba->saved_uic_err);
+ seq_printf(file, "power_mode_change_cnt = %d\n",
+ hba->ufs_stats.power_mode_change_cnt);
+ seq_printf(file, "hibern8_exit_cnt = %d\n",
+ hba->ufs_stats.hibern8_exit_cnt);
return 0;
}
diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
index f5bfddd..b6ba4c4 100644
--- a/drivers/scsi/ufs/ufshcd.c
+++ b/drivers/scsi/ufs/ufshcd.c
@@ -4875,6 +4875,7 @@
memcpy(&hba->pwr_info, pwr_mode,
sizeof(struct ufs_pa_layer_attr));
+ hba->ufs_stats.power_mode_change_cnt++;
}
return ret;
@@ -7640,9 +7641,6 @@
{
int err_reg_hist_size = sizeof(struct ufs_uic_err_reg_hist);
- hba->ufs_stats.hibern8_exit_cnt = 0;
- hba->ufs_stats.last_hibern8_exit_tstamp = ktime_set(0, 0);
-
memset(&hba->ufs_stats.pa_err, 0, err_reg_hist_size);
memset(&hba->ufs_stats.dl_err, 0, err_reg_hist_size);
memset(&hba->ufs_stats.nl_err, 0, err_reg_hist_size);
diff --git a/drivers/scsi/ufs/ufshcd.h b/drivers/scsi/ufs/ufshcd.h
index a2c36a2..1b21238 100644
--- a/drivers/scsi/ufs/ufshcd.h
+++ b/drivers/scsi/ufs/ufshcd.h
@@ -644,6 +644,7 @@
struct ufshcd_clk_ctx clk_rel;
u32 hibern8_exit_cnt;
ktime_t last_hibern8_exit_tstamp;
+ u32 power_mode_change_cnt;
struct ufs_uic_err_reg_hist pa_err;
struct ufs_uic_err_reg_hist dl_err;
struct ufs_uic_err_reg_hist nl_err;
diff --git a/drivers/slimbus/slimbus.c b/drivers/slimbus/slimbus.c
index 567f290..3ae9a10 100644
--- a/drivers/slimbus/slimbus.c
+++ b/drivers/slimbus/slimbus.c
@@ -2397,6 +2397,8 @@
bool opensl1valid = false;
int maxctrlw1, maxctrlw3, i;
+ /* intitalize array to zero */
+ memset(opensl1, 0x0, sizeof(opensl1));
finalexp = (ctrl->sched.chc3[last3])->rootexp;
if (last1 >= 0) {
slc1 = ctrl->sched.chc1[coeff1];
diff --git a/drivers/soc/qcom/Makefile b/drivers/soc/qcom/Makefile
index 6eef58f..37b33e6 100644
--- a/drivers/soc/qcom/Makefile
+++ b/drivers/soc/qcom/Makefile
@@ -54,7 +54,7 @@
obj-$(CONFIG_MSM_SYSTEM_HEALTH_MONITOR) += system_health_monitor_v01.o
obj-$(CONFIG_MSM_SYSTEM_HEALTH_MONITOR) += system_health_monitor.o
obj-$(CONFIG_MSM_SYSMON_GLINK_COMM) += sysmon-glink.o sysmon-qmi.o
-obj-$(CONFIG_ICNSS) += icnss.o wlan_firmware_service_v01.o icnss_utils.o
+obj-$(CONFIG_ICNSS) += icnss.o wlan_firmware_service_v01.o
obj-$(CONFIG_MEM_SHARE_QMI_SERVICE) += memshare/
obj-$(CONFIG_MSM_PIL_SSR_GENERIC) += subsys-pil-tz.o
diff --git a/drivers/soc/qcom/icnss.c b/drivers/soc/qcom/icnss.c
index ecf72ca..6ce481b 100644
--- a/drivers/soc/qcom/icnss.c
+++ b/drivers/soc/qcom/icnss.c
@@ -397,12 +397,6 @@
uint32_t rejuvenate_ack_err;
};
-#define MAX_NO_OF_MAC_ADDR 4
-struct icnss_wlan_mac_addr {
- u8 mac_addr[MAX_NO_OF_MAC_ADDR][ETH_ALEN];
- uint32_t no_of_mac_addr_set;
-};
-
enum icnss_pdr_cause_index {
ICNSS_FW_CRASH,
ICNSS_ROOT_PD_CRASH,
@@ -479,8 +473,6 @@
uint64_t vph_pwr;
atomic_t pm_count;
struct ramdump_device *msa0_dump_dev;
- bool is_wlan_mac_set;
- struct icnss_wlan_mac_addr wlan_mac_addr;
bool bypass_s1_smmu;
u8 cause_for_rejuvenation;
u8 requesting_sub_system;
@@ -3279,78 +3271,6 @@
}
EXPORT_SYMBOL(icnss_socinfo_get_serial_number);
-int icnss_set_wlan_mac_address(const u8 *in, const uint32_t len)
-{
- struct icnss_priv *priv = penv;
- uint32_t no_of_mac_addr;
- struct icnss_wlan_mac_addr *addr = NULL;
- int iter;
- u8 *temp = NULL;
-
- if (!priv) {
- icnss_pr_err("Priv data is NULL\n");
- return -EINVAL;
- }
-
- if (priv->is_wlan_mac_set) {
- icnss_pr_dbg("WLAN MAC address is already set\n");
- return 0;
- }
-
- if (len == 0 || (len % ETH_ALEN) != 0) {
- icnss_pr_err("Invalid length %d\n", len);
- return -EINVAL;
- }
-
- no_of_mac_addr = len / ETH_ALEN;
- if (no_of_mac_addr > MAX_NO_OF_MAC_ADDR) {
- icnss_pr_err("Exceed maxinum supported MAC address %u %u\n",
- MAX_NO_OF_MAC_ADDR, no_of_mac_addr);
- return -EINVAL;
- }
-
- priv->is_wlan_mac_set = true;
- addr = &priv->wlan_mac_addr;
- addr->no_of_mac_addr_set = no_of_mac_addr;
- temp = &addr->mac_addr[0][0];
-
- for (iter = 0; iter < no_of_mac_addr;
- ++iter, temp += ETH_ALEN, in += ETH_ALEN) {
- ether_addr_copy(temp, in);
- icnss_pr_dbg("MAC_ADDR:%02x:%02x:%02x:%02x:%02x:%02x\n",
- temp[0], temp[1], temp[2],
- temp[3], temp[4], temp[5]);
- }
-
- return 0;
-}
-EXPORT_SYMBOL(icnss_set_wlan_mac_address);
-
-u8 *icnss_get_wlan_mac_address(struct device *dev, uint32_t *num)
-{
- struct icnss_priv *priv = dev_get_drvdata(dev);
- struct icnss_wlan_mac_addr *addr = NULL;
-
- if (priv->magic != ICNSS_MAGIC) {
- icnss_pr_err("Invalid drvdata: dev %p, data %p, magic 0x%x\n",
- dev, priv, priv->magic);
- goto out;
- }
-
- if (!priv->is_wlan_mac_set) {
- icnss_pr_dbg("WLAN MAC address is not set\n");
- goto out;
- }
-
- addr = &priv->wlan_mac_addr;
- *num = addr->no_of_mac_addr_set;
- return &addr->mac_addr[0][0];
-out:
- *num = 0;
- return NULL;
-}
-EXPORT_SYMBOL(icnss_get_wlan_mac_address);
-
int icnss_trigger_recovery(struct device *dev)
{
int ret = 0;
diff --git a/drivers/soc/qcom/icnss_utils.c b/drivers/soc/qcom/icnss_utils.c
deleted file mode 100644
index 6974146..0000000
--- a/drivers/soc/qcom/icnss_utils.c
+++ /dev/null
@@ -1,140 +0,0 @@
-/* Copyright (c) 2016-2017, The Linux Foundation. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 and
- * only version 2 as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- */
-
-#include <linux/module.h>
-#include <linux/slab.h>
-#include <soc/qcom/icnss.h>
-
-#define ICNSS_MAX_CH_NUM 45
-
-static DEFINE_MUTEX(unsafe_channel_list_lock);
-static DEFINE_SPINLOCK(dfs_nol_info_lock);
-static int driver_load_cnt;
-
-static struct icnss_unsafe_channel_list {
- u16 unsafe_ch_count;
- u16 unsafe_ch_list[ICNSS_MAX_CH_NUM];
-} unsafe_channel_list;
-
-static struct icnss_dfs_nol_info {
- void *dfs_nol_info;
- u16 dfs_nol_info_len;
-} dfs_nol_info;
-
-int icnss_set_wlan_unsafe_channel(u16 *unsafe_ch_list, u16 ch_count)
-{
- mutex_lock(&unsafe_channel_list_lock);
- if ((!unsafe_ch_list) || (ch_count > ICNSS_MAX_CH_NUM)) {
- mutex_unlock(&unsafe_channel_list_lock);
- return -EINVAL;
- }
-
- unsafe_channel_list.unsafe_ch_count = ch_count;
-
- if (ch_count != 0) {
- memcpy(
- (char *)unsafe_channel_list.unsafe_ch_list,
- (char *)unsafe_ch_list, ch_count * sizeof(u16));
- }
- mutex_unlock(&unsafe_channel_list_lock);
-
- return 0;
-}
-EXPORT_SYMBOL(icnss_set_wlan_unsafe_channel);
-
-int icnss_get_wlan_unsafe_channel(u16 *unsafe_ch_list,
- u16 *ch_count, u16 buf_len)
-{
- mutex_lock(&unsafe_channel_list_lock);
- if (!unsafe_ch_list || !ch_count) {
- mutex_unlock(&unsafe_channel_list_lock);
- return -EINVAL;
- }
-
- if (buf_len < (unsafe_channel_list.unsafe_ch_count * sizeof(u16))) {
- mutex_unlock(&unsafe_channel_list_lock);
- return -ENOMEM;
- }
-
- *ch_count = unsafe_channel_list.unsafe_ch_count;
- memcpy(
- (char *)unsafe_ch_list,
- (char *)unsafe_channel_list.unsafe_ch_list,
- unsafe_channel_list.unsafe_ch_count * sizeof(u16));
- mutex_unlock(&unsafe_channel_list_lock);
-
- return 0;
-}
-EXPORT_SYMBOL(icnss_get_wlan_unsafe_channel);
-
-int icnss_wlan_set_dfs_nol(const void *info, u16 info_len)
-{
- void *temp;
- void *old_nol_info;
- struct icnss_dfs_nol_info *dfs_info;
-
- if (!info || !info_len)
- return -EINVAL;
-
- temp = kmalloc(info_len, GFP_ATOMIC);
- if (!temp)
- return -ENOMEM;
-
- memcpy(temp, info, info_len);
- spin_lock_bh(&dfs_nol_info_lock);
- dfs_info = &dfs_nol_info;
- old_nol_info = dfs_info->dfs_nol_info;
- dfs_info->dfs_nol_info = temp;
- dfs_info->dfs_nol_info_len = info_len;
- spin_unlock_bh(&dfs_nol_info_lock);
- kfree(old_nol_info);
-
- return 0;
-}
-EXPORT_SYMBOL(icnss_wlan_set_dfs_nol);
-
-int icnss_wlan_get_dfs_nol(void *info, u16 info_len)
-{
- int len;
- struct icnss_dfs_nol_info *dfs_info;
-
- if (!info || !info_len)
- return -EINVAL;
-
- spin_lock_bh(&dfs_nol_info_lock);
-
- dfs_info = &dfs_nol_info;
- if (dfs_info->dfs_nol_info == NULL ||
- dfs_info->dfs_nol_info_len == 0) {
- spin_unlock_bh(&dfs_nol_info_lock);
- return -ENOENT;
- }
-
- len = min(info_len, dfs_info->dfs_nol_info_len);
- memcpy(info, dfs_info->dfs_nol_info, len);
- spin_unlock_bh(&dfs_nol_info_lock);
-
- return len;
-}
-EXPORT_SYMBOL(icnss_wlan_get_dfs_nol);
-
-void icnss_increment_driver_load_cnt(void)
-{
- ++driver_load_cnt;
-}
-EXPORT_SYMBOL(icnss_increment_driver_load_cnt);
-
-int icnss_get_driver_load_cnt(void)
-{
- return driver_load_cnt;
-}
-EXPORT_SYMBOL(icnss_get_driver_load_cnt);
diff --git a/drivers/soc/qcom/llcc-core.c b/drivers/soc/qcom/llcc-core.c
index 3d6b002..a5e5b56 100644
--- a/drivers/soc/qcom/llcc-core.c
+++ b/drivers/soc/qcom/llcc-core.c
@@ -35,6 +35,15 @@
#define DRP0_INTERRUPT_ENABLE BIT(6)
#define SB_DB_DRP_INTERRUPT_ENABLE 0x3
+#ifdef CONFIG_EDAC_QCOM_LLCC
+#define ENABLE_ECC_INTR 1
+#else
+#define ENABLE_ECC_INTR 0
+#endif
+
+static int enable_ecc_intr = ENABLE_ECC_INTR;
+module_param(enable_ecc_intr, int, 0444);
+
static void qcom_llcc_core_setup(struct regmap *llcc_regmap, uint32_t b_off)
{
u32 sb_err_threshold;
@@ -81,7 +90,8 @@
return -EINVAL;
}
- qcom_llcc_core_setup(llcc_regmap, b_off);
+ if (enable_ecc_intr)
+ qcom_llcc_core_setup(llcc_regmap, b_off);
return 0;
}
diff --git a/drivers/soc/qcom/msm_bus/msm_bus_bimc_rpmh.c b/drivers/soc/qcom/msm_bus/msm_bus_bimc_rpmh.c
index c1e8feb..dafae4c 100644
--- a/drivers/soc/qcom/msm_bus/msm_bus_bimc_rpmh.c
+++ b/drivers/soc/qcom/msm_bus/msm_bus_bimc_rpmh.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
@@ -242,7 +242,7 @@
(M_BKE_GC_GC_BMSK >> \
(M_BKE_GC_GC_SHFT + 1))
-static int bimc_div(int64_t *a, uint32_t b)
+static int bimc_div(uint64_t *a, uint32_t b)
{
if ((*a > 0) && (*a < b)) {
*a = 0;
diff --git a/drivers/soc/qcom/peripheral-loader.c b/drivers/soc/qcom/peripheral-loader.c
index a443239..9d22925 100644
--- a/drivers/soc/qcom/peripheral-loader.c
+++ b/drivers/soc/qcom/peripheral-loader.c
@@ -56,6 +56,7 @@
#define PIL_NUM_DESC 10
#define NUM_OF_ENCRYPTED_KEY 3
+#define MAX_LEN 96
static void __iomem *pil_info_base;
static void __iomem *pil_minidump_base;
@@ -836,6 +837,23 @@
return 0;
}
+static int pil_notify_aop(struct pil_desc *desc, char *status)
+{
+ struct qmp_pkt pkt;
+ char mbox_msg[MAX_LEN];
+
+ if (!desc->signal_aop)
+ return 0;
+
+ snprintf(mbox_msg, MAX_LEN,
+ "{class: image, res: load_state, name: %s, val: %s}",
+ desc->name, status);
+ pkt.size = MAX_LEN;
+ pkt.data = mbox_msg;
+
+ return mbox_send_message(desc->mbox, &pkt);
+}
+
/* Synchronize request_firmware() with suspend */
static DECLARE_RWSEM(pil_pm_rwsem);
@@ -857,6 +875,12 @@
bool mem_protect = false;
bool hyp_assign = false;
+ ret = pil_notify_aop(desc, "on");
+ if (ret < 0) {
+ pil_err(desc, "Failed to send ON message to AOP rc:%d\n", ret);
+ return ret;
+ }
+
if (desc->shutdown_fail)
pil_err(desc, "Subsystem shutdown failed previously!\n");
@@ -1015,6 +1039,7 @@
priv->region = NULL;
}
pil_release_mmap(desc);
+ pil_notify_aop(desc, "off");
}
return ret;
}
@@ -1026,6 +1051,7 @@
*/
void pil_shutdown(struct pil_desc *desc)
{
+ int ret;
struct pil_priv *priv = desc->priv;
if (desc->ops->shutdown) {
@@ -1043,6 +1069,9 @@
pil_proxy_unvote(desc, 1);
else
flush_delayed_work(&priv->proxy);
+ ret = pil_notify_aop(desc, "off");
+ if (ret < 0)
+ pr_warn("pil: failed to send OFF message to AOP rc:%d\n", ret);
desc->modem_ssr = true;
}
EXPORT_SYMBOL(pil_shutdown);
diff --git a/drivers/soc/qcom/peripheral-loader.h b/drivers/soc/qcom/peripheral-loader.h
index daa4533..f09adf5 100644
--- a/drivers/soc/qcom/peripheral-loader.h
+++ b/drivers/soc/qcom/peripheral-loader.h
@@ -12,6 +12,9 @@
#ifndef __MSM_PERIPHERAL_LOADER_H
#define __MSM_PERIPHERAL_LOADER_H
+#include <linux/mailbox_client.h>
+#include <linux/mailbox/qmp.h>
+
struct device;
struct module;
struct pil_priv;
@@ -57,6 +60,9 @@
bool modem_ssr;
bool clear_fw_region;
u32 subsys_vmid;
+ bool signal_aop;
+ struct mbox_client cl;
+ struct mbox_chan *mbox;
};
/**
diff --git a/drivers/soc/qcom/pil-msa.c b/drivers/soc/qcom/pil-msa.c
index 926016f..ec3063e 100644
--- a/drivers/soc/qcom/pil-msa.c
+++ b/drivers/soc/qcom/pil-msa.c
@@ -615,7 +615,7 @@
char *fw_name_p;
void *mba_dp_virt;
dma_addr_t mba_dp_phys, mba_dp_phys_end;
- int ret, count;
+ int ret;
const u8 *data;
struct device *dma_dev = md->mba_mem_dev_fixed ?: &md->mba_mem_dev;
@@ -681,10 +681,9 @@
&mba_dp_phys, &mba_dp_phys_end);
/* Load the MBA image into memory */
- count = fw->size;
- if (count <= SZ_1M) {
+ if (fw->size <= SZ_1M) {
/* Ensures memcpy is done for max 1MB fw size */
- memcpy(mba_dp_virt, data, count);
+ memcpy(mba_dp_virt, data, fw->size);
} else {
dev_err(pil->dev, "%s fw image loading into memory is failed due to fw size overflow\n",
__func__);
diff --git a/drivers/soc/qcom/pil-q6v5-mss.c b/drivers/soc/qcom/pil-q6v5-mss.c
index e9d3534..cf5f7e4 100644
--- a/drivers/soc/qcom/pil-q6v5-mss.c
+++ b/drivers/soc/qcom/pil-q6v5-mss.c
@@ -217,6 +217,22 @@
drv->subsys_desc.wdog_bite_handler = modem_wdog_bite_intr_handler;
drv->q6->desc.modem_ssr = false;
+ drv->q6->desc.signal_aop = of_property_read_bool(pdev->dev.of_node,
+ "qcom,signal-aop");
+ if (drv->q6->desc.signal_aop) {
+ drv->q6->desc.cl.dev = &pdev->dev;
+ drv->q6->desc.cl.tx_block = true;
+ drv->q6->desc.cl.tx_tout = 1000;
+ drv->q6->desc.cl.knows_txdone = false;
+ drv->q6->desc.mbox = mbox_request_channel(&drv->q6->desc.cl, 0);
+ if (IS_ERR(drv->q6->desc.mbox)) {
+ ret = PTR_ERR(drv->q6->desc.mbox);
+ dev_err(&pdev->dev, "Failed to get mailbox channel %pK %d\n",
+ drv->q6->desc.mbox, ret);
+ goto err_subsys;
+ }
+ }
+
drv->subsys = subsys_register(&drv->subsys_desc);
if (IS_ERR(drv->subsys)) {
ret = PTR_ERR(drv->subsys);
diff --git a/drivers/soc/qcom/pil-q6v5.c b/drivers/soc/qcom/pil-q6v5.c
index 6a30381..6d6b9f7 100644
--- a/drivers/soc/qcom/pil-q6v5.c
+++ b/drivers/soc/qcom/pil-q6v5.c
@@ -84,7 +84,7 @@
/* QDSP6v65 parameters */
#define QDSP6SS_BOOT_CORE_START (0x400)
#define QDSP6SS_BOOT_CMD (0x404)
-#define QDSP6SS_BOOT_STATUS (0x408)
+#define MSS_STATUS (0x40)
#define QDSP6SS_SLEEP (0x3C)
#define SLEEP_CHECK_MAX_LOOPS (200)
#define BOOT_FSM_TIMEOUT (100)
@@ -410,8 +410,8 @@
writel_relaxed(1, drv->reg_base + QDSP6SS_BOOT_CMD);
/* Wait for boot FSM to complete */
- ret = readl_poll_timeout(drv->reg_base + QDSP6SS_BOOT_STATUS, val,
- val != 0, 10, BOOT_FSM_TIMEOUT);
+ ret = readl_poll_timeout(drv->rmb_base + MSS_STATUS, val,
+ (val & BIT(1)) != 0, 10, BOOT_FSM_TIMEOUT);
if (ret) {
dev_err(drv->desc.dev, "Boot FSM failed to complete.\n");
diff --git a/drivers/soc/qcom/spcom.c b/drivers/soc/qcom/spcom.c
index de5f0ff..68681f9 100644
--- a/drivers/soc/qcom/spcom.c
+++ b/drivers/soc/qcom/spcom.c
@@ -206,10 +206,8 @@
* Only one rx/tx transaction at a time (request + response).
*/
int ref_count;
- u32 pid;
- /* link UP/DOWN callback */
- void (*notify_link_state_cb)(bool up);
+ u32 pid; /* debug only to find user space application */
/* abort flags */
bool rx_abort;
@@ -493,13 +491,10 @@
ch->glink_state = event;
- /*
- * if spcom_notify_state() is called within glink_open()
- * then ch->glink_handle is not updated yet.
- */
- if (!ch->glink_handle) {
- pr_debug("update glink_handle, ch [%s].\n", ch->name);
- ch->glink_handle = handle;
+ if (!handle) {
+ pr_err("inavlid glink_handle, ch [%s].\n", ch->name);
+ mutex_unlock(&ch->lock);
+ return;
}
/* signal before unlock mutex & before calling glink */
@@ -512,8 +507,7 @@
*/
pr_debug("call glink_queue_rx_intent() ch [%s].\n", ch->name);
- ret = glink_queue_rx_intent(ch->glink_handle,
- ch, ch->rx_buf_size);
+ ret = glink_queue_rx_intent(handle, ch, ch->rx_buf_size);
if (ret) {
pr_err("glink_queue_rx_intent() err [%d]\n", ret);
} else {
@@ -736,6 +730,7 @@
long timeleft;
const char *name;
void *handle;
+ u32 pid = current_pid();
mutex_lock(&ch->lock);
name = ch->name;
@@ -749,7 +744,7 @@
}
pr_debug("ch [%s] opened by PID [%d], count [%d]\n",
- name, ch->pid, ch->ref_count);
+ name, pid, ch->ref_count);
pr_debug("Open channel [%s] timeout_msec [%d].\n", name, timeout_msec);
@@ -777,7 +772,7 @@
/* init channel context after successful open */
ch->glink_handle = handle;
ch->ref_count++;
- ch->pid = current_pid();
+ ch->pid = pid;
ch->txn_id = INITIAL_TXN_ID;
mutex_unlock(&ch->lock);
@@ -1026,10 +1021,12 @@
ch->name, ch->actual_rx_size);
goto exit_ready;
}
+ mutex_unlock(&ch->lock); /* unlock while waiting */
pr_debug("Wait for Rx Done, ch [%s].\n", ch->name);
wait_for_completion(&ch->rx_done);
+ mutex_lock(&ch->lock); /* re-lock after waiting */
/* Check Rx Abort on SP reset */
if (ch->rx_abort) {
pr_err("rx aborted.\n");
@@ -2027,6 +2024,7 @@
void *buf,
uint32_t size)
{
+ int ret = -1;
uint32_t next_req_size = 0;
if (size < sizeof(next_req_size)) {
@@ -2034,7 +2032,10 @@
return -EINVAL;
}
- next_req_size = spcom_get_next_request_size(ch);
+ ret = spcom_get_next_request_size(ch);
+ if (ret < 0)
+ return ret;
+ next_req_size = (uint32_t) ret;
memcpy(buf, &next_req_size, sizeof(next_req_size));
pr_debug("next_req_size [%d].\n", next_req_size);
@@ -2139,18 +2140,20 @@
void *buf,
uint32_t size)
{
+ int ret = -1;
+
if (size == SPCOM_GET_NEXT_REQUEST_SIZE) {
pr_debug("get next request size, ch [%s].\n", ch->name);
ch->is_server = true;
- size = spcom_handle_get_req_size(ch, buf, size);
+ ret = spcom_handle_get_req_size(ch, buf, size);
} else {
pr_debug("get request/response, ch [%s].\n", ch->name);
- size = spcom_handle_read_req_resp(ch, buf, size);
+ ret = spcom_handle_read_req_resp(ch, buf, size);
}
pr_debug("ch [%s] , size = %d.\n", ch->name, size);
- return size;
+ return ret;
}
/*======================================================================*/
@@ -2302,6 +2305,7 @@
char *buf;
struct spcom_channel *ch;
const char *name = file_to_filename(filp);
+ int buf_size = 0;
pr_debug("Write file [%s] size [%d] pos [%d].\n",
name, (int) size, (int) *f_pos);
@@ -2328,6 +2332,7 @@
(int) size, (int) SPCOM_MAX_COMMAND_SIZE);
return -EINVAL;
}
+ buf_size = size; /* explicit casting size_t to int */
if (*f_pos != 0) {
pr_err("offset should be zero, no sparse buffer.\n");
@@ -2345,7 +2350,7 @@
return -EFAULT;
}
- ret = spcom_handle_write(ch, buf, size);
+ ret = spcom_handle_write(ch, buf, buf_size);
if (ret) {
pr_err("handle command error [%d].\n", ret);
kfree(buf);
@@ -2373,6 +2378,7 @@
char *buf;
struct spcom_channel *ch;
const char *name = file_to_filename(filp);
+ uint32_t buf_size = 0;
pr_debug("Read file [%s], size = %d bytes.\n", name, (int) size);
@@ -2381,6 +2387,7 @@
pr_err("invalid parameters.\n");
return -EINVAL;
}
+ buf_size = size; /* explicit casting size_t to uint32_t */
ch = filp->private_data;
@@ -2398,7 +2405,7 @@
if (buf == NULL)
return -ENOMEM;
- ret = spcom_handle_read(ch, buf, size);
+ ret = spcom_handle_read(ch, buf, buf_size);
if (ret < 0) {
pr_err("read error [%d].\n", ret);
kfree(buf);
@@ -2481,9 +2488,14 @@
done = (spcom_dev->link_state == GLINK_LINK_STATE_UP);
break;
case SPCOM_POLL_CH_CONNECT:
+ /*
+ * ch is not expected to be NULL since user must call open()
+ * to get FD before it can call poll().
+ * open() will fail if no ch related to the char-device.
+ */
if (ch == NULL) {
pr_err("invalid ch pointer, file [%s].\n", name);
- return -EINVAL;
+ return POLLERR;
}
pr_debug("ch [%s] SPCOM_POLL_CH_CONNECT.\n", name);
if (wait) {
@@ -2784,7 +2796,7 @@
{
int ret;
- pr_info("spcom driver version 1.1 17-July-2017.\n");
+ pr_info("spcom driver version 1.2 23-Aug-2017.\n");
ret = platform_driver_register(&spcom_driver);
if (ret)
diff --git a/drivers/soc/qcom/subsys-pil-tz.c b/drivers/soc/qcom/subsys-pil-tz.c
index 01eb260..3ea4be6 100644
--- a/drivers/soc/qcom/subsys-pil-tz.c
+++ b/drivers/soc/qcom/subsys-pil-tz.c
@@ -1152,6 +1152,22 @@
d->subsys_desc.wdog_bite_handler = subsys_wdog_bite_irq_handler;
d->subsys_desc.stop_ack_handler = subsys_stop_ack_intr_handler;
}
+ d->desc.signal_aop = of_property_read_bool(pdev->dev.of_node,
+ "qcom,signal-aop");
+ if (d->desc.signal_aop) {
+ d->desc.cl.dev = &pdev->dev;
+ d->desc.cl.tx_block = true;
+ d->desc.cl.tx_tout = 1000;
+ d->desc.cl.knows_txdone = false;
+ d->desc.mbox = mbox_request_channel(&d->desc.cl, 0);
+ if (IS_ERR(d->desc.mbox)) {
+ rc = PTR_ERR(d->desc.mbox);
+ dev_err(&pdev->dev, "Failed to get mailbox channel %pK %d\n",
+ d->desc.mbox, rc);
+ goto err_ramdump;
+ }
+ }
+
d->ramdump_dev = create_ramdump_device(d->subsys_desc.name,
&pdev->dev);
if (!d->ramdump_dev) {
diff --git a/drivers/spi/spi-geni-qcom.c b/drivers/spi/spi-geni-qcom.c
index e46bc98..8dc42ac 100644
--- a/drivers/spi/spi-geni-qcom.c
+++ b/drivers/spi/spi-geni-qcom.c
@@ -24,6 +24,7 @@
#include <linux/qcom-geni-se.h>
#include <linux/msm_gpi.h>
#include <linux/spi/spi.h>
+#include <linux/spi/spi-geni-qcom.h>
#define SPI_NUM_CHIPSELECT (4)
#define SPI_XFER_TIMEOUT_MS (250)
@@ -67,6 +68,11 @@
/* SPI_TX/SPI_RX_TRANS_LEN fields */
#define TRANS_LEN_MSK (GENMASK(23, 0))
+/* SE_SPI_DELAY_COUNTERS */
+#define SPI_INTER_WORDS_DELAY_MSK (GENMASK(9, 0))
+#define SPI_CS_CLK_DELAY_MSK (GENMASK(19, 10))
+#define SPI_CS_CLK_DELAY_SHFT (10)
+
/* M_CMD OP codes for SPI */
#define SPI_TX_ONLY (1)
#define SPI_RX_ONLY (2)
@@ -229,6 +235,8 @@
int ret = 0;
int idx;
int div;
+ struct spi_geni_qcom_ctrl_data *delay_params = NULL;
+ u32 spi_delay_params = 0;
loopback_cfg &= ~LOOPBACK_MSK;
cpol &= ~CPOL;
@@ -246,6 +254,22 @@
if (spi_slv->mode & SPI_CS_HIGH)
demux_output_inv |= BIT(spi_slv->chip_select);
+ if (spi_slv->controller_data) {
+ u32 cs_clk_delay = 0;
+ u32 inter_words_delay = 0;
+
+ delay_params =
+ (struct spi_geni_qcom_ctrl_data *) spi_slv->controller_data;
+ cs_clk_delay =
+ (delay_params->spi_cs_clk_delay << SPI_CS_CLK_DELAY_SHFT)
+ & SPI_CS_CLK_DELAY_MSK;
+ inter_words_delay =
+ delay_params->spi_inter_words_delay &
+ SPI_INTER_WORDS_DELAY_MSK;
+ spi_delay_params =
+ (inter_words_delay | cs_clk_delay);
+ }
+
demux_sel = spi_slv->chip_select;
mas->cur_speed_hz = spi_slv->max_speed_hz;
mas->cur_word_len = spi_slv->bits_per_word;
@@ -267,12 +291,13 @@
geni_write_reg(demux_output_inv, mas->base, SE_SPI_DEMUX_OUTPUT_INV);
geni_write_reg(clk_sel, mas->base, SE_GENI_CLK_SEL);
geni_write_reg(m_clk_cfg, mas->base, GENI_SER_M_CLK_CFG);
+ geni_write_reg(spi_delay_params, mas->base, SE_SPI_DELAY_COUNTERS);
GENI_SE_DBG(mas->ipc, false, mas->dev,
"%s:Loopback%d demux_sel0x%x demux_op_inv 0x%x clk_cfg 0x%x\n",
__func__, loopback_cfg, demux_sel, demux_output_inv, m_clk_cfg);
GENI_SE_DBG(mas->ipc, false, mas->dev,
- "%s:clk_sel 0x%x cpol %d cpha %d\n", __func__,
- clk_sel, cpol, cpha);
+ "%s:clk_sel 0x%x cpol %d cpha %d delay 0x%x\n", __func__,
+ clk_sel, cpol, cpha, spi_delay_params);
/* Ensure message level attributes are written before returning */
mb();
setup_fifo_params_exit:
@@ -306,7 +331,8 @@
}
static struct msm_gpi_tre *setup_config0_tre(struct spi_transfer *xfer,
- struct spi_geni_master *mas, u16 mode)
+ struct spi_geni_master *mas, u16 mode,
+ u32 cs_clk_delay, u32 inter_words_delay)
{
struct msm_gpi_tre *c0_tre = &mas->gsi[mas->num_xfers].config0_tre;
u8 flags = 0;
@@ -340,12 +366,16 @@
}
c0_tre->dword[0] = MSM_GPI_SPI_CONFIG0_TRE_DWORD0(pack, flags,
word_len);
- c0_tre->dword[1] = MSM_GPI_SPI_CONFIG0_TRE_DWORD1(0, 0, 0);
+ c0_tre->dword[1] = MSM_GPI_SPI_CONFIG0_TRE_DWORD1(0, cs_clk_delay,
+ inter_words_delay);
c0_tre->dword[2] = MSM_GPI_SPI_CONFIG0_TRE_DWORD2(idx, div);
c0_tre->dword[3] = MSM_GPI_SPI_CONFIG0_TRE_DWORD3(0, 0, 0, 1);
GENI_SE_DBG(mas->ipc, false, mas->dev,
"%s: flags 0x%x word %d pack %d idx %d div %d\n",
__func__, flags, word_len, pack, idx, div);
+ GENI_SE_DBG(mas->ipc, false, mas->dev,
+ "%s: cs_clk_delay %d inter_words_delay %d\n", __func__,
+ cs_clk_delay, inter_words_delay);
return c0_tre;
}
@@ -503,13 +533,27 @@
u32 rx_len = 0;
int go_flags = 0;
unsigned long flags = DMA_PREP_INTERRUPT | DMA_CTRL_ACK;
+ struct spi_geni_qcom_ctrl_data *delay_params = NULL;
+ u32 cs_clk_delay = 0;
+ u32 inter_words_delay = 0;
+
+ if (spi_slv->controller_data) {
+ delay_params =
+ (struct spi_geni_qcom_ctrl_data *) spi_slv->controller_data;
+
+ cs_clk_delay =
+ delay_params->spi_cs_clk_delay;
+ inter_words_delay =
+ delay_params->spi_inter_words_delay;
+ }
if ((xfer->bits_per_word != mas->cur_word_len) ||
(xfer->speed_hz != mas->cur_speed_hz)) {
mas->cur_word_len = xfer->bits_per_word;
mas->cur_speed_hz = xfer->speed_hz;
tx_nent++;
- c0_tre = setup_config0_tre(xfer, mas, spi_slv->mode);
+ c0_tre = setup_config0_tre(xfer, mas, spi_slv->mode,
+ cs_clk_delay, inter_words_delay);
if (IS_ERR_OR_NULL(c0_tre)) {
dev_err(mas->dev, "%s:Err setting c0tre:%d\n",
__func__, ret);
diff --git a/drivers/staging/rts5208/rtsx_scsi.c b/drivers/staging/rts5208/rtsx_scsi.c
index 01438fa..f50076d 100644
--- a/drivers/staging/rts5208/rtsx_scsi.c
+++ b/drivers/staging/rts5208/rtsx_scsi.c
@@ -414,7 +414,7 @@
sense->ascq = ascq;
if (sns_key_info0 != 0) {
sense->sns_key_info[0] = SKSV | sns_key_info0;
- sense->sns_key_info[1] = (sns_key_info1 & 0xf0) >> 8;
+ sense->sns_key_info[1] = (sns_key_info1 & 0xf0) >> 4;
sense->sns_key_info[2] = sns_key_info1 & 0x0f;
}
}
diff --git a/drivers/usb/core/devio.c b/drivers/usb/core/devio.c
index 840930b0..c8075eb 100644
--- a/drivers/usb/core/devio.c
+++ b/drivers/usb/core/devio.c
@@ -629,6 +629,8 @@
if (as->status < 0 && as->bulk_addr && as->status != -ECONNRESET &&
as->status != -ENOENT)
cancel_bulk_urbs(ps, as->bulk_addr);
+
+ wake_up(&ps->wait);
spin_unlock(&ps->lock);
if (signr) {
@@ -636,8 +638,6 @@
put_pid(pid);
put_cred(cred);
}
-
- wake_up(&ps->wait);
}
static void destroy_async(struct usb_dev_state *ps, struct list_head *list)
diff --git a/drivers/usb/core/quirks.c b/drivers/usb/core/quirks.c
index 574da2b..82806e3 100644
--- a/drivers/usb/core/quirks.c
+++ b/drivers/usb/core/quirks.c
@@ -57,8 +57,9 @@
/* Microsoft LifeCam-VX700 v2.0 */
{ USB_DEVICE(0x045e, 0x0770), .driver_info = USB_QUIRK_RESET_RESUME },
- /* Logitech HD Pro Webcams C920 and C930e */
+ /* Logitech HD Pro Webcams C920, C920-C and C930e */
{ USB_DEVICE(0x046d, 0x082d), .driver_info = USB_QUIRK_DELAY_INIT },
+ { USB_DEVICE(0x046d, 0x0841), .driver_info = USB_QUIRK_DELAY_INIT },
{ USB_DEVICE(0x046d, 0x0843), .driver_info = USB_QUIRK_DELAY_INIT },
/* Logitech ConferenceCam CC3000e */
@@ -217,6 +218,9 @@
{ USB_DEVICE(0x1a0a, 0x0200), .driver_info =
USB_QUIRK_LINEAR_UFRAME_INTR_BINTERVAL },
+ /* Corsair Strafe RGB */
+ { USB_DEVICE(0x1b1c, 0x1b20), .driver_info = USB_QUIRK_DELAY_INIT },
+
/* Acer C120 LED Projector */
{ USB_DEVICE(0x1de1, 0xc102), .driver_info = USB_QUIRK_NO_LPM },
diff --git a/drivers/usb/gadget/function/f_gsi.c b/drivers/usb/gadget/function/f_gsi.c
index 18241f4..c11629d 100644
--- a/drivers/usb/gadget/function/f_gsi.c
+++ b/drivers/usb/gadget/function/f_gsi.c
@@ -1565,12 +1565,22 @@
struct usb_request *req)
{
struct f_gsi *gsi = req->context;
+ rndis_init_msg_type *buf;
int status;
status = rndis_msg_parser(gsi->params, (u8 *) req->buf);
if (status < 0)
log_event_err("RNDIS command error %d, %d/%d",
status, req->actual, req->length);
+
+ buf = (rndis_init_msg_type *)req->buf;
+ if (buf->MessageType == RNDIS_MSG_INIT) {
+ gsi->d_port.in_aggr_size = min_t(u32, gsi->d_port.in_aggr_size,
+ gsi->params->dl_max_xfer_size);
+ log_event_dbg("RNDIS host dl_aggr_size:%d in_aggr_size:%d\n",
+ gsi->params->dl_max_xfer_size,
+ gsi->d_port.in_aggr_size);
+ }
}
static void
diff --git a/drivers/usb/gadget/function/f_gsi.h b/drivers/usb/gadget/function/f_gsi.h
index a560083..d6bf0f4 100644
--- a/drivers/usb/gadget/function/f_gsi.h
+++ b/drivers/usb/gadget/function/f_gsi.h
@@ -1393,7 +1393,7 @@
/* string descriptors: */
static struct usb_string qdss_gsi_string_defs[] = {
- [0].s = "Qualcomm DPL Data",
+ [0].s = "DPL Data",
{}, /* end of list */
};
diff --git a/drivers/usb/gadget/function/f_qdss.c b/drivers/usb/gadget/function/f_qdss.c
index 40a7acf..a0fecb2 100644
--- a/drivers/usb/gadget/function/f_qdss.c
+++ b/drivers/usb/gadget/function/f_qdss.c
@@ -338,7 +338,7 @@
struct usb_gadget *gadget = c->cdev->gadget;
struct f_qdss *qdss = func_to_qdss(f);
struct usb_ep *ep;
- int iface;
+ int iface, id;
pr_debug("qdss_bind\n");
@@ -356,6 +356,12 @@
qdss_data_intf_desc.bInterfaceNumber = iface;
qdss->data_iface_id = iface;
+ id = usb_string_id(c->cdev);
+ if (id < 0)
+ return id;
+ qdss_string_defs[QDSS_DATA_IDX].id = id;
+ qdss_data_intf_desc.iInterface = id;
+
if (qdss->debug_inface_enabled) {
/* Allocate ctrl I/F */
iface = usb_interface_id(c, f);
@@ -365,6 +371,11 @@
}
qdss_ctrl_intf_desc.bInterfaceNumber = iface;
qdss->ctrl_iface_id = iface;
+ id = usb_string_id(c->cdev);
+ if (id < 0)
+ return id;
+ qdss_string_defs[QDSS_CTRL_IDX].id = id;
+ qdss_ctrl_intf_desc.iInterface = id;
}
ep = usb_ep_autoconfig_ss(gadget, &qdss_ss_data_desc,
diff --git a/drivers/usb/gadget/function/rndis.c b/drivers/usb/gadget/function/rndis.c
index 38d58f3..ac2231a 100644
--- a/drivers/usb/gadget/function/rndis.c
+++ b/drivers/usb/gadget/function/rndis.c
@@ -813,8 +813,17 @@
/* For USB: responses may take up to 10 seconds */
switch (MsgType) {
case RNDIS_MSG_INIT:
- pr_debug("%s: RNDIS_MSG_INIT\n",
- __func__);
+ pr_debug("%s: RNDIS_MSG_INIT\n", __func__);
+ tmp++; /* to get RequestID */
+ params->host_rndis_major_ver = get_unaligned_le32(tmp++);
+ params->host_rndis_minor_ver = get_unaligned_le32(tmp++);
+ params->dl_max_xfer_size = get_unaligned_le32(tmp++);
+
+ pr_debug("%s(): RNDIS Host Major:%d Minor:%d version\n",
+ __func__, params->host_rndis_major_ver,
+ params->host_rndis_minor_ver);
+ pr_debug("%s(): DL Max Transfer size:%x\n",
+ __func__, params->dl_max_xfer_size);
params->state = RNDIS_INITIALIZED;
return rndis_init_response(params, (rndis_init_msg_type *)buf);
diff --git a/drivers/usb/gadget/function/rndis.h b/drivers/usb/gadget/function/rndis.h
index 939c3be..4ffc282 100644
--- a/drivers/usb/gadget/function/rndis.h
+++ b/drivers/usb/gadget/function/rndis.h
@@ -191,6 +191,9 @@
u32 vendorID;
u8 max_pkt_per_xfer;
+ u32 host_rndis_major_ver;
+ u32 host_rndis_minor_ver;
+ u32 dl_max_xfer_size;
const char *vendorDescr;
u8 pkt_alignment_factor;
void (*resp_avail)(void *v);
diff --git a/drivers/usb/host/pci-quirks.c b/drivers/usb/host/pci-quirks.c
index 5f4ca78..58b9685 100644
--- a/drivers/usb/host/pci-quirks.c
+++ b/drivers/usb/host/pci-quirks.c
@@ -142,29 +142,30 @@
pinfo->sb_type.gen = AMD_CHIPSET_SB700;
else if (rev >= 0x40 && rev <= 0x4f)
pinfo->sb_type.gen = AMD_CHIPSET_SB800;
- }
- pinfo->smbus_dev = pci_get_device(PCI_VENDOR_ID_AMD,
- 0x145c, NULL);
- if (pinfo->smbus_dev) {
- pinfo->sb_type.gen = AMD_CHIPSET_TAISHAN;
} else {
pinfo->smbus_dev = pci_get_device(PCI_VENDOR_ID_AMD,
PCI_DEVICE_ID_AMD_HUDSON2_SMBUS, NULL);
- if (!pinfo->smbus_dev) {
- pinfo->sb_type.gen = NOT_AMD_CHIPSET;
- return 0;
+ if (pinfo->smbus_dev) {
+ rev = pinfo->smbus_dev->revision;
+ if (rev >= 0x11 && rev <= 0x14)
+ pinfo->sb_type.gen = AMD_CHIPSET_HUDSON2;
+ else if (rev >= 0x15 && rev <= 0x18)
+ pinfo->sb_type.gen = AMD_CHIPSET_BOLTON;
+ else if (rev >= 0x39 && rev <= 0x3a)
+ pinfo->sb_type.gen = AMD_CHIPSET_YANGTZE;
+ } else {
+ pinfo->smbus_dev = pci_get_device(PCI_VENDOR_ID_AMD,
+ 0x145c, NULL);
+ if (pinfo->smbus_dev) {
+ rev = pinfo->smbus_dev->revision;
+ pinfo->sb_type.gen = AMD_CHIPSET_TAISHAN;
+ } else {
+ pinfo->sb_type.gen = NOT_AMD_CHIPSET;
+ return 0;
+ }
}
-
- rev = pinfo->smbus_dev->revision;
- if (rev >= 0x11 && rev <= 0x14)
- pinfo->sb_type.gen = AMD_CHIPSET_HUDSON2;
- else if (rev >= 0x15 && rev <= 0x18)
- pinfo->sb_type.gen = AMD_CHIPSET_BOLTON;
- else if (rev >= 0x39 && rev <= 0x3a)
- pinfo->sb_type.gen = AMD_CHIPSET_YANGTZE;
}
-
pinfo->sb_type.rev = rev;
return 1;
}
diff --git a/drivers/usb/musb/musb_core.c b/drivers/usb/musb/musb_core.c
index 261ed2c..a6b6b1c 100644
--- a/drivers/usb/musb/musb_core.c
+++ b/drivers/usb/musb/musb_core.c
@@ -2655,6 +2655,13 @@
{
struct musb *musb = dev_to_musb(dev);
unsigned long flags;
+ int ret;
+
+ ret = pm_runtime_get_sync(dev);
+ if (ret < 0) {
+ pm_runtime_put_noidle(dev);
+ return ret;
+ }
musb_platform_disable(musb);
musb_generic_disable(musb);
@@ -2703,14 +2710,6 @@
if ((devctl & mask) != (musb->context.devctl & mask))
musb->port1_status = 0;
- /*
- * The USB HUB code expects the device to be in RPM_ACTIVE once it came
- * out of suspend
- */
- pm_runtime_disable(dev);
- pm_runtime_set_active(dev);
- pm_runtime_enable(dev);
-
musb_start(musb);
spin_lock_irqsave(&musb->lock, flags);
@@ -2720,6 +2719,9 @@
error);
spin_unlock_irqrestore(&musb->lock, flags);
+ pm_runtime_mark_last_busy(dev);
+ pm_runtime_put_autosuspend(dev);
+
return 0;
}
diff --git a/drivers/usb/phy/phy-msm-ssusb-qmp.c b/drivers/usb/phy/phy-msm-ssusb-qmp.c
index 59f5379..7e7c76c 100644
--- a/drivers/usb/phy/phy-msm-ssusb-qmp.c
+++ b/drivers/usb/phy/phy-msm-ssusb-qmp.c
@@ -623,10 +623,7 @@
}
if (suspend) {
- if (!phy->cable_connected)
- writel_relaxed(0x00,
- phy->base + phy->phy_reg[USB3_PHY_POWER_DOWN_CONTROL]);
- else
+ if (phy->cable_connected)
msm_ssusb_qmp_enable_autonomous(phy, 1);
/* Make sure above write completed with PHY */
@@ -674,6 +671,10 @@
struct msm_ssphy_qmp *phy = container_of(uphy, struct msm_ssphy_qmp,
phy);
+ writel_relaxed(0x00,
+ phy->base + phy->phy_reg[USB3_PHY_POWER_DOWN_CONTROL]);
+ readl_relaxed(phy->base + phy->phy_reg[USB3_PHY_POWER_DOWN_CONTROL]);
+
dev_dbg(uphy->dev, "QMP phy disconnect notification\n");
dev_dbg(uphy->dev, " cable_connected=%d\n", phy->cable_connected);
phy->cable_connected = false;
diff --git a/drivers/usb/serial/option.c b/drivers/usb/serial/option.c
index fe12315..2a99443 100644
--- a/drivers/usb/serial/option.c
+++ b/drivers/usb/serial/option.c
@@ -2023,6 +2023,7 @@
{ USB_DEVICE_AND_INTERFACE_INFO(0x2001, 0x7d03, 0xff, 0x02, 0x01) },
{ USB_DEVICE_AND_INTERFACE_INFO(0x2001, 0x7d03, 0xff, 0x00, 0x00) },
{ USB_DEVICE_INTERFACE_CLASS(0x2001, 0x7d04, 0xff) }, /* D-Link DWM-158 */
+ { USB_DEVICE_INTERFACE_CLASS(0x2001, 0x7d0e, 0xff) }, /* D-Link DWM-157 C1 */
{ USB_DEVICE_INTERFACE_CLASS(0x2001, 0x7e19, 0xff), /* D-Link DWM-221 B1 */
.driver_info = (kernel_ulong_t)&net_intf4_blacklist },
{ USB_DEVICE_INTERFACE_CLASS(0x2001, 0x7e35, 0xff), /* D-Link DWM-222 */
diff --git a/drivers/vhost/net.c b/drivers/vhost/net.c
index 5dc128a..96a0661 100644
--- a/drivers/vhost/net.c
+++ b/drivers/vhost/net.c
@@ -537,8 +537,13 @@
preempt_enable();
- if (vhost_enable_notify(&net->dev, vq))
+ if (!vhost_vq_avail_empty(&net->dev, vq))
vhost_poll_queue(&vq->poll);
+ else if (unlikely(vhost_enable_notify(&net->dev, vq))) {
+ vhost_disable_notify(&net->dev, vq);
+ vhost_poll_queue(&vq->poll);
+ }
+
mutex_unlock(&vq->mutex);
len = peek_head_len(sk);
diff --git a/fs/btrfs/super.c b/fs/btrfs/super.c
index 74ed5aa..f6e1119 100644
--- a/fs/btrfs/super.c
+++ b/fs/btrfs/super.c
@@ -1834,6 +1834,8 @@
goto restore;
}
+ btrfs_qgroup_rescan_resume(fs_info);
+
if (!fs_info->uuid_root) {
btrfs_info(fs_info, "creating UUID tree");
ret = btrfs_create_uuid_tree(fs_info);
diff --git a/fs/dlm/user.c b/fs/dlm/user.c
index 58c2f4a..9ac6591 100644
--- a/fs/dlm/user.c
+++ b/fs/dlm/user.c
@@ -355,6 +355,10 @@
error = misc_register(&ls->ls_device);
if (error) {
kfree(ls->ls_device.name);
+ /* this has to be set to NULL
+ * to avoid a double-free in dlm_device_deregister
+ */
+ ls->ls_device.name = NULL;
}
fail:
return error;
diff --git a/fs/f2fs/recovery.c b/fs/f2fs/recovery.c
index 2fc84a9..98c1a63 100644
--- a/fs/f2fs/recovery.c
+++ b/fs/f2fs/recovery.c
@@ -316,7 +316,7 @@
return 0;
/* Get the previous summary */
- for (i = CURSEG_WARM_DATA; i <= CURSEG_COLD_DATA; i++) {
+ for (i = CURSEG_HOT_DATA; i <= CURSEG_COLD_DATA; i++) {
struct curseg_info *curseg = CURSEG_I(sbi, i);
if (curseg->segno == segno) {
sum = curseg->sum_blk->entries[blkoff];
@@ -626,8 +626,6 @@
}
clear_sbi_flag(sbi, SBI_POR_DOING);
- if (err)
- set_ckpt_flags(sbi, CP_ERROR_FLAG);
mutex_unlock(&sbi->cp_mutex);
/* let's drop all the directory inodes for clean checkpoint */
diff --git a/fs/inode.c b/fs/inode.c
index 0aaebd1..3844c31 100644
--- a/fs/inode.c
+++ b/fs/inode.c
@@ -637,6 +637,7 @@
dispose_list(&dispose);
}
+EXPORT_SYMBOL_GPL(evict_inodes);
/**
* invalidate_inodes - attempt to free all inodes on a superblock
diff --git a/fs/internal.h b/fs/internal.h
index 15fe2aa..3e58863 100644
--- a/fs/internal.h
+++ b/fs/internal.h
@@ -138,7 +138,6 @@
extern void inode_io_list_del(struct inode *inode);
extern long get_nr_dirty_inodes(void);
-extern void evict_inodes(struct super_block *);
extern int invalidate_inodes(struct super_block *, bool);
/*
diff --git a/fs/iomap.c b/fs/iomap.c
index 798c291..a49db88 100644
--- a/fs/iomap.c
+++ b/fs/iomap.c
@@ -281,7 +281,7 @@
unsigned long bytes; /* Bytes to write to page */
offset = (pos & (PAGE_SIZE - 1));
- bytes = min_t(unsigned long, PAGE_SIZE - offset, length);
+ bytes = min_t(loff_t, PAGE_SIZE - offset, length);
rpage = __iomap_read_page(inode, pos);
if (IS_ERR(rpage))
@@ -376,7 +376,7 @@
unsigned offset, bytes;
offset = pos & (PAGE_SIZE - 1); /* Within page */
- bytes = min_t(unsigned, PAGE_SIZE - offset, count);
+ bytes = min_t(loff_t, PAGE_SIZE - offset, count);
if (IS_DAX(inode))
status = iomap_dax_zero(pos, offset, bytes, iomap);
diff --git a/fs/namespace.c b/fs/namespace.c
index 7731f77..2160bb9 100644
--- a/fs/namespace.c
+++ b/fs/namespace.c
@@ -227,6 +227,7 @@
mnt->mnt_count = 1;
mnt->mnt_writers = 0;
#endif
+ mnt->mnt.data = NULL;
INIT_HLIST_NODE(&mnt->mnt_hash);
INIT_LIST_HEAD(&mnt->mnt_child);
@@ -976,7 +977,6 @@
if (!mnt)
return ERR_PTR(-ENOMEM);
- mnt->mnt.data = NULL;
if (type->alloc_mnt_data) {
mnt->mnt.data = type->alloc_mnt_data();
if (!mnt->mnt.data) {
@@ -990,7 +990,6 @@
root = mount_fs(type, flags, name, &mnt->mnt, data);
if (IS_ERR(root)) {
- kfree(mnt->mnt.data);
mnt_free_id(mnt);
free_vfsmnt(mnt);
return ERR_CAST(root);
@@ -1109,7 +1108,6 @@
return mnt;
out_free:
- kfree(mnt->mnt.data);
mnt_free_id(mnt);
free_vfsmnt(mnt);
return ERR_PTR(err);
diff --git a/fs/nfs/file.c b/fs/nfs/file.c
index 84c1cb9..1eec947 100644
--- a/fs/nfs/file.c
+++ b/fs/nfs/file.c
@@ -636,11 +636,11 @@
if (result <= 0)
goto out;
- result = generic_write_sync(iocb, result);
- if (result < 0)
- goto out;
written = result;
iocb->ki_pos += written;
+ result = generic_write_sync(iocb, written);
+ if (result < 0)
+ goto out;
/* Return error values */
if (nfs_need_check_write(file, inode)) {
diff --git a/fs/nfs/internal.h b/fs/nfs/internal.h
index 80bcc0b..52ea41b 100644
--- a/fs/nfs/internal.h
+++ b/fs/nfs/internal.h
@@ -248,7 +248,6 @@
extern const struct nfs_pageio_ops nfs_pgio_rw_ops;
struct nfs_pgio_header *nfs_pgio_header_alloc(const struct nfs_rw_ops *);
void nfs_pgio_header_free(struct nfs_pgio_header *);
-void nfs_pgio_data_destroy(struct nfs_pgio_header *);
int nfs_generic_pgio(struct nfs_pageio_descriptor *, struct nfs_pgio_header *);
int nfs_initiate_pgio(struct rpc_clnt *clnt, struct nfs_pgio_header *hdr,
struct rpc_cred *cred, const struct nfs_rpc_ops *rpc_ops,
diff --git a/fs/nfs/pagelist.c b/fs/nfs/pagelist.c
index 142a74f..3d17fc8 100644
--- a/fs/nfs/pagelist.c
+++ b/fs/nfs/pagelist.c
@@ -497,16 +497,6 @@
}
EXPORT_SYMBOL_GPL(nfs_pgio_header_alloc);
-/*
- * nfs_pgio_header_free - Free a read or write header
- * @hdr: The header to free
- */
-void nfs_pgio_header_free(struct nfs_pgio_header *hdr)
-{
- hdr->rw_ops->rw_free_header(hdr);
-}
-EXPORT_SYMBOL_GPL(nfs_pgio_header_free);
-
/**
* nfs_pgio_data_destroy - make @hdr suitable for reuse
*
@@ -515,14 +505,24 @@
*
* @hdr: A header that has had nfs_generic_pgio called
*/
-void nfs_pgio_data_destroy(struct nfs_pgio_header *hdr)
+static void nfs_pgio_data_destroy(struct nfs_pgio_header *hdr)
{
if (hdr->args.context)
put_nfs_open_context(hdr->args.context);
if (hdr->page_array.pagevec != hdr->page_array.page_array)
kfree(hdr->page_array.pagevec);
}
-EXPORT_SYMBOL_GPL(nfs_pgio_data_destroy);
+
+/*
+ * nfs_pgio_header_free - Free a read or write header
+ * @hdr: The header to free
+ */
+void nfs_pgio_header_free(struct nfs_pgio_header *hdr)
+{
+ nfs_pgio_data_destroy(hdr);
+ hdr->rw_ops->rw_free_header(hdr);
+}
+EXPORT_SYMBOL_GPL(nfs_pgio_header_free);
/**
* nfs_pgio_rpcsetup - Set up arguments for a pageio call
@@ -636,7 +636,6 @@
static void nfs_pgio_error(struct nfs_pgio_header *hdr)
{
set_bit(NFS_IOHDR_REDO, &hdr->flags);
- nfs_pgio_data_destroy(hdr);
hdr->completion_ops->completion(hdr);
}
@@ -647,7 +646,6 @@
static void nfs_pgio_release(void *calldata)
{
struct nfs_pgio_header *hdr = calldata;
- nfs_pgio_data_destroy(hdr);
hdr->completion_ops->completion(hdr);
}
diff --git a/fs/nfs/pnfs.c b/fs/nfs/pnfs.c
index 415d7e6..b7a07ba 100644
--- a/fs/nfs/pnfs.c
+++ b/fs/nfs/pnfs.c
@@ -2145,7 +2145,6 @@
nfs_pageio_reset_write_mds(desc);
mirror->pg_recoalesce = 1;
}
- nfs_pgio_data_destroy(hdr);
hdr->release(hdr);
}
@@ -2257,7 +2256,6 @@
nfs_pageio_reset_read_mds(desc);
mirror->pg_recoalesce = 1;
}
- nfs_pgio_data_destroy(hdr);
hdr->release(hdr);
}
diff --git a/fs/sdcardfs/derived_perm.c b/fs/sdcardfs/derived_perm.c
index 1239d1c..fffaad4 100644
--- a/fs/sdcardfs/derived_perm.c
+++ b/fs/sdcardfs/derived_perm.c
@@ -176,6 +176,9 @@
gid_t gid = sbi->options.fs_low_gid;
struct iattr newattrs;
+ if (!sbi->options.gid_derivation)
+ return;
+
info = SDCARDFS_I(d_inode(dentry));
info_d = info->data;
perm = info_d->perm;
diff --git a/fs/sdcardfs/inode.c b/fs/sdcardfs/inode.c
index 683b492..4a971e2 100644
--- a/fs/sdcardfs/inode.c
+++ b/fs/sdcardfs/inode.c
@@ -34,10 +34,14 @@
if (!cred)
return NULL;
- if (data->under_obb)
- uid = AID_MEDIA_OBB;
- else
- uid = multiuser_get_uid(data->userid, sbi->options.fs_low_uid);
+ if (sbi->options.gid_derivation) {
+ if (data->under_obb)
+ uid = AID_MEDIA_OBB;
+ else
+ uid = multiuser_get_uid(data->userid, sbi->options.fs_low_uid);
+ } else {
+ uid = sbi->options.fs_low_uid;
+ }
cred->fsuid = make_kuid(&init_user_ns, uid);
cred->fsgid = make_kgid(&init_user_ns, sbi->options.fs_low_gid);
diff --git a/fs/sdcardfs/main.c b/fs/sdcardfs/main.c
index 80825b2..0a2b516 100644
--- a/fs/sdcardfs/main.c
+++ b/fs/sdcardfs/main.c
@@ -32,6 +32,7 @@
Opt_multiuser,
Opt_userid,
Opt_reserved_mb,
+ Opt_gid_derivation,
Opt_err,
};
@@ -43,6 +44,7 @@
{Opt_mask, "mask=%u"},
{Opt_userid, "userid=%d"},
{Opt_multiuser, "multiuser"},
+ {Opt_gid_derivation, "derive_gid"},
{Opt_reserved_mb, "reserved_mb=%u"},
{Opt_err, NULL}
};
@@ -64,6 +66,8 @@
vfsopts->gid = 0;
/* by default, 0MB is reserved */
opts->reserved_mb = 0;
+ /* by default, gid derivation is off */
+ opts->gid_derivation = false;
*debug = 0;
@@ -115,6 +119,9 @@
return 0;
opts->reserved_mb = option;
break;
+ case Opt_gid_derivation:
+ opts->gid_derivation = true;
+ break;
/* unknown option */
default:
if (!silent)
diff --git a/fs/sdcardfs/sdcardfs.h b/fs/sdcardfs/sdcardfs.h
index 4e0ce49..d1d8bab 100644
--- a/fs/sdcardfs/sdcardfs.h
+++ b/fs/sdcardfs/sdcardfs.h
@@ -219,6 +219,7 @@
gid_t fs_low_gid;
userid_t fs_user_id;
bool multiuser;
+ bool gid_derivation;
unsigned int reserved_mb;
};
diff --git a/fs/sdcardfs/super.c b/fs/sdcardfs/super.c
index 7f4539b..b89947d 100644
--- a/fs/sdcardfs/super.c
+++ b/fs/sdcardfs/super.c
@@ -302,6 +302,8 @@
seq_printf(m, ",mask=%u", vfsopts->mask);
if (opts->fs_user_id)
seq_printf(m, ",userid=%u", opts->fs_user_id);
+ if (opts->gid_derivation)
+ seq_puts(m, ",derive_gid");
if (opts->reserved_mb != 0)
seq_printf(m, ",reserved=%uMB", opts->reserved_mb);
diff --git a/fs/xfs/libxfs/xfs_attr_leaf.c b/fs/xfs/libxfs/xfs_attr_leaf.c
index 2852521..c6c15e5 100644
--- a/fs/xfs/libxfs/xfs_attr_leaf.c
+++ b/fs/xfs/libxfs/xfs_attr_leaf.c
@@ -351,7 +351,7 @@
err = xfs_da_read_buf(tp, dp, bno, mappedbno, bpp,
XFS_ATTR_FORK, &xfs_attr3_leaf_buf_ops);
- if (!err && tp)
+ if (!err && tp && *bpp)
xfs_trans_buf_set_type(tp, *bpp, XFS_BLFT_ATTR_LEAF_BUF);
return err;
}
diff --git a/fs/xfs/libxfs/xfs_bmap.c b/fs/xfs/libxfs/xfs_bmap.c
index 2a8cbd1..d2f4ab1 100644
--- a/fs/xfs/libxfs/xfs_bmap.c
+++ b/fs/xfs/libxfs/xfs_bmap.c
@@ -579,7 +579,7 @@
#else
#define xfs_bmap_check_leaf_extents(cur, ip, whichfork) do { } while (0)
-#define xfs_bmap_validate_ret(bno,len,flags,mval,onmap,nmap)
+#define xfs_bmap_validate_ret(bno,len,flags,mval,onmap,nmap) do { } while (0)
#endif /* DEBUG */
/*
@@ -5555,6 +5555,8 @@
int whichfork; /* data or attribute fork */
xfs_fsblock_t sum;
xfs_filblks_t len = *rlen; /* length to unmap in file */
+ xfs_fileoff_t max_len;
+ xfs_agnumber_t prev_agno = NULLAGNUMBER, agno;
trace_xfs_bunmap(ip, bno, len, flags, _RET_IP_);
@@ -5576,6 +5578,16 @@
ASSERT(len > 0);
ASSERT(nexts >= 0);
+ /*
+ * Guesstimate how many blocks we can unmap without running the risk of
+ * blowing out the transaction with a mix of EFIs and reflink
+ * adjustments.
+ */
+ if (xfs_is_reflink_inode(ip) && whichfork == XFS_DATA_FORK)
+ max_len = min(len, xfs_refcount_max_unmap(tp->t_log_res));
+ else
+ max_len = len;
+
if (!(ifp->if_flags & XFS_IFEXTENTS) &&
(error = xfs_iread_extents(tp, ip, whichfork)))
return error;
@@ -5621,7 +5633,7 @@
extno = 0;
while (bno != (xfs_fileoff_t)-1 && bno >= start && lastx >= 0 &&
- (nexts == 0 || extno < nexts)) {
+ (nexts == 0 || extno < nexts) && max_len > 0) {
/*
* Is the found extent after a hole in which bno lives?
* Just back up to the previous extent, if so.
@@ -5647,6 +5659,17 @@
ASSERT(ep != NULL);
del = got;
wasdel = isnullstartblock(del.br_startblock);
+
+ /*
+ * Make sure we don't touch multiple AGF headers out of order
+ * in a single transaction, as that could cause AB-BA deadlocks.
+ */
+ if (!wasdel) {
+ agno = XFS_FSB_TO_AGNO(mp, del.br_startblock);
+ if (prev_agno != NULLAGNUMBER && prev_agno > agno)
+ break;
+ prev_agno = agno;
+ }
if (got.br_startoff < start) {
del.br_startoff = start;
del.br_blockcount -= start - got.br_startoff;
@@ -5655,6 +5678,15 @@
}
if (del.br_startoff + del.br_blockcount > bno + 1)
del.br_blockcount = bno + 1 - del.br_startoff;
+
+ /* How much can we safely unmap? */
+ if (max_len < del.br_blockcount) {
+ del.br_startoff += del.br_blockcount - max_len;
+ if (!wasdel)
+ del.br_startblock += del.br_blockcount - max_len;
+ del.br_blockcount = max_len;
+ }
+
sum = del.br_startblock + del.br_blockcount;
if (isrt &&
(mod = do_mod(sum, mp->m_sb.sb_rextsize))) {
@@ -5835,6 +5867,7 @@
if (!isrt && wasdel)
xfs_mod_fdblocks(mp, (int64_t)del.br_blockcount, false);
+ max_len -= del.br_blockcount;
bno = del.br_startoff - 1;
nodelete:
/*
@@ -6604,25 +6637,33 @@
int whichfork,
xfs_fileoff_t startoff,
xfs_fsblock_t startblock,
- xfs_filblks_t blockcount,
+ xfs_filblks_t *blockcount,
xfs_exntst_t state)
{
struct xfs_bmbt_irec bmap;
int nimaps = 1;
xfs_fsblock_t firstfsb;
int flags = XFS_BMAPI_REMAP;
- int done;
int error = 0;
bmap.br_startblock = startblock;
bmap.br_startoff = startoff;
- bmap.br_blockcount = blockcount;
+ bmap.br_blockcount = *blockcount;
bmap.br_state = state;
+ /*
+ * firstfsb is tied to the transaction lifetime and is used to
+ * ensure correct AG locking order and schedule work item
+ * continuations. XFS_BUI_MAX_FAST_EXTENTS (== 1) restricts us
+ * to only making one bmap call per transaction, so it should
+ * be safe to have it as a local variable here.
+ */
+ firstfsb = NULLFSBLOCK;
+
trace_xfs_bmap_deferred(tp->t_mountp,
XFS_FSB_TO_AGNO(tp->t_mountp, startblock), type,
XFS_FSB_TO_AGBNO(tp->t_mountp, startblock),
- ip->i_ino, whichfork, startoff, blockcount, state);
+ ip->i_ino, whichfork, startoff, *blockcount, state);
if (whichfork != XFS_DATA_FORK && whichfork != XFS_ATTR_FORK)
return -EFSCORRUPTED;
@@ -6641,12 +6682,11 @@
bmap.br_blockcount, flags, &firstfsb,
bmap.br_blockcount, &bmap, &nimaps,
dfops);
+ *blockcount = 0;
break;
case XFS_BMAP_UNMAP:
- error = xfs_bunmapi(tp, ip, bmap.br_startoff,
- bmap.br_blockcount, flags, 1, &firstfsb,
- dfops, &done);
- ASSERT(done);
+ error = __xfs_bunmapi(tp, ip, startoff, blockcount,
+ XFS_BMAPI_REMAP, 1, &firstfsb, dfops);
break;
default:
ASSERT(0);
diff --git a/fs/xfs/libxfs/xfs_bmap.h b/fs/xfs/libxfs/xfs_bmap.h
index e7d40b3..db53ac7f 100644
--- a/fs/xfs/libxfs/xfs_bmap.h
+++ b/fs/xfs/libxfs/xfs_bmap.h
@@ -265,7 +265,7 @@
int xfs_bmap_finish_one(struct xfs_trans *tp, struct xfs_defer_ops *dfops,
struct xfs_inode *ip, enum xfs_bmap_intent_type type,
int whichfork, xfs_fileoff_t startoff, xfs_fsblock_t startblock,
- xfs_filblks_t blockcount, xfs_exntst_t state);
+ xfs_filblks_t *blockcount, xfs_exntst_t state);
int xfs_bmap_map_extent(struct xfs_mount *mp, struct xfs_defer_ops *dfops,
struct xfs_inode *ip, struct xfs_bmbt_irec *imap);
int xfs_bmap_unmap_extent(struct xfs_mount *mp, struct xfs_defer_ops *dfops,
diff --git a/fs/xfs/libxfs/xfs_bmap_btree.c b/fs/xfs/libxfs/xfs_bmap_btree.c
index 5c39186..9968a74 100644
--- a/fs/xfs/libxfs/xfs_bmap_btree.c
+++ b/fs/xfs/libxfs/xfs_bmap_btree.c
@@ -888,6 +888,7 @@
cur = xfs_bmbt_init_cursor(ip->i_mount, tp, ip, whichfork);
if (!cur)
return -ENOMEM;
+ cur->bc_private.b.flags |= XFS_BTCUR_BPRV_INVALID_OWNER;
error = xfs_btree_change_owner(cur, new_owner, buffer_list);
xfs_btree_del_cursor(cur, error ? XFS_BTREE_ERROR : XFS_BTREE_NOERROR);
diff --git a/fs/xfs/libxfs/xfs_btree.c b/fs/xfs/libxfs/xfs_btree.c
index 91c6891..4ad1e21 100644
--- a/fs/xfs/libxfs/xfs_btree.c
+++ b/fs/xfs/libxfs/xfs_btree.c
@@ -714,7 +714,8 @@
* Get the block pointer for this level.
*/
block = xfs_btree_get_block(cur, level, &bp);
- xfs_btree_check_block(cur, block, level, bp);
+ if (xfs_btree_check_block(cur, block, level, bp))
+ return 0;
/*
* It's empty, there is no such record.
*/
@@ -743,7 +744,8 @@
* Get the block pointer for this level.
*/
block = xfs_btree_get_block(cur, level, &bp);
- xfs_btree_check_block(cur, block, level, bp);
+ if (xfs_btree_check_block(cur, block, level, bp))
+ return 0;
/*
* It's empty, there is no such record.
*/
@@ -1772,6 +1774,7 @@
/* Check the inode owner since the verifiers don't. */
if (xfs_sb_version_hascrc(&cur->bc_mp->m_sb) &&
+ !(cur->bc_private.b.flags & XFS_BTCUR_BPRV_INVALID_OWNER) &&
(cur->bc_flags & XFS_BTREE_LONG_PTRS) &&
be64_to_cpu((*blkp)->bb_u.l.bb_owner) !=
cur->bc_private.b.ip->i_ino)
@@ -4432,10 +4435,15 @@
/* modify the owner */
block = xfs_btree_get_block(cur, level, &bp);
- if (cur->bc_flags & XFS_BTREE_LONG_PTRS)
+ if (cur->bc_flags & XFS_BTREE_LONG_PTRS) {
+ if (block->bb_u.l.bb_owner == cpu_to_be64(bbcoi->new_owner))
+ return 0;
block->bb_u.l.bb_owner = cpu_to_be64(bbcoi->new_owner);
- else
+ } else {
+ if (block->bb_u.s.bb_owner == cpu_to_be32(bbcoi->new_owner))
+ return 0;
block->bb_u.s.bb_owner = cpu_to_be32(bbcoi->new_owner);
+ }
/*
* If the block is a root block hosted in an inode, we might not have a
@@ -4444,16 +4452,19 @@
* block is formatted into the on-disk inode fork. We still change it,
* though, so everything is consistent in memory.
*/
- if (bp) {
- if (cur->bc_tp) {
- xfs_trans_ordered_buf(cur->bc_tp, bp);
- xfs_btree_log_block(cur, bp, XFS_BB_OWNER);
- } else {
- xfs_buf_delwri_queue(bp, bbcoi->buffer_list);
- }
- } else {
+ if (!bp) {
ASSERT(cur->bc_flags & XFS_BTREE_ROOT_IN_INODE);
ASSERT(level == cur->bc_nlevels - 1);
+ return 0;
+ }
+
+ if (cur->bc_tp) {
+ if (!xfs_trans_ordered_buf(cur->bc_tp, bp)) {
+ xfs_btree_log_block(cur, bp, XFS_BB_OWNER);
+ return -EAGAIN;
+ }
+ } else {
+ xfs_buf_delwri_queue(bp, bbcoi->buffer_list);
}
return 0;
diff --git a/fs/xfs/libxfs/xfs_btree.h b/fs/xfs/libxfs/xfs_btree.h
index 3b0fc1a..33c7be2 100644
--- a/fs/xfs/libxfs/xfs_btree.h
+++ b/fs/xfs/libxfs/xfs_btree.h
@@ -268,7 +268,8 @@
short forksize; /* fork's inode space */
char whichfork; /* data or attr fork */
char flags; /* flags */
-#define XFS_BTCUR_BPRV_WASDEL 1 /* was delayed */
+#define XFS_BTCUR_BPRV_WASDEL (1<<0) /* was delayed */
+#define XFS_BTCUR_BPRV_INVALID_OWNER (1<<1) /* for ext swap */
} b;
} bc_private; /* per-btree type data */
} xfs_btree_cur_t;
diff --git a/fs/xfs/libxfs/xfs_da_btree.c b/fs/xfs/libxfs/xfs_da_btree.c
index 1bdf288..b305dbf 100644
--- a/fs/xfs/libxfs/xfs_da_btree.c
+++ b/fs/xfs/libxfs/xfs_da_btree.c
@@ -263,7 +263,7 @@
err = xfs_da_read_buf(tp, dp, bno, mappedbno, bpp,
which_fork, &xfs_da3_node_buf_ops);
- if (!err && tp) {
+ if (!err && tp && *bpp) {
struct xfs_da_blkinfo *info = (*bpp)->b_addr;
int type;
diff --git a/fs/xfs/libxfs/xfs_dir2_block.c b/fs/xfs/libxfs/xfs_dir2_block.c
index aa17cb7..43c902f 100644
--- a/fs/xfs/libxfs/xfs_dir2_block.c
+++ b/fs/xfs/libxfs/xfs_dir2_block.c
@@ -139,7 +139,7 @@
err = xfs_da_read_buf(tp, dp, mp->m_dir_geo->datablk, -1, bpp,
XFS_DATA_FORK, &xfs_dir3_block_buf_ops);
- if (!err && tp)
+ if (!err && tp && *bpp)
xfs_trans_buf_set_type(tp, *bpp, XFS_BLFT_DIR_BLOCK_BUF);
return err;
}
diff --git a/fs/xfs/libxfs/xfs_dir2_leaf.c b/fs/xfs/libxfs/xfs_dir2_leaf.c
index b887fb2..f2e342e 100644
--- a/fs/xfs/libxfs/xfs_dir2_leaf.c
+++ b/fs/xfs/libxfs/xfs_dir2_leaf.c
@@ -268,7 +268,7 @@
err = xfs_da_read_buf(tp, dp, fbno, mappedbno, bpp,
XFS_DATA_FORK, &xfs_dir3_leaf1_buf_ops);
- if (!err && tp)
+ if (!err && tp && *bpp)
xfs_trans_buf_set_type(tp, *bpp, XFS_BLFT_DIR_LEAF1_BUF);
return err;
}
@@ -285,7 +285,7 @@
err = xfs_da_read_buf(tp, dp, fbno, mappedbno, bpp,
XFS_DATA_FORK, &xfs_dir3_leafn_buf_ops);
- if (!err && tp)
+ if (!err && tp && *bpp)
xfs_trans_buf_set_type(tp, *bpp, XFS_BLFT_DIR_LEAFN_BUF);
return err;
}
diff --git a/fs/xfs/libxfs/xfs_ialloc.c b/fs/xfs/libxfs/xfs_ialloc.c
index a2818f6..42fef07 100644
--- a/fs/xfs/libxfs/xfs_ialloc.c
+++ b/fs/xfs/libxfs/xfs_ialloc.c
@@ -368,8 +368,6 @@
* transaction and pin the log appropriately.
*/
xfs_trans_ordered_buf(tp, fbuf);
- xfs_trans_log_buf(tp, fbuf, 0,
- BBTOB(fbuf->b_length) - 1);
}
} else {
fbuf->b_flags |= XBF_DONE;
@@ -1123,6 +1121,7 @@
int error;
int offset;
int i, j;
+ int searchdistance = 10;
pag = xfs_perag_get(mp, agno);
@@ -1149,7 +1148,6 @@
if (pagno == agno) {
int doneleft; /* done, to the left */
int doneright; /* done, to the right */
- int searchdistance = 10;
error = xfs_inobt_lookup(cur, pagino, XFS_LOOKUP_LE, &i);
if (error)
@@ -1210,21 +1208,9 @@
/*
* Loop until we find an inode chunk with a free inode.
*/
- while (!doneleft || !doneright) {
+ while (--searchdistance > 0 && (!doneleft || !doneright)) {
int useleft; /* using left inode chunk this time */
- if (!--searchdistance) {
- /*
- * Not in range - save last search
- * location and allocate a new inode
- */
- xfs_btree_del_cursor(tcur, XFS_BTREE_NOERROR);
- pag->pagl_leftrec = trec.ir_startino;
- pag->pagl_rightrec = rec.ir_startino;
- pag->pagl_pagino = pagino;
- goto newino;
- }
-
/* figure out the closer block if both are valid. */
if (!doneleft && !doneright) {
useleft = pagino -
@@ -1236,13 +1222,13 @@
/* free inodes to the left? */
if (useleft && trec.ir_freecount) {
- rec = trec;
xfs_btree_del_cursor(cur, XFS_BTREE_NOERROR);
cur = tcur;
pag->pagl_leftrec = trec.ir_startino;
pag->pagl_rightrec = rec.ir_startino;
pag->pagl_pagino = pagino;
+ rec = trec;
goto alloc_inode;
}
@@ -1268,26 +1254,37 @@
goto error1;
}
- /*
- * We've reached the end of the btree. because
- * we are only searching a small chunk of the
- * btree each search, there is obviously free
- * inodes closer to the parent inode than we
- * are now. restart the search again.
- */
- pag->pagl_pagino = NULLAGINO;
- pag->pagl_leftrec = NULLAGINO;
- pag->pagl_rightrec = NULLAGINO;
- xfs_btree_del_cursor(tcur, XFS_BTREE_NOERROR);
- xfs_btree_del_cursor(cur, XFS_BTREE_NOERROR);
- goto restart_pagno;
+ if (searchdistance <= 0) {
+ /*
+ * Not in range - save last search
+ * location and allocate a new inode
+ */
+ xfs_btree_del_cursor(tcur, XFS_BTREE_NOERROR);
+ pag->pagl_leftrec = trec.ir_startino;
+ pag->pagl_rightrec = rec.ir_startino;
+ pag->pagl_pagino = pagino;
+
+ } else {
+ /*
+ * We've reached the end of the btree. because
+ * we are only searching a small chunk of the
+ * btree each search, there is obviously free
+ * inodes closer to the parent inode than we
+ * are now. restart the search again.
+ */
+ pag->pagl_pagino = NULLAGINO;
+ pag->pagl_leftrec = NULLAGINO;
+ pag->pagl_rightrec = NULLAGINO;
+ xfs_btree_del_cursor(tcur, XFS_BTREE_NOERROR);
+ xfs_btree_del_cursor(cur, XFS_BTREE_NOERROR);
+ goto restart_pagno;
+ }
}
/*
* In a different AG from the parent.
* See if the most recently allocated block has any free.
*/
-newino:
if (agi->agi_newino != cpu_to_be32(NULLAGINO)) {
error = xfs_inobt_lookup(cur, be32_to_cpu(agi->agi_newino),
XFS_LOOKUP_EQ, &i);
diff --git a/fs/xfs/libxfs/xfs_inode_fork.c b/fs/xfs/libxfs/xfs_inode_fork.c
index 8a37efe..4e30448 100644
--- a/fs/xfs/libxfs/xfs_inode_fork.c
+++ b/fs/xfs/libxfs/xfs_inode_fork.c
@@ -1539,14 +1539,11 @@
xfs_ifork_t *ifp, /* inode fork pointer */
int new_size) /* new indirection array size */
{
- int nlists; /* number of irec's (ex lists) */
- int size; /* current indirection array size */
-
ASSERT(ifp->if_flags & XFS_IFEXTIREC);
- nlists = ifp->if_real_bytes / XFS_IEXT_BUFSZ;
- size = nlists * sizeof(xfs_ext_irec_t);
ASSERT(ifp->if_real_bytes);
- ASSERT((new_size >= 0) && (new_size != size));
+ ASSERT((new_size >= 0) &&
+ (new_size != ((ifp->if_real_bytes / XFS_IEXT_BUFSZ) *
+ sizeof(xfs_ext_irec_t))));
if (new_size == 0) {
xfs_iext_destroy(ifp);
} else {
diff --git a/fs/xfs/libxfs/xfs_refcount.c b/fs/xfs/libxfs/xfs_refcount.c
index 82a38d8..d71cb63 100644
--- a/fs/xfs/libxfs/xfs_refcount.c
+++ b/fs/xfs/libxfs/xfs_refcount.c
@@ -784,14 +784,6 @@
}
/*
- * While we're adjusting the refcounts records of an extent, we have
- * to keep an eye on the number of extents we're dirtying -- run too
- * many in a single transaction and we'll exceed the transaction's
- * reservation and crash the fs. Each record adds 12 bytes to the
- * log (plus any key updates) so we'll conservatively assume 24 bytes
- * per record. We must also leave space for btree splits on both ends
- * of the range and space for the CUD and a new CUI.
- *
* XXX: This is a pretty hand-wavy estimate. The penalty for guessing
* true incorrectly is a shutdown FS; the penalty for guessing false
* incorrectly is more transaction rolls than might be necessary.
@@ -822,7 +814,7 @@
else if (overhead > cur->bc_tp->t_log_res)
return false;
return cur->bc_tp->t_log_res - overhead >
- cur->bc_private.a.priv.refc.nr_ops * 32;
+ cur->bc_private.a.priv.refc.nr_ops * XFS_REFCOUNT_ITEM_OVERHEAD;
}
/*
@@ -1648,6 +1640,10 @@
error = xfs_alloc_read_agf(mp, tp, agno, 0, &agbp);
if (error)
goto out_trans;
+ if (!agbp) {
+ error = -ENOMEM;
+ goto out_trans;
+ }
cur = xfs_refcountbt_init_cursor(mp, tp, agbp, agno, NULL);
/* Find all the leftover CoW staging extents. */
diff --git a/fs/xfs/libxfs/xfs_refcount.h b/fs/xfs/libxfs/xfs_refcount.h
index 098dc668..eafb9d1 100644
--- a/fs/xfs/libxfs/xfs_refcount.h
+++ b/fs/xfs/libxfs/xfs_refcount.h
@@ -67,4 +67,20 @@
extern int xfs_refcount_recover_cow_leftovers(struct xfs_mount *mp,
xfs_agnumber_t agno);
+/*
+ * While we're adjusting the refcounts records of an extent, we have
+ * to keep an eye on the number of extents we're dirtying -- run too
+ * many in a single transaction and we'll exceed the transaction's
+ * reservation and crash the fs. Each record adds 12 bytes to the
+ * log (plus any key updates) so we'll conservatively assume 32 bytes
+ * per record. We must also leave space for btree splits on both ends
+ * of the range and space for the CUD and a new CUI.
+ */
+#define XFS_REFCOUNT_ITEM_OVERHEAD 32
+
+static inline xfs_fileoff_t xfs_refcount_max_unmap(int log_res)
+{
+ return (log_res * 3 / 4) / XFS_REFCOUNT_ITEM_OVERHEAD;
+}
+
#endif /* __XFS_REFCOUNT_H__ */
diff --git a/fs/xfs/xfs_aops.c b/fs/xfs/xfs_aops.c
index 5789814..d23889e 100644
--- a/fs/xfs/xfs_aops.c
+++ b/fs/xfs/xfs_aops.c
@@ -90,11 +90,11 @@
* associated buffer_heads, paying attention to the start and end offsets that
* we need to process on the page.
*
- * Landmine Warning: bh->b_end_io() will call end_page_writeback() on the last
- * buffer in the IO. Once it does this, it is unsafe to access the bufferhead or
- * the page at all, as we may be racing with memory reclaim and it can free both
- * the bufferhead chain and the page as it will see the page as clean and
- * unused.
+ * Note that we open code the action in end_buffer_async_write here so that we
+ * only have to iterate over the buffers attached to the page once. This is not
+ * only more efficient, but also ensures that we only calls end_page_writeback
+ * at the end of the iteration, and thus avoids the pitfall of having the page
+ * and buffers potentially freed after every call to end_buffer_async_write.
*/
static void
xfs_finish_page_writeback(
@@ -102,29 +102,45 @@
struct bio_vec *bvec,
int error)
{
- unsigned int end = bvec->bv_offset + bvec->bv_len - 1;
- struct buffer_head *head, *bh, *next;
+ struct buffer_head *head = page_buffers(bvec->bv_page), *bh = head;
+ bool busy = false;
unsigned int off = 0;
- unsigned int bsize;
+ unsigned long flags;
ASSERT(bvec->bv_offset < PAGE_SIZE);
ASSERT((bvec->bv_offset & (i_blocksize(inode) - 1)) == 0);
- ASSERT(end < PAGE_SIZE);
+ ASSERT(bvec->bv_offset + bvec->bv_len <= PAGE_SIZE);
ASSERT((bvec->bv_len & (i_blocksize(inode) - 1)) == 0);
- bh = head = page_buffers(bvec->bv_page);
-
- bsize = bh->b_size;
+ local_irq_save(flags);
+ bit_spin_lock(BH_Uptodate_Lock, &head->b_state);
do {
- if (off > end)
- break;
- next = bh->b_this_page;
- if (off < bvec->bv_offset)
- goto next_bh;
- bh->b_end_io(bh, !error);
-next_bh:
- off += bsize;
- } while ((bh = next) != head);
+ if (off >= bvec->bv_offset &&
+ off < bvec->bv_offset + bvec->bv_len) {
+ ASSERT(buffer_async_write(bh));
+ ASSERT(bh->b_end_io == NULL);
+
+ if (error) {
+ mapping_set_error(bvec->bv_page->mapping, -EIO);
+ set_buffer_write_io_error(bh);
+ clear_buffer_uptodate(bh);
+ SetPageError(bvec->bv_page);
+ } else {
+ set_buffer_uptodate(bh);
+ }
+ clear_buffer_async_write(bh);
+ unlock_buffer(bh);
+ } else if (buffer_async_write(bh)) {
+ ASSERT(buffer_locked(bh));
+ busy = true;
+ }
+ off += bh->b_size;
+ } while ((bh = bh->b_this_page) != head);
+ bit_spin_unlock(BH_Uptodate_Lock, &head->b_state);
+ local_irq_restore(flags);
+
+ if (!busy)
+ end_page_writeback(bvec->bv_page);
}
/*
@@ -138,8 +154,10 @@
int error)
{
struct inode *inode = ioend->io_inode;
- struct bio *last = ioend->io_bio;
- struct bio *bio, *next;
+ struct bio *bio = &ioend->io_inline_bio;
+ struct bio *last = ioend->io_bio, *next;
+ u64 start = bio->bi_iter.bi_sector;
+ bool quiet = bio_flagged(bio, BIO_QUIET);
for (bio = &ioend->io_inline_bio; bio; bio = next) {
struct bio_vec *bvec;
@@ -160,6 +178,11 @@
bio_put(bio);
}
+
+ if (unlikely(error && !quiet)) {
+ xfs_err_ratelimited(XFS_I(inode)->i_mount,
+ "writeback error on sector %llu", start);
+ }
}
/*
@@ -427,7 +450,8 @@
ASSERT(!buffer_delay(bh));
ASSERT(!buffer_unwritten(bh));
- mark_buffer_async_write(bh);
+ bh->b_end_io = NULL;
+ set_buffer_async_write(bh);
set_buffer_uptodate(bh);
clear_buffer_dirty(bh);
}
@@ -1566,9 +1590,12 @@
* The swap code (ab-)uses ->bmap to get a block mapping and then
* bypasseѕ the file system for actual I/O. We really can't allow
* that on reflinks inodes, so we have to skip out here. And yes,
- * 0 is the magic code for a bmap error..
+ * 0 is the magic code for a bmap error.
+ *
+ * Since we don't pass back blockdev info, we can't return bmap
+ * information for rt files either.
*/
- if (xfs_is_reflink_inode(ip)) {
+ if (xfs_is_reflink_inode(ip) || XFS_IS_REALTIME_INODE(ip)) {
xfs_iunlock(ip, XFS_IOLOCK_SHARED);
return 0;
}
diff --git a/fs/xfs/xfs_bmap_item.c b/fs/xfs/xfs_bmap_item.c
index c4b90e7..5a54dcd 100644
--- a/fs/xfs/xfs_bmap_item.c
+++ b/fs/xfs/xfs_bmap_item.c
@@ -395,6 +395,7 @@
struct xfs_map_extent *bmap;
xfs_fsblock_t startblock_fsb;
xfs_fsblock_t inode_fsb;
+ xfs_filblks_t count;
bool op_ok;
struct xfs_bud_log_item *budp;
enum xfs_bmap_intent_type type;
@@ -403,6 +404,7 @@
struct xfs_trans *tp;
struct xfs_inode *ip = NULL;
struct xfs_defer_ops dfops;
+ struct xfs_bmbt_irec irec;
xfs_fsblock_t firstfsb;
ASSERT(!test_bit(XFS_BUI_RECOVERED, &buip->bui_flags));
@@ -480,13 +482,24 @@
}
xfs_trans_ijoin(tp, ip, 0);
+ count = bmap->me_len;
error = xfs_trans_log_finish_bmap_update(tp, budp, &dfops, type,
ip, whichfork, bmap->me_startoff,
- bmap->me_startblock, bmap->me_len,
- state);
+ bmap->me_startblock, &count, state);
if (error)
goto err_dfops;
+ if (count > 0) {
+ ASSERT(type == XFS_BMAP_UNMAP);
+ irec.br_startblock = bmap->me_startblock;
+ irec.br_blockcount = count;
+ irec.br_startoff = bmap->me_startoff;
+ irec.br_state = state;
+ error = xfs_bmap_unmap_extent(tp->t_mountp, &dfops, ip, &irec);
+ if (error)
+ goto err_dfops;
+ }
+
/* Finish transaction, free inodes. */
error = xfs_defer_finish(&tp, &dfops, NULL);
if (error)
diff --git a/fs/xfs/xfs_bmap_util.c b/fs/xfs/xfs_bmap_util.c
index 87b495e..5ffefac 100644
--- a/fs/xfs/xfs_bmap_util.c
+++ b/fs/xfs/xfs_bmap_util.c
@@ -1825,29 +1825,18 @@
}
/*
- * Before we've swapped the forks, lets set the owners of the forks
- * appropriately. We have to do this as we are demand paging the btree
- * buffers, and so the validation done on read will expect the owner
- * field to be correctly set. Once we change the owners, we can swap the
- * inode forks.
+ * Btree format (v3) inodes have the inode number stamped in the bmbt
+ * block headers. We can't start changing the bmbt blocks until the
+ * inode owner change is logged so recovery does the right thing in the
+ * event of a crash. Set the owner change log flags now and leave the
+ * bmbt scan as the last step.
*/
if (ip->i_d.di_version == 3 &&
- ip->i_d.di_format == XFS_DINODE_FMT_BTREE) {
+ ip->i_d.di_format == XFS_DINODE_FMT_BTREE)
(*target_log_flags) |= XFS_ILOG_DOWNER;
- error = xfs_bmbt_change_owner(tp, ip, XFS_DATA_FORK,
- tip->i_ino, NULL);
- if (error)
- return error;
- }
-
if (tip->i_d.di_version == 3 &&
- tip->i_d.di_format == XFS_DINODE_FMT_BTREE) {
+ tip->i_d.di_format == XFS_DINODE_FMT_BTREE)
(*src_log_flags) |= XFS_ILOG_DOWNER;
- error = xfs_bmbt_change_owner(tp, tip, XFS_DATA_FORK,
- ip->i_ino, NULL);
- if (error)
- return error;
- }
/*
* Swap the data forks of the inodes
@@ -1925,6 +1914,48 @@
return 0;
}
+/*
+ * Fix up the owners of the bmbt blocks to refer to the current inode. The
+ * change owner scan attempts to order all modified buffers in the current
+ * transaction. In the event of ordered buffer failure, the offending buffer is
+ * physically logged as a fallback and the scan returns -EAGAIN. We must roll
+ * the transaction in this case to replenish the fallback log reservation and
+ * restart the scan. This process repeats until the scan completes.
+ */
+static int
+xfs_swap_change_owner(
+ struct xfs_trans **tpp,
+ struct xfs_inode *ip,
+ struct xfs_inode *tmpip)
+{
+ int error;
+ struct xfs_trans *tp = *tpp;
+
+ do {
+ error = xfs_bmbt_change_owner(tp, ip, XFS_DATA_FORK, ip->i_ino,
+ NULL);
+ /* success or fatal error */
+ if (error != -EAGAIN)
+ break;
+
+ error = xfs_trans_roll(tpp, NULL);
+ if (error)
+ break;
+ tp = *tpp;
+
+ /*
+ * Redirty both inodes so they can relog and keep the log tail
+ * moving forward.
+ */
+ xfs_trans_ijoin(tp, ip, 0);
+ xfs_trans_ijoin(tp, tmpip, 0);
+ xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE);
+ xfs_trans_log_inode(tp, tmpip, XFS_ILOG_CORE);
+ } while (true);
+
+ return error;
+}
+
int
xfs_swap_extents(
struct xfs_inode *ip, /* target inode */
@@ -1938,8 +1969,8 @@
int error = 0;
int lock_flags;
struct xfs_ifork *cowfp;
- __uint64_t f;
- int resblks;
+ uint64_t f;
+ int resblks = 0;
/*
* Lock the inodes against other IO, page faults and truncate to
@@ -1987,11 +2018,8 @@
XFS_SWAP_RMAP_SPACE_RES(mp,
XFS_IFORK_NEXTENTS(tip, XFS_DATA_FORK),
XFS_DATA_FORK);
- error = xfs_trans_alloc(mp, &M_RES(mp)->tr_write, resblks,
- 0, 0, &tp);
- } else
- error = xfs_trans_alloc(mp, &M_RES(mp)->tr_ichange, 0,
- 0, 0, &tp);
+ }
+ error = xfs_trans_alloc(mp, &M_RES(mp)->tr_write, resblks, 0, 0, &tp);
if (error)
goto out_unlock;
@@ -2077,6 +2105,23 @@
xfs_trans_log_inode(tp, tip, target_log_flags);
/*
+ * The extent forks have been swapped, but crc=1,rmapbt=0 filesystems
+ * have inode number owner values in the bmbt blocks that still refer to
+ * the old inode. Scan each bmbt to fix up the owner values with the
+ * inode number of the current inode.
+ */
+ if (src_log_flags & XFS_ILOG_DOWNER) {
+ error = xfs_swap_change_owner(&tp, ip, tip);
+ if (error)
+ goto out_trans_cancel;
+ }
+ if (target_log_flags & XFS_ILOG_DOWNER) {
+ error = xfs_swap_change_owner(&tp, tip, ip);
+ if (error)
+ goto out_trans_cancel;
+ }
+
+ /*
* If this is a synchronous mount, make sure that the
* transaction goes to disk before returning to the user.
*/
diff --git a/fs/xfs/xfs_buf.c b/fs/xfs/xfs_buf.c
index 1626927..eca7bae 100644
--- a/fs/xfs/xfs_buf.c
+++ b/fs/xfs/xfs_buf.c
@@ -116,7 +116,7 @@
__xfs_buf_ioacct_dec(
struct xfs_buf *bp)
{
- ASSERT(spin_is_locked(&bp->b_lock));
+ lockdep_assert_held(&bp->b_lock);
if (bp->b_state & XFS_BSTATE_IN_FLIGHT) {
bp->b_state &= ~XFS_BSTATE_IN_FLIGHT;
@@ -2022,6 +2022,66 @@
return error;
}
+/*
+ * Push a single buffer on a delwri queue.
+ *
+ * The purpose of this function is to submit a single buffer of a delwri queue
+ * and return with the buffer still on the original queue. The waiting delwri
+ * buffer submission infrastructure guarantees transfer of the delwri queue
+ * buffer reference to a temporary wait list. We reuse this infrastructure to
+ * transfer the buffer back to the original queue.
+ *
+ * Note the buffer transitions from the queued state, to the submitted and wait
+ * listed state and back to the queued state during this call. The buffer
+ * locking and queue management logic between _delwri_pushbuf() and
+ * _delwri_queue() guarantee that the buffer cannot be queued to another list
+ * before returning.
+ */
+int
+xfs_buf_delwri_pushbuf(
+ struct xfs_buf *bp,
+ struct list_head *buffer_list)
+{
+ LIST_HEAD (submit_list);
+ int error;
+
+ ASSERT(bp->b_flags & _XBF_DELWRI_Q);
+
+ trace_xfs_buf_delwri_pushbuf(bp, _RET_IP_);
+
+ /*
+ * Isolate the buffer to a new local list so we can submit it for I/O
+ * independently from the rest of the original list.
+ */
+ xfs_buf_lock(bp);
+ list_move(&bp->b_list, &submit_list);
+ xfs_buf_unlock(bp);
+
+ /*
+ * Delwri submission clears the DELWRI_Q buffer flag and returns with
+ * the buffer on the wait list with an associated reference. Rather than
+ * bounce the buffer from a local wait list back to the original list
+ * after I/O completion, reuse the original list as the wait list.
+ */
+ xfs_buf_delwri_submit_buffers(&submit_list, buffer_list);
+
+ /*
+ * The buffer is now under I/O and wait listed as during typical delwri
+ * submission. Lock the buffer to wait for I/O completion. Rather than
+ * remove the buffer from the wait list and release the reference, we
+ * want to return with the buffer queued to the original list. The
+ * buffer already sits on the original list with a wait list reference,
+ * however. If we let the queue inherit that wait list reference, all we
+ * need to do is reset the DELWRI_Q flag.
+ */
+ xfs_buf_lock(bp);
+ error = bp->b_error;
+ bp->b_flags |= _XBF_DELWRI_Q;
+ xfs_buf_unlock(bp);
+
+ return error;
+}
+
int __init
xfs_buf_init(void)
{
diff --git a/fs/xfs/xfs_buf.h b/fs/xfs/xfs_buf.h
index ad514a8..f961b19 100644
--- a/fs/xfs/xfs_buf.h
+++ b/fs/xfs/xfs_buf.h
@@ -333,6 +333,7 @@
extern bool xfs_buf_delwri_queue(struct xfs_buf *, struct list_head *);
extern int xfs_buf_delwri_submit(struct list_head *);
extern int xfs_buf_delwri_submit_nowait(struct list_head *);
+extern int xfs_buf_delwri_pushbuf(struct xfs_buf *, struct list_head *);
/* Buffer Daemon Setup Routines */
extern int xfs_buf_init(void);
diff --git a/fs/xfs/xfs_buf_item.c b/fs/xfs/xfs_buf_item.c
index 0306168..e0a0af0 100644
--- a/fs/xfs/xfs_buf_item.c
+++ b/fs/xfs/xfs_buf_item.c
@@ -29,6 +29,7 @@
#include "xfs_error.h"
#include "xfs_trace.h"
#include "xfs_log.h"
+#include "xfs_inode.h"
kmem_zone_t *xfs_buf_item_zone;
@@ -322,6 +323,8 @@
ASSERT((bip->bli_flags & XFS_BLI_STALE) ||
(xfs_blft_from_flags(&bip->__bli_format) > XFS_BLFT_UNKNOWN_BUF
&& xfs_blft_from_flags(&bip->__bli_format) < XFS_BLFT_MAX_BUF));
+ ASSERT(!(bip->bli_flags & XFS_BLI_ORDERED) ||
+ (bip->bli_flags & XFS_BLI_STALE));
/*
@@ -346,16 +349,6 @@
bip->bli_flags &= ~XFS_BLI_INODE_BUF;
}
- if ((bip->bli_flags & (XFS_BLI_ORDERED|XFS_BLI_STALE)) ==
- XFS_BLI_ORDERED) {
- /*
- * The buffer has been logged just to order it. It is not being
- * included in the transaction commit, so don't format it.
- */
- trace_xfs_buf_item_format_ordered(bip);
- return;
- }
-
for (i = 0; i < bip->bli_format_count; i++) {
xfs_buf_item_format_segment(bip, lv, &vecp, offset,
&bip->bli_formats[i]);
@@ -574,26 +567,20 @@
{
struct xfs_buf_log_item *bip = BUF_ITEM(lip);
struct xfs_buf *bp = bip->bli_buf;
- bool clean;
- bool aborted;
- int flags;
+ bool aborted = !!(lip->li_flags & XFS_LI_ABORTED);
+ bool hold = !!(bip->bli_flags & XFS_BLI_HOLD);
+ bool dirty = !!(bip->bli_flags & XFS_BLI_DIRTY);
+#if defined(DEBUG) || defined(XFS_WARN)
+ bool ordered = !!(bip->bli_flags & XFS_BLI_ORDERED);
+#endif
/* Clear the buffer's association with this transaction. */
bp->b_transp = NULL;
/*
- * If this is a transaction abort, don't return early. Instead, allow
- * the brelse to happen. Normally it would be done for stale
- * (cancelled) buffers at unpin time, but we'll never go through the
- * pin/unpin cycle if we abort inside commit.
+ * The per-transaction state has been copied above so clear it from the
+ * bli.
*/
- aborted = (lip->li_flags & XFS_LI_ABORTED) ? true : false;
- /*
- * Before possibly freeing the buf item, copy the per-transaction state
- * so we can reference it safely later after clearing it from the
- * buffer log item.
- */
- flags = bip->bli_flags;
bip->bli_flags &= ~(XFS_BLI_LOGGED | XFS_BLI_HOLD | XFS_BLI_ORDERED);
/*
@@ -601,7 +588,7 @@
* unlock the buffer and free the buf item when the buffer is unpinned
* for the last time.
*/
- if (flags & XFS_BLI_STALE) {
+ if (bip->bli_flags & XFS_BLI_STALE) {
trace_xfs_buf_item_unlock_stale(bip);
ASSERT(bip->__bli_format.blf_flags & XFS_BLF_CANCEL);
if (!aborted) {
@@ -619,40 +606,34 @@
* regardless of whether it is dirty or not. A dirty abort implies a
* shutdown, anyway.
*
- * Ordered buffers are dirty but may have no recorded changes, so ensure
- * we only release clean items here.
+ * The bli dirty state should match whether the blf has logged segments
+ * except for ordered buffers, where only the bli should be dirty.
*/
- clean = (flags & XFS_BLI_DIRTY) ? false : true;
- if (clean) {
- int i;
- for (i = 0; i < bip->bli_format_count; i++) {
- if (!xfs_bitmap_empty(bip->bli_formats[i].blf_data_map,
- bip->bli_formats[i].blf_map_size)) {
- clean = false;
- break;
- }
- }
- }
+ ASSERT((!ordered && dirty == xfs_buf_item_dirty_format(bip)) ||
+ (ordered && dirty && !xfs_buf_item_dirty_format(bip)));
/*
* Clean buffers, by definition, cannot be in the AIL. However, aborted
- * buffers may be dirty and hence in the AIL. Therefore if we are
- * aborting a buffer and we've just taken the last refernce away, we
- * have to check if it is in the AIL before freeing it. We need to free
- * it in this case, because an aborted transaction has already shut the
- * filesystem down and this is the last chance we will have to do so.
+ * buffers may be in the AIL regardless of dirty state. An aborted
+ * transaction that invalidates a buffer already in the AIL may have
+ * marked it stale and cleared the dirty state, for example.
+ *
+ * Therefore if we are aborting a buffer and we've just taken the last
+ * reference away, we have to check if it is in the AIL before freeing
+ * it. We need to free it in this case, because an aborted transaction
+ * has already shut the filesystem down and this is the last chance we
+ * will have to do so.
*/
if (atomic_dec_and_test(&bip->bli_refcount)) {
- if (clean)
- xfs_buf_item_relse(bp);
- else if (aborted) {
+ if (aborted) {
ASSERT(XFS_FORCED_SHUTDOWN(lip->li_mountp));
xfs_trans_ail_remove(lip, SHUTDOWN_LOG_IO_ERROR);
xfs_buf_item_relse(bp);
- }
+ } else if (!dirty)
+ xfs_buf_item_relse(bp);
}
- if (!(flags & XFS_BLI_HOLD))
+ if (!hold)
xfs_buf_relse(bp);
}
@@ -942,14 +923,22 @@
/*
- * Return 1 if the buffer has been logged or ordered in a transaction (at any
- * point, not just the current transaction) and 0 if not.
+ * Return true if the buffer has any ranges logged/dirtied by a transaction,
+ * false otherwise.
*/
-uint
-xfs_buf_item_dirty(
- xfs_buf_log_item_t *bip)
+bool
+xfs_buf_item_dirty_format(
+ struct xfs_buf_log_item *bip)
{
- return (bip->bli_flags & XFS_BLI_DIRTY);
+ int i;
+
+ for (i = 0; i < bip->bli_format_count; i++) {
+ if (!xfs_bitmap_empty(bip->bli_formats[i].blf_data_map,
+ bip->bli_formats[i].blf_map_size))
+ return true;
+ }
+
+ return false;
}
STATIC void
@@ -1051,6 +1040,31 @@
}
}
+/*
+ * Invoke the error state callback for each log item affected by the failed I/O.
+ *
+ * If a metadata buffer write fails with a non-permanent error, the buffer is
+ * eventually resubmitted and so the completion callbacks are not run. The error
+ * state may need to be propagated to the log items attached to the buffer,
+ * however, so the next AIL push of the item knows hot to handle it correctly.
+ */
+STATIC void
+xfs_buf_do_callbacks_fail(
+ struct xfs_buf *bp)
+{
+ struct xfs_log_item *next;
+ struct xfs_log_item *lip = bp->b_fspriv;
+ struct xfs_ail *ailp = lip->li_ailp;
+
+ spin_lock(&ailp->xa_lock);
+ for (; lip; lip = next) {
+ next = lip->li_bio_list;
+ if (lip->li_ops->iop_error)
+ lip->li_ops->iop_error(lip, bp);
+ }
+ spin_unlock(&ailp->xa_lock);
+}
+
static bool
xfs_buf_iodone_callback_error(
struct xfs_buf *bp)
@@ -1120,7 +1134,11 @@
if ((mp->m_flags & XFS_MOUNT_UNMOUNTING) && mp->m_fail_unmount)
goto permanent_error;
- /* still a transient error, higher layers will retry */
+ /*
+ * Still a transient error, run IO completion failure callbacks and let
+ * the higher layers retry the buffer.
+ */
+ xfs_buf_do_callbacks_fail(bp);
xfs_buf_ioerror(bp, 0);
xfs_buf_relse(bp);
return true;
@@ -1201,3 +1219,31 @@
xfs_trans_ail_delete(ailp, lip, SHUTDOWN_CORRUPT_INCORE);
xfs_buf_item_free(BUF_ITEM(lip));
}
+
+/*
+ * Requeue a failed buffer for writeback
+ *
+ * Return true if the buffer has been re-queued properly, false otherwise
+ */
+bool
+xfs_buf_resubmit_failed_buffers(
+ struct xfs_buf *bp,
+ struct xfs_log_item *lip,
+ struct list_head *buffer_list)
+{
+ struct xfs_log_item *next;
+
+ /*
+ * Clear XFS_LI_FAILED flag from all items before resubmit
+ *
+ * XFS_LI_FAILED set/clear is protected by xa_lock, caller this
+ * function already have it acquired
+ */
+ for (; lip; lip = next) {
+ next = lip->li_bio_list;
+ xfs_clear_li_failed(lip);
+ }
+
+ /* Add this buffer back to the delayed write list */
+ return xfs_buf_delwri_queue(bp, buffer_list);
+}
diff --git a/fs/xfs/xfs_buf_item.h b/fs/xfs/xfs_buf_item.h
index f7eba99..9690ce6 100644
--- a/fs/xfs/xfs_buf_item.h
+++ b/fs/xfs/xfs_buf_item.h
@@ -64,12 +64,15 @@
int xfs_buf_item_init(struct xfs_buf *, struct xfs_mount *);
void xfs_buf_item_relse(struct xfs_buf *);
void xfs_buf_item_log(xfs_buf_log_item_t *, uint, uint);
-uint xfs_buf_item_dirty(xfs_buf_log_item_t *);
+bool xfs_buf_item_dirty_format(struct xfs_buf_log_item *);
void xfs_buf_attach_iodone(struct xfs_buf *,
void(*)(struct xfs_buf *, xfs_log_item_t *),
xfs_log_item_t *);
void xfs_buf_iodone_callbacks(struct xfs_buf *);
void xfs_buf_iodone(struct xfs_buf *, struct xfs_log_item *);
+bool xfs_buf_resubmit_failed_buffers(struct xfs_buf *,
+ struct xfs_log_item *,
+ struct list_head *);
extern kmem_zone_t *xfs_buf_item_zone;
diff --git a/fs/xfs/xfs_file.c b/fs/xfs/xfs_file.c
index df206cf..586b398 100644
--- a/fs/xfs/xfs_file.c
+++ b/fs/xfs/xfs_file.c
@@ -729,6 +729,7 @@
xfs_rw_iunlock(ip, iolock);
eofb.eof_flags = XFS_EOF_FLAGS_SYNC;
xfs_icache_free_eofblocks(ip->i_mount, &eofb);
+ xfs_icache_free_cowblocks(ip->i_mount, &eofb);
goto write_retry;
}
@@ -1139,29 +1140,8 @@
want = min_t(pgoff_t, end - index, PAGEVEC_SIZE - 1) + 1;
nr_pages = pagevec_lookup(&pvec, inode->i_mapping, index,
want);
- /*
- * No page mapped into given range. If we are searching holes
- * and if this is the first time we got into the loop, it means
- * that the given offset is landed in a hole, return it.
- *
- * If we have already stepped through some block buffers to find
- * holes but they all contains data. In this case, the last
- * offset is already updated and pointed to the end of the last
- * mapped page, if it does not reach the endpoint to search,
- * that means there should be a hole between them.
- */
- if (nr_pages == 0) {
- /* Data search found nothing */
- if (type == DATA_OFF)
- break;
-
- ASSERT(type == HOLE_OFF);
- if (lastoff == startoff || lastoff < endoff) {
- found = true;
- *offset = lastoff;
- }
+ if (nr_pages == 0)
break;
- }
for (i = 0; i < nr_pages; i++) {
struct page *page = pvec.pages[i];
@@ -1227,21 +1207,20 @@
/*
* The number of returned pages less than our desired, search
- * done. In this case, nothing was found for searching data,
- * but we found a hole behind the last offset.
+ * done.
*/
- if (nr_pages < want) {
- if (type == HOLE_OFF) {
- *offset = lastoff;
- found = true;
- }
+ if (nr_pages < want)
break;
- }
index = pvec.pages[i - 1]->index + 1;
pagevec_release(&pvec);
} while (index <= end);
+ /* No page at lastoff and we are not done - we found a hole. */
+ if (type == HOLE_OFF && lastoff < endoff) {
+ *offset = lastoff;
+ found = true;
+ }
out:
pagevec_release(&pvec);
return found;
diff --git a/fs/xfs/xfs_icache.c b/fs/xfs/xfs_icache.c
index 74304b6..86a4911 100644
--- a/fs/xfs/xfs_icache.c
+++ b/fs/xfs/xfs_icache.c
@@ -66,7 +66,6 @@
XFS_STATS_INC(mp, vn_active);
ASSERT(atomic_read(&ip->i_pincount) == 0);
- ASSERT(!spin_is_locked(&ip->i_flags_lock));
ASSERT(!xfs_isiflocked(ip));
ASSERT(ip->i_ino == 0);
@@ -192,7 +191,7 @@
{
struct xfs_mount *mp = pag->pag_mount;
- ASSERT(spin_is_locked(&pag->pag_ici_lock));
+ lockdep_assert_held(&pag->pag_ici_lock);
if (pag->pag_ici_reclaimable++)
return;
@@ -214,7 +213,7 @@
{
struct xfs_mount *mp = pag->pag_mount;
- ASSERT(spin_is_locked(&pag->pag_ici_lock));
+ lockdep_assert_held(&pag->pag_ici_lock);
if (--pag->pag_ici_reclaimable)
return;
@@ -1079,11 +1078,11 @@
* Because we use RCU freeing we need to ensure the inode always appears
* to be reclaimed with an invalid inode number when in the free state.
* We do this as early as possible under the ILOCK so that
- * xfs_iflush_cluster() can be guaranteed to detect races with us here.
- * By doing this, we guarantee that once xfs_iflush_cluster has locked
- * XFS_ILOCK that it will see either a valid, flushable inode that will
- * serialise correctly, or it will see a clean (and invalid) inode that
- * it can skip.
+ * xfs_iflush_cluster() and xfs_ifree_cluster() can be guaranteed to
+ * detect races with us here. By doing this, we guarantee that once
+ * xfs_iflush_cluster() or xfs_ifree_cluster() has locked XFS_ILOCK that
+ * it will see either a valid inode that will serialise correctly, or it
+ * will see an invalid inode that it can skip.
*/
spin_lock(&ip->i_flags_lock);
ip->i_flags = XFS_IRECLAIM;
diff --git a/fs/xfs/xfs_inode.c b/fs/xfs/xfs_inode.c
index 7a0b4ee..9e795ab 100644
--- a/fs/xfs/xfs_inode.c
+++ b/fs/xfs/xfs_inode.c
@@ -881,7 +881,6 @@
case S_IFREG:
case S_IFDIR:
if (pip && (pip->i_d.di_flags & XFS_DIFLAG_ANY)) {
- uint64_t di_flags2 = 0;
uint di_flags = 0;
if (S_ISDIR(mode)) {
@@ -918,20 +917,23 @@
di_flags |= XFS_DIFLAG_NODEFRAG;
if (pip->i_d.di_flags & XFS_DIFLAG_FILESTREAM)
di_flags |= XFS_DIFLAG_FILESTREAM;
- if (pip->i_d.di_flags2 & XFS_DIFLAG2_DAX)
- di_flags2 |= XFS_DIFLAG2_DAX;
ip->i_d.di_flags |= di_flags;
- ip->i_d.di_flags2 |= di_flags2;
}
if (pip &&
(pip->i_d.di_flags2 & XFS_DIFLAG2_ANY) &&
pip->i_d.di_version == 3 &&
ip->i_d.di_version == 3) {
+ uint64_t di_flags2 = 0;
+
if (pip->i_d.di_flags2 & XFS_DIFLAG2_COWEXTSIZE) {
- ip->i_d.di_flags2 |= XFS_DIFLAG2_COWEXTSIZE;
+ di_flags2 |= XFS_DIFLAG2_COWEXTSIZE;
ip->i_d.di_cowextsize = pip->i_d.di_cowextsize;
}
+ if (pip->i_d.di_flags2 & XFS_DIFLAG2_DAX)
+ di_flags2 |= XFS_DIFLAG2_DAX;
+
+ ip->i_d.di_flags2 |= di_flags2;
}
/* FALLTHROUGH */
case S_IFLNK:
@@ -2366,11 +2368,24 @@
* already marked stale. If we can't lock it, back off
* and retry.
*/
- if (ip != free_ip &&
- !xfs_ilock_nowait(ip, XFS_ILOCK_EXCL)) {
- rcu_read_unlock();
- delay(1);
- goto retry;
+ if (ip != free_ip) {
+ if (!xfs_ilock_nowait(ip, XFS_ILOCK_EXCL)) {
+ rcu_read_unlock();
+ delay(1);
+ goto retry;
+ }
+
+ /*
+ * Check the inode number again in case we're
+ * racing with freeing in xfs_reclaim_inode().
+ * See the comments in that function for more
+ * information as to why the initial check is
+ * not sufficient.
+ */
+ if (ip->i_ino != inum + i) {
+ xfs_iunlock(ip, XFS_ILOCK_EXCL);
+ continue;
+ }
}
rcu_read_unlock();
diff --git a/fs/xfs/xfs_inode_item.c b/fs/xfs/xfs_inode_item.c
index d90e781..9491574 100644
--- a/fs/xfs/xfs_inode_item.c
+++ b/fs/xfs/xfs_inode_item.c
@@ -27,6 +27,7 @@
#include "xfs_error.h"
#include "xfs_trace.h"
#include "xfs_trans_priv.h"
+#include "xfs_buf_item.h"
#include "xfs_log.h"
@@ -475,6 +476,23 @@
wake_up_bit(&ip->i_flags, __XFS_IPINNED_BIT);
}
+/*
+ * Callback used to mark a buffer with XFS_LI_FAILED when items in the buffer
+ * have been failed during writeback
+ *
+ * This informs the AIL that the inode is already flush locked on the next push,
+ * and acquires a hold on the buffer to ensure that it isn't reclaimed before
+ * dirty data makes it to disk.
+ */
+STATIC void
+xfs_inode_item_error(
+ struct xfs_log_item *lip,
+ struct xfs_buf *bp)
+{
+ ASSERT(xfs_isiflocked(INODE_ITEM(lip)->ili_inode));
+ xfs_set_li_failed(lip, bp);
+}
+
STATIC uint
xfs_inode_item_push(
struct xfs_log_item *lip,
@@ -484,13 +502,28 @@
{
struct xfs_inode_log_item *iip = INODE_ITEM(lip);
struct xfs_inode *ip = iip->ili_inode;
- struct xfs_buf *bp = NULL;
+ struct xfs_buf *bp = lip->li_buf;
uint rval = XFS_ITEM_SUCCESS;
int error;
if (xfs_ipincount(ip) > 0)
return XFS_ITEM_PINNED;
+ /*
+ * The buffer containing this item failed to be written back
+ * previously. Resubmit the buffer for IO.
+ */
+ if (lip->li_flags & XFS_LI_FAILED) {
+ if (!xfs_buf_trylock(bp))
+ return XFS_ITEM_LOCKED;
+
+ if (!xfs_buf_resubmit_failed_buffers(bp, lip, buffer_list))
+ rval = XFS_ITEM_FLUSHING;
+
+ xfs_buf_unlock(bp);
+ return rval;
+ }
+
if (!xfs_ilock_nowait(ip, XFS_ILOCK_SHARED))
return XFS_ITEM_LOCKED;
@@ -622,7 +655,8 @@
.iop_unlock = xfs_inode_item_unlock,
.iop_committed = xfs_inode_item_committed,
.iop_push = xfs_inode_item_push,
- .iop_committing = xfs_inode_item_committing
+ .iop_committing = xfs_inode_item_committing,
+ .iop_error = xfs_inode_item_error
};
@@ -710,7 +744,8 @@
* the AIL lock.
*/
iip = INODE_ITEM(blip);
- if (iip->ili_logged && blip->li_lsn == iip->ili_flush_lsn)
+ if ((iip->ili_logged && blip->li_lsn == iip->ili_flush_lsn) ||
+ lip->li_flags & XFS_LI_FAILED)
need_ail++;
blip = next;
@@ -718,7 +753,8 @@
/* make sure we capture the state of the initial inode. */
iip = INODE_ITEM(lip);
- if (iip->ili_logged && lip->li_lsn == iip->ili_flush_lsn)
+ if ((iip->ili_logged && lip->li_lsn == iip->ili_flush_lsn) ||
+ lip->li_flags & XFS_LI_FAILED)
need_ail++;
/*
@@ -731,22 +767,30 @@
* holding the lock before removing the inode from the AIL.
*/
if (need_ail) {
- struct xfs_log_item *log_items[need_ail];
- int i = 0;
+ bool mlip_changed = false;
+
+ /* this is an opencoded batch version of xfs_trans_ail_delete */
spin_lock(&ailp->xa_lock);
for (blip = lip; blip; blip = blip->li_bio_list) {
- iip = INODE_ITEM(blip);
- if (iip->ili_logged &&
- blip->li_lsn == iip->ili_flush_lsn) {
- log_items[i++] = blip;
+ if (INODE_ITEM(blip)->ili_logged &&
+ blip->li_lsn == INODE_ITEM(blip)->ili_flush_lsn)
+ mlip_changed |= xfs_ail_delete_one(ailp, blip);
+ else {
+ xfs_clear_li_failed(blip);
}
- ASSERT(i <= need_ail);
}
- /* xfs_trans_ail_delete_bulk() drops the AIL lock. */
- xfs_trans_ail_delete_bulk(ailp, log_items, i,
- SHUTDOWN_CORRUPT_INCORE);
- }
+ if (mlip_changed) {
+ if (!XFS_FORCED_SHUTDOWN(ailp->xa_mount))
+ xlog_assign_tail_lsn_locked(ailp->xa_mount);
+ if (list_empty(&ailp->xa_ail))
+ wake_up_all(&ailp->xa_empty);
+ }
+ spin_unlock(&ailp->xa_lock);
+
+ if (mlip_changed)
+ xfs_log_space_wake(ailp->xa_mount);
+ }
/*
* clean up and unlock the flush lock now we are done. We can clear the
diff --git a/fs/xfs/xfs_ioctl.c b/fs/xfs/xfs_ioctl.c
index 73cfc71..bce2e26 100644
--- a/fs/xfs/xfs_ioctl.c
+++ b/fs/xfs/xfs_ioctl.c
@@ -928,16 +928,15 @@
return 0;
}
-STATIC void
-xfs_set_diflags(
+STATIC uint16_t
+xfs_flags2diflags(
struct xfs_inode *ip,
unsigned int xflags)
{
- unsigned int di_flags;
- uint64_t di_flags2;
-
/* can't set PREALLOC this way, just preserve it */
- di_flags = (ip->i_d.di_flags & XFS_DIFLAG_PREALLOC);
+ uint16_t di_flags =
+ (ip->i_d.di_flags & XFS_DIFLAG_PREALLOC);
+
if (xflags & FS_XFLAG_IMMUTABLE)
di_flags |= XFS_DIFLAG_IMMUTABLE;
if (xflags & FS_XFLAG_APPEND)
@@ -967,19 +966,24 @@
if (xflags & FS_XFLAG_EXTSIZE)
di_flags |= XFS_DIFLAG_EXTSIZE;
}
- ip->i_d.di_flags = di_flags;
- /* diflags2 only valid for v3 inodes. */
- if (ip->i_d.di_version < 3)
- return;
+ return di_flags;
+}
- di_flags2 = (ip->i_d.di_flags2 & XFS_DIFLAG2_REFLINK);
+STATIC uint64_t
+xfs_flags2diflags2(
+ struct xfs_inode *ip,
+ unsigned int xflags)
+{
+ uint64_t di_flags2 =
+ (ip->i_d.di_flags2 & XFS_DIFLAG2_REFLINK);
+
if (xflags & FS_XFLAG_DAX)
di_flags2 |= XFS_DIFLAG2_DAX;
if (xflags & FS_XFLAG_COWEXTSIZE)
di_flags2 |= XFS_DIFLAG2_COWEXTSIZE;
- ip->i_d.di_flags2 = di_flags2;
+ return di_flags2;
}
STATIC void
@@ -1005,11 +1009,12 @@
inode->i_flags |= S_NOATIME;
else
inode->i_flags &= ~S_NOATIME;
+#if 0 /* disabled until the flag switching races are sorted out */
if (xflags & FS_XFLAG_DAX)
inode->i_flags |= S_DAX;
else
inode->i_flags &= ~S_DAX;
-
+#endif
}
static int
@@ -1019,6 +1024,7 @@
struct fsxattr *fa)
{
struct xfs_mount *mp = ip->i_mount;
+ uint64_t di_flags2;
/* Can't change realtime flag if any extents are allocated. */
if ((ip->i_d.di_nextents || ip->i_delayed_blks) &&
@@ -1049,7 +1055,14 @@
!capable(CAP_LINUX_IMMUTABLE))
return -EPERM;
- xfs_set_diflags(ip, fa->fsx_xflags);
+ /* diflags2 only valid for v3 inodes. */
+ di_flags2 = xfs_flags2diflags2(ip, fa->fsx_xflags);
+ if (di_flags2 && ip->i_d.di_version < 3)
+ return -EINVAL;
+
+ ip->i_d.di_flags = xfs_flags2diflags(ip, fa->fsx_xflags);
+ ip->i_d.di_flags2 = di_flags2;
+
xfs_diflags_to_linux(ip);
xfs_trans_ichgtime(tp, ip, XFS_ICHGTIME_CHG);
xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE);
diff --git a/fs/xfs/xfs_iops.c b/fs/xfs/xfs_iops.c
index a1247c3..5b81f7f 100644
--- a/fs/xfs/xfs_iops.c
+++ b/fs/xfs/xfs_iops.c
@@ -802,7 +802,7 @@
* Caution: The caller of this function is responsible for calling
* setattr_prepare() or otherwise verifying the change is fine.
*/
-int
+STATIC int
xfs_setattr_size(
struct xfs_inode *ip,
struct iattr *iattr)
diff --git a/fs/xfs/xfs_linux.h b/fs/xfs/xfs_linux.h
index 1455b2520..3ebed16 100644
--- a/fs/xfs/xfs_linux.h
+++ b/fs/xfs/xfs_linux.h
@@ -363,7 +363,14 @@
#endif /* DEBUG */
#ifdef CONFIG_XFS_RT
-#define XFS_IS_REALTIME_INODE(ip) ((ip)->i_d.di_flags & XFS_DIFLAG_REALTIME)
+
+/*
+ * make sure we ignore the inode flag if the filesystem doesn't have a
+ * configured realtime device.
+ */
+#define XFS_IS_REALTIME_INODE(ip) \
+ (((ip)->i_d.di_flags & XFS_DIFLAG_REALTIME) && \
+ (ip)->i_mount->m_rtdev_targp)
#else
#define XFS_IS_REALTIME_INODE(ip) (0)
#endif
diff --git a/fs/xfs/xfs_log.c b/fs/xfs/xfs_log.c
index b57ab34..33c9a3a 100644
--- a/fs/xfs/xfs_log.c
+++ b/fs/xfs/xfs_log.c
@@ -743,15 +743,45 @@
struct xfs_mount *mp)
{
int error = 0;
+ bool readonly = (mp->m_flags & XFS_MOUNT_RDONLY);
if (mp->m_flags & XFS_MOUNT_NORECOVERY) {
ASSERT(mp->m_flags & XFS_MOUNT_RDONLY);
return 0;
+ } else if (readonly) {
+ /* Allow unlinked processing to proceed */
+ mp->m_flags &= ~XFS_MOUNT_RDONLY;
}
+ /*
+ * During the second phase of log recovery, we need iget and
+ * iput to behave like they do for an active filesystem.
+ * xfs_fs_drop_inode needs to be able to prevent the deletion
+ * of inodes before we're done replaying log items on those
+ * inodes. Turn it off immediately after recovery finishes
+ * so that we don't leak the quota inodes if subsequent mount
+ * activities fail.
+ *
+ * We let all inodes involved in redo item processing end up on
+ * the LRU instead of being evicted immediately so that if we do
+ * something to an unlinked inode, the irele won't cause
+ * premature truncation and freeing of the inode, which results
+ * in log recovery failure. We have to evict the unreferenced
+ * lru inodes after clearing MS_ACTIVE because we don't
+ * otherwise clean up the lru if there's a subsequent failure in
+ * xfs_mountfs, which leads to us leaking the inodes if nothing
+ * else (e.g. quotacheck) references the inodes before the
+ * mount failure occurs.
+ */
+ mp->m_super->s_flags |= MS_ACTIVE;
error = xlog_recover_finish(mp->m_log);
if (!error)
xfs_log_work_queue(mp);
+ mp->m_super->s_flags &= ~MS_ACTIVE;
+ evict_inodes(mp->m_super);
+
+ if (readonly)
+ mp->m_flags |= XFS_MOUNT_RDONLY;
return error;
}
@@ -801,11 +831,14 @@
int error;
/*
- * Don't write out unmount record on read-only mounts.
+ * Don't write out unmount record on norecovery mounts or ro devices.
* Or, if we are doing a forced umount (typically because of IO errors).
*/
- if (mp->m_flags & XFS_MOUNT_RDONLY)
+ if (mp->m_flags & XFS_MOUNT_NORECOVERY ||
+ xfs_readonly_buftarg(log->l_mp->m_logdev_targp)) {
+ ASSERT(mp->m_flags & XFS_MOUNT_RDONLY);
return 0;
+ }
error = _xfs_log_force(mp, XFS_LOG_SYNC, NULL);
ASSERT(error || !(XLOG_FORCED_SHUTDOWN(log)));
@@ -3304,8 +3337,6 @@
*/
if (iclog->ic_state & XLOG_STATE_IOERROR)
return -EIO;
- if (log_flushed)
- *log_flushed = 1;
} else {
no_sleep:
@@ -3409,8 +3440,6 @@
xlog_wait(&iclog->ic_prev->ic_write_wait,
&log->l_icloglock);
- if (log_flushed)
- *log_flushed = 1;
already_slept = 1;
goto try_again;
}
@@ -3444,9 +3473,6 @@
*/
if (iclog->ic_state & XLOG_STATE_IOERROR)
return -EIO;
-
- if (log_flushed)
- *log_flushed = 1;
} else { /* just return */
spin_unlock(&log->l_icloglock);
}
diff --git a/fs/xfs/xfs_log_recover.c b/fs/xfs/xfs_log_recover.c
index 9b3d7c7..0590926 100644
--- a/fs/xfs/xfs_log_recover.c
+++ b/fs/xfs/xfs_log_recover.c
@@ -1029,61 +1029,106 @@
}
/*
- * Check the log tail for torn writes. This is required when torn writes are
- * detected at the head and the head had to be walked back to a previous record.
- * The tail of the previous record must now be verified to ensure the torn
- * writes didn't corrupt the previous tail.
+ * Calculate distance from head to tail (i.e., unused space in the log).
+ */
+static inline int
+xlog_tail_distance(
+ struct xlog *log,
+ xfs_daddr_t head_blk,
+ xfs_daddr_t tail_blk)
+{
+ if (head_blk < tail_blk)
+ return tail_blk - head_blk;
+
+ return tail_blk + (log->l_logBBsize - head_blk);
+}
+
+/*
+ * Verify the log tail. This is particularly important when torn or incomplete
+ * writes have been detected near the front of the log and the head has been
+ * walked back accordingly.
*
- * Return an error if CRC verification fails as recovery cannot proceed.
+ * We also have to handle the case where the tail was pinned and the head
+ * blocked behind the tail right before a crash. If the tail had been pushed
+ * immediately prior to the crash and the subsequent checkpoint was only
+ * partially written, it's possible it overwrote the last referenced tail in the
+ * log with garbage. This is not a coherency problem because the tail must have
+ * been pushed before it can be overwritten, but appears as log corruption to
+ * recovery because we have no way to know the tail was updated if the
+ * subsequent checkpoint didn't write successfully.
+ *
+ * Therefore, CRC check the log from tail to head. If a failure occurs and the
+ * offending record is within max iclog bufs from the head, walk the tail
+ * forward and retry until a valid tail is found or corruption is detected out
+ * of the range of a possible overwrite.
*/
STATIC int
xlog_verify_tail(
struct xlog *log,
xfs_daddr_t head_blk,
- xfs_daddr_t tail_blk)
+ xfs_daddr_t *tail_blk,
+ int hsize)
{
struct xlog_rec_header *thead;
struct xfs_buf *bp;
xfs_daddr_t first_bad;
- int count;
int error = 0;
bool wrapped;
- xfs_daddr_t tmp_head;
+ xfs_daddr_t tmp_tail;
+ xfs_daddr_t orig_tail = *tail_blk;
bp = xlog_get_bp(log, 1);
if (!bp)
return -ENOMEM;
/*
- * Seek XLOG_MAX_ICLOGS + 1 records past the current tail record to get
- * a temporary head block that points after the last possible
- * concurrently written record of the tail.
+ * Make sure the tail points to a record (returns positive count on
+ * success).
*/
- count = xlog_seek_logrec_hdr(log, head_blk, tail_blk,
- XLOG_MAX_ICLOGS + 1, bp, &tmp_head, &thead,
- &wrapped);
- if (count < 0) {
- error = count;
+ error = xlog_seek_logrec_hdr(log, head_blk, *tail_blk, 1, bp,
+ &tmp_tail, &thead, &wrapped);
+ if (error < 0)
goto out;
+ if (*tail_blk != tmp_tail)
+ *tail_blk = tmp_tail;
+
+ /*
+ * Run a CRC check from the tail to the head. We can't just check
+ * MAX_ICLOGS records past the tail because the tail may point to stale
+ * blocks cleared during the search for the head/tail. These blocks are
+ * overwritten with zero-length records and thus record count is not a
+ * reliable indicator of the iclog state before a crash.
+ */
+ first_bad = 0;
+ error = xlog_do_recovery_pass(log, head_blk, *tail_blk,
+ XLOG_RECOVER_CRCPASS, &first_bad);
+ while ((error == -EFSBADCRC || error == -EFSCORRUPTED) && first_bad) {
+ int tail_distance;
+
+ /*
+ * Is corruption within range of the head? If so, retry from
+ * the next record. Otherwise return an error.
+ */
+ tail_distance = xlog_tail_distance(log, head_blk, first_bad);
+ if (tail_distance > BTOBB(XLOG_MAX_ICLOGS * hsize))
+ break;
+
+ /* skip to the next record; returns positive count on success */
+ error = xlog_seek_logrec_hdr(log, head_blk, first_bad, 2, bp,
+ &tmp_tail, &thead, &wrapped);
+ if (error < 0)
+ goto out;
+
+ *tail_blk = tmp_tail;
+ first_bad = 0;
+ error = xlog_do_recovery_pass(log, head_blk, *tail_blk,
+ XLOG_RECOVER_CRCPASS, &first_bad);
}
- /*
- * If the call above didn't find XLOG_MAX_ICLOGS + 1 records, we ran
- * into the actual log head. tmp_head points to the start of the record
- * so update it to the actual head block.
- */
- if (count < XLOG_MAX_ICLOGS + 1)
- tmp_head = head_blk;
-
- /*
- * We now have a tail and temporary head block that covers at least
- * XLOG_MAX_ICLOGS records from the tail. We need to verify that these
- * records were completely written. Run a CRC verification pass from
- * tail to head and return the result.
- */
- error = xlog_do_recovery_pass(log, tmp_head, tail_blk,
- XLOG_RECOVER_CRCPASS, &first_bad);
-
+ if (!error && *tail_blk != orig_tail)
+ xfs_warn(log->l_mp,
+ "Tail block (0x%llx) overwrite detected. Updated to 0x%llx",
+ orig_tail, *tail_blk);
out:
xlog_put_bp(bp);
return error;
@@ -1143,7 +1188,7 @@
*/
error = xlog_do_recovery_pass(log, *head_blk, tmp_rhead_blk,
XLOG_RECOVER_CRCPASS, &first_bad);
- if (error == -EFSBADCRC) {
+ if ((error == -EFSBADCRC || error == -EFSCORRUPTED) && first_bad) {
/*
* We've hit a potential torn write. Reset the error and warn
* about it.
@@ -1183,31 +1228,12 @@
ASSERT(0);
return 0;
}
-
- /*
- * Now verify the tail based on the updated head. This is
- * required because the torn writes trimmed from the head could
- * have been written over the tail of a previous record. Return
- * any errors since recovery cannot proceed if the tail is
- * corrupt.
- *
- * XXX: This leaves a gap in truly robust protection from torn
- * writes in the log. If the head is behind the tail, the tail
- * pushes forward to create some space and then a crash occurs
- * causing the writes into the previous record's tail region to
- * tear, log recovery isn't able to recover.
- *
- * How likely is this to occur? If possible, can we do something
- * more intelligent here? Is it safe to push the tail forward if
- * we can determine that the tail is within the range of the
- * torn write (e.g., the kernel can only overwrite the tail if
- * it has actually been pushed forward)? Alternatively, could we
- * somehow prevent this condition at runtime?
- */
- error = xlog_verify_tail(log, *head_blk, *tail_blk);
}
+ if (error)
+ return error;
- return error;
+ return xlog_verify_tail(log, *head_blk, tail_blk,
+ be32_to_cpu((*rhead)->h_size));
}
/*
@@ -4152,7 +4178,7 @@
#define XLOG_RECOVER_COMMIT_QUEUE_MAX 100
- hlist_del(&trans->r_list);
+ hlist_del_init(&trans->r_list);
error = xlog_recover_reorder_trans(log, trans, pass);
if (error)
@@ -4354,6 +4380,8 @@
xlog_recover_item_t *item, *n;
int i;
+ hlist_del_init(&trans->r_list);
+
list_for_each_entry_safe(item, n, &trans->r_itemq, ri_list) {
/* Free the regions in the item. */
list_del(&item->ri_list);
@@ -4799,12 +4827,16 @@
int error = 0;
struct xfs_ail_cursor cur;
struct xfs_ail *ailp;
+#if defined(DEBUG) || defined(XFS_WARN)
xfs_lsn_t last_lsn;
+#endif
ailp = log->l_ailp;
spin_lock(&ailp->xa_lock);
lip = xfs_trans_ail_cursor_first(ailp, &cur, 0);
+#if defined(DEBUG) || defined(XFS_WARN)
last_lsn = xlog_assign_lsn(log->l_curr_cycle, log->l_curr_block);
+#endif
while (lip != NULL) {
/*
* We're done when we see something other than an intent.
@@ -5214,7 +5246,7 @@
xfs_daddr_t *first_bad) /* out: first bad log rec */
{
xlog_rec_header_t *rhead;
- xfs_daddr_t blk_no;
+ xfs_daddr_t blk_no, rblk_no;
xfs_daddr_t rhead_blk;
char *offset;
xfs_buf_t *hbp, *dbp;
@@ -5222,11 +5254,15 @@
int error2 = 0;
int bblks, split_bblks;
int hblks, split_hblks, wrapped_hblks;
+ int i;
struct hlist_head rhash[XLOG_RHASH_SIZE];
LIST_HEAD (buffer_list);
ASSERT(head_blk != tail_blk);
- rhead_blk = 0;
+ blk_no = rhead_blk = tail_blk;
+
+ for (i = 0; i < XLOG_RHASH_SIZE; i++)
+ INIT_HLIST_HEAD(&rhash[i]);
/*
* Read the header of the tail block and get the iclog buffer size from
@@ -5301,7 +5337,6 @@
}
memset(rhash, 0, sizeof(rhash));
- blk_no = rhead_blk = tail_blk;
if (tail_blk > head_blk) {
/*
* Perform recovery around the end of the physical log.
@@ -5363,9 +5398,19 @@
bblks = (int)BTOBB(be32_to_cpu(rhead->h_len));
blk_no += hblks;
- /* Read in data for log record */
- if (blk_no + bblks <= log->l_logBBsize) {
- error = xlog_bread(log, blk_no, bblks, dbp,
+ /*
+ * Read the log record data in multiple reads if it
+ * wraps around the end of the log. Note that if the
+ * header already wrapped, blk_no could point past the
+ * end of the log. The record data is contiguous in
+ * that case.
+ */
+ if (blk_no + bblks <= log->l_logBBsize ||
+ blk_no >= log->l_logBBsize) {
+ /* mod blk_no in case the header wrapped and
+ * pushed it beyond the end of the log */
+ rblk_no = do_mod(blk_no, log->l_logBBsize);
+ error = xlog_bread(log, rblk_no, bblks, dbp,
&offset);
if (error)
goto bread_err2;
@@ -5464,6 +5509,19 @@
if (error && first_bad)
*first_bad = rhead_blk;
+ /*
+ * Transactions are freed at commit time but transactions without commit
+ * records on disk are never committed. Free any that may be left in the
+ * hash table.
+ */
+ for (i = 0; i < XLOG_RHASH_SIZE; i++) {
+ struct hlist_node *tmp;
+ struct xlog_recover *trans;
+
+ hlist_for_each_entry_safe(trans, tmp, &rhash[i], r_list)
+ xlog_recover_free_trans(trans);
+ }
+
return error ? error : error2;
}
@@ -5542,6 +5600,8 @@
xfs_buf_t *bp;
xfs_sb_t *sbp;
+ trace_xfs_log_recover(log, head_blk, tail_blk);
+
/*
* First replay the images in the log.
*/
diff --git a/fs/xfs/xfs_mount.c b/fs/xfs/xfs_mount.c
index 13796f2..d4ce8d2 100644
--- a/fs/xfs/xfs_mount.c
+++ b/fs/xfs/xfs_mount.c
@@ -925,15 +925,6 @@
}
/*
- * During the second phase of log recovery, we need iget and
- * iput to behave like they do for an active filesystem.
- * xfs_fs_drop_inode needs to be able to prevent the deletion
- * of inodes before we're done replaying log items on those
- * inodes.
- */
- mp->m_super->s_flags |= MS_ACTIVE;
-
- /*
* Finish recovering the file system. This part needed to be delayed
* until after the root and real-time bitmap inodes were consistently
* read in.
@@ -1008,12 +999,13 @@
out_quota:
xfs_qm_unmount_quotas(mp);
out_rtunmount:
- mp->m_super->s_flags &= ~MS_ACTIVE;
xfs_rtunmount_inodes(mp);
out_rele_rip:
IRELE(rip);
cancel_delayed_work_sync(&mp->m_reclaim_work);
xfs_reclaim_inodes(mp, SYNC_WAIT);
+ /* Clean out dquots that might be in memory after quotacheck. */
+ xfs_qm_unmount(mp);
out_log_dealloc:
mp->m_flags |= XFS_MOUNT_UNMOUNTING;
xfs_log_mount_cancel(mp);
diff --git a/fs/xfs/xfs_qm.c b/fs/xfs/xfs_qm.c
index 8b9a9f1..1fdd3fa 100644
--- a/fs/xfs/xfs_qm.c
+++ b/fs/xfs/xfs_qm.c
@@ -111,6 +111,9 @@
skipped = 0;
break;
}
+ /* we're done if id overflows back to zero */
+ if (!next_index)
+ break;
}
if (skipped) {
@@ -1247,6 +1250,7 @@
struct xfs_dquot *dqp,
void *data)
{
+ struct xfs_mount *mp = dqp->q_mount;
struct list_head *buffer_list = data;
struct xfs_buf *bp = NULL;
int error = 0;
@@ -1257,7 +1261,32 @@
if (!XFS_DQ_IS_DIRTY(dqp))
goto out_unlock;
- xfs_dqflock(dqp);
+ /*
+ * The only way the dquot is already flush locked by the time quotacheck
+ * gets here is if reclaim flushed it before the dqadjust walk dirtied
+ * it for the final time. Quotacheck collects all dquot bufs in the
+ * local delwri queue before dquots are dirtied, so reclaim can't have
+ * possibly queued it for I/O. The only way out is to push the buffer to
+ * cycle the flush lock.
+ */
+ if (!xfs_dqflock_nowait(dqp)) {
+ /* buf is pinned in-core by delwri list */
+ DEFINE_SINGLE_BUF_MAP(map, dqp->q_blkno,
+ mp->m_quotainfo->qi_dqchunklen);
+ bp = _xfs_buf_find(mp->m_ddev_targp, &map, 1, 0, NULL);
+ if (!bp) {
+ error = -EINVAL;
+ goto out_unlock;
+ }
+ xfs_buf_unlock(bp);
+
+ xfs_buf_delwri_pushbuf(bp, buffer_list);
+ xfs_buf_rele(bp);
+
+ error = -EAGAIN;
+ goto out_unlock;
+ }
+
error = xfs_qm_dqflush(dqp, &bp);
if (error)
goto out_unlock;
diff --git a/fs/xfs/xfs_reflink.c b/fs/xfs/xfs_reflink.c
index 29a75ec..0015c19 100644
--- a/fs/xfs/xfs_reflink.c
+++ b/fs/xfs/xfs_reflink.c
@@ -169,6 +169,8 @@
error = xfs_alloc_read_agf(mp, NULL, agno, 0, &agbp);
if (error)
return error;
+ if (!agbp)
+ return -ENOMEM;
cur = xfs_refcountbt_init_cursor(mp, NULL, agbp, agno, NULL);
@@ -333,7 +335,7 @@
struct xfs_defer_ops *dfops)
{
struct xfs_bmbt_irec irec = *imap;
- xfs_fsblock_t first_block;
+ xfs_fsblock_t first_block = NULLFSBLOCK;
int nimaps = 1;
if (imap->br_state == XFS_EXT_NORM)
diff --git a/fs/xfs/xfs_super.c b/fs/xfs/xfs_super.c
index 882fb85..67d589e 100644
--- a/fs/xfs/xfs_super.c
+++ b/fs/xfs/xfs_super.c
@@ -1214,7 +1214,7 @@
tmp_mp->m_super = sb;
error = xfs_parseargs(tmp_mp, options);
xfs_free_fsname(tmp_mp);
- kfree(tmp_mp);
+ kmem_free(tmp_mp);
return error;
}
diff --git a/fs/xfs/xfs_trace.h b/fs/xfs/xfs_trace.h
index 828f383..bdf69e1 100644
--- a/fs/xfs/xfs_trace.h
+++ b/fs/xfs/xfs_trace.h
@@ -366,6 +366,7 @@
DEFINE_BUF_EVENT(xfs_buf_delwri_queue);
DEFINE_BUF_EVENT(xfs_buf_delwri_queued);
DEFINE_BUF_EVENT(xfs_buf_delwri_split);
+DEFINE_BUF_EVENT(xfs_buf_delwri_pushbuf);
DEFINE_BUF_EVENT(xfs_buf_get_uncached);
DEFINE_BUF_EVENT(xfs_bdstrat_shut);
DEFINE_BUF_EVENT(xfs_buf_item_relse);
@@ -519,7 +520,6 @@
DEFINE_BUF_ITEM_EVENT(xfs_buf_item_size_ordered);
DEFINE_BUF_ITEM_EVENT(xfs_buf_item_size_stale);
DEFINE_BUF_ITEM_EVENT(xfs_buf_item_format);
-DEFINE_BUF_ITEM_EVENT(xfs_buf_item_format_ordered);
DEFINE_BUF_ITEM_EVENT(xfs_buf_item_format_stale);
DEFINE_BUF_ITEM_EVENT(xfs_buf_item_ordered);
DEFINE_BUF_ITEM_EVENT(xfs_buf_item_pin);
@@ -1990,6 +1990,24 @@
DEFINE_SWAPEXT_EVENT(xfs_swap_extent_before);
DEFINE_SWAPEXT_EVENT(xfs_swap_extent_after);
+TRACE_EVENT(xfs_log_recover,
+ TP_PROTO(struct xlog *log, xfs_daddr_t headblk, xfs_daddr_t tailblk),
+ TP_ARGS(log, headblk, tailblk),
+ TP_STRUCT__entry(
+ __field(dev_t, dev)
+ __field(xfs_daddr_t, headblk)
+ __field(xfs_daddr_t, tailblk)
+ ),
+ TP_fast_assign(
+ __entry->dev = log->l_mp->m_super->s_dev;
+ __entry->headblk = headblk;
+ __entry->tailblk = tailblk;
+ ),
+ TP_printk("dev %d:%d headblk 0x%llx tailblk 0x%llx",
+ MAJOR(__entry->dev), MINOR(__entry->dev), __entry->headblk,
+ __entry->tailblk)
+)
+
TRACE_EVENT(xfs_log_recover_record,
TP_PROTO(struct xlog *log, struct xlog_rec_header *rhead, int pass),
TP_ARGS(log, rhead, pass),
diff --git a/fs/xfs/xfs_trans.h b/fs/xfs/xfs_trans.h
index 98024cb..5669cf0 100644
--- a/fs/xfs/xfs_trans.h
+++ b/fs/xfs/xfs_trans.h
@@ -50,6 +50,7 @@
struct xfs_ail *li_ailp; /* ptr to AIL */
uint li_type; /* item type */
uint li_flags; /* misc flags */
+ struct xfs_buf *li_buf; /* real buffer pointer */
struct xfs_log_item *li_bio_list; /* buffer item list */
void (*li_cb)(struct xfs_buf *,
struct xfs_log_item *);
@@ -65,11 +66,13 @@
} xfs_log_item_t;
#define XFS_LI_IN_AIL 0x1
-#define XFS_LI_ABORTED 0x2
+#define XFS_LI_ABORTED 0x2
+#define XFS_LI_FAILED 0x4
#define XFS_LI_FLAGS \
{ XFS_LI_IN_AIL, "IN_AIL" }, \
- { XFS_LI_ABORTED, "ABORTED" }
+ { XFS_LI_ABORTED, "ABORTED" }, \
+ { XFS_LI_FAILED, "FAILED" }
struct xfs_item_ops {
void (*iop_size)(xfs_log_item_t *, int *, int *);
@@ -80,6 +83,7 @@
void (*iop_unlock)(xfs_log_item_t *);
xfs_lsn_t (*iop_committed)(xfs_log_item_t *, xfs_lsn_t);
void (*iop_committing)(xfs_log_item_t *, xfs_lsn_t);
+ void (*iop_error)(xfs_log_item_t *, xfs_buf_t *);
};
void xfs_log_item_init(struct xfs_mount *mp, struct xfs_log_item *item,
@@ -213,12 +217,14 @@
void xfs_trans_binval(xfs_trans_t *, struct xfs_buf *);
void xfs_trans_inode_buf(xfs_trans_t *, struct xfs_buf *);
void xfs_trans_stale_inode_buf(xfs_trans_t *, struct xfs_buf *);
-void xfs_trans_ordered_buf(xfs_trans_t *, struct xfs_buf *);
+bool xfs_trans_ordered_buf(xfs_trans_t *, struct xfs_buf *);
void xfs_trans_dquot_buf(xfs_trans_t *, struct xfs_buf *, uint);
void xfs_trans_inode_alloc_buf(xfs_trans_t *, struct xfs_buf *);
void xfs_trans_ichgtime(struct xfs_trans *, struct xfs_inode *, int);
void xfs_trans_ijoin(struct xfs_trans *, struct xfs_inode *, uint);
-void xfs_trans_log_buf(xfs_trans_t *, struct xfs_buf *, uint, uint);
+void xfs_trans_log_buf(struct xfs_trans *, struct xfs_buf *, uint,
+ uint);
+void xfs_trans_dirty_buf(struct xfs_trans *, struct xfs_buf *);
void xfs_trans_log_inode(xfs_trans_t *, struct xfs_inode *, uint);
void xfs_extent_free_init_defer_op(void);
@@ -277,6 +283,6 @@
struct xfs_bud_log_item *rudp, struct xfs_defer_ops *dfops,
enum xfs_bmap_intent_type type, struct xfs_inode *ip,
int whichfork, xfs_fileoff_t startoff, xfs_fsblock_t startblock,
- xfs_filblks_t blockcount, xfs_exntst_t state);
+ xfs_filblks_t *blockcount, xfs_exntst_t state);
#endif /* __XFS_TRANS_H__ */
diff --git a/fs/xfs/xfs_trans_ail.c b/fs/xfs/xfs_trans_ail.c
index d6c9c3e..70f5ab0 100644
--- a/fs/xfs/xfs_trans_ail.c
+++ b/fs/xfs/xfs_trans_ail.c
@@ -684,8 +684,24 @@
}
}
-/*
- * xfs_trans_ail_delete_bulk - remove multiple log items from the AIL
+bool
+xfs_ail_delete_one(
+ struct xfs_ail *ailp,
+ struct xfs_log_item *lip)
+{
+ struct xfs_log_item *mlip = xfs_ail_min(ailp);
+
+ trace_xfs_ail_delete(lip, mlip->li_lsn, lip->li_lsn);
+ xfs_ail_delete(ailp, lip);
+ xfs_clear_li_failed(lip);
+ lip->li_flags &= ~XFS_LI_IN_AIL;
+ lip->li_lsn = 0;
+
+ return mlip == lip;
+}
+
+/**
+ * Remove a log items from the AIL
*
* @xfs_trans_ail_delete_bulk takes an array of log items that all need to
* removed from the AIL. The caller is already holding the AIL lock, and done
@@ -706,52 +722,36 @@
* before returning.
*/
void
-xfs_trans_ail_delete_bulk(
+xfs_trans_ail_delete(
struct xfs_ail *ailp,
- struct xfs_log_item **log_items,
- int nr_items,
+ struct xfs_log_item *lip,
int shutdown_type) __releases(ailp->xa_lock)
{
- xfs_log_item_t *mlip;
- int mlip_changed = 0;
- int i;
+ struct xfs_mount *mp = ailp->xa_mount;
+ bool mlip_changed;
- mlip = xfs_ail_min(ailp);
-
- for (i = 0; i < nr_items; i++) {
- struct xfs_log_item *lip = log_items[i];
- if (!(lip->li_flags & XFS_LI_IN_AIL)) {
- struct xfs_mount *mp = ailp->xa_mount;
-
- spin_unlock(&ailp->xa_lock);
- if (!XFS_FORCED_SHUTDOWN(mp)) {
- xfs_alert_tag(mp, XFS_PTAG_AILDELETE,
- "%s: attempting to delete a log item that is not in the AIL",
- __func__);
- xfs_force_shutdown(mp, shutdown_type);
- }
- return;
+ if (!(lip->li_flags & XFS_LI_IN_AIL)) {
+ spin_unlock(&ailp->xa_lock);
+ if (!XFS_FORCED_SHUTDOWN(mp)) {
+ xfs_alert_tag(mp, XFS_PTAG_AILDELETE,
+ "%s: attempting to delete a log item that is not in the AIL",
+ __func__);
+ xfs_force_shutdown(mp, shutdown_type);
}
-
- trace_xfs_ail_delete(lip, mlip->li_lsn, lip->li_lsn);
- xfs_ail_delete(ailp, lip);
- lip->li_flags &= ~XFS_LI_IN_AIL;
- lip->li_lsn = 0;
- if (mlip == lip)
- mlip_changed = 1;
+ return;
}
+ mlip_changed = xfs_ail_delete_one(ailp, lip);
if (mlip_changed) {
- if (!XFS_FORCED_SHUTDOWN(ailp->xa_mount))
- xlog_assign_tail_lsn_locked(ailp->xa_mount);
+ if (!XFS_FORCED_SHUTDOWN(mp))
+ xlog_assign_tail_lsn_locked(mp);
if (list_empty(&ailp->xa_ail))
wake_up_all(&ailp->xa_empty);
- spin_unlock(&ailp->xa_lock);
-
- xfs_log_space_wake(ailp->xa_mount);
- } else {
- spin_unlock(&ailp->xa_lock);
}
+
+ spin_unlock(&ailp->xa_lock);
+ if (mlip_changed)
+ xfs_log_space_wake(ailp->xa_mount);
}
int
diff --git a/fs/xfs/xfs_trans_bmap.c b/fs/xfs/xfs_trans_bmap.c
index 6408e7d..14543d9 100644
--- a/fs/xfs/xfs_trans_bmap.c
+++ b/fs/xfs/xfs_trans_bmap.c
@@ -63,7 +63,7 @@
int whichfork,
xfs_fileoff_t startoff,
xfs_fsblock_t startblock,
- xfs_filblks_t blockcount,
+ xfs_filblks_t *blockcount,
xfs_exntst_t state)
{
int error;
@@ -196,16 +196,23 @@
void **state)
{
struct xfs_bmap_intent *bmap;
+ xfs_filblks_t count;
int error;
bmap = container_of(item, struct xfs_bmap_intent, bi_list);
+ count = bmap->bi_bmap.br_blockcount;
error = xfs_trans_log_finish_bmap_update(tp, done_item, dop,
bmap->bi_type,
bmap->bi_owner, bmap->bi_whichfork,
bmap->bi_bmap.br_startoff,
bmap->bi_bmap.br_startblock,
- bmap->bi_bmap.br_blockcount,
+ &count,
bmap->bi_bmap.br_state);
+ if (!error && count > 0) {
+ ASSERT(bmap->bi_type == XFS_BMAP_UNMAP);
+ bmap->bi_bmap.br_blockcount = count;
+ return -EAGAIN;
+ }
kmem_free(bmap);
return error;
}
diff --git a/fs/xfs/xfs_trans_buf.c b/fs/xfs/xfs_trans_buf.c
index 8ee29ca..3ba7a96 100644
--- a/fs/xfs/xfs_trans_buf.c
+++ b/fs/xfs/xfs_trans_buf.c
@@ -356,6 +356,7 @@
xfs_buf_t *bp)
{
xfs_buf_log_item_t *bip;
+ int freed;
/*
* Default to a normal brelse() call if the tp is NULL.
@@ -419,16 +420,22 @@
/*
* Drop our reference to the buf log item.
*/
- atomic_dec(&bip->bli_refcount);
+ freed = atomic_dec_and_test(&bip->bli_refcount);
/*
- * If the buf item is not tracking data in the log, then
- * we must free it before releasing the buffer back to the
- * free pool. Before releasing the buffer to the free pool,
- * clear the transaction pointer in b_fsprivate2 to dissolve
- * its relation to this transaction.
+ * If the buf item is not tracking data in the log, then we must free it
+ * before releasing the buffer back to the free pool.
+ *
+ * If the fs has shutdown and we dropped the last reference, it may fall
+ * on us to release a (possibly dirty) bli if it never made it to the
+ * AIL (e.g., the aborted unpin already happened and didn't release it
+ * due to our reference). Since we're already shutdown and need xa_lock,
+ * just force remove from the AIL and release the bli here.
*/
- if (!xfs_buf_item_dirty(bip)) {
+ if (XFS_FORCED_SHUTDOWN(tp->t_mountp) && freed) {
+ xfs_trans_ail_remove(&bip->bli_item, SHUTDOWN_LOG_IO_ERROR);
+ xfs_buf_item_relse(bp);
+ } else if (!(bip->bli_flags & XFS_BLI_DIRTY)) {
/***
ASSERT(bp->b_pincount == 0);
***/
@@ -486,25 +493,17 @@
}
/*
- * This is called to mark bytes first through last inclusive of the given
- * buffer as needing to be logged when the transaction is committed.
- * The buffer must already be associated with the given transaction.
- *
- * First and last are numbers relative to the beginning of this buffer,
- * so the first byte in the buffer is numbered 0 regardless of the
- * value of b_blkno.
+ * Mark a buffer dirty in the transaction.
*/
void
-xfs_trans_log_buf(xfs_trans_t *tp,
- xfs_buf_t *bp,
- uint first,
- uint last)
+xfs_trans_dirty_buf(
+ struct xfs_trans *tp,
+ struct xfs_buf *bp)
{
- xfs_buf_log_item_t *bip = bp->b_fspriv;
+ struct xfs_buf_log_item *bip = bp->b_fspriv;
ASSERT(bp->b_transp == tp);
ASSERT(bip != NULL);
- ASSERT(first <= last && last < BBTOB(bp->b_length));
ASSERT(bp->b_iodone == NULL ||
bp->b_iodone == xfs_buf_iodone_callbacks);
@@ -524,8 +523,6 @@
bp->b_iodone = xfs_buf_iodone_callbacks;
bip->bli_item.li_cb = xfs_buf_iodone;
- trace_xfs_trans_log_buf(bip);
-
/*
* If we invalidated the buffer within this transaction, then
* cancel the invalidation now that we're dirtying the buffer
@@ -538,17 +535,37 @@
bp->b_flags &= ~XBF_STALE;
bip->__bli_format.blf_flags &= ~XFS_BLF_CANCEL;
}
+ bip->bli_flags |= XFS_BLI_DIRTY | XFS_BLI_LOGGED;
tp->t_flags |= XFS_TRANS_DIRTY;
bip->bli_item.li_desc->lid_flags |= XFS_LID_DIRTY;
+}
- /*
- * If we have an ordered buffer we are not logging any dirty range but
- * it still needs to be marked dirty and that it has been logged.
- */
- bip->bli_flags |= XFS_BLI_DIRTY | XFS_BLI_LOGGED;
- if (!(bip->bli_flags & XFS_BLI_ORDERED))
- xfs_buf_item_log(bip, first, last);
+/*
+ * This is called to mark bytes first through last inclusive of the given
+ * buffer as needing to be logged when the transaction is committed.
+ * The buffer must already be associated with the given transaction.
+ *
+ * First and last are numbers relative to the beginning of this buffer,
+ * so the first byte in the buffer is numbered 0 regardless of the
+ * value of b_blkno.
+ */
+void
+xfs_trans_log_buf(
+ struct xfs_trans *tp,
+ struct xfs_buf *bp,
+ uint first,
+ uint last)
+{
+ struct xfs_buf_log_item *bip = bp->b_fspriv;
+
+ ASSERT(first <= last && last < BBTOB(bp->b_length));
+ ASSERT(!(bip->bli_flags & XFS_BLI_ORDERED));
+
+ xfs_trans_dirty_buf(tp, bp);
+
+ trace_xfs_trans_log_buf(bip);
+ xfs_buf_item_log(bip, first, last);
}
@@ -701,14 +718,13 @@
}
/*
- * Mark the buffer as ordered for this transaction. This means
- * that the contents of the buffer are not recorded in the transaction
- * but it is tracked in the AIL as though it was. This allows us
- * to record logical changes in transactions rather than the physical
- * changes we make to the buffer without changing writeback ordering
- * constraints of metadata buffers.
+ * Mark the buffer as ordered for this transaction. This means that the contents
+ * of the buffer are not recorded in the transaction but it is tracked in the
+ * AIL as though it was. This allows us to record logical changes in
+ * transactions rather than the physical changes we make to the buffer without
+ * changing writeback ordering constraints of metadata buffers.
*/
-void
+bool
xfs_trans_ordered_buf(
struct xfs_trans *tp,
struct xfs_buf *bp)
@@ -719,8 +735,18 @@
ASSERT(bip != NULL);
ASSERT(atomic_read(&bip->bli_refcount) > 0);
+ if (xfs_buf_item_dirty_format(bip))
+ return false;
+
bip->bli_flags |= XFS_BLI_ORDERED;
trace_xfs_buf_item_ordered(bip);
+
+ /*
+ * We don't log a dirty range of an ordered buffer but it still needs
+ * to be marked dirty and that it has been logged.
+ */
+ xfs_trans_dirty_buf(tp, bp);
+ return true;
}
/*
diff --git a/fs/xfs/xfs_trans_priv.h b/fs/xfs/xfs_trans_priv.h
index 49931b7..b317a36 100644
--- a/fs/xfs/xfs_trans_priv.h
+++ b/fs/xfs/xfs_trans_priv.h
@@ -106,18 +106,9 @@
xfs_trans_ail_update_bulk(ailp, NULL, &lip, 1, lsn);
}
-void xfs_trans_ail_delete_bulk(struct xfs_ail *ailp,
- struct xfs_log_item **log_items, int nr_items,
- int shutdown_type)
- __releases(ailp->xa_lock);
-static inline void
-xfs_trans_ail_delete(
- struct xfs_ail *ailp,
- xfs_log_item_t *lip,
- int shutdown_type) __releases(ailp->xa_lock)
-{
- xfs_trans_ail_delete_bulk(ailp, &lip, 1, shutdown_type);
-}
+bool xfs_ail_delete_one(struct xfs_ail *ailp, struct xfs_log_item *lip);
+void xfs_trans_ail_delete(struct xfs_ail *ailp, struct xfs_log_item *lip,
+ int shutdown_type) __releases(ailp->xa_lock);
static inline void
xfs_trans_ail_remove(
@@ -173,4 +164,35 @@
*dst = *src;
}
#endif
+
+static inline void
+xfs_clear_li_failed(
+ struct xfs_log_item *lip)
+{
+ struct xfs_buf *bp = lip->li_buf;
+
+ ASSERT(lip->li_flags & XFS_LI_IN_AIL);
+ lockdep_assert_held(&lip->li_ailp->xa_lock);
+
+ if (lip->li_flags & XFS_LI_FAILED) {
+ lip->li_flags &= ~XFS_LI_FAILED;
+ lip->li_buf = NULL;
+ xfs_buf_rele(bp);
+ }
+}
+
+static inline void
+xfs_set_li_failed(
+ struct xfs_log_item *lip,
+ struct xfs_buf *bp)
+{
+ lockdep_assert_held(&lip->li_ailp->xa_lock);
+
+ if (!(lip->li_flags & XFS_LI_FAILED)) {
+ xfs_buf_hold(bp);
+ lip->li_flags |= XFS_LI_FAILED;
+ lip->li_buf = bp;
+ }
+}
+
#endif /* __XFS_TRANS_PRIV_H__ */
diff --git a/include/dt-bindings/msm/msm-bus-ids.h b/include/dt-bindings/msm/msm-bus-ids.h
index bc87beb..e20175d 100644
--- a/include/dt-bindings/msm/msm-bus-ids.h
+++ b/include/dt-bindings/msm/msm-bus-ids.h
@@ -251,7 +251,8 @@
#define MSM_BUS_MASTER_CAMNOC_HF1_UNCOMP 147
#define MSM_BUS_MASTER_CAMNOC_SF_UNCOMP 148
#define MSM_BUS_MASTER_GIC 149
-#define MSM_BUS_MASTER_MASTER_LAST 150
+#define MSM_BUS_MASTER_EMMC 150
+#define MSM_BUS_MASTER_MASTER_LAST 151
#define MSM_BUS_MASTER_LLCC_DISPLAY 20000
#define MSM_BUS_MASTER_MNOC_HF_MEM_NOC_DISPLAY 20001
@@ -767,6 +768,7 @@
#define ICBID_MASTER_CNOC_A2NOC 146
#define ICBID_MASTER_WLAN 147
#define ICBID_MASTER_MSS_CE 148
+#define ICBID_MASTER_EMMC 149
#define ICBID_SLAVE_EBI1 0
#define ICBID_SLAVE_APPSS_L2 1
diff --git a/include/linux/fs.h b/include/linux/fs.h
index 6d6114a..18bd249 100644
--- a/include/linux/fs.h
+++ b/include/linux/fs.h
@@ -2782,6 +2782,7 @@
#endif
extern void unlock_new_inode(struct inode *);
extern unsigned int get_next_ino(void);
+extern void evict_inodes(struct super_block *sb);
extern void __iget(struct inode * inode);
extern void iget_failed(struct inode *);
diff --git a/include/linux/irqchip/arm-gic-v3.h b/include/linux/irqchip/arm-gic-v3.h
index b7e3431..c122409 100644
--- a/include/linux/irqchip/arm-gic-v3.h
+++ b/include/linux/irqchip/arm-gic-v3.h
@@ -450,6 +450,8 @@
return !!(val & ICC_SRE_EL1_SRE);
}
+void gic_show_pending_irqs(void);
+unsigned int get_gic_highpri_irq(void);
#endif
#endif
diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h
index d92d9a6..266471e 100644
--- a/include/linux/netdevice.h
+++ b/include/linux/netdevice.h
@@ -3905,6 +3905,8 @@
updev; \
updev = netdev_all_upper_get_next_dev_rcu(dev, &(iter)))
+bool netdev_has_any_upper_dev(struct net_device *dev);
+
void *netdev_lower_get_next_private(struct net_device *dev,
struct list_head **iter);
void *netdev_lower_get_next_private_rcu(struct net_device *dev,
diff --git a/include/linux/pci_ids.h b/include/linux/pci_ids.h
index 3e5dbbe..4308204 100644
--- a/include/linux/pci_ids.h
+++ b/include/linux/pci_ids.h
@@ -574,6 +574,7 @@
#define PCI_DEVICE_ID_AMD_CS5536_EHC 0x2095
#define PCI_DEVICE_ID_AMD_CS5536_UDC 0x2096
#define PCI_DEVICE_ID_AMD_CS5536_UOC 0x2097
+#define PCI_DEVICE_ID_AMD_CS5536_DEV_IDE 0x2092
#define PCI_DEVICE_ID_AMD_CS5536_IDE 0x209A
#define PCI_DEVICE_ID_AMD_LX_VIDEO 0x2081
#define PCI_DEVICE_ID_AMD_LX_AES 0x2082
diff --git a/include/linux/qcom-geni-se.h b/include/linux/qcom-geni-se.h
index 463785d..77a46bd 100644
--- a/include/linux/qcom-geni-se.h
+++ b/include/linux/qcom-geni-se.h
@@ -924,7 +924,7 @@
return -ENXIO;
}
-void geni_se_dump_dbg_regs(struct se_geni_rsc *rsc, void __iomem *base,
+static void geni_se_dump_dbg_regs(struct se_geni_rsc *rsc, void __iomem *base,
void *ipc)
{
}
diff --git a/include/linux/sched.h b/include/linux/sched.h
index e5541af..67860f3 100644
--- a/include/linux/sched.h
+++ b/include/linux/sched.h
@@ -3960,6 +3960,7 @@
#define SCHED_CPUFREQ_INTERCLUSTER_MIG (1U << 3)
#define SCHED_CPUFREQ_WALT (1U << 4)
#define SCHED_CPUFREQ_PL (1U << 5)
+#define SCHED_CPUFREQ_EARLY_DET (1U << 6)
#define SCHED_CPUFREQ_RT_DL (SCHED_CPUFREQ_RT | SCHED_CPUFREQ_DL)
diff --git a/include/linux/spi/spi-geni-qcom.h b/include/linux/spi/spi-geni-qcom.h
new file mode 100644
index 0000000..8aee88a
--- /dev/null
+++ b/include/linux/spi/spi-geni-qcom.h
@@ -0,0 +1,23 @@
+/*
+ * Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#ifndef __SPI_GENI_QCOM_HEADER___
+#define __SPI_GENI_QCOM_HEADER___
+
+struct spi_geni_qcom_ctrl_data {
+ u32 spi_cs_clk_delay;
+ u32 spi_inter_words_delay;
+};
+
+#endif /*__SPI_GENI_QCOM_HEADER___*/
diff --git a/include/linux/sync_file.h b/include/linux/sync_file.h
index aa17ccf..c97fac8 100644
--- a/include/linux/sync_file.h
+++ b/include/linux/sync_file.h
@@ -43,9 +43,10 @@
struct fence *fence;
struct fence_cb cb;
+ unsigned long flags;
};
-#define POLL_ENABLED FENCE_FLAG_USER_BITS
+#define POLL_ENABLED 0
struct sync_file *sync_file_create(struct fence *fence);
struct fence *sync_file_get_fence(int fd);
diff --git a/include/linux/workqueue.h b/include/linux/workqueue.h
index 733a21e..1061add 100644
--- a/include/linux/workqueue.h
+++ b/include/linux/workqueue.h
@@ -311,8 +311,8 @@
__WQ_DRAINING = 1 << 16, /* internal: workqueue is draining */
__WQ_ORDERED = 1 << 17, /* internal: workqueue is ordered */
- __WQ_ORDERED_EXPLICIT = 1 << 18, /* internal: alloc_ordered_workqueue() */
__WQ_LEGACY = 1 << 18, /* internal: create*_workqueue() */
+ __WQ_ORDERED_EXPLICIT = 1 << 19, /* internal: alloc_ordered_workqueue() */
WQ_MAX_ACTIVE = 512, /* I like 512, better ideas? */
WQ_MAX_UNBOUND_PER_CPU = 4, /* 4 * #cpus for unbound wq */
diff --git a/include/net/inet_frag.h b/include/net/inet_frag.h
index 909972a..634d192 100644
--- a/include/net/inet_frag.h
+++ b/include/net/inet_frag.h
@@ -1,14 +1,9 @@
#ifndef __NET_FRAG_H__
#define __NET_FRAG_H__
-#include <linux/percpu_counter.h>
-
struct netns_frags {
- /* The percpu_counter "mem" need to be cacheline aligned.
- * mem.count must not share cacheline with other writers
- */
- struct percpu_counter mem ____cacheline_aligned_in_smp;
-
+ /* Keep atomic mem on separate cachelines in structs that include it */
+ atomic_t mem ____cacheline_aligned_in_smp;
/* sysctls */
int timeout;
int high_thresh;
@@ -108,15 +103,10 @@
int inet_frags_init(struct inet_frags *);
void inet_frags_fini(struct inet_frags *);
-static inline int inet_frags_init_net(struct netns_frags *nf)
+static inline void inet_frags_init_net(struct netns_frags *nf)
{
- return percpu_counter_init(&nf->mem, 0, GFP_KERNEL);
+ atomic_set(&nf->mem, 0);
}
-static inline void inet_frags_uninit_net(struct netns_frags *nf)
-{
- percpu_counter_destroy(&nf->mem);
-}
-
void inet_frags_exit_net(struct netns_frags *nf, struct inet_frags *f);
void inet_frag_kill(struct inet_frag_queue *q, struct inet_frags *f);
@@ -140,37 +130,24 @@
/* Memory Tracking Functions. */
-/* The default percpu_counter batch size is not big enough to scale to
- * fragmentation mem acct sizes.
- * The mem size of a 64K fragment is approx:
- * (44 fragments * 2944 truesize) + frag_queue struct(200) = 129736 bytes
- */
-static unsigned int frag_percpu_counter_batch = 130000;
-
static inline int frag_mem_limit(struct netns_frags *nf)
{
- return percpu_counter_read(&nf->mem);
+ return atomic_read(&nf->mem);
}
static inline void sub_frag_mem_limit(struct netns_frags *nf, int i)
{
- __percpu_counter_add(&nf->mem, -i, frag_percpu_counter_batch);
+ atomic_sub(i, &nf->mem);
}
static inline void add_frag_mem_limit(struct netns_frags *nf, int i)
{
- __percpu_counter_add(&nf->mem, i, frag_percpu_counter_batch);
+ atomic_add(i, &nf->mem);
}
-static inline unsigned int sum_frag_mem_limit(struct netns_frags *nf)
+static inline int sum_frag_mem_limit(struct netns_frags *nf)
{
- unsigned int res;
-
- local_bh_disable();
- res = percpu_counter_sum_positive(&nf->mem);
- local_bh_enable();
-
- return res;
+ return atomic_read(&nf->mem);
}
/* RFC 3168 support :
diff --git a/include/net/ip6_fib.h b/include/net/ip6_fib.h
index a74e2aa..a6bcb18 100644
--- a/include/net/ip6_fib.h
+++ b/include/net/ip6_fib.h
@@ -68,6 +68,7 @@
__u16 fn_flags;
int fn_sernum;
struct rt6_info *rr_ptr;
+ struct rcu_head rcu;
};
#ifndef CONFIG_IPV6_SUBTREES
@@ -102,7 +103,7 @@
* the same cache line.
*/
struct fib6_table *rt6i_table;
- struct fib6_node *rt6i_node;
+ struct fib6_node __rcu *rt6i_node;
struct in6_addr rt6i_gateway;
@@ -165,13 +166,40 @@
rt0->rt6i_flags |= RTF_EXPIRES;
}
+/* Function to safely get fn->sernum for passed in rt
+ * and store result in passed in cookie.
+ * Return true if we can get cookie safely
+ * Return false if not
+ */
+static inline bool rt6_get_cookie_safe(const struct rt6_info *rt,
+ u32 *cookie)
+{
+ struct fib6_node *fn;
+ bool status = false;
+
+ rcu_read_lock();
+ fn = rcu_dereference(rt->rt6i_node);
+
+ if (fn) {
+ *cookie = fn->fn_sernum;
+ status = true;
+ }
+
+ rcu_read_unlock();
+ return status;
+}
+
static inline u32 rt6_get_cookie(const struct rt6_info *rt)
{
+ u32 cookie = 0;
+
if (rt->rt6i_flags & RTF_PCPU ||
(unlikely(rt->dst.flags & DST_NOCACHE) && rt->dst.from))
rt = (struct rt6_info *)(rt->dst.from);
- return rt->rt6i_node ? rt->rt6i_node->fn_sernum : 0;
+ rt6_get_cookie_safe(rt, &cookie);
+
+ return cookie;
}
static inline void ip6_rt_put(struct rt6_info *rt)
diff --git a/include/soc/qcom/icnss.h b/include/soc/qcom/icnss.h
index 3527c35..e58a522 100644
--- a/include/soc/qcom/icnss.h
+++ b/include/soc/qcom/icnss.h
@@ -127,16 +127,7 @@
extern int icnss_smmu_map(struct device *dev, phys_addr_t paddr,
uint32_t *iova_addr, size_t size);
extern unsigned int icnss_socinfo_get_serial_number(struct device *dev);
-extern int icnss_set_wlan_unsafe_channel(u16 *unsafe_ch_list, u16 ch_count);
-extern int icnss_get_wlan_unsafe_channel(u16 *unsafe_ch_list, u16 *ch_count,
- u16 buf_len);
-extern int icnss_wlan_set_dfs_nol(const void *info, u16 info_len);
-extern int icnss_wlan_get_dfs_nol(void *info, u16 info_len);
extern bool icnss_is_qmi_disable(void);
extern bool icnss_is_fw_ready(void);
-extern int icnss_set_wlan_mac_address(const u8 *in, const uint32_t len);
-extern u8 *icnss_get_wlan_mac_address(struct device *dev, uint32_t *num);
extern int icnss_trigger_recovery(struct device *dev);
-extern int icnss_get_driver_load_cnt(void);
-extern void icnss_increment_driver_load_cnt(void);
#endif /* _ICNSS_WLAN_H_ */
diff --git a/include/trace/events/iommu.h b/include/trace/events/iommu.h
index 2c7befb..9652037 100644
--- a/include/trace/events/iommu.h
+++ b/include/trace/events/iommu.h
@@ -161,6 +161,62 @@
TP_ARGS(dev, iova, flags)
);
+
+DECLARE_EVENT_CLASS(iommu_errata_tlbi,
+
+ TP_PROTO(struct device *dev, u64 time),
+
+ TP_ARGS(dev, time),
+
+ TP_STRUCT__entry(
+ __string(device, dev_name(dev))
+ __field(u64, time)
+ ),
+
+ TP_fast_assign(
+ __assign_str(device, dev_name(dev));
+ __entry->time = time;
+ ),
+
+ TP_printk("IOMMU:%s %lld us",
+ __get_str(device), __entry->time
+ )
+);
+
+DEFINE_EVENT(iommu_errata_tlbi, errata_tlbi_start,
+
+ TP_PROTO(struct device *dev, u64 time),
+
+ TP_ARGS(dev, time)
+);
+
+DEFINE_EVENT(iommu_errata_tlbi, errata_tlbi_end,
+
+ TP_PROTO(struct device *dev, u64 time),
+
+ TP_ARGS(dev, time)
+);
+
+DEFINE_EVENT(iommu_errata_tlbi, errata_throttle_start,
+
+ TP_PROTO(struct device *dev, u64 time),
+
+ TP_ARGS(dev, time)
+);
+
+DEFINE_EVENT(iommu_errata_tlbi, errata_throttle_end,
+
+ TP_PROTO(struct device *dev, u64 time),
+
+ TP_ARGS(dev, time)
+);
+
+DEFINE_EVENT(iommu_errata_tlbi, errata_failed,
+
+ TP_PROTO(struct device *dev, u64 time),
+
+ TP_ARGS(dev, time)
+);
#endif /* _TRACE_IOMMU_H */
/* This part must be outside protection */
diff --git a/include/uapi/linux/rmnet_ipa_fd_ioctl.h b/include/uapi/linux/rmnet_ipa_fd_ioctl.h
index f04ac49..04aaaad 100644
--- a/include/uapi/linux/rmnet_ipa_fd_ioctl.h
+++ b/include/uapi/linux/rmnet_ipa_fd_ioctl.h
@@ -33,6 +33,7 @@
#define WAN_IOCTL_QUERY_DL_FILTER_STATS 8
#define WAN_IOCTL_ADD_FLT_RULE_EX 9
#define WAN_IOCTL_QUERY_TETHER_STATS_ALL 10
+#define WAN_IOCTL_NOTIFY_WAN_STATE 11
/* User space may not have this defined. */
#ifndef IFNAMSIZ
@@ -126,6 +127,10 @@
uint32_t index;
};
+struct wan_ioctl_notify_wan_state {
+ uint8_t up;
+};
+
#define WAN_IOC_ADD_FLT_RULE _IOWR(WAN_IOC_MAGIC, \
WAN_IOCTL_ADD_FLT_RULE, \
struct ipa_install_fltr_rule_req_msg_v01 *)
@@ -170,4 +175,8 @@
WAN_IOCTL_QUERY_TETHER_STATS_ALL, \
struct wan_ioctl_query_tether_stats_all *)
+#define WAN_IOC_NOTIFY_WAN_STATE _IOWR(WAN_IOC_MAGIC, \
+ WAN_IOCTL_NOTIFY_WAN_STATE, \
+ struct wan_ioctl_notify_wan_state *)
+
#endif /* _RMNET_IPA_FD_IOCTL_H */
diff --git a/include/uapi/media/cam_req_mgr.h b/include/uapi/media/cam_req_mgr.h
index fee26a9..9b7d055 100644
--- a/include/uapi/media/cam_req_mgr.h
+++ b/include/uapi/media/cam_req_mgr.h
@@ -216,7 +216,8 @@
/* Maximum allowed buffers in existence */
#define CAM_MEM_BUFQ_MAX 1024
-#define CAM_MEM_MGR_HDL_IDX_SIZE 16
+#define CAM_MEM_MGR_SECURE_BIT_POS 15
+#define CAM_MEM_MGR_HDL_IDX_SIZE 15
#define CAM_MEM_MGR_HDL_FD_SIZE 16
#define CAM_MEM_MGR_HDL_IDX_END_POS 16
#define CAM_MEM_MGR_HDL_FD_END_POS 32
@@ -224,11 +225,19 @@
#define CAM_MEM_MGR_HDL_IDX_MASK ((1 << CAM_MEM_MGR_HDL_IDX_SIZE) - 1)
#define GET_MEM_HANDLE(idx, fd) \
- ((idx << (CAM_MEM_MGR_HDL_IDX_END_POS - CAM_MEM_MGR_HDL_IDX_SIZE)) | \
+ ((idx & CAM_MEM_MGR_HDL_IDX_MASK) | \
(fd << (CAM_MEM_MGR_HDL_FD_END_POS - CAM_MEM_MGR_HDL_FD_SIZE))) \
#define CAM_MEM_MGR_GET_HDL_IDX(hdl) (hdl & CAM_MEM_MGR_HDL_IDX_MASK)
+#define CAM_MEM_MGR_SET_SECURE_HDL(hdl, flag) \
+ ((flag) ? (hdl |= (1 << CAM_MEM_MGR_SECURE_BIT_POS)) : \
+ ((hdl) &= ~(1 << CAM_MEM_MGR_SECURE_BIT_POS)))
+
+#define CAM_MEM_MGR_IS_SECURE_HDL(hdl) \
+ (((hdl) & \
+ (1<<CAM_MEM_MGR_SECURE_BIT_POS)) >> CAM_MEM_MGR_SECURE_BIT_POS)
+
/**
* memory allocation type
*/
diff --git a/include/uapi/media/cam_sensor.h b/include/uapi/media/cam_sensor.h
index 2fe7f2b..87f25b0 100644
--- a/include/uapi/media/cam_sensor.h
+++ b/include/uapi/media/cam_sensor.h
@@ -8,6 +8,7 @@
#define CAM_SENSOR_PROBE_CMD (CAM_COMMON_OPCODE_MAX + 1)
#define CAM_FLASH_MAX_LED_TRIGGERS 3
#define MAX_OIS_NAME_SIZE 32
+#define CAM_CSIPHY_SECURE_MODE_ENABLED 1
/**
* struct cam_sensor_query_cap - capabilities info for sensor
*
@@ -316,15 +317,15 @@
/**
* cam_csiphy_info: Provides cmdbuffer structre
- * @lane_mask : Lane mask details
- * @lane_assign : Lane sensor will be using
- * @csiphy_3phase : Total number of lanes
- * @combo_mode : Info regarding combo_mode is enable / disable
- * @lane_cnt : Total number of lanes
- * @reserved
- * @3phase : Details whether 3Phase / 2Phase operation
- * @settle_time : Settling time in ms
- * @data_rate : Data rate
+ * @lane_mask : Lane mask details
+ * @lane_assign : Lane sensor will be using
+ * @csiphy_3phase : Total number of lanes
+ * @combo_mode : Info regarding combo_mode is enable / disable
+ * @lane_cnt : Total number of lanes
+ * @secure_mode : Secure mode flag to enable / disable
+ * @3phase : Details whether 3Phase / 2Phase operation
+ * @settle_time : Settling time in ms
+ * @data_rate : Data rate
*
*/
struct cam_csiphy_info {
@@ -333,7 +334,7 @@
uint8_t csiphy_3phase;
uint8_t combo_mode;
uint8_t lane_cnt;
- uint8_t reserved;
+ uint8_t secure_mode;
uint64_t settle_time;
uint64_t data_rate;
} __attribute__((packed));
diff --git a/kernel/configs/README.android b/kernel/configs/README.android
deleted file mode 100644
index 2e2d7c0..0000000
--- a/kernel/configs/README.android
+++ /dev/null
@@ -1,15 +0,0 @@
-The android-*.config files in this directory are meant to be used as a base
-for an Android kernel config. All devices should have the options in
-android-base.config enabled. While not mandatory, the options in
-android-recommended.config enable advanced Android features.
-
-Assuming you already have a minimalist defconfig for your device, a possible
-way to enable these options would be:
-
- ARCH=<arch> scripts/kconfig/merge_config.sh <path_to>/<device>_defconfig kernel/configs/android-base.config kernel/configs/android-recommended.config
-
-This will generate a .config that can then be used to save a new defconfig or
-compile a new kernel with Android features enabled.
-
-Because there is no tool to consistently generate these config fragments,
-lets keep them alphabetically sorted instead of random.
diff --git a/kernel/configs/android-base-arm64.cfg b/kernel/configs/android-base-arm64.cfg
deleted file mode 100644
index 43f23d6..0000000
--- a/kernel/configs/android-base-arm64.cfg
+++ /dev/null
@@ -1,5 +0,0 @@
-# KEEP ALPHABETICALLY SORTED
-CONFIG_ARMV8_DEPRECATED=y
-CONFIG_CP15_BARRIER_EMULATION=y
-CONFIG_SETEND_EMULATION=y
-CONFIG_SWP_EMULATION=y
diff --git a/kernel/configs/android-base.config b/kernel/configs/android-base.config
deleted file mode 100644
index 7dc5b07..0000000
--- a/kernel/configs/android-base.config
+++ /dev/null
@@ -1,165 +0,0 @@
-# KEEP ALPHABETICALLY SORTED
-# CONFIG_DEVKMEM is not set
-# CONFIG_DEVMEM is not set
-# CONFIG_FHANDLE is not set
-# CONFIG_INET_LRO is not set
-# CONFIG_NFSD is not set
-# CONFIG_NFS_FS is not set
-# CONFIG_OABI_COMPAT is not set
-# CONFIG_SYSVIPC is not set
-# CONFIG_USELIB is not set
-CONFIG_ANDROID=y
-CONFIG_ANDROID_BINDER_DEVICES=binder,hwbinder,vndbinder
-CONFIG_ANDROID_BINDER_IPC=y
-CONFIG_ANDROID_LOW_MEMORY_KILLER=y
-CONFIG_ASHMEM=y
-CONFIG_AUDIT=y
-CONFIG_BLK_DEV_INITRD=y
-CONFIG_CGROUPS=y
-CONFIG_CGROUP_CPUACCT=y
-CONFIG_CGROUP_FREEZER=y
-CONFIG_CGROUP_SCHED=y
-CONFIG_CGROUP_BPF=y
-CONFIG_DEFAULT_SECURITY_SELINUX=y
-CONFIG_EMBEDDED=y
-CONFIG_FB=y
-CONFIG_HARDENED_USERCOPY=y
-CONFIG_HIGH_RES_TIMERS=y
-CONFIG_IKCONFIG=y
-CONFIG_IKCONFIG_PROC=y
-CONFIG_INET6_AH=y
-CONFIG_INET6_ESP=y
-CONFIG_INET6_IPCOMP=y
-CONFIG_INET=y
-CONFIG_INET_DIAG_DESTROY=y
-CONFIG_INET_ESP=y
-CONFIG_INET_XFRM_MODE_TUNNEL=y
-CONFIG_IP6_NF_FILTER=y
-CONFIG_IP6_NF_IPTABLES=y
-CONFIG_IP6_NF_MANGLE=y
-CONFIG_IP6_NF_MATCH_RPFILTER=y
-CONFIG_IP6_NF_RAW=y
-CONFIG_IP6_NF_TARGET_REJECT=y
-CONFIG_IPV6=y
-CONFIG_IPV6_MIP6=y
-CONFIG_IPV6_MULTIPLE_TABLES=y
-CONFIG_IPV6_OPTIMISTIC_DAD=y
-CONFIG_IPV6_ROUTER_PREF=y
-CONFIG_IPV6_ROUTE_INFO=y
-CONFIG_IP_ADVANCED_ROUTER=y
-CONFIG_IP_MULTICAST=y
-CONFIG_IP_MULTIPLE_TABLES=y
-CONFIG_IP_NF_ARPFILTER=y
-CONFIG_IP_NF_ARPTABLES=y
-CONFIG_IP_NF_ARP_MANGLE=y
-CONFIG_IP_NF_FILTER=y
-CONFIG_IP_NF_IPTABLES=y
-CONFIG_IP_NF_MANGLE=y
-CONFIG_IP_NF_MATCH_AH=y
-CONFIG_IP_NF_MATCH_ECN=y
-CONFIG_IP_NF_MATCH_TTL=y
-CONFIG_IP_NF_NAT=y
-CONFIG_IP_NF_RAW=y
-CONFIG_IP_NF_SECURITY=y
-CONFIG_IP_NF_TARGET_MASQUERADE=y
-CONFIG_IP_NF_TARGET_NETMAP=y
-CONFIG_IP_NF_TARGET_REDIRECT=y
-CONFIG_IP_NF_TARGET_REJECT=y
-CONFIG_MODULES=y
-CONFIG_MODULE_UNLOAD=y
-CONFIG_MODVERSIONS=y
-CONFIG_NET=y
-CONFIG_NETDEVICES=y
-CONFIG_NETFILTER=y
-CONFIG_NETFILTER_XT_MATCH_COMMENT=y
-CONFIG_NETFILTER_XT_MATCH_CONNLIMIT=y
-CONFIG_NETFILTER_XT_MATCH_CONNMARK=y
-CONFIG_NETFILTER_XT_MATCH_CONNTRACK=y
-CONFIG_NETFILTER_XT_MATCH_HASHLIMIT=y
-CONFIG_NETFILTER_XT_MATCH_HELPER=y
-CONFIG_NETFILTER_XT_MATCH_IPRANGE=y
-CONFIG_NETFILTER_XT_MATCH_LENGTH=y
-CONFIG_NETFILTER_XT_MATCH_LIMIT=y
-CONFIG_NETFILTER_XT_MATCH_MAC=y
-CONFIG_NETFILTER_XT_MATCH_MARK=y
-CONFIG_NETFILTER_XT_MATCH_PKTTYPE=y
-CONFIG_NETFILTER_XT_MATCH_POLICY=y
-CONFIG_NETFILTER_XT_MATCH_QTAGUID=y
-CONFIG_NETFILTER_XT_MATCH_QUOTA2=y
-CONFIG_NETFILTER_XT_MATCH_QUOTA=y
-CONFIG_NETFILTER_XT_MATCH_SOCKET=y
-CONFIG_NETFILTER_XT_MATCH_STATE=y
-CONFIG_NETFILTER_XT_MATCH_STATISTIC=y
-CONFIG_NETFILTER_XT_MATCH_STRING=y
-CONFIG_NETFILTER_XT_MATCH_TIME=y
-CONFIG_NETFILTER_XT_MATCH_U32=y
-CONFIG_NETFILTER_XT_TARGET_CLASSIFY=y
-CONFIG_NETFILTER_XT_TARGET_CONNMARK=y
-CONFIG_NETFILTER_XT_TARGET_CONNSECMARK=y
-CONFIG_NETFILTER_XT_TARGET_IDLETIMER=y
-CONFIG_NETFILTER_XT_TARGET_MARK=y
-CONFIG_NETFILTER_XT_TARGET_NFLOG=y
-CONFIG_NETFILTER_XT_TARGET_NFQUEUE=y
-CONFIG_NETFILTER_XT_TARGET_SECMARK=y
-CONFIG_NETFILTER_XT_TARGET_TCPMSS=y
-CONFIG_NETFILTER_XT_TARGET_TPROXY=y
-CONFIG_NETFILTER_XT_TARGET_TRACE=y
-CONFIG_NET_CLS_ACT=y
-CONFIG_NET_CLS_U32=y
-CONFIG_NET_EMATCH=y
-CONFIG_NET_EMATCH_U32=y
-CONFIG_NET_KEY=y
-CONFIG_NET_SCHED=y
-CONFIG_NET_SCH_HTB=y
-CONFIG_NF_CONNTRACK=y
-CONFIG_NF_CONNTRACK_AMANDA=y
-CONFIG_NF_CONNTRACK_EVENTS=y
-CONFIG_NF_CONNTRACK_FTP=y
-CONFIG_NF_CONNTRACK_H323=y
-CONFIG_NF_CONNTRACK_IPV4=y
-CONFIG_NF_CONNTRACK_IPV6=y
-CONFIG_NF_CONNTRACK_IRC=y
-CONFIG_NF_CONNTRACK_NETBIOS_NS=y
-CONFIG_NF_CONNTRACK_PPTP=y
-CONFIG_NF_CONNTRACK_SANE=y
-CONFIG_NF_CONNTRACK_SECMARK=y
-CONFIG_NF_CONNTRACK_TFTP=y
-CONFIG_NF_CT_NETLINK=y
-CONFIG_NF_CT_PROTO_DCCP=y
-CONFIG_NF_CT_PROTO_SCTP=y
-CONFIG_NF_CT_PROTO_UDPLITE=y
-CONFIG_NF_NAT=y
-CONFIG_NO_HZ=y
-CONFIG_PACKET=y
-CONFIG_PM_AUTOSLEEP=y
-CONFIG_PM_WAKELOCKS=y
-CONFIG_PPP=y
-CONFIG_PPPOLAC=y
-CONFIG_PPPOPNS=y
-CONFIG_PPP_BSDCOMP=y
-CONFIG_PPP_DEFLATE=y
-CONFIG_PPP_MPPE=y
-CONFIG_PREEMPT=y
-CONFIG_PROFILING=y
-CONFIG_RANDOMIZE_BASE=y
-CONFIG_RTC_CLASS=y
-CONFIG_RT_GROUP_SCHED=y
-CONFIG_SECCOMP=y
-CONFIG_SECURITY=y
-CONFIG_SECURITY_NETWORK=y
-CONFIG_SECURITY_PERF_EVENTS_RESTRICT=y
-CONFIG_SECURITY_SELINUX=y
-CONFIG_STAGING=y
-CONFIG_TUN=y
-CONFIG_UID_SYS_STATS=y
-CONFIG_UNIX=y
-CONFIG_USB_CONFIGFS=y
-CONFIG_USB_CONFIGFS_F_ACC=y
-CONFIG_USB_CONFIGFS_F_AUDIO_SRC=y
-CONFIG_USB_CONFIGFS_F_FS=y
-CONFIG_USB_CONFIGFS_F_MIDI=y
-CONFIG_USB_CONFIGFS_F_MTP=y
-CONFIG_USB_CONFIGFS_F_PTP=y
-CONFIG_USB_CONFIGFS_UEVENT=y
-CONFIG_USB_GADGET=y
-CONFIG_XFRM_USER=y
diff --git a/kernel/configs/android-recommended.config b/kernel/configs/android-recommended.config
deleted file mode 100644
index da146fa..0000000
--- a/kernel/configs/android-recommended.config
+++ /dev/null
@@ -1,138 +0,0 @@
-# KEEP ALPHABETICALLY SORTED
-# CONFIG_AIO is not set
-# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set
-# CONFIG_INPUT_MOUSE is not set
-# CONFIG_LEGACY_PTYS is not set
-# CONFIG_NF_CONNTRACK_SIP is not set
-# CONFIG_PM_WAKELOCKS_GC is not set
-# CONFIG_VT is not set
-CONFIG_ARM64_SW_TTBR0_PAN=y
-CONFIG_BACKLIGHT_LCD_SUPPORT=y
-CONFIG_BLK_DEV_DM=y
-CONFIG_BLK_DEV_LOOP=y
-CONFIG_BLK_DEV_RAM=y
-CONFIG_BLK_DEV_RAM_SIZE=8192
-CONFIG_CC_STACKPROTECTOR_STRONG=y
-CONFIG_COMPACTION=y
-CONFIG_CPU_SW_DOMAIN_PAN=y
-CONFIG_DEBUG_RODATA=y
-CONFIG_DM_CRYPT=y
-CONFIG_DM_UEVENT=y
-CONFIG_DM_VERITY=y
-CONFIG_DM_VERITY_FEC=y
-CONFIG_DRAGONRISE_FF=y
-CONFIG_ENABLE_DEFAULT_TRACERS=y
-CONFIG_EXT4_FS=y
-CONFIG_EXT4_FS_SECURITY=y
-CONFIG_FUSE_FS=y
-CONFIG_GREENASIA_FF=y
-CONFIG_HIDRAW=y
-CONFIG_HID_A4TECH=y
-CONFIG_HID_ACRUX=y
-CONFIG_HID_ACRUX_FF=y
-CONFIG_HID_APPLE=y
-CONFIG_HID_BELKIN=y
-CONFIG_HID_CHERRY=y
-CONFIG_HID_CHICONY=y
-CONFIG_HID_CYPRESS=y
-CONFIG_HID_DRAGONRISE=y
-CONFIG_HID_ELECOM=y
-CONFIG_HID_EMS_FF=y
-CONFIG_HID_EZKEY=y
-CONFIG_HID_GREENASIA=y
-CONFIG_HID_GYRATION=y
-CONFIG_HID_HOLTEK=y
-CONFIG_HID_KENSINGTON=y
-CONFIG_HID_KEYTOUCH=y
-CONFIG_HID_KYE=y
-CONFIG_HID_LCPOWER=y
-CONFIG_HID_LOGITECH=y
-CONFIG_HID_LOGITECH_DJ=y
-CONFIG_HID_MAGICMOUSE=y
-CONFIG_HID_MICROSOFT=y
-CONFIG_HID_MONTEREY=y
-CONFIG_HID_MULTITOUCH=y
-CONFIG_HID_NTRIG=y
-CONFIG_HID_ORTEK=y
-CONFIG_HID_PANTHERLORD=y
-CONFIG_HID_PETALYNX=y
-CONFIG_HID_PICOLCD=y
-CONFIG_HID_PRIMAX=y
-CONFIG_HID_PRODIKEYS=y
-CONFIG_HID_ROCCAT=y
-CONFIG_HID_SAITEK=y
-CONFIG_HID_SAMSUNG=y
-CONFIG_HID_SMARTJOYPLUS=y
-CONFIG_HID_SONY=y
-CONFIG_HID_SPEEDLINK=y
-CONFIG_HID_SUNPLUS=y
-CONFIG_HID_THRUSTMASTER=y
-CONFIG_HID_TIVO=y
-CONFIG_HID_TOPSEED=y
-CONFIG_HID_TWINHAN=y
-CONFIG_HID_UCLOGIC=y
-CONFIG_HID_WACOM=y
-CONFIG_HID_WALTOP=y
-CONFIG_HID_WIIMOTE=y
-CONFIG_HID_ZEROPLUS=y
-CONFIG_HID_ZYDACRON=y
-CONFIG_INPUT_EVDEV=y
-CONFIG_INPUT_GPIO=y
-CONFIG_INPUT_JOYSTICK=y
-CONFIG_INPUT_KEYCHORD=y
-CONFIG_INPUT_KEYRESET=y
-CONFIG_INPUT_MISC=y
-CONFIG_INPUT_TABLET=y
-CONFIG_INPUT_UINPUT=y
-CONFIG_ION=y
-CONFIG_JOYSTICK_XPAD=y
-CONFIG_JOYSTICK_XPAD_FF=y
-CONFIG_JOYSTICK_XPAD_LEDS=y
-CONFIG_KALLSYMS_ALL=y
-CONFIG_KSM=y
-CONFIG_LOGIG940_FF=y
-CONFIG_LOGIRUMBLEPAD2_FF=y
-CONFIG_LOGITECH_FF=y
-CONFIG_MD=y
-CONFIG_MEDIA_SUPPORT=y
-CONFIG_MEMORY_STATE_TIME=y
-CONFIG_MSDOS_FS=y
-CONFIG_PANIC_TIMEOUT=5
-CONFIG_PANTHERLORD_FF=y
-CONFIG_PERF_EVENTS=y
-CONFIG_PM_DEBUG=y
-CONFIG_PM_RUNTIME=y
-CONFIG_PM_WAKELOCKS_LIMIT=0
-CONFIG_POWER_SUPPLY=y
-CONFIG_PSTORE=y
-CONFIG_PSTORE_CONSOLE=y
-CONFIG_PSTORE_RAM=y
-CONFIG_QFMT_V2=y
-CONFIG_QUOTA=y
-CONFIG_QUOTACTL=y
-CONFIG_QUOTA_NETLINK_INTERFACE=y
-CONFIG_QUOTA_TREE=y
-CONFIG_SCHEDSTATS=y
-CONFIG_SMARTJOYPLUS_FF=y
-CONFIG_SND=y
-CONFIG_SOUND=y
-CONFIG_SUSPEND_TIME=y
-CONFIG_TABLET_USB_ACECAD=y
-CONFIG_TABLET_USB_AIPTEK=y
-CONFIG_TABLET_USB_GTCO=y
-CONFIG_TABLET_USB_HANWANG=y
-CONFIG_TABLET_USB_KBTAB=y
-CONFIG_TASKSTATS=y
-CONFIG_TASK_DELAY_ACCT=y
-CONFIG_TASK_IO_ACCOUNTING=y
-CONFIG_TASK_XACCT=y
-CONFIG_TIMER_STATS=y
-CONFIG_TMPFS=y
-CONFIG_TMPFS_POSIX_ACL=y
-CONFIG_UHID=y
-CONFIG_MEMORY_STATE_TIME=y
-CONFIG_USB_ANNOUNCE_NEW_DEVICES=y
-CONFIG_USB_EHCI_HCD=y
-CONFIG_USB_HIDDEV=y
-CONFIG_USB_USBNET=y
-CONFIG_VFAT_FS=y
diff --git a/kernel/kcov.c b/kernel/kcov.c
index 3cbb0c8..f8f3f4c 100644
--- a/kernel/kcov.c
+++ b/kernel/kcov.c
@@ -14,6 +14,7 @@
#include <linux/debugfs.h>
#include <linux/uaccess.h>
#include <linux/kcov.h>
+#include <asm/setup.h>
/*
* kcov descriptor (one per opened debugfs file).
@@ -68,6 +69,11 @@
if (mode == KCOV_MODE_TRACE) {
unsigned long *area;
unsigned long pos;
+ unsigned long ip = _RET_IP_;
+
+#ifdef CONFIG_RANDOMIZE_BASE
+ ip -= kaslr_offset();
+#endif
/*
* There is some code that runs in interrupts but for which
@@ -81,7 +87,7 @@
/* The first word is number of subsequent PCs. */
pos = READ_ONCE(area[0]) + 1;
if (likely(pos < t->kcov_size)) {
- area[pos] = _RET_IP_;
+ area[pos] = ip;
WRITE_ONCE(area[0], pos);
}
}
diff --git a/kernel/locking/locktorture.c b/kernel/locking/locktorture.c
index f8c5af5..d3de04b 100644
--- a/kernel/locking/locktorture.c
+++ b/kernel/locking/locktorture.c
@@ -780,6 +780,10 @@
else
lock_torture_print_module_parms(cxt.cur_ops,
"End of test: SUCCESS");
+
+ kfree(cxt.lwsa);
+ kfree(cxt.lrsa);
+
end:
torture_cleanup_end();
}
@@ -924,6 +928,8 @@
GFP_KERNEL);
if (reader_tasks == NULL) {
VERBOSE_TOROUT_ERRSTRING("reader_tasks: Out of memory");
+ kfree(writer_tasks);
+ writer_tasks = NULL;
firsterr = -ENOMEM;
goto unwind;
}
diff --git a/kernel/sched/core.c b/kernel/sched/core.c
index 352cfca..08fd4be 100644
--- a/kernel/sched/core.c
+++ b/kernel/sched/core.c
@@ -3305,6 +3305,7 @@
bool early_notif;
u32 old_load;
struct related_thread_group *grp;
+ unsigned int flag = 0;
sched_clock_tick();
@@ -3321,10 +3322,12 @@
cpu_load_update_active(rq);
calc_global_load_tick(rq);
sched_freq_tick(cpu);
- cpufreq_update_util(rq, 0);
early_notif = early_detection_notify(rq, wallclock);
+ if (early_notif)
+ flag = SCHED_CPUFREQ_WALT | SCHED_CPUFREQ_EARLY_DET;
+ cpufreq_update_util(rq, flag);
raw_spin_unlock(&rq->lock);
if (early_notif)
diff --git a/kernel/sched/cpufreq_schedutil.c b/kernel/sched/cpufreq_schedutil.c
index c2372f8..2eb966c 100644
--- a/kernel/sched/cpufreq_schedutil.c
+++ b/kernel/sched/cpufreq_schedutil.c
@@ -28,6 +28,7 @@
struct sugov_tunables {
struct gov_attr_set attr_set;
unsigned int rate_limit_us;
+ unsigned int hispeed_load;
unsigned int hispeed_freq;
bool pl;
};
@@ -266,7 +267,7 @@
}
#define NL_RATIO 75
-#define HISPEED_LOAD 90
+#define DEFAULT_HISPEED_LOAD 90
static void sugov_walt_adjust(struct sugov_cpu *sg_cpu, unsigned long *util,
unsigned long *max)
{
@@ -280,7 +281,7 @@
return;
is_hiload = (cpu_util >= mult_frac(sg_policy->avg_cap,
- HISPEED_LOAD,
+ sg_policy->tunables->hispeed_load,
100));
if (is_hiload && !is_migration)
@@ -508,6 +509,26 @@
return count;
}
+static ssize_t hispeed_load_show(struct gov_attr_set *attr_set, char *buf)
+{
+ struct sugov_tunables *tunables = to_sugov_tunables(attr_set);
+
+ return sprintf(buf, "%u\n", tunables->hispeed_load);
+}
+
+static ssize_t hispeed_load_store(struct gov_attr_set *attr_set,
+ const char *buf, size_t count)
+{
+ struct sugov_tunables *tunables = to_sugov_tunables(attr_set);
+
+ if (kstrtouint(buf, 10, &tunables->hispeed_load))
+ return -EINVAL;
+
+ tunables->hispeed_load = min(100U, tunables->hispeed_load);
+
+ return count;
+}
+
static ssize_t hispeed_freq_show(struct gov_attr_set *attr_set, char *buf)
{
struct sugov_tunables *tunables = to_sugov_tunables(attr_set);
@@ -559,11 +580,13 @@
}
static struct governor_attr rate_limit_us = __ATTR_RW(rate_limit_us);
+static struct governor_attr hispeed_load = __ATTR_RW(hispeed_load);
static struct governor_attr hispeed_freq = __ATTR_RW(hispeed_freq);
static struct governor_attr pl = __ATTR_RW(pl);
static struct attribute *sugov_attributes[] = {
&rate_limit_us.attr,
+ &hispeed_load.attr,
&hispeed_freq.attr,
&pl.attr,
NULL
@@ -710,6 +733,7 @@
}
tunables->rate_limit_us = LATENCY_MULTIPLIER;
+ tunables->hispeed_load = DEFAULT_HISPEED_LOAD;
tunables->hispeed_freq = 0;
lat = policy->cpuinfo.transition_latency / NSEC_PER_USEC;
if (lat)
diff --git a/kernel/sched/fair.c b/kernel/sched/fair.c
index 38fa781..d61c570 100755
--- a/kernel/sched/fair.c
+++ b/kernel/sched/fair.c
@@ -5658,10 +5658,10 @@
for (idx = 0; idx < sge->nr_cap_states; idx++) {
if (sge->cap_states[idx].cap >= util)
- break;
+ return idx;
}
- return idx;
+ return (sge->nr_cap_states - 1);
}
static int find_new_capacity(struct energy_env *eenv,
@@ -6161,15 +6161,15 @@
return __task_fits(p, cpu, cpu_util(cpu));
}
-static bool __cpu_overutilized(int cpu, int delta)
+bool __cpu_overutilized(int cpu, unsigned long util)
{
- return (capacity_orig_of(cpu) * 1024) <
- ((cpu_util(cpu) + delta) * sysctl_sched_capacity_margin);
+ return (capacity_orig_of(cpu) * 1024 <
+ util * sysctl_sched_capacity_margin);
}
bool cpu_overutilized(int cpu)
{
- return __cpu_overutilized(cpu, 0);
+ return __cpu_overutilized(cpu, cpu_util(cpu));
}
#ifdef CONFIG_SCHED_TUNE
@@ -6996,7 +6996,7 @@
if (is_reserved(i))
continue;
- if (sched_cpu_high_irqload(cpu))
+ if (sched_cpu_high_irqload(i))
continue;
/*
@@ -7188,7 +7188,9 @@
task_util_boosted = 0;
#endif
/* Not enough spare capacity on previous cpu */
- if (__cpu_overutilized(task_cpu(p), task_util_boosted)) {
+ if (__cpu_overutilized(task_cpu(p),
+ cpu_util(task_cpu(p)) +
+ task_util_boosted)) {
trace_sched_task_util_overutilzed(p, task_cpu(p),
task_util(p), target_cpu,
target_cpu, 0, need_idle);
diff --git a/kernel/sched/rt.c b/kernel/sched/rt.c
index 1bc4828..35382df 100644
--- a/kernel/sched/rt.c
+++ b/kernel/sched/rt.c
@@ -1724,11 +1724,11 @@
unsigned long cpu_capacity;
unsigned long best_capacity;
unsigned long util, best_cpu_util = ULONG_MAX;
+ unsigned long best_cpu_util_cum = ULONG_MAX;
+ unsigned long util_cum;
+ unsigned long tutil = task_util(task);
int best_cpu_idle_idx = INT_MAX;
int cpu_idle_idx = -1;
- long new_util_cum;
- int max_spare_cap_cpu = -1;
- long max_spare_cap = -LONG_MAX;
bool placement_boost;
/* Make sure the mask is initialized first */
@@ -1791,55 +1791,55 @@
* double count rt task load.
*/
util = cpu_util(cpu);
- if (!cpu_overutilized(cpu)) {
- if (cpu_isolated(cpu))
+
+ if (__cpu_overutilized(cpu, util + tutil))
+ continue;
+
+ if (cpu_isolated(cpu))
+ continue;
+
+ if (sched_cpu_high_irqload(cpu))
+ continue;
+
+ /* Find the least loaded CPU */
+ if (util > best_cpu_util)
+ continue;
+
+ /*
+ * If the previous CPU has same load, keep it as
+ * best_cpu.
+ */
+ if (best_cpu_util == util && best_cpu == task_cpu(task))
+ continue;
+
+ /*
+ * If candidate CPU is the previous CPU, select it.
+ * Otherwise, if its load is same with best_cpu and in
+ * a shallower C-state, select it. If all above
+ * conditions are same, select the least cumulative
+ * window demand CPU.
+ */
+ if (sysctl_sched_cstate_aware)
+ cpu_idle_idx = idle_get_state_idx(cpu_rq(cpu));
+
+ util_cum = cpu_util_cum(cpu, 0);
+ if (cpu != task_cpu(task) && best_cpu_util == util) {
+ if (best_cpu_idle_idx < cpu_idle_idx)
continue;
- if (sched_cpu_high_irqload(cpu))
+ if (best_cpu_idle_idx == cpu_idle_idx &&
+ best_cpu_util_cum < util_cum)
continue;
-
- new_util_cum = cpu_util_cum(cpu, 0);
-
- if (!task_in_cum_window_demand(cpu_rq(cpu),
- task))
- new_util_cum += task_util(task);
-
- trace_sched_cpu_util(task, cpu, task_util(task),
- 0, new_util_cum, 0);
-
- if (sysctl_sched_cstate_aware)
- cpu_idle_idx =
- idle_get_state_idx(cpu_rq(cpu));
-
- if (add_capacity_margin(new_util_cum, cpu) <
- capacity_curr_of(cpu)) {
- if (cpu_idle_idx < best_cpu_idle_idx ||
- (best_cpu != task_cpu(task) &&
- (best_cpu_idle_idx ==
- cpu_idle_idx &&
- best_cpu_util > util))) {
- best_cpu_util = util;
- best_cpu = cpu;
- best_cpu_idle_idx =
- cpu_idle_idx;
- }
- } else {
- long spare_cap = capacity_of(cpu) -
- util;
-
- if (spare_cap > 0 &&
- max_spare_cap < spare_cap) {
- max_spare_cap_cpu = cpu;
- max_spare_cap = spare_cap;
- }
- }
}
+
+ best_cpu_idle_idx = cpu_idle_idx;
+ best_cpu_util_cum = util_cum;
+ best_cpu_util = util;
+ best_cpu = cpu;
}
if (best_cpu != -1) {
return best_cpu;
- } else if (max_spare_cap_cpu != -1) {
- return max_spare_cap_cpu;
} else if (!cpumask_empty(&backup_search_cpu)) {
cpumask_copy(&search_cpu, &backup_search_cpu);
cpumask_clear(&backup_search_cpu);
diff --git a/kernel/sched/sched.h b/kernel/sched/sched.h
index 0a1e62f..a5b1377 100644
--- a/kernel/sched/sched.h
+++ b/kernel/sched/sched.h
@@ -1457,6 +1457,7 @@
extern void set_cpus_allowed_common(struct task_struct *p, const struct cpumask *new_mask);
+bool __cpu_overutilized(int cpu, unsigned long util);
bool cpu_overutilized(int cpu);
#endif
@@ -2291,7 +2292,7 @@
#ifdef CONFIG_SCHED_WALT
unsigned int exception_flags = SCHED_CPUFREQ_INTERCLUSTER_MIG |
- SCHED_CPUFREQ_PL;
+ SCHED_CPUFREQ_PL | SCHED_CPUFREQ_EARLY_DET;
/*
* Skip if we've already reported, but not if this is an inter-cluster
diff --git a/kernel/sched/tune.c b/kernel/sched/tune.c
index 217bafe..93643ba 100644
--- a/kernel/sched/tune.c
+++ b/kernel/sched/tune.c
@@ -838,7 +838,6 @@
bg = &per_cpu(cpu_boost_groups, cpu);
bg->group[st->idx].boost = 0;
bg->group[st->idx].tasks = 0;
- raw_spin_lock_init(&bg->lock);
}
return 0;
diff --git a/mm/memory.c b/mm/memory.c
index b5e0ed3..378ebc0 100644
--- a/mm/memory.c
+++ b/mm/memory.c
@@ -3596,6 +3596,11 @@
/* do counter updates before entering really critical section. */
check_sync_rss_stat(current);
+ if (!arch_vma_access_permitted(vma, flags & FAULT_FLAG_WRITE,
+ flags & FAULT_FLAG_INSTRUCTION,
+ flags & FAULT_FLAG_REMOTE))
+ return VM_FAULT_SIGSEGV;
+
/*
* Enable the memcg OOM handling for faults triggered in user
* space. Kernel faults are handled more gracefully.
@@ -3603,11 +3608,6 @@
if (flags & FAULT_FLAG_USER)
mem_cgroup_oom_enable();
- if (!arch_vma_access_permitted(vma, flags & FAULT_FLAG_WRITE,
- flags & FAULT_FLAG_INSTRUCTION,
- flags & FAULT_FLAG_REMOTE))
- return VM_FAULT_SIGSEGV;
-
if (unlikely(is_vm_hugetlb_page(vma)))
ret = hugetlb_fault(vma->vm_mm, vma, address, flags);
else
diff --git a/mm/page_owner.c b/mm/page_owner.c
index 65e24fb..fe850b9 100644
--- a/mm/page_owner.c
+++ b/mm/page_owner.c
@@ -143,7 +143,7 @@
.nr_entries = 0,
.entries = entries,
.max_entries = PAGE_OWNER_STACK_DEPTH,
- .skip = 0
+ .skip = 2
};
depot_stack_handle_t handle;
diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c
index 577f1c0..ffd09c1 100644
--- a/net/bluetooth/l2cap_core.c
+++ b/net/bluetooth/l2cap_core.c
@@ -58,7 +58,7 @@
u8 code, u8 ident, u16 dlen, void *data);
static void l2cap_send_cmd(struct l2cap_conn *conn, u8 ident, u8 code, u16 len,
void *data);
-static int l2cap_build_conf_req(struct l2cap_chan *chan, void *data);
+static int l2cap_build_conf_req(struct l2cap_chan *chan, void *data, size_t data_size);
static void l2cap_send_disconn_req(struct l2cap_chan *chan, int err);
static void l2cap_tx(struct l2cap_chan *chan, struct l2cap_ctrl *control,
@@ -1473,7 +1473,7 @@
set_bit(CONF_REQ_SENT, &chan->conf_state);
l2cap_send_cmd(conn, l2cap_get_ident(conn), L2CAP_CONF_REQ,
- l2cap_build_conf_req(chan, buf), buf);
+ l2cap_build_conf_req(chan, buf, sizeof(buf)), buf);
chan->num_conf_req++;
}
@@ -2977,12 +2977,15 @@
return len;
}
-static void l2cap_add_conf_opt(void **ptr, u8 type, u8 len, unsigned long val)
+static void l2cap_add_conf_opt(void **ptr, u8 type, u8 len, unsigned long val, size_t size)
{
struct l2cap_conf_opt *opt = *ptr;
BT_DBG("type 0x%2.2x len %u val 0x%lx", type, len, val);
+ if (size < L2CAP_CONF_OPT_SIZE + len)
+ return;
+
opt->type = type;
opt->len = len;
@@ -3007,7 +3010,7 @@
*ptr += L2CAP_CONF_OPT_SIZE + len;
}
-static void l2cap_add_opt_efs(void **ptr, struct l2cap_chan *chan)
+static void l2cap_add_opt_efs(void **ptr, struct l2cap_chan *chan, size_t size)
{
struct l2cap_conf_efs efs;
@@ -3035,7 +3038,7 @@
}
l2cap_add_conf_opt(ptr, L2CAP_CONF_EFS, sizeof(efs),
- (unsigned long) &efs);
+ (unsigned long) &efs, size);
}
static void l2cap_ack_timeout(struct work_struct *work)
@@ -3181,11 +3184,12 @@
chan->ack_win = chan->tx_win;
}
-static int l2cap_build_conf_req(struct l2cap_chan *chan, void *data)
+static int l2cap_build_conf_req(struct l2cap_chan *chan, void *data, size_t data_size)
{
struct l2cap_conf_req *req = data;
struct l2cap_conf_rfc rfc = { .mode = chan->mode };
void *ptr = req->data;
+ void *endptr = data + data_size;
u16 size;
BT_DBG("chan %p", chan);
@@ -3210,7 +3214,7 @@
done:
if (chan->imtu != L2CAP_DEFAULT_MTU)
- l2cap_add_conf_opt(&ptr, L2CAP_CONF_MTU, 2, chan->imtu);
+ l2cap_add_conf_opt(&ptr, L2CAP_CONF_MTU, 2, chan->imtu, endptr - ptr);
switch (chan->mode) {
case L2CAP_MODE_BASIC:
@@ -3229,7 +3233,7 @@
rfc.max_pdu_size = 0;
l2cap_add_conf_opt(&ptr, L2CAP_CONF_RFC, sizeof(rfc),
- (unsigned long) &rfc);
+ (unsigned long) &rfc, endptr - ptr);
break;
case L2CAP_MODE_ERTM:
@@ -3249,21 +3253,21 @@
L2CAP_DEFAULT_TX_WINDOW);
l2cap_add_conf_opt(&ptr, L2CAP_CONF_RFC, sizeof(rfc),
- (unsigned long) &rfc);
+ (unsigned long) &rfc, endptr - ptr);
if (test_bit(FLAG_EFS_ENABLE, &chan->flags))
- l2cap_add_opt_efs(&ptr, chan);
+ l2cap_add_opt_efs(&ptr, chan, endptr - ptr);
if (test_bit(FLAG_EXT_CTRL, &chan->flags))
l2cap_add_conf_opt(&ptr, L2CAP_CONF_EWS, 2,
- chan->tx_win);
+ chan->tx_win, endptr - ptr);
if (chan->conn->feat_mask & L2CAP_FEAT_FCS)
if (chan->fcs == L2CAP_FCS_NONE ||
test_bit(CONF_RECV_NO_FCS, &chan->conf_state)) {
chan->fcs = L2CAP_FCS_NONE;
l2cap_add_conf_opt(&ptr, L2CAP_CONF_FCS, 1,
- chan->fcs);
+ chan->fcs, endptr - ptr);
}
break;
@@ -3281,17 +3285,17 @@
rfc.max_pdu_size = cpu_to_le16(size);
l2cap_add_conf_opt(&ptr, L2CAP_CONF_RFC, sizeof(rfc),
- (unsigned long) &rfc);
+ (unsigned long) &rfc, endptr - ptr);
if (test_bit(FLAG_EFS_ENABLE, &chan->flags))
- l2cap_add_opt_efs(&ptr, chan);
+ l2cap_add_opt_efs(&ptr, chan, endptr - ptr);
if (chan->conn->feat_mask & L2CAP_FEAT_FCS)
if (chan->fcs == L2CAP_FCS_NONE ||
test_bit(CONF_RECV_NO_FCS, &chan->conf_state)) {
chan->fcs = L2CAP_FCS_NONE;
l2cap_add_conf_opt(&ptr, L2CAP_CONF_FCS, 1,
- chan->fcs);
+ chan->fcs, endptr - ptr);
}
break;
}
@@ -3302,10 +3306,11 @@
return ptr - data;
}
-static int l2cap_parse_conf_req(struct l2cap_chan *chan, void *data)
+static int l2cap_parse_conf_req(struct l2cap_chan *chan, void *data, size_t data_size)
{
struct l2cap_conf_rsp *rsp = data;
void *ptr = rsp->data;
+ void *endptr = data + data_size;
void *req = chan->conf_req;
int len = chan->conf_len;
int type, hint, olen;
@@ -3407,7 +3412,7 @@
return -ECONNREFUSED;
l2cap_add_conf_opt(&ptr, L2CAP_CONF_RFC, sizeof(rfc),
- (unsigned long) &rfc);
+ (unsigned long) &rfc, endptr - ptr);
}
if (result == L2CAP_CONF_SUCCESS) {
@@ -3420,7 +3425,7 @@
chan->omtu = mtu;
set_bit(CONF_MTU_DONE, &chan->conf_state);
}
- l2cap_add_conf_opt(&ptr, L2CAP_CONF_MTU, 2, chan->omtu);
+ l2cap_add_conf_opt(&ptr, L2CAP_CONF_MTU, 2, chan->omtu, endptr - ptr);
if (remote_efs) {
if (chan->local_stype != L2CAP_SERV_NOTRAFIC &&
@@ -3434,7 +3439,7 @@
l2cap_add_conf_opt(&ptr, L2CAP_CONF_EFS,
sizeof(efs),
- (unsigned long) &efs);
+ (unsigned long) &efs, endptr - ptr);
} else {
/* Send PENDING Conf Rsp */
result = L2CAP_CONF_PENDING;
@@ -3467,7 +3472,7 @@
set_bit(CONF_MODE_DONE, &chan->conf_state);
l2cap_add_conf_opt(&ptr, L2CAP_CONF_RFC,
- sizeof(rfc), (unsigned long) &rfc);
+ sizeof(rfc), (unsigned long) &rfc, endptr - ptr);
if (test_bit(FLAG_EFS_ENABLE, &chan->flags)) {
chan->remote_id = efs.id;
@@ -3481,7 +3486,7 @@
le32_to_cpu(efs.sdu_itime);
l2cap_add_conf_opt(&ptr, L2CAP_CONF_EFS,
sizeof(efs),
- (unsigned long) &efs);
+ (unsigned long) &efs, endptr - ptr);
}
break;
@@ -3495,7 +3500,7 @@
set_bit(CONF_MODE_DONE, &chan->conf_state);
l2cap_add_conf_opt(&ptr, L2CAP_CONF_RFC, sizeof(rfc),
- (unsigned long) &rfc);
+ (unsigned long) &rfc, endptr - ptr);
break;
@@ -3517,10 +3522,11 @@
}
static int l2cap_parse_conf_rsp(struct l2cap_chan *chan, void *rsp, int len,
- void *data, u16 *result)
+ void *data, size_t size, u16 *result)
{
struct l2cap_conf_req *req = data;
void *ptr = req->data;
+ void *endptr = data + size;
int type, olen;
unsigned long val;
struct l2cap_conf_rfc rfc = { .mode = L2CAP_MODE_BASIC };
@@ -3538,13 +3544,13 @@
chan->imtu = L2CAP_DEFAULT_MIN_MTU;
} else
chan->imtu = val;
- l2cap_add_conf_opt(&ptr, L2CAP_CONF_MTU, 2, chan->imtu);
+ l2cap_add_conf_opt(&ptr, L2CAP_CONF_MTU, 2, chan->imtu, endptr - ptr);
break;
case L2CAP_CONF_FLUSH_TO:
chan->flush_to = val;
l2cap_add_conf_opt(&ptr, L2CAP_CONF_FLUSH_TO,
- 2, chan->flush_to);
+ 2, chan->flush_to, endptr - ptr);
break;
case L2CAP_CONF_RFC:
@@ -3558,13 +3564,13 @@
chan->fcs = 0;
l2cap_add_conf_opt(&ptr, L2CAP_CONF_RFC,
- sizeof(rfc), (unsigned long) &rfc);
+ sizeof(rfc), (unsigned long) &rfc, endptr - ptr);
break;
case L2CAP_CONF_EWS:
chan->ack_win = min_t(u16, val, chan->ack_win);
l2cap_add_conf_opt(&ptr, L2CAP_CONF_EWS, 2,
- chan->tx_win);
+ chan->tx_win, endptr - ptr);
break;
case L2CAP_CONF_EFS:
@@ -3577,7 +3583,7 @@
return -ECONNREFUSED;
l2cap_add_conf_opt(&ptr, L2CAP_CONF_EFS, sizeof(efs),
- (unsigned long) &efs);
+ (unsigned long) &efs, endptr - ptr);
break;
case L2CAP_CONF_FCS:
@@ -3682,7 +3688,7 @@
return;
l2cap_send_cmd(conn, l2cap_get_ident(conn), L2CAP_CONF_REQ,
- l2cap_build_conf_req(chan, buf), buf);
+ l2cap_build_conf_req(chan, buf, sizeof(buf)), buf);
chan->num_conf_req++;
}
@@ -3890,7 +3896,7 @@
u8 buf[128];
set_bit(CONF_REQ_SENT, &chan->conf_state);
l2cap_send_cmd(conn, l2cap_get_ident(conn), L2CAP_CONF_REQ,
- l2cap_build_conf_req(chan, buf), buf);
+ l2cap_build_conf_req(chan, buf, sizeof(buf)), buf);
chan->num_conf_req++;
}
@@ -3968,7 +3974,7 @@
break;
l2cap_send_cmd(conn, l2cap_get_ident(conn), L2CAP_CONF_REQ,
- l2cap_build_conf_req(chan, req), req);
+ l2cap_build_conf_req(chan, req, sizeof(req)), req);
chan->num_conf_req++;
break;
@@ -4080,7 +4086,7 @@
}
/* Complete config. */
- len = l2cap_parse_conf_req(chan, rsp);
+ len = l2cap_parse_conf_req(chan, rsp, sizeof(rsp));
if (len < 0) {
l2cap_send_disconn_req(chan, ECONNRESET);
goto unlock;
@@ -4114,7 +4120,7 @@
if (!test_and_set_bit(CONF_REQ_SENT, &chan->conf_state)) {
u8 buf[64];
l2cap_send_cmd(conn, l2cap_get_ident(conn), L2CAP_CONF_REQ,
- l2cap_build_conf_req(chan, buf), buf);
+ l2cap_build_conf_req(chan, buf, sizeof(buf)), buf);
chan->num_conf_req++;
}
@@ -4174,7 +4180,7 @@
char buf[64];
len = l2cap_parse_conf_rsp(chan, rsp->data, len,
- buf, &result);
+ buf, sizeof(buf), &result);
if (len < 0) {
l2cap_send_disconn_req(chan, ECONNRESET);
goto done;
@@ -4204,7 +4210,7 @@
/* throw out any old stored conf requests */
result = L2CAP_CONF_SUCCESS;
len = l2cap_parse_conf_rsp(chan, rsp->data, len,
- req, &result);
+ req, sizeof(req), &result);
if (len < 0) {
l2cap_send_disconn_req(chan, ECONNRESET);
goto done;
@@ -4781,7 +4787,7 @@
set_bit(CONF_REQ_SENT, &chan->conf_state);
l2cap_send_cmd(chan->conn, l2cap_get_ident(chan->conn),
L2CAP_CONF_REQ,
- l2cap_build_conf_req(chan, buf), buf);
+ l2cap_build_conf_req(chan, buf, sizeof(buf)), buf);
chan->num_conf_req++;
}
}
@@ -7457,7 +7463,7 @@
set_bit(CONF_REQ_SENT, &chan->conf_state);
l2cap_send_cmd(conn, l2cap_get_ident(conn),
L2CAP_CONF_REQ,
- l2cap_build_conf_req(chan, buf),
+ l2cap_build_conf_req(chan, buf, sizeof(buf)),
buf);
chan->num_conf_req++;
}
diff --git a/net/bridge/br_device.c b/net/bridge/br_device.c
index fcaa484..04eea2f 100644
--- a/net/bridge/br_device.c
+++ b/net/bridge/br_device.c
@@ -48,6 +48,9 @@
return NETDEV_TX_OK;
}
+#ifdef CONFIG_NET_SWITCHDEV
+ skb->offload_fwd_mark = 0;
+#endif
BR_INPUT_SKB_CB(skb)->brdev = dev;
skb_reset_mac_header(skb);
diff --git a/net/core/datagram.c b/net/core/datagram.c
index 58dfa23..4fa4011 100644
--- a/net/core/datagram.c
+++ b/net/core/datagram.c
@@ -351,7 +351,7 @@
if (flags & MSG_PEEK) {
err = -ENOENT;
spin_lock_bh(&sk->sk_receive_queue.lock);
- if (skb == skb_peek(&sk->sk_receive_queue)) {
+ if (skb->next) {
__skb_unlink(skb, &sk->sk_receive_queue);
atomic_dec(&skb->users);
err = 0;
diff --git a/net/core/dev.c b/net/core/dev.c
index 33cbbe6..bc129b0 100644
--- a/net/core/dev.c
+++ b/net/core/dev.c
@@ -5367,12 +5367,13 @@
* Find out if a device is linked to an upper device and return true in case
* it is. The caller must hold the RTNL lock.
*/
-static bool netdev_has_any_upper_dev(struct net_device *dev)
+bool netdev_has_any_upper_dev(struct net_device *dev)
{
ASSERT_RTNL();
return !list_empty(&dev->all_adj_list.upper);
}
+EXPORT_SYMBOL(netdev_has_any_upper_dev);
/**
* netdev_master_upper_dev_get - Get master upper device
diff --git a/net/ieee802154/6lowpan/reassembly.c b/net/ieee802154/6lowpan/reassembly.c
index 30d875d..f85b08b 100644
--- a/net/ieee802154/6lowpan/reassembly.c
+++ b/net/ieee802154/6lowpan/reassembly.c
@@ -580,19 +580,14 @@
{
struct netns_ieee802154_lowpan *ieee802154_lowpan =
net_ieee802154_lowpan(net);
- int res;
ieee802154_lowpan->frags.high_thresh = IPV6_FRAG_HIGH_THRESH;
ieee802154_lowpan->frags.low_thresh = IPV6_FRAG_LOW_THRESH;
ieee802154_lowpan->frags.timeout = IPV6_FRAG_TIMEOUT;
- res = inet_frags_init_net(&ieee802154_lowpan->frags);
- if (res)
- return res;
- res = lowpan_frags_ns_sysctl_register(net);
- if (res)
- inet_frags_uninit_net(&ieee802154_lowpan->frags);
- return res;
+ inet_frags_init_net(&ieee802154_lowpan->frags);
+
+ return lowpan_frags_ns_sysctl_register(net);
}
static void __net_exit lowpan_frags_exit_net(struct net *net)
diff --git a/net/ipv4/inet_fragment.c b/net/ipv4/inet_fragment.c
index b5e9317..631c0d0 100644
--- a/net/ipv4/inet_fragment.c
+++ b/net/ipv4/inet_fragment.c
@@ -234,10 +234,8 @@
cond_resched();
if (read_seqretry(&f->rnd_seqlock, seq) ||
- percpu_counter_sum(&nf->mem))
+ sum_frag_mem_limit(nf))
goto evict_again;
-
- percpu_counter_destroy(&nf->mem);
}
EXPORT_SYMBOL(inet_frags_exit_net);
diff --git a/net/ipv4/ip_fragment.c b/net/ipv4/ip_fragment.c
index bbe7f72..453db95 100644
--- a/net/ipv4/ip_fragment.c
+++ b/net/ipv4/ip_fragment.c
@@ -835,8 +835,6 @@
static int __net_init ipv4_frags_init_net(struct net *net)
{
- int res;
-
/* Fragment cache limits.
*
* The fragment memory accounting code, (tries to) account for
@@ -862,13 +860,9 @@
net->ipv4.frags.max_dist = 64;
- res = inet_frags_init_net(&net->ipv4.frags);
- if (res)
- return res;
- res = ip4_frags_ns_ctl_register(net);
- if (res)
- inet_frags_uninit_net(&net->ipv4.frags);
- return res;
+ inet_frags_init_net(&net->ipv4.frags);
+
+ return ip4_frags_ns_ctl_register(net);
}
static void __net_exit ipv4_frags_exit_net(struct net *net)
diff --git a/net/ipv4/ip_tunnel.c b/net/ipv4/ip_tunnel.c
index 5719d6b..bd7f183 100644
--- a/net/ipv4/ip_tunnel.c
+++ b/net/ipv4/ip_tunnel.c
@@ -609,8 +609,8 @@
ip_rt_put(rt);
goto tx_dropped;
}
- iptunnel_xmit(NULL, rt, skb, fl4.saddr, fl4.daddr, proto, key->tos,
- key->ttl, df, !net_eq(tunnel->net, dev_net(dev)));
+ iptunnel_xmit(NULL, rt, skb, fl4.saddr, fl4.daddr, proto, tos, ttl,
+ df, !net_eq(tunnel->net, dev_net(dev)));
return;
tx_error:
dev->stats.tx_errors++;
diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c
index 7c90130..4946e8f 100644
--- a/net/ipv4/tcp.c
+++ b/net/ipv4/tcp.c
@@ -2306,6 +2306,10 @@
tcp_set_ca_state(sk, TCP_CA_Open);
tcp_clear_retrans(tp);
inet_csk_delack_init(sk);
+ /* Initialize rcv_mss to TCP_MIN_MSS to avoid division by 0
+ * issue in __tcp_select_window()
+ */
+ icsk->icsk_ack.rcv_mss = TCP_MIN_MSS;
tcp_init_send_head(sk);
memset(&tp->rx_opt, 0, sizeof(tp->rx_opt));
__sk_dst_reset(sk);
diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c
index fe5305a..371312b 100644
--- a/net/ipv6/addrconf.c
+++ b/net/ipv6/addrconf.c
@@ -5485,7 +5485,7 @@
* our DAD process, so we don't need
* to do it again
*/
- if (!(ifp->rt->rt6i_node))
+ if (!rcu_access_pointer(ifp->rt->rt6i_node))
ip6_ins_rt(ifp->rt);
if (ifp->idev->cnf.forwarding)
addrconf_join_anycast(ifp);
diff --git a/net/ipv6/ip6_fib.c b/net/ipv6/ip6_fib.c
index ff38959..5da8649 100644
--- a/net/ipv6/ip6_fib.c
+++ b/net/ipv6/ip6_fib.c
@@ -148,11 +148,23 @@
return fn;
}
-static void node_free(struct fib6_node *fn)
+static void node_free_immediate(struct fib6_node *fn)
{
kmem_cache_free(fib6_node_kmem, fn);
}
+static void node_free_rcu(struct rcu_head *head)
+{
+ struct fib6_node *fn = container_of(head, struct fib6_node, rcu);
+
+ kmem_cache_free(fib6_node_kmem, fn);
+}
+
+static void node_free(struct fib6_node *fn)
+{
+ call_rcu(&fn->rcu, node_free_rcu);
+}
+
static void rt6_rcu_free(struct rt6_info *rt)
{
call_rcu(&rt->dst.rcu_head, dst_rcu_free);
@@ -189,6 +201,12 @@
}
}
+static void fib6_free_table(struct fib6_table *table)
+{
+ inetpeer_invalidate_tree(&table->tb6_peers);
+ kfree(table);
+}
+
static void fib6_link_table(struct net *net, struct fib6_table *tb)
{
unsigned int h;
@@ -589,9 +607,9 @@
if (!in || !ln) {
if (in)
- node_free(in);
+ node_free_immediate(in);
if (ln)
- node_free(ln);
+ node_free_immediate(ln);
return ERR_PTR(-ENOMEM);
}
@@ -862,7 +880,7 @@
rt->dst.rt6_next = iter;
*ins = rt;
- rt->rt6i_node = fn;
+ rcu_assign_pointer(rt->rt6i_node, fn);
atomic_inc(&rt->rt6i_ref);
inet6_rt_notify(RTM_NEWROUTE, rt, info, nlflags);
info->nl_net->ipv6.rt6_stats->fib_rt_entries++;
@@ -887,7 +905,7 @@
return err;
*ins = rt;
- rt->rt6i_node = fn;
+ rcu_assign_pointer(rt->rt6i_node, fn);
rt->dst.rt6_next = iter->dst.rt6_next;
atomic_inc(&rt->rt6i_ref);
inet6_rt_notify(RTM_NEWROUTE, rt, info, NLM_F_REPLACE);
@@ -1020,7 +1038,7 @@
root, and then (in failure) stale node
in main tree.
*/
- node_free(sfn);
+ node_free_immediate(sfn);
err = PTR_ERR(sn);
goto failure;
}
@@ -1447,8 +1465,9 @@
int fib6_del(struct rt6_info *rt, struct nl_info *info)
{
+ struct fib6_node *fn = rcu_dereference_protected(rt->rt6i_node,
+ lockdep_is_held(&rt->rt6i_table->tb6_lock));
struct net *net = info->nl_net;
- struct fib6_node *fn = rt->rt6i_node;
struct rt6_info **rtp;
#if RT6_DEBUG >= 2
@@ -1637,7 +1656,9 @@
if (res) {
#if RT6_DEBUG >= 2
pr_debug("%s: del failed: rt=%p@%p err=%d\n",
- __func__, rt, rt->rt6i_node, res);
+ __func__, rt,
+ rcu_access_pointer(rt->rt6i_node),
+ res);
#endif
continue;
}
@@ -1878,15 +1899,22 @@
static void fib6_net_exit(struct net *net)
{
+ unsigned int i;
+
rt6_ifdown(net, NULL);
del_timer_sync(&net->ipv6.ip6_fib_timer);
-#ifdef CONFIG_IPV6_MULTIPLE_TABLES
- inetpeer_invalidate_tree(&net->ipv6.fib6_local_tbl->tb6_peers);
- kfree(net->ipv6.fib6_local_tbl);
-#endif
- inetpeer_invalidate_tree(&net->ipv6.fib6_main_tbl->tb6_peers);
- kfree(net->ipv6.fib6_main_tbl);
+ for (i = 0; i < FIB6_TABLE_HASHSZ; i++) {
+ struct hlist_head *head = &net->ipv6.fib_table_hash[i];
+ struct hlist_node *tmp;
+ struct fib6_table *tb;
+
+ hlist_for_each_entry_safe(tb, tmp, head, tb6_hlist) {
+ hlist_del(&tb->tb6_hlist);
+ fib6_free_table(tb);
+ }
+ }
+
kfree(net->ipv6.fib_table_hash);
kfree(net->ipv6.rt6_stats);
}
diff --git a/net/ipv6/ip6_gre.c b/net/ipv6/ip6_gre.c
index c329a15..ae87b9a 100644
--- a/net/ipv6/ip6_gre.c
+++ b/net/ipv6/ip6_gre.c
@@ -432,7 +432,9 @@
}
break;
case ICMPV6_PKT_TOOBIG:
- mtu = be32_to_cpu(info) - offset;
+ mtu = be32_to_cpu(info) - offset - t->tun_hlen;
+ if (t->dev->type == ARPHRD_ETHER)
+ mtu -= ETH_HLEN;
if (mtu < IPV6_MIN_MTU)
mtu = IPV6_MIN_MTU;
t->dev->mtu = mtu;
diff --git a/net/ipv6/netfilter/nf_conntrack_reasm.c b/net/ipv6/netfilter/nf_conntrack_reasm.c
index 986d4ca..b263bf3 100644
--- a/net/ipv6/netfilter/nf_conntrack_reasm.c
+++ b/net/ipv6/netfilter/nf_conntrack_reasm.c
@@ -622,18 +622,12 @@
static int nf_ct_net_init(struct net *net)
{
- int res;
-
net->nf_frag.frags.high_thresh = IPV6_FRAG_HIGH_THRESH;
net->nf_frag.frags.low_thresh = IPV6_FRAG_LOW_THRESH;
net->nf_frag.frags.timeout = IPV6_FRAG_TIMEOUT;
- res = inet_frags_init_net(&net->nf_frag.frags);
- if (res)
- return res;
- res = nf_ct_frag6_sysctl_register(net);
- if (res)
- inet_frags_uninit_net(&net->nf_frag.frags);
- return res;
+ inet_frags_init_net(&net->nf_frag.frags);
+
+ return nf_ct_frag6_sysctl_register(net);
}
static void nf_ct_net_exit(struct net *net)
diff --git a/net/ipv6/output_core.c b/net/ipv6/output_core.c
index abb2c30..a338bbc 100644
--- a/net/ipv6/output_core.c
+++ b/net/ipv6/output_core.c
@@ -86,7 +86,6 @@
while (offset <= packet_len) {
struct ipv6_opt_hdr *exthdr;
- unsigned int len;
switch (**nexthdr) {
@@ -112,10 +111,9 @@
exthdr = (struct ipv6_opt_hdr *)(skb_network_header(skb) +
offset);
- len = ipv6_optlen(exthdr);
- if (len + offset >= IPV6_MAXPLEN)
+ offset += ipv6_optlen(exthdr);
+ if (offset > IPV6_MAXPLEN)
return -EINVAL;
- offset += len;
*nexthdr = &exthdr->nexthdr;
}
diff --git a/net/ipv6/reassembly.c b/net/ipv6/reassembly.c
index 3815e85..e585c0a 100644
--- a/net/ipv6/reassembly.c
+++ b/net/ipv6/reassembly.c
@@ -709,19 +709,13 @@
static int __net_init ipv6_frags_init_net(struct net *net)
{
- int res;
-
net->ipv6.frags.high_thresh = IPV6_FRAG_HIGH_THRESH;
net->ipv6.frags.low_thresh = IPV6_FRAG_LOW_THRESH;
net->ipv6.frags.timeout = IPV6_FRAG_TIMEOUT;
- res = inet_frags_init_net(&net->ipv6.frags);
- if (res)
- return res;
- res = ip6_frags_ns_sysctl_register(net);
- if (res)
- inet_frags_uninit_net(&net->ipv6.frags);
- return res;
+ inet_frags_init_net(&net->ipv6.frags);
+
+ return ip6_frags_ns_sysctl_register(net);
}
static void __net_exit ipv6_frags_exit_net(struct net *net)
diff --git a/net/ipv6/route.c b/net/ipv6/route.c
index d8123f6..5acd855 100644
--- a/net/ipv6/route.c
+++ b/net/ipv6/route.c
@@ -1261,7 +1261,9 @@
static struct dst_entry *rt6_check(struct rt6_info *rt, u32 cookie)
{
- if (!rt->rt6i_node || (rt->rt6i_node->fn_sernum != cookie))
+ u32 rt_cookie = 0;
+
+ if (!rt6_get_cookie_safe(rt, &rt_cookie) || rt_cookie != cookie)
return NULL;
if (rt6_check_expired(rt))
@@ -1329,8 +1331,14 @@
if (rt->rt6i_flags & RTF_CACHE) {
dst_hold(&rt->dst);
ip6_del_rt(rt);
- } else if (rt->rt6i_node && (rt->rt6i_flags & RTF_DEFAULT)) {
- rt->rt6i_node->fn_sernum = -1;
+ } else {
+ struct fib6_node *fn;
+
+ rcu_read_lock();
+ fn = rcu_dereference(rt->rt6i_node);
+ if (fn && (rt->rt6i_flags & RTF_DEFAULT))
+ fn->fn_sernum = -1;
+ rcu_read_unlock();
}
}
}
@@ -1347,7 +1355,8 @@
static bool rt6_cache_allowed_for_pmtu(const struct rt6_info *rt)
{
return !(rt->rt6i_flags & RTF_CACHE) &&
- (rt->rt6i_flags & RTF_PCPU || rt->rt6i_node);
+ (rt->rt6i_flags & RTF_PCPU ||
+ rcu_access_pointer(rt->rt6i_node));
}
static void __ip6_rt_update_pmtu(struct dst_entry *dst, const struct sock *sk,
diff --git a/net/kcm/kcmsock.c b/net/kcm/kcmsock.c
index fecad10..7eb0e8f 100644
--- a/net/kcm/kcmsock.c
+++ b/net/kcm/kcmsock.c
@@ -1381,6 +1381,10 @@
if (!csk)
return -EINVAL;
+ /* We must prevent loops or risk deadlock ! */
+ if (csk->sk_family == PF_KCM)
+ return -EOPNOTSUPP;
+
psock = kmem_cache_zalloc(kcm_psockp, GFP_KERNEL);
if (!psock)
return -ENOMEM;
diff --git a/net/netfilter/xt_qtaguid.c b/net/netfilter/xt_qtaguid.c
index ade9306..1cf2874 100644
--- a/net/netfilter/xt_qtaguid.c
+++ b/net/netfilter/xt_qtaguid.c
@@ -1772,7 +1772,7 @@
kgid_t gid_max = make_kgid(&init_user_ns, info->gid_max);
set_sk_callback_lock = true;
read_lock_bh(&sk->sk_callback_lock);
- MT_DEBUG("qtaguid[%d]: sk=%p->sk_socket=%p->file=%p\n",
+ MT_DEBUG("qtaguid[%d]: sk=%pK->sk_socket=%pK->file=%pK\n",
par->hooknum, sk, sk->sk_socket,
sk->sk_socket ? sk->sk_socket->file : (void *)-1LL);
filp = sk->sk_socket ? sk->sk_socket->file : NULL;
diff --git a/net/netfilter/xt_socket.c b/net/netfilter/xt_socket.c
index a52fbaf..ec87467 100644
--- a/net/netfilter/xt_socket.c
+++ b/net/netfilter/xt_socket.c
@@ -244,7 +244,7 @@
transparent = xt_socket_sk_is_transparent(sk);
if (info->flags & XT_SOCKET_RESTORESKMARK && !wildcard &&
- transparent)
+ transparent && sk_fullsock(sk))
pskb->mark = sk->sk_mark;
sock_gen_put(sk);
@@ -433,7 +433,7 @@
transparent = xt_socket_sk_is_transparent(sk);
if (info->flags & XT_SOCKET_RESTORESKMARK && !wildcard &&
- transparent)
+ transparent && sk_fullsock(sk))
pskb->mark = sk->sk_mark;
if (sk != skb->sk)
diff --git a/net/packet/af_packet.c b/net/packet/af_packet.c
index ae7bfd2..35ba4b6 100644
--- a/net/packet/af_packet.c
+++ b/net/packet/af_packet.c
@@ -2151,6 +2151,7 @@
struct timespec ts;
__u32 ts_status;
bool is_drop_n_account = false;
+ bool do_vnet = false;
/* struct tpacket{2,3}_hdr is aligned to a multiple of TPACKET_ALIGNMENT.
* We may add members to them until current aligned size without forcing
@@ -2201,8 +2202,10 @@
netoff = TPACKET_ALIGN(po->tp_hdrlen +
(maclen < 16 ? 16 : maclen)) +
po->tp_reserve;
- if (po->has_vnet_hdr)
+ if (po->has_vnet_hdr) {
netoff += sizeof(struct virtio_net_hdr);
+ do_vnet = true;
+ }
macoff = netoff - maclen;
}
if (po->tp_version <= TPACKET_V2) {
@@ -2219,8 +2222,10 @@
skb_set_owner_r(copy_skb, sk);
}
snaplen = po->rx_ring.frame_size - macoff;
- if ((int)snaplen < 0)
+ if ((int)snaplen < 0) {
snaplen = 0;
+ do_vnet = false;
+ }
}
} else if (unlikely(macoff + snaplen >
GET_PBDQC_FROM_RB(&po->rx_ring)->max_frame_len)) {
@@ -2233,6 +2238,7 @@
if (unlikely((int)snaplen < 0)) {
snaplen = 0;
macoff = GET_PBDQC_FROM_RB(&po->rx_ring)->max_frame_len;
+ do_vnet = false;
}
}
spin_lock(&sk->sk_receive_queue.lock);
@@ -2258,7 +2264,7 @@
}
spin_unlock(&sk->sk_receive_queue.lock);
- if (po->has_vnet_hdr) {
+ if (do_vnet) {
if (__packet_rcv_vnet(skb, h.raw + macoff -
sizeof(struct virtio_net_hdr))) {
spin_lock(&sk->sk_receive_queue.lock);
diff --git a/net/rmnet_data/rmnet_data_handlers.c b/net/rmnet_data/rmnet_data_handlers.c
index 35be79e..57646ef 100644
--- a/net/rmnet_data/rmnet_data_handlers.c
+++ b/net/rmnet_data/rmnet_data_handlers.c
@@ -537,6 +537,7 @@
{
int required_headroom, additional_header_length, ckresult;
struct rmnet_map_header_s *map_header;
+ int non_linear_skb;
additional_header_length = 0;
@@ -565,9 +566,11 @@
rmnet_stats_ul_checksum(ckresult);
}
+ non_linear_skb = (orig_dev->features & NETIF_F_GSO) &&
+ skb_is_nonlinear(skb);
+
if ((!(config->egress_data_format &
- RMNET_EGRESS_FORMAT_AGGREGATION)) ||
- ((orig_dev->features & NETIF_F_GSO) && skb_is_nonlinear(skb)))
+ RMNET_EGRESS_FORMAT_AGGREGATION)) || non_linear_skb)
map_header = rmnet_map_add_map_header
(skb, additional_header_length, RMNET_MAP_NO_PAD_BYTES);
else
@@ -589,7 +592,8 @@
skb->protocol = htons(ETH_P_MAP);
- if (config->egress_data_format & RMNET_EGRESS_FORMAT_AGGREGATION) {
+ if ((config->egress_data_format & RMNET_EGRESS_FORMAT_AGGREGATION) &&
+ !non_linear_skb) {
rmnet_map_aggregate(skb, config);
return RMNET_MAP_CONSUMED;
}
diff --git a/net/sctp/sctp_diag.c b/net/sctp/sctp_diag.c
index 048954e..e8f56b7 100644
--- a/net/sctp/sctp_diag.c
+++ b/net/sctp/sctp_diag.c
@@ -70,7 +70,8 @@
info = nla_data(attr);
list_for_each_entry_rcu(laddr, address_list, list) {
- memcpy(info, &laddr->a, addrlen);
+ memcpy(info, &laddr->a, sizeof(laddr->a));
+ memset(info + sizeof(laddr->a), 0, addrlen - sizeof(laddr->a));
info += addrlen;
}
@@ -93,7 +94,9 @@
info = nla_data(attr);
list_for_each_entry(from, &asoc->peer.transport_addr_list,
transports) {
- memcpy(info, &from->ipaddr, addrlen);
+ memcpy(info, &from->ipaddr, sizeof(from->ipaddr));
+ memset(info + sizeof(from->ipaddr), 0,
+ addrlen - sizeof(from->ipaddr));
info += addrlen;
}
diff --git a/net/sctp/socket.c b/net/sctp/socket.c
index 9647e31..3ef7252 100644
--- a/net/sctp/socket.c
+++ b/net/sctp/socket.c
@@ -4373,8 +4373,7 @@
info->sctpi_ictrlchunks = asoc->stats.ictrlchunks;
prim = asoc->peer.primary_path;
- memcpy(&info->sctpi_p_address, &prim->ipaddr,
- sizeof(struct sockaddr_storage));
+ memcpy(&info->sctpi_p_address, &prim->ipaddr, sizeof(prim->ipaddr));
info->sctpi_p_state = prim->state;
info->sctpi_p_cwnd = prim->cwnd;
info->sctpi_p_srtt = prim->srtt;
diff --git a/net/sctp/ulpqueue.c b/net/sctp/ulpqueue.c
index 84d0fda..d3cfbf2 100644
--- a/net/sctp/ulpqueue.c
+++ b/net/sctp/ulpqueue.c
@@ -265,7 +265,8 @@
sctp_ulpq_clear_pd(ulpq);
if (queue == &sk->sk_receive_queue && !sp->data_ready_signalled) {
- sp->data_ready_signalled = 1;
+ if (!sock_owned_by_user(sk))
+ sp->data_ready_signalled = 1;
sk->sk_data_ready(sk);
}
return 1;
diff --git a/security/commoncap.c b/security/commoncap.c
index 3e44d01..b5aca42 100644
--- a/security/commoncap.c
+++ b/security/commoncap.c
@@ -58,7 +58,7 @@
}
/**
- * cap_capable - Determine whether a task has a particular effective capability
+ * __cap_capable - Determine whether a task has a particular effective capability
* @cred: The credentials to use
* @ns: The user namespace in which we need the capability
* @cap: The capability to check for
@@ -72,18 +72,11 @@
* cap_has_capability() returns 0 when a task has a capability, but the
* kernel's capable() and has_capability() returns 1 for this case.
*/
-int cap_capable(const struct cred *cred, struct user_namespace *targ_ns,
+int __cap_capable(const struct cred *cred, struct user_namespace *targ_ns,
int cap, int audit)
{
struct user_namespace *ns = targ_ns;
-#ifdef CONFIG_ANDROID_PARANOID_NETWORK
- if (cap == CAP_NET_RAW && in_egroup_p(AID_NET_RAW))
- return 0;
- if (cap == CAP_NET_ADMIN && in_egroup_p(AID_NET_ADMIN))
- return 0;
-#endif
-
/* See if cred has the capability in the target user namespace
* by examining the target user namespace and all of the target
* user namespace's parents.
@@ -114,6 +107,27 @@
/* We never get here */
}
+int cap_capable(const struct cred *cred, struct user_namespace *targ_ns,
+ int cap, int audit)
+{
+ int ret = __cap_capable(cred, targ_ns, cap, audit);
+
+#ifdef CONFIG_ANDROID_PARANOID_NETWORK
+ if (ret != 0 && cap == CAP_NET_RAW && in_egroup_p(AID_NET_RAW)) {
+ printk("Process %s granted CAP_NET_RAW from Android group net_raw.\n", current->comm);
+ printk(" Please update the .rc file to explictly set 'capabilities NET_RAW'\n");
+ printk(" Implicit grants are deprecated and will be removed in the future.\n");
+ return 0;
+ }
+ if (ret != 0 && cap == CAP_NET_ADMIN && in_egroup_p(AID_NET_ADMIN)) {
+ printk("Process %s granted CAP_NET_ADMIN from Android group net_admin.\n", current->comm);
+ printk(" Please update the .rc file to explictly set 'capabilities NET_ADMIN'\n");
+ printk(" Implicit grants are deprecated and will be removed in the future.\n");
+ return 0;
+ }
+#endif
+ return ret;
+}
/**
* cap_settime - Determine whether the current process may set the system clock
* @ts: The time to set
diff --git a/sound/isa/msnd/msnd_midi.c b/sound/isa/msnd/msnd_midi.c
index ffc67fd..58e59cd 100644
--- a/sound/isa/msnd/msnd_midi.c
+++ b/sound/isa/msnd/msnd_midi.c
@@ -120,24 +120,24 @@
unsigned long flags;
struct snd_msndmidi *mpu = mpuv;
void *pwMIDQData = mpu->dev->mappedbase + MIDQ_DATA_BUFF;
+ u16 head, tail, size;
spin_lock_irqsave(&mpu->input_lock, flags);
- while (readw(mpu->dev->MIDQ + JQS_wTail) !=
- readw(mpu->dev->MIDQ + JQS_wHead)) {
- u16 wTmp, val;
- val = readw(pwMIDQData + 2 * readw(mpu->dev->MIDQ + JQS_wHead));
+ head = readw(mpu->dev->MIDQ + JQS_wHead);
+ tail = readw(mpu->dev->MIDQ + JQS_wTail);
+ size = readw(mpu->dev->MIDQ + JQS_wSize);
+ if (head > size || tail > size)
+ goto out;
+ while (head != tail) {
+ unsigned char val = readw(pwMIDQData + 2 * head);
- if (test_bit(MSNDMIDI_MODE_BIT_INPUT_TRIGGER,
- &mpu->mode))
- snd_rawmidi_receive(mpu->substream_input,
- (unsigned char *)&val, 1);
-
- wTmp = readw(mpu->dev->MIDQ + JQS_wHead) + 1;
- if (wTmp > readw(mpu->dev->MIDQ + JQS_wSize))
- writew(0, mpu->dev->MIDQ + JQS_wHead);
- else
- writew(wTmp, mpu->dev->MIDQ + JQS_wHead);
+ if (test_bit(MSNDMIDI_MODE_BIT_INPUT_TRIGGER, &mpu->mode))
+ snd_rawmidi_receive(mpu->substream_input, &val, 1);
+ if (++head > size)
+ head = 0;
+ writew(head, mpu->dev->MIDQ + JQS_wHead);
}
+ out:
spin_unlock_irqrestore(&mpu->input_lock, flags);
}
EXPORT_SYMBOL(snd_msndmidi_input_read);
diff --git a/sound/isa/msnd/msnd_pinnacle.c b/sound/isa/msnd/msnd_pinnacle.c
index 4c07266..a31ea6c 100644
--- a/sound/isa/msnd/msnd_pinnacle.c
+++ b/sound/isa/msnd/msnd_pinnacle.c
@@ -170,23 +170,24 @@
{
struct snd_msnd *chip = dev_id;
void *pwDSPQData = chip->mappedbase + DSPQ_DATA_BUFF;
+ u16 head, tail, size;
/* Send ack to DSP */
/* inb(chip->io + HP_RXL); */
/* Evaluate queued DSP messages */
- while (readw(chip->DSPQ + JQS_wTail) != readw(chip->DSPQ + JQS_wHead)) {
- u16 wTmp;
-
- snd_msnd_eval_dsp_msg(chip,
- readw(pwDSPQData + 2 * readw(chip->DSPQ + JQS_wHead)));
-
- wTmp = readw(chip->DSPQ + JQS_wHead) + 1;
- if (wTmp > readw(chip->DSPQ + JQS_wSize))
- writew(0, chip->DSPQ + JQS_wHead);
- else
- writew(wTmp, chip->DSPQ + JQS_wHead);
+ head = readw(chip->DSPQ + JQS_wHead);
+ tail = readw(chip->DSPQ + JQS_wTail);
+ size = readw(chip->DSPQ + JQS_wSize);
+ if (head > size || tail > size)
+ goto out;
+ while (head != tail) {
+ snd_msnd_eval_dsp_msg(chip, readw(pwDSPQData + 2 * head));
+ if (++head > size)
+ head = 0;
+ writew(head, chip->DSPQ + JQS_wHead);
}
+ out:
/* Send ack to DSP */
inb(chip->io + HP_RXL);
return IRQ_HANDLED;
diff --git a/sound/usb/pcm.c b/sound/usb/pcm.c
index 8279009..dd81574 100644
--- a/sound/usb/pcm.c
+++ b/sound/usb/pcm.c
@@ -39,6 +39,8 @@
#define SUBSTREAM_FLAG_DATA_EP_STARTED 0
#define SUBSTREAM_FLAG_SYNC_EP_STARTED 1
+#define MAX_SETALT_TIMEOUT_MS 1000
+
/* return the estimated delay based on USB frame counters */
snd_pcm_uframes_t snd_usb_pcm_delay(struct snd_usb_substream *subs,
unsigned int rate)
@@ -508,7 +510,8 @@
/* close the old interface */
if (subs->interface >= 0 && subs->interface != fmt->iface) {
- err = usb_set_interface(subs->dev, subs->interface, 0);
+ err = usb_set_interface_timeout(subs->dev, subs->interface, 0,
+ MAX_SETALT_TIMEOUT_MS);
if (err < 0) {
dev_err(&dev->dev,
"%d:%d: return to setting 0 failed (%d)\n",
@@ -527,7 +530,8 @@
if (err < 0)
return -EIO;
- err = usb_set_interface(dev, fmt->iface, fmt->altsetting);
+ err = usb_set_interface_timeout(dev, fmt->iface,
+ fmt->altsetting, MAX_SETALT_TIMEOUT_MS);
if (err < 0) {
dev_err(&dev->dev,
"%d:%d: usb_set_interface failed (%d)\n",
@@ -574,7 +578,8 @@
if (!enable) {
if (subs->interface >= 0) {
- usb_set_interface(subs->dev, subs->interface, 0);
+ usb_set_interface_timeout(subs->dev, subs->interface, 0,
+ MAX_SETALT_TIMEOUT_MS);
subs->altset_idx = 0;
subs->interface = -1;
subs->cur_audiofmt = NULL;
diff --git a/tools/testing/selftests/x86/fsgsbase.c b/tools/testing/selftests/x86/fsgsbase.c
index 5b2b4b3..9b4610c 100644
--- a/tools/testing/selftests/x86/fsgsbase.c
+++ b/tools/testing/selftests/x86/fsgsbase.c
@@ -285,9 +285,12 @@
}
}
-static void set_gs_and_switch_to(unsigned long local, unsigned long remote)
+static void set_gs_and_switch_to(unsigned long local,
+ unsigned short force_sel,
+ unsigned long remote)
{
unsigned long base;
+ unsigned short sel_pre_sched, sel_post_sched;
bool hard_zero = false;
if (local == HARD_ZERO) {
@@ -297,6 +300,8 @@
printf("[RUN]\tARCH_SET_GS(0x%lx)%s, then schedule to 0x%lx\n",
local, hard_zero ? " and clear gs" : "", remote);
+ if (force_sel)
+ printf("\tBefore schedule, set selector to 0x%hx\n", force_sel);
if (syscall(SYS_arch_prctl, ARCH_SET_GS, local) != 0)
err(1, "ARCH_SET_GS");
if (hard_zero)
@@ -307,18 +312,35 @@
printf("[FAIL]\tGSBASE wasn't set as expected\n");
}
+ if (force_sel) {
+ asm volatile ("mov %0, %%gs" : : "rm" (force_sel));
+ sel_pre_sched = force_sel;
+ local = read_base(GS);
+
+ /*
+ * Signal delivery seems to mess up weird selectors. Put it
+ * back.
+ */
+ asm volatile ("mov %0, %%gs" : : "rm" (force_sel));
+ } else {
+ asm volatile ("mov %%gs, %0" : "=rm" (sel_pre_sched));
+ }
+
remote_base = remote;
ftx = 1;
syscall(SYS_futex, &ftx, FUTEX_WAKE, 0, NULL, NULL, 0);
while (ftx != 0)
syscall(SYS_futex, &ftx, FUTEX_WAIT, 1, NULL, NULL, 0);
+ asm volatile ("mov %%gs, %0" : "=rm" (sel_post_sched));
base = read_base(GS);
- if (base == local) {
- printf("[OK]\tGSBASE remained 0x%lx\n", local);
+ if (base == local && sel_pre_sched == sel_post_sched) {
+ printf("[OK]\tGS/BASE remained 0x%hx/0x%lx\n",
+ sel_pre_sched, local);
} else {
nerrs++;
- printf("[FAIL]\tGSBASE changed to 0x%lx\n", base);
+ printf("[FAIL]\tGS/BASE changed from 0x%hx/0x%lx to 0x%hx/0x%lx\n",
+ sel_pre_sched, local, sel_post_sched, base);
}
}
@@ -381,8 +403,15 @@
for (int local = 0; local < 4; local++) {
for (int remote = 0; remote < 4; remote++) {
- set_gs_and_switch_to(bases_with_hard_zero[local],
- bases_with_hard_zero[remote]);
+ for (unsigned short s = 0; s < 5; s++) {
+ unsigned short sel = s;
+ if (s == 4)
+ asm ("mov %%ss, %0" : "=rm" (sel));
+ set_gs_and_switch_to(
+ bases_with_hard_zero[local],
+ sel,
+ bases_with_hard_zero[remote]);
+ }
}
}