Merge "ARM: dts: msm: Add HDR support for dsi 4K panels"
diff --git a/Documentation/devicetree/bindings/arm/msm/qcom,osm.txt b/Documentation/devicetree/bindings/arm/msm/qcom,osm.txt
index 7496f4d..64154590 100644
--- a/Documentation/devicetree/bindings/arm/msm/qcom,osm.txt
+++ b/Documentation/devicetree/bindings/arm/msm/qcom,osm.txt
@@ -21,27 +21,27 @@
Usage: required
Value type: <stringlist>
Definition: Address names. Must be "osm_l3_base", "osm_pwrcl_base",
- "osm_perfcl_base", and "cpr_rc".
+ "osm_perfcl_base".
Must be specified in the same order as the corresponding
addresses are specified in the reg property.
-- vdd_l3_mx_ao-supply
- Usage: required
- Value type: <phandle>
- Definition: Phandle to the MX active-only regulator device.
-
-- vdd_pwrcl_mx_ao-supply
- Usage: required
- Value type: <phandle>
- Definition: Phandle to the MX active-only regulator device.
-
- qcom,mx-turbo-freq
- Usage: required
+ Usage: optional
Value type: <array>
Definition: List of frequencies for the 3 clock domains (following the
order of L3, power, and performance clusters) that denote
the lowest rate that requires a TURBO vote on the MX rail.
+- vdd_l3_mx_ao-supply
+ Usage: required if qcom,mx-turbo-freq is specified
+ Value type: <phandle>
+ Definition: Phandle to the MX active-only regulator device.
+
+- vdd_pwrcl_mx_ao-supply
+ Usage: required if qcom,mx-turbo-freq is specified
+ Value type: <phandle>
+ Definition: Phandle to the MX active-only regulator device.
+
- l3-devs
Usage: optional
Value type: <phandle>
@@ -63,10 +63,8 @@
compatible = "qcom,clk-cpu-osm";
reg = <0x17d41000 0x1400>,
<0x17d43000 0x1400>,
- <0x17d45800 0x1400>,
- <0x784248 0x4>;
- reg-names = "osm_l3_base", "osm_pwrcl_base", "osm_perfcl_base",
- "cpr_rc";
+ <0x17d45800 0x1400>;
+ reg-names = "osm_l3_base", "osm_pwrcl_base", "osm_perfcl_base";
vdd_l3_mx_ao-supply = <&pm8998_s6_level_ao>;
vdd_pwrcl_mx_ao-supply = <&pm8998_s6_level_ao>;
diff --git a/Documentation/devicetree/bindings/firmware/qcom,scm.txt b/Documentation/devicetree/bindings/firmware/qcom,scm.txt
index 3b4436e..bdba526 100644
--- a/Documentation/devicetree/bindings/firmware/qcom,scm.txt
+++ b/Documentation/devicetree/bindings/firmware/qcom,scm.txt
@@ -11,6 +11,8 @@
* "qcom,scm-msm8660" for MSM8660 platforms
* "qcom,scm-msm8690" for MSM8690 platforms
* "qcom,scm" for later processors (MSM8916, APQ8084, MSM8974, etc)
+ * "android,firmware" for firmware image
+ * "android,vbmeta" for setting system properties for verified boot.
- clocks: One to three clocks may be required based on compatible.
* Only core clock required for "qcom,scm-apq8064", "qcom,scm-msm8660", and "qcom,scm-msm8960"
* Core, iface, and bus clocks required for "qcom,scm"
@@ -26,3 +28,26 @@
clock-names = "core", "bus", "iface";
};
};
+
+Example for SDM845:
+
+ firmware {
+ android {
+ compatible = "android,firmware";
+ vbmeta {
+ compatible = "android,vbmeta";
+ parts = "vbmeta,boot,system,vendor,dtbo";
+ };
+
+ fstab {
+ compatible = "android,fstab";
+ vendor {
+ compatible = "android,vendor";
+ dev = "/dev/block/platform/soc/1d84000.ufshc/by-name/vendor";
+ type = "ext4";
+ mnt_flags = "ro,barrier=1,discard";
+ fsmgr_flags = "wait,slotselect,avb";
+ };
+ };
+ };
+ };
diff --git a/Documentation/devicetree/bindings/regulator/rpm-smd-regulator.txt b/Documentation/devicetree/bindings/regulator/rpm-smd-regulator.txt
new file mode 100644
index 0000000..9f40a09
--- /dev/null
+++ b/Documentation/devicetree/bindings/regulator/rpm-smd-regulator.txt
@@ -0,0 +1,328 @@
+Qualcomm Technologies, Inc. RPM Regulators
+
+rpm-regulator-smd is a regulator driver which supports regulators inside of
+PMICs which are controlled by the RPM processor. Communication with the RPM
+processor takes place over SMD.
+
+Required structure:
+- RPM regulators must be described in two levels of devices nodes. The first
+ level describes the interface with the RPM. The second level describes
+ properties of one regulator framework interface (of potentially many) to
+ the regulator.
+
+[First Level Nodes]
+
+Required properties:
+- compatible: Must be "qcom,rpm-smd-regulator-resource"
+- qcom,resource-name: Resource name string for this regulator to be used in RPM
+ transactions. Length is 4 characters max.
+- qcom,resource-id: Resource instance ID for this regulator to be used in RPM
+ transactions.
+- qcom,regulator-type: Type of this regulator. Supported values are:
+ 0 = LDO
+ 1 = SMPS
+ 2 = VS
+ 3 = NCP
+ 4 = Buck or Boost (BoB)
+
+Optional properties:
+- qcom,allow-atomic: Flag specifying if atomic access is allowed for this
+ regulator. Supported values are:
+ 0 or not present = mutex locks used
+ 1 = spinlocks used
+- qcom,enable-time: Time in us to delay after enabling the regulator
+- qcom,hpm-min-load: Load current in uA which corresponds to the minimum load
+ which requires the regulator to be in high power mode.
+- qcom,apps-only: Flag which indicates that the regulator only has
+ consumers on the application processor. If this flag
+ is specified, then voltage and current updates are
+ only sent to the RPM if the regulator is enabled.
+- qcom,always-wait-for-ack: Flag which indicates that the application
+ processor must wait for an ACK or a NACK from the RPM
+ for every request sent for this regulator including
+ those which are for a strictly lower power state.
+
+[Second Level Nodes]
+
+Required properties:
+- compatible: Must be "qcom,rpm-smd-regulator"
+- regulator-name: A string used as a descriptive name for regulator outputs
+- qcom,set: Specifies which sets that requests made with this
+ regulator interface should be sent to. Regulator
+ requests sent in the active set take effect immediately.
+ Requests sent in the sleep set take effect when the Apps
+ processor transitions into RPM assisted power collapse.
+ Supported values are:
+ 1 = Active set only
+ 2 = Sleep set only
+ 3 = Both active and sleep sets
+
+
+
+Optional properties:
+- parent-supply: phandle to the parent supply/regulator node
+- qcom,system-load: Load in uA present on regulator that is not
+ captured by any consumer request
+- qcom,use-voltage-corner: Flag that signifies if regulator_set_voltage
+ calls should modify the corner parameter instead
+ of the voltage parameter. When used, voltages
+ specified inside of the regulator framework
+ represent corners that have been incremented by
+ 1. This value shift is necessary to work around
+ limitations in the regulator framework which
+ treat 0 uV as an error.
+- qcom,use-voltage-floor-corner: Flag that signifies if regulator_set_voltage
+ calls should modify the floor corner parameter
+ instead of the voltage parameter. When used,
+ voltages specified inside of the regulator
+ framework represent corners that have been
+ incremented by 1. The properties
+ qcom,use-voltage-corner and
+ qcom,use-voltage-floor-corner are mutually
+ exclusive. Only one may be specified for a
+ given regulator.
+- qcom,use-voltage-level: Flag that signifies if regulator_set_voltage
+ calls should modify the level parameter instead
+ of the voltage parameter.
+- qcom,use-voltage-floor-level: Flag that signifies if regulator_set_voltage
+ calls should modify the floor level parameter
+ instead of the voltage parameter.
+ The properties qcom,use-voltage-level and
+ qcom,use-voltage-floor-level are mutually
+ exclusive. Only one may be specified for a
+ given regulator.
+- qcom,use-pin-ctrl-voltage1: Flag which indicates that updates to voltage
+ should be sent to the pin control voltage 1
+ parameter. Only one pin may be specified per
+ regulator. This property only applies to BoB
+ type regulators.
+- qcom,use-pin-ctrl-voltage2: Flag which indicates that updates to voltage
+ should be sent to the pin control voltage 2
+ parameter. Only one pin may be specified per
+ regulator. This property only applies to BoB
+ type regulators.
+- qcom,use-pin-ctrl-voltage3: Flag which indicates that updates to voltage
+ should be sent to the pin control voltage 3
+ parameter. Only one pin may be specified per
+ regulator. This property only applies to BoB
+ type regulators.
+- qcom,always-send-voltage: Flag which indicates that updates to the
+ voltage, voltage corner or voltage level set
+ point should always be sent immediately to the
+ RPM. If this flag is not specified, then
+ voltage set point updates are only sent if the
+ given regulator has also been enabled by a
+ Linux consumer.
+- qcom,always-send-current: Flag which indicates that updates to the load
+ current should always be sent immediately to the
+ RPM. If this flag is not specified, then load
+ current updates are only sent if the given
+ regulator has also been enabled by a Linux
+ consumer.
+- qcom,send-defaults: Boolean flag which indicates that the initial
+ parameter values should be sent to the RPM
+ before consumers make their own requests. If
+ this flag is not specified, then initial
+ parameters values will only be sent after some
+ consumer makes a request.
+- qcom,enable-with-pin-ctrl: Double in which the first element corresponds to
+ the pin control enable parameter value to send
+ when all consumers have requested the regulator
+ to be disabled. The second element corresponds
+ to the pin control enable parameter value to
+ send when any consumer has requested the
+ regulator to be enabled. Each element supports
+ the same set of values as the
+ qcom,init-pin-ctrl-enable property listed below.
+
+The following properties specify initial values for parameters to be sent to the
+RPM in regulator requests.
+- qcom,init-enable: 0 = regulator disabled
+ 1 = regulator enabled
+- qcom,init-voltage: Voltage in uV
+- qcom,init-current: Current in mA
+- qcom,init-ldo-mode: Operating mode to be used with LDO regulators
+ Supported values are:
+ 0 = mode determined by current requests
+ 1 = force HPM (NPM)
+- qcom,init-smps-mode: Operating mode to be used with SMPS regulators
+ Supported values are:
+ 0 = auto; hardware determines mode
+ 1 = mode determined by current requests
+ 2 = force HPM (PWM)
+- qcom,init-bob-mode: Operating mode to be used with BoB regulators
+ Supported values are:
+ 0 = pass; use priority order
+ 1 = force PFM
+ 2 = auto; hardware determines mode
+ 3 = force PWM
+- qcom,init-pin-ctrl-enable: Bit mask specifying which hardware pins should be
+ used to enable the regulator, if any; supported
+ bits are:
+ 0 = ignore all hardware enable signals
+ BIT(0) = follow HW0_EN signal
+ BIT(1) = follow HW1_EN signal
+ BIT(2) = follow HW2_EN signal
+ BIT(3) = follow HW3_EN signal
+- qcom,init-pin-ctrl-mode: Bit mask specifying which hardware pins should be
+ used to force the regulator into high power
+ mode, if any. Supported bits are:
+ 0 = ignore all hardware enable signals
+ BIT(0) = follow HW0_EN signal
+ BIT(1) = follow HW1_EN signal
+ BIT(2) = follow HW2_EN signal
+ BIT(3) = follow HW3_EN signal
+ BIT(4) = follow PMIC awake state
+- qcom,init-pin-ctrl-voltage1: Minimum voltage in micro-volts to use while pin
+ control 1 is enabled. This property only
+ applies to BoB type regulators.
+- qcom,init-pin-ctrl-voltage2: Minimum voltage in micro-volts to use while pin
+ control 2 is enabled. This property only
+ applies to BoB type regulators.
+- qcom,init-pin-ctrl-voltage3: Minimum voltage in micro-volts to use while pin
+ control 3 is enabled. This property only
+ applies to BoB type regulators.
+- qcom,init-frequency: Switching frequency divisor for SMPS regulators.
+ Supported values are n = 0 to 31 where
+ freq = 19.2 MHz / (n + 1).
+- qcom,init-head-room: Voltage head room in mV required for the
+ regulator. This head room value should be used
+ in situations where the device connected to the
+ output of the regulator has low noise tolerance.
+ Note that the RPM independently enforces a
+ safety head room value for subregulated LDOs
+ which is sufficient to account for LDO drop-out
+ voltage.
+- qcom,init-quiet-mode: Specify that quiet mode is needed for an SMPS
+ regulator in order to have lower output noise.
+ Supported values are:
+ 0 = No quiet mode
+ 1 = Quiet mode
+ 2 = Super quiet mode
+- qcom,init-freq-reason: Consumer requiring specified frequency for an
+ SMPS regulator. Supported values are:
+ 0 = None
+ 1 = Bluetooth
+ 2 = GPS
+ 4 = WLAN
+ 8 = WAN
+- qcom,init-voltage-corner: Performance corner to use in order to determine
+ voltage set point. This value corresponds to
+ the actual value that will be sent and is not
+ incremented by 1 like the values used inside of
+ the regulator framework. The meaning of corner
+ values is set by the RPM. It is possible that
+ different regulators on a given platform or
+ similar regulators on different platforms will
+ utilize different corner values. These are
+ corner values supported on MSM8974 for PMIC
+ PM8841 SMPS 2 (VDD_Dig); nominal voltages for
+ these corners are also shown:
+ 0 = None (don't care)
+ 1 = Retention (0.5000 V)
+ 2 = SVS Krait (0.7250 V)
+ 3 = SVS SOC (0.8125 V)
+ 4 = Normal (0.9000 V)
+ 5 = Turbo (0.9875 V)
+ 6 = Super Turbo (1.0500 V)
+- qcom,init-disallow-bypass: Specify that bypass mode should not be used for a
+ given LDO regulator. When in bypass mode, an
+ LDO performs no regulation and acts as a simple
+ switch. The RPM can utilize this mode for an
+ LDO that is subregulated from an SMPS when it is
+ possible to reduce the SMPS voltage to the
+ desired LDO output level. Bypass mode may be
+ disallowed if lower LDO output noise is
+ required. Supported values are:
+ 0 = Allow RPM to utilize LDO bypass mode
+ if possible
+ 1 = Disallow LDO bypass mode
+- qcom,init-voltage-floor-corner: Minimum performance corner to use if any
+ processor in the system is awake. This property
+ supports the same values as
+ qcom,init-voltage-corner.
+- qcom,init-voltage-level: Performance level to use in order to determine
+ voltage set point. The meaning of level
+ values is set by the RPM. It is possible that
+ different regulators on a given platform or
+ similar regulators on different platforms will
+ utilize different level values. These are
+ level values supported on MSM8952 for PMIC
+ PM8952 SMPS 2 (VDD_Dig); nominal voltages for
+ these level are also shown:
+ 16 = Retention (0.5000 V)
+ 128 = SVS (1.0500 V)
+ 192 = SVS+ (1.1550 V)
+ 256 = Normal (1.2250 V)
+ 320 = Normal+ (1.2875 V)
+ 384 = Turbo (1.3500 V)
+- qcom,init-voltage-floor-level: Minimum performance level to use if any
+ processor in the system is awake. This property
+ supports the same values as
+ qcom,init-voltage-level.
+
+All properties specified within the core regulator framework can also be used in
+second level nodes. These bindings can be found in:
+Documentation/devicetree/bindings/regulator/regulator.txt.
+
+Examples:
+
+rpm-regulator-smpb1 {
+ qcom,resource-name = "smpb";
+ qcom,resource-id = <1>;
+ qcom,regulator-type = <1>;
+ qcom,hpm-min-load = <100000>;
+ compatible = "qcom,rpm-smd-regulator-resource";
+ status = "disabled";
+
+ pm8841_s1: regulator-s1 {
+ regulator-name = "8841_s1";
+ qcom,set = <3>;
+ regulator-min-microvolt = <900000>;
+ regulator-max-microvolt = <1150000>;
+ qcom,init-voltage = <1150000>;
+ compatible = "qcom,rpm-smd-regulator";
+ };
+ pm8841_s1_ao: regulator-s1-ao {
+ regulator-name = "8841_s1_ao";
+ qcom,set = <1>;
+ regulator-min-microvolt = <900000>;
+ regulator-max-microvolt = <1150000>;
+ compatible = "qcom,rpm-smd-regulator";
+ };
+ pm8841_s1_corner: regulator-s1-corner {
+ regulator-name = "8841_s1_corner";
+ qcom,set = <3>;
+ regulator-min-microvolt = <1>;
+ regulator-max-microvolt = <6>;
+ qcom,init-voltage-corner = <3>;
+ qcom,use-voltage-corner;
+ compatible = "qcom,rpm-smd-regulator";
+ };
+};
+
+rpm-regulator-ldoa2 {
+ qcom,resource-name = "ldoa";
+ qcom,resource-id = <2>;
+ qcom,regulator-type = <0>;
+ qcom,hpm-min-load = <10000>;
+ compatible = "qcom,rpm-smd-regulator-resource";
+
+ regulator-l2 {
+ compatible = "qcom,rpm-smd-regulator";
+ regulator-name = "8941_l2";
+ qcom,set = <3>;
+ regulator-min-microvolt = <1225000>;
+ regulator-max-microvolt = <1225000>;
+ qcom,init-voltage = <1225000>;
+ };
+ regulator-l2-pin-ctrl {
+ compatible = "qcom,rpm-smd-regulator";
+ regulator-name = "8941_l2_pin_ctrl";
+ qcom,set = <3>;
+ regulator-min-microvolt = <1225000>;
+ regulator-max-microvolt = <1225000>;
+ qcom,init-voltage = <1225000>;
+ qcom,enable-with-pin-ctrl = <0 1>;
+ };
+};
diff --git a/Documentation/devicetree/bindings/regulator/spm-regulator.txt b/Documentation/devicetree/bindings/regulator/spm-regulator.txt
new file mode 100644
index 0000000..c324157
--- /dev/null
+++ b/Documentation/devicetree/bindings/regulator/spm-regulator.txt
@@ -0,0 +1,61 @@
+Qualcomm Technologies Inc. SPM Regulators
+
+spm-regulator is a regulator device which supports PMIC processor supply
+regulators via the SPM module.
+
+Required properties:
+- compatible: Must be "qcom,spm-regulator"
+- reg: Specifies the SPMI address and size for this regulator device
+- regulator-name: A string used as a descriptive name for the regulator
+
+Required structure:
+- A qcom,spm-regulator node must be a child of an SPMI node that has specified
+ the spmi-slave-container property
+
+Optional properties:
+- qcom,mode: A string which specifies the mode to use for the regulator.
+ Supported values are "pwm" and "auto". PWM mode is more
+ robust, but draws more current than auto mode. If this
+ property is not specified, then the regulator will remain
+ in whatever mode hardware or bootloaders set it to.
+- qcom,cpu-num: Specifies which CPU this regulator powers. This property is
+ not need when the SPM regulator is shared between all CPUs.
+- qcom,bypass-spm: Boolean flag which indicates that voltage control should not
+ be managed by an SPM. Instead, the voltage should be
+ controlled via SPMI.
+- qcom,max-voltage-step: Maximum single voltage step size in microvolts.
+- qcom,recal-mask: Bit mask of the APSS clusters to recalibrate after each
+ voltage change. Bit 0 corresponds to the first cluster,
+ bit 1 corresponds to the second cluster, and so on.
+
+Optional structure:
+- A child node may be specified within a qcom,spm-regulator node which defines
+ an additional regulator which controls the AVS minimum and maximum
+ voltage limits.
+- The AVS child node must contain these properties defined in regulator.txt:
+ regulator-name, regulator-min-microvolt, regulator-max-microvolt.
+
+All properties specified within the core regulator framework can also be used.
+These bindings can be found in regulator.txt.
+
+Example:
+ qcom,spmi@fc4c0000 {
+
+ qcom,pm8226@1 {
+ spmi-slave-container;
+
+ spm-regulator@1700 {
+ compatible = "qcom,spm-regulator";
+ regulator-name = "8226_s2";
+ reg = <0x1700 0x100>;
+ regulator-min-microvolt = <900000>;
+ regulator-max-microvolt = <1275000>;
+
+ avs-limit-regulator {
+ regulator-name = "8226_s2_avs_limit";
+ regulator-min-microvolt = <900000>;
+ regulator-max-microvolt = <1275000>;
+ }
+ };
+ };
+ };
diff --git a/Documentation/devicetree/bindings/usb/msm-phy.txt b/Documentation/devicetree/bindings/usb/msm-phy.txt
index 9ee2cc6..f8c8a69 100644
--- a/Documentation/devicetree/bindings/usb/msm-phy.txt
+++ b/Documentation/devicetree/bindings/usb/msm-phy.txt
@@ -38,7 +38,8 @@
Required properties:
- compatible: Should be "qcom,usb-ssphy-qmp", "qcom,usb-ssphy-qmp-v1" or
- "qcom,usb-ssphy-qmp-v2" or "qcom,usb-ssphy-qmp-dp-combo"
+ "qcom,usb-ssphy-qmp-v2" or "qcom,usb-ssphy-qmp-usb3-or-dp" or
+ "qcom,usb-ssphy-qmp-dp-combo"
- reg: Address and length of the register set for the device
Required regs are:
"qmp_phy_base" : QMP PHY Base register set.
@@ -159,6 +160,9 @@
"efuse_addr": EFUSE address to read and update analog tune parameter.
"emu_phy_base" : phy base address used for programming emulation target phy.
"ref_clk_addr" : ref_clk bcr address used for on/off ref_clk before reset.
+ "tcsr_clamp_dig_n" : To enable/disable digital clamp to the phy. When
+ de-asserted, it will prevent random leakage from qusb2 phy resulting from
+ out of sequence turn on/off of 1p8, 3p3 and DVDD regulators.
"refgen_north_bg_reg" : address used to read REFGEN status for overriding QUSB PHY register.
- clocks: a list of phandles to the PHY clocks. Use as per
Documentation/devicetree/bindings/clock/clock-bindings.txt
@@ -176,6 +180,10 @@
- qcom,hold-reset: Indicates that hold QUSB PHY into reset state.
- qcom,phy-clk-scheme: Should be one of "cml" or "cmos" if ref_clk_addr is provided.
- qcom,major-rev: provide major revision number to differentiate power up sequence. default is 2.0
+ - pinctrl-names/pinctrl-0/1: The GPIOs configured as output function. Names represents "active"
+ state when attached in host mode and "suspend" state when detached.
+ - qcom,tune2-efuse-correction: The value to be adjusted from fused value for
+ improved rise/fall times.
Example:
qusb_phy: qusb@f9b39000 {
diff --git a/Documentation/devicetree/bindings/vendor-prefixes.txt b/Documentation/devicetree/bindings/vendor-prefixes.txt
index a491bd7..a37e441 100644
--- a/Documentation/devicetree/bindings/vendor-prefixes.txt
+++ b/Documentation/devicetree/bindings/vendor-prefixes.txt
@@ -24,6 +24,7 @@
ams AMS AG
amstaos AMS-Taos Inc.
analogix Analogix Semiconductor, Inc.
+android Google
apm Applied Micro Circuits Corporation (APM)
aptina Aptina Imaging
arasan Arasan Chip Systems
diff --git a/arch/Kconfig b/arch/Kconfig
index babac73..a364ece 100644
--- a/arch/Kconfig
+++ b/arch/Kconfig
@@ -224,6 +224,14 @@
An architecture should select this when it can successfully
build and run with CONFIG_FORTIFY_SOURCE.
+config FORTIFY_COMPILE_CHECK
+ depends on ARCH_HAS_FORTIFY_SOURCE
+ bool
+ help
+ Disable compile time size check for string routines as part
+ of fortify source. Selecting this option will not enforce compile
+ time size check for string functions.
+
# Select if arch init_task initializer is different to init/init_task.c
config ARCH_INIT_TASK
bool
diff --git a/arch/arm/boot/dts/qcom/sdxpoorwills-bus.dtsi b/arch/arm/boot/dts/qcom/sdxpoorwills-bus.dtsi
index d1d44ec..e6dc45a 100644
--- a/arch/arm/boot/dts/qcom/sdxpoorwills-bus.dtsi
+++ b/arch/arm/boot/dts/qcom/sdxpoorwills-bus.dtsi
@@ -23,6 +23,9 @@
reg-names = "mc_virt-base", "mem_noc-base",
"system_noc-base", "ipa_virt-base";
+ mbox-names = "apps_rsc";
+ mboxes = <&apps_rsc 0>;
+
/*RSCs*/
rsc_apps: rsc-apps {
cell-id = <MSM_BUS_RSC_APPS>;
@@ -59,7 +62,7 @@
bcm_ip0: bcm-ip0 {
cell-id = <MSM_BUS_BCM_IP0>;
label = "IP0";
- qcom,bcm-name = "CE";
+ qcom,bcm-name = "IP0";
qcom,rscs = <&rsc_apps>;
qcom,bcm-dev;
};
@@ -240,8 +243,8 @@
label = "fab-system_noc";
qcom,fab-dev;
qcom,base-name = "system_noc-base";
- qcom,qos-off = <0>;
- qcom,base-offset = <0>;
+ qcom,qos-off = <4096>;
+ qcom,base-offset = <45056>;
qcom,bypass-qos-prg;
qcom,bus-type = <1>;
clocks = <>;
@@ -261,7 +264,7 @@
mas_llcc_mc: mas-llcc-mc {
cell-id = <MSM_BUS_MASTER_LLCC>;
label = "mas-llcc-mc";
- qcom,buswidth = <16>;
+ qcom,buswidth = <4>;
qcom,agg-ports = <1>;
qcom,connections = <&slv_ebi>;
qcom,bus-dev = <&fab_mc_virt>;
@@ -277,7 +280,7 @@
qcom,bus-dev = <&fab_mem_noc>;
qcom,bcms = <&bcm_sh1>;
qcom,ap-owned;
- qcom,prio = <0>;
+ qcom,prio = <6>;
};
mas_qnm_snoc_gc: mas-qnm-snoc-gc {
@@ -290,6 +293,7 @@
qcom,bus-dev = <&fab_mem_noc>;
qcom,ap-owned;
qcom,prio = <0>;
+ qcom,forwarding;
};
mas_xm_apps_rdwr: mas-xm-apps-rdwr {
@@ -310,9 +314,12 @@
label = "mas-qhm-audio";
qcom,buswidth = <4>;
qcom,agg-ports = <1>;
+ qcom,qport = <9>;
qcom,connections = <&slv_qns_aggre_noc>;
qcom,bus-dev = <&fab_system_noc>;
qcom,bcms = <&bcm_pn2>;
+ qcom,ap-owned;
+ qcom,prio = <1>;
};
mas_qhm_blsp1: mas-qhm-blsp1 {
@@ -320,9 +327,12 @@
label = "mas-qhm-blsp1";
qcom,buswidth = <4>;
qcom,agg-ports = <1>;
+ qcom,qport = <10>;
qcom,connections = <&slv_qns_aggre_noc>;
qcom,bus-dev = <&fab_system_noc>;
qcom,bcms = <&bcm_pn3>;
+ qcom,ap-owned;
+ qcom,prio = <1>;
};
mas_qhm_qdss_bam: mas-qhm-qdss-bam {
@@ -330,20 +340,22 @@
label = "mas-qhm-qdss-bam";
qcom,buswidth = <4>;
qcom,agg-ports = <1>;
+ qcom,qport = <11>;
qcom,connections = <&slv_qhs_crypto_cfg
- &slv_qhs_snoc_cfg &slv_qhs_emac_cfg
- &slv_qhs_aoss &slv_qhs_spmi_fetcher
- &slv_qhs_pdm &slv_qns_snoc_memnoc
- &slv_qhs_tcsr &slv_qhs_qpic
- &slv_qxs_imem &slv_qhs_ipa
- &slv_qhs_usb3_phy &slv_qhs_aop
- &slv_qhs_blsp1 &slv_qhs_sdc1
- &slv_qhs_pcie_parf &slv_qhs_audio
- &slv_qhs_tlmm &slv_qhs_prng
- &slv_xs_sys_tcu_cfg &slv_qhs_clk_ctl
- &slv_qhs_usb3>;
+ &slv_qhs_pdm &slv_qhs_pcie_parf
+ &slv_qhs_tlmm &slv_qhs_spmi_fetcher
+ &slv_qhs_prng &slv_qhs_qpic
+ &slv_qxs_imem &slv_qhs_snoc_cfg
+ &slv_qhs_audio &slv_qhs_sdc1
+ &slv_qhs_aoss &slv_qhs_ipa
+ &slv_qns_snoc_memnoc &slv_qhs_usb3_phy
+ &slv_qhs_aop &slv_qhs_tcsr
+ &slv_qhs_blsp1 &slv_xs_sys_tcu_cfg
+ &slv_qhs_usb3 &slv_qhs_clk_ctl>;
qcom,bus-dev = <&fab_system_noc>;
qcom,bcms = <&bcm_sn8>;
+ qcom,ap-owned;
+ qcom,prio = <1>;
};
mas_qhm_qpic: mas-qhm-qpic {
@@ -351,7 +363,7 @@
label = "mas-qhm-qpic";
qcom,buswidth = <4>;
qcom,agg-ports = <1>;
- qcom,connections = <&slv_qhs_aoss &slv_qns_aggre_noc>;
+ qcom,connections = <&slv_qns_aggre_noc>;
qcom,bus-dev = <&fab_system_noc>;
qcom,bcms = <&bcm_pn3>;
};
@@ -381,18 +393,17 @@
qcom,buswidth = <8>;
qcom,agg-ports = <1>;
qcom,connections = <&slv_qhs_crypto_cfg
- &slv_qhs_snoc_cfg &slv_qhs_emac_cfg
+ &slv_qhs_snoc_cfg &slv_qhs_sdc1
&slv_qhs_aoss &slv_qhs_spmi_fetcher
&slv_qhs_pdm &slv_qns_snoc_memnoc
&slv_qhs_tcsr &slv_xs_qdss_stm
&slv_qhs_qpic &slv_qxs_imem
&slv_qhs_ipa &slv_qhs_usb3_phy
&slv_qhs_aop &slv_qhs_blsp1
- &slv_qhs_sdc1 &slv_qhs_pcie_parf
- &slv_qhs_audio &slv_qxs_pcie
- &slv_qhs_tlmm &slv_qhs_prng
- &slv_xs_sys_tcu_cfg &slv_qhs_clk_ctl
- &slv_qhs_usb3>;
+ &slv_qhs_pcie_parf &slv_qhs_audio
+ &slv_qxs_pcie &slv_qhs_tlmm
+ &slv_qhs_prng &slv_xs_sys_tcu_cfg
+ &slv_qhs_clk_ctl &slv_qhs_usb3>;
qcom,bus-dev = <&fab_system_noc>;
qcom,bcms = <&bcm_sn7>;
};
@@ -403,17 +414,17 @@
qcom,buswidth = <8>;
qcom,agg-ports = <1>;
qcom,connections = <&slv_qhs_crypto_cfg
- &slv_qhs_snoc_cfg &slv_qhs_emac_cfg
+ &slv_qhs_snoc_cfg &slv_qhs_sdc1
&slv_qhs_aoss &slv_qhs_spmi_fetcher
&slv_qhs_pdm &slv_qns_snoc_memnoc
&slv_qhs_tcsr &slv_xs_qdss_stm
&slv_qhs_qpic &slv_qxs_imem
&slv_qhs_ipa &slv_qhs_usb3_phy
&slv_qhs_aop &slv_qhs_blsp1
- &slv_qhs_sdc1 &slv_qhs_pcie_parf
- &slv_qhs_audio &slv_qhs_tlmm
- &slv_qhs_prng &slv_xs_sys_tcu_cfg
- &slv_qhs_clk_ctl &slv_qhs_usb3>;
+ &slv_qhs_pcie_parf &slv_qhs_audio
+ &slv_qhs_tlmm &slv_qhs_prng
+ &slv_xs_sys_tcu_cfg &slv_qhs_clk_ctl
+ &slv_qhs_usb3>;
qcom,bus-dev = <&fab_system_noc>;
};
@@ -423,17 +434,16 @@
qcom,buswidth = <8>;
qcom,agg-ports = <1>;
qcom,connections = <&slv_qhs_crypto_cfg
- &slv_qhs_snoc_cfg &slv_qhs_emac_cfg
- &slv_qhs_aoss &slv_qhs_spmi_fetcher
- &slv_qhs_pdm &slv_qhs_tcsr
- &slv_xs_qdss_stm &slv_qhs_qpic
- &slv_qxs_imem &slv_qhs_ipa
+ &slv_qhs_pdm &slv_qhs_pcie_parf
+ &slv_qhs_tlmm &slv_qhs_spmi_fetcher
+ &slv_qhs_prng &slv_qhs_qpic
+ &slv_qxs_imem &slv_qhs_snoc_cfg
+ &slv_qhs_audio &slv_qhs_sdc1
+ &slv_qhs_aoss &slv_qhs_ipa
&slv_qhs_usb3_phy &slv_qhs_aop
- &slv_qhs_blsp1 &slv_qhs_sdc1
- &slv_qhs_pcie_parf &slv_qhs_audio
- &slv_qhs_tlmm &slv_qhs_prng
- &slv_xs_sys_tcu_cfg &slv_qhs_clk_ctl
- &slv_qhs_usb3>;
+ &slv_qhs_tcsr &slv_qhs_blsp1
+ &slv_xs_sys_tcu_cfg &slv_qhs_usb3
+ &slv_xs_qdss_stm &slv_qhs_clk_ctl>;
qcom,bus-dev = <&fab_system_noc>;
qcom,bcms = <&bcm_sn9>;
};
@@ -443,9 +453,12 @@
label = "mas-qxm-crypto";
qcom,buswidth = <8>;
qcom,agg-ports = <1>;
- qcom,connections = <&slv_qhs_aoss &slv_qns_aggre_noc>;
+ qcom,qport = <1>;
+ qcom,connections = <&slv_qns_aggre_noc>;
qcom,bus-dev = <&fab_system_noc>;
- qcom,bcms = <&bcm_ce>;
+ qcom,bcms = <&bcm_ce>, <&bcm_pn5>;
+ qcom,ap-owned;
+ qcom,prio = <2>;
};
mas_qxm_ipa: mas-qxm-ipa {
@@ -453,9 +466,25 @@
label = "mas-qxm-ipa";
qcom,buswidth = <8>;
qcom,agg-ports = <1>;
+ qcom,qport = <5>;
qcom,connections = <&slv_qns_aggre_noc_ipa>;
qcom,bus-dev = <&fab_system_noc>;
qcom,bcms = <&bcm_sn11>;
+ qcom,ap-owned;
+ qcom,prio = <2>;
+ qcom,forwarding;
+ };
+
+ mas_qxm_ipa2pcie_slv: mas-qxm-ipa2pcie-slv {
+ cell-id = <MSM_BUS_MASTER_IPA_PCIE>;
+ label = "mas-qxm-ipa2pcie-slv";
+ qcom,buswidth = <8>;
+ qcom,agg-ports = <1>;
+ qcom,qport = <6>;
+ qcom,connections = <&slv_qxs_pcie>;
+ qcom,bus-dev = <&fab_system_noc>;
+ qcom,ap-owned;
+ qcom,prio = <2>;
};
mas_xm_emac: mas-xm-emac {
@@ -463,8 +492,11 @@
label = "mas-xm-emac";
qcom,buswidth = <8>;
qcom,agg-ports = <1>;
+ qcom,qport = <7>;
qcom,connections = <&slv_qns_aggre_noc>;
qcom,bus-dev = <&fab_system_noc>;
+ qcom,ap-owned;
+ qcom,prio = <1>;
};
mas_xm_pcie: mas-xm-pcie {
@@ -472,8 +504,12 @@
label = "mas-xm-pcie";
qcom,buswidth = <8>;
qcom,agg-ports = <1>;
+ qcom,qport = <2>;
qcom,connections = <&slv_qns_aggre_noc>;
qcom,bus-dev = <&fab_system_noc>;
+ qcom,ap-owned;
+ qcom,prio = <2>;
+ qcom,forwarding;
};
mas_xm_qdss_etr: mas-xm-qdss-etr {
@@ -481,20 +517,22 @@
label = "mas-xm-qdss-etr";
qcom,buswidth = <8>;
qcom,agg-ports = <1>;
+ qcom,qport = <3>;
qcom,connections = <&slv_qhs_crypto_cfg
- &slv_qhs_snoc_cfg &slv_qhs_emac_cfg
- &slv_qhs_aoss &slv_qhs_spmi_fetcher
- &slv_qhs_pdm &slv_qns_snoc_memnoc
- &slv_qhs_tcsr &slv_qhs_qpic
- &slv_qxs_imem &slv_qhs_ipa
- &slv_qhs_usb3_phy &slv_qhs_aop
- &slv_qhs_blsp1 &slv_qhs_sdc1
- &slv_qhs_pcie_parf &slv_qhs_audio
- &slv_qhs_tlmm &slv_qhs_prng
- &slv_xs_sys_tcu_cfg &slv_qhs_clk_ctl
- &slv_qhs_usb3>;
+ &slv_qhs_pdm &slv_qhs_pcie_parf
+ &slv_qhs_tlmm &slv_qhs_spmi_fetcher
+ &slv_qhs_prng &slv_qhs_qpic
+ &slv_qxs_imem &slv_qhs_snoc_cfg
+ &slv_qhs_audio &slv_qhs_sdc1
+ &slv_qhs_aoss &slv_qhs_ipa
+ &slv_qns_snoc_memnoc &slv_qhs_usb3_phy
+ &slv_qhs_aop &slv_qhs_tcsr
+ &slv_qhs_blsp1 &slv_xs_sys_tcu_cfg
+ &slv_qhs_usb3 &slv_qhs_clk_ctl>;
qcom,bus-dev = <&fab_system_noc>;
qcom,bcms = <&bcm_sn8>;
+ qcom,ap-owned;
+ qcom,prio = <1>;
};
mas_xm_sdc1: mas-xm-sdc1 {
@@ -502,9 +540,12 @@
label = "mas-xm-sdc1";
qcom,buswidth = <8>;
qcom,agg-ports = <1>;
- qcom,connections = <&slv_qhs_aoss &slv_qns_aggre_noc>;
+ qcom,qport = <8>;
+ qcom,connections = <&slv_qns_aggre_noc>;
qcom,bus-dev = <&fab_system_noc>;
qcom,bcms = <&bcm_pn1>;
+ qcom,ap-owned;
+ qcom,prio = <1>;
};
mas_xm_usb3: mas-xm-usb3 {
@@ -512,8 +553,11 @@
label = "mas-xm-usb3";
qcom,buswidth = <8>;
qcom,agg-ports = <1>;
+ qcom,qport = <4>;
qcom,connections = <&slv_qns_aggre_noc>;
qcom,bus-dev = <&fab_system_noc>;
+ qcom,ap-owned;
+ qcom,prio = <2>;
};
/*Internal nodes*/
@@ -532,7 +576,7 @@
slv_ebi:slv-ebi {
cell-id = <MSM_BUS_SLAVE_EBI_CH0>;
label = "slv-ebi";
- qcom,buswidth = <16>;
+ qcom,buswidth = <4>;
qcom,agg-ports = <1>;
qcom,bus-dev = <&fab_mc_virt>;
qcom,bcms = <&bcm_mc0>;
@@ -612,15 +656,6 @@
qcom,bcms = <&bcm_pn0>;
};
- slv_qhs_emac_cfg:slv-qhs-emac-cfg {
- cell-id = <MSM_BUS_SLAVE_EMAC_CFG>;
- label = "slv-qhs-emac-cfg";
- qcom,buswidth = <4>;
- qcom,agg-ports = <1>;
- qcom,bus-dev = <&fab_system_noc>;
- qcom,bcms = <&bcm_pn0>;
- };
-
slv_qhs_ipa:slv-qhs-ipa {
cell-id = <MSM_BUS_SLAVE_IPA_CFG>;
label = "slv-qhs-ipa";
diff --git a/arch/arm/boot/dts/qcom/sdxpoorwills-cdp.dts b/arch/arm/boot/dts/qcom/sdxpoorwills-cdp.dts
index 15129c7..30484fb 100644
--- a/arch/arm/boot/dts/qcom/sdxpoorwills-cdp.dts
+++ b/arch/arm/boot/dts/qcom/sdxpoorwills-cdp.dts
@@ -20,12 +20,12 @@
model = "Qualcomm Technologies, Inc. SDXPOORWILLS CDP";
compatible = "qcom,sdxpoorwills-cdp",
"qcom,sdxpoorwills", "qcom,cdp";
- qcom,board-id = <1 0x0>, <1 0x100>;
+ qcom,board-id = <1 0x0>, <1 0x100>, <1 0x2>, <1 0x102>;
};
-&blsp1_uart2 {
+&serial_uart {
pinctrl-names = "default";
- pinctrl-0 = <&uart2_console_active>;
+ pinctrl-0 = <&uart3_console_active>;
status = "ok";
};
diff --git a/arch/arm/boot/dts/qcom/sdxpoorwills-mtp.dts b/arch/arm/boot/dts/qcom/sdxpoorwills-mtp.dts
index 8d7e377..73adbdc 100644
--- a/arch/arm/boot/dts/qcom/sdxpoorwills-mtp.dts
+++ b/arch/arm/boot/dts/qcom/sdxpoorwills-mtp.dts
@@ -20,12 +20,12 @@
model = "Qualcomm Technologies, Inc. SDXPOORWILLS MTP";
compatible = "qcom,sdxpoorwills-mtp",
"qcom,sdxpoorwills", "qcom,mtp";
- qcom,board-id = <8 0x0>, <8 0x100>;
+ qcom,board-id = <8 0x0>, <8 0x100>, <8 0x2>, <8 0x102>;
};
-&blsp1_uart2 {
+&serial_uart {
pinctrl-names = "default";
- pinctrl-0 = <&uart2_console_active>;
+ pinctrl-0 = <&uart3_console_active>;
status = "ok";
};
diff --git a/arch/arm/boot/dts/qcom/sdxpoorwills-pinctrl.dtsi b/arch/arm/boot/dts/qcom/sdxpoorwills-pinctrl.dtsi
index b6c04ec..dce3bbf 100644
--- a/arch/arm/boot/dts/qcom/sdxpoorwills-pinctrl.dtsi
+++ b/arch/arm/boot/dts/qcom/sdxpoorwills-pinctrl.dtsi
@@ -32,6 +32,30 @@
};
};
+ uart3_console_active: uart3_console_active {
+ mux {
+ pins = "gpio8", "gpio9";
+ function = "blsp_uart3";
+ };
+ config {
+ pins = "gpio8", "gpio9";
+ drive-strength = <2>;
+ bias-disable;
+ };
+ };
+
+ uart3_console_sleep: uart3_console_sleep {
+ mux {
+ pins = "gpio8", "gpio9";
+ function = "gpio";
+ };
+ config {
+ pins = "gpio8", "gpio9";
+ drive-strength = <2>;
+ bias-disable;
+ };
+ };
+
/* I2C CONFIGURATION */
i2c_1 {
i2c_1_active: i2c_1_active {
diff --git a/arch/arm/boot/dts/qcom/sdxpoorwills-regulator.dtsi b/arch/arm/boot/dts/qcom/sdxpoorwills-regulator.dtsi
index 9947594..e62c4a3 100644
--- a/arch/arm/boot/dts/qcom/sdxpoorwills-regulator.dtsi
+++ b/arch/arm/boot/dts/qcom/sdxpoorwills-regulator.dtsi
@@ -64,6 +64,13 @@
regulator-max-microvolt = <RPMH_REGULATOR_LEVEL_MAX>;
qcom,min-dropout-voltage-level = <(-1)>;
};
+
+ cx_cdev: regulator-cdev {
+ compatible = "qcom,rpmh-reg-cdev";
+ mboxes = <&qmp_aop 0>;
+ qcom,reg-resource-name = "cx";
+ #cooling-cells = <2>;
+ };
};
rpmh-regulator-ldoa1 {
@@ -99,7 +106,6 @@
regulator-max-microvolt = <1128000>;
qcom,init-voltage = <1128000>;
qcom,init-mode = <RPMH_REGULATOR_MODE_LDO_LPM>;
- regulator-always-on;
};
};
@@ -168,9 +174,9 @@
pmxpoorwills_l7: regualtor-pmxpoorwills-l7 {
regulator-name = "pmxpoorwills_l7";
qcom,set = <RPMH_REGULATOR_SET_ALL>;
- regulator-min-microvolt = <2952000>;
+ regulator-min-microvolt = <1800000>;
regulator-max-microvolt = <2952000>;
- qcom,init-voltage = <2952000>;
+ qcom,init-voltage = <1800000>;
qcom,init-mode = <RPMH_REGULATOR_MODE_LDO_LPM>;
};
};
@@ -186,9 +192,9 @@
pmxpoorwills_l8: regualtor-pmxpoorwills-l8 {
regulator-name = "pmxpoorwills_l8";
qcom,set = <RPMH_REGULATOR_SET_ALL>;
- regulator-min-microvolt = <800000>;
- regulator-max-microvolt = <800000>;
- qcom,init-voltage = <800000>;
+ regulator-min-microvolt = <480000>;
+ regulator-max-microvolt = <900000>;
+ qcom,init-voltage = <480000>;
qcom,init-mode = <RPMH_REGULATOR_MODE_LDO_LPM>;
};
};
@@ -211,6 +217,14 @@
regulator-min-microvolt = <RPMH_REGULATOR_LEVEL_OFF>;
regulator-max-microvolt = <RPMH_REGULATOR_LEVEL_MAX>;
};
+
+ mx_cdev: mx-cdev-lvl {
+ compatible = "qcom,regulator-cooling-device";
+ regulator-cdev-supply = <&pmxpoorwills_l9_level>;
+ regulator-levels = <RPMH_REGULATOR_LEVEL_NOM
+ RPMH_REGULATOR_LEVEL_OFF>;
+ #cooling-cells = <2>;
+ };
};
rpmh-regulator-ldoa10 {
@@ -242,9 +256,9 @@
pmxpoorwills_l11: regualtor-pmxpoorwills-l11 {
regulator-name = "pmxpoorwills_l11";
qcom,set = <RPMH_REGULATOR_SET_ALL>;
- regulator-min-microvolt = <1808000>;
- regulator-max-microvolt = <1808000>;
- qcom,init-voltage = <1808000>;
+ regulator-min-microvolt = <1704000>;
+ regulator-max-microvolt = <3000000>;
+ qcom,init-voltage = <1704000>;
qcom,init-mode = <RPMH_REGULATOR_MODE_LDO_LPM>;
};
};
@@ -278,9 +292,9 @@
pmxpoorwills_l13: regualtor-pmxpoorwills-l13 {
regulator-name = "pmxpoorwills_l13";
qcom,set = <RPMH_REGULATOR_SET_ALL>;
- regulator-min-microvolt = <1808000>;
- regulator-max-microvolt = <1808000>;
- qcom,init-voltage = <1808000>;
+ regulator-min-microvolt = <1704000>;
+ regulator-max-microvolt = <3000000>;
+ qcom,init-voltage = <1704000>;
qcom,init-mode = <RPMH_REGULATOR_MODE_LDO_LPM>;
};
};
@@ -296,9 +310,9 @@
pmxpoorwills_l14: regualtor-pmxpoorwills-l14 {
regulator-name = "pmxpoorwills_l14";
qcom,set = <RPMH_REGULATOR_SET_ALL>;
- regulator-min-microvolt = <620000>;
- regulator-max-microvolt = <620000>;
- qcom,init-voltage = <620000>;
+ regulator-min-microvolt = <600000>;
+ regulator-max-microvolt = <800000>;
+ qcom,init-voltage = <600000>;
qcom,init-mode = <RPMH_REGULATOR_MODE_LDO_LPM>;
};
};
@@ -314,11 +328,10 @@
pmxpoorwills_l16: regualtor-pmxpoorwills-l16 {
regulator-name = "pmxpoorwills_l16";
qcom,set = <RPMH_REGULATOR_SET_ALL>;
- regulator-min-microvolt = <752000>;
- regulator-max-microvolt = <752000>;
- qcom,init-voltage = <752000>;
+ regulator-min-microvolt = <304000>;
+ regulator-max-microvolt = <880000>;
+ qcom,init-voltage = <304000>;
qcom,init-mode = <RPMH_REGULATOR_MODE_LDO_LPM>;
- regulator-always-on;
};
};
@@ -332,4 +345,18 @@
qcom,set = <RPMH_REGULATOR_SET_ALL>;
};
};
+
+ /* Stub regulators */
+
+ /*
+ * RPMh does not provide support for PMXPOORWILLS L6 because it is
+ * always on at 1.8 V. Therefore, use a fixed regulator for L6.
+ */
+ pmxpoorwills_l6: regulator-pmxpoorwills-l6 {
+ compatible = "regulator-fixed";
+ regulator-name = "pmxpoorwills_l6";
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ regulator-always-on;
+ };
};
diff --git a/arch/arm/boot/dts/qcom/sdxpoorwills-rumi.dts b/arch/arm/boot/dts/qcom/sdxpoorwills-rumi.dts
index aa9e7f2..b73d3aa 100644
--- a/arch/arm/boot/dts/qcom/sdxpoorwills-rumi.dts
+++ b/arch/arm/boot/dts/qcom/sdxpoorwills-rumi.dts
@@ -43,11 +43,13 @@
/delete-node/ rpmh-regulator-ldoa14;
/delete-node/ rpmh-regulator-ldoa16;
/delete-node/ rpmh-regulator-rgmii;
+
+ /delete-node/ thermal-zones;
};
#include "sdxpoorwills-stub-regulator.dtsi"
-&blsp1_uart2 {
+&serial_uart {
pinctrl-names = "default";
pinctrl-0 = <&uart2_console_active>;
status = "ok";
@@ -61,6 +63,10 @@
compatible = "regulator-fixed";
};
+&ipa_hw {
+ qcom,ipa-hw-mode = <1>; /* IPA hw type = Virtual */
+};
+
&usb {
/delete-property/ qcom,usb-dbm;
qcom,charging-disabled;
diff --git a/arch/arm/boot/dts/qcom/sdxpoorwills-smp2p.dtsi b/arch/arm/boot/dts/qcom/sdxpoorwills-smp2p.dtsi
index f9ad6f4..fbfaa0d 100644
--- a/arch/arm/boot/dts/qcom/sdxpoorwills-smp2p.dtsi
+++ b/arch/arm/boot/dts/qcom/sdxpoorwills-smp2p.dtsi
@@ -105,5 +105,28 @@
interrupt-controller;
#interrupt-cells = <2>;
};
+
+ /* ipa - outbound entry to mss */
+ smp2pgpio_ipa_1_out: qcom,smp2pgpio-ipa-1-out {
+ compatible = "qcom,smp2pgpio";
+ qcom,entry-name = "ipa";
+ qcom,remote-pid = <1>;
+ gpio-controller;
+ #gpio-cells = <2>;
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ };
+
+ /* ipa - inbound entry from mss */
+ smp2pgpio_ipa_1_in: qcom,smp2pgpio-ipa-1-in {
+ compatible = "qcom,smp2pgpio";
+ qcom,entry-name = "ipa";
+ qcom,remote-pid = <1>;
+ qcom,is-inbound;
+ gpio-controller;
+ #gpio-cells = <2>;
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ };
};
diff --git a/arch/arm/boot/dts/qcom/sdxpoorwills-thermal.dtsi b/arch/arm/boot/dts/qcom/sdxpoorwills-thermal.dtsi
index 5a4810a..65467f9 100644
--- a/arch/arm/boot/dts/qcom/sdxpoorwills-thermal.dtsi
+++ b/arch/arm/boot/dts/qcom/sdxpoorwills-thermal.dtsi
@@ -163,6 +163,14 @@
trip = <&aoss_trip>;
cooling-device = <&adsp_vdd 0 0>;
};
+ cx_vdd_cdev {
+ trip = <&aoss_trip>;
+ cooling-device = <&cx_cdev 0 0>;
+ };
+ mx_vdd_cdev {
+ trip = <&aoss_trip>;
+ cooling-device = <&mx_cdev 0 0>;
+ };
};
};
@@ -188,6 +196,14 @@
trip = <&mdm_q6_trip>;
cooling-device = <&adsp_vdd 0 0>;
};
+ cx_vdd_cdev {
+ trip = <&mdm_q6_trip>;
+ cooling-device = <&cx_cdev 0 0>;
+ };
+ mx_vdd_cdev {
+ trip = <&mdm_q6_trip>;
+ cooling-device = <&mx_cdev 0 0>;
+ };
};
};
@@ -213,6 +229,14 @@
trip = <&ddrss_trip>;
cooling-device = <&adsp_vdd 0 0>;
};
+ cx_vdd_cdev {
+ trip = <&ddrss_trip>;
+ cooling-device = <&cx_cdev 0 0>;
+ };
+ mx_vdd_cdev {
+ trip = <&ddrss_trip>;
+ cooling-device = <&mx_cdev 0 0>;
+ };
};
};
@@ -238,6 +262,14 @@
trip = <&cpu_trip>;
cooling-device = <&adsp_vdd 0 0>;
};
+ cx_vdd_cdev {
+ trip = <&cpu_trip>;
+ cooling-device = <&cx_cdev 0 0>;
+ };
+ mx_vdd_cdev {
+ trip = <&cpu_trip>;
+ cooling-device = <&mx_cdev 0 0>;
+ };
};
};
@@ -263,6 +295,14 @@
trip = <&mdm_trip>;
cooling-device = <&adsp_vdd 0 0>;
};
+ cx_vdd_cdev {
+ trip = <&mdm_trip>;
+ cooling-device = <&cx_cdev 0 0>;
+ };
+ mx_vdd_cdev {
+ trip = <&mdm_trip>;
+ cooling-device = <&mx_cdev 0 0>;
+ };
};
};
@@ -274,8 +314,8 @@
tracks-low;
trips {
mdm_vpe_trip: mdm-vpe-trip {
- temperature = <125000>;
- hysteresis = <1000>;
+ temperature = <5000>;
+ hysteresis = <5000>;
type = "passive";
};
};
@@ -288,6 +328,49 @@
trip = <&mdm_vpe_trip>;
cooling-device = <&adsp_vdd 0 0>;
};
+ cx_vdd_cdev {
+ trip = <&mdm_vpe_trip>;
+ cooling-device = <&cx_cdev 0 0>;
+ };
+ mx_vdd_cdev {
+ trip = <&mdm_vpe_trip>;
+ cooling-device = <&mx_cdev 0 0>;
+ };
};
};
+
+ xo-therm-adc {
+ polling-delay-passive = <0>;
+ polling-delay = <0>;
+ thermal-sensors = <&pmxpoorwills_vadc 0x4c>;
+ thermal-governor = "user_space";
+ };
+
+ pa-therm1-adc {
+ polling-delay-passive = <0>;
+ polling-delay = <0>;
+ thermal-sensors = <&pmxpoorwills_vadc 0x4d>;
+ thermal-governor = "user_space";
+ };
+
+ pa-therm2-adc {
+ polling-delay-passive = <0>;
+ polling-delay = <0>;
+ thermal-sensors = <&pmxpoorwills_vadc 0x4e>;
+ thermal-governor = "user_space";
+ };
+
+ mdm-case-therm-adc {
+ polling-delay-passive = <0>;
+ polling-delay = <0>;
+ thermal-sensors = <&pmxpoorwills_vadc 0x4f>;
+ thermal-governor = "user_space";
+ };
+
+ ambient-therm-adc {
+ polling-delay-passive = <0>;
+ polling-delay = <0>;
+ thermal-sensors = <&pmxpoorwills_vadc 0x52>;
+ thermal-governor = "user_space";
+ };
};
diff --git a/arch/arm/boot/dts/qcom/sdxpoorwills-usb.dtsi b/arch/arm/boot/dts/qcom/sdxpoorwills-usb.dtsi
index be2b63e..d9258d8 100644
--- a/arch/arm/boot/dts/qcom/sdxpoorwills-usb.dtsi
+++ b/arch/arm/boot/dts/qcom/sdxpoorwills-usb.dtsi
@@ -12,6 +12,7 @@
*/
#include <dt-bindings/clock/qcom,rpmh.h>
#include <dt-bindings/clock/qcom,gcc-sdxpoorwills.h>
+#include <dt-bindings/msm/msm-bus-ids.h>
&soc {
/* USB port for DWC3 controller */
@@ -47,6 +48,19 @@
resets = <&clock_gcc GCC_USB30_BCR>;
reset-names = "core_reset";
+ qcom,msm-bus,name = "usb";
+ qcom,msm-bus,num-cases = <2>;
+ qcom,msm-bus,num-paths = <3>;
+ qcom,msm-bus,vectors-KBps =
+ <MSM_BUS_MASTER_USB3 MSM_BUS_SLAVE_EBI_CH0 0 0>,
+ <MSM_BUS_MASTER_USB3 MSM_BUS_SLAVE_IPA_CFG 0 0>,
+ <MSM_BUS_MASTER_AMPSS_M0 MSM_BUS_SLAVE_USB3 0 0>,
+ <MSM_BUS_MASTER_USB3
+ MSM_BUS_SLAVE_EBI_CH0 240000 700000>,
+ <MSM_BUS_MASTER_USB3
+ MSM_BUS_SLAVE_IPA_CFG 0 2400>,
+ <MSM_BUS_MASTER_AMPSS_M0 MSM_BUS_SLAVE_USB3 0 40000>;
+
dwc3@a600000 {
compatible = "snps,dwc3";
reg = <0x0a600000 0xcd00>;
@@ -92,8 +106,10 @@
/* USB port for Super Speed PHY */
usb3_qmp_phy: ssphy@ff0000 {
compatible = "qcom,usb-ssphy-qmp-v2";
- reg = <0xff0000 0x1000>;
- reg-names = "qmp_phy_base";
+ reg = <0xff0000 0x1000>,
+ <0x01fcb244 0x4>;
+ reg-names = "qmp_phy_base",
+ "vls_clamp_reg";
vdd-supply = <&pmxpoorwills_l4>;
core-supply = <&pmxpoorwills_l1>;
@@ -101,112 +117,108 @@
qcom,vbus-valid-override;
qcom,qmp-phy-init-seq =
/* <reg_offset, value, delay> */
- <0x048 0x07 0x00 /* QSERDES_COM_PLL_IVCO */
- 0x080 0x14 0x00 /* QSERDES_COM_SYSCLK_EN_SEL */
- 0x034 0x04 0x00 /* QSERDES_COM_BIAS_EN_CLKBUFLR_EN */
- 0x138 0x30 0x00 /* QSERDES_COM_CLK_SELECT */
- 0x03c 0x02 0x00 /* QSERDES_COM_SYS_CLK_CTRL */
- 0x08c 0x08 0x00 /* QSERDES_COM_RESETSM_CNTRL2 */
- 0x15c 0x06 0x00 /* QSERDES_COM_CMN_CONFIG */
- 0x164 0x01 0x00 /* QSERDES_COM_SVS_MODE_CLK_SEL */
- 0x13c 0x80 0x00 /* QSERDES_COM_HSCLK_SEL */
- 0x0b0 0x82 0x00 /* QSERDES_COM_DEC_START_MODE0 */
- 0x0b8 0xab 0x00 /* QSERDES_COM_DIV_FRAC_START1_MODE0 */
- 0x0bc 0xea 0x00 /* QSERDES_COM_DIV_FRAC_START2_MODE0 */
- 0x0c0 0x02 0x00 /* QSERDES_COM_DIV_FRAC_START3_MODE0 */
- 0x060 0x06 0x00 /* QSERDES_COM_CP_CTRL_MODE0 */
- 0x068 0x16 0x00 /* QSERDES_COM_PLL_RCTRL_MODE0 */
- 0x070 0x36 0x00 /* QSERDES_COM_PLL_CCTRL_MODE0 */
- 0x0dc 0x00 0x00 /* QSERDES_COM_INTEGLOOP_GAIN1_MODE0 */
- 0x0d8 0x3f 0x00 /* QSERDES_COM_INTEGLOOP_GAIN0_MODE0 */
- 0x0f8 0x01 0x00 /* QSERDES_COM_VCO_TUNE2_MODE0 */
- 0x0f4 0xc9 0x00 /* QSERDES_COM_VCO_TUNE1_MODE0 */
- 0x148 0x0a 0x00 /* QSERDES_COM_CORECLK_DIV_MODE0 */
- 0x0a0 0x00 0x00 /* QSERDES_COM_LOCK_CMP3_MODE0 */
- 0x09c 0x34 0x00 /* QSERDES_COM_LOCK_CMP2_MODE0 */
- 0x098 0x15 0x00 /* QSERDES_COM_LOCK_CMP1_MODE0 */
- 0x090 0x04 0x00 /* QSERDES_COM_LOCK_CMP_EN */
- 0x154 0x00 0x00 /* QSERDES_COM_CORE_CLK_EN */
- 0x094 0x00 0x00 /* QSERDES_COM_LOCK_CMP_CFG */
- 0x0f0 0x00 0x00 /* QSERDES_COM_VCO_TUNE_MAP */
- 0x040 0x0a 0x00 /* QSERDES_COM_SYSCLK_BUF_ENABLE */
- 0x0d0 0x80 0x00 /* QSERDES_COM_INTEGLOOP_INITVAL */
+ <0x058 0x07 0x00 /* QSERDES_COM_PLL_IVCO */
+ 0x094 0x1a 0x00 /* QSERDES_COM_SYSCLK_EN_SEL */
+ 0x044 0x14 0x00 /* QSERDES_COM_BIAS_EN_CLKBUFLR_EN */
+ 0x154 0x31 0x00 /* QSERDES_COM_CLK_SELECT */
+ 0x04c 0x02 0x00 /* QSERDES_COM_SYS_CLK_CTRL */
+ 0x0a0 0x08 0x00 /* QSERDES_COM_RESETSM_CNTRL2 */
+ 0x17c 0x06 0x00 /* QSERDES_COM_CMN_CONFIG */
+ 0x184 0x05 0x00 /* QSERDES_COM_SVS_MODE_CLK_SEL */
+ 0x1bc 0x11 0x00 /* QSERDES_COM_BIN_VCOCAL_HSCLK_SEL*/
+ 0x158 0x01 0x00 /* QSERDES_COM_HSCLK_SEL */
+ 0x0bc 0x82 0x00 /* QSERDES_COM_DEC_START_MODE0 */
+ 0x0cc 0xab 0x00 /* QSERDES_COM_DIV_FRAC_START1_MODE0 */
+ 0x0d0 0xea 0x00 /* QSERDES_COM_DIV_FRAC_START2_MODE0 */
+ 0x0d4 0x02 0x00 /* COM_DIV_FRAC_START3_MODE0 */
+ 0x1ac 0xca 0x00 /* COM_BIN_VCOCAL_CMP_CODE1_MODE0 */
+ 0x1b0 0x1e 0x00 /* COM_BIN_VCOCAL_CMP_CODE2_MODE0 */
+ 0x074 0x06 0x00 /* QSERDES_COM_CP_CTRL_MODE0 */
+ 0x07c 0x16 0x00 /* QSERDES_COM_PLL_RCTRL_MODE0 */
+ 0x084 0x36 0x00 /* QSERDES_COM_PLL_CCTRL_MODE0 */
+ 0x0f0 0x00 0x00 /* QSERDES_COM_INTEGLOOP_GAIN1_MODE0 */
+ 0x0ec 0x3f 0x00 /* QSERDES_COM_INTEGLOOP_GAIN0_MODE0 */
+ 0x114 0x02 0x00 /* QSERDES_COM_VCO_TUNE2_MODE0 */
+ 0x110 0x24 0x00 /* QSERDES_COM_VCO_TUNE1_MODE0 */
+ 0x168 0x0a 0x00 /* QSERDES_COM_CORECLK_DIV_MODE0 */
+ 0x0b0 0x34 0x00 /* QSERDES_COM_LOCK_CMP2_MODE0 */
+ 0x0ac 0x14 0x00 /* QSERDES_COM_LOCK_CMP1_MODE0 */
+ 0x0a4 0x04 0x00 /* QSERDES_COM_LOCK_CMP_EN */
+ 0x174 0x00 0x00 /* QSERDES_COM_CORE_CLK_EN */
+ 0x0a8 0x00 0x00 /* QSERDES_COM_LOCK_CMP_CFG */
+ 0x10c 0x00 0x00 /* QSERDES_COM_VCO_TUNE_MAP */
+ 0x050 0x0a 0x00 /* QSERDES_COM_SYSCLK_BUF_ENABLE */
+ 0x00c 0x0a 0x00 /* QSERDES_COM_BG_TIMER */
0x010 0x01 0x00 /* QSERDES_COM_SSC_EN_CENTER */
0x01c 0x31 0x00 /* QSERDES_COM_SSC_PER1 */
0x020 0x01 0x00 /* QSERDES_COM_SSC_PER2 */
0x014 0x00 0x00 /* QSERDES_COM_SSC_ADJ_PER1 */
0x018 0x00 0x00 /* QSERDES_COM_SSC_ADJ_PER2 */
- 0x024 0x85 0x00 /* QSERDES_COM_SSC_STEP_SIZE1 */
- 0x028 0x07 0x00 /* QSERDES_COM_SSC_STEP_SIZE2 */
- 0x4c0 0x0c 0x00 /* QSERDES_RX_VGA_CAL_CNTRL2 */
- 0x564 0x50 0x00 /* QSERDES_RX_RX_MODE_00 */
- 0x430 0x0b 0x00 /* QSERDES_RX_UCDR_FASTLOCK_FO_GAIN */
- 0x4d4 0x0e 0x00 /* QSERDES_RX_RX_EQU_ADAPTOR_CNTRL2 */
- 0x4d8 0x4e 0x00 /* QSERDES_RX_RX_EQU_ADAPTOR_CNTRL3 */
- 0x4dc 0x18 0x00 /* QSERDES_RX_RX_EQU_ADAPTOR_CNTRL4 */
- 0x4f8 0x77 0x00 /* RX_RX_EQ_OFFSET_ADAPTOR_CNTRL1 */
- 0x4fc 0x80 0x00 /* RX_RX_OFFSET_ADAPTOR_CNTRL2 */
- 0x504 0x03 0x00 /* QSERDES_RX_SIGDET_CNTRL */
- 0x50c 0x1c 0x00 /* QSERDES_RX_SIGDET_DEGLITCH_CNTRL */
- 0x434 0x75 0x00 /* RX_UCDR_SO_SATURATION_AND_ENABLE */
- 0x444 0x80 0x00 /* QSERDES_RX_UCDR_PI_CONTROLS */
+ 0x030 0xde 0x00 /* QSERDES_COM_SSC_STEP_SIZE1_MODE1 */
+ 0x034 0x07 0x00 /* QSERDES_COM_SSC_STEP_SIZE2_MODE1 */
+ 0x024 0xde 0x00 /* QSERDES_COM_SSC_STEP_SIZE1_MODE0 */
+ 0x028 0x07 0x00 /* QSERDES_COM_SSC_STEP_SIZE1_MODE0 */
+ 0x4a4 0x3f 0x00 /* QSERDES_RX_RX_IDAC_ENABLES */
+ 0x594 0xbf 0x00 /* QSERDES_RX_RX_MODE_01_HIGH4 */
+ 0x590 0x09 0x00 /* QSERDES_RX_RX_MODE_01_HIGH3 */
+ 0x58c 0xc8 0x00 /* QSERDES_RX_RX_MODE_01_HIGH2 */
+ 0x588 0xc8 0x00 /* QSERDES_RX_RX_MODE_01_HIGH */
+ 0x584 0xe0 0x00 /* QSERDES_RX_RX_MODE_01_LOW */
+ 0x444 0x01 0x00 /* QSERDES_RX_UCDR_PI_CONTROLS */
0x408 0x0a 0x00 /* QSERDES_RX_UCDR_FO_GAIN */
- 0x40c 0x06 0x00 /* QSERDES_RX_UCDR_SO_GAIN */
- 0x500 0x00 0x00 /* QSERDES_RX_SIGDET_ENABLES */
- 0x260 0x10 0x00 /* QSERDES_TX_HIGHZ_DRVR_EN */
- 0x2a4 0x12 0x00 /* QSERDES_TX_RCV_DETECT_LVL_2 */
- 0x28c 0xc6 0x00 /* QSERDES_TX_LANE_MODE_1 */
- 0x248 0x09 0x00 /* TX_RES_CODE_LANE_OFFSET_RX */
- 0x244 0x0d 0x00 /* TX_RES_CODE_LANE_OFFSET_TX */
- 0x8c8 0x83 0x00 /* USB3_UNI_PCS_FLL_CNTRL2 */
- 0x8cc 0x09 0x00 /* USB3_UNI_PCS_FLL_CNT_VAL_L */
- 0x8d0 0xa2 0x00 /* USB3_UNI_PCS_FLL_CNT_VAL_H_TOL */
- 0x8d4 0x40 0x00 /* USB3_UNI_PCS_FLL_MAN_CODE */
- 0x8c4 0x02 0x00 /* USB3_UNI_PCS_FLL_CNTRL1 */
- 0x864 0x1b 0x00 /* USB3_UNI_PCS_POWER_STATE_CONFIG2 */
- 0x80c 0x9f 0x00 /* USB3_UNI_PCS_TXMGN_V0 */
- 0x810 0x9f 0x00 /* USB3_UNI_PCS_TXMGN_V1 */
- 0x814 0xb5 0x00 /* USB3_UNI_PCS_TXMGN_V2 */
- 0x818 0x4c 0x00 /* USB3_UNI_PCS_TXMGN_V3 */
- 0x81c 0x64 0x00 /* USB3_UNI_PCS_TXMGN_V4 */
- 0x820 0x6a 0x00 /* USB3_UNI_PCS_TXMGN_LS */
- 0x824 0x15 0x00 /* USB3_UNI_PCS_TXDEEMPH_M6DB_V0 */
- 0x828 0x0d 0x00 /* USB3_UNI_PCS_TXDEEMPH_M3P5DB_V0 */
- 0x82c 0x15 0x00 /* USB3_UNI_PCS_TXDEEMPH_M6DB_V1 */
- 0x830 0x0d 0x00 /* USB3_UNI_PCS_TXDEEMPH_M3P5DB_V1 */
- 0x834 0x15 0x00 /* USB3_UNI_PCS_TXDEEMPH_M6DB_V2 */
- 0x838 0x0d 0x00 /* USB3_UNI_PCS_TXDEEMPH_M3P5DB_V2 */
- 0x83c 0x15 0x00 /* USB3_UNI_PCS_TXDEEMPH_M6DB_V3 */
- 0x840 0x0d 0x00 /* USB3_UNI_PCS_TXDEEMPH_M3P5DB_V3 */
- 0x844 0x15 0x00 /* USB3_UNI_PCS_TXDEEMPH_M6DB_V4 */
- 0x848 0x0d 0x00 /* USB3_UNI_PCS_TXDEEMPH_M3P5DB_V4 */
- 0x84c 0x15 0x00 /* USB3_UNI_PCS_TXDEEMPH_M6DB_LS */
- 0x850 0x0d 0x00 /* USB3_UNI_PCS_TXDEEMPH_M3P5DB_LS */
- 0x85c 0x02 0x00 /* USB3_UNI_PCS_RATE_SLEW_CNTRL */
- 0x8a0 0x04 0x00 /* PCS_PWRUP_RESET_DLY_TIME_AUXCLK */
- 0x88c 0x44 0x00 /* USB3_UNI_PCS_TSYNC_RSYNC_TIME */
- 0x880 0xd1 0x00 /* USB3_UNI_PCS_LOCK_DETECT_CONFIG1 */
- 0x884 0x1f 0x00 /* USB3_UNI_PCS_LOCK_DETECT_CONFIG2 */
- 0x888 0x47 0x00 /* USB3_UNI_PCS_LOCK_DETECT_CONFIG3 */
- 0x870 0xe7 0x00 /* USB3_UNI_PCS_RCVR_DTCT_DLY_P1U2_L */
- 0x874 0x03 0x00 /* USB3_UNI_PCS_RCVR_DTCT_DLY_P1U2_H */
- 0x878 0x40 0x00 /* USB3_UNI_PCS_RCVR_DTCT_DLY_U3_L */
- 0x87c 0x00 0x00 /* USB3_UNI_PCS_RCVR_DTCT_DLY_U3_H */
- 0x9d8 0xba 0x00 /* USB3_UNI_PCS_RX_SIGDET_LVL */
- 0x8b8 0x75 0x00 /* RXEQTRAINING_WAIT_TIME */
- 0x8b0 0x86 0x00 /* PCS_LFPS_TX_ECSTART_EQTLOCK */
- 0x8bc 0x13 0x00 /* PCS_RXEQTRAINING_RUN_TIME */
- 0xa0c 0x21 0x00 /* USB3_UNI_PCS_REFGEN_REQ_CONFIG1 */
- 0xa10 0x60 0x00 /* USB3_UNI_PCS_REFGEN_REQ_CONFIG2 */
+ 0x414 0x06 0x00 /* QSERDES_RX_UCDR_SO_GAIN */
+ 0x430 0x2f 0x00 /* QSERDES_RX_UCDR_FASTLOCK_FO_GAIN */
+ 0x43c 0xff 0x00 /* RX_UCDR_FASTLOCK_COUNT_LOW */
+ 0x440 0x0f 0x00 /* RX_UCDR_FASTLOCK_COUNT_HIGH */
+ 0x420 0x0a 0x00 /* QSERDES_RX_UCDR_SVS_FO_GAIN */
+ 0x42c 0x06 0x00 /* QSERDES_RX_UCDR_SVS_SO_GAIN */
+ 0x434 0x7f 0x00 /* RX_UCDR_SO_SATURATION_AND_ENABLE */
+ 0x4d8 0x0c 0x00 /* QSERDES_RX_VGA_CAL_CNTRL2 */
+ 0x4ec 0x0e 0x00 /* QSERDES_RX_RX_EQU_ADAPTOR_CNTRL2 */
+ 0x4f0 0x4e 0x00 /* QSERDES_RX_RX_EQU_ADAPTOR_CNTRL3 */
+ 0x4f4 0x18 0x00 /* QSERDES_RX_RX_EQU_ADAPTOR_CNTRL4 */
+ 0x5b4 0x04 0x00 /* QSERDES_RX_DFE_EN_TIMER */
+ 0x510 0x77 0x00 /* RX_RX_EQ_OFFSET_ADAPTOR_CNTRL1 */
+ 0x514 0x80 0x00 /* RX_RX_OFFSET_ADAPTOR_CNTRL2 */
+ 0x51c 0x04 0x00 /* QSERDES_RX_SIGDET_CNTRL */
+ 0x524 0x1a 0x00 /* QSERDES_RX_SIGDET_DEGLITCH_CNTRL */
+ 0x4fc 0x00 0x00 /* QSERDES_RX_RX_IDAC_TSETTLE_HIGH */
+ 0x4f8 0xc0 0x00 /* QSERDES_RX_RX_IDAC_TSETTLE_LOW */
+ 0x258 0x10 0x00 /* QSERDES_TX_HIGHZ_DRVR_EN */
+ 0x29c 0x12 0x00 /* QSERDES_TX_RCV_DETECT_LVL_2 */
+ 0x284 0x05 0x00 /* QSERDES_TX_LANE_MODE_1 */
+ 0x288 0x02 0x00 /* QSERDES_TX_LANE_MODE_2 */
+ 0x28c 0x00 0x00 /* QSERDES_TX_LANE_MODE_3*/
+ 0x89c 0x83 0x00 /* USB3_UNI_PCS_FLL_CNTRL2 */
+ 0x8a0 0x09 0x00 /* USB3_UNI_PCS_FLL_CNT_VAL_L */
+ 0x8a4 0xa2 0x00 /* USB3_UNI_PCS_FLL_CNT_VAL_H_TOL */
+ 0x8a8 0x40 0x00 /* USB3_UNI_PCS_FLL_MAN_CODE */
+ 0x898 0x02 0x00 /* USB3_UNI_PCS_FLL_CNTRL1 */
+ 0x8c4 0xd0 0x00 /* USB3_UNI_PCS_LOCK_DETECT_CONFIG1 */
+ 0x8c8 0x17 0x00 /* USB3_UNI_PCS_LOCK_DETECT_CONFIG2 */
+ 0x8cc 0x20 0x00 /* USB3_UNI_PCS_LOCK_DETECT_CONFIG3 */
+ 0x890 0x4f 0x00 /* USB3_UNI_PCS_POWER_STATE_CONFIG1 */
+ 0x990 0xe7 0x00 /* USB3_UNI_PCS_RCVR_DTCT_DLY_P1U2_L */
+ 0x994 0x03 0x00 /* USB3_UNI_PCS_RCVR_DTCT_DLY_P1U2_H */
+ 0x988 0xba 0x00 /* USB3_UNI_PCS_RX_SIGDET_LVL */
+ 0xe2c 0x75 0x00 /* USB3_RXEQTRAINING_WAIT_TIME */
+ 0xe38 0x07 0x00 /* USB3_RXEQTRAINING_DFE_TIME_S2 */
+ 0xe18 0x64 0x00 /* USB3_LFPS_DET_HIGH_COUNT_VAL */
+ 0x9c0 0x88 0x00 /* USB3_UNI_PCS_ALIGN_DETECT_CONFIG1 */
+ 0x9c4 0x13 0x00 /* USB3_UNI_PCS_ALIGN_DETECT_CONFIG2 */
+ 0x9dc 0x0d 0x00 /* USB3_UNI_PCS_EQ_CONFIG1 */
+ 0x9e0 0x0d 0x00 /* USB3_UNI_PCS_EQ_CONFIG2 */
+ 0x8dc 0x21 0x00 /* USB3_UNI_PCS_REFGEN_REQ_CONFIG1 */
+ 0x8e0 0x60 0x00 /* USB3_UNI_PCS_REFGEN_REQ_CONFIG2 */
0xffffffff 0xffffffff 0x00>;
qcom,qmp-phy-reg-offset =
- <0x974 /* USB3_UNI_PCS_PCS_STATUS */
- 0x8d8 /* USB3_UNI_PCS_AUTONOMOUS_MODE_CTRL */
- 0x8dc /* USB3_UNI_PCS_LFPS_RXTERM_IRQ_CLEAR */
- 0x804 /* USB3_UNI_PCS_POWER_DOWN_CONTROL */
+ <0x814 /* USB3_UNI_PCS_PCS_STATUS */
+ 0xe08 /* USB3_UNI_PCS_AUTONOMOUS_MODE_CTRL */
+ 0xe14 /* USB3_UNI_PCS_LFPS_RXTERM_IRQ_CLEAR */
+ 0x840 /* USB3_UNI_PCS_POWER_DOWN_CONTROL */
0x800 /* USB3_UNI_PCS_SW_RESET */
- 0x808>; /* USB3_UNI_PCS_START_CONTROL */
+ 0x844>; /* USB3_UNI_PCS_START_CONTROL */
clocks = <&clock_gcc GCC_USB3_PHY_AUX_CLK>,
<&clock_gcc GCC_USB3_PHY_PIPE_CLK>,
@@ -215,5 +227,8 @@
clock-names = "aux_clk", "pipe_clk", "ref_clk_src",
"cfg_ahb_clk";
+ resets = <&clock_gcc GCC_USB3_PHY_BCR>,
+ <&clock_gcc GCC_USB3PHY_PHY_BCR>;
+ reset-names = "phy_reset", "phy_phy_reset";
};
};
diff --git a/arch/arm/boot/dts/qcom/sdxpoorwills.dtsi b/arch/arm/boot/dts/qcom/sdxpoorwills.dtsi
index 3d2dc66..b6393a91 100644
--- a/arch/arm/boot/dts/qcom/sdxpoorwills.dtsi
+++ b/arch/arm/boot/dts/qcom/sdxpoorwills.dtsi
@@ -206,7 +206,17 @@
mbox-names = "apps";
};
- blsp1_uart2: serial@831000 {
+ snoc_cnoc_keepalive: qcom,snoc_cnoc_keepalive {
+ compatible = "qcom,devbw";
+ governor = "powersave";
+ qcom,src-dst-ports = <53 747>;
+ qcom,active-only;
+ status = "ok";
+ qcom,bw-tbl =
+ < 1 >;
+ };
+
+ serial_uart: serial@831000 {
compatible = "qcom,msm-uartdm-v1.4", "qcom,msm-uartdm";
reg = <0x831000 0x200>;
interrupts = <0 26 0>;
@@ -296,10 +306,10 @@
};
};
- restart@4ab000 {
+ restart@c264000 {
compatible = "qcom,pshold";
- reg = <0x4ab000 0x4>,
- <0x193d100 0x4>;
+ reg = <0x0c264000 0x4>,
+ <0x01fd3000 0x4>;
reg-names = "pshold-base", "tcsr-boot-misc-detect";
};
@@ -484,11 +494,178 @@
reg = <0xc37000c 8>;
};
+ qcom,msm_gsi {
+ compatible = "qcom,msm_gsi";
+ };
+
+ qcom,rmnet-ipa {
+ compatible = "qcom,rmnet-ipa3";
+ qcom,rmnet-ipa-ssr;
+ qcom,ipa-loaduC;
+ qcom,ipa-advertise-sg-support;
+ };
+
system_pm {
compatible = "qcom,system-pm";
mboxes = <&apps_rsc 0>;
};
+ ipa_hw: qcom,ipa@01e00000 {
+ compatible = "qcom,ipa";
+ reg = <0x1e00000 0x34000>,
+ <0x1e04000 0x28000>;
+ reg-names = "ipa-base", "gsi-base";
+ interrupts =
+ <0 241 0>,
+ <0 47 0>;
+ interrupt-names = "ipa-irq", "gsi-irq";
+ qcom,ipa-hw-ver = <14>; /* IPA core version = IPAv4.0 */
+ qcom,ipa-hw-mode = <0>;
+ qcom,ee = <0>;
+ qcom,use-ipa-tethering-bridge;
+ qcom,mhi-event-ring-id-limits = <9 10>; /* start and end */
+ qcom,modem-cfg-emb-pipe-flt;
+ qcom,use-ipa-pm;
+ qcom,bandwidth-vote-for-ipa;
+ qcom,msm-bus,name = "ipa";
+ qcom,msm-bus,num-cases = <5>;
+ qcom,msm-bus,num-paths = <4>;
+ qcom,msm-bus,vectors-KBps =
+ /* No vote */
+ <90 512 0 0>,
+ <90 585 0 0>,
+ <1 676 0 0>,
+ <143 777 0 0>,
+ /* SVS2 */
+ <90 512 3616000 7232000>,
+ <90 585 300000 600000>,
+ <1 676 90000 180000>, /*gcc_config_noc_clk_src */
+ <143 777 0 120>, /* IB defined for IPA2X_clk in MHz*/
+ /* SVS */
+ <90 512 6640000 13280000>,
+ <90 585 400000 800000>,
+ <1 676 100000 200000>,
+ <143 777 0 250>, /* IB defined for IPA2X_clk in MHz*/
+ /* NOMINAL */
+ <90 512 10400000 20800000>,
+ <90 585 800000 1600000>,
+ <1 676 200000 400000>,
+ <143 777 0 440>, /* IB defined for IPA2X_clk in MHz*/
+ /* TURBO */
+ <90 512 10400000 20800000>,
+ <90 585 960000 1920000>,
+ <1 676 266000 532000>,
+ <143 777 0 500>; /* IB defined for IPA clk in MHz*/
+ qcom,bus-vector-names = "MIN", "SVS2", "SVS", "NOMINAL",
+ "TURBO";
+ qcom,throughput-threshold = <310 600 1000>;
+ qcom,scaling-exceptions = <>;
+
+
+ /* IPA RAM mmap */
+ qcom,ipa-ram-mmap = <
+ 0x280 /* ofst_start; */
+ 0x0 /* nat_ofst; */
+ 0x0 /* nat_size; */
+ 0x288 /* v4_flt_hash_ofst; */
+ 0x78 /* v4_flt_hash_size; */
+ 0x4000 /* v4_flt_hash_size_ddr; */
+ 0x308 /* v4_flt_nhash_ofst; */
+ 0x78 /* v4_flt_nhash_size; */
+ 0x4000 /* v4_flt_nhash_size_ddr; */
+ 0x388 /* v6_flt_hash_ofst; */
+ 0x78 /* v6_flt_hash_size; */
+ 0x4000 /* v6_flt_hash_size_ddr; */
+ 0x408 /* v6_flt_nhash_ofst; */
+ 0x78 /* v6_flt_nhash_size; */
+ 0x4000 /* v6_flt_nhash_size_ddr; */
+ 0xf /* v4_rt_num_index; */
+ 0x0 /* v4_modem_rt_index_lo; */
+ 0x7 /* v4_modem_rt_index_hi; */
+ 0x8 /* v4_apps_rt_index_lo; */
+ 0xe /* v4_apps_rt_index_hi; */
+ 0x488 /* v4_rt_hash_ofst; */
+ 0x78 /* v4_rt_hash_size; */
+ 0x4000 /* v4_rt_hash_size_ddr; */
+ 0x508 /* v4_rt_nhash_ofst; */
+ 0x78 /* v4_rt_nhash_size; */
+ 0x4000 /* v4_rt_nhash_size_ddr; */
+ 0xf /* v6_rt_num_index; */
+ 0x0 /* v6_modem_rt_index_lo; */
+ 0x7 /* v6_modem_rt_index_hi; */
+ 0x8 /* v6_apps_rt_index_lo; */
+ 0xe /* v6_apps_rt_index_hi; */
+ 0x588 /* v6_rt_hash_ofst; */
+ 0x78 /* v6_rt_hash_size; */
+ 0x4000 /* v6_rt_hash_size_ddr; */
+ 0x608 /* v6_rt_nhash_ofst; */
+ 0x78 /* v6_rt_nhash_size; */
+ 0x4000 /* v6_rt_nhash_size_ddr; */
+ 0x688 /* modem_hdr_ofst; */
+ 0x140 /* modem_hdr_size; */
+ 0x7c8 /* apps_hdr_ofst; */
+ 0x0 /* apps_hdr_size; */
+ 0x800 /* apps_hdr_size_ddr; */
+ 0x7d0 /* modem_hdr_proc_ctx_ofst; */
+ 0x200 /* modem_hdr_proc_ctx_size; */
+ 0x9d0 /* apps_hdr_proc_ctx_ofst; */
+ 0x200 /* apps_hdr_proc_ctx_size; */
+ 0x0 /* apps_hdr_proc_ctx_size_ddr; */
+ 0x0 /* modem_comp_decomp_ofst; diff */
+ 0x0 /* modem_comp_decomp_size; diff */
+ 0x13f0 /* modem_ofst; */
+ 0x100c /* modem_size; */
+ 0x23fc /* apps_v4_flt_hash_ofst; */
+ 0x0 /* apps_v4_flt_hash_size; */
+ 0x23fc /* apps_v4_flt_nhash_ofst; */
+ 0x0 /* apps_v4_flt_nhash_size; */
+ 0x23fc /* apps_v6_flt_hash_ofst; */
+ 0x0 /* apps_v6_flt_hash_size; */
+ 0x23fc /* apps_v6_flt_nhash_ofst; */
+ 0x0 /* apps_v6_flt_nhash_size; */
+ 0x80 /* uc_info_ofst; */
+ 0x200 /* uc_info_size; */
+ 0x2800 /* end_ofst; */
+ 0x23fc /* apps_v4_rt_hash_ofst; */
+ 0x0 /* apps_v4_rt_hash_size; */
+ 0x23fc /* apps_v4_rt_nhash_ofst; */
+ 0x0 /* apps_v4_rt_nhash_size; */
+ 0x23fc /* apps_v6_rt_hash_ofst; */
+ 0x0 /* apps_v6_rt_hash_size; */
+ 0x23fc /* apps_v6_rt_nhash_ofst; */
+ 0x0 /* apps_v6_rt_nhash_size; */
+ 0x2400 /* uc_event_ring_ofst; */
+ 0x400 /* uc_event_ring_size;*/
+ 0xbd8 /* pdn_config_ofst; */
+ 0x50 /* pdn_config_size; */
+ 0xc30 /* stats_quota_ofst */
+ 0x60 /* stats_quota_size */
+ 0xc90 /* stats_tethering_ofst */
+ 0x140 /* stats_tethering_size */
+ 0xdd0 /* stats_flt_v4_ofst */
+ 0x180 /* stats_flt_v4_size */
+ 0xf50 /* stats_flt_v6_ofst */
+ 0x180 /* stats_flt_v6_size */
+ 0x10d0 /* stats_rt_v4_ofst */
+ 0x180 /* stats_rt_v4_size */
+ 0x1250 /* stats_rt_v6_ofst */
+ 0x180 /* stats_rt_v6_size */
+ 0x13d0 /* stats_drop_ofst */
+ 0x20 /* stats_drop_size */
+ >;
+
+ /* smp2p gpio information */
+ qcom,smp2pgpio_map_ipa_1_out {
+ compatible = "qcom,smp2pgpio-map-ipa-1-out";
+ gpios = <&smp2pgpio_ipa_1_out 0 0>;
+ };
+
+ qcom,smp2pgpio_map_ipa_1_in {
+ compatible = "qcom,smp2pgpio-map-ipa-1-in";
+ gpios = <&smp2pgpio_ipa_1_in 0 0>;
+ };
+ };
+
emac_hw: qcom,emac@00020000 {
compatible = "qcom,emac-dwc-eqos";
reg = <0x20000 0x10000>,
@@ -518,7 +695,7 @@
reg = <0xc300000 0x400>,
<0x17811008 0x4>;
reg-names = "msgram", "irq-reg-base";
- qcom,irq-mask = <0x1>;
+ qcom,irq-mask = <0x2>;
interrupts = <GIC_SPI 221 IRQ_TYPE_EDGE_RISING>;
priority = <0>;
mbox-desc-offset = <0x0>;
diff --git a/arch/arm/configs/msm8953-perf_defconfig b/arch/arm/configs/msm8953-perf_defconfig
index 067878b..fd1cac3 100644
--- a/arch/arm/configs/msm8953-perf_defconfig
+++ b/arch/arm/configs/msm8953-perf_defconfig
@@ -25,6 +25,7 @@
# CONFIG_PID_NS is not set
CONFIG_SCHED_AUTOGROUP=y
CONFIG_SCHED_TUNE=y
+CONFIG_DEFAULT_USE_ENERGY_AWARE=y
CONFIG_BLK_DEV_INITRD=y
# CONFIG_RD_XZ is not set
# CONFIG_RD_LZO is not set
@@ -357,6 +358,8 @@
CONFIG_MMC_SDHCI=y
CONFIG_MMC_SDHCI_PLTFM=y
CONFIG_MMC_SDHCI_MSM=y
+CONFIG_MMC_SDHCI_MSM_ICE=y
+CONFIG_MMC_CQ_HCI=y
CONFIG_NEW_LEDS=y
CONFIG_LEDS_CLASS=y
CONFIG_LEDS_QPNP=y
diff --git a/arch/arm/configs/msm8953_defconfig b/arch/arm/configs/msm8953_defconfig
index 46f3e0c..c126ccd 100644
--- a/arch/arm/configs/msm8953_defconfig
+++ b/arch/arm/configs/msm8953_defconfig
@@ -29,6 +29,7 @@
# CONFIG_PID_NS is not set
CONFIG_SCHED_AUTOGROUP=y
CONFIG_SCHED_TUNE=y
+CONFIG_DEFAULT_USE_ENERGY_AWARE=y
CONFIG_BLK_DEV_INITRD=y
# CONFIG_RD_XZ is not set
# CONFIG_RD_LZO is not set
@@ -369,6 +370,8 @@
CONFIG_MMC_SDHCI=y
CONFIG_MMC_SDHCI_PLTFM=y
CONFIG_MMC_SDHCI_MSM=y
+CONFIG_MMC_SDHCI_MSM_ICE=y
+CONFIG_MMC_CQ_HCI=y
CONFIG_NEW_LEDS=y
CONFIG_LEDS_CLASS=y
CONFIG_LEDS_QPNP=y
diff --git a/arch/arm/configs/sdxpoorwills-perf_defconfig b/arch/arm/configs/sdxpoorwills-perf_defconfig
index 456ff5e..e015eff 100644
--- a/arch/arm/configs/sdxpoorwills-perf_defconfig
+++ b/arch/arm/configs/sdxpoorwills-perf_defconfig
@@ -228,6 +228,7 @@
CONFIG_CPU_THERMAL=y
CONFIG_THERMAL_QPNP=y
CONFIG_THERMAL_TSENS=y
+CONFIG_QTI_AOP_REG_COOLING_DEVICE=y
CONFIG_QTI_QMI_COOLING_DEVICE=y
CONFIG_REGULATOR_COOLING_DEVICE=y
CONFIG_MFD_I2C_PMIC=y
diff --git a/arch/arm/configs/sdxpoorwills_defconfig b/arch/arm/configs/sdxpoorwills_defconfig
index f2b20b0..d0568aa 100644
--- a/arch/arm/configs/sdxpoorwills_defconfig
+++ b/arch/arm/configs/sdxpoorwills_defconfig
@@ -221,6 +221,7 @@
CONFIG_CPU_THERMAL=y
CONFIG_THERMAL_QPNP=y
CONFIG_THERMAL_TSENS=y
+CONFIG_QTI_AOP_REG_COOLING_DEVICE=y
CONFIG_QTI_QMI_COOLING_DEVICE=y
CONFIG_REGULATOR_COOLING_DEVICE=y
CONFIG_MFD_I2C_PMIC=y
@@ -312,6 +313,8 @@
CONFIG_MSM_QMP=y
CONFIG_QCOM_SCM=y
CONFIG_MSM_BOOT_STATS=y
+CONFIG_QCOM_BUS_SCALING=y
+CONFIG_QCOM_BUS_CONFIG_RPMH=y
CONFIG_MSM_SMEM=y
CONFIG_MSM_GLINK=y
CONFIG_MSM_GLINK_LOOPBACK_SERVER=y
@@ -328,6 +331,7 @@
CONFIG_QCOM_COMMAND_DB=y
CONFIG_MSM_PM=y
CONFIG_DEVFREQ_GOV_SIMPLE_ONDEMAND=y
+CONFIG_QCOM_DEVFREQ_DEVBW=y
CONFIG_IIO=y
CONFIG_PWM=y
CONFIG_PWM_QPNP=y
diff --git a/arch/arm/mach-qcom/Kconfig b/arch/arm/mach-qcom/Kconfig
index 4761bc5..8ca4247 100644
--- a/arch/arm/mach-qcom/Kconfig
+++ b/arch/arm/mach-qcom/Kconfig
@@ -43,7 +43,6 @@
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
diff --git a/arch/arm64/Kconfig.platforms b/arch/arm64/Kconfig.platforms
index 6531949..96f43d6 100644
--- a/arch/arm64/Kconfig.platforms
+++ b/arch/arm64/Kconfig.platforms
@@ -124,6 +124,7 @@
config ARCH_SDM845
bool "Enable Support for Qualcomm Technologies Inc. SDM845"
depends on ARCH_QCOM
+ select COMMON_CLK
select COMMON_CLK_QCOM
select QCOM_GDSC
help
@@ -133,6 +134,7 @@
config ARCH_SDM670
bool "Enable Support for Qualcomm Technologies Inc. SDM670"
depends on ARCH_QCOM
+ select COMMON_CLK
select COMMON_CLK_QCOM
select QCOM_GDSC
help
diff --git a/arch/arm64/boot/dts/qcom/Makefile b/arch/arm64/boot/dts/qcom/Makefile
index 3df7439..5a7e17e 100644
--- a/arch/arm64/boot/dts/qcom/Makefile
+++ b/arch/arm64/boot/dts/qcom/Makefile
@@ -126,7 +126,8 @@
sda670-pm660a-mtp-overlay.dtbo \
qcs605-cdp-overlay.dtbo \
qcs605-mtp-overlay.dtbo \
- qcs605-external-codec-mtp-overlay.dtbo
+ qcs605-external-codec-mtp-overlay.dtbo \
+ qcs605-lc-mtp-overlay.dtbo
sdm670-cdp-overlay.dtbo-base := sdm670.dtb
sdm670-mtp-overlay.dtbo-base := sdm670.dtb
@@ -154,6 +155,7 @@
qcs605-cdp-overlay.dtbo-base := qcs605.dtb
qcs605-mtp-overlay.dtbo-base := qcs605.dtb
qcs605-external-codec-mtp-overlay.dtbo-base := qcs605.dtb
+qcs605-lc-mtp-overlay.dtbo-base := qcs605.dtb
else
dtb-$(CONFIG_ARCH_SDM670) += sdm670-rumi.dtb \
@@ -182,7 +184,8 @@
qcs605-360camera.dtb \
qcs605-mtp.dtb \
qcs605-cdp.dtb \
- qcs605-external-codec-mtp.dtb
+ qcs605-external-codec-mtp.dtb \
+ qcs605-lc-mtp.dtb
endif
ifeq ($(CONFIG_BUILD_ARM64_DT_OVERLAY),y)
diff --git a/arch/arm64/boot/dts/qcom/batterydata-ascent-3450mAh.dtsi b/arch/arm64/boot/dts/qcom/batterydata-ascent-3450mAh.dtsi
new file mode 100644
index 0000000..3eed42a
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/batterydata-ascent-3450mAh.dtsi
@@ -0,0 +1,60 @@
+/*
+ * Copyright (c) 2015, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+qcom,ascent-3450mah {
+ /* #Ascent_860_82209_0000_3450mAh_averaged_MasterSlave_Sept28th2015*/
+ qcom,max-voltage-uv = <4350000>;
+ qcom,nom-batt-capacity-mah = <3450>;
+ qcom,batt-id-kohm = <60>;
+ qcom,battery-beta = <3435>;
+ qcom,battery-type = "ascent_3450mah";
+ qcom,chg-rslow-comp-c1 = <6834679>;
+ qcom,chg-rslow-comp-c2 = <20647220>;
+ qcom,chg-rs-to-rslow = <915002>;
+ qcom,chg-rslow-comp-thr = <0xD5>;
+ qcom,checksum = <0xE50C>;
+ qcom,fg-profile-data = [
+ C5 83 25 77
+ AB 7B CA 74
+ 4C 83 7F 5B
+ EB 80 ED 8C
+ EA 81 61 9B
+ A6 BE 2B D0
+ 55 0E D6 83
+ 09 77 25 7B
+ 03 74 49 83
+ CC 70 0C 70
+ 0C 85 67 82
+ E6 93 27 B5
+ 61 C0 58 10
+ 23 0D 50 59
+ CE 6E 71 FD
+ CD 15 CC 3F
+ 1D 36 00 00
+ B9 47 29 3B
+ 1D 2E 00 00
+ 00 00 00 00
+ 00 00 00 00
+ D8 6A E7 69
+ B3 7C 4E 7A
+ 7E 77 77 70
+ 40 77 0D 73
+ 22 76 96 6A
+ 71 65 20 B0
+ 2C 97 63 12
+ 64 A0 71 0C
+ 28 00 FF 36
+ F0 11 30 03
+ 00 00 00 0C
+ ];
+};
diff --git a/arch/arm64/boot/dts/qcom/batterydata-itech-3000mah.dtsi b/arch/arm64/boot/dts/qcom/batterydata-itech-3000mah.dtsi
new file mode 100644
index 0000000..24b4626
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/batterydata-itech-3000mah.dtsi
@@ -0,0 +1,61 @@
+/* Copyright (c) 2014-2015, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+qcom,itech-3000mah {
+ /* #Itech_B00826LF_3000mAh_Feb24th_Averaged*/
+ qcom,max-voltage-uv = <4350000>;
+ qcom,v-cutoff-uv = <3400000>;
+ qcom,chg-term-ua = <100000>;
+ qcom,batt-id-kohm = <100>;
+ qcom,battery-type = "itech_3000mah";
+ qcom,chg-rslow-comp-c1 = <4365000>;
+ qcom,chg-rslow-comp-c2 = <8609000>;
+ qcom,chg-rslow-comp-thr = <0xBE>;
+ qcom,chg-rs-to-rslow = <761000>;
+ qcom,fastchg-current-ma = <2000>;
+ qcom,fg-cc-cv-threshold-mv = <4340>;
+ qcom,checksum = <0x0B7C>;
+ qcom,fg-profile-data = [
+ F0 83 6B 7D
+ 66 81 EC 77
+ 43 83 E3 5A
+ 7C 81 33 8D
+ E1 81 EC 98
+ 7B B5 F8 BB
+ 5B 12 E2 83
+ 4A 7C 63 80
+ CF 75 50 83
+ FD 5A 83 82
+ E6 8E 12 82
+ B6 9A 1A BE
+ BE CB 55 0E
+ 96 0B E0 5A
+ CE 6E 71 FD
+ 2A 31 7E 47
+ CF 40 00 00
+ DB 45 0F 32
+ AF 31 00 00
+ 00 00 00 00
+ 00 00 00 00
+ E3 6A 60 69
+ 9E 6D 47 83
+ 13 7C 23 70
+ 0B 74 8F 80
+ DB 75 17 68
+ BA 75 BF B3
+ 21 5B 69 B5
+ 6C A0 71 0C
+ 28 00 FF 36
+ F0 11 30 03
+ 00 00 00 0E
+ ];
+};
diff --git a/arch/arm64/boot/dts/qcom/batterydata-qrd-sku1-4v4-2800mah.dtsi b/arch/arm64/boot/dts/qcom/batterydata-qrd-sku1-4v4-2800mah.dtsi
new file mode 100644
index 0000000..da52039
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/batterydata-qrd-sku1-4v4-2800mah.dtsi
@@ -0,0 +1,62 @@
+/* Copyright (c) 2015-2016, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+qcom,qrd_msm8937_sku1_2920mah {
+ /* #QRD8937_2800mAh_China_data_averaged_MasterSlave_Oct30th2015*/
+ qcom,max-voltage-uv = <4400000>;
+ qcom,nom-batt-capacity-mah = <2800>;
+ qcom,batt-id-kohm = <90>;
+ qcom,battery-beta = <3380>;
+ qcom,battery-type = "qrd_msm8937_sku1_2800mah";
+ qcom,fastchg-current-ma = <2600>;
+ qcom,fg-cc-cv-threshold-mv = <4390>;
+ qcom,chg-rslow-comp-c1 = <6733839>;
+ qcom,chg-rslow-comp-c2 = <23336040>;
+ qcom,chg-rs-to-rslow = <1049243>;
+ qcom,chg-rslow-comp-thr = <0xDB>;
+ qcom,checksum = <0x7E2A>;
+ qcom,gui-version = "PMI8950GUI - 2.0.0.14";
+ qcom,fg-profile-data = [
+ C6 83 8A 77
+ 3E 80 84 75
+ 72 83 A1 7C
+ A0 90 FC 97
+ 3F 82 09 99
+ 92 B7 97 C3
+ 4C 14 EB 83
+ A7 7C CE 80
+ 79 76 60 83
+ 3B 64 34 88
+ 19 94 49 82
+ 07 9A 7F BD
+ BF CA 53 0D
+ 32 0B 68 59
+ 14 70 71 FD
+ 8C 28 9C 45
+ 3F 21 00 00
+ B6 47 FE 30
+ 0B 40 00 00
+ 00 00 00 00
+ 00 00 00 00
+ 3A 70 78 6B
+ F7 77 7F 88
+ 32 7C F2 70
+ 64 75 0B 79
+ 2B 77 F3 6B
+ CA 70 7D B1
+ 21 57 6B 6B
+ 6D A0 71 0C
+ 28 00 FF 36
+ F0 11 30 03
+ 00 00 00 0C
+ ];
+};
diff --git a/arch/arm64/boot/dts/qcom/fg-gen3-batterydata-ascent-3450mah.dtsi b/arch/arm64/boot/dts/qcom/fg-gen3-batterydata-ascent-3450mah.dtsi
index 7705d01..1990b65 100644
--- a/arch/arm64/boot/dts/qcom/fg-gen3-batterydata-ascent-3450mah.dtsi
+++ b/arch/arm64/boot/dts/qcom/fg-gen3-batterydata-ascent-3450mah.dtsi
@@ -17,42 +17,42 @@
qcom,fastchg-current-ma = <3450>;
qcom,batt-id-kohm = <60>;
qcom,battery-beta = <3435>;
- qcom,battery-type = "ascent_3450mah_averaged_masterslave_jul11th2017";
- qcom,checksum = <0x7C33>;
+ qcom,battery-type = "ascent_3450mah_averaged_masterslave_oct30th2017";
+ qcom,checksum = <0xAAE2>;
qcom,gui-version = "PMI8998GUI - 2.0.0.58";
qcom,fg-profile-data = [
8F 1F 94 05
73 0A 4A 06
27 1D 21 EA
- 16 0A 3B 0C
+ 16 0A 3A 0C
07 18 97 22
A5 3C EC 4A
5C 00 00 00
10 00 00 00
- 00 00 92 BC
- CD BD 02 B4
+ 00 00 43 C5
+ 92 BC 89 BB
11 00 08 00
69 DA AD 07
4B FD 19 FA
- 1D 0C B0 0C
+ 7E 01 49 13
EB F3 78 3B
24 06 09 20
27 00 14 00
7E 1F F2 05
- 19 0A 55 FD
- 6C 1D C6 ED
+ 19 0A AB 06
+ 6C 1D B9 07
1A 12 FF 1D
6F 18 EB 22
B9 45 6F 52
55 00 00 00
0E 00 00 00
- 00 00 A1 D5
- 34 BA A0 CA
+ 00 00 33 CC
+ 72 CA B3 C4
0F 00 00 00
93 00 AD 07
8D FD F6 00
- BA 0D 5C 04
- B3 FC F4 1B
+ 6F E3 44 0B
+ AB FC F9 1B
C3 33 CC FF
07 10 00 00
A4 0D 99 45
diff --git a/arch/arm64/boot/dts/qcom/msm-arm-smmu-sdm670.dtsi b/arch/arm64/boot/dts/qcom/msm-arm-smmu-sdm670.dtsi
index ae22a36..ab088b8 100644
--- a/arch/arm64/boot/dts/qcom/msm-arm-smmu-sdm670.dtsi
+++ b/arch/arm64/boot/dts/qcom/msm-arm-smmu-sdm670.dtsi
@@ -322,3 +322,19 @@
dma-coherent;
};
};
+
+&apps_smmu {
+ qcom,actlr = <0x0880 0x8 0x103>,
+ <0x0881 0x8 0x103>,
+ <0x0c80 0x8 0x103>,
+ <0x0c81 0x8 0x103>,
+ <0x1090 0x0 0x103>,
+ <0x1091 0x0 0x103>,
+ <0x10a0 0x8 0x103>,
+ <0x10b0 0x0 0x103>,
+ <0x10a1 0x8 0x103>,
+ <0x10a3 0x8 0x103>,
+ <0x10a4 0x8 0x103>,
+ <0x10b4 0x0 0x103>,
+ <0x10a5 0x8 0x103>;
+};
diff --git a/arch/arm64/boot/dts/qcom/msm8953-cpu.dtsi b/arch/arm64/boot/dts/qcom/msm8953-cpu.dtsi
index 1b78fdd..8d80a40 100644
--- a/arch/arm64/boot/dts/qcom/msm8953-cpu.dtsi
+++ b/arch/arm64/boot/dts/qcom/msm8953-cpu.dtsi
@@ -58,6 +58,7 @@
reg = <0x0>;
enable-method = "psci";
efficiency = <1024>;
+ sched-energy-costs = <&CPU_COST_0 &CLUSTER_COST_0>;
next-level-cache = <&L2_0>;
L2_0: l2-cache {
compatible = "arm,arch-cache";
@@ -81,6 +82,7 @@
enable-method = "psci";
reg = <0x1>;
efficiency = <1024>;
+ sched-energy-costs = <&CPU_COST_0 &CLUSTER_COST_0>;
next-level-cache = <&L2_0>;
L1_I_1: l1-icache {
compatible = "arm,arch-cache";
@@ -98,6 +100,7 @@
enable-method = "psci";
reg = <0x2>;
efficiency = <1024>;
+ sched-energy-costs = <&CPU_COST_0 &CLUSTER_COST_0>;
next-level-cache = <&L2_0>;
L1_I_2: l1-icache {
compatible = "arm,arch-cache";
@@ -115,6 +118,7 @@
enable-method = "psci";
reg = <0x3>;
efficiency = <1024>;
+ sched-energy-costs = <&CPU_COST_0 &CLUSTER_COST_0>;
next-level-cache = <&L2_0>;
L1_I_3: l1-icache {
compatible = "arm,arch-cache";
@@ -132,6 +136,7 @@
enable-method = "psci";
reg = <0x100>;
efficiency = <1126>;
+ sched-energy-costs = <&CPU_COST_0 &CLUSTER_COST_1>;
next-level-cache = <&L2_1>;
L2_1: l2-cache {
compatible = "arm,arch-cache";
@@ -155,6 +160,7 @@
enable-method = "psci";
reg = <0x101>;
efficiency = <1126>;
+ sched-energy-costs = <&CPU_COST_0 &CLUSTER_COST_1>;
next-level-cache = <&L2_1>;
L1_I_101: l1-icache {
compatible = "arm,arch-cache";
@@ -172,6 +178,7 @@
enable-method = "psci";
reg = <0x102>;
efficiency = <1126>;
+ sched-energy-costs = <&CPU_COST_0 &CLUSTER_COST_1>;
next-level-cache = <&L2_1>;
L1_I_102: l1-icache {
compatible = "arm,arch-cache";
@@ -189,6 +196,7 @@
enable-method = "psci";
reg = <0x103>;
efficiency = <1126>;
+ sched-energy-costs = <&CPU_COST_0 &CLUSTER_COST_1>;
next-level-cache = <&L2_1>;
L1_I_103: l1-icache {
compatible = "arm,arch-cache";
@@ -200,6 +208,77 @@
};
};
};
+
+ energy_costs: energy-costs {
+ compatible = "sched-energy";
+
+ CPU_COST_0: core-cost0 {
+ busy-cost-data = <
+ 652800 5
+ 883200 8
+ 1036800 10
+ 1248000 13
+ 1401600 16
+ 1536000 19
+ 1689600 22
+ 1804800 26
+ 1843200 27
+ 1958400 33
+ 2016000 36
+ 2150400 43
+ 2208000 44
+ 2304000 54
+ 2400000 65
+ >;
+ idle-cost-data = <
+ 4 3 2 1
+ >;
+ };
+ CLUSTER_COST_0: cluster-cost0 {
+ busy-cost-data = <
+ 652800 69
+ 883200 72
+ 1036800 74
+ 1248000 77
+ 1401600 80
+ 1536000 90
+ 1689600 100
+ 1804800 110
+ 1843200 120
+ 1958400 130
+ 2016000 140
+ 2150400 150
+ 2208000 160
+ 2304000 170
+ 2400000 180
+ >;
+ idle-cost-data = <
+ 4 3 2 1
+ >;
+ };
+ CLUSTER_COST_1: cluster-cost1 {
+ busy-cost-data = <
+ 652800 5
+ 883200 8
+ 1036800 10
+ 1248000 13
+ 1401600 16
+ 1536000 85
+ 1689600 95
+ 1804800 105
+ 1843200 115
+ 1958400 125
+ 2016000 135
+ 2150400 145
+ 2208000 155
+ 2304000 165
+ 2400000 175
+ >;
+ idle-cost-data = <
+ 4 3 2 1
+ >;
+ };
+ };
};
&soc {
diff --git a/arch/arm64/boot/dts/qcom/msm8953-mtp.dts b/arch/arm64/boot/dts/qcom/msm8953-mtp.dts
index 1e8b0f0..12b039c 100644
--- a/arch/arm64/boot/dts/qcom/msm8953-mtp.dts
+++ b/arch/arm64/boot/dts/qcom/msm8953-mtp.dts
@@ -14,7 +14,9 @@
/dts-v1/;
#include "msm8953.dtsi"
+#include "pmi8950.dtsi"
#include "msm8953-mtp.dtsi"
+#include "msm8953-pmi8950.dtsi"
/ {
model = "Qualcomm Technologies, Inc. MSM8953 + PMI8950 MTP";
@@ -22,3 +24,21 @@
qcom,board-id= <8 0>;
qcom,pmic-id = <0x010016 0x010011 0x0 0x0>;
};
+
+/{
+ mtp_batterydata: qcom,battery-data {
+ qcom,batt-id-range-pct = <15>;
+ #include "batterydata-itech-3000mah.dtsi"
+ #include "batterydata-ascent-3450mAh.dtsi"
+ };
+};
+
+&pmi8950_fg {
+ qcom,battery-data = <&mtp_batterydata>;
+};
+
+&pmi8950_charger {
+ qcom,battery-data = <&mtp_batterydata>;
+ qcom,chg-led-sw-controls;
+ qcom,chg-led-support;
+};
diff --git a/arch/arm64/boot/dts/qcom/msm8953-pmi8950.dtsi b/arch/arm64/boot/dts/qcom/msm8953-pmi8950.dtsi
new file mode 100644
index 0000000..6270223
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/msm8953-pmi8950.dtsi
@@ -0,0 +1,28 @@
+/*
+ * Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+&soc {
+ led_flash0: qcom,camera-flash {
+ cell-index = <0>;
+ compatible = "qcom,camera-flash";
+ qcom,flash-type = <1>;
+ qcom,flash-source = <&pmi8950_flash0 &pmi8950_flash1>;
+ qcom,torch-source = <&pmi8950_torch0 &pmi8950_torch1>;
+ qcom,switch-source = <&pmi8950_switch>;
+ };
+};
+
+&labibb {
+ status = "ok";
+ qpnp,qpnp-labibb-mode = "lcd";
+};
diff --git a/arch/arm64/boot/dts/qcom/msm8953-regulator.dtsi b/arch/arm64/boot/dts/qcom/msm8953-regulator.dtsi
new file mode 100644
index 0000000..e4634c4
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/msm8953-regulator.dtsi
@@ -0,0 +1,928 @@
+/*
+ * Copyright (c) 2015-2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <dt-bindings/interrupt-controller/arm-gic.h>
+
+&rpm_bus {
+ rpm-regulator-smpa1 {
+ status = "okay";
+ pm8953_s1: regulator-s1 {
+ regulator-min-microvolt = <870000>;
+ regulator-max-microvolt = <1156000>;
+ qcom,init-voltage = <1000000>;
+ status = "okay";
+ };
+ };
+
+ /* PM8953 S2 - VDD_CX supply */
+ rpm-regulator-smpa2 {
+ status = "okay";
+ pm8953_s2_level: regulator-s2-level {
+ compatible = "qcom,rpm-smd-regulator";
+ regulator-name = "pm8953_s2_level";
+ qcom,set = <3>;
+ regulator-min-microvolt =
+ <RPM_SMD_REGULATOR_LEVEL_RETENTION>;
+ regulator-max-microvolt =
+ <RPM_SMD_REGULATOR_LEVEL_TURBO>;
+ qcom,use-voltage-level;
+ };
+
+ pm8953_s2_floor_level: regulator-s2-floor-level {
+ compatible = "qcom,rpm-smd-regulator";
+ regulator-name = "pm8953_s2_floor_level";
+ qcom,set = <3>;
+ regulator-min-microvolt =
+ <RPM_SMD_REGULATOR_LEVEL_RETENTION>;
+ regulator-max-microvolt =
+ <RPM_SMD_REGULATOR_LEVEL_TURBO>;
+ qcom,use-voltage-floor-level;
+ qcom,always-send-voltage;
+ };
+
+ pm8953_s2_level_ao: regulator-s2-level-ao {
+ compatible = "qcom,rpm-smd-regulator";
+ regulator-name = "pm8953_s2_level_ao";
+ qcom,set = <1>;
+ regulator-min-microvolt =
+ <RPM_SMD_REGULATOR_LEVEL_RETENTION>;
+ regulator-max-microvolt =
+ <RPM_SMD_REGULATOR_LEVEL_TURBO>;
+ qcom,use-voltage-level;
+ };
+ };
+
+ rpm-regulator-smpa3 {
+ status = "okay";
+ pm8953_s3: regulator-s3 {
+ regulator-min-microvolt = <1225000>;
+ regulator-max-microvolt = <1225000>;
+ qcom,init-voltage = <1225000>;
+ status = "okay";
+ };
+ };
+
+ rpm-regulator-smpa4 {
+ status = "okay";
+ pm8953_s4: regulator-s4 {
+ regulator-min-microvolt = <1900000>;
+ regulator-max-microvolt = <2050000>;
+ qcom,init-voltage = <1900000>;
+ status = "okay";
+ };
+ };
+
+ /* VDD_MX supply */
+ rpm-regulator-smpa7 {
+ status = "okay";
+ pm8953_s7_level: regulator-s7-level {
+ compatible = "qcom,rpm-smd-regulator";
+ regulator-name = "pm8953_s7_level";
+ qcom,set = <3>;
+ regulator-min-microvolt =
+ <RPM_SMD_REGULATOR_LEVEL_RETENTION>;
+ regulator-max-microvolt =
+ <RPM_SMD_REGULATOR_LEVEL_TURBO>;
+ qcom,init-voltage-level =
+ <RPM_SMD_REGULATOR_LEVEL_RETENTION>;
+ qcom,use-voltage-level;
+ qcom,always-send-voltage;
+ };
+
+ pm8953_s7_level_ao: regulator-s7-level-ao {
+ compatible = "qcom,rpm-smd-regulator";
+ regulator-name = "pm8953_s7_level_ao";
+ qcom,set = <1>;
+ regulator-min-microvolt =
+ <RPM_SMD_REGULATOR_LEVEL_RETENTION>;
+ regulator-max-microvolt =
+ <RPM_SMD_REGULATOR_LEVEL_TURBO>;
+ qcom,use-voltage-level;
+ qcom,always-send-voltage;
+ };
+
+ pm8953_s7_level_so: regulator-s7-level-so {
+ compatible = "qcom,rpm-smd-regulator";
+ regulator-name = "pm8953_s7_level_so";
+ qcom,set = <2>;
+ regulator-min-microvolt =
+ <RPM_SMD_REGULATOR_LEVEL_RETENTION>;
+ regulator-max-microvolt =
+ <RPM_SMD_REGULATOR_LEVEL_TURBO>;
+ qcom,init-voltage-level =
+ <RPM_SMD_REGULATOR_LEVEL_RETENTION>;
+ qcom,use-voltage-level;
+ };
+ };
+
+ rpm-regulator-ldoa1 {
+ status = "okay";
+ pm8953_l1: regulator-l1 {
+ regulator-min-microvolt = <1000000>;
+ regulator-max-microvolt = <1100000>;
+ qcom,init-voltage = <1000000>;
+ status = "okay";
+ };
+ };
+
+ rpm-regulator-ldoa2 {
+ status = "okay";
+ pm8953_l2: regulator-l2 {
+ regulator-min-microvolt = <975000>;
+ regulator-max-microvolt = <1225000>;
+ qcom,init-voltage = <975000>;
+ status = "okay";
+ };
+ };
+
+ rpm-regulator-ldoa3 {
+ status = "okay";
+ pm8953_l3: regulator-l3 {
+ regulator-min-microvolt = <925000>;
+ regulator-max-microvolt = <925000>;
+ qcom,init-voltage = <925000>;
+ status = "okay";
+ };
+ };
+
+ rpm-regulator-ldoa5 {
+ status = "okay";
+ pm8953_l5: regulator-l5 {
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ qcom,init-voltage = <1800000>;
+ status = "okay";
+ };
+ };
+
+ rpm-regulator-ldoa6 {
+ status = "okay";
+ pm8953_l6: regulator-l6 {
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ qcom,init-voltage = <1800000>;
+ status = "okay";
+ };
+ };
+
+ rpm-regulator-ldoa7 {
+ status = "okay";
+ pm8953_l7: regulator-l7 {
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1900000>;
+ qcom,init-voltage = <1800000>;
+ status = "okay";
+ };
+
+ pm8953_l7_ao: regulator-l7-ao {
+ compatible = "qcom,rpm-smd-regulator";
+ regulator-name = "pm8953_l7_ao";
+ qcom,set = <1>;
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1900000>;
+ qcom,init-voltage = <1800000>;
+ };
+ };
+
+ rpm-regulator-ldoa8 {
+ status = "okay";
+ pm8953_l8: regulator-l8 {
+ regulator-min-microvolt = <2900000>;
+ regulator-max-microvolt = <2900000>;
+ qcom,init-voltage = <2900000>;
+ status = "okay";
+ };
+ };
+
+ rpm-regulator-ldoa9 {
+ status = "okay";
+ pm8953_l9: regulator-l9 {
+ regulator-min-microvolt = <3000000>;
+ regulator-max-microvolt = <3300000>;
+ qcom,init-voltage = <3000000>;
+ status = "okay";
+ };
+ };
+
+ rpm-regulator-ldoa10 {
+ status = "okay";
+ pm8953_l10: regulator-l10 {
+ regulator-min-microvolt = <2850000>;
+ regulator-max-microvolt = <2850000>;
+ qcom,init-voltage = <2850000>;
+ status = "okay";
+ };
+ };
+
+ rpm-regulator-ldoa11 {
+ status = "okay";
+ pm8953_l11: regulator-l11 {
+ regulator-min-microvolt = <2950000>;
+ regulator-max-microvolt = <2950000>;
+ qcom,init-voltage = <2950000>;
+ status = "okay";
+ };
+ };
+
+ rpm-regulator-ldoa12 {
+ status = "okay";
+ pm8953_l12: regulator-l12 {
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <2950000>;
+ qcom,init-voltage = <1800000>;
+ status = "okay";
+ };
+ };
+
+ rpm-regulator-ldoa13 {
+ status = "okay";
+ pm8953_l13: regulator-l13 {
+ regulator-min-microvolt = <3125000>;
+ regulator-max-microvolt = <3125000>;
+ qcom,init-voltage = <3125000>;
+ status = "okay";
+ };
+ };
+
+ rpm-regulator-ldoa16 {
+ status = "okay";
+ pm8953_l16: regulator-l16 {
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ qcom,init-voltage = <1800000>;
+ status = "okay";
+ };
+ };
+
+ rpm-regulator-ldoa17 {
+ status = "okay";
+ pm8953_l17: regulator-l17 {
+ regulator-min-microvolt = <2850000>;
+ regulator-max-microvolt = <2850000>;
+ qcom,init-voltage = <2850000>;
+ status = "okay";
+ };
+ };
+
+ rpm-regulator-ldoa19 {
+ status = "okay";
+ pm8953_l19: regulator-l19 {
+ regulator-min-microvolt = <1200000>;
+ regulator-max-microvolt = <1350000>;
+ qcom,init-voltage = <1200000>;
+ status = "okay";
+ };
+ };
+
+ rpm-regulator-ldoa22 {
+ status = "okay";
+ pm8953_l22: regulator-l22 {
+ regulator-min-microvolt = <2800000>;
+ regulator-max-microvolt = <2850000>;
+ qcom,init-voltage = <2800000>;
+ status = "okay";
+ };
+ };
+
+ rpm-regulator-ldoa23 {
+ status = "okay";
+ pm8953_l23: regulator-l23 {
+ regulator-min-microvolt = <975000>;
+ regulator-max-microvolt = <1225000>;
+ qcom,init-voltage = <975000>;
+ status = "okay";
+ };
+ };
+};
+
+&spmi_bus {
+ qcom,pm8953@1 {
+ /* PM8953 S5 + S6 = VDD_APC supply */
+ pm8953_s5: spm-regulator@2000 {
+ compatible = "qcom,spm-regulator";
+ reg = <0x2000 0x100>;
+ regulator-name = "pm8953_s5";
+ regulator-min-microvolt = <400000>;
+ regulator-max-microvolt = <1140000>;
+
+ pm8953_s5_limit: avs-limit-regulator {
+ regulator-name = "pm8953_s5_avs_limit";
+ regulator-min-microvolt = <400000>;
+ regulator-max-microvolt = <1140000>;
+ };
+ };
+ };
+};
+
+&soc {
+ apc_mem_acc_vreg: regulator@19461d4 {
+ compatible = "qcom,mem-acc-regulator";
+ reg = <0x019461d4 0x4>, <0x019461d8 0x4>;
+ reg-names = "acc-sel-l1", "acc-sel-l2";
+ regulator-name = "apc_mem_acc_corner";
+ regulator-min-microvolt = <1>;
+ regulator-max-microvolt = <2>;
+
+ qcom,corner-acc-map = <0x1 0x0>;
+ qcom,acc-sel-l1-bit-pos = <0>;
+ qcom,acc-sel-l1-bit-size = <1>;
+ qcom,acc-sel-l2-bit-pos = <0>;
+ qcom,acc-sel-l2-bit-size = <1>;
+ };
+
+ apc_cpr: cpr4-ctrl@b018000 {
+ compatible = "qcom,cpr4-msm8953-apss-regulator";
+ reg = <0xb018000 0x4000>, <0xa4000 0x1000>;
+ reg-names = "cpr_ctrl", "fuse_base";
+ interrupts = <GIC_SPI 15 IRQ_TYPE_EDGE_RISING>;
+ interrupt-names = "cpr";
+
+ qcom,cpr-ctrl-name = "apc";
+
+ qcom,cpr-sensor-time = <1000>;
+ qcom,cpr-loop-time = <5000000>;
+ qcom,cpr-idle-cycles = <15>;
+ qcom,cpr-step-quot-init-min = <12>;
+ qcom,cpr-step-quot-init-max = <14>;
+ qcom,cpr-count-mode = <0>; /* All-at-once */
+ qcom,cpr-count-repeat = <14>;
+ qcom,cpr-down-error-step-limit = <1>;
+ qcom,cpr-up-error-step-limit = <1>;
+
+ qcom,apm-ctrl = <&apc_apm>;
+ qcom,apm-threshold-voltage = <850000>;
+ qcom,apm-hysteresis-voltage = <5000>;
+
+ vdd-supply = <&pm8953_s5>;
+ qcom,voltage-step = <5000>;
+ vdd-limit-supply = <&pm8953_s5_limit>;
+ mem-acc-supply = <&apc_mem_acc_vreg>;
+
+ qcom,cpr-enable;
+ qcom,cpr-hw-closed-loop;
+
+ qcom,cpr-panic-reg-addr-list =
+ <0xb1d2c18 0xb1d2900 0x0b1112b0 0xb018798>;
+ qcom,cpr-panic-reg-name-list =
+ "CCI_SAW4_PMIC_STS", "CCI_SAW4_VCTL",
+ "APCS_ALIAS0_APM_CTLER_STATUS",
+ "APCS0_CPR_CORE_ADJ_MODE_REG";
+
+ qcom,cpr-temp-point-map = <250 650 850>;
+ qcom,cpr-initial-temp-band = <0>;
+
+ /* Turbo (corner 6) ceiling voltage */
+ qcom,cpr-aging-ref-voltage = <990000>;
+
+ thread@0 {
+ qcom,cpr-thread-id = <0>;
+ qcom,cpr-consecutive-up = <0>;
+ qcom,cpr-consecutive-down = <2>;
+ qcom,cpr-up-threshold = <2>;
+ qcom,cpr-down-threshold = <1>;
+
+ apc_vreg: regulator {
+ regulator-name = "apc_corner";
+ regulator-min-microvolt = <1>;
+ regulator-max-microvolt = <9>;
+
+ qcom,cpr-fuse-corners = <4>;
+ qcom,cpr-fuse-combos = <64>;
+ qcom,cpr-speed-bins = <8>;
+ qcom,cpr-speed-bin-corners =
+ <9 0 7 0 0 0 7 9>;
+ qcom,cpr-corners =
+ /* Speed bin 0 */
+ <9 9 9 9 9 9 9 9>,
+
+ /* Speed bin 1 */
+ <0 0 0 0 0 0 0 0>,
+
+ /* Speed bin 2 */
+ <7 7 7 7 7 7 7 7>,
+
+ /* Speed bin 3..5 */
+ <0 0 0 0 0 0 0 0>,
+ <0 0 0 0 0 0 0 0>,
+ <0 0 0 0 0 0 0 0>,
+
+ /* Speed bin 6 */
+ <7 7 7 7 7 7 7 7>,
+
+ /* Speed bin 7 */
+ <9 9 9 9 9 9 9 9>;
+
+ qcom,cpr-corner-fmax-map =
+ /* Speed bin 0 */
+ <1 2 4 9>,
+
+ /* Speed bin 1 */
+ <0 0 0 0>,
+
+ /* Speed bin 2 */
+ <1 2 4 7>,
+
+ /* Speed bin 3..5 */
+ <0 0 0 0>,
+ <0 0 0 0>,
+ <0 0 0 0>,
+
+ /* Speed bin 6 */
+ <1 2 4 7>,
+
+ /* Speed bin 7 */
+ <1 2 4 9>;
+
+ qcom,cpr-voltage-ceiling =
+ /* Speed bin 0 */
+ <715000 790000 860000 865000 920000
+ 990000 1065000 1065000 1065000>,
+
+ /* Speed bin 2 */
+ <715000 790000 860000 865000 920000
+ 990000 1065000>,
+
+ /* Speed bin 6 */
+ <715000 790000 860000 865000 920000
+ 990000 1065000>,
+
+ /* Speed bin 7 */
+ <715000 790000 860000 865000 920000
+ 990000 1065000 1065000 1065000>;
+
+ qcom,cpr-voltage-floor =
+ /* Speed bin 0 */
+ <500000 500000 500000 500000 500000
+ 500000 500000 500000 500000>,
+
+ /* Speed bin 2 */
+ <500000 500000 500000 500000 500000
+ 500000 500000>,
+
+ /* Speed bin 6 */
+ <500000 500000 500000 500000 500000
+ 500000 500000>,
+
+ /* Speed bin 7 */
+ <500000 500000 500000 500000 500000
+ 500000 500000 500000 500000>;
+
+ qcom,cpr-floor-to-ceiling-max-range =
+ /* Speed bin 0; CPR rev 0..7 */
+ < 0 0 0 0 0
+ 0 0 0 0>,
+ <50000 50000 50000 50000 50000
+ 50000 50000 50000 50000>,
+ <50000 50000 50000 50000 50000
+ 50000 50000 50000 50000>,
+ <50000 50000 50000 50000 50000
+ 50000 50000 50000 50000>,
+ <50000 50000 50000 50000 50000
+ 50000 50000 50000 50000>,
+ <50000 50000 50000 50000 50000
+ 50000 50000 50000 50000>,
+ <50000 50000 50000 50000 50000
+ 50000 50000 50000 50000>,
+ <50000 50000 50000 50000 50000
+ 50000 50000 50000 50000>,
+
+ /* Speed bin 2; CPR rev 0..7 */
+ < 0 0 0 0 0
+ 0 0>,
+ <50000 50000 50000 50000 50000
+ 50000 50000>,
+ <50000 50000 50000 50000 50000
+ 50000 50000>,
+ <50000 50000 50000 50000 50000
+ 50000 50000>,
+ <50000 50000 50000 50000 50000
+ 50000 50000>,
+ <50000 50000 50000 50000 50000
+ 50000 50000>,
+ <50000 50000 50000 50000 50000
+ 50000 50000>,
+ <50000 50000 50000 50000 50000
+ 50000 50000>,
+
+ /* Speed bin 6; CPR rev 0..7 */
+ < 0 0 0 0 0
+ 0 0>,
+ <50000 50000 50000 50000 50000
+ 50000 50000>,
+ <50000 50000 50000 50000 50000
+ 50000 50000>,
+ <50000 50000 50000 50000 50000
+ 50000 50000>,
+ <50000 50000 50000 50000 50000
+ 50000 50000>,
+ <50000 50000 50000 50000 50000
+ 50000 50000>,
+ <50000 50000 50000 50000 50000
+ 50000 50000>,
+ <50000 50000 50000 50000 50000
+ 50000 50000>,
+
+ /* Speed bin 7; CPR rev 0..7 */
+ < 0 0 0 0 0
+ 0 0 0 0>,
+ <50000 50000 50000 50000 50000
+ 50000 50000 50000 50000>,
+ <50000 50000 50000 50000 50000
+ 50000 50000 50000 50000>,
+ <50000 50000 50000 50000 50000
+ 50000 50000 50000 50000>,
+ <50000 50000 50000 50000 50000
+ 50000 50000 50000 50000>,
+ <50000 50000 50000 50000 50000
+ 50000 50000 50000 50000>,
+ <50000 50000 50000 50000 50000
+ 50000 50000 50000 50000>,
+ <50000 50000 50000 50000 50000
+ 50000 50000 50000 50000>;
+
+ qcom,cpr-misc-fuse-voltage-adjustment =
+ /* Speed bin 0; misc fuse 0..1 */
+ < 0 0 0 0 0
+ 0 0 0 0>,
+ < 0 0 30000 0 0
+ 0 0 0 0>,
+
+ /* Speed bin 2; misc fuse 0..1 */
+ < 0 0 0 0 0
+ 0 0>,
+ < 0 0 30000 0 0
+ 0 0>,
+
+ /* Speed bin 6; misc fuse 0..1 */
+ < 0 0 0 0 0
+ 0 0>,
+ < 0 0 30000 0 0
+ 0 0>,
+
+ /* Speed bin 7; misc fuse 0..1 */
+ < 0 0 0 0 0
+ 0 0 0 0>,
+ < 0 0 30000 0 0
+ 0 0 0 0>;
+
+ qcom,mem-acc-voltage =
+ /* Speed bin 0 */
+ <1 1 2 2 2 2 2 2 2>,
+
+ /* Speed bin 2 */
+ <1 1 2 2 2 2 2>,
+
+ /* Speed bin 6 */
+ <1 1 2 2 2 2 2>,
+
+ /* Speed bin 7 */
+ <1 1 2 2 2 2 2 2 2>;
+
+ qcom,corner-frequencies =
+ /* Speed bin 0 */
+ <652800000 1036800000 1401600000
+ 1689600000 1804800000 1958400000
+ 2016000000 2150400000 2208000000>,
+
+ /* Speed bin 2 */
+ <652800000 1036800000 1401600000
+ 1689600000 1804800000 1958400000
+ 2016000000>,
+
+ /* Speed bin 6 */
+ <652800000 1036800000 1401600000
+ 1689600000 1804800000 1958400000
+ 2016000000>,
+
+ /* Speed bin 7 */
+ <652800000 1036800000 1401600000
+ 1689600000 1804800000 1958400000
+ 2016000000 2150400000 2208000000>;
+
+ qcom,cpr-open-loop-voltage-fuse-adjustment =
+ /* Speed bin 0; CPR rev 0..7 */
+ < 0 0 0 0>,
+ < 25000 0 5000 40000>,
+ < 25000 0 5000 40000>,
+ < 25000 0 5000 40000>,
+ < 0 0 0 0>,
+ < 0 0 0 0>,
+ < 0 0 0 0>,
+ < 0 0 0 0>,
+
+ /* Speed bin 1; CPR rev 0..7 */
+ < 0 0 0 0>,
+ < 0 0 0 0>,
+ < 0 0 0 0>,
+ < 0 0 0 0>,
+ < 0 0 0 0>,
+ < 0 0 0 0>,
+ < 0 0 0 0>,
+ < 0 0 0 0>,
+
+ /* Speed bin 2; CPR rev 0..7 */
+ < 0 0 0 0>,
+ < 25000 0 5000 40000>,
+ < 25000 0 5000 40000>,
+ < 25000 0 5000 40000>,
+ < 0 0 0 0>,
+ < 0 0 0 0>,
+ < 0 0 0 0>,
+ < 0 0 0 0>,
+
+ /* Speed bin 3; CPR rev 0..7 */
+ < 0 0 0 0>,
+ < 0 0 0 0>,
+ < 0 0 0 0>,
+ < 0 0 0 0>,
+ < 0 0 0 0>,
+ < 0 0 0 0>,
+ < 0 0 0 0>,
+ < 0 0 0 0>,
+
+ /* Speed bin 4; CPR rev 0..7 */
+ < 0 0 0 0>,
+ < 0 0 0 0>,
+ < 0 0 0 0>,
+ < 0 0 0 0>,
+ < 0 0 0 0>,
+ < 0 0 0 0>,
+ < 0 0 0 0>,
+ < 0 0 0 0>,
+
+ /* Speed bin 5; CPR rev 0..7 */
+ < 0 0 0 0>,
+ < 0 0 0 0>,
+ < 0 0 0 0>,
+ < 0 0 0 0>,
+ < 0 0 0 0>,
+ < 0 0 0 0>,
+ < 0 0 0 0>,
+ < 0 0 0 0>,
+
+ /* Speed bin 6; CPR rev 0..7 */
+ < 0 0 0 0>,
+ < 25000 0 5000 40000>,
+ < 25000 0 5000 40000>,
+ < 25000 0 5000 40000>,
+ < 0 0 0 0>,
+ < 0 0 0 0>,
+ < 0 0 0 0>,
+ < 0 0 0 0>,
+
+ /* Speed bin 7; CPR rev 0..7 */
+ < 0 0 0 0>,
+ < 25000 0 5000 40000>,
+ < 25000 0 5000 40000>,
+ < 25000 0 5000 40000>,
+ < 0 0 0 0>,
+ < 0 0 0 0>,
+ < 0 0 0 0>,
+ < 0 0 0 0>;
+
+ qcom,cpr-closed-loop-voltage-fuse-adjustment =
+ /* Speed bin 0; CPR rev 0..7 */
+ < 0 0 0 0>,
+ < 10000 (-15000) 0 25000>,
+ < 10000 (-15000) 0 25000>,
+ <(-5000) (-30000) (-15000) 10000>,
+ < 0 0 0 0>,
+ < 0 0 0 0>,
+ < 0 0 0 0>,
+ < 0 0 0 0>,
+
+ /* Speed bin 1; CPR rev 0..7 */
+ < 0 0 0 0>,
+ < 0 0 0 0>,
+ < 0 0 0 0>,
+ < 0 0 0 0>,
+ < 0 0 0 0>,
+ < 0 0 0 0>,
+ < 0 0 0 0>,
+ < 0 0 0 0>,
+
+ /* Speed bin 2; CPR rev 0..7 */
+ < 0 0 0 0>,
+ < 10000 (-15000) 0 25000>,
+ < 10000 (-15000) 0 25000>,
+ <(-5000) (-30000) (-15000) 10000>,
+ < 0 0 0 0>,
+ < 0 0 0 0>,
+ < 0 0 0 0>,
+ < 0 0 0 0>,
+
+ /* Speed bin 3; CPR rev 0..7 */
+ < 0 0 0 0>,
+ < 0 0 0 0>,
+ < 0 0 0 0>,
+ < 0 0 0 0>,
+ < 0 0 0 0>,
+ < 0 0 0 0>,
+ < 0 0 0 0>,
+ < 0 0 0 0>,
+
+ /* Speed bin 4; CPR rev 0..7 */
+ < 0 0 0 0>,
+ < 0 0 0 0>,
+ < 0 0 0 0>,
+ < 0 0 0 0>,
+ < 0 0 0 0>,
+ < 0 0 0 0>,
+ < 0 0 0 0>,
+ < 0 0 0 0>,
+
+ /* Speed bin 5; CPR rev 0..7 */
+ < 0 0 0 0>,
+ < 0 0 0 0>,
+ < 0 0 0 0>,
+ < 0 0 0 0>,
+ < 0 0 0 0>,
+ < 0 0 0 0>,
+ < 0 0 0 0>,
+ < 0 0 0 0>,
+
+ /* Speed bin 6; CPR rev 0..7 */
+ < 0 0 0 0>,
+ < 10000 (-15000) 0 25000>,
+ < 10000 (-15000) 0 25000>,
+ <(-5000) (-30000) (-15000) 10000>,
+ < 0 0 0 0>,
+ < 0 0 0 0>,
+ < 0 0 0 0>,
+ < 0 0 0 0>,
+
+ /* Speed bin 7; CPR rev 0..7 */
+ < 0 0 0 0>,
+ < 10000 (-15000) 0 25000>,
+ < 10000 (-15000) 0 25000>,
+ <(-5000) (-30000) (-15000) 10000>,
+ < 0 0 0 0>,
+ < 0 0 0 0>,
+ < 0 0 0 0>,
+ < 0 0 0 0>;
+
+ qcom,cpr-ro-scaling-factor =
+ <3610 3790 0 2200 2450 2310 2170 2210
+ 2330 2210 2470 2340 780 2700 2450 2090>,
+ <3610 3790 0 2200 2450 2310 2170 2210
+ 2330 2210 2470 2340 780 2700 2450 2090>,
+ <3610 3790 0 2200 2450 2310 2170 2210
+ 2330 2210 2470 2340 780 2700 2450 2090>,
+ <3610 3790 0 2200 2450 2310 2170 2210
+ 2330 2210 2470 2340 780 2700 2450 2090>;
+
+ qcom,allow-voltage-interpolation;
+ qcom,allow-quotient-interpolation;
+ qcom,cpr-scaled-open-loop-voltage-as-ceiling;
+
+ qcom,corner-allow-temp-adjustment =
+ /* Speed bin 0; CPR rev 0..7 */
+ <0 0 0 0 0 0 0 0 0>,
+ <0 0 0 0 0 0 0 0 0>,
+ <0 0 0 0 0 0 0 0 0>,
+ <1 1 1 1 0 0 0 0 0>,
+ <1 1 1 1 0 0 0 0 0>,
+ <1 1 1 1 0 0 0 0 0>,
+ <1 1 1 1 0 0 0 0 0>,
+ <1 1 1 1 0 0 0 0 0>,
+
+ /* Speed bin 2; CPR rev 0..7 */
+ <0 0 0 0 0 0 0>,
+ <0 0 0 0 0 0 0>,
+ <0 0 0 0 0 0 0>,
+ <1 1 1 1 0 0 0>,
+ <1 1 1 1 0 0 0>,
+ <1 1 1 1 0 0 0>,
+ <1 1 1 1 0 0 0>,
+ <1 1 1 1 0 0 0>,
+
+ /* Speed bin 6; CPR rev 0..7 */
+ <0 0 0 0 0 0 0>,
+ <0 0 0 0 0 0 0>,
+ <0 0 0 0 0 0 0>,
+ <1 1 1 1 0 0 0>,
+ <1 1 1 1 0 0 0>,
+ <1 1 1 1 0 0 0>,
+ <1 1 1 1 0 0 0>,
+ <1 1 1 1 0 0 0>,
+
+ /* Speed bin 7; CPR rev 0..7 */
+ <0 0 0 0 0 0 0 0 0>,
+ <0 0 0 0 0 0 0 0 0>,
+ <0 0 0 0 0 0 0 0 0>,
+ <1 1 1 1 0 0 0 0 0>,
+ <1 1 1 1 0 0 0 0 0>,
+ <1 1 1 1 0 0 0 0 0>,
+ <1 1 1 1 0 0 0 0 0>,
+ <1 1 1 1 0 0 0 0 0>;
+
+ qcom,cpr-corner1-temp-core-voltage-adjustment =
+ <(0) (-5000) (-15000) (-20000)>;
+
+ qcom,cpr-corner2-temp-core-voltage-adjustment =
+ <(0) (-5000) (-15000) (-15000)>;
+
+ qcom,cpr-corner3-temp-core-voltage-adjustment =
+ <(0) (-5000) (-15000) (0)>;
+
+ qcom,cpr-corner4-temp-core-voltage-adjustment =
+ <(0) (-5000) (-15000) (0)>;
+
+ qcom,cpr-aging-max-voltage-adjustment = <15000>;
+ qcom,cpr-aging-ref-corner = <6>; /* Turbo */
+ qcom,cpr-aging-ro-scaling-factor = <2800>;
+ qcom,allow-aging-voltage-adjustment =
+ /* Speed bin 0 */
+ <0 0 0 1 1 1 1 1>,
+
+ /* Speed bin 1 */
+ <0 0 0 0 0 0 0 0>,
+
+ /* Speed bin 2 */
+ <0 0 0 1 1 1 1 1>,
+
+ /* Speed bin 3..5 */
+ <0 0 0 0 0 0 0 0>,
+ <0 0 0 0 0 0 0 0>,
+ <0 0 0 0 0 0 0 0>,
+
+ /* Speed bin 6 */
+ <0 0 0 1 1 1 1 1>,
+
+ /* Speed bin 7 */
+ <0 0 0 1 1 1 1 1>;
+ };
+ };
+ };
+
+ gfx_mem_acc: regulator@194415c {
+ compatible = "qcom,mem-acc-regulator";
+ reg = <0x0194415c 0x4>;
+ reg-names = "acc-sel-l1";
+ regulator-name = "gfx_mem_acc_corner";
+ regulator-min-microvolt = <1>;
+ regulator-max-microvolt = <2>;
+
+ qcom,acc-sel-l1-bit-pos = <0>;
+ qcom,acc-sel-l1-bit-size = <1>;
+ qcom,corner-acc-map = <0x1 0x0>;
+ };
+
+ gfx_vreg_corner: ldo@185f000 {
+ compatible = "qcom,msm8953-gfx-ldo";
+ reg = <0x0185f000 0x30>, <0xa4000 0x1000>;
+ reg-names = "ldo_addr", "efuse_addr";
+
+ regulator-name = "msm_gfx_ldo";
+ regulator-min-microvolt = <1>;
+ regulator-max-microvolt = <7>;
+
+ qcom,ldo-voltage-ceiling = <620000 680000 750000>;
+ qcom,ldo-voltage-floor = <510000 510000 600000>;
+
+ qcom,num-corners = <7>;
+ qcom,num-ldo-corners = <3>;
+ qcom,ldo-enable-corner-map = <1 1 1 0 0 0 0>;
+ qcom,init-corner = <4>;
+
+ vdd-cx-supply = <&pm8953_s2_level>;
+ qcom,vdd-cx-corner-map = <RPM_SMD_REGULATOR_LEVEL_LOW_SVS>,
+ <RPM_SMD_REGULATOR_LEVEL_LOW_SVS>,
+ <RPM_SMD_REGULATOR_LEVEL_SVS>,
+ <RPM_SMD_REGULATOR_LEVEL_SVS_PLUS>,
+ <RPM_SMD_REGULATOR_LEVEL_NOM>,
+ <RPM_SMD_REGULATOR_LEVEL_NOM_PLUS>,
+ <RPM_SMD_REGULATOR_LEVEL_TURBO>;
+
+ mem-acc-supply = <&gfx_mem_acc>;
+ qcom,mem-acc-corner-map = <1 1 1 2 2 2 2>;
+ qcom,ldo-init-voltage-adjustment = <35000 25000 0>;
+ };
+
+ eldo2_8953: eldo2 {
+ compatible = "regulator-fixed";
+ regulator-name = "eldo2_8953";
+ startup-delay-us = <0>;
+ enable-active-high;
+ gpio = <&tlmm 50 0>;
+ regulator-always-on;
+ };
+
+ adv_vreg: adv_vreg {
+ compatible = "regulator-fixed";
+ regulator-name = "adv_vreg";
+ startup-delay-us = <400>;
+ enable-active-high;
+ gpio = <&pm8953_gpios 5 0>;
+ };
+};
diff --git a/arch/arm64/boot/dts/qcom/msm8953.dtsi b/arch/arm64/boot/dts/qcom/msm8953.dtsi
index 12b39a9..0a2b814 100644
--- a/arch/arm64/boot/dts/qcom/msm8953.dtsi
+++ b/arch/arm64/boot/dts/qcom/msm8953.dtsi
@@ -13,7 +13,9 @@
#include "skeleton64.dtsi"
#include <dt-bindings/gpio/gpio.h>
+#include <dt-bindings/spmi/spmi.h>
#include <dt-bindings/interrupt-controller/arm-gic.h>
+#include <dt-bindings/regulator/qcom,rpm-smd-regulator.h>
/ {
model = "Qualcomm Technologies, Inc. MSM 8953";
@@ -255,6 +257,229 @@
qcom,pipe-attr-ee;
};
+ thermal_zones: thermal-zones {
+ mdm-core-usr {
+ polling-delay-passive = <0>;
+ polling-delay = <0>;
+ thermal-governor = "user_space";
+ thermal-sensors = <&tsens0 1>;
+ trips {
+ active-config0 {
+ temperature = <125000>;
+ hysteresis = <1000>;
+ type = "passive";
+ };
+ };
+ };
+
+ qdsp-usr {
+ polling-delay-passive = <0>;
+ polling-delay = <0>;
+ thermal-governor = "user_space";
+ thermal-sensors = <&tsens0 2>;
+ trips {
+ active-config0 {
+ temperature = <125000>;
+ hysteresis = <1000>;
+ type = "passive";
+ };
+ };
+ };
+
+ camera-usr {
+ polling-delay-passive = <0>;
+ polling-delay = <0>;
+ thermal-governor = "user_space";
+ thermal-sensors = <&tsens0 3>;
+ trips {
+ active-config0 {
+ temperature = <125000>;
+ hysteresis = <1000>;
+ type = "passive";
+ };
+ };
+ };
+
+ apc1_cpu0-usr {
+ polling-delay-passive = <0>;
+ polling-delay = <0>;
+ thermal-sensors = <&tsens0 4>;
+ thermal-governor = "user_space";
+ trips {
+ active-config0 {
+ temperature = <125000>;
+ hysteresis = <1000>;
+ type = "passive";
+ };
+ };
+ };
+
+ apc1_cpu1-usr {
+ polling-delay-passive = <0>;
+ polling-delay = <0>;
+ thermal-sensors = <&tsens0 5>;
+ thermal-governor = "user_space";
+ trips {
+ active-config0 {
+ temperature = <125000>;
+ hysteresis = <1000>;
+ type = "passive";
+ };
+ };
+ };
+
+ apc1_cpu2-usr {
+ polling-delay-passive = <0>;
+ polling-delay = <0>;
+ thermal-sensors = <&tsens0 6>;
+ thermal-governor = "user_space";
+ trips {
+ active-config0 {
+ temperature = <125000>;
+ hysteresis = <1000>;
+ type = "passive";
+ };
+ };
+ };
+
+ apc1_cpu3-usr {
+ polling-delay-passive = <0>;
+ polling-delay = <0>;
+ thermal-sensors = <&tsens0 7>;
+ thermal-governor = "user_space";
+ trips {
+ active-config0 {
+ temperature = <125000>;
+ hysteresis = <1000>;
+ type = "passive";
+ };
+ };
+ };
+
+ apc1_l2-usr {
+ polling-delay-passive = <0>;
+ polling-delay = <0>;
+ thermal-sensors = <&tsens0 8>;
+ thermal-governor = "user_space";
+ trips {
+ active-config0 {
+ temperature = <125000>;
+ hysteresis = <1000>;
+ type = "passive";
+ };
+ };
+ };
+
+ apc0_cpu0-usr {
+ polling-delay-passive = <0>;
+ polling-delay = <0>;
+ thermal-sensors = <&tsens0 9>;
+ thermal-governor = "user_space";
+ trips {
+ active-config0 {
+ temperature = <125000>;
+ hysteresis = <1000>;
+ type = "passive";
+ };
+ };
+ };
+
+ apc0_cpu1-usr {
+ polling-delay-passive = <0>;
+ polling-delay = <0>;
+ thermal-sensors = <&tsens0 10>;
+ thermal-governor = "user_space";
+ trips {
+ active-config0 {
+ temperature = <125000>;
+ hysteresis = <1000>;
+ type = "passive";
+ };
+ };
+ };
+
+ apc0_cpu2-usr {
+ polling-delay-passive = <0>;
+ polling-delay = <0>;
+ thermal-sensors = <&tsens0 11>;
+ thermal-governor = "user_space";
+ trips {
+ active-config0 {
+ temperature = <125000>;
+ hysteresis = <1000>;
+ type = "passive";
+ };
+ };
+ };
+
+ apc0_cpu3-usr {
+ polling-delay-passive = <0>;
+ polling-delay = <0>;
+ thermal-sensors = <&tsens0 12>;
+ thermal-governor = "user_space";
+ trips {
+ active-config0 {
+ temperature = <125000>;
+ hysteresis = <1000>;
+ type = "passive";
+ };
+ };
+ };
+
+ apc0_l2-usr {
+ polling-delay-passive = <0>;
+ polling-delay = <0>;
+ thermal-sensors = <&tsens0 13>;
+ thermal-governor = "user_space";
+ trips {
+ active-config0 {
+ temperature = <125000>;
+ hysteresis = <1000>;
+ type = "passive";
+ };
+ };
+ };
+
+ gpu0-usr {
+ polling-delay-passive = <0>;
+ polling-delay = <0>;
+ thermal-sensors = <&tsens0 14>;
+ thermal-governor = "user_space";
+ trips {
+ active-config0 {
+ temperature = <125000>;
+ hysteresis = <1000>;
+ type = "passive";
+ };
+ };
+ };
+
+ gpu1-usr {
+ polling-delay-passive = <0>;
+ polling-delay = <0>;
+ thermal-sensors = <&tsens0 15>;
+ thermal-governor = "user_space";
+ trips {
+ active-config0 {
+ temperature = <125000>;
+ hysteresis = <1000>;
+ type = "passive";
+ };
+ };
+ };
+ };
+
+ tsens0: tsens@4a8000 {
+ compatible = "qcom,msm8953-tsens";
+ reg = <0x4a8000 0x1000>,
+ <0x4a9000 0x1000>;
+ reg-names = "tsens_srot_physical",
+ "tsens_tm_physical";
+ interrupts = <0 184 0>, <0 314 0>;
+ interrupt-names = "tsens-upper-lower", "tsens-critical";
+ #thermal-sensor-cells = <1>;
+ };
+
blsp1_uart0: serial@78af000 {
compatible = "qcom,msm-uartdm-v1.4", "qcom,msm-uartdm";
reg = <0x78af000 0x200>;
@@ -617,7 +842,12 @@
reg = <0x6b0 32>;
};
- pil@94c {
+ kaslr_offset@6d0 {
+ compatible = "qcom,msm-imem-kaslr_offset";
+ reg = <0x6d0 12>;
+ };
+
+ pil@94c {
compatible = "qcom,msm-imem-pil";
reg = <0x94c 200>;
@@ -764,3 +994,7 @@
cell-index = <0>;
};
};
+
+#include "pm8953-rpm-regulator.dtsi"
+#include "pm8953.dtsi"
+#include "msm8953-regulator.dtsi"
diff --git a/arch/arm64/boot/dts/qcom/pm8953-rpm-regulator.dtsi b/arch/arm64/boot/dts/qcom/pm8953-rpm-regulator.dtsi
new file mode 100644
index 0000000..1e594c6
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/pm8953-rpm-regulator.dtsi
@@ -0,0 +1,382 @@
+/*
+ * Copyright (c) 2015-2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+&rpm_bus {
+ rpm-regulator-smpa1 {
+ compatible = "qcom,rpm-smd-regulator-resource";
+ qcom,resource-name = "smpa";
+ qcom,resource-id = <1>;
+ qcom,regulator-type = <1>;
+ qcom,hpm-min-load = <100000>;
+ status = "disabled";
+
+ regulator-s1 {
+ compatible = "qcom,rpm-smd-regulator";
+ regulator-name = "pm8953_s1";
+ qcom,set = <3>;
+ status = "disabled";
+ };
+ };
+
+ rpm-regulator-smpa2 {
+ compatible = "qcom,rpm-smd-regulator-resource";
+ qcom,resource-name = "smpa";
+ qcom,resource-id = <2>;
+ qcom,regulator-type = <1>;
+ qcom,hpm-min-load = <100000>;
+ status = "disabled";
+
+ regulator-s2 {
+ compatible = "qcom,rpm-smd-regulator";
+ regulator-name = "pm8953_s2";
+ qcom,set = <3>;
+ status = "disabled";
+ };
+ };
+
+ rpm-regulator-smpa3 {
+ compatible = "qcom,rpm-smd-regulator-resource";
+ qcom,resource-name = "smpa";
+ qcom,resource-id = <3>;
+ qcom,regulator-type = <1>;
+ qcom,hpm-min-load = <100000>;
+ status = "disabled";
+
+ regulator-s3 {
+ compatible = "qcom,rpm-smd-regulator";
+ regulator-name = "pm8953_s3";
+ qcom,set = <3>;
+ status = "disabled";
+ };
+ };
+
+ rpm-regulator-smpa4 {
+ compatible = "qcom,rpm-smd-regulator-resource";
+ qcom,resource-name = "smpa";
+ qcom,resource-id = <4>;
+ qcom,regulator-type = <1>;
+ qcom,hpm-min-load = <100000>;
+ status = "disabled";
+
+ regulator-s4 {
+ compatible = "qcom,rpm-smd-regulator";
+ regulator-name = "pm8953_s4";
+ qcom,set = <3>;
+ status = "disabled";
+ };
+ };
+
+ rpm-regulator-smpa7 {
+ compatible = "qcom,rpm-smd-regulator-resource";
+ qcom,resource-name = "smpa";
+ qcom,resource-id = <7>;
+ qcom,regulator-type = <1>;
+ qcom,hpm-min-load = <100000>;
+ status = "disabled";
+
+ regulator-s7 {
+ compatible = "qcom,rpm-smd-regulator";
+ regulator-name = "pm8953_s7";
+ qcom,set = <3>;
+ status = "disabled";
+ };
+ };
+
+ rpm-regulator-ldoa1 {
+ compatible = "qcom,rpm-smd-regulator-resource";
+ qcom,resource-name = "ldoa";
+ qcom,resource-id = <1>;
+ qcom,regulator-type = <0>;
+ qcom,hpm-min-load = <10000>;
+ status = "disabled";
+
+ regulator-l1 {
+ compatible = "qcom,rpm-smd-regulator";
+ regulator-name = "pm8953_l1";
+ qcom,set = <3>;
+ status = "disabled";
+ };
+ };
+
+ rpm-regulator-ldoa2 {
+ compatible = "qcom,rpm-smd-regulator-resource";
+ qcom,resource-name = "ldoa";
+ qcom,resource-id = <2>;
+ qcom,regulator-type = <0>;
+ qcom,hpm-min-load = <10000>;
+ status = "disabled";
+
+ regulator-l2 {
+ compatible = "qcom,rpm-smd-regulator";
+ regulator-name = "pm8953_l2";
+ qcom,set = <3>;
+ status = "disabled";
+ };
+ };
+
+ rpm-regulator-ldoa3 {
+ compatible = "qcom,rpm-smd-regulator-resource";
+ qcom,resource-name = "ldoa";
+ qcom,resource-id = <3>;
+ qcom,regulator-type = <0>;
+ qcom,hpm-min-load = <10000>;
+ status = "disabled";
+
+ regulator-l3 {
+ compatible = "qcom,rpm-smd-regulator";
+ regulator-name = "pm8953_l3";
+ qcom,set = <3>;
+ status = "disabled";
+ };
+ };
+
+ rpm-regulator-ldoa5 {
+ compatible = "qcom,rpm-smd-regulator-resource";
+ qcom,resource-name = "ldoa";
+ qcom,resource-id = <5>;
+ qcom,regulator-type = <0>;
+ qcom,hpm-min-load = <10000>;
+ status = "disabled";
+
+ regulator-l5 {
+ compatible = "qcom,rpm-smd-regulator";
+ regulator-name = "pm8953_l5";
+ qcom,set = <3>;
+ status = "disabled";
+ };
+ };
+
+ rpm-regulator-ldoa6 {
+ compatible = "qcom,rpm-smd-regulator-resource";
+ qcom,resource-name = "ldoa";
+ qcom,resource-id = <6>;
+ qcom,regulator-type = <0>;
+ qcom,hpm-min-load = <10000>;
+ status = "disabled";
+
+ regulator-l6 {
+ compatible = "qcom,rpm-smd-regulator";
+ regulator-name = "pm8953_l6";
+ qcom,set = <3>;
+ status = "disabled";
+ };
+ };
+
+ rpm-regulator-ldoa7 {
+ compatible = "qcom,rpm-smd-regulator-resource";
+ qcom,resource-name = "ldoa";
+ qcom,resource-id = <7>;
+ qcom,regulator-type = <0>;
+ qcom,hpm-min-load = <10000>;
+ status = "disabled";
+
+ regulator-l7 {
+ compatible = "qcom,rpm-smd-regulator";
+ regulator-name = "pm8953_l7";
+ qcom,set = <3>;
+ status = "disabled";
+ };
+ };
+
+ rpm-regulator-ldoa8 {
+ compatible = "qcom,rpm-smd-regulator-resource";
+ qcom,resource-name = "ldoa";
+ qcom,resource-id = <8>;
+ qcom,regulator-type = <0>;
+ qcom,hpm-min-load = <10000>;
+ status = "disabled";
+
+ regulator-l8 {
+ compatible = "qcom,rpm-smd-regulator";
+ regulator-name = "pm8953_l8";
+ qcom,set = <3>;
+ status = "disabled";
+ };
+ };
+
+ rpm-regulator-ldoa9 {
+ compatible = "qcom,rpm-smd-regulator-resource";
+ qcom,resource-name = "ldoa";
+ qcom,resource-id = <9>;
+ qcom,regulator-type = <0>;
+ qcom,hpm-min-load = <10000>;
+ status = "disabled";
+
+ regulator-l9 {
+ compatible = "qcom,rpm-smd-regulator";
+ regulator-name = "pm8953_l9";
+ qcom,set = <3>;
+ status = "disabled";
+ };
+ };
+
+ rpm-regulator-ldoa10 {
+ compatible = "qcom,rpm-smd-regulator-resource";
+ qcom,resource-name = "ldoa";
+ qcom,resource-id = <10>;
+ qcom,regulator-type = <0>;
+ qcom,hpm-min-load = <10000>;
+ status = "disabled";
+
+ regulator-l10 {
+ compatible = "qcom,rpm-smd-regulator";
+ regulator-name = "pm8953_l10";
+ qcom,set = <3>;
+ status = "disabled";
+ };
+ };
+
+ rpm-regulator-ldoa11 {
+ compatible = "qcom,rpm-smd-regulator-resource";
+ qcom,resource-name = "ldoa";
+ qcom,resource-id = <11>;
+ qcom,regulator-type = <0>;
+ qcom,hpm-min-load = <10000>;
+ status = "disabled";
+
+ regulator-l11 {
+ compatible = "qcom,rpm-smd-regulator";
+ regulator-name = "pm8953_l11";
+ qcom,set = <3>;
+ status = "disabled";
+ };
+ };
+
+ rpm-regulator-ldoa12 {
+ compatible = "qcom,rpm-smd-regulator-resource";
+ qcom,resource-name = "ldoa";
+ qcom,resource-id = <12>;
+ qcom,regulator-type = <0>;
+ qcom,hpm-min-load = <10000>;
+ status = "disabled";
+
+ regulator-l12 {
+ compatible = "qcom,rpm-smd-regulator";
+ regulator-name = "pm8953_l12";
+ qcom,set = <3>;
+ status = "disabled";
+ };
+ };
+
+ rpm-regulator-ldoa13 {
+ compatible = "qcom,rpm-smd-regulator-resource";
+ qcom,resource-name = "ldoa";
+ qcom,resource-id = <13>;
+ qcom,regulator-type = <0>;
+ qcom,hpm-min-load = <5000>;
+ status = "disabled";
+
+ regulator-l13 {
+ compatible = "qcom,rpm-smd-regulator";
+ regulator-name = "pm8953_l13";
+ qcom,set = <3>;
+ status = "disabled";
+ };
+ };
+
+ rpm-regulator-ldoa16 {
+ compatible = "qcom,rpm-smd-regulator-resource";
+ qcom,resource-name = "ldoa";
+ qcom,resource-id = <16>;
+ qcom,regulator-type = <0>;
+ qcom,hpm-min-load = <5000>;
+ status = "disabled";
+
+ regulator-l16 {
+ compatible = "qcom,rpm-smd-regulator";
+ regulator-name = "pm8953_l16";
+ qcom,set = <3>;
+ status = "disabled";
+ };
+ };
+
+ rpm-regulator-ldoa17 {
+ compatible = "qcom,rpm-smd-regulator-resource";
+ qcom,resource-name = "ldoa";
+ qcom,resource-id = <17>;
+ qcom,regulator-type = <0>;
+ qcom,hpm-min-load = <10000>;
+ status = "disabled";
+
+ regulator-l17 {
+ compatible = "qcom,rpm-smd-regulator";
+ regulator-name = "pm8953_l17";
+ qcom,set = <3>;
+ status = "disabled";
+ };
+ };
+
+ rpm-regulator-ldoa19 {
+ compatible = "qcom,rpm-smd-regulator-resource";
+ qcom,resource-name = "ldoa";
+ qcom,resource-id = <19>;
+ qcom,regulator-type = <0>;
+ qcom,hpm-min-load = <10000>;
+ status = "disabled";
+
+ regulator-l19 {
+ compatible = "qcom,rpm-smd-regulator";
+ regulator-name = "pm8953_l19";
+ qcom,set = <3>;
+ status = "disabled";
+ };
+ };
+
+ rpm-regulator-ldoa22 {
+ compatible = "qcom,rpm-smd-regulator-resource";
+ qcom,resource-name = "ldoa";
+ qcom,resource-id = <22>;
+ qcom,regulator-type = <0>;
+ qcom,hpm-min-load = <10000>;
+ status = "disabled";
+
+ regulator-l22 {
+ compatible = "qcom,rpm-smd-regulator";
+ regulator-name = "pm8953_l22";
+ qcom,set = <3>;
+ status = "disabled";
+ };
+ };
+
+ rpm-regulator-ldoa23 {
+ compatible = "qcom,rpm-smd-regulator-resource";
+ qcom,resource-name = "ldoa";
+ qcom,resource-id = <23>;
+ qcom,regulator-type = <0>;
+ qcom,hpm-min-load = <10000>;
+ status = "disabled";
+
+ regulator-l23 {
+ compatible = "qcom,rpm-smd-regulator";
+ regulator-name = "pm8953_l23";
+ qcom,set = <3>;
+ status = "disabled";
+ };
+ };
+
+ /* Regulator to notify APC corner to RPM */
+ rpm-regulator-clk0 {
+ compatible = "qcom,rpm-smd-regulator-resource";
+ qcom,resource-name = "clk0";
+ qcom,resource-id = <3>;
+ qcom,regulator-type = <1>;
+ status = "disabled";
+
+ regulator-clk0 {
+ compatible = "qcom,rpm-smd-regulator";
+ regulator-name = "rpm_apc";
+ qcom,set = <3>;
+ status = "disabled";
+ };
+ };
+};
diff --git a/arch/arm64/boot/dts/qcom/pm8953.dtsi b/arch/arm64/boot/dts/qcom/pm8953.dtsi
new file mode 100644
index 0000000..0ddb9f5
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/pm8953.dtsi
@@ -0,0 +1,375 @@
+/*
+ * Copyright (c) 2015-2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+&spmi_bus {
+
+ qcom,pm8953@0 {
+ compatible = "qcom,spmi-pmic";
+ reg = <0x0 SPMI_USID>;
+ #address-cells = <1>;
+ #size-cells = <1>;
+
+ pm8953_revid: qcom,revid@100 {
+ compatible = "qcom,qpnp-revid";
+ reg = <0x100 0x100>;
+ };
+
+ qcom,power-on@800 {
+ compatible = "qcom,qpnp-power-on";
+ reg = <0x800 0x100>;
+ interrupts = <0x0 0x8 0x0 IRQ_TYPE_NONE>,
+ <0x0 0x8 0x1 IRQ_TYPE_NONE>,
+ <0x0 0x8 0x4 IRQ_TYPE_NONE>,
+ <0x0 0x8 0x5 IRQ_TYPE_NONE>;
+ interrupt-names = "kpdpwr", "resin",
+ "resin-bark", "kpdpwr-resin-bark";
+ qcom,pon-dbc-delay = <15625>;
+ qcom,system-reset;
+
+ qcom,pon_1 {
+ qcom,pon-type = <0>;
+ qcom,pull-up = <1>;
+ linux,code = <116>;
+ };
+
+ qcom,pon_2 {
+ qcom,pon-type = <1>;
+ qcom,pull-up = <1>;
+ linux,code = <114>;
+ };
+ };
+
+ pm8953_temp_alarm: qcom,temp-alarm@2400 {
+ compatible = "qcom,qpnp-temp-alarm";
+ reg = <0x2400 0x100>;
+ interrupts = <0x0 0x24 0x0 IRQ_TYPE_EDGE_RISING>;
+ label = "pm8953_tz";
+ qcom,channel-num = <8>;
+ qcom,threshold-set = <0>;
+ qcom,temp_alarm-vadc = <&pm8953_vadc>;
+ };
+
+ pm8953_coincell: qcom,coincell@2800 {
+ compatible = "qcom,qpnp-coincell";
+ reg = <0x2800 0x100>;
+ };
+
+ pm8953_mpps: mpps {
+ compatible = "qcom,qpnp-pin";
+ spmi-dev-container;
+ gpio-controller;
+ #gpio-cells = <2>;
+ #address-cells = <1>;
+ #size-cells = <1>;
+ label = "pm8953-mpp";
+
+ mpp@a000 {
+ reg = <0xa000 0x100>;
+ qcom,pin-num = <1>;
+ status = "disabled";
+ };
+
+ mpp@a100 {
+ reg = <0xa100 0x100>;
+ qcom,pin-num = <2>;
+ /* MPP2 - PA_THERM config */
+ qcom,mode = <4>; /* AIN input */
+ qcom,invert = <1>; /* Enable MPP */
+ qcom,ain-route = <1>; /* AMUX 6 */
+ qcom,master-en = <1>;
+ qcom,src-sel = <0>; /* Function constant */
+ };
+
+ mpp@a200 {
+ reg = <0xa200 0x100>;
+ qcom,pin-num = <3>;
+ status = "disabled";
+ };
+
+ mpp@a300 {
+ reg = <0xa300 0x100>;
+ qcom,pin-num = <4>;
+ /* MPP4 - CASE_THERM config */
+ qcom,mode = <4>; /* AIN input */
+ qcom,invert = <1>; /* Enable MPP */
+ qcom,ain-route = <3>; /* AMUX 8 */
+ qcom,master-en = <1>;
+ qcom,src-sel = <0>; /* Function constant */
+ };
+ };
+
+ pm8953_gpios: gpios {
+ spmi-dev-container;
+ compatible = "qcom,qpnp-pin";
+ gpio-controller;
+ #gpio-cells = <2>;
+ #address-cells = <1>;
+ #size-cells = <1>;
+ label = "pm8953-gpio";
+
+ gpio@c000 {
+ reg = <0xc000 0x100>;
+ qcom,pin-num = <1>;
+ status = "disabled";
+ };
+
+ gpio@c100 {
+ reg = <0xc100 0x100>;
+ qcom,pin-num = <2>;
+ status = "disabled";
+ };
+
+ gpio@c200 {
+ reg = <0xc200 0x100>;
+ qcom,pin-num = <3>;
+ status = "disabled";
+ };
+
+ gpio@c300 {
+ reg = <0xc300 0x100>;
+ qcom,pin-num = <4>;
+ status = "disabled";
+ };
+
+ gpio@c400 {
+ reg = <0xc400 0x100>;
+ qcom,pin-num = <5>;
+ status = "disabled";
+ };
+
+ gpio@c500 {
+ reg = <0xc500 0x100>;
+ qcom,pin-num = <6>;
+ status = "disabled";
+ };
+
+ gpio@c600 {
+ reg = <0xc600 0x100>;
+ qcom,pin-num = <7>;
+ status = "disabled";
+ };
+
+ gpio@c700 {
+ reg = <0xc700 0x100>;
+ qcom,pin-num = <8>;
+ status = "disabled";
+ };
+ };
+
+ pm8953_vadc: vadc@3100 {
+ compatible = "qcom,qpnp-vadc";
+ reg = <0x3100 0x100>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ interrupts = <0x0 0x31 0x0 IRQ_TYPE_EDGE_RISING>;
+ interrupt-names = "eoc-int-en-set";
+ qcom,adc-bit-resolution = <15>;
+ qcom,adc-vdd-reference = <1800>;
+ qcom,vadc-poll-eoc;
+
+ chan@5 {
+ label = "vcoin";
+ reg = <5>;
+ qcom,decimation = <0>;
+ 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@7 {
+ label = "vph_pwr";
+ reg = <7>;
+ qcom,decimation = <0>;
+ 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@8 {
+ label = "die_temp";
+ reg = <8>;
+ qcom,decimation = <0>;
+ qcom,pre-div-channel-scaling = <0>;
+ qcom,calibration-type = "absolute";
+ qcom,scale-function = <3>;
+ qcom,hw-settle-time = <0>;
+ qcom,fast-avg-setup = <0>;
+ };
+
+ chan@9 {
+ label = "ref_625mv";
+ reg = <9>;
+ qcom,decimation = <0>;
+ qcom,pre-div-channel-scaling = <0>;
+ qcom,calibration-type = "absolute";
+ qcom,scale-function = <0>;
+ qcom,hw-settle-time = <0>;
+ qcom,fast-avg-setup = <0>;
+ };
+
+ chan@a {
+ label = "ref_1250v";
+ reg = <0xa>;
+ qcom,decimation = <0>;
+ qcom,pre-div-channel-scaling = <0>;
+ qcom,calibration-type = "absolute";
+ qcom,scale-function = <0>;
+ qcom,hw-settle-time = <0>;
+ qcom,fast-avg-setup = <0>;
+ };
+
+ chan@c {
+ label = "ref_buf_625mv";
+ reg = <0xc>;
+ qcom,decimation = <0>;
+ qcom,pre-div-channel-scaling = <0>;
+ qcom,calibration-type = "absolute";
+ qcom,scale-function = <0>;
+ qcom,hw-settle-time = <0>;
+ qcom,fast-avg-setup = <0>;
+ };
+
+ chan@36 {
+ label = "pa_therm0";
+ reg = <0x36>;
+ qcom,decimation = <0>;
+ qcom,pre-div-channel-scaling = <0>;
+ qcom,calibration-type = "ratiometric";
+ qcom,scale-function = <2>;
+ qcom,hw-settle-time = <2>;
+ qcom,fast-avg-setup = <0>;
+ };
+
+ chan@11 {
+ label = "pa_therm1";
+ reg = <0x11>;
+ qcom,decimation = <0>;
+ qcom,pre-div-channel-scaling = <0>;
+ qcom,calibration-type = "ratiometric";
+ qcom,scale-function = <2>;
+ qcom,hw-settle-time = <2>;
+ qcom,fast-avg-setup = <0>;
+ };
+
+
+ chan@32 {
+ label = "xo_therm";
+ reg = <0x32>;
+ qcom,decimation = <0>;
+ 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@3c {
+ label = "xo_therm_buf";
+ reg = <0x3c>;
+ qcom,decimation = <0>;
+ 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@13 {
+ label = "case_therm";
+ reg = <0x13>;
+ qcom,decimation = <0>;
+ qcom,pre-div-channel-scaling = <0>;
+ qcom,calibration-type = "ratiometric";
+ qcom,scale-function = <2>;
+ qcom,hw-settle-time = <2>;
+ qcom,fast-avg-setup = <0>;
+ };
+ };
+
+ pm8953_adc_tm: vadc@3400 {
+ compatible = "qcom,qpnp-adc-tm";
+ reg = <0x3400 0x100>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ interrupts = <0x0 0x34 0x0 IRQ_TYPE_EDGE_RISING>,
+ <0x0 0x34 0x3 IRQ_TYPE_EDGE_RISING>,
+ <0x0 0x34 0x4 IRQ_TYPE_EDGE_RISING>;
+ interrupt-names = "eoc-int-en-set",
+ "high-thr-en-set",
+ "low-thr-en-set";
+ qcom,adc-bit-resolution = <15>;
+ qcom,adc-vdd-reference = <1800>;
+ qcom,adc_tm-vadc = <&pm8953_vadc>;
+ };
+
+ pm8953_rtc: qcom,pm8953_rtc {
+ spmi-dev-container;
+ compatible = "qcom,qpnp-rtc";
+ #address-cells = <1>;
+ #size-cells = <1>;
+ qcom,qpnp-rtc-write = <0>;
+ qcom,qpnp-rtc-alarm-pwrup = <0>;
+
+ qcom,pm8953_rtc_rw@6000 {
+ reg = <0x6000 0x100>;
+ };
+
+ qcom,pm8953_rtc_alarm@6100 {
+ reg = <0x6100 0x100>;
+ interrupts = <0x0 0x61 0x1 IRQ_TYPE_NONE>;
+ };
+ };
+
+ pm8953_typec: qcom,pm8953_typec@bf00 {
+ compatible = "qcom,qpnp-typec";
+ reg = <0xbf00 0x100>;
+ interrupts = <0x0 0xbf 0x0 IRQ_TYPE_EDGE_RISING>,
+ <0x0 0xbf 0x1 IRQ_TYPE_EDGE_RISING>,
+ <0x0 0xbf 0x2 IRQ_TYPE_EDGE_RISING>,
+ <0x0 0xbf 0x3 IRQ_TYPE_EDGE_RISING>,
+ <0x0 0xbf 0x4 IRQ_TYPE_EDGE_RISING>,
+ <0x0 0xbf 0x6 IRQ_TYPE_EDGE_RISING>,
+ <0x0 0xbf 0x7 IRQ_TYPE_EDGE_RISING>;
+
+ interrupt-names = "vrd-change",
+ "ufp-detect",
+ "ufp-detach",
+ "dfp-detect",
+ "dfp-detach",
+ "vbus-err",
+ "vconn-oc";
+ };
+ };
+
+ pm8953_1: qcom,pm8953@1 {
+ compatible = "qcom,spmi-pmic";
+ reg = <0x1 SPMI_USID>;
+ #address-cells = <1>;
+ #size-cells = <1>;
+
+ pm8953_pwm: pwm@bc00 {
+ status = "disabled";
+ compatible = "qcom,qpnp-pwm";
+ reg = <0xbc00 0x100>;
+ reg-names = "qpnp-lpg-channel-base";
+ qcom,channel-id = <0>;
+ qcom,supported-sizes = <6>, <9>;
+ #pwm-cells = <2>;
+ };
+ };
+};
diff --git a/arch/arm64/boot/dts/qcom/pm8998.dtsi b/arch/arm64/boot/dts/qcom/pm8998.dtsi
index dc3ffda..89499f8 100644
--- a/arch/arm64/boot/dts/qcom/pm8998.dtsi
+++ b/arch/arm64/boot/dts/qcom/pm8998.dtsi
@@ -248,7 +248,7 @@
pm8998_trip2: pm8998-trip2 {
temperature = <145000>;
hysteresis = <0>;
- type = "critical";
+ type = "passive";
};
};
};
diff --git a/arch/arm64/boot/dts/qcom/pmi8950.dtsi b/arch/arm64/boot/dts/qcom/pmi8950.dtsi
index 4223cfe..8b4fccb 100644
--- a/arch/arm64/boot/dts/qcom/pmi8950.dtsi
+++ b/arch/arm64/boot/dts/qcom/pmi8950.dtsi
@@ -43,7 +43,7 @@
reg = <0x3100 0x100>;
#address-cells = <1>;
#size-cells = <0>;
- interrupts = <0x2 0x31 0x0>;
+ interrupts = <0x2 0x31 0x0 IRQ_TYPE_EDGE_RISING>;
interrupt-names = "eoc-int-en-set";
qcom,adc-bit-resolution = <15>;
qcom,adc-vdd-reference = <1800>;
@@ -140,7 +140,6 @@
};
pmi8950_gpios: gpios {
- spmi-dev-container;
compatible = "qcom,qpnp-pin";
gpio-controller;
#gpio-cells = <2>;
@@ -162,7 +161,6 @@
};
pmi8950_mpps: mpps {
- spmi-dev-container;
compatible = "qcom,qpnp-pin";
gpio-controller;
#gpio-cells = <2>;
@@ -196,7 +194,6 @@
};
pmi8950_charger: qcom,qpnp-smbcharger {
- spmi-dev-container;
compatible = "qcom,qpnp-smbcharger";
#address-cells = <1>;
#size-cells = <1>;
@@ -218,14 +215,14 @@
qcom,chgr@1000 {
reg = <0x1000 0x100>;
- interrupts = <0x2 0x10 0x0>,
- <0x2 0x10 0x1>,
- <0x2 0x10 0x2>,
- <0x2 0x10 0x3>,
- <0x2 0x10 0x4>,
- <0x2 0x10 0x5>,
- <0x2 0x10 0x6>,
- <0x2 0x10 0x7>;
+ interrupts = <0x2 0x10 0x0 IRQ_TYPE_NONE>,
+ <0x2 0x10 0x1 IRQ_TYPE_NONE>,
+ <0x2 0x10 0x2 IRQ_TYPE_NONE>,
+ <0x2 0x10 0x3 IRQ_TYPE_NONE>,
+ <0x2 0x10 0x4 IRQ_TYPE_NONE>,
+ <0x2 0x10 0x5 IRQ_TYPE_NONE>,
+ <0x2 0x10 0x6 IRQ_TYPE_NONE>,
+ <0x2 0x10 0x7 IRQ_TYPE_NONE>;
interrupt-names = "chg-error",
"chg-inhibit",
@@ -239,9 +236,9 @@
qcom,otg@1100 {
reg = <0x1100 0x100>;
- interrupts = <0x2 0x11 0x0>,
- <0x2 0x11 0x1>,
- <0x2 0x11 0x3>;
+ interrupts = <0x2 0x11 0x0 IRQ_TYPE_NONE>,
+ <0x2 0x11 0x1 IRQ_TYPE_NONE>,
+ <0x2 0x11 0x3 IRQ_TYPE_NONE>;
interrupt-names = "otg-fail",
"otg-oc",
"usbid-change";
@@ -249,14 +246,14 @@
qcom,bat-if@1200 {
reg = <0x1200 0x100>;
- interrupts = <0x2 0x12 0x0>,
- <0x2 0x12 0x1>,
- <0x2 0x12 0x2>,
- <0x2 0x12 0x3>,
- <0x2 0x12 0x4>,
- <0x2 0x12 0x5>,
- <0x2 0x12 0x6>,
- <0x2 0x12 0x7>;
+ interrupts = <0x2 0x12 0x0 IRQ_TYPE_NONE>,
+ <0x2 0x12 0x1 IRQ_TYPE_NONE>,
+ <0x2 0x12 0x2 IRQ_TYPE_NONE>,
+ <0x2 0x12 0x3 IRQ_TYPE_NONE>,
+ <0x2 0x12 0x4 IRQ_TYPE_NONE>,
+ <0x2 0x12 0x5 IRQ_TYPE_NONE>,
+ <0x2 0x12 0x6 IRQ_TYPE_NONE>,
+ <0x2 0x12 0x7 IRQ_TYPE_NONE>;
interrupt-names = "batt-hot",
"batt-warm",
@@ -270,10 +267,10 @@
qcom,usb-chgpth@1300 {
reg = <0x1300 0x100>;
- interrupts = <0x2 0x13 0x0>,
- <0x2 0x13 0x1>,
- <0x2 0x13 0x2>,
- <0x2 0x13 0x5>;
+ interrupts = <0x2 0x13 0x0 IRQ_TYPE_NONE>,
+ <0x2 0x13 0x1 IRQ_TYPE_NONE>,
+ <0x2 0x13 0x2 IRQ_TYPE_NONE>,
+ <0x2 0x13 0x5 IRQ_TYPE_NONE>;
interrupt-names = "usbin-uv",
"usbin-ov",
@@ -283,20 +280,20 @@
qcom,dc-chgpth@1400 {
reg = <0x1400 0x100>;
- interrupts = <0x2 0x14 0x0>,
- <0x2 0x14 0x1>;
+ interrupts = <0x2 0x14 0x0 IRQ_TYPE_NONE>,
+ <0x2 0x14 0x1 IRQ_TYPE_NONE>;
interrupt-names = "dcin-uv",
"dcin-ov";
};
qcom,chgr-misc@1600 {
reg = <0x1600 0x100>;
- interrupts = <0x2 0x16 0x0>,
- <0x2 0x16 0x1>,
- <0x2 0x16 0x2>,
- <0x2 0x16 0x3>,
- <0x2 0x16 0x4>,
- <0x2 0x16 0x5>;
+ interrupts = <0x2 0x16 0x0 IRQ_TYPE_NONE>,
+ <0x2 0x16 0x1 IRQ_TYPE_NONE>,
+ <0x2 0x16 0x2 IRQ_TYPE_NONE>,
+ <0x2 0x16 0x3 IRQ_TYPE_NONE>,
+ <0x2 0x16 0x4 IRQ_TYPE_NONE>,
+ <0x2 0x16 0x5 IRQ_TYPE_NONE>;
interrupt-names = "power-ok",
"temp-shutdown",
@@ -312,7 +309,6 @@
};
pmi8950_fg: qcom,fg {
- spmi-dev-container;
compatible = "qcom,qpnp-fg";
#address-cells = <1>;
#size-cells = <1>;
@@ -330,13 +326,13 @@
qcom,fg-soc@4000 {
status = "okay";
reg = <0x4000 0x100>;
- interrupts = <0x2 0x40 0x0>,
- <0x2 0x40 0x1>,
- <0x2 0x40 0x2>,
- <0x2 0x40 0x3>,
- <0x2 0x40 0x4>,
- <0x2 0x40 0x5>,
- <0x2 0x40 0x6>;
+ interrupts = <0x2 0x40 0x0 IRQ_TYPE_NONE>,
+ <0x2 0x40 0x1 IRQ_TYPE_NONE>,
+ <0x2 0x40 0x2 IRQ_TYPE_NONE>,
+ <0x2 0x40 0x3 IRQ_TYPE_NONE>,
+ <0x2 0x40 0x4 IRQ_TYPE_NONE>,
+ <0x2 0x40 0x5 IRQ_TYPE_NONE>,
+ <0x2 0x40 0x6 IRQ_TYPE_NONE>;
interrupt-names = "high-soc",
"low-soc",
@@ -349,14 +345,14 @@
qcom,fg-batt@4100 {
reg = <0x4100 0x100>;
- interrupts = <0x2 0x41 0x0>,
- <0x2 0x41 0x1>,
- <0x2 0x41 0x2>,
- <0x2 0x41 0x3>,
- <0x2 0x41 0x4>,
- <0x2 0x41 0x5>,
- <0x2 0x41 0x6>,
- <0x2 0x41 0x7>;
+ interrupts = <0x2 0x41 0x0 IRQ_TYPE_NONE>,
+ <0x2 0x41 0x1 IRQ_TYPE_NONE>,
+ <0x2 0x41 0x2 IRQ_TYPE_NONE>,
+ <0x2 0x41 0x3 IRQ_TYPE_NONE>,
+ <0x2 0x41 0x4 IRQ_TYPE_NONE>,
+ <0x2 0x41 0x5 IRQ_TYPE_NONE>,
+ <0x2 0x41 0x6 IRQ_TYPE_NONE>,
+ <0x2 0x41 0x7 IRQ_TYPE_NONE>;
interrupt-names = "soft-cold",
"soft-hot",
@@ -375,8 +371,8 @@
qcom,fg-memif@4400 {
status = "okay";
reg = <0x4400 0x100>;
- interrupts = <0x2 0x44 0x0>,
- <0x2 0x44 0x2>;
+ interrupts = <0x2 0x44 0x0 IRQ_TYPE_NONE>,
+ <0x2 0x44 0x2 IRQ_TYPE_NONE>;
interrupt-names = "mem-avail",
"data-rcvry-sug";
@@ -387,8 +383,8 @@
compatible = "qcom,msm-bcl";
reg = <0x4200 0xFF 0x88E 0x2>;
reg-names = "fg_user_adc", "pon_spare";
- interrupts = <0x2 0x42 0x0>,
- <0x2 0x42 0x1>;
+ interrupts = <0x2 0x42 0x0 IRQ_TYPE_NONE>,
+ <0x2 0x42 0x1 IRQ_TYPE_NONE>;
interrupt-names = "bcl-high-ibat-int",
"bcl-low-vbat-int";
qcom,vbat-scaling-factor = <39000>;
@@ -429,7 +425,6 @@
labibb: qpnp-labibb-regulator {
status = "disabled";
- spmi-dev-container;
compatible = "qcom,qpnp-labibb-regulator";
#address-cells = <1>;
#size-cells = <1>;
@@ -512,7 +507,7 @@
"qpnp-wled-sink-base",
"qpnp-wled-ibb-base",
"qpnp-wled-lab-base";
- interrupts = <0x3 0xd8 0x2>;
+ interrupts = <0x3 0xd8 0x2 IRQ_TYPE_EDGE_RISING>;
interrupt-names = "sc-irq";
status = "okay";
linux,name = "wled";
@@ -531,6 +526,7 @@
qcom,fs-curr-ua = <20000>;
qcom,led-strings-list = [00 01];
qcom,en-ext-pfet-sc-pro;
+ qcom,pmic-revid = <&pmi8950_revid>;
qcom,cons-sync-write-delay-us = <1000>;
};
@@ -617,8 +613,8 @@
pmi_haptic: qcom,haptic@c000 {
compatible = "qcom,qpnp-haptic";
reg = <0xc000 0x100>;
- interrupts = <0x3 0xc0 0x0>,
- <0x3 0xc0 0x1>;
+ interrupts = <0x3 0xc0 0x0 IRQ_TYPE_EDGE_BOTH>,
+ <0x3 0xc0 0x1 IRQ_TYPE_EDGE_BOTH>;
interrupt-names = "sc-irq", "play-irq";
qcom,pmic-revid = <&pmi8950_revid>;
vcc_pon-supply = <&pon_perph_reg>;
diff --git a/arch/arm64/boot/dts/qcom/pmi8998.dtsi b/arch/arm64/boot/dts/qcom/pmi8998.dtsi
index 5b48c14..2f4b00e 100644
--- a/arch/arm64/boot/dts/qcom/pmi8998.dtsi
+++ b/arch/arm64/boot/dts/qcom/pmi8998.dtsi
@@ -103,6 +103,7 @@
qcom,thermal-mitigation
= <3000000 1500000 1000000 500000>;
qcom,auto-recharge-soc;
+ qcom,suspend-input-on-debug-batt;
qcom,chgr@1000 {
reg = <0x1000 0x100>;
@@ -731,7 +732,7 @@
trips {
ibat_high: low-ibat {
- temperature = <4200>;
+ temperature = <5000>;
hysteresis = <200>;
type = "passive";
};
@@ -745,7 +746,7 @@
trips {
ibat_vhigh: ibat_vhigh {
- temperature = <4300>;
+ temperature = <6000>;
hysteresis = <100>;
type = "passive";
};
@@ -760,7 +761,7 @@
trips {
low_vbat: low-vbat {
- temperature = <3300>;
+ temperature = <3200>;
hysteresis = <100>;
type = "passive";
};
@@ -801,7 +802,7 @@
trips {
low-vbat {
- temperature = <3100>;
+ temperature = <2800>;
hysteresis = <0>;
type = "passive";
};
@@ -816,7 +817,7 @@
trips {
low-vbat {
- temperature = <2900>;
+ temperature = <2600>;
hysteresis = <0>;
type = "passive";
};
@@ -883,7 +884,7 @@
pmi8998_trip2: pmi8998-trip2 {
temperature = <145000>;
hysteresis = <0>;
- type = "critical";
+ type = "passive";
};
};
};
diff --git a/arch/arm64/boot/dts/qcom/qcs605-lc-mtp-overlay.dts b/arch/arm64/boot/dts/qcom/qcs605-lc-mtp-overlay.dts
new file mode 100644
index 0000000..e27baba
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/qcs605-lc-mtp-overlay.dts
@@ -0,0 +1,30 @@
+/*
+ * Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+/dts-v1/;
+/plugin/;
+
+#include <dt-bindings/clock/qcom,gcc-sdm845.h>
+#include <dt-bindings/clock/qcom,camcc-sdm845.h>
+#include <dt-bindings/clock/qcom,dispcc-sdm845.h>
+#include <dt-bindings/clock/qcom,rpmh.h>
+#include <dt-bindings/interrupt-controller/arm-gic.h>
+
+#include "qcs605-lc-mtp.dtsi"
+
+/ {
+ model = "Qualcomm Technologies, Inc. QC605 LC Groot + PM8005 MTP";
+ compatible = "qcom,qcs605-mtp", "qcom,qcs605", "qcom,mtp";
+ qcom,msm-id = <347 0x0>;
+ qcom,board-id = <8 4>;
+};
diff --git a/arch/arm64/boot/dts/qcom/qcs605-lc-mtp.dts b/arch/arm64/boot/dts/qcom/qcs605-lc-mtp.dts
new file mode 100644
index 0000000..194bfeb
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/qcs605-lc-mtp.dts
@@ -0,0 +1,24 @@
+/*
+ * 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 "qcs605.dtsi"
+#include "qcs605-lc-mtp.dtsi"
+
+/ {
+ model = "Qualcomm Technologies, Inc. QC605 LC Groot + PM8005 MTP";
+ compatible = "qcom,qcs605-mtp", "qcom,qcs605", "qcom,mtp";
+ qcom,board-id = <8 4>;
+
+};
diff --git a/arch/arm64/boot/dts/qcom/qcs605-lc-mtp.dtsi b/arch/arm64/boot/dts/qcom/qcs605-lc-mtp.dtsi
new file mode 100644
index 0000000..025d9a2
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/qcs605-lc-mtp.dtsi
@@ -0,0 +1,205 @@
+/* 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 "pm8005.dtsi"
+#include "sdm670-pmic-overlay.dtsi"
+#include "qcs605-pm660-pm8005-regulator.dtsi"
+
+/ {
+ cpus {
+ /delete-node/ cpu@200;
+ /delete-node/ cpu@300;
+ /delete-node/ cpu@400;
+ /delete-node/ cpu@500;
+
+ cpu-map {
+ cluster0 {
+ /delete-node/ core2;
+ /delete-node/ core3;
+ /delete-node/ core4;
+ /delete-node/ core5;
+ };
+ };
+ };
+
+
+};
+
+&soc {
+ /delete-node/ jtagmm@7240000;
+ /delete-node/ jtagmm@7340000;
+ /delete-node/ jtagmm@7440000;
+ /delete-node/ jtagmm@7540000;
+ /delete-node/ cti@7220000;
+ /delete-node/ cti@7320000;
+ /delete-node/ cti@7420000;
+ /delete-node/ cti@7520000;
+ /delete-node/ etm@7240000;
+ /delete-node/ etm@7340000;
+ /delete-node/ etm@7440000;
+ /delete-node/ etm@7540000;
+ cpuss_dump {
+ /delete-node/ qcom,l1_i_cache200;
+ /delete-node/ qcom,l1_i_cache300;
+ /delete-node/ qcom,l1_i_cache400;
+ /delete-node/ qcom,l1_i_cache500;
+ /delete-node/ qcom,l1_d_cache200;
+ /delete-node/ qcom,l1_d_cache300;
+ /delete-node/ qcom,l1_d_cache400;
+ /delete-node/ qcom,l1_d_cache500;
+ /delete-node/ qcom,l1_tlb_dump200;
+ /delete-node/ qcom,l1_tlb_dump300;
+ /delete-node/ qcom,l1_tlb_dump400;
+ /delete-node/ qcom,l1_tlb_dump500;
+ };
+
+ devfreq_memlat_0: qcom,cpu0-memlat-mon {
+ qcom,cpulist = <&CPU0 &CPU1>;
+ };
+
+ devfreq_l3lat_0: qcom,cpu0-l3lat-mon {
+ qcom,cpulist = <&CPU0 &CPU1>;
+ };
+ devfreq_compute0: qcom,devfreq-compute0 {
+ qcom,cpulist = <&CPU0 &CPU1>;
+ };
+
+ funnel_apss: funnel@7800000 {
+ ports {
+ /delete-node/ port@3;
+ /delete-node/ port@4;
+ /delete-node/ port@5;
+ /delete-node/ port@6;
+ };
+ };
+
+ qcom,lpm-levels {
+ qcom,pm-cluster@0 {
+ qcom,pm-cpu@0 {
+ qcom,cpu = <&CPU0 &CPU1>;
+ };
+ };
+ };
+};
+
+&pm660_temp_alarm {
+ cooling-maps {
+ /delete-node/ trip0_cpu2;
+ /delete-node/ trip0_cpu3;
+ /delete-node/ trip0_cpu4;
+ /delete-node/ trip0_cpu5;
+ /delete-node/ trip1_cpu2;
+ /delete-node/ trip1_cpu3;
+ /delete-node/ trip1_cpu4;
+ /delete-node/ trip1_cpu5;
+ };
+};
+
+&thermal_zones {
+
+ xo-therm-cpu-step {
+ cooling-maps {
+ /delete-node/ skin_cpu2;
+ /delete-node/ skin_cpu3;
+ /delete-node/ skin_cpu4;
+ /delete-node/ skin_cpu5;
+ };
+ };
+};
+
+&spmi_bus {
+ /delete-node/ qcom,pm660l@2;
+ /delete-node/ qcom,pm660l@3;
+};
+
+&thermal_zones {
+ pm660l_tz {
+ /delete-property/ thermal-sensors;
+ };
+};
+
+&soc {
+ qcom,turing@8300000 {
+ /delete-property/ vdd_cx-supply;
+ };
+
+ qcom,lpass@62400000 {
+ /delete-property/ vdd_cx-supply;
+ };
+};
+
+&clock_cpucc {
+ /delete-property/ vdd_l3_mx_ao-supply;
+ /delete-property/ vdd_pwrcl_mx_ao-supply;
+};
+
+&clock_gcc {
+ /delete-property/ vdd_cx-supply;
+ /delete-property/ vdd_cx_ao-supply;
+};
+
+&clock_videocc {
+ /delete-property/ vdd_cx-supply;
+};
+
+&clock_camcc {
+ /delete-property/ vdd_mx-supply;
+ /delete-property/ vdd_cx-supply;
+};
+
+&clock_dispcc {
+ /delete-property/ vdd_cx-supply;
+};
+
+&clock_gpucc {
+ /delete-property/ vdd_mx-supply;
+ /delete-property/ vdd_cx-supply;
+};
+
+&pil_modem {
+ /delete-property/ vdd_mx-supply;
+ /delete-property/ vdd_cx-supply;
+ /delete-property/ vdd_mss-supply;
+};
+
+&clock_gfx {
+ /delete-property/ vdd_gfx-supply;
+};
+
+&gpu_gx_gdsc {
+ /delete-property/ parent-supply;
+};
+
+&mdss_dsi_phy0 {
+ /delete-property/ vdda-0p9-supply;
+};
+
+&mdss_dsi_phy1 {
+ /delete-property/ vdda-0p9-supply;
+};
+
+&sde_dp {
+ /delete-property/ vdda-0p9-supply;
+};
+
+&qusb_phy0 {
+ /delete-property/ vdd-supply;
+ /delete-property/ vdda33-supply;
+};
+
+&usb_qmp_dp_phy {
+ /delete-property/ vdd-supply;
+};
+
+&pm660_pdphy {
+ /delete-property/ vdd-pdphy-supply;
+};
diff --git a/arch/arm64/boot/dts/qcom/qcs605-pm660-pm8005-regulator.dtsi b/arch/arm64/boot/dts/qcom/qcs605-pm660-pm8005-regulator.dtsi
new file mode 100644
index 0000000..a881ec4
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/qcs605-pm660-pm8005-regulator.dtsi
@@ -0,0 +1,474 @@
+/* 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 PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <dt-bindings/regulator/qcom,rpmh-regulator.h>
+
+&soc {
+ /* Delete all regulators */
+ /delete-node/ rpmh-regulator-smpa4;
+ /delete-node/ rpmh-regulator-modemlvl;
+ /delete-node/ rpmh-regulator-smpa6;
+ /delete-node/ rpmh-regulator-mxlvl;
+ /delete-node/ rpmh-regulator-gfxlvl;
+ /delete-node/ rpmh-regulator-cxlvl;
+ /delete-node/ rpmh-regulator-ldoa1;
+ /delete-node/ rpmh-regulator-ldoa2;
+ /delete-node/ rpmh-regulator-ldoa3;
+ /delete-node/ rpmh-regulator-ldoa5;
+ /delete-node/ rpmh-regulator-ldoa6;
+ /delete-node/ rpmh-regulator-ldoa7;
+ /delete-node/ rpmh-regulator-ldoa8;
+ /delete-node/ rpmh-regulator-ldoa9;
+ /delete-node/ rpmh-regulator-ldoa10;
+ /delete-node/ rpmh-regulator-ldoa11;
+ /delete-node/ rpmh-regulator-ldoa12;
+ /delete-node/ rpmh-regulator-ldoa13;
+ /delete-node/ rpmh-regulator-ldoa14;
+ /delete-node/ rpmh-regulator-ldoa15;
+ /delete-node/ rpmh-regulator-ldoa16;
+ /delete-node/ rpmh-regulator-ldoa17;
+ /delete-node/ rpmh-regulator-ldoa19;
+ /delete-node/ rpmh-regulator-ldob1;
+ /delete-node/ rpmh-regulator-ldob2;
+ /delete-node/ rpmh-regulator-ldob3;
+ /delete-node/ rpmh-regulator-ldob4;
+ /delete-node/ rpmh-regulator-ldob5;
+ /delete-node/ rpmh-regulator-ldob6;
+ /delete-node/ rpmh-regulator-ldob7;
+ /delete-node/ rpmh-regulator-ldob8;
+ /delete-node/ rpmh-regulator-lcxlvl;
+ /delete-node/ rpmh-regulator-lmxlvl;
+ /delete-node/ rpmh-regulator-bobb1;
+
+ /* RPMh regulators */
+
+ /* pm660 S2 - VDD_MX supply */
+ rpmh-regulator-mxlvl {
+ compatible = "qcom,rpmh-arc-regulator";
+ mboxes = <&apps_rsc 0>;
+ qcom,resource-name = "mx.lvl";
+ pm660_s2_level: regulator-pm660-s2 {
+ regulator-name = "pm660_s2_level";
+ qcom,set = <RPMH_REGULATOR_SET_ALL>;
+ regulator-min-microvolt = <RPMH_REGULATOR_LEVEL_OFF>;
+ regulator-max-microvolt = <RPMH_REGULATOR_LEVEL_MAX>;
+ };
+
+ pm660_s2_level_ao: regulator-pm660-s2-level-ao {
+ regulator-name = "pm660_s2_level_ao";
+ qcom,set = <RPMH_REGULATOR_SET_ACTIVE>;
+ regulator-min-microvolt = <RPMH_REGULATOR_LEVEL_OFF>;
+ regulator-max-microvolt = <RPMH_REGULATOR_LEVEL_MAX>;
+ };
+
+ mx_cdev: mx-cdev-lvl {
+ compatible = "qcom,regulator-cooling-device";
+ regulator-cdev-supply = <&pm660_s2_level>;
+ regulator-levels = <RPMH_REGULATOR_LEVEL_NOM
+ RPMH_REGULATOR_LEVEL_OFF>;
+ #cooling-cells = <2>;
+ };
+ };
+
+ rpmh-regulator-smpa4 {
+ compatible = "qcom,rpmh-vrm-regulator";
+ mboxes = <&apps_rsc 0>;
+ qcom,resource-name = "smpa4";
+ pm660_s4: regulator-pm660-s4 {
+ regulator-name = "pm660_s4";
+ qcom,set = <RPMH_REGULATOR_SET_ALL>;
+ regulator-min-microvolt = <1640000>;
+ regulator-max-microvolt = <2040000>;
+ qcom,init-voltage = <1640000>;
+ };
+ };
+
+ /* pm8005 S1 + S4 - VDD_CX supply */
+ rpmh-regulator-cxlvl {
+ compatible = "qcom,rpmh-arc-regulator";
+ mboxes = <&apps_rsc 0>;
+ qcom,resource-name = "cx.lvl";
+ pm8005_s1_level-parent-supply = <&pm660_s2_level>;
+ pm8005_s1_level_ao-parent-supply = <&pm660_s2_level_ao>;
+ pm8005_s1_level: regulator-pm8005-s1-level {
+ regulator-name = "pm8005_s1_level";
+ qcom,set = <RPMH_REGULATOR_SET_ALL>;
+ regulator-min-microvolt = <RPMH_REGULATOR_LEVEL_OFF>;
+ regulator-max-microvolt = <RPMH_REGULATOR_LEVEL_MAX>;
+ qcom,min-dropout-voltage-level = <(-1)>;
+ };
+
+ pm8005_s1_level_ao: regulator-pm8005-s1-level-ao {
+ regulator-name = "pm8005_s1_level_ao";
+ qcom,set = <RPMH_REGULATOR_SET_ACTIVE>;
+ regulator-min-microvolt = <RPMH_REGULATOR_LEVEL_OFF>;
+ regulator-max-microvolt = <RPMH_REGULATOR_LEVEL_MAX>;
+ qcom,min-dropout-voltage-level = <(-1)>;
+ };
+
+ cx_cdev: regulator-cdev {
+ compatible = "qcom,rpmh-reg-cdev";
+ mboxes = <&qmp_aop 0>;
+ qcom,reg-resource-name = "cx";
+ #cooling-cells = <2>;
+ };
+ };
+
+ rpmh-regulator-smpc2 {
+ compatible = "qcom,rpmh-vrm-regulator";
+ mboxes = <&apps_rsc 0>;
+ qcom,resource-name = "smpc2";
+ pm8005_s2: regulator-pm8005-s2 {
+ regulator-name = "pm8005_s2";
+ qcom,set = <RPMH_REGULATOR_SET_ALL>;
+ regulator-min-microvolt = <1000000>;
+ regulator-max-microvolt = <1200000>;
+ qcom,init-voltage = <1000000>;
+ };
+ };
+
+ /* pm8005 S3 - VDD_GFX supply */
+ rpmh-regulator-gfxlvl {
+ compatible = "qcom,rpmh-arc-regulator";
+ mboxes = <&apps_rsc 0>;
+ qcom,resource-name = "gfx.lvl";
+ pm8005_s3_level: regulator-pm8005-s3 {
+ regulator-name = "pm8005_s3_level";
+ qcom,set = <RPMH_REGULATOR_SET_ALL>;
+ regulator-min-microvolt
+ = <RPMH_REGULATOR_LEVEL_MIN_SVS>;
+ regulator-max-microvolt
+ = <RPMH_REGULATOR_LEVEL_MAX>;
+ qcom,init-voltage-level
+ = <RPMH_REGULATOR_LEVEL_MIN_SVS>;
+ };
+ };
+
+ rpmh-regulator-ldoa1 {
+ compatible = "qcom,rpmh-vrm-regulator";
+ mboxes = <&apps_rsc 0>;
+ qcom,resource-name = "ldoa1";
+ qcom,supported-modes =
+ <RPMH_REGULATOR_MODE_LDO_LPM
+ RPMH_REGULATOR_MODE_LDO_HPM>;
+ qcom,mode-threshold-currents = <0 1>;
+ pm660_l1: regulator-pm660-l1 {
+ regulator-name = "pm660_l1";
+ qcom,set = <RPMH_REGULATOR_SET_ALL>;
+ regulator-min-microvolt = <800000>;
+ regulator-max-microvolt = <800000>;
+ qcom,init-voltage = <800000>;
+ qcom,init-mode = <RPMH_REGULATOR_MODE_LDO_LPM>;
+ };
+ };
+
+ rpmh-regulator-ldoa2 {
+ compatible = "qcom,rpmh-vrm-regulator";
+ mboxes = <&apps_rsc 0>;
+ qcom,resource-name = "ldoa2";
+ qcom,supported-modes =
+ <RPMH_REGULATOR_MODE_LDO_LPM
+ RPMH_REGULATOR_MODE_LDO_HPM>;
+ qcom,mode-threshold-currents = <0 1>;
+ pm660_l2: regulator-pm660-l2 {
+ regulator-name = "pm660_l2";
+ qcom,set = <RPMH_REGULATOR_SET_ALL>;
+ regulator-min-microvolt = <1144000>;
+ regulator-max-microvolt = <1256000>;
+ qcom,init-voltage = <1144000>;
+ qcom,init-mode = <RPMH_REGULATOR_MODE_LDO_LPM>;
+ };
+ };
+
+ rpmh-regulator-ldoa3 {
+ compatible = "qcom,rpmh-vrm-regulator";
+ mboxes = <&apps_rsc 0>;
+ qcom,resource-name = "ldoa3";
+ qcom,supported-modes =
+ <RPMH_REGULATOR_MODE_LDO_LPM
+ RPMH_REGULATOR_MODE_LDO_HPM>;
+ qcom,mode-threshold-currents = <0 1>;
+ pm660_l3: regulator-pm660-l3 {
+ regulator-name = "pm660_l3";
+ qcom,set = <RPMH_REGULATOR_SET_ALL>;
+ regulator-min-microvolt = <1200000>;
+ regulator-max-microvolt = <1352000>;
+ qcom,init-voltage = <1200000>;
+ qcom,init-mode = <RPMH_REGULATOR_MODE_LDO_LPM>;
+ };
+ };
+
+ rpmh-regulator-ldoa5 {
+ compatible = "qcom,rpmh-vrm-regulator";
+ mboxes = <&apps_rsc 0>;
+ qcom,resource-name = "ldoa5";
+ qcom,supported-modes =
+ <RPMH_REGULATOR_MODE_LDO_LPM
+ RPMH_REGULATOR_MODE_LDO_HPM>;
+ qcom,mode-threshold-currents = <0 1>;
+ pm660_l5: regulator-pm660-l5 {
+ regulator-name = "pm660_l5";
+ qcom,set = <RPMH_REGULATOR_SET_ALL>;
+ regulator-min-microvolt = <1200000>;
+ regulator-max-microvolt = <1304000>;
+ qcom,init-voltage = <1200000>;
+ qcom,init-mode = <RPMH_REGULATOR_MODE_LDO_LPM>;
+ };
+ };
+
+ rpmh-regulator-ldoa6 {
+ compatible = "qcom,rpmh-vrm-regulator";
+ mboxes = <&apps_rsc 0>;
+ qcom,resource-name = "ldoa6";
+ qcom,supported-modes =
+ <RPMH_REGULATOR_MODE_LDO_LPM
+ RPMH_REGULATOR_MODE_LDO_HPM>;
+ qcom,mode-threshold-currents = <0 1>;
+ pm660_l6: regulator-pm660-l6 {
+ regulator-name = "pm660_l6";
+ qcom,set = <RPMH_REGULATOR_SET_ALL>;
+ regulator-min-microvolt = <880000>;
+ regulator-max-microvolt = <880000>;
+ qcom,init-voltage = <880000>;
+ qcom,init-mode = <RPMH_REGULATOR_MODE_LDO_LPM>;
+ };
+ };
+
+ /* pm660 L7 = VDD_LPI_CX supply */
+ rpmh-regulator-lcxlvl {
+ compatible = "qcom,rpmh-arc-regulator";
+ mboxes = <&apps_rsc 0>;
+ qcom,resource-name = "lcx.lvl";
+ pm660_l7_level: regulator-pm660-l7-level {
+ regulator-name = "pm660_l7_level";
+ qcom,set = <RPMH_REGULATOR_SET_ALL>;
+ regulator-min-microvolt = <RPMH_REGULATOR_LEVEL_OFF>;
+ regulator-max-microvolt = <RPMH_REGULATOR_LEVEL_MAX>;
+ };
+ };
+
+ rpmh-regulator-ldoa8 {
+ compatible = "qcom,rpmh-vrm-regulator";
+ mboxes = <&apps_rsc 0>;
+ qcom,resource-name = "ldoa8";
+ qcom,supported-modes =
+ <RPMH_REGULATOR_MODE_LDO_LPM
+ RPMH_REGULATOR_MODE_LDO_HPM>;
+ qcom,mode-threshold-currents = <0 1>;
+ pm660_l8: regulator-pm660-l8 {
+ regulator-name = "pm660_l8";
+ qcom,set = <RPMH_REGULATOR_SET_ALL>;
+ regulator-min-microvolt = <1696000>;
+ regulator-max-microvolt = <1952000>;
+ qcom,init-voltage = <1696000>;
+ qcom,init-mode = <RPMH_REGULATOR_MODE_LDO_LPM>;
+ };
+ };
+
+ rpmh-regulator-ldoa9 {
+ compatible = "qcom,rpmh-vrm-regulator";
+ mboxes = <&apps_rsc 0>;
+ qcom,resource-name = "ldoa9";
+ qcom,supported-modes =
+ <RPMH_REGULATOR_MODE_LDO_LPM
+ RPMH_REGULATOR_MODE_LDO_HPM>;
+ qcom,mode-threshold-currents = <0 1>;
+ pm660_l9: regulator-pm660-l9 {
+ regulator-name = "pm660_l9";
+ qcom,set = <RPMH_REGULATOR_SET_ALL>;
+ regulator-min-microvolt = <1616000>;
+ regulator-max-microvolt = <1984000>;
+ qcom,init-voltage = <1616000>;
+ qcom,init-mode = <RPMH_REGULATOR_MODE_LDO_LPM>;
+ };
+ };
+
+ rpmh-regulator-ldoa10 {
+ compatible = "qcom,rpmh-vrm-regulator";
+ mboxes = <&apps_rsc 0>;
+ qcom,resource-name = "ldoa10";
+ qcom,supported-modes =
+ <RPMH_REGULATOR_MODE_LDO_LPM
+ RPMH_REGULATOR_MODE_LDO_HPM>;
+ qcom,mode-threshold-currents = <0 1>;
+ pm660_l10: regulator-pm660-l10 {
+ regulator-name = "pm660_l10";
+ qcom,set = <RPMH_REGULATOR_SET_ALL>;
+ regulator-min-microvolt = <1696000>;
+ regulator-max-microvolt = <1952000>;
+ qcom,init-voltage = <1696000>;
+ qcom,init-mode = <RPMH_REGULATOR_MODE_LDO_LPM>;
+ };
+ };
+
+ rpmh-regulator-ldoa11 {
+ compatible = "qcom,rpmh-vrm-regulator";
+ mboxes = <&apps_rsc 0>;
+ qcom,resource-name = "ldoa11";
+ qcom,supported-modes =
+ <RPMH_REGULATOR_MODE_LDO_LPM
+ RPMH_REGULATOR_MODE_LDO_HPM>;
+ qcom,mode-threshold-currents = <0 1>;
+ pm660_l11: regulator-pm660-l11 {
+ regulator-name = "pm660_l11";
+ qcom,set = <RPMH_REGULATOR_SET_ALL>;
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1904000>;
+ qcom,init-voltage = <1800000>;
+ qcom,init-mode = <RPMH_REGULATOR_MODE_LDO_LPM>;
+ };
+ };
+
+ rpmh-regulator-ldoa12 {
+ compatible = "qcom,rpmh-vrm-regulator";
+ mboxes = <&apps_rsc 0>;
+ qcom,resource-name = "ldoa12";
+ qcom,supported-modes =
+ <RPMH_REGULATOR_MODE_LDO_LPM
+ RPMH_REGULATOR_MODE_LDO_HPM>;
+ qcom,mode-threshold-currents = <0 1>;
+ pm660_l12: regulator-pm660-l12 {
+ regulator-name = "pm660_l12";
+ qcom,set = <RPMH_REGULATOR_SET_ALL>;
+ regulator-min-microvolt = <1616000>;
+ regulator-max-microvolt = <1984000>;
+ qcom,init-voltage = <1616000>;
+ qcom,init-mode = <RPMH_REGULATOR_MODE_LDO_LPM>;
+ };
+ };
+
+ rpmh-regulator-ldoa13 {
+ compatible = "qcom,rpmh-vrm-regulator";
+ mboxes = <&apps_rsc 0>;
+ qcom,resource-name = "ldoa13";
+ qcom,supported-modes =
+ <RPMH_REGULATOR_MODE_LDO_LPM
+ RPMH_REGULATOR_MODE_LDO_HPM>;
+ qcom,mode-threshold-currents = <0 1>;
+ pm660_l13: regulator-pm660-l13 {
+ regulator-name = "pm660_l13";
+ qcom,set = <RPMH_REGULATOR_SET_ALL>;
+ regulator-min-microvolt = <1696000>;
+ regulator-max-microvolt = <1904000>;
+ qcom,init-voltage = <1696000>;
+ qcom,init-mode = <RPMH_REGULATOR_MODE_LDO_LPM>;
+ };
+ };
+
+ rpmh-regulator-ldoa14 {
+ compatible = "qcom,rpmh-vrm-regulator";
+ mboxes = <&apps_rsc 0>;
+ qcom,resource-name = "ldoa14";
+ qcom,supported-modes =
+ <RPMH_REGULATOR_MODE_LDO_LPM
+ RPMH_REGULATOR_MODE_LDO_HPM>;
+ qcom,mode-threshold-currents = <0 1>;
+ pm660_l14: regulator-pm660-l14 {
+ regulator-name = "pm660_l14";
+ qcom,set = <RPMH_REGULATOR_SET_ALL>;
+ regulator-min-microvolt = <1696000>;
+ regulator-max-microvolt = <1904000>;
+ qcom,init-voltage = <1696000>;
+ qcom,init-mode = <RPMH_REGULATOR_MODE_LDO_LPM>;
+ };
+ };
+
+ rpmh-regulator-ldoa15 {
+ compatible = "qcom,rpmh-vrm-regulator";
+ mboxes = <&apps_rsc 0>;
+ qcom,resource-name = "ldoa15";
+ qcom,supported-modes =
+ <RPMH_REGULATOR_MODE_LDO_LPM
+ RPMH_REGULATOR_MODE_LDO_HPM>;
+ qcom,mode-threshold-currents = <0 1>;
+ pm660_l15: regulator-pm660-l15 {
+ regulator-name = "pm660_l15";
+ qcom,set = <RPMH_REGULATOR_SET_ALL>;
+ regulator-min-microvolt = <2896000>;
+ regulator-max-microvolt = <3000000>;
+ qcom,init-voltage = <2896000>;
+ qcom,init-mode = <RPMH_REGULATOR_MODE_LDO_LPM>;
+ };
+ };
+
+ rpmh-regulator-ldoa16 {
+ compatible = "qcom,rpmh-vrm-regulator";
+ mboxes = <&apps_rsc 0>;
+ qcom,resource-name = "ldoa16";
+ qcom,supported-modes =
+ <RPMH_REGULATOR_MODE_LDO_LPM
+ RPMH_REGULATOR_MODE_LDO_HPM>;
+ qcom,mode-threshold-currents = <0 1>;
+ pm660_l16: regulator-pm660-l16 {
+ regulator-name = "pm660_l16";
+ qcom,set = <RPMH_REGULATOR_SET_ALL>;
+ regulator-min-microvolt = <2896000>;
+ regulator-max-microvolt = <3104000>;
+ qcom,init-voltage = <2896000>;
+ qcom,init-mode = <RPMH_REGULATOR_MODE_LDO_LPM>;
+ };
+ };
+
+ rpmh-regulator-ldoa17 {
+ compatible = "qcom,rpmh-vrm-regulator";
+ mboxes = <&apps_rsc 0>;
+ qcom,resource-name = "ldoa17";
+ qcom,supported-modes =
+ <RPMH_REGULATOR_MODE_LDO_LPM
+ RPMH_REGULATOR_MODE_LDO_HPM>;
+ qcom,mode-threshold-currents = <0 1>;
+ pm660_l17: regulator-pm660-l17 {
+ regulator-name = "pm660_l17";
+ qcom,set = <RPMH_REGULATOR_SET_ALL>;
+ regulator-min-microvolt = <2920000>;
+ regulator-max-microvolt = <3232000>;
+ qcom,init-voltage = <2920000>;
+ qcom,init-mode = <RPMH_REGULATOR_MODE_LDO_LPM>;
+ };
+ };
+
+ rpmh-regulator-ldoa18 {
+ compatible = "qcom,rpmh-vrm-regulator";
+ mboxes = <&apps_rsc 0>;
+ qcom,resource-name = "ldoa18";
+ qcom,supported-modes =
+ <RPMH_REGULATOR_MODE_LDO_LPM
+ RPMH_REGULATOR_MODE_LDO_HPM>;
+ qcom,mode-threshold-currents = <0 1>;
+ pm660_l18: regulator-pm660-l18 {
+ regulator-name = "pm660_l18";
+ qcom,set = <RPMH_REGULATOR_SET_ALL>;
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <3000000>;
+ qcom,init-voltage = <1800000>;
+ qcom,init-mode = <RPMH_REGULATOR_MODE_LDO_LPM>;
+ };
+ };
+
+ rpmh-regulator-ldoa19 {
+ compatible = "qcom,rpmh-vrm-regulator";
+ mboxes = <&apps_rsc 0>;
+ qcom,resource-name = "ldoa19";
+ qcom,supported-modes =
+ <RPMH_REGULATOR_MODE_LDO_LPM
+ RPMH_REGULATOR_MODE_LDO_HPM>;
+ qcom,mode-threshold-currents = <0 1>;
+ pm660_l19: regulator-pm660-l19 {
+ regulator-name = "pm660_l19";
+ qcom,set = <RPMH_REGULATOR_SET_ALL>;
+ regulator-min-microvolt = <2944000>;
+ regulator-max-microvolt = <3304000>;
+ qcom,init-voltage = <2944000>;
+ qcom,init-mode = <RPMH_REGULATOR_MODE_LDO_LPM>;
+ };
+ };
+};
diff --git a/arch/arm64/boot/dts/qcom/qcs605.dtsi b/arch/arm64/boot/dts/qcom/qcs605.dtsi
index 66493d1..6cf9a82 100644
--- a/arch/arm64/boot/dts/qcom/qcs605.dtsi
+++ b/arch/arm64/boot/dts/qcom/qcs605.dtsi
@@ -27,3 +27,23 @@
&ipa_hw {
status = "disabled";
};
+
+&thermal_zones {
+ lmh-dcvs-00 {
+ trips {
+ active-config {
+ temperature = <105000>;
+ hysteresis = <40000>;
+ };
+ };
+ };
+
+ lmh-dcvs-01 {
+ trips {
+ active-config {
+ temperature = <105000>;
+ hysteresis = <40000>;
+ };
+ };
+ };
+};
diff --git a/arch/arm64/boot/dts/qcom/sdm450.dtsi b/arch/arm64/boot/dts/qcom/sdm450.dtsi
index 8087399..b080ff7 100644
--- a/arch/arm64/boot/dts/qcom/sdm450.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm450.dtsi
@@ -19,3 +19,18 @@
qcom,msm-id = <338 0x0>;
};
+&CPU4 {
+ efficiency = <1024>;
+};
+
+&CPU5 {
+ efficiency = <1024>;
+};
+
+&CPU6 {
+ efficiency = <1024>;
+};
+
+&CPU7 {
+ efficiency = <1024>;
+};
diff --git a/arch/arm64/boot/dts/qcom/sdm670-camera-sensor-qrd.dtsi b/arch/arm64/boot/dts/qcom/sdm670-camera-sensor-qrd.dtsi
index 6506f98..7ab99a3 100644
--- a/arch/arm64/boot/dts/qcom/sdm670-camera-sensor-qrd.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm670-camera-sensor-qrd.dtsi
@@ -229,12 +229,13 @@
cam_vana-supply = <&cam_rear_avdd_gpio_regulator>;
cam_vdig-supply = <&cam_rear_dvdd_gpio_regulator>;
cam_clk-supply = <&titan_top_gdsc>;
+ cam_vaf-supply = <&actuator_regulator>;
regulator-names = "cam_vio", "cam_vana", "cam_vdig",
- "cam_clk";
+ "cam_clk", "cam_vaf";
rgltr-cntrl-support;
- rgltr-min-voltage = <0 0 0 0>;
- rgltr-max-voltage = <0 0 0 0>;
- rgltr-load-current = <0 0 0 0>;
+ rgltr-min-voltage = <1800000 2850000 1200000 0 2800000>;
+ rgltr-max-voltage = <1800000 2850000 1200000 0 2800000>;
+ rgltr-load-current = <0 80000 105000 0 0>;
gpio-no-mux = <0>;
pinctrl-names = "cam_default", "cam_suspend";
pinctrl-0 = <&cam_sensor_mclk0_active
@@ -266,12 +267,13 @@
cam_vana-supply = <&cam_avdd_gpio_regulator>;
cam_vdig-supply = <&cam_dvdd_gpio_regulator>;
cam_clk-supply = <&titan_top_gdsc>;
- regulator-names = "cam_vio", "cam_vana", "cam_vdig",
- "cam_clk";
+ cam_vaf-supply = <&actuator_regulator>;
+ regulator-names = "cam_vdig", "cam_vio", "cam_vana",
+ "cam_clk", "cam_vaf";
rgltr-cntrl-support;
- rgltr-min-voltage = <0 0 0 0>;
- rgltr-max-voltage = <0 0 0 0>;
- rgltr-load-current = <0 0 0 0>;
+ rgltr-min-voltage = <1200000 1800000 2850000 0 2800000>;
+ rgltr-max-voltage = <1200000 1800000 2850000 0 2800000>;
+ rgltr-load-current = <105000 0 80000 0 0>;
gpio-no-mux = <0>;
pinctrl-names = "cam_default", "cam_suspend";
pinctrl-0 = <&cam_sensor_mclk1_active
@@ -303,12 +305,13 @@
cam_vana-supply = <&cam_avdd_gpio_regulator>;
cam_vdig-supply = <&cam_dvdd_gpio_regulator>;
cam_clk-supply = <&titan_top_gdsc>;
+ cam_vaf-supply = <&actuator_regulator>;
regulator-names = "cam_vio", "cam_vana", "cam_vdig",
- "cam_clk";
+ "cam_clk", "cam_vaf";
rgltr-cntrl-support;
- rgltr-min-voltage = <0 0 0 0>;
- rgltr-max-voltage = <0 0 0 0>;
- rgltr-load-current = <0 0 0 0>;
+ rgltr-min-voltage = <1800000 2850000 1200000 0 2800000>;
+ rgltr-max-voltage = <1800000 2850000 1200000 0 2800000>;
+ rgltr-load-current = <0 80000 105000 0 0>;
gpio-no-mux = <0>;
pinctrl-names = "cam_default", "cam_suspend";
pinctrl-0 = <&cam_sensor_mclk2_active
@@ -350,9 +353,9 @@
regulator-names = "cam_vio", "cam_vana", "cam_vdig",
"cam_clk";
rgltr-cntrl-support;
- rgltr-min-voltage = <0 0 0 0>;
- rgltr-max-voltage = <0 0 0 0>;
- rgltr-load-current = <0 0 0 0>;
+ rgltr-min-voltage = <1800000 2850000 1200000 0>;
+ rgltr-max-voltage = <1800000 2850000 1200000 0>;
+ rgltr-load-current = <0 80000 105000 0>;
gpio-no-mux = <0>;
pinctrl-names = "cam_default", "cam_suspend";
pinctrl-0 = <&cam_sensor_mclk0_active
@@ -390,12 +393,12 @@
cam_vana-supply = <&cam_avdd_gpio_regulator>;
cam_vdig-supply = <&cam_dvdd_gpio_regulator>;
cam_clk-supply = <&titan_top_gdsc>;
- regulator-names = "cam_vio", "cam_vana", "cam_vdig",
+ regulator-names = "cam_vdig", "cam_vio", "cam_vana",
"cam_clk";
rgltr-cntrl-support;
- rgltr-min-voltage = <0 0 0 0>;
- rgltr-max-voltage = <0 0 0 0>;
- rgltr-load-current = <0 0 0 0>;
+ rgltr-min-voltage = <1200000 1800000 2850000 0>;
+ rgltr-max-voltage = <1200000 1800000 2850000 0>;
+ rgltr-load-current = <105000 0 80000 0>;
gpio-no-mux = <0>;
pinctrl-names = "cam_default", "cam_suspend";
pinctrl-0 = <&cam_sensor_mclk1_active
@@ -435,9 +438,9 @@
regulator-names = "cam_vio", "cam_vana", "cam_vdig",
"cam_clk";
rgltr-cntrl-support;
- rgltr-min-voltage = <0 0 0 0>;
- rgltr-max-voltage = <0 0 0 0>;
- rgltr-load-current = <0 0 0 0>;
+ rgltr-min-voltage = <1800000 2850000 1200000 0>;
+ rgltr-max-voltage = <1800000 2850000 1200000 0>;
+ rgltr-load-current = <0 80000 105000 0>;
gpio-no-mux = <0>;
pinctrl-names = "cam_default", "cam_suspend";
pinctrl-0 = <&cam_sensor_mclk2_active
diff --git a/arch/arm64/boot/dts/qcom/sdm670-camera.dtsi b/arch/arm64/boot/dts/qcom/sdm670-camera.dtsi
index 110e626..1f40e20 100644
--- a/arch/arm64/boot/dts/qcom/sdm670-camera.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm670-camera.dtsi
@@ -875,7 +875,6 @@
"soc_ahb_clk",
"cpas_ahb_clk",
"camnoc_axi_clk",
- "icp_apb_clk",
"icp_clk",
"icp_clk_src";
clocks = <&clock_gcc GCC_CAMERA_AHB_CLK>,
@@ -884,7 +883,6 @@
<&clock_camcc CAM_CC_SOC_AHB_CLK>,
<&clock_camcc CAM_CC_CPAS_AHB_CLK>,
<&clock_camcc CAM_CC_CAMNOC_AXI_CLK>,
- <&clock_camcc CAM_CC_ICP_APB_CLK>,
<&clock_camcc CAM_CC_ICP_CLK>,
<&clock_camcc CAM_CC_ICP_CLK_SRC>;
diff --git a/arch/arm64/boot/dts/qcom/sdm670-coresight.dtsi b/arch/arm64/boot/dts/qcom/sdm670-coresight.dtsi
index 8323476..f8a8e15 100644
--- a/arch/arm64/boot/dts/qcom/sdm670-coresight.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm670-coresight.dtsi
@@ -63,6 +63,9 @@
clocks = <&clock_aop QDSS_CLK>;
clock-names = "apb_pclk";
+ interrupts = <GIC_SPI 270 IRQ_TYPE_EDGE_RISING>;
+ interrupt-names = "byte-cntr-irq";
+
port {
tmc_etr_in_replicator: endpoint {
slave-mode;
diff --git a/arch/arm64/boot/dts/qcom/sdm670-lpi.dtsi b/arch/arm64/boot/dts/qcom/sdm670-lpi.dtsi
index c64ed2c..c76fbce 100644
--- a/arch/arm64/boot/dts/qcom/sdm670-lpi.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm670-lpi.dtsi
@@ -26,7 +26,7 @@
config {
pins = "gpio18";
- drive-strength = <2>;
+ drive-strength = <4>;
output-low;
};
};
@@ -53,7 +53,7 @@
config {
pins = "gpio19";
- drive-strength = <2>;
+ drive-strength = <4>;
output-low;
};
};
@@ -80,7 +80,7 @@
config {
pins = "gpio21";
- drive-strength = <2>;
+ drive-strength = <4>;
output-low;
};
};
@@ -107,7 +107,7 @@
config {
pins = "gpio23", "gpio25";
- drive-strength = <2>;
+ drive-strength = <4>;
output-low;
};
};
@@ -159,7 +159,7 @@
config {
pins = "gpio22";
- drive-strength = <2>;
+ drive-strength = <4>;
};
};
@@ -184,7 +184,7 @@
config {
pins = "gpio24";
- drive-strength = <2>;
+ drive-strength = <4>;
};
};
diff --git a/arch/arm64/boot/dts/qcom/sdm670-mtp.dtsi b/arch/arm64/boot/dts/qcom/sdm670-mtp.dtsi
index e9924e2..c136752 100644
--- a/arch/arm64/boot/dts/qcom/sdm670-mtp.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm670-mtp.dtsi
@@ -371,4 +371,7 @@
xo-therm-mdm-step {
status = "disabled";
};
+ xo-therm-batt-step {
+ status = "disabled";
+ };
};
diff --git a/arch/arm64/boot/dts/qcom/sdm670-pm.dtsi b/arch/arm64/boot/dts/qcom/sdm670-pm.dtsi
index dd35a36..fe88aae 100644
--- a/arch/arm64/boot/dts/qcom/sdm670-pm.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm670-pm.dtsi
@@ -186,12 +186,4 @@
reg = <0xc300000 0x1000>, <0xc3f0004 0x4>;
reg-names = "phys_addr_base", "offset_addr";
};
-
- pdc: interrupt-controller@b220000{
- compatible = "qcom,pdc-sdm670";
- reg = <0xb220000 0x400>;
- #interrupt-cells = <3>;
- interrupt-parent = <&intc>;
- interrupt-controller;
- };
};
diff --git a/arch/arm64/boot/dts/qcom/sdm670-pmic-overlay.dtsi b/arch/arm64/boot/dts/qcom/sdm670-pmic-overlay.dtsi
index 0a7e25d..5d3975c 100644
--- a/arch/arm64/boot/dts/qcom/sdm670-pmic-overlay.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm670-pmic-overlay.dtsi
@@ -385,3 +385,63 @@
vbus_dwc3-supply = <&smb2_vbus>;
qcom,no-vbus-vote-with-type-C;
};
+
+&thermal_zones {
+ xo-therm-batt-step {
+ polling-delay-passive = <0>;
+ polling-delay = <0>;
+ thermal-sensors = <&pm660_adc_tm 0x4c>;
+ thermal-governor = "step_wise";
+
+ trips {
+ batt_trip1: batt-trip1 {
+ temperature = <40000>;
+ hysteresis = <2000>;
+ type = "passive";
+ };
+ batt_trip2: batt-trip2 {
+ temperature = <45000>;
+ hysteresis = <2000>;
+ type = "passive";
+ };
+ batt_trip3: batt-trip3 {
+ temperature = <48000>;
+ hysteresis = <3000>;
+ type = "passive";
+ };
+ batt_trip4: batt-trip4 {
+ temperature = <50000>;
+ hysteresis = <2000>;
+ type = "passive";
+ };
+ batt_trip5: batt-trip5 {
+ temperature = <52000>;
+ hysteresis = <2000>;
+ type = "passive";
+ };
+ };
+
+ cooling-maps {
+ battery_lvl1 {
+ trip = <&batt_trip1>;
+ cooling-device = <&pm660_charger 1 1>;
+ };
+ battery_lvl2 {
+ trip = <&batt_trip2>;
+ cooling-device = <&pm660_charger 2 2>;
+ };
+ battery_lvl3 {
+ trip = <&batt_trip3>;
+ cooling-device = <&pm660_charger 3 3>;
+ };
+ battery_lvl4 {
+ trip = <&batt_trip4>;
+ cooling-device = <&pm660_charger 4 4>;
+ };
+ battery_lvl5 {
+ trip = <&batt_trip5>;
+ cooling-device = <&pm660_charger 5 5>;
+ };
+ };
+ };
+};
diff --git a/arch/arm64/boot/dts/qcom/sdm670-qrd.dtsi b/arch/arm64/boot/dts/qcom/sdm670-qrd.dtsi
index f3c6b00..ea6e1c7 100644
--- a/arch/arm64/boot/dts/qcom/sdm670-qrd.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm670-qrd.dtsi
@@ -78,6 +78,8 @@
};
&pm660_charger {
+ qcom,thermal-mitigation = <4200000 3500000 3000000 2500000
+ 2000000 1500000 1000000 500000>;
qcom,battery-data = <&qrd_batterydata>;
qcom,sw-jeita-enable;
};
diff --git a/arch/arm64/boot/dts/qcom/sdm670-regulator.dtsi b/arch/arm64/boot/dts/qcom/sdm670-regulator.dtsi
index 3c84314..9898ada 100644
--- a/arch/arm64/boot/dts/qcom/sdm670-regulator.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm670-regulator.dtsi
@@ -459,9 +459,9 @@
pm660_l19: regulator-pm660-l19 {
regulator-name = "pm660_l19";
qcom,set = <RPMH_REGULATOR_SET_ALL>;
- regulator-min-microvolt = <3312000>;
+ regulator-min-microvolt = <3000000>;
regulator-max-microvolt = <3312000>;
- qcom,init-voltage = <3312000>;
+ qcom,init-voltage = <3000000>;
qcom,init-mode = <RPMH_REGULATOR_MODE_LDO_LPM>;
};
};
diff --git a/arch/arm64/boot/dts/qcom/sdm670-thermal.dtsi b/arch/arm64/boot/dts/qcom/sdm670-thermal.dtsi
index 6324b64..8cbc84f 100644
--- a/arch/arm64/boot/dts/qcom/sdm670-thermal.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm670-thermal.dtsi
@@ -1539,7 +1539,7 @@
type = "passive";
};
silver_trip1: silver-trip1 {
- temperature = <48000>;
+ temperature = <50000>;
hysteresis = <0>;
type = "passive";
};
@@ -1606,7 +1606,7 @@
};
modem_trip2: modem-trip2 {
temperature = <48000>;
- hysteresis = <2000>;
+ hysteresis = <3000>;
type = "passive";
};
modem_trip3: modem-trip3 {
diff --git a/arch/arm64/boot/dts/qcom/sdm670.dtsi b/arch/arm64/boot/dts/qcom/sdm670.dtsi
index 7ee700d..8db4013 100644
--- a/arch/arm64/boot/dts/qcom/sdm670.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm670.dtsi
@@ -464,10 +464,22 @@
#size-cells = <2>;
ranges;
- removed_regions: removed_regions@85700000 {
+ hyp_region: hyp_region@85700000 {
compatible = "removed-dma-pool";
no-map;
- reg = <0 0x85700000 0 0x3800000>;
+ reg = <0 0x85700000 0 0x600000>;
+ };
+
+ xbl_region: xbl_region@85e00000 {
+ compatible = "removed-dma-pool";
+ no-map;
+ reg = <0 0x85e00000 0 0x100000>;
+ };
+
+ removed_region: removed_region@85fc0000 {
+ compatible = "removed-dma-pool";
+ no-map;
+ reg = <0 0x85fc0000 0 0x2f40000>;
};
pil_camera_mem: camera_region@8ab00000 {
@@ -488,22 +500,28 @@
reg = <0 0x92e00000 0 0x500000>;
};
- pil_cdsp_mem: cdsp_regions@93300000 {
+ wlan_msa_mem: wlan_msa_region@93300000 {
compatible = "removed-dma-pool";
no-map;
- reg = <0 0x93300000 0 0x800000>;
+ reg = <0 0x93300000 0 0x100000>;
};
- pil_mba_mem: pil_mba_region@0x93b00000 {
+ pil_cdsp_mem: cdsp_regions@93400000 {
compatible = "removed-dma-pool";
no-map;
- reg = <0 0x93b00000 0 0x200000>;
+ reg = <0 0x93400000 0 0x800000>;
};
- pil_adsp_mem: pil_adsp_region@93d00000 {
+ pil_mba_mem: pil_mba_region@0x93c00000 {
compatible = "removed-dma-pool";
no-map;
- reg = <0 0x93d00000 0 0x1e00000>;
+ reg = <0 0x93c00000 0 0x200000>;
+ };
+
+ pil_adsp_mem: pil_adsp_region@93e00000 {
+ compatible = "removed-dma-pool";
+ no-map;
+ reg = <0 0x93e00000 0 0x1e00000>;
};
adsp_mem: adsp_region {
@@ -565,6 +583,8 @@
#include "sdm670-smp2p.dtsi"
+#include "msm-rdbg.dtsi"
+
#include "sdm670-qupv3.dtsi"
#include "sdm670-coresight.dtsi"
@@ -681,6 +701,14 @@
interrupt-parent = <&intc>;
};
+ pdc: interrupt-controller@b220000{
+ compatible = "qcom,pdc-sdm670";
+ reg = <0xb220000 0x400>;
+ #interrupt-cells = <3>;
+ interrupt-parent = <&intc>;
+ interrupt-controller;
+ };
+
timer {
compatible = "arm,armv8-timer";
interrupts = <1 1 0xf08>,
@@ -1034,14 +1062,12 @@
compatible = "qcom,clk-cpu-osm-sdm670";
reg = <0x17d41000 0x1400>,
<0x17d43000 0x1400>,
- <0x17d45800 0x1400>,
- <0x784248 0x4>;
- reg-names = "osm_l3_base", "osm_pwrcl_base", "osm_perfcl_base",
- "cpr_rc";
+ <0x17d45800 0x1400>;
+ reg-names = "osm_l3_base", "osm_pwrcl_base", "osm_perfcl_base";
vdd_l3_mx_ao-supply = <&pm660l_s1_level_ao>;
vdd_pwrcl_mx_ao-supply = <&pm660l_s1_level_ao>;
- qcom,mx-turbo-freq = <1478400000 1689600000 3300000001>;
+ qcom,mx-turbo-freq = <3300000001 3300000001 3300000001>;
l3-devs = <&l3_cpu0 &l3_cpu6>;
clock-names = "xo_ao";
@@ -1110,7 +1136,7 @@
reg-names = "wdt-base";
interrupts = <0 0 0>, <0 1 0>;
qcom,bark-time = <11000>;
- qcom,pet-time = <10000>;
+ qcom,pet-time = <9360>;
qcom,ipi-ping;
qcom,wakeup-enable;
};
@@ -2471,7 +2497,9 @@
vdd-1.8-xo-supply = <&pm660_l9>;
vdd-1.3-rfa-supply = <&pm660_l6>;
vdd-3.3-ch0-supply = <&pm660_l19>;
+ qcom,vdd-3.3-ch0-config = <3000000 3312000>;
qcom,wlan-msa-memory = <0x100000>;
+ qcom,wlan-msa-fixed-region = <&wlan_msa_mem>;
qcom,smmu-s1-bypass;
};
@@ -2780,6 +2808,7 @@
};
&bps_gdsc {
+ qcom,support-hw-trigger;
status = "ok";
};
@@ -2792,10 +2821,12 @@
};
&ipe_0_gdsc {
+ qcom,support-hw-trigger;
status = "ok";
};
&ipe_1_gdsc {
+ qcom,support-hw-trigger;
status = "ok";
};
diff --git a/arch/arm64/boot/dts/qcom/sdm845-4k-panel-qrd-overlay.dts b/arch/arm64/boot/dts/qcom/sdm845-4k-panel-qrd-overlay.dts
index f9c6f65..c6622d4 100644
--- a/arch/arm64/boot/dts/qcom/sdm845-4k-panel-qrd-overlay.dts
+++ b/arch/arm64/boot/dts/qcom/sdm845-4k-panel-qrd-overlay.dts
@@ -62,7 +62,3 @@
&dsi_sharp_4k_dsc_video_display {
qcom,dsi-display-active;
};
-
-&mdss_mdp {
- connectors = <&sde_rscc &sde_wb &sde_dp>;
-};
diff --git a/arch/arm64/boot/dts/qcom/sdm845-bus.dtsi b/arch/arm64/boot/dts/qcom/sdm845-bus.dtsi
index cf7ccae..3ce5626 100644
--- a/arch/arm64/boot/dts/qcom/sdm845-bus.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm845-bus.dtsi
@@ -751,38 +751,6 @@
qcom,bcms = <&bcm_cn0>;
};
- mas_qhm_tic: mas-qhm-tic {
- cell-id = <MSM_BUS_MASTER_TIC>;
- label = "mas-qhm-tic";
- qcom,buswidth = <4>;
- qcom,agg-ports = <1>;
- qcom,connections = <&slv_qhs_tlmm_south
- &slv_qhs_spss_cfg &slv_qhs_camera_cfg
- &slv_qhs_sdc4 &slv_qhs_sdc2
- &slv_qhs_mnoc_cfg &slv_qhs_ufs_mem_cfg
- &slv_qhs_snoc_cfg &slv_qhs_glm
- &slv_qhs_pdm &slv_qhs_a2_noc_cfg
- &slv_qhs_qdss_cfg &slv_qhs_display_cfg
- &slv_qhs_tcsr &slv_qhs_dcc_cfg
- &slv_qhs_ddrss_cfg &slv_qns_cnoc_a2noc
- &slv_qhs_phy_refgen_south
- &slv_qhs_pcie_gen3_cfg
- &slv_qhs_pcie0_cfg &slv_qhs_gpuss_cfg
- &slv_qhs_venus_cfg &slv_qhs_tsif
- &slv_qhs_compute_dsp_cfg &slv_qhs_aop
- &slv_qhs_qupv3_north &slv_qhs_usb3_0
- &slv_srvc_cnoc &slv_qhs_ufs_card_cfg
- &slv_qhs_usb3_1 &slv_qhs_ipa
- &slv_qhs_cpr_cx &slv_qhs_a1_noc_cfg
- &slv_qhs_aoss &slv_qhs_prng
- &slv_qhs_vsense_ctrl_cfg &slv_qhs_qupv3_south
- &slv_qhs_spdm &slv_qhs_crypto0_cfg
- &slv_qhs_pimem_cfg &slv_qhs_tlmm_north
- &slv_qhs_clk_ctl &slv_qhs_imem_cfg>;
- qcom,bus-dev = <&fab_config_noc>;
- qcom,bcms = <&bcm_cn0>;
- };
-
mas_qnm_snoc: mas-qnm-snoc {
cell-id = <MSM_BUS_SNOC_CNOC_MAS>;
label = "mas-qnm-snoc";
@@ -814,38 +782,6 @@
qcom,bcms = <&bcm_cn0>;
};
- mas_xm_qdss_dap: mas-xm-qdss-dap {
- cell-id = <MSM_BUS_MASTER_QDSS_DAP>;
- label = "mas-xm-qdss-dap";
- qcom,buswidth = <8>;
- qcom,agg-ports = <1>;
- qcom,connections = <&slv_qhs_tlmm_south
- &slv_qhs_spss_cfg &slv_qhs_camera_cfg
- &slv_qhs_sdc4 &slv_qhs_sdc2
- &slv_qhs_mnoc_cfg &slv_qhs_ufs_mem_cfg
- &slv_qhs_snoc_cfg &slv_qhs_glm
- &slv_qhs_pdm &slv_qhs_a2_noc_cfg
- &slv_qhs_qdss_cfg &slv_qhs_display_cfg
- &slv_qhs_tcsr &slv_qhs_dcc_cfg
- &slv_qhs_ddrss_cfg &slv_qns_cnoc_a2noc
- &slv_qhs_phy_refgen_south
- &slv_qhs_pcie_gen3_cfg
- &slv_qhs_pcie0_cfg &slv_qhs_gpuss_cfg
- &slv_qhs_venus_cfg &slv_qhs_tsif
- &slv_qhs_compute_dsp_cfg &slv_qhs_aop
- &slv_qhs_qupv3_north &slv_qhs_usb3_0
- &slv_srvc_cnoc &slv_qhs_ufs_card_cfg
- &slv_qhs_usb3_1 &slv_qhs_ipa
- &slv_qhs_cpr_cx &slv_qhs_a1_noc_cfg
- &slv_qhs_aoss &slv_qhs_prng
- &slv_qhs_vsense_ctrl_cfg &slv_qhs_qupv3_south
- &slv_qhs_spdm &slv_qhs_crypto0_cfg
- &slv_qhs_pimem_cfg &slv_qhs_tlmm_north
- &slv_qhs_clk_ctl &slv_qhs_imem_cfg>;
- qcom,bus-dev = <&fab_config_noc>;
- qcom,bcms = <&bcm_cn0>;
- };
-
mas_qhm_cnoc: mas-qhm-cnoc {
cell-id = <MSM_BUS_MASTER_CNOC_DC_NOC>;
label = "mas-qhm-cnoc";
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 31cfdd6..f31b3a5 100644
--- a/arch/arm64/boot/dts/qcom/sdm845-camera-sensor-cdp.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm845-camera-sensor-cdp.dtsi
@@ -97,6 +97,10 @@
qcom,cam-res-mgr {
compatible = "qcom,cam-res-mgr";
status = "ok";
+ shared-gpios = <8>;
+ pinctrl-names = "cam_res_mgr_default", "cam_res_mgr_suspend";
+ pinctrl-0 = <&cam_res_mgr_active>;
+ pinctrl-1 = <&cam_res_mgr_suspend>;
};
actuator_rear: qcom,actuator@0 {
diff --git a/arch/arm64/boot/dts/qcom/sdm845-camera-sensor-mtp.dtsi b/arch/arm64/boot/dts/qcom/sdm845-camera-sensor-mtp.dtsi
index d7f25977..a3a48af 100644
--- a/arch/arm64/boot/dts/qcom/sdm845-camera-sensor-mtp.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm845-camera-sensor-mtp.dtsi
@@ -97,6 +97,10 @@
qcom,cam-res-mgr {
compatible = "qcom,cam-res-mgr";
status = "ok";
+ shared-gpios = <8>;
+ pinctrl-names = "cam_res_mgr_default", "cam_res_mgr_suspend";
+ pinctrl-0 = <&cam_res_mgr_active>;
+ pinctrl-1 = <&cam_res_mgr_suspend>;
};
actuator_rear: qcom,actuator@0 {
diff --git a/arch/arm64/boot/dts/qcom/sdm845-ion.dtsi b/arch/arm64/boot/dts/qcom/sdm845-ion.dtsi
index 829dfcc..7d83184 100644
--- a/arch/arm64/boot/dts/qcom/sdm845-ion.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm845-ion.dtsi
@@ -33,6 +33,12 @@
qcom,ion-heap-type = "DMA";
};
+ qcom,ion-heap@19 { /* QSEECOM TA HEAP */
+ reg = <19>;
+ memory-region = <&qseecom_ta_mem>;
+ qcom,ion-heap-type = "DMA";
+ };
+
qcom,ion-heap@13 { /* SECURE SPSS HEAP */
reg = <13>;
memory-region = <&secure_sp_mem>;
diff --git a/arch/arm64/boot/dts/qcom/sdm845-pinctrl.dtsi b/arch/arm64/boot/dts/qcom/sdm845-pinctrl.dtsi
index 244ac1d..191e76d 100644
--- a/arch/arm64/boot/dts/qcom/sdm845-pinctrl.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm845-pinctrl.dtsi
@@ -2985,12 +2985,12 @@
cam_sensor_front_active: cam_sensor_front_active {
/* RESET AVDD_LDO*/
mux {
- pins = "gpio28", "gpio8";
+ pins = "gpio28";
function = "gpio";
};
config {
- pins = "gpio28", "gpio8";
+ pins = "gpio28";
bias-disable; /* No PULL */
drive-strength = <2>; /* 2 MA */
};
@@ -3014,12 +3014,12 @@
cam_sensor_iris_active: cam_sensor_iris_active {
/* RESET AVDD_LDO*/
mux {
- pins = "gpio9", "gpio8";
+ pins = "gpio9";
function = "gpio";
};
config {
- pins = "gpio9", "gpio8";
+ pins = "gpio9";
bias-disable; /* No PULL */
drive-strength = <2>; /* 2 MA */
};
@@ -3074,12 +3074,12 @@
cam_sensor_rear2_active: cam_sensor_rear2_active {
/* RESET, STANDBY */
mux {
- pins = "gpio9","gpio8";
+ pins = "gpio9";
function = "gpio";
};
config {
- pins = "gpio9","gpio8";
+ pins = "gpio9";
bias-disable; /* No PULL */
drive-strength = <2>; /* 2 MA */
};
@@ -3088,17 +3088,47 @@
cam_sensor_rear2_suspend: cam_sensor_rear2_suspend {
/* RESET, STANDBY */
mux {
- pins = "gpio9","gpio8";
+ pins = "gpio9";
function = "gpio";
};
config {
- pins = "gpio9","gpio8";
+ pins = "gpio9";
bias-pull-down; /* PULL DOWN */
drive-strength = <2>; /* 2 MA */
output-low;
};
};
+ cam_res_mgr_active: cam_res_mgr_active {
+ /* AVDD_LDO*/
+ mux {
+ pins = "gpio8";
+ function = "gpio";
+ };
+
+ config {
+ pins = "gpio8";
+ bias-disable; /* No PULL */
+ drive-strength = <2>; /* 2 MA */
+ };
+ };
+
+ cam_res_mgr_suspend: cam_res_mgr_suspend {
+ /* AVDD_LDO */
+ mux {
+ pins = "gpio8";
+ function = "gpio";
+ };
+
+ config {
+ pins = "gpio8";
+ bias-disable; /* No PULL */
+ drive-strength = <2>; /* 2 MA */
+ output-low;
+ };
+ };
+
+
trigout_a: trigout_a {
mux {
pins = "gpio90";
diff --git a/arch/arm64/boot/dts/qcom/sdm845-pm.dtsi b/arch/arm64/boot/dts/qcom/sdm845-pm.dtsi
index 8f1afe9..b24ef1d 100644
--- a/arch/arm64/boot/dts/qcom/sdm845-pm.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm845-pm.dtsi
@@ -139,12 +139,4 @@
reg = <0xC300000 0x1000>, <0xC3F0004 0x4>;
reg-names = "phys_addr_base", "offset_addr";
};
-
- pdc: interrupt-controller@0xb220000{
- compatible = "qcom,pdc-sdm845";
- reg = <0xb220000 0x400>;
- #interrupt-cells = <3>;
- interrupt-parent = <&intc>;
- interrupt-controller;
- };
};
diff --git a/arch/arm64/boot/dts/qcom/sdm845-qrd.dtsi b/arch/arm64/boot/dts/qcom/sdm845-qrd.dtsi
index 6dae069..3ee0138 100644
--- a/arch/arm64/boot/dts/qcom/sdm845-qrd.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm845-qrd.dtsi
@@ -51,6 +51,26 @@
status = "ok";
};
+&soc {
+ gpio_keys {
+ compatible = "gpio-keys";
+ label = "gpio-keys";
+
+ pinctrl-names = "default";
+ pinctrl-0 = <&key_vol_up_default>;
+
+ vol_up {
+ label = "volume_up";
+ gpios = <&pm8998_gpios 6 GPIO_ACTIVE_LOW>;
+ linux,input-type = <1>;
+ linux,code = <115>;
+ gpio-key,wakeup;
+ debounce-interval = <15>;
+ linux,can-disable;
+ };
+ };
+};
+
&qupv3_se3_i2c {
status = "ok";
nq@28 {
@@ -162,7 +182,7 @@
};
&mdss_mdp {
- connectors = <&sde_rscc &sde_wb>;
+ connectors = <&sde_rscc &sde_wb &sde_dp>;
};
&dsi_nt35597_truly_dsc_cmd {
diff --git a/arch/arm64/boot/dts/qcom/sdm845-regulator.dtsi b/arch/arm64/boot/dts/qcom/sdm845-regulator.dtsi
index da4d41c..9672b94 100644
--- a/arch/arm64/boot/dts/qcom/sdm845-regulator.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm845-regulator.dtsi
@@ -296,7 +296,7 @@
qcom,supported-modes =
<RPMH_REGULATOR_MODE_LDO_LPM
RPMH_REGULATOR_MODE_LDO_HPM>;
- qcom,mode-threshold-currents = <0 1>;
+ qcom,mode-threshold-currents = <0 10000>;
pm8998_l7: regulator-l7 {
regulator-name = "pm8998_l7";
qcom,set = <RPMH_REGULATOR_SET_ALL>;
@@ -479,7 +479,7 @@
qcom,supported-modes =
<RPMH_REGULATOR_MODE_LDO_LPM
RPMH_REGULATOR_MODE_LDO_HPM>;
- qcom,mode-threshold-currents = <0 1>;
+ qcom,mode-threshold-currents = <0 10000>;
pm8998_l17: regulator-l17 {
regulator-name = "pm8998_l17";
qcom,set = <RPMH_REGULATOR_SET_ALL>;
@@ -587,7 +587,7 @@
qcom,supported-modes =
<RPMH_REGULATOR_MODE_LDO_LPM
RPMH_REGULATOR_MODE_LDO_HPM>;
- qcom,mode-threshold-currents = <0 1>;
+ qcom,mode-threshold-currents = <0 10000>;
pm8998_l23: regulator-l23 {
regulator-name = "pm8998_l23";
qcom,set = <RPMH_REGULATOR_SET_ALL>;
@@ -624,7 +624,7 @@
qcom,supported-modes =
<RPMH_REGULATOR_MODE_LDO_LPM
RPMH_REGULATOR_MODE_LDO_HPM>;
- qcom,mode-threshold-currents = <0 1>;
+ qcom,mode-threshold-currents = <0 10000>;
pm8998_l25: regulator-l25 {
regulator-name = "pm8998_l25";
qcom,set = <RPMH_REGULATOR_SET_ALL>;
diff --git a/arch/arm64/boot/dts/qcom/sdm845-v2.dtsi b/arch/arm64/boot/dts/qcom/sdm845-v2.dtsi
index 1fcf893..947d28b 100644
--- a/arch/arm64/boot/dts/qcom/sdm845-v2.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm845-v2.dtsi
@@ -81,12 +81,6 @@
&clock_cpucc {
compatible = "qcom,clk-cpu-osm-v2";
- reg = <0x17d41000 0x1400>,
- <0x17d43000 0x1400>,
- <0x17d45800 0x1400>,
- <0x78425c 0x4>;
- reg-names = "osm_l3_base", "osm_pwrcl_base", "osm_perfcl_base",
- "cpr_rc";
};
&pcie1 {
diff --git a/arch/arm64/boot/dts/qcom/sdm845.dtsi b/arch/arm64/boot/dts/qcom/sdm845.dtsi
index 5b050c5..1ce9f1f 100644
--- a/arch/arm64/boot/dts/qcom/sdm845.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm845.dtsi
@@ -603,6 +603,14 @@
size = <0 0x1400000>;
};
+ qseecom_ta_mem: qseecom_ta_region {
+ compatible = "shared-dma-pool";
+ alloc-ranges = <0 0x00000000 0 0xffffffff>;
+ reusable;
+ alignment = <0 0x400000>;
+ size = <0 0x1000000>;
+ };
+
secure_sp_mem: secure_sp_region { /* SPSS-HLOS ION shared mem */
compatible = "shared-dma-pool";
alloc-ranges = <0 0x00000000 0 0xffffffff>; /* 32-bit */
@@ -754,6 +762,14 @@
interrupt-parent = <&intc>;
};
+ pdc: interrupt-controller@b220000{
+ compatible = "qcom,pdc-sdm845";
+ reg = <0xb220000 0x400>;
+ #interrupt-cells = <3>;
+ interrupt-parent = <&intc>;
+ interrupt-controller;
+ };
+
timer {
compatible = "arm,armv8-timer";
interrupts = <1 1 0xf08>,
@@ -1229,10 +1245,8 @@
compatible = "qcom,clk-cpu-osm";
reg = <0x17d41000 0x1400>,
<0x17d43000 0x1400>,
- <0x17d45800 0x1400>,
- <0x784248 0x4>;
- reg-names = "osm_l3_base", "osm_pwrcl_base", "osm_perfcl_base",
- "cpr_rc";
+ <0x17d45800 0x1400>;
+ reg-names = "osm_l3_base", "osm_pwrcl_base", "osm_perfcl_base";
vdd_l3_mx_ao-supply = <&pm8998_s6_level_ao>;
vdd_pwrcl_mx_ao-supply = <&pm8998_s6_level_ao>;
diff --git a/arch/arm64/configs/msm8953-perf_defconfig b/arch/arm64/configs/msm8953-perf_defconfig
index db96773..0e6e6f8 100644
--- a/arch/arm64/configs/msm8953-perf_defconfig
+++ b/arch/arm64/configs/msm8953-perf_defconfig
@@ -26,6 +26,7 @@
# CONFIG_PID_NS is not set
CONFIG_SCHED_AUTOGROUP=y
CONFIG_SCHED_TUNE=y
+CONFIG_DEFAULT_USE_ENERGY_AWARE=y
CONFIG_BLK_DEV_INITRD=y
# CONFIG_RD_XZ is not set
# CONFIG_RD_LZO is not set
@@ -65,6 +66,7 @@
CONFIG_CP15_BARRIER_EMULATION=y
CONFIG_SETEND_EMULATION=y
# CONFIG_ARM64_VHE is not set
+CONFIG_RANDOMIZE_BASE=y
CONFIG_BUILD_ARM64_APPENDED_DTB_IMAGE=y
# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set
CONFIG_COMPAT=y
@@ -278,6 +280,7 @@
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
# CONFIG_VT is not set
@@ -300,10 +303,17 @@
CONFIG_PINCTRL_QCOM_SPMI_PMIC=y
CONFIG_GPIOLIB=y
CONFIG_GPIO_SYSFS=y
+CONFIG_GPIO_QPNP_PIN=y
+CONFIG_GPIO_QPNP_PIN_DEBUG=y
CONFIG_POWER_RESET_QCOM=y
CONFIG_QCOM_DLOAD_MODE=y
CONFIG_POWER_RESET_XGENE=y
CONFIG_POWER_RESET_SYSCON=y
+CONFIG_QPNP_FG=y
+CONFIG_SMB135X_CHARGER=y
+CONFIG_SMB1351_USB_CHARGER=y
+CONFIG_QPNP_SMBCHARGER=y
+CONFIG_MSM_APM=y
CONFIG_SENSORS_QPNP_ADC_VOLTAGE=y
CONFIG_THERMAL=y
CONFIG_THERMAL_QPNP=y
@@ -311,10 +321,16 @@
CONFIG_THERMAL_TSENS=y
CONFIG_MSM_BCL_PERIPHERAL_CTL=y
CONFIG_QTI_THERMAL_LIMITS_DCVS=y
+CONFIG_MFD_SPMI_PMIC=y
CONFIG_REGULATOR_FIXED_VOLTAGE=y
+CONFIG_REGULATOR_CPR4_APSS=y
CONFIG_REGULATOR_CPRH_KBSS=y
+CONFIG_REGULATOR_MEM_ACC=y
+CONFIG_REGULATOR_MSM_GFX_LDO=y
CONFIG_REGULATOR_QPNP_LABIBB=y
CONFIG_REGULATOR_QPNP=y
+CONFIG_REGULATOR_RPM_SMD=y
+CONFIG_REGULATOR_SPM=y
CONFIG_REGULATOR_STUB=y
CONFIG_MEDIA_SUPPORT=y
CONFIG_MEDIA_CAMERA_SUPPORT=y
@@ -367,10 +383,14 @@
CONFIG_MMC_SDHCI=y
CONFIG_MMC_SDHCI_PLTFM=y
CONFIG_MMC_SDHCI_MSM=y
+CONFIG_MMC_SDHCI_MSM_ICE=y
+CONFIG_MMC_CQ_HCI=y
CONFIG_NEW_LEDS=y
CONFIG_LEDS_CLASS=y
CONFIG_LEDS_QPNP=y
+CONFIG_LEDS_QPNP_FLASH=y
CONFIG_LEDS_QPNP_WLED=y
+CONFIG_LEDS_QPNP_HAPTICS=y
CONFIG_LEDS_TRIGGERS=y
CONFIG_EDAC=y
CONFIG_EDAC_MM_EDAC=y
@@ -395,10 +415,11 @@
CONFIG_QPNP_COINCELL=y
CONFIG_QPNP_REVID=y
CONFIG_USB_BAM=y
-CONFIG_QCOM_MDSS_PLL=y
CONFIG_REMOTE_SPINLOCK_MSM=y
CONFIG_MAILBOX=y
CONFIG_ARM_SMMU=y
+CONFIG_MSM_SPM=y
+CONFIG_MSM_L2_SPM=y
CONFIG_MSM_BOOT_STATS=y
CONFIG_QCOM_EUD=y
CONFIG_QCOM_WATCHDOG_V2=y
diff --git a/arch/arm64/configs/msm8953_defconfig b/arch/arm64/configs/msm8953_defconfig
index d893fd0..a8634aa 100644
--- a/arch/arm64/configs/msm8953_defconfig
+++ b/arch/arm64/configs/msm8953_defconfig
@@ -30,6 +30,7 @@
# CONFIG_PID_NS is not set
CONFIG_SCHED_AUTOGROUP=y
CONFIG_SCHED_TUNE=y
+CONFIG_DEFAULT_USE_ENERGY_AWARE=y
CONFIG_BLK_DEV_INITRD=y
# CONFIG_RD_XZ is not set
# CONFIG_RD_LZO is not set
@@ -71,6 +72,7 @@
CONFIG_CP15_BARRIER_EMULATION=y
CONFIG_SETEND_EMULATION=y
# CONFIG_ARM64_VHE is not set
+CONFIG_RANDOMIZE_BASE=y
CONFIG_BUILD_ARM64_APPENDED_DTB_IMAGE=y
# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set
CONFIG_COMPAT=y
@@ -288,6 +290,7 @@
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
# CONFIG_VT is not set
@@ -310,10 +313,17 @@
CONFIG_PINCTRL_QCOM_SPMI_PMIC=y
CONFIG_GPIOLIB=y
CONFIG_GPIO_SYSFS=y
+CONFIG_GPIO_QPNP_PIN=y
+CONFIG_GPIO_QPNP_PIN_DEBUG=y
CONFIG_POWER_RESET_QCOM=y
CONFIG_QCOM_DLOAD_MODE=y
CONFIG_POWER_RESET_XGENE=y
CONFIG_POWER_RESET_SYSCON=y
+CONFIG_QPNP_FG=y
+CONFIG_SMB135X_CHARGER=y
+CONFIG_SMB1351_USB_CHARGER=y
+CONFIG_QPNP_SMBCHARGER=y
+CONFIG_MSM_APM=y
CONFIG_SENSORS_QPNP_ADC_VOLTAGE=y
CONFIG_THERMAL=y
CONFIG_THERMAL_QPNP=y
@@ -321,10 +331,16 @@
CONFIG_THERMAL_TSENS=y
CONFIG_MSM_BCL_PERIPHERAL_CTL=y
CONFIG_QTI_THERMAL_LIMITS_DCVS=y
+CONFIG_MFD_SPMI_PMIC=y
CONFIG_REGULATOR_FIXED_VOLTAGE=y
+CONFIG_REGULATOR_CPR4_APSS=y
CONFIG_REGULATOR_CPRH_KBSS=y
+CONFIG_REGULATOR_MEM_ACC=y
+CONFIG_REGULATOR_MSM_GFX_LDO=y
CONFIG_REGULATOR_QPNP_LABIBB=y
CONFIG_REGULATOR_QPNP=y
+CONFIG_REGULATOR_RPM_SMD=y
+CONFIG_REGULATOR_SPM=y
CONFIG_REGULATOR_STUB=y
CONFIG_MEDIA_SUPPORT=y
CONFIG_MEDIA_CAMERA_SUPPORT=y
@@ -379,10 +395,14 @@
CONFIG_MMC_SDHCI=y
CONFIG_MMC_SDHCI_PLTFM=y
CONFIG_MMC_SDHCI_MSM=y
+CONFIG_MMC_SDHCI_MSM_ICE=y
+CONFIG_MMC_CQ_HCI=y
CONFIG_NEW_LEDS=y
CONFIG_LEDS_CLASS=y
CONFIG_LEDS_QPNP=y
+CONFIG_LEDS_QPNP_FLASH=y
CONFIG_LEDS_QPNP_WLED=y
+CONFIG_LEDS_QPNP_HAPTICS=y
CONFIG_LEDS_TRIGGERS=y
CONFIG_EDAC=y
CONFIG_EDAC_MM_EDAC=y
@@ -406,13 +426,14 @@
CONFIG_QPNP_COINCELL=y
CONFIG_QPNP_REVID=y
CONFIG_USB_BAM=y
-CONFIG_QCOM_MDSS_PLL=y
CONFIG_REMOTE_SPINLOCK_MSM=y
CONFIG_MAILBOX=y
CONFIG_ARM_SMMU=y
CONFIG_IOMMU_DEBUG=y
CONFIG_IOMMU_DEBUG_TRACKING=y
CONFIG_IOMMU_TESTS=y
+CONFIG_MSM_SPM=y
+CONFIG_MSM_L2_SPM=y
CONFIG_MSM_BOOT_STATS=y
CONFIG_MSM_CORE_HANG_DETECT=y
CONFIG_MSM_GLADIATOR_HANG_DETECT=y
diff --git a/arch/arm64/configs/sdm670-perf_defconfig b/arch/arm64/configs/sdm670-perf_defconfig
index 9a43bb6..e8fe5bc 100644
--- a/arch/arm64/configs/sdm670-perf_defconfig
+++ b/arch/arm64/configs/sdm670-perf_defconfig
@@ -571,6 +571,9 @@
CONFIG_EXT2_FS_XATTR=y
CONFIG_EXT3_FS=y
CONFIG_EXT4_FS_SECURITY=y
+CONFIG_EXT4_ENCRYPTION=y
+CONFIG_EXT4_FS_ENCRYPTION=y
+CONFIG_EXT4_FS_ICE_ENCRYPTION=y
CONFIG_QUOTA=y
CONFIG_QUOTA_NETLINK_INTERFACE=y
CONFIG_QFMT_V2=y
@@ -602,13 +605,13 @@
CONFIG_CORESIGHT_EVENT=y
CONFIG_CORESIGHT_HWEVENT=y
CONFIG_CORESIGHT_DUMMY=y
+CONFIG_PFK=y
CONFIG_SECURITY_PERF_EVENTS_RESTRICT=y
CONFIG_SECURITY=y
CONFIG_HARDENED_USERCOPY=y
CONFIG_FORTIFY_SOURCE=y
CONFIG_SECURITY_SELINUX=y
CONFIG_SECURITY_SMACK=y
-CONFIG_CRYPTO_CTR=y
CONFIG_CRYPTO_XCBC=y
CONFIG_CRYPTO_MD4=y
CONFIG_CRYPTO_TWOFISH=y
diff --git a/arch/arm64/configs/sdm670_defconfig b/arch/arm64/configs/sdm670_defconfig
index 822324d..ca923f1 100644
--- a/arch/arm64/configs/sdm670_defconfig
+++ b/arch/arm64/configs/sdm670_defconfig
@@ -314,6 +314,7 @@
CONFIG_HW_RANDOM_MSM_LEGACY=y
# CONFIG_DEVPORT is not set
CONFIG_MSM_ADSPRPC=y
+CONFIG_MSM_RDBG=m
CONFIG_I2C_CHARDEV=y
CONFIG_I2C_QCOM_GENI=y
CONFIG_SPI=y
@@ -588,6 +589,9 @@
CONFIG_EXT2_FS_XATTR=y
CONFIG_EXT3_FS=y
CONFIG_EXT4_FS_SECURITY=y
+CONFIG_EXT4_ENCRYPTION=y
+CONFIG_EXT4_FS_ENCRYPTION=y
+CONFIG_EXT4_FS_ICE_ENCRYPTION=y
CONFIG_QUOTA=y
CONFIG_QUOTA_NETLINK_INTERFACE=y
CONFIG_FUSE_FS=y
@@ -665,13 +669,13 @@
CONFIG_CORESIGHT_TGU=y
CONFIG_CORESIGHT_HWEVENT=y
CONFIG_CORESIGHT_DUMMY=y
+CONFIG_PFK=y
CONFIG_SECURITY_PERF_EVENTS_RESTRICT=y
CONFIG_SECURITY=y
CONFIG_HARDENED_USERCOPY=y
CONFIG_FORTIFY_SOURCE=y
CONFIG_SECURITY_SELINUX=y
CONFIG_SECURITY_SMACK=y
-CONFIG_CRYPTO_CTR=y
CONFIG_CRYPTO_XCBC=y
CONFIG_CRYPTO_MD4=y
CONFIG_CRYPTO_TWOFISH=y
diff --git a/drivers/bluetooth/btfm_slim.c b/drivers/bluetooth/btfm_slim.c
index 64d7ac7..6792e04 100644
--- a/drivers/bluetooth/btfm_slim.c
+++ b/drivers/bluetooth/btfm_slim.c
@@ -130,7 +130,8 @@
BTFMSLIM_DBG("port: %d ch: %d", ch->port, ch->ch);
/* Define the channel with below parameters */
- prop.prot = SLIM_AUTO_ISO;
+ prop.prot = ((rates == 44100) || (rates == 88200)) ?
+ SLIM_PUSH : SLIM_AUTO_ISO;
prop.baser = ((rates == 44100) || (rates == 88200)) ?
SLIM_RATE_11025HZ : SLIM_RATE_4000HZ;
prop.dataf = ((rates == 48000) || (rates == 44100) ||
@@ -228,17 +229,34 @@
BTFMSLIM_INFO("port:%d, grp: %d, ch->grph:0x%x, ch->ch_hdl:0x%x ",
ch->port, grp, ch->grph, ch->ch_hdl);
+
+ /* For 44.1/88.2 Khz A2DP Rx, disconnect the port first */
+ if (rxport &&
+ (btfmslim->sample_rate == 44100 ||
+ btfmslim->sample_rate == 88200)) {
+ BTFMSLIM_DBG("disconnecting the ports, removing the channel");
+ ret = slim_disconnect_ports(btfmslim->slim_pgd,
+ &ch->port_hdl, 1);
+ if (ret < 0) {
+ BTFMSLIM_ERR("slim_disconnect_ports failed ret[%d]",
+ ret);
+ }
+ }
+
/* Remove the channel immediately*/
ret = slim_control_ch(btfmslim->slim_pgd, (grp ? ch->grph : ch->ch_hdl),
SLIM_CH_REMOVE, true);
if (ret < 0) {
BTFMSLIM_ERR("slim_control_ch failed ret[%d]", ret);
- ret = slim_disconnect_ports(btfmslim->slim_pgd,
- &ch->port_hdl, 1);
- if (ret < 0) {
- BTFMSLIM_ERR("slim_disconnect_ports failed ret[%d]",
- ret);
- goto error;
+ if (btfmslim->sample_rate != 44100 &&
+ btfmslim->sample_rate != 88200) {
+ ret = slim_disconnect_ports(btfmslim->slim_pgd,
+ &ch->port_hdl, 1);
+ if (ret < 0) {
+ BTFMSLIM_ERR("disconnect_ports failed ret[%d]",
+ ret);
+ goto error;
+ }
}
}
diff --git a/drivers/bluetooth/btfm_slim_wcn3990.c b/drivers/bluetooth/btfm_slim_wcn3990.c
index 2dbba83..9f2bf90 100644
--- a/drivers/bluetooth/btfm_slim_wcn3990.c
+++ b/drivers/bluetooth/btfm_slim_wcn3990.c
@@ -88,8 +88,12 @@
BTFMSLIM_DBG("port(%d) enable(%d)", port_num, enable);
if (rxport) {
- if (enable) {
- /* For SCO Rx, A2DP Rx */
+ BTFMSLIM_DBG("sample rate is %d", btfmslim->sample_rate);
+ if (enable &&
+ btfmslim->sample_rate != 44100 &&
+ btfmslim->sample_rate != 88200) {
+ BTFMSLIM_DBG("setting multichannel bit");
+ /* For SCO Rx, A2DP Rx other than 44.1 and 88.2Khz */
if (port_num < 24) {
rxport_num = port_num - 16;
reg_val = 0x01 << rxport_num;
diff --git a/drivers/char/adsprpc.c b/drivers/char/adsprpc.c
index 35eea02..3058ce3 100644
--- a/drivers/char/adsprpc.c
+++ b/drivers/char/adsprpc.c
@@ -117,11 +117,11 @@
return offset;
}
-static inline int buf_num_pages(uint64_t buf, ssize_t len)
+static inline uint64_t buf_num_pages(uint64_t buf, size_t len)
{
uint64_t start = buf_page_start(buf) >> PAGE_SHIFT;
uint64_t end = (((uint64_t) buf + len - 1) & PAGE_MASK) >> PAGE_SHIFT;
- int nPages = end - start + 1;
+ uint64_t nPages = end - start + 1;
return nPages;
}
@@ -153,7 +153,7 @@
struct fastrpc_file *fl;
void *virt;
uint64_t phys;
- ssize_t size;
+ size_t size;
};
struct fastrpc_ctx_lst;
@@ -179,7 +179,7 @@
unsigned int *attrs;
struct fastrpc_mmap **maps;
struct fastrpc_buf *buf;
- ssize_t used;
+ size_t used;
struct fastrpc_file *fl;
uint32_t sc;
struct overlap *overs;
@@ -238,13 +238,13 @@
int ramdumpenabled;
void *remoteheap_ramdump_dev;
struct fastrpc_glink_info link;
- struct mutex mut;
};
struct fastrpc_apps {
struct fastrpc_channel_ctx *channel;
struct cdev cdev;
struct class *class;
+ struct mutex smd_mutex;
struct smq_phy_page range;
struct hlist_head maps;
uint32_t staticpd_flags;
@@ -268,9 +268,9 @@
struct dma_buf_attachment *attach;
struct ion_handle *handle;
uint64_t phys;
- ssize_t size;
- uintptr_t __user va;
- ssize_t len;
+ size_t size;
+ uintptr_t va;
+ size_t len;
int refs;
uintptr_t raddr;
int uncached;
@@ -424,12 +424,15 @@
}
static int fastrpc_mmap_find(struct fastrpc_file *fl, int fd,
- uintptr_t __user va, ssize_t len, int mflags, int refs,
+ uintptr_t va, size_t len, int mflags, int refs,
struct fastrpc_mmap **ppmap)
{
struct fastrpc_apps *me = &gfa;
struct fastrpc_mmap *match = NULL, *map = NULL;
struct hlist_node *n;
+
+ if ((va + len) < va)
+ return -EOVERFLOW;
if (mflags == ADSP_MMAP_HEAP_ADDR ||
mflags == ADSP_MMAP_REMOTE_HEAP_ADDR) {
spin_lock(&me->hlock);
@@ -465,17 +468,16 @@
return -ENOTTY;
}
-static int dma_alloc_memory(phys_addr_t *region_start, ssize_t size)
+static int dma_alloc_memory(dma_addr_t *region_phys, void **vaddr, size_t size)
{
struct fastrpc_apps *me = &gfa;
- void *vaddr = NULL;
if (me->dev == NULL) {
pr_err("device adsprpc-mem is not initialized\n");
return -ENODEV;
}
- vaddr = dma_alloc_coherent(me->dev, size, region_start, GFP_KERNEL);
- if (!vaddr) {
+ *vaddr = dma_alloc_coherent(me->dev, size, region_phys, GFP_KERNEL);
+ if (!*vaddr) {
pr_err("ADSPRPC: Failed to allocate %x remote heap memory\n",
(unsigned int)size);
return -ENOMEM;
@@ -484,7 +486,7 @@
}
static int fastrpc_mmap_remove(struct fastrpc_file *fl, uintptr_t va,
- ssize_t len, struct fastrpc_mmap **ppmap)
+ size_t len, struct fastrpc_mmap **ppmap)
{
struct fastrpc_mmap *match = NULL, *map;
struct hlist_node *n;
@@ -560,7 +562,7 @@
}
if (map->phys) {
dma_free_coherent(me->dev, map->size,
- &(map->va), map->phys);
+ (void *)map->va, (dma_addr_t)map->phys);
}
} else {
int destVM[1] = {VMID_HLOS};
@@ -603,7 +605,7 @@
struct fastrpc_session_ctx **session);
static int fastrpc_mmap_create(struct fastrpc_file *fl, int fd,
- unsigned int attr, uintptr_t __user va, ssize_t len, int mflags,
+ unsigned int attr, uintptr_t va, size_t len, int mflags,
struct fastrpc_mmap **ppmap)
{
struct fastrpc_apps *me = &gfa;
@@ -613,7 +615,8 @@
struct fastrpc_channel_ctx *chan = &apps->channel[cid];
struct fastrpc_mmap *map = NULL;
unsigned long attrs;
- phys_addr_t region_start = 0;
+ dma_addr_t region_phys = 0;
+ void *region_vaddr = NULL;
unsigned long flags;
int err = 0, vmid;
@@ -633,12 +636,13 @@
mflags == ADSP_MMAP_REMOTE_HEAP_ADDR) {
map->apps = me;
map->fl = NULL;
- VERIFY(err, !dma_alloc_memory(®ion_start, len));
+ VERIFY(err, !dma_alloc_memory(®ion_phys, ®ion_vaddr,
+ len));
if (err)
goto bail;
- map->phys = (uintptr_t)region_start;
+ map->phys = (uintptr_t)region_phys;
map->size = len;
- map->va = (uintptr_t __user)map->phys;
+ map->va = (uintptr_t)region_vaddr;
} else {
if (map->attr && (map->attr & FASTRPC_ATTR_KEEP_MAP)) {
pr_info("adsprpc: buffer mapped with persist attr %x\n",
@@ -654,10 +658,6 @@
if (err)
goto bail;
- map->uncached = !ION_IS_CACHED(flags);
- if (map->attr & FASTRPC_ATTR_NOVA)
- map->uncached = 1;
-
map->secure = flags & ION_FLAG_SECURE;
if (map->secure) {
if (!fl->secsctx)
@@ -670,9 +670,15 @@
sess = fl->secsctx;
else
sess = fl->sctx;
+
VERIFY(err, !IS_ERR_OR_NULL(sess));
if (err)
goto bail;
+
+ map->uncached = !ION_IS_CACHED(flags);
+ if (map->attr & FASTRPC_ATTR_NOVA && !sess->smmu.coherent)
+ map->uncached = 1;
+
VERIFY(err, !IS_ERR_OR_NULL(map->buf = dma_buf_get(fd)));
if (err)
goto bail;
@@ -738,7 +744,7 @@
return err;
}
-static int fastrpc_buf_alloc(struct fastrpc_file *fl, ssize_t size,
+static int fastrpc_buf_alloc(struct fastrpc_file *fl, size_t size,
struct fastrpc_buf **obuf)
{
int err = 0, vmid;
@@ -1116,7 +1122,7 @@
int outbufs = REMOTE_SCALARS_OUTBUFS(sc);
int handles, bufs = inbufs + outbufs;
uintptr_t args;
- ssize_t rlen = 0, copylen = 0, metalen = 0;
+ size_t rlen = 0, copylen = 0, metalen = 0;
int i, oix;
int err = 0;
int mflags = 0;
@@ -1130,8 +1136,8 @@
ipage = pages;
for (i = 0; i < bufs; ++i) {
- uintptr_t __user buf = (uintptr_t __user)lpra[i].buf.pv;
- ssize_t len = lpra[i].buf.len;
+ uintptr_t buf = (uintptr_t)lpra[i].buf.pv;
+ size_t len = lpra[i].buf.len;
if (ctx->fds[i] && (ctx->fds[i] != -1))
fastrpc_mmap_create(ctx->fl, ctx->fds[i],
@@ -1147,14 +1153,14 @@
goto bail;
ipage += 1;
}
- metalen = copylen = (ssize_t)&ipage[0] + (sizeof(uint64_t) * M_FDLIST) +
+ metalen = copylen = (size_t)&ipage[0] + (sizeof(uint64_t) * M_FDLIST) +
(sizeof(uint32_t) * M_CRCLIST);
/* calculate len requreed for copying */
for (oix = 0; oix < inbufs + outbufs; ++oix) {
int i = ctx->overps[oix]->raix;
uintptr_t mstart, mend;
- ssize_t len = lpra[i].buf.len;
+ size_t len = lpra[i].buf.len;
if (!len)
continue;
@@ -1204,7 +1210,7 @@
for (i = 0; rpra && i < inbufs + outbufs; ++i) {
struct fastrpc_mmap *map = ctx->maps[i];
uint64_t buf = ptr_to_uint64(lpra[i].buf.pv);
- ssize_t len = lpra[i].buf.len;
+ size_t len = lpra[i].buf.len;
rpra[i].buf.pv = 0;
rpra[i].buf.len = len;
@@ -1213,7 +1219,7 @@
if (map) {
struct vm_area_struct *vma;
uintptr_t offset;
- int num = buf_num_pages(buf, len);
+ uint64_t num = buf_num_pages(buf, len);
int idx = list[i].pgidx;
if (map->attr & FASTRPC_ATTR_NOVA) {
@@ -1256,9 +1262,9 @@
for (oix = 0; oix < inbufs + outbufs; ++oix) {
int i = ctx->overps[oix]->raix;
struct fastrpc_mmap *map = ctx->maps[i];
- ssize_t mlen;
+ size_t mlen;
uint64_t buf;
- ssize_t len = lpra[i].buf.len;
+ size_t len = lpra[i].buf.len;
if (!len)
continue;
@@ -1496,12 +1502,12 @@
INIT_HLIST_HEAD(&me->drivers);
spin_lock_init(&me->hlock);
+ mutex_init(&me->smd_mutex);
me->channel = &gcinfo[0];
for (i = 0; i < NUM_CHANNELS; i++) {
init_completion(&me->channel[i].work);
init_completion(&me->channel[i].workport);
me->channel[i].sesscount = 0;
- mutex_init(&me->channel[i].mut);
}
}
@@ -1619,7 +1625,7 @@
int destVMperm[1] = {PERM_READ | PERM_WRITE | PERM_EXEC};
int hlosVMperm[1] = {PERM_READ | PERM_WRITE | PERM_EXEC};
- VERIFY(err, !fastrpc_channel_open(fl));
+ VERIFY(err, 0 == (err = fastrpc_channel_open(fl)));
if (err)
goto bail;
if (init->flags == FASTRPC_INIT_ATTACH) {
@@ -1645,9 +1651,9 @@
int mflags = 0;
struct {
int pgid;
- int namelen;
- int filelen;
- int pageslen;
+ unsigned int namelen;
+ unsigned int filelen;
+ unsigned int pageslen;
int attrs;
int siglen;
} inbuf;
@@ -1656,14 +1662,22 @@
inbuf.namelen = strlen(current->comm) + 1;
inbuf.filelen = init->filelen;
fl->pd = 1;
+
+ VERIFY(err, access_ok(0, (void __user *)init->file,
+ init->filelen));
+ if (err)
+ goto bail;
if (init->filelen) {
VERIFY(err, !fastrpc_mmap_create(fl, init->filefd, 0,
init->file, init->filelen, mflags, &file));
if (err)
goto bail;
}
-
inbuf.pageslen = 1;
+ VERIFY(err, access_ok(1, (void __user *)init->mem,
+ init->memlen));
+ if (err)
+ goto bail;
VERIFY(err, !fastrpc_mmap_create(fl, init->memfd, 0,
init->mem, init->memlen, mflags, &mem));
if (err)
@@ -1712,12 +1726,12 @@
} else if (init->flags == FASTRPC_INIT_CREATE_STATIC) {
remote_arg_t ra[3];
uint64_t phys = 0;
- ssize_t size = 0;
+ size_t size = 0;
int fds[3];
struct {
int pgid;
- int namelen;
- int pageslen;
+ unsigned int namelen;
+ unsigned int pageslen;
} inbuf;
if (!init->filelen)
@@ -1959,7 +1973,7 @@
struct {
int pid;
uintptr_t vaddrout;
- ssize_t size;
+ size_t size;
} inargs;
inargs.pid = fl->tgid;
@@ -2038,7 +2052,7 @@
}
static int fastrpc_mmap_remove(struct fastrpc_file *fl, uintptr_t va,
- ssize_t len, struct fastrpc_mmap **ppmap);
+ size_t len, struct fastrpc_mmap **ppmap);
static void fastrpc_mmap_add(struct fastrpc_mmap *map);
@@ -2091,12 +2105,12 @@
struct fastrpc_mmap *map = NULL;
int err = 0;
- if (!fastrpc_mmap_find(fl, ud->fd, (uintptr_t __user)ud->vaddrin,
+ if (!fastrpc_mmap_find(fl, ud->fd, (uintptr_t)ud->vaddrin,
ud->size, ud->flags, 1, &map))
return 0;
VERIFY(err, !fastrpc_mmap_create(fl, ud->fd, 0,
- (uintptr_t __user)ud->vaddrin, ud->size,
+ (uintptr_t)ud->vaddrin, ud->size,
ud->flags, &map));
if (err)
goto bail;
@@ -2122,7 +2136,7 @@
ctx->chan = NULL;
glink_unregister_link_state_cb(ctx->link.link_notify_handle);
ctx->link.link_notify_handle = NULL;
- mutex_unlock(&ctx->mut);
+ mutex_unlock(&me->smd_mutex);
pr_info("'closed /dev/%s c %d %d'\n", gcinfo[cid].name,
MAJOR(me->dev_no), cid);
}
@@ -2215,15 +2229,6 @@
link->port_state = FASTRPC_LINK_DISCONNECTED;
break;
case GLINK_REMOTE_DISCONNECTED:
- mutex_lock(&me->channel[cid].mut);
- if (me->channel[cid].chan) {
- link->port_state = FASTRPC_LINK_REMOTE_DISCONNECTING;
- fastrpc_glink_close(me->channel[cid].chan, cid);
- me->channel[cid].chan = NULL;
- } else {
- link->port_state = FASTRPC_LINK_DISCONNECTED;
- }
- mutex_unlock(&me->channel[cid].mut);
break;
default:
break;
@@ -2234,20 +2239,23 @@
struct fastrpc_session_ctx **session)
{
int err = 0;
+ struct fastrpc_apps *me = &gfa;
- mutex_lock(&chan->mut);
+ mutex_lock(&me->smd_mutex);
if (!*session)
err = fastrpc_session_alloc_locked(chan, secure, session);
- mutex_unlock(&chan->mut);
+ mutex_unlock(&me->smd_mutex);
return err;
}
static void fastrpc_session_free(struct fastrpc_channel_ctx *chan,
struct fastrpc_session_ctx *session)
{
- mutex_lock(&chan->mut);
+ struct fastrpc_apps *me = &gfa;
+
+ mutex_lock(&me->smd_mutex);
session->used = 0;
- mutex_unlock(&chan->mut);
+ mutex_unlock(&me->smd_mutex);
}
static int fastrpc_file_free(struct fastrpc_file *fl)
@@ -2280,7 +2288,7 @@
}
if (fl->ssrcount == fl->apps->channel[cid].ssrcount)
kref_put_mutex(&fl->apps->channel[cid].kref,
- fastrpc_channel_close, &fl->apps->channel[cid].mut);
+ fastrpc_channel_close, &fl->apps->smd_mutex);
if (fl->sctx)
fastrpc_session_free(&fl->apps->channel[cid], fl->sctx);
if (fl->secsctx)
@@ -2357,20 +2365,6 @@
return err;
}
-static void fastrpc_glink_stop(int cid)
-{
- int err = 0;
- struct fastrpc_glink_info *link;
-
- VERIFY(err, (cid >= 0 && cid < NUM_CHANNELS));
- if (err)
- return;
- link = &gfa.channel[cid].link;
-
- if (link->port_state == FASTRPC_LINK_CONNECTED)
- link->port_state = FASTRPC_LINK_REMOTE_DISCONNECTING;
-}
-
static void fastrpc_glink_close(void *chan, int cid)
{
int err = 0;
@@ -2548,20 +2542,23 @@
struct fastrpc_apps *me = &gfa;
int cid, err = 0;
+ mutex_lock(&me->smd_mutex);
+
VERIFY(err, fl && fl->sctx);
if (err)
- return err;
+ goto bail;
cid = fl->cid;
VERIFY(err, cid >= 0 && cid < NUM_CHANNELS);
if (err)
goto bail;
- mutex_lock(&me->channel[cid].mut);
if (me->channel[cid].ssrcount !=
me->channel[cid].prevssrcount) {
if (!me->channel[cid].issubsystemup) {
VERIFY(err, 0);
- if (err)
+ if (err) {
+ err = -ENOTCONN;
goto bail;
+ }
}
}
fl->ssrcount = me->channel[cid].ssrcount;
@@ -2574,11 +2571,9 @@
if (err)
goto bail;
- mutex_unlock(&me->channel[cid].mut);
VERIFY(err,
wait_for_completion_timeout(&me->channel[cid].workport,
RPC_TIMEOUT));
- mutex_lock(&me->channel[cid].mut);
if (err) {
me->channel[cid].chan = NULL;
goto bail;
@@ -2603,7 +2598,7 @@
}
bail:
- mutex_unlock(&me->channel[cid].mut);
+ mutex_unlock(&me->smd_mutex);
return err;
}
@@ -2866,7 +2861,7 @@
p.init.init.memlen < INIT_MEMLEN_MAX);
if (err)
goto bail;
- VERIFY(err, 0 == fastrpc_init_process(fl, &p.init));
+ VERIFY(err, 0 == (err = fastrpc_init_process(fl, &p.init)));
if (err)
goto bail;
break;
@@ -2892,14 +2887,16 @@
ctx = container_of(nb, struct fastrpc_channel_ctx, nb);
cid = ctx - &me->channel[0];
if (code == SUBSYS_BEFORE_SHUTDOWN) {
- mutex_lock(&ctx->mut);
+ mutex_lock(&me->smd_mutex);
ctx->ssrcount++;
ctx->issubsystemup = 0;
- pr_info("'restart notifier: /dev/%s c %d %d'\n",
- gcinfo[cid].name, MAJOR(me->dev_no), cid);
- if (ctx->chan)
- fastrpc_glink_stop(cid);
- mutex_unlock(&ctx->mut);
+ if (ctx->chan) {
+ fastrpc_glink_close(ctx->chan, cid);
+ ctx->chan = NULL;
+ pr_info("'restart notifier: closed /dev/%s c %d %d'\n",
+ gcinfo[cid].name, MAJOR(me->dev_no), cid);
+ }
+ mutex_unlock(&me->smd_mutex);
if (cid == 0)
me->staticpd_flags = 0;
fastrpc_notify_drivers(me, cid);
@@ -3071,15 +3068,15 @@
static void fastrpc_deinit(void)
{
+ struct fastrpc_apps *me = &gfa;
struct fastrpc_channel_ctx *chan = gcinfo;
int i, j;
for (i = 0; i < NUM_CHANNELS; i++, chan++) {
if (chan->chan) {
kref_put_mutex(&chan->kref,
- fastrpc_channel_close, &chan->mut);
+ fastrpc_channel_close, &me->smd_mutex);
chan->chan = NULL;
- mutex_destroy(&chan->mut);
}
for (j = 0; j < NUM_SESSIONS; j++) {
struct fastrpc_session_ctx *sess = &chan->session[j];
diff --git a/drivers/char/adsprpc_compat.c b/drivers/char/adsprpc_compat.c
index 21ad3f9..0f07483 100644
--- a/drivers/char/adsprpc_compat.c
+++ b/drivers/char/adsprpc_compat.c
@@ -42,7 +42,7 @@
struct compat_remote_buf {
compat_uptr_t pv; /* buffer pointer */
- compat_ssize_t len; /* length of buffer */
+ compat_size_t len; /* length of buffer */
};
union compat_remote_arg {
@@ -78,13 +78,13 @@
compat_int_t fd; /* ion fd */
compat_uint_t flags; /* flags for dsp to map with */
compat_uptr_t vaddrin; /* optional virtual address */
- compat_ssize_t size; /* size */
+ compat_size_t size; /* size */
compat_uptr_t vaddrout; /* dsps virtual address */
};
struct compat_fastrpc_ioctl_munmap {
compat_uptr_t vaddrout; /* address to unmap */
- compat_ssize_t size; /* size */
+ compat_size_t size; /* size */
};
struct compat_fastrpc_ioctl_init {
@@ -128,7 +128,7 @@
unsigned int cmd)
{
compat_uint_t u, sc;
- compat_ssize_t s;
+ compat_size_t s;
compat_uptr_t p;
struct fastrpc_ioctl_invoke_crc *inv;
union compat_remote_arg *pra32;
@@ -190,7 +190,7 @@
{
compat_uint_t u;
compat_int_t i;
- compat_ssize_t s;
+ compat_size_t s;
compat_uptr_t p;
int err;
@@ -224,7 +224,7 @@
struct fastrpc_ioctl_munmap __user *unmap)
{
compat_uptr_t p;
- compat_ssize_t s;
+ compat_size_t s;
int err;
err = get_user(p, &unmap32->vaddrout);
diff --git a/drivers/char/adsprpc_shared.h b/drivers/char/adsprpc_shared.h
index e2f8983..535160a 100644
--- a/drivers/char/adsprpc_shared.h
+++ b/drivers/char/adsprpc_shared.h
@@ -122,7 +122,7 @@
struct remote_buf64 {
uint64_t pv;
- int64_t len;
+ uint64_t len;
};
struct remote_dma_handle64 {
@@ -141,7 +141,7 @@
struct remote_buf {
void *pv; /* buffer pointer */
- ssize_t len; /* length of buffer */
+ size_t len; /* length of buffer */
};
struct remote_dma_handle {
@@ -181,30 +181,30 @@
struct fastrpc_ioctl_init {
uint32_t flags; /* one of FASTRPC_INIT_* macros */
- uintptr_t __user file; /* pointer to elf file */
- int32_t filelen; /* elf file length */
+ uintptr_t file; /* pointer to elf file */
+ uint32_t filelen; /* elf file length */
int32_t filefd; /* ION fd for the file */
- uintptr_t __user mem; /* mem for the PD */
- int32_t memlen; /* mem length */
+ uintptr_t mem; /* mem for the PD */
+ uint32_t memlen; /* mem length */
int32_t memfd; /* ION fd for the mem */
};
struct fastrpc_ioctl_init_attrs {
struct fastrpc_ioctl_init init;
int attrs;
- int siglen;
+ unsigned int siglen;
};
struct fastrpc_ioctl_munmap {
uintptr_t vaddrout; /* address to unmap */
- ssize_t size; /* size */
+ size_t size; /* size */
};
struct fastrpc_ioctl_mmap {
int fd; /* ion fd */
uint32_t flags; /* flags for dsp to map with */
- uintptr_t __user *vaddrin; /* optional virtual address */
- ssize_t size; /* size */
+ uintptr_t vaddrin; /* optional virtual address */
+ size_t size; /* size */
uintptr_t vaddrout; /* dsps virtual address */
};
@@ -216,9 +216,9 @@
};
struct fastrpc_ioctl_perf { /* kernel performance data */
- uintptr_t __user data;
+ uintptr_t data;
uint32_t numkeys;
- uintptr_t __user keys;
+ uintptr_t keys;
};
#define FASTRPC_CONTROL_LATENCY (1)
@@ -269,7 +269,7 @@
static inline struct smq_invoke_buf *smq_invoke_buf_start(remote_arg64_t *pra,
uint32_t sc)
{
- int len = REMOTE_SCALARS_LENGTH(sc);
+ unsigned int len = REMOTE_SCALARS_LENGTH(sc);
return (struct smq_invoke_buf *)(&pra[len]);
}
@@ -277,7 +277,7 @@
static inline struct smq_phy_page *smq_phy_page_start(uint32_t sc,
struct smq_invoke_buf *buf)
{
- int nTotal = REMOTE_SCALARS_LENGTH(sc);
+ unsigned int nTotal = REMOTE_SCALARS_LENGTH(sc);
return (struct smq_phy_page *)(&buf[nTotal]);
}
diff --git a/drivers/char/diag/diagfwd.c b/drivers/char/diag/diagfwd.c
index da13912..f157a2f 100644
--- a/drivers/char/diag/diagfwd.c
+++ b/drivers/char/diag/diagfwd.c
@@ -1687,10 +1687,10 @@
break;
case TYPE_CMD:
if (peripheral >= 0 && peripheral < NUM_PERIPHERALS) {
- diagfwd_write_done(peripheral, type, num);
DIAG_LOG(DIAG_DEBUG_PERIPHERALS,
"Marking buffer as free after write done p: %d, t: %d, buf_num: %d\n",
peripheral, type, num);
+ diagfwd_write_done(peripheral, type, num);
}
if (peripheral == APPS_DATA ||
ctxt == DIAG_MEMORY_DEVICE_MODE) {
diff --git a/drivers/char/diag/diagfwd_peripheral.c b/drivers/char/diag/diagfwd_peripheral.c
index 4d6ae23..c7bd2205 100644
--- a/drivers/char/diag/diagfwd_peripheral.c
+++ b/drivers/char/diag/diagfwd_peripheral.c
@@ -205,7 +205,8 @@
}
if (buf->len < max_size) {
- if (driver->logging_mode == DIAG_MEMORY_DEVICE_MODE) {
+ if (driver->logging_mode == DIAG_MEMORY_DEVICE_MODE ||
+ driver->logging_mode == DIAG_MULTI_MODE) {
ch = &diag_md[DIAG_LOCAL_PROC];
for (i = 0; ch != NULL &&
i < ch->num_tbl_entries; i++) {
@@ -478,7 +479,8 @@
flag_buf_1 = 1;
temp_fwdinfo_cpd = fwd_info->buf_1;
if (fwd_info->type == TYPE_DATA) {
- for (i = 0; i <= (fwd_info->num_pd - 2); i++)
+ for (i = 0; (i <= (fwd_info->num_pd - 2)) &&
+ fwd_info->buf_upd[i][0]; i++)
temp_buf_upd[i] =
fwd_info->buf_upd[i][0]->data_raw;
}
@@ -487,7 +489,8 @@
flag_buf_2 = 1;
temp_fwdinfo_cpd = fwd_info->buf_2;
if (fwd_info->type == TYPE_DATA) {
- for (i = 0; i <= (fwd_info->num_pd - 2); i++)
+ for (i = 0; (i <= (fwd_info->num_pd - 2)) &&
+ fwd_info->buf_upd[i][1]; i++)
temp_buf_upd[i] =
fwd_info->buf_upd[i][1]->data_raw;
}
@@ -557,6 +560,8 @@
else
temp_fwdinfo_upd =
fwd_info->buf_upd[i][1];
+ if (!temp_fwdinfo_upd)
+ break;
temp_fwdinfo_upd->ctxt &= 0x00FFFFFF;
temp_fwdinfo_upd->ctxt |=
(SET_PD_CTXT(ctxt_upd[i]));
@@ -1631,6 +1636,10 @@
fail_return:
diag_ws_release();
atomic_set(&temp_buf->in_busy, 0);
+ DIAG_LOG(DIAG_DEBUG_PERIPHERALS,
+ "Buffer for core PD is marked free, p: %d, t: %d, buf_num: %d\n",
+ fwd_info->peripheral, fwd_info->type,
+ GET_BUF_NUM(temp_buf->ctxt));
}
static void diagfwd_queue_read(struct diagfwd_info *fwd_info)
diff --git a/drivers/clk/qcom/clk-alpha-pll.c b/drivers/clk/qcom/clk-alpha-pll.c
index bf9b99d..514c0ad 100644
--- a/drivers/clk/qcom/clk-alpha-pll.c
+++ b/drivers/clk/qcom/clk-alpha-pll.c
@@ -401,8 +401,8 @@
{
struct clk_alpha_pll *pll = to_clk_alpha_pll(hw);
const struct pll_vco *vco;
- u32 l, off = pll->offset;
- u64 a;
+ u32 l = 0, off = pll->offset;
+ u64 a = 0;
rate = alpha_pll_round_rate(pll, rate, prate, &l, &a);
vco = alpha_pll_find_vco(pll, rate);
@@ -668,9 +668,9 @@
{
struct clk_alpha_pll *pll = to_clk_alpha_pll(hw);
unsigned long rrate;
- u32 regval, l, off = pll->offset;
- u64 a;
- int ret;
+ u32 regval = 0, l = 0, off = pll->offset;
+ u64 a = 0;
+ int ret = 0;
ret = regmap_read(pll->clkr.regmap, off + PLL_MODE, ®val);
if (ret)
@@ -1146,8 +1146,8 @@
unsigned long rrate;
bool is_enabled;
int ret;
- u32 l, val, off = pll->offset;
- u64 a;
+ u32 l = 0, val = 0, off = pll->offset;
+ u64 a = 0;
rrate = alpha_pll_round_rate(pll, rate, prate, &l, &a);
/*
diff --git a/drivers/clk/qcom/clk-cpu-a7.c b/drivers/clk/qcom/clk-cpu-a7.c
index c0cc00f8..3e8a75d 100644
--- a/drivers/clk/qcom/clk-cpu-a7.c
+++ b/drivers/clk/qcom/clk-cpu-a7.c
@@ -664,6 +664,11 @@
/* Put proxy vote for APSS PLL */
clk_prepare_enable(apcs_cpu_pll.clkr.hw.clk);
+ /* Reconfigure APSS RCG */
+ ret = clk_set_rate(apcs_clk.clkr.hw.clk, sys_apc0_aux_clk.rrate);
+ if (ret)
+ dev_err(&pdev->dev, "Unable to set aux rate on apcs_clk\n");
+
/* Set to TURBO boot frequency */
ret = clk_set_rate(apcs_clk.clkr.hw.clk, a7cc_clk_init_rate);
if (ret)
diff --git a/drivers/clk/qcom/clk-cpu-osm.c b/drivers/clk/qcom/clk-cpu-osm.c
index fb0b504..b6204cb 100644
--- a/drivers/clk/qcom/clk-cpu-osm.c
+++ b/drivers/clk/qcom/clk-cpu-osm.c
@@ -55,9 +55,6 @@
#define VOLT_REG 0x114
#define CORE_DCVS_CTRL 0xbc
-#define EFUSE_SHIFT(v1) ((v1) ? 3 : 2)
-#define EFUSE_MASK 0x7
-
#define DCVS_PERF_STATE_DESIRED_REG_0_V1 0x780
#define DCVS_PERF_STATE_DESIRED_REG_0_V2 0x920
#define DCVS_PERF_STATE_DESIRED_REG(n, v1) \
@@ -77,6 +74,7 @@
u16 virtual_corner;
u16 open_loop_volt;
long frequency;
+ u16 ccount;
};
struct clk_osm {
@@ -90,11 +88,11 @@
u32 num_entries;
u32 cluster_num;
u32 core_num;
+ unsigned long rate;
u64 total_cycle_counter;
u32 prev_cycle_counter;
u32 max_core_count;
u32 mx_turbo_freq;
- unsigned int cpr_rc;
};
static bool is_sdm845v1;
@@ -153,6 +151,24 @@
return -EINVAL;
}
+static int clk_osm_set_rate(struct clk_hw *hw, unsigned long rate,
+ unsigned long parent_rate)
+{
+ struct clk_osm *c = to_clk_osm(hw);
+
+ c->rate = rate;
+
+ return 0;
+}
+
+static unsigned long clk_osm_recalc_rate(struct clk_hw *hw,
+ unsigned long parent_rate)
+{
+ struct clk_osm *c = to_clk_osm(hw);
+
+ return c->rate;
+}
+
static long clk_osm_round_rate(struct clk_hw *hw, unsigned long rate,
unsigned long *parent_rate)
{
@@ -294,7 +310,7 @@
return cpuclk->osm_table[index].frequency;
}
-static struct clk_ops clk_ops_l3_osm = {
+static const struct clk_ops clk_ops_l3_osm = {
.round_rate = clk_osm_round_rate,
.list_rate = clk_osm_list_rate,
.recalc_rate = l3_clk_recalc_rate,
@@ -302,8 +318,20 @@
.debug_init = clk_debug_measure_add,
};
-static struct clk_ops clk_ops_core;
-static struct clk_ops clk_ops_cpu_osm;
+static const struct clk_ops clk_ops_core = {
+ .set_rate = clk_cpu_set_rate,
+ .round_rate = clk_cpu_round_rate,
+ .recalc_rate = clk_cpu_recalc_rate,
+ .debug_init = clk_debug_measure_add,
+};
+
+static const struct clk_ops clk_ops_cpu_osm = {
+ .set_rate = clk_osm_set_rate,
+ .round_rate = clk_osm_round_rate,
+ .recalc_rate = clk_osm_recalc_rate,
+ .list_rate = clk_osm_list_rate,
+ .debug_init = clk_debug_measure_add,
+};
static struct clk_init_data osm_clks_init[] = {
[0] = {
@@ -639,7 +667,7 @@
struct clk_osm *c, *parent;
struct clk_hw *p_hw;
int ret;
- unsigned int i;
+ unsigned int i, prev_cc = 0;
unsigned int xo_kHz;
c = osm_configure_policy(policy);
@@ -686,8 +714,12 @@
if (core_count != parent->max_core_count)
table[i].frequency = CPUFREQ_ENTRY_INVALID;
- /* Two of the same frequencies means end of table */
- if (i > 0 && table[i - 1].driver_data == table[i].driver_data) {
+ /*
+ * Two of the same frequencies with the same core counts means
+ * end of table.
+ */
+ if (i > 0 && table[i - 1].driver_data == table[i].driver_data
+ && prev_cc == core_count) {
struct cpufreq_frequency_table *prev = &table[i - 1];
if (prev->frequency == CPUFREQ_ENTRY_INVALID) {
@@ -697,6 +729,7 @@
break;
}
+ prev_cc = core_count;
}
table[i].frequency = CPUFREQ_TABLE_END;
@@ -940,6 +973,7 @@
data = clk_osm_read_reg(c, FREQ_REG + i * OSM_REG_SIZE);
src = ((data & GENMASK(31, 30)) >> 30);
lval = (data & GENMASK(7, 0));
+ c->osm_table[i].ccount = CORE_COUNT_VAL(data);
if (!src)
c->osm_table[i].frequency = OSM_INIT_RATE;
@@ -956,8 +990,10 @@
c->osm_table[i].virtual_corner,
c->osm_table[i].open_loop_volt);
- if (i > 0 && j == OSM_TABLE_SIZE && c->osm_table[i].frequency ==
- c->osm_table[i - 1].frequency)
+ if (i > 0 && j == OSM_TABLE_SIZE &&
+ c->osm_table[i].frequency ==
+ c->osm_table[i - 1].frequency &&
+ c->osm_table[i].ccount == c->osm_table[i - 1].ccount)
j = i;
}
@@ -979,8 +1015,7 @@
return -ENOMEM;
for (i = 0; i < j; i++) {
- if (c->osm_table[i].frequency < c->mx_turbo_freq ||
- (c->cpr_rc > 1))
+ if (c->osm_table[i].frequency < c->mx_turbo_freq)
vdd->vdd_uv[i] = RPMH_REGULATOR_LEVEL_NOM;
else
vdd->vdd_uv[i] = RPMH_REGULATOR_LEVEL_TURBO;
@@ -1071,19 +1106,68 @@
perfcl_clk.max_core_count = 2;
}
+/* Request MX supply if configured in device tree */
+static int clk_cpu_osm_request_mx_supply(struct device *dev)
+{
+ u32 *array;
+ int rc;
+
+ if (!of_find_property(dev->of_node, "qcom,mx-turbo-freq", NULL)) {
+ osm_clks_init[l3_clk.cluster_num].vdd_class = NULL;
+ osm_clks_init[pwrcl_clk.cluster_num].vdd_class = NULL;
+ return 0;
+ }
+
+ vdd_l3_mx_ao.regulator[0] = devm_regulator_get(dev, "vdd_l3_mx_ao");
+ if (IS_ERR(vdd_l3_mx_ao.regulator[0])) {
+ rc = PTR_ERR(vdd_l3_mx_ao.regulator[0]);
+ if (rc != -EPROBE_DEFER)
+ dev_err(dev, "Unable to get vdd_l3_mx_ao regulator, rc=%d\n",
+ rc);
+ return rc;
+ }
+
+ vdd_pwrcl_mx_ao.regulator[0] = devm_regulator_get(dev,
+ "vdd_pwrcl_mx_ao");
+ if (IS_ERR(vdd_pwrcl_mx_ao.regulator[0])) {
+ rc = PTR_ERR(vdd_pwrcl_mx_ao.regulator[0]);
+ if (rc != -EPROBE_DEFER)
+ dev_err(dev, "Unable to get vdd_pwrcl_mx_ao regulator, rc=%d\n",
+ rc);
+ return rc;
+ }
+
+ array = kcalloc(MAX_CLUSTER_CNT, sizeof(*array), GFP_KERNEL);
+ if (!array)
+ return -ENOMEM;
+
+ rc = of_property_read_u32_array(dev->of_node, "qcom,mx-turbo-freq",
+ array, MAX_CLUSTER_CNT);
+ if (rc) {
+ dev_err(dev, "unable to read qcom,mx-turbo-freq property, rc=%d\n",
+ rc);
+ kfree(array);
+ return rc;
+ }
+
+ l3_clk.mx_turbo_freq = array[l3_clk.cluster_num];
+ pwrcl_clk.mx_turbo_freq = array[pwrcl_clk.cluster_num];
+ perfcl_clk.mx_turbo_freq = array[perfcl_clk.cluster_num];
+
+ kfree(array);
+
+ return 0;
+}
+
static int clk_cpu_osm_driver_probe(struct platform_device *pdev)
{
int rc = 0, i, cpu;
- bool is_sdm670 = false;
- u32 *array;
- u32 val, pte_efuse;
- void __iomem *vbase;
+ u32 val;
int num_clks = ARRAY_SIZE(osm_qcom_clk_hws);
struct clk *ext_xo_clk, *clk;
struct clk_osm *osm_clk;
struct device *dev = &pdev->dev;
struct clk_onecell_data *clk_data;
- struct resource *res;
struct cpu_cycle_counter_cb cb = {
.get_cpu_cycle_counter = clk_osm_get_cpu_cycle_counter,
};
@@ -1103,68 +1187,12 @@
"qcom,clk-cpu-osm");
if (of_device_is_compatible(pdev->dev.of_node,
- "qcom,clk-cpu-osm-sdm670")) {
- is_sdm670 = true;
+ "qcom,clk-cpu-osm-sdm670"))
clk_cpu_osm_driver_sdm670_fixup();
- }
- res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "cpr_rc");
- if (res) {
- vbase = devm_ioremap(&pdev->dev, res->start,
- resource_size(res));
- if (!vbase) {
- dev_err(&pdev->dev, "Unable to map in cpr_rc base\n");
- return -ENOMEM;
- }
- pte_efuse = readl_relaxed(vbase);
- l3_clk.cpr_rc = pwrcl_clk.cpr_rc = perfcl_clk.cpr_rc =
- ((pte_efuse >> EFUSE_SHIFT(is_sdm845v1 | is_sdm670))
- & EFUSE_MASK);
- pr_info("LOCAL_CPR_RC: %u\n", l3_clk.cpr_rc);
- devm_iounmap(&pdev->dev, vbase);
- } else {
- dev_err(&pdev->dev,
- "Unable to get platform resource for cpr_rc\n");
- return -ENOMEM;
- }
-
- vdd_l3_mx_ao.regulator[0] = devm_regulator_get(&pdev->dev,
- "vdd_l3_mx_ao");
- if (IS_ERR(vdd_l3_mx_ao.regulator[0])) {
- if (PTR_ERR(vdd_l3_mx_ao.regulator[0]) != -EPROBE_DEFER)
- dev_err(&pdev->dev,
- "Unable to get vdd_l3_mx_ao regulator\n");
- return PTR_ERR(vdd_l3_mx_ao.regulator[0]);
- }
-
- vdd_pwrcl_mx_ao.regulator[0] = devm_regulator_get(&pdev->dev,
- "vdd_pwrcl_mx_ao");
- if (IS_ERR(vdd_pwrcl_mx_ao.regulator[0])) {
- if (PTR_ERR(vdd_pwrcl_mx_ao.regulator[0]) != -EPROBE_DEFER)
- dev_err(&pdev->dev,
- "Unable to get vdd_pwrcl_mx_ao regulator\n");
- return PTR_ERR(vdd_pwrcl_mx_ao.regulator[0]);
- }
-
- array = devm_kcalloc(&pdev->dev, MAX_CLUSTER_CNT, sizeof(*array),
- GFP_KERNEL);
- if (!array)
- return -ENOMEM;
-
- rc = of_property_read_u32_array(pdev->dev.of_node, "qcom,mx-turbo-freq",
- array, MAX_CLUSTER_CNT);
- if (rc) {
- dev_err(&pdev->dev, "unable to find qcom,mx-turbo-freq property, rc=%d\n",
- rc);
- devm_kfree(&pdev->dev, array);
+ rc = clk_cpu_osm_request_mx_supply(dev);
+ if (rc)
return rc;
- }
-
- l3_clk.mx_turbo_freq = array[l3_clk.cluster_num];
- pwrcl_clk.mx_turbo_freq = array[pwrcl_clk.cluster_num];
- perfcl_clk.mx_turbo_freq = array[perfcl_clk.cluster_num];
-
- devm_kfree(&pdev->dev, array);
clk_data = devm_kzalloc(&pdev->dev, sizeof(struct clk_onecell_data),
GFP_KERNEL);
@@ -1220,16 +1248,6 @@
spin_lock_init(&pwrcl_clk.lock);
spin_lock_init(&perfcl_clk.lock);
- clk_ops_core = clk_dummy_ops;
- clk_ops_core.set_rate = clk_cpu_set_rate;
- clk_ops_core.round_rate = clk_cpu_round_rate;
- clk_ops_core.recalc_rate = clk_cpu_recalc_rate;
-
- clk_ops_cpu_osm = clk_dummy_ops;
- clk_ops_cpu_osm.round_rate = clk_osm_round_rate;
- clk_ops_cpu_osm.list_rate = clk_osm_list_rate;
- clk_ops_cpu_osm.debug_init = clk_debug_measure_add;
-
/* Register OSM l3, pwr and perf clocks with Clock Framework */
for (i = 0; i < num_clks; i++) {
if (!osm_qcom_clk_hws[i])
diff --git a/drivers/clk/qcom/gcc-sdxpoorwills.c b/drivers/clk/qcom/gcc-sdxpoorwills.c
index 1b5cf61..52a18ea 100644
--- a/drivers/clk/qcom/gcc-sdxpoorwills.c
+++ b/drivers/clk/qcom/gcc-sdxpoorwills.c
@@ -1353,9 +1353,22 @@
},
};
+static struct clk_branch gcc_pcie_0_clkref_clk = {
+ .halt_reg = 0x88004,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x88004,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_pcie_0_clkref_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
static struct clk_branch gcc_pcie_aux_clk = {
.halt_reg = 0x37020,
- .halt_check = BRANCH_HALT_VOTED,
+ .halt_check = BRANCH_HALT_DELAY,
.clkr = {
.enable_reg = 0x6d00c,
.enable_mask = BIT(3),
@@ -1414,7 +1427,7 @@
static struct clk_branch gcc_pcie_pipe_clk = {
.halt_reg = 0x37028,
- .halt_check = BRANCH_HALT_VOTED,
+ .halt_check = BRANCH_HALT_DELAY,
.clkr = {
.enable_reg = 0x6d00c,
.enable_mask = BIT(4),
@@ -1695,14 +1708,26 @@
},
};
-static struct clk_branch gcc_usb3_phy_pipe_clk = {
- .halt_reg = 0xb054,
- .halt_check = BRANCH_HALT,
+static struct clk_gate2 gcc_usb3_phy_pipe_clk = {
+ .udelay = 500,
.clkr = {
.enable_reg = 0xb054,
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "gcc_usb3_phy_pipe_clk",
+ .ops = &clk_gate2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_usb3_prim_clkref_clk = {
+ .halt_reg = 0x88000,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x88000,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_usb3_prim_clkref_clk",
.ops = &clk_branch2_ops,
},
},
@@ -1782,6 +1807,7 @@
[GCC_MSS_CFG_AHB_CLK] = &gcc_mss_cfg_ahb_clk.clkr,
[GCC_MSS_GPLL0_DIV_CLK_SRC] = &gcc_mss_gpll0_div_clk_src.clkr,
[GCC_MSS_SNOC_AXI_CLK] = &gcc_mss_snoc_axi_clk.clkr,
+ [GCC_PCIE_0_CLKREF_CLK] = &gcc_pcie_0_clkref_clk.clkr,
[GCC_PCIE_AUX_CLK] = &gcc_pcie_aux_clk.clkr,
[GCC_PCIE_AUX_PHY_CLK_SRC] = &gcc_pcie_aux_phy_clk_src.clkr,
[GCC_PCIE_CFG_AHB_CLK] = &gcc_pcie_cfg_ahb_clk.clkr,
@@ -1813,6 +1839,7 @@
[GCC_USB3_PHY_AUX_CLK] = &gcc_usb3_phy_aux_clk.clkr,
[GCC_USB3_PHY_AUX_CLK_SRC] = &gcc_usb3_phy_aux_clk_src.clkr,
[GCC_USB3_PHY_PIPE_CLK] = &gcc_usb3_phy_pipe_clk.clkr,
+ [GCC_USB3_PRIM_CLKREF_CLK] = &gcc_usb3_prim_clkref_clk.clkr,
[GCC_USB_PHY_CFG_AHB2PHY_CLK] = &gcc_usb_phy_cfg_ahb2phy_clk.clkr,
[GPLL0] = &gpll0.clkr,
[GPLL0_OUT_EVEN] = &gpll0_out_even.clkr,
@@ -1837,6 +1864,8 @@
[GCC_SDCC1_BCR] = { 0xf000 },
[GCC_SPMI_FETCHER_BCR] = { 0x3f000 },
[GCC_USB30_BCR] = { 0xb000 },
+ [GCC_USB3_PHY_BCR] = { 0xc000 },
+ [GCC_USB3PHY_PHY_BCR] = { 0xc004 },
[GCC_USB_PHY_CFG_AHB2PHY_BCR] = { 0xe000 },
};
@@ -1903,7 +1932,7 @@
{
return platform_driver_register(&gcc_sdxpoorwills_driver);
}
-core_initcall(gcc_sdxpoorwills_init);
+subsys_initcall(gcc_sdxpoorwills_init);
static void __exit gcc_sdxpoorwills_exit(void)
{
diff --git a/drivers/clk/qcom/mdss/mdss-dsi-pll-10nm.c b/drivers/clk/qcom/mdss/mdss-dsi-pll-10nm.c
index 97d0a0f..3f9fcd9 100644
--- a/drivers/clk/qcom/mdss/mdss-dsi-pll-10nm.c
+++ b/drivers/clk/qcom/mdss/mdss-dsi-pll-10nm.c
@@ -33,24 +33,52 @@
/* Register Offsets from PLL base address */
#define PLL_ANALOG_CONTROLS_ONE 0x000
#define PLL_ANALOG_CONTROLS_TWO 0x004
+#define PLL_INT_LOOP_SETTINGS 0x008
+#define PLL_INT_LOOP_SETTINGS_TWO 0x00c
#define PLL_ANALOG_CONTROLS_THREE 0x010
+#define PLL_ANALOG_CONTROLS_FOUR 0x014
+#define PLL_INT_LOOP_CONTROLS 0x018
#define PLL_DSM_DIVIDER 0x01c
#define PLL_FEEDBACK_DIVIDER 0x020
#define PLL_SYSTEM_MUXES 0x024
+#define PLL_FREQ_UPDATE_CONTROL_OVERRIDES 0x028
#define PLL_CMODE 0x02c
#define PLL_CALIBRATION_SETTINGS 0x030
+#define PLL_BAND_SEL_CAL_TIMER_LOW 0x034
+#define PLL_BAND_SEL_CAL_TIMER_HIGH 0x038
+#define PLL_BAND_SEL_CAL_SETTINGS 0x03c
+#define PLL_BAND_SEL_MIN 0x040
+#define PLL_BAND_SEL_MAX 0x044
+#define PLL_BAND_SEL_PFILT 0x048
+#define PLL_BAND_SEL_IFILT 0x04c
+#define PLL_BAND_SEL_CAL_SETTINGS_TWO 0x050
#define PLL_BAND_SEL_CAL_SETTINGS_THREE 0x054
+#define PLL_BAND_SEL_CAL_SETTINGS_FOUR 0x058
+#define PLL_BAND_SEL_ICODE_HIGH 0x05c
+#define PLL_BAND_SEL_ICODE_LOW 0x060
#define PLL_FREQ_DETECT_SETTINGS_ONE 0x064
#define PLL_PFILT 0x07c
#define PLL_IFILT 0x080
+#define PLL_GAIN 0x084
+#define PLL_ICODE_LOW 0x088
+#define PLL_ICODE_HIGH 0x08c
+#define PLL_LOCKDET 0x090
#define PLL_OUTDIV 0x094
+#define PLL_FASTLOCK_CONTROL 0x098
+#define PLL_PASS_OUT_OVERRIDE_ONE 0x09c
+#define PLL_PASS_OUT_OVERRIDE_TWO 0x0a0
#define PLL_CORE_OVERRIDE 0x0a4
#define PLL_CORE_INPUT_OVERRIDE 0x0a8
+#define PLL_RATE_CHANGE 0x0ac
+#define PLL_PLL_DIGITAL_TIMERS 0x0b0
#define PLL_PLL_DIGITAL_TIMERS_TWO 0x0b4
+#define PLL_DEC_FRAC_MUXES 0x0c8
#define PLL_DECIMAL_DIV_START_1 0x0cc
#define PLL_FRAC_DIV_START_LOW_1 0x0d0
#define PLL_FRAC_DIV_START_MID_1 0x0d4
#define PLL_FRAC_DIV_START_HIGH_1 0x0d8
+#define PLL_MASH_CONTROL 0x0ec
+#define PLL_SSC_MUX_CONTROL 0x108
#define PLL_SSC_STEPSIZE_LOW_1 0x10c
#define PLL_SSC_STEPSIZE_HIGH_1 0x110
#define PLL_SSC_DIV_PER_LOW_1 0x114
@@ -64,9 +92,16 @@
#define PLL_PLL_BAND_SET_RATE_1 0x154
#define PLL_PLL_INT_GAIN_IFILT_BAND_1 0x15c
#define PLL_PLL_FL_INT_GAIN_PFILT_BAND_1 0x164
+#define PLL_FASTLOCK_EN_BAND 0x16c
+#define PLL_FREQ_TUNE_ACCUM_INIT_MUX 0x17c
#define PLL_PLL_LOCK_OVERRIDE 0x180
#define PLL_PLL_LOCK_DELAY 0x184
+#define PLL_PLL_LOCK_MIN_DELAY 0x188
#define PLL_CLOCK_INVERTERS 0x18c
+#define PLL_SPARE_AND_JPC_OVERRIDES 0x190
+#define PLL_BIAS_CONTROL_1 0x194
+#define PLL_BIAS_CONTROL_2 0x198
+#define PLL_ALOG_OBSV_BUS_CTRL_1 0x19c
#define PLL_COMMON_STATUS_ONE 0x1a0
/* Register Offsets from PHY base address */
@@ -503,6 +538,49 @@
MDSS_PLL_REG_W(pll_base, PLL_IFILT, 0x3f);
}
+static void dsi_pll_init_val(struct mdss_pll_resources *rsc)
+{
+ void __iomem *pll_base = rsc->pll_base;
+
+ MDSS_PLL_REG_W(pll_base, PLL_CORE_INPUT_OVERRIDE, 0x10);
+ MDSS_PLL_REG_W(pll_base, PLL_INT_LOOP_SETTINGS, 0x3f);
+ MDSS_PLL_REG_W(pll_base, PLL_INT_LOOP_SETTINGS_TWO, 0x0);
+ MDSS_PLL_REG_W(pll_base, PLL_ANALOG_CONTROLS_FOUR, 0x0);
+ MDSS_PLL_REG_W(pll_base, PLL_INT_LOOP_CONTROLS, 0x80);
+ MDSS_PLL_REG_W(pll_base, PLL_FREQ_UPDATE_CONTROL_OVERRIDES, 0x0);
+ MDSS_PLL_REG_W(pll_base, PLL_BAND_SEL_CAL_TIMER_LOW, 0x0);
+ MDSS_PLL_REG_W(pll_base, PLL_BAND_SEL_CAL_TIMER_HIGH, 0x02);
+ MDSS_PLL_REG_W(pll_base, PLL_BAND_SEL_CAL_SETTINGS, 0x82);
+ MDSS_PLL_REG_W(pll_base, PLL_BAND_SEL_MIN, 0x00);
+ MDSS_PLL_REG_W(pll_base, PLL_BAND_SEL_MAX, 0xff);
+ MDSS_PLL_REG_W(pll_base, PLL_BAND_SEL_PFILT, 0x00);
+ MDSS_PLL_REG_W(pll_base, PLL_BAND_SEL_IFILT, 0x00);
+ MDSS_PLL_REG_W(pll_base, PLL_BAND_SEL_CAL_SETTINGS_TWO, 0x25);
+ MDSS_PLL_REG_W(pll_base, PLL_BAND_SEL_CAL_SETTINGS_FOUR, 0x4f);
+ MDSS_PLL_REG_W(pll_base, PLL_BAND_SEL_ICODE_HIGH, 0x0a);
+ MDSS_PLL_REG_W(pll_base, PLL_BAND_SEL_ICODE_LOW, 0x0);
+ MDSS_PLL_REG_W(pll_base, PLL_GAIN, 0x42);
+ MDSS_PLL_REG_W(pll_base, PLL_ICODE_LOW, 0x00);
+ MDSS_PLL_REG_W(pll_base, PLL_ICODE_HIGH, 0x00);
+ MDSS_PLL_REG_W(pll_base, PLL_LOCKDET, 0x30);
+ MDSS_PLL_REG_W(pll_base, PLL_FASTLOCK_CONTROL, 0x04);
+ MDSS_PLL_REG_W(pll_base, PLL_PASS_OUT_OVERRIDE_ONE, 0x00);
+ MDSS_PLL_REG_W(pll_base, PLL_PASS_OUT_OVERRIDE_TWO, 0x00);
+ MDSS_PLL_REG_W(pll_base, PLL_RATE_CHANGE, 0x01);
+ MDSS_PLL_REG_W(pll_base, PLL_PLL_DIGITAL_TIMERS, 0x08);
+ MDSS_PLL_REG_W(pll_base, PLL_DEC_FRAC_MUXES, 0x00);
+ MDSS_PLL_REG_W(pll_base, PLL_MASH_CONTROL, 0x03);
+ MDSS_PLL_REG_W(pll_base, PLL_SSC_MUX_CONTROL, 0x0);
+ MDSS_PLL_REG_W(pll_base, PLL_SSC_CONTROL, 0x0);
+ MDSS_PLL_REG_W(pll_base, PLL_FASTLOCK_EN_BAND, 0x03);
+ MDSS_PLL_REG_W(pll_base, PLL_FREQ_TUNE_ACCUM_INIT_MUX, 0x0);
+ MDSS_PLL_REG_W(pll_base, PLL_PLL_LOCK_MIN_DELAY, 0x19);
+ MDSS_PLL_REG_W(pll_base, PLL_SPARE_AND_JPC_OVERRIDES, 0x0);
+ MDSS_PLL_REG_W(pll_base, PLL_BIAS_CONTROL_1, 0x40);
+ MDSS_PLL_REG_W(pll_base, PLL_BIAS_CONTROL_2, 0x20);
+ MDSS_PLL_REG_W(pll_base, PLL_ALOG_OBSV_BUS_CTRL_1, 0x0);
+}
+
static void dsi_pll_commit(struct dsi_pll_10nm *pll,
struct mdss_pll_resources *rsc)
{
@@ -559,6 +637,8 @@
return rc;
}
+ dsi_pll_init_val(rsc);
+
dsi_pll_setup_config(pll, rsc);
dsi_pll_calc_dec_frac(pll, rsc);
diff --git a/drivers/cpufreq/qcom-cpufreq.c b/drivers/cpufreq/qcom-cpufreq.c
index d310380..90fac32 100644
--- a/drivers/cpufreq/qcom-cpufreq.c
+++ b/drivers/cpufreq/qcom-cpufreq.c
@@ -410,7 +410,7 @@
if (!IS_ERR(ftbl)) {
for_each_possible_cpu(cpu)
per_cpu(freq_table, cpu) = ftbl;
- return 0;
+ goto out_register;
}
/*
@@ -450,6 +450,7 @@
per_cpu(freq_table, cpu) = ftbl;
}
+out_register:
ret = register_pm_notifier(&msm_cpufreq_pm_notifier);
if (ret)
return ret;
diff --git a/drivers/gpu/drm/msm/Kconfig b/drivers/gpu/drm/msm/Kconfig
index 31e5b76..ba71ce8 100644
--- a/drivers/gpu/drm/msm/Kconfig
+++ b/drivers/gpu/drm/msm/Kconfig
@@ -3,7 +3,7 @@
tristate "MSM DRM"
depends on DRM
depends on ARCH_QCOM || (ARM && COMPILE_TEST)
- depends on OF && COMMON_CLK
+ depends on OF
select REGULATOR
select DRM_KMS_HELPER
select DRM_PANEL
@@ -39,6 +39,7 @@
config DRM_MSM_HDMI
bool "Enable HDMI support in MSM DRM driver"
depends on DRM_MSM
+ depends on COMMON_CLK
default n
help
Compile in support for HDMI driver in msm drm
diff --git a/drivers/gpu/drm/msm/dp/dp_aux.c b/drivers/gpu/drm/msm/dp/dp_aux.c
index 2d76d13..79f2ec9 100644
--- a/drivers/gpu/drm/msm/dp/dp_aux.c
+++ b/drivers/gpu/drm/msm/dp/dp_aux.c
@@ -332,6 +332,7 @@
struct drm_dp_aux_msg helper_msg;
u32 const message_size = 0x10;
u32 const segment_address = 0x30;
+ u32 const edid_block_length = 0x80;
bool i2c_mot = input_msg->request & DP_AUX_I2C_MOT;
bool i2c_read = input_msg->request &
(DP_AUX_I2C_READ & DP_AUX_NATIVE_READ);
@@ -339,6 +340,15 @@
if (!i2c_mot || !i2c_read || (input_msg->size == 0))
return;
+ /*
+ * Sending the segment value and EDID offset will be performed
+ * from the DRM upstream EDID driver for each block. Avoid
+ * duplicate AUX transactions related to this while reading the
+ * first 16 bytes of each block.
+ */
+ if (!(aux->offset % edid_block_length))
+ goto end;
+
aux->read = false;
aux->cmd_busy = true;
aux->no_send_addr = true;
@@ -371,6 +381,7 @@
helper_msg.buffer = &aux->offset;
helper_msg.size = 1;
dp_aux_cmd_fifo_tx(aux, &helper_msg);
+end:
aux->offset += message_size;
if (aux->offset == 0x80 || aux->offset == 0x100)
diff --git a/drivers/gpu/drm/msm/dsi-staging/dsi_catalog.c b/drivers/gpu/drm/msm/dsi-staging/dsi_catalog.c
index 0ddb47f..f2c2985 100644
--- a/drivers/gpu/drm/msm/dsi-staging/dsi_catalog.c
+++ b/drivers/gpu/drm/msm/dsi-staging/dsi_catalog.c
@@ -83,6 +83,7 @@
dsi_ctrl_hw_14_reg_dump_to_buffer;
ctrl->ops.schedule_dma_cmd = NULL;
ctrl->ops.get_cont_splash_status = NULL;
+ ctrl->ops.kickoff_command_non_embedded_mode = NULL;
break;
case DSI_CTRL_VERSION_2_0:
ctrl->ops.setup_lane_map = dsi_ctrl_hw_20_setup_lane_map;
@@ -97,6 +98,7 @@
ctrl->ops.clamp_disable = NULL;
ctrl->ops.schedule_dma_cmd = NULL;
ctrl->ops.get_cont_splash_status = NULL;
+ ctrl->ops.kickoff_command_non_embedded_mode = NULL;
break;
case DSI_CTRL_VERSION_2_2:
ctrl->ops.phy_reset_config = dsi_ctrl_hw_22_phy_reset_config;
@@ -113,6 +115,8 @@
ctrl->ops.clamp_enable = NULL;
ctrl->ops.clamp_disable = NULL;
ctrl->ops.schedule_dma_cmd = dsi_ctrl_hw_22_schedule_dma_cmd;
+ ctrl->ops.kickoff_command_non_embedded_mode =
+ dsi_ctrl_hw_kickoff_non_embedded_mode;
break;
default:
break;
diff --git a/drivers/gpu/drm/msm/dsi-staging/dsi_catalog.h b/drivers/gpu/drm/msm/dsi-staging/dsi_catalog.h
index 735f61f..f7756dc 100644
--- a/drivers/gpu/drm/msm/dsi-staging/dsi_catalog.h
+++ b/drivers/gpu/drm/msm/dsi-staging/dsi_catalog.h
@@ -213,6 +213,9 @@
ssize_t dsi_ctrl_hw_20_reg_dump_to_buffer(struct dsi_ctrl_hw *ctrl,
char *buf,
u32 size);
+void dsi_ctrl_hw_kickoff_non_embedded_mode(struct dsi_ctrl_hw *ctrl,
+ struct dsi_ctrl_cmd_dma_info *cmd,
+ u32 flags);
/* Definitions specific to 2.2 DSI controller hardware */
bool dsi_ctrl_hw_22_get_cont_splash_status(struct dsi_ctrl_hw *ctrl);
diff --git a/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl.c b/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl.c
index 1f10e3c..5318a5f 100644
--- a/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl.c
+++ b/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl.c
@@ -940,6 +940,62 @@
udelay(sleep_ms * 1000);
}
+void dsi_message_setup_tx_mode(struct dsi_ctrl *dsi_ctrl,
+ u32 cmd_len,
+ u32 *flags)
+{
+ /**
+ * Setup the mode of transmission
+ * override cmd fetch mode during secure session
+ */
+ if (dsi_ctrl->secure_mode) {
+ *flags &= ~DSI_CTRL_CMD_FETCH_MEMORY;
+ *flags |= DSI_CTRL_CMD_FIFO_STORE;
+ pr_debug("[%s] override to TPG during secure session\n",
+ dsi_ctrl->name);
+ return;
+ }
+
+ /* Check to see if cmd len plus header is greater than fifo size */
+ if ((cmd_len + 4) > DSI_EMBEDDED_MODE_DMA_MAX_SIZE_BYTES) {
+ *flags |= DSI_CTRL_CMD_NON_EMBEDDED_MODE;
+ pr_debug("[%s] override to non-embedded mode,cmd len =%d\n",
+ dsi_ctrl->name, cmd_len);
+ return;
+ }
+}
+
+int dsi_message_validate_tx_mode(struct dsi_ctrl *dsi_ctrl,
+ u32 cmd_len,
+ u32 *flags)
+{
+ int rc = 0;
+
+ if (*flags & DSI_CTRL_CMD_FIFO_STORE) {
+ /* if command size plus header is greater than fifo size */
+ if ((cmd_len + 4) > DSI_CTRL_MAX_CMD_FIFO_STORE_SIZE) {
+ pr_err("Cannot transfer Cmd in FIFO config\n");
+ return -ENOTSUPP;
+ }
+ if (!dsi_ctrl->hw.ops.kickoff_fifo_command) {
+ pr_err("Cannot transfer command,ops not defined\n");
+ return -ENOTSUPP;
+ }
+ }
+
+ if (*flags & DSI_CTRL_CMD_NON_EMBEDDED_MODE) {
+ if (*flags & DSI_CTRL_CMD_BROADCAST) {
+ pr_err("Non embedded not supported with broadcast\n");
+ return -ENOTSUPP;
+ }
+ if (!dsi_ctrl->hw.ops.kickoff_command_non_embedded_mode) {
+ pr_err(" Cannot transfer command,ops not defined\n");
+ return -ENOTSUPP;
+ }
+ }
+ return rc;
+}
+
static int dsi_message_tx(struct dsi_ctrl *dsi_ctrl,
const struct mipi_dsi_msg *msg,
u32 flags)
@@ -955,12 +1011,34 @@
u8 *cmdbuf;
struct dsi_mode_info *timing;
- /* override cmd fetch mode during secure session */
- if (dsi_ctrl->secure_mode) {
- flags &= ~DSI_CTRL_CMD_FETCH_MEMORY;
- flags |= DSI_CTRL_CMD_FIFO_STORE;
- pr_debug("[%s] override to TPG during secure session\n",
- dsi_ctrl->name);
+ /* Select the tx mode to transfer the command */
+ dsi_message_setup_tx_mode(dsi_ctrl, msg->tx_len, &flags);
+
+ /* Validate the mode before sending the command */
+ rc = dsi_message_validate_tx_mode(dsi_ctrl, msg->tx_len, &flags);
+ if (rc) {
+ pr_err(" Cmd tx validation failed, cannot transfer cmd\n");
+ rc = -ENOTSUPP;
+ goto error;
+ }
+
+ if (flags & DSI_CTRL_CMD_NON_EMBEDDED_MODE) {
+ cmd_mem.offset = dsi_ctrl->cmd_buffer_iova;
+ cmd_mem.en_broadcast = (flags & DSI_CTRL_CMD_BROADCAST) ?
+ true : false;
+ cmd_mem.is_master = (flags & DSI_CTRL_CMD_BROADCAST_MASTER) ?
+ true : false;
+ cmd_mem.use_lpm = (msg->flags & MIPI_DSI_MSG_USE_LPM) ?
+ true : false;
+ cmd_mem.datatype = msg->type;
+ cmd_mem.length = msg->tx_len;
+
+ dsi_ctrl->cmd_len = msg->tx_len;
+ memcpy(dsi_ctrl->vaddr, msg->tx_buf, msg->tx_len);
+ pr_debug(" non-embedded mode , size of command =%zd\n",
+ msg->tx_len);
+
+ goto kickoff;
}
rc = mipi_dsi_create_packet(&packet, msg);
@@ -969,16 +1047,6 @@
goto error;
}
- /* fail cmds more than the supported size in TPG mode */
- if ((flags & DSI_CTRL_CMD_FIFO_STORE) &&
- (msg->tx_len > DSI_CTRL_MAX_CMD_FIFO_STORE_SIZE)) {
- pr_err("[%s] TPG cmd size:%zd not supported, secure:%d\n",
- dsi_ctrl->name, msg->tx_len,
- dsi_ctrl->secure_mode);
- rc = -ENOTSUPP;
- goto error;
- }
-
rc = dsi_ctrl_copy_and_pad_cmd(dsi_ctrl,
&packet,
&buffer,
@@ -993,6 +1061,7 @@
buffer[3] |= BIT(7);//set the last cmd bit in header.
if (flags & DSI_CTRL_CMD_FETCH_MEMORY) {
+ /* Embedded mode config is selected */
cmd_mem.offset = dsi_ctrl->cmd_buffer_iova;
cmd_mem.en_broadcast = (flags & DSI_CTRL_CMD_BROADCAST) ?
true : false;
@@ -1006,6 +1075,7 @@
for (cnt = 0; cnt < length; cnt++)
cmdbuf[dsi_ctrl->cmd_len + cnt] = buffer[cnt];
+ msm_gem_sync(dsi_ctrl->tx_cmd_buf);
dsi_ctrl->cmd_len += length;
if (!(msg->flags & MIPI_DSI_MSG_LASTCOMMAND)) {
@@ -1026,6 +1096,7 @@
true : false;
}
+kickoff:
timing = &(dsi_ctrl->host_config.video_timing);
if (timing)
line_no += timing->v_back_porch + timing->v_sync_width +
@@ -1045,9 +1116,18 @@
if (flags & DSI_CTRL_CMD_DEFER_TRIGGER) {
if (flags & DSI_CTRL_CMD_FETCH_MEMORY) {
- dsi_ctrl->hw.ops.kickoff_command(&dsi_ctrl->hw,
+ if (flags & DSI_CTRL_CMD_NON_EMBEDDED_MODE) {
+ dsi_ctrl->hw.ops.
+ kickoff_command_non_embedded_mode(
+ &dsi_ctrl->hw,
&cmd_mem,
hw_flags);
+ } else {
+ dsi_ctrl->hw.ops.kickoff_command(
+ &dsi_ctrl->hw,
+ &cmd_mem,
+ hw_flags);
+ }
} else if (flags & DSI_CTRL_CMD_FIFO_STORE) {
dsi_ctrl->hw.ops.kickoff_fifo_command(&dsi_ctrl->hw,
&cmd,
@@ -1065,9 +1145,18 @@
reinit_completion(&dsi_ctrl->irq_info.cmd_dma_done);
if (flags & DSI_CTRL_CMD_FETCH_MEMORY) {
- dsi_ctrl->hw.ops.kickoff_command(&dsi_ctrl->hw,
- &cmd_mem,
- hw_flags);
+ if (flags & DSI_CTRL_CMD_NON_EMBEDDED_MODE) {
+ dsi_ctrl->hw.ops.
+ kickoff_command_non_embedded_mode(
+ &dsi_ctrl->hw,
+ &cmd_mem,
+ hw_flags);
+ } else {
+ dsi_ctrl->hw.ops.kickoff_command(
+ &dsi_ctrl->hw,
+ &cmd_mem,
+ hw_flags);
+ }
} else if (flags & DSI_CTRL_CMD_FIFO_STORE) {
dsi_ctrl->hw.ops.kickoff_fifo_command(&dsi_ctrl->hw,
&cmd,
@@ -1106,6 +1195,16 @@
dsi_ctrl->hw.ops.mask_error_intr(&dsi_ctrl->hw,
BIT(DSI_FIFO_OVERFLOW), false);
dsi_ctrl->hw.ops.reset_cmd_fifo(&dsi_ctrl->hw);
+
+ /*
+ * DSI 2.2 needs a soft reset whenever we send non-embedded
+ * mode command followed by embedded mode. Otherwise it will
+ * result in smmu write faults with DSI as client.
+ */
+ if (flags & DSI_CTRL_CMD_NON_EMBEDDED_MODE) {
+ dsi_ctrl->hw.ops.soft_reset(&dsi_ctrl->hw);
+ dsi_ctrl->cmd_len = 0;
+ }
}
error:
if (buffer)
@@ -2124,6 +2223,8 @@
if (dsi_ctrl->hw.ops.clear_interrupt_status)
dsi_ctrl->hw.ops.clear_interrupt_status(&dsi_ctrl->hw, 0x0);
+ SDE_EVT32_IRQ(dsi_ctrl->cell_index, status, errors);
+
/* handle DSI error recovery */
if (status & DSI_ERROR)
dsi_ctrl_handle_error_status(dsi_ctrl, errors);
@@ -2183,7 +2284,7 @@
* @dsi_ctrl: Pointer to associated dsi_ctrl structure
* Returns: Zero on success
*/
-static int dsi_ctrl_setup_isr(struct dsi_ctrl *dsi_ctrl)
+static int _dsi_ctrl_setup_isr(struct dsi_ctrl *dsi_ctrl)
{
int irq_num, rc;
@@ -2377,8 +2478,6 @@
}
}
- dsi_ctrl_setup_isr(dsi_ctrl);
-
dsi_ctrl->hw.ops.enable_status_interrupts(&dsi_ctrl->hw, 0x0);
dsi_ctrl->hw.ops.enable_error_interrupts(&dsi_ctrl->hw, 0xFF00E0);
@@ -2390,6 +2489,25 @@
return rc;
}
+/**
+ * dsi_ctrl_isr_configure() - API to register/deregister dsi isr
+ * @dsi_ctrl: DSI controller handle.
+ * @enable: variable to control register/deregister isr
+ */
+void dsi_ctrl_isr_configure(struct dsi_ctrl *dsi_ctrl, bool enable)
+{
+ if (!dsi_ctrl)
+ return;
+
+ mutex_lock(&dsi_ctrl->ctrl_lock);
+ if (enable)
+ _dsi_ctrl_setup_isr(dsi_ctrl);
+ else
+ _dsi_ctrl_destroy_isr(dsi_ctrl);
+
+ mutex_unlock(&dsi_ctrl->ctrl_lock);
+}
+
int dsi_ctrl_soft_reset(struct dsi_ctrl *dsi_ctrl)
{
if (!dsi_ctrl)
@@ -2465,8 +2583,6 @@
mutex_lock(&dsi_ctrl->ctrl_lock);
- _dsi_ctrl_destroy_isr(dsi_ctrl);
-
rc = dsi_ctrl_check_state(dsi_ctrl, DSI_CTRL_OP_HOST_INIT, 0x0);
if (rc) {
pr_err("[DSI_%d] Controller state check failed, rc=%d\n",
@@ -2682,6 +2798,11 @@
if (dsi_ctrl->hw.ops.mask_error_intr)
dsi_ctrl->hw.ops.mask_error_intr(&dsi_ctrl->hw,
BIT(DSI_FIFO_OVERFLOW), false);
+
+ if (flags & DSI_CTRL_CMD_NON_EMBEDDED_MODE) {
+ dsi_ctrl->hw.ops.soft_reset(&dsi_ctrl->hw);
+ dsi_ctrl->cmd_len = 0;
+ }
}
mutex_unlock(&dsi_ctrl->ctrl_lock);
@@ -3152,6 +3273,28 @@
}
/**
+ * dsi_ctrl_irq_update() - Put a irq vote to process DSI error
+ * interrupts at any time.
+ * @dsi_ctrl: DSI controller handle.
+ * @enable: variable to enable/disable irq
+ */
+void dsi_ctrl_irq_update(struct dsi_ctrl *dsi_ctrl, bool enable)
+{
+ if (!dsi_ctrl)
+ return;
+
+ mutex_lock(&dsi_ctrl->ctrl_lock);
+ if (enable)
+ dsi_ctrl_enable_status_interrupt(dsi_ctrl,
+ DSI_SINT_ERROR, NULL);
+ else
+ dsi_ctrl_disable_status_interrupt(dsi_ctrl,
+ DSI_SINT_ERROR);
+
+ mutex_unlock(&dsi_ctrl->ctrl_lock);
+}
+
+/**
* dsi_ctrl_drv_register() - register platform driver for dsi controller
*/
void dsi_ctrl_drv_register(void)
diff --git a/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl.h b/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl.h
index f5b08a0..8850df4 100644
--- a/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl.h
+++ b/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl.h
@@ -37,6 +37,7 @@
* and transfer it.
* @DSI_CTRL_CMD_LAST_COMMAND: Trigger the DMA cmd transfer if this is last
* command in the batch.
+ * @DSI_CTRL_CMD_NON_EMBEDDED_MODE:Trasfer cmd packets in non embedded mode.
*/
#define DSI_CTRL_CMD_READ 0x1
#define DSI_CTRL_CMD_BROADCAST 0x2
@@ -45,6 +46,12 @@
#define DSI_CTRL_CMD_FIFO_STORE 0x10
#define DSI_CTRL_CMD_FETCH_MEMORY 0x20
#define DSI_CTRL_CMD_LAST_COMMAND 0x40
+#define DSI_CTRL_CMD_NON_EMBEDDED_MODE 0x80
+
+/* DSI embedded mode fifo size
+ * If the command is greater than 256 bytes it is sent in non-embedded mode.
+ */
+#define DSI_EMBEDDED_MODE_DMA_MAX_SIZE_BYTES 256
/* max size supported for dsi cmd transfer using TPG */
#define DSI_CTRL_MAX_CMD_FIFO_STORE_SIZE 64
@@ -680,4 +687,34 @@
*/
int dsi_ctrl_vid_engine_en(struct dsi_ctrl *dsi_ctrl, bool on);
+/**
+ * @dsi_ctrl: DSI controller handle.
+ * cmd_len: Length of command.
+ * flags: Config mode flags.
+ */
+void dsi_message_setup_tx_mode(struct dsi_ctrl *dsi_ctrl, u32 cmd_len,
+ u32 *flags);
+
+/**
+ * @dsi_ctrl: DSI controller handle.
+ * cmd_len: Length of command.
+ * flags: Config mode flags.
+ */
+int dsi_message_validate_tx_mode(struct dsi_ctrl *dsi_ctrl, u32 cmd_len,
+ u32 *flags);
+
+/**
+ * dsi_ctrl_isr_configure() - API to register/deregister dsi isr
+ * @dsi_ctrl: DSI controller handle.
+ * @enable: variable to control register/deregister isr
+ */
+void dsi_ctrl_isr_configure(struct dsi_ctrl *dsi_ctrl, bool enable);
+
+/**
+ * dsi_ctrl_irq_update() - Put a irq vote to process DSI error
+ * interrupts at any time.
+ * @dsi_ctrl: DSI controller handle.
+ * @enable: variable to control enable/disable irq line
+ */
+void dsi_ctrl_irq_update(struct dsi_ctrl *dsi_ctrl, bool enable);
#endif /* _DSI_CTRL_H_ */
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 c77065c..567f289 100644
--- a/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl_hw.h
+++ b/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl_hw.h
@@ -296,6 +296,7 @@
* struct dsi_ctrl_cmd_dma_info - command buffer information
* @offset: IOMMU VA for command buffer address.
* @length: Length of the command buffer.
+ * @datatype: Datatype of cmd.
* @en_broadcast: Enable broadcast mode if set to true.
* @is_master: Is master in broadcast mode.
* @use_lpm: Use low power mode for command transmission.
@@ -303,6 +304,7 @@
struct dsi_ctrl_cmd_dma_info {
u32 offset;
u32 length;
+ u8 datatype;
bool en_broadcast;
bool is_master;
bool use_lpm;
@@ -497,6 +499,25 @@
u32 flags);
/**
+ * kickoff_command_non_embedded_mode() - cmd in non embedded mode
+ * @ctrl: Pointer to the controller host hardware.
+ * @cmd: Command information.
+ * @flags: Modifiers for command transmission.
+ *
+ * If command length is greater than DMA FIFO size of 256 bytes we use
+ * this non- embedded mode.
+ * The controller hardware is programmed with address and size of the
+ * command buffer. The transmission is kicked off if
+ * DSI_CTRL_HW_CMD_WAIT_FOR_TRIGGER flag is not set. If this flag is
+ * set, caller should make a separate call to trigger_command_dma() to
+ * transmit the command.
+ */
+
+ void (*kickoff_command_non_embedded_mode)(struct dsi_ctrl_hw *ctrl,
+ struct dsi_ctrl_cmd_dma_info *cmd,
+ u32 flags);
+
+ /**
* kickoff_fifo_command() - transmits a command using FIFO in dsi
* hardware.
* @ctrl: Pointer to the controller host hardware.
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
index 650c2e0..d94d6f7b 100644
--- 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
@@ -79,3 +79,48 @@
reg = DSI_R32(ctrl, DSI_SCRATCH_REGISTER_1);
return reg == 0x1 ? true : false;
}
+
+/*
+ * dsi_ctrl_hw_kickoff_non_embedded_mode()-Kickoff cmd in non-embedded mode
+ * @ctrl: - Pointer to the controller host hardware.
+ * @dsi_ctrl_cmd_dma_info: - command buffer information.
+ * @flags: - DSI CTRL Flags.
+ */
+void dsi_ctrl_hw_kickoff_non_embedded_mode(struct dsi_ctrl_hw *ctrl,
+ struct dsi_ctrl_cmd_dma_info *cmd,
+ u32 flags)
+{
+ u32 reg = 0;
+
+ reg = DSI_R32(ctrl, DSI_COMMAND_MODE_DMA_CTRL);
+
+ reg &= ~BIT(31);/* disable broadcast */
+ reg &= ~BIT(30);
+
+ if (cmd->use_lpm)
+ reg |= BIT(26);
+ else
+ reg &= ~BIT(26);
+
+ /* Select non EMBEDDED_MODE, pick the packet header from register */
+ reg &= ~BIT(28);
+ reg |= BIT(24);/* long packet */
+ reg |= BIT(29);/* wc_sel = 1 */
+ reg |= (((cmd->datatype) & 0x03f) << 16);/* data type */
+ DSI_W32(ctrl, DSI_COMMAND_MODE_DMA_CTRL, reg);
+
+ /* Enable WRITE_WATERMARK_DISABLE and READ_WATERMARK_DISABLE bits */
+ reg = DSI_R32(ctrl, DSI_DMA_FIFO_CTRL);
+ reg |= BIT(20);
+ reg |= BIT(16);
+ DSI_W32(ctrl, DSI_DMA_FIFO_CTRL, reg);
+
+ DSI_W32(ctrl, DSI_DMA_CMD_OFFSET, cmd->offset);
+ DSI_W32(ctrl, DSI_DMA_CMD_LENGTH, ((cmd->length) & 0xFFFFFF));
+
+ /* wait for writes to complete before kick off */
+ wmb();
+
+ if (!(flags & DSI_CTRL_HW_CMD_WAIT_FOR_TRIGGER))
+ DSI_W32(ctrl, DSI_CMD_MODE_DMA_SW_TRIGGER, 0x1);
+}
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 c2c8f57..c753c80 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
@@ -612,9 +612,17 @@
else
reg &= ~BIT(26);
- reg |= BIT(28);
+ reg |= BIT(28);/* Select embedded mode */
+ reg &= ~BIT(24);/* packet type */
+ reg &= ~BIT(29);/* WC_SEL to 0 */
DSI_W32(ctrl, DSI_COMMAND_MODE_DMA_CTRL, reg);
+ reg = DSI_R32(ctrl, DSI_DMA_FIFO_CTRL);
+ reg &= ~BIT(20);/* Enable write watermark*/
+ reg &= ~BIT(16);/* Enable read watermark */
+
+
+ DSI_W32(ctrl, DSI_DMA_FIFO_CTRL, reg);
DSI_W32(ctrl, DSI_DMA_CMD_OFFSET, cmd->offset);
DSI_W32(ctrl, DSI_DMA_CMD_LENGTH, (cmd->length & 0xFFFFFF));
diff --git a/drivers/gpu/drm/msm/dsi-staging/dsi_display.c b/drivers/gpu/drm/msm/dsi-staging/dsi_display.c
index d92a71d..985cb51 100644
--- a/drivers/gpu/drm/msm/dsi-staging/dsi_display.c
+++ b/drivers/gpu/drm/msm/dsi-staging/dsi_display.c
@@ -2369,6 +2369,40 @@
return 0;
}
+static void dsi_display_ctrl_isr_configure(struct dsi_display *display, bool en)
+{
+ int i;
+ struct dsi_display_ctrl *ctrl;
+
+ if (!display)
+ return;
+
+ for (i = 0; (i < display->ctrl_count) &&
+ (i < MAX_DSI_CTRLS_PER_DISPLAY); i++) {
+ ctrl = &display->ctrl[i];
+ if (!ctrl)
+ continue;
+ dsi_ctrl_isr_configure(ctrl->ctrl, en);
+ }
+}
+
+static void dsi_display_ctrl_irq_update(struct dsi_display *display, bool en)
+{
+ int i;
+ struct dsi_display_ctrl *ctrl;
+
+ if (!display)
+ return;
+
+ for (i = 0; (i < display->ctrl_count) &&
+ (i < MAX_DSI_CTRLS_PER_DISPLAY); i++) {
+ ctrl = &display->ctrl[i];
+ if (!ctrl)
+ continue;
+ dsi_ctrl_irq_update(ctrl->ctrl, en);
+ }
+}
+
int dsi_pre_clkoff_cb(void *priv,
enum dsi_clk_type clk,
enum dsi_clk_state new_state)
@@ -2485,6 +2519,9 @@
*/
if (display->phy_idle_power_off || mmss_clamp)
dsi_display_phy_idle_on(display, mmss_clamp);
+
+ /* enable dsi to serve irqs */
+ dsi_display_ctrl_irq_update(display, true);
}
if (clk & DSI_LINK_CLK) {
if (display->ulps_enabled) {
@@ -2514,6 +2551,8 @@
if ((clk_type & DSI_CORE_CLK) &&
(curr_state == DSI_CLK_OFF)) {
+ /* dsi will not be able to serve irqs from here */
+ dsi_display_ctrl_irq_update(display, false);
rc = dsi_display_phy_power_off(display);
if (rc)
@@ -4752,6 +4791,9 @@
}
}
+ /* Set up ctrl isr before enabling core clk */
+ dsi_display_ctrl_isr_configure(display, true);
+
rc = dsi_display_clk_ctrl(display->dsi_clk_handle,
DSI_CORE_CLK, DSI_CLK_ON);
if (rc) {
@@ -5280,6 +5322,9 @@
pr_err("[%s] failed to disable DSI clocks, rc=%d\n",
display->name, rc);
+ /* destrory dsi isr set up */
+ dsi_display_ctrl_isr_configure(display, false);
+
rc = dsi_panel_post_unprepare(display->panel);
if (rc)
pr_err("[%s] panel post-unprepare failed, rc=%d\n",
diff --git a/drivers/gpu/drm/msm/msm_drv.h b/drivers/gpu/drm/msm/msm_drv.h
index e5c3082..cc09256 100644
--- a/drivers/gpu/drm/msm/msm_drv.h
+++ b/drivers/gpu/drm/msm/msm_drv.h
@@ -727,6 +727,7 @@
void msm_gem_shrinker_init(struct drm_device *dev);
void msm_gem_shrinker_cleanup(struct drm_device *dev);
+void msm_gem_sync(struct drm_gem_object *obj);
int msm_gem_mmap_obj(struct drm_gem_object *obj,
struct vm_area_struct *vma);
int msm_gem_mmap(struct file *filp, struct vm_area_struct *vma);
diff --git a/drivers/gpu/drm/msm/msm_gem.c b/drivers/gpu/drm/msm/msm_gem.c
index f8c3df5..d9aad88 100644
--- a/drivers/gpu/drm/msm/msm_gem.c
+++ b/drivers/gpu/drm/msm/msm_gem.c
@@ -104,12 +104,13 @@
msm_obj->pages = p;
- /* For non-cached buffers, ensure the new pages are clean
- * because display controller, GPU, etc. are not coherent:
+ /*
+ * Make sure to flush the CPU cache for newly allocated memory
+ * so we don't get ourselves into trouble with a dirty cache
*/
if (msm_obj->flags & (MSM_BO_WC|MSM_BO_UNCACHED))
- dma_map_sg(dev->dev, msm_obj->sgt->sgl,
- msm_obj->sgt->nents, DMA_BIDIRECTIONAL);
+ dma_sync_sg_for_device(dev->dev, msm_obj->sgt->sgl,
+ msm_obj->sgt->nents, DMA_BIDIRECTIONAL);
}
return msm_obj->pages;
@@ -120,12 +121,6 @@
struct msm_gem_object *msm_obj = to_msm_bo(obj);
if (msm_obj->pages) {
- /* For non-cached buffers, ensure the new pages are clean
- * because display controller, GPU, etc. are not coherent:
- */
- if (msm_obj->flags & (MSM_BO_WC|MSM_BO_UNCACHED))
- dma_unmap_sg(obj->dev->dev, msm_obj->sgt->sgl,
- msm_obj->sgt->nents, DMA_BIDIRECTIONAL);
sg_free_table(msm_obj->sgt);
kfree(msm_obj->sgt);
@@ -155,6 +150,24 @@
/* when we start tracking the pin count, then do something here */
}
+void msm_gem_sync(struct drm_gem_object *obj)
+{
+ struct msm_gem_object *msm_obj;
+
+ if (!obj)
+ return;
+
+ msm_obj = to_msm_bo(obj);
+
+ /*
+ * dma_sync_sg_for_device synchronises a single contiguous or
+ * scatter/gather mapping for the CPU and device.
+ */
+ dma_sync_sg_for_device(obj->dev->dev, msm_obj->sgt->sgl,
+ msm_obj->sgt->nents, DMA_BIDIRECTIONAL);
+}
+
+
int msm_gem_mmap_obj(struct drm_gem_object *obj,
struct vm_area_struct *vma)
{
diff --git a/drivers/gpu/drm/msm/msm_smmu.c b/drivers/gpu/drm/msm/msm_smmu.c
index 7c879651..779bc67 100644
--- a/drivers/gpu/drm/msm/msm_smmu.c
+++ b/drivers/gpu/drm/msm/msm_smmu.c
@@ -444,9 +444,7 @@
DRM_ERROR("SMMU device:%s", client->dev ? client->dev->kobj.name : "");
/* generate dump, but no panic */
- SDE_DBG_DUMP("sde", "dsi0_ctrl", "dsi0_phy", "dsi1_ctrl",
- "dsi1_phy", "vbif", "dbg_bus",
- "vbif_dbg_bus");
+ SDE_DBG_DUMP("all", "dbg_bus", "vbif_dbg_bus");
/*
* return -ENOSYS to allow smmu driver to dump out useful
diff --git a/drivers/gpu/drm/msm/sde/sde_core_perf.c b/drivers/gpu/drm/msm/sde/sde_core_perf.c
index 6b36745..fa53464 100644
--- a/drivers/gpu/drm/msm/sde/sde_core_perf.c
+++ b/drivers/gpu/drm/msm/sde/sde_core_perf.c
@@ -29,6 +29,8 @@
#define SDE_PERF_MODE_STRING_SIZE 128
+static DEFINE_MUTEX(sde_core_perf_lock);
+
/**
* enum sde_perf_mode - performance tuning mode
* @SDE_PERF_MODE_NORMAL: performance controlled by user mode client
@@ -170,6 +172,15 @@
}
SDE_EVT32(crtc->base.id, perf->core_clk_rate);
+ trace_sde_perf_calc_crtc(crtc->base.id,
+ perf->bw_ctl[SDE_POWER_HANDLE_DBUS_ID_MNOC],
+ perf->bw_ctl[SDE_POWER_HANDLE_DBUS_ID_LLCC],
+ perf->bw_ctl[SDE_POWER_HANDLE_DBUS_ID_EBI],
+ perf->max_per_pipe_ib[SDE_POWER_HANDLE_DBUS_ID_MNOC],
+ perf->max_per_pipe_ib[SDE_POWER_HANDLE_DBUS_ID_LLCC],
+ perf->max_per_pipe_ib[SDE_POWER_HANDLE_DBUS_ID_EBI],
+ perf->core_clk_rate);
+
SDE_DEBUG(
"crtc=%d clk_rate=%llu core_ib=%llu core_ab=%llu llcc_ib=%llu llcc_ab=%llu mem_ib=%llu mem_ab=%llu\n",
crtc->base.id, perf->core_clk_rate,
@@ -294,8 +305,7 @@
}
static void _sde_core_perf_crtc_update_bus(struct sde_kms *kms,
- struct drm_crtc *crtc, u32 bus_id,
- struct sde_core_perf_params *crtc_perf)
+ struct drm_crtc *crtc, u32 bus_id)
{
u64 bw_sum_of_intfs = 0, bus_ab_quota, bus_ib_quota;
struct sde_core_perf_params perf = { { 0 } };
@@ -304,6 +314,7 @@
struct drm_crtc *tmp_crtc;
struct sde_crtc_state *sde_cstate;
struct msm_drm_private *priv = kms->dev->dev_private;
+ struct sde_crtc *sde_crtc;
u64 tmp_max_per_pipe_ib;
u64 tmp_bw_ctl;
@@ -313,18 +324,12 @@
_is_crtc_client_type_matches(tmp_crtc, curr_client_type,
&kms->perf)) {
- if (crtc->base.id == tmp_crtc->base.id) {
- /* for current crtc use the cached values */
- tmp_max_per_pipe_ib =
- crtc_perf->max_per_pipe_ib[bus_id];
- tmp_bw_ctl = crtc_perf->bw_ctl[bus_id];
- } else {
- sde_cstate = to_sde_crtc_state(tmp_crtc->state);
- tmp_max_per_pipe_ib =
- sde_cstate->new_perf.max_per_pipe_ib[bus_id];
- tmp_bw_ctl =
- sde_cstate->new_perf.bw_ctl[bus_id];
- }
+ /* use current perf, which are the values voted */
+ sde_crtc = to_sde_crtc(tmp_crtc);
+ tmp_max_per_pipe_ib =
+ sde_crtc->cur_perf.max_per_pipe_ib[bus_id];
+ tmp_bw_ctl =
+ sde_crtc->cur_perf.bw_ctl[bus_id];
perf.max_per_pipe_ib[bus_id] =
max(perf.max_per_pipe_ib[bus_id],
@@ -459,30 +464,25 @@
SDE_DEBUG("Release BW crtc=%d\n", crtc->base.id);
for (i = 0; i < SDE_POWER_HANDLE_DBUS_ID_MAX; i++) {
sde_crtc->cur_perf.bw_ctl[i] = 0;
- _sde_core_perf_crtc_update_bus(kms, crtc, i,
- &sde_crtc->cur_perf);
+ _sde_core_perf_crtc_update_bus(kms, crtc, i);
}
}
}
-static u64 _sde_core_perf_get_core_clk_rate(struct sde_kms *kms,
- struct sde_core_perf_params *crct_perf, struct drm_crtc *crtc)
+static u64 _sde_core_perf_get_core_clk_rate(struct sde_kms *kms)
{
u64 clk_rate = kms->perf.perf_tune.min_core_clk;
struct drm_crtc *tmp_crtc;
- struct sde_crtc_state *sde_cstate;
+ struct sde_crtc *sde_crtc;
u64 tmp_rate;
drm_for_each_crtc(tmp_crtc, kms->dev) {
if (_sde_core_perf_crtc_is_power_on(tmp_crtc)) {
- if (crtc->base.id == tmp_crtc->base.id) {
- /* for current CRTC, use the cached value */
- tmp_rate = crct_perf->core_clk_rate;
- } else {
- sde_cstate = to_sde_crtc_state(tmp_crtc->state);
- tmp_rate = sde_cstate->new_perf.core_clk_rate;
- }
+ /* use current perf, which are the values voted */
+ sde_crtc = to_sde_crtc(tmp_crtc);
+ tmp_rate = sde_crtc->cur_perf.core_clk_rate;
+
clk_rate = max(tmp_rate, clk_rate);
clk_rate = clk_round_rate(kms->perf.core_clk, clk_rate);
@@ -531,6 +531,8 @@
SDE_DEBUG("crtc:%d stop_req:%d core_clk:%llu\n",
crtc->base.id, stop_req, kms->perf.core_clk_rate);
+ mutex_lock(&sde_core_perf_lock);
+
/*
* cache the performance numbers in the crtc prior to the
* crtc kickoff, so the same numbers are used during the
@@ -552,19 +554,32 @@
* 2. new bandwidth vote - "ab or ib vote" is lower
* than current vote at end of commit or stop.
*/
- if ((params_changed && ((new->bw_ctl[i] >
- old->bw_ctl[i]) ||
- (new->max_per_pipe_ib[i] >
- old->max_per_pipe_ib[i]))) ||
- (!params_changed && ((new->bw_ctl[i] <
- old->bw_ctl[i]) ||
- (new->max_per_pipe_ib[i] <
- old->max_per_pipe_ib[i])))) {
+
+ if ((params_changed &&
+ (new->bw_ctl[i] > old->bw_ctl[i])) ||
+ (!params_changed &&
+ (new->bw_ctl[i] < old->bw_ctl[i]))) {
+
SDE_DEBUG(
"crtc=%d p=%d new_bw=%llu,old_bw=%llu\n",
crtc->base.id, params_changed,
new->bw_ctl[i], old->bw_ctl[i]);
old->bw_ctl[i] = new->bw_ctl[i];
+ update_bus |= BIT(i);
+ }
+
+ if ((params_changed &&
+ (new->max_per_pipe_ib[i] >
+ old->max_per_pipe_ib[i])) ||
+ (!params_changed &&
+ (new->max_per_pipe_ib[i] <
+ old->max_per_pipe_ib[i]))) {
+
+ SDE_DEBUG(
+ "crtc=%d p=%d new_ib=%llu,old_ib=%llu\n",
+ crtc->base.id, params_changed,
+ new->max_per_pipe_ib[i],
+ old->max_per_pipe_ib[i]);
old->max_per_pipe_ib[i] =
new->max_per_pipe_ib[i];
update_bus |= BIT(i);
@@ -608,15 +623,18 @@
update_clk = 1;
}
trace_sde_perf_crtc_update(crtc->base.id,
- new->bw_ctl[SDE_POWER_HANDLE_DBUS_ID_MNOC],
- new->bw_ctl[SDE_POWER_HANDLE_DBUS_ID_LLCC],
- new->bw_ctl[SDE_POWER_HANDLE_DBUS_ID_EBI],
- new->core_clk_rate, stop_req,
- update_bus, update_clk);
+ new->bw_ctl[SDE_POWER_HANDLE_DBUS_ID_MNOC],
+ new->max_per_pipe_ib[SDE_POWER_HANDLE_DBUS_ID_MNOC],
+ new->bw_ctl[SDE_POWER_HANDLE_DBUS_ID_LLCC],
+ new->max_per_pipe_ib[SDE_POWER_HANDLE_DBUS_ID_LLCC],
+ new->bw_ctl[SDE_POWER_HANDLE_DBUS_ID_EBI],
+ new->max_per_pipe_ib[SDE_POWER_HANDLE_DBUS_ID_EBI],
+ new->core_clk_rate, stop_req,
+ update_bus, update_clk, params_changed);
for (i = 0; i < SDE_POWER_HANDLE_DBUS_ID_MAX; i++) {
if (update_bus & BIT(i))
- _sde_core_perf_crtc_update_bus(kms, crtc, i, old);
+ _sde_core_perf_crtc_update_bus(kms, crtc, i);
}
/*
@@ -624,7 +642,7 @@
* bandwidth is available before clock rate is increased.
*/
if (update_clk) {
- clk_rate = _sde_core_perf_get_core_clk_rate(kms, old, crtc);
+ clk_rate = _sde_core_perf_get_core_clk_rate(kms);
SDE_EVT32(kms->dev, stop_req, clk_rate, params_changed,
old->core_clk_rate, new->core_clk_rate);
@@ -633,12 +651,15 @@
if (ret) {
SDE_ERROR("failed to set %s clock rate %llu\n",
kms->perf.clk_name, clk_rate);
+ mutex_unlock(&sde_core_perf_lock);
return;
}
kms->perf.core_clk_rate = clk_rate;
SDE_DEBUG("update clk rate = %lld HZ\n", clk_rate);
}
+ mutex_unlock(&sde_core_perf_lock);
+
}
#ifdef CONFIG_DEBUG_FS
diff --git a/drivers/gpu/drm/msm/sde/sde_crtc.c b/drivers/gpu/drm/msm/sde/sde_crtc.c
index 94c7f40..9cdef88 100644
--- a/drivers/gpu/drm/msm/sde/sde_crtc.c
+++ b/drivers/gpu/drm/msm/sde/sde_crtc.c
@@ -3501,6 +3501,9 @@
if (dump_status)
SDE_DBG_DUMP("all", "dbg_bus", "vbif_dbg_bus");
+ /* optionally generate a panic instead of performing a h/w reset */
+ SDE_DBG_CTRL("stop_ftrace", "reset_hw_panic");
+
for (i = 0; i < sde_crtc->num_mixers; ++i) {
ctl = sde_crtc->mixers[i].hw_ctl;
if (!ctl || !ctl->ops.reset)
@@ -3618,10 +3621,11 @@
/*
* For inline ASYNC modes, the flush bits are not written
- * to hardware atomically, so avoid using it if a video
- * mode encoder is active on this CRTC.
+ * to hardware atomically. This is not fully supported for
+ * non-command mode encoders, so force SYNC mode if any
+ * of them are attached to the CRTC.
*/
- if (sde_encoder_get_intf_mode(encoder) == INTF_MODE_VIDEO) {
+ if (sde_encoder_get_intf_mode(encoder) != INTF_MODE_CMD) {
cstate->sbuf_cfg.rot_op_mode =
SDE_CTL_ROT_OP_MODE_INLINE_SYNC;
return false;
diff --git a/drivers/gpu/drm/msm/sde/sde_encoder.c b/drivers/gpu/drm/msm/sde/sde_encoder.c
index df65ea3..0ed994b 100644
--- a/drivers/gpu/drm/msm/sde/sde_encoder.c
+++ b/drivers/gpu/drm/msm/sde/sde_encoder.c
@@ -1512,6 +1512,7 @@
struct drm_crtc *primary_crtc;
int pipe = -1;
int rc = 0;
+ int wait_refcount;
if (!drm_enc || !drm_enc->dev) {
SDE_ERROR("invalid encoder arguments\n");
@@ -1599,6 +1600,12 @@
return ret;
}
+ if (wait_vblank_crtc_id)
+ wait_refcount =
+ sde_rsc_client_get_vsync_refcount(sde_enc->rsc_client);
+ SDE_EVT32_VERBOSE(DRMID(drm_enc), wait_vblank_crtc_id, wait_refcount,
+ SDE_EVTLOG_FUNC_ENTRY);
+
if (crtc->base.id != wait_vblank_crtc_id) {
primary_crtc = drm_crtc_find(drm_enc->dev, wait_vblank_crtc_id);
if (!primary_crtc) {
@@ -1636,6 +1643,11 @@
SDE_EVT32(DRMID(drm_enc), wait_vblank_crtc_id, wait_count,
SDE_EVTLOG_ERROR);
+ if (wait_refcount)
+ sde_rsc_client_reset_vsync_refcount(sde_enc->rsc_client);
+ SDE_EVT32_VERBOSE(DRMID(drm_enc), wait_vblank_crtc_id, wait_refcount,
+ SDE_EVTLOG_FUNC_EXIT);
+
return ret;
}
@@ -2128,7 +2140,7 @@
mutex_lock(&sde_enc->rc_lock);
if (sde_enc->rc_state != SDE_ENC_RC_STATE_ON) {
- SDE_ERROR_ENC(sde_enc, "sw_event:%d, rc:%d !ON state\n",
+ SDE_DEBUG_ENC(sde_enc, "sw_event:%d, rc:%d !ON state\n",
sw_event, sde_enc->rc_state);
SDE_EVT32(DRMID(drm_enc), sw_event, sde_enc->rc_state,
SDE_EVTLOG_ERROR);
@@ -2756,18 +2768,35 @@
}
}
+int sde_encoder_idle_request(struct drm_encoder *drm_enc)
+{
+ struct sde_encoder_virt *sde_enc;
+
+ if (!drm_enc) {
+ SDE_ERROR("invalid drm encoder\n");
+ return -EINVAL;
+ }
+
+ sde_enc = to_sde_encoder_virt(drm_enc);
+ sde_encoder_resource_control(&sde_enc->base,
+ SDE_ENC_RC_EVENT_ENTER_IDLE);
+
+ return 0;
+}
+
static void sde_encoder_off_work(struct kthread_work *work)
{
struct sde_encoder_virt *sde_enc = container_of(work,
struct sde_encoder_virt, delayed_off_work.work);
+ struct drm_encoder *drm_enc;
if (!sde_enc) {
SDE_ERROR("invalid sde encoder\n");
return;
}
+ drm_enc = &sde_enc->base;
- sde_encoder_resource_control(&sde_enc->base,
- SDE_ENC_RC_EVENT_ENTER_IDLE);
+ sde_encoder_idle_request(drm_enc);
}
/**
diff --git a/drivers/gpu/drm/msm/sde/sde_encoder.h b/drivers/gpu/drm/msm/sde/sde_encoder.h
index f8a3cf3..937bd18 100644
--- a/drivers/gpu/drm/msm/sde/sde_encoder.h
+++ b/drivers/gpu/drm/msm/sde/sde_encoder.h
@@ -155,6 +155,14 @@
int sde_encoder_wait_for_event(struct drm_encoder *drm_encoder,
enum msm_event_wait event);
+/**
+ * sde_encoder_idle_request - request for idle request to avoid 4 vsync cycle
+ * to turn off the clocks.
+ * @encoder: encoder pointer
+ * Returns: 0 on success, errorcode otherwise
+ */
+int sde_encoder_idle_request(struct drm_encoder *drm_enc);
+
/*
* sde_encoder_get_intf_mode - get interface mode of the given encoder
* @encoder: Pointer to drm encoder object
diff --git a/drivers/gpu/drm/msm/sde/sde_encoder_phys_vid.c b/drivers/gpu/drm/msm/sde/sde_encoder_phys_vid.c
index aaf50f6..659827c 100644
--- a/drivers/gpu/drm/msm/sde/sde_encoder_phys_vid.c
+++ b/drivers/gpu/drm/msm/sde/sde_encoder_phys_vid.c
@@ -268,7 +268,7 @@
timing = &vid_enc->timing_params;
vfp_fetch_lines = programmable_fetch_get_num_lines(vid_enc, timing);
- if (vfp_fetch_lines && rot_fetch_lines) {
+ if (rot_fetch_lines) {
vert_total = get_vertical_total(timing);
horiz_total = get_horizontal_total(timing);
if (vert_total >= (vfp_fetch_lines + rot_fetch_lines)) {
@@ -277,6 +277,13 @@
horiz_total + 1;
f.enable = 1;
f.fetch_start = rot_fetch_start_vsync_counter;
+ } else {
+ SDE_ERROR_VIDENC(vid_enc,
+ "vert_total %u rot_fetch_lines %u vfp_fetch_lines %u\n",
+ vert_total, rot_fetch_lines, vfp_fetch_lines);
+ SDE_EVT32(DRMID(phys_enc->parent), vert_total,
+ rot_fetch_lines, vfp_fetch_lines,
+ SDE_EVTLOG_ERROR);
}
}
diff --git a/drivers/gpu/drm/msm/sde/sde_hw_ctl.c b/drivers/gpu/drm/msm/sde/sde_hw_ctl.c
index 426ecf1..4437987 100644
--- a/drivers/gpu/drm/msm/sde/sde_hw_ctl.c
+++ b/drivers/gpu/drm/msm/sde/sde_hw_ctl.c
@@ -610,6 +610,35 @@
SDE_REG_WRITE(c, CTL_TOP, intf_cfg);
}
+static inline u32 sde_hw_ctl_read_ctl_top(struct sde_hw_ctl *ctx)
+{
+ struct sde_hw_blk_reg_map *c;
+ u32 ctl_top;
+
+ if (!ctx) {
+ pr_err("Invalid input argument\n");
+ return 0;
+ }
+ c = &ctx->hw;
+ ctl_top = SDE_REG_READ(c, CTL_TOP);
+ return ctl_top;
+}
+
+static inline u32 sde_hw_ctl_read_ctl_layers(struct sde_hw_ctl *ctx, int index)
+{
+ struct sde_hw_blk_reg_map *c;
+ u32 ctl_top;
+
+ if (!ctx) {
+ pr_err("Invalid input argument\n");
+ return 0;
+ }
+ c = &ctx->hw;
+ ctl_top = SDE_REG_READ(c, CTL_LAYER(index));
+ pr_debug("Ctl_layer value = 0x%x\n", ctl_top);
+ return ctl_top;
+}
+
static void sde_hw_ctl_setup_sbuf_cfg(struct sde_hw_ctl *ctx,
struct sde_ctl_sbuf_cfg *cfg)
{
@@ -640,6 +669,8 @@
ops->get_flush_register = sde_hw_ctl_get_flush_register;
ops->trigger_start = sde_hw_ctl_trigger_start;
ops->trigger_pending = sde_hw_ctl_trigger_pending;
+ ops->read_ctl_top = sde_hw_ctl_read_ctl_top;
+ ops->read_ctl_layers = sde_hw_ctl_read_ctl_layers;
ops->setup_intf_cfg = sde_hw_ctl_intf_cfg;
ops->reset = sde_hw_ctl_reset_control;
ops->hard_reset = sde_hw_ctl_hard_reset;
@@ -663,27 +694,6 @@
}
};
-#define CTL_BASE_OFFSET 0x2000
-#define CTL_TOP_OFFSET(index) (CTL_BASE_OFFSET + (0x200 * (index)) + CTL_TOP)
-
-void sde_get_ctl_top_for_cont_splash(void __iomem *mmio,
- struct ctl_top *top, int index)
-{
- if (!mmio || !top) {
- SDE_ERROR("invalid input parameters\n");
- return;
- }
-
- top->value = readl_relaxed(mmio + CTL_TOP_OFFSET(index));
- top->intf_sel = (top->value >> 4) & 0xf;
- top->pp_sel = (top->value >> 8) & 0x7;
- top->dspp_sel = (top->value >> 11) & 0x3;
- top->mode_sel = (top->value >> 17) & 0x1;
-
- SDE_DEBUG("ctl[%d]_top->0x%x,pp_sel=0x%x,dspp_sel=0x%x,intf_sel=0x%x\n",
- index, top->value, top->pp_sel, top->dspp_sel, top->intf_sel);
-}
-
static struct sde_hw_blk_ops sde_hw_ops = {
.start = NULL,
.stop = NULL,
diff --git a/drivers/gpu/drm/msm/sde/sde_hw_ctl.h b/drivers/gpu/drm/msm/sde/sde_hw_ctl.h
index f8594da..a9bd104 100644
--- a/drivers/gpu/drm/msm/sde/sde_hw_ctl.h
+++ b/drivers/gpu/drm/msm/sde/sde_hw_ctl.h
@@ -201,6 +201,23 @@
enum sde_rot blk);
/**
+ * read CTL_TOP register value and return
+ * the data.
+ * @ctx : ctl path ctx pointer
+ * @return : CTL top register value
+ */
+ u32 (*read_ctl_top)(struct sde_hw_ctl *ctx);
+
+ /**
+ * read CTL layers register value and return
+ * the data.
+ * @ctx : ctl path ctx pointer
+ * @index : layer index for this ctl path
+ * @return : CTL layers register value
+ */
+ u32 (*read_ctl_layers)(struct sde_hw_ctl *ctx, int index);
+
+ /**
* Set all blend stages to disabled
* @ctx : ctl path ctx pointer
*/
@@ -269,15 +286,6 @@
void __iomem *mmio);
/**
- * sde_get_ctl_top_for_cont_splash - retrieve the current LM blocks
- * @mmio: mapped register io address of MDP
- * @top: pointer to the current "ctl_top" structure thats needs update
- * @index: ctl_top index
- */
-void sde_get_ctl_top_for_cont_splash(void __iomem *mmio,
- struct ctl_top *top, int index);
-
-/**
* sde_hw_ctl - convert base object sde_hw_base to container
* @hw: Pointer to base hardware block
* return: Pointer to hardware block container
diff --git a/drivers/gpu/drm/msm/sde/sde_hw_lm.c b/drivers/gpu/drm/msm/sde/sde_hw_lm.c
index 134db51..4e677c2 100644
--- a/drivers/gpu/drm/msm/sde/sde_hw_lm.c
+++ b/drivers/gpu/drm/msm/sde/sde_hw_lm.c
@@ -278,43 +278,6 @@
}
};
-#define CTL_BASE_OFFSET 0x2000
-#define CTL_TOP_LM_OFFSET(index, lm) \
- (CTL_BASE_OFFSET + (0x200 * index) + (lm * 0x4))
-
-int sde_get_ctl_lm_for_cont_splash(void __iomem *mmio, int max_lm_cnt,
- u8 lm_cnt, u8 *lm_ids, struct ctl_top *top, int index)
-{
- int j;
- struct sde_splash_lm_hw *lm;
-
- if (!mmio || !top || !lm_ids) {
- SDE_ERROR("invalid input parameters\n");
- return 0;
- }
-
- lm = top->lm;
- for (j = 0; j < max_lm_cnt; j++) {
- lm[top->ctl_lm_cnt].lm_reg_value = readl_relaxed(mmio
- + CTL_TOP_LM_OFFSET(index, j));
- SDE_DEBUG("ctl[%d]_top --> lm[%d]=0x%x, j=%d\n",
- index, top->ctl_lm_cnt,
- lm[top->ctl_lm_cnt].lm_reg_value, j);
- SDE_DEBUG("lm_cnt = %d\n", lm_cnt);
- if (lm[top->ctl_lm_cnt].lm_reg_value) {
- lm[top->ctl_lm_cnt].ctl_id = index;
- lm_ids[lm_cnt++] = j + LM_0;
- lm[top->ctl_lm_cnt].lm_id = j + LM_0;
- SDE_DEBUG("ctl_id=%d, lm[%d].lm_id = %d\n",
- lm[top->ctl_lm_cnt].ctl_id,
- top->ctl_lm_cnt,
- lm[top->ctl_lm_cnt].lm_id);
- top->ctl_lm_cnt++;
- }
- }
- return top->ctl_lm_cnt;
-}
-
static struct sde_hw_blk_ops sde_hw_ops = {
.start = NULL,
.stop = NULL,
diff --git a/drivers/gpu/drm/msm/sde/sde_hw_lm.h b/drivers/gpu/drm/msm/sde/sde_hw_lm.h
index a2307ec..8a146bd 100644
--- a/drivers/gpu/drm/msm/sde/sde_hw_lm.h
+++ b/drivers/gpu/drm/msm/sde/sde_hw_lm.h
@@ -117,19 +117,6 @@
}
/**
- * sde_get_ctl_lm_for_cont_splash - retrieve the current LM blocks
- * @mmio: mapped register io address of MDP
- * @max_lm_cnt: number of LM blocks supported in the hw
- * @lm_cnt: number of LM blocks already active
- * @lm_ids: pointer to store the active LM block IDs
- * @top: pointer to the current "ctl_top" structure
- * @index: ctl_top index
- * return: number of active LM blocks for this CTL block
- */
-int sde_get_ctl_lm_for_cont_splash(void __iomem *mmio, int max_lm_cnt,
- u8 lm_cnt, u8 *lm_ids, struct ctl_top *top, int index);
-
-/**
* sde_hw_lm_init(): Initializes the mixer hw driver object.
* should be called once before accessing every mixer.
* @idx: mixer index for which driver object is required
diff --git a/drivers/gpu/drm/msm/sde/sde_hw_mdss.h b/drivers/gpu/drm/msm/sde/sde_hw_mdss.h
index 3125ebf..7977294 100644
--- a/drivers/gpu/drm/msm/sde/sde_hw_mdss.h
+++ b/drivers/gpu/drm/msm/sde/sde_hw_mdss.h
@@ -581,6 +581,7 @@
* @ctl_top_cnt:stores the active number of MDSS "top" blks of the current mode
* @lm_cnt: stores the active number of MDSS "LM" blks for the current mode
* @dsc_cnt: stores the active number of MDSS "dsc" blks for the current mode
+ * @cont_splash_en: Stores the cont_splash status (enabled/disbled)
*/
struct sde_splash_data {
bool smmu_handoff_pending;
@@ -593,6 +594,7 @@
u8 ctl_top_cnt;
u8 lm_cnt;
u8 dsc_cnt;
+ bool cont_splash_en;
};
#endif /* _SDE_HW_MDSS_H */
diff --git a/drivers/gpu/drm/msm/sde/sde_hw_pingpong.c b/drivers/gpu/drm/msm/sde/sde_hw_pingpong.c
index 050e21b..2a03785 100644
--- a/drivers/gpu/drm/msm/sde/sde_hw_pingpong.c
+++ b/drivers/gpu/drm/msm/sde/sde_hw_pingpong.c
@@ -162,6 +162,17 @@
SDE_REG_WRITE(c, PP_DSC_MODE, 1);
}
+static u32 sde_hw_pp_get_dsc_status(struct sde_hw_pingpong *pp)
+{
+ struct sde_hw_blk_reg_map *c;
+
+ if (!pp)
+ return 0;
+
+ c = &pp->hw;
+ return SDE_REG_READ(c, PP_DSC_MODE);
+}
+
static void sde_hw_pp_dsc_disable(struct sde_hw_pingpong *pp)
{
struct sde_hw_blk_reg_map *c;
@@ -342,6 +353,7 @@
ops->setup_dsc = sde_hw_pp_setup_dsc;
ops->enable_dsc = sde_hw_pp_dsc_enable;
ops->disable_dsc = sde_hw_pp_dsc_disable;
+ ops->get_dsc_status = sde_hw_pp_get_dsc_status;
ops->get_autorefresh = sde_hw_pp_get_autorefresh_config;
ops->poll_timeout_wr_ptr = sde_hw_pp_poll_timeout_wr_ptr;
ops->get_line_count = sde_hw_pp_get_line_count;
@@ -357,49 +369,6 @@
}
};
-#define MDP_PP_DSC_OFFSET(index) (0x71000 + (0x800 * index) + 0x0a0)
-#define MDP_PP_AUTOREFRESH_OFFSET(index) (0x71000 + (0x800 * index) + 0x030)
-
-int sde_get_pp_dsc_for_cont_splash(void __iomem *mmio,
- int max_dsc_cnt, u8 *dsc_ids)
-{
- int index;
- int value, dsc_cnt = 0;
-
- if (!mmio || !dsc_ids) {
- SDE_ERROR("invalid input parameters\n");
- return 0;
- }
-
- SDE_DEBUG("max_dsc_cnt = %d\n", max_dsc_cnt);
- for (index = 0; index < max_dsc_cnt; index++) {
- value = readl_relaxed(mmio
- + MDP_PP_DSC_OFFSET(index));
- SDE_DEBUG("DSC[%d]=0x%x\n",
- index, value);
- SDE_DEBUG("dsc_cnt = %d\n", dsc_cnt);
- if (value) {
- dsc_ids[dsc_cnt] = index + DSC_0;
- dsc_cnt++;
- }
- value = readl_relaxed(mmio
- + MDP_PP_AUTOREFRESH_OFFSET(index));
- SDE_DEBUG("AUTOREFRESH[%d]=0x%x\n",
- index, value);
- if (value) {
- SDE_DEBUG("Disabling autoreferesh\n");
- writel_relaxed(0x0, mmio
- + MDP_PP_AUTOREFRESH_OFFSET(index));
- /*
- * Wait for one frame update so that auto refresh
- * disable is through
- */
- usleep_range(16000, 20000);
- }
- }
- return dsc_cnt;
-}
-
static struct sde_hw_blk_ops sde_hw_ops = {
.start = NULL,
.stop = NULL,
diff --git a/drivers/gpu/drm/msm/sde/sde_hw_pingpong.h b/drivers/gpu/drm/msm/sde/sde_hw_pingpong.h
index fef49f4..4911658 100644
--- a/drivers/gpu/drm/msm/sde/sde_hw_pingpong.h
+++ b/drivers/gpu/drm/msm/sde/sde_hw_pingpong.h
@@ -128,6 +128,12 @@
void (*disable_dsc)(struct sde_hw_pingpong *pp);
/**
+ * Get DSC status
+ * @Return: register value of DSC config
+ */
+ u32 (*get_dsc_status)(struct sde_hw_pingpong *pp);
+
+ /**
* Program the dither hw block
*/
int (*setup_dither)(struct sde_hw_pingpong *pp, void *cfg, size_t len);
@@ -161,16 +167,6 @@
}
/**
- * sde_get_pp_dsc_for_cont_splash - retrieve the current dsc enabled blocks
- * @mmio: mapped register io address of MDP
- * @max_dsc_cnt: number of DSC blocks supported in the hw
- * @dsc_ids: pointer to store the active DSC block IDs
- * return: number of active DSC blocks
- */
-int sde_get_pp_dsc_for_cont_splash(void __iomem *mmio,
- int max_dsc_cnt, u8 *dsc_ids);
-
-/**
* sde_hw_pingpong_init - initializes the pingpong driver for the passed
* pingpong idx.
* @idx: Pingpong index for which driver object is required
diff --git a/drivers/gpu/drm/msm/sde/sde_hw_reg_dma_v1.c b/drivers/gpu/drm/msm/sde/sde_hw_reg_dma_v1.c
index cf65784..6ccf957 100644
--- a/drivers/gpu/drm/msm/sde/sde_hw_reg_dma_v1.c
+++ b/drivers/gpu/drm/msm/sde/sde_hw_reg_dma_v1.c
@@ -481,6 +481,7 @@
cmd1 |= (cfg->op == REG_DMA_WRITE) ? (BIT(22)) : 0;
cmd1 |= (SIZE_DWORD(cfg->dma_buf->index) & MAX_DWORDS_SZ);
+ msm_gem_sync(cfg->dma_buf->buf);
SET_UP_REG_DMA_REG(hw, reg_dma);
SDE_REG_WRITE(&hw, REG_DMA_OP_MODE_OFF, BIT(0));
SDE_REG_WRITE(&hw, reg_dma_clear_status_off,
diff --git a/drivers/gpu/drm/msm/sde/sde_hw_sspp.c b/drivers/gpu/drm/msm/sde/sde_hw_sspp.c
index e7aa6ea..0d85c53 100644
--- a/drivers/gpu/drm/msm/sde/sde_hw_sspp.c
+++ b/drivers/gpu/drm/msm/sde/sde_hw_sspp.c
@@ -260,13 +260,13 @@
*/
static void sde_hw_sspp_setup_format(struct sde_hw_pipe *ctx,
const struct sde_format *fmt,
- bool blend_enabled, u32 flags,
+ bool const_alpha_en, u32 flags,
enum sde_sspp_multirect_index rect_mode)
{
struct sde_hw_blk_reg_map *c;
u32 chroma_samp, unpack, src_format;
u32 opmode = 0;
- u32 fast_clear = 0;
+ u32 alpha_en_mask = 0;
u32 op_mode_off, unpack_pat_off, format_off;
u32 idx;
@@ -329,11 +329,10 @@
SDE_FETCH_CONFIG_RESET_VALUE |
ctx->mdp->highest_bank_bit << 18);
if (IS_UBWC_20_SUPPORTED(ctx->catalog->ubwc_version)) {
- fast_clear = (fmt->alpha_enable && blend_enabled) ?
- BIT(31) : 0;
+ alpha_en_mask = const_alpha_en ? BIT(31) : 0;
SDE_REG_WRITE(c, SSPP_UBWC_STATIC_CTRL,
- fast_clear | (ctx->mdp->ubwc_swizzle) |
- (ctx->mdp->highest_bank_bit << 4));
+ alpha_en_mask | (ctx->mdp->ubwc_swizzle) |
+ (ctx->mdp->highest_bank_bit << 4));
}
}
diff --git a/drivers/gpu/drm/msm/sde/sde_irq.c b/drivers/gpu/drm/msm/sde/sde_irq.c
index 10435da..e25d8fb 100644
--- a/drivers/gpu/drm/msm/sde/sde_irq.c
+++ b/drivers/gpu/drm/msm/sde/sde_irq.c
@@ -104,7 +104,7 @@
}
/* disable irq until power event enables it */
- if (!sde_kms->cont_splash_en)
+ if (!sde_kms->splash_data.cont_splash_en)
irq_set_status_flags(sde_kms->irq_num, IRQ_NOAUTOEN);
}
diff --git a/drivers/gpu/drm/msm/sde/sde_kms.c b/drivers/gpu/drm/msm/sde/sde_kms.c
index a54e39a9..bbd6f45 100644
--- a/drivers/gpu/drm/msm/sde/sde_kms.c
+++ b/drivers/gpu/drm/msm/sde/sde_kms.c
@@ -666,9 +666,9 @@
SDE_EVT32_VERBOSE(SDE_EVTLOG_FUNC_EXIT);
- if (sde_kms->cont_splash_en) {
+ if (sde_kms->splash_data.cont_splash_en) {
SDE_DEBUG("Disabling cont_splash feature\n");
- sde_kms->cont_splash_en = false;
+ sde_kms->splash_data.cont_splash_en = false;
sde_power_resource_enable(&priv->phandle,
sde_kms->core_client, false);
SDE_DEBUG("removing Vote for MDP Resources\n");
@@ -2165,7 +2165,7 @@
return -EINVAL;
}
- if (!sde_kms->cont_splash_en) {
+ if (!sde_kms->splash_data.cont_splash_en) {
DRM_INFO("cont_splash feature not enabled\n");
return rc;
}
@@ -2323,7 +2323,8 @@
if (num_crtcs == 0) {
DRM_DEBUG("all crtcs are already in the off state\n");
drm_atomic_state_free(state);
- goto suspended;
+ sde_kms->suspend_block = true;
+ goto unlock;
}
/* commit the "disable all" state */
@@ -2334,9 +2335,24 @@
goto unlock;
}
-suspended:
sde_kms->suspend_block = true;
+ drm_for_each_connector(conn, ddev) {
+ uint64_t lp;
+
+ lp = sde_connector_get_lp(conn);
+ if (lp != SDE_MODE_DPMS_LP2)
+ continue;
+
+ ret = sde_encoder_wait_for_event(conn->encoder,
+ MSM_ENC_TX_COMPLETE);
+ if (ret && ret != -EWOULDBLOCK)
+ SDE_ERROR(
+ "[enc: %d] wait for commit done returned %d\n",
+ conn->encoder->base.id, ret);
+ else if (!ret)
+ sde_encoder_idle_request(conn->encoder);
+ }
unlock:
if (ret == -EDEADLK) {
drm_modeset_backoff(&ctx);
@@ -2489,68 +2505,6 @@
return ret;
}
-/* the caller api needs to turn on clock before calling this function */
-static int _sde_kms_cont_splash_res_init(struct sde_kms *sde_kms)
-{
- struct sde_mdss_cfg *cat;
- struct drm_device *dev;
- struct msm_drm_private *priv;
- struct sde_splash_data *splash_data;
- int i;
- int ctl_top_cnt;
-
- if (!sde_kms || !sde_kms->catalog) {
- SDE_ERROR("invalid kms\n");
- return -EINVAL;
- }
- cat = sde_kms->catalog;
- dev = sde_kms->dev;
- priv = dev->dev_private;
- splash_data = &sde_kms->splash_data;
- SDE_DEBUG("mixer_count=%d, ctl_count=%d, dsc_count=%d\n",
- cat->mixer_count,
- cat->ctl_count,
- cat->dsc_count);
-
- ctl_top_cnt = cat->ctl_count;
-
- if (ctl_top_cnt > ARRAY_SIZE(splash_data->top)) {
- SDE_ERROR("Mismatch in ctl_top array size\n");
- return -EINVAL;
- }
- for (i = 0; i < ctl_top_cnt; i++) {
- sde_get_ctl_top_for_cont_splash(sde_kms->mmio,
- &splash_data->top[i], i);
- if (splash_data->top[i].intf_sel) {
- splash_data->lm_cnt +=
- sde_get_ctl_lm_for_cont_splash
- (sde_kms->mmio,
- sde_kms->catalog->mixer_count,
- splash_data->lm_cnt,
- splash_data->lm_ids,
- &splash_data->top[i], i);
- splash_data->ctl_ids[splash_data->ctl_top_cnt]
- = i + CTL_0;
- splash_data->ctl_top_cnt++;
- sde_kms->cont_splash_en = true;
- }
- }
-
- /* Skip DSC blk reads if cont_splash is disabled */
- if (!sde_kms->cont_splash_en)
- return 0;
-
- splash_data->dsc_cnt =
- sde_get_pp_dsc_for_cont_splash(sde_kms->mmio,
- sde_kms->catalog->dsc_count,
- splash_data->dsc_ids);
- SDE_DEBUG("splash_data: ctl_top_cnt=%d, lm_cnt=%d, dsc_cnt=%d\n",
- splash_data->ctl_top_cnt, splash_data->lm_cnt,
- splash_data->dsc_cnt);
-
- return 0;
-}
-
static void sde_kms_handle_power_event(u32 event_type, void *usr)
{
struct sde_kms *sde_kms = usr;
@@ -2663,6 +2617,7 @@
struct sde_kms *sde_kms;
struct drm_device *dev;
struct msm_drm_private *priv;
+ struct sde_rm *rm = NULL;
bool splash_mem_found = false;
int i, rc = -EINVAL;
@@ -2787,12 +2742,24 @@
sde_dbg_init_dbg_buses(sde_kms->core_rev);
+ rm = &sde_kms->rm;
+ rc = sde_rm_init(rm, sde_kms->catalog, sde_kms->mmio,
+ sde_kms->dev);
+ if (rc) {
+ SDE_ERROR("rm init failed: %d\n", rc);
+ goto power_error;
+ }
+
+ sde_kms->rm_init = true;
+
/*
* Attempt continuous splash handoff only if reserved
* splash memory is found.
*/
if (splash_mem_found)
- _sde_kms_cont_splash_res_init(sde_kms);
+ sde_rm_cont_splash_res_init(&sde_kms->rm,
+ &sde_kms->splash_data,
+ sde_kms->catalog);
/* Initialize reg dma block which is a singleton */
rc = sde_reg_dma_init(sde_kms->reg_dma, sde_kms->catalog,
@@ -2807,16 +2774,6 @@
SDE_ERROR("sde_kms_mmu_init failed: %d\n", rc);
goto power_error;
}
-
- rc = sde_rm_init(&sde_kms->rm, sde_kms->catalog, sde_kms->mmio,
- sde_kms->dev);
- if (rc) {
- SDE_ERROR("rm init failed: %d\n", rc);
- goto power_error;
- }
-
- sde_kms->rm_init = true;
-
sde_kms->hw_mdp = sde_rm_get_mdp(&sde_kms->rm);
if (IS_ERR_OR_NULL(sde_kms->hw_mdp)) {
rc = PTR_ERR(sde_kms->hw_mdp);
@@ -2925,7 +2882,7 @@
SDE_DEBUG("added genpd provider %s\n", sde_kms->genpd.name);
}
- if (sde_kms->cont_splash_en)
+ if (sde_kms->splash_data.cont_splash_en)
SDE_DEBUG("Skipping MDP Resources disable\n");
else
sde_power_resource_enable(&priv->phandle,
diff --git a/drivers/gpu/drm/msm/sde/sde_kms.h b/drivers/gpu/drm/msm/sde/sde_kms.h
index 501797b..48f85bf 100644
--- a/drivers/gpu/drm/msm/sde/sde_kms.h
+++ b/drivers/gpu/drm/msm/sde/sde_kms.h
@@ -216,7 +216,6 @@
struct sde_rm rm;
bool rm_init;
struct sde_splash_data splash_data;
- bool cont_splash_en;
struct sde_hw_vbif *hw_vbif[VBIF_MAX];
struct sde_hw_mdp *hw_mdp;
int dsi_display_count;
diff --git a/drivers/gpu/drm/msm/sde/sde_plane.c b/drivers/gpu/drm/msm/sde/sde_plane.c
index 9f27286..f2f870f 100644
--- a/drivers/gpu/drm/msm/sde/sde_plane.c
+++ b/drivers/gpu/drm/msm/sde/sde_plane.c
@@ -2810,6 +2810,7 @@
bool parallel_fetch_qualified = true;
enum sde_sspp_multirect_mode mode = SDE_SSPP_MULTIRECT_NONE;
const struct msm_format *msm_fmt;
+ bool const_alpha_enable = true;
for (i = 0; i < R_MAX; i++) {
drm_state[i] = i ? plane->r1 : plane->r0;
@@ -2877,6 +2878,10 @@
if (sde_plane[i]->is_virtual)
mode = sde_plane_get_property(pstate[i],
PLANE_PROP_MULTIRECT_MODE);
+
+ if (pstate[i]->const_alpha_en != const_alpha_enable)
+ const_alpha_enable = false;
+
}
buffer_lines = 2 * max_tile_height;
@@ -2936,8 +2941,10 @@
break;
}
- for (i = 0; i < R_MAX; i++)
+ for (i = 0; i < R_MAX; i++) {
pstate[i]->multirect_mode = mode;
+ pstate[i]->const_alpha_en = const_alpha_enable;
+ }
if (mode == SDE_SSPP_MULTIRECT_NONE)
return -EINVAL;
@@ -3138,6 +3145,29 @@
return sde_vbif_halt_plane_xin(sde_kms, xin_id, clk_ctrl);
}
+
+static inline int _sde_plane_power_enable(struct drm_plane *plane, bool enable)
+{
+ struct msm_drm_private *priv;
+ struct sde_kms *sde_kms;
+
+ if (!plane->dev || !plane->dev->dev_private) {
+ SDE_ERROR("invalid drm device\n");
+ return -EINVAL;
+ }
+
+ priv = plane->dev->dev_private;
+ if (!priv->kms) {
+ SDE_ERROR("invalid kms\n");
+ return -EINVAL;
+ }
+
+ sde_kms = to_sde_kms(priv->kms);
+
+ return sde_power_resource_enable(&priv->phandle, sde_kms->core_client,
+ enable);
+}
+
static void sde_plane_cleanup_fb(struct drm_plane *plane,
struct drm_plane_state *old_state)
{
@@ -3163,6 +3193,13 @@
psde->pipe - SSPP_VIG0);
/* halt this plane now */
+ ret = _sde_plane_power_enable(plane, true);
+ if (ret) {
+ SDE_ERROR("power resource enable failed with %d", ret);
+ SDE_EVT32(ret);
+ return;
+ }
+
ret = _sde_plane_fetch_halt(plane);
if (ret) {
SDE_ERROR_PLANE(psde,
@@ -3171,6 +3208,7 @@
SDE_EVT32(DRMID(plane), psde->pipe - SSPP_VIG0,
ret, SDE_EVTLOG_ERROR);
}
+ _sde_plane_power_enable(plane, false);
}
old_rstate = &old_pstate->rot;
@@ -3541,6 +3579,10 @@
pstate->excl_rect.w, pstate->excl_rect.h);
}
+ pstate->const_alpha_en = fmt->alpha_enable &&
+ (SDE_DRM_BLEND_OP_OPAQUE !=
+ sde_plane_get_property(pstate, PLANE_PROP_BLEND_OP));
+
modeset_update:
if (!ret)
_sde_plane_sspp_atomic_check_mode_changed(psde,
@@ -3638,7 +3680,6 @@
struct drm_framebuffer *fb;
struct sde_rect src, dst;
bool q16_data = true;
- bool blend_enabled = true;
int idx;
if (!plane) {
@@ -3876,12 +3917,9 @@
if (rstate->out_rotation & DRM_REFLECT_Y)
src_flags |= SDE_SSPP_FLIP_UD;
- blend_enabled = (SDE_DRM_BLEND_OP_OPAQUE !=
- sde_plane_get_property(pstate, PLANE_PROP_BLEND_OP));
-
/* update format */
psde->pipe_hw->ops.setup_format(psde->pipe_hw, fmt,
- blend_enabled, src_flags,
+ pstate->const_alpha_en, src_flags,
pstate->multirect_index);
if (psde->pipe_hw->ops.setup_cdp) {
diff --git a/drivers/gpu/drm/msm/sde/sde_plane.h b/drivers/gpu/drm/msm/sde/sde_plane.h
index d1eb399..e8b621c 100644
--- a/drivers/gpu/drm/msm/sde/sde_plane.h
+++ b/drivers/gpu/drm/msm/sde/sde_plane.h
@@ -128,6 +128,7 @@
* @dirty: bitmask for which pipe h/w config functions need to be updated
* @multirect_index: index of the rectangle of SSPP
* @multirect_mode: parallel or time multiplex multirect mode
+ * @const_alpha_en: const alpha channel is enabled for this HW pipe
* @pending: whether the current update is still pending
* @defer_prepare_fb: indicate if prepare_fb call was deferred
* @scaler3_cfg: configuration data for scaler3
@@ -146,6 +147,7 @@
uint32_t dirty;
uint32_t multirect_index;
uint32_t multirect_mode;
+ bool const_alpha_en;
bool pending;
bool defer_prepare_fb;
diff --git a/drivers/gpu/drm/msm/sde/sde_rm.c b/drivers/gpu/drm/msm/sde/sde_rm.c
index c2c1f75..1b71a82 100644
--- a/drivers/gpu/drm/msm/sde/sde_rm.c
+++ b/drivers/gpu/drm/msm/sde/sde_rm.c
@@ -1129,6 +1129,204 @@
return ret;
}
+/**
+ * sde_rm_get_pp_dsc_for_cont_splash - retrieve the current dsc enabled blocks
+ * and disable autorefresh if enabled.
+ * @mmio: mapped register io address of MDP
+ * @max_dsc_cnt: number of DSC blocks supported in the hw
+ * @dsc_ids: pointer to store the active DSC block IDs
+ * return: number of active DSC blocks
+ */
+static int _sde_rm_get_pp_dsc_for_cont_splash(struct sde_rm *rm,
+ int max_dsc_cnt, u8 *dsc_ids)
+{
+ int index = 0;
+ int value, dsc_cnt = 0;
+ struct sde_hw_autorefresh cfg;
+ struct sde_rm_hw_iter iter_pp;
+
+ if (!rm || !dsc_ids) {
+ SDE_ERROR("invalid input parameters\n");
+ return 0;
+ }
+
+ SDE_DEBUG("max_dsc_cnt = %d\n", max_dsc_cnt);
+ sde_rm_init_hw_iter(&iter_pp, 0, SDE_HW_BLK_PINGPONG);
+ while (_sde_rm_get_hw_locked(rm, &iter_pp)) {
+ struct sde_hw_pingpong *pp =
+ to_sde_hw_pingpong(iter_pp.blk->hw);
+
+ if (!pp->ops.get_dsc_status) {
+ SDE_ERROR("get_dsc_status ops not initialized\n");
+ return 0;
+ }
+ value = pp->ops.get_dsc_status(pp);
+ SDE_DEBUG("DSC[%d]=0x%x, dsc_cnt = %d\n",
+ index, value, dsc_cnt);
+ if (value) {
+ dsc_ids[dsc_cnt] = index + DSC_0;
+ dsc_cnt++;
+ }
+ index++;
+
+ if (!pp->ops.get_autorefresh) {
+ SDE_ERROR("get_autorefresh api not supported\n");
+ return 0;
+ }
+ memset(&cfg, 0, sizeof(cfg));
+ if (!pp->ops.get_autorefresh(pp, &cfg)
+ && (cfg.enable)
+ && (pp->ops.setup_autorefresh)) {
+ cfg.enable = false;
+ SDE_DEBUG("Disabling autoreferesh\n");
+ pp->ops.setup_autorefresh(pp, &cfg);
+ /*
+ * Wait for one frame update so that
+ * auto refresh disable is through
+ */
+ usleep_range(16000, 20000);
+ }
+ }
+
+ return dsc_cnt;
+}
+
+/**
+ * _sde_rm_get_ctl_lm_for_cont_splash - retrieve the current LM blocks
+ * @ctl: Pointer to CTL hardware block
+ * @max_lm_cnt: number of LM blocks supported in the hw
+ * @lm_cnt: number of LM blocks already active
+ * @lm_ids: pointer to store the active LM block IDs
+ * @top: pointer to the current "ctl_top" structure
+ * @index: ctl_top index
+ * return: number of active LM blocks for this CTL block
+ */
+static int _sde_rm_get_ctl_lm_for_cont_splash(struct sde_hw_ctl *ctl,
+ int max_lm_cnt, u8 lm_cnt,
+ u8 *lm_ids, struct ctl_top *top,
+ int index)
+{
+ int j;
+ struct sde_splash_lm_hw *lm;
+
+ if (!ctl || !top || !lm_ids) {
+ SDE_ERROR("invalid input parameters\n");
+ return 0;
+ }
+
+ lm = top->lm;
+ for (j = 0; j < max_lm_cnt; j++) {
+ lm[top->ctl_lm_cnt].lm_reg_value =
+ ctl->ops.read_ctl_layers(ctl, j + LM_0);
+ SDE_DEBUG("ctl[%d]_top --> lm[%d]=0x%x, j=%d\n",
+ index, top->ctl_lm_cnt,
+ lm[top->ctl_lm_cnt].lm_reg_value, j);
+ SDE_DEBUG("lm_cnt = %d\n", lm_cnt);
+ if (lm[top->ctl_lm_cnt].lm_reg_value) {
+ lm[top->ctl_lm_cnt].ctl_id = index;
+ lm_ids[lm_cnt++] = j + LM_0;
+ lm[top->ctl_lm_cnt].lm_id = j + LM_0;
+ SDE_DEBUG("ctl_id=%d, lm[%d].lm_id = %d\n",
+ lm[top->ctl_lm_cnt].ctl_id,
+ top->ctl_lm_cnt,
+ lm[top->ctl_lm_cnt].lm_id);
+ top->ctl_lm_cnt++;
+ }
+ }
+ return top->ctl_lm_cnt;
+}
+
+/**
+ * _sde_rm_get_ctl_top_for_cont_splash - retrieve the current LM blocks
+ * @ctl: Pointer to CTL hardware block
+ * @top: pointer to the current "ctl_top" structure thats needs update
+ * @index: ctl_top index
+ */
+static void _sde_rm_get_ctl_top_for_cont_splash(struct sde_hw_ctl *ctl,
+ struct ctl_top *top)
+{
+ if (!ctl || !top) {
+ SDE_ERROR("invalid input parameters\n");
+ return;
+ }
+
+ if (!ctl->ops.read_ctl_top) {
+ SDE_ERROR("read_ctl_top not initialized\n");
+ return;
+ }
+
+ top->value = ctl->ops.read_ctl_top(ctl);
+ top->intf_sel = (top->value >> 4) & 0xf;
+ top->pp_sel = (top->value >> 8) & 0x7;
+ top->dspp_sel = (top->value >> 11) & 0x3;
+ top->mode_sel = (top->value >> 17) & 0x1;
+
+ SDE_DEBUG("id=%d,top->0x%x,pp_sel=0x%x,dspp_sel=0x%x,intf_sel=%d\n",
+ ctl->idx, top->value, top->pp_sel,
+ top->dspp_sel, top->intf_sel);
+}
+
+int sde_rm_cont_splash_res_init(struct sde_rm *rm,
+ struct sde_splash_data *splash_data,
+ struct sde_mdss_cfg *cat)
+{
+ struct sde_rm_hw_iter iter_c;
+ int index = 0, ctl_top_cnt;
+
+ if (!rm || !cat || !splash_data) {
+ SDE_ERROR("invalid input parameters\n");
+ return -EINVAL;
+ }
+
+ SDE_DEBUG("mixer_count=%d, ctl_count=%d, dsc_count=%d\n",
+ cat->mixer_count,
+ cat->ctl_count,
+ cat->dsc_count);
+
+ ctl_top_cnt = cat->ctl_count;
+
+ if (ctl_top_cnt > ARRAY_SIZE(splash_data->top)) {
+ SDE_ERROR("Mismatch in ctl_top array size\n");
+ return -EINVAL;
+ }
+
+ sde_rm_init_hw_iter(&iter_c, 0, SDE_HW_BLK_CTL);
+ while (_sde_rm_get_hw_locked(rm, &iter_c)) {
+ struct sde_hw_ctl *ctl = to_sde_hw_ctl(iter_c.blk->hw);
+
+ _sde_rm_get_ctl_top_for_cont_splash(ctl,
+ &splash_data->top[index]);
+ if (splash_data->top[index].intf_sel) {
+ splash_data->lm_cnt +=
+ _sde_rm_get_ctl_lm_for_cont_splash
+ (ctl,
+ cat->mixer_count,
+ splash_data->lm_cnt,
+ splash_data->lm_ids,
+ &splash_data->top[index], index);
+ splash_data->ctl_ids[splash_data->ctl_top_cnt]
+ = index + CTL_0;
+ splash_data->ctl_top_cnt++;
+ splash_data->cont_splash_en = true;
+ }
+ index++;
+ }
+
+ /* Skip DSC blk reads if cont_splash is disabled */
+ if (!splash_data->cont_splash_en)
+ return 0;
+
+ splash_data->dsc_cnt =
+ _sde_rm_get_pp_dsc_for_cont_splash(rm,
+ cat->dsc_count,
+ splash_data->dsc_ids);
+ SDE_DEBUG("splash_data: ctl_top_cnt=%d, lm_cnt=%d, dsc_cnt=%d\n",
+ splash_data->ctl_top_cnt, splash_data->lm_cnt,
+ splash_data->dsc_cnt);
+
+ return 0;
+}
+
static int _sde_rm_make_next_rsvp_for_cont_splash(
struct sde_rm *rm,
struct drm_encoder *enc,
@@ -1484,7 +1682,7 @@
sde_kms = to_sde_kms(priv->kms);
/* Check if this is just a page-flip */
- if (!sde_kms->cont_splash_en &&
+ if (!sde_kms->splash_data.cont_splash_en &&
!drm_atomic_crtc_needs_modeset(crtc_state))
return 0;
@@ -1536,7 +1734,7 @@
}
/* Check the proposed reservation, store it in hw's "next" field */
- if (sde_kms->cont_splash_en) {
+ if (sde_kms->splash_data.cont_splash_en) {
SDE_DEBUG("cont_splash feature enabled\n");
ret = _sde_rm_make_next_rsvp_for_cont_splash
(rm, enc, crtc_state, conn_state, rsvp_nxt, &reqs);
diff --git a/drivers/gpu/drm/msm/sde/sde_rm.h b/drivers/gpu/drm/msm/sde/sde_rm.h
index 0545609..b2dd87d 100644
--- a/drivers/gpu/drm/msm/sde/sde_rm.h
+++ b/drivers/gpu/drm/msm/sde/sde_rm.h
@@ -126,7 +126,7 @@
*/
int sde_rm_init(struct sde_rm *rm,
struct sde_mdss_cfg *cat,
- void *mmio,
+ void __iomem *mmio,
struct drm_device *dev);
/**
@@ -207,6 +207,19 @@
int sde_rm_check_property_topctl(uint64_t val);
/**
+ * sde_rm_cont_splash_res_init - Read the current MDSS configuration
+ * to update the splash data structure with the topology
+ * configured by the bootloader.
+ * @rm: SDE Resource Manager handle
+ * @splash_data: Pointer to the splash_data structure to be updated.
+ * @cat: Pointer to the SDE catalog
+ * @Return: 0 on success or error
+ */
+int sde_rm_cont_splash_res_init(struct sde_rm *rm,
+ struct sde_splash_data *splash_data,
+ struct sde_mdss_cfg *cat);
+
+/**
* sde_rm_update_topology - sets topology property of the connector
* @conn_state: drm state of the connector
* @topology: topology selected for the display
diff --git a/drivers/gpu/drm/msm/sde/sde_trace.h b/drivers/gpu/drm/msm/sde/sde_trace.h
index ef4cdeb..2909778 100644
--- a/drivers/gpu/drm/msm/sde/sde_trace.h
+++ b/drivers/gpu/drm/msm/sde/sde_trace.h
@@ -93,21 +93,24 @@
)
TRACE_EVENT(sde_perf_update_bus,
- TP_PROTO(int client, unsigned long long ab_quota,
+ TP_PROTO(int client, u32 bus_id, unsigned long long ab_quota,
unsigned long long ib_quota),
- TP_ARGS(client, ab_quota, ib_quota),
+ TP_ARGS(client, bus_id, ab_quota, ib_quota),
TP_STRUCT__entry(
__field(int, client)
+ __field(u32, bus_id);
__field(u64, ab_quota)
__field(u64, ib_quota)
),
TP_fast_assign(
__entry->client = client;
+ __entry->bus_id = bus_id;
__entry->ab_quota = ab_quota;
__entry->ib_quota = ib_quota;
),
- TP_printk("Request client:%d ab=%llu ib=%llu",
+ TP_printk("Request client:%d bus_id:%d ab=%llu ib=%llu",
__entry->client,
+ __entry->bus_id,
__entry->ab_quota,
__entry->ib_quota)
)
@@ -209,41 +212,111 @@
)
TRACE_EVENT(sde_perf_crtc_update,
- TP_PROTO(u32 crtc, u64 bw_ctl_mnoc, u64 bw_ctl_llcc,
- u64 bw_ctl_ebi, u32 core_clk_rate,
- bool stop_req, u32 update_bus, u32 update_clk),
- TP_ARGS(crtc, bw_ctl_mnoc, bw_ctl_llcc, bw_ctl_ebi, core_clk_rate,
- stop_req, update_bus, update_clk),
+ TP_PROTO(u32 crtc,
+ u64 bw_ctl_mnoc, u64 per_pipe_ib_mnoc,
+ u64 bw_ctl_llcc, u64 per_pipe_ib_llcc,
+ u64 bw_ctl_ebi, u64 per_pipe_ib_ebi,
+ u32 core_clk_rate, bool stop_req,
+ u32 update_bus, u32 update_clk, int params),
+ TP_ARGS(crtc,
+ bw_ctl_mnoc, per_pipe_ib_mnoc,
+ bw_ctl_llcc, per_pipe_ib_llcc,
+ bw_ctl_ebi, per_pipe_ib_ebi,
+ core_clk_rate, stop_req,
+ update_bus, update_clk, params),
+ TP_STRUCT__entry(
+ __field(u32, crtc)
+ __field(u64, bw_ctl_mnoc)
+ __field(u64, per_pipe_ib_mnoc)
+ __field(u64, bw_ctl_llcc)
+ __field(u64, per_pipe_ib_llcc)
+ __field(u64, bw_ctl_ebi)
+ __field(u64, per_pipe_ib_ebi)
+ __field(u32, core_clk_rate)
+ __field(bool, stop_req)
+ __field(u32, update_bus)
+ __field(u32, update_clk)
+ __field(int, params)
+ ),
+ TP_fast_assign(
+ __entry->crtc = crtc;
+ __entry->bw_ctl_mnoc = bw_ctl_mnoc;
+ __entry->per_pipe_ib_mnoc = per_pipe_ib_mnoc;
+ __entry->bw_ctl_llcc = bw_ctl_llcc;
+ __entry->per_pipe_ib_llcc = per_pipe_ib_llcc;
+ __entry->bw_ctl_ebi = bw_ctl_ebi;
+ __entry->per_pipe_ib_ebi = per_pipe_ib_ebi;
+ __entry->core_clk_rate = core_clk_rate;
+ __entry->stop_req = stop_req;
+ __entry->update_bus = update_bus;
+ __entry->update_clk = update_clk;
+ __entry->params = params;
+ ),
+ TP_printk(
+ "crtc=%d mnoc=[%llu %llu] llcc=[%llu %llu] ebi=[%llu %llu] clk=%u stop=%d ubus=%d uclk=%d %d",
+ __entry->crtc,
+ __entry->bw_ctl_mnoc,
+ __entry->per_pipe_ib_mnoc,
+ __entry->bw_ctl_llcc,
+ __entry->per_pipe_ib_llcc,
+ __entry->bw_ctl_ebi,
+ __entry->per_pipe_ib_ebi,
+ __entry->core_clk_rate,
+ __entry->stop_req,
+ __entry->update_bus,
+ __entry->update_clk,
+ __entry->params)
+);
+
+TRACE_EVENT(sde_perf_calc_crtc,
+ TP_PROTO(u32 crtc,
+ u64 bw_ctl_mnoc,
+ u64 bw_ctl_llcc,
+ u64 bw_ctl_ebi,
+ u64 ib_mnoc,
+ u64 ib_llcc,
+ u64 ib_ebi,
+ u32 core_clk_rate
+ ),
+ TP_ARGS(crtc,
+ bw_ctl_mnoc,
+ bw_ctl_llcc,
+ bw_ctl_ebi,
+ ib_mnoc,
+ ib_llcc,
+ ib_ebi,
+ core_clk_rate),
TP_STRUCT__entry(
__field(u32, crtc)
__field(u64, bw_ctl_mnoc)
__field(u64, bw_ctl_llcc)
__field(u64, bw_ctl_ebi)
+ __field(u64, ib_mnoc)
+ __field(u64, ib_llcc)
+ __field(u64, ib_ebi)
__field(u32, core_clk_rate)
- __field(bool, stop_req)
- __field(u32, update_bus)
- __field(u32, update_clk)
+
),
TP_fast_assign(
__entry->crtc = crtc;
__entry->bw_ctl_mnoc = bw_ctl_mnoc;
__entry->bw_ctl_llcc = bw_ctl_llcc;
__entry->bw_ctl_ebi = bw_ctl_ebi;
+ __entry->ib_mnoc = ib_mnoc;
+ __entry->ib_llcc = ib_llcc;
+ __entry->ib_ebi = ib_ebi;
__entry->core_clk_rate = core_clk_rate;
- __entry->stop_req = stop_req;
- __entry->update_bus = update_bus;
- __entry->update_clk = update_clk;
),
TP_printk(
- "crtc=%d bw_mnoc=%llu bw_llcc=%llu bw_ebi=%llu clk_rate=%u stop_req=%d u_bus=%d u_clk=%d",
+ "crtc=%d mnoc=[%llu, %llu] llcc=[%llu %llu] ebi=[%llu, %llu] clk_rate=%u",
__entry->crtc,
__entry->bw_ctl_mnoc,
+ __entry->ib_mnoc,
__entry->bw_ctl_llcc,
+ __entry->ib_llcc,
__entry->bw_ctl_ebi,
- __entry->core_clk_rate,
- __entry->stop_req,
- __entry->update_bus,
- __entry->update_clk)
+ __entry->ib_ebi,
+ __entry->core_clk_rate)
);
#define SDE_ATRACE_END(name) trace_tracing_mark_write(current->tgid, name, 0)
diff --git a/drivers/gpu/drm/msm/sde_dbg.c b/drivers/gpu/drm/msm/sde_dbg.c
index c34b198..5c72efa 100644
--- a/drivers/gpu/drm/msm/sde_dbg.c
+++ b/drivers/gpu/drm/msm/sde_dbg.c
@@ -71,7 +71,8 @@
#define DBG_CTRL_STOP_FTRACE BIT(0)
#define DBG_CTRL_PANIC_UNDERRUN BIT(1)
-#define DBG_CTRL_MAX BIT(2)
+#define DBG_CTRL_RESET_HW_PANIC BIT(2)
+#define DBG_CTRL_MAX BIT(3)
/**
* struct sde_dbg_reg_offset - tracking for start and end of region
@@ -2709,7 +2710,6 @@
va_list args;
char *blk_name = NULL;
-
/* no debugfs controlled events are enabled, just return */
if (!sde_dbg_base.debugfs_ctrl)
return;
@@ -2738,8 +2738,16 @@
pr_debug("panic underrun\n");
panic("underrun");
}
+
+ if (!strcmp(blk_name, "reset_hw_panic") &&
+ sde_dbg_base.debugfs_ctrl &
+ DBG_CTRL_RESET_HW_PANIC) {
+ pr_debug("reset hw panic\n");
+ panic("reset_hw");
+ }
}
+ va_end(args);
}
diff --git a/drivers/gpu/drm/msm/sde_power_handle.c b/drivers/gpu/drm/msm/sde_power_handle.c
index 34a826d..40542ab 100644
--- a/drivers/gpu/drm/msm/sde_power_handle.c
+++ b/drivers/gpu/drm/msm/sde_power_handle.c
@@ -29,6 +29,7 @@
#include "sde_power_handle.h"
#include "sde_trace.h"
+#include "sde_dbg.h"
static const char *data_bus_name[SDE_POWER_HANDLE_DBUS_ID_MAX] = {
[SDE_POWER_HANDLE_DBUS_ID_MNOC] = "qcom,sde-data-bus",
@@ -470,7 +471,7 @@
pclient->ab[bus_client] = ab_quota;
pclient->ib[bus_client] = ib_quota;
- trace_sde_perf_update_bus(bus_client, ab_quota, ib_quota);
+ trace_sde_perf_update_bus(bus_client, bus_id, ab_quota, ib_quota);
list_for_each_entry(client, &phandle->power_client_clist, list) {
for (i = 0; i < SDE_POWER_HANDLE_DATA_BUS_CLIENT_MAX; i++) {
@@ -932,6 +933,7 @@
goto rsc_err;
}
+ SDE_EVT32_VERBOSE(enable, SDE_EVTLOG_FUNC_CASE1);
rc = msm_dss_enable_clk(mp->clk_config, mp->num_clk, enable);
if (rc) {
pr_err("clock enable failed rc:%d\n", rc);
@@ -945,6 +947,7 @@
sde_power_event_trigger_locked(phandle,
SDE_POWER_EVENT_PRE_DISABLE);
+ SDE_EVT32_VERBOSE(enable, SDE_EVTLOG_FUNC_CASE2);
msm_dss_enable_clk(mp->clk_config, mp->num_clk, enable);
sde_power_rsc_update(phandle, false);
@@ -964,7 +967,9 @@
}
end:
+ SDE_EVT32_VERBOSE(enable, SDE_EVTLOG_FUNC_EXIT);
mutex_unlock(&phandle->phandle_lock);
+
return rc;
clk_err:
diff --git a/drivers/gpu/drm/msm/sde_rsc.c b/drivers/gpu/drm/msm/sde_rsc.c
index 82b1199..ca4f0da 100644
--- a/drivers/gpu/drm/msm/sde_rsc.c
+++ b/drivers/gpu/drm/msm/sde_rsc.c
@@ -39,8 +39,11 @@
/* this time is ~1ms - only wake tcs in any mode */
#define RSC_BACKOFF_TIME_NS (SINGLE_TCS_EXECUTION_TIME + 100)
-/* this time is ~1ms - only wake TCS in mode-0 */
-#define RSC_MODE_THRESHOLD_TIME_IN_NS (SINGLE_TCS_EXECUTION_TIME + 100)
+/**
+ * this time is ~1ms - only wake TCS in mode-0.
+ * This time must be greater than backoff time.
+ */
+#define RSC_MODE_THRESHOLD_TIME_IN_NS (RSC_BACKOFF_TIME_NS + 2700)
/* this time is ~2ms - sleep+ wake TCS in mode-1 */
#define RSC_TIME_SLOT_0_NS ((SINGLE_TCS_EXECUTION_TIME * 2) + 100)
@@ -561,6 +564,23 @@
msleep(PRIMARY_VBLANK_WORST_CASE_MS);
} else {
*wait_vblank_crtc_id = rsc->primary_client->crtc_id;
+
+ /* increase refcount, so we wait for the next vsync */
+ atomic_inc(&rsc->rsc_vsync_wait);
+ SDE_EVT32(atomic_read(&rsc->rsc_vsync_wait));
+ }
+ } else if (atomic_read(&rsc->rsc_vsync_wait)) {
+ SDE_EVT32(rsc->primary_client, rsc->current_state,
+ atomic_read(&rsc->rsc_vsync_wait));
+
+ /* Wait for the vsync, if the refcount is set */
+ rc = wait_event_timeout(rsc->rsc_vsync_waitq,
+ atomic_read(&rsc->rsc_vsync_wait) == 0,
+ msecs_to_jiffies(PRIMARY_VBLANK_WORST_CASE_MS*2));
+ if (!rc) {
+ pr_err("Timeout waiting for vsync\n");
+ SDE_EVT32(atomic_read(&rsc->rsc_vsync_wait),
+ SDE_EVTLOG_ERROR);
}
}
end:
@@ -600,6 +620,23 @@
msleep(PRIMARY_VBLANK_WORST_CASE_MS);
} else {
*wait_vblank_crtc_id = rsc->primary_client->crtc_id;
+
+ /* increase refcount, so we wait for the next vsync */
+ atomic_inc(&rsc->rsc_vsync_wait);
+ SDE_EVT32(atomic_read(&rsc->rsc_vsync_wait));
+ }
+ } else if (atomic_read(&rsc->rsc_vsync_wait)) {
+ SDE_EVT32(rsc->primary_client, rsc->current_state,
+ atomic_read(&rsc->rsc_vsync_wait));
+
+ /* Wait for the vsync, if the refcount is set */
+ rc = wait_event_timeout(rsc->rsc_vsync_waitq,
+ atomic_read(&rsc->rsc_vsync_wait) == 0,
+ msecs_to_jiffies(PRIMARY_VBLANK_WORST_CASE_MS*2));
+ if (!rc) {
+ pr_err("Timeout waiting for vsync\n");
+ SDE_EVT32(atomic_read(&rsc->rsc_vsync_wait),
+ SDE_EVTLOG_ERROR);
}
}
@@ -608,6 +645,65 @@
}
/**
+ * sde_rsc_client_get_vsync_refcount() - returns the status of the vsync
+ * refcount, to signal if the client needs to reset the refcounting logic
+ * @client: Client pointer provided by sde_rsc_client_create().
+ *
+ * Return: value of the vsync refcount.
+ */
+int sde_rsc_client_get_vsync_refcount(
+ struct sde_rsc_client *caller_client)
+{
+ struct sde_rsc_priv *rsc;
+
+ if (!caller_client) {
+ pr_err("invalid client for rsc state update\n");
+ return -EINVAL;
+ } else if (caller_client->rsc_index >= MAX_RSC_COUNT) {
+ pr_err("invalid rsc index\n");
+ return -EINVAL;
+ }
+
+ rsc = rsc_prv_list[caller_client->rsc_index];
+ if (!rsc)
+ return 0;
+
+ return atomic_read(&rsc->rsc_vsync_wait);
+}
+
+/**
+ * sde_rsc_client_reset_vsync_refcount() - reduces the refcounting
+ * logic that waits for the vsync.
+ * @client: Client pointer provided by sde_rsc_client_create().
+ *
+ * Return: zero if refcount was already zero.
+ */
+int sde_rsc_client_reset_vsync_refcount(
+ struct sde_rsc_client *caller_client)
+{
+ struct sde_rsc_priv *rsc;
+ int ret;
+
+ if (!caller_client) {
+ pr_err("invalid client for rsc state update\n");
+ return -EINVAL;
+ } else if (caller_client->rsc_index >= MAX_RSC_COUNT) {
+ pr_err("invalid rsc index\n");
+ return -EINVAL;
+ }
+
+ rsc = rsc_prv_list[caller_client->rsc_index];
+ if (!rsc)
+ return 0;
+
+ ret = atomic_add_unless(&rsc->rsc_vsync_wait, -1, 0);
+ wake_up_all(&rsc->rsc_vsync_waitq);
+ SDE_EVT32(atomic_read(&rsc->rsc_vsync_wait));
+
+ return ret;
+}
+
+/**
* sde_rsc_client_is_state_update_complete() - check if state update is complete
* RSC state transition is not complete until HW receives VBLANK signal. This
* function checks RSC HW to determine whether that signal has been received.
@@ -1307,6 +1403,7 @@
INIT_LIST_HEAD(&rsc->client_list);
INIT_LIST_HEAD(&rsc->event_list);
mutex_init(&rsc->client_lock);
+ init_waitqueue_head(&rsc->rsc_vsync_waitq);
pr_info("sde rsc index:%d probed successfully\n",
SDE_RSC_INDEX + counter);
diff --git a/drivers/gpu/drm/msm/sde_rsc_priv.h b/drivers/gpu/drm/msm/sde_rsc_priv.h
index 64b0216..5c62466 100644
--- a/drivers/gpu/drm/msm/sde_rsc_priv.h
+++ b/drivers/gpu/drm/msm/sde_rsc_priv.h
@@ -149,6 +149,8 @@
* and ab/ib vote on display rsc
* master_drm: Primary client waits for vsync on this drm object based
* on crtc id
+ * rsc_vsync_wait: Refcount to indicate if we have to wait for the vsync.
+ * rsc_vsync_waitq: Queue to wait for the vsync.
*/
struct sde_rsc_priv {
u32 version;
@@ -177,6 +179,8 @@
struct sde_rsc_client *primary_client;
struct drm_device *master_drm;
+ atomic_t rsc_vsync_wait;
+ wait_queue_head_t rsc_vsync_waitq;
};
/**
diff --git a/drivers/gpu/msm/a6xx_reg.h b/drivers/gpu/msm/a6xx_reg.h
index 5991cd5..89453b0 100644
--- a/drivers/gpu/msm/a6xx_reg.h
+++ b/drivers/gpu/msm/a6xx_reg.h
@@ -405,6 +405,7 @@
#define A6XX_RBBM_SECVID_TSB_ADDR_MODE_CNTL 0xF810
#define A6XX_RBBM_VBIF_CLIENT_QOS_CNTL 0x00010
+#define A6XX_RBBM_GPR0_CNTL 0x00018
#define A6XX_RBBM_INTERFACE_HANG_INT_CNTL 0x0001f
#define A6XX_RBBM_INT_CLEAR_CMD 0x00037
#define A6XX_RBBM_INT_0_MASK 0x00038
@@ -809,7 +810,7 @@
/* GBIF registers */
#define A6XX_GBIF_HALT 0x3c45
#define A6XX_GBIF_HALT_ACK 0x3c46
-#define A6XX_GBIF_HALT_MASK 0x1
+#define A6XX_GBIF_HALT_MASK 0x2
#define A6XX_GBIF_PERF_PWR_CNT_EN 0x3cc0
#define A6XX_GBIF_PERF_CNT_SEL 0x3cc2
@@ -982,37 +983,8 @@
/* ISENSE registers */
#define A6XX_GMU_ISENSE_CTRL 0x1F95D
-#define A6XX_GPU_CS_ENABLE_REG 0x23120
#define A6XX_GPU_GMU_CX_GMU_ISENSE_CTRL 0x1f95d
-#define A6XX_GPU_CS_AMP_CALIBRATION_CONTROL3 0x22d78
-#define A6XX_GPU_CS_AMP_CALIBRATION_CONTROL2 0x22d58
-#define A6XX_GPU_CS_A_SENSOR_CTRL_0 0x22d80
-#define A6XX_GPU_CS_A_SENSOR_CTRL_2 0x422da
-#define A6XX_GPU_CS_SENSOR_GENERAL_STATUS 0x2301a
-#define A6XX_GPU_CS_AMP_CALIBRATION_CONTROL1 0x23157
-#define A6XX_GPU_CS_SENSOR_GENERAL_STATUS 0x2301a
-#define A6XX_GPU_CS_AMP_CALIBRATION_STATUS1_0 0x2301d
-#define A6XX_GPU_CS_AMP_CALIBRATION_STATUS1_2 0x2301f
-#define A6XX_GPU_CS_AMP_CALIBRATION_STATUS1_4 0x23021
-#define A6XX_GPU_CS_AMP_CALIBRATION_DONE 0x23165
-#define A6XX_GPU_CS_AMP_PERIOD_CTRL 0x2316d
-#define A6XX_GPU_CS_AMP_CALIBRATION_DONE 0x23165
-
-#define CS_PWR_ON_STATUS (10)
-#define AMP_SW_WRM_TRIM_START (24)
-#define AMP_TRIM_TIMER (6)
-#define AMP_SW_TRIM_START (0)
-#define SS_AMPTRIM_DONE (11)
-#define AMP_OFFSET_CHECK_MIN_ERR (1)
-#define AMP_OFFSET_CHECK_MAX_ERR (2)
-#define AMP_OUT_OF_RANGE_ERR (4)
-#define TRIM_CNT_VALUE (1)
-#define RUNTIME_CNT_VALUE (16)
-#define TRIM_ENABLE (0)
-
-#define AMP_ERR (BIT(AMP_OFFSET_CHECK_MIN_ERR) || \
- BIT(AMP_OFFSET_CHECK_MAX_ERR) || \
- BIT(AMP_OUT_OF_RANGE_ERR))
+#define A6XX_GPU_CS_ENABLE_REG 0x23120
/* LM registers */
#define A6XX_GPU_GMU_CX_GMU_PWR_THRESHOLD 0x1F94D
diff --git a/drivers/gpu/msm/adreno-gpulist.h b/drivers/gpu/msm/adreno-gpulist.h
index 770cf3b..08cd06b 100644
--- a/drivers/gpu/msm/adreno-gpulist.h
+++ b/drivers/gpu/msm/adreno-gpulist.h
@@ -347,7 +347,7 @@
.minor = 0,
.patchid = ANY_ID,
.features = ADRENO_64BIT | ADRENO_RPMH | ADRENO_IFPC |
- ADRENO_GPMU | ADRENO_CONTENT_PROTECTION | ADRENO_LM |
+ ADRENO_GPMU | ADRENO_CONTENT_PROTECTION |
ADRENO_IOCOHERENT,
.sqefw_name = "a630_sqe.fw",
.zap_name = "a630_zap",
diff --git a/drivers/gpu/msm/adreno.c b/drivers/gpu/msm/adreno.c
index 13fe0a7..b8006b7 100644
--- a/drivers/gpu/msm/adreno.c
+++ b/drivers/gpu/msm/adreno.c
@@ -1872,8 +1872,18 @@
OOB_GPU_CHECK_MASK,
OOB_GPU_CLEAR_MASK);
if (error) {
+ struct gmu_device *gmu = &device->gmu;
+
gpudev->oob_clear(adreno_dev, OOB_GPU_CLEAR_MASK);
- return error;
+ if (gmu->gx_gdsc &&
+ regulator_is_enabled(gmu->gx_gdsc)) {
+ /* GPU is on. Try recovery */
+ set_bit(GMU_FAULT, &gmu->flags);
+ gmu_snapshot(device);
+ error = -EINVAL;
+ } else {
+ return error;
+ }
}
}
@@ -1907,7 +1917,7 @@
* GMU to return to the lowest idle level. This is
* because some idle level transitions require VBIF and MMU.
*/
- if (gpudev->wait_for_lowest_idle &&
+ if (!error && gpudev->wait_for_lowest_idle &&
gpudev->wait_for_lowest_idle(adreno_dev)) {
struct gmu_device *gmu = &device->gmu;
diff --git a/drivers/gpu/msm/adreno.h b/drivers/gpu/msm/adreno.h
index b77f6e1..0dd1921 100644
--- a/drivers/gpu/msm/adreno.h
+++ b/drivers/gpu/msm/adreno.h
@@ -226,6 +226,10 @@
#define ADRENO_HWCG_CTRL 3
#define ADRENO_THROTTLING_CTRL 4
+/* VBIF, GBIF halt request and ack mask */
+#define GBIF_HALT_REQUEST 0x1E0
+#define VBIF_RESET_ACK_MASK 0x00f0
+#define VBIF_RESET_ACK_TIMEOUT 100
/* number of throttle counters for DCVS adjustment */
#define ADRENO_GPMU_THROTTLE_COUNTERS 4
@@ -683,6 +687,8 @@
ADRENO_REG_RBBM_SECVID_TSB_TRUSTED_BASE,
ADRENO_REG_RBBM_SECVID_TSB_TRUSTED_BASE_HI,
ADRENO_REG_RBBM_SECVID_TSB_TRUSTED_SIZE,
+ ADRENO_REG_RBBM_GPR0_CNTL,
+ ADRENO_REG_RBBM_VBIF_GX_RESET_STATUS,
ADRENO_REG_VBIF_XIN_HALT_CTRL0,
ADRENO_REG_VBIF_XIN_HALT_CTRL1,
ADRENO_REG_VBIF_VERSION,
@@ -1889,17 +1895,15 @@
* @ack_reg: register offset to wait for acknowledge
*/
static inline int adreno_wait_for_vbif_halt_ack(struct kgsl_device *device,
- int ack_reg)
+ int ack_reg, unsigned int mask)
{
struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
- struct adreno_gpudev *gpudev = ADRENO_GPU_DEVICE(adreno_dev);
unsigned long wait_for_vbif;
- unsigned int mask = gpudev->vbif_xin_halt_ctrl0_mask;
unsigned int val;
int ret = 0;
/* wait for the transactions to clear */
- wait_for_vbif = jiffies + msecs_to_jiffies(100);
+ wait_for_vbif = jiffies + msecs_to_jiffies(VBIF_RESET_ACK_TIMEOUT);
while (1) {
adreno_readreg(adreno_dev, ack_reg,
&val);
@@ -1929,15 +1933,27 @@
int ret = 0;
if (adreno_has_gbif(adreno_dev)) {
+ /*
+ * Halt GBIF GX first and then CX part.
+ * Need to release CX Halt explicitly in case of SW_RESET.
+ * GX Halt release will be taken care by SW_RESET internally.
+ */
+ adreno_writereg(adreno_dev, ADRENO_REG_RBBM_GPR0_CNTL,
+ GBIF_HALT_REQUEST);
+ ret = adreno_wait_for_vbif_halt_ack(device,
+ ADRENO_REG_RBBM_VBIF_GX_RESET_STATUS,
+ VBIF_RESET_ACK_MASK);
+ if (ret)
+ return ret;
+
adreno_writereg(adreno_dev, ADRENO_REG_GBIF_HALT, mask);
ret = adreno_wait_for_vbif_halt_ack(device,
- ADRENO_REG_GBIF_HALT_ACK);
- adreno_writereg(adreno_dev, ADRENO_REG_GBIF_HALT, 0);
+ ADRENO_REG_GBIF_HALT_ACK, mask);
} else {
adreno_writereg(adreno_dev, ADRENO_REG_VBIF_XIN_HALT_CTRL0,
mask);
ret = adreno_wait_for_vbif_halt_ack(device,
- ADRENO_REG_VBIF_XIN_HALT_CTRL1);
+ ADRENO_REG_VBIF_XIN_HALT_CTRL1, mask);
adreno_writereg(adreno_dev, ADRENO_REG_VBIF_XIN_HALT_CTRL0, 0);
}
return ret;
diff --git a/drivers/gpu/msm/adreno_a6xx.c b/drivers/gpu/msm/adreno_a6xx.c
index 83dd3fb..09d6a10 100644
--- a/drivers/gpu/msm/adreno_a6xx.c
+++ b/drivers/gpu/msm/adreno_a6xx.c
@@ -43,6 +43,8 @@
#define A6XX_GPU_CX_REG_BASE 0x509E000
#define A6XX_GPU_CX_REG_SIZE 0x1000
+#define GPU_LIMIT_THRESHOLD_ENABLE BIT(31)
+
static int _load_gmu_firmware(struct kgsl_device *device);
static const struct adreno_vbif_data a630_vbif[] = {
@@ -758,6 +760,38 @@
a6xx_preemption_start(adreno_dev);
a6xx_protect_init(adreno_dev);
+
+ /*
+ * We start LM here because we want all the following to be up
+ * 1. GX HS
+ * 2. SPTPRAC
+ * 3. HFI
+ * At this point, we are guaranteed all.
+ */
+ if (ADRENO_FEATURE(adreno_dev, ADRENO_LM) &&
+ test_bit(ADRENO_LM_CTRL, &adreno_dev->pwrctrl_flag)) {
+ int result;
+ struct gmu_device *gmu = &device->gmu;
+ struct device *dev = &gmu->pdev->dev;
+
+ kgsl_gmu_regwrite(device, A6XX_GPU_GMU_CX_GMU_PWR_THRESHOLD,
+ GPU_LIMIT_THRESHOLD_ENABLE | lm_limit(adreno_dev));
+ kgsl_gmu_regwrite(device, A6XX_GMU_AO_SPARE_CNTL, 1);
+ kgsl_gmu_regwrite(device, A6XX_GPU_GMU_CX_GMU_ISENSE_CTRL, 0x1);
+
+ gmu->lm_config.lm_type = 1;
+ gmu->lm_config.lm_sensor_type = 1;
+ gmu->lm_config.throttle_config = 1;
+ gmu->lm_config.idle_throttle_en = 0;
+ gmu->lm_config.acd_en = 0;
+ gmu->bcl_config = 0;
+ gmu->lm_dcvs_level = 0;
+
+ result = hfi_send_lmconfig(gmu);
+ if (result)
+ dev_err(dev, "Failure enabling limits management (%d)\n",
+ result);
+ }
}
/*
@@ -1713,80 +1747,6 @@
return 0;
}
-#define KMASK(start, n) (GENMASK((start + n), (start)))
-
-static void isense_cold_trimm(struct kgsl_device *device)
-{
- unsigned int reg;
- struct gmu_device *gmu = &device->gmu;
-
- kgsl_gmu_regwrite(device, A6XX_GMU_AO_SPARE_CNTL, 1);
- kgsl_gmu_regwrite(device, A6XX_GPU_CS_AMP_CALIBRATION_DONE, 0);
-
- kgsl_gmu_regwrite(device, A6XX_GPU_GMU_CX_GMU_ISENSE_CTRL, 0x1);
- kgsl_gmu_regwrite(device, A6XX_GPU_CS_AMP_CALIBRATION_CONTROL3,
- 0x00000F8F);
- kgsl_gmu_regwrite(device, A6XX_GPU_CS_AMP_CALIBRATION_CONTROL2,
- 0x00705161);
- udelay(10);
- kgsl_gmu_regwrite(device, A6XX_GPU_CS_ENABLE_REG, 0x3);
- kgsl_gmu_regwrite(device, A6XX_GPU_CS_A_SENSOR_CTRL_0, 0x10040a);
- kgsl_gmu_regwrite(device, A6XX_GPU_CS_A_SENSOR_CTRL_2, 0x10040a);
-
- kgsl_gmu_regread(device, A6XX_GPU_CS_SENSOR_GENERAL_STATUS, ®);
- if ((reg & BIT(CS_PWR_ON_STATUS)) != (1 << CS_PWR_ON_STATUS)) {
- dev_err(&gmu->pdev->dev, "ERROR - ISENSE power-up\n");
- return;
- }
-
- kgsl_gmu_regrmw(device, A6XX_GPU_CS_AMP_CALIBRATION_CONTROL1,
- KMASK(AMP_TRIM_TIMER, 15), 70 << AMP_TRIM_TIMER);
- kgsl_gmu_regrmw(device, A6XX_GPU_CS_AMP_CALIBRATION_CONTROL1,
- KMASK(AMP_SW_TRIM_START, 1), 0 << AMP_SW_TRIM_START);
- kgsl_gmu_regrmw(device, A6XX_GPU_CS_AMP_CALIBRATION_CONTROL1,
- KMASK(AMP_SW_TRIM_START, 1), 1 << AMP_SW_TRIM_START);
-
- if (timed_poll_check(device, A6XX_GPU_CS_SENSOR_GENERAL_STATUS,
- BIT(SS_AMPTRIM_DONE), GMU_START_TIMEOUT,
- BIT(SS_AMPTRIM_DONE))) {
- dev_err(&gmu->pdev->dev, "ISENSE SS_AMPTRIM failure\n");
- return;
- }
-
- kgsl_gmu_regread(device, A6XX_GPU_CS_AMP_CALIBRATION_STATUS1_0, ®);
- if (reg & AMP_ERR) {
- kgsl_gmu_regread(device, A6XX_GPU_CS_AMP_CALIBRATION_STATUS1_0,
- ®);
- dev_err(&gmu->pdev->dev,
- "ISENSE ERROR:trimming GX 0x%08x\n", reg);
- return;
- }
-
- kgsl_gmu_regread(device, A6XX_GPU_CS_AMP_CALIBRATION_STATUS1_2, ®);
- if (reg & AMP_ERR) {
- kgsl_gmu_regread(device, A6XX_GPU_CS_AMP_CALIBRATION_STATUS1_2,
- ®);
- dev_err(&gmu->pdev->dev,
- "ISENSE ERROR:trimming SPTPRAC 0x%08x\n", reg);
- return;
- }
-
- kgsl_gmu_regwrite(device, A6XX_GPU_CS_AMP_CALIBRATION_DONE, 1);
- kgsl_gmu_regrmw(device, A6XX_GPU_CS_AMP_PERIOD_CTRL,
- KMASK(TRIM_CNT_VALUE, 13), 20 << TRIM_CNT_VALUE);
- kgsl_gmu_regrmw(device, A6XX_GPU_CS_AMP_PERIOD_CTRL,
- KMASK(RUNTIME_CNT_VALUE, 9), 50 << RUNTIME_CNT_VALUE);
-
- kgsl_gmu_regrmw(device, A6XX_GPU_CS_AMP_PERIOD_CTRL,
- KMASK(TRIM_ENABLE, 1), 1 << TRIM_ENABLE);
- udelay(4);
- kgsl_gmu_regrmw(device, A6XX_GPU_CS_AMP_PERIOD_CTRL,
- KMASK(TRIM_ENABLE, 1), 0 << TRIM_ENABLE);
- kgsl_gmu_regwrite(device, A6XX_GPU_CS_AMP_CALIBRATION_DONE, 1);
-
-}
-
-#define GPU_LIMIT_THRESHOLD_ENABLE BIT(31)
/*
* a6xx_gmu_fw_start() - set up GMU and start FW
* @device: Pointer to KGSL device
@@ -1867,13 +1827,6 @@
kgsl_gmu_regwrite(device, A6XX_GMU_HFI_SFR_ADDR, chipid);
- if (ADRENO_FEATURE(adreno_dev, ADRENO_LM) &&
- test_bit(ADRENO_LM_CTRL, &adreno_dev->pwrctrl_flag)) {
- kgsl_gmu_regwrite(device, A6XX_GPU_GMU_CX_GMU_PWR_THRESHOLD,
- GPU_LIMIT_THRESHOLD_ENABLE | lm_limit(adreno_dev));
- isense_cold_trimm(device);
- }
-
/* Configure power control and bring the GMU out of reset */
a6xx_gmu_power_config(device);
ret = a6xx_gmu_start(device);
@@ -2096,8 +2049,7 @@
return _load_gmu_firmware(device);
}
-#define VBIF_RESET_ACK_TIMEOUT 100
-#define VBIF_RESET_ACK_MASK 0x00f0
+#define GBIF_CX_HALT_MASK BIT(1)
static int a6xx_soft_reset(struct adreno_device *adreno_dev)
{
@@ -2138,6 +2090,13 @@
if (!vbif_acked)
return -ETIMEDOUT;
+ /*
+ * GBIF GX halt will be released automatically by sw_reset.
+ * Release GBIF CX halt after sw_reset
+ */
+ if (adreno_has_gbif(adreno_dev))
+ kgsl_regrmw(device, A6XX_GBIF_HALT, GBIF_CX_HALT_MASK, 0);
+
a6xx_sptprac_enable(adreno_dev);
return 0;
@@ -2354,8 +2313,14 @@
udelay(100);
}
- if (acked)
- ret = adreno_soft_reset(device);
+ if (acked) {
+ /* Make sure VBIF/GBIF is cleared before resetting */
+ ret = adreno_vbif_clear_pending_transactions(device);
+
+ if (ret == 0)
+ ret = adreno_soft_reset(device);
+ }
+
if (ret)
KGSL_DEV_ERR_ONCE(device, "Device soft reset failed\n");
}
@@ -3692,6 +3657,9 @@
A6XX_VBIF_XIN_HALT_CTRL0),
ADRENO_REG_DEFINE(ADRENO_REG_VBIF_XIN_HALT_CTRL1,
A6XX_VBIF_XIN_HALT_CTRL1),
+ ADRENO_REG_DEFINE(ADRENO_REG_RBBM_GPR0_CNTL, A6XX_RBBM_GPR0_CNTL),
+ ADRENO_REG_DEFINE(ADRENO_REG_RBBM_VBIF_GX_RESET_STATUS,
+ A6XX_RBBM_VBIF_GX_RESET_STATUS),
ADRENO_REG_DEFINE(ADRENO_REG_GBIF_HALT, A6XX_GBIF_HALT),
ADRENO_REG_DEFINE(ADRENO_REG_GBIF_HALT_ACK, A6XX_GBIF_HALT_ACK),
ADRENO_REG_DEFINE(ADRENO_REG_RBBM_ALWAYSON_COUNTER_LO,
diff --git a/drivers/gpu/msm/adreno_a6xx_snapshot.c b/drivers/gpu/msm/adreno_a6xx_snapshot.c
index 3f92f75..589417f 100644
--- a/drivers/gpu/msm/adreno_a6xx_snapshot.c
+++ b/drivers/gpu/msm/adreno_a6xx_snapshot.c
@@ -195,6 +195,35 @@
unsigned int ctxt_id;
};
+static const unsigned int a6xx_hlsq_non_ctx_registers[] = {
+ 0xBE00, 0xBE01, 0xBE04, 0xBE05, 0xBE08, 0xBE09, 0xBE10, 0xBE15,
+ 0xBE20, 0xBE23,
+};
+
+static const unsigned int a6xx_sp_non_ctx_registers[] = {
+ 0xAE00, 0xAE04, 0xAE0C, 0xAE0C, 0xAE0F, 0xAE2B, 0xAE30, 0xAE32,
+ 0xAE35, 0xAE35, 0xAE3A, 0xAE3F, 0xAE50, 0xAE52,
+};
+
+static const unsigned int a6xx_tp_non_ctx_registers[] = {
+ 0xB600, 0xB601, 0xB604, 0xB605, 0xB610, 0xB61B, 0xB620, 0xB623,
+};
+
+static struct a6xx_non_ctx_dbgahb_registers {
+ unsigned int regbase;
+ unsigned int statetype;
+ const unsigned int *regs;
+ unsigned int num_sets;
+ unsigned int offset;
+} a6xx_non_ctx_dbgahb[] = {
+ { 0x0002F800, 0x40, a6xx_hlsq_non_ctx_registers,
+ ARRAY_SIZE(a6xx_hlsq_non_ctx_registers) / 2 },
+ { 0x0002B800, 0x20, a6xx_sp_non_ctx_registers,
+ ARRAY_SIZE(a6xx_sp_non_ctx_registers) / 2 },
+ { 0x0002D800, 0x0, a6xx_tp_non_ctx_registers,
+ ARRAY_SIZE(a6xx_tp_non_ctx_registers) / 2 },
+};
+
static const unsigned int a6xx_vbif_ver_20xxxxxx_registers[] = {
/* VBIF */
0x3000, 0x3007, 0x300C, 0x3014, 0x3018, 0x302D, 0x3030, 0x3031,
@@ -308,15 +337,6 @@
/* VFD */
0xA600, 0xA601, 0xA603, 0xA603, 0xA60A, 0xA60A, 0xA610, 0xA617,
0xA630, 0xA630,
- /* SP */
- 0xAE00, 0xAE04, 0xAE0C, 0xAE0C, 0xAE0F, 0xAE2B, 0xAE30, 0xAE32,
- 0xAE35, 0xAE35, 0xAE3A, 0xAE3F, 0xAE50, 0xAE52,
- /* TP */
- 0xB600, 0xB601, 0xB604, 0xB605, 0xB610, 0xB61B, 0xB620, 0xB623,
- /* HLSQ */
- 0xBE00, 0xBE01, 0xBE04, 0xBE05, 0xBE08, 0xBE09, 0xBE10, 0xBE15,
- 0xBE20, 0xBE23,
-
};
/*
@@ -832,6 +852,106 @@
return data_size + sizeof(*header);
}
+static size_t a6xx_legacy_snapshot_non_ctx_dbgahb(struct kgsl_device *device,
+ u8 *buf, size_t remain, void *priv)
+{
+ struct kgsl_snapshot_regs *header =
+ (struct kgsl_snapshot_regs *)buf;
+ struct a6xx_non_ctx_dbgahb_registers *regs =
+ (struct a6xx_non_ctx_dbgahb_registers *)priv;
+ unsigned int *data = (unsigned int *)(buf + sizeof(*header));
+ int count = 0;
+ unsigned int read_sel;
+ int i, j;
+
+ if (!device->snapshot_legacy)
+ return 0;
+
+ /* Figure out how many registers we are going to dump */
+ for (i = 0; i < regs->num_sets; i++) {
+ int start = regs->regs[i * 2];
+ int end = regs->regs[i * 2 + 1];
+
+ count += (end - start + 1);
+ }
+
+ if (remain < (count * 8) + sizeof(*header)) {
+ SNAPSHOT_ERR_NOMEM(device, "REGISTERS");
+ return 0;
+ }
+
+ header->count = count;
+
+ read_sel = (regs->statetype & 0xff) << 8;
+ kgsl_regwrite(device, A6XX_HLSQ_DBG_READ_SEL, read_sel);
+
+ for (i = 0; i < regs->num_sets; i++) {
+ unsigned int start = regs->regs[2 * i];
+ unsigned int end = regs->regs[2 * i + 1];
+
+ for (j = start; j <= end; j++) {
+ unsigned int val;
+
+ val = a6xx_read_dbgahb(device, regs->regbase, j);
+ *data++ = j;
+ *data++ = val;
+
+ }
+ }
+ return (count * 8) + sizeof(*header);
+}
+
+static size_t a6xx_snapshot_non_ctx_dbgahb(struct kgsl_device *device, u8 *buf,
+ size_t remain, void *priv)
+{
+ struct kgsl_snapshot_regs *header =
+ (struct kgsl_snapshot_regs *)buf;
+ struct a6xx_non_ctx_dbgahb_registers *regs =
+ (struct a6xx_non_ctx_dbgahb_registers *)priv;
+ unsigned int count = 0;
+ unsigned int *data = (unsigned int *)(buf + sizeof(*header));
+ unsigned int i, k;
+ unsigned int *src;
+
+ if (crash_dump_valid == false)
+ return a6xx_legacy_snapshot_non_ctx_dbgahb(device, buf, remain,
+ regs);
+
+ if (remain < sizeof(*header)) {
+ SNAPSHOT_ERR_NOMEM(device, "REGISTERS");
+ return 0;
+ }
+
+ remain -= sizeof(*header);
+
+ src = (unsigned int *)(a6xx_crashdump_registers.hostptr + regs->offset);
+
+ for (i = 0; i < regs->num_sets; i++) {
+ unsigned int start;
+ unsigned int end;
+
+ start = regs->regs[2 * i];
+ end = regs->regs[(2 * i) + 1];
+
+ if (remain < (end - start + 1) * 8) {
+ SNAPSHOT_ERR_NOMEM(device, "REGISTERS");
+ goto out;
+ }
+
+ remain -= ((end - start) + 1) * 8;
+
+ for (k = start; k <= end; k++, count++) {
+ *data++ = k;
+ *data++ = *src++;
+ }
+ }
+out:
+ header->count = count;
+
+ /* Return the size of the section */
+ return (count * 8) + sizeof(*header);
+}
+
static void a6xx_snapshot_dbgahb_regs(struct kgsl_device *device,
struct kgsl_snapshot *snapshot)
{
@@ -851,6 +971,12 @@
a6xx_snapshot_cluster_dbgahb, &info);
}
}
+
+ for (i = 0; i < ARRAY_SIZE(a6xx_non_ctx_dbgahb); i++) {
+ kgsl_snapshot_add_section(device,
+ KGSL_SNAPSHOT_SECTION_REGS, snapshot,
+ a6xx_snapshot_non_ctx_dbgahb, &a6xx_non_ctx_dbgahb[i]);
+ }
}
static size_t a6xx_legacy_snapshot_mvc(struct kgsl_device *device, u8 *buf,
@@ -1622,6 +1748,40 @@
return qwords;
}
+static int _a6xx_crashdump_init_non_ctx_dbgahb(uint64_t *ptr, uint64_t *offset)
+{
+ int qwords = 0;
+ unsigned int i, k;
+ unsigned int count;
+
+ for (i = 0; i < ARRAY_SIZE(a6xx_non_ctx_dbgahb); i++) {
+ struct a6xx_non_ctx_dbgahb_registers *regs =
+ &a6xx_non_ctx_dbgahb[i];
+
+ regs->offset = *offset;
+
+ /* Program the aperture */
+ ptr[qwords++] = (regs->statetype & 0xff) << 8;
+ ptr[qwords++] = (((uint64_t)A6XX_HLSQ_DBG_READ_SEL << 44)) |
+ (1 << 21) | 1;
+
+ for (k = 0; k < regs->num_sets; k++) {
+ unsigned int start = regs->regs[2 * k];
+
+ count = REG_PAIR_COUNT(regs->regs, k);
+ ptr[qwords++] =
+ a6xx_crashdump_registers.gpuaddr + *offset;
+ ptr[qwords++] =
+ (((uint64_t)(A6XX_HLSQ_DBG_AHB_READ_APERTURE +
+ start - regs->regbase / 4) << 44)) |
+ count;
+
+ *offset += count * sizeof(unsigned int);
+ }
+ }
+ return qwords;
+}
+
void a6xx_crashdump_init(struct adreno_device *adreno_dev)
{
struct kgsl_device *device = KGSL_DEVICE(adreno_dev);
@@ -1713,6 +1873,26 @@
}
}
+ /*
+ * Calculate the script and data size for non context debug
+ * AHB registers
+ */
+ for (i = 0; i < ARRAY_SIZE(a6xx_non_ctx_dbgahb); i++) {
+ struct a6xx_non_ctx_dbgahb_registers *regs =
+ &a6xx_non_ctx_dbgahb[i];
+
+ /* 16 bytes for programming the aperture */
+ script_size += 16;
+
+ /* Reading each pair of registers takes 16 bytes */
+ script_size += 16 * regs->num_sets;
+
+ /* A dword per register read from the cluster list */
+ for (k = 0; k < regs->num_sets; k++)
+ data_size += REG_PAIR_COUNT(regs->regs, k) *
+ sizeof(unsigned int);
+ }
+
/* Now allocate the script and data buffers */
/* The script buffers needs 2 extra qwords on the end */
@@ -1763,6 +1943,8 @@
ptr += _a6xx_crashdump_init_ctx_dbgahb(ptr, &offset);
+ ptr += _a6xx_crashdump_init_non_ctx_dbgahb(ptr, &offset);
+
*ptr++ = 0;
*ptr++ = 0;
}
diff --git a/drivers/gpu/msm/adreno_drawctxt.c b/drivers/gpu/msm/adreno_drawctxt.c
index b81be8f..6876796 100644
--- a/drivers/gpu/msm/adreno_drawctxt.c
+++ b/drivers/gpu/msm/adreno_drawctxt.c
@@ -424,16 +424,6 @@
return ERR_PTR(ret);
}
- if (gpudev->preemption_context_init) {
- ret = gpudev->preemption_context_init(&drawctxt->base);
- if (ret != 0) {
- kgsl_context_detach(&drawctxt->base);
- kgsl_context_put(&drawctxt->base);
- kfree(drawctxt);
- return ERR_PTR(ret);
- }
- }
-
kgsl_sharedmem_writel(device, &device->memstore,
KGSL_MEMSTORE_OFFSET(drawctxt->base.id, soptimestamp),
0);
@@ -445,6 +435,14 @@
INIT_LIST_HEAD(&drawctxt->active_node);
+ if (gpudev->preemption_context_init) {
+ ret = gpudev->preemption_context_init(&drawctxt->base);
+ if (ret != 0) {
+ kgsl_context_detach(&drawctxt->base);
+ return ERR_PTR(ret);
+ }
+ }
+
/* copy back whatever flags we dediced were valid */
*flags = drawctxt->base.flags;
return &drawctxt->base;
diff --git a/drivers/gpu/msm/kgsl_device.h b/drivers/gpu/msm/kgsl_device.h
index 0ab775a..6fca1e15 100644
--- a/drivers/gpu/msm/kgsl_device.h
+++ b/drivers/gpu/msm/kgsl_device.h
@@ -498,6 +498,7 @@
* @sysfs_read: Count of current reads via sysfs
* @first_read: True until the snapshot read is started
* @gmu_fault: Snapshot collected when GMU fault happened
+ * @recovered: True if GPU was recovered after previous snapshot
*/
struct kgsl_snapshot {
uint64_t ib1base;
@@ -521,6 +522,7 @@
unsigned int sysfs_read;
bool first_read;
bool gmu_fault;
+ bool recovered;
};
/**
diff --git a/drivers/gpu/msm/kgsl_gmu.c b/drivers/gpu/msm/kgsl_gmu.c
index 0a7424a..df06a0d 100644
--- a/drivers/gpu/msm/kgsl_gmu.c
+++ b/drivers/gpu/msm/kgsl_gmu.c
@@ -1343,29 +1343,27 @@
struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
struct gmu_device *gmu = &device->gmu;
- if (!gmu->fault_count) {
- /* Mask so there's no interrupt caused by NMI */
- adreno_write_gmureg(adreno_dev,
- ADRENO_REG_GMU_GMU2HOST_INTR_MASK, 0xFFFFFFFF);
+ /* Mask so there's no interrupt caused by NMI */
+ adreno_write_gmureg(adreno_dev,
+ ADRENO_REG_GMU_GMU2HOST_INTR_MASK, 0xFFFFFFFF);
- /* Make sure the interrupt is masked before causing it */
- wmb();
- adreno_write_gmureg(adreno_dev,
- ADRENO_REG_GMU_NMI_CONTROL_STATUS, 0);
- adreno_write_gmureg(adreno_dev,
- ADRENO_REG_GMU_CM3_CFG, (1 << 9));
+ /* Make sure the interrupt is masked before causing it */
+ wmb();
+ adreno_write_gmureg(adreno_dev,
+ ADRENO_REG_GMU_NMI_CONTROL_STATUS, 0);
+ adreno_write_gmureg(adreno_dev,
+ ADRENO_REG_GMU_CM3_CFG, (1 << 9));
- /* Wait for the NMI to be handled */
- wmb();
- udelay(100);
- kgsl_device_snapshot(device, NULL, true);
+ /* Wait for the NMI to be handled */
+ wmb();
+ udelay(100);
+ kgsl_device_snapshot(device, NULL, true);
- adreno_write_gmureg(adreno_dev,
- ADRENO_REG_GMU_GMU2HOST_INTR_CLR, 0xFFFFFFFF);
- adreno_write_gmureg(adreno_dev,
- ADRENO_REG_GMU_GMU2HOST_INTR_MASK,
- (unsigned int) ~HFI_IRQ_MASK);
- }
+ adreno_write_gmureg(adreno_dev,
+ ADRENO_REG_GMU_GMU2HOST_INTR_CLR, 0xFFFFFFFF);
+ adreno_write_gmureg(adreno_dev,
+ ADRENO_REG_GMU_GMU2HOST_INTR_MASK,
+ (unsigned int) ~HFI_IRQ_MASK);
gmu->fault_count++;
}
diff --git a/drivers/gpu/msm/kgsl_hfi.c b/drivers/gpu/msm/kgsl_hfi.c
index 3a5b489..daac9f1 100644
--- a/drivers/gpu/msm/kgsl_hfi.c
+++ b/drivers/gpu/msm/kgsl_hfi.c
@@ -611,24 +611,6 @@
if (result)
return result;
- if (ADRENO_FEATURE(adreno_dev, ADRENO_LM) &&
- test_bit(ADRENO_LM_CTRL, &adreno_dev->pwrctrl_flag)) {
- gmu->lm_config.lm_type = 1;
- gmu->lm_config.lm_sensor_type = 1;
- gmu->lm_config.throttle_config = 1;
- gmu->lm_config.idle_throttle_en = 0;
- gmu->lm_config.acd_en = 0;
- gmu->bcl_config = 0;
- gmu->lm_dcvs_level = 0;
-
- result = hfi_send_lmconfig(gmu);
- if (result) {
- dev_err(dev, "Failure enabling LM (%d)\n",
- result);
- return result;
- }
- }
-
/* Tell the GMU we are sending no more HFIs until the next boot */
if (ADRENO_QUIRK(adreno_dev, ADRENO_QUIRK_HFI_USE_REG)) {
result = hfi_send_test(gmu);
diff --git a/drivers/gpu/msm/kgsl_hfi.h b/drivers/gpu/msm/kgsl_hfi.h
index 105599c..b24509d 100644
--- a/drivers/gpu/msm/kgsl_hfi.h
+++ b/drivers/gpu/msm/kgsl_hfi.h
@@ -360,4 +360,5 @@
uint32_t bw_idx, enum rpm_ack_type ack_type);
int hfi_notify_slumber(struct gmu_device *gmu, uint32_t init_perf_idx,
uint32_t init_bw_idx);
+int hfi_send_lmconfig(struct gmu_device *gmu);
#endif /* __KGSL_HFI_H */
diff --git a/drivers/gpu/msm/kgsl_iommu.c b/drivers/gpu/msm/kgsl_iommu.c
index ab3ab31..b354ef2 100644
--- a/drivers/gpu/msm/kgsl_iommu.c
+++ b/drivers/gpu/msm/kgsl_iommu.c
@@ -796,7 +796,7 @@
struct kgsl_iommu_context *ctx;
u64 ptbase;
u32 contextidr;
- pid_t tid = 0;
+ pid_t pid = 0;
pid_t ptname;
struct _mem_entry prev, next;
int write;
@@ -851,7 +851,7 @@
if (context != NULL) {
/* save pagefault timestamp for GFT */
set_bit(KGSL_CONTEXT_PRIV_PAGEFAULT, &context->priv);
- tid = context->tid;
+ pid = context->proc_priv->pid;
}
ctx->fault = 1;
@@ -872,7 +872,7 @@
contextidr = KGSL_IOMMU_GET_CTX_REG(ctx, CONTEXTIDR);
ptname = MMU_FEATURE(mmu, KGSL_MMU_GLOBAL_PAGETABLE) ?
- KGSL_MMU_GLOBAL_PT : tid;
+ KGSL_MMU_GLOBAL_PT : pid;
/*
* Trace needs to be logged before searching the faulting
* address in free list as it takes quite long time in
diff --git a/drivers/gpu/msm/kgsl_pwrctrl.c b/drivers/gpu/msm/kgsl_pwrctrl.c
index 940a741f..cda7a5b 100644
--- a/drivers/gpu/msm/kgsl_pwrctrl.c
+++ b/drivers/gpu/msm/kgsl_pwrctrl.c
@@ -2124,6 +2124,45 @@
devm_clk_put(&device->pdev->dev, pwr->gpu_bimc_int_clk);
}
+static bool _gpu_freq_supported(struct kgsl_pwrctrl *pwr, unsigned int freq)
+{
+ int i;
+
+ for (i = pwr->num_pwrlevels - 2; i >= 0; i--) {
+ if (pwr->pwrlevels[i].gpu_freq == freq)
+ return true;
+ }
+
+ return false;
+}
+
+static void kgsl_pwrctrl_disable_unused_opp(struct kgsl_device *device)
+{
+ struct device *dev = &device->pdev->dev;
+ struct dev_pm_opp *opp;
+ unsigned long freq = 0;
+ int ret;
+
+ ret = dev_pm_opp_get_opp_count(dev);
+ /* Return early, If no OPP table or OPP count is zero */
+ if (ret <= 0)
+ return;
+
+ while (1) {
+ rcu_read_lock();
+ opp = dev_pm_opp_find_freq_ceil(dev, &freq);
+ rcu_read_unlock();
+
+ if (IS_ERR(opp))
+ break;
+
+ if (!_gpu_freq_supported(&device->pwrctrl, freq))
+ dev_pm_opp_disable(dev, freq);
+
+ freq++;
+ }
+}
+
int kgsl_pwrctrl_init(struct kgsl_device *device)
{
int i, k, m, n = 0, result;
@@ -2181,6 +2220,8 @@
pwr->pwrlevels[i].gpu_freq = freq;
}
+ kgsl_pwrctrl_disable_unused_opp(device);
+
kgsl_clk_set_rate(device, pwr->num_pwrlevels - 1);
clk_set_rate(pwr->grp_clks[6],
@@ -2691,6 +2732,9 @@
* GPU will not be powered on
*/
WARN_ONCE(1, "Failed to recover GMU\n");
+ device->snapshot->recovered = false;
+ } else {
+ device->snapshot->recovered = true;
}
clear_bit(GMU_FAULT, &gmu->flags);
diff --git a/drivers/gpu/msm/kgsl_snapshot.c b/drivers/gpu/msm/kgsl_snapshot.c
index f710d8f..33ce60d 100644
--- a/drivers/gpu/msm/kgsl_snapshot.c
+++ b/drivers/gpu/msm/kgsl_snapshot.c
@@ -663,7 +663,7 @@
* Overwrite a non-GMU fault snapshot if a GMU fault occurs.
*/
if (device->snapshot != NULL) {
- if (!gmu_fault || device->snapshot->gmu_fault)
+ if (!gmu_fault || !device->snapshot->recovered)
return;
/*
@@ -689,6 +689,7 @@
snapshot->ptr = device->snapshot_memory.ptr;
snapshot->remain = device->snapshot_memory.size;
snapshot->gmu_fault = gmu_fault;
+ snapshot->recovered = false;
snapshot->first_read = true;
snapshot->sysfs_read = 0;
diff --git a/drivers/iommu/arm-smmu.c b/drivers/iommu/arm-smmu.c
index 86438a9..6324728 100644
--- a/drivers/iommu/arm-smmu.c
+++ b/drivers/iommu/arm-smmu.c
@@ -47,6 +47,7 @@
#include <linux/platform_device.h>
#include <linux/slab.h>
#include <linux/spinlock.h>
+#include <soc/qcom/scm.h>
#include <soc/qcom/secure_buffer.h>
#include <linux/of_platform.h>
#include <linux/msm-bus.h>
@@ -4446,34 +4447,60 @@
return ret;
}
+#define SCM_CONFIG_ERRATA1_CLIENT_ALL 0x2
+#define SCM_CONFIG_ERRATA1 0x3
static void __qsmmuv500_errata1_tlbiall(struct arm_smmu_domain *smmu_domain)
{
struct arm_smmu_device *smmu = smmu_domain->smmu;
struct device *dev = smmu_domain->dev;
struct arm_smmu_cfg *cfg = &smmu_domain->cfg;
void __iomem *base;
+ int ret;
ktime_t cur;
u32 val;
+ struct scm_desc desc = {
+ .args[0] = SCM_CONFIG_ERRATA1_CLIENT_ALL,
+ .args[1] = false,
+ .arginfo = SCM_ARGS(2, SCM_VAL, SCM_VAL),
+ };
base = ARM_SMMU_CB_BASE(smmu) + ARM_SMMU_CB(smmu, cfg->cbndx);
writel_relaxed(0, base + ARM_SMMU_CB_S1_TLBIALL);
writel_relaxed(0, base + ARM_SMMU_CB_TLBSYNC);
+ if (!readl_poll_timeout_atomic(base + ARM_SMMU_CB_TLBSTATUS, val,
+ !(val & TLBSTATUS_SACTIVE), 0, 100))
+ return;
+
+ ret = scm_call2_atomic(SCM_SIP_FNID(SCM_SVC_SMMU_PROGRAM,
+ SCM_CONFIG_ERRATA1),
+ &desc);
+ if (ret) {
+ dev_err(smmu->dev, "Calling into TZ to disable ERRATA1 failed - IOMMU hardware in bad state\n");
+ BUG();
+ return;
+ }
+
+ cur = ktime_get();
+ trace_tlbi_throttle_start(dev, 0);
+ msm_bus_noc_throttle_wa(true);
+
if (readl_poll_timeout_atomic(base + ARM_SMMU_CB_TLBSTATUS, val,
- !(val & TLBSTATUS_SACTIVE), 0, 100)) {
- cur = ktime_get();
- trace_tlbi_throttle_start(dev, 0);
+ !(val & TLBSTATUS_SACTIVE), 0, 10000)) {
+ dev_err(smmu->dev, "ERRATA1 TLBSYNC timeout - IOMMU hardware in bad state");
+ trace_tlbsync_timeout(dev, 0);
+ BUG();
+ }
- msm_bus_noc_throttle_wa(true);
- if (readl_poll_timeout_atomic(base + ARM_SMMU_CB_TLBSTATUS, val,
- !(val & TLBSTATUS_SACTIVE), 0, 10000)) {
- dev_err(smmu->dev, "ERRATA1 TLBSYNC timeout");
- trace_tlbsync_timeout(dev, 0);
- }
+ msm_bus_noc_throttle_wa(false);
+ trace_tlbi_throttle_end(dev, ktime_us_delta(ktime_get(), cur));
- msm_bus_noc_throttle_wa(false);
-
- trace_tlbi_throttle_end(
- dev, ktime_us_delta(ktime_get(), cur));
+ desc.args[1] = true;
+ ret = scm_call2_atomic(SCM_SIP_FNID(SCM_SVC_SMMU_PROGRAM,
+ SCM_CONFIG_ERRATA1),
+ &desc);
+ if (ret) {
+ dev_err(smmu->dev, "Calling into TZ to reenable ERRATA1 failed - IOMMU hardware in bad state\n");
+ BUG();
}
}
diff --git a/drivers/leds/leds-qpnp-flash-v2.c b/drivers/leds/leds-qpnp-flash-v2.c
index 5bd52e4..1a2aea9 100644
--- a/drivers/leds/leds-qpnp-flash-v2.c
+++ b/drivers/leds/leds-qpnp-flash-v2.c
@@ -731,7 +731,8 @@
#define FLASH_VDIP_MARGIN 50000
#define BOB_EFFICIENCY 900LL
#define VIN_FLASH_MIN_UV 3300000LL
-static int qpnp_flash_led_calc_max_current(struct qpnp_flash_led *led)
+static int qpnp_flash_led_calc_max_current(struct qpnp_flash_led *led,
+ int *max_current)
{
int ocv_uv, ibat_now, voltage_hdrm_mv, rc;
int rbatt_uohm = 0;
@@ -747,8 +748,10 @@
}
/* If no battery is connected, return max possible flash current */
- if (!rbatt_uohm)
- return FLASH_LED_MAX_TOTAL_CURRENT_MA;
+ if (!rbatt_uohm) {
+ *max_current = FLASH_LED_MAX_TOTAL_CURRENT_MA;
+ return 0;
+ }
rc = get_property_from_fg(led, POWER_SUPPLY_PROP_VOLTAGE_OCV, &ocv_uv);
if (rc < 0) {
@@ -785,7 +788,7 @@
/* Wait for LMH mitigation to take effect */
udelay(100);
- return qpnp_flash_led_calc_max_current(led);
+ return qpnp_flash_led_calc_max_current(led, max_current);
}
/*
@@ -825,13 +828,14 @@
avail_flash_ua = div64_s64(avail_flash_power_fw, vin_flash_uv * MCONV);
pr_debug("avail_iflash=%lld, ocv=%d, ibat=%d, rbatt=%d, trigger_lmh=%d\n",
avail_flash_ua, ocv_uv, ibat_now, rbatt_uohm, led->trigger_lmh);
- return min(FLASH_LED_MAX_TOTAL_CURRENT_MA,
+ *max_current = min(FLASH_LED_MAX_TOTAL_CURRENT_MA,
(int)(div64_s64(avail_flash_ua, MCONV)));
+ return 0;
}
-static int qpnp_flash_led_calc_thermal_current_lim(struct qpnp_flash_led *led)
+static int qpnp_flash_led_calc_thermal_current_lim(struct qpnp_flash_led *led,
+ int *thermal_current_lim)
{
- int thermal_current_lim = 0;
int rc;
u8 thermal_thrsh1, thermal_thrsh2, thermal_thrsh3, otst_status;
@@ -888,7 +892,7 @@
/* Look up current limit based on THERMAL_OTST status */
if (otst_status)
- thermal_current_lim =
+ *thermal_current_lim =
led->pdata->thermal_derate_current[otst_status >> 1];
/* Restore THERMAL_THRESHx registers to original values */
@@ -913,23 +917,36 @@
if (rc < 0)
return rc;
- return thermal_current_lim;
+ return 0;
}
-static int qpnp_flash_led_get_max_avail_current(struct qpnp_flash_led *led)
+static int qpnp_flash_led_get_max_avail_current(struct qpnp_flash_led *led,
+ int *max_avail_current)
{
- int max_avail_current, thermal_current_lim = 0;
+ int thermal_current_lim = 0, rc;
led->trigger_lmh = false;
- max_avail_current = qpnp_flash_led_calc_max_current(led);
- if (led->pdata->thermal_derate_en)
- thermal_current_lim =
- qpnp_flash_led_calc_thermal_current_lim(led);
+ rc = qpnp_flash_led_calc_max_current(led, max_avail_current);
+ if (rc < 0) {
+ pr_err("Couldn't calculate max_avail_current, rc=%d\n", rc);
+ return rc;
+ }
+
+ if (led->pdata->thermal_derate_en) {
+ rc = qpnp_flash_led_calc_thermal_current_lim(led,
+ &thermal_current_lim);
+ if (rc < 0) {
+ pr_err("Couldn't calculate thermal_current_lim, rc=%d\n",
+ rc);
+ return rc;
+ }
+ }
if (thermal_current_lim)
- max_avail_current = min(max_avail_current, thermal_current_lim);
+ *max_avail_current = min(*max_avail_current,
+ thermal_current_lim);
- return max_avail_current;
+ return 0;
}
static void qpnp_flash_led_aggregate_max_current(struct flash_node_data *fnode)
@@ -1237,12 +1254,11 @@
}
if (options & QUERY_MAX_CURRENT) {
- rc = qpnp_flash_led_get_max_avail_current(led);
+ rc = qpnp_flash_led_get_max_avail_current(led, max_current);
if (rc < 0) {
pr_err("query max current failed, rc=%d\n", rc);
return rc;
}
- *max_current = rc;
}
return 0;
@@ -1291,7 +1307,7 @@
static ssize_t qpnp_flash_led_max_current_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
- int rc;
+ int rc, max_current = 0;
struct flash_switch_data *snode;
struct qpnp_flash_led *led;
struct led_classdev *led_cdev = dev_get_drvdata(dev);
@@ -1299,11 +1315,11 @@
snode = container_of(led_cdev, struct flash_switch_data, cdev);
led = dev_get_drvdata(&snode->pdev->dev);
- rc = qpnp_flash_led_get_max_avail_current(led);
+ rc = qpnp_flash_led_get_max_avail_current(led, &max_current);
if (rc < 0)
pr_err("query max current failed, rc=%d\n", rc);
- return snprintf(buf, PAGE_SIZE, "%d\n", rc);
+ return snprintf(buf, PAGE_SIZE, "%d\n", max_current);
}
/* sysfs attributes exported by flash_led */
diff --git a/drivers/mailbox/mailbox.c b/drivers/mailbox/mailbox.c
index 9dc85cd..620cc7e 100644
--- a/drivers/mailbox/mailbox.c
+++ b/drivers/mailbox/mailbox.c
@@ -53,17 +53,16 @@
return idx;
}
-static void msg_submit(struct mbox_chan *chan)
+static int __msg_submit(struct mbox_chan *chan)
{
unsigned count, idx;
unsigned long flags;
void *data;
int err = -EBUSY;
-again:
spin_lock_irqsave(&chan->lock, flags);
- if (!chan->msg_count || (chan->active_req && err != -EAGAIN))
+ if (!chan->msg_count || chan->active_req)
goto exit;
count = chan->msg_count;
@@ -86,15 +85,23 @@
exit:
spin_unlock_irqrestore(&chan->lock, flags);
+ return err;
+}
+
+static void msg_submit(struct mbox_chan *chan)
+{
+ int err = 0;
+
/*
* If the controller returns -EAGAIN, then it means, our spinlock
* here is preventing the controller from receiving its interrupt,
* that would help clear the controller channels that are currently
* blocked waiting on the interrupt response.
- * Unlock and retry again.
+ * Retry again.
*/
- if (err == -EAGAIN)
- goto again;
+ do {
+ err = __msg_submit(chan);
+ } while (err == -EAGAIN);
if (!err && (chan->txdone_method & TXDONE_BY_POLL))
/* kick start the timer immediately to avoid delays */
diff --git a/drivers/media/platform/msm/camera/cam_cpas/cam_cpas_hw.c b/drivers/media/platform/msm/camera/cam_cpas/cam_cpas_hw.c
index f1dfc7c..00ead5d 100644
--- a/drivers/media/platform/msm/camera/cam_cpas/cam_cpas_hw.c
+++ b/drivers/media/platform/msm/camera/cam_cpas/cam_cpas_hw.c
@@ -585,7 +585,7 @@
if (rc) {
CAM_ERR(CAM_CPAS,
"Failed camnoc vote ab[%llu] ib[%llu] rc=%d",
- 0, camnoc_bw, rc);
+ (uint64_t)0, camnoc_bw, rc);
goto unlock_axi_port;
}
}
diff --git a/drivers/media/platform/msm/camera/cam_cpas/cpas_top/cpastop_v170_110.h b/drivers/media/platform/msm/camera/cam_cpas/cpas_top/cpastop_v170_110.h
index 4418fb1..3c572f0 100644
--- a/drivers/media/platform/msm/camera/cam_cpas/cpas_top/cpastop_v170_110.h
+++ b/drivers/media/platform/msm/camera/cam_cpas/cpas_top/cpastop_v170_110.h
@@ -230,7 +230,7 @@
.offset = 0x38, /* SPECIFIC_CDM_URGENCY_LOW */
.mask = 0x7, /* SPECIFIC_CDM_URGENCY_LOW_READ_MASK */
.shift = 0x0, /* SPECIFIC_CDM_URGENCY_LOW_READ_SHIFT */
- .value = 0,
+ .value = 0x2,
},
.danger_lut = {
.enable = false,
@@ -258,7 +258,7 @@
.access_type = CAM_REG_TYPE_READ_WRITE,
.masked_value = 0,
.offset = 0x430, /* SPECIFIC_IFE02_PRIORITYLUT_LOW */
- .value = 0x44443333,
+ .value = 0x66666543,
},
.priority_lut_high = {
.enable = true,
@@ -288,7 +288,7 @@
.enable = true,
.access_type = CAM_REG_TYPE_READ_WRITE,
.offset = 0x448, /* SPECIFIC_IFE02_SAFELUT_LOW */
- .value = 0x3,
+ .value = 0x1,
},
.ubwc_ctl = {
.enable = true,
@@ -306,7 +306,7 @@
.access_type = CAM_REG_TYPE_READ_WRITE,
.masked_value = 0,
.offset = 0x830, /* SPECIFIC_IFE13_PRIORITYLUT_LOW */
- .value = 0x44443333,
+ .value = 0x66666543,
},
.priority_lut_high = {
.enable = true,
@@ -336,7 +336,7 @@
.enable = true,
.access_type = CAM_REG_TYPE_READ_WRITE,
.offset = 0x848, /* SPECIFIC_IFE13_SAFELUT_LOW */
- .value = 0x3,
+ .value = 0x1,
},
.ubwc_ctl = {
.enable = true,
diff --git a/drivers/media/platform/msm/camera/cam_fd/fd_hw_mgr/cam_fd_hw_mgr.c b/drivers/media/platform/msm/camera/cam_fd/fd_hw_mgr/cam_fd_hw_mgr.c
index bff42f4..e57066d 100644
--- a/drivers/media/platform/msm/camera/cam_fd/fd_hw_mgr/cam_fd_hw_mgr.c
+++ b/drivers/media/platform/msm/camera/cam_fd/fd_hw_mgr/cam_fd_hw_mgr.c
@@ -402,7 +402,7 @@
(struct cam_fd_hw_cmd_prestart_args *)user_data;
if (!blob_data || (blob_size == 0)) {
- CAM_ERR(CAM_FD, "Invalid blob info %pK %d", blob_data,
+ CAM_ERR(CAM_FD, "Invalid blob info %pK %u", blob_data,
blob_size);
return -EINVAL;
}
@@ -417,7 +417,7 @@
uint32_t *get_raw_results = (uint32_t *)blob_data;
if (sizeof(uint32_t) != blob_size) {
- CAM_ERR(CAM_FD, "Invalid blob size %d %d",
+ CAM_ERR(CAM_FD, "Invalid blob size %lu %u",
sizeof(uint32_t), blob_size);
return -EINVAL;
}
@@ -430,7 +430,7 @@
(struct cam_fd_soc_clock_bw_request *)blob_data;
if (sizeof(struct cam_fd_soc_clock_bw_request) != blob_size) {
- CAM_ERR(CAM_FD, "Invalid blob size %d %d",
+ CAM_ERR(CAM_FD, "Invalid blob size %lu %u",
sizeof(struct cam_fd_soc_clock_bw_request),
blob_size);
return -EINVAL;
diff --git a/drivers/media/platform/msm/camera/cam_fd/fd_hw_mgr/fd_hw/cam_fd_hw_core.c b/drivers/media/platform/msm/camera/cam_fd/fd_hw_mgr/fd_hw/cam_fd_hw_core.c
index 51c8e4a..640c6f6 100644
--- a/drivers/media/platform/msm/camera/cam_fd/fd_hw_mgr/fd_hw/cam_fd_hw_core.c
+++ b/drivers/media/platform/msm/camera/cam_fd/fd_hw_mgr/fd_hw/cam_fd_hw_core.c
@@ -127,7 +127,7 @@
time_left = wait_for_completion_timeout(&fd_core->reset_complete,
msecs_to_jiffies(CAM_FD_HW_HALT_RESET_TIMEOUT));
if (time_left <= 0)
- CAM_WARN(CAM_FD, "HW reset timeout time_left=%d", time_left);
+ CAM_WARN(CAM_FD, "HW reset timeout time_left=%ld", time_left);
CAM_DBG(CAM_FD, "FD Wrapper SW Sync Reset complete");
@@ -157,7 +157,7 @@
time_left = wait_for_completion_timeout(&fd_core->halt_complete,
msecs_to_jiffies(CAM_FD_HW_HALT_RESET_TIMEOUT));
if (time_left <= 0)
- CAM_WARN(CAM_FD, "HW halt timeout time_left=%d", time_left);
+ CAM_WARN(CAM_FD, "HW halt timeout time_left=%ld", time_left);
CAM_DBG(CAM_FD, "FD Wrapper Halt complete");
@@ -651,7 +651,7 @@
}
if (arg_size != sizeof(struct cam_fd_hw_init_args)) {
- CAM_ERR(CAM_FD, "Invalid arg size %d, %d", arg_size,
+ CAM_ERR(CAM_FD, "Invalid arg size %u, %lu", arg_size,
sizeof(struct cam_fd_hw_init_args));
return -EINVAL;
}
@@ -735,7 +735,7 @@
}
if (arg_size != sizeof(struct cam_fd_hw_deinit_args)) {
- CAM_ERR(CAM_FD, "Invalid arg size %d, %d", arg_size,
+ CAM_ERR(CAM_FD, "Invalid arg size %u, %lu", arg_size,
sizeof(struct cam_fd_hw_deinit_args));
return -EINVAL;
}
@@ -859,7 +859,7 @@
}
if (arg_size != sizeof(struct cam_fd_hw_cmd_start_args)) {
- CAM_ERR(CAM_FD, "Invalid arg size %d, %d", arg_size,
+ CAM_ERR(CAM_FD, "Invalid arg size %u, %lu", arg_size,
sizeof(struct cam_fd_hw_cmd_start_args));
return -EINVAL;
}
@@ -1010,7 +1010,7 @@
}
if (arg_size != sizeof(struct cam_fd_hw_reserve_args)) {
- CAM_ERR(CAM_FD, "Invalid arg size %d, %d", arg_size,
+ CAM_ERR(CAM_FD, "Invalid arg size %u, %lu", arg_size,
sizeof(struct cam_fd_hw_reserve_args));
return -EINVAL;
}
@@ -1079,7 +1079,7 @@
}
if (arg_size != sizeof(struct cam_fd_hw_release_args)) {
- CAM_ERR(CAM_FD, "Invalid arg size %d, %d", arg_size,
+ CAM_ERR(CAM_FD, "Invalid arg size %u, %lu", arg_size,
sizeof(struct cam_fd_hw_release_args));
return -EINVAL;
}
diff --git a/drivers/media/platform/msm/camera/cam_icp/fw_inc/hfi_intf.h b/drivers/media/platform/msm/camera/cam_icp/fw_inc/hfi_intf.h
index ce7a8b3..b9b59a1 100644
--- a/drivers/media/platform/msm/camera/cam_icp/fw_inc/hfi_intf.h
+++ b/drivers/media/platform/msm/camera/cam_icp/fw_inc/hfi_intf.h
@@ -123,8 +123,9 @@
* power collapse for IPE and BPS hardware.
*
* @enable: flag to enable/disable
+ * @core_info: Core information to firmware
*/
-int hfi_enable_ipe_bps_pc(bool enable);
+int hfi_enable_ipe_bps_pc(bool enable, uint32_t core_info);
/**
* hfi_cmd_ubwc_config() - UBWC configuration to firmware
@@ -132,4 +133,15 @@
*/
int hfi_cmd_ubwc_config(uint32_t *ubwc_cfg);
+/**
+ * cam_hfi_resume() - function to resume
+ * @hfi_mem: hfi memory info
+ * @icp_base: icp base address
+ * @debug: debug flag
+ *
+ * Returns success(zero)/failure(non zero)
+ */
+int cam_hfi_resume(struct hfi_mem_info *hfi_mem,
+ void __iomem *icp_base, bool debug);
+
#endif /* _HFI_INTF_H_ */
diff --git a/drivers/media/platform/msm/camera/cam_icp/fw_inc/hfi_reg.h b/drivers/media/platform/msm/camera/cam_icp/fw_inc/hfi_reg.h
index eb4b132..6909972 100644
--- a/drivers/media/platform/msm/camera/cam_icp/fw_inc/hfi_reg.h
+++ b/drivers/media/platform/msm/camera/cam_icp/fw_inc/hfi_reg.h
@@ -51,6 +51,15 @@
#define ICP_CSR_DBGSWENABLE (1 << 22)
#define ICP_CSR_A5_STATUS_WFI (1 << 7)
+#define ICP_FLAG_A5_CTRL_DBG_EN (ICP_FLAG_CSR_WAKE_UP_EN|\
+ ICP_FLAG_CSR_A5_EN|\
+ ICP_CSR_EDBGRQ|\
+ ICP_CSR_DBGSWENABLE)
+
+#define ICP_FLAG_A5_CTRL_EN (ICP_FLAG_CSR_WAKE_UP_EN|\
+ ICP_FLAG_CSR_A5_EN|\
+ ICP_CSR_EN_CLKGATE_WFI)
+
/* start of Queue table and queues */
#define MAX_ICP_HFI_QUEUES 4
#define ICP_QHDR_TX_TYPE_MASK 0xFF000000
diff --git a/drivers/media/platform/msm/camera/cam_icp/fw_inc/hfi_sys_defs.h b/drivers/media/platform/msm/camera/cam_icp/fw_inc/hfi_sys_defs.h
index aaa18bb..84cc129 100644
--- a/drivers/media/platform/msm/camera/cam_icp/fw_inc/hfi_sys_defs.h
+++ b/drivers/media/platform/msm/camera/cam_icp/fw_inc/hfi_sys_defs.h
@@ -254,9 +254,11 @@
* struct hfi_ipe_bps_pc
* payload structure to configure HFI_PROPERTY_SYS_IPEBPS_PC
* @enable: Flag to enable IPE, BPS interfrane power collapse
+ * @core_info: Core information to firmware
*/
struct hfi_ipe_bps_pc {
uint32_t enable;
+ uint32_t core_info;
} __packed;
/**
diff --git a/drivers/media/platform/msm/camera/cam_icp/hfi.c b/drivers/media/platform/msm/camera/cam_icp/hfi.c
index a8855ae..eca16d6 100644
--- a/drivers/media/platform/msm/camera/cam_icp/hfi.c
+++ b/drivers/media/platform/msm/camera/cam_icp/hfi.c
@@ -40,6 +40,8 @@
#define HFI_VERSION_INFO_STEP_BMSK 0xFF
#define HFI_VERSION_INFO_STEP_SHFT 0
+#define HFI_MAX_POLL_TRY 5
+
static struct hfi_info *g_hfi;
unsigned int g_icp_mmu_hdl;
static DEFINE_MUTEX(hfi_cmd_q_mutex);
@@ -248,7 +250,7 @@
return 0;
}
-int hfi_enable_ipe_bps_pc(bool enable)
+int hfi_enable_ipe_bps_pc(bool enable, uint32_t core_info)
{
uint8_t *prop;
struct hfi_cmd_prop *dbg_prop;
@@ -267,6 +269,7 @@
dbg_prop->num_prop = 1;
dbg_prop->prop_data[0] = HFI_PROP_SYS_IPEBPS_PC;
dbg_prop->prop_data[1] = enable;
+ dbg_prop->prop_data[2] = core_info;
hfi_write_cmd(prop);
kfree(prop);
@@ -420,14 +423,28 @@
{
uint32_t data;
uint32_t val;
+ uint32_t try = 0;
- data = cam_io_r(icp_base + HFI_REG_A5_CSR_A5_STATUS);
- /* Add waiting logic in case it is not idle */
- if (data & ICP_CSR_A5_STATUS_WFI) {
- val = cam_io_r(icp_base + HFI_REG_A5_CSR_A5_CONTROL);
- val &= ~(ICP_FLAG_CSR_A5_EN | ICP_FLAG_CSR_WAKE_UP_EN);
- cam_io_w(val, icp_base + HFI_REG_A5_CSR_A5_CONTROL);
+ while (try < HFI_MAX_POLL_TRY) {
+ data = cam_io_r(icp_base + HFI_REG_A5_CSR_A5_STATUS);
+ CAM_DBG(CAM_HFI, "wfi status = %x\n", (int)data);
+
+ if (data & ICP_CSR_A5_STATUS_WFI)
+ break;
+ /* Need to poll here to confirm that FW is going trigger wfi
+ * and Host can the proceed. No interrupt is expected from FW
+ * at this time.
+ */
+ msleep(100);
+ try++;
}
+
+ val = cam_io_r(icp_base + HFI_REG_A5_CSR_A5_CONTROL);
+ val &= ~(ICP_FLAG_CSR_A5_EN | ICP_FLAG_CSR_WAKE_UP_EN);
+ cam_io_w(val, icp_base + HFI_REG_A5_CSR_A5_CONTROL);
+
+ val = cam_io_r(icp_base + HFI_REG_A5_CSR_NSEC_RESET);
+ cam_io_w(val, icp_base + HFI_REG_A5_CSR_NSEC_RESET);
}
void cam_hfi_enable_cpu(void __iomem *icp_base)
@@ -437,6 +454,64 @@
cam_io_w((uint32_t)0x10, icp_base + HFI_REG_A5_CSR_NSEC_RESET);
}
+int cam_hfi_resume(struct hfi_mem_info *hfi_mem,
+ void __iomem *icp_base, bool debug)
+{
+ int rc = 0;
+ uint32_t data;
+ uint32_t fw_version, status = 0;
+
+ cam_hfi_enable_cpu(icp_base);
+ g_hfi->csr_base = icp_base;
+
+ rc = readw_poll_timeout((icp_base + HFI_REG_ICP_HOST_INIT_RESPONSE),
+ status, status != ICP_INIT_RESP_SUCCESS, 15, 200);
+
+ if (rc) {
+ CAM_ERR(CAM_HFI, "timed out , status = %u", status);
+ return -EINVAL;
+ }
+
+ fw_version = cam_io_r(icp_base + HFI_REG_FW_VERSION);
+ CAM_DBG(CAM_HFI, "fw version : [%x]", fw_version);
+
+ cam_io_w((uint32_t)INTR_ENABLE, icp_base + HFI_REG_A5_CSR_A2HOSTINTEN);
+
+ if (debug) {
+ cam_io_w_mb(ICP_FLAG_A5_CTRL_DBG_EN,
+ (icp_base + HFI_REG_A5_CSR_A5_CONTROL));
+
+ /* Barrier needed as next write should be done after
+ * sucessful previous write. Next write enable clock
+ * gating
+ */
+ wmb();
+
+ cam_io_w_mb((uint32_t)ICP_FLAG_A5_CTRL_EN,
+ icp_base + HFI_REG_A5_CSR_A5_CONTROL);
+
+ } else {
+ cam_io_w_mb((uint32_t)ICP_FLAG_A5_CTRL_EN,
+ icp_base + HFI_REG_A5_CSR_A5_CONTROL);
+ }
+
+ data = cam_io_r(icp_base + HFI_REG_A5_CSR_A5_STATUS);
+ CAM_DBG(CAM_HFI, "wfi status = %x", (int)data);
+
+ cam_io_w((uint32_t)hfi_mem->qtbl.iova, icp_base + HFI_REG_QTBL_PTR);
+ cam_io_w((uint32_t)hfi_mem->shmem.iova,
+ icp_base + HFI_REG_SHARED_MEM_PTR);
+ cam_io_w((uint32_t)hfi_mem->shmem.len,
+ icp_base + HFI_REG_SHARED_MEM_SIZE);
+ cam_io_w((uint32_t)hfi_mem->sec_heap.iova,
+ icp_base + HFI_REG_UNCACHED_HEAP_PTR);
+ cam_io_w((uint32_t)hfi_mem->sec_heap.len,
+ icp_base + HFI_REG_UNCACHED_HEAP_SIZE);
+
+ cam_io_w((uint32_t)INTR_ENABLE, icp_base + HFI_REG_A5_CSR_A2HOSTINTEN);
+ return rc;
+}
+
int cam_hfi_init(uint8_t event_driven_mode, struct hfi_mem_info *hfi_mem,
void __iomem *icp_base, bool debug)
{
diff --git a/drivers/media/platform/msm/camera/cam_icp/icp_hw/a5_hw/a5_core.c b/drivers/media/platform/msm/camera/cam_icp/icp_hw/a5_hw/a5_core.c
index 635d0df..aeec16c 100644
--- a/drivers/media/platform/msm/camera/cam_icp/icp_hw/a5_hw/a5_core.c
+++ b/drivers/media/platform/msm/camera/cam_icp/icp_hw/a5_hw/a5_core.c
@@ -422,6 +422,11 @@
case CAM_ICP_A5_SEND_INIT:
hfi_send_system_cmd(HFI_CMD_SYS_INIT, 0, 0);
break;
+
+ case CAM_ICP_A5_CMD_PC_PREP:
+ hfi_send_system_cmd(HFI_CMD_SYS_PC_PREP, 0, 0);
+ break;
+
case CAM_ICP_A5_CMD_VOTE_CPAS: {
struct cam_icp_cpas_vote *cpas_vote = cmd_args;
diff --git a/drivers/media/platform/msm/camera/cam_icp/icp_hw/bps_hw/bps_core.c b/drivers/media/platform/msm/camera/cam_icp/icp_hw/bps_hw/bps_core.c
index 3473d08..c18a5e4 100644
--- a/drivers/media/platform/msm/camera/cam_icp/icp_hw/bps_hw/bps_core.c
+++ b/drivers/media/platform/msm/camera/cam_icp/icp_hw/bps_hw/bps_core.c
@@ -157,8 +157,11 @@
CAM_CPAS_REG_CPASTOP,
hw_info->pwr_ctrl, true, 0x1);
- if ((pwr_status >> BPS_PWR_ON_MASK))
+ if ((pwr_status >> BPS_PWR_ON_MASK)) {
+ CAM_ERR(CAM_ICP, "BPS: pwr_status(%x):pwr_ctrl(%x)",
+ pwr_status, pwr_ctrl);
return -EINVAL;
+ }
}
cam_bps_get_gdsc_control(soc_info);
cam_cpas_reg_read(core_info->cpas_handle,
@@ -189,7 +192,7 @@
cam_cpas_reg_read(core_info->cpas_handle,
CAM_CPAS_REG_CPASTOP, hw_info->pwr_ctrl, true, &pwr_ctrl);
if (pwr_ctrl & BPS_COLLAPSE_MASK) {
- CAM_ERR(CAM_ICP, "BPS: resume failed : %d", pwr_ctrl);
+ CAM_ERR(CAM_ICP, "BPS: pwr_ctrl(%x)", pwr_ctrl);
return -EINVAL;
}
diff --git a/drivers/media/platform/msm/camera/cam_icp/icp_hw/icp_hw_mgr/cam_icp_hw_mgr.c b/drivers/media/platform/msm/camera/cam_icp/icp_hw/icp_hw_mgr/cam_icp_hw_mgr.c
index 6f997a2..29a1b9a 100644
--- a/drivers/media/platform/msm/camera/cam_icp/icp_hw/icp_hw_mgr/cam_icp_hw_mgr.c
+++ b/drivers/media/platform/msm/camera/cam_icp/icp_hw/icp_hw_mgr/cam_icp_hw_mgr.c
@@ -729,9 +729,6 @@
struct cam_hw_intf *bps_dev_intf = NULL;
int rc = 0;
- if (!icp_hw_mgr.icp_pc_flag)
- return rc;
-
ipe0_dev_intf = hw_mgr->devices[CAM_ICP_DEV_IPE][0];
ipe1_dev_intf = hw_mgr->devices[CAM_ICP_DEV_IPE][1];
bps_dev_intf = hw_mgr->devices[CAM_ICP_DEV_BPS][0];
@@ -741,36 +738,61 @@
return -EINVAL;
}
- bps_dev_intf->hw_ops.process_cmd(
- bps_dev_intf->hw_priv,
- CAM_ICP_BPS_CMD_POWER_RESUME, NULL, 0);
+ if (ctx_data->icp_dev_acquire_info->dev_type == CAM_ICP_RES_TYPE_BPS) {
+ if (hw_mgr->bps_ctxt_cnt++)
+ goto end;
+ bps_dev_intf->hw_ops.init(bps_dev_intf->hw_priv, NULL, 0);
+ if (icp_hw_mgr.icp_pc_flag) {
+ bps_dev_intf->hw_ops.process_cmd(
+ bps_dev_intf->hw_priv,
+ CAM_ICP_BPS_CMD_POWER_RESUME, NULL, 0);
+ hw_mgr->core_info = hw_mgr->core_info | ICP_PWR_CLP_BPS;
+ }
+ } else {
+ if (hw_mgr->ipe_ctxt_cnt++)
+ goto end;
- ipe0_dev_intf->hw_ops.process_cmd(
- ipe0_dev_intf->hw_priv,
- CAM_ICP_IPE_CMD_POWER_RESUME, NULL, 0);
+ ipe0_dev_intf->hw_ops.init(ipe0_dev_intf->hw_priv, NULL, 0);
+ if (icp_hw_mgr.icp_pc_flag) {
+ ipe0_dev_intf->hw_ops.process_cmd(
+ ipe0_dev_intf->hw_priv,
+ CAM_ICP_IPE_CMD_POWER_RESUME, NULL, 0);
+ }
- if (ipe1_dev_intf) {
- ipe1_dev_intf->hw_ops.process_cmd(
- ipe1_dev_intf->hw_priv,
- CAM_ICP_IPE_CMD_POWER_RESUME, NULL, 0);
+ if ((icp_hw_mgr.ipe1_enable) && (ipe1_dev_intf)) {
+ ipe1_dev_intf->hw_ops.init(ipe1_dev_intf->hw_priv,
+ NULL, 0);
+
+ if (icp_hw_mgr.icp_pc_flag) {
+ ipe1_dev_intf->hw_ops.process_cmd(
+ ipe1_dev_intf->hw_priv,
+ CAM_ICP_IPE_CMD_POWER_RESUME,
+ NULL, 0);
+ }
+ }
+ if (icp_hw_mgr.icp_pc_flag) {
+ hw_mgr->core_info = hw_mgr->core_info |
+ (ICP_PWR_CLP_IPE0 | ICP_PWR_CLP_IPE1);
+ }
}
- rc = hfi_enable_ipe_bps_pc(true);
-
+ CAM_DBG(CAM_ICP, "core_info %X", hw_mgr->core_info);
+ if (icp_hw_mgr.icp_pc_flag)
+ rc = hfi_enable_ipe_bps_pc(true, hw_mgr->core_info);
+ else
+ rc = hfi_enable_ipe_bps_pc(false, hw_mgr->core_info);
+end:
return rc;
}
static int cam_icp_mgr_ipe_bps_power_collapse(struct cam_icp_hw_mgr *hw_mgr,
struct cam_icp_hw_ctx_data *ctx_data, int dev_type)
{
- int rc = 0;
+ int rc = 0, dev;
struct cam_hw_intf *ipe0_dev_intf = NULL;
struct cam_hw_intf *ipe1_dev_intf = NULL;
struct cam_hw_intf *bps_dev_intf = NULL;
- if (!icp_hw_mgr.icp_pc_flag)
- return rc;
-
ipe0_dev_intf = hw_mgr->devices[CAM_ICP_DEV_IPE][0];
ipe1_dev_intf = hw_mgr->devices[CAM_ICP_DEV_IPE][1];
bps_dev_intf = hw_mgr->devices[CAM_ICP_DEV_BPS][0];
@@ -780,20 +802,64 @@
return -EINVAL;
}
- rc = bps_dev_intf->hw_ops.process_cmd(
- bps_dev_intf->hw_priv,
- CAM_ICP_BPS_CMD_POWER_COLLAPSE, NULL, 0);
+ if (!ctx_data)
+ dev = dev_type;
+ else
+ dev = ctx_data->icp_dev_acquire_info->dev_type;
- rc = ipe0_dev_intf->hw_ops.process_cmd(
- ipe0_dev_intf->hw_priv,
- CAM_ICP_IPE_CMD_POWER_COLLAPSE, NULL, 0);
+ if (dev == CAM_ICP_RES_TYPE_BPS) {
+ CAM_DBG(CAM_ICP, "bps ctx cnt %d", hw_mgr->bps_ctxt_cnt);
+ if (ctx_data)
+ --hw_mgr->bps_ctxt_cnt;
- if (ipe1_dev_intf) {
- rc = ipe1_dev_intf->hw_ops.process_cmd(
- ipe1_dev_intf->hw_priv,
- CAM_ICP_IPE_CMD_POWER_COLLAPSE, NULL, 0);
+ if (hw_mgr->bps_ctxt_cnt)
+ goto end;
+
+ if (icp_hw_mgr.icp_pc_flag) {
+ rc = bps_dev_intf->hw_ops.process_cmd(
+ bps_dev_intf->hw_priv,
+ CAM_ICP_BPS_CMD_POWER_COLLAPSE,
+ NULL, 0);
+ hw_mgr->core_info =
+ hw_mgr->core_info & (~ICP_PWR_CLP_BPS);
+ }
+
+ bps_dev_intf->hw_ops.deinit(bps_dev_intf->hw_priv, NULL, 0);
+ } else {
+ CAM_DBG(CAM_ICP, "ipe ctx cnt %d", hw_mgr->ipe_ctxt_cnt);
+ if (ctx_data)
+ --hw_mgr->ipe_ctxt_cnt;
+
+ if (hw_mgr->ipe_ctxt_cnt)
+ goto end;
+
+ if (icp_hw_mgr.icp_pc_flag) {
+ rc = ipe0_dev_intf->hw_ops.process_cmd(
+ ipe0_dev_intf->hw_priv,
+ CAM_ICP_IPE_CMD_POWER_COLLAPSE, NULL, 0);
+
+ }
+ ipe0_dev_intf->hw_ops.deinit(ipe0_dev_intf->hw_priv, NULL, 0);
+
+ if (ipe1_dev_intf) {
+ if (icp_hw_mgr.icp_pc_flag) {
+ rc = ipe1_dev_intf->hw_ops.process_cmd(
+ ipe1_dev_intf->hw_priv,
+ CAM_ICP_IPE_CMD_POWER_COLLAPSE,
+ NULL, 0);
+ }
+
+ ipe1_dev_intf->hw_ops.deinit(ipe1_dev_intf->hw_priv,
+ NULL, 0);
+ }
+ if (icp_hw_mgr.icp_pc_flag) {
+ hw_mgr->core_info = hw_mgr->core_info &
+ (~(ICP_PWR_CLP_IPE0 | ICP_PWR_CLP_IPE1));
+ }
}
+ CAM_DBG(CAM_ICP, "Exit: core_info = %x", hw_mgr->core_info);
+end:
return rc;
}
@@ -844,6 +910,7 @@
rc = -ENOMEM;
goto err;
}
+ icp_hw_mgr.icp_pc_flag = 1;
if (!debugfs_create_file("icp_debug_clk",
0644,
@@ -1229,13 +1296,19 @@
{
int rc = 0;
int size_processed = 0;
- struct hfi_msg_ipebps_async_ack *async_ack = NULL;
switch (msg_ptr[ICP_PACKET_TYPE]) {
case HFI_MSG_SYS_INIT_DONE:
CAM_DBG(CAM_ICP, "received SYS_INIT_DONE");
complete(&hw_mgr->a5_complete);
- size_processed = sizeof(struct hfi_msg_init_done);
+ size_processed = (
+ (struct hfi_msg_init_done *)msg_ptr)->size;
+ break;
+
+ case HFI_MSG_SYS_PC_PREP_DONE:
+ CAM_DBG(CAM_ICP, "HFI_MSG_SYS_PC_PREP_DONE is received\n");
+ complete(&hw_mgr->a5_complete);
+ size_processed = sizeof(struct hfi_msg_pc_prep_done);
break;
case HFI_MSG_SYS_PING_ACK:
@@ -1253,20 +1326,21 @@
case HFI_MSG_IPEBPS_ASYNC_COMMAND_INDIRECT_ACK:
CAM_DBG(CAM_ICP, "received ASYNC_INDIRECT_ACK");
rc = cam_icp_mgr_process_indirect_ack_msg(msg_ptr);
- async_ack = (struct hfi_msg_ipebps_async_ack *)msg_ptr;
- size_processed = async_ack->size;
- async_ack = NULL;
+ size_processed = (
+ (struct hfi_msg_ipebps_async_ack *)msg_ptr)->size;
break;
case HFI_MSG_IPEBPS_ASYNC_COMMAND_DIRECT_ACK:
CAM_DBG(CAM_ICP, "received ASYNC_DIRECT_ACK");
rc = cam_icp_mgr_process_direct_ack_msg(msg_ptr);
- size_processed = sizeof(struct hfi_msg_ipebps_async_ack);
+ size_processed = (
+ (struct hfi_msg_ipebps_async_ack *)msg_ptr)->size;
break;
case HFI_MSG_EVENT_NOTIFY:
CAM_DBG(CAM_ICP, "received EVENT_NOTIFY");
- size_processed = sizeof(struct hfi_msg_event_notify);
+ size_processed = (
+ (struct hfi_msg_event_notify *)msg_ptr)->size;
break;
default:
@@ -1357,13 +1431,13 @@
{
int rc;
cam_smmu_dealloc_firmware(icp_hw_mgr.iommu_hdl);
+ rc = cam_mem_mgr_free_memory_region(&icp_hw_mgr.hfi_mem.sec_heap);
+ if (rc)
+ CAM_ERR(CAM_ICP, "failed to unreserve sec heap");
cam_mem_mgr_release_mem(&icp_hw_mgr.hfi_mem.qtbl);
cam_mem_mgr_release_mem(&icp_hw_mgr.hfi_mem.cmd_q);
cam_mem_mgr_release_mem(&icp_hw_mgr.hfi_mem.msg_q);
cam_mem_mgr_release_mem(&icp_hw_mgr.hfi_mem.dbg_q);
- rc = cam_mem_mgr_free_memory_region(&icp_hw_mgr.hfi_mem.sec_heap);
- if (rc)
- CAM_ERR(CAM_ICP, "failed to unreserve sec heap");
}
static int cam_icp_alloc_secheap_mem(struct cam_mem_mgr_memory_desc *secheap)
@@ -1534,6 +1608,159 @@
ctx_data->state = CAM_ICP_CTX_STATE_FREE;
}
+static int cam_icp_mgr_send_pc_prep(struct cam_icp_hw_mgr *hw_mgr)
+{
+ int rc;
+ struct cam_hw_intf *a5_dev_intf = NULL;
+ unsigned long rem_jiffies;
+ int timeout = 5000;
+
+ a5_dev_intf = hw_mgr->devices[CAM_ICP_DEV_A5][0];
+ if (!a5_dev_intf) {
+ CAM_ERR(CAM_ICP, "a5_dev_intf is invalid\n");
+ return -EINVAL;
+ }
+
+ reinit_completion(&hw_mgr->a5_complete);
+ CAM_DBG(CAM_ICP, "Sending HFI init command");
+ rc = a5_dev_intf->hw_ops.process_cmd(
+ a5_dev_intf->hw_priv, CAM_ICP_A5_CMD_PC_PREP, NULL, 0);
+ if (rc)
+ return rc;
+
+ CAM_DBG(CAM_ICP, "Wait for PC_PREP_DONE Message\n");
+ rem_jiffies = wait_for_completion_timeout(&icp_hw_mgr.a5_complete,
+ msecs_to_jiffies((timeout)));
+ if (!rem_jiffies) {
+ rc = -ETIMEDOUT;
+ CAM_ERR(CAM_ICP, "PC_PREP response timed out %d\n", rc);
+ }
+ CAM_DBG(CAM_ICP, "Done Waiting for PC_PREP Message\n");
+
+ return rc;
+}
+
+static int cam_ipe_bps_deint(struct cam_icp_hw_mgr *hw_mgr)
+{
+ struct cam_hw_intf *ipe0_dev_intf = NULL;
+ struct cam_hw_intf *ipe1_dev_intf = NULL;
+ struct cam_hw_intf *bps_dev_intf = NULL;
+
+ ipe0_dev_intf = hw_mgr->devices[CAM_ICP_DEV_IPE][0];
+ ipe1_dev_intf = hw_mgr->devices[CAM_ICP_DEV_IPE][1];
+ bps_dev_intf = hw_mgr->devices[CAM_ICP_DEV_BPS][0];
+ if ((!ipe0_dev_intf) || (!bps_dev_intf)) {
+ CAM_ERR(CAM_ICP, "dev intfs are wrong, failed to close");
+ return 0;
+ }
+
+ if (ipe1_dev_intf) {
+ ipe1_dev_intf->hw_ops.deinit(ipe1_dev_intf->hw_priv,
+ NULL, 0);
+ }
+ ipe0_dev_intf->hw_ops.deinit(ipe0_dev_intf->hw_priv, NULL, 0);
+ bps_dev_intf->hw_ops.deinit(bps_dev_intf->hw_priv, NULL, 0);
+ return 0;
+}
+static int cam_icp_mgr_icp_power_collapse(struct cam_icp_hw_mgr *hw_mgr)
+{
+ int rc;
+ struct cam_hw_intf *a5_dev_intf = NULL;
+ struct cam_hw_info *a5_dev = NULL;
+
+ CAM_DBG(CAM_ICP, "ENTER");
+
+ a5_dev_intf = hw_mgr->devices[CAM_ICP_DEV_A5][0];
+ if (!a5_dev_intf) {
+ CAM_ERR(CAM_ICP, "a5_dev_intf is invalid\n");
+ return -EINVAL;
+ }
+ a5_dev = (struct cam_hw_info *)a5_dev_intf->hw_priv;
+
+ rc = cam_icp_mgr_send_pc_prep(hw_mgr);
+
+ cam_hfi_disable_cpu(a5_dev->soc_info.reg_map[A5_SIERRA_BASE].mem_base);
+ a5_dev_intf->hw_ops.deinit(a5_dev_intf->hw_priv, NULL, 0);
+ CAM_DBG(CAM_ICP, "EXIT");
+
+ return rc;
+}
+
+static int cam_icp_mgr_hfi_resume(struct cam_icp_hw_mgr *hw_mgr)
+{
+ struct cam_hw_intf *a5_dev_intf = NULL;
+ struct cam_hw_info *a5_dev = NULL;
+ struct hfi_mem_info hfi_mem;
+
+ a5_dev_intf = hw_mgr->devices[CAM_ICP_DEV_A5][0];
+ if (!a5_dev_intf) {
+ CAM_ERR(CAM_ICP, "a5_dev_intf is invalid\n");
+ return -EINVAL;
+ }
+ a5_dev = (struct cam_hw_info *)a5_dev_intf->hw_priv;
+
+ hfi_mem.qtbl.kva = icp_hw_mgr.hfi_mem.qtbl.kva;
+ hfi_mem.qtbl.iova = icp_hw_mgr.hfi_mem.qtbl.iova;
+ hfi_mem.qtbl.len = icp_hw_mgr.hfi_mem.qtbl.len;
+ CAM_DBG(CAM_ICP, "kva = %llX IOVA = %X length = %lld\n",
+ hfi_mem.qtbl.kva, hfi_mem.qtbl.iova, hfi_mem.qtbl.len);
+
+ hfi_mem.cmd_q.kva = icp_hw_mgr.hfi_mem.cmd_q.kva;
+ hfi_mem.cmd_q.iova = icp_hw_mgr.hfi_mem.cmd_q.iova;
+ hfi_mem.cmd_q.len = icp_hw_mgr.hfi_mem.cmd_q.len;
+ CAM_DBG(CAM_ICP, "kva = %llX IOVA = %X length = %lld\n",
+ hfi_mem.cmd_q.kva, hfi_mem.cmd_q.iova, hfi_mem.cmd_q.len);
+
+ hfi_mem.msg_q.kva = icp_hw_mgr.hfi_mem.msg_q.kva;
+ hfi_mem.msg_q.iova = icp_hw_mgr.hfi_mem.msg_q.iova;
+ hfi_mem.msg_q.len = icp_hw_mgr.hfi_mem.msg_q.len;
+ CAM_DBG(CAM_ICP, "kva = %llX IOVA = %X length = %lld\n",
+ hfi_mem.msg_q.kva, hfi_mem.msg_q.iova, hfi_mem.msg_q.len);
+
+ hfi_mem.dbg_q.kva = icp_hw_mgr.hfi_mem.dbg_q.kva;
+ hfi_mem.dbg_q.iova = icp_hw_mgr.hfi_mem.dbg_q.iova;
+ hfi_mem.dbg_q.len = icp_hw_mgr.hfi_mem.dbg_q.len;
+ CAM_DBG(CAM_ICP, "kva = %llX IOVA = %X length = %lld\n",
+ hfi_mem.dbg_q.kva, hfi_mem.dbg_q.iova, hfi_mem.dbg_q.len);
+
+ hfi_mem.sec_heap.kva = icp_hw_mgr.hfi_mem.sec_heap.kva;
+ hfi_mem.sec_heap.iova = icp_hw_mgr.hfi_mem.sec_heap.iova;
+ hfi_mem.sec_heap.len = icp_hw_mgr.hfi_mem.sec_heap.len;
+
+ hfi_mem.shmem.iova = icp_hw_mgr.hfi_mem.shmem.iova_start;
+ hfi_mem.shmem.len = icp_hw_mgr.hfi_mem.shmem.iova_len;
+ return cam_hfi_resume(&hfi_mem,
+ a5_dev->soc_info.reg_map[A5_SIERRA_BASE].mem_base,
+ hw_mgr->a5_jtag_debug);
+}
+
+static int cam_icp_mgr_icp_resume(struct cam_icp_hw_mgr *hw_mgr)
+{
+ int rc = 0;
+ struct cam_hw_intf *a5_dev_intf = NULL;
+
+ CAM_DBG(CAM_ICP, "Enter");
+ a5_dev_intf = hw_mgr->devices[CAM_ICP_DEV_A5][0];
+
+ if (!a5_dev_intf) {
+ CAM_ERR(CAM_ICP, "a5 dev intf is wrong");
+ return -EINVAL;
+ }
+
+ rc = a5_dev_intf->hw_ops.init(a5_dev_intf->hw_priv, NULL, 0);
+ if (rc)
+ return -EINVAL;
+
+ rc = cam_icp_mgr_hfi_resume(hw_mgr);
+ if (rc)
+ goto hfi_resume_failed;
+
+ CAM_DBG(CAM_ICP, "Exit");
+ return rc;
+hfi_resume_failed:
+ cam_icp_mgr_icp_power_collapse(hw_mgr);
+ return rc;
+}
static int cam_icp_mgr_abort_handle(
struct cam_icp_hw_ctx_data *ctx_data)
{
@@ -1673,13 +1900,12 @@
return -EINVAL;
}
- mutex_lock(&hw_mgr->hw_mgr_mutex);
mutex_lock(&hw_mgr->ctx_data[ctx_id].ctx_mutex);
if (hw_mgr->ctx_data[ctx_id].state !=
CAM_ICP_CTX_STATE_ACQUIRED) {
mutex_unlock(&hw_mgr->ctx_data[ctx_id].ctx_mutex);
mutex_unlock(&hw_mgr->hw_mgr_mutex);
- CAM_WARN(CAM_ICP,
+ CAM_DBG(CAM_ICP,
"ctx with id: %d not in right state to release: %d",
ctx_id, hw_mgr->ctx_data[ctx_id].state);
return 0;
@@ -1704,7 +1930,6 @@
hw_mgr->ctx_data[ctx_id].icp_dev_acquire_info = NULL;
hw_mgr->ctx_data[ctx_id].state = CAM_ICP_CTX_STATE_FREE;
mutex_unlock(&hw_mgr->ctx_data[ctx_id].ctx_mutex);
- mutex_unlock(&hw_mgr->hw_mgr_mutex);
return 0;
}
@@ -1739,10 +1964,11 @@
struct cam_hw_intf *a5_dev_intf = NULL;
struct cam_icp_a5_set_irq_cb irq_cb;
struct cam_icp_a5_set_fw_buf_info fw_buf_info;
- int i, rc = 0;
+ int rc = 0;
+ CAM_DBG(CAM_ICP, "E");
mutex_lock(&hw_mgr->hw_mgr_mutex);
- if ((hw_mgr->fw_download == false) && (!hw_mgr->ctxt_cnt)) {
+ if (hw_mgr->fw_download == false) {
CAM_DBG(CAM_ICP, "hw mgr is already closed");
mutex_unlock(&hw_mgr->hw_mgr_mutex);
return 0;
@@ -1750,7 +1976,7 @@
a5_dev_intf = hw_mgr->devices[CAM_ICP_DEV_A5][0];
if (!a5_dev_intf) {
- CAM_ERR(CAM_ICP, "a5_dev_intf is NULL");
+ CAM_DBG(CAM_ICP, "a5_dev_intf is NULL");
mutex_unlock(&hw_mgr->hw_mgr_mutex);
return -EINVAL;
}
@@ -1765,14 +1991,8 @@
sizeof(fw_buf_info));
if (rc)
CAM_ERR(CAM_ICP, "nullify the fw buf failed");
- mutex_unlock(&hw_mgr->hw_mgr_mutex);
- for (i = 0; i < CAM_ICP_CTX_MAX; i++)
- cam_icp_mgr_release_ctx(hw_mgr, i);
-
- mutex_lock(&hw_mgr->hw_mgr_mutex);
cam_hfi_deinit();
- cam_icp_mgr_device_deinit(hw_mgr);
irq_cb.icp_hw_mgr_cb = NULL;
irq_cb.data = NULL;
@@ -2020,21 +2240,18 @@
goto fw_init_failed;
}
- rc = a5_dev_intf->hw_ops.process_cmd(
- a5_dev_intf->hw_priv,
- CAM_ICP_A5_CMD_POWER_COLLAPSE,
- NULL, 0);
- hw_mgr->fw_download = true;
hw_mgr->ctxt_cnt = 0;
- CAM_DBG(CAM_ICP, "FW download done successfully");
if (icp_hw_mgr.a5_debug_q)
hfi_set_debug_level(icp_hw_mgr.a5_dbg_lvl);
mutex_unlock(&hw_mgr->hw_mgr_mutex);
- if (!download_fw_args)
- cam_icp_mgr_hw_close(hw_mgr, NULL);
+ rc = cam_ipe_bps_deint(hw_mgr);
+ rc = cam_icp_mgr_icp_power_collapse(hw_mgr);
+
+ hw_mgr->fw_download = true;
+ CAM_DBG(CAM_ICP, "FW download done successfully");
return rc;
fw_init_failed:
@@ -2504,7 +2721,7 @@
ctx_data = release_hw->ctxt_to_hw_map;
if (!ctx_data) {
- CAM_ERR(CAM_ICP, "NULL ctx");
+ CAM_ERR(CAM_ICP, "NULL ctx data");
return -EINVAL;
}
@@ -2527,14 +2744,15 @@
cam_icp_mgr_send_abort_status(ctx_data);
}
+ mutex_lock(&hw_mgr->hw_mgr_mutex);
rc = cam_icp_mgr_release_ctx(hw_mgr, ctx_id);
if (!hw_mgr->ctxt_cnt) {
- cam_icp_mgr_ipe_bps_power_collapse(hw_mgr,
- NULL, 0);
- cam_icp_mgr_hw_close(hw_mgr, NULL);
+ CAM_DBG(CAM_ICP, "Last Release");
+ cam_icp_mgr_icp_power_collapse(hw_mgr);
cam_icp_hw_mgr_reset_clk_info(hw_mgr);
hw_mgr->secure_mode = CAM_SECURE_MODE_NON_SECURE;
}
+ mutex_unlock(&hw_mgr->hw_mgr_mutex);
return rc;
}
@@ -2676,8 +2894,10 @@
if (copy_from_user(&icp_dev_acquire_info,
(void __user *)args->acquire_info,
- sizeof(struct cam_icp_acquire_dev_info)))
+ sizeof(struct cam_icp_acquire_dev_info))) {
+ CAM_ERR(CAM_ICP, "Failed in acquire");
return -EFAULT;
+ }
if (icp_dev_acquire_info.secure_mode > CAM_SECURE_MODE_SECURE) {
CAM_ERR(CAM_ICP, "Invalid mode:%d",
@@ -2710,7 +2930,7 @@
}
acquire_size = sizeof(struct cam_icp_acquire_dev_info) +
- (icp_dev_acquire_info.num_out_res *
+ ((icp_dev_acquire_info.num_out_res - 1) *
sizeof(struct cam_icp_res_info));
ctx_data->icp_dev_acquire_info = kzalloc(acquire_size, GFP_KERNEL);
if (!ctx_data->icp_dev_acquire_info) {
@@ -2721,6 +2941,7 @@
if (copy_from_user(ctx_data->icp_dev_acquire_info,
(void __user *)args->acquire_info, acquire_size)) {
+ CAM_ERR(CAM_ICP, "Failed in acquire: size = %d", acquire_size);
if (!hw_mgr->ctxt_cnt)
hw_mgr->secure_mode = CAM_SECURE_MODE_NON_SECURE;
kfree(ctx_data->icp_dev_acquire_info);
@@ -2804,21 +3025,28 @@
mutex_lock(&hw_mgr->hw_mgr_mutex);
if (!hw_mgr->ctxt_cnt) {
- mutex_unlock(&hw_mgr->hw_mgr_mutex);
rc = cam_icp_clk_info_init(hw_mgr, ctx_data);
- if (rc)
+ if (rc) {
+ mutex_unlock(&hw_mgr->hw_mgr_mutex);
goto get_io_buf_failed;
- rc = cam_icp_mgr_hw_open(hw_mgr, ctx_data);
- if (rc)
+ }
+
+ rc = cam_icp_mgr_icp_resume(hw_mgr);
+ if (rc) {
+ mutex_unlock(&hw_mgr->hw_mgr_mutex);
goto get_io_buf_failed;
- rc = cam_icp_mgr_ipe_bps_resume(hw_mgr, ctx_data);
- if (rc)
- goto ipe_bps_resume_failed;
+ }
rc = cam_icp_send_ubwc_cfg(hw_mgr);
- if (rc)
+ if (rc) {
+ mutex_unlock(&hw_mgr->hw_mgr_mutex);
goto ubwc_cfg_failed;
- mutex_lock(&hw_mgr->hw_mgr_mutex);
+ }
+ }
+ rc = cam_icp_mgr_ipe_bps_resume(hw_mgr, ctx_data);
+ if (rc) {
+ mutex_unlock(&hw_mgr->hw_mgr_mutex);
+ goto ipe_bps_resume_failed;
}
mutex_unlock(&hw_mgr->hw_mgr_mutex);
@@ -2827,6 +3055,7 @@
CAM_ERR(CAM_ICP, "ping ack not received");
goto send_ping_failed;
}
+ CAM_DBG(CAM_ICP, "ping ack received");
rc = cam_icp_mgr_create_handle(icp_dev_acquire_info->dev_type,
ctx_data);
@@ -2866,6 +3095,7 @@
mutex_lock(&hw_mgr->hw_mgr_mutex);
hw_mgr->ctxt_cnt++;
mutex_unlock(&hw_mgr->hw_mgr_mutex);
+ CAM_DBG(CAM_ICP, "Acquire Done");
return 0;
@@ -2876,11 +3106,11 @@
cam_icp_mgr_destroy_handle(ctx_data);
create_handle_failed:
send_ping_failed:
-ubwc_cfg_failed:
cam_icp_mgr_ipe_bps_power_collapse(hw_mgr, ctx_data, 0);
ipe_bps_resume_failed:
+ubwc_cfg_failed:
if (!hw_mgr->ctxt_cnt)
- cam_icp_mgr_hw_close(hw_mgr, NULL);
+ cam_icp_mgr_icp_power_collapse(hw_mgr);
get_io_buf_failed:
kfree(hw_mgr->ctx_data[ctx_id].icp_dev_acquire_info);
hw_mgr->ctx_data[ctx_id].icp_dev_acquire_info = NULL;
diff --git a/drivers/media/platform/msm/camera/cam_icp/icp_hw/icp_hw_mgr/cam_icp_hw_mgr.h b/drivers/media/platform/msm/camera/cam_icp/icp_hw/icp_hw_mgr/cam_icp_hw_mgr.h
index ab19f45..e8919e8 100644
--- a/drivers/media/platform/msm/camera/cam_icp/icp_hw/icp_hw_mgr/cam_icp_hw_mgr.h
+++ b/drivers/media/platform/msm/camera/cam_icp/icp_hw/icp_hw_mgr/cam_icp_hw_mgr.h
@@ -252,6 +252,7 @@
* @ipe0_enable: Flag for IPE0
* @ipe1_enable: Flag for IPE1
* @bps_enable: Flag for BPS
+ * @core_info: 32 bit value , tells IPE0/1 and BPS
*/
struct cam_icp_hw_mgr {
struct mutex hw_mgr_mutex;
@@ -288,9 +289,11 @@
bool ipe0_enable;
bool ipe1_enable;
bool bps_enable;
+ uint32_t core_info;
};
static int cam_icp_mgr_hw_close(void *hw_priv, void *hw_close_args);
static int cam_icp_mgr_hw_open(void *hw_mgr_priv, void *download_fw_args);
-
+static int cam_icp_mgr_icp_resume(struct cam_icp_hw_mgr *hw_mgr);
+static int cam_icp_mgr_icp_power_collapse(struct cam_icp_hw_mgr *hw_mgr);
#endif /* CAM_ICP_HW_MGR_H */
diff --git a/drivers/media/platform/msm/camera/cam_icp/icp_hw/icp_hw_mgr/include/cam_a5_hw_intf.h b/drivers/media/platform/msm/camera/cam_icp/icp_hw/icp_hw_mgr/include/cam_a5_hw_intf.h
index dad7736..fd0482c 100644
--- a/drivers/media/platform/msm/camera/cam_icp/icp_hw/icp_hw_mgr/include/cam_a5_hw_intf.h
+++ b/drivers/media/platform/msm/camera/cam_icp/icp_hw/icp_hw_mgr/include/cam_a5_hw_intf.h
@@ -32,6 +32,7 @@
CAM_ICP_A5_CMD_CPAS_START,
CAM_ICP_A5_CMD_CPAS_STOP,
CAM_ICP_A5_CMD_UBWC_CFG,
+ CAM_ICP_A5_CMD_PC_PREP,
CAM_ICP_A5_CMD_MAX,
};
diff --git a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c
index d407771..ccab3a0 100644
--- a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c
+++ b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c
@@ -1008,8 +1008,7 @@
rc = cam_ife_hw_mgr_get_res(&ife_ctx->free_res_list,
&csid_res);
if (rc) {
- CAM_ERR(CAM_ISP, "No more free hw mgr resource",
- __func__);
+ CAM_ERR(CAM_ISP, "No more free hw mgr resource");
goto err;
}
cam_ife_hw_mgr_put_res(&ife_ctx->res_list_ife_csid, &csid_res);
@@ -1987,6 +1986,7 @@
struct cam_hw_release_args *release_args = release_hw_args;
struct cam_ife_hw_mgr *hw_mgr = hw_mgr_priv;
struct cam_ife_hw_mgr_ctx *ctx;
+ uint32_t i;
if (!hw_mgr_priv || !release_hw_args) {
CAM_ERR(CAM_ISP, "Invalid arguments");
@@ -2015,6 +2015,15 @@
/* clean context */
list_del_init(&ctx->list);
ctx->ctx_in_use = 0;
+ ctx->is_rdi_only_context = 0;
+ ctx->cdm_handle = 0;
+ ctx->cdm_ops = NULL;
+ atomic_set(&ctx->overflow_pending, 0);
+ for (i = 0; i < CAM_IFE_HW_NUM_MAX; i++) {
+ ctx->sof_cnt[i] = 0;
+ ctx->eof_cnt[i] = 0;
+ ctx->epoch_cnt[i] = 0;
+ }
CAM_DBG(CAM_ISP, "Exit...ctx id:%d",
ctx->ctx_index);
cam_ife_hw_mgr_put_ctx(&hw_mgr->free_ctx_list, &ctx);
@@ -2761,8 +2770,7 @@
CAM_DBG(CAM_ISP, "Enter");
if (!recovery_data) {
- CAM_ERR(CAM_ISP, "recovery_data parameter is NULL",
- __func__);
+ CAM_ERR(CAM_ISP, "recovery_data parameter is NULL");
return -EINVAL;
}
recovery_data->no_of_context = 0;
diff --git a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/hw_utils/irq_controller/cam_irq_controller.c b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/hw_utils/irq_controller/cam_irq_controller.c
index 44dc5c4..031b7b2 100644
--- a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/hw_utils/irq_controller/cam_irq_controller.c
+++ b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/hw_utils/irq_controller/cam_irq_controller.c
@@ -88,7 +88,7 @@
* @th_list_head: List of handlers sorted by priority
* @hdl_idx: Unique identity of handler assigned on Subscribe.
* Used to Unsubscribe.
- * @rw_lock: Read-Write Lock for use by controller
+ * @lock: Lock for use by controller
*/
struct cam_irq_controller {
const char *name;
@@ -101,7 +101,7 @@
struct list_head evt_handler_list_head;
struct list_head th_list_head[CAM_IRQ_PRIORITY_MAX];
uint32_t hdl_idx;
- rwlock_t rw_lock;
+ spinlock_t lock;
struct cam_irq_th_payload th_payload;
};
@@ -208,7 +208,7 @@
for (i = 0; i < CAM_IRQ_PRIORITY_MAX; i++)
INIT_LIST_HEAD(&controller->th_list_head[i]);
- rwlock_init(&controller->rw_lock);
+ spin_lock_init(&controller->lock);
controller->hdl_idx = 1;
*irq_controller = controller;
@@ -304,7 +304,7 @@
need_lock = !in_irq();
if (need_lock)
- write_lock_irqsave(&controller->rw_lock, flags);
+ spin_lock_irqsave(&controller->lock, flags);
for (i = 0; i < controller->num_registers; i++) {
controller->irq_register_arr[i].top_half_enable_mask[priority]
|= evt_bit_mask_arr[i];
@@ -316,14 +316,15 @@
cam_io_w_mb(irq_mask, controller->mem_base +
controller->irq_register_arr[i].mask_reg_offset);
}
- if (need_lock)
- write_unlock_irqrestore(&controller->rw_lock, flags);
list_add_tail(&evt_handler->list_node,
&controller->evt_handler_list_head);
list_add_tail(&evt_handler->th_list_node,
&controller->th_list_head[priority]);
+ if (need_lock)
+ spin_unlock_irqrestore(&controller->lock, flags);
+
return evt_handler->index;
free_evt_handler:
@@ -348,6 +349,10 @@
if (!controller)
return rc;
+ need_lock = !in_irq();
+ if (need_lock)
+ spin_lock_irqsave(&controller->lock, flags);
+
list_for_each_entry_safe(evt_handler, evt_handler_temp,
&controller->evt_handler_list_head, list_node) {
if (evt_handler->index == handle) {
@@ -358,12 +363,12 @@
}
}
- if (!found)
+ if (!found) {
+ if (need_lock)
+ spin_unlock_irqrestore(&controller->lock, flags);
return rc;
+ }
- need_lock = !in_irq();
- if (need_lock)
- write_lock_irqsave(&controller->rw_lock, flags);
for (i = 0; i < controller->num_registers; i++) {
controller->irq_register_arr[i].
top_half_enable_mask[evt_handler->priority] |=
@@ -378,7 +383,7 @@
controller->irq_register_arr[i].mask_reg_offset);
}
if (need_lock)
- write_unlock_irqrestore(&controller->rw_lock, flags);
+ spin_unlock_irqrestore(&controller->lock, flags);
return rc;
}
@@ -398,6 +403,10 @@
if (!controller)
return rc;
+ need_lock = !in_irq();
+ if (need_lock)
+ spin_lock_irqsave(&controller->lock, flags);
+
list_for_each_entry_safe(evt_handler, evt_handler_temp,
&controller->evt_handler_list_head, list_node) {
if (evt_handler->index == handle) {
@@ -408,12 +417,12 @@
}
}
- if (!found)
+ if (!found) {
+ if (need_lock)
+ spin_unlock_irqrestore(&controller->lock, flags);
return rc;
+ }
- need_lock = !in_irq();
- if (need_lock)
- write_lock_irqsave(&controller->rw_lock, flags);
for (i = 0; i < controller->num_registers; i++) {
controller->irq_register_arr[i].
top_half_enable_mask[evt_handler->priority] &=
@@ -441,7 +450,7 @@
controller->global_clear_offset);
}
if (need_lock)
- write_unlock_irqrestore(&controller->rw_lock, flags);
+ spin_unlock_irqrestore(&controller->lock, flags);
return rc;
}
@@ -459,6 +468,10 @@
int rc = -EINVAL;
bool need_lock;
+ need_lock = !in_irq();
+ if (need_lock)
+ spin_lock_irqsave(&controller->lock, flags);
+
list_for_each_entry_safe(evt_handler, evt_handler_temp,
&controller->evt_handler_list_head, list_node) {
if (evt_handler->index == handle) {
@@ -471,11 +484,7 @@
}
}
- need_lock = !in_irq();
-
if (found) {
- if (need_lock)
- write_lock_irqsave(&controller->rw_lock, flags);
for (i = 0; i < controller->num_registers; i++) {
controller->irq_register_arr[i].
top_half_enable_mask[evt_handler->priority] &=
@@ -501,13 +510,14 @@
controller->mem_base +
controller->global_clear_offset);
}
- if (need_lock)
- write_unlock_irqrestore(&controller->rw_lock, flags);
kfree(evt_handler->evt_bit_mask_arr);
kfree(evt_handler);
}
+ if (need_lock)
+ spin_unlock_irqrestore(&controller->lock, flags);
+
return rc;
}
@@ -607,9 +617,9 @@
if (!controller)
return IRQ_NONE;
- CAM_DBG(CAM_ISP, "locking controller %pK name %s rw_lock %pK",
- controller, controller->name, &controller->rw_lock);
- read_lock(&controller->rw_lock);
+ CAM_DBG(CAM_ISP, "locking controller %pK name %s lock %pK",
+ controller, controller->name, &controller->lock);
+ spin_lock(&controller->lock);
for (i = 0; i < controller->num_registers; i++) {
controller->irq_status_arr[i] = cam_io_r_mb(
controller->mem_base +
@@ -630,8 +640,6 @@
i, j, need_th_processing[j]);
}
}
- CAM_DBG(CAM_ISP, "unlocked controller %pK name %s rw_lock %pK",
- controller, controller->name, &controller->rw_lock);
CAM_DBG(CAM_ISP, "Status Registers read Successful");
@@ -648,7 +656,9 @@
&controller->th_list_head[i]);
}
}
- read_unlock(&controller->rw_lock);
+ spin_unlock(&controller->lock);
+ CAM_DBG(CAM_ISP, "unlocked controller %pK name %s lock %pK",
+ controller, controller->name, &controller->lock);
return IRQ_HANDLED;
}
diff --git a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.c b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.c
index daf515a..70c9c3b 100644
--- a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.c
+++ b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.c
@@ -1497,9 +1497,9 @@
struct cam_isp_resource_node *res)
{
int rc = 0;
+ uint32_t val = 0;
struct cam_ife_csid_reg_offset *csid_reg;
struct cam_hw_soc_info *soc_info;
- uint32_t val = 0;
csid_reg = csid_hw->csid_info->csid_reg;
soc_info = &csid_hw->hw_info->soc_info;
@@ -1596,10 +1596,10 @@
enum cam_ife_csid_halt_cmd stop_cmd)
{
int rc = 0;
+ uint32_t val = 0;
struct cam_ife_csid_reg_offset *csid_reg;
struct cam_hw_soc_info *soc_info;
struct cam_ife_csid_path_cfg *path_data;
- uint32_t val = 0;
path_data = (struct cam_ife_csid_path_cfg *) res->res_priv;
csid_reg = csid_hw->csid_info->csid_reg;
@@ -1656,21 +1656,6 @@
/* For slave mode, halt command should take it from master */
- /* Enable the EOF interrupt for resume at boundary case */
- if (stop_cmd != CAM_CSID_HALT_IMMEDIATELY) {
- init_completion(&csid_hw->csid_ipp_complete);
- val = cam_io_r_mb(soc_info->reg_map[0].mem_base +
- csid_reg->ipp_reg->csid_ipp_irq_mask_addr);
- val |= CSID_PATH_INFO_INPUT_EOF;
- cam_io_w_mb(val, soc_info->reg_map[0].mem_base +
- csid_reg->ipp_reg->csid_ipp_irq_mask_addr);
- } else {
- val &= ~(CSID_PATH_INFO_RST_DONE |
- CSID_PATH_ERROR_FIFO_OVERFLOW);
- cam_io_w_mb(val, soc_info->reg_map[0].mem_base +
- csid_reg->ipp_reg->csid_ipp_irq_mask_addr);
- }
-
return rc;
}
@@ -1811,9 +1796,9 @@
struct cam_isp_resource_node *res)
{
int rc = 0;
+ uint32_t val = 0, id;
struct cam_ife_csid_reg_offset *csid_reg;
struct cam_hw_soc_info *soc_info;
- uint32_t val = 0, id;
csid_reg = csid_hw->csid_info->csid_reg;
soc_info = &csid_hw->hw_info->soc_info;
@@ -1889,9 +1874,9 @@
enum cam_ife_csid_halt_cmd stop_cmd)
{
int rc = 0;
+ uint32_t id;
struct cam_ife_csid_reg_offset *csid_reg;
struct cam_hw_soc_info *soc_info;
- uint32_t val = 0, id;
csid_reg = csid_hw->csid_info->csid_reg;
soc_info = &csid_hw->hw_info->soc_info;
@@ -1926,25 +1911,9 @@
return -EINVAL;
}
-
CAM_DBG(CAM_ISP, "CSID:%d res_id:%d",
csid_hw->hw_intf->hw_idx, res->res_id);
- init_completion(&csid_hw->csid_rdin_complete[id]);
-
- if (stop_cmd != CAM_CSID_HALT_IMMEDIATELY) {
- val = cam_io_r_mb(soc_info->reg_map[0].mem_base +
- csid_reg->rdi_reg[id]->csid_rdi_irq_mask_addr);
- val |= CSID_PATH_INFO_INPUT_EOF;
- cam_io_w_mb(val, soc_info->reg_map[0].mem_base +
- csid_reg->rdi_reg[id]->csid_rdi_irq_mask_addr);
- } else {
- val &= ~(CSID_PATH_INFO_RST_DONE |
- CSID_PATH_ERROR_FIFO_OVERFLOW);
- cam_io_w_mb(val, soc_info->reg_map[0].mem_base +
- csid_reg->rdi_reg[id]->csid_rdi_irq_mask_addr);
- }
-
/*Halt the RDI path */
cam_io_w_mb(stop_cmd, soc_info->reg_map[0].mem_base +
csid_reg->rdi_reg[id]->csid_rdi_ctrl_addr);
@@ -2029,12 +1998,10 @@
struct cam_isp_resource_node *res)
{
int rc = 0;
+ uint32_t val = 0, id, status, path_status_reg;
struct cam_ife_csid_reg_offset *csid_reg;
struct cam_hw_soc_info *soc_info;
- struct completion *complete;
- uint32_t val = 0, id;
-
csid_reg = csid_hw->csid_info->csid_reg;
soc_info = &csid_hw->hw_info->soc_info;
@@ -2060,19 +2027,19 @@
}
if (res->res_id == CAM_IFE_PIX_PATH_RES_IPP)
- complete = &csid_hw->csid_ipp_complete;
+ path_status_reg = csid_reg->ipp_reg->csid_ipp_status_addr;
else
- complete = &csid_hw->csid_rdin_complete[res->res_id];
+ path_status_reg = csid_reg->rdi_reg[res->res_id]->
+ csid_rdi_status_addr;
- rc = wait_for_completion_timeout(complete,
- msecs_to_jiffies(IFE_CSID_TIMEOUT));
- if (rc <= 0) {
- CAM_ERR(CAM_ISP, "CSID%d stop at frame boundary failid:%drc:%d",
- csid_hw->hw_intf->hw_idx,
- res->res_id, rc);
- if (rc == 0)
- /* continue even have timeout */
- rc = -ETIMEDOUT;
+ rc = readl_poll_timeout(soc_info->reg_map[0].mem_base +
+ path_status_reg, status,
+ (status == 1),
+ CAM_IFE_CSID_TIMEOUT_SLEEP_US, CAM_IFE_CSID_TIMEOUT_ALL_US);
+ if (rc < 0) {
+ CAM_ERR(CAM_ISP, "Time out: Res id:%d Path has not halted",
+ res->res_id);
+ rc = -ETIMEDOUT;
}
/* Disable the interrupt */
@@ -2778,7 +2745,8 @@
val = cam_io_r_mb(soc_info->reg_map[0].mem_base +
csid_reg->csi2_reg->
csid_csi2_rx_captured_short_pkt_1_addr);
- CAM_ERR(CAM_ISP, "CSID:%d short packet ECC :%d", val);
+ CAM_ERR(CAM_ISP, "CSID:%d short packet ECC :%d",
+ csid_hw->hw_intf->hw_idx, val);
}
if ((csid_hw->csid_debug & CSID_DEBUG_ENABLE_CPHY_PKT_CAPTURE) &&
@@ -2812,9 +2780,6 @@
CAM_ERR(CAM_ISP, "CSID:%d IPP EOF received",
csid_hw->hw_intf->hw_idx);
- if (irq_status_ipp & CSID_PATH_INFO_INPUT_EOF)
- complete(&csid_hw->csid_ipp_complete);
-
if (irq_status_ipp & CSID_PATH_ERROR_FIFO_OVERFLOW) {
CAM_ERR(CAM_ISP, "CSID:%d IPP fifo over flow",
csid_hw->hw_intf->hw_idx);
@@ -2840,9 +2805,6 @@
(csid_hw->csid_debug & CSID_DEBUG_ENABLE_EOF_IRQ))
CAM_ERR(CAM_ISP, "CSID RDI:%d EOF received", i);
- if (irq_status_rdi[i] & CSID_PATH_INFO_INPUT_EOF)
- complete(&csid_hw->csid_rdin_complete[i]);
-
if (irq_status_rdi[i] & CSID_PATH_ERROR_FIFO_OVERFLOW) {
CAM_ERR(CAM_ISP, "CSID:%d RDI fifo over flow",
csid_hw->hw_intf->hw_idx);
diff --git a/drivers/media/platform/msm/camera/cam_jpeg/jpeg_hw/jpeg_dma_hw/jpeg_dma_dev.c b/drivers/media/platform/msm/camera/cam_jpeg/jpeg_hw/jpeg_dma_hw/jpeg_dma_dev.c
index ed58b41..05ae7cc 100644
--- a/drivers/media/platform/msm/camera/cam_jpeg/jpeg_hw/jpeg_dma_hw/jpeg_dma_dev.c
+++ b/drivers/media/platform/msm/camera/cam_jpeg/jpeg_hw/jpeg_dma_hw/jpeg_dma_dev.c
@@ -172,7 +172,7 @@
cam_jpeg_dma_irq,
jpeg_dma_dev);
if (rc) {
- CAM_ERR(CAM_JPEG, "%failed to init_soc %d", rc);
+ CAM_ERR(CAM_JPEG, "failed to init_soc %d", rc);
goto error_init_soc;
}
diff --git a/drivers/media/platform/msm/camera/cam_req_mgr/cam_mem_mgr.c b/drivers/media/platform/msm/camera/cam_req_mgr/cam_mem_mgr.c
index 6ad0934..9689698 100644
--- a/drivers/media/platform/msm/camera/cam_req_mgr/cam_mem_mgr.c
+++ b/drivers/media/platform/msm/camera/cam_req_mgr/cam_mem_mgr.c
@@ -768,7 +768,10 @@
}
mutex_lock(&tbl.bufq[i].q_lock);
- ion_free(tbl.client, tbl.bufq[i].i_hdl);
+ if (tbl.bufq[i].i_hdl) {
+ ion_free(tbl.client, tbl.bufq[i].i_hdl);
+ tbl.bufq[i].i_hdl = NULL;
+ }
tbl.bufq[i].fd = -1;
tbl.bufq[i].flags = 0;
tbl.bufq[i].buf_handle = -1;
@@ -813,7 +816,17 @@
return -EINVAL;
}
- CAM_DBG(CAM_CRM, "Flags = %X", tbl.bufq[idx].flags);
+ CAM_DBG(CAM_CRM, "Flags = %X idx %d", tbl.bufq[idx].flags, idx);
+
+ mutex_lock(&tbl.m_lock);
+ if ((!tbl.bufq[idx].active) &&
+ (tbl.bufq[idx].vaddr) == 0) {
+ CAM_WARN(CAM_CRM, "Buffer at idx=%d is already unmapped,",
+ idx);
+ mutex_unlock(&tbl.m_lock);
+ return 0;
+ }
+
if (tbl.bufq[idx].flags & CAM_MEM_FLAG_KMD_ACCESS)
if (tbl.bufq[idx].i_hdl && tbl.bufq[idx].kmdvaddr)
@@ -856,8 +869,11 @@
tbl.bufq[idx].is_imported = false;
tbl.bufq[idx].len = 0;
tbl.bufq[idx].num_hdl = 0;
+ tbl.bufq[idx].active = false;
mutex_unlock(&tbl.bufq[idx].q_lock);
- cam_mem_put_slot(idx);
+ mutex_destroy(&tbl.bufq[idx].q_lock);
+ clear_bit(idx, tbl.bitmap);
+ mutex_unlock(&tbl.m_lock);
return rc;
}
@@ -1043,6 +1059,10 @@
}
if (!tbl.bufq[idx].active) {
+ if (tbl.bufq[idx].vaddr == 0) {
+ CAM_ERR(CAM_CRM, "buffer is released already");
+ return 0;
+ }
CAM_ERR(CAM_CRM, "Released buffer state should be active");
return -EINVAL;
}
@@ -1184,6 +1204,10 @@
}
if (!tbl.bufq[idx].active) {
+ if (tbl.bufq[idx].vaddr == 0) {
+ CAM_ERR(CAM_CRM, "buffer is released already");
+ return 0;
+ }
CAM_ERR(CAM_CRM, "Released buffer state should be active");
return -EINVAL;
}
diff --git a/drivers/media/platform/msm/camera/cam_req_mgr/cam_req_mgr_core.c b/drivers/media/platform/msm/camera/cam_req_mgr/cam_req_mgr_core.c
index d7a382f..784e90b 100644
--- a/drivers/media/platform/msm/camera/cam_req_mgr/cam_req_mgr_core.c
+++ b/drivers/media/platform/msm/camera/cam_req_mgr/cam_req_mgr_core.c
@@ -25,23 +25,6 @@
static struct cam_req_mgr_core_device *g_crm_core_dev;
-
-void cam_req_mgr_handle_core_shutdown(void)
-{
- struct cam_req_mgr_core_session *session;
- struct cam_req_mgr_core_session *tsession;
- struct cam_req_mgr_session_info ses_info;
-
- if (!list_empty(&g_crm_core_dev->session_head)) {
- list_for_each_entry_safe(session, tsession,
- &g_crm_core_dev->session_head, entry) {
- ses_info.session_hdl =
- session->session_hdl;
- cam_req_mgr_destroy_session(&ses_info);
- }
- }
-}
-
static int __cam_req_mgr_setup_payload(struct cam_req_mgr_core_workq *workq)
{
int32_t i = 0;
@@ -202,11 +185,18 @@
if (tbl->inject_delay > 0 && (traverse_data->validate_only == false)) {
CAM_DBG(CAM_CRM, "Injecting Delay of one frame");
- apply_data[tbl->pd].req_id = -1;
tbl->inject_delay--;
/* This pd table is not ready to proceed with asked idx */
SET_FAILURE_BIT(traverse_data->result, tbl->pd);
- return -EAGAIN;
+ apply_data[tbl->pd].req_id = -1;
+ if (tbl->next) {
+ __cam_req_mgr_dec_idx(&next_idx, tbl->pd_delta,
+ tbl->num_slots);
+ traverse_data->idx = next_idx;
+ traverse_data->tbl = tbl->next;
+ rc = __cam_req_mgr_traverse(traverse_data);
+ }
+ return rc;
}
/* Check if req is ready or in skip mode or pd tbl is in skip mode */
@@ -241,8 +231,20 @@
}
} else {
/* This pd table is not ready to proceed with asked idx */
- SET_FAILURE_BIT(traverse_data->result, tbl->pd);
- return -EAGAIN;
+ if (tbl->slot[curr_idx].state == CRM_REQ_STATE_APPLIED)
+ SET_SUCCESS_BIT(traverse_data->result, tbl->pd);
+ else
+ SET_FAILURE_BIT(traverse_data->result, tbl->pd);
+
+ apply_data[tbl->pd].req_id = -1;
+ if (tbl->next) {
+ __cam_req_mgr_dec_idx(&next_idx, tbl->pd_delta,
+ tbl->num_slots);
+ traverse_data->idx = next_idx;
+ traverse_data->tbl = tbl->next;
+ rc = __cam_req_mgr_traverse(traverse_data);
+ }
+ return rc;
}
return 0;
}
@@ -472,12 +474,14 @@
* traversed through
* @idx : index within input request queue
* @validate_only : Whether to validate only and/or update settings
+ * @result : Holds the value that indicates which of the pd
+ * tables have a req that is ready to be applied
*
* @return : 0 for success, negative for failure
*
*/
static int __cam_req_mgr_check_link_is_ready(struct cam_req_mgr_core_link *link,
- int32_t idx, bool validate_only)
+ int32_t idx, bool validate_only, int *result)
{
int rc;
struct cam_req_mgr_traverse traverse_data;
@@ -508,15 +512,18 @@
CAM_DBG(CAM_CRM, "SOF: idx %d result %x pd_mask %x rc %d",
idx, traverse_data.result, link->pd_mask, rc);
- if (!rc && traverse_data.result == link->pd_mask) {
+ if (!traverse_data.result)
+ return -EAGAIN;
+
+ if (!rc) {
CAM_DBG(CAM_CRM,
"APPLY: link_hdl= %x idx= %d, req_id= %lld :%lld :%lld",
link->link_hdl, idx,
apply_data[2].req_id, apply_data[1].req_id,
apply_data[0].req_id);
- } else
- rc = -EAGAIN;
+ }
+ *result = traverse_data.result;
return rc;
}
@@ -645,12 +652,16 @@
* @link : pointer to link whose input queue and req tbl are
* traversed through
* @slot : pointer to the current slot being processed
+ * @result : Holds the value that indicates which of the pd
+ * tables have a req that is ready to be applied
+ *
* @return : 0 for success, negative for failure
*
*/
static int __cam_req_mgr_process_sync_req(
struct cam_req_mgr_core_link *link,
- struct cam_req_mgr_slot *slot)
+ struct cam_req_mgr_slot *slot,
+ int *result)
{
struct cam_req_mgr_core_link *sync_link = NULL;
int64_t req_id = 0;
@@ -675,7 +686,7 @@
link->sof_counter++;
}
- rc = __cam_req_mgr_check_link_is_ready(link, slot->idx, true);
+ rc = __cam_req_mgr_check_link_is_ready(link, slot->idx, true, result);
if (rc) {
CAM_DBG(CAM_CRM,
"Req: %lld [My link]not available link: %x, rc=%d",
@@ -687,7 +698,7 @@
sync_link->req.in_q, req_id);
if (sync_slot_idx != -1) {
rc = __cam_req_mgr_check_link_is_ready(
- sync_link, sync_slot_idx, true);
+ sync_link, sync_slot_idx, true, result);
CAM_DBG(CAM_CRM, "sync_slot_idx=%d, status=%d, rc=%d",
sync_slot_idx,
sync_link->req.in_q->slot[sync_slot_idx].status,
@@ -698,8 +709,8 @@
}
if ((sync_slot_idx != -1) &&
- ((sync_link->req.in_q->slot[sync_slot_idx].status ==
- CRM_SLOT_STATUS_REQ_APPLIED) || (rc == 0))) {
+ ((sync_link->req.in_q->slot[sync_slot_idx].status ==
+ CRM_SLOT_STATUS_REQ_APPLIED) || (rc == 0))) {
rc = __cam_req_mgr_validate_sof_cnt(link, sync_link);
if (rc) {
CAM_DBG(CAM_CRM,
@@ -707,7 +718,8 @@
req_id, sync_link->link_hdl);
goto failure;
}
- __cam_req_mgr_check_link_is_ready(link, slot->idx, false);
+ __cam_req_mgr_check_link_is_ready(link, slot->idx, false,
+ result);
} else {
CAM_DBG(CAM_CRM,
"Req: %lld [Other link] not ready to apply on link: %x",
@@ -724,6 +736,41 @@
}
/**
+ * __cam_req_mgr_reset_pd_tables()
+ *
+ * @brief : resets pd tables based on req getting applied on
+ * from a particular pd table
+ * @link : pointer to link whose input queue and req tbl are
+ * traversed through
+ * @slot : Pointer to the current slot
+ * @result : indicates request of which pd table was successfully
+ * processed
+ *
+ */
+static void __cam_req_mgr_reset_pd_tables(
+ struct cam_req_mgr_core_link *link,
+ struct cam_req_mgr_slot *slot,
+ int result)
+{
+ int pd_set_bit = 0;
+ int curr_idx = slot->idx;
+ int no_tables = link->req.num_tbl;
+ int max_pd_delay = link->max_delay;
+ struct cam_req_mgr_req_tbl *tbl = link->req.l_tbl;
+ struct cam_req_mgr_req_queue *in_q = link->req.in_q;
+
+ while (no_tables) {
+ pd_set_bit = (result & (1 << max_pd_delay));
+ if (pd_set_bit)
+ tbl->slot[curr_idx].state = CRM_REQ_STATE_APPLIED;
+ max_pd_delay--;
+ no_tables--;
+ tbl = tbl->next;
+ __cam_req_mgr_dec_idx(&curr_idx, 1, in_q->num_slots);
+ }
+}
+
+/**
* __cam_req_mgr_process_req()
*
* @brief : processes read index in request queue and traverse through table
@@ -736,7 +783,7 @@
static int __cam_req_mgr_process_req(struct cam_req_mgr_core_link *link,
uint32_t trigger)
{
- int rc = 0, idx;
+ int rc = 0, idx, result = 0;
struct cam_req_mgr_slot *slot = NULL;
struct cam_req_mgr_req_queue *in_q;
struct cam_req_mgr_core_session *session;
@@ -782,10 +829,11 @@
}
if (slot->sync_mode == CAM_REQ_MGR_SYNC_MODE_SYNC)
- rc = __cam_req_mgr_process_sync_req(link, slot);
+ rc = __cam_req_mgr_process_sync_req(link, slot,
+ &result);
else
rc = __cam_req_mgr_check_link_is_ready(link,
- slot->idx, false);
+ slot->idx, false, &result);
if (rc < 0) {
/*
@@ -830,16 +878,25 @@
spin_unlock_bh(&link->link_state_spin_lock);
if (link->trigger_mask == link->subscribe_event) {
- slot->status = CRM_SLOT_STATUS_REQ_APPLIED;
+ if (result == link->pd_mask) {
+ slot->status = CRM_SLOT_STATUS_REQ_APPLIED;
+ CAM_DBG(CAM_CRM, "req %d is applied on link %d",
+ slot->req_id, link->link_hdl);
+ idx = in_q->rd_idx;
+ __cam_req_mgr_dec_idx(
+ &idx, link->max_delay + 1,
+ in_q->num_slots);
+ __cam_req_mgr_reset_req_slot(link, idx);
+ } else {
+ CAM_DBG(CAM_CRM,
+ "Req:%lld not applied on all devices",
+ slot->req_id);
+ __cam_req_mgr_reset_pd_tables(link, slot,
+ result);
+ slot->status = CRM_SLOT_STATUS_REQ_PENDING;
+ }
+
link->trigger_mask = 0;
- CAM_DBG(CAM_CRM, "req %d is applied on link %d",
- slot->req_id,
- link->link_hdl);
- idx = in_q->rd_idx;
- __cam_req_mgr_dec_idx(
- &idx, link->max_delay + 1,
- in_q->num_slots);
- __cam_req_mgr_reset_req_slot(link, idx);
}
}
mutex_unlock(&session->lock);
@@ -2028,6 +2085,22 @@
return rc;
}
+void cam_req_mgr_handle_core_shutdown(void)
+{
+ struct cam_req_mgr_core_session *session;
+ struct cam_req_mgr_core_session *tsession;
+ struct cam_req_mgr_session_info ses_info;
+
+ if (!list_empty(&g_crm_core_dev->session_head)) {
+ list_for_each_entry_safe(session, tsession,
+ &g_crm_core_dev->session_head, entry) {
+ ses_info.session_hdl =
+ session->session_hdl;
+ cam_req_mgr_destroy_session(&ses_info);
+ }
+ }
+}
+
/* IOCTLs handling section */
int cam_req_mgr_create_session(
struct cam_req_mgr_session_info *ses_info)
@@ -2314,21 +2387,23 @@
if (!sched_req) {
CAM_ERR(CAM_CRM, "csl_req is NULL");
- rc = -EINVAL;
- goto end;
+ return -EINVAL;
}
+ mutex_lock(&g_crm_core_dev->crm_lock);
link = (struct cam_req_mgr_core_link *)
cam_get_device_priv(sched_req->link_hdl);
if (!link) {
CAM_DBG(CAM_CRM, "link ptr NULL %x", sched_req->link_hdl);
- return -EINVAL;
+ rc = -EINVAL;
+ goto end;
}
session = (struct cam_req_mgr_core_session *)link->parent;
if (!session) {
CAM_WARN(CAM_CRM, "session ptr NULL %x", sched_req->link_hdl);
- return -EINVAL;
+ rc = -EINVAL;
+ goto end;
}
CAM_DBG(CAM_CRM, "link %x req %lld, sync_mode %d",
@@ -2351,6 +2426,7 @@
CAM_DBG(CAM_CRM, "DONE dev %x req %lld sync_mode %d",
sched_req->link_hdl, sched_req->req_id, sched_req->sync_mode);
end:
+ mutex_unlock(&g_crm_core_dev->crm_lock);
return rc;
}
@@ -2373,11 +2449,13 @@
return -EINVAL;
}
+ mutex_lock(&g_crm_core_dev->crm_lock);
/* session hdl's priv data is cam session struct */
cam_session = (struct cam_req_mgr_core_session *)
cam_get_device_priv(sync_info->session_hdl);
if (!cam_session) {
CAM_ERR(CAM_CRM, "NULL pointer");
+ mutex_unlock(&g_crm_core_dev->crm_lock);
return -EINVAL;
}
@@ -2414,6 +2492,7 @@
done:
mutex_unlock(&cam_session->lock);
+ mutex_unlock(&g_crm_core_dev->crm_lock);
return rc;
}
@@ -2439,6 +2518,7 @@
goto end;
}
+ mutex_lock(&g_crm_core_dev->crm_lock);
/* session hdl's priv data is cam session struct */
session = (struct cam_req_mgr_core_session *)
cam_get_device_priv(flush_info->session_hdl);
@@ -2482,6 +2562,7 @@
&link->workq_comp,
msecs_to_jiffies(CAM_REQ_MGR_SCHED_REQ_TIMEOUT));
end:
+ mutex_unlock(&g_crm_core_dev->crm_lock);
return rc;
}
diff --git a/drivers/media/platform/msm/camera/cam_req_mgr/cam_req_mgr_core.h b/drivers/media/platform/msm/camera/cam_req_mgr/cam_req_mgr_core.h
index 42f8c77..4511a5d 100644
--- a/drivers/media/platform/msm/camera/cam_req_mgr/cam_req_mgr_core.h
+++ b/drivers/media/platform/msm/camera/cam_req_mgr/cam_req_mgr_core.h
@@ -79,12 +79,14 @@
* EMPTY : indicates req slot is empty
* PENDING : indicates req slot is waiting for reqs from all devs
* READY : indicates req slot is ready to be sent to devs
+ * APPLIED : indicates req slot is already sent to devs
* INVALID : indicates req slot is not in valid state
*/
enum crm_req_state {
CRM_REQ_STATE_EMPTY,
CRM_REQ_STATE_PENDING,
CRM_REQ_STATE_READY,
+ CRM_REQ_STATE_APPLIED,
CRM_REQ_STATE_INVALID,
};
diff --git a/drivers/media/platform/msm/camera/cam_req_mgr/cam_req_mgr_timer.c b/drivers/media/platform/msm/camera/cam_req_mgr/cam_req_mgr_timer.c
index 2aa2ab1..2189202 100644
--- a/drivers/media/platform/msm/camera/cam_req_mgr/cam_req_mgr_timer.c
+++ b/drivers/media/platform/msm/camera/cam_req_mgr/cam_req_mgr_timer.c
@@ -82,7 +82,7 @@
{
CAM_DBG(CAM_CRM, "destroy timer %pK", *crm_timer);
if (*crm_timer) {
- del_timer(&(*crm_timer)->sys_timer);
+ del_timer_sync(&(*crm_timer)->sys_timer);
kfree(*crm_timer);
*crm_timer = NULL;
}
diff --git a/drivers/media/platform/msm/camera/cam_sensor_module/cam_actuator/cam_actuator_core.c b/drivers/media/platform/msm/camera/cam_sensor_module/cam_actuator/cam_actuator_core.c
index febf922..079f5bb 100644
--- a/drivers/media/platform/msm/camera/cam_sensor_module/cam_actuator/cam_actuator_core.c
+++ b/drivers/media/platform/msm/camera/cam_sensor_module/cam_actuator/cam_actuator_core.c
@@ -33,6 +33,7 @@
power_info->power_setting[0].seq_type = SENSOR_VAF;
power_info->power_setting[0].seq_val = CAM_VAF;
power_info->power_setting[0].config_val = 1;
+ power_info->power_setting[0].delay = 2;
power_info->power_down_setting_size = 1;
power_info->power_down_setting =
@@ -67,6 +68,18 @@
(struct cam_actuator_soc_private *)a_ctrl->soc_info.soc_private;
power_info = &soc_private->power_info;
+ if ((power_info->power_setting == NULL) &&
+ (power_info->power_down_setting == NULL)) {
+ CAM_INFO(CAM_ACTUATOR,
+ "Using default power settings");
+ rc = cam_actuator_construct_default_power_setting(power_info);
+ if (rc < 0) {
+ CAM_ERR(CAM_ACTUATOR,
+ "Construct default actuator power setting failed.");
+ return rc;
+ }
+ }
+
/* Parse and fill vreg params for power up settings */
rc = msm_camera_fill_vreg_params(
&a_ctrl->soc_info,
@@ -93,16 +106,14 @@
rc = cam_sensor_core_power_up(power_info, soc_info);
if (rc) {
- CAM_ERR(CAM_ACTUATOR, "failed in ois power up rc %d", rc);
+ CAM_ERR(CAM_ACTUATOR,
+ "failed in actuator power up rc %d", rc);
return rc;
}
- /* VREG needs some delay to power up */
- usleep_range(2000, 2050);
-
rc = camera_io_init(&a_ctrl->io_master_info);
if (rc < 0)
- CAM_ERR(CAM_ACTUATOR, "cci_init failed: rc: %d", rc);
+ CAM_ERR(CAM_ACTUATOR, "cci init failed: rc: %d", rc);
return rc;
}
@@ -115,7 +126,7 @@
struct cam_actuator_soc_private *soc_private;
if (!a_ctrl) {
- CAM_ERR(CAM_ACTUATOR, "failed: e_ctrl %pK", a_ctrl);
+ CAM_ERR(CAM_ACTUATOR, "failed: a_ctrl %pK", a_ctrl);
return -EINVAL;
}
@@ -369,23 +380,34 @@
int32_t cam_actuator_i2c_pkt_parse(struct cam_actuator_ctrl_t *a_ctrl,
void *arg)
{
- int32_t rc = 0;
+ int32_t rc = 0;
+ int32_t i = 0;
+ uint32_t total_cmd_buf_in_bytes = 0;
+ size_t len_of_buff = 0;
+ uint32_t *offset = NULL;
+ uint32_t *cmd_buf = NULL;
uint64_t generic_ptr;
- struct cam_control *ioctl_ctrl = NULL;
- struct cam_packet *csl_packet = NULL;
+ struct common_header *cmm_hdr = NULL;
+ struct cam_control *ioctl_ctrl = NULL;
+ struct cam_packet *csl_packet = NULL;
struct cam_config_dev_cmd config;
- struct i2c_data_settings *i2c_data = NULL;
+ struct i2c_data_settings *i2c_data = NULL;
struct i2c_settings_array *i2c_reg_settings = NULL;
- struct cam_cmd_buf_desc *cmd_desc = NULL;
- size_t len_of_buff = 0;
- uint32_t *offset = NULL, *cmd_buf;
- struct cam_req_mgr_add_request add_req;
+ struct cam_cmd_buf_desc *cmd_desc = NULL;
+ struct cam_req_mgr_add_request add_req;
+ struct cam_actuator_soc_private *soc_private = NULL;
+ struct cam_sensor_power_ctrl_t *power_info = NULL;
if (!a_ctrl || !arg) {
CAM_ERR(CAM_ACTUATOR, "Invalid Args");
return -EINVAL;
}
+ soc_private =
+ (struct cam_actuator_soc_private *)a_ctrl->soc_info.soc_private;
+
+ power_info = &soc_private->power_info;
+
ioctl_ctrl = (struct cam_control *)arg;
if (copy_from_user(&config, (void __user *) ioctl_ctrl->handle,
sizeof(config)))
@@ -405,53 +427,99 @@
return -EINVAL;
}
- csl_packet = (struct cam_packet *)(generic_ptr +
- config.offset);
+ csl_packet = (struct cam_packet *)(generic_ptr + config.offset);
CAM_DBG(CAM_ACTUATOR, "Pkt opcode: %d", csl_packet->header.op_code);
- if ((csl_packet->header.op_code & 0xFFFFFF) ==
- CAM_ACTUATOR_PACKET_OPCODE_INIT) {
- i2c_data = &(a_ctrl->i2c_data);
- i2c_reg_settings = &i2c_data->init_settings;
-
+ switch (csl_packet->header.op_code & 0xFFFFFF) {
+ case CAM_ACTUATOR_PACKET_OPCODE_INIT:
offset = (uint32_t *)&csl_packet->payload;
offset += (csl_packet->cmd_buf_offset / sizeof(uint32_t));
cmd_desc = (struct cam_cmd_buf_desc *)(offset);
- if (csl_packet->num_cmd_buf != 2) {
- CAM_ERR(CAM_ACTUATOR, "cmd Buffers in Init : %d",
- csl_packet->num_cmd_buf);
- return -EINVAL;
+ /* Loop through multiple command buffers */
+ for (i = 0; i < csl_packet->num_cmd_buf; i++) {
+ total_cmd_buf_in_bytes = cmd_desc[i].length;
+ if (!total_cmd_buf_in_bytes)
+ continue;
+ rc = cam_mem_get_cpu_buf(cmd_desc[i].mem_handle,
+ (uint64_t *)&generic_ptr, &len_of_buff);
+ if (rc < 0) {
+ CAM_ERR(CAM_ACTUATOR, "Failed to get cpu buf");
+ return rc;
+ }
+ cmd_buf = (uint32_t *)generic_ptr;
+ if (!cmd_buf) {
+ CAM_ERR(CAM_ACTUATOR, "invalid cmd buf");
+ return -EINVAL;
+ }
+ cmd_buf += cmd_desc[i].offset / sizeof(uint32_t);
+ cmm_hdr = (struct common_header *)cmd_buf;
+
+ switch (cmm_hdr->cmd_type) {
+ case CAMERA_SENSOR_CMD_TYPE_I2C_INFO:
+ CAM_DBG(CAM_ACTUATOR,
+ "Received slave info buffer");
+ rc = cam_actuator_slaveInfo_pkt_parser(
+ a_ctrl, cmd_buf);
+ if (rc < 0) {
+ CAM_ERR(CAM_ACTUATOR,
+ "Failed to parse slave info: %d", rc);
+ return rc;
+ }
+ break;
+ case CAMERA_SENSOR_CMD_TYPE_PWR_UP:
+ case CAMERA_SENSOR_CMD_TYPE_PWR_DOWN:
+ CAM_DBG(CAM_ACTUATOR,
+ "Received power settings buffer");
+ rc = cam_sensor_update_power_settings(
+ cmd_buf,
+ total_cmd_buf_in_bytes,
+ power_info);
+ if (rc) {
+ CAM_ERR(CAM_ACTUATOR,
+ "Failed:parse power settings: %d",
+ rc);
+ return rc;
+ }
+ break;
+ default:
+ CAM_DBG(CAM_ACTUATOR,
+ "Received initSettings buffer");
+ i2c_data = &(a_ctrl->i2c_data);
+ i2c_reg_settings =
+ &i2c_data->init_settings;
+
+ i2c_reg_settings->request_id = 0;
+ i2c_reg_settings->is_settings_valid = 1;
+ rc = cam_sensor_i2c_command_parser(
+ i2c_reg_settings,
+ &cmd_desc[i], 1);
+ if (rc < 0) {
+ CAM_ERR(CAM_ACTUATOR,
+ "Failed:parse init settings: %d",
+ rc);
+ return rc;
+ }
+ break;
+ }
}
- rc = cam_mem_get_cpu_buf(cmd_desc[0].mem_handle,
- (uint64_t *)&generic_ptr, &len_of_buff);
- if (rc < 0) {
- CAM_ERR(CAM_ACTUATOR, "Failed to get cpu buf");
- return rc;
- }
- cmd_buf = (uint32_t *)generic_ptr;
- cmd_buf += cmd_desc->offset / sizeof(uint32_t);
- rc = cam_actuator_slaveInfo_pkt_parser(a_ctrl, cmd_buf);
- if (rc < 0) {
- CAM_ERR(CAM_ACTUATOR, "Failed in parsing the pkt");
- return rc;
- }
- cmd_buf += (sizeof(struct cam_cmd_i2c_info)/sizeof(uint32_t));
- i2c_data->init_settings.request_id = 0;
- i2c_reg_settings->is_settings_valid = 1;
- rc = cam_sensor_i2c_command_parser(i2c_reg_settings,
- &cmd_desc[1], 1);
- if (rc < 0) {
- CAM_ERR(CAM_ACTUATOR, "Actuator pkt parsing failed: %d",
- rc);
- return rc;
+ if (a_ctrl->cam_act_state == CAM_ACTUATOR_ACQUIRE) {
+ rc = cam_actuator_power_up(a_ctrl);
+ if (rc < 0) {
+ CAM_ERR(CAM_ACTUATOR,
+ " Actuator Power up failed");
+ return rc;
+ }
+ a_ctrl->cam_act_state = CAM_ACTUATOR_CONFIG;
}
rc = cam_actuator_apply_settings(a_ctrl,
&a_ctrl->i2c_data.init_settings);
- if (rc < 0)
+ if (rc < 0) {
CAM_ERR(CAM_ACTUATOR, "Cannot apply Init settings");
+ return rc;
+ }
/* Delete the request even if the apply is failed */
rc = delete_request(&a_ctrl->i2c_data.init_settings);
@@ -460,10 +528,16 @@
"Fail in deleting the Init settings");
rc = 0;
}
- } else if ((csl_packet->header.op_code & 0xFFFFFF) ==
- CAM_ACTUATOR_PACKET_AUTO_MOVE_LENS) {
- a_ctrl->setting_apply_state =
- ACT_APPLY_SETTINGS_NOW;
+ break;
+ case CAM_ACTUATOR_PACKET_AUTO_MOVE_LENS:
+ if (a_ctrl->cam_act_state < CAM_ACTUATOR_CONFIG) {
+ rc = -EINVAL;
+ CAM_WARN(CAM_ACTUATOR,
+ "Not in right state to move lens: %d",
+ a_ctrl->cam_act_state);
+ return rc;
+ }
+ a_ctrl->setting_apply_state = ACT_APPLY_SETTINGS_NOW;
i2c_data = &(a_ctrl->i2c_data);
i2c_reg_settings = &i2c_data->init_settings;
@@ -477,16 +551,22 @@
rc = cam_sensor_i2c_command_parser(i2c_reg_settings,
cmd_desc, 1);
if (rc < 0) {
- CAM_ERR(CAM_ACTUATOR, "Actuator pkt parsing failed: %d",
- rc);
+ CAM_ERR(CAM_ACTUATOR,
+ "Auto move lens parsing failed: %d", rc);
return rc;
}
- } else if ((csl_packet->header.op_code & 0xFFFFFF) ==
- CAM_ACTUATOR_PACKET_MANUAL_MOVE_LENS) {
+ break;
+ case CAM_ACTUATOR_PACKET_MANUAL_MOVE_LENS:
+ if (a_ctrl->cam_act_state < CAM_ACTUATOR_CONFIG) {
+ rc = -EINVAL;
+ CAM_WARN(CAM_ACTUATOR,
+ "Not in right state to move lens: %d",
+ a_ctrl->cam_act_state);
+ return rc;
+ }
i2c_data = &(a_ctrl->i2c_data);
- i2c_reg_settings =
- &i2c_data->per_frame
- [csl_packet->header.request_id % MAX_PER_FRAME_ARRAY];
+ i2c_reg_settings = &i2c_data->per_frame[
+ csl_packet->header.request_id % MAX_PER_FRAME_ARRAY];
i2c_data->init_settings.request_id =
csl_packet->header.request_id;
@@ -497,10 +577,11 @@
rc = cam_sensor_i2c_command_parser(i2c_reg_settings,
cmd_desc, 1);
if (rc < 0) {
- CAM_ERR(CAM_ACTUATOR, "Actuator pkt parsing failed: %d",
- rc);
+ CAM_ERR(CAM_ACTUATOR,
+ "Manual move lens parsing failed: %d", rc);
return rc;
}
+ break;
}
if ((csl_packet->header.op_code & 0xFFFFFF) !=
@@ -526,12 +607,13 @@
if (a_ctrl->cam_act_state == CAM_ACTUATOR_INIT)
return;
- if ((a_ctrl->cam_act_state == CAM_ACTUATOR_START) ||
- (a_ctrl->cam_act_state == CAM_ACTUATOR_ACQUIRE)) {
+ if (a_ctrl->cam_act_state >= CAM_ACTUATOR_CONFIG) {
rc = cam_actuator_power_down(a_ctrl);
if (rc < 0)
CAM_ERR(CAM_ACTUATOR, "Actuator Power down failed");
+ }
+ if (a_ctrl->cam_act_state >= CAM_ACTUATOR_ACQUIRE) {
rc = cam_destroy_device_hdl(a_ctrl->bridge_intf.device_hdl);
if (rc < 0)
CAM_ERR(CAM_ACTUATOR, "destroying dhdl failed");
@@ -595,28 +677,24 @@
goto release_mutex;
}
- rc = cam_actuator_power_up(a_ctrl);
- if (rc < 0) {
- CAM_ERR(CAM_ACTUATOR, " Actuator Power up failed");
- goto release_mutex;
- }
-
a_ctrl->cam_act_state = CAM_ACTUATOR_ACQUIRE;
}
break;
case CAM_RELEASE_DEV: {
- if (a_ctrl->cam_act_state != CAM_ACTUATOR_ACQUIRE) {
+ if (a_ctrl->cam_act_state == CAM_ACTUATOR_START) {
rc = -EINVAL;
CAM_WARN(CAM_ACTUATOR,
- "Not in right state to release : %d",
- a_ctrl->cam_act_state);
+ "Cant release actuator: in start state");
goto release_mutex;
}
- rc = cam_actuator_power_down(a_ctrl);
- if (rc < 0) {
- CAM_ERR(CAM_ACTUATOR, "Actuator Power down failed");
- goto release_mutex;
+ if (a_ctrl->cam_act_state == CAM_ACTUATOR_CONFIG) {
+ rc = cam_actuator_power_down(a_ctrl);
+ if (rc < 0) {
+ CAM_ERR(CAM_ACTUATOR,
+ "Actuator Power down failed");
+ goto release_mutex;
+ }
}
if (a_ctrl->bridge_intf.device_hdl == -1) {
@@ -648,7 +726,7 @@
}
break;
case CAM_START_DEV: {
- if (a_ctrl->cam_act_state != CAM_ACTUATOR_ACQUIRE) {
+ if (a_ctrl->cam_act_state != CAM_ACTUATOR_CONFIG) {
rc = -EINVAL;
CAM_WARN(CAM_ACTUATOR,
"Not in right state to start : %d",
@@ -681,7 +759,7 @@
i2c_set->request_id, rc);
}
}
- a_ctrl->cam_act_state = CAM_ACTUATOR_ACQUIRE;
+ a_ctrl->cam_act_state = CAM_ACTUATOR_CONFIG;
}
break;
case CAM_CONFIG_DEV: {
diff --git a/drivers/media/platform/msm/camera/cam_sensor_module/cam_actuator/cam_actuator_dev.c b/drivers/media/platform/msm/camera/cam_sensor_module/cam_actuator/cam_actuator_dev.c
index c5c9b0a..96fdfeb 100644
--- a/drivers/media/platform/msm/camera/cam_sensor_module/cam_actuator/cam_actuator_dev.c
+++ b/drivers/media/platform/msm/camera/cam_sensor_module/cam_actuator/cam_actuator_dev.c
@@ -183,7 +183,7 @@
rc = cam_actuator_parse_dt(a_ctrl, &client->dev);
if (rc < 0) {
CAM_ERR(CAM_ACTUATOR, "failed: cam_sensor_parse_dt rc %d", rc);
- goto free_ctrl;
+ goto free_soc;
}
rc = cam_actuator_init_subdev(a_ctrl);
@@ -218,19 +218,10 @@
v4l2_set_subdevdata(&(a_ctrl->v4l2_dev_str.sd), a_ctrl);
- rc = cam_actuator_construct_default_power_setting(
- &soc_private->power_info);
- if (rc < 0) {
- CAM_ERR(CAM_ACTUATOR,
- "Construct default actuator power setting failed.");
- goto free_mem;
- }
-
a_ctrl->cam_act_state = CAM_ACTUATOR_INIT;
return rc;
-free_mem:
- kfree(a_ctrl->i2c_data.per_frame);
+
unreg_subdev:
cam_unregister_subdev(&(a_ctrl->v4l2_dev_str));
free_soc:
@@ -311,7 +302,7 @@
struct cam_actuator_ctrl_t *a_ctrl = NULL;
struct cam_actuator_soc_private *soc_private = NULL;
- /* Create sensor control structure */
+ /* Create actuator control structure */
a_ctrl = devm_kzalloc(&pdev->dev,
sizeof(struct cam_actuator_ctrl_t), GFP_KERNEL);
if (!a_ctrl)
@@ -379,18 +370,10 @@
platform_set_drvdata(pdev, a_ctrl);
v4l2_set_subdevdata(&a_ctrl->v4l2_dev_str.sd, a_ctrl);
-
- rc = cam_actuator_construct_default_power_setting(
- &soc_private->power_info);
- if (rc < 0) {
- CAM_ERR(CAM_ACTUATOR,
- "Construct default actuator power setting failed.");
- goto unreg_subdev;
- }
+ a_ctrl->cam_act_state = CAM_ACTUATOR_INIT;
return rc;
-unreg_subdev:
- cam_unregister_subdev(&(a_ctrl->v4l2_dev_str));
+
free_mem:
kfree(a_ctrl->i2c_data.per_frame);
free_soc:
diff --git a/drivers/media/platform/msm/camera/cam_sensor_module/cam_actuator/cam_actuator_dev.h b/drivers/media/platform/msm/camera/cam_sensor_module/cam_actuator/cam_actuator_dev.h
index 8b8b1ef..c4333a0 100644
--- a/drivers/media/platform/msm/camera/cam_sensor_module/cam_actuator/cam_actuator_dev.h
+++ b/drivers/media/platform/msm/camera/cam_sensor_module/cam_actuator/cam_actuator_dev.h
@@ -56,6 +56,7 @@
enum cam_actuator_state {
CAM_ACTUATOR_INIT,
CAM_ACTUATOR_ACQUIRE,
+ CAM_ACTUATOR_CONFIG,
CAM_ACTUATOR_START,
};
diff --git a/drivers/media/platform/msm/camera/cam_sensor_module/cam_actuator/cam_actuator_soc.c b/drivers/media/platform/msm/camera/cam_sensor_module/cam_actuator/cam_actuator_soc.c
index 55b7c72..96dc284 100644
--- a/drivers/media/platform/msm/camera/cam_sensor_module/cam_actuator/cam_actuator_soc.c
+++ b/drivers/media/platform/msm/camera/cam_sensor_module/cam_actuator/cam_actuator_soc.c
@@ -46,8 +46,10 @@
CAM_DBG(CAM_ACTUATOR, "cci-master %d, rc %d",
a_ctrl->cci_i2c_master, rc);
if ((rc < 0) || (a_ctrl->cci_i2c_master >= MASTER_MAX)) {
- CAM_ERR(CAM_ACTUATOR, "Wrong info: dt CCI master:%d",
- a_ctrl->cci_i2c_master);
+ CAM_ERR(CAM_ACTUATOR,
+ "Wrong info: rc: %d, dt CCI master:%d",
+ rc, a_ctrl->cci_i2c_master);
+ rc = -EFAULT;
return rc;
}
}
diff --git a/drivers/media/platform/msm/camera/cam_sensor_module/cam_cci/cam_cci_core.c b/drivers/media/platform/msm/camera/cam_sensor_module/cam_cci/cam_cci_core.c
index d7a6504..9a711ec 100644
--- a/drivers/media/platform/msm/camera/cam_sensor_module/cam_cci/cam_cci_core.c
+++ b/drivers/media/platform/msm/camera/cam_sensor_module/cam_cci/cam_cci_core.c
@@ -119,7 +119,8 @@
rc = wait_for_completion_timeout(&cci_dev->
cci_master_info[master].report_q[queue], CCI_TIMEOUT);
if (rc <= 0) {
- CAM_ERR(CAM_CCI, "Wait_for_completion_timeout %d");
+ CAM_ERR(CAM_CCI, "Wait_for_completion_timeout: rc: %d",
+ rc);
if (rc == 0)
rc = -ETIMEDOUT;
cam_cci_flush_queue(cci_dev, master);
@@ -312,7 +313,7 @@
if (atomic_read(&cci_dev->cci_master_info[master].q_free[queue]) == 0) {
rc = cam_cci_lock_queue(cci_dev, master, queue, 0);
if (rc < 0) {
- CAM_ERR(CAM_CCI, "failed line %d");
+ CAM_ERR(CAM_CCI, "failed rc: %d", rc);
return rc;
}
rc = cam_cci_wait_report_cmd(cci_dev, master, queue);
diff --git a/drivers/media/platform/msm/camera/cam_sensor_module/cam_cci/cam_cci_dev.c b/drivers/media/platform/msm/camera/cam_sensor_module/cam_cci/cam_cci_dev.c
index 6cfb965..ed91250 100644
--- a/drivers/media/platform/msm/camera/cam_sensor_module/cam_cci/cam_cci_dev.c
+++ b/drivers/media/platform/msm/camera/cam_sensor_module/cam_cci/cam_cci_dev.c
@@ -146,16 +146,16 @@
base + CCI_RESET_CMD_ADDR);
}
if (irq & CCI_IRQ_STATUS_0_I2C_M0_ERROR_BMSK) {
- CAM_ERR(CAM_CCI, "MASTER_0 error 0x%x", irq);
cci_dev->cci_master_info[MASTER_0].status = -EINVAL;
cam_io_w_mb(CCI_M0_HALT_REQ_RMSK,
base + CCI_HALT_REQ_ADDR);
+ CAM_DBG(CAM_CCI, "MASTER_0 error 0x%x", irq);
}
if (irq & CCI_IRQ_STATUS_0_I2C_M1_ERROR_BMSK) {
- CAM_ERR(CAM_CCI, "MASTER_1 error 0x%x", irq);
cci_dev->cci_master_info[MASTER_1].status = -EINVAL;
cam_io_w_mb(CCI_M1_HALT_REQ_RMSK,
base + CCI_HALT_REQ_ADDR);
+ CAM_DBG(CAM_CCI, "MASTER_1 error 0x%x", irq);
}
return IRQ_HANDLED;
}
diff --git a/drivers/media/platform/msm/camera/cam_sensor_module/cam_csiphy/cam_csiphy_core.c b/drivers/media/platform/msm/camera/cam_sensor_module/cam_csiphy/cam_csiphy_core.c
index 2adca66..262e49c 100644
--- a/drivers/media/platform/msm/camera/cam_sensor_module/cam_csiphy/cam_csiphy_core.c
+++ b/drivers/media/platform/msm/camera/cam_sensor_module/cam_csiphy/cam_csiphy_core.c
@@ -140,12 +140,6 @@
csiphy_dev->csiphy_info.data_rate = cam_cmd_csiphy_info->data_rate;
csiphy_dev->csiphy_info.secure_mode = cam_cmd_csiphy_info->secure_mode;
- if (csiphy_dev->csiphy_info.secure_mode &&
- (csiphy_dev->config_count == 1))
- rc = cam_csiphy_notify_secure_mode(
- csiphy_dev->soc_info.index,
- CAM_SECURE_MODE_SECURE);
-
return rc;
}
@@ -365,6 +359,14 @@
if (csiphy_dev->csiphy_state == CAM_CSIPHY_START) {
soc_info = &csiphy_dev->soc_info;
+ if (csiphy_dev->csiphy_info.secure_mode)
+ cam_csiphy_notify_secure_mode(
+ csiphy_dev->soc_info.index,
+ CAM_SECURE_MODE_NON_SECURE);
+
+ csiphy_dev->csiphy_info.secure_mode =
+ CAM_SECURE_MODE_NON_SECURE;
+
cam_csiphy_reset(csiphy_dev);
cam_soc_util_disable_platform_resource(soc_info, true, true);
@@ -393,6 +395,43 @@
csiphy_dev->csiphy_state = CAM_CSIPHY_INIT;
}
+static int32_t cam_csiphy_external_cmd(struct csiphy_device *csiphy_dev,
+ struct cam_config_dev_cmd *p_submit_cmd)
+{
+ struct cam_csiphy_info cam_cmd_csiphy_info;
+ int32_t rc = 0;
+
+ if (copy_from_user(&cam_cmd_csiphy_info,
+ (void __user *)p_submit_cmd->packet_handle,
+ sizeof(struct cam_csiphy_info))) {
+ CAM_ERR(CAM_CSIPHY, "failed to copy cam_csiphy_info\n");
+ rc = -EFAULT;
+ } else {
+ csiphy_dev->csiphy_info.lane_cnt =
+ cam_cmd_csiphy_info.lane_cnt;
+ csiphy_dev->csiphy_info.lane_cnt =
+ cam_cmd_csiphy_info.lane_cnt;
+ csiphy_dev->csiphy_info.lane_mask =
+ cam_cmd_csiphy_info.lane_mask;
+ csiphy_dev->csiphy_info.csiphy_3phase =
+ cam_cmd_csiphy_info.csiphy_3phase;
+ csiphy_dev->csiphy_info.combo_mode =
+ cam_cmd_csiphy_info.combo_mode;
+ csiphy_dev->csiphy_info.settle_time =
+ cam_cmd_csiphy_info.settle_time;
+ csiphy_dev->csiphy_info.data_rate =
+ cam_cmd_csiphy_info.data_rate;
+ CAM_DBG(CAM_CSIPHY,
+ "%s CONFIG_DEV_EXT settle_time= %lld lane_cnt=%d lane_mask=0x%x",
+ __func__,
+ csiphy_dev->csiphy_info.settle_time,
+ csiphy_dev->csiphy_info.lane_cnt,
+ csiphy_dev->csiphy_info.lane_mask);
+ }
+
+ return rc;
+}
+
int32_t cam_csiphy_core_cfg(void *phy_dev,
void *arg)
{
@@ -516,6 +555,14 @@
goto release_mutex;
}
+ if (csiphy_dev->csiphy_info.secure_mode)
+ cam_csiphy_notify_secure_mode(
+ csiphy_dev->soc_info.index,
+ CAM_SECURE_MODE_NON_SECURE);
+
+ csiphy_dev->csiphy_info.secure_mode =
+ CAM_SECURE_MODE_NON_SECURE;
+
rc = cam_csiphy_disable_hw(csiphy_dev);
if (rc < 0)
CAM_ERR(CAM_CSIPHY, "Failed in csiphy release");
@@ -560,15 +607,6 @@
csiphy_dev->config_count--;
csiphy_dev->acquire_count--;
- if (csiphy_dev->csiphy_info.secure_mode &&
- (!csiphy_dev->config_count)) {
- csiphy_dev->csiphy_info.secure_mode =
- CAM_SECURE_MODE_NON_SECURE;
- rc = cam_csiphy_notify_secure_mode(
- csiphy_dev->soc_info.index,
- CAM_SECURE_MODE_NON_SECURE);
- }
-
if (csiphy_dev->acquire_count == 0)
csiphy_dev->csiphy_state = CAM_CSIPHY_INIT;
}
@@ -609,6 +647,15 @@
goto release_mutex;
}
+ if (csiphy_dev->csiphy_info.secure_mode) {
+ rc = cam_csiphy_notify_secure_mode(
+ csiphy_dev->soc_info.index,
+ CAM_SECURE_MODE_SECURE);
+ if (rc < 0)
+ csiphy_dev->csiphy_info.secure_mode =
+ CAM_SECURE_MODE_NON_SECURE;
+ }
+
rc = cam_csiphy_enable_hw(csiphy_dev);
if (rc != 0) {
CAM_ERR(CAM_CSIPHY, "cam_csiphy_enable_hw failed");
@@ -629,6 +676,19 @@
csiphy_dev->csiphy_state = CAM_CSIPHY_START;
}
break;
+ case CAM_CONFIG_DEV_EXTERNAL: {
+ struct cam_config_dev_cmd submit_cmd;
+
+ if (copy_from_user(&submit_cmd,
+ (void __user *)cmd->handle,
+ sizeof(struct cam_config_dev_cmd))) {
+ CAM_ERR(CAM_CSIPHY, "failed copy config ext\n");
+ rc = -EFAULT;
+ } else {
+ rc = cam_csiphy_external_cmd(csiphy_dev, &submit_cmd);
+ }
+ break;
+ }
default:
CAM_ERR(CAM_CSIPHY, "Invalid Opcode: %d", cmd->op_code);
rc = -EINVAL;
diff --git a/drivers/media/platform/msm/camera/cam_sensor_module/cam_eeprom/cam_eeprom_core.c b/drivers/media/platform/msm/camera/cam_sensor_module/cam_eeprom/cam_eeprom_core.c
index 72b1779..b0fbead 100644
--- a/drivers/media/platform/msm/camera/cam_sensor_module/cam_eeprom/cam_eeprom_core.c
+++ b/drivers/media/platform/msm/camera/cam_sensor_module/cam_eeprom/cam_eeprom_core.c
@@ -128,7 +128,6 @@
i2c_reg_settings.reg_setting = &i2c_reg_array;
rc = camera_io_dev_write(&e_ctrl->io_master_info,
&i2c_reg_settings);
-
if (rc) {
CAM_ERR(CAM_EEPROM,
"page disable failed rc %d",
@@ -161,7 +160,7 @@
power_info->power_setting_size);
if (rc) {
CAM_ERR(CAM_EEPROM,
- "failed to fill vreg params for power up rc:%d", rc);
+ "failed to fill power up vreg params rc:%d", rc);
return rc;
}
@@ -172,7 +171,7 @@
power_info->power_down_setting_size);
if (rc) {
CAM_ERR(CAM_EEPROM,
- "failed to fill vreg params power down rc:%d", rc);
+ "failed to fill power down vreg params rc:%d", rc);
return rc;
}
@@ -410,10 +409,12 @@
static int32_t cam_eeprom_parse_memory_map(
struct cam_eeprom_memory_block_t *data,
void *cmd_buf, int cmd_length, uint16_t *cmd_length_bytes,
- int16_t num_map)
+ int *num_map)
{
int32_t rc = 0;
+ int32_t cnt = 0;
int32_t processed_size = 0;
+ uint8_t generic_op_code;
struct cam_eeprom_memory_map_t *map = data->map;
struct common_header *cmm_hdr =
(struct common_header *)cmd_buf;
@@ -421,19 +422,30 @@
struct cam_cmd_i2c_random_wr *i2c_random_wr = NULL;
struct cam_cmd_i2c_continuous_rd *i2c_cont_rd = NULL;
struct cam_cmd_conditional_wait *i2c_poll = NULL;
+ struct cam_cmd_unconditional_wait *i2c_uncond_wait = NULL;
+ generic_op_code = cmm_hdr->third_byte;
switch (cmm_hdr->cmd_type) {
case CAMERA_SENSOR_CMD_TYPE_I2C_RNDM_WR:
i2c_random_wr = (struct cam_cmd_i2c_random_wr *)cmd_buf;
- cmd_length_in_bytes = sizeof(struct cam_cmd_i2c_random_wr);
+ cmd_length_in_bytes = sizeof(struct cam_cmd_i2c_random_wr) +
+ ((i2c_random_wr->header.count - 1) *
+ sizeof(struct i2c_random_wr_payload));
- map[num_map].page.addr =
- i2c_random_wr->random_wr_payload[0].reg_addr;
- map[num_map].page.addr_type = i2c_random_wr->header.addr_type;
- map[num_map].page.data =
- i2c_random_wr->random_wr_payload[0].reg_data;
- map[num_map].page.data_type = i2c_random_wr->header.data_type;
- map[num_map].page.valid_size = 1;
+ for (cnt = 0; cnt < (i2c_random_wr->header.count);
+ cnt++) {
+ map[*num_map + cnt].page.addr =
+ i2c_random_wr->random_wr_payload[cnt].reg_addr;
+ map[*num_map + cnt].page.addr_type =
+ i2c_random_wr->header.addr_type;
+ map[*num_map + cnt].page.data =
+ i2c_random_wr->random_wr_payload[cnt].reg_data;
+ map[*num_map + cnt].page.data_type =
+ i2c_random_wr->header.data_type;
+ map[*num_map + cnt].page.valid_size = 1;
+ }
+
+ *num_map += (i2c_random_wr->header.count - 1);
cmd_buf += cmd_length_in_bytes / sizeof(int32_t);
processed_size +=
cmd_length_in_bytes;
@@ -442,30 +454,62 @@
i2c_cont_rd = (struct cam_cmd_i2c_continuous_rd *)cmd_buf;
cmd_length_in_bytes = sizeof(struct cam_cmd_i2c_continuous_rd);
- map[num_map].mem.addr = i2c_cont_rd->reg_addr;
- map[num_map].mem.addr_type = i2c_cont_rd->header.addr_type;
- map[num_map].mem.data_type = i2c_cont_rd->header.data_type;
- map[num_map].mem.valid_size =
+ map[*num_map].mem.addr = i2c_cont_rd->reg_addr;
+ map[*num_map].mem.addr_type = i2c_cont_rd->header.addr_type;
+ map[*num_map].mem.data_type = i2c_cont_rd->header.data_type;
+ map[*num_map].mem.valid_size =
i2c_cont_rd->header.count;
cmd_buf += cmd_length_in_bytes / sizeof(int32_t);
processed_size +=
cmd_length_in_bytes;
- data->num_data += map[num_map].mem.valid_size;
+ data->num_data += map[*num_map].mem.valid_size;
break;
case CAMERA_SENSOR_CMD_TYPE_WAIT:
- i2c_poll = (struct cam_cmd_conditional_wait *)cmd_buf;
- cmd_length_in_bytes = sizeof(struct cam_cmd_conditional_wait);
+ if (generic_op_code ==
+ CAMERA_SENSOR_WAIT_OP_HW_UCND ||
+ generic_op_code ==
+ CAMERA_SENSOR_WAIT_OP_SW_UCND) {
+ i2c_uncond_wait =
+ (struct cam_cmd_unconditional_wait *)cmd_buf;
+ cmd_length_in_bytes =
+ sizeof(struct cam_cmd_unconditional_wait);
- map[num_map].poll.addr = i2c_poll->reg_addr;
- map[num_map].poll.addr_type = i2c_poll->addr_type;
- map[num_map].poll.data = i2c_poll->reg_data;
- map[num_map].poll.data_type = i2c_poll->data_type;
- map[num_map].poll.delay = i2c_poll->timeout;
- map[num_map].poll.valid_size = 1;
+ if (*num_map < 1) {
+ CAM_ERR(CAM_EEPROM,
+ "invalid map number, num_map=%d",
+ *num_map);
+ return -EINVAL;
+ }
+
+ /*
+ * Though delay is added all of them, but delay will
+ * be applicable to only one of them as only one of
+ * them will have valid_size set to >= 1.
+ */
+ map[*num_map - 1].mem.delay = i2c_uncond_wait->delay;
+ map[*num_map - 1].page.delay = i2c_uncond_wait->delay;
+ map[*num_map - 1].pageen.delay = i2c_uncond_wait->delay;
+ } else if (generic_op_code ==
+ CAMERA_SENSOR_WAIT_OP_COND) {
+ i2c_poll = (struct cam_cmd_conditional_wait *)cmd_buf;
+ cmd_length_in_bytes =
+ sizeof(struct cam_cmd_conditional_wait);
+
+ map[*num_map].poll.addr = i2c_poll->reg_addr;
+ map[*num_map].poll.addr_type = i2c_poll->addr_type;
+ map[*num_map].poll.data = i2c_poll->reg_data;
+ map[*num_map].poll.data_type = i2c_poll->data_type;
+ map[*num_map].poll.delay = i2c_poll->timeout;
+ map[*num_map].poll.valid_size = 1;
+ }
+ cmd_buf += cmd_length_in_bytes / sizeof(int32_t);
+ processed_size +=
+ cmd_length_in_bytes;
break;
default:
break;
}
+
*cmd_length_bytes = processed_size;
return rc;
}
@@ -536,26 +580,26 @@
switch (cmm_hdr->cmd_type) {
case CAMERA_SENSOR_CMD_TYPE_I2C_INFO:
i2c_info = (struct cam_cmd_i2c_info *)cmd_buf;
- num_map++;
- map[num_map].saddr = i2c_info->slave_addr;
+ /* Configure the following map slave address */
+ map[num_map + 1].saddr = i2c_info->slave_addr;
rc = cam_eeprom_update_slaveInfo(e_ctrl,
cmd_buf);
cmd_length_in_bytes =
sizeof(struct cam_cmd_i2c_info);
processed_cmd_buf_in_bytes +=
cmd_length_in_bytes;
- cmd_buf += cmd_length_in_bytes/4;
- e_ctrl->cal_data.num_map = num_map + 1;
+ cmd_buf += cmd_length_in_bytes/
+ sizeof(uint32_t);
break;
case CAMERA_SENSOR_CMD_TYPE_PWR_UP:
case CAMERA_SENSOR_CMD_TYPE_PWR_DOWN:
- cmd_length_in_bytes =
- sizeof(struct cam_cmd_power);
+ cmd_length_in_bytes = total_cmd_buf_in_bytes;
rc = cam_sensor_update_power_settings(cmd_buf,
cmd_length_in_bytes, power_info);
processed_cmd_buf_in_bytes +=
- total_cmd_buf_in_bytes;
- cmd_buf += total_cmd_buf_in_bytes/4;
+ cmd_length_in_bytes;
+ cmd_buf += cmd_length_in_bytes/
+ sizeof(uint32_t);
if (rc) {
CAM_ERR(CAM_EEPROM, "Failed");
return rc;
@@ -564,18 +608,20 @@
case CAMERA_SENSOR_CMD_TYPE_I2C_RNDM_WR:
case CAMERA_SENSOR_CMD_TYPE_I2C_CONT_RD:
case CAMERA_SENSOR_CMD_TYPE_WAIT:
+ num_map++;
rc = cam_eeprom_parse_memory_map(
&e_ctrl->cal_data, cmd_buf,
total_cmd_buf_in_bytes,
- &cmd_length_in_bytes, num_map);
+ &cmd_length_in_bytes, &num_map);
processed_cmd_buf_in_bytes +=
cmd_length_in_bytes;
- cmd_buf += cmd_length_in_bytes/4;
+ cmd_buf += cmd_length_in_bytes/sizeof(uint32_t);
break;
default:
break;
}
}
+ e_ctrl->cal_data.num_map = num_map + 1;
}
return rc;
}
diff --git a/drivers/media/platform/msm/camera/cam_sensor_module/cam_eeprom/cam_eeprom_dev.c b/drivers/media/platform/msm/camera/cam_sensor_module/cam_eeprom/cam_eeprom_dev.c
index f3c4811..68c5eea 100644
--- a/drivers/media/platform/msm/camera/cam_sensor_module/cam_eeprom/cam_eeprom_dev.c
+++ b/drivers/media/platform/msm/camera/cam_sensor_module/cam_eeprom/cam_eeprom_dev.c
@@ -419,8 +419,10 @@
e_ctrl->io_master_info.master_type = CCI_MASTER;
e_ctrl->io_master_info.cci_client = kzalloc(
sizeof(struct cam_sensor_cci_client), GFP_KERNEL);
- if (!e_ctrl->io_master_info.cci_client)
+ if (!e_ctrl->io_master_info.cci_client) {
+ rc = -ENOMEM;
goto free_e_ctrl;
+ }
soc_private = kzalloc(sizeof(struct cam_eeprom_soc_private),
GFP_KERNEL);
diff --git a/drivers/media/platform/msm/camera/cam_sensor_module/cam_eeprom/cam_eeprom_soc.c b/drivers/media/platform/msm/camera/cam_sensor_module/cam_eeprom/cam_eeprom_soc.c
index c250045..5a6a401 100644
--- a/drivers/media/platform/msm/camera/cam_sensor_module/cam_eeprom/cam_eeprom_soc.c
+++ b/drivers/media/platform/msm/camera/cam_sensor_module/cam_eeprom/cam_eeprom_soc.c
@@ -295,17 +295,17 @@
(struct cam_eeprom_soc_private *)e_ctrl->soc_info.soc_private;
uint32_t temp;
+ if (!soc_info->dev) {
+ CAM_ERR(CAM_EEPROM, "Dev is NULL");
+ return -EINVAL;
+ }
+
rc = cam_soc_util_get_dt_properties(soc_info);
if (rc < 0) {
CAM_ERR(CAM_EEPROM, "Failed to read DT properties rc : %d", rc);
return rc;
}
- if (!soc_info->dev) {
- CAM_ERR(CAM_EEPROM, "Dev is NULL");
- return -EINVAL;
- }
-
of_node = soc_info->dev->of_node;
rc = of_property_read_string(of_node, "eeprom-name",
@@ -318,8 +318,9 @@
if (e_ctrl->io_master_info.master_type == CCI_MASTER) {
rc = of_property_read_u32(of_node, "cci-master",
&e_ctrl->cci_i2c_master);
- if (rc < 0) {
+ if (rc < 0 || (e_ctrl->cci_i2c_master >= MASTER_MAX)) {
CAM_DBG(CAM_EEPROM, "failed rc %d", rc);
+ rc = -EFAULT;
return rc;
}
}
@@ -349,7 +350,7 @@
"i2c-freq-mode read fail %d", rc);
soc_private->i2c_info.i2c_freq_mode = 0;
}
- if (soc_private->i2c_info.i2c_freq_mode >= I2C_MAX_MODES) {
+ if (soc_private->i2c_info.i2c_freq_mode >= I2C_MAX_MODES) {
CAM_ERR(CAM_EEPROM, "invalid i2c_freq_mode = %d",
soc_private->i2c_info.i2c_freq_mode);
soc_private->i2c_info.i2c_freq_mode = 0;
@@ -362,7 +363,7 @@
soc_info->clk[i] = devm_clk_get(soc_info->dev,
soc_info->clk_name[i]);
if (!soc_info->clk[i]) {
- CAM_ERR(CAM_SENSOR, "get failed for %s",
+ CAM_ERR(CAM_EEPROM, "get failed for %s",
soc_info->clk_name[i]);
rc = -ENOENT;
return rc;
diff --git a/drivers/media/platform/msm/camera/cam_sensor_module/cam_flash/cam_flash_core.c b/drivers/media/platform/msm/camera/cam_sensor_module/cam_flash/cam_flash_core.c
index 55da264..e0d4502 100644
--- a/drivers/media/platform/msm/camera/cam_sensor_module/cam_flash/cam_flash_core.c
+++ b/drivers/media/platform/msm/camera/cam_sensor_module/cam_flash/cam_flash_core.c
@@ -17,7 +17,7 @@
#include "cam_res_mgr_api.h"
int cam_flash_prepare(struct cam_flash_ctrl *flash_ctrl,
- enum cam_flash_state state)
+ bool regulator_enable)
{
int rc = 0;
@@ -26,7 +26,7 @@
return -EINVAL;
}
- if ((state == CAM_FLASH_STATE_START) &&
+ if (regulator_enable &&
(flash_ctrl->is_regulator_enabled == false)) {
rc = qpnp_flash_led_prepare(flash_ctrl->switch_trigger,
ENABLE_REGULATOR, NULL);
@@ -36,8 +36,7 @@
return rc;
}
flash_ctrl->is_regulator_enabled = true;
- flash_ctrl->flash_state = CAM_FLASH_STATE_START;
- } else if ((state == CAM_FLASH_STATE_STOP) &&
+ } else if ((!regulator_enable) &&
(flash_ctrl->is_regulator_enabled == true)) {
rc = qpnp_flash_led_prepare(flash_ctrl->switch_trigger,
DISABLE_REGULATOR, NULL);
@@ -47,7 +46,6 @@
return rc;
}
flash_ctrl->is_regulator_enabled = false;
- flash_ctrl->flash_state = CAM_FLASH_STATE_ACQUIRE;
} else {
CAM_ERR(CAM_FLASH, "Wrong Flash State : %d",
flash_ctrl->flash_state);
@@ -68,12 +66,14 @@
nrt_settings = &fctrl->nrt_info;
if (nrt_settings->cmn_attr.cmd_type ==
- CAMERA_SENSOR_FLASH_CMD_TYPE_INIT) {
+ CAMERA_SENSOR_FLASH_CMD_TYPE_INIT_INFO) {
fctrl->flash_init_setting.cmn_attr.is_settings_valid = false;
} else if ((nrt_settings->cmn_attr.cmd_type ==
CAMERA_SENSOR_FLASH_CMD_TYPE_WIDGET) ||
(nrt_settings->cmn_attr.cmd_type ==
- CAMERA_SENSOR_FLASH_CMD_TYPE_RER)) {
+ CAMERA_SENSOR_FLASH_CMD_TYPE_RER) ||
+ (nrt_settings->cmn_attr.cmd_type ==
+ CAMERA_SENSOR_FLASH_CMD_TYPE_INIT_FIRE)) {
fctrl->nrt_info.cmn_attr.is_settings_valid = false;
fctrl->nrt_info.cmn_attr.count = 0;
fctrl->nrt_info.num_iterations = 0;
@@ -312,6 +312,49 @@
if (req_id == 0) {
if (fctrl->nrt_info.cmn_attr.cmd_type ==
+ CAMERA_SENSOR_FLASH_CMD_TYPE_INIT_FIRE) {
+ flash_data = &fctrl->nrt_info;
+ if (flash_data->opcode ==
+ CAMERA_SENSOR_FLASH_OP_FIREHIGH) {
+ if (fctrl->flash_state !=
+ CAM_FLASH_STATE_CONFIG) {
+ CAM_WARN(CAM_FLASH,
+ "Cannot apply Start Dev:Prev state: %d",
+ fctrl->flash_state);
+ return rc;
+ }
+ rc = cam_flash_prepare(fctrl, true);
+ if (rc) {
+ CAM_ERR(CAM_FLASH,
+ "Enable Regulator Failed rc = %d", rc);
+ return rc;
+ }
+ rc = cam_flash_high(fctrl, flash_data);
+ if (rc)
+ CAM_ERR(CAM_FLASH,
+ "FLASH ON failed : %d",
+ rc);
+ }
+ if (flash_data->opcode ==
+ CAMERA_SENSOR_FLASH_OP_OFF) {
+ rc = cam_flash_off(fctrl);
+ if (rc) {
+ CAM_ERR(CAM_FLASH,
+ "LED OFF FAILED: %d",
+ rc);
+ return rc;
+ }
+ if ((fctrl->flash_state ==
+ CAM_FLASH_STATE_START) &&
+ (fctrl->is_regulator_enabled == true)) {
+ rc = cam_flash_prepare(fctrl, false);
+ if (rc)
+ CAM_ERR(CAM_FLASH,
+ "Disable Regulator failed: %d",
+ rc);
+ }
+ }
+ } else if (fctrl->nrt_info.cmn_attr.cmd_type ==
CAMERA_SENSOR_FLASH_CMD_TYPE_WIDGET) {
flash_data = &fctrl->nrt_info;
if (flash_data->opcode ==
@@ -323,18 +366,13 @@
rc);
goto nrt_del_req;
}
- fctrl->flash_state =
- CAM_FLASH_STATE_LOW;
} else if (flash_data->opcode ==
CAMERA_SENSOR_FLASH_OP_OFF) {
- if (fctrl->flash_state ==
- CAM_FLASH_STATE_LOW) {
- rc = cam_flash_off(fctrl);
- if (rc)
- CAM_ERR(CAM_FLASH,
- "LED off failed: %d",
- rc);
- }
+ rc = cam_flash_off(fctrl);
+ if (rc)
+ CAM_ERR(CAM_FLASH,
+ "LED off failed: %d",
+ rc);
}
} else if (fctrl->nrt_info.cmn_attr.cmd_type ==
CAMERA_SENSOR_FLASH_CMD_TYPE_RER) {
@@ -360,8 +398,6 @@
"Fire Torch Failed");
goto nrt_del_req;
}
- fctrl->flash_state =
- CAM_FLASH_STATE_LOW;
usleep_range(
flash_data->led_on_delay_ms * 1000,
@@ -398,7 +434,6 @@
rc);
goto apply_setting_err;
}
- fctrl->flash_state = CAM_FLASH_STATE_HIGH;
}
} else if ((flash_data->opcode ==
CAMERA_SENSOR_FLASH_OP_FIRELOW) &&
@@ -413,19 +448,15 @@
rc);
goto apply_setting_err;
}
- fctrl->flash_state = CAM_FLASH_STATE_LOW;
}
} else if ((flash_data->opcode == CAMERA_SENSOR_FLASH_OP_OFF) &&
(flash_data->cmn_attr.is_settings_valid) &&
(flash_data->cmn_attr.request_id == req_id)) {
- if ((fctrl->flash_state == CAM_FLASH_STATE_LOW) ||
- (fctrl->flash_state == CAM_FLASH_STATE_HIGH)) {
- rc = cam_flash_off(fctrl);
- if (rc) {
- CAM_ERR(CAM_FLASH,
- "Flash off failed %d", rc);
- goto apply_setting_err;
- }
+ rc = cam_flash_off(fctrl);
+ if (rc) {
+ CAM_ERR(CAM_FLASH,
+ "Flash off failed %d", rc);
+ goto apply_setting_err;
}
} else {
CAM_DBG(CAM_FLASH, "NOP opcode: req_id: %u", req_id);
@@ -503,11 +534,39 @@
cam_flash_info = (struct cam_flash_init *)cmd_buf;
switch (cam_flash_info->cmd_type) {
- case CAMERA_SENSOR_FLASH_CMD_TYPE_INIT:
+ case CAMERA_SENSOR_FLASH_CMD_TYPE_INIT_INFO:
fctrl->flash_type = cam_flash_info->flash_type;
fctrl->is_regulator_enabled = false;
fctrl->nrt_info.cmn_attr.cmd_type =
- CAMERA_SENSOR_FLASH_CMD_TYPE_INIT;
+ CAMERA_SENSOR_FLASH_CMD_TYPE_INIT_INFO;
+ fctrl->flash_state =
+ CAM_FLASH_STATE_CONFIG;
+ break;
+ case CAMERA_SENSOR_FLASH_CMD_TYPE_INIT_FIRE:
+ CAM_DBG(CAM_FLASH, "Widget Flash Operation");
+ flash_operation_info =
+ (struct cam_flash_set_on_off *) cmd_buf;
+ fctrl->nrt_info.cmn_attr.count =
+ flash_operation_info->count;
+ fctrl->nrt_info.cmn_attr.request_id = 0;
+ fctrl->nrt_info.opcode =
+ flash_operation_info->opcode;
+ fctrl->nrt_info.cmn_attr.cmd_type =
+ CAMERA_SENSOR_FLASH_CMD_TYPE_INIT_FIRE;
+ for (i = 0;
+ i < flash_operation_info->count; i++)
+ fctrl->nrt_info.led_current_ma[i] =
+ flash_operation_info->led_current_ma[i];
+
+ mutex_lock(&fctrl->flash_wq_mutex);
+ rc = cam_flash_apply_setting(fctrl, 0);
+ if (rc)
+ CAM_ERR(CAM_FLASH,
+ "Apply setting failed: %d",
+ rc);
+ mutex_unlock(&fctrl->flash_wq_mutex);
+ fctrl->flash_state =
+ CAM_FLASH_STATE_CONFIG;
break;
default:
CAM_ERR(CAM_FLASH, "Wrong cmd_type = %d",
@@ -553,21 +612,35 @@
case CAMERA_SENSOR_FLASH_CMD_TYPE_FIRE: {
CAM_DBG(CAM_FLASH,
"CAMERA_FLASH_CMD_TYPE_OPS case called");
- flash_operation_info =
- (struct cam_flash_set_on_off *) cmd_buf;
- if (!flash_operation_info) {
- CAM_ERR(CAM_FLASH, "flash_operation_info Null");
+ if ((fctrl->flash_state == CAM_FLASH_STATE_START) ||
+ (fctrl->flash_state ==
+ CAM_FLASH_STATE_CONFIG)) {
+ flash_operation_info =
+ (struct cam_flash_set_on_off *) cmd_buf;
+ if (!flash_operation_info) {
+ CAM_ERR(CAM_FLASH,
+ "flash_operation_info Null");
+ return -EINVAL;
+ }
+
+ fctrl->per_frame[frame_offset].opcode =
+ flash_operation_info->opcode;
+ fctrl->per_frame[frame_offset].cmn_attr.count =
+ flash_operation_info->count;
+ for (i = 0;
+ i < flash_operation_info->count; i++)
+ fctrl->per_frame[frame_offset].
+ led_current_ma[i]
+ = flash_operation_info->
+ led_current_ma[i];
+
+ } else {
+ CAM_ERR(CAM_FLASH,
+ "Rxed Update packets without linking");
+ fctrl->per_frame[frame_offset].
+ cmn_attr.is_settings_valid = false;
return -EINVAL;
}
-
- fctrl->per_frame[frame_offset].opcode =
- flash_operation_info->opcode;
- fctrl->per_frame[frame_offset].cmn_attr.count =
- flash_operation_info->count;
- for (i = 0; i < flash_operation_info->count; i++)
- fctrl->per_frame[frame_offset].led_current_ma[i]
- = flash_operation_info->
- led_current_ma[i];
break;
}
default:
@@ -668,9 +741,18 @@
break;
}
case CAM_PKT_NOP_OPCODE: {
- CAM_DBG(CAM_FLASH, "NOP Packet is Received: req_id: %u",
- csl_packet->header.request_id);
- goto update_req_mgr;
+ if ((fctrl->flash_state == CAM_FLASH_STATE_START) ||
+ (fctrl->flash_state == CAM_FLASH_STATE_CONFIG)) {
+ CAM_DBG(CAM_FLASH, "NOP Packet is Received: req_id: %u",
+ csl_packet->header.request_id);
+ goto update_req_mgr;
+ } else {
+ CAM_ERR(CAM_FLASH,
+ "Rxed Update packets without linking");
+ fctrl->per_frame[frame_offset].
+ cmn_attr.is_settings_valid = false;
+ return -EINVAL;
+ }
}
default:
CAM_ERR(CAM_FLASH, "Wrong Opcode : %d",
@@ -739,9 +821,7 @@
{
int rc = 0, i, j;
- if ((fctrl->flash_state == CAM_FLASH_STATE_LOW) ||
- (fctrl->flash_state == CAM_FLASH_STATE_HIGH))
- cam_flash_off(fctrl);
+ cam_flash_off(fctrl);
for (i = 0; i < MAX_PER_FRAME_ARRAY; i++) {
fctrl->per_frame[i].cmn_attr.request_id = 0;
@@ -760,7 +840,7 @@
if ((fctrl->flash_state == CAM_FLASH_STATE_START) &&
(fctrl->is_regulator_enabled == true)) {
- rc = cam_flash_prepare(fctrl, CAM_FLASH_STATE_STOP);
+ rc = cam_flash_prepare(fctrl, false);
if (rc)
CAM_ERR(CAM_FLASH, "Disable Regulator Failed rc: %d",
rc);
@@ -794,15 +874,13 @@
if (fctrl->flash_state == CAM_FLASH_STATE_INIT)
return;
- if (fctrl->flash_state == CAM_FLASH_STATE_ACQUIRE) {
- cam_flash_release_dev(fctrl);
- return;
+ if ((fctrl->flash_state == CAM_FLASH_STATE_CONFIG) ||
+ (fctrl->flash_state == CAM_FLASH_STATE_START)) {
+ rc = cam_flash_stop_dev(fctrl);
+ if (rc)
+ CAM_ERR(CAM_FLASH, "Stop Failed rc: %d", rc);
}
- rc = cam_flash_stop_dev(fctrl);
- if (rc)
- CAM_ERR(CAM_FLASH, "Stop Failed rc: %d", rc);
-
rc = cam_flash_release_dev(fctrl);
if (rc)
CAM_ERR(CAM_FLASH, "Release failed rc: %d", rc);
diff --git a/drivers/media/platform/msm/camera/cam_sensor_module/cam_flash/cam_flash_core.h b/drivers/media/platform/msm/camera/cam_sensor_module/cam_flash/cam_flash_core.h
index d5ea04c..f73409a 100644
--- a/drivers/media/platform/msm/camera/cam_sensor_module/cam_flash/cam_flash_core.h
+++ b/drivers/media/platform/msm/camera/cam_sensor_module/cam_flash/cam_flash_core.h
@@ -28,7 +28,7 @@
int cam_flash_flush_request(struct cam_req_mgr_flush_request *flush);
int cam_flash_off(struct cam_flash_ctrl *fctrl);
int cam_flash_prepare(struct cam_flash_ctrl *flash_ctrl,
- enum cam_flash_state state);
+ bool regulator_enable);
void cam_flash_shutdown(struct cam_flash_ctrl *flash_ctrl);
int cam_flash_stop_dev(struct cam_flash_ctrl *flash_ctrl);
int cam_flash_release_dev(struct cam_flash_ctrl *fctrl);
diff --git a/drivers/media/platform/msm/camera/cam_sensor_module/cam_flash/cam_flash_dev.c b/drivers/media/platform/msm/camera/cam_sensor_module/cam_flash/cam_flash_dev.c
index 2b371a3..eddbf97 100644
--- a/drivers/media/platform/msm/camera/cam_sensor_module/cam_flash/cam_flash_dev.c
+++ b/drivers/media/platform/msm/camera/cam_sensor_module/cam_flash/cam_flash_dev.c
@@ -131,7 +131,7 @@
}
case CAM_START_DEV: {
CAM_DBG(CAM_FLASH, "CAM_START_DEV");
- if (fctrl->flash_state != CAM_FLASH_STATE_ACQUIRE) {
+ if (fctrl->flash_state != CAM_FLASH_STATE_CONFIG) {
CAM_WARN(CAM_FLASH,
"Cannot apply Start Dev: Prev state: %d",
fctrl->flash_state);
@@ -139,7 +139,7 @@
goto release_mutex;
}
- rc = cam_flash_prepare(fctrl, CAM_FLASH_STATE_START);
+ rc = cam_flash_prepare(fctrl, true);
if (rc) {
CAM_ERR(CAM_FLASH,
"Enable Regulator Failed rc = %d", rc);
@@ -154,6 +154,7 @@
break;
}
case CAM_STOP_DEV: {
+ CAM_DBG(CAM_FLASH, "CAM_STOP_DEV ENTER");
if (fctrl->flash_state != CAM_FLASH_STATE_START) {
CAM_WARN(CAM_FLASH,
"Cannot apply Stop dev: Prev state is: %d",
diff --git a/drivers/media/platform/msm/camera/cam_sensor_module/cam_flash/cam_flash_dev.h b/drivers/media/platform/msm/camera/cam_sensor_module/cam_flash/cam_flash_dev.h
index bacf088..92726a9 100644
--- a/drivers/media/platform/msm/camera/cam_sensor_module/cam_flash/cam_flash_dev.h
+++ b/drivers/media/platform/msm/camera/cam_sensor_module/cam_flash/cam_flash_dev.h
@@ -50,10 +50,8 @@
enum cam_flash_state {
CAM_FLASH_STATE_INIT,
CAM_FLASH_STATE_ACQUIRE,
+ CAM_FLASH_STATE_CONFIG,
CAM_FLASH_STATE_START,
- CAM_FLASH_STATE_LOW,
- CAM_FLASH_STATE_HIGH,
- CAM_FLASH_STATE_STOP,
};
/**
diff --git a/drivers/media/platform/msm/camera/cam_sensor_module/cam_ois/cam_ois_core.c b/drivers/media/platform/msm/camera/cam_sensor_module/cam_ois/cam_ois_core.c
index 4e4b112..76f5b46 100644
--- a/drivers/media/platform/msm/camera/cam_sensor_module/cam_ois/cam_ois_core.c
+++ b/drivers/media/platform/msm/camera/cam_sensor_module/cam_ois/cam_ois_core.c
@@ -35,6 +35,7 @@
power_info->power_setting[0].seq_type = SENSOR_VAF;
power_info->power_setting[0].seq_val = CAM_VAF;
power_info->power_setting[0].config_val = 1;
+ power_info->power_setting[0].delay = 2;
power_info->power_down_setting_size = 1;
power_info->power_down_setting =
@@ -112,9 +113,21 @@
(struct cam_ois_soc_private *)o_ctrl->soc_info.soc_private;
power_info = &soc_private->power_info;
+ if ((power_info->power_setting == NULL) &&
+ (power_info->power_down_setting == NULL)) {
+ CAM_INFO(CAM_OIS,
+ "Using default power settings");
+ rc = cam_ois_construct_default_power_setting(power_info);
+ if (rc < 0) {
+ CAM_ERR(CAM_OIS,
+ "Construct default ois power setting failed.");
+ return rc;
+ }
+ }
+
/* Parse and fill vreg params for power up settings */
rc = msm_camera_fill_vreg_params(
- &o_ctrl->soc_info,
+ soc_info,
power_info->power_setting,
power_info->power_setting_size);
if (rc) {
@@ -125,12 +138,12 @@
/* Parse and fill vreg params for power down settings*/
rc = msm_camera_fill_vreg_params(
- &o_ctrl->soc_info,
+ soc_info,
power_info->power_down_setting,
power_info->power_down_setting_size);
if (rc) {
CAM_ERR(CAM_OIS,
- "failed to fill vreg params power down rc:%d", rc);
+ "failed to fill vreg params for power down rc:%d", rc);
return rc;
}
@@ -142,9 +155,6 @@
return rc;
}
- /* VREG needs some delay to power up */
- usleep_range(2000, 2050);
-
rc = camera_io_init(&o_ctrl->io_master_info);
if (rc)
CAM_ERR(CAM_OIS, "cci_init failed: rc: %d", rc);
@@ -152,6 +162,12 @@
return rc;
}
+/**
+ * cam_ois_power_down - power down OIS device
+ * @o_ctrl: ctrl structure
+ *
+ * Returns success or failure
+ */
static int cam_ois_power_down(struct cam_ois_ctrl_t *o_ctrl)
{
int32_t rc = 0;
@@ -392,6 +408,9 @@
static int cam_ois_pkt_parse(struct cam_ois_ctrl_t *o_ctrl, void *arg)
{
int32_t rc = 0;
+ int32_t i = 0;
+ uint32_t total_cmd_buf_in_bytes = 0;
+ struct common_header *cmm_hdr = NULL;
uint64_t generic_ptr;
struct cam_control *ioctl_ctrl = NULL;
struct cam_config_dev_cmd dev_config;
@@ -402,6 +421,9 @@
struct cam_packet *csl_packet = NULL;
size_t len_of_buff = 0;
uint32_t *offset = NULL, *cmd_buf;
+ struct cam_ois_soc_private *soc_private =
+ (struct cam_ois_soc_private *)o_ctrl->soc_info.soc_private;
+ struct cam_sensor_power_ctrl_t *power_info = &soc_private->power_info;
ioctl_ctrl = (struct cam_control *)arg;
if (copy_from_user(&dev_config, (void __user *) ioctl_ctrl->handle,
@@ -430,52 +452,94 @@
offset += (csl_packet->cmd_buf_offset / sizeof(uint32_t));
cmd_desc = (struct cam_cmd_buf_desc *)(offset);
- if ((csl_packet->num_cmd_buf < 2) &&
- (csl_packet->num_cmd_buf > 3)) {
- CAM_ERR(CAM_OIS, "wrong cmd Buffer count: %d",
- csl_packet->num_cmd_buf);
- return -EINVAL;
- }
+ /* Loop through multiple command buffers */
+ for (i = 0; i < csl_packet->num_cmd_buf; i++) {
+ total_cmd_buf_in_bytes = cmd_desc[i].length;
+ if (!total_cmd_buf_in_bytes)
+ continue;
- rc = cam_mem_get_cpu_buf(cmd_desc[0].mem_handle,
- (uint64_t *)&generic_ptr, &len_of_buff);
- if (rc < 0) {
- CAM_ERR(CAM_OIS, "Failed to get cpu buf");
- return rc;
- }
-
- cmd_buf = (uint32_t *)generic_ptr;
- cmd_buf += cmd_desc->offset / sizeof(uint32_t);
- rc = cam_ois_slaveInfo_pkt_parser(o_ctrl, cmd_buf);
- if (rc < 0) {
- CAM_ERR(CAM_OIS, "Failed in parsing the pkt");
- return rc;
- }
-
- cmd_buf += (sizeof(struct cam_cmd_i2c_info)/sizeof(uint32_t));
-
- i2c_reg_settings = &(o_ctrl->i2c_init_data);
- i2c_reg_settings->is_settings_valid = 1;
- i2c_reg_settings->request_id = 0;
- rc = cam_sensor_i2c_command_parser(i2c_reg_settings,
- &cmd_desc[1], 1);
- if (rc < 0) {
- CAM_ERR(CAM_OIS, "OIS pkt parsing failed: %d",
- rc);
- return rc;
- }
-
- if (o_ctrl->is_ois_calib) {
- i2c_reg_settings = &(o_ctrl->i2c_calib_data);
- i2c_reg_settings->is_settings_valid = 1;
- i2c_reg_settings->request_id = 0;
- rc = cam_sensor_i2c_command_parser(i2c_reg_settings,
- &cmd_desc[2], 1);
+ rc = cam_mem_get_cpu_buf(cmd_desc[i].mem_handle,
+ (uint64_t *)&generic_ptr, &len_of_buff);
if (rc < 0) {
- CAM_ERR(CAM_OIS,
- "OIS pkt parsing failed: %d", rc);
+ CAM_ERR(CAM_OIS, "Failed to get cpu buf");
return rc;
}
+ cmd_buf = (uint32_t *)generic_ptr;
+ if (!cmd_buf) {
+ CAM_ERR(CAM_OIS, "invalid cmd buf");
+ return -EINVAL;
+ }
+ cmd_buf += cmd_desc->offset / sizeof(uint32_t);
+ cmm_hdr = (struct common_header *)cmd_buf;
+
+ switch (cmm_hdr->cmd_type) {
+ case CAMERA_SENSOR_CMD_TYPE_I2C_INFO:
+ rc = cam_ois_slaveInfo_pkt_parser(
+ o_ctrl, cmd_buf);
+ if (rc < 0) {
+ CAM_ERR(CAM_OIS,
+ "Failed in parsing slave info");
+ return rc;
+ }
+ break;
+ case CAMERA_SENSOR_CMD_TYPE_PWR_UP:
+ case CAMERA_SENSOR_CMD_TYPE_PWR_DOWN:
+ CAM_DBG(CAM_OIS,
+ "Received power settings buffer");
+ rc = cam_sensor_update_power_settings(
+ cmd_buf,
+ total_cmd_buf_in_bytes,
+ power_info);
+ if (rc) {
+ CAM_ERR(CAM_OIS,
+ "Failed: parse power settings");
+ return rc;
+ }
+ break;
+ default:
+ if (o_ctrl->i2c_init_data.is_settings_valid == 0) {
+ CAM_DBG(CAM_OIS,
+ "Received init settings");
+ i2c_reg_settings =
+ &(o_ctrl->i2c_init_data);
+ i2c_reg_settings->is_settings_valid = 1;
+ i2c_reg_settings->request_id = 0;
+ rc = cam_sensor_i2c_command_parser(
+ i2c_reg_settings,
+ &cmd_desc[i], 1);
+ if (rc < 0) {
+ CAM_ERR(CAM_OIS,
+ "init parsing failed: %d", rc);
+ return rc;
+ }
+ } else if ((o_ctrl->is_ois_calib != 0) &&
+ (o_ctrl->i2c_calib_data.
+ is_settings_valid == 0)) {
+ CAM_DBG(CAM_OIS,
+ "Received calib settings");
+ i2c_reg_settings = &(o_ctrl->i2c_calib_data);
+ i2c_reg_settings->is_settings_valid = 1;
+ i2c_reg_settings->request_id = 0;
+ rc = cam_sensor_i2c_command_parser(
+ i2c_reg_settings,
+ &cmd_desc[i], 1);
+ if (rc < 0) {
+ CAM_ERR(CAM_OIS,
+ "Calib parsing failed: %d", rc);
+ return rc;
+ }
+ }
+ break;
+ }
+ }
+
+ if (o_ctrl->cam_ois_state != CAM_OIS_CONFIG) {
+ rc = cam_ois_power_up(o_ctrl);
+ if (rc) {
+ CAM_ERR(CAM_OIS, " OIS Power up failed");
+ return rc;
+ }
+ o_ctrl->cam_ois_state = CAM_OIS_CONFIG;
}
if (o_ctrl->ois_fw_flag) {
@@ -515,6 +579,13 @@
}
break;
case CAM_OIS_PACKET_OPCODE_OIS_CONTROL:
+ if (o_ctrl->cam_ois_state < CAM_OIS_CONFIG) {
+ rc = -EINVAL;
+ CAM_WARN(CAM_OIS,
+ "Not in right state to control OIS: %d",
+ o_ctrl->cam_ois_state);
+ return rc;
+ }
offset = (uint32_t *)&csl_packet->payload;
offset += (csl_packet->cmd_buf_offset / sizeof(uint32_t));
cmd_desc = (struct cam_cmd_buf_desc *)(offset);
@@ -555,12 +626,13 @@
if (o_ctrl->cam_ois_state == CAM_OIS_INIT)
return;
- if ((o_ctrl->cam_ois_state == CAM_OIS_START) ||
- (o_ctrl->cam_ois_state == CAM_OIS_ACQUIRE)) {
+ if (o_ctrl->cam_ois_state >= CAM_OIS_CONFIG) {
rc = cam_ois_power_down(o_ctrl);
if (rc < 0)
CAM_ERR(CAM_OIS, "OIS Power down failed");
+ }
+ if (o_ctrl->cam_ois_state >= CAM_OIS_ACQUIRE) {
rc = cam_destroy_device_hdl(o_ctrl->bridge_intf.device_hdl);
if (rc < 0)
CAM_ERR(CAM_OIS, "destroying the device hdl");
@@ -611,16 +683,10 @@
goto release_mutex;
}
- rc = cam_ois_power_up(o_ctrl);
- if (rc) {
- CAM_ERR(CAM_OIS, " OIS Power up failed");
- goto release_mutex;
- }
-
o_ctrl->cam_ois_state = CAM_OIS_ACQUIRE;
break;
case CAM_START_DEV:
- if (o_ctrl->cam_ois_state != CAM_OIS_ACQUIRE) {
+ if (o_ctrl->cam_ois_state != CAM_OIS_CONFIG) {
rc = -EINVAL;
CAM_WARN(CAM_OIS,
"Not in right state for start : %d",
@@ -637,18 +703,19 @@
}
break;
case CAM_RELEASE_DEV:
- if (o_ctrl->cam_ois_state != CAM_OIS_ACQUIRE) {
+ if (o_ctrl->cam_ois_state == CAM_OIS_START) {
rc = -EINVAL;
CAM_WARN(CAM_OIS,
- "Not in right state for release : %d",
- o_ctrl->cam_ois_state);
+ "Cant release ois: in start state");
goto release_mutex;
}
- rc = cam_ois_power_down(o_ctrl);
- if (rc < 0) {
- CAM_ERR(CAM_OIS, "OIS Power down failed");
- goto release_mutex;
+ if (o_ctrl->cam_ois_state == CAM_OIS_CONFIG) {
+ rc = cam_ois_power_down(o_ctrl);
+ if (rc < 0) {
+ CAM_ERR(CAM_OIS, "OIS Power down failed");
+ goto release_mutex;
+ }
}
if (o_ctrl->bridge_intf.device_hdl == -1) {
@@ -673,7 +740,7 @@
"Not in right state for stop : %d",
o_ctrl->cam_ois_state);
}
- o_ctrl->cam_ois_state = CAM_OIS_ACQUIRE;
+ o_ctrl->cam_ois_state = CAM_OIS_CONFIG;
break;
default:
CAM_ERR(CAM_OIS, "invalid opcode");
diff --git a/drivers/media/platform/msm/camera/cam_sensor_module/cam_ois/cam_ois_dev.c b/drivers/media/platform/msm/camera/cam_sensor_module/cam_ois/cam_ois_dev.c
index 5e1d719..d742acf 100644
--- a/drivers/media/platform/msm/camera/cam_sensor_module/cam_ois/cam_ois_dev.c
+++ b/drivers/media/platform/msm/camera/cam_sensor_module/cam_ois/cam_ois_dev.c
@@ -197,27 +197,19 @@
rc = cam_ois_driver_soc_init(o_ctrl);
if (rc) {
CAM_ERR(CAM_OIS, "failed: cam_sensor_parse_dt rc %d", rc);
- goto octrl_free;
+ goto soc_free;
}
rc = cam_ois_init_subdev_param(o_ctrl);
if (rc)
- goto octrl_free;
-
- rc = cam_ois_construct_default_power_setting(
- &soc_private->power_info);
- if (rc < 0) {
- CAM_ERR(CAM_OIS,
- "Construct default ois power setting failed.");
- goto unreg_subdev;
- }
+ goto soc_free;
o_ctrl->cam_ois_state = CAM_OIS_INIT;
return rc;
-unreg_subdev:
- cam_unregister_subdev(&(o_ctrl->v4l2_dev_str));
+soc_free:
+ kfree(soc_private);
octrl_free:
kfree(o_ctrl);
probe_failure:
@@ -285,6 +277,7 @@
goto free_cci_client;
}
o_ctrl->soc_info.soc_private = soc_private;
+ soc_private->power_info.dev = &pdev->dev;
INIT_LIST_HEAD(&(o_ctrl->i2c_init_data.list_head));
INIT_LIST_HEAD(&(o_ctrl->i2c_calib_data.list_head));
@@ -307,14 +300,6 @@
}
o_ctrl->bridge_intf.device_hdl = -1;
- rc = cam_ois_construct_default_power_setting(
- &soc_private->power_info);
- if (rc < 0) {
- CAM_ERR(CAM_OIS,
- "Construct default ois power setting failed.");
- goto unreg_subdev;
- }
-
platform_set_drvdata(pdev, o_ctrl);
v4l2_set_subdevdata(&o_ctrl->v4l2_dev_str.sd, o_ctrl);
diff --git a/drivers/media/platform/msm/camera/cam_sensor_module/cam_ois/cam_ois_dev.h b/drivers/media/platform/msm/camera/cam_sensor_module/cam_ois/cam_ois_dev.h
index 80f1e84..3b7195e 100644
--- a/drivers/media/platform/msm/camera/cam_sensor_module/cam_ois/cam_ois_dev.h
+++ b/drivers/media/platform/msm/camera/cam_sensor_module/cam_ois/cam_ois_dev.h
@@ -34,6 +34,7 @@
enum cam_ois_state {
CAM_OIS_INIT,
CAM_OIS_ACQUIRE,
+ CAM_OIS_CONFIG,
CAM_OIS_START,
};
diff --git a/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor/cam_sensor_core.c b/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor/cam_sensor_core.c
index 97158e4..9ce7a21 100644
--- a/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor/cam_sensor_core.c
+++ b/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor/cam_sensor_core.c
@@ -165,27 +165,41 @@
}
case CAM_SENSOR_PACKET_OPCODE_SENSOR_UPDATE: {
- i2c_reg_settings =
- &i2c_data->
- per_frame[csl_packet->header.request_id %
- MAX_PER_FRAME_ARRAY];
- CAM_DBG(CAM_SENSOR, "Received Packet: %lld",
+ if ((s_ctrl->sensor_state == CAM_SENSOR_CONFIG) ||
+ (s_ctrl->sensor_state == CAM_SENSOR_START)) {
+ i2c_reg_settings =
+ &i2c_data->
+ per_frame[csl_packet->header.request_id %
+ MAX_PER_FRAME_ARRAY];
+ CAM_DBG(CAM_SENSOR, "Received Packet: %lld",
csl_packet->header.request_id % MAX_PER_FRAME_ARRAY);
- if (i2c_reg_settings->is_settings_valid == 1) {
- CAM_ERR(CAM_SENSOR,
- "Already some pkt in offset req : %lld",
- csl_packet->header.request_id);
- rc = delete_request(i2c_reg_settings);
- if (rc < 0) {
+ if (i2c_reg_settings->is_settings_valid == 1) {
CAM_ERR(CAM_SENSOR,
+ "Already some pkt in offset req : %lld",
+ csl_packet->header.request_id);
+ rc = delete_request(i2c_reg_settings);
+ if (rc < 0) {
+ CAM_ERR(CAM_SENSOR,
"Failed in Deleting the err: %d", rc);
- return rc;
+ return rc;
+ }
}
+ } else {
+ CAM_ERR(CAM_SENSOR,
+ "Rxed Update packets without linking");
+ return -EINVAL;
}
break;
}
case CAM_SENSOR_PACKET_OPCODE_SENSOR_NOP: {
- cam_sensor_update_req_mgr(s_ctrl, csl_packet);
+ if ((s_ctrl->sensor_state == CAM_SENSOR_CONFIG) ||
+ (s_ctrl->sensor_state == CAM_SENSOR_START)) {
+ cam_sensor_update_req_mgr(s_ctrl, csl_packet);
+ } else {
+ CAM_ERR(CAM_SENSOR,
+ "Rxed Update packets without linking");
+ rc = -EINVAL;
+ }
return rc;
}
default:
@@ -476,22 +490,18 @@
cam_sensor_release_resource(s_ctrl);
- if ((s_ctrl->sensor_state == CAM_SENSOR_START) ||
- (s_ctrl->sensor_state == CAM_SENSOR_ACQUIRE)) {
+ if (s_ctrl->sensor_state >= CAM_SENSOR_ACQUIRE)
cam_sensor_power_down(s_ctrl);
- rc = cam_destroy_device_hdl(s_ctrl->bridge_intf.device_hdl);
- if (rc < 0)
- CAM_ERR(CAM_SENSOR, " failed destroying dhdl");
- s_ctrl->bridge_intf.device_hdl = -1;
- s_ctrl->bridge_intf.link_hdl = -1;
- s_ctrl->bridge_intf.session_hdl = -1;
- s_ctrl->sensor_state = CAM_SENSOR_PROBE;
- }
- if (s_ctrl->sensor_state == CAM_SENSOR_PROBE) {
- kfree(power_info->power_setting);
- kfree(power_info->power_down_setting);
- }
+ rc = cam_destroy_device_hdl(s_ctrl->bridge_intf.device_hdl);
+ if (rc < 0)
+ CAM_ERR(CAM_SENSOR, " failed destroying dhdl");
+ s_ctrl->bridge_intf.device_hdl = -1;
+ s_ctrl->bridge_intf.link_hdl = -1;
+ s_ctrl->bridge_intf.session_hdl = -1;
+
+ kfree(power_info->power_setting);
+ kfree(power_info->power_down_setting);
s_ctrl->sensor_state = CAM_SENSOR_INIT;
}
@@ -614,7 +624,6 @@
rc = cam_sensor_power_up(s_ctrl);
if (rc < 0) {
CAM_ERR(CAM_SENSOR, "power up failed");
- cam_sensor_power_down(s_ctrl);
kfree(pu);
kfree(pd);
goto release_mutex;
@@ -697,7 +706,8 @@
}
break;
case CAM_RELEASE_DEV: {
- if (s_ctrl->sensor_state != CAM_SENSOR_ACQUIRE) {
+ if ((s_ctrl->sensor_state < CAM_SENSOR_ACQUIRE) ||
+ (s_ctrl->sensor_state > CAM_SENSOR_CONFIG)) {
rc = -EINVAL;
CAM_WARN(CAM_SENSOR,
"Not in right state to release : %d",
@@ -744,7 +754,7 @@
break;
}
case CAM_START_DEV: {
- if (s_ctrl->sensor_state != CAM_SENSOR_ACQUIRE) {
+ if (s_ctrl->sensor_state != CAM_SENSOR_CONFIG) {
rc = -EINVAL;
CAM_WARN(CAM_SENSOR,
"Not in right state to start : %d",
@@ -826,6 +836,7 @@
"Fail in deleting the config settings");
goto release_mutex;
}
+ s_ctrl->sensor_state = CAM_SENSOR_CONFIG;
s_ctrl->i2c_data.config_settings.request_id = -1;
}
}
@@ -1000,7 +1011,6 @@
return rc;
}
}
- i2c_set->is_settings_valid = 0;
}
} else {
offset = req_id % MAX_PER_FRAME_ARRAY;
diff --git a/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor/cam_sensor_dev.h b/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor/cam_sensor_dev.h
index 8c49837..624ea29 100644
--- a/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor/cam_sensor_dev.h
+++ b/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor/cam_sensor_dev.h
@@ -51,8 +51,8 @@
enum cam_sensor_state_t {
CAM_SENSOR_INIT,
- CAM_SENSOR_PROBE,
CAM_SENSOR_ACQUIRE,
+ CAM_SENSOR_CONFIG,
CAM_SENSOR_START,
};
diff --git a/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor_io/cam_sensor_io.c b/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor_io/cam_sensor_io.c
index d69ff47..7a6d7fd 100644
--- a/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor_io/cam_sensor_io.c
+++ b/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor_io/cam_sensor_io.c
@@ -15,8 +15,8 @@
int32_t camera_io_dev_poll(struct camera_io_master *io_master_info,
uint32_t addr, uint16_t data, uint32_t data_mask,
- enum camera_sensor_i2c_type data_type,
enum camera_sensor_i2c_type addr_type,
+ enum camera_sensor_i2c_type data_type,
uint32_t delay_ms)
{
int16_t mask = data_mask & 0xFF;
diff --git a/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor_io/cam_sensor_io.h b/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor_io/cam_sensor_io.h
index f6620c0..ec5ed25 100644
--- a/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor_io/cam_sensor_io.h
+++ b/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor_io/cam_sensor_io.h
@@ -110,8 +110,8 @@
*/
int32_t camera_io_dev_poll(struct camera_io_master *io_master_info,
uint32_t addr, uint16_t data, uint32_t data_mask,
- enum camera_sensor_i2c_type data_type,
enum camera_sensor_i2c_type addr_type,
+ enum camera_sensor_i2c_type data_type,
uint32_t delay_ms);
#include "cam_sensor_i2c.h"
diff --git a/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor_utils/cam_sensor_cmn_header.h b/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor_utils/cam_sensor_cmn_header.h
index 2e91efc..72ca737 100644
--- a/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor_utils/cam_sensor_cmn_header.h
+++ b/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor_utils/cam_sensor_cmn_header.h
@@ -50,11 +50,13 @@
CAMERA_SENSOR_CMD_TYPE_I2C_CONT_WR,
CAMERA_SENSOR_CMD_TYPE_I2C_CONT_RD,
CAMERA_SENSOR_CMD_TYPE_WAIT,
- CAMERA_SENSOR_FLASH_CMD_TYPE_INIT,
+ CAMERA_SENSOR_FLASH_CMD_TYPE_INIT_INFO,
CAMERA_SENSOR_FLASH_CMD_TYPE_FIRE,
CAMERA_SENSOR_FLASH_CMD_TYPE_RER,
CAMERA_SENSOR_FLASH_CMD_TYPE_QUERYCURR,
CAMERA_SENSOR_FLASH_CMD_TYPE_WIDGET,
+ CAMERA_SENSOR_CMD_TYPE_RD_DATA,
+ CAMERA_SENSOR_FLASH_CMD_TYPE_INIT_FIRE,
CAMERA_SENSOR_CMD_TYPE_MAX,
};
diff --git a/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor_utils/cam_sensor_util.c b/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor_utils/cam_sensor_util.c
index 37784b4..82ba24f 100644
--- a/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor_utils/cam_sensor_util.c
+++ b/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor_utils/cam_sensor_util.c
@@ -421,7 +421,7 @@
if (power_setting[i].seq_type < SENSOR_MCLK ||
power_setting[i].seq_type >= SENSOR_SEQ_TYPE_MAX) {
- CAM_ERR(CAM_SENSOR, "failed: Invalid Seq type\n",
+ CAM_ERR(CAM_SENSOR, "failed: Invalid Seq type: %d",
power_setting[i].seq_type);
return -EINVAL;
}
@@ -676,14 +676,12 @@
struct cam_cmd_power *pwr_cmd =
(struct cam_cmd_power *)ptr;
- power_info->
- power_setting_size +=
- pwr_cmd->count;
+ power_info->power_setting_size += pwr_cmd->count;
scr = ptr + sizeof(struct cam_cmd_power);
tot_size = tot_size + sizeof(struct cam_cmd_power);
if (pwr_cmd->count == 0)
- CAM_DBG(CAM_SENSOR, "Un expected Command");
+ CAM_WARN(CAM_SENSOR, "Un expected Command");
for (i = 0; i < pwr_cmd->count; i++, pwr_up++) {
power_info->
@@ -979,7 +977,7 @@
GFP_KERNEL);
if (!*pgpio_num_info)
return -ENOMEM;
- gpio_num_info = *pgpio_num_info;
+ gpio_num_info = *pgpio_num_info;
rc = of_property_read_u32(of_node, "gpio-vana", &val);
if (rc != -EINVAL) {
@@ -1266,6 +1264,8 @@
CAM_ERR(CAM_SENSOR,
"Cannot set shared pin to active state");
+ CAM_DBG(CAM_SENSOR, "power setting size: %d", ctrl->power_setting_size);
+
for (index = 0; index < ctrl->power_setting_size; index++) {
CAM_DBG(CAM_SENSOR, "index: %d", index);
power_setting = &ctrl->power_setting[index];
diff --git a/drivers/media/platform/msm/camera/cam_sync/cam_sync.c b/drivers/media/platform/msm/camera/cam_sync/cam_sync.c
index ae9f74c..46e9d5d 100644
--- a/drivers/media/platform/msm/camera/cam_sync/cam_sync.c
+++ b/drivers/media/platform/msm/camera/cam_sync/cam_sync.c
@@ -254,6 +254,12 @@
signalable_row = sync_dev->sync_table + list_info->sync_obj;
spin_lock_bh(&sync_dev->row_spinlocks[list_info->sync_obj]);
+ if (signalable_row->state == CAM_SYNC_STATE_INVALID) {
+ spin_unlock_bh(
+ &sync_dev->row_spinlocks[list_info->sync_obj]);
+ continue;
+ }
+
/* Dispatch kernel callbacks if any were registered earlier */
list_for_each_entry_safe(sync_cb,
temp_sync_cb, &signalable_row->callback_list, list) {
diff --git a/drivers/media/platform/msm/camera/cam_sync/cam_sync_util.c b/drivers/media/platform/msm/camera/cam_sync/cam_sync_util.c
index 826253c..afac68d 100644
--- a/drivers/media/platform/msm/camera/cam_sync/cam_sync_util.c
+++ b/drivers/media/platform/msm/camera/cam_sync/cam_sync_util.c
@@ -306,6 +306,10 @@
row->state = CAM_SYNC_STATE_INVALID;
memset(row, 0, sizeof(*row));
clear_bit(idx, sync_dev->bitmap);
+ INIT_LIST_HEAD(&row->callback_list);
+ INIT_LIST_HEAD(&row->parents_list);
+ INIT_LIST_HEAD(&row->children_list);
+ INIT_LIST_HEAD(&row->user_payload_list);
spin_unlock_bh(&sync_dev->row_spinlocks[idx]);
return 0;
diff --git a/drivers/media/platform/msm/camera/cam_utils/cam_debug_util.c b/drivers/media/platform/msm/camera/cam_utils/cam_debug_util.c
index f451155..26f2ba1 100644
--- a/drivers/media/platform/msm/camera/cam_utils/cam_debug_util.c
+++ b/drivers/media/platform/msm/camera/cam_utils/cam_debug_util.c
@@ -94,43 +94,19 @@
return name;
}
-void cam_debug_log(unsigned int module_id, enum cam_debug_level dbg_level,
- const char *func, const int line, const char *fmt, ...)
+void cam_debug_log(unsigned int module_id, const char *func, const int line,
+ const char *fmt, ...)
{
char str_buffer[STR_BUFFER_MAX_LENGTH];
va_list args;
va_start(args, fmt);
- switch (dbg_level) {
- case CAM_LEVEL_DBG:
- if (debug_mdl & module_id) {
- vsnprintf(str_buffer, STR_BUFFER_MAX_LENGTH, fmt, args);
- pr_info("CAM_DBG: %s: %s: %d: %s\n",
- cam_get_module_name(module_id),
- func, line, str_buffer);
- va_end(args);
- }
- break;
- case CAM_LEVEL_ERR:
+ if (debug_mdl & module_id) {
vsnprintf(str_buffer, STR_BUFFER_MAX_LENGTH, fmt, args);
- pr_err("CAM_ERR: %s: %s: %d: %s\n",
- cam_get_module_name(module_id), func, line, str_buffer);
+ pr_info("CAM_DBG: %s: %s: %d: %s\n",
+ cam_get_module_name(module_id),
+ func, line, str_buffer);
va_end(args);
- break;
- case CAM_LEVEL_INFO:
- vsnprintf(str_buffer, STR_BUFFER_MAX_LENGTH, fmt, args);
- pr_info("CAM_INFO: %s: %s: %d: %s\n",
- cam_get_module_name(module_id), func, line, str_buffer);
- va_end(args);
- break;
- case CAM_LEVEL_WARN:
- vsnprintf(str_buffer, STR_BUFFER_MAX_LENGTH, fmt, args);
- pr_warn("CAM_WARN: %s: %s: %d: %s\n",
- cam_get_module_name(module_id), func, line, str_buffer);
- va_end(args);
- break;
- default:
- break;
}
}
diff --git a/drivers/media/platform/msm/camera/cam_utils/cam_debug_util.h b/drivers/media/platform/msm/camera/cam_utils/cam_debug_util.h
index c0160c4..4e97100 100644
--- a/drivers/media/platform/msm/camera/cam_utils/cam_debug_util.h
+++ b/drivers/media/platform/msm/camera/cam_utils/cam_debug_util.h
@@ -38,13 +38,6 @@
#define STR_BUFFER_MAX_LENGTH 1024
-enum cam_debug_level {
- CAM_LEVEL_INFO,
- CAM_LEVEL_WARN,
- CAM_LEVEL_ERR,
- CAM_LEVEL_DBG,
-};
-
/*
* cam_debug_log()
*
@@ -52,15 +45,14 @@
* respective debug logs
*
* @module_id : Respective Module ID which is calling this function
- * @dbg_level : Debug level from cam_module_debug_level enum entries
* @func : Function which is calling to print logs
* @line : Line number associated with the function which is calling
* to print log
* @fmt : Formatted string which needs to be print in the log
*
*/
-void cam_debug_log(unsigned int module_id, enum cam_debug_level dbg_level,
- const char *func, const int line, const char *fmt, ...);
+void cam_debug_log(unsigned int module_id, const char *func, const int line,
+ const char *fmt, ...);
/*
* cam_get_module_name()
@@ -80,8 +72,8 @@
* @args : Arguments which needs to be print in log
*/
#define CAM_ERR(__module, fmt, args...) \
- cam_debug_log(__module, CAM_LEVEL_ERR, __func__, __LINE__, fmt, ##args)
-
+ pr_err("CAM_ERR: %s: %s: %d " fmt "\n", \
+ cam_get_module_name(__module), __func__, __LINE__, ##args)
/*
* CAM_WARN
* @brief : This Macro will print warning logs
@@ -91,8 +83,8 @@
* @args : Arguments which needs to be print in log
*/
#define CAM_WARN(__module, fmt, args...) \
- cam_debug_log(__module, CAM_LEVEL_WARN, __func__, __LINE__, fmt, ##args)
-
+ pr_warn("CAM_WARN: %s: %s: %d " fmt "\n", \
+ cam_get_module_name(__module), __func__, __LINE__, ##args)
/*
* CAM_INFO
* @brief : This Macro will print Information logs
@@ -102,8 +94,8 @@
* @args : Arguments which needs to be print in log
*/
#define CAM_INFO(__module, fmt, args...) \
- cam_debug_log(__module, CAM_LEVEL_INFO, __func__, __LINE__, fmt, ##args)
-
+ pr_info("CAM_INFO: %s: %s: %d " fmt "\n", \
+ cam_get_module_name(__module), __func__, __LINE__, ##args)
/*
* CAM_DBG
* @brief : This Macro will print debug logs when enabled using GROUP
@@ -113,14 +105,14 @@
* @args : Arguments which needs to be print in log
*/
#define CAM_DBG(__module, fmt, args...) \
- cam_debug_log(__module, CAM_LEVEL_DBG, __func__, __LINE__, fmt, ##args)
+ cam_debug_log(__module, __func__, __LINE__, fmt, ##args)
/*
* CAM_ERR_RATE_LIMIT
* @brief : This Macro will prevent error print logs with ratelimit
*/
#define CAM_ERR_RATE_LIMIT(__module, fmt, args...) \
- pr_err_ratelimited("CAM_ERR: %s: %s: %d" fmt "\n", \
+ pr_err_ratelimited("CAM_ERR: %s: %s: %d " fmt "\n", \
cam_get_module_name(__module), __func__, __LINE__, ##args)
#endif /* _CAM_DEBUG_UTIL_H_ */
diff --git a/drivers/media/platform/msm/camera/cam_utils/cam_io_util.c b/drivers/media/platform/msm/camera/cam_utils/cam_io_util.c
index c1fbb2a..1b5fd9f 100644
--- a/drivers/media/platform/msm/camera/cam_utils/cam_io_util.c
+++ b/drivers/media/platform/msm/camera/cam_utils/cam_io_util.c
@@ -22,7 +22,7 @@
return -EINVAL;
CAM_DBG(CAM_UTIL, "0x%pK %08x", addr, data);
- writel_relaxed(data, addr);
+ writel_relaxed_no_log(data, addr);
return 0;
}
@@ -35,7 +35,7 @@
CAM_DBG(CAM_UTIL, "0x%pK %08x", addr, data);
/* Ensure previous writes are done */
wmb();
- writel_relaxed(data, addr);
+ writel_relaxed_no_log(data, addr);
return 0;
}
diff --git a/drivers/media/platform/msm/camera/cam_utils/cam_packet_util.c b/drivers/media/platform/msm/camera/cam_utils/cam_packet_util.c
index aecce12..30ab075 100644
--- a/drivers/media/platform/msm/camera/cam_utils/cam_packet_util.c
+++ b/drivers/media/platform/msm/camera/cam_utils/cam_packet_util.c
@@ -211,7 +211,7 @@
rc = cam_mem_get_cpu_buf(cmd_buf->mem_handle, &cpu_addr, &buf_size);
if (rc || !cpu_addr || (buf_size == 0)) {
CAM_ERR(CAM_UTIL, "Failed in Get cpu addr, rc=%d, cpu_addr=%pK",
- rc, cpu_addr);
+ rc, (void *)cpu_addr);
return rc;
}
@@ -219,7 +219,7 @@
CAM_DBG(CAM_UTIL,
"GenericCmdBuffer cpuaddr=%pK, blobptr=%pK, len=%d",
- cpu_addr, blob_ptr, cmd_buf->length);
+ (void *)cpu_addr, (void *)blob_ptr, cmd_buf->length);
len_read = 0;
while (len_read < cmd_buf->length) {
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 07fb944..786107b 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
@@ -132,7 +132,7 @@
uint32_t clk_index, unsigned long clk_rate)
{
if (!soc_info || (clk_index >= soc_info->num_clk) || (clk_rate == 0)) {
- CAM_ERR(CAM_UTIL, "Invalid input params %pK, %d %lld",
+ CAM_ERR(CAM_UTIL, "Invalid input params %pK, %d %lu",
soc_info, clk_index, clk_rate);
return clk_rate;
}
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 c85d255..8eef152 100644
--- a/drivers/media/platform/msm/sde/rotator/sde_rotator_base.h
+++ b/drivers/media/platform/msm/sde/rotator/sde_rotator_base.h
@@ -198,6 +198,7 @@
u32 offset;
u32 len;
enum sde_rot_regdump_access access;
+ u32 value;
};
struct sde_rot_lut_cfg {
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 fb74dab..916f978 100644
--- a/drivers/media/platform/msm/sde/rotator/sde_rotator_debug.c
+++ b/drivers/media/platform/msm/sde/rotator/sde_rotator_debug.c
@@ -422,7 +422,12 @@
head = ®dump[i];
if (head->access == SDE_ROT_REGDUMP_WRITE) {
- writel_relaxed(1, mdata->sde_io.base + head->offset);
+ if (head->len != 1) {
+ SDEROT_ERR("invalid write len %u\n", head->len);
+ continue;
+ }
+ writel_relaxed(head->value,
+ mdata->sde_io.base + head->offset);
/* Make sure write go through */
wmb();
} else {
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 c94830a..7c36934 100644
--- a/drivers/media/platform/msm/sde/rotator/sde_rotator_r3.c
+++ b/drivers/media/platform/msm/sde/rotator/sde_rotator_r3.c
@@ -538,13 +538,13 @@
* REGDMA RAM should be dump at last.
*/
{ "SDEROT_REGDMA_RESET", ROTTOP_SW_RESET_OVERRIDE, 1,
- SDE_ROT_REGDUMP_WRITE },
+ SDE_ROT_REGDUMP_WRITE, 1 },
{ "SDEROT_REGDMA_RAM", SDE_ROT_REGDMA_RAM_OFFSET, 0x2000,
SDE_ROT_REGDUMP_READ },
{ "SDEROT_VBIF_NRT", SDE_ROT_VBIF_NRT_OFFSET, 0x590,
SDE_ROT_REGDUMP_VBIF },
- { "SDEROT_REGDMA_RESET", ROTTOP_SW_RESET_OVERRIDE, 0,
- SDE_ROT_REGDUMP_WRITE },
+ { "SDEROT_REGDMA_RESET", ROTTOP_SW_RESET_OVERRIDE, 1,
+ SDE_ROT_REGDUMP_WRITE, 0 },
};
struct sde_rot_cdp_params {
diff --git a/drivers/media/platform/msm/vidc/msm_venc.c b/drivers/media/platform/msm/vidc/msm_venc.c
index ba49f24..7bb6d89 100644
--- a/drivers/media/platform/msm/vidc/msm_venc.c
+++ b/drivers/media/platform/msm/vidc/msm_venc.c
@@ -2274,11 +2274,8 @@
struct hal_frame_size blur_res;
struct hal_quantization_range qp_range;
struct hal_quantization qp;
- struct hal_hdr10_pq_sei hdr10_sei_params;
- struct msm_vidc_mastering_display_colour_sei_payload *mdisp_sei
- = &(hdr10_sei_params.disp_color_sei);
- struct msm_vidc_content_light_level_sei_payload *cll_sei
- = &(hdr10_sei_params.cll_sei);
+ struct msm_vidc_mastering_display_colour_sei_payload *mdisp_sei = NULL;
+ struct msm_vidc_content_light_level_sei_payload *cll_sei = NULL;
if (!inst || !inst->core || !inst->core->device || !ctrl) {
dprintk(VIDC_ERR, "%s invalid parameters\n", __func__);
@@ -2293,6 +2290,9 @@
control = ctrl->controls;
+ mdisp_sei = &(inst->hdr10_sei_params.disp_color_sei);
+ cll_sei = &(inst->hdr10_sei_params.cll_sei);
+
for (i = 0; i < ctrl->count; i++) {
switch (control[i].id) {
case V4L2_CID_MPEG_VIDC_VIDEO_LTRMODE:
@@ -2429,9 +2429,9 @@
break;
case V4L2_CID_MPEG_VIDC_VENC_HDR_INFO:
if (control[i].value ==
- V4L2_MPEG_VIDC_VENC_HDR_INFO_DISABLED)
+ V4L2_MPEG_VIDC_VENC_HDR_INFO_DISABLED ||
+ !mdisp_sei || !cll_sei)
break;
- memset(&hdr10_sei_params, 0, sizeof(hdr10_sei_params));
i++;
while (i < ctrl->count) {
switch (control[i].id) {
@@ -2494,7 +2494,7 @@
}
property_id =
HAL_PARAM_VENC_HDR10_PQ_SEI;
- pdata = &hdr10_sei_params;
+ pdata = &inst->hdr10_sei_params;
break;
default:
dprintk(VIDC_ERR, "Invalid id set: %d\n",
diff --git a/drivers/media/platform/msm/vidc/msm_vidc_clocks.c b/drivers/media/platform/msm/vidc/msm_vidc_clocks.c
index 1d22077..dc9302e 100644
--- a/drivers/media/platform/msm/vidc/msm_vidc_clocks.c
+++ b/drivers/media/platform/msm/vidc/msm_vidc_clocks.c
@@ -640,8 +640,8 @@
else if (temp->clk_data.core_id == VIDC_CORE_ID_2)
freq_core_2 += temp->clk_data.min_freq;
else if (temp->clk_data.core_id == VIDC_CORE_ID_3) {
- freq_core_1 += temp->clk_data.min_freq / 2;
- freq_core_2 += temp->clk_data.min_freq / 2;
+ freq_core_1 += temp->clk_data.min_freq;
+ freq_core_2 += temp->clk_data.min_freq;
}
freq_core_max = max_t(unsigned long, freq_core_1, freq_core_2);
diff --git a/drivers/media/platform/msm/vidc/msm_vidc_common.c b/drivers/media/platform/msm/vidc/msm_vidc_common.c
index 4c000b7..7d4e4a1 100644
--- a/drivers/media/platform/msm/vidc/msm_vidc_common.c
+++ b/drivers/media/platform/msm/vidc/msm_vidc_common.c
@@ -5488,8 +5488,9 @@
input_height = inst->prop.height[OUTPUT_PORT];
input_width = inst->prop.width[OUTPUT_PORT];
- if (input_width % 2 != 0 || input_height % 2 != 0 ||
- output_width % 2 != 0 || output_height % 2 != 0) {
+ if (inst->session_type == MSM_VIDC_ENCODER && (input_width % 2 != 0 ||
+ input_height % 2 != 0 || output_width % 2 != 0 ||
+ output_height % 2 != 0)) {
dprintk(VIDC_ERR,
"Height and Width should be even numbers for NV12\n");
dprintk(VIDC_ERR,
@@ -5682,7 +5683,7 @@
handle = msm_smem_get_handle(inst->mem_client, dma_buf);
offset = b->m.planes[i].data_offset;
- size = b->m.planes[i].length;
+ size = b->m.planes[i].length - offset;
cache_ops = SMEM_CACHE_INVALIDATE;
skip = false;
@@ -5751,7 +5752,7 @@
handle = msm_smem_get_handle(inst->mem_client, dma_buf);
offset = b->m.planes[i].data_offset;
- size = b->m.planes[i].length;
+ size = b->m.planes[i].length - offset;
cache_ops = SMEM_CACHE_INVALIDATE;
skip = false;
@@ -5771,8 +5772,15 @@
skip = true;
} else if (b->type ==
V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
- if (!i) /* bitstream */
- skip = true;
+ if (!i) { /* bitstream */
+ /*
+ * Include vp8e header bytes as well
+ * by making offset equal to zero
+ */
+ offset = 0;
+ size = b->m.planes[i].bytesused +
+ b->m.planes[i].data_offset;
+ }
}
}
diff --git a/drivers/media/platform/msm/vidc/msm_vidc_internal.h b/drivers/media/platform/msm/vidc/msm_vidc_internal.h
index 0b6331c..98b5714 100644
--- a/drivers/media/platform/msm/vidc/msm_vidc_internal.h
+++ b/drivers/media/platform/msm/vidc/msm_vidc_internal.h
@@ -410,6 +410,7 @@
u32 level;
u32 entropy_mode;
struct msm_vidc_codec_data *codec_data;
+ struct hal_hdr10_pq_sei hdr10_sei_params;
};
extern struct msm_vidc_drv *vidc_driver;
diff --git a/drivers/media/platform/msm/vidc/msm_vidc_platform.c b/drivers/media/platform/msm/vidc/msm_vidc_platform.c
index d7641c3..c84490f 100644
--- a/drivers/media/platform/msm/vidc/msm_vidc_platform.c
+++ b/drivers/media/platform/msm/vidc/msm_vidc_platform.c
@@ -199,11 +199,11 @@
},
{
.key = "qcom,power-collapse-delay",
- .value = 500,
+ .value = 1500,
},
{
.key = "qcom,hw-resp-timeout",
- .value = 250,
+ .value = 1000,
},
};
@@ -250,11 +250,11 @@
},
{
.key = "qcom,power-collapse-delay",
- .value = 500,
+ .value = 1500,
},
{
.key = "qcom,hw-resp-timeout",
- .value = 250,
+ .value = 1000,
},
};
diff --git a/drivers/misc/qseecom.c b/drivers/misc/qseecom.c
index 4c4835d..3f7e7bb 100644
--- a/drivers/misc/qseecom.c
+++ b/drivers/misc/qseecom.c
@@ -1732,7 +1732,7 @@
if (ptr_svc->svc.listener_id != lstnr) {
pr_warn("Service requested does not exist\n");
__qseecom_qseos_fail_return_resp_tz(data, resp,
- &send_data_rsp, ptr_svc, lstnr);
+ &send_data_rsp, NULL, lstnr);
return -ERESTARTSYS;
}
pr_debug("waking up rcv_req_wq and waiting for send_resp_wq\n");
@@ -1943,7 +1943,7 @@
}
static int __qseecom_process_blocked_on_listener_smcinvoke(
- struct qseecom_command_scm_resp *resp)
+ struct qseecom_command_scm_resp *resp, uint32_t app_id)
{
struct qseecom_registered_listener_list *list_ptr;
int ret = 0;
@@ -1990,9 +1990,18 @@
&ireq, sizeof(ireq),
&continue_resp, sizeof(continue_resp));
if (ret) {
- pr_err("scm_call for continue blocked req for session %d failed, ret %d\n",
- session_id, ret);
- goto exit;
+ /* retry with legacy cmd */
+ qseecom.smcinvoke_support = false;
+ ireq.app_or_session_id = app_id;
+ ret = qseecom_scm_call(SCM_SVC_TZSCHEDULER, 1,
+ &ireq, sizeof(ireq),
+ &continue_resp, sizeof(continue_resp));
+ qseecom.smcinvoke_support = true;
+ if (ret) {
+ pr_err("cont block req for app %d or session %d fail\n",
+ app_id, session_id);
+ goto exit;
+ }
}
resp->result = QSEOS_RESULT_INCOMPLETE;
exit:
@@ -2009,7 +2018,7 @@
resp, ptr_app, data);
else
return __qseecom_process_blocked_on_listener_smcinvoke(
- resp);
+ resp, data->client.app_id);
}
static int __qseecom_reentrancy_process_incomplete_cmd(
struct qseecom_dev_handle *data,
@@ -4790,6 +4799,9 @@
resp.resp_type = desc->ret[1]; /*incomplete:unused;blocked:session_id*/
resp.data = desc->ret[2]; /*listener_id*/
+ dummy_private_data.client.app_id = desc->ret[1];
+ dummy_app_entry.app_id = desc->ret[1];
+
mutex_lock(&app_access_lock);
if (qseecom.qsee_reentrancy_support)
ret = __qseecom_process_reentrancy(&resp, &dummy_app_entry,
diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c
index c172be9..89edc6d 100644
--- a/drivers/mmc/core/core.c
+++ b/drivers/mmc/core/core.c
@@ -2320,8 +2320,10 @@
spin_unlock_irqrestore(&host->lock, flags);
remove_wait_queue(&host->wq, &wait);
- if (pm)
+ if (pm) {
+ mmc_host_clk_hold(host);
pm_runtime_get_sync(mmc_dev(host));
+ }
if (host->ops->enable && !stop && host->claim_cnt == 1)
host->ops->enable(host);
@@ -2360,8 +2362,10 @@
mmc_delay(10);
} while (!claimed_host && retry_cnt--);
- if (pm)
+ if (pm) {
+ mmc_host_clk_hold(host);
pm_runtime_get_sync(mmc_dev(host));
+ }
if (host->ops->enable && claimed_host && host->claim_cnt == 1)
host->ops->enable(host);
@@ -2396,6 +2400,7 @@
wake_up(&host->wq);
pm_runtime_mark_last_busy(mmc_dev(host));
pm_runtime_put_autosuspend(mmc_dev(host));
+ mmc_host_clk_release(host);
}
}
EXPORT_SYMBOL(mmc_release_host);
diff --git a/drivers/net/wireless/cnss_utils/cnss_utils.c b/drivers/net/wireless/cnss_utils/cnss_utils.c
index 4955130..77a58c8 100644
--- a/drivers/net/wireless/cnss_utils/cnss_utils.c
+++ b/drivers/net/wireless/cnss_utils/cnss_utils.c
@@ -13,8 +13,10 @@
#define pr_fmt(fmt) "cnss_utils: " fmt
#include <linux/module.h>
+#include <linux/kernel.h>
#include <linux/slab.h>
#include <linux/etherdevice.h>
+#include <linux/debugfs.h>
#include <net/cnss_utils.h>
#define CNSS_MAX_CH_NUM 45
@@ -29,6 +31,7 @@
};
#define MAX_NO_OF_MAC_ADDR 4
+#define MAC_PREFIX_LEN 2
struct cnss_wlan_mac_addr {
u8 mac_addr[MAX_NO_OF_MAC_ADDR][ETH_ALEN];
u32 no_of_mac_addr_set;
@@ -50,6 +53,7 @@
struct cnss_wlan_mac_addr wlan_mac_addr;
struct cnss_wlan_mac_addr wlan_der_mac_addr;
enum cnss_utils_cc_src cc_source;
+ struct dentry *root_dentry;
} *cnss_utils_priv;
int cnss_utils_set_wlan_unsafe_channel(struct device *dev,
@@ -317,6 +321,137 @@
}
EXPORT_SYMBOL(cnss_utils_get_cc_source);
+static ssize_t cnss_utils_mac_write(struct file *fp,
+ const char __user *user_buf,
+ size_t count, loff_t *off)
+{
+ struct cnss_utils_priv *priv =
+ ((struct seq_file *)fp->private_data)->private;
+ char buf[128];
+ char *input, *mac_type, *mac_address;
+ u8 *dest_mac;
+ u8 val;
+ const char *delim = " \n";
+ size_t len = 0;
+ char temp[3] = "";
+
+ len = min_t(size_t, count, sizeof(buf) - 1);
+ if (copy_from_user(buf, user_buf, len))
+ return -EINVAL;
+ buf[len] = '\0';
+
+ input = buf;
+
+ mac_type = strsep(&input, delim);
+ if (!mac_type)
+ return -EINVAL;
+ if (!input)
+ return -EINVAL;
+
+ mac_address = strsep(&input, delim);
+ if (!mac_address)
+ return -EINVAL;
+ if (strncmp("0x", mac_address, MAC_PREFIX_LEN)) {
+ pr_err("Invalid MAC prefix\n");
+ return -EINVAL;
+ }
+
+ len = strlen(mac_address);
+ mac_address += MAC_PREFIX_LEN;
+ len -= MAC_PREFIX_LEN;
+ if (len < ETH_ALEN * 2 || len > ETH_ALEN * 2 * MAX_NO_OF_MAC_ADDR ||
+ len % (ETH_ALEN * 2) != 0) {
+ pr_err("Invalid MAC address length %zu\n", len);
+ return -EINVAL;
+ }
+
+ if (!strcmp("provisioned", mac_type)) {
+ dest_mac = &priv->wlan_mac_addr.mac_addr[0][0];
+ priv->wlan_mac_addr.no_of_mac_addr_set = len / (ETH_ALEN * 2);
+ } else if (!strcmp("derived", mac_type)) {
+ dest_mac = &priv->wlan_der_mac_addr.mac_addr[0][0];
+ priv->wlan_der_mac_addr.no_of_mac_addr_set =
+ len / (ETH_ALEN * 2);
+ } else {
+ pr_err("Invalid MAC address type %s\n", mac_type);
+ return -EINVAL;
+ }
+
+ while (len--) {
+ temp[0] = *mac_address++;
+ temp[1] = *mac_address++;
+ if (kstrtou8(temp, 16, &val))
+ return -EINVAL;
+ *dest_mac++ = val;
+ }
+ return count;
+}
+
+static int cnss_utils_mac_show(struct seq_file *s, void *data)
+{
+ u8 mac[6];
+ int i;
+ struct cnss_utils_priv *priv = s->private;
+ struct cnss_wlan_mac_addr *addr = NULL;
+
+ addr = &priv->wlan_mac_addr;
+ if (addr->no_of_mac_addr_set) {
+ seq_puts(s, "\nProvisioned MAC addresseses\n");
+ for (i = 0; i < addr->no_of_mac_addr_set; i++) {
+ ether_addr_copy(mac, addr->mac_addr[i]);
+ seq_printf(s, "MAC_ADDR:%02x:%02x:%02x:%02x:%02x:%02x\n",
+ mac[0], mac[1], mac[2],
+ mac[3], mac[4], mac[5]);
+ }
+ }
+
+ addr = &priv->wlan_der_mac_addr;
+ if (addr->no_of_mac_addr_set) {
+ seq_puts(s, "\nDerived MAC addresseses\n");
+ for (i = 0; i < addr->no_of_mac_addr_set; i++) {
+ ether_addr_copy(mac, addr->mac_addr[i]);
+ seq_printf(s, "MAC_ADDR:%02x:%02x:%02x:%02x:%02x:%02x\n",
+ mac[0], mac[1], mac[2],
+ mac[3], mac[4], mac[5]);
+ }
+ }
+
+ return 0;
+}
+
+static int cnss_utils_mac_open(struct inode *inode, struct file *file)
+{
+ return single_open(file, cnss_utils_mac_show, inode->i_private);
+}
+
+static const struct file_operations cnss_utils_mac_fops = {
+ .read = seq_read,
+ .write = cnss_utils_mac_write,
+ .release = single_release,
+ .open = cnss_utils_mac_open,
+ .owner = THIS_MODULE,
+ .llseek = seq_lseek,
+};
+
+static int cnss_utils_debugfs_create(struct cnss_utils_priv *priv)
+{
+ int ret = 0;
+ struct dentry *root_dentry;
+
+ root_dentry = debugfs_create_dir("cnss_utils", NULL);
+
+ if (IS_ERR(root_dentry)) {
+ ret = PTR_ERR(root_dentry);
+ pr_err("Unable to create debugfs %d\n", ret);
+ goto out;
+ }
+ priv->root_dentry = root_dentry;
+ debugfs_create_file("mac_address", 0600, root_dentry, priv,
+ &cnss_utils_mac_fops);
+out:
+ return ret;
+}
+
static int __init cnss_utils_init(void)
{
struct cnss_utils_priv *priv = NULL;
@@ -329,7 +464,7 @@
mutex_init(&priv->unsafe_channel_list_lock);
spin_lock_init(&priv->dfs_nol_info_lock);
-
+ cnss_utils_debugfs_create(priv);
cnss_utils_priv = priv;
return 0;
diff --git a/drivers/platform/msm/ipa/ipa_api.c b/drivers/platform/msm/ipa/ipa_api.c
index 7df312e..e20ddba 100644
--- a/drivers/platform/msm/ipa/ipa_api.c
+++ b/drivers/platform/msm/ipa/ipa_api.c
@@ -2728,6 +2728,26 @@
EXPORT_SYMBOL(ipa_start_gsi_channel);
/**
+* ipa_is_vlan_mode - check if a LAN driver should load in VLAN mode
+* @iface - type of vlan capable device
+* @res - query result: true for vlan mode, false for non vlan mode
+*
+* API must be called after ipa_is_ready() returns true, otherwise it will fail
+*
+* Returns: 0 on success, negative on failure
+*/
+int ipa_is_vlan_mode(enum ipa_vlan_ifaces iface, bool *res)
+{
+ int ret;
+
+ IPA_API_DISPATCH_RETURN(ipa_is_vlan_mode, iface, res);
+
+ return ret;
+
+}
+EXPORT_SYMBOL(ipa_is_vlan_mode);
+
+/**
* ipa_get_version_string() - Get string representation of IPA version
* @ver: IPA version
*
diff --git a/drivers/platform/msm/ipa/ipa_api.h b/drivers/platform/msm/ipa/ipa_api.h
index 0779f34..f3e62b8 100644
--- a/drivers/platform/msm/ipa/ipa_api.h
+++ b/drivers/platform/msm/ipa/ipa_api.h
@@ -420,6 +420,7 @@
int (*ipa_get_smmu_params)(struct ipa_smmu_in_params *in,
struct ipa_smmu_out_params *out);
+ int (*ipa_is_vlan_mode)(enum ipa_vlan_ifaces iface, bool *res);
};
#ifdef CONFIG_IPA
diff --git a/drivers/platform/msm/ipa/ipa_clients/ecm_ipa.c b/drivers/platform/msm/ipa/ipa_clients/ecm_ipa.c
index 2975192..eadd58b 100644
--- a/drivers/platform/msm/ipa/ipa_clients/ecm_ipa.c
+++ b/drivers/platform/msm/ipa/ipa_clients/ecm_ipa.c
@@ -12,6 +12,7 @@
#include <linux/debugfs.h>
#include <linux/errno.h>
#include <linux/etherdevice.h>
+#include <linux/if_vlan.h>
#include <linux/fs.h>
#include <linux/module.h>
#include <linux/netdevice.h>
@@ -123,6 +124,7 @@
* @ipa_rm_resource_name_prod: IPA resource manager producer resource
* @ipa_rm_resource_name_cons: IPA resource manager consumer resource
* @pm_hdl: handle for IPA PM
+ * @is_vlan_mode: does the driver need to work in VLAN mode?
*/
struct ecm_ipa_dev {
struct net_device *net;
@@ -141,6 +143,7 @@
enum ipa_rm_resource_name ipa_rm_resource_name_prod;
enum ipa_rm_resource_name ipa_rm_resource_name_cons;
u32 pm_hdl;
+ bool is_vlan_mode;
};
static int ecm_ipa_open(struct net_device *net);
@@ -173,7 +176,8 @@
(struct file *file, char __user *ubuf, size_t count, loff_t *ppos);
static void ecm_ipa_debugfs_init(struct ecm_ipa_dev *ecm_ipa_ctx);
static void ecm_ipa_debugfs_destroy(struct ecm_ipa_dev *ecm_ipa_ctx);
-static int ecm_ipa_ep_registers_cfg(u32 usb_to_ipa_hdl, u32 ipa_to_usb_hdl);
+static int ecm_ipa_ep_registers_cfg(u32 usb_to_ipa_hdl, u32 ipa_to_usb_hdl,
+ bool is_vlan_mode);
static int ecm_ipa_set_device_ethernet_addr
(u8 *dev_ethaddr, u8 device_ethaddr[]);
static enum ecm_ipa_state ecm_ipa_next_state
@@ -283,6 +287,12 @@
}
ECM_IPA_DEBUG("Device Ethernet address set %pM\n", net->dev_addr);
+ if (ipa_is_vlan_mode(IPA_VLAN_IF_ECM, &ecm_ipa_ctx->is_vlan_mode)) {
+ ECM_IPA_ERROR("couldn't acquire vlan mode, is ipa ready?\n");
+ goto fail_get_vlan_mode;
+ }
+ ECM_IPA_DEBUG("is vlan mode %d\n", ecm_ipa_ctx->is_vlan_mode);
+
result = ecm_ipa_rules_cfg
(ecm_ipa_ctx, params->host_ethaddr, params->device_ethaddr);
if (result) {
@@ -319,8 +329,9 @@
fail_register_netdev:
ecm_ipa_rules_destroy(ecm_ipa_ctx);
-fail_set_device_ethernet:
fail_rules_cfg:
+fail_get_vlan_mode:
+fail_set_device_ethernet:
ecm_ipa_debugfs_destroy(ecm_ipa_ctx);
fail_netdev_priv:
free_netdev(net);
@@ -450,7 +461,8 @@
}
ECM_IPA_DEBUG("ecm_ipa 2 Tx and 2 Rx properties were registered\n");
- retval = ecm_ipa_ep_registers_cfg(usb_to_ipa_hdl, ipa_to_usb_hdl);
+ retval = ecm_ipa_ep_registers_cfg(usb_to_ipa_hdl, ipa_to_usb_hdl,
+ ecm_ipa_ctx->is_vlan_mode);
if (retval) {
ECM_IPA_ERROR("fail on ep cfg\n");
goto fail;
@@ -606,6 +618,10 @@
goto out;
}
+ if (ecm_ipa_ctx->is_vlan_mode)
+ if (unlikely(skb->protocol != ETH_P_8021Q))
+ ECM_IPA_DEBUG("ether_type != ETH_P_8021Q && vlan\n");
+
ret = ipa_tx_dp(ecm_ipa_ctx->ipa_to_usb_client, skb, NULL);
if (ret) {
ECM_IPA_ERROR("ipa transmit failed (%d)\n", ret);
@@ -843,6 +859,41 @@
ECM_IPA_DEBUG("queue started\n");
}
+static void ecm_ipa_prepare_header_insertion(
+ int eth_type,
+ const char *hdr_name, struct ipa_hdr_add *add_hdr,
+ const void *dst_mac, const void *src_mac, bool is_vlan_mode)
+{
+ struct ethhdr *eth_hdr;
+ struct vlan_ethhdr *eth_vlan_hdr;
+
+ ECM_IPA_LOG_ENTRY();
+
+ add_hdr->is_partial = 0;
+ strlcpy(add_hdr->name, hdr_name, IPA_RESOURCE_NAME_MAX);
+ add_hdr->is_eth2_ofst_valid = true;
+ add_hdr->eth2_ofst = 0;
+
+ if (is_vlan_mode) {
+ eth_vlan_hdr = (struct vlan_ethhdr *)add_hdr->hdr;
+ memcpy(eth_vlan_hdr->h_dest, dst_mac, ETH_ALEN);
+ memcpy(eth_vlan_hdr->h_source, src_mac, ETH_ALEN);
+ eth_vlan_hdr->h_vlan_encapsulated_proto =
+ htons(eth_type);
+ eth_vlan_hdr->h_vlan_proto = htons(ETH_P_8021Q);
+ add_hdr->hdr_len = VLAN_ETH_HLEN;
+ add_hdr->type = IPA_HDR_L2_802_1Q;
+ } else {
+ eth_hdr = (struct ethhdr *)add_hdr->hdr;
+ memcpy(eth_hdr->h_dest, dst_mac, ETH_ALEN);
+ memcpy(eth_hdr->h_source, src_mac, ETH_ALEN);
+ eth_hdr->h_proto = htons(eth_type);
+ add_hdr->hdr_len = ETH_HLEN;
+ add_hdr->type = IPA_HDR_L2_ETHERNET_II;
+ }
+ ECM_IPA_LOG_EXIT();
+}
+
/**
* ecm_ipa_rules_cfg() - set header insertion and register Tx/Rx properties
* Headers will be committed to HW
@@ -859,8 +910,6 @@
struct ipa_ioc_add_hdr *hdrs;
struct ipa_hdr_add *ipv4_hdr;
struct ipa_hdr_add *ipv6_hdr;
- struct ethhdr *eth_ipv4;
- struct ethhdr *eth_ipv6;
int result = 0;
ECM_IPA_LOG_ENTRY();
@@ -871,28 +920,17 @@
result = -ENOMEM;
goto out;
}
+
ipv4_hdr = &hdrs->hdr[0];
- eth_ipv4 = (struct ethhdr *)ipv4_hdr->hdr;
+ ecm_ipa_prepare_header_insertion(
+ ETH_P_IP, ECM_IPA_IPV4_HDR_NAME,
+ ipv4_hdr, dst_mac, src_mac, ecm_ipa_ctx->is_vlan_mode);
+
ipv6_hdr = &hdrs->hdr[1];
- eth_ipv6 = (struct ethhdr *)ipv6_hdr->hdr;
- strlcpy(ipv4_hdr->name, ECM_IPA_IPV4_HDR_NAME, IPA_RESOURCE_NAME_MAX);
- memcpy(eth_ipv4->h_dest, dst_mac, ETH_ALEN);
- memcpy(eth_ipv4->h_source, src_mac, ETH_ALEN);
- eth_ipv4->h_proto = htons(ETH_P_IP);
- ipv4_hdr->hdr_len = ETH_HLEN;
- ipv4_hdr->is_partial = 0;
- ipv4_hdr->is_eth2_ofst_valid = true;
- ipv4_hdr->eth2_ofst = 0;
- ipv4_hdr->type = IPA_HDR_L2_ETHERNET_II;
- strlcpy(ipv6_hdr->name, ECM_IPA_IPV6_HDR_NAME, IPA_RESOURCE_NAME_MAX);
- memcpy(eth_ipv6->h_dest, dst_mac, ETH_ALEN);
- memcpy(eth_ipv6->h_source, src_mac, ETH_ALEN);
- eth_ipv6->h_proto = htons(ETH_P_IPV6);
- ipv6_hdr->hdr_len = ETH_HLEN;
- ipv6_hdr->is_partial = 0;
- ipv6_hdr->is_eth2_ofst_valid = true;
- ipv6_hdr->eth2_ofst = 0;
- ipv6_hdr->type = IPA_HDR_L2_ETHERNET_II;
+ ecm_ipa_prepare_header_insertion(
+ ETH_P_IPV6, ECM_IPA_IPV6_HDR_NAME,
+ ipv6_hdr, dst_mac, src_mac, ecm_ipa_ctx->is_vlan_mode);
+
hdrs->commit = 1;
hdrs->num_hdrs = 2;
result = ipa_add_hdr(hdrs);
@@ -972,10 +1010,14 @@
struct ipa_rx_intf rx_properties = {0};
struct ipa_ioc_rx_intf_prop *rx_ipv4_property;
struct ipa_ioc_rx_intf_prop *rx_ipv6_property;
+ enum ipa_hdr_l2_type hdr_l2_type = IPA_HDR_L2_ETHERNET_II;
int result = 0;
ECM_IPA_LOG_ENTRY();
+ if (ecm_ipa_ctx->is_vlan_mode)
+ hdr_l2_type = IPA_HDR_L2_802_1Q;
+
tx_properties.prop = properties;
ipv4_property = &tx_properties.prop[0];
ipv4_property->ip = IPA_IP_v4;
@@ -983,11 +1025,11 @@
strlcpy
(ipv4_property->hdr_name, ECM_IPA_IPV4_HDR_NAME,
IPA_RESOURCE_NAME_MAX);
- ipv4_property->hdr_l2_type = IPA_HDR_L2_ETHERNET_II;
+ ipv4_property->hdr_l2_type = hdr_l2_type;
ipv6_property = &tx_properties.prop[1];
ipv6_property->ip = IPA_IP_v6;
ipv6_property->dst_pipe = ecm_ipa_ctx->ipa_to_usb_client;
- ipv6_property->hdr_l2_type = IPA_HDR_L2_ETHERNET_II;
+ ipv6_property->hdr_l2_type = hdr_l2_type;
strlcpy
(ipv6_property->hdr_name, ECM_IPA_IPV6_HDR_NAME,
IPA_RESOURCE_NAME_MAX);
@@ -998,12 +1040,12 @@
rx_ipv4_property->ip = IPA_IP_v4;
rx_ipv4_property->attrib.attrib_mask = 0;
rx_ipv4_property->src_pipe = ecm_ipa_ctx->usb_to_ipa_client;
- rx_ipv4_property->hdr_l2_type = IPA_HDR_L2_ETHERNET_II;
+ rx_ipv4_property->hdr_l2_type = hdr_l2_type;
rx_ipv6_property = &rx_properties.prop[1];
rx_ipv6_property->ip = IPA_IP_v6;
rx_ipv6_property->attrib.attrib_mask = 0;
rx_ipv6_property->src_pipe = ecm_ipa_ctx->usb_to_ipa_client;
- rx_ipv6_property->hdr_l2_type = IPA_HDR_L2_ETHERNET_II;
+ rx_ipv6_property->hdr_l2_type = hdr_l2_type;
rx_properties.num_props = 2;
result = ipa_register_intf("ecm0", &tx_properties, &rx_properties);
@@ -1336,6 +1378,13 @@
goto fail_file;
}
+ file = debugfs_create_bool("is_vlan_mode", flags_read_only,
+ ecm_ipa_ctx->directory, &ecm_ipa_ctx->is_vlan_mode);
+ if (!file) {
+ ECM_IPA_ERROR("could not create is_vlan_mode file\n");
+ goto fail_file;
+ }
+
ECM_IPA_DEBUG("debugfs entries were created\n");
ECM_IPA_LOG_EXIT();
@@ -1362,8 +1411,9 @@
/**
* ecm_ipa_ep_cfg() - configure the USB endpoints for ECM
*
- *usb_to_ipa_hdl: handle received from ipa_connect
- *ipa_to_usb_hdl: handle received from ipa_connect
+ * @usb_to_ipa_hdl: handle received from ipa_connect
+ * @ipa_to_usb_hdl: handle received from ipa_connect
+ * @is_vlan_mode - should driver work in vlan mode?
*
* USB to IPA pipe:
* - No de-aggregation
@@ -1374,16 +1424,21 @@
* - No aggregation
* - Add Ethernet header
*/
-static int ecm_ipa_ep_registers_cfg(u32 usb_to_ipa_hdl, u32 ipa_to_usb_hdl)
+static int ecm_ipa_ep_registers_cfg(u32 usb_to_ipa_hdl, u32 ipa_to_usb_hdl,
+ bool is_vlan_mode)
{
int result = 0;
struct ipa_ep_cfg usb_to_ipa_ep_cfg;
struct ipa_ep_cfg ipa_to_usb_ep_cfg;
+ uint8_t hdr_add = 0;
+
ECM_IPA_LOG_ENTRY();
+ if (is_vlan_mode)
+ hdr_add = VLAN_HLEN;
memset(&usb_to_ipa_ep_cfg, 0, sizeof(struct ipa_ep_cfg));
usb_to_ipa_ep_cfg.aggr.aggr_en = IPA_BYPASS_AGGR;
- usb_to_ipa_ep_cfg.hdr.hdr_len = ETH_HLEN;
+ usb_to_ipa_ep_cfg.hdr.hdr_len = ETH_HLEN + hdr_add;
usb_to_ipa_ep_cfg.nat.nat_en = IPA_SRC_NAT;
usb_to_ipa_ep_cfg.route.rt_tbl_hdl = 0;
usb_to_ipa_ep_cfg.mode.dst = IPA_CLIENT_A5_LAN_WAN_CONS;
@@ -1395,7 +1450,7 @@
}
memset(&ipa_to_usb_ep_cfg, 0, sizeof(struct ipa_ep_cfg));
ipa_to_usb_ep_cfg.aggr.aggr_en = IPA_BYPASS_AGGR;
- ipa_to_usb_ep_cfg.hdr.hdr_len = ETH_HLEN;
+ ipa_to_usb_ep_cfg.hdr.hdr_len = ETH_HLEN + hdr_add;
ipa_to_usb_ep_cfg.nat.nat_en = IPA_BYPASS_NAT;
result = ipa_cfg_ep(ipa_to_usb_hdl, &ipa_to_usb_ep_cfg);
if (result) {
diff --git a/drivers/platform/msm/ipa/ipa_clients/ipa_usb.c b/drivers/platform/msm/ipa/ipa_clients/ipa_usb.c
index 90920d9..d274490 100644
--- a/drivers/platform/msm/ipa/ipa_clients/ipa_usb.c
+++ b/drivers/platform/msm/ipa/ipa_clients/ipa_usb.c
@@ -741,6 +741,10 @@
&ipa3_usb_ctx->ttype_ctx[ttype];
int result;
+ /* create PM resources for the first tethering protocol only */
+ if (ipa3_usb_ctx->num_init_prot > 0)
+ return 0;
+
memset(&ttype_ctx->pm_ctx.reg_params, 0,
sizeof(ttype_ctx->pm_ctx.reg_params));
ttype_ctx->pm_ctx.reg_params.name = (ttype == IPA_USB_TRANSPORT_DPL) ?
diff --git a/drivers/platform/msm/ipa/ipa_clients/rndis_ipa.c b/drivers/platform/msm/ipa/ipa_clients/rndis_ipa.c
index 2e87bd2..4958c69 100644
--- a/drivers/platform/msm/ipa/ipa_clients/rndis_ipa.c
+++ b/drivers/platform/msm/ipa/ipa_clients/rndis_ipa.c
@@ -12,6 +12,7 @@
#include <linux/atomic.h>
#include <linux/errno.h>
#include <linux/etherdevice.h>
+#include <linux/if_vlan.h>
#include <linux/debugfs.h>
#include <linux/in.h>
#include <linux/stddef.h>
@@ -162,6 +163,7 @@
* @xmit_error_delayed_work: work item for cases where IPA driver Tx fails
* @state_lock: used to protect the state variable.
* @pm_hdl: handle for IPA PM framework
+ * @is_vlan_mode: should driver work in vlan mode?
*/
struct rndis_ipa_dev {
struct net_device *net;
@@ -191,6 +193,7 @@
struct delayed_work xmit_error_delayed_work;
spinlock_t state_lock; /* Spinlock for the state variable.*/
u32 pm_hdl;
+ bool is_vlan_mode;
};
/**
@@ -217,19 +220,20 @@
static void rndis_ipa_tx_timeout(struct net_device *net);
static int rndis_ipa_stop(struct net_device *net);
static void rndis_ipa_enable_data_path(struct rndis_ipa_dev *rndis_ipa_ctx);
-static struct sk_buff *rndis_encapsulate_skb(struct sk_buff *skb);
+static struct sk_buff *rndis_encapsulate_skb(struct sk_buff *skb,
+ struct rndis_ipa_dev *rndis_ipa_ctx);
static void rndis_ipa_xmit_error(struct sk_buff *skb);
static void rndis_ipa_xmit_error_aftercare_wq(struct work_struct *work);
static void rndis_ipa_prepare_header_insertion
(int eth_type,
const char *hdr_name, struct ipa_hdr_add *add_hdr,
- const void *dst_mac, const void *src_mac);
+ const void *dst_mac, const void *src_mac, bool is_vlan_mode);
static int rndis_ipa_hdrs_cfg
(struct rndis_ipa_dev *rndis_ipa_ctx,
const void *dst_mac, const void *src_mac);
static int rndis_ipa_hdrs_destroy(struct rndis_ipa_dev *rndis_ipa_ctx);
static struct net_device_stats *rndis_ipa_get_stats(struct net_device *net);
-static int rndis_ipa_register_properties(char *netdev_name);
+static int rndis_ipa_register_properties(char *netdev_name, bool is_vlan_mode);
static int rndis_ipa_deregister_properties(char *netdev_name);
static void rndis_ipa_rm_notify
(void *user_data, enum ipa_rm_event event,
@@ -262,7 +266,8 @@
(u32 usb_to_ipa_hdl,
u32 ipa_to_usb_hdl, u32 max_xfer_size_bytes_to_dev,
u32 max_xfer_size_bytes_to_host, u32 mtu,
- bool deaggr_enable);
+ bool deaggr_enable,
+ bool is_vlan_mode);
static int rndis_ipa_set_device_ethernet_addr
(u8 *dev_ethaddr,
u8 device_ethaddr[]);
@@ -566,6 +571,14 @@
}
RNDIS_IPA_DEBUG("Device Ethernet address set %pM\n", net->dev_addr);
+ if (ipa_is_vlan_mode(IPA_VLAN_IF_RNDIS,
+ &rndis_ipa_ctx->is_vlan_mode)) {
+ RNDIS_IPA_ERROR("couldn't acquire vlan mode, is ipa ready?\n");
+ goto fail_get_vlan_mode;
+ }
+
+ RNDIS_IPA_DEBUG("is_vlan_mode %d\n", rndis_ipa_ctx->is_vlan_mode);
+
result = rndis_ipa_hdrs_cfg
(rndis_ipa_ctx,
params->host_ethaddr,
@@ -576,7 +589,8 @@
}
RNDIS_IPA_DEBUG("IPA header-insertion configed for Ethernet+RNDIS\n");
- result = rndis_ipa_register_properties(net->name);
+ result = rndis_ipa_register_properties(net->name,
+ rndis_ipa_ctx->is_vlan_mode);
if (result) {
RNDIS_IPA_ERROR("fail on properties set\n");
goto fail_register_tx;
@@ -612,8 +626,9 @@
rndis_ipa_deregister_properties(net->name);
fail_register_tx:
rndis_ipa_hdrs_destroy(rndis_ipa_ctx);
-fail_set_device_ethernet:
fail_hdrs_cfg:
+fail_get_vlan_mode:
+fail_set_device_ethernet:
rndis_ipa_debugfs_destroy(rndis_ipa_ctx);
fail_netdev_priv:
free_netdev(net);
@@ -728,7 +743,8 @@
max_xfer_size_bytes_to_dev,
max_xfer_size_bytes_to_host,
rndis_ipa_ctx->net->mtu,
- rndis_ipa_ctx->deaggregation_enable);
+ rndis_ipa_ctx->deaggregation_enable,
+ rndis_ipa_ctx->is_vlan_mode);
if (result) {
RNDIS_IPA_ERROR("fail on ep cfg\n");
goto fail;
@@ -910,7 +926,7 @@
goto out;
}
- skb = rndis_encapsulate_skb(skb);
+ skb = rndis_encapsulate_skb(skb, rndis_ipa_ctx);
trace_rndis_tx_dp(skb->protocol);
ret = ipa_tx_dp(IPA_TO_USB_CLIENT, skb, NULL);
if (ret) {
@@ -1456,6 +1472,7 @@
* for IPA->USB pipe
* src_mac: device MAC (Ethernet) address to be added to packets
* for IPA->USB pipe
+ * is_vlan_mode: should driver work in vlan mode?
*
* This function shall build the header-insertion block request for a
* single Ethernet+RNDIS header)
@@ -1468,23 +1485,37 @@
static void rndis_ipa_prepare_header_insertion(
int eth_type,
const char *hdr_name, struct ipa_hdr_add *add_hdr,
- const void *dst_mac, const void *src_mac)
+ const void *dst_mac, const void *src_mac, bool is_vlan_mode)
{
struct ethhdr *eth_hdr;
+ struct vlan_ethhdr *eth_vlan_hdr;
add_hdr->hdr_len = sizeof(rndis_template_hdr);
add_hdr->is_partial = false;
strlcpy(add_hdr->name, hdr_name, IPA_RESOURCE_NAME_MAX);
memcpy(add_hdr->hdr, &rndis_template_hdr, sizeof(rndis_template_hdr));
- eth_hdr = (struct ethhdr *)(add_hdr->hdr + sizeof(rndis_template_hdr));
- memcpy(eth_hdr->h_dest, dst_mac, ETH_ALEN);
- memcpy(eth_hdr->h_source, src_mac, ETH_ALEN);
- eth_hdr->h_proto = htons(eth_type);
- add_hdr->hdr_len += ETH_HLEN;
add_hdr->is_eth2_ofst_valid = true;
add_hdr->eth2_ofst = sizeof(rndis_template_hdr);
- add_hdr->type = IPA_HDR_L2_ETHERNET_II;
+
+ if (is_vlan_mode) {
+ eth_vlan_hdr = (struct vlan_ethhdr *)(add_hdr->hdr +
+ sizeof(rndis_template_hdr));
+ memcpy(eth_vlan_hdr->h_dest, dst_mac, ETH_ALEN);
+ memcpy(eth_vlan_hdr->h_source, src_mac, ETH_ALEN);
+ eth_vlan_hdr->h_vlan_encapsulated_proto = htons(eth_type);
+ eth_vlan_hdr->h_vlan_proto = htons(ETH_P_8021Q);
+ add_hdr->hdr_len += VLAN_ETH_HLEN;
+ add_hdr->type = IPA_HDR_L2_802_1Q;
+ } else {
+ eth_hdr = (struct ethhdr *)(add_hdr->hdr +
+ sizeof(rndis_template_hdr));
+ memcpy(eth_hdr->h_dest, dst_mac, ETH_ALEN);
+ memcpy(eth_hdr->h_source, src_mac, ETH_ALEN);
+ eth_hdr->h_proto = htons(eth_type);
+ add_hdr->hdr_len += ETH_HLEN;
+ add_hdr->type = IPA_HDR_L2_ETHERNET_II;
+ }
}
/**
@@ -1526,10 +1557,10 @@
ipv6_hdr = &hdrs->hdr[1];
rndis_ipa_prepare_header_insertion
(ETH_P_IP, IPV4_HDR_NAME,
- ipv4_hdr, dst_mac, src_mac);
+ ipv4_hdr, dst_mac, src_mac, rndis_ipa_ctx->is_vlan_mode);
rndis_ipa_prepare_header_insertion
(ETH_P_IPV6, IPV6_HDR_NAME,
- ipv6_hdr, dst_mac, src_mac);
+ ipv6_hdr, dst_mac, src_mac, rndis_ipa_ctx->is_vlan_mode);
hdrs->commit = 1;
hdrs->num_hdrs = 2;
@@ -1610,6 +1641,7 @@
* rndis_ipa_register_properties() - set Tx/Rx properties needed
* by IPA configuration manager
* @netdev_name: a string with the name of the network interface device
+ * @is_vlan_mode: should driver work in vlan mode?
*
* Register Tx/Rx properties to allow user space configuration (IPA
* Configuration Manager):
@@ -1628,7 +1660,7 @@
* This rules shall be added based on the attribute mask supplied at
* this function, that is, always hit rule.
*/
-static int rndis_ipa_register_properties(char *netdev_name)
+static int rndis_ipa_register_properties(char *netdev_name, bool is_vlan_mode)
{
struct ipa_tx_intf tx_properties = {0};
struct ipa_ioc_tx_intf_prop properties[2] = { {0}, {0} };
@@ -1638,10 +1670,14 @@
struct ipa_rx_intf rx_properties = {0};
struct ipa_ioc_rx_intf_prop *rx_ipv4_property;
struct ipa_ioc_rx_intf_prop *rx_ipv6_property;
+ enum ipa_hdr_l2_type hdr_l2_type = IPA_HDR_L2_ETHERNET_II;
int result = 0;
RNDIS_IPA_LOG_ENTRY();
+ if (is_vlan_mode)
+ hdr_l2_type = IPA_HDR_L2_802_1Q;
+
tx_properties.prop = properties;
ipv4_property = &tx_properties.prop[0];
ipv4_property->ip = IPA_IP_v4;
@@ -1649,14 +1685,14 @@
strlcpy
(ipv4_property->hdr_name, IPV4_HDR_NAME,
IPA_RESOURCE_NAME_MAX);
- ipv4_property->hdr_l2_type = IPA_HDR_L2_ETHERNET_II;
+ ipv4_property->hdr_l2_type = hdr_l2_type;
ipv6_property = &tx_properties.prop[1];
ipv6_property->ip = IPA_IP_v6;
ipv6_property->dst_pipe = IPA_TO_USB_CLIENT;
strlcpy
(ipv6_property->hdr_name, IPV6_HDR_NAME,
IPA_RESOURCE_NAME_MAX);
- ipv6_property->hdr_l2_type = IPA_HDR_L2_ETHERNET_II;
+ ipv6_property->hdr_l2_type = hdr_l2_type;
tx_properties.num_props = 2;
rx_properties.prop = rx_ioc_properties;
@@ -1664,12 +1700,12 @@
rx_ipv4_property->ip = IPA_IP_v4;
rx_ipv4_property->attrib.attrib_mask = 0;
rx_ipv4_property->src_pipe = IPA_CLIENT_USB_PROD;
- rx_ipv4_property->hdr_l2_type = IPA_HDR_L2_ETHERNET_II;
+ rx_ipv4_property->hdr_l2_type = hdr_l2_type;
rx_ipv6_property = &rx_properties.prop[1];
rx_ipv6_property->ip = IPA_IP_v6;
rx_ipv6_property->attrib.attrib_mask = 0;
rx_ipv6_property->src_pipe = IPA_CLIENT_USB_PROD;
- rx_ipv6_property->hdr_l2_type = IPA_HDR_L2_ETHERNET_II;
+ rx_ipv6_property->hdr_l2_type = hdr_l2_type;
rx_properties.num_props = 2;
result = ipa_register_intf("rndis0", &tx_properties, &rx_properties);
@@ -1948,12 +1984,14 @@
* rndis_encapsulate_skb() - encapsulate the given Ethernet skb with
* an RNDIS header
* @skb: packet to be encapsulated with the RNDIS header
+ * @rndis_ipa_ctx: main driver context
*
* Shall use a template header for RNDIS and update it with the given
* skb values.
* Ethernet is expected to be already encapsulate the packet.
*/
-static struct sk_buff *rndis_encapsulate_skb(struct sk_buff *skb)
+static struct sk_buff *rndis_encapsulate_skb(struct sk_buff *skb,
+ struct rndis_ipa_dev *rndis_ipa_ctx)
{
struct rndis_pkt_hdr *rndis_hdr;
int payload_byte_len = skb->len;
@@ -1971,6 +2009,10 @@
skb = new_skb;
}
+ if (rndis_ipa_ctx->is_vlan_mode)
+ if (unlikely(skb->protocol != ETH_P_8021Q))
+ RNDIS_IPA_DEBUG("ether_type != ETH_P_8021Q && vlan\n");
+
/* make room at the head of the SKB to put the RNDIS header */
rndis_hdr = (struct rndis_pkt_hdr *)skb_push(skb,
sizeof(rndis_template_hdr));
@@ -2046,6 +2088,8 @@
* @max_xfer_size_bytes_to_host: the maximum size, in bytes, that the host
* expects to receive from the device. supplied on REMOTE_NDIS_INITIALIZE_MSG.
* @mtu: the netdev MTU size, in bytes
+ * @deaggr_enable: should deaggregation be enabled?
+ * @is_vlan_mode: should driver work in vlan mode?
*
* USB to IPA pipe:
* - de-aggregation
@@ -2064,7 +2108,8 @@
u32 max_xfer_size_bytes_to_dev,
u32 max_xfer_size_bytes_to_host,
u32 mtu,
- bool deaggr_enable)
+ bool deaggr_enable,
+ bool is_vlan_mode)
{
int result;
struct ipa_ep_cfg *usb_to_ipa_ep_cfg;
@@ -2077,6 +2122,20 @@
RNDIS_IPA_DEBUG("deaggregation disabled\n");
}
+ if (is_vlan_mode) {
+ usb_to_ipa_ep_cfg->hdr.hdr_len =
+ VLAN_ETH_HLEN + sizeof(struct rndis_pkt_hdr);
+ ipa_to_usb_ep_cfg.hdr.hdr_len =
+ VLAN_ETH_HLEN + sizeof(struct rndis_pkt_hdr);
+ ipa_to_usb_ep_cfg.hdr.hdr_additional_const_len = VLAN_ETH_HLEN;
+ } else {
+ usb_to_ipa_ep_cfg->hdr.hdr_len =
+ ETH_HLEN + sizeof(struct rndis_pkt_hdr);
+ ipa_to_usb_ep_cfg.hdr.hdr_len =
+ ETH_HLEN + sizeof(struct rndis_pkt_hdr);
+ ipa_to_usb_ep_cfg.hdr.hdr_additional_const_len = ETH_HLEN;
+ }
+
usb_to_ipa_ep_cfg->deaggr.max_packet_len = max_xfer_size_bytes_to_dev;
result = ipa_cfg_ep(usb_to_ipa_hdl, usb_to_ipa_ep_cfg);
if (result) {
@@ -2452,6 +2511,14 @@
goto fail_file;
}
+ file = debugfs_create_bool("is_vlan_mode", flags_read_only,
+ rndis_ipa_ctx->directory,
+ &rndis_ipa_ctx->is_vlan_mode);
+ if (!file) {
+ RNDIS_IPA_ERROR("fail to create is_vlan_mode file\n");
+ goto fail_file;
+ }
+
RNDIS_IPA_DEBUG("debugfs entries were created\n");
RNDIS_IPA_LOG_EXIT();
diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa.c b/drivers/platform/msm/ipa/ipa_v3/ipa.c
index af4d448..57b988b 100644
--- a/drivers/platform/msm/ipa/ipa_v3/ipa.c
+++ b/drivers/platform/msm/ipa/ipa_v3/ipa.c
@@ -3855,6 +3855,9 @@
{
u32 clk_rate;
+ if (!ipa3_ctx->enable_clock_scaling)
+ return 0;
+
IPADBG_LOW("idx = %d\n", idx);
if (idx <= 0 || idx >= ipa3_ctx->ctrl->msm_bus_data_ptr->num_usecases) {
@@ -3863,10 +3866,12 @@
}
if (idx == 1)
- clk_rate = ipa3_ctx->ctrl->ipa_clk_rate_svs;
+ clk_rate = ipa3_ctx->ctrl->ipa_clk_rate_svs2;
else if (idx == 2)
- clk_rate = ipa3_ctx->ctrl->ipa_clk_rate_nominal;
+ clk_rate = ipa3_ctx->ctrl->ipa_clk_rate_svs;
else if (idx == 3)
+ clk_rate = ipa3_ctx->ctrl->ipa_clk_rate_nominal;
+ else if (idx == 4)
clk_rate = ipa3_ctx->ctrl->ipa_clk_rate_turbo;
else {
IPAERR("bad voltage\n");
@@ -4633,7 +4638,7 @@
{
unsigned long missing;
- char dbg_buff[16] = { 0 };
+ char dbg_buff[32] = { 0 };
if (sizeof(dbg_buff) < count + 1)
return -EFAULT;
@@ -4646,7 +4651,9 @@
}
if (count > 0)
- dbg_buff[count - 1] = '\0';
+ dbg_buff[count] = '\0';
+
+ IPADBG("user input string %s\n", dbg_buff);
/* Prevent consequent calls from trying to load the FW again. */
if (ipa3_is_ready())
@@ -4654,13 +4661,36 @@
/* Check MHI configuration on MDM devices */
if (!ipa3_is_msm_device()) {
+
+ if (strnstr(dbg_buff, "vlan", strlen(dbg_buff))) {
+ if (strnstr(dbg_buff, "eth", strlen(dbg_buff)))
+ ipa3_ctx->vlan_mode_iface[IPA_VLAN_IF_EMAC] =
+ true;
+ if (strnstr(dbg_buff, "rndis", strlen(dbg_buff)))
+ ipa3_ctx->vlan_mode_iface[IPA_VLAN_IF_RNDIS] =
+ true;
+ if (strnstr(dbg_buff, "ecm", strlen(dbg_buff)))
+ ipa3_ctx->vlan_mode_iface[IPA_VLAN_IF_ECM] =
+ true;
+
+ /*
+ * when vlan mode is passed to our dev we expect
+ * another write
+ */
+ return count;
+ }
+
if (!strcasecmp(dbg_buff, "MHI")) {
ipa3_ctx->ipa_config_is_mhi = true;
pr_info(
- "IPA is loading with MHI configuration\n");
- } else {
+ "IPA is loading with MHI configuration\n");
+ } else if (!strcmp(dbg_buff, "1\n")) {
pr_info(
- "IPA is loading with non MHI configuration\n");
+ "IPA is loading with non MHI configuration\n");
+ } else {
+ IPAERR("got invalid string %s not loading FW\n",
+ dbg_buff);
+ return count;
}
}
diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_i.h b/drivers/platform/msm/ipa/ipa_v3/ipa_i.h
index adbd7b8..d7d74a3 100644
--- a/drivers/platform/msm/ipa/ipa_v3/ipa_i.h
+++ b/drivers/platform/msm/ipa/ipa_v3/ipa_i.h
@@ -1373,6 +1373,7 @@
int num_ipa_cne_evt_req;
struct mutex ipa_cne_evt_lock;
bool use_ipa_pm;
+ bool vlan_mode_iface[IPA_VLAN_IF_MAX];
};
struct ipa3_plat_drv_res {
diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_pm.c b/drivers/platform/msm/ipa/ipa_v3/ipa_pm.c
index 3bf0327..be342cb 100644
--- a/drivers/platform/msm/ipa/ipa_v3/ipa_pm.c
+++ b/drivers/platform/msm/ipa/ipa_v3/ipa_pm.c
@@ -1030,8 +1030,9 @@
client->state);
spin_unlock_irqrestore(&client->state_lock, flags);
} else if (client->state ==
- IPA_PM_ACTIVATED_PENDING_DEACTIVATION ||
- IPA_PM_ACTIVATED_PENDING_RESCHEDULE) {
+ IPA_PM_ACTIVATED_PENDING_DEACTIVATION ||
+ client->state ==
+ IPA_PM_ACTIVATED_PENDING_RESCHEDULE) {
run_algorithm = true;
client->state = IPA_PM_DEACTIVATED;
IPA_PM_DBG_STATE(client->hdl, client->name,
diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_utils.c b/drivers/platform/msm/ipa/ipa_v3/ipa_utils.c
index fb29d00..7421eb8 100644
--- a/drivers/platform/msm/ipa/ipa_v3/ipa_utils.c
+++ b/drivers/platform/msm/ipa/ipa_v3/ipa_utils.c
@@ -1205,25 +1205,25 @@
false,
IPA_DPS_HPS_SEQ_TYPE_INVALID,
QMB_MASTER_SELECT_DDR,
- { 18, 12, 6, 9, IPA_EE_AP } },
+ { 18, 11, 6, 9, IPA_EE_AP } },
[IPA_4_0][IPA_CLIENT_WLAN2_CONS] = {
true, IPA_v4_0_GROUP_UL_DL,
false,
IPA_DPS_HPS_SEQ_TYPE_INVALID,
QMB_MASTER_SELECT_DDR,
- { 20, 14, 9, 9, IPA_EE_AP } },
+ { 20, 13, 9, 9, IPA_EE_AP } },
[IPA_4_0][IPA_CLIENT_WLAN3_CONS] = {
true, IPA_v4_0_GROUP_UL_DL,
false,
IPA_DPS_HPS_SEQ_TYPE_INVALID,
QMB_MASTER_SELECT_DDR,
- { 21, 15, 9, 9, IPA_EE_AP } },
+ { 21, 14, 9, 9, IPA_EE_AP } },
[IPA_4_0][IPA_CLIENT_USB_CONS] = {
true, IPA_v4_0_GROUP_UL_DL,
false,
IPA_DPS_HPS_SEQ_TYPE_INVALID,
QMB_MASTER_SELECT_PCIE,
- { 19, 13, 9, 9, IPA_EE_AP } },
+ { 19, 12, 9, 9, IPA_EE_AP } },
[IPA_4_0][IPA_CLIENT_USB_DPL_CONS] = {
true, IPA_v4_0_GROUP_UL_DL,
false,
@@ -1291,19 +1291,19 @@
false,
IPA_DPS_HPS_SEQ_TYPE_INVALID,
QMB_MASTER_SELECT_PCIE,
- { 18, 12, 6, 9, IPA_EE_AP } },
+ { 18, 11, 6, 9, IPA_EE_AP } },
[IPA_4_0][IPA_CLIENT_TEST3_CONS] = {
true, IPA_v4_0_GROUP_UL_DL,
false,
IPA_DPS_HPS_SEQ_TYPE_INVALID,
QMB_MASTER_SELECT_DDR,
- { 20, 14, 9, 9, IPA_EE_AP } },
+ { 20, 13, 9, 9, IPA_EE_AP } },
[IPA_4_0][IPA_CLIENT_TEST4_CONS] = {
true, IPA_v4_0_GROUP_UL_DL,
false,
IPA_DPS_HPS_SEQ_TYPE_INVALID,
QMB_MASTER_SELECT_PCIE,
- { 21, 15, 9, 9, IPA_EE_AP } },
+ { 21, 14, 9, 9, IPA_EE_AP } },
/* Dummy consumer (pipe 31) is used in L2TP rt rule */
[IPA_4_0][IPA_CLIENT_DUMMY_CONS] = {
true, IPA_v4_0_GROUP_UL_DL,
@@ -1404,7 +1404,7 @@
false,
IPA_DPS_HPS_SEQ_TYPE_INVALID,
QMB_MASTER_SELECT_DDR,
- { 19, 13, 9, 9, IPA_EE_AP } },
+ { 19, 12, 9, 9, IPA_EE_AP } },
[IPA_4_0_MHI][IPA_CLIENT_USB_DPL_CONS] = {
true, IPA_v4_0_MHI_GROUP_DDR,
false,
@@ -1446,13 +1446,13 @@
false,
IPA_DPS_HPS_SEQ_TYPE_INVALID,
QMB_MASTER_SELECT_PCIE,
- { 20, 14, 9, 9, IPA_EE_AP } },
+ { 20, 13, 9, 9, IPA_EE_AP } },
[IPA_4_0_MHI][IPA_CLIENT_MEMCPY_DMA_ASYNC_CONS] = {
true, IPA_v4_0_MHI_GROUP_DMA,
false,
IPA_DPS_HPS_SEQ_TYPE_INVALID,
QMB_MASTER_SELECT_PCIE,
- { 21, 15, 9, 9, IPA_EE_AP } },
+ { 21, 14, 9, 9, IPA_EE_AP } },
[IPA_4_0_MHI][IPA_CLIENT_Q6_LTE_WIFI_AGGR_CONS] = {
true, IPA_v4_0_GROUP_UL_DL,
false,
@@ -1477,19 +1477,19 @@
false,
IPA_DPS_HPS_SEQ_TYPE_INVALID,
QMB_MASTER_SELECT_PCIE,
- { 18, 12, 6, 9, IPA_EE_AP } },
+ { 18, 11, 6, 9, IPA_EE_AP } },
[IPA_4_0_MHI][IPA_CLIENT_TEST3_CONS] = {
true, IPA_v4_0_GROUP_UL_DL,
false,
IPA_DPS_HPS_SEQ_TYPE_INVALID,
QMB_MASTER_SELECT_DDR,
- { 20, 14, 9, 9, IPA_EE_AP } },
+ { 20, 13, 9, 9, IPA_EE_AP } },
[IPA_4_0_MHI][IPA_CLIENT_TEST4_CONS] = {
true, IPA_v4_0_GROUP_UL_DL,
false,
IPA_DPS_HPS_SEQ_TYPE_INVALID,
QMB_MASTER_SELECT_PCIE,
- { 21, 15, 9, 9, IPA_EE_AP } },
+ { 21, 14, 9, 9, IPA_EE_AP } },
/* Dummy consumer (pipe 31) is used in L2TP rt rule */
[IPA_4_0_MHI][IPA_CLIENT_DUMMY_CONS] = {
true, IPA_v4_0_GROUP_UL_DL,
@@ -1583,7 +1583,6 @@
clients->names[i++] = IPA_CLIENT_WLAN1_CONS;
clients->names[i++] = IPA_CLIENT_WLAN2_CONS;
clients->names[i++] = IPA_CLIENT_WLAN3_CONS;
- clients->names[i++] = IPA_CLIENT_WLAN4_CONS;
break;
case IPA_RM_RESOURCE_MHI_CONS:
clients->names[i++] = IPA_CLIENT_MHI_CONS;
@@ -4318,6 +4317,38 @@
ipa3_ctx->tag_process_before_gating = val;
}
+/**
+ * ipa3_is_vlan_mode - check if a LAN driver should load in VLAN mode
+ * @iface - type of vlan capable device
+ * @res - query result: true for vlan mode, false for non vlan mode
+ *
+ * API must be called after ipa_is_ready() returns true, otherwise it will fail
+ *
+ * Returns: 0 on success, negative on failure
+ */
+static int ipa3_is_vlan_mode(enum ipa_vlan_ifaces iface, bool *res)
+{
+ if (!res) {
+ IPAERR("NULL out param\n");
+ return -EINVAL;
+ }
+
+ if (iface < 0 || iface > IPA_VLAN_IF_MAX) {
+ IPAERR("invalid iface %d\n", iface);
+ return -EINVAL;
+ }
+
+ if (!ipa3_is_ready()) {
+ IPAERR("IPA is not ready yet\n");
+ return -ENODEV;
+ }
+
+ *res = ipa3_ctx->vlan_mode_iface[iface];
+
+ IPADBG("Driver %d vlan mode is %d\n", iface, *res);
+ return 0;
+}
+
int ipa3_bind_api_controller(enum ipa_hw_type ipa_hw_type,
struct ipa_api_controller *api_ctrl)
{
@@ -4504,6 +4535,7 @@
api_ctrl->ipa_disable_wdi3_pipes = ipa3_disable_wdi3_pipes;
api_ctrl->ipa_tz_unlock_reg = ipa3_tz_unlock_reg;
api_ctrl->ipa_get_smmu_params = ipa3_get_smmu_params;
+ api_ctrl->ipa_is_vlan_mode = ipa3_is_vlan_mode;
return 0;
}
@@ -4867,6 +4899,77 @@
}
}
+static int __ipa3_stop_gsi_channel(u32 clnt_hdl)
+{
+ struct ipa_mem_buffer mem;
+ int res = 0;
+ int i;
+ struct ipa3_ep_context *ep;
+
+ if (clnt_hdl >= ipa3_ctx->ipa_num_pipes ||
+ ipa3_ctx->ep[clnt_hdl].valid == 0) {
+ IPAERR("bad parm.\n");
+ return -EINVAL;
+ }
+
+ ep = &ipa3_ctx->ep[clnt_hdl];
+ memset(&mem, 0, sizeof(mem));
+
+ if (IPA_CLIENT_IS_PROD(ep->client)) {
+ IPADBG("Calling gsi_stop_channel ch:%lu\n",
+ ep->gsi_chan_hdl);
+ res = gsi_stop_channel(ep->gsi_chan_hdl);
+ IPADBG("gsi_stop_channel ch: %lu returned %d\n",
+ ep->gsi_chan_hdl, res);
+ return res;
+ }
+
+ for (i = 0; i < IPA_GSI_CHANNEL_STOP_MAX_RETRY; i++) {
+ IPADBG("Calling gsi_stop_channel ch:%lu\n",
+ ep->gsi_chan_hdl);
+ res = gsi_stop_channel(ep->gsi_chan_hdl);
+ IPADBG("gsi_stop_channel ch: %lu returned %d\n",
+ ep->gsi_chan_hdl, res);
+ if (res != -GSI_STATUS_AGAIN && res != -GSI_STATUS_TIMED_OUT)
+ return res;
+
+ IPADBG("Inject a DMA_TASK with 1B packet to IPA\n");
+ /* Send a 1B packet DMA_TASK to IPA and try again */
+ res = ipa3_inject_dma_task_for_gsi();
+ if (res) {
+ IPAERR("Failed to inject DMA TASk for GSI\n");
+ return res;
+ }
+
+ /* sleep for short period to flush IPA */
+ usleep_range(IPA_GSI_CHANNEL_STOP_SLEEP_MIN_USEC,
+ IPA_GSI_CHANNEL_STOP_SLEEP_MAX_USEC);
+ }
+
+ IPAERR("Failed to stop GSI channel with retries\n");
+ return -EFAULT;
+}
+
+/**
+ * ipa3_stop_gsi_channel()- Stops a GSI channel in IPA
+ * @chan_hdl: GSI channel handle
+ *
+ * This function implements the sequence to stop a GSI channel
+ * in IPA. This function returns when the channel is in STOP state.
+ *
+ * Return value: 0 on success, negative otherwise
+ */
+int ipa3_stop_gsi_channel(u32 clnt_hdl)
+{
+ int res;
+
+ IPA_ACTIVE_CLIENTS_INC_EP(ipa3_get_client_mapping(clnt_hdl));
+ res = __ipa3_stop_gsi_channel(clnt_hdl);
+ IPA_ACTIVE_CLIENTS_DEC_EP(ipa3_get_client_mapping(clnt_hdl));
+
+ return res;
+}
+
void ipa3_suspend_apps_pipes(bool suspend)
{
struct ipa_ep_cfg_ctrl cfg;
@@ -4889,7 +4992,7 @@
ipa_ep_idx);
if (ipa3_ctx->ipa_hw_type >= IPA_HW_v4_0) {
if (suspend) {
- res = ipa3_stop_gsi_channel(ipa_ep_idx);
+ res = __ipa3_stop_gsi_channel(ipa_ep_idx);
if (res) {
IPAERR("failed to stop LAN channel\n");
ipa_assert();
@@ -4923,7 +5026,7 @@
ipa_ep_idx);
if (ipa3_ctx->ipa_hw_type >= IPA_HW_v4_0) {
if (suspend) {
- res = ipa3_stop_gsi_channel(ipa_ep_idx);
+ res = __ipa3_stop_gsi_channel(ipa_ep_idx);
if (res) {
IPAERR("failed to stop WAN channel\n");
ipa_assert();
@@ -5013,73 +5116,6 @@
return 0;
}
-/**
- * ipa3_stop_gsi_channel()- Stops a GSI channel in IPA
- * @chan_hdl: GSI channel handle
- *
- * This function implements the sequence to stop a GSI channel
- * in IPA. This function returns when the channel is is STOP state.
- *
- * Return value: 0 on success, negative otherwise
- */
-int ipa3_stop_gsi_channel(u32 clnt_hdl)
-{
- struct ipa_mem_buffer mem;
- int res = 0;
- int i;
- struct ipa3_ep_context *ep;
-
- if (clnt_hdl >= ipa3_ctx->ipa_num_pipes ||
- ipa3_ctx->ep[clnt_hdl].valid == 0) {
- IPAERR("bad parm.\n");
- return -EINVAL;
- }
-
- ep = &ipa3_ctx->ep[clnt_hdl];
-
- IPA_ACTIVE_CLIENTS_INC_EP(ipa3_get_client_mapping(clnt_hdl));
-
- memset(&mem, 0, sizeof(mem));
-
- if (IPA_CLIENT_IS_PROD(ep->client)) {
- IPADBG("Calling gsi_stop_channel ch:%lu\n",
- ep->gsi_chan_hdl);
- res = gsi_stop_channel(ep->gsi_chan_hdl);
- IPADBG("gsi_stop_channel ch: %lu returned %d\n",
- ep->gsi_chan_hdl, res);
- goto end_sequence;
- }
-
- for (i = 0; i < IPA_GSI_CHANNEL_STOP_MAX_RETRY; i++) {
- IPADBG("Calling gsi_stop_channel ch:%lu\n",
- ep->gsi_chan_hdl);
- res = gsi_stop_channel(ep->gsi_chan_hdl);
- IPADBG("gsi_stop_channel ch: %lu returned %d\n",
- ep->gsi_chan_hdl, res);
- if (res != -GSI_STATUS_AGAIN && res != -GSI_STATUS_TIMED_OUT)
- goto end_sequence;
-
- IPADBG("Inject a DMA_TASK with 1B packet to IPA\n");
- /* Send a 1B packet DMA_TASK to IPA and try again */
- res = ipa3_inject_dma_task_for_gsi();
- if (res) {
- IPAERR("Failed to inject DMA TASk for GSI\n");
- goto end_sequence;
- }
-
- /* sleep for short period to flush IPA */
- usleep_range(IPA_GSI_CHANNEL_STOP_SLEEP_MIN_USEC,
- IPA_GSI_CHANNEL_STOP_SLEEP_MAX_USEC);
- }
-
- IPAERR("Failed to stop GSI channel with retries\n");
- res = -EFAULT;
-end_sequence:
- IPA_ACTIVE_CLIENTS_DEC_EP(ipa3_get_client_mapping(clnt_hdl));
-
- return res;
-}
-
static int ipa3_load_single_fw(const struct firmware *firmware,
const struct elf32_phdr *phdr)
{
diff --git a/drivers/platform/msm/ipa/ipa_v3/rmnet_ipa.c b/drivers/platform/msm/ipa/ipa_v3/rmnet_ipa.c
index 66d4b10..0444b67 100644
--- a/drivers/platform/msm/ipa/ipa_v3/rmnet_ipa.c
+++ b/drivers/platform/msm/ipa/ipa_v3/rmnet_ipa.c
@@ -2455,8 +2455,14 @@
ret);
goto config_err;
}
+
+ /*
+ * for IPA 4.0 offline charge is not needed and we need to prevent
+ * power collapse until IPA uC is loaded.
+ */
atomic_set(&rmnet_ipa3_ctx->is_initialized, 1);
- if (!atomic_read(&rmnet_ipa3_ctx->is_ssr)) {
+ if (!atomic_read(&rmnet_ipa3_ctx->is_ssr) && ipa3_ctx->ipa_hw_type !=
+ IPA_HW_v4_0) {
/* offline charging mode */
ipa3_proxy_clk_unvote();
}
diff --git a/drivers/platform/msm/ipa/test/ipa_test_mhi.c b/drivers/platform/msm/ipa/test/ipa_test_mhi.c
index 98861de..195799e 100644
--- a/drivers/platform/msm/ipa/test/ipa_test_mhi.c
+++ b/drivers/platform/msm/ipa/test/ipa_test_mhi.c
@@ -612,7 +612,8 @@
p_events[ev_ring_idx].rp =
(u32)event_ring_bufs[ev_ring_idx].phys_base;
p_events[ev_ring_idx].wp =
- (u32)event_ring_bufs[ev_ring_idx].phys_base;
+ (u32)event_ring_bufs[ev_ring_idx].phys_base +
+ event_ring_bufs[ev_ring_idx].size - 16;
} else {
IPA_UT_LOG("Skip configuring event ring - already done\n");
}
@@ -3261,11 +3262,11 @@
IPA_UT_ADD_TEST(suspend_resume_with_open_aggr,
"several suspend/resume iterations with open aggregation frame",
ipa_mhi_test_in_loop_suspend_resume_aggr_open,
- true, IPA_HW_v3_0, IPA_HW_MAX),
+ true, IPA_HW_v3_0, IPA_HW_v3_5_1),
IPA_UT_ADD_TEST(force_suspend_resume_with_open_aggr,
"several force suspend/resume iterations with open aggregation frame",
ipa_mhi_test_in_loop_force_suspend_resume_aggr_open,
- true, IPA_HW_v3_0, IPA_HW_MAX),
+ true, IPA_HW_v3_0, IPA_HW_v3_5_1),
IPA_UT_ADD_TEST(suspend_resume_with_host_wakeup,
"several suspend and host wakeup resume iterations",
ipa_mhi_test_in_loop_suspend_host_wakeup,
diff --git a/drivers/platform/msm/msm_11ad/msm_11ad.c b/drivers/platform/msm/msm_11ad/msm_11ad.c
index f64e9de..4c0531f 100644
--- a/drivers/platform/msm/msm_11ad/msm_11ad.c
+++ b/drivers/platform/msm/msm_11ad/msm_11ad.c
@@ -33,16 +33,14 @@
#include "wil_platform.h"
#include "msm_11ad.h"
-#define WIGIG_VENDOR (0x1ae9)
-#define WIGIG_DEVICE (0x0310)
-
#define SMMU_BASE 0x20000000 /* Device address range base */
#define SMMU_SIZE ((SZ_1G * 4ULL) - SMMU_BASE)
#define WIGIG_ENABLE_DELAY 50
#define WIGIG_SUBSYS_NAME "WIGIG"
-#define WIGIG_RAMDUMP_SIZE 0x200000 /* maximum ramdump size */
+#define WIGIG_RAMDUMP_SIZE_SPARROW 0x200000 /* maximum ramdump size */
+#define WIGIG_RAMDUMP_SIZE_TALYN 0x400000 /* maximum ramdump size */
#define WIGIG_DUMP_FORMAT_VER 0x1
#define WIGIG_DUMP_MAGIC_VER_V1 0x57474947
#define VDD_MIN_UV 1028000
@@ -61,6 +59,18 @@
static const char * const gpio_en_name = "qcom,wigig-en";
static const char * const sleep_clk_en_name = "qcom,sleep-clk-en";
+struct wigig_pci {
+ struct pci_device_id pci_dev;
+ u32 ramdump_sz;
+};
+
+static const struct wigig_pci wigig_pci_tbl[] = {
+ { .pci_dev = { PCI_DEVICE(0x1ae9, 0x0310) },
+ .ramdump_sz = WIGIG_RAMDUMP_SIZE_SPARROW},
+ { .pci_dev = { PCI_DEVICE(0x17cb, 0x1201) },
+ .ramdump_sz = WIGIG_RAMDUMP_SIZE_TALYN},
+};
+
struct msm11ad_vreg {
const char *name;
struct regulator *reg;
@@ -113,6 +123,7 @@
void *ramdump_addr;
struct msm_dump_data dump_data;
struct ramdump_device *ramdump_dev;
+ u32 ramdump_size;
/* external vregs and clocks */
struct msm11ad_vreg vdd;
@@ -859,7 +870,7 @@
{
if (ctx->rops.ramdump && ctx->wil_handle) {
int rc = ctx->rops.ramdump(ctx->wil_handle, ctx->ramdump_addr,
- WIGIG_RAMDUMP_SIZE);
+ ctx->ramdump_size);
if (rc) {
dev_err(ctx->dev, "ramdump failed : %d\n", rc);
return -EINVAL;
@@ -898,7 +909,7 @@
memset(&segment, 0, sizeof(segment));
segment.v_address = ctx->ramdump_addr;
- segment.size = WIGIG_RAMDUMP_SIZE;
+ segment.size = ctx->ramdump_size;
return do_ramdump(ctx->ramdump_dev, &segment, 1);
}
@@ -961,14 +972,14 @@
}
/* register ramdump area */
- ctx->ramdump_addr = kmalloc(WIGIG_RAMDUMP_SIZE, GFP_KERNEL);
+ ctx->ramdump_addr = kmalloc(ctx->ramdump_size, GFP_KERNEL);
if (!ctx->ramdump_addr) {
rc = -ENOMEM;
goto out_rc;
}
ctx->dump_data.addr = virt_to_phys(ctx->ramdump_addr);
- ctx->dump_data.len = WIGIG_RAMDUMP_SIZE;
+ ctx->dump_data.len = ctx->ramdump_size;
dump_entry.id = MSM_DUMP_DATA_WIGIG;
dump_entry.addr = virt_to_phys(&ctx->dump_data);
@@ -1031,8 +1042,9 @@
struct device_node *rc_node;
struct pci_dev *pcidev = NULL;
u32 smmu_mapping[2];
- int rc;
+ int rc, i;
u32 val;
+ bool pcidev_found = false;
ctx = devm_kzalloc(dev, sizeof(*ctx), GFP_KERNEL);
if (!ctx)
@@ -1118,7 +1130,7 @@
rc = msm_11ad_init_vregs(ctx);
if (rc) {
dev_err(ctx->dev, "msm_11ad_init_vregs failed: %d\n", rc);
- goto out_bus_scale;
+ return rc;
}
rc = msm_11ad_enable_vregs(ctx);
if (rc) {
@@ -1161,21 +1173,32 @@
goto out_rc;
}
/* search for PCIE device in our domain */
- do {
- pcidev = pci_get_device(WIGIG_VENDOR, WIGIG_DEVICE, pcidev);
- if (!pcidev)
- break;
+ for (i = 0; i < ARRAY_SIZE(wigig_pci_tbl); ++i) {
+ do {
+ pcidev = pci_get_device(wigig_pci_tbl[i].pci_dev.vendor,
+ wigig_pci_tbl[i].pci_dev.device,
+ pcidev);
+ if (!pcidev)
+ break;
- if (pci_domain_nr(pcidev->bus) == ctx->rc_index)
+ if (pci_domain_nr(pcidev->bus) == ctx->rc_index) {
+ ctx->ramdump_size = wigig_pci_tbl[i].ramdump_sz;
+ pcidev_found = true;
+ break;
+ }
+ } while (true);
+
+ if (pcidev_found)
break;
- } while (true);
- if (!pcidev) {
+ }
+ if (!pcidev_found) {
rc = -ENODEV;
- dev_err(ctx->dev, "Wigig device %4x:%4x not found\n",
- WIGIG_VENDOR, WIGIG_DEVICE);
+ dev_err(ctx->dev, "Wigig device not found\n");
goto out_rc;
}
ctx->pcidev = pcidev;
+ dev_dbg(ctx->dev, "Wigig device %4x:%4x found\n",
+ ctx->pcidev->vendor, ctx->pcidev->device);
rc = msm_pcie_pm_control(MSM_PCIE_RESUME, pcidev->bus->number,
pcidev, NULL, 0);
@@ -1267,8 +1290,6 @@
msm_11ad_release_clocks(ctx);
msm_11ad_disable_vregs(ctx);
msm_11ad_release_vregs(ctx);
-out_bus_scale:
- msm_bus_cl_clear_pdata(ctx->bus_scale);
return rc;
}
diff --git a/drivers/platform/msm/usb_bam.c b/drivers/platform/msm/usb_bam.c
index 93121df..95e3782 100644
--- a/drivers/platform/msm/usb_bam.c
+++ b/drivers/platform/msm/usb_bam.c
@@ -321,10 +321,18 @@
struct usb_bam_ctx_type *ctx = &msm_usb_bam[pipe_connect->bam_type];
struct sps_mem_buffer *data_buf = &(pipe_connect->data_mem_buf);
struct sps_mem_buffer *desc_buf = &(pipe_connect->desc_mem_buf);
+ struct device *dev = &ctx->usb_bam_pdev->dev;
+ struct sg_table data_sgt, desc_sgt;
+ dma_addr_t data_iova, desc_iova;
+ u32 data_fifo_size;
pr_debug("%s: data_fifo size:%x desc_fifo_size:%x\n",
__func__, pipe_connect->data_fifo_size,
pipe_connect->desc_fifo_size);
+
+ if (dev->parent)
+ dev = dev->parent;
+
switch (pipe_connect->mem_type) {
case SPS_PIPE_MEM:
log_event_dbg("%s: USB BAM using SPS pipe memory\n", __func__);
@@ -366,7 +374,16 @@
ret = -ENOMEM;
goto err_exit;
}
+
memset_io(data_buf->base, 0, data_buf->size);
+ data_buf->iova = dma_map_resource(dev, data_buf->phys_base,
+ data_buf->size, DMA_BIDIRECTIONAL, 0);
+ if (dma_mapping_error(dev, data_buf->iova))
+ log_event_err("%s(): oci_mem: err mapping data_buf\n",
+ __func__);
+ log_event_dbg("%s: data_buf:%s virt:%pK, phys:%lx, iova:%lx\n",
+ __func__, dev_name(dev), data_buf->base,
+ (unsigned long)data_buf->phys_base, data_buf->iova);
desc_buf->phys_base = pipe_connect->desc_fifo_base_offset +
ctx->usb_bam_data->usb_bam_fifo_baseaddr;
@@ -380,6 +397,16 @@
goto err_exit;
}
memset_io(desc_buf->base, 0, desc_buf->size);
+ desc_buf->iova = dma_map_resource(dev, desc_buf->phys_base,
+ desc_buf->size,
+ DMA_BIDIRECTIONAL, 0);
+ if (dma_mapping_error(dev, desc_buf->iova))
+ log_event_err("%s(): oci_mem: err mapping desc_buf\n",
+ __func__);
+
+ log_event_dbg("%s: desc_buf:%s virt:%pK, phys:%lx, iova:%lx\n",
+ __func__, dev_name(dev), desc_buf->base,
+ (unsigned long)desc_buf->phys_base, desc_buf->iova);
break;
case SYSTEM_MEM:
log_event_dbg("%s: USB BAM using system memory\n", __func__);
@@ -391,56 +418,57 @@
}
/* BAM would use system memory, allocate FIFOs */
- data_buf->size = pipe_connect->data_fifo_size;
+ data_fifo_size = data_buf->size = pipe_connect->data_fifo_size;
/* On platforms which use CI controller, USB HW can fetch
* additional 128 bytes at the end of circular buffer when
* AXI prefetch is enabled and hence requirement is to
* allocate 512 bytes more than required length.
*/
if (pipe_connect->bam_type == CI_CTRL)
- data_buf->base =
- dma_alloc_coherent(&ctx->usb_bam_pdev->dev,
- (pipe_connect->data_fifo_size +
- DATA_FIFO_EXTRA_MEM_ALLOC_SIZE),
- &(data_buf->phys_base),
- GFP_KERNEL);
- else
- data_buf->base =
- dma_alloc_coherent(&ctx->usb_bam_pdev->dev,
- pipe_connect->data_fifo_size,
- &(data_buf->phys_base),
- GFP_KERNEL);
+ data_fifo_size += DATA_FIFO_EXTRA_MEM_ALLOC_SIZE;
+
+ data_buf->base = dma_alloc_attrs(dev, data_fifo_size,
+ &data_iova, GFP_KERNEL,
+ DMA_ATTR_FORCE_CONTIGUOUS);
if (!data_buf->base) {
- log_event_err("%s: dma_alloc_coherent failed for data fifo\n",
+ log_event_err("%s: data_fifo: dma_alloc_attr failed\n",
__func__);
ret = -ENOMEM;
goto err_exit;
}
memset(data_buf->base, 0, pipe_connect->data_fifo_size);
+ data_buf->iova = data_iova;
+ dma_get_sgtable(dev, &data_sgt, data_buf->base, data_buf->iova,
+ data_fifo_size);
+ data_buf->phys_base = page_to_phys(sg_page(data_sgt.sgl));
+ sg_free_table(&data_sgt);
+ log_event_dbg("%s: data_buf:%s virt:%pK, phys:%lx, iova:%lx\n",
+ __func__, dev_name(dev), data_buf->base,
+ (unsigned long)data_buf->phys_base, data_buf->iova);
+
desc_buf->size = pipe_connect->desc_fifo_size;
- desc_buf->base = dma_alloc_coherent(&ctx->usb_bam_pdev->dev,
- pipe_connect->desc_fifo_size,
- &(desc_buf->phys_base),
- GFP_KERNEL);
+ desc_buf->base = dma_alloc_attrs(dev,
+ pipe_connect->desc_fifo_size,
+ &desc_iova, GFP_KERNEL,
+ DMA_ATTR_FORCE_CONTIGUOUS);
if (!desc_buf->base) {
- log_event_err("%s: dma_alloc_coherent failed for desc fifo\n",
+ log_event_err("%s: desc_fifo: dma_alloc_attr failed\n",
__func__);
- if (pipe_connect->bam_type == CI_CTRL)
- dma_free_coherent(&ctx->usb_bam_pdev->dev,
- (pipe_connect->data_fifo_size +
- DATA_FIFO_EXTRA_MEM_ALLOC_SIZE),
- data_buf->base,
- data_buf->phys_base);
- else
- dma_free_coherent(&ctx->usb_bam_pdev->dev,
- pipe_connect->data_fifo_size,
- data_buf->base,
- data_buf->phys_base);
+ dma_free_attrs(dev, data_fifo_size, data_buf->base,
+ data_buf->iova, DMA_ATTR_FORCE_CONTIGUOUS);
ret = -ENOMEM;
goto err_exit;
}
memset(desc_buf->base, 0, pipe_connect->desc_fifo_size);
+ desc_buf->iova = desc_iova;
+ dma_get_sgtable(dev, &desc_sgt, desc_buf->base, desc_buf->iova,
+ desc_buf->size);
+ desc_buf->phys_base = page_to_phys(sg_page(desc_sgt.sgl));
+ sg_free_table(&desc_sgt);
+ log_event_dbg("%s: desc_buf:%s virt:%pK, phys:%lx, iova:%lx\n",
+ __func__, dev_name(dev), desc_buf->base,
+ (unsigned long)desc_buf->phys_base, desc_buf->iova);
break;
default:
log_event_err("%s: invalid mem type\n", __func__);
@@ -476,35 +504,40 @@
&ctx->usb_bam_connections[idx];
struct sps_connect *sps_connection =
&ctx->usb_bam_sps.sps_connections[idx];
+ struct device *dev = &ctx->usb_bam_pdev->dev;
+ u32 data_fifo_size;
pr_debug("%s(): data size:%x desc size:%x\n",
__func__, sps_connection->data.size,
sps_connection->desc.size);
+ if (dev->parent)
+ dev = dev->parent;
+
switch (pipe_connect->mem_type) {
case SYSTEM_MEM:
log_event_dbg("%s: Freeing system memory used by PIPE\n",
__func__);
- if (sps_connection->data.phys_base) {
+ if (sps_connection->data.iova) {
+ data_fifo_size = sps_connection->data.size;
if (cur_bam == CI_CTRL)
- dma_free_coherent(&ctx->usb_bam_pdev->dev,
- (sps_connection->data.size +
- DATA_FIFO_EXTRA_MEM_ALLOC_SIZE),
+ data_fifo_size +=
+ DATA_FIFO_EXTRA_MEM_ALLOC_SIZE;
+
+ dma_free_attrs(dev, data_fifo_size,
sps_connection->data.base,
- sps_connection->data.phys_base);
- else
- dma_free_coherent(&ctx->usb_bam_pdev->dev,
- sps_connection->data.size,
- sps_connection->data.base,
- sps_connection->data.phys_base);
+ sps_connection->data.iova,
+ DMA_ATTR_FORCE_CONTIGUOUS);
+ sps_connection->data.iova = 0;
sps_connection->data.phys_base = 0;
pipe_connect->data_mem_buf.base = NULL;
}
- if (sps_connection->desc.phys_base) {
- dma_free_coherent(&ctx->usb_bam_pdev->dev,
- sps_connection->desc.size,
+ if (sps_connection->desc.iova) {
+ dma_free_attrs(dev, sps_connection->desc.size,
sps_connection->desc.base,
- sps_connection->desc.phys_base);
+ sps_connection->desc.iova,
+ DMA_ATTR_FORCE_CONTIGUOUS);
+ sps_connection->desc.iova = 0;
sps_connection->desc.phys_base = 0;
pipe_connect->desc_mem_buf.base = NULL;
}
@@ -512,11 +545,25 @@
case OCI_MEM:
log_event_dbg("Freeing oci memory used by BAM PIPE\n");
if (sps_connection->data.base) {
+ if (sps_connection->data.iova) {
+ dma_unmap_resource(dev,
+ sps_connection->data.iova,
+ sps_connection->data.size,
+ DMA_BIDIRECTIONAL, 0);
+ sps_connection->data.iova = 0;
+ }
iounmap(sps_connection->data.base);
sps_connection->data.base = NULL;
pipe_connect->data_mem_buf.base = NULL;
}
if (sps_connection->desc.base) {
+ if (sps_connection->desc.iova) {
+ dma_unmap_resource(dev,
+ sps_connection->desc.iova,
+ sps_connection->desc.size,
+ DMA_BIDIRECTIONAL, 0);
+ sps_connection->desc.iova = 0;
+ }
iounmap(sps_connection->desc.base);
sps_connection->desc.base = NULL;
pipe_connect->desc_mem_buf.base = NULL;
@@ -530,7 +577,8 @@
return 0;
}
-static int connect_pipe(enum usb_ctrl cur_bam, u8 idx, u32 *usb_pipe_idx)
+static int connect_pipe(enum usb_ctrl cur_bam, u8 idx, u32 *usb_pipe_idx,
+ unsigned long iova)
{
int ret;
struct usb_bam_ctx_type *ctx = &msm_usb_bam[cur_bam];
@@ -575,9 +623,11 @@
if (dir == USB_TO_PEER_PERIPHERAL) {
sps_connection->mode = SPS_MODE_SRC;
*usb_pipe_idx = pipe_connect->src_pipe_index;
+ sps_connection->dest_iova = iova;
} else {
sps_connection->mode = SPS_MODE_DEST;
*usb_pipe_idx = pipe_connect->dst_pipe_index;
+ sps_connection->source_iova = iova;
}
sps_connection->data = *data_buf;
@@ -1059,7 +1109,34 @@
return 0;
}
-int usb_bam_connect(enum usb_ctrl cur_bam, int idx, u32 *bam_pipe_idx)
+int get_qdss_bam_info(enum usb_ctrl cur_bam, u8 idx,
+ phys_addr_t *p_addr, u32 *bam_size)
+{
+ int ret = 0;
+ struct usb_bam_ctx_type *ctx = &msm_usb_bam[cur_bam];
+ struct usb_bam_pipe_connect *pipe_connect =
+ &ctx->usb_bam_connections[idx];
+ unsigned long peer_bam_handle;
+
+ ret = sps_phy2h(pipe_connect->dst_phy_addr, &peer_bam_handle);
+ if (ret) {
+ log_event_err("%s: sps_phy2h failed (src BAM) %d\n",
+ __func__, ret);
+ return ret;
+ }
+
+ ret = sps_get_bam_addr(peer_bam_handle, p_addr, bam_size);
+ if (ret) {
+ log_event_err("%s: sps_get_bam_addr failed%d\n",
+ __func__, ret);
+ return ret;
+ }
+
+ return 0;
+}
+
+int usb_bam_connect(enum usb_ctrl cur_bam, int idx, u32 *bam_pipe_idx,
+ unsigned long iova)
{
int ret;
struct usb_bam_ctx_type *ctx = &msm_usb_bam[cur_bam];
@@ -1110,7 +1187,7 @@
/* Set the BAM mode (host/device) according to connected pipe */
info[cur_bam].cur_bam_mode = pipe_connect->bam_mode;
- ret = connect_pipe(cur_bam, idx, bam_pipe_idx);
+ ret = connect_pipe(cur_bam, idx, bam_pipe_idx, iova);
if (ret) {
log_event_err("%s: pipe connection[%d] failure\n",
__func__, idx);
@@ -3024,6 +3101,7 @@
struct usb_bam_ctx_type *ctx = dev_get_drvdata(&pdev->dev);
enum usb_ctrl bam_type = ctx->usb_bam_data->bam_type;
struct sps_bam_props props;
+ struct device *dev;
memset(&props, 0, sizeof(props));
@@ -3059,8 +3137,16 @@
pr_debug("Register and enable HSUSB BAM\n");
props.options |= SPS_BAM_OPT_ENABLE_AT_BOOT;
}
- ret = sps_register_bam_device(&props, &ctx->h_bam);
+ dev = &ctx->usb_bam_pdev->dev;
+ if (dev && dev->parent && !device_property_present(dev->parent,
+ "qcom,smmu-s1-bypass")) {
+ pr_info("%s: setting SPS_BAM_SMMU_EN flag with (%s)\n",
+ __func__, dev_name(dev));
+ props.options |= SPS_BAM_SMMU_EN;
+ }
+
+ ret = sps_register_bam_device(&props, &ctx->h_bam);
if (ret < 0) {
log_event_err("%s: register bam error %d\n", __func__, ret);
return -EFAULT;
diff --git a/drivers/power/reset/msm-poweroff.c b/drivers/power/reset/msm-poweroff.c
index bfc401a..5b31889 100644
--- a/drivers/power/reset/msm-poweroff.c
+++ b/drivers/power/reset/msm-poweroff.c
@@ -301,12 +301,29 @@
__raw_writel(0x7766550a, restart_reason);
} else if (!strncmp(cmd, "oem-", 4)) {
unsigned long code;
+ unsigned long reset_reason;
int ret;
ret = kstrtoul(cmd + 4, 16, &code);
- if (!ret)
+ if (!ret) {
+ /* Bit-2 to bit-7 of SOFT_RB_SPARE for hard
+ * reset reason:
+ * Value 0 to 31 for common defined features
+ * Value 32 to 63 for oem specific features
+ */
+ reset_reason = code +
+ PON_RESTART_REASON_OEM_MIN;
+ if (reset_reason > PON_RESTART_REASON_OEM_MAX ||
+ reset_reason < PON_RESTART_REASON_OEM_MIN) {
+ pr_err("Invalid oem reset reason: %lx\n",
+ reset_reason);
+ } else {
+ qpnp_pon_set_restart_reason(
+ reset_reason);
+ }
__raw_writel(0x6f656d00 | (code & 0xff),
restart_reason);
+ }
} else if (!strncmp(cmd, "edl", 3)) {
enable_emergency_dload_mode();
} else {
diff --git a/drivers/power/supply/qcom/smb-lib.c b/drivers/power/supply/qcom/smb-lib.c
index ec165b3..1e5e136 100644
--- a/drivers/power/supply/qcom/smb-lib.c
+++ b/drivers/power/supply/qcom/smb-lib.c
@@ -1462,8 +1462,10 @@
if (!chg->usb_icl_votable) {
chg->usb_icl_votable = find_votable("USB_ICL");
- if (!chg->usb_icl_votable)
- return -EINVAL;
+ if (!chg->usb_icl_votable) {
+ rc = -EINVAL;
+ goto unlock;
+ }
}
vote(chg->usb_icl_votable, USBIN_USBIN_BOOST_VOTER, true, 0);
diff --git a/drivers/regulator/Kconfig b/drivers/regulator/Kconfig
index 6afa0f5..ee1b322 100644
--- a/drivers/regulator/Kconfig
+++ b/drivers/regulator/Kconfig
@@ -1046,6 +1046,27 @@
control allows for voting on regulator state between multiple
processors within the SoC.
+config REGULATOR_RPM_SMD
+ bool "RPM SMD regulator driver"
+ depends on OF
+ depends on MSM_RPM_SMD
+ help
+ Compile in support for the RPM SMD regulator driver which is used for
+ setting voltages and other parameters of the various power rails
+ supplied by some Qualcomm PMICs. The RPM SMD regulator driver should
+ be used on systems which contain an RPM which communicates with the
+ application processor over SMD.
+
+config REGULATOR_SPM
+ bool "SPM regulator driver"
+ depends on SPMI
+ help
+ Enable support for the SPM regulator driver which is used for
+ setting voltages of processor supply regulators via the SPM module
+ found inside chips of Qualcomm Technologies Inc. The SPM regulator
+ driver can be used on QTI SoCs where the APSS processor cores are
+ supplied by their own PMIC regulator.
+
config REGULATOR_STUB
tristate "Stub Regulator"
help
diff --git a/drivers/regulator/Makefile b/drivers/regulator/Makefile
index 59dea6e..b2bfba8 100644
--- a/drivers/regulator/Makefile
+++ b/drivers/regulator/Makefile
@@ -113,6 +113,8 @@
obj-$(CONFIG_REGULATOR_WM8350) += wm8350-regulator.o
obj-$(CONFIG_REGULATOR_WM8400) += wm8400-regulator.o
obj-$(CONFIG_REGULATOR_WM8994) += wm8994-regulator.o
+obj-$(CONFIG_REGULATOR_RPM_SMD) += rpm-smd-regulator.o
+obj-$(CONFIG_REGULATOR_SPM) += spm-regulator.o
obj-$(CONFIG_REGULATOR_CPR3) += cpr3-regulator.o cpr3-util.o
obj-$(CONFIG_REGULATOR_CPR3_HMSS) += cpr3-hmss-regulator.o
diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c
index e463117..1f60635 100644
--- a/drivers/regulator/core.c
+++ b/drivers/regulator/core.c
@@ -4184,6 +4184,7 @@
debugfs_remove_recursive(rdev->debugfs);
if (rdev->debug_consumer)
rdev->debug_consumer->debugfs = NULL;
+ rdev->debugfs = NULL;
regulator_put(rdev->debug_consumer);
}
}
@@ -4225,9 +4226,10 @@
regulator = regulator_get(NULL, rdev_get_name(rdev));
if (IS_ERR(regulator)) {
- debugfs_remove_recursive(rdev->debugfs);
- rdev_err(rdev, "regulator get failed, ret=%ld\n",
- PTR_ERR(regulator));
+ rdev_deinit_debugfs(rdev);
+ if (PTR_ERR(regulator) != -EPROBE_DEFER)
+ rdev_err(rdev, "regulator get failed, ret=%ld\n",
+ PTR_ERR(regulator));
return;
}
rdev->debug_consumer = regulator;
diff --git a/drivers/regulator/rpm-smd-regulator.c b/drivers/regulator/rpm-smd-regulator.c
new file mode 100644
index 0000000..b38db82
--- /dev/null
+++ b/drivers/regulator/rpm-smd-regulator.c
@@ -0,0 +1,1945 @@
+/* Copyright (c) 2012-2015, 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/module.h>
+#include <linux/err.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+#include <linux/string.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
+#include <linux/regulator/driver.h>
+#include <linux/regulator/machine.h>
+#include <linux/regulator/of_regulator.h>
+#include <linux/regulator/rpm-smd-regulator.h>
+#include <soc/qcom/rpm-smd.h>
+
+/* Debug Definitions */
+
+enum {
+ RPM_VREG_DEBUG_REQUEST = BIT(0),
+ RPM_VREG_DEBUG_FULL_REQUEST = BIT(1),
+ RPM_VREG_DEBUG_DUPLICATE = BIT(2),
+};
+
+static int rpm_vreg_debug_mask;
+module_param_named(
+ debug_mask, rpm_vreg_debug_mask, int, S_IRUSR | S_IWUSR
+);
+
+#define vreg_err(req, fmt, ...) \
+ pr_err("%s: " fmt, req->rdesc.name, ##__VA_ARGS__)
+
+/* RPM regulator request types */
+enum rpm_regulator_type {
+ RPM_REGULATOR_TYPE_LDO,
+ RPM_REGULATOR_TYPE_SMPS,
+ RPM_REGULATOR_TYPE_VS,
+ RPM_REGULATOR_TYPE_NCP,
+ RPM_REGULATOR_TYPE_BOB,
+ RPM_REGULATOR_TYPE_MAX,
+};
+
+/* RPM resource parameters */
+enum rpm_regulator_param_index {
+ RPM_REGULATOR_PARAM_ENABLE,
+ RPM_REGULATOR_PARAM_VOLTAGE,
+ RPM_REGULATOR_PARAM_CURRENT,
+ RPM_REGULATOR_PARAM_MODE_LDO,
+ RPM_REGULATOR_PARAM_MODE_SMPS,
+ RPM_REGULATOR_PARAM_PIN_CTRL_ENABLE,
+ RPM_REGULATOR_PARAM_PIN_CTRL_MODE,
+ RPM_REGULATOR_PARAM_FREQUENCY,
+ RPM_REGULATOR_PARAM_HEAD_ROOM,
+ RPM_REGULATOR_PARAM_QUIET_MODE,
+ RPM_REGULATOR_PARAM_FREQ_REASON,
+ RPM_REGULATOR_PARAM_CORNER,
+ RPM_REGULATOR_PARAM_BYPASS,
+ RPM_REGULATOR_PARAM_FLOOR_CORNER,
+ RPM_REGULATOR_PARAM_LEVEL,
+ RPM_REGULATOR_PARAM_FLOOR_LEVEL,
+ RPM_REGULATOR_PARAM_MODE_BOB,
+ RPM_REGULATOR_PARAM_PIN_CTRL_VOLTAGE1,
+ RPM_REGULATOR_PARAM_PIN_CTRL_VOLTAGE2,
+ RPM_REGULATOR_PARAM_PIN_CTRL_VOLTAGE3,
+ RPM_REGULATOR_PARAM_MAX,
+};
+
+enum rpm_regulator_smps_mode {
+ RPM_REGULATOR_SMPS_MODE_AUTO = 0,
+ RPM_REGULATOR_SMPS_MODE_IPEAK = 1,
+ RPM_REGULATOR_SMPS_MODE_PWM = 2,
+};
+
+enum rpm_regulator_ldo_mode {
+ RPM_REGULATOR_LDO_MODE_IPEAK = 0,
+ RPM_REGULATOR_LDO_MODE_HPM = 1,
+};
+
+enum rpm_regulator_bob_mode {
+ RPM_REGULATOR_BOB_MODE_PASS = 0,
+ RPM_REGULATOR_BOB_MODE_PFM = 1,
+ RPM_REGULATOR_BOB_MODE_AUTO = 2,
+ RPM_REGULATOR_BOB_MODE_PWM = 3,
+};
+
+#define RPM_SET_CONFIG_ACTIVE BIT(0)
+#define RPM_SET_CONFIG_SLEEP BIT(1)
+#define RPM_SET_CONFIG_BOTH (RPM_SET_CONFIG_ACTIVE \
+ | RPM_SET_CONFIG_SLEEP)
+struct rpm_regulator_param {
+ char *name;
+ char *property_name;
+ u32 key;
+ u32 min;
+ u32 max;
+ u32 supported_regulator_types;
+};
+
+#define PARAM(_idx, _support_ldo, _support_smps, _support_vs, _support_ncp, \
+ _support_bob, _name, _min, _max, _property_name) \
+ [RPM_REGULATOR_PARAM_##_idx] = { \
+ .name = _name, \
+ .property_name = _property_name, \
+ .min = _min, \
+ .max = _max, \
+ .supported_regulator_types = \
+ _support_ldo << RPM_REGULATOR_TYPE_LDO | \
+ _support_smps << RPM_REGULATOR_TYPE_SMPS | \
+ _support_vs << RPM_REGULATOR_TYPE_VS | \
+ _support_ncp << RPM_REGULATOR_TYPE_NCP | \
+ _support_bob << RPM_REGULATOR_TYPE_BOB, \
+ }
+
+static struct rpm_regulator_param params[RPM_REGULATOR_PARAM_MAX] = {
+ /* ID LDO SMPS VS NCP BOB name min max property-name */
+ PARAM(ENABLE, 1, 1, 1, 1, 1, "swen", 0, 1, "qcom,init-enable"),
+ PARAM(VOLTAGE, 1, 1, 0, 1, 1, "uv", 0, 0x7FFFFFF, "qcom,init-voltage"),
+ PARAM(CURRENT, 1, 1, 0, 0, 0, "ma", 0, 0x1FFF, "qcom,init-current"),
+ PARAM(MODE_LDO, 1, 0, 0, 0, 0, "lsmd", 0, 1, "qcom,init-ldo-mode"),
+ PARAM(MODE_SMPS, 0, 1, 0, 0, 0, "ssmd", 0, 2, "qcom,init-smps-mode"),
+ PARAM(PIN_CTRL_ENABLE, 1, 1, 1, 0, 0, "pcen", 0, 0xF, "qcom,init-pin-ctrl-enable"),
+ PARAM(PIN_CTRL_MODE, 1, 1, 1, 0, 0, "pcmd", 0, 0x1F, "qcom,init-pin-ctrl-mode"),
+ PARAM(FREQUENCY, 0, 1, 0, 1, 0, "freq", 0, 31, "qcom,init-frequency"),
+ PARAM(HEAD_ROOM, 1, 0, 0, 1, 0, "hr", 0, 0x7FFFFFFF, "qcom,init-head-room"),
+ PARAM(QUIET_MODE, 0, 1, 0, 0, 0, "qm", 0, 2, "qcom,init-quiet-mode"),
+ PARAM(FREQ_REASON, 0, 1, 0, 1, 0, "resn", 0, 8, "qcom,init-freq-reason"),
+ PARAM(CORNER, 1, 1, 0, 0, 0, "corn", 0, 6, "qcom,init-voltage-corner"),
+ PARAM(BYPASS, 1, 0, 0, 0, 0, "bypa", 0, 1, "qcom,init-disallow-bypass"),
+ PARAM(FLOOR_CORNER, 1, 1, 0, 0, 0, "vfc", 0, 6, "qcom,init-voltage-floor-corner"),
+ PARAM(LEVEL, 1, 1, 0, 0, 0, "vlvl", 0, 0xFFFF, "qcom,init-voltage-level"),
+ PARAM(FLOOR_LEVEL, 1, 1, 0, 0, 0, "vfl", 0, 0xFFFF, "qcom,init-voltage-floor-level"),
+ PARAM(MODE_BOB, 0, 0, 0, 0, 1, "bobm", 0, 3, "qcom,init-bob-mode"),
+ PARAM(PIN_CTRL_VOLTAGE1, 0, 0, 0, 0, 1, "pcv1", 0, 0x7FFFFFF, "qcom,init-pin-ctrl-voltage1"),
+ PARAM(PIN_CTRL_VOLTAGE2, 0, 0, 0, 0, 1, "pcv2", 0, 0x7FFFFFF, "qcom,init-pin-ctrl-voltage2"),
+ PARAM(PIN_CTRL_VOLTAGE3, 0, 0, 0, 0, 1, "pcv3", 0, 0x7FFFFFF, "qcom,init-pin-ctrl-voltage3"),
+};
+
+struct rpm_regulator_mode_map {
+ int ldo_mode;
+ int smps_mode;
+};
+
+static struct rpm_regulator_mode_map mode_mapping[] = {
+ [RPM_REGULATOR_MODE_AUTO]
+ = {-1, RPM_REGULATOR_SMPS_MODE_AUTO},
+ [RPM_REGULATOR_MODE_IPEAK]
+ = {RPM_REGULATOR_LDO_MODE_IPEAK, RPM_REGULATOR_SMPS_MODE_IPEAK},
+ [RPM_REGULATOR_MODE_HPM]
+ = {RPM_REGULATOR_LDO_MODE_HPM, RPM_REGULATOR_SMPS_MODE_PWM},
+};
+
+/* Indices for use with pin control enable via enable/disable feature. */
+#define RPM_VREG_PIN_CTRL_STATE_DISABLE 0
+#define RPM_VREG_PIN_CTRL_STATE_ENABLE 1
+#define RPM_VREG_PIN_CTRL_STATE_COUNT 2
+
+struct rpm_vreg_request {
+ u32 param[RPM_REGULATOR_PARAM_MAX];
+ u32 valid;
+ u32 modified;
+};
+
+struct rpm_vreg {
+ struct rpm_vreg_request aggr_req_active;
+ struct rpm_vreg_request aggr_req_sleep;
+ struct list_head reg_list;
+ const char *resource_name;
+ u32 resource_id;
+ bool allow_atomic;
+ int regulator_type;
+ int hpm_min_load;
+ int enable_time;
+ spinlock_t slock;
+ struct mutex mlock;
+ unsigned long flags;
+ bool sleep_request_sent;
+ bool wait_for_ack_active;
+ bool wait_for_ack_sleep;
+ bool always_wait_for_ack;
+ bool apps_only;
+ struct msm_rpm_request *handle_active;
+ struct msm_rpm_request *handle_sleep;
+};
+
+struct rpm_regulator {
+ struct regulator_desc rdesc;
+ struct regulator_dev *rdev;
+ struct rpm_vreg *rpm_vreg;
+ struct list_head list;
+ bool set_active;
+ bool set_sleep;
+ bool always_send_voltage;
+ bool always_send_current;
+ bool use_pin_ctrl_for_enable;
+ struct rpm_vreg_request req;
+ int system_load;
+ int min_uV;
+ int max_uV;
+ u32 pin_ctrl_mask[RPM_VREG_PIN_CTRL_STATE_COUNT];
+ enum rpm_regulator_param_index voltage_index;
+ int voltage_offset;
+};
+
+/*
+ * This voltage in uV is returned by get_voltage functions when there is no way
+ * to determine the current voltage level. It is needed because the regulator
+ * framework treats a 0 uV voltage as an error.
+ */
+#define VOLTAGE_UNKNOWN 1
+
+/*
+ * Regulator requests sent in the active set take effect immediately. Requests
+ * sent in the sleep set take effect when the Apps processor transitions into
+ * RPM assisted power collapse. For any given regulator, if an active set
+ * request is present, but not a sleep set request, then the active set request
+ * is used at all times, even when the Apps processor is power collapsed.
+ *
+ * The rpm-regulator-smd takes advantage of this default usage of the active set
+ * request by only sending a sleep set request if it differs from the
+ * corresponding active set request.
+ */
+#define RPM_SET_ACTIVE MSM_RPM_CTX_ACTIVE_SET
+#define RPM_SET_SLEEP MSM_RPM_CTX_SLEEP_SET
+
+static u32 rpm_vreg_string_to_int(const u8 *str)
+{
+ int i, len;
+ u32 output = 0;
+
+ len = strnlen(str, sizeof(u32));
+ for (i = 0; i < len; i++)
+ output |= str[i] << (i * 8);
+
+ return output;
+}
+
+static inline void rpm_vreg_lock(struct rpm_vreg *rpm_vreg)
+{
+ if (rpm_vreg->allow_atomic)
+ spin_lock_irqsave(&rpm_vreg->slock, rpm_vreg->flags);
+ else
+ mutex_lock(&rpm_vreg->mlock);
+}
+
+static inline void rpm_vreg_unlock(struct rpm_vreg *rpm_vreg)
+{
+ if (rpm_vreg->allow_atomic)
+ spin_unlock_irqrestore(&rpm_vreg->slock, rpm_vreg->flags);
+ else
+ mutex_unlock(&rpm_vreg->mlock);
+}
+
+static inline bool rpm_vreg_active_or_sleep_enabled(struct rpm_vreg *rpm_vreg)
+{
+ return (rpm_vreg->aggr_req_active.param[RPM_REGULATOR_PARAM_ENABLE]
+ && (rpm_vreg->aggr_req_active.valid
+ & BIT(RPM_REGULATOR_PARAM_ENABLE)))
+ || ((rpm_vreg->aggr_req_sleep.param[RPM_REGULATOR_PARAM_ENABLE])
+ && (rpm_vreg->aggr_req_sleep.valid
+ & BIT(RPM_REGULATOR_PARAM_ENABLE)));
+}
+
+static inline bool rpm_vreg_shared_active_or_sleep_enabled_valid
+ (struct rpm_vreg *rpm_vreg)
+{
+ return !rpm_vreg->apps_only &&
+ ((rpm_vreg->aggr_req_active.valid
+ & BIT(RPM_REGULATOR_PARAM_ENABLE))
+ || (rpm_vreg->aggr_req_sleep.valid
+ & BIT(RPM_REGULATOR_PARAM_ENABLE)));
+}
+
+static const u32 power_level_params =
+ BIT(RPM_REGULATOR_PARAM_ENABLE) |
+ BIT(RPM_REGULATOR_PARAM_VOLTAGE) |
+ BIT(RPM_REGULATOR_PARAM_CURRENT) |
+ BIT(RPM_REGULATOR_PARAM_CORNER) |
+ BIT(RPM_REGULATOR_PARAM_BYPASS) |
+ BIT(RPM_REGULATOR_PARAM_FLOOR_CORNER) |
+ BIT(RPM_REGULATOR_PARAM_LEVEL) |
+ BIT(RPM_REGULATOR_PARAM_FLOOR_LEVEL);
+
+static bool rpm_vreg_ack_required(struct rpm_vreg *rpm_vreg, u32 set,
+ const u32 *prev_param, const u32 *param,
+ u32 prev_valid, u32 modified)
+{
+ u32 mask;
+ int i;
+
+ if (rpm_vreg->always_wait_for_ack
+ || (set == RPM_SET_ACTIVE && rpm_vreg->wait_for_ack_active)
+ || (set == RPM_SET_SLEEP && rpm_vreg->wait_for_ack_sleep))
+ return true;
+
+ for (i = 0; i < RPM_REGULATOR_PARAM_MAX; i++) {
+ mask = BIT(i);
+ if (modified & mask) {
+ if ((prev_valid & mask) && (power_level_params & mask)
+ && (param[i] <= prev_param[i]))
+ continue;
+ else
+ return true;
+ }
+ }
+
+ return false;
+}
+
+static void rpm_vreg_check_param_max(struct rpm_regulator *regulator, int index,
+ u32 new_max)
+{
+ struct rpm_vreg *rpm_vreg = regulator->rpm_vreg;
+
+ if (regulator->set_active
+ && (rpm_vreg->aggr_req_active.valid & BIT(index))
+ && rpm_vreg->aggr_req_active.param[index] > new_max)
+ rpm_vreg->wait_for_ack_active = true;
+
+ if (regulator->set_sleep
+ && (rpm_vreg->aggr_req_sleep.valid & BIT(index))
+ && rpm_vreg->aggr_req_sleep.param[index] > new_max)
+ rpm_vreg->wait_for_ack_sleep = true;
+}
+
+/*
+ * This is used when voting for LPM or HPM by subtracting or adding to the
+ * hpm_min_load of a regulator. It has units of uA.
+ */
+#define LOAD_THRESHOLD_STEP 1000
+
+static inline int rpm_vreg_hpm_min_uA(struct rpm_vreg *rpm_vreg)
+{
+ return rpm_vreg->hpm_min_load;
+}
+
+static inline int rpm_vreg_lpm_max_uA(struct rpm_vreg *rpm_vreg)
+{
+ return rpm_vreg->hpm_min_load - LOAD_THRESHOLD_STEP;
+}
+
+#define MICRO_TO_MILLI(uV) ((uV) / 1000)
+#define MILLI_TO_MICRO(uV) ((uV) * 1000)
+
+#define DEBUG_PRINT_BUFFER_SIZE 512
+#define REQ_SENT 0
+#define REQ_PREV 1
+#define REQ_CACHED 2
+#define REQ_TYPES 3
+
+static void rpm_regulator_req(struct rpm_regulator *regulator, int set,
+ bool sent)
+{
+ char buf[DEBUG_PRINT_BUFFER_SIZE];
+ size_t buflen = DEBUG_PRINT_BUFFER_SIZE;
+ struct rpm_vreg *rpm_vreg = regulator->rpm_vreg;
+ struct rpm_vreg_request *aggr;
+ bool first;
+ u32 mask[REQ_TYPES] = {0, 0, 0};
+ const char *req_names[REQ_TYPES] = {"sent", "prev", "cached"};
+ int pos = 0;
+ int i, j;
+
+ aggr = (set == RPM_SET_ACTIVE)
+ ? &rpm_vreg->aggr_req_active : &rpm_vreg->aggr_req_sleep;
+
+ if (rpm_vreg_debug_mask & RPM_VREG_DEBUG_DUPLICATE) {
+ mask[REQ_SENT] = aggr->modified;
+ mask[REQ_PREV] = aggr->valid & ~aggr->modified;
+ } else if (sent
+ && (rpm_vreg_debug_mask & RPM_VREG_DEBUG_FULL_REQUEST)) {
+ mask[REQ_SENT] = aggr->modified;
+ mask[REQ_PREV] = aggr->valid & ~aggr->modified;
+ } else if (sent && (rpm_vreg_debug_mask & RPM_VREG_DEBUG_REQUEST)) {
+ mask[REQ_SENT] = aggr->modified;
+ }
+
+ if (!(mask[REQ_SENT] | mask[REQ_PREV]))
+ return;
+
+ if (set == RPM_SET_SLEEP && !rpm_vreg->sleep_request_sent) {
+ mask[REQ_CACHED] = mask[REQ_SENT] | mask[REQ_PREV];
+ mask[REQ_SENT] = 0;
+ mask[REQ_PREV] = 0;
+ }
+
+ pos += scnprintf(buf + pos, buflen - pos, "%s%s: ",
+ KERN_INFO, __func__);
+
+ pos += scnprintf(buf + pos, buflen - pos, "%s %u (%s): s=%s",
+ rpm_vreg->resource_name, rpm_vreg->resource_id,
+ regulator->rdesc.name,
+ (set == RPM_SET_ACTIVE ? "act" : "slp"));
+
+ for (i = 0; i < REQ_TYPES; i++) {
+ if (mask[i])
+ pos += scnprintf(buf + pos, buflen - pos, "; %s: ",
+ req_names[i]);
+
+ first = true;
+ for (j = 0; j < RPM_REGULATOR_PARAM_MAX; j++) {
+ if (mask[i] & BIT(j)) {
+ pos += scnprintf(buf + pos, buflen - pos,
+ "%s%s=%u", (first ? "" : ", "),
+ params[j].name, aggr->param[j]);
+ first = false;
+ }
+ }
+ }
+
+ pos += scnprintf(buf + pos, buflen - pos, "\n");
+ printk(buf);
+}
+
+#define RPM_VREG_SET_PARAM(_regulator, _param, _val) \
+{ \
+ (_regulator)->req.param[RPM_REGULATOR_PARAM_##_param] = _val; \
+ (_regulator)->req.modified |= BIT(RPM_REGULATOR_PARAM_##_param); \
+} \
+
+static int rpm_vreg_add_kvp_to_request(struct rpm_vreg *rpm_vreg,
+ const u32 *param, int idx, u32 set)
+{
+ struct msm_rpm_request *handle;
+
+ handle = (set == RPM_SET_ACTIVE ? rpm_vreg->handle_active
+ : rpm_vreg->handle_sleep);
+
+ if (rpm_vreg->allow_atomic)
+ return msm_rpm_add_kvp_data_noirq(handle, params[idx].key,
+ (u8 *)¶m[idx], 4);
+ else
+ return msm_rpm_add_kvp_data(handle, params[idx].key,
+ (u8 *)¶m[idx], 4);
+}
+
+static void rpm_vreg_check_modified_requests(const u32 *prev_param,
+ const u32 *param, u32 prev_valid, u32 *modified)
+{
+ u32 value_changed = 0;
+ int i;
+
+ for (i = 0; i < RPM_REGULATOR_PARAM_MAX; i++) {
+ if (param[i] != prev_param[i])
+ value_changed |= BIT(i);
+ }
+
+ /*
+ * Only keep bits that are for changed parameters or previously
+ * invalid parameters.
+ */
+ *modified &= value_changed | ~prev_valid;
+}
+
+static int rpm_vreg_add_modified_requests(struct rpm_regulator *regulator,
+ u32 set, const u32 *param, u32 modified)
+{
+ struct rpm_vreg *rpm_vreg = regulator->rpm_vreg;
+ int rc = 0;
+ int i;
+
+ for (i = 0; i < RPM_REGULATOR_PARAM_MAX; i++) {
+ /* Only send requests for modified parameters. */
+ if (modified & BIT(i)) {
+ rc = rpm_vreg_add_kvp_to_request(rpm_vreg, param, i,
+ set);
+ if (rc) {
+ vreg_err(regulator,
+ "add KVP failed: %s %u; %s, rc=%d\n",
+ rpm_vreg->resource_name,
+ rpm_vreg->resource_id, params[i].name,
+ rc);
+ return rc;
+ }
+ }
+ }
+
+ return rc;
+}
+
+static int rpm_vreg_send_request(struct rpm_regulator *regulator, u32 set,
+ bool wait_for_ack)
+{
+ struct rpm_vreg *rpm_vreg = regulator->rpm_vreg;
+ struct msm_rpm_request *handle
+ = (set == RPM_SET_ACTIVE ? rpm_vreg->handle_active
+ : rpm_vreg->handle_sleep);
+ int rc = 0;
+ void *temp;
+
+ if (unlikely(rpm_vreg->allow_atomic)) {
+ rc = msm_rpm_wait_for_ack_noirq(msm_rpm_send_request_noirq(
+ handle));
+ } else if (wait_for_ack) {
+ rc = msm_rpm_wait_for_ack(msm_rpm_send_request(handle));
+ } else {
+ temp = msm_rpm_send_request_noack(handle);
+ if (IS_ERR(temp))
+ rc = PTR_ERR(temp);
+ }
+
+ if (rc)
+ vreg_err(regulator,
+ "msm rpm send failed: %s %u; set=%s, rc=%d\n",
+ rpm_vreg->resource_name,
+ rpm_vreg->resource_id,
+ (set == RPM_SET_ACTIVE ? "act" : "slp"), rc);
+
+ return rc;
+}
+
+#define RPM_VREG_AGGR_MIN(_idx, _param_aggr, _param_reg) \
+{ \
+ _param_aggr[RPM_REGULATOR_PARAM_##_idx] \
+ = min(_param_aggr[RPM_REGULATOR_PARAM_##_idx], \
+ _param_reg[RPM_REGULATOR_PARAM_##_idx]); \
+}
+
+#define RPM_VREG_AGGR_MAX(_idx, _param_aggr, _param_reg) \
+{ \
+ _param_aggr[RPM_REGULATOR_PARAM_##_idx] \
+ = max(_param_aggr[RPM_REGULATOR_PARAM_##_idx], \
+ _param_reg[RPM_REGULATOR_PARAM_##_idx]); \
+}
+
+#define RPM_VREG_AGGR_SUM(_idx, _param_aggr, _param_reg) \
+{ \
+ _param_aggr[RPM_REGULATOR_PARAM_##_idx] \
+ += _param_reg[RPM_REGULATOR_PARAM_##_idx]; \
+}
+
+#define RPM_VREG_AGGR_OR(_idx, _param_aggr, _param_reg) \
+{ \
+ _param_aggr[RPM_REGULATOR_PARAM_##_idx] \
+ |= _param_reg[RPM_REGULATOR_PARAM_##_idx]; \
+}
+
+/*
+ * Aggregation is performed on each parameter based on the way that the RPM
+ * aggregates that type internally between RPM masters.
+ */
+static void rpm_vreg_aggregate_params(u32 *param_aggr, const u32 *param_reg)
+{
+ RPM_VREG_AGGR_MAX(ENABLE, param_aggr, param_reg);
+ RPM_VREG_AGGR_MAX(VOLTAGE, param_aggr, param_reg);
+ RPM_VREG_AGGR_SUM(CURRENT, param_aggr, param_reg);
+ RPM_VREG_AGGR_MAX(MODE_LDO, param_aggr, param_reg);
+ RPM_VREG_AGGR_MAX(MODE_SMPS, param_aggr, param_reg);
+ RPM_VREG_AGGR_OR(PIN_CTRL_ENABLE, param_aggr, param_reg);
+ RPM_VREG_AGGR_OR(PIN_CTRL_MODE, param_aggr, param_reg);
+ RPM_VREG_AGGR_MIN(FREQUENCY, param_aggr, param_reg);
+ RPM_VREG_AGGR_MAX(HEAD_ROOM, param_aggr, param_reg);
+ RPM_VREG_AGGR_MAX(QUIET_MODE, param_aggr, param_reg);
+ RPM_VREG_AGGR_MAX(FREQ_REASON, param_aggr, param_reg);
+ RPM_VREG_AGGR_MAX(CORNER, param_aggr, param_reg);
+ RPM_VREG_AGGR_MAX(BYPASS, param_aggr, param_reg);
+ RPM_VREG_AGGR_MAX(FLOOR_CORNER, param_aggr, param_reg);
+ RPM_VREG_AGGR_MAX(LEVEL, param_aggr, param_reg);
+ RPM_VREG_AGGR_MAX(FLOOR_LEVEL, param_aggr, param_reg);
+ RPM_VREG_AGGR_MAX(MODE_BOB, param_aggr, param_reg);
+ RPM_VREG_AGGR_MAX(PIN_CTRL_VOLTAGE1, param_aggr, param_reg);
+ RPM_VREG_AGGR_MAX(PIN_CTRL_VOLTAGE2, param_aggr, param_reg);
+ RPM_VREG_AGGR_MAX(PIN_CTRL_VOLTAGE3, param_aggr, param_reg);
+}
+
+static int rpm_vreg_aggregate_requests(struct rpm_regulator *regulator)
+{
+ struct rpm_vreg *rpm_vreg = regulator->rpm_vreg;
+ u32 param_active[RPM_REGULATOR_PARAM_MAX];
+ u32 param_sleep[RPM_REGULATOR_PARAM_MAX];
+ u32 modified_active, modified_sleep;
+ struct rpm_regulator *reg;
+ bool sleep_set_differs = false;
+ bool send_active = false;
+ bool send_sleep = false;
+ bool wait_for_ack;
+ int rc = 0;
+ int i;
+
+ memset(param_active, 0, sizeof(param_active));
+ memset(param_sleep, 0, sizeof(param_sleep));
+ modified_active = rpm_vreg->aggr_req_active.modified;
+ modified_sleep = rpm_vreg->aggr_req_sleep.modified;
+
+ /*
+ * Aggregate all of the requests for this regulator in both active
+ * and sleep sets.
+ */
+ list_for_each_entry(reg, &rpm_vreg->reg_list, list) {
+ if (reg->set_active) {
+ rpm_vreg_aggregate_params(param_active, reg->req.param);
+ modified_active |= reg->req.modified;
+ }
+ if (reg->set_sleep) {
+ rpm_vreg_aggregate_params(param_sleep, reg->req.param);
+ modified_sleep |= reg->req.modified;
+ }
+ }
+
+ /*
+ * Check if the aggregated sleep set parameter values differ from the
+ * aggregated active set parameter values.
+ */
+ if (!rpm_vreg->sleep_request_sent) {
+ for (i = 0; i < RPM_REGULATOR_PARAM_MAX; i++) {
+ if ((param_active[i] != param_sleep[i])
+ && (modified_sleep & BIT(i))) {
+ sleep_set_differs = true;
+ break;
+ }
+ }
+ }
+
+ /* Add KVPs to the active set RPM request if they have new values. */
+ rpm_vreg_check_modified_requests(rpm_vreg->aggr_req_active.param,
+ param_active, rpm_vreg->aggr_req_active.valid,
+ &modified_active);
+ rc = rpm_vreg_add_modified_requests(regulator, RPM_SET_ACTIVE,
+ param_active, modified_active);
+ if (rc)
+ return rc;
+ send_active = modified_active;
+
+ /*
+ * Sleep set configurations are only sent if they differ from the
+ * active set values. This is because the active set values will take
+ * effect during rpm assisted power collapse in the absence of sleep set
+ * values.
+ *
+ * However, once a sleep set request is sent for a given regulator,
+ * additional sleep set requests must be sent in the future even if they
+ * match the corresponding active set requests.
+ */
+ if (rpm_vreg->sleep_request_sent || sleep_set_differs) {
+ /* Add KVPs to the sleep set RPM request if they are new. */
+ rpm_vreg_check_modified_requests(rpm_vreg->aggr_req_sleep.param,
+ param_sleep, rpm_vreg->aggr_req_sleep.valid,
+ &modified_sleep);
+ rc = rpm_vreg_add_modified_requests(regulator, RPM_SET_SLEEP,
+ param_sleep, modified_sleep);
+ if (rc)
+ return rc;
+ send_sleep = modified_sleep;
+ }
+
+ /* Send active set request to the RPM if it contains new KVPs. */
+ if (send_active) {
+ wait_for_ack = rpm_vreg_ack_required(rpm_vreg, RPM_SET_ACTIVE,
+ rpm_vreg->aggr_req_active.param,
+ param_active,
+ rpm_vreg->aggr_req_active.valid,
+ modified_active);
+ rc = rpm_vreg_send_request(regulator, RPM_SET_ACTIVE,
+ wait_for_ack);
+ if (rc)
+ return rc;
+ rpm_vreg->aggr_req_active.valid |= modified_active;
+ rpm_vreg->wait_for_ack_active = false;
+ }
+ /* Store the results of the aggregation. */
+ rpm_vreg->aggr_req_active.modified = modified_active;
+ memcpy(rpm_vreg->aggr_req_active.param, param_active,
+ sizeof(param_active));
+
+ /* Handle debug printing of the active set request. */
+ rpm_regulator_req(regulator, RPM_SET_ACTIVE, send_active);
+ if (send_active)
+ rpm_vreg->aggr_req_active.modified = 0;
+
+ /* Send sleep set request to the RPM if it contains new KVPs. */
+ if (send_sleep) {
+ wait_for_ack = rpm_vreg_ack_required(rpm_vreg, RPM_SET_SLEEP,
+ rpm_vreg->aggr_req_sleep.param,
+ param_sleep,
+ rpm_vreg->aggr_req_sleep.valid,
+ modified_sleep);
+ rc = rpm_vreg_send_request(regulator, RPM_SET_SLEEP,
+ wait_for_ack);
+ if (rc)
+ return rc;
+ else
+ rpm_vreg->sleep_request_sent = true;
+ rpm_vreg->aggr_req_sleep.valid |= modified_sleep;
+ rpm_vreg->wait_for_ack_sleep = false;
+ }
+ /* Store the results of the aggregation. */
+ rpm_vreg->aggr_req_sleep.modified = modified_sleep;
+ memcpy(rpm_vreg->aggr_req_sleep.param, param_sleep,
+ sizeof(param_sleep));
+
+ /* Handle debug printing of the sleep set request. */
+ rpm_regulator_req(regulator, RPM_SET_SLEEP, send_sleep);
+ if (send_sleep)
+ rpm_vreg->aggr_req_sleep.modified = 0;
+
+ /*
+ * Loop over all requests for this regulator to update the valid and
+ * modified values for use in future aggregation.
+ */
+ list_for_each_entry(reg, &rpm_vreg->reg_list, list) {
+ reg->req.valid |= reg->req.modified;
+ reg->req.modified = 0;
+ }
+
+ return rc;
+}
+
+static int rpm_vreg_is_enabled(struct regulator_dev *rdev)
+{
+ struct rpm_regulator *reg = rdev_get_drvdata(rdev);
+
+ if (likely(!reg->use_pin_ctrl_for_enable))
+ return reg->req.param[RPM_REGULATOR_PARAM_ENABLE];
+ else
+ return reg->req.param[RPM_REGULATOR_PARAM_PIN_CTRL_ENABLE]
+ == reg->pin_ctrl_mask[RPM_VREG_PIN_CTRL_STATE_ENABLE];
+}
+
+static int rpm_vreg_enable(struct regulator_dev *rdev)
+{
+ struct rpm_regulator *reg = rdev_get_drvdata(rdev);
+ int rc;
+ u32 prev_enable;
+
+ rpm_vreg_lock(reg->rpm_vreg);
+
+ if (likely(!reg->use_pin_ctrl_for_enable)) {
+ /* Enable using swen KVP. */
+ prev_enable = reg->req.param[RPM_REGULATOR_PARAM_ENABLE];
+ RPM_VREG_SET_PARAM(reg, ENABLE, 1);
+ rc = rpm_vreg_aggregate_requests(reg);
+ if (rc) {
+ vreg_err(reg, "enable failed, rc=%d", rc);
+ RPM_VREG_SET_PARAM(reg, ENABLE, prev_enable);
+ }
+ } else {
+ /* Enable using pcen KVP. */
+ prev_enable
+ = reg->req.param[RPM_REGULATOR_PARAM_PIN_CTRL_ENABLE];
+ RPM_VREG_SET_PARAM(reg, PIN_CTRL_ENABLE,
+ reg->pin_ctrl_mask[RPM_VREG_PIN_CTRL_STATE_ENABLE]);
+ rc = rpm_vreg_aggregate_requests(reg);
+ if (rc) {
+ vreg_err(reg, "enable failed, rc=%d", rc);
+ RPM_VREG_SET_PARAM(reg, PIN_CTRL_ENABLE, prev_enable);
+ }
+ }
+
+ rpm_vreg_unlock(reg->rpm_vreg);
+
+ return rc;
+}
+
+static int rpm_vreg_disable(struct regulator_dev *rdev)
+{
+ struct rpm_regulator *reg = rdev_get_drvdata(rdev);
+ int rc;
+ u32 prev_enable;
+
+ rpm_vreg_lock(reg->rpm_vreg);
+
+ if (likely(!reg->use_pin_ctrl_for_enable)) {
+ /* Disable using swen KVP. */
+ prev_enable = reg->req.param[RPM_REGULATOR_PARAM_ENABLE];
+ RPM_VREG_SET_PARAM(reg, ENABLE, 0);
+ rc = rpm_vreg_aggregate_requests(reg);
+ if (rc) {
+ vreg_err(reg, "disable failed, rc=%d", rc);
+ RPM_VREG_SET_PARAM(reg, ENABLE, prev_enable);
+ }
+ } else {
+ /* Disable using pcen KVP. */
+ prev_enable
+ = reg->req.param[RPM_REGULATOR_PARAM_PIN_CTRL_ENABLE];
+ RPM_VREG_SET_PARAM(reg, PIN_CTRL_ENABLE,
+ reg->pin_ctrl_mask[RPM_VREG_PIN_CTRL_STATE_DISABLE]);
+ rc = rpm_vreg_aggregate_requests(reg);
+ if (rc) {
+ vreg_err(reg, "disable failed, rc=%d", rc);
+ RPM_VREG_SET_PARAM(reg, PIN_CTRL_ENABLE, prev_enable);
+ }
+ }
+
+ rpm_vreg_unlock(reg->rpm_vreg);
+
+ return rc;
+}
+
+#define RPM_VREG_SET_VOLTAGE(_regulator, _val) \
+{ \
+ (_regulator)->req.param[(_regulator)->voltage_index] = _val; \
+ (_regulator)->req.modified |= BIT((_regulator)->voltage_index); \
+} \
+
+static int rpm_vreg_set_voltage(struct regulator_dev *rdev, int min_uV,
+ int max_uV, unsigned *selector)
+{
+ struct rpm_regulator *reg = rdev_get_drvdata(rdev);
+ int rc = 0;
+ int voltage;
+ u32 prev_voltage;
+
+ voltage = min_uV - reg->voltage_offset;
+
+ if (voltage < params[reg->voltage_index].min
+ || voltage > params[reg->voltage_index].max) {
+ vreg_err(reg, "voltage=%d for key=%s is not within allowed range: [%u, %u]\n",
+ voltage, params[reg->voltage_index].name,
+ params[reg->voltage_index].min,
+ params[reg->voltage_index].max);
+ return -EINVAL;
+ }
+
+ rpm_vreg_lock(reg->rpm_vreg);
+
+ prev_voltage = reg->req.param[reg->voltage_index];
+ RPM_VREG_SET_VOLTAGE(reg, voltage);
+
+ rpm_vreg_check_param_max(reg, reg->voltage_index,
+ max_uV - reg->voltage_offset);
+
+ /*
+ * Only send a new voltage if the regulator is currently enabled or
+ * if the regulator has been configured to always send voltage updates.
+ */
+ if (reg->always_send_voltage
+ || rpm_vreg_active_or_sleep_enabled(reg->rpm_vreg)
+ || rpm_vreg_shared_active_or_sleep_enabled_valid(reg->rpm_vreg))
+ rc = rpm_vreg_aggregate_requests(reg);
+
+ if (rc) {
+ vreg_err(reg, "set voltage for key=%s failed, rc=%d",
+ params[reg->voltage_index].name, rc);
+ RPM_VREG_SET_VOLTAGE(reg, prev_voltage);
+ }
+
+ rpm_vreg_unlock(reg->rpm_vreg);
+
+ return rc;
+}
+
+static int rpm_vreg_get_voltage(struct regulator_dev *rdev)
+{
+ struct rpm_regulator *reg = rdev_get_drvdata(rdev);
+ int uV;
+
+ uV = reg->req.param[reg->voltage_index] + reg->voltage_offset;
+ if (uV == 0)
+ uV = VOLTAGE_UNKNOWN;
+
+ return uV;
+}
+
+static int rpm_vreg_set_mode(struct regulator_dev *rdev, unsigned int mode)
+{
+ struct rpm_regulator *reg = rdev_get_drvdata(rdev);
+ int rc = 0;
+ u32 prev_current;
+ int prev_uA;
+
+ rpm_vreg_lock(reg->rpm_vreg);
+
+ prev_current = reg->req.param[RPM_REGULATOR_PARAM_CURRENT];
+ prev_uA = MILLI_TO_MICRO(prev_current);
+
+ if (mode == REGULATOR_MODE_NORMAL) {
+ /* Make sure that request current is in HPM range. */
+ if (prev_uA < rpm_vreg_hpm_min_uA(reg->rpm_vreg))
+ RPM_VREG_SET_PARAM(reg, CURRENT,
+ MICRO_TO_MILLI(rpm_vreg_hpm_min_uA(reg->rpm_vreg)));
+ } else if (REGULATOR_MODE_IDLE) {
+ /* Make sure that request current is in LPM range. */
+ if (prev_uA > rpm_vreg_lpm_max_uA(reg->rpm_vreg))
+ RPM_VREG_SET_PARAM(reg, CURRENT,
+ MICRO_TO_MILLI(rpm_vreg_lpm_max_uA(reg->rpm_vreg)));
+ } else {
+ vreg_err(reg, "invalid mode: %u\n", mode);
+ rpm_vreg_unlock(reg->rpm_vreg);
+ return -EINVAL;
+ }
+
+ /*
+ * Only send a new load current value if the regulator is currently
+ * enabled or if the regulator has been configured to always send
+ * current updates.
+ */
+ if (reg->always_send_current
+ || rpm_vreg_active_or_sleep_enabled(reg->rpm_vreg)
+ || rpm_vreg_shared_active_or_sleep_enabled_valid(reg->rpm_vreg))
+ rc = rpm_vreg_aggregate_requests(reg);
+
+ if (rc) {
+ vreg_err(reg, "set mode failed, rc=%d\n", rc);
+ RPM_VREG_SET_PARAM(reg, CURRENT, prev_current);
+ }
+
+ rpm_vreg_unlock(reg->rpm_vreg);
+
+ return rc;
+}
+
+static unsigned int rpm_vreg_get_mode(struct regulator_dev *rdev)
+{
+ struct rpm_regulator *reg = rdev_get_drvdata(rdev);
+
+ return (reg->req.param[RPM_REGULATOR_PARAM_CURRENT]
+ >= MICRO_TO_MILLI(reg->rpm_vreg->hpm_min_load))
+ ? REGULATOR_MODE_NORMAL : REGULATOR_MODE_IDLE;
+}
+
+static unsigned int rpm_vreg_get_optimum_mode(struct regulator_dev *rdev,
+ int input_uV, int output_uV, int load_uA)
+{
+ struct rpm_regulator *reg = rdev_get_drvdata(rdev);
+ u32 load_mA;
+
+ load_uA += reg->system_load;
+
+ load_mA = MICRO_TO_MILLI(load_uA);
+ if (load_mA > params[RPM_REGULATOR_PARAM_CURRENT].max)
+ load_mA = params[RPM_REGULATOR_PARAM_CURRENT].max;
+
+ rpm_vreg_lock(reg->rpm_vreg);
+ RPM_VREG_SET_PARAM(reg, CURRENT, load_mA);
+ rpm_vreg_unlock(reg->rpm_vreg);
+
+ return (load_uA >= reg->rpm_vreg->hpm_min_load)
+ ? REGULATOR_MODE_NORMAL : REGULATOR_MODE_IDLE;
+}
+
+static int rpm_vreg_set_bob_mode(struct regulator_dev *rdev, unsigned int mode)
+{
+ struct rpm_regulator *reg = rdev_get_drvdata(rdev);
+ int rc;
+ u32 prev_mode;
+
+ rpm_vreg_lock(reg->rpm_vreg);
+
+ prev_mode = reg->req.param[RPM_REGULATOR_PARAM_MODE_BOB];
+
+ switch (mode) {
+ case REGULATOR_MODE_FAST:
+ RPM_VREG_SET_PARAM(reg, MODE_BOB, RPM_REGULATOR_BOB_MODE_PWM);
+ break;
+ case REGULATOR_MODE_NORMAL:
+ RPM_VREG_SET_PARAM(reg, MODE_BOB, RPM_REGULATOR_BOB_MODE_AUTO);
+ break;
+ case REGULATOR_MODE_IDLE:
+ RPM_VREG_SET_PARAM(reg, MODE_BOB, RPM_REGULATOR_BOB_MODE_PFM);
+ break;
+ case REGULATOR_MODE_STANDBY:
+ RPM_VREG_SET_PARAM(reg, MODE_BOB, RPM_REGULATOR_BOB_MODE_PASS);
+ break;
+ default:
+ vreg_err(reg, "invalid mode: %u\n", mode);
+ rpm_vreg_unlock(reg->rpm_vreg);
+ return -EINVAL;
+ }
+
+ rc = rpm_vreg_aggregate_requests(reg);
+ if (rc) {
+ vreg_err(reg, "set BoB mode failed, rc=%d\n", rc);
+ RPM_VREG_SET_PARAM(reg, MODE_BOB, prev_mode);
+ }
+
+ rpm_vreg_unlock(reg->rpm_vreg);
+
+ return rc;
+}
+
+static unsigned int rpm_vreg_get_bob_mode(struct regulator_dev *rdev)
+{
+ struct rpm_regulator *reg = rdev_get_drvdata(rdev);
+ unsigned int mode;
+
+ switch (reg->req.param[RPM_REGULATOR_PARAM_MODE_BOB]) {
+ case RPM_REGULATOR_BOB_MODE_PWM:
+ mode = REGULATOR_MODE_FAST;
+ break;
+ case RPM_REGULATOR_BOB_MODE_AUTO:
+ mode = REGULATOR_MODE_NORMAL;
+ break;
+ case RPM_REGULATOR_BOB_MODE_PFM:
+ mode = REGULATOR_MODE_IDLE;
+ break;
+ case RPM_REGULATOR_BOB_MODE_PASS:
+ mode = REGULATOR_MODE_STANDBY;
+ break;
+ default:
+ vreg_err(reg, "BoB mode unknown\n");
+ mode = REGULATOR_MODE_NORMAL;
+ }
+
+ return mode;
+}
+
+static int rpm_vreg_enable_time(struct regulator_dev *rdev)
+{
+ struct rpm_regulator *reg = rdev_get_drvdata(rdev);
+
+ return reg->rpm_vreg->enable_time;
+}
+
+static int rpm_vreg_send_defaults(struct rpm_regulator *reg)
+{
+ int rc;
+
+ rpm_vreg_lock(reg->rpm_vreg);
+ rc = rpm_vreg_aggregate_requests(reg);
+ if (rc)
+ vreg_err(reg, "RPM request failed, rc=%d", rc);
+ rpm_vreg_unlock(reg->rpm_vreg);
+
+ return rc;
+}
+
+static int rpm_vreg_configure_pin_control_enable(struct rpm_regulator *reg,
+ struct device_node *node)
+{
+ struct rpm_regulator_param *pcen_param =
+ ¶ms[RPM_REGULATOR_PARAM_PIN_CTRL_ENABLE];
+ int rc, i;
+
+ if (!of_find_property(node, "qcom,enable-with-pin-ctrl", NULL))
+ return 0;
+
+ if (pcen_param->supported_regulator_types
+ & BIT(reg->rpm_vreg->regulator_type)) {
+ rc = of_property_read_u32_array(node,
+ "qcom,enable-with-pin-ctrl", reg->pin_ctrl_mask,
+ RPM_VREG_PIN_CTRL_STATE_COUNT);
+ if (rc) {
+ vreg_err(reg, "could not read qcom,enable-with-pin-ctrl, rc=%d\n",
+ rc);
+ return rc;
+ }
+
+ /* Verify that the mask values are valid. */
+ for (i = 0; i < RPM_VREG_PIN_CTRL_STATE_COUNT; i++) {
+ if (reg->pin_ctrl_mask[i] < pcen_param->min
+ || reg->pin_ctrl_mask[i] > pcen_param->max) {
+ vreg_err(reg, "device tree property: qcom,enable-with-pin-ctrl[%d]=%u is outside allowed range [%u, %u]\n",
+ i, reg->pin_ctrl_mask[i],
+ pcen_param->min, pcen_param->max);
+ return -EINVAL;
+ }
+ }
+
+ reg->use_pin_ctrl_for_enable = true;
+ } else {
+ pr_warn("%s: regulator type=%d does not support device tree property: qcom,enable-with-pin-ctrl\n",
+ reg->rdesc.name, reg->rpm_vreg->regulator_type);
+ }
+
+ return 0;
+}
+
+/**
+ * rpm_regulator_get() - lookup and obtain a handle to an RPM regulator
+ * @dev: device for regulator consumer
+ * @supply: supply name
+ *
+ * Returns a struct rpm_regulator corresponding to the regulator producer,
+ * or ERR_PTR() containing errno.
+ *
+ * This function may only be called from nonatomic context.
+ */
+struct rpm_regulator *rpm_regulator_get(struct device *dev, const char *supply)
+{
+ struct rpm_regulator *framework_reg;
+ struct rpm_regulator *priv_reg = NULL;
+ struct regulator *regulator;
+ struct rpm_vreg *rpm_vreg;
+
+ regulator = regulator_get(dev, supply);
+ if (IS_ERR(regulator)) {
+ pr_err("could not find regulator for: dev=%s, supply=%s, rc=%ld\n",
+ (dev ? dev_name(dev) : ""), (supply ? supply : ""),
+ PTR_ERR(regulator));
+ return ERR_CAST(regulator);
+ }
+
+ framework_reg = regulator_get_drvdata(regulator);
+ if (framework_reg == NULL) {
+ pr_err("regulator structure not found.\n");
+ regulator_put(regulator);
+ return ERR_PTR(-ENODEV);
+ }
+ regulator_put(regulator);
+
+ rpm_vreg = framework_reg->rpm_vreg;
+
+ priv_reg = kzalloc(sizeof(struct rpm_regulator), GFP_KERNEL);
+ if (priv_reg == NULL) {
+ vreg_err(framework_reg,
+ "could not allocate memory for regulator\n");
+ return ERR_PTR(-ENOMEM);
+ }
+
+ /*
+ * Allocate a regulator_dev struct so that framework callback functions
+ * can be called from the private API functions.
+ */
+ priv_reg->rdev = kzalloc(sizeof(struct regulator_dev), GFP_KERNEL);
+ if (priv_reg->rdev == NULL) {
+ vreg_err(framework_reg,
+ "could not allocate memory for regulator_dev\n");
+ kfree(priv_reg);
+ return ERR_PTR(-ENOMEM);
+ }
+ priv_reg->rdev->reg_data = priv_reg;
+ priv_reg->rpm_vreg = rpm_vreg;
+ priv_reg->rdesc.name = framework_reg->rdesc.name;
+ priv_reg->rdesc.ops = framework_reg->rdesc.ops;
+ priv_reg->set_active = framework_reg->set_active;
+ priv_reg->set_sleep = framework_reg->set_sleep;
+ priv_reg->min_uV = framework_reg->min_uV;
+ priv_reg->max_uV = framework_reg->max_uV;
+ priv_reg->system_load = framework_reg->system_load;
+
+ might_sleep_if(!rpm_vreg->allow_atomic);
+ rpm_vreg_lock(rpm_vreg);
+ list_add(&priv_reg->list, &rpm_vreg->reg_list);
+ rpm_vreg_unlock(rpm_vreg);
+
+ return priv_reg;
+}
+EXPORT_SYMBOL(rpm_regulator_get);
+
+static int rpm_regulator_check_input(struct rpm_regulator *regulator)
+{
+ if (IS_ERR_OR_NULL(regulator) || regulator->rpm_vreg == NULL) {
+ pr_err("invalid rpm_regulator pointer\n");
+ return -EINVAL;
+ }
+
+ might_sleep_if(!regulator->rpm_vreg->allow_atomic);
+
+ return 0;
+}
+
+/**
+ * rpm_regulator_put() - free the RPM regulator handle
+ * @regulator: RPM regulator handle
+ *
+ * Parameter reaggregation does not take place when rpm_regulator_put is called.
+ * Therefore, regulator enable state and voltage must be configured
+ * appropriately before calling rpm_regulator_put.
+ *
+ * This function may be called from either atomic or nonatomic context. If this
+ * function is called from atomic context, then the regulator being operated on
+ * must be configured via device tree with qcom,allow-atomic == 1.
+ */
+void rpm_regulator_put(struct rpm_regulator *regulator)
+{
+ struct rpm_vreg *rpm_vreg;
+ int rc = rpm_regulator_check_input(regulator);
+
+ if (rc)
+ return;
+
+ rpm_vreg = regulator->rpm_vreg;
+
+ might_sleep_if(!rpm_vreg->allow_atomic);
+ rpm_vreg_lock(rpm_vreg);
+ list_del(®ulator->list);
+ rpm_vreg_unlock(rpm_vreg);
+
+ kfree(regulator->rdev);
+ kfree(regulator);
+}
+EXPORT_SYMBOL(rpm_regulator_put);
+
+/**
+ * rpm_regulator_enable() - enable regulator output
+ * @regulator: RPM regulator handle
+ *
+ * Returns 0 on success or errno on failure.
+ *
+ * This function may be called from either atomic or nonatomic context. If this
+ * function is called from atomic context, then the regulator being operated on
+ * must be configured via device tree with qcom,allow-atomic == 1.
+ */
+int rpm_regulator_enable(struct rpm_regulator *regulator)
+{
+ int rc = rpm_regulator_check_input(regulator);
+
+ if (rc)
+ return rc;
+
+ return rpm_vreg_enable(regulator->rdev);
+}
+EXPORT_SYMBOL(rpm_regulator_enable);
+
+/**
+ * rpm_regulator_disable() - disable regulator output
+ * @regulator: RPM regulator handle
+ *
+ * Returns 0 on success or errno on failure.
+ *
+ * The enable state of the regulator is determined by aggregating the requests
+ * of all consumers. Therefore, it is possible that the regulator will remain
+ * enabled even after rpm_regulator_disable is called.
+ *
+ * This function may be called from either atomic or nonatomic context. If this
+ * function is called from atomic context, then the regulator being operated on
+ * must be configured via device tree with qcom,allow-atomic == 1.
+ */
+int rpm_regulator_disable(struct rpm_regulator *regulator)
+{
+ int rc = rpm_regulator_check_input(regulator);
+
+ if (rc)
+ return rc;
+
+ return rpm_vreg_disable(regulator->rdev);
+}
+EXPORT_SYMBOL(rpm_regulator_disable);
+
+/**
+ * rpm_regulator_set_voltage() - set regulator output voltage
+ * @regulator: RPM regulator handle
+ * @min_uV: minimum required voltage in uV
+ * @max_uV: maximum acceptable voltage in uV
+ *
+ * Sets a voltage regulator to the desired output voltage. This can be set
+ * while the regulator is disabled or enabled. If the regulator is enabled then
+ * the voltage will change to the new value immediately; otherwise, if the
+ * regulator is disabled, then the regulator will output at the new voltage when
+ * enabled.
+ *
+ * The min_uV to max_uV voltage range requested must intersect with the
+ * voltage constraint range configured for the regulator.
+ *
+ * Returns 0 on success or errno on failure.
+ *
+ * The final voltage value that is sent to the RPM is aggregated based upon the
+ * values requested by all consumers of the regulator. This corresponds to the
+ * maximum min_uV value.
+ *
+ * This function may be called from either atomic or nonatomic context. If this
+ * function is called from atomic context, then the regulator being operated on
+ * must be configured via device tree with qcom,allow-atomic == 1.
+ */
+int rpm_regulator_set_voltage(struct rpm_regulator *regulator, int min_uV,
+ int max_uV)
+{
+ int rc = rpm_regulator_check_input(regulator);
+ int uV = min_uV;
+
+ if (rc)
+ return rc;
+
+ if (regulator->rpm_vreg->regulator_type == RPM_REGULATOR_TYPE_VS) {
+ vreg_err(regulator, "unsupported regulator type: %d\n",
+ regulator->rpm_vreg->regulator_type);
+ return -EINVAL;
+ }
+
+ if (min_uV > max_uV) {
+ vreg_err(regulator, "min_uV=%d must be less than max_uV=%d\n",
+ min_uV, max_uV);
+ return -EINVAL;
+ }
+
+ if (uV < regulator->min_uV && max_uV >= regulator->min_uV)
+ uV = regulator->min_uV;
+
+ if (uV < regulator->min_uV || uV > regulator->max_uV) {
+ vreg_err(regulator,
+ "request v=[%d, %d] is outside allowed v=[%d, %d]\n",
+ min_uV, max_uV, regulator->min_uV, regulator->max_uV);
+ return -EINVAL;
+ }
+
+ return regulator->rdesc.ops->set_voltage(regulator->rdev, uV, uV, NULL);
+}
+EXPORT_SYMBOL(rpm_regulator_set_voltage);
+
+/**
+ * rpm_regulator_set_mode() - set regulator operating mode
+ * @regulator: RPM regulator handle
+ * @mode: operating mode requested for the regulator
+ *
+ * Requests that the mode of the regulator be set to the mode specified. This
+ * parameter is aggregated using a max function such that AUTO < IPEAK < HPM.
+ *
+ * Returns 0 on success or errno on failure.
+ */
+int rpm_regulator_set_mode(struct rpm_regulator *regulator,
+ enum rpm_regulator_mode mode)
+{
+ int index = 0;
+ u32 new_mode, prev_mode;
+ int rc;
+
+ rc = rpm_regulator_check_input(regulator);
+ if (rc)
+ return rc;
+
+ if (mode < 0 || mode >= ARRAY_SIZE(mode_mapping)) {
+ vreg_err(regulator, "invalid mode requested: %d\n", mode);
+ return -EINVAL;
+ }
+
+ switch (regulator->rpm_vreg->regulator_type) {
+ case RPM_REGULATOR_TYPE_SMPS:
+ index = RPM_REGULATOR_PARAM_MODE_SMPS;
+ new_mode = mode_mapping[mode].smps_mode;
+ break;
+ case RPM_REGULATOR_TYPE_LDO:
+ index = RPM_REGULATOR_PARAM_MODE_LDO;
+ new_mode = mode_mapping[mode].ldo_mode;
+ break;
+ default:
+ vreg_err(regulator, "unsupported regulator type: %d\n",
+ regulator->rpm_vreg->regulator_type);
+ return -EINVAL;
+ };
+
+ if (new_mode < params[index].min || new_mode > params[index].max) {
+ vreg_err(regulator, "invalid mode requested: %d for type: %d\n",
+ mode, regulator->rpm_vreg->regulator_type);
+ return -EINVAL;
+ }
+
+ rpm_vreg_lock(regulator->rpm_vreg);
+
+ prev_mode = regulator->req.param[index];
+ regulator->req.param[index] = new_mode;
+ regulator->req.modified |= BIT(index);
+
+ rc = rpm_vreg_aggregate_requests(regulator);
+ if (rc) {
+ vreg_err(regulator, "set mode failed, rc=%d", rc);
+ regulator->req.param[index] = prev_mode;
+ }
+
+ rpm_vreg_unlock(regulator->rpm_vreg);
+
+ return rc;
+}
+EXPORT_SYMBOL(rpm_regulator_set_mode);
+
+static struct regulator_ops ldo_ops = {
+ .enable = rpm_vreg_enable,
+ .disable = rpm_vreg_disable,
+ .is_enabled = rpm_vreg_is_enabled,
+ .set_voltage = rpm_vreg_set_voltage,
+ .get_voltage = rpm_vreg_get_voltage,
+ .set_mode = rpm_vreg_set_mode,
+ .get_mode = rpm_vreg_get_mode,
+ .get_optimum_mode = rpm_vreg_get_optimum_mode,
+ .enable_time = rpm_vreg_enable_time,
+};
+
+static struct regulator_ops smps_ops = {
+ .enable = rpm_vreg_enable,
+ .disable = rpm_vreg_disable,
+ .is_enabled = rpm_vreg_is_enabled,
+ .set_voltage = rpm_vreg_set_voltage,
+ .get_voltage = rpm_vreg_get_voltage,
+ .set_mode = rpm_vreg_set_mode,
+ .get_mode = rpm_vreg_get_mode,
+ .get_optimum_mode = rpm_vreg_get_optimum_mode,
+ .enable_time = rpm_vreg_enable_time,
+};
+
+static struct regulator_ops switch_ops = {
+ .enable = rpm_vreg_enable,
+ .disable = rpm_vreg_disable,
+ .is_enabled = rpm_vreg_is_enabled,
+ .enable_time = rpm_vreg_enable_time,
+};
+
+static struct regulator_ops ncp_ops = {
+ .enable = rpm_vreg_enable,
+ .disable = rpm_vreg_disable,
+ .is_enabled = rpm_vreg_is_enabled,
+ .set_voltage = rpm_vreg_set_voltage,
+ .get_voltage = rpm_vreg_get_voltage,
+ .enable_time = rpm_vreg_enable_time,
+};
+
+static struct regulator_ops bob_ops = {
+ .enable = rpm_vreg_enable,
+ .disable = rpm_vreg_disable,
+ .is_enabled = rpm_vreg_is_enabled,
+ .set_voltage = rpm_vreg_set_voltage,
+ .get_voltage = rpm_vreg_get_voltage,
+ .set_mode = rpm_vreg_set_bob_mode,
+ .get_mode = rpm_vreg_get_bob_mode,
+ .enable_time = rpm_vreg_enable_time,
+};
+
+static struct regulator_ops *vreg_ops[] = {
+ [RPM_REGULATOR_TYPE_LDO] = &ldo_ops,
+ [RPM_REGULATOR_TYPE_SMPS] = &smps_ops,
+ [RPM_REGULATOR_TYPE_VS] = &switch_ops,
+ [RPM_REGULATOR_TYPE_NCP] = &ncp_ops,
+ [RPM_REGULATOR_TYPE_BOB] = &bob_ops,
+};
+
+static int rpm_vreg_device_remove(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct rpm_regulator *reg;
+ struct rpm_vreg *rpm_vreg;
+
+ reg = platform_get_drvdata(pdev);
+ if (reg) {
+ rpm_vreg = reg->rpm_vreg;
+ rpm_vreg_lock(rpm_vreg);
+ regulator_unregister(reg->rdev);
+ list_del(®->list);
+ kfree(reg);
+ rpm_vreg_unlock(rpm_vreg);
+ } else {
+ dev_err(dev, "%s: drvdata missing\n", __func__);
+ return -EINVAL;
+ }
+
+ platform_set_drvdata(pdev, NULL);
+
+ return 0;
+}
+
+static int rpm_vreg_resource_remove(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct rpm_regulator *reg, *reg_temp;
+ struct rpm_vreg *rpm_vreg;
+
+ rpm_vreg = platform_get_drvdata(pdev);
+ if (rpm_vreg) {
+ rpm_vreg_lock(rpm_vreg);
+ list_for_each_entry_safe(reg, reg_temp, &rpm_vreg->reg_list,
+ list) {
+ /* Only touch data for private consumers. */
+ if (reg->rdev->desc == NULL) {
+ list_del(®->list);
+ kfree(reg->rdev);
+ kfree(reg);
+ } else {
+ dev_err(dev, "%s: not all child devices have been removed\n",
+ __func__);
+ }
+ }
+ rpm_vreg_unlock(rpm_vreg);
+
+ msm_rpm_free_request(rpm_vreg->handle_active);
+ msm_rpm_free_request(rpm_vreg->handle_sleep);
+
+ kfree(rpm_vreg);
+ } else {
+ dev_err(dev, "%s: drvdata missing\n", __func__);
+ return -EINVAL;
+ }
+
+ platform_set_drvdata(pdev, NULL);
+
+ return 0;
+}
+
+static int rpm_vreg_set_smps_ldo_voltage_index(struct device *dev,
+ struct rpm_regulator *reg)
+{
+ struct device_node *node = dev->of_node;
+ int chosen = 0;
+
+ if (of_property_read_bool(node, "qcom,use-voltage-corner")) {
+ reg->voltage_index = RPM_REGULATOR_PARAM_CORNER;
+ reg->voltage_offset = RPM_REGULATOR_CORNER_NONE;
+ chosen++;
+ }
+
+ if (of_property_read_bool(node, "qcom,use-voltage-floor-corner")) {
+ reg->voltage_index = RPM_REGULATOR_PARAM_FLOOR_CORNER;
+ reg->voltage_offset = RPM_REGULATOR_CORNER_NONE;
+ chosen++;
+ }
+
+ if (of_property_read_bool(node, "qcom,use-voltage-level")) {
+ reg->voltage_index = RPM_REGULATOR_PARAM_LEVEL;
+ chosen++;
+ }
+
+ if (of_property_read_bool(node, "qcom,use-voltage-floor-level")) {
+ reg->voltage_index = RPM_REGULATOR_PARAM_FLOOR_LEVEL;
+ chosen++;
+ }
+
+ if (chosen > 1) {
+ dev_err(dev, "only one qcom,use-voltage-* may be specified\n");
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int rpm_vreg_set_bob_voltage_index(struct device *dev,
+ struct rpm_regulator *reg)
+{
+ struct device_node *node = dev->of_node;
+ int chosen = 0;
+
+ if (of_property_read_bool(node, "qcom,use-pin-ctrl-voltage1")) {
+ reg->voltage_index = RPM_REGULATOR_PARAM_PIN_CTRL_VOLTAGE1;
+ chosen++;
+ }
+
+ if (of_property_read_bool(node, "qcom,use-pin-ctrl-voltage2")) {
+ reg->voltage_index = RPM_REGULATOR_PARAM_PIN_CTRL_VOLTAGE2;
+ chosen++;
+ }
+
+ if (of_property_read_bool(node, "qcom,use-pin-ctrl-voltage3")) {
+ reg->voltage_index = RPM_REGULATOR_PARAM_PIN_CTRL_VOLTAGE3;
+ chosen++;
+ }
+
+ if (chosen > 1) {
+ dev_err(dev, "only one qcom,use-pin-ctrl-voltage* may be specified\n");
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int rpm_vreg_device_set_voltage_index(struct device *dev,
+ struct rpm_regulator *reg, int type)
+{
+ int rc = 0;
+
+ reg->voltage_index = RPM_REGULATOR_PARAM_VOLTAGE;
+
+ switch (type) {
+ case RPM_REGULATOR_TYPE_SMPS:
+ case RPM_REGULATOR_TYPE_LDO:
+ rc = rpm_vreg_set_smps_ldo_voltage_index(dev, reg);
+ break;
+ case RPM_REGULATOR_TYPE_BOB:
+ rc = rpm_vreg_set_bob_voltage_index(dev, reg);
+ break;
+ }
+
+ return rc;
+}
+
+/*
+ * This probe is called for child rpm-regulator devices which have
+ * properties which are required to configure individual regulator
+ * framework regulators for a given RPM regulator resource.
+ */
+static int rpm_vreg_device_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct device_node *node = dev->of_node;
+ struct regulator_init_data *init_data;
+ struct rpm_vreg *rpm_vreg;
+ struct rpm_regulator *reg;
+ struct regulator_config reg_config = {};
+ int rc = 0;
+ int i, regulator_type;
+ u32 val;
+
+ if (!dev->of_node) {
+ dev_err(dev, "%s: device tree information missing\n", __func__);
+ return -ENODEV;
+ }
+
+ if (pdev->dev.parent == NULL) {
+ dev_err(dev, "%s: parent device missing\n", __func__);
+ return -ENODEV;
+ }
+
+ rpm_vreg = dev_get_drvdata(pdev->dev.parent);
+ if (rpm_vreg == NULL) {
+ dev_err(dev, "%s: rpm_vreg not found in parent device\n",
+ __func__);
+ return -ENODEV;
+ }
+
+ reg = kzalloc(sizeof(struct rpm_regulator), GFP_KERNEL);
+ if (reg == NULL) {
+ dev_err(dev, "%s: could not allocate memory for reg\n",
+ __func__);
+ return -ENOMEM;
+ }
+
+ regulator_type = rpm_vreg->regulator_type;
+ reg->rpm_vreg = rpm_vreg;
+ reg->rdesc.owner = THIS_MODULE;
+ reg->rdesc.type = REGULATOR_VOLTAGE;
+ reg->rdesc.ops = vreg_ops[regulator_type];
+
+ rc = rpm_vreg_device_set_voltage_index(dev, reg, regulator_type);
+ if (rc)
+ goto fail_free_reg;
+
+ reg->always_send_voltage
+ = of_property_read_bool(node, "qcom,always-send-voltage");
+ reg->always_send_current
+ = of_property_read_bool(node, "qcom,always-send-current");
+
+ if (regulator_type == RPM_REGULATOR_TYPE_VS)
+ reg->rdesc.n_voltages = 0;
+ else
+ reg->rdesc.n_voltages = 2;
+
+ rc = of_property_read_u32(node, "qcom,set", &val);
+ if (rc) {
+ dev_err(dev, "%s: sleep set and/or active set must be configured via qcom,set property, rc=%d\n",
+ __func__, rc);
+ goto fail_free_reg;
+ } else if (!(val & RPM_SET_CONFIG_BOTH)) {
+ dev_err(dev, "%s: qcom,set=%u property is invalid\n", __func__,
+ val);
+ rc = -EINVAL;
+ goto fail_free_reg;
+ }
+
+ reg->set_active = !!(val & RPM_SET_CONFIG_ACTIVE);
+ reg->set_sleep = !!(val & RPM_SET_CONFIG_SLEEP);
+
+ init_data = of_get_regulator_init_data(dev, node, ®->rdesc);
+ if (init_data == NULL) {
+ dev_err(dev, "%s: unable to allocate memory\n", __func__);
+ rc = -ENOMEM;
+ goto fail_free_reg;
+ }
+ if (init_data->constraints.name == NULL) {
+ dev_err(dev, "%s: regulator name not specified\n", __func__);
+ rc = -EINVAL;
+ goto fail_free_reg;
+ }
+
+ init_data->constraints.input_uV = init_data->constraints.max_uV;
+
+ if (of_get_property(node, "parent-supply", NULL))
+ init_data->supply_regulator = "parent";
+
+ /*
+ * Fill in ops and mode masks based on callbacks specified for
+ * this type of regulator.
+ */
+ if (reg->rdesc.ops->enable)
+ init_data->constraints.valid_ops_mask
+ |= REGULATOR_CHANGE_STATUS;
+ if (reg->rdesc.ops->get_voltage)
+ init_data->constraints.valid_ops_mask
+ |= REGULATOR_CHANGE_VOLTAGE;
+ if (reg->rdesc.ops->get_mode) {
+ init_data->constraints.valid_ops_mask
+ |= REGULATOR_CHANGE_MODE | REGULATOR_CHANGE_DRMS;
+ init_data->constraints.valid_modes_mask
+ |= REGULATOR_MODE_NORMAL | REGULATOR_MODE_IDLE;
+ }
+
+ reg->rdesc.name = init_data->constraints.name;
+ reg->min_uV = init_data->constraints.min_uV;
+ reg->max_uV = init_data->constraints.max_uV;
+
+ /* Initialize the param array based on optional properties. */
+ for (i = 0; i < RPM_REGULATOR_PARAM_MAX; i++) {
+ rc = of_property_read_u32(node, params[i].property_name, &val);
+ if (rc == 0) {
+ if (params[i].supported_regulator_types
+ & BIT(regulator_type)) {
+ if (val < params[i].min
+ || val > params[i].max) {
+ pr_warn("%s: device tree property: %s=%u is outsided allowed range [%u, %u]\n",
+ reg->rdesc.name,
+ params[i].property_name, val,
+ params[i].min, params[i].max);
+ continue;
+ }
+ reg->req.param[i] = val;
+ reg->req.modified |= BIT(i);
+ } else {
+ pr_warn("%s: regulator type=%d does not support device tree property: %s\n",
+ reg->rdesc.name, regulator_type,
+ params[i].property_name);
+ }
+ }
+ }
+
+ of_property_read_u32(node, "qcom,system-load", ®->system_load);
+
+ rc = rpm_vreg_configure_pin_control_enable(reg, node);
+ if (rc) {
+ vreg_err(reg, "could not configure pin control enable, rc=%d\n",
+ rc);
+ goto fail_free_reg;
+ }
+
+ rpm_vreg_lock(rpm_vreg);
+ list_add(®->list, &rpm_vreg->reg_list);
+ rpm_vreg_unlock(rpm_vreg);
+
+ if (of_property_read_bool(node, "qcom,send-defaults")) {
+ rc = rpm_vreg_send_defaults(reg);
+ if (rc) {
+ vreg_err(reg, "could not send defaults, rc=%d\n", rc);
+ goto fail_remove_from_list;
+ }
+ }
+
+ reg_config.dev = dev;
+ reg_config.init_data = init_data;
+ reg_config.of_node = node;
+ reg_config.driver_data = reg;
+ reg->rdev = regulator_register(®->rdesc, ®_config);
+ if (IS_ERR(reg->rdev)) {
+ rc = PTR_ERR(reg->rdev);
+ reg->rdev = NULL;
+ pr_err("regulator_register failed: %s, rc=%d\n",
+ reg->rdesc.name, rc);
+ goto fail_remove_from_list;
+ }
+
+ platform_set_drvdata(pdev, reg);
+
+ pr_debug("successfully probed: %s\n", reg->rdesc.name);
+
+ return 0;
+
+fail_remove_from_list:
+ rpm_vreg_lock(rpm_vreg);
+ list_del(®->list);
+ rpm_vreg_unlock(rpm_vreg);
+
+fail_free_reg:
+ kfree(reg);
+ return rc;
+}
+
+/*
+ * This probe is called for parent rpm-regulator devices which have
+ * properties which are required to identify a given RPM resource.
+ */
+static int rpm_vreg_resource_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct device_node *node = dev->of_node;
+ struct rpm_vreg *rpm_vreg;
+ int val = 0;
+ u32 resource_type;
+ int rc;
+
+ if (!dev->of_node) {
+ dev_err(dev, "%s: device tree information missing\n", __func__);
+ return -ENODEV;
+ }
+
+ /* Create new rpm_vreg entry. */
+ rpm_vreg = kzalloc(sizeof(struct rpm_vreg), GFP_KERNEL);
+ if (rpm_vreg == NULL) {
+ dev_err(dev, "%s: could not allocate memory for vreg\n",
+ __func__);
+ return -ENOMEM;
+ }
+
+ /* Required device tree properties: */
+ rc = of_property_read_string(node, "qcom,resource-name",
+ &rpm_vreg->resource_name);
+ if (rc) {
+ dev_err(dev, "%s: qcom,resource-name missing in DT node\n",
+ __func__);
+ goto fail_free_vreg;
+ }
+ resource_type = rpm_vreg_string_to_int(rpm_vreg->resource_name);
+
+ rc = of_property_read_u32(node, "qcom,resource-id",
+ &rpm_vreg->resource_id);
+ if (rc) {
+ dev_err(dev, "%s: qcom,resource-id missing in DT node\n",
+ __func__);
+ goto fail_free_vreg;
+ }
+
+ rc = of_property_read_u32(node, "qcom,regulator-type",
+ &rpm_vreg->regulator_type);
+ if (rc) {
+ dev_err(dev, "%s: qcom,regulator-type missing in DT node\n",
+ __func__);
+ goto fail_free_vreg;
+ }
+
+ if ((rpm_vreg->regulator_type < 0)
+ || (rpm_vreg->regulator_type >= RPM_REGULATOR_TYPE_MAX)) {
+ dev_err(dev, "%s: invalid regulator type: %d\n", __func__,
+ rpm_vreg->regulator_type);
+ rc = -EINVAL;
+ goto fail_free_vreg;
+ }
+
+ /* Optional device tree properties: */
+ of_property_read_u32(node, "qcom,allow-atomic", &val);
+ rpm_vreg->allow_atomic = !!val;
+ of_property_read_u32(node, "qcom,enable-time", &rpm_vreg->enable_time);
+ of_property_read_u32(node, "qcom,hpm-min-load",
+ &rpm_vreg->hpm_min_load);
+ rpm_vreg->apps_only = of_property_read_bool(node, "qcom,apps-only");
+ rpm_vreg->always_wait_for_ack
+ = of_property_read_bool(node, "qcom,always-wait-for-ack");
+
+ rpm_vreg->handle_active = msm_rpm_create_request(RPM_SET_ACTIVE,
+ resource_type, rpm_vreg->resource_id, RPM_REGULATOR_PARAM_MAX);
+ if (rpm_vreg->handle_active == NULL
+ || IS_ERR(rpm_vreg->handle_active)) {
+ rc = PTR_ERR(rpm_vreg->handle_active);
+ if (rc != -EPROBE_DEFER)
+ dev_err(dev, "%s: failed to create active RPM handle, rc=%d\n",
+ __func__, rc);
+ goto fail_free_vreg;
+ }
+
+ rpm_vreg->handle_sleep = msm_rpm_create_request(RPM_SET_SLEEP,
+ resource_type, rpm_vreg->resource_id, RPM_REGULATOR_PARAM_MAX);
+ if (rpm_vreg->handle_sleep == NULL || IS_ERR(rpm_vreg->handle_sleep)) {
+ rc = PTR_ERR(rpm_vreg->handle_sleep);
+ if (rc != -EPROBE_DEFER)
+ dev_err(dev, "%s: failed to create sleep RPM handle, rc=%d\n",
+ __func__, rc);
+ goto fail_free_handle_active;
+ }
+
+ INIT_LIST_HEAD(&rpm_vreg->reg_list);
+
+ if (rpm_vreg->allow_atomic)
+ spin_lock_init(&rpm_vreg->slock);
+ else
+ mutex_init(&rpm_vreg->mlock);
+
+ platform_set_drvdata(pdev, rpm_vreg);
+
+ rc = of_platform_populate(node, NULL, NULL, dev);
+ if (rc) {
+ dev_err(dev, "%s: failed to add child nodes, rc=%d\n", __func__,
+ rc);
+ goto fail_unset_drvdata;
+ }
+
+ pr_debug("successfully probed: %s (%08X) %u\n", rpm_vreg->resource_name,
+ resource_type, rpm_vreg->resource_id);
+
+ return rc;
+
+fail_unset_drvdata:
+ platform_set_drvdata(pdev, NULL);
+ msm_rpm_free_request(rpm_vreg->handle_sleep);
+
+fail_free_handle_active:
+ msm_rpm_free_request(rpm_vreg->handle_active);
+
+fail_free_vreg:
+ kfree(rpm_vreg);
+
+ return rc;
+}
+
+static struct of_device_id rpm_vreg_match_table_device[] = {
+ { .compatible = "qcom,rpm-smd-regulator", },
+ {}
+};
+
+static struct of_device_id rpm_vreg_match_table_resource[] = {
+ { .compatible = "qcom,rpm-smd-regulator-resource", },
+ {}
+};
+
+static struct platform_driver rpm_vreg_device_driver = {
+ .probe = rpm_vreg_device_probe,
+ .remove = rpm_vreg_device_remove,
+ .driver = {
+ .name = "qcom,rpm-smd-regulator",
+ .owner = THIS_MODULE,
+ .of_match_table = rpm_vreg_match_table_device,
+ },
+};
+
+static struct platform_driver rpm_vreg_resource_driver = {
+ .probe = rpm_vreg_resource_probe,
+ .remove = rpm_vreg_resource_remove,
+ .driver = {
+ .name = "qcom,rpm-smd-regulator-resource",
+ .owner = THIS_MODULE,
+ .of_match_table = rpm_vreg_match_table_resource,
+ },
+};
+
+/**
+ * rpm_smd_regulator_driver_init() - initialize the RPM SMD regulator drivers
+ *
+ * This function registers the RPM SMD regulator platform drivers.
+ *
+ * Returns 0 on success or errno on failure.
+ */
+int __init rpm_smd_regulator_driver_init(void)
+{
+ static bool initialized;
+ int i, rc;
+
+ if (initialized)
+ return 0;
+ else
+ initialized = true;
+
+ /* Store parameter string names as integers */
+ for (i = 0; i < RPM_REGULATOR_PARAM_MAX; i++)
+ params[i].key = rpm_vreg_string_to_int(params[i].name);
+
+ rc = platform_driver_register(&rpm_vreg_device_driver);
+ if (rc)
+ return rc;
+
+ return platform_driver_register(&rpm_vreg_resource_driver);
+}
+EXPORT_SYMBOL(rpm_smd_regulator_driver_init);
+
+static void __exit rpm_vreg_exit(void)
+{
+ platform_driver_unregister(&rpm_vreg_device_driver);
+ platform_driver_unregister(&rpm_vreg_resource_driver);
+}
+
+arch_initcall(rpm_smd_regulator_driver_init);
+module_exit(rpm_vreg_exit);
+
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("MSM RPM SMD regulator driver");
diff --git a/drivers/regulator/spm-regulator.c b/drivers/regulator/spm-regulator.c
new file mode 100644
index 0000000..af8e96f
--- /dev/null
+++ b/drivers/regulator/spm-regulator.c
@@ -0,0 +1,1329 @@
+/* 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
+ * 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/arm-smccc.h>
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/regmap.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/slab.h>
+#include <linux/spmi.h>
+#include <linux/platform_device.h>
+#include <linux/string.h>
+#include <linux/regulator/driver.h>
+#include <linux/regulator/machine.h>
+#include <linux/regulator/of_regulator.h>
+#include <linux/regulator/spm-regulator.h>
+#include <soc/qcom/spm.h>
+#include <linux/arm-smccc.h>
+
+#if defined(CONFIG_ARM64) || (defined(CONFIG_ARM) && defined(CONFIG_ARM_PSCI))
+#else
+ #define __invoke_psci_fn_smc(a, b, c, d) 0
+#endif
+
+#define SPM_REGULATOR_DRIVER_NAME "qcom,spm-regulator"
+
+struct voltage_range {
+ int min_uV;
+ int set_point_min_uV;
+ int max_uV;
+ int step_uV;
+};
+
+enum qpnp_regulator_uniq_type {
+ QPNP_TYPE_HF,
+ QPNP_TYPE_FTS2,
+ QPNP_TYPE_FTS2p5,
+ QPNP_TYPE_FTS426,
+ QPNP_TYPE_ULT_HF,
+};
+
+enum qpnp_regulator_type {
+ QPNP_HF_TYPE = 0x03,
+ QPNP_FTS2_TYPE = 0x1C,
+ QPNP_FTS2p5_TYPE = 0x1C,
+ QPNP_FTS426_TYPE = 0x1C,
+ QPNP_ULT_HF_TYPE = 0x22,
+};
+
+enum qpnp_regulator_subtype {
+ QPNP_FTS2_SUBTYPE = 0x08,
+ QPNP_HF_SUBTYPE = 0x08,
+ QPNP_FTS2p5_SUBTYPE = 0x09,
+ QPNP_FTS426_SUBTYPE = 0x0A,
+ QPNP_ULT_HF_SUBTYPE = 0x0D,
+};
+
+enum qpnp_logical_mode {
+ QPNP_LOGICAL_MODE_AUTO,
+ QPNP_LOGICAL_MODE_PWM,
+};
+
+static const struct voltage_range fts2_range0 = {0, 350000, 1275000, 5000};
+static const struct voltage_range fts2_range1 = {0, 700000, 2040000, 10000};
+static const struct voltage_range fts2p5_range0
+ = { 80000, 350000, 1355000, 5000};
+static const struct voltage_range fts2p5_range1
+ = {160000, 700000, 2200000, 10000};
+static const struct voltage_range fts426_range = {0, 320000, 1352000, 4000};
+static const struct voltage_range ult_hf_range0 = {375000, 375000, 1562500,
+ 12500};
+static const struct voltage_range ult_hf_range1 = {750000, 750000, 1525000,
+ 25000};
+static const struct voltage_range hf_range0 = {375000, 375000, 1562500, 12500};
+static const struct voltage_range hf_range1 = {1550000, 1550000, 3125000,
+ 25000};
+
+#define QPNP_SMPS_REG_TYPE 0x04
+#define QPNP_SMPS_REG_SUBTYPE 0x05
+#define QPNP_SMPS_REG_VOLTAGE_RANGE 0x40
+#define QPNP_SMPS_REG_VOLTAGE_SETPOINT 0x41
+#define QPNP_SMPS_REG_MODE 0x45
+#define QPNP_SMPS_REG_STEP_CTRL 0x61
+#define QPNP_SMPS_REG_UL_LL_CTRL 0x68
+
+/* FTS426 voltage control registers */
+#define QPNP_FTS426_REG_VOLTAGE_LB 0x40
+#define QPNP_FTS426_REG_VOLTAGE_UB 0x41
+#define QPNP_FTS426_REG_VOLTAGE_VALID_LB 0x42
+#define QPNP_FTS426_REG_VOLTAGE_VALID_UB 0x43
+
+/* HF voltage limit registers */
+#define QPNP_HF_REG_VOLTAGE_ULS 0x69
+#define QPNP_HF_REG_VOLTAGE_LLS 0x6B
+
+/* FTS voltage limit registers */
+#define QPNP_FTS_REG_VOLTAGE_ULS_VALID 0x6A
+#define QPNP_FTS_REG_VOLTAGE_LLS_VALID 0x6C
+
+/* FTS426 voltage limit registers */
+#define QPNP_FTS426_REG_VOLTAGE_ULS_LB 0x68
+#define QPNP_FTS426_REG_VOLTAGE_ULS_UB 0x69
+
+/* Common regulator UL & LL limits control register layout */
+#define QPNP_COMMON_UL_EN_MASK 0x80
+#define QPNP_COMMON_LL_EN_MASK 0x40
+
+#define QPNP_SMPS_MODE_PWM 0x80
+#define QPNP_SMPS_MODE_AUTO 0x40
+#define QPNP_FTS426_MODE_PWM 0x07
+#define QPNP_FTS426_MODE_AUTO 0x06
+
+#define QPNP_SMPS_STEP_CTRL_STEP_MASK 0x18
+#define QPNP_SMPS_STEP_CTRL_STEP_SHIFT 3
+#define QPNP_SMPS_STEP_CTRL_DELAY_MASK 0x07
+#define QPNP_SMPS_STEP_CTRL_DELAY_SHIFT 0
+#define QPNP_FTS426_STEP_CTRL_DELAY_MASK 0x03
+#define QPNP_FTS426_STEP_CTRL_DELAY_SHIFT 0
+
+/* Clock rate in kHz of the FTS2 regulator reference clock. */
+#define QPNP_SMPS_CLOCK_RATE 19200
+#define QPNP_FTS426_CLOCK_RATE 4800
+
+/* Time to delay in us to ensure that a mode change has completed. */
+#define QPNP_FTS2_MODE_CHANGE_DELAY 50
+
+/* Minimum time in us that it takes to complete a single SPMI write. */
+#define QPNP_SPMI_WRITE_MIN_DELAY 8
+
+/* Minimum voltage stepper delay for each step. */
+#define QPNP_FTS2_STEP_DELAY 8
+#define QPNP_HF_STEP_DELAY 20
+#define QPNP_FTS426_STEP_DELAY 2
+
+/* Arbitrarily large max step size used to avoid possible numerical overflow */
+#define SPM_REGULATOR_MAX_STEP_UV 10000000
+
+/*
+ * The ratio QPNP_FTS2_STEP_MARGIN_NUM/QPNP_FTS2_STEP_MARGIN_DEN is use to
+ * adjust the step rate in order to account for oscillator variance.
+ */
+#define QPNP_FTS2_STEP_MARGIN_NUM 4
+#define QPNP_FTS2_STEP_MARGIN_DEN 5
+#define QPNP_FTS426_STEP_MARGIN_NUM 10
+#define QPNP_FTS426_STEP_MARGIN_DEN 11
+
+/*
+ * Settling delay for FTS2.5
+ * Warm-up=20uS, 0-10% & 90-100% non-linear V-ramp delay = 50uS
+ */
+#define FTS2P5_SETTLING_DELAY_US 70
+
+/* VSET value to decide the range of ULT SMPS */
+#define ULT_SMPS_RANGE_SPLIT 0x60
+
+struct spm_vreg {
+ struct regulator_desc rdesc;
+ struct regulator_dev *rdev;
+ struct platform_device *pdev;
+ struct regmap *regmap;
+ const struct voltage_range *range;
+ int uV;
+ int last_set_uV;
+ unsigned vlevel;
+ unsigned last_set_vlevel;
+ u32 max_step_uV;
+ bool online;
+ u16 spmi_base_addr;
+ enum qpnp_logical_mode init_mode;
+ enum qpnp_logical_mode mode;
+ int step_rate;
+ enum qpnp_regulator_uniq_type regulator_type;
+ u32 cpu_num;
+ bool bypass_spm;
+ struct regulator_desc avs_rdesc;
+ struct regulator_dev *avs_rdev;
+ int avs_min_uV;
+ int avs_max_uV;
+ bool avs_enabled;
+ u32 recal_cluster_mask;
+};
+
+static inline bool spm_regulator_using_avs(struct spm_vreg *vreg)
+{
+ return vreg->avs_rdev && !vreg->bypass_spm;
+}
+
+static int spm_regulator_uv_to_vlevel(struct spm_vreg *vreg, int uV)
+{
+ int vlevel;
+
+ if (vreg->regulator_type == QPNP_TYPE_FTS426)
+ return roundup(uV, vreg->range->step_uV) / 1000;
+
+ vlevel = DIV_ROUND_UP(uV - vreg->range->min_uV, vreg->range->step_uV);
+
+ /* Fix VSET for ULT HF Buck */
+ if (vreg->regulator_type == QPNP_TYPE_ULT_HF
+ && vreg->range == &ult_hf_range1) {
+ vlevel &= 0x1F;
+ vlevel |= ULT_SMPS_RANGE_SPLIT;
+ }
+
+ return vlevel;
+}
+
+static int spm_regulator_vlevel_to_uv(struct spm_vreg *vreg, int vlevel)
+{
+ if (vreg->regulator_type == QPNP_TYPE_FTS426)
+ return vlevel * 1000;
+ /*
+ * Calculate ULT HF buck VSET based on range:
+ * In case of range 0: VSET is a 7 bit value.
+ * In case of range 1: VSET is a 5 bit value.
+ */
+ if (vreg->regulator_type == QPNP_TYPE_ULT_HF
+ && vreg->range == &ult_hf_range1)
+ vlevel &= ~ULT_SMPS_RANGE_SPLIT;
+
+ return vlevel * vreg->range->step_uV + vreg->range->min_uV;
+}
+
+static unsigned spm_regulator_vlevel_to_selector(struct spm_vreg *vreg,
+ unsigned vlevel)
+{
+ /* Fix VSET for ULT HF Buck */
+ if (vreg->regulator_type == QPNP_TYPE_ULT_HF
+ && vreg->range == &ult_hf_range1)
+ vlevel &= ~ULT_SMPS_RANGE_SPLIT;
+
+ return vlevel - (vreg->range->set_point_min_uV - vreg->range->min_uV)
+ / vreg->range->step_uV;
+}
+
+static int qpnp_smps_read_voltage(struct spm_vreg *vreg)
+{
+ int rc;
+ u8 val[2] = {0};
+
+ if (vreg->regulator_type == QPNP_TYPE_FTS426) {
+ rc = regmap_bulk_read(vreg->regmap,
+ vreg->spmi_base_addr + QPNP_FTS426_REG_VOLTAGE_VALID_LB,
+ val, 2);
+ if (rc) {
+ dev_err(&vreg->pdev->dev, "%s: could not read voltage setpoint registers, rc=%d\n",
+ __func__, rc);
+ return rc;
+ }
+
+ vreg->last_set_vlevel = ((unsigned)val[1] << 8) | val[0];
+ } else {
+ rc = regmap_bulk_read(vreg->regmap,
+ vreg->spmi_base_addr + QPNP_SMPS_REG_VOLTAGE_SETPOINT,
+ val, 1);
+ if (rc) {
+ dev_err(&vreg->pdev->dev, "%s: could not read voltage setpoint register, rc=%d\n",
+ __func__, rc);
+ return rc;
+ }
+ vreg->last_set_vlevel = val[0];
+ }
+
+ vreg->last_set_uV = spm_regulator_vlevel_to_uv(vreg,
+ vreg->last_set_vlevel);
+ return rc;
+}
+
+static int qpnp_smps_write_voltage(struct spm_vreg *vreg, unsigned vlevel)
+{
+ int rc = 0;
+ u8 reg[2];
+
+ /* Set voltage control registers via SPMI. */
+ reg[0] = vlevel & 0xFF;
+ reg[1] = (vlevel >> 8) & 0xFF;
+
+ if (vreg->regulator_type == QPNP_TYPE_FTS426) {
+ rc = regmap_bulk_write(vreg->regmap,
+ vreg->spmi_base_addr + QPNP_FTS426_REG_VOLTAGE_LB,
+ reg, 2);
+ } else {
+ rc = regmap_write(vreg->regmap,
+ vreg->spmi_base_addr + QPNP_SMPS_REG_VOLTAGE_SETPOINT,
+ reg[0]);
+ }
+
+ if (rc)
+ pr_err("%s: regmap_write failed, rc=%d\n",
+ vreg->rdesc.name, rc);
+
+ return rc;
+}
+
+static inline enum qpnp_logical_mode qpnp_regval_to_mode(struct spm_vreg *vreg,
+ u8 regval)
+{
+ if (vreg->regulator_type == QPNP_TYPE_FTS426)
+ return (regval == QPNP_FTS426_MODE_PWM)
+ ? QPNP_LOGICAL_MODE_PWM : QPNP_LOGICAL_MODE_AUTO;
+ else
+ return (regval & QPNP_SMPS_MODE_PWM)
+ ? QPNP_LOGICAL_MODE_PWM : QPNP_LOGICAL_MODE_AUTO;
+}
+
+static inline u8 qpnp_mode_to_regval(struct spm_vreg *vreg,
+ enum qpnp_logical_mode mode)
+{
+ if (vreg->regulator_type == QPNP_TYPE_FTS426)
+ return (mode == QPNP_LOGICAL_MODE_PWM)
+ ? QPNP_FTS426_MODE_PWM : QPNP_FTS426_MODE_AUTO;
+ else
+ return (mode == QPNP_LOGICAL_MODE_PWM)
+ ? QPNP_SMPS_MODE_PWM : QPNP_SMPS_MODE_AUTO;
+}
+
+static int qpnp_smps_set_mode(struct spm_vreg *vreg, u8 mode)
+{
+ int rc;
+
+ rc = regmap_write(vreg->regmap,
+ vreg->spmi_base_addr + QPNP_SMPS_REG_MODE,
+ qpnp_mode_to_regval(vreg, mode));
+ if (rc)
+ dev_err(&vreg->pdev->dev,
+ "%s: could not write to mode register, rc=%d\n",
+ __func__, rc);
+
+ return rc;
+}
+
+static int spm_regulator_get_voltage(struct regulator_dev *rdev)
+{
+ struct spm_vreg *vreg = rdev_get_drvdata(rdev);
+ int vlevel, rc;
+
+ if (spm_regulator_using_avs(vreg)) {
+ vlevel = msm_spm_get_vdd(vreg->cpu_num);
+
+ if (vlevel < 0) {
+ pr_debug("%s: msm_spm_get_vdd failed, rc=%d; falling back on SPMI read\n",
+ vreg->rdesc.name, vlevel);
+
+ rc = qpnp_smps_read_voltage(vreg);
+ if (rc) {
+ pr_err("%s: voltage read failed, rc=%d\n",
+ vreg->rdesc.name, rc);
+ return rc;
+ }
+
+ return vreg->last_set_uV;
+ }
+
+ vreg->last_set_vlevel = vlevel;
+ vreg->last_set_uV = spm_regulator_vlevel_to_uv(vreg, vlevel);
+
+ return vreg->last_set_uV;
+ } else {
+ return vreg->uV;
+ }
+};
+
+static int spm_regulator_write_voltage(struct spm_vreg *vreg, int uV)
+{
+ unsigned vlevel = spm_regulator_uv_to_vlevel(vreg, uV);
+ bool spm_failed = false;
+ int rc = 0;
+ u32 slew_delay;
+
+ if (likely(!vreg->bypass_spm)) {
+ /* Set voltage control register via SPM. */
+ rc = msm_spm_set_vdd(vreg->cpu_num, vlevel);
+ if (rc) {
+ pr_debug("%s: msm_spm_set_vdd failed, rc=%d; falling back on SPMI write\n",
+ vreg->rdesc.name, rc);
+ spm_failed = true;
+ }
+ }
+
+ if (unlikely(vreg->bypass_spm || spm_failed)) {
+ rc = qpnp_smps_write_voltage(vreg, vlevel);
+ if (rc) {
+ pr_err("%s: voltage write failed, rc=%d\n",
+ vreg->rdesc.name, rc);
+ return rc;
+ }
+ }
+
+ if (uV > vreg->last_set_uV) {
+ /* Wait for voltage stepping to complete. */
+ slew_delay = DIV_ROUND_UP(uV - vreg->last_set_uV,
+ vreg->step_rate);
+ if (vreg->regulator_type == QPNP_TYPE_FTS2p5)
+ slew_delay += FTS2P5_SETTLING_DELAY_US;
+ udelay(slew_delay);
+ } else if (vreg->regulator_type == QPNP_TYPE_FTS2p5) {
+ /* add the ramp-down delay */
+ slew_delay = DIV_ROUND_UP(vreg->last_set_uV - uV,
+ vreg->step_rate) + FTS2P5_SETTLING_DELAY_US;
+ udelay(slew_delay);
+ }
+
+ vreg->last_set_uV = uV;
+ vreg->last_set_vlevel = vlevel;
+
+ return rc;
+}
+
+static int spm_regulator_recalibrate(struct spm_vreg *vreg)
+{
+ struct arm_smccc_res res;
+
+ if (!vreg->recal_cluster_mask)
+ return 0;
+
+ arm_smccc_smc(0xC4000020, vreg->recal_cluster_mask, 2, 0, 0, 0, 0, 0, &res);
+ if (res.a0)
+ pr_err("%s: recalibration failed, rc=%ld\n", vreg->rdesc.name,
+ res.a0);
+
+ return res.a0;
+}
+
+static int _spm_regulator_set_voltage(struct regulator_dev *rdev)
+{
+ struct spm_vreg *vreg = rdev_get_drvdata(rdev);
+ bool pwm_required;
+ int rc = 0;
+ int uV;
+
+ rc = spm_regulator_get_voltage(rdev);
+ if (rc < 0)
+ return rc;
+
+ if (vreg->vlevel == vreg->last_set_vlevel)
+ return 0;
+
+ pwm_required = (vreg->regulator_type == QPNP_TYPE_FTS2)
+ && (vreg->init_mode != QPNP_LOGICAL_MODE_PWM)
+ && vreg->uV > vreg->last_set_uV;
+
+ if (pwm_required) {
+ /* Switch to PWM mode so that voltage ramping is fast. */
+ rc = qpnp_smps_set_mode(vreg, QPNP_LOGICAL_MODE_PWM);
+ if (rc)
+ return rc;
+ }
+
+ do {
+ uV = vreg->uV > vreg->last_set_uV
+ ? min(vreg->uV, vreg->last_set_uV + (int)vreg->max_step_uV)
+ : max(vreg->uV, vreg->last_set_uV - (int)vreg->max_step_uV);
+
+ rc = spm_regulator_write_voltage(vreg, uV);
+ if (rc)
+ return rc;
+ } while (vreg->last_set_uV != vreg->uV);
+
+ if (pwm_required) {
+ /* Wait for mode transition to complete. */
+ udelay(QPNP_FTS2_MODE_CHANGE_DELAY - QPNP_SPMI_WRITE_MIN_DELAY);
+ /* Switch to AUTO mode so that power consumption is lowered. */
+ rc = qpnp_smps_set_mode(vreg, QPNP_LOGICAL_MODE_AUTO);
+ if (rc)
+ return rc;
+ }
+
+ rc = spm_regulator_recalibrate(vreg);
+
+ return rc;
+}
+
+static int spm_regulator_set_voltage(struct regulator_dev *rdev, int min_uV,
+ int max_uV, unsigned *selector)
+{
+ struct spm_vreg *vreg = rdev_get_drvdata(rdev);
+ const struct voltage_range *range = vreg->range;
+ int uV = min_uV;
+ unsigned vlevel;
+
+ if (uV < range->set_point_min_uV && max_uV >= range->set_point_min_uV)
+ uV = range->set_point_min_uV;
+
+ if (uV < range->set_point_min_uV || uV > range->max_uV) {
+ pr_err("%s: request v=[%d, %d] is outside possible v=[%d, %d]\n",
+ vreg->rdesc.name, min_uV, max_uV,
+ range->set_point_min_uV, range->max_uV);
+ return -EINVAL;
+ }
+
+ vlevel = spm_regulator_uv_to_vlevel(vreg, uV);
+ uV = spm_regulator_vlevel_to_uv(vreg, vlevel);
+
+ if (uV > max_uV) {
+ pr_err("%s: request v=[%d, %d] cannot be met by any set point\n",
+ vreg->rdesc.name, min_uV, max_uV);
+ return -EINVAL;
+ }
+
+ *selector = spm_regulator_vlevel_to_selector(vreg, vlevel);
+ vreg->vlevel = vlevel;
+ vreg->uV = uV;
+
+ if (!vreg->online)
+ return 0;
+
+ return _spm_regulator_set_voltage(rdev);
+}
+
+static int spm_regulator_list_voltage(struct regulator_dev *rdev,
+ unsigned selector)
+{
+ struct spm_vreg *vreg = rdev_get_drvdata(rdev);
+
+ if (selector >= vreg->rdesc.n_voltages)
+ return 0;
+
+ return selector * vreg->range->step_uV + vreg->range->set_point_min_uV;
+}
+
+static int spm_regulator_enable(struct regulator_dev *rdev)
+{
+ struct spm_vreg *vreg = rdev_get_drvdata(rdev);
+ int rc;
+
+ rc = _spm_regulator_set_voltage(rdev);
+
+ if (!rc)
+ vreg->online = true;
+
+ return rc;
+}
+
+static int spm_regulator_disable(struct regulator_dev *rdev)
+{
+ struct spm_vreg *vreg = rdev_get_drvdata(rdev);
+
+ vreg->online = false;
+
+ return 0;
+}
+
+static int spm_regulator_is_enabled(struct regulator_dev *rdev)
+{
+ struct spm_vreg *vreg = rdev_get_drvdata(rdev);
+
+ return vreg->online;
+}
+
+static unsigned int spm_regulator_get_mode(struct regulator_dev *rdev)
+{
+ struct spm_vreg *vreg = rdev_get_drvdata(rdev);
+
+ return vreg->mode == QPNP_LOGICAL_MODE_PWM
+ ? REGULATOR_MODE_NORMAL : REGULATOR_MODE_IDLE;
+}
+
+static int spm_regulator_set_mode(struct regulator_dev *rdev, unsigned int mode)
+{
+ struct spm_vreg *vreg = rdev_get_drvdata(rdev);
+
+ /*
+ * Map REGULATOR_MODE_NORMAL to PWM mode and REGULATOR_MODE_IDLE to
+ * init_mode. This ensures that the regulator always stays in PWM mode
+ * in the case that qcom,mode has been specified as "pwm" in device
+ * tree.
+ */
+ vreg->mode = (mode == REGULATOR_MODE_NORMAL) ? QPNP_LOGICAL_MODE_PWM
+ : vreg->init_mode;
+
+ return qpnp_smps_set_mode(vreg, vreg->mode);
+}
+
+static struct regulator_ops spm_regulator_ops = {
+ .get_voltage = spm_regulator_get_voltage,
+ .set_voltage = spm_regulator_set_voltage,
+ .list_voltage = spm_regulator_list_voltage,
+ .get_mode = spm_regulator_get_mode,
+ .set_mode = spm_regulator_set_mode,
+ .enable = spm_regulator_enable,
+ .disable = spm_regulator_disable,
+ .is_enabled = spm_regulator_is_enabled,
+};
+
+static int spm_regulator_avs_set_voltage(struct regulator_dev *rdev, int min_uV,
+ int max_uV, unsigned *selector)
+{
+ struct spm_vreg *vreg = rdev_get_drvdata(rdev);
+ const struct voltage_range *range = vreg->range;
+ unsigned vlevel_min, vlevel_max;
+ int uV, avs_min_uV, avs_max_uV, rc;
+
+ uV = min_uV;
+
+ if (uV < range->set_point_min_uV && max_uV >= range->set_point_min_uV)
+ uV = range->set_point_min_uV;
+
+ if (uV < range->set_point_min_uV || uV > range->max_uV) {
+ pr_err("%s: request v=[%d, %d] is outside possible v=[%d, %d]\n",
+ vreg->avs_rdesc.name, min_uV, max_uV,
+ range->set_point_min_uV, range->max_uV);
+ return -EINVAL;
+ }
+
+ vlevel_min = spm_regulator_uv_to_vlevel(vreg, uV);
+ avs_min_uV = spm_regulator_vlevel_to_uv(vreg, vlevel_min);
+
+ if (avs_min_uV > max_uV) {
+ pr_err("%s: request v=[%d, %d] cannot be met by any set point\n",
+ vreg->avs_rdesc.name, min_uV, max_uV);
+ return -EINVAL;
+ }
+
+ uV = max_uV;
+
+ if (uV > range->max_uV && min_uV <= range->max_uV)
+ uV = range->max_uV;
+
+ if (uV < range->set_point_min_uV || uV > range->max_uV) {
+ pr_err("%s: request v=[%d, %d] is outside possible v=[%d, %d]\n",
+ vreg->avs_rdesc.name, min_uV, max_uV,
+ range->set_point_min_uV, range->max_uV);
+ return -EINVAL;
+ }
+
+ vlevel_max = spm_regulator_uv_to_vlevel(vreg, uV);
+ avs_max_uV = spm_regulator_vlevel_to_uv(vreg, vlevel_max);
+
+ if (avs_max_uV < min_uV) {
+ pr_err("%s: request v=[%d, %d] cannot be met by any set point\n",
+ vreg->avs_rdesc.name, min_uV, max_uV);
+ return -EINVAL;
+ }
+
+ if (likely(!vreg->bypass_spm)) {
+ rc = msm_spm_avs_set_limit(vreg->cpu_num, vlevel_min,
+ vlevel_max);
+ if (rc) {
+ pr_err("%s: AVS limit setting failed, rc=%d\n",
+ vreg->avs_rdesc.name, rc);
+ return rc;
+ }
+ }
+
+ *selector = spm_regulator_vlevel_to_selector(vreg, vlevel_min);
+ vreg->avs_min_uV = avs_min_uV;
+ vreg->avs_max_uV = avs_max_uV;
+
+ return 0;
+}
+
+static int spm_regulator_avs_get_voltage(struct regulator_dev *rdev)
+{
+ struct spm_vreg *vreg = rdev_get_drvdata(rdev);
+
+ return vreg->avs_min_uV;
+}
+
+static int spm_regulator_avs_enable(struct regulator_dev *rdev)
+{
+ struct spm_vreg *vreg = rdev_get_drvdata(rdev);
+ int rc;
+
+ if (likely(!vreg->bypass_spm)) {
+ rc = msm_spm_avs_enable(vreg->cpu_num);
+ if (rc) {
+ pr_err("%s: AVS enable failed, rc=%d\n",
+ vreg->avs_rdesc.name, rc);
+ return rc;
+ }
+ }
+
+ vreg->avs_enabled = true;
+
+ return 0;
+}
+
+static int spm_regulator_avs_disable(struct regulator_dev *rdev)
+{
+ struct spm_vreg *vreg = rdev_get_drvdata(rdev);
+ int rc;
+
+ if (likely(!vreg->bypass_spm)) {
+ rc = msm_spm_avs_disable(vreg->cpu_num);
+ if (rc) {
+ pr_err("%s: AVS disable failed, rc=%d\n",
+ vreg->avs_rdesc.name, rc);
+ return rc;
+ }
+ }
+
+ vreg->avs_enabled = false;
+
+ return 0;
+}
+
+static int spm_regulator_avs_is_enabled(struct regulator_dev *rdev)
+{
+ struct spm_vreg *vreg = rdev_get_drvdata(rdev);
+
+ return vreg->avs_enabled;
+}
+
+static struct regulator_ops spm_regulator_avs_ops = {
+ .get_voltage = spm_regulator_avs_get_voltage,
+ .set_voltage = spm_regulator_avs_set_voltage,
+ .list_voltage = spm_regulator_list_voltage,
+ .enable = spm_regulator_avs_enable,
+ .disable = spm_regulator_avs_disable,
+ .is_enabled = spm_regulator_avs_is_enabled,
+};
+
+static int qpnp_smps_check_type(struct spm_vreg *vreg)
+{
+ int rc;
+ u8 type[2];
+
+ rc = regmap_bulk_read(vreg->regmap,
+ vreg->spmi_base_addr + QPNP_SMPS_REG_TYPE,
+ type,
+ 2);
+ if (rc) {
+ dev_err(&vreg->pdev->dev,
+ "%s: could not read type register, rc=%d\n",
+ __func__, rc);
+ return rc;
+ }
+
+ if (type[0] == QPNP_FTS2_TYPE && type[1] == QPNP_FTS2_SUBTYPE) {
+ vreg->regulator_type = QPNP_TYPE_FTS2;
+ } else if (type[0] == QPNP_FTS2p5_TYPE
+ && type[1] == QPNP_FTS2p5_SUBTYPE) {
+ vreg->regulator_type = QPNP_TYPE_FTS2p5;
+ } else if (type[0] == QPNP_FTS426_TYPE
+ && type[1] == QPNP_FTS426_SUBTYPE) {
+ vreg->regulator_type = QPNP_TYPE_FTS426;
+ } else if (type[0] == QPNP_ULT_HF_TYPE
+ && type[1] == QPNP_ULT_HF_SUBTYPE) {
+ vreg->regulator_type = QPNP_TYPE_ULT_HF;
+ } else if (type[0] == QPNP_HF_TYPE
+ && type[1] == QPNP_HF_SUBTYPE) {
+ vreg->regulator_type = QPNP_TYPE_HF;
+ } else {
+ dev_err(&vreg->pdev->dev,
+ "%s: invalid type=0x%02X, subtype=0x%02X register pair\n",
+ __func__, type[0], type[1]);
+ return -ENODEV;
+ };
+
+ return rc;
+}
+
+static int qpnp_smps_init_range(struct spm_vreg *vreg,
+ const struct voltage_range *range0, const struct voltage_range *range1)
+{
+ int rc;
+ u8 reg = 0;
+ uint val;
+
+ rc = regmap_read(vreg->regmap,
+ vreg->spmi_base_addr + QPNP_SMPS_REG_VOLTAGE_RANGE,
+ &val);
+ if (rc) {
+ dev_err(&vreg->pdev->dev,
+ "%s: could not read voltage range register, rc=%d\n",
+ __func__, rc);
+ return rc;
+ }
+ reg = (u8)val;
+
+ if (reg == 0x00) {
+ vreg->range = range0;
+ } else if (reg == 0x01) {
+ vreg->range = range1;
+ } else {
+ dev_err(&vreg->pdev->dev, "%s: voltage range=%d is invalid\n",
+ __func__, reg);
+ rc = -EINVAL;
+ }
+
+ return rc;
+}
+
+static int qpnp_ult_hf_init_range(struct spm_vreg *vreg)
+{
+ int rc;
+ u8 reg = 0;
+ uint val;
+
+ rc = regmap_read(vreg->regmap,
+ vreg->spmi_base_addr + QPNP_SMPS_REG_VOLTAGE_SETPOINT,
+ &val);
+ if (rc) {
+ dev_err(&vreg->pdev->dev,
+ "%s: could not read voltage range register, rc=%d\n",
+ __func__, rc);
+ return rc;
+ }
+ reg = (u8)val;
+
+ vreg->range = (reg < ULT_SMPS_RANGE_SPLIT) ? &ult_hf_range0 :
+ &ult_hf_range1;
+ return rc;
+}
+
+static int qpnp_smps_init_voltage(struct spm_vreg *vreg)
+{
+ int rc;
+
+ rc = qpnp_smps_read_voltage(vreg);
+ if (rc) {
+ pr_err("%s: voltage read failed, rc=%d\n", vreg->rdesc.name,
+ rc);
+ return rc;
+ }
+
+ vreg->vlevel = vreg->last_set_vlevel;
+ vreg->uV = vreg->last_set_uV;
+
+ /* Initialize SAW voltage control register */
+ if (!vreg->bypass_spm) {
+ rc = msm_spm_set_vdd(vreg->cpu_num, vreg->vlevel);
+ if (rc)
+ pr_err("%s: msm_spm_set_vdd failed, rc=%d\n",
+ vreg->rdesc.name, rc);
+ }
+
+ return 0;
+}
+
+static int qpnp_smps_init_mode(struct spm_vreg *vreg)
+{
+ const char *mode_name;
+ int rc;
+ uint val;
+
+ rc = of_property_read_string(vreg->pdev->dev.of_node, "qcom,mode",
+ &mode_name);
+ if (!rc) {
+ if (strcmp("pwm", mode_name) == 0) {
+ vreg->init_mode = QPNP_LOGICAL_MODE_PWM;
+ } else if ((strcmp("auto", mode_name) == 0) &&
+ (vreg->regulator_type != QPNP_TYPE_ULT_HF)) {
+ vreg->init_mode = QPNP_LOGICAL_MODE_AUTO;
+ } else {
+ dev_err(&vreg->pdev->dev,
+ "%s: unknown regulator mode: %s\n",
+ __func__, mode_name);
+ return -EINVAL;
+ }
+
+ rc = qpnp_smps_set_mode(vreg, vreg->init_mode);
+ if (rc)
+ return rc;
+ } else {
+ rc = regmap_read(vreg->regmap,
+ vreg->spmi_base_addr + QPNP_SMPS_REG_MODE,
+ &val);
+ if (rc)
+ dev_err(&vreg->pdev->dev,
+ "%s: could not read mode register, rc=%d\n",
+ __func__, rc);
+ vreg->init_mode = qpnp_regval_to_mode(vreg, val);
+ }
+
+ vreg->mode = vreg->init_mode;
+
+ return rc;
+}
+
+static int qpnp_smps_init_step_rate(struct spm_vreg *vreg)
+{
+ int rc;
+ u8 reg = 0;
+ int step = 0, delay;
+ uint val;
+
+ rc = regmap_read(vreg->regmap,
+ vreg->spmi_base_addr + QPNP_SMPS_REG_STEP_CTRL, &val);
+ if (rc) {
+ dev_err(&vreg->pdev->dev,
+ "%s: could not read stepping control register, rc=%d\n",
+ __func__, rc);
+ return rc;
+ }
+ reg = (u8)val;
+
+ /* ULT and FTS426 bucks do not support steps */
+ if (vreg->regulator_type != QPNP_TYPE_ULT_HF && vreg->regulator_type !=
+ QPNP_TYPE_FTS426)
+ step = (reg & QPNP_SMPS_STEP_CTRL_STEP_MASK)
+ >> QPNP_SMPS_STEP_CTRL_STEP_SHIFT;
+
+ if (vreg->regulator_type == QPNP_TYPE_FTS426) {
+ delay = (reg & QPNP_FTS426_STEP_CTRL_DELAY_MASK)
+ >> QPNP_FTS426_STEP_CTRL_DELAY_SHIFT;
+
+ /* step_rate has units of uV/us. */
+ vreg->step_rate = QPNP_FTS426_CLOCK_RATE * vreg->range->step_uV;
+ } else {
+ delay = (reg & QPNP_SMPS_STEP_CTRL_DELAY_MASK)
+ >> QPNP_SMPS_STEP_CTRL_DELAY_SHIFT;
+
+ /* step_rate has units of uV/us. */
+ vreg->step_rate = QPNP_SMPS_CLOCK_RATE * vreg->range->step_uV
+ * (1 << step);
+ }
+
+ if ((vreg->regulator_type == QPNP_TYPE_ULT_HF)
+ || (vreg->regulator_type == QPNP_TYPE_HF))
+ vreg->step_rate /= 1000 * (QPNP_HF_STEP_DELAY << delay);
+ else if (vreg->regulator_type == QPNP_TYPE_FTS426)
+ vreg->step_rate /= 1000 * (QPNP_FTS426_STEP_DELAY << delay);
+ else
+ vreg->step_rate /= 1000 * (QPNP_FTS2_STEP_DELAY << delay);
+
+ if (vreg->regulator_type == QPNP_TYPE_FTS426)
+ vreg->step_rate = vreg->step_rate * QPNP_FTS426_STEP_MARGIN_NUM
+ / QPNP_FTS426_STEP_MARGIN_DEN;
+ else
+ vreg->step_rate = vreg->step_rate * QPNP_FTS2_STEP_MARGIN_NUM
+ / QPNP_FTS2_STEP_MARGIN_DEN;
+
+ /* Ensure that the stepping rate is greater than 0. */
+ vreg->step_rate = max(vreg->step_rate, 1);
+
+ return rc;
+}
+
+static int qpnp_smps_check_constraints(struct spm_vreg *vreg,
+ struct regulator_init_data *init_data)
+{
+ int rc = 0, limit_min_uV, limit_max_uV;
+ u16 ul_reg, ll_reg;
+ u8 reg[2];
+
+ limit_min_uV = 0;
+ limit_max_uV = INT_MAX;
+
+ ul_reg = QPNP_FTS_REG_VOLTAGE_ULS_VALID;
+ ll_reg = QPNP_FTS_REG_VOLTAGE_LLS_VALID;
+
+ switch (vreg->regulator_type) {
+ case QPNP_TYPE_HF:
+ ul_reg = QPNP_HF_REG_VOLTAGE_ULS;
+ ll_reg = QPNP_HF_REG_VOLTAGE_LLS;
+ case QPNP_TYPE_FTS2:
+ case QPNP_TYPE_FTS2p5:
+ rc = regmap_bulk_read(vreg->regmap, vreg->spmi_base_addr
+ + QPNP_SMPS_REG_UL_LL_CTRL, reg, 1);
+ if (rc) {
+ dev_err(&vreg->pdev->dev, "%s: UL_LL register read failed, rc=%d\n",
+ __func__, rc);
+ return rc;
+ }
+
+ if (reg[0] & QPNP_COMMON_UL_EN_MASK) {
+ rc = regmap_bulk_read(vreg->regmap, vreg->spmi_base_addr
+ + ul_reg, ®[1], 1);
+ if (rc) {
+ dev_err(&vreg->pdev->dev, "%s: ULS register read failed, rc=%d\n",
+ __func__, rc);
+ return rc;
+ }
+
+ limit_max_uV = spm_regulator_vlevel_to_uv(vreg, reg[1]);
+ }
+
+ if (reg[0] & QPNP_COMMON_LL_EN_MASK) {
+ rc = regmap_bulk_read(vreg->regmap, vreg->spmi_base_addr
+ + ll_reg, ®[1], 1);
+ if (rc) {
+ dev_err(&vreg->pdev->dev, "%s: LLS register read failed, rc=%d\n",
+ __func__, rc);
+ return rc;
+ }
+
+ limit_min_uV = spm_regulator_vlevel_to_uv(vreg, reg[1]);
+ }
+
+ break;
+ case QPNP_TYPE_FTS426:
+ rc = regmap_bulk_read(vreg->regmap, vreg->spmi_base_addr
+ + QPNP_FTS426_REG_VOLTAGE_ULS_LB,
+ reg, 2);
+ if (rc) {
+ dev_err(&vreg->pdev->dev, "%s: could not read voltage limit registers, rc=%d\n",
+ __func__, rc);
+ return rc;
+ }
+
+ limit_max_uV = spm_regulator_vlevel_to_uv(vreg,
+ ((unsigned)reg[1] << 8) | reg[0]);
+ break;
+ case QPNP_TYPE_ULT_HF:
+ /* no HW voltage limit configuration */
+ break;
+ }
+
+ if (init_data->constraints.min_uV < limit_min_uV
+ || init_data->constraints.max_uV > limit_max_uV) {
+ dev_err(&vreg->pdev->dev, "regulator min/max(%d/%d) constraints do not fit within HW configured min/max(%d/%d) constraints\n",
+ init_data->constraints.min_uV,
+ init_data->constraints.max_uV, limit_min_uV,
+ limit_max_uV);
+ return -EINVAL;
+ }
+
+ return rc;
+}
+
+static bool spm_regulator_using_range0(struct spm_vreg *vreg)
+{
+ return vreg->range == &fts2_range0 || vreg->range == &fts2p5_range0
+ || vreg->range == &ult_hf_range0 || vreg->range == &hf_range0
+ || vreg->range == &fts426_range;
+}
+
+/* Register a regulator to enable/disable AVS and set AVS min/max limits. */
+static int spm_regulator_avs_register(struct spm_vreg *vreg,
+ struct device *dev, struct device_node *node)
+{
+ struct regulator_config reg_config = {};
+ struct device_node *avs_node = NULL;
+ struct device_node *child_node;
+ struct regulator_init_data *init_data;
+ int rc;
+
+ /*
+ * Find the first available child node (if any). It corresponds to an
+ * AVS limits regulator.
+ */
+ for_each_available_child_of_node(node, child_node) {
+ avs_node = child_node;
+ break;
+ }
+
+ if (!avs_node)
+ return 0;
+
+ init_data = of_get_regulator_init_data(dev, avs_node, &vreg->avs_rdesc);
+ if (!init_data) {
+ dev_err(dev, "%s: unable to allocate memory\n", __func__);
+ return -ENOMEM;
+ }
+ init_data->constraints.input_uV = init_data->constraints.max_uV;
+ init_data->constraints.valid_ops_mask |= REGULATOR_CHANGE_STATUS
+ | REGULATOR_CHANGE_VOLTAGE;
+
+ if (!init_data->constraints.name) {
+ dev_err(dev, "%s: AVS node is missing regulator name\n",
+ __func__);
+ return -EINVAL;
+ }
+
+ vreg->avs_rdesc.name = init_data->constraints.name;
+ vreg->avs_rdesc.type = REGULATOR_VOLTAGE;
+ vreg->avs_rdesc.owner = THIS_MODULE;
+ vreg->avs_rdesc.ops = &spm_regulator_avs_ops;
+ vreg->avs_rdesc.n_voltages
+ = (vreg->range->max_uV - vreg->range->set_point_min_uV)
+ / vreg->range->step_uV + 1;
+
+ reg_config.dev = dev;
+ reg_config.init_data = init_data;
+ reg_config.driver_data = vreg;
+ reg_config.of_node = avs_node;
+
+ vreg->avs_rdev = regulator_register(&vreg->avs_rdesc, ®_config);
+ if (IS_ERR(vreg->avs_rdev)) {
+ rc = PTR_ERR(vreg->avs_rdev);
+ dev_err(dev, "%s: AVS regulator_register failed, rc=%d\n",
+ __func__, rc);
+ return rc;
+ }
+
+ if (vreg->bypass_spm)
+ pr_debug("%s: SPM bypassed so AVS regulator calls are no-ops\n",
+ vreg->avs_rdesc.name);
+
+ return 0;
+}
+
+static int spm_regulator_probe(struct platform_device *pdev)
+{
+ struct regulator_config reg_config = {};
+ struct device_node *node = pdev->dev.of_node;
+ struct regulator_init_data *init_data;
+ struct spm_vreg *vreg;
+ unsigned int base;
+ bool bypass_spm;
+ int rc;
+
+ if (!node) {
+ dev_err(&pdev->dev, "%s: device node missing\n", __func__);
+ return -ENODEV;
+ }
+
+ bypass_spm = of_property_read_bool(node, "qcom,bypass-spm");
+ if (!bypass_spm) {
+ rc = msm_spm_probe_done();
+ if (rc) {
+ if (rc != -EPROBE_DEFER)
+ dev_err(&pdev->dev,
+ "%s: spm unavailable, rc=%d\n",
+ __func__, rc);
+ return rc;
+ }
+ }
+
+ vreg = devm_kzalloc(&pdev->dev, sizeof(*vreg), GFP_KERNEL);
+ if (!vreg) {
+ pr_err("allocation failed.\n");
+ return -ENOMEM;
+ }
+ vreg->regmap = dev_get_regmap(pdev->dev.parent, NULL);
+ if (!vreg->regmap) {
+ dev_err(&pdev->dev, "Couldn't get parent's regmap\n");
+ return -EINVAL;
+ }
+ vreg->pdev = pdev;
+ vreg->bypass_spm = bypass_spm;
+
+ rc = of_property_read_u32(pdev->dev.of_node, "reg", &base);
+ if (rc < 0) {
+ dev_err(&pdev->dev,
+ "Couldn't find reg in node = %s rc = %d\n",
+ pdev->dev.of_node->full_name, rc);
+ return rc;
+ }
+ vreg->spmi_base_addr = base;
+
+ rc = qpnp_smps_check_type(vreg);
+ if (rc)
+ return rc;
+
+ /* Specify CPU 0 as default in order to handle shared regulator case. */
+ vreg->cpu_num = 0;
+ of_property_read_u32(vreg->pdev->dev.of_node, "qcom,cpu-num",
+ &vreg->cpu_num);
+
+ of_property_read_u32(vreg->pdev->dev.of_node, "qcom,recal-mask",
+ &vreg->recal_cluster_mask);
+
+ /*
+ * The regulator must be initialized to range 0 or range 1 during
+ * PMIC power on sequence. Once it is set, it cannot be changed
+ * dynamically.
+ */
+ if (vreg->regulator_type == QPNP_TYPE_FTS2)
+ rc = qpnp_smps_init_range(vreg, &fts2_range0, &fts2_range1);
+ else if (vreg->regulator_type == QPNP_TYPE_FTS2p5)
+ rc = qpnp_smps_init_range(vreg, &fts2p5_range0, &fts2p5_range1);
+ else if (vreg->regulator_type == QPNP_TYPE_FTS426)
+ vreg->range = &fts426_range;
+ else if (vreg->regulator_type == QPNP_TYPE_HF)
+ rc = qpnp_smps_init_range(vreg, &hf_range0, &hf_range1);
+ else if (vreg->regulator_type == QPNP_TYPE_ULT_HF)
+ rc = qpnp_ult_hf_init_range(vreg);
+ if (rc)
+ return rc;
+
+ rc = qpnp_smps_init_voltage(vreg);
+ if (rc)
+ return rc;
+
+ rc = qpnp_smps_init_mode(vreg);
+ if (rc)
+ return rc;
+
+ rc = qpnp_smps_init_step_rate(vreg);
+ if (rc)
+ return rc;
+
+ init_data = of_get_regulator_init_data(&pdev->dev, node, &vreg->rdesc);
+ if (!init_data) {
+ dev_err(&pdev->dev, "%s: unable to allocate memory\n",
+ __func__);
+ return -ENOMEM;
+ }
+ init_data->constraints.input_uV = init_data->constraints.max_uV;
+ init_data->constraints.valid_ops_mask |= REGULATOR_CHANGE_STATUS
+ | REGULATOR_CHANGE_VOLTAGE | REGULATOR_CHANGE_MODE;
+ init_data->constraints.valid_modes_mask
+ = REGULATOR_MODE_NORMAL | REGULATOR_MODE_IDLE;
+
+ if (!init_data->constraints.name) {
+ dev_err(&pdev->dev, "%s: node is missing regulator name\n",
+ __func__);
+ return -EINVAL;
+ }
+
+ rc = qpnp_smps_check_constraints(vreg, init_data);
+ if (rc) {
+ dev_err(&pdev->dev, "%s: regulator constraints check failed, rc=%d\n",
+ __func__, rc);
+ return rc;
+ }
+
+ vreg->rdesc.name = init_data->constraints.name;
+ vreg->rdesc.type = REGULATOR_VOLTAGE;
+ vreg->rdesc.owner = THIS_MODULE;
+ vreg->rdesc.ops = &spm_regulator_ops;
+ vreg->rdesc.n_voltages
+ = (vreg->range->max_uV - vreg->range->set_point_min_uV)
+ / vreg->range->step_uV + 1;
+
+ vreg->max_step_uV = SPM_REGULATOR_MAX_STEP_UV;
+ of_property_read_u32(vreg->pdev->dev.of_node,
+ "qcom,max-voltage-step", &vreg->max_step_uV);
+
+ if (vreg->max_step_uV > SPM_REGULATOR_MAX_STEP_UV)
+ vreg->max_step_uV = SPM_REGULATOR_MAX_STEP_UV;
+
+ vreg->max_step_uV = rounddown(vreg->max_step_uV, vreg->range->step_uV);
+ pr_debug("%s: max single voltage step size=%u uV\n",
+ vreg->rdesc.name, vreg->max_step_uV);
+
+ reg_config.dev = &pdev->dev;
+ reg_config.init_data = init_data;
+ reg_config.driver_data = vreg;
+ reg_config.of_node = node;
+ vreg->rdev = regulator_register(&vreg->rdesc, ®_config);
+
+ if (IS_ERR(vreg->rdev)) {
+ rc = PTR_ERR(vreg->rdev);
+ dev_err(&pdev->dev, "%s: regulator_register failed, rc=%d\n",
+ __func__, rc);
+ return rc;
+ }
+
+ rc = spm_regulator_avs_register(vreg, &pdev->dev, node);
+ if (rc) {
+ regulator_unregister(vreg->rdev);
+ return rc;
+ }
+
+ dev_set_drvdata(&pdev->dev, vreg);
+
+ pr_info("name=%s, range=%s, voltage=%d uV, mode=%s, step rate=%d uV/us\n",
+ vreg->rdesc.name,
+ spm_regulator_using_range0(vreg) ? "LV" : "MV",
+ vreg->uV,
+ vreg->init_mode == QPNP_LOGICAL_MODE_PWM ? "PWM" :
+ (vreg->init_mode == QPNP_LOGICAL_MODE_AUTO ? "AUTO" : "PFM"),
+ vreg->step_rate);
+
+ return rc;
+}
+
+static int spm_regulator_remove(struct platform_device *pdev)
+{
+ struct spm_vreg *vreg = dev_get_drvdata(&pdev->dev);
+
+ if (vreg->avs_rdev)
+ regulator_unregister(vreg->avs_rdev);
+ regulator_unregister(vreg->rdev);
+
+ return 0;
+}
+
+static struct of_device_id spm_regulator_match_table[] = {
+ { .compatible = SPM_REGULATOR_DRIVER_NAME, },
+ {}
+};
+
+static const struct platform_device_id spm_regulator_id[] = {
+ { SPM_REGULATOR_DRIVER_NAME, 0 },
+ {}
+};
+MODULE_DEVICE_TABLE(spmi, spm_regulator_id);
+
+static struct platform_driver spm_regulator_driver = {
+ .driver = {
+ .name = SPM_REGULATOR_DRIVER_NAME,
+ .of_match_table = spm_regulator_match_table,
+ .owner = THIS_MODULE,
+ },
+ .probe = spm_regulator_probe,
+ .remove = spm_regulator_remove,
+ .id_table = spm_regulator_id,
+};
+
+/**
+ * spm_regulator_init() - register spmi driver for spm-regulator
+ *
+ * This initialization function should be called in systems in which driver
+ * registration ordering must be controlled precisely.
+ *
+ * Returns 0 on success or errno on failure.
+ */
+int __init spm_regulator_init(void)
+{
+ static bool has_registered;
+
+ if (has_registered)
+ return 0;
+ else
+ has_registered = true;
+
+ return platform_driver_register(&spm_regulator_driver);
+}
+EXPORT_SYMBOL(spm_regulator_init);
+
+static void __exit spm_regulator_exit(void)
+{
+ platform_driver_unregister(&spm_regulator_driver);
+}
+
+arch_initcall(spm_regulator_init);
+module_exit(spm_regulator_exit);
+
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("SPM regulator driver");
+MODULE_ALIAS("platform:spm-regulator");
diff --git a/drivers/scsi/ufs/ufs-qcom-ice.c b/drivers/scsi/ufs/ufs-qcom-ice.c
index 84765b1..d288e83 100644
--- a/drivers/scsi/ufs/ufs-qcom-ice.c
+++ b/drivers/scsi/ufs/ufs-qcom-ice.c
@@ -27,6 +27,8 @@
#define UFS_QCOM_ICE_DEFAULT_DBG_PRINT_EN 0
+static struct workqueue_struct *ice_workqueue;
+
static void ufs_qcom_ice_dump_regs(struct ufs_qcom_host *qcom_host, int offset,
int len, char *prefix)
{
@@ -224,6 +226,13 @@
}
qcom_host->dbg_print_en |= UFS_QCOM_ICE_DEFAULT_DBG_PRINT_EN;
+ ice_workqueue = alloc_workqueue("ice-set-key",
+ WQ_MEM_RECLAIM | WQ_HIGHPRI, 0);
+ if (!ice_workqueue) {
+ dev_err(ufs_dev, "%s: workqueue allocation failed.\n",
+ __func__);
+ goto out;
+ }
INIT_WORK(&qcom_host->ice_cfg_work, ufs_qcom_ice_cfg_work);
out:
@@ -284,7 +293,7 @@
if (!qcom_host->work_pending) {
qcom_host->req_pending = cmd->request;
- if (!schedule_work(
+ if (!queue_work(ice_workqueue,
&qcom_host->ice_cfg_work)) {
qcom_host->req_pending = NULL;
@@ -404,7 +413,7 @@
if (!qcom_host->work_pending) {
qcom_host->req_pending = cmd->request;
- if (!schedule_work(
+ if (!queue_work(ice_workqueue,
&qcom_host->ice_cfg_work)) {
qcom_host->req_pending = NULL;
diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
index a6bc1da..8060142 100644
--- a/drivers/scsi/ufs/ufshcd.c
+++ b/drivers/scsi/ufs/ufshcd.c
@@ -6146,7 +6146,7 @@
out:
ufshcd_scsi_unblock_requests(hba);
- pm_runtime_put_sync(hba->dev);
+ pm_runtime_put(hba->dev);
return;
}
diff --git a/drivers/soc/qcom/glink_smem_native_xprt.c b/drivers/soc/qcom/glink_smem_native_xprt.c
index ea7374f..187c80d 100644
--- a/drivers/soc/qcom/glink_smem_native_xprt.c
+++ b/drivers/soc/qcom/glink_smem_native_xprt.c
@@ -557,6 +557,12 @@
len = fifo_write_body(einfo, data, len, &write_index);
if (unlikely(len < 0))
return len;
+
+ /* All data writes need to be flushed to memory before the write index
+ * is updated. This protects against a race condition where the remote
+ * reads stale data because the write index was written before the data.
+ */
+ wmb();
einfo->tx_ch_desc->write_index = write_index;
send_irq(einfo);
@@ -599,6 +605,11 @@
if (unlikely(len3 < 0))
return len3;
+ /* All data writes need to be flushed to memory before the write index
+ * is updated. This protects against a race condition where the remote
+ * reads stale data because the write index was written before the data.
+ */
+ wmb();
einfo->tx_ch_desc->write_index = write_index;
send_irq(einfo);
diff --git a/drivers/soc/qcom/llcc-slice.c b/drivers/soc/qcom/llcc-slice.c
index 5dd49e8..8a835f5 100644
--- a/drivers/soc/qcom/llcc-slice.c
+++ b/drivers/soc/qcom/llcc-slice.c
@@ -80,6 +80,7 @@
const struct llcc_slice_config *llcc_data_ptr;
struct llcc_slice_desc *desc;
struct platform_device *pdev;
+ u32 sz, count;
if (of_parse_phandle_with_args(dev->of_node, "cache-slices",
"#cache-cells", n, &phargs)) {
@@ -100,14 +101,17 @@
}
llcc_data_ptr = drv->slice_data;
+ sz = drv->llcc_config_data_sz;
+ count = 0;
- while (llcc_data_ptr) {
+ while (llcc_data_ptr && count < sz) {
if (llcc_data_ptr->usecase_id == phargs.args[0])
break;
llcc_data_ptr++;
+ count++;
}
- if (llcc_data_ptr == NULL) {
+ if (llcc_data_ptr == NULL || count == sz) {
pr_err("can't find %d usecase id\n", phargs.args[0]);
return ERR_PTR(-ENODEV);
}
diff --git a/drivers/soc/qcom/peripheral-loader.c b/drivers/soc/qcom/peripheral-loader.c
index 9d22925..0efd287 100644
--- a/drivers/soc/qcom/peripheral-loader.c
+++ b/drivers/soc/qcom/peripheral-loader.c
@@ -511,11 +511,12 @@
}
static int pil_alloc_region(struct pil_priv *priv, phys_addr_t min_addr,
- phys_addr_t max_addr, size_t align)
+ phys_addr_t max_addr, size_t align,
+ size_t mdt_size)
{
void *region;
size_t size = max_addr - min_addr;
- size_t aligned_size;
+ size_t aligned_size = max(size, mdt_size);
/* Don't reallocate due to fragmentation concerns, just sanity check */
if (priv->region) {
@@ -526,9 +527,11 @@
}
if (align > SZ_4M)
- aligned_size = ALIGN(size, SZ_4M);
+ aligned_size = ALIGN(aligned_size, SZ_4M);
+ else if (align > SZ_1M)
+ aligned_size = ALIGN(aligned_size, SZ_1M);
else
- aligned_size = ALIGN(size, SZ_1M);
+ aligned_size = ALIGN(aligned_size, SZ_4K);
priv->desc->attrs = 0;
priv->desc->attrs |= DMA_ATTR_SKIP_ZEROING | DMA_ATTR_NO_KERNEL_MAPPING;
@@ -553,7 +556,8 @@
return 0;
}
-static int pil_setup_region(struct pil_priv *priv, const struct pil_mdt *mdt)
+static int pil_setup_region(struct pil_priv *priv, const struct pil_mdt *mdt,
+ size_t mdt_size)
{
const struct elf32_phdr *phdr;
phys_addr_t min_addr_r, min_addr_n, max_addr_r, max_addr_n, start, end;
@@ -598,7 +602,8 @@
max_addr_r = ALIGN(max_addr_r, SZ_4K);
if (relocatable) {
- ret = pil_alloc_region(priv, min_addr_r, max_addr_r, align);
+ ret = pil_alloc_region(priv, min_addr_r, max_addr_r, align,
+ mdt_size);
} else {
priv->region_start = min_addr_n;
priv->region_end = max_addr_n;
@@ -629,14 +634,15 @@
return ret;
}
-static int pil_init_mmap(struct pil_desc *desc, const struct pil_mdt *mdt)
+static int pil_init_mmap(struct pil_desc *desc, const struct pil_mdt *mdt,
+ size_t mdt_size)
{
struct pil_priv *priv = desc->priv;
const struct elf32_phdr *phdr;
struct pil_seg *seg;
int i, ret;
- ret = pil_setup_region(priv, mdt);
+ ret = pil_setup_region(priv, mdt, mdt_size);
if (ret)
return ret;
@@ -702,6 +708,12 @@
/* Clear memory so that unauthorized ELF code is not left behind */
buf = desc->map_fw_mem(priv->region_start, (priv->region_end -
priv->region_start), map_data);
+
+ if (!buf) {
+ pil_err(desc, "Failed to map memory\n");
+ return;
+ }
+
pil_memset_io(buf, 0, (priv->region_end - priv->region_start));
desc->unmap_fw_mem(buf, (priv->region_end - priv->region_start),
map_data);
@@ -922,7 +934,7 @@
goto release_fw;
}
- ret = pil_init_mmap(desc, mdt);
+ ret = pil_init_mmap(desc, mdt, fw->size);
if (ret)
goto release_fw;
@@ -935,7 +947,8 @@
trace_pil_event("before_init_image", desc);
if (desc->ops->init_image)
- ret = desc->ops->init_image(desc, fw->data, fw->size);
+ ret = desc->ops->init_image(desc, fw->data, fw->size,
+ priv->region_start, priv->region);
if (ret) {
pil_err(desc, "Initializing image failed(rc:%d)\n", ret);
goto err_boot;
diff --git a/drivers/soc/qcom/peripheral-loader.h b/drivers/soc/qcom/peripheral-loader.h
index f09adf5..27ed336 100644
--- a/drivers/soc/qcom/peripheral-loader.h
+++ b/drivers/soc/qcom/peripheral-loader.h
@@ -119,7 +119,7 @@
*/
struct pil_reset_ops {
int (*init_image)(struct pil_desc *pil, const u8 *metadata,
- size_t size);
+ size_t size, phys_addr_t mdata_phys, void *region);
int (*mem_setup)(struct pil_desc *pil, phys_addr_t addr, size_t size);
int (*verify_blob)(struct pil_desc *pil, phys_addr_t phy_addr,
size_t size);
diff --git a/drivers/soc/qcom/pil-msa.c b/drivers/soc/qcom/pil-msa.c
index a3eb551..ce31d66 100644
--- a/drivers/soc/qcom/pil-msa.c
+++ b/drivers/soc/qcom/pil-msa.c
@@ -769,7 +769,8 @@
}
static int pil_msa_auth_modem_mdt(struct pil_desc *pil, const u8 *metadata,
- size_t size)
+ size_t size, phys_addr_t region_start,
+ void *region)
{
struct modem_data *drv = dev_get_drvdata(pil->dev);
void *mdata_virt;
@@ -851,7 +852,8 @@
}
static int pil_msa_mss_reset_mba_load_auth_mdt(struct pil_desc *pil,
- const u8 *metadata, size_t size)
+ const u8 *metadata, size_t size,
+ phys_addr_t region_start, void *region)
{
int ret;
@@ -859,7 +861,8 @@
if (ret)
return ret;
- return pil_msa_auth_modem_mdt(pil, metadata, size);
+ return pil_msa_auth_modem_mdt(pil, metadata, size, region_start,
+ region);
}
static int pil_msa_mba_verify_blob(struct pil_desc *pil, phys_addr_t phy_addr,
diff --git a/drivers/soc/qcom/pil-q6v5-mss.c b/drivers/soc/qcom/pil-q6v5-mss.c
index 2ca0615..728a68c 100644
--- a/drivers/soc/qcom/pil-q6v5-mss.c
+++ b/drivers/soc/qcom/pil-q6v5-mss.c
@@ -60,9 +60,6 @@
strlcpy(reason, smem_reason, min(size, MAX_SSR_REASON_LEN));
pr_err("modem subsystem failure reason: %s.\n", reason);
-
- smem_reason[0] = '\0';
- wmb();
}
static void restart_modem(struct modem_data *drv)
diff --git a/drivers/soc/qcom/qbt1000.c b/drivers/soc/qcom/qbt1000.c
index 86f314a..b7472a4 100644
--- a/drivers/soc/qcom/qbt1000.c
+++ b/drivers/soc/qcom/qbt1000.c
@@ -471,7 +471,7 @@
case QBT1000_SEND_TZCMD:
{
struct qbt1000_send_tz_cmd tzcmd;
- void *rsp_buf;
+ void *rsp_buf = NULL;
if (copy_from_user(&tzcmd, priv_arg,
sizeof(tzcmd))
@@ -861,8 +861,8 @@
static irqreturn_t qbt1000_ipc_irq_handler(int irq, void *dev_id)
{
uint8_t *msg_buffer;
- struct fw_ipc_cmd *rx_cmd;
- struct fw_ipc_header *header;
+ struct fw_ipc_cmd *rx_cmd = NULL;
+ struct fw_ipc_header *header = NULL;
int i, j;
uint32_t rxipc = FP_APP_CMD_RX_IPC;
struct qbt1000_drvdata *drvdata = (struct qbt1000_drvdata *)dev_id;
diff --git a/drivers/soc/qcom/service-notifier.c b/drivers/soc/qcom/service-notifier.c
index f4c67f1..dc45b20 100644
--- a/drivers/soc/qcom/service-notifier.c
+++ b/drivers/soc/qcom/service-notifier.c
@@ -105,6 +105,7 @@
struct work_struct ind_ack;
struct work_struct qmi_handle_free;
struct workqueue_struct *svc_event_wq;
+ struct rw_semaphore qmi_client_handle_rwlock;
struct qmi_handle *clnt_handle;
struct notifier_block notifier;
void *ssr_handle;
@@ -115,7 +116,6 @@
};
static LIST_HEAD(qmi_client_list);
static DEFINE_MUTEX(qmi_list_lock);
-static DEFINE_MUTEX(qmi_client_release_lock);
static DEFINE_MUTEX(notif_add_lock);
@@ -128,11 +128,11 @@
struct qmi_client_info *data = container_of(work,
struct qmi_client_info, qmi_handle_free);
- mutex_lock(&qmi_client_release_lock);
+ down_write(&data->qmi_client_handle_rwlock);
data->service_connected = false;
qmi_handle_destroy(data->clnt_handle);
data->clnt_handle = NULL;
- mutex_unlock(&qmi_client_release_lock);
+ up_write(&data->qmi_client_handle_rwlock);
}
static struct service_notif_info *_find_service_info(const char *service_path)
@@ -170,10 +170,12 @@
struct qmi_client_info *data = container_of(work,
struct qmi_client_info, svc_rcv_msg);
+ down_read(&data->qmi_client_handle_rwlock);
do {
pr_debug("Polling for QMI recv msg(instance-id: %d)\n",
data->instance_id);
} while ((ret = qmi_recv_msg(data->clnt_handle)) == 0);
+ up_read(&data->qmi_client_handle_rwlock);
pr_debug("Notified about a Receive event (instance-id: %d)\n",
data->instance_id);
@@ -237,9 +239,11 @@
resp_desc.max_msg_len = SERVREG_NOTIF_SET_ACK_RESP_MSG_LEN;
resp_desc.ei_array = qmi_servreg_notif_set_ack_resp_msg_v01_ei;
+ down_read(&data->qmi_client_handle_rwlock);
rc = qmi_send_req_wait(data->clnt_handle, &req_desc,
&req, sizeof(req), &resp_desc, &resp,
sizeof(resp), SERVER_TIMEOUT);
+ up_read(&data->qmi_client_handle_rwlock);
if (rc < 0) {
pr_err("%s: Sending Ack failed/server timeout, ret - %d\n",
data->ind_msg.service_path, rc);
@@ -308,9 +312,11 @@
resp_desc.ei_array =
qmi_servreg_notif_register_listener_resp_msg_v01_ei;
+ down_read(&data->qmi_client_handle_rwlock);
rc = qmi_send_req_wait(data->clnt_handle, &req_desc, &req, sizeof(req),
&resp_desc, &resp, sizeof(resp),
SERVER_TIMEOUT);
+ up_read(&data->qmi_client_handle_rwlock);
if (rc < 0) {
pr_err("%s: Message sending failed/server timeout, ret - %d\n",
service_notif->service_path, rc);
@@ -349,13 +355,13 @@
int rc;
int curr_state;
- mutex_lock(&qmi_client_release_lock);
+ down_read(&data->qmi_client_handle_rwlock);
/* Create a Local client port for QMI communication */
data->clnt_handle = qmi_handle_create(root_service_clnt_notify, work);
if (!data->clnt_handle) {
pr_err("QMI client handle alloc failed (instance-id: %d)\n",
data->instance_id);
- mutex_unlock(&qmi_client_release_lock);
+ up_read(&data->qmi_client_handle_rwlock);
return;
}
@@ -368,11 +374,11 @@
data->instance_id, rc);
qmi_handle_destroy(data->clnt_handle);
data->clnt_handle = NULL;
- mutex_unlock(&qmi_client_release_lock);
+ up_read(&data->qmi_client_handle_rwlock);
return;
}
data->service_connected = true;
- mutex_unlock(&qmi_client_release_lock);
+ up_read(&data->qmi_client_handle_rwlock);
pr_info("Connection established between QMI handle and %d service\n",
data->instance_id);
/* Register for indication messages about service */
@@ -554,6 +560,7 @@
}
qmi_data->instance_id = instance_id;
+ init_rwsem(&qmi_data->qmi_client_handle_rwlock);
qmi_data->clnt_handle = NULL;
qmi_data->notifier.notifier_call = service_event_notify;
diff --git a/drivers/soc/qcom/subsys-pil-tz.c b/drivers/soc/qcom/subsys-pil-tz.c
index 5b600f6..d3819b6 100644
--- a/drivers/soc/qcom/subsys-pil-tz.c
+++ b/drivers/soc/qcom/subsys-pil-tz.c
@@ -47,6 +47,13 @@
#define desc_to_data(d) container_of(d, struct pil_tz_data, desc)
#define subsys_to_data(d) container_of(d, struct pil_tz_data, subsys_desc)
+struct pil_map_fw_info {
+ void *region;
+ unsigned long attrs;
+ phys_addr_t base_addr;
+ struct device *dev;
+};
+
/**
* struct reg_info - regulator info
* @reg: regulator handle
@@ -586,7 +593,8 @@
}
static int pil_init_image_trusted(struct pil_desc *pil,
- const u8 *metadata, size_t size)
+ const u8 *metadata, size_t size, phys_addr_t mdata_phys,
+ void *region)
{
struct pil_tz_data *d = desc_to_data(pil);
struct pas_init_image_req {
@@ -595,11 +603,15 @@
} request;
u32 scm_ret = 0;
void *mdata_buf;
- dma_addr_t mdata_phys;
int ret;
- unsigned long attrs = 0;
- struct device dev = {0};
struct scm_desc desc = {0};
+ struct pil_map_fw_info map_fw_info = {
+ .attrs = pil->attrs,
+ .region = region,
+ .base_addr = mdata_phys,
+ .dev = pil->dev,
+ };
+ void *map_data = pil->map_data ? pil->map_data : &map_fw_info;
if (d->subsys_desc.no_auth)
return 0;
@@ -607,15 +619,10 @@
ret = scm_pas_enable_bw();
if (ret)
return ret;
- arch_setup_dma_ops(&dev, 0, 0, NULL, 0);
- dev.coherent_dma_mask =
- DMA_BIT_MASK(sizeof(dma_addr_t) * 8);
- attrs |= DMA_ATTR_STRONGLY_ORDERED;
- mdata_buf = dma_alloc_attrs(&dev, size, &mdata_phys, GFP_KERNEL,
- attrs);
+ mdata_buf = pil->map_fw_mem(mdata_phys, size, map_data);
if (!mdata_buf) {
- pr_err("scm-pas: Allocation for metadata failed.\n");
+ dev_err(pil->dev, "Failed to map memory for metadata.\n");
scm_pas_disable_bw();
return -ENOMEM;
}
@@ -637,7 +644,7 @@
scm_ret = desc.ret[0];
}
- dma_free_attrs(&dev, size, mdata_buf, mdata_phys, attrs);
+ pil->unmap_fw_mem(mdata_buf, size, map_data);
scm_pas_disable_bw();
if (ret)
return ret;
@@ -857,9 +864,6 @@
strlcpy(reason, smem_reason, min(size, MAX_SSR_REASON_LEN));
pr_err("%s subsystem failure reason: %s.\n", name, reason);
-
- smem_reason[0] = '\0';
- wmb();
}
static int subsys_shutdown(const struct subsys_desc *subsys, bool force_stop)
diff --git a/drivers/spi/spi-geni-qcom.c b/drivers/spi/spi-geni-qcom.c
index 7aaf08b..186e7ae 100644
--- a/drivers/spi/spi-geni-qcom.c
+++ b/drivers/spi/spi-geni-qcom.c
@@ -230,8 +230,8 @@
u32 cpha = geni_read_reg(mas->base, SE_SPI_CPHA);
u32 demux_sel = 0;
u32 demux_output_inv = 0;
- u32 clk_sel = geni_read_reg(mas->base, SE_GENI_CLK_SEL);
- u32 m_clk_cfg = geni_read_reg(mas->base, GENI_SER_M_CLK_CFG);
+ u32 clk_sel = 0;
+ u32 m_clk_cfg = 0;
int ret = 0;
int idx;
int div;
@@ -884,8 +884,8 @@
/* Speed and bits per word can be overridden per transfer */
if (xfer->speed_hz != mas->cur_speed_hz) {
int ret = 0;
- u32 clk_sel = geni_read_reg(mas->base, SE_GENI_CLK_SEL);
- u32 m_clk_cfg = geni_read_reg(mas->base, GENI_SER_M_CLK_CFG);
+ u32 clk_sel = 0;
+ u32 m_clk_cfg = 0;
int idx = 0;
int div = 0;
diff --git a/drivers/staging/android/ion/ion.c b/drivers/staging/android/ion/ion.c
index 720ac31..c1103c7 100644
--- a/drivers/staging/android/ion/ion.c
+++ b/drivers/staging/android/ion/ion.c
@@ -1523,6 +1523,11 @@
}
buffer = dmabuf->priv;
+ if (!is_buffer_hlos_assigned(buffer)) {
+ pr_err("%s: cannot sync a secure dmabuf\n", __func__);
+ dma_buf_put(dmabuf);
+ return -EINVAL;
+ }
dma_sync_sg_for_device(NULL, buffer->sg_table->sgl,
buffer->sg_table->nents, DMA_BIDIRECTIONAL);
dma_buf_put(dmabuf);
diff --git a/drivers/staging/android/ion/msm/msm_ion.c b/drivers/staging/android/ion/msm/msm_ion.c
index c7b58ce..9d53391 100644
--- a/drivers/staging/android/ion/msm/msm_ion.c
+++ b/drivers/staging/android/ion/msm/msm_ion.c
@@ -88,6 +88,10 @@
.name = ION_QSECOM_HEAP_NAME,
},
{
+ .id = ION_QSECOM_TA_HEAP_ID,
+ .name = ION_QSECOM_TA_HEAP_NAME,
+ },
+ {
.id = ION_SPSS_HEAP_ID,
.name = ION_SPSS_HEAP_NAME,
},
@@ -340,7 +344,7 @@
if (!ION_IS_CACHED(flags))
return 0;
- if (flags & ION_FLAG_SECURE)
+ if (!is_buffer_hlos_assigned(ion_handle_buffer(handle)))
return 0;
table = ion_sg_table(client, handle);
@@ -675,6 +679,20 @@
return -EINVAL;
}
+bool is_buffer_hlos_assigned(struct ion_buffer *buffer)
+{
+ bool is_hlos = false;
+
+ if (buffer->heap->type == (enum ion_heap_type)ION_HEAP_TYPE_HYP_CMA &&
+ (buffer->flags & ION_FLAG_CP_HLOS))
+ is_hlos = true;
+
+ if (get_secure_vmid(buffer->flags) <= 0)
+ is_hlos = true;
+
+ return is_hlos;
+}
+
int get_vmid(unsigned long flags)
{
int vmid;
@@ -751,9 +769,9 @@
down_read(&mm->mmap_sem);
- start = (unsigned long)data.flush_data.vaddr;
- end = (unsigned long)data.flush_data.vaddr
- + data.flush_data.length;
+ start = (unsigned long)data.flush_data.vaddr +
+ data.flush_data.offset;
+ end = start + data.flush_data.length;
if (check_vaddr_bounds(start, end)) {
pr_err("%s: virtual address %pK is out of bounds\n",
diff --git a/drivers/staging/android/ion/msm/msm_ion.h b/drivers/staging/android/ion/msm/msm_ion.h
index 741d017..ad7b1c5 100644
--- a/drivers/staging/android/ion/msm/msm_ion.h
+++ b/drivers/staging/android/ion/msm/msm_ion.h
@@ -174,6 +174,8 @@
void *vaddr, unsigned int offset, unsigned long len,
unsigned int cmd);
+bool is_buffer_hlos_assigned(struct ion_buffer *buffer);
+
#else
static inline struct ion_client *msm_ion_client_create(const char *name)
{
@@ -202,6 +204,10 @@
return -ENODEV;
}
+static bool is_buffer_hlos_assigned(struct ion_buffer *buffer)
+{
+ return true;
+}
#endif /* CONFIG_ION */
#endif
diff --git a/drivers/staging/android/lowmemorykiller.c b/drivers/staging/android/lowmemorykiller.c
index 8d67f76..4747949 100644
--- a/drivers/staging/android/lowmemorykiller.c
+++ b/drivers/staging/android/lowmemorykiller.c
@@ -221,6 +221,22 @@
return 0;
}
+static int test_task_state(struct task_struct *p, int state)
+{
+ struct task_struct *t;
+
+ for_each_thread(p, t) {
+ task_lock(t);
+ if (t->state & state) {
+ task_unlock(t);
+ return 1;
+ }
+ task_unlock(t);
+ }
+
+ return 0;
+}
+
static int test_task_lmk_waiting(struct task_struct *p)
{
struct task_struct *t;
@@ -435,7 +451,7 @@
int other_free;
int other_file;
- if (mutex_lock_interruptible(&scan_mutex) < 0)
+ if (!mutex_trylock(&scan_mutex))
return 0;
other_free = global_page_state(NR_FREE_PAGES) - totalreserve_pages;
@@ -495,8 +511,6 @@
if (time_before_eq(jiffies, lowmem_deathpending_timeout)) {
if (test_task_lmk_waiting(tsk)) {
rcu_read_unlock();
- /* give the system time to free up the memory */
- msleep_interruptible(20);
mutex_unlock(&scan_mutex);
return 0;
}
@@ -533,6 +547,16 @@
long cache_limit = minfree * (long)(PAGE_SIZE / 1024);
long free = other_free * (long)(PAGE_SIZE / 1024);
+ if (test_task_lmk_waiting(selected) &&
+ (test_task_state(selected, TASK_UNINTERRUPTIBLE))) {
+ lowmem_print(2, "'%s' (%d) is already killed\n",
+ selected->comm,
+ selected->pid);
+ rcu_read_unlock();
+ mutex_unlock(&scan_mutex);
+ return 0;
+ }
+
task_lock(selected);
send_sig(SIGKILL, selected, 0);
if (selected->mm)
diff --git a/drivers/staging/android/uapi/msm_ion.h b/drivers/staging/android/uapi/msm_ion.h
index 84598db..4f9dd73 100644
--- a/drivers/staging/android/uapi/msm_ion.h
+++ b/drivers/staging/android/uapi/msm_ion.h
@@ -33,6 +33,7 @@
ION_CP_MFC_HEAP_ID = 12,
ION_SPSS_HEAP_ID = 13, /* Secure Processor ION heap */
ION_CP_WB_HEAP_ID = 16, /* 8660 only */
+ ION_QSECOM_TA_HEAP_ID = 19,
ION_CAMERA_HEAP_ID = 20, /* 8660 only */
ION_SYSTEM_CONTIG_HEAP_ID = 21,
ION_ADSP_HEAP_ID = 22,
@@ -130,6 +131,7 @@
#define ION_PIL1_HEAP_NAME "pil_1"
#define ION_PIL2_HEAP_NAME "pil_2"
#define ION_QSECOM_HEAP_NAME "qsecom"
+#define ION_QSECOM_TA_HEAP_NAME "qsecom_ta"
#define ION_SECURE_HEAP_NAME "secure_heap"
#define ION_SECURE_DISPLAY_HEAP_NAME "secure_display"
diff --git a/drivers/thermal/Makefile b/drivers/thermal/Makefile
index acbd26b..27bf54b 100644
--- a/drivers/thermal/Makefile
+++ b/drivers/thermal/Makefile
@@ -58,4 +58,4 @@
obj-$(CONFIG_MTK_THERMAL) += mtk_thermal.o
obj-$(CONFIG_GENERIC_ADC_THERMAL) += thermal-generic-adc.o
obj-$(CONFIG_THERMAL_QPNP_ADC_TM) += qpnp-adc-tm.o
-obj-$(CONFIG_THERMAL_TSENS) += msm-tsens.o tsens2xxx.o tsens-dbg.o
+obj-$(CONFIG_THERMAL_TSENS) += msm-tsens.o tsens2xxx.o tsens-dbg.o tsens-mtc.o
diff --git a/drivers/thermal/tsens-dbg.c b/drivers/thermal/tsens-dbg.c
index 2e795b1..e1fc6b9 100644
--- a/drivers/thermal/tsens-dbg.c
+++ b/drivers/thermal/tsens-dbg.c
@@ -12,7 +12,9 @@
*/
#include <asm/arch_timer.h>
+#include <linux/platform_device.h>
#include "tsens.h"
+#include "tsens-mtc.h"
/* debug defines */
#define TSENS_DBG_BUS_ID_0 0
@@ -42,6 +44,177 @@
int (*dbg_func)(struct tsens_device *, u32, u32, int *);
};
+static ssize_t
+zonemask_show(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ struct tsens_device *tmdev = NULL;
+
+ tmdev = tsens_controller_is_present();
+ if (!tmdev) {
+ pr_err("No TSENS controller present\n");
+ return -EPROBE_DEFER;
+ }
+
+ return snprintf(buf, PAGE_SIZE,
+ "Zone =%d th1=%d th2=%d\n", tmdev->mtcsys.zone_mtc,
+ tmdev->mtcsys.th1, tmdev->mtcsys.th2);
+}
+
+static ssize_t
+zonemask_store(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ int ret;
+ struct tsens_device *tmdev = NULL;
+
+ tmdev = tsens_controller_is_present();
+ if (!tmdev) {
+ pr_err("No TSENS controller present\n");
+ return -EPROBE_DEFER;
+ }
+
+ ret = sscanf(buf, "%d %d %d", &tmdev->mtcsys.zone_mtc,
+ &tmdev->mtcsys.th1, &tmdev->mtcsys.th2);
+
+ if (ret != TSENS_ZONEMASK_PARAMS) {
+ pr_err("Invalid command line arguments\n");
+ count = -EINVAL;
+ } else {
+ pr_debug("store zone_mtc=%d th1=%d th2=%d\n",
+ tmdev->mtcsys.zone_mtc,
+ tmdev->mtcsys.th1, tmdev->mtcsys.th2);
+ ret = tsens_set_mtc_zone_sw_mask(tmdev->mtcsys.zone_mtc,
+ tmdev->mtcsys.th1, tmdev->mtcsys.th2);
+ if (ret < 0) {
+ pr_err("Invalid command line arguments\n");
+ count = -EINVAL;
+ }
+ }
+
+ return count;
+}
+
+static ssize_t
+zonelog_show(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ int ret, zlog[TSENS_MTC_ZONE_LOG_SIZE];
+ struct tsens_device *tmdev = NULL;
+
+ tmdev = tsens_controller_is_present();
+ if (!tmdev) {
+ pr_err("No TSENS controller present\n");
+ return -EPROBE_DEFER;
+ }
+
+ ret = tsens_get_mtc_zone_log(tmdev->mtcsys.zone_log, zlog);
+ if (ret < 0) {
+ pr_err("Invalid command line arguments\n");
+ return -EINVAL;
+ }
+
+ return snprintf(buf, PAGE_SIZE,
+ "Log[0]=%d\nLog[1]=%d\nLog[2]=%d\nLog[3]=%d\nLog[4]=%d\nLog[5]=%d\n",
+ zlog[0], zlog[1], zlog[2], zlog[3], zlog[4], zlog[5]);
+}
+
+static ssize_t
+zonelog_store(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ int ret;
+ struct tsens_device *tmdev = NULL;
+
+ tmdev = tsens_controller_is_present();
+ if (!tmdev) {
+ pr_err("No TSENS controller present\n");
+ return -EPROBE_DEFER;
+ }
+
+ ret = kstrtou32(buf, 0, &tmdev->mtcsys.zone_log);
+ if (ret < 0) {
+ pr_err("Invalid command line arguments\n");
+ return -EINVAL;
+ }
+
+ return count;
+}
+
+static ssize_t
+zonehist_show(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ int ret, zhist[TSENS_MTC_ZONE_HISTORY_SIZE];
+ struct tsens_device *tmdev = NULL;
+
+ tmdev = tsens_controller_is_present();
+ if (!tmdev) {
+ pr_err("No TSENS controller present\n");
+ return -EPROBE_DEFER;
+ }
+
+ ret = tsens_get_mtc_zone_history(tmdev->mtcsys.zone_hist, zhist);
+ if (ret < 0) {
+ pr_err("Invalid command line arguments\n");
+ return -EINVAL;
+ }
+
+ return snprintf(buf, PAGE_SIZE,
+ "Cool = %d\nYellow = %d\nRed = %d\n",
+ zhist[0], zhist[1], zhist[2]);
+}
+
+static ssize_t
+zonehist_store(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ int ret;
+ struct tsens_device *tmdev = NULL;
+
+ tmdev = tsens_controller_is_present();
+ if (!tmdev) {
+ pr_err("No TSENS controller present\n");
+ return -EPROBE_DEFER;
+ }
+
+ ret = kstrtou32(buf, 0, &tmdev->mtcsys.zone_hist);
+ if (ret < 0) {
+ pr_err("Invalid command line arguments\n");
+ return -EINVAL;
+ }
+
+ return count;
+}
+
+static struct device_attribute tsens_mtc_dev_attr[] = {
+ __ATTR(zonemask, 0644, zonemask_show, zonemask_store),
+ __ATTR(zonelog, 0644, zonelog_show, zonelog_store),
+ __ATTR(zonehist, 0644, zonehist_show, zonehist_store),
+};
+
+static int tsens_dbg_mtc_data(struct tsens_device *data,
+ u32 id, u32 dbg_type, int *val)
+{
+ int result = 0, i;
+ struct tsens_device *tmdev = NULL;
+ struct device_attribute *attr_ptr = NULL;
+
+ attr_ptr = tsens_mtc_dev_attr;
+ tmdev = data;
+
+ for (i = 0; i < ARRAY_SIZE(tsens_mtc_dev_attr); i++) {
+ result = device_create_file(&tmdev->pdev->dev, &attr_ptr[i]);
+ if (result < 0)
+ goto error;
+ }
+
+ return result;
+
+error:
+ for (i--; i >= 0; i--)
+ device_remove_file(&tmdev->pdev->dev, &attr_ptr[i]);
+
+ return result;
+}
+
static int tsens_dbg_log_temp_reads(struct tsens_device *data, u32 id,
u32 dbg_type, int *temp)
{
@@ -206,6 +379,7 @@
[TSENS_DBG_LOG_INTERRUPT_TIMESTAMP] = {
tsens_dbg_log_interrupt_timestamp},
[TSENS_DBG_LOG_BUS_ID_DATA] = {tsens_dbg_log_bus_id_data},
+ [TSENS_DBG_MTC_DATA] = {tsens_dbg_mtc_data},
};
int tsens2xxx_dbg(struct tsens_device *data, u32 id, u32 dbg_type, int *val)
diff --git a/drivers/thermal/tsens-mtc.c b/drivers/thermal/tsens-mtc.c
new file mode 100644
index 0000000..529503f
--- /dev/null
+++ b/drivers/thermal/tsens-mtc.c
@@ -0,0 +1,195 @@
+/* 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
+ * 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 "tsens.h"
+#include "tsens-mtc.h"
+
+struct tsens_device *tsens_controller_is_present(void)
+{
+ struct tsens_device *tmdev_chip = NULL;
+
+ if (list_empty(&tsens_device_list)) {
+ pr_err("%s: TSENS controller not available\n", __func__);
+ return tmdev_chip;
+ }
+
+ list_for_each_entry(tmdev_chip, &tsens_device_list, list)
+ return tmdev_chip;
+
+ return tmdev_chip;
+}
+EXPORT_SYMBOL(tsens_controller_is_present);
+
+static int tsens_mtc_reset_history_counter(unsigned int zone)
+{
+ unsigned int reg_cntl, is_valid;
+ void __iomem *sensor_addr;
+ struct tsens_device *tmdev = NULL;
+
+ if (zone > TSENS_NUM_MTC_ZONES_SUPPORT)
+ return -EINVAL;
+
+ tmdev = tsens_controller_is_present();
+ if (!tmdev) {
+ pr_err("No TSENS controller present\n");
+ return -EPROBE_DEFER;
+ }
+
+ sensor_addr = TSENS_TM_MTC_ZONE0_SW_MASK_ADDR(tmdev->tsens_tm_addr);
+ reg_cntl = readl_relaxed((sensor_addr +
+ (zone * TSENS_SN_ADDR_OFFSET)));
+ is_valid = (reg_cntl & TSENS_RESET_HISTORY_MASK)
+ >> TSENS_RESET_HISTORY_SHIFT;
+ if (!is_valid) {
+ /*Enable the bit to reset counter*/
+ writel_relaxed(reg_cntl | (1 << TSENS_RESET_HISTORY_SHIFT),
+ (sensor_addr + (zone * TSENS_SN_ADDR_OFFSET)));
+ reg_cntl = readl_relaxed((sensor_addr +
+ (zone * TSENS_SN_ADDR_OFFSET)));
+ pr_debug("tsens : zone =%d reg=%x\n", zone, reg_cntl);
+ }
+
+ /*Disble the bit to start counter*/
+ writel_relaxed(reg_cntl & ~(1 << TSENS_RESET_HISTORY_SHIFT),
+ (sensor_addr + (zone * TSENS_SN_ADDR_OFFSET)));
+ reg_cntl = readl_relaxed((sensor_addr +
+ (zone * TSENS_SN_ADDR_OFFSET)));
+ pr_debug("tsens : zone =%d reg=%x\n", zone, reg_cntl);
+
+ return 0;
+}
+EXPORT_SYMBOL(tsens_mtc_reset_history_counter);
+
+int tsens_set_mtc_zone_sw_mask(unsigned int zone, unsigned int th1_enable,
+ unsigned int th2_enable)
+{
+ unsigned int reg_cntl;
+ void __iomem *sensor_addr;
+ struct tsens_device *tmdev = NULL;
+
+ if (zone > TSENS_NUM_MTC_ZONES_SUPPORT)
+ return -EINVAL;
+
+ tmdev = tsens_controller_is_present();
+ if (!tmdev) {
+ pr_err("No TSENS controller present\n");
+ return -EPROBE_DEFER;
+ }
+
+ sensor_addr = TSENS_TM_MTC_ZONE0_SW_MASK_ADDR
+ (tmdev->tsens_tm_addr);
+
+ if (th1_enable && th2_enable)
+ writel_relaxed(TSENS_MTC_IN_EFFECT,
+ (sensor_addr +
+ (zone * TSENS_SN_ADDR_OFFSET)));
+ if (!th1_enable && !th2_enable)
+ writel_relaxed(TSENS_MTC_DISABLE,
+ (sensor_addr +
+ (zone * TSENS_SN_ADDR_OFFSET)));
+ if (th1_enable && !th2_enable)
+ writel_relaxed(TSENS_TH1_MTC_IN_EFFECT,
+ (sensor_addr +
+ (zone * TSENS_SN_ADDR_OFFSET)));
+ if (!th1_enable && th2_enable)
+ writel_relaxed(TSENS_TH2_MTC_IN_EFFECT,
+ (sensor_addr +
+ (zone * TSENS_SN_ADDR_OFFSET)));
+ reg_cntl = readl_relaxed((sensor_addr +
+ (zone * TSENS_SN_ADDR_OFFSET)));
+ pr_debug("tsens : zone =%d th1=%d th2=%d reg=%x\n",
+ zone, th1_enable, th2_enable, reg_cntl);
+
+ return 0;
+}
+EXPORT_SYMBOL(tsens_set_mtc_zone_sw_mask);
+
+int tsens_get_mtc_zone_log(unsigned int zone, void *zone_log)
+{
+ unsigned int i, reg_cntl, is_valid, log[TSENS_MTC_ZONE_LOG_SIZE];
+ int *zlog = (int *)zone_log;
+ void __iomem *sensor_addr;
+ struct tsens_device *tmdev = NULL;
+
+ if (zone > TSENS_NUM_MTC_ZONES_SUPPORT)
+ return -EINVAL;
+
+ tmdev = tsens_controller_is_present();
+ if (!tmdev) {
+ pr_err("No TSENS controller present\n");
+ return -EPROBE_DEFER;
+ }
+
+ sensor_addr = TSENS_TM_MTC_ZONE0_LOG(tmdev->tsens_tm_addr);
+
+ reg_cntl = readl_relaxed((sensor_addr +
+ (zone * TSENS_SN_ADDR_OFFSET)));
+ is_valid = (reg_cntl & TSENS_LOGS_VALID_MASK)
+ >> TSENS_LOGS_VALID_SHIFT;
+ if (is_valid) {
+ log[0] = (reg_cntl & TSENS_LOGS_LATEST_MASK);
+ log[1] = (reg_cntl & TSENS_LOGS_LOG1_MASK)
+ >> TSENS_LOGS_LOG1_SHIFT;
+ log[2] = (reg_cntl & TSENS_LOGS_LOG2_MASK)
+ >> TSENS_LOGS_LOG2_SHIFT;
+ log[3] = (reg_cntl & TSENS_LOGS_LOG3_MASK)
+ >> TSENS_LOGS_LOG3_SHIFT;
+ log[4] = (reg_cntl & TSENS_LOGS_LOG4_MASK)
+ >> TSENS_LOGS_LOG4_SHIFT;
+ log[5] = (reg_cntl & TSENS_LOGS_LOG5_MASK)
+ >> TSENS_LOGS_LOG5_SHIFT;
+ for (i = 0; i < (TSENS_MTC_ZONE_LOG_SIZE); i++) {
+ *(zlog+i) = log[i];
+ pr_debug("Log[%d]=%d\n", i, log[i]);
+ }
+ } else {
+ pr_debug("tsens: Valid bit disabled\n");
+ return -EINVAL;
+ }
+ return 0;
+}
+EXPORT_SYMBOL(tsens_get_mtc_zone_log);
+
+int tsens_get_mtc_zone_history(unsigned int zone, void *zone_hist)
+{
+ unsigned int i, reg_cntl, hist[TSENS_MTC_ZONE_HISTORY_SIZE];
+ int *zhist = (int *)zone_hist;
+ void __iomem *sensor_addr;
+ struct tsens_device *tmdev = NULL;
+
+ if (zone > TSENS_NUM_MTC_ZONES_SUPPORT)
+ return -EINVAL;
+
+ tmdev = tsens_controller_is_present();
+ if (!tmdev) {
+ pr_err("No TSENS controller present\n");
+ return -EPROBE_DEFER;
+ }
+
+ sensor_addr = TSENS_TM_MTC_ZONE0_HISTORY(tmdev->tsens_tm_addr);
+ reg_cntl = readl_relaxed((sensor_addr +
+ (zone * TSENS_SN_ADDR_OFFSET)));
+
+ hist[0] = (reg_cntl & TSENS_PS_COOL_CMD_MASK);
+ hist[1] = (reg_cntl & TSENS_PS_YELLOW_CMD_MASK)
+ >> TSENS_PS_YELLOW_CMD_SHIFT;
+ hist[2] = (reg_cntl & TSENS_PS_RED_CMD_MASK)
+ >> TSENS_PS_RED_CMD_SHIFT;
+ for (i = 0; i < (TSENS_MTC_ZONE_HISTORY_SIZE); i++) {
+ *(zhist+i) = hist[i];
+ pr_debug("tsens : %d\n", hist[i]);
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL(tsens_get_mtc_zone_history);
diff --git a/drivers/thermal/tsens-mtc.h b/drivers/thermal/tsens-mtc.h
new file mode 100644
index 0000000..979513f
--- /dev/null
+++ b/drivers/thermal/tsens-mtc.h
@@ -0,0 +1,59 @@
+/* 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
+ * 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 TSENS_NUM_MTC_ZONES_SUPPORT 3
+#define TSENS_TM_MTC_ZONE0_SW_MASK_ADDR(n) ((n) + 0x140)
+#define TSENS_TM_MTC_ZONE0_LOG(n) ((n) + 0x150)
+#define TSENS_TM_MTC_ZONE0_HISTORY(n) ((n) + 0x160)
+#define TSENS_SN_ADDR_OFFSET 0x4
+#define TSENS_RESET_HISTORY_MASK 0x4
+#define TSENS_ZONEMASK_PARAMS 3
+#define TSENS_MTC_ZONE_LOG_SIZE 6
+#define TSENS_MTC_ZONE_HISTORY_SIZE 3
+
+#define TSENS_TH1_MTC_IN_EFFECT BIT(0)
+#define TSENS_TH2_MTC_IN_EFFECT BIT(1)
+#define TSENS_MTC_IN_EFFECT 0x3
+#define TSENS_MTC_DISABLE 0x0
+
+#define TSENS_LOGS_VALID_MASK 0x40000000
+#define TSENS_LOGS_VALID_SHIFT 30
+#define TSENS_LOGS_LATEST_MASK 0x0000001f
+#define TSENS_LOGS_LOG1_MASK 0x000003e0
+#define TSENS_LOGS_LOG2_MASK 0x00007c00
+#define TSENS_LOGS_LOG3_MASK 0x000f8000
+#define TSENS_LOGS_LOG4_MASK 0x01f00000
+#define TSENS_LOGS_LOG5_MASK 0x3e000000
+#define TSENS_LOGS_LOG1_SHIFT 5
+#define TSENS_LOGS_LOG2_SHIFT 10
+#define TSENS_LOGS_LOG3_SHIFT 15
+#define TSENS_LOGS_LOG4_SHIFT 20
+#define TSENS_LOGS_LOG5_SHIFT 25
+
+#define TSENS_PS_RED_CMD_MASK 0x3ff00000
+#define TSENS_PS_YELLOW_CMD_MASK 0x000ffc00
+#define TSENS_PS_COOL_CMD_MASK 0x000003ff
+#define TSENS_PS_YELLOW_CMD_SHIFT 0xa
+#define TSENS_PS_RED_CMD_SHIFT 0x14
+
+#define TSENS_RESET_HISTORY_SHIFT 2
+
+#define TSENS_ZONEMASK_PARAMS 3
+#define TSENS_MTC_ZONE_LOG_SIZE 6
+#define TSENS_MTC_ZONE_HISTORY_SIZE 3
+
+extern int tsens_get_mtc_zone_history(unsigned int zone, void *zone_hist);
+extern struct tsens_device *tsens_controller_is_present(void);
+extern int tsens_set_mtc_zone_sw_mask(unsigned int zone,
+ unsigned int th1_enable, unsigned int th2_enable);
+extern int tsens_get_mtc_zone_log(unsigned int zone, void *zone_log);
diff --git a/drivers/thermal/tsens.h b/drivers/thermal/tsens.h
index ec2d592..ae4741d 100644
--- a/drivers/thermal/tsens.h
+++ b/drivers/thermal/tsens.h
@@ -32,6 +32,7 @@
TSENS_DBG_LOG_TEMP_READS,
TSENS_DBG_LOG_INTERRUPT_TIMESTAMP,
TSENS_DBG_LOG_BUS_ID_DATA,
+ TSENS_DBG_MTC_DATA,
TSENS_DBG_LOG_MAX
};
@@ -114,6 +115,15 @@
u32 cycle_compltn_monitor_mask;
bool wd_bark;
u32 wd_bark_mask;
+ bool mtc;
+};
+
+struct tsens_mtc_sysfs {
+ uint32_t zone_log;
+ int zone_mtc;
+ int th1;
+ int th2;
+ uint32_t zone_hist;
};
struct tsens_device {
@@ -130,8 +140,10 @@
spinlock_t tsens_upp_low_lock;
const struct tsens_data *ctrl_data;
struct tsens_sensor sensor[0];
+ struct tsens_mtc_sysfs mtcsys;
};
extern const struct tsens_data data_tsens2xxx, data_tsens23xx, data_tsens24xx;
+extern struct list_head tsens_device_list;
#endif /* __QCOM_TSENS_H__ */
diff --git a/drivers/thermal/tsens2xxx.c b/drivers/thermal/tsens2xxx.c
index fd625ae..50c847f 100644
--- a/drivers/thermal/tsens2xxx.c
+++ b/drivers/thermal/tsens2xxx.c
@@ -570,6 +570,11 @@
spin_lock_init(&tmdev->tsens_crit_lock);
spin_lock_init(&tmdev->tsens_upp_low_lock);
+ if (tmdev->ctrl_data->mtc) {
+ if (tmdev->ops->dbg)
+ tmdev->ops->dbg(tmdev, 0, TSENS_DBG_MTC_DATA, NULL);
+ }
+
return 0;
}
@@ -628,6 +633,7 @@
.wd_bark = false,
.wd_bark_mask = 1,
.ops = &ops_tsens2xxx,
+ .mtc = true,
};
const struct tsens_data data_tsens23xx = {
@@ -636,6 +642,7 @@
.wd_bark = true,
.wd_bark_mask = 1,
.ops = &ops_tsens2xxx,
+ .mtc = false,
};
const struct tsens_data data_tsens24xx = {
@@ -645,4 +652,5 @@
/* Enable Watchdog monitoring by unmasking */
.wd_bark_mask = 0,
.ops = &ops_tsens2xxx,
+ .mtc = false,
};
diff --git a/drivers/tty/serial/msm_geni_serial.c b/drivers/tty/serial/msm_geni_serial.c
index 89c1681..0ce23c3 100644
--- a/drivers/tty/serial/msm_geni_serial.c
+++ b/drivers/tty/serial/msm_geni_serial.c
@@ -493,6 +493,7 @@
} else {
pm_runtime_get_noresume(uport->dev);
pm_runtime_set_active(uport->dev);
+ enable_irq(uport->irq);
}
pm_runtime_enable(uport->dev);
if (lock)
@@ -1285,6 +1286,8 @@
geni_se_rx_dma_unprep(msm_port->wrapper_dev, msm_port->rx_dma,
DMA_RX_BUF_SIZE);
+ msm_port->rx_dma = (dma_addr_t)NULL;
+
rx_bytes = geni_read_reg_nolog(uport->membase, SE_DMA_RX_LEN_IN);
if (unlikely(!msm_port->rx_buf)) {
IPC_LOG_MSG(msm_port->ipc_log_rx, "%s: NULL Rx_buf\n",
@@ -2576,7 +2579,8 @@
SE_UART_MANUAL_RFR);
/* Ensure that the Rx is running before enabling interrupts */
mb();
- enable_irq(port->uport.irq);
+ if (pm_runtime_enabled(dev))
+ enable_irq(port->uport.irq);
IPC_LOG_MSG(port->ipc_log_pwr, "%s:\n", __func__);
exit_runtime_resume:
return ret;
diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c
index a5e050a..719fcbf 100644
--- a/drivers/usb/dwc3/core.c
+++ b/drivers/usb/dwc3/core.c
@@ -1173,6 +1173,9 @@
device_property_read_u32(dev, "snps,xhci-imod-value",
&dwc->xhci_imod_value);
+ dwc->core_id = -1;
+ device_property_read_u32(dev, "usb-core-id", &dwc->core_id);
+
dwc->usb3_lpm_capable = device_property_read_bool(dev,
"snps,usb3_lpm_capable");
@@ -1243,7 +1246,7 @@
dwc->dwc_wq = alloc_ordered_workqueue("dwc_wq", WQ_HIGHPRI);
if (!dwc->dwc_wq) {
pr_err("%s: Unable to create workqueue dwc_wq\n", __func__);
- return -ENOMEM;
+ goto err0;
}
INIT_WORK(&dwc->bh_work, dwc3_bh_work);
@@ -1290,7 +1293,7 @@
ret = dwc3_core_init_mode(dwc);
if (ret)
- goto err0;
+ goto err1;
ret = dwc3_debugfs_init(dwc);
if (ret) {
@@ -1312,6 +1315,8 @@
err_core_init:
dwc3_core_exit_mode(dwc);
+err1:
+ destroy_workqueue(dwc->dwc_wq);
err0:
/*
* restore res->start back to its original value so that, in case the
@@ -1319,7 +1324,6 @@
* memory region the next time probe is called.
*/
res->start -= DWC3_GLOBALS_REGS_START;
- destroy_workqueue(dwc->dwc_wq);
return ret;
}
diff --git a/drivers/usb/dwc3/core.h b/drivers/usb/dwc3/core.h
index 68a40f9..a8400dd 100644
--- a/drivers/usb/dwc3/core.h
+++ b/drivers/usb/dwc3/core.h
@@ -954,6 +954,7 @@
* increments or 0 to disable.
* @create_reg_debugfs: create debugfs entry to allow dwc3 register dump
* @xhci_imod_value: imod value to use with xhci
+ * @core_id: usb core id to differentiate different controller
*/
struct dwc3 {
struct usb_ctrlrequest *ctrl_req;
@@ -1150,6 +1151,7 @@
struct dwc3_gadget_events dbg_gadget_events;
bool create_reg_debugfs;
u32 xhci_imod_value;
+ int core_id;
};
/* -------------------------------------------------------------------------- */
diff --git a/drivers/usb/dwc3/dbm.c b/drivers/usb/dwc3/dbm.c
index 3860a1a..44c082a 100644
--- a/drivers/usb/dwc3/dbm.c
+++ b/drivers/usb/dwc3/dbm.c
@@ -450,7 +450,7 @@
}
-int dbm_data_fifo_config(struct dbm *dbm, u8 dep_num, phys_addr_t addr,
+int dbm_data_fifo_config(struct dbm *dbm, u8 dep_num, unsigned long addr,
u32 size, u8 dst_pipe_idx)
{
u8 dbm_ep = dst_pipe_idx;
diff --git a/drivers/usb/dwc3/dbm.h b/drivers/usb/dwc3/dbm.h
index 260afc2..d8e1ce9 100644
--- a/drivers/usb/dwc3/dbm.h
+++ b/drivers/usb/dwc3/dbm.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012-2015, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-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
@@ -63,7 +63,7 @@
int dbm_get_num_of_eps_configured(struct dbm *dbm);
int dbm_event_buffer_config(struct dbm *dbm, u32 addr_lo, u32 addr_hi,
int size);
-int dbm_data_fifo_config(struct dbm *dbm, u8 dep_num, phys_addr_t addr,
+int dbm_data_fifo_config(struct dbm *dbm, u8 dep_num, unsigned long addr,
u32 size, u8 dst_pipe_idx);
void dbm_set_speed(struct dbm *dbm, bool speed);
void dbm_enable(struct dbm *dbm);
diff --git a/drivers/usb/dwc3/dwc3-msm.c b/drivers/usb/dwc3/dwc3-msm.c
index 874499d..dadd61e 100644
--- a/drivers/usb/dwc3/dwc3-msm.c
+++ b/drivers/usb/dwc3/dwc3-msm.c
@@ -229,6 +229,7 @@
struct power_supply *usb_psy;
struct work_struct vbus_draw_work;
bool in_host_mode;
+ bool in_device_mode;
enum usb_device_speed max_rh_port_speed;
unsigned int tx_fifo_size;
bool vbus_active;
@@ -461,7 +462,7 @@
* @size - size of data fifo.
*
*/
-int msm_data_fifo_config(struct usb_ep *ep, phys_addr_t addr,
+int msm_data_fifo_config(struct usb_ep *ep, unsigned long addr,
u32 size, u8 dst_pipe_idx)
{
struct dwc3_ep *dep = to_dwc3_ep(ep);
@@ -2002,7 +2003,7 @@
unsigned long timeout;
u32 reg = 0;
- if ((mdwc->in_host_mode || mdwc->vbus_active)
+ if ((mdwc->in_host_mode || mdwc->in_device_mode)
&& dwc3_msm_is_superspeed(mdwc) && !mdwc->in_restart) {
if (!atomic_read(&mdwc->in_p3)) {
dev_err(mdwc->dev, "Not in P3,aborting LPM sequence\n");
@@ -2265,7 +2266,8 @@
clk_disable_unprepare(mdwc->xo_clk);
/* Perform controller power collapse */
- if (!mdwc->in_host_mode && (!mdwc->vbus_active || mdwc->in_restart)) {
+ if (!mdwc->in_host_mode && (!mdwc->in_device_mode ||
+ mdwc->in_restart)) {
mdwc->lpm_flags |= MDWC3_POWER_COLLAPSE;
dev_dbg(mdwc->dev, "%s: power collapse\n", __func__);
dwc3_msm_config_gdsc(mdwc, 0);
@@ -2307,7 +2309,7 @@
* using HS_PHY_IRQ or SS_PHY_IRQ. Hence enable wakeup only in
* case of host bus suspend and device bus suspend.
*/
- if (mdwc->vbus_active || mdwc->in_host_mode) {
+ if (mdwc->in_device_mode || mdwc->in_host_mode) {
if (mdwc->use_pdc_interrupts) {
enable_usb_pdc_interrupt(mdwc, true);
} else {
@@ -2320,6 +2322,7 @@
}
dev_info(mdwc->dev, "DWC3 in low power mode\n");
+ dbg_event(0xFF, "Ctl Sus", atomic_read(&dwc->in_lpm));
mutex_unlock(&mdwc->suspend_resume_mutex);
return 0;
}
@@ -3020,6 +3023,13 @@
return ret;
}
dev_dbg(mdwc->dev, "IOMMU mapping created: %pK\n", mdwc->iommu_map);
+ ret = iommu_domain_set_attr(mdwc->iommu_map->domain,
+ DOMAIN_ATTR_UPSTREAM_IOVA_ALLOCATOR, &atomic_ctx);
+ if (ret) {
+ dev_err(mdwc->dev, "set UPSTREAM_IOVA_ALLOCATOR failed(%d)\n",
+ ret);
+ goto release_mapping;
+ }
ret = iommu_domain_set_attr(mdwc->iommu_map->domain, DOMAIN_ATTR_ATOMIC,
&atomic_ctx);
@@ -3141,14 +3151,6 @@
if (!mdwc)
return -ENOMEM;
- if (dma_set_mask_and_coherent(dev, DMA_BIT_MASK(64))) {
- dev_err(&pdev->dev, "setting DMA mask to 64 failed.\n");
- if (dma_set_mask_and_coherent(dev, DMA_BIT_MASK(32))) {
- dev_err(&pdev->dev, "setting DMA mask to 32 failed.\n");
- return -EOPNOTSUPP;
- }
- }
-
platform_set_drvdata(pdev, mdwc);
mdwc->dev = &pdev->dev;
@@ -3341,6 +3343,15 @@
if (ret)
goto err;
+ if (dma_set_mask_and_coherent(dev, DMA_BIT_MASK(64))) {
+ dev_err(&pdev->dev, "setting DMA mask to 64 failed.\n");
+ if (dma_set_mask_and_coherent(dev, DMA_BIT_MASK(32))) {
+ dev_err(&pdev->dev, "setting DMA mask to 32 failed.\n");
+ ret = -EOPNOTSUPP;
+ goto uninit_iommu;
+ }
+ }
+
/* Assumes dwc3 is the first DT child of dwc3-msm */
dwc3_node = of_get_next_available_child(node, NULL);
if (!dwc3_node) {
@@ -3890,6 +3901,7 @@
dwc3_msm_block_reset(mdwc, false);
dwc3_set_mode(dwc, DWC3_GCTL_PRTCAP_DEVICE);
+ mdwc->in_device_mode = true;
usb_gadget_vbus_connect(&dwc->gadget);
#ifdef CONFIG_SMP
mdwc->pm_qos_req_dma.type = PM_QOS_REQ_AFFINE_IRQ;
@@ -3908,6 +3920,7 @@
msm_dwc3_perf_vote_update(mdwc, false);
pm_qos_remove_request(&mdwc->pm_qos_req_dma);
+ mdwc->in_device_mode = false;
usb_gadget_vbus_disconnect(&dwc->gadget);
usb_phy_notify_disconnect(mdwc->hs_phy, USB_SPEED_HIGH);
usb_phy_notify_disconnect(mdwc->ss_phy, USB_SPEED_SUPER);
@@ -3944,6 +3957,7 @@
if (ret)
goto err;
+ dbg_event(0xFF, "USB_lpm_state", atomic_read(&dwc->in_lpm));
/*
* stop host mode functionality performs autosuspend with mdwc
* device, and it may take sometime to call PM runtime suspend.
@@ -3951,6 +3965,12 @@
* suspend immediately to put USB controller and PHYs into suspend.
*/
ret = pm_runtime_suspend(mdwc->dev);
+ /*
+ * If mdwc device is already suspended, pm_runtime_suspend() API
+ * returns 1, which is not error. Overwrite with zero if it is.
+ */
+ if (ret > 0)
+ ret = 0;
dbg_event(0xFF, "pm_runtime_sus", ret);
dwc->maximum_speed = usb_speed;
@@ -3989,7 +4009,10 @@
psy_type = get_psy_type(mdwc);
if (psy_type == POWER_SUPPLY_TYPE_USB_FLOAT) {
- pval.intval = -ETIMEDOUT;
+ if (!mA)
+ pval.intval = -ETIMEDOUT;
+ else
+ pval.intval = 1000 * mA;
goto set_prop;
}
diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c
index 5571374..70c00d2 100644
--- a/drivers/usb/dwc3/gadget.c
+++ b/drivers/usb/dwc3/gadget.c
@@ -989,7 +989,7 @@
*/
if (speed == USB_SPEED_HIGH) {
struct usb_ep *ep = &dep->endpoint;
- unsigned int mult = ep->mult - 1;
+ unsigned int mult = 2;
unsigned int maxp;
maxp = usb_endpoint_maxp(ep->desc) & 0x07ff;
@@ -1058,6 +1058,9 @@
{
u8 tmp = index;
+ if (!dep->trb_pool)
+ return NULL;
+
if (!tmp)
tmp = DWC3_TRB_NUM - 1;
@@ -1163,7 +1166,7 @@
static int __dwc3_gadget_kick_transfer(struct dwc3_ep *dep, u16 cmd_param)
{
struct dwc3_gadget_ep_cmd_params params;
- struct dwc3_request *req;
+ struct dwc3_request *req, *req1, *n;
struct dwc3 *dwc = dep->dwc;
int starting;
int ret;
@@ -1193,6 +1196,30 @@
ret = dwc3_send_gadget_ep_cmd(dep, cmd, ¶ms);
if (ret < 0) {
+ if ((ret == -EAGAIN) && starting &&
+ usb_endpoint_xfer_isoc(dep->endpoint.desc)) {
+ /* If bit13 in Command complete event is set, software
+ * must issue ENDTRANDFER command and wait for
+ * Xfernotready event to queue the requests again.
+ */
+ if (!dep->resource_index) {
+ dep->resource_index =
+ dwc3_gadget_ep_get_transfer_index(dep);
+ WARN_ON_ONCE(!dep->resource_index);
+ }
+ dwc3_stop_active_transfer(dwc, dep->number, true);
+
+ list_for_each_entry_safe_reverse(req1, n,
+ &dep->started_list, list) {
+ req1->trb->ctrl &= ~DWC3_TRB_CTRL_HWO;
+ req1->trb = NULL;
+ dwc3_gadget_move_pending_list_front(req1);
+ dwc3_ep_inc_deq(dep);
+ }
+
+ return ret;
+ }
+
/*
* FIXME we need to iterate over the list of requests
* here and stop, unmap, free and del each of the linked
@@ -1240,7 +1267,7 @@
* Schedule the first trb for one interval in the future or at
* least 4 microframes.
*/
- uf = cur_uf + max_t(u32, 4, dep->interval);
+ uf = cur_uf + max_t(u32, 16, dep->interval);
ret = __dwc3_gadget_kick_transfer(dep, uf);
if (ret < 0)
@@ -1279,7 +1306,7 @@
if (req->request.status == -EINPROGRESS) {
ret = -EBUSY;
- dev_err(dwc->dev, "%s: %p request already in queue",
+ dev_err_ratelimited(dwc->dev, "%s: %p request already in queue",
dep->name, req);
return ret;
}
@@ -1570,7 +1597,11 @@
else
trb = &dwc->ep0_trb[dep->trb_enqueue];
- transfer_in_flight = trb->ctrl & DWC3_TRB_CTRL_HWO;
+ if (trb)
+ transfer_in_flight = trb->ctrl & DWC3_TRB_CTRL_HWO;
+ else
+ transfer_in_flight = false;
+
started = !list_empty(&dep->started_list);
if (!protocol && ((dep->direction && transfer_in_flight) ||
@@ -2638,6 +2669,9 @@
unsigned actual;
int chain;
+ if (req->trb->ctrl & DWC3_TRB_CTRL_HWO)
+ return 0;
+
length = req->request.length;
chain = req->num_pending_sgs > 0;
if (chain) {
@@ -2696,18 +2730,17 @@
if (usb_endpoint_xfer_isoc(dep->endpoint.desc) &&
list_empty(&dep->started_list)) {
- if (list_empty(&dep->pending_list)) {
+ if (list_empty(&dep->pending_list))
/*
* If there is no entry in request list then do
* not issue END TRANSFER now. Just set PENDING
* flag, so that END TRANSFER is issued when an
* entry is added into request list.
*/
- dep->flags = DWC3_EP_PENDING_REQUEST;
- } else {
+ dep->flags |= DWC3_EP_PENDING_REQUEST;
+ else
dwc3_stop_active_transfer(dwc, dep->number, true);
- dep->flags = DWC3_EP_ENABLED;
- }
+ dep->flags &= ~DWC3_EP_MISSED_ISOC;
return 1;
}
diff --git a/drivers/usb/dwc3/gadget.h b/drivers/usb/dwc3/gadget.h
index 8d0a5eb..25d8d8f 100644
--- a/drivers/usb/dwc3/gadget.h
+++ b/drivers/usb/dwc3/gadget.h
@@ -68,6 +68,14 @@
return list_first_entry(list, struct dwc3_request, list);
}
+static inline void dwc3_gadget_move_pending_list_front(struct dwc3_request *req)
+{
+ struct dwc3_ep *dep = req->dep;
+
+ req->started = false;
+ list_move(&req->list, &dep->pending_list);
+}
+
static inline void dwc3_gadget_move_started_request(struct dwc3_request *req)
{
struct dwc3_ep *dep = req->dep;
diff --git a/drivers/usb/dwc3/host.c b/drivers/usb/dwc3/host.c
index 3f79aa4..8b159c3 100644
--- a/drivers/usb/dwc3/host.c
+++ b/drivers/usb/dwc3/host.c
@@ -52,7 +52,7 @@
return irq;
}
-#define NUMBER_OF_PROPS 4
+#define NUMBER_OF_PROPS 5
int dwc3_host_init(struct dwc3 *dwc)
{
struct property_entry props[NUMBER_OF_PROPS];
@@ -62,6 +62,7 @@
struct platform_device *dwc3_pdev = to_platform_device(dwc->dev);
int prop_idx = 0;
struct property_entry imod_prop;
+ struct property_entry core_id_prop;
irq = dwc3_host_get_irq(dwc);
if (irq < 0)
@@ -112,6 +113,15 @@
props[prop_idx++] = imod_prop;
}
+ if (dwc->core_id >= 0) {
+ core_id_prop.name = "usb-core-id";
+ core_id_prop.length = sizeof(u32);
+ core_id_prop.is_string = false;
+ core_id_prop.is_array = false;
+ core_id_prop.value.u32_data = dwc->core_id;
+ props[prop_idx++] = core_id_prop;
+ }
+
/**
* WORKAROUND: dwc3 revisions <=3.00a have a limitation
* where Port Disable command doesn't work.
diff --git a/drivers/usb/gadget/Kconfig b/drivers/usb/gadget/Kconfig
index b040fdd..31c1dd2b 100644
--- a/drivers/usb/gadget/Kconfig
+++ b/drivers/usb/gadget/Kconfig
@@ -182,6 +182,9 @@
config USB_F_RNDIS
tristate
+config USB_F_QCRNDIS
+ tristate
+
config USB_F_MASS_STORAGE
tristate
@@ -312,6 +315,14 @@
On hardware that can't implement the full protocol,
a simple CDC subset is used, placing fewer demands on USB.
+config USB_CONFIGFS_QCRNDIS
+ bool "QCRNDIS"
+ depends on USB_CONFIGFS
+ depends on RNDIS_IPA
+ depends on NET
+ select USB_U_ETHER
+ select USB_F_QCRNDIS
+
config USB_CONFIGFS_RNDIS
bool "RNDIS"
depends on USB_CONFIGFS
diff --git a/drivers/usb/gadget/composite.c b/drivers/usb/gadget/composite.c
index 7037696..4aee8c8 100644
--- a/drivers/usb/gadget/composite.c
+++ b/drivers/usb/gadget/composite.c
@@ -363,8 +363,11 @@
spin_lock_irqsave(&cdev->lock, flags);
- if (cdev->deactivations == 0)
+ if (cdev->deactivations == 0) {
+ spin_unlock_irqrestore(&cdev->lock, flags);
status = usb_gadget_deactivate(cdev->gadget);
+ spin_lock_irqsave(&cdev->lock, flags);
+ }
if (status == 0)
cdev->deactivations++;
@@ -395,8 +398,11 @@
status = -EINVAL;
else {
cdev->deactivations--;
- if (cdev->deactivations == 0)
+ if (cdev->deactivations == 0) {
+ spin_unlock_irqrestore(&cdev->lock, flags);
status = usb_gadget_activate(cdev->gadget);
+ spin_lock_irqsave(&cdev->lock, flags);
+ }
}
spin_unlock_irqrestore(&cdev->lock, flags);
diff --git a/drivers/usb/gadget/function/Makefile b/drivers/usb/gadget/function/Makefile
index 960c2cc..90c426b 100644
--- a/drivers/usb/gadget/function/Makefile
+++ b/drivers/usb/gadget/function/Makefile
@@ -64,3 +64,5 @@
obj-$(CONFIG_USB_F_GSI) += usb_f_gsi.o
usb_f_qdss-y := f_qdss.o u_qdss.o
obj-$(CONFIG_USB_F_QDSS) += usb_f_qdss.o
+usb_f_qcrndis-y := f_qc_rndis.o rndis.o u_data_ipa.o
+obj-$(CONFIG_USB_F_QCRNDIS) += usb_f_qcrndis.o
diff --git a/drivers/usb/gadget/function/f_cdev.c b/drivers/usb/gadget/function/f_cdev.c
index 4cb2817..0e86d28 100644
--- a/drivers/usb/gadget/function/f_cdev.c
+++ b/drivers/usb/gadget/function/f_cdev.c
@@ -48,7 +48,7 @@
#define DEVICE_NAME "at_usb"
#define MODULE_NAME "msm_usb_bridge"
-#define NUM_INSTANCE 2
+#define NUM_INSTANCE 3
#define MAX_CDEV_INST_NAME 15
#define MAX_CDEV_FUNC_NAME 5
diff --git a/drivers/usb/gadget/function/f_gsi.c b/drivers/usb/gadget/function/f_gsi.c
index 71e84fd..b1a4a29 100644
--- a/drivers/usb/gadget/function/f_gsi.c
+++ b/drivers/usb/gadget/function/f_gsi.c
@@ -2507,6 +2507,10 @@
struct f_gsi *gsi = func_to_gsi(f);
struct rndis_params *params;
int status;
+ __u8 class;
+ __u8 subclass;
+ __u8 proto;
+
if (gsi->prot_id == IPA_USB_RMNET ||
gsi->prot_id == IPA_USB_DIAG)
@@ -2588,6 +2592,85 @@
DEFAULT_PKT_ALIGNMENT_FACTOR);
rndis_set_pkt_alignment_factor(gsi->params,
DEFAULT_PKT_ALIGNMENT_FACTOR);
+
+ /* Windows7/Windows10 automatically loads RNDIS drivers for
+ * class drivers which represents MISC_ACTIVE_SYNC,
+ * MISC_RNDIS_OVER_ETHERNET & WIRELESS_CONTROLLER_REMOTE_NDIS.
+ * All the codes listed below are from
+ * http://www.usb.org/developers/defined_class and its unknown
+ * why windows loads rndis class driver for some of them.
+ * Note that, Windows loads NDIS6 stack automatically for
+ * MISC_RNDIS_OVER_ETHERNET. Windows loads NDIS5 stack for
+ * MISC_ACTIVE_SYNC and WIRELESS_CONTROLLER_REMOTE_NDIS.
+ * For other class codes, NDIS stack can be selected using
+ * customized INF file but that defeats the purpose as its
+ * expected to load drivers automatically for known class
+ * drivers published by usbif.
+ * Linux rndis host driver supports MISC_ACTIVE_SYNC and
+ * WIRELESS_CONTROLLER_REMOTE_NDIS as of now.
+ * Default to rndis over ethernet which loads NDIS6 drivers
+ * for windows7/windows10 to avoid data stall issues
+ */
+ if (gsi->rndis_id == RNDIS_ID_UNKNOWN)
+ gsi->rndis_id = MISC_RNDIS_OVER_ETHERNET;
+
+ switch (gsi->rndis_id) {
+ default:
+ /* fall throug */
+ case WIRELESS_CONTROLLER_REMOTE_NDIS:
+ class = USB_CLASS_WIRELESS_CONTROLLER;
+ subclass = 0x01;
+ proto = 0x03;
+ break;
+ case MISC_ACTIVE_SYNC:
+ class = USB_CLASS_MISC;
+ subclass = 0x01;
+ proto = 0x01;
+ break;
+ case MISC_RNDIS_OVER_ETHERNET:
+ class = USB_CLASS_MISC;
+ subclass = 0x04;
+ proto = 0x01;
+ break;
+ case MISC_RNDIS_OVER_WIFI:
+ class = USB_CLASS_MISC;
+ subclass = 0x04;
+ proto = 0x02;
+ break;
+ case MISC_RNDIS_OVER_WIMAX:
+ class = USB_CLASS_MISC;
+ subclass = 0x04;
+ proto = 0x03;
+ break;
+ case MISC_RNDIS_OVER_WWAN:
+ class = USB_CLASS_MISC;
+ subclass = 0x04;
+ proto = 0x04;
+ break;
+ case MISC_RNDIS_FOR_IPV4:
+ class = USB_CLASS_MISC;
+ subclass = 0x04;
+ proto = 0x05;
+ break;
+ case MISC_RNDIS_FOR_IPV6:
+ class = USB_CLASS_MISC;
+ subclass = 0x04;
+ proto = 0x06;
+ break;
+ case MISC_RNDIS_FOR_GPRS:
+ class = USB_CLASS_MISC;
+ subclass = 0x04;
+ proto = 0x07;
+ break;
+ }
+
+ info.iad_desc->bFunctionClass = class;
+ info.iad_desc->bFunctionSubClass = subclass;
+ info.iad_desc->bFunctionProtocol = proto;
+ info.ctrl_desc->bInterfaceClass = class;
+ info.ctrl_desc->bInterfaceSubClass = subclass;
+ info.ctrl_desc->bInterfaceProtocol = proto;
+
break;
case IPA_USB_MBIM:
info.string_defs = mbim_gsi_string_defs;
@@ -3086,6 +3169,43 @@
.ct_owner = THIS_MODULE,
};
+static ssize_t gsi_rndis_class_id_show(struct config_item *item, char *page)
+{
+ struct f_gsi *gsi = to_gsi_opts(item)->gsi;
+
+ return snprintf(page, PAGE_SIZE, "%d\n", gsi->rndis_id);
+}
+
+static ssize_t gsi_rndis_class_id_store(struct config_item *item,
+ const char *page, size_t len)
+{
+ struct f_gsi *gsi = to_gsi_opts(item)->gsi;
+ u8 id;
+
+ if (kstrtou8(page, 0, &id))
+ return -EINVAL;
+
+ if (id > RNDIS_ID_UNKNOWN && id < RNDIS_ID_MAX)
+ gsi->rndis_id = id;
+ else
+ return -EINVAL;
+
+ return len;
+}
+CONFIGFS_ATTR(gsi_, rndis_class_id);
+
+static struct configfs_attribute *gsi_rndis_attrs[] = {
+ &gsi_attr_info,
+ &gsi_attr_rndis_class_id,
+ NULL,
+};
+
+static struct config_item_type gsi_func_rndis_type = {
+ .ct_item_ops = &gsi_item_ops,
+ .ct_attrs = gsi_rndis_attrs,
+ .ct_owner = THIS_MODULE,
+};
+
static void gsi_inst_clean(struct gsi_opts *opts)
{
if (opts->gsi->c_port.ctrl_device.fops)
@@ -3127,6 +3247,10 @@
}
mutex_unlock(&inst_status[prot_id].gsi_lock);
+ if (prot_id == IPA_USB_RNDIS)
+ config_group_init_type_name(&opts->func_inst.group, "",
+ &gsi_func_rndis_type);
+
gsi = gsi_function_init(prot_id);
if (IS_ERR(gsi))
return PTR_ERR(gsi);
diff --git a/drivers/usb/gadget/function/f_gsi.h b/drivers/usb/gadget/function/f_gsi.h
index bdd0dfa..fa36d05 100644
--- a/drivers/usb/gadget/function/f_gsi.h
+++ b/drivers/usb/gadget/function/f_gsi.h
@@ -122,6 +122,20 @@
GSI_CTRL_NOTIFY_RESPONSE_AVAILABLE,
};
+enum rndis_class_id {
+ RNDIS_ID_UNKNOWN,
+ WIRELESS_CONTROLLER_REMOTE_NDIS,
+ MISC_ACTIVE_SYNC,
+ MISC_RNDIS_OVER_ETHERNET,
+ MISC_RNDIS_OVER_WIFI,
+ MISC_RNDIS_OVER_WIMAX,
+ MISC_RNDIS_OVER_WWAN,
+ MISC_RNDIS_FOR_IPV4,
+ MISC_RNDIS_FOR_IPV6,
+ MISC_RNDIS_FOR_GPRS,
+ RNDIS_ID_MAX,
+};
+
#define MAXQUEUELEN 128
struct event_queue {
u8 event[MAXQUEUELEN];
@@ -258,6 +272,7 @@
struct rndis_params *params;
atomic_t connected;
bool data_interface_up;
+ enum rndis_class_id rndis_id;
const struct usb_endpoint_descriptor *in_ep_desc_backup;
const struct usb_endpoint_descriptor *out_ep_desc_backup;
@@ -572,7 +587,7 @@
static struct usb_endpoint_descriptor rndis_gsi_fs_in_desc = {
.bLength = USB_DT_ENDPOINT_SIZE,
.bDescriptorType = USB_DT_ENDPOINT,
-
+ .wMaxPacketSize = cpu_to_le16(64),
.bEndpointAddress = USB_DIR_IN,
.bmAttributes = USB_ENDPOINT_XFER_BULK,
};
@@ -580,7 +595,7 @@
static struct usb_endpoint_descriptor rndis_gsi_fs_out_desc = {
.bLength = USB_DT_ENDPOINT_SIZE,
.bDescriptorType = USB_DT_ENDPOINT,
-
+ .wMaxPacketSize = cpu_to_le16(64),
.bEndpointAddress = USB_DIR_OUT,
.bmAttributes = USB_ENDPOINT_XFER_BULK,
};
diff --git a/drivers/usb/gadget/function/f_mtp.c b/drivers/usb/gadget/function/f_mtp.c
index aea32e4..239d9bf 100644
--- a/drivers/usb/gadget/function/f_mtp.c
+++ b/drivers/usb/gadget/function/f_mtp.c
@@ -1464,6 +1464,7 @@
mtp_ss_out_comp_desc.bMaxBurst = max_burst;
}
+ fi_mtp->func_inst.f = &dev->function;
DBG(cdev, "%s speed %s: IN/%s, OUT/%s\n",
gadget_is_superspeed(c->cdev->gadget) ? "super" :
(gadget_is_dualspeed(c->cdev->gadget) ? "dual" : "full"),
@@ -1475,9 +1476,10 @@
mtp_function_unbind(struct usb_configuration *c, struct usb_function *f)
{
struct mtp_dev *dev = func_to_mtp(f);
+ struct mtp_instance *fi_mtp;
struct usb_request *req;
int i;
-
+ fi_mtp = container_of(f->fi, struct mtp_instance, func_inst);
mtp_string_defs[INTERFACE_STRING_INDEX].id = 0;
mutex_lock(&dev->read_mutex);
while ((req = mtp_req_get(dev, &dev->tx_idle)))
@@ -1490,6 +1492,7 @@
dev->state = STATE_OFFLINE;
kfree(f->os_desc_table);
f->os_desc_n = 0;
+ fi_mtp->func_inst.f = NULL;
}
static int mtp_function_set_alt(struct usb_function *f,
diff --git a/drivers/usb/gadget/function/f_ncm.c b/drivers/usb/gadget/function/f_ncm.c
index 98e353d..b0d0020 100644
--- a/drivers/usb/gadget/function/f_ncm.c
+++ b/drivers/usb/gadget/function/f_ncm.c
@@ -1706,6 +1706,8 @@
DBG(c->cdev, "ncm unbind\n");
+ opts->bound = false;
+
hrtimer_cancel(&ncm->task_timer);
tasklet_kill(&ncm->tx_tasklet);
@@ -1716,7 +1718,6 @@
usb_ep_free_request(ncm->notify, ncm->notify_req);
gether_cleanup(netdev_priv(opts->net));
- opts->bound = false;
}
static struct usb_function *ncm_alloc(struct usb_function_instance *fi)
diff --git a/drivers/usb/gadget/function/f_qc_rndis.c b/drivers/usb/gadget/function/f_qc_rndis.c
new file mode 100644
index 0000000..a8e7092
--- /dev/null
+++ b/drivers/usb/gadget/function/f_qc_rndis.c
@@ -0,0 +1,1580 @@
+/*
+ * f_qc_rndis.c -- RNDIS link function driver
+ *
+ * Copyright (C) 2003-2005,2008 David Brownell
+ * Copyright (C) 2003-2004 Robert Schwebel, Benedikt Spranger
+ * Copyright (C) 2008 Nokia Corporation
+ * Copyright (C) 2009 Samsung Electronics
+ * Author: Michal Nazarewicz (mina86@mina86.com)
+ * 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
+ *
+ * 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 VERBOSE_DEBUG */
+
+#include <linux/slab.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/device.h>
+#include <linux/etherdevice.h>
+
+#include <linux/atomic.h>
+
+#include "u_ether.h"
+#include "rndis.h"
+#include "u_data_ipa.h"
+#include <linux/rndis_ipa.h>
+#include "configfs.h"
+
+unsigned int rndis_dl_max_xfer_size = 9216;
+module_param(rndis_dl_max_xfer_size, uint, 0644);
+MODULE_PARM_DESC(rndis_dl_max_xfer_size,
+ "Max size of bus transfer to host");
+
+static struct class *rndis_class;
+static dev_t rndis_dev;
+static DEFINE_IDA(chardev_ida);
+
+/*
+ * This function is an RNDIS Ethernet port -- a Microsoft protocol that's
+ * been promoted instead of the standard CDC Ethernet. The published RNDIS
+ * spec is ambiguous, incomplete, and needlessly complex. Variants such as
+ * ActiveSync have even worse status in terms of specification.
+ *
+ * In short: it's a protocol controlled by (and for) Microsoft, not for an
+ * Open ecosystem or markets. Linux supports it *only* because Microsoft
+ * doesn't support the CDC Ethernet standard.
+ *
+ * The RNDIS data transfer model is complex, with multiple Ethernet packets
+ * per USB message, and out of band data. The control model is built around
+ * what's essentially an "RNDIS RPC" protocol. It's all wrapped in a CDC ACM
+ * (modem, not Ethernet) veneer, with those ACM descriptors being entirely
+ * useless (they're ignored). RNDIS expects to be the only function in its
+ * configuration, so it's no real help if you need composite devices; and
+ * it expects to be the first configuration too.
+ *
+ * There is a single technical advantage of RNDIS over CDC Ethernet, if you
+ * discount the fluff that its RPC can be made to deliver: it doesn't need
+ * a NOP altsetting for the data interface. That lets it work on some of the
+ * "so smart it's stupid" hardware which takes over configuration changes
+ * from the software, and adds restrictions like "no altsettings".
+ *
+ * Unfortunately MSFT's RNDIS drivers are buggy. They hang or oops, and
+ * have all sorts of contrary-to-specification oddities that can prevent
+ * them from working sanely. Since bugfixes (or accurate specs, letting
+ * Linux work around those bugs) are unlikely to ever come from MSFT, you
+ * may want to avoid using RNDIS on purely operational grounds.
+ *
+ * Omissions from the RNDIS 1.0 specification include:
+ *
+ * - Power management ... references data that's scattered around lots
+ * of other documentation, which is incorrect/incomplete there too.
+ *
+ * - There are various undocumented protocol requirements, like the need
+ * to send garbage in some control-OUT messages.
+ *
+ * - MS-Windows drivers sometimes emit undocumented requests.
+ *
+ * This function is based on RNDIS link function driver and
+ * contains MSM specific implementation.
+ */
+
+struct f_rndis_qc {
+ struct usb_function func;
+ u8 ctrl_id, data_id;
+ u8 ethaddr[ETH_ALEN];
+ u32 vendorID;
+ u8 ul_max_pkt_per_xfer;
+ u8 pkt_alignment_factor;
+ u32 max_pkt_size;
+ const char *manufacturer;
+ struct rndis_params *params;
+ atomic_t ioctl_excl;
+ atomic_t open_excl;
+
+ struct usb_ep *notify;
+ struct usb_request *notify_req;
+ atomic_t notify_count;
+ struct gadget_ipa_port bam_port;
+ struct cdev cdev;
+ struct device *dev;
+ u8 port_num;
+ u16 cdc_filter;
+ bool net_ready_trigger;
+};
+
+static struct ipa_usb_init_params rndis_ipa_params;
+static spinlock_t rndis_lock;
+static bool rndis_ipa_supported;
+static void rndis_qc_open(struct f_rndis_qc *rndis);
+
+static inline struct f_rndis_qc *func_to_rndis_qc(struct usb_function *f)
+{
+ return container_of(f, struct f_rndis_qc, func);
+}
+
+/* peak (theoretical) bulk transfer rate in bits-per-second */
+static unsigned int rndis_qc_bitrate(struct usb_gadget *g)
+{
+ if (gadget_is_superspeed(g) && g->speed == USB_SPEED_SUPER)
+ return 13 * 1024 * 8 * 1000 * 8;
+ else if (gadget_is_dualspeed(g) && g->speed == USB_SPEED_HIGH)
+ return 13 * 512 * 8 * 1000 * 8;
+ else
+ return 19 * 64 * 1 * 1000 * 8;
+}
+
+/*-------------------------------------------------------------------------*/
+
+#define RNDIS_QC_LOG2_STATUS_INTERVAL_MSEC 5 /* 1 << 5 == 32 msec */
+#define RNDIS_QC_STATUS_BYTECOUNT 8 /* 8 bytes data */
+
+/* currently only one rndis instance is supported - port
+ * index 0.
+ */
+#define RNDIS_QC_NO_PORTS 1
+#define RNDIS_QC_ACTIVE_PORT 0
+
+/* default max packets per tarnsfer value */
+#define DEFAULT_MAX_PKT_PER_XFER 15
+
+/* default pkt alignment factor */
+#define DEFAULT_PKT_ALIGNMENT_FACTOR 4
+
+#define RNDIS_QC_IOCTL_MAGIC 'i'
+#define RNDIS_QC_GET_MAX_PKT_PER_XFER _IOR(RNDIS_QC_IOCTL_MAGIC, 1, u8)
+#define RNDIS_QC_GET_MAX_PKT_SIZE _IOR(RNDIS_QC_IOCTL_MAGIC, 2, u32)
+
+
+/* interface descriptor: */
+
+/* interface descriptor: Supports "Wireless" RNDIS; auto-detected by Windows*/
+static struct usb_interface_descriptor rndis_qc_control_intf = {
+ .bLength = sizeof(rndis_qc_control_intf),
+ .bDescriptorType = USB_DT_INTERFACE,
+
+ /* .bInterfaceNumber = DYNAMIC */
+ /* status endpoint is optional; this could be patched later */
+ .bNumEndpoints = 1,
+ .bInterfaceClass = USB_CLASS_WIRELESS_CONTROLLER,
+ .bInterfaceSubClass = 0x01,
+ .bInterfaceProtocol = 0x03,
+ /* .iInterface = DYNAMIC */
+};
+
+static struct usb_cdc_header_desc rndis_qc_header_desc = {
+ .bLength = sizeof(rndis_qc_header_desc),
+ .bDescriptorType = USB_DT_CS_INTERFACE,
+ .bDescriptorSubType = USB_CDC_HEADER_TYPE,
+
+ .bcdCDC = cpu_to_le16(0x0110),
+};
+
+static struct usb_cdc_call_mgmt_descriptor rndis_qc_call_mgmt_descriptor = {
+ .bLength = sizeof(rndis_qc_call_mgmt_descriptor),
+ .bDescriptorType = USB_DT_CS_INTERFACE,
+ .bDescriptorSubType = USB_CDC_CALL_MANAGEMENT_TYPE,
+
+ .bmCapabilities = 0x00,
+ .bDataInterface = 0x01,
+};
+
+static struct usb_cdc_acm_descriptor rndis_qc_acm_descriptor = {
+ .bLength = sizeof(rndis_qc_acm_descriptor),
+ .bDescriptorType = USB_DT_CS_INTERFACE,
+ .bDescriptorSubType = USB_CDC_ACM_TYPE,
+
+ .bmCapabilities = 0x00,
+};
+
+static struct usb_cdc_union_desc rndis_qc_union_desc = {
+ .bLength = sizeof(rndis_qc_union_desc),
+ .bDescriptorType = USB_DT_CS_INTERFACE,
+ .bDescriptorSubType = USB_CDC_UNION_TYPE,
+ /* .bMasterInterface0 = DYNAMIC */
+ /* .bSlaveInterface0 = DYNAMIC */
+};
+
+/* the data interface has two bulk endpoints */
+
+static struct usb_interface_descriptor rndis_qc_data_intf = {
+ .bLength = sizeof(rndis_qc_data_intf),
+ .bDescriptorType = USB_DT_INTERFACE,
+
+ /* .bInterfaceNumber = DYNAMIC */
+ .bNumEndpoints = 2,
+ .bInterfaceClass = USB_CLASS_CDC_DATA,
+ .bInterfaceSubClass = 0,
+ .bInterfaceProtocol = 0,
+ /* .iInterface = DYNAMIC */
+};
+
+
+/* Supports "Wireless" RNDIS; auto-detected by Windows */
+static struct usb_interface_assoc_descriptor
+rndis_qc_iad_descriptor = {
+ .bLength = sizeof(rndis_qc_iad_descriptor),
+ .bDescriptorType = USB_DT_INTERFACE_ASSOCIATION,
+ .bFirstInterface = 0, /* XXX, hardcoded */
+ .bInterfaceCount = 2, /* control + data */
+ .bFunctionClass = USB_CLASS_WIRELESS_CONTROLLER,
+ .bFunctionSubClass = 0x01,
+ .bFunctionProtocol = 0x03,
+ /* .iFunction = DYNAMIC */
+};
+
+/* full speed support: */
+
+static struct usb_endpoint_descriptor rndis_qc_fs_notify_desc = {
+ .bLength = USB_DT_ENDPOINT_SIZE,
+ .bDescriptorType = USB_DT_ENDPOINT,
+
+ .bEndpointAddress = USB_DIR_IN,
+ .bmAttributes = USB_ENDPOINT_XFER_INT,
+ .wMaxPacketSize = cpu_to_le16(RNDIS_QC_STATUS_BYTECOUNT),
+ .bInterval = 1 << RNDIS_QC_LOG2_STATUS_INTERVAL_MSEC,
+};
+
+static struct usb_endpoint_descriptor rndis_qc_fs_in_desc = {
+ .bLength = USB_DT_ENDPOINT_SIZE,
+ .bDescriptorType = USB_DT_ENDPOINT,
+
+ .bEndpointAddress = USB_DIR_IN,
+ .bmAttributes = USB_ENDPOINT_XFER_BULK,
+};
+
+static struct usb_endpoint_descriptor rndis_qc_fs_out_desc = {
+ .bLength = USB_DT_ENDPOINT_SIZE,
+ .bDescriptorType = USB_DT_ENDPOINT,
+
+ .bEndpointAddress = USB_DIR_OUT,
+ .bmAttributes = USB_ENDPOINT_XFER_BULK,
+};
+
+static struct usb_descriptor_header *eth_qc_fs_function[] = {
+ (struct usb_descriptor_header *) &rndis_qc_iad_descriptor,
+ /* control interface matches ACM, not Ethernet */
+ (struct usb_descriptor_header *) &rndis_qc_control_intf,
+ (struct usb_descriptor_header *) &rndis_qc_header_desc,
+ (struct usb_descriptor_header *) &rndis_qc_call_mgmt_descriptor,
+ (struct usb_descriptor_header *) &rndis_qc_acm_descriptor,
+ (struct usb_descriptor_header *) &rndis_qc_union_desc,
+ (struct usb_descriptor_header *) &rndis_qc_fs_notify_desc,
+ /* data interface has no altsetting */
+ (struct usb_descriptor_header *) &rndis_qc_data_intf,
+ (struct usb_descriptor_header *) &rndis_qc_fs_in_desc,
+ (struct usb_descriptor_header *) &rndis_qc_fs_out_desc,
+ NULL,
+};
+
+/* high speed support: */
+
+static struct usb_endpoint_descriptor rndis_qc_hs_notify_desc = {
+ .bLength = USB_DT_ENDPOINT_SIZE,
+ .bDescriptorType = USB_DT_ENDPOINT,
+
+ .bEndpointAddress = USB_DIR_IN,
+ .bmAttributes = USB_ENDPOINT_XFER_INT,
+ .wMaxPacketSize = cpu_to_le16(RNDIS_QC_STATUS_BYTECOUNT),
+ .bInterval = RNDIS_QC_LOG2_STATUS_INTERVAL_MSEC + 4,
+};
+static struct usb_endpoint_descriptor rndis_qc_hs_in_desc = {
+ .bLength = USB_DT_ENDPOINT_SIZE,
+ .bDescriptorType = USB_DT_ENDPOINT,
+
+ .bEndpointAddress = USB_DIR_IN,
+ .bmAttributes = USB_ENDPOINT_XFER_BULK,
+ .wMaxPacketSize = cpu_to_le16(512),
+};
+
+static struct usb_endpoint_descriptor rndis_qc_hs_out_desc = {
+ .bLength = USB_DT_ENDPOINT_SIZE,
+ .bDescriptorType = USB_DT_ENDPOINT,
+
+ .bEndpointAddress = USB_DIR_OUT,
+ .bmAttributes = USB_ENDPOINT_XFER_BULK,
+ .wMaxPacketSize = cpu_to_le16(512),
+};
+
+static struct usb_descriptor_header *eth_qc_hs_function[] = {
+ (struct usb_descriptor_header *) &rndis_qc_iad_descriptor,
+ /* control interface matches ACM, not Ethernet */
+ (struct usb_descriptor_header *) &rndis_qc_control_intf,
+ (struct usb_descriptor_header *) &rndis_qc_header_desc,
+ (struct usb_descriptor_header *) &rndis_qc_call_mgmt_descriptor,
+ (struct usb_descriptor_header *) &rndis_qc_acm_descriptor,
+ (struct usb_descriptor_header *) &rndis_qc_union_desc,
+ (struct usb_descriptor_header *) &rndis_qc_hs_notify_desc,
+ /* data interface has no altsetting */
+ (struct usb_descriptor_header *) &rndis_qc_data_intf,
+ (struct usb_descriptor_header *) &rndis_qc_hs_in_desc,
+ (struct usb_descriptor_header *) &rndis_qc_hs_out_desc,
+ NULL,
+};
+
+/* super speed support: */
+
+static struct usb_endpoint_descriptor rndis_qc_ss_notify_desc = {
+ .bLength = USB_DT_ENDPOINT_SIZE,
+ .bDescriptorType = USB_DT_ENDPOINT,
+
+ .bEndpointAddress = USB_DIR_IN,
+ .bmAttributes = USB_ENDPOINT_XFER_INT,
+ .wMaxPacketSize = cpu_to_le16(RNDIS_QC_STATUS_BYTECOUNT),
+ .bInterval = RNDIS_QC_LOG2_STATUS_INTERVAL_MSEC + 4,
+};
+
+static struct usb_ss_ep_comp_descriptor ss_intr_comp_desc = {
+ .bLength = sizeof(ss_intr_comp_desc),
+ .bDescriptorType = USB_DT_SS_ENDPOINT_COMP,
+
+ /* the following 3 values can be tweaked if necessary */
+ /* .bMaxBurst = 0, */
+ /* .bmAttributes = 0, */
+ .wBytesPerInterval = cpu_to_le16(RNDIS_QC_STATUS_BYTECOUNT),
+};
+
+static struct usb_ss_ep_comp_descriptor rndis_qc_ss_intr_comp_desc = {
+ .bLength = sizeof(ss_intr_comp_desc),
+ .bDescriptorType = USB_DT_SS_ENDPOINT_COMP,
+
+ /* the following 3 values can be tweaked if necessary */
+ /* .bMaxBurst = 0, */
+ /* .bmAttributes = 0, */
+ .wBytesPerInterval = cpu_to_le16(RNDIS_QC_STATUS_BYTECOUNT),
+};
+
+static struct usb_ss_ep_comp_descriptor ss_bulk_comp_desc = {
+ .bLength = sizeof(ss_bulk_comp_desc),
+ .bDescriptorType = USB_DT_SS_ENDPOINT_COMP,
+
+ /* the following 2 values can be tweaked if necessary */
+ /* .bMaxBurst = 0, */
+ /* .bmAttributes = 0, */
+};
+
+static struct usb_endpoint_descriptor rndis_qc_ss_in_desc = {
+ .bLength = USB_DT_ENDPOINT_SIZE,
+ .bDescriptorType = USB_DT_ENDPOINT,
+
+ .bEndpointAddress = USB_DIR_IN,
+ .bmAttributes = USB_ENDPOINT_XFER_BULK,
+ .wMaxPacketSize = cpu_to_le16(1024),
+};
+
+static struct usb_endpoint_descriptor rndis_qc_ss_out_desc = {
+ .bLength = USB_DT_ENDPOINT_SIZE,
+ .bDescriptorType = USB_DT_ENDPOINT,
+
+ .bEndpointAddress = USB_DIR_OUT,
+ .bmAttributes = USB_ENDPOINT_XFER_BULK,
+ .wMaxPacketSize = cpu_to_le16(1024),
+};
+
+static struct usb_ss_ep_comp_descriptor rndis_qc_ss_bulk_comp_desc = {
+ .bLength = sizeof(ss_bulk_comp_desc),
+ .bDescriptorType = USB_DT_SS_ENDPOINT_COMP,
+
+ /* the following 2 values can be tweaked if necessary */
+ /* .bMaxBurst = 0, */
+ /* .bmAttributes = 0, */
+};
+
+static struct usb_descriptor_header *eth_qc_ss_function[] = {
+ (struct usb_descriptor_header *) &rndis_qc_iad_descriptor,
+
+ /* control interface matches ACM, not Ethernet */
+ (struct usb_descriptor_header *) &rndis_qc_control_intf,
+ (struct usb_descriptor_header *) &rndis_qc_header_desc,
+ (struct usb_descriptor_header *) &rndis_qc_call_mgmt_descriptor,
+ (struct usb_descriptor_header *) &rndis_qc_acm_descriptor,
+ (struct usb_descriptor_header *) &rndis_qc_union_desc,
+ (struct usb_descriptor_header *) &rndis_qc_ss_notify_desc,
+ (struct usb_descriptor_header *) &rndis_qc_ss_intr_comp_desc,
+
+ /* data interface has no altsetting */
+ (struct usb_descriptor_header *) &rndis_qc_data_intf,
+ (struct usb_descriptor_header *) &rndis_qc_ss_in_desc,
+ (struct usb_descriptor_header *) &rndis_qc_ss_bulk_comp_desc,
+ (struct usb_descriptor_header *) &rndis_qc_ss_out_desc,
+ (struct usb_descriptor_header *) &rndis_qc_ss_bulk_comp_desc,
+ NULL,
+};
+
+/* string descriptors: */
+
+static struct usb_string rndis_qc_string_defs[] = {
+ [0].s = "RNDIS Communications Control",
+ [1].s = "RNDIS Ethernet Data",
+ [2].s = "RNDIS",
+ { } /* end of list */
+};
+
+static struct usb_gadget_strings rndis_qc_string_table = {
+ .language = 0x0409, /* en-us */
+ .strings = rndis_qc_string_defs,
+};
+
+static struct usb_gadget_strings *rndis_qc_strings[] = {
+ &rndis_qc_string_table,
+ NULL,
+};
+
+struct f_rndis_qc *_rndis_qc;
+
+static inline int rndis_qc_lock(atomic_t *excl)
+{
+ if (atomic_inc_return(excl) == 1)
+ return 0;
+
+ atomic_dec(excl);
+ return -EBUSY;
+}
+
+static inline void rndis_qc_unlock(atomic_t *excl)
+{
+ atomic_dec(excl);
+}
+
+/*-------------------------------------------------------------------------*/
+
+static void rndis_qc_response_available(void *_rndis)
+{
+ struct f_rndis_qc *rndis = _rndis;
+ struct usb_request *req = rndis->notify_req;
+ __le32 *data = req->buf;
+ int status;
+
+ if (atomic_inc_return(&rndis->notify_count) != 1)
+ return;
+
+ if (!rndis->notify->driver_data)
+ return;
+
+ /* Send RNDIS RESPONSE_AVAILABLE notification; a
+ * USB_CDC_NOTIFY_RESPONSE_AVAILABLE "should" work too
+ *
+ * This is the only notification defined by RNDIS.
+ */
+ data[0] = cpu_to_le32(1);
+ data[1] = cpu_to_le32(0);
+
+ status = usb_ep_queue(rndis->notify, req, GFP_ATOMIC);
+ if (status) {
+ atomic_dec(&rndis->notify_count);
+ pr_info("notify/0 --> %d\n", status);
+ }
+}
+
+static void rndis_qc_response_complete(struct usb_ep *ep,
+ struct usb_request *req)
+{
+ struct f_rndis_qc *rndis;
+ int status = req->status;
+ struct usb_composite_dev *cdev;
+ struct usb_ep *notify_ep;
+
+ spin_lock(&rndis_lock);
+ rndis = _rndis_qc;
+ if (!rndis || !rndis->notify || !rndis->notify->driver_data) {
+ spin_unlock(&rndis_lock);
+ return;
+ }
+
+ if (!rndis->func.config || !rndis->func.config->cdev) {
+ pr_err("%s(): cdev or config is NULL.\n", __func__);
+ spin_unlock(&rndis_lock);
+ return;
+ }
+
+ cdev = rndis->func.config->cdev;
+
+ /* after TX:
+ * - USB_CDC_GET_ENCAPSULATED_RESPONSE (ep0/control)
+ * - RNDIS_RESPONSE_AVAILABLE (status/irq)
+ */
+ switch (status) {
+ case -ECONNRESET:
+ case -ESHUTDOWN:
+ /* connection gone */
+ atomic_set(&rndis->notify_count, 0);
+ goto out;
+ default:
+ pr_info("RNDIS %s response error %d, %d/%d\n",
+ ep->name, status,
+ req->actual, req->length);
+ /* FALLTHROUGH */
+ case 0:
+ if (ep != rndis->notify)
+ goto out;
+
+ /* handle multiple pending RNDIS_RESPONSE_AVAILABLE
+ * notifications by resending until we're done
+ */
+ if (atomic_dec_and_test(&rndis->notify_count))
+ goto out;
+ notify_ep = rndis->notify;
+ spin_unlock(&rndis_lock);
+ status = usb_ep_queue(notify_ep, req, GFP_ATOMIC);
+ if (status) {
+ spin_lock(&rndis_lock);
+ if (!_rndis_qc)
+ goto out;
+ atomic_dec(&_rndis_qc->notify_count);
+ DBG(cdev, "notify/1 --> %d\n", status);
+ spin_unlock(&rndis_lock);
+ }
+ }
+
+ return;
+
+out:
+ spin_unlock(&rndis_lock);
+}
+
+static void rndis_qc_command_complete(struct usb_ep *ep,
+ struct usb_request *req)
+{
+ struct f_rndis_qc *rndis;
+ int status;
+ rndis_init_msg_type *buf;
+ u32 ul_max_xfer_size, dl_max_xfer_size;
+
+ if (req->status != 0) {
+ pr_err("%s: RNDIS command completion error %d\n",
+ __func__, req->status);
+ return;
+ }
+
+ spin_lock(&rndis_lock);
+ rndis = _rndis_qc;
+ if (!rndis || !rndis->notify || !rndis->notify->driver_data) {
+ spin_unlock(&rndis_lock);
+ return;
+ }
+
+ /* received RNDIS command from USB_CDC_SEND_ENCAPSULATED_COMMAND */
+ status = rndis_msg_parser(rndis->params, (u8 *) req->buf);
+ if (status < 0)
+ pr_err("RNDIS command error %d, %d/%d\n",
+ status, req->actual, req->length);
+
+ buf = (rndis_init_msg_type *)req->buf;
+
+ if (buf->MessageType == RNDIS_MSG_INIT) {
+ ul_max_xfer_size = rndis_get_ul_max_xfer_size(rndis->params);
+ ipa_data_set_ul_max_xfer_size(ul_max_xfer_size);
+ /*
+ * For consistent data throughput from IPA, it is required to
+ * fine tune aggregation byte limit as 7KB. RNDIS IPA driver
+ * use provided this value to calculate aggregation byte limit
+ * and program IPA hardware for aggregation.
+ * Host provides 8KB or 16KB as Max Transfer size, hence select
+ * minimum out of host provided value and optimum transfer size
+ * to get 7KB as aggregation byte limit.
+ */
+ if (rndis_dl_max_xfer_size)
+ dl_max_xfer_size = min_t(u32, rndis_dl_max_xfer_size,
+ rndis_get_dl_max_xfer_size(rndis->params));
+ else
+ dl_max_xfer_size =
+ rndis_get_dl_max_xfer_size(rndis->params);
+ ipa_data_set_dl_max_xfer_size(dl_max_xfer_size);
+ }
+ spin_unlock(&rndis_lock);
+}
+
+static int
+rndis_qc_setup(struct usb_function *f, const struct usb_ctrlrequest *ctrl)
+{
+ struct f_rndis_qc *rndis = func_to_rndis_qc(f);
+ struct usb_composite_dev *cdev = f->config->cdev;
+ struct usb_request *req = cdev->req;
+ int value = -EOPNOTSUPP;
+ u16 w_index = le16_to_cpu(ctrl->wIndex);
+ u16 w_value = le16_to_cpu(ctrl->wValue);
+ u16 w_length = le16_to_cpu(ctrl->wLength);
+
+ /* composite driver infrastructure handles everything except
+ * CDC class messages; interface activation uses set_alt().
+ */
+ pr_debug("%s: Enter\n", __func__);
+ switch ((ctrl->bRequestType << 8) | ctrl->bRequest) {
+
+ /* RNDIS uses the CDC command encapsulation mechanism to implement
+ * an RPC scheme, with much getting/setting of attributes by OID.
+ */
+ case ((USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE) << 8)
+ | USB_CDC_SEND_ENCAPSULATED_COMMAND:
+ if (w_value || w_index != rndis->ctrl_id)
+ goto invalid;
+ /* read the request; process it later */
+ value = w_length;
+ req->complete = rndis_qc_command_complete;
+ /* later, rndis_response_available() sends a notification */
+ break;
+
+ case ((USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE) << 8)
+ | USB_CDC_GET_ENCAPSULATED_RESPONSE:
+ if (w_value || w_index != rndis->ctrl_id)
+ goto invalid;
+ else {
+ u8 *buf;
+ u32 n;
+
+ /* return the result */
+ buf = rndis_get_next_response(rndis->params, &n);
+ if (buf) {
+ memcpy(req->buf, buf, n);
+ req->complete = rndis_qc_response_complete;
+ rndis_free_response(rndis->params, buf);
+ value = n;
+ }
+ /* else stalls ... spec says to avoid that */
+ }
+ break;
+
+ default:
+invalid:
+ VDBG(cdev, "invalid control req%02x.%02x v%04x i%04x l%d\n",
+ ctrl->bRequestType, ctrl->bRequest,
+ w_value, w_index, w_length);
+ }
+
+ /* respond with data transfer or status phase? */
+ if (value >= 0) {
+ DBG(cdev, "rndis req%02x.%02x v%04x i%04x l%d\n",
+ ctrl->bRequestType, ctrl->bRequest,
+ w_value, w_index, w_length);
+ req->context = rndis;
+ req->zero = (value < w_length);
+ req->length = value;
+ value = usb_ep_queue(cdev->gadget->ep0, req, GFP_ATOMIC);
+ if (value < 0)
+ pr_err("rndis response on err %d\n", value);
+ }
+
+ /* device either stalls (value < 0) or reports success */
+ return value;
+}
+
+struct net_device *rndis_qc_get_net(const char *netname)
+{
+ struct net_device *net_dev;
+
+ net_dev = dev_get_by_name(&init_net, netname);
+ if (!net_dev)
+ return ERR_PTR(-EINVAL);
+
+ /*
+ * Decrement net_dev refcount as it was incremented in
+ * dev_get_by_name().
+ */
+ dev_put(net_dev);
+ return net_dev;
+}
+
+static int rndis_qc_set_alt(struct usb_function *f, unsigned int intf,
+ unsigned int alt)
+{
+ struct f_rndis_qc *rndis = func_to_rndis_qc(f);
+ struct f_rndis_qc_opts *opts;
+ struct usb_composite_dev *cdev = f->config->cdev;
+ u8 src_connection_idx;
+ u8 dst_connection_idx;
+ enum usb_ctrl usb_bam_type;
+ int ret;
+
+ /* we know alt == 0 */
+
+ opts = container_of(f->fi, struct f_rndis_qc_opts, func_inst);
+ if (intf == rndis->ctrl_id) {
+ if (rndis->notify->driver_data) {
+ VDBG(cdev, "reset rndis control %d\n", intf);
+ usb_ep_disable(rndis->notify);
+ }
+ if (!rndis->notify->desc) {
+ VDBG(cdev, "init rndis ctrl %d\n", intf);
+ if (config_ep_by_speed(cdev->gadget, f, rndis->notify))
+ goto fail;
+ }
+ usb_ep_enable(rndis->notify);
+ rndis->notify->driver_data = rndis;
+
+ } else if (intf == rndis->data_id) {
+ struct net_device *net;
+
+ rndis->net_ready_trigger = false;
+ if (rndis->bam_port.in->driver_data) {
+ DBG(cdev, "reset rndis\n");
+ /* bam_port is needed for disconnecting the BAM data
+ * path. Only after the BAM data path is disconnected,
+ * we can disconnect the port from the network layer.
+ */
+ ipa_data_disconnect(&rndis->bam_port,
+ USB_IPA_FUNC_RNDIS);
+ }
+
+ if (!rndis->bam_port.in->desc || !rndis->bam_port.out->desc) {
+ DBG(cdev, "init rndis\n");
+ if (config_ep_by_speed(cdev->gadget, f,
+ rndis->bam_port.in) ||
+ config_ep_by_speed(cdev->gadget, f,
+ rndis->bam_port.out)) {
+ rndis->bam_port.in->desc = NULL;
+ rndis->bam_port.out->desc = NULL;
+ goto fail;
+ }
+ }
+
+ /* RNDIS should be in the "RNDIS uninitialized" state,
+ * either never activated or after rndis_uninit().
+ *
+ * We don't want data to flow here until a nonzero packet
+ * filter is set, at which point it enters "RNDIS data
+ * initialized" state ... but we do want the endpoints
+ * to be activated. It's a strange little state.
+ *
+ * REVISIT the RNDIS gadget code has done this wrong for a
+ * very long time. We need another call to the link layer
+ * code -- gether_updown(...bool) maybe -- to do it right.
+ */
+ rndis->cdc_filter = 0;
+
+ rndis->bam_port.cdev = cdev;
+ rndis->bam_port.func = &rndis->func;
+ ipa_data_port_select(USB_IPA_FUNC_RNDIS);
+ usb_bam_type = usb_bam_get_bam_type(cdev->gadget->name);
+
+ src_connection_idx = usb_bam_get_connection_idx(usb_bam_type,
+ IPA_P_BAM, USB_TO_PEER_PERIPHERAL, USB_BAM_DEVICE,
+ rndis->port_num);
+ dst_connection_idx = usb_bam_get_connection_idx(usb_bam_type,
+ IPA_P_BAM, PEER_PERIPHERAL_TO_USB, USB_BAM_DEVICE,
+ rndis->port_num);
+ if (src_connection_idx < 0 || dst_connection_idx < 0) {
+ pr_err("%s: usb_bam_get_connection_idx failed\n",
+ __func__);
+ return ret;
+ }
+ if (ipa_data_connect(&rndis->bam_port, USB_IPA_FUNC_RNDIS,
+ src_connection_idx, dst_connection_idx))
+ goto fail;
+
+ DBG(cdev, "RNDIS RX/TX early activation ...\n");
+ rndis_qc_open(rndis);
+ net = rndis_qc_get_net("rndis0");
+ if (IS_ERR(net))
+ return PTR_ERR(net);
+ opts->net = net;
+
+ rndis_set_param_dev(rndis->params, net,
+ &rndis->cdc_filter);
+ } else
+ goto fail;
+
+ return 0;
+fail:
+ return -EINVAL;
+}
+
+static void rndis_qc_disable(struct usb_function *f)
+{
+ struct f_rndis_qc *rndis = func_to_rndis_qc(f);
+ struct usb_composite_dev *cdev = f->config->cdev;
+ unsigned long flags;
+
+ if (!rndis->notify->driver_data)
+ return;
+
+ DBG(cdev, "rndis deactivated\n");
+
+ spin_lock_irqsave(&rndis_lock, flags);
+ rndis_uninit(rndis->params);
+ spin_unlock_irqrestore(&rndis_lock, flags);
+ ipa_data_disconnect(&rndis->bam_port, USB_IPA_FUNC_RNDIS);
+
+ msm_ep_unconfig(rndis->bam_port.out);
+ msm_ep_unconfig(rndis->bam_port.in);
+ usb_ep_disable(rndis->notify);
+ rndis->notify->driver_data = NULL;
+}
+
+static void rndis_qc_suspend(struct usb_function *f)
+{
+ struct f_rndis_qc *rndis = func_to_rndis_qc(f);
+ bool remote_wakeup_allowed;
+
+ if (f->config->cdev->gadget->speed == USB_SPEED_SUPER)
+ remote_wakeup_allowed = f->func_wakeup_allowed;
+ else
+ remote_wakeup_allowed = f->config->cdev->gadget->remote_wakeup;
+
+ pr_info("%s(): start rndis suspend: remote_wakeup_allowed:%d\n:",
+ __func__, remote_wakeup_allowed);
+
+ if (!remote_wakeup_allowed) {
+ /* This is required as Linux host side RNDIS driver doesn't
+ * send RNDIS_MESSAGE_PACKET_FILTER before suspending USB bus.
+ * Hence we perform same operations explicitly here for Linux
+ * host case. In case of windows, this RNDIS state machine is
+ * already updated due to receiving of PACKET_FILTER.
+ */
+ rndis_flow_control(rndis->params, true);
+ pr_debug("%s(): Disconnecting\n", __func__);
+ }
+
+ ipa_data_suspend(&rndis->bam_port, USB_IPA_FUNC_RNDIS,
+ remote_wakeup_allowed);
+ pr_debug("rndis suspended\n");
+}
+
+static void rndis_qc_resume(struct usb_function *f)
+{
+ struct f_rndis_qc *rndis = func_to_rndis_qc(f);
+ bool remote_wakeup_allowed;
+
+ pr_debug("%s: rndis resumed\n", __func__);
+
+ /* Nothing to do if DATA interface wasn't initialized */
+ if (!rndis->bam_port.cdev) {
+ pr_debug("data interface was not up\n");
+ return;
+ }
+
+ if (f->config->cdev->gadget->speed == USB_SPEED_SUPER)
+ remote_wakeup_allowed = f->func_wakeup_allowed;
+ else
+ remote_wakeup_allowed = f->config->cdev->gadget->remote_wakeup;
+
+ ipa_data_resume(&rndis->bam_port, USB_IPA_FUNC_RNDIS,
+ remote_wakeup_allowed);
+
+ if (!remote_wakeup_allowed) {
+ rndis_qc_open(rndis);
+ /*
+ * Linux Host doesn't sends RNDIS_MSG_INIT or non-zero value
+ * set with RNDIS_MESSAGE_PACKET_FILTER after performing bus
+ * resume. Hence trigger USB IPA transfer functionality
+ * explicitly here. For Windows host case is also being
+ * handle with RNDIS state machine.
+ */
+ rndis_flow_control(rndis->params, false);
+ }
+
+ pr_debug("%s: RNDIS resume completed\n", __func__);
+}
+
+/*-------------------------------------------------------------------------*/
+
+/*
+ * This isn't quite the same mechanism as CDC Ethernet, since the
+ * notification scheme passes less data, but the same set of link
+ * states must be tested. A key difference is that altsettings are
+ * not used to tell whether the link should send packets or not.
+ */
+
+static void rndis_qc_open(struct f_rndis_qc *rndis)
+{
+ struct usb_composite_dev *cdev = rndis->func.config->cdev;
+
+ DBG(cdev, "%s\n", __func__);
+
+ rndis_set_param_medium(rndis->params, RNDIS_MEDIUM_802_3,
+ rndis_qc_bitrate(cdev->gadget) / 100);
+ rndis_signal_connect(rndis->params);
+}
+
+void ipa_data_flow_control_enable(bool enable, struct rndis_params *param)
+{
+ if (enable)
+ ipa_data_stop_rndis_ipa(USB_IPA_FUNC_RNDIS);
+ else
+ ipa_data_start_rndis_ipa(USB_IPA_FUNC_RNDIS);
+}
+
+/*-------------------------------------------------------------------------*/
+
+/* ethernet function driver setup/binding */
+
+static int
+rndis_qc_bind(struct usb_configuration *c, struct usb_function *f)
+{
+ struct usb_composite_dev *cdev = c->cdev;
+ struct f_rndis_qc *rndis = func_to_rndis_qc(f);
+ struct rndis_params *params;
+ int status;
+ struct usb_ep *ep;
+
+ /* maybe allocate device-global string IDs */
+ if (rndis_qc_string_defs[0].id == 0) {
+
+ /* control interface label */
+ status = usb_string_id(c->cdev);
+ if (status < 0)
+ return status;
+ rndis_qc_string_defs[0].id = status;
+ rndis_qc_control_intf.iInterface = status;
+
+ /* data interface label */
+ status = usb_string_id(c->cdev);
+ if (status < 0)
+ return status;
+ rndis_qc_string_defs[1].id = status;
+ rndis_qc_data_intf.iInterface = status;
+
+ /* IAD iFunction label */
+ status = usb_string_id(c->cdev);
+ if (status < 0)
+ return status;
+ rndis_qc_string_defs[2].id = status;
+ rndis_qc_iad_descriptor.iFunction = status;
+ }
+
+ /* allocate instance-specific interface IDs */
+ status = usb_interface_id(c, f);
+ if (status < 0)
+ goto fail;
+ rndis->ctrl_id = status;
+ rndis_qc_iad_descriptor.bFirstInterface = status;
+
+ rndis_qc_control_intf.bInterfaceNumber = status;
+ rndis_qc_union_desc.bMasterInterface0 = status;
+
+ status = usb_interface_id(c, f);
+ if (status < 0)
+ goto fail;
+ rndis->data_id = status;
+
+ rndis_qc_data_intf.bInterfaceNumber = status;
+ rndis_qc_union_desc.bSlaveInterface0 = status;
+
+ status = -ENODEV;
+
+ /* allocate instance-specific endpoints */
+ ep = usb_ep_autoconfig(cdev->gadget, &rndis_qc_fs_in_desc);
+ if (!ep)
+ goto fail;
+ rndis->bam_port.in = ep;
+ ep->driver_data = cdev; /* claim */
+
+ ep = usb_ep_autoconfig(cdev->gadget, &rndis_qc_fs_out_desc);
+ if (!ep)
+ goto fail;
+ rndis->bam_port.out = ep;
+ ep->driver_data = cdev; /* claim */
+
+ /* NOTE: a status/notification endpoint is, strictly speaking,
+ * optional. We don't treat it that way though! It's simpler,
+ * and some newer profiles don't treat it as optional.
+ */
+ ep = usb_ep_autoconfig(cdev->gadget, &rndis_qc_fs_notify_desc);
+ if (!ep)
+ goto fail;
+ rndis->notify = ep;
+ ep->driver_data = cdev; /* claim */
+
+ status = -ENOMEM;
+
+ /* allocate notification request and buffer */
+ rndis->notify_req = usb_ep_alloc_request(ep, GFP_KERNEL);
+ if (!rndis->notify_req)
+ goto fail;
+ rndis->notify_req->buf = kmalloc(RNDIS_QC_STATUS_BYTECOUNT, GFP_KERNEL);
+ if (!rndis->notify_req->buf)
+ goto fail;
+ rndis->notify_req->length = RNDIS_QC_STATUS_BYTECOUNT;
+ rndis->notify_req->context = rndis;
+ rndis->notify_req->complete = rndis_qc_response_complete;
+
+ /* copy descriptors, and track endpoint copies */
+ f->fs_descriptors = usb_copy_descriptors(eth_qc_fs_function);
+ if (!f->fs_descriptors)
+ goto fail;
+
+ /* support all relevant hardware speeds... we expect that when
+ * hardware is dual speed, all bulk-capable endpoints work at
+ * both speeds
+ */
+ if (gadget_is_dualspeed(c->cdev->gadget)) {
+ rndis_qc_hs_in_desc.bEndpointAddress =
+ rndis_qc_fs_in_desc.bEndpointAddress;
+ rndis_qc_hs_out_desc.bEndpointAddress =
+ rndis_qc_fs_out_desc.bEndpointAddress;
+ rndis_qc_hs_notify_desc.bEndpointAddress =
+ rndis_qc_fs_notify_desc.bEndpointAddress;
+
+ /* copy descriptors, and track endpoint copies */
+ f->hs_descriptors = usb_copy_descriptors(eth_qc_hs_function);
+
+ if (!f->hs_descriptors)
+ goto fail;
+ }
+
+ if (gadget_is_superspeed(c->cdev->gadget)) {
+ rndis_qc_ss_in_desc.bEndpointAddress =
+ rndis_qc_fs_in_desc.bEndpointAddress;
+ rndis_qc_ss_out_desc.bEndpointAddress =
+ rndis_qc_fs_out_desc.bEndpointAddress;
+ rndis_qc_ss_notify_desc.bEndpointAddress =
+ rndis_qc_fs_notify_desc.bEndpointAddress;
+
+ /* copy descriptors, and track endpoint copies */
+ f->ss_descriptors = usb_copy_descriptors(eth_qc_ss_function);
+ if (!f->ss_descriptors)
+ goto fail;
+ }
+
+ params = rndis_register(rndis_qc_response_available, rndis,
+ ipa_data_flow_control_enable);
+ if (params < 0)
+ goto fail;
+ rndis->params = params;
+
+ rndis_set_param_medium(rndis->params, RNDIS_MEDIUM_802_3, 0);
+ rndis_set_host_mac(rndis->params, rndis->ethaddr);
+
+ if (rndis->manufacturer && rndis->vendorID &&
+ rndis_set_param_vendor(rndis->params, rndis->vendorID,
+ rndis->manufacturer))
+ goto fail;
+
+ pr_debug("%s(): max_pkt_per_xfer:%d\n", __func__,
+ rndis->ul_max_pkt_per_xfer);
+ rndis_set_max_pkt_xfer(rndis->params, rndis->ul_max_pkt_per_xfer);
+
+ /* In case of aggregated packets QC device will request
+ * aliment to 4 (2^2).
+ */
+ pr_debug("%s(): pkt_alignment_factor:%d\n", __func__,
+ rndis->pkt_alignment_factor);
+ rndis_set_pkt_alignment_factor(rndis->params,
+ rndis->pkt_alignment_factor);
+
+ /* NOTE: all that is done without knowing or caring about
+ * the network link ... which is unavailable to this code
+ * until we're activated via set_alt().
+ */
+
+ DBG(cdev, "RNDIS: %s speed IN/%s OUT/%s NOTIFY/%s\n",
+ gadget_is_superspeed(c->cdev->gadget) ? "super" :
+ gadget_is_dualspeed(c->cdev->gadget) ? "dual" : "full",
+ rndis->bam_port.in->name, rndis->bam_port.out->name,
+ rndis->notify->name);
+ return 0;
+
+fail:
+ if (gadget_is_superspeed(c->cdev->gadget) && f->ss_descriptors)
+ usb_free_descriptors(f->ss_descriptors);
+ if (gadget_is_dualspeed(c->cdev->gadget) && f->hs_descriptors)
+ usb_free_descriptors(f->hs_descriptors);
+ if (f->fs_descriptors)
+ usb_free_descriptors(f->fs_descriptors);
+
+ if (rndis->notify_req) {
+ kfree(rndis->notify_req->buf);
+ usb_ep_free_request(rndis->notify, rndis->notify_req);
+ }
+
+ /* we might as well release our claims on endpoints */
+ if (rndis->notify)
+ rndis->notify->driver_data = NULL;
+ if (rndis->bam_port.out->desc)
+ rndis->bam_port.out->driver_data = NULL;
+ if (rndis->bam_port.in->desc)
+ rndis->bam_port.in->driver_data = NULL;
+
+ pr_err("%s: can't bind, err %d\n", f->name, status);
+
+ return status;
+}
+
+static void rndis_qc_free(struct usb_function *f)
+{
+ struct f_rndis_qc_opts *opts;
+
+ opts = container_of(f->fi, struct f_rndis_qc_opts, func_inst);
+ opts->refcnt--;
+}
+
+static void
+rndis_qc_unbind(struct usb_configuration *c, struct usb_function *f)
+{
+ struct f_rndis_qc *rndis = func_to_rndis_qc(f);
+
+ pr_debug("rndis_qc_unbind: free\n");
+ rndis_deregister(rndis->params);
+
+ if (gadget_is_dualspeed(c->cdev->gadget))
+ usb_free_descriptors(f->hs_descriptors);
+ usb_free_descriptors(f->fs_descriptors);
+
+ kfree(rndis->notify_req->buf);
+ usb_ep_free_request(rndis->notify, rndis->notify_req);
+
+ /*
+ * call flush_workqueue to make sure that any pending
+ * disconnect_work() from u_bam_data.c file is being
+ * flushed before calling this rndis_ipa_cleanup API
+ * as rndis ipa disconnect API is required to be
+ * called before this.
+ */
+ ipa_data_flush_workqueue();
+ rndis_ipa_cleanup(rndis_ipa_params.private);
+ rndis_ipa_supported = false;
+
+}
+
+void rndis_ipa_reset_trigger(void)
+{
+ struct f_rndis_qc *rndis;
+
+ rndis = _rndis_qc;
+ if (!rndis) {
+ pr_err("%s: No RNDIS instance", __func__);
+ return;
+ }
+
+ rndis->net_ready_trigger = false;
+}
+
+/*
+ * Callback let RNDIS_IPA trigger us when network interface is up
+ * and userspace is ready to answer DHCP requests
+ */
+void rndis_net_ready_notify(void)
+{
+ struct f_rndis_qc *rndis;
+ unsigned long flags;
+
+ spin_lock_irqsave(&rndis_lock, flags);
+ rndis = _rndis_qc;
+ if (!rndis) {
+ pr_err("%s: No RNDIS instance", __func__);
+ spin_unlock_irqrestore(&rndis_lock, flags);
+ return;
+ }
+ if (rndis->net_ready_trigger) {
+ pr_err("%s: Already triggered", __func__);
+ spin_unlock_irqrestore(&rndis_lock, flags);
+ return;
+ }
+
+ pr_debug("%s: Set net_ready_trigger", __func__);
+ rndis->net_ready_trigger = true;
+ spin_unlock_irqrestore(&rndis_lock, flags);
+ ipa_data_start_rx_tx(USB_IPA_FUNC_RNDIS);
+}
+
+/**
+ * rndis_qc_bind_config - add RNDIS network link to a configuration
+ * @c: the configuration to support the network link
+ * @ethaddr: a buffer in which the ethernet address of the host side
+ * side of the link was recorded
+ * Context: single threaded during gadget setup
+ *
+ * Returns zero on success, else negative errno.
+ *
+ * Caller must have called @gether_setup(). Caller is also responsible
+ * for calling @gether_cleanup() before module unload.
+ */
+
+static struct
+usb_function *rndis_qc_bind_config_vendor(struct usb_function_instance *fi,
+ u32 vendorID, const char *manufacturer,
+ u8 max_pkt_per_xfer, u8 pkt_alignment_factor)
+{
+ struct f_rndis_qc_opts *opts = container_of(fi,
+ struct f_rndis_qc_opts, func_inst);
+ struct f_rndis_qc *rndis;
+ int status;
+
+ /* allocate and initialize one new instance */
+ status = -ENOMEM;
+
+ opts = container_of(fi, struct f_rndis_qc_opts, func_inst);
+
+ opts->refcnt++;
+ rndis = opts->rndis;
+
+ rndis->vendorID = opts->vendor_id;
+ rndis->manufacturer = opts->manufacturer;
+ /* export host's Ethernet address in CDC format */
+ random_ether_addr(rndis_ipa_params.host_ethaddr);
+ random_ether_addr(rndis_ipa_params.device_ethaddr);
+ pr_debug("setting host_ethaddr=%pM, device_ethaddr=%pM\n",
+ rndis_ipa_params.host_ethaddr,
+ rndis_ipa_params.device_ethaddr);
+ rndis_ipa_supported = true;
+ ether_addr_copy(rndis->ethaddr, rndis_ipa_params.host_ethaddr);
+ rndis_ipa_params.device_ready_notify = rndis_net_ready_notify;
+
+ /* if max_pkt_per_xfer was not configured set to default value */
+ rndis->ul_max_pkt_per_xfer =
+ max_pkt_per_xfer ? max_pkt_per_xfer :
+ DEFAULT_MAX_PKT_PER_XFER;
+ ipa_data_set_ul_max_pkt_num(rndis->ul_max_pkt_per_xfer);
+
+ /*
+ * Check no RNDIS aggregation, and alignment if not mentioned,
+ * use alignment factor as zero. If aggregated RNDIS data transfer,
+ * max packet per transfer would be default if it is not set
+ * explicitly, and same way use alignment factor as 2 by default.
+ * This would eliminate need of writing to sysfs if default RNDIS
+ * aggregation setting required. Writing to both sysfs entries,
+ * those values will always override default values.
+ */
+ if ((rndis->pkt_alignment_factor == 0) &&
+ (rndis->ul_max_pkt_per_xfer == 1))
+ rndis->pkt_alignment_factor = 0;
+ else
+ rndis->pkt_alignment_factor = pkt_alignment_factor ?
+ pkt_alignment_factor :
+ DEFAULT_PKT_ALIGNMENT_FACTOR;
+
+ /* RNDIS activates when the host changes this filter */
+ rndis->cdc_filter = 0;
+
+ rndis->func.name = "rndis";
+ rndis->func.strings = rndis_qc_strings;
+ /* descriptors are per-instance copies */
+ rndis->func.bind = rndis_qc_bind;
+ rndis->func.unbind = rndis_qc_unbind;
+ rndis->func.set_alt = rndis_qc_set_alt;
+ rndis->func.setup = rndis_qc_setup;
+ rndis->func.disable = rndis_qc_disable;
+ rndis->func.suspend = rndis_qc_suspend;
+ rndis->func.resume = rndis_qc_resume;
+ rndis->func.free_func = rndis_qc_free;
+
+ status = rndis_ipa_init(&rndis_ipa_params);
+ if (status) {
+ pr_err("%s: failed to init rndis_ipa\n", __func__);
+ goto fail;
+ }
+
+ _rndis_qc = rndis;
+
+ return &rndis->func;
+fail:
+ kfree(rndis);
+ _rndis_qc = NULL;
+ return ERR_PTR(status);
+}
+
+static struct usb_function *qcrndis_alloc(struct usb_function_instance *fi)
+{
+ return rndis_qc_bind_config_vendor(fi, 0, NULL, 0, 0);
+}
+
+static int rndis_qc_open_dev(struct inode *ip, struct file *fp)
+{
+ int ret = 0;
+ unsigned long flags;
+
+ pr_info("Open rndis QC driver\n");
+
+ spin_lock_irqsave(&rndis_lock, flags);
+ if (!_rndis_qc) {
+ pr_err("rndis_qc_dev not created yet\n");
+ ret = -ENODEV;
+ goto fail;
+ }
+
+ if (rndis_qc_lock(&_rndis_qc->open_excl)) {
+ pr_err("Already opened\n");
+ ret = -EBUSY;
+ goto fail;
+ }
+
+ fp->private_data = _rndis_qc;
+fail:
+ spin_unlock_irqrestore(&rndis_lock, flags);
+
+ if (!ret)
+ pr_info("rndis QC file opened\n");
+
+ return ret;
+}
+
+static int rndis_qc_release_dev(struct inode *ip, struct file *fp)
+{
+ unsigned long flags;
+
+ pr_info("Close rndis QC file\n");
+
+ spin_lock_irqsave(&rndis_lock, flags);
+
+ if (!_rndis_qc) {
+ pr_err("rndis_qc_dev not present\n");
+ spin_unlock_irqrestore(&rndis_lock, flags);
+ return -ENODEV;
+ }
+ rndis_qc_unlock(&_rndis_qc->open_excl);
+ spin_unlock_irqrestore(&rndis_lock, flags);
+ return 0;
+}
+
+static long rndis_qc_ioctl(struct file *fp, unsigned int cmd, unsigned long arg)
+{
+ u8 qc_max_pkt_per_xfer = 0;
+ u32 qc_max_pkt_size = 0;
+ int ret = 0;
+ unsigned long flags;
+
+ spin_lock_irqsave(&rndis_lock, flags);
+ if (!_rndis_qc) {
+ pr_err("rndis_qc_dev not present\n");
+ ret = -ENODEV;
+ goto fail;
+ }
+
+ qc_max_pkt_per_xfer = _rndis_qc->ul_max_pkt_per_xfer;
+ qc_max_pkt_size = _rndis_qc->max_pkt_size;
+
+ if (rndis_qc_lock(&_rndis_qc->ioctl_excl)) {
+ ret = -EBUSY;
+ goto fail;
+ }
+
+ spin_unlock_irqrestore(&rndis_lock, flags);
+
+ pr_info("Received command %d\n", cmd);
+
+ switch (cmd) {
+ case RNDIS_QC_GET_MAX_PKT_PER_XFER:
+ ret = copy_to_user((void __user *)arg,
+ &qc_max_pkt_per_xfer,
+ sizeof(qc_max_pkt_per_xfer));
+ if (ret) {
+ pr_err("copying to user space failed\n");
+ ret = -EFAULT;
+ }
+ pr_info("Sent UL max packets per xfer %d\n",
+ qc_max_pkt_per_xfer);
+ break;
+ case RNDIS_QC_GET_MAX_PKT_SIZE:
+ ret = copy_to_user((void __user *)arg,
+ &qc_max_pkt_size,
+ sizeof(qc_max_pkt_size));
+ if (ret) {
+ pr_err("copying to user space failed\n");
+ ret = -EFAULT;
+ }
+ pr_debug("Sent max packet size %d\n",
+ qc_max_pkt_size);
+ break;
+ default:
+ pr_err("Unsupported IOCTL\n");
+ ret = -EINVAL;
+ }
+
+ spin_lock_irqsave(&rndis_lock, flags);
+
+ if (!_rndis_qc) {
+ pr_err("rndis_qc_dev not present\n");
+ ret = -ENODEV;
+ goto fail;
+ }
+
+ rndis_qc_unlock(&_rndis_qc->ioctl_excl);
+
+fail:
+ spin_unlock_irqrestore(&rndis_lock, flags);
+ return ret;
+}
+
+static const struct file_operations rndis_qc_fops = {
+ .owner = THIS_MODULE,
+ .open = rndis_qc_open_dev,
+ .release = rndis_qc_release_dev,
+ .unlocked_ioctl = rndis_qc_ioctl,
+};
+
+static void qcrndis_free_inst(struct usb_function_instance *f)
+{
+ struct f_rndis_qc_opts *opts = container_of(f,
+ struct f_rndis_qc_opts, func_inst);
+ int minor = MINOR(opts->rndis->cdev.dev);
+ unsigned long flags;
+
+ device_destroy(rndis_class, MKDEV(MAJOR(rndis_dev), minor));
+ class_destroy(rndis_class);
+ cdev_del(&opts->rndis->cdev);
+ ida_simple_remove(&chardev_ida, minor);
+ unregister_chrdev_region(rndis_dev, 1);
+
+ ipa_data_free(USB_IPA_FUNC_RNDIS);
+ spin_lock_irqsave(&rndis_lock, flags);
+ kfree(opts->rndis);
+ _rndis_qc = NULL;
+ kfree(opts);
+ spin_unlock_irqrestore(&rndis_lock, flags);
+}
+
+static int qcrndis_set_inst_name(struct usb_function_instance *fi,
+ const char *name)
+{
+ struct f_rndis_qc_opts *opts = container_of(fi,
+ struct f_rndis_qc_opts, func_inst);
+ struct f_rndis_qc *rndis;
+ int name_len;
+ int ret, minor;
+
+ name_len = strlen(name) + 1;
+ if (name_len > MAX_INST_NAME_LEN)
+ return -ENAMETOOLONG;
+
+ pr_debug("initialize rndis QC instance\n");
+ rndis = kzalloc(sizeof(*rndis), GFP_KERNEL);
+ if (!rndis) {
+ pr_err("%s: fail allocate and initialize new instance\n",
+ __func__);
+ return -ENOMEM;
+ }
+
+ spin_lock_init(&rndis_lock);
+ opts->rndis = rndis;
+ rndis_class = class_create(THIS_MODULE, "usbrndis");
+ ret = alloc_chrdev_region(&rndis_dev, 0, 1, "usb_rndis");
+ if (ret < 0) {
+ pr_err("Fail to allocate usb rndis char dev region\n");
+ return ret;
+ }
+
+ /* get a minor number */
+ minor = ida_simple_get(&chardev_ida, 0, 0, GFP_KERNEL);
+ if (minor < 0) {
+ pr_err("%s: No more minor numbers left! rc:%d\n", __func__,
+ minor);
+ ret = -ENODEV;
+ goto fail_out_of_minors;
+ }
+ rndis->dev = device_create(rndis_class, NULL,
+ MKDEV(MAJOR(rndis_dev), minor),
+ rndis, "android_rndis_qc");
+ if (IS_ERR(rndis->dev)) {
+ ret = PTR_ERR(rndis->dev);
+ pr_err("%s: device_create failed for (%d)", __func__, ret);
+ goto fail_return_minor;
+ }
+ cdev_init(&rndis->cdev, &rndis_qc_fops);
+ ret = cdev_add(&rndis->cdev, MKDEV(MAJOR(rndis_dev), minor), 1);
+ if (ret < 0) {
+ pr_err("%s: cdev_add failed for %s (%d)", __func__,
+ name, ret);
+ goto fail_cdev_add;
+ }
+
+ if (ret)
+ pr_err("rndis QC driver failed to register\n");
+
+ ret = ipa_data_setup(USB_IPA_FUNC_RNDIS);
+ if (ret) {
+ pr_err("bam_data_setup failed err: %d\n", ret);
+ goto fail_data_setup;
+ }
+
+ return 0;
+fail_data_setup:
+ cdev_del(&rndis->cdev);
+fail_cdev_add:
+ device_destroy(rndis_class, MKDEV(MAJOR(rndis_dev), minor));
+fail_return_minor:
+ ida_simple_remove(&chardev_ida, minor);
+fail_out_of_minors:
+ unregister_chrdev_region(rndis_dev, 1);
+ class_destroy(rndis_class);
+ kfree(rndis);
+ return ret;
+}
+
+static inline
+struct f_rndis_qc_opts *to_f_qc_rndis_opts(struct config_item *item)
+{
+ return container_of(to_config_group(item), struct f_rndis_qc_opts,
+ func_inst.group);
+}
+
+static void qcrndis_attr_release(struct config_item *item)
+{
+ struct f_rndis_qc_opts *opts = to_f_qc_rndis_opts(item);
+
+ usb_put_function_instance(&opts->func_inst);
+}
+
+static struct configfs_item_operations qcrndis_item_ops = {
+ .release = qcrndis_attr_release,
+};
+
+static struct config_item_type qcrndis_func_type = {
+ .ct_item_ops = &qcrndis_item_ops,
+ .ct_owner = THIS_MODULE,
+};
+
+static struct usb_function_instance *qcrndis_alloc_inst(void)
+{
+ struct f_rndis_qc_opts *opts;
+
+ opts = kzalloc(sizeof(*opts), GFP_KERNEL);
+ if (!opts)
+ return ERR_PTR(-ENOMEM);
+
+ opts->func_inst.set_inst_name = qcrndis_set_inst_name;
+ opts->func_inst.free_func_inst = qcrndis_free_inst;
+
+ config_group_init_type_name(&opts->func_inst.group, "",
+ &qcrndis_func_type);
+
+ return &opts->func_inst;
+}
+
+void *rndis_qc_get_ipa_rx_cb(void)
+{
+ return rndis_ipa_params.ipa_rx_notify;
+}
+
+void *rndis_qc_get_ipa_tx_cb(void)
+{
+ return rndis_ipa_params.ipa_tx_notify;
+}
+
+void *rndis_qc_get_ipa_priv(void)
+{
+ return rndis_ipa_params.private;
+}
+
+bool rndis_qc_get_skip_ep_config(void)
+{
+ return rndis_ipa_params.skip_ep_cfg;
+}
+
+DECLARE_USB_FUNCTION_INIT(rndis_bam, qcrndis_alloc_inst, qcrndis_alloc);
+
+static int __init usb_qcrndis_init(void)
+{
+ int ret;
+
+ ret = usb_function_register(&rndis_bamusb_func);
+ if (ret) {
+ pr_err("%s: failed to register diag %d\n", __func__, ret);
+ return ret;
+ }
+ return ret;
+}
+
+static void __exit usb_qcrndis_exit(void)
+{
+ usb_function_unregister(&rndis_bamusb_func);
+}
+
+module_init(usb_qcrndis_init);
+module_exit(usb_qcrndis_exit);
+MODULE_DESCRIPTION("USB RMNET Function Driver");
diff --git a/drivers/usb/gadget/function/f_qdss.h b/drivers/usb/gadget/function/f_qdss.h
index 4ba2e9b..72edb90 100644
--- a/drivers/usb/gadget/function/f_qdss.h
+++ b/drivers/usb/gadget/function/f_qdss.h
@@ -31,6 +31,9 @@
u32 peer_pipe_idx;
unsigned long usb_bam_handle;
struct sps_mem_buffer *data_fifo;
+ unsigned long qdss_bam_iova;
+ phys_addr_t qdss_bam_phys;
+ u32 qdss_bam_size;
};
struct gqdss {
diff --git a/drivers/usb/gadget/function/rndis.c b/drivers/usb/gadget/function/rndis.c
index ac2231a..5d8e6fa 100644
--- a/drivers/usb/gadget/function/rndis.c
+++ b/drivers/usb/gadget/function/rndis.c
@@ -596,6 +596,7 @@
resp->AFListOffset = cpu_to_le32(0);
resp->AFListSize = cpu_to_le32(0);
+ params->ul_max_xfer_size = le32_to_cpu(resp->MaxTransferSize);
params->resp_avail(params->v);
return 0;
}
@@ -1015,6 +1016,18 @@
}
EXPORT_SYMBOL_GPL(rndis_set_param_medium);
+u32 rndis_get_dl_max_xfer_size(struct rndis_params *params)
+{
+ pr_debug("%s:\n", __func__);
+ return params->dl_max_xfer_size;
+}
+
+u32 rndis_get_ul_max_xfer_size(struct rndis_params *params)
+{
+ pr_debug("%s:\n", __func__);
+ return params->ul_max_xfer_size;
+}
+
void rndis_set_max_pkt_xfer(struct rndis_params *params, u8 max_pkt_per_xfer)
{
pr_debug("%s:\n", __func__);
diff --git a/drivers/usb/gadget/function/rndis.h b/drivers/usb/gadget/function/rndis.h
index 4ffc282..a3051c4 100644
--- a/drivers/usb/gadget/function/rndis.h
+++ b/drivers/usb/gadget/function/rndis.h
@@ -194,6 +194,7 @@
u32 host_rndis_major_ver;
u32 host_rndis_minor_ver;
u32 dl_max_xfer_size;
+ u32 ul_max_xfer_size;
const char *vendorDescr;
u8 pkt_alignment_factor;
void (*resp_avail)(void *v);
@@ -216,6 +217,8 @@
int rndis_set_param_medium(struct rndis_params *params, u32 medium,
u32 speed);
void rndis_set_max_pkt_xfer(struct rndis_params *params, u8 max_pkt_per_xfer);
+u32 rndis_get_ul_max_xfer_size(struct rndis_params *params);
+u32 rndis_get_dl_max_xfer_size(struct rndis_params *params);
void rndis_add_hdr(struct sk_buff *skb);
int rndis_rm_hdr(struct gether *port, struct sk_buff *skb,
struct sk_buff_head *list);
diff --git a/drivers/usb/gadget/function/u_data_ipa.c b/drivers/usb/gadget/function/u_data_ipa.c
new file mode 100644
index 0000000..f379028
--- /dev/null
+++ b/drivers/usb/gadget/function/u_data_ipa.c
@@ -0,0 +1,1402 @@
+/* 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.
+ */
+
+#include <linux/kernel.h>
+#include <linux/interrupt.h>
+#include <linux/device.h>
+#include <linux/delay.h>
+#include <linux/slab.h>
+#include <linux/termios.h>
+#include <linux/netdevice.h>
+#include <linux/debugfs.h>
+#include <linux/bitops.h>
+#include <linux/termios.h>
+#include <linux/usb_bam.h>
+
+#include "u_data_ipa.h"
+#include "u_rmnet.h"
+
+struct ipa_data_ch_info {
+ struct usb_request *rx_req;
+ struct usb_request *tx_req;
+ unsigned long flags;
+ unsigned int id;
+ enum ipa_func_type func_type;
+ bool is_connected;
+ unsigned int port_num;
+ spinlock_t port_lock;
+
+ struct work_struct connect_w;
+ struct work_struct disconnect_w;
+ struct work_struct suspend_w;
+ struct work_struct resume_w;
+
+ u32 src_pipe_idx;
+ u32 dst_pipe_idx;
+ u8 src_connection_idx;
+ u8 dst_connection_idx;
+ enum usb_ctrl usb_bam_type;
+ struct gadget_ipa_port *port_usb;
+ struct usb_gadget *gadget;
+ atomic_t pipe_connect_notified;
+ struct usb_bam_connect_ipa_params ipa_params;
+};
+
+struct rndis_data_ch_info {
+ /* this provides downlink (device->host i.e host) side configuration*/
+ u32 dl_max_transfer_size;
+ /* this provides uplink (host->device i.e device) side configuration */
+ u32 ul_max_transfer_size;
+ u32 ul_max_packets_number;
+ bool ul_aggregation_enable;
+ u32 prod_clnt_hdl;
+ u32 cons_clnt_hdl;
+ void *priv;
+};
+
+static struct workqueue_struct *ipa_data_wq;
+struct ipa_data_ch_info *ipa_data_ports[IPA_N_PORTS];
+static struct rndis_data_ch_info *rndis_data;
+/**
+ * ipa_data_endless_complete() - completion callback for endless TX/RX request
+ * @ep: USB endpoint for which this completion happen
+ * @req: USB endless request
+ *
+ * This completion is being called when endless (TX/RX) transfer is terminated
+ * i.e. disconnect or suspend case.
+ */
+static void ipa_data_endless_complete(struct usb_ep *ep,
+ struct usb_request *req)
+{
+ pr_debug("%s: endless complete for(%s) with status: %d\n",
+ __func__, ep->name, req->status);
+}
+
+/**
+ * ipa_data_start_endless_xfer() - configure USB endpoint and
+ * queue endless TX/RX request
+ * @port: USB IPA data channel information
+ * @in: USB endpoint direction i.e. true: IN(Device TX), false: OUT(Device RX)
+ *
+ * It is being used to queue endless TX/RX request with UDC driver.
+ * It does set required DBM endpoint configuration before queueing endless
+ * TX/RX request.
+ */
+static void ipa_data_start_endless_xfer(struct ipa_data_ch_info *port, bool in)
+{
+ unsigned long flags;
+ int status;
+ struct usb_ep *ep;
+
+ spin_lock_irqsave(&port->port_lock, flags);
+ if (!port->port_usb || (in && !port->tx_req)
+ || (!in && !port->rx_req)) {
+ spin_unlock_irqrestore(&port->port_lock, flags);
+ pr_err("%s(): port_usb/req is NULL.\n", __func__);
+ return;
+ }
+
+ if (in)
+ ep = port->port_usb->in;
+ else
+ ep = port->port_usb->out;
+
+ spin_unlock_irqrestore(&port->port_lock, flags);
+
+ if (in) {
+ pr_debug("%s: enqueue endless TX_REQ(IN)\n", __func__);
+ status = usb_ep_queue(ep, port->tx_req, GFP_ATOMIC);
+ if (status)
+ pr_err("error enqueuing endless TX_REQ, %d\n", status);
+ } else {
+ pr_debug("%s: enqueue endless RX_REQ(OUT)\n", __func__);
+ status = usb_ep_queue(ep, port->rx_req, GFP_ATOMIC);
+ if (status)
+ pr_err("error enqueuing endless RX_REQ, %d\n", status);
+ }
+}
+
+/**
+ * ipa_data_stop_endless_xfer() - terminate and dequeue endless TX/RX request
+ * @port: USB IPA data channel information
+ * @in: USB endpoint direction i.e. IN - Device TX, OUT - Device RX
+ *
+ * It is being used to terminate and dequeue endless TX/RX request with UDC
+ * driver.
+ */
+static void ipa_data_stop_endless_xfer(struct ipa_data_ch_info *port, bool in)
+{
+ unsigned long flags;
+ int status;
+ struct usb_ep *ep;
+
+ spin_lock_irqsave(&port->port_lock, flags);
+ if (!port->port_usb || (in && !port->tx_req)
+ || (!in && !port->rx_req)) {
+ spin_unlock_irqrestore(&port->port_lock, flags);
+ pr_err("%s(): port_usb/req is NULL.\n", __func__);
+ return;
+ }
+
+ if (in)
+ ep = port->port_usb->in;
+ else
+ ep = port->port_usb->out;
+
+ spin_unlock_irqrestore(&port->port_lock, flags);
+
+ if (in) {
+ pr_debug("%s: dequeue endless TX_REQ(IN)\n", __func__);
+ status = usb_ep_dequeue(ep, port->tx_req);
+ if (status)
+ pr_err("error dequeueing endless TX_REQ, %d\n", status);
+ } else {
+ pr_debug("%s: dequeue endless RX_REQ(OUT)\n", __func__);
+ status = usb_ep_dequeue(ep, port->rx_req);
+ if (status)
+ pr_err("error dequeueing endless RX_REQ, %d\n", status);
+ }
+}
+
+/*
+ * Called when IPA triggers us that the network interface is up.
+ * Starts the transfers on bulk endpoints.
+ * (optimization reasons, the pipes and bam with IPA are already connected)
+ */
+void ipa_data_start_rx_tx(enum ipa_func_type func)
+{
+ struct ipa_data_ch_info *port;
+ unsigned long flags;
+ struct usb_ep *epin, *epout;
+
+ pr_debug("%s: Triggered: starting tx, rx", __func__);
+ /* queue in & out requests */
+ port = ipa_data_ports[func];
+ if (!port) {
+ pr_err("%s: port is NULL, can't start tx, rx", __func__);
+ return;
+ }
+
+ spin_lock_irqsave(&port->port_lock, flags);
+
+ if (!port->port_usb || !port->port_usb->in ||
+ !port->port_usb->out) {
+ pr_err("%s: Can't start tx, rx, ep not enabled", __func__);
+ spin_unlock_irqrestore(&port->port_lock, flags);
+ return;
+ }
+
+ if (!port->rx_req || !port->tx_req) {
+ pr_err("%s: No request d->rx_req=%pK, d->tx_req=%pK", __func__,
+ port->rx_req, port->tx_req);
+ spin_unlock_irqrestore(&port->port_lock, flags);
+ return;
+ }
+ if (!port->is_connected) {
+ pr_debug("%s: pipes are disconnected", __func__);
+ spin_unlock_irqrestore(&port->port_lock, flags);
+ return;
+ }
+
+ epout = port->port_usb->out;
+ epin = port->port_usb->in;
+ spin_unlock_irqrestore(&port->port_lock, flags);
+
+ /* queue in & out requests */
+ pr_debug("%s: Starting rx", __func__);
+ if (epout)
+ ipa_data_start_endless_xfer(port, false);
+
+ pr_debug("%s: Starting tx", __func__);
+ if (epin)
+ ipa_data_start_endless_xfer(port, true);
+}
+/**
+ * ipa_data_disconnect_work() - Perform USB IPA BAM disconnect
+ * @w: disconnect work
+ *
+ * It is being schedule from ipa_data_disconnect() API when particular function
+ * is being disable due to USB disconnect or USB composition switch is being
+ * trigger . This API performs disconnect of USB BAM pipe, IPA BAM pipe and also
+ * initiate USB IPA BAM pipe handshake for USB Disconnect sequence. Due to
+ * handshake operation and involvement of SPS related APIs, this functioality
+ * can't be used from atomic context.
+ */
+static void ipa_data_disconnect_work(struct work_struct *w)
+{
+ struct ipa_data_ch_info *port = container_of(w, struct ipa_data_ch_info,
+ disconnect_w);
+ unsigned long flags;
+ int ret;
+
+ spin_lock_irqsave(&port->port_lock, flags);
+ if (!port->is_connected) {
+ spin_unlock_irqrestore(&port->port_lock, flags);
+ pr_debug("Already disconnected.\n");
+ return;
+ }
+ port->is_connected = false;
+ pr_debug("%s(): prod_clnt_hdl:%d cons_clnt_hdl:%d\n", __func__,
+ port->ipa_params.prod_clnt_hdl,
+ port->ipa_params.cons_clnt_hdl);
+
+ spin_unlock_irqrestore(&port->port_lock, flags);
+ ret = usb_bam_disconnect_ipa(port->usb_bam_type, &port->ipa_params);
+ if (ret)
+ pr_err("usb_bam_disconnect_ipa failed: err:%d\n", ret);
+
+ if (port->func_type == USB_IPA_FUNC_RNDIS) {
+ /*
+ * NOTE: it is required to disconnect USB and IPA BAM related
+ * pipes before calling IPA tethered function related disconnect
+ * API. IPA tethered function related disconnect API delete
+ * depedency graph with IPA RM which would results into IPA not
+ * pulling data although there is pending data on USB BAM
+ * producer pipe.
+ */
+ if (atomic_xchg(&port->pipe_connect_notified, 0) == 1) {
+ void *priv;
+
+ priv = rndis_qc_get_ipa_priv();
+ rndis_ipa_pipe_disconnect_notify(priv);
+ }
+ }
+
+ if (port->ipa_params.prod_clnt_hdl)
+ usb_bam_free_fifos(port->usb_bam_type,
+ port->dst_connection_idx);
+ if (port->ipa_params.cons_clnt_hdl)
+ usb_bam_free_fifos(port->usb_bam_type,
+ port->src_connection_idx);
+
+ if (port->func_type == USB_IPA_FUNC_RMNET)
+ teth_bridge_disconnect(port->ipa_params.src_client);
+ /*
+ * Decrement usage count which was incremented
+ * upon cable connect or cable disconnect in suspended state.
+ */
+ usb_gadget_autopm_put_async(port->gadget);
+
+ pr_debug("%s(): disconnect work completed.\n", __func__);
+}
+
+/**
+ * ipa_data_disconnect() - Restore USB ep operation and disable USB endpoint
+ * @gp: USB gadget IPA Port
+ * @port_num: Port num used by function driver which need to be disable
+ *
+ * It is being called from atomic context from gadget driver when particular
+ * function is being disable due to USB cable disconnect or USB composition
+ * switch is being trigger. This API performs restoring USB endpoint operation
+ * and disable USB endpoint used for accelerated path.
+ */
+void ipa_data_disconnect(struct gadget_ipa_port *gp, enum ipa_func_type func)
+{
+ struct ipa_data_ch_info *port;
+ unsigned long flags;
+ struct usb_gadget *gadget = NULL;
+
+ pr_debug("dev:%pK port number:%d\n", gp, func);
+ if (func >= USB_IPA_NUM_FUNCS) {
+ pr_err("invalid ipa portno#%d\n", func);
+ return;
+ }
+
+ if (!gp) {
+ pr_err("data port is null\n");
+ return;
+ }
+
+ port = ipa_data_ports[func];
+ if (!port) {
+ pr_err("port %u is NULL", func);
+ return;
+ }
+
+ spin_lock_irqsave(&port->port_lock, flags);
+ if (port->port_usb) {
+ gadget = port->port_usb->cdev->gadget;
+ port->port_usb->ipa_consumer_ep = -1;
+ port->port_usb->ipa_producer_ep = -1;
+
+ if (port->port_usb->in) {
+ /*
+ * Disable endpoints.
+ * Unlocking is needed since disabling the eps might
+ * stop active transfers and therefore the request
+ * complete function will be called, where we try
+ * to obtain the spinlock as well.
+ */
+ msm_ep_unconfig(port->port_usb->in);
+ spin_unlock_irqrestore(&port->port_lock, flags);
+ usb_ep_disable(port->port_usb->in);
+ spin_lock_irqsave(&port->port_lock, flags);
+ if (port->tx_req) {
+ usb_ep_free_request(port->port_usb->in,
+ port->tx_req);
+ port->tx_req = NULL;
+ }
+ port->port_usb->in->endless = false;
+ }
+
+ if (port->port_usb->out) {
+ msm_ep_unconfig(port->port_usb->out);
+ spin_unlock_irqrestore(&port->port_lock, flags);
+ usb_ep_disable(port->port_usb->out);
+ spin_lock_irqsave(&port->port_lock, flags);
+ if (port->rx_req) {
+ usb_ep_free_request(port->port_usb->out,
+ port->rx_req);
+ port->rx_req = NULL;
+ }
+ port->port_usb->out->endless = false;
+ }
+
+ port->port_usb = NULL;
+ }
+ spin_unlock_irqrestore(&port->port_lock, flags);
+ queue_work(ipa_data_wq, &port->disconnect_w);
+}
+
+/**
+ * configure_fifo() - Configure USB BAM Pipe's data FIFO
+ * @idx: USB BAM Pipe index
+ * @ep: USB endpoint
+ *
+ * This function configures USB BAM data fifo using fetched pipe configuraion
+ * using provided index value. This function needs to used before starting
+ * endless transfer.
+ */
+static void configure_fifo(enum usb_ctrl bam_type, u8 idx, struct usb_ep *ep)
+{
+ struct sps_mem_buffer data_fifo = {0};
+ u32 usb_bam_pipe_idx;
+
+ get_bam2bam_connection_info(bam_type, idx,
+ &usb_bam_pipe_idx,
+ NULL, &data_fifo, NULL);
+ msm_data_fifo_config(ep, data_fifo.phys_base, data_fifo.size,
+ usb_bam_pipe_idx);
+}
+
+/**
+ * ipa_data_connect_work() - Perform USB IPA BAM connect
+ * @w: connect work
+ *
+ * It is being schedule from ipa_data_connect() API when particular function
+ * which is using USB IPA accelerated path. This API performs allocating request
+ * for USB endpoint (tx/rx) for endless purpose, configure USB endpoint to be
+ * used in accelerated path, connect of USB BAM pipe, IPA BAM pipe and also
+ * initiate USB IPA BAM pipe handshake for connect sequence.
+ */
+static void ipa_data_connect_work(struct work_struct *w)
+{
+ struct ipa_data_ch_info *port = container_of(w, struct ipa_data_ch_info,
+ connect_w);
+ struct gadget_ipa_port *gport;
+ struct usb_gadget *gadget = NULL;
+ struct teth_bridge_connect_params connect_params;
+ struct teth_bridge_init_params teth_bridge_params;
+ u32 sps_params;
+ int ret;
+ unsigned long flags;
+ bool is_ipa_disconnected = true;
+
+ pr_debug("%s: Connect workqueue started\n", __func__);
+
+ spin_lock_irqsave(&port->port_lock, flags);
+
+ if (!port->port_usb) {
+ spin_unlock_irqrestore(&port->port_lock, flags);
+ usb_gadget_autopm_put_async(port->gadget);
+ pr_err("%s(): port_usb is NULL.\n", __func__);
+ return;
+ }
+
+ gport = port->port_usb;
+ if (gport && gport->cdev)
+ gadget = gport->cdev->gadget;
+
+ if (!gadget) {
+ spin_unlock_irqrestore(&port->port_lock, flags);
+ usb_gadget_autopm_put_async(port->gadget);
+ pr_err("%s: gport is NULL.\n", __func__);
+ return;
+ }
+
+ /*
+ * check if connect_w got called two times during RNDIS resume as
+ * explicit flow control is called to start data transfers after
+ * ipa_data_connect()
+ */
+ if (port->is_connected) {
+ pr_debug("IPA connect is already done & Transfers started\n");
+ spin_unlock_irqrestore(&port->port_lock, flags);
+ usb_gadget_autopm_put_async(port->gadget);
+ return;
+ }
+
+ gport->ipa_consumer_ep = -1;
+ gport->ipa_producer_ep = -1;
+
+ port->is_connected = true;
+
+ /* update IPA Parameteres here. */
+ port->ipa_params.usb_connection_speed = gadget->speed;
+ port->ipa_params.reset_pipe_after_lpm =
+ msm_dwc3_reset_ep_after_lpm(gadget);
+ port->ipa_params.skip_ep_cfg = true;
+ port->ipa_params.keep_ipa_awake = true;
+ port->ipa_params.cons_clnt_hdl = -1;
+ port->ipa_params.prod_clnt_hdl = -1;
+
+ if (gport->out) {
+ spin_unlock_irqrestore(&port->port_lock, flags);
+ usb_bam_alloc_fifos(port->usb_bam_type,
+ port->src_connection_idx);
+ spin_lock_irqsave(&port->port_lock, flags);
+ if (!port->port_usb || port->rx_req == NULL) {
+ spin_unlock_irqrestore(&port->port_lock, flags);
+ pr_err("%s: port_usb is NULL, or rx_req cleaned\n",
+ __func__);
+ goto out;
+ }
+
+ sps_params = MSM_SPS_MODE | MSM_DISABLE_WB
+ | MSM_PRODUCER | port->src_pipe_idx;
+ port->rx_req->length = 32*1024;
+ port->rx_req->udc_priv = sps_params;
+ configure_fifo(port->usb_bam_type,
+ port->src_connection_idx,
+ port->port_usb->out);
+ ret = msm_ep_config(gport->out);
+ if (ret) {
+ pr_err("msm_ep_config() failed for OUT EP\n");
+ spin_unlock_irqrestore(&port->port_lock, flags);
+ goto out;
+ }
+ }
+
+ if (gport->in) {
+ spin_unlock_irqrestore(&port->port_lock, flags);
+ usb_bam_alloc_fifos(port->usb_bam_type,
+ port->dst_connection_idx);
+ spin_lock_irqsave(&port->port_lock, flags);
+ if (!port->port_usb || port->tx_req == NULL) {
+ spin_unlock_irqrestore(&port->port_lock, flags);
+ pr_err("%s: port_usb is NULL, or tx_req cleaned\n",
+ __func__);
+ goto unconfig_msm_ep_out;
+ }
+ sps_params = MSM_SPS_MODE | MSM_DISABLE_WB |
+ port->dst_pipe_idx;
+ port->tx_req->length = 32*1024;
+ port->tx_req->udc_priv = sps_params;
+ configure_fifo(port->usb_bam_type,
+ port->dst_connection_idx, gport->in);
+ ret = msm_ep_config(gport->in);
+ if (ret) {
+ pr_err("msm_ep_config() failed for IN EP\n");
+ spin_unlock_irqrestore(&port->port_lock, flags);
+ goto unconfig_msm_ep_out;
+ }
+ }
+
+ if (port->func_type == USB_IPA_FUNC_RMNET) {
+ teth_bridge_params.client = port->ipa_params.src_client;
+ ret = teth_bridge_init(&teth_bridge_params);
+ if (ret) {
+ pr_err("%s:teth_bridge_init() failed\n", __func__);
+ spin_unlock_irqrestore(&port->port_lock, flags);
+ goto unconfig_msm_ep_in;
+ }
+ }
+
+ /*
+ * Perform below operations for Tx from Device (OUT transfer)
+ * 1. Connect with pipe of USB BAM with IPA BAM pipe
+ * 2. Update USB Endpoint related information using SPS Param.
+ * 3. Configure USB Endpoint/DBM for the same.
+ * 4. Override USB ep queue functionality for endless transfer.
+ */
+ if (gport->out) {
+ pr_debug("configure bam ipa connect for USB OUT\n");
+ port->ipa_params.dir = USB_TO_PEER_PERIPHERAL;
+
+ if (port->func_type == USB_IPA_FUNC_RNDIS) {
+ port->ipa_params.notify = rndis_qc_get_ipa_rx_cb();
+ port->ipa_params.priv = rndis_qc_get_ipa_priv();
+ port->ipa_params.skip_ep_cfg =
+ rndis_qc_get_skip_ep_config();
+ } else if (port->func_type == USB_IPA_FUNC_RMNET) {
+ port->ipa_params.notify =
+ teth_bridge_params.usb_notify_cb;
+ port->ipa_params.priv =
+ teth_bridge_params.private_data;
+ port->ipa_params.reset_pipe_after_lpm =
+ msm_dwc3_reset_ep_after_lpm(gadget);
+ port->ipa_params.ipa_ep_cfg.mode.mode = IPA_BASIC;
+ port->ipa_params.skip_ep_cfg =
+ teth_bridge_params.skip_ep_cfg;
+ }
+
+ spin_unlock_irqrestore(&port->port_lock, flags);
+ ret = usb_bam_connect_ipa(port->usb_bam_type,
+ &port->ipa_params);
+ if (ret) {
+ pr_err("usb_bam_connect_ipa out failed err:%d\n", ret);
+ goto disconnect_usb_bam_ipa_out;
+ }
+ spin_lock_irqsave(&port->port_lock, flags);
+ is_ipa_disconnected = false;
+ /* check if USB cable is disconnected or not */
+ if (!port->port_usb) {
+ pr_debug("%s:%d: cable is disconnected.\n",
+ __func__, __LINE__);
+ spin_unlock_irqrestore(&port->port_lock, flags);
+ goto disconnect_usb_bam_ipa_out;
+ }
+
+ gport->ipa_consumer_ep = port->ipa_params.ipa_cons_ep_idx;
+ }
+
+ if (gport->in) {
+ pr_debug("configure bam ipa connect for USB IN\n");
+ port->ipa_params.dir = PEER_PERIPHERAL_TO_USB;
+
+ if (port->func_type == USB_IPA_FUNC_RNDIS) {
+ port->ipa_params.notify = rndis_qc_get_ipa_tx_cb();
+ port->ipa_params.priv = rndis_qc_get_ipa_priv();
+ port->ipa_params.skip_ep_cfg =
+ rndis_qc_get_skip_ep_config();
+ } else if (port->func_type == USB_IPA_FUNC_RMNET) {
+ port->ipa_params.notify =
+ teth_bridge_params.usb_notify_cb;
+ port->ipa_params.priv =
+ teth_bridge_params.private_data;
+ port->ipa_params.reset_pipe_after_lpm =
+ msm_dwc3_reset_ep_after_lpm(gadget);
+ port->ipa_params.ipa_ep_cfg.mode.mode = IPA_BASIC;
+ port->ipa_params.skip_ep_cfg =
+ teth_bridge_params.skip_ep_cfg;
+ }
+
+ if (port->func_type == USB_IPA_FUNC_DPL)
+ port->ipa_params.dst_client = IPA_CLIENT_USB_DPL_CONS;
+ spin_unlock_irqrestore(&port->port_lock, flags);
+ ret = usb_bam_connect_ipa(port->usb_bam_type,
+ &port->ipa_params);
+ if (ret) {
+ pr_err("usb_bam_connect_ipa IN failed err:%d\n", ret);
+ goto disconnect_usb_bam_ipa_out;
+ }
+ spin_lock_irqsave(&port->port_lock, flags);
+ is_ipa_disconnected = false;
+ /* check if USB cable is disconnected or not */
+ if (!port->port_usb) {
+ pr_debug("%s:%d: cable is disconnected.\n",
+ __func__, __LINE__);
+ spin_unlock_irqrestore(&port->port_lock, flags);
+ goto disconnect_usb_bam_ipa_out;
+ }
+
+ gport->ipa_producer_ep = port->ipa_params.ipa_prod_ep_idx;
+ }
+
+ spin_unlock_irqrestore(&port->port_lock, flags);
+ if (port->func_type == USB_IPA_FUNC_RNDIS) {
+ rndis_data->prod_clnt_hdl =
+ port->ipa_params.prod_clnt_hdl;
+ rndis_data->cons_clnt_hdl =
+ port->ipa_params.cons_clnt_hdl;
+ rndis_data->priv = port->ipa_params.priv;
+
+ pr_debug("ul_max_transfer_size:%d\n",
+ rndis_data->ul_max_transfer_size);
+ pr_debug("ul_max_packets_number:%d\n",
+ rndis_data->ul_max_packets_number);
+ pr_debug("dl_max_transfer_size:%d\n",
+ rndis_data->dl_max_transfer_size);
+
+ ret = rndis_ipa_pipe_connect_notify(
+ rndis_data->cons_clnt_hdl,
+ rndis_data->prod_clnt_hdl,
+ rndis_data->ul_max_transfer_size,
+ rndis_data->ul_max_packets_number,
+ rndis_data->dl_max_transfer_size,
+ rndis_data->priv);
+ if (ret) {
+ pr_err("%s: failed to connect IPA: err:%d\n",
+ __func__, ret);
+ return;
+ }
+ atomic_set(&port->pipe_connect_notified, 1);
+ } else if (port->func_type == USB_IPA_FUNC_RMNET ||
+ port->func_type == USB_IPA_FUNC_DPL) {
+ /* For RmNet and DPL need to update_ipa_pipes to qti */
+ enum qti_port_type qti_port_type = port->func_type ==
+ USB_IPA_FUNC_RMNET ? QTI_PORT_RMNET : QTI_PORT_DPL;
+ gqti_ctrl_update_ipa_pipes(port->port_usb, qti_port_type,
+ gport->ipa_producer_ep, gport->ipa_consumer_ep);
+ }
+
+ if (port->func_type == USB_IPA_FUNC_RMNET) {
+ connect_params.ipa_usb_pipe_hdl =
+ port->ipa_params.prod_clnt_hdl;
+ connect_params.usb_ipa_pipe_hdl =
+ port->ipa_params.cons_clnt_hdl;
+ connect_params.tethering_mode =
+ TETH_TETHERING_MODE_RMNET;
+ connect_params.client_type =
+ port->ipa_params.src_client;
+ ret = teth_bridge_connect(&connect_params);
+ if (ret) {
+ pr_err("%s:teth_bridge_connect() failed\n", __func__);
+ goto disconnect_usb_bam_ipa_out;
+ }
+ }
+
+ pr_debug("ipa_producer_ep:%d ipa_consumer_ep:%d\n",
+ gport->ipa_producer_ep,
+ gport->ipa_consumer_ep);
+
+ pr_debug("src_bam_idx:%d dst_bam_idx:%d\n",
+ port->src_connection_idx, port->dst_connection_idx);
+
+ /* Don't queue the transfers yet, only after network stack is up */
+ if (port->func_type == USB_IPA_FUNC_RNDIS) {
+ pr_debug("%s: Not starting now, waiting for network notify",
+ __func__);
+ return;
+ }
+
+ if (gport->out)
+ ipa_data_start_endless_xfer(port, false);
+ if (gport->in)
+ ipa_data_start_endless_xfer(port, true);
+
+ pr_debug("Connect workqueue done (port %pK)", port);
+ return;
+
+disconnect_usb_bam_ipa_out:
+ if (!is_ipa_disconnected) {
+ usb_bam_disconnect_ipa(port->usb_bam_type, &port->ipa_params);
+ is_ipa_disconnected = true;
+ }
+ if (port->func_type == USB_IPA_FUNC_RMNET)
+ teth_bridge_disconnect(port->ipa_params.src_client);
+unconfig_msm_ep_in:
+ spin_lock_irqsave(&port->port_lock, flags);
+ /* check if USB cable is disconnected or not */
+ if (port->port_usb && gport->in)
+ msm_ep_unconfig(port->port_usb->in);
+ spin_unlock_irqrestore(&port->port_lock, flags);
+unconfig_msm_ep_out:
+ if (gport->in)
+ usb_bam_free_fifos(port->usb_bam_type,
+ port->dst_connection_idx);
+ spin_lock_irqsave(&port->port_lock, flags);
+ /* check if USB cable is disconnected or not */
+ if (port->port_usb && gport->out)
+ msm_ep_unconfig(port->port_usb->out);
+ spin_unlock_irqrestore(&port->port_lock, flags);
+out:
+ if (gport->out)
+ usb_bam_free_fifos(port->usb_bam_type,
+ port->src_connection_idx);
+ spin_lock_irqsave(&port->port_lock, flags);
+ port->is_connected = false;
+ spin_unlock_irqrestore(&port->port_lock, flags);
+ usb_gadget_autopm_put_async(port->gadget);
+}
+
+/**
+ * ipa_data_connect() - Prepare IPA params and enable USB endpoints
+ * @gp: USB IPA gadget port
+ * @port_num: port number used by accelerated function
+ * @src_connection_idx: USB BAM pipe index used as producer
+ * @dst_connection_idx: USB BAM pipe index used as consumer
+ *
+ * It is being called from accelerated function driver (from set_alt()) to
+ * initiate USB BAM IPA connection. This API is enabling accelerated endpoints
+ * and schedule connect_work() which establishes USB IPA BAM communication.
+ */
+int ipa_data_connect(struct gadget_ipa_port *gp, enum ipa_func_type func,
+ u8 src_connection_idx, u8 dst_connection_idx)
+{
+ struct ipa_data_ch_info *port;
+ unsigned long flags;
+ int ret = 0;
+
+ pr_debug("dev:%pK port#%d src_connection_idx:%d dst_connection_idx:%d\n",
+ gp, func, src_connection_idx, dst_connection_idx);
+
+ if (func >= USB_IPA_NUM_FUNCS) {
+ pr_err("invalid portno#%d\n", func);
+ ret = -ENODEV;
+ goto err;
+ }
+
+ if (!gp) {
+ pr_err("gadget port is null\n");
+ ret = -ENODEV;
+ goto err;
+ }
+
+ port = ipa_data_ports[func];
+
+ spin_lock_irqsave(&port->port_lock, flags);
+ port->port_usb = gp;
+ port->gadget = gp->cdev->gadget;
+
+ if (gp->out) {
+ port->rx_req = usb_ep_alloc_request(gp->out, GFP_ATOMIC);
+ if (!port->rx_req) {
+ spin_unlock_irqrestore(&port->port_lock, flags);
+ pr_err("%s: failed to allocate rx_req\n", __func__);
+ goto err;
+ }
+ port->rx_req->context = port;
+ port->rx_req->complete = ipa_data_endless_complete;
+ port->rx_req->length = 0;
+ port->rx_req->no_interrupt = 1;
+ }
+
+ if (gp->in) {
+ port->tx_req = usb_ep_alloc_request(gp->in, GFP_ATOMIC);
+ if (!port->tx_req) {
+ pr_err("%s: failed to allocate tx_req\n", __func__);
+ goto free_rx_req;
+ }
+ port->tx_req->context = port;
+ port->tx_req->complete = ipa_data_endless_complete;
+ port->tx_req->length = 0;
+ port->tx_req->no_interrupt = 1;
+ }
+ port->src_connection_idx = src_connection_idx;
+ port->dst_connection_idx = dst_connection_idx;
+ port->usb_bam_type = usb_bam_get_bam_type(gp->cdev->gadget->name);
+
+ port->ipa_params.src_pipe = &(port->src_pipe_idx);
+ port->ipa_params.dst_pipe = &(port->dst_pipe_idx);
+ port->ipa_params.src_idx = src_connection_idx;
+ port->ipa_params.dst_idx = dst_connection_idx;
+
+ /*
+ * Disable Xfer complete and Xfer not ready interrupts by
+ * marking endless flag which is used in UDC driver to enable
+ * these interrupts. with this set, these interrupts for selected
+ * endpoints won't be enabled.
+ */
+ if (port->port_usb->in) {
+ port->port_usb->in->endless = true;
+ ret = usb_ep_enable(port->port_usb->in);
+ if (ret) {
+ pr_err("usb_ep_enable failed eptype:IN ep:%pK",
+ port->port_usb->in);
+ usb_ep_free_request(port->port_usb->in, port->tx_req);
+ port->tx_req = NULL;
+ port->port_usb->in->endless = false;
+ goto err_usb_in;
+ }
+ }
+
+ if (port->port_usb->out) {
+ port->port_usb->out->endless = true;
+ ret = usb_ep_enable(port->port_usb->out);
+ if (ret) {
+ pr_err("usb_ep_enable failed eptype:OUT ep:%pK",
+ port->port_usb->out);
+ usb_ep_free_request(port->port_usb->out, port->rx_req);
+ port->rx_req = NULL;
+ port->port_usb->out->endless = false;
+ goto err_usb_out;
+ }
+ }
+
+ /* Wait for host to enable flow_control */
+ if (port->func_type == USB_IPA_FUNC_RNDIS) {
+ spin_unlock_irqrestore(&port->port_lock, flags);
+ ret = 0;
+ return ret;
+ }
+
+ /*
+ * Increment usage count upon cable connect. Decrement after IPA
+ * handshake is done in disconnect work (due to cable disconnect)
+ * or in suspend work.
+ */
+ usb_gadget_autopm_get_noresume(port->gadget);
+
+ queue_work(ipa_data_wq, &port->connect_w);
+ spin_unlock_irqrestore(&port->port_lock, flags);
+
+ return ret;
+
+err_usb_out:
+ if (port->port_usb->in) {
+ usb_ep_disable(port->port_usb->in);
+ port->port_usb->in->endless = false;
+ }
+err_usb_in:
+ if (gp->in && port->tx_req) {
+ usb_ep_free_request(gp->in, port->tx_req);
+ port->tx_req = NULL;
+ }
+free_rx_req:
+ if (gp->out && port->rx_req) {
+ usb_ep_free_request(gp->out, port->rx_req);
+ port->rx_req = NULL;
+ }
+ spin_unlock_irqrestore(&port->port_lock, flags);
+err:
+ pr_debug("%s(): failed with error:%d\n", __func__, ret);
+ return ret;
+}
+
+/**
+ * ipa_data_start() - Restart USB endless transfer
+ * @param: IPA data channel information
+ * @dir: USB BAM pipe direction
+ *
+ * It is being used to restart USB endless transfer for USB bus resume.
+ * For USB consumer case, it restarts USB endless RX transfer, whereas
+ * for USB producer case, it resets DBM endpoint and restart USB endless
+ * TX transfer.
+ */
+static void ipa_data_start(void *param, enum usb_bam_pipe_dir dir)
+{
+ struct ipa_data_ch_info *port = param;
+ struct usb_gadget *gadget = NULL;
+
+ if (!port || !port->port_usb || !port->port_usb->cdev->gadget) {
+ pr_err("%s:port,cdev or gadget is NULL\n", __func__);
+ return;
+ }
+
+ gadget = port->port_usb->cdev->gadget;
+ if (dir == USB_TO_PEER_PERIPHERAL) {
+ pr_debug("%s(): start endless RX\n", __func__);
+ ipa_data_start_endless_xfer(port, false);
+ } else {
+ pr_debug("%s(): start endless TX\n", __func__);
+ if (msm_dwc3_reset_ep_after_lpm(gadget)) {
+ configure_fifo(port->usb_bam_type,
+ port->dst_connection_idx, port->port_usb->in);
+ }
+ ipa_data_start_endless_xfer(port, true);
+ }
+}
+
+/**
+ * ipa_data_stop() - Stop endless Tx/Rx transfers
+ * @param: IPA data channel information
+ * @dir: USB BAM pipe direction
+ *
+ * It is being used to stop endless Tx/Rx transfers. It is being used
+ * for USB bus suspend functionality.
+ */
+static void ipa_data_stop(void *param, enum usb_bam_pipe_dir dir)
+{
+ struct ipa_data_ch_info *port = param;
+ struct usb_gadget *gadget = NULL;
+
+ if (!port || !port->port_usb || !port->port_usb->cdev->gadget) {
+ pr_err("%s:port,cdev or gadget is NULL\n", __func__);
+ return;
+ }
+
+ gadget = port->port_usb->cdev->gadget;
+ if (dir == USB_TO_PEER_PERIPHERAL) {
+ pr_debug("%s(): stop endless RX transfer\n", __func__);
+ ipa_data_stop_endless_xfer(port, false);
+ } else {
+ pr_debug("%s(): stop endless TX transfer\n", __func__);
+ ipa_data_stop_endless_xfer(port, true);
+ }
+}
+
+void ipa_data_flush_workqueue(void)
+{
+ pr_debug("%s(): Flushing workqueue\n", __func__);
+ flush_workqueue(ipa_data_wq);
+}
+
+/**
+ * ipa_data_suspend() - Initiate USB BAM IPA suspend functionality
+ * @gp: Gadget IPA port
+ * @port_num: port number used by function
+ *
+ * It is being used to initiate USB BAM IPA suspend functionality
+ * for USB bus suspend functionality.
+ */
+void ipa_data_suspend(struct gadget_ipa_port *gp, enum ipa_func_type func,
+ bool remote_wakeup_enabled)
+{
+ struct ipa_data_ch_info *port;
+ unsigned long flags;
+
+ if (func >= USB_IPA_NUM_FUNCS) {
+ pr_err("invalid ipa portno#%d\n", func);
+ return;
+ }
+
+ if (!gp) {
+ pr_err("data port is null\n");
+ return;
+ }
+ pr_debug("%s: suspended port %d\n", __func__, func);
+
+ port = ipa_data_ports[func];
+ if (!port) {
+ pr_err("%s(): Port is NULL.\n", __func__);
+ return;
+ }
+
+ /* suspend with remote wakeup disabled */
+ if (!remote_wakeup_enabled) {
+ /*
+ * When remote wakeup is disabled, IPA BAM is disconnected
+ * because it cannot send new data until the USB bus is resumed.
+ * Endpoint descriptors info is saved before it gets reset by
+ * the BAM disconnect API. This lets us restore this info when
+ * the USB bus is resumed.
+ */
+ if (gp->in) {
+ gp->in_ep_desc_backup = gp->in->desc;
+ pr_debug("in_ep_desc_backup = %pK\n",
+ gp->in_ep_desc_backup);
+ }
+ if (gp->out) {
+ gp->out_ep_desc_backup = gp->out->desc;
+ pr_debug("out_ep_desc_backup = %pK\n",
+ gp->out_ep_desc_backup);
+ }
+ ipa_data_disconnect(gp, func);
+ return;
+ }
+
+ spin_lock_irqsave(&port->port_lock, flags);
+ queue_work(ipa_data_wq, &port->suspend_w);
+ spin_unlock_irqrestore(&port->port_lock, flags);
+}
+static void bam2bam_data_suspend_work(struct work_struct *w)
+{
+ struct ipa_data_ch_info *port = container_of(w, struct ipa_data_ch_info,
+ connect_w);
+ unsigned long flags;
+ int ret;
+
+ pr_debug("%s: suspend started\n", __func__);
+ spin_lock_irqsave(&port->port_lock, flags);
+
+ /* In case of RNDIS, host enables flow_control invoking connect_w. If it
+ * is delayed then we may end up having suspend_w run before connect_w.
+ * In this scenario, connect_w may or may not at all start if cable gets
+ * disconnected or if host changes configuration e.g. RNDIS --> MBIM
+ * For these cases don't do runtime_put as there was no _get yet, and
+ * detect this condition on disconnect to not do extra pm_runtme_get
+ * for SUSPEND --> DISCONNECT scenario.
+ */
+ if (!port->is_connected) {
+ pr_err("%s: Not yet connected. SUSPEND pending.\n", __func__);
+ spin_unlock_irqrestore(&port->port_lock, flags);
+ return;
+ }
+ ret = usb_bam_register_wake_cb(port->usb_bam_type,
+ port->dst_connection_idx, NULL, port);
+ if (ret) {
+ pr_err("%s(): Failed to register BAM wake callback.\n",
+ __func__);
+ return;
+ }
+
+ usb_bam_register_start_stop_cbs(port->usb_bam_type,
+ port->dst_connection_idx, ipa_data_start,
+ ipa_data_stop, port);
+ /*
+ * release lock here because bam_data_start() or
+ * bam_data_stop() called from usb_bam_suspend()
+ * re-acquires port lock.
+ */
+ spin_unlock_irqrestore(&port->port_lock, flags);
+ usb_bam_suspend(port->usb_bam_type, &port->ipa_params);
+ spin_lock_irqsave(&port->port_lock, flags);
+
+ /*
+ * Decrement usage count after IPA handshake is done
+ * to allow gadget parent to go to lpm. This counter was
+ * incremented upon cable connect.
+ */
+ usb_gadget_autopm_put_async(port->gadget);
+
+ spin_unlock_irqrestore(&port->port_lock, flags);
+}
+
+/**
+ * ipa_data_resume() - Initiate USB resume functionality
+ * @gp: Gadget IPA port
+ * @port_num: port number used by function
+ *
+ * It is being used to initiate USB resume functionality
+ * for USB bus resume case.
+ */
+void ipa_data_resume(struct gadget_ipa_port *gp, enum ipa_func_type func,
+ bool remote_wakeup_enabled)
+{
+ struct ipa_data_ch_info *port;
+ unsigned long flags;
+ struct usb_gadget *gadget = NULL;
+ u8 src_connection_idx = 0;
+ u8 dst_connection_idx = 0;
+ enum usb_ctrl usb_bam_type;
+
+ pr_debug("dev:%pK port number:%d\n", gp, func);
+
+ if (func >= USB_IPA_NUM_FUNCS) {
+ pr_err("invalid ipa portno#%d\n", func);
+ return;
+ }
+
+ if (!gp) {
+ pr_err("data port is null\n");
+ return;
+ }
+
+ port = ipa_data_ports[func];
+ if (!port) {
+ pr_err("port %u is NULL", func);
+ return;
+ }
+
+ gadget = gp->cdev->gadget;
+ /* resume with remote wakeup disabled */
+ if (!remote_wakeup_enabled) {
+ int bam_pipe_num = (func == USB_IPA_FUNC_DPL) ? 1 : 0;
+
+ usb_bam_type = usb_bam_get_bam_type(gadget->name);
+ /* Restore endpoint descriptors info. */
+ if (gp->in) {
+ gp->in->desc = gp->in_ep_desc_backup;
+ pr_debug("in_ep_desc_backup = %pK\n",
+ gp->in_ep_desc_backup);
+ dst_connection_idx = usb_bam_get_connection_idx(
+ usb_bam_type, IPA_P_BAM, PEER_PERIPHERAL_TO_USB,
+ USB_BAM_DEVICE, bam_pipe_num);
+ }
+ if (gp->out) {
+ gp->out->desc = gp->out_ep_desc_backup;
+ pr_debug("out_ep_desc_backup = %pK\n",
+ gp->out_ep_desc_backup);
+ src_connection_idx = usb_bam_get_connection_idx(
+ usb_bam_type, IPA_P_BAM, USB_TO_PEER_PERIPHERAL,
+ USB_BAM_DEVICE, bam_pipe_num);
+ }
+ ipa_data_connect(gp, func,
+ src_connection_idx, dst_connection_idx);
+ return;
+ }
+
+ spin_lock_irqsave(&port->port_lock, flags);
+
+ /*
+ * Increment usage count here to disallow gadget
+ * parent suspend. This counter will decrement
+ * after IPA handshake is done in disconnect work
+ * (due to cable disconnect) or in bam_data_disconnect
+ * in suspended state.
+ */
+ usb_gadget_autopm_get_noresume(port->gadget);
+ queue_work(ipa_data_wq, &port->resume_w);
+ spin_unlock_irqrestore(&port->port_lock, flags);
+}
+
+static void bam2bam_data_resume_work(struct work_struct *w)
+{
+ struct ipa_data_ch_info *port = container_of(w, struct ipa_data_ch_info,
+ connect_w);
+ struct usb_gadget *gadget;
+ unsigned long flags;
+ int ret;
+
+ spin_lock_irqsave(&port->port_lock, flags);
+ if (!port->port_usb || !port->port_usb->cdev) {
+ pr_err("port->port_usb or cdev is NULL");
+ goto exit;
+ }
+
+ if (!port->port_usb->cdev->gadget) {
+ pr_err("port->port_usb->cdev->gadget is NULL");
+ goto exit;
+ }
+
+ pr_debug("%s: resume started\n", __func__);
+ gadget = port->port_usb->cdev->gadget;
+ if (!gadget) {
+ spin_unlock_irqrestore(&port->port_lock, flags);
+ pr_err("%s(): Gadget is NULL.\n", __func__);
+ return;
+ }
+
+ ret = usb_bam_register_wake_cb(port->usb_bam_type,
+ port->dst_connection_idx, NULL, NULL);
+ if (ret) {
+ spin_unlock_irqrestore(&port->port_lock, flags);
+ pr_err("%s(): Failed to register BAM wake callback.\n",
+ __func__);
+ return;
+ }
+
+ if (msm_dwc3_reset_ep_after_lpm(gadget)) {
+ configure_fifo(port->usb_bam_type, port->src_connection_idx,
+ port->port_usb->out);
+ configure_fifo(port->usb_bam_type, port->dst_connection_idx,
+ port->port_usb->in);
+ spin_unlock_irqrestore(&port->port_lock, flags);
+ msm_dwc3_reset_dbm_ep(port->port_usb->in);
+ spin_lock_irqsave(&port->port_lock, flags);
+ usb_bam_resume(port->usb_bam_type, &port->ipa_params);
+ }
+
+exit:
+ spin_unlock_irqrestore(&port->port_lock, flags);
+}
+
+/**
+ * ipa_data_port_alloc() - Allocate IPA USB Port structure
+ * @portno: port number to be used by particular USB function
+ *
+ * It is being used by USB function driver to allocate IPA data port
+ * for USB IPA data accelerated path.
+ *
+ * Retrun: 0 in case of success, otherwise errno.
+ */
+static int ipa_data_port_alloc(enum ipa_func_type func)
+{
+ struct ipa_data_ch_info *port = NULL;
+
+ if (ipa_data_ports[func] != NULL) {
+ pr_debug("port %d already allocated.\n", func);
+ return 0;
+ }
+
+ port = kzalloc(sizeof(struct ipa_data_ch_info), GFP_KERNEL);
+ if (!port)
+ return -ENOMEM;
+
+ ipa_data_ports[func] = port;
+
+ pr_debug("port:%pK with portno:%d allocated\n", port, func);
+ return 0;
+}
+
+/**
+ * ipa_data_port_select() - Select particular port for BAM2BAM IPA mode
+ * @portno: port number to be used by particular USB function
+ * @func_type: USB gadget function type
+ *
+ * It is being used by USB function driver to select which BAM2BAM IPA
+ * port particular USB function wants to use.
+ *
+ */
+void ipa_data_port_select(enum ipa_func_type func)
+{
+ struct ipa_data_ch_info *port = NULL;
+
+ pr_debug("portno:%d\n", func);
+
+ port = ipa_data_ports[func];
+ port->port_num = func;
+ port->is_connected = false;
+
+ spin_lock_init(&port->port_lock);
+
+ if (!work_pending(&port->connect_w))
+ INIT_WORK(&port->connect_w, ipa_data_connect_work);
+
+ if (!work_pending(&port->disconnect_w))
+ INIT_WORK(&port->disconnect_w, ipa_data_disconnect_work);
+
+ INIT_WORK(&port->suspend_w, bam2bam_data_suspend_work);
+ INIT_WORK(&port->resume_w, bam2bam_data_resume_work);
+
+ port->ipa_params.src_client = IPA_CLIENT_USB_PROD;
+ port->ipa_params.dst_client = IPA_CLIENT_USB_CONS;
+ port->func_type = func;
+};
+
+void ipa_data_free(enum ipa_func_type func)
+{
+ pr_debug("freeing %d IPA BAM port", func);
+
+ kfree(ipa_data_ports[func]);
+ ipa_data_ports[func] = NULL;
+ if (func == USB_IPA_FUNC_RNDIS)
+ kfree(rndis_data);
+ if (ipa_data_wq) {
+ destroy_workqueue(ipa_data_wq);
+ ipa_data_wq = NULL;
+ }
+}
+
+/**
+ * ipa_data_setup() - setup BAM2BAM IPA port
+ *
+ * Each USB function who wants to use BAM2BAM IPA port would
+ * be counting number of IPA port to use and initialize those
+ * ports at time of bind_config() in android gadget driver.
+ *
+ * Retrun: 0 in case of success, otherwise errno.
+ */
+int ipa_data_setup(enum ipa_func_type func)
+{
+ int ret;
+
+ pr_debug("requested %d IPA BAM port", func);
+
+ if (func >= USB_IPA_NUM_FUNCS) {
+ pr_err("Invalid num of ports count:%d\n", func);
+ return -EINVAL;
+ }
+
+ ret = ipa_data_port_alloc(func);
+ if (ret) {
+ pr_err("Failed to alloc port:%d\n", func);
+ return ret;
+ }
+
+ if (func == USB_IPA_FUNC_RNDIS) {
+ rndis_data = kzalloc(sizeof(*rndis_data), GFP_KERNEL);
+ if (!rndis_data) {
+ pr_err("%s: fail allocate and initialize new instance\n",
+ __func__);
+ goto free_ipa_ports;
+ }
+ }
+ if (ipa_data_wq) {
+ pr_debug("ipa_data_wq is already setup.");
+ return 0;
+ }
+
+ ipa_data_wq = alloc_workqueue("k_usb_ipa_data",
+ WQ_UNBOUND | WQ_MEM_RECLAIM, 1);
+ if (!ipa_data_wq) {
+ pr_err("Failed to create workqueue\n");
+ ret = -ENOMEM;
+ goto free_rndis_data;
+ }
+
+ return 0;
+
+free_rndis_data:
+ if (func == USB_IPA_FUNC_RNDIS)
+ kfree(rndis_data);
+free_ipa_ports:
+ kfree(ipa_data_ports[func]);
+ ipa_data_ports[func] = NULL;
+
+ return ret;
+}
+
+void ipa_data_set_ul_max_xfer_size(u32 max_transfer_size)
+{
+ if (!max_transfer_size) {
+ pr_err("%s: invalid parameters\n", __func__);
+ return;
+ }
+ rndis_data->ul_max_transfer_size = max_transfer_size;
+ pr_debug("%s(): ul_max_xfer_size:%d\n", __func__, max_transfer_size);
+}
+
+void ipa_data_set_dl_max_xfer_size(u32 max_transfer_size)
+{
+
+ if (!max_transfer_size) {
+ pr_err("%s: invalid parameters\n", __func__);
+ return;
+ }
+ rndis_data->dl_max_transfer_size = max_transfer_size;
+ pr_debug("%s(): dl_max_xfer_size:%d\n", __func__, max_transfer_size);
+}
+
+void ipa_data_set_ul_max_pkt_num(u8 max_packets_number)
+{
+ if (!max_packets_number) {
+ pr_err("%s: invalid parameters\n", __func__);
+ return;
+ }
+
+ rndis_data->ul_max_packets_number = max_packets_number;
+
+ if (max_packets_number > 1)
+ rndis_data->ul_aggregation_enable = true;
+ else
+ rndis_data->ul_aggregation_enable = false;
+
+ pr_debug("%s(): ul_aggregation enable:%d ul_max_packets_number:%d\n",
+ __func__, rndis_data->ul_aggregation_enable,
+ max_packets_number);
+}
+
+void ipa_data_start_rndis_ipa(enum ipa_func_type func)
+{
+ struct ipa_data_ch_info *port;
+
+ pr_debug("%s\n", __func__);
+
+ port = ipa_data_ports[func];
+ if (!port) {
+ pr_err("%s: port is NULL", __func__);
+ return;
+ }
+
+ if (atomic_read(&port->pipe_connect_notified)) {
+ pr_debug("%s: Transfers already started?\n", __func__);
+ return;
+ }
+ /*
+ * Increment usage count upon cable connect. Decrement after IPA
+ * handshake is done in disconnect work due to cable disconnect
+ * or in suspend work.
+ */
+ usb_gadget_autopm_get_noresume(port->gadget);
+ queue_work(ipa_data_wq, &port->connect_w);
+}
+
+void ipa_data_stop_rndis_ipa(enum ipa_func_type func)
+{
+ struct ipa_data_ch_info *port;
+ unsigned long flags;
+
+ pr_debug("%s\n", __func__);
+
+ port = ipa_data_ports[func];
+ if (!port) {
+ pr_err("%s: port is NULL", __func__);
+ return;
+ }
+
+ if (!atomic_read(&port->pipe_connect_notified))
+ return;
+
+ rndis_ipa_reset_trigger();
+ ipa_data_stop_endless_xfer(port, true);
+ ipa_data_stop_endless_xfer(port, false);
+ spin_lock_irqsave(&port->port_lock, flags);
+ /* check if USB cable is disconnected or not */
+ if (port->port_usb) {
+ msm_ep_unconfig(port->port_usb->in);
+ msm_ep_unconfig(port->port_usb->out);
+ }
+ spin_unlock_irqrestore(&port->port_lock, flags);
+ queue_work(ipa_data_wq, &port->disconnect_w);
+}
diff --git a/drivers/usb/gadget/function/u_data_ipa.h b/drivers/usb/gadget/function/u_data_ipa.h
new file mode 100644
index 0000000..70d4293
--- /dev/null
+++ b/drivers/usb/gadget/function/u_data_ipa.h
@@ -0,0 +1,127 @@
+/* Copyright (c) 2014,2016 The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * 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 __U_DATA_IPA_H
+#define __U_DATA_IPA_H
+
+#include <linux/usb/composite.h>
+#include <linux/rndis_ipa.h>
+#include <linux/usb/gadget.h>
+#include <linux/cdev.h>
+#include <linux/ipa_usb.h>
+#include <linux/usb_bam.h>
+
+#include "u_rmnet.h"
+
+enum ipa_func_type {
+ USB_IPA_FUNC_ECM,
+ USB_IPA_FUNC_MBIM,
+ USB_IPA_FUNC_RMNET,
+ USB_IPA_FUNC_RNDIS,
+ USB_IPA_FUNC_DPL,
+ USB_IPA_NUM_FUNCS,
+};
+
+/* Max Number of IPA data ports supported */
+#define IPA_N_PORTS USB_IPA_NUM_FUNCS
+
+struct gadget_ipa_port {
+ struct usb_composite_dev *cdev;
+ struct usb_function *func;
+ int rx_buffer_size;
+ struct usb_ep *in;
+ struct usb_ep *out;
+ int ipa_consumer_ep;
+ int ipa_producer_ep;
+ const struct usb_endpoint_descriptor *in_ep_desc_backup;
+ const struct usb_endpoint_descriptor *out_ep_desc_backup;
+
+};
+
+struct ipa_function_bind_info {
+ struct usb_string *string_defs;
+ int data_str_idx;
+ struct usb_interface_descriptor *data_desc;
+ struct usb_endpoint_descriptor *fs_in_desc;
+ struct usb_endpoint_descriptor *fs_out_desc;
+ struct usb_endpoint_descriptor *fs_notify_desc;
+ struct usb_endpoint_descriptor *hs_in_desc;
+ struct usb_endpoint_descriptor *hs_out_desc;
+ struct usb_endpoint_descriptor *hs_notify_desc;
+ struct usb_endpoint_descriptor *ss_in_desc;
+ struct usb_endpoint_descriptor *ss_out_desc;
+ struct usb_endpoint_descriptor *ss_notify_desc;
+
+ struct usb_descriptor_header **fs_desc_hdr;
+ struct usb_descriptor_header **hs_desc_hdr;
+ struct usb_descriptor_header **ss_desc_hdr;
+};
+
+/* for configfs support */
+#define MAX_INST_NAME_LEN 40
+
+struct f_rndis_qc_opts {
+ struct usb_function_instance func_inst;
+ struct f_rndis_qc *rndis;
+ u32 vendor_id;
+ const char *manufacturer;
+ struct net_device *net;
+ int refcnt;
+};
+
+struct f_rmnet_opts {
+ struct usb_function_instance func_inst;
+ struct f_rmnet *dev;
+ int refcnt;
+};
+
+void ipa_data_port_select(enum ipa_func_type func);
+void ipa_data_disconnect(struct gadget_ipa_port *gp, enum ipa_func_type func);
+int ipa_data_connect(struct gadget_ipa_port *gp, enum ipa_func_type func,
+ u8 src_connection_idx, u8 dst_connection_idx);
+int ipa_data_setup(enum ipa_func_type func);
+void ipa_data_free(enum ipa_func_type func);
+
+void ipa_data_flush_workqueue(void);
+void ipa_data_resume(struct gadget_ipa_port *gp, enum ipa_func_type func,
+ bool remote_wakeup_enabled);
+void ipa_data_suspend(struct gadget_ipa_port *gp, enum ipa_func_type func,
+ bool remote_wakeup_enabled);
+
+void ipa_data_set_ul_max_xfer_size(u32 ul_max_xfer_size);
+
+void ipa_data_set_dl_max_xfer_size(u32 dl_max_transfer_size);
+
+void ipa_data_set_ul_max_pkt_num(u8 ul_max_packets_number);
+
+void ipa_data_start_rx_tx(enum ipa_func_type func);
+
+void ipa_data_start_rndis_ipa(enum ipa_func_type func);
+
+void ipa_data_stop_rndis_ipa(enum ipa_func_type func);
+
+void *rndis_qc_get_ipa_priv(void);
+void *rndis_qc_get_ipa_rx_cb(void);
+bool rndis_qc_get_skip_ep_config(void);
+void *rndis_qc_get_ipa_tx_cb(void);
+void rndis_ipa_reset_trigger(void);
+#if IS_ENABLED(CONFIG_USB_CONFIGFS_RMNET_BAM)
+void gqti_ctrl_update_ipa_pipes(void *gr, enum qti_port_type qport,
+ u32 ipa_prod, u32 ipa_cons);
+#else
+static inline void gqti_ctrl_update_ipa_pipes(void *gr,
+ enum qti_port_type qport,
+ u32 ipa_prod, u32 ipa_cons)
+{
+}
+#endif /* CONFIG_USB_CONFIGFS_RMNET_BAM */
+#endif
diff --git a/drivers/usb/gadget/function/u_ether_configfs.h b/drivers/usb/gadget/function/u_ether_configfs.h
index 4f47289..0468459 100644
--- a/drivers/usb/gadget/function/u_ether_configfs.h
+++ b/drivers/usb/gadget/function/u_ether_configfs.h
@@ -35,6 +35,11 @@
struct f_##_f_##_opts *opts = to_f_##_f_##_opts(item); \
int result; \
\
+ if (opts->bound == false) { \
+ pr_err("Gadget function do not bind yet.\n"); \
+ return -ENODEV; \
+ } \
+ \
mutex_lock(&opts->lock); \
result = gether_get_dev_addr(opts->net, page, PAGE_SIZE); \
mutex_unlock(&opts->lock); \
@@ -48,6 +53,11 @@
struct f_##_f_##_opts *opts = to_f_##_f_##_opts(item); \
int ret; \
\
+ if (opts->bound == false) { \
+ pr_err("Gadget function do not bind yet.\n"); \
+ return -ENODEV; \
+ } \
+ \
mutex_lock(&opts->lock); \
if (opts->refcnt) { \
mutex_unlock(&opts->lock); \
@@ -70,6 +80,11 @@
struct f_##_f_##_opts *opts = to_f_##_f_##_opts(item); \
int result; \
\
+ if (opts->bound == false) { \
+ pr_err("Gadget function do not bind yet.\n"); \
+ return -ENODEV; \
+ } \
+ \
mutex_lock(&opts->lock); \
result = gether_get_host_addr(opts->net, page, PAGE_SIZE); \
mutex_unlock(&opts->lock); \
@@ -83,6 +98,11 @@
struct f_##_f_##_opts *opts = to_f_##_f_##_opts(item); \
int ret; \
\
+ if (opts->bound == false) { \
+ pr_err("Gadget function do not bind yet.\n"); \
+ return -ENODEV; \
+ } \
+ \
mutex_lock(&opts->lock); \
if (opts->refcnt) { \
mutex_unlock(&opts->lock); \
@@ -105,6 +125,11 @@
struct f_##_f_##_opts *opts = to_f_##_f_##_opts(item); \
unsigned qmult; \
\
+ if (opts->bound == false) { \
+ pr_err("Gadget function do not bind yet.\n"); \
+ return -ENODEV; \
+ } \
+ \
mutex_lock(&opts->lock); \
qmult = gether_get_qmult(opts->net); \
mutex_unlock(&opts->lock); \
@@ -118,6 +143,11 @@
u8 val; \
int ret; \
\
+ if (opts->bound == false) { \
+ pr_err("Gadget function do not bind yet.\n"); \
+ return -ENODEV; \
+ } \
+ \
mutex_lock(&opts->lock); \
if (opts->refcnt) { \
ret = -EBUSY; \
@@ -144,6 +174,11 @@
struct f_##_f_##_opts *opts = to_f_##_f_##_opts(item); \
int ret; \
\
+ if (opts->bound == false) { \
+ pr_err("Gadget function do not bind yet.\n"); \
+ return -ENODEV; \
+ } \
+ \
mutex_lock(&opts->lock); \
ret = gether_get_ifname(opts->net, page, PAGE_SIZE); \
mutex_unlock(&opts->lock); \
diff --git a/drivers/usb/gadget/function/u_qdss.c b/drivers/usb/gadget/function/u_qdss.c
index 06eecd1..b4353ac 100644
--- a/drivers/usb/gadget/function/u_qdss.c
+++ b/drivers/usb/gadget/function/u_qdss.c
@@ -47,6 +47,8 @@
int idx;
struct usb_qdss_bam_connect_info bam_info;
struct usb_gadget *gadget;
+ struct device *dev;
+ int ret;
pr_debug("set_qdss_data_connection\n");
@@ -57,6 +59,7 @@
gadget = qdss->gadget;
usb_bam_type = usb_bam_get_bam_type(gadget->name);
+ dev = gadget->dev.parent;
bam_info = qdss->bam_info;
/* There is only one qdss pipe, so the pipe number can be set to 0 */
@@ -68,6 +71,23 @@
}
if (enable) {
+ ret = get_qdss_bam_info(usb_bam_type, idx,
+ &bam_info.qdss_bam_phys,
+ &bam_info.qdss_bam_size);
+ if (ret) {
+ pr_err("%s(): failed to get qdss bam info err(%d)\n",
+ __func__, ret);
+ return ret;
+ }
+
+ bam_info.qdss_bam_iova = dma_map_resource(dev->parent,
+ bam_info.qdss_bam_phys, bam_info.qdss_bam_size,
+ DMA_BIDIRECTIONAL, 0);
+ if (!bam_info.qdss_bam_iova) {
+ pr_err("dma_map_resource failed\n");
+ return -ENOMEM;
+ }
+
usb_bam_alloc_fifos(usb_bam_type, idx);
bam_info.data_fifo =
kzalloc(sizeof(struct sps_mem_buffer), GFP_KERNEL);
@@ -76,25 +96,34 @@
usb_bam_free_fifos(usb_bam_type, idx);
return -ENOMEM;
}
+
+ pr_debug("%s(): qdss_bam: iova:%lx p_addr:%lx size:%x\n",
+ __func__, bam_info.qdss_bam_iova,
+ (unsigned long)bam_info.qdss_bam_phys,
+ bam_info.qdss_bam_size);
+
get_bam2bam_connection_info(usb_bam_type, idx,
&bam_info.usb_bam_pipe_idx,
NULL, bam_info.data_fifo, NULL);
alloc_sps_req(qdss->port.data);
msm_data_fifo_config(qdss->port.data,
- bam_info.data_fifo->phys_base,
- bam_info.data_fifo->size,
- bam_info.usb_bam_pipe_idx);
+ bam_info.data_fifo->iova,
+ bam_info.data_fifo->size,
+ bam_info.usb_bam_pipe_idx);
init_data(qdss->port.data);
res = usb_bam_connect(usb_bam_type, idx,
- &(bam_info.usb_bam_pipe_idx));
+ &(bam_info.usb_bam_pipe_idx),
+ bam_info.qdss_bam_iova);
} else {
- kfree(bam_info.data_fifo);
res = usb_bam_disconnect_pipe(usb_bam_type, idx);
if (res)
pr_err("usb_bam_disconnection error\n");
+ dma_unmap_resource(dev->parent, bam_info.qdss_bam_iova,
+ bam_info.qdss_bam_size, DMA_BIDIRECTIONAL, 0);
usb_bam_free_fifos(usb_bam_type, idx);
+ kfree(bam_info.data_fifo);
}
return res;
diff --git a/drivers/usb/gadget/function/u_rmnet.h b/drivers/usb/gadget/function/u_rmnet.h
new file mode 100644
index 0000000..0126932
--- /dev/null
+++ b/drivers/usb/gadget/function/u_rmnet.h
@@ -0,0 +1,56 @@
+/* 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.
+ */
+
+#ifndef __U_RMNET_H
+#define __U_RMNET_H
+
+#include <linux/usb/composite.h>
+#include <linux/usb/cdc.h>
+#include <linux/wait.h>
+#include <linux/workqueue.h>
+
+#include "f_qdss.h"
+
+struct rmnet_ctrl_pkt {
+ void *buf;
+ int len;
+ struct list_head list;
+};
+
+struct grmnet {
+ /* to usb host, aka laptop, windows pc etc. Will
+ * be filled by usb driver of rmnet functionality
+ */
+ int (*send_cpkt_response)(void *g, void *buf, size_t len);
+
+ /* to modem, and to be filled by driver implementing
+ * control function
+ */
+ int (*send_encap_cmd)(enum qti_port_type qport, void *buf, size_t len);
+ void (*notify_modem)(void *g, enum qti_port_type qport, int cbits);
+
+ void (*disconnect)(struct grmnet *g);
+ void (*connect)(struct grmnet *g);
+};
+
+enum ctrl_client {
+ FRMNET_CTRL_CLIENT,
+ GPS_CTRL_CLIENT,
+
+ NR_CTRL_CLIENTS
+};
+
+int gqti_ctrl_connect(void *gr, enum qti_port_type qport, unsigned int intf);
+void gqti_ctrl_disconnect(void *gr, enum qti_port_type qport);
+int gqti_ctrl_init(void);
+void gqti_ctrl_cleanup(void);
+#endif /* __U_RMNET_H*/
diff --git a/drivers/usb/host/xhci-hub.c b/drivers/usb/host/xhci-hub.c
index 5434902..643e087 100644
--- a/drivers/usb/host/xhci-hub.c
+++ b/drivers/usb/host/xhci-hub.c
@@ -23,6 +23,7 @@
#include <linux/gfp.h>
#include <linux/slab.h>
#include <asm/unaligned.h>
+#include <linux/usb/phy.h>
#include "xhci.h"
#include "xhci-trace.h"
@@ -1065,6 +1066,7 @@
u16 wake_mask = 0;
u16 timeout = 0;
u16 test_mode = 0;
+ enum usb_device_speed s = hcd->self.root_hub->speed;
max_ports = xhci_get_ports(hcd, &port_array);
bus_state = &xhci->bus_state[hcd_index(hcd)];
@@ -1314,6 +1316,10 @@
writel(temp, port_array[wIndex]);
temp = readl(port_array[wIndex]);
+
+ if (s == USB_SPEED_HIGH)
+ usb_phy_start_port_reset(hcd->usb_phy);
+
xhci_dbg(xhci, "set port reset, actual port %d status = 0x%x\n", wIndex, temp);
break;
case USB_PORT_FEAT_REMOTE_WAKE_MASK:
diff --git a/drivers/usb/host/xhci-plat.c b/drivers/usb/host/xhci-plat.c
index 588546a..c7596a7 100644
--- a/drivers/usb/host/xhci-plat.c
+++ b/drivers/usb/host/xhci-plat.c
@@ -220,7 +220,15 @@
* 3. xhci_plat is grandchild of a pci device (dwc3-pci)
*/
sysdev = &pdev->dev;
- if (sysdev->parent && !sysdev->of_node && sysdev->parent->of_node)
+ /*
+ * If sysdev->parent->parent is available and part of IOMMU group
+ * (indicating possible usage of SMMU enablement), then use
+ * sysdev->parent->parent as sysdev.
+ */
+ if (sysdev->parent && !sysdev->of_node && sysdev->parent->of_node &&
+ sysdev->parent->parent && sysdev->parent->parent->iommu_group)
+ sysdev = sysdev->parent->parent;
+ else if (sysdev->parent && !sysdev->of_node && sysdev->parent->of_node)
sysdev = sysdev->parent;
#ifdef CONFIG_PCI
else if (sysdev->parent && sysdev->parent->parent &&
@@ -316,7 +324,7 @@
if (device_property_read_u32(&pdev->dev, "xhci-imod-value", &imod))
imod = 0;
- if (device_property_read_u32(sysdev, "usb-core-id", &xhci->core_id))
+ if (device_property_read_u32(&pdev->dev, "usb-core-id", &xhci->core_id))
xhci->core_id = -EINVAL;
hcd->usb_phy = devm_usb_get_phy_by_phandle(sysdev, "usb-phy", 0);
diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c
index ab3633c..ae8a727 100644
--- a/drivers/usb/host/xhci.c
+++ b/drivers/usb/host/xhci.c
@@ -138,7 +138,13 @@
{
u32 temp;
int ret;
+ struct usb_hcd *hcd = xhci_to_hcd(xhci);
+ /*
+ * disable irq to avoid xhci_irq flooding due to unhandeled port
+ * change event in halt state, as soon as xhci_start clears halt bit
+ */
+ disable_irq(hcd->irq);
temp = readl(&xhci->op_regs->command);
temp |= (CMD_RUN);
xhci_dbg_trace(xhci, trace_xhci_dbg_init, "// Turn on HC, cmd = 0x%x.",
@@ -159,6 +165,8 @@
/* clear state flags. Including dying, halted or removing */
xhci->xhc_state = 0;
+ enable_irq(hcd->irq);
+
return ret;
}
diff --git a/drivers/usb/pd/policy_engine.c b/drivers/usb/pd/policy_engine.c
index 5cd7670..56b2a6d 100644
--- a/drivers/usb/pd/policy_engine.c
+++ b/drivers/usb/pd/policy_engine.c
@@ -477,6 +477,21 @@
}
EXPORT_SYMBOL(usbpd_get_plug_orientation);
+static unsigned int get_connector_type(struct usbpd *pd)
+{
+ int ret;
+ union power_supply_propval val;
+
+ ret = power_supply_get_property(pd->usb_psy,
+ POWER_SUPPLY_PROP_CONNECTOR_TYPE, &val);
+
+ if (ret) {
+ dev_err(&pd->dev, "Unable to read CONNECTOR TYPE: %d\n", ret);
+ return ret;
+ }
+ return val.intval;
+}
+
static inline void stop_usb_host(struct usbpd *pd)
{
extcon_set_state_sync(pd->extcon, EXTCON_USB_HOST, 0);
@@ -2084,7 +2099,6 @@
if (pd->current_pr == PR_SINK) {
usbpd_set_state(pd, PE_SNK_STARTUP);
} else if (pd->current_pr == PR_SRC) {
- enable_vbus(pd);
if (!pd->vconn_enabled &&
pd->typec_mode ==
POWER_SUPPLY_TYPEC_SINK_POWERED_CABLE) {
@@ -2094,6 +2108,7 @@
else
pd->vconn_enabled = true;
}
+ enable_vbus(pd);
usbpd_set_state(pd, PE_SRC_STARTUP);
}
@@ -3906,6 +3921,11 @@
goto destroy_wq;
}
+ if (get_connector_type(pd) == POWER_SUPPLY_CONNECTOR_MICRO_USB) {
+ usbpd_dbg(&pd->dev, "USB connector is microAB hence failing pdphy_probe\n");
+ ret = -EINVAL;
+ goto put_psy;
+ }
/*
* associate extcon with the parent dev as it could have a DT
* node which will be useful for extcon_get_edev_by_phandle()
diff --git a/drivers/usb/phy/phy-msm-qusb-v2.c b/drivers/usb/phy/phy-msm-qusb-v2.c
index 81c39a3..cce17e0 100644
--- a/drivers/usb/phy/phy-msm-qusb-v2.c
+++ b/drivers/usb/phy/phy-msm-qusb-v2.c
@@ -27,6 +27,7 @@
#include <linux/usb/phy.h>
#include <linux/reset.h>
#include <linux/debugfs.h>
+#include <linux/hrtimer.h>
/* QUSB2PHY_PWR_CTRL1 register related bits */
#define PWR_CTRL1_POWR_DOWN BIT(0)
@@ -126,6 +127,10 @@
u32 sq_ctrl2_default;
bool chirp_disable;
+ struct pinctrl *pinctrl;
+ struct pinctrl_state *atest_usb13_suspend;
+ struct pinctrl_state *atest_usb13_active;
+
/* emulation targets specific */
void __iomem *emu_phy_base;
bool emulation;
@@ -139,6 +144,8 @@
/* override TUNEX registers value */
struct dentry *root;
u8 tune[5];
+
+ struct hrtimer timer;
};
static void qusb_phy_enable_clocks(struct qusb_phy *qphy, bool on)
@@ -511,6 +518,42 @@
return 0;
}
+static enum hrtimer_restart qusb_dis_ext_pulldown_timer(struct hrtimer *timer)
+{
+ struct qusb_phy *qphy = container_of(timer, struct qusb_phy, timer);
+ int ret = 0;
+
+ if (qphy->pinctrl && qphy->atest_usb13_suspend) {
+ ret = pinctrl_select_state(qphy->pinctrl,
+ qphy->atest_usb13_suspend);
+ if (ret < 0)
+ dev_err(qphy->phy.dev,
+ "pinctrl state suspend select failed\n");
+ }
+
+ return HRTIMER_NORESTART;
+}
+
+static void qusb_phy_enable_ext_pulldown(struct usb_phy *phy)
+{
+ struct qusb_phy *qphy = container_of(phy, struct qusb_phy, phy);
+ int ret = 0;
+
+ dev_dbg(phy->dev, "%s\n", __func__);
+
+ if (qphy->pinctrl && qphy->atest_usb13_active) {
+ ret = pinctrl_select_state(qphy->pinctrl,
+ qphy->atest_usb13_active);
+ if (ret < 0) {
+ dev_err(phy->dev,
+ "pinctrl state active select failed\n");
+ return;
+ }
+
+ hrtimer_start(&qphy->timer, ms_to_ktime(10), HRTIMER_MODE_REL);
+ }
+}
+
static void qusb_phy_shutdown(struct usb_phy *phy)
{
struct qusb_phy *qphy = container_of(phy, struct qusb_phy, phy);
@@ -1082,6 +1125,30 @@
return PTR_ERR(qphy->vdda18);
}
+ qphy->pinctrl = devm_pinctrl_get(dev);
+ if (IS_ERR(qphy->pinctrl)) {
+ ret = PTR_ERR(qphy->pinctrl);
+ if (ret == -EPROBE_DEFER)
+ return ret;
+ dev_err(dev, "pinctrl not available\n");
+ goto skip_pinctrl_config;
+ }
+ qphy->atest_usb13_suspend = pinctrl_lookup_state(qphy->pinctrl,
+ "atest_usb13_suspend");
+ if (IS_ERR(qphy->atest_usb13_suspend)) {
+ dev_err(dev, "pinctrl lookup atest_usb13_suspend failed\n");
+ goto skip_pinctrl_config;
+ }
+
+ qphy->atest_usb13_active = pinctrl_lookup_state(qphy->pinctrl,
+ "atest_usb13_active");
+ if (IS_ERR(qphy->atest_usb13_active))
+ dev_err(dev, "pinctrl lookup atest_usb13_active failed\n");
+
+ hrtimer_init(&qphy->timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
+ qphy->timer.function = qusb_dis_ext_pulldown_timer;
+
+skip_pinctrl_config:
mutex_init(&qphy->lock);
platform_set_drvdata(pdev, qphy);
@@ -1093,6 +1160,7 @@
qphy->phy.notify_connect = qusb_phy_notify_connect;
qphy->phy.notify_disconnect = qusb_phy_notify_disconnect;
qphy->phy.disable_chirp = qusb_phy_disable_chirp;
+ qphy->phy.start_port_reset = qusb_phy_enable_ext_pulldown;
ret = usb_add_phy_dev(&qphy->phy);
if (ret)
diff --git a/drivers/usb/phy/phy-msm-qusb.c b/drivers/usb/phy/phy-msm-qusb.c
index f7ff9e8f..9c33c6e 100644
--- a/drivers/usb/phy/phy-msm-qusb.c
+++ b/drivers/usb/phy/phy-msm-qusb.c
@@ -45,6 +45,8 @@
#define FREEZIO_N BIT(1)
#define POWER_DOWN BIT(0)
+#define QUSB2PHY_PORT_TEST_CTRL 0xB8
+
#define QUSB2PHY_PWR_CTRL1 0x210
#define PWR_CTRL1_CLAMP_N_EN BIT(1)
#define PWR_CTRL1_POWR_DOWN BIT(0)
@@ -68,10 +70,7 @@
#define QUSB2PHY_PORT_TUNE2 0x84
#define QUSB2PHY_PORT_TUNE3 0x88
#define QUSB2PHY_PORT_TUNE4 0x8C
-
-/* In case Efuse register shows zero, use this value */
-#define TUNE2_DEFAULT_HIGH_NIBBLE 0xB
-#define TUNE2_DEFAULT_LOW_NIBBLE 0x3
+#define QUSB2PHY_PORT_TUNE5 0x90
/* Get TUNE2's high nibble value read from efuse */
#define TUNE2_HIGH_NIBBLE_VAL(val, pos, mask) ((val >> pos) & mask)
@@ -98,21 +97,42 @@
#define QUSB2PHY_REFCLK_ENABLE BIT(0)
-unsigned int tune2;
-module_param(tune2, uint, S_IRUGO | S_IWUSR);
+static unsigned int tune1;
+module_param(tune1, uint, 0644);
+MODULE_PARM_DESC(tune1, "QUSB PHY TUNE1");
+
+static unsigned int tune2;
+module_param(tune2, uint, 0644);
MODULE_PARM_DESC(tune2, "QUSB PHY TUNE2");
+static unsigned int tune3;
+module_param(tune3, uint, 0644);
+MODULE_PARM_DESC(tune3, "QUSB PHY TUNE3");
+
+static unsigned int tune4;
+module_param(tune4, uint, 0644);
+MODULE_PARM_DESC(tune4, "QUSB PHY TUNE4");
+
+static unsigned int tune5;
+module_param(tune5, uint, 0644);
+MODULE_PARM_DESC(tune5, "QUSB PHY TUNE5");
+
+
struct qusb_phy {
struct usb_phy phy;
void __iomem *base;
void __iomem *tune2_efuse_reg;
void __iomem *ref_clk_base;
+ void __iomem *tcsr_clamp_dig_n;
struct clk *ref_clk_src;
struct clk *ref_clk;
struct clk *cfg_ahb_clk;
struct reset_control *phy_reset;
+ struct clk *iface_clk;
+ struct clk *core_clk;
+ struct regulator *gdsc;
struct regulator *vdd;
struct regulator *vdda33;
struct regulator *vdda18;
@@ -124,6 +144,7 @@
u32 tune2_val;
int tune2_efuse_bit_pos;
int tune2_efuse_num_of_bits;
+ int tune2_efuse_correction;
bool power_enabled;
bool clocks_enabled;
@@ -145,6 +166,8 @@
int phy_pll_reset_seq_len;
int *emu_dcm_reset_seq;
int emu_dcm_reset_seq_len;
+ bool put_into_high_z_state;
+ struct mutex phy_lock;
};
static void qusb_phy_enable_clocks(struct qusb_phy *qphy, bool on)
@@ -155,14 +178,22 @@
if (!qphy->clocks_enabled && on) {
clk_prepare_enable(qphy->ref_clk_src);
clk_prepare_enable(qphy->ref_clk);
+ clk_prepare_enable(qphy->iface_clk);
+ clk_prepare_enable(qphy->core_clk);
clk_prepare_enable(qphy->cfg_ahb_clk);
qphy->clocks_enabled = true;
}
if (qphy->clocks_enabled && !on) {
+ clk_disable_unprepare(qphy->cfg_ahb_clk);
+ /*
+ * FSM depedency beween iface_clk and core_clk.
+ * Hence turned off core_clk before iface_clk.
+ */
+ clk_disable_unprepare(qphy->core_clk);
+ clk_disable_unprepare(qphy->iface_clk);
clk_disable_unprepare(qphy->ref_clk);
clk_disable_unprepare(qphy->ref_clk_src);
- clk_disable_unprepare(qphy->cfg_ahb_clk);
qphy->clocks_enabled = false;
}
@@ -170,6 +201,32 @@
qphy->clocks_enabled);
}
+static int qusb_phy_gdsc(struct qusb_phy *qphy, bool on)
+{
+ int ret;
+
+ if (IS_ERR_OR_NULL(qphy->gdsc))
+ return -EPERM;
+
+ if (on) {
+ dev_dbg(qphy->phy.dev, "TURNING ON GDSC\n");
+ ret = regulator_enable(qphy->gdsc);
+ if (ret) {
+ dev_err(qphy->phy.dev, "unable to enable gdsc\n");
+ return ret;
+ }
+ } else {
+ dev_dbg(qphy->phy.dev, "TURNING OFF GDSC\n");
+ ret = regulator_disable(qphy->gdsc);
+ if (ret) {
+ dev_err(qphy->phy.dev, "unable to disable gdsc\n");
+ return ret;
+ }
+ }
+
+ return ret;
+}
+
static int qusb_phy_config_vdd(struct qusb_phy *qphy, int high)
{
int min, ret;
@@ -313,6 +370,7 @@
{
u8 num_of_bits;
u32 bit_mask = 1;
+ u8 reg_val;
pr_debug("%s(): num_of_bits:%d bit_pos:%d\n", __func__,
qphy->tune2_efuse_num_of_bits,
@@ -326,9 +384,8 @@
/*
* Read EFUSE register having TUNE2 parameter's high nibble.
- * If efuse register shows value as 0x0, then use default value
- * as 0xB as high nibble. Otherwise use efuse register based
- * value for this purpose.
+ * If efuse register shows value as 0x0, then use previous value
+ * as it is. Otherwise use efuse register based value for this purpose.
*/
qphy->tune2_val = readl_relaxed(qphy->tune2_efuse_reg);
pr_debug("%s(): bit_mask:%d efuse based tune2 value:%d\n",
@@ -337,12 +394,24 @@
qphy->tune2_val = TUNE2_HIGH_NIBBLE_VAL(qphy->tune2_val,
qphy->tune2_efuse_bit_pos, bit_mask);
- if (!qphy->tune2_val)
- qphy->tune2_val = TUNE2_DEFAULT_HIGH_NIBBLE;
+ /* Update higher nibble of TUNE2 value for better rise/fall times */
+ if (qphy->tune2_efuse_correction && qphy->tune2_val) {
+ if (qphy->tune2_efuse_correction > 5 ||
+ qphy->tune2_efuse_correction < -10)
+ pr_warn("Correction value is out of range : %d\n",
+ qphy->tune2_efuse_correction);
+ else
+ qphy->tune2_val = qphy->tune2_val +
+ qphy->tune2_efuse_correction;
+ }
- /* Get TUNE2 byte value using high and low nibble value */
- qphy->tune2_val = ((qphy->tune2_val << 0x4) |
- TUNE2_DEFAULT_LOW_NIBBLE);
+ reg_val = readb_relaxed(qphy->base + QUSB2PHY_PORT_TUNE2);
+ if (qphy->tune2_val) {
+ reg_val &= 0x0f;
+ reg_val |= (qphy->tune2_val << 4);
+ }
+
+ qphy->tune2_val = reg_val;
}
static void qusb_phy_write_seq(void __iomem *base, u32 *seq, int cnt,
@@ -450,7 +519,7 @@
* and try to read EFUSE value only once i.e. not every USB
* cable connect case.
*/
- if (qphy->tune2_efuse_reg) {
+ if (qphy->tune2_efuse_reg && !tune2) {
if (!qphy->tune2_val)
qusb_phy_get_tune2_param(qphy);
@@ -460,13 +529,29 @@
qphy->base + QUSB2PHY_PORT_TUNE2);
}
- /* If tune2 modparam set, override tune2 value */
- if (tune2) {
- pr_debug("%s(): (modparam) TUNE2 val:0x%02x\n",
- __func__, tune2);
+ /* If tune modparam set, override tune value */
+
+ pr_debug("%s():userspecified modparams TUNEX val:0x%x %x %x %x %x\n",
+ __func__, tune1, tune2, tune3, tune4, tune5);
+ if (tune1)
+ writel_relaxed(tune1,
+ qphy->base + QUSB2PHY_PORT_TUNE1);
+
+ if (tune2)
writel_relaxed(tune2,
qphy->base + QUSB2PHY_PORT_TUNE2);
- }
+
+ if (tune3)
+ writel_relaxed(tune3,
+ qphy->base + QUSB2PHY_PORT_TUNE3);
+
+ if (tune4)
+ writel_relaxed(tune4,
+ qphy->base + QUSB2PHY_PORT_TUNE4);
+
+ if (tune5)
+ writel_relaxed(tune5,
+ qphy->base + QUSB2PHY_PORT_TUNE5);
/* ensure above writes are completed before re-enabling PHY */
wmb();
@@ -596,27 +681,55 @@
writel_relaxed(intr_mask,
qphy->base + QUSB2PHY_PORT_INTR_CTRL);
+ if (linestate & (LINESTATE_DP | LINESTATE_DM)) {
+ /* enable phy auto-resume */
+ writel_relaxed(0x0C,
+ qphy->base + QUSB2PHY_PORT_TEST_CTRL);
+ /* flush the previous write before next write */
+ wmb();
+ writel_relaxed(0x04,
+ qphy->base + QUSB2PHY_PORT_TEST_CTRL);
+ }
+
+
+ dev_dbg(phy->dev, "%s: intr_mask = %x\n",
+ __func__, intr_mask);
+
+ /* Makes sure that above write goes through */
+ wmb();
+
qusb_phy_enable_clocks(qphy, false);
} else { /* Disconnect case */
+ mutex_lock(&qphy->phy_lock);
/* Disable all interrupts */
writel_relaxed(0x00,
qphy->base + QUSB2PHY_PORT_INTR_CTRL);
- /*
- * Phy in non-driving mode leaves Dp and Dm lines in
- * high-Z state. Controller power collapse is not
- * switching phy to non-driving mode causing charger
- * detection failure. Bring phy to non-driving mode by
- * overriding controller output via UTMI interface.
- */
- writel_relaxed(TERM_SELECT | XCVR_SELECT_FS |
- OP_MODE_NON_DRIVE,
- qphy->base + QUSB2PHY_PORT_UTMI_CTRL1);
- writel_relaxed(UTMI_ULPI_SEL | UTMI_TEST_MUX_SEL,
- qphy->base + QUSB2PHY_PORT_UTMI_CTRL2);
+ /* Disable PHY */
+ writel_relaxed(POWER_DOWN,
+ qphy->base + QUSB2PHY_PORT_POWERDOWN);
+ /* Make sure that above write is completed */
+ wmb();
qusb_phy_enable_clocks(qphy, false);
- qusb_phy_enable_power(qphy, false);
+ if (qphy->tcsr_clamp_dig_n)
+ writel_relaxed(0x0,
+ qphy->tcsr_clamp_dig_n);
+ /* Do not disable power rails if there is vote for it */
+ if (!qphy->dpdm_enable)
+ qusb_phy_enable_power(qphy, false);
+ else
+ dev_dbg(phy->dev, "race with rm_pulldown. Keep ldo ON\n");
+ mutex_unlock(&qphy->phy_lock);
+
+ /*
+ * Set put_into_high_z_state to true so next USB
+ * cable connect, DPF_DMF request performs PHY
+ * reset and put it into high-z state. For bootup
+ * with or without USB cable, it doesn't require
+ * to put QUSB PHY into high-z state.
+ */
+ qphy->put_into_high_z_state = true;
}
qphy->suspended = true;
} else {
@@ -629,6 +742,9 @@
qphy->base + QUSB2PHY_PORT_INTR_CTRL);
} else {
qusb_phy_enable_power(qphy, true);
+ if (qphy->tcsr_clamp_dig_n)
+ writel_relaxed(0x1,
+ qphy->tcsr_clamp_dig_n);
qusb_phy_enable_clocks(qphy, true);
}
qphy->suspended = false;
@@ -669,15 +785,61 @@
dev_dbg(qphy->phy.dev, "%s dpdm_enable:%d\n",
__func__, qphy->dpdm_enable);
+ mutex_lock(&qphy->phy_lock);
if (!qphy->dpdm_enable) {
ret = qusb_phy_enable_power(qphy, true);
if (ret < 0) {
dev_dbg(qphy->phy.dev,
"dpdm regulator enable failed:%d\n", ret);
+ mutex_unlock(&qphy->phy_lock);
return ret;
}
qphy->dpdm_enable = true;
+ if (qphy->put_into_high_z_state) {
+ if (qphy->tcsr_clamp_dig_n)
+ writel_relaxed(0x1,
+ qphy->tcsr_clamp_dig_n);
+
+ qusb_phy_gdsc(qphy, true);
+ qusb_phy_enable_clocks(qphy, true);
+
+ dev_dbg(qphy->phy.dev, "RESET QUSB PHY\n");
+ ret = reset_control_assert(qphy->phy_reset);
+ if (ret)
+ dev_err(qphy->phy.dev, "phyassert failed\n");
+ usleep_range(100, 150);
+ ret = reset_control_deassert(qphy->phy_reset);
+ if (ret)
+ dev_err(qphy->phy.dev, "deassert failed\n");
+
+ /*
+ * Phy in non-driving mode leaves Dp and Dm
+ * lines in high-Z state. Controller power
+ * collapse is not switching phy to non-driving
+ * mode causing charger detection failure. Bring
+ * phy to non-driving mode by overriding
+ * controller output via UTMI interface.
+ */
+ writel_relaxed(TERM_SELECT | XCVR_SELECT_FS |
+ OP_MODE_NON_DRIVE,
+ qphy->base + QUSB2PHY_PORT_UTMI_CTRL1);
+ writel_relaxed(UTMI_ULPI_SEL |
+ UTMI_TEST_MUX_SEL,
+ qphy->base + QUSB2PHY_PORT_UTMI_CTRL2);
+
+
+ /* Disable PHY */
+ writel_relaxed(CLAMP_N_EN | FREEZIO_N |
+ POWER_DOWN,
+ qphy->base + QUSB2PHY_PORT_POWERDOWN);
+ /* Make sure that above write is completed */
+ wmb();
+
+ qusb_phy_enable_clocks(qphy, false);
+ qusb_phy_gdsc(qphy, false);
+ }
}
+ mutex_unlock(&qphy->phy_lock);
return ret;
}
@@ -690,19 +852,25 @@
dev_dbg(qphy->phy.dev, "%s dpdm_enable:%d\n",
__func__, qphy->dpdm_enable);
+ mutex_lock(&qphy->phy_lock);
if (qphy->dpdm_enable) {
if (!qphy->cable_connected) {
+ if (qphy->tcsr_clamp_dig_n)
+ writel_relaxed(0x0,
+ qphy->tcsr_clamp_dig_n);
dev_dbg(qphy->phy.dev, "turn off for HVDCP case\n");
ret = qusb_phy_enable_power(qphy, false);
if (ret < 0) {
dev_dbg(qphy->phy.dev,
"dpdm regulator disable failed:%d\n",
ret);
+ mutex_unlock(&qphy->phy_lock);
return ret;
}
}
qphy->dpdm_enable = false;
}
+ mutex_unlock(&qphy->phy_lock);
return ret;
}
@@ -794,6 +962,9 @@
"qcom,tune2-efuse-num-bits",
&qphy->tune2_efuse_num_of_bits);
}
+ of_property_read_u32(dev->of_node,
+ "qcom,tune2-efuse-correction",
+ &qphy->tune2_efuse_correction);
if (ret) {
dev_err(dev, "DT Value for tune2 efuse is invalid.\n");
@@ -829,6 +1000,17 @@
}
}
+ res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
+ "tcsr_clamp_dig_n_1p8");
+ if (res) {
+ qphy->tcsr_clamp_dig_n = devm_ioremap_nocache(dev,
+ res->start, resource_size(res));
+ if (IS_ERR(qphy->tcsr_clamp_dig_n)) {
+ dev_err(dev, "err reading tcsr_clamp_dig_n\n");
+ qphy->tcsr_clamp_dig_n = NULL;
+ }
+ }
+
qphy->ref_clk_src = devm_clk_get(dev, "ref_clk_src");
if (IS_ERR(qphy->ref_clk_src))
dev_dbg(dev, "clk get failed for ref_clk_src\n");
@@ -847,6 +1029,34 @@
if (IS_ERR(qphy->phy_reset))
return PTR_ERR(qphy->phy_reset);
+ if (of_property_match_string(dev->of_node,
+ "clock-names", "iface_clk") >= 0) {
+ qphy->iface_clk = devm_clk_get(dev, "iface_clk");
+ if (IS_ERR(qphy->iface_clk)) {
+ ret = PTR_ERR(qphy->iface_clk);
+ qphy->iface_clk = NULL;
+ if (ret == -EPROBE_DEFER)
+ return ret;
+ dev_err(dev, "couldn't get iface_clk(%d)\n", ret);
+ }
+ }
+
+ if (of_property_match_string(dev->of_node,
+ "clock-names", "core_clk") >= 0) {
+ qphy->core_clk = devm_clk_get(dev, "core_clk");
+ if (IS_ERR(qphy->core_clk)) {
+ ret = PTR_ERR(qphy->core_clk);
+ qphy->core_clk = NULL;
+ if (ret == -EPROBE_DEFER)
+ return ret;
+ dev_err(dev, "couldn't get core_clk(%d)\n", ret);
+ }
+ }
+
+ qphy->gdsc = devm_regulator_get(dev, "USB3_GDSC");
+ if (IS_ERR(qphy->gdsc))
+ qphy->gdsc = NULL;
+
qphy->emulation = of_property_read_bool(dev->of_node,
"qcom,emulation");
@@ -981,6 +1191,7 @@
return PTR_ERR(qphy->vdda18);
}
+ mutex_init(&qphy->phy_lock);
platform_set_drvdata(pdev, qphy);
qphy->phy.label = "msm-qusb-phy";
@@ -1010,6 +1221,10 @@
if (ret)
usb_remove_phy(&qphy->phy);
+ /* de-assert clamp dig n to reduce leakage on 1p8 upon boot up */
+ if (qphy->tcsr_clamp_dig_n)
+ writel_relaxed(0x0, qphy->tcsr_clamp_dig_n);
+
return ret;
}
diff --git a/drivers/usb/phy/phy-msm-snps-hs.c b/drivers/usb/phy/phy-msm-snps-hs.c
index 2d18faf..fd84889 100644
--- a/drivers/usb/phy/phy-msm-snps-hs.c
+++ b/drivers/usb/phy/phy-msm-snps-hs.c
@@ -74,7 +74,7 @@
#define USB_HSPHY_3P3_HPM_LOAD 16000 /* uA */
#define USB_HSPHY_3P3_VOL_FSHOST 3150000 /* uV */
-#define USB_HSPHY_1P8_VOL_MIN 1800000 /* uV */
+#define USB_HSPHY_1P8_VOL_MIN 1704000 /* uV */
#define USB_HSPHY_1P8_VOL_MAX 1800000 /* uV */
#define USB_HSPHY_1P8_HPM_LOAD 19000 /* uA */
diff --git a/drivers/usb/phy/phy-msm-ssusb-qmp.c b/drivers/usb/phy/phy-msm-ssusb-qmp.c
index 7e7c76c..8134579 100644
--- a/drivers/usb/phy/phy-msm-ssusb-qmp.c
+++ b/drivers/usb/phy/phy-msm-ssusb-qmp.c
@@ -152,6 +152,9 @@
{
.compatible = "qcom,usb-ssphy-qmp-dp-combo",
},
+ {
+ .compatible = "qcom,usb-ssphy-qmp-usb3-or-dp",
+ },
{ },
};
MODULE_DEVICE_TABLE(of, msm_usb_id_table);
@@ -177,10 +180,11 @@
static void msm_ssusb_qmp_clamp_enable(struct msm_ssphy_qmp *phy, bool val)
{
switch (phy->phy.type) {
- case USB_PHY_TYPE_USB3_DP:
+ case USB_PHY_TYPE_USB3_AND_DP:
writel_relaxed(!val, phy->base +
phy->phy_reg[USB3_PCS_MISC_CLAMP_ENABLE]);
break;
+ case USB_PHY_TYPE_USB3_OR_DP:
case USB_PHY_TYPE_USB3:
writel_relaxed(!!val, phy->vls_clamp_reg);
break;
@@ -345,7 +349,7 @@
usb_qmp_powerup_phy(phy);
switch (phy->phy.type) {
- case USB_PHY_TYPE_USB3_DP:
+ case USB_PHY_TYPE_USB3_AND_DP:
/* override hardware control for reset of qmp phy */
writel_relaxed(SW_DPPHY_RESET_MUX | SW_DPPHY_RESET |
SW_USB3PHY_RESET_MUX | SW_USB3PHY_RESET,
@@ -366,7 +370,7 @@
writel_relaxed(0x00,
phy->base + phy->phy_reg[USB3_DP_COM_RESET_OVRD_CTRL]);
break;
- case USB_PHY_TYPE_USB3:
+ case USB_PHY_TYPE_USB3_OR_DP:
if (val > 0) {
dev_err(phy->phy.dev,
"USB QMP PHY: Update TYPEC CTRL(%d)\n", val);
@@ -375,7 +379,8 @@
}
break;
default:
- dev_err(phy->phy.dev, "portselect: Unknown USB QMP PHY type\n");
+ dev_dbg(phy->phy.dev, "no portselect for phy type %d\n",
+ phy->phy.type);
break;
}
@@ -386,7 +391,7 @@
static void usb_qmp_powerup_phy(struct msm_ssphy_qmp *phy)
{
switch (phy->phy.type) {
- case USB_PHY_TYPE_USB3_DP:
+ case USB_PHY_TYPE_USB3_AND_DP:
/* power up USB3 and DP common logic block */
writel_relaxed(0x01,
phy->base + phy->phy_reg[USB3_DP_COM_POWER_DOWN_CTRL]);
@@ -399,6 +404,7 @@
*/
/* intentional fall-through */
+ case USB_PHY_TYPE_USB3_OR_DP:
case USB_PHY_TYPE_USB3:
/* power up USB3 PHY */
writel_relaxed(0x01,
@@ -453,7 +459,7 @@
}
/* perform software reset of PHY common logic */
- if (phy->phy.type == USB_PHY_TYPE_USB3_DP)
+ if (phy->phy.type == USB_PHY_TYPE_USB3_AND_DP)
writel_relaxed(0x00,
phy->base + phy->phy_reg[USB3_DP_COM_SW_RESET]);
@@ -797,7 +803,11 @@
phy->phy.type = USB_PHY_TYPE_USB3;
if (of_device_is_compatible(dev->of_node,
"qcom,usb-ssphy-qmp-dp-combo"))
- phy->phy.type = USB_PHY_TYPE_USB3_DP;
+ phy->phy.type = USB_PHY_TYPE_USB3_AND_DP;
+
+ if (of_device_is_compatible(dev->of_node,
+ "qcom,usb-ssphy-qmp-usb-or-dp"))
+ phy->phy.type = USB_PHY_TYPE_USB3_OR_DP;
ret = msm_ssphy_qmp_get_clks(phy, dev);
if (ret)
@@ -810,7 +820,7 @@
goto err;
}
- if (phy->phy.type == USB_PHY_TYPE_USB3_DP) {
+ if (phy->phy.type == USB_PHY_TYPE_USB3_AND_DP) {
phy->global_phy_reset = devm_reset_control_get(dev,
"global_phy_reset");
if (IS_ERR(phy->global_phy_reset)) {
@@ -871,7 +881,7 @@
goto err;
}
- if (phy->phy.type == USB_PHY_TYPE_USB3) {
+ if (phy->phy.type != USB_PHY_TYPE_USB3_AND_DP) {
res = platform_get_resource_byname(pdev,
IORESOURCE_MEM, "vls_clamp_reg");
phy->vls_clamp_reg = devm_ioremap_resource(dev, res);
@@ -978,7 +988,7 @@
phy->phy.notify_connect = msm_ssphy_qmp_notify_connect;
phy->phy.notify_disconnect = msm_ssphy_qmp_notify_disconnect;
- if (phy->phy.type == USB_PHY_TYPE_USB3_DP)
+ if (phy->phy.type == USB_PHY_TYPE_USB3_AND_DP)
phy->phy.reset = msm_ssphy_qmp_dp_combo_reset;
else
phy->phy.reset = msm_ssphy_qmp_reset;
diff --git a/fs/jbd2/journal.c b/fs/jbd2/journal.c
index 7d4b557..6cb3a8c 100644
--- a/fs/jbd2/journal.c
+++ b/fs/jbd2/journal.c
@@ -276,11 +276,11 @@
goto loop;
end_loop:
- write_unlock(&journal->j_state_lock);
del_timer_sync(&journal->j_commit_timer);
journal->j_task = NULL;
wake_up(&journal->j_wait_done_commit);
jbd_debug(1, "Journal thread exiting.\n");
+ write_unlock(&journal->j_state_lock);
return 0;
}
diff --git a/fs/sdcardfs/inode.c b/fs/sdcardfs/inode.c
index 4a971e2..8ed0ea1 100644
--- a/fs/sdcardfs/inode.c
+++ b/fs/sdcardfs/inode.c
@@ -600,7 +600,7 @@
static int sdcardfs_permission_wrn(struct inode *inode, int mask)
{
- WARN_RATELIMIT(1, "sdcardfs does not support permission. Use permission2.\n");
+ pr_debug("sdcardfs does not support permission. Use permission2.\n");
return -EINVAL;
}
diff --git a/include/dt-bindings/clock/qcom,gcc-sdxpoorwills.h b/include/dt-bindings/clock/qcom,gcc-sdxpoorwills.h
index 950811f..7e1394c 100644
--- a/include/dt-bindings/clock/qcom,gcc-sdxpoorwills.h
+++ b/include/dt-bindings/clock/qcom,gcc-sdxpoorwills.h
@@ -65,43 +65,44 @@
#define GCC_MSS_CFG_AHB_CLK 47
#define GCC_MSS_GPLL0_DIV_CLK_SRC 48
#define GCC_MSS_SNOC_AXI_CLK 49
-#define GCC_PCIE_AUX_CLK 50
-#define GCC_PCIE_AUX_PHY_CLK_SRC 51
-#define GCC_PCIE_CFG_AHB_CLK 52
-#define GCC_PCIE_MSTR_AXI_CLK 53
-#define GCC_PCIE_PHY_REFGEN_CLK 54
-#define GCC_PCIE_PHY_REFGEN_CLK_SRC 55
-#define GCC_PCIE_PIPE_CLK 56
-#define GCC_PCIE_SLEEP_CLK 57
-#define GCC_PCIE_SLV_AXI_CLK 58
-#define GCC_PCIE_SLV_Q2A_AXI_CLK 59
-#define GCC_PDM2_CLK 60
-#define GCC_PDM2_CLK_SRC 61
-#define GCC_PDM_AHB_CLK 62
-#define GCC_PDM_XO4_CLK 63
-#define GCC_PRNG_AHB_CLK 64
-#define GCC_SDCC1_AHB_CLK 65
-#define GCC_SDCC1_APPS_CLK 66
-#define GCC_SDCC1_APPS_CLK_SRC 67
-#define GCC_SPMI_FETCHER_AHB_CLK 68
-#define GCC_SPMI_FETCHER_CLK 69
-#define GCC_SPMI_FETCHER_CLK_SRC 70
-#define GCC_SYS_NOC_CPUSS_AHB_CLK 71
-#define GCC_SYS_NOC_USB3_CLK 72
-#define GCC_USB30_MASTER_CLK 73
-#define GCC_USB30_MASTER_CLK_SRC 74
-#define GCC_USB30_MOCK_UTMI_CLK 75
-#define GCC_USB30_MOCK_UTMI_CLK_SRC 76
-#define GCC_USB30_SLEEP_CLK 77
-#define GCC_USB3_PHY_AUX_CLK 78
-#define GCC_USB3_PHY_AUX_CLK_SRC 79
-#define GCC_USB3_PHY_PIPE_CLK 80
-#define GCC_USB_PHY_CFG_AHB2PHY_CLK 81
-#define GPLL0 82
-#define GPLL0_OUT_EVEN 83
-#define GPLL4 84
-#define GPLL4_OUT_EVEN 85
-#define GCC_USB3_PRIM_CLKREF_CLK 86
+#define GCC_PCIE_0_CLKREF_CLK 50
+#define GCC_PCIE_AUX_CLK 51
+#define GCC_PCIE_AUX_PHY_CLK_SRC 52
+#define GCC_PCIE_CFG_AHB_CLK 53
+#define GCC_PCIE_MSTR_AXI_CLK 54
+#define GCC_PCIE_PHY_REFGEN_CLK 55
+#define GCC_PCIE_PHY_REFGEN_CLK_SRC 56
+#define GCC_PCIE_PIPE_CLK 57
+#define GCC_PCIE_SLEEP_CLK 58
+#define GCC_PCIE_SLV_AXI_CLK 59
+#define GCC_PCIE_SLV_Q2A_AXI_CLK 60
+#define GCC_PDM2_CLK 61
+#define GCC_PDM2_CLK_SRC 62
+#define GCC_PDM_AHB_CLK 63
+#define GCC_PDM_XO4_CLK 64
+#define GCC_PRNG_AHB_CLK 65
+#define GCC_SDCC1_AHB_CLK 66
+#define GCC_SDCC1_APPS_CLK 67
+#define GCC_SDCC1_APPS_CLK_SRC 68
+#define GCC_SPMI_FETCHER_AHB_CLK 69
+#define GCC_SPMI_FETCHER_CLK 70
+#define GCC_SPMI_FETCHER_CLK_SRC 71
+#define GCC_SYS_NOC_CPUSS_AHB_CLK 72
+#define GCC_SYS_NOC_USB3_CLK 73
+#define GCC_USB30_MASTER_CLK 74
+#define GCC_USB30_MASTER_CLK_SRC 75
+#define GCC_USB30_MOCK_UTMI_CLK 76
+#define GCC_USB30_MOCK_UTMI_CLK_SRC 77
+#define GCC_USB30_SLEEP_CLK 78
+#define GCC_USB3_PHY_AUX_CLK 79
+#define GCC_USB3_PHY_AUX_CLK_SRC 80
+#define GCC_USB3_PHY_PIPE_CLK 81
+#define GCC_USB3_PRIM_CLKREF_CLK 82
+#define GCC_USB_PHY_CFG_AHB2PHY_CLK 83
+#define GPLL0 84
+#define GPLL0_OUT_EVEN 85
+#define GPLL4 86
+#define GPLL4_OUT_EVEN 87
/* CPU clocks */
#define CLOCK_A7SS 0
diff --git a/include/dt-bindings/msm/msm-bus-ids.h b/include/dt-bindings/msm/msm-bus-ids.h
index ffa4bb0..f43b73b 100644
--- a/include/dt-bindings/msm/msm-bus-ids.h
+++ b/include/dt-bindings/msm/msm-bus-ids.h
@@ -262,7 +262,7 @@
#define MSM_BUS_MASTER_SPMI_FETCHER 151
#define MSM_BUS_MASTER_ANOC_SNOC 152
#define MSM_BUS_MASTER_ANOC_IPA 153
-#define MSM_BUS_MASTER_MASTER_LAST 154
+#define MSM_BUS_MASTER_IPA_PCIE 154
#define MSM_BUS_MASTER_LLCC_DISPLAY 20000
#define MSM_BUS_MASTER_MNOC_HF_MEM_NOC_DISPLAY 20001
@@ -343,10 +343,8 @@
#define MSM_BUS_SNOC_INT_2 10066
#define MSM_BUS_A0NOC_QDSS_INT 10067
#define MSM_BUS_SLAVE_ANOC_PCIE_A1NOC_SNOC 10068
-#define MSM_BUS_INT_LAST 10069
#define MSM_BUS_INT_TEST_ID 20000
-#define MSM_BUS_INT_TEST_LAST 20050
#define MSM_BUS_SLAVE_FIRST 512
#define MSM_BUS_SLAVE_EBI_CH0 512
@@ -607,7 +605,6 @@
#define MSM_BUS_SLAVE_ANOC_IPA 780
#define MSM_BUS_SLAVE_EMAC_CFG 781
#define MSM_BUS_SLAVE_EMMC_CFG 782
-#define MSM_BUS_SLAVE_LAST 783
#define MSM_BUS_SLAVE_EBI_CH0_DISPLAY 20512
#define MSM_BUS_SLAVE_LLCC_DISPLAY 20513
diff --git a/include/dt-bindings/regulator/qcom,rpm-smd-regulator.h b/include/dt-bindings/regulator/qcom,rpm-smd-regulator.h
new file mode 100644
index 0000000..8718c47
--- /dev/null
+++ b/include/dt-bindings/regulator/qcom,rpm-smd-regulator.h
@@ -0,0 +1,29 @@
+/* Copyright (c) 2015, 2017 The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef __QCOM_RPM_SMD_REGULATOR_H
+#define __QCOM_RPM_SMD_REGULATOR_H
+
+#define RPM_SMD_REGULATOR_LEVEL_NONE 0
+#define RPM_SMD_REGULATOR_LEVEL_RETENTION 16
+#define RPM_SMD_REGULATOR_LEVEL_RETENTION_PLUS 32
+#define RPM_SMD_REGULATOR_LEVEL_MIN_SVS 48
+#define RPM_SMD_REGULATOR_LEVEL_LOW_SVS 64
+#define RPM_SMD_REGULATOR_LEVEL_SVS 128
+#define RPM_SMD_REGULATOR_LEVEL_SVS_PLUS 192
+#define RPM_SMD_REGULATOR_LEVEL_NOM 256
+#define RPM_SMD_REGULATOR_LEVEL_NOM_PLUS 320
+#define RPM_SMD_REGULATOR_LEVEL_TURBO 384
+#define RPM_SMD_REGULATOR_LEVEL_TURBO_NO_CPR 416
+#define RPM_SMD_REGULATOR_LEVEL_BINNING 512
+
+#endif
diff --git a/include/linux/input/qpnp-power-on.h b/include/linux/input/qpnp-power-on.h
index a2624ab..5944f0f 100644
--- a/include/linux/input/qpnp-power-on.h
+++ b/include/linux/input/qpnp-power-on.h
@@ -51,6 +51,7 @@
};
enum pon_restart_reason {
+ /* 0 ~ 31 for common defined features */
PON_RESTART_REASON_UNKNOWN = 0x00,
PON_RESTART_REASON_RECOVERY = 0x01,
PON_RESTART_REASON_BOOTLOADER = 0x02,
@@ -58,6 +59,10 @@
PON_RESTART_REASON_DMVERITY_CORRUPTED = 0x04,
PON_RESTART_REASON_DMVERITY_ENFORCE = 0x05,
PON_RESTART_REASON_KEYS_CLEAR = 0x06,
+
+ /* 32 ~ 63 for OEMs/ODMs secific features */
+ PON_RESTART_REASON_OEM_MIN = 0x20,
+ PON_RESTART_REASON_OEM_MAX = 0x3f,
};
#ifdef CONFIG_INPUT_QPNP_POWER_ON
diff --git a/include/linux/ipa.h b/include/linux/ipa.h
index 405aed5..46ee6da 100644
--- a/include/linux/ipa.h
+++ b/include/linux/ipa.h
@@ -117,6 +117,19 @@
};
/**
+* enum ipa_vlan_ifaces - vlan interfaces types
+* @IPA_VLAN_IF_EMAC: used for EMAC ethernet device
+* @IPA_VLAN_IF_RNDIS: used for RNDIS USB device
+* @IPA_VLAN_IF_ECM: used for ECM USB device
+*/
+enum ipa_vlan_ifaces {
+ IPA_VLAN_IF_EMAC,
+ IPA_VLAN_IF_RNDIS,
+ IPA_VLAN_IF_ECM,
+ IPA_VLAN_IF_MAX
+};
+
+/**
* struct ipa_ep_cfg_nat - NAT configuration in IPA end-point
* @nat_en: This defines the default NAT mode for the pipe: in case of
* filter miss - the default NAT mode defines the NATing operation
@@ -1585,10 +1598,18 @@
* Returns: 0 on success, negative on failure
*/
int ipa_tz_unlock_reg(struct ipa_tz_unlock_reg_info *reg_info, u16 num_regs);
-
int ipa_get_smmu_params(struct ipa_smmu_in_params *in,
struct ipa_smmu_out_params *out);
-
+/**
+ * ipa_is_vlan_mode - check if a LAN driver should load in VLAN mode
+ * @iface - type of vlan capable device
+ * @res - query result: true for vlan mode, false for non vlan mode
+ *
+ * API must be called after ipa_is_ready() returns true, otherwise it will fail
+ *
+ * Returns: 0 on success, negative on failure
+ */
+int ipa_is_vlan_mode(enum ipa_vlan_ifaces iface, bool *res);
#else /* (CONFIG_IPA || CONFIG_IPA3) */
/*
@@ -2382,6 +2403,11 @@
{
return -EPERM;
}
+
+static inline int ipa_is_vlan_mode(enum ipa_vlan_ifaces iface, bool *res)
+{
+ return -EPERM;
+}
#endif /* (CONFIG_IPA || CONFIG_IPA3) */
#endif /* _IPA_H_ */
diff --git a/include/linux/mm.h b/include/linux/mm.h
index 9b21e2a..907e029 100644
--- a/include/linux/mm.h
+++ b/include/linux/mm.h
@@ -1164,8 +1164,6 @@
struct address_space *check_mapping; /* Check page->mapping if set */
pgoff_t first_index; /* Lowest page->index to unmap */
pgoff_t last_index; /* Highest page->index to unmap */
- bool ignore_dirty; /* Ignore dirty pages */
- bool check_swap_entries; /* Check also swap entries */
};
struct page *vm_normal_page(struct vm_area_struct *vma, unsigned long addr,
diff --git a/include/linux/regulator/rpm-smd-regulator.h b/include/linux/regulator/rpm-smd-regulator.h
new file mode 100644
index 0000000..1c735cd
--- /dev/null
+++ b/include/linux/regulator/rpm-smd-regulator.h
@@ -0,0 +1,134 @@
+/* Copyright (c) 2012-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.
+ */
+
+#ifndef _LINUX_REGULATOR_RPM_SMD_H
+#define _LINUX_REGULATOR_RPM_SMD_H
+
+#include <linux/device.h>
+
+struct rpm_regulator;
+
+/**
+ * enum rpm_regulator_voltage_corner - possible voltage corner values
+ *
+ * These should be used in regulator_set_voltage() and
+ * rpm_regulator_set_voltage() calls for corner type regulators as if they had
+ * units of uV.
+ *
+ * Note, the meaning of corner values is set by the RPM. It is possible that
+ * future platforms will utilize different corner values. The values specified
+ * in this enum correspond to MSM8974 for PMIC PM8841 SMPS 2 (VDD_Dig).
+ */
+enum rpm_regulator_voltage_corner {
+ RPM_REGULATOR_CORNER_NONE = 1,
+ RPM_REGULATOR_CORNER_RETENTION,
+ RPM_REGULATOR_CORNER_SVS_KRAIT,
+ RPM_REGULATOR_CORNER_SVS_SOC,
+ RPM_REGULATOR_CORNER_NORMAL,
+ RPM_REGULATOR_CORNER_TURBO,
+ RPM_REGULATOR_CORNER_SUPER_TURBO,
+};
+
+/**
+ * enum rpm_regulator_voltage_level - possible voltage level values
+ *
+ * These should be used in regulator_set_voltage() and
+ * rpm_regulator_set_voltage() calls for level type regulators as if they had
+ * units of uV.
+ *
+ * Note: the meaning of level values is set by the RPM.
+ */
+enum rpm_regulator_voltage_level {
+ RPM_REGULATOR_LEVEL_NONE = 0,
+ RPM_REGULATOR_LEVEL_RETENTION = 16,
+ RPM_REGULATOR_LEVEL_RETENTION_PLUS = 32,
+ RPM_REGULATOR_LEVEL_MIN_SVS = 48,
+ RPM_REGULATOR_LEVEL_LOW_SVS = 64,
+ RPM_REGULATOR_LEVEL_SVS = 128,
+ RPM_REGULATOR_LEVEL_SVS_PLUS = 192,
+ RPM_REGULATOR_LEVEL_NOM = 256,
+ RPM_REGULATOR_LEVEL_NOM_PLUS = 320,
+ RPM_REGULATOR_LEVEL_TURBO = 384,
+ RPM_REGULATOR_LEVEL_TURBO_NO_CPR = 416,
+ RPM_REGULATOR_LEVEL_BINNING = 512,
+ RPM_REGULATOR_LEVEL_MAX = 65535,
+};
+
+/**
+ * enum rpm_regulator_mode - control mode for LDO or SMPS type regulators
+ * %RPM_REGULATOR_MODE_AUTO: For SMPS type regulators, use SMPS auto mode so
+ * that the hardware can automatically switch
+ * between PFM and PWM modes based on realtime
+ * load.
+ * LDO type regulators do not support this mode.
+ * %RPM_REGULATOR_MODE_IPEAK: For SMPS type regulators, use aggregated
+ * software current requests to determine
+ * usage of PFM or PWM mode.
+ * For LDO type regulators, use aggregated
+ * software current requests to determine
+ * usage of LPM or HPM mode.
+ * %RPM_REGULATOR_MODE_HPM: For SMPS type regulators, force the
+ * usage of PWM mode.
+ * For LDO type regulators, force the
+ * usage of HPM mode.
+ *
+ * These values should be used in calls to rpm_regulator_set_mode().
+ */
+enum rpm_regulator_mode {
+ RPM_REGULATOR_MODE_AUTO,
+ RPM_REGULATOR_MODE_IPEAK,
+ RPM_REGULATOR_MODE_HPM,
+};
+
+#ifdef CONFIG_REGULATOR_RPM_SMD
+
+struct rpm_regulator *rpm_regulator_get(struct device *dev, const char *supply);
+
+void rpm_regulator_put(struct rpm_regulator *regulator);
+
+int rpm_regulator_enable(struct rpm_regulator *regulator);
+
+int rpm_regulator_disable(struct rpm_regulator *regulator);
+
+int rpm_regulator_set_voltage(struct rpm_regulator *regulator, int min_uV,
+ int max_uV);
+
+int rpm_regulator_set_mode(struct rpm_regulator *regulator,
+ enum rpm_regulator_mode mode);
+
+int __init rpm_smd_regulator_driver_init(void);
+
+#else
+
+static inline struct rpm_regulator *rpm_regulator_get(struct device *dev,
+ const char *supply) { return NULL; }
+
+static inline void rpm_regulator_put(struct rpm_regulator *regulator) { }
+
+static inline int rpm_regulator_enable(struct rpm_regulator *regulator)
+ { return 0; }
+
+static inline int rpm_regulator_disable(struct rpm_regulator *regulator)
+ { return 0; }
+
+static inline int rpm_regulator_set_voltage(struct rpm_regulator *regulator,
+ int min_uV, int max_uV) { return 0; }
+
+static inline int rpm_regulator_set_mode(struct rpm_regulator *regulator,
+ enum rpm_regulator_mode mode) { return 0; }
+
+static inline int __init rpm_smd_regulator_driver_init(void) { return 0; }
+
+#endif /* CONFIG_REGULATOR_RPM_SMD */
+
+#endif
diff --git a/include/linux/regulator/spm-regulator.h b/include/linux/regulator/spm-regulator.h
new file mode 100644
index 0000000..bd5da2e
--- /dev/null
+++ b/include/linux/regulator/spm-regulator.h
@@ -0,0 +1,25 @@
+/* Copyright (c) 2013-2014, 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 _LINUX_REGULATOR_SPM_H
+#define _LINUX_REGULATOR_SPM_H
+
+#include <linux/err.h>
+#include <linux/init.h>
+
+#ifdef CONFIG_REGULATOR_SPM
+int __init spm_regulator_init(void);
+#else
+static inline int __init spm_regulator_init(void) { return -ENODEV; }
+#endif
+
+#endif
diff --git a/include/linux/sde_rsc.h b/include/linux/sde_rsc.h
index cda2654..d2c1a95 100644
--- a/include/linux/sde_rsc.h
+++ b/include/linux/sde_rsc.h
@@ -186,6 +186,26 @@
int *wait_vblank_crtc_id);
/**
+ * sde_rsc_client_get_vsync_refcount() - returns the status of the vsync
+ * refcount, to signal if the client needs to reset the refcounting logic
+ * @client: Client pointer provided by sde_rsc_client_create().
+ *
+ * Return: true if the state update has completed.
+ */
+int sde_rsc_client_get_vsync_refcount(
+ struct sde_rsc_client *caller_client);
+
+/**
+ * sde_rsc_client_reset_vsync_refcount() - reduces the refcounting
+ * logic that waits for the vsync.
+ * @client: Client pointer provided by sde_rsc_client_create().
+ *
+ * Return: true if the state update has completed.
+ */
+int sde_rsc_client_reset_vsync_refcount(
+ struct sde_rsc_client *caller_client);
+
+/**
* sde_rsc_client_is_state_update_complete() - check if state update is complete
* RSC state transition is not complete until HW receives VBLANK signal. This
* function checks RSC HW to determine whether that signal has been received.
@@ -265,6 +285,18 @@
return 0;
}
+int sde_rsc_client_get_vsync_refcount(
+ struct sde_rsc_client *caller_client)
+{
+ return 0;
+}
+
+int sde_rsc_client_reset_vsync_refcount(
+ struct sde_rsc_client *caller_client)
+{
+ return 0;
+}
+
static inline bool sde_rsc_client_is_state_update_complete(
struct sde_rsc_client *caller_client)
{
diff --git a/include/linux/string.h b/include/linux/string.h
index 0463dfb..4691e7f 100644
--- a/include/linux/string.h
+++ b/include/linux/string.h
@@ -173,9 +173,16 @@
#define __RENAME(x) __asm__(#x)
void fortify_panic(const char *name) __noreturn __cold;
+
+#ifdef CONFIG_FORTIFY_COMPILE_CHECK
void __read_overflow(void) __compiletime_error("detected read beyond size of object passed as 1st parameter");
void __read_overflow2(void) __compiletime_error("detected read beyond size of object passed as 2nd parameter");
void __write_overflow(void) __compiletime_error("detected write beyond size of object passed as 1st parameter");
+#else
+#define __read_overflow(void) do { } while (0)
+#define __read_overflow2(void) do { } while (0)
+#define __write_overflow(void) do { } while (0)
+#endif
#if !defined(__NO_FORTIFY) && defined(__OPTIMIZE__) && defined(CONFIG_FORTIFY_SOURCE)
__FORTIFY_INLINE char *strncpy(char *p, const char *q, __kernel_size_t size)
diff --git a/include/linux/usb/gadget.h b/include/linux/usb/gadget.h
index 4f56e98..b2eb2d0 100644
--- a/include/linux/usb/gadget.h
+++ b/include/linux/usb/gadget.h
@@ -1120,12 +1120,12 @@
int msm_ep_config(struct usb_ep *ep);
int msm_ep_unconfig(struct usb_ep *ep);
void dwc3_tx_fifo_resize_request(struct usb_ep *ep, bool qdss_enable);
-int msm_data_fifo_config(struct usb_ep *ep, phys_addr_t addr, u32 size,
+int msm_data_fifo_config(struct usb_ep *ep, unsigned long addr, u32 size,
u8 dst_pipe_idx);
bool msm_dwc3_reset_ep_after_lpm(struct usb_gadget *gadget);
int msm_dwc3_reset_dbm_ep(struct usb_ep *ep);
#else
-static inline int msm_data_fifo_config(struct usb_ep *ep, phys_addr_t addr,
+static inline int msm_data_fifo_config(struct usb_ep *ep, unsigned long addr,
u32 size, u8 dst_pipe_idx)
{ return -ENODEV; }
diff --git a/include/linux/usb/phy.h b/include/linux/usb/phy.h
index 092c32e..64aa52e 100644
--- a/include/linux/usb/phy.h
+++ b/include/linux/usb/phy.h
@@ -45,7 +45,8 @@
USB_PHY_TYPE_UNDEFINED,
USB_PHY_TYPE_USB2,
USB_PHY_TYPE_USB3,
- USB_PHY_TYPE_USB3_DP,
+ USB_PHY_TYPE_USB3_OR_DP,
+ USB_PHY_TYPE_USB3_AND_DP,
};
/* OTG defines lots of enumeration states before device reset */
@@ -114,6 +115,8 @@
/* enable/disable VBUS */
int (*set_vbus)(struct usb_phy *x, int on);
+ /* callback to indicate port is being reset or reset the port */
+ void (*start_port_reset)(struct usb_phy *x);
/* effective for B devices, ignored for A-peripheral */
int (*set_power)(struct usb_phy *x,
@@ -213,6 +216,15 @@
return x->set_vbus(x, false);
}
+static inline void
+usb_phy_start_port_reset(struct usb_phy *x)
+{
+ if (!x || !x->start_port_reset)
+ return;
+
+ x->start_port_reset(x);
+}
+
static inline int
usb_phy_reset(struct usb_phy *x)
{
diff --git a/include/linux/usb_bam.h b/include/linux/usb_bam.h
index 1b0ca4a..84d7549 100644
--- a/include/linux/usb_bam.h
+++ b/include/linux/usb_bam.h
@@ -245,10 +245,13 @@
*
* @bam_pipe_idx - allocated pipe index.
*
+ * @iova - IPA address of USB peer BAM (i.e. QDSS BAM)
+ *
* @return 0 on success, negative value on error
*
*/
-int usb_bam_connect(enum usb_ctrl bam_type, int idx, u32 *bam_pipe_idx);
+int usb_bam_connect(enum usb_ctrl bam_type, int idx, u32 *bam_pipe_idx,
+ unsigned long iova);
/**
* Connect USB-to-IPA SPS connection.
@@ -430,12 +433,14 @@
/* Frees memory for data fifo and descriptor fifos. */
int usb_bam_free_fifos(enum usb_ctrl cur_bam, u8 idx);
-
+int get_qdss_bam_info(enum usb_ctrl cur_bam, u8 idx,
+ phys_addr_t *p_addr, u32 *bam_size);
bool msm_bam_hsic_lpm_ok(void);
bool msm_bam_hsic_host_pipe_empty(void);
bool msm_usb_bam_enable(enum usb_ctrl ctrl, bool bam_enable);
#else
-static inline int usb_bam_connect(enum usb_ctrl bam, u8 idx, u32 *bam_pipe_idx)
+static inline int usb_bam_connect(enum usb_ctrl bam, u8 idx, u32 *bam_pipe_idx,
+ unsigned long iova)
{
return -ENODEV;
}
@@ -529,6 +534,11 @@
return false;
}
+static int get_qdss_bam_info(enum usb_ctrl cur_bam, u8 idx,
+ phys_addr_t *p_addr, u32 *bam_size)
+{
+ return false;
+}
static inline bool msm_bam_hsic_lpm_ok(void) { return true; }
static inline bool msm_bam_hsic_host_pipe_empty(void) { return true; }
static inline bool msm_usb_bam_enable(enum usb_ctrl ctrl, bool bam_enable)
diff --git a/include/trace/events/oom.h b/include/trace/events/oom.h
index 1e97498..beddb19 100644
--- a/include/trace/events/oom.h
+++ b/include/trace/events/oom.h
@@ -27,6 +27,85 @@
__entry->pid, __entry->comm, __entry->oom_score_adj)
);
+TRACE_EVENT(mark_victim,
+ TP_PROTO(int pid),
+
+ TP_ARGS(pid),
+
+ TP_STRUCT__entry(
+ __field(int, pid)
+ ),
+
+ TP_fast_assign(
+ __entry->pid = pid;
+ ),
+
+ TP_printk("pid=%d", __entry->pid)
+);
+
+TRACE_EVENT(wake_reaper,
+ TP_PROTO(int pid),
+
+ TP_ARGS(pid),
+
+ TP_STRUCT__entry(
+ __field(int, pid)
+ ),
+
+ TP_fast_assign(
+ __entry->pid = pid;
+ ),
+
+ TP_printk("pid=%d", __entry->pid)
+);
+
+TRACE_EVENT(start_task_reaping,
+ TP_PROTO(int pid),
+
+ TP_ARGS(pid),
+
+ TP_STRUCT__entry(
+ __field(int, pid)
+ ),
+
+ TP_fast_assign(
+ __entry->pid = pid;
+ ),
+
+ TP_printk("pid=%d", __entry->pid)
+);
+
+TRACE_EVENT(finish_task_reaping,
+ TP_PROTO(int pid),
+
+ TP_ARGS(pid),
+
+ TP_STRUCT__entry(
+ __field(int, pid)
+ ),
+
+ TP_fast_assign(
+ __entry->pid = pid;
+ ),
+
+ TP_printk("pid=%d", __entry->pid)
+);
+
+TRACE_EVENT(skip_task_reaping,
+ TP_PROTO(int pid),
+
+ TP_ARGS(pid),
+
+ TP_STRUCT__entry(
+ __field(int, pid)
+ ),
+
+ TP_fast_assign(
+ __entry->pid = pid;
+ ),
+
+ TP_printk("pid=%d", __entry->pid)
+);
#endif
/* This part must be outside protection */
diff --git a/include/uapi/linux/msm_ipa.h b/include/uapi/linux/msm_ipa.h
index d3b9a33..ef07f78 100644
--- a/include/uapi/linux/msm_ipa.h
+++ b/include/uapi/linux/msm_ipa.h
@@ -819,13 +819,17 @@
* IPA_HDR_L2_NONE: L2 header which isn't Ethernet II and isn't 802_3
* IPA_HDR_L2_ETHERNET_II: L2 header of type Ethernet II
* IPA_HDR_L2_802_3: L2 header of type 802_3
+ * IPA_HDR_L2_802_1Q: L2 header of type 802_1Q
*/
enum ipa_hdr_l2_type {
IPA_HDR_L2_NONE,
IPA_HDR_L2_ETHERNET_II,
IPA_HDR_L2_802_3,
+ IPA_HDR_L2_802_1Q,
};
-#define IPA_HDR_L2_MAX (IPA_HDR_L2_802_3 + 1)
+#define IPA_HDR_L2_MAX (IPA_HDR_L2_802_1Q + 1)
+
+#define IPA_HDR_L2_802_1Q IPA_HDR_L2_802_1Q
/**
* enum ipa_hdr_l2_type - Processing context type
diff --git a/include/uapi/media/cam_defs.h b/include/uapi/media/cam_defs.h
index 9a767dd..cabf0a8 100644
--- a/include/uapi/media/cam_defs.h
+++ b/include/uapi/media/cam_defs.h
@@ -17,6 +17,9 @@
#define CAM_SD_SHUTDOWN (CAM_COMMON_OPCODE_BASE + 0x7)
#define CAM_COMMON_OPCODE_MAX (CAM_COMMON_OPCODE_BASE + 0x8)
+#define CAM_EXT_OPCODE_BASE 0x200
+#define CAM_CONFIG_DEV_EXTERNAL (CAM_EXT_OPCODE_BASE + 0x1)
+
/* camera handle type */
#define CAM_HANDLE_USER_POINTER 1
#define CAM_HANDLE_MEM_HANDLE 2
diff --git a/include/uapi/media/cam_req_mgr.h b/include/uapi/media/cam_req_mgr.h
index 6846b8f..3f1facd 100644
--- a/include/uapi/media/cam_req_mgr.h
+++ b/include/uapi/media/cam_req_mgr.h
@@ -424,6 +424,7 @@
*/
struct cam_req_mgr_message {
int32_t session_hdl;
+ int32_t reserved;
union {
struct cam_req_mgr_error_msg err_msg;
struct cam_req_mgr_frame_msg frame_msg;
diff --git a/kernel/compat.c b/kernel/compat.c
index 333d364..1cd7051 100644
--- a/kernel/compat.c
+++ b/kernel/compat.c
@@ -109,7 +109,7 @@
struct timezone __user *, tz)
{
struct timeval user_tv;
- struct timespec new_ts;
+ struct timespec new_ts = {0};
struct timezone new_tz;
if (tv) {
diff --git a/kernel/fork.c b/kernel/fork.c
index 610aded..b83adf9 100644
--- a/kernel/fork.c
+++ b/kernel/fork.c
@@ -879,7 +879,6 @@
}
if (mm->binfmt)
module_put(mm->binfmt->module);
- set_bit(MMF_OOM_SKIP, &mm->flags);
mmdrop(mm);
}
diff --git a/kernel/time/time.c b/kernel/time/time.c
index bd62fb8..1b2d209 100644
--- a/kernel/time/time.c
+++ b/kernel/time/time.c
@@ -194,7 +194,7 @@
struct timezone __user *, tz)
{
struct timeval user_tv;
- struct timespec new_ts;
+ struct timespec new_ts = {0};
struct timezone new_tz;
if (tv) {
diff --git a/mm/internal.h b/mm/internal.h
index 0ee4f54..6aa1c51 100644
--- a/mm/internal.h
+++ b/mm/internal.h
@@ -41,6 +41,11 @@
void free_pgtables(struct mmu_gather *tlb, struct vm_area_struct *start_vma,
unsigned long floor, unsigned long ceiling);
+static inline bool can_madv_dontneed_vma(struct vm_area_struct *vma)
+{
+ return !(vma->vm_flags & (VM_LOCKED|VM_HUGETLB|VM_PFNMAP));
+}
+
void unmap_page_range(struct mmu_gather *tlb,
struct vm_area_struct *vma,
unsigned long addr, unsigned long end,
diff --git a/mm/madvise.c b/mm/madvise.c
index 088a5b22..8b25167 100644
--- a/mm/madvise.c
+++ b/mm/madvise.c
@@ -25,6 +25,8 @@
#include <asm/tlb.h>
+#include "internal.h"
+
/*
* Any behaviour which results in changes to the vma->vm_flags needs to
* take mmap_sem for writing. Others, which simply traverse vmas, need
@@ -474,7 +476,7 @@
unsigned long start, unsigned long end)
{
*prev = vma;
- if (vma->vm_flags & (VM_LOCKED|VM_HUGETLB|VM_PFNMAP))
+ if (!can_madv_dontneed_vma(vma))
return -EINVAL;
zap_page_range(vma, start, end - start, NULL);
diff --git a/mm/memory.c b/mm/memory.c
index 378ebc0..82d2000 100644
--- a/mm/memory.c
+++ b/mm/memory.c
@@ -1154,12 +1154,6 @@
if (!PageAnon(page)) {
if (pte_dirty(ptent)) {
- /*
- * oom_reaper cannot tear down dirty
- * pages
- */
- if (unlikely(details && details->ignore_dirty))
- continue;
force_flush = 1;
set_page_dirty(page);
}
@@ -1179,8 +1173,8 @@
}
continue;
}
- /* only check swap_entries if explicitly asked for in details */
- if (unlikely(details && !details->check_swap_entries))
+ /* If details->check_mapping, we leave swap entries. */
+ if (unlikely(details))
continue;
entry = pte_to_swp_entry(ptent);
diff --git a/mm/mmap.c b/mm/mmap.c
index 6f90f07..7e6c049 100644
--- a/mm/mmap.c
+++ b/mm/mmap.c
@@ -44,6 +44,7 @@
#include <linux/userfaultfd_k.h>
#include <linux/moduleparam.h>
#include <linux/pkeys.h>
+#include <linux/oom.h>
#include <asm/uaccess.h>
#include <asm/cacheflush.h>
@@ -2983,6 +2984,23 @@
/* Use -1 here to ensure all VMAs in the mm are unmapped */
unmap_vmas(&tlb, vma, 0, -1);
+ set_bit(MMF_OOM_SKIP, &mm->flags);
+ if (unlikely(tsk_is_oom_victim(current))) {
+ /*
+ * Wait for oom_reap_task() to stop working on this
+ * mm. Because MMF_OOM_SKIP is already set before
+ * calling down_read(), oom_reap_task() will not run
+ * on this "mm" post up_write().
+ *
+ * tsk_is_oom_victim() cannot be set from under us
+ * either because current->mm is already set to NULL
+ * under task_lock before calling mmput and oom_mm is
+ * set not NULL by the OOM killer only if current->mm
+ * is found not NULL while holding the task_lock.
+ */
+ down_write(&mm->mmap_sem);
+ up_write(&mm->mmap_sem);
+ }
free_pgtables(&tlb, vma, FIRST_USER_ADDRESS, USER_PGTABLES_CEILING);
tlb_finish_mmu(&tlb, 0, -1);
diff --git a/mm/oom_kill.c b/mm/oom_kill.c
index 1f13413..af9a8a6 100644
--- a/mm/oom_kill.c
+++ b/mm/oom_kill.c
@@ -470,8 +470,6 @@
{
struct mmu_gather tlb;
struct vm_area_struct *vma;
- struct zap_details details = {.check_swap_entries = true,
- .ignore_dirty = true};
bool ret = true;
/*
@@ -492,6 +490,7 @@
if (!down_read_trylock(&mm->mmap_sem)) {
ret = false;
+ trace_skip_task_reaping(tsk->pid);
goto unlock_oom;
}
@@ -511,15 +510,19 @@
}
/*
- * increase mm_users only after we know we will reap something so
- * that the mmput_async is called only when we have reaped something
- * and delayed __mmput doesn't matter that much
+ * MMF_OOM_SKIP is set by exit_mmap when the OOM reaper can't
+ * work on the mm anymore. The check for MMF_OOM_SKIP must run
+ * under mmap_sem for reading because it serializes against the
+ * down_write();up_write() cycle in exit_mmap().
*/
- if (!mmget_not_zero(mm)) {
+ if (test_bit(MMF_OOM_SKIP, &mm->flags)) {
up_read(&mm->mmap_sem);
+ trace_skip_task_reaping(tsk->pid);
goto unlock_oom;
}
+ trace_start_task_reaping(tsk->pid);
+
/*
* Tell all users of get_user/copy_from_user etc... that the content
* is no longer stable. No barriers really needed because unmapping
@@ -528,16 +531,8 @@
*/
set_bit(MMF_UNSTABLE, &mm->flags);
- tlb_gather_mmu(&tlb, mm, 0, -1);
for (vma = mm->mmap ; vma; vma = vma->vm_next) {
- if (is_vm_hugetlb_page(vma))
- continue;
-
- /*
- * mlocked VMAs require explicit munlocking before unmap.
- * Let's keep it simple here and skip such VMAs.
- */
- if (vma->vm_flags & VM_LOCKED)
+ if (!can_madv_dontneed_vma(vma))
continue;
/*
@@ -550,11 +545,13 @@
* we do not want to block exit_mmap by keeping mm ref
* count elevated without a good reason.
*/
- if (vma_is_anonymous(vma) || !(vma->vm_flags & VM_SHARED))
+ if (vma_is_anonymous(vma) || !(vma->vm_flags & VM_SHARED)) {
+ tlb_gather_mmu(&tlb, mm, vma->vm_start, vma->vm_end);
unmap_page_range(&tlb, vma, vma->vm_start, vma->vm_end,
- &details);
+ NULL);
+ tlb_finish_mmu(&tlb, vma->vm_start, vma->vm_end);
+ }
}
- tlb_finish_mmu(&tlb, 0, -1);
pr_info("oom_reaper: reaped process %d (%s), now anon-rss:%lukB, file-rss:%lukB, shmem-rss:%lukB\n",
task_pid_nr(tsk), tsk->comm,
K(get_mm_counter(mm, MM_ANONPAGES)),
@@ -562,12 +559,7 @@
K(get_mm_counter(mm, MM_SHMEMPAGES)));
up_read(&mm->mmap_sem);
- /*
- * Drop our reference but make sure the mmput slow path is called from a
- * different context because we shouldn't risk we get stuck there and
- * put the oom_reaper out of the way.
- */
- mmput_async(mm);
+ trace_finish_task_reaping(tsk->pid);
unlock_oom:
mutex_unlock(&oom_lock);
return ret;
@@ -644,6 +636,7 @@
tsk->oom_reaper_list = oom_reaper_list;
oom_reaper_list = tsk;
spin_unlock(&oom_reaper_lock);
+ trace_wake_reaper(tsk->pid);
wake_up(&oom_reaper_wait);
}
@@ -695,6 +688,7 @@
*/
__thaw_task(tsk);
atomic_inc(&oom_victims);
+ trace_mark_victim(tsk->pid);
}
/**
diff --git a/mm/page_alloc.c b/mm/page_alloc.c
index bcfc58b..baf31df 100644
--- a/mm/page_alloc.c
+++ b/mm/page_alloc.c
@@ -7428,10 +7428,10 @@
}
/* Make sure the range is really isolated. */
- if (test_pages_isolated(outer_start, end, false)) {
+ ret = test_pages_isolated(outer_start, end, false);
+ if (ret) {
pr_info_ratelimited("%s: [%lx, %lx) PFNs busy\n",
__func__, outer_start, end);
- ret = -EBUSY;
goto done;
}