Merge "drm/msm/sde: update plane states properly during atomic check" into msm-4.9
diff --git a/Documentation/devicetree/bindings/arm/coresight.txt b/Documentation/devicetree/bindings/arm/coresight.txt
index 53e4295..fe53218 100644
--- a/Documentation/devicetree/bindings/arm/coresight.txt
+++ b/Documentation/devicetree/bindings/arm/coresight.txt
@@ -73,9 +73,6 @@
AMBA markee):
- "arm,coresight-replicator"
- "qcom,coresight-csr"
- - "arm,coresight-cti"
- - "qcom,coresight-tpda"
- - "qcom,coresight-tpdm"
- "qcom,coresight-remote-etm"
- "qcom,coresight-hwevent"
- "qcom,coresight-dummy"
@@ -264,7 +261,7 @@
};
tpda_mss: tpda@7043000 {
- compatible = "qcom,coresight-tpda";
+ compatible = "qcom,coresight-tpda", "arm,primecell";
reg = <0x7043000 0x1000>;
reg-names = "tpda-base";
@@ -274,9 +271,8 @@
qcom,dsb-elem-size = <0 32>;
qcom,cmb-elem-size = <0 32>;
- clocks = <&clock_gcc clk_qdss_clk>,
- <&clock_gcc clk_qdss_a_clk>;
- clock-names = "core_clk", "core_a_clk";
+ clocks = <&clock_aop clk_qdss_clk>;
+ clock-names = "apb_pclk";
ports {
#address-cells = <1>;
@@ -345,15 +341,14 @@
};
tpdm_mss: tpdm@7042000 {
- compatible = "qcom,coresight-tpdm";
+ compatible = "qcom,coresight-tpdm", "arm,primecell";
reg = <0x7042000 0x1000>;
reg-names = "tpdm-base";
coresight-name = "coresight-tpdm-mss";
- clocks = <&clock_gcc clk_qdss_clk>,
- <&clock_gcc clk_qdss_a_clk>;
- clock-names = "core_clk", "core_a_clk";
+ clocks = <&clock_aop qdss_clk>;
+ clock-names = "apb_pclk";
port{
tpdm_mss_out_tpda_mss: endpoint {
@@ -364,15 +359,14 @@
4. CTIs
cti0: cti@6010000 {
- compatible = "arm,coresight-cti";
+ compatible = "arm,coresight-cti", "arm,primecell";
reg = <0x6010000 0x1000>;
reg-names = "cti-base";
coresight-name = "coresight-cti0";
- clocks = <&clock_gcc clk_qdss_clk>,
- <&clock_gcc clk_qdss_a_clk>;
- clock-names = "core_clk", "core_a_clk";
+ clocks = <&clock_aop qdss_clk>;
+ clock-names = "apb_pclk";
};
[1]. There is currently two version of STM: STM32 and STM500. Both
diff --git a/Documentation/devicetree/bindings/arm/msm/imem.txt b/Documentation/devicetree/bindings/arm/msm/imem.txt
index d1f8ce1..eaa7146b 100644
--- a/Documentation/devicetree/bindings/arm/msm/imem.txt
+++ b/Documentation/devicetree/bindings/arm/msm/imem.txt
@@ -57,6 +57,11 @@
-compatible: "qcom,msm-imem-emergency_download_mode"
-reg: start address and size of emergency_download_mode region in imem
+Kaslr Offset:
+------------------------
+-compatible: "qcom,msm-imem-kaslr_offset"
+-reg: start address and size of kaslr_offset region in imem
+
USB Diag Cookies:
-----------------
Memory region used to store USB PID and serial numbers to be used by
@@ -95,6 +100,12 @@
reg = <0x6b0 32>;
};
+ kaslr_offset@6d0 {
+ compatible = "qcom,msm-imem-kaslr_offset";
+ reg = <0x6d0 12>;
+ };
+
+
pil@94c {
compatible = "qcom,msm-imem-pil";
reg = <0x94c 200>;
diff --git a/Documentation/devicetree/bindings/arm/msm/msm.txt b/Documentation/devicetree/bindings/arm/msm/msm.txt
index baae281..bf93a2a 100644
--- a/Documentation/devicetree/bindings/arm/msm/msm.txt
+++ b/Documentation/devicetree/bindings/arm/msm/msm.txt
@@ -110,6 +110,9 @@
- MDMCALIFORNIUM
compatible = "qcom,mdmcalifornium"
+- SDXPOORWILLS
+ compatible = "qcom,sdxpoorwills"
+
- VPIPA
compatible = "qcom,msmvpipa"
@@ -302,3 +305,4 @@
compatible = "qcom,mdmcalifornium-mtp"
compatible = "qcom,apq8009-cdp"
compatible = "qcom,apq8009-mtp"
+compatible = "qcom,sdxpoorwills-rumi"
diff --git a/Documentation/devicetree/bindings/arm/msm/rpm_stats.txt b/Documentation/devicetree/bindings/arm/msm/rpm_stats.txt
new file mode 100644
index 0000000..02dab4c
--- /dev/null
+++ b/Documentation/devicetree/bindings/arm/msm/rpm_stats.txt
@@ -0,0 +1,33 @@
+* RPM Stats
+
+RPM maintains a counter of the number of times the SoC entered a deeper sleep
+mode involving lowering or powering down the backbone rails - Cx and Mx and
+the oscillator clock, XO.
+
+PROPERTIES
+
+- compatible:
+ Usage: required
+ Value type: <string>
+ Definition: Should be "qcom,rpm-stats".
+
+- reg:
+ Usage: required
+ Value type: <prop-encoded-array>
+ Definition: The address on the RPM RAM from where the stats are read
+ should be provided as "phys_addr_base". The offset from
+ which the stats are available should be provided as
+ "offset_addr".
+
+- reg-names:
+ Usage: required
+ Value type: <prop-encoded-array>
+ Definition: Provides labels for the reg property.
+
+EXAMPLE:
+
+ qcom,rpm-stats@c000000 {
+ compatible = "qcom,rpm-stats";
+ reg = <0xC000000 0x1000>, <0x3F0000 0x4>;
+ reg-names = "phys_addr_base", "offset_addr";
+ };
diff --git a/Documentation/devicetree/bindings/clock/qcom,aop-qmp.txt b/Documentation/devicetree/bindings/clock/qcom,aop-qmp.txt
new file mode 100644
index 0000000..231b8a3
--- /dev/null
+++ b/Documentation/devicetree/bindings/clock/qcom,aop-qmp.txt
@@ -0,0 +1,17 @@
+Qualcomm Technologies, Inc. Always On Processor Clock controller Binding
+------------------------------------------------------------------------
+
+Required properties :
+- compatible : must be "qcom,aop-qmp-clk"
+- #clock-cells : must contain 1
+- mboxes : list of QMP mailbox phandle and channel identifier tuples.
+- mbox-names: List of identifier strings for each mailbox channel.
+ Must contain "qdss_clk".
+
+Example :
+ clock_qdss: qcom,aopclk {
+ compatible = "qcom,aop-qmp-clk";
+ #clock-cells = <1>;
+ mboxes = <&qmp_aop 0>;
+ mbox-names = "qdss_clk";
+ };
diff --git a/Documentation/devicetree/bindings/drm/msm/sde-dsi.txt b/Documentation/devicetree/bindings/drm/msm/sde-dsi.txt
index c6626d1..3ad0986 100644
--- a/Documentation/devicetree/bindings/drm/msm/sde-dsi.txt
+++ b/Documentation/devicetree/bindings/drm/msm/sde-dsi.txt
@@ -6,8 +6,9 @@
DSI Controller:
Required properties:
- compatible: Should be "qcom,dsi-ctrl-hw-v<version>". Supported
- versions include 1.4 and 2.0.
- eg: qcom,dsi-ctrl-hw-v1.4, qcom,dsi-ctrl-hw-v2.0
+ versions include 1.4, 2.0 and 2.2.
+ eg: qcom,dsi-ctrl-hw-v1.4, qcom,dsi-ctrl-hw-v2.0,
+ qcom,dsi-ctrl-hw-v2.2
And for dsi phy driver:
qcom,dsi-phy-v0.0-hpm, qcom,dsi-phy-v0.0-lpm,
qcom,dsi-phy-v1.0, qcom,dsi-phy-v2.0,
diff --git a/Documentation/devicetree/bindings/media/video/msm-cam-smmu.txt b/Documentation/devicetree/bindings/media/video/msm-cam-smmu.txt
new file mode 100644
index 0000000..2ed913c
--- /dev/null
+++ b/Documentation/devicetree/bindings/media/video/msm-cam-smmu.txt
@@ -0,0 +1,130 @@
+* Qualcomm Technologies, Inc. MSM Camera SMMU
+
+The MSM camera SMMU device provides SMMU context bank definitions
+for all HW blocks that need to map IOVA to physical memory. These
+definitions consist of various properties that define how the
+IOVA address space is laid out for each HW block in the camera
+subsystem.
+
+=======================
+Required Node Structure
+=======================
+The camera SMMU device must be described in three levels of device nodes. The
+first level describes the overall SMMU device. Within it, second level nodes
+describe individual context banks that map different stream ids. There can
+also be second level nodes describing firmware device nodes. Each HW block
+such as IFE, ICP maps into these second level device nodes. All context bank
+specific properties that define how the IOVA is laid out is contained within
+third level device nodes within the second level device nodes.
+
+During the kernel initialization all the devices are probed recursively and
+a device pointer is created for each context bank keeping track of the IOVA
+mapping information.
+
+Duplicate regions of the same type are not allowed within the same
+context bank. All context banks must contain an IO region at the very least.
+
+==================================
+First Level Node - CAM SMMU device
+==================================
+- compatible
+ Usage: required
+ Value type: <string>
+ Definition: Should be "qcom,msm-cam-smmu".
+
+===================================================================
+Second Level Node - CAM SMMU context bank device or firmware device
+===================================================================
+- compatible
+ Usage: required
+ Value type: <string>
+ Definition: Should be "qcom,msm-cam-smmu-cb" or "qcom,msm-cam-smmu-fw-dev".
+
+- memory-region
+ Usage: optional
+ Value type: <phandle>
+ Definition: Should specify the phandle of the memory region for firmware.
+ allocation
+
+- iommus
+ Usage: required
+ Value type: <phandle>
+ Definition: Should specify the phandle of the iommu sid.
+
+- label
+ Usage: required
+ Value type: <string>
+ Definition: Should specify a string label to identify the context bank.
+
+=============================================
+Third Level Node - CAM SMMU memory map device
+=============================================
+- iova-region-name
+ Usage: required
+ Value type: <string>
+ Definition: Should specify a string label to identify the IOVA region.
+
+- iova-region-start
+ Usage: required
+ Value type: <u32>
+ Definition: Should specify start IOVA for region.
+
+- iova-region-len
+ Usage: required
+ Value type: <u32>
+ Definition: Should specify length for IOVA region.
+
+- iova-region-id
+ Usage: required
+ Value type: <u32>
+ Definition: Should specify the numerical identifier for IOVA region.
+ Allowed values are: 0x00 to 0x03
+ - Firmware region: 0x00
+ - Shared region: 0x01
+ - Scratch region: 0x02
+ - IO region: 0x03
+
+Example:
+ qcom,cam_smmu@0 {
+ compatible = "qcom,msm-cam-smmu";
+
+ msm_cam_smmu_icp {
+ compatible = "qcom,msm-cam-smmu-cb";
+ iommus = <&apps_smmu 0x1078>,
+ <&apps_smmu 0x1020>,
+ <&apps_smmu 0x1028>,
+ <&apps_smmu 0x1040>,
+ <&apps_smmu 0x1048>,
+ <&apps_smmu 0x1030>,
+ <&apps_smmu 0x1050>;
+ label = "icp";
+ icp_iova_mem_map: iova-mem-map {
+ iova-mem-region-firmware {
+ /* Firmware region is 5MB */
+ iova-region-name = "firmware";
+ iova-region-start = <0x0>;
+ iova-region-len = <0x500000>;
+ iova-region-id = <0x0>;
+ status = "ok";
+ };
+
+ iova-mem-region-shared {
+ /* Shared region is 100MB long */
+ iova-region-name = "shared";
+ iova-region-start = <0x7400000>;
+ iova-region-len = <0x6400000>;
+ iova-region-id = <0x1>;
+ status = "ok";
+ };
+
+ iova-mem-region-io {
+ /* IO region is approximately 3.5 GB */
+ iova-region-name = "io";
+ iova-region-start = <0xd800000>;
+ iova-region-len = <0xd2800000>;
+ iova-region-id = <0x3>;
+ status = "ok";
+ };
+ };
+ };
+ };
diff --git a/Documentation/devicetree/bindings/media/video/msm-vidc.txt b/Documentation/devicetree/bindings/media/video/msm-vidc.txt
index 6d72e8b..bdc0eba 100644
--- a/Documentation/devicetree/bindings/media/video/msm-vidc.txt
+++ b/Documentation/devicetree/bindings/media/video/msm-vidc.txt
@@ -10,6 +10,10 @@
of macroblocks per second. The load is a reflection of hardware capability
rather than a performance guarantee. Performance is guaranteed only up to
advertised capability of the chipset.
+- qcom,max-hq-mbs-per-frame : Max no of mbs per frame beyond which
+ "High Quality" encoding is not supported.
+- qcom,max-hq-frames-per-sec : Max no of frames per second beyond which
+ "High Quality" encoding is not supported.
Optional properties:
- reg : offset and length of the register set for the device.
@@ -157,7 +161,6 @@
Example:
-
qcom,vidc@fdc00000 {
compatible = "qcom,msm-vidc";
reg = <0xfdc00000 0xff000>;
@@ -182,6 +185,8 @@
qcom,use_dynamic_bw_update;
qcom,fw-bias = <0xe000000>;
qcom,allowed-clock-rates = <200000000 300000000 400000000>;
+ qcom,max-hq-mbs-per-frame = <8160>;
+ qcom,max-hq-frames-per-sec = <60>;
msm_vidc_cb1: msm_vidc_cb1 {
compatible = "qcom,msm-vidc,context-bank";
label = "venus_ns";
diff --git a/Documentation/devicetree/bindings/mmc/sdhci-msm.txt b/Documentation/devicetree/bindings/mmc/sdhci-msm.txt
index fd7e140..da9a632 100644
--- a/Documentation/devicetree/bindings/mmc/sdhci-msm.txt
+++ b/Documentation/devicetree/bindings/mmc/sdhci-msm.txt
@@ -68,6 +68,15 @@
command-queueing mode or legacy respectively.
- qcom,core_3_0v_support: an optional property that is used to fake
3.0V support for SDIO devices.
+ - qcom,scaling-lower-bus-speed-mode: specifies the lower bus speed mode to be used
+ during clock scaling. If this property is not
+ defined, then it falls back to the default HS
+ bus speed mode to maintain backward compatibility.
+ - qcom,sdr104-wa: On Certain chipsets, SDR104 mode might be unstable causing CRC errors
+ on the interface. So there is a workaround implemented to skip printing
+ register dumps on CRC errors and also downgrade bus speed mode to
+ SDR50/DDR50 in case of continuous CRC errors. Set this flag to enable
+ this workaround.
In the following, <supply> can be vdd (flash core voltage) or vdd-io (I/O voltage).
- qcom,<supply>-always-on - specifies whether supply should be kept "on" always.
@@ -130,6 +139,8 @@
qcom,large-address-bus;
qcom,bus-speed-mode = "HS200_1p8v", "DDR_1p8v";
+ qcom,scaling-lower-bus-speed-mode = "DDR52";
+
gpios = <&msmgpio 40 0>, /* CLK */
<&msmgpio 39 0>, /* CMD */
<&msmgpio 38 0>, /* DATA0 */
diff --git a/Documentation/devicetree/bindings/pinctrl/qcom,sdxpoorwill-pinctrl b/Documentation/devicetree/bindings/pinctrl/qcom,sdxpoorwill-pinctrl
new file mode 100644
index 0000000..9a69084
--- /dev/null
+++ b/Documentation/devicetree/bindings/pinctrl/qcom,sdxpoorwill-pinctrl
@@ -0,0 +1,186 @@
+Qualcomm Technologies, Inc. SDXPOORWILLS TLMM block
+
+This binding describes the Top Level Mode Multiplexer block found in the
+SDXPOORWILLS platform.
+
+- compatible:
+ Usage: required
+ Value type: <string>
+ Definition: must be "qcom,sdxpoorwills-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-gpio149
+ Supports mux, bias and drive-strength
+
+ sdc1_clk, sdc1_cmd, sdc1_data sdc2_clk, sdc2_cmd,
+ sdc2_data sdc1_rclk
+ Supports bias and drive-strength
+
+- 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:
+
+ blsp_uart1, blsp_spi1, blsp_i2c1, blsp_uim1, atest_tsens,
+ bimc_dte1, dac_calib0, blsp_spi8, blsp_uart8, blsp_uim8,
+ qdss_cti_trig_out_b, bimc_dte0, dac_calib1, qdss_cti_trig_in_b,
+ dac_calib2, atest_tsens2, atest_usb1, blsp_spi10, blsp_uart10,
+ blsp_uim10, atest_bbrx1, atest_usb13, atest_bbrx0, atest_usb12,
+ mdp_vsync, edp_lcd, blsp_i2c10, atest_gpsadc1, atest_usb11,
+ atest_gpsadc0, edp_hot, atest_usb10, m_voc, dac_gpio, atest_char,
+ cam_mclk, pll_bypassnl, qdss_stm7, blsp_i2c8, qdss_tracedata_b,
+ pll_reset, qdss_stm6, qdss_stm5, qdss_stm4, atest_usb2, cci_i2c,
+ qdss_stm3, dac_calib3, atest_usb23, atest_char3, dac_calib4,
+ qdss_stm2, atest_usb22, atest_char2, qdss_stm1, dac_calib5,
+ atest_usb21, atest_char1, dbg_out, qdss_stm0, dac_calib6,
+ atest_usb20, atest_char0, dac_calib10, qdss_stm10,
+ qdss_cti_trig_in_a, cci_timer4, blsp_spi6, blsp_uart6, blsp_uim6,
+ blsp2_spi, qdss_stm9, qdss_cti_trig_out_a, dac_calib11,
+ qdss_stm8, cci_timer0, qdss_stm13, dac_calib7, cci_timer1,
+ qdss_stm12, dac_calib8, cci_timer2, blsp1_spi, qdss_stm11,
+ dac_calib9, cci_timer3, cci_async, dac_calib12, blsp_i2c6,
+ qdss_tracectl_a, dac_calib13, qdss_traceclk_a, dac_calib14,
+ dac_calib15, hdmi_rcv, dac_calib16, hdmi_cec, pwr_modem,
+ dac_calib17, hdmi_ddc, pwr_nav, dac_calib18, pwr_crypto,
+ dac_calib19, hdmi_hot, dac_calib20, dac_calib21, pci_e0,
+ dac_calib22, dac_calib23, dac_calib24, tsif1_sync, dac_calib25,
+ sd_write, tsif1_error, blsp_spi2, blsp_uart2, blsp_uim2,
+ qdss_cti, blsp_i2c2, blsp_spi3, blsp_uart3, blsp_uim3, blsp_i2c3,
+ uim3, blsp_spi9, blsp_uart9, blsp_uim9, blsp10_spi, blsp_i2c9,
+ blsp_spi7, blsp_uart7, blsp_uim7, qdss_tracedata_a, blsp_i2c7,
+ qua_mi2s, gcc_gp1_clk_a, ssc_irq, uim4, blsp_spi11, blsp_uart11,
+ blsp_uim11, gcc_gp2_clk_a, gcc_gp3_clk_a, blsp_i2c11, cri_trng0,
+ cri_trng1, cri_trng, qdss_stm18, pri_mi2s, qdss_stm17, blsp_spi4,
+ blsp_uart4, blsp_uim4, qdss_stm16, qdss_stm15, blsp_i2c4,
+ qdss_stm14, dac_calib26, spkr_i2s, audio_ref, lpass_slimbus,
+ isense_dbg, tsense_pwm1, tsense_pwm2, btfm_slimbus, ter_mi2s,
+ qdss_stm22, qdss_stm21, qdss_stm20, qdss_stm19, gcc_gp1_clk_b,
+ sec_mi2s, blsp_spi5, blsp_uart5, blsp_uim5, gcc_gp2_clk_b,
+ gcc_gp3_clk_b, blsp_i2c5, blsp_spi12, blsp_uart12, blsp_uim12,
+ qdss_stm25, qdss_stm31, blsp_i2c12, qdss_stm30, qdss_stm29,
+ tsif1_clk, qdss_stm28, tsif1_en, tsif1_data, sdc4_cmd, qdss_stm27,
+ qdss_traceclk_b, tsif2_error, sdc43, vfr_1, qdss_stm26, tsif2_clk,
+ sdc4_clk, qdss_stm24, tsif2_en, sdc42, qdss_stm23, qdss_tracectl_b,
+ sd_card, tsif2_data, sdc41, tsif2_sync, sdc40, mdp_vsync_p_b,
+ ldo_en, mdp_vsync_s_b, ldo_update, blsp11_uart_tx_b, blsp11_uart_rx_b,
+ blsp11_i2c_sda_b, prng_rosc, blsp11_i2c_scl_b, uim2, uim1, uim_batt,
+ pci_e2, pa_indicator, adsp_ext, ddr_bist, qdss_tracedata_11,
+ qdss_tracedata_12, modem_tsync, nav_dr, nav_pps, pci_e1, gsm_tx,
+ qspi_cs, ssbi2, ssbi1, mss_lte, qspi_clk, qspi0, qspi1, qspi2, qspi3,
+ gpio
+
+- 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@03900000 {
+ compatible = "qcom,sdxpoorwills-pinctrl";
+ reg = <0x03900000 0x300000>;
+ interrupts = <0 212 0>;
+ gpio-controller;
+ #gpio-cells = <2>;
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ };
diff --git a/Documentation/devicetree/bindings/power/supply/qcom/qpnp-smb2.txt b/Documentation/devicetree/bindings/power/supply/qcom/qpnp-smb2.txt
index f4a22e0..e1f194f3 100644
--- a/Documentation/devicetree/bindings/power/supply/qcom/qpnp-smb2.txt
+++ b/Documentation/devicetree/bindings/power/supply/qcom/qpnp-smb2.txt
@@ -169,6 +169,18 @@
Definition: Boolean flag which when present enables input suspend for
debug battery.
+- qcom,min-freq-khz
+ Usage: optional
+ Value type: <u32>
+ Definition: Specifies the minimum charger buck/boost switching frequency
+ in KHz. It overrides the min frequency defined for the charger.
+
+- qcom,max-freq-khz
+ Usage: optional
+ Value type: <u32>
+ Definition: Specifies the maximum charger buck/boost switching frequency in
+ KHz. It overrides the max frequency defined for the charger.
+
=============================================
Second Level Nodes - SMB2 Charger Peripherals
=============================================
diff --git a/Documentation/devicetree/bindings/power/supply/qcom/smb138x-charger.txt b/Documentation/devicetree/bindings/power/supply/qcom/smb138x-charger.txt
index 92ef23c..5529e308 100644
--- a/Documentation/devicetree/bindings/power/supply/qcom/smb138x-charger.txt
+++ b/Documentation/devicetree/bindings/power/supply/qcom/smb138x-charger.txt
@@ -22,7 +22,8 @@
Definition: String which indicates the charging mode. Can be one of the
following:
Standalone/Parallel Master - "qcom,smb138x-charger"
- Parallel Slave - "qcom,smb138x-parallel-slave"
+ smb138x Parallel Slave - "qcom,smb138x-parallel-slave"
+ smb1355 Parallel Slave - "qcom,smb1355-parallel-slave",
- qcom,pmic-revid
Usage: required
@@ -35,7 +36,8 @@
Usage: optional
Value type: <u32>
Definition: Specifies parallel charging mode. If not specified, MID-MID
- option is selected by default.
+ option is selected by default. Note that smb1355 can only
+ run in MID-MID configuration.
- qcom,suspend-input
Usage: optional
@@ -125,7 +127,7 @@
=======
smb138x_charger: qcom,smb138x-charger {
- compatible = "qcom,qpnp-smb138x-charger";
+ compatible = "qcom,smb138x-charger";
#address-cells = <1>;
#size-cells = <1>;
diff --git a/Documentation/devicetree/bindings/prng/msm-rng.txt b/Documentation/devicetree/bindings/prng/msm-rng.txt
new file mode 100644
index 0000000..917c2fb
--- /dev/null
+++ b/Documentation/devicetree/bindings/prng/msm-rng.txt
@@ -0,0 +1,18 @@
+* RNG (Random Number Generator)
+
+Required properties:
+- compatible : Should be "qcom,msm-rng"
+- reg : Offset and length of the register set for the device
+
+Optional property:
+- qcom,msm-rng-iface-clk : If the device uses iface-clk.
+- qcom,no-qrng-config : Flag to decide whether the driver do the hardware configuration or not.
+
+Example:
+
+ qcom,msm-rng@f9bff000 {
+ compatible = "qcom,msm-rng";
+ reg = <0xf9bff000 0x200>;
+ qcom,msm-rng-iface-clk;
+ qcom,no-qrng-config;
+ };
diff --git a/Documentation/devicetree/bindings/serial/qcom,msm-geni-uart.txt b/Documentation/devicetree/bindings/serial/qcom,msm-geni-uart.txt
index e53b691..04b624b 100644
--- a/Documentation/devicetree/bindings/serial/qcom,msm-geni-uart.txt
+++ b/Documentation/devicetree/bindings/serial/qcom,msm-geni-uart.txt
@@ -16,6 +16,10 @@
Should be "active" and "sleep" for the pin confuguration when core is active
or when entering sleep state.
+Optional properties:
+- qcom,bus-mas: contains the bus master id needed to put in bus bandwidth votes
+ for inter-connect buses.
+
Example:
qupv3_uart11: qcom,qup_uart@0xa88000 {
compatible = "qcom,msm-geni-uart";
@@ -29,4 +33,5 @@
pinctrl-0 = <&qup_1_uart_3_active>;
pinctrl-1 = <&qup_1_uart_3_sleep>;
interrupts = <0 355 0>;
+ qcom,bus-mas = <MASTER_BLSP_2>;
};
diff --git a/Documentation/devicetree/bindings/soc/qcom/dcc.txt b/Documentation/devicetree/bindings/soc/qcom/dcc.txt
index 0fd4e15..8a9761c 100644
--- a/Documentation/devicetree/bindings/soc/qcom/dcc.txt
+++ b/Documentation/devicetree/bindings/soc/qcom/dcc.txt
@@ -14,6 +14,11 @@
of the component.
- reg-names : names corresponding to each reg property value.
+ dcc-base: Base address for DCC configuration reg
+ dcc-ram-base: Start of HLOS address space in SRAM
+ dcc-xpu-base: Base address for XPU configuration reg
+
+- dcc-ram-offset: Address offset from the start of the SRAM address space.
Optional properties:
diff --git a/Documentation/devicetree/bindings/thermal/qcom-lmh-dcvs.txt b/Documentation/devicetree/bindings/thermal/qcom-lmh-dcvs.txt
index 080d4da..8bead0d 100644
--- a/Documentation/devicetree/bindings/thermal/qcom-lmh-dcvs.txt
+++ b/Documentation/devicetree/bindings/thermal/qcom-lmh-dcvs.txt
@@ -25,12 +25,18 @@
interrupt generated by the LMH DCVSh hardware. LMH
DCVSh hardware will generate this interrupt whenever
it makes a new cpu DCVS decision.
+- qcom,affinity:
+ Usage: Required
+ Value type: <u32>
+ Definition: Should specify the cluster affinity this hardware
+ corresponds to.
Example:
lmh_dcvs0: qcom,limits-dcvs@0 {
compatible = "qcom,msm-hw-limits";
interrupts = <GIC_SPI 38 IRQ_TYPE_LEVEL_HIGH>;
+ qcom,affinity = <0>;
};
CPU0: cpu@0 {
diff --git a/Documentation/devicetree/bindings/thermal/tsens.txt b/Documentation/devicetree/bindings/thermal/tsens.txt
index 1065456..3e59c43 100644
--- a/Documentation/devicetree/bindings/thermal/tsens.txt
+++ b/Documentation/devicetree/bindings/thermal/tsens.txt
@@ -21,34 +21,25 @@
The compatible property is used to identify the respective controller to use
for the corresponding SoC.
- reg : offset and length of the TSENS registers with associated property in reg-names
- as "tsens_physical" for TSENS TM physical address region.
+ as "tsens_srot_physical" for TSENS SROT physical address region. TSENS TM
+ physical address region as "tsens_tm_physical".
- reg-names : resource names used for the physical address of the TSENS
- registers. Should be "tsens_physical" for physical address of the TSENS.
+ registers. Should be "tsens_srot_physical" for physical address of the TSENS
+ SROT region and "tsens_tm_physical" for physical address of the TM region.
- interrupts : TSENS interrupt to notify Upper/Lower and Critical temperature threshold.
- interrupt-names: Should be "tsens-upper-lower" for temperature threshold.
Add "tsens-critical" for Critical temperature threshold notification
in addition to "tsens-upper-lower" for 8996 TSENS since
8996 supports Upper/Lower and Critical temperature threshold.
-- qcom,sensors : Total number of available Temperature sensors for TSENS.
-
-Optional properties:
-- qcom,sensor-id : If the flag is present map the TSENS sensors based on the
- remote sensors that are enabled in HW. Ensure the mapping is not
- more than the number of supported sensors.
-- qcom,client-id : If the flag is present use it to identify the SW ID mapping
- used to associate it with the controller and the physical sensor
- mapping within the controller. The physical sensor mapping within
- each controller is done using the qcom,sensor-id property. If the
- property is not present the SW ID mapping with default from 0 to
- total number of supported sensors with each controller instance.
Example:
tsens@fc4a8000 {
compatible = "qcom,msm-tsens";
- reg = <0xfc4a8000 0x2000>;,
- reg-names = "tsens_physical";
+ reg = <0xfc4a8000 0x10>,
+ <0xfc4b8000 0x1ff>;
+ reg-names = "tsens_srot_physical",
+ "tsens_tm_physical";
interrupts = <0 184 0>;
interrupt-names = "tsens-upper-lower";
- qcom,sensors = <11>;
};
diff --git a/Documentation/devicetree/bindings/uio/msm_sharedmem.txt b/Documentation/devicetree/bindings/uio/msm_sharedmem.txt
new file mode 100644
index 0000000..749c6e85
--- /dev/null
+++ b/Documentation/devicetree/bindings/uio/msm_sharedmem.txt
@@ -0,0 +1,18 @@
+msm_sharedmem provides the shared memory addresses for various clients in user-space
+
+Required properties:
+- compatible: Must be "qcom,sharedmem-uio"
+- reg : The address and size of the shared memory. The address/sizes may vary.
+ A reg address of Zero indicates that the shared memory is dynamically
+ allocated using dma_alloc_coherent. A non zero reg address is used
+ directly.
+- reg-names : Indicates various client-names.
+- qcom,client-id : The client id for the QMI clients.
+
+Example:
+ qcom,msm_sharedmem@0dc80000 {
+ compatible = "qcom,sharedmem-uio";
+ reg = <0x0dc80000 0x00180000>,
+ reg-names = "rmtfs";
+ qcom,client-id = <0x00000001>;
+ };
diff --git a/Makefile b/Makefile
index c2660d2..2b8f550 100644
--- a/Makefile
+++ b/Makefile
@@ -1,6 +1,6 @@
VERSION = 4
PATCHLEVEL = 9
-SUBLEVEL = 23
+SUBLEVEL = 25
EXTRAVERSION =
NAME = Roaring Lionus
diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
index b174261..d04e168 100644
--- a/arch/arm/Kconfig
+++ b/arch/arm/Kconfig
@@ -550,7 +550,7 @@
config ARCH_QCOM
bool "Qualcomm MSM (non-multiplatform)"
- select ARCH_REQUIRE_GPIOLIB
+ select GPIOLIB
select CPU_V7
select AUTO_ZRELADDR
select HAVE_SMP
diff --git a/arch/arm/boot/dts/qcom/Makefile b/arch/arm/boot/dts/qcom/Makefile
index 14422e5..7eb0c7f 100644
--- a/arch/arm/boot/dts/qcom/Makefile
+++ b/arch/arm/boot/dts/qcom/Makefile
@@ -1,4 +1,5 @@
+dtb-$(CONFIG_ARCH_SDXPOORWILLS) += sdxpoorwills-rumi.dtb
ifeq ($(CONFIG_ARM64),y)
diff --git a/arch/arm/boot/dts/qcom/sdxpoorwills-pinctrl.dtsi b/arch/arm/boot/dts/qcom/sdxpoorwills-pinctrl.dtsi
new file mode 100644
index 0000000..ac02429
--- /dev/null
+++ b/arch/arm/boot/dts/qcom/sdxpoorwills-pinctrl.dtsi
@@ -0,0 +1,35 @@
+/* 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 {
+ tlmm: pinctrl@3900000 {
+ compatible = "qcom,sdxpoorwills-pinctrl";
+ reg = <0x3900000 0x300000>;
+ interrupts = <0 212 0>;
+ gpio-controller;
+ #gpio-cells = <2>;
+ interrupt-controller;
+ #interrupt-cells = <2>;
+
+ uart2_console_active: uart2_console_active {
+ mux {
+ pins = "gpio4", "gpio5";
+ function = "blsp_uart2";
+ };
+ config {
+ pins = "gpio4", "gpio5";
+ drive-strength = <2>;
+ bias-disable;
+ };
+ };
+ };
+};
diff --git a/arch/arm/boot/dts/qcom/sdxpoorwills-rumi.dts b/arch/arm/boot/dts/qcom/sdxpoorwills-rumi.dts
new file mode 100644
index 0000000..967e71f
--- /dev/null
+++ b/arch/arm/boot/dts/qcom/sdxpoorwills-rumi.dts
@@ -0,0 +1,29 @@
+/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+/dts-v1/;
+
+
+#include "sdxpoorwills.dtsi"
+#include "sdxpoorwills-pinctrl.dtsi"
+
+/ {
+ model = "Qualcomm Technologies, Inc. SDXPOORWILLS RUMI";
+ compatible = "qcom,sdxpoorwills-rumi",
+ "qcom,sdxpoorwills", "qcom,rumi";
+ qcom,board-id = <15 0>;
+};
+
+&blsp1_uart2 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&uart2_console_active>;
+};
diff --git a/arch/arm/boot/dts/qcom/sdxpoorwills.dtsi b/arch/arm/boot/dts/qcom/sdxpoorwills.dtsi
new file mode 100644
index 0000000..0afa5a8
--- /dev/null
+++ b/arch/arm/boot/dts/qcom/sdxpoorwills.dtsi
@@ -0,0 +1,157 @@
+/* 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 "skeleton.dtsi"
+#include <dt-bindings/clock/qcom,gcc-sdxpoorwills.h>
+
+/ {
+ model = "Qualcomm Technologies, Inc. SDX POORWILLS";
+ compatible = "qcom,sdxpoorwills";
+ qcom,msm-id = <334 0x0>;
+ interrupt-parent = <&intc>;
+
+ reserved-memory {
+ #address-cells = <1>;
+ #size-cells = <1>;
+ ranges;
+
+ peripheral2_mem: peripheral2_region@8fd00000 {
+ compatible = "removed-dma-pool";
+ no-map;
+ reg = <0x8fd00000 0x300000>;
+ label = "peripheral2_mem";
+ };
+ };
+
+ cpus {
+ #size-cells = <0>;
+ #address-cells = <1>;
+
+ CPU0: cpu@0 {
+ device-type = "cpu";
+ compatible = "arm,cortex-a7";
+ reg = <0x0>;
+ };
+ };
+
+ soc: soc { };
+};
+
+
+&soc {
+ #address-cells = <1>;
+ #size-cells = <1>;
+ ranges;
+
+ intc: interrupt-controller@17800000 {
+ compatible = "qcom,msm-qgic2";
+ interrupt-controller;
+ #interrupt-cells = <3>;
+ reg = <0x17800000 0x1000>,
+ <0x17802000 0x1000>;
+ };
+
+ timer {
+ compatible = "arm,armv7-timer";
+ interrupts = <1 13 0xf08>,
+ <1 12 0xf08>,
+ <1 10 0xf08>,
+ <1 11 0xf08>;
+ clock-frequency = <19200000>;
+ };
+
+ timer@17820000 {
+ #address-cells = <1>;
+ #size-cells = <1>;
+ ranges;
+ compatible = "arm,armv7-timer-mem";
+ reg = <0x17820000 0x1000>;
+ clock-frequency = <19200000>;
+
+ frame@17821000 {
+ frame-number = <0>;
+ interrupts = <0 7 0x4>,
+ <0 6 0x4>;
+ reg = <0x17821000 0x1000>,
+ <0x17822000 0x1000>;
+ };
+
+ frame@17823000 {
+ frame-number = <1>;
+ interrupts = <0 8 0x4>;
+ reg = <0x17823000 0x1000>;
+ status = "disabled";
+ };
+
+ frame@17824000 {
+ frame-number = <2>;
+ interrupts = <0 9 0x4>;
+ reg = <0x17824000 0x1000>;
+ status = "disabled";
+ };
+
+ frame@17825000 {
+ frame-number = <3>;
+ interrupts = <0 10 0x4>;
+ reg = <0x17825000 0x1000>;
+ status = "disabled";
+ };
+
+ frame@17826000 {
+ frame-number = <4>;
+ interrupts = <0 11 0x4>;
+ reg = <0x17826000 0x1000>;
+ status = "disabled";
+ };
+
+ frame@17827000 {
+ frame-number = <5>;
+ interrupts = <0 12 0x4>;
+ reg = <0x17827000 0x1000>;
+ status = "disabled";
+ };
+
+ frame@17828000 {
+ frame-number = <6>;
+ interrupts = <0 13 0x4>;
+ reg = <0x17828000 0x1000>;
+ status = "disabled";
+ };
+
+ frame@17829000 {
+ frame-number = <7>;
+ interrupts = <0 14 0x4>;
+ reg = <0x17829000 0x1000>;
+ status = "disabled";
+ };
+ };
+
+ clock_gcc: qcom,gcc@100000 {
+ compatible = "qcom,dummycc";
+ clock-output-names = "gcc_clocks";
+ #clock-cells = <1>;
+ };
+
+ clock_cpu: qcom,clock-a7@17810008 {
+ compatible = "qcom,dummycc";
+ clock-output-names = "cpu_clocks";
+ #clock-cells = <1>;
+ };
+
+ blsp1_uart2: serial@831000 {
+ compatible = "qcom,msm-uartdm-v1.4", "qcom,msm-uartdm";
+ reg = <0x831000 0x200>;
+ interrupts = <0 26 0>;
+ status = "disabled";
+ };
+};
diff --git a/arch/arm/configs/sdxpoorwills-perf_defconfig b/arch/arm/configs/sdxpoorwills-perf_defconfig
new file mode 100644
index 0000000..1f6d2cc
--- /dev/null
+++ b/arch/arm/configs/sdxpoorwills-perf_defconfig
@@ -0,0 +1,289 @@
+CONFIG_NO_HZ=y
+CONFIG_HIGH_RES_TIMERS=y
+CONFIG_IKCONFIG=y
+CONFIG_IKCONFIG_PROC=y
+CONFIG_CGROUPS=y
+CONFIG_CGROUP_DEBUG=y
+CONFIG_CGROUP_FREEZER=y
+CONFIG_CGROUP_CPUACCT=y
+CONFIG_CGROUP_SCHED=y
+# CONFIG_FAIR_GROUP_SCHED is not set
+CONFIG_RT_GROUP_SCHED=y
+CONFIG_NAMESPACES=y
+# CONFIG_UTS_NS is not set
+# CONFIG_PID_NS is not set
+CONFIG_BLK_DEV_INITRD=y
+CONFIG_CC_OPTIMIZE_FOR_SIZE=y
+CONFIG_KALLSYMS_ALL=y
+CONFIG_EMBEDDED=y
+# CONFIG_SLUB_DEBUG is not set
+CONFIG_PROFILING=y
+CONFIG_CC_STACKPROTECTOR_REGULAR=y
+CONFIG_MODULES=y
+CONFIG_MODULE_UNLOAD=y
+CONFIG_MODULE_FORCE_UNLOAD=y
+CONFIG_PARTITION_ADVANCED=y
+CONFIG_ARCH_QCOM=y
+CONFIG_ARCH_SDXPOORWILLS=y
+CONFIG_PREEMPT=y
+CONFIG_AEABI=y
+CONFIG_CMA=y
+CONFIG_CPU_FREQ=y
+CONFIG_CPU_FREQ_GOV_INTERACTIVE=y
+CONFIG_CPU_IDLE=y
+CONFIG_VFP=y
+CONFIG_NEON=y
+# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set
+CONFIG_PM_AUTOSLEEP=y
+CONFIG_NET=y
+CONFIG_PACKET=y
+CONFIG_UNIX=y
+CONFIG_INET=y
+CONFIG_IP_MULTICAST=y
+CONFIG_IP_ADVANCED_ROUTER=y
+CONFIG_IP_MULTIPLE_TABLES=y
+CONFIG_IP_MROUTE=y
+CONFIG_IP_MROUTE_MULTIPLE_TABLES=y
+CONFIG_IP_PIMSM_V2=y
+CONFIG_IPV6_MULTIPLE_TABLES=y
+CONFIG_IPV6_SUBTREES=y
+CONFIG_IPV6_MROUTE=y
+CONFIG_IPV6_MROUTE_MULTIPLE_TABLES=y
+CONFIG_IPV6_PIMSM_V2=y
+CONFIG_NETFILTER=y
+CONFIG_NETFILTER_DEBUG=y
+CONFIG_NF_CONNTRACK=y
+CONFIG_NF_CONNTRACK_EVENTS=y
+CONFIG_NF_CONNTRACK_TIMEOUT=y
+CONFIG_NF_CONNTRACK_TIMESTAMP=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_SNMP=y
+CONFIG_NF_CONNTRACK_PPTP=y
+CONFIG_NF_CONNTRACK_SIP=y
+CONFIG_NF_CONNTRACK_TFTP=y
+CONFIG_NF_CT_NETLINK=y
+CONFIG_NF_CT_NETLINK_TIMEOUT=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_TPROXY=y
+CONFIG_NETFILTER_XT_TARGET_TRACE=y
+CONFIG_NETFILTER_XT_MATCH_ADDRTYPE=y
+CONFIG_NETFILTER_XT_MATCH_CONNLABEL=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_IPRANGE=y
+CONFIG_NETFILTER_XT_MATCH_LIMIT=y
+CONFIG_NETFILTER_XT_MATCH_MULTIPORT=y
+CONFIG_NETFILTER_XT_MATCH_PHYSDEV=m
+CONFIG_NETFILTER_XT_MATCH_PKTTYPE=y
+CONFIG_NETFILTER_XT_MATCH_STATE=y
+CONFIG_IP_SET=y
+CONFIG_NF_CONNTRACK_IPV4=y
+CONFIG_IP_NF_IPTABLES=y
+CONFIG_IP_NF_MATCH_AH=y
+CONFIG_IP_NF_MATCH_ECN=y
+CONFIG_IP_NF_MATCH_TTL=y
+CONFIG_IP_NF_FILTER=y
+CONFIG_IP_NF_TARGET_REJECT=y
+CONFIG_IP_NF_NAT=y
+CONFIG_IP_NF_TARGET_MASQUERADE=y
+CONFIG_IP_NF_TARGET_NETMAP=y
+CONFIG_IP_NF_TARGET_REDIRECT=y
+CONFIG_IP_NF_MANGLE=y
+CONFIG_IP_NF_TARGET_ECN=y
+CONFIG_IP_NF_TARGET_TTL=y
+CONFIG_IP_NF_RAW=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_AH=y
+CONFIG_IP6_NF_MATCH_FRAG=y
+CONFIG_IP6_NF_MATCH_OPTS=y
+CONFIG_IP6_NF_MATCH_HL=y
+CONFIG_IP6_NF_MATCH_IPV6HEADER=y
+CONFIG_IP6_NF_MATCH_MH=y
+CONFIG_IP6_NF_MATCH_RT=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_BRIDGE_EBT_T_FILTER=y
+CONFIG_BRIDGE_EBT_T_NAT=y
+CONFIG_BRIDGE_EBT_ARP=y
+CONFIG_BRIDGE_EBT_IP=y
+CONFIG_BRIDGE_EBT_IP6=y
+CONFIG_BRIDGE_EBT_ARPREPLY=y
+CONFIG_BRIDGE_EBT_DNAT=y
+CONFIG_BRIDGE_EBT_SNAT=y
+CONFIG_BRIDGE=y
+CONFIG_NET_SCHED=y
+CONFIG_NET_SCH_PRIO=y
+CONFIG_BT=y
+CONFIG_BT_RFCOMM=y
+CONFIG_BT_RFCOMM_TTY=y
+CONFIG_BT_BNEP=y
+CONFIG_BT_BNEP_MC_FILTER=y
+CONFIG_BT_BNEP_PROTO_FILTER=y
+CONFIG_BT_HIDP=y
+CONFIG_BT_HCIUART=y
+CONFIG_BT_HCIUART_H4=y
+CONFIG_MSM_BT_POWER=y
+CONFIG_CFG80211=y
+CONFIG_CFG80211_DEBUGFS=y
+CONFIG_CFG80211_INTERNAL_REGDB=y
+CONFIG_CFG80211_WEXT=y
+CONFIG_RFKILL=y
+CONFIG_IPC_ROUTER=y
+CONFIG_IPC_ROUTER_SECURITY=y
+CONFIG_DMA_CMA=y
+CONFIG_CMA_SIZE_MBYTES=12
+CONFIG_MTD=y
+CONFIG_MTD_TESTS=m
+CONFIG_MTD_CMDLINE_PARTS=y
+CONFIG_MTD_BLOCK=y
+CONFIG_MTD_UBI=y
+CONFIG_BLK_DEV_LOOP=y
+CONFIG_BLK_DEV_RAM=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_NETDEVICES=y
+CONFIG_TUN=y
+# CONFIG_NET_VENDOR_BROADCOM is not set
+# CONFIG_NET_VENDOR_CIRRUS is not set
+# CONFIG_NET_VENDOR_FARADAY is not set
+# CONFIG_NET_VENDOR_INTEL is not set
+CONFIG_KS8851=y
+# CONFIG_NET_VENDOR_MICROCHIP is not set
+# CONFIG_NET_VENDOR_NATSEMI is not set
+# CONFIG_NET_VENDOR_SEEQ is not set
+# CONFIG_NET_VENDOR_SMSC is not set
+# CONFIG_NET_VENDOR_STMICRO is not set
+CONFIG_PPP=y
+CONFIG_PPP_ASYNC=y
+CONFIG_USB_USBNET=y
+CONFIG_USB_NET_SMSC75XX=y
+CONFIG_USB_NET_SMSC95XX=y
+CONFIG_WCNSS_MEM_PRE_ALLOC=y
+CONFIG_CLD_LL_CORE=y
+# CONFIG_INPUT_MOUSEDEV is not set
+CONFIG_INPUT_EVDEV=y
+# CONFIG_INPUT_KEYBOARD is not set
+# CONFIG_INPUT_MOUSE is not set
+CONFIG_INPUT_MISC=y
+CONFIG_INPUT_UINPUT=y
+CONFIG_INPUT_GPIO=m
+CONFIG_SERIO_LIBPS2=y
+# CONFIG_LEGACY_PTYS is not set
+CONFIG_HW_RANDOM=y
+CONFIG_I2C=y
+CONFIG_I2C_CHARDEV=y
+CONFIG_SOUNDWIRE=y
+CONFIG_SPI=y
+CONFIG_SPI_QUP=y
+CONFIG_SPI_SPIDEV=m
+CONFIG_PINCTRL_SDXPOORWILLS=y
+CONFIG_DEBUG_GPIO=y
+CONFIG_GPIO_SYSFS=y
+CONFIG_POWER_RESET=y
+CONFIG_POWER_SUPPLY=y
+CONFIG_THERMAL=y
+CONFIG_REGULATOR=y
+CONFIG_SOUND=y
+CONFIG_SND=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=y
+CONFIG_USB_ANNOUNCE_NEW_DEVICES=y
+CONFIG_USB_XHCI_HCD=y
+CONFIG_USB_EHCI_HCD=y
+CONFIG_USB_EHCI_MSM=y
+CONFIG_USB_ACM=y
+CONFIG_USB_STORAGE=y
+CONFIG_USB_STORAGE_DEBUG=y
+CONFIG_USB_STORAGE_DATAFAB=y
+CONFIG_USB_STORAGE_FREECOM=y
+CONFIG_USB_STORAGE_ISD200=y
+CONFIG_USB_STORAGE_USBAT=y
+CONFIG_USB_STORAGE_SDDR09=y
+CONFIG_USB_STORAGE_SDDR55=y
+CONFIG_USB_STORAGE_JUMPSHOT=y
+CONFIG_USB_STORAGE_ALAUDA=y
+CONFIG_USB_STORAGE_ONETOUCH=y
+CONFIG_USB_STORAGE_KARMA=y
+CONFIG_USB_STORAGE_CYPRESS_ATACB=y
+CONFIG_USB_DWC3=y
+CONFIG_NOP_USB_XCEIV=y
+CONFIG_USB_MSM_SSPHY_QMP=y
+CONFIG_USB_GADGET=y
+CONFIG_USB_GADGET_DEBUG_FILES=y
+CONFIG_USB_GADGET_VBUS_DRAW=500
+CONFIG_MMC=y
+CONFIG_MMC_PARANOID_SD_INIT=y
+CONFIG_MMC_BLOCK_MINORS=32
+CONFIG_MMC_TEST=m
+CONFIG_MMC_SDHCI=y
+CONFIG_MMC_SDHCI_PLTFM=y
+CONFIG_MMC_SDHCI_MSM=y
+CONFIG_RTC_CLASS=y
+CONFIG_DMADEVICES=y
+CONFIG_UIO=y
+CONFIG_STAGING=y
+CONFIG_GSI=y
+CONFIG_SPS=y
+CONFIG_SPS_SUPPORT_NDP_BAM=y
+CONFIG_USB_BAM=y
+CONFIG_REMOTE_SPINLOCK_MSM=y
+CONFIG_QCOM_SCM=y
+CONFIG_MSM_BOOT_STATS=y
+CONFIG_MSM_SMEM=y
+CONFIG_TRACER_PKT=y
+CONFIG_MSM_SMP2P=y
+CONFIG_MSM_SMP2P_TEST=y
+CONFIG_MSM_SUBSYSTEM_RESTART=y
+CONFIG_PWM=y
+CONFIG_QCOM_SHOW_RESUME_IRQ=y
+CONFIG_ANDROID=y
+CONFIG_EXT3_FS=y
+CONFIG_EXT4_FS_SECURITY=y
+CONFIG_VFAT_FS=y
+CONFIG_TMPFS=y
+CONFIG_UBIFS_FS=y
+CONFIG_UBIFS_FS_ADVANCED_COMPR=y
+CONFIG_NLS_CODEPAGE_437=y
+CONFIG_NLS_ASCII=y
+CONFIG_NLS_ISO8859_1=y
+CONFIG_PRINTK_TIME=y
+CONFIG_DEBUG_INFO=y
+CONFIG_MAGIC_SYSRQ=y
+CONFIG_PANIC_TIMEOUT=5
+# CONFIG_SCHED_DEBUG is not set
+CONFIG_SCHEDSTATS=y
+CONFIG_TIMER_STATS=y
+# CONFIG_DEBUG_PREEMPT is not set
+CONFIG_IPC_LOGGING=y
+CONFIG_BLK_DEV_IO_TRACE=y
diff --git a/arch/arm/configs/sdxpoorwills_defconfig b/arch/arm/configs/sdxpoorwills_defconfig
new file mode 100644
index 0000000..5d61163
--- /dev/null
+++ b/arch/arm/configs/sdxpoorwills_defconfig
@@ -0,0 +1,295 @@
+CONFIG_NO_HZ=y
+CONFIG_HIGH_RES_TIMERS=y
+CONFIG_IKCONFIG=y
+CONFIG_IKCONFIG_PROC=y
+CONFIG_CGROUPS=y
+CONFIG_CGROUP_DEBUG=y
+CONFIG_CGROUP_FREEZER=y
+CONFIG_CGROUP_CPUACCT=y
+CONFIG_CGROUP_SCHED=y
+# CONFIG_FAIR_GROUP_SCHED is not set
+CONFIG_RT_GROUP_SCHED=y
+CONFIG_NAMESPACES=y
+# CONFIG_UTS_NS is not set
+# CONFIG_PID_NS is not set
+CONFIG_BLK_DEV_INITRD=y
+# CONFIG_RD_XZ is not set
+# CONFIG_RD_LZ4 is not set
+CONFIG_CC_OPTIMIZE_FOR_SIZE=y
+CONFIG_KALLSYMS_ALL=y
+CONFIG_EMBEDDED=y
+CONFIG_PROFILING=y
+CONFIG_CC_STACKPROTECTOR_REGULAR=y
+CONFIG_MODULES=y
+CONFIG_MODULE_UNLOAD=y
+CONFIG_MODULE_FORCE_UNLOAD=y
+CONFIG_PARTITION_ADVANCED=y
+CONFIG_ARCH_QCOM=y
+CONFIG_ARCH_SDXPOORWILLS=y
+# CONFIG_VDSO is not set
+CONFIG_PREEMPT=y
+CONFIG_AEABI=y
+CONFIG_CMA=y
+CONFIG_CPU_FREQ=y
+CONFIG_CPU_FREQ_GOV_INTERACTIVE=y
+CONFIG_CPU_IDLE=y
+CONFIG_VFP=y
+CONFIG_NEON=y
+# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set
+CONFIG_PM_AUTOSLEEP=y
+CONFIG_NET=y
+CONFIG_PACKET=y
+CONFIG_UNIX=y
+CONFIG_INET=y
+CONFIG_IP_MULTICAST=y
+CONFIG_IP_ADVANCED_ROUTER=y
+CONFIG_IP_MULTIPLE_TABLES=y
+CONFIG_IP_MROUTE=y
+CONFIG_IP_MROUTE_MULTIPLE_TABLES=y
+CONFIG_IP_PIMSM_V2=y
+CONFIG_IPV6_MULTIPLE_TABLES=y
+CONFIG_IPV6_SUBTREES=y
+CONFIG_IPV6_MROUTE=y
+CONFIG_IPV6_MROUTE_MULTIPLE_TABLES=y
+CONFIG_IPV6_PIMSM_V2=y
+CONFIG_NETFILTER=y
+CONFIG_NETFILTER_DEBUG=y
+CONFIG_NF_CONNTRACK=y
+CONFIG_NF_CONNTRACK_EVENTS=y
+CONFIG_NF_CONNTRACK_TIMEOUT=y
+CONFIG_NF_CONNTRACK_TIMESTAMP=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_SNMP=y
+CONFIG_NF_CONNTRACK_PPTP=y
+CONFIG_NF_CONNTRACK_SIP=y
+CONFIG_NF_CONNTRACK_TFTP=y
+CONFIG_NF_CT_NETLINK=y
+CONFIG_NF_CT_NETLINK_TIMEOUT=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_TPROXY=y
+CONFIG_NETFILTER_XT_TARGET_TRACE=y
+CONFIG_NETFILTER_XT_MATCH_ADDRTYPE=y
+CONFIG_NETFILTER_XT_MATCH_CONNLABEL=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_IPRANGE=y
+CONFIG_NETFILTER_XT_MATCH_LIMIT=y
+CONFIG_NETFILTER_XT_MATCH_MULTIPORT=y
+CONFIG_NETFILTER_XT_MATCH_PHYSDEV=m
+CONFIG_NETFILTER_XT_MATCH_PKTTYPE=y
+CONFIG_NETFILTER_XT_MATCH_STATE=y
+CONFIG_IP_SET=y
+CONFIG_NF_CONNTRACK_IPV4=y
+CONFIG_IP_NF_IPTABLES=y
+CONFIG_IP_NF_MATCH_AH=y
+CONFIG_IP_NF_MATCH_ECN=y
+CONFIG_IP_NF_MATCH_TTL=y
+CONFIG_IP_NF_FILTER=y
+CONFIG_IP_NF_TARGET_REJECT=y
+CONFIG_IP_NF_NAT=y
+CONFIG_IP_NF_TARGET_MASQUERADE=y
+CONFIG_IP_NF_TARGET_NETMAP=y
+CONFIG_IP_NF_TARGET_REDIRECT=y
+CONFIG_IP_NF_MANGLE=y
+CONFIG_IP_NF_TARGET_ECN=y
+CONFIG_IP_NF_TARGET_TTL=y
+CONFIG_IP_NF_RAW=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_AH=y
+CONFIG_IP6_NF_MATCH_FRAG=y
+CONFIG_IP6_NF_MATCH_OPTS=y
+CONFIG_IP6_NF_MATCH_HL=y
+CONFIG_IP6_NF_MATCH_IPV6HEADER=y
+CONFIG_IP6_NF_MATCH_MH=y
+CONFIG_IP6_NF_MATCH_RT=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_BRIDGE_EBT_T_FILTER=y
+CONFIG_BRIDGE_EBT_T_NAT=y
+CONFIG_BRIDGE_EBT_ARP=y
+CONFIG_BRIDGE_EBT_IP=y
+CONFIG_BRIDGE_EBT_IP6=y
+CONFIG_BRIDGE_EBT_ARPREPLY=y
+CONFIG_BRIDGE_EBT_DNAT=y
+CONFIG_BRIDGE_EBT_SNAT=y
+CONFIG_BRIDGE=y
+CONFIG_NET_SCHED=y
+CONFIG_NET_SCH_PRIO=y
+CONFIG_RFKILL=y
+CONFIG_IPC_ROUTER=y
+CONFIG_IPC_ROUTER_SECURITY=y
+CONFIG_DMA_CMA=y
+CONFIG_CMA_SIZE_MBYTES=12
+CONFIG_MTD=y
+CONFIG_MTD_TESTS=m
+CONFIG_MTD_CMDLINE_PARTS=y
+CONFIG_MTD_BLOCK=y
+CONFIG_MTD_UBI=y
+CONFIG_BLK_DEV_LOOP=y
+CONFIG_BLK_DEV_RAM=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_NETDEVICES=y
+CONFIG_TUN=y
+# CONFIG_NET_VENDOR_BROADCOM is not set
+# CONFIG_NET_VENDOR_CIRRUS is not set
+# CONFIG_NET_VENDOR_FARADAY is not set
+# CONFIG_NET_VENDOR_INTEL is not set
+CONFIG_KS8851=y
+# CONFIG_NET_VENDOR_MICROCHIP is not set
+# CONFIG_NET_VENDOR_NATSEMI is not set
+# CONFIG_NET_VENDOR_SEEQ is not set
+# CONFIG_NET_VENDOR_SMSC is not set
+# CONFIG_NET_VENDOR_STMICRO is not set
+CONFIG_PPP=y
+CONFIG_PPP_ASYNC=y
+CONFIG_USB_USBNET=y
+CONFIG_USB_NET_SMSC75XX=y
+CONFIG_USB_NET_SMSC95XX=y
+CONFIG_WCNSS_MEM_PRE_ALLOC=y
+CONFIG_CLD_LL_CORE=y
+# CONFIG_INPUT_MOUSEDEV is not set
+CONFIG_INPUT_EVDEV=y
+# CONFIG_INPUT_KEYBOARD is not set
+# CONFIG_INPUT_MOUSE is not set
+CONFIG_INPUT_MISC=y
+CONFIG_INPUT_UINPUT=y
+CONFIG_INPUT_GPIO=m
+CONFIG_SERIO_LIBPS2=y
+# CONFIG_LEGACY_PTYS is not set
+CONFIG_SERIAL_MSM=y
+CONFIG_SERIAL_MSM_CONSOLE=y
+CONFIG_HVC_DCC=y
+CONFIG_HW_RANDOM=y
+CONFIG_I2C=y
+CONFIG_I2C_CHARDEV=y
+CONFIG_SOUNDWIRE=y
+CONFIG_SPI=y
+CONFIG_SPI_SPIDEV=m
+CONFIG_SLIMBUS=y
+CONFIG_PINCTRL_SDXPOORWILLS=y
+CONFIG_POWER_RESET=y
+CONFIG_POWER_SUPPLY=y
+CONFIG_THERMAL=y
+CONFIG_MSM_CDC_PINCTRL=y
+CONFIG_MSM_CDC_SUPPLY=y
+CONFIG_REGULATOR=y
+CONFIG_FB=y
+CONFIG_SOUND=y
+CONFIG_SND=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=y
+CONFIG_USB_ANNOUNCE_NEW_DEVICES=y
+CONFIG_USB_XHCI_HCD=y
+CONFIG_USB_EHCI_HCD=y
+CONFIG_USB_ACM=y
+CONFIG_USB_STORAGE=y
+CONFIG_USB_STORAGE_DEBUG=y
+CONFIG_USB_STORAGE_DATAFAB=y
+CONFIG_USB_STORAGE_FREECOM=y
+CONFIG_USB_STORAGE_ISD200=y
+CONFIG_USB_STORAGE_USBAT=y
+CONFIG_USB_STORAGE_SDDR09=y
+CONFIG_USB_STORAGE_SDDR55=y
+CONFIG_USB_STORAGE_JUMPSHOT=y
+CONFIG_USB_STORAGE_ALAUDA=y
+CONFIG_USB_STORAGE_ONETOUCH=y
+CONFIG_USB_STORAGE_KARMA=y
+CONFIG_USB_STORAGE_CYPRESS_ATACB=y
+CONFIG_USB_DWC3=y
+CONFIG_NOP_USB_XCEIV=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_PARANOID_SD_INIT=y
+CONFIG_MMC_BLOCK_MINORS=32
+CONFIG_MMC_TEST=m
+CONFIG_MMC_SDHCI=y
+CONFIG_MMC_SDHCI_PLTFM=y
+CONFIG_RTC_CLASS=y
+CONFIG_DMADEVICES=y
+CONFIG_UIO=y
+CONFIG_STAGING=y
+CONFIG_SPS=y
+CONFIG_SPS_SUPPORT_NDP_BAM=y
+CONFIG_HWSPINLOCK_QCOM=y
+CONFIG_QCOM_SMEM=y
+CONFIG_QCOM_SMD=y
+CONFIG_QCOM_SCM=y
+CONFIG_MSM_BOOT_STATS=y
+CONFIG_TRACER_PKT=y
+CONFIG_MSM_SUBSYSTEM_RESTART=y
+CONFIG_DEVFREQ_GOV_SIMPLE_ONDEMAND=y
+CONFIG_PWM=y
+CONFIG_QCOM_SHOW_RESUME_IRQ=y
+CONFIG_ANDROID=y
+CONFIG_STM=y
+CONFIG_EXT3_FS=y
+CONFIG_EXT4_FS_SECURITY=y
+CONFIG_VFAT_FS=y
+CONFIG_TMPFS=y
+CONFIG_UBIFS_FS=y
+CONFIG_UBIFS_FS_ADVANCED_COMPR=y
+CONFIG_NLS_CODEPAGE_437=y
+CONFIG_NLS_ASCII=y
+CONFIG_NLS_ISO8859_1=y
+CONFIG_PRINTK_TIME=y
+CONFIG_DYNAMIC_DEBUG=y
+CONFIG_DEBUG_INFO=y
+CONFIG_MAGIC_SYSRQ=y
+CONFIG_DEBUG_PAGEALLOC=y
+CONFIG_DEBUG_KMEMLEAK=y
+CONFIG_DEBUG_KMEMLEAK_DEFAULT_OFF=y
+CONFIG_DEBUG_STACK_USAGE=y
+CONFIG_DEBUG_MEMORY_INIT=y
+CONFIG_PANIC_TIMEOUT=5
+CONFIG_SCHEDSTATS=y
+CONFIG_TIMER_STATS=y
+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_BLK_DEV_IO_TRACE=y
+CONFIG_DEBUG_USER=y
+CONFIG_CRYPTO_ECB=y
+CONFIG_CRYPTO_CMAC=y
+CONFIG_CRYPTO_SHA256=y
+CONFIG_XZ_DEC=y
diff --git a/arch/arm/mach-qcom/Kconfig b/arch/arm/mach-qcom/Kconfig
index 28866e9..f4d7965 100644
--- a/arch/arm/mach-qcom/Kconfig
+++ b/arch/arm/mach-qcom/Kconfig
@@ -38,5 +38,18 @@
select CLKSRC_OF
select COMMON_CLK
+config ARCH_SDXPOORWILLS
+ bool "Enable support for SDXPOORWILLS"
+ select CPU_V7
+ select HAVE_ARM_ARCH_TIMER
+ select MSM_CORTEX_A7
+ select COMMON_CLK_MSM
+ select PINCTRL
+ select QCOM_SCM if SMP
+ select MSM_JTAG_MM if CORESIGHT_ETM
+ select PM_DEVFREQ
+ select COMMON_CLK
+ select COMMON_CLK_QCOM
+ select QCOM_GDSC
endmenu
endif
diff --git a/arch/arm/mach-qcom/Makefile b/arch/arm/mach-qcom/Makefile
index e7ffa04..d893b27 100644
--- a/arch/arm/mach-qcom/Makefile
+++ b/arch/arm/mach-qcom/Makefile
@@ -1,2 +1,3 @@
obj-$(CONFIG_USE_OF) += board-dt.o
obj-$(CONFIG_SMP) += platsmp.o
+obj-$(CONFIG_ARCH_SDXPOORWILLS) += board-poorwills.o
diff --git a/arch/arm/mach-qcom/board-poorwills.c b/arch/arm/mach-qcom/board-poorwills.c
new file mode 100644
index 0000000..31f5d3e
--- /dev/null
+++ b/arch/arm/mach-qcom/board-poorwills.c
@@ -0,0 +1,32 @@
+/* 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/kernel.h>
+#include "board-dt.h"
+#include <asm/mach/map.h>
+#include <asm/mach/arch.h>
+
+static const char *sdxpoorwills_dt_match[] __initconst = {
+ "qcom,sdxpoorwills",
+ NULL
+};
+
+static void __init sdxpoorwills_init(void)
+{
+ board_dt_populate(NULL);
+}
+
+DT_MACHINE_START(SDXPOORWILLS_DT,
+ "Qualcomm Technologies, Inc. SDX POORWILLS (Flattened Device Tree)")
+ .init_machine = sdxpoorwills_init,
+ .dt_compat = sdxpoorwills_dt_match,
+MACHINE_END
diff --git a/arch/arm/mm/dma-mapping.c b/arch/arm/mm/dma-mapping.c
index 33f3cc6..19f444e 100644
--- a/arch/arm/mm/dma-mapping.c
+++ b/arch/arm/mm/dma-mapping.c
@@ -2401,6 +2401,7 @@
set_dma_ops(dev, dma_ops);
}
+EXPORT_SYMBOL(arch_setup_dma_ops);
void arch_teardown_dma_ops(struct device *dev)
{
diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig
index d2deed5..b861876 100644
--- a/arch/arm64/Kconfig
+++ b/arch/arm64/Kconfig
@@ -686,7 +686,7 @@
config ARM64_DMA_IOMMU_ALIGNMENT
int "Maximum PAGE_SIZE order of alignment for DMA IOMMU buffers"
range 4 9
- default 8
+ default 9
help
DMA mapping framework by default aligns all buffers to the smallest
PAGE_SIZE order which is greater than or equal to the requested buffer
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 3766d51..f1501fa 100644
--- a/arch/arm64/boot/dts/qcom/msm-arm-smmu-sdm845.dtsi
+++ b/arch/arm64/boot/dts/qcom/msm-arm-smmu-sdm845.dtsi
@@ -33,16 +33,12 @@
<GIC_SPI 369 IRQ_TYPE_EDGE_RISING>,
<GIC_SPI 370 IRQ_TYPE_EDGE_RISING>,
<GIC_SPI 371 IRQ_TYPE_EDGE_RISING>;
- clock-names = "gcc_gpu_cfg_ahb_clk",
- "gcc_ddrss_gpu_axi_clk",
+ clock-names = "gcc_ddrss_gpu_axi_clk",
"gcc_gpu_memnoc_gfx_clk",
- "gcc_gpu_snoc_dvm_gfx_clk",
"gpu_cc_ahb_clk",
"gpu_cc_cx_gmu_clk";
- clocks = <&clock_gcc GCC_GPU_CFG_AHB_CLK>,
- <&clock_gcc GCC_DDRSS_GPU_AXI_CLK>,
+ clocks = <&clock_gcc GCC_DDRSS_GPU_AXI_CLK>,
<&clock_gcc GCC_GPU_MEMNOC_GFX_CLK>,
- <&clock_gcc GCC_GPU_SNOC_DVM_GFX_CLK>,
<&clock_gpucc GPU_CC_AHB_CLK>,
<&clock_gpucc GPU_CC_CX_GMU_CLK>;
attach-impl-defs =
diff --git a/arch/arm64/boot/dts/qcom/pm8998.dtsi b/arch/arm64/boot/dts/qcom/pm8998.dtsi
index 7c496f1..15db8da 100644
--- a/arch/arm64/boot/dts/qcom/pm8998.dtsi
+++ b/arch/arm64/boot/dts/qcom/pm8998.dtsi
@@ -136,6 +136,7 @@
interrupt-names = "eoc-int-en-set";
qcom,adc-bit-resolution = <15>;
qcom,adc-vdd-reference = <1875>;
+ #thermal-sensor-cells = <1>;
chan@6 {
label = "die_temp";
diff --git a/arch/arm64/boot/dts/qcom/pmi8998.dtsi b/arch/arm64/boot/dts/qcom/pmi8998.dtsi
index 539685a..923804f 100644
--- a/arch/arm64/boot/dts/qcom/pmi8998.dtsi
+++ b/arch/arm64/boot/dts/qcom/pmi8998.dtsi
@@ -232,6 +232,25 @@
<12000 2250>; /* 12V @ 2.25A */
};
+ bcl_sensor: bcl@4200 {
+ compatible = "qcom,msm-bcl-lmh";
+ reg = <0x4200 0xff>,
+ <0x4300 0xff>;
+ reg-names = "fg_user_adc",
+ "fg_lmh";
+ interrupts = <0x2 0x42 0x0 IRQ_TYPE_NONE>,
+ <0x2 0x42 0x1 IRQ_TYPE_NONE>,
+ <0x2 0x42 0x2 IRQ_TYPE_NONE>,
+ <0x2 0x42 0x3 IRQ_TYPE_NONE>,
+ <0x2 0x42 0x4 IRQ_TYPE_NONE>;
+ interrupt-names = "bcl-high-ibat",
+ "bcl-very-high-ibat",
+ "bcl-low-vbat",
+ "bcl-very-low-vbat",
+ "bcl-crit-low-vbat";
+ #thermal-sensor-cells = <1>;
+ };
+
pmi8998_rradc: rradc@4500 {
compatible = "qcom,rradc";
reg = <0x4500 0x100>;
@@ -651,3 +670,130 @@
};
};
};
+
+&thermal_zones {
+ ibat-high {
+ polling-delay-passive = <0>;
+ polling-delay = <0>;
+ thermal-governor = "step_wise";
+ thermal-sensors = <&bcl_sensor 0>;
+
+ trips {
+ ibat_high: low-ibat {
+ temperature = <4200>;
+ hysteresis = <200>;
+ type = "passive";
+ };
+ };
+ };
+ ibat-vhigh {
+ polling-delay-passive = <0>;
+ polling-delay = <0>;
+ thermal-governor = "step_wise";
+ thermal-sensors = <&bcl_sensor 1>;
+
+ trips {
+ ibat_vhigh: ibat_vhigh {
+ temperature = <4300>;
+ hysteresis = <100>;
+ type = "passive";
+ };
+ };
+ };
+ vbat {
+ polling-delay-passive = <100>;
+ polling-delay = <0>;
+ thermal-governor = "low_limits_cap";
+ thermal-sensors = <&bcl_sensor 2>;
+ tracks-low;
+
+ trips {
+ low_vbat: low-vbat {
+ temperature = <3300>;
+ hysteresis = <100>;
+ type = "passive";
+ };
+ };
+ cooling-maps {
+ vbat_cpu4 {
+ trip = <&low_vbat>;
+ cooling-device = <&CPU4 22 22>;
+ };
+ vbat_cpu5 {
+ trip = <&low_vbat>;
+ cooling-device = <&CPU5 22 22>;
+ };
+ vbat_map6 {
+ trip = <&low_vbat>;
+ cooling-device = <&CPU6 22 22>;
+ };
+ vbat_map7 {
+ trip = <&low_vbat>;
+ cooling-device = <&CPU7 22 22>;
+ };
+ };
+ };
+ vbat_low {
+ polling-delay-passive = <0>;
+ polling-delay = <0>;
+ thermal-governor = "low_limits_cap";
+ thermal-sensors = <&bcl_sensor 3>;
+ tracks-low;
+
+ trips {
+ low-vbat {
+ temperature = <3100>;
+ hysteresis = <0>;
+ type = "passive";
+ };
+ };
+ };
+ vbat_too_low {
+ polling-delay-passive = <0>;
+ polling-delay = <0>;
+ thermal-governor = "low_limits_cap";
+ thermal-sensors = <&bcl_sensor 4>;
+ tracks-low;
+
+ trips {
+ low-vbat {
+ temperature = <2900>;
+ hysteresis = <0>;
+ type = "passive";
+ };
+ };
+ };
+ soc {
+ polling-delay-passive = <100>;
+ polling-delay = <0>;
+ thermal-governor = "low_limits_cap";
+ thermal-sensors = <&bcl_sensor 5>;
+ tracks-low;
+
+ trips {
+ low_soc: low-soc {
+ temperature = <10>;
+ hysteresis = <0>;
+ type = "passive";
+ };
+ };
+ cooling-maps {
+ soc_cpu4 {
+ trip = <&low_soc>;
+ cooling-device = <&CPU4 22 22>;
+ };
+ soc_cpu5 {
+ trip = <&low_soc>;
+ cooling-device = <&CPU5 22 22>;
+ };
+ soc_map6 {
+ trip = <&low_soc>;
+ cooling-device = <&CPU6 22 22>;
+ };
+ soc_map7 {
+ trip = <&low_soc>;
+ cooling-device = <&CPU7 22 22>;
+ };
+ };
+ };
+};
diff --git a/arch/arm64/boot/dts/qcom/sdm845-audio.dtsi b/arch/arm64/boot/dts/qcom/sdm845-audio.dtsi
index b66ca94..9d59a16 100644
--- a/arch/arm64/boot/dts/qcom/sdm845-audio.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm845-audio.dtsi
@@ -18,7 +18,7 @@
&msm_audio_ion {
iommus = <&apps_smmu 0x1821>;
- qcom,smmu-sid-mask = <0xf>;
+ qcom,smmu-sid-mask = /bits/ 64 <0xf>;
};
&soc {
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 fce1687..c0189a4 100644
--- a/arch/arm64/boot/dts/qcom/sdm845-camera-sensor-cdp.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm845-camera-sensor-cdp.dtsi
@@ -14,7 +14,7 @@
&soc {
led_flash_rear: qcom,camera-flash@0 {
cell-index = <0>;
- reg = <0x0>;
+ reg = <0x00 0x00>;
compatible = "qcom,camera-flash";
qcom,flash-source = <&pmi8998_flash0 &pmi8998_flash1>;
qcom,torch-source = <&pmi8998_torch0 &pmi8998_torch1>;
@@ -24,7 +24,7 @@
led_flash_front: qcom,camera-flash@1 {
cell-index = <1>;
- reg = <0x1>;
+ reg = <0x01 0x00>;
compatible = "qcom,camera-flash";
qcom,flash-source = <&pmi8998_flash2>;
qcom,torch-source = <&pmi8998_torch2>;
@@ -34,7 +34,7 @@
actuator_regulator: gpio-regulator@0 {
compatible = "regulator-fixed";
- reg = <0x0>;
+ reg = <0x00 0x00>;
regulator-name = "actuator_regulator";
regulator-min-microvolt = <2800000>;
regulator-max-microvolt = <2800000>;
@@ -46,7 +46,7 @@
camera_rear_ldo: gpio-regulator@1 {
compatible = "regulator-fixed";
- reg = <0x1>;
+ reg = <0x01 0x00>;
regulator-name = "camera_rear_ldo";
regulator-min-microvolt = <1050000>;
regulator-max-microvolt = <1050000>;
@@ -60,7 +60,7 @@
camera_ldo: gpio-regulator@2 {
compatible = "regulator-fixed";
- reg = <0x2>;
+ reg = <0x02 0x00>;
regulator-name = "camera_ldo";
regulator-min-microvolt = <1050000>;
regulator-max-microvolt = <1050000>;
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 fce1687..c0189a4 100644
--- a/arch/arm64/boot/dts/qcom/sdm845-camera-sensor-mtp.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm845-camera-sensor-mtp.dtsi
@@ -14,7 +14,7 @@
&soc {
led_flash_rear: qcom,camera-flash@0 {
cell-index = <0>;
- reg = <0x0>;
+ reg = <0x00 0x00>;
compatible = "qcom,camera-flash";
qcom,flash-source = <&pmi8998_flash0 &pmi8998_flash1>;
qcom,torch-source = <&pmi8998_torch0 &pmi8998_torch1>;
@@ -24,7 +24,7 @@
led_flash_front: qcom,camera-flash@1 {
cell-index = <1>;
- reg = <0x1>;
+ reg = <0x01 0x00>;
compatible = "qcom,camera-flash";
qcom,flash-source = <&pmi8998_flash2>;
qcom,torch-source = <&pmi8998_torch2>;
@@ -34,7 +34,7 @@
actuator_regulator: gpio-regulator@0 {
compatible = "regulator-fixed";
- reg = <0x0>;
+ reg = <0x00 0x00>;
regulator-name = "actuator_regulator";
regulator-min-microvolt = <2800000>;
regulator-max-microvolt = <2800000>;
@@ -46,7 +46,7 @@
camera_rear_ldo: gpio-regulator@1 {
compatible = "regulator-fixed";
- reg = <0x1>;
+ reg = <0x01 0x00>;
regulator-name = "camera_rear_ldo";
regulator-min-microvolt = <1050000>;
regulator-max-microvolt = <1050000>;
@@ -60,7 +60,7 @@
camera_ldo: gpio-regulator@2 {
compatible = "regulator-fixed";
- reg = <0x2>;
+ reg = <0x02 0x00>;
regulator-name = "camera_ldo";
regulator-min-microvolt = <1050000>;
regulator-max-microvolt = <1050000>;
diff --git a/arch/arm64/boot/dts/qcom/sdm845-cdp.dtsi b/arch/arm64/boot/dts/qcom/sdm845-cdp.dtsi
index 96ce5a8..68824d7 100644
--- a/arch/arm64/boot/dts/qcom/sdm845-cdp.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm845-cdp.dtsi
@@ -12,6 +12,30 @@
#include <dt-bindings/gpio/gpio.h>
#include "sdm845-camera-sensor-cdp.dtsi"
+
+/ {
+ bluetooth: bt_wcn3990 {
+ compatible = "qca,wcn3990";
+ qca,bt-vdd-io-supply = <&pm8998_s3>;
+ qca,bt-vdd-xtal-supply = <&pm8998_s5>;
+ qca,bt-vdd-core-supply = <&pm8998_l7>;
+ qca,bt-vdd-pa-supply = <&pm8998_l17>;
+ qca,bt-vdd-ldo-supply = <&pm8998_l25>;
+
+ qca,bt-vdd-io-voltage-level = <1352000 1352000>;
+ qca,bt-vdd-xtal-voltage-level = <2040000 2040000>;
+ qca,bt-vdd-core-voltage-level = <1800000 1800000>;
+ qca,bt-vdd-pa-voltage-level = <1304000 1304000>;
+ qca,bt-vdd-ldo-voltage-level = <3312000 3312000>;
+
+ qca,bt-vdd-io-current-level = <1>; /* LPM/PFM */
+ qca,bt-vdd-xtal-current-level = <1>; /* LPM/PFM */
+ qca,bt-vdd-core-current-level = <1>; /* LPM/PFM */
+ qca,bt-vdd-pa-current-level = <1>; /* LPM/PFM */
+ qca,bt-vdd-ldo-current-level = <1>; /* LPM/PFM */
+ };
+};
+
&soc {
sound-tavil {
qcom,us-euro-gpios = <&tavil_us_euro_sw>;
@@ -119,6 +143,26 @@
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 &sdc2_data_on>;
+ pinctrl-1 = <&sdc2_clk_off &sdc2_cmd_off &sdc2_data_off>;
+
+ qcom,clk-rates = <400000 20000000 25000000
+ 50000000 100000000 200000000>;
+ qcom,bus-speed-mode = "SDR12", "SDR25", "SDR50", "DDR50", "SDR104";
+
+ status = "ok";
+};
+
&pmi8998_switch1 {
pinctrl-names = "led_enable", "led_disable";
pinctrl-0 = <&flash_led3_front_en>;
@@ -165,6 +209,30 @@
status = "ok";
};
+&labibb {
+ status = "ok";
+ qcom,qpnp-labibb-mode = "lcd";
+};
+
+&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-panel-mode-gpio-state = "dual_port";
+ qcom,panel-mode-gpio = <&tlmm 52 0>;
+ qcom,platform-reset-gpio = <&tlmm 6 0>;
+};
+
+&dsi_dual_nt35597_truly_video_display {
+ qcom,dsi-display-active;
+};
+
+&pmi8998_wled {
+ status = "okay";
+ qcom,led-strings-list = [01 02];
+};
+
&qupv3_se8_spi {
status = "ok";
};
@@ -190,3 +258,113 @@
&usb_qmp_phy {
status = "okay";
};
+
+&pm8998_vadc {
+ chan@83 {
+ label = "vph_pwr";
+ reg = <0x83>;
+ qcom,decimation = <2>;
+ qcom,pre-div-channel-scaling = <1>;
+ qcom,calibration-type = "absolute";
+ qcom,scale-function = <0>;
+ qcom,hw-settle-time = <0>;
+ qcom,fast-avg-setup = <0>;
+ };
+
+ chan@85 {
+ label = "vcoin";
+ reg = <0x85>;
+ qcom,decimation = <2>;
+ qcom,pre-div-channel-scaling = <1>;
+ qcom,calibration-type = "absolute";
+ qcom,scale-function = <0>;
+ qcom,hw-settle-time = <0>;
+ qcom,fast-avg-setup = <0>;
+ };
+
+ chan@4c {
+ label = "xo_therm";
+ reg = <0x4c>;
+ qcom,decimation = <2>;
+ qcom,pre-div-channel-scaling = <0>;
+ qcom,calibration-type = "ratiometric";
+ qcom,scale-function = <4>;
+ qcom,hw-settle-time = <2>;
+ qcom,fast-avg-setup = <0>;
+ qcom,vadc-thermal-node;
+ };
+
+ chan@4d {
+ label = "msm_therm";
+ reg = <0x4d>;
+ qcom,decimation = <2>;
+ qcom,pre-div-channel-scaling = <0>;
+ qcom,calibration-type = "ratiometric";
+ qcom,scale-function = <2>;
+ qcom,hw-settle-time = <2>;
+ qcom,fast-avg-setup = <0>;
+ qcom,vadc-thermal-node;
+ };
+
+ chan@4f {
+ label = "pa_therm1";
+ reg = <0x4f>;
+ qcom,decimation = <2>;
+ qcom,pre-div-channel-scaling = <0>;
+ qcom,calibration-type = "ratiometric";
+ qcom,scale-function = <2>;
+ qcom,hw-settle-time = <2>;
+ qcom,fast-avg-setup = <0>;
+ qcom,vadc-thermal-node;
+ };
+
+ chan@51 {
+ label = "quiet_therm";
+ reg = <0x51>;
+ qcom,decimation = <2>;
+ qcom,pre-div-channel-scaling = <0>;
+ qcom,calibration-type = "ratiometric";
+ qcom,scale-function = <2>;
+ qcom,hw-settle-time = <2>;
+ qcom,fast-avg-setup = <0>;
+ qcom,vadc-thermal-node;
+ };
+};
+
+&pm8998_adc_tm {
+ chan@83 {
+ label = "vph_pwr";
+ reg = <0x83>;
+ qcom,pre-div-channel-scaling = <1>;
+ qcom,calibration-type = "absolute";
+ qcom,scale-function = <0>;
+ qcom,hw-settle-time = <0>;
+ qcom,btm-channel-number = <0x60>;
+ };
+};
+
+&thermal_zones {
+ xo-therm-adc {
+ polling-delay-passive = <0>;
+ polling-delay = <0>;
+ thermal-sensors = <&pm8998_vadc 0x4c>;
+ };
+
+ msm-therm-adc {
+ polling-delay-passive = <0>;
+ polling-delay = <0>;
+ thermal-sensors = <&pm8998_vadc 0x4d>;
+ };
+
+ pa-therm1-adc {
+ polling-delay-passive = <0>;
+ polling-delay = <0>;
+ thermal-sensors = <&pm8998_vadc 0x4f>;
+ };
+
+ quiet-therm-adc {
+ polling-delay-passive = <0>;
+ polling-delay = <0>;
+ thermal-sensors = <&pm8998_vadc 0x51>;
+ };
+};
diff --git a/arch/arm64/boot/dts/qcom/sdm845-coresight.dtsi b/arch/arm64/boot/dts/qcom/sdm845-coresight.dtsi
index fa225ef1..434de76 100644
--- a/arch/arm64/boot/dts/qcom/sdm845-coresight.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm845-coresight.dtsi
@@ -21,9 +21,8 @@
coresight-name = "coresight-replicator";
- clocks = <&clock_gcc RPMH_QDSS_CLK>,
- <&clock_gcc RPMH_QDSS_A_CLK>;
- clock-names = "apb_pclk", "core_a_clk";
+ clocks = <&clock_aop QDSS_CLK>;
+ clock-names = "apb_pclk";
ports {
#address-cells = <1>;
@@ -57,9 +56,8 @@
coresight-name = "coresight-replicator-swao";
- clocks = <&clock_gcc RPMH_QDSS_CLK>,
- <&clock_gcc RPMH_QDSS_A_CLK>;
- clock-names = "apb_pclk", "core_a_clk";
+ clocks = <&clock_aop QDSS_CLK>;
+ clock-names = "apb_pclk";
ports {
#address-cells = <1>;
@@ -106,9 +104,8 @@
coresight-name = "coresight-tmc-etf-swao";
- clocks = <&clock_gcc RPMH_QDSS_CLK>,
- <&clock_gcc RPMH_QDSS_A_CLK>;
- clock-names = "apb_pclk", "core_a_clk";
+ clocks = <&clock_aop QDSS_CLK>;
+ clock-names = "apb_pclk";
ports {
#address-cells = <1>;
@@ -143,9 +140,8 @@
coresight-name = "coresight-funnel-swao";
- clocks = <&clock_gcc RPMH_QDSS_CLK>,
- <&clock_gcc RPMH_QDSS_A_CLK>;
- clock-names = "apb_pclk", "core_a_clk";
+ clocks = <&clock_aop QDSS_CLK>;
+ clock-names = "apb_pclk";
ports {
#address-cells = <1>;
@@ -171,7 +167,8 @@
};
tpda_swao: tpda@6b01000 {
- compatible = "qcom,coresight-tpda";
+ compatible = "arm,primecell";
+ arm,primecell-periphid = <0x0003b969>;
reg = <0x6b01000 0x1000>;
reg-names = "tpda-base";
@@ -181,9 +178,8 @@
qcom,dsb-elem-size = <1 32>;
qcom,cmb-elem-size = <0 64>;
- clocks = <&clock_gcc RPMH_QDSS_CLK>,
- <&clock_gcc RPMH_QDSS_A_CLK>;
- clock-names = "core_clk", "core_a_clk";
+ clocks = <&clock_aop QDSS_CLK>;
+ clock-names = "apb_pclk";
ports {
#address-cells = <1>;
@@ -220,16 +216,16 @@
};
tpdm_swao0: tpdm@6b02000 {
- compatible = "qcom,coresight-tpdm";
+ compatible = "arm,primecell";
+ arm,primecell-periphid = <0x0003b968>;
reg = <0x6b02000 0x1000>;
reg-names = "tpdm-base";
coresight-name = "coresight-tpdm-swao-0";
- clocks = <&clock_gcc RPMH_QDSS_CLK>,
- <&clock_gcc RPMH_QDSS_A_CLK>;
- clock-names = "core_clk", "core_a_clk";
+ clocks = <&clock_aop QDSS_CLK>;
+ clock-names = "apb_pclk";
port {
tpdm_swao0_out_tpda_swao: endpoint {
@@ -239,15 +235,15 @@
};
tpdm_swao1: tpdm@6b03000 {
- compatible = "qcom,coresight-tpdm";
+ compatible = "arm,primecell";
+ arm,primecell-periphid = <0x0003b968>;
reg = <0x6b03000 0x1000>;
reg-names = "tpdm-base";
coresight-name="coresight-tpdm-swao-1";
- clocks = <&clock_gcc RPMH_QDSS_CLK>,
- <&clock_gcc RPMH_QDSS_A_CLK>;
- clock-names = "core_clk", "core_a_clk";
+ clocks = <&clock_aop QDSS_CLK>;
+ clock-names = "apb_pclk";
port {
tpdm_swao1_out_tpda_swao: endpoint {
@@ -265,13 +261,13 @@
reg-names = "tmc-base", "bam-base";
arm,buffer-size = <0x400000>;
+ arm,sg-enable;
coresight-name = "coresight-tmc-etr";
coresight-ctis = <&cti0 &cti8>;
- clocks = <&clock_gcc RPMH_QDSS_CLK>,
- <&clock_gcc RPMH_QDSS_A_CLK>;
- clock-names = "apb_pclk", "core_a_clk";
+ clocks = <&clock_aop QDSS_CLK>;
+ clock-names = "apb_pclk";
port {
tmc_etr_in_replicator: endpoint {
@@ -292,9 +288,8 @@
coresight-ctis = <&cti0 &cti8>;
arm,default-sink;
- clocks = <&clock_gcc RPMH_QDSS_CLK>,
- <&clock_gcc RPMH_QDSS_A_CLK>;
- clock-names = "apb_pclk", "core_a_clk";
+ clocks = <&clock_aop QDSS_CLK>;
+ clock-names = "apb_pclk";
ports {
#address-cells = <1>;
@@ -329,9 +324,8 @@
coresight-name = "coresight-funnel-merg";
- clocks = <&clock_gcc RPMH_QDSS_CLK>,
- <&clock_gcc RPMH_QDSS_A_CLK>;
- clock-names = "apb_pclk", "core_a_clk";
+ clocks = <&clock_aop QDSS_CLK>;
+ clock-names = "apb_pclk";
ports {
#address-cells = <1>;
@@ -375,9 +369,8 @@
coresight-name = "coresight-stm";
- clocks = <&clock_gcc RPMH_QDSS_CLK>,
- <&clock_gcc RPMH_QDSS_A_CLK>;
- clock-names = "apb_pclk", "core_a_clk";
+ clocks = <&clock_aop QDSS_CLK>;
+ clock-names = "apb_pclk";
port {
stm_out_funnel_in0: endpoint {
@@ -396,9 +389,8 @@
coresight-name = "coresight-funnel-in0";
- clocks = <&clock_gcc RPMH_QDSS_CLK>,
- <&clock_gcc RPMH_QDSS_A_CLK>;
- clock-names = "apb_pclk", "core_a_clk";
+ clocks = <&clock_aop QDSS_CLK>;
+ clock-names = "apb_pclk";
ports {
#address-cells = <1>;
@@ -449,9 +441,8 @@
coresight-name = "coresight-funnel-in2";
- clocks = <&clock_gcc RPMH_QDSS_CLK>,
- <&clock_gcc RPMH_QDSS_A_CLK>;
- clock-names = "apb_pclk", "core_a_clk";
+ clocks = <&clock_aop QDSS_CLK>;
+ clock-names = "apb_pclk";
ports {
#address-cells = <1>;
@@ -498,7 +489,8 @@
};
tpda: tpda@6004000 {
- compatible = "qcom,coresight-tpda";
+ compatible = "arm,primecell";
+ arm,primecell-periphid = <0x0003b969>;
reg = <0x6004000 0x1000>;
reg-names = "tpda-base";
@@ -511,6 +503,7 @@
qcom,dsb-elem-size = <0 32>,
<2 32>,
<3 32>,
+ <5 32>,
<10 32>,
<11 32>,
<13 32>;
@@ -518,9 +511,8 @@
<7 64>,
<13 64>;
- clocks = <&clock_gcc RPMH_QDSS_CLK>,
- <&clock_gcc RPMH_QDSS_A_CLK>;
- clock-names = "core_clk", "core_a_clk";
+ clocks = <&clock_aop QDSS_CLK>;
+ clock-names = "apb_pclk";
ports {
#address-cells = <1>;
@@ -562,6 +554,15 @@
};
port@4 {
+ reg = <5>;
+ tpda_in_funnel_lpass: endpoint {
+ slave-mode;
+ remote-endpoint =
+ <&funnel_lpass_out_tpda>;
+ };
+ };
+
+ port@5 {
reg = <7>;
tpda_in_tpdm_vsense: endpoint {
slave-mode;
@@ -570,7 +571,7 @@
};
};
- port@5 {
+ port@6 {
reg = <10>;
tpda_in_tpdm_qm: endpoint {
slave-mode;
@@ -579,7 +580,7 @@
};
};
- port@6 {
+ port@7 {
reg = <11>;
tpda_in_tpdm_north: endpoint {
slave-mode;
@@ -588,7 +589,7 @@
};
};
- port@7 {
+ port@8 {
reg = <13>;
tpda_in_tpdm_pimem: endpoint {
slave-mode;
@@ -608,9 +609,8 @@
coresight-name = "coresight-funnel-modem";
- clocks = <&clock_gcc RPMH_QDSS_CLK>,
- <&clock_gcc RPMH_QDSS_A_CLK>;
- clock-names = "apb_pclk", "core_a_clk";
+ clocks = <&clock_aop QDSS_CLK>;
+ clock-names = "apb_pclk";
ports {
#address-cells = <1>;
@@ -636,7 +636,8 @@
};
tpda_modem: tpda@6831000 {
- compatible = "qcom,coresight-tpda";
+ compatible = "arm,primecell";
+ arm,primecell-periphid = <0x0003b969>;
reg = <0x6831000 0x1000>;
reg-names = "tpda-base";
@@ -646,9 +647,8 @@
qcom,dsb-elem-size = <0 32>;
qcom,cmb-elem-size = <0 64>;
- clocks = <&clock_gcc RPMH_QDSS_CLK>,
- <&clock_gcc RPMH_QDSS_A_CLK>;
- clock-names = "core_clk", "core_a_clk";
+ clocks = <&clock_aop QDSS_CLK>;
+ clock-names = "apb_pclk";
ports {
#address-cells = <1>;
@@ -673,15 +673,15 @@
};
tpdm_modem: tpdm@6830000 {
- compatible = "qcom,coresight-tpdm";
+ compatible = "arm,primecell";
+ arm,primecell-periphid = <0x0003b968>;
reg = <0x6830000 0x1000>;
reg-names = "tpdm-base";
coresight-name = "coresight-tpdm-modem";
- clocks = <&clock_gcc RPMH_QDSS_CLK>,
- <&clock_gcc RPMH_QDSS_A_CLK>;
- clock-names = "core_clk", "core_a_clk";
+ clocks = <&clock_aop QDSS_CLK>;
+ clock-names = "apb_pclk";
port {
tpdm_modem_out_tpda_modem: endpoint {
@@ -690,16 +690,68 @@
};
};
- tpdm_center: tpdm@6c28000 {
+ funnel_lpass: funnel@6845000 {
+ compatible = "arm,primecell";
+ arm,primecell-periphid = <0x0003b908>;
+
+ reg = <0x6845000 0x1000>;
+ reg-names = "funnel-base";
+
+ coresight-name = "coresight-funnel-lpass";
+
+ clocks = <&clock_aop QDSS_CLK>;
+ clock-names = "apb_pclk";
+
+ ports {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ port@0 {
+ reg = <0>;
+ funnel_lpass_out_tpda: endpoint {
+ remote-endpoint =
+ <&tpda_in_funnel_lpass>;
+ };
+ };
+
+ port@1 {
+ reg = <0>;
+ funnel_lpass_in_tpdm_lpass: endpoint {
+ slave-mode;
+ remote-endpoint =
+ <&tpdm_lpass_out_funnel_lpass>;
+ };
+ };
+ };
+ };
+
+ tpdm_lpass: tpdm@6844000 {
compatible = "qcom,coresight-tpdm";
+ reg = <0x6844000 0x1000>;
+ reg-names = "tpdm-base";
+
+ coresight-name = "coresight-tpdm-lpass";
+
+ clocks = <&clock_aop QDSS_CLK>;
+ clock-names = "core_clk";
+
+ port {
+ tpdm_lpass_out_funnel_lpass: endpoint {
+ remote-endpoint = <&funnel_lpass_in_tpdm_lpass>;
+ };
+ };
+ };
+
+ tpdm_center: tpdm@6c28000 {
+ compatible = "arm,primecell";
+ arm,primecell-periphid = <0x0003b968>;
reg = <0x6c28000 0x1000>;
reg-names = "tpdm-base";
coresight-name = "coresight-tpdm-center";
- clocks = <&clock_gcc RPMH_QDSS_CLK>,
- <&clock_gcc RPMH_QDSS_A_CLK>;
- clock-names = "core_clk", "core_a_clk";
+ clocks = <&clock_aop QDSS_CLK>;
+ clock-names = "apb_pclk";
port {
tpdm_center_out_tpda: endpoint {
@@ -709,15 +761,15 @@
};
tpdm_north: tpdm@6a24000 {
- compatible = "qcom,coresight-tpdm";
+ compatible = "arm,primecell";
+ arm,primecell-periphid = <0x0003b968>;
reg = <0x6a24000 0x1000>;
reg-names = "tpdm-base";
coresight-name = "coresight-tpdm-north";
- clocks = <&clock_gcc RPMH_QDSS_CLK>,
- <&clock_gcc RPMH_QDSS_A_CLK>;
- clock-names = "core_clk", "core_a_clk";
+ clocks = <&clock_aop QDSS_CLK>;
+ clock-names = "apb_pclk";
port {
tpdm_north_out_tpda: endpoint {
@@ -727,15 +779,15 @@
};
tpdm_qm: tpdm@69d0000 {
- compatible = "qcom,coresight-tpdm";
+ compatible = "arm,primecell";
+ arm,primecell-periphid = <0x0003b968>;
reg = <0x69d0000 0x1000>;
reg-names = "tpdm-base";
coresight-name = "coresight-tpdm-qm";
- clocks = <&clock_gcc RPMH_QDSS_CLK>,
- <&clock_gcc RPMH_QDSS_A_CLK>;
- clock-names = "core_clk", "core_a_clk";
+ clocks = <&clock_aop QDSS_CLK>;
+ clock-names = "apb_pclk";
port {
tpdm_qm_out_tpda: endpoint {
@@ -745,7 +797,8 @@
};
tpda_apss: tpda@7862000 {
- compatible = "qcom,coresight-tpda";
+ compatible = "arm,primecell";
+ arm,primecell-periphid = <0x0003b969>;
reg = <0x7862000 0x1000>;
reg-names = "tpda-base";
@@ -754,9 +807,8 @@
qcom,tpda-atid = <66>;
qcom,dsb-elem-size = <0 32>;
- clocks = <&clock_gcc RPMH_QDSS_CLK>,
- <&clock_gcc RPMH_QDSS_A_CLK>;
- clock-names = "core_clk", "core_a_clk";
+ clocks = <&clock_aop QDSS_CLK>;
+ clock-names = "apb_pclk";
ports {
#address-cells = <1>;
@@ -781,15 +833,15 @@
};
tpdm_apss: tpdm@7860000 {
- compatible = "qcom,coresight-tpdm";
+ compatible = "arm,primecell";
+ arm,primecell-periphid = <0x0003b968>;
reg = <0x7860000 0x1000>;
reg-names = "tpdm-base";
coresight-name = "coresight-tpdm-apss";
- clocks = <&clock_gcc RPMH_QDSS_CLK>,
- <&clock_gcc RPMH_QDSS_A_CLK>;
- clock-names = "core_clk", "core_a_clk";
+ clocks = <&clock_aop QDSS_CLK>;
+ clock-names = "apb_pclk";
port {
tpdm_apss_out_tpda_apss: endpoint {
@@ -799,7 +851,8 @@
};
tpda_llm_silver: tpda@78c0000 {
- compatible = "qcom,coresight-tpda";
+ compatible = "arm,primecell";
+ arm,primecell-periphid = <0x0003b969>;
reg = <0x78c0000 0x1000>;
reg-names = "tpda-base";
@@ -808,9 +861,8 @@
qcom,tpda-atid = <72>;
qcom,cmb-elem-size = <0 64>;
- clocks = <&clock_gcc RPMH_QDSS_CLK>,
- <&clock_gcc RPMH_QDSS_A_CLK>;
- clock-names = "core_clk", "core_a_clk";
+ clocks = <&clock_aop QDSS_CLK>;
+ clock-names = "apb_pclk";
ports {
#address-cells = <1>;
@@ -835,15 +887,15 @@
};
tpdm_llm_silver: tpdm@78a0000 {
- compatible = "qcom,coresight-tpdm";
+ compatible = "arm,primecell";
+ arm,primecell-periphid = <0x0003b968>;
reg = <0x78a0000 0x1000>;
reg-names = "tpdm-base";
coresight-name = "coresight-tpdm-llm-silver";
- clocks = <&clock_gcc RPMH_QDSS_CLK>,
- <&clock_gcc RPMH_QDSS_A_CLK>;
- clock-names = "core_clk", "core_a_clk";
+ clocks = <&clock_aop QDSS_CLK>;
+ clock-names = "apb_pclk";
port {
tpdm_llm_silver_out_tpda_llm_silver: endpoint {
@@ -854,7 +906,8 @@
};
tpda_llm_gold: tpda@78d0000 {
- compatible = "qcom,coresight-tpda";
+ compatible = "arm,primecell";
+ arm,primecell-periphid = <0x0003b969>;
reg = <0x78d0000 0x1000>;
reg-names = "tpda-base";
@@ -863,9 +916,8 @@
qcom,tpda-atid = <73>;
qcom,cmb-elem-size = <0 64>;
- clocks = <&clock_gcc RPMH_QDSS_CLK>,
- <&clock_gcc RPMH_QDSS_A_CLK>;
- clock-names = "core_clk", "core_a_clk";
+ clocks = <&clock_aop QDSS_CLK>;
+ clock-names = "apb_pclk";
ports {
#address-cells = <1>;
@@ -890,15 +942,15 @@
};
tpdm_llm_gold: tpdm@78b0000 {
- compatible = "qcom,coresight-tpdm";
+ compatible = "arm,primecell";
+ arm,primecell-periphid = <0x0003b968>;
reg = <0x78b0000 0x1000>;
reg-names = "tpdm-base";
coresight-name = "coresight-tpdm-llm-gold";
- clocks = <&clock_gcc RPMH_QDSS_CLK>,
- <&clock_gcc RPMH_QDSS_A_CLK>;
- clock-names = "core_clk", "core_a_clk";
+ clocks = <&clock_aop QDSS_CLK>;
+ clock-names = "apb_pclk";
port {
tpdm_llm_gold_out_tpda_llm_gold: endpoint {
@@ -917,9 +969,8 @@
coresight-name = "coresight-funnel-dl-mm";
- clocks = <&clock_gcc RPMH_QDSS_CLK>,
- <&clock_gcc RPMH_QDSS_A_CLK>;
- clock-names = "apb_pclk", "core_a_clk";
+ clocks = <&clock_aop QDSS_CLK>;
+ clock-names = "apb_pclk";
ports {
#address-cells = <1>;
@@ -945,15 +996,15 @@
};
tpdm_mm: tpdm@6c08000 {
- compatible = "qcom,coresight-tpdm";
+ compatible = "arm,primecell";
+ arm,primecell-periphid = <0x0003b968>;
reg = <0x6c08000 0x1000>;
reg-names = "tpdm-base";
coresight-name = "coresight-tpdm-mm";
- clocks = <&clock_gcc RPMH_QDSS_CLK>,
- <&clock_gcc RPMH_QDSS_A_CLK>;
- clock-names = "core_clk", "core_a_clk";
+ clocks = <&clock_aop QDSS_CLK>;
+ clock-names = "apb_pclk";
port {
tpdm_mm_out_funnel_dl_mm: endpoint {
@@ -971,9 +1022,8 @@
coresight-name = "coresight-funnel-ddr-0";
- clocks = <&clock_gcc RPMH_QDSS_CLK>,
- <&clock_gcc RPMH_QDSS_A_CLK>;
- clock-names = "apb_pclk", "core_a_clk";
+ clocks = <&clock_aop QDSS_CLK>;
+ clock-names = "apb_pclk";
ports {
#address-cells = <1>;
@@ -999,15 +1049,15 @@
};
tpdm_ddr: tpdm@69e0000 {
- compatible = "qcom,coresight-tpdm";
+ compatible = "arm,primecell";
+ arm,primecell-periphid = <0x0003b968>;
reg = <0x69e0000 0x1000>;
reg-names = "tpdm-base";
coresight-name = "coresight-tpdm-ddr";
- clocks = <&clock_gcc RPMH_QDSS_CLK>,
- <&clock_gcc RPMH_QDSS_A_CLK>;
- clock-names = "core_clk", "core_a_clk";
+ clocks = <&clock_aop QDSS_CLK>;
+ clock-names = "apb_pclk";
port {
tpdm_ddr_out_funnel_ddr_0: endpoint {
@@ -1017,15 +1067,15 @@
};
tpdm_pimem: tpdm@6850000 {
- compatible = "qcom,coresight-tpdm";
+ compatible = "arm,primecell";
+ arm,primecell-periphid = <0x0003b968>;
reg = <0x6850000 0x1000>;
reg-names = "tpdm-base";
coresight-name = "coresight-tpdm-pimem";
- clocks = <&clock_gcc RPMH_QDSS_CLK>,
- <&clock_gcc RPMH_QDSS_A_CLK>;
- clock-names = "core_clk", "core_a_clk";
+ clocks = <&clock_aop QDSS_CLK>;
+ clock-names = "apb_pclk";
port {
tpdm_pimem_out_tpda: endpoint {
@@ -1035,15 +1085,15 @@
};
tpdm_vsense: tpdm@6840000 {
- compatible = "qcom,coresight-tpdm";
+ compatible = "arm,primecell";
+ arm,primecell-periphid = <0x0003b968>;
reg = <0x6840000 0x1000>;
reg-names = "tpdm-base";
coresight-name = "coresight-tpdm-vsense";
- clocks = <&clock_gcc RPMH_QDSS_CLK>,
- <&clock_gcc RPMH_QDSS_A_CLK>;
- clock-names = "core_clk", "core_a_clk";
+ clocks = <&clock_aop QDSS_CLK>;
+ clock-names = "apb_pclk";
port{
tpdm_vsense_out_tpda: endpoint {
@@ -1053,7 +1103,8 @@
};
tpda_olc: tpda@7832000 {
- compatible = "qcom,coresight-tpda";
+ compatible = "arm,primecell";
+ arm,primecell-periphid = <0x0003b969>;
reg = <0x7832000 0x1000>;
reg-names = "tpda-base";
@@ -1062,9 +1113,8 @@
qcom,tpda-atid = <69>;
qcom,cmb-elem-size = <0 64>;
- clocks = <&clock_gcc RPMH_QDSS_CLK>,
- <&clock_gcc RPMH_QDSS_A_CLK>;
- clock-names = "core_clk", "core_a_clk";
+ clocks = <&clock_aop QDSS_CLK>;
+ clock-names = "apb_pclk";
ports {
#address-cells = <1>;
@@ -1088,15 +1138,15 @@
};
tpdm_olc: tpdm@7830000 {
- compatible = "qcom,coresight-tpdm";
+ compatible = "arm,primecell";
+ arm,primecell-periphid = <0x0003b968>;
reg = <0x7830000 0x1000>;
reg-names = "tpdm-base";
coresight-name = "coresight-tpdm-olc";
- clocks = <&clock_gcc RPMH_QDSS_CLK>,
- <&clock_gcc RPMH_QDSS_A_CLK>;
- clock-names = "core_clk", "core_a_clk";
+ clocks = <&clock_aop QDSS_CLK>;
+ clock-names = "apb_pclk";
port{
tpdm_olc_out_tpda_olc: endpoint {
@@ -1106,7 +1156,8 @@
};
tpda_spss: tpda@6882000 {
- compatible = "qcom,coresight-tpda";
+ compatible = "arm,primecell";
+ arm,primecell-periphid = <0x0003b969>;
reg = <0x6882000 0x1000>;
reg-names = "tpda-base";
@@ -1115,9 +1166,8 @@
qcom,tpda-atid = <70>;
qcom,dsb-elem-size = <0 32>;
- clocks = <&clock_gcc RPMH_QDSS_CLK>,
- <&clock_gcc RPMH_QDSS_A_CLK>;
- clock-names = "core_clk", "core_a_clk";
+ clocks = <&clock_aop QDSS_CLK>;
+ clock-names = "apb_pclk";
ports {
#address-cells = <1>;
@@ -1141,16 +1191,15 @@
};
tpdm_spss: tpdm@6880000 {
- compatible = "qcom,coresight-tpdm";
+ compatible = "arm,primecell";
+ arm,primecell-periphid = <0x0003b968>;
reg = <0x6880000 0x1000>;
reg-names = "tpdm-base";
coresight-name = "coresight-tpdm-spss";
- clocks = <&clock_gcc RPMH_QDSS_CLK>,
- <&clock_gcc RPMH_QDSS_A_CLK>;
- clock-names = "core_clk", "core_a_clk";
-
+ clocks = <&clock_aop QDSS_CLK>;
+ clock-names = "apb_pclk";
qcom,msr-fix-req;
port{
@@ -1169,9 +1218,8 @@
coresight-name = "coresight-funnel-spss";
- clocks = <&clock_gcc RPMH_QDSS_CLK>,
- <&clock_gcc RPMH_QDSS_A_CLK>;
- clock-names = "apb_pclk", "core_a_clk";
+ clocks = <&clock_aop QDSS_CLK>;
+ clock-names = "apb_pclk";
ports {
#address-cells = <1>;
@@ -1205,9 +1253,8 @@
coresight-name = "coresight-funnel-qatb";
- clocks = <&clock_gcc RPMH_QDSS_CLK>,
- <&clock_gcc RPMH_QDSS_A_CLK>;
- clock-names = "apb_pclk", "core_a_clk";
+ clocks = <&clock_aop QDSS_CLK>;
+ clock-names = "apb_pclk";
ports {
#address-cells = <1>;
@@ -1233,299 +1280,315 @@
};
cti0: cti@6010000 {
- compatible = "arm,coresight-cti";
+ compatible = "arm,primecell";
+ arm,primecell-periphid = <0x0003b966>;
reg = <0x6010000 0x1000>;
reg-names = "cti-base";
coresight-name = "coresight-cti0";
- clocks = <&clock_gcc RPMH_QDSS_CLK>,
- <&clock_gcc RPMH_QDSS_A_CLK>;
- clock-names = "core_clk", "core_a_clk";
+ clocks = <&clock_aop QDSS_CLK>;
+ clock-names = "apb_pclk";
+
};
cti1: cti@6011000 {
- compatible = "arm,coresight-cti";
+ compatible = "arm,primecell";
+ arm,primecell-periphid = <0x0003b966>;
reg = <0x6011000 0x1000>;
reg-names = "cti-base";
coresight-name = "coresight-cti1";
- clocks = <&clock_gcc RPMH_QDSS_CLK>,
- <&clock_gcc RPMH_QDSS_A_CLK>;
- clock-names = "core_clk", "core_a_clk";
+ clocks = <&clock_aop QDSS_CLK>;
+ clock-names = "apb_pclk";
+
};
cti2: cti@6012000 {
- compatible = "arm,coresight-cti";
+ compatible = "arm,primecell";
+ arm,primecell-periphid = <0x0003b966>;
reg = <0x6012000 0x1000>;
reg-names = "cti-base";
coresight-name = "coresight-cti2";
- clocks = <&clock_gcc RPMH_QDSS_CLK>,
- <&clock_gcc RPMH_QDSS_A_CLK>;
- clock-names = "core_clk", "core_a_clk";
+ clocks = <&clock_aop QDSS_CLK>;
+ clock-names = "apb_pclk";
};
cti3: cti@6013000 {
- compatible = "arm,coresight-cti";
+ compatible = "arm,primecell";
+ arm,primecell-periphid = <0x0003b966>;
reg = <0x6013000 0x1000>;
reg-names = "cti-base";
coresight-name = "coresight-cti3";
- clocks = <&clock_gcc RPMH_QDSS_CLK>,
- <&clock_gcc RPMH_QDSS_A_CLK>;
- clock-names = "core_clk", "core_a_clk";
+ clocks = <&clock_aop QDSS_CLK>;
+ clock-names = "apb_pclk";
+
};
cti4: cti@6014000 {
- compatible = "arm,coresight-cti";
+ compatible = "arm,primecell";
+ arm,primecell-periphid = <0x0003b966>;
reg = <0x6014000 0x1000>;
reg-names = "cti-base";
coresight-name = "coresight-cti4";
- clocks = <&clock_gcc RPMH_QDSS_CLK>,
- <&clock_gcc RPMH_QDSS_A_CLK>;
- clock-names = "core_clk", "core_a_clk";
+ clocks = <&clock_aop QDSS_CLK>;
+ clock-names = "apb_pclk";
+
};
cti5: cti@6015000 {
- compatible = "arm,coresight-cti";
+ compatible = "arm,primecell";
+ arm,primecell-periphid = <0x0003b966>;
reg = <0x6015000 0x1000>;
reg-names = "cti-base";
coresight-name = "coresight-cti5";
- clocks = <&clock_gcc RPMH_QDSS_CLK>,
- <&clock_gcc RPMH_QDSS_A_CLK>;
- clock-names = "core_clk", "core_a_clk";
+ clocks = <&clock_aop QDSS_CLK>;
+ clock-names = "apb_pclk";
+
};
cti6: cti@6016000 {
- compatible = "arm,coresight-cti";
+ compatible = "arm,primecell";
+ arm,primecell-periphid = <0x0003b966>;
reg = <0x6016000 0x1000>;
reg-names = "cti-base";
coresight-name = "coresight-cti6";
- clocks = <&clock_gcc RPMH_QDSS_CLK>,
- <&clock_gcc RPMH_QDSS_A_CLK>;
- clock-names = "core_clk", "core_a_clk";
+ clocks = <&clock_aop QDSS_CLK>;
+ clock-names = "apb_pclk";
+
};
cti7: cti@6017000 {
- compatible = "arm,coresight-cti";
+ compatible = "arm,primecell";
+ arm,primecell-periphid = <0x0003b966>;
reg = <0x6017000 0x1000>;
reg-names = "cti-base";
coresight-name = "coresight-cti7";
- clocks = <&clock_gcc RPMH_QDSS_CLK>,
- <&clock_gcc RPMH_QDSS_A_CLK>;
- clock-names = "core_clk", "core_a_clk";
+ clocks = <&clock_aop QDSS_CLK>;
+ clock-names = "apb_pclk";
+
};
cti8: cti@6018000 {
- compatible = "arm,coresight-cti";
+ compatible = "arm,primecell";
+ arm,primecell-periphid = <0x0003b966>;
reg = <0x6018000 0x1000>;
reg-names = "cti-base";
coresight-name = "coresight-cti8";
- clocks = <&clock_gcc RPMH_QDSS_CLK>,
- <&clock_gcc RPMH_QDSS_A_CLK>;
- clock-names = "core_clk", "core_a_clk";
+ clocks = <&clock_aop QDSS_CLK>;
+ clock-names = "apb_pclk";
+
};
cti9: cti@6019000 {
- compatible = "arm,coresight-cti";
+ compatible = "arm,primecell";
+ arm,primecell-periphid = <0x0003b966>;
reg = <0x6019000 0x1000>;
reg-names = "cti-base";
coresight-name = "coresight-cti9";
- clocks = <&clock_gcc RPMH_QDSS_CLK>,
- <&clock_gcc RPMH_QDSS_A_CLK>;
- clock-names = "core_clk", "core_a_clk";
+ clocks = <&clock_aop QDSS_CLK>;
+ clock-names = "apb_pclk";
+
};
cti10: cti@601a000 {
- compatible = "arm,coresight-cti";
+ compatible = "arm,primecell";
+ arm,primecell-periphid = <0x0003b966>;
reg = <0x601a000 0x1000>;
reg-names = "cti-base";
coresight-name = "coresight-cti10";
- clocks = <&clock_gcc RPMH_QDSS_CLK>,
- <&clock_gcc RPMH_QDSS_A_CLK>;
- clock-names = "core_clk", "core_a_clk";
+ clocks = <&clock_aop QDSS_CLK>;
+ clock-names = "apb_pclk";
+
};
cti11: cti@601b000 {
- compatible = "arm,coresight-cti";
+ compatible = "arm,primecell";
+ arm,primecell-periphid = <0x0003b966>;
reg = <0x601b000 0x1000>;
reg-names = "cti-base";
coresight-name = "coresight-cti11";
- clocks = <&clock_gcc RPMH_QDSS_CLK>,
- <&clock_gcc RPMH_QDSS_A_CLK>;
- clock-names = "core_clk", "core_a_clk";
+ clocks = <&clock_aop QDSS_CLK>;
+ clock-names = "apb_pclk";
+
};
cti12: cti@601c000 {
- compatible = "arm,coresight-cti";
+ compatible = "arm,primecell";
+ arm,primecell-periphid = <0x0003b966>;
reg = <0x601c000 0x1000>;
reg-names = "cti-base";
coresight-name = "coresight-cti12";
- clocks = <&clock_gcc RPMH_QDSS_CLK>,
- <&clock_gcc RPMH_QDSS_A_CLK>;
- clock-names = "core_clk", "core_a_clk";
+ clocks = <&clock_aop QDSS_CLK>;
+ clock-names = "apb_pclk";
+
};
cti13: cti@601d000 {
- compatible = "arm,coresight-cti";
+ compatible = "arm,primecell";
+ arm,primecell-periphid = <0x0003b966>;
reg = <0x601d000 0x1000>;
reg-names = "cti-base";
coresight-name = "coresight-cti13";
- clocks = <&clock_gcc RPMH_QDSS_CLK>,
- <&clock_gcc RPMH_QDSS_A_CLK>;
- clock-names = "core_clk", "core_a_clk";
+ clocks = <&clock_aop QDSS_CLK>;
+ clock-names = "apb_pclk";
+
};
cti14: cti@601e000 {
- compatible = "arm,coresight-cti";
+ compatible = "arm,primecell";
+ arm,primecell-periphid = <0x0003b966>;
reg = <0x601e000 0x1000>;
reg-names = "cti-base";
coresight-name = "coresight-cti14";
- clocks = <&clock_gcc RPMH_QDSS_CLK>,
- <&clock_gcc RPMH_QDSS_A_CLK>;
- clock-names = "core_clk", "core_a_clk";
+ clocks = <&clock_aop QDSS_CLK>;
+ clock-names = "apb_pclk";
+
};
cti15: cti@601f000 {
- compatible = "arm,coresight-cti";
+ compatible = "arm,primecell";
+ arm,primecell-periphid = <0x0003b966>;
reg = <0x601f000 0x1000>;
reg-names = "cti-base";
coresight-name = "coresight-cti15";
- clocks = <&clock_gcc RPMH_QDSS_CLK>,
- <&clock_gcc RPMH_QDSS_A_CLK>;
- clock-names = "core_clk", "core_a_clk";
+ clocks = <&clock_aop QDSS_CLK>;
+ clock-names = "apb_pclk";
+
};
cti_cpu0: cti@7020000 {
- compatible = "arm,coresight-cti";
+ compatible = "arm,primecell";
+ arm,primecell-periphid = <0x0003b966>;
reg = <0x7020000 0x1000>;
reg-names = "cti-base";
coresight-name = "coresight-cti-cpu0";
cpu = <&CPU0>;
- clocks = <&clock_gcc RPMH_QDSS_CLK>,
- <&clock_gcc RPMH_QDSS_A_CLK>;
- clock-names = "core_clk", "core_a_clk";
+ clocks = <&clock_aop QDSS_CLK>;
+ clock-names = "apb_pclk";
+
};
cti_cpu1: cti@7120000 {
- compatible = "arm,coresight-cti";
+ compatible = "arm,primecell";
+ arm,primecell-periphid = <0x0003b966>;
reg = <0x7120000 0x1000>;
reg-names = "cti-base";
coresight-name = "coresight-cti-cpu1";
cpu = <&CPU1>;
- clocks = <&clock_gcc RPMH_QDSS_CLK>,
- <&clock_gcc RPMH_QDSS_A_CLK>;
- clock-names = "core_clk", "core_a_clk";
+ clocks = <&clock_aop QDSS_CLK>;
+ clock-names = "apb_pclk";
};
cti_cpu2: cti@7220000 {
- compatible = "arm,coresight-cti";
+ compatible = "arm,primecell";
+ arm,primecell-periphid = <0x0003b966>;
reg = <0x7220000 0x1000>;
reg-names = "cti-base";
coresight-name = "coresight-cti-cpu2";
cpu = <&CPU2>;
- clocks = <&clock_gcc RPMH_QDSS_CLK>,
- <&clock_gcc RPMH_QDSS_A_CLK>;
- clock-names = "core_clk", "core_a_clk";
+ clocks = <&clock_aop QDSS_CLK>;
+ clock-names = "apb_pclk";
};
cti_cpu3: cti@7320000 {
- compatible = "arm,coresight-cti";
+ compatible = "arm,primecell";
+ arm,primecell-periphid = <0x0003b966>;
reg = <0x7320000 0x1000>;
reg-names = "cti-base";
coresight-name = "coresight-cti-cpu3";
cpu = <&CPU3>;
- clocks = <&clock_gcc RPMH_QDSS_CLK>,
- <&clock_gcc RPMH_QDSS_A_CLK>;
- clock-names = "core_clk", "core_a_clk";
+ clocks = <&clock_aop QDSS_CLK>;
+ clock-names = "apb_pclk";
};
cti_cpu4: cti@7420000 {
- compatible = "arm,coresight-cti";
+ compatible = "arm,primecell";
+ arm,primecell-periphid = <0x0003b966>;
reg = <0x7420000 0x1000>;
reg-names = "cti-base";
coresight-name = "coresight-cti-cpu4";
cpu = <&CPU4>;
- clocks = <&clock_gcc RPMH_QDSS_CLK>,
- <&clock_gcc RPMH_QDSS_A_CLK>;
- clock-names = "core_clk", "core_a_clk";
+ clocks = <&clock_aop QDSS_CLK>;
+ clock-names = "apb_pclk";
};
cti_cpu5: cti@7520000 {
- compatible = "arm,coresight-cti";
+ compatible = "arm,primecell";
+ arm,primecell-periphid = <0x0003b966>;
reg = <0x7520000 0x1000>;
reg-names = "cti-base";
coresight-name = "coresight-cti-cpu5";
cpu = <&CPU5>;
- clocks = <&clock_gcc RPMH_QDSS_CLK>,
- <&clock_gcc RPMH_QDSS_A_CLK>;
- clock-names = "core_clk", "core_a_clk";
+ clocks = <&clock_aop QDSS_CLK>;
+ clock-names = "apb_pclk";
};
cti_cpu6: cti@7620000 {
- compatible = "arm,coresight-cti";
+ compatible = "arm,primecell";
+ arm,primecell-periphid = <0x0003b966>;
reg = <0x7620000 0x1000>;
reg-names = "cti-base";
coresight-name = "coresight-cti-cpu6";
cpu = <&CPU6>;
- clocks = <&clock_gcc RPMH_QDSS_CLK>,
- <&clock_gcc RPMH_QDSS_A_CLK>;
- clock-names = "core_clk", "core_a_clk";
+ clocks = <&clock_aop QDSS_CLK>;
+ clock-names = "apb_pclk";
};
cti_cpu7: cti@7720000 {
- compatible = "arm,coresight-cti";
+ compatible = "arm,primecell";
+ arm,primecell-periphid = <0x0003b966>;
reg = <0x7720000 0x1000>;
reg-names = "cti-base";
coresight-name = "coresight-cti-cpu7";
cpu = <&CPU7>;
- clocks = <&clock_gcc RPMH_QDSS_CLK>,
- <&clock_gcc RPMH_QDSS_A_CLK>;
- clock-names = "core_clk", "core_a_clk";
+ clocks = <&clock_aop QDSS_CLK>;
+ clock-names = "apb_pclk";
};
dummy_eud: dummy_sink {
@@ -1552,9 +1615,8 @@
coresight-name = "coresight-funnel-apss-merg";
- clocks = <&clock_gcc RPMH_QDSS_CLK>,
- <&clock_gcc RPMH_QDSS_A_CLK>;
- clock-names = "apb_pclk", "core_a_clk";
+ clocks = <&clock_aop QDSS_CLK>;
+ clock-names = "apb_pclk";
ports {
#address-cells = <1>;
@@ -1624,9 +1686,8 @@
coresight-name = "coresight-etm0";
- clocks = <&clock_gcc RPMH_QDSS_CLK>,
- <&clock_gcc RPMH_QDSS_A_CLK>;
- clock-names = "apb_pclk", "core_a_clk";
+ clocks = <&clock_aop QDSS_CLK>;
+ clock-names = "apb_pclk";
port {
etm0_out_funnel_apss: endpoint {
@@ -1644,9 +1705,8 @@
coresight-name = "coresight-etm1";
- clocks = <&clock_gcc RPMH_QDSS_CLK>,
- <&clock_gcc RPMH_QDSS_A_CLK>;
- clock-names = "apb_pclk", "core_a_clk";
+ clocks = <&clock_aop QDSS_CLK>;
+ clock-names = "apb_pclk";
port {
etm1_out_funnel_apss: endpoint {
@@ -1664,9 +1724,8 @@
coresight-name = "coresight-etm2";
- clocks = <&clock_gcc RPMH_QDSS_CLK>,
- <&clock_gcc RPMH_QDSS_A_CLK>;
- clock-names = "apb_pclk", "core_a_clk";
+ clocks = <&clock_aop QDSS_CLK>;
+ clock-names = "apb_pclk";
port {
etm2_out_funnel_apss: endpoint {
@@ -1684,9 +1743,8 @@
coresight-name = "coresight-etm3";
- clocks = <&clock_gcc RPMH_QDSS_CLK>,
- <&clock_gcc RPMH_QDSS_A_CLK>;
- clock-names = "apb_pclk", "core_a_clk";
+ clocks = <&clock_aop QDSS_CLK>;
+ clock-names = "apb_pclk";
port {
etm3_out_funnel_apss: endpoint {
@@ -1704,9 +1762,8 @@
coresight-name = "coresight-etm4";
- clocks = <&clock_gcc RPMH_QDSS_CLK>,
- <&clock_gcc RPMH_QDSS_A_CLK>;
- clock-names = "apb_pclk", "core_a_clk";
+ clocks = <&clock_aop QDSS_CLK>;
+ clock-names = "apb_pclk";
port {
etm4_out_funnel_apss: endpoint {
@@ -1724,9 +1781,8 @@
coresight-name = "coresight-etm5";
- clocks = <&clock_gcc RPMH_QDSS_CLK>,
- <&clock_gcc RPMH_QDSS_A_CLK>;
- clock-names = "apb_pclk", "core_a_clk";
+ clocks = <&clock_aop QDSS_CLK>;
+ clock-names = "apb_pclk";
port {
etm5_out_funnel_apss: endpoint {
@@ -1744,9 +1800,8 @@
coresight-name = "coresight-etm6";
- clocks = <&clock_gcc RPMH_QDSS_CLK>,
- <&clock_gcc RPMH_QDSS_A_CLK>;
- clock-names = "apb_pclk", "core_a_clk";
+ clocks = <&clock_aop QDSS_CLK>;
+ clock-names = "apb_pclk";
port {
etm6_out_funnel_apss: endpoint {
@@ -1764,9 +1819,8 @@
coresight-name = "coresight-etm7";
- clocks = <&clock_gcc RPMH_QDSS_CLK>,
- <&clock_gcc RPMH_QDSS_A_CLK>;
- clock-names = "apb_pclk", "core_a_clk";
+ clocks = <&clock_aop QDSS_CLK>;
+ clock-names = "apb_pclk";
port {
etm7_out_funnel_apss: endpoint {
@@ -1784,9 +1838,8 @@
coresight-name = "coresight-funnel-apss";
- clocks = <&clock_gcc RPMH_QDSS_CLK>,
- <&clock_gcc RPMH_QDSS_A_CLK>;
- clock-names = "apb_pclk", "core_a_clk";
+ clocks = <&clock_aop QDSS_CLK>;
+ clock-names = "apb_pclk";
ports {
#address-cells = <1>;
diff --git a/arch/arm64/boot/dts/qcom/sdm845-gpu.dtsi b/arch/arm64/boot/dts/qcom/sdm845-gpu.dtsi
index 3f2317a..bfbaabb 100644
--- a/arch/arm64/boot/dts/qcom/sdm845-gpu.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm845-gpu.dtsi
@@ -74,6 +74,7 @@
qcom,gpu-qdss-stm = <0x161c0000 0x40000>; // base addr, size
qcom,tsens-name = "tsens_tz_sensor12";
+ #cooling-cells = <2>;
clocks = <&clock_gfx GPU_CC_GX_GFX3D_CLK>,
<&clock_gcc GCC_GPU_CFG_AHB_CLK>,
diff --git a/arch/arm64/boot/dts/qcom/sdm845-mtp.dtsi b/arch/arm64/boot/dts/qcom/sdm845-mtp.dtsi
index e36ccf2..4391189 100644
--- a/arch/arm64/boot/dts/qcom/sdm845-mtp.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm845-mtp.dtsi
@@ -12,6 +12,30 @@
#include <dt-bindings/gpio/gpio.h>
#include "sdm845-camera-sensor-mtp.dtsi"
+
+/ {
+ bluetooth: bt_wcn3990 {
+ compatible = "qca,wcn3990";
+ qca,bt-vdd-io-supply = <&pm8998_s3>;
+ qca,bt-vdd-xtal-supply = <&pm8998_s5>;
+ qca,bt-vdd-core-supply = <&pm8998_l7>;
+ qca,bt-vdd-pa-supply = <&pm8998_l17>;
+ qca,bt-vdd-ldo-supply = <&pm8998_l25>;
+
+ qca,bt-vdd-io-voltage-level = <1352000 1352000>;
+ qca,bt-vdd-xtal-voltage-level = <2040000 2040000>;
+ qca,bt-vdd-core-voltage-level = <1800000 1800000>;
+ qca,bt-vdd-pa-voltage-level = <1304000 1304000>;
+ qca,bt-vdd-ldo-voltage-level = <3312000 3312000>;
+
+ qca,bt-vdd-io-current-level = <1>; /* LPM/PFM */
+ qca,bt-vdd-xtal-current-level = <1>; /* LPM/PFM */
+ qca,bt-vdd-core-current-level = <1>; /* LPM/PFM */
+ qca,bt-vdd-pa-current-level = <1>; /* LPM/PFM */
+ qca,bt-vdd-ldo-current-level = <1>; /* LPM/PFM */
+ };
+};
+
&soc {
gpio_keys {
compatible = "gpio-keys";
@@ -54,6 +78,30 @@
};
};
+&labibb {
+ status = "ok";
+ qcom,qpnp-labibb-mode = "lcd";
+};
+
+&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-panel-mode-gpio-state = "dual_port";
+ qcom,panel-mode-gpio = <&tlmm 52 0>;
+ qcom,platform-reset-gpio = <&tlmm 6 0>;
+};
+
+&dsi_dual_nt35597_truly_video_display {
+ qcom,dsi-display-active;
+};
+
+&pmi8998_wled {
+ status = "okay";
+ qcom,led-strings-list = [01 02];
+};
+
&ufsphy_mem {
compatible = "qcom,ufs-phy-qmp-v3";
@@ -104,6 +152,26 @@
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 &sdc2_data_on>;
+ pinctrl-1 = <&sdc2_clk_off &sdc2_cmd_off &sdc2_data_off>;
+
+ qcom,clk-rates = <400000 20000000 25000000
+ 50000000 100000000 200000000>;
+ qcom,bus-speed-mode = "SDR12", "SDR25", "SDR50", "DDR50", "SDR104";
+
+ status = "ok";
+};
+
&pmi8998_switch1 {
pinctrl-names = "led_enable", "led_disable";
pinctrl-0 = <&flash_led3_front_en>;
@@ -168,3 +236,113 @@
&usb_qmp_phy {
status = "okay";
};
+
+&pm8998_vadc {
+ chan@83 {
+ label = "vph_pwr";
+ reg = <0x83>;
+ qcom,decimation = <2>;
+ qcom,pre-div-channel-scaling = <1>;
+ qcom,calibration-type = "absolute";
+ qcom,scale-function = <0>;
+ qcom,hw-settle-time = <0>;
+ qcom,fast-avg-setup = <0>;
+ };
+
+ chan@85 {
+ label = "vcoin";
+ reg = <0x85>;
+ qcom,decimation = <2>;
+ qcom,pre-div-channel-scaling = <1>;
+ qcom,calibration-type = "absolute";
+ qcom,scale-function = <0>;
+ qcom,hw-settle-time = <0>;
+ qcom,fast-avg-setup = <0>;
+ };
+
+ chan@4c {
+ label = "xo_therm";
+ reg = <0x4c>;
+ qcom,decimation = <2>;
+ qcom,pre-div-channel-scaling = <0>;
+ qcom,calibration-type = "ratiometric";
+ qcom,scale-function = <4>;
+ qcom,hw-settle-time = <2>;
+ qcom,fast-avg-setup = <0>;
+ qcom,vadc-thermal-node;
+ };
+
+ chan@4d {
+ label = "msm_therm";
+ reg = <0x4d>;
+ qcom,decimation = <2>;
+ qcom,pre-div-channel-scaling = <0>;
+ qcom,calibration-type = "ratiometric";
+ qcom,scale-function = <2>;
+ qcom,hw-settle-time = <2>;
+ qcom,fast-avg-setup = <0>;
+ qcom,vadc-thermal-node;
+ };
+
+ chan@4f {
+ label = "pa_therm1";
+ reg = <0x4f>;
+ qcom,decimation = <2>;
+ qcom,pre-div-channel-scaling = <0>;
+ qcom,calibration-type = "ratiometric";
+ qcom,scale-function = <2>;
+ qcom,hw-settle-time = <2>;
+ qcom,fast-avg-setup = <0>;
+ qcom,vadc-thermal-node;
+ };
+
+ chan@51 {
+ label = "quiet_therm";
+ reg = <0x51>;
+ qcom,decimation = <2>;
+ qcom,pre-div-channel-scaling = <0>;
+ qcom,calibration-type = "ratiometric";
+ qcom,scale-function = <2>;
+ qcom,hw-settle-time = <2>;
+ qcom,fast-avg-setup = <0>;
+ qcom,vadc-thermal-node;
+ };
+};
+
+&pm8998_adc_tm {
+ chan@83 {
+ label = "vph_pwr";
+ reg = <0x83>;
+ qcom,pre-div-channel-scaling = <1>;
+ qcom,calibration-type = "absolute";
+ qcom,scale-function = <0>;
+ qcom,hw-settle-time = <0>;
+ qcom,btm-channel-number = <0x60>;
+ };
+};
+
+&thermal_zones {
+ xo-therm-adc {
+ polling-delay-passive = <0>;
+ polling-delay = <0>;
+ thermal-sensors = <&pm8998_vadc 0x4c>;
+ };
+
+ msm-therm-adc {
+ polling-delay-passive = <0>;
+ polling-delay = <0>;
+ thermal-sensors = <&pm8998_vadc 0x4d>;
+ };
+
+ pa-therm1-adc {
+ polling-delay-passive = <0>;
+ polling-delay = <0>;
+ thermal-sensors = <&pm8998_vadc 0x4f>;
+ };
+
+ quiet-therm-adc {
+ polling-delay-passive = <0>;
+ polling-delay = <0>;
+ thermal-sensors = <&pm8998_vadc 0x51>;
+ };
+};
diff --git a/arch/arm64/boot/dts/qcom/sdm845-pinctrl.dtsi b/arch/arm64/boot/dts/qcom/sdm845-pinctrl.dtsi
index bd09c7c..d6af58b 100644
--- a/arch/arm64/boot/dts/qcom/sdm845-pinctrl.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm845-pinctrl.dtsi
@@ -112,6 +112,54 @@
};
};
+ sdc2_clk_on: sdc2_clk_on {
+ config {
+ pins = "sdc2_clk";
+ bias-disable; /* NO pull */
+ drive-strength = <16>; /* 16 MA */
+ };
+ };
+
+ sdc2_clk_off: sdc2_clk_off {
+ config {
+ pins = "sdc2_clk";
+ bias-disable; /* NO pull */
+ drive-strength = <2>; /* 2 MA */
+ };
+ };
+
+ sdc2_cmd_on: sdc2_cmd_on {
+ config {
+ pins = "sdc2_cmd";
+ bias-pull-up; /* pull up */
+ drive-strength = <10>; /* 10 MA */
+ };
+ };
+
+ sdc2_cmd_off: sdc2_cmd_off {
+ config {
+ pins = "sdc2_cmd";
+ bias-pull-up; /* pull up */
+ drive-strength = <2>; /* 2 MA */
+ };
+ };
+
+ sdc2_data_on: sdc2_data_on {
+ config {
+ pins = "sdc2_data";
+ bias-pull-up; /* pull up */
+ drive-strength = <10>; /* 10 MA */
+ };
+ };
+
+ sdc2_data_off: sdc2_data_off {
+ config {
+ pins = "sdc2_data";
+ bias-pull-up; /* pull up */
+ drive-strength = <2>; /* 2 MA */
+ };
+ };
+
cdc_reset_ctrl {
cdc_reset_sleep: cdc_reset_sleep {
mux {
diff --git a/arch/arm64/boot/dts/qcom/sdm845-pm.dtsi b/arch/arm64/boot/dts/qcom/sdm845-pm.dtsi
index 21b5659..70e749b 100644
--- a/arch/arm64/boot/dts/qcom/sdm845-pm.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm845-pm.dtsi
@@ -139,4 +139,10 @@
};
};
};
+
+ qcom,rpm-stats@c300000 {
+ compatible = "qcom,rpm-stats";
+ reg = <0xC300000 0x1000>, <0xC3F0004 0x4>;
+ reg-names = "phys_addr_base", "offset_addr";
+ };
};
diff --git a/arch/arm64/boot/dts/qcom/sdm845-qupv3.dtsi b/arch/arm64/boot/dts/qcom/sdm845-qupv3.dtsi
index 1c31a7a..dd0d08e 100644
--- a/arch/arm64/boot/dts/qcom/sdm845-qupv3.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm845-qupv3.dtsi
@@ -10,6 +10,8 @@
* GNU General Public License for more details.
*/
+#include <dt-bindings/msm/msm-bus-ids.h>
+
&soc {
/* QUPv3 South instances */
@@ -30,6 +32,7 @@
pinctrl-1 = <&qupv3_se6_4uart_sleep>;
interrupts = <GIC_SPI 607 0>;
status = "disabled";
+ qcom,bus-mas = <MSM_BUS_MASTER_BLSP_1>;
};
qupv3_se7_4uart: qcom,qup_uart@0x89c000 {
@@ -45,6 +48,7 @@
pinctrl-1 = <&qupv3_se7_4uart_sleep>;
interrupts = <GIC_SPI 608 0>;
status = "disabled";
+ qcom,bus-mas = <MSM_BUS_MASTER_BLSP_1>;
};
/* I2C */
@@ -336,6 +340,7 @@
pinctrl-names = "default", "sleep";
pinctrl-0 = <&qupv3_se9_2uart_active>;
pinctrl-1 = <&qupv3_se9_2uart_sleep>;
+ qcom,bus-mas = <MSM_BUS_MASTER_BLSP_2>;
interrupts = <GIC_SPI 354 0>;
status = "disabled";
};
@@ -353,6 +358,7 @@
pinctrl-0 = <&qupv3_se10_2uart_active>;
pinctrl-1 = <&qupv3_se10_2uart_sleep>;
interrupts = <GIC_SPI 355 0>;
+ qcom,bus-mas = <MSM_BUS_MASTER_BLSP_2>;
status = "disabled";
};
diff --git a/arch/arm64/boot/dts/qcom/sdm845-regulator.dtsi b/arch/arm64/boot/dts/qcom/sdm845-regulator.dtsi
index 9a5cb3b..6989f326 100644
--- a/arch/arm64/boot/dts/qcom/sdm845-regulator.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm845-regulator.dtsi
@@ -28,6 +28,32 @@
};
};
+&spmi_bus {
+ qcom,pm8998@1 {
+ /* PM8998 S12 + S11 + S10 = VDD_APC1 supply */
+ pm8998_s12: regulator@3500 {
+ compatible = "qcom,qpnp-regulator";
+ reg = <0x3500 0x100>;
+ regulator-name = "pm8998_s12";
+ regulator-min-microvolt = <568000>;
+ regulator-max-microvolt = <1056000>;
+ qcom,enable-time = <500>;
+ regulator-always-on;
+ };
+
+ /* PM8998 S13 = VDD_APC0 supply */
+ pm8998_s13: regulator@3800 {
+ compatible = "qcom,qpnp-regulator";
+ reg = <0x3800 0x100>;
+ regulator-name = "pm8998_s13";
+ regulator-min-microvolt = <568000>;
+ regulator-max-microvolt = <928000>;
+ qcom,enable-time = <500>;
+ regulator-always-on;
+ };
+ };
+};
+
&soc {
/* CPR controller regulators */
apc0_cpr: cprh-ctrl@17dc0000 {
@@ -59,7 +85,10 @@
qcom,cpr-saw-use-unit-mV;
qcom,saw-avs-ctrl = <0x101C031>;
- qcom,saw-avs-limit = <0x3A00000>;
+ qcom,saw-avs-limit = <0x3A003A0>;
+
+ qcom,cpr-enable;
+ qcom,cpr-hw-closed-loop;
qcom,cpr-panic-reg-addr-list =
<0x17dc3a84 0x17dc3a88 0x17840c18>;
@@ -68,6 +97,9 @@
"APSS_SILVER_CPRH_STATUS_1",
"SILVER_SAW4_PMIC_STS";
+ qcom,cpr-aging-ref-voltage = <928000>;
+ vdd-supply = <&pm8998_s13>;
+
thread@1 {
qcom,cpr-thread-id = <1>;
qcom,cpr-consecutive-up = <0>;
@@ -134,6 +166,14 @@
qcom,allow-voltage-interpolation;
qcom,allow-quotient-interpolation;
qcom,cpr-scaled-open-loop-voltage-as-ceiling;
+
+ qcom,cpr-aging-max-voltage-adjustment = <15000>;
+ qcom,cpr-aging-ref-corner = <17>;
+ qcom,cpr-aging-ro-scaling-factor = <1620>;
+ qcom,allow-aging-voltage-adjustment =
+ <0 1 1 1 1 1 1 1>;
+ qcom,allow-aging-open-loop-voltage-adjustment =
+ <1>;
};
};
@@ -194,6 +234,14 @@
qcom,allow-voltage-interpolation;
qcom,allow-quotient-interpolation;
qcom,cpr-scaled-open-loop-voltage-as-ceiling;
+
+ qcom,cpr-aging-max-voltage-adjustment = <15000>;
+ qcom,cpr-aging-ref-corner = <9>;
+ qcom,cpr-aging-ro-scaling-factor = <1620>;
+ qcom,allow-aging-voltage-adjustment =
+ <0 1 1 1 1 1 1 1>;
+ qcom,allow-aging-open-loop-voltage-adjustment =
+ <1>;
};
};
};
@@ -232,13 +280,19 @@
qcom,cpr-saw-use-unit-mV;
qcom,saw-avs-ctrl = <0x101C031>;
- qcom,saw-avs-limit = <0x4200000>;
+ qcom,saw-avs-limit = <0x4200420>;
+
+ qcom,cpr-enable;
+ qcom,cpr-hw-closed-loop;
qcom,cpr-panic-reg-addr-list =
<0x17db3a84 0x17830c18>;
qcom,cpr-panic-reg-name-list =
"APSS_GOLD_CPRH_STATUS_0", "GOLD_SAW4_PMIC_STS";
+ qcom,cpr-aging-ref-voltage = <1056000>;
+ vdd-supply = <&pm8998_s12>;
+
thread@0 {
qcom,cpr-thread-id = <0>;
qcom,cpr-consecutive-up = <0>;
@@ -311,6 +365,14 @@
qcom,allow-voltage-interpolation;
qcom,allow-quotient-interpolation;
qcom,cpr-scaled-open-loop-voltage-as-ceiling;
+
+ qcom,cpr-aging-max-voltage-adjustment = <15000>;
+ qcom,cpr-aging-ref-corner = <22>;
+ qcom,cpr-aging-ro-scaling-factor = <1700>;
+ qcom,allow-aging-voltage-adjustment =
+ <0 1 1 1 1 1 1 1>;
+ qcom,allow-aging-open-loop-voltage-adjustment =
+ <1>;
};
};
};
diff --git a/arch/arm64/boot/dts/qcom/sdm845-rumi.dtsi b/arch/arm64/boot/dts/qcom/sdm845-rumi.dtsi
index 3ec83f5..6991b17 100644
--- a/arch/arm64/boot/dts/qcom/sdm845-rumi.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm845-rumi.dtsi
@@ -44,6 +44,26 @@
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 &sdc2_data_on>;
+ pinctrl-1 = <&sdc2_clk_off &sdc2_cmd_off &sdc2_data_off>;
+
+ qcom,clk-rates = <400000 20000000 25000000
+ 50000000 100000000 200000000>;
+ qcom,bus-speed-mode = "SDR12", "SDR25", "SDR50", "DDR50", "SDR104";
+
+ status = "ok";
+};
+
&soc {
qcom,icnss@18800000 {
compatible = "qcom,icnss";
diff --git a/arch/arm64/boot/dts/qcom/sdm845-sde-display.dtsi b/arch/arm64/boot/dts/qcom/sdm845-sde-display.dtsi
index 2ff9b2f..e56073c 100644
--- a/arch/arm64/boot/dts/qcom/sdm845-sde-display.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm845-sde-display.dtsi
@@ -23,6 +23,7 @@
#include "dsi-panel-sharp-1080p-cmd.dtsi"
#include "dsi-panel-sharp-dualmipi-1080p-120hz.dtsi"
#include "dsi-panel-s6e3ha3-amoled-dualmipi-wqhd-cmd.dtsi"
+#include <dt-bindings/clock/mdss-10nm-pll-clk.h>
&soc {
dsi_panel_pwr_supply: dsi_panel_pwr_supply {
@@ -198,15 +199,15 @@
qcom,dsi-ctrl = <&mdss_dsi0 &mdss_dsi1>;
qcom,dsi-phy = <&mdss_dsi_phy0 &mdss_dsi_phy1>;
- clocks = <&clock_dispcc DISP_CC_MDSS_BYTE0_CLK_SRC>,
- <&clock_dispcc DISP_CC_MDSS_PCLK0_CLK_SRC>;
+ 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 6 0>;
+ qcom,panel-mode-gpio = <&tlmm 52 0>;
qcom,dsi-panel = <&dsi_dual_nt35597_truly_video>;
vddio-supply = <&pm8998_l14>;
@@ -291,7 +292,7 @@
};
&mdss_mdp {
- connectors = <&sde_wb>;
+ connectors = <&sde_wb &dsi_dual_nt35597_truly_video_display>;
};
&dsi_dual_nt35597_truly_video {
diff --git a/arch/arm64/boot/dts/qcom/sdm845-sde-pll.dtsi b/arch/arm64/boot/dts/qcom/sdm845-sde-pll.dtsi
new file mode 100644
index 0000000..168f2a9
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/sdm845-sde-pll.dtsi
@@ -0,0 +1,67 @@
+/* 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.
+ */
+
+&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>;
+ };
+ };
+ };
+};
diff --git a/arch/arm64/boot/dts/qcom/sdm845-sde.dtsi b/arch/arm64/boot/dts/qcom/sdm845-sde.dtsi
index 3e00577..cb5d924 100644
--- a/arch/arm64/boot/dts/qcom/sdm845-sde.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm845-sde.dtsi
@@ -23,15 +23,12 @@
<&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_SRC>,
- <&clock_dispcc DISP_CC_MDSS_VSYNC_CLK_SRC>,
<&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_src",
- "vsync_clk_src", "core_clk", "vsync_clk";
- clock-rate = <0 0 0 0 300000000 0 300000000 0 0>;
- clock-max-rate = <0 0 0 0 430000000 0 430000000 0 0>;
+ 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 430000000 19200000 0>;
sde-vdd-supply = <&mdss_core_gdsc>;
@@ -276,98 +273,81 @@
};
mdss_dsi0: qcom,mdss_dsi_ctrl0@ae94000 {
- compatible = "qcom,dsi-ctrl-hw-v2.0";
+ compatible = "qcom,dsi-ctrl-hw-v2.2";
label = "dsi-ctrl-0";
- status = "disabled";
cell-index = <0>;
- reg = <0xae94000 0x400>;
- reg-names = "dsi_ctrl";
+ reg = <0xae94000 0x400>,
+ <0xaf08000 0x4>;
+ reg-names = "dsi_ctrl", "disp_cc_base";
interrupt-parent = <&mdss_mdp>;
interrupts = <4 0>;
vdda-1p2-supply = <&pm8998_l26>;
- vdda-0p9-supply = <&pm8998_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_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";
+ "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-0p9";
- qcom,supply-min-voltage = <925000>;
- qcom,supply-max-voltage = <925000>;
- qcom,supply-enable-load = <17000>;
- qcom,supply-disable-load = <32>;
- };
-
- qcom,ctrl-supply-entry@1 {
- reg = <0>;
qcom,supply-name = "vdda-1p2";
- qcom,supply-min-voltage = <1250000>;
- qcom,supply-max-voltage = <1250000>;
- qcom,supply-enable-load = <18160>;
- qcom,supply-disable-load = <1>;
+ 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.0";
+ compatible = "qcom,dsi-ctrl-hw-v2.2";
label = "dsi-ctrl-1";
- status = "disabled";
cell-index = <1>;
- reg = <0xae96000 0x400>;
- reg-names = "dsi_ctrl";
+ reg = <0xae96000 0x400>,
+ <0xaf08000 0x4>;
+ reg-names = "dsi_ctrl", "disp_cc_base";
interrupt-parent = <&mdss_mdp>;
interrupts = <5 0>;
vdda-1p2-supply = <&pm8998_l26>;
- vdda-0p9-supply = <&pm8998_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>;
+ 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";
+ "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-0p9";
- qcom,supply-min-voltage = <925000>;
- qcom,supply-max-voltage = <925000>;
- qcom,supply-enable-load = <17000>;
- qcom,supply-disable-load = <32>;
- };
-
- qcom,ctrl-supply-entry@1 {
- reg = <0>;
qcom,supply-name = "vdda-1p2";
- qcom,supply-min-voltage = <1250000>;
- qcom,supply-max-voltage = <1250000>;
- qcom,supply-enable-load = <18160>;
- qcom,supply-disable-load = <1>;
+ 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";
- status = "disabled";
label = "dsi-phy-0";
cell-index = <0>;
reg = <0xae94400 0x7c0>;
reg-names = "dsi_phy";
gdsc-supply = <&mdss_core_gdsc>;
- vdda-1p2-supply = <&pm8998_l26>;
+ vdda-0p9-supply = <&pm8998_l1>;
qcom,platform-strength-ctrl = [55 03
55 03
55 03
@@ -384,24 +364,23 @@
#size-cells = <0>;
qcom,phy-supply-entry@0 {
reg = <0>;
- qcom,supply-name = "vdda-1p2";
- qcom,supply-min-voltage = <1250000>;
- qcom,supply-max-voltage = <1250000>;
- qcom,supply-enable-load = <2500>;
- qcom,supply-disable-load = <1>;
+ 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";
- status = "disabled";
label = "dsi-phy-1";
cell-index = <1>;
reg = <0xae96400 0x7c0>;
reg-names = "dsi_phy";
gdsc-supply = <&mdss_core_gdsc>;
- vdda-1p2-supply = <&pm8998_l26>;
+ vdda-0p9-supply = <&pm8998_l1>;
qcom,platform-strength-ctrl = [55 03
55 03
55 03
@@ -418,11 +397,11 @@
#size-cells = <0>;
qcom,phy-supply-entry@0 {
reg = <0>;
- qcom,supply-name = "vdda-1p2";
- qcom,supply-min-voltage = <1250000>;
- qcom,supply-max-voltage = <1250000>;
- qcom,supply-enable-load = <2500>;
- qcom,supply-disable-load = <1>;
+ 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-usb.dtsi b/arch/arm64/boot/dts/qcom/sdm845-usb.dtsi
index e194912..c80343a 100644
--- a/arch/arm64/boot/dts/qcom/sdm845-usb.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm845-usb.dtsi
@@ -137,7 +137,7 @@
0x29 0x244 /* TUNE2 */
0xca 0x248 /* TUNE3 */
0x04 0x24c /* TUNE4 */
- 0x00 0x250 /* TUNE5 */
+ 0x03 0x250 /* TUNE5 */
0x00 0x23c /* CHG_CTRL2 */
0x22 0x210>; /* PWR_CTRL1 */
@@ -286,10 +286,11 @@
<&clock_gcc GCC_USB3_PRIM_PHY_PIPE_CLK>,
<&clock_rpmh RPMH_CXO_CLK>,
<&clock_gcc GCC_USB3_PRIM_CLKREF_CLK>,
- <&clock_gcc GCC_USB3_PRIM_PHY_COM_AUX_CLK>;
+ <&clock_gcc GCC_USB3_PRIM_PHY_COM_AUX_CLK>,
+ <&clock_gcc GCC_USB_PHY_CFG_AHB2PHY_CLK>;
clock-names = "aux_clk", "pipe_clk", "ref_clk_src",
- "ref_clk", "com_aux_clk";
+ "ref_clk", "com_aux_clk", "cfg_ahb_clk";
resets = <&clock_gcc GCC_USB3_DP_PHY_PRIM_BCR>,
<&clock_gcc GCC_USB3_PHY_PRIM_BCR>;
@@ -391,7 +392,7 @@
0x29 0x244 /* TUNE2 */
0xca 0x248 /* TUNE3 */
0x04 0x24c /* TUNE4 */
- 0x00 0x250 /* TUNE5 */
+ 0x03 0x250 /* TUNE5 */
0x00 0x23c /* CHG_CTRL2 */
0x22 0x210>; /* PWR_CTRL1 */
@@ -529,10 +530,11 @@
clocks = <&clock_gcc GCC_USB3_SEC_PHY_AUX_CLK>,
<&clock_gcc GCC_USB3_SEC_PHY_PIPE_CLK>,
<&clock_rpmh RPMH_CXO_CLK>,
- <&clock_gcc GCC_USB3_SEC_CLKREF_CLK>;
+ <&clock_gcc GCC_USB3_SEC_CLKREF_CLK>,
+ <&clock_gcc GCC_USB_PHY_CFG_AHB2PHY_CLK>;
clock-names = "aux_clk", "pipe_clk", "ref_clk_src",
- "ref_clk";
+ "ref_clk", "cfg_ahb_clk";
resets = <&clock_gcc GCC_USB3_PHY_SEC_BCR>,
<&clock_gcc GCC_USB3PHY_PHY_SEC_BCR>;
diff --git a/arch/arm64/boot/dts/qcom/sdm845-vidc.dtsi b/arch/arm64/boot/dts/qcom/sdm845-vidc.dtsi
index da1414d..b9dc816 100644
--- a/arch/arm64/boot/dts/qcom/sdm845-vidc.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm845-vidc.dtsi
@@ -46,9 +46,11 @@
qcom,proxy-clock-names = "core_clk", "iface_clk",
"bus_clk", "core0_clk", "core0_bus_clk",
"core1_clk", "core1_bus_clk";
- qcom,clock-configs = <0x0 0x0 0x0 0x0 0x0 0x0 0x0>;
+ qcom,clock-configs = <0x1 0x0 0x0 0x1 0x0 0x1 0x0>;
qcom,allowed-clock-rates = <200000000 320000000 380000000
444000000 533000000>;
+ qcom,max-hq-mbs-per-frame = <8160>;
+ qcom,max-hq-frames-per-sec = <60>;
qcom,clock-freq-tbl {
qcom,profile-enc {
qcom,codec-mask = <0x55555555>;
diff --git a/arch/arm64/boot/dts/qcom/sdm845.dtsi b/arch/arm64/boot/dts/qcom/sdm845.dtsi
index a852277..54e0162 100644
--- a/arch/arm64/boot/dts/qcom/sdm845.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm845.dtsi
@@ -18,10 +18,12 @@
#include <dt-bindings/clock/qcom,videocc-sdm845.h>
#include <dt-bindings/clock/qcom,cpucc-sdm845.h>
#include <dt-bindings/clock/qcom,rpmh.h>
+#include <dt-bindings/clock/qcom,aop-qmp.h>
#include <dt-bindings/regulator/qcom,rpmh-regulator.h>
#include <dt-bindings/interrupt-controller/arm-gic.h>
#include <dt-bindings/soc/qcom,tcs-mbox.h>
#include <dt-bindings/spmi/spmi.h>
+#include <dt-bindings/thermal/thermal.h>
/ {
model = "Qualcomm Technologies, Inc. SDM845";
@@ -32,6 +34,7 @@
aliases {
ufshc1 = &ufshc_mem; /* Embedded UFS slot */
ufshc2 = &ufshc_card; /* Removable UFS slot */
+ sdhc2 = &sdhc_2; /* SDC2 SD card slot */
};
cpus {
@@ -46,6 +49,8 @@
efficiency = <1024>;
cache-size = <0x8000>;
cpu-release-addr = <0x0 0x90000000>;
+ qcom,lmh-dcvs = <&lmh_dcvs0>;
+ #cooling-cells = <2>;
next-level-cache = <&L2_0>;
L2_0: l2-cache {
compatible = "arm,arch-cache";
@@ -77,6 +82,8 @@
efficiency = <1024>;
cache-size = <0x8000>;
cpu-release-addr = <0x0 0x90000000>;
+ qcom,lmh-dcvs = <&lmh_dcvs0>;
+ #cooling-cells = <2>;
next-level-cache = <&L2_100>;
L2_100: l2-cache {
compatible = "arm,arch-cache";
@@ -102,6 +109,8 @@
efficiency = <1024>;
cache-size = <0x8000>;
cpu-release-addr = <0x0 0x90000000>;
+ qcom,lmh-dcvs = <&lmh_dcvs0>;
+ #cooling-cells = <2>;
next-level-cache = <&L2_200>;
L2_200: l2-cache {
compatible = "arm,arch-cache";
@@ -127,6 +136,8 @@
efficiency = <1024>;
cache-size = <0x8000>;
cpu-release-addr = <0x0 0x90000000>;
+ qcom,lmh-dcvs = <&lmh_dcvs0>;
+ #cooling-cells = <2>;
next-level-cache = <&L2_300>;
L2_300: l2-cache {
compatible = "arm,arch-cache";
@@ -152,6 +163,8 @@
efficiency = <1740>;
cache-size = <0x20000>;
cpu-release-addr = <0x0 0x90000000>;
+ qcom,lmh-dcvs = <&lmh_dcvs1>;
+ #cooling-cells = <2>;
next-level-cache = <&L2_400>;
L2_400: l2-cache {
compatible = "arm,arch-cache";
@@ -177,6 +190,8 @@
efficiency = <1740>;
cache-size = <0x20000>;
cpu-release-addr = <0x0 0x90000000>;
+ qcom,lmh-dcvs = <&lmh_dcvs1>;
+ #cooling-cells = <2>;
next-level-cache = <&L2_500>;
L2_500: l2-cache {
compatible = "arm,arch-cache";
@@ -202,6 +217,8 @@
efficiency = <1740>;
cache-size = <0x20000>;
cpu-release-addr = <0x0 0x90000000>;
+ qcom,lmh-dcvs = <&lmh_dcvs1>;
+ #cooling-cells = <2>;
next-level-cache = <&L2_600>;
L2_600: l2-cache {
compatible = "arm,arch-cache";
@@ -227,6 +244,8 @@
efficiency = <1740>;
cache-size = <0x20000>;
cpu-release-addr = <0x0 0x90000000>;
+ qcom,lmh-dcvs = <&lmh_dcvs1>;
+ #cooling-cells = <2>;
next-level-cache = <&L2_700>;
L2_700: l2-cache {
compatible = "arm,arch-cache";
@@ -411,6 +430,7 @@
};
#include "msm-gdsc-sdm845.dtsi"
+#include "sdm845-sde-pll.dtsi"
#include "sdm845-sde.dtsi"
#include "sdm845-sde-display.dtsi"
#include "sdm845-qupv3.dtsi"
@@ -993,6 +1013,13 @@
#clock-cells = <1>;
};
+ clock_aop: qcom,aopclk {
+ compatible = "qcom,aop-qmp-clk";
+ #clock-cells = <1>;
+ mboxes = <&qmp_aop 0>;
+ mbox-names = "qdss_clk";
+ };
+
ufsphy_mem: ufsphy_mem@1d87000 {
reg = <0x1d87000 0xda8>; /* PHY regs */
reg-names = "phy_mem";
@@ -1204,6 +1231,57 @@
status = "disabled";
};
+ sdhc_2: sdhci@8804000 {
+ compatible = "qcom,sdhci-msm-v5";
+ reg = <0x8804000 0x1000>;
+ reg-names = "hc_mem";
+
+ interrupts = <0 204 0>, <0 222 0>;
+ interrupt-names = "hc_irq", "pwr_irq";
+
+ qcom,bus-width = <4>;
+ qcom,large-address-bus;
+
+ qcom,msm-bus,name = "sdhc2";
+ qcom,msm-bus,num-cases = <8>;
+ qcom,msm-bus,num-paths = <2>;
+ qcom,msm-bus,vectors-KBps =
+ /* No vote */
+ <81 512 0 0>, <1 608 0 0>,
+ /* 400 KB/s*/
+ <81 512 1046 1600>,
+ <1 608 1600 1600>,
+ /* 20 MB/s */
+ <81 512 52286 80000>,
+ <1 608 80000 80000>,
+ /* 25 MB/s */
+ <81 512 65360 100000>,
+ <1 608 100000 100000>,
+ /* 50 MB/s */
+ <81 512 130718 200000>,
+ <1 608 133320 133320>,
+ /* 100 MB/s */
+ <81 512 261438 200000>,
+ <1 608 150000 150000>,
+ /* 200 MB/s */
+ <81 512 261438 400000>,
+ <1 608 300000 300000>,
+ /* Max. bandwidth */
+ <81 512 1338562 4096000>,
+ <1 608 1338562 4096000>;
+ qcom,bus-bw-vectors-bps = <0 400000 20000000 25000000 50000000
+ 100000000 200000000 4294967295>;
+
+ qcom,sdr104-wa;
+
+ qcom,devfreq,freq-table = <50000000 200000000>;
+ clocks = <&clock_gcc GCC_SDCC2_AHB_CLK>,
+ <&clock_gcc GCC_SDCC2_APPS_CLK>;
+ clock-names = "iface_clk", "core_clk";
+
+ status = "disabled";
+ };
+
pil_modem: qcom,mss@4080000 {
compatible = "qcom,pil-q6v55-mss";
reg = <0x4080000 0x100>,
@@ -1221,13 +1299,12 @@
<&clock_gcc GCC_BOOT_ROM_AHB_CLK>,
<&clock_gcc GCC_MSS_GPLL0_DIV_CLK_SRC>,
<&clock_gcc GCC_MSS_SNOC_AXI_CLK>,
- <&clock_gcc GCC_MSS_AXIS2_CLK>,
<&clock_gcc GCC_MSS_MFAB_AXIS_CLK>,
<&clock_gcc GCC_PRNG_AHB_CLK>;
clock-names = "xo", "iface_clk", "bus_clk",
"mem_clk", "gpll0_mss_clk", "snoc_axi_clk",
- "axis2_clk","mnoc_axi_clk", "prng_clk";
- qcom,proxy-clock-names = "xo", "axis2_clk", "prng_clk";
+ "mnoc_axi_clk", "prng_clk";
+ qcom,proxy-clock-names = "xo", "prng_clk";
qcom,active-clock-names = "iface_clk", "bus_clk", "mem_clk",
"gpll0_mss_clk", "snoc_axi_clk",
"mnoc_axi_clk";
@@ -1256,6 +1333,10 @@
/* GPIO output to mss */
qcom,gpio-force-stop = <&smp2pgpio_ssr_smp2p_1_out 0 0>;
+ qcom,mba-mem@0 {
+ compatible = "qcom,pil-mba-mem";
+ memory-region = <&pil_mba_mem>;
+ };
};
qcom,lpass@17300000 {
@@ -1336,6 +1417,16 @@
qcom,ea-pc = <0x270>;
};
+ slim_qca: slim@17240000 {
+ cell-index = <3>;
+ compatible = "qcom,slim-ngd";
+ reg = <0x17240000 0x2c000>,
+ <0x17204000 0x20000>;
+ reg-names = "slimbus_physical", "slimbus_bam_physical";
+ interrupts = <0 291 0>, <0 292 0>;
+ interrupt-names = "slimbus_irq", "slimbus_bam_irq";
+ };
+
eud: qcom,msm-eud@88e0000 {
compatible = "qcom,msm-eud";
interrupt-names = "eud_irq";
@@ -1423,11 +1514,22 @@
qcom,rtb-size = <0x100000>;
};
+ qcom,mpm2-sleep-counter@0x0c221000 {
+ compatible = "qcom,mpm2-sleep-counter";
+ reg = <0x0c221000 0x1000>;
+ clock-frequency = <32768>;
+ };
+
qcom,msm-cdsp-loader {
compatible = "qcom,cdsp-loader";
qcom,proc-img-to-load = "cdsp";
};
+ qcom,msm-adsprpc-mem {
+ compatible = "qcom,msm-adsprpc-mem-region";
+ memory-region = <&adsp_mem>;
+ };
+
qcom,msm_fastrpc {
compatible = "qcom,msm-fastrpc-compute";
@@ -1479,6 +1581,32 @@
iommus = <&apps_smmu 0x1408>,
<&apps_smmu 0x1428>;
};
+ qcom,msm_fastrpc_compute_cb9 {
+ compatible = "qcom,msm-fastrpc-compute-cb";
+ label = "cdsprpc-smd";
+ qcom,secure-context-bank;
+ iommus = <&apps_smmu 0x1409>,
+ <&apps_smmu 0x1419>,
+ <&apps_smmu 0x1429>;
+ };
+ qcom,msm_fastrpc_compute_cb10 {
+ compatible = "qcom,msm-fastrpc-compute-cb";
+ label = "cdsprpc-smd";
+ qcom,secure-context-bank;
+ iommus = <&apps_smmu 0x140A>,
+ <&apps_smmu 0x141A>,
+ <&apps_smmu 0x142A>;
+ };
+ qcom,msm_fastrpc_compute_cb11 {
+ compatible = "qcom,msm-fastrpc-compute-cb";
+ label = "adsprpc-smd";
+ iommus = <&apps_smmu 0x1823>;
+ };
+ qcom,msm_fastrpc_compute_cb12 {
+ compatible = "qcom,msm-fastrpc-compute-cb";
+ label = "adsprpc-smd";
+ iommus = <&apps_smmu 0x1824>;
+ };
};
qcom,msm-imem@146bf000 {
@@ -1498,10 +1626,20 @@
reg = <0x65c 4>;
};
+ boot_stats@6b0 {
+ compatible = "qcom,msm-imem-boot_stats";
+ reg = <0x6b0 32>;
+ };
+
pil@94c {
compatible = "qcom,msm-imem-pil";
reg = <0x94c 200>;
};
+
+ kaslr_offset@6d0 {
+ compatible = "qcom,msm-imem-kaslr_offset";
+ reg = <0x6d0 12>;
+ };
};
qcom,venus@aae0000 {
@@ -1958,15 +2096,74 @@
qcom,pipe-attr-ee;
};
+ qcom_seecom: qseecom@86d00000 {
+ compatible = "qcom,qseecom";
+ reg = <0x86d00000 0x2200000>;
+ reg-names = "secapp-region";
+ qcom,hlos-num-ce-hw-instances = <1>;
+ qcom,hlos-ce-hw-instance = <0>;
+ qcom,qsee-ce-hw-instance = <0>;
+ qcom,disk-encrypt-pipe-pair = <2>;
+ qcom,support-fde;
+ qcom,no-clock-support;
+ qcom,msm-bus,name = "qseecom-noc";
+ qcom,msm-bus,num-cases = <4>;
+ qcom,msm-bus,num-paths = <1>;
+ qcom,msm-bus,vectors-KBps =
+ <125 512 0 0>,
+ <125 512 200000 400000>,
+ <125 512 300000 800000>,
+ <125 512 400000 1000000>;
+ clock-names = "core_clk_src", "core_clk",
+ "iface_clk", "bus_clk";
+ clocks = <&clock_gcc GCC_CE1_CLK>,
+ <&clock_gcc GCC_CE1_CLK>,
+ <&clock_gcc GCC_CE1_AHB_CLK>,
+ <&clock_gcc GCC_CE1_AXI_CLK>;
+ qcom,ce-opp-freq = <171430000>;
+ qcom,qsee-reentrancy-support = <2>;
+ };
+
+ qcom_rng: qrng@793000 {
+ compatible = "qcom,msm-rng";
+ reg = <0x793000 0x1000>;
+ qcom,msm-rng-iface-clk;
+ qcom,no-qrng-config;
+ qcom,msm-bus,name = "msm-rng-noc";
+ qcom,msm-bus,num-cases = <2>;
+ qcom,msm-bus,num-paths = <1>;
+ qcom,msm-bus,vectors-KBps =
+ <1 618 0 0>, /* No vote */
+ <1 618 0 800>; /* 100 KHz */
+ clocks = <&clock_gcc GCC_PRNG_AHB_CLK>;
+ clock-names = "iface_clk";
+ };
+
+ qcom_tzlog: tz-log@146bf720 {
+ compatible = "qcom,tz-log";
+ reg = <0x146bf720 0x3000>;
+ qcom,hyplog-enabled;
+ hyplog-address-offset = <0x410>;
+ hyplog-size-offset = <0x414>;
+ };
+
qcom,msm_gsi {
compatible = "qcom,msm_gsi";
};
+ qcom,rmtfs_sharedmem@0 {
+ compatible = "qcom,sharedmem-uio";
+ reg = <0x0 0x200000>;
+ reg-names = "rmtfs";
+ qcom,client-id = <0x00000001>;
+ };
+
qcom,rmnet-ipa {
compatible = "qcom,rmnet-ipa3";
qcom,rmnet-ipa-ssr;
qcom,ipa-loaduC;
qcom,ipa-advertise-sg-support;
+ qcom,ipa-napi-enable;
};
ipa_hw: qcom,ipa@01e00000 {
@@ -1985,6 +2182,8 @@
qcom,modem-cfg-emb-pipe-flt;
qcom,ipa-wdi2;
qcom,use-64-bit-dma-mask;
+ qcom,arm-smmu;
+ qcom,smmu-s1-bypass;
qcom,bandwidth-vote-for-ipa;
qcom,msm-bus,name = "ipa";
qcom,msm-bus,num-cases = <4>;
@@ -2064,26 +2263,28 @@
0x0 /* modem_comp_decomp_ofst; diff */
0x0 /* modem_comp_decomp_size; diff */
0xbd8 /* modem_ofst; */
- 0x1424 /* modem_size; */
- 0x1ffc /* apps_v4_flt_hash_ofst; */
+ 0x1024 /* modem_size; */
+ 0x2000 /* apps_v4_flt_hash_ofst; */
0x0 /* apps_v4_flt_hash_size; */
- 0x1ffc /* apps_v4_flt_nhash_ofst; */
+ 0x2000 /* apps_v4_flt_nhash_ofst; */
0x0 /* apps_v4_flt_nhash_size; */
- 0x1ffc /* apps_v6_flt_hash_ofst; */
+ 0x2000 /* apps_v6_flt_hash_ofst; */
0x0 /* apps_v6_flt_hash_size; */
- 0x1ffc /* apps_v6_flt_nhash_ofst; */
+ 0x2000 /* apps_v6_flt_nhash_ofst; */
0x0 /* apps_v6_flt_nhash_size; */
0x80 /* uc_info_ofst; */
0x200 /* uc_info_size; */
0x2000 /* end_ofst; */
- 0x1ffc /* apps_v4_rt_hash_ofst; */
+ 0x2000 /* apps_v4_rt_hash_ofst; */
0x0 /* apps_v4_rt_hash_size; */
- 0x1ffc /* apps_v4_rt_nhash_ofst; */
+ 0x2000 /* apps_v4_rt_nhash_ofst; */
0x0 /* apps_v4_rt_nhash_size; */
- 0x1ffc /* apps_v6_rt_hash_ofst; */
+ 0x2000 /* apps_v6_rt_hash_ofst; */
0x0 /* apps_v6_rt_hash_size; */
- 0x1ffc /* apps_v6_rt_nhash_ofst; */
+ 0x2000 /* apps_v6_rt_nhash_ofst; */
0x0 /* apps_v6_rt_nhash_size; */
+ 0x1c00 /* uc_event_ring_ofst; */
+ 0x400 /* uc_event_ring_size; */
>;
/* smp2p gpio information */
@@ -2096,6 +2297,23 @@
compatible = "qcom,smp2pgpio-map-ipa-1-in";
gpios = <&smp2pgpio_ipa_1_in 0 0>;
};
+
+ ipa_smmu_ap: ipa_smmu_ap {
+ compatible = "qcom,ipa-smmu-ap-cb";
+ iommus = <&apps_smmu 0x720>;
+ qcom,iova-mapping = <0x20000000 0x40000000>;
+ };
+
+ ipa_smmu_wlan: ipa_smmu_wlan {
+ compatible = "qcom,ipa-smmu-wlan-cb";
+ iommus = <&apps_smmu 0x721>;
+ };
+
+ ipa_smmu_uc: ipa_smmu_uc {
+ compatible = "qcom,ipa-smmu-uc-cb";
+ iommus = <&apps_smmu 0x722>;
+ qcom,iova-mapping = <0x40000000 0x20000000>;
+ };
};
qcom,ipa_fws {
@@ -2145,6 +2363,8 @@
reg = <0x10a2000 0x1000>,
<0x10ae000 0x2000>;
reg-names = "dcc-base", "dcc-ram-base";
+
+ dcc-ram-offset = <0x6000>;
};
qcom,msm-core@780000 {
@@ -2174,6 +2394,1045 @@
<0 425 0 /* CE11 */ >;
qcom,wlan-msa-memory = <0x100000>;
};
+
+ thermal_zones: thermal-zones {
+ aoss0-ts0-h {
+ polling-delay-passive = <0>;
+ polling-delay = <0>;
+ thermal-governor = "user_space";
+ thermal-sensors = <&tsens0 0>;
+ trips {
+ active-config0 {
+ temperature = <65000>;
+ hysteresis = <1000>;
+ type = "passive";
+ };
+ };
+ };
+
+ cpu0-silver-ts0-h {
+ polling-delay-passive = <0>;
+ polling-delay = <0>;
+ thermal-governor = "user_space";
+ thermal-sensors = <&tsens0 1>;
+ trips {
+ active-config0 {
+ temperature = <65000>;
+ hysteresis = <1000>;
+ type = "passive";
+ };
+ };
+ };
+
+ cpu1-silver-ts0-h {
+ polling-delay-passive = <0>;
+ polling-delay = <0>;
+ thermal-governor = "user_space";
+ thermal-sensors = <&tsens0 2>;
+ trips {
+ active-config0 {
+ temperature = <65000>;
+ hysteresis = <1000>;
+ type = "passive";
+ };
+ };
+ };
+
+ cpu2-silver-ts0-h {
+ polling-delay-passive = <0>;
+ polling-delay = <0>;
+ thermal-governor = "user_space";
+ thermal-sensors = <&tsens0 3>;
+ trips {
+ active-config0 {
+ temperature = <65000>;
+ hysteresis = <1000>;
+ type = "passive";
+ };
+ };
+ };
+
+ cpu3-silver-ts0-h {
+ polling-delay-passive = <0>;
+ polling-delay = <0>;
+ thermal-sensors = <&tsens0 4>;
+ thermal-governor = "user_space";
+ trips {
+ active-config0 {
+ temperature = <65000>;
+ hysteresis = <1000>;
+ type = "passive";
+ };
+ };
+ };
+
+ kryo-l3-0-ts0-h {
+ polling-delay-passive = <0>;
+ polling-delay = <0>;
+ thermal-sensors = <&tsens0 5>;
+ thermal-governor = "user_space";
+ trips {
+ active-config0 {
+ temperature = <65000>;
+ hysteresis = <1000>;
+ type = "passive";
+ };
+ };
+ };
+
+ kryo-l3-1-ts0-h {
+ polling-delay-passive = <0>;
+ polling-delay = <0>;
+ thermal-sensors = <&tsens0 6>;
+ thermal-governor = "user_space";
+ trips {
+ active-config0 {
+ temperature = <65000>;
+ hysteresis = <1000>;
+ type = "passive";
+ };
+ };
+ };
+
+ cpu0-gold-ts0-h {
+ polling-delay-passive = <0>;
+ polling-delay = <0>;
+ thermal-sensors = <&tsens0 7>;
+ thermal-governor = "user_space";
+ trips {
+ active-config0 {
+ temperature = <65000>;
+ hysteresis = <1000>;
+ type = "passive";
+ };
+ };
+ };
+
+ cpu1-gold-ts0-h {
+ polling-delay-passive = <0>;
+ polling-delay = <0>;
+ thermal-sensors = <&tsens0 8>;
+ thermal-governor = "user_space";
+ trips {
+ active-config0 {
+ temperature = <65000>;
+ hysteresis = <1000>;
+ type = "passive";
+ };
+ };
+ };
+
+ cpu2-gold-ts0-h {
+ polling-delay-passive = <0>;
+ polling-delay = <0>;
+ thermal-sensors = <&tsens0 9>;
+ thermal-governor = "user_space";
+ trips {
+ active-config0 {
+ temperature = <65000>;
+ hysteresis = <1000>;
+ type = "passive";
+ };
+ };
+ };
+
+ cpu3-gold-ts0-h {
+ polling-delay-passive = <0>;
+ polling-delay = <0>;
+ thermal-sensors = <&tsens0 10>;
+ thermal-governor = "user_space";
+ trips {
+ active-config0 {
+ temperature = <65000>;
+ hysteresis = <1000>;
+ type = "passive";
+ };
+ };
+ };
+
+ gpu0-ts0-h {
+ polling-delay-passive = <0>;
+ polling-delay = <0>;
+ thermal-sensors = <&tsens0 11>;
+ thermal-governor = "user_space";
+ trips {
+ active-config0 {
+ temperature = <65000>;
+ hysteresis = <1000>;
+ type = "passive";
+ };
+ };
+ };
+
+ gpu1-ts0-h {
+ polling-delay-passive = <0>;
+ polling-delay = <0>;
+ thermal-governor = "user_space";
+ thermal-sensors = <&tsens0 12>;
+ trips {
+ active-config0 {
+ temperature = <65000>;
+ hysteresis = <1000>;
+ type = "passive";
+ };
+ };
+ };
+
+ aoss1-ts1-h {
+ polling-delay-passive = <0>;
+ polling-delay = <0>;
+ thermal-sensors = <&tsens1 0>;
+ thermal-governor = "user_space";
+ trips {
+ active-config0 {
+ temperature = <65000>;
+ hysteresis = <1000>;
+ type = "passive";
+ };
+ };
+ };
+
+ mdm-dsp-ts1-h {
+ polling-delay-passive = <0>;
+ polling-delay = <0>;
+ thermal-sensors = <&tsens1 1>;
+ thermal-governor = "user_space";
+ trips {
+ active-config0 {
+ temperature = <65000>;
+ hysteresis = <1000>;
+ type = "passive";
+ };
+ };
+ };
+
+
+
+ ddr-ts1-h {
+ polling-delay-passive = <0>;
+ polling-delay = <0>;
+ thermal-sensors = <&tsens1 2>;
+ thermal-governor = "user_space";
+ trips {
+ active-config0 {
+ temperature = <65000>;
+ hysteresis = <1000>;
+ type = "passive";
+ };
+ };
+ };
+
+ wlan-ts1-h {
+ polling-delay-passive = <0>;
+ polling-delay = <0>;
+ thermal-sensors = <&tsens1 3>;
+ thermal-governor = "user_space";
+ trips {
+ active-config0 {
+ temperature = <65000>;
+ hysteresis = <1000>;
+ type = "passive";
+ };
+ };
+ };
+
+ compute-hvx-ts1-h {
+ polling-delay-passive = <0>;
+ polling-delay = <0>;
+ thermal-sensors = <&tsens1 4>;
+ thermal-governor = "user_space";
+ trips {
+ active-config0 {
+ temperature = <65000>;
+ hysteresis = <1000>;
+ type = "passive";
+ };
+ };
+ };
+
+ camera-ts1-h {
+ polling-delay-passive = <0>;
+ polling-delay = <0>;
+ thermal-sensors = <&tsens1 5>;
+ thermal-governor = "user_space";
+ trips {
+ active-config0 {
+ temperature = <65000>;
+ hysteresis = <1000>;
+ type = "passive";
+ };
+ };
+ };
+
+ mmss-ts1-h {
+ polling-delay-passive = <0>;
+ polling-delay = <0>;
+ thermal-sensors = <&tsens1 6>;
+ thermal-governor = "user_space";
+ trips {
+ active-config0 {
+ temperature = <65000>;
+ hysteresis = <1000>;
+ type = "passive";
+ };
+ };
+ };
+
+ mdm-core-ts1-h {
+ polling-delay-passive = <0>;
+ polling-delay = <0>;
+ thermal-sensors = <&tsens1 7>;
+ thermal-governor = "user_space";
+ trips {
+ active-config0 {
+ temperature = <65000>;
+ hysteresis = <1000>;
+ type = "passive";
+ };
+ };
+ };
+
+ gpu0 {
+ polling-delay-passive = <10>;
+ polling-delay = <0>;
+ thermal-sensors = <&tsens0 11>;
+ thermal-governor = "step_wise";
+ trips {
+ gpu0_trip: gpu0-trip {
+ temperature = <95000>;
+ hysteresis = <0>;
+ type = "passive";
+ };
+ };
+ cooling-maps {
+ gpu0_cdev {
+ trip = <&gpu0_trip>;
+ cooling-device =
+ <&msm_gpu 1 THERMAL_NO_LIMIT>;
+ };
+ };
+ };
+
+ gpu1 {
+ polling-delay-passive = <10>;
+ polling-delay = <0>;
+ thermal-sensors = <&tsens0 12>;
+ thermal-governor = "step_wise";
+ trips {
+ gpu1_trip: gpu1-trip {
+ temperature = <95000>;
+ hysteresis = <0>;
+ type = "passive";
+ };
+ };
+ cooling-maps {
+ gpu1_cdev {
+ trip = <&gpu1_trip>;
+ cooling-device =
+ <&msm_gpu 1 THERMAL_NO_LIMIT>;
+ };
+ };
+ };
+
+ pop-mem {
+ polling-delay-passive = <10>;
+ polling-delay = <0>;
+ thermal-sensors = <&tsens1 2>;
+ thermal-governor = "step_wise";
+ trips {
+ pop_trip: pop-trip {
+ temperature = <95000>;
+ hysteresis = <0>;
+ type = "passive";
+ };
+ };
+ cooling-maps {
+ pop_cdev {
+ trip = <&pop_trip>;
+ cooling-device =
+ <&CPU4 1 THERMAL_NO_LIMIT>;
+ };
+ };
+ };
+
+ aoss0-ts0-l {
+ polling-delay-passive = <0>;
+ polling-delay = <0>;
+ thermal-governor = "low_limits_floor";
+ thermal-sensors = <&tsens0 0>;
+ tracks-low;
+ trips {
+ aoss0_trip: aoss0-trip {
+ temperature = <5000>;
+ hysteresis = <5000>;
+ type = "passive";
+ };
+ };
+ cooling-maps {
+ cpu0_vdd_cdev {
+ trip = <&aoss0_trip>;
+ cooling-device = <&CPU0 12 12>;
+ };
+ cpu4_vdd_cdev {
+ trip = <&aoss0_trip>;
+ cooling-device = <&CPU4 12 12>;
+ };
+ gpu_vdd_cdev {
+ trip = <&aoss0_trip>;
+ cooling-device = <&msm_gpu 4 4>;
+ };
+ };
+ };
+
+ cpu0-silver-ts0-l {
+ polling-delay-passive = <0>;
+ polling-delay = <0>;
+ thermal-governor = "low_limits_floor";
+ thermal-sensors = <&tsens0 1>;
+ tracks-low;
+ trips {
+ cpu0_trip: cpu0-trip {
+ temperature = <5000>;
+ hysteresis = <5000>;
+ type = "passive";
+ };
+ };
+ cooling-maps {
+ cpu0_vdd_cdev {
+ trip = <&cpu0_trip>;
+ cooling-device = <&CPU0 12 12>;
+ };
+ cpu4_vdd_cdev {
+ trip = <&cpu0_trip>;
+ cooling-device = <&CPU4 12 12>;
+ };
+ gpu_vdd_cdev {
+ trip = <&cpu0_trip>;
+ cooling-device = <&msm_gpu 4 4>;
+ };
+ };
+ };
+
+ cpu1-silver-ts0-l {
+ polling-delay-passive = <0>;
+ polling-delay = <0>;
+ thermal-governor = "low_limits_floor";
+ thermal-sensors = <&tsens0 2>;
+ tracks-low;
+ trips {
+ cpu1_trip: cpu1-trip {
+ temperature = <5000>;
+ hysteresis = <5000>;
+ type = "passive";
+ };
+ };
+ cooling-maps {
+ cpu0_vdd_cdev {
+ trip = <&cpu1_trip>;
+ cooling-device = <&CPU0 12 12>;
+ };
+ cpu4_vdd_cdev {
+ trip = <&cpu1_trip>;
+ cooling-device = <&CPU4 12 12>;
+ };
+ gpu_vdd_cdev {
+ trip = <&cpu1_trip>;
+ cooling-device = <&msm_gpu 4 4>;
+ };
+ };
+ };
+
+ cpu2-silver-ts0-l {
+ polling-delay-passive = <0>;
+ polling-delay = <0>;
+ thermal-governor = "low_limits_floor";
+ thermal-sensors = <&tsens0 3>;
+ tracks-low;
+ trips {
+ cpu2_trip: cpu2-trip {
+ temperature = <5000>;
+ hysteresis = <5000>;
+ type = "passive";
+ };
+ };
+ cooling-maps {
+ cpu0_vdd_cdev {
+ trip = <&cpu2_trip>;
+ cooling-device = <&CPU0 12 12>;
+ };
+ cpu4_vdd_cdev {
+ trip = <&cpu2_trip>;
+ cooling-device = <&CPU4 12 12>;
+ };
+ gpu_vdd_cdev {
+ trip = <&cpu2_trip>;
+ cooling-device = <&msm_gpu 4 4>;
+ };
+ };
+ };
+
+ cpu3-silver-ts0-l {
+ polling-delay-passive = <0>;
+ polling-delay = <0>;
+ thermal-governor = "low_limits_floor";
+ thermal-sensors = <&tsens0 4>;
+ tracks-low;
+ trips {
+ cpu3_trip: cpu3-trip {
+ temperature = <5000>;
+ hysteresis = <5000>;
+ type = "passive";
+ };
+ };
+ cooling-maps {
+ cpu0_vdd_cdev {
+ trip = <&cpu3_trip>;
+ cooling-device = <&CPU0 12 12>;
+ };
+ cpu4_vdd_cdev {
+ trip = <&cpu3_trip>;
+ cooling-device = <&CPU4 12 12>;
+ };
+ gpu_vdd_cdev {
+ trip = <&cpu3_trip>;
+ cooling-device = <&msm_gpu 4 4>;
+ };
+ };
+ };
+
+ kryo-l3-0-ts0-l {
+ polling-delay-passive = <0>;
+ polling-delay = <0>;
+ thermal-governor = "low_limits_floor";
+ thermal-sensors = <&tsens0 5>;
+ tracks-low;
+ trips {
+ l3_0_trip: l3-0-trip {
+ temperature = <5000>;
+ hysteresis = <5000>;
+ type = "passive";
+ };
+ };
+ cooling-maps {
+ cpu0_vdd_cdev {
+ trip = <&l3_0_trip>;
+ cooling-device = <&CPU0 12 12>;
+ };
+ cpu4_vdd_cdev {
+ trip = <&l3_0_trip>;
+ cooling-device = <&CPU4 12 12>;
+ };
+ gpu_vdd_cdev {
+ trip = <&l3_0_trip>;
+ cooling-device = <&msm_gpu 4 4>;
+ };
+ };
+ };
+
+ kryo-l3-1-ts0-l {
+ polling-delay-passive = <0>;
+ polling-delay = <0>;
+ thermal-governor = "low_limits_floor";
+ thermal-sensors = <&tsens0 6>;
+ tracks-low;
+ trips {
+ l3_1_trip: l3-1-trip {
+ temperature = <5000>;
+ hysteresis = <5000>;
+ type = "passive";
+ };
+ };
+ cooling-maps {
+ cpu0_vdd_cdev {
+ trip = <&l3_1_trip>;
+ cooling-device = <&CPU0 12 12>;
+ };
+ cpu4_vdd_cdev {
+ trip = <&l3_1_trip>;
+ cooling-device = <&CPU4 12 12>;
+ };
+ gpu_vdd_cdev {
+ trip = <&l3_1_trip>;
+ cooling-device = <&msm_gpu 4 4>;
+ };
+ };
+ };
+
+ cpu0-gold-ts0-l {
+ polling-delay-passive = <0>;
+ polling-delay = <0>;
+ thermal-governor = "low_limits_floor";
+ thermal-sensors = <&tsens0 7>;
+ tracks-low;
+ trips {
+ cpug0_trip: cpug0-trip {
+ temperature = <5000>;
+ hysteresis = <5000>;
+ type = "passive";
+ };
+ };
+ cooling-maps {
+ cpu0_vdd_cdev {
+ trip = <&cpug0_trip>;
+ cooling-device = <&CPU0 12 12>;
+ };
+ cpu4_vdd_cdev {
+ trip = <&cpug0_trip>;
+ cooling-device = <&CPU4 12 12>;
+ };
+ gpu_vdd_cdev {
+ trip = <&cpug0_trip>;
+ cooling-device = <&msm_gpu 4 4>;
+ };
+ };
+ };
+
+ cpu1-gold-ts0-l {
+ polling-delay-passive = <0>;
+ polling-delay = <0>;
+ thermal-governor = "low_limits_floor";
+ thermal-sensors = <&tsens0 8>;
+ tracks-low;
+ trips {
+ cpug1_trip: cpug1-trip {
+ temperature = <5000>;
+ hysteresis = <5000>;
+ type = "passive";
+ };
+ };
+ cooling-maps {
+ cpu0_vdd_cdev {
+ trip = <&cpug1_trip>;
+ cooling-device = <&CPU0 12 12>;
+ };
+ cpu4_vdd_cdev {
+ trip = <&cpug1_trip>;
+ cooling-device = <&CPU4 12 12>;
+ };
+ gpu_vdd_cdev {
+ trip = <&cpug1_trip>;
+ cooling-device = <&msm_gpu 4 4>;
+ };
+ };
+ };
+
+ cpu2-gold-ts0-l {
+ polling-delay-passive = <0>;
+ polling-delay = <0>;
+ thermal-governor = "low_limits_floor";
+ thermal-sensors = <&tsens0 9>;
+ tracks-low;
+ trips {
+ cpug2_trip: cpug2-trip {
+ temperature = <5000>;
+ hysteresis = <5000>;
+ type = "passive";
+ };
+ };
+ cooling-maps {
+ cpu0_vdd_cdev {
+ trip = <&cpug2_trip>;
+ cooling-device = <&CPU0 12 12>;
+ };
+ cpu4_vdd_cdev {
+ trip = <&cpug2_trip>;
+ cooling-device = <&CPU4 12 12>;
+ };
+ gpu_vdd_cdev {
+ trip = <&cpug2_trip>;
+ cooling-device = <&msm_gpu 4 4>;
+ };
+ };
+ };
+
+ cpu3-gold-ts0-l {
+ polling-delay-passive = <0>;
+ polling-delay = <0>;
+ thermal-governor = "low_limits_floor";
+ thermal-sensors = <&tsens0 9>;
+ tracks-low;
+ trips {
+ cpug3_trip: cpug3-trip {
+ temperature = <5000>;
+ hysteresis = <5000>;
+ type = "passive";
+ };
+ };
+ cooling-maps {
+ cpu0_vdd_cdev {
+ trip = <&cpug3_trip>;
+ cooling-device = <&CPU0 12 12>;
+ };
+ cpu4_vdd_cdev {
+ trip = <&cpug3_trip>;
+ cooling-device = <&CPU4 12 12>;
+ };
+ gpu_vdd_cdev {
+ trip = <&cpug3_trip>;
+ cooling-device = <&msm_gpu 4 4>;
+ };
+ };
+ };
+
+ gpu0-ts0-l {
+ polling-delay-passive = <0>;
+ polling-delay = <0>;
+ thermal-governor = "low_limits_floor";
+ thermal-sensors = <&tsens0 10>;
+ tracks-low;
+ trips {
+ gpu0_trip_l: gpu0-trip {
+ temperature = <5000>;
+ hysteresis = <5000>;
+ type = "passive";
+ };
+ };
+ cooling-maps {
+ cpu0_vdd_cdev {
+ trip = <&gpu0_trip_l>;
+ cooling-device = <&CPU0 12 12>;
+ };
+ cpu4_vdd_cdev {
+ trip = <&gpu0_trip_l>;
+ cooling-device = <&CPU4 12 12>;
+ };
+ gpu_vdd_cdev {
+ trip = <&gpu0_trip_l>;
+ cooling-device = <&msm_gpu 4 4>;
+ };
+ };
+ };
+
+ gpu1-ts0-l {
+ polling-delay-passive = <0>;
+ polling-delay = <0>;
+ thermal-governor = "low_limits_floor";
+ thermal-sensors = <&tsens0 11>;
+ tracks-low;
+ trips {
+ gpu1_trip_l: gpu1-trip_l {
+ temperature = <5000>;
+ hysteresis = <5000>;
+ type = "passive";
+ };
+ };
+ cooling-maps {
+ cpu0_vdd_cdev {
+ trip = <&gpu1_trip_l>;
+ cooling-device = <&CPU0 12 12>;
+ };
+ cpu4_vdd_cdev {
+ trip = <&gpu1_trip_l>;
+ cooling-device = <&CPU4 12 12>;
+ };
+ gpu_vdd_cdev {
+ trip = <&gpu1_trip_l>;
+ cooling-device = <&msm_gpu 4 4>;
+ };
+ };
+ };
+
+ aoss1-ts1-l {
+ polling-delay-passive = <0>;
+ polling-delay = <0>;
+ thermal-governor = "low_limits_floor";
+ thermal-sensors = <&tsens1 0>;
+ tracks-low;
+ trips {
+ aoss1_trip: aoss1-trip {
+ temperature = <5000>;
+ hysteresis = <5000>;
+ type = "passive";
+ };
+ };
+ cooling-maps {
+ cpu0_vdd_cdev {
+ trip = <&aoss1_trip>;
+ cooling-device = <&CPU0 12 12>;
+ };
+ cpu4_vdd_cdev {
+ trip = <&aoss1_trip>;
+ cooling-device = <&CPU4 12 12>;
+ };
+ gpu_vdd_cdev {
+ trip = <&aoss1_trip>;
+ cooling-device = <&msm_gpu 4 4>;
+ };
+ };
+ };
+
+ mdm-dsp-ts1-l {
+ polling-delay-passive = <0>;
+ polling-delay = <0>;
+ thermal-governor = "low_limits_floor";
+ thermal-sensors = <&tsens1 1>;
+ tracks-low;
+ trips {
+ dsp_trip: dsp-trip {
+ temperature = <5000>;
+ hysteresis = <5000>;
+ type = "passive";
+ };
+ };
+ cooling-maps {
+ cpu0_vdd_cdev {
+ trip = <&dsp_trip>;
+ cooling-device = <&CPU0 12 12>;
+ };
+ cpu4_vdd_cdev {
+ trip = <&dsp_trip>;
+ cooling-device = <&CPU4 12 12>;
+ };
+ gpu_vdd_cdev {
+ trip = <&dsp_trip>;
+ cooling-device = <&msm_gpu 4 4>;
+ };
+ };
+ };
+
+ ddr-ts1-l {
+ polling-delay-passive = <0>;
+ polling-delay = <0>;
+ thermal-governor = "low_limits_floor";
+ thermal-sensors = <&tsens1 2>;
+ tracks-low;
+ trips {
+ ddr_trip: ddr-trip {
+ temperature = <5000>;
+ hysteresis = <5000>;
+ type = "passive";
+ };
+ };
+ cooling-maps {
+ cpu0_vdd_cdev {
+ trip = <&ddr_trip>;
+ cooling-device = <&CPU0 12 12>;
+ };
+ cpu4_vdd_cdev {
+ trip = <&ddr_trip>;
+ cooling-device = <&CPU4 12 12>;
+ };
+ gpu_vdd_cdev {
+ trip = <&ddr_trip>;
+ cooling-device = <&msm_gpu 4 4>;
+ };
+ };
+ };
+
+ wlan-ts1-l {
+ polling-delay-passive = <0>;
+ polling-delay = <0>;
+ thermal-governor = "low_limits_floor";
+ thermal-sensors = <&tsens1 3>;
+ tracks-low;
+ trips {
+ wlan_trip: wlan-trip {
+ temperature = <5000>;
+ hysteresis = <5000>;
+ type = "passive";
+ };
+ };
+ cooling-maps {
+ cpu0_vdd_cdev {
+ trip = <&wlan_trip>;
+ cooling-device = <&CPU0 12 12>;
+ };
+ cpu4_vdd_cdev {
+ trip = <&wlan_trip>;
+ cooling-device = <&CPU4 12 12>;
+ };
+ gpu_vdd_cdev {
+ trip = <&wlan_trip>;
+ cooling-device = <&msm_gpu 4 4>;
+ };
+ };
+ };
+
+ compute-hvx-ts1-l {
+ polling-delay-passive = <0>;
+ polling-delay = <0>;
+ thermal-governor = "low_limits_floor";
+ thermal-sensors = <&tsens1 4>;
+ tracks-low;
+ trips {
+ hvx_trip: hvx-trip {
+ temperature = <5000>;
+ hysteresis = <5000>;
+ type = "passive";
+ };
+ };
+ cooling-maps {
+ cpu0_vdd_cdev {
+ trip = <&hvx_trip>;
+ cooling-device = <&CPU0 12 12>;
+ };
+ cpu4_vdd_cdev {
+ trip = <&hvx_trip>;
+ cooling-device = <&CPU4 12 12>;
+ };
+ gpu_vdd_cdev {
+ trip = <&hvx_trip>;
+ cooling-device = <&msm_gpu 4 4>;
+ };
+ };
+ };
+
+ camera-ts1-l {
+ polling-delay-passive = <0>;
+ polling-delay = <0>;
+ thermal-governor = "low_limits_floor";
+ thermal-sensors = <&tsens1 5>;
+ tracks-low;
+ trips {
+ camera_trip: camera-trip {
+ temperature = <5000>;
+ hysteresis = <5000>;
+ type = "passive";
+ };
+ };
+ cooling-maps {
+ cpu0_vdd_cdev {
+ trip = <&camera_trip>;
+ cooling-device = <&CPU0 12 12>;
+ };
+ cpu4_vdd_cdev {
+ trip = <&camera_trip>;
+ cooling-device = <&CPU4 12 12>;
+ };
+ gpu_vdd_cdev {
+ trip = <&camera_trip>;
+ cooling-device = <&msm_gpu 4 4>;
+ };
+ };
+ };
+
+ mmss-ts1-l {
+ polling-delay-passive = <0>;
+ polling-delay = <0>;
+ thermal-governor = "low_limits_floor";
+ thermal-sensors = <&tsens1 6>;
+ tracks-low;
+ trips {
+ mmss_trip: mmss-trip {
+ temperature = <5000>;
+ hysteresis = <5000>;
+ type = "passive";
+ };
+ };
+ cooling-maps {
+ cpu0_vdd_cdev {
+ trip = <&mmss_trip>;
+ cooling-device = <&CPU0 12 12>;
+ };
+ cpu4_vdd_cdev {
+ trip = <&mmss_trip>;
+ cooling-device = <&CPU4 12 12>;
+ };
+ gpu_vdd_cdev {
+ trip = <&mmss_trip>;
+ cooling-device = <&msm_gpu 4 4>;
+ };
+ };
+ };
+
+ mdm-core-ts1-l {
+ polling-delay-passive = <0>;
+ polling-delay = <0>;
+ thermal-governor = "low_limits_floor";
+ thermal-sensors = <&tsens1 7>;
+ tracks-low;
+ trips {
+ mdm_trip: mdm-trip {
+ temperature = <5000>;
+ hysteresis = <5000>;
+ type = "passive";
+ };
+ };
+ cooling-maps {
+ cpu0_vdd_cdev {
+ trip = <&mdm_trip>;
+ cooling-device = <&CPU0 12 12>;
+ };
+ cpu4_vdd_cdev {
+ trip = <&mdm_trip>;
+ cooling-device = <&CPU4 12 12>;
+ };
+ gpu_vdd_cdev {
+ trip = <&mdm_trip>;
+ cooling-device = <&msm_gpu 4 4>;
+ };
+ };
+ };
+
+ lmh-dcvs-01 {
+ polling-delay-passive = <0>;
+ polling-delay = <0>;
+ thermal-governor = "user_space";
+ thermal-sensors = <&lmh_dcvs1>;
+
+ trips {
+ active-config {
+ temperature = <95000>;
+ hysteresis = <30000>;
+ type = "passive";
+ };
+ };
+ };
+
+ lmh-dcvs-00 {
+ polling-delay-passive = <0>;
+ polling-delay = <0>;
+ thermal-governor = "user_space";
+ thermal-sensors = <&lmh_dcvs0>;
+
+ trips {
+ active-config {
+ temperature = <95000>;
+ hysteresis = <30000>;
+ type = "passive";
+ };
+ };
+ };
+
+ };
+
+ tsens0: tsens@c222000 {
+ compatible = "qcom,sdm845-tsens";
+ reg = <0xc222000 0x4>,
+ <0xc263000 0x1ff>;
+ reg-names = "tsens_srot_physical",
+ "tsens_tm_physical";
+ interrupts = <0 506 0>, <0 508 0>;
+ interrupt-names = "tsens-upper-lower", "tsens-critical";
+ #thermal-sensor-cells = <1>;
+ };
+
+ tsens1: tsens@c223000 {
+ compatible = "qcom,sdm845-tsens";
+ reg = <0xc223000 0x4>,
+ <0xc265000 0x1ff>;
+ reg-names = "tsens_srot_physical",
+ "tsens_tm_physical";
+ interrupts = <0 507 0>, <0 509 0>;
+ interrupt-names = "tsens-upper-lower", "tsens-critical";
+ #thermal-sensor-cells = <1>;
+ };
+};
+
+&clock_cpucc {
+ lmh_dcvs0: qcom,limits-dcvs@0 {
+ compatible = "qcom,msm-hw-limits";
+ interrupts = <GIC_SPI 37 IRQ_TYPE_LEVEL_HIGH>;
+ qcom,affinity = <0>;
+ #thermal-sensor-cells = <0>;
+ };
+
+ lmh_dcvs1: qcom,limits-dcvs@1 {
+ compatible = "qcom,msm-hw-limits";
+ interrupts = <GIC_SPI 38 IRQ_TYPE_LEVEL_HIGH>;
+ qcom,affinity = <1>;
+ #thermal-sensor-cells = <0>;
+ };
};
&pcie_0_gdsc {
diff --git a/arch/arm64/configs/sdm845-perf_defconfig b/arch/arm64/configs/sdm845-perf_defconfig
index 1d0b50d..fa6bae8 100644
--- a/arch/arm64/configs/sdm845-perf_defconfig
+++ b/arch/arm64/configs/sdm845-perf_defconfig
@@ -55,6 +55,7 @@
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
@@ -264,6 +265,7 @@
# CONFIG_INPUT_MOUSE is not set
CONFIG_INPUT_TOUCHSCREEN=y
CONFIG_INPUT_MISC=y
+CONFIG_INPUT_HBTP_INPUT=y
CONFIG_INPUT_QPNP_POWER_ON=y
CONFIG_INPUT_UINPUT=y
# CONFIG_SERIO_SERPORT is not set
@@ -274,6 +276,7 @@
CONFIG_SERIAL_MSM_GENI=y
CONFIG_DIAG_CHAR=y
CONFIG_HW_RANDOM=y
+CONFIG_HW_RANDOM_MSM_LEGACY=y
CONFIG_MSM_ADSPRPC=y
CONFIG_I2C_CHARDEV=y
CONFIG_I2C_QCOM_GENI=y
@@ -300,8 +303,17 @@
CONFIG_QPNP_QNOVO=y
CONFIG_SENSORS_QPNP_ADC_VOLTAGE=y
CONFIG_THERMAL=y
+CONFIG_THERMAL_WRITABLE_TRIPS=y
+CONFIG_THERMAL_DEFAULT_GOV_USER_SPACE=y
+CONFIG_THERMAL_GOV_STEP_WISE=y
+CONFIG_THERMAL_GOV_LOW_LIMITS=y
+CONFIG_CPU_THERMAL=y
+CONFIG_DEVFREQ_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_MFD_I2C_PMIC=y
CONFIG_MFD_SPMI_PMIC=y
CONFIG_WCD934X_CODEC=y
@@ -380,6 +392,7 @@
CONFIG_USB_CONFIGFS_F_GSI=y
CONFIG_USB_CONFIGFS_F_QDSS=y
CONFIG_MMC=y
+CONFIG_MMC_CLKGATE=y
CONFIG_MMC_BLOCK_MINORS=32
CONFIG_MMC_BLOCK_DEFERRED_RESUME=y
CONFIG_MMC_TEST=y
@@ -396,6 +409,7 @@
CONFIG_RTC_DRV_QPNP=y
CONFIG_DMADEVICES=y
CONFIG_UIO=y
+CONFIG_UIO_MSM_SHAREDMEM=y
CONFIG_STAGING=y
CONFIG_ASHMEM=y
CONFIG_ANDROID_LOW_MEMORY_KILLER=y
@@ -419,6 +433,7 @@
CONFIG_MSM_CLK_RPMH=y
CONFIG_CLOCK_CPU_OSM=y
CONFIG_MSM_GPUCC_SDM845=y
+CONFIG_MSM_CLK_AOP_QMP=y
CONFIG_QCOM_MDSS_PLL=y
CONFIG_REMOTE_SPINLOCK_MSM=y
CONFIG_MSM_QMP=y
@@ -427,8 +442,10 @@
CONFIG_QCOM_LAZY_MAPPING=y
CONFIG_IOMMU_DEBUG=y
CONFIG_IOMMU_TESTS=y
+CONFIG_QCOM_RUN_QUEUE_STATS=y
CONFIG_QCOM_LLCC=y
CONFIG_QCOM_SDM845_LLCC=y
+CONFIG_MSM_BOOT_STATS=y
CONFIG_QCOM_EUD=y
CONFIG_QCOM_WATCHDOG_V2=y
CONFIG_QCOM_MEMORY_DUMP_V2=y
@@ -478,6 +495,7 @@
CONFIG_ARM_GIC_V3_ACL=y
CONFIG_ANDROID=y
CONFIG_ANDROID_BINDER_IPC=y
+CONFIG_MSM_TZ_LOG=y
CONFIG_EXT2_FS=y
CONFIG_EXT2_FS_XATTR=y
CONFIG_EXT3_FS=y
diff --git a/arch/arm64/configs/sdm845_defconfig b/arch/arm64/configs/sdm845_defconfig
index d9c54c5..a71aa64 100644
--- a/arch/arm64/configs/sdm845_defconfig
+++ b/arch/arm64/configs/sdm845_defconfig
@@ -61,6 +61,7 @@
CONFIG_CLEANCACHE=y
CONFIG_CMA=y
CONFIG_ZSMALLOC=y
+CONFIG_BALANCE_ANON_FILE_RECLAIM=y
CONFIG_SECCOMP=y
CONFIG_ARMV8_DEPRECATED=y
CONFIG_SWP_EMULATION=y
@@ -273,6 +274,7 @@
CONFIG_INPUT_JOYSTICK=y
CONFIG_INPUT_TOUCHSCREEN=y
CONFIG_INPUT_MISC=y
+CONFIG_INPUT_HBTP_INPUT=y
CONFIG_INPUT_QPNP_POWER_ON=y
CONFIG_INPUT_UINPUT=y
# CONFIG_SERIO_SERPORT is not set
@@ -281,9 +283,8 @@
CONFIG_SERIAL_MSM_GENI=y
CONFIG_SERIAL_MSM_GENI_CONSOLE=y
CONFIG_DIAG_CHAR=y
-CONFIG_HVC_DCC=y
-CONFIG_HVC_DCC_SERIALIZE_SMP=y
CONFIG_HW_RANDOM=y
+CONFIG_HW_RANDOM_MSM_LEGACY=y
CONFIG_MSM_ADSPRPC=y
CONFIG_I2C_CHARDEV=y
CONFIG_I2C_QCOM_GENI=y
@@ -310,8 +311,17 @@
CONFIG_QPNP_QNOVO=y
CONFIG_SENSORS_QPNP_ADC_VOLTAGE=y
CONFIG_THERMAL=y
+CONFIG_THERMAL_WRITABLE_TRIPS=y
+CONFIG_THERMAL_DEFAULT_GOV_USER_SPACE=y
+CONFIG_THERMAL_GOV_STEP_WISE=y
+CONFIG_THERMAL_GOV_LOW_LIMITS=y
+CONFIG_CPU_THERMAL=y
+CONFIG_DEVFREQ_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_MFD_I2C_PMIC=y
CONFIG_MFD_SPMI_PMIC=y
CONFIG_WCD934X_CODEC=y
@@ -328,6 +338,7 @@
CONFIG_VIDEO_ADV_DEBUG=y
CONFIG_VIDEO_FIXED_MINOR_RANGES=y
CONFIG_V4L_PLATFORM_DRIVERS=y
+CONFIG_SPECTRA_CAMERA=y
CONFIG_MSM_VIDC_V4L2=y
CONFIG_MSM_VIDC_VMEM=y
CONFIG_MSM_VIDC_GOVERNORS=y
@@ -389,6 +400,7 @@
CONFIG_USB_CONFIGFS_F_GSI=y
CONFIG_USB_CONFIGFS_F_QDSS=y
CONFIG_MMC=y
+CONFIG_MMC_CLKGATE=y
CONFIG_MMC_BLOCK_MINORS=32
CONFIG_MMC_BLOCK_DEFERRED_RESUME=y
CONFIG_MMC_TEST=y
@@ -413,6 +425,7 @@
CONFIG_RTC_DRV_QPNP=y
CONFIG_DMADEVICES=y
CONFIG_UIO=y
+CONFIG_UIO_MSM_SHAREDMEM=y
CONFIG_STAGING=y
CONFIG_ASHMEM=y
CONFIG_ANDROID_LOW_MEMORY_KILLER=y
@@ -436,6 +449,7 @@
CONFIG_MSM_CLK_RPMH=y
CONFIG_CLOCK_CPU_OSM=y
CONFIG_MSM_GPUCC_SDM845=y
+CONFIG_MSM_CLK_AOP_QMP=y
CONFIG_QCOM_MDSS_PLL=y
CONFIG_REMOTE_SPINLOCK_MSM=y
CONFIG_MSM_QMP=y
@@ -445,8 +459,10 @@
CONFIG_IOMMU_DEBUG=y
CONFIG_IOMMU_TESTS=y
CONFIG_QCOM_CPUSS_DUMP=y
+CONFIG_QCOM_RUN_QUEUE_STATS=y
CONFIG_QCOM_LLCC=y
CONFIG_QCOM_SDM845_LLCC=y
+CONFIG_MSM_BOOT_STATS=y
CONFIG_MSM_CORE_HANG_DETECT=y
CONFIG_MSM_GLADIATOR_HANG_DETECT=y
CONFIG_QCOM_EUD=y
@@ -501,6 +517,7 @@
CONFIG_PHY_XGENE=y
CONFIG_ANDROID=y
CONFIG_ANDROID_BINDER_IPC=y
+CONFIG_MSM_TZ_LOG=y
CONFIG_EXT2_FS=y
CONFIG_EXT2_FS_XATTR=y
CONFIG_EXT3_FS=y
@@ -521,10 +538,12 @@
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
@@ -539,7 +558,6 @@
CONFIG_DEBUG_MEMORY_INIT=y
CONFIG_LOCKUP_DETECTOR=y
CONFIG_BOOTPARAM_HARDLOCKUP_PANIC=y
-CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC=y
CONFIG_WQ_WATCHDOG=y
CONFIG_PANIC_TIMEOUT=5
CONFIG_PANIC_ON_SCHED_BUG=y
@@ -552,7 +570,6 @@
CONFIG_DEBUG_MUTEXES=y
CONFIG_DEBUG_ATOMIC_SLEEP=y
CONFIG_DEBUG_LIST=y
-CONFIG_RCU_PANIC_ON_STALL=1
CONFIG_FAULT_INJECTION=y
CONFIG_FAIL_PAGE_ALLOC=y
CONFIG_FAULT_INJECTION_DEBUG_FS=y
diff --git a/arch/arm64/kernel/topology.c b/arch/arm64/kernel/topology.c
index 3b40f26..aaf4bd7 100644
--- a/arch/arm64/kernel/topology.c
+++ b/arch/arm64/kernel/topology.c
@@ -394,7 +394,7 @@
{
struct sched_group_energy *sge = sge_array[cpu][SD_LEVEL1];
- if (!sge) {
+ if (sched_is_energy_aware() && !sge) {
pr_warn("Invalid sched_group_energy for Cluster%d\n", cpu);
return NULL;
}
@@ -407,7 +407,7 @@
{
struct sched_group_energy *sge = sge_array[cpu][SD_LEVEL0];
- if (!sge) {
+ if (sched_is_energy_aware() && !sge) {
pr_warn("Invalid sched_group_energy for CPU%d\n", cpu);
return NULL;
}
diff --git a/arch/arm64/mm/fault.c b/arch/arm64/mm/fault.c
index 296e139..0a34644 100644
--- a/arch/arm64/mm/fault.c
+++ b/arch/arm64/mm/fault.c
@@ -335,7 +335,8 @@
if (is_el0_instruction_abort(esr)) {
vm_flags = VM_EXEC;
- } else if ((esr & ESR_ELx_WNR) && !(esr & ESR_ELx_CM)) {
+ } else if (((esr & ESR_ELx_WNR) && !(esr & ESR_ELx_CM)) ||
+ ((esr & ESR_ELx_CM) && !(mm_flags & FAULT_FLAG_USER))) {
vm_flags = VM_WRITE;
mm_flags |= FAULT_FLAG_WRITE;
}
diff --git a/arch/mips/lantiq/irq.c b/arch/mips/lantiq/irq.c
index 0ddf369..8ac0e59 100644
--- a/arch/mips/lantiq/irq.c
+++ b/arch/mips/lantiq/irq.c
@@ -269,11 +269,6 @@
DEFINE_HWx_IRQDISPATCH(5)
#endif
-static void ltq_hw_irq_handler(struct irq_desc *desc)
-{
- ltq_hw_irqdispatch(irq_desc_get_irq(desc) - 2);
-}
-
#ifdef CONFIG_MIPS_MT_SMP
void __init arch_init_ipiirq(int irq, struct irqaction *action)
{
@@ -318,19 +313,23 @@
asmlinkage void plat_irq_dispatch(void)
{
unsigned int pending = read_c0_status() & read_c0_cause() & ST0_IM;
- int irq;
+ unsigned int i;
- if (!pending) {
- spurious_interrupt();
- return;
+ if ((MIPS_CPU_TIMER_IRQ == 7) && (pending & CAUSEF_IP7)) {
+ do_IRQ(MIPS_CPU_TIMER_IRQ);
+ goto out;
+ } else {
+ for (i = 0; i < MAX_IM; i++) {
+ if (pending & (CAUSEF_IP2 << i)) {
+ ltq_hw_irqdispatch(i);
+ goto out;
+ }
+ }
}
+ pr_alert("Spurious IRQ: CAUSE=0x%08x\n", read_c0_status());
- pending >>= CAUSEB_IP;
- while (pending) {
- irq = fls(pending) - 1;
- do_IRQ(MIPS_CPU_IRQ_BASE + irq);
- pending &= ~BIT(irq);
- }
+out:
+ return;
}
static int icu_map(struct irq_domain *d, unsigned int irq, irq_hw_number_t hw)
@@ -355,6 +354,11 @@
.map = icu_map,
};
+static struct irqaction cascade = {
+ .handler = no_action,
+ .name = "cascade",
+};
+
int __init icu_of_init(struct device_node *node, struct device_node *parent)
{
struct device_node *eiu_node;
@@ -386,7 +390,7 @@
mips_cpu_irq_init();
for (i = 0; i < MAX_IM; i++)
- irq_set_chained_handler(i + 2, ltq_hw_irq_handler);
+ setup_irq(i + 2, &cascade);
if (cpu_has_vint) {
pr_info("Setting up vectored interrupts\n");
diff --git a/arch/parisc/include/asm/uaccess.h b/arch/parisc/include/asm/uaccess.h
index 7fcf512..0497cec 100644
--- a/arch/parisc/include/asm/uaccess.h
+++ b/arch/parisc/include/asm/uaccess.h
@@ -42,10 +42,10 @@
#define get_user __get_user
#if !defined(CONFIG_64BIT)
-#define LDD_USER(ptr) __get_user_asm64(ptr)
+#define LDD_USER(val, ptr) __get_user_asm64(val, ptr)
#define STD_USER(x, ptr) __put_user_asm64(x, ptr)
#else
-#define LDD_USER(ptr) __get_user_asm("ldd", ptr)
+#define LDD_USER(val, ptr) __get_user_asm(val, "ldd", ptr)
#define STD_USER(x, ptr) __put_user_asm("std", x, ptr)
#endif
@@ -100,63 +100,87 @@
" mtsp %0,%%sr2\n\t" \
: : "r"(get_fs()) : )
-#define __get_user(x, ptr) \
-({ \
- register long __gu_err __asm__ ("r8") = 0; \
- register long __gu_val; \
- \
- load_sr2(); \
- switch (sizeof(*(ptr))) { \
- case 1: __get_user_asm("ldb", ptr); break; \
- case 2: __get_user_asm("ldh", ptr); break; \
- case 4: __get_user_asm("ldw", ptr); break; \
- case 8: LDD_USER(ptr); break; \
- default: BUILD_BUG(); break; \
- } \
- \
- (x) = (__force __typeof__(*(ptr))) __gu_val; \
- __gu_err; \
+#define __get_user_internal(val, ptr) \
+({ \
+ register long __gu_err __asm__ ("r8") = 0; \
+ \
+ switch (sizeof(*(ptr))) { \
+ case 1: __get_user_asm(val, "ldb", ptr); break; \
+ case 2: __get_user_asm(val, "ldh", ptr); break; \
+ case 4: __get_user_asm(val, "ldw", ptr); break; \
+ case 8: LDD_USER(val, ptr); break; \
+ default: BUILD_BUG(); \
+ } \
+ \
+ __gu_err; \
})
-#define __get_user_asm(ldx, ptr) \
+#define __get_user(val, ptr) \
+({ \
+ load_sr2(); \
+ __get_user_internal(val, ptr); \
+})
+
+#define __get_user_asm(val, ldx, ptr) \
+{ \
+ register long __gu_val; \
+ \
__asm__("1: " ldx " 0(%%sr2,%2),%0\n" \
"9:\n" \
ASM_EXCEPTIONTABLE_ENTRY_EFAULT(1b, 9b) \
: "=r"(__gu_val), "=r"(__gu_err) \
- : "r"(ptr), "1"(__gu_err));
+ : "r"(ptr), "1"(__gu_err)); \
+ \
+ (val) = (__force __typeof__(*(ptr))) __gu_val; \
+}
#if !defined(CONFIG_64BIT)
-#define __get_user_asm64(ptr) \
+#define __get_user_asm64(val, ptr) \
+{ \
+ union { \
+ unsigned long long l; \
+ __typeof__(*(ptr)) t; \
+ } __gu_tmp; \
+ \
__asm__(" copy %%r0,%R0\n" \
"1: ldw 0(%%sr2,%2),%0\n" \
"2: ldw 4(%%sr2,%2),%R0\n" \
"9:\n" \
ASM_EXCEPTIONTABLE_ENTRY_EFAULT(1b, 9b) \
ASM_EXCEPTIONTABLE_ENTRY_EFAULT(2b, 9b) \
- : "=r"(__gu_val), "=r"(__gu_err) \
- : "r"(ptr), "1"(__gu_err));
+ : "=&r"(__gu_tmp.l), "=r"(__gu_err) \
+ : "r"(ptr), "1"(__gu_err)); \
+ \
+ (val) = __gu_tmp.t; \
+}
#endif /* !defined(CONFIG_64BIT) */
-#define __put_user(x, ptr) \
+#define __put_user_internal(x, ptr) \
({ \
register long __pu_err __asm__ ("r8") = 0; \
__typeof__(*(ptr)) __x = (__typeof__(*(ptr)))(x); \
\
- load_sr2(); \
switch (sizeof(*(ptr))) { \
- case 1: __put_user_asm("stb", __x, ptr); break; \
- case 2: __put_user_asm("sth", __x, ptr); break; \
- case 4: __put_user_asm("stw", __x, ptr); break; \
- case 8: STD_USER(__x, ptr); break; \
- default: BUILD_BUG(); break; \
- } \
+ case 1: __put_user_asm("stb", __x, ptr); break; \
+ case 2: __put_user_asm("sth", __x, ptr); break; \
+ case 4: __put_user_asm("stw", __x, ptr); break; \
+ case 8: STD_USER(__x, ptr); break; \
+ default: BUILD_BUG(); \
+ } \
\
__pu_err; \
})
+#define __put_user(x, ptr) \
+({ \
+ load_sr2(); \
+ __put_user_internal(x, ptr); \
+})
+
+
/*
* The "__put_user/kernel_asm()" macros tell gcc they read from memory
* instead of writing. This is because they do not write to any memory
diff --git a/arch/parisc/lib/lusercopy.S b/arch/parisc/lib/lusercopy.S
index f01188c..85c28bb 100644
--- a/arch/parisc/lib/lusercopy.S
+++ b/arch/parisc/lib/lusercopy.S
@@ -201,7 +201,7 @@
add dst,len,end
/* short copy with less than 16 bytes? */
- cmpib,>>=,n 15,len,.Lbyte_loop
+ cmpib,COND(>>=),n 15,len,.Lbyte_loop
/* same alignment? */
xor src,dst,t0
@@ -216,7 +216,7 @@
/* loop until we are 64-bit aligned */
.Lalign_loop64:
extru dst,31,3,t1
- cmpib,=,n 0,t1,.Lcopy_loop_16
+ cmpib,=,n 0,t1,.Lcopy_loop_16_start
20: ldb,ma 1(srcspc,src),t1
21: stb,ma t1,1(dstspc,dst)
b .Lalign_loop64
@@ -225,6 +225,7 @@
ASM_EXCEPTIONTABLE_ENTRY(20b,.Lcopy_done)
ASM_EXCEPTIONTABLE_ENTRY(21b,.Lcopy_done)
+.Lcopy_loop_16_start:
ldi 31,t0
.Lcopy_loop_16:
cmpb,COND(>>=),n t0,len,.Lword_loop
@@ -267,7 +268,7 @@
/* loop until we are 32-bit aligned */
.Lalign_loop32:
extru dst,31,2,t1
- cmpib,=,n 0,t1,.Lcopy_loop_4
+ cmpib,=,n 0,t1,.Lcopy_loop_8
20: ldb,ma 1(srcspc,src),t1
21: stb,ma t1,1(dstspc,dst)
b .Lalign_loop32
@@ -277,7 +278,7 @@
ASM_EXCEPTIONTABLE_ENTRY(21b,.Lcopy_done)
-.Lcopy_loop_4:
+.Lcopy_loop_8:
cmpib,COND(>>=),n 15,len,.Lbyte_loop
10: ldw 0(srcspc,src),t1
@@ -299,7 +300,7 @@
ASM_EXCEPTIONTABLE_ENTRY(16b,.Lcopy_done)
ASM_EXCEPTIONTABLE_ENTRY(17b,.Lcopy_done)
- b .Lcopy_loop_4
+ b .Lcopy_loop_8
ldo -16(len),len
.Lbyte_loop:
@@ -324,7 +325,7 @@
.Lunaligned_copy:
/* align until dst is 32bit-word-aligned */
extru dst,31,2,t1
- cmpib,COND(=),n 0,t1,.Lcopy_dstaligned
+ cmpib,=,n 0,t1,.Lcopy_dstaligned
20: ldb 0(srcspc,src),t1
ldo 1(src),src
21: stb,ma t1,1(dstspc,dst)
@@ -362,7 +363,7 @@
cmpiclr,<> 1,t0,%r0
b,n .Lcase1
.Lcase0:
- cmpb,= %r0,len,.Lcda_finish
+ cmpb,COND(=) %r0,len,.Lcda_finish
nop
1: ldw,ma 4(srcspc,src), a3
@@ -376,7 +377,7 @@
1: ldw,ma 4(srcspc,src), a3
ASM_EXCEPTIONTABLE_ENTRY(1b,.Lcda_rdfault)
ldo -1(len),len
- cmpb,=,n %r0,len,.Ldo0
+ cmpb,COND(=),n %r0,len,.Ldo0
.Ldo4:
1: ldw,ma 4(srcspc,src), a0
ASM_EXCEPTIONTABLE_ENTRY(1b,.Lcda_rdfault)
@@ -402,7 +403,7 @@
1: stw,ma t0, 4(dstspc,dst)
ASM_EXCEPTIONTABLE_ENTRY(1b,.Lcopy_done)
ldo -4(len),len
- cmpb,<> %r0,len,.Ldo4
+ cmpb,COND(<>) %r0,len,.Ldo4
nop
.Ldo0:
shrpw a2, a3, %sar, t0
@@ -436,14 +437,14 @@
/* fault exception fixup handlers: */
#ifdef CONFIG_64BIT
.Lcopy16_fault:
-10: b .Lcopy_done
- std,ma t1,8(dstspc,dst)
+ b .Lcopy_done
+10: std,ma t1,8(dstspc,dst)
ASM_EXCEPTIONTABLE_ENTRY(10b,.Lcopy_done)
#endif
.Lcopy8_fault:
-10: b .Lcopy_done
- stw,ma t1,4(dstspc,dst)
+ b .Lcopy_done
+10: stw,ma t1,4(dstspc,dst)
ASM_EXCEPTIONTABLE_ENTRY(10b,.Lcopy_done)
.exit
diff --git a/arch/powerpc/kernel/entry_64.S b/arch/powerpc/kernel/entry_64.S
index 6432d4b..767ef6d 100644
--- a/arch/powerpc/kernel/entry_64.S
+++ b/arch/powerpc/kernel/entry_64.S
@@ -689,7 +689,7 @@
addi r8,r1,INT_FRAME_SIZE /* Get the kprobed function entry */
- lwz r3,GPR1(r1)
+ ld r3,GPR1(r1)
subi r3,r3,INT_FRAME_SIZE /* dst: Allocate a trampoline exception frame */
mr r4,r1 /* src: current exception frame */
mr r1,r3 /* Reroute the trampoline frame to r1 */
@@ -703,8 +703,8 @@
addi r6,r6,8
bdnz 2b
- /* Do real store operation to complete stwu */
- lwz r5,GPR1(r1)
+ /* Do real store operation to complete stdu */
+ ld r5,GPR1(r1)
std r8,0(r5)
/* Clear _TIF_EMULATE_STACK_STORE flag */
diff --git a/arch/s390/include/asm/pgtable.h b/arch/s390/include/asm/pgtable.h
index 0362cd5..0cea702 100644
--- a/arch/s390/include/asm/pgtable.h
+++ b/arch/s390/include/asm/pgtable.h
@@ -1029,6 +1029,8 @@
static inline void set_pte_at(struct mm_struct *mm, unsigned long addr,
pte_t *ptep, pte_t entry)
{
+ if (pte_present(entry))
+ pte_val(entry) &= ~_PAGE_UNUSED;
if (mm_has_pgste(mm))
ptep_set_pte_at(mm, addr, ptep, entry);
else
diff --git a/arch/x86/entry/vdso/vdso32-setup.c b/arch/x86/entry/vdso/vdso32-setup.c
index 7853b53..3f9d1a8 100644
--- a/arch/x86/entry/vdso/vdso32-setup.c
+++ b/arch/x86/entry/vdso/vdso32-setup.c
@@ -30,8 +30,10 @@
{
vdso32_enabled = simple_strtoul(s, NULL, 0);
- if (vdso32_enabled > 1)
+ if (vdso32_enabled > 1) {
pr_warn("vdso32 values other than 0 and 1 are no longer allowed; vdso disabled\n");
+ vdso32_enabled = 0;
+ }
return 1;
}
@@ -62,13 +64,18 @@
/* Register vsyscall32 into the ABI table */
#include <linux/sysctl.h>
+static const int zero;
+static const int one = 1;
+
static struct ctl_table abi_table2[] = {
{
.procname = "vsyscall32",
.data = &vdso32_enabled,
.maxlen = sizeof(int),
.mode = 0644,
- .proc_handler = proc_dointvec
+ .proc_handler = proc_dointvec_minmax,
+ .extra1 = (int *)&zero,
+ .extra2 = (int *)&one,
},
{}
};
diff --git a/arch/x86/events/intel/lbr.c b/arch/x86/events/intel/lbr.c
index 81b321a..f924629 100644
--- a/arch/x86/events/intel/lbr.c
+++ b/arch/x86/events/intel/lbr.c
@@ -507,6 +507,9 @@
cpuc->lbr_entries[i].to = msr_lastbranch.to;
cpuc->lbr_entries[i].mispred = 0;
cpuc->lbr_entries[i].predicted = 0;
+ cpuc->lbr_entries[i].in_tx = 0;
+ cpuc->lbr_entries[i].abort = 0;
+ cpuc->lbr_entries[i].cycles = 0;
cpuc->lbr_entries[i].reserved = 0;
}
cpuc->lbr_stack.nr = i;
diff --git a/arch/x86/include/asm/elf.h b/arch/x86/include/asm/elf.h
index e7f155c..94aad63 100644
--- a/arch/x86/include/asm/elf.h
+++ b/arch/x86/include/asm/elf.h
@@ -278,7 +278,7 @@
#define ARCH_DLINFO_IA32 \
do { \
- if (vdso32_enabled) { \
+ if (VDSO_CURRENT_BASE) { \
NEW_AUX_ENT(AT_SYSINFO, VDSO_ENTRY); \
NEW_AUX_ENT(AT_SYSINFO_EHDR, VDSO_CURRENT_BASE); \
} \
diff --git a/arch/x86/include/asm/pmem.h b/arch/x86/include/asm/pmem.h
index 2c1ebeb..529bb4a 100644
--- a/arch/x86/include/asm/pmem.h
+++ b/arch/x86/include/asm/pmem.h
@@ -55,7 +55,8 @@
* @size: number of bytes to write back
*
* Write back a cache range using the CLWB (cache line write back)
- * instruction.
+ * instruction. Note that @size is internally rounded up to be cache
+ * line size aligned.
*/
static inline void arch_wb_cache_pmem(void *addr, size_t size)
{
@@ -69,15 +70,6 @@
clwb(p);
}
-/*
- * copy_from_iter_nocache() on x86 only uses non-temporal stores for iovec
- * iterators, so for other types (bvec & kvec) we must do a cache write-back.
- */
-static inline bool __iter_needs_pmem_wb(struct iov_iter *i)
-{
- return iter_is_iovec(i) == false;
-}
-
/**
* arch_copy_from_iter_pmem - copy data from an iterator to PMEM
* @addr: PMEM destination address
@@ -94,7 +86,35 @@
/* TODO: skip the write-back by always using non-temporal stores */
len = copy_from_iter_nocache(addr, bytes, i);
- if (__iter_needs_pmem_wb(i))
+ /*
+ * In the iovec case on x86_64 copy_from_iter_nocache() uses
+ * non-temporal stores for the bulk of the transfer, but we need
+ * to manually flush if the transfer is unaligned. A cached
+ * memory copy is used when destination or size is not naturally
+ * aligned. That is:
+ * - Require 8-byte alignment when size is 8 bytes or larger.
+ * - Require 4-byte alignment when size is 4 bytes.
+ *
+ * In the non-iovec case the entire destination needs to be
+ * flushed.
+ */
+ if (iter_is_iovec(i)) {
+ unsigned long flushed, dest = (unsigned long) addr;
+
+ if (bytes < 8) {
+ if (!IS_ALIGNED(dest, 4) || (bytes != 4))
+ arch_wb_cache_pmem(addr, 1);
+ } else {
+ if (!IS_ALIGNED(dest, 8)) {
+ dest = ALIGN(dest, boot_cpu_data.x86_clflush_size);
+ arch_wb_cache_pmem(addr, 1);
+ }
+
+ flushed = dest - (unsigned long) addr;
+ if (bytes > flushed && !IS_ALIGNED(bytes - flushed, 8))
+ arch_wb_cache_pmem(addr + bytes - 1, 1);
+ }
+ } else
arch_wb_cache_pmem(addr, bytes);
return len;
diff --git a/arch/x86/kernel/cpu/mcheck/mce-genpool.c b/arch/x86/kernel/cpu/mcheck/mce-genpool.c
index 93d824e..040af19 100644
--- a/arch/x86/kernel/cpu/mcheck/mce-genpool.c
+++ b/arch/x86/kernel/cpu/mcheck/mce-genpool.c
@@ -85,7 +85,7 @@
head = llist_reverse_order(head);
llist_for_each_entry_safe(node, tmp, head, llnode) {
mce = &node->mce;
- atomic_notifier_call_chain(&x86_mce_decoder_chain, 0, mce);
+ blocking_notifier_call_chain(&x86_mce_decoder_chain, 0, mce);
gen_pool_free(mce_evt_pool, (unsigned long)node, sizeof(*node));
}
}
diff --git a/arch/x86/kernel/cpu/mcheck/mce-internal.h b/arch/x86/kernel/cpu/mcheck/mce-internal.h
index cd74a3f..de20902 100644
--- a/arch/x86/kernel/cpu/mcheck/mce-internal.h
+++ b/arch/x86/kernel/cpu/mcheck/mce-internal.h
@@ -13,7 +13,7 @@
MCE_PANIC_SEVERITY,
};
-extern struct atomic_notifier_head x86_mce_decoder_chain;
+extern struct blocking_notifier_head x86_mce_decoder_chain;
#define ATTR_LEN 16
#define INITIAL_CHECK_INTERVAL 5 * 60 /* 5 minutes */
diff --git a/arch/x86/kernel/cpu/mcheck/mce.c b/arch/x86/kernel/cpu/mcheck/mce.c
index a7fdf45..22cda29 100644
--- a/arch/x86/kernel/cpu/mcheck/mce.c
+++ b/arch/x86/kernel/cpu/mcheck/mce.c
@@ -120,7 +120,7 @@
* CPU/chipset specific EDAC code can register a notifier call here to print
* MCE errors in a human-readable form.
*/
-ATOMIC_NOTIFIER_HEAD(x86_mce_decoder_chain);
+BLOCKING_NOTIFIER_HEAD(x86_mce_decoder_chain);
/* Do initial initialization of a struct mce */
void mce_setup(struct mce *m)
@@ -213,13 +213,13 @@
if (nb != &mce_srao_nb && nb->priority == INT_MAX)
nb->priority -= 1;
- atomic_notifier_chain_register(&x86_mce_decoder_chain, nb);
+ blocking_notifier_chain_register(&x86_mce_decoder_chain, nb);
}
EXPORT_SYMBOL_GPL(mce_register_decode_chain);
void mce_unregister_decode_chain(struct notifier_block *nb)
{
- atomic_notifier_chain_unregister(&x86_mce_decoder_chain, nb);
+ blocking_notifier_chain_unregister(&x86_mce_decoder_chain, nb);
}
EXPORT_SYMBOL_GPL(mce_unregister_decode_chain);
@@ -272,8 +272,6 @@
static void print_mce(struct mce *m)
{
- int ret = 0;
-
pr_emerg(HW_ERR "CPU %d: Machine Check Exception: %Lx Bank %d: %016Lx\n",
m->extcpu, m->mcgstatus, m->bank, m->status);
@@ -309,14 +307,6 @@
m->cpuvendor, m->cpuid, m->time, m->socketid, m->apicid,
cpu_data(m->extcpu).microcode);
- /*
- * Print out human-readable details about the MCE error,
- * (if the CPU has an implementation for that)
- */
- ret = atomic_notifier_call_chain(&x86_mce_decoder_chain, 0, m);
- if (ret == NOTIFY_STOP)
- return;
-
pr_emerg_ratelimited(HW_ERR "Run the above through 'mcelog --ascii'\n");
}
diff --git a/arch/x86/kernel/cpu/mcheck/mce_amd.c b/arch/x86/kernel/cpu/mcheck/mce_amd.c
index 9b54034..3dfca7b 100644
--- a/arch/x86/kernel/cpu/mcheck/mce_amd.c
+++ b/arch/x86/kernel/cpu/mcheck/mce_amd.c
@@ -59,7 +59,7 @@
"load_store",
"insn_fetch",
"combined_unit",
- "",
+ "decode_unit",
"northbridge",
"execution_unit",
};
diff --git a/arch/x86/kernel/signal_compat.c b/arch/x86/kernel/signal_compat.c
index ec1f756..71beb28 100644
--- a/arch/x86/kernel/signal_compat.c
+++ b/arch/x86/kernel/signal_compat.c
@@ -151,8 +151,8 @@
if (from->si_signo == SIGSEGV) {
if (from->si_code == SEGV_BNDERR) {
- compat_uptr_t lower = (unsigned long)&to->si_lower;
- compat_uptr_t upper = (unsigned long)&to->si_upper;
+ compat_uptr_t lower = (unsigned long)from->si_lower;
+ compat_uptr_t upper = (unsigned long)from->si_upper;
put_user_ex(lower, &to->si_lower);
put_user_ex(upper, &to->si_upper);
}
diff --git a/arch/x86/kvm/vmx.c b/arch/x86/kvm/vmx.c
index 69b8f8a..43b55ef 100644
--- a/arch/x86/kvm/vmx.c
+++ b/arch/x86/kvm/vmx.c
@@ -6925,14 +6925,20 @@
}
page = nested_get_page(vcpu, vmptr);
- if (page == NULL ||
- *(u32 *)kmap(page) != VMCS12_REVISION) {
+ if (page == NULL) {
nested_vmx_failInvalid(vcpu);
+ skip_emulated_instruction(vcpu);
+ return 1;
+ }
+ if (*(u32 *)kmap(page) != VMCS12_REVISION) {
kunmap(page);
+ nested_release_page_clean(page);
+ nested_vmx_failInvalid(vcpu);
skip_emulated_instruction(vcpu);
return 1;
}
kunmap(page);
+ nested_release_page_clean(page);
vmx->nested.vmxon_ptr = vmptr;
break;
case EXIT_REASON_VMCLEAR:
diff --git a/arch/x86/mm/init.c b/arch/x86/mm/init.c
index 22af912..889e761 100644
--- a/arch/x86/mm/init.c
+++ b/arch/x86/mm/init.c
@@ -643,21 +643,40 @@
* devmem_is_allowed() checks to see if /dev/mem access to a certain address
* is valid. The argument is a physical page number.
*
- *
- * On x86, access has to be given to the first megabyte of ram because that area
- * contains BIOS code and data regions used by X and dosemu and similar apps.
- * Access has to be given to non-kernel-ram areas as well, these contain the PCI
- * mmio resources as well as potential bios/acpi data regions.
+ * On x86, access has to be given to the first megabyte of RAM because that
+ * area traditionally contains BIOS code and data regions used by X, dosemu,
+ * and similar apps. Since they map the entire memory range, the whole range
+ * must be allowed (for mapping), but any areas that would otherwise be
+ * disallowed are flagged as being "zero filled" instead of rejected.
+ * Access has to be given to non-kernel-ram areas as well, these contain the
+ * PCI mmio resources as well as potential bios/acpi data regions.
*/
int devmem_is_allowed(unsigned long pagenr)
{
- if (pagenr < 256)
- return 1;
- if (iomem_is_exclusive(pagenr << PAGE_SHIFT))
+ if (page_is_ram(pagenr)) {
+ /*
+ * For disallowed memory regions in the low 1MB range,
+ * request that the page be shown as all zeros.
+ */
+ if (pagenr < 256)
+ return 2;
+
return 0;
- if (!page_is_ram(pagenr))
- return 1;
- return 0;
+ }
+
+ /*
+ * This must follow RAM test, since System RAM is considered a
+ * restricted resource under CONFIG_STRICT_IOMEM.
+ */
+ if (iomem_is_exclusive(pagenr << PAGE_SHIFT)) {
+ /* Low 1MB bypasses iomem restrictions. */
+ if (pagenr < 256)
+ return 1;
+
+ return 0;
+ }
+
+ return 1;
}
void free_init_pages(char *what, unsigned long begin, unsigned long end)
diff --git a/arch/x86/platform/efi/quirks.c b/arch/x86/platform/efi/quirks.c
index 30031d5..cdfe8c6 100644
--- a/arch/x86/platform/efi/quirks.c
+++ b/arch/x86/platform/efi/quirks.c
@@ -201,6 +201,10 @@
return;
}
+ /* No need to reserve regions that will never be freed. */
+ if (md.attribute & EFI_MEMORY_RUNTIME)
+ return;
+
size += addr % EFI_PAGE_SIZE;
size = round_up(size, EFI_PAGE_SIZE);
addr = round_down(addr, EFI_PAGE_SIZE);
diff --git a/arch/x86/xen/apic.c b/arch/x86/xen/apic.c
index 44c88ad..bcea81f 100644
--- a/arch/x86/xen/apic.c
+++ b/arch/x86/xen/apic.c
@@ -145,7 +145,7 @@
static int xen_cpu_present_to_apicid(int cpu)
{
if (cpu_present(cpu))
- return xen_get_apic_id(xen_apic_read(APIC_ID));
+ return cpu_data(cpu).apicid;
else
return BAD_APICID;
}
diff --git a/crypto/ahash.c b/crypto/ahash.c
index 2ce8bcb..cce0268 100644
--- a/crypto/ahash.c
+++ b/crypto/ahash.c
@@ -31,6 +31,7 @@
crypto_completion_t complete;
void *data;
u8 *result;
+ u32 flags;
void *ubuf[] CRYPTO_MINALIGN_ATTR;
};
@@ -252,6 +253,8 @@
priv->result = req->result;
priv->complete = req->base.complete;
priv->data = req->base.data;
+ priv->flags = req->base.flags;
+
/*
* WARNING: We do not backup req->priv here! The req->priv
* is for internal use of the Crypto API and the
@@ -266,38 +269,44 @@
return 0;
}
-static void ahash_restore_req(struct ahash_request *req)
+static void ahash_restore_req(struct ahash_request *req, int err)
{
struct ahash_request_priv *priv = req->priv;
+ if (!err)
+ memcpy(priv->result, req->result,
+ crypto_ahash_digestsize(crypto_ahash_reqtfm(req)));
+
/* Restore the original crypto request. */
req->result = priv->result;
- req->base.complete = priv->complete;
- req->base.data = priv->data;
+
+ ahash_request_set_callback(req, priv->flags,
+ priv->complete, priv->data);
req->priv = NULL;
/* Free the req->priv.priv from the ADJUSTED request. */
kzfree(priv);
}
-static void ahash_op_unaligned_finish(struct ahash_request *req, int err)
+static void ahash_notify_einprogress(struct ahash_request *req)
{
struct ahash_request_priv *priv = req->priv;
+ struct crypto_async_request oreq;
- if (err == -EINPROGRESS)
- return;
+ oreq.data = priv->data;
- if (!err)
- memcpy(priv->result, req->result,
- crypto_ahash_digestsize(crypto_ahash_reqtfm(req)));
-
- ahash_restore_req(req);
+ priv->complete(&oreq, -EINPROGRESS);
}
static void ahash_op_unaligned_done(struct crypto_async_request *req, int err)
{
struct ahash_request *areq = req->data;
+ if (err == -EINPROGRESS) {
+ ahash_notify_einprogress(areq);
+ return;
+ }
+
/*
* Restore the original request, see ahash_op_unaligned() for what
* goes where.
@@ -308,7 +317,7 @@
*/
/* First copy req->result into req->priv.result */
- ahash_op_unaligned_finish(areq, err);
+ ahash_restore_req(areq, err);
/* Complete the ORIGINAL request. */
areq->base.complete(&areq->base, err);
@@ -324,7 +333,12 @@
return err;
err = op(req);
- ahash_op_unaligned_finish(req, err);
+ if (err == -EINPROGRESS ||
+ (err == -EBUSY && (ahash_request_flags(req) &
+ CRYPTO_TFM_REQ_MAY_BACKLOG)))
+ return err;
+
+ ahash_restore_req(req, err);
return err;
}
@@ -359,25 +373,14 @@
}
EXPORT_SYMBOL_GPL(crypto_ahash_digest);
-static void ahash_def_finup_finish2(struct ahash_request *req, int err)
-{
- struct ahash_request_priv *priv = req->priv;
-
- if (err == -EINPROGRESS)
- return;
-
- if (!err)
- memcpy(priv->result, req->result,
- crypto_ahash_digestsize(crypto_ahash_reqtfm(req)));
-
- ahash_restore_req(req);
-}
-
static void ahash_def_finup_done2(struct crypto_async_request *req, int err)
{
struct ahash_request *areq = req->data;
- ahash_def_finup_finish2(areq, err);
+ if (err == -EINPROGRESS)
+ return;
+
+ ahash_restore_req(areq, err);
areq->base.complete(&areq->base, err);
}
@@ -388,11 +391,15 @@
goto out;
req->base.complete = ahash_def_finup_done2;
- req->base.flags &= ~CRYPTO_TFM_REQ_MAY_SLEEP;
+
err = crypto_ahash_reqtfm(req)->final(req);
+ if (err == -EINPROGRESS ||
+ (err == -EBUSY && (ahash_request_flags(req) &
+ CRYPTO_TFM_REQ_MAY_BACKLOG)))
+ return err;
out:
- ahash_def_finup_finish2(req, err);
+ ahash_restore_req(req, err);
return err;
}
@@ -400,7 +407,16 @@
{
struct ahash_request *areq = req->data;
+ if (err == -EINPROGRESS) {
+ ahash_notify_einprogress(areq);
+ return;
+ }
+
+ areq->base.flags &= ~CRYPTO_TFM_REQ_MAY_SLEEP;
+
err = ahash_def_finup_finish1(areq, err);
+ if (areq->priv)
+ return;
areq->base.complete(&areq->base, err);
}
@@ -415,6 +431,11 @@
return err;
err = tfm->update(req);
+ if (err == -EINPROGRESS ||
+ (err == -EBUSY && (ahash_request_flags(req) &
+ CRYPTO_TFM_REQ_MAY_BACKLOG)))
+ return err;
+
return ahash_def_finup_finish1(req, err);
}
diff --git a/crypto/algif_aead.c b/crypto/algif_aead.c
index e8817e2..fde8d88 100644
--- a/crypto/algif_aead.c
+++ b/crypto/algif_aead.c
@@ -39,6 +39,7 @@
struct aead_async_rsgl first_rsgl;
struct list_head list;
struct kiocb *iocb;
+ struct sock *sk;
unsigned int tsgls;
char iv[];
};
@@ -379,12 +380,10 @@
static void aead_async_cb(struct crypto_async_request *_req, int err)
{
- struct sock *sk = _req->data;
- struct alg_sock *ask = alg_sk(sk);
- struct aead_ctx *ctx = ask->private;
- struct crypto_aead *tfm = crypto_aead_reqtfm(&ctx->aead_req);
- struct aead_request *req = aead_request_cast(_req);
+ struct aead_request *req = _req->data;
+ struct crypto_aead *tfm = crypto_aead_reqtfm(req);
struct aead_async_req *areq = GET_ASYM_REQ(req, tfm);
+ struct sock *sk = areq->sk;
struct scatterlist *sg = areq->tsgl;
struct aead_async_rsgl *rsgl;
struct kiocb *iocb = areq->iocb;
@@ -447,11 +446,12 @@
memset(&areq->first_rsgl, '\0', sizeof(areq->first_rsgl));
INIT_LIST_HEAD(&areq->list);
areq->iocb = msg->msg_iocb;
+ areq->sk = sk;
memcpy(areq->iv, ctx->iv, crypto_aead_ivsize(tfm));
aead_request_set_tfm(req, tfm);
aead_request_set_ad(req, ctx->aead_assoclen);
aead_request_set_callback(req, CRYPTO_TFM_REQ_MAY_BACKLOG,
- aead_async_cb, sk);
+ aead_async_cb, req);
used -= ctx->aead_assoclen;
/* take over all tx sgls from ctx */
diff --git a/drivers/acpi/ec.c b/drivers/acpi/ec.c
index 48e19d0..22ca892 100644
--- a/drivers/acpi/ec.c
+++ b/drivers/acpi/ec.c
@@ -729,12 +729,12 @@
static int ec_guard(struct acpi_ec *ec)
{
- unsigned long guard = usecs_to_jiffies(ec_polling_guard);
+ unsigned long guard = usecs_to_jiffies(ec->polling_guard);
unsigned long timeout = ec->timestamp + guard;
/* Ensure guarding period before polling EC status */
do {
- if (ec_busy_polling) {
+ if (ec->busy_polling) {
/* Perform busy polling */
if (ec_transaction_completed(ec))
return 0;
@@ -998,6 +998,28 @@
spin_unlock_irqrestore(&ec->lock, flags);
}
+static void acpi_ec_enter_noirq(struct acpi_ec *ec)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&ec->lock, flags);
+ ec->busy_polling = true;
+ ec->polling_guard = 0;
+ ec_log_drv("interrupt blocked");
+ spin_unlock_irqrestore(&ec->lock, flags);
+}
+
+static void acpi_ec_leave_noirq(struct acpi_ec *ec)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&ec->lock, flags);
+ ec->busy_polling = ec_busy_polling;
+ ec->polling_guard = ec_polling_guard;
+ ec_log_drv("interrupt unblocked");
+ spin_unlock_irqrestore(&ec->lock, flags);
+}
+
void acpi_ec_block_transactions(void)
{
struct acpi_ec *ec = first_ec;
@@ -1278,7 +1300,7 @@
if (function != ACPI_READ && function != ACPI_WRITE)
return AE_BAD_PARAMETER;
- if (ec_busy_polling || bits > 8)
+ if (ec->busy_polling || bits > 8)
acpi_ec_burst_enable(ec);
for (i = 0; i < bytes; ++i, ++address, ++value)
@@ -1286,7 +1308,7 @@
acpi_ec_read(ec, address, value) :
acpi_ec_write(ec, address, *value);
- if (ec_busy_polling || bits > 8)
+ if (ec->busy_polling || bits > 8)
acpi_ec_burst_disable(ec);
switch (result) {
@@ -1329,6 +1351,8 @@
spin_lock_init(&ec->lock);
INIT_WORK(&ec->work, acpi_ec_event_handler);
ec->timestamp = jiffies;
+ ec->busy_polling = true;
+ ec->polling_guard = 0;
return ec;
}
@@ -1390,6 +1414,7 @@
acpi_ec_start(ec, false);
if (!test_bit(EC_FLAGS_EC_HANDLER_INSTALLED, &ec->flags)) {
+ acpi_ec_enter_noirq(ec);
status = acpi_install_address_space_handler(ec->handle,
ACPI_ADR_SPACE_EC,
&acpi_ec_space_handler,
@@ -1429,6 +1454,7 @@
/* This is not fatal as we can poll EC events */
if (ACPI_SUCCESS(status)) {
set_bit(EC_FLAGS_GPE_HANDLER_INSTALLED, &ec->flags);
+ acpi_ec_leave_noirq(ec);
if (test_bit(EC_FLAGS_STARTED, &ec->flags) &&
ec->reference_count >= 1)
acpi_ec_enable_gpe(ec, true);
@@ -1839,34 +1865,6 @@
}
#ifdef CONFIG_PM_SLEEP
-static void acpi_ec_enter_noirq(struct acpi_ec *ec)
-{
- unsigned long flags;
-
- if (ec == first_ec) {
- spin_lock_irqsave(&ec->lock, flags);
- ec->saved_busy_polling = ec_busy_polling;
- ec->saved_polling_guard = ec_polling_guard;
- ec_busy_polling = true;
- ec_polling_guard = 0;
- ec_log_drv("interrupt blocked");
- spin_unlock_irqrestore(&ec->lock, flags);
- }
-}
-
-static void acpi_ec_leave_noirq(struct acpi_ec *ec)
-{
- unsigned long flags;
-
- if (ec == first_ec) {
- spin_lock_irqsave(&ec->lock, flags);
- ec_busy_polling = ec->saved_busy_polling;
- ec_polling_guard = ec->saved_polling_guard;
- ec_log_drv("interrupt unblocked");
- spin_unlock_irqrestore(&ec->lock, flags);
- }
-}
-
static int acpi_ec_suspend_noirq(struct device *dev)
{
struct acpi_ec *ec =
diff --git a/drivers/acpi/internal.h b/drivers/acpi/internal.h
index 0c45226..219b90b 100644
--- a/drivers/acpi/internal.h
+++ b/drivers/acpi/internal.h
@@ -172,8 +172,8 @@
struct work_struct work;
unsigned long timestamp;
unsigned long nr_pending_queries;
- bool saved_busy_polling;
- unsigned int saved_polling_guard;
+ bool busy_polling;
+ unsigned int polling_guard;
};
extern struct acpi_ec *first_ec;
diff --git a/drivers/acpi/nfit/core.c b/drivers/acpi/nfit/core.c
index d1664df..9ef3941 100644
--- a/drivers/acpi/nfit/core.c
+++ b/drivers/acpi/nfit/core.c
@@ -1617,7 +1617,11 @@
const struct nfit_set_info_map *map0 = m0;
const struct nfit_set_info_map *map1 = m1;
- return map0->region_offset - map1->region_offset;
+ if (map0->region_offset < map1->region_offset)
+ return -1;
+ else if (map0->region_offset > map1->region_offset)
+ return 1;
+ return 0;
}
/* Retrieve the nth entry referencing this spa */
diff --git a/drivers/acpi/power.c b/drivers/acpi/power.c
index fcd4ce6..1c2b846 100644
--- a/drivers/acpi/power.c
+++ b/drivers/acpi/power.c
@@ -200,6 +200,7 @@
return -EINVAL;
/* The state of the list is 'on' IFF all resources are 'on'. */
+ cur_state = 0;
list_for_each_entry(entry, list, node) {
struct acpi_power_resource *resource = entry->resource;
acpi_handle handle = resource->device.handle;
diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c
index 5a2fdf1..dd3786a 100644
--- a/drivers/acpi/scan.c
+++ b/drivers/acpi/scan.c
@@ -1827,15 +1827,20 @@
return;
device->flags.match_driver = true;
- if (!ret) {
- ret = device_attach(&device->dev);
- if (ret < 0)
- return;
-
- if (!ret && device->pnp.type.platform_id)
- acpi_default_enumeration(device);
+ if (ret > 0) {
+ acpi_device_set_enumerated(device);
+ goto ok;
}
+ ret = device_attach(&device->dev);
+ if (ret < 0)
+ return;
+
+ if (ret > 0 || !device->pnp.type.platform_id)
+ acpi_device_set_enumerated(device);
+ else
+ acpi_default_enumeration(device);
+
ok:
list_for_each_entry(child, &device->children, node)
acpi_bus_attach(child);
diff --git a/drivers/android/binder.c b/drivers/android/binder.c
index d7eb419..6485c77 100644
--- a/drivers/android/binder.c
+++ b/drivers/android/binder.c
@@ -1765,7 +1765,9 @@
ret = -EBADF;
goto err_fget;
}
+ preempt_enable_no_resched();
ret = security_binder_transfer_file(proc->tsk, target_proc->tsk, file);
+ preempt_disable();
if (ret < 0) {
ret = -EPERM;
goto err_security;
diff --git a/drivers/base/dma-removed.c b/drivers/base/dma-removed.c
index 4281801..09e77d5 100644
--- a/drivers/base/dma-removed.c
+++ b/drivers/base/dma-removed.c
@@ -1,6 +1,6 @@
/*
*
- * Copyright (c) 2013-2016, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2013-2017, The Linux Foundation. All rights reserved.
* Copyright (C) 2000-2004 Russell King
*
* This program is free software; you can redistribute it and/or modify
@@ -294,6 +294,7 @@
bool no_kernel_mapping = attrs & DMA_ATTR_NO_KERNEL_MAPPING;
struct removed_region *dma_mem = dev->removed_mem;
+ size = PAGE_ALIGN(size);
if (!no_kernel_mapping)
iounmap(cpu_addr);
mutex_lock(&dma_mem->lock);
diff --git a/drivers/base/regmap/regcache.c b/drivers/base/regmap/regcache.c
index 4e58256..da97163 100644
--- a/drivers/base/regmap/regcache.c
+++ b/drivers/base/regmap/regcache.c
@@ -731,6 +731,53 @@
return ret;
}
+static int regcache_sync_block_raw_multi_reg(struct regmap *map, void *block,
+ unsigned long *cache_present,
+ unsigned int block_base,
+ unsigned int start,
+ unsigned int end)
+{
+ unsigned int i, val;
+ unsigned int regtmp = 0;
+ int ret = 0;
+ struct reg_sequence *regs;
+ size_t num_regs = ((end - start) + 1);
+
+ regs = kcalloc(num_regs, sizeof(struct reg_sequence), GFP_KERNEL);
+ if (!regs)
+ return -ENOMEM;
+
+ num_regs = 0;
+ for (i = start; i < end; i++) {
+ regtmp = block_base + (i * map->reg_stride);
+
+ /* skip registers that are not defined/available */
+ if (!regcache_reg_present(cache_present, i))
+ continue;
+
+ val = regcache_get_val(map, block, i);
+
+ /* Is this the hardware default? If so skip. */
+ ret = regcache_lookup_reg(map, regtmp);
+ if (ret >= 0 && val == map->reg_defaults[ret].def) {
+ continue;
+ } else {
+ regs[num_regs].reg = regtmp;
+ regs[num_regs].def = val;
+ regs[num_regs].delay_us = 0;
+ num_regs += 1;
+ }
+ }
+ ret = 0;
+ if (num_regs) {
+ dev_dbg(map->dev, "%s: start: 0x%x - end: 0x%x\n",
+ __func__, regs[0].reg, regs[num_regs-1].reg);
+ ret = _regmap_raw_multi_reg_write(map, regs, num_regs);
+ }
+ kfree(regs);
+ return ret;
+}
+
static int regcache_sync_block_raw(struct regmap *map, void *block,
unsigned long *cache_present,
unsigned int block_base, unsigned int start,
@@ -778,7 +825,12 @@
unsigned int block_base, unsigned int start,
unsigned int end)
{
- if (regmap_can_raw_write(map) && !map->use_single_write)
+ if (regmap_can_raw_write(map) && map->can_multi_write)
+ return regcache_sync_block_raw_multi_reg(map, block,
+ cache_present,
+ block_base, start,
+ end);
+ else if (regmap_can_raw_write(map) && !map->use_single_write)
return regcache_sync_block_raw(map, block, cache_present,
block_base, start, end);
else
diff --git a/drivers/base/regmap/regmap-swr.c b/drivers/base/regmap/regmap-swr.c
index 1a2e09e..be1eb00 100644
--- a/drivers/base/regmap/regmap-swr.c
+++ b/drivers/base/regmap/regmap-swr.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2015-2017, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -11,6 +11,9 @@
* GNU General Public License for more details.
*/
+#include <linux/device.h>
+#include <linux/slab.h>
+#include <linux/mutex.h>
#include <linux/regmap.h>
#include <linux/soundwire/soundwire.h>
#include <linux/module.h>
@@ -20,16 +23,22 @@
static int regmap_swr_gather_write(void *context,
const void *reg, size_t reg_size,
- const void *val, size_t val_size)
+ const void *val, size_t val_len)
{
struct device *dev = context;
struct swr_device *swr = to_swr_device(dev);
struct regmap *map = dev_get_regmap(dev, NULL);
- size_t addr_bytes = map->format.reg_bytes;
- int ret = 0;
- int i;
- u32 reg_addr = 0;
+ size_t addr_bytes;
+ size_t val_bytes;
+ int i, ret = 0;
+ u16 reg_addr = 0;
+ u8 *value;
+ if (map == NULL) {
+ dev_err(dev, "%s: regmap is NULL\n", __func__);
+ return -EINVAL;
+ }
+ addr_bytes = map->format.reg_bytes;
if (swr == NULL) {
dev_err(dev, "%s: swr device is NULL\n", __func__);
return -EINVAL;
@@ -40,29 +49,107 @@
return -EINVAL;
}
reg_addr = *(u16 *)reg;
- for (i = 0; i < val_size; i++) {
- ret = swr_write(swr, swr->dev_num, (reg_addr+i),
- (u32 *)(val+i));
+ val_bytes = map->format.val_bytes;
+ /* val_len = val_bytes * val_count */
+ for (i = 0; i < (val_len / val_bytes); i++) {
+ value = (u8 *)val + (val_bytes * i);
+ ret = swr_write(swr, swr->dev_num, (reg_addr + i), value);
if (ret < 0) {
dev_err(dev, "%s: write reg 0x%x failed, err %d\n",
- __func__, (reg_addr+i), ret);
+ __func__, (reg_addr + i), ret);
break;
}
}
return ret;
}
+static int regmap_swr_raw_multi_reg_write(void *context, const void *data,
+ size_t count)
+{
+ struct device *dev = context;
+ struct swr_device *swr = to_swr_device(dev);
+ struct regmap *map = dev_get_regmap(dev, NULL);
+ size_t addr_bytes;
+ size_t val_bytes;
+ size_t pad_bytes;
+ size_t num_regs;
+ int i = 0;
+ int ret = 0;
+ u16 *reg;
+ u8 *val;
+ u8 *buf;
+
+ if (swr == NULL) {
+ dev_err(dev, "%s: swr device is NULL\n", __func__);
+ return -EINVAL;
+ }
+
+ if (map == NULL) {
+ dev_err(dev, "%s: regmap is NULL\n", __func__);
+ return -EINVAL;
+ }
+
+ addr_bytes = map->format.reg_bytes;
+ val_bytes = map->format.val_bytes;
+ pad_bytes = map->format.pad_bytes;
+
+ if (addr_bytes + val_bytes + pad_bytes == 0) {
+ dev_err(dev, "%s: sum of addr, value and pad is 0\n", __func__);
+ return -EINVAL;
+ }
+ num_regs = count / (addr_bytes + val_bytes + pad_bytes);
+
+ reg = kcalloc(num_regs, sizeof(u16), GFP_KERNEL);
+ if (!reg)
+ return -ENOMEM;
+
+ val = kcalloc(num_regs, sizeof(u8), GFP_KERNEL);
+ if (!val) {
+ ret = -ENOMEM;
+ goto mem_fail;
+ }
+
+ buf = (u8 *)data;
+ for (i = 0; i < num_regs; i++) {
+ reg[i] = *(u16 *)buf;
+ buf += (map->format.reg_bytes + map->format.pad_bytes);
+ val[i] = *buf;
+ buf += map->format.val_bytes;
+ }
+ ret = swr_bulk_write(swr, swr->dev_num, reg, val, num_regs);
+ if (ret)
+ dev_err(dev, "%s: multi reg write failed\n", __func__);
+
+ kfree(val);
+mem_fail:
+ kfree(reg);
+ return ret;
+}
+
static int regmap_swr_write(void *context, const void *data, size_t count)
{
struct device *dev = context;
struct regmap *map = dev_get_regmap(dev, NULL);
- size_t addr_bytes = map->format.reg_bytes;
+ size_t addr_bytes;
+ size_t val_bytes;
+ size_t pad_bytes;
+
+ if (map == NULL) {
+ dev_err(dev, "%s: regmap is NULL\n", __func__);
+ return -EINVAL;
+ }
+ addr_bytes = map->format.reg_bytes;
+ val_bytes = map->format.val_bytes;
+ pad_bytes = map->format.pad_bytes;
WARN_ON(count < addr_bytes);
- return regmap_swr_gather_write(context, data, addr_bytes,
- (data + addr_bytes),
- (count - addr_bytes));
+ if (count > (addr_bytes + val_bytes + pad_bytes))
+ return regmap_swr_raw_multi_reg_write(context, data, count);
+ else
+ return regmap_swr_gather_write(context, data, addr_bytes,
+ (data + addr_bytes),
+ (count - addr_bytes));
}
static int regmap_swr_read(void *context,
@@ -72,10 +159,15 @@
struct device *dev = context;
struct swr_device *swr = to_swr_device(dev);
struct regmap *map = dev_get_regmap(dev, NULL);
- size_t addr_bytes = map->format.reg_bytes;
+ size_t addr_bytes;
int ret = 0;
- u32 reg_addr = 0;
+ u16 reg_addr = 0;
+ if (map == NULL) {
+ dev_err(dev, "%s: regmap is NULL\n", __func__);
+ return -EINVAL;
+ }
+ addr_bytes = map->format.reg_bytes;
if (swr == NULL) {
dev_err(dev, "%s: swr is NULL\n", __func__);
return -EINVAL;
@@ -85,7 +177,7 @@
__func__, reg_size);
return -EINVAL;
}
- reg_addr = *(u32 *)reg;
+ reg_addr = *(u16 *)reg;
ret = swr_read(swr, swr->dev_num, reg_addr, val, val_size);
if (ret < 0)
dev_err(dev, "%s: codec reg 0x%x read failed %d\n",
diff --git a/drivers/block/nbd.c b/drivers/block/nbd.c
index 7a10487..c9441f9 100644
--- a/drivers/block/nbd.c
+++ b/drivers/block/nbd.c
@@ -54,7 +54,7 @@
struct mutex tx_lock;
struct gendisk *disk;
- int blksize;
+ loff_t blksize;
loff_t bytesize;
/* protects initialization and shutdown of the socket */
@@ -126,7 +126,7 @@
}
static int nbd_size_set(struct nbd_device *nbd, struct block_device *bdev,
- int blocksize, int nr_blocks)
+ loff_t blocksize, loff_t nr_blocks)
{
int ret;
@@ -135,7 +135,7 @@
return ret;
nbd->blksize = blocksize;
- nbd->bytesize = (loff_t)blocksize * (loff_t)nr_blocks;
+ nbd->bytesize = blocksize * nr_blocks;
nbd_size_update(nbd, bdev);
@@ -648,7 +648,7 @@
case NBD_SET_SIZE:
return nbd_size_set(nbd, bdev, nbd->blksize,
- arg / nbd->blksize);
+ div_s64(arg, nbd->blksize));
case NBD_SET_SIZE_BLOCKS:
return nbd_size_set(nbd, bdev, nbd->blksize, arg);
@@ -817,7 +817,7 @@
debugfs_create_file("tasks", 0444, dir, nbd, &nbd_dbg_tasks_ops);
debugfs_create_u64("size_bytes", 0444, dir, &nbd->bytesize);
debugfs_create_u32("timeout", 0444, dir, &nbd->tag_set.timeout);
- debugfs_create_u32("blocksize", 0444, dir, &nbd->blksize);
+ debugfs_create_u64("blocksize", 0444, dir, &nbd->blksize);
debugfs_create_file("flags", 0444, dir, nbd, &nbd_dbg_flags_ops);
return 0;
diff --git a/drivers/block/zram/zram_drv.c b/drivers/block/zram/zram_drv.c
index d2ef51c..c9914d65 100644
--- a/drivers/block/zram/zram_drv.c
+++ b/drivers/block/zram/zram_drv.c
@@ -582,13 +582,13 @@
if (!handle || zram_test_flag(meta, index, ZRAM_ZERO)) {
bit_spin_unlock(ZRAM_ACCESS, &meta->table[index].value);
- clear_page(mem);
+ memset(mem, 0, PAGE_SIZE);
return 0;
}
cmem = zs_map_object(meta->mem_pool, handle, ZS_MM_RO);
if (size == PAGE_SIZE) {
- copy_page(mem, cmem);
+ memcpy(mem, cmem, PAGE_SIZE);
} else {
struct zcomp_strm *zstrm = zcomp_stream_get(zram->comp);
@@ -780,7 +780,7 @@
if ((clen == PAGE_SIZE) && !is_partial_io(bvec)) {
src = kmap_atomic(page);
- copy_page(cmem, src);
+ memcpy(cmem, src, PAGE_SIZE);
kunmap_atomic(src);
} else {
memcpy(cmem, src, clen);
diff --git a/drivers/char/diag/diag_dci.c b/drivers/char/diag/diag_dci.c
index 9c26f87..e907d0d 100644
--- a/drivers/char/diag/diag_dci.c
+++ b/drivers/char/diag/diag_dci.c
@@ -773,6 +773,7 @@
if (*buf != 0x80) {
list_del(&entry->track);
kfree(entry);
+ entry = NULL;
return 1;
}
@@ -790,6 +791,7 @@
if (delayed_rsp_id == 0) {
list_del(&entry->track);
kfree(entry);
+ entry = NULL;
return 1;
}
@@ -803,6 +805,7 @@
if (rsp_count > 0 && rsp_count < 0x1000) {
list_del(&entry->track);
kfree(entry);
+ entry = NULL;
return 1;
}
@@ -1447,6 +1450,7 @@
dci_ops_tbl[proc].peripheral_status &= ~peripheral_mask;
/* Notify the DCI process that the peripheral DCI Channel is up */
+ mutex_lock(&driver->dci_mutex);
list_for_each_safe(start, temp, &driver->dci_client_list) {
entry = list_entry(start, struct diag_dci_client_tbl, track);
if (entry->client_info.token != proc)
@@ -1469,6 +1473,7 @@
info.si_int, stat);
}
}
+ mutex_unlock(&driver->dci_mutex);
}
static int diag_send_dci_pkt(struct diag_cmd_reg_t *entry,
@@ -1942,6 +1947,7 @@
reg_entry.cmd_code_hi = header->subsys_cmd_code;
reg_entry.cmd_code_lo = header->subsys_cmd_code;
+ mutex_lock(&driver->cmd_reg_mutex);
temp_entry = diag_cmd_search(®_entry, ALL_PROC);
if (temp_entry) {
reg_item = container_of(temp_entry, struct diag_cmd_reg_t,
@@ -1953,6 +1959,7 @@
reg_entry.cmd_code, reg_entry.subsys_id,
reg_entry.cmd_code_hi);
}
+ mutex_unlock(&driver->cmd_reg_mutex);
return ret;
}
@@ -2684,10 +2691,12 @@
err:
pr_err("diag: Could not initialize diag DCI buffers");
kfree(driver->apps_dci_buf);
+ driver->apps_dci_buf = NULL;
if (driver->diag_dci_wq)
destroy_workqueue(driver->diag_dci_wq);
kfree(partial_pkt.data);
+ partial_pkt.data = NULL;
mutex_destroy(&driver->dci_mutex);
mutex_destroy(&dci_log_mask_mutex);
mutex_destroy(&dci_event_mask_mutex);
@@ -2707,7 +2716,9 @@
void diag_dci_exit(void)
{
kfree(partial_pkt.data);
+ partial_pkt.data = NULL;
kfree(driver->apps_dci_buf);
+ driver->apps_dci_buf = NULL;
mutex_destroy(&driver->dci_mutex);
mutex_destroy(&dci_log_mask_mutex);
mutex_destroy(&dci_event_mask_mutex);
@@ -2914,22 +2925,30 @@
mutex_destroy(&proc_buf->health_mutex);
if (proc_buf->buf_primary) {
kfree(proc_buf->buf_primary->data);
+ proc_buf->buf_primary->data = NULL;
mutex_destroy(
&proc_buf->buf_primary->data_mutex);
}
kfree(proc_buf->buf_primary);
+ proc_buf->buf_primary = NULL;
if (proc_buf->buf_cmd) {
kfree(proc_buf->buf_cmd->data);
+ proc_buf->buf_cmd->data = NULL;
mutex_destroy(
&proc_buf->buf_cmd->data_mutex);
}
kfree(proc_buf->buf_cmd);
+ proc_buf->buf_cmd = NULL;
}
}
kfree(new_entry->dci_event_mask);
+ new_entry->dci_event_mask = NULL;
kfree(new_entry->dci_log_mask);
+ new_entry->dci_log_mask = NULL;
kfree(new_entry->buffers);
+ new_entry->buffers = NULL;
kfree(new_entry);
+ new_entry = NULL;
}
mutex_unlock(&driver->dci_mutex);
return DIAG_DCI_NO_REG;
@@ -2960,6 +2979,7 @@
* masks and send the masks to peripherals
*/
kfree(entry->dci_log_mask);
+ entry->dci_log_mask = NULL;
diag_dci_invalidate_cumulative_log_mask(token);
if (token == DCI_LOCAL_PROC)
diag_update_userspace_clients(DCI_LOG_MASKS_TYPE);
@@ -2967,6 +2987,7 @@
if (ret != DIAG_DCI_NO_ERROR)
return ret;
kfree(entry->dci_event_mask);
+ entry->dci_event_mask = NULL;
diag_dci_invalidate_cumulative_event_mask(token);
if (token == DCI_LOCAL_PROC)
diag_update_userspace_clients(DCI_EVENT_MASKS_TYPE);
@@ -2981,6 +3002,7 @@
if (!list_empty(&req_entry->track))
list_del(&req_entry->track);
kfree(req_entry);
+ req_entry = NULL;
}
}
@@ -2996,6 +3018,7 @@
buf_entry->data = NULL;
mutex_unlock(&buf_entry->data_mutex);
kfree(buf_entry);
+ buf_entry = NULL;
} else if (buf_entry->buf_type == DCI_BUF_CMD) {
peripheral = buf_entry->data_source;
if (peripheral == APPS_DATA)
@@ -3022,14 +3045,17 @@
mutex_unlock(&buf_entry->data_mutex);
mutex_destroy(&buf_entry->data_mutex);
kfree(buf_entry);
+ buf_entry = NULL;
}
mutex_lock(&proc_buf->buf_primary->data_mutex);
kfree(proc_buf->buf_primary->data);
+ proc_buf->buf_primary->data = NULL;
mutex_unlock(&proc_buf->buf_primary->data_mutex);
mutex_lock(&proc_buf->buf_cmd->data_mutex);
kfree(proc_buf->buf_cmd->data);
+ proc_buf->buf_cmd->data = NULL;
mutex_unlock(&proc_buf->buf_cmd->data_mutex);
mutex_destroy(&proc_buf->health_mutex);
@@ -3037,13 +3063,17 @@
mutex_destroy(&proc_buf->buf_cmd->data_mutex);
kfree(proc_buf->buf_primary);
+ proc_buf->buf_primary = NULL;
kfree(proc_buf->buf_cmd);
+ proc_buf->buf_cmd = NULL;
mutex_unlock(&proc_buf->buf_mutex);
}
mutex_destroy(&entry->write_buf_mutex);
kfree(entry->buffers);
+ entry->buffers = NULL;
kfree(entry);
+ entry = NULL;
if (driver->num_dci_client == 0) {
diag_update_proc_vote(DIAG_PROC_DCI, VOTE_DOWN, token);
diff --git a/drivers/char/diag/diag_memorydevice.c b/drivers/char/diag/diag_memorydevice.c
index 558e362..13ad402 100644
--- a/drivers/char/diag/diag_memorydevice.c
+++ b/drivers/char/diag/diag_memorydevice.c
@@ -354,8 +354,8 @@
ch->tbl[j].buf = NULL;
ch->tbl[j].len = 0;
ch->tbl[j].ctx = 0;
- spin_lock_init(&(ch->lock));
}
+ spin_lock_init(&(ch->lock));
}
return 0;
diff --git a/drivers/char/diag/diag_usb.c b/drivers/char/diag/diag_usb.c
index ac8a6d0..1cf7f52 100644
--- a/drivers/char/diag/diag_usb.c
+++ b/drivers/char/diag/diag_usb.c
@@ -14,6 +14,7 @@
#include <linux/init.h>
#include <linux/module.h>
#include <linux/device.h>
+#include <linux/kernel.h>
#include <linux/err.h>
#include <linux/sched.h>
#include <linux/ratelimit.h>
@@ -218,7 +219,8 @@
if (!ch)
return;
- if (!atomic_read(&ch->connected) && driver->usb_connected)
+ if (!atomic_read(&ch->connected) &&
+ driver->usb_connected && diag_mask_param())
diag_clear_masks(NULL);
if (ch && ch->ops && ch->ops->close)
diff --git a/drivers/char/diag/diagchar.h b/drivers/char/diag/diagchar.h
index ea380fb..d3dde50 100644
--- a/drivers/char/diag/diagchar.h
+++ b/drivers/char/diag/diagchar.h
@@ -505,6 +505,7 @@
int ref_count;
int mask_clear;
struct mutex diag_maskclear_mutex;
+ struct mutex diag_notifier_mutex;
struct mutex diagchar_mutex;
struct mutex diag_file_mutex;
wait_queue_head_t wait_q;
@@ -547,7 +548,7 @@
struct mutex diag_id_mutex;
struct mutex cmd_reg_mutex;
uint32_t cmd_reg_count;
- struct mutex diagfwd_channel_mutex;
+ struct mutex diagfwd_channel_mutex[NUM_PERIPHERALS];
/* Sizes that reflect memory pool sizes */
unsigned int poolsize;
unsigned int poolsize_hdlc;
@@ -666,6 +667,7 @@
void diag_cmd_remove_reg_by_pid(int pid);
void diag_cmd_remove_reg_by_proc(int proc);
int diag_cmd_chk_polling(struct diag_cmd_reg_entry_t *entry);
+int diag_mask_param(void);
void diag_clear_masks(struct diag_md_session_t *info);
void diag_record_stats(int type, int flag);
diff --git a/drivers/char/diag/diagchar_core.c b/drivers/char/diag/diagchar_core.c
index c44a9ea..128d6ce 100644
--- a/drivers/char/diag/diagchar_core.c
+++ b/drivers/char/diag/diagchar_core.c
@@ -143,6 +143,14 @@
static struct timer_list drain_timer;
static int timer_in_progress;
+/*
+ * Diag Mask clear variable
+ * Used for clearing masks upon
+ * USB disconnection and stopping ODL
+ */
+static int diag_mask_clear_param = 1;
+module_param(diag_mask_clear_param, int, 0644);
+
struct diag_apps_data_t {
void *buf;
uint32_t len;
@@ -388,7 +396,10 @@
return ret;
}
-
+int diag_mask_param(void)
+{
+ return diag_mask_clear_param;
+}
void diag_clear_masks(struct diag_md_session_t *info)
{
int ret;
@@ -421,14 +432,17 @@
if (!session_info)
return;
- diag_clear_masks(session_info);
+ if (diag_mask_clear_param)
+ diag_clear_masks(session_info);
mutex_lock(&driver->diag_maskclear_mutex);
driver->mask_clear = 1;
mutex_unlock(&driver->diag_maskclear_mutex);
+ mutex_lock(&driver->diagchar_mutex);
session_peripheral_mask = session_info->peripheral_mask;
diag_md_session_close(session_info);
+ mutex_unlock(&driver->diagchar_mutex);
for (i = 0; i < NUM_MD_SESSIONS; i++)
if (MD_PERIPHERAL_MASK(i) & session_peripheral_mask)
diag_mux_close_peripheral(DIAG_LOCAL_PROC, i);
@@ -701,7 +715,7 @@
list_for_each_safe(start, temp, &driver->cmd_reg_list) {
item = list_entry(start, struct diag_cmd_reg_t, link);
- if (item == NULL || &item->entry == NULL) {
+ if (&item->entry == NULL) {
pr_err("diag: In %s, unable to search command\n",
__func__);
return NULL;
@@ -3402,7 +3416,7 @@
static int __init diagchar_init(void)
{
dev_t dev;
- int ret;
+ int ret, i;
pr_debug("diagfwd initializing ..\n");
ret = 0;
@@ -3445,10 +3459,12 @@
mutex_init(&driver->hdlc_disable_mutex);
mutex_init(&driver->diagchar_mutex);
mutex_init(&driver->diag_maskclear_mutex);
+ mutex_init(&driver->diag_notifier_mutex);
mutex_init(&driver->diag_file_mutex);
mutex_init(&driver->delayed_rsp_mutex);
mutex_init(&apps_data_mutex);
- mutex_init(&driver->diagfwd_channel_mutex);
+ for (i = 0; i < NUM_PERIPHERALS; i++)
+ mutex_init(&driver->diagfwd_channel_mutex[i]);
init_waitqueue_head(&driver->wait_q);
INIT_WORK(&(driver->diag_drain_work), diag_drain_work_fn);
INIT_WORK(&(driver->update_user_clients),
diff --git a/drivers/char/diag/diagfwd.c b/drivers/char/diag/diagfwd.c
index f9dc670d..cd49f00 100644
--- a/drivers/char/diag/diagfwd.c
+++ b/drivers/char/diag/diagfwd.c
@@ -1303,6 +1303,8 @@
static int diagfwd_mux_close(int id, int mode)
{
+ uint8_t i;
+
switch (mode) {
case DIAG_USB_MODE:
driver->usb_connected = 0;
@@ -1323,10 +1325,23 @@
*/
} else {
/*
- * With clearing of masks on ODL exit and
- * USB disconnection, closing of the channel is
- * not needed.This enables read and drop of stale packets.
+ * With sysfs parameter to clear masks set,
+ * peripheral masks are cleared on ODL exit and
+ * USB disconnection and buffers are not marked busy.
+ * This enables read and drop of stale packets.
+ *
+ * With sysfs parameter to clear masks cleared,
+ * masks are not cleared and buffers are to be marked
+ * busy to ensure traffic generated by peripheral
+ * are not read
*/
+ if (!(diag_mask_param())) {
+ for (i = 0; i < NUM_PERIPHERALS; i++) {
+ diagfwd_close(i, TYPE_DATA);
+ diagfwd_close(i, TYPE_CMD);
+ }
+ }
+ /* Re enable HDLC encoding */
pr_debug("diag: In %s, re-enabling HDLC encoding\n",
__func__);
mutex_lock(&driver->hdlc_disable_mutex);
diff --git a/drivers/char/diag/diagfwd_cntl.c b/drivers/char/diag/diagfwd_cntl.c
index b262897..e13871e 100644
--- a/drivers/char/diag/diagfwd_cntl.c
+++ b/drivers/char/diag/diagfwd_cntl.c
@@ -359,6 +359,8 @@
feature_mask_len = FEATURE_MASK_LEN;
}
+ diag_cmd_remove_reg_by_proc(peripheral);
+
driver->feature[peripheral].rcvd_feature_mask = 1;
for (i = 0; i < feature_mask_len && read_len < len; i++) {
@@ -660,7 +662,7 @@
if (!new_item)
return -ENOMEM;
kmemleak_not_leak(new_item);
- new_item->process_name = kzalloc(strlen(process_name), GFP_KERNEL);
+ new_item->process_name = kzalloc(strlen(process_name) + 1, GFP_KERNEL);
if (!new_item->process_name) {
kfree(new_item);
new_item = NULL;
diff --git a/drivers/char/diag/diagfwd_peripheral.c b/drivers/char/diag/diagfwd_peripheral.c
index 6685be3..5a8ef04 100644
--- a/drivers/char/diag/diagfwd_peripheral.c
+++ b/drivers/char/diag/diagfwd_peripheral.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2015-2016, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2015-2017, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -436,9 +436,9 @@
fwd_info->inited = 1;
fwd_info->read_bytes = 0;
fwd_info->write_bytes = 0;
- spin_lock_init(&fwd_info->buf_lock);
- spin_lock_init(&fwd_info->write_buf_lock);
+ mutex_init(&fwd_info->buf_mutex);
mutex_init(&fwd_info->data_mutex);
+ spin_lock_init(&fwd_info->write_buf_lock);
}
}
@@ -452,8 +452,8 @@
fwd_info->ch_open = 0;
fwd_info->read_bytes = 0;
fwd_info->write_bytes = 0;
- spin_lock_init(&fwd_info->buf_lock);
spin_lock_init(&fwd_info->write_buf_lock);
+ mutex_init(&fwd_info->buf_mutex);
mutex_init(&fwd_info->data_mutex);
/*
* This state shouldn't be set for Control channels
@@ -646,7 +646,7 @@
}
- mutex_lock(&driver->diagfwd_channel_mutex);
+ mutex_lock(&driver->diagfwd_channel_mutex[peripheral]);
fwd_info = &early_init_info[transport][peripheral];
if (fwd_info->p_ops && fwd_info->p_ops->close)
fwd_info->p_ops->close(fwd_info->ctxt);
@@ -670,7 +670,7 @@
diagfwd_late_open(dest_info);
diagfwd_cntl_open(dest_info);
init_fn(peripheral);
- mutex_unlock(&driver->diagfwd_channel_mutex);
+ mutex_unlock(&driver->diagfwd_channel_mutex[peripheral]);
diagfwd_queue_read(&peripheral_info[TYPE_DATA][peripheral]);
diagfwd_queue_read(&peripheral_info[TYPE_CMD][peripheral]);
}
@@ -1065,7 +1065,6 @@
void diagfwd_buffers_init(struct diagfwd_info *fwd_info)
{
- unsigned long flags;
if (!fwd_info)
return;
@@ -1076,10 +1075,10 @@
return;
}
- spin_lock_irqsave(&fwd_info->buf_lock, flags);
+ mutex_lock(&fwd_info->buf_mutex);
if (!fwd_info->buf_1) {
fwd_info->buf_1 = kzalloc(sizeof(struct diagfwd_buf_t),
- GFP_ATOMIC);
+ GFP_KERNEL);
if (!fwd_info->buf_1)
goto err;
kmemleak_not_leak(fwd_info->buf_1);
@@ -1087,7 +1086,7 @@
if (!fwd_info->buf_1->data) {
fwd_info->buf_1->data = kzalloc(PERIPHERAL_BUF_SZ +
APF_DIAG_PADDING,
- GFP_ATOMIC);
+ GFP_KERNEL);
if (!fwd_info->buf_1->data)
goto err;
fwd_info->buf_1->len = PERIPHERAL_BUF_SZ;
@@ -1099,7 +1098,7 @@
if (fwd_info->type == TYPE_DATA) {
if (!fwd_info->buf_2) {
fwd_info->buf_2 = kzalloc(sizeof(struct diagfwd_buf_t),
- GFP_ATOMIC);
+ GFP_KERNEL);
if (!fwd_info->buf_2)
goto err;
kmemleak_not_leak(fwd_info->buf_2);
@@ -1108,7 +1107,7 @@
if (!fwd_info->buf_2->data) {
fwd_info->buf_2->data = kzalloc(PERIPHERAL_BUF_SZ +
APF_DIAG_PADDING,
- GFP_ATOMIC);
+ GFP_KERNEL);
if (!fwd_info->buf_2->data)
goto err;
fwd_info->buf_2->len = PERIPHERAL_BUF_SZ;
@@ -1124,7 +1123,7 @@
fwd_info->buf_1->data_raw =
kzalloc(PERIPHERAL_BUF_SZ +
APF_DIAG_PADDING,
- GFP_ATOMIC);
+ GFP_KERNEL);
if (!fwd_info->buf_1->data_raw)
goto err;
fwd_info->buf_1->len_raw = PERIPHERAL_BUF_SZ;
@@ -1134,7 +1133,7 @@
fwd_info->buf_2->data_raw =
kzalloc(PERIPHERAL_BUF_SZ +
APF_DIAG_PADDING,
- GFP_ATOMIC);
+ GFP_KERNEL);
if (!fwd_info->buf_2->data_raw)
goto err;
fwd_info->buf_2->len_raw = PERIPHERAL_BUF_SZ;
@@ -1148,7 +1147,7 @@
if (!fwd_info->buf_1->data_raw) {
fwd_info->buf_1->data_raw = kzalloc(PERIPHERAL_BUF_SZ +
APF_DIAG_PADDING,
- GFP_ATOMIC);
+ GFP_KERNEL);
if (!fwd_info->buf_1->data_raw)
goto err;
fwd_info->buf_1->len_raw = PERIPHERAL_BUF_SZ;
@@ -1156,22 +1155,21 @@
}
}
- spin_unlock_irqrestore(&fwd_info->buf_lock, flags);
+ mutex_unlock(&fwd_info->buf_mutex);
return;
err:
- spin_unlock_irqrestore(&fwd_info->buf_lock, flags);
+ mutex_unlock(&fwd_info->buf_mutex);
diagfwd_buffers_exit(fwd_info);
}
static void diagfwd_buffers_exit(struct diagfwd_info *fwd_info)
{
- unsigned long flags;
if (!fwd_info)
return;
- spin_lock_irqsave(&fwd_info->buf_lock, flags);
+ mutex_lock(&fwd_info->buf_mutex);
if (fwd_info->buf_1) {
kfree(fwd_info->buf_1->data);
fwd_info->buf_1->data = NULL;
@@ -1188,7 +1186,7 @@
kfree(fwd_info->buf_2);
fwd_info->buf_2 = NULL;
}
- spin_unlock_irqrestore(&fwd_info->buf_lock, flags);
+ mutex_unlock(&fwd_info->buf_mutex);
}
void diagfwd_write_buffers_init(struct diagfwd_info *fwd_info)
diff --git a/drivers/char/diag/diagfwd_peripheral.h b/drivers/char/diag/diagfwd_peripheral.h
index b8deb38..5884a12 100644
--- a/drivers/char/diag/diagfwd_peripheral.h
+++ b/drivers/char/diag/diagfwd_peripheral.h
@@ -71,8 +71,8 @@
atomic_t opened;
unsigned long read_bytes;
unsigned long write_bytes;
- spinlock_t buf_lock;
spinlock_t write_buf_lock;
+ struct mutex buf_mutex;
struct mutex data_mutex;
void *ctxt;
struct diagfwd_buf_t *buf_1;
diff --git a/drivers/char/diag/diagfwd_socket.c b/drivers/char/diag/diagfwd_socket.c
index 6403abc..af8bf00 100644
--- a/drivers/char/diag/diagfwd_socket.c
+++ b/drivers/char/diag/diagfwd_socket.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2015-2016, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2015-2017, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -34,14 +34,17 @@
#include "diagfwd_socket.h"
#include "diag_ipc_logging.h"
+#include <soc/qcom/subsystem_notif.h>
+#include <soc/qcom/subsystem_restart.h>
+
#define DIAG_SVC_ID 0x1001
#define MODEM_INST_BASE 0
#define LPASS_INST_BASE 64
#define WCNSS_INST_BASE 128
#define SENSORS_INST_BASE 192
-#define WDSP_INST_BASE 256
-#define CDSP_INST_BASE 320
+#define CDSP_INST_BASE 256
+#define WDSP_INST_BASE 320
#define INST_ID_CNTL 0
#define INST_ID_CMD 1
@@ -50,6 +53,7 @@
#define INST_ID_DCI 4
struct diag_cntl_socket_info *cntl_socket;
+static uint64_t bootup_req[NUM_SOCKET_SUBSYSTEMS];
struct diag_socket_info socket_data[NUM_PERIPHERALS] = {
{
@@ -287,13 +291,6 @@
spin_unlock_irqrestore(&info->lock, flags);
diag_ws_on_notify();
- /*
- * Initialize read buffers for the servers. The servers must read data
- * first to get the address of its clients.
- */
- if (!atomic_read(&info->opened) && info->port_type == PORT_TYPE_SERVER)
- diagfwd_buffers_init(info->fwd_ctxt);
-
queue_work(info->wq, &(info->read_work));
wake_up_interruptible(&info->read_wait_q);
}
@@ -422,7 +419,7 @@
return;
}
__socket_open_channel(info);
- DIAG_LOG(DIAG_DEBUG_PERIPHERALS, "%s exiting\n", info->name);
+ DIAG_LOG(DIAG_DEBUG_PERIPHERALS, "%s opened client\n", info->name);
}
static void socket_open_server(struct diag_socket_info *info)
@@ -498,6 +495,13 @@
if (!atomic_read(&info->opened))
return;
+ if (bootup_req[info->peripheral] == PEPIPHERAL_SSR_UP) {
+ DIAG_LOG(DIAG_DEBUG_PERIPHERALS,
+ "diag: %s is up, stopping cleanup: bootup_req = %d\n",
+ info->name, (int)bootup_req[info->peripheral]);
+ return;
+ }
+
memset(&info->remote_addr, 0, sizeof(struct sockaddr_msm_ipc));
diagfwd_channel_close(info->fwd_ctxt);
@@ -614,7 +618,9 @@
case CNTL_CMD_REMOVE_CLIENT:
DIAG_LOG(DIAG_DEBUG_PERIPHERALS, "%s received remove client\n",
info->name);
+ mutex_lock(&driver->diag_notifier_mutex);
socket_close_channel(info);
+ mutex_unlock(&driver->diag_notifier_mutex);
break;
default:
return -EINVAL;
@@ -623,6 +629,25 @@
return 0;
}
+static int restart_notifier_cb(struct notifier_block *this,
+ unsigned long code,
+ void *data);
+
+struct restart_notifier_block {
+ unsigned int processor;
+ char *name;
+ struct notifier_block nb;
+};
+
+static struct restart_notifier_block restart_notifiers[] = {
+ {SOCKET_MODEM, "modem", .nb.notifier_call = restart_notifier_cb},
+ {SOCKET_ADSP, "adsp", .nb.notifier_call = restart_notifier_cb},
+ {SOCKET_WCNSS, "wcnss", .nb.notifier_call = restart_notifier_cb},
+ {SOCKET_SLPI, "slpi", .nb.notifier_call = restart_notifier_cb},
+ {SOCKET_CDSP, "cdsp", .nb.notifier_call = restart_notifier_cb},
+};
+
+
static void cntl_socket_read_work_fn(struct work_struct *work)
{
union cntl_port_msg msg;
@@ -630,7 +655,6 @@
struct kvec iov = { 0 };
struct msghdr read_msg = { 0 };
-
if (!cntl_socket)
return;
@@ -679,6 +703,9 @@
if (!info)
return;
+ if (!atomic_read(&info->opened) && info->port_type == PORT_TYPE_SERVER)
+ diagfwd_buffers_init(info->fwd_ctxt);
+
diagfwd_channel_read(info->fwd_ctxt);
}
@@ -847,8 +874,11 @@
int diag_socket_init(void)
{
int err = 0;
+ int i;
int peripheral = 0;
+ void *handle;
struct diag_socket_info *info = NULL;
+ struct restart_notifier_block *nb;
for (peripheral = 0; peripheral < NUM_PERIPHERALS; peripheral++) {
info = &socket_cntl[peripheral];
@@ -869,6 +899,17 @@
goto fail;
}
+ for (i = 0; i < ARRAY_SIZE(restart_notifiers); i++) {
+ nb = &restart_notifiers[i];
+ if (nb) {
+ handle = subsys_notif_register_notifier(nb->name,
+ &nb->nb);
+ DIAG_LOG(DIAG_DEBUG_PERIPHERALS,
+ "%s: registering notifier for '%s', handle=%p\n",
+ __func__, nb->name, handle);
+ }
+ }
+
register_ipcrtr_af_init_notifier(&socket_notify);
fail:
return err;
@@ -904,6 +945,65 @@
return 0;
}
+static int restart_notifier_cb(struct notifier_block *this, unsigned long code,
+ void *_cmd)
+{
+ struct restart_notifier_block *notifier;
+
+ notifier = container_of(this,
+ struct restart_notifier_block, nb);
+ if (!notifier) {
+ DIAG_LOG(DIAG_DEBUG_PERIPHERALS,
+ "diag: %s: invalid notifier block\n", __func__);
+ return NOTIFY_DONE;
+ }
+
+ mutex_lock(&driver->diag_notifier_mutex);
+ DIAG_LOG(DIAG_DEBUG_PERIPHERALS,
+ "%s: ssr for processor %d ('%s')\n",
+ __func__, notifier->processor, notifier->name);
+
+ switch (code) {
+
+ case SUBSYS_BEFORE_SHUTDOWN:
+ DIAG_LOG(DIAG_DEBUG_PERIPHERALS,
+ "diag: %s: SUBSYS_BEFORE_SHUTDOWN\n", __func__);
+ bootup_req[notifier->processor] = PEPIPHERAL_SSR_DOWN;
+ break;
+
+ case SUBSYS_AFTER_SHUTDOWN:
+ DIAG_LOG(DIAG_DEBUG_PERIPHERALS,
+ "diag: %s: SUBSYS_AFTER_SHUTDOWN\n", __func__);
+ break;
+
+ case SUBSYS_BEFORE_POWERUP:
+ DIAG_LOG(DIAG_DEBUG_PERIPHERALS,
+ "diag: %s: SUBSYS_BEFORE_POWERUP\n", __func__);
+ break;
+
+ case SUBSYS_AFTER_POWERUP:
+ DIAG_LOG(DIAG_DEBUG_PERIPHERALS,
+ "diag: %s: SUBSYS_AFTER_POWERUP\n", __func__);
+ if (!bootup_req[notifier->processor]) {
+ bootup_req[notifier->processor] = PEPIPHERAL_SSR_DOWN;
+ break;
+ }
+ bootup_req[notifier->processor] = PEPIPHERAL_SSR_UP;
+ break;
+
+ default:
+ DIAG_LOG(DIAG_DEBUG_PERIPHERALS,
+ "diag: code: %lu\n", code);
+ break;
+ }
+ mutex_unlock(&driver->diag_notifier_mutex);
+ DIAG_LOG(DIAG_DEBUG_PERIPHERALS,
+ "diag: bootup_req[%s] = %d\n",
+ notifier->name, (int)bootup_req[notifier->processor]);
+
+ return NOTIFY_DONE;
+}
+
int diag_socket_init_peripheral(uint8_t peripheral)
{
struct diag_socket_info *info = NULL;
@@ -986,9 +1086,9 @@
(info->data_ready > 0) || (!info->hdl) ||
(atomic_read(&info->diag_state) == 0));
if (err) {
- mutex_lock(&driver->diagfwd_channel_mutex);
+ mutex_lock(&driver->diagfwd_channel_mutex[info->peripheral]);
diagfwd_channel_read_done(info->fwd_ctxt, buf, 0);
- mutex_unlock(&driver->diagfwd_channel_mutex);
+ mutex_unlock(&driver->diagfwd_channel_mutex[info->peripheral]);
return -ERESTARTSYS;
}
@@ -1000,9 +1100,9 @@
DIAG_LOG(DIAG_DEBUG_PERIPHERALS,
"%s closing read thread. diag state is closed\n",
info->name);
- mutex_lock(&driver->diagfwd_channel_mutex);
+ mutex_lock(&driver->diagfwd_channel_mutex[info->peripheral]);
diagfwd_channel_read_done(info->fwd_ctxt, buf, 0);
- mutex_unlock(&driver->diagfwd_channel_mutex);
+ mutex_unlock(&driver->diagfwd_channel_mutex[info->peripheral]);
return 0;
}
@@ -1069,10 +1169,10 @@
if (total_recd > 0) {
DIAG_LOG(DIAG_DEBUG_PERIPHERALS, "%s read total bytes: %d\n",
info->name, total_recd);
- mutex_lock(&driver->diagfwd_channel_mutex);
+ mutex_lock(&driver->diagfwd_channel_mutex[info->peripheral]);
err = diagfwd_channel_read_done(info->fwd_ctxt,
buf, total_recd);
- mutex_unlock(&driver->diagfwd_channel_mutex);
+ mutex_unlock(&driver->diagfwd_channel_mutex[info->peripheral]);
if (err)
goto fail;
} else {
@@ -1085,9 +1185,9 @@
return 0;
fail:
- mutex_lock(&driver->diagfwd_channel_mutex);
+ mutex_lock(&driver->diagfwd_channel_mutex[info->peripheral]);
diagfwd_channel_read_done(info->fwd_ctxt, buf, 0);
- mutex_unlock(&driver->diagfwd_channel_mutex);
+ mutex_unlock(&driver->diagfwd_channel_mutex[info->peripheral]);
return -EIO;
}
diff --git a/drivers/char/diag/diagfwd_socket.h b/drivers/char/diag/diagfwd_socket.h
index a2b922a..a9487b1 100644
--- a/drivers/char/diag/diagfwd_socket.h
+++ b/drivers/char/diag/diagfwd_socket.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2015, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2015-2016, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -24,10 +24,24 @@
#define PORT_TYPE_SERVER 0
#define PORT_TYPE_CLIENT 1
+#define PEPIPHERAL_AFTER_BOOT 0
+#define PEPIPHERAL_SSR_DOWN 1
+#define PEPIPHERAL_SSR_UP 2
+
#define CNTL_CMD_NEW_SERVER 4
#define CNTL_CMD_REMOVE_SERVER 5
#define CNTL_CMD_REMOVE_CLIENT 6
+enum {
+ SOCKET_MODEM,
+ SOCKET_ADSP,
+ SOCKET_WCNSS,
+ SOCKET_SLPI,
+ SOCKET_CDSP,
+ SOCKET_APPS,
+ NUM_SOCKET_SUBSYSTEMS,
+};
+
struct diag_socket_info {
uint8_t peripheral;
uint8_t type;
diff --git a/drivers/char/hw_random/Kconfig b/drivers/char/hw_random/Kconfig
index 200dab5..18849f4 100644
--- a/drivers/char/hw_random/Kconfig
+++ b/drivers/char/hw_random/Kconfig
@@ -337,7 +337,6 @@
config HW_RANDOM_MSM
tristate "Qualcomm SoCs Random Number Generator support"
depends on HW_RANDOM && ARCH_QCOM
- default HW_RANDOM
---help---
This driver provides kernel-side support for the Random Number
Generator hardware found on Qualcomm SoCs.
@@ -347,6 +346,20 @@
If unsure, say Y.
+config HW_RANDOM_MSM_LEGACY
+ tristate "QTI MSM Random Number Generator support (LEGACY)"
+ depends on HW_RANDOM && ARCH_QCOM
+ select CRYPTO_AES
+ select CRYPTO_ECB
+ ---help---
+ This driver provides kernel-side support for the Random Number
+ Generator hardware found on QTI MSM SoCs.
+
+ To compile this driver as a module, choose M here: the
+ module will be called msm_rng.
+
+ If unsure, say Y.
+
config HW_RANDOM_ST
tristate "ST Microelectronics HW Random Number Generator support"
depends on HW_RANDOM && ARCH_STI
diff --git a/drivers/char/hw_random/Makefile b/drivers/char/hw_random/Makefile
index 5f52b1e..637adb5 100644
--- a/drivers/char/hw_random/Makefile
+++ b/drivers/char/hw_random/Makefile
@@ -30,6 +30,7 @@
obj-$(CONFIG_HW_RANDOM_BCM2835) += bcm2835-rng.o
obj-$(CONFIG_HW_RANDOM_IPROC_RNG200) += iproc-rng200.o
obj-$(CONFIG_HW_RANDOM_MSM) += msm-rng.o
+obj-$(CONFIG_HW_RANDOM_MSM_LEGACY) += msm_rng.o
obj-$(CONFIG_HW_RANDOM_ST) += st-rng.o
obj-$(CONFIG_HW_RANDOM_XGENE) += xgene-rng.o
obj-$(CONFIG_HW_RANDOM_STM32) += stm32-rng.o
diff --git a/drivers/char/hw_random/msm_rng.c b/drivers/char/hw_random/msm_rng.c
new file mode 100644
index 0000000..7641a6a
--- /dev/null
+++ b/drivers/char/hw_random/msm_rng.c
@@ -0,0 +1,481 @@
+/*
+ * Copyright (c) 2011-2013, 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/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/device.h>
+#include <linux/platform_device.h>
+#include <linux/hw_random.h>
+#include <linux/clk.h>
+#include <linux/slab.h>
+#include <linux/io.h>
+#include <linux/err.h>
+#include <linux/types.h>
+#include <soc/qcom/socinfo.h>
+#include <linux/msm-bus.h>
+#include <linux/qrng.h>
+#include <linux/fs.h>
+#include <linux/cdev.h>
+#include <linux/delay.h>
+#include <linux/crypto.h>
+#include <crypto/internal/rng.h>
+
+#include <linux/platform_data/qcom_crypto_device.h>
+
+
+
+#define DRIVER_NAME "msm_rng"
+
+/* Device specific register offsets */
+#define PRNG_DATA_OUT_OFFSET 0x0000
+#define PRNG_STATUS_OFFSET 0x0004
+#define PRNG_LFSR_CFG_OFFSET 0x0100
+#define PRNG_CONFIG_OFFSET 0x0104
+
+/* Device specific register masks and config values */
+#define PRNG_LFSR_CFG_MASK 0xFFFF0000
+#define PRNG_LFSR_CFG_CLOCKS 0x0000DDDD
+#define PRNG_CONFIG_MASK 0xFFFFFFFD
+#define PRNG_HW_ENABLE 0x00000002
+
+#define MAX_HW_FIFO_DEPTH 16 /* FIFO is 16 words deep */
+#define MAX_HW_FIFO_SIZE (MAX_HW_FIFO_DEPTH * 4) /* FIFO is 32 bits wide */
+
+struct msm_rng_device {
+ struct platform_device *pdev;
+ void __iomem *base;
+ struct clk *prng_clk;
+ uint32_t qrng_perf_client;
+ struct mutex rng_lock;
+};
+
+struct msm_rng_device msm_rng_device_info;
+static struct msm_rng_device *msm_rng_dev_cached;
+struct mutex cached_rng_lock;
+static long msm_rng_ioctl(struct file *filp, unsigned int cmd,
+ unsigned long arg)
+{
+ long ret = 0;
+
+ switch (cmd) {
+ case QRNG_IOCTL_RESET_BUS_BANDWIDTH:
+ pr_info("calling msm_rng_bus_scale(LOW)\n");
+ ret = msm_bus_scale_client_update_request(
+ msm_rng_device_info.qrng_perf_client, 0);
+ if (ret)
+ pr_err("failed qrng_reset_bus_bw, ret = %ld\n", ret);
+ break;
+ default:
+ pr_err("Unsupported IOCTL call");
+ break;
+ }
+ return ret;
+}
+
+/*
+ *
+ * This function calls hardware random bit generator directory and retuns it
+ * back to caller
+ *
+ */
+static int msm_rng_direct_read(struct msm_rng_device *msm_rng_dev,
+ void *data, size_t max)
+{
+ struct platform_device *pdev;
+ void __iomem *base;
+ size_t currsize = 0;
+ u32 val;
+ u32 *retdata = data;
+ int ret;
+ int failed = 0;
+
+ pdev = msm_rng_dev->pdev;
+ base = msm_rng_dev->base;
+
+ /* no room for word data */
+ if (max < 4)
+ return 0;
+
+ mutex_lock(&msm_rng_dev->rng_lock);
+
+ if (msm_rng_dev->qrng_perf_client) {
+ ret = msm_bus_scale_client_update_request(
+ msm_rng_dev->qrng_perf_client, 1);
+ if (ret)
+ pr_err("bus_scale_client_update_req failed!\n");
+ }
+ /* enable PRNG clock */
+ ret = clk_prepare_enable(msm_rng_dev->prng_clk);
+ if (ret) {
+ dev_err(&pdev->dev, "failed to enable clock in callback\n");
+ goto err;
+ }
+ /* read random data from h/w */
+ do {
+ /* check status bit if data is available */
+ while (!(readl_relaxed(base + PRNG_STATUS_OFFSET)
+ & 0x00000001)) {
+ if (failed == 10) {
+ pr_err("Data not available after retry\n");
+ break;
+ }
+ pr_err("msm_rng:Data not available!\n");
+ msleep_interruptible(10);
+ failed++;
+ }
+
+ /* read FIFO */
+ val = readl_relaxed(base + PRNG_DATA_OUT_OFFSET);
+ if (!val)
+ break; /* no data to read so just bail */
+
+ /* write data back to callers pointer */
+ *(retdata++) = val;
+ currsize += 4;
+ /* make sure we stay on 32bit boundary */
+ if ((max - currsize) < 4)
+ break;
+
+ } while (currsize < max);
+
+ /* vote to turn off clock */
+ clk_disable_unprepare(msm_rng_dev->prng_clk);
+err:
+ if (msm_rng_dev->qrng_perf_client) {
+ ret = msm_bus_scale_client_update_request(
+ msm_rng_dev->qrng_perf_client, 0);
+ if (ret)
+ pr_err("bus_scale_client_update_req failed!\n");
+ }
+ mutex_unlock(&msm_rng_dev->rng_lock);
+
+ val = 0L;
+ return currsize;
+}
+static int msm_rng_read(struct hwrng *rng, void *data, size_t max, bool wait)
+{
+ struct msm_rng_device *msm_rng_dev;
+ int rv = 0;
+
+ msm_rng_dev = (struct msm_rng_device *)rng->priv;
+ rv = msm_rng_direct_read(msm_rng_dev, data, max);
+
+ return rv;
+}
+
+
+static struct hwrng msm_rng = {
+ .name = DRIVER_NAME,
+ .read = msm_rng_read,
+ .quality = 700,
+};
+
+static int msm_rng_enable_hw(struct msm_rng_device *msm_rng_dev)
+{
+ unsigned long val = 0;
+ unsigned long reg_val = 0;
+ int ret = 0;
+
+ if (msm_rng_dev->qrng_perf_client) {
+ ret = msm_bus_scale_client_update_request(
+ msm_rng_dev->qrng_perf_client, 1);
+ if (ret)
+ pr_err("bus_scale_client_update_req failed!\n");
+ }
+ /* Enable the PRNG CLK */
+ ret = clk_prepare_enable(msm_rng_dev->prng_clk);
+ if (ret) {
+ dev_err(&(msm_rng_dev->pdev)->dev,
+ "failed to enable clock in probe\n");
+ return -EPERM;
+ }
+
+ /* Enable PRNG h/w only if it is NOT ON */
+ val = readl_relaxed(msm_rng_dev->base + PRNG_CONFIG_OFFSET) &
+ PRNG_HW_ENABLE;
+ /* PRNG H/W is not ON */
+ if (val != PRNG_HW_ENABLE) {
+ val = readl_relaxed(msm_rng_dev->base + PRNG_LFSR_CFG_OFFSET);
+ val &= PRNG_LFSR_CFG_MASK;
+ val |= PRNG_LFSR_CFG_CLOCKS;
+ writel_relaxed(val, msm_rng_dev->base + PRNG_LFSR_CFG_OFFSET);
+
+ /* The PRNG CONFIG register should be first written */
+ mb();
+
+ reg_val = readl_relaxed(msm_rng_dev->base + PRNG_CONFIG_OFFSET)
+ & PRNG_CONFIG_MASK;
+ reg_val |= PRNG_HW_ENABLE;
+ writel_relaxed(reg_val, msm_rng_dev->base + PRNG_CONFIG_OFFSET);
+
+ /* The PRNG clk should be disabled only after we enable the
+ * PRNG h/w by writing to the PRNG CONFIG register.
+ */
+ mb();
+ }
+ clk_disable_unprepare(msm_rng_dev->prng_clk);
+
+ if (msm_rng_dev->qrng_perf_client) {
+ ret = msm_bus_scale_client_update_request(
+ msm_rng_dev->qrng_perf_client, 0);
+ if (ret)
+ pr_err("bus_scale_client_update_req failed!\n");
+ }
+
+ return 0;
+}
+
+static const struct file_operations msm_rng_fops = {
+ .unlocked_ioctl = msm_rng_ioctl,
+};
+static struct class *msm_rng_class;
+static struct cdev msm_rng_cdev;
+
+static int msm_rng_probe(struct platform_device *pdev)
+{
+ struct resource *res;
+ struct msm_rng_device *msm_rng_dev = NULL;
+ void __iomem *base = NULL;
+ bool configure_qrng = true;
+ int error = 0;
+ int ret = 0;
+ struct device *dev;
+
+ struct msm_bus_scale_pdata *qrng_platform_support = NULL;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (res == NULL) {
+ dev_err(&pdev->dev, "invalid address\n");
+ error = -EFAULT;
+ goto err_exit;
+ }
+
+ msm_rng_dev = kzalloc(sizeof(struct msm_rng_device), GFP_KERNEL);
+ if (!msm_rng_dev) {
+ error = -ENOMEM;
+ goto err_exit;
+ }
+
+ base = ioremap(res->start, resource_size(res));
+ if (!base) {
+ dev_err(&pdev->dev, "ioremap failed\n");
+ error = -ENOMEM;
+ goto err_iomap;
+ }
+ msm_rng_dev->base = base;
+
+ /* create a handle for clock control */
+ if ((pdev->dev.of_node) && (of_property_read_bool(pdev->dev.of_node,
+ "qcom,msm-rng-iface-clk")))
+ msm_rng_dev->prng_clk = clk_get(&pdev->dev,
+ "iface_clk");
+ else
+ msm_rng_dev->prng_clk = clk_get(&pdev->dev, "core_clk");
+ if (IS_ERR(msm_rng_dev->prng_clk)) {
+ dev_err(&pdev->dev, "failed to register clock source\n");
+ error = -EPERM;
+ goto err_clk_get;
+ }
+
+ /* save away pdev and register driver data */
+ msm_rng_dev->pdev = pdev;
+ platform_set_drvdata(pdev, msm_rng_dev);
+
+ if (pdev->dev.of_node) {
+ /* Register bus client */
+ qrng_platform_support = msm_bus_cl_get_pdata(pdev);
+ msm_rng_dev->qrng_perf_client = msm_bus_scale_register_client(
+ qrng_platform_support);
+ msm_rng_device_info.qrng_perf_client =
+ msm_rng_dev->qrng_perf_client;
+ if (!msm_rng_dev->qrng_perf_client)
+ pr_err("Unable to register bus client\n");
+ }
+
+ /* Enable rng h/w for the targets which can access the entire
+ * address space of PRNG.
+ */
+ if ((pdev->dev.of_node) && (of_property_read_bool(pdev->dev.of_node,
+ "qcom,no-qrng-config")))
+ configure_qrng = false;
+ if (configure_qrng) {
+ error = msm_rng_enable_hw(msm_rng_dev);
+ if (error)
+ goto rollback_clk;
+ }
+
+ mutex_init(&msm_rng_dev->rng_lock);
+ mutex_init(&cached_rng_lock);
+
+ /* register with hwrng framework */
+ msm_rng.priv = (unsigned long) msm_rng_dev;
+ error = hwrng_register(&msm_rng);
+ if (error) {
+ dev_err(&pdev->dev, "failed to register hwrng\n");
+ error = -EPERM;
+ goto rollback_clk;
+ }
+ ret = register_chrdev(QRNG_IOC_MAGIC, DRIVER_NAME, &msm_rng_fops);
+
+ msm_rng_class = class_create(THIS_MODULE, "msm-rng");
+ if (IS_ERR(msm_rng_class)) {
+ pr_err("class_create failed\n");
+ return PTR_ERR(msm_rng_class);
+ }
+
+ dev = device_create(msm_rng_class, NULL, MKDEV(QRNG_IOC_MAGIC, 0),
+ NULL, "msm-rng");
+ if (IS_ERR(dev)) {
+ pr_err("Device create failed\n");
+ error = PTR_ERR(dev);
+ goto unregister_chrdev;
+ }
+ cdev_init(&msm_rng_cdev, &msm_rng_fops);
+ msm_rng_dev_cached = msm_rng_dev;
+ return error;
+
+unregister_chrdev:
+ unregister_chrdev(QRNG_IOC_MAGIC, DRIVER_NAME);
+rollback_clk:
+ clk_put(msm_rng_dev->prng_clk);
+err_clk_get:
+ iounmap(msm_rng_dev->base);
+err_iomap:
+ kzfree(msm_rng_dev);
+err_exit:
+ return error;
+}
+
+static int msm_rng_remove(struct platform_device *pdev)
+{
+ struct msm_rng_device *msm_rng_dev = platform_get_drvdata(pdev);
+
+ unregister_chrdev(QRNG_IOC_MAGIC, DRIVER_NAME);
+ hwrng_unregister(&msm_rng);
+ clk_put(msm_rng_dev->prng_clk);
+ iounmap(msm_rng_dev->base);
+ platform_set_drvdata(pdev, NULL);
+ if (msm_rng_dev->qrng_perf_client)
+ msm_bus_scale_unregister_client(msm_rng_dev->qrng_perf_client);
+
+ kzfree(msm_rng_dev);
+ msm_rng_dev_cached = NULL;
+ return 0;
+}
+
+static int qrng_get_random(struct crypto_rng *tfm, const u8 *src,
+ unsigned int slen, u8 *rdata,
+ unsigned int dlen)
+{
+ int sizeread = 0;
+ int rv = -EFAULT;
+
+ if (!msm_rng_dev_cached) {
+ pr_err("%s: msm_rng_dev is not initialized.\n", __func__);
+ rv = -ENODEV;
+ goto err_exit;
+ }
+
+ if (!rdata) {
+ pr_err("%s: data buffer is null!\n", __func__);
+ rv = -EINVAL;
+ goto err_exit;
+ }
+
+ if (signal_pending(current) ||
+ mutex_lock_interruptible(&cached_rng_lock)) {
+ pr_err("%s: mutex lock interrupted!\n", __func__);
+ rv = -ERESTARTSYS;
+ goto err_exit;
+ }
+ sizeread = msm_rng_direct_read(msm_rng_dev_cached, rdata, dlen);
+
+ if (sizeread == dlen)
+ rv = 0;
+
+ mutex_unlock(&cached_rng_lock);
+err_exit:
+ return rv;
+
+}
+
+static int qrng_reset(struct crypto_rng *tfm, const u8 *seed, unsigned int slen)
+{
+ return 0;
+}
+
+static struct rng_alg rng_algs[] = { {
+ .generate = qrng_get_random,
+ .seed = qrng_reset,
+ .seedsize = 0,
+ .base = {
+ .cra_name = "qrng",
+ .cra_driver_name = "fips_hw_qrng",
+ .cra_priority = 300,
+ .cra_ctxsize = 0,
+ .cra_module = THIS_MODULE,
+ }
+} };
+
+static const struct of_device_id qrng_match[] = {
+ { .compatible = "qcom,msm-rng",
+ },
+ {}
+};
+
+static struct platform_driver rng_driver = {
+ .probe = msm_rng_probe,
+ .remove = msm_rng_remove,
+ .driver = {
+ .name = DRIVER_NAME,
+ .owner = THIS_MODULE,
+ .of_match_table = qrng_match,
+ }
+};
+
+static int __init msm_rng_init(void)
+{
+ int ret;
+
+ msm_rng_dev_cached = NULL;
+ ret = platform_driver_register(&rng_driver);
+ if (ret) {
+ pr_err("%s: platform_driver_register error:%d\n",
+ __func__, ret);
+ goto err_exit;
+ }
+ ret = crypto_register_rngs(rng_algs, ARRAY_SIZE(rng_algs));
+ if (ret) {
+ pr_err("%s: crypto_register_algs error:%d\n",
+ __func__, ret);
+ goto err_exit;
+ }
+
+err_exit:
+ return ret;
+}
+
+module_init(msm_rng_init);
+
+static void __exit msm_rng_exit(void)
+{
+ crypto_unregister_rngs(rng_algs, ARRAY_SIZE(rng_algs));
+ platform_driver_unregister(&rng_driver);
+}
+
+module_exit(msm_rng_exit);
+
+MODULE_DESCRIPTION("QTI MSM Random Number Driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/char/mem.c b/drivers/char/mem.c
index 6d9cc2d..7e4a9d1 100644
--- a/drivers/char/mem.c
+++ b/drivers/char/mem.c
@@ -60,6 +60,10 @@
#endif
#ifdef CONFIG_STRICT_DEVMEM
+static inline int page_is_allowed(unsigned long pfn)
+{
+ return devmem_is_allowed(pfn);
+}
static inline int range_is_allowed(unsigned long pfn, unsigned long size)
{
u64 from = ((u64)pfn) << PAGE_SHIFT;
@@ -75,6 +79,10 @@
return 1;
}
#else
+static inline int page_is_allowed(unsigned long pfn)
+{
+ return 1;
+}
static inline int range_is_allowed(unsigned long pfn, unsigned long size)
{
return 1;
@@ -122,23 +130,31 @@
while (count > 0) {
unsigned long remaining;
+ int allowed;
sz = size_inside_page(p, count);
- if (!range_is_allowed(p >> PAGE_SHIFT, count))
+ allowed = page_is_allowed(p >> PAGE_SHIFT);
+ if (!allowed)
return -EPERM;
+ if (allowed == 2) {
+ /* Show zeros for restricted memory. */
+ remaining = clear_user(buf, sz);
+ } else {
+ /*
+ * On ia64 if a page has been mapped somewhere as
+ * uncached, then it must also be accessed uncached
+ * by the kernel or data corruption may occur.
+ */
+ ptr = xlate_dev_mem_ptr(p);
+ if (!ptr)
+ return -EFAULT;
- /*
- * On ia64 if a page has been mapped somewhere as uncached, then
- * it must also be accessed uncached by the kernel or data
- * corruption may occur.
- */
- ptr = xlate_dev_mem_ptr(p);
- if (!ptr)
- return -EFAULT;
+ remaining = copy_to_user(buf, ptr, sz);
- remaining = copy_to_user(buf, ptr, sz);
- unxlate_dev_mem_ptr(p, ptr);
+ unxlate_dev_mem_ptr(p, ptr);
+ }
+
if (remaining)
return -EFAULT;
@@ -181,30 +197,36 @@
#endif
while (count > 0) {
+ int allowed;
+
sz = size_inside_page(p, count);
- if (!range_is_allowed(p >> PAGE_SHIFT, sz))
+ allowed = page_is_allowed(p >> PAGE_SHIFT);
+ if (!allowed)
return -EPERM;
- /*
- * On ia64 if a page has been mapped somewhere as uncached, then
- * it must also be accessed uncached by the kernel or data
- * corruption may occur.
- */
- ptr = xlate_dev_mem_ptr(p);
- if (!ptr) {
- if (written)
- break;
- return -EFAULT;
- }
+ /* Skip actual writing when a page is marked as restricted. */
+ if (allowed == 1) {
+ /*
+ * On ia64 if a page has been mapped somewhere as
+ * uncached, then it must also be accessed uncached
+ * by the kernel or data corruption may occur.
+ */
+ ptr = xlate_dev_mem_ptr(p);
+ if (!ptr) {
+ if (written)
+ break;
+ return -EFAULT;
+ }
- copied = copy_from_user(ptr, buf, sz);
- unxlate_dev_mem_ptr(p, ptr);
- if (copied) {
- written += sz - copied;
- if (written)
- break;
- return -EFAULT;
+ copied = copy_from_user(ptr, buf, sz);
+ unxlate_dev_mem_ptr(p, ptr);
+ if (copied) {
+ written += sz - copied;
+ if (written)
+ break;
+ return -EFAULT;
+ }
}
buf += sz;
diff --git a/drivers/char/virtio_console.c b/drivers/char/virtio_console.c
index 5649234..471a301 100644
--- a/drivers/char/virtio_console.c
+++ b/drivers/char/virtio_console.c
@@ -1136,6 +1136,8 @@
{
struct port *port;
struct scatterlist sg[1];
+ void *data;
+ int ret;
if (unlikely(early_put_chars))
return early_put_chars(vtermno, buf, count);
@@ -1144,8 +1146,14 @@
if (!port)
return -EPIPE;
- sg_init_one(sg, buf, count);
- return __send_to_port(port, sg, 1, count, (void *)buf, false);
+ data = kmemdup(buf, count, GFP_ATOMIC);
+ if (!data)
+ return -ENOMEM;
+
+ sg_init_one(sg, data, count);
+ ret = __send_to_port(port, sg, 1, count, data, false);
+ kfree(data);
+ return ret;
}
/*
diff --git a/drivers/clk/clk.c b/drivers/clk/clk.c
index ece2f00..b248b1b 100644
--- a/drivers/clk/clk.c
+++ b/drivers/clk/clk.c
@@ -71,6 +71,8 @@
bool orphan;
unsigned int enable_count;
unsigned int prepare_count;
+ bool need_handoff_enable;
+ bool need_handoff_prepare;
unsigned long min_rate;
unsigned long max_rate;
unsigned long accuracy;
@@ -997,6 +999,19 @@
hlist_for_each_entry(child, &core->children, child_node)
clk_unprepare_unused_subtree(child);
+ /*
+ * setting CLK_ENABLE_HAND_OFF flag triggers this conditional
+ *
+ * need_handoff_prepare implies this clk was already prepared by
+ * __clk_init. now we have a proper user, so unset the flag in our
+ * internal bookkeeping. See CLK_ENABLE_HAND_OFF flag in clk-provider.h
+ * for details.
+ */
+ if (core->need_handoff_prepare) {
+ core->need_handoff_prepare = false;
+ clk_core_unprepare(core);
+ }
+
if (core->prepare_count)
return;
@@ -1023,6 +1038,21 @@
hlist_for_each_entry(child, &core->children, child_node)
clk_disable_unused_subtree(child);
+ /*
+ * setting CLK_ENABLE_HAND_OFF flag triggers this conditional
+ *
+ * need_handoff_enable implies this clk was already enabled by
+ * __clk_init. now we have a proper user, so unset the flag in our
+ * internal bookkeeping. See CLK_ENABLE_HAND_OFF flag in clk-provider.h
+ * for details.
+ */
+ if (core->need_handoff_enable) {
+ core->need_handoff_enable = false;
+ flags = clk_enable_lock();
+ clk_core_disable(core);
+ clk_enable_unlock(flags);
+ }
+
if (core->flags & CLK_OPS_PARENT_ENABLE)
clk_core_prepare_enable(core->parent);
@@ -3140,6 +3170,37 @@
clk_enable_unlock(flags);
}
+ /*
+ * enable clocks with the CLK_ENABLE_HAND_OFF flag set
+ *
+ * This flag causes the framework to enable the clock at registration
+ * time, which is sometimes necessary for clocks that would cause a
+ * system crash when gated (e.g. cpu, memory, etc). The prepare_count
+ * is migrated over to the first clk consumer to call clk_prepare().
+ * Similarly the clk's enable_count is migrated to the first consumer
+ * to call clk_enable().
+ */
+ if (core->flags & CLK_ENABLE_HAND_OFF) {
+ unsigned long flags;
+
+ /*
+ * Few clocks might have hardware gating which would be
+ * required to be ON before prepare/enabling the clocks. So
+ * check if the clock has been turned ON earlier and we should
+ * prepare/enable those clocks.
+ */
+ if (clk_core_is_enabled(core)) {
+ core->need_handoff_prepare = true;
+ core->need_handoff_enable = true;
+ ret = clk_core_prepare(core);
+ if (ret)
+ goto out;
+ flags = clk_enable_lock();
+ clk_core_enable(core);
+ clk_enable_unlock(flags);
+ }
+ }
+
kref_init(&core->ref);
out:
clk_prepare_unlock();
diff --git a/drivers/clk/qcom/Kconfig b/drivers/clk/qcom/Kconfig
index 7226dd3..d47b66e 100644
--- a/drivers/clk/qcom/Kconfig
+++ b/drivers/clk/qcom/Kconfig
@@ -1,6 +1,7 @@
config QCOM_GDSC
bool
select PM_GENERIC_DOMAINS if PM
+ depends on REGULATOR
config COMMON_CLK_QCOM
tristate "Support for Qualcomm's clock controllers"
@@ -225,4 +226,13 @@
sdm845 devices.
Say Y if you want to support graphics controller devices.
+config MSM_CLK_AOP_QMP
+ tristate "AOP QMP Clock Driver"
+ depends on COMMON_CLK_QCOM && MSM_QMP
+ help
+ Always On Processor manages few shared clocks on some Qualcomm
+ Technologies, Inc. SoCs. It accepts requests from other hardware
+ subsystems via QMP mailboxes.
+ Say Y to support the clocks managed by AOP on platforms such as sdm845.
+
source "drivers/clk/qcom/mdss/Kconfig"
diff --git a/drivers/clk/qcom/Makefile b/drivers/clk/qcom/Makefile
index 1d042cd..930e281 100644
--- a/drivers/clk/qcom/Makefile
+++ b/drivers/clk/qcom/Makefile
@@ -24,6 +24,7 @@
obj-$(CONFIG_MDM_GCC_9615) += gcc-mdm9615.o
obj-$(CONFIG_MDM_LCC_9615) += lcc-mdm9615.o
obj-$(CONFIG_MSM_CAMCC_SDM845) += camcc-sdm845.o
+obj-$(CONFIG_MSM_CLK_AOP_QMP) += clk-aop-qmp.o
obj-$(CONFIG_MSM_CLK_RPMH) += clk-rpmh.o
obj-$(CONFIG_MSM_DISPCC_SDM845) += dispcc-sdm845.o
obj-$(CONFIG_MSM_GCC_8660) += gcc-msm8660.o
diff --git a/drivers/clk/qcom/camcc-sdm845.c b/drivers/clk/qcom/camcc-sdm845.c
index a274975..6296c40 100644
--- a/drivers/clk/qcom/camcc-sdm845.c
+++ b/drivers/clk/qcom/camcc-sdm845.c
@@ -764,6 +764,7 @@
};
static const struct freq_tbl ftbl_cam_cc_mclk0_clk_src[] = {
+ F(24000000, P_CAM_CC_PLL3_OUT_EVEN, 16, 0, 0),
F(33333333, P_CAM_CC_PLL0_OUT_EVEN, 2, 1, 9),
F(34285714, P_CAM_CC_PLL2_OUT_EVEN, 14, 0, 0),
{ }
@@ -1114,19 +1115,6 @@
},
};
-static struct clk_branch cam_cc_debug_clk = {
- .halt_reg = 0xc008,
- .halt_check = BRANCH_HALT,
- .clkr = {
- .enable_reg = 0xc008,
- .enable_mask = BIT(0),
- .hw.init = &(struct clk_init_data){
- .name = "cam_cc_debug_clk",
- .ops = &clk_branch2_ops,
- },
- },
-};
-
static struct clk_branch cam_cc_fd_core_clk = {
.halt_reg = 0xb0c8,
.halt_check = BRANCH_HALT,
@@ -1763,7 +1751,6 @@
[CAM_CC_CSIPHY0_CLK] = &cam_cc_csiphy0_clk.clkr,
[CAM_CC_CSIPHY1_CLK] = &cam_cc_csiphy1_clk.clkr,
[CAM_CC_CSIPHY2_CLK] = &cam_cc_csiphy2_clk.clkr,
- [CAM_CC_DEBUG_CLK] = &cam_cc_debug_clk.clkr,
[CAM_CC_FAST_AHB_CLK_SRC] = &cam_cc_fast_ahb_clk_src.clkr,
[CAM_CC_FD_CORE_CLK] = &cam_cc_fd_core_clk.clkr,
[CAM_CC_FD_CORE_CLK_SRC] = &cam_cc_fd_core_clk_src.clkr,
diff --git a/drivers/clk/qcom/clk-aop-qmp.c b/drivers/clk/qcom/clk-aop-qmp.c
new file mode 100644
index 0000000..f698a55
--- /dev/null
+++ b/drivers/clk/qcom/clk-aop-qmp.c
@@ -0,0 +1,322 @@
+/*
+ * Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#define pr_fmt(fmt) "%s: " fmt, __func__
+
+#include <linux/clk-provider.h>
+#include <linux/clk.h>
+#include <linux/err.h>
+#include <linux/kernel.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/mailbox_client.h>
+#include <dt-bindings/clock/qcom,aop-qmp.h>
+
+#define MAX_LEN 96
+#define MBOX_TOUT_MS 1000
+
+struct qmp_pkt {
+ u32 size;
+ void *data;
+};
+
+#define DEFINE_CLK_AOP_QMP(_name, _class, _res, _estate, _dstate) \
+ static struct clk_aop_qmp _name = { \
+ .msg.class = #_class, \
+ .msg.res = #_res, \
+ .enable_state = _estate, \
+ .disable_state = _dstate, \
+ .hw.init = &(struct clk_init_data){ \
+ .ops = &aop_qmp_clk_ops, \
+ .name = #_name, \
+ .num_parents = 0, \
+ .flags = CLK_ENABLE_HAND_OFF, \
+ }, \
+ }
+
+#define to_aop_qmp_clk(hw) container_of(hw, struct clk_aop_qmp, hw)
+
+/*
+ * struct qmp_mbox_msg - mailbox data to QMP
+ * @class: identifies the class.
+ * @res: identifies the resource in the class
+ * @level: identifies the level for the resource.
+ */
+struct qmp_mbox_msg {
+ char class[MAX_LEN];
+ char res[MAX_LEN];
+ int level;
+};
+
+/*
+ * struct clk_aop_qmp - AOP clock
+ * @dev: The device that corresponds to this clock.
+ * @hw: The clock hardware for this clock.
+ * @cl: The client mailbox for this clock.
+ * @mbox: The mbox controller for this clock.
+ * @level: The clock level for this clock.
+ * @enable_state: The clock state when this clock is prepared.
+ * @disable_state: The clock state when this clock is unprepared.
+ * @msg: QMP data associated with this clock.
+ * @enabled: Status of the clock enable.
+ */
+struct clk_aop_qmp {
+ struct device *dev;
+ struct clk_hw hw;
+ struct mbox_client cl;
+ struct mbox_chan *mbox;
+ int level;
+ int enable_state;
+ int disable_state;
+ struct qmp_mbox_msg msg;
+ bool enabled;
+};
+
+static DEFINE_MUTEX(clk_aop_lock);
+
+static unsigned long clk_aop_qmp_recalc_rate(struct clk_hw *hw,
+ unsigned long parent_rate)
+{
+ struct clk_aop_qmp *clk = to_aop_qmp_clk(hw);
+
+ return clk->level;
+}
+
+static long clk_aop_qmp_round_rate(struct clk_hw *hw, unsigned long rate,
+ unsigned long *parent_rate)
+{
+ return rate;
+}
+
+static int clk_aop_qmp_set_rate(struct clk_hw *hw, unsigned long rate,
+ unsigned long parent_rate)
+{
+ char mbox_msg[MAX_LEN];
+ struct qmp_pkt pkt;
+ struct clk_aop_qmp *clk = to_aop_qmp_clk(hw);
+ int ret = 0;
+
+ mutex_lock(&clk_aop_lock);
+
+ snprintf(mbox_msg, MAX_LEN, "{class: %s, res: %s, val: %ld}",
+ clk->msg.class, clk->msg.res, rate);
+ pkt.size = MAX_LEN;
+ pkt.data = mbox_msg;
+
+ ret = mbox_send_message(clk->mbox, &pkt);
+ if (ret < 0) {
+ pr_err("Failed to send set rate request of %lu for %s, ret %d\n",
+ rate, clk_hw_get_name(hw), ret);
+ goto err;
+ } else
+ /* Success: update the return value */
+ ret = 0;
+
+ /* update the current clock level once the mailbox message is sent */
+ clk->level = rate;
+err:
+ mutex_unlock(&clk_aop_lock);
+
+ return ret;
+}
+
+static int clk_aop_qmp_prepare(struct clk_hw *hw)
+{
+ char mbox_msg[MAX_LEN];
+ unsigned long rate;
+ int ret = 0;
+ struct qmp_pkt pkt;
+ struct clk_aop_qmp *clk = to_aop_qmp_clk(hw);
+
+ mutex_lock(&clk_aop_lock);
+
+ if (clk->level)
+ rate = clk->level;
+ else
+ rate = clk->enable_state;
+
+ snprintf(mbox_msg, MAX_LEN, "{class: %s, res: %s, val: %ld}",
+ clk->msg.class, clk->msg.res, rate);
+ pkt.size = MAX_LEN;
+ pkt.data = mbox_msg;
+
+ ret = mbox_send_message(clk->mbox, &pkt);
+ if (ret < 0) {
+ pr_err("Failed to send clk prepare request for %s, ret %d\n",
+ clk_hw_get_name(hw), ret);
+ goto err;
+ } else
+ /* Success: update the return value */
+ ret = 0;
+
+ /* update the current clock level once the mailbox message is sent */
+ clk->level = rate;
+
+ clk->enabled = true;
+err:
+ mutex_unlock(&clk_aop_lock);
+
+ return ret;
+}
+
+static void clk_aop_qmp_unprepare(struct clk_hw *hw)
+{
+ char mbox_msg[MAX_LEN];
+ unsigned long rate;
+ int ret = 0;
+ struct qmp_pkt pkt;
+ struct clk_aop_qmp *clk = to_aop_qmp_clk(hw);
+
+ mutex_lock(&clk_aop_lock);
+
+ rate = clk->disable_state;
+
+ snprintf(mbox_msg, MAX_LEN, "{class: %s, res: %s, val: %ld}",
+ clk->msg.class, clk->msg.res, rate);
+ pkt.size = MAX_LEN;
+ pkt.data = mbox_msg;
+
+ ret = mbox_send_message(clk->mbox, &pkt);
+ if (ret < 0) {
+ pr_err("Failed to send clk unprepare request for %s, ret %d\n",
+ clk_hw_get_name(hw), ret);
+ goto err;
+ }
+
+ clk->enabled = false;
+err:
+ mutex_unlock(&clk_aop_lock);
+}
+
+static int clk_aop_qmp_is_enabled(struct clk_hw *hw)
+{
+ struct clk_aop_qmp *clk = to_aop_qmp_clk(hw);
+
+ return clk->enabled;
+}
+
+static const struct clk_ops aop_qmp_clk_ops = {
+ .prepare = clk_aop_qmp_prepare,
+ .unprepare = clk_aop_qmp_unprepare,
+ .recalc_rate = clk_aop_qmp_recalc_rate,
+ .set_rate = clk_aop_qmp_set_rate,
+ .round_rate = clk_aop_qmp_round_rate,
+ .is_enabled = clk_aop_qmp_is_enabled,
+};
+
+DEFINE_CLK_AOP_QMP(qdss_qmp_clk, clock, qdss,
+ QDSS_CLK_LEVEL_DYNAMIC, QDSS_CLK_LEVEL_OFF);
+
+static struct clk_hw *aop_qmp_clk_hws[] = {
+ [QDSS_CLK] = &qdss_qmp_clk.hw,
+};
+
+static int qmp_update_client(struct clk_hw *hw, struct device *dev,
+ struct mbox_chan *mbox)
+{
+ struct clk_aop_qmp *clk_aop = to_aop_qmp_clk(hw);
+
+ /* Use mailbox client with blocking mode */
+ clk_aop->cl.dev = dev;
+ clk_aop->cl.tx_block = true;
+ clk_aop->cl.tx_tout = MBOX_TOUT_MS;
+ clk_aop->cl.knows_txdone = false;
+
+ if (mbox) {
+ clk_aop->mbox = mbox;
+ return 0;
+ }
+
+ /* Allocate mailbox channel */
+ mbox = clk_aop->mbox = mbox_request_channel(&clk_aop->cl, 0);
+ if (IS_ERR(clk_aop->mbox) && PTR_ERR(clk_aop->mbox) != -EPROBE_DEFER) {
+ dev_err(dev, "Failed to get mailbox channel %pK %ld\n",
+ mbox, PTR_ERR(mbox));
+ return PTR_ERR(clk_aop->mbox);
+ }
+
+ return 0;
+}
+
+static int aop_qmp_clk_probe(struct platform_device *pdev)
+{
+ struct clk *clk;
+ struct device_node *np = pdev->dev.of_node;
+ struct mbox_chan *mbox = NULL;
+ int num_clks = ARRAY_SIZE(aop_qmp_clk_hws);
+ int ret = 0, i = 0;
+
+ /*
+ * Allocate mbox channel for the first clock client. The same channel
+ * would be used for the rest of the clock clients.
+ */
+ ret = qmp_update_client(aop_qmp_clk_hws[i], &pdev->dev, mbox);
+ if (ret < 0)
+ return ret;
+
+ for (i = 1; i < num_clks; i++) {
+ ret = qmp_update_client(aop_qmp_clk_hws[i], &pdev->dev, mbox);
+ if (ret < 0) {
+ dev_err(&pdev->dev, "Failed to update QMP client %d\n",
+ ret);
+ goto fail;
+ }
+ }
+
+ for (i = 0; i < num_clks; i++) {
+ ret = clk_aop_qmp_prepare(aop_qmp_clk_hws[i]);
+ if (ret < 0)
+ goto fail;
+ }
+
+ for (i = 0; i < num_clks; i++) {
+ clk = devm_clk_register(&pdev->dev, aop_qmp_clk_hws[i]);
+ if (IS_ERR(clk)) {
+ ret = PTR_ERR(clk);
+ goto fail;
+ }
+ }
+
+ ret = of_clk_add_provider(np, of_clk_src_simple_get, clk);
+ if (ret) {
+ dev_err(&pdev->dev, "Failed to register clock provider\n");
+ goto fail;
+ }
+
+ dev_info(&pdev->dev, "Registered clocks with AOP\n");
+
+ return ret;
+fail:
+ mbox_free_channel(mbox);
+
+ return ret;
+}
+
+static const struct of_device_id aop_qmp_clk_of_match[] = {
+ { .compatible = "qcom,aop-qmp-clk", },
+ {}
+};
+
+static struct platform_driver aop_qmp_clk_driver = {
+ .driver = {
+ .name = "qmp-aop-clk",
+ .of_match_table = aop_qmp_clk_of_match,
+ },
+ .probe = aop_qmp_clk_probe,
+};
+
+static int __init aop_qmp_clk_init(void)
+{
+ return platform_driver_register(&aop_qmp_clk_driver);
+}
+subsys_initcall(aop_qmp_clk_init);
diff --git a/drivers/clk/qcom/clk-cpu-osm.c b/drivers/clk/qcom/clk-cpu-osm.c
index 8bbf55c..035d337 100644
--- a/drivers/clk/qcom/clk-cpu-osm.c
+++ b/drivers/clk/qcom/clk-cpu-osm.c
@@ -509,34 +509,22 @@
.set_rate = l3_clk_set_rate,
};
-enum {
- P_XO,
-};
-
-static const struct parent_map gcc_parent_map_1[] = {
- { P_XO, 0 },
-};
-
-static const char * const gcc_parent_names_1[] = {
- "xo",
-};
-
static struct clk_init_data osm_clks_init[] = {
[0] = {
.name = "l3_clk",
- .parent_names = (const char *[]){ "bi_tcxo" },
+ .parent_names = (const char *[]){ "bi_tcxo_ao" },
.num_parents = 1,
.ops = &clk_ops_l3_osm,
},
[1] = {
.name = "pwrcl_clk",
- .parent_names = (const char *[]){ "bi_tcxo" },
+ .parent_names = (const char *[]){ "bi_tcxo_ao" },
.num_parents = 1,
.ops = &clk_ops_cpu_osm,
},
[2] = {
.name = "perfcl_clk",
- .parent_names = (const char *[]){ "bi_tcxo" },
+ .parent_names = (const char *[]){ "bi_tcxo_ao" },
.num_parents = 1,
.ops = &clk_ops_cpu_osm,
},
diff --git a/drivers/clk/qcom/dispcc-sdm845.c b/drivers/clk/qcom/dispcc-sdm845.c
index cb073a8..3b56fa1 100644
--- a/drivers/clk/qcom/dispcc-sdm845.c
+++ b/drivers/clk/qcom/dispcc-sdm845.c
@@ -478,19 +478,6 @@
},
};
-static struct clk_branch disp_cc_debug_clk = {
- .halt_reg = 0x600c,
- .halt_check = BRANCH_HALT,
- .clkr = {
- .enable_reg = 0x600c,
- .enable_mask = BIT(0),
- .hw.init = &(struct clk_init_data){
- .name = "disp_cc_debug_clk",
- .ops = &clk_branch2_ops,
- },
- },
-};
-
static struct clk_branch disp_cc_mdss_ahb_clk = {
.halt_reg = 0x4004,
.halt_check = BRANCH_HALT,
@@ -546,7 +533,7 @@
"disp_cc_mdss_byte0_clk_src",
},
.num_parents = 1,
- .flags = CLK_SET_RATE_PARENT | CLK_GET_RATE_NOCACHE,
+ .flags = CLK_GET_RATE_NOCACHE,
.ops = &clk_regmap_div_ops,
},
},
@@ -599,7 +586,7 @@
"disp_cc_mdss_byte1_clk_src",
},
.num_parents = 1,
- .flags = CLK_SET_RATE_PARENT | CLK_GET_RATE_NOCACHE,
+ .flags = CLK_GET_RATE_NOCACHE,
.ops = &clk_regmap_div_ops,
},
},
@@ -949,7 +936,6 @@
};
static struct clk_regmap *disp_cc_sdm845_clocks[] = {
- [DISP_CC_DEBUG_CLK] = &disp_cc_debug_clk.clkr,
[DISP_CC_MDSS_AHB_CLK] = &disp_cc_mdss_ahb_clk.clkr,
[DISP_CC_MDSS_AXI_CLK] = &disp_cc_mdss_axi_clk.clkr,
[DISP_CC_MDSS_BYTE0_CLK] = &disp_cc_mdss_byte0_clk.clkr,
diff --git a/drivers/clk/qcom/gcc-sdm845.c b/drivers/clk/qcom/gcc-sdm845.c
index 79b1a59..678dd10 100644
--- a/drivers/clk/qcom/gcc-sdm845.c
+++ b/drivers/clk/qcom/gcc-sdm845.c
@@ -151,6 +151,13 @@
"core_bi_pll_test_se",
};
+static const char * const gcc_parent_names_7[] = {
+ "bi_tcxo_ao",
+ "gpll0",
+ "gpll0_out_even",
+ "core_bi_pll_test_se",
+};
+
static struct clk_dummy measure_only_snoc_clk = {
.rrate = 1000,
.hw.init = &(struct clk_init_data){
@@ -256,8 +263,6 @@
static const struct freq_tbl ftbl_gcc_cpuss_ahb_clk_src[] = {
F(19200000, P_BI_TCXO, 1, 0, 0),
- F(50000000, P_GPLL0_OUT_MAIN, 12, 0, 0),
- F(100000000, P_GPLL0_OUT_MAIN, 6, 0, 0),
{ }
};
@@ -269,7 +274,7 @@
.freq_tbl = ftbl_gcc_cpuss_ahb_clk_src,
.clkr.hw.init = &(struct clk_init_data){
.name = "gcc_cpuss_ahb_clk_src",
- .parent_names = gcc_parent_names_0,
+ .parent_names = gcc_parent_names_7,
.num_parents = 4,
.flags = CLK_SET_RATE_PARENT,
.ops = &clk_rcg2_ops,
@@ -1463,19 +1468,6 @@
},
};
-static struct clk_branch gcc_cxo_tx1_clkref_clk = {
- .halt_reg = 0x8c020,
- .halt_check = BRANCH_HALT,
- .clkr = {
- .enable_reg = 0x8c020,
- .enable_mask = BIT(0),
- .hw.init = &(struct clk_init_data){
- .name = "gcc_cxo_tx1_clkref_clk",
- .ops = &clk_branch2_ops,
- },
- },
-};
-
static struct clk_branch gcc_ddrss_gpu_axi_clk = {
.halt_reg = 0x44038,
.halt_check = BRANCH_VOTED,
@@ -2428,32 +2420,6 @@
},
};
-static struct clk_branch gcc_rx1_usb2_clkref_clk = {
- .halt_reg = 0x8c014,
- .halt_check = BRANCH_HALT,
- .clkr = {
- .enable_reg = 0x8c014,
- .enable_mask = BIT(0),
- .hw.init = &(struct clk_init_data){
- .name = "gcc_rx1_usb2_clkref_clk",
- .ops = &clk_branch2_ops,
- },
- },
-};
-
-static struct clk_branch gcc_rx2_qlink_clkref_clk = {
- .halt_reg = 0x8c018,
- .halt_check = BRANCH_HALT,
- .clkr = {
- .enable_reg = 0x8c018,
- .enable_mask = BIT(0),
- .hw.init = &(struct clk_init_data){
- .name = "gcc_rx2_qlink_clkref_clk",
- .ops = &clk_branch2_ops,
- },
- },
-};
-
static struct clk_branch gcc_sdcc2_ahb_clk = {
.halt_reg = 0x14008,
.halt_check = BRANCH_HALT,
@@ -3146,7 +3112,6 @@
[GCC_CPUSS_GNOC_CLK] = &gcc_cpuss_gnoc_clk.clkr,
[GCC_CPUSS_RBCPR_CLK] = &gcc_cpuss_rbcpr_clk.clkr,
[GCC_CPUSS_RBCPR_CLK_SRC] = &gcc_cpuss_rbcpr_clk_src.clkr,
- [GCC_CXO_TX1_CLKREF_CLK] = &gcc_cxo_tx1_clkref_clk.clkr,
[GCC_DDRSS_GPU_AXI_CLK] = &gcc_ddrss_gpu_axi_clk.clkr,
[GCC_DISP_AHB_CLK] = &gcc_disp_ahb_clk.clkr,
[GCC_DISP_AXI_CLK] = &gcc_disp_axi_clk.clkr,
@@ -3233,8 +3198,6 @@
[GCC_QUPV3_WRAP_0_S_AHB_CLK] = &gcc_qupv3_wrap_0_s_ahb_clk.clkr,
[GCC_QUPV3_WRAP_1_M_AHB_CLK] = &gcc_qupv3_wrap_1_m_ahb_clk.clkr,
[GCC_QUPV3_WRAP_1_S_AHB_CLK] = &gcc_qupv3_wrap_1_s_ahb_clk.clkr,
- [GCC_RX1_USB2_CLKREF_CLK] = &gcc_rx1_usb2_clkref_clk.clkr,
- [GCC_RX2_QLINK_CLKREF_CLK] = &gcc_rx2_qlink_clkref_clk.clkr,
[GCC_SDCC2_AHB_CLK] = &gcc_sdcc2_ahb_clk.clkr,
[GCC_SDCC2_APPS_CLK] = &gcc_sdcc2_apps_clk.clkr,
[GCC_SDCC2_APPS_CLK_SRC] = &gcc_sdcc2_apps_clk_src.clkr,
@@ -3332,6 +3295,8 @@
[GCC_USB3PHY_PHY_SEC_BCR] = { 0x50010 },
[GCC_USB3_DP_PHY_SEC_BCR] = { 0x50014 },
[GCC_USB_PHY_CFG_AHB2PHY_BCR] = { 0x6a000 },
+ [GCC_PCIE_0_PHY_BCR] = { 0x6c01c },
+ [GCC_PCIE_1_PHY_BCR] = { 0x8e01c },
};
static const struct regmap_config gcc_sdm845_regmap_config = {
diff --git a/drivers/clk/qcom/gpucc-sdm845.c b/drivers/clk/qcom/gpucc-sdm845.c
index d9a626e..0115bb1 100644
--- a/drivers/clk/qcom/gpucc-sdm845.c
+++ b/drivers/clk/qcom/gpucc-sdm845.c
@@ -413,19 +413,6 @@
},
};
-static struct clk_branch gpu_cc_debug_clk = {
- .halt_reg = 0x1100,
- .halt_check = BRANCH_HALT,
- .clkr = {
- .enable_reg = 0x1100,
- .enable_mask = BIT(0),
- .hw.init = &(struct clk_init_data){
- .name = "gpu_cc_debug_clk",
- .ops = &clk_branch2_ops,
- },
- },
-};
-
static struct clk_branch gpu_cc_gx_cxo_clk = {
.halt_reg = 0x1060,
.halt_check = BRANCH_HALT,
@@ -544,7 +531,6 @@
[GPU_CC_CX_SNOC_DVM_CLK] = &gpu_cc_cx_snoc_dvm_clk.clkr,
[GPU_CC_CXO_AON_CLK] = &gpu_cc_cxo_aon_clk.clkr,
[GPU_CC_CXO_CLK] = &gpu_cc_cxo_clk.clkr,
- [GPU_CC_DEBUG_CLK] = &gpu_cc_debug_clk.clkr,
[GPU_CC_GMU_CLK_SRC] = &gpu_cc_gmu_clk_src.clkr,
[GPU_CC_GX_CXO_CLK] = &gpu_cc_gx_cxo_clk.clkr,
[GPU_CC_GX_GMU_CLK] = &gpu_cc_gx_gmu_clk.clkr,
diff --git a/drivers/clk/qcom/mdss/mdss-dsi-pll-10nm.c b/drivers/clk/qcom/mdss/mdss-dsi-pll-10nm.c
index 6ce0d76..9ce0afc 100644
--- a/drivers/clk/qcom/mdss/mdss-dsi-pll-10nm.c
+++ b/drivers/clk/qcom/mdss/mdss-dsi-pll-10nm.c
@@ -23,9 +23,10 @@
#define VCO_DELAY_USEC 1
-#define MHZ_375 375000000UL
-#define MHZ_750 750000000UL
-#define MHZ_1500 1500000000UL
+#define MHZ_250 250000000UL
+#define MHZ_500 500000000UL
+#define MHZ_1000 1000000000UL
+#define MHZ_1100 1100000000UL
#define MHZ_1900 1900000000UL
#define MHZ_3000 3000000000UL
@@ -40,6 +41,8 @@
#define PLL_CALIBRATION_SETTINGS 0x030
#define PLL_BAND_SEL_CAL_SETTINGS_THREE 0x054
#define PLL_FREQ_DETECT_SETTINGS_ONE 0x064
+#define PLL_PFILT 0x07c
+#define PLL_IFILT 0x080
#define PLL_OUTDIV 0x094
#define PLL_CORE_OVERRIDE 0x0a4
#define PLL_CORE_INPUT_OVERRIDE 0x0a8
@@ -63,6 +66,7 @@
#define PLL_PLL_FL_INT_GAIN_PFILT_BAND_1 0x164
#define PLL_PLL_LOCK_OVERRIDE 0x180
#define PLL_PLL_LOCK_DELAY 0x184
+#define PLL_CLOCK_INVERTERS 0x18c
#define PLL_COMMON_STATUS_ONE 0x1a0
/* Register Offsets from PHY base address */
@@ -96,6 +100,7 @@
u32 frac_div_start_low;
u32 frac_div_start_mid;
u32 frac_div_start_high;
+ u32 pll_clock_inverters;
u32 ssc_stepsize_low;
u32 ssc_stepsize_high;
u32 ssc_div_per_low;
@@ -206,20 +211,36 @@
u64 dec, dec_multiple;
u32 frac;
u64 multiplier;
+ u32 i;
target_freq = rsc->vco_current_rate;
pr_debug("target_freq = %llu\n", target_freq);
if (config->div_override) {
computed_output_div = config->output_div;
+
+ /*
+ * Computed_output_div = 2 ^ div_log
+ * To get div_log from output div just get the index of the
+ * 1 bit in the value.
+ * div_log ranges from 0-3. so check the 4 lsbs
+ */
+
+ for (i = 0; i < 4; i++) {
+ if (computed_output_div & (1 << i)) {
+ div_log = i;
+ break;
+ }
+ }
+
} else {
- if (target_freq < MHZ_375) {
+ if (target_freq < MHZ_250) {
computed_output_div = 8;
div_log = 3;
- } else if (target_freq < MHZ_750) {
+ } else if (target_freq < MHZ_500) {
computed_output_div = 4;
div_log = 2;
- } else if (target_freq < MHZ_1500) {
+ } else if (target_freq < MHZ_1000) {
computed_output_div = 2;
div_log = 1;
} else {
@@ -248,6 +269,10 @@
regs->pll_prop_gain_rate = 10;
else
regs->pll_prop_gain_rate = 12;
+ if (pll_freq < MHZ_1100)
+ regs->pll_clock_inverters = 8;
+ else
+ regs->pll_clock_inverters = 0;
regs->pll_outdiv_rate = div_log;
regs->pll_lockdet_rate = config->lock_timer;
@@ -338,7 +363,6 @@
MDSS_PLL_REG_W(pll_base, PLL_ANALOG_CONTROLS_THREE, 0x00);
MDSS_PLL_REG_W(pll_base, PLL_DSM_DIVIDER, 0x00);
MDSS_PLL_REG_W(pll_base, PLL_FEEDBACK_DIVIDER, 0x4e);
- MDSS_PLL_REG_W(pll_base, PLL_CMODE, 0x00);
MDSS_PLL_REG_W(pll_base, PLL_CALIBRATION_SETTINGS, 0x40);
MDSS_PLL_REG_W(pll_base, PLL_BAND_SEL_CAL_SETTINGS_THREE, 0xba);
MDSS_PLL_REG_W(pll_base, PLL_FREQ_DETECT_SETTINGS_ONE, 0x0c);
@@ -347,9 +371,11 @@
MDSS_PLL_REG_W(pll_base, PLL_PLL_DIGITAL_TIMERS_TWO, 0x08);
MDSS_PLL_REG_W(pll_base, PLL_PLL_PROP_GAIN_RATE_1, 0x08);
MDSS_PLL_REG_W(pll_base, PLL_PLL_BAND_SET_RATE_1, 0xc0);
- MDSS_PLL_REG_W(pll_base, PLL_PLL_INT_GAIN_IFILT_BAND_1, 0x82);
+ MDSS_PLL_REG_W(pll_base, PLL_PLL_INT_GAIN_IFILT_BAND_1, 0xfa);
MDSS_PLL_REG_W(pll_base, PLL_PLL_FL_INT_GAIN_PFILT_BAND_1, 0x4c);
MDSS_PLL_REG_W(pll_base, PLL_PLL_LOCK_OVERRIDE, 0x80);
+ MDSS_PLL_REG_W(pll_base, PLL_PFILT, 0x29);
+ MDSS_PLL_REG_W(pll_base, PLL_IFILT, 0x3f);
}
static void dsi_pll_commit(struct dsi_pll_10nm *pll,
@@ -367,9 +393,11 @@
reg->frac_div_start_mid);
MDSS_PLL_REG_W(pll_base, PLL_FRAC_DIV_START_HIGH_1,
reg->frac_div_start_high);
- MDSS_PLL_REG_W(pll_base, PLL_PLL_LOCKDET_RATE_1, 0xc8);
+ MDSS_PLL_REG_W(pll_base, PLL_PLL_LOCKDET_RATE_1, 0x40);
MDSS_PLL_REG_W(pll_base, PLL_PLL_OUTDIV_RATE, reg->pll_outdiv_rate);
- MDSS_PLL_REG_W(pll_base, PLL_PLL_LOCK_DELAY, 0x0a);
+ MDSS_PLL_REG_W(pll_base, PLL_PLL_LOCK_DELAY, 0x06);
+ MDSS_PLL_REG_W(pll_base, PLL_CMODE, 0x10);
+ MDSS_PLL_REG_W(pll_base, PLL_CLOCK_INVERTERS, reg->pll_clock_inverters);
}
@@ -450,8 +478,8 @@
{
u32 data = MDSS_PLL_REG_R(rsc->phy_base, PHY_CMN_CTRL_0);
- MDSS_PLL_REG_W(rsc->phy_base, PHY_CMN_CTRL_0, data & ~BIT(5));
MDSS_PLL_REG_W(rsc->pll_base, PLL_SYSTEM_MUXES, 0);
+ MDSS_PLL_REG_W(rsc->phy_base, PHY_CMN_CTRL_0, data & ~BIT(5));
ndelay(250);
}
@@ -464,6 +492,22 @@
ndelay(250);
}
+static void dsi_pll_disable_global_clk(struct mdss_pll_resources *rsc)
+{
+ u32 data;
+
+ data = MDSS_PLL_REG_R(rsc->phy_base, PHY_CMN_CLK_CFG1);
+ MDSS_PLL_REG_W(rsc->phy_base, PHY_CMN_CLK_CFG1, (data & ~BIT(5)));
+}
+
+static void dsi_pll_enable_global_clk(struct mdss_pll_resources *rsc)
+{
+ u32 data;
+
+ data = MDSS_PLL_REG_R(rsc->phy_base, PHY_CMN_CLK_CFG1);
+ MDSS_PLL_REG_W(rsc->phy_base, PHY_CMN_CLK_CFG1, (data | BIT(5)));
+}
+
static int dsi_pll_enable(struct dsi_pll_vco_clk *vco)
{
int rc;
@@ -490,6 +534,11 @@
}
rsc->pll_on = true;
+
+ dsi_pll_enable_global_clk(rsc);
+ if (rsc->slave)
+ dsi_pll_enable_global_clk(rsc->slave);
+
MDSS_PLL_REG_W(rsc->phy_base, PHY_CMN_RBUF_CTRL, 0x01);
if (rsc->slave)
MDSS_PLL_REG_W(rsc->slave->phy_base, PHY_CMN_RBUF_CTRL, 0x01);
@@ -500,8 +549,9 @@
static void dsi_pll_disable_sub(struct mdss_pll_resources *rsc)
{
- dsi_pll_disable_pll_bias(rsc);
+ dsi_pll_disable_global_clk(rsc);
MDSS_PLL_REG_W(rsc->phy_base, PHY_CMN_RBUF_CTRL, 0);
+ dsi_pll_disable_pll_bias(rsc);
}
static void dsi_pll_disable(struct dsi_pll_vco_clk *vco)
@@ -613,6 +663,9 @@
u32 outdiv;
u64 pll_freq, tmp64;
+ if (!vco->priv)
+ pr_err("vco priv is null\n");
+
rc = mdss_pll_resource_enable(pll, true);
if (rc) {
pr_err("failed to enable pll(%d) resource, rc=%d\n",
@@ -671,9 +724,11 @@
reg_val = MDSS_PLL_REG_R(pll->phy_base, PHY_CMN_CLK_CFG0);
*div = (reg_val & 0xF0) >> 4;
- if (*div == 0)
- *div = 1;
- else
+ /**
+ * Common clock framework the divider value is interpreted as one less
+ * hence we return one less for all dividers except when zero
+ */
+ if (*div != 0)
*div -= 1;
(void)mdss_pll_resource_enable(pll, false);
@@ -701,13 +756,15 @@
pr_err("Failed to enable dsi pll resources, rc=%d\n", rc);
return rc;
}
- /* In common clock framework the divider value provided is one less */
+ /**
+ * In common clock framework the divider value provided is one less and
+ * and hence adjusting the divider value by one prior to writing it to
+ * hardware
+ */
div++;
-
pixel_clk_set_div_sub(pll, div);
if (pll->slave)
pixel_clk_set_div_sub(pll->slave, div);
-
(void)mdss_pll_resource_enable(pll, false);
return 0;
@@ -728,12 +785,12 @@
reg_val = MDSS_PLL_REG_R(pll->phy_base, PHY_CMN_CLK_CFG0);
*div = (reg_val & 0x0F);
- /* Common clock framework will add one to divider value sent */
- if (*div == 0)
- *div = 1;
- else
+ /**
+ *Common clock framework the divider value is interpreted as one less
+ * hence we return one less for all dividers except when zero
+ */
+ if (*div != 0)
*div -= 1;
-
(void)mdss_pll_resource_enable(pll, false);
return rc;
@@ -771,6 +828,12 @@
pr_err("Failed to enable dsi pll resources, rc=%d\n", rc);
return rc;
}
+
+ /**
+ * In common clock framework the divider value provided is one less and
+ * and hence adjusting the divider value by one prior to writing it to
+ * hardware
+ */
div++;
bit_clk_set_div_sub(rsc, div);
@@ -806,9 +869,11 @@
else
*div = 1;
- if (*div == 0)
- *div = 1;
- else
+ /**
+ *Common clock framework the divider value is interpreted as one less
+ * hence we return one less for all dividers except when zero
+ */
+ if (*div != 0)
*div -= 1;
(void)mdss_pll_resource_enable(pll, false);
@@ -851,8 +916,12 @@
return rc;
}
+ /**
+ * In common clock framework the divider value provided is one less and
+ * and hence adjusting the divider value by one prior to writing it to
+ * hardware
+ */
div++;
-
rc = post_vco_clk_set_div_sub(pll, div);
if (!rc && pll->slave)
rc = post_vco_clk_set_div_sub(pll->slave, div);
@@ -885,9 +954,11 @@
else
*div = 1;
- if (*div == 0)
- *div = 1;
- else
+ /**
+ *Common clock framework the divider value is interpreted as one less
+ * hence we return one less for all dividers except when zero
+ */
+ if (*div != 0)
*div -= 1;
(void)mdss_pll_resource_enable(pll, false);
@@ -930,8 +1001,12 @@
return rc;
}
+ /**
+ * In common clock framework the divider value provided is one less and
+ * and hence adjusting the divider value by one prior to writing it to
+ * hardware
+ */
div++;
-
rc = post_bit_clk_set_div_sub(pll, div);
if (!rc && pll->slave)
rc = post_bit_clk_set_div_sub(pll->slave, div);
@@ -1032,7 +1107,7 @@
static struct dsi_pll_vco_clk dsi0pll_vco_clk = {
.ref_clk_rate = 19200000UL,
- .min_rate = 1500000000UL,
+ .min_rate = 1000000000UL,
.max_rate = 3500000000UL,
.hw.init = &(struct clk_init_data){
.name = "dsi0pll_vco_clk",
@@ -1045,7 +1120,7 @@
static struct dsi_pll_vco_clk dsi1pll_vco_clk = {
.ref_clk_rate = 19200000UL,
- .min_rate = 1500000000UL,
+ .min_rate = 1000000000UL,
.max_rate = 3500000000UL,
.hw.init = &(struct clk_init_data){
.name = "dsi1pll_vco_clk",
@@ -1057,7 +1132,6 @@
};
static struct clk_regmap_div dsi0pll_bitclk_src = {
- .reg = 0x48,
.shift = 0,
.width = 4,
.clkr = {
@@ -1072,7 +1146,6 @@
};
static struct clk_regmap_div dsi1pll_bitclk_src = {
- .reg = 0x48,
.shift = 0,
.width = 4,
.clkr = {
@@ -1087,9 +1160,8 @@
};
static struct clk_regmap_div dsi0pll_post_vco_div = {
- .reg = 0x48,
.shift = 0,
- .width = 4,
+ .width = 2,
.clkr = {
.hw.init = &(struct clk_init_data){
.name = "dsi0pll_post_vco_div",
@@ -1102,9 +1174,8 @@
};
static struct clk_regmap_div dsi1pll_post_vco_div = {
- .reg = 0x48,
.shift = 0,
- .width = 4,
+ .width = 2,
.clkr = {
.hw.init = &(struct clk_init_data){
.name = "dsi1pll_post_vco_div",
@@ -1141,9 +1212,8 @@
};
static struct clk_regmap_div dsi0pll_post_bit_div = {
- .reg = 0x48,
.shift = 0,
- .width = 4,
+ .width = 1,
.clkr = {
.hw.init = &(struct clk_init_data){
.name = "dsi0pll_post_bit_div",
@@ -1156,9 +1226,8 @@
};
static struct clk_regmap_div dsi1pll_post_bit_div = {
- .reg = 0x48,
.shift = 0,
- .width = 4,
+ .width = 1,
.clkr = {
.hw.init = &(struct clk_init_data){
.name = "dsi1pll_post_bit_div",
@@ -1171,12 +1240,11 @@
};
static struct clk_regmap_mux dsi0pll_byteclk_mux = {
- .reg = 0x48,
.shift = 0,
- .width = 4,
+ .width = 0,
.clkr = {
.hw.init = &(struct clk_init_data){
- .name = "dsi0pll_byteclk_mux",
+ .name = "dsi0_phy_pll_out_byteclk",
.parent_names = (const char *[]){"dsi0pll_byteclk_src"},
.num_parents = 1,
.flags = (CLK_GET_RATE_NOCACHE | CLK_SET_RATE_PARENT),
@@ -1186,12 +1254,11 @@
};
static struct clk_regmap_mux dsi1pll_byteclk_mux = {
- .reg = 0x48,
.shift = 0,
- .width = 4,
+ .width = 0,
.clkr = {
.hw.init = &(struct clk_init_data){
- .name = "dsi1pll_byteclk_mux",
+ .name = "dsi1_phy_pll_out_byteclk",
.parent_names = (const char *[]){"dsi1pll_byteclk_src"},
.num_parents = 1,
.flags = (CLK_GET_RATE_NOCACHE | CLK_SET_RATE_PARENT),
@@ -1201,15 +1268,14 @@
};
static struct clk_regmap_mux dsi0pll_pclk_src_mux = {
- .reg = 0x48,
.shift = 0,
- .width = 4,
+ .width = 0,
.clkr = {
.hw.init = &(struct clk_init_data){
.name = "dsi0pll_pclk_src_mux",
.parent_names = (const char *[]){"dsi0pll_post_bit_div",
- "dsi0pll_post_bit_div"},
- .num_parents = 1,
+ "dsi0pll_post_vco_div"},
+ .num_parents = 2,
.flags = (CLK_GET_RATE_NOCACHE | CLK_SET_RATE_PARENT),
.ops = &clk_regmap_mux_closest_ops,
},
@@ -1217,15 +1283,14 @@
};
static struct clk_regmap_mux dsi1pll_pclk_src_mux = {
- .reg = 0x48,
.shift = 0,
- .width = 4,
+ .width = 0,
.clkr = {
.hw.init = &(struct clk_init_data){
.name = "dsi1pll_pclk_src_mux",
.parent_names = (const char *[]){"dsi1pll_post_bit_div",
- "dsi1pll_post_bit_div"},
- .num_parents = 1,
+ "dsi1pll_post_vco_div"},
+ .num_parents = 2,
.flags = (CLK_GET_RATE_NOCACHE | CLK_SET_RATE_PARENT),
.ops = &clk_regmap_mux_closest_ops,
},
@@ -1233,7 +1298,6 @@
};
static struct clk_regmap_div dsi0pll_pclk_src = {
- .reg = 0x48,
.shift = 0,
.width = 4,
.clkr = {
@@ -1249,7 +1313,6 @@
};
static struct clk_regmap_div dsi1pll_pclk_src = {
- .reg = 0x48,
.shift = 0,
.width = 4,
.clkr = {
@@ -1265,12 +1328,11 @@
};
static struct clk_regmap_mux dsi0pll_pclk_mux = {
- .reg = 0x48,
.shift = 0,
- .width = 4,
+ .width = 0,
.clkr = {
.hw.init = &(struct clk_init_data){
- .name = "dsi0pll_pclk_mux",
+ .name = "dsi0_phy_pll_out_dsiclk",
.parent_names = (const char *[]){"dsi0pll_pclk_src"},
.num_parents = 1,
.flags = (CLK_GET_RATE_NOCACHE | CLK_SET_RATE_PARENT),
@@ -1280,12 +1342,11 @@
};
static struct clk_regmap_mux dsi1pll_pclk_mux = {
- .reg = 0x48,
.shift = 0,
- .width = 4,
+ .width = 0,
.clkr = {
.hw.init = &(struct clk_init_data){
- .name = "dsi1pll_pclk_mux",
+ .name = "dsi1_phy_pll_out_dsiclk",
.parent_names = (const char *[]){"dsi1pll_pclk_src"},
.num_parents = 1,
.flags = (CLK_GET_RATE_NOCACHE | CLK_SET_RATE_PARENT),
@@ -1339,8 +1400,8 @@
}
pll_rsc_db[ndx] = pll_res;
- pll_res->priv = &plls[ndx];
plls[ndx].rsc = pll_res;
+ pll_res->priv = &plls[ndx];
pll_res->vco_delay = VCO_DELAY_USEC;
clk_data = devm_kzalloc(&pdev->dev, sizeof(struct clk_onecell_data),
@@ -1386,6 +1447,7 @@
pll_res, &dsi_pll_10nm_config);
dsi0pll_byteclk_mux.clkr.regmap = rmap;
+ dsi0pll_vco_clk.priv = pll_res;
for (i = VCO_CLK_0; i <= PCLK_MUX_0_CLK; i++) {
clk = devm_clk_register(&pdev->dev,
mdss_dsi_pllcc_10nm[i]);
@@ -1431,6 +1493,7 @@
rmap = devm_regmap_init(&pdev->dev, &mdss_mux_regmap_bus,
pll_res, &dsi_pll_10nm_config);
dsi1pll_byteclk_mux.clkr.regmap = rmap;
+ dsi1pll_vco_clk.priv = pll_res;
for (i = VCO_CLK_1; i <= PCLK_MUX_1_CLK; i++) {
clk = devm_clk_register(&pdev->dev,
diff --git a/drivers/clk/qcom/mdss/mdss-pll.c b/drivers/clk/qcom/mdss/mdss-pll.c
index 0a0d303..7f82fda 100644
--- a/drivers/clk/qcom/mdss/mdss-pll.c
+++ b/drivers/clk/qcom/mdss/mdss-pll.c
@@ -150,6 +150,7 @@
switch (pll_res->pll_interface_type) {
case MDSS_DSI_PLL_10NM:
rc = dsi_pll_clock_register_10nm(pdev, pll_res);
+ break;
case MDSS_UNKNOWN_PLL:
default:
rc = -EINVAL;
@@ -370,7 +371,7 @@
return rc;
}
-subsys_initcall(mdss_pll_driver_init);
+fs_initcall(mdss_pll_driver_init);
static void __exit mdss_pll_driver_deinit(void)
{
diff --git a/drivers/clk/qcom/mdss/mdss-pll.h b/drivers/clk/qcom/mdss/mdss-pll.h
index 28b7ca6..eccfcea 100644
--- a/drivers/clk/qcom/mdss/mdss-pll.h
+++ b/drivers/clk/qcom/mdss/mdss-pll.h
@@ -194,9 +194,7 @@
WARN(1, "gdsc_base register is not defined\n");
return true;
}
-
- return ((readl_relaxed(pll_res->gdsc_base + 0x4) & BIT(31)) &&
- (!(readl_relaxed(pll_res->gdsc_base) & BIT(0)))) ? false : true;
+ return readl_relaxed(pll_res->gdsc_base) & BIT(31) ? false : true;
}
static inline int mdss_pll_div_prepare(struct clk_hw *hw)
diff --git a/drivers/clk/qcom/videocc-sdm845.c b/drivers/clk/qcom/videocc-sdm845.c
index 8b63979..4eb8a04 100644
--- a/drivers/clk/qcom/videocc-sdm845.c
+++ b/drivers/clk/qcom/videocc-sdm845.c
@@ -151,19 +151,6 @@
},
};
-static struct clk_branch video_cc_debug_clk = {
- .halt_reg = 0xa58,
- .halt_check = BRANCH_HALT,
- .clkr = {
- .enable_reg = 0xa58,
- .enable_mask = BIT(0),
- .hw.init = &(struct clk_init_data){
- .name = "video_cc_debug_clk",
- .ops = &clk_branch2_ops,
- },
- },
-};
-
static struct clk_branch video_cc_qdss_trig_clk = {
.halt_reg = 0x970,
.halt_check = BRANCH_HALT,
@@ -299,7 +286,6 @@
static struct clk_regmap *video_cc_sdm845_clocks[] = {
[VIDEO_CC_APB_CLK] = &video_cc_apb_clk.clkr,
[VIDEO_CC_AT_CLK] = &video_cc_at_clk.clkr,
- [VIDEO_CC_DEBUG_CLK] = &video_cc_debug_clk.clkr,
[VIDEO_CC_QDSS_TRIG_CLK] = &video_cc_qdss_trig_clk.clkr,
[VIDEO_CC_QDSS_TSCTR_DIV8_CLK] = &video_cc_qdss_tsctr_div8_clk.clkr,
[VIDEO_CC_VCODEC0_AXI_CLK] = &video_cc_vcodec0_axi_clk.clkr,
diff --git a/drivers/clocksource/arm_arch_timer.c b/drivers/clocksource/arm_arch_timer.c
index 550a59c..5db1897 100644
--- a/drivers/clocksource/arm_arch_timer.c
+++ b/drivers/clocksource/arm_arch_timer.c
@@ -441,15 +441,14 @@
{
u32 cntkctl = arch_timer_get_cntkctl();
- /* Disable user access to the timers and the physical counter */
+ /* Disable user access to the timers */
/* Also disable virtual event stream */
cntkctl &= ~(ARCH_TIMER_USR_PT_ACCESS_EN
| ARCH_TIMER_USR_VT_ACCESS_EN
- | ARCH_TIMER_VIRT_EVT_EN
- | ARCH_TIMER_USR_PCT_ACCESS_EN);
+ | ARCH_TIMER_VIRT_EVT_EN);
- /* Enable user access to the virtual counter */
- cntkctl |= ARCH_TIMER_USR_VCT_ACCESS_EN;
+ /* Enable user access to the virtual and physical counters */
+ cntkctl |= ARCH_TIMER_USR_VCT_ACCESS_EN | ARCH_TIMER_USR_PCT_ACCESS_EN;
arch_timer_set_cntkctl(cntkctl);
}
diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c
index 66e604e..b315236 100644
--- a/drivers/cpufreq/cpufreq.c
+++ b/drivers/cpufreq/cpufreq.c
@@ -2480,6 +2480,20 @@
*********************************************************************/
static enum cpuhp_state hp_online;
+static int cpuhp_cpufreq_online(unsigned int cpu)
+{
+ cpufreq_online(cpu);
+
+ return 0;
+}
+
+static int cpuhp_cpufreq_offline(unsigned int cpu)
+{
+ cpufreq_offline(cpu);
+
+ return 0;
+}
+
/**
* cpufreq_register_driver - register a CPU Frequency driver
* @driver_data: A struct cpufreq_driver containing the values#
@@ -2542,8 +2556,8 @@
}
ret = cpuhp_setup_state_nocalls(CPUHP_AP_ONLINE_DYN, "cpufreq:online",
- cpufreq_online,
- cpufreq_offline);
+ cpuhp_cpufreq_online,
+ cpuhp_cpufreq_offline);
if (ret < 0)
goto err_if_unreg;
hp_online = ret;
diff --git a/drivers/dax/Kconfig b/drivers/dax/Kconfig
index 3e2ab3b..9e95bf9 100644
--- a/drivers/dax/Kconfig
+++ b/drivers/dax/Kconfig
@@ -2,6 +2,7 @@
tristate "DAX: direct access to differentiated memory"
default m if NVDIMM_DAX
depends on TRANSPARENT_HUGEPAGE
+ select SRCU
help
Support raw access to differentiated (persistence, bandwidth,
latency...) memory via an mmap(2) capable character
diff --git a/drivers/dax/dax.c b/drivers/dax/dax.c
index 152552d..1932248 100644
--- a/drivers/dax/dax.c
+++ b/drivers/dax/dax.c
@@ -24,6 +24,7 @@
#include "dax.h"
static dev_t dax_devt;
+DEFINE_STATIC_SRCU(dax_srcu);
static struct class *dax_class;
static DEFINE_IDA(dax_minor_ida);
static int nr_dax = CONFIG_NR_DEV_DAX;
@@ -59,7 +60,7 @@
* @region - parent region
* @dev - device backing the character device
* @cdev - core chardev data
- * @alive - !alive + rcu grace period == no new mappings can be established
+ * @alive - !alive + srcu grace period == no new mappings can be established
* @id - child id in the region
* @num_resources - number of physical address extents in this device
* @res - array of physical address ranges
@@ -437,7 +438,7 @@
static int dax_dev_pmd_fault(struct vm_area_struct *vma, unsigned long addr,
pmd_t *pmd, unsigned int flags)
{
- int rc;
+ int rc, id;
struct file *filp = vma->vm_file;
struct dax_dev *dax_dev = filp->private_data;
@@ -445,9 +446,9 @@
current->comm, (flags & FAULT_FLAG_WRITE)
? "write" : "read", vma->vm_start, vma->vm_end);
- rcu_read_lock();
+ id = srcu_read_lock(&dax_srcu);
rc = __dax_dev_pmd_fault(dax_dev, vma, addr, pmd, flags);
- rcu_read_unlock();
+ srcu_read_unlock(&dax_srcu, id);
return rc;
}
@@ -563,11 +564,11 @@
* Note, rcu is not protecting the liveness of dax_dev, rcu is
* ensuring that any fault handlers that might have seen
* dax_dev->alive == true, have completed. Any fault handlers
- * that start after synchronize_rcu() has started will abort
+ * that start after synchronize_srcu() has started will abort
* upon seeing dax_dev->alive == false.
*/
dax_dev->alive = false;
- synchronize_rcu();
+ synchronize_srcu(&dax_srcu);
unmap_mapping_range(dax_dev->inode->i_mapping, 0, 0, 1);
cdev_del(cdev);
device_unregister(dev);
diff --git a/drivers/devfreq/bimc-bwmon.c b/drivers/devfreq/bimc-bwmon.c
index a4a1cfb..d70104d 100644
--- a/drivers/devfreq/bimc-bwmon.c
+++ b/drivers/devfreq/bimc-bwmon.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2014-2016, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2014-2017, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -54,6 +54,11 @@
#define MON2_ZONE_CNT(m) ((m)->base + 0x2D8)
#define MON2_ZONE_MAX(m, zone) ((m)->base + 0x2E0 + 0x4 * zone)
+enum bwmon_type {
+ BWMON_1,
+ BWMON_2,
+};
+
struct bwmon_spec {
bool wrap_on_thres;
bool overflow;
@@ -65,7 +70,7 @@
void __iomem *base;
void __iomem *global_base;
unsigned int mport;
- unsigned int irq;
+ int irq;
const struct bwmon_spec *spec;
struct device *dev;
struct bw_hwmon hw;
@@ -76,7 +81,6 @@
};
#define to_bwmon(ptr) container_of(ptr, struct bwmon, hw)
-#define has_hw_sampling(m) (m->spec->hw_sampling)
#define ENABLE_MASK BIT(0)
#define THROTTLE_MASK 0x1F
@@ -86,20 +90,29 @@
#define INT_STATUS_MASK_HWS 0xF0
static DEFINE_SPINLOCK(glb_lock);
-static void mon_enable(struct bwmon *m)
+
+static __always_inline void mon_enable(struct bwmon *m, enum bwmon_type type)
{
- if (has_hw_sampling(m))
- writel_relaxed((ENABLE_MASK | m->throttle_adj), MON2_EN(m));
- else
- writel_relaxed((ENABLE_MASK | m->throttle_adj), MON_EN(m));
+ switch (type) {
+ case BWMON_1:
+ writel_relaxed(ENABLE_MASK | m->throttle_adj, MON_EN(m));
+ break;
+ case BWMON_2:
+ writel_relaxed(ENABLE_MASK | m->throttle_adj, MON2_EN(m));
+ break;
+ }
}
-static void mon_disable(struct bwmon *m)
+static __always_inline void mon_disable(struct bwmon *m, enum bwmon_type type)
{
- if (has_hw_sampling(m))
- writel_relaxed(m->throttle_adj, MON2_EN(m));
- else
+ switch (type) {
+ case BWMON_1:
writel_relaxed(m->throttle_adj, MON_EN(m));
+ break;
+ case BWMON_2:
+ writel_relaxed(m->throttle_adj, MON2_EN(m));
+ break;
+ }
/*
* mon_disable() and mon_irq_clear(),
* If latter goes first and count happen to trigger irq, we would
@@ -110,24 +123,25 @@
#define MON_CLEAR_BIT 0x1
#define MON_CLEAR_ALL_BIT 0x2
-static void mon_clear(struct bwmon *m, bool clear_all)
+static __always_inline
+void mon_clear(struct bwmon *m, bool clear_all, enum bwmon_type type)
{
- if (!has_hw_sampling(m)) {
+ switch (type) {
+ case BWMON_1:
writel_relaxed(MON_CLEAR_BIT, MON_CLEAR(m));
- goto out;
+ break;
+ case BWMON_2:
+ if (clear_all)
+ writel_relaxed(MON_CLEAR_ALL_BIT, MON2_CLEAR(m));
+ else
+ writel_relaxed(MON_CLEAR_BIT, MON2_CLEAR(m));
+ break;
}
-
- if (clear_all)
- writel_relaxed(MON_CLEAR_ALL_BIT, MON2_CLEAR(m));
- else
- writel_relaxed(MON_CLEAR_BIT, MON2_CLEAR(m));
-
/*
* The counter clear and IRQ clear bits are not in the same 4KB
* region. So, we need to make sure the counter clear is completed
* before we try to clear the IRQ or do any other counter operations.
*/
-out:
mb();
}
@@ -148,72 +162,141 @@
}
}
-static void mon_irq_enable(struct bwmon *m)
+static void mon_glb_irq_enable(struct bwmon *m)
{
u32 val;
- spin_lock(&glb_lock);
val = readl_relaxed(GLB_INT_EN(m));
val |= 1 << m->mport;
writel_relaxed(val, GLB_INT_EN(m));
-
- val = readl_relaxed(MON_INT_EN(m));
- val |= has_hw_sampling(m) ? INT_STATUS_MASK_HWS : INT_ENABLE_V1;
- writel_relaxed(val, MON_INT_EN(m));
- spin_unlock(&glb_lock);
- /*
- * make Sure irq enable complete for local and global
- * to avoid race with other monitor calls
- */
- mb();
}
-static void mon_irq_disable(struct bwmon *m)
+static __always_inline
+void mon_irq_enable(struct bwmon *m, enum bwmon_type type)
{
u32 val;
spin_lock(&glb_lock);
- val = readl_relaxed(GLB_INT_EN(m));
- val &= ~(1 << m->mport);
- writel_relaxed(val, GLB_INT_EN(m));
-
- val = readl_relaxed(MON_INT_EN(m));
- val &= has_hw_sampling(m) ? ~INT_STATUS_MASK_HWS : ~INT_ENABLE_V1;
- writel_relaxed(val, MON_INT_EN(m));
+ switch (type) {
+ case BWMON_1:
+ mon_glb_irq_enable(m);
+ val = readl_relaxed(MON_INT_EN(m));
+ val |= INT_ENABLE_V1;
+ writel_relaxed(val, MON_INT_EN(m));
+ break;
+ case BWMON_2:
+ mon_glb_irq_enable(m);
+ val = readl_relaxed(MON_INT_EN(m));
+ val |= INT_STATUS_MASK_HWS;
+ writel_relaxed(val, MON_INT_EN(m));
+ break;
+ }
spin_unlock(&glb_lock);
/*
- * make Sure irq disable complete for local and global
+ * make sure irq enable complete for local and global
* to avoid race with other monitor calls
*/
mb();
}
-static unsigned int mon_irq_status(struct bwmon *m)
+static void mon_glb_irq_disable(struct bwmon *m)
+{
+ u32 val;
+
+ val = readl_relaxed(GLB_INT_EN(m));
+ val &= ~(1 << m->mport);
+ writel_relaxed(val, GLB_INT_EN(m));
+}
+
+static __always_inline
+void mon_irq_disable(struct bwmon *m, enum bwmon_type type)
+{
+ u32 val;
+
+ spin_lock(&glb_lock);
+
+ switch (type) {
+ case BWMON_1:
+ mon_glb_irq_disable(m);
+ val = readl_relaxed(MON_INT_EN(m));
+ val &= ~INT_ENABLE_V1;
+ writel_relaxed(val, MON_INT_EN(m));
+ break;
+ case BWMON_2:
+ mon_glb_irq_disable(m);
+ val = readl_relaxed(MON_INT_EN(m));
+ val &= ~INT_STATUS_MASK_HWS;
+ writel_relaxed(val, MON_INT_EN(m));
+ break;
+ }
+ spin_unlock(&glb_lock);
+ /*
+ * make sure irq disable complete for local and global
+ * to avoid race with other monitor calls
+ */
+ mb();
+}
+
+static __always_inline
+unsigned int mon_irq_status(struct bwmon *m, enum bwmon_type type)
{
u32 mval;
- mval = readl_relaxed(MON_INT_STATUS(m));
-
- dev_dbg(m->dev, "IRQ status p:%x, g:%x\n", mval,
- readl_relaxed(GLB_INT_STATUS(m)));
-
- mval &= has_hw_sampling(m) ? INT_STATUS_MASK_HWS : INT_STATUS_MASK;
+ switch (type) {
+ case BWMON_1:
+ mval = readl_relaxed(MON_INT_STATUS(m));
+ dev_dbg(m->dev, "IRQ status p:%x, g:%x\n", mval,
+ readl_relaxed(GLB_INT_STATUS(m)));
+ mval &= INT_STATUS_MASK;
+ break;
+ case BWMON_2:
+ mval = readl_relaxed(MON_INT_STATUS(m));
+ dev_dbg(m->dev, "IRQ status p:%x, g:%x\n", mval,
+ readl_relaxed(GLB_INT_STATUS(m)));
+ mval &= INT_STATUS_MASK_HWS;
+ break;
+ }
return mval;
}
-static void mon_irq_clear(struct bwmon *m)
+
+static void mon_glb_irq_clear(struct bwmon *m)
{
- u32 intclr;
-
- intclr = has_hw_sampling(m) ? INT_STATUS_MASK_HWS : INT_STATUS_MASK;
-
- writel_relaxed(intclr, MON_INT_CLR(m));
+ /*
+ * Synchronize the local interrupt clear in mon_irq_clear()
+ * with the global interrupt clear here. Otherwise, the CPU
+ * may reorder the two writes and clear the global interrupt
+ * before the local interrupt, causing the global interrupt
+ * to be retriggered by the local interrupt still being high.
+ */
mb();
writel_relaxed(1 << m->mport, GLB_INT_CLR(m));
+ /*
+ * Similarly, because the global registers are in a different
+ * region than the local registers, we need to ensure any register
+ * writes to enable the monitor after this call are ordered with the
+ * clearing here so that local writes don't happen before the
+ * interrupt is cleared.
+ */
mb();
}
+static __always_inline
+void mon_irq_clear(struct bwmon *m, enum bwmon_type type)
+{
+ switch (type) {
+ case BWMON_1:
+ writel_relaxed(INT_STATUS_MASK, MON_INT_CLR(m));
+ mon_glb_irq_clear(m);
+ break;
+ case BWMON_2:
+ writel_relaxed(INT_STATUS_MASK_HWS, MON_INT_CLR(m));
+ mon_glb_irq_clear(m);
+ break;
+ }
+}
+
static int mon_set_throttle_adj(struct bw_hwmon *hw, uint adj)
{
struct bwmon *m = to_bwmon(hw);
@@ -331,12 +414,12 @@
#define THRES_HIT(status) (status & BIT(0))
#define OVERFLOW(status) (status & BIT(1))
-static unsigned long mon_get_count(struct bwmon *m)
+static unsigned long mon_get_count1(struct bwmon *m)
{
unsigned long count, status;
count = readl_relaxed(MON_CNT(m));
- status = mon_irq_status(m);
+ status = mon_irq_status(m, BWMON_1);
dev_dbg(m->dev, "Counter: %08lx\n", count);
@@ -385,6 +468,23 @@
return count;
}
+static __always_inline
+unsigned long mon_get_count(struct bwmon *m, enum bwmon_type type)
+{
+ unsigned long count;
+
+ switch (type) {
+ case BWMON_1:
+ count = mon_get_count1(m);
+ break;
+ case BWMON_2:
+ count = mon_get_zone_stats(m);
+ break;
+ }
+
+ return count;
+}
+
/* ********** CPUBW specific code ********** */
/* Returns MBps of read/writes for the sampling window. */
@@ -398,30 +498,41 @@
return mbps;
}
-static unsigned long get_bytes_and_clear(struct bw_hwmon *hw)
+static __always_inline
+unsigned long __get_bytes_and_clear(struct bw_hwmon *hw, enum bwmon_type type)
{
struct bwmon *m = to_bwmon(hw);
unsigned long count;
- mon_disable(m);
- count = has_hw_sampling(m) ? mon_get_zone_stats(m) : mon_get_count(m);
- mon_clear(m, false);
- mon_irq_clear(m);
- mon_enable(m);
+ mon_disable(m, type);
+ count = mon_get_count(m, type);
+ mon_clear(m, false, type);
+ mon_irq_clear(m, type);
+ mon_enable(m, type);
return count;
}
+static unsigned long get_bytes_and_clear(struct bw_hwmon *hw)
+{
+ return __get_bytes_and_clear(hw, BWMON_1);
+}
+
+static unsigned long get_bytes_and_clear2(struct bw_hwmon *hw)
+{
+ return __get_bytes_and_clear(hw, BWMON_2);
+}
+
static unsigned long set_thres(struct bw_hwmon *hw, unsigned long bytes)
{
unsigned long count;
u32 limit;
struct bwmon *m = to_bwmon(hw);
- mon_disable(m);
- count = mon_get_count(m);
- mon_clear(m, false);
- mon_irq_clear(m);
+ mon_disable(m, BWMON_1);
+ count = mon_get_count1(m);
+ mon_clear(m, false, BWMON_1);
+ mon_irq_clear(m, BWMON_1);
if (likely(!m->spec->wrap_on_thres))
limit = bytes;
@@ -429,7 +540,7 @@
limit = max(bytes, 500000UL);
mon_set_limit(m, limit);
- mon_enable(m);
+ mon_enable(m, BWMON_1);
return count;
}
@@ -438,21 +549,22 @@
{
struct bwmon *m = to_bwmon(hw);
- mon_disable(m);
- mon_clear(m, false);
- mon_irq_clear(m);
+ mon_disable(m, BWMON_2);
+ mon_clear(m, false, BWMON_2);
+ mon_irq_clear(m, BWMON_2);
mon_set_zones(m, sample_ms);
- mon_enable(m);
+ mon_enable(m, BWMON_2);
return 0;
}
-static irqreturn_t bwmon_intr_handler(int irq, void *dev)
+static irqreturn_t
+__bwmon_intr_handler(int irq, void *dev, enum bwmon_type type)
{
struct bwmon *m = dev;
- m->intr_status = mon_irq_status(m);
+ m->intr_status = mon_irq_status(m, type);
if (!m->intr_status)
return IRQ_NONE;
@@ -462,6 +574,16 @@
return IRQ_HANDLED;
}
+static irqreturn_t bwmon_intr_handler(int irq, void *dev)
+{
+ return __bwmon_intr_handler(irq, dev, BWMON_1);
+}
+
+static irqreturn_t bwmon_intr_handler2(int irq, void *dev)
+{
+ return __bwmon_intr_handler(irq, dev, BWMON_2);
+}
+
static irqreturn_t bwmon_intr_thread(int irq, void *dev)
{
struct bwmon *m = dev;
@@ -470,98 +592,180 @@
return IRQ_HANDLED;
}
-static int start_bw_hwmon(struct bw_hwmon *hw, unsigned long mbps)
+static __always_inline int
+__start_bw_hwmon(struct bw_hwmon *hw, unsigned long mbps, enum bwmon_type type)
{
struct bwmon *m = to_bwmon(hw);
- u32 limit;
- u32 zone_actions = calc_zone_actions();
+ u32 limit, zone_actions;
int ret;
+ irq_handler_t handler;
- ret = request_threaded_irq(m->irq, bwmon_intr_handler,
- bwmon_intr_thread,
+ switch (type) {
+ case BWMON_1:
+ handler = bwmon_intr_handler;
+ limit = mbps_to_bytes(mbps, hw->df->profile->polling_ms, 0);
+ break;
+ case BWMON_2:
+ zone_actions = calc_zone_actions();
+ handler = bwmon_intr_handler2;
+ break;
+ }
+
+ ret = request_threaded_irq(m->irq, handler, bwmon_intr_thread,
IRQF_ONESHOT | IRQF_SHARED,
dev_name(m->dev), m);
if (ret) {
dev_err(m->dev, "Unable to register interrupt handler! (%d)\n",
- ret);
+ ret);
return ret;
}
- mon_disable(m);
+ mon_disable(m, type);
- mon_clear(m, true);
- limit = mbps_to_bytes(mbps, hw->df->profile->polling_ms, 0);
- if (has_hw_sampling(m)) {
+ mon_clear(m, false, type);
+
+ switch (type) {
+ case BWMON_1:
+ handler = bwmon_intr_handler;
+ mon_set_limit(m, limit);
+ break;
+ case BWMON_2:
mon_set_zones(m, hw->df->profile->polling_ms);
/* Set the zone actions to increment appropriate counters */
writel_relaxed(zone_actions, MON2_ZONE_ACTIONS(m));
- } else {
- mon_set_limit(m, limit);
+ break;
}
- mon_irq_clear(m);
- mon_irq_enable(m);
- mon_enable(m);
+ mon_irq_clear(m, type);
+ mon_irq_enable(m, type);
+ mon_enable(m, type);
return 0;
}
-static void stop_bw_hwmon(struct bw_hwmon *hw)
+static int start_bw_hwmon(struct bw_hwmon *hw, unsigned long mbps)
+{
+ return __start_bw_hwmon(hw, mbps, BWMON_1);
+}
+
+static int start_bw_hwmon2(struct bw_hwmon *hw, unsigned long mbps)
+{
+ return __start_bw_hwmon(hw, mbps, BWMON_2);
+}
+
+static __always_inline
+void __stop_bw_hwmon(struct bw_hwmon *hw, enum bwmon_type type)
{
struct bwmon *m = to_bwmon(hw);
- mon_irq_disable(m);
+ mon_irq_disable(m, type);
free_irq(m->irq, m);
- mon_disable(m);
- mon_clear(m, true);
- mon_irq_clear(m);
+ mon_disable(m, type);
+ mon_clear(m, true, type);
+ mon_irq_clear(m, type);
+}
+
+static void stop_bw_hwmon(struct bw_hwmon *hw)
+{
+ return __stop_bw_hwmon(hw, BWMON_1);
+}
+
+static void stop_bw_hwmon2(struct bw_hwmon *hw)
+{
+ return __stop_bw_hwmon(hw, BWMON_2);
+}
+
+static __always_inline
+int __suspend_bw_hwmon(struct bw_hwmon *hw, enum bwmon_type type)
+{
+ struct bwmon *m = to_bwmon(hw);
+
+ mon_irq_disable(m, type);
+ free_irq(m->irq, m);
+ mon_disable(m, type);
+ mon_irq_clear(m, type);
+
+ return 0;
}
static int suspend_bw_hwmon(struct bw_hwmon *hw)
{
- struct bwmon *m = to_bwmon(hw);
+ return __suspend_bw_hwmon(hw, BWMON_1);
+}
- mon_irq_disable(m);
- free_irq(m->irq, m);
- mon_disable(m);
- mon_irq_clear(m);
+static int suspend_bw_hwmon2(struct bw_hwmon *hw)
+{
+ return __suspend_bw_hwmon(hw, BWMON_2);
+}
+
+static int __resume_bw_hwmon(struct bw_hwmon *hw, enum bwmon_type type)
+{
+ struct bwmon *m = to_bwmon(hw);
+ int ret;
+ irq_handler_t handler;
+
+ switch (type) {
+ case BWMON_1:
+ handler = bwmon_intr_handler;
+ break;
+ case BWMON_2:
+ handler = bwmon_intr_handler2;
+ break;
+ }
+
+ mon_clear(m, false, type);
+ ret = request_threaded_irq(m->irq, handler, bwmon_intr_thread,
+ IRQF_ONESHOT | IRQF_SHARED,
+ dev_name(m->dev), m);
+ if (ret) {
+ dev_err(m->dev, "Unable to register interrupt handler! (%d)\n",
+ ret);
+ return ret;
+ }
+
+ mon_irq_enable(m, type);
+ mon_enable(m, type);
return 0;
}
static int resume_bw_hwmon(struct bw_hwmon *hw)
{
- struct bwmon *m = to_bwmon(hw);
- int ret;
+ return __resume_bw_hwmon(hw, BWMON_1);
+}
- mon_clear(m, false);
- ret = request_threaded_irq(m->irq, bwmon_intr_handler,
- bwmon_intr_thread,
- IRQF_ONESHOT | IRQF_SHARED,
- dev_name(m->dev), m);
- if (ret) {
- dev_err(m->dev, "Unable to register interrupt handler! (%d)\n",
- ret);
- return ret;
- }
-
- mon_irq_enable(m);
- mon_enable(m);
-
- return 0;
+static int resume_bw_hwmon2(struct bw_hwmon *hw)
+{
+ return __resume_bw_hwmon(hw, BWMON_2);
}
/*************************************************************************/
static const struct bwmon_spec spec[] = {
- { .wrap_on_thres = true, .overflow = false, .throt_adj = false,
- .hw_sampling = false},
- { .wrap_on_thres = false, .overflow = true, .throt_adj = false,
- .hw_sampling = false},
- { .wrap_on_thres = false, .overflow = true, .throt_adj = true,
- .hw_sampling = false},
- { .wrap_on_thres = false, .overflow = true, .throt_adj = true,
- .hw_sampling = true},
+ [0] = {
+ .wrap_on_thres = true,
+ .overflow = false,
+ .throt_adj = false,
+ .hw_sampling = false
+ },
+ [1] = {
+ .wrap_on_thres = false,
+ .overflow = true,
+ .throt_adj = false,
+ .hw_sampling = false
+ },
+ [2] = {
+ .wrap_on_thres = false,
+ .overflow = true,
+ .throt_adj = true,
+ .hw_sampling = false
+ },
+ [3] = {
+ .wrap_on_thres = false,
+ .overflow = true,
+ .throt_adj = true,
+ .hw_sampling = true
+ },
};
static const struct of_device_id bimc_bwmon_match_table[] = {
@@ -577,7 +781,6 @@
struct device *dev = &pdev->dev;
struct resource *res;
struct bwmon *m;
- const struct of_device_id *id;
int ret;
u32 data;
@@ -593,22 +796,11 @@
}
m->mport = data;
- id = of_match_device(bimc_bwmon_match_table, dev);
- if (!id) {
+ m->spec = of_device_get_match_data(dev);
+ if (!m->spec) {
dev_err(dev, "Unknown device type!\n");
return -ENODEV;
}
- m->spec = id->data;
-
- if (has_hw_sampling(m)) {
- ret = of_property_read_u32(dev->of_node,
- "qcom,hw-timer-hz", &data);
- if (ret) {
- dev_err(dev, "HW sampling rate not specified!\n");
- return ret;
- }
- m->hw_timer_hz = data;
- }
res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "base");
if (!res) {
@@ -641,17 +833,33 @@
m->hw.of_node = of_parse_phandle(dev->of_node, "qcom,target-dev", 0);
if (!m->hw.of_node)
return -EINVAL;
- m->hw.start_hwmon = &start_bw_hwmon;
- m->hw.stop_hwmon = &stop_bw_hwmon;
- m->hw.suspend_hwmon = &suspend_bw_hwmon;
- m->hw.resume_hwmon = &resume_bw_hwmon;
- m->hw.get_bytes_and_clear = &get_bytes_and_clear;
- m->hw.set_thres = &set_thres;
- if (has_hw_sampling(m))
- m->hw.set_hw_events = &set_hw_events;
+
+ if (m->spec->hw_sampling) {
+ ret = of_property_read_u32(dev->of_node, "qcom,hw-timer-hz",
+ &m->hw_timer_hz);
+ if (ret) {
+ dev_err(dev, "HW sampling rate not specified!\n");
+ return ret;
+ }
+
+ m->hw.start_hwmon = start_bw_hwmon2;
+ m->hw.stop_hwmon = stop_bw_hwmon2;
+ m->hw.suspend_hwmon = suspend_bw_hwmon2;
+ m->hw.resume_hwmon = resume_bw_hwmon2;
+ m->hw.get_bytes_and_clear = get_bytes_and_clear2;
+ m->hw.set_hw_events = set_hw_events;
+ } else {
+ m->hw.start_hwmon = start_bw_hwmon;
+ m->hw.stop_hwmon = stop_bw_hwmon;
+ m->hw.suspend_hwmon = suspend_bw_hwmon;
+ m->hw.resume_hwmon = resume_bw_hwmon;
+ m->hw.get_bytes_and_clear = get_bytes_and_clear;
+ m->hw.set_thres = set_thres;
+ }
+
if (m->spec->throt_adj) {
- m->hw.set_throttle_adj = &mon_set_throttle_adj;
- m->hw.get_throttle_adj = &mon_get_throttle_adj;
+ m->hw.set_throttle_adj = mon_set_throttle_adj;
+ m->hw.get_throttle_adj = mon_get_throttle_adj;
}
ret = register_bw_hwmon(dev, &m->hw);
diff --git a/drivers/devfreq/devfreq.c b/drivers/devfreq/devfreq.c
index 5b85b8d..8f582f6 100644
--- a/drivers/devfreq/devfreq.c
+++ b/drivers/devfreq/devfreq.c
@@ -70,6 +70,29 @@
}
/**
+ * devfreq_set_freq_limits() - Set min and max frequency from freq_table
+ * @devfreq: the devfreq instance
+ */
+static void devfreq_set_freq_limits(struct devfreq *devfreq)
+{
+ int idx;
+ unsigned long min = ~0, max = 0;
+
+ if (!devfreq->profile->freq_table)
+ return;
+
+ for (idx = 0; idx < devfreq->profile->max_state; idx++) {
+ if (min > devfreq->profile->freq_table[idx])
+ min = devfreq->profile->freq_table[idx];
+ if (max < devfreq->profile->freq_table[idx])
+ max = devfreq->profile->freq_table[idx];
+ }
+
+ devfreq->min_freq = min;
+ devfreq->max_freq = max;
+}
+
+/**
* devfreq_get_freq_level() - Lookup freq_table for the frequency
* @devfreq: the devfreq instance
* @freq: the target frequency
@@ -569,6 +592,7 @@
devfreq_set_freq_table(devfreq);
mutex_lock(&devfreq->lock);
}
+ devfreq_set_freq_limits(devfreq);
dev_set_name(&devfreq->dev, "%s", dev_name(dev));
err = device_register(&devfreq->dev);
diff --git a/drivers/devfreq/governor_bw_hwmon.c b/drivers/devfreq/governor_bw_hwmon.c
index d7cc425..53c0f8a 100644
--- a/drivers/devfreq/governor_bw_hwmon.c
+++ b/drivers/devfreq/governor_bw_hwmon.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2013-2016, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2013-2017, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -143,25 +143,27 @@
{ \
struct devfreq *df = to_devfreq(dev); \
struct hwmon_node *hw = df->data; \
- int ret; \
+ int ret, numvals; \
unsigned int i = 0, val; \
+ char **strlist; \
\
- do { \
- ret = kstrtoint(buf, 10, &val); \
+ strlist = argv_split(GFP_KERNEL, buf, &numvals); \
+ if (!strlist) \
+ return -ENOMEM; \
+ numvals = min(numvals, n - 1); \
+ for (i = 0; i < numvals; i++) { \
+ ret = kstrtouint(strlist[i], 10, &val); \
if (ret) \
- break; \
- buf = strnchr(buf, PAGE_SIZE, ' '); \
- if (buf) \
- buf++; \
+ goto out; \
val = max(val, _min); \
val = min(val, _max); \
hw->name[i] = val; \
- i++; \
- } while (buf && i < n - 1); \
- if (i < 1) \
- return -EINVAL; \
+ } \
+ ret = count; \
+out: \
+ argv_free(strlist); \
hw->name[i] = 0; \
- return count; \
+ return ret; \
}
#define gov_list_attr(__attr, n, min, max) \
diff --git a/drivers/edac/Kconfig b/drivers/edac/Kconfig
index 192080e..13b8b71 100644
--- a/drivers/edac/Kconfig
+++ b/drivers/edac/Kconfig
@@ -514,6 +514,17 @@
For debugging issues having to do with stability and overall system
health, you should probably say 'Y' here.
+config EDAC_LLCC_POLL
+ depends on EDAC_QCOM_LLCC
+ bool "Poll on LLCC ECC registers - LLCC"
+ help
+ This option chooses whether or not you want to poll on the LLCC
+ ECC registers. When this is enabled, the polling rate can be set as
+ a module parameter. By default, it will call the polling function
+ every second.
+ This option should only be used if the associated interrupt lines
+ are not enabled.
+
config EDAC_QCOM_LLCC_PANIC_ON_CE
depends on EDAC_QCOM_LLCC
bool "panic on correctable errors - qcom llcc"
diff --git a/drivers/edac/qcom_llcc_edac.c b/drivers/edac/qcom_llcc_edac.c
index 6bec860..4403f86 100644
--- a/drivers/edac/qcom_llcc_edac.c
+++ b/drivers/edac/qcom_llcc_edac.c
@@ -78,10 +78,12 @@
#define DRP_TRP_INT_CLEAR 0x3
#define DRP_TRP_CNT_CLEAR 0x3
+#ifdef CONFIG_EDAC_LLCC_POLL
static int poll_msec = 5000;
module_param(poll_msec, int, 0444);
+#endif
-static int interrupt_mode;
+static int interrupt_mode = 1;
module_param(interrupt_mode, int, 0444);
MODULE_PARM_DESC(interrupt_mode,
"Controls whether to use interrupt or poll mode");
@@ -331,10 +333,12 @@
}
}
+#ifdef CONFIG_EDAC_LLCC_POLL
static void qcom_llcc_poll_cache_errors(struct edac_device_ctl_info *edev_ctl)
{
qcom_llcc_check_cache_errors(edev_ctl);
}
+#endif
static irqreturn_t llcc_ecc_irq_handler
(int irq, void *edev_ctl)
@@ -360,9 +364,11 @@
edev_ctl->mod_name = dev_name(dev);
edev_ctl->dev_name = dev_name(dev);
edev_ctl->ctl_name = "llcc";
+#ifdef CONFIG_EDAC_LLCC_POLL
edev_ctl->poll_msec = poll_msec;
edev_ctl->edac_check = qcom_llcc_poll_cache_errors;
edev_ctl->defer_work = 1;
+#endif
edev_ctl->panic_on_ce = LLCC_ERP_PANIC_ON_CE;
edev_ctl->panic_on_ue = LLCC_ERP_PANIC_ON_UE;
@@ -383,7 +389,7 @@
}
rc = devm_request_irq(dev, drv->ecc_irq, llcc_ecc_irq_handler,
- IRQF_TRIGGER_RISING, "llcc_ecc", edev_ctl);
+ IRQF_TRIGGER_HIGH, "llcc_ecc", edev_ctl);
if (rc) {
dev_err(dev, "failed to request ecc irq\n");
goto out;
diff --git a/drivers/firmware/efi/libstub/gop.c b/drivers/firmware/efi/libstub/gop.c
index 932742e..24c461d 100644
--- a/drivers/firmware/efi/libstub/gop.c
+++ b/drivers/firmware/efi/libstub/gop.c
@@ -149,7 +149,8 @@
status = __gop_query32(sys_table_arg, gop32, &info, &size,
¤t_fb_base);
- if (status == EFI_SUCCESS && (!first_gop || conout_found)) {
+ if (status == EFI_SUCCESS && (!first_gop || conout_found) &&
+ info->pixel_format != PIXEL_BLT_ONLY) {
/*
* Systems that use the UEFI Console Splitter may
* provide multiple GOP devices, not all of which are
@@ -266,7 +267,8 @@
status = __gop_query64(sys_table_arg, gop64, &info, &size,
¤t_fb_base);
- if (status == EFI_SUCCESS && (!first_gop || conout_found)) {
+ if (status == EFI_SUCCESS && (!first_gop || conout_found) &&
+ info->pixel_format != PIXEL_BLT_ONLY) {
/*
* Systems that use the UEFI Console Splitter may
* provide multiple GOP devices, not all of which are
diff --git a/drivers/gpu/drm/etnaviv/etnaviv_gpu.c b/drivers/gpu/drm/etnaviv/etnaviv_gpu.c
index b87d278..a336754 100644
--- a/drivers/gpu/drm/etnaviv/etnaviv_gpu.c
+++ b/drivers/gpu/drm/etnaviv/etnaviv_gpu.c
@@ -1305,7 +1305,7 @@
if (!fence) {
event_free(gpu, event);
ret = -ENOMEM;
- goto out_pm_put;
+ goto out_unlock;
}
gpu->event[event].fence = fence;
@@ -1345,6 +1345,7 @@
hangcheck_timer_reset(gpu);
ret = 0;
+out_unlock:
mutex_unlock(&gpu->lock);
out_pm_put:
diff --git a/drivers/gpu/drm/msm/Makefile b/drivers/gpu/drm/msm/Makefile
index b5d78b1..4112bef 100644
--- a/drivers/gpu/drm/msm/Makefile
+++ b/drivers/gpu/drm/msm/Makefile
@@ -109,6 +109,7 @@
dsi-staging/dsi_ctrl_hw_cmn.o \
dsi-staging/dsi_ctrl_hw_1_4.o \
dsi-staging/dsi_ctrl_hw_2_0.o \
+ dsi-staging/dsi_ctrl_hw_2_2.o \
dsi-staging/dsi_ctrl.o \
dsi-staging/dsi_catalog.o \
dsi-staging/dsi_drm.o \
diff --git a/drivers/gpu/drm/msm/dsi-staging/dsi_catalog.c b/drivers/gpu/drm/msm/dsi-staging/dsi_catalog.c
index 976be99..3625ed0 100644
--- a/drivers/gpu/drm/msm/dsi-staging/dsi_catalog.c
+++ b/drivers/gpu/drm/msm/dsi-staging/dsi_catalog.c
@@ -83,6 +83,19 @@
ctrl->ops.clamp_enable = NULL;
ctrl->ops.clamp_disable = NULL;
break;
+ case DSI_CTRL_VERSION_2_2:
+ ctrl->ops.phy_reset_config = dsi_ctrl_hw_22_phy_reset_config;
+ ctrl->ops.setup_lane_map = dsi_ctrl_hw_20_setup_lane_map;
+ ctrl->ops.wait_for_lane_idle =
+ dsi_ctrl_hw_20_wait_for_lane_idle;
+ ctrl->ops.reg_dump_to_buffer =
+ dsi_ctrl_hw_20_reg_dump_to_buffer;
+ ctrl->ops.ulps_ops.ulps_request = NULL;
+ ctrl->ops.ulps_ops.ulps_exit = NULL;
+ ctrl->ops.ulps_ops.get_lanes_in_ulps = NULL;
+ ctrl->ops.clamp_enable = NULL;
+ ctrl->ops.clamp_disable = NULL;
+ break;
default:
break;
}
@@ -121,6 +134,7 @@
switch (version) {
case DSI_CTRL_VERSION_1_4:
case DSI_CTRL_VERSION_2_0:
+ case DSI_CTRL_VERSION_2_2:
dsi_catalog_cmn_init(ctrl, version);
break;
default:
@@ -167,6 +181,8 @@
dsi_phy_hw_v3_0_ulps_exit;
phy->ops.ulps_ops.get_lanes_in_ulps =
dsi_phy_hw_v3_0_get_lanes_in_ulps;
+ phy->ops.ulps_ops.is_lanes_in_ulps =
+ dsi_phy_hw_v3_0_is_lanes_in_ulps;
phy->ops.phy_timing_val = dsi_phy_hw_timing_val_v3_0;
}
diff --git a/drivers/gpu/drm/msm/dsi-staging/dsi_catalog.h b/drivers/gpu/drm/msm/dsi-staging/dsi_catalog.h
index 4a6a934..5dcdf46 100644
--- a/drivers/gpu/drm/msm/dsi-staging/dsi_catalog.h
+++ b/drivers/gpu/drm/msm/dsi-staging/dsi_catalog.h
@@ -97,6 +97,7 @@
void dsi_phy_hw_v3_0_ulps_exit(struct dsi_phy_hw *phy,
struct dsi_phy_cfg *cfg, u32 lanes);
u32 dsi_phy_hw_v3_0_get_lanes_in_ulps(struct dsi_phy_hw *phy);
+bool dsi_phy_hw_v3_0_is_lanes_in_ulps(u32 lanes, u32 ulps_lanes);
int dsi_phy_hw_timing_val_v3_0(struct dsi_phy_per_lane_cfgs *timing_cfg,
u32 *timing_val, u32 size);
@@ -157,6 +158,8 @@
void dsi_ctrl_hw_dln0_phy_err(struct dsi_ctrl_hw *ctrl);
void dsi_ctrl_hw_cmn_phy_reset_config(struct dsi_ctrl_hw *ctrl,
bool enable);
+void dsi_ctrl_hw_22_phy_reset_config(struct dsi_ctrl_hw *ctrl,
+ bool enable);
/* Definitions specific to 1.4 DSI controller hardware */
int dsi_ctrl_hw_14_wait_for_lane_idle(struct dsi_ctrl_hw *ctrl, u32 lanes);
diff --git a/drivers/gpu/drm/msm/dsi-staging/dsi_clk_manager.c b/drivers/gpu/drm/msm/dsi-staging/dsi_clk_manager.c
index cc87775..560964e 100644
--- a/drivers/gpu/drm/msm/dsi-staging/dsi_clk_manager.c
+++ b/drivers/gpu/drm/msm/dsi-staging/dsi_clk_manager.c
@@ -236,32 +236,52 @@
return rc;
error_disable_mmss_clk:
- clk_disable_unprepare(c_clks->clks.core_mmss_clk);
+ if (c_clks->clks.core_mmss_clk)
+ clk_disable_unprepare(c_clks->clks.core_mmss_clk);
error_disable_bus_clk:
- clk_disable_unprepare(c_clks->clks.bus_clk);
+ if (c_clks->clks.bus_clk)
+ clk_disable_unprepare(c_clks->clks.bus_clk);
error_disable_iface_clk:
- clk_disable_unprepare(c_clks->clks.iface_clk);
+ if (c_clks->clks.iface_clk)
+ clk_disable_unprepare(c_clks->clks.iface_clk);
error_disable_mnoc_clk:
if (c_clks->clks.mnoc_clk)
clk_disable_unprepare(c_clks->clks.mnoc_clk);
error_disable_core_clk:
- clk_disable_unprepare(c_clks->clks.mdp_core_clk);
+ if (c_clks->clks.mdp_core_clk)
+ clk_disable_unprepare(c_clks->clks.mdp_core_clk);
error:
return rc;
}
int dsi_core_clk_stop(struct dsi_core_clks *c_clks)
{
- if (msm_bus_scale_client_update_request(c_clks->bus_handle, 0))
- pr_err("bus scale client disable failed\n");
- clk_disable_unprepare(c_clks->clks.core_mmss_clk);
- clk_disable_unprepare(c_clks->clks.bus_clk);
- clk_disable_unprepare(c_clks->clks.iface_clk);
+ int rc = 0;
+
+ if (c_clks->bus_handle) {
+ rc = msm_bus_scale_client_update_request(c_clks->bus_handle, 0);
+ if (rc) {
+ pr_err("bus scale client disable failed, rc=%d\n", rc);
+ return rc;
+ }
+ }
+
+ if (c_clks->clks.core_mmss_clk)
+ clk_disable_unprepare(c_clks->clks.core_mmss_clk);
+
+ if (c_clks->clks.bus_clk)
+ clk_disable_unprepare(c_clks->clks.bus_clk);
+
+ if (c_clks->clks.iface_clk)
+ clk_disable_unprepare(c_clks->clks.iface_clk);
+
if (c_clks->clks.mnoc_clk)
clk_disable_unprepare(c_clks->clks.mnoc_clk);
- clk_disable_unprepare(c_clks->clks.mdp_core_clk);
- return 0;
+ if (c_clks->clks.mdp_core_clk)
+ clk_disable_unprepare(c_clks->clks.mdp_core_clk);
+
+ return rc;
}
static int dsi_link_clk_set_rate(struct dsi_link_clks *l_clks)
diff --git a/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl.c b/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl.c
index 5df48c3..9a71ea0 100644
--- a/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl.c
+++ b/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl.c
@@ -62,6 +62,7 @@
static const enum dsi_ctrl_version dsi_ctrl_v1_4 = DSI_CTRL_VERSION_1_4;
static const enum dsi_ctrl_version dsi_ctrl_v2_0 = DSI_CTRL_VERSION_2_0;
+static const enum dsi_ctrl_version dsi_ctrl_v2_2 = DSI_CTRL_VERSION_2_2;
static const struct of_device_id msm_dsi_of_match[] = {
{
@@ -72,6 +73,10 @@
.compatible = "qcom,dsi-ctrl-hw-v2.0",
.data = &dsi_ctrl_v2_0,
},
+ {
+ .compatible = "qcom,dsi-ctrl-hw-v2.2",
+ .data = &dsi_ctrl_v2_2,
+ },
{}
};
@@ -428,15 +433,34 @@
pr_debug("[%s] map dsi_ctrl registers to %p\n", ctrl->name,
ctrl->hw.base);
- ptr = msm_ioremap(pdev, "mmss_misc", ctrl->name);
- if (IS_ERR(ptr)) {
- rc = PTR_ERR(ptr);
- return rc;
+ switch (ctrl->version) {
+ case DSI_CTRL_VERSION_1_4:
+ case DSI_CTRL_VERSION_2_0:
+ ptr = msm_ioremap(pdev, "mmss_misc", ctrl->name);
+ if (IS_ERR(ptr)) {
+ pr_err("mmss_misc base address not found for [%s]\n",
+ ctrl->name);
+ rc = PTR_ERR(ptr);
+ return rc;
+ }
+ ctrl->hw.mmss_misc_base = ptr;
+ ctrl->hw.disp_cc_base = NULL;
+ break;
+ case DSI_CTRL_VERSION_2_2:
+ ptr = msm_ioremap(pdev, "disp_cc_base", ctrl->name);
+ if (IS_ERR(ptr)) {
+ pr_err("disp_cc base address not found for [%s]\n",
+ ctrl->name);
+ rc = PTR_ERR(ptr);
+ return rc;
+ }
+ ctrl->hw.disp_cc_base = ptr;
+ ctrl->hw.mmss_misc_base = NULL;
+ break;
+ default:
+ break;
}
- ctrl->hw.mmss_misc_base = ptr;
- pr_debug("[%s] map mmss_misc registers to %p\n", ctrl->name,
- ctrl->hw.mmss_misc_base);
return rc;
}
@@ -532,7 +556,7 @@
goto fail;
}
- link->esc_clk = devm_clk_get(&pdev->dev, "core_clk");
+ link->esc_clk = devm_clk_get(&pdev->dev, "esc_clk");
if (IS_ERR(link->esc_clk)) {
rc = PTR_ERR(link->esc_clk);
pr_err("failed to get esc_clk, rc=%d\n", rc);
@@ -613,10 +637,8 @@
rc = dsi_pwr_get_dt_vreg_data(&pdev->dev,
&ctrl->pwr_info.digital,
"qcom,core-supply-entries");
- if (rc) {
- pr_err("failed to get digital supply, rc = %d\n", rc);
- goto error;
- }
+ if (rc)
+ pr_debug("failed to get digital supply, rc = %d\n", rc);
rc = dsi_pwr_get_dt_vreg_data(&pdev->dev,
&ctrl->pwr_info.host_pwr,
@@ -663,10 +685,10 @@
ctrl->pwr_info.host_pwr.vregs = NULL;
ctrl->pwr_info.host_pwr.count = 0;
error_digital:
- devm_kfree(&pdev->dev, ctrl->pwr_info.digital.vregs);
+ if (ctrl->pwr_info.digital.vregs)
+ devm_kfree(&pdev->dev, ctrl->pwr_info.digital.vregs);
ctrl->pwr_info.digital.vregs = NULL;
ctrl->pwr_info.digital.count = 0;
-error:
return rc;
}
@@ -1204,6 +1226,7 @@
}
dsi_ctrl->cell_index = index;
+ dsi_ctrl->version = version;
dsi_ctrl->name = of_get_property(pdev->dev.of_node, "label", NULL);
if (!dsi_ctrl->name)
@@ -1227,7 +1250,6 @@
goto fail_clks;
}
- dsi_ctrl->version = version;
rc = dsi_catalog_ctrl_setup(&dsi_ctrl->hw, dsi_ctrl->version,
dsi_ctrl->cell_index);
if (rc) {
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 161024a..859d707 100644
--- a/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl_hw.h
+++ b/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl_hw.h
@@ -41,6 +41,7 @@
DSI_CTRL_VERSION_UNKNOWN,
DSI_CTRL_VERSION_1_4,
DSI_CTRL_VERSION_2_0,
+ DSI_CTRL_VERSION_2_2,
DSI_CTRL_VERSION_MAX
};
@@ -575,18 +576,26 @@
/*
* struct dsi_ctrl_hw - DSI controller hardware object specific to an instance
- * @base: VA for the DSI controller base address.
- * @length: Length of the DSI controller register map.
- * @index: Instance ID of the controller.
- * @feature_map: Features supported by the DSI controller.
- * @ops: Function pointers to the operations supported by the
- * controller.
+ * @base: VA for the DSI controller base address.
+ * @length: Length of the DSI controller register map.
+ * @mmss_misc_base: Base address of mmss_misc register map.
+ * @mmss_misc_length: Length of mmss_misc register map.
+ * @disp_cc_base: Base address of disp_cc register map.
+ * @disp_cc_length: Length of disp_cc register map.
+ * @index: Instance ID of the controller.
+ * @feature_map: Features supported by the DSI controller.
+ * @ops: Function pointers to the operations supported by the
+ * controller.
+ * @supported_interrupts: Number of supported interrupts.
+ * @supported_errors: Number of supported errors.
*/
struct dsi_ctrl_hw {
void __iomem *base;
u32 length;
void __iomem *mmss_misc_base;
u32 mmss_misc_length;
+ void __iomem *disp_cc_base;
+ u32 disp_cc_length;
u32 index;
/* features */
diff --git a/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl_hw_2_2.c b/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl_hw_2_2.c
new file mode 100644
index 0000000..1b1e811
--- /dev/null
+++ b/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl_hw_2_2.c
@@ -0,0 +1,42 @@
+/*
+ * Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#define pr_fmt(fmt) "dsi-hw:" fmt
+
+#include "dsi_ctrl_hw.h"
+#include "dsi_ctrl_reg.h"
+#include "dsi_hw.h"
+
+/* Equivalent to register DISP_CC_MISC_CMD */
+#define DISP_CC_CLAMP_REG_OFF 0x00
+
+/**
+ * dsi_ctrl_hw_22_phy_reset_config() - to configure clamp control during ulps
+ * @ctrl: Pointer to the controller host hardware.
+ * @enable: boolean to specify enable/disable.
+ */
+void dsi_ctrl_hw_22_phy_reset_config(struct dsi_ctrl_hw *ctrl,
+ bool enable)
+{
+ u32 reg = 0;
+
+ reg = DSI_DISP_CC_R32(ctrl, DISP_CC_CLAMP_REG_OFF);
+
+ /* Mask/unmask disable PHY reset bit */
+ if (enable)
+ reg &= ~BIT(ctrl->index);
+ else
+ reg |= BIT(ctrl->index);
+ DSI_DISP_CC_W32(ctrl, DISP_CC_CLAMP_REG_OFF, reg);
+}
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 8605338..122a63d 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
@@ -320,8 +320,8 @@
reg |= (common_cfg->bit_swap_green ? BIT(4) : 0);
reg |= (common_cfg->bit_swap_blue ? BIT(8) : 0);
DSI_W32(ctrl, DSI_VIDEO_MODE_DATA_CTRL, reg);
- /* Enable Timing double buffering */
- DSI_W32(ctrl, DSI_DSI_TIMING_DB_MODE, 0x1);
+ /* Disable Timing double buffering */
+ DSI_W32(ctrl, DSI_DSI_TIMING_DB_MODE, 0x0);
pr_debug("[DSI_%d] Video engine setup done\n", ctrl->index);
diff --git a/drivers/gpu/drm/msm/dsi-staging/dsi_display.c b/drivers/gpu/drm/msm/dsi-staging/dsi_display.c
index 2c5bd76..106511c 100644
--- a/drivers/gpu/drm/msm/dsi-staging/dsi_display.c
+++ b/drivers/gpu/drm/msm/dsi-staging/dsi_display.c
@@ -260,7 +260,8 @@
return rc;
}
- rc = dsi_phy_set_ulps(m_ctrl->phy, &display->config, enable);
+ rc = dsi_phy_set_ulps(m_ctrl->phy, &display->config, enable,
+ display->clamp_enabled);
if (rc) {
pr_err("Ulps PHY state change(%d) failed\n", enable);
return rc;
@@ -278,7 +279,8 @@
return rc;
}
- rc = dsi_phy_set_ulps(ctrl->phy, &display->config, enable);
+ rc = dsi_phy_set_ulps(ctrl->phy, &display->config, enable,
+ display->clamp_enabled);
if (rc) {
pr_err("Ulps PHY state change(%d) failed\n", enable);
return rc;
@@ -1365,8 +1367,7 @@
/*
* Enable DSI clamps only if entering idle power collapse.
*/
- if (dsi_panel_initialized(display->panel) &&
- dsi_panel_ulps_feature_enabled(display->panel)) {
+ if (dsi_panel_initialized(display->panel)) {
dsi_display_phy_idle_off(display);
rc = dsi_display_set_clamp(display, true);
if (rc)
diff --git a/drivers/gpu/drm/msm/dsi-staging/dsi_hw.h b/drivers/gpu/drm/msm/dsi-staging/dsi_hw.h
index 447f613..8250da3 100644
--- a/drivers/gpu/drm/msm/dsi-staging/dsi_hw.h
+++ b/drivers/gpu/drm/msm/dsi-staging/dsi_hw.h
@@ -33,6 +33,15 @@
writel_relaxed((val), (dsi_hw)->mmss_misc_base + (off)); \
} while (0)
+#define DSI_DISP_CC_R32(dsi_hw, off) \
+ readl_relaxed((dsi_hw)->disp_cc_base + (off))
+#define DSI_DISP_CC_W32(dsi_hw, off, val) \
+ do {\
+ pr_err("[DSI_%d][%s] - [0x%08x]\n", \
+ (dsi_hw)->index, #off, val); \
+ writel_relaxed((val), (dsi_hw)->disp_cc_base + (off)); \
+ } while (0)
+
#define DSI_R64(dsi_hw, off) readq_relaxed((dsi_hw)->base + (off))
#define DSI_W64(dsi_hw, off, val) writeq_relaxed((val), (dsi_hw)->base + (off))
diff --git a/drivers/gpu/drm/msm/dsi-staging/dsi_panel.c b/drivers/gpu/drm/msm/dsi-staging/dsi_panel.c
index bda9c2d..b814eb8 100644
--- a/drivers/gpu/drm/msm/dsi-staging/dsi_panel.c
+++ b/drivers/gpu/drm/msm/dsi-staging/dsi_panel.c
@@ -1512,6 +1512,17 @@
return rc;
}
+static int dsi_panel_parse_features(struct dsi_panel *panel,
+ struct device_node *of_node)
+{
+ panel->ulps_enabled =
+ of_property_read_bool(of_node, "qcom,ulps-enabled");
+
+ pr_debug("ulps_enabled:%d\n", panel->ulps_enabled);
+
+ return 0;
+}
+
static int dsi_panel_parse_jitter_config(struct dsi_panel *panel,
struct device_node *of_node)
{
@@ -2117,6 +2128,10 @@
if (rc)
pr_err("failed to parse panel jitter config, rc=%d\n", rc);
+ rc = dsi_panel_parse_features(panel, of_node);
+ if (rc)
+ pr_err("failed to parse panel features, rc=%d\n", rc);
+
rc = dsi_panel_parse_hdr_config(panel, of_node);
if (rc)
pr_err("failed to parse hdr config, rc=%d\n", rc);
@@ -2490,7 +2505,6 @@
panel->name, rc);
goto error;
}
- panel->panel_initialized = false;
error:
mutex_unlock(&panel->panel_lock);
return rc;
@@ -2536,6 +2550,8 @@
panel->name, rc);
goto error;
}
+ panel->panel_initialized = false;
+
error:
mutex_unlock(&panel->panel_lock);
return rc;
diff --git a/drivers/gpu/drm/msm/dsi-staging/dsi_phy.c b/drivers/gpu/drm/msm/dsi-staging/dsi_phy.c
index 96a98bd..ebfb40b8 100644
--- a/drivers/gpu/drm/msm/dsi-staging/dsi_phy.c
+++ b/drivers/gpu/drm/msm/dsi-staging/dsi_phy.c
@@ -388,7 +388,7 @@
/** TODO: initialize debugfs */
dsi_phy->pdev = pdev;
platform_set_drvdata(pdev, dsi_phy);
- pr_debug("Probe successful for %s\n", dsi_phy->name);
+ pr_info("Probe successful for %s\n", dsi_phy->name);
return 0;
fail_supplies:
@@ -669,7 +669,7 @@
}
static int dsi_phy_enable_ulps(struct msm_dsi_phy *phy,
- struct dsi_host_config *config)
+ struct dsi_host_config *config, bool clamp_enabled)
{
int rc = 0;
u32 lanes = 0;
@@ -679,17 +679,25 @@
lanes = config->common_config.data_lanes;
lanes |= DSI_CLOCK_LANE;
- rc = phy->hw.ops.ulps_ops.wait_for_lane_idle(&phy->hw, lanes);
- if (rc) {
- pr_err("lanes not entering idle, skip ULPS\n");
- return rc;
+ /*
+ * If DSI clamps are enabled, it means that the DSI lanes are
+ * already in idle state. Checking for lanes to be in idle state
+ * should be skipped during ULPS entry programming while coming
+ * out of idle screen.
+ */
+ if (!clamp_enabled) {
+ rc = phy->hw.ops.ulps_ops.wait_for_lane_idle(&phy->hw, lanes);
+ if (rc) {
+ pr_err("lanes not entering idle, skip ULPS\n");
+ return rc;
+ }
}
phy->hw.ops.ulps_ops.ulps_request(&phy->hw, &phy->cfg, lanes);
ulps_lanes = phy->hw.ops.ulps_ops.get_lanes_in_ulps(&phy->hw);
- if ((lanes & ulps_lanes) != lanes) {
+ if (!phy->hw.ops.ulps_ops.is_lanes_in_ulps(lanes, ulps_lanes)) {
pr_err("Failed to enter ULPS, request=0x%x, actual=0x%x\n",
lanes, ulps_lanes);
rc = -EIO;
@@ -701,7 +709,6 @@
static int dsi_phy_disable_ulps(struct msm_dsi_phy *phy,
struct dsi_host_config *config)
{
- int rc = 0;
u32 ulps_lanes, lanes = 0;
if (config->panel_mode == DSI_OP_CMD_MODE)
@@ -710,25 +717,27 @@
ulps_lanes = phy->hw.ops.ulps_ops.get_lanes_in_ulps(&phy->hw);
- if ((lanes & ulps_lanes) != lanes)
- pr_err("Mismatch between lanes in ULPS\n");
-
- lanes &= ulps_lanes;
+ if (!phy->hw.ops.ulps_ops.is_lanes_in_ulps(lanes, ulps_lanes)) {
+ pr_err("Mismatch in ULPS: lanes:%d, ulps_lanes:%d\n",
+ lanes, ulps_lanes);
+ return -EIO;
+ }
phy->hw.ops.ulps_ops.ulps_exit(&phy->hw, &phy->cfg, lanes);
ulps_lanes = phy->hw.ops.ulps_ops.get_lanes_in_ulps(&phy->hw);
- if (ulps_lanes & lanes) {
+
+ if (phy->hw.ops.ulps_ops.is_lanes_in_ulps(lanes, ulps_lanes)) {
pr_err("Lanes (0x%x) stuck in ULPS\n", ulps_lanes);
- rc = -EIO;
+ return -EIO;
}
- return rc;
+ return 0;
}
int dsi_phy_set_ulps(struct msm_dsi_phy *phy, struct dsi_host_config *config,
- bool enable)
+ bool enable, bool clamp_enabled)
{
int rc = 0;
@@ -738,7 +747,10 @@
}
if (!phy->hw.ops.ulps_ops.ulps_request ||
- !phy->hw.ops.ulps_ops.ulps_exit) {
+ !phy->hw.ops.ulps_ops.ulps_exit ||
+ !phy->hw.ops.ulps_ops.get_lanes_in_ulps ||
+ !phy->hw.ops.ulps_ops.is_lanes_in_ulps ||
+ !phy->hw.ops.ulps_ops.wait_for_lane_idle) {
pr_debug("DSI PHY ULPS ops not present\n");
return 0;
}
@@ -746,7 +758,7 @@
mutex_lock(&phy->phy_lock);
if (enable)
- rc = dsi_phy_enable_ulps(phy, config);
+ rc = dsi_phy_enable_ulps(phy, config, clamp_enabled);
else
rc = dsi_phy_disable_ulps(phy, config);
diff --git a/drivers/gpu/drm/msm/dsi-staging/dsi_phy.h b/drivers/gpu/drm/msm/dsi-staging/dsi_phy.h
index 4a64855..e721486 100644
--- a/drivers/gpu/drm/msm/dsi-staging/dsi_phy.h
+++ b/drivers/gpu/drm/msm/dsi-staging/dsi_phy.h
@@ -182,11 +182,12 @@
* @phy: DSI PHY handle
* @config: DSi host configuration information.
* @enable: Enable/Disable
+ * @clamp_enabled: mmss_clamp enabled/disabled
*
* Return: error code.
*/
int dsi_phy_set_ulps(struct msm_dsi_phy *phy, struct dsi_host_config *config,
- bool enable);
+ bool enable, bool clamp_enabled);
/**
* dsi_phy_clk_cb_register() - Register PHY clock control callback
diff --git a/drivers/gpu/drm/msm/dsi-staging/dsi_phy_hw.h b/drivers/gpu/drm/msm/dsi-staging/dsi_phy_hw.h
index daaa78a..51c2f46 100644
--- a/drivers/gpu/drm/msm/dsi-staging/dsi_phy_hw.h
+++ b/drivers/gpu/drm/msm/dsi-staging/dsi_phy_hw.h
@@ -143,15 +143,22 @@
* @phy: Pointer to DSI PHY hardware instance.
*
* Returns an ORed list of lanes (enum dsi_data_lanes) that are in ULPS
- * state. If 0 is returned, all the lanes are active.
+ * state.
*
* Return: List of lanes in ULPS state.
*/
u32 (*get_lanes_in_ulps)(struct dsi_phy_hw *phy);
+
+ /**
+ * is_lanes_in_ulps() - checks if the given lanes are in ulps
+ * @lanes: lanes to be checked.
+ * @ulps_lanes: lanes in ulps currenly.
+ *
+ * Return: true if all the given lanes are in ulps; false otherwise.
+ */
+ bool (*is_lanes_in_ulps)(u32 ulps, u32 ulps_lanes);
};
-
-
/**
* struct dsi_phy_hw_ops - Operations for DSI PHY hardware.
* @regulator_enable: Enable PHY regulators.
diff --git a/drivers/gpu/drm/msm/dsi-staging/dsi_phy_hw_v3_0.c b/drivers/gpu/drm/msm/dsi-staging/dsi_phy_hw_v3_0.c
index 96f5c19..371239d 100644
--- a/drivers/gpu/drm/msm/dsi-staging/dsi_phy_hw_v3_0.c
+++ b/drivers/gpu/drm/msm/dsi-staging/dsi_phy_hw_v3_0.c
@@ -159,7 +159,7 @@
struct dsi_phy_cfg *cfg)
{
int i;
- u8 tx_dctrl[] = {0x00, 0x00, 0x00, 0x02, 0x01};
+ u8 tx_dctrl[] = {0x00, 0x00, 0x00, 0x04, 0x01};
/* Strength ctrl settings */
for (i = DSI_LOGICAL_LANE_0; i < DSI_LANE_MAX; i++) {
@@ -186,6 +186,10 @@
DSI_W32(phy, DSIPHY_LNX_OFFSET_BOT_CTRL(i), 0x0);
DSI_W32(phy, DSIPHY_LNX_TX_DCTRL(i), tx_dctrl[i]);
}
+
+ /* Toggle BIT 0 to release freeze I/0 */
+ DSI_W32(phy, DSIPHY_LNX_TX_DCTRL(3), 0x05);
+ DSI_W32(phy, DSIPHY_LNX_TX_DCTRL(3), 0x04);
}
/**
@@ -419,6 +423,14 @@
return lanes;
}
+bool dsi_phy_hw_v3_0_is_lanes_in_ulps(u32 lanes, u32 ulps_lanes)
+{
+ if (lanes & ulps_lanes)
+ return false;
+
+ return true;
+}
+
int dsi_phy_hw_timing_val_v3_0(struct dsi_phy_per_lane_cfgs *timing_cfg,
u32 *timing_val, u32 size)
{
diff --git a/drivers/gpu/drm/msm/msm_drv.c b/drivers/gpu/drm/msm/msm_drv.c
index d7b225b..4e0b678 100644
--- a/drivers/gpu/drm/msm/msm_drv.c
+++ b/drivers/gpu/drm/msm/msm_drv.c
@@ -356,8 +356,8 @@
{
.compatible = "qcom,sde-kms",
.data = (void *)KMS_SDE,
- /* end node */
- } };
+ },
+ {} };
struct device *dev = &pdev->dev;
const struct of_device_id *match;
diff --git a/drivers/gpu/drm/msm/msm_drv.h b/drivers/gpu/drm/msm/msm_drv.h
index 4b263d3..4471d0b 100644
--- a/drivers/gpu/drm/msm/msm_drv.h
+++ b/drivers/gpu/drm/msm/msm_drv.h
@@ -138,6 +138,7 @@
CRTC_PROP_MEM_IB,
CRTC_PROP_ROT_PREFILL_BW,
CRTC_PROP_ROT_CLK,
+ CRTC_PROP_ROI_V1,
/* total # of properties */
CRTC_PROP_COUNT
@@ -158,6 +159,7 @@
CONNECTOR_PROP_DST_Y,
CONNECTOR_PROP_DST_W,
CONNECTOR_PROP_DST_H,
+ CONNECTOR_PROP_ROI_V1,
/* enum/bitmask properties */
CONNECTOR_PROP_TOPOLOGY_NAME,
@@ -200,6 +202,38 @@
};
/**
+ * struct msm_roi_alignment - region of interest alignment restrictions
+ * @xstart_pix_align: left x offset alignment restriction
+ * @width_pix_align: width alignment restriction
+ * @ystart_pix_align: top y offset alignment restriction
+ * @height_pix_align: height alignment restriction
+ * @min_width: minimum width restriction
+ * @min_height: minimum height restriction
+ */
+struct msm_roi_alignment {
+ uint32_t xstart_pix_align;
+ uint32_t width_pix_align;
+ uint32_t ystart_pix_align;
+ uint32_t height_pix_align;
+ uint32_t min_width;
+ uint32_t min_height;
+};
+
+/**
+ * struct msm_roi_caps - display's region of interest capabilities
+ * @enabled: true if some region of interest is supported
+ * @merge_rois: merge rois before sending to display
+ * @num_roi: maximum number of rois supported
+ * @align: roi alignment restrictions
+ */
+struct msm_roi_caps {
+ bool enabled;
+ bool merge_rois;
+ uint32_t num_roi;
+ struct msm_roi_alignment align;
+};
+
+/**
* struct msm_display_dsc_info - defines dsc configuration
* @version: DSC version.
* @scr_rev: DSC revision.
@@ -338,6 +372,7 @@
* @vtotal: display vertical total
* @jitter: display jitter configuration
* @comp_info: Compression supported by the display
+ * @roi_caps: Region of interest capability info
*/
struct msm_display_info {
int intf_type;
@@ -361,21 +396,19 @@
uint32_t jitter;
struct msm_compression_info comp_info;
+ struct msm_roi_caps roi_caps;
};
#define MSM_MAX_ROI 4
/**
- * struct msm_roi_mapping - Regions of interest structure for mapping CRTC to
- * Connector output
- * @num_rects: number of valid rectangles in src and dst arrays
- * @src: source roi rectangle
- * @dst: destination roi rectangle
+ * struct msm_roi_list - list of regions of interest for a drm object
+ * @num_rects: number of valid rectangles in the roi array
+ * @roi: list of roi rectangles
*/
-struct msm_roi_mapping {
+struct msm_roi_list {
uint32_t num_rects;
- struct drm_clip_rect src[MSM_MAX_ROI];
- struct drm_clip_rect dst[MSM_MAX_ROI];
+ struct drm_clip_rect roi[MSM_MAX_ROI];
};
/**
@@ -383,7 +416,7 @@
* @rois: Regions of interest structure for mapping CRTC to Connector output
*/
struct msm_display_kickoff_params {
- struct msm_roi_mapping *rois;
+ struct msm_roi_list *rois;
};
/**
diff --git a/drivers/gpu/drm/msm/sde/sde_connector.c b/drivers/gpu/drm/msm/sde/sde_connector.c
index 6e793d9..e3f8261 100644
--- a/drivers/gpu/drm/msm/sde/sde_connector.c
+++ b/drivers/gpu/drm/msm/sde/sde_connector.c
@@ -21,6 +21,12 @@
#define BL_NODE_NAME_SIZE 32
+#define SDE_DEBUG_CONN(c, fmt, ...) SDE_DEBUG("conn%d " fmt,\
+ (c) ? (c)->base.base.id : -1, ##__VA_ARGS__)
+
+#define SDE_ERROR_CONN(c, fmt, ...) SDE_ERROR("conn%d " fmt,\
+ (c) ? (c)->base.base.id : -1, ##__VA_ARGS__)
+
static const struct drm_prop_enum_list e_topology_name[] = {
{SDE_RM_TOPOLOGY_UNKNOWN, "sde_unknown"},
{SDE_RM_TOPOLOGY_SINGLEPIPE, "sde_singlepipe"},
@@ -78,7 +84,8 @@
.get_brightness = sde_backlight_device_get_brightness,
};
-static int sde_backlight_setup(struct sde_connector *c_conn)
+static int sde_backlight_setup(struct sde_connector *c_conn,
+ struct drm_device *dev)
{
struct backlight_device *bl_device;
struct backlight_properties props;
@@ -87,7 +94,7 @@
static int display_count;
char bl_node_name[BL_NODE_NAME_SIZE];
- if (!c_conn) {
+ if (!c_conn || !dev || !dev->dev) {
SDE_ERROR("invalid param\n");
return -EINVAL;
} else if (c_conn->connector_type != DRM_MODE_CONNECTOR_DSI) {
@@ -104,7 +111,7 @@
props.brightness = bl_config->brightness_max_level;
snprintf(bl_node_name, BL_NODE_NAME_SIZE, "panel%u-backlight",
display_count);
- bl_device = backlight_device_register(bl_node_name, c_conn->base.kdev,
+ bl_device = backlight_device_register(bl_node_name, dev->dev,
c_conn, &sde_backlight_device_ops, &props);
if (IS_ERR_OR_NULL(bl_device)) {
SDE_ERROR("Failed to register backlight: %ld\n",
@@ -247,6 +254,25 @@
return rc;
}
+void sde_connector_clk_ctrl(struct drm_connector *connector, bool enable)
+{
+ struct sde_connector *c_conn;
+ struct dsi_display *display;
+ u32 state = enable ? DSI_CLK_ON : DSI_CLK_OFF;
+
+ if (!connector) {
+ SDE_ERROR("invalid connector\n");
+ return;
+ }
+
+ c_conn = to_sde_connector(connector);
+ display = (struct dsi_display *) c_conn->display;
+
+ if (display && c_conn->ops.clk_ctrl)
+ c_conn->ops.clk_ctrl(display->mdp_clk_handle,
+ DSI_ALL_CLKS, state);
+}
+
static void sde_connector_destroy(struct drm_connector *connector)
{
struct sde_connector *c_conn;
@@ -396,6 +422,122 @@
return &c_state->base;
}
+static int _sde_connector_roi_v1_check_roi(
+ struct sde_connector *c_conn,
+ struct drm_clip_rect *roi_conn,
+ const struct msm_roi_caps *caps)
+{
+ const struct msm_roi_alignment *align = &caps->align;
+ int w = roi_conn->x2 - roi_conn->x1;
+ int h = roi_conn->y2 - roi_conn->y1;
+
+ if (w <= 0 || h <= 0) {
+ SDE_ERROR_CONN(c_conn, "invalid conn roi w %d h %d\n", w, h);
+ return -EINVAL;
+ }
+
+ if (w < align->min_width || w % align->width_pix_align) {
+ SDE_ERROR_CONN(c_conn,
+ "invalid conn roi width %d min %d align %d\n",
+ w, align->min_width, align->width_pix_align);
+ return -EINVAL;
+ }
+
+ if (h < align->min_height || h % align->height_pix_align) {
+ SDE_ERROR_CONN(c_conn,
+ "invalid conn roi height %d min %d align %d\n",
+ h, align->min_height, align->height_pix_align);
+ return -EINVAL;
+ }
+
+ if (roi_conn->x1 % align->xstart_pix_align) {
+ SDE_ERROR_CONN(c_conn, "invalid conn roi x1 %d align %d\n",
+ roi_conn->x1, align->xstart_pix_align);
+ return -EINVAL;
+ }
+
+ if (roi_conn->y1 % align->ystart_pix_align) {
+ SDE_ERROR_CONN(c_conn, "invalid conn roi y1 %d align %d\n",
+ roi_conn->y1, align->ystart_pix_align);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int _sde_connector_set_roi_v1(
+ struct sde_connector *c_conn,
+ struct sde_connector_state *c_state,
+ void *usr_ptr)
+{
+ struct sde_drm_roi_v1 roi_v1;
+ struct msm_display_info display_info;
+ struct msm_roi_caps *caps;
+ int i, rc;
+
+ if (!c_conn || !c_state) {
+ SDE_ERROR("invalid args\n");
+ return -EINVAL;
+ }
+
+ rc = sde_connector_get_info(&c_conn->base, &display_info);
+ if (rc) {
+ SDE_ERROR_CONN(c_conn, "display get info error: %d\n", rc);
+ return rc;
+ }
+
+ caps = &display_info.roi_caps;
+ if (!caps->enabled) {
+ SDE_ERROR_CONN(c_conn, "display roi capability is disabled\n");
+ return -ENOTSUPP;
+ }
+
+ memset(&c_state->rois, 0, sizeof(c_state->rois));
+
+ if (!usr_ptr) {
+ SDE_DEBUG_CONN(c_conn, "rois cleared\n");
+ return 0;
+ }
+
+ if (copy_from_user(&roi_v1, usr_ptr, sizeof(roi_v1))) {
+ SDE_ERROR_CONN(c_conn, "failed to copy roi_v1 data\n");
+ return -EINVAL;
+ }
+
+ SDE_DEBUG_CONN(c_conn, "num_rects %d\n", roi_v1.num_rects);
+
+ if (roi_v1.num_rects == 0) {
+ SDE_DEBUG_CONN(c_conn, "rois cleared\n");
+ return 0;
+ }
+
+ if (roi_v1.num_rects > SDE_MAX_ROI_V1 ||
+ roi_v1.num_rects > caps->num_roi) {
+ SDE_ERROR_CONN(c_conn, "too many rects specified: %d\n",
+ roi_v1.num_rects);
+ return -EINVAL;
+ }
+
+ c_state->rois.num_rects = roi_v1.num_rects;
+ for (i = 0; i < roi_v1.num_rects; ++i) {
+ int rc;
+
+ rc = _sde_connector_roi_v1_check_roi(c_conn, &roi_v1.roi[i],
+ caps);
+ if (rc)
+ return rc;
+
+ c_state->rois.roi[i] = roi_v1.roi[i];
+ SDE_DEBUG_CONN(c_conn, "roi%d: roi 0x%x 0x%x 0x%x 0x%x\n", i,
+ c_state->rois.roi[i].x1,
+ c_state->rois.roi[i].y1,
+ c_state->rois.roi[i].x2,
+ c_state->rois.roi[i].y2);
+ }
+
+ return 0;
+}
+
static int sde_connector_atomic_set_property(struct drm_connector *connector,
struct drm_connector_state *state,
struct drm_property *property,
@@ -461,6 +603,12 @@
SDE_ERROR("invalid topology_control: 0x%llX\n", val);
}
+ if (idx == CONNECTOR_PROP_ROI_V1) {
+ rc = _sde_connector_set_roi_v1(c_conn, c_state, (void *)val);
+ if (rc)
+ SDE_ERROR_CONN(c_conn, "invalid roi_v1, rc: %d\n", rc);
+ }
+
/* check for custom property handling */
if (!rc && c_conn->ops.set_property) {
rc = c_conn->ops.set_property(connector,
@@ -510,13 +658,7 @@
idx = msm_property_index(&c_conn->property_info, property);
if (idx == CONNECTOR_PROP_RETIRE_FENCE)
- /*
- * Set a fence offset if not a virtual connector, so that the
- * fence signals after one additional commit rather than at the
- * end of the current one.
- */
- rc = sde_fence_create(&c_conn->retire_fence, val,
- c_conn->connector_type != DRM_MODE_CONNECTOR_VIRTUAL);
+ rc = sde_fence_create(&c_conn->retire_fence, val, 0);
else
/* get cached property value */
rc = msm_property_atomic_get(&c_conn->property_info,
@@ -705,6 +847,7 @@
struct sde_kms_info *info;
struct sde_connector *c_conn = NULL;
struct dsi_display *dsi_display;
+ struct msm_display_info display_info;
int rc;
if (!dev || !dev->dev_private || !encoder) {
@@ -779,7 +922,7 @@
goto error_cleanup_fence;
}
- rc = sde_backlight_setup(c_conn);
+ rc = sde_backlight_setup(c_conn, dev);
if (rc) {
SDE_ERROR("failed to setup backlight, rc=%d\n", rc);
goto error_cleanup_fence;
@@ -837,6 +980,13 @@
}
}
+ rc = sde_connector_get_info(&c_conn->base, &display_info);
+ if (!rc && display_info.roi_caps.enabled) {
+ msm_property_install_volatile_range(
+ &c_conn->property_info, "sde_drm_roi_v1", 0x0,
+ 0, ~0, 0, CONNECTOR_PROP_ROI_V1);
+ }
+
msm_property_install_range(&c_conn->property_info, "RETIRE_FENCE",
0x0, 0, INR_OPEN_MAX, 0, CONNECTOR_PROP_RETIRE_FENCE);
diff --git a/drivers/gpu/drm/msm/sde/sde_connector.h b/drivers/gpu/drm/msm/sde/sde_connector.h
index 70d4952..601299e 100644
--- a/drivers/gpu/drm/msm/sde/sde_connector.h
+++ b/drivers/gpu/drm/msm/sde/sde_connector.h
@@ -150,6 +150,14 @@
int (*pre_kickoff)(struct drm_connector *connector,
void *display,
struct msm_display_kickoff_params *params);
+
+ /**
+ * clk_ctrl - perform clk enable/disable on the connector
+ * @handle: Pointer to clk handle
+ * @type: Type of clks
+ * @enable: State of clks
+ */
+ int (*clk_ctrl)(void *handle, u32 type, u32 state);
};
/**
@@ -273,7 +281,7 @@
int mmu_id;
uint64_t property_values[CONNECTOR_PROP_COUNT];
- struct msm_roi_mapping rois;
+ struct msm_roi_list rois;
};
/**
@@ -366,6 +374,13 @@
struct msm_display_info *info);
/**
+ * sde_connector_clk_ctrl - enables/disables the connector clks
+ * @connector: Pointer to drm connector object
+ * @enable: true/false to enable/disable
+ */
+void sde_connector_clk_ctrl(struct drm_connector *connector, bool enable);
+
+/**
* sde_connector_trigger_event - indicate that an event has occurred
* Any callbacks that have been registered against this event will
* be called from the same thread context.
@@ -425,5 +440,22 @@
*/
int sde_connector_pre_kickoff(struct drm_connector *connector);
+/**
+ * sde_connector_needs_offset - adjust the output fence offset based on
+ * display type
+ * @connector: Pointer to drm connector object
+ * Returns: true if offset is required, false for all other cases.
+ */
+static inline bool sde_connector_needs_offset(struct drm_connector *connector)
+{
+ struct sde_connector *c_conn;
+
+ if (!connector)
+ return false;
+
+ c_conn = to_sde_connector(connector);
+ return (c_conn->connector_type != DRM_MODE_CONNECTOR_VIRTUAL);
+}
+
#endif /* _SDE_CONNECTOR_H_ */
diff --git a/drivers/gpu/drm/msm/sde/sde_crtc.c b/drivers/gpu/drm/msm/sde/sde_crtc.c
index e7a867f..6bae083 100644
--- a/drivers/gpu/drm/msm/sde/sde_crtc.c
+++ b/drivers/gpu/drm/msm/sde/sde_crtc.c
@@ -656,21 +656,344 @@
}
}
+void sde_crtc_get_crtc_roi(struct drm_crtc_state *state,
+ const struct sde_rect **crtc_roi)
+{
+ struct sde_crtc_state *crtc_state;
+
+ if (!state || !crtc_roi)
+ return;
+
+ crtc_state = to_sde_crtc_state(state);
+ *crtc_roi = &crtc_state->crtc_roi;
+}
+
+static int _sde_crtc_set_roi_v1(struct drm_crtc_state *state,
+ void *usr_ptr)
+{
+ struct drm_crtc *crtc;
+ struct sde_crtc_state *cstate;
+ struct sde_drm_roi_v1 roi_v1;
+ int i;
+
+ if (!state) {
+ SDE_ERROR("invalid args\n");
+ return -EINVAL;
+ }
+
+ cstate = to_sde_crtc_state(state);
+ crtc = cstate->base.crtc;
+
+ memset(&cstate->user_roi_list, 0, sizeof(cstate->user_roi_list));
+
+ if (!usr_ptr) {
+ SDE_DEBUG("crtc%d: rois cleared\n", DRMID(crtc));
+ return 0;
+ }
+
+ if (copy_from_user(&roi_v1, usr_ptr, sizeof(roi_v1))) {
+ SDE_ERROR("crtc%d: failed to copy roi_v1 data\n", DRMID(crtc));
+ return -EINVAL;
+ }
+
+ SDE_DEBUG("crtc%d: num_rects %d\n", DRMID(crtc), roi_v1.num_rects);
+
+ if (roi_v1.num_rects == 0) {
+ SDE_DEBUG("crtc%d: rois cleared\n", DRMID(crtc));
+ return 0;
+ }
+
+ if (roi_v1.num_rects > SDE_MAX_ROI_V1) {
+ SDE_ERROR("crtc%d: too many rects specified: %d\n", DRMID(crtc),
+ roi_v1.num_rects);
+ return -EINVAL;
+ }
+
+ cstate->user_roi_list.num_rects = roi_v1.num_rects;
+ for (i = 0; i < roi_v1.num_rects; ++i) {
+ cstate->user_roi_list.roi[i] = roi_v1.roi[i];
+ SDE_DEBUG("crtc%d: roi%d: roi (%d,%d) (%d,%d)\n",
+ DRMID(crtc), i,
+ cstate->user_roi_list.roi[i].x1,
+ cstate->user_roi_list.roi[i].y1,
+ cstate->user_roi_list.roi[i].x2,
+ cstate->user_roi_list.roi[i].y2);
+ }
+
+ return 0;
+}
+
+static int _sde_crtc_set_crtc_roi(struct drm_crtc *crtc,
+ struct drm_crtc_state *state)
+{
+ struct drm_connector *conn;
+ struct drm_connector_state *conn_state;
+ struct sde_crtc *sde_crtc;
+ struct sde_crtc_state *crtc_state;
+ struct sde_rect *crtc_roi;
+ struct drm_clip_rect crtc_clip, *user_rect;
+ int i, num_attached_conns = 0;
+
+ if (!crtc || !state)
+ return -EINVAL;
+
+ sde_crtc = to_sde_crtc(crtc);
+ crtc_state = to_sde_crtc_state(state);
+ crtc_roi = &crtc_state->crtc_roi;
+
+ /* init to invalid range maxes */
+ crtc_clip.x1 = ~0;
+ crtc_clip.y1 = ~0;
+ crtc_clip.x2 = 0;
+ crtc_clip.y2 = 0;
+
+ for_each_connector_in_state(state->state, conn, conn_state, i) {
+ struct sde_connector_state *sde_conn_state;
+
+ if (!conn_state || conn_state->crtc != crtc)
+ continue;
+
+ if (num_attached_conns) {
+ SDE_ERROR(
+ "crtc%d: unsupported: roi on crtc w/ >1 connectors\n",
+ DRMID(crtc));
+ return -EINVAL;
+ }
+ ++num_attached_conns;
+
+ sde_conn_state = to_sde_connector_state(conn_state);
+
+ if (memcmp(&sde_conn_state->rois, &crtc_state->user_roi_list,
+ sizeof(crtc_state->user_roi_list))) {
+ SDE_ERROR("%s: crtc -> conn roi scaling unsupported\n",
+ sde_crtc->name);
+ return -EINVAL;
+ }
+ }
+
+ /* aggregate all clipping rectangles together for overall crtc roi */
+ for (i = 0; i < crtc_state->user_roi_list.num_rects; i++) {
+ user_rect = &crtc_state->user_roi_list.roi[i];
+
+ crtc_clip.x1 = min(crtc_clip.x1, user_rect->x1);
+ crtc_clip.y1 = min(crtc_clip.y1, user_rect->y1);
+ crtc_clip.x2 = max(crtc_clip.x2, user_rect->x2);
+ crtc_clip.y2 = max(crtc_clip.y2, user_rect->y2);
+
+ SDE_DEBUG(
+ "%s: conn%d roi%d (%d,%d),(%d,%d) -> crtc (%d,%d),(%d,%d)\n",
+ sde_crtc->name, DRMID(crtc), i,
+ user_rect->x1, user_rect->y1,
+ user_rect->x2, user_rect->y2,
+ crtc_clip.x1, crtc_clip.y1,
+ crtc_clip.x2, crtc_clip.y2);
+
+ }
+
+ if (crtc_clip.x2 && crtc_clip.y2) {
+ crtc_roi->x = crtc_clip.x1;
+ crtc_roi->y = crtc_clip.y1;
+ crtc_roi->w = crtc_clip.x2 - crtc_clip.x1;
+ crtc_roi->h = crtc_clip.y2 - crtc_clip.y1;
+ } else {
+ crtc_roi->x = 0;
+ crtc_roi->y = 0;
+ crtc_roi->w = 0;
+ crtc_roi->h = 0;
+ }
+
+ 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);
+
+ return 0;
+}
+
+static int _sde_crtc_set_lm_roi(struct drm_crtc *crtc,
+ struct drm_crtc_state *state, int lm_idx)
+{
+ struct sde_crtc *sde_crtc;
+ struct sde_crtc_state *crtc_state;
+ const struct sde_rect *crtc_roi;
+ const struct sde_rect *lm_bounds;
+ struct sde_rect *lm_roi;
+
+ if (!crtc || !state || lm_idx >= ARRAY_SIZE(crtc_state->lm_bounds))
+ return -EINVAL;
+
+ sde_crtc = to_sde_crtc(crtc);
+ crtc_state = to_sde_crtc_state(state);
+ crtc_roi = &crtc_state->crtc_roi;
+ lm_bounds = &crtc_state->lm_bounds[lm_idx];
+ lm_roi = &crtc_state->lm_roi[lm_idx];
+
+ if (!sde_kms_rect_is_null(crtc_roi)) {
+ sde_kms_rect_intersect(crtc_roi, lm_bounds, lm_roi);
+ if (sde_kms_rect_is_null(lm_roi)) {
+ SDE_ERROR("unsupported R/L only partial update\n");
+ return -EINVAL;
+ }
+ } else {
+ memcpy(lm_roi, lm_bounds, sizeof(*lm_roi));
+ }
+
+ 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);
+
+ return 0;
+}
+
+static int _sde_crtc_check_rois_centered_and_symmetric(struct drm_crtc *crtc,
+ struct drm_crtc_state *state)
+{
+ struct sde_crtc *sde_crtc;
+ struct sde_crtc_state *crtc_state;
+ const struct sde_rect *roi_prv, *roi_cur;
+ int lm_idx;
+
+ if (!crtc || !state)
+ return -EINVAL;
+
+ /*
+ * On certain HW, ROIs must be centered on the split between LMs,
+ * and be of equal width.
+ */
+
+ sde_crtc = to_sde_crtc(crtc);
+ crtc_state = to_sde_crtc_state(state);
+
+ roi_prv = &crtc_state->lm_roi[0];
+ for (lm_idx = 1; lm_idx < sde_crtc->num_mixers; lm_idx++) {
+ roi_cur = &crtc_state->lm_roi[lm_idx];
+
+ /* check lm rois are equal width & first roi ends at 2nd roi */
+ if (((roi_prv->x + roi_prv->w) != roi_cur->x) ||
+ (roi_prv->w != roi_cur->w)) {
+ SDE_ERROR("%s: roi lm%d x %d w %d lm%d x %d w %d\n",
+ sde_crtc->name,
+ lm_idx-1, roi_prv->x, roi_prv->w,
+ lm_idx, roi_cur->x, roi_cur->w);
+ return -EINVAL;
+ }
+ roi_prv = roi_cur;
+ }
+
+ return 0;
+}
+
+static int _sde_crtc_check_planes_within_crtc_roi(struct drm_crtc *crtc,
+ struct drm_crtc_state *state)
+{
+ struct sde_crtc *sde_crtc;
+ struct sde_crtc_state *crtc_state;
+ const struct sde_rect *crtc_roi;
+ struct drm_plane_state *pstate;
+ struct drm_plane *plane;
+
+ if (!crtc || !state)
+ return -EINVAL;
+
+ /*
+ * Reject commit if a Plane CRTC destination coordinates fall outside
+ * the partial CRTC ROI. LM output is determined via connector ROIs,
+ * if they are specified, not Plane CRTC ROIs.
+ */
+
+ sde_crtc = to_sde_crtc(crtc);
+ crtc_state = to_sde_crtc_state(state);
+ crtc_roi = &crtc_state->crtc_roi;
+
+ if (sde_kms_rect_is_null(crtc_roi))
+ return 0;
+
+ drm_atomic_crtc_state_for_each_plane(plane, state) {
+ struct sde_rect plane_roi, intersection;
+
+ pstate = drm_atomic_get_plane_state(state->state, plane);
+ if (IS_ERR_OR_NULL(pstate)) {
+ int rc = PTR_ERR(pstate);
+
+ SDE_ERROR("%s: failed to get plane%d state, %d\n",
+ sde_crtc->name, plane->base.id, rc);
+ return rc;
+ }
+
+ plane_roi.x = pstate->crtc_x;
+ plane_roi.y = pstate->crtc_y;
+ plane_roi.w = pstate->crtc_w;
+ plane_roi.h = pstate->crtc_h;
+ sde_kms_rect_intersect(crtc_roi, &plane_roi, &intersection);
+ if (!sde_kms_rect_is_equal(&plane_roi, &intersection)) {
+ SDE_ERROR(
+ "%s: plane%d crtc roi (%d,%d,%d,%d) outside crtc roi (%d,%d,%d,%d)\n",
+ sde_crtc->name, plane->base.id,
+ plane_roi.x, plane_roi.y,
+ plane_roi.w, plane_roi.h,
+ crtc_roi->x, crtc_roi->y,
+ crtc_roi->w, crtc_roi->h);
+ return -E2BIG;
+ }
+ }
+
+ return 0;
+}
+
+static int _sde_crtc_check_rois(struct drm_crtc *crtc,
+ struct drm_crtc_state *state)
+{
+ struct sde_crtc *sde_crtc;
+ int lm_idx;
+ int rc;
+
+ if (!crtc || !state)
+ return -EINVAL;
+
+ sde_crtc = to_sde_crtc(crtc);
+
+ rc = _sde_crtc_set_crtc_roi(crtc, state);
+ if (rc)
+ return rc;
+
+ for (lm_idx = 0; lm_idx < sde_crtc->num_mixers; lm_idx++) {
+ rc = _sde_crtc_set_lm_roi(crtc, state, lm_idx);
+ if (rc)
+ return rc;
+ }
+
+ rc = _sde_crtc_check_rois_centered_and_symmetric(crtc, state);
+ if (rc)
+ return rc;
+
+ rc = _sde_crtc_check_planes_within_crtc_roi(crtc, state);
+ if (rc)
+ return rc;
+
+ return 0;
+}
+
static void _sde_crtc_program_lm_output_roi(struct drm_crtc *crtc)
{
struct sde_crtc *sde_crtc;
struct sde_crtc_state *crtc_state;
+ const struct sde_rect *lm_roi;
+ struct sde_hw_mixer *hw_lm;
int lm_idx, lm_horiz_position;
+ if (!crtc)
+ return;
+
sde_crtc = to_sde_crtc(crtc);
crtc_state = to_sde_crtc_state(crtc->state);
lm_horiz_position = 0;
for (lm_idx = 0; lm_idx < sde_crtc->num_mixers; lm_idx++) {
- const struct sde_rect *lm_roi = &crtc_state->lm_bounds[lm_idx];
- struct sde_hw_mixer *hw_lm = sde_crtc->mixers[lm_idx].hw_lm;
struct sde_hw_mixer_cfg cfg;
+ lm_roi = &crtc_state->lm_roi[lm_idx];
+ hw_lm = sde_crtc->mixers[lm_idx].hw_lm;
+
+ SDE_EVT32(DRMID(crtc_state->base.crtc), lm_idx,
+ lm_roi->x, lm_roi->y, lm_roi->w, lm_roi->h);
+
if (sde_kms_rect_is_null(lm_roi))
continue;
@@ -742,9 +1065,12 @@
format = to_sde_format(msm_framebuffer_format(pstate->base.fb));
- SDE_EVT32(DRMID(plane), state->src_x, state->src_y,
- state->src_w >> 16, state->src_h >> 16, state->crtc_x,
- state->crtc_y, state->crtc_w, state->crtc_h);
+ SDE_EVT32(DRMID(crtc), DRMID(plane),
+ state->fb ? state->fb->base.id : -1,
+ state->src_x >> 16, state->src_y >> 16,
+ state->src_w >> 16, state->src_h >> 16,
+ state->crtc_x, state->crtc_y,
+ state->crtc_w, state->crtc_h);
for (lm_idx = 0; lm_idx < sde_crtc->num_mixers; lm_idx++) {
struct sde_rect intersect;
@@ -877,6 +1203,8 @@
ctl->ops.setup_blendstage(ctl, mixer[i].hw_lm->idx,
&sde_crtc->stage_cfg, i);
}
+
+ _sde_crtc_program_lm_output_roi(crtc);
}
void sde_crtc_prepare_commit(struct drm_crtc *crtc,
@@ -1329,14 +1657,18 @@
crtc_split_width = sde_crtc_mixer_width(sde_crtc, adj_mode);
for (i = 0; i < sde_crtc->num_mixers; i++) {
- struct sde_rect *lm_bound = &cstate->lm_bounds[i];
-
- lm_bound->x = crtc_split_width * i;
- lm_bound->y = 0;
- lm_bound->w = crtc_split_width;
- lm_bound->h = adj_mode->vdisplay;
- SDE_EVT32(DRMID(crtc), i, lm_bound->x, lm_bound->y,
- lm_bound->w, lm_bound->h);
+ 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;
+ memcpy(&cstate->lm_roi[i], &cstate->lm_bounds[i],
+ sizeof(cstate->lm_roi[i]));
+ SDE_EVT32(DRMID(crtc), i,
+ cstate->lm_bounds[i].x, cstate->lm_bounds[i].y,
+ cstate->lm_bounds[i].w, cstate->lm_bounds[i].h);
+ SDE_DEBUG("%s: lm%d bnd&roi (%d,%d,%d,%d)\n", sde_crtc->name, i,
+ cstate->lm_roi[i].x, cstate->lm_roi[i].y,
+ cstate->lm_roi[i].w, cstate->lm_roi[i].h);
}
drm_mode_debug_printmodeline(adj_mode);
@@ -1366,10 +1698,10 @@
sde_crtc = to_sde_crtc(crtc);
dev = crtc->dev;
- if (!sde_crtc->num_mixers)
+ if (!sde_crtc->num_mixers) {
_sde_crtc_setup_mixers(crtc);
-
- _sde_crtc_setup_lm_bounds(crtc, crtc->state);
+ _sde_crtc_setup_lm_bounds(crtc, crtc->state);
+ }
if (sde_crtc->event) {
WARN_ON(sde_crtc->event);
@@ -1459,7 +1791,7 @@
continue;
cstate->rsc_client =
- sde_encoder_update_rsc_client(encoder, true);
+ sde_encoder_get_rsc_client(encoder);
}
cstate->rsc_update = true;
}
@@ -1796,7 +2128,6 @@
if (encoder->crtc != crtc)
continue;
sde_encoder_register_frame_event_callback(encoder, NULL, NULL);
- sde_encoder_update_rsc_client(encoder, false);
cstate->rsc_client = NULL;
cstate->rsc_update = false;
}
@@ -2118,6 +2449,11 @@
}
}
+ rc = _sde_crtc_check_rois(crtc, state);
+ if (rc) {
+ SDE_ERROR("crtc%d failed roi check %d\n", crtc->base.id, rc);
+ goto end;
+ }
end:
_sde_crtc_rp_free_unused(&cstate->rp);
@@ -2244,6 +2580,9 @@
"dim_layer_v1", 0x0, 0, ~0, 0, CRTC_PROP_DIM_LAYER_V1);
}
+ msm_property_install_volatile_range(&sde_crtc->property_info,
+ "sde_drm_roi_v1", 0x0, 0, ~0, 0, CRTC_PROP_ROI_V1);
+
sde_kms_info_reset(info);
sde_kms_info_add_keyint(info, "hw_version", catalog->hwversion);
@@ -2316,6 +2655,9 @@
case CRTC_PROP_DIM_LAYER_V1:
_sde_crtc_set_dim_layer_v1(cstate, (void *)val);
break;
+ case CRTC_PROP_ROI_V1:
+ ret = _sde_crtc_set_roi_v1(state, (void *)val);
+ break;
default:
/* nothing to do */
break;
@@ -2365,19 +2707,28 @@
struct sde_crtc *sde_crtc;
struct sde_crtc_state *cstate;
int i, ret = -EINVAL;
+ bool conn_offset = 0;
if (!crtc || !state) {
SDE_ERROR("invalid argument(s)\n");
} else {
sde_crtc = to_sde_crtc(crtc);
cstate = to_sde_crtc_state(state);
+
+ for (i = 0; i < cstate->num_connectors; ++i) {
+ conn_offset = sde_connector_needs_offset(
+ cstate->connectors[i]);
+ if (conn_offset)
+ break;
+ }
+
i = msm_property_index(&sde_crtc->property_info, property);
if (i == CRTC_PROP_OUTPUT_FENCE) {
uint32_t offset = sde_crtc_get_property(cstate,
CRTC_PROP_OUTPUT_FENCE_OFFSET);
- ret = sde_fence_create(
- &sde_crtc->output_fence, val, offset);
+ ret = sde_fence_create(&sde_crtc->output_fence, val,
+ offset + conn_offset);
if (ret)
SDE_ERROR("fence create failed\n");
} else {
diff --git a/drivers/gpu/drm/msm/sde/sde_crtc.h b/drivers/gpu/drm/msm/sde/sde_crtc.h
index 36231d4..7ad0955 100644
--- a/drivers/gpu/drm/msm/sde/sde_crtc.h
+++ b/drivers/gpu/drm/msm/sde/sde_crtc.h
@@ -250,6 +250,11 @@
* @rsc_client : sde rsc client when mode is valid
* @lm_bounds : LM boundaries based on current mode full resolution, no ROI.
* Origin top left of CRTC.
+ * @crtc_roi : Current CRTC ROI. Possibly sub-rectangle of mode.
+ * Origin top left of CRTC.
+ * @lm_roi : Current LM ROI, possibly sub-rectangle of mode.
+ * Origin top left of CRTC.
+ * @user_roi_list : List of user's requested ROIs as from set property
* @property_values: Current crtc property values
* @input_fence_timeout_ns : Cached input fence timeout, in ns
* @property_blobs: Reference pointers for blob properties
@@ -270,6 +275,9 @@
bool rsc_update;
struct sde_rect lm_bounds[CRTC_DUAL_MIXERS];
+ struct sde_rect crtc_roi;
+ struct sde_rect lm_roi[CRTC_DUAL_MIXERS];
+ struct msm_roi_list user_roi_list;
uint64_t property_values[CRTC_PROP_COUNT];
uint64_t input_fence_timeout_ns;
@@ -433,4 +441,14 @@
*/
void sde_crtc_res_put(struct drm_crtc_state *state, u32 type, u64 tag);
+/**
+ * sde_crtc_get_crtc_roi - retrieve the crtc_roi from the given state object
+ * used to allow the planes to adjust their final lm out_xy value in the
+ * case of partial update
+ * @crtc_state: Pointer to crtc state
+ * @crtc_roi: Output pointer to crtc roi in the given state
+ */
+void sde_crtc_get_crtc_roi(struct drm_crtc_state *state,
+ const struct sde_rect **crtc_roi);
+
#endif /* _SDE_CRTC_H_ */
diff --git a/drivers/gpu/drm/msm/sde/sde_encoder.c b/drivers/gpu/drm/msm/sde/sde_encoder.c
index 67fb783..742ea20 100644
--- a/drivers/gpu/drm/msm/sde/sde_encoder.c
+++ b/drivers/gpu/drm/msm/sde/sde_encoder.c
@@ -284,6 +284,24 @@
}
}
+static void _sde_encoder_adjust_mode(struct drm_connector *connector,
+ struct drm_display_mode *adj_mode)
+{
+ struct drm_display_mode *cur_mode;
+
+ if (!connector || !adj_mode)
+ return;
+
+ list_for_each_entry(cur_mode, &connector->modes, head) {
+ if (cur_mode->vdisplay == adj_mode->vdisplay &&
+ cur_mode->hdisplay == adj_mode->hdisplay &&
+ cur_mode->vrefresh == adj_mode->vrefresh) {
+ adj_mode->private = cur_mode->private;
+ adj_mode->private_flags = cur_mode->private_flags;
+ }
+ }
+}
+
static int sde_encoder_virt_atomic_check(
struct drm_encoder *drm_enc,
struct drm_crtc_state *crtc_state,
@@ -312,6 +330,15 @@
adj_mode = &crtc_state->adjusted_mode;
SDE_EVT32(DRMID(drm_enc));
+ /*
+ * display drivers may populate private fields of the drm display mode
+ * structure while registering possible modes of a connector with DRM.
+ * These private fields are not populated back while DRM invokes
+ * the mode_set callbacks. This module retrieves and populates the
+ * private fields of the given mode.
+ */
+ _sde_encoder_adjust_mode(conn_state->connector, adj_mode);
+
/* perform atomic check on the first physical encoder (master) */
for (i = 0; i < sde_enc->num_phys_encs; i++) {
struct sde_encoder_phys *phys = sde_enc->phys_encs[i];
@@ -656,6 +683,71 @@
return ret;
}
+static int sde_encoder_update_rsc_client(
+ struct drm_encoder *drm_enc, bool enable)
+{
+ struct sde_encoder_virt *sde_enc;
+ enum sde_rsc_state rsc_state;
+ struct sde_rsc_cmd_config rsc_config;
+ int ret;
+ struct msm_display_info *disp_info;
+
+ if (!drm_enc) {
+ SDE_ERROR("invalid encoder\n");
+ return -EINVAL;
+ }
+
+ sde_enc = to_sde_encoder_virt(drm_enc);
+ disp_info = &sde_enc->disp_info;
+
+ /**
+ * only primary command mode panel can request CMD state.
+ * all other panels/displays can request for VID state including
+ * secondary command mode panel.
+ */
+ rsc_state = enable ?
+ (((disp_info->capabilities & MSM_DISPLAY_CAP_CMD_MODE) &&
+ disp_info->is_primary) ? SDE_RSC_CMD_STATE :
+ SDE_RSC_VID_STATE) : SDE_RSC_IDLE_STATE;
+
+ if (rsc_state != SDE_RSC_IDLE_STATE && !sde_enc->rsc_state_update
+ && disp_info->is_primary) {
+ rsc_config.fps = disp_info->frame_rate;
+ rsc_config.vtotal = disp_info->vtotal;
+ rsc_config.prefill_lines = disp_info->prefill_lines;
+ rsc_config.jitter = disp_info->jitter;
+ /* update it only once */
+ sde_enc->rsc_state_update = true;
+
+ ret = sde_rsc_client_state_update(sde_enc->rsc_client,
+ rsc_state, &rsc_config,
+ drm_enc->crtc ? drm_enc->crtc->index : -1);
+ } else {
+ ret = sde_rsc_client_state_update(sde_enc->rsc_client,
+ rsc_state, NULL,
+ drm_enc->crtc ? drm_enc->crtc->index : -1);
+ }
+
+ if (ret)
+ SDE_ERROR("sde rsc client update failed ret:%d\n", ret);
+
+ return ret;
+}
+
+struct sde_rsc_client *sde_encoder_get_rsc_client(struct drm_encoder *drm_enc)
+{
+ struct sde_encoder_virt *sde_enc;
+ struct msm_display_info *disp_info;
+
+ if (!drm_enc)
+ return NULL;
+
+ sde_enc = to_sde_encoder_virt(drm_enc);
+ disp_info = &sde_enc->disp_info;
+
+ return disp_info->is_primary ? sde_enc->rsc_client : NULL;
+}
+
static void sde_encoder_virt_mode_set(struct drm_encoder *drm_enc,
struct drm_display_mode *mode,
struct drm_display_mode *adj_mode)
@@ -778,6 +870,8 @@
}
}
+ sde_encoder_update_rsc_client(drm_enc, true);
+
if (!sde_enc->cur_master)
SDE_ERROR("virt encoder has no master! num_phys %d\n", i);
else if (sde_enc->cur_master->ops.enable)
@@ -833,6 +927,8 @@
del_timer_sync(&sde_enc->frame_done_timer);
}
+ sde_encoder_update_rsc_client(drm_enc, false);
+
if (sde_enc->cur_master && sde_enc->cur_master->ops.disable)
sde_enc->cur_master->ops.disable(sde_enc->cur_master);
@@ -927,57 +1023,6 @@
}
}
-struct sde_rsc_client *sde_encoder_update_rsc_client(
- struct drm_encoder *drm_enc, bool enable)
-{
- struct sde_encoder_virt *sde_enc;
- enum sde_rsc_state rsc_state;
- struct sde_rsc_cmd_config rsc_config;
- int ret;
- struct msm_display_info *disp_info;
-
- if (!drm_enc) {
- SDE_ERROR("invalid encoder\n");
- return NULL;
- }
-
- sde_enc = to_sde_encoder_virt(drm_enc);
- disp_info = &sde_enc->disp_info;
-
- /**
- * only primary command mode panel can request CMD state.
- * all other panels/displays can request for VID state including
- * secondary command mode panel.
- */
- rsc_state = enable ?
- (((disp_info->capabilities & MSM_DISPLAY_CAP_CMD_MODE) &&
- disp_info->is_primary) ? SDE_RSC_CMD_STATE :
- SDE_RSC_VID_STATE) : SDE_RSC_IDLE_STATE;
-
- if (rsc_state != SDE_RSC_IDLE_STATE && !sde_enc->rsc_state_update
- && disp_info->is_primary) {
- rsc_config.fps = disp_info->frame_rate;
- rsc_config.vtotal = disp_info->vtotal;
- rsc_config.prefill_lines = disp_info->prefill_lines;
- rsc_config.jitter = disp_info->jitter;
- /* update it only once */
- sde_enc->rsc_state_update = true;
-
- ret = sde_rsc_client_state_update(sde_enc->rsc_client,
- rsc_state, &rsc_config,
- drm_enc->crtc ? drm_enc->crtc->index : -1);
- } else {
- ret = sde_rsc_client_state_update(sde_enc->rsc_client,
- rsc_state, NULL,
- drm_enc->crtc ? drm_enc->crtc->index : -1);
- }
-
- if (ret)
- SDE_ERROR("sde rsc client update failed ret:%d\n", ret);
-
- return sde_enc->disp_info.is_primary ? sde_enc->rsc_client : NULL;
-}
-
void sde_encoder_register_frame_event_callback(struct drm_encoder *drm_enc,
void (*frame_event_cb)(void *, u32 event),
void *frame_event_cb_data)
diff --git a/drivers/gpu/drm/msm/sde/sde_encoder.h b/drivers/gpu/drm/msm/sde/sde_encoder.h
index cdecd08..5795e04 100644
--- a/drivers/gpu/drm/msm/sde/sde_encoder.h
+++ b/drivers/gpu/drm/msm/sde/sde_encoder.h
@@ -83,13 +83,11 @@
void (*cb)(void *, u32), void *data);
/**
- * sde_encoder_update_rsc_client - updates the rsc client state for primary
+ * sde_encoder_get_rsc_client - gets the rsc client state for primary
* for primary display.
* @encoder: encoder pointer
- * @enable: enable/disable the client
*/
-struct sde_rsc_client *sde_encoder_update_rsc_client(
- struct drm_encoder *encoder, bool enable);
+struct sde_rsc_client *sde_encoder_get_rsc_client(struct drm_encoder *encoder);
/**
* sde_encoder_prepare_for_kickoff - schedule double buffer flip of the ctl
diff --git a/drivers/gpu/drm/msm/sde/sde_hw_catalog.c b/drivers/gpu/drm/msm/sde/sde_hw_catalog.c
index 11cca1f..cfa3b5e 100644
--- a/drivers/gpu/drm/msm/sde/sde_hw_catalog.c
+++ b/drivers/gpu/drm/msm/sde/sde_hw_catalog.c
@@ -490,8 +490,8 @@
return 0;
for (i = 0, cur_pos = dst_list_pos;
- (cur_pos < (dst_list_size - 1)) && src_list[i].fourcc_format
- && (i < src_list_size); ++i, ++cur_pos)
+ (cur_pos < (dst_list_size - 1)) && (i < src_list_size)
+ && src_list[i].fourcc_format; ++i, ++cur_pos)
dst_list[cur_pos] = src_list[i];
dst_list[cur_pos].fourcc_format = 0;
@@ -565,7 +565,7 @@
rc = -EINVAL;
}
*off_count = 0;
- memset(prop_count, 0, sizeof(int *) * prop_size);
+ memset(prop_count, 0, sizeof(int) * prop_size);
return rc;
}
}
diff --git a/drivers/gpu/drm/msm/sde/sde_hw_hwio.h b/drivers/gpu/drm/msm/sde/sde_hw_hwio.h
deleted file mode 100644
index e69de29..0000000
--- a/drivers/gpu/drm/msm/sde/sde_hw_hwio.h
+++ /dev/null
diff --git a/drivers/gpu/drm/msm/sde/sde_kms.c b/drivers/gpu/drm/msm/sde/sde_kms.c
index 731135f..4a5479d 100644
--- a/drivers/gpu/drm/msm/sde/sde_kms.c
+++ b/drivers/gpu/drm/msm/sde/sde_kms.c
@@ -566,7 +566,8 @@
.get_info = dsi_display_get_info,
.set_backlight = dsi_display_set_backlight,
.soft_reset = dsi_display_soft_reset,
- .pre_kickoff = dsi_conn_pre_kickoff
+ .pre_kickoff = dsi_conn_pre_kickoff,
+ .clk_ctrl = dsi_display_clk_ctrl
};
static const struct sde_connector_ops wb_ops = {
.post_init = sde_wb_connector_post_init,
@@ -1529,7 +1530,7 @@
}
rc = sde_core_perf_init(&sde_kms->perf, dev, sde_kms->catalog,
- &priv->phandle, priv->pclient, "core_clk_src");
+ &priv->phandle, priv->pclient, "core_clk");
if (rc) {
SDE_ERROR("failed to init perf %d\n", rc);
goto perf_err;
diff --git a/drivers/gpu/drm/msm/sde/sde_plane.c b/drivers/gpu/drm/msm/sde/sde_plane.c
index 416ff46..93268be 100644
--- a/drivers/gpu/drm/msm/sde/sde_plane.c
+++ b/drivers/gpu/drm/msm/sde/sde_plane.c
@@ -2212,6 +2212,7 @@
struct drm_crtc *crtc;
struct drm_framebuffer *fb;
struct sde_rect src, dst;
+ const struct sde_rect *crtc_roi;
bool q16_data = true;
int idx;
@@ -2291,6 +2292,11 @@
}
}
+ /* re-program the output rects always in the case of partial update */
+ sde_crtc_get_crtc_roi(crtc->state, &crtc_roi);
+ if (!sde_kms_rect_is_null(crtc_roi))
+ pstate->dirty |= SDE_PLANE_DIRTY_RECTS;
+
if (pstate->dirty & SDE_PLANE_DIRTY_RECTS)
memset(&(psde->pipe_cfg), 0, sizeof(struct sde_hw_pipe_cfg));
@@ -2328,6 +2334,13 @@
src.y &= ~0x1;
}
+ /*
+ * adjust layer mixer position of the sspp in the presence
+ * of a partial update to the active lm origin
+ */
+ dst.x -= crtc_roi->x;
+ dst.y -= crtc_roi->y;
+
psde->pipe_cfg.src_rect = src;
psde->pipe_cfg.dst_rect = dst;
diff --git a/drivers/gpu/drm/msm/sde_power_handle.c b/drivers/gpu/drm/msm/sde_power_handle.c
index 62efe8e..3618479 100644
--- a/drivers/gpu/drm/msm/sde_power_handle.c
+++ b/drivers/gpu/drm/msm/sde_power_handle.c
@@ -25,10 +25,48 @@
#include <linux/msm-bus.h>
#include <linux/msm-bus-board.h>
#include <linux/sde_io_util.h>
+#include <linux/sde_rsc.h>
#include "sde_power_handle.h"
#include "sde_trace.h"
+static void sde_power_event_trigger_locked(struct sde_power_handle *phandle,
+ u32 event_type)
+{
+ struct sde_power_event *event;
+
+ list_for_each_entry(event, &phandle->event_list, list) {
+ if (event->event_type & event_type)
+ event->cb_fnc(event_type, event->usr);
+ }
+}
+
+static int sde_power_rsc_update(struct sde_power_handle *phandle, bool enable)
+{
+ u32 rsc_state;
+ int ret = 0;
+
+ /* creates the rsc client on the first enable */
+ if (!phandle->rsc_client_init) {
+ phandle->rsc_client = sde_rsc_client_create(SDE_RSC_INDEX,
+ "sde_power_handle", false);
+ if (IS_ERR_OR_NULL(phandle->rsc_client)) {
+ pr_debug("sde rsc client create failed :%ld\n",
+ PTR_ERR(phandle->rsc_client));
+ phandle->rsc_client = NULL;
+ }
+ phandle->rsc_client_init = true;
+ }
+
+ rsc_state = enable ? SDE_RSC_CLK_STATE : SDE_RSC_IDLE_STATE;
+
+ if (phandle->rsc_client)
+ ret = sde_rsc_client_state_update(phandle->rsc_client,
+ rsc_state, NULL, -1);
+
+ return ret;
+}
+
struct sde_power_client *sde_power_client_create(
struct sde_power_handle *phandle, char *client_name)
{
@@ -48,6 +86,7 @@
strlcpy(client->name, client_name, MAX_CLIENT_NAME_LEN);
client->usecase_ndx = VOTE_INDEX_DISABLE;
client->id = id;
+ client->active = true;
pr_debug("client %s created:%pK id :%d\n", client_name,
client, id);
id++;
@@ -62,6 +101,9 @@
{
if (!client || !phandle) {
pr_err("reg bus vote: invalid client handle\n");
+ } else if (!client->active) {
+ pr_err("sde power deinit already done\n");
+ kfree(client);
} else {
pr_debug("bus vote client %s destroyed:%pK id:%u\n",
client->name, client, client->id);
@@ -661,6 +703,11 @@
}
INIT_LIST_HEAD(&phandle->power_client_clist);
+ INIT_LIST_HEAD(&phandle->event_list);
+
+ phandle->rsc_client = NULL;
+ phandle->rsc_client_init = false;
+
mutex_init(&phandle->phandle_lock);
return rc;
@@ -672,10 +719,12 @@
clk_err:
msm_dss_config_vreg(&pdev->dev, mp->vreg_config, mp->num_vreg, 0);
vreg_err:
- devm_kfree(&pdev->dev, mp->vreg_config);
+ if (mp->vreg_config)
+ devm_kfree(&pdev->dev, mp->vreg_config);
mp->num_vreg = 0;
parse_vreg_err:
- devm_kfree(&pdev->dev, mp->clk_config);
+ if (mp->clk_config)
+ devm_kfree(&pdev->dev, mp->clk_config);
mp->num_clk = 0;
end:
return rc;
@@ -685,6 +734,8 @@
struct sde_power_handle *phandle)
{
struct dss_module_power *mp;
+ struct sde_power_client *curr_client, *next_client;
+ struct sde_power_event *curr_event, *next_event;
if (!phandle || !pdev) {
pr_err("invalid input param\n");
@@ -692,6 +743,26 @@
}
mp = &phandle->mp;
+ mutex_lock(&phandle->phandle_lock);
+ list_for_each_entry_safe(curr_client, next_client,
+ &phandle->power_client_clist, list) {
+ pr_err("cliend:%s-%d still registered with refcount:%d\n",
+ curr_client->name, curr_client->id,
+ curr_client->refcount);
+ curr_client->active = false;
+ list_del(&curr_client->list);
+ }
+
+ list_for_each_entry_safe(curr_event, next_event,
+ &phandle->event_list, list) {
+ pr_err("event:%d, client:%s still registered\n",
+ curr_event->event_type,
+ curr_event->client_name);
+ curr_event->active = false;
+ list_del(&curr_event->list);
+ }
+ mutex_unlock(&phandle->phandle_lock);
+
sde_power_data_bus_unregister(&phandle->data_bus_handle);
sde_power_reg_bus_unregister(phandle->reg_bus_hdl);
@@ -708,6 +779,9 @@
mp->num_vreg = 0;
mp->num_clk = 0;
+
+ if (phandle->rsc_client)
+ sde_rsc_client_destroy(phandle->rsc_client);
}
int sde_power_resource_enable(struct sde_power_handle *phandle,
@@ -757,6 +831,9 @@
goto end;
if (enable) {
+ sde_power_event_trigger_locked(phandle,
+ SDE_POWER_EVENT_PRE_ENABLE);
+
rc = sde_power_data_bus_update(&phandle->data_bus_handle,
enable);
if (rc) {
@@ -764,10 +841,13 @@
goto data_bus_hdl_err;
}
- rc = msm_dss_enable_vreg(mp->vreg_config, mp->num_vreg, enable);
- if (rc) {
- pr_err("failed to enable vregs rc=%d\n", rc);
- goto vreg_err;
+ if (!phandle->rsc_client_init) {
+ rc = msm_dss_enable_vreg(mp->vreg_config, mp->num_vreg,
+ enable);
+ if (rc) {
+ pr_err("failed to enable vregs rc=%d\n", rc);
+ goto vreg_err;
+ }
}
rc = sde_power_reg_bus_update(phandle->reg_bus_hdl,
@@ -777,20 +857,39 @@
goto reg_bus_hdl_err;
}
+ rc = sde_power_rsc_update(phandle, true);
+ if (rc) {
+ pr_err("failed to update rsc\n");
+ goto rsc_err;
+ }
+
rc = msm_dss_enable_clk(mp->clk_config, mp->num_clk, enable);
if (rc) {
pr_err("clock enable failed rc:%d\n", rc);
goto clk_err;
}
+
+ sde_power_event_trigger_locked(phandle,
+ SDE_POWER_EVENT_POST_ENABLE);
+
} else {
+ sde_power_event_trigger_locked(phandle,
+ SDE_POWER_EVENT_PRE_DISABLE);
+
msm_dss_enable_clk(mp->clk_config, mp->num_clk, enable);
+ sde_power_rsc_update(phandle, false);
+
sde_power_reg_bus_update(phandle->reg_bus_hdl,
max_usecase_ndx);
- msm_dss_enable_vreg(mp->vreg_config, mp->num_vreg, enable);
-
+ if (!phandle->rsc_client_init)
+ msm_dss_enable_vreg(mp->vreg_config, mp->num_vreg,
+ enable);
sde_power_data_bus_update(&phandle->data_bus_handle, enable);
+
+ sde_power_event_trigger_locked(phandle,
+ SDE_POWER_EVENT_POST_DISABLE);
}
end:
@@ -798,9 +897,12 @@
return rc;
clk_err:
+ sde_power_rsc_update(phandle, false);
+rsc_err:
sde_power_reg_bus_update(phandle->reg_bus_hdl, prev_usecase_ndx);
reg_bus_hdl_err:
- msm_dss_enable_vreg(mp->vreg_config, mp->num_vreg, 0);
+ if (!phandle->rsc_client_init)
+ msm_dss_enable_vreg(mp->vreg_config, mp->num_vreg, 0);
vreg_err:
sde_power_data_bus_update(&phandle->data_bus_handle, 0);
data_bus_hdl_err:
@@ -903,3 +1005,52 @@
return clk;
}
+
+struct sde_power_event *sde_power_handle_register_event(
+ struct sde_power_handle *phandle,
+ u32 event_type, void (*cb_fnc)(u32 event_type, void *usr),
+ void *usr, char *client_name)
+{
+ struct sde_power_event *event;
+
+ if (!phandle) {
+ pr_err("invalid power handle\n");
+ return ERR_PTR(-EINVAL);
+ } else if (!cb_fnc || !event_type) {
+ pr_err("no callback fnc or event type\n");
+ return ERR_PTR(-EINVAL);
+ }
+
+ event = kzalloc(sizeof(struct sde_power_event), GFP_KERNEL);
+ if (!event)
+ return ERR_PTR(-ENOMEM);
+
+ event->event_type = event_type;
+ event->cb_fnc = cb_fnc;
+ event->usr = usr;
+ strlcpy(event->client_name, client_name, MAX_CLIENT_NAME_LEN);
+ event->active = true;
+
+ mutex_lock(&phandle->phandle_lock);
+ list_add(&event->list, &phandle->event_list);
+ mutex_unlock(&phandle->phandle_lock);
+
+ return event;
+}
+
+void sde_power_handle_unregister_event(
+ struct sde_power_handle *phandle,
+ struct sde_power_event *event)
+{
+ if (!phandle || !event) {
+ pr_err("invalid phandle or event\n");
+ } else if (!event->active) {
+ pr_err("power handle deinit already done\n");
+ kfree(event);
+ } else {
+ mutex_lock(&phandle->phandle_lock);
+ list_del_init(&event->list);
+ mutex_unlock(&phandle->phandle_lock);
+ kfree(event);
+ }
+}
diff --git a/drivers/gpu/drm/msm/sde_power_handle.h b/drivers/gpu/drm/msm/sde_power_handle.h
index 4e262a3..b26ef9f 100644
--- a/drivers/gpu/drm/msm/sde_power_handle.h
+++ b/drivers/gpu/drm/msm/sde_power_handle.h
@@ -23,6 +23,18 @@
#include <linux/sde_io_util.h>
+/* event will be triggered before power handler disable */
+#define SDE_POWER_EVENT_PRE_DISABLE 0x1
+
+/* event will be triggered after power handler disable */
+#define SDE_POWER_EVENT_POST_DISABLE 0x2
+
+/* event will be triggered before power handler enable */
+#define SDE_POWER_EVENT_PRE_ENABLE 0x4
+
+/* event will be triggered after power handler enable */
+#define SDE_POWER_EVENT_POST_ENABLE 0x8
+
/**
* mdss_bus_vote_type: register bus vote type
* VOTE_INDEX_DISABLE: removes the client vote
@@ -59,6 +71,7 @@
* @list: list to attach power handle master list
* @ab: arbitrated bandwidth for each bus client
* @ib: instantaneous bandwidth for each bus client
+ * @active: inidcates the state of sde power handle
*/
struct sde_power_client {
char name[MAX_CLIENT_NAME_LEN];
@@ -68,6 +81,7 @@
struct list_head list;
u64 ab[SDE_POWER_HANDLE_DATA_BUS_CLIENT_MAX];
u64 ib[SDE_POWER_HANDLE_DATA_BUS_CLIENT_MAX];
+ bool active;
};
/**
@@ -90,6 +104,24 @@
u32 ao_bw_uc_idx;
};
+/*
+ * struct sde_power_event - local event registration structure
+ * @client_name: name of the client registering
+ * @cb_fnc: pointer to desired callback function
+ * @usr: user pointer to pass to callback event trigger
+ * @event: refer to SDE_POWER_HANDLE_EVENT_*
+ * @list: list to attach event master list
+ * @active: indicates the state of sde power handle
+ */
+struct sde_power_event {
+ char client_name[MAX_CLIENT_NAME_LEN];
+ void (*cb_fnc)(u32 event_type, void *usr);
+ void *usr;
+ u32 event_type;
+ struct list_head list;
+ bool active;
+};
+
/**
* struct sde_power_handle: power handle main struct
* @mp: module power for clock and regulator
@@ -99,6 +131,9 @@
* @usecase_ndx: current usecase index
* @reg_bus_hdl: current register bus handle
* @data_bus_handle: context structure for data bus control
+ * @event_list: current power handle event list
+ * @rsc_client: sde rsc client pointer
+ * @rsc_client_init: boolean to control rsc client create
*/
struct sde_power_handle {
struct dss_module_power mp;
@@ -108,6 +143,9 @@
u32 current_usecase_ndx;
u32 reg_bus_hdl;
struct sde_power_data_bus_handle data_bus_handle;
+ struct list_head event_list;
+ struct sde_rsc_client *rsc_client;
+ bool rsc_client_init;
};
/**
@@ -226,4 +264,28 @@
void sde_power_data_bus_bandwidth_ctrl(struct sde_power_handle *phandle,
struct sde_power_client *pclient, int enable);
+/**
+ * sde_power_handle_register_event - register a callback function for an event.
+ * Clients can register for multiple events with a single register.
+ * Any block with access to phandle can register for the event
+ * notification.
+ * @phandle: power handle containing the resources
+ * @event_type: event type to register; refer SDE_POWER_HANDLE_EVENT_*
+ * @cb_fnc: pointer to desired callback function
+ * @usr: user pointer to pass to callback on event trigger
+ *
+ * Return: event pointer if success, or error code otherwise
+ */
+struct sde_power_event *sde_power_handle_register_event(
+ struct sde_power_handle *phandle,
+ u32 event_type, void (*cb_fnc)(u32 event_type, void *usr),
+ void *usr, char *client_name);
+/**
+ * sde_power_handle_unregister_event - unregister callback for event(s)
+ * @phandle: power handle containing the resources
+ * @event: event pointer returned after power handle register
+ */
+void sde_power_handle_unregister_event(struct sde_power_handle *phandle,
+ struct sde_power_event *event);
+
#endif /* _SDE_POWER_HANDLE_H_ */
diff --git a/drivers/gpu/drm/msm/sde_rsc.c b/drivers/gpu/drm/msm/sde_rsc.c
index c1b812a..d762904 100644
--- a/drivers/gpu/drm/msm/sde_rsc.c
+++ b/drivers/gpu/drm/msm/sde_rsc.c
@@ -388,7 +388,7 @@
static int sde_rsc_switch_to_cmd(struct sde_rsc_priv *rsc,
struct sde_rsc_cmd_config *config,
- struct sde_rsc_client *caller_client, bool wait_req)
+ struct sde_rsc_client *caller_client)
{
struct sde_rsc_client *client;
int rc = STATE_UPDATE_NOT_ALLOWED;
@@ -416,8 +416,8 @@
if (rsc->hw_ops.state_update)
rc = rsc->hw_ops.state_update(rsc, SDE_RSC_CMD_STATE);
- /* wait for vsync */
- if (!rc && wait_req)
+ /* wait for vsync for vid to cmd state switch */
+ if (!rc && (rsc->current_state == SDE_RSC_VID_STATE))
drm_wait_one_vblank(rsc->master_drm,
rsc->primary_client->crtc_id);
end:
@@ -436,13 +436,19 @@
if (rsc->hw_ops.state_update)
rc = rsc->hw_ops.state_update(rsc, SDE_RSC_CLK_STATE);
+
+ /* wait for vsync for cmd to clk state switch */
+ if (!rc && rsc->primary_client &&
+ (rsc->current_state == SDE_RSC_CMD_STATE))
+ drm_wait_one_vblank(rsc->master_drm,
+ rsc->primary_client->crtc_id);
end:
return rc;
}
static bool sde_rsc_switch_to_vid(struct sde_rsc_priv *rsc,
struct sde_rsc_cmd_config *config,
- struct sde_rsc_client *caller_client, bool wait_req)
+ struct sde_rsc_client *caller_client)
{
int rc = 0;
@@ -454,8 +460,9 @@
if (rsc->hw_ops.state_update)
rc = rsc->hw_ops.state_update(rsc, SDE_RSC_VID_STATE);
- /* wait for vsync */
- if (!rc && rsc->primary_client && wait_req)
+ /* wait for vsync for cmd to vid state switch */
+ if (!rc && rsc->primary_client &&
+ (rsc->current_state == SDE_RSC_CMD_STATE))
drm_wait_one_vblank(rsc->master_drm,
rsc->primary_client->crtc_id);
return rc;
@@ -481,7 +488,6 @@
{
int rc = 0;
struct sde_rsc_priv *rsc;
- bool wait_requested = false;
if (!caller_client) {
pr_err("invalid client for rsc state update\n");
@@ -512,11 +518,7 @@
__builtin_return_address(0), rsc->current_state,
caller_client->name, state);
- /* only switch state needs vsync wait */
- wait_requested = (rsc->current_state == SDE_RSC_VID_STATE) ||
- (rsc->current_state == SDE_RSC_CMD_STATE);
-
- if (rsc->power_collapse)
+ if (rsc->current_state == SDE_RSC_IDLE_STATE)
sde_rsc_clk_enable(&rsc->phandle, rsc->pclient, true);
switch (state) {
@@ -526,7 +528,7 @@
/* video state client might be exiting; try cmd state switch */
if (rc == TRY_CMD_MODE_SWITCH) {
rc = sde_rsc_switch_to_cmd(rsc, NULL,
- rsc->primary_client, wait_requested);
+ rsc->primary_client);
if (!rc)
state = SDE_RSC_CMD_STATE;
@@ -539,13 +541,11 @@
break;
case SDE_RSC_CMD_STATE:
- rc = sde_rsc_switch_to_cmd(rsc, config, caller_client,
- wait_requested);
+ rc = sde_rsc_switch_to_cmd(rsc, config, caller_client);
break;
case SDE_RSC_VID_STATE:
- rc = sde_rsc_switch_to_vid(rsc, config, caller_client,
- wait_requested);
+ rc = sde_rsc_switch_to_vid(rsc, config, caller_client);
break;
case SDE_RSC_CLK_STATE:
@@ -561,7 +561,7 @@
rc = 0;
goto clk_disable;
} else if (rc) {
- pr_err("state update failed rc:%d\n", rc);
+ pr_debug("state:%d update failed rc:%d\n", state, rc);
goto clk_disable;
}
@@ -569,7 +569,7 @@
rsc->current_state = state;
clk_disable:
- if (rsc->power_collapse)
+ if (rsc->current_state == SDE_RSC_IDLE_STATE)
sde_rsc_clk_enable(&rsc->phandle, rsc->pclient, false);
end:
mutex_unlock(&rsc->client_lock);
@@ -615,14 +615,9 @@
caller_client->name, ab_vote, ib_vote);
mutex_lock(&rsc->client_lock);
- if ((caller_client->current_state == SDE_RSC_IDLE_STATE) ||
- (rsc->current_state == SDE_RSC_IDLE_STATE)) {
-
- pr_err("invalid state: client state:%d rsc state:%d\n",
- caller_client->current_state, rsc->current_state);
- rc = -EINVAL;
- goto end;
- }
+ rc = sde_rsc_clk_enable(&rsc->phandle, rsc->pclient, true);
+ if (rc)
+ goto clk_enable_fail;
if (rsc->hw_ops.is_amc_mode)
amc_mode = rsc->hw_ops.is_amc_mode(rsc);
@@ -644,14 +639,19 @@
}
}
+ rpmh_invalidate(rsc->disp_rsc);
sde_power_data_bus_set_quota(&rsc->phandle, rsc->pclient,
SDE_POWER_HANDLE_DATA_BUS_CLIENT_RT, ab_vote, ib_vote);
+ rpmh_flush(rsc->disp_rsc);
if (rsc->hw_ops.tcs_use_ok)
rsc->hw_ops.tcs_use_ok(rsc);
end:
+ sde_rsc_clk_enable(&rsc->phandle, rsc->pclient, false);
+clk_enable_fail:
mutex_unlock(&rsc->client_lock);
+
return rc;
}
EXPORT_SYMBOL(sde_rsc_client_vote);
@@ -668,6 +668,10 @@
rsc = s->private;
mutex_lock(&rsc->client_lock);
+ ret = sde_rsc_clk_enable(&rsc->phandle, rsc->pclient, true);
+ if (ret)
+ goto end;
+
seq_printf(s, "rsc current state:%d\n", rsc->current_state);
seq_printf(s, "wraper backoff time(ns):%d\n",
rsc->timer_config.static_wakeup_time_ns);
@@ -691,17 +695,15 @@
seq_printf(s, "\t client:%s state:%d\n",
client->name, client->current_state);
- sde_rsc_clk_enable(&rsc->phandle, rsc->pclient, true);
-
if (rsc->hw_ops.debug_show) {
ret = rsc->hw_ops.debug_show(s, rsc);
if (ret)
pr_err("sde rsc: hw debug failed ret:%d\n", ret);
}
-
sde_rsc_clk_enable(&rsc->phandle, rsc->pclient, false);
- mutex_unlock(&rsc->client_lock);
+end:
+ mutex_unlock(&rsc->client_lock);
return 0;
}
@@ -722,20 +724,23 @@
{
struct sde_rsc_priv *rsc = file->private_data;
char buffer[MAX_BUFFER_SIZE];
- int blen = 0;
+ int blen = 0, rc;
if (*ppos || !rsc || !rsc->hw_ops.mode_ctrl)
return 0;
mutex_lock(&rsc->client_lock);
- sde_rsc_clk_enable(&rsc->phandle, rsc->pclient, true);
+ rc = sde_rsc_clk_enable(&rsc->phandle, rsc->pclient, true);
+ if (rc)
+ goto end;
blen = rsc->hw_ops.mode_ctrl(rsc, MODE_READ, buffer,
MAX_BUFFER_SIZE, 0);
sde_rsc_clk_enable(&rsc->phandle, rsc->pclient, false);
- mutex_unlock(&rsc->client_lock);
+end:
+ mutex_unlock(&rsc->client_lock);
if (blen < 0)
return 0;
@@ -752,6 +757,7 @@
struct sde_rsc_priv *rsc = file->private_data;
char *input, *mode;
u32 mode0_state = 0, mode1_state = 0, mode2_state = 0;
+ int rc;
if (!rsc || !rsc->hw_ops.mode_ctrl)
return 0;
@@ -767,7 +773,9 @@
input[count - 1] = '\0';
mutex_lock(&rsc->client_lock);
- sde_rsc_clk_enable(&rsc->phandle, rsc->pclient, true);
+ rc = sde_rsc_clk_enable(&rsc->phandle, rsc->pclient, true);
+ if (rc)
+ goto clk_enable_fail;
mode = strnstr(input, "mode0=", strlen("mode0="));
if (mode) {
@@ -794,9 +802,10 @@
end:
sde_rsc_clk_enable(&rsc->phandle, rsc->pclient, false);
+clk_enable_fail:
mutex_unlock(&rsc->client_lock);
- pr_err("req: mode0:%d mode1:%d mode2:%d\n", mode0_state, mode1_state,
+ pr_info("req: mode0:%d mode1:%d mode2:%d\n", mode0_state, mode1_state,
mode2_state);
kfree(input);
return count;
@@ -814,20 +823,23 @@
{
struct sde_rsc_priv *rsc = file->private_data;
char buffer[MAX_BUFFER_SIZE];
- int blen = 0;
+ int blen = 0, rc;
if (*ppos || !rsc || !rsc->hw_ops.hw_vsync)
return 0;
mutex_lock(&rsc->client_lock);
- sde_rsc_clk_enable(&rsc->phandle, rsc->pclient, true);
+ rc = sde_rsc_clk_enable(&rsc->phandle, rsc->pclient, true);
+ if (rc)
+ goto end;
blen = rsc->hw_ops.hw_vsync(rsc, VSYNC_READ, buffer,
MAX_BUFFER_SIZE, 0);
sde_rsc_clk_enable(&rsc->phandle, rsc->pclient, false);
- mutex_unlock(&rsc->client_lock);
+end:
+ mutex_unlock(&rsc->client_lock);
if (blen < 0)
return 0;
@@ -844,6 +856,7 @@
struct sde_rsc_priv *rsc = file->private_data;
char *input, *vsync_mode;
u32 vsync_state = 0;
+ int rc;
if (!rsc || !rsc->hw_ops.hw_vsync)
return 0;
@@ -865,7 +878,9 @@
}
mutex_lock(&rsc->client_lock);
- sde_rsc_clk_enable(&rsc->phandle, rsc->pclient, true);
+ rc = sde_rsc_clk_enable(&rsc->phandle, rsc->pclient, true);
+ if (rc)
+ goto end;
if (vsync_state)
rsc->hw_ops.hw_vsync(rsc, VSYNC_ENABLE, NULL,
@@ -874,8 +889,9 @@
rsc->hw_ops.hw_vsync(rsc, VSYNC_DISABLE, NULL, 0, 0);
sde_rsc_clk_enable(&rsc->phandle, rsc->pclient, false);
- mutex_unlock(&rsc->client_lock);
+end:
+ mutex_unlock(&rsc->client_lock);
kfree(input);
return count;
}
@@ -930,6 +946,8 @@
msm_dss_iounmap(&rsc->wrapper_io);
if (rsc->drv_io.base)
msm_dss_iounmap(&rsc->drv_io);
+ if (rsc->disp_rsc)
+ rpmh_release(rsc->disp_rsc);
if (rsc->pclient)
sde_power_client_destroy(&rsc->phandle, rsc->pclient);
@@ -1038,6 +1056,17 @@
goto sde_rsc_fail;
}
+ rsc->disp_rsc = rpmh_get_byname(pdev, "disp_rsc");
+ if (IS_ERR_OR_NULL(rsc->disp_rsc)) {
+ ret = PTR_ERR(rsc->disp_rsc);
+ rsc->disp_rsc = NULL;
+ pr_err("sde rsc:get display rsc failed ret:%d\n", ret);
+ goto sde_rsc_fail;
+ }
+ rpmh_invalidate(rsc->disp_rsc);
+ /* call flush to disable the disp rsc interrupt */
+ rpmh_flush(rsc->disp_rsc);
+
ret = msm_dss_ioremap_byname(pdev, &rsc->wrapper_io, "wrapper");
if (ret) {
pr_err("sde rsc: wrapper io data mapping failed ret=%d\n", ret);
@@ -1084,7 +1113,6 @@
snprintf(name, MAX_RSC_CLIENT_NAME_LEN, "%s%d", "sde_rsc", counter);
_sde_rsc_init_debugfs(rsc, name);
counter++;
- rsc->power_collapse = true;
ret = component_add(&pdev->dev, &sde_rsc_comp_ops);
if (ret)
diff --git a/drivers/gpu/drm/msm/sde_rsc_hw.c b/drivers/gpu/drm/msm/sde_rsc_hw.c
index de579c1..b63fbc6 100644
--- a/drivers/gpu/drm/msm/sde_rsc_hw.c
+++ b/drivers/gpu/drm/msm/sde_rsc_hw.c
@@ -36,6 +36,7 @@
#define SDE_RSCC_AMC_TCS_MODE_IRQ_STATUS_DRV0 0x1c00
#define SDE_RSCC_SOFT_WAKEUP_TIME_LO_DRV0 0xc04
+#define SDE_RSCC_SOFT_WAKEUP_TIME_HI_DRV0 0xc08
#define SDE_RSCC_MAX_IDLE_DURATION_DRV0 0xc0c
#define SDE_RSC_SOLVER_TIME_SLOT_TABLE_0_DRV0 0x1000
#define SDE_RSC_SOLVER_TIME_SLOT_TABLE_1_DRV0 0x1004
@@ -224,7 +225,9 @@
pr_debug("rsc solver init\n");
dss_reg_w(&rsc->drv_io, SDE_RSCC_SOFT_WAKEUP_TIME_LO_DRV0,
- 0x7FFFFFFF, rsc->debug_mode);
+ 0xFFFFFFFF, rsc->debug_mode);
+ dss_reg_w(&rsc->drv_io, SDE_RSCC_SOFT_WAKEUP_TIME_HI_DRV0,
+ 0xFFFFFFFF, rsc->debug_mode);
dss_reg_w(&rsc->drv_io, SDE_RSCC_MAX_IDLE_DURATION_DRV0,
0xEFFFFFFF, rsc->debug_mode);
@@ -308,6 +311,15 @@
rsc_event_trigger(rsc, SDE_RSC_EVENT_PRE_CORE_PC);
+ /* update qtimers to high during clk & video mode state */
+ if ((rsc->current_state == SDE_RSC_VID_STATE) ||
+ (rsc->current_state == SDE_RSC_CLK_STATE)) {
+ dss_reg_w(&rsc->wrapper_io, SDE_RSCC_F0_QTMR_V1_CNTP_CVAL_HI,
+ 0xffffffff, rsc->debug_mode);
+ dss_reg_w(&rsc->wrapper_io, SDE_RSCC_F0_QTMR_V1_CNTP_CVAL_LO,
+ 0xffffffff, rsc->debug_mode);
+ }
+
wrapper_status = dss_reg_r(&rsc->wrapper_io, SDE_RSCC_WRAPPER_CTRL,
rsc->debug_mode);
wrapper_status |= BIT(3);
@@ -357,8 +369,6 @@
return 0;
end:
- regulator_set_mode(rsc->fs, REGULATOR_MODE_NORMAL);
-
rsc_event_trigger(rsc, SDE_RSC_EVENT_POST_CORE_RESTORE);
return rc;
@@ -378,8 +388,7 @@
if ((state == SDE_RSC_VID_STATE) || (state == SDE_RSC_CLK_STATE)) {
reg = dss_reg_r(&rsc->wrapper_io,
SDE_RSCC_WRAPPER_OVERRIDE_CTRL, rsc->debug_mode);
- reg |= BIT(8);
- reg &= ~(BIT(1) | BIT(0));
+ reg &= ~(BIT(8) | BIT(0));
dss_reg_w(&rsc->wrapper_io, SDE_RSCC_WRAPPER_OVERRIDE_CTRL,
reg, rsc->debug_mode);
}
@@ -411,7 +420,7 @@
rc = 0;
break;
}
- usleep_range(1, 2);
+ usleep_range(10, 100);
}
reg = dss_reg_r(&rsc->wrapper_io, SDE_RSCC_SPARE_PWR_EVENT,
@@ -419,14 +428,9 @@
reg &= ~BIT(13);
dss_reg_w(&rsc->wrapper_io, SDE_RSCC_SPARE_PWR_EVENT,
reg, rsc->debug_mode);
-
if (rc)
pr_err("vdd reg is not enabled yet\n");
- rc = regulator_set_mode(rsc->fs, REGULATOR_MODE_NORMAL);
- if (rc)
- pr_err("vdd reg normal mode set failed rc:%d\n", rc);
-
rsc_event_trigger(rsc, SDE_RSC_EVENT_POST_CORE_RESTORE);
return rc;
@@ -454,6 +458,9 @@
0x1, rsc->debug_mode);
dss_reg_w(&rsc->drv_io, SDE_RSCC_SOLVER_OVERRIDE_CTRL_DRV0,
0x0, rsc->debug_mode);
+ dss_reg_w(&rsc->drv_io,
+ SDE_RSC_SOLVER_SOLVER_MODES_ENABLED_DRV0, 0x7,
+ rsc->debug_mode);
reg = dss_reg_r(&rsc->wrapper_io,
SDE_RSCC_WRAPPER_OVERRIDE_CTRL, rsc->debug_mode);
reg |= (BIT(0) | BIT(8));
@@ -477,8 +484,9 @@
reg &= ~(BIT(1) | BIT(0));
dss_reg_w(&rsc->wrapper_io, SDE_RSCC_WRAPPER_OVERRIDE_CTRL,
reg, rsc->debug_mode);
- dss_reg_w(&rsc->drv_io, SDE_RSCC_SOLVER_OVERRIDE_CTRL_DRV0,
- 0x1, rsc->debug_mode);
+ dss_reg_w(&rsc->drv_io,
+ SDE_RSC_SOLVER_SOLVER_MODES_ENABLED_DRV0, 0x5,
+ rsc->debug_mode);
/* make sure that solver mode is override */
wmb();
@@ -487,6 +495,17 @@
case SDE_RSC_CLK_STATE:
pr_debug("clk state handling\n");
+
+ reg = dss_reg_r(&rsc->wrapper_io,
+ SDE_RSCC_WRAPPER_OVERRIDE_CTRL, rsc->debug_mode);
+ reg &= ~(BIT(8) | BIT(0));
+ dss_reg_w(&rsc->wrapper_io, SDE_RSCC_WRAPPER_OVERRIDE_CTRL,
+ reg, rsc->debug_mode);
+ dss_reg_w(&rsc->drv_io,
+ SDE_RSC_SOLVER_SOLVER_MODES_ENABLED_DRV0, 0x5,
+ rsc->debug_mode);
+ /* make sure that solver mode is disabled */
+ wmb();
break;
case SDE_RSC_IDLE_STATE:
diff --git a/drivers/gpu/drm/msm/sde_rsc_priv.h b/drivers/gpu/drm/msm/sde_rsc_priv.h
index 30810fe..b83a866 100644
--- a/drivers/gpu/drm/msm/sde_rsc_priv.h
+++ b/drivers/gpu/drm/msm/sde_rsc_priv.h
@@ -111,6 +111,7 @@
* @pclient: module power client of phandle
* @fs: "MDSS GDSC" handle
*
+ * @disp_rsc: display rsc handle
* @drv_io: sde drv io data mapping
* @wrapper_io: wrapper io data mapping
*
@@ -141,6 +142,7 @@
struct sde_power_client *pclient;
struct regulator *fs;
+ struct rpmh_client *disp_rsc;
struct dss_io_data drv_io;
struct dss_io_data wrapper_io;
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c
index e0d7f84..d741ff8 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c
@@ -714,7 +714,7 @@
.i2c = nv04_i2c_new,
.imem = nv40_instmem_new,
.mc = nv44_mc_new,
- .mmu = nv44_mmu_new,
+ .mmu = nv04_mmu_new,
.pci = nv40_pci_new,
.therm = nv40_therm_new,
.timer = nv41_timer_new,
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.c
index fbb8c7d..0d65e7f 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.c
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.c
@@ -433,8 +433,6 @@
case 0x94:
case 0x96:
case 0x98:
- case 0xaa:
- case 0xac:
return true;
default:
break;
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/mpeg/nv31.c b/drivers/gpu/drm/nouveau/nvkm/engine/mpeg/nv31.c
index 003ac91..8a88952 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/mpeg/nv31.c
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/mpeg/nv31.c
@@ -198,7 +198,7 @@
}
if (type == 0x00000010) {
- if (!nv31_mpeg_mthd(mpeg, mthd, data))
+ if (nv31_mpeg_mthd(mpeg, mthd, data))
show &= ~0x01000000;
}
}
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/mpeg/nv44.c b/drivers/gpu/drm/nouveau/nvkm/engine/mpeg/nv44.c
index e536f37..c3cf02e 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/mpeg/nv44.c
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/mpeg/nv44.c
@@ -172,7 +172,7 @@
}
if (type == 0x00000010) {
- if (!nv44_mpeg_mthd(subdev->device, mthd, data))
+ if (nv44_mpeg_mthd(subdev->device, mthd, data))
show &= ~0x01000000;
}
}
diff --git a/drivers/gpu/msm/a6xx_reg.h b/drivers/gpu/msm/a6xx_reg.h
index fddfb2c..69b639a 100644
--- a/drivers/gpu/msm/a6xx_reg.h
+++ b/drivers/gpu/msm/a6xx_reg.h
@@ -678,6 +678,7 @@
#define A6XX_GMU_DCVS_RETURN 0x1CBFF
#define A6XX_GMU_CM3_SYSRESET 0x1F800
#define A6XX_GMU_CM3_BOOT_CONFIG 0x1F801
+#define A6XX_GMU_CM3_FW_BUSY 0x1F81A
#define A6XX_GMU_CM3_FW_INIT_RESULT 0x1F81C
#define A6XX_GMU_PWR_COL_INTER_FRAME_CTRL 0x1F8C0
#define A6XX_GMU_PWR_COL_INTER_FRAME_HYST 0x1F8C1
@@ -718,9 +719,9 @@
#define A6XX_GMU_GENERAL_7 0x1F9CC
#define A6XX_GMU_AO_INTERRUPT_EN 0x23B03
-#define A6XX_GMU_HOST_INTERRUPT_CLR 0x23B04
-#define A6XX_GMU_HOST_INTERRUPT_STATUS 0x23B05
-#define A6XX_GMU_HOST_INTERRUPT_MASK 0x23B06
+#define A6XX_GMU_AO_HOST_INTERRUPT_CLR 0x23B04
+#define A6XX_GMU_AO_HOST_INTERRUPT_STATUS 0x23B05
+#define A6XX_GMU_AO_HOST_INTERRUPT_MASK 0x23B06
#define A6XX_GPU_GMU_AO_GPU_CX_BUSY_STATUS 0x23B0C
#define A6XX_GMU_AHB_FENCE_STATUS 0x23B13
#define A6XX_GMU_RBBM_INT_UNMASKED_STATUS 0x23B15
@@ -764,7 +765,6 @@
#define PDC_GPU_TCS1_CMD0_MSGID 0x21575
#define PDC_GPU_TCS1_CMD0_ADDR 0x21576
#define PDC_GPU_TCS1_CMD0_DATA 0x21577
-#define PDC_GPU_TIMESTAMP_UNIT1_EN_DRV0 0x23489
#define PDC_GPU_SEQ_MEM_0 0xA0000
#endif /* _A6XX_REG_H */
diff --git a/drivers/gpu/msm/adreno.h b/drivers/gpu/msm/adreno.h
index 75d5587..530529f 100644
--- a/drivers/gpu/msm/adreno.h
+++ b/drivers/gpu/msm/adreno.h
@@ -618,9 +618,9 @@
ADRENO_REG_VBIF_XIN_HALT_CTRL1,
ADRENO_REG_VBIF_VERSION,
ADRENO_REG_GMU_AO_INTERRUPT_EN,
- ADRENO_REG_GMU_HOST_INTERRUPT_CLR,
- ADRENO_REG_GMU_HOST_INTERRUPT_STATUS,
- ADRENO_REG_GMU_HOST_INTERRUPT_MASK,
+ ADRENO_REG_GMU_AO_HOST_INTERRUPT_CLR,
+ ADRENO_REG_GMU_AO_HOST_INTERRUPT_STATUS,
+ ADRENO_REG_GMU_AO_HOST_INTERRUPT_MASK,
ADRENO_REG_GMU_PWR_COL_KEEPALIVE,
ADRENO_REG_GMU_AHB_FENCE_STATUS,
ADRENO_REG_GMU_RPMH_POWER_STATE,
@@ -629,6 +629,7 @@
ADRENO_REG_GMU_HFI_SFR_ADDR,
ADRENO_REG_GMU_GMU2HOST_INTR_CLR,
ADRENO_REG_GMU_GMU2HOST_INTR_INFO,
+ ADRENO_REG_GMU_GMU2HOST_INTR_MASK,
ADRENO_REG_GMU_HOST2GMU_INTR_SET,
ADRENO_REG_GMU_HOST2GMU_INTR_CLR,
ADRENO_REG_GMU_HOST2GMU_INTR_RAW_INFO,
diff --git a/drivers/gpu/msm/adreno_a6xx.c b/drivers/gpu/msm/adreno_a6xx.c
index 944faa3..3c3f99f 100644
--- a/drivers/gpu/msm/adreno_a6xx.c
+++ b/drivers/gpu/msm/adreno_a6xx.c
@@ -504,15 +504,6 @@
__raw_writel(value, reg);
}
-static void _gmu_regrmw(struct kgsl_device *device,
- unsigned int offsetwords, unsigned int mask)
-{
- unsigned int value;
-
- kgsl_gmu_regread(device, offsetwords, &value);
- kgsl_gmu_regwrite(device, offsetwords, value | mask);
-}
-
/*
* _load_gmu_rpmh_ucode() - Load the ucode into the GPU PDC/RSC blocks
* PDC and RSC execute GPU power on/off RPMh sequence
@@ -651,22 +642,25 @@
/* Configure registers for idle setting. The setting is cumulative */
switch (gmu->idle_level) {
case GPU_HW_MIN_VOLT:
- _gmu_regrmw(device, A6XX_GMU_RPMH_CTRL, MIN_BW_ENABLE_MASK);
- _gmu_regrmw(device, A6XX_GMU_RPMH_HYST_CTRL, MIN_BW_HYST);
+ kgsl_gmu_regrmw(device, A6XX_GMU_RPMH_CTRL, 0,
+ MIN_BW_ENABLE_MASK);
+ kgsl_gmu_regrmw(device, A6XX_GMU_RPMH_HYST_CTRL, 0,
+ MIN_BW_HYST);
/* fall through */
case GPU_HW_NAP:
- _gmu_regrmw(device, A6XX_GMU_GPU_NAP_CTRL, HW_NAP_ENABLE_MASK);
+ kgsl_gmu_regrmw(device, A6XX_GMU_GPU_NAP_CTRL, 0,
+ HW_NAP_ENABLE_MASK);
/* fall through */
case GPU_HW_IFPC:
kgsl_gmu_regwrite(device, A6XX_GMU_PWR_COL_INTER_FRAME_HYST,
0x000A0080);
- _gmu_regrmw(device, A6XX_GMU_PWR_COL_INTER_FRAME_CTRL,
+ kgsl_gmu_regrmw(device, A6XX_GMU_PWR_COL_INTER_FRAME_CTRL, 0,
IFPC_ENABLE_MASK);
/* fall through */
case GPU_HW_SPTP_PC:
kgsl_gmu_regwrite(device, A6XX_GMU_PWR_COL_SPTPRAC_HYST,
0x000A0080);
- _gmu_regrmw(device, A6XX_GMU_PWR_COL_INTER_FRAME_CTRL,
+ kgsl_gmu_regrmw(device, A6XX_GMU_PWR_COL_INTER_FRAME_CTRL, 0,
SPTP_ENABLE_MASK);
/* fall through */
default:
@@ -675,11 +669,13 @@
/* ACD feature enablement */
if (ADRENO_FEATURE(adreno_dev, ADRENO_LM))
- _gmu_regrmw(device, A6XX_GMU_BOOT_KMD_LM_HANDSHAKE, BIT(10));
+ kgsl_gmu_regrmw(device, A6XX_GMU_BOOT_KMD_LM_HANDSHAKE, 0,
+ BIT(10));
/* Enable RPMh GPU client */
if (ADRENO_FEATURE(adreno_dev, ADRENO_RPMH))
- _gmu_regrmw(device, A6XX_GMU_RPMH_CTRL, RPMH_ENABLE_MASK);
+ kgsl_gmu_regrmw(device, A6XX_GMU_RPMH_CTRL, 0,
+ RPMH_ENABLE_MASK);
/* Disable reference bandgap voltage */
kgsl_gmu_regwrite(device, A6XX_GMU_AO_SPARE_CNTL, 1);
@@ -721,9 +717,8 @@
{
struct gmu_device *gmu = &device->gmu;
- kgsl_gmu_regwrite(device, A6XX_GMU_GMU2HOST_INTR_MASK,
- (HFI_IRQ_MASK & (~HFI_IRQ_MSGQ_MASK)));
-
+ kgsl_gmu_regrmw(device, A6XX_GMU_GMU2HOST_INTR_MASK,
+ HFI_IRQ_MSGQ_MASK, 0);
kgsl_gmu_regwrite(device, A6XX_GMU_HFI_CTRL_INIT, 1);
if (timed_poll_check(device,
@@ -862,13 +857,14 @@
struct kgsl_pwrctrl *pwr = &device->pwrctrl;
struct gmu_device *gmu = &device->gmu;
- if (!IS_ERR_OR_NULL(gmu->gx_gdsc)) {
- ret = regulator_enable(gmu->gx_gdsc);
- if (ret) {
- dev_err(&gmu->pdev->dev,
- "Failed to turn on GPU HM HS\n");
- return ret;
- }
+ if (regulator_is_enabled(gmu->gx_gdsc))
+ return 0;
+
+ ret = regulator_enable(gmu->gx_gdsc);
+ if (ret) {
+ dev_err(&gmu->pdev->dev,
+ "Failed to turn on GPU HM HS\n");
+ return ret;
}
ret = clk_set_rate(pwr->grp_clks[0],
@@ -890,15 +886,15 @@
struct kgsl_pwrctrl *pwr = &device->pwrctrl;
struct gmu_device *gmu = &device->gmu;
+ if (!regulator_is_enabled(gmu->gx_gdsc))
+ return 0;
+
clk_disable_unprepare(pwr->grp_clks[0]);
clk_set_rate(pwr->grp_clks[0],
pwr->pwrlevels[pwr->num_pwrlevels - 1].
gpu_freq);
- if (IS_ERR_OR_NULL(gmu->gx_gdsc))
- return 0;
-
return regulator_disable(gmu->gx_gdsc);
}
@@ -1092,7 +1088,7 @@
ret = a6xx_hm_sptprac_control(device, false);
/* RSC sleep sequence */
- _regwrite(gmu->pdc_reg_virt, PDC_GPU_TIMESTAMP_UNIT1_EN_DRV0, 1);
+ kgsl_gmu_regwrite(device, A6XX_RSCC_TIMESTAMP_UNIT1_EN_DRV0, 1);
kgsl_gmu_regwrite(device, A6XX_GMU_RSCC_CONTROL_REQ, 1);
wmb();
@@ -1307,16 +1303,11 @@
struct kgsl_device *device = KGSL_DEVICE(adreno_dev);
struct gmu_device *gmu = &device->gmu;
- if (timed_poll_check(device, A6XX_GMU_RPMH_POWER_STATE,
- gmu->idle_level, GMU_START_TIMEOUT, 0xf)) {
- dev_err(&gmu->pdev->dev,
- "GMU is not going to powerstate %d\n",
- gmu->idle_level);
- return -ETIMEDOUT;
- }
+ /* TODO: Remove this register write when firmware is updated */
+ kgsl_gmu_regwrite(device, A6XX_GMU_CM3_FW_BUSY, 0);
if (timed_poll_check(device, A6XX_GPU_GMU_AO_GPU_CX_BUSY_STATUS,
- 0, GMU_START_TIMEOUT, CXGXCPUBUSYIGNAHB)) {
+ 0, GMU_START_TIMEOUT, CXGXCPUBUSYIGNAHB)) {
dev_err(&gmu->pdev->dev, "GMU is not idling\n");
return -ETIMEDOUT;
}
@@ -2053,12 +2044,12 @@
A6XX_GMU_ALWAYS_ON_COUNTER_H),
ADRENO_REG_DEFINE(ADRENO_REG_GMU_AO_INTERRUPT_EN,
A6XX_GMU_AO_INTERRUPT_EN),
- ADRENO_REG_DEFINE(ADRENO_REG_GMU_HOST_INTERRUPT_CLR,
- A6XX_GMU_HOST_INTERRUPT_CLR),
- ADRENO_REG_DEFINE(ADRENO_REG_GMU_HOST_INTERRUPT_STATUS,
- A6XX_GMU_HOST_INTERRUPT_STATUS),
- ADRENO_REG_DEFINE(ADRENO_REG_GMU_HOST_INTERRUPT_MASK,
- A6XX_GMU_HOST_INTERRUPT_MASK),
+ ADRENO_REG_DEFINE(ADRENO_REG_GMU_AO_HOST_INTERRUPT_CLR,
+ A6XX_GMU_AO_HOST_INTERRUPT_CLR),
+ ADRENO_REG_DEFINE(ADRENO_REG_GMU_AO_HOST_INTERRUPT_STATUS,
+ A6XX_GMU_AO_HOST_INTERRUPT_STATUS),
+ ADRENO_REG_DEFINE(ADRENO_REG_GMU_AO_HOST_INTERRUPT_MASK,
+ A6XX_GMU_AO_HOST_INTERRUPT_MASK),
ADRENO_REG_DEFINE(ADRENO_REG_GMU_PWR_COL_KEEPALIVE,
A6XX_GMU_GMU_PWR_COL_KEEPALIVE),
ADRENO_REG_DEFINE(ADRENO_REG_GMU_AHB_FENCE_STATUS,
@@ -2075,6 +2066,8 @@
A6XX_GMU_GMU2HOST_INTR_CLR),
ADRENO_REG_DEFINE(ADRENO_REG_GMU_GMU2HOST_INTR_INFO,
A6XX_GMU_GMU2HOST_INTR_INFO),
+ ADRENO_REG_DEFINE(ADRENO_REG_GMU_GMU2HOST_INTR_MASK,
+ A6XX_GMU_GMU2HOST_INTR_MASK),
ADRENO_REG_DEFINE(ADRENO_REG_GMU_HOST2GMU_INTR_SET,
A6XX_GMU_HOST2GMU_INTR_SET),
ADRENO_REG_DEFINE(ADRENO_REG_GMU_HOST2GMU_INTR_CLR,
diff --git a/drivers/gpu/msm/adreno_a6xx_snapshot.c b/drivers/gpu/msm/adreno_a6xx_snapshot.c
index b5d7fe1..ba83cd7 100644
--- a/drivers/gpu/msm/adreno_a6xx_snapshot.c
+++ b/drivers/gpu/msm/adreno_a6xx_snapshot.c
@@ -221,12 +221,12 @@
static const unsigned int a6xx_registers[] = {
/* RBBM */
- 0x0000, 0x0002, 0x0010, 0x0010, 0x0012, 0x0012, 0x0014, 0x0014,
- 0x0018, 0x001B, 0x001e, 0x0032, 0x0038, 0x003C, 0x0042, 0x0042,
- 0x0044, 0x0044, 0x0047, 0x0047, 0x0056, 0x0056, 0x00AD, 0x00AE,
- 0x00B0, 0x00FB, 0x0100, 0x011D, 0x0200, 0x020D, 0x0210, 0x0213,
- 0x0218, 0x023D, 0x0400, 0x04F9, 0x0500, 0x0500, 0x0505, 0x050B,
- 0x050E, 0x0511, 0x0533, 0x0533, 0x0540, 0x0555,
+ 0x0000, 0x0002, 0x0010, 0x0010, 0x0012, 0x0012, 0x0018, 0x001B,
+ 0x001e, 0x0032, 0x0038, 0x003C, 0x0042, 0x0042, 0x0044, 0x0044,
+ 0x0047, 0x0047, 0x0056, 0x0056, 0x00AD, 0x00AE, 0x00B0, 0x00FB,
+ 0x0100, 0x011D, 0x0200, 0x020D, 0x0210, 0x0213, 0x0218, 0x023D,
+ 0x0400, 0x04F9, 0x0500, 0x0500, 0x0505, 0x050B, 0x050E, 0x0511,
+ 0x0533, 0x0533, 0x0540, 0x0555,
/* CP */
0x0800, 0x0808, 0x0810, 0x0813, 0x0820, 0x0821, 0x0823, 0x0827,
0x0830, 0x0833, 0x0840, 0x0843, 0x084F, 0x086F, 0x0880, 0x088A,
@@ -240,8 +240,8 @@
0x0E10, 0x0E13, 0x0E17, 0x0E19, 0x0E1C, 0x0E2B, 0x0E30, 0x0E32,
0x0E38, 0x0E39,
/* GRAS */
- 0x8600, 0x8601, 0x8604, 0x8605, 0x8610, 0x861B, 0x8620, 0x8620,
- 0x8628, 0x862B, 0x8630, 0x8637,
+ 0x8600, 0x8601, 0x8610, 0x861B, 0x8620, 0x8620, 0x8628, 0x862B,
+ 0x8630, 0x8637,
/* RB */
0x8E01, 0x8E01, 0x8E04, 0x8E05, 0x8E07, 0x8E08, 0x8E0C, 0x8E0C,
0x8E10, 0x8E1C, 0x8E20, 0x8E25, 0x8E28, 0x8E28, 0x8E2C, 0x8E2F,
@@ -254,7 +254,7 @@
0x9E70, 0x9E72, 0x9E78, 0x9E79, 0x9E80, 0x9FFF,
/* VFD */
0xA600, 0xA601, 0xA603, 0xA603, 0xA60A, 0xA60A, 0xA610, 0xA617,
- 0xA630, 0xA630, 0xD200, 0xD263,
+ 0xA630, 0xA630,
};
enum a6xx_debugbus_id {
@@ -275,11 +275,12 @@
A6XX_DBGBUS_LRZ = 0x10,
A6XX_DBGBUS_A2D = 0x11,
A6XX_DBGBUS_CCUFCHE = 0x12,
- A6XX_DBGBUS_GMU = 0x13,
+ A6XX_DBGBUS_GMU_CX = 0x13,
A6XX_DBGBUS_RBP = 0x14,
A6XX_DBGBUS_DCS = 0x15,
A6XX_DBGBUS_RBBM_CFG = 0x16,
A6XX_DBGBUS_CX = 0x17,
+ A6XX_DBGBUS_GMU_GX = 0x18,
A6XX_DBGBUS_TPFCHE = 0x19,
A6XX_DBGBUS_GPC = 0x1d,
A6XX_DBGBUS_LARC = 0x1e,
@@ -321,6 +322,7 @@
{ A6XX_DBGBUS_RBP, 0x100, },
{ A6XX_DBGBUS_DCS, 0x100, },
{ A6XX_DBGBUS_RBBM_CFG, 0x100, },
+ { A6XX_DBGBUS_GMU_GX, 0x100, },
{ A6XX_DBGBUS_TPFCHE, 0x100, },
{ A6XX_DBGBUS_GPC, 0x100, },
{ A6XX_DBGBUS_LARC, 0x100, },
@@ -345,7 +347,7 @@
static void __iomem *a6xx_cx_dbgc;
static const struct adreno_debugbus_block a6xx_cx_dbgc_debugbus_blocks[] = {
{ A6XX_DBGBUS_VBIF, 0x100, },
- { A6XX_DBGBUS_GMU, 0x100, },
+ { A6XX_DBGBUS_GMU_CX, 0x100, },
{ A6XX_DBGBUS_CX, 0x100, },
};
@@ -581,8 +583,9 @@
struct kgsl_snapshot *snapshot)
{
unsigned int pool_size;
+ u8 *buf = snapshot->ptr;
- /* Save the mempool size to 0 to stabilize it while dumping */
+ /* Set the mempool size to 0 to stabilize it while dumping */
kgsl_regread(device, A6XX_CP_MEM_POOL_SIZE, &pool_size);
kgsl_regwrite(device, A6XX_CP_MEM_POOL_SIZE, 0);
@@ -590,6 +593,22 @@
A6XX_CP_MEM_POOL_DBG_ADDR, A6XX_CP_MEM_POOL_DBG_DATA,
0, 0x2060);
+ /*
+ * Data at offset 0x2000 in the mempool section is the mempool size.
+ * Since we set it to 0, patch in the original size so that the data
+ * is consistent.
+ */
+ if (buf < snapshot->ptr) {
+ unsigned int *data;
+
+ /* Skip over the headers */
+ buf += sizeof(struct kgsl_snapshot_section_header) +
+ sizeof(struct kgsl_snapshot_indexed_regs);
+
+ data = (unsigned int *)buf + 0x2000;
+ *data = pool_size;
+ }
+
/* Restore the saved mempool size */
kgsl_regwrite(device, A6XX_CP_MEM_POOL_SIZE, pool_size);
}
@@ -883,12 +902,14 @@
static size_t a6xx_snapshot_dbgc_debugbus_block(struct kgsl_device *device,
u8 *buf, size_t remain, void *priv)
{
+ struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
struct kgsl_snapshot_debugbus *header =
(struct kgsl_snapshot_debugbus *)buf;
struct adreno_debugbus_block *block = priv;
int i;
unsigned int *data = (unsigned int *)(buf + sizeof(*header));
unsigned int dwords;
+ unsigned int block_id;
size_t size;
dwords = block->dwords;
@@ -904,9 +925,14 @@
header->id = block->block_id;
header->count = dwords * 2;
+ block_id = block->block_id;
+ /* GMU_GX data is read using the GMU_CX block id on A630 */
+ if (adreno_is_a630(adreno_dev) &&
+ (block_id == A6XX_DBGBUS_GMU_GX))
+ block_id = A6XX_DBGBUS_GMU_CX;
+
for (i = 0; i < dwords; i++)
- a6xx_dbgc_debug_bus_read(device, block->block_id, i,
- &data[i*2]);
+ a6xx_dbgc_debug_bus_read(device, block_id, i, &data[i*2]);
return size;
}
diff --git a/drivers/gpu/msm/adreno_debugfs.c b/drivers/gpu/msm/adreno_debugfs.c
index b1f832f..2a1d352 100644
--- a/drivers/gpu/msm/adreno_debugfs.c
+++ b/drivers/gpu/msm/adreno_debugfs.c
@@ -137,11 +137,8 @@
break;
}
case KGSL_CMD_SYNCPOINT_TYPE_FENCE: {
- char fence_str[128];
-
- kgsl_dump_fence(sync_event->handle,
- fence_str, sizeof(fence_str));
- seq_printf(s, "sync: [%pK] %s", sync_event->handle, fence_str);
+ seq_printf(s, "sync: [%pK] %s", sync_event->handle,
+ sync_event->fence_name);
break;
}
default:
@@ -241,6 +238,9 @@
static void drawobj_print(struct seq_file *s,
struct kgsl_drawobj *drawobj)
{
+ if (!kref_get_unless_zero(&drawobj->refcount))
+ return;
+
if (drawobj->type == SYNCOBJ_TYPE)
syncobj_print(s, SYNCOBJ(drawobj));
else if ((drawobj->type == CMDOBJ_TYPE) ||
@@ -251,6 +251,7 @@
print_flags(s, drawobj_flags, ARRAY_SIZE(drawobj_flags),
drawobj->flags);
+ kgsl_drawobj_put(drawobj);
seq_puts(s, "\n");
}
diff --git a/drivers/gpu/msm/adreno_drawctxt.c b/drivers/gpu/msm/adreno_drawctxt.c
index 9f4e185..f77d438 100644
--- a/drivers/gpu/msm/adreno_drawctxt.c
+++ b/drivers/gpu/msm/adreno_drawctxt.c
@@ -95,6 +95,9 @@
goto stats;
}
+ if (!kref_get_unless_zero(&drawobj->refcount))
+ goto stats;
+
if (drawobj->type == SYNCOBJ_TYPE) {
struct kgsl_drawobj_sync *syncobj = SYNCOBJ(drawobj);
@@ -106,6 +109,8 @@
kgsl_dump_syncpoints(device, syncobj);
}
}
+
+ kgsl_drawobj_put(drawobj);
}
stats:
diff --git a/drivers/gpu/msm/kgsl.c b/drivers/gpu/msm/kgsl.c
index 2283096..15f68bf 100644
--- a/drivers/gpu/msm/kgsl.c
+++ b/drivers/gpu/msm/kgsl.c
@@ -1955,7 +1955,7 @@
}
handle = kgsl_sync_fence_async_wait(event.fd,
- gpuobj_free_fence_func, entry);
+ gpuobj_free_fence_func, entry, NULL, 0);
/* if handle is NULL the fence has already signaled */
if (handle == NULL)
diff --git a/drivers/gpu/msm/kgsl_device.h b/drivers/gpu/msm/kgsl_device.h
index bf31c00..d955aa0 100644
--- a/drivers/gpu/msm/kgsl_device.h
+++ b/drivers/gpu/msm/kgsl_device.h
@@ -569,6 +569,17 @@
device->ftbl->regwrite(device, offsetwords, val | bits);
}
+static inline void kgsl_gmu_regrmw(struct kgsl_device *device,
+ unsigned int offsetwords,
+ unsigned int mask, unsigned int bits)
+{
+ unsigned int val = 0;
+
+ kgsl_gmu_regread(device, offsetwords, &val);
+ val &= ~mask;
+ kgsl_gmu_regwrite(device, offsetwords, val | bits);
+}
+
static inline int kgsl_idle(struct kgsl_device *device)
{
return device->ftbl->idle(device);
diff --git a/drivers/gpu/msm/kgsl_drawobj.c b/drivers/gpu/msm/kgsl_drawobj.c
index 3a87e6e..bca3d57 100644
--- a/drivers/gpu/msm/kgsl_drawobj.c
+++ b/drivers/gpu/msm/kgsl_drawobj.c
@@ -44,7 +44,7 @@
static struct kmem_cache *sparseobjs_cache;
-static void drawobj_destroy_object(struct kref *kref)
+void kgsl_drawobj_destroy_object(struct kref *kref)
{
struct kgsl_drawobj *drawobj = container_of(kref,
struct kgsl_drawobj, refcount);
@@ -68,12 +68,6 @@
}
}
-static inline void drawobj_put(struct kgsl_drawobj *drawobj)
-{
- if (drawobj)
- kref_put(&drawobj->refcount, drawobj_destroy_object);
-}
-
void kgsl_dump_syncpoints(struct kgsl_device *device,
struct kgsl_drawobj_sync *syncobj)
{
@@ -100,16 +94,11 @@
retired);
break;
}
- case KGSL_CMD_SYNCPOINT_TYPE_FENCE: {
- char fence_str[128];
-
- kgsl_dump_fence(event->handle,
- fence_str, sizeof(fence_str));
- dev_err(device->dev,
- " fence: %s\n", fence_str);
+ case KGSL_CMD_SYNCPOINT_TYPE_FENCE:
+ dev_err(device->dev, " fence: %s\n",
+ event->fence_name);
break;
}
- }
}
}
@@ -117,13 +106,23 @@
{
struct kgsl_device *device;
struct kgsl_drawobj_sync *syncobj = (struct kgsl_drawobj_sync *) data;
- struct kgsl_drawobj *drawobj = DRAWOBJ(syncobj);
+ struct kgsl_drawobj *drawobj;
struct kgsl_drawobj_sync_event *event;
unsigned int i;
- if (syncobj == NULL || drawobj->context == NULL)
+ if (syncobj == NULL)
return;
+ drawobj = DRAWOBJ(syncobj);
+
+ if (!kref_get_unless_zero(&drawobj->refcount))
+ return;
+
+ if (drawobj->context == NULL) {
+ kgsl_drawobj_put(drawobj);
+ return;
+ }
+
device = drawobj->context->device;
dev_err(device->dev,
@@ -147,18 +146,14 @@
dev_err(device->dev, " [%d] TIMESTAMP %d:%d\n",
i, event->context->id, event->timestamp);
break;
- case KGSL_CMD_SYNCPOINT_TYPE_FENCE: {
- char fence_str[128];
-
- kgsl_dump_fence(event->handle,
- fence_str, sizeof(fence_str));
+ case KGSL_CMD_SYNCPOINT_TYPE_FENCE:
dev_err(device->dev, " [%d] FENCE %s\n",
- i, fence_str);
+ i, event->fence_name);
break;
}
- }
}
+ kgsl_drawobj_put(drawobj);
dev_err(device->dev, "--gpu syncpoint deadlock print end--\n");
}
@@ -204,7 +199,7 @@
drawobj_sync_expire(device, event);
kgsl_context_put(event->context);
- drawobj_put(&event->syncobj->base);
+ kgsl_drawobj_put(&event->syncobj->base);
}
static inline void memobj_list_free(struct list_head *list)
@@ -265,7 +260,7 @@
break;
case KGSL_CMD_SYNCPOINT_TYPE_FENCE:
if (kgsl_sync_fence_async_cancel(event->handle))
- drawobj_put(drawobj);
+ kgsl_drawobj_put(drawobj);
break;
}
}
@@ -321,21 +316,19 @@
else
return;
- drawobj_put(drawobj);
+ kgsl_drawobj_put(drawobj);
}
EXPORT_SYMBOL(kgsl_drawobj_destroy);
static void drawobj_sync_fence_func(void *priv)
{
struct kgsl_drawobj_sync_event *event = priv;
- char fence_str[128];
- kgsl_dump_fence(event->handle, fence_str, sizeof(fence_str));
- trace_syncpoint_fence_expire(event->syncobj, fence_str);
+ trace_syncpoint_fence_expire(event->syncobj, event->fence_name);
drawobj_sync_expire(event->device, event);
- drawobj_put(&event->syncobj->base);
+ kgsl_drawobj_put(&event->syncobj->base);
}
/* drawobj_add_sync_fence() - Add a new sync fence syncpoint
@@ -352,7 +345,6 @@
struct kgsl_drawobj *drawobj = DRAWOBJ(syncobj);
struct kgsl_drawobj_sync_event *event;
unsigned int id;
- char fence_str[128];
kref_get(&drawobj->refcount);
@@ -369,7 +361,8 @@
set_bit(event->id, &syncobj->pending);
event->handle = kgsl_sync_fence_async_wait(sync->fd,
- drawobj_sync_fence_func, event);
+ drawobj_sync_fence_func, event,
+ event->fence_name, sizeof(event->fence_name));
if (IS_ERR_OR_NULL(event->handle)) {
int ret = PTR_ERR(event->handle);
@@ -377,7 +370,7 @@
clear_bit(event->id, &syncobj->pending);
event->handle = NULL;
- drawobj_put(drawobj);
+ kgsl_drawobj_put(drawobj);
/*
* If ret == 0 the fence was already signaled - print a trace
@@ -389,8 +382,7 @@
return ret;
}
- kgsl_dump_fence(event->handle, fence_str, sizeof(fence_str));
- trace_syncpoint_fence(syncobj, fence_str);
+ trace_syncpoint_fence(syncobj, event->fence_name);
return 0;
}
@@ -457,7 +449,7 @@
if (ret) {
clear_bit(event->id, &syncobj->pending);
- drawobj_put(drawobj);
+ kgsl_drawobj_put(drawobj);
} else {
trace_syncpoint_timestamp(syncobj, context, sync->timestamp);
}
diff --git a/drivers/gpu/msm/kgsl_drawobj.h b/drivers/gpu/msm/kgsl_drawobj.h
index 5ec98ed..06eef7f 100644
--- a/drivers/gpu/msm/kgsl_drawobj.h
+++ b/drivers/gpu/msm/kgsl_drawobj.h
@@ -105,6 +105,8 @@
unsigned long timeout_jiffies;
};
+#define KGSL_FENCE_NAME_LEN 74
+
/**
* struct kgsl_drawobj_sync_event
* @id: identifer (positiion within the pending bitmap)
@@ -114,6 +116,7 @@
* register this event
* @timestamp: Pending timestamp for the event
* @handle: Pointer to a sync fence handle
+ * @fence_name: A fence name string to describe the fence
* @device: Pointer to the KGSL device
*/
struct kgsl_drawobj_sync_event {
@@ -123,6 +126,7 @@
struct kgsl_context *context;
unsigned int timestamp;
struct kgsl_sync_fence_cb *handle;
+ char fence_name[KGSL_FENCE_NAME_LEN];
struct kgsl_device *device;
};
@@ -206,6 +210,8 @@
void kgsl_drawobj_destroy(struct kgsl_drawobj *drawobj);
+void kgsl_drawobj_destroy_object(struct kref *kref);
+
static inline bool kgsl_drawobj_events_pending(
struct kgsl_drawobj_sync *syncobj)
{
@@ -220,4 +226,11 @@
return test_bit(bit, &syncobj->pending);
}
+
+static inline void kgsl_drawobj_put(struct kgsl_drawobj *drawobj)
+{
+ if (drawobj)
+ kref_put(&drawobj->refcount, kgsl_drawobj_destroy_object);
+}
+
#endif /* __KGSL_DRAWOBJ_H */
diff --git a/drivers/gpu/msm/kgsl_gmu.c b/drivers/gpu/msm/kgsl_gmu.c
index 97e4b6f..0c821cd 100644
--- a/drivers/gpu/msm/kgsl_gmu.c
+++ b/drivers/gpu/msm/kgsl_gmu.c
@@ -748,44 +748,49 @@
{
struct gmu_device *gmu = data;
struct kgsl_device *device = container_of(gmu, struct kgsl_device, gmu);
- struct kgsl_hfi *hfi = &gmu->hfi;
unsigned int status = 0;
- if (irq == gmu->gmu_interrupt_num) {
- adreno_read_gmureg(ADRENO_DEVICE(device),
- ADRENO_REG_GMU_HOST_INTERRUPT_STATUS,
- &status);
+ adreno_read_gmureg(ADRENO_DEVICE(device),
+ ADRENO_REG_GMU_AO_HOST_INTERRUPT_STATUS, &status);
+ adreno_write_gmureg(ADRENO_DEVICE(device),
+ ADRENO_REG_GMU_AO_HOST_INTERRUPT_CLR, status);
- /* Ignore GMU_INT_RSCC_COMP interrupts */
- if (status & GMU_INT_WDOG_BITE)
- dev_err_ratelimited(&gmu->pdev->dev,
- "GMU watchdog expired interrupt\n");
- if (status & GMU_INT_DBD_WAKEUP)
- dev_err_ratelimited(&gmu->pdev->dev,
- "GMU doorbell interrupt received\n");
- if (status & GMU_INT_HOST_AHB_BUS_ERR)
- dev_err_ratelimited(&gmu->pdev->dev,
- "AHB bus error interrupt received\n");
+ /* Ignore GMU_INT_RSCC_COMP and GMU_INT_DBD WAKEUP interrupts */
+ if (status & GMU_INT_WDOG_BITE)
+ dev_err_ratelimited(&gmu->pdev->dev,
+ "GMU watchdog expired interrupt received\n");
+ if (status & GMU_INT_HOST_AHB_BUS_ERR)
+ dev_err_ratelimited(&gmu->pdev->dev,
+ "AHB bus error interrupt received\n");
+ if (status & ~GMU_AO_INT_MASK)
+ dev_err_ratelimited(&gmu->pdev->dev,
+ "Unhandled GMU interrupts 0x%lx\n",
+ status & ~GMU_AO_INT_MASK);
- adreno_write_gmureg(ADRENO_DEVICE(device),
- ADRENO_REG_GMU_HOST_INTERRUPT_CLR,
- status);
- } else {
- adreno_read_gmureg(ADRENO_DEVICE(device),
- ADRENO_REG_GMU_GMU2HOST_INTR_INFO,
- &status);
- adreno_write_gmureg(ADRENO_DEVICE(device),
- ADRENO_REG_GMU_GMU2HOST_INTR_CLR,
- status);
+ return IRQ_HANDLED;
+}
- if (status & HFI_IRQ_MASK) {
- if (status & HFI_IRQ_MSGQ_MASK)
- tasklet_hi_schedule(&hfi->tasklet);
- } else
- dev_err_ratelimited(&gmu->pdev->dev,
- "Unhandled GMU interrupts %x\n",
- status);
- }
+static irqreturn_t hfi_irq_handler(int irq, void *data)
+{
+ struct kgsl_hfi *hfi = data;
+ struct gmu_device *gmu = container_of(hfi, struct gmu_device, hfi);
+ struct kgsl_device *device = container_of(gmu, struct kgsl_device, gmu);
+ unsigned int status = 0;
+
+ adreno_read_gmureg(ADRENO_DEVICE(device),
+ ADRENO_REG_GMU_GMU2HOST_INTR_INFO, &status);
+ adreno_write_gmureg(ADRENO_DEVICE(device),
+ ADRENO_REG_GMU_GMU2HOST_INTR_CLR, status);
+
+ if (status & HFI_IRQ_MSGQ_MASK)
+ tasklet_hi_schedule(&hfi->tasklet);
+ if (status & HFI_IRQ_CM3_FAULT_MASK)
+ dev_err_ratelimited(&gmu->pdev->dev,
+ "GMU CM3 fault interrupt received\n");
+ if (status & ~HFI_IRQ_MASK)
+ dev_err_ratelimited(&gmu->pdev->dev,
+ "Unhandled HFI interrupts 0x%lx\n",
+ status & ~HFI_IRQ_MASK);
return IRQ_HANDLED;
}
@@ -978,6 +983,82 @@
return 0;
}
+static int gmu_irq_probe(struct gmu_device *gmu)
+{
+ int ret;
+ struct kgsl_hfi *hfi = &gmu->hfi;
+
+ hfi->hfi_interrupt_num = platform_get_irq_byname(gmu->pdev,
+ "kgsl_hfi_irq");
+ ret = devm_request_irq(&gmu->pdev->dev,
+ hfi->hfi_interrupt_num,
+ hfi_irq_handler, IRQF_TRIGGER_HIGH,
+ "HFI", hfi);
+ if (ret) {
+ dev_err(&gmu->pdev->dev, "request_irq(%d) failed: %d\n",
+ hfi->hfi_interrupt_num, ret);
+ return ret;
+ }
+
+ gmu->gmu_interrupt_num = platform_get_irq_byname(gmu->pdev,
+ "kgsl_gmu_irq");
+ ret = devm_request_irq(&gmu->pdev->dev,
+ gmu->gmu_interrupt_num,
+ gmu_irq_handler, IRQF_TRIGGER_HIGH,
+ "GMU", gmu);
+ if (ret)
+ dev_err(&gmu->pdev->dev, "request_irq(%d) failed: %d\n",
+ gmu->gmu_interrupt_num, ret);
+
+ return ret;
+}
+
+static void gmu_irq_enable(struct kgsl_device *device)
+{
+ struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
+ struct gmu_device *gmu = &device->gmu;
+ struct kgsl_hfi *hfi = &gmu->hfi;
+
+ /* Clear any pending IRQs before unmasking on GMU */
+ adreno_write_gmureg(adreno_dev, ADRENO_REG_GMU_GMU2HOST_INTR_CLR,
+ 0xFFFFFFFF);
+ adreno_write_gmureg(adreno_dev, ADRENO_REG_GMU_AO_HOST_INTERRUPT_CLR,
+ 0xFFFFFFFF);
+
+ /* Unmask needed IRQs on GMU */
+ adreno_write_gmureg(adreno_dev, ADRENO_REG_GMU_GMU2HOST_INTR_MASK,
+ (unsigned int) ~HFI_IRQ_MASK);
+ adreno_write_gmureg(adreno_dev, ADRENO_REG_GMU_AO_HOST_INTERRUPT_MASK,
+ (unsigned int) ~GMU_AO_INT_MASK);
+
+ /* Enable all IRQs on host */
+ enable_irq(hfi->hfi_interrupt_num);
+ enable_irq(gmu->gmu_interrupt_num);
+}
+
+static void gmu_irq_disable(struct kgsl_device *device)
+{
+ struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
+ struct gmu_device *gmu = &device->gmu;
+ struct kgsl_hfi *hfi = &gmu->hfi;
+
+ /* Disable all IRQs on host */
+ disable_irq(gmu->gmu_interrupt_num);
+ disable_irq(hfi->hfi_interrupt_num);
+
+ /* Mask all IRQs on GMU */
+ adreno_write_gmureg(adreno_dev, ADRENO_REG_GMU_AO_HOST_INTERRUPT_MASK,
+ 0xFFFFFFFF);
+ adreno_write_gmureg(adreno_dev, ADRENO_REG_GMU_GMU2HOST_INTR_MASK,
+ 0xFFFFFFFF);
+
+ /* Clear any pending IRQs before disabling */
+ adreno_write_gmureg(adreno_dev, ADRENO_REG_GMU_AO_HOST_INTERRUPT_CLR,
+ 0xFFFFFFFF);
+ adreno_write_gmureg(adreno_dev, ADRENO_REG_GMU_GMU2HOST_INTR_CLR,
+ 0xFFFFFFFF);
+}
+
/* Do not access any GMU registers in GMU probe function */
int gmu_probe(struct kgsl_device *device)
{
@@ -1024,32 +1105,13 @@
gmu->gmu2gpu_offset = (gmu->reg_phys - device->reg_phys) >> 2;
- /* Initialize HFI GMU interrupts */
- hfi->hfi_interrupt_num = platform_get_irq_byname(gmu->pdev,
- "kgsl_hfi_irq");
- ret = devm_request_irq(&gmu->pdev->dev,
- hfi->hfi_interrupt_num,
- gmu_irq_handler, IRQF_TRIGGER_HIGH,
- "GMU", gmu);
- if (ret) {
- dev_err(&gmu->pdev->dev, "request_irq(%d) failed: %d\n",
- hfi->hfi_interrupt_num, ret);
+ /* Initialize HFI and GMU interrupts */
+ ret = gmu_irq_probe(gmu);
+ if (ret)
goto error;
- }
-
- gmu->gmu_interrupt_num = platform_get_irq_byname(gmu->pdev,
- "kgsl_gmu_irq");
- ret = devm_request_irq(&gmu->pdev->dev,
- gmu->gmu_interrupt_num,
- gmu_irq_handler, IRQF_TRIGGER_HIGH,
- "GMU", gmu);
- if (ret) {
- dev_err(&gmu->pdev->dev, "request_irq(%d) failed: %d\n",
- gmu->gmu_interrupt_num, ret);
- goto error;
- }
/* Don't enable GMU interrupts until GMU started */
+ /* We cannot use gmu_irq_disable because it writes registers */
disable_irq(gmu->gmu_interrupt_num);
disable_irq(hfi->hfi_interrupt_num);
@@ -1153,7 +1215,6 @@
while ((j < MAX_GMU_CLKS) && gmu->clks[j]) {
clk_disable_unprepare(gmu->clks[j]);
- gmu->clks[j] = NULL;
j++;
}
@@ -1200,7 +1261,6 @@
struct adreno_gpudev *gpudev = ADRENO_GPU_DEVICE(adreno_dev);
struct kgsl_pwrctrl *pwr = &device->pwrctrl;
struct gmu_device *gmu = &device->gmu;
- struct kgsl_hfi *hfi = &gmu->hfi;
int bus_level = pwr->pwrlevels[pwr->default_pwrlevel].bus_freq;
if (!kgsl_gmu_isenabled(device))
@@ -1235,8 +1295,7 @@
if (ret)
goto error_bus;
- enable_irq(hfi->hfi_interrupt_num);
- enable_irq(gmu->gmu_interrupt_num);
+ gmu_irq_enable(device);
ret = hfi_start(gmu, GMU_COLD_BOOT);
if (ret)
@@ -1254,8 +1313,7 @@
if (ret)
goto error_clks;
- enable_irq(hfi->hfi_interrupt_num);
- enable_irq(gmu->gmu_interrupt_num);
+ gmu_irq_enable(device);
ret = hfi_start(gmu, GMU_WARM_BOOT);
if (ret)
@@ -1293,8 +1351,7 @@
error_gpu:
hfi_stop(gmu);
- disable_irq(gmu->gmu_interrupt_num);
- disable_irq(hfi->hfi_interrupt_num);
+ gmu_irq_disable(device);
if (device->state == KGSL_STATE_INIT ||
device->state == KGSL_STATE_SUSPEND) {
if (ADRENO_QUIRK(adreno_dev, ADRENO_QUIRK_HFI_USE_REG))
@@ -1312,31 +1369,43 @@
return ret;
}
+#define GMU_IDLE_TIMEOUT 10 /* ms */
+
/* Caller shall ensure GPU is ready for SLUMBER */
void gmu_stop(struct kgsl_device *device)
{
struct gmu_device *gmu = &device->gmu;
- struct kgsl_hfi *hfi = &gmu->hfi;
struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
struct adreno_gpudev *gpudev = ADRENO_GPU_DEVICE(adreno_dev);
+ unsigned long t;
+ bool idle = false;
if (!test_bit(GMU_CLK_ON, &gmu->flags))
return;
- if (gpudev->wait_for_gmu_idle &&
- !gpudev->wait_for_gmu_idle(adreno_dev)) {
- dev_err(&gmu->pdev->dev, "Failure to stop gmu");
- return;
+ if (gpudev->hw_isidle) {
+ t = jiffies + msecs_to_jiffies(GMU_IDLE_TIMEOUT);
+ while (!time_after(jiffies, t)) {
+ if (gpudev->hw_isidle(adreno_dev)) {
+ idle = true;
+ break;
+ }
+ cpu_relax();
+ }
}
gpudev->rpmh_gpu_pwrctrl(adreno_dev, GMU_NOTIFY_SLUMBER, 0, 0);
+ if (!idle || (gpudev->wait_for_gmu_idle &&
+ gpudev->wait_for_gmu_idle(adreno_dev))) {
+ dev_err(&gmu->pdev->dev, "Failure to stop GMU");
+ return;
+ }
+
/* Pending message in all queues are abandoned */
hfi_stop(gmu);
clear_bit(GMU_HFI_ON, &gmu->flags);
-
- disable_irq(gmu->gmu_interrupt_num);
- disable_irq(hfi->hfi_interrupt_num);
+ gmu_irq_disable(device);
gpudev->rpmh_gpu_pwrctrl(adreno_dev, GMU_FW_STOP, 0, 0);
gmu_disable_clks(gmu);
@@ -1351,7 +1420,7 @@
{
struct gmu_device *gmu = &device->gmu;
struct kgsl_hfi *hfi = &gmu->hfi;
- int i;
+ int i = 0;
if (!device->gmu.pdev)
return;
@@ -1359,16 +1428,20 @@
tasklet_kill(&hfi->tasklet);
gmu_stop(device);
+ gmu_irq_disable(device);
+
+ while ((i < MAX_GMU_CLKS) && gmu->clks[i]) {
+ gmu->clks[i] = NULL;
+ i++;
+ }
if (gmu->gmu_interrupt_num) {
- disable_irq(gmu->gmu_interrupt_num);
devm_free_irq(&gmu->pdev->dev,
gmu->gmu_interrupt_num, gmu);
gmu->gmu_interrupt_num = 0;
}
if (hfi->hfi_interrupt_num) {
- disable_irq(hfi->hfi_interrupt_num);
devm_free_irq(&gmu->pdev->dev,
hfi->hfi_interrupt_num, gmu);
hfi->hfi_interrupt_num = 0;
diff --git a/drivers/gpu/msm/kgsl_gmu.h b/drivers/gpu/msm/kgsl_gmu.h
index ac2c151..7055eb7 100644
--- a/drivers/gpu/msm/kgsl_gmu.h
+++ b/drivers/gpu/msm/kgsl_gmu.h
@@ -26,7 +26,6 @@
#define GMU_INT_HOST_AHB_BUS_ERR BIT(5)
#define GMU_AO_INT_MASK \
(GMU_INT_WDOG_BITE | \
- GMU_INT_DBD_WAKEUP | \
GMU_INT_HOST_AHB_BUS_ERR)
#define MAX_GMUFW_SIZE 0x2000 /* in dwords */
@@ -147,7 +146,7 @@
GPU_HW_NAP = 0x4,
GPU_HW_MIN_VOLT = 0x5,
GPU_HW_MIN_DDR = 0x6,
- GPU_HW_SLUMBER = 0xF
+ GPU_HW_SLUMBER = 0x7
};
/**
diff --git a/drivers/gpu/msm/kgsl_hfi.h b/drivers/gpu/msm/kgsl_hfi.h
index 39b513e..83abec4 100644
--- a/drivers/gpu/msm/kgsl_hfi.h
+++ b/drivers/gpu/msm/kgsl_hfi.h
@@ -38,16 +38,15 @@
#define GMU_QUEUE_START_ADDR(hfi_mem, i) \
((hfi_mem)->gmuaddr + HFI_QUEUE_OFFSET(i))
-#define HFI_IRQ_MSGQ_MASK 0x1
-#define HFI_IRQ_DBGQ_MASK 0x2
-#define HFI_IRQ_BLOCKED_MSG_MASK 0x4
-#define HFI_IRQ_GMU_ERR_MASK 0xFF0000
-#define HFI_IRQ_OOB_MASK 0xFF000000
-#define HFI_IRQ_MASK (HFI_IRQ_MSGQ_MASK |\
- HFI_IRQ_DBGQ_MASK |\
- HFI_IRQ_BLOCKED_MSG_MASK |\
- HFI_IRQ_GMU_ERR_MASK |\
- HFI_IRQ_OOB_MASK)
+#define HFI_IRQ_MSGQ_MASK BIT(0)
+#define HFI_IRQ_DBGQ_MASK BIT(1)
+#define HFI_IRQ_BLOCKED_MSG_MASK BIT(2)
+#define HFI_IRQ_CM3_FAULT_MASK BIT(23)
+#define HFI_IRQ_GMU_ERR_MASK GENMASK(22, 16)
+#define HFI_IRQ_OOB_MASK GENMASK(31, 24)
+#define HFI_IRQ_MASK (HFI_IRQ_MSGQ_MASK |\
+ HFI_IRQ_CM3_FAULT_MASK)
+
/**
* struct hfi_queue_table_header - HFI queue table structure
* @version: HFI protocol version
diff --git a/drivers/gpu/msm/kgsl_sync.c b/drivers/gpu/msm/kgsl_sync.c
index 3b57b73..973a2ff 100644
--- a/drivers/gpu/msm/kgsl_sync.c
+++ b/drivers/gpu/msm/kgsl_sync.c
@@ -152,6 +152,17 @@
return ret;
}
+/* Only to be used if creating a related event failed */
+static void kgsl_sync_cancel(struct kgsl_sync_fence *kfence)
+{
+ spin_lock(&kfence->parent->lock);
+ if (!list_empty(&kfence->child_list)) {
+ list_del_init(&kfence->child_list);
+ fence_put(&kfence->fence);
+ }
+ spin_unlock(&kfence->parent->lock);
+}
+
/**
* kgsl_add_fence_event - Create a new fence event
* @device - KGSL device to create the event on
@@ -235,6 +246,7 @@
put_unused_fd(priv.fence_fd);
if (kfence) {
+ kgsl_sync_cancel(kfence);
/*
* Put the refcount of sync file. This will release
* kfence->fence as well.
@@ -366,7 +378,7 @@
list_for_each_entry_safe(kfence, next, &ktimeline->child_list_head,
child_list) {
if (fence_is_signaled_locked(&kfence->fence)) {
- list_del(&kfence->child_list);
+ list_del_init(&kfence->child_list);
fence_put(&kfence->fence);
}
}
@@ -419,8 +431,27 @@
kfree(kcb);
}
+static void kgsl_get_fence_name(struct fence *fence,
+ char *fence_name, int name_len)
+{
+ char *ptr = fence_name;
+ char *last = fence_name + name_len;
+
+ ptr += snprintf(ptr, last - ptr, "%s %s",
+ fence->ops->get_driver_name(fence),
+ fence->ops->get_timeline_name(fence));
+
+ if ((ptr + 2) >= last)
+ return;
+
+ if (fence->ops->fence_value_str) {
+ ptr += snprintf(ptr, last - ptr, ": ");
+ fence->ops->fence_value_str(fence, ptr, last - ptr);
+ }
+}
+
struct kgsl_sync_fence_cb *kgsl_sync_fence_async_wait(int fd,
- void (*func)(void *priv), void *priv)
+ void (*func)(void *priv), void *priv, char *fence_name, int name_len)
{
struct kgsl_sync_fence_cb *kcb;
struct fence *fence;
@@ -441,13 +472,16 @@
kcb->priv = priv;
kcb->func = func;
+ if (fence_name)
+ kgsl_get_fence_name(fence, fence_name, name_len);
+
/* if status then error or signaled */
status = fence_add_callback(fence, &kcb->fence_cb,
kgsl_sync_fence_callback);
if (status) {
kfree(kcb);
- if (fence_is_signaled(fence))
+ if (!fence_is_signaled(fence))
kcb = ERR_PTR(status);
else
kcb = NULL;
@@ -777,43 +811,3 @@
.release = kgsl_syncsource_fence_release,
};
-void kgsl_dump_fence(struct kgsl_sync_fence_cb *handle,
- char *fence_str, int len)
-{
- struct fence *fence;
- char *ptr = fence_str;
- char *last = fence_str + len;
-
- if (!handle || !handle->fence) {
- snprintf(fence_str, len, "NULL");
- return;
- }
-
- fence = handle->fence;
-
- ptr += snprintf(ptr, last - ptr, "%s %s",
- fence->ops->get_timeline_name(fence),
- fence->ops->get_driver_name(fence));
- if (ptr >= last)
- return;
-
- if (fence->ops->timeline_value_str &&
- fence->ops->fence_value_str) {
- char value[64];
- bool success;
-
- fence->ops->fence_value_str(fence, value, sizeof(value));
- success = !!strlen(value);
-
- if (success) {
- ptr += snprintf(ptr, last - ptr, ": %s", value);
- if (ptr >= last)
- return;
-
- fence->ops->timeline_value_str(fence, value,
- sizeof(value));
- ptr += snprintf(ptr, last - ptr, " / %s", value);
- }
- }
-}
-
diff --git a/drivers/gpu/msm/kgsl_sync.h b/drivers/gpu/msm/kgsl_sync.h
index dc84c54..99fe0e1 100644
--- a/drivers/gpu/msm/kgsl_sync.h
+++ b/drivers/gpu/msm/kgsl_sync.h
@@ -91,7 +91,8 @@
void kgsl_sync_timeline_put(struct kgsl_sync_timeline *ktimeline);
struct kgsl_sync_fence_cb *kgsl_sync_fence_async_wait(int fd,
- void (*func)(void *priv), void *priv);
+ void (*func)(void *priv), void *priv,
+ char *fence_name, int name_len);
int kgsl_sync_fence_async_cancel(struct kgsl_sync_fence_cb *kcb);
@@ -109,8 +110,8 @@
void kgsl_syncsource_cleanup(struct kgsl_process_private *private,
struct kgsl_syncsource *syncsource);
-void kgsl_dump_fence(struct kgsl_sync_fence_cb *handle,
- char *fence_str, int len);
+void kgsl_dump_fence(struct kgsl_drawobj_sync_event *event,
+ char *fence_str, int len);
#else
static inline int kgsl_add_fence_event(struct kgsl_device *device,
@@ -134,8 +135,10 @@
{
}
-static inline struct kgsl_sync_fence_cb *kgsl_sync_fence_async_wait(int fd,
- void (*func)(void *priv), void *priv)
+
+struct kgsl_sync_fence_cb *kgsl_sync_fence_async_wait(int fd,
+ void (*func)(void *priv), void *priv,
+ char *fence_name, int name_len)
{
return NULL;
}
@@ -185,8 +188,8 @@
}
-void kgsl_dump_fence(struct kgsl_sync_fence_cb *handle,
- char *fence_str, int len)
+void kgsl_dump_fence(struct kgsl_drawobj_sync_event *event,
+ char *fence_str, int len)
{
}
diff --git a/drivers/hwmon/qpnp-adc-common.c b/drivers/hwmon/qpnp-adc-common.c
index 33b760f..d883483 100644
--- a/drivers/hwmon/qpnp-adc-common.c
+++ b/drivers/hwmon/qpnp-adc-common.c
@@ -392,78 +392,78 @@
/* Voltage to temperature */
static const struct qpnp_vadc_map_pt adcmap_100k_104ef_104fb[] = {
- {1758, -40},
- {1742, -35},
- {1719, -30},
- {1691, -25},
- {1654, -20},
- {1608, -15},
- {1551, -10},
- {1483, -5},
+ {1758, -40000},
+ {1742, -35000},
+ {1719, -30000},
+ {1691, -25000},
+ {1654, -20000},
+ {1608, -15000},
+ {1551, -10000},
+ {1483, -5000},
{1404, 0},
- {1315, 5},
- {1218, 10},
- {1114, 15},
- {1007, 20},
- {900, 25},
- {795, 30},
- {696, 35},
- {605, 40},
- {522, 45},
- {448, 50},
- {383, 55},
- {327, 60},
- {278, 65},
- {237, 70},
- {202, 75},
- {172, 80},
- {146, 85},
- {125, 90},
- {107, 95},
- {92, 100},
- {79, 105},
- {68, 110},
- {59, 115},
- {51, 120},
- {44, 125}
+ {1315, 5000},
+ {1218, 10000},
+ {1114, 15000},
+ {1007, 20000},
+ {900, 25000},
+ {795, 30000},
+ {696, 35000},
+ {605, 40000},
+ {522, 45000},
+ {448, 50000},
+ {383, 55000},
+ {327, 60000},
+ {278, 65000},
+ {237, 70000},
+ {202, 75000},
+ {172, 80000},
+ {146, 85000},
+ {125, 90000},
+ {107, 95000},
+ {92, 100000},
+ {79, 105000},
+ {68, 110000},
+ {59, 115000},
+ {51, 120000},
+ {44, 125000}
};
/* Voltage to temperature */
static const struct qpnp_vadc_map_pt adcmap_150k_104ef_104fb[] = {
- {1738, -40},
- {1714, -35},
- {1682, -30},
- {1641, -25},
- {1589, -20},
- {1526, -15},
- {1451, -10},
- {1363, -5},
+ {1738, -40000},
+ {1714, -35000},
+ {1682, -30000},
+ {1641, -25000},
+ {1589, -20000},
+ {1526, -15000},
+ {1451, -10000},
+ {1363, -5000},
{1266, 0},
- {1159, 5},
- {1048, 10},
- {936, 15},
- {825, 20},
- {720, 25},
- {622, 30},
- {533, 35},
- {454, 40},
- {385, 45},
- {326, 50},
- {275, 55},
- {232, 60},
- {195, 65},
- {165, 70},
- {139, 75},
- {118, 80},
- {100, 85},
- {85, 90},
- {73, 95},
- {62, 100},
- {53, 105},
- {46, 110},
- {40, 115},
- {34, 120},
- {30, 125}
+ {1159, 5000},
+ {1048, 10000},
+ {936, 15000},
+ {825, 20000},
+ {720, 25000},
+ {622, 30000},
+ {533, 35000},
+ {454, 40000},
+ {385, 45000},
+ {326, 50000},
+ {275, 55000},
+ {232, 60000},
+ {195, 65000},
+ {165, 70000},
+ {139, 75000},
+ {118, 80000},
+ {100, 85000},
+ {85, 90000},
+ {73, 95000},
+ {62, 100000},
+ {53, 105000},
+ {46, 110000},
+ {40, 115000},
+ {34, 120000},
+ {30, 125000}
};
static const struct qpnp_vadc_map_pt adcmap_smb_batt_therm[] = {
@@ -595,40 +595,40 @@
* 1.875V reference.
*/
static const struct qpnp_vadc_map_pt adcmap_100k_104ef_104fb_1875_vref[] = {
- { 1831, -40 },
- { 1814, -35 },
- { 1791, -30 },
- { 1761, -25 },
- { 1723, -20 },
- { 1675, -15 },
- { 1616, -10 },
- { 1545, -5 },
+ { 1831, -40000 },
+ { 1814, -35000 },
+ { 1791, -30000 },
+ { 1761, -25000 },
+ { 1723, -20000 },
+ { 1675, -15000 },
+ { 1616, -10000 },
+ { 1545, -5000 },
{ 1463, 0 },
- { 1370, 5 },
- { 1268, 10 },
- { 1160, 15 },
- { 1049, 20 },
- { 937, 25 },
- { 828, 30 },
- { 726, 35 },
- { 630, 40 },
- { 544, 45 },
- { 467, 50 },
- { 399, 55 },
- { 340, 60 },
- { 290, 65 },
- { 247, 70 },
- { 209, 75 },
- { 179, 80 },
- { 153, 85 },
- { 130, 90 },
- { 112, 95 },
- { 96, 100 },
- { 82, 105 },
- { 71, 110 },
- { 62, 115 },
- { 53, 120 },
- { 46, 125 },
+ { 1370, 5000 },
+ { 1268, 10000 },
+ { 1160, 15000 },
+ { 1049, 20000 },
+ { 937, 25000 },
+ { 828, 30000 },
+ { 726, 35000 },
+ { 630, 40000 },
+ { 544, 45000 },
+ { 467, 50000 },
+ { 399, 55000 },
+ { 340, 60000 },
+ { 290, 65000 },
+ { 247, 70000 },
+ { 209, 75000 },
+ { 179, 80000 },
+ { 153, 85000 },
+ { 130, 90000 },
+ { 112, 95000 },
+ { 96, 100000 },
+ { 82, 105000 },
+ { 71, 110000 },
+ { 62, 115000 },
+ { 53, 120000 },
+ { 46, 125000 },
};
static int32_t qpnp_adc_map_voltage_temp(const struct qpnp_vadc_map_pt *pts,
diff --git a/drivers/hwmon/qpnp-adc-voltage.c b/drivers/hwmon/qpnp-adc-voltage.c
index 6cd63b2..4b5e206 100644
--- a/drivers/hwmon/qpnp-adc-voltage.c
+++ b/drivers/hwmon/qpnp-adc-voltage.c
@@ -2562,10 +2562,9 @@
return rc;
}
-static int qpnp_vadc_get_temp(struct thermal_zone_device *thermal,
- int *temp)
+static int qpnp_vadc_get_temp(void *data, int *temp)
{
- struct qpnp_vadc_thermal_data *vadc_therm = thermal->devdata;
+ struct qpnp_vadc_thermal_data *vadc_therm = data;
struct qpnp_vadc_chip *vadc = vadc_therm->vadc_dev;
struct qpnp_vadc_result result;
int rc = 0;
@@ -2583,7 +2582,7 @@
return rc;
}
-static struct thermal_zone_device_ops qpnp_vadc_thermal_ops = {
+static struct thermal_zone_of_device_ops qpnp_vadc_thermal_ops = {
.get_temp = qpnp_vadc_get_temp,
};
@@ -2612,9 +2611,11 @@
vadc->adc->adc_channels[i].name);
vadc->vadc_therm_chan[i].vadc_dev = vadc;
vadc->vadc_therm_chan[i].tz_dev =
- thermal_zone_device_register(name,
- 0, 0, &vadc->vadc_therm_chan[i],
- &qpnp_vadc_thermal_ops, NULL, 0, 0);
+ devm_thermal_zone_of_sensor_register(
+ vadc->dev,
+ vadc->vadc_therm_chan[i].vadc_channel,
+ &vadc->vadc_therm_chan[i],
+ &qpnp_vadc_thermal_ops);
if (IS_ERR(vadc->vadc_therm_chan[i].tz_dev)) {
pr_err("thermal device register failed.\n");
goto thermal_err_sens;
diff --git a/drivers/hwtracing/coresight/coresight-cti.c b/drivers/hwtracing/coresight/coresight-cti.c
index a2ce81a..8a57ed2 100644
--- a/drivers/hwtracing/coresight/coresight-cti.c
+++ b/drivers/hwtracing/coresight/coresight-cti.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2013-2016, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2013-2017, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -19,7 +19,7 @@
#include <linux/err.h>
#include <linux/slab.h>
#include <linux/mutex.h>
-#include <linux/clk.h>
+#include <linux/amba/bus.h>
#include <linux/cpu_pm.h>
#include <linux/topology.h>
#include <linux/of.h>
@@ -379,7 +379,7 @@
* within the mutex lock region in addition to within the spinlock.
*/
if (drvdata->refcnt == 0) {
- ret = clk_prepare_enable(drvdata->clk);
+ ret = pm_runtime_get_sync(drvdata->dev);
if (ret)
goto err1;
}
@@ -402,7 +402,7 @@
* adjusting its value.
*/
if (drvdata->refcnt == 0)
- clk_disable_unprepare(drvdata->clk);
+ pm_runtime_put(drvdata->dev);
err1:
cti_trigin_gpio_disable(drvdata);
err0:
@@ -463,7 +463,7 @@
* within the mutex lock region in addition to within the spinlock.
*/
if (drvdata->refcnt == 0) {
- ret = clk_prepare_enable(drvdata->clk);
+ ret = pm_runtime_get_sync(drvdata->dev);
if (ret)
goto err1;
}
@@ -485,7 +485,7 @@
* __cti_map_trigout so it is safe to check it against 0.
*/
if (drvdata->refcnt == 0)
- clk_disable_unprepare(drvdata->clk);
+ pm_runtime_put(drvdata->dev);
err1:
cti_trigout_gpio_disable(drvdata);
err0:
@@ -563,7 +563,7 @@
* within the mutex lock region in addition to within the spinlock.
*/
if (drvdata->refcnt == 0)
- clk_disable_unprepare(drvdata->clk);
+ pm_runtime_put(drvdata->dev);
if (drvdata->gpio_trigin->trig == trig)
cti_trigin_gpio_disable(drvdata);
@@ -632,7 +632,7 @@
* within the mutex lock region in addition to within the spinlock.
*/
if (drvdata->refcnt == 0)
- clk_disable_unprepare(drvdata->clk);
+ pm_runtime_put(drvdata->dev);
if (drvdata->gpio_trigout->trig == trig)
cti_trigout_gpio_disable(drvdata);
@@ -1388,34 +1388,29 @@
.notifier_call = cti_cpu_pm_callback,
};
-static int cti_probe(struct platform_device *pdev)
+static int cti_probe(struct amba_device *adev, const struct amba_id *id)
{
int ret;
int trig;
- struct device *dev = &pdev->dev;
+ struct device *dev = &adev->dev;
struct coresight_platform_data *pdata;
struct cti_drvdata *drvdata;
- struct resource *res;
struct coresight_desc *desc;
struct device_node *cpu_node;
- pdata = of_get_coresight_platform_data(dev, pdev->dev.of_node);
+ pdata = of_get_coresight_platform_data(dev, adev->dev.of_node);
if (IS_ERR(pdata))
return PTR_ERR(pdata);
- pdev->dev.platform_data = pdata;
+ adev->dev.platform_data = pdata;
drvdata = devm_kzalloc(dev, sizeof(*drvdata), GFP_KERNEL);
if (!drvdata)
return -ENOMEM;
/* Store the driver data pointer for use in exported functions */
- drvdata->dev = &pdev->dev;
- platform_set_drvdata(pdev, drvdata);
+ drvdata->dev = &adev->dev;
+ dev_set_drvdata(dev, drvdata);
- res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "cti-base");
- if (!res)
- return -ENODEV;
-
- drvdata->base = devm_ioremap(dev, res->start, resource_size(res));
+ drvdata->base = devm_ioremap_resource(dev, &adev->res);
if (!drvdata->base)
return -ENOMEM;
@@ -1423,21 +1418,13 @@
mutex_init(&drvdata->mutex);
- drvdata->clk = devm_clk_get(dev, "core_clk");
- if (IS_ERR(drvdata->clk))
- return PTR_ERR(drvdata->clk);
-
- ret = clk_set_rate(drvdata->clk, CORESIGHT_CLK_RATE_TRACE);
- if (ret)
- return ret;
-
drvdata->gpio_trigin = devm_kzalloc(dev, sizeof(struct cti_pctrl),
GFP_KERNEL);
if (!drvdata->gpio_trigin)
return -ENOMEM;
drvdata->gpio_trigin->trig = -1;
- ret = of_property_read_u32(pdev->dev.of_node,
+ ret = of_property_read_u32(adev->dev.of_node,
"qcom,cti-gpio-trigin", &trig);
if (!ret)
drvdata->gpio_trigin->trig = trig;
@@ -1450,7 +1437,7 @@
return -ENOMEM;
drvdata->gpio_trigout->trig = -1;
- ret = of_property_read_u32(pdev->dev.of_node,
+ ret = of_property_read_u32(adev->dev.of_node,
"qcom,cti-gpio-trigout", &trig);
if (!ret)
drvdata->gpio_trigout->trig = trig;
@@ -1458,7 +1445,7 @@
return ret;
drvdata->cpu = -1;
- cpu_node = of_parse_phandle(pdev->dev.of_node, "cpu", 0);
+ cpu_node = of_parse_phandle(adev->dev.of_node, "cpu", 0);
if (cpu_node) {
drvdata->cpu = pdata ? pdata->cpu : -1;
if (drvdata->cpu == -1) {
@@ -1468,7 +1455,7 @@
}
if (!cti_save_disable)
- drvdata->cti_save = of_property_read_bool(pdev->dev.of_node,
+ drvdata->cti_save = of_property_read_bool(adev->dev.of_node,
"qcom,cti-save");
if (drvdata->cti_save) {
drvdata->state = devm_kzalloc(dev, sizeof(struct cti_state),
@@ -1476,18 +1463,18 @@
if (!drvdata->state)
return -ENOMEM;
- drvdata->cti_hwclk = of_property_read_bool(pdev->dev.of_node,
+ drvdata->cti_hwclk = of_property_read_bool(adev->dev.of_node,
"qcom,cti-hwclk");
}
if (drvdata->cti_save && !drvdata->cti_hwclk) {
- ret = clk_prepare_enable(drvdata->clk);
+ ret = pm_runtime_get_sync(drvdata->dev);
if (ret)
return ret;
}
mutex_lock(&cti_lock);
drvdata->cti.name = ((struct coresight_platform_data *)
- (pdev->dev.platform_data))->name;
+ (adev->dev.platform_data))->name;
list_add_tail(&drvdata->cti.link, &cti_list);
mutex_unlock(&cti_lock);
@@ -1497,8 +1484,8 @@
goto err;
}
desc->type = CORESIGHT_DEV_TYPE_NONE;
- desc->pdata = pdev->dev.platform_data;
- desc->dev = &pdev->dev;
+ desc->pdata = adev->dev.platform_data;
+ desc->dev = &adev->dev;
desc->groups = cti_attr_grps;
drvdata->csdev = coresight_register(desc);
if (IS_ERR(drvdata->csdev)) {
@@ -1511,56 +1498,35 @@
cpu_pm_register_notifier(&cti_cpu_pm_notifier);
registered++;
}
-
+ pm_runtime_put(&adev->dev);
dev_dbg(dev, "CTI initialized\n");
return 0;
err:
if (drvdata->cti_save && !drvdata->cti_hwclk)
- clk_disable_unprepare(drvdata->clk);
+ pm_runtime_put(&adev->dev);
return ret;
}
-static int cti_remove(struct platform_device *pdev)
-{
- struct cti_drvdata *drvdata = platform_get_drvdata(pdev);
-
- if (drvdata->cti_save) {
- registered--;
- if (!registered)
- cpu_pm_unregister_notifier(&cti_cpu_pm_notifier);
- }
- coresight_unregister(drvdata->csdev);
- if (drvdata->cti_save && !drvdata->cti_hwclk)
- clk_disable_unprepare(drvdata->clk);
- return 0;
-}
-
-static const struct of_device_id cti_match[] = {
- {.compatible = "arm,coresight-cti"},
- {}
+static struct amba_id cti_ids[] = {
+ {
+ .id = 0x0003b966,
+ .mask = 0x0003ffff,
+ .data = "CTI",
+ },
+ { 0, 0},
};
-static struct platform_driver cti_driver = {
- .probe = cti_probe,
- .remove = cti_remove,
- .driver = {
+static struct amba_driver cti_driver = {
+ .drv = {
.name = "coresight-cti",
.owner = THIS_MODULE,
- .of_match_table = cti_match,
+ .suppress_bind_attrs = true,
},
+ .probe = cti_probe,
+ .id_table = cti_ids,
};
-static int __init cti_init(void)
-{
- return platform_driver_register(&cti_driver);
-}
-module_init(cti_init);
-
-static void __exit cti_exit(void)
-{
- platform_driver_unregister(&cti_driver);
-}
-module_exit(cti_exit);
+builtin_amba_driver(cti_driver);
MODULE_LICENSE("GPL v2");
MODULE_DESCRIPTION("CoreSight CTI driver");
diff --git a/drivers/hwtracing/coresight/coresight-replicator-qcom.c b/drivers/hwtracing/coresight/coresight-replicator-qcom.c
index 0bd8b78..98547a9 100644
--- a/drivers/hwtracing/coresight/coresight-replicator-qcom.c
+++ b/drivers/hwtracing/coresight/coresight-replicator-qcom.c
@@ -47,8 +47,6 @@
{
struct replicator_state *drvdata = dev_get_drvdata(csdev->dev.parent);
- pm_runtime_get_sync(drvdata->dev);
-
CS_UNLOCK(drvdata->base);
/*
@@ -85,7 +83,6 @@
CS_LOCK(drvdata->base);
- pm_runtime_put(drvdata->dev);
dev_info(drvdata->dev, "REPLICATOR disabled\n");
}
diff --git a/drivers/hwtracing/coresight/coresight-tmc.c b/drivers/hwtracing/coresight/coresight-tmc.c
index f5018fc..10e8da4 100644
--- a/drivers/hwtracing/coresight/coresight-tmc.c
+++ b/drivers/hwtracing/coresight/coresight-tmc.c
@@ -436,8 +436,11 @@
if (ret)
drvdata->size = SZ_1M;
+ if (of_property_read_bool(np, "arm,sg-enable"))
+ drvdata->memtype = TMC_ETR_MEM_TYPE_SG;
+ else
+ drvdata->memtype = TMC_ETR_MEM_TYPE_CONTIG;
drvdata->mem_size = drvdata->size;
- drvdata->memtype = TMC_ETR_MEM_TYPE_CONTIG;
drvdata->mem_type = drvdata->memtype;
} else {
drvdata->size = readl_relaxed(drvdata->base + TMC_RSZ) * 4;
diff --git a/drivers/hwtracing/coresight/coresight-tpda.c b/drivers/hwtracing/coresight/coresight-tpda.c
index c96087d..5d2d087 100644
--- a/drivers/hwtracing/coresight/coresight-tpda.c
+++ b/drivers/hwtracing/coresight/coresight-tpda.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
@@ -14,10 +14,10 @@
#include <linux/module.h>
#include <linux/device.h>
#include <linux/platform_device.h>
+#include <linux/amba/bus.h>
#include <linux/io.h>
#include <linux/err.h>
#include <linux/fs.h>
-#include <linux/clk.h>
#include <linux/bitmap.h>
#include <linux/of.h>
#include <linux/coresight.h>
@@ -53,7 +53,6 @@
void __iomem *base;
struct device *dev;
struct coresight_device *csdev;
- struct clk *clk;
struct mutex lock;
bool enable;
uint32_t atid;
@@ -183,11 +182,6 @@
static int tpda_enable(struct coresight_device *csdev, int inport, int outport)
{
struct tpda_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
- int ret;
-
- ret = clk_prepare_enable(drvdata->clk);
- if (ret)
- return ret;
mutex_lock(&drvdata->lock);
__tpda_enable(drvdata, inport);
@@ -221,8 +215,6 @@
drvdata->enable = false;
mutex_unlock(&drvdata->lock);
- clk_disable_unprepare(drvdata->clk);
-
dev_info(drvdata->dev, "TPDA inport %d disabled\n", inport);
}
@@ -653,31 +645,27 @@
drvdata->freq_ts = true;
}
-static int tpda_probe(struct platform_device *pdev)
+static int tpda_probe(struct amba_device *adev, const struct amba_id *id)
{
int ret;
- struct device *dev = &pdev->dev;
+ struct device *dev = &adev->dev;
struct coresight_platform_data *pdata;
struct tpda_drvdata *drvdata;
- struct resource *res;
struct coresight_desc *desc;
- pdata = of_get_coresight_platform_data(dev, pdev->dev.of_node);
+ pdata = of_get_coresight_platform_data(dev, adev->dev.of_node);
if (IS_ERR(pdata))
return PTR_ERR(pdata);
- pdev->dev.platform_data = pdata;
+ adev->dev.platform_data = pdata;
drvdata = devm_kzalloc(dev, sizeof(*drvdata), GFP_KERNEL);
if (!drvdata)
return -ENOMEM;
- drvdata->dev = &pdev->dev;
- platform_set_drvdata(pdev, drvdata);
- res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "tpda-base");
- if (!res)
- return -ENODEV;
+ drvdata->dev = &adev->dev;
+ dev_set_drvdata(dev, drvdata);
- drvdata->base = devm_ioremap(dev, res->start, resource_size(res));
+ drvdata->base = devm_ioremap_resource(dev, &adev->res);
if (!drvdata->base)
return -ENOMEM;
@@ -687,22 +675,10 @@
if (ret)
return ret;
- drvdata->clk = devm_clk_get(dev, "core_clk");
- if (IS_ERR(drvdata->clk))
- return PTR_ERR(drvdata->clk);
-
- ret = clk_set_rate(drvdata->clk, CORESIGHT_CLK_RATE_TRACE);
- if (ret)
- return ret;
-
- ret = clk_prepare_enable(drvdata->clk);
- if (ret)
- return ret;
-
if (!coresight_authstatus_enabled(drvdata->base))
goto err;
- clk_disable_unprepare(drvdata->clk);
+ pm_runtime_put(&adev->dev);
tpda_init_default_data(drvdata);
@@ -712,8 +688,8 @@
desc->type = CORESIGHT_DEV_TYPE_LINK;
desc->subtype.link_subtype = CORESIGHT_DEV_SUBTYPE_LINK_MERG;
desc->ops = &tpda_cs_ops;
- desc->pdata = pdev->dev.platform_data;
- desc->dev = &pdev->dev;
+ desc->pdata = adev->dev.platform_data;
+ desc->dev = &adev->dev;
desc->groups = tpda_attr_grps;
drvdata->csdev = coresight_register(desc);
if (IS_ERR(drvdata->csdev))
@@ -722,44 +698,29 @@
dev_dbg(drvdata->dev, "TPDA initialized\n");
return 0;
err:
- clk_disable_unprepare(drvdata->clk);
return -EPERM;
}
-static int tpda_remove(struct platform_device *pdev)
-{
- struct tpda_drvdata *drvdata = platform_get_drvdata(pdev);
-
- coresight_unregister(drvdata->csdev);
- return 0;
-}
-
-static const struct of_device_id tpda_match[] = {
- {.compatible = "qcom,coresight-tpda"},
- {}
+static struct amba_id tpda_ids[] = {
+ {
+ .id = 0x0003b969,
+ .mask = 0x0003ffff,
+ .data = "TPDA",
+ },
+ { 0, 0},
};
-static struct platform_driver tpda_driver = {
- .probe = tpda_probe,
- .remove = tpda_remove,
- .driver = {
+static struct amba_driver tpda_driver = {
+ .drv = {
.name = "coresight-tpda",
.owner = THIS_MODULE,
- .of_match_table = tpda_match,
+ .suppress_bind_attrs = true,
},
+ .probe = tpda_probe,
+ .id_table = tpda_ids,
};
-static int __init tpda_init(void)
-{
- return platform_driver_register(&tpda_driver);
-}
-module_init(tpda_init);
-
-static void __exit tpda_exit(void)
-{
- platform_driver_unregister(&tpda_driver);
-}
-module_exit(tpda_exit);
+builtin_amba_driver(tpda_driver);
MODULE_LICENSE("GPL v2");
MODULE_DESCRIPTION("Trace, Profiling & Diagnostic Aggregator driver");
diff --git a/drivers/hwtracing/coresight/coresight-tpdm.c b/drivers/hwtracing/coresight/coresight-tpdm.c
index 673689c..36e3db2 100644
--- a/drivers/hwtracing/coresight/coresight-tpdm.c
+++ b/drivers/hwtracing/coresight/coresight-tpdm.c
@@ -13,11 +13,10 @@
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/device.h>
-#include <linux/platform_device.h>
+#include <linux/amba/bus.h>
#include <linux/io.h>
#include <linux/err.h>
#include <linux/fs.h>
-#include <linux/clk.h>
#include <linux/bitmap.h>
#include <linux/of.h>
#include <linux/coresight.h>
@@ -159,11 +158,6 @@
TPDM_SUPPORT_TYPE_NO,
};
-enum tpdm_cmb_mode {
- TPDM_CMB_MODE_CONTINUOUS,
- TPDM_CMB_MODE_TRACE_ON_CHANGE,
-};
-
enum tpdm_cmb_patt_bits {
TPDM_CMB_LSB,
TPDM_CMB_MSB,
@@ -234,7 +228,8 @@
};
struct cmb_dataset {
- enum tpdm_cmb_mode mode;
+ bool trace_mode;
+ uint32_t cycle_acc;
uint32_t patt_val[TPDM_CMB_PATT_CMP];
uint32_t patt_mask[TPDM_CMB_PATT_CMP];
bool patt_ts;
@@ -250,7 +245,6 @@
void __iomem *base;
struct device *dev;
struct coresight_device *csdev;
- struct clk *clk;
struct mutex lock;
bool enable;
bool clk_enable;
@@ -528,24 +522,18 @@
static void __tpdm_enable_cmb(struct tpdm_drvdata *drvdata)
{
uint32_t val;
+ int i;
- tpdm_writel(drvdata, drvdata->cmb->patt_val[TPDM_CMB_LSB],
- TPDM_CMB_TPR(TPDM_CMB_LSB));
- tpdm_writel(drvdata, drvdata->cmb->patt_mask[TPDM_CMB_LSB],
- TPDM_CMB_TPMR(TPDM_CMB_LSB));
- tpdm_writel(drvdata, drvdata->cmb->patt_val[TPDM_CMB_MSB],
- TPDM_CMB_TPR(TPDM_CMB_MSB));
- tpdm_writel(drvdata, drvdata->cmb->patt_mask[TPDM_CMB_MSB],
- TPDM_CMB_TPMR(TPDM_CMB_MSB));
-
- tpdm_writel(drvdata, drvdata->cmb->trig_patt_val[TPDM_CMB_LSB],
- TPDM_CMB_XPR(TPDM_CMB_LSB));
- tpdm_writel(drvdata, drvdata->cmb->trig_patt_mask[TPDM_CMB_LSB],
- TPDM_CMB_XPMR(TPDM_CMB_LSB));
- tpdm_writel(drvdata, drvdata->cmb->trig_patt_val[TPDM_CMB_MSB],
- TPDM_CMB_XPR(TPDM_CMB_MSB));
- tpdm_writel(drvdata, drvdata->cmb->trig_patt_mask[TPDM_CMB_MSB],
- TPDM_CMB_XPMR(TPDM_CMB_MSB));
+ for (i = 0; i < TPDM_CMB_PATT_CMP; i++) {
+ tpdm_writel(drvdata, drvdata->cmb->patt_val[i],
+ TPDM_CMB_TPR(i));
+ tpdm_writel(drvdata, drvdata->cmb->patt_mask[i],
+ TPDM_CMB_TPMR(i));
+ tpdm_writel(drvdata, drvdata->cmb->trig_patt_val[i],
+ TPDM_CMB_XPR(i));
+ tpdm_writel(drvdata, drvdata->cmb->trig_patt_mask[i],
+ TPDM_CMB_XPMR(i));
+ }
val = tpdm_readl(drvdata, TPDM_CMB_TIER);
if (drvdata->cmb->patt_ts == true)
@@ -563,10 +551,13 @@
val = tpdm_readl(drvdata, TPDM_CMB_CR);
/* Set the flow control bit */
val = val & ~BIT(2);
- if (drvdata->cmb->mode == TPDM_CMB_MODE_CONTINUOUS)
- val = val & ~BIT(1);
- else
+ if (drvdata->cmb->trace_mode)
val = val | BIT(1);
+ else
+ val = val & ~BIT(1);
+
+ val = val & ~BM(8, 9);
+ val = val | BMVAL(drvdata->cmb->cycle_acc, 0, 1) << 8;
tpdm_writel(drvdata, val, TPDM_CMB_CR);
/* Set the enable bit */
val = val | BIT(0);
@@ -577,24 +568,18 @@
{
uint32_t val;
struct mcmb_dataset *mcmb = drvdata->cmb->mcmb;
+ int i;
- tpdm_writel(drvdata, drvdata->cmb->patt_val[TPDM_CMB_LSB],
- TPDM_CMB_TPR(TPDM_CMB_LSB));
- tpdm_writel(drvdata, drvdata->cmb->patt_mask[TPDM_CMB_LSB],
- TPDM_CMB_TPMR(TPDM_CMB_LSB));
- tpdm_writel(drvdata, drvdata->cmb->patt_val[TPDM_CMB_MSB],
- TPDM_CMB_TPR(TPDM_CMB_MSB));
- tpdm_writel(drvdata, drvdata->cmb->patt_mask[TPDM_CMB_MSB],
- TPDM_CMB_TPMR(TPDM_CMB_MSB));
-
- tpdm_writel(drvdata, drvdata->cmb->trig_patt_val[TPDM_CMB_LSB],
- TPDM_CMB_XPR(TPDM_CMB_LSB));
- tpdm_writel(drvdata, drvdata->cmb->trig_patt_mask[TPDM_CMB_LSB],
- TPDM_CMB_XPMR(TPDM_CMB_LSB));
- tpdm_writel(drvdata, drvdata->cmb->trig_patt_val[TPDM_CMB_MSB],
- TPDM_CMB_XPR(TPDM_CMB_MSB));
- tpdm_writel(drvdata, drvdata->cmb->trig_patt_mask[TPDM_CMB_MSB],
- TPDM_CMB_XPMR(TPDM_CMB_MSB));
+ for (i = 0; i < TPDM_CMB_PATT_CMP; i++) {
+ tpdm_writel(drvdata, drvdata->cmb->patt_val[i],
+ TPDM_CMB_TPR(i));
+ tpdm_writel(drvdata, drvdata->cmb->patt_mask[i],
+ TPDM_CMB_TPMR(i));
+ tpdm_writel(drvdata, drvdata->cmb->trig_patt_val[i],
+ TPDM_CMB_XPR(i));
+ tpdm_writel(drvdata, drvdata->cmb->trig_patt_mask[i],
+ TPDM_CMB_XPMR(i));
+ }
val = tpdm_readl(drvdata, TPDM_CMB_TIER);
if (drvdata->cmb->patt_ts == true)
@@ -612,14 +597,17 @@
val = tpdm_readl(drvdata, TPDM_CMB_CR);
/* Set the flow control bit */
val = val & ~BIT(2);
- if (drvdata->cmb->mode == TPDM_CMB_MODE_CONTINUOUS)
- val = val & ~BIT(1);
- else
+ if (drvdata->cmb->trace_mode)
val = val | BIT(1);
+ else
+ val = val & ~BIT(1);
- val = val | (BMVAL(mcmb->mcmb_trig_lane, 0, 3) << 18);
-
- val = val | (mcmb->mcmb_lane_select << 10);
+ val = val & ~BM(8, 9);
+ val = val | BMVAL(drvdata->cmb->cycle_acc, 0, 1) << 8;
+ val = val & ~BM(18, 20);
+ val = val | (BMVAL(mcmb->mcmb_trig_lane, 0, 2) << 18);
+ val = val & ~BM(10, 17);
+ val = val | (BMVAL(mcmb->mcmb_lane_select, 0, 7) << 10);
tpdm_writel(drvdata, val, TPDM_CMB_CR);
/* Set the enable bit */
@@ -658,11 +646,6 @@
struct perf_event *event, u32 mode)
{
struct tpdm_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
- int ret;
-
- ret = clk_prepare_enable(drvdata->clk);
- if (ret)
- return ret;
mutex_lock(&drvdata->lock);
__tpdm_enable(drvdata);
@@ -722,7 +705,8 @@
if (test_bit(TPDM_DS_DSB, drvdata->enable_ds))
__tpdm_disable_dsb(drvdata);
- if (test_bit(TPDM_DS_CMB, drvdata->enable_ds))
+ if (test_bit(TPDM_DS_CMB, drvdata->enable_ds) ||
+ test_bit(TPDM_DS_MCMB, drvdata->enable_ds))
__tpdm_disable_cmb(drvdata);
if (drvdata->clk_enable)
@@ -741,8 +725,6 @@
drvdata->enable = false;
mutex_unlock(&drvdata->lock);
- clk_disable_unprepare(drvdata->clk);
-
dev_info(drvdata->dev, "TPDM tracing disabled\n");
}
@@ -3192,9 +3174,10 @@
test_bit(TPDM_DS_MCMB, drvdata->datasets)))
return -EPERM;
- return scnprintf(buf, PAGE_SIZE, "%s\n",
- drvdata->cmb->mode == TPDM_CMB_MODE_CONTINUOUS ?
- "continuous" : "trace_on_change");
+ return scnprintf(buf, PAGE_SIZE, "trace_mode: %s cycle_acc: %d\n",
+ drvdata->cmb->trace_mode ?
+ "trace_on_change" : "continuous",
+ drvdata->cmb->cycle_acc);
}
static ssize_t tpdm_store_cmb_mode(struct device *dev,
@@ -3203,180 +3186,118 @@
size_t size)
{
struct tpdm_drvdata *drvdata = dev_get_drvdata(dev->parent);
- char str[20] = "";
+ unsigned int trace_mode, cycle_acc;
+ int nval;
- if (strlen(buf) >= 20)
+ nval = sscanf(buf, "%u %u", &trace_mode, &cycle_acc);
+ if (nval != 2)
return -EINVAL;
- if (sscanf(buf, "%s", str) != 1)
- return -EINVAL;
+
if (!(test_bit(TPDM_DS_CMB, drvdata->datasets) ||
test_bit(TPDM_DS_MCMB, drvdata->datasets)))
return -EPERM;
mutex_lock(&drvdata->lock);
- if (!strcmp(str, "continuous")) {
- drvdata->cmb->mode = TPDM_CMB_MODE_CONTINUOUS;
- } else if (!strcmp(str, "trace_on_change")) {
- drvdata->cmb->mode = TPDM_CMB_MODE_TRACE_ON_CHANGE;
- } else {
- mutex_unlock(&drvdata->lock);
- return -EINVAL;
- }
+ drvdata->cmb->trace_mode = trace_mode;
+ drvdata->cmb->cycle_acc = cycle_acc;
mutex_unlock(&drvdata->lock);
return size;
}
static DEVICE_ATTR(cmb_mode, 0644,
tpdm_show_cmb_mode, tpdm_store_cmb_mode);
-static ssize_t tpdm_show_cmb_patt_val_lsb(struct device *dev,
+static ssize_t tpdm_show_cmb_patt_val(struct device *dev,
struct device_attribute *attr,
char *buf)
{
struct tpdm_drvdata *drvdata = dev_get_drvdata(dev->parent);
- unsigned long val;
+ ssize_t size = 0;
+ int i;
if (!(test_bit(TPDM_DS_CMB, drvdata->datasets) ||
test_bit(TPDM_DS_MCMB, drvdata->datasets)))
return -EPERM;
- val = drvdata->cmb->patt_val[TPDM_CMB_LSB];
-
- return scnprintf(buf, PAGE_SIZE, "%#lx\n", val);
+ mutex_lock(&drvdata->lock);
+ for (i = 0; i < TPDM_CMB_PATT_CMP; i++) {
+ size += scnprintf(buf + size, PAGE_SIZE - size,
+ "Index: 0x%x Value: 0x%x\n", i,
+ drvdata->cmb->patt_val[i]);
+ }
+ mutex_unlock(&drvdata->lock);
+ return size;
}
-static ssize_t tpdm_store_cmb_patt_val_lsb(struct device *dev,
+static ssize_t tpdm_store_cmb_patt_val(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t size)
{
struct tpdm_drvdata *drvdata = dev_get_drvdata(dev->parent);
- unsigned long val;
+ unsigned long index, val;
- if (kstrtoul(buf, 16, &val))
+ if (sscanf(buf, "%lx %lx", &index, &val) != 2)
+ return -EINVAL;
+ if (index >= TPDM_CMB_PATT_CMP)
return -EINVAL;
if (!(test_bit(TPDM_DS_CMB, drvdata->datasets) ||
test_bit(TPDM_DS_MCMB, drvdata->datasets)))
return -EPERM;
mutex_lock(&drvdata->lock);
- drvdata->cmb->patt_val[TPDM_CMB_LSB] = val;
+ drvdata->cmb->patt_val[index] = val;
mutex_unlock(&drvdata->lock);
+
return size;
}
-static DEVICE_ATTR(cmb_patt_val_lsb, 0644,
- tpdm_show_cmb_patt_val_lsb,
- tpdm_store_cmb_patt_val_lsb);
+static DEVICE_ATTR(cmb_patt_val, 0644,
+ tpdm_show_cmb_patt_val,
+ tpdm_store_cmb_patt_val);
-static ssize_t tpdm_show_cmb_patt_mask_lsb(struct device *dev,
+static ssize_t tpdm_show_cmb_patt_mask(struct device *dev,
struct device_attribute *attr,
char *buf)
{
struct tpdm_drvdata *drvdata = dev_get_drvdata(dev->parent);
- unsigned long val;
+ ssize_t size = 0;
+ int i;
if (!(test_bit(TPDM_DS_CMB, drvdata->datasets) ||
test_bit(TPDM_DS_MCMB, drvdata->datasets)))
return -EPERM;
- val = drvdata->cmb->patt_mask[TPDM_CMB_LSB];
+ mutex_lock(&drvdata->lock);
+ for (i = 0; i < TPDM_CMB_PATT_CMP; i++) {
+ size += scnprintf(buf + size, PAGE_SIZE - size,
+ "Index: 0x%x Value: 0x%x\n", i,
+ drvdata->cmb->patt_mask[i]);
+ }
+ mutex_unlock(&drvdata->lock);
+ return size;
- return scnprintf(buf, PAGE_SIZE, "%#lx\n", val);
}
-static ssize_t tpdm_store_cmb_patt_mask_lsb(struct device *dev,
+static ssize_t tpdm_store_cmb_patt_mask(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t size)
{
struct tpdm_drvdata *drvdata = dev_get_drvdata(dev->parent);
- unsigned long val;
+ unsigned long index, val;
- if (kstrtoul(buf, 16, &val))
+ if (sscanf(buf, "%lx %lx", &index, &val) != 2)
+ return -EINVAL;
+ if (index >= TPDM_CMB_PATT_CMP)
return -EINVAL;
if (!(test_bit(TPDM_DS_CMB, drvdata->datasets) ||
test_bit(TPDM_DS_MCMB, drvdata->datasets)))
return -EPERM;
mutex_lock(&drvdata->lock);
- drvdata->cmb->patt_mask[TPDM_CMB_LSB] = val;
+ drvdata->cmb->patt_mask[index] = val;
mutex_unlock(&drvdata->lock);
return size;
}
-static DEVICE_ATTR(cmb_patt_mask_lsb, 0644,
- tpdm_show_cmb_patt_mask_lsb, tpdm_store_cmb_patt_mask_lsb);
-
-static ssize_t tpdm_show_cmb_patt_val_msb(struct device *dev,
- struct device_attribute *attr,
- char *buf)
-{
- struct tpdm_drvdata *drvdata = dev_get_drvdata(dev->parent);
- unsigned long val;
-
- if (!(test_bit(TPDM_DS_CMB, drvdata->datasets) ||
- test_bit(TPDM_DS_MCMB, drvdata->datasets)))
- return -EPERM;
-
- val = drvdata->cmb->patt_val[TPDM_CMB_MSB];
-
- return scnprintf(buf, PAGE_SIZE, "%#lx\n", val);
-}
-
-static ssize_t tpdm_store_cmb_patt_val_msb(struct device *dev,
- struct device_attribute *attr,
- const char *buf, size_t size)
-{
- struct tpdm_drvdata *drvdata = dev_get_drvdata(dev->parent);
- unsigned long val;
-
- if (kstrtoul(buf, 16, &val))
- return -EINVAL;
- if (!(test_bit(TPDM_DS_CMB, drvdata->datasets) ||
- test_bit(TPDM_DS_MCMB, drvdata->datasets)))
- return -EPERM;
-
- mutex_lock(&drvdata->lock);
- drvdata->cmb->patt_val[TPDM_CMB_MSB] = val;
- mutex_unlock(&drvdata->lock);
- return size;
-}
-static DEVICE_ATTR(cmb_patt_val_msb, 0644,
- tpdm_show_cmb_patt_val_msb,
- tpdm_store_cmb_patt_val_msb);
-
-static ssize_t tpdm_show_cmb_patt_mask_msb(struct device *dev,
- struct device_attribute *attr,
- char *buf)
-{
- struct tpdm_drvdata *drvdata = dev_get_drvdata(dev->parent);
- unsigned long val;
-
- if (!(test_bit(TPDM_DS_CMB, drvdata->datasets) ||
- test_bit(TPDM_DS_MCMB, drvdata->datasets)))
- return -EPERM;
-
- val = drvdata->cmb->patt_mask[TPDM_CMB_MSB];
-
- return scnprintf(buf, PAGE_SIZE, "%#lx\n", val);
-}
-
-static ssize_t tpdm_store_cmb_patt_mask_msb(struct device *dev,
- struct device_attribute *attr,
- const char *buf, size_t size)
-{
- struct tpdm_drvdata *drvdata = dev_get_drvdata(dev->parent);
- unsigned long val;
-
- if (kstrtoul(buf, 16, &val))
- return -EINVAL;
- if (!(test_bit(TPDM_DS_CMB, drvdata->datasets) ||
- test_bit(TPDM_DS_MCMB, drvdata->datasets)))
- return -EPERM;
-
- mutex_lock(&drvdata->lock);
- drvdata->cmb->patt_mask[TPDM_CMB_MSB] = val;
- mutex_unlock(&drvdata->lock);
- return size;
-}
-static DEVICE_ATTR(cmb_patt_mask_msb, 0644,
- tpdm_show_cmb_patt_mask_msb, tpdm_store_cmb_patt_mask_msb);
+static DEVICE_ATTR(cmb_patt_mask, 0644,
+ tpdm_show_cmb_patt_mask, tpdm_store_cmb_patt_mask);
static ssize_t tpdm_show_cmb_patt_ts(struct device *dev,
struct device_attribute *attr,
@@ -3896,10 +3817,8 @@
static struct attribute *tpdm_cmb_attrs[] = {
&dev_attr_cmb_available_modes.attr,
&dev_attr_cmb_mode.attr,
- &dev_attr_cmb_patt_val_lsb.attr,
- &dev_attr_cmb_patt_mask_lsb.attr,
- &dev_attr_cmb_patt_val_msb.attr,
- &dev_attr_cmb_patt_mask_msb.attr,
+ &dev_attr_cmb_patt_val.attr,
+ &dev_attr_cmb_patt_mask.attr,
&dev_attr_cmb_patt_ts.attr,
&dev_attr_cmb_trig_patt_val_lsb.attr,
&dev_attr_cmb_trig_patt_mask_lsb.attr,
@@ -4011,57 +3930,40 @@
drvdata->cmb->trig_ts = true;
}
-static int tpdm_probe(struct platform_device *pdev)
+static int tpdm_probe(struct amba_device *adev, const struct amba_id *id)
{
int ret, i;
uint32_t pidr, devid;
- struct device *dev = &pdev->dev;
+ struct device *dev = &adev->dev;
struct coresight_platform_data *pdata;
struct tpdm_drvdata *drvdata;
- struct resource *res;
struct coresight_desc *desc;
static int traceid = TPDM_TRACE_ID_START;
uint32_t version;
- pdata = of_get_coresight_platform_data(dev, pdev->dev.of_node);
+ pdata = of_get_coresight_platform_data(dev, adev->dev.of_node);
if (IS_ERR(pdata))
return PTR_ERR(pdata);
- pdev->dev.platform_data = pdata;
+ adev->dev.platform_data = pdata;
drvdata = devm_kzalloc(dev, sizeof(*drvdata), GFP_KERNEL);
if (!drvdata)
return -ENOMEM;
- drvdata->dev = &pdev->dev;
- platform_set_drvdata(pdev, drvdata);
+ drvdata->dev = &adev->dev;
+ dev_set_drvdata(dev, drvdata);
- res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "tpdm-base");
- if (!res)
- return -ENODEV;
-
- drvdata->base = devm_ioremap(dev, res->start, resource_size(res));
+ drvdata->base = devm_ioremap_resource(dev, &adev->res);
if (!drvdata->base)
return -ENOMEM;
- drvdata->clk_enable = of_property_read_bool(pdev->dev.of_node,
+ drvdata->clk_enable = of_property_read_bool(adev->dev.of_node,
"qcom,clk-enable");
- drvdata->msr_fix_req = of_property_read_bool(pdev->dev.of_node,
+ drvdata->msr_fix_req = of_property_read_bool(adev->dev.of_node,
"qcom,msr-fix-req");
mutex_init(&drvdata->lock);
- drvdata->clk = devm_clk_get(dev, "core_clk");
- if (IS_ERR(drvdata->clk))
- return PTR_ERR(drvdata->clk);
-
- ret = clk_set_rate(drvdata->clk, CORESIGHT_CLK_RATE_TRACE);
- if (ret)
- return ret;
-
- ret = clk_prepare_enable(drvdata->clk);
- if (ret)
- return ret;
-
version = tpdm_readl(drvdata, CORESIGHT_PERIPHIDR2);
drvdata->version = BMVAL(version, 4, 7);
@@ -4089,7 +3991,7 @@
drvdata->bc_counters_avail = BMVAL(devid, 6, 10) + 1;
drvdata->tc_counters_avail = BMVAL(devid, 4, 5) + 1;
- clk_disable_unprepare(drvdata->clk);
+ pm_runtime_put(&adev->dev);
drvdata->traceid = traceid++;
@@ -4099,8 +4001,8 @@
desc->type = CORESIGHT_DEV_TYPE_SOURCE;
desc->subtype.source_subtype = CORESIGHT_DEV_SUBTYPE_SOURCE_PROC;
desc->ops = &tpdm_cs_ops;
- desc->pdata = pdev->dev.platform_data;
- desc->dev = &pdev->dev;
+ desc->pdata = adev->dev.platform_data;
+ desc->dev = &adev->dev;
desc->groups = tpdm_attr_grps;
drvdata->csdev = coresight_register(desc);
if (IS_ERR(drvdata->csdev))
@@ -4114,40 +4016,26 @@
return 0;
}
-static int tpdm_remove(struct platform_device *pdev)
-{
- struct tpdm_drvdata *drvdata = platform_get_drvdata(pdev);
-
- coresight_unregister(drvdata->csdev);
- return 0;
-}
-
-static const struct of_device_id tpdm_match[] = {
- {.compatible = "qcom,coresight-tpdm"},
- {}
+static struct amba_id tpdm_ids[] = {
+ {
+ .id = 0x0003b968,
+ .mask = 0x0003ffff,
+ .data = "TPDM",
+ },
+ { 0, 0},
};
-static struct platform_driver tpdm_driver = {
- .probe = tpdm_probe,
- .remove = tpdm_remove,
- .driver = {
+static struct amba_driver tpdm_driver = {
+ .drv = {
.name = "coresight-tpdm",
.owner = THIS_MODULE,
- .of_match_table = tpdm_match,
+ .suppress_bind_attrs = true,
},
+ .probe = tpdm_probe,
+ .id_table = tpdm_ids,
};
-static int __init tpdm_init(void)
-{
- return platform_driver_register(&tpdm_driver);
-}
-module_init(tpdm_init);
-
-static void __exit tpdm_exit(void)
-{
- platform_driver_unregister(&tpdm_driver);
-}
-module_exit(tpdm_exit);
+builtin_amba_driver(tpdm_driver);
MODULE_LICENSE("GPL v2");
MODULE_DESCRIPTION("Trace, Profiling & Diagnostic Monitor driver");
diff --git a/drivers/input/joystick/xpad.c b/drivers/input/joystick/xpad.c
index bbe1524..f397a5b 100644
--- a/drivers/input/joystick/xpad.c
+++ b/drivers/input/joystick/xpad.c
@@ -201,6 +201,7 @@
{ 0x1430, 0x8888, "TX6500+ Dance Pad (first generation)", MAP_DPAD_TO_BUTTONS, XTYPE_XBOX },
{ 0x146b, 0x0601, "BigBen Interactive XBOX 360 Controller", 0, XTYPE_XBOX360 },
{ 0x1532, 0x0037, "Razer Sabertooth", 0, XTYPE_XBOX360 },
+ { 0x1532, 0x0a03, "Razer Wildcat", 0, XTYPE_XBOXONE },
{ 0x15e4, 0x3f00, "Power A Mini Pro Elite", 0, XTYPE_XBOX360 },
{ 0x15e4, 0x3f0a, "Xbox Airflo wired controller", 0, XTYPE_XBOX360 },
{ 0x15e4, 0x3f10, "Batarang Xbox 360 controller", 0, XTYPE_XBOX360 },
@@ -329,6 +330,7 @@
XPAD_XBOX360_VENDOR(0x24c6), /* PowerA Controllers */
XPAD_XBOXONE_VENDOR(0x24c6), /* PowerA Controllers */
XPAD_XBOX360_VENDOR(0x1532), /* Razer Sabertooth */
+ XPAD_XBOXONE_VENDOR(0x1532), /* Razer Wildcat */
XPAD_XBOX360_VENDOR(0x15e4), /* Numark X-Box 360 controllers */
XPAD_XBOX360_VENDOR(0x162e), /* Joytech X-Box 360 controllers */
{ }
diff --git a/drivers/input/mouse/elantech.c b/drivers/input/mouse/elantech.c
index db7d1d6..7826994 100644
--- a/drivers/input/mouse/elantech.c
+++ b/drivers/input/mouse/elantech.c
@@ -1118,6 +1118,7 @@
* Asus UX32VD 0x361f02 00, 15, 0e clickpad
* Avatar AVIU-145A2 0x361f00 ? clickpad
* Fujitsu LIFEBOOK E544 0x470f00 d0, 12, 09 2 hw buttons
+ * Fujitsu LIFEBOOK E547 0x470f00 50, 12, 09 2 hw buttons
* Fujitsu LIFEBOOK E554 0x570f01 40, 14, 0c 2 hw buttons
* Fujitsu T725 0x470f01 05, 12, 09 2 hw buttons
* Fujitsu H730 0x570f00 c0, 14, 0c 3 hw buttons (**)
@@ -1524,6 +1525,13 @@
},
},
{
+ /* Fujitsu LIFEBOOK E547 does not work with crc_enabled == 0 */
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "LIFEBOOK E547"),
+ },
+ },
+ {
/* Fujitsu LIFEBOOK E554 does not work with crc_enabled == 0 */
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU"),
diff --git a/drivers/iommu/arm-smmu.c b/drivers/iommu/arm-smmu.c
index 1e37af3..dd96670 100644
--- a/drivers/iommu/arm-smmu.c
+++ b/drivers/iommu/arm-smmu.c
@@ -828,26 +828,26 @@
return 0;
}
- ret = regulator_bulk_enable(pwr->num_gdscs, pwr->gdscs);
+ ret = arm_smmu_request_bus(pwr);
if (ret)
goto out_unlock;
- ret = arm_smmu_request_bus(pwr);
+ ret = regulator_bulk_enable(pwr->num_gdscs, pwr->gdscs);
if (ret)
- goto out_disable_regulators;
+ goto out_disable_bus;
ret = arm_smmu_prepare_clocks(pwr);
if (ret)
- goto out_disable_bus;
+ goto out_disable_regulators;
pwr->power_count = 1;
mutex_unlock(&pwr->power_lock);
return 0;
-out_disable_bus:
- arm_smmu_unrequest_bus(pwr);
out_disable_regulators:
regulator_bulk_disable(pwr->num_gdscs, pwr->gdscs);
+out_disable_bus:
+ arm_smmu_unrequest_bus(pwr);
out_unlock:
mutex_unlock(&pwr->power_lock);
return ret;
@@ -868,8 +868,8 @@
}
arm_smmu_unprepare_clocks(pwr);
- arm_smmu_unrequest_bus(pwr);
regulator_bulk_disable(pwr->num_gdscs, pwr->gdscs);
+ arm_smmu_unrequest_bus(pwr);
pwr->power_count = 0;
mutex_unlock(&pwr->power_lock);
}
@@ -3341,7 +3341,7 @@
i = 0;
of_property_for_each_string(dev->of_node, "qcom,regulator-names",
prop, cname)
- pwr->gdscs[i].supply = cname;
+ pwr->gdscs[i++].supply = cname;
ret = devm_regulator_bulk_get(dev, pwr->num_gdscs, pwr->gdscs);
return ret;
@@ -4375,7 +4375,7 @@
/* Attempt to register child devices */
ret = device_for_each_child(dev, smmu, qsmmuv500_tbu_register);
if (ret)
- return -EINVAL;
+ return -EPROBE_DEFER;
return 0;
}
diff --git a/drivers/iommu/iommu.c b/drivers/iommu/iommu.c
index c90fbf0..261c125 100644
--- a/drivers/iommu/iommu.c
+++ b/drivers/iommu/iommu.c
@@ -1750,3 +1750,23 @@
return 0;
}
EXPORT_SYMBOL_GPL(iommu_fwspec_add_ids);
+
+/*
+ * Return the id asoociated with a pci device.
+ */
+int iommu_fwspec_get_id(struct device *dev, u32 *id)
+{
+ struct iommu_fwspec *fwspec = dev->iommu_fwspec;
+
+ if (!fwspec)
+ return -EINVAL;
+
+ if (!dev_is_pci(dev))
+ return -EINVAL;
+
+ if (fwspec->num_ids != 1)
+ return -EINVAL;
+
+ *id = fwspec->ids[0];
+ return 0;
+}
diff --git a/drivers/irqchip/irq-imx-gpcv2.c b/drivers/irqchip/irq-imx-gpcv2.c
index 15af9a9..2d203b4 100644
--- a/drivers/irqchip/irq-imx-gpcv2.c
+++ b/drivers/irqchip/irq-imx-gpcv2.c
@@ -230,6 +230,8 @@
return -ENOMEM;
}
+ raw_spin_lock_init(&cd->rlock);
+
cd->gpc_base = of_iomap(node, 0);
if (!cd->gpc_base) {
pr_err("fsl-gpcv2: unable to map gpc registers\n");
diff --git a/drivers/mailbox/qti-tcs.c b/drivers/mailbox/qti-tcs.c
index 0a802fd..dfed3cd 100644
--- a/drivers/mailbox/qti-tcs.c
+++ b/drivers/mailbox/qti-tcs.c
@@ -15,6 +15,7 @@
#include <linux/atomic.h>
#include <linux/bitmap.h>
+#include <linux/delay.h>
#include <linux/interrupt.h>
#include <linux/jiffies.h>
#include <linux/kernel.h>
@@ -84,8 +85,8 @@
#define TCS_HIDDEN_CMD_SHIFT 0x08
#define TCS_TYPE_NR 4
-#define TCS_MBOX_TOUT_MS 2000
#define MAX_POOL_SIZE (MAX_TCS_PER_TYPE * TCS_TYPE_NR)
+#define TCS_M_INIT 0xFFFF
struct tcs_drv;
@@ -95,12 +96,13 @@
struct tcs_mbox_msg *msg;
u32 m; /* m-th TCS */
struct tasklet_struct tasklet;
- struct delayed_work dwork;
int err;
+ int idx;
+ bool in_use;
};
struct tcs_response_pool {
- struct tcs_response *resp;
+ struct tcs_response resp[MAX_POOL_SIZE];
spinlock_t lock;
DECLARE_BITMAP(avail, MAX_POOL_SIZE);
};
@@ -116,8 +118,6 @@
int ncpt; /* num cmds per tcs */
DECLARE_BITMAP(slots, MAX_TCS_SLOTS);
spinlock_t tcs_lock; /* TCS type lock */
- spinlock_t tcs_m_lock[MAX_TCS_PER_TYPE];
- struct tcs_response *resp[MAX_TCS_PER_TYPE];
};
/* One per MBOX controller */
@@ -133,11 +133,12 @@
int num_tcs;
struct workqueue_struct *wq;
struct tcs_response_pool *resp_pool;
- atomic_t tcs_in_use[TCS_TYPE_NR * MAX_TCS_PER_TYPE];
+ atomic_t tcs_in_use[MAX_POOL_SIZE];
+ atomic_t tcs_send_count[MAX_POOL_SIZE];
+ atomic_t tcs_irq_count[MAX_POOL_SIZE];
};
static void tcs_notify_tx_done(unsigned long data);
-static void tcs_notify_timeout(struct work_struct *work);
static int tcs_response_pool_init(struct tcs_drv *drv)
{
@@ -148,16 +149,12 @@
if (!pool)
return -ENOMEM;
- pool->resp = devm_kzalloc(&drv->pdev->dev, sizeof(*pool->resp) *
- MAX_POOL_SIZE, GFP_KERNEL);
- if (!pool->resp)
- return -ENOMEM;
-
for (i = 0; i < MAX_POOL_SIZE; i++) {
tasklet_init(&pool->resp[i].tasklet, tcs_notify_tx_done,
(unsigned long) &pool->resp[i]);
- INIT_DELAYED_WORK(&pool->resp[i].dwork,
- tcs_notify_timeout);
+ pool->resp[i].drv = drv;
+ pool->resp[i].idx = i;
+ pool->resp[i].m = TCS_M_INIT;
}
spin_lock_init(&pool->lock);
@@ -166,39 +163,59 @@
return 0;
}
-static struct tcs_response *get_response_from_pool(struct tcs_drv *drv)
+static struct tcs_response *setup_response(struct tcs_drv *drv,
+ struct tcs_mbox_msg *msg, struct mbox_chan *chan,
+ u32 m, int err)
{
struct tcs_response_pool *pool = drv->resp_pool;
struct tcs_response *resp = ERR_PTR(-ENOMEM);
- unsigned long flags;
int pos;
- spin_lock_irqsave(&pool->lock, flags);
+ spin_lock(&pool->lock);
pos = find_first_zero_bit(pool->avail, MAX_POOL_SIZE);
if (pos != MAX_POOL_SIZE) {
bitmap_set(pool->avail, pos, 1);
resp = &pool->resp[pos];
- memset(resp, 0, sizeof(*resp));
- tasklet_init(&resp->tasklet, tcs_notify_tx_done,
- (unsigned long) resp);
- INIT_DELAYED_WORK(&resp->dwork, tcs_notify_timeout);
- resp->drv = drv;
+ resp->chan = chan;
+ resp->msg = msg;
+ resp->m = m;
+ resp->err = err;
+ resp->in_use = false;
}
- spin_unlock_irqrestore(&pool->lock, flags);
+ spin_unlock(&pool->lock);
return resp;
}
-static void free_response_to_pool(struct tcs_response *resp)
+static void free_response(struct tcs_response *resp)
{
struct tcs_response_pool *pool = resp->drv->resp_pool;
- unsigned long flags;
- int i;
- spin_lock_irqsave(&pool->lock, flags);
- i = resp - pool->resp;
- bitmap_clear(pool->avail, i, 1);
- spin_unlock_irqrestore(&pool->lock, flags);
+ spin_lock(&pool->lock);
+ resp->err = -EINVAL;
+ bitmap_clear(pool->avail, resp->idx, 1);
+ spin_unlock(&pool->lock);
+}
+
+static inline struct tcs_response *get_response(struct tcs_drv *drv, u32 m)
+{
+ struct tcs_response_pool *pool = drv->resp_pool;
+ struct tcs_response *resp = NULL;
+ int pos = 0;
+
+ do {
+ pos = find_next_bit(pool->avail, MAX_POOL_SIZE, pos);
+ if (pos == MAX_POOL_SIZE)
+ break;
+ resp = &pool->resp[pos];
+ if (resp->m == m && !resp->in_use) {
+ resp->in_use = true;
+ break;
+ }
+ pos++;
+ } while (1);
+
+ return resp;
}
static inline u32 read_drv_config(void __iomem *base)
@@ -226,7 +243,7 @@
write_tcs_reg(base, reg, m, n, data);
if (data == read_tcs_reg(base, reg, m, n))
break;
- cpu_relax();
+ udelay(1);
} while (1);
}
@@ -311,23 +328,11 @@
return get_tcs_of_type(drv, type);
}
-static inline struct tcs_response *get_tcs_response(struct tcs_drv *drv, int m)
-{
- struct tcs_mbox *tcs = get_tcs_from_index(drv, m);
-
- return tcs ? tcs->resp[m - tcs->tcs_offset] : NULL;
-}
-
static inline void send_tcs_response(struct tcs_response *resp)
{
tasklet_schedule(&resp->tasklet);
}
-static inline void schedule_tcs_err_response(struct tcs_response *resp)
-{
- schedule_delayed_work(&resp->dwork, msecs_to_jiffies(TCS_MBOX_TOUT_MS));
-}
-
/**
* tcs_irq_handler: TX Done / Recv data handler
*/
@@ -340,7 +345,6 @@
struct tcs_mbox *tcs;
struct tcs_response *resp;
struct tcs_cmd *cmd;
- u32 irq_clear = 0;
u32 data;
/* Know which TCSes were triggered */
@@ -350,15 +354,14 @@
if (!(irq_status & BIT(m)))
continue;
- /* Find the TCS that triggered */
- resp = get_tcs_response(drv, m);
+ atomic_inc(&drv->tcs_irq_count[m]);
+
+ resp = get_response(drv, m);
if (!resp) {
pr_err("No resp request for TCS-%d\n", m);
continue;
}
- cancel_delayed_work(&resp->dwork);
-
tcs = get_tcs_from_index(drv, m);
if (!tcs) {
pr_err("TCS-%d doesn't exist in DRV\n", m);
@@ -397,18 +400,13 @@
write_tcs_reg(base, TCS_DRV_CMD_ENABLE, m, 0, 0);
}
- /* Notify the client that this request is completed. */
+ /* Clear the TCS IRQ status */
+ write_tcs_reg(base, TCS_DRV_IRQ_CLEAR, 0, 0, BIT(m));
+
+ /* Clean up response object and notify mbox in tasklet */
send_tcs_response(resp);
- irq_clear |= BIT(m);
- }
- /* Clear the TCS IRQ status */
- write_tcs_reg(base, TCS_DRV_IRQ_CLEAR, 0, 0, irq_clear);
-
- /* Mark the TCS as free */
- for (m = 0; irq_status >= BIT(m); m++) {
- if (!(irq_status & BIT(m)))
- continue;
+ /* Notify the client that this request is completed. */
atomic_set(&drv->tcs_in_use[m], 0);
}
@@ -435,54 +433,8 @@
int err = resp->err;
int m = resp->m;
- free_response_to_pool(resp);
mbox_notify_tx_done(chan, msg, m, err);
-}
-
-/**
- * tcs_notify_timeout: TX Done for requests that do trigger TCS, but
- * we do not get a response IRQ back.
- */
-static void tcs_notify_timeout(struct work_struct *work)
-{
- struct delayed_work *dwork = to_delayed_work(work);
- struct tcs_response *resp = container_of(dwork,
- struct tcs_response, dwork);
- struct mbox_chan *chan = resp->chan;
- struct tcs_mbox_msg *msg = resp->msg;
- struct tcs_drv *drv = resp->drv;
- int m = resp->m;
-
- /*
- * In case the RPMH resource fails to respond to the completion
- * request, the TCS would be blocked forever waiting on the response.
- * There is no way to recover from this case.
- */
- if (!tcs_is_free(drv, m)) {
- bool pending = false;
- struct tcs_cmd *cmd;
- int i;
- u32 addr;
-
- for (i = 0; i < msg->num_payload; i++) {
- cmd = &msg->payload[i];
- addr = read_tcs_reg(drv->reg_base, TCS_DRV_CMD_ADDR,
- m, i);
- pending = (cmd->addr == addr);
- }
- if (pending) {
- pr_err("TCS-%d blocked waiting for RPMH to respond.\n",
- m);
- for (i = 0; i < msg->num_payload; i++)
- pr_err("Addr: 0x%x Data: 0x%x\n",
- msg->payload[i].addr,
- msg->payload[i].data);
- BUG();
- }
- }
-
- free_response_to_pool(resp);
- mbox_notify_tx_done(chan, msg, -1, -ETIMEDOUT);
+ free_response(resp);
}
static void __tcs_buffer_write(struct tcs_drv *drv, int d, int m, int n,
@@ -525,8 +477,6 @@
write_tcs_reg(base, TCS_DRV_CMD_ENABLE, m, 0, cmd_enable);
if (trigger) {
- /* Mark the TCS as busy */
- atomic_set(&drv->tcs_in_use[m], 1);
/* HW req: Clear the DRV_CONTROL and enable TCS again */
write_tcs_reg_sync(base, TCS_DRV_CONTROL, m, 0, 0);
write_tcs_reg_sync(base, TCS_DRV_CONTROL, m, 0, enable);
@@ -560,54 +510,45 @@
return true;
}
-static void wait_for_req_inflight(struct tcs_drv *drv, struct tcs_mbox *tcs,
+static int check_for_req_inflight(struct tcs_drv *drv, struct tcs_mbox *tcs,
struct tcs_mbox_msg *msg)
{
- u32 curr_enabled;
+ u32 curr_enabled, addr;
int i, j, k;
- bool is_free;
+ void __iomem *base = drv->reg_base;
+ int m = tcs->tcs_offset;
- do {
- is_free = true;
- for (i = 1; i > tcs->tcs_mask; i = i << 1) {
- if (!(tcs->tcs_mask & i))
+ for (i = 0; i < tcs->num_tcs; i++, m++) {
+ if (tcs_is_free(drv, m))
+ continue;
+
+ curr_enabled = read_tcs_reg(base, TCS_DRV_CMD_ENABLE, m, 0);
+ for (j = 0; j < curr_enabled; j++) {
+ if (!(curr_enabled & BIT(j)))
continue;
- if (tcs_is_free(drv, i))
- continue;
- curr_enabled = read_tcs_reg(drv->reg_base,
- TCS_DRV_CMD_ENABLE, i, 0);
- for (j = 0; j < msg->num_payload; j++) {
- for (k = 0; k < curr_enabled; k++) {
- if (!(curr_enabled & BIT(k)))
- continue;
- if (tcs->cmd_addr[k] ==
- msg->payload[j].addr) {
- is_free = false;
- goto retry;
- }
- }
+ addr = read_tcs_reg(base, TCS_DRV_CMD_ADDR, m, j);
+ for (k = 0; k < msg->num_payload; k++) {
+ if (addr == msg->payload[k].addr)
+ return -EBUSY;
}
}
-retry:
- if (!is_free)
- cpu_relax();
- } while (!is_free);
+ }
+
+ return 0;
}
static int find_free_tcs(struct tcs_mbox *tcs)
{
- int slot, m = 0;
+ int slot = -EBUSY;
+ int m = 0;
/* Loop until we find a free AMC */
- do {
+ for (m = 0; m < tcs->num_tcs; m++) {
if (tcs_is_free(tcs->drv, tcs->tcs_offset + m)) {
slot = m * tcs->ncpt;
break;
}
- if (++m >= tcs->num_tcs)
- m = 0;
- cpu_relax();
- } while (1);
+ }
return slot;
}
@@ -663,26 +604,6 @@
return (slot != MAX_TCS_SLOTS) ? slot : -ENOMEM;
}
-static struct tcs_response *setup_response(struct tcs_mbox *tcs,
- struct mbox_chan *chan, struct tcs_mbox_msg *msg, int m)
-{
- struct tcs_response *resp = get_response_from_pool(tcs->drv);
-
- if (IS_ERR(resp))
- return resp;
-
- if (m < tcs->tcs_offset)
- return ERR_PTR(-EINVAL);
-
- tcs->resp[m - tcs->tcs_offset] = resp;
- resp->msg = msg;
- resp->chan = chan;
- resp->m = m;
- resp->err = 0;
-
- return resp;
-}
-
static int tcs_mbox_write(struct mbox_chan *chan, struct tcs_mbox_msg *msg,
bool trigger)
{
@@ -690,21 +611,36 @@
struct tcs_drv *drv = container_of(chan->mbox, struct tcs_drv, mbox);
int d = drv->drv_id;
struct tcs_mbox *tcs;
- int i, slot, offset, m, n;
+ int i, slot, offset, m, n, ret;
struct tcs_response *resp = NULL;
+ unsigned long flags;
tcs = get_tcs_for_msg(drv, msg);
if (IS_ERR(tcs))
return PTR_ERR(tcs);
+ if (trigger)
+ resp = setup_response(drv, msg, chan, TCS_M_INIT, 0);
+
/* Identify the sequential slots that we can write to */
- spin_lock(&tcs->tcs_lock);
+ spin_lock_irqsave(&tcs->tcs_lock, flags);
slot = find_slots(tcs, msg);
if (slot < 0) {
dev_err(dev, "No TCS slot found.\n");
- spin_unlock(&tcs->tcs_lock);
+ spin_unlock_irqrestore(&tcs->tcs_lock, flags);
+ if (resp)
+ free_response(resp);
return slot;
}
+
+ if (trigger) {
+ ret = check_for_req_inflight(drv, tcs, msg);
+ if (ret) {
+ spin_unlock_irqrestore(&tcs->tcs_lock, flags);
+ return ret;
+ }
+ }
+
/* Mark the slots as in-use, before we unlock */
if (tcs->type == SLEEP_TCS || tcs->type == WAKE_TCS)
bitmap_set(tcs->slots, slot, msg->num_payload);
@@ -713,37 +649,22 @@
for (i = 0; tcs->cmd_addr && i < msg->num_payload; i++)
tcs->cmd_addr[slot + i] = msg->payload[i].addr;
- if (trigger)
- resp = setup_response(tcs, chan, msg,
- slot / tcs->ncpt + tcs->tcs_offset);
-
- spin_unlock(&tcs->tcs_lock);
-
- /*
- * Find the TCS corresponding to the slot and start writing.
- * Break down 'slot' into a 'n' position in the 'm'th TCS.
- */
offset = slot / tcs->ncpt;
m = offset + tcs->tcs_offset;
n = slot % tcs->ncpt;
- spin_lock(&tcs->tcs_m_lock[offset]);
+ /* Block, if we have an address from the msg in flight */
if (trigger) {
- /* Block, if we have an address from the msg in flight */
- wait_for_req_inflight(drv, tcs, msg);
- /* If the TCS is busy there is nothing to do but spin wait */
- while (!tcs_is_free(drv, m))
- cpu_relax();
+ resp->m = m;
+ /* Mark the TCS as busy */
+ atomic_set(&drv->tcs_in_use[m], 1);
+ atomic_inc(&drv->tcs_send_count[m]);
}
/* Write to the TCS or AMC */
__tcs_buffer_write(drv, d, m, n, msg, trigger);
- /* Schedule a timeout response, incase there is no actual response */
- if (trigger)
- schedule_tcs_err_response(resp);
-
- spin_unlock(&tcs->tcs_m_lock[offset]);
+ spin_unlock_irqrestore(&tcs->tcs_lock, flags);
return 0;
}
@@ -760,24 +681,21 @@
int m, i;
int inv_types[] = { WAKE_TCS, SLEEP_TCS };
int type = 0;
+ unsigned long flags;
do {
tcs = get_tcs_of_type(drv, inv_types[type]);
if (IS_ERR(tcs))
return PTR_ERR(tcs);
- spin_lock(&tcs->tcs_lock);
+ spin_lock_irqsave(&tcs->tcs_lock, flags);
for (i = 0; i < tcs->num_tcs; i++) {
m = i + tcs->tcs_offset;
- spin_lock(&tcs->tcs_m_lock[i]);
- while (!tcs_is_free(drv, m))
- cpu_relax();
__tcs_buffer_invalidate(drv->reg_base, m);
- spin_unlock(&tcs->tcs_m_lock[i]);
}
/* Mark the TCS as free */
bitmap_zero(tcs->slots, MAX_TCS_SLOTS);
- spin_unlock(&tcs->tcs_lock);
+ spin_unlock_irqrestore(&tcs->tcs_lock, flags);
} while (++type < ARRAY_SIZE(inv_types));
return 0;
@@ -799,6 +717,7 @@
struct tcs_mbox_msg *msg = data;
const struct device *dev = chan->cl->dev;
int ret = -EINVAL;
+ int count = 0;
if (!msg) {
dev_err(dev, "Payload error.\n");
@@ -835,17 +754,21 @@
tcs_mbox_invalidate(chan);
/* Post the message to the TCS and trigger */
- ret = tcs_mbox_write(chan, msg, true);
+ do {
+ ret = tcs_mbox_write(chan, msg, true);
+ if (ret == -EBUSY) {
+ ret = -EIO;
+ udelay(10);
+ } else
+ break;
+ } while (++count < 10);
tx_fail:
if (ret) {
struct tcs_drv *drv = container_of(chan->mbox,
- struct tcs_drv, mbox);
- struct tcs_response *resp = get_response_from_pool(drv);
-
- resp->chan = chan;
- resp->msg = msg;
- resp->err = ret;
+ struct tcs_drv, mbox);
+ struct tcs_response *resp = setup_response(
+ drv, msg, chan, TCS_M_INIT, ret);
dev_err(dev, "Error sending RPMH message %d\n", ret);
send_tcs_response(resp);
@@ -873,6 +796,7 @@
const struct device *dev = chan->cl->dev;
struct tcs_drv *drv = container_of(chan->mbox, struct tcs_drv, mbox);
struct tcs_mbox *tcs;
+ unsigned long flags;
tcs = get_tcs_of_type(drv, CONTROL_TCS);
if (IS_ERR(tcs))
@@ -883,9 +807,9 @@
return -EINVAL;
}
- spin_lock(&tcs->tcs_lock);
+ spin_lock_irqsave(&tcs->tcs_lock, flags);
__tcs_write_hidden(tcs->drv, drv->drv_id, msg);
- spin_unlock(&tcs->tcs_lock);
+ spin_unlock_irqrestore(&tcs->tcs_lock, flags);
return 0;
}
@@ -1040,8 +964,6 @@
tcs->ncpt = (tcs->type == CONTROL_TCS) ? TCS_HIDDEN_MAX_SLOTS
: ncpt;
spin_lock_init(&tcs->tcs_lock);
- for (j = 0; j < ARRAY_SIZE(tcs->tcs_m_lock); j++)
- spin_lock_init(&tcs->tcs_m_lock[j]);
if (tcs->num_tcs <= 0 || tcs->type == CONTROL_TCS)
continue;
@@ -1115,9 +1037,8 @@
if (irq < 0)
return irq;
- ret = devm_request_threaded_irq(&pdev->dev, irq, NULL,
- tcs_irq_handler,
- IRQF_ONESHOT | IRQF_TRIGGER_HIGH | IRQF_NO_SUSPEND,
+ ret = devm_request_irq(&pdev->dev, irq, tcs_irq_handler,
+ IRQF_TRIGGER_HIGH | IRQF_NO_SUSPEND,
"tcs_irq", drv);
if (ret)
return ret;
diff --git a/drivers/media/platform/msm/camera/Makefile b/drivers/media/platform/msm/camera/Makefile
index c897669..19de267 100644
--- a/drivers/media/platform/msm/camera/Makefile
+++ b/drivers/media/platform/msm/camera/Makefile
@@ -2,3 +2,4 @@
obj-$(CONFIG_SPECTRA_CAMERA) += cam_utils/
obj-$(CONFIG_SPECTRA_CAMERA) += cam_core/
obj-$(CONFIG_SPECTRA_CAMERA) += cam_sync/
+obj-$(CONFIG_SPECTRA_CAMERA) += cam_smmu/
diff --git a/drivers/media/platform/msm/camera/cam_req_mgr/Makefile b/drivers/media/platform/msm/camera/cam_req_mgr/Makefile
index f8c864f..87707b1 100644
--- a/drivers/media/platform/msm/camera/cam_req_mgr/Makefile
+++ b/drivers/media/platform/msm/camera/cam_req_mgr/Makefile
@@ -1 +1,3 @@
-obj-$(CONFIG_SPECTRA_CAMERA) += cam_req_mgr_dev.o cam_req_mgr_util.o cam_req_mgr_core.o cam_req_mgr_workq.o
+ccflags-y += -Idrivers/media/platform/msm/camera/cam_smmu/
+
+obj-$(CONFIG_SPECTRA_CAMERA) += cam_req_mgr_dev.o cam_req_mgr_util.o cam_req_mgr_core.o cam_req_mgr_workq.o cam_mem_mgr.o
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
new file mode 100644
index 0000000..f3ef0e9
--- /dev/null
+++ b/drivers/media/platform/msm/camera/cam_req_mgr/cam_mem_mgr.c
@@ -0,0 +1,968 @@
+/* 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.
+ */
+
+#define pr_fmt(fmt) "CAM-MEM-MGR %s:%d " fmt, __func__, __LINE__
+
+#ifdef CONFIG_MEM_MGR_DBG
+#define CDBG(fmt, args...) pr_err(fmt, ##args)
+#else
+#define CDBG(fmt, args...) pr_debug(fmt, ##args)
+#endif
+
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/mutex.h>
+#include <linux/msm_ion.h>
+#include <asm/cacheflush.h>
+
+#include "cam_req_mgr_util.h"
+#include "cam_mem_mgr.h"
+#include "cam_smmu_api.h"
+
+static struct cam_mem_table tbl;
+
+static int cam_mem_util_map_cpu_va(struct ion_handle *hdl,
+ uint64_t *vaddr,
+ size_t *len)
+{
+ *vaddr = (uintptr_t)ion_map_kernel(tbl.client, hdl);
+ if (IS_ERR_OR_NULL((void *)*vaddr)) {
+ pr_err("kernel map fail");
+ return -ENOSPC;
+ }
+
+ if (ion_handle_get_size(tbl.client, hdl, len)) {
+ pr_err("kernel get len failed");
+ ion_unmap_kernel(tbl.client, hdl);
+ return -ENOSPC;
+ }
+
+ return 0;
+}
+
+static int cam_mem_util_get_dma_dir(uint32_t flags)
+{
+ int rc = -EINVAL;
+
+ if (flags & CAM_MEM_FLAG_HW_READ_ONLY)
+ rc = DMA_TO_DEVICE;
+ else if (flags & CAM_MEM_FLAG_HW_WRITE_ONLY)
+ rc = DMA_FROM_DEVICE;
+ else if (flags & CAM_MEM_FLAG_HW_READ_WRITE)
+ rc = DMA_BIDIRECTIONAL;
+
+ return rc;
+}
+
+static int cam_mem_util_client_create(void)
+{
+ int rc = 0;
+
+ tbl.client = msm_ion_client_create("camera_global_pool");
+ if (IS_ERR_OR_NULL(tbl.client)) {
+ pr_err("fail to create client\n");
+ rc = -EINVAL;
+ }
+
+ return rc;
+}
+
+static void cam_mem_util_client_destroy(void)
+{
+ ion_client_destroy(tbl.client);
+ tbl.client = NULL;
+}
+
+int cam_mem_mgr_init(void)
+{
+ int rc;
+ int i;
+ int bitmap_size;
+
+ memset(tbl.bufq, 0, sizeof(tbl.bufq));
+
+ rc = cam_mem_util_client_create();
+ if (rc < 0) {
+ pr_err("fail to create ion client\n");
+ goto client_fail;
+ }
+
+ bitmap_size = BITS_TO_LONGS(CAM_MEM_BUFQ_MAX) * sizeof(long);
+ tbl.bitmap = kzalloc(sizeof(bitmap_size), GFP_KERNEL);
+ if (!tbl.bitmap) {
+ rc = -ENOMEM;
+ goto bitmap_fail;
+ }
+ tbl.bits = bitmap_size * BITS_PER_BYTE;
+ bitmap_zero(tbl.bitmap, tbl.bits);
+ /* We need to reserve slot 0 because 0 is invalid */
+ set_bit(0, tbl.bitmap);
+
+ for (i = 1; i < CAM_MEM_BUFQ_MAX; i++) {
+ tbl.bufq[i].fd = -1;
+ tbl.bufq[i].buf_handle = -1;
+ }
+ mutex_init(&tbl.m_lock);
+ return rc;
+
+bitmap_fail:
+ cam_mem_util_client_destroy();
+client_fail:
+ return rc;
+}
+
+static int cam_mem_mgr_cleanup_table(void)
+{
+ int i;
+
+ mutex_lock(&tbl.m_lock);
+ for (i = 1; i < CAM_MEM_BUFQ_MAX; i++) {
+ if (!tbl.bufq[i].active) {
+ CDBG("Buffer inactive at idx=%d, continuing\n", i);
+ continue;
+ } else {
+ pr_err("Active buffer at idx=%d, possible leak\n", i);
+ }
+
+ mutex_lock(&tbl.bufq[i].q_lock);
+ ion_free(tbl.client, tbl.bufq[i].i_hdl);
+ tbl.bufq[i].fd = -1;
+ tbl.bufq[i].flags = 0;
+ tbl.bufq[i].buf_handle = -1;
+ tbl.bufq[i].vaddr = 0;
+ tbl.bufq[i].len = 0;
+ memset(tbl.bufq[i].hdls, 0,
+ sizeof(int32_t) * tbl.bufq[i].num_hdl);
+ tbl.bufq[i].num_hdl = 0;
+ tbl.bufq[i].i_hdl = NULL;
+ tbl.bufq[i].active = false;
+ mutex_unlock(&tbl.bufq[i].q_lock);
+ mutex_destroy(&tbl.bufq[i].q_lock);
+ }
+ bitmap_zero(tbl.bitmap, tbl.bits);
+ /* We need to reserve slot 0 because 0 is invalid */
+ set_bit(0, tbl.bitmap);
+ mutex_unlock(&tbl.m_lock);
+
+ return 0;
+}
+
+void cam_mem_mgr_deinit(void)
+{
+ cam_mem_mgr_cleanup_table();
+ mutex_lock(&tbl.m_lock);
+ bitmap_zero(tbl.bitmap, tbl.bits);
+ kfree(tbl.bitmap);
+ tbl.bitmap = NULL;
+ cam_mem_util_client_destroy();
+ mutex_unlock(&tbl.m_lock);
+ mutex_destroy(&tbl.m_lock);
+}
+
+static int32_t cam_mem_get_slot(void)
+{
+ int32_t idx;
+
+ mutex_lock(&tbl.m_lock);
+ idx = find_first_zero_bit(tbl.bitmap, tbl.bits);
+ if (idx >= CAM_MEM_BUFQ_MAX || idx <= 0) {
+ mutex_unlock(&tbl.m_lock);
+ return -ENOMEM;
+ }
+
+ set_bit(idx, tbl.bitmap);
+ tbl.bufq[idx].active = true;
+ mutex_init(&tbl.bufq[idx].q_lock);
+ mutex_unlock(&tbl.m_lock);
+
+ return idx;
+}
+
+static void cam_mem_put_slot(int32_t idx)
+{
+ mutex_lock(&tbl.m_lock);
+ mutex_lock(&tbl.bufq[idx].q_lock);
+ tbl.bufq[idx].active = false;
+ mutex_unlock(&tbl.bufq[idx].q_lock);
+ mutex_destroy(&tbl.bufq[idx].q_lock);
+ clear_bit(idx, tbl.bitmap);
+ mutex_unlock(&tbl.m_lock);
+}
+
+int cam_mem_get_io_buf(int32_t buf_handle, int32_t mmu_handle,
+ uint64_t *iova_ptr, size_t *len_ptr)
+{
+ int rc = 0, idx;
+
+ idx = CAM_MEM_MGR_GET_HDL_IDX(buf_handle);
+ if (idx >= CAM_MEM_BUFQ_MAX || idx <= 0)
+ return -EINVAL;
+
+ if (!tbl.bufq[idx].active)
+ return -EINVAL;
+
+ mutex_lock(&tbl.bufq[idx].q_lock);
+ if (buf_handle != tbl.bufq[idx].buf_handle) {
+ rc = -EINVAL;
+ goto handle_mismatch;
+ }
+
+ rc = cam_smmu_get_iova(mmu_handle,
+ tbl.bufq[idx].fd,
+ iova_ptr,
+ len_ptr);
+ if (rc < 0)
+ pr_err("fail to get buf hdl :%d", buf_handle);
+
+handle_mismatch:
+ mutex_unlock(&tbl.bufq[idx].q_lock);
+ return rc;
+}
+EXPORT_SYMBOL(cam_mem_get_io_buf);
+
+int cam_mem_get_cpu_buf(int32_t buf_handle, uint64_t *vaddr_ptr, size_t *len)
+{
+ int rc = 0;
+ int idx;
+ struct ion_handle *ion_hdl = NULL;
+ uint64_t kvaddr = 0;
+ size_t klen = 0;
+
+ if (!buf_handle || !vaddr_ptr || !len)
+ return -EINVAL;
+
+ idx = CAM_MEM_MGR_GET_HDL_IDX(buf_handle);
+ if (idx >= CAM_MEM_BUFQ_MAX || idx <= 0)
+ return -EINVAL;
+
+ if (!tbl.bufq[idx].active)
+ return -EPERM;
+
+ mutex_lock(&tbl.bufq[idx].q_lock);
+ if (buf_handle != tbl.bufq[idx].buf_handle) {
+ rc = -EINVAL;
+ goto exit_func;
+ }
+
+ ion_hdl = tbl.bufq[idx].i_hdl;
+ if (!ion_hdl) {
+ pr_err("Invalid ION handle\n");
+ rc = -EINVAL;
+ goto exit_func;
+ }
+
+ if (tbl.bufq[idx].flags & CAM_MEM_FLAG_KMD_ACCESS) {
+ if (!tbl.bufq[idx].kmdvaddr) {
+ rc = cam_mem_util_map_cpu_va(ion_hdl,
+ &kvaddr, &klen);
+ if (rc)
+ goto exit_func;
+ tbl.bufq[idx].kmdvaddr = kvaddr;
+ }
+ } else {
+ rc = -EINVAL;
+ goto exit_func;
+ }
+
+ *vaddr_ptr = tbl.bufq[idx].kmdvaddr;
+ *len = tbl.bufq[idx].len;
+
+exit_func:
+ mutex_unlock(&tbl.bufq[idx].q_lock);
+ return rc;
+}
+EXPORT_SYMBOL(cam_mem_get_cpu_buf);
+
+int cam_mem_mgr_cache_ops(struct cam_mem_cache_ops_cmd *cmd)
+{
+ int rc = 0, idx;
+ uint32_t ion_cache_ops;
+ unsigned long ion_flag = 0;
+
+ if (!cmd)
+ return -EINVAL;
+
+ idx = CAM_MEM_MGR_GET_HDL_IDX(cmd->buf_handle);
+ if (idx >= CAM_MEM_BUFQ_MAX || idx <= 0)
+ return -EINVAL;
+
+ mutex_lock(&tbl.bufq[idx].q_lock);
+
+ if (!tbl.bufq[idx].active) {
+ rc = -EINVAL;
+ goto fail;
+ }
+
+ if (cmd->buf_handle != tbl.bufq[idx].buf_handle) {
+ rc = -EINVAL;
+ goto fail;
+ }
+
+ rc = ion_handle_get_flags(tbl.client, tbl.bufq[idx].i_hdl,
+ &ion_flag);
+ if (rc) {
+ pr_err("cache get flags failed %d\n", rc);
+ goto fail;
+ }
+
+ if (ION_IS_CACHED(ion_flag)) {
+ switch (cmd->mem_cache_ops) {
+ case CAM_MEM_CLEAN_CACHE:
+ ion_cache_ops = ION_IOC_CLEAN_CACHES;
+ break;
+ case CAM_MEM_INV_CACHE:
+ ion_cache_ops = ION_IOC_INV_CACHES;
+ break;
+ case CAM_MEM_CLEAN_INV_CACHE:
+ ion_cache_ops = ION_IOC_CLEAN_INV_CACHES;
+ break;
+ default:
+ pr_err("invalid cache ops :%d", cmd->mem_cache_ops);
+ rc = -EINVAL;
+ goto fail;
+ }
+
+ rc = msm_ion_do_cache_op(tbl.client,
+ tbl.bufq[idx].i_hdl,
+ (void *)tbl.bufq[idx].vaddr,
+ tbl.bufq[idx].len,
+ ion_cache_ops);
+ if (rc)
+ pr_err("cache operation failed %d\n", rc);
+ }
+fail:
+ mutex_unlock(&tbl.bufq[idx].q_lock);
+ return rc;
+}
+EXPORT_SYMBOL(cam_mem_mgr_cache_ops);
+
+static int cam_mem_util_get_ion_buffer(size_t len,
+ size_t align,
+ unsigned int heap_id_mask,
+ unsigned int flags,
+ struct ion_handle **hdl,
+ int *fd)
+{
+ int rc = 0;
+
+ *hdl = ion_alloc(tbl.client, len, align, heap_id_mask, flags);
+ if (IS_ERR_OR_NULL(*hdl))
+ return -ENOMEM;
+
+ *fd = ion_share_dma_buf_fd(tbl.client, *hdl);
+ if (*fd < 0) {
+ pr_err("dma buf get fd fail");
+ rc = -EINVAL;
+ goto get_fd_fail;
+ }
+
+ return rc;
+
+get_fd_fail:
+ ion_free(tbl.client, *hdl);
+ return rc;
+}
+
+static int cam_mem_util_ion_alloc(struct cam_mem_mgr_alloc_cmd *cmd,
+ struct ion_handle **hdl,
+ int *fd)
+{
+ uint32_t heap_id;
+ uint32_t ion_flag = 0;
+ int rc;
+
+ if (cmd->flags & CAM_MEM_FLAG_PROTECTED_MODE)
+ heap_id = ION_HEAP(ION_SECURE_DISPLAY_HEAP_ID);
+ else
+ heap_id = ION_HEAP(ION_SYSTEM_HEAP_ID);
+
+ if (cmd->flags & CAM_MEM_FLAG_CACHE)
+ ion_flag |= ION_FLAG_CACHED;
+ else
+ ion_flag &= ~ION_FLAG_CACHED;
+
+ rc = cam_mem_util_get_ion_buffer(cmd->len,
+ cmd->align,
+ heap_id,
+ ion_flag,
+ hdl,
+ fd);
+
+ return rc;
+}
+
+
+static int cam_mem_util_check_flags(struct cam_mem_mgr_alloc_cmd *cmd)
+{
+ if (!cmd->flags) {
+ pr_err("Invalid flags\n");
+ return -EINVAL;
+ }
+
+ if (cmd->num_hdl > CAM_MEM_MMU_MAX_HANDLE) {
+ pr_err("Num of mmu hdl exceeded maximum(%d)\n",
+ CAM_MEM_MMU_MAX_HANDLE);
+ return -EINVAL;
+ }
+
+ if (cmd->flags & CAM_MEM_FLAG_PROTECTED_MODE &&
+ cmd->flags & CAM_MEM_FLAG_KMD_ACCESS) {
+ pr_err("Kernel mapping in secure mode not allowed");
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int cam_mem_util_check_map_flags(struct cam_mem_mgr_map_cmd *cmd)
+{
+ if (!cmd->flags) {
+ pr_err("Invalid flags\n");
+ return -EINVAL;
+ }
+
+ if (cmd->num_hdl > CAM_MEM_MMU_MAX_HANDLE) {
+ pr_err("Num of mmu hdl exceeded maximum(%d)\n",
+ CAM_MEM_MMU_MAX_HANDLE);
+ return -EINVAL;
+ }
+
+ if (cmd->flags & CAM_MEM_FLAG_PROTECTED_MODE &&
+ cmd->flags & CAM_MEM_FLAG_KMD_ACCESS) {
+ pr_err("Kernel mapping in secure mode not allowed");
+ return -EINVAL;
+ }
+
+ if (cmd->flags & CAM_MEM_FLAG_HW_SHARED_ACCESS) {
+ pr_err("Shared memory buffers are not allowed to be mapped\n");
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int cam_mem_util_map_hw_va(uint32_t flags,
+ int32_t *mmu_hdls,
+ int32_t num_hdls,
+ int fd,
+ dma_addr_t *hw_vaddr,
+ size_t *len,
+ enum cam_smmu_region_id region)
+{
+ int i;
+ int rc = -1;
+ int dir = cam_mem_util_get_dma_dir(flags);
+
+ if (dir < 0) {
+ pr_err("fail to map DMA direction\n");
+ return dir;
+ }
+
+ if (flags & CAM_MEM_FLAG_PROTECTED_MODE) {
+ for (i = 0; i < num_hdls; i++) {
+ rc = cam_smmu_map_sec_iova(mmu_hdls[i],
+ fd,
+ dir,
+ (dma_addr_t *)hw_vaddr,
+ len);
+
+ if (rc < 0) {
+ pr_err("Failed to securely map to smmu");
+ goto multi_map_fail;
+ }
+ }
+ } else {
+ for (i = 0; i < num_hdls; i++) {
+ rc = cam_smmu_map_iova(mmu_hdls[i],
+ fd,
+ dir,
+ (dma_addr_t *)hw_vaddr,
+ len,
+ region);
+
+ if (rc < 0) {
+ pr_err("Failed to map to smmu");
+ goto multi_map_fail;
+ }
+ }
+ }
+
+ return rc;
+multi_map_fail:
+ if (flags & CAM_MEM_FLAG_PROTECTED_MODE)
+ for (--i; i > 0; i--)
+ cam_smmu_unmap_sec_iova(mmu_hdls[i], fd);
+ else
+ for (--i; i > 0; i--)
+ cam_smmu_unmap_iova(mmu_hdls[i],
+ fd,
+ CAM_SMMU_REGION_IO);
+ return rc;
+
+}
+
+int cam_mem_mgr_alloc_and_map(struct cam_mem_mgr_alloc_cmd *cmd)
+{
+ int rc;
+ int32_t idx;
+ struct ion_handle *ion_hdl;
+ int ion_fd;
+ dma_addr_t hw_vaddr = 0;
+ size_t len;
+
+ if (!cmd) {
+ pr_err(" Invalid argument\n");
+ return -EINVAL;
+ }
+ len = cmd->len;
+
+ rc = cam_mem_util_check_flags(cmd);
+ if (rc) {
+ pr_err("Invalid flags: flags = %X\n", cmd->flags);
+ return rc;
+ }
+
+ rc = cam_mem_util_ion_alloc(cmd,
+ &ion_hdl,
+ &ion_fd);
+ if (rc) {
+ pr_err("Ion allocation failed\n");
+ return rc;
+ }
+
+ idx = cam_mem_get_slot();
+ if (idx < 0) {
+ rc = -ENOMEM;
+ goto slot_fail;
+ }
+
+ if (cmd->flags & CAM_MEM_FLAG_HW_READ_WRITE ||
+ cmd->flags & CAM_MEM_FLAG_HW_SHARED_ACCESS) {
+
+ enum cam_smmu_region_id region;
+
+ if (cmd->flags & CAM_MEM_FLAG_HW_READ_WRITE)
+ region = CAM_SMMU_REGION_IO;
+
+
+ if (cmd->flags & CAM_MEM_FLAG_HW_SHARED_ACCESS)
+ region = CAM_SMMU_REGION_SHARED;
+
+ rc = cam_mem_util_map_hw_va(cmd->flags,
+ cmd->mmu_hdls,
+ cmd->num_hdl,
+ ion_fd,
+ &hw_vaddr,
+ &len,
+ region);
+ if (rc)
+ goto map_hw_fail;
+ }
+
+ mutex_lock(&tbl.bufq[idx].q_lock);
+ tbl.bufq[idx].fd = ion_fd;
+ tbl.bufq[idx].flags = cmd->flags;
+ tbl.bufq[idx].buf_handle = GET_MEM_HANDLE(idx, ion_fd);
+ tbl.bufq[idx].kmdvaddr = 0;
+
+ if (cmd->num_hdl > 0)
+ tbl.bufq[idx].vaddr = hw_vaddr;
+ else
+ tbl.bufq[idx].vaddr = 0;
+
+ tbl.bufq[idx].i_hdl = ion_hdl;
+ tbl.bufq[idx].len = cmd->len;
+ tbl.bufq[idx].num_hdl = cmd->num_hdl;
+ memcpy(tbl.bufq[idx].hdls, cmd->mmu_hdls,
+ sizeof(int32_t) * cmd->num_hdl);
+ tbl.bufq[idx].is_imported = false;
+ mutex_unlock(&tbl.bufq[idx].q_lock);
+
+ cmd->out.buf_handle = tbl.bufq[idx].buf_handle;
+ cmd->out.fd = tbl.bufq[idx].fd;
+ cmd->out.vaddr = 0;
+
+ CDBG("buf handle: %x, fd: %d, len: %zu\n",
+ cmd->out.buf_handle, cmd->out.fd,
+ tbl.bufq[idx].len);
+
+ return rc;
+
+map_hw_fail:
+ cam_mem_put_slot(idx);
+slot_fail:
+ ion_free(tbl.client, ion_hdl);
+ return rc;
+}
+
+int cam_mem_mgr_map(struct cam_mem_mgr_map_cmd *cmd)
+{
+ int32_t idx;
+ int rc;
+ struct ion_handle *ion_hdl;
+ dma_addr_t hw_vaddr = 0;
+ size_t len = 0;
+
+ if (!cmd || (cmd->fd < 0)) {
+ pr_err("Invalid argument\n");
+ return -EINVAL;
+ }
+
+ if (cmd->num_hdl > CAM_MEM_MMU_MAX_HANDLE)
+ return -EINVAL;
+
+ rc = cam_mem_util_check_map_flags(cmd);
+ if (rc) {
+ pr_err("Invalid flags: flags = %X\n", cmd->flags);
+ return rc;
+ }
+
+ ion_hdl = ion_import_dma_buf_fd(tbl.client, cmd->fd);
+ if (IS_ERR_OR_NULL((void *)(ion_hdl))) {
+ pr_err("Failed to import ion fd\n");
+ return -EINVAL;
+ }
+
+ if (cmd->flags & CAM_MEM_FLAG_HW_READ_WRITE) {
+ rc = cam_mem_util_map_hw_va(cmd->flags,
+ cmd->mmu_hdls,
+ cmd->num_hdl,
+ cmd->fd,
+ &hw_vaddr,
+ &len,
+ CAM_SMMU_REGION_IO);
+ if (rc)
+ goto map_fail;
+ }
+
+ idx = cam_mem_get_slot();
+ if (idx < 0) {
+ rc = -ENOMEM;
+ goto map_fail;
+ }
+
+ mutex_lock(&tbl.bufq[idx].q_lock);
+ tbl.bufq[idx].fd = cmd->fd;
+ tbl.bufq[idx].flags = cmd->flags;
+ tbl.bufq[idx].buf_handle = GET_MEM_HANDLE(idx, cmd->fd);
+ tbl.bufq[idx].kmdvaddr = 0;
+
+ if (cmd->num_hdl > 0)
+ tbl.bufq[idx].vaddr = hw_vaddr;
+ else
+ tbl.bufq[idx].vaddr = 0;
+
+ tbl.bufq[idx].i_hdl = ion_hdl;
+ tbl.bufq[idx].len = len;
+ tbl.bufq[idx].num_hdl = cmd->num_hdl;
+ memcpy(tbl.bufq[idx].hdls, cmd->mmu_hdls,
+ sizeof(int32_t) * cmd->num_hdl);
+ tbl.bufq[idx].is_imported = true;
+ mutex_unlock(&tbl.bufq[idx].q_lock);
+
+ cmd->out.buf_handle = tbl.bufq[idx].buf_handle;
+ cmd->out.vaddr = 0;
+
+ return rc;
+
+map_fail:
+ ion_free(tbl.client, ion_hdl);
+ return rc;
+}
+
+static int cam_mem_util_unmap_hw_va(int32_t idx,
+ enum cam_smmu_region_id region)
+{
+ int i;
+ uint32_t flags;
+ int32_t *mmu_hdls;
+ int num_hdls;
+ int fd;
+ int rc = -EINVAL;
+
+ if (idx >= CAM_MEM_BUFQ_MAX || idx <= 0) {
+ pr_err("Incorrect index\n");
+ return rc;
+ }
+
+ flags = tbl.bufq[idx].flags;
+ mmu_hdls = tbl.bufq[idx].hdls;
+ num_hdls = tbl.bufq[idx].num_hdl;
+ fd = tbl.bufq[idx].fd;
+
+ if (flags & CAM_MEM_FLAG_PROTECTED_MODE) {
+ for (i = 0; i < num_hdls; i++) {
+ rc = cam_smmu_unmap_sec_iova(mmu_hdls[i], fd);
+ if (rc < 0)
+ goto unmap_end;
+ }
+ } else {
+ for (i = 0; i < num_hdls; i++) {
+ rc = cam_smmu_unmap_iova(mmu_hdls[i],
+ fd,
+ region);
+ if (rc < 0)
+ goto unmap_end;
+ }
+ }
+
+unmap_end:
+ return rc;
+}
+
+static int cam_mem_util_unmap(int32_t idx)
+{
+ int rc = 0;
+ enum cam_smmu_region_id region;
+
+ if (idx >= CAM_MEM_BUFQ_MAX || idx <= 0) {
+ pr_err("Incorrect index\n");
+ return -EINVAL;
+ }
+
+ CDBG("Flags = %X\n", tbl.bufq[idx].flags);
+
+ if (tbl.bufq[idx].flags & CAM_MEM_FLAG_KMD_ACCESS)
+ if (tbl.bufq[idx].i_hdl && tbl.bufq[idx].kmdvaddr)
+ ion_unmap_kernel(tbl.client, tbl.bufq[idx].i_hdl);
+
+ if (tbl.bufq[idx].flags & CAM_MEM_FLAG_HW_READ_WRITE)
+ region = CAM_SMMU_REGION_IO;
+
+ if (tbl.bufq[idx].flags & CAM_MEM_FLAG_HW_SHARED_ACCESS)
+ region = CAM_SMMU_REGION_SHARED;
+
+ rc = cam_mem_util_unmap_hw_va(idx,
+ region);
+
+ mutex_lock(&tbl.bufq[idx].q_lock);
+ tbl.bufq[idx].flags = 0;
+ tbl.bufq[idx].buf_handle = -1;
+ tbl.bufq[idx].vaddr = 0;
+ memset(tbl.bufq[idx].hdls, 0,
+ sizeof(int32_t) * CAM_MEM_MMU_MAX_HANDLE);
+
+ CDBG("Ion handle at idx = %d freeing = %pK, fd = %d\n",
+ idx, tbl.bufq[idx].i_hdl, tbl.bufq[idx].fd);
+
+ if (tbl.bufq[idx].i_hdl && !tbl.bufq[idx].is_imported) {
+ CDBG("Freeing up non-imported buffer at fd = %d, hdl = %pK",
+ tbl.bufq[idx].fd,
+ tbl.bufq[idx].i_hdl);
+ ion_free(tbl.client, tbl.bufq[idx].i_hdl);
+ tbl.bufq[idx].i_hdl = NULL;
+ } else {
+ CDBG("Not freeing up imported buffer at fd = %d",
+ tbl.bufq[idx].fd);
+ }
+
+ tbl.bufq[idx].fd = -1;
+ tbl.bufq[idx].is_imported = false;
+ tbl.bufq[idx].i_hdl = NULL;
+ tbl.bufq[idx].len = 0;
+ tbl.bufq[idx].num_hdl = 0;
+ mutex_unlock(&tbl.bufq[idx].q_lock);
+ cam_mem_put_slot(idx);
+
+ return rc;
+}
+
+int cam_mem_mgr_release(struct cam_mem_mgr_release_cmd *cmd)
+{
+ int idx;
+ int rc;
+
+ if (!cmd) {
+ pr_err("Invalid argument\n");
+ return -EINVAL;
+ }
+
+ idx = CAM_MEM_MGR_GET_HDL_IDX(cmd->buf_handle);
+ if (idx >= CAM_MEM_BUFQ_MAX || idx <= 0) {
+ pr_err("Incorrect index extracted from mem handle\n");
+ return -EINVAL;
+ }
+
+ if (!tbl.bufq[idx].active) {
+ pr_err("Released buffer state should be active\n");
+ return -EINVAL;
+ }
+
+ if (tbl.bufq[idx].buf_handle != cmd->buf_handle) {
+ pr_err("Released buf handle not matching within table\n");
+ return -EINVAL;
+ }
+
+ CDBG("Releasing hdl = %u\n", cmd->buf_handle);
+ rc = cam_mem_util_unmap(idx);
+
+ return rc;
+}
+
+int cam_mem_mgr_request_mem(struct cam_mem_mgr_request_desc *inp,
+ struct cam_mem_mgr_memory_desc *out)
+{
+ struct ion_handle *hdl;
+ int ion_fd;
+ int rc = 0;
+ uint32_t heap_id;
+ int32_t ion_flag = 0;
+ uint64_t kvaddr;
+ dma_addr_t iova = 0;
+ size_t request_len = 0;
+ int32_t idx;
+ uint32_t mem_handle;
+ int32_t smmu_hdl = 0;
+ int32_t num_hdl = 0;
+ enum cam_smmu_region_id region;
+
+ if (!inp || !out) {
+ pr_err("Invalid params\n");
+ return -EINVAL;
+ }
+
+ if (inp->region != CAM_MEM_MGR_REGION_SHARED &&
+ inp->region != CAM_MEM_MGR_REGION_NON_SECURE_IO) {
+ pr_err("Invalid flags for request mem\n");
+ return -EINVAL;
+ }
+
+ if (inp->flags & CAM_MEM_FLAG_CACHE)
+ ion_flag |= ION_FLAG_CACHED;
+ else
+ ion_flag &= ~ION_FLAG_CACHED;
+
+ heap_id = ION_HEAP(ION_SYSTEM_HEAP_ID);
+
+ rc = cam_mem_util_get_ion_buffer(inp->size,
+ inp->align,
+ heap_id,
+ ion_flag,
+ &hdl,
+ &ion_fd);
+
+ if (rc) {
+ pr_err("ION alloc failed for shared buffer\n");
+ goto ion_fail;
+ } else {
+ CDBG("Got ION fd = %d, hdl = %pK\n", ion_fd, hdl);
+ }
+
+ rc = cam_mem_util_map_cpu_va(hdl, &kvaddr, &request_len);
+ if (rc) {
+ pr_err("Failed to get kernel vaddr\n");
+ goto map_fail;
+ }
+
+ if (!inp->smmu_hdl) {
+ pr_err("Invalid SMMU handle\n");
+ rc = -EINVAL;
+ goto smmu_fail;
+ }
+
+ if (inp->region == CAM_MEM_MGR_REGION_SHARED)
+ region = CAM_SMMU_REGION_SHARED;
+
+ if (inp->region == CAM_MEM_MGR_REGION_NON_SECURE_IO)
+ region = CAM_SMMU_REGION_IO;
+
+ rc = cam_smmu_map_iova(inp->smmu_hdl,
+ ion_fd,
+ CAM_SMMU_MAP_RW,
+ &iova,
+ &request_len,
+ region);
+
+ if (rc < 0) {
+ pr_err("SMMU mapping failed\n");
+ goto smmu_fail;
+ }
+
+ smmu_hdl = inp->smmu_hdl;
+ num_hdl = 1;
+
+ idx = cam_mem_get_slot();
+ if (idx < 0) {
+ rc = -ENOMEM;
+ goto slot_fail;
+ }
+
+ mutex_lock(&tbl.bufq[idx].q_lock);
+ mem_handle = GET_MEM_HANDLE(idx, ion_fd);
+ tbl.bufq[idx].fd = ion_fd;
+ tbl.bufq[idx].flags = inp->flags;
+ tbl.bufq[idx].buf_handle = mem_handle;
+ tbl.bufq[idx].kmdvaddr = kvaddr;
+
+ tbl.bufq[idx].vaddr = iova;
+
+ tbl.bufq[idx].i_hdl = hdl;
+ tbl.bufq[idx].len = inp->size;
+ tbl.bufq[idx].num_hdl = num_hdl;
+ memcpy(tbl.bufq[idx].hdls, &smmu_hdl,
+ sizeof(int32_t));
+ tbl.bufq[idx].is_imported = false;
+ mutex_unlock(&tbl.bufq[idx].q_lock);
+
+ out->kva = kvaddr;
+ out->iova = (uint32_t)iova;
+ out->smmu_hdl = smmu_hdl;
+ out->mem_handle = mem_handle;
+ out->len = inp->size;
+ out->region = inp->region;
+
+ return rc;
+slot_fail:
+ cam_smmu_unmap_iova(inp->smmu_hdl,
+ ion_fd,
+ inp->region);
+smmu_fail:
+ ion_unmap_kernel(tbl.client, hdl);
+map_fail:
+ ion_free(tbl.client, hdl);
+ion_fail:
+ return rc;
+}
+EXPORT_SYMBOL(cam_mem_mgr_request_mem);
+
+int cam_mem_mgr_release_mem(struct cam_mem_mgr_memory_desc *inp)
+{
+ int32_t idx;
+ int rc;
+
+ if (!inp) {
+ pr_err("Invalid argument\n");
+ return -EINVAL;
+ }
+
+ idx = CAM_MEM_MGR_GET_HDL_IDX(inp->mem_handle);
+ if (idx >= CAM_MEM_BUFQ_MAX || idx <= 0) {
+ pr_err("Incorrect index extracted from mem handle\n");
+ return -EINVAL;
+ }
+
+ if (!tbl.bufq[idx].active) {
+ pr_err("Released buffer state should be active\n");
+ return -EINVAL;
+ }
+
+ if (tbl.bufq[idx].buf_handle != inp->mem_handle) {
+ pr_err("Released buf handle not matching within table\n");
+ return -EINVAL;
+ }
+
+ CDBG("Releasing hdl = %X\n", inp->mem_handle);
+ rc = cam_mem_util_unmap(idx);
+
+ return rc;
+}
+EXPORT_SYMBOL(cam_mem_mgr_release_mem);
diff --git a/drivers/media/platform/msm/camera/cam_req_mgr/cam_mem_mgr.h b/drivers/media/platform/msm/camera/cam_req_mgr/cam_mem_mgr.h
new file mode 100644
index 0000000..c5f839b
--- /dev/null
+++ b/drivers/media/platform/msm/camera/cam_req_mgr/cam_mem_mgr.h
@@ -0,0 +1,121 @@
+/* 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.
+ */
+
+#ifndef _CAM_MEM_MGR_H_
+#define _CAM_MEM_MGR_H_
+
+#include <media/cam_req_mgr.h>
+#include "cam_mem_mgr_api.h"
+
+#define CAM_MEM_BUFQ_MAX 1024
+
+/**
+ * struct cam_mem_buf_queue
+ *
+ * @i_hdl: ion handle for the buffer
+ * @q_lock: mutex lock for buffer
+ * @hdls: list of mapped handles
+ * @num_hdl: number of handles
+ * @fd: file descriptor of buffer
+ * @buf_handle: unique handle for buffer
+ * @align: alignment for allocation
+ * @len: size of buffer
+ * @flags: attributes of buffer
+ * @vaddr: IOVA of buffer
+ * @kmdvaddr: Kernel virtual address
+ * @active: state of the buffer
+ * @is_imported: Flag indicating if buffer is imported from an FD in user space
+ */
+struct cam_mem_buf_queue {
+ struct ion_handle *i_hdl;
+ struct mutex q_lock;
+ int32_t hdls[CAM_MEM_MMU_MAX_HANDLE];
+ int32_t num_hdl;
+ int32_t fd;
+ int32_t buf_handle;
+ int32_t align;
+ size_t len;
+ uint32_t flags;
+ uint64_t vaddr;
+ uint64_t kmdvaddr;
+ bool active;
+ bool is_imported;
+};
+
+/**
+ * struct cam_mem_table
+ *
+ * @m_lock: mutex lock for table
+ * @bitmap: bitmap of the mem mgr utility
+ * @bits: max bits of the utility
+ * @client: ion client pointer
+ * @bufq: array of buffers
+ */
+struct cam_mem_table {
+ struct mutex m_lock;
+ void *bitmap;
+ size_t bits;
+ struct ion_client *client;
+ struct cam_mem_buf_queue bufq[CAM_MEM_BUFQ_MAX];
+};
+
+/**
+ * @brief: Allocates and maps buffer
+ *
+ * @cmd: Allocation information
+ *
+ * @return Status of operation. Negative in case of error. Zero otherwise.
+ */
+int cam_mem_mgr_alloc_and_map(struct cam_mem_mgr_alloc_cmd *cmd);
+
+/**
+ * @brief: Releases a buffer reference
+ *
+ * @cmd: Buffer release information
+ *
+ * @return Status of operation. Negative in case of error. Zero otherwise.
+ */
+int cam_mem_mgr_release(struct cam_mem_mgr_release_cmd *cmd);
+
+/**
+ * @brief Maps a buffer
+ *
+ * @cmd: Buffer mapping information
+ *
+ * @return Status of operation. Negative in case of error. Zero otherwise.
+ */
+int cam_mem_mgr_map(struct cam_mem_mgr_map_cmd *cmd);
+
+/**
+ * @brief: Perform cache ops on the buffer
+ *
+ * @cmd: Cache ops information
+ *
+ * @return Status of operation. Negative in case of error. Zero otherwise.
+ */
+int cam_mem_mgr_cache_ops(struct cam_mem_cache_ops_cmd *cmd);
+
+/**
+ * @brief: Initializes the memory manager
+ *
+ * @return Status of operation. Negative in case of error. Zero otherwise.
+ */
+int cam_mem_mgr_init(void);
+
+/**
+ * @brief: Tears down the memory manager
+ *
+ * @return None
+ */
+void cam_mem_mgr_deinit(void);
+
+#endif /* _CAM_MEM_MGR_H_ */
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
new file mode 100644
index 0000000..32a754e
--- /dev/null
+++ b/drivers/media/platform/msm/camera/cam_req_mgr/cam_mem_mgr_api.h
@@ -0,0 +1,105 @@
+/* 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.
+ */
+
+#ifndef _CAM_MEM_MGR_API_H_
+#define _CAM_MEM_MGR_API_H_
+
+#include <media/cam_req_mgr.h>
+
+/* Region IDs for memory manager */
+#define CAM_MEM_MGR_REGION_FIRMWARE 0
+#define CAM_MEM_MGR_REGION_SHARED 1
+#define CAM_MEM_MGR_REGION_NON_SECURE_IO 2
+#define CAM_MEM_MGR_REGION_SECURE_IO 3
+#define CAM_MEM_MGR_REGION_SCRATCH 4
+
+/**
+ * struct cam_mem_mgr_request_desc
+ *
+ * @size : Size of memory requested for allocation
+ * @align : Alignment of requested memory
+ * @smmu_hdl: SMMU handle to identify context bank where memory will be mapped
+ * @flags : Flags to indicate cached/uncached property
+ * @region : Region where memory should be allocated
+ */
+struct cam_mem_mgr_request_desc {
+ uint64_t size;
+ uint64_t align;
+ int32_t smmu_hdl;
+ uint32_t flags;
+ uint32_t region;
+};
+
+/**
+ * struct cam_mem_mgr_memory_desc
+ *
+ * @kva : Kernel virtual address of allocated memory
+ * @iova : IOVA of allocated memory
+ * @smmu_hdl : SMMU handle of allocated memory
+ * @mem_handle : Mem handle identifying allocated memory
+ * @len : Length of allocated memory
+ * @region : Region to which allocated memory belongs
+ */
+struct cam_mem_mgr_memory_desc {
+ uint64_t kva;
+ uint32_t iova;
+ int32_t smmu_hdl;
+ uint32_t mem_handle;
+ uint64_t len;
+ uint32_t region;
+};
+
+/**
+ * @brief: Requests a memory buffer
+ *
+ * @inp: Information specifying requested buffer properties
+ * @out: Information about allocated buffer
+ *
+ * @return Status of operation. Negative in case of error. Zero otherwise.
+ */
+int cam_mem_mgr_request_mem(struct cam_mem_mgr_request_desc *inp,
+ struct cam_mem_mgr_memory_desc *out);
+
+/**
+ * @brief: Releases a memory buffer
+ *
+ * @inp: Information specifying buffer to be released
+ *
+ * @return Status of operation. Negative in case of error. Zero otherwise.
+ */
+int cam_mem_mgr_release_mem(struct cam_mem_mgr_memory_desc *inp);
+
+/**
+ * @brief: Returns IOVA information about buffer
+ *
+ * @buf_handle: Handle of the buffer
+ * @mmu_handle: SMMU handle where buffer is mapped
+ * @iova_ptr : Pointer to mmu's iova
+ * @len_ptr : Length of the buffer
+ *
+ * @return Status of operation. Negative in case of error. Zero otherwise.
+ */
+int cam_mem_get_io_buf(int32_t buf_handle, int32_t mmu_handle,
+ uint64_t *iova_ptr, size_t *len_ptr);
+/**
+ * @brief: Returns CPU address information about buffer
+ *
+ * @buf_handle: Handle for the buffer
+ * @vaddr_ptr : pointer to kernel virtual address
+ * @len_ptr : Length of the buffer
+ *
+ * @return Status of operation. Negative in case of error. Zero otherwise.
+ */
+int cam_mem_get_cpu_buf(int32_t buf_handle, uint64_t *vaddr_ptr,
+ size_t *len);
+
+#endif /* _CAM_MEM_MGR_API_H_ */
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 f3af1bd..43b020c6 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
@@ -1,4 +1,4 @@
-/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2016-2017, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -24,6 +24,7 @@
#include "cam_req_mgr_util.h"
#include "cam_req_mgr_core.h"
#include "cam_subdev.h"
+#include "cam_mem_mgr.h"
#define CAM_REQ_MGR_EVENT_MAX 30
@@ -115,7 +116,18 @@
spin_unlock_bh(&g_dev.cam_eventq_lock);
g_dev.open_cnt++;
+ rc = cam_mem_mgr_init();
+ if (rc) {
+ g_dev.open_cnt--;
+ pr_err("mem mgr init failed\n");
+ goto mem_mgr_init_fail;
+ }
+ mutex_unlock(&g_dev.cam_lock);
+ return rc;
+
+mem_mgr_init_fail:
+ v4l2_fh_release(filep);
end:
mutex_unlock(&g_dev.cam_lock);
return rc;
@@ -154,6 +166,7 @@
spin_unlock_bh(&g_dev.cam_eventq_lock);
cam_req_mgr_util_free_hdls();
+ cam_mem_mgr_deinit();
mutex_unlock(&g_dev.cam_lock);
return 0;
@@ -316,6 +329,84 @@
rc = cam_req_mgr_sync_mode(&sync_mode);
}
break;
+ case CAM_REQ_MGR_ALLOC_BUF: {
+ struct cam_mem_mgr_alloc_cmd cmd;
+
+ if (k_ioctl->size != sizeof(cmd))
+ return -EINVAL;
+
+ if (copy_from_user(&cmd,
+ (void *)k_ioctl->handle,
+ k_ioctl->size)) {
+ rc = -EFAULT;
+ break;
+ }
+
+ rc = cam_mem_mgr_alloc_and_map(&cmd);
+ if (!rc)
+ if (copy_to_user((void *)k_ioctl->handle,
+ &cmd, k_ioctl->size)) {
+ rc = -EFAULT;
+ break;
+ }
+ }
+ break;
+ case CAM_REQ_MGR_MAP_BUF: {
+ struct cam_mem_mgr_map_cmd cmd;
+
+ if (k_ioctl->size != sizeof(cmd))
+ return -EINVAL;
+
+ if (copy_from_user(&cmd,
+ (void *)k_ioctl->handle,
+ k_ioctl->size)) {
+ rc = -EFAULT;
+ break;
+ }
+
+ rc = cam_mem_mgr_map(&cmd);
+ if (!rc)
+ if (copy_to_user((void *)k_ioctl->handle,
+ &cmd, k_ioctl->size)) {
+ rc = -EFAULT;
+ break;
+ }
+ }
+ break;
+ case CAM_REQ_MGR_RELEASE_BUF: {
+ struct cam_mem_mgr_release_cmd cmd;
+
+ if (k_ioctl->size != sizeof(cmd))
+ return -EINVAL;
+
+ if (copy_from_user(&cmd,
+ (void *)k_ioctl->handle,
+ k_ioctl->size)) {
+ rc = -EFAULT;
+ break;
+ }
+
+ rc = cam_mem_mgr_release(&cmd);
+ }
+ break;
+ case CAM_REQ_MGR_CACHE_OPS: {
+ struct cam_mem_cache_ops_cmd cmd;
+
+ if (k_ioctl->size != sizeof(cmd))
+ return -EINVAL;
+
+ if (copy_from_user(&cmd,
+ (void *)k_ioctl->handle,
+ k_ioctl->size)) {
+ rc = -EFAULT;
+ break;
+ }
+
+ rc = cam_mem_mgr_cache_ops(&cmd);
+ if (rc)
+ rc = -EINVAL;
+ }
+ break;
default:
return -ENOIOCTLCMD;
}
@@ -444,6 +535,7 @@
static int cam_req_mgr_remove(struct platform_device *pdev)
{
cam_req_mgr_core_device_deinit();
+ cam_mem_mgr_deinit();
cam_req_mgr_util_deinit();
cam_media_device_cleanup();
cam_video_device_cleanup();
@@ -482,6 +574,12 @@
goto req_mgr_util_fail;
}
+ rc = cam_mem_mgr_init();
+ if (rc) {
+ pr_err("mem mgr init failed\n");
+ goto mem_mgr_init_fail;
+ }
+
rc = cam_req_mgr_core_device_init();
if (rc) {
pr_err("core device setup failed\n");
@@ -493,8 +591,12 @@
return rc;
req_mgr_core_fail:
+ cam_mem_mgr_deinit();
+mem_mgr_init_fail:
cam_req_mgr_util_deinit();
req_mgr_util_fail:
+ mutex_destroy(&g_dev.dev_lock);
+ mutex_destroy(&g_dev.cam_lock);
cam_video_device_cleanup();
video_setup_fail:
cam_media_device_cleanup();
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 4f75a19..019a775 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
@@ -28,25 +28,34 @@
#endif
static struct cam_req_mgr_util_hdl_tbl *hdl_tbl;
-static struct mutex hdl_tbl_mutex = __MUTEX_INITIALIZER(hdl_tbl_mutex);
+static DEFINE_SPINLOCK(hdl_tbl_lock);
int cam_req_mgr_util_init(void)
{
int rc = 0;
int bitmap_size;
+ static struct cam_req_mgr_util_hdl_tbl *hdl_tbl_local;
- mutex_lock(&hdl_tbl_mutex);
if (hdl_tbl) {
rc = -EINVAL;
pr_err("Hdl_tbl is already present\n");
goto hdl_tbl_check_failed;
}
- hdl_tbl = kzalloc(sizeof(*hdl_tbl), GFP_KERNEL);
- if (!hdl_tbl) {
+ hdl_tbl_local = kzalloc(sizeof(*hdl_tbl), GFP_KERNEL);
+ if (!hdl_tbl_local) {
rc = -ENOMEM;
goto hdl_tbl_alloc_failed;
}
+ spin_lock_bh(&hdl_tbl_lock);
+ if (hdl_tbl) {
+ spin_unlock_bh(&hdl_tbl_lock);
+ rc = -EEXIST;
+ kfree(hdl_tbl_local);
+ goto hdl_tbl_check_failed;
+ }
+ hdl_tbl = hdl_tbl_local;
+ spin_unlock_bh(&hdl_tbl_lock);
bitmap_size = BITS_TO_LONGS(CAM_REQ_MGR_MAX_HANDLES) * sizeof(long);
hdl_tbl->bitmap = kzalloc(sizeof(bitmap_size), GFP_KERNEL);
@@ -55,7 +64,6 @@
goto bitmap_alloc_fail;
}
hdl_tbl->bits = bitmap_size * BITS_PER_BYTE;
- mutex_unlock(&hdl_tbl_mutex);
return rc;
@@ -64,16 +72,15 @@
hdl_tbl = NULL;
hdl_tbl_alloc_failed:
hdl_tbl_check_failed:
- mutex_unlock(&hdl_tbl_mutex);
return rc;
}
int cam_req_mgr_util_deinit(void)
{
- mutex_lock(&hdl_tbl_mutex);
+ spin_lock_bh(&hdl_tbl_lock);
if (!hdl_tbl) {
pr_err("Hdl tbl is NULL\n");
- mutex_unlock(&hdl_tbl_mutex);
+ spin_unlock_bh(&hdl_tbl_lock);
return -EINVAL;
}
@@ -81,7 +88,7 @@
hdl_tbl->bitmap = NULL;
kfree(hdl_tbl);
hdl_tbl = NULL;
- mutex_unlock(&hdl_tbl_mutex);
+ spin_unlock_bh(&hdl_tbl_lock);
return 0;
}
@@ -90,10 +97,10 @@
{
int i = 0;
- mutex_lock(&hdl_tbl_mutex);
+ spin_lock_bh(&hdl_tbl_lock);
if (!hdl_tbl) {
pr_err("Hdl tbl is NULL\n");
- mutex_unlock(&hdl_tbl_mutex);
+ spin_unlock_bh(&hdl_tbl_lock);
return -EINVAL;
}
@@ -107,7 +114,7 @@
}
}
bitmap_zero(hdl_tbl->bitmap, CAM_REQ_MGR_MAX_HANDLES);
- mutex_unlock(&hdl_tbl_mutex);
+ spin_unlock_bh(&hdl_tbl_lock);
return 0;
}
@@ -132,17 +139,17 @@
int rand = 0;
int32_t handle = 0;
- mutex_lock(&hdl_tbl_mutex);
+ spin_lock_bh(&hdl_tbl_lock);
if (!hdl_tbl) {
pr_err("Hdl tbl is NULL\n");
- mutex_unlock(&hdl_tbl_mutex);
+ spin_unlock_bh(&hdl_tbl_lock);
return -EINVAL;
}
idx = cam_get_free_handle_index();
if (idx < 0) {
pr_err("Unable to create session handle\n");
- mutex_unlock(&hdl_tbl_mutex);
+ spin_unlock_bh(&hdl_tbl_lock);
return idx;
}
@@ -154,7 +161,7 @@
hdl_tbl->hdl[idx].state = HDL_ACTIVE;
hdl_tbl->hdl[idx].priv = priv;
hdl_tbl->hdl[idx].ops = NULL;
- mutex_unlock(&hdl_tbl_mutex);
+ spin_unlock_bh(&hdl_tbl_lock);
return handle;
}
@@ -165,17 +172,17 @@
int rand = 0;
int32_t handle;
- mutex_lock(&hdl_tbl_mutex);
+ spin_lock_bh(&hdl_tbl_lock);
if (!hdl_tbl) {
pr_err("Hdl tbl is NULL\n");
- mutex_unlock(&hdl_tbl_mutex);
+ spin_unlock_bh(&hdl_tbl_lock);
return -EINVAL;
}
idx = cam_get_free_handle_index();
if (idx < 0) {
pr_err("Unable to create device handle\n");
- mutex_unlock(&hdl_tbl_mutex);
+ spin_unlock_bh(&hdl_tbl_lock);
return idx;
}
@@ -187,7 +194,7 @@
hdl_tbl->hdl[idx].state = HDL_ACTIVE;
hdl_tbl->hdl[idx].priv = hdl_data->priv;
hdl_tbl->hdl[idx].ops = hdl_data->ops;
- mutex_unlock(&hdl_tbl_mutex);
+ spin_unlock_bh(&hdl_tbl_lock);
return handle;
}
@@ -198,7 +205,7 @@
int type;
void *priv;
- mutex_lock(&hdl_tbl_mutex);
+ spin_lock_bh(&hdl_tbl_lock);
if (!hdl_tbl) {
pr_err("Hdl tbl is NULL\n");
goto device_priv_fail;
@@ -227,12 +234,12 @@
}
priv = hdl_tbl->hdl[idx].priv;
- mutex_unlock(&hdl_tbl_mutex);
+ spin_unlock_bh(&hdl_tbl_lock);
return priv;
device_priv_fail:
- mutex_unlock(&hdl_tbl_mutex);
+ spin_unlock_bh(&hdl_tbl_lock);
return NULL;
}
@@ -242,7 +249,7 @@
int type;
void *ops;
- mutex_lock(&hdl_tbl_mutex);
+ spin_lock_bh(&hdl_tbl_lock);
if (!hdl_tbl) {
pr_err("Hdl tbl is NULL\n");
goto device_ops_fail;
@@ -271,12 +278,12 @@
}
ops = hdl_tbl->hdl[idx].ops;
- mutex_unlock(&hdl_tbl_mutex);
+ spin_unlock_bh(&hdl_tbl_lock);
return ops;
device_ops_fail:
- mutex_unlock(&hdl_tbl_mutex);
+ spin_unlock_bh(&hdl_tbl_lock);
return NULL;
}
@@ -285,7 +292,7 @@
int idx;
int type;
- mutex_lock(&hdl_tbl_mutex);
+ spin_lock_bh(&hdl_tbl_lock);
if (!hdl_tbl) {
pr_err("Hdl tbl is NULL\n");
goto destroy_hdl_fail;
@@ -315,12 +322,12 @@
hdl_tbl->hdl[idx].state = HDL_FREE;
clear_bit(idx, hdl_tbl->bitmap);
- mutex_unlock(&hdl_tbl_mutex);
+ spin_unlock_bh(&hdl_tbl_lock);
return 0;
destroy_hdl_fail:
- mutex_unlock(&hdl_tbl_mutex);
+ spin_unlock_bh(&hdl_tbl_lock);
return -EINVAL;
}
diff --git a/drivers/media/platform/msm/camera/cam_req_mgr/cam_req_mgr_workq.c b/drivers/media/platform/msm/camera/cam_req_mgr/cam_req_mgr_workq.c
index e327723..1f6a97a 100644
--- a/drivers/media/platform/msm/camera/cam_req_mgr/cam_req_mgr_workq.c
+++ b/drivers/media/platform/msm/camera/cam_req_mgr/cam_req_mgr_workq.c
@@ -22,12 +22,16 @@
return NULL;
spin_lock(&workq->task.lock);
+ if (list_empty(&workq->task.empty_head))
+ goto end;
+
task = list_first_entry(&workq->task.empty_head,
struct crm_workq_task, entry);
if (task) {
atomic_sub(1, &workq->task.free_cnt);
list_del_init(&task->entry);
}
+end:
spin_unlock(&workq->task.lock);
return task;
@@ -104,14 +108,14 @@
workq = (struct cam_req_mgr_core_workq *)
container_of(w, struct cam_req_mgr_core_workq, work);
- spin_lock(&workq->task.lock);
list_for_each_entry_safe(task, task_save,
&workq->task.process_head, entry) {
atomic_sub(1, &workq->task.pending_cnt);
+ spin_lock(&workq->task.lock);
list_del_init(&task->entry);
+ spin_unlock(&workq->task.lock);
cam_req_mgr_process_task(task);
}
- spin_unlock(&workq->task.lock);
CRM_DBG("processed task %p free_cnt %d",
task, atomic_read(&workq->task.free_cnt));
}
@@ -138,7 +142,6 @@
goto end;
}
- spin_lock(&workq->task.lock);
if (task->cancel == 1) {
cam_req_mgr_workq_put_task(task);
CRM_WARN("task aborted and queued back to pool");
@@ -146,12 +149,14 @@
spin_unlock(&workq->task.lock);
goto end;
}
+ spin_lock(&workq->task.lock);
list_add_tail(&task->entry,
&workq->task.process_head);
+ spin_unlock(&workq->task.lock);
atomic_add(1, &workq->task.pending_cnt);
CRM_DBG("enq task %p pending_cnt %d",
task, atomic_read(&workq->task.pending_cnt));
- spin_unlock(&workq->task.lock);
+
queue_work(workq->job, &workq->work);
diff --git a/drivers/media/platform/msm/camera/cam_smmu/Makefile b/drivers/media/platform/msm/camera/cam_smmu/Makefile
new file mode 100644
index 0000000..3619da7
--- /dev/null
+++ b/drivers/media/platform/msm/camera/cam_smmu/Makefile
@@ -0,0 +1 @@
+obj-$(CONFIG_SPECTRA_CAMERA) += cam_smmu_api.o
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
new file mode 100644
index 0000000..f4215b5
--- /dev/null
+++ b/drivers/media/platform/msm/camera/cam_smmu/cam_smmu_api.c
@@ -0,0 +1,2284 @@
+/* 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
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#define pr_fmt(fmt) "CAM-SMMU %s:%d " fmt, __func__, __LINE__
+
+#include <linux/module.h>
+#include <linux/dma-buf.h>
+#include <asm/dma-iommu.h>
+#include <linux/dma-direction.h>
+#include <linux/of_platform.h>
+#include <linux/iommu.h>
+#include <linux/slab.h>
+#include <linux/dma-mapping.h>
+#include <linux/msm_dma_iommu_mapping.h>
+#include <linux/workqueue.h>
+#include <linux/genalloc.h>
+
+#include "cam_smmu_api.h"
+
+#define SHARED_MEM_POOL_GRANULARITY 12
+
+#define IOMMU_INVALID_DIR -1
+#define BYTE_SIZE 8
+#define COOKIE_NUM_BYTE 2
+#define COOKIE_SIZE (BYTE_SIZE*COOKIE_NUM_BYTE)
+#define COOKIE_MASK ((1<<COOKIE_SIZE)-1)
+#define HANDLE_INIT (-1)
+#define CAM_SMMU_CB_MAX 2
+
+#define GET_SMMU_HDL(x, y) (((x) << COOKIE_SIZE) | ((y) & COOKIE_MASK))
+#define GET_SMMU_TABLE_IDX(x) (((x) >> COOKIE_SIZE) & COOKIE_MASK)
+
+#ifdef CONFIG_CAM_SMMU_DBG
+#define CDBG(fmt, args...) pr_err(fmt, ##args)
+#else
+#define CDBG(fmt, args...) pr_debug(fmt, ##args)
+#endif
+
+struct firmware_alloc_info {
+ struct device *fw_dev;
+ void *fw_kva;
+ dma_addr_t fw_dma_hdl;
+};
+
+struct firmware_alloc_info icp_fw;
+
+struct cam_smmu_work_payload {
+ int idx;
+ struct iommu_domain *domain;
+ struct device *dev;
+ unsigned long iova;
+ int flags;
+ void *token;
+ struct list_head list;
+};
+
+enum cam_protection_type {
+ CAM_PROT_INVALID,
+ CAM_NON_SECURE,
+ CAM_SECURE,
+ CAM_PROT_MAX,
+};
+
+enum cam_iommu_type {
+ CAM_SMMU_INVALID,
+ CAM_QSMMU,
+ CAM_ARM_SMMU,
+ CAM_SMMU_MAX,
+};
+
+enum cam_smmu_buf_state {
+ CAM_SMMU_BUFF_EXIST,
+ CAM_SMMU_BUFF_NOT_EXIST
+};
+
+enum cam_smmu_init_dir {
+ CAM_SMMU_TABLE_INIT,
+ CAM_SMMU_TABLE_DEINIT,
+};
+
+struct scratch_mapping {
+ void *bitmap;
+ size_t bits;
+ unsigned int order;
+ dma_addr_t base;
+};
+
+struct cam_smmu_region_info {
+ dma_addr_t iova_start;
+ size_t iova_len;
+};
+
+struct cam_context_bank_info {
+ struct device *dev;
+ struct dma_iommu_mapping *mapping;
+ dma_addr_t va_start;
+ size_t va_len;
+ const char *name;
+ bool is_secure;
+ uint8_t scratch_buf_support;
+ uint8_t firmware_support;
+ uint8_t shared_support;
+ uint8_t io_support;
+ bool is_fw_allocated;
+
+ struct scratch_mapping scratch_map;
+ struct gen_pool *shared_mem_pool;
+
+ struct cam_smmu_region_info scratch_info;
+ struct cam_smmu_region_info firmware_info;
+ struct cam_smmu_region_info shared_info;
+ struct cam_smmu_region_info io_info;
+
+ struct list_head smmu_buf_list;
+ struct mutex lock;
+ int handle;
+ enum cam_smmu_ops_param state;
+
+ void (*handler[CAM_SMMU_CB_MAX])(struct iommu_domain *,
+ struct device *, unsigned long,
+ int, void*);
+ void *token[CAM_SMMU_CB_MAX];
+ int cb_count;
+};
+
+struct cam_iommu_cb_set {
+ struct cam_context_bank_info *cb_info;
+ u32 cb_num;
+ u32 cb_init_count;
+ struct work_struct smmu_work;
+ struct mutex payload_list_lock;
+ struct list_head payload_list;
+};
+
+static const struct of_device_id msm_cam_smmu_dt_match[] = {
+ { .compatible = "qcom,msm-cam-smmu", },
+ { .compatible = "qcom,msm-cam-smmu-cb", },
+ { .compatible = "qcom,msm-cam-smmu-fw-dev", },
+ {}
+};
+
+struct cam_dma_buff_info {
+ struct dma_buf *buf;
+ struct dma_buf_attachment *attach;
+ struct sg_table *table;
+ enum dma_data_direction dir;
+ enum cam_smmu_region_id region_id;
+ int iommu_dir;
+ int ref_count;
+ dma_addr_t paddr;
+ struct list_head list;
+ int ion_fd;
+ size_t len;
+ size_t phys_len;
+};
+
+static struct cam_iommu_cb_set iommu_cb_set;
+
+static enum dma_data_direction cam_smmu_translate_dir(
+ enum cam_smmu_map_dir dir);
+
+static int cam_smmu_check_handle_unique(int hdl);
+
+static int cam_smmu_create_iommu_handle(int idx);
+
+static int cam_smmu_create_add_handle_in_table(char *name,
+ int *hdl);
+
+static struct cam_dma_buff_info *cam_smmu_find_mapping_by_ion_index(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);
+
+static int cam_smmu_alloc_scratch_va(struct scratch_mapping *mapping,
+ size_t size,
+ dma_addr_t *iova);
+
+static int cam_smmu_free_scratch_va(struct scratch_mapping *mapping,
+ dma_addr_t addr, size_t size);
+
+static struct cam_dma_buff_info *cam_smmu_find_mapping_by_virt_address(int idx,
+ dma_addr_t virt_addr);
+
+static int cam_smmu_map_buffer_and_add_to_list(int idx, int ion_fd,
+ enum dma_data_direction dma_dir, dma_addr_t *paddr_ptr,
+ size_t *len_ptr,
+ enum cam_smmu_region_id region_id);
+
+static int cam_smmu_alloc_scratch_buffer_add_to_list(int idx,
+ size_t virt_len,
+ size_t phys_len,
+ unsigned int iommu_dir,
+ dma_addr_t *virt_addr);
+
+static int cam_smmu_unmap_buf_and_remove_from_list(
+ struct cam_dma_buff_info *mapping_info, int idx);
+
+static int cam_smmu_free_scratch_buffer_remove_from_list(
+ struct cam_dma_buff_info *mapping_info,
+ int idx);
+
+static void cam_smmu_clean_buffer_list(int idx);
+
+static void cam_smmu_print_list(int idx);
+
+static void cam_smmu_print_table(void);
+
+static int cam_smmu_probe(struct platform_device *pdev);
+
+static void cam_smmu_check_vaddr_in_range(int idx, void *vaddr);
+
+static void cam_smmu_page_fault_work(struct work_struct *work)
+{
+ int j;
+ int idx;
+ struct cam_smmu_work_payload *payload;
+
+ mutex_lock(&iommu_cb_set.payload_list_lock);
+ if (list_empty(&iommu_cb_set.payload_list)) {
+ pr_err("Payload list empty\n");
+ mutex_unlock(&iommu_cb_set.payload_list_lock);
+ return;
+ }
+
+ payload = list_first_entry(&iommu_cb_set.payload_list,
+ struct cam_smmu_work_payload,
+ list);
+ list_del(&payload->list);
+ mutex_unlock(&iommu_cb_set.payload_list_lock);
+
+ /* Dereference the payload to call the handler */
+ idx = payload->idx;
+ mutex_lock(&iommu_cb_set.cb_info[idx].lock);
+ cam_smmu_check_vaddr_in_range(idx, (void *)payload->iova);
+ for (j = 0; j < CAM_SMMU_CB_MAX; j++) {
+ if ((iommu_cb_set.cb_info[idx].handler[j])) {
+ iommu_cb_set.cb_info[idx].handler[j](
+ payload->domain,
+ payload->dev,
+ payload->iova,
+ payload->flags,
+ iommu_cb_set.cb_info[idx].token[j]);
+ }
+ }
+ mutex_unlock(&iommu_cb_set.cb_info[idx].lock);
+ kfree(payload);
+}
+
+static void cam_smmu_print_list(int idx)
+{
+ struct cam_dma_buff_info *mapping;
+
+ pr_err("index = %d\n", idx);
+ list_for_each_entry(mapping,
+ &iommu_cb_set.cb_info[idx].smmu_buf_list, list) {
+ pr_err("ion_fd = %d, paddr= 0x%pK, len = %u, region = %d\n",
+ mapping->ion_fd, (void *)mapping->paddr,
+ (unsigned int)mapping->len,
+ mapping->region_id);
+ }
+}
+
+static void cam_smmu_print_table(void)
+{
+ int i;
+
+ for (i = 0; i < iommu_cb_set.cb_num; i++) {
+ pr_err("i= %d, handle= %d, name_addr=%pK\n", i,
+ (int)iommu_cb_set.cb_info[i].handle,
+ (void *)iommu_cb_set.cb_info[i].name);
+ pr_err("dev = %pK\n", iommu_cb_set.cb_info[i].dev);
+ }
+}
+
+static void cam_smmu_check_vaddr_in_range(int idx, void *vaddr)
+{
+ struct cam_dma_buff_info *mapping;
+ unsigned long start_addr, end_addr, current_addr;
+
+ current_addr = (unsigned long)vaddr;
+ list_for_each_entry(mapping,
+ &iommu_cb_set.cb_info[idx].smmu_buf_list, list) {
+ start_addr = (unsigned long)mapping->paddr;
+ end_addr = (unsigned long)mapping->paddr + mapping->len;
+
+ if (start_addr <= current_addr && current_addr < end_addr) {
+ pr_err("va %pK valid: range:%pK-%pK, fd = %d cb: %s\n",
+ vaddr, (void *)start_addr, (void *)end_addr,
+ mapping->ion_fd,
+ iommu_cb_set.cb_info[idx].name);
+ goto end;
+ } else {
+ CDBG("va %pK is not in this range: %pK-%pK, fd = %d\n",
+ vaddr, (void *)start_addr, (void *)end_addr,
+ mapping->ion_fd);
+ }
+ }
+ pr_err("Cannot find vaddr:%pK in SMMU %s uses invalid virt address\n",
+ vaddr, iommu_cb_set.cb_info[idx].name);
+end:
+ return;
+}
+
+void cam_smmu_reg_client_page_fault_handler(int handle,
+ void (*client_page_fault_handler)(struct iommu_domain *,
+ struct device *, unsigned long,
+ int, void*), void *token)
+{
+ int idx, i = 0;
+
+ if (!token || (handle == HANDLE_INIT)) {
+ pr_err("Error: token is NULL or invalid handle\n");
+ return;
+ }
+
+ idx = GET_SMMU_TABLE_IDX(handle);
+ if (idx < 0 || idx >= iommu_cb_set.cb_num) {
+ pr_err("Error: handle or index invalid. idx = %d hdl = %x\n",
+ idx, handle);
+ return;
+ }
+
+ mutex_lock(&iommu_cb_set.cb_info[idx].lock);
+ if (iommu_cb_set.cb_info[idx].handle != handle) {
+ pr_err("Error: hdl is not valid, table_hdl = %x, hdl = %x\n",
+ iommu_cb_set.cb_info[idx].handle, handle);
+ mutex_unlock(&iommu_cb_set.cb_info[idx].lock);
+ return;
+ }
+
+ if (client_page_fault_handler) {
+ if (iommu_cb_set.cb_info[idx].cb_count == CAM_SMMU_CB_MAX) {
+ pr_err("%s Should not regiester more handlers\n",
+ iommu_cb_set.cb_info[idx].name);
+ mutex_unlock(&iommu_cb_set.cb_info[idx].lock);
+ return;
+ }
+ iommu_cb_set.cb_info[idx].cb_count++;
+ for (i = 0; i < iommu_cb_set.cb_info[idx].cb_count; i++) {
+ if (iommu_cb_set.cb_info[idx].token[i] == NULL) {
+ iommu_cb_set.cb_info[idx].token[i] = token;
+ iommu_cb_set.cb_info[idx].handler[i] =
+ client_page_fault_handler;
+ break;
+ }
+ }
+ } else {
+ for (i = 0; i < CAM_SMMU_CB_MAX; i++) {
+ if (iommu_cb_set.cb_info[idx].token[i] == token) {
+ iommu_cb_set.cb_info[idx].token[i] = NULL;
+ iommu_cb_set.cb_info[idx].handler[i] =
+ NULL;
+ iommu_cb_set.cb_info[idx].cb_count--;
+ break;
+ }
+ }
+ if (i == CAM_SMMU_CB_MAX)
+ pr_err("Error: hdl %x no matching tokens: %s\n",
+ handle, iommu_cb_set.cb_info[idx].name);
+ }
+ mutex_unlock(&iommu_cb_set.cb_info[idx].lock);
+}
+
+static int cam_smmu_iommu_fault_handler(struct iommu_domain *domain,
+ struct device *dev, unsigned long iova,
+ int flags, void *token)
+{
+ char *cb_name;
+ int idx;
+ struct cam_smmu_work_payload *payload;
+
+ if (!token) {
+ pr_err("Error: token is NULL\n");
+ pr_err("Error: domain = %pK, device = %pK\n", domain, dev);
+ pr_err("iova = %lX, flags = %d\n", iova, flags);
+ return 0;
+ }
+
+ cb_name = (char *)token;
+ /* Check whether it is in the table */
+ for (idx = 0; idx < iommu_cb_set.cb_num; idx++) {
+ if (!strcmp(iommu_cb_set.cb_info[idx].name, cb_name))
+ break;
+ }
+
+ if (idx < 0 || idx >= iommu_cb_set.cb_num) {
+ pr_err("Error: index is not valid, index = %d, token = %s\n",
+ idx, cb_name);
+ return 0;
+ }
+
+ payload = kzalloc(sizeof(struct cam_smmu_work_payload), GFP_ATOMIC);
+ if (!payload)
+ return 0;
+
+ payload->domain = domain;
+ payload->dev = dev;
+ payload->iova = iova;
+ payload->flags = flags;
+ payload->token = token;
+ payload->idx = idx;
+
+ mutex_lock(&iommu_cb_set.payload_list_lock);
+ list_add_tail(&payload->list, &iommu_cb_set.payload_list);
+ mutex_unlock(&iommu_cb_set.payload_list_lock);
+
+ schedule_work(&iommu_cb_set.smmu_work);
+
+ return 0;
+}
+
+static int cam_smmu_translate_dir_to_iommu_dir(
+ enum cam_smmu_map_dir dir)
+{
+ switch (dir) {
+ case CAM_SMMU_MAP_READ:
+ return IOMMU_READ;
+ case CAM_SMMU_MAP_WRITE:
+ return IOMMU_WRITE;
+ case CAM_SMMU_MAP_RW:
+ return IOMMU_READ|IOMMU_WRITE;
+ case CAM_SMMU_MAP_INVALID:
+ default:
+ pr_err("Error: Direction is invalid. dir = %d\n", dir);
+ break;
+ };
+ return IOMMU_INVALID_DIR;
+}
+
+static enum dma_data_direction cam_smmu_translate_dir(
+ enum cam_smmu_map_dir dir)
+{
+ switch (dir) {
+ case CAM_SMMU_MAP_READ:
+ return DMA_FROM_DEVICE;
+ case CAM_SMMU_MAP_WRITE:
+ return DMA_TO_DEVICE;
+ case CAM_SMMU_MAP_RW:
+ return DMA_BIDIRECTIONAL;
+ case CAM_SMMU_MAP_INVALID:
+ default:
+ pr_err("Error: Direction is invalid. dir = %d\n", (int)dir);
+ break;
+ }
+ return DMA_NONE;
+}
+
+void cam_smmu_reset_iommu_table(enum cam_smmu_init_dir ops)
+{
+ unsigned int i;
+ int j = 0;
+
+ for (i = 0; i < iommu_cb_set.cb_num; i++) {
+ iommu_cb_set.cb_info[i].handle = HANDLE_INIT;
+ INIT_LIST_HEAD(&iommu_cb_set.cb_info[i].smmu_buf_list);
+ iommu_cb_set.cb_info[i].state = CAM_SMMU_DETACH;
+ iommu_cb_set.cb_info[i].dev = NULL;
+ iommu_cb_set.cb_info[i].cb_count = 0;
+ for (j = 0; j < CAM_SMMU_CB_MAX; j++) {
+ iommu_cb_set.cb_info[i].token[j] = NULL;
+ iommu_cb_set.cb_info[i].handler[j] = NULL;
+ }
+ if (ops == CAM_SMMU_TABLE_INIT)
+ mutex_init(&iommu_cb_set.cb_info[i].lock);
+ else
+ mutex_destroy(&iommu_cb_set.cb_info[i].lock);
+ }
+}
+
+static int cam_smmu_check_handle_unique(int hdl)
+{
+ int i;
+
+ if (hdl == HANDLE_INIT) {
+ CDBG("iommu handle is init number. Need to try again\n");
+ return 1;
+ }
+
+ for (i = 0; i < iommu_cb_set.cb_num; i++) {
+ if (iommu_cb_set.cb_info[i].handle == HANDLE_INIT)
+ continue;
+
+ if (iommu_cb_set.cb_info[i].handle == hdl) {
+ CDBG("iommu handle %d conflicts\n", (int)hdl);
+ return 1;
+ }
+ }
+ return 0;
+}
+
+/**
+ * use low 2 bytes for handle cookie
+ */
+static int cam_smmu_create_iommu_handle(int idx)
+{
+ int rand, hdl = 0;
+
+ get_random_bytes(&rand, COOKIE_NUM_BYTE);
+ hdl = GET_SMMU_HDL(idx, rand);
+ CDBG("create handle value = %x\n", (int)hdl);
+ return hdl;
+}
+
+static int cam_smmu_attach_device(int idx)
+{
+ int rc;
+ struct cam_context_bank_info *cb = &iommu_cb_set.cb_info[idx];
+
+ /* attach the mapping to device */
+ rc = arm_iommu_attach_device(cb->dev, cb->mapping);
+ if (rc < 0) {
+ pr_err("Error: ARM IOMMU attach failed. ret = %d\n", rc);
+ rc = -ENODEV;
+ }
+
+ return rc;
+}
+
+static int cam_smmu_create_add_handle_in_table(char *name,
+ int *hdl)
+{
+ int i;
+ int handle;
+
+ /* create handle and add in the iommu hardware table */
+ for (i = 0; i < iommu_cb_set.cb_num; i++) {
+ if (!strcmp(iommu_cb_set.cb_info[i].name, name)) {
+ mutex_lock(&iommu_cb_set.cb_info[i].lock);
+ if (iommu_cb_set.cb_info[i].handle != HANDLE_INIT) {
+ pr_err("Error: %s already got handle 0x%x\n",
+ name,
+ iommu_cb_set.cb_info[i].handle);
+ mutex_unlock(&iommu_cb_set.cb_info[i].lock);
+ return -EINVAL;
+ }
+
+ /* make sure handle is unique */
+ do {
+ handle = cam_smmu_create_iommu_handle(i);
+ } while (cam_smmu_check_handle_unique(handle));
+
+ /* put handle in the table */
+ iommu_cb_set.cb_info[i].handle = handle;
+ iommu_cb_set.cb_info[i].cb_count = 0;
+ *hdl = handle;
+ CDBG("%s creates handle 0x%x\n", name, handle);
+ mutex_unlock(&iommu_cb_set.cb_info[i].lock);
+ return 0;
+ }
+ }
+
+ pr_err("Error: Cannot find name %s or all handle exist!\n",
+ name);
+ cam_smmu_print_table();
+ return -EINVAL;
+}
+
+static int cam_smmu_init_scratch_map(struct scratch_mapping *scratch_map,
+ dma_addr_t base, size_t size,
+ int order)
+{
+ unsigned int count = size >> (PAGE_SHIFT + order);
+ unsigned int bitmap_size = BITS_TO_LONGS(count) * sizeof(long);
+ int err = 0;
+
+ if (!count) {
+ err = -EINVAL;
+ pr_err("Page count is zero, size passed = %zu\n", size);
+ goto bail;
+ }
+
+ scratch_map->bitmap = kzalloc(bitmap_size, GFP_KERNEL);
+ if (!scratch_map->bitmap) {
+ err = -ENOMEM;
+ goto bail;
+ }
+
+ scratch_map->base = base;
+ scratch_map->bits = BITS_PER_BYTE * bitmap_size;
+ scratch_map->order = order;
+
+bail:
+ return err;
+}
+
+static int cam_smmu_alloc_scratch_va(struct scratch_mapping *mapping,
+ size_t size,
+ dma_addr_t *iova)
+{
+ unsigned int order = get_order(size);
+ unsigned int align = 0;
+ unsigned int count, start;
+
+ count = ((PAGE_ALIGN(size) >> PAGE_SHIFT) +
+ (1 << mapping->order) - 1) >> mapping->order;
+
+ /*
+ * Transparently, add a guard page to the total count of pages
+ * to be allocated
+ */
+ count++;
+
+ if (order > mapping->order)
+ align = (1 << (order - mapping->order)) - 1;
+
+ start = bitmap_find_next_zero_area(mapping->bitmap, mapping->bits, 0,
+ count, align);
+
+ if (start > mapping->bits)
+ return -ENOMEM;
+
+ bitmap_set(mapping->bitmap, start, count);
+ *iova = mapping->base + (start << (mapping->order + PAGE_SHIFT));
+
+ return 0;
+}
+
+static int cam_smmu_free_scratch_va(struct scratch_mapping *mapping,
+ dma_addr_t addr, size_t size)
+{
+ unsigned int start = (addr - mapping->base) >>
+ (mapping->order + PAGE_SHIFT);
+ unsigned int count = ((size >> PAGE_SHIFT) +
+ (1 << mapping->order) - 1) >> mapping->order;
+
+ if (!addr) {
+ pr_err("Error: Invalid address\n");
+ return -EINVAL;
+ }
+
+ if (start + count > mapping->bits) {
+ pr_err("Error: Invalid page bits in scratch map\n");
+ return -EINVAL;
+ }
+
+ /*
+ * Transparently, add a guard page to the total count of pages
+ * to be freed
+ */
+ count++;
+ bitmap_clear(mapping->bitmap, start, count);
+
+ return 0;
+}
+
+static struct cam_dma_buff_info *cam_smmu_find_mapping_by_virt_address(int idx,
+ dma_addr_t virt_addr)
+{
+ struct cam_dma_buff_info *mapping;
+
+ list_for_each_entry(mapping, &iommu_cb_set.cb_info[idx].smmu_buf_list,
+ list) {
+ if (mapping->paddr == virt_addr) {
+ CDBG("Found virtual address %lx\n",
+ (unsigned long)virt_addr);
+ return mapping;
+ }
+ }
+
+ pr_err("Error: Cannot find virtual address %lx by index %d\n",
+ (unsigned long)virt_addr, idx);
+ return NULL;
+}
+
+static struct cam_dma_buff_info *cam_smmu_find_mapping_by_ion_index(int idx,
+ int ion_fd)
+{
+ struct cam_dma_buff_info *mapping;
+
+ list_for_each_entry(mapping, &iommu_cb_set.cb_info[idx].smmu_buf_list,
+ list) {
+ if (mapping->ion_fd == ion_fd) {
+ CDBG(" find ion_fd %d\n", ion_fd);
+ return mapping;
+ }
+ }
+
+ pr_err("Error: Cannot find fd %d by index %d\n",
+ ion_fd, idx);
+ return NULL;
+}
+
+static void cam_smmu_clean_buffer_list(int idx)
+{
+ int ret;
+ struct cam_dma_buff_info *mapping_info, *temp;
+
+ list_for_each_entry_safe(mapping_info, temp,
+ &iommu_cb_set.cb_info[idx].smmu_buf_list, list) {
+ CDBG("Free mapping address %pK, i = %d, fd = %d\n",
+ (void *)mapping_info->paddr, idx,
+ mapping_info->ion_fd);
+
+ if (mapping_info->ion_fd == 0xDEADBEEF)
+ /* Clean up scratch buffers */
+ ret = cam_smmu_free_scratch_buffer_remove_from_list(
+ mapping_info, idx);
+ else
+ /* Clean up regular mapped buffers */
+ ret = cam_smmu_unmap_buf_and_remove_from_list(
+ mapping_info,
+ idx);
+
+ if (ret < 0) {
+ pr_err("Buffer delete failed: idx = %d\n", idx);
+ pr_err("Buffer delete failed: addr = %lx, fd = %d\n",
+ (unsigned long)mapping_info->paddr,
+ mapping_info->ion_fd);
+ /*
+ * Ignore this error and continue to delete other
+ * buffers in the list
+ */
+ continue;
+ }
+ }
+}
+
+static int cam_smmu_attach(int idx)
+{
+ int ret;
+
+ if (iommu_cb_set.cb_info[idx].state == CAM_SMMU_ATTACH) {
+ ret = -EALREADY;
+ } else if (iommu_cb_set.cb_info[idx].state == CAM_SMMU_DETACH) {
+ ret = cam_smmu_attach_device(idx);
+ if (ret < 0) {
+ pr_err("Error: ATTACH fail\n");
+ return -ENODEV;
+ }
+ iommu_cb_set.cb_info[idx].state = CAM_SMMU_ATTACH;
+ ret = 0;
+ } else {
+ pr_err("Error: Not detach/attach: %d\n",
+ iommu_cb_set.cb_info[idx].state);
+ ret = -EINVAL;
+ }
+
+ return ret;
+}
+
+static int cam_smmu_detach_device(int idx)
+{
+ int rc = 0;
+ struct cam_context_bank_info *cb = &iommu_cb_set.cb_info[idx];
+
+ /* detach the mapping to device if not already detached */
+ if (iommu_cb_set.cb_info[idx].state == CAM_SMMU_DETACH) {
+ rc = -EALREADY;
+ } else if (iommu_cb_set.cb_info[idx].state == CAM_SMMU_ATTACH) {
+ arm_iommu_detach_device(cb->dev);
+ iommu_cb_set.cb_info[idx].state = CAM_SMMU_DETACH;
+ }
+
+ return rc;
+}
+
+static int cam_smmu_alloc_iova(size_t size,
+ int32_t smmu_hdl, uint32_t *iova)
+{
+ int rc = 0;
+ int idx;
+ uint32_t vaddr = 0;
+
+ if (!iova || !size || (smmu_hdl == HANDLE_INIT)) {
+ pr_err("Error: Input args are invalid\n");
+ return -EINVAL;
+ }
+
+ CDBG("Allocating iova size = %zu for smmu hdl=%X\n", size, smmu_hdl);
+
+ idx = GET_SMMU_TABLE_IDX(smmu_hdl);
+ if (idx < 0 || idx >= iommu_cb_set.cb_num) {
+ pr_err("Error: handle or index invalid. idx = %d hdl = %x\n",
+ idx, smmu_hdl);
+ return -EINVAL;
+ }
+
+ if (iommu_cb_set.cb_info[idx].handle != smmu_hdl) {
+ pr_err("Error: hdl is not valid, table_hdl = %x, hdl = %x\n",
+ iommu_cb_set.cb_info[idx].handle, smmu_hdl);
+ rc = -EINVAL;
+ goto get_addr_end;
+ }
+
+ if (!iommu_cb_set.cb_info[idx].shared_support) {
+ pr_err("Error: Shared memory not supported for hdl = %X\n",
+ smmu_hdl);
+ rc = -EINVAL;
+ goto get_addr_end;
+ }
+
+ vaddr = gen_pool_alloc(iommu_cb_set.cb_info[idx].shared_mem_pool, size);
+ if (!vaddr)
+ return -ENOMEM;
+
+ *iova = vaddr;
+
+get_addr_end:
+ return rc;
+}
+
+static int cam_smmu_free_iova(uint32_t addr, size_t size,
+ int32_t smmu_hdl)
+{
+ int rc = 0;
+ int idx;
+
+ if (!size || (smmu_hdl == HANDLE_INIT)) {
+ pr_err("Error: Input args are invalid\n");
+ return -EINVAL;
+ }
+
+ idx = GET_SMMU_TABLE_IDX(smmu_hdl);
+ if (idx < 0 || idx >= iommu_cb_set.cb_num) {
+ pr_err("Error: handle or index invalid. idx = %d hdl = %x\n",
+ idx, smmu_hdl);
+ return -EINVAL;
+ }
+
+ if (iommu_cb_set.cb_info[idx].handle != smmu_hdl) {
+ pr_err("Error: hdl is not valid, table_hdl = %x, hdl = %x\n",
+ iommu_cb_set.cb_info[idx].handle, smmu_hdl);
+ rc = -EINVAL;
+ goto get_addr_end;
+ }
+
+ gen_pool_free(iommu_cb_set.cb_info[idx].shared_mem_pool, addr, size);
+
+get_addr_end:
+ return rc;
+}
+
+int cam_smmu_alloc_firmware(int32_t smmu_hdl,
+ dma_addr_t *iova,
+ uint64_t *cpuva,
+ size_t *len)
+{
+ int rc;
+ int32_t idx;
+ size_t firmware_len = 0;
+ size_t firmware_start = 0;
+ struct iommu_domain *domain;
+
+ if (!iova || !len || !cpuva || (smmu_hdl == HANDLE_INIT)) {
+ pr_err("Error: Input args are invalid\n");
+ return -EINVAL;
+ }
+
+ idx = GET_SMMU_TABLE_IDX(smmu_hdl);
+ if (idx < 0 || idx >= iommu_cb_set.cb_num) {
+ pr_err("Error: handle or index invalid. idx = %d hdl = %x\n",
+ idx, smmu_hdl);
+ rc = -EINVAL;
+ goto end;
+ }
+
+ if (!iommu_cb_set.cb_info[idx].firmware_support) {
+ pr_err("Firmware memory not supported for this SMMU handle\n");
+ rc = -EINVAL;
+ goto end;
+ }
+
+ mutex_lock(&iommu_cb_set.cb_info[idx].lock);
+ if (iommu_cb_set.cb_info[idx].is_fw_allocated) {
+ pr_err("Trying to allocate twice\n");
+ rc = -ENOMEM;
+ goto unlock_and_end;
+ }
+
+ firmware_len = iommu_cb_set.cb_info[idx].firmware_info.iova_len;
+ firmware_start = iommu_cb_set.cb_info[idx].firmware_info.iova_start;
+ CDBG("Firmware area len from DT = %zu\n", firmware_len);
+
+ icp_fw.fw_kva = dma_alloc_coherent(icp_fw.fw_dev,
+ firmware_len,
+ &icp_fw.fw_dma_hdl,
+ GFP_KERNEL);
+ if (!icp_fw.fw_kva) {
+ pr_err("FW memory alloc failed\n");
+ rc = -ENOMEM;
+ goto unlock_and_end;
+ } else {
+ CDBG("DMA alloc returned fw = %pK, hdl = %pK\n",
+ icp_fw.fw_kva, (void *)icp_fw.fw_dma_hdl);
+ }
+
+ domain = iommu_cb_set.cb_info[idx].mapping->domain;
+ rc = iommu_map(domain,
+ firmware_start,
+ icp_fw.fw_dma_hdl,
+ firmware_len,
+ IOMMU_READ|IOMMU_WRITE|IOMMU_PRIV);
+
+ if (rc) {
+ pr_err("Failed to map FW into IOMMU\n");
+ rc = -ENOMEM;
+ goto alloc_fail;
+ }
+ iommu_cb_set.cb_info[idx].is_fw_allocated = true;
+
+ *iova = iommu_cb_set.cb_info[idx].firmware_info.iova_start;
+ *cpuva = (uint64_t)icp_fw.fw_kva;
+ *len = firmware_len;
+ mutex_unlock(&iommu_cb_set.cb_info[idx].lock);
+
+ return rc;
+
+alloc_fail:
+ dma_free_coherent(icp_fw.fw_dev,
+ firmware_len,
+ icp_fw.fw_kva,
+ icp_fw.fw_dma_hdl);
+unlock_and_end:
+ mutex_unlock(&iommu_cb_set.cb_info[idx].lock);
+end:
+ return rc;
+}
+EXPORT_SYMBOL(cam_smmu_alloc_firmware);
+
+int cam_smmu_dealloc_firmware(int32_t smmu_hdl)
+{
+ int rc = 0;
+ int32_t idx;
+ size_t firmware_len = 0;
+ size_t firmware_start = 0;
+ struct iommu_domain *domain;
+ size_t unmapped = 0;
+
+ if (smmu_hdl == HANDLE_INIT) {
+ pr_err("Error: Invalid handle\n");
+ return -EINVAL;
+ }
+
+ idx = GET_SMMU_TABLE_IDX(smmu_hdl);
+ if (idx < 0 || idx >= iommu_cb_set.cb_num) {
+ pr_err("Error: handle or index invalid. idx = %d hdl = %x\n",
+ idx, smmu_hdl);
+ rc = -EINVAL;
+ goto end;
+ }
+
+ if (!iommu_cb_set.cb_info[idx].firmware_support) {
+ pr_err("Firmware memory not supported for this SMMU handle\n");
+ rc = -EINVAL;
+ goto end;
+ }
+
+ mutex_lock(&iommu_cb_set.cb_info[idx].lock);
+ if (!iommu_cb_set.cb_info[idx].is_fw_allocated) {
+ pr_err("Trying to deallocate firmware that is not allocated\n");
+ rc = -ENOMEM;
+ goto unlock_and_end;
+ }
+
+ firmware_len = iommu_cb_set.cb_info[idx].firmware_info.iova_len;
+ firmware_start = iommu_cb_set.cb_info[idx].firmware_info.iova_start;
+ domain = iommu_cb_set.cb_info[idx].mapping->domain;
+ unmapped = iommu_unmap(domain,
+ firmware_start,
+ firmware_len);
+
+ if (unmapped != firmware_len) {
+ pr_err("Only %zu unmapped out of total %zu\n",
+ unmapped,
+ firmware_len);
+ rc = -EINVAL;
+ }
+
+ dma_free_coherent(icp_fw.fw_dev,
+ firmware_len,
+ icp_fw.fw_kva,
+ icp_fw.fw_dma_hdl);
+
+ icp_fw.fw_kva = 0;
+ icp_fw.fw_dma_hdl = 0;
+
+ iommu_cb_set.cb_info[idx].is_fw_allocated = false;
+
+unlock_and_end:
+ mutex_unlock(&iommu_cb_set.cb_info[idx].lock);
+end:
+ return rc;
+}
+EXPORT_SYMBOL(cam_smmu_dealloc_firmware);
+
+static int cam_smmu_map_buffer_and_add_to_list(int idx, int ion_fd,
+ enum dma_data_direction dma_dir, dma_addr_t *paddr_ptr,
+ size_t *len_ptr,
+ enum cam_smmu_region_id region_id)
+{
+ int rc = -1;
+ struct cam_dma_buff_info *mapping_info;
+ struct dma_buf *buf = NULL;
+ struct dma_buf_attachment *attach = NULL;
+ struct sg_table *table = NULL;
+ struct iommu_domain *domain;
+ size_t size = 0;
+ uint32_t iova = 0;
+
+ /* allocate memory for each buffer information */
+ buf = dma_buf_get(ion_fd);
+ if (IS_ERR_OR_NULL(buf)) {
+ rc = PTR_ERR(buf);
+ pr_err("Error: dma get buf failed. fd = %d\n", ion_fd);
+ goto err_out;
+ }
+
+ attach = dma_buf_attach(buf, iommu_cb_set.cb_info[idx].dev);
+ if (IS_ERR_OR_NULL(attach)) {
+ rc = PTR_ERR(attach);
+ pr_err("Error: dma buf attach failed\n");
+ goto err_put;
+ }
+
+ table = dma_buf_map_attachment(attach, dma_dir);
+ if (IS_ERR_OR_NULL(table)) {
+ rc = PTR_ERR(table);
+ pr_err("Error: dma buf map attachment failed\n");
+ goto err_detach;
+ }
+
+ if (region_id == CAM_SMMU_REGION_SHARED) {
+ domain = iommu_cb_set.cb_info[idx].mapping->domain;
+ if (!domain) {
+ pr_err("CB has no domain set\n");
+ goto err_unmap_sg;
+ }
+
+ rc = cam_smmu_alloc_iova(*len_ptr,
+ iommu_cb_set.cb_info[idx].handle,
+ &iova);
+
+ if (rc < 0) {
+ pr_err("IOVA alloc failed for shared memory\n");
+ goto err_unmap_sg;
+ }
+
+ size = iommu_map_sg(domain,
+ iova,
+ table->sgl,
+ table->nents,
+ IOMMU_READ | IOMMU_WRITE);
+
+ if (size < 0) {
+ pr_err("IOMMU mapping failed\n");
+ rc = cam_smmu_free_iova(iova,
+ size,
+ iommu_cb_set.cb_info[idx].handle);
+
+ if (rc)
+ pr_err("IOVA free failed\n");
+ rc = -ENOMEM;
+ goto err_unmap_sg;
+ } else {
+ CDBG("iommu_map_sg returned %zu\n", size);
+ *paddr_ptr = iova;
+ *len_ptr = size;
+ }
+ } else if (region_id == CAM_SMMU_REGION_IO) {
+ rc = msm_dma_map_sg_lazy(iommu_cb_set.cb_info[idx].dev,
+ table->sgl, table->nents, dma_dir, buf);
+
+ if (rc != table->nents) {
+ pr_err("Error: msm_dma_map_sg_lazy failed\n");
+ rc = -ENOMEM;
+ goto err_unmap_sg;
+ } else {
+ *paddr_ptr = sg_dma_address(table->sgl);
+ *len_ptr = (size_t)sg_dma_len(table->sgl);
+ }
+ } else {
+ pr_err("Error: Wrong region id passed for %s\n", __func__);
+ rc = -EINVAL;
+ goto err_unmap_sg;
+ }
+
+ if (table->sgl) {
+ CDBG("DMA buf: %pK, device: %pK, attach: %pK, table: %pK\n",
+ (void *)buf,
+ (void *)iommu_cb_set.cb_info[idx].dev,
+ (void *)attach, (void *)table);
+ CDBG("table sgl: %pK, rc: %d, dma_address: 0x%x\n",
+ (void *)table->sgl, rc,
+ (unsigned int)table->sgl->dma_address);
+ } else {
+ rc = -EINVAL;
+ pr_err("Error: table sgl is null\n");
+ goto err_unmap_sg;
+ }
+
+ /* fill up mapping_info */
+ mapping_info = kzalloc(sizeof(struct cam_dma_buff_info), GFP_KERNEL);
+ if (!mapping_info) {
+ rc = -ENOSPC;
+ goto err_alloc;
+ }
+ mapping_info->ion_fd = ion_fd;
+ mapping_info->buf = buf;
+ mapping_info->attach = attach;
+ mapping_info->table = table;
+ mapping_info->paddr = *paddr_ptr;
+ mapping_info->len = *len_ptr;
+ mapping_info->dir = dma_dir;
+ mapping_info->ref_count = 1;
+ mapping_info->region_id = region_id;
+
+ if (!*paddr_ptr || !*len_ptr) {
+ pr_err("Error: Space Allocation failed!\n");
+ kfree(mapping_info);
+ rc = -ENOSPC;
+ goto err_alloc;
+ }
+ CDBG("ion_fd = %d, dev = %pK, paddr= %pK, len = %u\n", ion_fd,
+ (void *)iommu_cb_set.cb_info[idx].dev,
+ (void *)*paddr_ptr, (unsigned int)*len_ptr);
+
+ /* add to the list */
+ list_add(&mapping_info->list, &iommu_cb_set.cb_info[idx].smmu_buf_list);
+ return 0;
+
+err_alloc:
+ if (region_id == CAM_SMMU_REGION_SHARED) {
+ cam_smmu_free_iova(iova,
+ size,
+ iommu_cb_set.cb_info[idx].handle);
+
+ iommu_unmap(iommu_cb_set.cb_info[idx].mapping->domain,
+ *paddr_ptr,
+ *len_ptr);
+ } else if (region_id == CAM_SMMU_REGION_IO) {
+ msm_dma_unmap_sg(iommu_cb_set.cb_info[idx].dev,
+ table->sgl,
+ table->nents,
+ dma_dir,
+ buf);
+ }
+err_unmap_sg:
+ dma_buf_unmap_attachment(attach, table, dma_dir);
+err_detach:
+ dma_buf_detach(buf, attach);
+err_put:
+ dma_buf_put(buf);
+err_out:
+ return rc;
+}
+
+static int cam_smmu_unmap_buf_and_remove_from_list(
+ struct cam_dma_buff_info *mapping_info,
+ int idx)
+{
+ int rc;
+ size_t size;
+ struct iommu_domain *domain;
+
+ if ((!mapping_info->buf) || (!mapping_info->table) ||
+ (!mapping_info->attach)) {
+ pr_err("Error: Invalid params dev = %pK, table = %pK\n",
+ (void *)iommu_cb_set.cb_info[idx].dev,
+ (void *)mapping_info->table);
+ pr_err("Error:dma_buf = %pK, attach = %pK\n",
+ (void *)mapping_info->buf,
+ (void *)mapping_info->attach);
+ return -EINVAL;
+ }
+
+ if (mapping_info->region_id == CAM_SMMU_REGION_SHARED) {
+ CDBG("Removing SHARED buffer paddr = %pK, len = %zu\n",
+ (void *)mapping_info->paddr, mapping_info->len);
+
+ domain = iommu_cb_set.cb_info[idx].mapping->domain;
+
+ size = iommu_unmap(domain,
+ mapping_info->paddr,
+ mapping_info->len);
+
+ if (size != mapping_info->len) {
+ pr_err("IOMMU unmap failed\n");
+ pr_err("Unmapped = %zu, requested = %zu\n",
+ size,
+ mapping_info->len);
+ }
+
+ rc = cam_smmu_free_iova(mapping_info->paddr,
+ mapping_info->len,
+ iommu_cb_set.cb_info[idx].handle);
+
+ if (rc)
+ pr_err("IOVA free failed\n");
+
+ } else if (mapping_info->region_id == CAM_SMMU_REGION_IO) {
+ msm_dma_unmap_sg(iommu_cb_set.cb_info[idx].dev,
+ mapping_info->table->sgl, mapping_info->table->nents,
+ mapping_info->dir, mapping_info->buf);
+ }
+
+ dma_buf_unmap_attachment(mapping_info->attach,
+ mapping_info->table, mapping_info->dir);
+ dma_buf_detach(mapping_info->buf, mapping_info->attach);
+ dma_buf_put(mapping_info->buf);
+
+ mapping_info->buf = NULL;
+
+ list_del_init(&mapping_info->list);
+
+ /* free one buffer */
+ kfree(mapping_info);
+ return 0;
+}
+
+static enum cam_smmu_buf_state cam_smmu_check_fd_in_list(int idx,
+ int ion_fd, dma_addr_t *paddr_ptr,
+ size_t *len_ptr)
+{
+ struct cam_dma_buff_info *mapping;
+
+ list_for_each_entry(mapping,
+ &iommu_cb_set.cb_info[idx].smmu_buf_list, list) {
+ if (mapping->ion_fd == ion_fd) {
+ mapping->ref_count++;
+ *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;
+
+ if (!identifier) {
+ pr_err("Error: iommu hardware name is NULL\n");
+ return -EINVAL;
+ }
+
+ if (!handle_ptr) {
+ pr_err("Error: handle pointer is NULL\n");
+ return -EINVAL;
+ }
+
+ /* create and put handle in the table */
+ ret = cam_smmu_create_add_handle_in_table(identifier, handle_ptr);
+ if (ret < 0)
+ pr_err("Error: %s get handle fail\n", identifier);
+
+ return ret;
+}
+EXPORT_SYMBOL(cam_smmu_get_handle);
+
+int cam_smmu_ops(int handle, enum cam_smmu_ops_param ops)
+{
+ int ret = 0, idx;
+
+ if (handle == HANDLE_INIT) {
+ pr_err("Error: Invalid handle\n");
+ return -EINVAL;
+ }
+
+ idx = GET_SMMU_TABLE_IDX(handle);
+ if (idx < 0 || idx >= iommu_cb_set.cb_num) {
+ pr_err("Error: Index invalid. idx = %d hdl = %x\n",
+ idx, handle);
+ return -EINVAL;
+ }
+
+ mutex_lock(&iommu_cb_set.cb_info[idx].lock);
+ if (iommu_cb_set.cb_info[idx].handle != handle) {
+ pr_err("Error: hdl is not valid, table_hdl = %x, hdl = %x\n",
+ iommu_cb_set.cb_info[idx].handle, handle);
+ mutex_unlock(&iommu_cb_set.cb_info[idx].lock);
+ return -EINVAL;
+ }
+
+ switch (ops) {
+ case CAM_SMMU_ATTACH: {
+ ret = cam_smmu_attach(idx);
+ break;
+ }
+ case CAM_SMMU_DETACH: {
+ ret = cam_smmu_detach_device(idx);
+ break;
+ }
+ case CAM_SMMU_VOTE:
+ case CAM_SMMU_DEVOTE:
+ default:
+ pr_err("Error: idx = %d, ops = %d\n", idx, ops);
+ ret = -EINVAL;
+ }
+ mutex_unlock(&iommu_cb_set.cb_info[idx].lock);
+ return ret;
+}
+EXPORT_SYMBOL(cam_smmu_ops);
+
+static int cam_smmu_alloc_scratch_buffer_add_to_list(int idx,
+ size_t virt_len,
+ size_t phys_len,
+ unsigned int iommu_dir,
+ dma_addr_t *virt_addr)
+{
+ unsigned long nents = virt_len / phys_len;
+ struct cam_dma_buff_info *mapping_info = NULL;
+ size_t unmapped;
+ dma_addr_t iova = 0;
+ struct scatterlist *sg;
+ int i = 0;
+ int rc;
+ struct iommu_domain *domain = NULL;
+ struct page *page;
+ struct sg_table *table = NULL;
+
+ CDBG("%s: nents = %lu, idx = %d, virt_len = %zx\n",
+ __func__, nents, idx, virt_len);
+ CDBG("%s: phys_len = %zx, iommu_dir = %d, virt_addr = %pK\n",
+ __func__, phys_len, iommu_dir, virt_addr);
+
+ /*
+ * This table will go inside the 'mapping' structure
+ * where it will be held until put_scratch_buffer is called
+ */
+ table = kzalloc(sizeof(struct sg_table), GFP_KERNEL);
+ if (!table) {
+ rc = -ENOMEM;
+ goto err_table_alloc;
+ }
+
+ rc = sg_alloc_table(table, nents, GFP_KERNEL);
+ if (rc < 0) {
+ rc = -EINVAL;
+ goto err_sg_alloc;
+ }
+
+ page = alloc_pages(GFP_KERNEL, get_order(phys_len));
+ if (!page) {
+ rc = -ENOMEM;
+ goto err_page_alloc;
+ }
+
+ /* Now we create the sg list */
+ for_each_sg(table->sgl, sg, table->nents, i)
+ sg_set_page(sg, page, phys_len, 0);
+
+
+ /* Get the domain from within our cb_set struct and map it*/
+ domain = iommu_cb_set.cb_info[idx].mapping->domain;
+
+ rc = cam_smmu_alloc_scratch_va(&iommu_cb_set.cb_info[idx].scratch_map,
+ virt_len, &iova);
+
+ if (rc < 0) {
+ pr_err("Could not find valid iova for scratch buffer");
+ goto err_iommu_map;
+ }
+
+ if (iommu_map_sg(domain,
+ iova,
+ table->sgl,
+ table->nents,
+ iommu_dir) != virt_len) {
+ pr_err("iommu_map_sg() failed");
+ goto err_iommu_map;
+ }
+
+ /* Now update our mapping information within the cb_set struct */
+ mapping_info = kzalloc(sizeof(struct cam_dma_buff_info), GFP_KERNEL);
+ if (!mapping_info) {
+ rc = -ENOMEM;
+ goto err_mapping_info;
+ }
+
+ mapping_info->ion_fd = 0xDEADBEEF;
+ mapping_info->buf = NULL;
+ mapping_info->attach = NULL;
+ mapping_info->table = table;
+ mapping_info->paddr = iova;
+ mapping_info->len = virt_len;
+ mapping_info->iommu_dir = iommu_dir;
+ mapping_info->ref_count = 1;
+ mapping_info->phys_len = phys_len;
+ mapping_info->region_id = CAM_SMMU_REGION_SCRATCH;
+
+ CDBG("%s: paddr = %pK, len = %zx, phys_len = %zx",
+ __func__, (void *)mapping_info->paddr,
+ mapping_info->len, mapping_info->phys_len);
+
+ list_add(&mapping_info->list, &iommu_cb_set.cb_info[idx].smmu_buf_list);
+
+ *virt_addr = (dma_addr_t)iova;
+
+ CDBG("%s: mapped virtual address = %lx\n", __func__,
+ (unsigned long)*virt_addr);
+ return 0;
+
+err_mapping_info:
+ unmapped = iommu_unmap(domain, iova, virt_len);
+ if (unmapped != virt_len)
+ pr_err("Unmapped only %zx instead of %zx", unmapped, virt_len);
+err_iommu_map:
+ __free_pages(page, get_order(phys_len));
+err_page_alloc:
+ sg_free_table(table);
+err_sg_alloc:
+ kfree(table);
+err_table_alloc:
+ return rc;
+}
+
+static int cam_smmu_free_scratch_buffer_remove_from_list(
+ struct cam_dma_buff_info *mapping_info,
+ int idx)
+{
+ int rc = 0;
+ size_t unmapped;
+ struct iommu_domain *domain =
+ iommu_cb_set.cb_info[idx].mapping->domain;
+ struct scratch_mapping *scratch_map =
+ &iommu_cb_set.cb_info[idx].scratch_map;
+
+ if (!mapping_info->table) {
+ pr_err("Error: Invalid params: dev = %pK, table = %pK",
+ (void *)iommu_cb_set.cb_info[idx].dev,
+ (void *)mapping_info->table);
+ return -EINVAL;
+ }
+
+ /* Clean up the mapping_info struct from the list */
+ unmapped = iommu_unmap(domain, mapping_info->paddr, mapping_info->len);
+ if (unmapped != mapping_info->len)
+ pr_err("Unmapped only %zx instead of %zx",
+ unmapped, mapping_info->len);
+
+ rc = cam_smmu_free_scratch_va(scratch_map,
+ mapping_info->paddr,
+ mapping_info->len);
+ if (rc < 0) {
+ pr_err("Error: Invalid iova while freeing scratch buffer\n");
+ rc = -EINVAL;
+ }
+
+ __free_pages(sg_page(mapping_info->table->sgl),
+ get_order(mapping_info->phys_len));
+ sg_free_table(mapping_info->table);
+ kfree(mapping_info->table);
+ list_del_init(&mapping_info->list);
+
+ kfree(mapping_info);
+ mapping_info = NULL;
+
+ return rc;
+}
+
+int cam_smmu_get_scratch_iova(int handle,
+ enum cam_smmu_map_dir dir,
+ dma_addr_t *paddr_ptr,
+ size_t virt_len,
+ size_t phys_len)
+{
+ int idx, rc;
+ unsigned int iommu_dir;
+
+ if (!paddr_ptr || !virt_len || !phys_len) {
+ pr_err("Error: Input pointer or lengths invalid\n");
+ return -EINVAL;
+ }
+
+ if (virt_len < phys_len) {
+ pr_err("Error: virt_len > phys_len\n");
+ return -EINVAL;
+ }
+
+ if (handle == HANDLE_INIT) {
+ pr_err("Error: Invalid handle\n");
+ return -EINVAL;
+ }
+
+ iommu_dir = cam_smmu_translate_dir_to_iommu_dir(dir);
+ if (iommu_dir == IOMMU_INVALID_DIR) {
+ pr_err("Error: translate direction failed. dir = %d\n", dir);
+ return -EINVAL;
+ }
+
+ idx = GET_SMMU_TABLE_IDX(handle);
+ if (idx < 0 || idx >= iommu_cb_set.cb_num) {
+ pr_err("Error: handle or index invalid. idx = %d hdl = %x\n",
+ idx, handle);
+ return -EINVAL;
+ }
+
+ mutex_lock(&iommu_cb_set.cb_info[idx].lock);
+ if (iommu_cb_set.cb_info[idx].handle != handle) {
+ pr_err("Error: hdl is not valid, table_hdl = %x, hdl = %x\n",
+ iommu_cb_set.cb_info[idx].handle, handle);
+ rc = -EINVAL;
+ goto error;
+ }
+
+ if (!iommu_cb_set.cb_info[idx].scratch_buf_support) {
+ pr_err("Error: Context bank does not support scratch bufs\n");
+ rc = -EINVAL;
+ goto error;
+ }
+
+ CDBG("%s: smmu handle = %x, idx = %d, dir = %d\n",
+ __func__, handle, idx, dir);
+ CDBG("%s: virt_len = %zx, phys_len = %zx\n",
+ __func__, phys_len, virt_len);
+
+ if (iommu_cb_set.cb_info[idx].state != CAM_SMMU_ATTACH) {
+ pr_err("Err:Dev %s should call SMMU attach before map buffer\n",
+ iommu_cb_set.cb_info[idx].name);
+ rc = -EINVAL;
+ goto error;
+ }
+
+ if (!IS_ALIGNED(virt_len, PAGE_SIZE)) {
+ pr_err("Requested scratch buffer length not page aligned\n");
+ rc = -EINVAL;
+ goto error;
+ }
+
+ if (!IS_ALIGNED(virt_len, phys_len)) {
+ pr_err("Requested virt length not aligned with phys length\n");
+ rc = -EINVAL;
+ goto error;
+ }
+
+ rc = cam_smmu_alloc_scratch_buffer_add_to_list(idx,
+ virt_len,
+ phys_len,
+ iommu_dir,
+ paddr_ptr);
+ if (rc < 0)
+ pr_err("Error: mapping or add list fail\n");
+
+error:
+ mutex_unlock(&iommu_cb_set.cb_info[idx].lock);
+ return rc;
+}
+
+int cam_smmu_put_scratch_iova(int handle,
+ dma_addr_t paddr)
+{
+ int idx;
+ int rc = -1;
+ struct cam_dma_buff_info *mapping_info;
+
+ if (handle == HANDLE_INIT) {
+ pr_err("Error: Invalid handle\n");
+ return -EINVAL;
+ }
+
+ /* find index in the iommu_cb_set.cb_info */
+ idx = GET_SMMU_TABLE_IDX(handle);
+ if (idx < 0 || idx >= iommu_cb_set.cb_num) {
+ pr_err("Error: handle or index invalid. idx = %d hdl = %x\n",
+ idx, handle);
+ return -EINVAL;
+ }
+
+ mutex_lock(&iommu_cb_set.cb_info[idx].lock);
+ if (iommu_cb_set.cb_info[idx].handle != handle) {
+ pr_err("Error: hdl is not valid, table_hdl = %x, hdl = %x\n",
+ iommu_cb_set.cb_info[idx].handle, handle);
+ rc = -EINVAL;
+ goto handle_err;
+ }
+
+ if (!iommu_cb_set.cb_info[idx].scratch_buf_support) {
+ pr_err("Error: Context bank does not support scratch buffers\n");
+ rc = -EINVAL;
+ goto handle_err;
+ }
+
+ /* Based on virtual address and index, we can find mapping info
+ * of the scratch buffer
+ */
+ mapping_info = cam_smmu_find_mapping_by_virt_address(idx, paddr);
+ if (!mapping_info) {
+ pr_err("Error: Invalid params\n");
+ rc = -ENODEV;
+ goto handle_err;
+ }
+
+ /* unmapping one buffer from device */
+ rc = cam_smmu_free_scratch_buffer_remove_from_list(mapping_info, idx);
+ if (rc < 0) {
+ pr_err("Error: unmap or remove list fail\n");
+ goto handle_err;
+ }
+
+handle_err:
+ mutex_unlock(&iommu_cb_set.cb_info[idx].lock);
+ return rc;
+}
+
+int cam_smmu_map_sec_iova(int handle, int ion_fd,
+ enum cam_smmu_map_dir dir, dma_addr_t *paddr_ptr,
+ size_t *len_ptr)
+{
+ /* not implemented yet */
+ return -EPERM;
+}
+EXPORT_SYMBOL(cam_smmu_map_sec_iova);
+
+int cam_smmu_map_iova(int handle, int ion_fd,
+ enum cam_smmu_map_dir dir, dma_addr_t *paddr_ptr,
+ size_t *len_ptr, enum cam_smmu_region_id region_id)
+{
+ int idx, rc;
+ enum dma_data_direction dma_dir;
+ enum cam_smmu_buf_state buf_state;
+
+ if (!paddr_ptr || !len_ptr) {
+ pr_err("Input pointers are invalid\n");
+ return -EINVAL;
+ }
+
+ if (handle == HANDLE_INIT) {
+ pr_err("Invalid handle\n");
+ return -EINVAL;
+ }
+
+ /* clean the content from clients */
+ *paddr_ptr = (dma_addr_t)NULL;
+ if (region_id != CAM_SMMU_REGION_SHARED)
+ *len_ptr = (size_t)0;
+
+ dma_dir = cam_smmu_translate_dir(dir);
+ if (dma_dir == DMA_NONE) {
+ pr_err("translate direction failed. dir = %d\n", dir);
+ return -EINVAL;
+ }
+
+ idx = GET_SMMU_TABLE_IDX(handle);
+ if (idx < 0 || idx >= iommu_cb_set.cb_num) {
+ pr_err("handle or index invalid. idx = %d hdl = %x\n",
+ idx, handle);
+ return -EINVAL;
+ }
+
+ mutex_lock(&iommu_cb_set.cb_info[idx].lock);
+ if (iommu_cb_set.cb_info[idx].handle != handle) {
+ pr_err("hdl is not valid, table_hdl = %x, hdl = %x\n",
+ iommu_cb_set.cb_info[idx].handle, handle);
+ rc = -EINVAL;
+ goto get_addr_end;
+ }
+
+ if (iommu_cb_set.cb_info[idx].state != CAM_SMMU_ATTACH) {
+ pr_err("Err:Dev %s should call SMMU attach before map buffer\n",
+ iommu_cb_set.cb_info[idx].name);
+ rc = -EINVAL;
+ goto get_addr_end;
+ }
+
+ buf_state = cam_smmu_check_fd_in_list(idx, ion_fd, paddr_ptr,
+ len_ptr);
+ if (buf_state == CAM_SMMU_BUFF_EXIST) {
+ CDBG("ion_fd:%d already in the list, give same addr back",
+ ion_fd);
+ rc = 0;
+ goto get_addr_end;
+ }
+ rc = cam_smmu_map_buffer_and_add_to_list(idx, ion_fd, dma_dir,
+ paddr_ptr, len_ptr, region_id);
+ if (rc < 0)
+ pr_err("mapping or add list fail\n");
+
+get_addr_end:
+ mutex_unlock(&iommu_cb_set.cb_info[idx].lock);
+ return rc;
+}
+EXPORT_SYMBOL(cam_smmu_map_iova);
+
+
+int cam_smmu_get_iova(int handle, int ion_fd,
+ dma_addr_t *paddr_ptr, size_t *len_ptr)
+{
+ int idx, rc = 0;
+ enum cam_smmu_buf_state buf_state;
+
+ if (!paddr_ptr || !len_ptr) {
+ pr_err("Error: Input pointers are invalid\n");
+ return -EINVAL;
+ }
+
+ if (handle == HANDLE_INIT) {
+ pr_err("Error: Invalid handle\n");
+ 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) {
+ pr_err("Error: handle or index invalid. idx = %d hdl = %x\n",
+ idx, handle);
+ return -EINVAL;
+ }
+
+ mutex_lock(&iommu_cb_set.cb_info[idx].lock);
+ if (iommu_cb_set.cb_info[idx].handle != handle) {
+ pr_err("Error: hdl is not valid, table_hdl = %x, hdl = %x\n",
+ iommu_cb_set.cb_info[idx].handle, handle);
+ rc = -EINVAL;
+ goto get_addr_end;
+ }
+
+ buf_state = cam_smmu_check_fd_in_list(idx, ion_fd, paddr_ptr, len_ptr);
+ if (buf_state == CAM_SMMU_BUFF_NOT_EXIST) {
+ CDBG("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_get_iova);
+
+int cam_smmu_unmap_sec_iova(int handle, int ion_fd)
+{
+ /* not implemented yet */
+ return -EPERM;
+}
+EXPORT_SYMBOL(cam_smmu_unmap_sec_iova);
+
+int cam_smmu_unmap_iova(int handle,
+ int ion_fd,
+ enum cam_smmu_region_id region_id)
+{
+ int idx, rc;
+ struct cam_dma_buff_info *mapping_info;
+
+ if (handle == HANDLE_INIT) {
+ pr_err("Error: Invalid handle\n");
+ return -EINVAL;
+ }
+
+ /* find index in the iommu_cb_set.cb_info */
+ idx = GET_SMMU_TABLE_IDX(handle);
+ if (idx < 0 || idx >= iommu_cb_set.cb_num) {
+ pr_err("Error: handle or index invalid. idx = %d hdl = %x\n",
+ idx, handle);
+ return -EINVAL;
+ }
+
+ mutex_lock(&iommu_cb_set.cb_info[idx].lock);
+ if (iommu_cb_set.cb_info[idx].handle != handle) {
+ pr_err("Error: hdl is not valid, table_hdl = %x, hdl = %x\n",
+ iommu_cb_set.cb_info[idx].handle, handle);
+ rc = -EINVAL;
+ goto unmap_end;
+ }
+
+ /* Based on ion fd and index, we can find mapping info of buffer */
+ mapping_info = cam_smmu_find_mapping_by_ion_index(idx, ion_fd);
+ if (!mapping_info) {
+ pr_err("Error: Invalid params! idx = %d, fd = %d\n",
+ idx, ion_fd);
+ rc = -EINVAL;
+ goto unmap_end;
+ }
+
+ mapping_info->ref_count--;
+ if (mapping_info->ref_count > 0) {
+ CDBG("There are still %u buffer(s) with same fd %d",
+ mapping_info->ref_count, mapping_info->ion_fd);
+ rc = 0;
+ goto unmap_end;
+ }
+
+ /* Unmapping one buffer from device */
+ CDBG("SMMU: removing buffer idx = %d\n", idx);
+ rc = cam_smmu_unmap_buf_and_remove_from_list(mapping_info, idx);
+ if (rc < 0)
+ pr_err("Error: unmap or remove list fail\n");
+
+unmap_end:
+ mutex_unlock(&iommu_cb_set.cb_info[idx].lock);
+ return rc;
+}
+EXPORT_SYMBOL(cam_smmu_unmap_iova);
+
+int cam_smmu_put_iova(int handle, int ion_fd)
+{
+ int idx;
+ int rc = 0;
+ struct cam_dma_buff_info *mapping_info;
+
+ if (handle == HANDLE_INIT) {
+ pr_err("Error: Invalid handle\n");
+ return -EINVAL;
+ }
+
+ /* find index in the iommu_cb_set.cb_info */
+ idx = GET_SMMU_TABLE_IDX(handle);
+ if (idx < 0 || idx >= iommu_cb_set.cb_num) {
+ pr_err("Error: handle or index invalid. idx = %d hdl = %x\n",
+ idx, handle);
+ return -EINVAL;
+ }
+
+ mutex_lock(&iommu_cb_set.cb_info[idx].lock);
+ if (iommu_cb_set.cb_info[idx].handle != handle) {
+ pr_err("Error: hdl is not valid, table_hdl = %x, hdl = %x\n",
+ iommu_cb_set.cb_info[idx].handle, handle);
+ rc = -EINVAL;
+ goto put_addr_end;
+ }
+
+ /* based on ion fd and index, we can find mapping info of buffer */
+ mapping_info = cam_smmu_find_mapping_by_ion_index(idx, ion_fd);
+ if (!mapping_info) {
+ pr_err("Error: Invalid params! idx = %d, fd = %d\n",
+ idx, ion_fd);
+ rc = -EINVAL;
+ goto put_addr_end;
+ }
+
+ mapping_info->ref_count--;
+
+put_addr_end:
+ mutex_unlock(&iommu_cb_set.cb_info[idx].lock);
+ return rc;
+}
+EXPORT_SYMBOL(cam_smmu_put_iova);
+
+int cam_smmu_destroy_handle(int handle)
+{
+ int idx;
+
+ if (handle == HANDLE_INIT) {
+ pr_err("Error: Invalid handle\n");
+ return -EINVAL;
+ }
+
+ idx = GET_SMMU_TABLE_IDX(handle);
+ if (idx < 0 || idx >= iommu_cb_set.cb_num) {
+ pr_err("Error: handle or index invalid. idx = %d hdl = %x\n",
+ idx, handle);
+ return -EINVAL;
+ }
+
+ mutex_lock(&iommu_cb_set.cb_info[idx].lock);
+ if (iommu_cb_set.cb_info[idx].handle != handle) {
+ pr_err("Error: hdl is not valid, table_hdl = %x, hdl = %x\n",
+ iommu_cb_set.cb_info[idx].handle, handle);
+ mutex_unlock(&iommu_cb_set.cb_info[idx].lock);
+ return -EINVAL;
+ }
+
+ if (!list_empty_careful(&iommu_cb_set.cb_info[idx].smmu_buf_list)) {
+ pr_err("Client %s buffer list is not clean!\n",
+ iommu_cb_set.cb_info[idx].name);
+ cam_smmu_print_list(idx);
+ cam_smmu_clean_buffer_list(idx);
+ }
+
+ 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;
+}
+EXPORT_SYMBOL(cam_smmu_destroy_handle);
+
+static void cam_smmu_deinit_cb(struct cam_context_bank_info *cb)
+{
+ arm_iommu_detach_device(cb->dev);
+
+ if (cb->io_support && cb->mapping) {
+ arm_iommu_release_mapping(cb->mapping);
+ cb->mapping = NULL;
+ }
+
+ if (cb->shared_support) {
+ gen_pool_destroy(cb->shared_mem_pool);
+ cb->shared_mem_pool = NULL;
+ }
+
+ if (cb->scratch_buf_support) {
+ kfree(cb->scratch_map.bitmap);
+ cb->scratch_map.bitmap = NULL;
+ }
+}
+
+static void cam_smmu_release_cb(struct platform_device *pdev)
+{
+ int i = 0;
+
+ for (i = 0; i < iommu_cb_set.cb_num; i++)
+ cam_smmu_deinit_cb(&iommu_cb_set.cb_info[i]);
+
+ devm_kfree(&pdev->dev, iommu_cb_set.cb_info);
+ iommu_cb_set.cb_num = 0;
+}
+
+static int cam_smmu_setup_cb(struct cam_context_bank_info *cb,
+ struct device *dev)
+{
+ int rc = 0;
+
+ if (!cb || !dev) {
+ pr_err("Error: invalid input params\n");
+ return -EINVAL;
+ }
+
+ cb->dev = dev;
+ cb->is_fw_allocated = false;
+
+ /* Create a pool with 4K granularity for supporting shared memory */
+ if (cb->shared_support) {
+ cb->shared_mem_pool = gen_pool_create(
+ SHARED_MEM_POOL_GRANULARITY, -1);
+
+ if (!cb->shared_mem_pool)
+ return -ENOMEM;
+
+ rc = gen_pool_add(cb->shared_mem_pool,
+ cb->shared_info.iova_start,
+ cb->shared_info.iova_len,
+ -1);
+
+ CDBG("Shared mem start->%lX\n",
+ (unsigned long)cb->shared_info.iova_start);
+ CDBG("Shared mem len->%zu\n", cb->shared_info.iova_len);
+
+ if (rc) {
+ pr_err("Genpool chunk creation failed\n");
+ gen_pool_destroy(cb->shared_mem_pool);
+ cb->shared_mem_pool = NULL;
+ return rc;
+ }
+ }
+
+ if (cb->scratch_buf_support) {
+ rc = cam_smmu_init_scratch_map(&cb->scratch_map,
+ cb->scratch_info.iova_start,
+ cb->scratch_info.iova_len,
+ 0);
+ if (rc < 0) {
+ pr_err("Error: failed to create scratch map\n");
+ rc = -ENODEV;
+ goto end;
+ }
+ }
+
+ /* create a virtual mapping */
+ if (cb->io_support) {
+ cb->mapping = arm_iommu_create_mapping(&platform_bus_type,
+ cb->io_info.iova_start, cb->io_info.iova_len);
+ if (IS_ERR(cb->mapping)) {
+ pr_err("Error: create mapping Failed\n");
+ rc = -ENODEV;
+ goto end;
+ }
+ } else {
+ pr_err("Context bank does not have IO region\n");
+ rc = -ENODEV;
+ goto end;
+ }
+
+ return rc;
+end:
+ if (cb->shared_support) {
+ gen_pool_destroy(cb->shared_mem_pool);
+ cb->shared_mem_pool = NULL;
+ }
+
+ if (cb->scratch_buf_support) {
+ kfree(cb->scratch_map.bitmap);
+ cb->scratch_map.bitmap = NULL;
+ }
+
+ return rc;
+}
+
+static int cam_alloc_smmu_context_banks(struct device *dev)
+{
+ struct device_node *domains_child_node = NULL;
+
+ if (!dev) {
+ pr_err("Error: Invalid device\n");
+ return -ENODEV;
+ }
+
+ iommu_cb_set.cb_num = 0;
+
+ /* traverse thru all the child nodes and increment the cb count */
+ for_each_available_child_of_node(dev->of_node, domains_child_node) {
+ if (of_device_is_compatible(domains_child_node,
+ "qcom,msm-cam-smmu-cb"))
+ iommu_cb_set.cb_num++;
+
+ if (of_device_is_compatible(domains_child_node,
+ "qcom,qsmmu-cam-cb"))
+ iommu_cb_set.cb_num++;
+ }
+
+ if (iommu_cb_set.cb_num == 0) {
+ pr_err("Error: no context banks present\n");
+ return -ENOENT;
+ }
+
+ /* allocate memory for the context banks */
+ iommu_cb_set.cb_info = devm_kzalloc(dev,
+ iommu_cb_set.cb_num * sizeof(struct cam_context_bank_info),
+ GFP_KERNEL);
+
+ if (!iommu_cb_set.cb_info) {
+ pr_err("Error: cannot allocate context banks\n");
+ return -ENOMEM;
+ }
+
+ cam_smmu_reset_iommu_table(CAM_SMMU_TABLE_INIT);
+ iommu_cb_set.cb_init_count = 0;
+
+ CDBG("no of context banks :%d\n", iommu_cb_set.cb_num);
+ return 0;
+}
+
+static int cam_smmu_get_memory_regions_info(struct device_node *of_node,
+ struct cam_context_bank_info *cb)
+{
+ int rc = 0;
+ struct device_node *mem_map_node = NULL;
+ struct device_node *child_node = NULL;
+ const char *region_name;
+ int num_regions = 0;
+
+ if (!of_node || !cb) {
+ pr_err("Invalid argument(s)\n");
+ return -EINVAL;
+ }
+
+ mem_map_node = of_get_child_by_name(of_node, "iova-mem-map");
+ if (!mem_map_node) {
+ pr_err("iova-mem-map not present\n");
+ return -EINVAL;
+ }
+
+ for_each_available_child_of_node(mem_map_node, child_node) {
+ uint32_t region_start;
+ uint32_t region_len;
+ uint32_t region_id;
+
+ num_regions++;
+ rc = of_property_read_string(child_node,
+ "iova-region-name", ®ion_name);
+ if (rc < 0) {
+ of_node_put(mem_map_node);
+ pr_err("IOVA region not found\n");
+ return -EINVAL;
+ }
+
+ rc = of_property_read_u32(child_node,
+ "iova-region-start", ®ion_start);
+ if (rc < 0) {
+ of_node_put(mem_map_node);
+ pr_err("Failed to read iova-region-start\n");
+ return -EINVAL;
+ }
+
+ rc = of_property_read_u32(child_node,
+ "iova-region-len", ®ion_len);
+ if (rc < 0) {
+ of_node_put(mem_map_node);
+ pr_err("Failed to read iova-region-len\n");
+ return -EINVAL;
+ }
+
+ rc = of_property_read_u32(child_node,
+ "iova-region-id", ®ion_id);
+ if (rc < 0) {
+ of_node_put(mem_map_node);
+ pr_err("Failed to read iova-region-id\n");
+ return -EINVAL;
+ }
+
+ switch (region_id) {
+ case CAM_SMMU_REGION_FIRMWARE:
+ cb->firmware_support = 1;
+ cb->firmware_info.iova_start = region_start;
+ cb->firmware_info.iova_len = region_len;
+ break;
+ case CAM_SMMU_REGION_SHARED:
+ cb->shared_support = 1;
+ cb->shared_info.iova_start = region_start;
+ cb->shared_info.iova_len = region_len;
+ break;
+ case CAM_SMMU_REGION_SCRATCH:
+ cb->scratch_buf_support = 1;
+ cb->scratch_info.iova_start = region_start;
+ cb->scratch_info.iova_len = region_len;
+ break;
+ case CAM_SMMU_REGION_IO:
+ cb->io_support = 1;
+ cb->io_info.iova_start = region_start;
+ cb->io_info.iova_len = region_len;
+ break;
+ default:
+ pr_err("Incorrect region id present in DT file: %d\n",
+ region_id);
+ }
+
+ CDBG("Found label -> %s\n", cb->name);
+ CDBG("Found region -> %s\n", region_name);
+ CDBG("region_start -> %X\n", region_start);
+ CDBG("region_len -> %X\n", region_len);
+ CDBG("region_id -> %X\n", region_id);
+ }
+ of_node_put(mem_map_node);
+
+ if (!num_regions) {
+ pr_err("No memory regions found, at least one needed\n");
+ rc = -ENODEV;
+ }
+
+ return rc;
+}
+
+static int cam_populate_smmu_context_banks(struct device *dev,
+ enum cam_iommu_type type)
+{
+ int rc = 0;
+ struct cam_context_bank_info *cb;
+ struct device *ctx = NULL;
+
+ if (!dev) {
+ pr_err("Error: Invalid device\n");
+ return -ENODEV;
+ }
+
+ /* check the bounds */
+ if (iommu_cb_set.cb_init_count >= iommu_cb_set.cb_num) {
+ pr_err("Error: populate more than allocated cb\n");
+ rc = -EBADHANDLE;
+ goto cb_init_fail;
+ }
+
+ /* read the context bank from cb set */
+ cb = &iommu_cb_set.cb_info[iommu_cb_set.cb_init_count];
+
+ /* set the name of the context bank */
+ rc = of_property_read_string(dev->of_node, "label", &cb->name);
+ if (rc < 0) {
+ pr_err("Error: failed to read label from sub device\n");
+ goto cb_init_fail;
+ }
+
+ rc = cam_smmu_get_memory_regions_info(dev->of_node,
+ cb);
+ if (rc < 0) {
+ pr_err("Error: Getting region info\n");
+ return rc;
+ }
+
+ /* set up the iommu mapping for the context bank */
+ if (type == CAM_QSMMU) {
+ pr_err("Error: QSMMU ctx not supported for : %s\n", cb->name);
+ return -ENODEV;
+ }
+
+ ctx = dev;
+ CDBG("getting Arm SMMU ctx : %s\n", cb->name);
+
+ rc = cam_smmu_setup_cb(cb, ctx);
+ if (rc < 0) {
+ pr_err("Error: failed to setup cb : %s\n", cb->name);
+ goto cb_init_fail;
+ }
+
+ if (cb->io_support && cb->mapping)
+ iommu_set_fault_handler(cb->mapping->domain,
+ cam_smmu_iommu_fault_handler,
+ (void *)cb->name);
+
+ /* increment count to next bank */
+ iommu_cb_set.cb_init_count++;
+
+ CDBG("X: cb init count :%d\n", iommu_cb_set.cb_init_count);
+
+cb_init_fail:
+ return rc;
+}
+
+static int cam_smmu_probe(struct platform_device *pdev)
+{
+ int rc = 0;
+ struct device *dev = &pdev->dev;
+
+ if (of_device_is_compatible(dev->of_node, "qcom,msm-cam-smmu")) {
+ rc = cam_alloc_smmu_context_banks(dev);
+ if (rc < 0) {
+ pr_err("Error: allocating context banks\n");
+ return -ENOMEM;
+ }
+ }
+ if (of_device_is_compatible(dev->of_node, "qcom,msm-cam-smmu-cb")) {
+ rc = cam_populate_smmu_context_banks(dev, CAM_ARM_SMMU);
+ if (rc < 0) {
+ pr_err("Error: populating context banks\n");
+ return -ENOMEM;
+ }
+ return rc;
+ }
+ if (of_device_is_compatible(dev->of_node, "qcom,qsmmu-cam-cb")) {
+ rc = cam_populate_smmu_context_banks(dev, CAM_QSMMU);
+ if (rc < 0) {
+ pr_err("Error: populating context banks\n");
+ return -ENOMEM;
+ }
+ return rc;
+ }
+
+ if (of_device_is_compatible(dev->of_node, "qcom,msm-cam-smmu-fw-dev")) {
+ icp_fw.fw_dev = &pdev->dev;
+ icp_fw.fw_kva = NULL;
+ icp_fw.fw_dma_hdl = 0;
+ return rc;
+ }
+
+ /* probe through all the subdevices */
+ rc = of_platform_populate(pdev->dev.of_node, msm_cam_smmu_dt_match,
+ NULL, &pdev->dev);
+ if (rc < 0) {
+ pr_err("Error: populating devices\n");
+ } else {
+ INIT_WORK(&iommu_cb_set.smmu_work, cam_smmu_page_fault_work);
+ mutex_init(&iommu_cb_set.payload_list_lock);
+ INIT_LIST_HEAD(&iommu_cb_set.payload_list);
+ }
+
+ return rc;
+}
+
+static int cam_smmu_remove(struct platform_device *pdev)
+{
+ /* release all the context banks and memory allocated */
+ cam_smmu_reset_iommu_table(CAM_SMMU_TABLE_DEINIT);
+ if (of_device_is_compatible(pdev->dev.of_node, "qcom,msm-cam-smmu"))
+ cam_smmu_release_cb(pdev);
+ return 0;
+}
+
+static struct platform_driver cam_smmu_driver = {
+ .probe = cam_smmu_probe,
+ .remove = cam_smmu_remove,
+ .driver = {
+ .name = "msm_cam_smmu",
+ .owner = THIS_MODULE,
+ .of_match_table = msm_cam_smmu_dt_match,
+ },
+};
+
+static int __init cam_smmu_init_module(void)
+{
+ return platform_driver_register(&cam_smmu_driver);
+}
+
+static void __exit cam_smmu_exit_module(void)
+{
+ platform_driver_unregister(&cam_smmu_driver);
+}
+
+module_init(cam_smmu_init_module);
+module_exit(cam_smmu_exit_module);
+MODULE_DESCRIPTION("MSM Camera SMMU driver");
+MODULE_LICENSE("GPL v2");
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
new file mode 100644
index 0000000..76e9135
--- /dev/null
+++ b/drivers/media/platform/msm/camera/cam_smmu/cam_smmu_api.h
@@ -0,0 +1,255 @@
+/* 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
+ * 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 _CAM_SMMU_API_H_
+#define _CAM_SMMU_API_H_
+
+#include <linux/dma-direction.h>
+#include <linux/module.h>
+#include <linux/dma-buf.h>
+#include <asm/dma-iommu.h>
+#include <linux/dma-direction.h>
+#include <linux/of_platform.h>
+#include <linux/iommu.h>
+#include <linux/random.h>
+#include <linux/spinlock_types.h>
+#include <linux/mutex.h>
+#include <linux/msm_ion.h>
+
+/*Enum for possible CAM SMMU operations */
+enum cam_smmu_ops_param {
+ CAM_SMMU_ATTACH,
+ CAM_SMMU_DETACH,
+ CAM_SMMU_VOTE,
+ CAM_SMMU_DEVOTE,
+ CAM_SMMU_OPS_INVALID
+};
+
+enum cam_smmu_map_dir {
+ CAM_SMMU_MAP_READ,
+ CAM_SMMU_MAP_WRITE,
+ CAM_SMMU_MAP_RW,
+ CAM_SMMU_MAP_INVALID
+};
+
+enum cam_smmu_region_id {
+ CAM_SMMU_REGION_FIRMWARE,
+ CAM_SMMU_REGION_SHARED,
+ CAM_SMMU_REGION_SCRATCH,
+ CAM_SMMU_REGION_IO
+};
+
+/**
+ * @brief : Gets an smmu handle
+ *
+ * @param identifier: Unique identifier to be used by clients which they
+ * should get from device tree. CAM SMMU driver will
+ * not enforce how this string is obtained and will
+ * only validate this against the list of permitted
+ * identifiers
+ * @param handle_ptr: Based on the indentifier, CAM SMMU drivier will
+ * fill the handle pointed by handle_ptr
+ * @return Status of operation. Negative in case of error. Zero otherwise.
+ */
+int cam_smmu_get_handle(char *identifier, int *handle_ptr);
+
+/**
+ * @brief : Performs IOMMU operations
+ *
+ * @param handle: Handle to identify the CAM SMMU client (VFE, CPP, FD etc.)
+ * @param op : Operation to be performed. Can be either CAM_SMMU_ATTACH
+ * or CAM_SMMU_DETACH
+ *
+ * @return Status of operation. Negative in case of error. Zero otherwise.
+ */
+int cam_smmu_ops(int handle, enum cam_smmu_ops_param op);
+
+/**
+ * @brief : Maps IOVA for calling driver
+ *
+ * @param handle: Handle to identify the CAM SMMU client (VFE, CPP, FD etc.)
+ * @param ion_fd: ION handle identifying the memory buffer.
+ * @dir : Mapping direction: which will traslate toDMA_BIDIRECTIONAL,
+ * DMA_TO_DEVICE or DMA_FROM_DEVICE
+ * @dma_addr : Pointer to physical address where mapped address will be
+ * returned if region_id is CAM_SMMU_REGION_IO. If region_id is
+ * CAM_SMMU_REGION_SHARED, dma_addr is used as an input parameter
+ * which specifies the cpu virtual address to map.
+ * @len : Length of buffer mapped returned by CAM SMMU driver.
+ * @return Status of operation. Negative in case of error. Zero otherwise.
+ */
+int cam_smmu_map_iova(int handle,
+ int ion_fd, enum cam_smmu_map_dir dir,
+ dma_addr_t *dma_addr, size_t *len_ptr,
+ enum cam_smmu_region_id region_id);
+
+/**
+ * @brief : Unmaps IOVA for calling driver
+ *
+ * @param handle: Handle to identify the CAMSMMU client (VFE, CPP, FD etc.)
+ * @param ion_fd: ION handle identifying the memory buffer.
+ *
+ * @return Status of operation. Negative in case of error. Zero otherwise.
+ */
+int cam_smmu_unmap_iova(int handle,
+ int ion_fd,
+ enum cam_smmu_region_id region_id);
+
+/**
+ * @brief : Allocates a scratch buffer
+ *
+ * This function allocates a scratch virtual buffer of length virt_len in the
+ * device virtual address space mapped to phys_len physically contiguous bytes
+ * in that device's SMMU.
+ *
+ * virt_len and phys_len are expected to be aligned to PAGE_SIZE and with each
+ * other, otherwise -EINVAL is returned.
+ *
+ * -EINVAL will be returned if virt_len is less than phys_len.
+ *
+ * Passing a too large phys_len might also cause failure if that much size is
+ * not available for allocation in a physically contiguous way.
+ *
+ * @param handle : Handle to identify the CAMSMMU client (VFE, CPP, FD etc.)
+ * @param dir : Direction of mapping which will translate to IOMMU_READ
+ * IOMMU_WRITE or a bit mask of both.
+ * @param paddr_ptr: Device virtual address that the client device will be
+ * able to read from/write to
+ * @param virt_len : Virtual length of the scratch buffer
+ * @param phys_len : Physical length of the scratch buffer
+ *
+ * @return Status of operation. Negative in case of error. Zero otherwise.
+ */
+
+int cam_smmu_get_scratch_iova(int handle,
+ enum cam_smmu_map_dir dir,
+ dma_addr_t *paddr_ptr,
+ size_t virt_len,
+ size_t phys_len);
+
+/**
+ * @brief : Frees a scratch buffer
+ *
+ * This function frees a scratch buffer and releases the corresponding SMMU
+ * mappings.
+ *
+ * @param handle : Handle to identify the CAMSMMU client (IFE, ICP, etc.)
+ * @param paddr : Device virtual address of client's scratch buffer that
+ * will be freed.
+ *
+ * @return Status of operation. Negative in case of error. Zero otherwise.
+ */
+
+int cam_smmu_put_scratch_iova(int handle,
+ dma_addr_t paddr);
+
+/**
+ *@brief : Destroys an smmu handle
+ *
+ * @param handle: Handle to identify the CAM SMMU client (VFE, CPP, FD etc.)
+ *
+ * @return Status of operation. Negative in case of error. Zero otherwise.
+ */
+int cam_smmu_destroy_handle(int handle);
+
+/**
+ * @brief : Finds index by handle in the smmu client table
+ *
+ * @param handle: Handle to identify the CAM SMMU client (VFE, CPP, FD etc.)
+ * @return Index of SMMU client. Nagative in case of error.
+ */
+int cam_smmu_find_index_by_handle(int hdl);
+
+/**
+ * @brief : Registers smmu fault handler for client
+ *
+ * @param handle: Handle to identify the CAM SMMU client (VFE, CPP, FD etc.)
+ * @param client_page_fault_handler: It is triggered in IOMMU page fault
+ * @param token: It is input param when trigger page fault handler
+ */
+void cam_smmu_reg_client_page_fault_handler(int handle,
+ void (*client_page_fault_handler)(struct iommu_domain *,
+ struct device *, unsigned long,
+ int, void*), void *token);
+
+/**
+ * @brief Maps memory from an ION fd into IOVA space
+ *
+ * @param handle: SMMU handle identifying the 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_iova(int handle, int ion_fd,
+ dma_addr_t *paddr_ptr, size_t *len_ptr);
+/**
+ * @brief Unmaps memory from context bank
+ *
+ * @param handle: SMMU handle identifying the context bank
+ * @param ion_fd: ION fd of memory to unmap
+ *
+ * @return Status of operation. Negative in case of error. Zero otherwise.
+ */
+int cam_smmu_put_iova(int handle, int ion_fd);
+
+/**
+ * @brief Maps secure memory for SMMU handle
+ *
+ * @param handle: SMMU handle identifying context bank
+ * @param ion_fd: ION fd to map securely
+ * @param dir: DMA Direction for the mapping
+ * @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);
+
+/**
+ * @brief Unmaps secure memopry for SMMU handle
+ *
+ * @param handle: SMMU handle identifying 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);
+
+
+/**
+ * @brief Allocates firmware for context bank
+ *
+ * @param smmu_hdl: SMMU handle identifying context bank
+ * @param iova: IOVA address of allocated firmware
+ * @param kvaddr: CPU mapped address of allocated firmware
+ * @param len: Length of allocated firmware memory
+ *
+ * @return Status of operation. Negative in case of error. Zero otherwise.
+ */
+int cam_smmu_alloc_firmware(int32_t smmu_hdl,
+ dma_addr_t *iova,
+ uint64_t *kvaddr,
+ size_t *len);
+
+/**
+ * @brief Deallocates firmware memory for context bank
+ *
+ * @param smmu_hdl: SMMU handle identifying the context bank
+ *
+ * @return Status of operation. Negative in case of error. Zero otherwise.
+ */
+int cam_smmu_dealloc_firmware(int32_t smmu_hdl);
+#endif /* _CAM_SMMU_API_H_ */
diff --git a/drivers/media/platform/msm/camera/cam_utils/cam_soc_util.c b/drivers/media/platform/msm/camera/cam_utils/cam_soc_util.c
index 683386c..b16e37e 100644
--- a/drivers/media/platform/msm/camera/cam_utils/cam_soc_util.c
+++ b/drivers/media/platform/msm/camera/cam_utils/cam_soc_util.c
@@ -412,6 +412,7 @@
goto put_regulator;
}
disable_irq(soc_info->irq_line->start);
+ soc_info->irq_data = irq_data;
}
/* Get Clock */
@@ -439,7 +440,8 @@
if (soc_info->irq_line) {
disable_irq(soc_info->irq_line->start);
- free_irq(soc_info->irq_line->start, soc_info);
+ devm_free_irq(&soc_info->pdev->dev,
+ soc_info->irq_line->start, irq_data);
}
put_regulator:
@@ -495,7 +497,8 @@
if (soc_info->irq_line) {
disable_irq(soc_info->irq_line->start);
- free_irq(soc_info->irq_line->start, soc_info);
+ devm_free_irq(&soc_info->pdev->dev,
+ soc_info->irq_line->start, soc_info->irq_data);
}
return 0;
diff --git a/drivers/media/platform/msm/camera/cam_utils/cam_soc_util.h b/drivers/media/platform/msm/camera/cam_utils/cam_soc_util.h
index 0baa9e6..3e8226f 100644
--- a/drivers/media/platform/msm/camera/cam_utils/cam_soc_util.h
+++ b/drivers/media/platform/msm/camera/cam_utils/cam_soc_util.h
@@ -58,6 +58,7 @@
* @index: Instance id for the camera device
* @irq_name: Name of the irq associated with the device
* @irq_line: Irq resource
+ * @irq_data: Private data that is passed when IRQ is requested
* @num_mem_block: Number of entry in the "reg-names"
* @mem_block_name: Array of the reg block name
* @mem_block_cam_base: Array of offset of this register space compared
@@ -85,6 +86,7 @@
const char *irq_name;
struct resource *irq_line;
+ void *irq_data;
uint32_t num_mem_block;
const char *mem_block_name[CAM_SOC_MAX_BLOCK];
diff --git a/drivers/media/platform/msm/sde/rotator/sde_rotator_base.h b/drivers/media/platform/msm/sde/rotator/sde_rotator_base.h
index a0b53bb..3bf6ce0 100644
--- a/drivers/media/platform/msm/sde/rotator/sde_rotator_base.h
+++ b/drivers/media/platform/msm/sde/rotator/sde_rotator_base.h
@@ -140,6 +140,18 @@
int domain;
};
+/*
+ * struct sde_rot_debug_bus: rotator debugbus header structure
+ * @wr_addr: write address for debugbus controller
+ * @block_id: rotator debugbus block id
+ * @test_id: rotator debugbus test id
+ */
+struct sde_rot_debug_bus {
+ u32 wr_addr;
+ u32 block_id;
+ u32 test_id;
+};
+
struct sde_rot_vbif_debug_bus {
u32 disable_bus_addr;
u32 block_bus_addr;
@@ -191,6 +203,8 @@
struct sde_rot_vbif_debug_bus *nrt_vbif_dbg_bus;
u32 nrt_vbif_dbg_bus_size;
+ struct sde_rot_debug_bus *rot_dbg_bus;
+ u32 rot_dbg_bus_size;
struct sde_rot_regdump *regdump;
u32 regdump_size;
@@ -199,6 +213,8 @@
int sec_cam_en;
struct ion_client *iclient;
+
+ bool clk_always_on;
};
int sde_rotator_base_init(struct sde_rot_data_type **pmdata,
diff --git a/drivers/media/platform/msm/sde/rotator/sde_rotator_debug.c b/drivers/media/platform/msm/sde/rotator/sde_rotator_debug.c
index e56c70a..e9ff67c 100644
--- a/drivers/media/platform/msm/sde/rotator/sde_rotator_debug.c
+++ b/drivers/media/platform/msm/sde/rotator/sde_rotator_debug.c
@@ -30,6 +30,7 @@
#define SDE_EVTLOG_DEFAULT_PANIC 1
#define SDE_EVTLOG_DEFAULT_REGDUMP SDE_ROT_DBG_DUMP_IN_MEM
#define SDE_EVTLOG_DEFAULT_VBIF_DBGBUSDUMP SDE_ROT_DBG_DUMP_IN_MEM
+#define SDE_EVTLOG_DEFAULT_ROT_DBGBUSDUMP SDE_ROT_DBG_DUMP_IN_MEM
/*
* evtlog will print this number of entries when it is called through
@@ -53,6 +54,8 @@
#define GROUP_BYTES 4
#define ROW_BYTES 16
+#define SDE_ROT_TEST_MASK(id, tp) ((id << 4) | (tp << 1) | BIT(0))
+
static DEFINE_SPINLOCK(sde_rot_xlock);
/*
@@ -86,11 +89,14 @@
* @panic_on_err - boolean indicates issue panic after EVTLOG dump
* @enable_reg_dump - control in-log/memory dump for rotator registers
* @enable_vbif_dbgbus_dump - control in-log/memory dump for VBIF debug bus
+ * @enable_rot_dbgbus_dump - control in-log/memroy dump for rotator debug bus
* @evtlog_dump_work - schedule work strucutre for timeout handler
* @work_dump_reg - storage for register dump control in schedule work
* @work_panic - storage for panic control in schedule work
* @work_vbif_dbgbus - storage for VBIF debug bus control in schedule work
+ * @work_rot_dbgbus - storage for rotator debug bus control in schedule work
* @nrt_vbif_dbgbus_dump - memory buffer for VBIF debug bus dumping
+ * @rot_dbgbus_dump - memory buffer for rotator debug bus dumping
* @reg_dump_array - memory buffer for rotator registers dumping
*/
struct sde_rot_dbg_evtlog {
@@ -103,14 +109,88 @@
u32 panic_on_err;
u32 enable_reg_dump;
u32 enable_vbif_dbgbus_dump;
+ u32 enable_rot_dbgbus_dump;
struct work_struct evtlog_dump_work;
bool work_dump_reg;
bool work_panic;
bool work_vbif_dbgbus;
+ bool work_rot_dbgbus;
u32 *nrt_vbif_dbgbus_dump; /* address for the nrt vbif debug bus dump */
+ u32 *rot_dbgbus_dump;
u32 *reg_dump_array[SDE_ROT_DEBUG_BASE_MAX];
} sde_rot_dbg_evtlog;
+static void sde_rot_dump_debug_bus(u32 bus_dump_flag, u32 **dump_mem)
+{
+ struct sde_rot_data_type *mdata = sde_rot_get_mdata();
+ bool in_log, in_mem;
+ u32 *dump_addr = NULL;
+ u32 status = 0;
+ struct sde_rot_debug_bus *head;
+ phys_addr_t phys = 0;
+ int i;
+ u32 offset;
+ void __iomem *base;
+
+ in_log = (bus_dump_flag & SDE_ROT_DBG_DUMP_IN_LOG);
+ in_mem = (bus_dump_flag & SDE_ROT_DBG_DUMP_IN_MEM);
+ base = mdata->sde_io.base;
+
+ if (!base || !mdata->rot_dbg_bus || !mdata->rot_dbg_bus_size)
+ return;
+
+ pr_info("======== SDE Rotator Debug bus DUMP =========\n");
+
+ if (in_mem) {
+ if (!(*dump_mem))
+ *dump_mem = dma_alloc_coherent(&mdata->pdev->dev,
+ mdata->rot_dbg_bus_size * 4 * sizeof(u32),
+ &phys, GFP_KERNEL);
+
+ if (*dump_mem) {
+ dump_addr = *dump_mem;
+ pr_info("%s: start_addr:0x%pK end_addr:0x%pK\n",
+ __func__, dump_addr,
+ dump_addr + (u32)mdata->rot_dbg_bus_size * 16);
+ } else {
+ in_mem = false;
+ pr_err("dump_mem: allocation fails\n");
+ }
+ }
+
+ sde_smmu_ctrl(1);
+
+ for (i = 0; i < mdata->rot_dbg_bus_size; i++) {
+ head = mdata->rot_dbg_bus + i;
+ writel_relaxed(SDE_ROT_TEST_MASK(head->block_id, head->test_id),
+ base + head->wr_addr);
+ wmb(); /* make sure test bits were written */
+
+ offset = head->wr_addr + 0x4;
+
+ status = readl_relaxed(base + offset);
+
+ if (in_log)
+ pr_err("waddr=0x%x blk=%d tst=%d val=0x%x\n",
+ head->wr_addr, head->block_id, head->test_id,
+ status);
+
+ if (dump_addr && in_mem) {
+ dump_addr[i*4] = head->wr_addr;
+ dump_addr[i*4 + 1] = head->block_id;
+ dump_addr[i*4 + 2] = head->test_id;
+ dump_addr[i*4 + 3] = status;
+ }
+
+ /* Disable debug bus once we are done */
+ writel_relaxed(0, base + head->wr_addr);
+ }
+
+ sde_smmu_ctrl(0);
+
+ pr_info("========End Debug bus=========\n");
+}
+
/*
* sde_rot_evtlog_is_enabled - helper function for checking EVTLOG
* enable/disable
@@ -518,18 +598,26 @@
* @dump_vbif_debug_bus: boolean indicates VBIF debug bus dump
*/
static void sde_rot_evtlog_dump_helper(bool dead, const char *panic_name,
- bool dump_rot, bool dump_vbif_debug_bus)
+ bool dump_rot, bool dump_vbif_debug_bus, bool dump_rot_debug_bus)
{
sde_rot_evtlog_dump_all();
- if (dump_rot)
- sde_rot_dump_reg_all();
+ if (dump_rot_debug_bus)
+ sde_rot_dump_debug_bus(
+ sde_rot_dbg_evtlog.enable_rot_dbgbus_dump,
+ &sde_rot_dbg_evtlog.rot_dbgbus_dump);
if (dump_vbif_debug_bus)
sde_rot_dump_vbif_debug_bus(
sde_rot_dbg_evtlog.enable_vbif_dbgbus_dump,
&sde_rot_dbg_evtlog.nrt_vbif_dbgbus_dump);
+ /*
+ * Rotator registers always dump last
+ */
+ if (dump_rot)
+ sde_rot_dump_reg_all();
+
if (dead)
panic(panic_name);
}
@@ -544,7 +632,8 @@
sde_rot_dbg_evtlog.work_panic,
"evtlog_workitem",
sde_rot_dbg_evtlog.work_dump_reg,
- sde_rot_dbg_evtlog.work_vbif_dbgbus);
+ sde_rot_dbg_evtlog.work_vbif_dbgbus,
+ sde_rot_dbg_evtlog.work_rot_dbgbus);
}
/*
@@ -569,6 +658,7 @@
bool dead = false;
bool dump_rot = false;
bool dump_vbif_dbgbus = false;
+ bool dump_rot_dbgbus = false;
char *blk_name = NULL;
va_list args;
@@ -590,6 +680,9 @@
if (!strcmp(blk_name, "vbif_dbg_bus"))
dump_vbif_dbgbus = true;
+ if (!strcmp(blk_name, "rot_dbg_bus"))
+ dump_rot_dbgbus = true;
+
if (!strcmp(blk_name, "panic"))
dead = true;
}
@@ -600,10 +693,11 @@
sde_rot_dbg_evtlog.work_panic = dead;
sde_rot_dbg_evtlog.work_dump_reg = dump_rot;
sde_rot_dbg_evtlog.work_vbif_dbgbus = dump_vbif_dbgbus;
+ sde_rot_dbg_evtlog.work_rot_dbgbus = dump_rot_dbgbus;
schedule_work(&sde_rot_dbg_evtlog.evtlog_dump_work);
} else {
sde_rot_evtlog_dump_helper(dead, name, dump_rot,
- dump_vbif_dbgbus);
+ dump_vbif_dbgbus, dump_rot_dbgbus);
}
}
@@ -836,6 +930,13 @@
return -EINVAL;
}
+ mdata->clk_always_on = false;
+ if (!debugfs_create_bool("clk_always_on", 0644,
+ debugfs_root, &mdata->clk_always_on)) {
+ SDEROT_WARN("failed to create debugfs clk_always_on\n");
+ return -EINVAL;
+ }
+
return 0;
}
@@ -919,12 +1020,16 @@
&sde_rot_dbg_evtlog.enable_reg_dump);
debugfs_create_u32("vbif_dbgbus_dump", 0644, sde_rot_dbg_evtlog.evtlog,
&sde_rot_dbg_evtlog.enable_vbif_dbgbus_dump);
+ debugfs_create_u32("rot_dbgbus_dump", 0644, sde_rot_dbg_evtlog.evtlog,
+ &sde_rot_dbg_evtlog.enable_rot_dbgbus_dump);
sde_rot_dbg_evtlog.evtlog_enable = SDE_EVTLOG_DEFAULT_ENABLE;
sde_rot_dbg_evtlog.panic_on_err = SDE_EVTLOG_DEFAULT_PANIC;
sde_rot_dbg_evtlog.enable_reg_dump = SDE_EVTLOG_DEFAULT_REGDUMP;
sde_rot_dbg_evtlog.enable_vbif_dbgbus_dump =
SDE_EVTLOG_DEFAULT_VBIF_DBGBUSDUMP;
+ sde_rot_dbg_evtlog.enable_rot_dbgbus_dump =
+ SDE_EVTLOG_DEFAULT_ROT_DBGBUSDUMP;
pr_info("evtlog_status: enable:%d, panic:%d, dump:%d\n",
sde_rot_dbg_evtlog.evtlog_enable,
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 1c94632..15ecc10 100644
--- a/drivers/media/platform/msm/sde/rotator/sde_rotator_dev.c
+++ b/drivers/media/platform/msm/sde/rotator/sde_rotator_dev.c
@@ -2594,8 +2594,13 @@
static long sde_rotator_compat_ioctl32(struct file *file,
unsigned int cmd, unsigned long arg)
{
+ struct video_device *vdev = video_devdata(file);
+ struct sde_rotator_ctx *ctx =
+ sde_rotator_ctx_from_fh(file->private_data);
long ret;
+ mutex_lock(vdev->lock);
+
switch (cmd) {
case VIDIOC_S_SDE_ROTATOR_FENCE:
case VIDIOC_G_SDE_ROTATOR_FENCE:
@@ -2604,14 +2609,14 @@
if (copy_from_user(&fence, (void __user *)arg,
sizeof(struct msm_sde_rotator_fence)))
- return -EFAULT;
+ goto ioctl32_error;
ret = sde_rotator_private_ioctl(file, file->private_data,
0, cmd, (void *)&fence);
if (copy_to_user((void __user *)arg, &fence,
sizeof(struct msm_sde_rotator_fence)))
- return -EFAULT;
+ goto ioctl32_error;
break;
}
@@ -2622,24 +2627,31 @@
if (copy_from_user(&comp_ratio, (void __user *)arg,
sizeof(struct msm_sde_rotator_comp_ratio)))
- return -EFAULT;
+ goto ioctl32_error;
ret = sde_rotator_private_ioctl(file, file->private_data,
0, cmd, (void *)&comp_ratio);
if (copy_to_user((void __user *)arg, &comp_ratio,
sizeof(struct msm_sde_rotator_comp_ratio)))
- return -EFAULT;
+ goto ioctl32_error;
break;
}
default:
+ SDEDEV_ERR(ctx->rot_dev->dev, "invalid ioctl32 type:%x\n", cmd);
ret = -ENOIOCTLCMD;
break;
}
+ mutex_unlock(vdev->lock);
return ret;
+
+ioctl32_error:
+ mutex_unlock(vdev->lock);
+ SDEDEV_ERR(ctx->rot_dev->dev, "error handling ioctl32 cmd:%x\n", cmd);
+ return -EFAULT;
}
#endif
diff --git a/drivers/media/platform/msm/sde/rotator/sde_rotator_r3.c b/drivers/media/platform/msm/sde/rotator/sde_rotator_r3.c
index a152573..8f2746d 100644
--- a/drivers/media/platform/msm/sde/rotator/sde_rotator_r3.c
+++ b/drivers/media/platform/msm/sde/rotator/sde_rotator_r3.c
@@ -385,11 +385,95 @@
};
static struct sde_rot_vbif_debug_bus nrt_vbif_dbg_bus_r3[] = {
- {0x214, 0x21c, 16, 1, 0x10}, /* arb clients */
+ {0x214, 0x21c, 16, 1, 0x200}, /* arb clients main */
{0x214, 0x21c, 0, 12, 0x13}, /* xin blocks - axi side */
{0x21c, 0x214, 0, 12, 0xc}, /* xin blocks - clock side */
};
+static struct sde_rot_debug_bus rot_dbgbus_r3[] = {
+ /*
+ * rottop - 0xA8850
+ */
+ /* REGDMA */
+ { 0XA8850, 0, 0 },
+ { 0XA8850, 0, 1 },
+ { 0XA8850, 0, 2 },
+ { 0XA8850, 0, 3 },
+ { 0XA8850, 0, 4 },
+
+ /* ROT_WB */
+ { 0XA8850, 1, 0 },
+ { 0XA8850, 1, 1 },
+ { 0XA8850, 1, 2 },
+ { 0XA8850, 1, 3 },
+ { 0XA8850, 1, 4 },
+ { 0XA8850, 1, 5 },
+ { 0XA8850, 1, 6 },
+ { 0XA8850, 1, 7 },
+
+ /* UBWC_DEC */
+ { 0XA8850, 2, 0 },
+
+ /* UBWC_ENC */
+ { 0XA8850, 3, 0 },
+
+ /* ROT_FETCH_0 */
+ { 0XA8850, 4, 0 },
+ { 0XA8850, 4, 1 },
+ { 0XA8850, 4, 2 },
+ { 0XA8850, 4, 3 },
+ { 0XA8850, 4, 4 },
+ { 0XA8850, 4, 5 },
+ { 0XA8850, 4, 6 },
+ { 0XA8850, 4, 7 },
+
+ /* ROT_FETCH_1 */
+ { 0XA8850, 5, 0 },
+ { 0XA8850, 5, 1 },
+ { 0XA8850, 5, 2 },
+ { 0XA8850, 5, 3 },
+ { 0XA8850, 5, 4 },
+ { 0XA8850, 5, 5 },
+ { 0XA8850, 5, 6 },
+ { 0XA8850, 5, 7 },
+
+ /* ROT_FETCH_2 */
+ { 0XA8850, 6, 0 },
+ { 0XA8850, 6, 1 },
+ { 0XA8850, 6, 2 },
+ { 0XA8850, 6, 3 },
+ { 0XA8850, 6, 4 },
+ { 0XA8850, 6, 5 },
+ { 0XA8850, 6, 6 },
+ { 0XA8850, 6, 7 },
+
+ /* ROT_FETCH_3 */
+ { 0XA8850, 7, 0 },
+ { 0XA8850, 7, 1 },
+ { 0XA8850, 7, 2 },
+ { 0XA8850, 7, 3 },
+ { 0XA8850, 7, 4 },
+ { 0XA8850, 7, 5 },
+ { 0XA8850, 7, 6 },
+ { 0XA8850, 7, 7 },
+
+ /* ROT_FETCH_4 */
+ { 0XA8850, 8, 0 },
+ { 0XA8850, 8, 1 },
+ { 0XA8850, 8, 2 },
+ { 0XA8850, 8, 3 },
+ { 0XA8850, 8, 4 },
+ { 0XA8850, 8, 5 },
+ { 0XA8850, 8, 6 },
+ { 0XA8850, 8, 7 },
+
+ /* ROT_UNPACK_0*/
+ { 0XA8850, 9, 0 },
+ { 0XA8850, 9, 1 },
+ { 0XA8850, 9, 2 },
+ { 0XA8850, 9, 3 },
+};
+
static struct sde_rot_regdump sde_rot_r3_regdump[] = {
{ "SDEROT_ROTTOP", SDE_ROT_ROTTOP_OFFSET, 0x100, SDE_ROT_REGDUMP_READ },
{ "SDEROT_SSPP", SDE_ROT_SSPP_OFFSET, 0x200, SDE_ROT_REGDUMP_READ },
@@ -1430,7 +1514,8 @@
sts = (status & ROT_ERROR_BIT) ? -ENODEV : 0;
if (status & ROT_ERROR_BIT)
- SDEROT_EVTLOG_TOUT_HANDLER("rot", "vbif_dbg_bus", "panic");
+ SDEROT_EVTLOG_TOUT_HANDLER("rot", "rot_dbg_bus",
+ "vbif_dbg_bus", "panic");
return sts;
}
@@ -1614,8 +1699,8 @@
SDEROT_ERR(
"Mismatch SWTS with HWTS: swts:0x%x, hwts:0x%x, regdma-sts:0x%x, rottop-sts:0x%x\n",
swts, hwts, regdmasts, rotsts);
- SDEROT_EVTLOG_TOUT_HANDLER("rot", "vbif_dbg_bus",
- "panic");
+ SDEROT_EVTLOG_TOUT_HANDLER("rot", "rot_dbg_bus",
+ "vbif_dbg_bus", "panic");
}
/* Turn off rotator clock after checking rotator registers */
@@ -2134,6 +2219,17 @@
SDE_VBIF_WRITE(mdata, MMSS_VBIF_NRT_VBIF_WRITE_GATHTER_EN,
BIT(XIN_WRITEBACK));
+ /*
+ * For debug purpose, disable clock gating, i.e. Clocks always on
+ */
+ if (mdata->clk_always_on) {
+ SDE_VBIF_WRITE(mdata, MMSS_VBIF_CLKON, 0x3);
+ SDE_VBIF_WRITE(mdata, MMSS_VBIF_NRT_VBIF_CLK_FORCE_CTRL0, 0x3);
+ SDE_VBIF_WRITE(mdata, MMSS_VBIF_NRT_VBIF_CLK_FORCE_CTRL1,
+ 0xFFFF);
+ SDE_ROTREG_WRITE(rot->mdss_base, ROTTOP_CLK_CTRL, 1);
+ }
+
return 0;
error:
@@ -2260,6 +2356,9 @@
mdata->nrt_vbif_dbg_bus_size =
ARRAY_SIZE(nrt_vbif_dbg_bus_r3);
+ mdata->rot_dbg_bus = rot_dbgbus_r3;
+ mdata->rot_dbg_bus_size = ARRAY_SIZE(rot_dbgbus_r3);
+
mdata->regdump = sde_rot_r3_regdump;
mdata->regdump_size = ARRAY_SIZE(sde_rot_r3_regdump);
SDE_ROTREG_WRITE(rot->mdss_base, REGDMA_TIMESTAMP_REG, 0);
diff --git a/drivers/media/platform/msm/vidc/hfi_packetization.c b/drivers/media/platform/msm/vidc/hfi_packetization.c
index 709f1d8..ac6ded0 100644
--- a/drivers/media/platform/msm/vidc/hfi_packetization.c
+++ b/drivers/media/platform/msm/vidc/hfi_packetization.c
@@ -1115,6 +1115,14 @@
pkt->size += sizeof(u32) * 2;
break;
}
+ case HAL_PARAM_SECURE:
+ {
+ create_pkt_enable(pkt->rg_property_data,
+ HFI_PROPERTY_PARAM_SECURE_SESSION,
+ ((struct hal_enable *)pdata)->enable);
+ pkt->size += sizeof(u32) * 2;
+ break;
+ }
case HAL_PARAM_VENC_SYNC_FRAME_SEQUENCE_HEADER:
{
create_pkt_enable(pkt->rg_property_data,
@@ -1799,6 +1807,34 @@
pkt->size += sizeof(u32) + sizeof(struct hfi_frame_size);
break;
}
+ case HAL_PARAM_VIDEO_CORES_USAGE:
+ {
+ struct hal_videocores_usage_info *hal = pdata;
+ struct hfi_videocores_usage_type *core_info =
+ (struct hfi_videocores_usage_type *)
+ &pkt->rg_property_data[1];
+
+ core_info->video_core_enable_mask = hal->video_core_enable_mask;
+
+ pkt->rg_property_data[0] =
+ HFI_PROPERTY_CONFIG_VIDEOCORES_USAGE;
+ pkt->size += sizeof(u32) + sizeof(*core_info);
+ break;
+ }
+ case HAL_PARAM_VIDEO_WORK_MODE:
+ {
+ struct hal_video_work_mode *hal = pdata;
+ struct hfi_video_work_mode *work_mode =
+ (struct hfi_video_work_mode *)
+ &pkt->rg_property_data[1];
+
+ work_mode->video_work_mode = hal->video_work_mode;
+
+ pkt->rg_property_data[0] =
+ HFI_PROPERTY_PARAM_WORK_MODE;
+ pkt->size += sizeof(u32) + sizeof(*work_mode);
+ break;
+ }
/* FOLLOWING PROPERTIES ARE NOT IMPLEMENTED IN CORE YET */
case HAL_CONFIG_BUFFER_REQUIREMENTS:
case HAL_CONFIG_PRIORITY:
diff --git a/drivers/media/platform/msm/vidc/hfi_response_handler.c b/drivers/media/platform/msm/vidc/hfi_response_handler.c
index 3378ff0..b424fbb 100644
--- a/drivers/media/platform/msm/vidc/hfi_response_handler.c
+++ b/drivers/media/platform/msm/vidc/hfi_response_handler.c
@@ -300,8 +300,8 @@
cmd_done.device_id = device_id;
cmd_done.session_id = (void *)(uintptr_t)pkt->session_id;
cmd_done.status = hfi_map_err_status(pkt->event_data1);
- dprintk(VIDC_INFO, "Received: SESSION_ERROR with event id : %d\n",
- pkt->event_data1);
+ dprintk(VIDC_INFO, "Received: SESSION_ERROR with event id : %#x %#x\n",
+ pkt->event_data1, pkt->event_data2);
switch (pkt->event_data1) {
case HFI_ERR_SESSION_INVALID_SCALE_FACTOR:
case HFI_ERR_SESSION_UNSUPPORT_BUFFERTYPE:
@@ -313,7 +313,9 @@
info->response.cmd = cmd_done;
return 0;
default:
- dprintk(VIDC_ERR, "HFI_EVENT_SESSION_ERROR\n");
+ dprintk(VIDC_ERR,
+ "HFI_EVENT_SESSION_ERROR: data1 %#x, data2 %#x\n",
+ pkt->event_data1, pkt->event_data2);
info->response_type = HAL_SESSION_ERROR;
info->response.cmd = cmd_done;
return 0;
diff --git a/drivers/media/platform/msm/vidc/msm_vdec.c b/drivers/media/platform/msm/vidc/msm_vdec.c
index b211175..3d3b7e9 100644
--- a/drivers/media/platform/msm/vidc/msm_vdec.c
+++ b/drivers/media/platform/msm/vidc/msm_vdec.c
@@ -564,6 +564,8 @@
inst->bufq[CAPTURE_PORT].plane_sizes[i] =
f->fmt.pix_mp.plane_fmt[i].sizeimage;
}
+
+ rc = msm_comm_try_get_bufreqs(inst);
} else if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
fmt = msm_comm_get_pixel_fmt_fourcc(vdec_formats,
@@ -776,7 +778,10 @@
msm_dcvs_try_enable(inst);
break;
case V4L2_CID_MPEG_VIDC_VIDEO_SECURE:
+ property_id = HAL_PARAM_SECURE;
inst->flags |= VIDC_SECURE;
+ property_val = !!(inst->flags & VIDC_SECURE);
+ pdata = &property_val;
dprintk(VIDC_DBG, "Setting secure mode to: %d\n",
!!(inst->flags & VIDC_SECURE));
break;
@@ -890,6 +895,7 @@
"Failed setting OUTPUT2 size : %d\n",
rc);
+ rc = msm_comm_try_get_bufreqs(inst);
break;
default:
dprintk(VIDC_ERR,
diff --git a/drivers/media/platform/msm/vidc/msm_venc.c b/drivers/media/platform/msm/vidc/msm_venc.c
index dccfe74..e198d8e 100644
--- a/drivers/media/platform/msm/vidc/msm_venc.c
+++ b/drivers/media/platform/msm/vidc/msm_venc.c
@@ -808,7 +808,7 @@
.name = "Layer ID for different settings",
.type = V4L2_CTRL_TYPE_INTEGER,
.minimum = 0,
- .maximum = 6,
+ .maximum = MSM_VIDC_ALL_LAYER_ID,
.default_value = 0,
.step = 1,
.qmenu = NULL,
@@ -1095,49 +1095,6 @@
return rc;
}
-static inline int msm_venc_power_save_mode_enable(struct msm_vidc_inst *inst)
-{
- u32 rc = 0;
- u32 prop_id = 0, power_save_min = 0, power_save_max = 0, inst_load = 0;
- void *pdata = NULL;
- struct hfi_device *hdev = NULL;
- enum hal_perf_mode venc_mode;
- enum load_calc_quirks quirks = LOAD_CALC_IGNORE_TURBO_LOAD |
- LOAD_CALC_IGNORE_THUMBNAIL_LOAD;
-
- if (!inst || !inst->core || !inst->core->device) {
- dprintk(VIDC_ERR, "%s invalid parameters\n", __func__);
- return -EINVAL;
- }
-
- inst_load = msm_comm_get_inst_load(inst, quirks);
- power_save_min = inst->capability.mbs_per_sec_power_save.min;
- power_save_max = inst->capability.mbs_per_sec_power_save.max;
-
- if (!power_save_min || !power_save_max)
- return rc;
-
- hdev = inst->core->device;
- if (inst_load >= power_save_min && inst_load <= power_save_max) {
- prop_id = HAL_CONFIG_VENC_PERF_MODE;
- venc_mode = HAL_PERF_MODE_POWER_SAVE;
- pdata = &venc_mode;
- rc = call_hfi_op(hdev, session_set_property,
- (void *)inst->session, prop_id, pdata);
- if (rc) {
- dprintk(VIDC_ERR,
- "%s: Failed to set power save mode for inst: %pK\n",
- __func__, inst);
- goto fail_power_mode_set;
- }
- inst->flags |= VIDC_LOW_POWER;
- dprintk(VIDC_INFO, "Power Save Mode set for inst: %pK\n", inst);
- }
-
-fail_power_mode_set:
- return rc;
-}
-
static struct v4l2_ctrl *get_ctrl_from_cluster(int id,
struct v4l2_ctrl **cluster, int ncontrols)
{
@@ -1265,7 +1222,7 @@
{
property_id = HAL_CONFIG_VENC_TARGET_BITRATE;
bitrate.bit_rate = ctrl->val;
- bitrate.layer_id = MSM_VIDC_ALL_LAYER_ID;
+ bitrate.layer_id = 0;
pdata = &bitrate;
inst->bitrate = ctrl->val;
break;
@@ -1544,6 +1501,9 @@
break;
case V4L2_CID_MPEG_VIDC_VIDEO_SECURE:
inst->flags |= VIDC_SECURE;
+ property_id = HAL_PARAM_SECURE;
+ property_val = !!(inst->flags & VIDC_SECURE);
+ pdata = &property_val;
dprintk(VIDC_INFO, "Setting secure mode to: %d\n",
!!(inst->flags & VIDC_SECURE));
break;
diff --git a/drivers/media/platform/msm/vidc/msm_vidc.c b/drivers/media/platform/msm/vidc/msm_vidc.c
index f160582..e071037 100644
--- a/drivers/media/platform/msm/vidc/msm_vidc.c
+++ b/drivers/media/platform/msm/vidc/msm_vidc.c
@@ -1018,12 +1018,6 @@
b->m.planes[i].m.userptr = buffer_info->uvaddr[i];
b->m.planes[i].reserved[0] = buffer_info->fd[i];
b->m.planes[i].reserved[1] = buffer_info->buff_off[i];
- if (!b->m.planes[i].m.userptr) {
- dprintk(VIDC_ERR,
- "%s: Failed to find user virtual address, %#lx, %d, %d\n",
- __func__, b->m.planes[i].m.userptr, b->type, i);
- return -EINVAL;
- }
}
if (!buffer_info) {
@@ -1296,14 +1290,6 @@
return rc;
}
-static inline int msm_vidc_decide_core_and_power_mode(
- struct msm_vidc_inst *inst)
-{
- dprintk(VIDC_DBG,
- "Core selection is not yet implemented for inst = %pK\n",
- inst);
- return 0;
-}
static inline int msm_vidc_verify_buffer_counts(struct msm_vidc_inst *inst)
{
int rc = 0, i = 0;
@@ -1364,15 +1350,22 @@
goto fail_start;
}
+ /* Decide work mode for current session */
+ rc = msm_vidc_decide_work_mode(inst);
+ if (rc) {
+ dprintk(VIDC_ERR,
+ "Failed to decide work mode for session %pK\n", inst);
+ goto fail_start;
+ }
+
/* Assign Core and LP mode for current session */
rc = msm_vidc_decide_core_and_power_mode(inst);
if (rc) {
dprintk(VIDC_ERR,
- "This session can't be submitted to HW%pK\n", inst);
+ "This session can't be submitted to HW %pK\n", inst);
goto fail_start;
}
-
if (msm_comm_get_stream_output_mode(inst) ==
HAL_VIDEO_DECODER_SECONDARY) {
b.buffer_type = HAL_BUFFER_OUTPUT2;
@@ -1387,7 +1380,7 @@
rc = msm_comm_try_get_bufreqs(inst);
- /* Check if current session is under HW capability */
+ /* Verify if buffer counts are correct */
rc = msm_vidc_verify_buffer_counts(inst);
if (rc) {
dprintk(VIDC_ERR,
@@ -1466,7 +1459,6 @@
return rc;
}
-
static int msm_vidc_start_streaming(struct vb2_queue *q, unsigned int count)
{
struct msm_vidc_inst *inst;
@@ -1980,6 +1972,7 @@
inst->state = MSM_VIDC_CORE_UNINIT_DONE;
inst->core = core;
inst->freq = 0;
+ inst->core_id = VIDC_CORE_ID_DEFAULT;
inst->bit_depth = MSM_VIDC_BIT_DEPTH_8;
inst->bitrate = 0;
inst->pic_struct = MSM_VIDC_PIC_STRUCT_PROGRESSIVE;
diff --git a/drivers/media/platform/msm/vidc/msm_vidc_clocks.c b/drivers/media/platform/msm/vidc/msm_vidc_clocks.c
index 1c78a45..d43ae5a 100644
--- a/drivers/media/platform/msm/vidc/msm_vidc_clocks.c
+++ b/drivers/media/platform/msm/vidc/msm_vidc_clocks.c
@@ -589,4 +589,288 @@
inst->dcvs.extra_capture_buffer_count;
}
+int msm_vidc_decide_work_mode(struct msm_vidc_inst *inst)
+{
+ int rc = 0;
+ bool low_latency_mode;
+ struct hfi_device *hdev;
+ struct hal_video_work_mode pdata;
+ struct hal_enable latency;
+
+ hdev = inst->core->device;
+
+ low_latency_mode = msm_comm_g_ctrl_for_id(inst,
+ V4L2_CID_MPEG_VIDC_VIDEO_LOWLATENCY_MODE);
+ if (low_latency_mode) {
+ pdata.video_work_mode = VIDC_WORK_MODE_1;
+ goto decision_done;
+ }
+
+ if (inst->session_type == MSM_VIDC_DECODER) {
+ pdata.video_work_mode = VIDC_WORK_MODE_2;
+ switch (inst->fmts[OUTPUT_PORT].fourcc) {
+ case V4L2_PIX_FMT_MPEG2:
+ pdata.video_work_mode = VIDC_WORK_MODE_1;
+ break;
+ case V4L2_PIX_FMT_H264:
+ case V4L2_PIX_FMT_HEVC:
+ if (inst->prop.height[OUTPUT_PORT] *
+ inst->prop.width[OUTPUT_PORT] <=
+ 1280 * 720)
+ pdata.video_work_mode = VIDC_WORK_MODE_1;
+ break;
+ }
+ } else if (inst->session_type == MSM_VIDC_ENCODER) {
+ u32 rc_mode = 0;
+
+ pdata.video_work_mode = VIDC_WORK_MODE_1;
+ rc_mode = msm_comm_g_ctrl_for_id(inst,
+ V4L2_CID_MPEG_VIDC_VIDEO_RATE_CONTROL);
+ if (rc_mode == V4L2_CID_MPEG_VIDC_VIDEO_RATE_CONTROL_VBR_VFR ||
+ rc_mode ==
+ V4L2_CID_MPEG_VIDC_VIDEO_RATE_CONTROL_VBR_CFR)
+ pdata.video_work_mode = VIDC_WORK_MODE_2;
+ } else {
+ return -EINVAL;
+ }
+
+decision_done:
+
+ inst->work_mode = pdata.video_work_mode;
+ rc = call_hfi_op(hdev, session_set_property,
+ (void *)inst->session, HAL_PARAM_VIDEO_WORK_MODE,
+ (void *)&pdata);
+ if (rc)
+ dprintk(VIDC_WARN,
+ " Failed to configure Work Mode %pK\n", inst);
+
+ /* For WORK_MODE_1, set Low Latency mode by default to HW. */
+
+ if (inst->work_mode == VIDC_WORK_MODE_1) {
+ latency.enable = 1;
+ rc = call_hfi_op(hdev, session_set_property,
+ (void *)inst->session, HAL_PARAM_VENC_LOW_LATENCY,
+ (void *)&latency);
+ }
+
+ rc = msm_comm_scale_clocks_and_bus(inst);
+
+ return rc;
+}
+
+static inline int msm_vidc_power_save_mode_enable(struct msm_vidc_inst *inst,
+ bool enable)
+{
+ u32 rc = 0, mbs_per_frame;
+ u32 prop_id = 0;
+ void *pdata = NULL;
+ struct hfi_device *hdev = NULL;
+ enum hal_perf_mode venc_mode;
+
+ hdev = inst->core->device;
+ if (inst->session_type != MSM_VIDC_ENCODER) {
+ dprintk(VIDC_DBG,
+ "%s : Not an encoder session. Nothing to do\n",
+ __func__);
+ return 0;
+ }
+ mbs_per_frame = msm_dcvs_get_mbs_per_frame(inst);
+ if (inst->core->resources.max_hq_mbs_per_frame > mbs_per_frame ||
+ inst->core->resources.max_hq_fps > inst->prop.fps) {
+ enable = true;
+ }
+
+ prop_id = HAL_CONFIG_VENC_PERF_MODE;
+ venc_mode = enable ? HAL_PERF_MODE_POWER_SAVE :
+ HAL_PERF_MODE_POWER_MAX_QUALITY;
+ pdata = &venc_mode;
+ rc = call_hfi_op(hdev, session_set_property,
+ (void *)inst->session, prop_id, pdata);
+ if (rc) {
+ dprintk(VIDC_ERR,
+ "%s: Failed to set power save mode for inst: %pK\n",
+ __func__, inst);
+ goto fail_power_mode_set;
+ }
+ inst->flags |= VIDC_LOW_POWER;
+ dprintk(VIDC_PROF, "Power Save Mode set for inst: %pK\n", inst);
+
+fail_power_mode_set:
+ return rc;
+}
+
+static int msm_vidc_move_core_to_power_save_mode(struct msm_vidc_core *core,
+ u32 core_id)
+{
+ struct msm_vidc_inst *inst = NULL;
+
+ if (!core) {
+ dprintk(VIDC_ERR, "Invalid args: %pK\n", core);
+ return -EINVAL;
+ }
+
+ dprintk(VIDC_PROF, "Core %d : Moving all inst to LP mode\n", core_id);
+ mutex_lock(&core->lock);
+ list_for_each_entry(inst, &core->instances, list) {
+ if (inst->core_id == core_id &&
+ inst->session_type == MSM_VIDC_ENCODER)
+ msm_vidc_power_save_mode_enable(inst, true);
+ }
+ mutex_unlock(&core->lock);
+
+ return 0;
+}
+
+static u32 get_core_load(struct msm_vidc_core *core,
+ u32 core_id, bool lp_mode)
+{
+ struct msm_vidc_inst *inst = NULL;
+ u32 current_inst_mbs_per_sec = 0, load = 0;
+
+ mutex_lock(&core->lock);
+ list_for_each_entry(inst, &core->instances, list) {
+ u32 cycles, lp_cycles;
+
+ if (!inst->core_id && core_id)
+ continue;
+ if (inst->session_type == MSM_VIDC_DECODER) {
+ cycles = lp_cycles = inst->entry->vpp_cycles;
+ } else if (inst->session_type == MSM_VIDC_ENCODER) {
+ lp_mode |= inst->flags & VIDC_LOW_POWER;
+ cycles = lp_mode ?
+ inst->entry->low_power_cycles :
+ inst->entry->vpp_cycles;
+ } else {
+ continue;
+ }
+ if (inst->core_id == 3)
+ cycles = cycles / 2;
+
+ current_inst_mbs_per_sec = msm_comm_get_inst_load(inst,
+ LOAD_CALC_NO_QUIRKS);
+ load += current_inst_mbs_per_sec * cycles;
+ }
+ mutex_unlock(&core->lock);
+
+ return load;
+}
+
+int msm_vidc_decide_core_and_power_mode(struct msm_vidc_inst *inst)
+{
+ int rc = 0, hier_mode = 0;
+ struct hfi_device *hdev;
+ struct msm_vidc_core *core;
+ unsigned long max_freq, lp_cycles = 0;
+ struct hal_videocores_usage_info core_info;
+ u32 core0_load = 0, core1_load = 0, core0_lp_load = 0,
+ core1_lp_load = 0;
+ u32 current_inst_load = 0, current_inst_lp_load = 0,
+ min_load = 0, min_lp_load = 0;
+ u32 min_core_id, min_lp_core_id;
+
+ core = inst->core;
+ hdev = core->device;
+ max_freq = msm_vidc_max_freq(inst);
+ inst->core_id = 0;
+
+ core0_load = get_core_load(core, VIDC_CORE_ID_1, false);
+ core1_load = get_core_load(core, VIDC_CORE_ID_2, false);
+ core0_lp_load = get_core_load(core, VIDC_CORE_ID_1, true);
+ core1_lp_load = get_core_load(core, VIDC_CORE_ID_2, true);
+
+ min_load = min(core0_load, core1_load);
+ min_core_id = core0_load < core1_load ?
+ VIDC_CORE_ID_1 : VIDC_CORE_ID_2;
+ min_lp_load = min(core0_lp_load, core1_lp_load);
+ min_lp_core_id = core0_lp_load < core1_lp_load ?
+ VIDC_CORE_ID_1 : VIDC_CORE_ID_2;
+
+ lp_cycles = inst->session_type == MSM_VIDC_ENCODER ?
+ inst->entry->low_power_cycles :
+ inst->entry->vpp_cycles;
+
+ current_inst_load = msm_comm_get_inst_load(inst, LOAD_CALC_NO_QUIRKS) *
+ inst->entry->vpp_cycles;
+
+ current_inst_lp_load = msm_comm_get_inst_load(inst,
+ LOAD_CALC_NO_QUIRKS) * lp_cycles;
+
+ dprintk(VIDC_DBG, "Core 0 Load = %d Core 1 Load = %d\n",
+ core0_load, core1_load);
+ dprintk(VIDC_DBG, "Core 0 LP Load = %d Core 1 LP Load = %d\n",
+ core0_lp_load, core1_lp_load);
+ dprintk(VIDC_DBG, "Max Load = %lu\n", max_freq);
+ dprintk(VIDC_DBG, "Current Load = %d Current LP Load = %d\n",
+ current_inst_load, current_inst_lp_load);
+
+ /* Hier mode can be normal HP or Hybrid HP. */
+
+ hier_mode = msm_comm_g_ctrl_for_id(inst,
+ V4L2_CID_MPEG_VIDC_VIDEO_HIER_P_NUM_LAYERS);
+ hier_mode |= msm_comm_g_ctrl_for_id(inst,
+ V4L2_CID_MPEG_VIDC_VIDEO_HYBRID_HIERP_MODE);
+
+ /* Try for preferred core based on settings. */
+ if (inst->session_type == MSM_VIDC_ENCODER && hier_mode) {
+ if (current_inst_load / 2 + core0_load <= max_freq &&
+ current_inst_load / 2 + core1_load <= max_freq) {
+ inst->core_id = VIDC_CORE_ID_3;
+ msm_vidc_power_save_mode_enable(inst, false);
+ goto decision_done;
+ }
+ }
+
+ if (inst->session_type == MSM_VIDC_ENCODER && hier_mode) {
+ if (current_inst_lp_load / 2 +
+ core0_lp_load <= max_freq &&
+ current_inst_lp_load / 2 +
+ core1_lp_load <= max_freq) {
+ inst->core_id = VIDC_CORE_ID_3;
+ msm_vidc_power_save_mode_enable(inst, true);
+ goto decision_done;
+ }
+ }
+
+ if (current_inst_load + min_load < max_freq) {
+ inst->core_id = min_core_id;
+ dprintk(VIDC_DBG,
+ "Selected normally : Core ID = %d\n",
+ inst->core_id);
+ msm_vidc_power_save_mode_enable(inst, false);
+ } else if (current_inst_lp_load + min_load < max_freq) {
+ /* Move current instance to LP and return */
+ inst->core_id = min_core_id;
+ dprintk(VIDC_DBG,
+ "Selected by moving current to LP : Core ID = %d\n",
+ inst->core_id);
+ msm_vidc_power_save_mode_enable(inst, true);
+
+ } else if (current_inst_lp_load + min_lp_load < max_freq) {
+ /* Move all instances to LP mode and return */
+ inst->core_id = min_lp_core_id;
+ dprintk(VIDC_DBG,
+ "Moved all inst's to LP: Core ID = %d\n",
+ inst->core_id);
+ msm_vidc_move_core_to_power_save_mode(core, min_lp_core_id);
+ } else {
+ rc = -EINVAL;
+ dprintk(VIDC_ERR,
+ "Sorry ... Core Can't support this load\n");
+ return rc;
+ }
+
+decision_done:
+ core_info.video_core_enable_mask = inst->core_id;
+
+ rc = call_hfi_op(hdev, session_set_property,
+ (void *)inst->session,
+ HAL_PARAM_VIDEO_CORES_USAGE, &core_info);
+ if (rc)
+ dprintk(VIDC_WARN,
+ " Failed to configure CORE ID %pK\n", inst);
+
+ rc = msm_comm_scale_clocks_and_bus(inst);
+
+ return rc;
+}
diff --git a/drivers/media/platform/msm/vidc/msm_vidc_clocks.h b/drivers/media/platform/msm/vidc/msm_vidc_clocks.h
index 79fd8f6..d01f074 100644
--- a/drivers/media/platform/msm/vidc/msm_vidc_clocks.h
+++ b/drivers/media/platform/msm/vidc/msm_vidc_clocks.h
@@ -38,6 +38,8 @@
int msm_comm_scale_clocks_and_bus(struct msm_vidc_inst *inst);
int msm_comm_init_clocks_and_bus_data(struct msm_vidc_inst *inst);
void msm_comm_free_freq_table(struct msm_vidc_inst *inst);
+int msm_vidc_decide_work_mode(struct msm_vidc_inst *inst);
+int msm_vidc_decide_core_and_power_mode(struct msm_vidc_inst *inst);
void msm_vidc_clear_freq_entry(struct msm_vidc_inst *inst,
ion_phys_addr_t device_addr);
diff --git a/drivers/media/platform/msm/vidc/msm_vidc_common.c b/drivers/media/platform/msm/vidc/msm_vidc_common.c
index 78e499b..853edf5 100644
--- a/drivers/media/platform/msm/vidc/msm_vidc_common.c
+++ b/drivers/media/platform/msm/vidc/msm_vidc_common.c
@@ -3990,7 +3990,7 @@
static int msm_vidc_update_host_buff_counts(struct msm_vidc_inst *inst)
{
- int extra_buffers, buffer_type;
+ int extra_buffers;
struct hal_buffer_requirements *bufreq;
bufreq = get_buff_req_buffer(inst,
@@ -3998,7 +3998,7 @@
if (!bufreq) {
dprintk(VIDC_ERR,
"Failed : No buffer requirements : %x\n",
- HAL_BUFFER_INPUT);
+ HAL_BUFFER_INPUT);
return -EINVAL;
}
extra_buffers = msm_vidc_get_extra_buff_count(inst, HAL_BUFFER_INPUT);
@@ -4006,21 +4006,55 @@
bufreq->buffer_count_min_host = bufreq->buffer_count_min +
extra_buffers;
- buffer_type = msm_comm_get_hal_output_buffer(inst);
- bufreq = get_buff_req_buffer(inst,
- buffer_type);
- if (!bufreq) {
- dprintk(VIDC_ERR,
- "Failed : No buffer requirements : %x\n",
- buffer_type);
- return -EINVAL;
+ if (msm_comm_get_stream_output_mode(inst) ==
+ HAL_VIDEO_DECODER_SECONDARY) {
+
+ bufreq = get_buff_req_buffer(inst,
+ HAL_BUFFER_OUTPUT);
+ if (!bufreq) {
+ dprintk(VIDC_ERR,
+ "Failed : No buffer requirements : %x\n",
+ HAL_BUFFER_OUTPUT);
+ return -EINVAL;
+ }
+
+ /* For DPB buffers, no need to add Extra buffers */
+
+ bufreq->buffer_count_actual = bufreq->buffer_count_min_host =
+ bufreq->buffer_count_min;
+
+ bufreq = get_buff_req_buffer(inst,
+ HAL_BUFFER_OUTPUT2);
+ if (!bufreq) {
+ dprintk(VIDC_ERR,
+ "Failed : No buffer requirements : %x\n",
+ HAL_BUFFER_OUTPUT2);
+ return -EINVAL;
+ }
+
+ extra_buffers = msm_vidc_get_extra_buff_count(inst,
+ HAL_BUFFER_OUTPUT);
+
+ bufreq->buffer_count_min_host =
+ bufreq->buffer_count_min + extra_buffers;
+ } else {
+
+ bufreq = get_buff_req_buffer(inst,
+ HAL_BUFFER_OUTPUT);
+ if (!bufreq) {
+ dprintk(VIDC_ERR,
+ "Failed : No buffer requirements : %x\n",
+ HAL_BUFFER_OUTPUT);
+ return -EINVAL;
+ }
+
+ extra_buffers = msm_vidc_get_extra_buff_count(inst,
+ HAL_BUFFER_OUTPUT);
+
+ bufreq->buffer_count_actual = bufreq->buffer_count_min_host =
+ bufreq->buffer_count_min + extra_buffers;
}
- extra_buffers = msm_vidc_get_extra_buff_count(inst, buffer_type);
-
- bufreq->buffer_count_min_host = bufreq->buffer_count_min +
- extra_buffers;
-
return 0;
}
@@ -5345,21 +5379,18 @@
goto exit;
}
- if (inst->prop.fps != fps) {
- dprintk(VIDC_PROF, "reported fps changed for %pK: %d->%d\n",
- inst, inst->prop.fps, fps);
- inst->prop.fps = fps;
+ dprintk(VIDC_PROF, "reported fps changed for %pK: %d->%d\n",
+ inst, inst->prop.fps, fps);
+ inst->prop.fps = fps;
+ if (inst->session_type == MSM_VIDC_ENCODER) {
frame_rate.frame_rate = inst->prop.fps * BIT(16);
frame_rate.buffer_type = HAL_BUFFER_OUTPUT;
pdata = &frame_rate;
- if (inst->session_type == MSM_VIDC_ENCODER) {
- rc = call_hfi_op(hdev, session_set_property,
- inst->session, property_id, pdata);
-
- if (rc)
- dprintk(VIDC_WARN,
- "Failed to set frame rate %d\n", rc);
- }
+ rc = call_hfi_op(hdev, session_set_property,
+ inst->session, property_id, pdata);
+ if (rc)
+ dprintk(VIDC_WARN,
+ "Failed to set frame rate %d\n", rc);
}
exit:
return rc;
diff --git a/drivers/media/platform/msm/vidc/msm_vidc_internal.h b/drivers/media/platform/msm/vidc/msm_vidc_internal.h
index 4b91193..53bc068 100644
--- a/drivers/media/platform/msm/vidc/msm_vidc_internal.h
+++ b/drivers/media/platform/msm/vidc/msm_vidc_internal.h
@@ -313,6 +313,8 @@
u32 level;
u32 entropy_mode;
struct clock_profile_entry *entry;
+ u32 core_id;
+ enum hal_work_mode work_mode;
};
extern struct msm_vidc_drv *vidc_driver;
diff --git a/drivers/media/platform/msm/vidc/msm_vidc_res_parse.c b/drivers/media/platform/msm/vidc/msm_vidc_res_parse.c
index 763c41d..0a6de41 100644
--- a/drivers/media/platform/msm/vidc/msm_vidc_res_parse.c
+++ b/drivers/media/platform/msm/vidc/msm_vidc_res_parse.c
@@ -940,6 +940,24 @@
goto err_load_max_hw_load;
}
+ rc = of_property_read_u32(pdev->dev.of_node,
+ "qcom,max-hq-mbs-per-frame",
+ &res->max_hq_mbs_per_frame);
+ if (rc) {
+ dprintk(VIDC_ERR,
+ "Failed to determine Max HQ mbs per frame: %d\n", rc);
+ goto err_load_HQ_values;
+ }
+
+ rc = of_property_read_u32(pdev->dev.of_node,
+ "qcom,max-hq-frames-per-sec",
+ &res->max_hq_fps);
+ if (rc) {
+ dprintk(VIDC_ERR,
+ "Failed to determine Max HQ fps: %d\n", rc);
+ goto err_load_HQ_values;
+ }
+
rc = msm_vidc_populate_legacy_context_bank(res);
if (rc) {
dprintk(VIDC_ERR,
@@ -985,6 +1003,7 @@
return rc;
err_setup_legacy_cb:
+err_load_HQ_values:
err_load_max_hw_load:
msm_vidc_free_allowed_clocks_table(res);
err_load_allowed_clocks_table:
diff --git a/drivers/media/platform/msm/vidc/msm_vidc_resources.h b/drivers/media/platform/msm/vidc/msm_vidc_resources.h
index 8fd43006..20b0ffc 100644
--- a/drivers/media/platform/msm/vidc/msm_vidc_resources.h
+++ b/drivers/media/platform/msm/vidc/msm_vidc_resources.h
@@ -165,6 +165,8 @@
uint32_t imem_size;
enum imem_type imem_type;
uint32_t max_load;
+ uint32_t max_hq_mbs_per_frame;
+ uint32_t max_hq_fps;
struct platform_device *pdev;
struct regulator_set regulator_set;
struct clock_set clock_set;
diff --git a/drivers/media/platform/msm/vidc/venus_hfi.c b/drivers/media/platform/msm/vidc/venus_hfi.c
index bfe3790..1a1078d 100644
--- a/drivers/media/platform/msm/vidc/venus_hfi.c
+++ b/drivers/media/platform/msm/vidc/venus_hfi.c
@@ -1394,12 +1394,6 @@
__strict_check(device);
- if (!__core_in_valid_state(device)) {
- dprintk(VIDC_DBG, "%s - fw not in init state\n", __func__);
- rc = -EINVAL;
- goto dbg_error_null;
- }
-
if (device->iface_queues[VIDC_IFACEQ_DBGQ_IDX].
q_array.align_virtual_addr == 0) {
dprintk(VIDC_ERR, "cannot read from shared DBG Q's\n");
@@ -1971,6 +1965,8 @@
if (device->res->pm_qos_latency_us &&
pm_qos_request_active(&device->qos))
pm_qos_remove_request(&device->qos);
+
+ __resume(device);
__set_state(device, VENUS_STATE_DEINIT);
__unload_fw(device);
@@ -4060,6 +4056,8 @@
__venus_power_off(device);
device->resources.fw.cookie = NULL;
__deinit_resources(device);
+
+ dprintk(VIDC_PROF, "Firmware unloaded successfully\n");
}
static int venus_hfi_get_fw_info(void *dev, struct hal_fw_info *fw_info)
diff --git a/drivers/media/platform/msm/vidc/vidc_hfi_api.h b/drivers/media/platform/msm/vidc/vidc_hfi_api.h
index 28bb7ab..f8e0a6a 100644
--- a/drivers/media/platform/msm/vidc/vidc_hfi_api.h
+++ b/drivers/media/platform/msm/vidc/vidc_hfi_api.h
@@ -221,6 +221,9 @@
HAL_PARAM_VENC_H264_TRANSFORM_8x8,
HAL_PARAM_VENC_VIDEO_SIGNAL_INFO,
HAL_PARAM_VENC_IFRAMESIZE_TYPE,
+ HAL_PARAM_VIDEO_CORES_USAGE,
+ HAL_PARAM_VIDEO_WORK_MODE,
+ HAL_PARAM_SECURE,
};
enum hal_domain {
@@ -819,6 +822,28 @@
u32 enable;
};
+enum hal_core_id {
+ VIDC_CORE_ID_DEFAULT = 0,
+ VIDC_CORE_ID_1 = 1, /* 0b01 */
+ VIDC_CORE_ID_2 = 2, /* 0b10 */
+ VIDC_CORE_ID_3 = 3, /* 0b11 */
+ VIDC_CORE_ID_UNUSED = 0x10000000,
+};
+
+struct hal_videocores_usage_info {
+ u32 video_core_enable_mask;
+};
+
+enum hal_work_mode {
+ VIDC_WORK_MODE_1,
+ VIDC_WORK_MODE_2,
+ VIDC_WORK_MODE_UNUSED = 0x10000000,
+};
+
+struct hal_video_work_mode {
+ u32 video_work_mode;
+};
+
struct hal_vpe_color_space_conversion {
u32 csc_matrix[HAL_MAX_MATRIX_COEFFS];
u32 csc_bias[HAL_MAX_BIAS_COEFFS];
diff --git a/drivers/media/platform/msm/vidc/vidc_hfi_helper.h b/drivers/media/platform/msm/vidc/vidc_hfi_helper.h
index bc7e8bd..d6c4bcb 100644
--- a/drivers/media/platform/msm/vidc/vidc_hfi_helper.h
+++ b/drivers/media/platform/msm/vidc/vidc_hfi_helper.h
@@ -163,6 +163,9 @@
#define HFI_VENC_PERFMODE_MAX_QUALITY 0x1
#define HFI_VENC_PERFMODE_POWER_SAVE 0x2
+#define HFI_WORKMODE_1 (HFI_COMMON_BASE + 0x1)
+#define HFI_WORKMODE_2 (HFI_COMMON_BASE + 0x2)
+
struct hfi_buffer_info {
u32 buffer_addr;
u32 extra_data_addr;
@@ -215,11 +218,17 @@
(HFI_PROPERTY_PARAM_COMMON_START + 0x00E)
#define HFI_PROPERTY_PARAM_MAX_SESSIONS_SUPPORTED \
(HFI_PROPERTY_PARAM_COMMON_START + 0x010)
+#define HFI_PROPERTY_PARAM_SECURE_SESSION \
+ (HFI_PROPERTY_PARAM_COMMON_START + 0x011)
+#define HFI_PROPERTY_PARAM_WORK_MODE \
+ (HFI_PROPERTY_PARAM_COMMON_START + 0x015)
#define HFI_PROPERTY_CONFIG_COMMON_START \
(HFI_DOMAIN_BASE_COMMON + HFI_ARCH_COMMON_OFFSET + 0x2000)
#define HFI_PROPERTY_CONFIG_FRAME_RATE \
(HFI_PROPERTY_CONFIG_COMMON_START + 0x001)
+#define HFI_PROPERTY_CONFIG_VIDEOCORES_USAGE \
+ (HFI_PROPERTY_CONFIG_COMMON_START + 0x002)
#define HFI_PROPERTY_PARAM_VDEC_COMMON_START \
(HFI_DOMAIN_BASE_VDEC + HFI_ARCH_COMMON_OFFSET + 0x3000)
@@ -561,6 +570,14 @@
u32 height;
};
+struct hfi_videocores_usage_type {
+ u32 video_core_enable_mask;
+};
+
+struct hfi_video_work_mode {
+ u32 video_work_mode;
+};
+
struct hfi_video_signal_metadata {
u32 enable;
u32 video_format;
diff --git a/drivers/media/usb/dvb-usb-v2/dvb_usb_core.c b/drivers/media/usb/dvb-usb-v2/dvb_usb_core.c
index a8e6624..a9bb2dd 100644
--- a/drivers/media/usb/dvb-usb-v2/dvb_usb_core.c
+++ b/drivers/media/usb/dvb-usb-v2/dvb_usb_core.c
@@ -1013,8 +1013,8 @@
void dvb_usbv2_disconnect(struct usb_interface *intf)
{
struct dvb_usb_device *d = usb_get_intfdata(intf);
- const char *name = d->name;
- struct device dev = d->udev->dev;
+ const char *devname = kstrdup(dev_name(&d->udev->dev), GFP_KERNEL);
+ const char *drvname = d->name;
dev_dbg(&d->udev->dev, "%s: bInterfaceNumber=%d\n", __func__,
intf->cur_altsetting->desc.bInterfaceNumber);
@@ -1024,8 +1024,9 @@
dvb_usbv2_exit(d);
- dev_info(&dev, "%s: '%s' successfully deinitialized and disconnected\n",
- KBUILD_MODNAME, name);
+ pr_info("%s: '%s:%s' successfully deinitialized and disconnected\n",
+ KBUILD_MODNAME, drvname, devname);
+ kfree(devname);
}
EXPORT_SYMBOL(dvb_usbv2_disconnect);
diff --git a/drivers/media/usb/dvb-usb/cxusb.c b/drivers/media/usb/dvb-usb/cxusb.c
index 2434030..9fd43a3 100644
--- a/drivers/media/usb/dvb-usb/cxusb.c
+++ b/drivers/media/usb/dvb-usb/cxusb.c
@@ -59,23 +59,24 @@
u8 cmd, u8 *wbuf, int wlen, u8 *rbuf, int rlen)
{
struct cxusb_state *st = d->priv;
- int ret, wo;
+ int ret;
if (1 + wlen > MAX_XFER_SIZE) {
warn("i2c wr: len=%d is too big!\n", wlen);
return -EOPNOTSUPP;
}
- wo = (rbuf == NULL || rlen == 0); /* write-only */
+ if (rlen > MAX_XFER_SIZE) {
+ warn("i2c rd: len=%d is too big!\n", rlen);
+ return -EOPNOTSUPP;
+ }
mutex_lock(&d->data_mutex);
st->data[0] = cmd;
memcpy(&st->data[1], wbuf, wlen);
- if (wo)
- ret = dvb_usb_generic_write(d, st->data, 1 + wlen);
- else
- ret = dvb_usb_generic_rw(d, st->data, 1 + wlen,
- rbuf, rlen, 0);
+ ret = dvb_usb_generic_rw(d, st->data, 1 + wlen, st->data, rlen, 0);
+ if (!ret && rbuf && rlen)
+ memcpy(rbuf, st->data, rlen);
mutex_unlock(&d->data_mutex);
return ret;
diff --git a/drivers/media/usb/dvb-usb/dvb-usb-firmware.c b/drivers/media/usb/dvb-usb/dvb-usb-firmware.c
index dd048a7..b8d2ac5 100644
--- a/drivers/media/usb/dvb-usb/dvb-usb-firmware.c
+++ b/drivers/media/usb/dvb-usb/dvb-usb-firmware.c
@@ -35,42 +35,51 @@
int usb_cypress_load_firmware(struct usb_device *udev, const struct firmware *fw, int type)
{
- struct hexline hx;
- u8 reset;
- int ret,pos=0;
+ struct hexline *hx;
+ u8 *buf;
+ int ret, pos = 0;
+ u16 cpu_cs_register = cypress[type].cpu_cs_register;
+
+ buf = kmalloc(sizeof(*hx), GFP_KERNEL);
+ if (!buf)
+ return -ENOMEM;
+ hx = (struct hexline *)buf;
/* stop the CPU */
- reset = 1;
- if ((ret = usb_cypress_writemem(udev,cypress[type].cpu_cs_register,&reset,1)) != 1)
+ buf[0] = 1;
+ if (usb_cypress_writemem(udev, cpu_cs_register, buf, 1) != 1)
err("could not stop the USB controller CPU.");
- while ((ret = dvb_usb_get_hexline(fw,&hx,&pos)) > 0) {
- deb_fw("writing to address 0x%04x (buffer: 0x%02x %02x)\n",hx.addr,hx.len,hx.chk);
- ret = usb_cypress_writemem(udev,hx.addr,hx.data,hx.len);
+ while ((ret = dvb_usb_get_hexline(fw, hx, &pos)) > 0) {
+ deb_fw("writing to address 0x%04x (buffer: 0x%02x %02x)\n", hx->addr, hx->len, hx->chk);
+ ret = usb_cypress_writemem(udev, hx->addr, hx->data, hx->len);
- if (ret != hx.len) {
+ if (ret != hx->len) {
err("error while transferring firmware "
"(transferred size: %d, block size: %d)",
- ret,hx.len);
+ ret, hx->len);
ret = -EINVAL;
break;
}
}
if (ret < 0) {
err("firmware download failed at %d with %d",pos,ret);
+ kfree(buf);
return ret;
}
if (ret == 0) {
/* restart the CPU */
- reset = 0;
- if (ret || usb_cypress_writemem(udev,cypress[type].cpu_cs_register,&reset,1) != 1) {
+ buf[0] = 0;
+ if (usb_cypress_writemem(udev, cpu_cs_register, buf, 1) != 1) {
err("could not restart the USB controller CPU.");
ret = -EINVAL;
}
} else
ret = -EIO;
+ kfree(buf);
+
return ret;
}
EXPORT_SYMBOL(usb_cypress_load_firmware);
diff --git a/drivers/misc/uid_sys_stats.c b/drivers/misc/uid_sys_stats.c
index 33fc2b9..3bc7d4e 100644
--- a/drivers/misc/uid_sys_stats.c
+++ b/drivers/misc/uid_sys_stats.c
@@ -238,28 +238,28 @@
io_last->fsync -= task->ioac.syscfs;
}
-static void update_io_stats_locked(void)
+static void update_io_stats_all_locked(void)
{
struct uid_entry *uid_entry;
struct task_struct *task, *temp;
struct io_stats *io_bucket, *io_curr, *io_last;
+ struct user_namespace *user_ns = current_user_ns();
unsigned long bkt;
-
- BUG_ON(!rt_mutex_is_locked(&uid_lock));
+ uid_t uid;
hash_for_each(hash_table, bkt, uid_entry, hash)
memset(&uid_entry->io[UID_STATE_TOTAL_CURR], 0,
sizeof(struct io_stats));
- read_lock(&tasklist_lock);
+ rcu_read_lock();
do_each_thread(temp, task) {
- uid_entry = find_or_register_uid(from_kuid_munged(
- current_user_ns(), task_uid(task)));
+ uid = from_kuid_munged(user_ns, task_uid(task));
+ uid_entry = find_or_register_uid(uid);
if (!uid_entry)
continue;
add_uid_io_curr_stats(uid_entry, task);
} while_each_thread(temp, task);
- read_unlock(&tasklist_lock);
+ rcu_read_unlock();
hash_for_each(hash_table, bkt, uid_entry, hash) {
io_bucket = &uid_entry->io[uid_entry->state];
@@ -282,6 +282,47 @@
}
}
+static void update_io_stats_uid_locked(uid_t target_uid)
+{
+ struct uid_entry *uid_entry;
+ struct task_struct *task, *temp;
+ struct io_stats *io_bucket, *io_curr, *io_last;
+ struct user_namespace *user_ns = current_user_ns();
+
+ uid_entry = find_or_register_uid(target_uid);
+ if (!uid_entry)
+ return;
+
+ memset(&uid_entry->io[UID_STATE_TOTAL_CURR], 0,
+ sizeof(struct io_stats));
+
+ rcu_read_lock();
+ do_each_thread(temp, task) {
+ if (from_kuid_munged(user_ns, task_uid(task)) != target_uid)
+ continue;
+ add_uid_io_curr_stats(uid_entry, task);
+ } while_each_thread(temp, task);
+ rcu_read_unlock();
+
+ io_bucket = &uid_entry->io[uid_entry->state];
+ io_curr = &uid_entry->io[UID_STATE_TOTAL_CURR];
+ io_last = &uid_entry->io[UID_STATE_TOTAL_LAST];
+
+ io_bucket->read_bytes +=
+ io_curr->read_bytes - io_last->read_bytes;
+ io_bucket->write_bytes +=
+ io_curr->write_bytes - io_last->write_bytes;
+ io_bucket->rchar += io_curr->rchar - io_last->rchar;
+ io_bucket->wchar += io_curr->wchar - io_last->wchar;
+ io_bucket->fsync += io_curr->fsync - io_last->fsync;
+
+ io_last->read_bytes = io_curr->read_bytes;
+ io_last->write_bytes = io_curr->write_bytes;
+ io_last->rchar = io_curr->rchar;
+ io_last->wchar = io_curr->wchar;
+ io_last->fsync = io_curr->fsync;
+}
+
static int uid_io_show(struct seq_file *m, void *v)
{
struct uid_entry *uid_entry;
@@ -289,7 +330,7 @@
rt_mutex_lock(&uid_lock);
- update_io_stats_locked();
+ update_io_stats_all_locked();
hash_for_each(hash_table, bkt, uid_entry, hash) {
seq_printf(m, "%d %llu %llu %llu %llu %llu %llu %llu %llu %llu %llu\n",
@@ -364,7 +405,7 @@
return count;
}
- update_io_stats_locked();
+ update_io_stats_uid_locked(uid);
uid_entry->state = state;
@@ -402,7 +443,7 @@
uid_entry->utime += utime;
uid_entry->stime += stime;
- update_io_stats_locked();
+ update_io_stats_uid_locked(uid);
clean_uid_io_last_stats(uid_entry, task);
exit:
diff --git a/drivers/mmc/card/block.c b/drivers/mmc/card/block.c
index dba5c41..d8e9599 100644
--- a/drivers/mmc/card/block.c
+++ b/drivers/mmc/card/block.c
@@ -2200,6 +2200,17 @@
int need_retune = card->host->need_retune;
int ecc_err = 0, gen_err = 0;
+ if (card->host->sdr104_wa && mmc_card_sd(card) &&
+ (card->host->ios.timing == MMC_TIMING_UHS_SDR104) &&
+ !card->sdr104_blocked &&
+ (brq->data.error == -EILSEQ ||
+ brq->data.error == -EIO ||
+ brq->data.error == -ETIMEDOUT ||
+ brq->cmd.error == -EILSEQ ||
+ brq->cmd.error == -EIO ||
+ brq->cmd.error == -ETIMEDOUT))
+ card->err_in_sdr104 = true;
+
/*
* sbc.error indicates a problem with the set block count
* command. No data will have been transferred.
@@ -3610,6 +3621,9 @@
if (!ctx_info->active_reqs)
wake_up_interruptible(&host->cmdq_ctx.queue_empty_wq);
+ if (blk_queue_stopped(mq->queue) && !ctx_info->active_reqs)
+ complete(&mq->cmdq_shutdown_complete);
+
return;
}
@@ -3637,6 +3651,7 @@
struct mmc_async_req *areq;
const u8 packed_nr = 2;
u8 reqs = 0;
+ bool reset = false;
#ifdef CONFIG_MMC_SIMULATE_MAX_SPEED
unsigned long waitfor = jiffies;
#endif
@@ -3682,6 +3697,26 @@
type = rq_data_dir(req) == READ ? MMC_BLK_READ : MMC_BLK_WRITE;
mmc_queue_bounce_post(mq_rq);
+ if (card->err_in_sdr104) {
+ /*
+ * Data CRC/timeout errors will manifest as CMD/DATA
+ * ERR. But we'd like to retry these too.
+ * Moreover, no harm done if this fails too for multiple
+ * times, we anyway reduce the bus-speed and retry the
+ * same request.
+ * If that fails too, we don't override this status.
+ */
+ if (status == MMC_BLK_ABORT ||
+ status == MMC_BLK_CMD_ERR ||
+ status == MMC_BLK_DATA_ERR ||
+ status == MMC_BLK_RETRY)
+ /* reset on all of these errors and retry */
+ reset = true;
+
+ status = MMC_BLK_RETRY;
+ card->err_in_sdr104 = false;
+ }
+
switch (status) {
case MMC_BLK_SUCCESS:
case MMC_BLK_PARTIAL:
@@ -3722,8 +3757,32 @@
break;
case MMC_BLK_RETRY:
retune_retry_done = brq->retune_retry_done;
- if (retry++ < MMC_BLK_MAX_RETRIES)
+ if (retry++ < MMC_BLK_MAX_RETRIES) {
break;
+ } else if (reset) {
+ reset = false;
+ /*
+ * If we exhaust all the retries due to
+ * CRC/timeout errors in SDR140 mode with UHS SD
+ * cards, re-configure the card in SDR50
+ * bus-speed mode.
+ * All subsequent re-init of this card will be
+ * in SDR50 mode, unless it is removed and
+ * re-inserted. When new UHS SD cards are
+ * inserted, it may start at SDR104 mode if
+ * supported by the card.
+ */
+ pr_err("%s: blocked SDR104, lower the bus-speed (SDR50 / DDR50)\n",
+ req->rq_disk->disk_name);
+ mmc_host_clear_sdr104(card->host);
+ mmc_suspend_clk_scaling(card->host);
+ mmc_blk_reset(md, card->host, type);
+ /* SDR104 mode is blocked from now on */
+ card->sdr104_blocked = true;
+ /* retry 5 times again */
+ retry = 0;
+ break;
+ }
/* Fall through */
case MMC_BLK_ABORT:
if (!mmc_blk_reset(md, card->host, type) &&
diff --git a/drivers/mmc/card/queue.c b/drivers/mmc/card/queue.c
index b2d11b5..ccfd225 100644
--- a/drivers/mmc/card/queue.c
+++ b/drivers/mmc/card/queue.c
@@ -100,7 +100,8 @@
* 4. cmdq state shouldn't be in error state.
* 5. free tag available to process the new request.
*/
- wait_event(ctx->wait, mmc_peek_request(mq) &&
+ wait_event(ctx->wait, kthread_should_stop()
+ || (mmc_peek_request(mq) &&
!(((req_op(mq->cmdq_req_peeked) == REQ_OP_FLUSH) ||
(req_op(mq->cmdq_req_peeked) == REQ_OP_DISCARD))
&& test_bit(CMDQ_STATE_DCMD_ACTIVE, &ctx->curr_state))
@@ -109,7 +110,7 @@
&& !(!host->card->part_curr && mmc_host_cq_disable(host) &&
!mmc_card_suspended(host->card))
&& !test_bit(CMDQ_STATE_ERR, &ctx->curr_state)
- && !mmc_check_blk_queue_start_tag(q, mq->cmdq_req_peeked));
+ && !mmc_check_blk_queue_start_tag(q, mq->cmdq_req_peeked)));
}
static int mmc_cmdq_thread(void *d)
@@ -127,6 +128,8 @@
int ret = 0;
mmc_cmdq_ready_wait(host, mq);
+ if (kthread_should_stop())
+ break;
ret = mq->cmdq_issue_fn(mq, mq->cmdq_req_peeked);
/*
@@ -668,6 +671,7 @@
blk_queue_softirq_done(mq->queue, mmc_cmdq_softirq_done);
INIT_WORK(&mq->cmdq_err_work, mmc_cmdq_error_work);
+ init_completion(&mq->cmdq_shutdown_complete);
init_completion(&mq->cmdq_pending_req_done);
blk_queue_rq_timed_out(mq->queue, mmc_cmdq_rq_timed_out);
@@ -724,7 +728,22 @@
goto out;
if (wait) {
- blk_cleanup_queue(q);
+
+ /*
+ * After blk_stop_queue is called, wait for all
+ * active_reqs to complete.
+ * Then wait for cmdq thread to exit before calling
+ * cmdq shutdown to avoid race between issuing
+ * requests and shutdown of cmdq.
+ */
+ spin_lock_irqsave(q->queue_lock, flags);
+ blk_stop_queue(q);
+ spin_unlock_irqrestore(q->queue_lock, flags);
+
+ if (host->cmdq_ctx.active_reqs)
+ wait_for_completion(
+ &mq->cmdq_shutdown_complete);
+ kthread_stop(mq->thread);
mq->cmdq_shutdown(mq);
} else {
spin_lock_irqsave(q->queue_lock, flags);
diff --git a/drivers/mmc/card/queue.h b/drivers/mmc/card/queue.h
index 02917aa..bf7a95b 100644
--- a/drivers/mmc/card/queue.h
+++ b/drivers/mmc/card/queue.h
@@ -77,6 +77,7 @@
struct work_struct cmdq_err_work;
struct completion cmdq_pending_req_done;
+ struct completion cmdq_shutdown_complete;
struct request *cmdq_req_peeked;
int (*err_check_fn)(struct mmc_card *, struct mmc_async_req *);
void (*packed_test_fn)(struct request_queue *, struct mmc_queue_req *);
diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c
index c3c888e..1397d03 100644
--- a/drivers/mmc/core/core.c
+++ b/drivers/mmc/core/core.c
@@ -474,6 +474,11 @@
if (!clk_scaling->enable)
goto out;
+ if (*freq == UINT_MAX)
+ *freq = clk_scaling->freq_table[1];
+ else
+ *freq = clk_scaling->freq_table[0];
+
pr_debug("%s: target freq = %lu (%s)\n", mmc_hostname(host),
*freq, current->comm);
@@ -612,12 +617,25 @@
}
out:
- clk_scaling->devfreq_profile.freq_table = (unsigned long *)clk_scaling->freq_table;
+ /**
+ * devfreq requires unsigned long type freq_table while the
+ * freq_table in clk_scaling is un32. Here allocates an individual
+ * memory space for it and release it when exit clock scaling.
+ */
+ clk_scaling->devfreq_profile.freq_table = kzalloc(
+ clk_scaling->freq_table_sz *
+ sizeof(*(clk_scaling->devfreq_profile.freq_table)),
+ GFP_KERNEL);
+ if (!clk_scaling->devfreq_profile.freq_table)
+ return -ENOMEM;
clk_scaling->devfreq_profile.max_state = clk_scaling->freq_table_sz;
- for (i = 0; i < clk_scaling->freq_table_sz; i++)
+ for (i = 0; i < clk_scaling->freq_table_sz; i++) {
+ clk_scaling->devfreq_profile.freq_table[i] =
+ clk_scaling->freq_table[i];
pr_debug("%s: freq[%d] = %u\n",
mmc_hostname(host), i, clk_scaling->freq_table[i]);
+ }
return 0;
}
@@ -853,6 +871,8 @@
return err;
}
+ kfree(host->clk_scaling.devfreq_profile.freq_table);
+
host->clk_scaling.devfreq = NULL;
atomic_set(&host->clk_scaling.devfreq_abort, 1);
pr_debug("%s: devfreq was removed\n", mmc_hostname(host));
@@ -4170,6 +4190,10 @@
if (ret) {
mmc_card_set_removed(host->card);
+ if (host->card->sdr104_blocked) {
+ mmc_host_set_sdr104(host);
+ host->card->sdr104_blocked = false;
+ }
pr_debug("%s: card remove detected\n", mmc_hostname(host));
}
@@ -4276,7 +4300,7 @@
mmc_release_host(host);
goto out;
}
-+ mmc_rescan_try_freq(host, host->f_min);
+ mmc_rescan_try_freq(host, host->f_min);
mmc_release_host(host);
out:
diff --git a/drivers/mmc/core/core.h b/drivers/mmc/core/core.h
index 3f39058..2adf42c 100644
--- a/drivers/mmc/core/core.h
+++ b/drivers/mmc/core/core.h
@@ -80,7 +80,6 @@
extern bool mmc_can_scale_clk(struct mmc_host *host);
extern int mmc_init_clk_scaling(struct mmc_host *host);
-extern int mmc_suspend_clk_scaling(struct mmc_host *host);
extern int mmc_resume_clk_scaling(struct mmc_host *host);
extern int mmc_exit_clk_scaling(struct mmc_host *host);
extern unsigned long mmc_get_max_frequency(struct mmc_host *host);
diff --git a/drivers/mmc/core/sd.c b/drivers/mmc/core/sd.c
index 7f66ad3..7112f9f 100644
--- a/drivers/mmc/core/sd.c
+++ b/drivers/mmc/core/sd.c
@@ -432,26 +432,26 @@
if ((card->host->caps & MMC_CAP_UHS_SDR104) &&
(card->sw_caps.sd3_bus_mode & SD_MODE_UHS_SDR104) &&
(card->host->f_max > UHS_SDR104_MIN_DTR)) {
- card->sd_bus_speed = UHS_SDR104_BUS_SPEED;
- } else if ((card->host->caps & MMC_CAP_UHS_DDR50) &&
- (card->sw_caps.sd3_bus_mode & SD_MODE_UHS_DDR50) &&
- (card->host->f_max > UHS_DDR50_MIN_DTR)) {
- card->sd_bus_speed = UHS_DDR50_BUS_SPEED;
+ card->sd_bus_speed = UHS_SDR104_BUS_SPEED;
} else if ((card->host->caps & (MMC_CAP_UHS_SDR104 |
MMC_CAP_UHS_SDR50)) && (card->sw_caps.sd3_bus_mode &
SD_MODE_UHS_SDR50) &&
(card->host->f_max > UHS_SDR50_MIN_DTR)) {
- card->sd_bus_speed = UHS_SDR50_BUS_SPEED;
+ card->sd_bus_speed = UHS_SDR50_BUS_SPEED;
+ } else if ((card->host->caps & MMC_CAP_UHS_DDR50) &&
+ (card->sw_caps.sd3_bus_mode & SD_MODE_UHS_DDR50) &&
+ (card->host->f_max > UHS_DDR50_MIN_DTR)) {
+ card->sd_bus_speed = UHS_DDR50_BUS_SPEED;
} else if ((card->host->caps & (MMC_CAP_UHS_SDR104 |
MMC_CAP_UHS_SDR50 | MMC_CAP_UHS_SDR25)) &&
(card->sw_caps.sd3_bus_mode & SD_MODE_UHS_SDR25) &&
(card->host->f_max > UHS_SDR25_MIN_DTR)) {
- card->sd_bus_speed = UHS_SDR25_BUS_SPEED;
+ card->sd_bus_speed = UHS_SDR25_BUS_SPEED;
} else if ((card->host->caps & (MMC_CAP_UHS_SDR104 |
MMC_CAP_UHS_SDR50 | MMC_CAP_UHS_SDR25 |
MMC_CAP_UHS_SDR12)) && (card->sw_caps.sd3_bus_mode &
SD_MODE_UHS_SDR12)) {
- card->sd_bus_speed = UHS_SDR12_BUS_SPEED;
+ card->sd_bus_speed = UHS_SDR12_BUS_SPEED;
}
}
@@ -1313,6 +1313,8 @@
#endif
mmc_card_clr_suspended(host->card);
+ if (host->card->sdr104_blocked)
+ goto out;
err = mmc_resume_clk_scaling(host);
if (err) {
pr_err("%s: %s: fail to resume clock scaling (%d)\n",
diff --git a/drivers/mmc/host/sdhci-esdhc-imx.c b/drivers/mmc/host/sdhci-esdhc-imx.c
index 7123ef9..445fc47 100644
--- a/drivers/mmc/host/sdhci-esdhc-imx.c
+++ b/drivers/mmc/host/sdhci-esdhc-imx.c
@@ -830,6 +830,7 @@
switch (uhs) {
case MMC_TIMING_UHS_SDR50:
+ case MMC_TIMING_UHS_DDR50:
pinctrl = imx_data->pins_100mhz;
break;
case MMC_TIMING_UHS_SDR104:
diff --git a/drivers/mmc/host/sdhci-msm.c b/drivers/mmc/host/sdhci-msm.c
index bcf33b8..fe62b69 100644
--- a/drivers/mmc/host/sdhci-msm.c
+++ b/drivers/mmc/host/sdhci-msm.c
@@ -1815,6 +1815,7 @@
int clk_table_len;
u32 *clk_table = NULL;
enum of_gpio_flags flags = OF_GPIO_ACTIVE_LOW;
+ const char *lower_bus_speed = NULL;
pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL);
if (!pdata) {
@@ -1845,6 +1846,19 @@
!msm_host->mmc->clk_scaling.freq_table_sz)
dev_err(dev, "bad dts clock scaling frequencies\n");
+ /*
+ * Few hosts can support DDR52 mode at the same lower
+ * system voltage corner as high-speed mode. In such cases,
+ * it is always better to put it in DDR mode which will
+ * improve the performance without any power impact.
+ */
+ if (!of_property_read_string(np, "qcom,scaling-lower-bus-speed-mode",
+ &lower_bus_speed)) {
+ if (!strcmp(lower_bus_speed, "DDR52"))
+ msm_host->mmc->clk_scaling.lower_bus_speed_mode |=
+ MMC_SCALING_LOWER_DDR52_MODE;
+ }
+
if (sdhci_msm_dt_get_array(dev, "qcom,clk-rates",
&clk_table, &clk_table_len, 0)) {
dev_err(dev, "failed parsing supported clock rates\n");
@@ -1925,6 +1939,8 @@
if (of_get_property(np, "qcom,core_3_0v_support", NULL))
pdata->core_3_0v_support = true;
+ pdata->sdr104_wa = of_property_read_bool(np, "qcom,sdr104-wa");
+
return pdata;
out:
return NULL;
@@ -4408,6 +4424,8 @@
if (msm_host->pdata->nonhotplug)
msm_host->mmc->caps2 |= MMC_CAP2_NONHOTPLUG;
+ msm_host->mmc->sdr104_wa = msm_host->pdata->sdr104_wa;
+
init_completion(&msm_host->pwr_irq_completion);
if (gpio_is_valid(msm_host->pdata->status_gpio)) {
diff --git a/drivers/mmc/host/sdhci-msm.h b/drivers/mmc/host/sdhci-msm.h
index 533b241..53b1953 100644
--- a/drivers/mmc/host/sdhci-msm.h
+++ b/drivers/mmc/host/sdhci-msm.h
@@ -151,6 +151,7 @@
unsigned char sup_ice_clk_cnt;
struct sdhci_msm_pm_qos_data pm_qos_data;
bool core_3_0v_support;
+ bool sdr104_wa;
};
struct sdhci_msm_bus_vote {
diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c
index 744e520..53a6ae8 100644
--- a/drivers/mmc/host/sdhci.c
+++ b/drivers/mmc/host/sdhci.c
@@ -3096,7 +3096,10 @@
mmc_hostname(host->mmc), intmask,
host->data->error, ktime_to_ms(ktime_sub(
ktime_get(), host->data_start_time)));
- sdhci_dumpregs(host);
+
+ if (!host->mmc->sdr104_wa ||
+ (host->mmc->ios.timing != MMC_TIMING_UHS_SDR104))
+ sdhci_dumpregs(host);
}
sdhci_finish_data(host);
} else {
diff --git a/drivers/mtd/ubi/upd.c b/drivers/mtd/ubi/upd.c
index 0134ba3..3971256 100644
--- a/drivers/mtd/ubi/upd.c
+++ b/drivers/mtd/ubi/upd.c
@@ -148,11 +148,11 @@
return err;
}
- if (bytes == 0) {
- err = ubi_wl_flush(ubi, UBI_ALL, UBI_ALL);
- if (err)
- return err;
+ err = ubi_wl_flush(ubi, UBI_ALL, UBI_ALL);
+ if (err)
+ return err;
+ if (bytes == 0) {
err = clear_update_marker(ubi, vol, 0);
if (err)
return err;
diff --git a/drivers/net/can/ifi_canfd/ifi_canfd.c b/drivers/net/can/ifi_canfd/ifi_canfd.c
index 368bb07..481895b 100644
--- a/drivers/net/can/ifi_canfd/ifi_canfd.c
+++ b/drivers/net/can/ifi_canfd/ifi_canfd.c
@@ -557,7 +557,7 @@
int work_done = 0;
u32 stcmd = readl(priv->base + IFI_CANFD_STCMD);
- u32 rxstcmd = readl(priv->base + IFI_CANFD_STCMD);
+ u32 rxstcmd = readl(priv->base + IFI_CANFD_RXSTCMD);
u32 errctr = readl(priv->base + IFI_CANFD_ERROR_CTR);
/* Handle bus state changes */
diff --git a/drivers/net/wireless/ath/ath9k/common-spectral.c b/drivers/net/wireless/ath/ath9k/common-spectral.c
index e2512d5..eedf86b 100644
--- a/drivers/net/wireless/ath/ath9k/common-spectral.c
+++ b/drivers/net/wireless/ath/ath9k/common-spectral.c
@@ -528,6 +528,9 @@
if (!(radar_info->pulse_bw_info & SPECTRAL_SCAN_BITMASK))
return 0;
+ if (!spec_priv->rfs_chan_spec_scan)
+ return 1;
+
/* Output buffers are full, no need to process anything
* since there is no space to put the result anyway
*/
@@ -1072,7 +1075,7 @@
void ath9k_cmn_spectral_deinit_debug(struct ath_spec_scan_priv *spec_priv)
{
- if (IS_ENABLED(CONFIG_ATH9K_DEBUGFS)) {
+ if (IS_ENABLED(CONFIG_ATH9K_DEBUGFS) && spec_priv->rfs_chan_spec_scan) {
relay_close(spec_priv->rfs_chan_spec_scan);
spec_priv->rfs_chan_spec_scan = NULL;
}
@@ -1086,6 +1089,9 @@
debugfs_phy,
1024, 256, &rfs_spec_scan_cb,
NULL);
+ if (!spec_priv->rfs_chan_spec_scan)
+ return;
+
debugfs_create_file("spectral_scan_ctl",
S_IRUSR | S_IWUSR,
debugfs_phy, spec_priv,
diff --git a/drivers/net/wireless/cnss_prealloc/cnss_prealloc.c b/drivers/net/wireless/cnss_prealloc/cnss_prealloc.c
index 61de231..3c89a73 100644
--- a/drivers/net/wireless/cnss_prealloc/cnss_prealloc.c
+++ b/drivers/net/wireless/cnss_prealloc/cnss_prealloc.c
@@ -210,6 +210,7 @@
#else
void wcnss_prealloc_check_memory_leak(void) {}
#endif
+EXPORT_SYMBOL(wcnss_prealloc_check_memory_leak);
int wcnss_pre_alloc_reset(void)
{
@@ -225,6 +226,7 @@
return n;
}
+EXPORT_SYMBOL(wcnss_pre_alloc_reset);
static int __init wcnss_pre_alloc_init(void)
{
diff --git a/drivers/nvdimm/bus.c b/drivers/nvdimm/bus.c
index 23d4a17..351bac8 100644
--- a/drivers/nvdimm/bus.c
+++ b/drivers/nvdimm/bus.c
@@ -934,8 +934,14 @@
rc = nd_desc->ndctl(nd_desc, nvdimm, cmd, buf, buf_len, NULL);
if (rc < 0)
goto out_unlock;
+ nvdimm_bus_unlock(&nvdimm_bus->dev);
+
if (copy_to_user(p, buf, buf_len))
rc = -EFAULT;
+
+ vfree(buf);
+ return rc;
+
out_unlock:
nvdimm_bus_unlock(&nvdimm_bus->dev);
out:
diff --git a/drivers/nvdimm/dimm_devs.c b/drivers/nvdimm/dimm_devs.c
index d614493..dcb32f3 100644
--- a/drivers/nvdimm/dimm_devs.c
+++ b/drivers/nvdimm/dimm_devs.c
@@ -388,7 +388,7 @@
int alias_dpa_busy(struct device *dev, void *data)
{
- resource_size_t map_end, blk_start, new, busy;
+ resource_size_t map_end, blk_start, new;
struct blk_alloc_info *info = data;
struct nd_mapping *nd_mapping;
struct nd_region *nd_region;
@@ -429,29 +429,19 @@
retry:
/*
* Find the free dpa from the end of the last pmem allocation to
- * the end of the interleave-set mapping that is not already
- * covered by a blk allocation.
+ * the end of the interleave-set mapping.
*/
- busy = 0;
for_each_dpa_resource(ndd, res) {
+ if (strncmp(res->name, "pmem", 4) != 0)
+ continue;
if ((res->start >= blk_start && res->start < map_end)
|| (res->end >= blk_start
&& res->end <= map_end)) {
- if (strncmp(res->name, "pmem", 4) == 0) {
- new = max(blk_start, min(map_end + 1,
- res->end + 1));
- if (new != blk_start) {
- blk_start = new;
- goto retry;
- }
- } else
- busy += min(map_end, res->end)
- - max(nd_mapping->start, res->start) + 1;
- } else if (nd_mapping->start > res->start
- && map_end < res->end) {
- /* total eclipse of the PMEM region mapping */
- busy += nd_mapping->size;
- break;
+ new = max(blk_start, min(map_end + 1, res->end + 1));
+ if (new != blk_start) {
+ blk_start = new;
+ goto retry;
+ }
}
}
@@ -463,52 +453,11 @@
return 1;
}
- info->available -= blk_start - nd_mapping->start + busy;
+ info->available -= blk_start - nd_mapping->start;
return 0;
}
-static int blk_dpa_busy(struct device *dev, void *data)
-{
- struct blk_alloc_info *info = data;
- struct nd_mapping *nd_mapping;
- struct nd_region *nd_region;
- resource_size_t map_end;
- int i;
-
- if (!is_nd_pmem(dev))
- return 0;
-
- nd_region = to_nd_region(dev);
- for (i = 0; i < nd_region->ndr_mappings; i++) {
- nd_mapping = &nd_region->mapping[i];
- if (nd_mapping->nvdimm == info->nd_mapping->nvdimm)
- break;
- }
-
- if (i >= nd_region->ndr_mappings)
- return 0;
-
- map_end = nd_mapping->start + nd_mapping->size - 1;
- if (info->res->start >= nd_mapping->start
- && info->res->start < map_end) {
- if (info->res->end <= map_end) {
- info->busy = 0;
- return 1;
- } else {
- info->busy -= info->res->end - map_end;
- return 0;
- }
- } else if (info->res->end >= nd_mapping->start
- && info->res->end <= map_end) {
- info->busy -= nd_mapping->start - info->res->start;
- return 0;
- } else {
- info->busy -= nd_mapping->size;
- return 0;
- }
-}
-
/**
* nd_blk_available_dpa - account the unused dpa of BLK region
* @nd_mapping: container of dpa-resource-root + labels
@@ -538,11 +487,7 @@
for_each_dpa_resource(ndd, res) {
if (strncmp(res->name, "blk", 3) != 0)
continue;
-
- info.res = res;
- info.busy = resource_size(res);
- device_for_each_child(&nvdimm_bus->dev, &info, blk_dpa_busy);
- info.available -= info.busy;
+ info.available -= resource_size(res);
}
return info.available;
diff --git a/drivers/pci/host/pci-msm.c b/drivers/pci/host/pci-msm.c
index 8b3216cd..6523cb0 100644
--- a/drivers/pci/host/pci-msm.c
+++ b/drivers/pci/host/pci-msm.c
@@ -6457,7 +6457,6 @@
}
dev_set_drvdata(&msm_pcie_dev[rc_idx].pdev->dev, &msm_pcie_dev[rc_idx]);
- msm_pcie_sysfs_init(&msm_pcie_dev[rc_idx]);
ret = msm_pcie_get_resources(&msm_pcie_dev[rc_idx],
msm_pcie_dev[rc_idx].pdev);
@@ -6508,6 +6507,8 @@
goto decrease_rc_num;
}
+ msm_pcie_sysfs_init(&msm_pcie_dev[rc_idx]);
+
msm_pcie_dev[rc_idx].drv_ready = true;
if (msm_pcie_dev[rc_idx].boot_option &
diff --git a/drivers/pinctrl/qcom/Kconfig b/drivers/pinctrl/qcom/Kconfig
index ba6d5ce..304e206 100644
--- a/drivers/pinctrl/qcom/Kconfig
+++ b/drivers/pinctrl/qcom/Kconfig
@@ -97,6 +97,15 @@
Qualcomm Technologies Inc TLMM block found on the Qualcomm
Technologies Inc SDM830 platform.
+config PINCTRL_SDXPOORWILLS
+ tristate "Qualcomm Technologies Inc SDXPOORWILLS 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 SDXPOORWILLS platform.
+
config PINCTRL_MSM8996
tristate "Qualcomm MSM8996 pin controller driver"
diff --git a/drivers/pinctrl/qcom/Makefile b/drivers/pinctrl/qcom/Makefile
index 5e05e897..4786960 100644
--- a/drivers/pinctrl/qcom/Makefile
+++ b/drivers/pinctrl/qcom/Makefile
@@ -17,5 +17,6 @@
obj-$(CONFIG_PINCTRL_QCOM_SSBI_PMIC) += pinctrl-ssbi-mpp.o
obj-$(CONFIG_PINCTRL_SDM845) += pinctrl-sdm845.o
obj-$(CONFIG_PINCTRL_SDM830) += pinctrl-sdm830.o
+obj-$(CONFIG_PINCTRL_SDXPOORWILLS) += pinctrl-sdxpoorwills.o
obj-$(CONFIG_PINCTRL_WCD) += pinctrl-wcd.o
obj-$(CONFIG_PINCTRL_LPI) += pinctrl-lpi.o
diff --git a/drivers/pinctrl/qcom/pinctrl-sdxpoorwills.c b/drivers/pinctrl/qcom/pinctrl-sdxpoorwills.c
new file mode 100644
index 0000000..4a21eb6
--- /dev/null
+++ b/drivers/pinctrl/qcom/pinctrl-sdxpoorwills.c
@@ -0,0 +1,1205 @@
+/*
+ * 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/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_BASE 0x0
+#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_BASE + REG_SIZE * id, \
+ .io_reg = REG_BASE + 0x4 + REG_SIZE * id, \
+ .intr_cfg_reg = REG_BASE + 0x8 + REG_SIZE * id, \
+ .intr_status_reg = REG_BASE + 0xc + REG_SIZE * id, \
+ .intr_target_reg = REG_BASE + 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 = 3, \
+ .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_polarity_bit = -1, \
+ .intr_detection_bit = -1, \
+ .intr_detection_width = -1, \
+ }
+static const struct pinctrl_pin_desc sdxpoorwills_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, "SDC1_CLK"),
+ PINCTRL_PIN(101, "SDC1_CMD"),
+ PINCTRL_PIN(102, "SDC1_DATA"),
+ PINCTRL_PIN(103, "SDC2_CLK"),
+ PINCTRL_PIN(104, "SDC2_CMD"),
+ PINCTRL_PIN(105, "SDC2_DATA"),
+};
+
+#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);
+
+static const unsigned int sdc1_clk_pins[] = { 100 };
+static const unsigned int sdc1_cmd_pins[] = { 101 };
+static const unsigned int sdc1_data_pins[] = { 102 };
+static const unsigned int sdc2_clk_pins[] = { 103 };
+static const unsigned int sdc2_cmd_pins[] = { 104 };
+static const unsigned int sdc2_data_pins[] = { 105 };
+
+enum sdxpoorwills_functions {
+ msm_mux_qdss_stm31,
+ msm_mux_blsp_uart1,
+ msm_mux_gpio,
+ msm_mux_uim2_data,
+ msm_mux_ebi0_wrcdc,
+ msm_mux_uim2_present,
+ msm_mux_qdss_stm30,
+ msm_mux_uim2_reset,
+ msm_mux_blsp_i2c1,
+ msm_mux_qdss_stm29,
+ msm_mux_uim2_clk,
+ msm_mux_qdss_stm28,
+ msm_mux_blsp_spi2,
+ msm_mux_blsp_uart2,
+ msm_mux_qdss_stm23,
+ msm_mux_qdss3,
+ msm_mux_qdss_stm22,
+ msm_mux_qdss2,
+ msm_mux_blsp_i2c2,
+ msm_mux_qdss_stm21,
+ msm_mux_qdss1,
+ msm_mux_qdss_stm20,
+ msm_mux_qdss0,
+ msm_mux_pri_mi2s,
+ msm_mux_blsp_spi3,
+ msm_mux_blsp_uart3,
+ msm_mux_ext_dbg,
+ msm_mux_ldo_en,
+ msm_mux_blsp_i2c3,
+ msm_mux_gcc_gp3,
+ msm_mux_qdss_stm19,
+ msm_mux_qdss12,
+ msm_mux_qdss_stm18,
+ msm_mux_qdss13,
+ msm_mux_qdss_stm17,
+ msm_mux_qdss14,
+ msm_mux_bimc_dte0,
+ msm_mux_native_tsens,
+ msm_mux_vsense_trigger,
+ msm_mux_qdss_stm26,
+ msm_mux_qdss9,
+ msm_mux_blsp_i2c4,
+ msm_mux_gcc_gp1,
+ msm_mux_qdss_stm25,
+ msm_mux_qdss10,
+ msm_mux_jitter_bist,
+ msm_mux_gcc_gp2,
+ msm_mux_qdss_stm24,
+ msm_mux_qdss11,
+ msm_mux_qdss_stm16,
+ msm_mux_qdss15,
+ msm_mux_bimc_dte1,
+ msm_mux_sec_mi2s,
+ msm_mux_blsp_spi4,
+ msm_mux_blsp_uart4,
+ msm_mux_qdss_cti,
+ msm_mux_qdss_stm27,
+ msm_mux_qdss8,
+ msm_mux_ebi2_a,
+ msm_mux_qdss_stm3,
+ msm_mux_ebi2_lcd,
+ msm_mux_qdss_stm2,
+ msm_mux_pll_bist,
+ msm_mux_qdss_stm1,
+ msm_mux_qdss_stm0,
+ msm_mux_adsp_ext,
+ msm_mux_epm1,
+ msm_mux_m_voc,
+ msm_mux_native_char,
+ msm_mux_native_char1,
+ msm_mux_pa_indicator,
+ msm_mux_qdss_traceclk,
+ msm_mux_native_char0,
+ msm_mux_qlink_en,
+ msm_mux_qlink_req,
+ msm_mux_pll_test,
+ msm_mux_cri_trng,
+ msm_mux_wmss_reset,
+ msm_mux_native_char3,
+ msm_mux_nav_pps,
+ msm_mux_nav_dr,
+ msm_mux_native_char2,
+ msm_mux_native_tsense,
+ msm_mux_prng_rosc,
+ msm_mux_cri_trng0,
+ msm_mux_cri_trng1,
+ msm_mux_pll_ref,
+ msm_mux_coex_uart,
+ msm_mux_qdss_stm11,
+ msm_mux_qdss_stm10,
+ msm_mux_ddr_pxi0,
+ msm_mux_ap2mdm_status,
+ msm_mux_ddr_bist,
+ msm_mux_mdm2ap_status,
+ msm_mux_ap2mdm_err,
+ msm_mux_mdm2ap_err,
+ msm_mux_ap2mdm_vdd,
+ msm_mux_mdm2ap_vdd,
+ msm_mux_ap2mdm_wake,
+ msm_mux_pciehost_rst,
+ msm_mux_blsp_spi1,
+ msm_mux_qdss_stm14,
+ msm_mux_pcie_wake,
+ msm_mux_mdm2ap_wake,
+ msm_mux_pci_e,
+ msm_mux_qdss_stm13,
+ msm_mux_i2s_mclk,
+ msm_mux_audio_ref,
+ msm_mux_ldo_update,
+ msm_mux_qdss_stm8,
+ msm_mux_qdss_stm7,
+ msm_mux_qdss4,
+ msm_mux_tgu_ch0,
+ msm_mux_pcie_clkreq,
+ msm_mux_qdss_stm9,
+ msm_mux_qdss_stm15,
+ msm_mux_mgpi_clk,
+ msm_mux_qdss_stm12,
+ msm_mux_qdss_tracectl,
+ msm_mux_atest_char,
+ msm_mux_qdss_stm6,
+ msm_mux_qdss5,
+ msm_mux_atest_char3,
+ msm_mux_qdss_stm5,
+ msm_mux_qdss6,
+ msm_mux_atest_char2,
+ msm_mux_qdss_stm4,
+ msm_mux_qdss7,
+ msm_mux_atest_char1,
+ msm_mux_uim1_data,
+ msm_mux_atest_char0,
+ msm_mux_uim1_present,
+ msm_mux_uim1_reset,
+ msm_mux_uim1_clk,
+ msm_mux_dbg_out,
+ msm_mux_gcc_plltest,
+ msm_mux_usb2phy_ac,
+ msm_mux_NA,
+};
+
+static const char * const qdss_stm31_groups[] = {
+ "gpio0",
+};
+static const char * const blsp_uart1_groups[] = {
+ "gpio0", "gpio1", "gpio2", "gpio3", "gpio20", "gpio21", "gpio22",
+ "gpio23",
+};
+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", "gpio26", "gpio27", "gpio28", "gpio29",
+ "gpio30", "gpio31", "gpio32", "gpio33", "gpio34", "gpio35", "gpio36",
+ "gpio37", "gpio38", "gpio39", "gpio40", "gpio41", "gpio42", "gpio43",
+ "gpio44", "gpio45", "gpio54", "gpio55", "gpio56", "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",
+};
+static const char * const uim2_data_groups[] = {
+ "gpio0",
+};
+static const char * const ebi0_wrcdc_groups[] = {
+ "gpio0", "gpio2",
+};
+static const char * const uim2_present_groups[] = {
+ "gpio1",
+};
+static const char * const qdss_stm30_groups[] = {
+ "gpio1",
+};
+static const char * const uim2_reset_groups[] = {
+ "gpio2",
+};
+static const char * const blsp_i2c1_groups[] = {
+ "gpio2", "gpio3", "gpio74", "gpio75",
+};
+static const char * const qdss_stm29_groups[] = {
+ "gpio2",
+};
+static const char * const uim2_clk_groups[] = {
+ "gpio3",
+};
+static const char * const qdss_stm28_groups[] = {
+ "gpio3",
+};
+static const char * const blsp_spi2_groups[] = {
+ "gpio4", "gpio5", "gpio6", "gpio7", "gpio52", "gpio62", "gpio71",
+};
+static const char * const blsp_uart2_groups[] = {
+ "gpio4", "gpio5", "gpio6", "gpio7", "gpio63", "gpio64", "gpio65",
+ "gpio66",
+};
+static const char * const qdss_stm23_groups[] = {
+ "gpio4",
+};
+static const char * const qdss3_groups[] = {
+ "gpio4",
+};
+static const char * const qdss_stm22_groups[] = {
+ "gpio5",
+};
+static const char * const qdss2_groups[] = {
+ "gpio5",
+};
+static const char * const blsp_i2c2_groups[] = {
+ "gpio6", "gpio7", "gpio65", "gpio66",
+};
+static const char * const qdss_stm21_groups[] = {
+ "gpio6",
+};
+static const char * const qdss1_groups[] = {
+ "gpio6",
+};
+static const char * const qdss_stm20_groups[] = {
+ "gpio7",
+};
+static const char * const qdss0_groups[] = {
+ "gpio7",
+};
+static const char * const pri_mi2s_groups[] = {
+ "gpio8", "gpio9", "gpio10", "gpio11", "gpio12", "gpio13", "gpio14",
+ "gpio15",
+};
+static const char * const blsp_spi3_groups[] = {
+ "gpio8", "gpio9", "gpio10", "gpio11", "gpio52", "gpio62", "gpio71",
+};
+static const char * const blsp_uart3_groups[] = {
+ "gpio8", "gpio9", "gpio10", "gpio11",
+};
+static const char * const ext_dbg_groups[] = {
+ "gpio8", "gpio9", "gpio10", "gpio11",
+};
+static const char * const ldo_en_groups[] = {
+ "gpio8",
+};
+static const char * const blsp_i2c3_groups[] = {
+ "gpio10", "gpio11",
+};
+static const char * const gcc_gp3_groups[] = {
+ "gpio11",
+};
+static const char * const qdss_stm19_groups[] = {
+ "gpio12",
+};
+static const char * const qdss12_groups[] = {
+ "gpio12",
+};
+static const char * const qdss_stm18_groups[] = {
+ "gpio13",
+};
+static const char * const qdss13_groups[] = {
+ "gpio13",
+};
+static const char * const qdss_stm17_groups[] = {
+ "gpio14",
+};
+static const char * const qdss14_groups[] = {
+ "gpio14",
+};
+static const char * const bimc_dte0_groups[] = {
+ "gpio14", "gpio59",
+};
+static const char * const native_tsens_groups[] = {
+ "gpio14",
+};
+static const char * const vsense_trigger_groups[] = {
+ "gpio14",
+};
+static const char * const qdss_stm26_groups[] = {
+ "gpio17",
+};
+static const char * const qdss9_groups[] = {
+ "gpio17",
+};
+static const char * const blsp_i2c4_groups[] = {
+ "gpio18", "gpio19", "gpio76", "gpio77",
+};
+static const char * const gcc_gp1_groups[] = {
+ "gpio18",
+};
+static const char * const qdss_stm25_groups[] = {
+ "gpio18",
+};
+static const char * const qdss10_groups[] = {
+ "gpio18",
+};
+static const char * const jitter_bist_groups[] = {
+ "gpio19",
+};
+static const char * const gcc_gp2_groups[] = {
+ "gpio19",
+};
+static const char * const qdss_stm24_groups[] = {
+ "gpio19",
+};
+static const char * const qdss11_groups[] = {
+ "gpio19",
+};
+static const char * const qdss_stm16_groups[] = {
+ "gpio15",
+};
+static const char * const qdss15_groups[] = {
+ "gpio15",
+};
+static const char * const bimc_dte1_groups[] = {
+ "gpio15", "gpio60",
+};
+static const char * const sec_mi2s_groups[] = {
+ "gpio16", "gpio17", "gpio18", "gpio19", "gpio20", "gpio21", "gpio22",
+ "gpio23",
+};
+static const char * const blsp_spi4_groups[] = {
+ "gpio16", "gpio17", "gpio18", "gpio19", "gpio52", "gpio62", "gpio71",
+};
+static const char * const blsp_uart4_groups[] = {
+ "gpio16", "gpio17", "gpio18", "gpio19", "gpio20", "gpio21", "gpio22",
+ "gpio23",
+};
+static const char * const qdss_cti_groups[] = {
+ "gpio16", "gpio16", "gpio17", "gpio17", "gpio22", "gpio22", "gpio23",
+ "gpio23", "gpio54", "gpio54", "gpio55", "gpio55", "gpio59", "gpio61",
+ "gpio88", "gpio88", "gpio89", "gpio89",
+};
+static const char * const qdss_stm27_groups[] = {
+ "gpio16",
+};
+static const char * const qdss8_groups[] = {
+ "gpio16",
+};
+static const char * const ebi2_a_groups[] = {
+ "gpio20",
+};
+static const char * const qdss_stm3_groups[] = {
+ "gpio20",
+};
+static const char * const ebi2_lcd_groups[] = {
+ "gpio21", "gpio22", "gpio23",
+};
+static const char * const qdss_stm2_groups[] = {
+ "gpio21",
+};
+static const char * const pll_bist_groups[] = {
+ "gpio22",
+};
+static const char * const qdss_stm1_groups[] = {
+ "gpio22",
+};
+static const char * const qdss_stm0_groups[] = {
+ "gpio23",
+};
+static const char * const adsp_ext_groups[] = {
+ "gpio24", "gpio25",
+};
+static const char * const epm1_groups[] = {
+ "gpio25",
+};
+static const char * const m_voc_groups[] = {
+ "gpio25", "gpio46", "gpio59", "gpio61",
+};
+static const char * const native_char_groups[] = {
+ "gpio26",
+};
+static const char * const native_char1_groups[] = {
+ "gpio32",
+};
+static const char * const pa_indicator_groups[] = {
+ "gpio33",
+};
+static const char * const qdss_traceclk_groups[] = {
+ "gpio33",
+};
+static const char * const native_char0_groups[] = {
+ "gpio33",
+};
+static const char * const qlink_en_groups[] = {
+ "gpio34",
+};
+static const char * const qlink_req_groups[] = {
+ "gpio35",
+};
+static const char * const pll_test_groups[] = {
+ "gpio35",
+};
+static const char * const cri_trng_groups[] = {
+ "gpio36",
+};
+static const char * const wmss_reset_groups[] = {
+ "gpio28",
+};
+static const char * const native_char3_groups[] = {
+ "gpio28",
+};
+static const char * const nav_pps_groups[] = {
+ "gpio29", "gpio42", "gpio62",
+};
+static const char * const nav_dr_groups[] = {
+ "gpio29", "gpio42", "gpio62",
+};
+static const char * const native_char2_groups[] = {
+ "gpio29",
+};
+static const char * const native_tsense_groups[] = {
+ "gpio29",
+};
+static const char * const prng_rosc_groups[] = {
+ "gpio38",
+};
+static const char * const cri_trng0_groups[] = {
+ "gpio40",
+};
+static const char * const cri_trng1_groups[] = {
+ "gpio41",
+};
+static const char * const pll_ref_groups[] = {
+ "gpio42",
+};
+static const char * const coex_uart_groups[] = {
+ "gpio44", "gpio45",
+};
+static const char * const qdss_stm11_groups[] = {
+ "gpio44",
+};
+static const char * const qdss_stm10_groups[] = {
+ "gpio45",
+};
+static const char * const ddr_pxi0_groups[] = {
+ "gpio45", "gpio46",
+};
+static const char * const ap2mdm_status_groups[] = {
+ "gpio46",
+};
+static const char * const ddr_bist_groups[] = {
+ "gpio46", "gpio47", "gpio48", "gpio49",
+};
+static const char * const mdm2ap_status_groups[] = {
+ "gpio47",
+};
+static const char * const ap2mdm_err_groups[] = {
+ "gpio48",
+};
+static const char * const mdm2ap_err_groups[] = {
+ "gpio49",
+};
+static const char * const ap2mdm_vdd_groups[] = {
+ "gpio50",
+};
+static const char * const mdm2ap_vdd_groups[] = {
+ "gpio51",
+};
+static const char * const ap2mdm_wake_groups[] = {
+ "gpio52",
+};
+static const char * const pciehost_rst_groups[] = {
+ "gpio52",
+};
+static const char * const blsp_spi1_groups[] = {
+ "gpio52", "gpio62", "gpio71", "gpio72", "gpio73", "gpio74", "gpio75",
+};
+static const char * const qdss_stm14_groups[] = {
+ "gpio52",
+};
+static const char * const pcie_wake_groups[] = {
+ "gpio53",
+};
+static const char * const mdm2ap_wake_groups[] = {
+ "gpio53",
+};
+static const char * const pci_e_groups[] = {
+ "gpio53", "gpio57",
+};
+static const char * const qdss_stm13_groups[] = {
+ "gpio53",
+};
+static const char * const i2s_mclk_groups[] = {
+ "gpio62",
+};
+static const char * const audio_ref_groups[] = {
+ "gpio62",
+};
+static const char * const ldo_update_groups[] = {
+ "gpio62",
+};
+static const char * const qdss_stm8_groups[] = {
+ "gpio62",
+};
+static const char * const qdss_stm7_groups[] = {
+ "gpio63",
+};
+static const char * const qdss4_groups[] = {
+ "gpio63",
+};
+static const char * const tgu_ch0_groups[] = {
+ "gpio55",
+};
+static const char * const pcie_clkreq_groups[] = {
+ "gpio56",
+};
+static const char * const qdss_stm9_groups[] = {
+ "gpio56",
+};
+static const char * const qdss_stm15_groups[] = {
+ "gpio57",
+};
+static const char * const mgpi_clk_groups[] = {
+ "gpio60", "gpio71",
+};
+static const char * const qdss_stm12_groups[] = {
+ "gpio60",
+};
+static const char * const qdss_tracectl_groups[] = {
+ "gpio60",
+};
+static const char * const atest_char_groups[] = {
+ "gpio63",
+};
+static const char * const qdss_stm6_groups[] = {
+ "gpio64",
+};
+static const char * const qdss5_groups[] = {
+ "gpio64",
+};
+static const char * const atest_char3_groups[] = {
+ "gpio64",
+};
+static const char * const qdss_stm5_groups[] = {
+ "gpio65",
+};
+static const char * const qdss6_groups[] = {
+ "gpio65",
+};
+static const char * const atest_char2_groups[] = {
+ "gpio65",
+};
+static const char * const qdss_stm4_groups[] = {
+ "gpio66",
+};
+static const char * const qdss7_groups[] = {
+ "gpio66",
+};
+static const char * const atest_char1_groups[] = {
+ "gpio66",
+};
+static const char * const uim1_data_groups[] = {
+ "gpio67",
+};
+static const char * const atest_char0_groups[] = {
+ "gpio67",
+};
+static const char * const uim1_present_groups[] = {
+ "gpio68",
+};
+static const char * const uim1_reset_groups[] = {
+ "gpio69",
+};
+static const char * const uim1_clk_groups[] = {
+ "gpio70",
+};
+static const char * const dbg_out_groups[] = {
+ "gpio71",
+};
+static const char * const gcc_plltest_groups[] = {
+ "gpio73", "gpio74",
+};
+static const char * const usb2phy_ac_groups[] = {
+ "gpio87",
+};
+
+static const struct msm_function sdxpoorwills_functions[] = {
+ FUNCTION(qdss_stm31),
+ FUNCTION(blsp_uart1),
+ FUNCTION(gpio),
+ FUNCTION(uim2_data),
+ FUNCTION(ebi0_wrcdc),
+ FUNCTION(uim2_present),
+ FUNCTION(qdss_stm30),
+ FUNCTION(uim2_reset),
+ FUNCTION(blsp_i2c1),
+ FUNCTION(qdss_stm29),
+ FUNCTION(uim2_clk),
+ FUNCTION(qdss_stm28),
+ FUNCTION(blsp_spi2),
+ FUNCTION(blsp_uart2),
+ FUNCTION(qdss_stm23),
+ FUNCTION(qdss3),
+ FUNCTION(qdss_stm22),
+ FUNCTION(qdss2),
+ FUNCTION(blsp_i2c2),
+ FUNCTION(qdss_stm21),
+ FUNCTION(qdss1),
+ FUNCTION(qdss_stm20),
+ FUNCTION(qdss0),
+ FUNCTION(pri_mi2s),
+ FUNCTION(blsp_spi3),
+ FUNCTION(blsp_uart3),
+ FUNCTION(ext_dbg),
+ FUNCTION(ldo_en),
+ FUNCTION(blsp_i2c3),
+ FUNCTION(gcc_gp3),
+ FUNCTION(qdss_stm19),
+ FUNCTION(qdss12),
+ FUNCTION(qdss_stm18),
+ FUNCTION(qdss13),
+ FUNCTION(qdss_stm17),
+ FUNCTION(qdss14),
+ FUNCTION(bimc_dte0),
+ FUNCTION(native_tsens),
+ FUNCTION(vsense_trigger),
+ FUNCTION(qdss_stm26),
+ FUNCTION(qdss9),
+ FUNCTION(blsp_i2c4),
+ FUNCTION(gcc_gp1),
+ FUNCTION(qdss_stm25),
+ FUNCTION(qdss10),
+ FUNCTION(jitter_bist),
+ FUNCTION(gcc_gp2),
+ FUNCTION(qdss_stm24),
+ FUNCTION(qdss11),
+ FUNCTION(qdss_stm16),
+ FUNCTION(qdss15),
+ FUNCTION(bimc_dte1),
+ FUNCTION(sec_mi2s),
+ FUNCTION(blsp_spi4),
+ FUNCTION(blsp_uart4),
+ FUNCTION(qdss_cti),
+ FUNCTION(qdss_stm27),
+ FUNCTION(qdss8),
+ FUNCTION(ebi2_a),
+ FUNCTION(qdss_stm3),
+ FUNCTION(ebi2_lcd),
+ FUNCTION(qdss_stm2),
+ FUNCTION(pll_bist),
+ FUNCTION(qdss_stm1),
+ FUNCTION(qdss_stm0),
+ FUNCTION(adsp_ext),
+ FUNCTION(epm1),
+ FUNCTION(m_voc),
+ FUNCTION(native_char),
+ FUNCTION(native_char1),
+ FUNCTION(pa_indicator),
+ FUNCTION(qdss_traceclk),
+ FUNCTION(native_char0),
+ FUNCTION(qlink_en),
+ FUNCTION(qlink_req),
+ FUNCTION(pll_test),
+ FUNCTION(cri_trng),
+ FUNCTION(wmss_reset),
+ FUNCTION(native_char3),
+ FUNCTION(nav_pps),
+ FUNCTION(nav_dr),
+ FUNCTION(native_char2),
+ FUNCTION(native_tsense),
+ FUNCTION(prng_rosc),
+ FUNCTION(cri_trng0),
+ FUNCTION(cri_trng1),
+ FUNCTION(pll_ref),
+ FUNCTION(coex_uart),
+ FUNCTION(qdss_stm11),
+ FUNCTION(qdss_stm10),
+ FUNCTION(ddr_pxi0),
+ FUNCTION(ap2mdm_status),
+ FUNCTION(ddr_bist),
+ FUNCTION(mdm2ap_status),
+ FUNCTION(ap2mdm_err),
+ FUNCTION(mdm2ap_err),
+ FUNCTION(ap2mdm_vdd),
+ FUNCTION(mdm2ap_vdd),
+ FUNCTION(ap2mdm_wake),
+ FUNCTION(pciehost_rst),
+ FUNCTION(blsp_spi1),
+ FUNCTION(qdss_stm14),
+ FUNCTION(pcie_wake),
+ FUNCTION(mdm2ap_wake),
+ FUNCTION(pci_e),
+ FUNCTION(qdss_stm13),
+ FUNCTION(i2s_mclk),
+ FUNCTION(audio_ref),
+ FUNCTION(ldo_update),
+ FUNCTION(qdss_stm8),
+ FUNCTION(qdss_stm7),
+ FUNCTION(qdss4),
+ FUNCTION(tgu_ch0),
+ FUNCTION(pcie_clkreq),
+ FUNCTION(qdss_stm9),
+ FUNCTION(qdss_stm15),
+ FUNCTION(mgpi_clk),
+ FUNCTION(qdss_stm12),
+ FUNCTION(qdss_tracectl),
+ FUNCTION(atest_char),
+ FUNCTION(qdss_stm6),
+ FUNCTION(qdss5),
+ FUNCTION(atest_char3),
+ FUNCTION(qdss_stm5),
+ FUNCTION(qdss6),
+ FUNCTION(atest_char2),
+ FUNCTION(qdss_stm4),
+ FUNCTION(qdss7),
+ FUNCTION(atest_char1),
+ FUNCTION(uim1_data),
+ FUNCTION(atest_char0),
+ FUNCTION(uim1_present),
+ FUNCTION(uim1_reset),
+ FUNCTION(uim1_clk),
+ FUNCTION(dbg_out),
+ FUNCTION(gcc_plltest),
+ FUNCTION(usb2phy_ac),
+};
+
+static const struct msm_pingroup sdxpoorwills_groups[] = {
+ PINGROUP(0, uim2_data, blsp_uart1, qdss_stm31, ebi0_wrcdc, NA, NA, NA,
+ NA, NA),
+ PINGROUP(1, uim2_present, blsp_uart1, qdss_stm30, NA, NA, NA, NA, NA,
+ NA),
+ PINGROUP(2, uim2_reset, blsp_uart1, blsp_i2c1, qdss_stm29, ebi0_wrcdc,
+ NA, NA, NA, NA),
+ PINGROUP(3, uim2_clk, blsp_uart1, blsp_i2c1, qdss_stm28, NA, NA, NA,
+ NA, NA),
+ PINGROUP(4, blsp_spi2, blsp_uart2, NA, qdss_stm23, qdss3, NA, NA, NA,
+ NA),
+ PINGROUP(5, blsp_spi2, blsp_uart2, NA, qdss_stm22, qdss2, NA, NA, NA,
+ NA),
+ PINGROUP(6, blsp_spi2, blsp_uart2, blsp_i2c2, NA, qdss_stm21, qdss1,
+ NA, NA, NA),
+ PINGROUP(7, blsp_spi2, blsp_uart2, blsp_i2c2, NA, qdss_stm20, qdss0,
+ NA, NA, NA),
+ PINGROUP(8, pri_mi2s, blsp_spi3, blsp_uart3, ext_dbg, ldo_en, NA, NA,
+ NA, NA),
+ PINGROUP(9, pri_mi2s, blsp_spi3, blsp_uart3, ext_dbg, NA, NA, NA, NA,
+ NA),
+ PINGROUP(10, pri_mi2s, blsp_spi3, blsp_uart3, blsp_i2c3, ext_dbg, NA,
+ NA, NA, NA),
+ PINGROUP(11, pri_mi2s, blsp_spi3, blsp_uart3, blsp_i2c3, ext_dbg,
+ gcc_gp3, NA, NA, NA),
+ PINGROUP(12, pri_mi2s, NA, qdss_stm19, qdss12, NA, NA, NA, NA, NA),
+ PINGROUP(13, pri_mi2s, NA, qdss_stm18, qdss13, NA, NA, NA, NA, NA),
+ PINGROUP(14, pri_mi2s, NA, NA, qdss_stm17, qdss14, bimc_dte0,
+ native_tsens, vsense_trigger, NA),
+ PINGROUP(15, pri_mi2s, NA, NA, qdss_stm16, qdss15, NA, NA, bimc_dte1,
+ NA),
+ PINGROUP(16, sec_mi2s, blsp_spi4, blsp_uart4, qdss_cti, qdss_cti, NA,
+ NA, qdss_stm27, qdss8),
+ PINGROUP(17, sec_mi2s, blsp_spi4, blsp_uart4, qdss_cti, qdss_cti, NA,
+ qdss_stm26, qdss9, NA),
+ PINGROUP(18, sec_mi2s, blsp_spi4, blsp_uart4, blsp_i2c4, gcc_gp1, NA,
+ qdss_stm25, qdss10, NA),
+ PINGROUP(19, sec_mi2s, blsp_spi4, blsp_uart4, blsp_i2c4, jitter_bist,
+ gcc_gp2, NA, qdss_stm24, qdss11),
+ PINGROUP(20, sec_mi2s, ebi2_a, blsp_uart1, blsp_uart4, NA, qdss_stm3,
+ NA, NA, NA),
+ PINGROUP(21, sec_mi2s, ebi2_lcd, blsp_uart1, blsp_uart4, NA, NA,
+ qdss_stm2, NA, NA),
+ PINGROUP(22, sec_mi2s, ebi2_lcd, blsp_uart1, qdss_cti, qdss_cti,
+ blsp_uart4, pll_bist, NA, qdss_stm1),
+ PINGROUP(23, sec_mi2s, ebi2_lcd, qdss_cti, qdss_cti, blsp_uart1,
+ blsp_uart4, NA, qdss_stm0, NA),
+ PINGROUP(24, adsp_ext, NA, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(25, m_voc, adsp_ext, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(26, NA, NA, NA, native_char, NA, NA, NA, NA, NA),
+ PINGROUP(27, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(28, wmss_reset, native_char3, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(29, NA, NA, nav_pps, nav_dr, NA, native_char2, native_tsense,
+ NA, NA),
+ PINGROUP(30, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(31, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(32, NA, native_char1, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(33, NA, pa_indicator, qdss_traceclk, native_char0, NA, NA, NA,
+ NA, NA),
+ PINGROUP(34, qlink_en, NA, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(35, qlink_req, pll_test, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(36, NA, NA, cri_trng, NA, NA, NA, NA, NA, NA),
+ PINGROUP(37, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(38, NA, NA, prng_rosc, NA, NA, NA, NA, NA, NA),
+ PINGROUP(39, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(40, NA, NA, cri_trng0, NA, NA, NA, NA, NA, NA),
+ PINGROUP(41, NA, NA, cri_trng1, NA, NA, NA, NA, NA, NA),
+ PINGROUP(42, nav_pps, NA, nav_dr, pll_ref, NA, NA, NA, NA, NA),
+ PINGROUP(43, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(44, coex_uart, NA, qdss_stm11, NA, NA, NA, NA, NA, NA),
+ PINGROUP(45, coex_uart, NA, qdss_stm10, ddr_pxi0, NA, NA, NA, NA, NA),
+ PINGROUP(46, m_voc, ddr_bist, ddr_pxi0, NA, NA, NA, NA, NA, NA),
+ PINGROUP(47, ddr_bist, NA, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(48, ddr_bist, NA, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(49, ddr_bist, NA, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(50, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(51, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(52, blsp_spi2, blsp_spi1, blsp_spi3, blsp_spi4, NA, NA,
+ qdss_stm14, NA, NA),
+ PINGROUP(53, pci_e, NA, NA, qdss_stm13, NA, NA, NA, NA, NA),
+ PINGROUP(54, qdss_cti, qdss_cti, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(55, qdss_cti, qdss_cti, tgu_ch0, NA, NA, NA, NA, NA, NA),
+ PINGROUP(56, pcie_clkreq, NA, qdss_stm9, NA, NA, NA, NA, NA, NA),
+ PINGROUP(57, NA, qdss_stm15, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(58, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(59, qdss_cti, m_voc, bimc_dte0, NA, NA, NA, NA, NA, NA),
+ PINGROUP(60, mgpi_clk, NA, qdss_stm12, qdss_tracectl, bimc_dte1, NA,
+ NA, NA, NA),
+ PINGROUP(61, qdss_cti, NA, m_voc, NA, NA, NA, NA, NA, NA),
+ PINGROUP(62, i2s_mclk, nav_pps, nav_dr, audio_ref, blsp_spi1,
+ blsp_spi2, blsp_spi3, blsp_spi4, ldo_update),
+ PINGROUP(63, blsp_uart2, NA, qdss_stm7, qdss4, atest_char, NA, NA, NA,
+ NA),
+ PINGROUP(64, blsp_uart2, NA, qdss_stm6, qdss5, atest_char3, NA, NA, NA,
+ NA),
+ PINGROUP(65, blsp_uart2, blsp_i2c2, NA, qdss_stm5, qdss6, atest_char2,
+ NA, NA, NA),
+ PINGROUP(66, blsp_uart2, blsp_i2c2, NA, qdss_stm4, qdss7, atest_char1,
+ NA, NA, NA),
+ PINGROUP(67, uim1_data, atest_char0, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(68, uim1_present, NA, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(69, uim1_reset, NA, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(70, uim1_clk, NA, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(71, mgpi_clk, blsp_spi1, blsp_spi2, blsp_spi3, blsp_spi4,
+ dbg_out, NA, NA, NA),
+ PINGROUP(72, NA, blsp_spi1, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(73, NA, blsp_spi1, NA, gcc_plltest, NA, NA, NA, NA, NA),
+ PINGROUP(74, NA, blsp_spi1, NA, blsp_i2c1, gcc_plltest, NA, NA, NA, NA),
+ PINGROUP(75, NA, blsp_spi1, NA, blsp_i2c1, NA, NA, NA, NA, NA),
+ PINGROUP(76, blsp_i2c4, NA, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(77, blsp_i2c4, NA, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(78, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(79, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(80, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(81, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(82, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(83, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(84, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(85, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(86, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(87, NA, NA, usb2phy_ac, NA, NA, NA, NA, NA, NA),
+ PINGROUP(88, qdss_cti, qdss_cti, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(89, qdss_cti, qdss_cti, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(90, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(91, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(92, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(93, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(94, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(95, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(96, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(97, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(98, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(99, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+ SDC_QDSD_PINGROUP(sdc1_clk, 0x9a000, 13, 6),
+ SDC_QDSD_PINGROUP(sdc1_cmd, 0x9a000, 11, 3),
+ SDC_QDSD_PINGROUP(sdc1_data, 0x9a000, 9, 0),
+};
+
+static const struct msm_pinctrl_soc_data sdxpoorwills_pinctrl = {
+ .pins = sdxpoorwills_pins,
+ .npins = ARRAY_SIZE(sdxpoorwills_pins),
+ .functions = sdxpoorwills_functions,
+ .nfunctions = ARRAY_SIZE(sdxpoorwills_functions),
+ .groups = sdxpoorwills_groups,
+ .ngroups = ARRAY_SIZE(sdxpoorwills_groups),
+ .ngpios = 100,
+};
+
+static int sdxpoorwills_pinctrl_probe(struct platform_device *pdev)
+{
+ return msm_pinctrl_probe(pdev, &sdxpoorwills_pinctrl);
+}
+
+static const struct of_device_id sdxpoorwills_pinctrl_of_match[] = {
+ { .compatible = "qcom,sdxpoorwills-pinctrl", },
+ { },
+};
+
+static struct platform_driver sdxpoorwills_pinctrl_driver = {
+ .driver = {
+ .name = "sdxpoorwills-pinctrl",
+ .owner = THIS_MODULE,
+ .of_match_table = sdxpoorwills_pinctrl_of_match,
+ },
+ .probe = sdxpoorwills_pinctrl_probe,
+ .remove = msm_pinctrl_remove,
+};
+
+static int __init sdxpoorwills_pinctrl_init(void)
+{
+ return platform_driver_register(&sdxpoorwills_pinctrl_driver);
+}
+arch_initcall(sdxpoorwills_pinctrl_init);
+
+static void __exit sdxpoorwills_pinctrl_exit(void)
+{
+ platform_driver_unregister(&sdxpoorwills_pinctrl_driver);
+}
+module_exit(sdxpoorwills_pinctrl_exit);
+
+MODULE_DESCRIPTION("QTI sdxpoorwills pinctrl driver");
+MODULE_LICENSE("GPL v2");
+MODULE_DEVICE_TABLE(of, sdxpoorwills_pinctrl_of_match);
diff --git a/drivers/platform/msm/gsi/gsi_dbg.c b/drivers/platform/msm/gsi/gsi_dbg.c
index b1d1dfa..f5e23c68 100644
--- a/drivers/platform/msm/gsi/gsi_dbg.c
+++ b/drivers/platform/msm/gsi/gsi_dbg.c
@@ -29,6 +29,7 @@
static struct dentry *dent;
static char dbg_buff[4096];
+static void *gsi_ipc_logbuf_low;
static void gsi_wq_print_dp_stats(struct work_struct *work);
static DECLARE_DELAYED_WORK(gsi_print_dp_stats_work, gsi_wq_print_dp_stats);
@@ -758,22 +759,20 @@
if (kstrtos8(dbg_buff, 0, &option))
return -EFAULT;
+ mutex_lock(&gsi_ctx->mlock);
if (option) {
- if (!gsi_ctx->ipc_logbuf_low) {
- gsi_ctx->ipc_logbuf_low =
+ if (!gsi_ipc_logbuf_low) {
+ gsi_ipc_logbuf_low =
ipc_log_context_create(GSI_IPC_LOG_PAGES,
"gsi_low", 0);
+ if (gsi_ipc_logbuf_low == NULL)
+ TERR("failed to get ipc_logbuf_low\n");
}
-
- if (gsi_ctx->ipc_logbuf_low == NULL) {
- TERR("failed to get ipc_logbuf_low\n");
- return -EFAULT;
- }
+ gsi_ctx->ipc_logbuf_low = gsi_ipc_logbuf_low;
} else {
- if (gsi_ctx->ipc_logbuf_low)
- ipc_log_context_destroy(gsi_ctx->ipc_logbuf_low);
gsi_ctx->ipc_logbuf_low = NULL;
}
+ mutex_unlock(&gsi_ctx->mlock);
return count;
}
diff --git a/drivers/platform/msm/ipa/ipa_api.c b/drivers/platform/msm/ipa/ipa_api.c
index d45fa51..a37947b 100644
--- a/drivers/platform/msm/ipa/ipa_api.c
+++ b/drivers/platform/msm/ipa/ipa_api.c
@@ -126,6 +126,7 @@
__stringify(IPA_CLIENT_Q6_DECOMP_PROD),
__stringify(IPA_CLIENT_Q6_DECOMP2_PROD),
__stringify(IPA_CLIENT_UC_USB_PROD),
+ __stringify(IPA_CLIENT_ETHERNET_PROD),
/* Below PROD client type is only for test purpose */
__stringify(IPA_CLIENT_TEST_PROD),
@@ -164,6 +165,7 @@
__stringify(IPA_CLIENT_Q6_DECOMP_CONS),
__stringify(IPA_CLIENT_Q6_DECOMP2_CONS),
__stringify(IPA_CLIENT_Q6_LTE_WIFI_AGGR_CONS),
+ __stringify(IPA_CLIENT_ETHERNET_CONS),
/* Below CONS client type is only for test purpose */
__stringify(IPA_CLIENT_TEST_CONS),
__stringify(IPA_CLIENT_TEST1_CONS),
diff --git a/drivers/platform/msm/ipa/ipa_v2/ipa.c b/drivers/platform/msm/ipa/ipa_v2/ipa.c
index 15bb7b4..af4d4c8 100644
--- a/drivers/platform/msm/ipa/ipa_v2/ipa.c
+++ b/drivers/platform/msm/ipa/ipa_v2/ipa.c
@@ -1584,6 +1584,7 @@
struct ipa_hw_imm_cmd_dma_shared_mem *cmd = NULL;
struct ipa_desc desc;
struct ipa_mem_buffer mem;
+ gfp_t flag = GFP_KERNEL | (ipa_ctx->use_dma_zone ? GFP_DMA : 0);
int rc;
if (memory_region_size == 0)
@@ -1603,7 +1604,7 @@
memset(mem.base, 0, mem.size);
cmd = kzalloc(sizeof(*cmd),
- GFP_KERNEL);
+ flag);
if (cmd == NULL) {
IPAERR("Failed to alloc immediate command object\n");
rc = -ENOMEM;
@@ -2166,6 +2167,7 @@
struct ipa_hw_imm_cmd_dma_shared_mem *cmd = NULL;
struct ipa_desc desc = {0};
struct ipa_mem_buffer mem;
+ gfp_t flag = GFP_KERNEL | (ipa_ctx->use_dma_zone ? GFP_DMA : 0);
int rc = 0;
phys_addr = ipa_ctx->ipa_wrapper_base +
@@ -2203,7 +2205,7 @@
}
memset(mem.base, 0, mem.size);
- cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
+ cmd = kzalloc(sizeof(*cmd), flag);
if (cmd == NULL) {
IPAERR("Failed to alloc immediate command object\n");
rc = -ENOMEM;
@@ -2314,6 +2316,7 @@
struct ipa_desc desc = { 0 };
struct ipa_mem_buffer mem;
struct ipa_hdr_init_local *cmd = NULL;
+ gfp_t flag = GFP_KERNEL | (ipa_ctx->use_dma_zone ? GFP_DMA : 0);
int rc = 0;
mem.size = IPA_MEM_PART(modem_hdr_size) + IPA_MEM_PART(apps_hdr_size);
@@ -2325,7 +2328,7 @@
}
memset(mem.base, 0, mem.size);
- cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
+ cmd = kzalloc(sizeof(*cmd), flag);
if (cmd == NULL) {
IPAERR("Failed to alloc header init command object\n");
rc = -ENOMEM;
@@ -2360,6 +2363,7 @@
struct ipa_mem_buffer mem;
struct ipa_hdr_init_local *cmd = NULL;
struct ipa_hw_imm_cmd_dma_shared_mem *dma_cmd = NULL;
+ gfp_t flag = GFP_KERNEL | (ipa_ctx->use_dma_zone ? GFP_DMA : 0);
mem.size = IPA_MEM_PART(modem_hdr_size) + IPA_MEM_PART(apps_hdr_size);
mem.base = dma_alloc_coherent(ipa_ctx->pdev, mem.size, &mem.phys_base,
@@ -2370,7 +2374,7 @@
}
memset(mem.base, 0, mem.size);
- cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
+ cmd = kzalloc(sizeof(*cmd), flag);
if (cmd == NULL) {
IPAERR("Failed to alloc header init command object\n");
dma_free_coherent(ipa_ctx->pdev, mem.size, mem.base,
@@ -2411,7 +2415,7 @@
memset(mem.base, 0, mem.size);
memset(&desc, 0, sizeof(desc));
- dma_cmd = kzalloc(sizeof(*dma_cmd), GFP_KERNEL);
+ dma_cmd = kzalloc(sizeof(*dma_cmd), flag);
if (dma_cmd == NULL) {
IPAERR("Failed to alloc immediate command object\n");
dma_free_coherent(ipa_ctx->pdev,
@@ -2462,6 +2466,7 @@
struct ipa_desc desc = { 0 };
struct ipa_mem_buffer mem;
struct ipa_ip_v4_routing_init *v4_cmd = NULL;
+ gfp_t flag = GFP_KERNEL | (ipa_ctx->use_dma_zone ? GFP_DMA : 0);
u32 *entry;
int i;
int rc = 0;
@@ -2486,7 +2491,7 @@
entry++;
}
- v4_cmd = kzalloc(sizeof(*v4_cmd), GFP_KERNEL);
+ v4_cmd = kzalloc(sizeof(*v4_cmd), flag);
if (v4_cmd == NULL) {
IPAERR("Failed to alloc v4 routing init command object\n");
rc = -ENOMEM;
@@ -2522,6 +2527,7 @@
struct ipa_desc desc = { 0 };
struct ipa_mem_buffer mem;
struct ipa_ip_v6_routing_init *v6_cmd = NULL;
+ gfp_t flag = GFP_KERNEL | (ipa_ctx->use_dma_zone ? GFP_DMA : 0);
u32 *entry;
int i;
int rc = 0;
@@ -2546,7 +2552,7 @@
entry++;
}
- v6_cmd = kzalloc(sizeof(*v6_cmd), GFP_KERNEL);
+ v6_cmd = kzalloc(sizeof(*v6_cmd), flag);
if (v6_cmd == NULL) {
IPAERR("Failed to alloc v6 routing init command object\n");
rc = -ENOMEM;
@@ -2582,6 +2588,7 @@
struct ipa_desc desc = { 0 };
struct ipa_mem_buffer mem;
struct ipa_ip_v4_filter_init *v4_cmd = NULL;
+ gfp_t flag = GFP_KERNEL | (ipa_ctx->use_dma_zone ? GFP_DMA : 0);
u32 *entry;
int i;
int rc = 0;
@@ -2604,7 +2611,7 @@
entry++;
}
- v4_cmd = kzalloc(sizeof(*v4_cmd), GFP_KERNEL);
+ v4_cmd = kzalloc(sizeof(*v4_cmd), flag);
if (v4_cmd == NULL) {
IPAERR("Failed to alloc v4 fliter init command object\n");
rc = -ENOMEM;
@@ -2640,6 +2647,7 @@
struct ipa_desc desc = { 0 };
struct ipa_mem_buffer mem;
struct ipa_ip_v6_filter_init *v6_cmd = NULL;
+ gfp_t flag = GFP_KERNEL | (ipa_ctx->use_dma_zone ? GFP_DMA : 0);
u32 *entry;
int i;
int rc = 0;
@@ -2662,7 +2670,7 @@
entry++;
}
- v6_cmd = kzalloc(sizeof(*v6_cmd), GFP_KERNEL);
+ v6_cmd = kzalloc(sizeof(*v6_cmd), flag);
if (v6_cmd == NULL) {
IPAERR("Failed to alloc v6 fliter init command object\n");
rc = -ENOMEM;
diff --git a/drivers/platform/msm/ipa/ipa_v2/ipa_dp.c b/drivers/platform/msm/ipa/ipa_v2/ipa_dp.c
index 3dca3e6..a822f66 100644
--- a/drivers/platform/msm/ipa/ipa_v2/ipa_dp.c
+++ b/drivers/platform/msm/ipa/ipa_v2/ipa_dp.c
@@ -322,8 +322,8 @@
dma_address = desc->dma_address;
tx_pkt->no_unmap_dma = true;
}
- if (!dma_address) {
- IPAERR("failed to DMA wrap\n");
+ if (dma_mapping_error(ipa_ctx->pdev, dma_address)) {
+ IPAERR("dma_map_single failed\n");
goto fail_dma_map;
}
@@ -445,7 +445,7 @@
}
dma_addr = dma_map_single(ipa_ctx->pdev,
transfer.iovec, size, DMA_TO_DEVICE);
- if (!dma_addr) {
+ if (dma_mapping_error(ipa_ctx->pdev, dma_addr)) {
IPAERR("dma_map_single failed for sps xfr buff\n");
kfree(transfer.iovec);
return -EFAULT;
@@ -493,6 +493,15 @@
tx_pkt->mem.base,
tx_pkt->mem.size,
DMA_TO_DEVICE);
+
+ if (dma_mapping_error(ipa_ctx->pdev,
+ tx_pkt->mem.phys_base)) {
+ IPAERR("dma_map_single ");
+ IPAERR("failed\n");
+ fail_dma_wrap = 1;
+ goto failure;
+ }
+
} else {
tx_pkt->mem.phys_base = desc[i].dma_address;
tx_pkt->no_unmap_dma = true;
@@ -1873,8 +1882,8 @@
rx_pkt->data.dma_addr = dma_map_single(ipa_ctx->pdev, ptr,
sys->rx_buff_sz,
DMA_FROM_DEVICE);
- if (rx_pkt->data.dma_addr == 0 ||
- rx_pkt->data.dma_addr == ~0) {
+ if (dma_mapping_error(ipa_ctx->pdev,
+ rx_pkt->data.dma_addr)) {
pr_err_ratelimited("%s dma map fail %p for %p sys=%p\n",
__func__, (void *)rx_pkt->data.dma_addr,
ptr, sys);
@@ -2029,18 +2038,20 @@
ptr = skb_put(rx_pkt->data.skb, IPA_WLAN_RX_BUFF_SZ);
rx_pkt->data.dma_addr = dma_map_single(ipa_ctx->pdev, ptr,
IPA_WLAN_RX_BUFF_SZ, DMA_FROM_DEVICE);
- if (rx_pkt->data.dma_addr == 0 ||
- rx_pkt->data.dma_addr == ~0) {
+ if (dma_mapping_error(ipa_ctx->pdev,
+ rx_pkt->data.dma_addr)) {
IPAERR("dma_map_single failure %p for %p\n",
(void *)rx_pkt->data.dma_addr, ptr);
goto fail_dma_mapping;
}
+ spin_lock_bh(&ipa_ctx->wc_memb.wlan_spinlock);
list_add_tail(&rx_pkt->link,
&ipa_ctx->wc_memb.wlan_comm_desc_list);
rx_len_cached = ++ipa_ctx->wc_memb.wlan_comm_total_cnt;
ipa_ctx->wc_memb.wlan_comm_free_cnt++;
+ spin_unlock_bh(&ipa_ctx->wc_memb.wlan_spinlock);
}
@@ -2101,8 +2112,8 @@
rx_pkt->data.dma_addr = dma_map_single(ipa_ctx->pdev, ptr,
sys->rx_buff_sz,
DMA_FROM_DEVICE);
- if (rx_pkt->data.dma_addr == 0 ||
- rx_pkt->data.dma_addr == ~0) {
+ if (dma_mapping_error(ipa_ctx->pdev,
+ rx_pkt->data.dma_addr)) {
IPAERR("dma_map_single failure %p for %p\n",
(void *)rx_pkt->data.dma_addr, ptr);
goto fail_dma_mapping;
@@ -2159,9 +2170,10 @@
ptr = skb_put(rx_pkt->data.skb, sys->rx_buff_sz);
rx_pkt->data.dma_addr = dma_map_single(ipa_ctx->pdev,
ptr, sys->rx_buff_sz, DMA_FROM_DEVICE);
- if (rx_pkt->data.dma_addr == 0 ||
- rx_pkt->data.dma_addr == ~0)
+ if (dma_mapping_error(ipa_ctx->pdev, rx_pkt->data.dma_addr)) {
+ IPAERR("dma_map_single failure for rx_pkt\n");
goto fail_dma_mapping;
+ }
list_add_tail(&rx_pkt->link, &sys->head_desc_list);
rx_len_cached = ++sys->len;
diff --git a/drivers/platform/msm/ipa/ipa_v2/ipa_hdr.c b/drivers/platform/msm/ipa/ipa_v2/ipa_hdr.c
index 25f8923..046f77f 100644
--- a/drivers/platform/msm/ipa/ipa_v2/ipa_hdr.c
+++ b/drivers/platform/msm/ipa/ipa_v2/ipa_hdr.c
@@ -268,6 +268,7 @@
struct ipa_mem_buffer mem;
struct ipa_hdr_init_system *cmd = NULL;
struct ipa_hw_imm_cmd_dma_shared_mem *dma_cmd = NULL;
+ gfp_t flag = GFP_ATOMIC | (ipa_ctx->use_dma_zone ? GFP_DMA : 0);
int rc = -EFAULT;
if (ipa_generate_hdr_hw_tbl(&mem)) {
@@ -281,7 +282,7 @@
IPA_MEM_PART(apps_hdr_size));
goto fail_send_cmd;
} else {
- dma_cmd = kzalloc(sizeof(*dma_cmd), GFP_ATOMIC);
+ dma_cmd = kzalloc(sizeof(*dma_cmd), flag);
if (dma_cmd == NULL) {
IPAERR("fail to alloc immediate cmd\n");
rc = -ENOMEM;
@@ -303,7 +304,7 @@
IPA_MEM_PART(apps_hdr_size_ddr));
goto fail_send_cmd;
} else {
- cmd = kzalloc(sizeof(*cmd), GFP_ATOMIC);
+ cmd = kzalloc(sizeof(*cmd), flag);
if (cmd == NULL) {
IPAERR("fail to alloc hdr init cmd\n");
rc = -ENOMEM;
@@ -359,6 +360,7 @@
struct ipa_hw_imm_cmd_dma_shared_mem *dma_cmd_hdr = NULL;
struct ipa_hw_imm_cmd_dma_shared_mem *dma_cmd_ctx = NULL;
struct ipa_register_write *reg_write_cmd = NULL;
+ gfp_t flag = GFP_ATOMIC | (ipa_ctx->use_dma_zone ? GFP_DMA : 0);
int rc = -EFAULT;
u32 proc_ctx_size;
u32 proc_ctx_ofst;
@@ -383,7 +385,7 @@
IPA_MEM_PART(apps_hdr_size));
goto fail_send_cmd1;
} else {
- dma_cmd_hdr = kzalloc(sizeof(*dma_cmd_hdr), GFP_ATOMIC);
+ dma_cmd_hdr = kzalloc(sizeof(*dma_cmd_hdr), flag);
if (dma_cmd_hdr == NULL) {
IPAERR("fail to alloc immediate cmd\n");
rc = -ENOMEM;
@@ -406,7 +408,7 @@
goto fail_send_cmd1;
} else {
hdr_init_cmd = kzalloc(sizeof(*hdr_init_cmd),
- GFP_ATOMIC);
+ flag);
if (hdr_init_cmd == NULL) {
IPAERR("fail to alloc immediate cmd\n");
rc = -ENOMEM;
@@ -431,7 +433,7 @@
goto fail_send_cmd1;
} else {
dma_cmd_ctx = kzalloc(sizeof(*dma_cmd_ctx),
- GFP_ATOMIC);
+ flag);
if (dma_cmd_ctx == NULL) {
IPAERR("fail to alloc immediate cmd\n");
rc = -ENOMEM;
@@ -456,7 +458,7 @@
goto fail_send_cmd1;
} else {
reg_write_cmd = kzalloc(sizeof(*reg_write_cmd),
- GFP_ATOMIC);
+ flag);
if (reg_write_cmd == NULL) {
IPAERR("fail to alloc immediate cmd\n");
rc = -ENOMEM;
@@ -722,6 +724,11 @@
entry->hdr,
entry->hdr_len,
DMA_TO_DEVICE);
+ if (dma_mapping_error(ipa_ctx->pdev,
+ entry->phys_base)) {
+ IPAERR("dma_map_single failure for entry\n");
+ goto fail_dma_mapping;
+ }
}
} else {
entry->is_hdr_proc_ctx = false;
@@ -798,6 +805,8 @@
list_del(&entry->link);
dma_unmap_single(ipa_ctx->pdev, entry->phys_base,
entry->hdr_len, DMA_TO_DEVICE);
+fail_dma_mapping:
+ entry->is_hdr_proc_ctx = false;
bad_hdr_len:
entry->cookie = 0;
kmem_cache_free(ipa_ctx->hdr_cache, entry);
diff --git a/drivers/platform/msm/ipa/ipa_v2/ipa_rt.c b/drivers/platform/msm/ipa/ipa_v2/ipa_rt.c
index 84849a2..21fdec0 100644
--- a/drivers/platform/msm/ipa/ipa_v2/ipa_rt.c
+++ b/drivers/platform/msm/ipa/ipa_v2/ipa_rt.c
@@ -695,6 +695,7 @@
struct ipa_mem_buffer head;
struct ipa_hw_imm_cmd_dma_shared_mem *cmd1 = NULL;
struct ipa_hw_imm_cmd_dma_shared_mem *cmd2 = NULL;
+ gfp_t flag = GFP_KERNEL | (ipa_ctx->use_dma_zone ? GFP_DMA : 0);
u16 avail;
u32 num_modem_rt_index;
int rc = 0;
@@ -745,7 +746,7 @@
}
cmd1 = kzalloc(sizeof(struct ipa_hw_imm_cmd_dma_shared_mem),
- GFP_KERNEL);
+ flag);
if (cmd1 == NULL) {
IPAERR("Failed to alloc immediate command object\n");
rc = -ENOMEM;
@@ -762,7 +763,7 @@
if (lcl) {
cmd2 = kzalloc(sizeof(struct ipa_hw_imm_cmd_dma_shared_mem),
- GFP_KERNEL);
+ flag);
if (cmd2 == NULL) {
IPAERR("Failed to alloc immediate command object\n");
rc = -ENOMEM;
diff --git a/drivers/platform/msm/ipa/ipa_v2/rmnet_ipa.c b/drivers/platform/msm/ipa/ipa_v2/rmnet_ipa.c
index 0af9387..4672233 100644
--- a/drivers/platform/msm/ipa/ipa_v2/rmnet_ipa.c
+++ b/drivers/platform/msm/ipa/ipa_v2/rmnet_ipa.c
@@ -1541,6 +1541,9 @@
memcpy(mux_channel[rmnet_index].vchannel_name,
extend_ioctl_data.u.rmnet_mux_val.vchannel_name,
sizeof(mux_channel[rmnet_index].vchannel_name));
+ mux_channel[rmnet_index].vchannel_name[
+ IFNAMSIZ - 1] = '\0';
+
IPAWANDBG("cashe device[%s:%d] in IPA_wan[%d]\n",
mux_channel[rmnet_index].vchannel_name,
mux_channel[rmnet_index].mux_id,
diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa.c b/drivers/platform/msm/ipa/ipa_v3/ipa.c
index 5fd6dcc..83fd2b2 100644
--- a/drivers/platform/msm/ipa/ipa_v3/ipa.c
+++ b/drivers/platform/msm/ipa/ipa_v3/ipa.c
@@ -2268,6 +2268,36 @@
desc[num_descs].len = cmd_pyld->len;
num_descs++;
}
+
+ /* disable statuses for modem producers */
+ if (IPA_CLIENT_IS_Q6_PROD(client_idx)) {
+ ipa_assert_on(num_descs >= ipa3_ctx->ipa_num_pipes);
+
+ reg_write.skip_pipeline_clear = false;
+ reg_write.pipeline_clear_options =
+ IPAHAL_HPS_CLEAR;
+ reg_write.offset =
+ ipahal_get_reg_n_ofst(IPA_ENDP_STATUS_n,
+ ep_idx);
+ reg_write.value = 0;
+ reg_write.value_mask = ~0;
+ cmd_pyld = ipahal_construct_imm_cmd(
+ IPA_IMM_CMD_REGISTER_WRITE, ®_write, false);
+ if (!cmd_pyld) {
+ IPAERR("fail construct register_write cmd\n");
+ ipa_assert();
+ return -EFAULT;
+ }
+
+ desc[num_descs].opcode = ipahal_imm_cmd_get_opcode(
+ IPA_IMM_CMD_REGISTER_WRITE);
+ desc[num_descs].type = IPA_IMM_CMD_DESC;
+ desc[num_descs].callback = ipa3_destroy_imm;
+ desc[num_descs].user1 = cmd_pyld;
+ desc[num_descs].pyld = cmd_pyld->data;
+ desc[num_descs].len = cmd_pyld->len;
+ num_descs++;
+ }
}
/* Will wait 500msecs for IPA tag process completion */
@@ -2367,11 +2397,11 @@
}
/**
- * _ipa_init_sram_v3_0() - Initialize IPA local SRAM.
+ * _ipa_init_sram_v3() - Initialize IPA local SRAM.
*
* Return codes: 0 for success, negative value for failure
*/
-int _ipa_init_sram_v3_0(void)
+int _ipa_init_sram_v3(void)
{
u32 *ipa_sram_mmio;
unsigned long phys_addr;
@@ -2414,7 +2444,10 @@
IPA_MEM_PART(modem_hdr_proc_ctx_ofst));
ipa3_sram_set_canary(ipa_sram_mmio, IPA_MEM_PART(modem_ofst) - 4);
ipa3_sram_set_canary(ipa_sram_mmio, IPA_MEM_PART(modem_ofst));
- ipa3_sram_set_canary(ipa_sram_mmio, IPA_MEM_PART(end_ofst));
+ ipa3_sram_set_canary(ipa_sram_mmio,
+ (ipa_get_hw_type() >= IPA_HW_v3_5) ?
+ IPA_MEM_PART(uc_event_ring_ofst) :
+ IPA_MEM_PART(end_ofst));
iounmap(ipa_sram_mmio);
@@ -4064,6 +4097,7 @@
cdev_del(&ipa3_ctx->cdev);
device_destroy(ipa3_ctx->class, ipa3_ctx->dev_num);
unregister_chrdev_region(ipa3_ctx->dev_num, 1);
+ ipa3_free_dma_task_for_gsi();
ipa3_destroy_flt_tbl_idrs();
idr_destroy(&ipa3_ctx->ipa_idr);
kmem_cache_destroy(ipa3_ctx->rx_pkt_wrapper_cache);
@@ -4604,6 +4638,13 @@
goto fail_rx_pkt_wrapper_cache;
}
+ /* allocate memory for DMA_TASK workaround */
+ result = ipa3_allocate_dma_task_for_gsi();
+ if (result) {
+ IPAERR("failed to allocate dma task\n");
+ goto fail_dma_task;
+ }
+
/* init the various list heads */
INIT_LIST_HEAD(&ipa3_ctx->hdr_tbl.head_hdr_entry_list);
for (i = 0; i < IPA_HDR_BIN_MAX; i++) {
@@ -4744,6 +4785,8 @@
fail_device_create:
unregister_chrdev_region(ipa3_ctx->dev_num, 1);
fail_alloc_chrdev_region:
+ ipa3_free_dma_task_for_gsi();
+fail_dma_task:
idr_destroy(&ipa3_ctx->ipa_idr);
kmem_cache_destroy(ipa3_ctx->rx_pkt_wrapper_cache);
fail_rx_pkt_wrapper_cache:
@@ -5488,13 +5531,6 @@
return result;
}
- result = of_platform_populate(pdev_p->dev.of_node,
- pdrv_match, NULL, &pdev_p->dev);
- if (result) {
- IPAERR("failed to populate platform\n");
- return result;
- }
-
if (of_property_read_bool(pdev_p->dev.of_node, "qcom,arm-smmu")) {
if (of_property_read_bool(pdev_p->dev.of_node,
"qcom,smmu-s1-bypass"))
@@ -5540,6 +5576,13 @@
}
}
+ result = of_platform_populate(pdev_p->dev.of_node,
+ pdrv_match, NULL, &pdev_p->dev);
+ if (result) {
+ IPAERR("failed to populate platform\n");
+ return result;
+ }
+
return result;
}
diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_debugfs.c b/drivers/platform/msm/ipa/ipa_v3/ipa_debugfs.c
index a414029..ca77be9 100644
--- a/drivers/platform/msm/ipa/ipa_v3/ipa_debugfs.c
+++ b/drivers/platform/msm/ipa/ipa_v3/ipa_debugfs.c
@@ -106,6 +106,7 @@
static char *active_clients_buf;
static s8 ep_reg_idx;
+static void *ipa_ipc_low_buff;
static ssize_t ipa3_read_gen_reg(struct file *file, char __user *ubuf,
@@ -1758,22 +1759,20 @@
if (kstrtos8(dbg_buff, 0, &option))
return -EFAULT;
+ mutex_lock(&ipa3_ctx->lock);
if (option) {
- if (!ipa3_ctx->logbuf_low) {
- ipa3_ctx->logbuf_low =
+ if (!ipa_ipc_low_buff) {
+ ipa_ipc_low_buff =
ipc_log_context_create(IPA_IPC_LOG_PAGES,
"ipa_low", 0);
}
-
- if (ipa3_ctx->logbuf_low == NULL) {
- IPAERR("failed to get logbuf_low\n");
- return -EFAULT;
- }
+ if (ipa_ipc_low_buff == NULL)
+ IPAERR("failed to get logbuf_low\n");
+ ipa3_ctx->logbuf_low = ipa_ipc_low_buff;
} else {
- if (ipa3_ctx->logbuf_low)
- ipc_log_context_destroy(ipa3_ctx->logbuf_low);
ipa3_ctx->logbuf_low = NULL;
}
+ mutex_unlock(&ipa3_ctx->lock);
return count;
}
diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_dp.c b/drivers/platform/msm/ipa/ipa_v3/ipa_dp.c
index 3937cfe..9d25e4a 100644
--- a/drivers/platform/msm/ipa/ipa_v3/ipa_dp.c
+++ b/drivers/platform/msm/ipa/ipa_v3/ipa_dp.c
@@ -3509,6 +3509,7 @@
if (!gsi_channel_props.ring_base_vaddr) {
IPAERR("fail to dma alloc %u bytes\n",
gsi_channel_props.ring_len);
+ result = -ENOMEM;
goto fail_alloc_channel_ring;
}
gsi_channel_props.ring_base_addr = dma_addr;
diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_i.h b/drivers/platform/msm/ipa/ipa_v3/ipa_i.h
index 8261a26..3af4486 100644
--- a/drivers/platform/msm/ipa/ipa_v3/ipa_i.h
+++ b/drivers/platform/msm/ipa/ipa_v3/ipa_i.h
@@ -997,6 +997,11 @@
u32 size;
};
+struct ipa_dma_task_info {
+ struct ipa_mem_buffer mem;
+ struct ipahal_imm_cmd_pyld *cmd_pyld;
+};
+
/**
* struct ipa3_context - IPA context
* @class: pointer to the struct class
@@ -1206,6 +1211,7 @@
struct ipa3_smp2p_info smp2p_info;
u32 ipa_tz_unlock_reg_num;
struct ipa_tz_unlock_reg_info *ipa_tz_unlock_reg;
+ struct ipa_dma_task_info dma_task_info;
};
struct ipa3_plat_drv_res {
@@ -1240,7 +1246,9 @@
* Order and type of members should not be changed without a suitable change
* to DTS file or the code that reads it.
*
- * IPA v3.0 SRAM memory layout:
+ * IPA SRAM memory layout:
+ * +-------------------------+
+ * | UC MEM |
* +-------------------------+
* | UC INFO |
* +-------------------------+
@@ -1308,10 +1316,14 @@
* +-------------------------+
* | CANARY |
* +-------------------------+
+ * | CANARY |
+ * +-------------------------+
* | MODEM MEM |
* +-------------------------+
* | CANARY |
* +-------------------------+
+ * | UC EVENT RING | From IPA 3.5
+ * +-------------------------+
*/
struct ipa3_mem_partition {
u32 ofst_start;
@@ -1384,6 +1396,8 @@
u32 apps_v6_rt_hash_size;
u32 apps_v6_rt_nhash_ofst;
u32 apps_v6_rt_nhash_size;
+ u32 uc_event_ring_ofst;
+ u32 uc_event_ring_size;
};
struct ipa3_controller {
@@ -1838,7 +1852,7 @@
int ipa3_teth_bridge_driver_init(void);
void ipa3_lan_rx_cb(void *priv, enum ipa_dp_evt_type evt, unsigned long data);
-int _ipa_init_sram_v3_0(void);
+int _ipa_init_sram_v3(void);
int _ipa_init_hdr_v3_0(void);
int _ipa_init_rt4_v3(void);
int _ipa_init_rt6_v3(void);
@@ -1982,4 +1996,6 @@
void ipa3_enable_dcd(void);
void ipa3_disable_prefetch(enum ipa_client_type client);
int ipa3_alloc_common_event_ring(void);
+int ipa3_allocate_dma_task_for_gsi(void);
+void ipa3_free_dma_task_for_gsi(void);
#endif /* _IPA3_I_H_ */
diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_utils.c b/drivers/platform/msm/ipa/ipa_v3/ipa_utils.c
index db3d6a4..5a38db3 100644
--- a/drivers/platform/msm/ipa/ipa_v3/ipa_utils.c
+++ b/drivers/platform/msm/ipa/ipa_v3/ipa_utils.c
@@ -2909,17 +2909,54 @@
*/
int ipa3_init_mem_partition(struct device_node *node)
{
+ const size_t ram_mmap_v3_0_size = 70;
+ const size_t ram_mmap_v3_5_size = 72;
+ const size_t ram_mmap_current_version_size =
+ sizeof(ipa3_ctx->ctrl->mem_partition) / sizeof(u32);
+ const size_t version = ipa_get_hw_type();
int result;
IPADBG("Reading from DTS as u32 array\n");
- result = of_property_read_u32_array(node,
- "qcom,ipa-ram-mmap", (u32 *)&ipa3_ctx->ctrl->mem_partition,
- sizeof(ipa3_ctx->ctrl->mem_partition) / sizeof(u32));
- if (result) {
+ /*
+ * The size of ipa-ram-mmap array depends on the IPA version. The
+ * actual size can't be assumed because of possible DTS versions
+ * mismatch. The size of the array monotonically increasing because the
+ * obsolete entries are set to zero rather than deleted, so the
+ * possible sizes are in range
+ * [ram_mmap_v3_0_size, ram_mmap_current_version_size]
+ */
+ result = of_property_read_variable_u32_array(node, "qcom,ipa-ram-mmap",
+ (u32 *)&ipa3_ctx->ctrl->mem_partition,
+ ram_mmap_v3_0_size, ram_mmap_current_version_size);
+
+ if (result <= 0) {
IPAERR("Read operation failed\n");
return -ENODEV;
}
+ if (version < IPA_HW_v3_0)
+ ipa_assert();
+ if (version < IPA_HW_v3_5) {
+ if (result != ram_mmap_v3_0_size) {
+ IPAERR("Mismatch at IPA RAM MMAP DTS entry\n");
+ return -ENODEV;
+ }
+ } else {
+ if (result != ram_mmap_v3_5_size) {
+ IPAERR("Mismatch at IPA RAM MMAP DTS entry\n");
+ return -ENODEV;
+ }
+
+ if (IPA_MEM_PART(uc_event_ring_ofst) & 1023) {
+ IPAERR("UC EVENT RING OFST 0x%x is unaligned\n",
+ IPA_MEM_PART(uc_event_ring_ofst));
+ return -ENODEV;
+ }
+
+ IPADBG("UC EVENT RING OFST 0x%x SIZE 0x%x\n",
+ IPA_MEM_PART(uc_event_ring_ofst),
+ IPA_MEM_PART(uc_event_ring_size));
+ }
IPADBG("NAT OFST 0x%x SIZE 0x%x\n", IPA_MEM_PART(nat_ofst),
IPA_MEM_PART(nat_size));
@@ -3167,7 +3204,7 @@
ctrl->clock_scaling_bw_threshold_turbo =
IPA_V3_0_BW_THRESHOLD_TURBO_MBPS;
ctrl->ipa_reg_base_ofst = ipahal_get_reg_base();
- ctrl->ipa_init_sram = _ipa_init_sram_v3_0;
+ ctrl->ipa_init_sram = _ipa_init_sram_v3;
ctrl->ipa_sram_read_settings = _ipa_sram_settings_read_v3_0;
ctrl->ipa_init_hdr = _ipa_init_hdr_v3_0;
@@ -4216,6 +4253,51 @@
}
}
+int ipa3_allocate_dma_task_for_gsi(void)
+{
+ struct ipahal_imm_cmd_dma_task_32b_addr cmd = { 0 };
+
+ IPADBG("Allocate mem\n");
+ ipa3_ctx->dma_task_info.mem.size = IPA_GSI_CHANNEL_STOP_PKT_SIZE;
+ ipa3_ctx->dma_task_info.mem.base = dma_alloc_coherent(ipa3_ctx->pdev,
+ ipa3_ctx->dma_task_info.mem.size,
+ &ipa3_ctx->dma_task_info.mem.phys_base,
+ GFP_KERNEL);
+ if (!ipa3_ctx->dma_task_info.mem.base) {
+ IPAERR("no mem\n");
+ return -EFAULT;
+ }
+
+ cmd.flsh = 1;
+ cmd.size1 = ipa3_ctx->dma_task_info.mem.size;
+ cmd.addr1 = ipa3_ctx->dma_task_info.mem.phys_base;
+ cmd.packet_size = ipa3_ctx->dma_task_info.mem.size;
+ ipa3_ctx->dma_task_info.cmd_pyld = ipahal_construct_imm_cmd(
+ IPA_IMM_CMD_DMA_TASK_32B_ADDR, &cmd, false);
+ if (!ipa3_ctx->dma_task_info.cmd_pyld) {
+ IPAERR("failed to construct dma_task_32b_addr cmd\n");
+ dma_free_coherent(ipa3_ctx->pdev,
+ ipa3_ctx->dma_task_info.mem.size,
+ ipa3_ctx->dma_task_info.mem.base,
+ ipa3_ctx->dma_task_info.mem.phys_base);
+ memset(&ipa3_ctx->dma_task_info, 0,
+ sizeof(ipa3_ctx->dma_task_info));
+ return -EFAULT;
+ }
+
+ return 0;
+}
+
+void ipa3_free_dma_task_for_gsi(void)
+{
+ dma_free_coherent(ipa3_ctx->pdev,
+ ipa3_ctx->dma_task_info.mem.size,
+ ipa3_ctx->dma_task_info.mem.base,
+ ipa3_ctx->dma_task_info.mem.phys_base);
+ ipahal_destroy_imm_cmd(ipa3_ctx->dma_task_info.cmd_pyld);
+ memset(&ipa3_ctx->dma_task_info, 0, sizeof(ipa3_ctx->dma_task_info));
+}
+
/**
* ipa3_inject_dma_task_for_gsi()- Send DMA_TASK to IPA for GSI stop channel
*
@@ -4224,41 +4306,12 @@
*/
int ipa3_inject_dma_task_for_gsi(void)
{
- static struct ipa_mem_buffer mem = {0};
- struct ipahal_imm_cmd_dma_task_32b_addr cmd = {0};
- static struct ipahal_imm_cmd_pyld *cmd_pyld;
struct ipa3_desc desc = {0};
- /* allocate the memory only for the very first time */
- if (!mem.base) {
- IPADBG("Allocate mem\n");
- mem.size = IPA_GSI_CHANNEL_STOP_PKT_SIZE;
- mem.base = dma_alloc_coherent(ipa3_ctx->pdev,
- mem.size,
- &mem.phys_base,
- GFP_KERNEL);
- if (!mem.base) {
- IPAERR("no mem\n");
- return -EFAULT;
- }
- }
- if (!cmd_pyld) {
- cmd.flsh = 1;
- cmd.size1 = mem.size;
- cmd.addr1 = mem.phys_base;
- cmd.packet_size = mem.size;
- cmd_pyld = ipahal_construct_imm_cmd(
- IPA_IMM_CMD_DMA_TASK_32B_ADDR, &cmd, false);
- if (!cmd_pyld) {
- IPAERR("failed to construct dma_task_32b_addr cmd\n");
- return -EFAULT;
- }
- }
-
desc.opcode = ipahal_imm_cmd_get_opcode_param(
IPA_IMM_CMD_DMA_TASK_32B_ADDR, 1);
- desc.pyld = cmd_pyld->data;
- desc.len = cmd_pyld->len;
+ desc.pyld = ipa3_ctx->dma_task_info.cmd_pyld->data;
+ desc.len = ipa3_ctx->dma_task_info.cmd_pyld->len;
desc.type = IPA_IMM_CMD_DESC;
IPADBG("sending 1B packet to IPA\n");
diff --git a/drivers/platform/msm/ipa/ipa_v3/rmnet_ipa.c b/drivers/platform/msm/ipa/ipa_v3/rmnet_ipa.c
index cb25b09..56e7718 100644
--- a/drivers/platform/msm/ipa/ipa_v3/rmnet_ipa.c
+++ b/drivers/platform/msm/ipa/ipa_v3/rmnet_ipa.c
@@ -1655,6 +1655,9 @@
extend_ioctl_data.u.rmnet_mux_val.vchannel_name,
sizeof(mux_channel[rmnet_index]
.vchannel_name));
+ mux_channel[rmnet_index].vchannel_name[
+ IFNAMSIZ - 1] = '\0';
+
IPAWANDBG("cashe device[%s:%d] in IPA_wan[%d]\n",
mux_channel[rmnet_index].vchannel_name,
mux_channel[rmnet_index].mux_id,
diff --git a/drivers/platform/x86/acer-wmi.c b/drivers/platform/x86/acer-wmi.c
index a66192f..c29b9b6 100644
--- a/drivers/platform/x86/acer-wmi.c
+++ b/drivers/platform/x86/acer-wmi.c
@@ -1846,11 +1846,24 @@
return status;
}
+#define ACER_WMID_ACCEL_HID "BST0001"
+
static acpi_status __init acer_wmi_get_handle_cb(acpi_handle ah, u32 level,
void *ctx, void **retval)
{
+ struct acpi_device *dev;
+
+ if (!strcmp(ctx, "SENR")) {
+ if (acpi_bus_get_device(ah, &dev))
+ return AE_OK;
+ if (!strcmp(ACER_WMID_ACCEL_HID, acpi_device_hid(dev)))
+ return AE_OK;
+ } else
+ return AE_OK;
+
*(acpi_handle *)retval = ah;
- return AE_OK;
+
+ return AE_CTRL_TERMINATE;
}
static int __init acer_wmi_get_handle(const char *name, const char *prop,
@@ -1877,7 +1890,7 @@
{
int err;
- err = acer_wmi_get_handle("SENR", "BST0001", &gsensor_handle);
+ err = acer_wmi_get_handle("SENR", ACER_WMID_ACCEL_HID, &gsensor_handle);
if (err)
return err;
@@ -2233,10 +2246,11 @@
err = acer_wmi_input_setup();
if (err)
return err;
+ err = acer_wmi_accel_setup();
+ if (err)
+ return err;
}
- acer_wmi_accel_setup();
-
err = platform_driver_register(&acer_platform_driver);
if (err) {
pr_err("Unable to register platform driver\n");
diff --git a/drivers/power/reset/msm-poweroff.c b/drivers/power/reset/msm-poweroff.c
index efcc4e8..9f04957 100644
--- a/drivers/power/reset/msm-poweroff.c
+++ b/drivers/power/reset/msm-poweroff.c
@@ -28,6 +28,7 @@
#include <asm/cacheflush.h>
#include <asm/system_misc.h>
+#include <asm/memory.h>
#include <soc/qcom/scm.h>
#include <soc/qcom/restart.h>
@@ -57,11 +58,17 @@
#ifdef CONFIG_QCOM_DLOAD_MODE
#define EDL_MODE_PROP "qcom,msm-imem-emergency_download_mode"
#define DL_MODE_PROP "qcom,msm-imem-download_mode"
+#ifdef CONFIG_RANDOMIZE_BASE
+#define KASLR_OFFSET_PROP "qcom,msm-imem-kaslr_offset"
+#endif
static int in_panic;
static void *dload_mode_addr;
static bool dload_mode_enabled;
static void *emergency_dload_mode_addr;
+#ifdef CONFIG_RANDOMIZE_BASE
+static void *kaslr_imem_addr;
+#endif
static bool scm_dload_supported;
static int dload_set(const char *val, struct kernel_param *kp);
@@ -420,6 +427,27 @@
pr_err("unable to map imem EDLOAD mode offset\n");
}
+#ifdef CONFIG_RANDOMIZE_BASE
+#define KASLR_OFFSET_BIT_MASK 0x00000000FFFFFFFF
+ np = of_find_compatible_node(NULL, NULL, KASLR_OFFSET_PROP);
+ if (!np) {
+ pr_err("unable to find DT imem KASLR_OFFSET node\n");
+ } else {
+ kaslr_imem_addr = of_iomap(np, 0);
+ if (!kaslr_imem_addr)
+ pr_err("unable to map imem KASLR offset\n");
+ }
+
+ if (kaslr_imem_addr && scm_is_secure_device()) {
+ __raw_writel(0xdead4ead, kaslr_imem_addr);
+ __raw_writel(KASLR_OFFSET_BIT_MASK &
+ (kimage_vaddr - KIMAGE_VADDR), kaslr_imem_addr + 4);
+ __raw_writel(KASLR_OFFSET_BIT_MASK &
+ ((kimage_vaddr - KIMAGE_VADDR) >> 32),
+ kaslr_imem_addr + 8);
+ iounmap(kaslr_imem_addr);
+ }
+#endif
#endif
np = of_find_compatible_node(NULL, NULL,
"qcom,msm-imem-restart_reason");
@@ -484,4 +512,4 @@
{
return platform_driver_register(&msm_restart_driver);
}
-device_initcall(msm_restart_init);
+pure_initcall(msm_restart_init);
diff --git a/drivers/power/supply/qcom/battery.c b/drivers/power/supply/qcom/battery.c
index b985ecd..54bef52 100644
--- a/drivers/power/supply/qcom/battery.c
+++ b/drivers/power/supply/qcom/battery.c
@@ -434,23 +434,28 @@
return rc;
}
- split_fcc(chip, total_fcc_ua, &master_fcc_ua, &slave_fcc_ua);
- pval.intval = slave_fcc_ua;
- rc = power_supply_set_property(chip->pl_psy,
- POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX, &pval);
- if (rc < 0) {
- pr_err("Couldn't set parallel fcc, rc=%d\n", rc);
- return rc;
- }
+ if (chip->pl_mode != POWER_SUPPLY_PL_NONE) {
+ split_fcc(chip, total_fcc_ua, &master_fcc_ua, &slave_fcc_ua);
- chip->slave_fcc_ua = slave_fcc_ua;
+ pval.intval = slave_fcc_ua;
+ rc = power_supply_set_property(chip->pl_psy,
+ POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX,
+ &pval);
+ if (rc < 0) {
+ pr_err("Couldn't set parallel fcc, rc=%d\n", rc);
+ return rc;
+ }
- pval.intval = master_fcc_ua;
- rc = power_supply_set_property(chip->main_psy,
- POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX, &pval);
- if (rc < 0) {
- pr_err("Could not set main fcc, rc=%d\n", rc);
- return rc;
+ chip->slave_fcc_ua = slave_fcc_ua;
+
+ pval.intval = master_fcc_ua;
+ rc = power_supply_set_property(chip->main_psy,
+ POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX,
+ &pval);
+ if (rc < 0) {
+ pr_err("Could not set main fcc, rc=%d\n", rc);
+ return rc;
+ }
}
pl_dbg(chip, PR_PARALLEL, "master_fcc=%d slave_fcc=%d distribution=(%d/%d)\n",
@@ -511,13 +516,14 @@
return 0;
}
-#define ICL_STEP_UV 25000
+#define ICL_STEP_UA 25000
static int usb_icl_vote_callback(struct votable *votable, void *data,
int icl_ua, const char *client)
{
int rc;
struct pl_data *chip = data;
union power_supply_propval pval = {0, };
+ bool rerun_aicl = false;
if (!chip->main_psy)
return 0;
@@ -543,22 +549,28 @@
}
/* rerun AICL if new ICL is above settled ICL */
- if (icl_ua > pval.intval) {
- /* set a lower ICL */
- pval.intval = max(pval.intval - ICL_STEP_UV, ICL_STEP_UV);
- power_supply_set_property(chip->main_psy,
- POWER_SUPPLY_PROP_CURRENT_MAX,
- &pval);
- /* wait for ICL change */
- msleep(100);
+ if (icl_ua > pval.intval)
+ rerun_aicl = true;
- pval.intval = icl_ua;
+ if (rerun_aicl) {
+ /* set a lower ICL */
+ pval.intval = max(pval.intval - ICL_STEP_UA, ICL_STEP_UA);
power_supply_set_property(chip->main_psy,
POWER_SUPPLY_PROP_CURRENT_MAX,
&pval);
/* wait for ICL change */
msleep(100);
}
+
+ /* set the effective ICL */
+ pval.intval = icl_ua;
+ power_supply_set_property(chip->main_psy,
+ POWER_SUPPLY_PROP_CURRENT_MAX,
+ &pval);
+ if (rerun_aicl)
+ /* wait for ICL change */
+ msleep(100);
+
vote(chip->pl_disable_votable, ICL_CHANGE_VOTER, false, 0);
return 0;
@@ -678,9 +690,6 @@
chip->main_psy = power_supply_get_by_name("main");
- if (chip->main_psy)
- rerun_election(chip->usb_icl_votable);
-
return !!chip->main_psy;
}
@@ -859,7 +868,18 @@
struct pl_data *chip = container_of(work,
struct pl_data, status_change_work);
- if (!is_main_available(chip))
+ if (!chip->main_psy && is_main_available(chip)) {
+ /*
+ * re-run election for FCC/FV/ICL once main_psy
+ * is available to ensure all votes are reflected
+ * on hardware
+ */
+ rerun_election(chip->usb_icl_votable);
+ rerun_election(chip->fcc_votable);
+ rerun_election(chip->fv_votable);
+ }
+
+ if (!chip->main_psy)
return;
if (!is_batt_available(chip))
diff --git a/drivers/power/supply/qcom/fg-core.h b/drivers/power/supply/qcom/fg-core.h
index ca551a5a..5983b5c 100644
--- a/drivers/power/supply/qcom/fg-core.h
+++ b/drivers/power/supply/qcom/fg-core.h
@@ -128,11 +128,6 @@
FG_IRQ_MAX,
};
-/* WA flags */
-enum {
- DELTA_SOC_IRQ_WA = BIT(0),
-};
-
/*
* List of FG_SRAM parameters. Please add a parameter only if it is an entry
* that will be used either to configure an entity (e.g. termination current)
@@ -152,6 +147,7 @@
FG_SRAM_CC_SOC,
FG_SRAM_CC_SOC_SW,
FG_SRAM_ACT_BATT_CAP,
+ FG_SRAM_TIMEBASE,
/* Entries below here are configurable during initialization */
FG_SRAM_CUTOFF_VOLT,
FG_SRAM_EMPTY_VOLT,
@@ -212,6 +208,7 @@
enum wa_flags {
PMI8998_V1_REV_WA = BIT(0),
+ PM660_TSMC_OSC_WA = BIT(1),
};
enum slope_limit_status {
@@ -325,6 +322,23 @@
{ 128000, 4852 },
};
+/* each tuple is - <temperature in degC, Timebase> */
+static const struct fg_pt fg_tsmc_osc_table[] = {
+ { -20, 395064 },
+ { -10, 398114 },
+ { 0, 401669 },
+ { 10, 404641 },
+ { 20, 408856 },
+ { 25, 412449 },
+ { 30, 416532 },
+ { 40, 420289 },
+ { 50, 425020 },
+ { 60, 430160 },
+ { 70, 434175 },
+ { 80, 439475 },
+ { 90, 444992 },
+};
+
struct fg_chip {
struct device *dev;
struct pmic_revid_data *pmic_rev_id;
@@ -336,6 +350,7 @@
struct power_supply *dc_psy;
struct power_supply *parallel_psy;
struct iio_channel *batt_id_chan;
+ struct iio_channel *die_temp_chan;
struct fg_memif *sram;
struct fg_irq_info *irqs;
struct votable *awake_votable;
diff --git a/drivers/power/supply/qcom/qpnp-fg-gen3.c b/drivers/power/supply/qcom/qpnp-fg-gen3.c
index b42a65d..806460f 100644
--- a/drivers/power/supply/qcom/qpnp-fg-gen3.c
+++ b/drivers/power/supply/qcom/qpnp-fg-gen3.c
@@ -47,6 +47,7 @@
#define ESR_UPD_TIGHT_LOW_TEMP_OFFSET 2
#define ESR_UPD_BROAD_LOW_TEMP_OFFSET 3
#define KI_COEFF_MED_DISCHG_WORD 9
+#define TIMEBASE_OFFSET 1
#define KI_COEFF_MED_DISCHG_OFFSET 3
#define KI_COEFF_HI_DISCHG_WORD 10
#define KI_COEFF_HI_DISCHG_OFFSET 0
@@ -261,6 +262,8 @@
fg_decode_cc_soc),
PARAM(ACT_BATT_CAP, ACT_BATT_CAP_BKUP_WORD, ACT_BATT_CAP_BKUP_OFFSET, 2,
1, 1, 0, NULL, fg_decode_default),
+ PARAM(TIMEBASE, KI_COEFF_MED_DISCHG_WORD, TIMEBASE_OFFSET, 2, 1000,
+ 61000, 0, fg_encode_default, NULL),
/* Entries below here are configurable during initialization */
PARAM(CUTOFF_VOLT, CUTOFF_VOLT_WORD, CUTOFF_VOLT_OFFSET, 2, 1000000,
244141, 0, fg_encode_voltage, NULL),
@@ -1967,7 +1970,7 @@
{
union power_supply_propval prop = {0, };
int rc;
- bool parallel_en = false;
+ bool parallel_en = false, qnovo_en = false;
if (is_parallel_charger_available(chip)) {
rc = power_supply_get_property(chip->parallel_psy,
@@ -1980,19 +1983,25 @@
parallel_en = prop.intval;
}
- fg_dbg(chip, FG_POWER_SUPPLY, "charge_status: %d parallel_en: %d esr_fcc_ctrl_en: %d\n",
- chip->charge_status, parallel_en, chip->esr_fcc_ctrl_en);
+ rc = power_supply_get_property(chip->batt_psy,
+ POWER_SUPPLY_PROP_CHARGE_QNOVO_ENABLE, &prop);
+ if (!rc)
+ qnovo_en = prop.intval;
+
+ fg_dbg(chip, FG_POWER_SUPPLY, "chg_sts: %d par_en: %d qnov_en: %d esr_fcc_ctrl_en: %d\n",
+ chip->charge_status, parallel_en, qnovo_en,
+ chip->esr_fcc_ctrl_en);
if (chip->charge_status == POWER_SUPPLY_STATUS_CHARGING &&
- parallel_en) {
+ (parallel_en || qnovo_en)) {
if (chip->esr_fcc_ctrl_en)
return 0;
/*
- * When parallel charging is enabled, configure ESR FCC to
- * 300mA to trigger an ESR pulse. Without this, FG can ask
- * the main charger to increase FCC when it is supposed to
- * decrease it.
+ * When parallel charging or Qnovo is enabled, configure ESR
+ * FCC to 300mA to trigger an ESR pulse. Without this, FG can
+ * request the main charger to increase FCC when it is supposed
+ * to decrease it.
*/
rc = fg_masked_write(chip, BATT_INFO_ESR_FAST_CRG_CFG(chip),
ESR_FAST_CRG_IVAL_MASK |
@@ -2011,8 +2020,8 @@
/*
* If we're here, then it means either the device is not in
- * charging state or parallel charging is disabled. Disable
- * ESR fast charge current control in SW.
+ * charging state or parallel charging / Qnovo is disabled.
+ * Disable ESR fast charge current control in SW.
*/
rc = fg_masked_write(chip, BATT_INFO_ESR_FAST_CRG_CFG(chip),
ESR_FAST_CRG_CTL_EN_BIT, 0);
@@ -3365,6 +3374,40 @@
return fg_ima_init(chip);
}
+static int fg_adjust_timebase(struct fg_chip *chip)
+{
+ int rc = 0, die_temp;
+ s32 time_base = 0;
+ u8 buf[2] = {0};
+
+ if ((chip->wa_flags & PM660_TSMC_OSC_WA) && chip->die_temp_chan) {
+ rc = iio_read_channel_processed(chip->die_temp_chan, &die_temp);
+ if (rc < 0) {
+ pr_err("Error in reading die_temp, rc:%d\n", rc);
+ return rc;
+ }
+
+ rc = fg_lerp(fg_tsmc_osc_table, ARRAY_SIZE(fg_tsmc_osc_table),
+ die_temp / 1000, &time_base);
+ if (rc < 0) {
+ pr_err("Error to lookup fg_tsmc_osc_table rc=%d\n", rc);
+ return rc;
+ }
+
+ fg_encode(chip->sp, FG_SRAM_TIMEBASE, time_base, buf);
+ rc = fg_sram_write(chip,
+ chip->sp[FG_SRAM_TIMEBASE].addr_word,
+ chip->sp[FG_SRAM_TIMEBASE].addr_byte, buf,
+ chip->sp[FG_SRAM_TIMEBASE].len, FG_IMA_DEFAULT);
+ if (rc < 0) {
+ pr_err("Error in writing timebase, rc=%d\n", rc);
+ return rc;
+ }
+ }
+
+ return 0;
+}
+
/* INTERRUPT HANDLERS STAY HERE */
static irqreturn_t fg_mem_xcp_irq_handler(int irq, void *data)
@@ -3486,6 +3529,10 @@
chip->health = prop.intval;
if (chip->last_batt_temp != batt_temp) {
+ rc = fg_adjust_timebase(chip);
+ if (rc < 0)
+ pr_err("Error in adjusting timebase, rc=%d\n", rc);
+
chip->last_batt_temp = batt_temp;
power_supply_changed(chip->batt_psy);
}
@@ -3555,6 +3602,10 @@
if (rc < 0)
pr_err("Error in validating ESR, rc=%d\n", rc);
+ rc = fg_adjust_timebase(chip);
+ if (rc < 0)
+ pr_err("Error in adjusting timebase, rc=%d\n", rc);
+
if (batt_psy_initialized(chip))
power_supply_changed(chip->batt_psy);
@@ -3897,6 +3948,8 @@
chip->sp = pmi8998_v2_sram_params;
chip->alg_flags = pmi8998_v2_alg_flags;
chip->use_ima_single_mode = true;
+ if (chip->pmic_rev_id->fab_id == PM660_FAB_ID_TSMC)
+ chip->wa_flags |= PM660_TSMC_OSC_WA;
break;
default:
return -EINVAL;
@@ -4238,6 +4291,21 @@
return rc;
}
+ rc = of_property_match_string(chip->dev->of_node,
+ "io-channel-names", "rradc_die_temp");
+ if (rc >= 0) {
+ chip->die_temp_chan = iio_channel_get(chip->dev,
+ "rradc_die_temp");
+ if (IS_ERR(chip->die_temp_chan)) {
+ if (PTR_ERR(chip->die_temp_chan) != -EPROBE_DEFER)
+ pr_err("rradc_die_temp unavailable %ld\n",
+ PTR_ERR(chip->die_temp_chan));
+ rc = PTR_ERR(chip->die_temp_chan);
+ chip->die_temp_chan = NULL;
+ return rc;
+ }
+ }
+
chip->awake_votable = create_votable("FG_WS", VOTE_SET_ANY, fg_awake_cb,
chip);
if (IS_ERR(chip->awake_votable)) {
diff --git a/drivers/power/supply/qcom/qpnp-qnovo.c b/drivers/power/supply/qcom/qpnp-qnovo.c
index c74dc89..eb97eb0 100644
--- a/drivers/power/supply/qcom/qpnp-qnovo.c
+++ b/drivers/power/supply/qcom/qpnp-qnovo.c
@@ -89,7 +89,16 @@
#define QNOVO_STRM_CTRL 0xA8
#define QNOVO_IADC_OFFSET_OVR_VAL 0xA9
#define QNOVO_IADC_OFFSET_OVR 0xAA
+
#define QNOVO_DISABLE_CHARGING 0xAB
+#define ERR_SWITCHER_DISABLED BIT(7)
+#define ERR_JEITA_SOFT_CONDITION BIT(6)
+#define ERR_BAT_OV BIT(5)
+#define ERR_CV_MODE BIT(4)
+#define ERR_BATTERY_MISSING BIT(3)
+#define ERR_SAFETY_TIMER_EXPIRED BIT(2)
+#define ERR_CHARGING_DISABLED BIT(1)
+#define ERR_JEITA_HARD_CONDITION BIT(0)
#define QNOVO_TR_IADC_OFFSET_0 0xF1
#define QNOVO_TR_IADC_OFFSET_1 0xF2
@@ -1107,24 +1116,28 @@
{
u8 val = 0;
int rc;
- bool charging;
+ bool ok_to_qnovo;
bool changed = false;
rc = qnovo_read(chip, QNOVO_ERROR_STS2, &val, 1);
if (rc < 0) {
pr_err("Couldn't read error sts rc = %d\n", rc);
- charging = false;
+ ok_to_qnovo = false;
} else {
- charging = !(val & QNOVO_ERROR_CHARGING_DISABLED);
+ /*
+ * For CV mode keep qnovo enabled, userspace is expected to
+ * disable it after few runs
+ */
+ ok_to_qnovo = (val == ERR_CV_MODE || val == 0) ? true : false;
}
- if (chip->ok_to_qnovo ^ charging) {
+ if (chip->ok_to_qnovo ^ ok_to_qnovo) {
- vote(chip->disable_votable, OK_TO_QNOVO_VOTER, !charging, 0);
- if (!charging)
+ vote(chip->disable_votable, OK_TO_QNOVO_VOTER, !ok_to_qnovo, 0);
+ if (!ok_to_qnovo)
vote(chip->disable_votable, USER_VOTER, true, 0);
- chip->ok_to_qnovo = charging;
+ chip->ok_to_qnovo = ok_to_qnovo;
changed = true;
}
@@ -1247,6 +1260,16 @@
chip->v_gain_mega = 1000000000 + (s64)(s8)vadc_gain * GAIN_LSB_FACTOR;
chip->v_gain_mega = div_s64(chip->v_gain_mega, 1000);
+ /* allow charger error conditions to disable qnovo, CV mode excluded */
+ val = ERR_SWITCHER_DISABLED | ERR_JEITA_SOFT_CONDITION | ERR_BAT_OV |
+ ERR_BATTERY_MISSING | ERR_SAFETY_TIMER_EXPIRED |
+ ERR_CHARGING_DISABLED | ERR_JEITA_HARD_CONDITION;
+ rc = qnovo_write(chip, QNOVO_DISABLE_CHARGING, &val, 1);
+ if (rc < 0) {
+ pr_err("Couldn't write QNOVO_DISABLE_CHARGING rc = %d\n", rc);
+ return rc;
+ }
+
return 0;
}
diff --git a/drivers/power/supply/qcom/qpnp-smb2.c b/drivers/power/supply/qcom/qpnp-smb2.c
index 8fd45f18..e802fbd 100644
--- a/drivers/power/supply/qcom/qpnp-smb2.c
+++ b/drivers/power/supply/qcom/qpnp-smb2.c
@@ -244,6 +244,8 @@
int boost_threshold_ua;
int fv_uv;
int wipower_max_uw;
+ int min_freq_khz;
+ int max_freq_khz;
u32 step_soc_threshold[STEP_CHARGING_MAX_STEPS - 1];
s32 step_cc_delta[STEP_CHARGING_MAX_STEPS];
struct device_node *revid_dev_node;
@@ -338,6 +340,18 @@
if (rc < 0)
chip->dt.boost_threshold_ua = MICRO_P1A;
+ rc = of_property_read_u32(node,
+ "qcom,min-freq-khz",
+ &chip->dt.min_freq_khz);
+ if (rc < 0)
+ chip->dt.min_freq_khz = -EINVAL;
+
+ rc = of_property_read_u32(node,
+ "qcom,max-freq-khz",
+ &chip->dt.max_freq_khz);
+ if (rc < 0)
+ chip->dt.max_freq_khz = -EINVAL;
+
rc = of_property_read_u32(node, "qcom,wipower-max-uw",
&chip->dt.wipower_max_uw);
if (rc < 0)
@@ -526,6 +540,12 @@
struct smb_charger *chg = &chip->chg;
int rc = 0;
+ mutex_lock(&chg->lock);
+ if (!chg->typec_present) {
+ rc = -EINVAL;
+ goto unlock;
+ }
+
switch (psp) {
case POWER_SUPPLY_PROP_VOLTAGE_MIN:
rc = smblib_set_prop_usb_voltage_min(chg, val);
@@ -564,6 +584,8 @@
break;
}
+unlock:
+ mutex_unlock(&chg->lock);
return rc;
}
@@ -1336,10 +1358,12 @@
return rc;
}
- /* disable try.SINK mode */
- rc = smblib_masked_write(chg, TYPE_C_CFG_3_REG, EN_TRYSINK_MODE_BIT, 0);
+ /* disable try.SINK mode and legacy cable IRQs */
+ rc = smblib_masked_write(chg, TYPE_C_CFG_3_REG, EN_TRYSINK_MODE_BIT |
+ TYPEC_NONCOMPLIANT_LEGACY_CABLE_INT_EN_BIT |
+ TYPEC_LEGACY_CABLE_INT_EN_BIT, 0);
if (rc < 0) {
- dev_err(chg->dev, "Couldn't set TRYSINK_MODE rc=%d\n", rc);
+ dev_err(chg->dev, "Couldn't set Type-C config rc=%d\n", rc);
return rc;
}
@@ -1438,6 +1462,16 @@
smblib_get_charge_param(chg, &chg->param.dc_icl,
&chip->dt.dc_icl_ua);
+ if (chip->dt.min_freq_khz > 0) {
+ chg->param.freq_buck.min_u = chip->dt.min_freq_khz;
+ chg->param.freq_boost.min_u = chip->dt.min_freq_khz;
+ }
+
+ if (chip->dt.max_freq_khz > 0) {
+ chg->param.freq_buck.max_u = chip->dt.max_freq_khz;
+ chg->param.freq_boost.max_u = chip->dt.max_freq_khz;
+ }
+
/* set a slower soft start setting for OTG */
rc = smblib_masked_write(chg, DC_ENG_SSUPPLY_CFG2_REG,
ENG_SSUPPLY_IVREF_OTG_SS_MASK, OTG_SS_SLOW);
@@ -1485,6 +1519,8 @@
DEFAULT_VOTER, true, chip->dt.dc_icl_ua);
vote(chg->hvdcp_disable_votable_indirect, PD_INACTIVE_VOTER,
true, 0);
+ vote(chg->hvdcp_disable_votable_indirect, VBUS_CC_SHORT_VOTER,
+ true, 0);
vote(chg->hvdcp_disable_votable_indirect, DEFAULT_VOTER,
chip->dt.hvdcp_disable, 0);
vote(chg->pd_disallowed_votable_indirect, CC_DETACHED_VOTER,
@@ -2022,6 +2058,16 @@
return rc;
}
+static void smb2_disable_interrupts(struct smb_charger *chg)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(smb2_irqs); i++) {
+ if (smb2_irqs[i].irq > 0)
+ disable_irq(smb2_irqs[i].irq);
+ }
+}
+
#if defined(CONFIG_DEBUG_FS)
static int force_batt_psy_update_write(void *data, u64 val)
@@ -2233,7 +2279,7 @@
rc = smblib_get_prop_batt_health(chg, &val);
if (rc < 0) {
pr_err("Couldn't get batt health rc=%d\n", rc);
- goto cleanup;
+ val.intval = POWER_SUPPLY_HEALTH_UNKNOWN;
}
batt_health = val.intval;
@@ -2284,6 +2330,9 @@
struct smb2 *chip = platform_get_drvdata(pdev);
struct smb_charger *chg = &chip->chg;
+ /* disable all interrupts */
+ smb2_disable_interrupts(chg);
+
/* configure power role for UFP */
smblib_masked_write(chg, TYPE_C_INTRPT_ENB_SOFTWARE_CTRL_REG,
TYPEC_POWER_ROLE_CMD_MASK, UFP_EN_CMD_BIT);
diff --git a/drivers/power/supply/qcom/smb-lib.c b/drivers/power/supply/qcom/smb-lib.c
index c8deedd..7d5a8bd 100644
--- a/drivers/power/supply/qcom/smb-lib.c
+++ b/drivers/power/supply/qcom/smb-lib.c
@@ -542,30 +542,6 @@
smblib_err(chg, "Couldn't re-run APSD rc=%d\n", rc);
}
-static int try_rerun_apsd_for_hvdcp(struct smb_charger *chg)
-{
- const struct apsd_result *apsd_result;
-
- /*
- * PD_INACTIVE_VOTER on hvdcp_disable_votable indicates whether
- * apsd rerun was tried earlier
- */
- if (get_client_vote(chg->hvdcp_disable_votable_indirect,
- PD_INACTIVE_VOTER)) {
- vote(chg->hvdcp_disable_votable_indirect,
- PD_INACTIVE_VOTER, false, 0);
- /* ensure hvdcp is enabled */
- if (!get_effective_result(
- chg->hvdcp_disable_votable_indirect)) {
- apsd_result = smblib_get_apsd_result(chg);
- if (apsd_result->bit & (QC_2P0_BIT | QC_3P0_BIT)) {
- smblib_rerun_apsd(chg);
- }
- }
- }
- return 0;
-}
-
static const struct apsd_result *smblib_update_usb_type(struct smb_charger *chg)
{
const struct apsd_result *apsd_result = smblib_get_apsd_result(chg);
@@ -684,6 +660,7 @@
chg->voltage_max_uv = MICRO_5V;
chg->usb_icl_delta_ua = 0;
chg->pulse_cnt = 0;
+ chg->uusb_apsd_rerun_done = false;
/* clear USB ICL vote for USB_PSY_VOTER */
rc = vote(chg->usb_icl_votable, USB_PSY_VOTER, false, 0);
@@ -751,6 +728,7 @@
rc);
}
+ chg->uusb_apsd_rerun_done = true;
smblib_rerun_apsd(chg);
return 0;
@@ -1020,6 +998,7 @@
struct smb_charger *chg = data;
int rc;
u8 val = HVDCP_AUTH_ALG_EN_CFG_BIT | HVDCP_EN_BIT;
+ u8 stat;
/* vote to enable/disable HW autonomous INOV */
vote(chg->hvdcp_hw_inov_dis_votable, client, !hvdcp_enable, 0);
@@ -1041,6 +1020,16 @@
return rc;
}
+ rc = smblib_read(chg, APSD_STATUS_REG, &stat);
+ if (rc < 0) {
+ smblib_err(chg, "Couldn't read APSD status rc=%d\n", rc);
+ return rc;
+ }
+
+ /* re-run APSD if HVDCP was detected */
+ if (stat & QC_CHARGER_BIT)
+ smblib_rerun_apsd(chg);
+
return 0;
}
@@ -1134,6 +1123,22 @@
return 0;
}
+static int smblib_typec_irq_disable_vote_callback(struct votable *votable,
+ void *data, int disable, const char *client)
+{
+ struct smb_charger *chg = data;
+
+ if (!chg->irq_info[TYPE_C_CHANGE_IRQ].irq)
+ return 0;
+
+ if (disable)
+ disable_irq_nosync(chg->irq_info[TYPE_C_CHANGE_IRQ].irq);
+ else
+ enable_irq(chg->irq_info[TYPE_C_CHANGE_IRQ].irq);
+
+ return 0;
+}
+
/*******************
* VCONN REGULATOR *
* *****************/
@@ -1142,7 +1147,7 @@
static int _smblib_vconn_regulator_enable(struct regulator_dev *rdev)
{
struct smb_charger *chg = rdev_get_drvdata(rdev);
- u8 otg_stat, stat4;
+ u8 otg_stat, val;
int rc = 0, i;
if (!chg->external_vconn) {
@@ -1173,17 +1178,12 @@
* VCONN_EN_ORIENTATION is overloaded with overriding the CC pin used
* for Vconn, and it should be set with reverse polarity of CC_OUT.
*/
- rc = smblib_read(chg, TYPE_C_STATUS_4_REG, &stat4);
- if (rc < 0) {
- smblib_err(chg, "Couldn't read TYPE_C_STATUS_4 rc=%d\n", rc);
- return rc;
- }
-
smblib_dbg(chg, PR_OTG, "enabling VCONN\n");
- stat4 = stat4 & CC_ORIENTATION_BIT ? 0 : VCONN_EN_ORIENTATION_BIT;
+ val = chg->typec_status[3] &
+ CC_ORIENTATION_BIT ? 0 : VCONN_EN_ORIENTATION_BIT;
rc = smblib_masked_write(chg, TYPE_C_INTRPT_ENB_SOFTWARE_CTRL_REG,
VCONN_EN_VALUE_BIT | VCONN_EN_ORIENTATION_BIT,
- VCONN_EN_VALUE_BIT | stat4);
+ VCONN_EN_VALUE_BIT | val);
if (rc < 0) {
smblib_err(chg, "Couldn't enable vconn setting rc=%d\n", rc);
return rc;
@@ -1531,6 +1531,21 @@
break;
}
+ if (val->intval != POWER_SUPPLY_STATUS_CHARGING)
+ return 0;
+
+ rc = smblib_read(chg, BATTERY_CHARGER_STATUS_7_REG, &stat);
+ if (rc < 0) {
+ smblib_err(chg, "Couldn't read BATTERY_CHARGER_STATUS_2 rc=%d\n",
+ rc);
+ return rc;
+ }
+
+ stat &= ENABLE_TRICKLE_BIT | ENABLE_PRE_CHARGING_BIT |
+ ENABLE_FAST_CHARGING_BIT | ENABLE_FULLON_MODE_BIT;
+ if (!stat)
+ val->intval = POWER_SUPPLY_STATUS_NOT_CHARGING;
+
return 0;
}
@@ -2131,23 +2146,13 @@
int smblib_get_prop_typec_cc_orientation(struct smb_charger *chg,
union power_supply_propval *val)
{
- int rc = 0;
- u8 stat;
-
- rc = smblib_read(chg, TYPE_C_STATUS_4_REG, &stat);
- if (rc < 0) {
- smblib_err(chg, "Couldn't read TYPE_C_STATUS_4 rc=%d\n", rc);
- return rc;
- }
- smblib_dbg(chg, PR_REGISTER, "TYPE_C_STATUS_4 = 0x%02x\n",
- stat);
-
- if (stat & CC_ATTACHED_BIT)
- val->intval = (bool)(stat & CC_ORIENTATION_BIT) + 1;
+ if (chg->typec_status[3] & CC_ATTACHED_BIT)
+ val->intval =
+ (bool)(chg->typec_status[3] & CC_ORIENTATION_BIT) + 1;
else
val->intval = 0;
- return rc;
+ return 0;
}
static const char * const smblib_typec_mode_name[] = {
@@ -2165,17 +2170,7 @@
static int smblib_get_prop_ufp_mode(struct smb_charger *chg)
{
- int rc;
- u8 stat;
-
- rc = smblib_read(chg, TYPE_C_STATUS_1_REG, &stat);
- if (rc < 0) {
- smblib_err(chg, "Couldn't read TYPE_C_STATUS_1 rc=%d\n", rc);
- return POWER_SUPPLY_TYPEC_NONE;
- }
- smblib_dbg(chg, PR_REGISTER, "TYPE_C_STATUS_1 = 0x%02x\n", stat);
-
- switch (stat) {
+ switch (chg->typec_status[0]) {
case 0:
return POWER_SUPPLY_TYPEC_NONE;
case UFP_TYPEC_RDSTD_BIT:
@@ -2193,17 +2188,7 @@
static int smblib_get_prop_dfp_mode(struct smb_charger *chg)
{
- int rc;
- u8 stat;
-
- rc = smblib_read(chg, TYPE_C_STATUS_2_REG, &stat);
- if (rc < 0) {
- smblib_err(chg, "Couldn't read TYPE_C_STATUS_2 rc=%d\n", rc);
- return POWER_SUPPLY_TYPEC_NONE;
- }
- smblib_dbg(chg, PR_REGISTER, "TYPE_C_STATUS_2 = 0x%02x\n", stat);
-
- switch (stat & DFP_TYPEC_MASK) {
+ switch (chg->typec_status[1] & DFP_TYPEC_MASK) {
case DFP_RA_RA_BIT:
return POWER_SUPPLY_TYPEC_SINK_AUDIO_ADAPTER;
case DFP_RD_RD_BIT:
@@ -2224,28 +2209,17 @@
int smblib_get_prop_typec_mode(struct smb_charger *chg,
union power_supply_propval *val)
{
- int rc;
- u8 stat;
-
- rc = smblib_read(chg, TYPE_C_STATUS_4_REG, &stat);
- if (rc < 0) {
- smblib_err(chg, "Couldn't read TYPE_C_STATUS_4 rc=%d\n", rc);
+ if (!(chg->typec_status[3] & TYPEC_DEBOUNCE_DONE_STATUS_BIT)) {
val->intval = POWER_SUPPLY_TYPEC_NONE;
- return rc;
- }
- smblib_dbg(chg, PR_REGISTER, "TYPE_C_STATUS_4 = 0x%02x\n", stat);
-
- if (!(stat & TYPEC_DEBOUNCE_DONE_STATUS_BIT)) {
- val->intval = POWER_SUPPLY_TYPEC_NONE;
- return rc;
+ return 0;
}
- if (stat & UFP_DFP_MODE_STATUS_BIT)
+ if (chg->typec_status[3] & UFP_DFP_MODE_STATUS_BIT)
val->intval = smblib_get_prop_dfp_mode(chg);
else
val->intval = smblib_get_prop_ufp_mode(chg);
- return rc;
+ return 0;
}
int smblib_get_prop_typec_power_role(struct smb_charger *chg,
@@ -2337,16 +2311,7 @@
int smblib_get_prop_pd_in_hard_reset(struct smb_charger *chg,
union power_supply_propval *val)
{
- int rc;
- u8 ctrl;
-
- rc = smblib_read(chg, TYPE_C_INTRPT_ENB_SOFTWARE_CTRL_REG, &ctrl);
- if (rc < 0) {
- smblib_err(chg, "Couldn't read TYPE_C_INTRPT_ENB_SOFTWARE_CTRL_REG rc=%d\n",
- rc);
- return rc;
- }
- val->intval = ctrl & EXIT_SNK_BASED_ON_CC_BIT;
+ val->intval = chg->pd_hard_reset;
return 0;
}
@@ -2542,53 +2507,60 @@
const union power_supply_propval *val)
{
int rc;
- u8 stat = 0;
- bool cc_debounced;
- bool orientation;
- bool pd_active = val->intval;
+ bool orientation, cc_debounced, sink_attached, hvdcp;
+ u8 stat;
- if (!get_effective_result(chg->pd_allowed_votable)) {
- smblib_err(chg, "PD is not allowed\n");
+ if (!get_effective_result(chg->pd_allowed_votable))
return -EINVAL;
- }
- vote(chg->apsd_disable_votable, PD_VOTER, pd_active, 0);
- vote(chg->pd_allowed_votable, PD_VOTER, pd_active, 0);
- vote(chg->usb_irq_enable_votable, PD_VOTER, pd_active, 0);
-
- /*
- * VCONN_EN_ORIENTATION_BIT controls whether to use CC1 or CC2 line
- * when TYPEC_SPARE_CFG_BIT (CC pin selection s/w override) is set
- * or when VCONN_EN_VALUE_BIT is set.
- */
- rc = smblib_read(chg, TYPE_C_STATUS_4_REG, &stat);
+ rc = smblib_read(chg, APSD_STATUS_REG, &stat);
if (rc < 0) {
- smblib_err(chg, "Couldn't read TYPE_C_STATUS_4 rc=%d\n", rc);
+ smblib_err(chg, "Couldn't read APSD status rc=%d\n", rc);
return rc;
}
- if (pd_active) {
- orientation = stat & CC_ORIENTATION_BIT;
+ cc_debounced = (bool)
+ (chg->typec_status[3] & TYPEC_DEBOUNCE_DONE_STATUS_BIT);
+ sink_attached = (bool)
+ (chg->typec_status[3] & UFP_DFP_MODE_STATUS_BIT);
+ hvdcp = stat & QC_CHARGER_BIT;
+
+ chg->pd_active = val->intval;
+ if (chg->pd_active) {
+ vote(chg->apsd_disable_votable, PD_VOTER, true, 0);
+ vote(chg->pd_allowed_votable, PD_VOTER, true, 0);
+ vote(chg->usb_irq_enable_votable, PD_VOTER, true, 0);
+
+ /*
+ * VCONN_EN_ORIENTATION_BIT controls whether to use CC1 or CC2
+ * line when TYPEC_SPARE_CFG_BIT (CC pin selection s/w override)
+ * is set or when VCONN_EN_VALUE_BIT is set.
+ */
+ orientation = chg->typec_status[3] & CC_ORIENTATION_BIT;
rc = smblib_masked_write(chg,
TYPE_C_INTRPT_ENB_SOFTWARE_CTRL_REG,
VCONN_EN_ORIENTATION_BIT,
orientation ? 0 : VCONN_EN_ORIENTATION_BIT);
- if (rc < 0) {
+ if (rc < 0)
smblib_err(chg,
"Couldn't enable vconn on CC line rc=%d\n", rc);
- return rc;
- }
+
+ /* SW controlled CC_OUT */
+ rc = smblib_masked_write(chg, TAPER_TIMER_SEL_CFG_REG,
+ TYPEC_SPARE_CFG_BIT, TYPEC_SPARE_CFG_BIT);
+ if (rc < 0)
+ smblib_err(chg, "Couldn't enable SW cc_out rc=%d\n",
+ rc);
+
/*
* Enforce 500mA for PD until the real vote comes in later.
* It is guaranteed that pd_active is set prior to
* pd_current_max
*/
rc = vote(chg->usb_icl_votable, PD_VOTER, true, USBIN_500MA);
- if (rc < 0) {
+ if (rc < 0)
smblib_err(chg, "Couldn't vote for USB ICL rc=%d\n",
- rc);
- return rc;
- }
+ rc);
/* since PD was found the cable must be non-legacy */
vote(chg->usb_icl_votable, LEGACY_UNKNOWN_VOTER, false, 0);
@@ -2596,36 +2568,40 @@
/* clear USB ICL vote for DCP_VOTER */
rc = vote(chg->usb_icl_votable, DCP_VOTER, false, 0);
if (rc < 0)
- smblib_err(chg,
- "Couldn't un-vote DCP from USB ICL rc=%d\n",
- rc);
+ smblib_err(chg, "Couldn't un-vote DCP from USB ICL rc=%d\n",
+ rc);
/* remove USB_PSY_VOTER */
rc = vote(chg->usb_icl_votable, USB_PSY_VOTER, false, 0);
- if (rc < 0) {
+ if (rc < 0)
smblib_err(chg, "Couldn't unvote USB_PSY rc=%d\n", rc);
- return rc;
- }
+ } else {
+ vote(chg->apsd_disable_votable, PD_VOTER, false, 0);
+ vote(chg->pd_allowed_votable, PD_VOTER, true, 0);
+ vote(chg->usb_irq_enable_votable, PD_VOTER, true, 0);
+ vote(chg->hvdcp_disable_votable_indirect, PD_INACTIVE_VOTER,
+ false, 0);
+
+ /* HW controlled CC_OUT */
+ rc = smblib_masked_write(chg, TAPER_TIMER_SEL_CFG_REG,
+ TYPEC_SPARE_CFG_BIT, 0);
+ if (rc < 0)
+ smblib_err(chg, "Couldn't enable HW cc_out rc=%d\n",
+ rc);
+
+ /*
+ * This WA should only run for HVDCP. Non-legacy SDP/CDP could
+ * draw more, but this WA will remove Rd causing VBUS to drop,
+ * and data could be interrupted. Non-legacy DCP could also draw
+ * more, but it may impact compliance.
+ */
+ if (!chg->typec_legacy_valid && cc_debounced &&
+ !sink_attached && hvdcp)
+ schedule_work(&chg->legacy_detection_work);
}
- /* CC pin selection s/w override in PD session; h/w otherwise. */
- rc = smblib_masked_write(chg, TAPER_TIMER_SEL_CFG_REG,
- TYPEC_SPARE_CFG_BIT,
- pd_active ? TYPEC_SPARE_CFG_BIT : 0);
- if (rc < 0) {
- smblib_err(chg, "Couldn't change cc_out ctrl to %s rc=%d\n",
- pd_active ? "SW" : "HW", rc);
- return rc;
- }
-
- cc_debounced = (bool)(stat & TYPEC_DEBOUNCE_DONE_STATUS_BIT);
- if (!pd_active && cc_debounced)
- try_rerun_apsd_for_hvdcp(chg);
-
- chg->pd_active = pd_active;
smblib_update_usb_type(chg);
power_supply_changed(chg->usb_psy);
-
return rc;
}
@@ -2728,88 +2704,70 @@
static int smblib_cc2_sink_removal_enter(struct smb_charger *chg)
{
- int rc = 0;
- union power_supply_propval cc2_val = {0, };
+ int rc, ccout, ufp_mode;
+ u8 stat;
if ((chg->wa_flags & TYPEC_CC2_REMOVAL_WA_BIT) == 0)
- return rc;
+ return 0;
- if (chg->cc2_sink_detach_flag != CC2_SINK_NONE)
- return rc;
+ if (chg->cc2_detach_wa_active)
+ return 0;
- rc = smblib_get_prop_typec_cc_orientation(chg, &cc2_val);
+ rc = smblib_read(chg, TYPE_C_STATUS_4_REG, &stat);
if (rc < 0) {
- smblib_err(chg, "Couldn't get cc orientation rc=%d\n", rc);
+ smblib_err(chg, "Couldn't read TYPE_C_STATUS_4 rc=%d\n", rc);
return rc;
}
- if (cc2_val.intval == 1)
- return rc;
+ ccout = (stat & CC_ATTACHED_BIT) ?
+ (!!(stat & CC_ORIENTATION_BIT) + 1) : 0;
+ ufp_mode = (stat & TYPEC_DEBOUNCE_DONE_STATUS_BIT) ?
+ !(stat & UFP_DFP_MODE_STATUS_BIT) : 0;
- rc = smblib_get_prop_typec_mode(chg, &cc2_val);
- if (rc < 0) {
- smblib_err(chg, "Couldn't get prop typec mode rc=%d\n", rc);
- return rc;
- }
+ if (ccout != 2)
+ return 0;
- switch (cc2_val.intval) {
- case POWER_SUPPLY_TYPEC_SOURCE_DEFAULT:
- smblib_reg_block_update(chg, cc2_detach_settings);
- chg->cc2_sink_detach_flag = CC2_SINK_STD;
- schedule_work(&chg->rdstd_cc2_detach_work);
- break;
- case POWER_SUPPLY_TYPEC_SOURCE_MEDIUM:
- case POWER_SUPPLY_TYPEC_SOURCE_HIGH:
- chg->cc2_sink_detach_flag = CC2_SINK_MEDIUM_HIGH;
- break;
- default:
- break;
- }
+ if (!ufp_mode)
+ return 0;
+ chg->cc2_detach_wa_active = true;
+ /* The CC2 removal WA will cause a type-c-change IRQ storm */
+ smblib_reg_block_update(chg, cc2_detach_settings);
+ schedule_work(&chg->rdstd_cc2_detach_work);
return rc;
}
static int smblib_cc2_sink_removal_exit(struct smb_charger *chg)
{
- int rc = 0;
-
if ((chg->wa_flags & TYPEC_CC2_REMOVAL_WA_BIT) == 0)
- return rc;
+ return 0;
- if (chg->cc2_sink_detach_flag == CC2_SINK_STD) {
- cancel_work_sync(&chg->rdstd_cc2_detach_work);
- smblib_reg_block_restore(chg, cc2_detach_settings);
- }
+ if (!chg->cc2_detach_wa_active)
+ return 0;
- chg->cc2_sink_detach_flag = CC2_SINK_NONE;
-
- return rc;
+ chg->cc2_detach_wa_active = false;
+ cancel_work_sync(&chg->rdstd_cc2_detach_work);
+ smblib_reg_block_restore(chg, cc2_detach_settings);
+ return 0;
}
int smblib_set_prop_pd_in_hard_reset(struct smb_charger *chg,
const union power_supply_propval *val)
{
- int rc;
+ int rc = 0;
+ if (chg->pd_hard_reset == val->intval)
+ return rc;
+
+ chg->pd_hard_reset = val->intval;
rc = smblib_masked_write(chg, TYPE_C_INTRPT_ENB_SOFTWARE_CTRL_REG,
- EXIT_SNK_BASED_ON_CC_BIT,
- (val->intval) ? EXIT_SNK_BASED_ON_CC_BIT : 0);
- if (rc < 0) {
- smblib_err(chg, "Could not set EXIT_SNK_BASED_ON_CC rc=%d\n",
+ EXIT_SNK_BASED_ON_CC_BIT,
+ (chg->pd_hard_reset) ? EXIT_SNK_BASED_ON_CC_BIT : 0);
+ if (rc < 0)
+ smblib_err(chg, "Couldn't set EXIT_SNK_BASED_ON_CC rc=%d\n",
rc);
- return rc;
- }
- vote(chg->apsd_disable_votable, PD_HARD_RESET_VOTER, val->intval, 0);
-
- if (val->intval)
- rc = smblib_cc2_sink_removal_enter(chg);
- else
- rc = smblib_cc2_sink_removal_exit(chg);
-
- if (rc < 0) {
- smblib_err(chg, "Could not detect cc2 removal rc=%d\n", rc);
- return rc;
- }
+ vote(chg->apsd_disable_votable, PD_HARD_RESET_VOTER,
+ chg->pd_hard_reset, 0);
return rc;
}
@@ -3116,25 +3074,43 @@
return IRQ_HANDLED;
}
-#define PL_DELAY_MS 30000
-irqreturn_t smblib_handle_usb_plugin(int irq, void *data)
+static void smblib_micro_usb_plugin(struct smb_charger *chg, bool vbus_rising)
{
- struct smb_irq_data *irq_data = data;
- struct smb_charger *chg = irq_data->parent_data;
+ if (vbus_rising) {
+ /* use the typec flag even though its not typec */
+ chg->typec_present = 1;
+ } else {
+ chg->typec_present = 0;
+ smblib_update_usb_type(chg);
+ extcon_set_cable_state_(chg->extcon, EXTCON_USB, false);
+ smblib_uusb_removal(chg);
+ }
+}
+
+static void smblib_typec_usb_plugin(struct smb_charger *chg, bool vbus_rising)
+{
+ if (vbus_rising)
+ smblib_cc2_sink_removal_exit(chg);
+ else
+ smblib_cc2_sink_removal_enter(chg);
+}
+
+#define PL_DELAY_MS 30000
+void smblib_usb_plugin_locked(struct smb_charger *chg)
+{
int rc;
u8 stat;
bool vbus_rising;
rc = smblib_read(chg, USBIN_BASE + INT_RT_STS_OFFSET, &stat);
if (rc < 0) {
- dev_err(chg->dev, "Couldn't read USB_INT_RT_STS rc=%d\n", rc);
- return IRQ_HANDLED;
+ smblib_err(chg, "Couldn't read USB_INT_RT_STS rc=%d\n", rc);
+ return;
}
vbus_rising = (bool)(stat & USBIN_PLUGIN_RT_STS_BIT);
- smblib_set_opt_freq_buck(chg,
- vbus_rising ? chg->chg_freq.freq_5V :
- chg->chg_freq.freq_removal);
+ smblib_set_opt_freq_buck(chg, vbus_rising ? chg->chg_freq.freq_5V :
+ chg->chg_freq.freq_removal);
/* fetch the DPDM regulator */
if (!chg->dpdm_reg && of_get_property(chg->dev->of_node,
@@ -3171,17 +3147,26 @@
smblib_err(chg, "Couldn't disable dpdm regulator rc=%d\n",
rc);
}
-
- if (chg->micro_usb_mode) {
- smblib_update_usb_type(chg);
- extcon_set_cable_state_(chg->extcon, EXTCON_USB, false);
- smblib_uusb_removal(chg);
- }
}
+ if (chg->micro_usb_mode)
+ smblib_micro_usb_plugin(chg, vbus_rising);
+ else
+ smblib_typec_usb_plugin(chg, vbus_rising);
+
power_supply_changed(chg->usb_psy);
- smblib_dbg(chg, PR_INTERRUPT, "IRQ: %s %s\n",
- irq_data->name, vbus_rising ? "attached" : "detached");
+ smblib_dbg(chg, PR_INTERRUPT, "IRQ: usbin-plugin %s\n",
+ vbus_rising ? "attached" : "detached");
+}
+
+irqreturn_t smblib_handle_usb_plugin(int irq, void *data)
+{
+ struct smb_irq_data *irq_data = data;
+ struct smb_charger *chg = irq_data->parent_data;
+
+ mutex_lock(&chg->lock);
+ smblib_usb_plugin_locked(chg);
+ mutex_unlock(&chg->lock);
return IRQ_HANDLED;
}
@@ -3350,9 +3335,6 @@
if (rising) {
vote(chg->pd_disallowed_votable_indirect, HVDCP_TIMEOUT_VOTER,
false, 0);
- if (get_effective_result(chg->pd_disallowed_votable_indirect))
- /* could be a legacy cable, try doing hvdcp */
- try_rerun_apsd_for_hvdcp(chg);
/* enable HDC and ICL irq for QC2/3 charger */
if (qc_charger)
@@ -3387,6 +3369,10 @@
static void smblib_force_legacy_icl(struct smb_charger *chg, int pst)
{
+ /* while PD is active it should have complete ICL control */
+ if (chg->pd_active)
+ return;
+
switch (pst) {
case POWER_SUPPLY_TYPE_USB:
/*
@@ -3426,7 +3412,7 @@
apsd_result = smblib_update_usb_type(chg);
- if (!chg->pd_active)
+ if (!chg->typec_legacy_valid)
smblib_force_legacy_icl(chg, apsd_result->pst);
switch (apsd_result->bit) {
@@ -3472,6 +3458,17 @@
}
smblib_dbg(chg, PR_REGISTER, "APSD_STATUS = 0x%02x\n", stat);
+ if (chg->micro_usb_mode && (stat & APSD_DTC_STATUS_DONE_BIT)
+ && !chg->uusb_apsd_rerun_done) {
+ /*
+ * Force re-run APSD to handle slow insertion related
+ * charger-mis-detection.
+ */
+ chg->uusb_apsd_rerun_done = true;
+ smblib_rerun_apsd(chg);
+ return IRQ_HANDLED;
+ }
+
smblib_handle_apsd_done(chg,
(bool)(stat & APSD_DTC_STATUS_DONE_BIT));
@@ -3505,71 +3502,6 @@
return IRQ_HANDLED;
}
-static void typec_source_removal(struct smb_charger *chg)
-{
- int rc;
-
- /* reset legacy unknown vote */
- vote(chg->usb_icl_votable, LEGACY_UNKNOWN_VOTER, false, 0);
-
- /* reset both usbin current and voltage votes */
- vote(chg->pl_enable_votable_indirect, USBIN_I_VOTER, false, 0);
- vote(chg->pl_enable_votable_indirect, USBIN_V_VOTER, false, 0);
-
- cancel_delayed_work_sync(&chg->hvdcp_detect_work);
-
- if (chg->wa_flags & QC_AUTH_INTERRUPT_WA_BIT) {
- /* re-enable AUTH_IRQ_EN_CFG_BIT */
- rc = smblib_masked_write(chg,
- USBIN_SOURCE_CHANGE_INTRPT_ENB_REG,
- AUTH_IRQ_EN_CFG_BIT, AUTH_IRQ_EN_CFG_BIT);
- if (rc < 0)
- smblib_err(chg,
- "Couldn't enable QC auth setting rc=%d\n", rc);
- }
-
- /* reconfigure allowed voltage for HVDCP */
- rc = smblib_set_adapter_allowance(chg,
- USBIN_ADAPTER_ALLOW_5V_OR_9V_TO_12V);
- if (rc < 0)
- smblib_err(chg, "Couldn't set USBIN_ADAPTER_ALLOW_5V_OR_9V_TO_12V rc=%d\n",
- rc);
-
- chg->voltage_min_uv = MICRO_5V;
- chg->voltage_max_uv = MICRO_5V;
-
- /* clear USB ICL vote for PD_VOTER */
- rc = vote(chg->usb_icl_votable, PD_VOTER, false, 0);
- if (rc < 0)
- smblib_err(chg, "Couldn't un-vote PD from USB ICL rc=%d\n", rc);
-
- /* clear USB ICL vote for USB_PSY_VOTER */
- rc = vote(chg->usb_icl_votable, USB_PSY_VOTER, false, 0);
- if (rc < 0)
- smblib_err(chg,
- "Couldn't un-vote USB_PSY from USB ICL rc=%d\n", rc);
-
- /* clear USB ICL vote for DCP_VOTER */
- rc = vote(chg->usb_icl_votable, DCP_VOTER, false, 0);
- if (rc < 0)
- smblib_err(chg,
- "Couldn't un-vote DCP from USB ICL rc=%d\n", rc);
-
-}
-
-static void typec_source_insertion(struct smb_charger *chg)
-{
- /*
- * at any time we want LEGACY_UNKNOWN, PD, or USB_PSY to be voting for
- * ICL, so vote LEGACY_UNKNOWN here if none of the above three have
- * casted their votes
- */
- if (!is_client_vote_enabled(chg->usb_icl_votable, LEGACY_UNKNOWN_VOTER)
- && !is_client_vote_enabled(chg->usb_icl_votable, PD_VOTER)
- && !is_client_vote_enabled(chg->usb_icl_votable, USB_PSY_VOTER))
- vote(chg->usb_icl_votable, LEGACY_UNKNOWN_VOTER, true, 100000);
-}
-
static void typec_sink_insertion(struct smb_charger *chg)
{
/* when a sink is inserted we should not wait on hvdcp timeout to
@@ -3590,30 +3522,50 @@
{
int rc;
- cancel_delayed_work_sync(&chg->pl_enable_work);
- vote(chg->pl_disable_votable, PL_DELAY_VOTER, true, 0);
- vote(chg->awake_votable, PL_DELAY_VOTER, false, 0);
+ chg->cc2_detach_wa_active = false;
+ /* reset APSD voters */
+ vote(chg->apsd_disable_votable, PD_HARD_RESET_VOTER, false, 0);
+ vote(chg->apsd_disable_votable, PD_VOTER, false, 0);
+
+ cancel_delayed_work_sync(&chg->pl_enable_work);
+ cancel_delayed_work_sync(&chg->hvdcp_detect_work);
+
+ /* reset input current limit voters */
+ vote(chg->usb_icl_votable, LEGACY_UNKNOWN_VOTER, true, 100000);
+ vote(chg->usb_icl_votable, PD_VOTER, false, 0);
+ vote(chg->usb_icl_votable, USB_PSY_VOTER, false, 0);
+ vote(chg->usb_icl_votable, DCP_VOTER, false, 0);
+ vote(chg->usb_icl_votable, PL_USBIN_USBIN_VOTER, false, 0);
+
+ /* reset hvdcp voters */
+ vote(chg->hvdcp_disable_votable_indirect, VBUS_CC_SHORT_VOTER, true, 0);
+ vote(chg->hvdcp_disable_votable_indirect, PD_INACTIVE_VOTER, true, 0);
+
+ /* reset power delivery voters */
+ vote(chg->pd_allowed_votable, PD_VOTER, false, 0);
vote(chg->pd_disallowed_votable_indirect, CC_DETACHED_VOTER, true, 0);
vote(chg->pd_disallowed_votable_indirect, HVDCP_TIMEOUT_VOTER, true, 0);
+
+ /* reset usb irq voters */
vote(chg->usb_irq_enable_votable, PD_VOTER, false, 0);
vote(chg->usb_irq_enable_votable, QC_VOTER, false, 0);
- /* reset votes from vbus_cc_short */
- vote(chg->hvdcp_disable_votable_indirect, VBUS_CC_SHORT_VOTER,
- true, 0);
- vote(chg->hvdcp_disable_votable_indirect, PD_INACTIVE_VOTER,
- true, 0);
- /*
- * cable could be removed during hard reset, remove its vote to
- * disable apsd
- */
- vote(chg->apsd_disable_votable, PD_HARD_RESET_VOTER, false, 0);
+ /* reset parallel voters */
+ vote(chg->pl_disable_votable, PL_DELAY_VOTER, true, 0);
+ vote(chg->pl_enable_votable_indirect, USBIN_I_VOTER, false, 0);
+ vote(chg->pl_enable_votable_indirect, USBIN_V_VOTER, false, 0);
+ vote(chg->awake_votable, PL_DELAY_VOTER, false, 0);
chg->vconn_attempts = 0;
chg->otg_attempts = 0;
chg->pulse_cnt = 0;
chg->usb_icl_delta_ua = 0;
+ chg->voltage_min_uv = MICRO_5V;
+ chg->voltage_max_uv = MICRO_5V;
+ chg->pd_active = 0;
+ chg->pd_hard_reset = 0;
+ chg->typec_legacy_valid = false;
/* enable APSD CC trigger for next insertion */
rc = smblib_masked_write(chg, TYPE_C_CFG_REG,
@@ -3621,15 +3573,48 @@
if (rc < 0)
smblib_err(chg, "Couldn't enable APSD_START_ON_CC rc=%d\n", rc);
- smblib_update_usb_type(chg);
- typec_source_removal(chg);
+ if (chg->wa_flags & QC_AUTH_INTERRUPT_WA_BIT) {
+ /* re-enable AUTH_IRQ_EN_CFG_BIT */
+ rc = smblib_masked_write(chg,
+ USBIN_SOURCE_CHANGE_INTRPT_ENB_REG,
+ AUTH_IRQ_EN_CFG_BIT, AUTH_IRQ_EN_CFG_BIT);
+ if (rc < 0)
+ smblib_err(chg,
+ "Couldn't enable QC auth setting rc=%d\n", rc);
+ }
+
+ /* reconfigure allowed voltage for HVDCP */
+ rc = smblib_set_adapter_allowance(chg,
+ USBIN_ADAPTER_ALLOW_5V_OR_9V_TO_12V);
+ if (rc < 0)
+ smblib_err(chg, "Couldn't set USBIN_ADAPTER_ALLOW_5V_OR_9V_TO_12V rc=%d\n",
+ rc);
+
+ /* enable DRP */
+ rc = smblib_masked_write(chg, TYPE_C_INTRPT_ENB_SOFTWARE_CTRL_REG,
+ TYPEC_POWER_ROLE_CMD_MASK, 0);
+ if (rc < 0)
+ smblib_err(chg, "Couldn't enable DRP rc=%d\n", rc);
+
+ /* HW controlled CC_OUT */
+ rc = smblib_masked_write(chg, TAPER_TIMER_SEL_CFG_REG,
+ TYPEC_SPARE_CFG_BIT, 0);
+ if (rc < 0)
+ smblib_err(chg, "Couldn't enable HW cc_out rc=%d\n", rc);
+
+ /* restore crude sensor */
+ rc = smblib_write(chg, TM_IO_DTEST4_SEL, 0xA5);
+ if (rc < 0)
+ smblib_err(chg, "Couldn't restore crude sensor rc=%d\n", rc);
+
typec_sink_removal(chg);
+ smblib_update_usb_type(chg);
}
static void smblib_handle_typec_insertion(struct smb_charger *chg,
- bool sink_attached, bool legacy_cable)
+ bool sink_attached)
{
- int rp, rc;
+ int rc;
vote(chg->pd_disallowed_votable_indirect, CC_DETACHED_VOTER, false, 0);
@@ -3639,59 +3624,36 @@
smblib_err(chg, "Couldn't disable APSD_START_ON_CC rc=%d\n",
rc);
- if (sink_attached) {
- typec_source_removal(chg);
+ if (sink_attached)
typec_sink_insertion(chg);
- } else {
- typec_source_insertion(chg);
+ else
typec_sink_removal(chg);
- }
-
- rp = smblib_get_prop_ufp_mode(chg);
- if (rp == POWER_SUPPLY_TYPEC_SOURCE_HIGH
- || rp == POWER_SUPPLY_TYPEC_NON_COMPLIANT) {
- smblib_dbg(chg, PR_MISC, "VBUS & CC could be shorted; keeping HVDCP disabled\n");
- vote(chg->hvdcp_disable_votable_indirect, VBUS_CC_SHORT_VOTER,
- true, 0);
- } else {
- vote(chg->hvdcp_disable_votable_indirect, VBUS_CC_SHORT_VOTER,
- false, 0);
- }
}
static void smblib_handle_typec_debounce_done(struct smb_charger *chg,
- bool rising, bool sink_attached, bool legacy_cable)
+ bool rising, bool sink_attached)
{
int rc;
union power_supply_propval pval = {0, };
- if (rising)
- smblib_handle_typec_insertion(chg, sink_attached, legacy_cable);
- else
- smblib_handle_typec_removal(chg);
+ if (rising) {
+ if (!chg->typec_present) {
+ chg->typec_present = true;
+ smblib_dbg(chg, PR_MISC, "TypeC insertion\n");
+ smblib_handle_typec_insertion(chg, sink_attached);
+ }
+ } else {
+ if (chg->typec_present) {
+ chg->typec_present = false;
+ smblib_dbg(chg, PR_MISC, "TypeC removal\n");
+ smblib_handle_typec_removal(chg);
+ }
+ }
rc = smblib_get_prop_typec_mode(chg, &pval);
if (rc < 0)
smblib_err(chg, "Couldn't get prop typec mode rc=%d\n", rc);
- /*
- * HW BUG - after cable is removed, medium or high rd reading
- * falls to std. Use it for signal of typec cc detachment in
- * software WA.
- */
- if (chg->cc2_sink_detach_flag == CC2_SINK_MEDIUM_HIGH
- && pval.intval == POWER_SUPPLY_TYPEC_SOURCE_DEFAULT) {
-
- chg->cc2_sink_detach_flag = CC2_SINK_WA_DONE;
-
- rc = smblib_masked_write(chg,
- TYPE_C_INTRPT_ENB_SOFTWARE_CTRL_REG,
- EXIT_SNK_BASED_ON_CC_BIT, 0);
- if (rc < 0)
- smblib_err(chg, "Couldn't get prop typec mode rc=%d\n",
- rc);
- }
-
smblib_dbg(chg, PR_INTERRUPT, "IRQ: debounce-done %s; Type-C %s detected\n",
rising ? "rising" : "falling",
smblib_typec_mode_name[pval.intval]);
@@ -3717,50 +3679,54 @@
return IRQ_HANDLED;
}
+static void smblib_usb_typec_change(struct smb_charger *chg)
+{
+ int rc;
+ bool debounce_done, sink_attached;
+
+ rc = smblib_multibyte_read(chg, TYPE_C_STATUS_1_REG,
+ chg->typec_status, 5);
+ if (rc < 0) {
+ smblib_err(chg, "Couldn't cache USB Type-C status rc=%d\n", rc);
+ return;
+ }
+
+ debounce_done =
+ (bool)(chg->typec_status[3] & TYPEC_DEBOUNCE_DONE_STATUS_BIT);
+ sink_attached =
+ (bool)(chg->typec_status[3] & UFP_DFP_MODE_STATUS_BIT);
+
+ smblib_handle_typec_debounce_done(chg, debounce_done, sink_attached);
+
+ if (chg->typec_status[3] & TYPEC_VBUS_ERROR_STATUS_BIT)
+ smblib_dbg(chg, PR_INTERRUPT, "IRQ: vbus-error\n");
+
+ if (chg->typec_status[3] & TYPEC_VCONN_OVERCURR_STATUS_BIT)
+ schedule_work(&chg->vconn_oc_work);
+
+ power_supply_changed(chg->usb_psy);
+}
+
irqreturn_t smblib_handle_usb_typec_change(int irq, void *data)
{
struct smb_irq_data *irq_data = data;
struct smb_charger *chg = irq_data->parent_data;
- int rc;
- u8 stat4, stat5;
- bool debounce_done, sink_attached, legacy_cable;
- if (chg->micro_usb_mode)
- return smblib_handle_usb_typec_change_for_uusb(chg);
-
- /* WA - not when PD hard_reset WIP on cc2 in sink mode */
- if (chg->cc2_sink_detach_flag == CC2_SINK_STD)
- return IRQ_HANDLED;
-
- rc = smblib_read(chg, TYPE_C_STATUS_4_REG, &stat4);
- if (rc < 0) {
- smblib_err(chg, "Couldn't read TYPE_C_STATUS_4 rc=%d\n", rc);
+ if (chg->micro_usb_mode) {
+ smblib_handle_usb_typec_change_for_uusb(chg);
return IRQ_HANDLED;
}
- rc = smblib_read(chg, TYPE_C_STATUS_5_REG, &stat5);
- if (rc < 0) {
- smblib_err(chg, "Couldn't read TYPE_C_STATUS_5 rc=%d\n", rc);
+ if (chg->cc2_detach_wa_active || chg->typec_en_dis_active) {
+ smblib_dbg(chg, PR_INTERRUPT, "Ignoring since %s active\n",
+ chg->cc2_detach_wa_active ?
+ "cc2_detach_wa" : "typec_en_dis");
return IRQ_HANDLED;
}
- debounce_done = (bool)(stat4 & TYPEC_DEBOUNCE_DONE_STATUS_BIT);
- sink_attached = (bool)(stat4 & UFP_DFP_MODE_STATUS_BIT);
- legacy_cable = (bool)(stat5 & TYPEC_LEGACY_CABLE_STATUS_BIT);
-
- smblib_handle_typec_debounce_done(chg,
- debounce_done, sink_attached, legacy_cable);
-
- if (stat4 & TYPEC_VBUS_ERROR_STATUS_BIT)
- smblib_dbg(chg, PR_INTERRUPT, "IRQ: %s vbus-error\n",
- irq_data->name);
-
- if (stat4 & TYPEC_VCONN_OVERCURR_STATUS_BIT)
- schedule_work(&chg->vconn_oc_work);
-
- power_supply_changed(chg->usb_psy);
- smblib_dbg(chg, PR_REGISTER, "TYPE_C_STATUS_4 = 0x%02x\n", stat4);
- smblib_dbg(chg, PR_REGISTER, "TYPE_C_STATUS_5 = 0x%02x\n", stat5);
+ mutex_lock(&chg->lock);
+ smblib_usb_typec_change(chg);
+ mutex_unlock(&chg->lock);
return IRQ_HANDLED;
}
@@ -3788,7 +3754,7 @@
{
struct smb_irq_data *irq_data = data;
struct smb_charger *chg = irq_data->parent_data;
- int rc;
+ int rc, usb_icl;
u8 stat;
if (!(chg->wa_flags & BOOST_BACK_WA))
@@ -3800,8 +3766,9 @@
return IRQ_HANDLED;
}
- if ((stat & USE_USBIN_BIT) &&
- get_effective_result(chg->usb_icl_votable) < USBIN_25MA)
+ /* skip suspending input if its already suspended by some other voter */
+ usb_icl = get_effective_result(chg->usb_icl_votable);
+ if ((stat & USE_USBIN_BIT) && usb_icl >= 0 && usb_icl < USBIN_25MA)
return IRQ_HANDLED;
if (stat & USE_DCIN_BIT)
@@ -3839,12 +3806,7 @@
vote(chg->pd_disallowed_votable_indirect, HVDCP_TIMEOUT_VOTER,
false, 0);
- if (get_effective_result(chg->pd_disallowed_votable_indirect))
- /* pd is still disabled, try hvdcp */
- try_rerun_apsd_for_hvdcp(chg);
- else
- /* notify pd now that pd is allowed */
- power_supply_changed(chg->usb_psy);
+ power_supply_changed(chg->usb_psy);
}
static void bms_update_work(struct work_struct *work)
@@ -3885,11 +3847,13 @@
static void rdstd_cc2_detach_work(struct work_struct *work)
{
int rc;
- u8 stat;
- struct smb_irq_data irq_data = {NULL, "cc2-removal-workaround"};
+ u8 stat4, stat5;
struct smb_charger *chg = container_of(work, struct smb_charger,
rdstd_cc2_detach_work);
+ if (!chg->cc2_detach_wa_active)
+ return;
+
/*
* WA steps -
* 1. Enable both UFP and DFP, wait for 10ms.
@@ -3897,7 +3861,7 @@
* 3. Removal detected if both TYPEC_DEBOUNCE_DONE_STATUS
* and TIMER_STAGE bits are gone, otherwise repeat all by
* work rescheduling.
- * Note, work will be cancelled when pd_hard_reset is 0.
+ * Note, work will be cancelled when USB_PLUGIN rises.
*/
rc = smblib_masked_write(chg, TYPE_C_INTRPT_ENB_SOFTWARE_CTRL_REG,
@@ -3920,30 +3884,35 @@
usleep_range(30000, 31000);
- rc = smblib_read(chg, TYPE_C_STATUS_4_REG, &stat);
+ rc = smblib_read(chg, TYPE_C_STATUS_4_REG, &stat4);
if (rc < 0) {
- smblib_err(chg, "Couldn't read TYPE_C_STATUS_4 rc=%d\n",
- rc);
+ smblib_err(chg, "Couldn't read TYPE_C_STATUS_4 rc=%d\n", rc);
return;
}
- if (stat & TYPEC_DEBOUNCE_DONE_STATUS_BIT)
- goto rerun;
- rc = smblib_read(chg, TYPE_C_STATUS_5_REG, &stat);
+ rc = smblib_read(chg, TYPE_C_STATUS_5_REG, &stat5);
if (rc < 0) {
smblib_err(chg,
"Couldn't read TYPE_C_STATUS_5_REG rc=%d\n", rc);
return;
}
- if (stat & TIMER_STAGE_2_BIT)
+
+ if ((stat4 & TYPEC_DEBOUNCE_DONE_STATUS_BIT)
+ || (stat5 & TIMER_STAGE_2_BIT)) {
+ smblib_dbg(chg, PR_MISC, "rerunning DD=%d TS2BIT=%d\n",
+ (int)(stat4 & TYPEC_DEBOUNCE_DONE_STATUS_BIT),
+ (int)(stat5 & TIMER_STAGE_2_BIT));
goto rerun;
+ }
- /* Bingo, cc2 removal detected */
+ smblib_dbg(chg, PR_MISC, "Bingo CC2 Removal detected\n");
+ chg->cc2_detach_wa_active = false;
+ rc = smblib_masked_write(chg, TYPE_C_INTRPT_ENB_SOFTWARE_CTRL_REG,
+ EXIT_SNK_BASED_ON_CC_BIT, 0);
smblib_reg_block_restore(chg, cc2_detach_settings);
- chg->cc2_sink_detach_flag = CC2_SINK_WA_DONE;
- irq_data.parent_data = chg;
- smblib_handle_usb_typec_change(0, &irq_data);
-
+ mutex_lock(&chg->lock);
+ smblib_usb_typec_change(chg);
+ mutex_unlock(&chg->lock);
return;
rerun:
@@ -4166,6 +4135,56 @@
vote(chg->awake_votable, PL_DELAY_VOTER, false, 0);
}
+static void smblib_legacy_detection_work(struct work_struct *work)
+{
+ struct smb_charger *chg = container_of(work, struct smb_charger,
+ legacy_detection_work);
+ int rc;
+ u8 stat;
+ bool legacy, rp_high;
+
+ mutex_lock(&chg->lock);
+ chg->typec_en_dis_active = 1;
+ smblib_dbg(chg, PR_MISC, "running legacy unknown workaround\n");
+ rc = smblib_masked_write(chg,
+ TYPE_C_INTRPT_ENB_SOFTWARE_CTRL_REG,
+ TYPEC_DISABLE_CMD_BIT,
+ TYPEC_DISABLE_CMD_BIT);
+ if (rc < 0)
+ smblib_err(chg, "Couldn't disable type-c rc=%d\n", rc);
+
+ /* wait for the adapter to turn off VBUS */
+ msleep(500);
+
+ rc = smblib_masked_write(chg,
+ TYPE_C_INTRPT_ENB_SOFTWARE_CTRL_REG,
+ TYPEC_DISABLE_CMD_BIT, 0);
+ if (rc < 0)
+ smblib_err(chg, "Couldn't enable type-c rc=%d\n", rc);
+
+ /* wait for type-c detection to complete */
+ msleep(100);
+
+ rc = smblib_read(chg, TYPE_C_STATUS_5_REG, &stat);
+ if (rc < 0) {
+ smblib_err(chg, "Couldn't read typec stat5 rc = %d\n", rc);
+ goto unlock;
+ }
+
+ chg->typec_legacy_valid = true;
+ vote(chg->usb_icl_votable, LEGACY_UNKNOWN_VOTER, false, 0);
+ legacy = stat & TYPEC_LEGACY_CABLE_STATUS_BIT;
+ rp_high = smblib_get_prop_ufp_mode(chg) ==
+ POWER_SUPPLY_TYPEC_SOURCE_HIGH;
+ if (!legacy || !rp_high)
+ vote(chg->hvdcp_disable_votable_indirect, VBUS_CC_SHORT_VOTER,
+ false, 0);
+
+unlock:
+ chg->typec_en_dis_active = 0;
+ mutex_unlock(&chg->lock);
+}
+
static int smblib_create_votables(struct smb_charger *chg)
{
int rc = 0;
@@ -4298,6 +4317,15 @@
return rc;
}
+ chg->typec_irq_disable_votable = create_votable("TYPEC_IRQ_DISABLE",
+ VOTE_SET_ANY,
+ smblib_typec_irq_disable_vote_callback,
+ chg);
+ if (IS_ERR(chg->typec_irq_disable_votable)) {
+ rc = PTR_ERR(chg->typec_irq_disable_votable);
+ return rc;
+ }
+
return rc;
}
@@ -4323,6 +4351,8 @@
destroy_votable(chg->apsd_disable_votable);
if (chg->hvdcp_hw_inov_dis_votable)
destroy_votable(chg->hvdcp_hw_inov_dis_votable);
+ if (chg->typec_irq_disable_votable)
+ destroy_votable(chg->typec_irq_disable_votable);
}
static void smblib_iio_deinit(struct smb_charger *chg)
@@ -4343,6 +4373,7 @@
{
int rc = 0;
+ mutex_init(&chg->lock);
mutex_init(&chg->write_lock);
mutex_init(&chg->otg_oc_lock);
INIT_WORK(&chg->bms_update_work, bms_update_work);
@@ -4355,6 +4386,7 @@
INIT_DELAYED_WORK(&chg->otg_ss_done_work, smblib_otg_ss_done_work);
INIT_DELAYED_WORK(&chg->icl_change_work, smblib_icl_change_work);
INIT_DELAYED_WORK(&chg->pl_enable_work, smblib_pl_enable_work);
+ INIT_WORK(&chg->legacy_detection_work, smblib_legacy_detection_work);
chg->fake_capacity = -EINVAL;
switch (chg->mode) {
diff --git a/drivers/power/supply/qcom/smb-lib.h b/drivers/power/supply/qcom/smb-lib.h
index 49b9d3d..b0d84f0 100644
--- a/drivers/power/supply/qcom/smb-lib.h
+++ b/drivers/power/supply/qcom/smb-lib.h
@@ -61,6 +61,7 @@
#define SW_QC3_VOTER "SW_QC3_VOTER"
#define AICL_RERUN_VOTER "AICL_RERUN_VOTER"
#define LEGACY_UNKNOWN_VOTER "LEGACY_UNKNOWN_VOTER"
+#define CC2_WA_VOTER "CC2_WA_VOTER"
#define VCONN_MAX_ATTEMPTS 3
#define OTG_MAX_ATTEMPTS 3
@@ -71,13 +72,6 @@
NUM_MODES,
};
-enum cc2_sink_type {
- CC2_SINK_NONE = 0,
- CC2_SINK_STD,
- CC2_SINK_MEDIUM_HIGH,
- CC2_SINK_WA_DONE,
-};
-
enum {
QC_CHARGER_DETECTION_WA_BIT = BIT(0),
BOOST_BACK_WA = BIT(1),
@@ -236,6 +230,7 @@
int smb_version;
/* locks */
+ struct mutex lock;
struct mutex write_lock;
struct mutex ps_change_lock;
struct mutex otg_oc_lock;
@@ -276,6 +271,7 @@
struct votable *apsd_disable_votable;
struct votable *hvdcp_hw_inov_dis_votable;
struct votable *usb_irq_enable_votable;
+ struct votable *typec_irq_disable_votable;
/* work */
struct work_struct bms_update_work;
@@ -289,6 +285,7 @@
struct delayed_work otg_ss_done_work;
struct delayed_work icl_change_work;
struct delayed_work pl_enable_work;
+ struct work_struct legacy_detection_work;
/* cached status */
int voltage_min_uv;
@@ -312,10 +309,16 @@
int vconn_attempts;
int default_icl_ua;
int otg_cl_ua;
+ bool uusb_apsd_rerun_done;
+ bool pd_hard_reset;
+ bool typec_present;
+ u8 typec_status[5];
+ bool typec_legacy_valid;
/* workaround flag */
u32 wa_flags;
- enum cc2_sink_type cc2_sink_detach_flag;
+ bool cc2_detach_wa_active;
+ bool typec_en_dis_active;
int boost_current_ua;
int temp_speed_reading_count;
diff --git a/drivers/power/supply/qcom/smb-reg.h b/drivers/power/supply/qcom/smb-reg.h
index 167666a..3f260a4 100644
--- a/drivers/power/supply/qcom/smb-reg.h
+++ b/drivers/power/supply/qcom/smb-reg.h
@@ -1025,4 +1025,14 @@
/* CHGR FREQ Peripheral registers */
#define FREQ_CLK_DIV_REG (CHGR_FREQ_BASE + 0x50)
+/* SMB1355 specific registers */
+#define SMB1355_TEMP_COMP_STATUS_REG (MISC_BASE + 0x07)
+#define SKIN_TEMP_RST_HOT_BIT BIT(6)
+#define SKIN_TEMP_UB_HOT_BIT BIT(5)
+#define SKIN_TEMP_LB_HOT_BIT BIT(4)
+#define DIE_TEMP_TSD_HOT_BIT BIT(3)
+#define DIE_TEMP_RST_HOT_BIT BIT(2)
+#define DIE_TEMP_UB_HOT_BIT BIT(1)
+#define DIE_TEMP_LB_HOT_BIT BIT(0)
+
#endif /* __SMB2_CHARGER_REG_H */
diff --git a/drivers/power/supply/qcom/smb1351-charger.c b/drivers/power/supply/qcom/smb1351-charger.c
index 0d1f2a6..b92a482 100644
--- a/drivers/power/supply/qcom/smb1351-charger.c
+++ b/drivers/power/supply/qcom/smb1351-charger.c
@@ -1655,7 +1655,7 @@
switch (prop) {
case POWER_SUPPLY_PROP_CHARGING_ENABLED:
- val->intval = !chip->usb_suspended_status;
+ val->intval = !chip->parallel_charger_suspended;
break;
case POWER_SUPPLY_PROP_CURRENT_MAX:
if (!chip->parallel_charger_suspended)
diff --git a/drivers/power/supply/qcom/smb138x-charger.c b/drivers/power/supply/qcom/smb138x-charger.c
index 83374bb..a29871b 100644
--- a/drivers/power/supply/qcom/smb138x-charger.c
+++ b/drivers/power/supply/qcom/smb138x-charger.c
@@ -104,6 +104,8 @@
struct smb_dt_props dt;
struct power_supply *parallel_psy;
u32 wa_flags;
+ struct pmic_revid_data *pmic_rev_id;
+ char *name;
};
static int __debug_mask;
@@ -167,6 +169,14 @@
if (rc < 0)
chip->dt.pl_mode = POWER_SUPPLY_PL_USBMID_USBMID;
+ /* check that smb1355 is configured to run in mid-mid mode */
+ if (chip->pmic_rev_id->pmic_subtype == SMB1355_SUBTYPE
+ && chip->dt.pl_mode != POWER_SUPPLY_PL_USBMID_USBMID) {
+ pr_err("Smb1355 can only run in MID-MID mode, saw = %d mode\n",
+ chip->dt.pl_mode);
+ return -EINVAL;
+ }
+
chip->dt.suspend_input = of_property_read_bool(node,
"qcom,suspend-input");
@@ -479,6 +489,30 @@
* PARALLEL PSY REGISTRATION *
*****************************/
+static int smb1355_get_prop_connector_health(struct smb138x *chip)
+{
+ struct smb_charger *chg = &chip->chg;
+ u8 temp;
+ int rc;
+
+ rc = smblib_read(chg, SMB1355_TEMP_COMP_STATUS_REG, &temp);
+ if (rc < 0) {
+ pr_err("Couldn't read comp stat reg rc = %d\n", rc);
+ return POWER_SUPPLY_HEALTH_UNKNOWN;
+ }
+
+ if (temp & SKIN_TEMP_RST_HOT_BIT)
+ return POWER_SUPPLY_HEALTH_OVERHEAT;
+
+ if (temp & SKIN_TEMP_UB_HOT_BIT)
+ return POWER_SUPPLY_HEALTH_HOT;
+
+ if (temp & SKIN_TEMP_LB_HOT_BIT)
+ return POWER_SUPPLY_HEALTH_WARM;
+
+ return POWER_SUPPLY_HEALTH_COOL;
+}
+
static int smb138x_get_prop_connector_health(struct smb138x *chip)
{
struct smb_charger *chg = &chip->chg;
@@ -536,16 +570,32 @@
POWER_SUPPLY_PROP_PIN_ENABLED,
POWER_SUPPLY_PROP_INPUT_SUSPEND,
POWER_SUPPLY_PROP_INPUT_CURRENT_LIMITED,
- POWER_SUPPLY_PROP_CURRENT_MAX,
POWER_SUPPLY_PROP_VOLTAGE_MAX,
POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX,
- POWER_SUPPLY_PROP_CURRENT_NOW,
- POWER_SUPPLY_PROP_CHARGER_TEMP,
- POWER_SUPPLY_PROP_CHARGER_TEMP_MAX,
POWER_SUPPLY_PROP_MODEL_NAME,
POWER_SUPPLY_PROP_PARALLEL_MODE,
POWER_SUPPLY_PROP_CONNECTOR_HEALTH,
POWER_SUPPLY_PROP_SET_SHIP_MODE,
+ POWER_SUPPLY_PROP_CHARGER_TEMP,
+ POWER_SUPPLY_PROP_CHARGER_TEMP_MAX,
+ POWER_SUPPLY_PROP_CURRENT_NOW,
+ POWER_SUPPLY_PROP_CURRENT_MAX,
+};
+
+static enum power_supply_property smb1355_parallel_props[] = {
+ POWER_SUPPLY_PROP_CHARGE_TYPE,
+ POWER_SUPPLY_PROP_CHARGING_ENABLED,
+ POWER_SUPPLY_PROP_PIN_ENABLED,
+ POWER_SUPPLY_PROP_INPUT_SUSPEND,
+ POWER_SUPPLY_PROP_INPUT_CURRENT_LIMITED,
+ POWER_SUPPLY_PROP_VOLTAGE_MAX,
+ POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX,
+ POWER_SUPPLY_PROP_MODEL_NAME,
+ POWER_SUPPLY_PROP_PARALLEL_MODE,
+ POWER_SUPPLY_PROP_CONNECTOR_HEALTH,
+ POWER_SUPPLY_PROP_SET_SHIP_MODE,
+ POWER_SUPPLY_PROP_CHARGER_TEMP,
+ POWER_SUPPLY_PROP_CHARGER_TEMP_MAX,
};
static int smb138x_parallel_get_prop(struct power_supply *psy,
@@ -583,14 +633,6 @@
else
val->intval = 0;
break;
- case POWER_SUPPLY_PROP_CURRENT_MAX:
- if ((chip->dt.pl_mode == POWER_SUPPLY_PL_USBIN_USBIN)
- || (chip->dt.pl_mode == POWER_SUPPLY_PL_USBIN_USBIN_EXT))
- rc = smblib_get_charge_param(chg, &chg->param.usb_icl,
- &val->intval);
- else
- val->intval = 0;
- break;
case POWER_SUPPLY_PROP_VOLTAGE_MAX:
rc = smblib_get_charge_param(chg, &chg->param.fv, &val->intval);
break;
@@ -598,28 +640,46 @@
rc = smblib_get_charge_param(chg, &chg->param.fcc,
&val->intval);
break;
- case POWER_SUPPLY_PROP_CURRENT_NOW:
- rc = smblib_get_prop_slave_current_now(chg, val);
- break;
- case POWER_SUPPLY_PROP_CHARGER_TEMP:
- rc = smb138x_get_prop_charger_temp(chip, val);
- break;
- case POWER_SUPPLY_PROP_CHARGER_TEMP_MAX:
- rc = smblib_get_prop_charger_temp_max(chg, val);
- break;
case POWER_SUPPLY_PROP_MODEL_NAME:
- val->strval = "smb138x";
+ val->strval = chip->name;
break;
case POWER_SUPPLY_PROP_PARALLEL_MODE:
val->intval = chip->dt.pl_mode;
break;
case POWER_SUPPLY_PROP_CONNECTOR_HEALTH:
- val->intval = smb138x_get_prop_connector_health(chip);
+ if (chip->pmic_rev_id->pmic_subtype != SMB1355_SUBTYPE)
+ val->intval = smb138x_get_prop_connector_health(chip);
+ else
+ val->intval = smb1355_get_prop_connector_health(chip);
break;
case POWER_SUPPLY_PROP_SET_SHIP_MODE:
/* Not in ship mode as long as device is active */
val->intval = 0;
break;
+ case POWER_SUPPLY_PROP_CHARGER_TEMP:
+ if (chip->pmic_rev_id->pmic_subtype != SMB1355_SUBTYPE)
+ rc = smb138x_get_prop_charger_temp(chip, val);
+ else
+ rc = smblib_get_prop_charger_temp(chg, val);
+ break;
+ case POWER_SUPPLY_PROP_CHARGER_TEMP_MAX:
+ rc = smblib_get_prop_charger_temp_max(chg, val);
+ break;
+ case POWER_SUPPLY_PROP_CURRENT_NOW:
+ if (chip->pmic_rev_id->pmic_subtype != SMB1355_SUBTYPE)
+ rc = smblib_get_prop_slave_current_now(chg, val);
+ else
+ rc = -ENODATA;
+ break;
+ case POWER_SUPPLY_PROP_CURRENT_MAX:
+ if ((chip->pmic_rev_id->pmic_subtype != SMB1355_SUBTYPE)
+ && ((chip->dt.pl_mode == POWER_SUPPLY_PL_USBIN_USBIN)
+ || (chip->dt.pl_mode == POWER_SUPPLY_PL_USBIN_USBIN_EXT)))
+ rc = smblib_get_charge_param(chg, &chg->param.usb_icl,
+ &val->intval);
+ else
+ rc = -ENODATA;
+ break;
default:
pr_err("parallel power supply get prop %d not supported\n",
prop);
@@ -703,7 +763,7 @@
return 0;
}
-static const struct power_supply_desc parallel_psy_desc = {
+static struct power_supply_desc parallel_psy_desc = {
.name = "parallel",
.type = POWER_SUPPLY_TYPE_PARALLEL,
.properties = smb138x_parallel_props,
@@ -731,6 +791,28 @@
return 0;
}
+static int smb1355_init_parallel_psy(struct smb138x *chip)
+{
+ struct power_supply_config parallel_cfg = {};
+ struct smb_charger *chg = &chip->chg;
+
+ parallel_cfg.drv_data = chip;
+ parallel_cfg.of_node = chg->dev->of_node;
+
+ /* change to smb1355's property list */
+ parallel_psy_desc.properties = smb1355_parallel_props;
+ parallel_psy_desc.num_properties = ARRAY_SIZE(smb1355_parallel_props);
+ chip->parallel_psy = devm_power_supply_register(chg->dev,
+ ¶llel_psy_desc,
+ ¶llel_cfg);
+ if (IS_ERR(chip->parallel_psy)) {
+ pr_err("Couldn't register parallel power supply\n");
+ return PTR_ERR(chip->parallel_psy);
+ }
+
+ return 0;
+}
+
/******************************
* VBUS REGULATOR REGISTRATION *
******************************/
@@ -1050,7 +1132,6 @@
static int smb138x_setup_wa_flags(struct smb138x *chip)
{
- struct pmic_revid_data *pmic_rev_id;
struct device_node *revid_dev_node;
revid_dev_node = of_parse_phandle(chip->chg.dev->of_node,
@@ -1060,8 +1141,8 @@
return -EINVAL;
}
- pmic_rev_id = get_revid_data(revid_dev_node);
- if (IS_ERR_OR_NULL(pmic_rev_id)) {
+ chip->pmic_rev_id = get_revid_data(revid_dev_node);
+ if (IS_ERR_OR_NULL(chip->pmic_rev_id)) {
/*
* the revid peripheral must be registered, any failure
* here only indicates that the rev-id module has not
@@ -1070,14 +1151,14 @@
return -EPROBE_DEFER;
}
- switch (pmic_rev_id->pmic_subtype) {
+ switch (chip->pmic_rev_id->pmic_subtype) {
case SMB1381_SUBTYPE:
- if (pmic_rev_id->rev4 < 2) /* SMB1381 rev 1.0 */
+ if (chip->pmic_rev_id->rev4 < 2) /* SMB1381 rev 1.0 */
chip->wa_flags |= OOB_COMP_WA_BIT;
break;
default:
pr_err("PMIC subtype %d not supported\n",
- pmic_rev_id->pmic_subtype);
+ chip->pmic_rev_id->pmic_subtype);
return -EINVAL;
}
@@ -1375,6 +1456,7 @@
chg->param = v1_params;
+ chip->name = "smb1381";
rc = smblib_init(chg);
if (rc < 0) {
pr_err("Couldn't initialize smblib rc=%d\n", rc);
@@ -1435,7 +1517,7 @@
return rc;
}
-static int smb138x_slave_probe(struct smb138x *chip)
+static int smb1355_slave_probe(struct smb138x *chip)
{
struct smb_charger *chg = &chip->chg;
int rc = 0;
@@ -1448,6 +1530,55 @@
goto cleanup;
}
+ rc = smb138x_parse_dt(chip);
+ if (rc < 0) {
+ pr_err("Couldn't parse device tree rc=%d\n", rc);
+ goto cleanup;
+ }
+
+ rc = smb138x_init_slave_hw(chip);
+ if (rc < 0) {
+ pr_err("Couldn't initialize hardware rc=%d\n", rc);
+ goto cleanup;
+ }
+
+ rc = smb1355_init_parallel_psy(chip);
+ if (rc < 0) {
+ pr_err("Couldn't initialize parallel psy rc=%d\n", rc);
+ goto cleanup;
+ }
+
+ rc = smb138x_determine_initial_slave_status(chip);
+ if (rc < 0) {
+ pr_err("Couldn't determine initial status rc=%d\n", rc);
+ goto cleanup;
+ }
+
+ rc = smb138x_request_interrupts(chip);
+ if (rc < 0) {
+ pr_err("Couldn't request interrupts rc=%d\n", rc);
+ goto cleanup;
+ }
+
+ return 0;
+
+cleanup:
+ smblib_deinit(chg);
+ return rc;
+}
+
+static int smb1381_slave_probe(struct smb138x *chip)
+{
+ struct smb_charger *chg = &chip->chg;
+ int rc = 0;
+
+ chg->param = v1_params;
+
+ rc = smblib_init(chg);
+ if (rc < 0) {
+ pr_err("Couldn't initialize smblib rc=%d\n", rc);
+ goto cleanup;
+ }
chg->iio.temp_max_chan = iio_channel_get(chg->dev, "charger_temp_max");
if (IS_ERR(chg->iio.temp_max_chan)) {
rc = PTR_ERR(chg->iio.temp_max_chan);
@@ -1515,25 +1646,71 @@
goto cleanup;
}
- return rc;
+ return 0;
cleanup:
smblib_deinit(chg);
- if (chip->parallel_psy)
- power_supply_unregister(chip->parallel_psy);
- if (chg->vbus_vreg && chg->vbus_vreg->rdev)
- regulator_unregister(chg->vbus_vreg->rdev);
return rc;
}
+static int slave_probe(struct smb138x *chip)
+{
+ struct device_node *revid_dev_node;
+ int rc = 0;
+
+ revid_dev_node = of_parse_phandle(chip->chg.dev->of_node,
+ "qcom,pmic-revid", 0);
+ if (!revid_dev_node) {
+ pr_err("Missing qcom,pmic-revid property\n");
+ return -EINVAL;
+ }
+
+ chip->pmic_rev_id = get_revid_data(revid_dev_node);
+ if (IS_ERR_OR_NULL(chip->pmic_rev_id)) {
+ /*
+ * the revid peripheral must be registered, any failure
+ * here only indicates that the rev-id module has not
+ * probed yet.
+ */
+ return -EPROBE_DEFER;
+ }
+
+ switch (chip->pmic_rev_id->pmic_subtype) {
+ case SMB1355_SUBTYPE:
+ chip->name = "smb1355";
+ rc = smb1355_slave_probe(chip);
+ break;
+ case SMB1381_SUBTYPE:
+ chip->name = "smb1381";
+ rc = smb1381_slave_probe(chip);
+ break;
+ default:
+ pr_err("Unsupported pmic subtype = 0x%02x\n",
+ chip->pmic_rev_id->pmic_subtype);
+ rc = -EINVAL;
+ }
+
+ if (rc < 0) {
+ if (rc != -EPROBE_DEFER)
+ pr_err("Couldn't probe SMB138X rc=%d\n", rc);
+ return rc;
+ }
+
+ return 0;
+}
+
static const struct of_device_id match_table[] = {
{
- .compatible = "qcom,smb138x-charger",
- .data = (void *) PARALLEL_MASTER
+ .compatible = "qcom,smb138x-charger",
+ .data = (void *) PARALLEL_MASTER,
},
{
- .compatible = "qcom,smb138x-parallel-slave",
- .data = (void *) PARALLEL_SLAVE
+ .compatible = "qcom,smb138x-parallel-slave",
+ .data = (void *) PARALLEL_SLAVE,
+ },
+ {
+ .compatible = "qcom,smb1355-parallel-slave",
+ .data = (void *) PARALLEL_SLAVE,
},
{ },
};
@@ -1580,7 +1757,7 @@
rc = smb138x_master_probe(chip);
break;
case PARALLEL_SLAVE:
- rc = smb138x_slave_probe(chip);
+ rc = slave_probe(chip);
break;
default:
pr_err("Couldn't find a matching mode %d\n", chip->chg.mode);
@@ -1594,7 +1771,8 @@
goto cleanup;
}
- pr_info("SMB138X probed successfully mode=%d\n", chip->chg.mode);
+ pr_info("%s probed successfully mode=%d pl_mode = %d\n",
+ chip->name, chip->chg.mode, chip->dt.pl_mode);
return rc;
cleanup:
diff --git a/drivers/pwm/pwm-rockchip.c b/drivers/pwm/pwm-rockchip.c
index ef89df1..744d561 100644
--- a/drivers/pwm/pwm-rockchip.c
+++ b/drivers/pwm/pwm-rockchip.c
@@ -191,6 +191,28 @@
return 0;
}
+static int rockchip_pwm_enable(struct pwm_chip *chip,
+ struct pwm_device *pwm,
+ bool enable,
+ enum pwm_polarity polarity)
+{
+ struct rockchip_pwm_chip *pc = to_rockchip_pwm_chip(chip);
+ int ret;
+
+ if (enable) {
+ ret = clk_enable(pc->clk);
+ if (ret)
+ return ret;
+ }
+
+ pc->data->set_enable(chip, pwm, enable, polarity);
+
+ if (!enable)
+ clk_disable(pc->clk);
+
+ return 0;
+}
+
static int rockchip_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm,
struct pwm_state *state)
{
@@ -207,22 +229,26 @@
return ret;
if (state->polarity != curstate.polarity && enabled) {
- pc->data->set_enable(chip, pwm, false, state->polarity);
+ ret = rockchip_pwm_enable(chip, pwm, false, state->polarity);
+ if (ret)
+ goto out;
enabled = false;
}
ret = rockchip_pwm_config(chip, pwm, state->duty_cycle, state->period);
if (ret) {
if (enabled != curstate.enabled)
- pc->data->set_enable(chip, pwm, !enabled,
- state->polarity);
-
+ rockchip_pwm_enable(chip, pwm, !enabled,
+ state->polarity);
goto out;
}
- if (state->enabled != enabled)
- pc->data->set_enable(chip, pwm, state->enabled,
- state->polarity);
+ if (state->enabled != enabled) {
+ ret = rockchip_pwm_enable(chip, pwm, state->enabled,
+ state->polarity);
+ if (ret)
+ goto out;
+ }
/*
* Update the state with the real hardware, which can differ a bit
diff --git a/drivers/rtc/rtc-tegra.c b/drivers/rtc/rtc-tegra.c
index 3853ba9..19e03d0 100644
--- a/drivers/rtc/rtc-tegra.c
+++ b/drivers/rtc/rtc-tegra.c
@@ -18,6 +18,7 @@
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include <linux/kernel.h>
+#include <linux/clk.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/slab.h>
@@ -59,6 +60,7 @@
struct platform_device *pdev;
struct rtc_device *rtc_dev;
void __iomem *rtc_base; /* NULL if not initialized. */
+ struct clk *clk;
int tegra_rtc_irq; /* alarm and periodic irq */
spinlock_t tegra_rtc_lock;
};
@@ -326,6 +328,14 @@
if (info->tegra_rtc_irq <= 0)
return -EBUSY;
+ info->clk = devm_clk_get(&pdev->dev, NULL);
+ if (IS_ERR(info->clk))
+ return PTR_ERR(info->clk);
+
+ ret = clk_prepare_enable(info->clk);
+ if (ret < 0)
+ return ret;
+
/* set context info. */
info->pdev = pdev;
spin_lock_init(&info->tegra_rtc_lock);
@@ -346,7 +356,7 @@
ret = PTR_ERR(info->rtc_dev);
dev_err(&pdev->dev, "Unable to register device (err=%d).\n",
ret);
- return ret;
+ goto disable_clk;
}
ret = devm_request_irq(&pdev->dev, info->tegra_rtc_irq,
@@ -356,12 +366,25 @@
dev_err(&pdev->dev,
"Unable to request interrupt for device (err=%d).\n",
ret);
- return ret;
+ goto disable_clk;
}
dev_notice(&pdev->dev, "Tegra internal Real Time Clock\n");
return 0;
+
+disable_clk:
+ clk_disable_unprepare(info->clk);
+ return ret;
+}
+
+static int tegra_rtc_remove(struct platform_device *pdev)
+{
+ struct tegra_rtc_info *info = platform_get_drvdata(pdev);
+
+ clk_disable_unprepare(info->clk);
+
+ return 0;
}
#ifdef CONFIG_PM_SLEEP
@@ -413,6 +436,7 @@
MODULE_ALIAS("platform:tegra_rtc");
static struct platform_driver tegra_rtc_driver = {
+ .remove = tegra_rtc_remove,
.shutdown = tegra_rtc_shutdown,
.driver = {
.name = "tegra_rtc",
diff --git a/drivers/scsi/qla2xxx/qla_os.c b/drivers/scsi/qla2xxx/qla_os.c
index 4f361d8..734e592 100644
--- a/drivers/scsi/qla2xxx/qla_os.c
+++ b/drivers/scsi/qla2xxx/qla_os.c
@@ -968,8 +968,13 @@
uint32_t qla2x00_isp_reg_stat(struct qla_hw_data *ha)
{
struct device_reg_24xx __iomem *reg = &ha->iobase->isp24;
+ struct device_reg_82xx __iomem *reg82 = &ha->iobase->isp82;
- return ((RD_REG_DWORD(®->host_status)) == ISP_REG_DISCONNECT);
+ if (IS_P3P_TYPE(ha))
+ return ((RD_REG_DWORD(®82->host_int)) == ISP_REG_DISCONNECT);
+ else
+ return ((RD_REG_DWORD(®->host_status)) ==
+ ISP_REG_DISCONNECT);
}
/**************************************************************************
diff --git a/drivers/scsi/sd.c b/drivers/scsi/sd.c
index b7889c7..c2ac982 100644
--- a/drivers/scsi/sd.c
+++ b/drivers/scsi/sd.c
@@ -1982,6 +1982,22 @@
#define READ_CAPACITY_RETRIES_ON_RESET 10
+/*
+ * Ensure that we don't overflow sector_t when CONFIG_LBDAF is not set
+ * and the reported logical block size is bigger than 512 bytes. Note
+ * that last_sector is a u64 and therefore logical_to_sectors() is not
+ * applicable.
+ */
+static bool sd_addressable_capacity(u64 lba, unsigned int sector_size)
+{
+ u64 last_sector = (lba + 1ULL) << (ilog2(sector_size) - 9);
+
+ if (sizeof(sector_t) == 4 && last_sector > U32_MAX)
+ return false;
+
+ return true;
+}
+
static int read_capacity_16(struct scsi_disk *sdkp, struct scsi_device *sdp,
unsigned char *buffer)
{
@@ -2047,7 +2063,7 @@
return -ENODEV;
}
- if ((sizeof(sdkp->capacity) == 4) && (lba >= 0xffffffffULL)) {
+ if (!sd_addressable_capacity(lba, sector_size)) {
sd_printk(KERN_ERR, sdkp, "Too big for this kernel. Use a "
"kernel compiled with support for large block "
"devices.\n");
@@ -2133,7 +2149,7 @@
return sector_size;
}
- if ((sizeof(sdkp->capacity) == 4) && (lba == 0xffffffff)) {
+ if (!sd_addressable_capacity(lba, sector_size)) {
sd_printk(KERN_ERR, sdkp, "Too big for this kernel. Use a "
"kernel compiled with support for large block "
"devices.\n");
@@ -2780,7 +2796,8 @@
q->limits.io_opt = logical_to_bytes(sdp, sdkp->opt_xfer_blocks);
rw_max = logical_to_sectors(sdp, sdkp->opt_xfer_blocks);
} else
- rw_max = BLK_DEF_MAX_SECTORS;
+ rw_max = min_not_zero(logical_to_sectors(sdp, dev_max),
+ (sector_t)BLK_DEF_MAX_SECTORS);
/* Combine with controller limits */
q->limits.max_sectors = min(rw_max, queue_max_hw_sectors(q));
diff --git a/drivers/scsi/sr.c b/drivers/scsi/sr.c
index bed2bbd..e635973 100644
--- a/drivers/scsi/sr.c
+++ b/drivers/scsi/sr.c
@@ -833,6 +833,7 @@
unsigned char *buffer;
struct scsi_mode_data data;
struct scsi_sense_hdr sshdr;
+ unsigned int ms_len = 128;
int rc, n;
static const char *loadmech[] =
@@ -859,10 +860,11 @@
scsi_test_unit_ready(cd->device, SR_TIMEOUT, MAX_RETRIES, &sshdr);
/* ask for mode page 0x2a */
- rc = scsi_mode_sense(cd->device, 0, 0x2a, buffer, 128,
+ rc = scsi_mode_sense(cd->device, 0, 0x2a, buffer, ms_len,
SR_TIMEOUT, 3, &data, NULL);
- if (!scsi_status_is_good(rc)) {
+ if (!scsi_status_is_good(rc) || data.length > ms_len ||
+ data.header_length + data.block_descriptor_length > data.length) {
/* failed, drive doesn't have capabilities mode page */
cd->cdi.speed = 1;
cd->cdi.mask |= (CDC_CD_R | CDC_CD_RW | CDC_DVD_R |
diff --git a/drivers/soc/qcom/Kconfig b/drivers/soc/qcom/Kconfig
index dbb7ebe..69e3032 100644
--- a/drivers/soc/qcom/Kconfig
+++ b/drivers/soc/qcom/Kconfig
@@ -645,3 +645,13 @@
This option enables driver for Data Capture and Compare engine. DCC
driver provides interface to configure DCC block and read back
captured data from DCC's internal SRAM.
+
+config QTI_RPM_STATS_LOG
+ bool "Qualcomm Technologies RPM Stats Driver"
+ depends on DEBUG_FS
+ default n
+ help
+ This option enables a driver which reads RPM messages from a shared
+ memory location. These messages provide statistical information about
+ the low power modes that RPM enters. The drivers outputs the message
+ via a debugfs node.
diff --git a/drivers/soc/qcom/Makefile b/drivers/soc/qcom/Makefile
index 060ac04..ba00ef10 100644
--- a/drivers/soc/qcom/Makefile
+++ b/drivers/soc/qcom/Makefile
@@ -68,3 +68,4 @@
obj-$(CONFIG_MSM_IDLE_STATS) += lpm-stats.o
obj-$(CONFIG_APSS_CORE_EA) += msm-core.o debug_core.o
obj-$(CONFIG_QCOM_DCC_V2) += dcc_v2.o
+obj-$(CONFIG_QTI_RPM_STATS_LOG) += rpm_stats.o
diff --git a/drivers/soc/qcom/dcc_v2.c b/drivers/soc/qcom/dcc_v2.c
index cb212b2..4d2f54d 100644
--- a/drivers/soc/qcom/dcc_v2.c
+++ b/drivers/soc/qcom/dcc_v2.c
@@ -121,6 +121,7 @@
struct mutex mutex;
void __iomem *ram_base;
uint32_t ram_size;
+ uint32_t ram_offset;
enum dcc_data_sink data_sink;
enum dcc_func_type func_type[DCC_MAX_LINK_LIST];
uint32_t ram_cfg;
@@ -517,9 +518,10 @@
/* 3. If in capture mode program DCC_RAM_CFG reg */
if (drvdata->func_type[list] == DCC_FUNC_TYPE_CAPTURE) {
- dcc_writel(drvdata, ram_cfg_base, DCC_LL_BASE(list));
- dcc_writel(drvdata, drvdata->ram_start,
- DCC_FD_BASE(list));
+ dcc_writel(drvdata, ram_cfg_base +
+ drvdata->ram_offset/4, DCC_LL_BASE(list));
+ dcc_writel(drvdata, drvdata->ram_start +
+ drvdata->ram_offset/4, DCC_FD_BASE(list));
dcc_writel(drvdata, 0, DCC_LL_TIMEOUT(list));
}
@@ -1342,6 +1344,11 @@
if (!drvdata->ram_base)
return -ENOMEM;
+ ret = of_property_read_u32(pdev->dev.of_node, "dcc-ram-offset",
+ &drvdata->ram_offset);
+ if (ret)
+ return -EINVAL;
+
drvdata->save_reg = of_property_read_bool(pdev->dev.of_node,
"qcom,save-reg");
diff --git a/drivers/soc/qcom/icnss.c b/drivers/soc/qcom/icnss.c
index 0b35caa..b759776 100644
--- a/drivers/soc/qcom/icnss.c
+++ b/drivers/soc/qcom/icnss.c
@@ -48,11 +48,6 @@
#include <soc/qcom/socinfo.h>
#include <soc/qcom/ramdump.h>
-#ifdef CONFIG_WCNSS_MEM_PRE_ALLOC
-#include <net/cnss_prealloc.h>
-#endif
-
-
#include "wlan_firmware_service_v01.h"
#ifdef CONFIG_ICNSS_DEBUG
@@ -1968,8 +1963,6 @@
if (ret < 0) {
icnss_pr_err("Driver probe failed: %d, state: 0x%lx\n",
ret, priv->state);
- wcnss_prealloc_check_memory_leak();
- wcnss_pre_alloc_reset();
goto out;
}
@@ -2099,8 +2092,6 @@
if (ret) {
icnss_pr_err("Driver probe failed: %d, state: 0x%lx\n",
ret, penv->state);
- wcnss_prealloc_check_memory_leak();
- wcnss_pre_alloc_reset();
goto power_off;
}
@@ -2126,8 +2117,6 @@
penv->ops->remove(&penv->pdev->dev);
clear_bit(ICNSS_DRIVER_PROBED, &penv->state);
- wcnss_prealloc_check_memory_leak();
- wcnss_pre_alloc_reset();
penv->ops = NULL;
@@ -2152,8 +2141,6 @@
penv->ops->remove(&priv->pdev->dev);
clear_bit(ICNSS_DRIVER_PROBED, &priv->state);
- wcnss_prealloc_check_memory_leak();
- wcnss_pre_alloc_reset();
icnss_hw_power_off(penv);
diff --git a/drivers/soc/qcom/lpm-stats.c b/drivers/soc/qcom/lpm-stats.c
index 74a86ec..ee68433 100644
--- a/drivers/soc/qcom/lpm-stats.c
+++ b/drivers/soc/qcom/lpm-stats.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012-2016, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-2017, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -425,7 +425,10 @@
uint64_t exit_time = 0;
/* Update time stats only when exit is preceded by enter */
- exit_time = stats->sleep_time;
+ if (stats->sleep_time < 0)
+ success = false;
+ else
+ exit_time = stats->sleep_time;
update_level_stats(&stats->time_stats[index], exit_time,
success);
}
diff --git a/drivers/soc/qcom/msm-core.c b/drivers/soc/qcom/msm-core.c
index de2a1ce..4ec791c 100644
--- a/drivers/soc/qcom/msm-core.c
+++ b/drivers/soc/qcom/msm-core.c
@@ -35,6 +35,7 @@
#include <linux/uaccess.h>
#include <linux/uio_driver.h>
#include <asm/smp_plat.h>
+#include <asm/cputype.h>
#include <stdbool.h>
#define CREATE_TRACE_POINTS
#include <trace/events/trace_msm_core.h>
@@ -46,7 +47,6 @@
#define DEFAULT_TEMP 40
#define DEFAULT_LOW_HYST_TEMP 10
#define DEFAULT_HIGH_HYST_TEMP 5
-#define CLUSTER_OFFSET_FOR_MPIDR 8
#define MAX_CORES_PER_CLUSTER 4
#define MAX_NUM_OF_CLUSTERS 2
#define NUM_OF_CORNERS 10
@@ -291,12 +291,11 @@
int cpu = -1;
struct cpu_activity_info *node;
struct cpu_static_info *sp, *clear_sp;
- int cpumask, cluster, mpidr;
+ int cpumask, cluster;
bool pdata_valid[NR_CPUS] = {0};
get_user(cpumask, &argp->cpumask);
get_user(cluster, &argp->cluster);
- mpidr = cluster << 8;
pr_debug("%s: cpumask %d, cluster: %d\n", __func__, cpumask,
cluster);
@@ -304,10 +303,12 @@
if (!(cpumask & 0x01))
continue;
- mpidr |= i;
for_each_possible_cpu(cpu) {
- if (cpu_logical_map(cpu) == mpidr)
- break;
+ if ((cpu_topology[cpu].core_id != i) &&
+ (cpu_topology[cpu].cluster_id != cluster))
+ continue;
+
+ break;
}
}
@@ -348,10 +349,9 @@
for (i = 0; i < MAX_CORES_PER_CLUSTER; i++, cpumask >>= 1) {
if (!(cpumask & 0x01))
continue;
- mpidr = (cluster << CLUSTER_OFFSET_FOR_MPIDR);
- mpidr |= i;
for_each_possible_cpu(cpu) {
- if (!(cpu_logical_map(cpu) == mpidr))
+ if (((cpu_topology[cpu].core_id != i) ||
+ (cpu_topology[cpu].cluster_id != cluster)))
continue;
node = &activity[cpu];
@@ -395,14 +395,12 @@
struct cpu_activity_info *node = NULL;
struct sched_params __user *argp = (struct sched_params __user *)arg;
int i, cpu = num_possible_cpus();
- int mpidr, cluster, cpumask;
+ int cluster, cpumask;
if (!argp)
return -EINVAL;
get_user(cluster, &argp->cluster);
- mpidr = (cluster << (MAX_CORES_PER_CLUSTER *
- MAX_NUM_OF_CLUSTERS));
get_user(cpumask, &argp->cpumask);
switch (cmd) {
@@ -414,8 +412,11 @@
case EA_VOLT:
for (i = 0; cpumask > 0; i++, cpumask >>= 1) {
for_each_possible_cpu(cpu) {
- if (cpu_logical_map(cpu) == (mpidr | i))
- break;
+ if (((cpu_topology[cpu].core_id != i) ||
+ (cpu_topology[cpu].cluster_id != cluster)))
+ continue;
+
+ break;
}
}
if (cpu >= num_possible_cpus())
diff --git a/drivers/soc/qcom/msm_bus/msm_bus_fabric_rpmh.c b/drivers/soc/qcom/msm_bus/msm_bus_fabric_rpmh.c
index 4167480..91d6349 100644
--- a/drivers/soc/qcom/msm_bus/msm_bus_fabric_rpmh.c
+++ b/drivers/soc/qcom/msm_bus/msm_bus_fabric_rpmh.c
@@ -311,7 +311,12 @@
if (list_empty(&cur_bcm_clist[i]))
continue;
list_for_each_entry(cur_bcm, &cur_bcm_clist[i], link) {
- if (cur_bcm->updated) {
+ if (cur_bcm->updated ||
+ (cur_bcm->node_vec[DUAL_CTX].vec_a == 0 &&
+ cur_bcm->node_vec[ACTIVE_CTX].vec_a == 0 &&
+ cur_bcm->node_vec[DUAL_CTX].vec_b == 0 &&
+ cur_bcm->node_vec[ACTIVE_CTX].vec_b == 0 &&
+ init_time == true)) {
if (last_tcs != -1 &&
list_is_last(&cur_bcm->link,
&cur_bcm_clist[i])) {
@@ -356,18 +361,19 @@
if (last_tcs != -1 &&
list_is_last(&cur_bcm->link,
&cur_bcm_clist[i])) {
- cmdlist_wake[k].data |=
+ cmdlist_wake[last_tcs].data |=
BCM_TCS_CMD_COMMIT_MASK;
- cmdlist_sleep[k].data |=
+ cmdlist_sleep[last_tcs].data |=
BCM_TCS_CMD_COMMIT_MASK;
- cmdlist_wake[k].complete = true;
- cmdlist_sleep[k].complete = true;
+ cmdlist_wake[last_tcs].complete = true;
+ cmdlist_sleep[last_tcs].complete = true;
idx++;
}
continue;
}
last_tcs = k;
n_sleep[idx]++;
+ n_wake[idx]++;
if (list_is_last(&cur_bcm->link,
&cur_bcm_clist[i])) {
commit = true;
@@ -584,7 +590,11 @@
cmdlist_wake, cmdlist_sleep, cur_bcm_clist);
ret = rpmh_invalidate(cur_mbox);
- ret = rpmh_write_passthru(cur_mbox, cur_rsc->rscdev->req_state,
+ if (cur_rsc->rscdev->req_state == RPMH_AWAKE_STATE)
+ ret = rpmh_write(cur_mbox, cur_rsc->rscdev->req_state,
+ cmdlist_active, cnt_active);
+ else
+ ret = rpmh_write_passthru(cur_mbox, cur_rsc->rscdev->req_state,
cmdlist_active, n_active);
ret = rpmh_write_passthru(cur_mbox, RPMH_WAKE_ONLY_STATE,
diff --git a/drivers/soc/qcom/rpm_stats.c b/drivers/soc/qcom/rpm_stats.c
new file mode 100644
index 0000000..15d8b1b
--- /dev/null
+++ b/drivers/soc/qcom/rpm_stats.c
@@ -0,0 +1,381 @@
+/* Copyright (c) 2011-2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * 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/debugfs.h>
+#include <linux/init.h>
+#include <linux/io.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/of.h>
+#include <linux/uaccess.h>
+#include <asm/arch_timer.h>
+
+#define RPM_STATS_NUM_REC 2
+#define MSM_ARCH_TIMER_FREQ 19200000
+
+#define GET_PDATA_OF_ATTR(attr) \
+ (container_of(attr, struct msm_rpmstats_kobj_attr, ka)->pd)
+
+struct msm_rpmstats_record {
+ char name[32];
+ u32 id;
+ u32 val;
+};
+
+struct msm_rpmstats_platform_data {
+ phys_addr_t phys_addr_base;
+ u32 phys_size;
+};
+
+struct msm_rpmstats_private_data {
+ void __iomem *reg_base;
+ u32 num_records;
+ u32 read_idx;
+ u32 len;
+ char buf[320];
+ struct msm_rpmstats_platform_data *platform_data;
+};
+
+struct msm_rpm_stats_data {
+ u32 stat_type;
+ u32 count;
+ u64 last_entered_at;
+ u64 last_exited_at;
+ u64 accumulated;
+};
+
+struct msm_rpmstats_kobj_attr {
+ struct kobj_attribute ka;
+ struct msm_rpmstats_platform_data *pd;
+};
+
+static inline u64 get_time_in_sec(u64 counter)
+{
+ do_div(counter, MSM_ARCH_TIMER_FREQ);
+
+ return counter;
+}
+
+static inline u64 get_time_in_msec(u64 counter)
+{
+ do_div(counter, MSM_ARCH_TIMER_FREQ);
+ counter *= MSEC_PER_SEC;
+
+ return counter;
+}
+
+static inline int msm_rpmstats_append_data_to_buf(char *buf,
+ struct msm_rpm_stats_data *data, int buflength)
+{
+ char stat_type[5];
+ u64 time_in_last_mode;
+ u64 time_since_last_mode;
+ u64 actual_last_sleep;
+
+ stat_type[4] = 0;
+ memcpy(stat_type, &data->stat_type, sizeof(u32));
+
+ time_in_last_mode = data->last_exited_at - data->last_entered_at;
+ time_in_last_mode = get_time_in_msec(time_in_last_mode);
+ time_since_last_mode = arch_counter_get_cntvct() - data->last_exited_at;
+ time_since_last_mode = get_time_in_sec(time_since_last_mode);
+ actual_last_sleep = get_time_in_msec(data->accumulated);
+
+ return snprintf(buf, buflength,
+ "RPM Mode:%s\n\t count:%d\ntime in last mode(msec):%llu\n"
+ "time since last mode(sec):%llu\nactual last sleep(msec):%llu\n\n",
+ stat_type, data->count, time_in_last_mode,
+ time_since_last_mode, actual_last_sleep);
+}
+
+static inline u32 msm_rpmstats_read_long_register(void __iomem *regbase,
+ int index, int offset)
+{
+ return readl_relaxed(regbase + offset +
+ index * sizeof(struct msm_rpm_stats_data));
+}
+
+static inline u64 msm_rpmstats_read_quad_register(void __iomem *regbase,
+ int index, int offset)
+{
+ u64 dst;
+
+ memcpy_fromio(&dst,
+ regbase + offset + index * sizeof(struct msm_rpm_stats_data),
+ 8);
+ return dst;
+}
+
+static inline int msm_rpmstats_copy_stats(
+ struct msm_rpmstats_private_data *prvdata)
+{
+ void __iomem *reg;
+ struct msm_rpm_stats_data data;
+ int i, length;
+
+ reg = prvdata->reg_base;
+
+ for (i = 0, length = 0; i < prvdata->num_records; i++) {
+ data.stat_type = msm_rpmstats_read_long_register(reg, i,
+ offsetof(struct msm_rpm_stats_data,
+ stat_type));
+ data.count = msm_rpmstats_read_long_register(reg, i,
+ offsetof(struct msm_rpm_stats_data, count));
+ data.last_entered_at = msm_rpmstats_read_quad_register(reg,
+ i, offsetof(struct msm_rpm_stats_data,
+ last_entered_at));
+ data.last_exited_at = msm_rpmstats_read_quad_register(reg,
+ i, offsetof(struct msm_rpm_stats_data,
+ last_exited_at));
+ data.accumulated = msm_rpmstats_read_quad_register(reg,
+ i, offsetof(struct msm_rpm_stats_data,
+ accumulated));
+ length += msm_rpmstats_append_data_to_buf(prvdata->buf + length,
+ &data, sizeof(prvdata->buf) - length);
+ prvdata->read_idx++;
+ }
+
+ return length;
+}
+
+static inline unsigned long msm_rpmstats_read_register(void __iomem *regbase,
+ int index, int offset)
+{
+ return readl_relaxed(regbase + index * 12 + (offset + 1) * 4);
+}
+
+static ssize_t msm_rpmstats_file_read(struct file *file, char __user *bufu,
+ size_t count, loff_t *ppos)
+{
+ struct msm_rpmstats_private_data *prvdata;
+
+ prvdata = file->private_data;
+ if (!prvdata)
+ return -EINVAL;
+
+ if (!bufu || count == 0)
+ return -EINVAL;
+
+ if ((*ppos >= prvdata->len) &&
+ (prvdata->read_idx < prvdata->num_records)) {
+ prvdata->len = msm_rpmstats_copy_stats(prvdata);
+ *ppos = 0;
+ }
+
+ return simple_read_from_buffer(bufu, count, ppos,
+ prvdata->buf, prvdata->len);
+}
+
+static int msm_rpmstats_file_open(struct inode *inode, struct file *file)
+{
+ struct msm_rpmstats_private_data *prvdata;
+ struct msm_rpmstats_platform_data *pdata;
+
+ pdata = inode->i_private;
+
+ file->private_data = kzalloc(sizeof(*prvdata), GFP_KERNEL);
+ if (!file->private_data)
+ return -ENOMEM;
+
+ prvdata = file->private_data;
+
+ prvdata->reg_base = ioremap_nocache(pdata->phys_addr_base,
+ pdata->phys_size);
+ if (!prvdata->reg_base) {
+ kfree(file->private_data);
+ prvdata = NULL;
+ pr_err("%s: ERROR could not ioremap start=%pa, len=%u\n",
+ __func__, &pdata->phys_addr_base,
+ pdata->phys_size);
+ return -EBUSY;
+ }
+
+ prvdata->read_idx = prvdata->len = 0;
+ prvdata->platform_data = pdata;
+ prvdata->num_records = RPM_STATS_NUM_REC;
+
+ return 0;
+}
+
+static int msm_rpmstats_file_close(struct inode *inode, struct file *file)
+{
+ struct msm_rpmstats_private_data *private = file->private_data;
+
+ if (private->reg_base)
+ iounmap(private->reg_base);
+ kfree(file->private_data);
+
+ return 0;
+}
+
+static const struct file_operations msm_rpmstats_fops = {
+ .owner = THIS_MODULE,
+ .open = msm_rpmstats_file_open,
+ .read = msm_rpmstats_file_read,
+ .release = msm_rpmstats_file_close,
+ .llseek = no_llseek,
+};
+
+static ssize_t rpmstats_show(struct kobject *kobj,
+ struct kobj_attribute *attr, char *buf)
+{
+ struct msm_rpmstats_private_data *prvdata = NULL;
+ struct msm_rpmstats_platform_data *pdata = NULL;
+
+ pdata = GET_PDATA_OF_ATTR(attr);
+
+ prvdata =
+ kmalloc(sizeof(*prvdata), GFP_KERNEL);
+ if (!prvdata)
+ return -ENOMEM;
+
+ prvdata->reg_base = ioremap_nocache(pdata->phys_addr_base,
+ pdata->phys_size);
+ if (!prvdata->reg_base) {
+ kfree(prvdata);
+ pr_err("%s: ERROR could not ioremap start=%pa, len=%u\n",
+ __func__, &pdata->phys_addr_base,
+ pdata->phys_size);
+ return -EBUSY;
+ }
+
+ prvdata->read_idx = prvdata->len = 0;
+ prvdata->platform_data = pdata;
+ prvdata->num_records = RPM_STATS_NUM_REC;
+
+ if (prvdata->read_idx < prvdata->num_records)
+ prvdata->len = msm_rpmstats_copy_stats(prvdata);
+
+ return snprintf(buf, prvdata->len, prvdata->buf);
+}
+
+static int msm_rpmstats_create_sysfs(struct msm_rpmstats_platform_data *pd)
+{
+ struct kobject *module_kobj = NULL;
+ struct kobject *rpmstats_kobj = NULL;
+ struct msm_rpmstats_kobj_attr *rpms_ka = NULL;
+ int ret = 0;
+
+ module_kobj = kset_find_obj(module_kset, KBUILD_MODNAME);
+ if (!module_kobj) {
+ pr_err("%s: Cannot find module_kset\n", __func__);
+ return -ENODEV;
+ }
+
+ rpmstats_kobj = kobject_create_and_add("rpmstats", module_kobj);
+ if (!rpmstats_kobj) {
+ pr_err("%s: Cannot create rpmstats kobject\n", __func__);
+ ret = -ENOMEM;
+ goto fail;
+ }
+
+ rpms_ka = kzalloc(sizeof(*rpms_ka), GFP_KERNEL);
+ if (!rpms_ka) {
+ kobject_put(rpmstats_kobj);
+ ret = -ENOMEM;
+ goto fail;
+ }
+
+ sysfs_attr_init(&rpms_ka->ka.attr);
+ rpms_ka->pd = pd;
+ rpms_ka->ka.attr.mode = 0444;
+ rpms_ka->ka.attr.name = "stats";
+ rpms_ka->ka.show = rpmstats_show;
+ rpms_ka->ka.store = NULL;
+
+ ret = sysfs_create_file(rpmstats_kobj, &rpms_ka->ka.attr);
+
+fail:
+ return ret;
+}
+
+static int msm_rpmstats_probe(struct platform_device *pdev)
+{
+ struct dentry *dent = NULL;
+ struct msm_rpmstats_platform_data *pdata;
+ struct msm_rpmstats_platform_data *pd;
+ struct resource *res = NULL, *offset = NULL;
+ u32 offset_addr = 0;
+ void __iomem *phys_ptr = NULL;
+
+ pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL);
+ if (!pdata)
+ return -ENOMEM;
+
+ res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
+ "phys_addr_base");
+ if (!res)
+ return -EINVAL;
+
+ offset = platform_get_resource_byname(pdev, IORESOURCE_MEM,
+ "offset_addr");
+ if (offset) {
+ /* Remap the rpm-stats pointer */
+ phys_ptr = ioremap_nocache(offset->start, SZ_4);
+ if (!phys_ptr) {
+ pr_err("%s: Failed to ioremap address: %x\n",
+ __func__, offset_addr);
+ return -ENODEV;
+ }
+ offset_addr = readl_relaxed(phys_ptr);
+ iounmap(phys_ptr);
+ }
+
+ pdata->phys_addr_base = res->start + offset_addr;
+ pdata->phys_size = resource_size(res);
+
+ if (pdev->dev.platform_data)
+ pd = pdev->dev.platform_data;
+
+ dent = debugfs_create_file("rpm_stats", 0444, NULL,
+ pdata, &msm_rpmstats_fops);
+ if (!dent) {
+ pr_err("%s: ERROR rpm_stats debugfs_create_file fail\n",
+ __func__);
+ return -ENOMEM;
+ }
+
+ msm_rpmstats_create_sysfs(pdata);
+
+ platform_set_drvdata(pdev, dent);
+ return 0;
+}
+
+static int msm_rpmstats_remove(struct platform_device *pdev)
+{
+ struct dentry *dent;
+
+ dent = platform_get_drvdata(pdev);
+ debugfs_remove(dent);
+ platform_set_drvdata(pdev, NULL);
+
+ return 0;
+}
+
+static const struct of_device_id rpm_stats_table[] = {
+ { .compatible = "qcom,rpm-stats" },
+ { },
+};
+
+static struct platform_driver msm_rpmstats_driver = {
+ .probe = msm_rpmstats_probe,
+ .remove = msm_rpmstats_remove,
+ .driver = {
+ .name = "msm_rpm_stat",
+ .owner = THIS_MODULE,
+ .of_match_table = rpm_stats_table,
+ },
+};
+builtin_platform_driver(msm_rpmstats_driver);
diff --git a/drivers/soc/qcom/rpmh.c b/drivers/soc/qcom/rpmh.c
index 1635bab..e30c159 100644
--- a/drivers/soc/qcom/rpmh.c
+++ b/drivers/soc/qcom/rpmh.c
@@ -88,8 +88,9 @@
struct rpmh_mbox *rpm = rc->rpmh;
struct rpmh_msg *msg = NULL;
int pos;
+ unsigned long flags;
- spin_lock(&rpm->lock);
+ spin_lock_irqsave(&rpm->lock, flags);
pos = find_first_zero_bit(rpm->fast_req, RPMH_MAX_FAST_RES);
if (pos != RPMH_MAX_FAST_RES) {
bitmap_set(rpm->fast_req, pos, 1);
@@ -98,7 +99,7 @@
msg->bit = pos;
msg->rc = rc;
}
- spin_unlock(&rpm->lock);
+ spin_unlock_irqrestore(&rpm->lock, flags);
return msg;
}
@@ -108,7 +109,7 @@
struct rpmh_msg *rpm_msg = container_of(msg, struct rpmh_msg, msg);
atomic_dec(rpm_msg->wait_count);
- wake_up_interruptible(rpm_msg->waitq);
+ wake_up(rpm_msg->waitq);
}
static void rpmh_tx_done(struct mbox_client *cl, void *msg, int r)
@@ -117,6 +118,7 @@
struct rpmh_mbox *rpm = rpm_msg->rc->rpmh;
atomic_t *wc = rpm_msg->wait_count;
wait_queue_head_t *waitq = rpm_msg->waitq;
+ unsigned long flags;
rpm_msg->err = r;
@@ -143,15 +145,15 @@
/* If we allocated the pool, set it as available */
if (rpm_msg->bit >= 0 && rpm_msg->bit != RPMH_MAX_FAST_RES) {
- spin_lock(&rpm->lock);
+ spin_lock_irqsave(&rpm->lock, flags);
bitmap_clear(rpm->fast_req, rpm_msg->bit, 1);
- spin_unlock(&rpm->lock);
+ spin_unlock_irqrestore(&rpm->lock, flags);
}
/* Signal the blocking thread we are done */
if (waitq) {
atomic_dec(wc);
- wake_up_interruptible(waitq);
+ wake_up(waitq);
}
}
@@ -174,8 +176,9 @@
{
struct rpmh_req *req;
struct rpmh_mbox *rpm = rc->rpmh;
+ unsigned long flags;
- spin_lock(&rpm->lock);
+ spin_lock_irqsave(&rpm->lock, flags);
req = __find_req(rc, cmd->addr);
if (req)
goto existing;
@@ -210,7 +213,7 @@
unlock:
rpm->dirty = true;
- spin_unlock(&rpm->lock);
+ spin_unlock_irqrestore(&rpm->lock, flags);
return req;
}
@@ -329,9 +332,7 @@
if (ret < 0)
return ret;
- ret = wait_event_interruptible(waitq, atomic_read(&wait_count) == 0);
- if (ret)
- return ret;
+ wait_event(waitq, atomic_read(&wait_count) == 0);
return rpm_msg.err;
}
@@ -423,13 +424,11 @@
rpm_msg.msg.num_payload = n;
ret = __rpmh_write(rc, state, &rpm_msg);
- if (ret < 0)
- return ret;
-
- ret = wait_event_interruptible(waitq, atomic_read(&wait_count) == 0);
if (ret)
return ret;
+ wait_event(waitq, atomic_read(&wait_count) == 0);
+
return rpm_msg.err;
}
EXPORT_SYMBOL(rpmh_write);
@@ -494,8 +493,6 @@
rpm_msg[i] = __get_rpmh_msg_async(rc, state, cmd, n[i]);
if (IS_ERR_OR_NULL(rpm_msg[i]))
return PTR_ERR(rpm_msg[i]);
- rpm_msg[i]->waitq = &waitq;
- rpm_msg[i]->wait_count = &wait_count;
cmd += n[i];
}
@@ -504,16 +501,18 @@
might_sleep();
atomic_set(&wait_count, count);
for (i = 0; i < count; i++) {
+ rpm_msg[i]->waitq = &waitq;
+ rpm_msg[i]->wait_count = &wait_count;
/* Bypass caching and write to mailbox directly */
ret = mbox_send_message(rc->chan, &rpm_msg[i]->msg);
if (ret < 0)
return ret;
}
- return wait_event_interruptible(waitq,
- atomic_read(&wait_count) == 0);
+ wait_event(waitq, atomic_read(&wait_count) == 0);
} else {
/* Send Sleep requests to the controller, expect no response */
for (i = 0; i < count; i++) {
+ rpm_msg[i]->waitq = NULL;
ret = mbox_send_controller_data(rc->chan,
&rpm_msg[i]->msg);
/* Clean up our call by spoofing tx_done */
@@ -521,6 +520,8 @@
}
return 0;
}
+
+ return 0;
}
EXPORT_SYMBOL(rpmh_write_passthru);
@@ -568,6 +569,7 @@
{
DEFINE_RPMH_MSG_ONSTACK(rc, 0, NULL, NULL, rpm_msg);
struct rpmh_mbox *rpm;
+ unsigned long flags;
if (IS_ERR_OR_NULL(rc))
return -EINVAL;
@@ -579,9 +581,9 @@
rpm_msg.msg.invalidate = true;
rpm_msg.msg.is_complete = false;
- spin_lock(&rpm->lock);
+ spin_lock_irqsave(&rpm->lock, flags);
rpm->dirty = true;
- spin_unlock(&rpm->lock);
+ spin_unlock_irqrestore(&rpm->lock, flags);
return mbox_send_controller_data(rc->chan, &rpm_msg.msg);
}
@@ -623,9 +625,7 @@
return ret;
/* Wait until the response is received from RPMH */
- ret = wait_event_interruptible(waitq, atomic_read(&wait_count) == 0);
- if (ret)
- return ret;
+ wait_event(waitq, atomic_read(&wait_count) == 0);
/* Read the data back from the tcs_mbox_msg structrure */
*resp = rpm_msg.cmd[0].data;
@@ -671,6 +671,7 @@
struct rpmh_req *p;
struct rpmh_mbox *rpm = rc->rpmh;
int ret;
+ unsigned long flags;
if (IS_ERR_OR_NULL(rc))
return -EINVAL;
@@ -681,13 +682,13 @@
if (!mbox_controller_is_idle(rc->chan))
return -EBUSY;
- spin_lock(&rpm->lock);
+ spin_lock_irqsave(&rpm->lock, flags);
if (!rpm->dirty) {
pr_debug("Skipping flush, TCS has latest data.\n");
- spin_unlock(&rpm->lock);
+ spin_unlock_irqrestore(&rpm->lock, flags);
return 0;
}
- spin_unlock(&rpm->lock);
+ spin_unlock_irqrestore(&rpm->lock, flags);
/*
* Nobody else should be calling this function other than sleep,
@@ -708,9 +709,9 @@
return ret;
}
- spin_lock(&rpm->lock);
+ spin_lock_irqsave(&rpm->lock, flags);
rpm->dirty = false;
- spin_unlock(&rpm->lock);
+ spin_unlock_irqrestore(&rpm->lock, flags);
return 0;
}
diff --git a/drivers/soc/qcom/socinfo.c b/drivers/soc/qcom/socinfo.c
index 55fa5d2..119ede3 100644
--- a/drivers/soc/qcom/socinfo.c
+++ b/drivers/soc/qcom/socinfo.c
@@ -550,6 +550,9 @@
/* Bat ID */
[328] = {MSM_CPU_SDM830, "SDM830"},
+ /* sdxpoorwills ID */
+ [334] = {SDX_CPU_SDXPOORWILLS, "SDXPOORWILLS"},
+
/* Uninitialized IDs are not known to run Linux.
* MSM_CPU_UNKNOWN is set to 0 to ensure these IDs are
* considered as unknown CPU.
@@ -1256,6 +1259,10 @@
dummy_socinfo.id = 328;
strlcpy(dummy_socinfo.build_id, "sdm830 - ",
sizeof(dummy_socinfo.build_id));
+ } else if (early_machine_is_sdxpoorwills()) {
+ dummy_socinfo.id = 334;
+ strlcpy(dummy_socinfo.build_id, "sdxpoorwills - ",
+ sizeof(dummy_socinfo.build_id));
}
strlcat(dummy_socinfo.build_id, "Dummy socinfo",
diff --git a/drivers/soc/qcom/subsys-pil-tz.c b/drivers/soc/qcom/subsys-pil-tz.c
index 272e70a..6ff39de 100644
--- a/drivers/soc/qcom/subsys-pil-tz.c
+++ b/drivers/soc/qcom/subsys-pil-tz.c
@@ -738,10 +738,21 @@
desc.args[0] = proc = d->pas_id;
desc.arginfo = SCM_ARGS(1);
+ if (d->bus_client) {
+ rc = msm_bus_scale_client_update_request(d->bus_client, 1);
+ if (rc) {
+ dev_err(pil->dev, "bandwidth request failed(rc:%d)\n",
+ rc);
+ return rc;
+ }
+ } else
+ WARN(d->enable_bus_scaling, "Bus scaling not set up for %s!\n",
+ d->subsys_desc.name);
+
rc = enable_regulators(d, pil->dev, d->proxy_regs,
d->proxy_reg_count, true);
if (rc)
- return rc;
+ goto err_regulators;
rc = prepare_enable_clocks(pil->dev, d->proxy_clks,
d->proxy_clk_count);
@@ -759,6 +770,11 @@
disable_unprepare_clocks(d->proxy_clks, d->proxy_clk_count);
disable_regulators(d, d->proxy_regs, d->proxy_reg_count, false);
+ if (d->bus_client)
+ msm_bus_scale_client_update_request(d->bus_client, 0);
+ else
+ WARN(d->enable_bus_scaling, "Bus scaling not set up for %s!\n",
+ d->subsys_desc.name);
if (rc)
return rc;
@@ -767,8 +783,15 @@
disable_regulators(d, d->regs, d->reg_count, false);
return scm_ret;
+
err_clks:
disable_regulators(d, d->proxy_regs, d->proxy_reg_count, false);
+err_regulators:
+ if (d->bus_client)
+ msm_bus_scale_client_update_request(d->bus_client, 0);
+ else
+ WARN(d->enable_bus_scaling, "Bus scaling not set up for %s!\n",
+ d->subsys_desc.name);
return rc;
}
diff --git a/drivers/soc/qcom/watchdog_v2.c b/drivers/soc/qcom/watchdog_v2.c
index f3d6209..7a784aa 100644
--- a/drivers/soc/qcom/watchdog_v2.c
+++ b/drivers/soc/qcom/watchdog_v2.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012-2016, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-2017, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -30,6 +30,7 @@
#include <soc/qcom/scm.h>
#include <soc/qcom/memory_dump.h>
#include <soc/qcom/watchdog.h>
+#include <linux/dma-mapping.h>
#define MODULE_NAME "msm_watchdog"
#define WDT0_ACCSCSSNBARK_INT 0
@@ -49,6 +50,7 @@
#define SCM_SET_REGSAVE_CMD 0x2
#define SCM_SVC_SEC_WDOG_DIS 0x7
#define MAX_CPU_CTX_SIZE 2048
+#define MAX_CPU_SCANDUMP_SIZE 0x10000
static struct msm_watchdog_data *wdog_data;
@@ -557,6 +559,49 @@
return;
}
+static void configure_scandump(struct msm_watchdog_data *wdog_dd)
+{
+ int ret;
+ struct msm_dump_entry dump_entry;
+ struct msm_dump_data *cpu_data;
+ int cpu;
+ static dma_addr_t dump_addr;
+ static void *dump_vaddr;
+
+ for_each_cpu(cpu, cpu_present_mask) {
+ cpu_data = devm_kzalloc(wdog_dd->dev,
+ sizeof(struct msm_dump_data),
+ GFP_KERNEL);
+ if (!cpu_data)
+ continue;
+
+ dump_vaddr = (void *) dma_alloc_coherent(wdog_dd->dev,
+ MAX_CPU_SCANDUMP_SIZE,
+ &dump_addr,
+ GFP_KERNEL);
+ if (!dump_vaddr) {
+ dev_err(wdog_dd->dev, "Couldn't get memory for dump\n");
+ continue;
+ }
+ memset(dump_vaddr, 0x0, MAX_CPU_SCANDUMP_SIZE);
+
+ cpu_data->addr = dump_addr;
+ cpu_data->len = MAX_CPU_SCANDUMP_SIZE;
+ dump_entry.id = MSM_DUMP_DATA_SCANDUMP_PER_CPU + cpu;
+ dump_entry.addr = virt_to_phys(cpu_data);
+ ret = msm_dump_data_register(MSM_DUMP_TABLE_APPS,
+ &dump_entry);
+ if (ret) {
+ dev_err(wdog_dd->dev, "Dump setup failed, id = %d\n",
+ MSM_DUMP_DATA_SCANDUMP_PER_CPU + cpu);
+ dma_free_coherent(wdog_dd->dev, MAX_CPU_SCANDUMP_SIZE,
+ dump_vaddr,
+ dump_addr);
+ devm_kfree(wdog_dd->dev, cpu_data);
+ }
+ }
+}
+
static int init_watchdog_sysfs(struct msm_watchdog_data *wdog_dd)
{
int error = 0;
@@ -617,6 +662,7 @@
delay_time = msecs_to_jiffies(wdog_dd->pet_time);
wdog_dd->min_slack_ticks = UINT_MAX;
wdog_dd->min_slack_ns = ULLONG_MAX;
+ configure_scandump(wdog_dd);
configure_bark_dump(wdog_dd);
timeout = (wdog_dd->bark_time * WDT_HZ)/1000;
__raw_writel(timeout, wdog_dd->base + WDT0_BARK_TIME);
diff --git a/drivers/soundwire/swr-wcd-ctrl.c b/drivers/soundwire/swr-wcd-ctrl.c
index 7e33e8b..ce2a367 100644
--- a/drivers/soundwire/swr-wcd-ctrl.c
+++ b/drivers/soundwire/swr-wcd-ctrl.c
@@ -524,7 +524,7 @@
{
struct swr_mstr_ctrl *swrm = swr_get_ctrl_data(master);
int ret = 0;
- int val = 0;
+ int val;
u8 *reg_val = (u8 *)buf;
if (!swrm) {
@@ -538,7 +538,9 @@
else
val = swrm->read(swrm->handle, reg_addr);
- *reg_val = (u8)val;
+ if (!ret)
+ *reg_val = (u8)val;
+
pm_runtime_mark_last_busy(&swrm->pdev->dev);
return ret;
diff --git a/drivers/staging/android/ashmem.c b/drivers/staging/android/ashmem.c
index 9435dc5..eb41e84 100644
--- a/drivers/staging/android/ashmem.c
+++ b/drivers/staging/android/ashmem.c
@@ -766,10 +766,12 @@
break;
case ASHMEM_SET_SIZE:
ret = -EINVAL;
+ mutex_lock(&ashmem_mutex);
if (!asma->file) {
ret = 0;
asma->size = (size_t)arg;
}
+ mutex_unlock(&ashmem_mutex);
break;
case ASHMEM_GET_SIZE:
ret = asma->size;
diff --git a/drivers/target/iscsi/iscsi_target_parameters.c b/drivers/target/iscsi/iscsi_target_parameters.c
index 0efa80b..4a073339a 100644
--- a/drivers/target/iscsi/iscsi_target_parameters.c
+++ b/drivers/target/iscsi/iscsi_target_parameters.c
@@ -782,22 +782,6 @@
if (!strcmp(param->name, MAXRECVDATASEGMENTLENGTH))
SET_PSTATE_REPLY_OPTIONAL(param);
/*
- * The GlobalSAN iSCSI Initiator for MacOSX does
- * not respond to MaxBurstLength, FirstBurstLength,
- * DefaultTime2Wait or DefaultTime2Retain parameter keys.
- * So, we set them to 'reply optional' here, and assume the
- * the defaults from iscsi_parameters.h if the initiator
- * is not RFC compliant and the keys are not negotiated.
- */
- if (!strcmp(param->name, MAXBURSTLENGTH))
- SET_PSTATE_REPLY_OPTIONAL(param);
- if (!strcmp(param->name, FIRSTBURSTLENGTH))
- SET_PSTATE_REPLY_OPTIONAL(param);
- if (!strcmp(param->name, DEFAULTTIME2WAIT))
- SET_PSTATE_REPLY_OPTIONAL(param);
- if (!strcmp(param->name, DEFAULTTIME2RETAIN))
- SET_PSTATE_REPLY_OPTIONAL(param);
- /*
* Required for gPXE iSCSI boot client
*/
if (!strcmp(param->name, MAXCONNECTIONS))
diff --git a/drivers/target/iscsi/iscsi_target_util.c b/drivers/target/iscsi/iscsi_target_util.c
index 1f38177..da5a5fc 100644
--- a/drivers/target/iscsi/iscsi_target_util.c
+++ b/drivers/target/iscsi/iscsi_target_util.c
@@ -735,21 +735,23 @@
{
struct se_cmd *se_cmd = NULL;
int rc;
+ bool op_scsi = false;
/*
* Determine if a struct se_cmd is associated with
* this struct iscsi_cmd.
*/
switch (cmd->iscsi_opcode) {
case ISCSI_OP_SCSI_CMD:
- se_cmd = &cmd->se_cmd;
- __iscsit_free_cmd(cmd, true, shutdown);
+ op_scsi = true;
/*
* Fallthrough
*/
case ISCSI_OP_SCSI_TMFUNC:
- rc = transport_generic_free_cmd(&cmd->se_cmd, shutdown);
- if (!rc && shutdown && se_cmd && se_cmd->se_sess) {
- __iscsit_free_cmd(cmd, true, shutdown);
+ se_cmd = &cmd->se_cmd;
+ __iscsit_free_cmd(cmd, op_scsi, shutdown);
+ rc = transport_generic_free_cmd(se_cmd, shutdown);
+ if (!rc && shutdown && se_cmd->se_sess) {
+ __iscsit_free_cmd(cmd, op_scsi, shutdown);
target_put_sess_cmd(se_cmd);
}
break;
diff --git a/drivers/target/target_core_fabric_configfs.c b/drivers/target/target_core_fabric_configfs.c
index 31a096a..6e456de 100644
--- a/drivers/target/target_core_fabric_configfs.c
+++ b/drivers/target/target_core_fabric_configfs.c
@@ -92,6 +92,11 @@
pr_err("Source se_lun->lun_se_dev does not exist\n");
return -EINVAL;
}
+ if (lun->lun_shutdown) {
+ pr_err("Unable to create mappedlun symlink because"
+ " lun->lun_shutdown=true\n");
+ return -EINVAL;
+ }
se_tpg = lun->lun_tpg;
nacl_ci = &lun_acl_ci->ci_parent->ci_group->cg_item;
diff --git a/drivers/target/target_core_tpg.c b/drivers/target/target_core_tpg.c
index 2744251..1949f50 100644
--- a/drivers/target/target_core_tpg.c
+++ b/drivers/target/target_core_tpg.c
@@ -640,6 +640,8 @@
*/
struct se_device *dev = rcu_dereference_raw(lun->lun_se_dev);
+ lun->lun_shutdown = true;
+
core_clear_lun_from_tpg(lun, tpg);
/*
* Wait for any active I/O references to percpu se_lun->lun_ref to
@@ -661,6 +663,8 @@
}
if (!(dev->se_hba->hba_flags & HBA_FLAGS_INTERNAL_USE))
hlist_del_rcu(&lun->link);
+
+ lun->lun_shutdown = false;
mutex_unlock(&tpg->tpg_lun_mutex);
percpu_ref_exit(&lun->lun_ref);
diff --git a/drivers/target/target_core_user.c b/drivers/target/target_core_user.c
index 70c143a..1a83456 100644
--- a/drivers/target/target_core_user.c
+++ b/drivers/target/target_core_user.c
@@ -306,24 +306,50 @@
DATA_BLOCK_BITS);
}
-static void gather_data_area(struct tcmu_dev *udev, unsigned long *cmd_bitmap,
- struct scatterlist *data_sg, unsigned int data_nents)
+static void gather_data_area(struct tcmu_dev *udev, struct tcmu_cmd *cmd,
+ bool bidi)
{
+ struct se_cmd *se_cmd = cmd->se_cmd;
int i, block;
int block_remaining = 0;
void *from, *to;
size_t copy_bytes, from_offset;
- struct scatterlist *sg;
+ struct scatterlist *sg, *data_sg;
+ unsigned int data_nents;
+ DECLARE_BITMAP(bitmap, DATA_BLOCK_BITS);
+
+ bitmap_copy(bitmap, cmd->data_bitmap, DATA_BLOCK_BITS);
+
+ if (!bidi) {
+ data_sg = se_cmd->t_data_sg;
+ data_nents = se_cmd->t_data_nents;
+ } else {
+ uint32_t count;
+
+ /*
+ * For bidi case, the first count blocks are for Data-Out
+ * buffer blocks, and before gathering the Data-In buffer
+ * the Data-Out buffer blocks should be discarded.
+ */
+ count = DIV_ROUND_UP(se_cmd->data_length, DATA_BLOCK_SIZE);
+ while (count--) {
+ block = find_first_bit(bitmap, DATA_BLOCK_BITS);
+ clear_bit(block, bitmap);
+ }
+
+ data_sg = se_cmd->t_bidi_data_sg;
+ data_nents = se_cmd->t_bidi_data_nents;
+ }
for_each_sg(data_sg, sg, data_nents, i) {
int sg_remaining = sg->length;
to = kmap_atomic(sg_page(sg)) + sg->offset;
while (sg_remaining > 0) {
if (block_remaining == 0) {
- block = find_first_bit(cmd_bitmap,
+ block = find_first_bit(bitmap,
DATA_BLOCK_BITS);
block_remaining = DATA_BLOCK_SIZE;
- clear_bit(block, cmd_bitmap);
+ clear_bit(block, bitmap);
}
copy_bytes = min_t(size_t, sg_remaining,
block_remaining);
@@ -389,6 +415,27 @@
return true;
}
+static inline size_t tcmu_cmd_get_data_length(struct tcmu_cmd *tcmu_cmd)
+{
+ struct se_cmd *se_cmd = tcmu_cmd->se_cmd;
+ size_t data_length = round_up(se_cmd->data_length, DATA_BLOCK_SIZE);
+
+ if (se_cmd->se_cmd_flags & SCF_BIDI) {
+ BUG_ON(!(se_cmd->t_bidi_data_sg && se_cmd->t_bidi_data_nents));
+ data_length += round_up(se_cmd->t_bidi_data_sg->length,
+ DATA_BLOCK_SIZE);
+ }
+
+ return data_length;
+}
+
+static inline uint32_t tcmu_cmd_get_block_cnt(struct tcmu_cmd *tcmu_cmd)
+{
+ size_t data_length = tcmu_cmd_get_data_length(tcmu_cmd);
+
+ return data_length / DATA_BLOCK_SIZE;
+}
+
static sense_reason_t
tcmu_queue_cmd_ring(struct tcmu_cmd *tcmu_cmd)
{
@@ -402,7 +449,7 @@
uint32_t cmd_head;
uint64_t cdb_off;
bool copy_to_data_area;
- size_t data_length;
+ size_t data_length = tcmu_cmd_get_data_length(tcmu_cmd);
DECLARE_BITMAP(old_bitmap, DATA_BLOCK_BITS);
if (test_bit(TCMU_DEV_BIT_BROKEN, &udev->flags))
@@ -416,8 +463,7 @@
* expensive to tell how many regions are freed in the bitmap
*/
base_command_size = max(offsetof(struct tcmu_cmd_entry,
- req.iov[se_cmd->t_bidi_data_nents +
- se_cmd->t_data_nents]),
+ req.iov[tcmu_cmd_get_block_cnt(tcmu_cmd)]),
sizeof(struct tcmu_cmd_entry));
command_size = base_command_size
+ round_up(scsi_command_size(se_cmd->t_task_cdb), TCMU_OP_ALIGN_SIZE);
@@ -428,11 +474,6 @@
mb = udev->mb_addr;
cmd_head = mb->cmd_head % udev->cmdr_size; /* UAM */
- data_length = se_cmd->data_length;
- if (se_cmd->se_cmd_flags & SCF_BIDI) {
- BUG_ON(!(se_cmd->t_bidi_data_sg && se_cmd->t_bidi_data_nents));
- data_length += se_cmd->t_bidi_data_sg->length;
- }
if ((command_size > (udev->cmdr_size / 2)) ||
data_length > udev->data_size) {
pr_warn("TCMU: Request of size %zu/%zu is too big for %u/%zu "
@@ -502,11 +543,14 @@
entry->req.iov_dif_cnt = 0;
/* Handle BIDI commands */
- iov_cnt = 0;
- alloc_and_scatter_data_area(udev, se_cmd->t_bidi_data_sg,
- se_cmd->t_bidi_data_nents, &iov, &iov_cnt, false);
- entry->req.iov_bidi_cnt = iov_cnt;
-
+ if (se_cmd->se_cmd_flags & SCF_BIDI) {
+ iov_cnt = 0;
+ iov++;
+ alloc_and_scatter_data_area(udev, se_cmd->t_bidi_data_sg,
+ se_cmd->t_bidi_data_nents, &iov, &iov_cnt,
+ false);
+ entry->req.iov_bidi_cnt = iov_cnt;
+ }
/* cmd's data_bitmap is what changed in process */
bitmap_xor(tcmu_cmd->data_bitmap, old_bitmap, udev->data_bitmap,
DATA_BLOCK_BITS);
@@ -582,19 +626,11 @@
se_cmd->scsi_sense_length);
free_data_area(udev, cmd);
} else if (se_cmd->se_cmd_flags & SCF_BIDI) {
- DECLARE_BITMAP(bitmap, DATA_BLOCK_BITS);
-
/* Get Data-In buffer before clean up */
- bitmap_copy(bitmap, cmd->data_bitmap, DATA_BLOCK_BITS);
- gather_data_area(udev, bitmap,
- se_cmd->t_bidi_data_sg, se_cmd->t_bidi_data_nents);
+ gather_data_area(udev, cmd, true);
free_data_area(udev, cmd);
} else if (se_cmd->data_direction == DMA_FROM_DEVICE) {
- DECLARE_BITMAP(bitmap, DATA_BLOCK_BITS);
-
- bitmap_copy(bitmap, cmd->data_bitmap, DATA_BLOCK_BITS);
- gather_data_area(udev, bitmap,
- se_cmd->t_data_sg, se_cmd->t_data_nents);
+ gather_data_area(udev, cmd, false);
free_data_area(udev, cmd);
} else if (se_cmd->data_direction == DMA_TO_DEVICE) {
free_data_area(udev, cmd);
diff --git a/drivers/thermal/Makefile b/drivers/thermal/Makefile
index 2faed7f..acbd26b 100644
--- a/drivers/thermal/Makefile
+++ b/drivers/thermal/Makefile
@@ -52,7 +52,7 @@
obj-$(CONFIG_INTEL_BXT_PMIC_THERMAL) += intel_bxt_pmic_thermal.o
obj-$(CONFIG_INTEL_PCH_THERMAL) += intel_pch_thermal.o
obj-$(CONFIG_ST_THERMAL) += st/
-obj-$(CONFIG_QCOM_TSENS) += qcom/
+obj-$(CONFIG_ARCH_QCOM) += qcom/
obj-$(CONFIG_TEGRA_SOCTHERM) += tegra/
obj-$(CONFIG_HISI_THERMAL) += hisi_thermal.o
obj-$(CONFIG_MTK_THERMAL) += mtk_thermal.o
diff --git a/drivers/thermal/cpu_cooling.c b/drivers/thermal/cpu_cooling.c
index a6245d5..37125c0 100644
--- a/drivers/thermal/cpu_cooling.c
+++ b/drivers/thermal/cpu_cooling.c
@@ -548,11 +548,29 @@
if (cpufreq_device->cpufreq_floor_state == state)
return 0;
- floor_freq = cpufreq_device->freq_table[state];
cpufreq_device->cpufreq_floor_state = state;
- cpufreq_device->floor_freq = floor_freq;
- cpufreq_update_policy(cpu);
+ /*
+ * Check if the device has a platform mitigation function that
+ * can handle the CPU freq mitigation, if not, notify cpufreq
+ * framework.
+ */
+ if (cpufreq_device->plat_ops &&
+ cpufreq_device->plat_ops->floor_limit) {
+ /*
+ * Last level is core isolation so use the frequency
+ * of previous state.
+ */
+ if (state == cpufreq_device->max_level)
+ state--;
+ floor_freq = cpufreq_device->freq_table[state];
+ cpufreq_device->floor_freq = floor_freq;
+ cpufreq_device->plat_ops->floor_limit(cpu, floor_freq);
+ } else {
+ floor_freq = cpufreq_device->freq_table[state];
+ cpufreq_device->floor_freq = floor_freq;
+ cpufreq_update_policy(cpu);
+ }
return 0;
}
diff --git a/drivers/thermal/msm-tsens.c b/drivers/thermal/msm-tsens.c
index 2013e7e..432adbc 100644
--- a/drivers/thermal/msm-tsens.c
+++ b/drivers/thermal/msm-tsens.c
@@ -24,29 +24,28 @@
LIST_HEAD(tsens_device_list);
-static int tsens_get_temp(struct tsens_sensor *s, int *temp)
+static int tsens_get_temp(void *data, int *temp)
{
+ struct tsens_sensor *s = data;
struct tsens_device *tmdev = s->tmdev;
return tmdev->ops->get_temp(s, temp);
}
-static int tsens_set_trip_temp(struct tsens_sensor *s, int trip, int temp)
+static int tsens_set_trip_temp(void *data, int low_temp, int high_temp)
{
+ struct tsens_sensor *s = data;
struct tsens_device *tmdev = s->tmdev;
- if (tmdev->ops->set_trip_temp)
- return tmdev->ops->set_trip_temp(s, trip, temp);
+ if (tmdev->ops->set_trips)
+ return tmdev->ops->set_trips(s, low_temp, high_temp);
return 0;
}
static int tsens_init(struct tsens_device *tmdev)
{
- if (tmdev->ops->hw_init)
- return tmdev->ops->hw_init(tmdev);
-
- return 0;
+ return tmdev->ops->hw_init(tmdev);
}
static int tsens_register_interrupts(struct tsens_device *tmdev)
@@ -85,19 +84,16 @@
static struct thermal_zone_of_device_ops tsens_tm_thermal_zone_ops = {
.get_temp = tsens_get_temp,
- .set_trip_temp = tsens_set_trip_temp,
+ .set_trips = tsens_set_trip_temp,
};
static int get_device_tree_data(struct platform_device *pdev,
struct tsens_device *tmdev)
{
struct device_node *of_node = pdev->dev.of_node;
- u32 *hw_id, *client_id;
- u32 rc = 0, i, tsens_num_sensors = 0;
- int tsens_len;
const struct of_device_id *id;
const struct tsens_data *data;
- struct resource *res_tsens_mem, *res_mem = NULL;
+ struct resource *res_tsens_mem;
if (!of_match_node(tsens_table, of_node)) {
pr_err("Need to read SoC specific fuse map\n");
@@ -111,16 +107,6 @@
}
data = id->data;
- hw_id = devm_kzalloc(&pdev->dev,
- tsens_num_sensors * sizeof(u32), GFP_KERNEL);
- if (!hw_id)
- return -ENOMEM;
-
- client_id = devm_kzalloc(&pdev->dev,
- tsens_num_sensors * sizeof(u32), GFP_KERNEL);
- if (!client_id)
- return -ENOMEM;
-
tmdev->ops = data->ops;
tmdev->ctrl_data = data;
tmdev->pdev = pdev;
@@ -132,49 +118,32 @@
/* TSENS register region */
res_tsens_mem = platform_get_resource_byname(pdev,
- IORESOURCE_MEM, "tsens_physical");
+ IORESOURCE_MEM, "tsens_srot_physical");
if (!res_tsens_mem) {
pr_err("Could not get tsens physical address resource\n");
return -EINVAL;
}
- tsens_len = res_tsens_mem->end - res_tsens_mem->start + 1;
+ tmdev->tsens_srot_addr = devm_ioremap_resource(&pdev->dev,
+ res_tsens_mem);
+ if (IS_ERR(tmdev->tsens_srot_addr)) {
+ dev_err(&pdev->dev, "Failed to IO map TSENS registers.\n");
+ return PTR_ERR(tmdev->tsens_srot_addr);
+ }
- res_mem = request_mem_region(res_tsens_mem->start,
- tsens_len, res_tsens_mem->name);
- if (!res_mem) {
- pr_err("Request tsens physical memory region failed\n");
+ /* TSENS TM register region */
+ res_tsens_mem = platform_get_resource_byname(pdev,
+ IORESOURCE_MEM, "tsens_tm_physical");
+ if (!res_tsens_mem) {
+ pr_err("Could not get tsens physical address resource\n");
return -EINVAL;
}
- tmdev->tsens_addr = ioremap(res_mem->start, tsens_len);
- if (!tmdev->tsens_addr) {
- pr_err("Failed to IO map TSENS registers.\n");
- return -EINVAL;
- }
-
- rc = of_property_read_u32_array(of_node,
- "qcom,sensor-id", hw_id, tsens_num_sensors);
- if (rc) {
- pr_err("Default sensor id mapping\n");
- for (i = 0; i < tsens_num_sensors; i++)
- tmdev->sensor[i].hw_id = i;
- } else {
- pr_err("Use specified sensor id mapping\n");
- for (i = 0; i < tsens_num_sensors; i++)
- tmdev->sensor[i].hw_id = hw_id[i];
- }
-
- rc = of_property_read_u32_array(of_node,
- "qcom,client-id", client_id, tsens_num_sensors);
- if (rc) {
- for (i = 0; i < tsens_num_sensors; i++)
- tmdev->sensor[i].id = i;
- pr_debug("Default client id mapping\n");
- } else {
- for (i = 0; i < tsens_num_sensors; i++)
- tmdev->sensor[i].id = client_id[i];
- pr_debug("Use specified client id mapping\n");
+ tmdev->tsens_tm_addr = devm_ioremap_resource(&pdev->dev,
+ res_tsens_mem);
+ if (IS_ERR(tmdev->tsens_tm_addr)) {
+ dev_err(&pdev->dev, "Failed to IO map TSENS TM registers.\n");
+ return PTR_ERR(tmdev->tsens_tm_addr);
}
return 0;
@@ -182,20 +151,28 @@
static int tsens_thermal_zone_register(struct tsens_device *tmdev)
{
- int rc = 0, i = 0;
+ int i = 0, sensor_missing = 0;
- for (i = 0; i < tmdev->num_sensors; i++) {
+ for (i = 0; i < TSENS_MAX_SENSORS; i++) {
tmdev->sensor[i].tmdev = tmdev;
- tmdev->sensor[i].tzd = devm_thermal_zone_of_sensor_register(
- &tmdev->pdev->dev, i, &tmdev->sensor[i],
- &tsens_tm_thermal_zone_ops);
+ tmdev->sensor[i].hw_id = i;
+ tmdev->sensor[i].tzd =
+ devm_thermal_zone_of_sensor_register(
+ &tmdev->pdev->dev, i,
+ &tmdev->sensor[i], &tsens_tm_thermal_zone_ops);
if (IS_ERR(tmdev->sensor[i].tzd)) {
- pr_err("Error registering sensor:%d\n", i);
+ pr_debug("Error registering sensor:%d\n", i);
+ sensor_missing++;
continue;
}
}
- return rc;
+ if (sensor_missing == TSENS_MAX_SENSORS) {
+ pr_err("No TSENS sensors to register?\n");
+ return -ENODEV;
+ }
+
+ return 0;
}
static int tsens_tm_remove(struct platform_device *pdev)
@@ -207,32 +184,19 @@
int tsens_tm_probe(struct platform_device *pdev)
{
- struct device_node *of_node = pdev->dev.of_node;
struct tsens_device *tmdev = NULL;
- u32 tsens_num_sensors = 0;
int rc;
if (!(pdev->dev.of_node))
return -ENODEV;
- rc = of_property_read_u32(of_node,
- "qcom,sensors", &tsens_num_sensors);
- if (rc || (!tsens_num_sensors)) {
- dev_err(&pdev->dev, "missing sensors\n");
- return -ENODEV;
- }
-
tmdev = devm_kzalloc(&pdev->dev,
sizeof(struct tsens_device) +
- tsens_num_sensors *
+ TSENS_MAX_SENSORS *
sizeof(struct tsens_sensor),
GFP_KERNEL);
- if (tmdev == NULL) {
- pr_err("%s: kzalloc() failed.\n", __func__);
+ if (tmdev == NULL)
return -ENOMEM;
- }
-
- tmdev->num_sensors = tsens_num_sensors;
rc = get_device_tree_data(pdev, tmdev);
if (rc) {
@@ -241,8 +205,10 @@
}
rc = tsens_init(tmdev);
- if (rc)
+ if (rc) {
+ pr_err("Error initializing TSENS controller\n");
return rc;
+ }
rc = tsens_thermal_zone_register(tmdev);
if (rc) {
diff --git a/drivers/thermal/qcom/bcl_peripheral.c b/drivers/thermal/qcom/bcl_peripheral.c
index 55ff770..75e553f 100644
--- a/drivers/thermal/qcom/bcl_peripheral.c
+++ b/drivers/thermal/qcom/bcl_peripheral.c
@@ -259,7 +259,7 @@
*/
for (vbat_idx = 2; vbat_idx < BCL_STD_VBAT_NR;
vbat_idx++) {
- if (vbat_uv > vbat_low[vbat_idx])
+ if (vbat_uv >= vbat_low[vbat_idx])
continue;
break;
}
@@ -274,7 +274,7 @@
*/
for (vbat_idx = 1; vbat_idx < (BCL_STD_VBAT_NR - 1);
vbat_idx++) {
- if (vbat_uv > vbat_low[vbat_idx])
+ if (vbat_uv >= vbat_low[vbat_idx])
continue;
break;
}
diff --git a/drivers/thermal/qcom/msm_lmh_dcvs.c b/drivers/thermal/qcom/msm_lmh_dcvs.c
index 7b6952f..74f5ce0 100644
--- a/drivers/thermal/qcom/msm_lmh_dcvs.c
+++ b/drivers/thermal/qcom/msm_lmh_dcvs.c
@@ -396,8 +396,6 @@
continue;
lmh_node = of_parse_phandle(cpu_node, "qcom,lmh-dcvs", 0);
if (lmh_node == dn) {
- affinity = MPIDR_AFFINITY_LEVEL(
- cpu_logical_map(cpu), 1);
/*set the cpumask*/
cpumask_set_cpu(cpu, &(mask));
}
@@ -409,7 +407,7 @@
* We return error if none of the CPUs have
* reference to our LMH node
*/
- if (affinity == -1)
+ if (cpumask_empty(&mask))
return -EINVAL;
ret = limits_dcvs_get_freq_limits(cpumask_first(&mask), &max_freq,
@@ -426,6 +424,9 @@
return -ENOMEM;
cpumask_copy(&hw->core_map, &mask);
+ ret = of_property_read_u32(dn, "qcom,affinity", &affinity);
+ if (ret)
+ return -ENODEV;
switch (affinity) {
case 0:
hw->affinity = LIMITS_CLUSTER_0;
diff --git a/drivers/thermal/tsens.h b/drivers/thermal/tsens.h
index b9ebb65..3b9b01a 100644
--- a/drivers/thermal/tsens.h
+++ b/drivers/thermal/tsens.h
@@ -23,9 +23,9 @@
#define DEBUG_SIZE 10
#define TSENS_MAX_SENSORS 16
-#define TSENS_CONTROLLER_ID(n) ((n) + 0x1000)
+#define TSENS_CONTROLLER_ID(n) (n)
#define TSENS_CTRL_ADDR(n) (n)
-#define TSENS_TM_SN_STATUS(n) ((n) + 0x10a0)
+#define TSENS_TM_SN_STATUS(n) ((n) + 0xa0)
enum tsens_dbg_type {
TSENS_DBG_POLL,
@@ -87,7 +87,7 @@
struct tsens_ops {
int (*hw_init)(struct tsens_device *);
int (*get_temp)(struct tsens_sensor *, int *);
- int (*set_trip_temp)(struct tsens_sensor *, int, int);
+ int (*set_trips)(struct tsens_sensor *, int, int);
int (*interrupts_reg)(struct tsens_device *);
int (*dbg)(struct tsens_device *, u32, u32, int *);
};
@@ -121,7 +121,8 @@
u32 num_sensors;
struct regmap *map;
struct regmap_field *status_field;
- void *tsens_addr;
+ void __iomem *tsens_srot_addr;
+ void __iomem *tsens_tm_addr;
const struct tsens_ops *ops;
struct tsens_dbg_context tsens_dbg;
spinlock_t tsens_crit_lock;
diff --git a/drivers/thermal/tsens2xxx.c b/drivers/thermal/tsens2xxx.c
index 1f0bee9..13b183d 100644
--- a/drivers/thermal/tsens2xxx.c
+++ b/drivers/thermal/tsens2xxx.c
@@ -18,19 +18,20 @@
#include <linux/of.h>
#include <linux/vmalloc.h>
#include "tsens.h"
+#include "thermal_core.h"
#define TSENS_DRIVER_NAME "msm-tsens"
-#define TSENS_TM_INT_EN(n) ((n) + 0x1004)
-#define TSENS_TM_CRITICAL_INT_STATUS(n) ((n) + 0x1014)
-#define TSENS_TM_CRITICAL_INT_CLEAR(n) ((n) + 0x1018)
-#define TSENS_TM_CRITICAL_INT_MASK(n) ((n) + 0x101c)
+#define TSENS_TM_INT_EN(n) ((n) + 0x4)
+#define TSENS_TM_CRITICAL_INT_STATUS(n) ((n) + 0x14)
+#define TSENS_TM_CRITICAL_INT_CLEAR(n) ((n) + 0x18)
+#define TSENS_TM_CRITICAL_INT_MASK(n) ((n) + 0x1c)
#define TSENS_TM_CRITICAL_WD_BARK BIT(31)
#define TSENS_TM_CRITICAL_CYCLE_MONITOR BIT(30)
#define TSENS_TM_CRITICAL_INT_EN BIT(2)
#define TSENS_TM_UPPER_INT_EN BIT(1)
#define TSENS_TM_LOWER_INT_EN BIT(0)
-#define TSENS_TM_SN_UPPER_LOWER_THRESHOLD(n) ((n) + 0x1020)
+#define TSENS_TM_SN_UPPER_LOWER_THRESHOLD(n) ((n) + 0x20)
#define TSENS_TM_SN_ADDR_OFFSET 0x4
#define TSENS_TM_UPPER_THRESHOLD_SET(n) ((n) << 12)
#define TSENS_TM_UPPER_THRESHOLD_VALUE_SHIFT(n) ((n) >> 12)
@@ -39,13 +40,13 @@
#define TSENS_TM_UPPER_THRESHOLD_MASK 0xfff000
#define TSENS_TM_LOWER_THRESHOLD_MASK 0xfff
#define TSENS_TM_UPPER_THRESHOLD_SHIFT 12
-#define TSENS_TM_SN_CRITICAL_THRESHOLD(n) ((n) + 0x1060)
+#define TSENS_TM_SN_CRITICAL_THRESHOLD(n) ((n) + 0x60)
#define TSENS_STATUS_ADDR_OFFSET 2
#define TSENS_TM_UPPER_INT_MASK(n) (((n) & 0xffff0000) >> 16)
#define TSENS_TM_LOWER_INT_MASK(n) ((n) & 0xffff)
-#define TSENS_TM_UPPER_LOWER_INT_STATUS(n) ((n) + 0x1008)
-#define TSENS_TM_UPPER_LOWER_INT_CLEAR(n) ((n) + 0x100c)
-#define TSENS_TM_UPPER_LOWER_INT_MASK(n) ((n) + 0x1010)
+#define TSENS_TM_UPPER_LOWER_INT_STATUS(n) ((n) + 0x8)
+#define TSENS_TM_UPPER_LOWER_INT_CLEAR(n) ((n) + 0xc)
+#define TSENS_TM_UPPER_LOWER_INT_MASK(n) ((n) + 0x10)
#define TSENS_TM_UPPER_INT_SET(n) (1 << (n + 16))
#define TSENS_TM_SN_CRITICAL_THRESHOLD_MASK 0xfff
#define TSENS_TM_SN_STATUS_VALID_BIT BIT(21)
@@ -55,6 +56,7 @@
#define TSENS_TM_SN_LAST_TEMP_MASK 0xfff
#define TSENS_TM_CODE_BIT_MASK 0xfff
#define TSENS_TM_CODE_SIGN_BIT 0x800
+#define TSENS_TM_SCALE_DECI_MILLIDEG 100
#define TSENS_EN BIT(0)
@@ -67,7 +69,7 @@
last_temp |= code_mask;
}
- *temp = last_temp * 100;
+ *temp = last_temp * TSENS_TM_SCALE_DECI_MILLIDEG;
}
static int tsens2xxx_get_temp(struct tsens_sensor *sensor, int *temp)
@@ -81,7 +83,7 @@
return -EINVAL;
tmdev = sensor->tmdev;
- sensor_addr = TSENS_TM_SN_STATUS(tmdev->tsens_addr);
+ sensor_addr = TSENS_TM_SN_STATUS(tmdev->tsens_tm_addr);
code = readl_relaxed_no_log(sensor_addr +
(sensor->hw_id << TSENS_STATUS_ADDR_OFFSET));
@@ -130,7 +132,6 @@
{
struct tsens_device *tmdev = NULL;
unsigned int reg_cntl, mask;
- unsigned long flags;
int rc = 0;
/* clear the interrupt and unmask */
@@ -141,56 +142,57 @@
if (!tmdev)
return -EINVAL;
- spin_lock_irqsave(&tmdev->tsens_upp_low_lock, flags);
+
mask = (tm_sensor->hw_id);
switch (trip) {
case THERMAL_TRIP_CRITICAL:
tmdev->sensor[tm_sensor->hw_id].
thr_state.crit_th_state = mode;
reg_cntl = readl_relaxed(TSENS_TM_CRITICAL_INT_MASK
- (tmdev->tsens_addr));
+ (tmdev->tsens_tm_addr));
if (mode == THERMAL_TRIP_ACTIVATION_DISABLED)
writel_relaxed(reg_cntl | (1 << mask),
(TSENS_TM_CRITICAL_INT_MASK
- (tmdev->tsens_addr)));
+ (tmdev->tsens_tm_addr)));
else
writel_relaxed(reg_cntl & ~(1 << mask),
(TSENS_TM_CRITICAL_INT_MASK
- (tmdev->tsens_addr)));
+ (tmdev->tsens_tm_addr)));
break;
- case THERMAL_TRIP_ACTIVE:
+ case THERMAL_TRIP_CONFIGURABLE_HI:
tmdev->sensor[tm_sensor->hw_id].
thr_state.high_th_state = mode;
reg_cntl = readl_relaxed(TSENS_TM_UPPER_LOWER_INT_MASK
- (tmdev->tsens_addr));
+ (tmdev->tsens_tm_addr));
if (mode == THERMAL_TRIP_ACTIVATION_DISABLED)
writel_relaxed(reg_cntl |
(TSENS_TM_UPPER_INT_SET(mask)),
(TSENS_TM_UPPER_LOWER_INT_MASK
- (tmdev->tsens_addr)));
+ (tmdev->tsens_tm_addr)));
else
writel_relaxed(reg_cntl &
~(TSENS_TM_UPPER_INT_SET(mask)),
(TSENS_TM_UPPER_LOWER_INT_MASK
- (tmdev->tsens_addr)));
+ (tmdev->tsens_tm_addr)));
break;
- case THERMAL_TRIP_PASSIVE:
+ case THERMAL_TRIP_CONFIGURABLE_LOW:
tmdev->sensor[tm_sensor->hw_id].
thr_state.low_th_state = mode;
reg_cntl = readl_relaxed(TSENS_TM_UPPER_LOWER_INT_MASK
- (tmdev->tsens_addr));
+ (tmdev->tsens_tm_addr));
if (mode == THERMAL_TRIP_ACTIVATION_DISABLED)
writel_relaxed(reg_cntl | (1 << mask),
- (TSENS_TM_UPPER_LOWER_INT_MASK(tmdev->tsens_addr)));
+ (TSENS_TM_UPPER_LOWER_INT_MASK
+ (tmdev->tsens_tm_addr)));
else
writel_relaxed(reg_cntl & ~(1 << mask),
- (TSENS_TM_UPPER_LOWER_INT_MASK(tmdev->tsens_addr)));
+ (TSENS_TM_UPPER_LOWER_INT_MASK
+ (tmdev->tsens_tm_addr)));
break;
default:
rc = -EINVAL;
}
- spin_unlock_irqrestore(&tmdev->tsens_upp_low_lock, flags);
/* Activate and enable the respective trip threshold setting */
mb();
@@ -198,14 +200,14 @@
}
static int tsens2xxx_set_trip_temp(struct tsens_sensor *tm_sensor,
- int trip, int temp)
+ int low_temp, int high_temp)
{
unsigned int reg_cntl;
unsigned long flags;
struct tsens_device *tmdev = NULL;
int rc = 0;
- if (!tm_sensor || trip < 0)
+ if (!tm_sensor)
return -EINVAL;
tmdev = tm_sensor->tmdev;
@@ -213,56 +215,81 @@
return -EINVAL;
spin_lock_irqsave(&tmdev->tsens_upp_low_lock, flags);
- switch (trip) {
- case THERMAL_TRIP_CRITICAL:
+
+ if (high_temp != INT_MAX) {
tmdev->sensor[tm_sensor->hw_id].
- thr_state.crit_temp = temp;
- temp &= TSENS_TM_SN_CRITICAL_THRESHOLD_MASK;
- writel_relaxed(temp,
- (TSENS_TM_SN_CRITICAL_THRESHOLD(tmdev->tsens_addr) +
- (tm_sensor->hw_id * TSENS_TM_SN_ADDR_OFFSET)));
- break;
- case THERMAL_TRIP_ACTIVE:
- tmdev->sensor[tm_sensor->hw_id].
- thr_state.high_temp = temp;
+ thr_state.high_temp = high_temp;
reg_cntl = readl_relaxed((TSENS_TM_SN_UPPER_LOWER_THRESHOLD
- (tmdev->tsens_addr)) +
+ (tmdev->tsens_tm_addr)) +
(tm_sensor->hw_id *
TSENS_TM_SN_ADDR_OFFSET));
- temp = TSENS_TM_UPPER_THRESHOLD_SET(temp);
- temp &= TSENS_TM_UPPER_THRESHOLD_MASK;
+ high_temp /= TSENS_TM_SCALE_DECI_MILLIDEG;
+ high_temp = TSENS_TM_UPPER_THRESHOLD_SET(high_temp);
+ high_temp &= TSENS_TM_UPPER_THRESHOLD_MASK;
reg_cntl &= ~TSENS_TM_UPPER_THRESHOLD_MASK;
- writel_relaxed(reg_cntl | temp,
- (TSENS_TM_SN_UPPER_LOWER_THRESHOLD(tmdev->tsens_addr) +
+ writel_relaxed(reg_cntl | high_temp,
+ (TSENS_TM_SN_UPPER_LOWER_THRESHOLD
+ (tmdev->tsens_tm_addr) +
(tm_sensor->hw_id * TSENS_TM_SN_ADDR_OFFSET)));
- break;
- case THERMAL_TRIP_PASSIVE:
- tmdev->sensor[tm_sensor->hw_id].
- thr_state.low_temp = temp;
- reg_cntl = readl_relaxed((TSENS_TM_SN_UPPER_LOWER_THRESHOLD
- (tmdev->tsens_addr)) +
- (tm_sensor->hw_id *
- TSENS_TM_SN_ADDR_OFFSET));
- temp &= TSENS_TM_LOWER_THRESHOLD_MASK;
- reg_cntl &= ~TSENS_TM_LOWER_THRESHOLD_MASK;
- writel_relaxed(reg_cntl | temp,
- (TSENS_TM_SN_UPPER_LOWER_THRESHOLD(tmdev->tsens_addr) +
- (tm_sensor->hw_id * TSENS_TM_SN_ADDR_OFFSET)));
- break;
- default:
- pr_err("Invalid trip to TSENS: %d\n", trip);
- rc = -EINVAL;
}
- spin_unlock_irqrestore(&tmdev->tsens_upp_low_lock, flags);
+ if (low_temp != INT_MIN) {
+ tmdev->sensor[tm_sensor->hw_id].
+ thr_state.low_temp = low_temp;
+ reg_cntl = readl_relaxed((TSENS_TM_SN_UPPER_LOWER_THRESHOLD
+ (tmdev->tsens_tm_addr)) +
+ (tm_sensor->hw_id *
+ TSENS_TM_SN_ADDR_OFFSET));
+ low_temp /= TSENS_TM_SCALE_DECI_MILLIDEG;
+ low_temp &= TSENS_TM_LOWER_THRESHOLD_MASK;
+ reg_cntl &= ~TSENS_TM_LOWER_THRESHOLD_MASK;
+ writel_relaxed(reg_cntl | low_temp,
+ (TSENS_TM_SN_UPPER_LOWER_THRESHOLD
+ (tmdev->tsens_tm_addr) +
+ (tm_sensor->hw_id * TSENS_TM_SN_ADDR_OFFSET)));
+ }
+
/* Set trip temperature thresholds */
mb();
- rc = tsens_tm_activate_trip_type(tm_sensor, trip,
+ if (high_temp != INT_MAX) {
+ rc = tsens_tm_activate_trip_type(tm_sensor,
+ THERMAL_TRIP_CONFIGURABLE_HI,
THERMAL_TRIP_ACTIVATION_ENABLED);
- if (rc)
- pr_err("Error during trip activation :%d\n", rc);
+ if (rc) {
+ pr_err("trip high enable error :%d\n", rc);
+ goto fail;
+ }
+ } else {
+ rc = tsens_tm_activate_trip_type(tm_sensor,
+ THERMAL_TRIP_CONFIGURABLE_HI,
+ THERMAL_TRIP_ACTIVATION_DISABLED);
+ if (rc) {
+ pr_err("trip high disable error :%d\n", rc);
+ goto fail;
+ }
+ }
+ if (low_temp != INT_MIN) {
+ rc = tsens_tm_activate_trip_type(tm_sensor,
+ THERMAL_TRIP_CONFIGURABLE_LOW,
+ THERMAL_TRIP_ACTIVATION_ENABLED);
+ if (rc) {
+ pr_err("trip low enable activation error :%d\n", rc);
+ goto fail;
+ }
+ } else {
+ rc = tsens_tm_activate_trip_type(tm_sensor,
+ THERMAL_TRIP_CONFIGURABLE_LOW,
+ THERMAL_TRIP_ACTIVATION_DISABLED);
+ if (rc) {
+ pr_err("trip low disable error :%d\n", rc);
+ goto fail;
+ }
+ }
+
+fail:
+ spin_unlock_irqrestore(&tmdev->tsens_upp_low_lock, flags);
return rc;
}
@@ -277,13 +304,13 @@
void __iomem *wd_critical_addr;
int wd_mask;
- sensor_status_addr = TSENS_TM_SN_STATUS(tm->tsens_addr);
+ sensor_status_addr = TSENS_TM_SN_STATUS(tm->tsens_tm_addr);
sensor_int_mask_addr =
- TSENS_TM_CRITICAL_INT_MASK(tm->tsens_addr);
+ TSENS_TM_CRITICAL_INT_MASK(tm->tsens_tm_addr);
sensor_critical_addr =
- TSENS_TM_SN_CRITICAL_THRESHOLD(tm->tsens_addr);
+ TSENS_TM_SN_CRITICAL_THRESHOLD(tm->tsens_tm_addr);
wd_critical_addr =
- TSENS_TM_CRITICAL_INT_STATUS(tm->tsens_addr);
+ TSENS_TM_CRITICAL_INT_STATUS(tm->tsens_tm_addr);
if (tm->ctrl_data->wd_bark) {
wd_mask = readl_relaxed(wd_critical_addr);
@@ -294,19 +321,22 @@
*/
writel_relaxed(wd_mask | TSENS_TM_CRITICAL_WD_BARK,
(TSENS_TM_CRITICAL_INT_CLEAR
- (tm->tsens_addr)));
+ (tm->tsens_tm_addr)));
writel_relaxed(wd_mask & ~(TSENS_TM_CRITICAL_WD_BARK),
(TSENS_TM_CRITICAL_INT_CLEAR
- (tm->tsens_addr)));
+ (tm->tsens_tm_addr)));
tm->tsens_dbg.tsens_critical_wd_cnt++;
return IRQ_HANDLED;
}
}
- for (i = 0; i < tm->num_sensors; i++) {
+ for (i = 0; i < TSENS_MAX_SENSORS; i++) {
int int_mask, int_mask_val;
u32 addr_offset;
+ if (IS_ERR(tm->sensor[i].tzd))
+ continue;
+
spin_lock_irqsave(&tm->tsens_crit_lock, flags);
addr_offset = tm->sensor[i].hw_id *
TSENS_TM_SN_ADDR_OFFSET;
@@ -320,13 +350,14 @@
/* Mask the corresponding interrupt for the sensors */
writel_relaxed(int_mask | int_mask_val,
TSENS_TM_CRITICAL_INT_MASK(
- tm->tsens_addr));
+ tm->tsens_tm_addr));
/* Clear the corresponding sensors interrupt */
writel_relaxed(int_mask_val,
- TSENS_TM_CRITICAL_INT_CLEAR(tm->tsens_addr));
+ TSENS_TM_CRITICAL_INT_CLEAR
+ (tm->tsens_tm_addr));
writel_relaxed(0,
TSENS_TM_CRITICAL_INT_CLEAR(
- tm->tsens_addr));
+ tm->tsens_tm_addr));
tm->sensor[i].thr_state.
crit_th_state = THERMAL_DEVICE_DISABLED;
}
@@ -342,22 +373,31 @@
static irqreturn_t tsens_tm_irq_thread(int irq, void *data)
{
struct tsens_device *tm = data;
- unsigned int i, status, threshold;
+ unsigned int i, status, threshold, temp;
unsigned long flags;
void __iomem *sensor_status_addr;
void __iomem *sensor_int_mask_addr;
void __iomem *sensor_upper_lower_addr;
u32 addr_offset = 0;
- sensor_status_addr = TSENS_TM_SN_STATUS(tm->tsens_addr);
+ sensor_status_addr = TSENS_TM_SN_STATUS(tm->tsens_tm_addr);
sensor_int_mask_addr =
- TSENS_TM_UPPER_LOWER_INT_MASK(tm->tsens_addr);
+ TSENS_TM_UPPER_LOWER_INT_MASK(tm->tsens_tm_addr);
sensor_upper_lower_addr =
- TSENS_TM_SN_UPPER_LOWER_THRESHOLD(tm->tsens_addr);
+ TSENS_TM_SN_UPPER_LOWER_THRESHOLD(tm->tsens_tm_addr);
- for (i = 0; i < tm->num_sensors; i++) {
+ for (i = 0; i < TSENS_MAX_SENSORS; i++) {
bool upper_thr = false, lower_thr = false;
- int int_mask, int_mask_val = 0;
+ int int_mask, int_mask_val = 0, rc;
+
+ if (IS_ERR(tm->sensor[i].tzd))
+ continue;
+
+ rc = tsens2xxx_get_temp(&tm->sensor[i], &temp);
+ if (rc) {
+ pr_debug("Error:%d reading temp sensor:%d\n", rc, i);
+ continue;
+ }
spin_lock_irqsave(&tm->tsens_upp_low_lock, flags);
addr_offset = tm->sensor[i].hw_id *
@@ -376,17 +416,28 @@
/* Mask the corresponding interrupt for the sensors */
writel_relaxed(int_mask | int_mask_val,
TSENS_TM_UPPER_LOWER_INT_MASK(
- tm->tsens_addr));
+ tm->tsens_tm_addr));
/* Clear the corresponding sensors interrupt */
writel_relaxed(int_mask_val,
TSENS_TM_UPPER_LOWER_INT_CLEAR(
- tm->tsens_addr));
+ tm->tsens_tm_addr));
writel_relaxed(0,
TSENS_TM_UPPER_LOWER_INT_CLEAR(
- tm->tsens_addr));
- upper_thr = true;
- tm->sensor[i].thr_state.
+ tm->tsens_tm_addr));
+ if (TSENS_TM_UPPER_THRESHOLD_VALUE(threshold) >
+ (temp/TSENS_TM_SCALE_DECI_MILLIDEG)) {
+ pr_debug("Re-arm high threshold\n");
+ rc = tsens_tm_activate_trip_type(
+ &tm->sensor[i],
+ THERMAL_TRIP_CONFIGURABLE_HI,
+ THERMAL_TRIP_ACTIVATION_ENABLED);
+ if (rc)
+ pr_err("high rearm failed:%d\n", rc);
+ } else {
+ upper_thr = true;
+ tm->sensor[i].thr_state.
high_th_state = THERMAL_DEVICE_DISABLED;
+ }
}
if ((status & TSENS_TM_SN_STATUS_LOWER_STATUS) &&
@@ -397,32 +448,36 @@
/* Mask the corresponding interrupt for the sensors */
writel_relaxed(int_mask | int_mask_val,
TSENS_TM_UPPER_LOWER_INT_MASK(
- tm->tsens_addr));
+ tm->tsens_tm_addr));
/* Clear the corresponding sensors interrupt */
writel_relaxed(int_mask_val,
TSENS_TM_UPPER_LOWER_INT_CLEAR(
- tm->tsens_addr));
+ tm->tsens_tm_addr));
writel_relaxed(0,
TSENS_TM_UPPER_LOWER_INT_CLEAR(
- tm->tsens_addr));
- lower_thr = true;
- tm->sensor[i].thr_state.
+ tm->tsens_tm_addr));
+ if (TSENS_TM_LOWER_THRESHOLD_VALUE(threshold)
+ < (temp/TSENS_TM_SCALE_DECI_MILLIDEG)) {
+ pr_debug("Re-arm low threshold\n");
+ rc = tsens_tm_activate_trip_type(
+ &tm->sensor[i],
+ THERMAL_TRIP_CONFIGURABLE_LOW,
+ THERMAL_TRIP_ACTIVATION_ENABLED);
+ if (rc)
+ pr_err("low rearm failed:%d\n", rc);
+ } else {
+ lower_thr = true;
+ tm->sensor[i].thr_state.
low_th_state = THERMAL_DEVICE_DISABLED;
+ }
}
spin_unlock_irqrestore(&tm->tsens_upp_low_lock, flags);
if (upper_thr || lower_thr) {
- int temp;
- enum thermal_trip_type trip =
- THERMAL_TRIP_CONFIGURABLE_LOW;
-
- if (upper_thr)
- trip = THERMAL_TRIP_CONFIGURABLE_HI;
- tsens2xxx_get_temp(&tm->sensor[i], &temp);
/* Use id for multiple controllers */
pr_debug("sensor:%d trigger temp (%d degC)\n",
- tm->sensor[i].hw_id,
- (status & TSENS_TM_SN_LAST_TEMP_MASK));
+ tm->sensor[i].hw_id, temp);
+ of_thermal_handle_trip(tm->sensor[i].tzd);
}
}
@@ -442,7 +497,7 @@
unsigned int srot_val;
int crit_mask;
- srot_addr = TSENS_CTRL_ADDR(tmdev->tsens_addr + 0x4);
+ srot_addr = TSENS_CTRL_ADDR(tmdev->tsens_srot_addr + 0x4);
srot_val = readl_relaxed(srot_addr);
if (!(srot_val & TSENS_EN)) {
pr_err("TSENS device is not enabled\n");
@@ -451,18 +506,18 @@
if (tmdev->ctrl_data->cycle_monitor) {
sensor_int_mask_addr =
- TSENS_TM_CRITICAL_INT_MASK(tmdev->tsens_addr);
+ TSENS_TM_CRITICAL_INT_MASK(tmdev->tsens_tm_addr);
crit_mask = readl_relaxed(sensor_int_mask_addr);
writel_relaxed(
crit_mask | tmdev->ctrl_data->cycle_compltn_monitor_val,
(TSENS_TM_CRITICAL_INT_MASK
- (tmdev->tsens_addr)));
+ (tmdev->tsens_tm_addr)));
/*Update critical cycle monitoring*/
mb();
}
writel_relaxed(TSENS_TM_CRITICAL_INT_EN |
TSENS_TM_UPPER_INT_EN | TSENS_TM_LOWER_INT_EN,
- TSENS_TM_INT_EN(tmdev->tsens_addr));
+ TSENS_TM_INT_EN(tmdev->tsens_tm_addr));
spin_lock_init(&tmdev->tsens_crit_lock);
spin_lock_init(&tmdev->tsens_upp_low_lock);
@@ -513,7 +568,7 @@
static const struct tsens_ops ops_tsens2xxx = {
.hw_init = tsens2xxx_hw_init,
.get_temp = tsens2xxx_get_temp,
- .set_trip_temp = tsens2xxx_set_trip_temp,
+ .set_trips = tsens2xxx_set_trip_temp,
.interrupts_reg = tsens2xxx_register_interrupts,
.dbg = tsens2xxx_dbg,
};
diff --git a/drivers/tty/serial/msm_geni_serial.c b/drivers/tty/serial/msm_geni_serial.c
index b3cb5c0..df9be34 100644
--- a/drivers/tty/serial/msm_geni_serial.c
+++ b/drivers/tty/serial/msm_geni_serial.c
@@ -27,6 +27,8 @@
#include <linux/serial_core.h>
#include <linux/tty.h>
#include <linux/tty_flip.h>
+#include <linux/msm-bus.h>
+#include <linux/msm-bus-board.h>
/* UART specific GENI registers */
#define SE_UART_LOOPBACK_CFG (0x22C)
@@ -95,6 +97,10 @@
#define GENI_UART_NR_PORTS (15)
#define DEF_FIFO_DEPTH_WORDS (16)
#define DEF_FIFO_WIDTH_BITS (32)
+#define UART_CORE2X_VOTE (10000)
+#define DEFAULT_SE_CLK (19200000)
+#define DEFAULT_BUS_WIDTH (4)
+
struct msm_geni_serial_port {
struct uart_port uport;
@@ -1257,6 +1263,25 @@
}
uport->dev = &pdev->dev;
+
+ if (!(of_property_read_u32(pdev->dev.of_node, "qcom,bus-mas",
+ &dev_port->serial_rsc.bus_mas))) {
+ dev_port->serial_rsc.bus_bw =
+ msm_bus_scale_register(
+ dev_port->serial_rsc.bus_mas,
+ MSM_BUS_SLAVE_EBI_CH0,
+ (char *)dev_name(&pdev->dev),
+ false);
+ if (IS_ERR_OR_NULL(dev_port->serial_rsc.bus_bw)) {
+ ret = PTR_ERR(dev_port->serial_rsc.bus_bw);
+ goto exit_geni_serial_probe;
+ }
+ dev_port->serial_rsc.ab = UART_CORE2X_VOTE;
+ dev_port->serial_rsc.ib = DEFAULT_SE_CLK * DEFAULT_BUS_WIDTH;
+ } else {
+ dev_info(&pdev->dev, "No bus master specified");
+ }
+
dev_port->serial_rsc.se_clk = devm_clk_get(&pdev->dev, "se-clk");
if (IS_ERR(dev_port->serial_rsc.se_clk)) {
ret = PTR_ERR(dev_port->serial_rsc.se_clk);
@@ -1364,6 +1389,7 @@
(struct uart_driver *)port->uport.private_data;
uart_remove_one_port(drv, &port->uport);
+ msm_bus_scale_unregister(port->serial_rsc.bus_bw);
return 0;
}
diff --git a/drivers/uio/Kconfig b/drivers/uio/Kconfig
index 52c98ce..ee15d7d 100644
--- a/drivers/uio/Kconfig
+++ b/drivers/uio/Kconfig
@@ -155,4 +155,11 @@
If you compile this as a module, it will be called uio_mf624.
+config UIO_MSM_SHAREDMEM
+ bool "MSM shared memory driver"
+ default n
+ help
+ Provides the clients with their respective alloted shared memory
+ addresses which are used as transport buffer.
+
endif
diff --git a/drivers/uio/Makefile b/drivers/uio/Makefile
index 8560dad..2282a69 100644
--- a/drivers/uio/Makefile
+++ b/drivers/uio/Makefile
@@ -9,3 +9,4 @@
obj-$(CONFIG_UIO_PRUSS) += uio_pruss.o
obj-$(CONFIG_UIO_MF624) += uio_mf624.o
obj-$(CONFIG_UIO_FSL_ELBC_GPCM) += uio_fsl_elbc_gpcm.o
+obj-$(CONFIG_UIO_MSM_SHAREDMEM) += msm_sharedmem/
diff --git a/drivers/uio/msm_sharedmem/Makefile b/drivers/uio/msm_sharedmem/Makefile
new file mode 100644
index 0000000..e6b8570
--- /dev/null
+++ b/drivers/uio/msm_sharedmem/Makefile
@@ -0,0 +1,4 @@
+obj-$(CONFIG_UIO_MSM_SHAREDMEM) := \
+ msm_sharedmem.o \
+ remote_filesystem_access_v01.o \
+ sharedmem_qmi.o \
diff --git a/drivers/uio/msm_sharedmem/msm_sharedmem.c b/drivers/uio/msm_sharedmem/msm_sharedmem.c
new file mode 100644
index 0000000..b25f55a
--- /dev/null
+++ b/drivers/uio/msm_sharedmem/msm_sharedmem.c
@@ -0,0 +1,240 @@
+/* Copyright (c) 2013-2016, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#define DRIVER_NAME "msm_sharedmem"
+#define pr_fmt(fmt) DRIVER_NAME ": %s: " fmt, __func__
+
+#include <linux/uio_driver.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/err.h>
+#include <linux/of.h>
+#include <linux/dma-mapping.h>
+
+#include <soc/qcom/secure_buffer.h>
+
+#include "sharedmem_qmi.h"
+
+#define CLIENT_ID_PROP "qcom,client-id"
+
+#define MPSS_RMTS_CLIENT_ID 1
+
+static int uio_get_mem_index(struct uio_info *info, struct vm_area_struct *vma)
+{
+ if (vma->vm_pgoff >= MAX_UIO_MAPS)
+ return -EINVAL;
+
+ if (info->mem[vma->vm_pgoff].size == 0)
+ return -EINVAL;
+
+ return (int)vma->vm_pgoff;
+}
+
+static int sharedmem_mmap(struct uio_info *info, struct vm_area_struct *vma)
+{
+ int result;
+ struct uio_mem *mem;
+ int mem_index = uio_get_mem_index(info, vma);
+
+ if (mem_index < 0) {
+ pr_err("mem_index is invalid errno %d\n", mem_index);
+ return mem_index;
+ }
+
+ mem = info->mem + mem_index;
+
+ if (vma->vm_end - vma->vm_start > mem->size) {
+ pr_err("vm_end[%lu] - vm_start[%lu] [%lu] > mem->size[%pa]\n",
+ vma->vm_end, vma->vm_start,
+ (vma->vm_end - vma->vm_start), &mem->size);
+ return -EINVAL;
+ }
+ pr_debug("Attempting to setup mmap.\n");
+
+ vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot);
+
+ result = remap_pfn_range(vma,
+ vma->vm_start,
+ mem->addr >> PAGE_SHIFT,
+ vma->vm_end - vma->vm_start,
+ vma->vm_page_prot);
+ if (result != 0)
+ pr_err("mmap Failed with errno %d\n", result);
+ else
+ pr_debug("mmap success\n");
+
+ return result;
+}
+
+/* Setup the shared ram permissions.
+ * This function currently supports the mpss client only.
+ */
+static void setup_shared_ram_perms(u32 client_id, phys_addr_t addr, u32 size)
+{
+ int ret;
+ u32 source_vmlist[1] = {VMID_HLOS};
+ int dest_vmids[2] = {VMID_HLOS, VMID_MSS_MSA};
+ int dest_perms[2] = {PERM_READ|PERM_WRITE,
+ PERM_READ|PERM_WRITE};
+
+ if (client_id != MPSS_RMTS_CLIENT_ID)
+ return;
+
+ ret = hyp_assign_phys(addr, size, source_vmlist, 1, dest_vmids,
+ dest_perms, 2);
+ if (ret != 0) {
+ if (ret == -EINVAL)
+ pr_warn("hyp_assign_phys is not supported!");
+ else
+ pr_err("hyp_assign_phys failed IPA=0x016%pa size=%u err=%d\n",
+ &addr, size, ret);
+ }
+}
+
+static int msm_sharedmem_probe(struct platform_device *pdev)
+{
+ int ret = 0;
+ struct uio_info *info = NULL;
+ struct resource *clnt_res = NULL;
+ u32 client_id = ((u32)~0U);
+ u32 shared_mem_size = 0;
+ void *shared_mem = NULL;
+ phys_addr_t shared_mem_pyhsical = 0;
+ bool is_addr_dynamic = false;
+ struct sharemem_qmi_entry qmi_entry;
+
+ /* Get the addresses from platform-data */
+ if (!pdev->dev.of_node) {
+ pr_err("Node not found\n");
+ ret = -ENODEV;
+ goto out;
+ }
+ clnt_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!clnt_res) {
+ pr_err("resource not found\n");
+ return -ENODEV;
+ }
+
+ ret = of_property_read_u32(pdev->dev.of_node, CLIENT_ID_PROP,
+ &client_id);
+ if (ret) {
+ client_id = ((u32)~0U);
+ pr_warn("qcom,client-id property not found\n");
+ }
+
+ info = devm_kzalloc(&pdev->dev, sizeof(struct uio_info), GFP_KERNEL);
+ if (!info)
+ return -ENOMEM;
+
+ shared_mem_size = resource_size(clnt_res);
+ shared_mem_pyhsical = clnt_res->start;
+
+ if (shared_mem_size == 0) {
+ pr_err("Shared memory size is zero\n");
+ return -EINVAL;
+ }
+
+ if (shared_mem_pyhsical == 0) {
+ is_addr_dynamic = true;
+ shared_mem = dma_alloc_coherent(&pdev->dev, shared_mem_size,
+ &shared_mem_pyhsical, GFP_KERNEL);
+ if (shared_mem == NULL) {
+ pr_err("Shared mem alloc client=%s, size=%u\n",
+ clnt_res->name, shared_mem_size);
+ return -ENOMEM;
+ }
+ }
+
+ /* Set up the permissions for the shared ram that was allocated. */
+ setup_shared_ram_perms(client_id, shared_mem_pyhsical, shared_mem_size);
+
+ /* Setup device */
+ info->mmap = sharedmem_mmap; /* Custom mmap function. */
+ info->name = clnt_res->name;
+ info->version = "1.0";
+ info->mem[0].addr = shared_mem_pyhsical;
+ info->mem[0].size = shared_mem_size;
+ info->mem[0].memtype = UIO_MEM_PHYS;
+
+ ret = uio_register_device(&pdev->dev, info);
+ if (ret) {
+ pr_err("uio register failed ret=%d\n", ret);
+ goto out;
+ }
+ dev_set_drvdata(&pdev->dev, info);
+
+ qmi_entry.client_id = client_id;
+ qmi_entry.client_name = info->name;
+ qmi_entry.address = info->mem[0].addr;
+ qmi_entry.size = info->mem[0].size;
+ qmi_entry.is_addr_dynamic = is_addr_dynamic;
+
+ sharedmem_qmi_add_entry(&qmi_entry);
+ pr_info("Device created for client '%s'\n", clnt_res->name);
+out:
+ return ret;
+}
+
+static int msm_sharedmem_remove(struct platform_device *pdev)
+{
+ struct uio_info *info = dev_get_drvdata(&pdev->dev);
+
+ uio_unregister_device(info);
+
+ return 0;
+}
+
+static const struct of_device_id msm_sharedmem_of_match[] = {
+ {.compatible = "qcom,sharedmem-uio",},
+ {},
+};
+MODULE_DEVICE_TABLE(of, msm_sharedmem_of_match);
+
+static struct platform_driver msm_sharedmem_driver = {
+ .probe = msm_sharedmem_probe,
+ .remove = msm_sharedmem_remove,
+ .driver = {
+ .name = DRIVER_NAME,
+ .owner = THIS_MODULE,
+ .of_match_table = msm_sharedmem_of_match,
+ },
+};
+
+
+static int __init msm_sharedmem_init(void)
+{
+ int result;
+
+ result = sharedmem_qmi_init();
+ if (result < 0) {
+ pr_err("sharedmem_qmi_init failed result = %d\n", result);
+ return result;
+ }
+
+ result = platform_driver_register(&msm_sharedmem_driver);
+ if (result != 0) {
+ pr_err("Platform driver registration failed\n");
+ return result;
+ }
+ return 0;
+}
+
+static void __exit msm_sharedmem_exit(void)
+{
+ platform_driver_unregister(&msm_sharedmem_driver);
+ sharedmem_qmi_exit();
+}
+
+module_init(msm_sharedmem_init);
+module_exit(msm_sharedmem_exit);
+
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/uio/msm_sharedmem/remote_filesystem_access_v01.c b/drivers/uio/msm_sharedmem/remote_filesystem_access_v01.c
new file mode 100644
index 0000000..b04c913
--- /dev/null
+++ b/drivers/uio/msm_sharedmem/remote_filesystem_access_v01.c
@@ -0,0 +1,80 @@
+ /* Copyright (c) 2014-2015, 2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * 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/qmi_encdec.h>
+
+#include <soc/qcom/msm_qmi_interface.h>
+
+#include "remote_filesystem_access_v01.h"
+
+struct elem_info rfsa_get_buff_addr_req_msg_v01_ei[] = {
+ {
+ .data_type = QMI_UNSIGNED_4_BYTE,
+ .elem_len = 1,
+ .elem_size = sizeof(uint32_t),
+ .is_array = NO_ARRAY,
+ .tlv_type = 0x01,
+ .offset = offsetof(struct rfsa_get_buff_addr_req_msg_v01,
+ client_id),
+ },
+ {
+ .data_type = QMI_UNSIGNED_4_BYTE,
+ .elem_len = 1,
+ .elem_size = sizeof(uint32_t),
+ .is_array = NO_ARRAY,
+ .tlv_type = 0x02,
+ .offset = offsetof(struct rfsa_get_buff_addr_req_msg_v01,
+ size),
+ },
+ {
+ .data_type = QMI_EOTI,
+ .is_array = NO_ARRAY,
+ .is_array = QMI_COMMON_TLV_TYPE,
+ },
+};
+
+struct elem_info rfsa_get_buff_addr_resp_msg_v01_ei[] = {
+ {
+ .data_type = QMI_STRUCT,
+ .elem_len = 1,
+ .elem_size = sizeof(struct qmi_response_type_v01),
+ .is_array = NO_ARRAY,
+ .tlv_type = 0x02,
+ .offset = offsetof(struct rfsa_get_buff_addr_resp_msg_v01,
+ resp),
+ .ei_array = get_qmi_response_type_v01_ei(),
+ },
+ {
+ .data_type = QMI_OPT_FLAG,
+ .elem_len = 1,
+ .elem_size = sizeof(uint8_t),
+ .is_array = NO_ARRAY,
+ .tlv_type = 0x10,
+ .offset = offsetof(struct rfsa_get_buff_addr_resp_msg_v01,
+ address_valid),
+ },
+ {
+ .data_type = QMI_UNSIGNED_8_BYTE,
+ .elem_len = 1,
+ .elem_size = sizeof(uint64_t),
+ .is_array = NO_ARRAY,
+ .tlv_type = 0x10,
+ .offset = offsetof(struct rfsa_get_buff_addr_resp_msg_v01,
+ address),
+ },
+ {
+ .data_type = QMI_EOTI,
+ .is_array = NO_ARRAY,
+ .is_array = QMI_COMMON_TLV_TYPE,
+ },
+};
+
diff --git a/drivers/uio/msm_sharedmem/remote_filesystem_access_v01.h b/drivers/uio/msm_sharedmem/remote_filesystem_access_v01.h
new file mode 100644
index 0000000..7ea8ce6
--- /dev/null
+++ b/drivers/uio/msm_sharedmem/remote_filesystem_access_v01.h
@@ -0,0 +1,39 @@
+ /* Copyright (c) 2014-2015, 2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * 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 __REMOTE_FILESYSTEM_ACCESS_V01_H__
+#define __REMOTE_FILESYSTEM_ACCESS_V01_H__
+
+#define RFSA_SERVICE_ID_V01 0x1C
+#define RFSA_SERVICE_VERS_V01 0x01
+
+#define QMI_RFSA_GET_BUFF_ADDR_REQ_MSG_V01 0x0023
+#define QMI_RFSA_GET_BUFF_ADDR_RESP_MSG_V01 0x0023
+
+#define RFSA_GET_BUFF_ADDR_REQ_MSG_MAX_LEN_V01 14
+#define RFSA_GET_BUFF_ADDR_RESP_MSG_MAX_LEN_V01 18
+
+extern struct elem_info rfsa_get_buff_addr_req_msg_v01_ei[];
+extern struct elem_info rfsa_get_buff_addr_resp_msg_v01_ei[];
+
+struct rfsa_get_buff_addr_req_msg_v01 {
+ uint32_t client_id;
+ uint32_t size;
+};
+
+struct rfsa_get_buff_addr_resp_msg_v01 {
+ struct qmi_response_type_v01 resp;
+ uint8_t address_valid;
+ uint64_t address;
+};
+
+#endif /* __REMOTE_FILESYSTEM_ACCESS_V01_H__ */
diff --git a/drivers/uio/msm_sharedmem/sharedmem_qmi.c b/drivers/uio/msm_sharedmem/sharedmem_qmi.c
new file mode 100644
index 0000000..fd95dee
--- /dev/null
+++ b/drivers/uio/msm_sharedmem/sharedmem_qmi.c
@@ -0,0 +1,453 @@
+/* Copyright (c) 2014-2015, 2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#define DRIVER_NAME "msm_sharedmem"
+#define pr_fmt(fmt) DRIVER_NAME ": %s: " fmt, __func__
+
+#include <linux/err.h>
+#include <linux/module.h>
+#include <linux/rwsem.h>
+#include <linux/slab.h>
+#include <linux/list.h>
+#include <linux/debugfs.h>
+#include <soc/qcom/msm_qmi_interface.h>
+#include "sharedmem_qmi.h"
+#include "remote_filesystem_access_v01.h"
+
+#define RFSA_SERVICE_INSTANCE_NUM 1
+#define SHARED_ADDR_ENTRY_NAME_MAX_LEN 10
+
+struct shared_addr_entry {
+ u32 id;
+ u64 address;
+ u32 size;
+ u64 request_count;
+ bool is_addr_dynamic;
+ char name[SHARED_ADDR_ENTRY_NAME_MAX_LEN + 1];
+};
+
+struct shared_addr_list {
+ struct list_head node;
+ struct shared_addr_entry entry;
+};
+
+static struct shared_addr_list list;
+
+static struct qmi_handle *sharedmem_qmi_svc_handle;
+static void sharedmem_qmi_svc_recv_msg(struct work_struct *work);
+static DECLARE_DELAYED_WORK(work_recv_msg, sharedmem_qmi_svc_recv_msg);
+static struct workqueue_struct *sharedmem_qmi_svc_workqueue;
+static struct dentry *dir_ent;
+
+static u32 rfsa_count;
+static u32 rmts_count;
+
+static DECLARE_RWSEM(sharedmem_list_lock); /* declare list lock semaphore */
+
+static struct work_struct sharedmem_qmi_init_work;
+
+static struct msg_desc rfsa_get_buffer_addr_req_desc = {
+ .max_msg_len = RFSA_GET_BUFF_ADDR_REQ_MSG_MAX_LEN_V01,
+ .msg_id = QMI_RFSA_GET_BUFF_ADDR_REQ_MSG_V01,
+ .ei_array = rfsa_get_buff_addr_req_msg_v01_ei,
+};
+
+static struct msg_desc rfsa_get_buffer_addr_resp_desc = {
+ .max_msg_len = RFSA_GET_BUFF_ADDR_RESP_MSG_MAX_LEN_V01,
+ .msg_id = QMI_RFSA_GET_BUFF_ADDR_RESP_MSG_V01,
+ .ei_array = rfsa_get_buff_addr_resp_msg_v01_ei,
+};
+
+void sharedmem_qmi_add_entry(struct sharemem_qmi_entry *qmi_entry)
+{
+ struct shared_addr_list *list_entry;
+
+ list_entry = kzalloc(sizeof(*list_entry), GFP_KERNEL);
+
+ /* If we cannot add the entry log the failure and bail */
+ if (list_entry == NULL) {
+ pr_err("Alloc of new list entry failed\n");
+ return;
+ }
+
+ /* Copy as much of the client name that can fit in the entry. */
+ strlcpy(list_entry->entry.name, qmi_entry->client_name,
+ sizeof(list_entry->entry.name));
+
+ /* Setup the rest of the entry. */
+ list_entry->entry.id = qmi_entry->client_id;
+ list_entry->entry.address = qmi_entry->address;
+ list_entry->entry.size = qmi_entry->size;
+ list_entry->entry.is_addr_dynamic = qmi_entry->is_addr_dynamic;
+ list_entry->entry.request_count = 0;
+
+ down_write(&sharedmem_list_lock);
+ list_add_tail(&(list_entry->node), &(list.node));
+ up_write(&sharedmem_list_lock);
+ pr_debug("Added new entry to list\n");
+
+}
+
+static int get_buffer_for_client(u32 id, u32 size, u64 *address)
+{
+ int result = -ENOENT;
+ int client_found = 0;
+ struct list_head *curr_node;
+ struct shared_addr_list *list_entry;
+
+ if (size == 0)
+ return -ENOMEM;
+
+ down_read(&sharedmem_list_lock);
+
+ list_for_each(curr_node, &list.node) {
+ list_entry = list_entry(curr_node, struct shared_addr_list,
+ node);
+ if (list_entry->entry.id == id) {
+ if (list_entry->entry.size >= size) {
+ *address = list_entry->entry.address;
+ list_entry->entry.request_count++;
+ result = 0;
+ } else {
+ pr_err("Shared mem req too large for id=%u\n",
+ id);
+ result = -ENOMEM;
+ }
+ client_found = 1;
+ break;
+ }
+ }
+
+ up_read(&sharedmem_list_lock);
+
+ if (client_found != 1) {
+ pr_err("Unknown client id %u\n", id);
+ result = -ENOENT;
+ }
+ return result;
+}
+
+static int sharedmem_qmi_get_buffer(void *conn_h, void *req_handle, void *req)
+{
+ struct rfsa_get_buff_addr_req_msg_v01 *get_buffer_req;
+ struct rfsa_get_buff_addr_resp_msg_v01 get_buffer_resp;
+ int result;
+ u64 address = 0;
+
+ get_buffer_req = (struct rfsa_get_buff_addr_req_msg_v01 *)req;
+ pr_debug("req->client_id = 0x%X and req->size = %d\n",
+ get_buffer_req->client_id, get_buffer_req->size);
+
+ result = get_buffer_for_client(get_buffer_req->client_id,
+ get_buffer_req->size, &address);
+ if (result != 0)
+ return result;
+
+ if (address == 0) {
+ pr_err("Entry found for client id= 0x%X but address is zero\n",
+ get_buffer_req->client_id);
+ return -ENOMEM;
+ }
+
+ memset(&get_buffer_resp, 0, sizeof(get_buffer_resp));
+ get_buffer_resp.address_valid = 1;
+ get_buffer_resp.address = address;
+ get_buffer_resp.resp.result = QMI_RESULT_SUCCESS_V01;
+
+ result = qmi_send_resp_from_cb(sharedmem_qmi_svc_handle, conn_h,
+ req_handle,
+ &rfsa_get_buffer_addr_resp_desc,
+ &get_buffer_resp,
+ sizeof(get_buffer_resp));
+ return result;
+}
+
+
+static int sharedmem_qmi_connect_cb(struct qmi_handle *handle, void *conn_h)
+{
+ if (sharedmem_qmi_svc_handle != handle || !conn_h)
+ return -EINVAL;
+ return 0;
+}
+
+static int sharedmem_qmi_disconnect_cb(struct qmi_handle *handle, void *conn_h)
+{
+ if (sharedmem_qmi_svc_handle != handle || !conn_h)
+ return -EINVAL;
+ return 0;
+}
+
+static int sharedmem_qmi_req_desc_cb(unsigned int msg_id,
+ struct msg_desc **req_desc)
+{
+ int rc;
+
+ switch (msg_id) {
+ case QMI_RFSA_GET_BUFF_ADDR_REQ_MSG_V01:
+ *req_desc = &rfsa_get_buffer_addr_req_desc;
+ rc = sizeof(struct rfsa_get_buff_addr_req_msg_v01);
+ break;
+
+ default:
+ rc = -ENOTSUPP;
+ break;
+ }
+ return rc;
+}
+
+static int sharedmem_qmi_req_cb(struct qmi_handle *handle, void *conn_h,
+ void *req_handle, unsigned int msg_id,
+ void *req)
+{
+ int rc = -ENOTSUPP;
+
+ if (sharedmem_qmi_svc_handle != handle || !conn_h)
+ return -EINVAL;
+
+ if (msg_id == QMI_RFSA_GET_BUFF_ADDR_REQ_MSG_V01)
+ rc = sharedmem_qmi_get_buffer(conn_h, req_handle, req);
+
+ return rc;
+}
+
+#define DEBUG_BUF_SIZE (2048)
+static char *debug_buffer;
+static u32 debug_data_size;
+static struct mutex dbg_buf_lock; /* mutex for debug_buffer */
+
+static ssize_t debug_read(struct file *file, char __user *buf,
+ size_t count, loff_t *file_pos)
+{
+ return simple_read_from_buffer(buf, count, file_pos, debug_buffer,
+ debug_data_size);
+}
+
+static u32 fill_debug_info(char *buffer, u32 buffer_size)
+{
+ u32 size = 0;
+ struct list_head *curr_node;
+ struct shared_addr_list *list_entry;
+
+ memset(buffer, 0, buffer_size);
+ size += scnprintf(buffer + size, buffer_size - size, "\n");
+
+ down_read(&sharedmem_list_lock);
+ list_for_each(curr_node, &list.node) {
+ list_entry = list_entry(curr_node, struct shared_addr_list,
+ node);
+ size += scnprintf(buffer + size, buffer_size - size,
+ "Client_name: %s\n", list_entry->entry.name);
+ size += scnprintf(buffer + size, buffer_size - size,
+ "Client_id: 0x%08X\n", list_entry->entry.id);
+ size += scnprintf(buffer + size, buffer_size - size,
+ "Buffer Size: 0x%08X (%d)\n",
+ list_entry->entry.size,
+ list_entry->entry.size);
+ size += scnprintf(buffer + size, buffer_size - size,
+ "Address: 0x%016llX\n",
+ list_entry->entry.address);
+ size += scnprintf(buffer + size, buffer_size - size,
+ "Address Allocation: %s\n",
+ (list_entry->entry.is_addr_dynamic ?
+ "Dynamic" : "Static"));
+ size += scnprintf(buffer + size, buffer_size - size,
+ "Request count: %llu\n",
+ list_entry->entry.request_count);
+ size += scnprintf(buffer + size, buffer_size - size, "\n\n");
+ }
+ up_read(&sharedmem_list_lock);
+
+ size += scnprintf(buffer + size, buffer_size - size,
+ "RFSA server start count = %u\n", rfsa_count);
+ size += scnprintf(buffer + size, buffer_size - size,
+ "RMTS server start count = %u\n", rmts_count);
+
+ size += scnprintf(buffer + size, buffer_size - size, "\n");
+ return size;
+}
+
+static int debug_open(struct inode *inode, struct file *file)
+{
+ u32 buffer_size;
+
+ mutex_lock(&dbg_buf_lock);
+ if (debug_buffer != NULL) {
+ mutex_unlock(&dbg_buf_lock);
+ return -EBUSY;
+ }
+ buffer_size = DEBUG_BUF_SIZE;
+ debug_buffer = kzalloc(buffer_size, GFP_KERNEL);
+ if (debug_buffer == NULL) {
+ mutex_unlock(&dbg_buf_lock);
+ return -ENOMEM;
+ }
+ debug_data_size = fill_debug_info(debug_buffer, buffer_size);
+ mutex_unlock(&dbg_buf_lock);
+ return 0;
+}
+
+static int debug_close(struct inode *inode, struct file *file)
+{
+ mutex_lock(&dbg_buf_lock);
+ kfree(debug_buffer);
+ debug_buffer = NULL;
+ debug_data_size = 0;
+ mutex_unlock(&dbg_buf_lock);
+ return 0;
+}
+
+static const struct file_operations debug_ops = {
+ .read = debug_read,
+ .open = debug_open,
+ .release = debug_close,
+};
+
+static int rfsa_increment(void *data, u64 val)
+{
+ if (rfsa_count != ~0)
+ rfsa_count++;
+ return 0;
+}
+
+static int rmts_increment(void *data, u64 val)
+{
+ if (rmts_count != ~0)
+ rmts_count++;
+ return 0;
+}
+
+DEFINE_SIMPLE_ATTRIBUTE(rfsa_fops, NULL, rfsa_increment, "%llu\n");
+DEFINE_SIMPLE_ATTRIBUTE(rmts_fops, NULL, rmts_increment, "%llu\n");
+
+static void debugfs_init(void)
+{
+ struct dentry *f_ent;
+
+ mutex_init(&dbg_buf_lock);
+ dir_ent = debugfs_create_dir("rmt_storage", NULL);
+ if (IS_ERR(dir_ent)) {
+ pr_err("Failed to create debug_fs directory\n");
+ return;
+ }
+
+ f_ent = debugfs_create_file("info", 0400, dir_ent, NULL, &debug_ops);
+ if (IS_ERR(f_ent)) {
+ pr_err("Failed to create debug_fs info file\n");
+ return;
+ }
+
+ f_ent = debugfs_create_file("rfsa", 0200, dir_ent, NULL, &rfsa_fops);
+ if (IS_ERR(f_ent)) {
+ pr_err("Failed to create debug_fs rfsa file\n");
+ return;
+ }
+
+ f_ent = debugfs_create_file("rmts", 0200, dir_ent, NULL, &rmts_fops);
+ if (IS_ERR(f_ent)) {
+ pr_err("Failed to create debug_fs rmts file\n");
+ return;
+ }
+}
+
+static void debugfs_exit(void)
+{
+ debugfs_remove_recursive(dir_ent);
+ mutex_destroy(&dbg_buf_lock);
+}
+
+static void sharedmem_qmi_svc_recv_msg(struct work_struct *work)
+{
+ int rc;
+
+ do {
+ pr_debug("Notified about a Receive Event\n");
+ } while ((rc = qmi_recv_msg(sharedmem_qmi_svc_handle)) == 0);
+
+ if (rc != -ENOMSG)
+ pr_err("Error receiving message\n");
+}
+
+static void sharedmem_qmi_notify(struct qmi_handle *handle,
+ enum qmi_event_type event, void *priv)
+{
+ switch (event) {
+ case QMI_RECV_MSG:
+ queue_delayed_work(sharedmem_qmi_svc_workqueue,
+ &work_recv_msg, 0);
+ break;
+ default:
+ break;
+ }
+}
+
+static struct qmi_svc_ops_options sharedmem_qmi_ops_options = {
+ .version = 1,
+ .service_id = RFSA_SERVICE_ID_V01,
+ .service_vers = RFSA_SERVICE_VERS_V01,
+ .service_ins = RFSA_SERVICE_INSTANCE_NUM,
+ .connect_cb = sharedmem_qmi_connect_cb,
+ .disconnect_cb = sharedmem_qmi_disconnect_cb,
+ .req_desc_cb = sharedmem_qmi_req_desc_cb,
+ .req_cb = sharedmem_qmi_req_cb,
+};
+
+
+static void sharedmem_register_qmi(void)
+{
+ int rc;
+
+ sharedmem_qmi_svc_workqueue =
+ create_singlethread_workqueue("sharedmem_qmi_work");
+ if (!sharedmem_qmi_svc_workqueue)
+ return;
+
+ sharedmem_qmi_svc_handle = qmi_handle_create(sharedmem_qmi_notify,
+ NULL);
+ if (!sharedmem_qmi_svc_handle) {
+ pr_err("Creating sharedmem_qmi qmi handle failed\n");
+ destroy_workqueue(sharedmem_qmi_svc_workqueue);
+ return;
+ }
+ rc = qmi_svc_register(sharedmem_qmi_svc_handle,
+ &sharedmem_qmi_ops_options);
+ if (rc < 0) {
+ pr_err("Registering sharedmem_qmi failed %d\n", rc);
+ qmi_handle_destroy(sharedmem_qmi_svc_handle);
+ destroy_workqueue(sharedmem_qmi_svc_workqueue);
+ return;
+ }
+ pr_info("qmi init successful\n");
+}
+
+static void sharedmem_qmi_init_worker(struct work_struct *work)
+{
+ sharedmem_register_qmi();
+ debugfs_init();
+}
+
+int sharedmem_qmi_init(void)
+{
+ INIT_LIST_HEAD(&list.node);
+ INIT_WORK(&sharedmem_qmi_init_work, sharedmem_qmi_init_worker);
+ schedule_work(&sharedmem_qmi_init_work);
+ return 0;
+}
+
+void sharedmem_qmi_exit(void)
+{
+ qmi_svc_unregister(sharedmem_qmi_svc_handle);
+ flush_workqueue(sharedmem_qmi_svc_workqueue);
+ qmi_handle_destroy(sharedmem_qmi_svc_handle);
+ destroy_workqueue(sharedmem_qmi_svc_workqueue);
+ debugfs_exit();
+}
diff --git a/drivers/uio/msm_sharedmem/sharedmem_qmi.h b/drivers/uio/msm_sharedmem/sharedmem_qmi.h
new file mode 100644
index 0000000..7353916
--- /dev/null
+++ b/drivers/uio/msm_sharedmem/sharedmem_qmi.h
@@ -0,0 +1,33 @@
+/* Copyright (c) 2014-2015, 2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * 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 __SHAREDMEM_QMI_H__
+#define __SHAREDMEM_QMI_H__
+
+#include <linux/module.h>
+
+struct sharemem_qmi_entry {
+ const char *client_name;
+ u32 client_id;
+ u64 address;
+ u32 size;
+ bool is_addr_dynamic;
+};
+
+int sharedmem_qmi_init(void);
+
+void sharedmem_qmi_exit(void);
+
+void sharedmem_qmi_add_entry(struct sharemem_qmi_entry *qmi_entry);
+
+#endif /* __SHAREDMEM_QMI_H__ */
diff --git a/drivers/usb/gadget/function/f_diag.c b/drivers/usb/gadget/function/f_diag.c
index 51e6104..e908ecf 100644
--- a/drivers/usb/gadget/function/f_diag.c
+++ b/drivers/usb/gadget/function/f_diag.c
@@ -307,21 +307,8 @@
ctxt->dpkts_tolaptop_pending--;
- if (!req->status) {
- if ((req->length >= ep->maxpacket) &&
- ((req->length % ep->maxpacket) == 0)) {
- ctxt->dpkts_tolaptop_pending++;
- req->length = 0;
- d_req->actual = req->actual;
- d_req->status = req->status;
- /* Queue zero length packet */
- if (!usb_ep_queue(ctxt->in, req, GFP_ATOMIC))
- return;
- ctxt->dpkts_tolaptop_pending--;
- } else {
- ctxt->dpkts_tolaptop++;
- }
- }
+ if (!req->status)
+ ctxt->dpkts_tolaptop++;
spin_lock_irqsave(&ctxt->lock, flags);
list_add_tail(&req->list, &ctxt->write_pool);
@@ -481,6 +468,7 @@
goto fail;
kmemleak_not_leak(req);
req->complete = diag_write_complete;
+ req->zero = true;
list_add_tail(&req->list, &ctxt->write_pool);
}
diff --git a/drivers/usb/gadget/function/f_mass_storage.c b/drivers/usb/gadget/function/f_mass_storage.c
index 54e14b1..cca261e 100644
--- a/drivers/usb/gadget/function/f_mass_storage.c
+++ b/drivers/usb/gadget/function/f_mass_storage.c
@@ -2285,16 +2285,15 @@
fsg->bulk_out_enabled = 0;
}
+ /* allow usb LPM after eps are disabled */
+ usb_gadget_autopm_put_async(common->gadget);
common->fsg = NULL;
wake_up(&common->fsg_wait);
}
common->running = 0;
- if (!new_fsg || rc) {
- /* allow usb LPM after eps are disabled */
- usb_gadget_autopm_put_async(common->gadget);
+ if (!new_fsg || rc)
return rc;
- }
common->fsg = new_fsg;
fsg = common->fsg;
diff --git a/drivers/usb/gadget/function/f_mtp.c b/drivers/usb/gadget/function/f_mtp.c
index c6aa884..aaa0fc2 100644
--- a/drivers/usb/gadget/function/f_mtp.c
+++ b/drivers/usb/gadget/function/f_mtp.c
@@ -587,11 +587,17 @@
struct mtp_dev *dev = fp->private_data;
struct usb_composite_dev *cdev = dev->cdev;
struct usb_request *req;
- ssize_t r = count, xfer, len;
+ ssize_t r = count;
+ unsigned xfer;
int ret = 0;
+ size_t len;
DBG(cdev, "mtp_read(%zu) state:%d\n", count, dev->state);
+ len = usb_ep_align_maybe(cdev->gadget, dev->ep_out, count);
+ if (len > MTP_BULK_BUFFER_SIZE)
+ return -EINVAL;
+
/* we will block until we're online */
DBG(cdev, "mtp_read: waiting for online state\n");
ret = wait_event_interruptible(dev->read_wq,
diff --git a/drivers/video/fbdev/efifb.c b/drivers/video/fbdev/efifb.c
index 37a37c4..6f2e729 100644
--- a/drivers/video/fbdev/efifb.c
+++ b/drivers/video/fbdev/efifb.c
@@ -10,6 +10,7 @@
#include <linux/efi.h>
#include <linux/errno.h>
#include <linux/fb.h>
+#include <linux/pci.h>
#include <linux/platform_device.h>
#include <linux/screen_info.h>
#include <video/vga.h>
@@ -118,6 +119,8 @@
return false;
}
+static bool pci_dev_disabled; /* FB base matches BAR of a disabled device */
+
static int efifb_probe(struct platform_device *dev)
{
struct fb_info *info;
@@ -127,7 +130,7 @@
unsigned int size_total;
char *option = NULL;
- if (screen_info.orig_video_isVGA != VIDEO_TYPE_EFI)
+ if (screen_info.orig_video_isVGA != VIDEO_TYPE_EFI || pci_dev_disabled)
return -ENODEV;
if (fb_get_options("efifb", &option))
@@ -327,3 +330,64 @@
};
builtin_platform_driver(efifb_driver);
+
+#if defined(CONFIG_PCI) && !defined(CONFIG_X86)
+
+static bool pci_bar_found; /* did we find a BAR matching the efifb base? */
+
+static void claim_efifb_bar(struct pci_dev *dev, int idx)
+{
+ u16 word;
+
+ pci_bar_found = true;
+
+ pci_read_config_word(dev, PCI_COMMAND, &word);
+ if (!(word & PCI_COMMAND_MEMORY)) {
+ pci_dev_disabled = true;
+ dev_err(&dev->dev,
+ "BAR %d: assigned to efifb but device is disabled!\n",
+ idx);
+ return;
+ }
+
+ if (pci_claim_resource(dev, idx)) {
+ pci_dev_disabled = true;
+ dev_err(&dev->dev,
+ "BAR %d: failed to claim resource for efifb!\n", idx);
+ return;
+ }
+
+ dev_info(&dev->dev, "BAR %d: assigned to efifb\n", idx);
+}
+
+static void efifb_fixup_resources(struct pci_dev *dev)
+{
+ u64 base = screen_info.lfb_base;
+ u64 size = screen_info.lfb_size;
+ int i;
+
+ if (pci_bar_found || screen_info.orig_video_isVGA != VIDEO_TYPE_EFI)
+ return;
+
+ if (screen_info.capabilities & VIDEO_CAPABILITY_64BIT_BASE)
+ base |= (u64)screen_info.ext_lfb_base << 32;
+
+ if (!base)
+ return;
+
+ for (i = 0; i < PCI_STD_RESOURCE_END; i++) {
+ struct resource *res = &dev->resource[i];
+
+ if (!(res->flags & IORESOURCE_MEM))
+ continue;
+
+ if (res->start <= base && res->end >= base + size - 1) {
+ claim_efifb_bar(dev, i);
+ break;
+ }
+ }
+}
+DECLARE_PCI_FIXUP_CLASS_HEADER(PCI_ANY_ID, PCI_ANY_ID, PCI_BASE_CLASS_DISPLAY,
+ 16, efifb_fixup_resources);
+
+#endif
diff --git a/drivers/video/fbdev/xen-fbfront.c b/drivers/video/fbdev/xen-fbfront.c
index 0567d51..ea2f19f 100644
--- a/drivers/video/fbdev/xen-fbfront.c
+++ b/drivers/video/fbdev/xen-fbfront.c
@@ -644,7 +644,6 @@
break;
case XenbusStateInitWait:
-InitWait:
xenbus_switch_state(dev, XenbusStateConnected);
break;
@@ -655,7 +654,8 @@
* get Connected twice here.
*/
if (dev->state != XenbusStateConnected)
- goto InitWait; /* no InitWait seen yet, fudge it */
+ /* no InitWait seen yet, fudge it */
+ xenbus_switch_state(dev, XenbusStateConnected);
if (xenbus_scanf(XBT_NIL, info->xbdev->otherend,
"request-update", "%d", &val) < 0)
diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h
index 203287f..94661cf 100644
--- a/fs/cifs/cifsglob.h
+++ b/fs/cifs/cifsglob.h
@@ -930,7 +930,6 @@
bool use_persistent:1; /* use persistent instead of durable handles */
#ifdef CONFIG_CIFS_SMB2
bool print:1; /* set if connection to printer share */
- bool bad_network_name:1; /* set if ret status STATUS_BAD_NETWORK_NAME */
__le32 capabilities;
__u32 share_flags;
__u32 maximal_access;
diff --git a/fs/cifs/file.c b/fs/cifs/file.c
index 1cd0e2e..3925758 100644
--- a/fs/cifs/file.c
+++ b/fs/cifs/file.c
@@ -2597,7 +2597,7 @@
wdata->credits = credits;
if (!wdata->cfile->invalidHandle ||
- !cifs_reopen_file(wdata->cfile, false))
+ !(rc = cifs_reopen_file(wdata->cfile, false)))
rc = server->ops->async_writev(wdata,
cifs_uncached_writedata_release);
if (rc) {
@@ -3002,7 +3002,7 @@
rdata->credits = credits;
if (!rdata->cfile->invalidHandle ||
- !cifs_reopen_file(rdata->cfile, true))
+ !(rc = cifs_reopen_file(rdata->cfile, true)))
rc = server->ops->async_readv(rdata);
error:
if (rc) {
@@ -3577,7 +3577,7 @@
}
if (!rdata->cfile->invalidHandle ||
- !cifs_reopen_file(rdata->cfile, true))
+ !(rc = cifs_reopen_file(rdata->cfile, true)))
rc = server->ops->async_readv(rdata);
if (rc) {
add_credits_and_wake_if(server, rdata->credits, 0);
diff --git a/fs/cifs/smb1ops.c b/fs/cifs/smb1ops.c
index fc537c2..87b87e0 100644
--- a/fs/cifs/smb1ops.c
+++ b/fs/cifs/smb1ops.c
@@ -1015,6 +1015,15 @@
return !cfile->srch_inf.endOfSearch && !cfile->invalidHandle;
}
+static bool
+cifs_can_echo(struct TCP_Server_Info *server)
+{
+ if (server->tcpStatus == CifsGood)
+ return true;
+
+ return false;
+}
+
struct smb_version_operations smb1_operations = {
.send_cancel = send_nt_cancel,
.compare_fids = cifs_compare_fids,
@@ -1049,6 +1058,7 @@
.get_dfs_refer = CIFSGetDFSRefer,
.qfs_tcon = cifs_qfs_tcon,
.is_path_accessible = cifs_is_path_accessible,
+ .can_echo = cifs_can_echo,
.query_path_info = cifs_query_path_info,
.query_file_info = cifs_query_file_info,
.get_srv_inum = cifs_get_srv_inum,
diff --git a/fs/cifs/smb2pdu.c b/fs/cifs/smb2pdu.c
index bdd3292..8021853 100644
--- a/fs/cifs/smb2pdu.c
+++ b/fs/cifs/smb2pdu.c
@@ -1084,9 +1084,6 @@
else
return -EIO;
- if (tcon && tcon->bad_network_name)
- return -ENOENT;
-
if ((tcon && tcon->seal) &&
((ses->server->capabilities & SMB2_GLOBAL_CAP_ENCRYPTION) == 0)) {
cifs_dbg(VFS, "encryption requested but no server support");
@@ -1188,8 +1185,6 @@
tcon_error_exit:
if (rsp->hdr.Status == STATUS_BAD_NETWORK_NAME) {
cifs_dbg(VFS, "BAD_NETWORK_NAME: %s\n", tree);
- if (tcon)
- tcon->bad_network_name = true;
}
goto tcon_exit;
}
@@ -1987,6 +1982,9 @@
struct cifs_tcon *tcon, *tcon2;
struct list_head tmp_list;
int tcon_exist = false;
+ int rc;
+ int resched = false;
+
/* Prevent simultaneous reconnects that can corrupt tcon->rlist list */
mutex_lock(&server->reconnect_mutex);
@@ -2014,13 +2012,18 @@
spin_unlock(&cifs_tcp_ses_lock);
list_for_each_entry_safe(tcon, tcon2, &tmp_list, rlist) {
- if (!smb2_reconnect(SMB2_INTERNAL_CMD, tcon))
+ rc = smb2_reconnect(SMB2_INTERNAL_CMD, tcon);
+ if (!rc)
cifs_reopen_persistent_handles(tcon);
+ else
+ resched = true;
list_del_init(&tcon->rlist);
cifs_put_tcon(tcon);
}
cifs_dbg(FYI, "Reconnecting tcons finished\n");
+ if (resched)
+ queue_delayed_work(cifsiod_wq, &server->reconnect, 2 * HZ);
mutex_unlock(&server->reconnect_mutex);
/* now we can safely release srv struct */
diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c
index a826864..3cb7fa2 100644
--- a/fs/ext4/inode.c
+++ b/fs/ext4/inode.c
@@ -72,10 +72,9 @@
csum = ext4_chksum(sbi, csum, (__u8 *)&dummy_csum,
csum_size);
offset += csum_size;
- csum = ext4_chksum(sbi, csum, (__u8 *)raw + offset,
- EXT4_INODE_SIZE(inode->i_sb) -
- offset);
}
+ csum = ext4_chksum(sbi, csum, (__u8 *)raw + offset,
+ EXT4_INODE_SIZE(inode->i_sb) - offset);
}
return csum;
diff --git a/fs/orangefs/devorangefs-req.c b/fs/orangefs/devorangefs-req.c
index f419dd9..fe2cbeb 100644
--- a/fs/orangefs/devorangefs-req.c
+++ b/fs/orangefs/devorangefs-req.c
@@ -208,14 +208,19 @@
continue;
/*
* Skip ops whose filesystem we don't know about unless
- * it is being mounted.
+ * it is being mounted or unmounted. It is possible for
+ * a filesystem we don't know about to be unmounted if
+ * it fails to mount in the kernel after userspace has
+ * been sent the mount request.
*/
/* XXX: is there a better way to detect this? */
} else if (ret == -1 &&
!(op->upcall.type ==
ORANGEFS_VFS_OP_FS_MOUNT ||
op->upcall.type ==
- ORANGEFS_VFS_OP_GETATTR)) {
+ ORANGEFS_VFS_OP_GETATTR ||
+ op->upcall.type ==
+ ORANGEFS_VFS_OP_FS_UMOUNT)) {
gossip_debug(GOSSIP_DEV_DEBUG,
"orangefs: skipping op tag %llu %s\n",
llu(op->tag), get_opname_string(op));
diff --git a/fs/orangefs/orangefs-kernel.h b/fs/orangefs/orangefs-kernel.h
index 3bf803d..45dd8f2 100644
--- a/fs/orangefs/orangefs-kernel.h
+++ b/fs/orangefs/orangefs-kernel.h
@@ -249,6 +249,7 @@
char devname[ORANGEFS_MAX_SERVER_ADDR_LEN];
struct super_block *sb;
int mount_pending;
+ int no_list;
struct list_head list;
};
diff --git a/fs/orangefs/super.c b/fs/orangefs/super.c
index cd261c8..629d8c9 100644
--- a/fs/orangefs/super.c
+++ b/fs/orangefs/super.c
@@ -493,7 +493,7 @@
if (ret) {
d = ERR_PTR(ret);
- goto free_op;
+ goto free_sb_and_op;
}
/*
@@ -519,6 +519,9 @@
spin_unlock(&orangefs_superblocks_lock);
op_release(new_op);
+ /* Must be removed from the list now. */
+ ORANGEFS_SB(sb)->no_list = 0;
+
if (orangefs_userspace_version >= 20906) {
new_op = op_alloc(ORANGEFS_VFS_OP_FEATURES);
if (!new_op)
@@ -533,6 +536,10 @@
return dget(sb->s_root);
+free_sb_and_op:
+ /* Will call orangefs_kill_sb with sb not in list. */
+ ORANGEFS_SB(sb)->no_list = 1;
+ deactivate_locked_super(sb);
free_op:
gossip_err("orangefs_mount: mount request failed with %d\n", ret);
if (ret == -EINVAL) {
@@ -558,12 +565,14 @@
*/
orangefs_unmount_sb(sb);
- /* remove the sb from our list of orangefs specific sb's */
-
- spin_lock(&orangefs_superblocks_lock);
- __list_del_entry(&ORANGEFS_SB(sb)->list); /* not list_del_init */
- ORANGEFS_SB(sb)->list.prev = NULL;
- spin_unlock(&orangefs_superblocks_lock);
+ if (!ORANGEFS_SB(sb)->no_list) {
+ /* remove the sb from our list of orangefs specific sb's */
+ spin_lock(&orangefs_superblocks_lock);
+ /* not list_del_init */
+ __list_del_entry(&ORANGEFS_SB(sb)->list);
+ ORANGEFS_SB(sb)->list.prev = NULL;
+ spin_unlock(&orangefs_superblocks_lock);
+ }
/*
* make sure that ORANGEFS_DEV_REMOUNT_ALL loop that might've seen us
diff --git a/fs/proc/task_mmu.c b/fs/proc/task_mmu.c
index 65d28f9..f998332 100644
--- a/fs/proc/task_mmu.c
+++ b/fs/proc/task_mmu.c
@@ -962,7 +962,14 @@
static inline void clear_soft_dirty_pmd(struct vm_area_struct *vma,
unsigned long addr, pmd_t *pmdp)
{
- pmd_t pmd = pmdp_huge_get_and_clear(vma->vm_mm, addr, pmdp);
+ pmd_t pmd = *pmdp;
+
+ /* See comment in change_huge_pmd() */
+ pmdp_invalidate(vma, addr, pmdp);
+ if (pmd_dirty(*pmdp))
+ pmd = pmd_mkdirty(pmd);
+ if (pmd_young(*pmdp))
+ pmd = pmd_mkyoung(pmd);
pmd = pmd_wrprotect(pmd);
pmd = pmd_clear_soft_dirty(pmd);
diff --git a/fs/sdcardfs/derived_perm.c b/fs/sdcardfs/derived_perm.c
index 14747a8..2964527 100644
--- a/fs/sdcardfs/derived_perm.c
+++ b/fs/sdcardfs/derived_perm.c
@@ -222,7 +222,7 @@
break;
case PERM_ANDROID_PACKAGE_CACHE:
if (info->d_uid != 0)
- gid = multiuser_get_cache_gid(info->d_uid);
+ gid = multiuser_get_ext_cache_gid(info->d_uid);
else
gid = multiuser_get_uid(info->userid, uid);
break;
@@ -252,7 +252,7 @@
goto retry_deleg;
}
if (error)
- pr_err("sdcardfs: Failed to touch up lower fs gid/uid.\n");
+ pr_debug("sdcardfs: Failed to touch up lower fs gid/uid for %s\n", name);
}
sdcardfs_put_lower_path(dentry, &path);
}
diff --git a/fs/sdcardfs/lookup.c b/fs/sdcardfs/lookup.c
index f9c0282..19154b7 100644
--- a/fs/sdcardfs/lookup.c
+++ b/fs/sdcardfs/lookup.c
@@ -91,7 +91,9 @@
struct sdcardfs_inode_info *info;
struct inode_data data;
struct inode *inode; /* the new inode to return */
- int err;
+
+ if (!igrab(lower_inode))
+ return ERR_PTR(-ESTALE);
data.id = id;
data.lower_inode = lower_inode;
@@ -106,22 +108,19 @@
sdcardfs_inode_set, /* inode init function */
&data); /* data passed to test+set fxns */
if (!inode) {
- err = -EACCES;
iput(lower_inode);
- return ERR_PTR(err);
+ return ERR_PTR(-ENOMEM);
}
- /* if found a cached inode, then just return it */
- if (!(inode->i_state & I_NEW))
+ /* if found a cached inode, then just return it (after iput) */
+ if (!(inode->i_state & I_NEW)) {
+ iput(lower_inode);
return inode;
+ }
/* initialize new inode */
info = SDCARDFS_I(inode);
inode->i_ino = lower_inode->i_ino;
- if (!igrab(lower_inode)) {
- err = -ESTALE;
- return ERR_PTR(err);
- }
sdcardfs_set_lower_inode(inode, lower_inode);
inode->i_version++;
diff --git a/fs/sdcardfs/multiuser.h b/fs/sdcardfs/multiuser.h
index 2e89b58..d0c925c 100644
--- a/fs/sdcardfs/multiuser.h
+++ b/fs/sdcardfs/multiuser.h
@@ -23,6 +23,8 @@
#define AID_APP_END 19999 /* last app user */
#define AID_CACHE_GID_START 20000 /* start of gids for apps to mark cached data */
#define AID_EXT_GID_START 30000 /* start of gids for apps to mark external data */
+#define AID_EXT_CACHE_GID_START 40000 /* start of gids for apps to mark external cached data */
+#define AID_EXT_CACHE_GID_END 49999 /* end of gids for apps to mark external cached data */
#define AID_SHARED_GID_START 50000 /* start of gids for apps in each user to share */
typedef uid_t userid_t;
@@ -33,9 +35,9 @@
return (user_id * AID_USER_OFFSET) + (app_id % AID_USER_OFFSET);
}
-static inline gid_t multiuser_get_cache_gid(uid_t uid)
+static inline gid_t multiuser_get_ext_cache_gid(uid_t uid)
{
- return uid - AID_APP_START + AID_CACHE_GID_START;
+ return uid - AID_APP_START + AID_EXT_CACHE_GID_START;
}
static inline gid_t multiuser_get_ext_gid(uid_t uid)
diff --git a/fs/ubifs/dir.c b/fs/ubifs/dir.c
index ca16c5d..87ab02e 100644
--- a/fs/ubifs/dir.c
+++ b/fs/ubifs/dir.c
@@ -622,6 +622,11 @@
return err;
lock_2_inodes(dir, inode);
+
+ /* Handle O_TMPFILE corner case, it is allowed to link a O_TMPFILE. */
+ if (inode->i_nlink == 0)
+ ubifs_delete_orphan(c, inode->i_ino);
+
inc_nlink(inode);
ihold(inode);
inode->i_ctime = ubifs_current_time(inode);
@@ -641,6 +646,8 @@
dir->i_size -= sz_change;
dir_ui->ui_size = dir->i_size;
drop_nlink(inode);
+ if (inode->i_nlink == 0)
+ ubifs_add_orphan(c, inode->i_ino);
unlock_2_inodes(dir, inode);
ubifs_release_budget(c, &req);
iput(inode);
@@ -1088,9 +1095,6 @@
struct timespec time;
unsigned int uninitialized_var(saved_nlink);
- if (flags & ~RENAME_NOREPLACE)
- return -EINVAL;
-
/*
* Budget request settings: deletion direntry, new direntry, removing
* the old inode, and changing old and new parent directory inodes.
diff --git a/include/crypto/internal/hash.h b/include/crypto/internal/hash.h
index 1d4f365..f6d9af3e 100644
--- a/include/crypto/internal/hash.h
+++ b/include/crypto/internal/hash.h
@@ -166,6 +166,16 @@
return crypto_alloc_instance2(name, alg, ahash_instance_headroom());
}
+static inline void ahash_request_complete(struct ahash_request *req, int err)
+{
+ req->base.complete(&req->base, err);
+}
+
+static inline u32 ahash_request_flags(struct ahash_request *req)
+{
+ return req->base.flags;
+}
+
static inline struct crypto_ahash *crypto_spawn_ahash(
struct crypto_ahash_spawn *spawn)
{
diff --git a/include/dt-bindings/clock/qcom,aop-qmp.h b/include/dt-bindings/clock/qcom,aop-qmp.h
new file mode 100644
index 0000000..b88dc36
--- /dev/null
+++ b/include/dt-bindings/clock/qcom,aop-qmp.h
@@ -0,0 +1,29 @@
+/*
+ * 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 _DT_BINDINGS_CLK_QCOM_AOP_QMP_H
+#define _DT_BINDINGS_CLK_QCOM_AOP_QMP_H
+
+#define QDSS_CLK_LEVEL_OFF 0
+#define QDSS_CLK_LEVEL_DYNAMIC 1
+#define QDSS_CLK_LEVEL_TURBO 2
+#define QDSS_CLK_LEVEL_NOMINAL 3
+#define QDSS_CLK_LEVEL_SVS_L1 4
+#define QDSS_CLK_LEVEL_SVS 5
+#define QDSS_CLK_LEVEL_LOW_SVS 6
+#define QDSS_CLK_LEVEL_MIN_SVS 7
+
+/* clocks id */
+#define QDSS_CLK 0
+
+#endif
diff --git a/include/dt-bindings/clock/qcom,camcc-sdm845.h b/include/dt-bindings/clock/qcom,camcc-sdm845.h
index e169172..0d9d9f6 100644
--- a/include/dt-bindings/clock/qcom,camcc-sdm845.h
+++ b/include/dt-bindings/clock/qcom,camcc-sdm845.h
@@ -34,71 +34,70 @@
#define CAM_CC_CSIPHY0_CLK 17
#define CAM_CC_CSIPHY1_CLK 18
#define CAM_CC_CSIPHY2_CLK 19
-#define CAM_CC_DEBUG_CLK 20
-#define CAM_CC_FAST_AHB_CLK_SRC 21
-#define CAM_CC_FD_CORE_CLK 22
-#define CAM_CC_FD_CORE_CLK_SRC 23
-#define CAM_CC_FD_CORE_UAR_CLK 24
-#define CAM_CC_ICP_APB_CLK 25
-#define CAM_CC_ICP_ATB_CLK 26
-#define CAM_CC_ICP_CLK 27
-#define CAM_CC_ICP_CLK_SRC 28
-#define CAM_CC_ICP_CTI_CLK 29
-#define CAM_CC_ICP_TS_CLK 30
-#define CAM_CC_IFE_0_AXI_CLK 31
-#define CAM_CC_IFE_0_CLK 32
-#define CAM_CC_IFE_0_CLK_SRC 33
-#define CAM_CC_IFE_0_CPHY_RX_CLK 34
-#define CAM_CC_IFE_0_CSID_CLK 35
-#define CAM_CC_IFE_0_CSID_CLK_SRC 36
-#define CAM_CC_IFE_0_DSP_CLK 37
-#define CAM_CC_IFE_1_AXI_CLK 38
-#define CAM_CC_IFE_1_CLK 39
-#define CAM_CC_IFE_1_CLK_SRC 40
-#define CAM_CC_IFE_1_CPHY_RX_CLK 41
-#define CAM_CC_IFE_1_CSID_CLK 42
-#define CAM_CC_IFE_1_CSID_CLK_SRC 43
-#define CAM_CC_IFE_1_DSP_CLK 44
-#define CAM_CC_IFE_LITE_CLK 45
-#define CAM_CC_IFE_LITE_CLK_SRC 46
-#define CAM_CC_IFE_LITE_CPHY_RX_CLK 47
-#define CAM_CC_IFE_LITE_CSID_CLK 48
-#define CAM_CC_IFE_LITE_CSID_CLK_SRC 49
-#define CAM_CC_IPE_0_AHB_CLK 50
-#define CAM_CC_IPE_0_AREG_CLK 51
-#define CAM_CC_IPE_0_AXI_CLK 52
-#define CAM_CC_IPE_0_CLK 53
-#define CAM_CC_IPE_0_CLK_SRC 54
-#define CAM_CC_IPE_1_AHB_CLK 55
-#define CAM_CC_IPE_1_AREG_CLK 56
-#define CAM_CC_IPE_1_AXI_CLK 57
-#define CAM_CC_IPE_1_CLK 58
-#define CAM_CC_IPE_1_CLK_SRC 59
-#define CAM_CC_JPEG_CLK 60
-#define CAM_CC_JPEG_CLK_SRC 61
-#define CAM_CC_LRME_CLK 62
-#define CAM_CC_LRME_CLK_SRC 63
-#define CAM_CC_MCLK0_CLK 64
-#define CAM_CC_MCLK0_CLK_SRC 65
-#define CAM_CC_MCLK1_CLK 66
-#define CAM_CC_MCLK1_CLK_SRC 67
-#define CAM_CC_MCLK2_CLK 68
-#define CAM_CC_MCLK2_CLK_SRC 69
-#define CAM_CC_MCLK3_CLK 70
-#define CAM_CC_MCLK3_CLK_SRC 71
-#define CAM_CC_PLL0 72
-#define CAM_CC_PLL0_OUT_EVEN 73
-#define CAM_CC_PLL1 74
-#define CAM_CC_PLL1_OUT_EVEN 75
-#define CAM_CC_PLL2 76
-#define CAM_CC_PLL2_OUT_EVEN 77
-#define CAM_CC_PLL2_OUT_ODD 78
-#define CAM_CC_PLL3 79
-#define CAM_CC_PLL3_OUT_EVEN 80
-#define CAM_CC_PLL_TEST_CLK 81
-#define CAM_CC_SLOW_AHB_CLK_SRC 82
-#define CAM_CC_SOC_AHB_CLK 83
-#define CAM_CC_SYS_TMR_CLK 84
+#define CAM_CC_FAST_AHB_CLK_SRC 20
+#define CAM_CC_FD_CORE_CLK 21
+#define CAM_CC_FD_CORE_CLK_SRC 22
+#define CAM_CC_FD_CORE_UAR_CLK 23
+#define CAM_CC_ICP_APB_CLK 24
+#define CAM_CC_ICP_ATB_CLK 25
+#define CAM_CC_ICP_CLK 26
+#define CAM_CC_ICP_CLK_SRC 27
+#define CAM_CC_ICP_CTI_CLK 28
+#define CAM_CC_ICP_TS_CLK 29
+#define CAM_CC_IFE_0_AXI_CLK 30
+#define CAM_CC_IFE_0_CLK 31
+#define CAM_CC_IFE_0_CLK_SRC 32
+#define CAM_CC_IFE_0_CPHY_RX_CLK 33
+#define CAM_CC_IFE_0_CSID_CLK 34
+#define CAM_CC_IFE_0_CSID_CLK_SRC 35
+#define CAM_CC_IFE_0_DSP_CLK 36
+#define CAM_CC_IFE_1_AXI_CLK 37
+#define CAM_CC_IFE_1_CLK 38
+#define CAM_CC_IFE_1_CLK_SRC 39
+#define CAM_CC_IFE_1_CPHY_RX_CLK 40
+#define CAM_CC_IFE_1_CSID_CLK 41
+#define CAM_CC_IFE_1_CSID_CLK_SRC 42
+#define CAM_CC_IFE_1_DSP_CLK 43
+#define CAM_CC_IFE_LITE_CLK 44
+#define CAM_CC_IFE_LITE_CLK_SRC 45
+#define CAM_CC_IFE_LITE_CPHY_RX_CLK 46
+#define CAM_CC_IFE_LITE_CSID_CLK 47
+#define CAM_CC_IFE_LITE_CSID_CLK_SRC 48
+#define CAM_CC_IPE_0_AHB_CLK 49
+#define CAM_CC_IPE_0_AREG_CLK 50
+#define CAM_CC_IPE_0_AXI_CLK 51
+#define CAM_CC_IPE_0_CLK 52
+#define CAM_CC_IPE_0_CLK_SRC 53
+#define CAM_CC_IPE_1_AHB_CLK 54
+#define CAM_CC_IPE_1_AREG_CLK 55
+#define CAM_CC_IPE_1_AXI_CLK 56
+#define CAM_CC_IPE_1_CLK 57
+#define CAM_CC_IPE_1_CLK_SRC 58
+#define CAM_CC_JPEG_CLK 59
+#define CAM_CC_JPEG_CLK_SRC 60
+#define CAM_CC_LRME_CLK 61
+#define CAM_CC_LRME_CLK_SRC 62
+#define CAM_CC_MCLK0_CLK 63
+#define CAM_CC_MCLK0_CLK_SRC 64
+#define CAM_CC_MCLK1_CLK 65
+#define CAM_CC_MCLK1_CLK_SRC 66
+#define CAM_CC_MCLK2_CLK 67
+#define CAM_CC_MCLK2_CLK_SRC 68
+#define CAM_CC_MCLK3_CLK 69
+#define CAM_CC_MCLK3_CLK_SRC 70
+#define CAM_CC_PLL0 71
+#define CAM_CC_PLL0_OUT_EVEN 72
+#define CAM_CC_PLL1 73
+#define CAM_CC_PLL1_OUT_EVEN 74
+#define CAM_CC_PLL2 75
+#define CAM_CC_PLL2_OUT_EVEN 76
+#define CAM_CC_PLL2_OUT_ODD 77
+#define CAM_CC_PLL3 78
+#define CAM_CC_PLL3_OUT_EVEN 79
+#define CAM_CC_PLL_TEST_CLK 80
+#define CAM_CC_SLOW_AHB_CLK_SRC 81
+#define CAM_CC_SOC_AHB_CLK 82
+#define CAM_CC_SYS_TMR_CLK 83
#define TITAN_CAM_CC_BPS_BCR 0
#define TITAN_CAM_CC_CAMNOC_BCR 1
diff --git a/include/dt-bindings/clock/qcom,dispcc-sdm845.h b/include/dt-bindings/clock/qcom,dispcc-sdm845.h
index b1988e4..24dd11e 100644
--- a/include/dt-bindings/clock/qcom,dispcc-sdm845.h
+++ b/include/dt-bindings/clock/qcom,dispcc-sdm845.h
@@ -14,49 +14,48 @@
#ifndef _DT_BINDINGS_CLK_MSM_DISP_CC_SDM845_H
#define _DT_BINDINGS_CLK_MSM_DISP_CC_SDM845_H
-#define DISP_CC_DEBUG_CLK 0
-#define DISP_CC_MDSS_AHB_CLK 1
-#define DISP_CC_MDSS_AXI_CLK 2
-#define DISP_CC_MDSS_BYTE0_CLK 3
-#define DISP_CC_MDSS_BYTE0_CLK_SRC 4
-#define DISP_CC_MDSS_BYTE0_INTF_CLK 5
-#define DISP_CC_MDSS_BYTE1_CLK 6
-#define DISP_CC_MDSS_BYTE1_CLK_SRC 7
-#define DISP_CC_MDSS_BYTE1_INTF_CLK 8
-#define DISP_CC_MDSS_DP_AUX_CLK 9
-#define DISP_CC_MDSS_DP_AUX_CLK_SRC 10
-#define DISP_CC_MDSS_DP_CRYPTO_CLK 11
-#define DISP_CC_MDSS_DP_CRYPTO_CLK_SRC 12
-#define DISP_CC_MDSS_DP_LINK_CLK 13
-#define DISP_CC_MDSS_DP_LINK_CLK_SRC 14
-#define DISP_CC_MDSS_DP_LINK_INTF_CLK 15
-#define DISP_CC_MDSS_DP_PIXEL1_CLK 16
-#define DISP_CC_MDSS_DP_PIXEL1_CLK_SRC 17
-#define DISP_CC_MDSS_DP_PIXEL_CLK 18
-#define DISP_CC_MDSS_DP_PIXEL_CLK_SRC 19
-#define DISP_CC_MDSS_ESC0_CLK 20
-#define DISP_CC_MDSS_ESC0_CLK_SRC 21
-#define DISP_CC_MDSS_ESC1_CLK 22
-#define DISP_CC_MDSS_ESC1_CLK_SRC 23
-#define DISP_CC_MDSS_MDP_CLK 24
-#define DISP_CC_MDSS_MDP_CLK_SRC 25
-#define DISP_CC_MDSS_MDP_LUT_CLK 26
-#define DISP_CC_MDSS_PCLK0_CLK 27
-#define DISP_CC_MDSS_PCLK0_CLK_SRC 28
-#define DISP_CC_MDSS_PCLK1_CLK 29
-#define DISP_CC_MDSS_PCLK1_CLK_SRC 30
-#define DISP_CC_MDSS_QDSS_AT_CLK 31
-#define DISP_CC_MDSS_QDSS_TSCTR_DIV8_CLK 32
-#define DISP_CC_MDSS_ROT_CLK 33
-#define DISP_CC_MDSS_ROT_CLK_SRC 34
-#define DISP_CC_MDSS_RSCC_AHB_CLK 35
-#define DISP_CC_MDSS_RSCC_VSYNC_CLK 36
-#define DISP_CC_MDSS_VSYNC_CLK 37
-#define DISP_CC_MDSS_VSYNC_CLK_SRC 38
-#define DISP_CC_PLL0 39
-#define DISP_CC_MDSS_BYTE0_DIV_CLK_SRC 40
-#define DISP_CC_MDSS_BYTE1_DIV_CLK_SRC 41
-#define DISP_CC_MDSS_DP_LINK_DIV_CLK_SRC 42
+#define DISP_CC_MDSS_AHB_CLK 0
+#define DISP_CC_MDSS_AXI_CLK 1
+#define DISP_CC_MDSS_BYTE0_CLK 2
+#define DISP_CC_MDSS_BYTE0_CLK_SRC 3
+#define DISP_CC_MDSS_BYTE0_INTF_CLK 4
+#define DISP_CC_MDSS_BYTE1_CLK 5
+#define DISP_CC_MDSS_BYTE1_CLK_SRC 6
+#define DISP_CC_MDSS_BYTE1_INTF_CLK 7
+#define DISP_CC_MDSS_DP_AUX_CLK 8
+#define DISP_CC_MDSS_DP_AUX_CLK_SRC 9
+#define DISP_CC_MDSS_DP_CRYPTO_CLK 10
+#define DISP_CC_MDSS_DP_CRYPTO_CLK_SRC 11
+#define DISP_CC_MDSS_DP_LINK_CLK 12
+#define DISP_CC_MDSS_DP_LINK_CLK_SRC 13
+#define DISP_CC_MDSS_DP_LINK_INTF_CLK 14
+#define DISP_CC_MDSS_DP_PIXEL1_CLK 15
+#define DISP_CC_MDSS_DP_PIXEL1_CLK_SRC 16
+#define DISP_CC_MDSS_DP_PIXEL_CLK 17
+#define DISP_CC_MDSS_DP_PIXEL_CLK_SRC 18
+#define DISP_CC_MDSS_ESC0_CLK 19
+#define DISP_CC_MDSS_ESC0_CLK_SRC 20
+#define DISP_CC_MDSS_ESC1_CLK 21
+#define DISP_CC_MDSS_ESC1_CLK_SRC 22
+#define DISP_CC_MDSS_MDP_CLK 23
+#define DISP_CC_MDSS_MDP_CLK_SRC 24
+#define DISP_CC_MDSS_MDP_LUT_CLK 25
+#define DISP_CC_MDSS_PCLK0_CLK 26
+#define DISP_CC_MDSS_PCLK0_CLK_SRC 27
+#define DISP_CC_MDSS_PCLK1_CLK 28
+#define DISP_CC_MDSS_PCLK1_CLK_SRC 29
+#define DISP_CC_MDSS_QDSS_AT_CLK 30
+#define DISP_CC_MDSS_QDSS_TSCTR_DIV8_CLK 31
+#define DISP_CC_MDSS_ROT_CLK 32
+#define DISP_CC_MDSS_ROT_CLK_SRC 33
+#define DISP_CC_MDSS_RSCC_AHB_CLK 34
+#define DISP_CC_MDSS_RSCC_VSYNC_CLK 35
+#define DISP_CC_MDSS_VSYNC_CLK 36
+#define DISP_CC_MDSS_VSYNC_CLK_SRC 37
+#define DISP_CC_PLL0 38
+#define DISP_CC_MDSS_BYTE0_DIV_CLK_SRC 39
+#define DISP_CC_MDSS_BYTE1_DIV_CLK_SRC 40
+#define DISP_CC_MDSS_DP_LINK_DIV_CLK_SRC 41
#define DISP_CC_MDSS_CORE_BCR 0
#define DISP_CC_MDSS_GCC_CLOCKS_BCR 1
diff --git a/include/dt-bindings/clock/qcom,gcc-sdm845.h b/include/dt-bindings/clock/qcom,gcc-sdm845.h
index f7a6978..73a8c0b 100644
--- a/include/dt-bindings/clock/qcom,gcc-sdm845.h
+++ b/include/dt-bindings/clock/qcom,gcc-sdm845.h
@@ -35,161 +35,158 @@
#define GCC_CPUSS_GNOC_CLK 17
#define GCC_CPUSS_RBCPR_CLK 18
#define GCC_CPUSS_RBCPR_CLK_SRC 19
-#define GCC_CXO_TX1_CLKREF_CLK 20
-#define GCC_DDRSS_GPU_AXI_CLK 21
-#define GCC_DISP_AHB_CLK 22
-#define GCC_DISP_AXI_CLK 23
-#define GCC_DISP_GPLL0_CLK_SRC 24
-#define GCC_DISP_GPLL0_DIV_CLK_SRC 25
-#define GCC_DISP_XO_CLK 26
-#define GCC_GP1_CLK 27
-#define GCC_GP1_CLK_SRC 28
-#define GCC_GP2_CLK 29
-#define GCC_GP2_CLK_SRC 30
-#define GCC_GP3_CLK 31
-#define GCC_GP3_CLK_SRC 32
-#define GCC_GPU_CFG_AHB_CLK 33
-#define GCC_GPU_GPLL0_CLK_SRC 34
-#define GCC_GPU_GPLL0_DIV_CLK_SRC 35
-#define GCC_GPU_MEMNOC_GFX_CLK 36
-#define GCC_GPU_SNOC_DVM_GFX_CLK 37
-#define GCC_MSS_AXIS2_CLK 38
-#define GCC_MSS_CFG_AHB_CLK 39
-#define GCC_MSS_GPLL0_DIV_CLK_SRC 40
-#define GCC_MSS_MFAB_AXIS_CLK 41
-#define GCC_MSS_Q6_MEMNOC_AXI_CLK 42
-#define GCC_MSS_SNOC_AXI_CLK 43
-#define GCC_PCIE_0_AUX_CLK 44
-#define GCC_PCIE_0_AUX_CLK_SRC 45
-#define GCC_PCIE_0_CFG_AHB_CLK 46
-#define GCC_PCIE_0_CLKREF_CLK 47
-#define GCC_PCIE_0_MSTR_AXI_CLK 48
-#define GCC_PCIE_0_PIPE_CLK 49
-#define GCC_PCIE_0_SLV_AXI_CLK 50
-#define GCC_PCIE_0_SLV_Q2A_AXI_CLK 51
-#define GCC_PCIE_1_AUX_CLK 52
-#define GCC_PCIE_1_AUX_CLK_SRC 53
-#define GCC_PCIE_1_CFG_AHB_CLK 54
-#define GCC_PCIE_1_CLKREF_CLK 55
-#define GCC_PCIE_1_MSTR_AXI_CLK 56
-#define GCC_PCIE_1_PIPE_CLK 57
-#define GCC_PCIE_1_SLV_AXI_CLK 58
-#define GCC_PCIE_1_SLV_Q2A_AXI_CLK 59
-#define GCC_PCIE_PHY_AUX_CLK 60
-#define GCC_PCIE_PHY_REFGEN_CLK 61
-#define GCC_PCIE_PHY_REFGEN_CLK_SRC 62
-#define GCC_PDM2_CLK 63
-#define GCC_PDM2_CLK_SRC 64
-#define GCC_PDM_AHB_CLK 65
-#define GCC_PDM_XO4_CLK 66
-#define GCC_PRNG_AHB_CLK 67
-#define GCC_QMIP_CAMERA_AHB_CLK 68
-#define GCC_QMIP_DISP_AHB_CLK 69
-#define GCC_QMIP_VIDEO_AHB_CLK 70
-#define GCC_QUPV3_WRAP0_S0_CLK 71
-#define GCC_QUPV3_WRAP0_S0_CLK_SRC 72
-#define GCC_QUPV3_WRAP0_S1_CLK 73
-#define GCC_QUPV3_WRAP0_S1_CLK_SRC 74
-#define GCC_QUPV3_WRAP0_S2_CLK 75
-#define GCC_QUPV3_WRAP0_S2_CLK_SRC 76
-#define GCC_QUPV3_WRAP0_S3_CLK 77
-#define GCC_QUPV3_WRAP0_S3_CLK_SRC 78
-#define GCC_QUPV3_WRAP0_S4_CLK 79
-#define GCC_QUPV3_WRAP0_S4_CLK_SRC 80
-#define GCC_QUPV3_WRAP0_S5_CLK 81
-#define GCC_QUPV3_WRAP0_S5_CLK_SRC 82
-#define GCC_QUPV3_WRAP0_S6_CLK 83
-#define GCC_QUPV3_WRAP0_S6_CLK_SRC 84
-#define GCC_QUPV3_WRAP0_S7_CLK 85
-#define GCC_QUPV3_WRAP0_S7_CLK_SRC 86
-#define GCC_QUPV3_WRAP1_S0_CLK 87
-#define GCC_QUPV3_WRAP1_S0_CLK_SRC 88
-#define GCC_QUPV3_WRAP1_S1_CLK 89
-#define GCC_QUPV3_WRAP1_S1_CLK_SRC 90
-#define GCC_QUPV3_WRAP1_S2_CLK 91
-#define GCC_QUPV3_WRAP1_S2_CLK_SRC 92
-#define GCC_QUPV3_WRAP1_S3_CLK 93
-#define GCC_QUPV3_WRAP1_S3_CLK_SRC 94
-#define GCC_QUPV3_WRAP1_S4_CLK 95
-#define GCC_QUPV3_WRAP1_S4_CLK_SRC 96
-#define GCC_QUPV3_WRAP1_S5_CLK 97
-#define GCC_QUPV3_WRAP1_S5_CLK_SRC 98
-#define GCC_QUPV3_WRAP1_S6_CLK 99
-#define GCC_QUPV3_WRAP1_S6_CLK_SRC 100
-#define GCC_QUPV3_WRAP1_S7_CLK 101
-#define GCC_QUPV3_WRAP1_S7_CLK_SRC 102
-#define GCC_QUPV3_WRAP_0_M_AHB_CLK 103
-#define GCC_QUPV3_WRAP_0_S_AHB_CLK 104
-#define GCC_QUPV3_WRAP_1_M_AHB_CLK 105
-#define GCC_QUPV3_WRAP_1_S_AHB_CLK 106
-#define GCC_RX1_USB2_CLKREF_CLK 107
-#define GCC_RX2_QLINK_CLKREF_CLK 108
-#define GCC_SDCC2_AHB_CLK 109
-#define GCC_SDCC2_APPS_CLK 110
-#define GCC_SDCC2_APPS_CLK_SRC 111
-#define GCC_SDCC4_AHB_CLK 112
-#define GCC_SDCC4_APPS_CLK 113
-#define GCC_SDCC4_APPS_CLK_SRC 114
-#define GCC_SYS_NOC_CPUSS_AHB_CLK 115
-#define GCC_TSIF_AHB_CLK 116
-#define GCC_TSIF_INACTIVITY_TIMERS_CLK 117
-#define GCC_TSIF_REF_CLK 118
-#define GCC_TSIF_REF_CLK_SRC 119
-#define GCC_UFS_CARD_AHB_CLK 120
-#define GCC_UFS_CARD_AXI_CLK 121
-#define GCC_UFS_CARD_AXI_CLK_SRC 122
-#define GCC_UFS_CARD_CLKREF_CLK 123
-#define GCC_UFS_CARD_ICE_CORE_CLK 124
-#define GCC_UFS_CARD_ICE_CORE_CLK_SRC 125
-#define GCC_UFS_CARD_PHY_AUX_CLK 126
-#define GCC_UFS_CARD_PHY_AUX_CLK_SRC 127
-#define GCC_UFS_CARD_RX_SYMBOL_0_CLK 128
-#define GCC_UFS_CARD_RX_SYMBOL_1_CLK 129
-#define GCC_UFS_CARD_TX_SYMBOL_0_CLK 130
-#define GCC_UFS_CARD_UNIPRO_CORE_CLK 131
-#define GCC_UFS_CARD_UNIPRO_CORE_CLK_SRC 132
-#define GCC_UFS_MEM_CLKREF_CLK 133
-#define GCC_UFS_PHY_AHB_CLK 134
-#define GCC_UFS_PHY_AXI_CLK 135
-#define GCC_UFS_PHY_AXI_CLK_SRC 136
-#define GCC_UFS_PHY_ICE_CORE_CLK 137
-#define GCC_UFS_PHY_ICE_CORE_CLK_SRC 138
-#define GCC_UFS_PHY_PHY_AUX_CLK 139
-#define GCC_UFS_PHY_PHY_AUX_CLK_SRC 140
-#define GCC_UFS_PHY_RX_SYMBOL_0_CLK 141
-#define GCC_UFS_PHY_RX_SYMBOL_1_CLK 142
-#define GCC_UFS_PHY_TX_SYMBOL_0_CLK 143
-#define GCC_UFS_PHY_UNIPRO_CORE_CLK 144
-#define GCC_UFS_PHY_UNIPRO_CORE_CLK_SRC 145
-#define GCC_USB30_PRIM_MASTER_CLK 146
-#define GCC_USB30_PRIM_MASTER_CLK_SRC 147
-#define GCC_USB30_PRIM_MOCK_UTMI_CLK 148
-#define GCC_USB30_PRIM_MOCK_UTMI_CLK_SRC 149
-#define GCC_USB30_PRIM_SLEEP_CLK 150
-#define GCC_USB30_SEC_MASTER_CLK 151
-#define GCC_USB30_SEC_MASTER_CLK_SRC 152
-#define GCC_USB30_SEC_MOCK_UTMI_CLK 153
-#define GCC_USB30_SEC_MOCK_UTMI_CLK_SRC 154
-#define GCC_USB30_SEC_SLEEP_CLK 155
-#define GCC_USB3_PRIM_CLKREF_CLK 156
-#define GCC_USB3_PRIM_PHY_AUX_CLK 157
-#define GCC_USB3_PRIM_PHY_AUX_CLK_SRC 158
-#define GCC_USB3_PRIM_PHY_COM_AUX_CLK 159
-#define GCC_USB3_PRIM_PHY_PIPE_CLK 160
-#define GCC_USB3_SEC_CLKREF_CLK 161
-#define GCC_USB3_SEC_PHY_AUX_CLK 162
-#define GCC_USB3_SEC_PHY_AUX_CLK_SRC 163
-#define GCC_USB3_SEC_PHY_COM_AUX_CLK 164
-#define GCC_USB3_SEC_PHY_PIPE_CLK 165
-#define GCC_USB_PHY_CFG_AHB2PHY_CLK 166
-#define GCC_VIDEO_AHB_CLK 167
-#define GCC_VIDEO_AXI_CLK 168
-#define GCC_VIDEO_XO_CLK 169
-#define GPLL0 170
-#define GPLL0_OUT_EVEN 171
-#define GPLL0_OUT_MAIN 172
-#define GPLL1 173
-#define GPLL1_OUT_MAIN 174
+#define GCC_DDRSS_GPU_AXI_CLK 20
+#define GCC_DISP_AHB_CLK 21
+#define GCC_DISP_AXI_CLK 22
+#define GCC_DISP_GPLL0_CLK_SRC 23
+#define GCC_DISP_GPLL0_DIV_CLK_SRC 24
+#define GCC_DISP_XO_CLK 25
+#define GCC_GP1_CLK 26
+#define GCC_GP1_CLK_SRC 27
+#define GCC_GP2_CLK 28
+#define GCC_GP2_CLK_SRC 29
+#define GCC_GP3_CLK 30
+#define GCC_GP3_CLK_SRC 31
+#define GCC_GPU_CFG_AHB_CLK 32
+#define GCC_GPU_GPLL0_CLK_SRC 33
+#define GCC_GPU_GPLL0_DIV_CLK_SRC 34
+#define GCC_GPU_MEMNOC_GFX_CLK 35
+#define GCC_GPU_SNOC_DVM_GFX_CLK 36
+#define GCC_MSS_AXIS2_CLK 37
+#define GCC_MSS_CFG_AHB_CLK 38
+#define GCC_MSS_GPLL0_DIV_CLK_SRC 39
+#define GCC_MSS_MFAB_AXIS_CLK 40
+#define GCC_MSS_Q6_MEMNOC_AXI_CLK 41
+#define GCC_MSS_SNOC_AXI_CLK 42
+#define GCC_PCIE_0_AUX_CLK 43
+#define GCC_PCIE_0_AUX_CLK_SRC 44
+#define GCC_PCIE_0_CFG_AHB_CLK 45
+#define GCC_PCIE_0_CLKREF_CLK 46
+#define GCC_PCIE_0_MSTR_AXI_CLK 47
+#define GCC_PCIE_0_PIPE_CLK 48
+#define GCC_PCIE_0_SLV_AXI_CLK 49
+#define GCC_PCIE_0_SLV_Q2A_AXI_CLK 50
+#define GCC_PCIE_1_AUX_CLK 51
+#define GCC_PCIE_1_AUX_CLK_SRC 52
+#define GCC_PCIE_1_CFG_AHB_CLK 53
+#define GCC_PCIE_1_CLKREF_CLK 54
+#define GCC_PCIE_1_MSTR_AXI_CLK 55
+#define GCC_PCIE_1_PIPE_CLK 56
+#define GCC_PCIE_1_SLV_AXI_CLK 57
+#define GCC_PCIE_1_SLV_Q2A_AXI_CLK 58
+#define GCC_PCIE_PHY_AUX_CLK 59
+#define GCC_PCIE_PHY_REFGEN_CLK 60
+#define GCC_PCIE_PHY_REFGEN_CLK_SRC 61
+#define GCC_PDM2_CLK 62
+#define GCC_PDM2_CLK_SRC 63
+#define GCC_PDM_AHB_CLK 64
+#define GCC_PDM_XO4_CLK 65
+#define GCC_PRNG_AHB_CLK 66
+#define GCC_QMIP_CAMERA_AHB_CLK 67
+#define GCC_QMIP_DISP_AHB_CLK 68
+#define GCC_QMIP_VIDEO_AHB_CLK 69
+#define GCC_QUPV3_WRAP0_S0_CLK 70
+#define GCC_QUPV3_WRAP0_S0_CLK_SRC 71
+#define GCC_QUPV3_WRAP0_S1_CLK 72
+#define GCC_QUPV3_WRAP0_S1_CLK_SRC 73
+#define GCC_QUPV3_WRAP0_S2_CLK 74
+#define GCC_QUPV3_WRAP0_S2_CLK_SRC 75
+#define GCC_QUPV3_WRAP0_S3_CLK 76
+#define GCC_QUPV3_WRAP0_S3_CLK_SRC 77
+#define GCC_QUPV3_WRAP0_S4_CLK 78
+#define GCC_QUPV3_WRAP0_S4_CLK_SRC 79
+#define GCC_QUPV3_WRAP0_S5_CLK 80
+#define GCC_QUPV3_WRAP0_S5_CLK_SRC 81
+#define GCC_QUPV3_WRAP0_S6_CLK 82
+#define GCC_QUPV3_WRAP0_S6_CLK_SRC 83
+#define GCC_QUPV3_WRAP0_S7_CLK 84
+#define GCC_QUPV3_WRAP0_S7_CLK_SRC 85
+#define GCC_QUPV3_WRAP1_S0_CLK 86
+#define GCC_QUPV3_WRAP1_S0_CLK_SRC 87
+#define GCC_QUPV3_WRAP1_S1_CLK 88
+#define GCC_QUPV3_WRAP1_S1_CLK_SRC 89
+#define GCC_QUPV3_WRAP1_S2_CLK 90
+#define GCC_QUPV3_WRAP1_S2_CLK_SRC 91
+#define GCC_QUPV3_WRAP1_S3_CLK 92
+#define GCC_QUPV3_WRAP1_S3_CLK_SRC 93
+#define GCC_QUPV3_WRAP1_S4_CLK 94
+#define GCC_QUPV3_WRAP1_S4_CLK_SRC 95
+#define GCC_QUPV3_WRAP1_S5_CLK 96
+#define GCC_QUPV3_WRAP1_S5_CLK_SRC 97
+#define GCC_QUPV3_WRAP1_S6_CLK 98
+#define GCC_QUPV3_WRAP1_S6_CLK_SRC 99
+#define GCC_QUPV3_WRAP1_S7_CLK 100
+#define GCC_QUPV3_WRAP1_S7_CLK_SRC 101
+#define GCC_QUPV3_WRAP_0_M_AHB_CLK 102
+#define GCC_QUPV3_WRAP_0_S_AHB_CLK 103
+#define GCC_QUPV3_WRAP_1_M_AHB_CLK 104
+#define GCC_QUPV3_WRAP_1_S_AHB_CLK 105
+#define GCC_SDCC2_AHB_CLK 106
+#define GCC_SDCC2_APPS_CLK 107
+#define GCC_SDCC2_APPS_CLK_SRC 108
+#define GCC_SDCC4_AHB_CLK 109
+#define GCC_SDCC4_APPS_CLK 110
+#define GCC_SDCC4_APPS_CLK_SRC 111
+#define GCC_SYS_NOC_CPUSS_AHB_CLK 112
+#define GCC_TSIF_AHB_CLK 113
+#define GCC_TSIF_INACTIVITY_TIMERS_CLK 114
+#define GCC_TSIF_REF_CLK 115
+#define GCC_TSIF_REF_CLK_SRC 116
+#define GCC_UFS_CARD_AHB_CLK 117
+#define GCC_UFS_CARD_AXI_CLK 118
+#define GCC_UFS_CARD_AXI_CLK_SRC 119
+#define GCC_UFS_CARD_CLKREF_CLK 120
+#define GCC_UFS_CARD_ICE_CORE_CLK 121
+#define GCC_UFS_CARD_ICE_CORE_CLK_SRC 122
+#define GCC_UFS_CARD_PHY_AUX_CLK 123
+#define GCC_UFS_CARD_PHY_AUX_CLK_SRC 124
+#define GCC_UFS_CARD_RX_SYMBOL_0_CLK 125
+#define GCC_UFS_CARD_RX_SYMBOL_1_CLK 126
+#define GCC_UFS_CARD_TX_SYMBOL_0_CLK 127
+#define GCC_UFS_CARD_UNIPRO_CORE_CLK 128
+#define GCC_UFS_CARD_UNIPRO_CORE_CLK_SRC 129
+#define GCC_UFS_MEM_CLKREF_CLK 130
+#define GCC_UFS_PHY_AHB_CLK 131
+#define GCC_UFS_PHY_AXI_CLK 132
+#define GCC_UFS_PHY_AXI_CLK_SRC 133
+#define GCC_UFS_PHY_ICE_CORE_CLK 134
+#define GCC_UFS_PHY_ICE_CORE_CLK_SRC 135
+#define GCC_UFS_PHY_PHY_AUX_CLK 136
+#define GCC_UFS_PHY_PHY_AUX_CLK_SRC 137
+#define GCC_UFS_PHY_RX_SYMBOL_0_CLK 138
+#define GCC_UFS_PHY_RX_SYMBOL_1_CLK 139
+#define GCC_UFS_PHY_TX_SYMBOL_0_CLK 140
+#define GCC_UFS_PHY_UNIPRO_CORE_CLK 141
+#define GCC_UFS_PHY_UNIPRO_CORE_CLK_SRC 142
+#define GCC_USB30_PRIM_MASTER_CLK 143
+#define GCC_USB30_PRIM_MASTER_CLK_SRC 144
+#define GCC_USB30_PRIM_MOCK_UTMI_CLK 145
+#define GCC_USB30_PRIM_MOCK_UTMI_CLK_SRC 146
+#define GCC_USB30_PRIM_SLEEP_CLK 147
+#define GCC_USB30_SEC_MASTER_CLK 148
+#define GCC_USB30_SEC_MASTER_CLK_SRC 149
+#define GCC_USB30_SEC_MOCK_UTMI_CLK 150
+#define GCC_USB30_SEC_MOCK_UTMI_CLK_SRC 151
+#define GCC_USB30_SEC_SLEEP_CLK 152
+#define GCC_USB3_PRIM_CLKREF_CLK 153
+#define GCC_USB3_PRIM_PHY_AUX_CLK 154
+#define GCC_USB3_PRIM_PHY_AUX_CLK_SRC 155
+#define GCC_USB3_PRIM_PHY_COM_AUX_CLK 156
+#define GCC_USB3_PRIM_PHY_PIPE_CLK 157
+#define GCC_USB3_SEC_CLKREF_CLK 158
+#define GCC_USB3_SEC_PHY_AUX_CLK 159
+#define GCC_USB3_SEC_PHY_AUX_CLK_SRC 160
+#define GCC_USB3_SEC_PHY_COM_AUX_CLK 161
+#define GCC_USB3_SEC_PHY_PIPE_CLK 162
+#define GCC_USB_PHY_CFG_AHB2PHY_CLK 163
+#define GCC_VIDEO_AHB_CLK 164
+#define GCC_VIDEO_AXI_CLK 165
+#define GCC_VIDEO_XO_CLK 166
+#define GPLL0 167
+#define GPLL0_OUT_EVEN 168
+#define GPLL0_OUT_MAIN 169
+#define GPLL1 170
+#define GPLL1_OUT_MAIN 171
/* GCC reset clocks */
#define GCC_GPU_BCR 0
@@ -217,6 +214,8 @@
#define GCC_USB3PHY_PHY_SEC_BCR 22
#define GCC_USB3_DP_PHY_SEC_BCR 23
#define GCC_USB_PHY_CFG_AHB2PHY_BCR 24
+#define GCC_PCIE_0_PHY_BCR 25
+#define GCC_PCIE_1_PHY_BCR 26
/* Dummy clocks for rate measurement */
#define MEASURE_ONLY_SNOC_CLK 0
diff --git a/include/dt-bindings/clock/qcom,gcc-sdxpoorwills.h b/include/dt-bindings/clock/qcom,gcc-sdxpoorwills.h
new file mode 100644
index 0000000..6243588
--- /dev/null
+++ b/include/dt-bindings/clock/qcom,gcc-sdxpoorwills.h
@@ -0,0 +1,123 @@
+/*
+ * 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 _DT_BINDINGS_CLK_MSM_GCC_SDX24_H
+#define _DT_BINDINGS_CLK_MSM_GCC_SDX24_H
+
+/* GCC clock registers */
+#define GCC_BLSP1_AHB_CLK 0
+#define GCC_BLSP1_QUP1_I2C_APPS_CLK 1
+#define GCC_BLSP1_QUP1_I2C_APPS_CLK_SRC 2
+#define GCC_BLSP1_QUP1_SPI_APPS_CLK 3
+#define GCC_BLSP1_QUP1_SPI_APPS_CLK_SRC 4
+#define GCC_BLSP1_QUP2_I2C_APPS_CLK 5
+#define GCC_BLSP1_QUP2_I2C_APPS_CLK_SRC 6
+#define GCC_BLSP1_QUP2_SPI_APPS_CLK 7
+#define GCC_BLSP1_QUP2_SPI_APPS_CLK_SRC 8
+#define GCC_BLSP1_QUP3_I2C_APPS_CLK 9
+#define GCC_BLSP1_QUP3_I2C_APPS_CLK_SRC 10
+#define GCC_BLSP1_QUP3_SPI_APPS_CLK 11
+#define GCC_BLSP1_QUP3_SPI_APPS_CLK_SRC 12
+#define GCC_BLSP1_QUP4_I2C_APPS_CLK 13
+#define GCC_BLSP1_QUP4_I2C_APPS_CLK_SRC 14
+#define GCC_BLSP1_QUP4_SPI_APPS_CLK 15
+#define GCC_BLSP1_QUP4_SPI_APPS_CLK_SRC 16
+#define GCC_BLSP1_SLEEP_CLK 17
+#define GCC_BLSP1_UART1_APPS_CLK 18
+#define GCC_BLSP1_UART1_APPS_CLK_SRC 19
+#define GCC_BLSP1_UART2_APPS_CLK 20
+#define GCC_BLSP1_UART2_APPS_CLK_SRC 21
+#define GCC_BLSP1_UART3_APPS_CLK 22
+#define GCC_BLSP1_UART3_APPS_CLK_SRC 23
+#define GCC_BLSP1_UART4_APPS_CLK 24
+#define GCC_BLSP1_UART4_APPS_CLK_SRC 25
+#define GCC_BOOT_ROM_AHB_CLK 26
+#define GCC_CE1_AHB_CLK 27
+#define GCC_CE1_AXI_CLK 28
+#define GCC_CE1_CLK 29
+#define GCC_CPUSS_AHB_CLK 30
+#define GCC_CPUSS_AHB_CLK_SRC 31
+#define GCC_CPUSS_GNOC_CLK 32
+#define GCC_CPUSS_GPLL0_CLK_SRC 33
+#define GCC_CPUSS_RBCPR_CLK 34
+#define GCC_CPUSS_RBCPR_CLK_SRC 35
+#define GCC_GP1_CLK 36
+#define GCC_GP1_CLK_SRC 37
+#define GCC_GP2_CLK 38
+#define GCC_GP2_CLK_SRC 39
+#define GCC_GP3_CLK 40
+#define GCC_GP3_CLK_SRC 41
+#define GCC_MSS_CFG_AHB_CLK 42
+#define GCC_MSS_GPLL0_DIV_CLK_SRC 43
+#define GCC_MSS_SNOC_AXI_CLK 44
+#define GCC_PCIE_AUX_CLK 45
+#define GCC_PCIE_AUX_PHY_CLK_SRC 46
+#define GCC_PCIE_CFG_AHB_CLK 47
+#define GCC_PCIE_MSTR_AXI_CLK 48
+#define GCC_PCIE_PHY_REFGEN_CLK 49
+#define GCC_PCIE_PHY_REFGEN_CLK_SRC 50
+#define GCC_PCIE_PIPE_CLK 51
+#define GCC_PCIE_SLEEP_CLK 52
+#define GCC_PCIE_SLV_AXI_CLK 53
+#define GCC_PCIE_SLV_Q2A_AXI_CLK 54
+#define GCC_PDM2_CLK 55
+#define GCC_PDM2_CLK_SRC 56
+#define GCC_PDM_AHB_CLK 57
+#define GCC_PDM_XO4_CLK 58
+#define GCC_PRNG_AHB_CLK 59
+#define GCC_SDCC1_AHB_CLK 60
+#define GCC_SDCC1_APPS_CLK 61
+#define GCC_SDCC1_APPS_CLK_SRC 62
+#define GCC_SPMI_FETCHER_AHB_CLK 63
+#define GCC_SPMI_FETCHER_CLK 64
+#define GCC_SPMI_FETCHER_CLK_SRC 65
+#define GCC_SYS_NOC_CPUSS_AHB_CLK 66
+#define GCC_USB30_MASTER_CLK 67
+#define GCC_USB30_MASTER_CLK_SRC 68
+#define GCC_USB30_MOCK_UTMI_CLK 69
+#define GCC_USB30_MOCK_UTMI_CLK_SRC 70
+#define GCC_USB30_SLEEP_CLK 71
+#define GCC_USB3_PHY_AUX_CLK 72
+#define GCC_USB3_PHY_AUX_CLK_SRC 73
+#define GCC_USB3_PHY_PIPE_CLK 74
+#define GCC_USB_PHY_CFG_AHB2PHY_CLK 75
+#define GCC_XO_DIV4_CLK 76
+#define GPLL0 77
+#define GPLL0_OUT_EVEN 78
+
+/* GDSCs */
+#define PCIE_GDSC 0
+#define USB30_GDSC 1
+
+/* CPU clocks */
+#define CLOCK_A7SS 0
+
+/* GCC reset clocks */
+#define GCC_BLSP1_QUP1_BCR 0
+#define GCC_BLSP1_QUP2_BCR 1
+#define GCC_BLSP1_QUP3_BCR 2
+#define GCC_BLSP1_QUP4_BCR 3
+#define GCC_BLSP1_UART2_BCR 4
+#define GCC_BLSP1_UART3_BCR 5
+#define GCC_BLSP1_UART4_BCR 6
+#define GCC_CE1_BCR 7
+#define GCC_PCIE_BCR 8
+#define GCC_PCIE_PHY_BCR 9
+#define GCC_PDM_BCR 10
+#define GCC_PRNG_BCR 11
+#define GCC_SDCC1_BCR 12
+#define GCC_SPMI_FETCHER_BCR 13
+#define GCC_USB30_BCR 14
+#define GCC_USB_PHY_CFG_AHB2PHY_BCR 15
+
+#endif
diff --git a/include/dt-bindings/clock/qcom,gpucc-sdm845.h b/include/dt-bindings/clock/qcom,gpucc-sdm845.h
index 13de1e1..c43a9f8 100644
--- a/include/dt-bindings/clock/qcom,gpucc-sdm845.h
+++ b/include/dt-bindings/clock/qcom,gpucc-sdm845.h
@@ -17,37 +17,36 @@
/* GPUCC clock registers */
#define GPU_CC_ACD_AHB_CLK 0
#define GPU_CC_ACD_CXO_CLK 1
-#define GPU_CC_AHB_CLK 2
+#define GPU_CC_AHB_CLK 2
#define GPU_CC_CRC_AHB_CLK 3
#define GPU_CC_CX_APB_CLK 4
#define GPU_CC_CX_GMU_CLK 5
#define GPU_CC_CX_QDSS_AT_CLK 6
#define GPU_CC_CX_QDSS_TRIG_CLK 7
-#define GPU_CC_CX_QDSS_TSCTR_CLK 8
-#define GPU_CC_CX_SNOC_DVM_CLK 9
+#define GPU_CC_CX_QDSS_TSCTR_CLK 8
+#define GPU_CC_CX_SNOC_DVM_CLK 9
#define GPU_CC_CXO_AON_CLK 10
-#define GPU_CC_CXO_CLK 11
-#define GPU_CC_DEBUG_CLK 12
-#define GPU_CC_GX_CXO_CLK 13
-#define GPU_CC_GX_GMU_CLK 14
-#define GPU_CC_GX_QDSS_TSCTR_CLK 15
-#define GPU_CC_GX_VSENSE_CLK 16
-#define GPU_CC_PLL0_OUT_MAIN 17
-#define GPU_CC_PLL0_OUT_ODD 18
-#define GPU_CC_PLL0_OUT_TEST 19
-#define GPU_CC_PLL1 20
-#define GPU_CC_PLL1_OUT_EVEN 21
-#define GPU_CC_PLL1_OUT_MAIN 22
-#define GPU_CC_PLL1_OUT_ODD 23
-#define GPU_CC_PLL1_OUT_TEST 24
-#define GPU_CC_PLL_TEST_CLK 25
-#define GPU_CC_RBCPR_AHB_CLK 26
-#define GPU_CC_RBCPR_CLK 27
-#define GPU_CC_RBCPR_CLK_SRC 28
-#define GPU_CC_SLEEP_CLK 29
-#define GPU_CC_GMU_CLK_SRC 30
-#define GPU_CC_CX_GFX3D_CLK 31
-#define GPU_CC_CX_GFX3D_SLV_CLK 32
+#define GPU_CC_CXO_CLK 11
+#define GPU_CC_GX_CXO_CLK 12
+#define GPU_CC_GX_GMU_CLK 13
+#define GPU_CC_GX_QDSS_TSCTR_CLK 14
+#define GPU_CC_GX_VSENSE_CLK 15
+#define GPU_CC_PLL0_OUT_MAIN 16
+#define GPU_CC_PLL0_OUT_ODD 17
+#define GPU_CC_PLL0_OUT_TEST 18
+#define GPU_CC_PLL1 19
+#define GPU_CC_PLL1_OUT_EVEN 20
+#define GPU_CC_PLL1_OUT_MAIN 21
+#define GPU_CC_PLL1_OUT_ODD 22
+#define GPU_CC_PLL1_OUT_TEST 23
+#define GPU_CC_PLL_TEST_CLK 24
+#define GPU_CC_RBCPR_AHB_CLK 25
+#define GPU_CC_RBCPR_CLK 26
+#define GPU_CC_RBCPR_CLK_SRC 27
+#define GPU_CC_SLEEP_CLK 28
+#define GPU_CC_GMU_CLK_SRC 29
+#define GPU_CC_CX_GFX3D_CLK 30
+#define GPU_CC_CX_GFX3D_SLV_CLK 31
/* GPUCC reset clock registers */
#define GPUCC_GPU_CC_ACD_BCR 0
@@ -63,5 +62,5 @@
#define GPU_CC_PLL0 0
#define GPU_CC_PLL0_OUT_EVEN 1
#define GPU_CC_GX_GFX3D_CLK_SRC 2
-#define GPU_CC_GX_GFX3D_CLK 3
+#define GPU_CC_GX_GFX3D_CLK 3
#endif
diff --git a/include/dt-bindings/clock/qcom,videocc-sdm845.h b/include/dt-bindings/clock/qcom,videocc-sdm845.h
index 723d2e0..b362852d 100644
--- a/include/dt-bindings/clock/qcom,videocc-sdm845.h
+++ b/include/dt-bindings/clock/qcom,videocc-sdm845.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2016, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2016-2017, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -16,18 +16,17 @@
#define VIDEO_CC_APB_CLK 0
#define VIDEO_CC_AT_CLK 1
-#define VIDEO_CC_DEBUG_CLK 2
-#define VIDEO_CC_QDSS_TRIG_CLK 3
-#define VIDEO_CC_QDSS_TSCTR_DIV8_CLK 4
-#define VIDEO_CC_VCODEC0_AXI_CLK 5
-#define VIDEO_CC_VCODEC0_CORE_CLK 6
-#define VIDEO_CC_VCODEC1_AXI_CLK 7
-#define VIDEO_CC_VCODEC1_CORE_CLK 8
-#define VIDEO_CC_VENUS_AHB_CLK 9
-#define VIDEO_CC_VENUS_CLK_SRC 10
-#define VIDEO_CC_VENUS_CTL_AXI_CLK 11
-#define VIDEO_CC_VENUS_CTL_CORE_CLK 12
-#define VIDEO_PLL0 13
+#define VIDEO_CC_QDSS_TRIG_CLK 2
+#define VIDEO_CC_QDSS_TSCTR_DIV8_CLK 3
+#define VIDEO_CC_VCODEC0_AXI_CLK 4
+#define VIDEO_CC_VCODEC0_CORE_CLK 5
+#define VIDEO_CC_VCODEC1_AXI_CLK 6
+#define VIDEO_CC_VCODEC1_CORE_CLK 7
+#define VIDEO_CC_VENUS_AHB_CLK 8
+#define VIDEO_CC_VENUS_CLK_SRC 9
+#define VIDEO_CC_VENUS_CTL_AXI_CLK 10
+#define VIDEO_CC_VENUS_CTL_CORE_CLK 11
+#define VIDEO_PLL0 12
#define VIDEO_CC_INTERFACE_BCR 0
#define VIDEO_CC_VCODEC0_BCR 1
diff --git a/include/linux/cgroup.h b/include/linux/cgroup.h
index af84de6..0353461 100644
--- a/include/linux/cgroup.h
+++ b/include/linux/cgroup.h
@@ -579,6 +579,24 @@
*/
int subsys_cgroup_allow_attach(struct cgroup_taskset *tset);
+static inline void cgroup_init_kthreadd(void)
+{
+ /*
+ * kthreadd is inherited by all kthreads, keep it in the root so
+ * that the new kthreads are guaranteed to stay in the root until
+ * initialization is finished.
+ */
+ current->no_cgroup_migration = 1;
+}
+
+static inline void cgroup_kthread_ready(void)
+{
+ /*
+ * This kthread finished initialization. The creator should have
+ * set PF_NO_SETAFFINITY if this kthread should stay in the root.
+ */
+ current->no_cgroup_migration = 0;
+}
#else /* !CONFIG_CGROUPS */
@@ -600,6 +618,8 @@
static inline int cgroup_init_early(void) { return 0; }
static inline int cgroup_init(void) { return 0; }
+static inline void cgroup_init_kthreadd(void) {}
+static inline void cgroup_kthread_ready(void) {}
static inline bool task_under_cgroup_hierarchy(struct task_struct *task,
struct cgroup *ancestor)
diff --git a/include/linux/clk-provider.h b/include/linux/clk-provider.h
index 8fd5fba..b1f2d00 100644
--- a/include/linux/clk-provider.h
+++ b/include/linux/clk-provider.h
@@ -36,7 +36,11 @@
#define CLK_IS_CRITICAL BIT(11) /* do not gate, ever */
/* parents need enable during gate/ungate, set rate and re-parent */
#define CLK_OPS_PARENT_ENABLE BIT(12)
- /* unused */
+#define CLK_ENABLE_HAND_OFF BIT(13) /* enable clock when registered. */
+ /*
+ * hand-off enable_count & prepare_count
+ * to first consumer that enables clk
+ */
#define CLK_IS_MEASURE BIT(14) /* measure clock */
struct clk;
diff --git a/include/linux/dma-mapping.h b/include/linux/dma-mapping.h
index 373dbd5..ec9c128 100644
--- a/include/linux/dma-mapping.h
+++ b/include/linux/dma-mapping.h
@@ -855,7 +855,9 @@
struct vm_area_struct *vma, void *cpu_addr,
dma_addr_t dma_addr, size_t size)
{
- return -ENODEV;
+ unsigned long attrs = DMA_ATTR_NON_CONSISTENT;
+
+ return dma_mmap_attrs(dev, vma, cpu_addr, dma_addr, size, attrs);
}
#if defined(CONFIG_NEED_DMA_MAP_STATE) || defined(CONFIG_DMA_API_DEBUG)
diff --git a/include/linux/iommu.h b/include/linux/iommu.h
index 5d3a4cd..1f6892c 100644
--- a/include/linux/iommu.h
+++ b/include/linux/iommu.h
@@ -435,6 +435,7 @@
const struct iommu_ops *ops);
void iommu_fwspec_free(struct device *dev);
int iommu_fwspec_add_ids(struct device *dev, u32 *ids, int num_ids);
+int iommu_fwspec_get_id(struct device *dev, u32 *id);
#else /* CONFIG_IOMMU_API */
@@ -705,6 +706,11 @@
return -ENODEV;
}
+static inline int iommu_fwspec_get_id(struct device *dev, u32 *id)
+{
+ return -ENODEV;
+}
+
#endif /* CONFIG_IOMMU_API */
#endif /* __LINUX_IOMMU_H */
diff --git a/include/linux/mmc/card.h b/include/linux/mmc/card.h
index d0ec667..72dd7ba 100644
--- a/include/linux/mmc/card.h
+++ b/include/linux/mmc/card.h
@@ -439,6 +439,8 @@
u8 *cached_ext_csd;
bool cmdq_init;
struct mmc_bkops_info bkops;
+ bool err_in_sdr104;
+ bool sdr104_blocked;
};
/*
diff --git a/include/linux/mmc/core.h b/include/linux/mmc/core.h
index 5d5aff1..959414b 100644
--- a/include/linux/mmc/core.h
+++ b/include/linux/mmc/core.h
@@ -179,6 +179,7 @@
extern int mmc_send_tuning(struct mmc_host *host, u32 opcode, int *cmd_error);
extern int mmc_get_ext_csd(struct mmc_card *card, u8 **new_ext_csd);
extern int mmc_set_auto_bkops(struct mmc_card *card, bool enable);
+extern int mmc_suspend_clk_scaling(struct mmc_host *host);
#define MMC_ERASE_ARG 0x00000000
#define MMC_SECURE_ERASE_ARG 0x80000000
diff --git a/include/linux/mmc/host.h b/include/linux/mmc/host.h
index ba1e826..ecfc173 100644
--- a/include/linux/mmc/host.h
+++ b/include/linux/mmc/host.h
@@ -587,6 +587,8 @@
struct io_latency_state io_lat_s;
#endif
+ bool sdr104_wa;
+
/*
* Set to 1 to just stop the SDCLK to the card without
* actually disabling the clock from it's source.
@@ -751,6 +753,16 @@
MMC_CAP_UHS_DDR50);
}
+static inline void mmc_host_clear_sdr104(struct mmc_host *host)
+{
+ host->caps &= ~MMC_CAP_UHS_SDR104;
+}
+
+static inline void mmc_host_set_sdr104(struct mmc_host *host)
+{
+ host->caps |= MMC_CAP_UHS_SDR104;
+}
+
static inline int mmc_host_packed_wr(struct mmc_host *host)
{
return host->caps2 & MMC_CAP2_PACKED_WR;
diff --git a/include/linux/qcom-geni-se.h b/include/linux/qcom-geni-se.h
index 6b790c6..cb4387d 100644
--- a/include/linux/qcom-geni-se.h
+++ b/include/linux/qcom-geni-se.h
@@ -39,6 +39,7 @@
struct clk *m_ahb_clk;
struct clk *s_ahb_clk;
struct msm_bus_client_handle *bus_bw;
+ unsigned int bus_mas;
unsigned long ab;
unsigned long ib;
struct pinctrl *geni_pinctrl;
@@ -87,6 +88,7 @@
#define SE_GENI_RX_RFR_WATERMARK_REG (0x814)
#define SE_GENI_M_GP_LENGTH (0x910)
#define SE_GENI_S_GP_LENGTH (0x914)
+#define SE_GSI_EVENT_EN (0xE18)
#define SE_IRQ_EN (0xE1C)
#define SE_HW_PARAM_0 (0xE24)
#define SE_HW_PARAM_1 (0xE28)
@@ -220,6 +222,12 @@
#define RX_LAST_BYTE_VALID_SHFT (28)
#define RX_FIFO_WC_MSK (GENMASK(24, 0))
+/* SE_GSI_EVENT_EN fields */
+#define DMA_RX_EVENT_EN (BIT(0))
+#define DMA_TX_EVENT_EN (BIT(1))
+#define GENI_M_EVENT_EN (BIT(2))
+#define GENI_S_EVENT_EN (BIT(3))
+
/* SE_IRQ_EN fields */
#define DMA_RX_IRQ_EN (BIT(0))
#define DMA_TX_IRQ_EN (BIT(1))
@@ -331,9 +339,11 @@
int ret = 0;
unsigned int io_mode = 0;
unsigned int geni_dma_mode = 0;
+ unsigned int gsi_event_en = 0;
io_mode = geni_read_reg(base, SE_IRQ_EN);
geni_dma_mode = geni_read_reg(base, SE_GENI_DMA_MODE_EN);
+ gsi_event_en = geni_read_reg(base, SE_GSI_EVENT_EN);
switch (mode) {
case FIFO_MODE:
@@ -341,15 +351,23 @@
io_mode |= (GENI_M_IRQ_EN | GENI_S_IRQ_EN);
io_mode |= (DMA_TX_IRQ_EN | DMA_RX_IRQ_EN);
geni_dma_mode &= ~GENI_DMA_MODE_EN;
+ gsi_event_en = 0;
break;
}
+ case GSI_DMA:
+ geni_dma_mode |= GENI_DMA_MODE_EN;
+ io_mode &= ~(DMA_TX_IRQ_EN | DMA_RX_IRQ_EN);
+ gsi_event_en |= (DMA_RX_EVENT_EN | DMA_TX_EVENT_EN |
+ GENI_M_EVENT_EN | GENI_S_EVENT_EN);
+ break;
default:
ret = -ENXIO;
goto exit_set_mode;
}
geni_write_reg(io_mode, base, SE_IRQ_EN);
geni_write_reg(geni_dma_mode, base, SE_GENI_DMA_MODE_EN);
+ geni_write_reg(gsi_event_en, base, SE_GSI_EVENT_EN);
exit_set_mode:
return ret;
}
diff --git a/include/linux/qpnp/qpnp-revid.h b/include/linux/qpnp/qpnp-revid.h
index a0e2283..7fca674 100644
--- a/include/linux/qpnp/qpnp-revid.h
+++ b/include/linux/qpnp/qpnp-revid.h
@@ -208,6 +208,12 @@
#define PM660_V1P1_REV3 0x01
#define PM660_V1P1_REV4 0x01
+/* PM660L REV_ID */
+#define PM660L_V1P1_REV1 0x00
+#define PM660L_V1P1_REV2 0x00
+#define PM660L_V1P1_REV3 0x01
+#define PM660L_V1P1_REV4 0x01
+
/* PMI8998 FAB_ID */
#define PMI8998_FAB_ID_SMIC 0x11
#define PMI8998_FAB_ID_GF 0x30
@@ -229,6 +235,9 @@
/* SMB1381 */
#define SMB1381_SUBTYPE 0x17
+/* SMB1355 */
+#define SMB1355_SUBTYPE 0x1C
+
struct pmic_revid_data {
u8 rev1;
u8 rev2;
diff --git a/include/linux/sched.h b/include/linux/sched.h
index 867de7d..52524a8 100644
--- a/include/linux/sched.h
+++ b/include/linux/sched.h
@@ -1167,6 +1167,8 @@
struct capacity_state *cap_states; /* ptr to capacity state array */
};
+extern bool sched_is_energy_aware(void);
+
unsigned long capacity_curr_of(int cpu);
struct sched_group;
@@ -1751,6 +1753,10 @@
#ifdef CONFIG_COMPAT_BRK
unsigned brk_randomized:1;
#endif
+#ifdef CONFIG_CGROUPS
+ /* disallow userland-initiated cgroup migration */
+ unsigned no_cgroup_migration:1;
+#endif
unsigned long atomic_flags; /* Flags needing atomic access. */
diff --git a/include/linux/uio.h b/include/linux/uio.h
index 6e22b54..c146ebc 100644
--- a/include/linux/uio.h
+++ b/include/linux/uio.h
@@ -39,7 +39,10 @@
};
union {
unsigned long nr_segs;
- int idx;
+ struct {
+ int idx;
+ int start_idx;
+ };
};
};
@@ -81,6 +84,7 @@
size_t iov_iter_copy_from_user_atomic(struct page *page,
struct iov_iter *i, unsigned long offset, size_t bytes);
void iov_iter_advance(struct iov_iter *i, size_t bytes);
+void iov_iter_revert(struct iov_iter *i, size_t bytes);
int iov_iter_fault_in_readable(struct iov_iter *i, size_t bytes);
size_t iov_iter_single_seg_count(const struct iov_iter *i);
size_t copy_page_to_iter(struct page *page, size_t offset, size_t bytes,
diff --git a/include/scsi/scsi.h b/include/scsi/scsi.h
index 8ec7c30..931b494 100644
--- a/include/scsi/scsi.h
+++ b/include/scsi/scsi.h
@@ -260,27 +260,6 @@
#define SCSI_INQ_PQ_NOT_CON 0x01
#define SCSI_INQ_PQ_NOT_CAP 0x03
-
-/*
- * Here are some scsi specific ioctl commands which are sometimes useful.
- *
- * Note that include/linux/cdrom.h also defines IOCTL 0x5300 - 0x5395
- */
-
-/* Used to obtain PUN and LUN info. Conflicts with CDROMAUDIOBUFSIZ */
-#define SCSI_IOCTL_GET_IDLUN 0x5382
-
-/* 0x5383 and 0x5384 were used for SCSI_IOCTL_TAGGED_{ENABLE,DISABLE} */
-
-/* Used to obtain the host number of a device. */
-#define SCSI_IOCTL_PROBE_HOST 0x5385
-
-/* Used to obtain the bus number for a device */
-#define SCSI_IOCTL_GET_BUS_NUMBER 0x5386
-
-/* Used to obtain the PCI location of a device */
-#define SCSI_IOCTL_GET_PCI 0x5387
-
/* Pull a u32 out of a SCSI message (using BE SCSI conventions) */
static inline __u32 scsi_to_u32(__u8 *ptr)
{
diff --git a/include/soc/qcom/memory_dump.h b/include/soc/qcom/memory_dump.h
index a7b87aa..dbae8e8 100644
--- a/include/soc/qcom/memory_dump.h
+++ b/include/soc/qcom/memory_dump.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012, 2014-2016, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012, 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
@@ -62,7 +62,7 @@
#define MSM_DUMP_MINOR(val) (val & 0xFFFFF)
-#define MAX_NUM_ENTRIES 0x120
+#define MAX_NUM_ENTRIES 0x140
enum msm_dump_data_ids {
MSM_DUMP_DATA_CPU_CTX = 0x00,
@@ -82,10 +82,12 @@
MSM_DUMP_DATA_VSENSE = 0xE9,
MSM_DUMP_DATA_RPM = 0xEA,
MSM_DUMP_DATA_SCANDUMP = 0xEB,
+ MSM_DUMP_DATA_RPMH = 0xEC,
MSM_DUMP_DATA_TMC_ETF = 0xF0,
MSM_DUMP_DATA_TMC_REG = 0x100,
MSM_DUMP_DATA_LOG_BUF = 0x110,
MSM_DUMP_DATA_LOG_BUF_FIRST_IDX = 0x111,
+ MSM_DUMP_DATA_SCANDUMP_PER_CPU = 0x130,
MSM_DUMP_DATA_MAX = MAX_NUM_ENTRIES,
};
diff --git a/include/soc/qcom/socinfo.h b/include/soc/qcom/socinfo.h
index 2656d5d..b54eefc 100644
--- a/include/soc/qcom/socinfo.h
+++ b/include/soc/qcom/socinfo.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2009-2016, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2009-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
@@ -96,6 +96,8 @@
of_flat_dt_is_compatible(of_get_flat_dt_root(), "qcom,msmhamster")
#define early_machine_is_msmfalcon() \
of_flat_dt_is_compatible(of_get_flat_dt_root(), "qcom,msmfalcon")
+#define early_machine_is_sdxpoorwills() \
+ of_flat_dt_is_compatible(of_get_flat_dt_root(), "qcom,sdxpoorwills")
#define early_machine_is_sdm845() \
of_flat_dt_is_compatible(of_get_flat_dt_root(), "qcom,sdm845")
#define early_machine_is_sdm830() \
@@ -137,6 +139,7 @@
#define early_machine_is_apqcobalt() 0
#define early_machine_is_msmhamster() 0
#define early_machine_is_msmfalcon() 0
+#define early_machine_is_sdxpoorwills() 0
#define early_machine_is_sdm845() 0
#define early_machine_is_sdm830() 0
#endif
@@ -198,6 +201,7 @@
MSM_CPU_COBALT,
MSM_CPU_HAMSTER,
MSM_CPU_FALCON,
+ SDX_CPU_SDXPOORWILLS,
MSM_CPU_SDM845,
MSM_CPU_SDM830,
};
diff --git a/include/target/target_core_base.h b/include/target/target_core_base.h
index 6233e8f..0383c60 100644
--- a/include/target/target_core_base.h
+++ b/include/target/target_core_base.h
@@ -705,6 +705,7 @@
u64 unpacked_lun;
#define SE_LUN_LINK_MAGIC 0xffff7771
u32 lun_link_magic;
+ bool lun_shutdown;
bool lun_access_ro;
u32 lun_index;
diff --git a/include/uapi/drm/sde_drm.h b/include/uapi/drm/sde_drm.h
index b1bf6aa..74034c6 100644
--- a/include/uapi/drm/sde_drm.h
+++ b/include/uapi/drm/sde_drm.h
@@ -344,4 +344,16 @@
uint64_t modes;
};
+#define SDE_MAX_ROI_V1 4
+
+/**
+ * struct sde_drm_roi_v1 - list of regions of interest for a drm object
+ * @num_rects: number of valid rectangles in the roi array
+ * @roi: list of roi rectangles
+ */
+struct sde_drm_roi_v1 {
+ uint32_t num_rects;
+ struct drm_clip_rect roi[SDE_MAX_ROI_V1];
+};
+
#endif /* _SDE_DRM_H_ */
diff --git a/include/uapi/media/cam_req_mgr.h b/include/uapi/media/cam_req_mgr.h
index fea6a70..b736755 100644
--- a/include/uapi/media/cam_req_mgr.h
+++ b/include/uapi/media/cam_req_mgr.h
@@ -21,6 +21,7 @@
#define CAM_CSIPHY_DEVICE_TYPE (CAM_DEVICE_TYPE_BASE + 8)
#define CAM_ACTUATOR_DEVICE_TYPE (CAM_DEVICE_TYPE_BASE + 9)
#define CAM_CCI_DEVICE_TYPE (CAM_DEVICE_TYPE_BASE + 10)
+#define CAM_FLASH_DEVICE_TYPE (CAM_DEVICE_TYPE_BASE + 11)
/* cam_req_mgr hdl info */
#define CAM_REQ_MGR_HDL_IDX_POS 8
@@ -189,9 +190,6 @@
#define CAM_REQ_MGR_MAP_BUF (CAM_COMMON_OPCODE_MAX + 10)
#define CAM_REQ_MGR_RELEASE_BUF (CAM_COMMON_OPCODE_MAX + 11)
#define CAM_REQ_MGR_CACHE_OPS (CAM_COMMON_OPCODE_MAX + 12)
-#define CAM_REQ_MGR_GET_MMU_HDLS_DEBUG (CAM_COMMON_OPCODE_MAX + 13)
-#define CAM_REQ_MGR_GET_IO_BUF_DEBUG (CAM_COMMON_OPCODE_MAX + 14)
-#define CAM_REQ_MGR_GET_KMD_BUF_DEBUG (CAM_COMMON_OPCODE_MAX + 15)
/* end of cam_req_mgr opcodes */
#define CAM_MEM_FLAG_HW_READ_WRITE (1<<0)
@@ -205,6 +203,7 @@
#define CAM_MEM_FLAG_STATS_BUF_TYPE (1<<8)
#define CAM_MEM_FLAG_PACKET_BUF_TYPE (1<<9)
#define CAM_MEM_FLAG_CACHE (1<<10)
+#define CAM_MEM_FLAG_HW_SHARED_ACCESS (1<<11)
#define CAM_MEM_MMU_MAX_HANDLE 16
diff --git a/include/uapi/scsi/scsi_ioctl.h b/include/uapi/scsi/scsi_ioctl.h
index 516c581a..d9ce5cc 100644
--- a/include/uapi/scsi/scsi_ioctl.h
+++ b/include/uapi/scsi/scsi_ioctl.h
@@ -17,9 +17,25 @@
#define SCSI_REMOVAL_PREVENT 1
#define SCSI_REMOVAL_ALLOW 0
-#ifdef __KERNEL__
+/*
+ * Here are some scsi specific ioctl commands which are sometimes useful.
+ *
+ * Note that include/linux/cdrom.h also defines IOCTL 0x5300 - 0x5395
+ */
-struct scsi_device;
+/* Used to obtain PUN and LUN info. Conflicts with CDROMAUDIOBUFSIZ */
+#define SCSI_IOCTL_GET_IDLUN 0x5382
+
+/* 0x5383 and 0x5384 were used for SCSI_IOCTL_TAGGED_{ENABLE,DISABLE} */
+
+/* Used to obtain the host number of a device. */
+#define SCSI_IOCTL_PROBE_HOST 0x5385
+
+/* Used to obtain the bus number for a device */
+#define SCSI_IOCTL_GET_BUS_NUMBER 0x5386
+
+/* Used to obtain the PCI location of a device */
+#define SCSI_IOCTL_GET_PCI 0x5387
/*
* Structures used for scsi_ioctl et al.
@@ -42,9 +58,11 @@
unsigned char host_wwn[8]; // include NULL term.
} Scsi_FCTargAddress;
+#ifdef __KERNEL__
+struct scsi_device;
+
int scsi_ioctl_block_when_processing_errors(struct scsi_device *sdev,
int cmd, bool ndelay);
extern int scsi_ioctl(struct scsi_device *, int, void __user *);
-
#endif /* __KERNEL__ */
#endif /* _SCSI_IOCTL_H */
diff --git a/kernel/cgroup.c b/kernel/cgroup.c
index eadd942..6670008 100644
--- a/kernel/cgroup.c
+++ b/kernel/cgroup.c
@@ -2877,7 +2877,7 @@
if (!uid_eq(cred->euid, GLOBAL_ROOT_UID) &&
!uid_eq(cred->euid, tcred->uid) &&
!uid_eq(cred->euid, tcred->suid) &&
- !ns_capable(tcred->user_ns, CAP_SYS_RESOURCE))
+ !ns_capable(tcred->user_ns, CAP_SYS_NICE))
ret = -EACCES;
if (!ret && cgroup_on_dfl(dst_cgrp)) {
@@ -2941,11 +2941,12 @@
tsk = tsk->group_leader;
/*
- * Workqueue threads may acquire PF_NO_SETAFFINITY and become
- * trapped in a cpuset, or RT worker may be born in a cgroup
- * with no rt_runtime allocated. Just say no.
+ * kthreads may acquire PF_NO_SETAFFINITY during initialization.
+ * If userland migrates such a kthread to a non-root cgroup, it can
+ * become trapped in a cpuset, or RT kthread may be born in a
+ * cgroup with no rt_runtime allocated. Just say no.
*/
- if (tsk == kthreadd_task || (tsk->flags & PF_NO_SETAFFINITY)) {
+ if (tsk->no_cgroup_migration || (tsk->flags & PF_NO_SETAFFINITY)) {
ret = -EINVAL;
goto out_unlock_rcu;
}
diff --git a/kernel/kthread.c b/kernel/kthread.c
index be2cc1f..c2c911a 100644
--- a/kernel/kthread.c
+++ b/kernel/kthread.c
@@ -18,6 +18,7 @@
#include <linux/freezer.h>
#include <linux/ptrace.h>
#include <linux/uaccess.h>
+#include <linux/cgroup.h>
#include <trace/events/sched.h>
static DEFINE_SPINLOCK(kthread_create_lock);
@@ -205,6 +206,7 @@
ret = -EINTR;
if (!test_bit(KTHREAD_SHOULD_STOP, &self.flags)) {
+ cgroup_kthread_ready();
__kthread_parkme(&self);
ret = threadfn(data);
}
@@ -530,6 +532,7 @@
set_mems_allowed(node_states[N_MEMORY]);
current->flags |= PF_NOFREEZE;
+ cgroup_init_kthreadd();
for (;;) {
set_current_state(TASK_INTERRUPTIBLE);
diff --git a/kernel/sched/cpufreq_schedutil.c b/kernel/sched/cpufreq_schedutil.c
index 69e0689..27d96e2 100644
--- a/kernel/sched/cpufreq_schedutil.c
+++ b/kernel/sched/cpufreq_schedutil.c
@@ -12,11 +12,14 @@
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
#include <linux/cpufreq.h>
+#include <linux/kthread.h>
#include <linux/slab.h>
#include <trace/events/power.h>
#include "sched.h"
+#define SUGOV_KTHREAD_PRIORITY 50
+
struct sugov_tunables {
struct gov_attr_set attr_set;
unsigned int rate_limit_us;
@@ -32,11 +35,14 @@
u64 last_freq_update_time;
s64 freq_update_delay_ns;
unsigned int next_freq;
+ unsigned int cached_raw_freq;
/* The next fields are only needed if fast switch cannot be used. */
struct irq_work irq_work;
- struct work_struct work;
+ struct kthread_work work;
struct mutex work_lock;
+ struct kthread_worker worker;
+ struct task_struct *thread;
bool work_in_progress;
bool need_freq_update;
@@ -46,7 +52,6 @@
struct update_util_data update_util;
struct sugov_policy *sg_policy;
- unsigned int cached_raw_freq;
unsigned long iowait_boost;
unsigned long iowait_boost_max;
u64 last_update;
@@ -110,7 +115,7 @@
/**
* get_next_freq - Compute a new frequency for a given cpufreq policy.
- * @sg_cpu: schedutil cpu object to compute the new frequency for.
+ * @sg_policy: schedutil policy object to compute the new frequency for.
* @util: Current CPU utilization.
* @max: CPU capacity.
*
@@ -130,19 +135,18 @@
* next_freq (as calculated above) is returned, subject to policy min/max and
* cpufreq driver limitations.
*/
-static unsigned int get_next_freq(struct sugov_cpu *sg_cpu, unsigned long util,
- unsigned long max)
+static unsigned int get_next_freq(struct sugov_policy *sg_policy,
+ unsigned long util, unsigned long max)
{
- struct sugov_policy *sg_policy = sg_cpu->sg_policy;
struct cpufreq_policy *policy = sg_policy->policy;
unsigned int freq = arch_scale_freq_invariant() ?
policy->cpuinfo.max_freq : policy->cur;
freq = (freq + (freq >> 2)) * util / max;
- if (freq == sg_cpu->cached_raw_freq && sg_policy->next_freq != UINT_MAX)
+ if (freq == sg_policy->cached_raw_freq && sg_policy->next_freq != UINT_MAX)
return sg_policy->next_freq;
- sg_cpu->cached_raw_freq = freq;
+ sg_policy->cached_raw_freq = freq;
return cpufreq_driver_resolve_freq(policy, freq);
}
@@ -207,7 +211,7 @@
} else {
sugov_get_util(&util, &max);
sugov_iowait_boost(sg_cpu, &util, &max);
- next_f = get_next_freq(sg_cpu, util, max);
+ next_f = get_next_freq(sg_policy, util, max);
}
sugov_update_commit(sg_policy, time, next_f);
}
@@ -261,7 +265,7 @@
sugov_iowait_boost(j_sg_cpu, &util, &max);
}
- return get_next_freq(sg_cpu, util, max);
+ return get_next_freq(sg_policy, util, max);
}
static void sugov_update_shared(struct update_util_data *hook, u64 time,
@@ -291,7 +295,7 @@
raw_spin_unlock(&sg_policy->update_lock);
}
-static void sugov_work(struct work_struct *work)
+static void sugov_work(struct kthread_work *work)
{
struct sugov_policy *sg_policy = container_of(work, struct sugov_policy, work);
@@ -308,7 +312,21 @@
struct sugov_policy *sg_policy;
sg_policy = container_of(irq_work, struct sugov_policy, irq_work);
- schedule_work_on(smp_processor_id(), &sg_policy->work);
+
+ /*
+ * For RT and deadline tasks, the schedutil governor shoots the
+ * frequency to maximum. Special care must be taken to ensure that this
+ * kthread doesn't result in the same behavior.
+ *
+ * This is (mostly) guaranteed by the work_in_progress flag. The flag is
+ * updated only at the end of the sugov_work() function and before that
+ * the schedutil governor rejects all other frequency scaling requests.
+ *
+ * There is a very rare case though, where the RT thread yields right
+ * after the work_in_progress flag is cleared. The effects of that are
+ * neglected for now.
+ */
+ kthread_queue_work(&sg_policy->worker, &sg_policy->work);
}
/************************** sysfs interface ************************/
@@ -371,19 +389,64 @@
return NULL;
sg_policy->policy = policy;
- init_irq_work(&sg_policy->irq_work, sugov_irq_work);
- INIT_WORK(&sg_policy->work, sugov_work);
- mutex_init(&sg_policy->work_lock);
raw_spin_lock_init(&sg_policy->update_lock);
return sg_policy;
}
static void sugov_policy_free(struct sugov_policy *sg_policy)
{
- mutex_destroy(&sg_policy->work_lock);
kfree(sg_policy);
}
+static int sugov_kthread_create(struct sugov_policy *sg_policy)
+{
+ struct task_struct *thread;
+ struct sched_param param = { .sched_priority = MAX_USER_RT_PRIO / 2 };
+ struct cpufreq_policy *policy = sg_policy->policy;
+ int ret;
+
+ /* kthread only required for slow path */
+ if (policy->fast_switch_enabled)
+ return 0;
+
+ kthread_init_work(&sg_policy->work, sugov_work);
+ kthread_init_worker(&sg_policy->worker);
+ thread = kthread_create(kthread_worker_fn, &sg_policy->worker,
+ "sugov:%d",
+ cpumask_first(policy->related_cpus));
+ if (IS_ERR(thread)) {
+ pr_err("failed to create sugov thread: %ld\n", PTR_ERR(thread));
+ return PTR_ERR(thread);
+ }
+
+ ret = sched_setscheduler_nocheck(thread, SCHED_FIFO, ¶m);
+ if (ret) {
+ kthread_stop(thread);
+ pr_warn("%s: failed to set SCHED_FIFO\n", __func__);
+ return ret;
+ }
+
+ sg_policy->thread = thread;
+ kthread_bind_mask(thread, policy->related_cpus);
+ init_irq_work(&sg_policy->irq_work, sugov_irq_work);
+ mutex_init(&sg_policy->work_lock);
+
+ wake_up_process(thread);
+
+ return 0;
+}
+
+static void sugov_kthread_stop(struct sugov_policy *sg_policy)
+{
+ /* kthread only required for slow path */
+ if (sg_policy->policy->fast_switch_enabled)
+ return;
+
+ kthread_flush_worker(&sg_policy->worker);
+ kthread_stop(sg_policy->thread);
+ mutex_destroy(&sg_policy->work_lock);
+}
+
static struct sugov_tunables *sugov_tunables_alloc(struct sugov_policy *sg_policy)
{
struct sugov_tunables *tunables;
@@ -416,16 +479,24 @@
if (policy->governor_data)
return -EBUSY;
+ cpufreq_enable_fast_switch(policy);
+
sg_policy = sugov_policy_alloc(policy);
- if (!sg_policy)
- return -ENOMEM;
+ if (!sg_policy) {
+ ret = -ENOMEM;
+ goto disable_fast_switch;
+ }
+
+ ret = sugov_kthread_create(sg_policy);
+ if (ret)
+ goto free_sg_policy;
mutex_lock(&global_tunables_lock);
if (global_tunables) {
if (WARN_ON(have_governor_per_policy())) {
ret = -EINVAL;
- goto free_sg_policy;
+ goto stop_kthread;
}
policy->governor_data = sg_policy;
sg_policy->tunables = global_tunables;
@@ -437,7 +508,7 @@
tunables = sugov_tunables_alloc(sg_policy);
if (!tunables) {
ret = -ENOMEM;
- goto free_sg_policy;
+ goto stop_kthread;
}
tunables->rate_limit_us = LATENCY_MULTIPLIER;
@@ -454,20 +525,25 @@
if (ret)
goto fail;
- out:
+out:
mutex_unlock(&global_tunables_lock);
-
- cpufreq_enable_fast_switch(policy);
return 0;
- fail:
+fail:
policy->governor_data = NULL;
sugov_tunables_free(tunables);
- free_sg_policy:
+stop_kthread:
+ sugov_kthread_stop(sg_policy);
+
+free_sg_policy:
mutex_unlock(&global_tunables_lock);
sugov_policy_free(sg_policy);
+
+disable_fast_switch:
+ cpufreq_disable_fast_switch(policy);
+
pr_err("initialization failed (error %d)\n", ret);
return ret;
}
@@ -478,8 +554,6 @@
struct sugov_tunables *tunables = sg_policy->tunables;
unsigned int count;
- cpufreq_disable_fast_switch(policy);
-
mutex_lock(&global_tunables_lock);
count = gov_attr_set_put(&tunables->attr_set, &sg_policy->tunables_hook);
@@ -489,7 +563,9 @@
mutex_unlock(&global_tunables_lock);
+ sugov_kthread_stop(sg_policy);
sugov_policy_free(sg_policy);
+ cpufreq_disable_fast_switch(policy);
}
static int sugov_start(struct cpufreq_policy *policy)
@@ -502,25 +578,19 @@
sg_policy->next_freq = UINT_MAX;
sg_policy->work_in_progress = false;
sg_policy->need_freq_update = false;
+ sg_policy->cached_raw_freq = 0;
for_each_cpu(cpu, policy->cpus) {
struct sugov_cpu *sg_cpu = &per_cpu(sugov_cpu, cpu);
+ memset(sg_cpu, 0, sizeof(*sg_cpu));
sg_cpu->sg_policy = sg_policy;
- if (policy_is_shared(policy)) {
- sg_cpu->util = 0;
- sg_cpu->max = 0;
- sg_cpu->flags = SCHED_CPUFREQ_RT;
- sg_cpu->last_update = 0;
- sg_cpu->cached_raw_freq = 0;
- sg_cpu->iowait_boost = 0;
- sg_cpu->iowait_boost_max = policy->cpuinfo.max_freq;
- cpufreq_add_update_util_hook(cpu, &sg_cpu->update_util,
- sugov_update_shared);
- } else {
- cpufreq_add_update_util_hook(cpu, &sg_cpu->update_util,
- sugov_update_single);
- }
+ sg_cpu->flags = SCHED_CPUFREQ_RT;
+ sg_cpu->iowait_boost_max = policy->cpuinfo.max_freq;
+ cpufreq_add_update_util_hook(cpu, &sg_cpu->update_util,
+ policy_is_shared(policy) ?
+ sugov_update_shared :
+ sugov_update_single);
}
return 0;
}
@@ -535,8 +605,10 @@
synchronize_sched();
- irq_work_sync(&sg_policy->irq_work);
- cancel_work_sync(&sg_policy->work);
+ if (!policy->fast_switch_enabled) {
+ irq_work_sync(&sg_policy->irq_work);
+ kthread_cancel_work_sync(&sg_policy->work);
+ }
}
static void sugov_limits(struct cpufreq_policy *policy)
diff --git a/kernel/sched/energy.c b/kernel/sched/energy.c
index b0656b7..05dd2cb 100644
--- a/kernel/sched/energy.c
+++ b/kernel/sched/energy.c
@@ -56,6 +56,9 @@
int sd_level, i, nstates, cpu;
const __be32 *val;
+ if (!sched_is_energy_aware())
+ return;
+
for_each_possible_cpu(cpu) {
cn = of_get_cpu_node(cpu, NULL);
if (!cn) {
diff --git a/kernel/sched/fair.c b/kernel/sched/fair.c
index 2a8643c..6fb615e 100644
--- a/kernel/sched/fair.c
+++ b/kernel/sched/fair.c
@@ -5343,6 +5343,15 @@
return sched_feat(ENERGY_AWARE);
}
+/*
+ * Externally visible function. Let's keep the one above
+ * so that the check is inlined/optimized in the sched paths.
+ */
+bool sched_is_energy_aware(void)
+{
+ return energy_aware();
+}
+
struct energy_env {
struct sched_group *sg_top;
struct sched_group *sg_cap;
diff --git a/kernel/time/hrtimer.c b/kernel/time/hrtimer.c
index 4223c4a..b1c7852 100644
--- a/kernel/time/hrtimer.c
+++ b/kernel/time/hrtimer.c
@@ -49,6 +49,7 @@
#include <linux/sched/deadline.h>
#include <linux/timer.h>
#include <linux/freezer.h>
+#include <linux/delay.h>
#include <asm/uaccess.h>
@@ -1616,20 +1617,41 @@
}
#ifdef CONFIG_HOTPLUG_CPU
-static void migrate_hrtimer_list(struct hrtimer_clock_base *old_base,
- struct hrtimer_clock_base *new_base,
+static void migrate_hrtimer_list(struct hrtimer_cpu_base *old_base,
+ struct hrtimer_cpu_base *new_base,
+ unsigned int i, bool wait,
bool remove_pinned)
{
struct hrtimer *timer;
struct timerqueue_node *node;
struct timerqueue_head pinned;
int is_pinned;
+ struct hrtimer_clock_base *old_c_base = &old_base->clock_base[i];
+ struct hrtimer_clock_base *new_c_base = &new_base->clock_base[i];
timerqueue_init_head(&pinned);
- while ((node = timerqueue_getnext(&old_base->active))) {
+ while ((node = timerqueue_getnext(&old_c_base->active))) {
timer = container_of(node, struct hrtimer, node);
- BUG_ON(hrtimer_callback_running(timer));
+ if (wait) {
+ /* Ensure timers are done running before continuing */
+ while (hrtimer_callback_running(timer)) {
+ raw_spin_unlock(&old_base->lock);
+ raw_spin_unlock(&new_base->lock);
+ cpu_relax();
+ /*
+ * cpu_relax may just be a barrier. Grant the
+ * run_hrtimer_list code some time to obtain
+ * the spinlock.
+ */
+ udelay(1);
+ raw_spin_lock(&new_base->lock);
+ raw_spin_lock_nested(&old_base->lock,
+ SINGLE_DEPTH_NESTING);
+ }
+ } else {
+ BUG_ON(hrtimer_callback_running(timer));
+ }
debug_deactivate(timer);
/*
@@ -1637,7 +1659,7 @@
* timer could be seen as !active and just vanish away
* under us on another CPU
*/
- __remove_hrtimer(timer, old_base, HRTIMER_STATE_ENQUEUED, 0);
+ __remove_hrtimer(timer, old_c_base, HRTIMER_STATE_ENQUEUED, 0);
is_pinned = timer->state & HRTIMER_STATE_PINNED;
if (!remove_pinned && is_pinned) {
@@ -1645,7 +1667,7 @@
continue;
}
- timer->base = new_base;
+ timer->base = new_c_base;
/*
* Enqueue the timers on the new cpu. This does not
* reprogram the event device in case the timer
@@ -1654,7 +1676,7 @@
* sort out already expired timers and reprogram the
* event device.
*/
- enqueue_hrtimer(timer, new_base);
+ enqueue_hrtimer(timer, new_c_base);
}
/* Re-queue pinned timers for non-hotplug usecase */
@@ -1662,11 +1684,12 @@
timer = container_of(node, struct hrtimer, node);
timerqueue_del(&pinned, &timer->node);
- enqueue_hrtimer(timer, old_base);
+ enqueue_hrtimer(timer, old_c_base);
}
}
-static void __migrate_hrtimers(unsigned int scpu, bool remove_pinned)
+static void
+__migrate_hrtimers(unsigned int scpu, bool wait, bool remove_pinned)
{
struct hrtimer_cpu_base *old_base, *new_base;
unsigned long flags;
@@ -1683,8 +1706,8 @@
raw_spin_lock_nested(&old_base->lock, SINGLE_DEPTH_NESTING);
for (i = 0; i < HRTIMER_MAX_CLOCK_BASES; i++) {
- migrate_hrtimer_list(&old_base->clock_base[i],
- &new_base->clock_base[i], remove_pinned);
+ migrate_hrtimer_list(old_base, new_base, i, wait,
+ remove_pinned);
}
raw_spin_unlock(&old_base->lock);
@@ -1700,13 +1723,13 @@
BUG_ON(cpu_online(scpu));
tick_cancel_sched_timer(scpu);
- __migrate_hrtimers(scpu, true);
+ __migrate_hrtimers(scpu, false, true);
return 0;
}
void hrtimer_quiesce_cpu(void *cpup)
{
- __migrate_hrtimers(*(int *)cpup, false);
+ __migrate_hrtimers(*(int *)cpup, true, false);
}
#endif /* CONFIG_HOTPLUG_CPU */
diff --git a/kernel/time/timer.c b/kernel/time/timer.c
index 470d966..5463c3b 100644
--- a/kernel/time/timer.c
+++ b/kernel/time/timer.c
@@ -1856,7 +1856,8 @@
spin_lock_irqsave(&new_base->lock, flags);
spin_lock_nested(&old_base->lock, SINGLE_DEPTH_NESTING);
- BUG_ON(old_base->running_timer);
+ if (!cpu_online(cpu))
+ BUG_ON(old_base->running_timer);
for (i = 0; i < WHEEL_SIZE; i++)
migrate_timer_list(new_base, old_base->vectors + i,
diff --git a/kernel/trace/ftrace.c b/kernel/trace/ftrace.c
index da87b3c..221eb59 100644
--- a/kernel/trace/ftrace.c
+++ b/kernel/trace/ftrace.c
@@ -3736,23 +3736,24 @@
ftrace_probe_registered = 1;
}
-static void __disable_ftrace_function_probe(void)
+static bool __disable_ftrace_function_probe(void)
{
int i;
if (!ftrace_probe_registered)
- return;
+ return false;
for (i = 0; i < FTRACE_FUNC_HASHSIZE; i++) {
struct hlist_head *hhd = &ftrace_func_hash[i];
if (hhd->first)
- return;
+ return false;
}
/* no more funcs left */
ftrace_shutdown(&trace_probe_ops, 0);
ftrace_probe_registered = 0;
+ return true;
}
@@ -3882,6 +3883,7 @@
__unregister_ftrace_function_probe(char *glob, struct ftrace_probe_ops *ops,
void *data, int flags)
{
+ struct ftrace_ops_hash old_hash_ops;
struct ftrace_func_entry *rec_entry;
struct ftrace_func_probe *entry;
struct ftrace_func_probe *p;
@@ -3893,6 +3895,7 @@
struct hlist_node *tmp;
char str[KSYM_SYMBOL_LEN];
int i, ret;
+ bool disabled;
if (glob && (strcmp(glob, "*") == 0 || !strlen(glob)))
func_g.search = NULL;
@@ -3911,6 +3914,10 @@
mutex_lock(&trace_probe_ops.func_hash->regex_lock);
+ old_hash_ops.filter_hash = old_hash;
+ /* Probes only have filters */
+ old_hash_ops.notrace_hash = NULL;
+
hash = alloc_and_copy_ftrace_hash(FTRACE_HASH_DEFAULT_BITS, *orig_hash);
if (!hash)
/* Hmm, should report this somehow */
@@ -3948,12 +3955,17 @@
}
}
mutex_lock(&ftrace_lock);
- __disable_ftrace_function_probe();
+ disabled = __disable_ftrace_function_probe();
/*
* Remove after the disable is called. Otherwise, if the last
* probe is removed, a null hash means *all enabled*.
*/
ret = ftrace_hash_move(&trace_probe_ops, 1, orig_hash, hash);
+
+ /* still need to update the function call sites */
+ if (ftrace_enabled && !disabled)
+ ftrace_run_modify_code(&trace_probe_ops, FTRACE_UPDATE_CALLS,
+ &old_hash_ops);
synchronize_sched();
if (!ret)
free_ftrace_hash_rcu(old_hash);
@@ -5389,6 +5401,15 @@
trace_free_pid_list(pid_list);
}
+void ftrace_clear_pids(struct trace_array *tr)
+{
+ mutex_lock(&ftrace_lock);
+
+ clear_ftrace_pids(tr);
+
+ mutex_unlock(&ftrace_lock);
+}
+
static void ftrace_pid_reset(struct trace_array *tr)
{
mutex_lock(&ftrace_lock);
diff --git a/kernel/trace/ring_buffer.c b/kernel/trace/ring_buffer.c
index f30847a..f5c016e 100644
--- a/kernel/trace/ring_buffer.c
+++ b/kernel/trace/ring_buffer.c
@@ -3435,11 +3435,23 @@
int ring_buffer_iter_empty(struct ring_buffer_iter *iter)
{
struct ring_buffer_per_cpu *cpu_buffer;
+ struct buffer_page *reader;
+ struct buffer_page *head_page;
+ struct buffer_page *commit_page;
+ unsigned commit;
cpu_buffer = iter->cpu_buffer;
- return iter->head_page == cpu_buffer->commit_page &&
- iter->head == rb_commit_index(cpu_buffer);
+ /* Remember, trace recording is off when iterator is in use */
+ reader = cpu_buffer->reader_page;
+ head_page = cpu_buffer->head_page;
+ commit_page = cpu_buffer->commit_page;
+ commit = rb_page_commit(commit_page);
+
+ return ((iter->head_page == commit_page && iter->head == commit) ||
+ (iter->head_page == reader && commit_page == head_page &&
+ head_page->read == commit &&
+ iter->head == rb_page_commit(cpu_buffer->reader_page)));
}
EXPORT_SYMBOL_GPL(ring_buffer_iter_empty);
diff --git a/kernel/trace/trace.c b/kernel/trace/trace.c
index b0c47c2..ebf9498 100644
--- a/kernel/trace/trace.c
+++ b/kernel/trace/trace.c
@@ -6576,11 +6576,13 @@
return ret;
out_reg:
+ ret = alloc_snapshot(&global_trace);
+ if (ret < 0)
+ goto out;
+
ret = register_ftrace_function_probe(glob, ops, count);
- if (ret >= 0)
- alloc_snapshot(&global_trace);
-
+ out:
return ret < 0 ? ret : 0;
}
@@ -7245,6 +7247,7 @@
tracing_set_nop(tr);
event_trace_del_tracer(tr);
+ ftrace_clear_pids(tr);
ftrace_destroy_function_files(tr);
tracefs_remove_recursive(tr->dir);
free_trace_buffers(tr);
diff --git a/kernel/trace/trace.h b/kernel/trace/trace.h
index 38dbb36..e5d06c9 100644
--- a/kernel/trace/trace.h
+++ b/kernel/trace/trace.h
@@ -871,6 +871,7 @@
void ftrace_init_tracefs(struct trace_array *tr, struct dentry *d_tracer);
void ftrace_init_tracefs_toplevel(struct trace_array *tr,
struct dentry *d_tracer);
+void ftrace_clear_pids(struct trace_array *tr);
#else
static inline int ftrace_trace_task(struct trace_array *tr)
{
@@ -889,6 +890,7 @@
static inline void ftrace_reset_array_ops(struct trace_array *tr) { }
static inline void ftrace_init_tracefs(struct trace_array *tr, struct dentry *d) { }
static inline void ftrace_init_tracefs_toplevel(struct trace_array *tr, struct dentry *d) { }
+static inline void ftrace_clear_pids(struct trace_array *tr) { }
/* ftace_func_t type is not defined, use macro instead of static inline */
#define ftrace_init_array_ops(tr, func) do { } while (0)
#endif /* CONFIG_FUNCTION_TRACER */
diff --git a/lib/iov_iter.c b/lib/iov_iter.c
index efb0b4d..a75ea63 100644
--- a/lib/iov_iter.c
+++ b/lib/iov_iter.c
@@ -734,6 +734,68 @@
}
EXPORT_SYMBOL(iov_iter_advance);
+void iov_iter_revert(struct iov_iter *i, size_t unroll)
+{
+ if (!unroll)
+ return;
+ i->count += unroll;
+ if (unlikely(i->type & ITER_PIPE)) {
+ struct pipe_inode_info *pipe = i->pipe;
+ int idx = i->idx;
+ size_t off = i->iov_offset;
+ while (1) {
+ size_t n = off - pipe->bufs[idx].offset;
+ if (unroll < n) {
+ off -= (n - unroll);
+ break;
+ }
+ unroll -= n;
+ if (!unroll && idx == i->start_idx) {
+ off = 0;
+ break;
+ }
+ if (!idx--)
+ idx = pipe->buffers - 1;
+ off = pipe->bufs[idx].offset + pipe->bufs[idx].len;
+ }
+ i->iov_offset = off;
+ i->idx = idx;
+ pipe_truncate(i);
+ return;
+ }
+ if (unroll <= i->iov_offset) {
+ i->iov_offset -= unroll;
+ return;
+ }
+ unroll -= i->iov_offset;
+ if (i->type & ITER_BVEC) {
+ const struct bio_vec *bvec = i->bvec;
+ while (1) {
+ size_t n = (--bvec)->bv_len;
+ i->nr_segs++;
+ if (unroll <= n) {
+ i->bvec = bvec;
+ i->iov_offset = n - unroll;
+ return;
+ }
+ unroll -= n;
+ }
+ } else { /* same logics for iovec and kvec */
+ const struct iovec *iov = i->iov;
+ while (1) {
+ size_t n = (--iov)->iov_len;
+ i->nr_segs++;
+ if (unroll <= n) {
+ i->iov = iov;
+ i->iov_offset = n - unroll;
+ return;
+ }
+ unroll -= n;
+ }
+ }
+}
+EXPORT_SYMBOL(iov_iter_revert);
+
/*
* Return the count of just the current iov_iter segment.
*/
@@ -787,6 +849,7 @@
i->idx = (pipe->curbuf + pipe->nrbufs) & (pipe->buffers - 1);
i->iov_offset = 0;
i->count = count;
+ i->start_idx = i->idx;
}
EXPORT_SYMBOL(iov_iter_pipe);
diff --git a/mm/Kconfig b/mm/Kconfig
index 0183305..eb10c90 100644
--- a/mm/Kconfig
+++ b/mm/Kconfig
@@ -720,3 +720,13 @@
bool
config ARCH_HAS_PKEYS
bool
+
+config FORCE_ALLOC_FROM_DMA_ZONE
+ bool "Force certain memory allocators to always return ZONE_DMA memory"
+ depends on ZONE_DMA
+ help
+ Ensure certain memory allocators always return memory from ZONE_DMA.
+ This option helps ensure that clients who require ZONE_DMA memory are
+ always using ZONE_DMA memory.
+
+ If unsure, say "n".
diff --git a/mm/huge_memory.c b/mm/huge_memory.c
index 917555c..d5b2b75 100644
--- a/mm/huge_memory.c
+++ b/mm/huge_memory.c
@@ -1380,8 +1380,7 @@
deactivate_page(page);
if (pmd_young(orig_pmd) || pmd_dirty(orig_pmd)) {
- orig_pmd = pmdp_huge_get_and_clear_full(tlb->mm, addr, pmd,
- tlb->fullmm);
+ pmdp_invalidate(vma, addr, pmd);
orig_pmd = pmd_mkold(orig_pmd);
orig_pmd = pmd_mkclean(orig_pmd);
diff --git a/mm/memcontrol.c b/mm/memcontrol.c
index e866ddcc..fdc790a 100644
--- a/mm/memcontrol.c
+++ b/mm/memcontrol.c
@@ -2152,6 +2152,8 @@
struct work_struct work;
};
+static struct workqueue_struct *memcg_kmem_cache_create_wq;
+
static void memcg_kmem_cache_create_func(struct work_struct *w)
{
struct memcg_kmem_cache_create_work *cw =
@@ -2183,7 +2185,7 @@
cw->cachep = cachep;
INIT_WORK(&cw->work, memcg_kmem_cache_create_func);
- schedule_work(&cw->work);
+ queue_work(memcg_kmem_cache_create_wq, &cw->work);
}
static void memcg_schedule_kmem_cache_create(struct mem_cgroup *memcg,
@@ -5796,6 +5798,17 @@
{
int cpu, node;
+#ifndef CONFIG_SLOB
+ /*
+ * Kmem cache creation is mostly done with the slab_mutex held,
+ * so use a special workqueue to avoid stalling all worker
+ * threads in case lots of cgroups are created simultaneously.
+ */
+ memcg_kmem_cache_create_wq =
+ alloc_ordered_workqueue("memcg_kmem_cache_create", 0);
+ BUG_ON(!memcg_kmem_cache_create_wq);
+#endif
+
hotcpu_notifier(memcg_cpu_hotplug_callback, 0);
for_each_possible_cpu(cpu)
diff --git a/mm/migrate.c b/mm/migrate.c
index f49de3cf..435f674 100644
--- a/mm/migrate.c
+++ b/mm/migrate.c
@@ -183,9 +183,9 @@
unlock_page(page);
put_page(page);
} else {
- putback_lru_page(page);
dec_node_page_state(page, NR_ISOLATED_ANON +
page_is_file_cache(page));
+ putback_lru_page(page);
}
}
}
diff --git a/mm/vmscan.c b/mm/vmscan.c
index 9d3f6d3..b4d398b 100644
--- a/mm/vmscan.c
+++ b/mm/vmscan.c
@@ -2595,16 +2595,23 @@
sc->nr_scanned - nr_scanned,
node_lru_pages);
+ /*
+ * Record the subtree's reclaim efficiency. The reclaimed
+ * pages from slab is excluded here because the corresponding
+ * scanned pages is not accounted. Moreover, freeing a page
+ * by slab shrinking depends on each slab's object population,
+ * making the cost model (i.e. scan:free) different from that
+ * of LRU.
+ */
+ vmpressure(sc->gfp_mask, sc->target_mem_cgroup, true,
+ sc->nr_scanned - nr_scanned,
+ sc->nr_reclaimed - nr_reclaimed);
+
if (reclaim_state) {
sc->nr_reclaimed += reclaim_state->reclaimed_slab;
reclaim_state->reclaimed_slab = 0;
}
- /* Record the subtree's reclaim efficiency */
- vmpressure(sc->gfp_mask, sc->target_mem_cgroup, true,
- sc->nr_scanned - nr_scanned,
- sc->nr_reclaimed - nr_reclaimed);
-
if (sc->nr_reclaimed - nr_reclaimed)
reclaimable = true;
diff --git a/mm/zsmalloc.c b/mm/zsmalloc.c
index b0bc023..1689bb5 100644
--- a/mm/zsmalloc.c
+++ b/mm/zsmalloc.c
@@ -280,7 +280,7 @@
struct zspage {
struct {
unsigned int fullness:FULLNESS_BITS;
- unsigned int class:CLASS_BITS;
+ unsigned int class:CLASS_BITS + 1;
unsigned int isolated:ISOLATED_BITS;
unsigned int magic:MAGIC_VAL_BITS;
};
diff --git a/net/core/datagram.c b/net/core/datagram.c
index b7de71f..963732e 100644
--- a/net/core/datagram.c
+++ b/net/core/datagram.c
@@ -378,7 +378,7 @@
struct iov_iter *to, int len)
{
int start = skb_headlen(skb);
- int i, copy = start - offset;
+ int i, copy = start - offset, start_off = offset, n;
struct sk_buff *frag_iter;
trace_skb_copy_datagram_iovec(skb, len);
@@ -387,11 +387,12 @@
if (copy > 0) {
if (copy > len)
copy = len;
- if (copy_to_iter(skb->data + offset, copy, to) != copy)
+ n = copy_to_iter(skb->data + offset, copy, to);
+ offset += n;
+ if (n != copy)
goto short_copy;
if ((len -= copy) == 0)
return 0;
- offset += copy;
}
/* Copy paged appendix. Hmm... why does this look so complicated? */
@@ -405,13 +406,14 @@
if ((copy = end - offset) > 0) {
if (copy > len)
copy = len;
- if (copy_page_to_iter(skb_frag_page(frag),
+ n = copy_page_to_iter(skb_frag_page(frag),
frag->page_offset + offset -
- start, copy, to) != copy)
+ start, copy, to);
+ offset += n;
+ if (n != copy)
goto short_copy;
if (!(len -= copy))
return 0;
- offset += copy;
}
start = end;
}
@@ -443,6 +445,7 @@
*/
fault:
+ iov_iter_revert(to, offset - start_off);
return -EFAULT;
short_copy:
@@ -593,7 +596,7 @@
__wsum *csump)
{
int start = skb_headlen(skb);
- int i, copy = start - offset;
+ int i, copy = start - offset, start_off = offset;
struct sk_buff *frag_iter;
int pos = 0;
int n;
@@ -603,11 +606,11 @@
if (copy > len)
copy = len;
n = csum_and_copy_to_iter(skb->data + offset, copy, csump, to);
+ offset += n;
if (n != copy)
goto fault;
if ((len -= copy) == 0)
return 0;
- offset += copy;
pos = copy;
}
@@ -629,12 +632,12 @@
offset - start, copy,
&csum2, to);
kunmap(page);
+ offset += n;
if (n != copy)
goto fault;
*csump = csum_block_add(*csump, csum2, pos);
if (!(len -= copy))
return 0;
- offset += copy;
pos += copy;
}
start = end;
@@ -667,6 +670,7 @@
return 0;
fault:
+ iov_iter_revert(to, offset - start_off);
return -EFAULT;
}
@@ -751,6 +755,7 @@
}
return 0;
csum_error:
+ iov_iter_revert(&msg->msg_iter, chunk);
return -EINVAL;
fault:
return -EFAULT;
diff --git a/net/core/skbuff.c b/net/core/skbuff.c
index f0f462c..8de6707 100644
--- a/net/core/skbuff.c
+++ b/net/core/skbuff.c
@@ -209,6 +209,9 @@
u8 *data;
bool pfmemalloc;
+ if (IS_ENABLED(CONFIG_FORCE_ALLOC_FROM_DMA_ZONE))
+ gfp_mask |= GFP_DMA;
+
cache = (flags & SKB_ALLOC_FCLONE)
? skbuff_fclone_cache : skbuff_head_cache;
@@ -367,6 +370,9 @@
unsigned long flags;
void *data;
+ if (IS_ENABLED(CONFIG_FORCE_ALLOC_FROM_DMA_ZONE))
+ gfp_mask |= GFP_DMA;
+
local_irq_save(flags);
nc = this_cpu_ptr(&netdev_alloc_cache);
data = __alloc_page_frag(nc, fragsz, gfp_mask);
diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c
index 0cfb91f..7588fa9 100644
--- a/net/ipv6/addrconf.c
+++ b/net/ipv6/addrconf.c
@@ -5978,13 +5978,6 @@
.mode = 0644,
.proc_handler = proc_dointvec,
},
- {
- .procname = "accept_ra_rt_table",
- .data = &ipv6_devconf.accept_ra_rt_table,
- .maxlen = sizeof(int),
- .mode = 0644,
- .proc_handler = proc_dointvec,
- },
#ifdef CONFIG_IPV6_OPTIMISTIC_DAD
{
.procname = "optimistic_dad",
diff --git a/net/ipv6/route.c b/net/ipv6/route.c
index 477600f..73527d8 100644
--- a/net/ipv6/route.c
+++ b/net/ipv6/route.c
@@ -2165,6 +2165,8 @@
continue;
if (cfg->fc_metric && cfg->fc_metric != rt->rt6i_metric)
continue;
+ if (cfg->fc_protocol && cfg->fc_protocol != rt->rt6i_protocol)
+ continue;
dst_hold(&rt->dst);
read_unlock_bh(&table->tb6_lock);
diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c
index a697ddf..acaaf61 100644
--- a/net/mac80211/rx.c
+++ b/net/mac80211/rx.c
@@ -208,6 +208,51 @@
return len;
}
+static void ieee80211_handle_mu_mimo_mon(struct ieee80211_sub_if_data *sdata,
+ struct sk_buff *skb,
+ int rtap_vendor_space)
+{
+ struct {
+ struct ieee80211_hdr_3addr hdr;
+ u8 category;
+ u8 action_code;
+ } __packed action;
+
+ if (!sdata)
+ return;
+
+ BUILD_BUG_ON(sizeof(action) != IEEE80211_MIN_ACTION_SIZE + 1);
+
+ if (skb->len < rtap_vendor_space + sizeof(action) +
+ VHT_MUMIMO_GROUPS_DATA_LEN)
+ return;
+
+ if (!is_valid_ether_addr(sdata->u.mntr.mu_follow_addr))
+ return;
+
+ skb_copy_bits(skb, rtap_vendor_space, &action, sizeof(action));
+
+ if (!ieee80211_is_action(action.hdr.frame_control))
+ return;
+
+ if (action.category != WLAN_CATEGORY_VHT)
+ return;
+
+ if (action.action_code != WLAN_VHT_ACTION_GROUPID_MGMT)
+ return;
+
+ if (!ether_addr_equal(action.hdr.addr1, sdata->u.mntr.mu_follow_addr))
+ return;
+
+ skb = skb_copy(skb, GFP_ATOMIC);
+ if (!skb)
+ return;
+
+ skb->pkt_type = IEEE80211_SDATA_QUEUE_TYPE_FRAME;
+ skb_queue_tail(&sdata->skb_queue, skb);
+ ieee80211_queue_work(&sdata->local->hw, &sdata->work);
+}
+
/*
* ieee80211_add_rx_radiotap_header - add radiotap header
*
@@ -515,7 +560,6 @@
struct net_device *prev_dev = NULL;
int present_fcs_len = 0;
unsigned int rtap_vendor_space = 0;
- struct ieee80211_mgmt *mgmt;
struct ieee80211_sub_if_data *monitor_sdata =
rcu_dereference(local->monitor_sdata);
@@ -553,6 +597,8 @@
return remove_monitor_info(local, origskb, rtap_vendor_space);
}
+ ieee80211_handle_mu_mimo_mon(monitor_sdata, origskb, rtap_vendor_space);
+
/* room for the radiotap header based on driver features */
rt_hdrlen = ieee80211_rx_radiotap_hdrlen(local, status, origskb);
needed_headroom = rt_hdrlen - rtap_vendor_space;
@@ -618,23 +664,6 @@
ieee80211_rx_stats(sdata->dev, skb->len);
}
- mgmt = (void *)skb->data;
- if (monitor_sdata &&
- skb->len >= IEEE80211_MIN_ACTION_SIZE + 1 + VHT_MUMIMO_GROUPS_DATA_LEN &&
- ieee80211_is_action(mgmt->frame_control) &&
- mgmt->u.action.category == WLAN_CATEGORY_VHT &&
- mgmt->u.action.u.vht_group_notif.action_code == WLAN_VHT_ACTION_GROUPID_MGMT &&
- is_valid_ether_addr(monitor_sdata->u.mntr.mu_follow_addr) &&
- ether_addr_equal(mgmt->da, monitor_sdata->u.mntr.mu_follow_addr)) {
- struct sk_buff *mu_skb = skb_copy(skb, GFP_ATOMIC);
-
- if (mu_skb) {
- mu_skb->pkt_type = IEEE80211_SDATA_QUEUE_TYPE_FRAME;
- skb_queue_tail(&monitor_sdata->skb_queue, mu_skb);
- ieee80211_queue_work(&local->hw, &monitor_sdata->work);
- }
- }
-
if (prev_dev) {
skb->dev = prev_dev;
netif_receive_skb(skb);
@@ -3617,6 +3646,27 @@
!ether_addr_equal(bssid, hdr->addr1))
return false;
}
+
+ /*
+ * 802.11-2016 Table 9-26 says that for data frames, A1 must be
+ * the BSSID - we've checked that already but may have accepted
+ * the wildcard (ff:ff:ff:ff:ff:ff).
+ *
+ * It also says:
+ * The BSSID of the Data frame is determined as follows:
+ * a) If the STA is contained within an AP or is associated
+ * with an AP, the BSSID is the address currently in use
+ * by the STA contained in the AP.
+ *
+ * So we should not accept data frames with an address that's
+ * multicast.
+ *
+ * Accepting it also opens a security problem because stations
+ * could encrypt it with the GTK and inject traffic that way.
+ */
+ if (ieee80211_is_data(hdr->frame_control) && multicast)
+ return false;
+
return true;
case NL80211_IFTYPE_WDS:
if (bssid || !ieee80211_is_data(hdr->frame_control))
diff --git a/net/sctp/socket.c b/net/sctp/socket.c
index 6cbe5bd..6734420 100644
--- a/net/sctp/socket.c
+++ b/net/sctp/socket.c
@@ -4735,6 +4735,12 @@
if (!asoc)
return -EINVAL;
+ /* If there is a thread waiting on more sndbuf space for
+ * sending on this asoc, it cannot be peeled.
+ */
+ if (waitqueue_active(&asoc->wait))
+ return -EBUSY;
+
/* An association cannot be branched off from an already peeled-off
* socket, nor is this supported for tcp style sockets.
*/
@@ -7427,8 +7433,6 @@
*/
release_sock(sk);
current_timeo = schedule_timeout(current_timeo);
- if (sk != asoc->base.sk)
- goto do_error;
lock_sock(sk);
*timeo_p = current_timeo;
diff --git a/scripts/build-all.py b/scripts/build-all.py
index d36e96f..bd468cd 100755
--- a/scripts/build-all.py
+++ b/scripts/build-all.py
@@ -307,10 +307,12 @@
r'qsd*_defconfig',
r'mpq*_defconfig',
r'sdm[0-9]*_defconfig',
+ r'sdx*_defconfig',
)
arch64_pats = (
r'msm*_defconfig',
r'sdm[0-9]*_defconfig',
+ r'sdx*_defconfig',
)
for p in arch_pats:
for n in glob.glob('arch/arm/configs/' + p):
diff --git a/security/keys/gc.c b/security/keys/gc.c
index addf060..9cb4fe4 100644
--- a/security/keys/gc.c
+++ b/security/keys/gc.c
@@ -46,7 +46,7 @@
* immediately unlinked.
*/
struct key_type key_type_dead = {
- .name = "dead",
+ .name = ".dead",
};
/*
diff --git a/security/keys/keyctl.c b/security/keys/keyctl.c
index d580ad0..dbbfd77 100644
--- a/security/keys/keyctl.c
+++ b/security/keys/keyctl.c
@@ -271,7 +271,8 @@
* Create and join an anonymous session keyring or join a named session
* keyring, creating it if necessary. A named session keyring must have Search
* permission for it to be joined. Session keyrings without this permit will
- * be skipped over.
+ * be skipped over. It is not permitted for userspace to create or join
+ * keyrings whose name begin with a dot.
*
* If successful, the ID of the joined session keyring will be returned.
*/
@@ -288,12 +289,16 @@
ret = PTR_ERR(name);
goto error;
}
+
+ ret = -EPERM;
+ if (name[0] == '.')
+ goto error_name;
}
/* join the session */
ret = join_session_keyring(name);
+error_name:
kfree(name);
-
error:
return ret;
}
@@ -1251,8 +1256,8 @@
* Read or set the default keyring in which request_key() will cache keys and
* return the old setting.
*
- * If a process keyring is specified then this will be created if it doesn't
- * yet exist. The old setting will be returned if successful.
+ * If a thread or process keyring is specified then it will be created if it
+ * doesn't yet exist. The old setting will be returned if successful.
*/
long keyctl_set_reqkey_keyring(int reqkey_defl)
{
@@ -1277,11 +1282,8 @@
case KEY_REQKEY_DEFL_PROCESS_KEYRING:
ret = install_process_keyring_to_cred(new);
- if (ret < 0) {
- if (ret != -EEXIST)
- goto error;
- ret = 0;
- }
+ if (ret < 0)
+ goto error;
goto set;
case KEY_REQKEY_DEFL_DEFAULT:
diff --git a/security/keys/process_keys.c b/security/keys/process_keys.c
index 40a8852..45536c6 100644
--- a/security/keys/process_keys.c
+++ b/security/keys/process_keys.c
@@ -127,13 +127,18 @@
}
/*
- * Install a fresh thread keyring directly to new credentials. This keyring is
- * allowed to overrun the quota.
+ * Install a thread keyring to the given credentials struct if it didn't have
+ * one already. This is allowed to overrun the quota.
+ *
+ * Return: 0 if a thread keyring is now present; -errno on failure.
*/
int install_thread_keyring_to_cred(struct cred *new)
{
struct key *keyring;
+ if (new->thread_keyring)
+ return 0;
+
keyring = keyring_alloc("_tid", new->uid, new->gid, new,
KEY_POS_ALL | KEY_USR_VIEW,
KEY_ALLOC_QUOTA_OVERRUN,
@@ -146,7 +151,9 @@
}
/*
- * Install a fresh thread keyring, discarding the old one.
+ * Install a thread keyring to the current task if it didn't have one already.
+ *
+ * Return: 0 if a thread keyring is now present; -errno on failure.
*/
static int install_thread_keyring(void)
{
@@ -157,8 +164,6 @@
if (!new)
return -ENOMEM;
- BUG_ON(new->thread_keyring);
-
ret = install_thread_keyring_to_cred(new);
if (ret < 0) {
abort_creds(new);
@@ -169,17 +174,17 @@
}
/*
- * Install a process keyring directly to a credentials struct.
+ * Install a process keyring to the given credentials struct if it didn't have
+ * one already. This is allowed to overrun the quota.
*
- * Returns -EEXIST if there was already a process keyring, 0 if one installed,
- * and other value on any other error
+ * Return: 0 if a process keyring is now present; -errno on failure.
*/
int install_process_keyring_to_cred(struct cred *new)
{
struct key *keyring;
if (new->process_keyring)
- return -EEXIST;
+ return 0;
keyring = keyring_alloc("_pid", new->uid, new->gid, new,
KEY_POS_ALL | KEY_USR_VIEW,
@@ -193,11 +198,9 @@
}
/*
- * Make sure a process keyring is installed for the current process. The
- * existing process keyring is not replaced.
+ * Install a process keyring to the current task if it didn't have one already.
*
- * Returns 0 if there is a process keyring by the end of this function, some
- * error otherwise.
+ * Return: 0 if a process keyring is now present; -errno on failure.
*/
static int install_process_keyring(void)
{
@@ -211,14 +214,18 @@
ret = install_process_keyring_to_cred(new);
if (ret < 0) {
abort_creds(new);
- return ret != -EEXIST ? ret : 0;
+ return ret;
}
return commit_creds(new);
}
/*
- * Install a session keyring directly to a credentials struct.
+ * Install the given keyring as the session keyring of the given credentials
+ * struct, replacing the existing one if any. If the given keyring is NULL,
+ * then install a new anonymous session keyring.
+ *
+ * Return: 0 on success; -errno on failure.
*/
int install_session_keyring_to_cred(struct cred *cred, struct key *keyring)
{
@@ -253,8 +260,11 @@
}
/*
- * Install a session keyring, discarding the old one. If a keyring is not
- * supplied, an empty one is invented.
+ * Install the given keyring as the session keyring of the current task,
+ * replacing the existing one if any. If the given keyring is NULL, then
+ * install a new anonymous session keyring.
+ *
+ * Return: 0 on success; -errno on failure.
*/
static int install_session_keyring(struct key *keyring)
{
diff --git a/sound/soc/intel/Kconfig b/sound/soc/intel/Kconfig
index fd5d1e0..e18fe9d 100644
--- a/sound/soc/intel/Kconfig
+++ b/sound/soc/intel/Kconfig
@@ -33,11 +33,9 @@
select SND_SOC_INTEL_SST_MATCH if ACPI
depends on (X86 || COMPILE_TEST)
-# firmware stuff depends DW_DMAC_CORE; since there is no depends-on from
-# the reverse selection, each machine driver needs to select
-# SND_SOC_INTEL_SST_FIRMWARE carefully depending on DW_DMAC_CORE
config SND_SOC_INTEL_SST_FIRMWARE
tristate
+ select DW_DMAC_CORE
config SND_SOC_INTEL_SST_ACPI
tristate
@@ -47,16 +45,18 @@
config SND_SOC_INTEL_HASWELL
tristate
+ select SND_SOC_INTEL_SST
select SND_SOC_INTEL_SST_FIRMWARE
config SND_SOC_INTEL_BAYTRAIL
tristate
+ select SND_SOC_INTEL_SST
+ select SND_SOC_INTEL_SST_FIRMWARE
config SND_SOC_INTEL_HASWELL_MACH
tristate "ASoC Audio DSP support for Intel Haswell Lynxpoint"
depends on X86_INTEL_LPSS && I2C && I2C_DESIGNWARE_PLATFORM
- depends on DW_DMAC_CORE
- select SND_SOC_INTEL_SST
+ depends on DMADEVICES
select SND_SOC_INTEL_HASWELL
select SND_SOC_RT5640
help
@@ -99,9 +99,8 @@
config SND_SOC_INTEL_BYT_RT5640_MACH
tristate "ASoC Audio driver for Intel Baytrail with RT5640 codec"
depends on X86_INTEL_LPSS && I2C
- depends on DW_DMAC_CORE && (SND_SST_IPC_ACPI = n)
- select SND_SOC_INTEL_SST
- select SND_SOC_INTEL_SST_FIRMWARE
+ depends on DMADEVICES
+ depends on SND_SST_IPC_ACPI = n
select SND_SOC_INTEL_BAYTRAIL
select SND_SOC_RT5640
help
@@ -112,9 +111,8 @@
config SND_SOC_INTEL_BYT_MAX98090_MACH
tristate "ASoC Audio driver for Intel Baytrail with MAX98090 codec"
depends on X86_INTEL_LPSS && I2C
- depends on DW_DMAC_CORE && (SND_SST_IPC_ACPI = n)
- select SND_SOC_INTEL_SST
- select SND_SOC_INTEL_SST_FIRMWARE
+ depends on DMADEVICES
+ depends on SND_SST_IPC_ACPI = n
select SND_SOC_INTEL_BAYTRAIL
select SND_SOC_MAX98090
help
@@ -123,9 +121,8 @@
config SND_SOC_INTEL_BDW_RT5677_MACH
tristate "ASoC Audio driver for Intel Broadwell with RT5677 codec"
- depends on X86_INTEL_LPSS && GPIOLIB && I2C && DW_DMAC
- depends on DW_DMAC_CORE=y
- select SND_SOC_INTEL_SST
+ depends on X86_INTEL_LPSS && GPIOLIB && I2C
+ depends on DMADEVICES
select SND_SOC_INTEL_HASWELL
select SND_SOC_RT5677
help
@@ -134,10 +131,8 @@
config SND_SOC_INTEL_BROADWELL_MACH
tristate "ASoC Audio DSP support for Intel Broadwell Wildcatpoint"
- depends on X86_INTEL_LPSS && I2C && DW_DMAC && \
- I2C_DESIGNWARE_PLATFORM
- depends on DW_DMAC_CORE
- select SND_SOC_INTEL_SST
+ depends on X86_INTEL_LPSS && I2C && I2C_DESIGNWARE_PLATFORM
+ depends on DMADEVICES
select SND_SOC_INTEL_HASWELL
select SND_SOC_RT286
help
diff --git a/sound/soc/msm/msm8998.c b/sound/soc/msm/msm8998.c
index 51c27b7..b75ba98 100644
--- a/sound/soc/msm/msm8998.c
+++ b/sound/soc/msm/msm8998.c
@@ -5247,7 +5247,6 @@
.platform_name = "msm-pcm-hostless",
.dynamic = 1,
.dpcm_playback = 1,
- .dpcm_capture = 1,
.trigger = {SND_SOC_DPCM_TRIGGER_POST,
SND_SOC_DPCM_TRIGGER_POST},
.no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
diff --git a/sound/soc/msm/qdsp6v2/msm-pcm-voice-v2.c b/sound/soc/msm/qdsp6v2/msm-pcm-voice-v2.c
index 826f566..654806e 100644
--- a/sound/soc/msm/qdsp6v2/msm-pcm-voice-v2.c
+++ b/sound/soc/msm/qdsp6v2/msm-pcm-voice-v2.c
@@ -153,27 +153,27 @@
struct snd_pcm_runtime *runtime = substream->runtime;
struct msm_voice *voice;
- if (!strcmp("VoLTE", substream->pcm->id)) {
+ if (!strncmp("VoLTE", substream->pcm->id, 5)) {
voice = &voice_info[VOLTE_SESSION_INDEX];
pr_debug("%s: Open VoLTE Substream Id=%s\n",
__func__, substream->pcm->id);
- } else if (!strcmp("Voice2", substream->pcm->id)) {
+ } else if (!strncmp("Voice2", substream->pcm->id, 6)) {
voice = &voice_info[VOICE2_SESSION_INDEX];
pr_debug("%s: Open Voice2 Substream Id=%s\n",
__func__, substream->pcm->id);
- } else if (!strcmp("QCHAT", substream->pcm->id)) {
+ } else if (!strncmp("QCHAT", substream->pcm->id, 5)) {
voice = &voice_info[QCHAT_SESSION_INDEX];
pr_debug("%s: Open QCHAT Substream Id=%s\n",
__func__, substream->pcm->id);
- } else if (!strcmp("VoWLAN", substream->pcm->id)) {
+ } else if (!strncmp("VoWLAN", substream->pcm->id, 6)) {
voice = &voice_info[VOWLAN_SESSION_INDEX];
pr_debug("%s: Open VoWLAN Substream Id=%s\n",
__func__, substream->pcm->id);
- } else if (!strcmp("VoiceMMode1", substream->pcm->id)) {
+ } else if (!strncmp("VoiceMMode1", substream->pcm->id, 11)) {
voice = &voice_info[VOICEMMODE1_INDEX];
pr_debug("%s: Open VoiceMMode1 Substream Id=%s\n",
__func__, substream->pcm->id);
- } else if (!strcmp("VoiceMMode2", substream->pcm->id)) {
+ } else if (!strncmp("VoiceMMode2", substream->pcm->id, 11)) {
voice = &voice_info[VOICEMMODE2_INDEX];
pr_debug("%s: Open VoiceMMode2 Substream Id=%s\n",
__func__, substream->pcm->id);
diff --git a/sound/soc/msm/sdm660-ext-dai-links.c b/sound/soc/msm/sdm660-ext-dai-links.c
index f64074d..1c03d8c 100644
--- a/sound/soc/msm/sdm660-ext-dai-links.c
+++ b/sound/soc/msm/sdm660-ext-dai-links.c
@@ -335,7 +335,6 @@
.platform_name = "msm-pcm-hostless",
.dynamic = 1,
.dpcm_playback = 1,
- .dpcm_capture = 1,
.trigger = {SND_SOC_DPCM_TRIGGER_POST,
SND_SOC_DPCM_TRIGGER_POST},
.no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
diff --git a/sound/soc/msm/sdm845.c b/sound/soc/msm/sdm845.c
index 6987949..0f41387 100644
--- a/sound/soc/msm/sdm845.c
+++ b/sound/soc/msm/sdm845.c
@@ -397,7 +397,8 @@
"KHZ_88P2", "KHZ_96", "KHZ_176P4",
"KHZ_192", "KHZ_352P8", "KHZ_384"};
static char const *ext_disp_sample_rate_text[] = {"KHZ_48", "KHZ_96",
- "KHZ_192"};
+ "KHZ_192", "KHZ_32", "KHZ_44P1",
+ "KHZ_88P2", "KHZ_176P4" };
static char const *tdm_ch_text[] = {"One", "Two", "Three", "Four",
"Five", "Six", "Seven", "Eight"};
static char const *tdm_bit_format_text[] = {"S16_LE", "S24_LE", "S32_LE"};
@@ -508,6 +509,9 @@
.key_code[7] = 0,
.linein_th = 5000,
.moisture_en = true,
+ .mbhc_micbias = MIC_BIAS_2,
+ .anc_micbias = MIC_BIAS_2,
+ .enable_anc_mic_detect = false,
};
static struct snd_soc_dapm_route wcd_audio_paths[] = {
@@ -1464,6 +1468,22 @@
return idx;
switch (ext_disp_rx_cfg[idx].sample_rate) {
+ case SAMPLING_RATE_176P4KHZ:
+ sample_rate_val = 6;
+ break;
+
+ case SAMPLING_RATE_88P2KHZ:
+ sample_rate_val = 5;
+ break;
+
+ case SAMPLING_RATE_44P1KHZ:
+ sample_rate_val = 4;
+ break;
+
+ case SAMPLING_RATE_32KHZ:
+ sample_rate_val = 3;
+ break;
+
case SAMPLING_RATE_192KHZ:
sample_rate_val = 2;
break;
@@ -1494,6 +1514,18 @@
return idx;
switch (ucontrol->value.integer.value[0]) {
+ case 6:
+ ext_disp_rx_cfg[idx].sample_rate = SAMPLING_RATE_176P4KHZ;
+ break;
+ case 5:
+ ext_disp_rx_cfg[idx].sample_rate = SAMPLING_RATE_88P2KHZ;
+ break;
+ case 4:
+ ext_disp_rx_cfg[idx].sample_rate = SAMPLING_RATE_44P1KHZ;
+ break;
+ case 3:
+ ext_disp_rx_cfg[idx].sample_rate = SAMPLING_RATE_32KHZ;
+ break;
case 2:
ext_disp_rx_cfg[idx].sample_rate = SAMPLING_RATE_192KHZ;
break;
@@ -4655,6 +4687,42 @@
},
};
+static struct snd_soc_dai_link msm_common_misc_fe_dai_links[] = {
+ {
+ .name = MSM_DAILINK_NAME(ASM Loopback),
+ .stream_name = "MultiMedia6",
+ .cpu_dai_name = "MultiMedia6",
+ .platform_name = "msm-pcm-loopback",
+ .dynamic = 1,
+ .dpcm_playback = 1,
+ .dpcm_capture = 1,
+ .codec_dai_name = "snd-soc-dummy-dai",
+ .codec_name = "snd-soc-dummy",
+ .trigger = {SND_SOC_DPCM_TRIGGER_POST,
+ SND_SOC_DPCM_TRIGGER_POST},
+ .ignore_suspend = 1,
+ .no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
+ .ignore_pmdown_time = 1,
+ .id = MSM_FRONTEND_DAI_MULTIMEDIA6,
+ },
+ {
+ .name = "USB Audio Hostless",
+ .stream_name = "USB Audio Hostless",
+ .cpu_dai_name = "USBAUDIO_HOSTLESS",
+ .platform_name = "msm-pcm-hostless",
+ .dynamic = 1,
+ .dpcm_playback = 1,
+ .dpcm_capture = 1,
+ .trigger = {SND_SOC_DPCM_TRIGGER_POST,
+ SND_SOC_DPCM_TRIGGER_POST},
+ .no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
+ .ignore_suspend = 1,
+ .ignore_pmdown_time = 1,
+ .codec_dai_name = "snd-soc-dummy-dai",
+ .codec_name = "snd-soc-dummy",
+ },
+};
+
static struct snd_soc_dai_link msm_common_be_dai_links[] = {
/* Backend AFE DAI Links */
{
@@ -5373,6 +5441,7 @@
static struct snd_soc_dai_link msm_tavil_snd_card_dai_links[
ARRAY_SIZE(msm_common_dai_links) +
ARRAY_SIZE(msm_tavil_fe_dai_links) +
+ ARRAY_SIZE(msm_common_misc_fe_dai_links) +
ARRAY_SIZE(msm_common_be_dai_links) +
ARRAY_SIZE(msm_tavil_be_dai_links) +
ARRAY_SIZE(msm_wcn_be_dai_links) +
@@ -5662,7 +5731,7 @@
{
struct snd_soc_card *card = NULL;
struct snd_soc_dai_link *dailink;
- int len_1, len_2, len_3;
+ int len_1, len_2, len_3, len_4;
int total_links;
const struct of_device_id *match;
@@ -5677,8 +5746,9 @@
card = &snd_soc_card_tavil_msm;
len_1 = ARRAY_SIZE(msm_common_dai_links);
len_2 = len_1 + ARRAY_SIZE(msm_tavil_fe_dai_links);
- len_3 = len_2 + ARRAY_SIZE(msm_common_be_dai_links);
- total_links = len_3 + ARRAY_SIZE(msm_tavil_be_dai_links);
+ len_3 = len_2 + ARRAY_SIZE(msm_common_misc_fe_dai_links);
+ len_4 = len_3 + ARRAY_SIZE(msm_common_be_dai_links);
+ total_links = len_4 + ARRAY_SIZE(msm_tavil_be_dai_links);
memcpy(msm_tavil_snd_card_dai_links,
msm_common_dai_links,
sizeof(msm_common_dai_links));
@@ -5686,9 +5756,12 @@
msm_tavil_fe_dai_links,
sizeof(msm_tavil_fe_dai_links));
memcpy(msm_tavil_snd_card_dai_links + len_2,
+ msm_common_misc_fe_dai_links,
+ sizeof(msm_common_misc_fe_dai_links));
+ memcpy(msm_tavil_snd_card_dai_links + len_3,
msm_common_be_dai_links,
sizeof(msm_common_be_dai_links));
- memcpy(msm_tavil_snd_card_dai_links + len_3,
+ memcpy(msm_tavil_snd_card_dai_links + len_4,
msm_tavil_be_dai_links,
sizeof(msm_tavil_be_dai_links));
@@ -6186,14 +6259,19 @@
pdev->dev.of_node->full_name);
dev_dbg(&pdev->dev, "Jack type properties set to default");
} else {
- if (!strcmp(mbhc_audio_jack_type, "4-pole-jack"))
+ if (!strcmp(mbhc_audio_jack_type, "4-pole-jack")) {
+ wcd_mbhc_cfg.enable_anc_mic_detect = false;
dev_dbg(&pdev->dev, "This hardware has 4 pole jack");
- else if (!strcmp(mbhc_audio_jack_type, "5-pole-jack"))
+ } else if (!strcmp(mbhc_audio_jack_type, "5-pole-jack")) {
+ wcd_mbhc_cfg.enable_anc_mic_detect = true;
dev_dbg(&pdev->dev, "This hardware has 5 pole jack");
- else if (!strcmp(mbhc_audio_jack_type, "6-pole-jack"))
+ } else if (!strcmp(mbhc_audio_jack_type, "6-pole-jack")) {
+ wcd_mbhc_cfg.enable_anc_mic_detect = true;
dev_dbg(&pdev->dev, "This hardware has 6 pole jack");
- else
+ } else {
+ wcd_mbhc_cfg.enable_anc_mic_detect = false;
dev_dbg(&pdev->dev, "Unknown value, set to default");
+ }
}
/*
* Parse US-Euro gpio info from DT. Report no error if us-euro